[opencv] 02/13: New upstream version 3.2.0+dfsg

Nobuhiro Iwamatsu iwamatsu at moszumanska.debian.org
Sat May 13 09:54:27 UTC 2017


This is an automated email from the git hooks/post-receive script.

iwamatsu pushed a commit to branch master
in repository opencv.

commit 66a432a195f0e8644b8e1b99830e415bee399916
Author: Nobuhiro Iwamatsu <iwamatsu at nigauri.org>
Date:   Fri May 12 12:45:27 2017 +0900

    New upstream version 3.2.0+dfsg
---
 CMakeLists.txt                                     |   386 +-
 CONTRIBUTING.md                                    |     2 +-
 LICENSE                                            |     8 +-
 README.md                                          |     6 +-
 apps/CMakeLists.txt                                |     3 +
 apps/annotation/CMakeLists.txt                     |     1 -
 apps/annotation/opencv_annotation.cpp              |   195 +-
 apps/createsamples/CMakeLists.txt                  |     1 -
 apps/createsamples/createsamples.cpp               |    13 +-
 apps/createsamples/utility.cpp                     |    24 +-
 apps/createsamples/utility.hpp                     |     2 +-
 apps/interactive-calibration/CMakeLists.txt        |    39 +
 apps/interactive-calibration/calibCommon.hpp       |   123 +
 apps/interactive-calibration/calibController.cpp   |   332 +
 apps/interactive-calibration/calibController.hpp   |    69 +
 apps/interactive-calibration/calibPipeline.cpp     |    97 +
 apps/interactive-calibration/calibPipeline.hpp     |    45 +
 apps/interactive-calibration/defaultConfig.xml     |    14 +
 apps/interactive-calibration/frameProcessor.cpp    |   523 +
 apps/interactive-calibration/frameProcessor.hpp    |   100 +
 apps/interactive-calibration/main.cpp              |   219 +
 .../parametersController.cpp                       |   143 +
 .../parametersController.hpp                       |    35 +
 .../interactive-calibration/rotationConverters.cpp |   126 +
 .../interactive-calibration/rotationConverters.hpp |    20 +
 apps/traincascade/CMakeLists.txt                   |     3 +-
 apps/traincascade/boost.cpp                        |    14 +-
 apps/traincascade/cascadeclassifier.cpp            |    15 +-
 apps/traincascade/imagestorage.cpp                 |     3 +-
 apps/traincascade/old_ml.hpp                       |     6 +-
 apps/traincascade/old_ml_precomp.hpp               |     4 +-
 apps/version/CMakeLists.txt                        |    32 +
 apps/version/opencv_version.cpp                    |    28 +
 apps/visualisation/CMakeLists.txt                  |    37 +
 apps/visualisation/opencv_visualisation.cpp        |   364 +
 cmake/FindGstreamerWindows.cmake                   |     2 +-
 cmake/FindOpenVX.cmake                             |    32 +
 cmake/OpenCVCompilerOptions.cmake                  |    91 +-
 cmake/OpenCVConfig.cmake                           |   173 -
 cmake/OpenCVDetectAndroidSDK.cmake                 |     2 +-
 cmake/OpenCVDetectCUDA.cmake                       |    38 +-
 cmake/OpenCVDetectCXXCompiler.cmake                |     8 +-
 cmake/OpenCVDetectOpenCL.cmake                     |    34 +-
 cmake/OpenCVDetectPython.cmake                     |    52 +-
 cmake/OpenCVDetectTBB.cmake                        |   155 +-
 cmake/OpenCVDetectVTK.cmake                        |     9 +-
 cmake/OpenCVFindAtlas.cmake                        |    97 +
 cmake/OpenCVFindIPP.cmake                          |     8 +-
 cmake/OpenCVFindLAPACK.cmake                       |    78 +
 cmake/OpenCVFindLibsGrfmt.cmake                    |    14 +-
 cmake/OpenCVFindLibsPerf.cmake                     |    25 +
 cmake/OpenCVFindLibsVideo.cmake                    |   129 +-
 cmake/OpenCVFindMKL.cmake                          |   136 +
 cmake/OpenCVFindMatlab.cmake                       |     2 +-
 cmake/OpenCVFindOpenBLAS.cmake                     |   106 +
 cmake/OpenCVGenABI.cmake                           |     2 +-
 cmake/OpenCVGenConfig.cmake                        |   150 +-
 cmake/OpenCVMinDepVersions.cmake                   |     2 +-
 cmake/OpenCVModule.cmake                           |    13 +-
 cmake/OpenCVPCHSupport.cmake                       |   104 +-
 cmake/OpenCVUtils.cmake                            |   248 +-
 cmake/checks/ffmpeg_test.cpp                       |    24 +
 cmake/checks/fp16.cpp                              |    33 +
 cmake/checks/opencl.cpp                            |     5 +-
 cmake/templates/OpenCVConfig-ANDROID.cmake.in      |    13 +
 cmake/templates/OpenCVConfig-CUDA.cmake.in         |    53 +
 cmake/templates/OpenCVConfig-IPPICV.cmake.in       |     7 +
 cmake/templates/OpenCVConfig.cmake.in              |   293 +-
 cmake/templates/OpenCVConfig.root-ANDROID.cmake.in |    50 +
 cmake/templates/OpenCVConfig.root-WIN32.cmake.in   |   144 +
 cmake/templates/custom_hal.hpp.in                  |     2 +-
 cmake/templates/cvconfig.h.in                      |    24 +-
 cmake/templates/opencv_modules.hpp.in              |     4 +
 contrib/.github/ISSUE_TEMPLATE.md                  |    30 +
 contrib/.github/PULL_REQUEST_TEMPLATE.md           |     9 +
 contrib/.gitignore                                 |    12 +
 contrib/.travis.yml                                |     2 +-
 contrib/CONTRIBUTING.md                            |     2 +-
 contrib/README.md                                  |     7 +-
 contrib/modules/README.md                          |    72 +-
 contrib/modules/aruco/CMakeLists.txt               |     2 +-
 contrib/modules/aruco/README.md                    |    10 +
 contrib/modules/aruco/include/opencv2/aruco.hpp    |   183 +-
 .../aruco/include/opencv2/aruco/charuco.hpp        |    87 +-
 .../aruco/include/opencv2/aruco/dictionary.hpp     |    63 +-
 contrib/modules/aruco/samples/calibrate_camera.cpp |    55 +-
 .../aruco/samples/calibrate_camera_charuco.cpp     |    61 +-
 contrib/modules/aruco/samples/create_board.cpp     |     8 +-
 .../modules/aruco/samples/create_board_charuco.cpp |    10 +-
 contrib/modules/aruco/samples/create_diamond.cpp   |     6 +-
 contrib/modules/aruco/samples/create_marker.cpp    |     2 +-
 contrib/modules/aruco/samples/detect_board.cpp     |    51 +-
 .../modules/aruco/samples/detect_board_charuco.cpp |    57 +-
 contrib/modules/aruco/samples/detect_diamonds.cpp  |    50 +-
 contrib/modules/aruco/samples/detect_markers.cpp   |    48 +-
 contrib/modules/aruco/samples/detector_params.yml  |     7 +
 contrib/modules/aruco/src/aruco.cpp                |   607 +-
 contrib/modules/aruco/src/charuco.cpp              |   267 +-
 contrib/modules/aruco/src/dictionary.cpp           |   123 +-
 contrib/modules/aruco/test/test_arucodetection.cpp |    55 +-
 contrib/modules/aruco/test/test_boarddetection.cpp |   119 +-
 .../modules/aruco/test/test_charucodetection.cpp   |    56 +-
 .../aruco_board_detection.markdown                 |    17 +-
 .../aruco_board_detection/images/board.jpg         |   Bin 81038 -> 10914 bytes
 .../aruco_calibration/aruco_calibration.markdown   |    10 +
 .../aruco_detection/aruco_detection.markdown       |    19 +-
 .../tutorials/aruco_detection/images/marker23.jpg  |   Bin 4777 -> 1163 bytes
 .../charuco_detection/charuco_detection.markdown   |    19 +-
 .../tutorials/charuco_detection/images/board.jpg   |   Bin 0 -> 31536 bytes
 .../charuco_detection/images/charucoboard.jpg      |   Bin 28375 -> 0 bytes
 .../charuco_diamond_detection.markdown             |    17 +-
 .../include/opencv2/bioinspired/retina.hpp         |     5 +-
 .../bioinspired/src/opencl/retina_kernel.cl        |    10 +-
 contrib/modules/bioinspired/src/retina.cpp         |    20 +-
 .../src/transientareassegmentationmodule.cpp       |    52 +-
 .../images/checkershadow_illusion4med.jpg          |   Bin 0 -> 78370 bytes
 .../images/checkershadow_illusion4med_proof.jpg    |   Bin 0 -> 1194 bytes
 .../retina_illusion/images/checkershadow_parvo.png |   Bin 0 -> 217220 bytes
 .../images/checkershadow_parvo_proof.png           |   Bin 0 -> 2553 bytes
 .../retina_illusion/retina_illusion.markdown       |   187 +
 .../bioinspired/tutorials/retina_model.markdown    |   478 -
 .../images/retina_TreeHdr_retina.jpg               |   Bin
 .../images/retina_TreeHdr_small.jpg                |   Bin
 .../images/studentsSample_input.jpg                |   Bin
 .../images/studentsSample_magno.jpg                |   Bin
 .../images/studentsSample_parvo.jpg                |   Bin
 .../tutorials/retina_model/retina_model.markdown   |   477 +
 .../tutorials/table_of_content_retina.markdown     |    14 +
 .../ccalib/include/opencv2/ccalib/omnidir.hpp      |     2 +-
 contrib/modules/ccalib/src/omnidir.cpp             |     8 +-
 .../ccalib/tutorial/omnidir_tutorial.markdown      |   185 -
 .../data/omni_calib_data.xml                       |     0
 .../data/omni_stereocalib_data.xml                 |     0
 .../{tutorial => tutorials}/img/disparity.jpg      |   Bin
 .../ccalib/{tutorial => tutorials}/img/imgs.jpg    |   Bin
 .../ccalib/{tutorial => tutorials}/img/lines.jpg   |   Bin
 .../{tutorial => tutorials}/img/pattern_img.jpg    |   Bin
 .../{tutorial => tutorials}/img/pointCloud.jpg     |   Bin
 .../{tutorial => tutorials}/img/random_pattern.jpg |   Bin
 .../ccalib/{tutorial => tutorials}/img/sample.jpg  |   Bin
 .../{tutorial => tutorials}/img/sample_rec_cyl.jpg |   Bin
 .../{tutorial => tutorials}/img/sample_rec_log.jpg |   Bin
 .../{tutorial => tutorials}/img/sample_rec_per.jpg |   Bin
 .../{tutorial => tutorials}/img/sample_rec_ste.jpg |   Bin
 .../multi_camera_tutorial.markdown                 |     0
 .../ccalib/tutorials/omnidir_tutorial.markdown     |   185 +
 contrib/modules/cnn_3dobj/CMakeLists.txt           |    25 +-
 contrib/modules/cnn_3dobj/FindCaffe.cmake          |     2 +-
 contrib/modules/cnn_3dobj/README.md                |    83 +-
 contrib/modules/cnn_3dobj/cnn_3dobj_config.hpp.in  |     5 -
 .../cnn_3dobj/include/opencv2/cnn_3dobj.hpp        |     9 +-
 .../cnn_3dobj/include/opencv2/cnn_3dobj_config.hpp |     0
 contrib/modules/cnn_3dobj/samples/CMakeLists.txt   |    21 -
 contrib/modules/cnn_3dobj/samples/classify.cpp     |   200 +
 .../modules/cnn_3dobj/samples/demo_classify.cpp    |   201 -
 .../cnn_3dobj/samples/demo_sphereview_data.cpp     |   333 -
 contrib/modules/cnn_3dobj/samples/demo_video.cpp   |   391 -
 ...{demo_model_analysis.cpp => model_analysis.cpp} |     0
 .../modules/cnn_3dobj/samples/sphereview_data.cpp  |   331 +
 contrib/modules/cnn_3dobj/samples/video.cpp        |   390 +
 .../test/test_cnn_3dobj_feature_extract.cpp        |    13 +-
 contrib/modules/cnn_3dobj/test/test_precomp.hpp    |     1 -
 .../data_generation/data_generation.markdown       |     3 +-
 .../feature_classification/classify.markdown       |     5 +-
 .../model_analysis/model_analysis.markdown         |     5 +-
 .../tutorials/table_of_content_cnn_3dobj.markdown  |     2 +-
 contrib/modules/contrib_world/CMakeLists.txt       |    10 +-
 contrib/modules/contrib_world/README.md            |     5 +
 contrib/modules/cvv/.gitignore                     |    10 +
 contrib/modules/cvv/CMakeLists.txt                 |    18 +-
 contrib/modules/cvv/README.md                      |     2 +
 contrib/modules/cvv/src/impl/filter_call.cpp       |     4 +-
 contrib/modules/cvv/src/impl/match_call.cpp        |     4 +-
 contrib/modules/cvv/src/impl/single_image_call.cpp |     4 +-
 .../modules/cvv/src/qtutil/matchview/colorutil.hpp |     1 +
 contrib/modules/cvv/src/qtutil/util.cpp            |     1 +
 contrib/modules/cvv/src/qtutil/zoomableimage.cpp   |     4 +-
 contrib/modules/cvv/src/view/defaultfilterview.cpp |     2 +-
 contrib/modules/cvv/src/view/dual_filter_view.cpp  |     2 +-
 contrib/modules/cvv/src/view/linematchview.cpp     |     2 +-
 contrib/modules/cvv/src/view/pointmatchview.cpp    |     2 +-
 contrib/modules/cvv/src/view/singlefilterview.cpp  |     2 +-
 .../modules/cvv/src/view/translationsmatchview.cpp |     2 +-
 contrib/modules/cvv/test/test_location.cpp         |     2 +-
 contrib/modules/cvv/test/test_main.cpp             |     2 +-
 contrib/modules/datasets/README.md                 |     4 +
 .../include/opencv2/datasets/track_alov.hpp        |   107 +
 contrib/modules/datasets/src/or_pascal.cpp         |    19 +-
 contrib/modules/datasets/src/track_alov.cpp        |   384 +
 .../modules/dnn/3rdparty/protobuf/CMakeLists.txt   |   151 +
 contrib/modules/dnn/CMakeLists.txt                 |    50 +-
 .../modules/dnn/cmake/OpenCVFindLibProtobuf.cmake  |    83 +-
 contrib/modules/dnn/cmake/download_model.cmake     |    31 +
 contrib/modules/dnn/cmake/download_protobuf.cmake  |    51 +
 .../modules/dnn/include/opencv2/dnn/all_layers.hpp |   405 +
 contrib/modules/dnn/include/opencv2/dnn/blob.hpp   |   155 +-
 .../modules/dnn/include/opencv2/dnn/blob.inl.hpp   |   287 +-
 contrib/modules/dnn/include/opencv2/dnn/dict.hpp   |    12 +-
 contrib/modules/dnn/include/opencv2/dnn/dnn.hpp    |   109 +-
 .../modules/dnn/include/opencv2/dnn/dnn.inl.hpp    |     8 +-
 contrib/modules/dnn/include/opencv2/dnn/layer.hpp  |    17 +-
 .../dnn/include/opencv2/dnn/shape_utils.hpp        |   137 +
 contrib/modules/dnn/misc/caffe/caffe.pb.cc         | 45683 +++++++++++++++++++
 contrib/modules/dnn/misc/caffe/caffe.pb.h          | 24439 ++++++++++
 contrib/modules/dnn/misc/python/pyopencv_dnn.hpp   |   108 +
 .../modules/dnn/misc/tensorflow/attr_value.pb.cc   |  3014 ++
 .../modules/dnn/misc/tensorflow/attr_value.pb.h    |  1697 +
 contrib/modules/dnn/misc/tensorflow/function.pb.cc |  2348 +
 contrib/modules/dnn/misc/tensorflow/function.pb.h  |  1160 +
 contrib/modules/dnn/misc/tensorflow/graph.pb.cc    |  1687 +
 contrib/modules/dnn/misc/tensorflow/graph.pb.h     |   814 +
 contrib/modules/dnn/misc/tensorflow/op_def.pb.cc   |  4045 ++
 contrib/modules/dnn/misc/tensorflow/op_def.pb.h    |  2103 +
 contrib/modules/dnn/misc/tensorflow/tensor.pb.cc   |  1596 +
 contrib/modules/dnn/misc/tensorflow/tensor.pb.h    |   770 +
 .../modules/dnn/misc/tensorflow/tensor_shape.pb.cc |   895 +
 .../modules/dnn/misc/tensorflow/tensor_shape.pb.h  |   423 +
 contrib/modules/dnn/misc/tensorflow/types.pb.cc    |   163 +
 contrib/modules/dnn/misc/tensorflow/types.pb.h     |   129 +
 contrib/modules/dnn/misc/tensorflow/versions.pb.cc |   572 +
 contrib/modules/dnn/misc/tensorflow/versions.pb.h  |   239 +
 contrib/modules/dnn/perf/perf_convolution.cpp      |    80 +
 contrib/modules/dnn/perf/perf_main.cpp             |     3 +
 contrib/modules/dnn/perf/perf_precomp.hpp          |    17 +
 contrib/modules/dnn/samples/.gitignore             |     1 +
 .../VGG_VOC0712_SSD_300x300_iter_60000.prototxt    |  1547 +
 contrib/modules/dnn/samples/caffe_googlenet.cpp    |    30 +-
 .../dnn/samples/fcn32s-heavy-pascal.prototxt       |   502 +
 .../dnn/samples/fcn8s-heavy-pascal.prototxt        |   612 +
 contrib/modules/dnn/samples/fcn_semsegm.cpp        |   159 +
 contrib/modules/dnn/samples/googlenet_python.py    |    34 +
 contrib/modules/dnn/samples/pascal-classes.txt     |    21 +
 contrib/modules/dnn/samples/rgb.jpg                |   Bin 0 -> 47099 bytes
 .../modules/dnn/samples/ssd_object_detection.cpp   |   153 +
 contrib/modules/dnn/samples/tf_inception.cpp       |   182 +
 contrib/modules/dnn/scripts/download_model.py      |    79 -
 contrib/modules/dnn/scripts/test_models.json       |     7 -
 contrib/modules/dnn/src/blob.cpp                   |   431 +-
 contrib/modules/dnn/src/caffe/caffe.proto          |   114 +-
 contrib/modules/dnn/src/caffe/caffe_importer.cpp   |   466 +-
 .../modules/dnn/src/caffe/compiled/caffe.tar.gz    |   Bin 150353 -> 0 bytes
 contrib/modules/dnn/src/caffe/glog_emulator.hpp    |    45 +-
 contrib/modules/dnn/src/caffe/layer_loaders.cpp    |   304 +
 contrib/modules/dnn/src/caffe/layer_loaders.hpp    |    60 +
 contrib/modules/dnn/src/dnn.cpp                    |   129 +-
 contrib/modules/dnn/src/init.cpp                   |    69 +-
 contrib/modules/dnn/src/layers/concat_layer.cpp    |    96 +-
 contrib/modules/dnn/src/layers/concat_layer.hpp    |    27 +-
 .../modules/dnn/src/layers/convolution_layer.cpp   |   379 +-
 .../modules/dnn/src/layers/convolution_layer.hpp   |    95 +-
 contrib/modules/dnn/src/layers/crop_layer.cpp      |   128 +
 contrib/modules/dnn/src/layers/crop_layer.hpp      |    62 +
 .../dnn/src/layers/detection_output_layer.cpp      |   750 +
 .../dnn/src/layers/detection_output_layer.hpp      |   226 +
 .../modules/dnn/src/layers/elementwise_layers.cpp  |    46 +
 .../modules/dnn/src/layers/elementwise_layers.hpp  |   314 +-
 contrib/modules/dnn/src/layers/eltwise_layer.cpp   |   127 +
 contrib/modules/dnn/src/layers/eltwise_layer.hpp   |    62 +
 contrib/modules/dnn/src/layers/flatten_layer.cpp   |   117 +
 contrib/modules/dnn/src/layers/flatten_layer.hpp   |    67 +
 .../dnn/src/layers/fully_connected_layer.cpp       |   115 +-
 .../dnn/src/layers/fully_connected_layer.hpp       |    28 +-
 contrib/modules/dnn/src/layers/im2col.cpp          |    85 -
 contrib/modules/dnn/src/layers/im2col.hpp          |   126 -
 contrib/modules/dnn/src/layers/layers_common.cpp   |   135 +-
 contrib/modules/dnn/src/layers/layers_common.hpp   |    11 +-
 contrib/modules/dnn/src/layers/lrn_layer.cpp       |   272 +-
 contrib/modules/dnn/src/layers/lrn_layer.hpp       |    40 +-
 contrib/modules/dnn/src/layers/mvn_layer.cpp       |    32 +-
 contrib/modules/dnn/src/layers/mvn_layer.hpp       |     8 +-
 .../dnn/src/layers/normalize_bbox_layer.cpp        |   201 +
 .../dnn/src/layers/normalize_bbox_layer.hpp        |    94 +
 contrib/modules/dnn/src/layers/op_blas.cpp         |   171 +
 contrib/modules/dnn/src/layers/op_blas.hpp         |    59 +
 contrib/modules/dnn/src/layers/op_im2col.cpp       |   168 +
 contrib/modules/dnn/src/layers/op_im2col.hpp       |   242 +
 contrib/modules/dnn/src/layers/permute_layer.cpp   |   185 +
 contrib/modules/dnn/src/layers/permute_layer.hpp   |    75 +
 contrib/modules/dnn/src/layers/pooling_layer.cpp   |   314 +-
 contrib/modules/dnn/src/layers/pooling_layer.hpp   |    47 +-
 contrib/modules/dnn/src/layers/prior_box_layer.cpp |   307 +
 contrib/modules/dnn/src/layers/prior_box_layer.hpp |   101 +
 .../modules/dnn/src/layers/recurrent_layers.cpp    |   442 +
 .../modules/dnn/src/layers/recurrent_layers.hpp    |    54 +
 contrib/modules/dnn/src/layers/reshape_layer.cpp   |   139 +-
 contrib/modules/dnn/src/layers/reshape_layer.hpp   |    17 +-
 contrib/modules/dnn/src/layers/shift_layer.cpp     |   157 +
 contrib/modules/dnn/src/layers/shift_layer.hpp     |    36 +
 contrib/modules/dnn/src/layers/slice_layer.cpp     |    91 +-
 contrib/modules/dnn/src/layers/slice_layer.hpp     |    16 +-
 contrib/modules/dnn/src/layers/softmax_layer.cpp   |   212 +-
 contrib/modules/dnn/src/layers/softmax_layer.hpp   |    30 +-
 contrib/modules/dnn/src/layers/split_layer.cpp     |    39 +-
 contrib/modules/dnn/src/layers/split_layer.hpp     |    10 +-
 contrib/modules/dnn/src/opencl/activations.cl      |    44 +
 contrib/modules/dnn/src/opencl/col2im.cl           |    62 +
 contrib/modules/dnn/src/opencl/im2col.cl           |    10 +-
 contrib/modules/dnn/src/opencl/lrn.cl              |    76 +
 contrib/modules/dnn/src/opencl/pooling.cl          |    94 +
 contrib/modules/dnn/src/opencl/softmax.cl          |    75 +
 contrib/modules/dnn/src/precomp.hpp                |     1 +
 .../modules/dnn/src/tensorflow/attr_value.proto    |    60 +
 contrib/modules/dnn/src/tensorflow/function.proto  |    95 +
 contrib/modules/dnn/src/tensorflow/graph.proto     |   112 +
 contrib/modules/dnn/src/tensorflow/op_def.proto    |   157 +
 contrib/modules/dnn/src/tensorflow/tensor.proto    |    68 +
 .../modules/dnn/src/tensorflow/tensor_shape.proto  |    45 +
 contrib/modules/dnn/src/tensorflow/tf_importer.cpp |   749 +
 contrib/modules/dnn/src/tensorflow/tf_io.cpp       |    63 +
 contrib/modules/dnn/src/tensorflow/tf_io.hpp       |    29 +
 contrib/modules/dnn/src/tensorflow/types.proto     |    60 +
 contrib/modules/dnn/src/tensorflow/versions.proto  |    31 +
 contrib/modules/dnn/src/torch/torch_importer.cpp   |    36 +-
 contrib/modules/dnn/test/cnpy.h                    |     2 +-
 contrib/modules/dnn/test/test_googlenet.cpp        |    17 +-
 contrib/modules/dnn/test/test_layers.cpp           |   267 +-
 contrib/modules/dnn/test/test_main.cpp             |    28 +
 contrib/modules/dnn/test/test_tf_importer.cpp      |    51 +
 contrib/modules/dnn/testdata/dnn/.gitignore        |     1 +
 .../dnn/tutorials/tutorial_dnn_build.markdown      |     8 +-
 .../dnn/tutorials/tutorial_dnn_googlenet.markdown  |    10 +-
 contrib/modules/dnns_easily_fooled/.gitignore      |    29 +
 contrib/modules/dpm/src/dpm_convolution.cpp        |    38 +-
 contrib/modules/dpm/src/dpm_nms.cpp                |     1 +
 contrib/modules/face/README.md                     |    10 +-
 .../data/cascades/haarcascade_mcs_eyepair_big.xml  |     4 +-
 .../cascades/haarcascade_mcs_eyepair_small.xml     |     4 +-
 .../face/data/cascades/haarcascade_mcs_leftear.xml |     4 +-
 .../face/data/cascades/haarcascade_mcs_lefteye.xml |     4 +-
 .../face/data/cascades/haarcascade_mcs_mouth.xml   |     4 +-
 .../face/data/cascades/haarcascade_mcs_nose.xml    |     4 +-
 .../data/cascades/haarcascade_mcs_rightear.xml     |     4 +-
 .../data/cascades/haarcascade_mcs_righteye.xml     |     4 +-
 .../data/cascades/haarcascade_mcs_upperbody.xml    |     4 +-
 contrib/modules/face/include/opencv2/face.hpp      |     9 +-
 contrib/modules/face/include/opencv2/face/bif.hpp  |    83 +
 .../include/opencv2/face/predict_collector.hpp     |    91 +-
 contrib/modules/face/src/bif.cpp                   |   221 +
 contrib/modules/face/src/eigen_faces.cpp           |     8 +-
 contrib/modules/face/src/facerec.cpp               |    10 +-
 contrib/modules/face/src/fisher_faces.cpp          |     8 +-
 contrib/modules/face/src/lbph_faces.cpp            |     8 +-
 contrib/modules/face/src/predict_collector.cpp     |    82 +-
 contrib/modules/face/test/test_bif.cpp             |    67 +
 contrib/modules/face/test/test_main.cpp            |    41 +
 contrib/modules/face/test/test_precomp.hpp         |    56 +
 .../modules/face/tutorials/face_tutorial.markdown  |     4 +-
 contrib/modules/freetype/CMakeLists.txt            |    26 +
 contrib/modules/freetype/README.md                 |    34 +
 .../modules/freetype/include/opencv2/freetype.hpp  |   130 +
 contrib/modules/freetype/src/freetype.cpp          |   502 +
 contrib/modules/freetype/src/precomp.hpp           |    60 +
 contrib/modules/fuzzy/CMakeLists.txt               |     2 +-
 .../fuzzy/include/opencv2/fuzzy/fuzzy_F0_math.hpp  |    31 +-
 .../fuzzy/include/opencv2/fuzzy/fuzzy_image.hpp    |    10 +-
 contrib/modules/fuzzy/src/fuzzy_F0_math.cpp        |   162 +-
 contrib/modules/fuzzy/src/fuzzy_image.cpp          |    37 +-
 contrib/modules/fuzzy/test/test_f0.cpp             |   164 +
 contrib/modules/fuzzy/test/test_image.cpp          |   117 +-
 contrib/modules/hdf/CMakeLists.txt                 |    37 +-
 contrib/modules/hdf/README.md                      |     6 +-
 contrib/modules/hdf/include/opencv2/hdf/hdf5.hpp   |    76 +-
 contrib/modules/hdf/src/hdf5.cpp                   |   275 +-
 contrib/modules/line_descriptor/README.md          |     6 +-
 .../include/opencv2/line_descriptor/descriptor.hpp |    15 +-
 .../modules/line_descriptor/perf/perf_matching.cpp |     2 +-
 .../line_descriptor/samples/knn_matching.cpp       |     2 +-
 .../modules/line_descriptor/src/LSDDetector.cpp    |     6 +-
 .../line_descriptor/src/binary_descriptor.cpp      |    29 +-
 .../src/binary_descriptor_matcher.cpp              |    31 +-
 contrib/modules/line_descriptor/src/bitops.hpp     |     4 +-
 .../test/test_descriptors_regression.cpp           |    15 +
 .../test/test_matcher_regression.cpp               |     2 +-
 contrib/modules/matlab/CMakeLists.txt              |    27 +-
 contrib/modules/matlab/generator/filters.pyc       |   Bin 10037 -> 0 bytes
 contrib/modules/matlab/generator/parse_tree.pyc    |   Bin 16547 -> 0 bytes
 .../matlab/include/opencv2/matlab/bridge.hpp       |     4 +
 contrib/modules/optflow/README.md                  |     6 +-
 contrib/modules/optflow/doc/optflow.bib            |    31 +
 .../modules/optflow/include/opencv2/optflow.hpp    |   163 +
 .../optflow/include/opencv2/optflow/pcaflow.hpp    |   149 +
 .../opencv2/optflow/sparse_matching_gpc.hpp        |   380 +
 contrib/modules/optflow/perf/perf_deepflow.cpp     |    69 +
 contrib/modules/optflow/perf/perf_disflow.cpp      |   103 +
 contrib/modules/optflow/perf/perf_main.cpp         |     3 +
 contrib/modules/optflow/perf/perf_precomp.hpp      |    17 +
 .../optflow/perf/perf_variational_refinement.cpp   |    77 +
 contrib/modules/optflow/samples/gpc_evaluate.cpp   |   164 +
 contrib/modules/optflow/samples/gpc_train.cpp      |    66 +
 .../optflow/samples/gpc_train_middlebury.py        |    58 +
 .../modules/optflow/samples/gpc_train_sintel.py    |    60 +
 contrib/modules/optflow/samples/motempl.py         |    26 +-
 .../optflow/samples/optical_flow_benchmark.py      |   268 +
 .../optflow/samples/optical_flow_evaluation.cpp    |    40 +-
 contrib/modules/optflow/samples/pcaflow_demo.cpp   |   172 +
 contrib/modules/optflow/samples/video.py           |   199 -
 contrib/modules/optflow/src/deepflow.cpp           |   714 +-
 contrib/modules/optflow/src/dis_flow.cpp           |  1125 +
 contrib/modules/optflow/src/learn_prior.py         |   166 +
 contrib/modules/optflow/src/motempl.cpp            |     3 +-
 .../optflow/src/opencl/sparse_matching_gpc.cl      |    69 +
 contrib/modules/optflow/src/pcaflow.cpp            |   526 +
 .../modules/optflow/src/sparse_matching_gpc.cpp    |   774 +
 .../modules/optflow/src/variational_refinement.cpp |  1191 +
 contrib/modules/optflow/test/test_OF_accuracy.cpp  |   285 +
 .../optflow/test/test_OF_reproducibility.cpp       |   159 +
 contrib/modules/optflow/test/test_simpleflow.cpp   |   190 -
 .../optflow/test/test_sparsetodenseflow.cpp        |   146 -
 contrib/modules/phase_unwrapping/CMakeLists.txt    |     2 +
 contrib/modules/phase_unwrapping/README.md         |     4 +
 .../phase_unwrapping/doc/phase_unwrapping.bib      |     9 +
 .../include/opencv2/phase_unwrapping.hpp           |    61 +
 .../phase_unwrapping/histogramphaseunwrapping.hpp  |   107 +
 .../opencv2/phase_unwrapping/phase_unwrapping.hpp  |    74 +
 .../modules/phase_unwrapping/samples/unwrap.cpp    |   125 +
 .../src/histogramphaseunwrapping.cpp               |   783 +
 contrib/modules/phase_unwrapping/src/precomp.hpp   |    49 +
 .../modules/phase_unwrapping/test/test_main.cpp    |     3 +
 .../modules/phase_unwrapping/test/test_precomp.hpp |    17 +
 .../phase_unwrapping/test/test_unwrapping.cpp      |   103 +
 .../tutorials/phase_unwrapping.markdown            |    10 +
 .../tutorials/unwrap/unwrap.markdown               |    68 +
 contrib/modules/plot/CMakeLists.txt                |     2 +-
 contrib/modules/plot/include/opencv2/plot.hpp      |    29 +-
 contrib/modules/plot/src/plot.cpp                  |    65 +-
 contrib/modules/rgbd/README.md                     |     4 +-
 contrib/modules/saliency/CMakeLists.txt            |     7 +
 contrib/modules/saliency/README.md                 |     6 +-
 contrib/modules/saliency/doc/saliency.bib          |     9 +
 .../opencv2/saliency/saliencyBaseClasses.hpp       |    18 +-
 .../saliency/saliencySpecializedClasses.hpp        |   139 +-
 .../modules/saliency/samples/computeSaliency.cpp   |    11 +
 .../modules/saliency/src/BING/objectnessBING.cpp   |     6 +-
 contrib/modules/saliency/src/saliency.cpp          |     2 +
 contrib/modules/saliency/src/staticSaliency.cpp    |     6 +-
 .../saliency/src/staticSaliencyFineGrained.cpp     |   310 +
 contrib/modules/sfm/CMakeLists.txt                 |    18 +-
 contrib/modules/sfm/README.md                      |     2 +-
 contrib/modules/sfm/cmake/FindGflags.cmake         |   582 +
 contrib/modules/sfm/cmake/FindGlog.cmake           |   210 +
 .../sfm/doc/pics/import_sagrada_familia.png        |   Bin 0 -> 92709 bytes
 contrib/modules/sfm/include/opencv2/sfm.hpp        |     2 +
 contrib/modules/sfm/include/opencv2/sfm/io.hpp     |    88 +
 .../modules/sfm/samples/import_reconstruction.cpp  |    80 +
 contrib/modules/sfm/src/io.cpp                     |    92 +
 contrib/modules/sfm/src/io/io_bundler.h            |   189 +
 contrib/modules/sfm/src/libmv_capi.h               |    29 +-
 .../src/libmv_light/libmv/multiview/CMakeLists.txt |     2 +-
 .../sfm_import_reconstruction.markdown             |    28 +
 .../sfm_trajectory_estimation.markdown             |     2 +-
 .../sfm/tutorials/table_of_content_sfm.markdown    |    10 +-
 contrib/modules/stereo/README.md                   |     2 +
 .../stereo/include/opencv2/stereo/matching.hpp     |    13 +-
 contrib/modules/structured_light/CMakeLists.txt    |     2 +-
 contrib/modules/structured_light/README.md         |     6 +-
 .../structured_light/doc/structured_light.bib      |    10 +
 .../include/opencv2/structured_light.hpp           |     1 +
 .../opencv2/structured_light/graycodepattern.hpp   |    11 +-
 .../opencv2/structured_light/sinusoidalpattern.hpp |   151 +
 .../opencv2/structured_light/structured_light.hpp  |     7 +-
 .../structured_light/samples/capsinpattern.cpp     |   335 +
 .../samples/projectorcalibration.cpp               |   517 +
 .../structured_light/src/graycodepattern.cpp       |    10 +
 .../structured_light/src/sinusoidalpattern.cpp     |   919 +
 .../modules/structured_light/test/test_faps.cpp    |   146 +
 .../capturesinpattern/capturesinpattern.markdown   |   207 +
 .../tutorials/structured_light.markdown            |    10 +-
 contrib/modules/surface_matching/README.md         |     7 +-
 contrib/modules/text/CMakeLists.txt                |    29 +-
 contrib/modules/text/FindTesseract.cmake           |    24 -
 contrib/modules/text/cmake/FindTesseract.cmake     |    23 +
 contrib/modules/text/include/opencv2/text.hpp      |     2 +-
 .../modules/text/include/opencv2/text/erfilter.hpp |    36 +-
 contrib/modules/text/include/opencv2/text/ocr.hpp  |    14 +-
 contrib/modules/text/samples/detect_er_chars.py    |    38 +
 contrib/modules/text/samples/textdetection.cpp     |     5 +-
 contrib/modules/text/samples/textdetection.py      |    58 +
 contrib/modules/text/src/erfilter.cpp              |   181 +-
 .../modules/text/src/ocr_beamsearch_decoder.cpp    |     2 +-
 contrib/modules/text/src/ocr_hmm_decoder.cpp       |    14 +-
 contrib/modules/text/test/test_detection.cpp       |    91 +
 contrib/modules/text/test/test_main.cpp            |     6 +
 contrib/modules/text/test/test_precomp.hpp         |     8 +
 contrib/modules/tracking/CMakeLists.txt            |     2 +-
 contrib/modules/tracking/README.md                 |     5 +-
 contrib/modules/tracking/doc/diagrams.markdown     |   256 -
 contrib/modules/tracking/doc/tracking.bib          |     7 +
 .../modules/tracking/include/opencv2/tracking.hpp  |     5 -
 .../include/opencv2/tracking/kalman_filters.hpp    |     4 +-
 .../include/opencv2/tracking/onlineMIL.hpp         |     2 -
 .../tracking/include/opencv2/tracking/tracker.hpp  |   405 +-
 contrib/modules/tracking/perf/perf_Tracker.cpp     |    70 +
 contrib/modules/tracking/samples/benchmark.cpp     |   718 +-
 contrib/modules/tracking/samples/goturnTracker.cpp |   217 +
 .../tracking/samples/multiTracker_dataset.cpp      |    13 +-
 .../modules/tracking/samples/tracker_dataset.cpp   |    19 +-
 .../tracking/src/augmented_unscented_kalman.cpp    |    80 +-
 contrib/modules/tracking/src/gtrTracker.cpp        |   191 +
 contrib/modules/tracking/src/gtrTracker.hpp        |    76 +
 contrib/modules/tracking/src/gtrUtils.cpp          |   146 +
 contrib/modules/tracking/src/gtrUtils.hpp          |    61 +
 contrib/modules/tracking/src/onlineMIL.cpp         |     2 +
 contrib/modules/tracking/src/precomp.hpp           |    55 +-
 contrib/modules/tracking/src/roiSelector.cpp       |    13 +-
 contrib/modules/tracking/src/tldDetector.cpp       |    74 +-
 contrib/modules/tracking/src/tldDetector.hpp       |    12 +-
 contrib/modules/tracking/src/tldModel.cpp          |    33 +-
 contrib/modules/tracking/src/tldModel.hpp          |     3 +-
 contrib/modules/tracking/src/tldTracker.cpp        |    10 +-
 contrib/modules/tracking/src/tracker.cpp           |     1 +
 contrib/modules/tracking/src/trackerKCF.cpp        |    12 +-
 contrib/modules/tracking/src/trackerMedianFlow.cpp |    11 +-
 contrib/modules/tracking/src/trackerModel.cpp      |     2 +-
 contrib/modules/tracking/src/unscented_kalman.cpp  |    78 +-
 contrib/modules/tracking/test/test_trackerOPE.cpp  |    14 +
 contrib/modules/tracking/test/test_trackerSRE.cpp  |    14 +
 contrib/modules/tracking/test/test_trackerTRE.cpp  |    16 +-
 .../tutorial_introduction_to_tracker.markdown      |     4 +-
 contrib/modules/ximgproc/README.md                 |    18 +-
 contrib/modules/ximgproc/doc/pics/corridor_fld.jpg |   Bin 0 -> 529077 bytes
 ...{slic-slico-kermit.png => superpixels_slic.png} |   Bin
 contrib/modules/ximgproc/doc/ximgproc.bib          |    70 +
 .../modules/ximgproc/include/opencv2/ximgproc.hpp  |    92 +-
 .../include/opencv2/ximgproc/deriche_filter.hpp    |    77 +
 .../include/opencv2/ximgproc/disparity_filter.hpp  |     2 +-
 .../include/opencv2/ximgproc/edge_filter.hpp       |    26 +-
 .../opencv2/ximgproc/fast_line_detector.hpp        |    81 +
 .../include/opencv2/ximgproc/paillou_filter.hpp    |    67 +
 .../include/opencv2/ximgproc/segmentation.hpp      |   202 +-
 .../ximgproc/include/opencv2/ximgproc/slic.hpp     |     2 +-
 .../opencv2/ximgproc/sparse_match_interpolator.hpp |     2 +-
 .../opencv2/ximgproc/weighted_median_filter.hpp    |    95 +
 .../ximgproc/perf/perf_adaptive_manifold.cpp       |     2 +-
 .../perf/perf_bilateral_texture_filter.cpp         |    83 +
 .../ximgproc/perf/perf_disparity_wls_filter.cpp    |     2 +-
 .../ximgproc/perf/perf_domain_transform.cpp        |     2 +-
 contrib/modules/ximgproc/perf/perf_fgs_filter.cpp  |     2 +-
 .../modules/ximgproc/perf/perf_guided_filter.cpp   |     2 +-
 contrib/modules/ximgproc/perf/perf_l0_smooth.cpp   |     2 +-
 .../ximgproc/perf/perf_rolling_guidance_filter.cpp |     2 +-
 .../ximgproc/perf/perf_weighted_median_filter.cpp  |    88 +
 .../ximgproc/perf/pref_joint_bilateral_filter.cpp  |     2 +-
 .../samples/cpp/graphsegmentation_demo.cpp         |   151 -
 contrib/modules/ximgproc/samples/deriche_demo.cpp  |   120 +
 contrib/modules/ximgproc/samples/fld_lines.cpp     |    91 +
 .../ximgproc/samples/graphsegmentation_demo.cpp    |   154 +
 contrib/modules/ximgproc/samples/live_demo.cpp     |     2 +-
 .../ximgproc/samples/niblack_thresholding.cpp      |    47 +-
 contrib/modules/ximgproc/samples/paillou_demo.cpp  |   107 +
 .../samples/selectivesearchsegmentation_demo.cpp   |   115 +
 contrib/modules/ximgproc/samples/slic.cpp          |   138 +
 .../ximgproc/samples/structured_edge_detection.cpp |    50 +-
 contrib/modules/ximgproc/samples/thinning.cpp      |    44 +
 .../ximgproc/src/adaptive_manifold_filter_n.cpp    |     2 +-
 .../ximgproc/src/bilateral_texture_filter.cpp      |   357 +
 contrib/modules/ximgproc/src/deriche_filter.cpp    |   430 +
 contrib/modules/ximgproc/src/disparity_filters.cpp |     2 +-
 contrib/modules/ximgproc/src/domain_transform.cpp  |     2 +-
 contrib/modules/ximgproc/src/dtfilter_cpu.cpp      |     2 +-
 contrib/modules/ximgproc/src/dtfilter_cpu.hpp      |     2 +-
 contrib/modules/ximgproc/src/dtfilter_cpu.inl.hpp  |     2 +-
 .../ximgproc/src/edgeaware_filters_common.cpp      |     2 +-
 .../ximgproc/src/edgeaware_filters_common.hpp      |     2 +-
 .../modules/ximgproc/src/fast_line_detector.cpp    |   730 +
 contrib/modules/ximgproc/src/fgs_filter.cpp        |     2 +-
 contrib/modules/ximgproc/src/graphsegmentation.cpp |    62 +
 contrib/modules/ximgproc/src/guided_filter.cpp     |    11 +-
 .../ximgproc/src/joint_bilateral_filter.cpp        |     2 +-
 contrib/modules/ximgproc/src/l0_smooth.cpp         |    10 +-
 contrib/modules/ximgproc/src/lsc.cpp               |     6 +-
 .../modules/ximgproc/src/niblack_thresholding.cpp  |    83 +-
 contrib/modules/ximgproc/src/paillou_filter.cpp    |   486 +
 contrib/modules/ximgproc/src/precomp.hpp           |     2 +-
 .../ximgproc/src/rolling_guidance_filter.cpp       |     2 +-
 contrib/modules/ximgproc/src/seeds.cpp             |    28 +-
 .../ximgproc/src/selectivesearchsegmentation.cpp   |  1108 +
 contrib/modules/ximgproc/src/slic.cpp              |    11 +-
 .../ximgproc/src/sparse_match_interpolators.cpp    |     2 +-
 .../ximgproc/src/structured_edge_detection.cpp     |     7 +-
 contrib/modules/ximgproc/src/thinning.cpp          |    92 +
 .../ximgproc/src/weighted_median_filter.cpp        |   723 +
 .../ximgproc/test/test_adaptive_manifold.cpp       |     2 +-
 .../test/test_adaptive_manifold_ref_impl.cpp       |     6 +-
 .../test/test_bilateral_texture_filter.cpp         |   141 +
 .../ximgproc/test/test_disparity_wls_filter.cpp    |     2 +-
 .../ximgproc/test/test_domain_transform.cpp        |     2 +-
 contrib/modules/ximgproc/test/test_fgs_filter.cpp  |     2 +-
 contrib/modules/ximgproc/test/test_fld.cpp         |   173 +
 .../modules/ximgproc/test/test_guided_filter.cpp   |    43 +-
 .../ximgproc/test/test_joint_bilateral_filter.cpp  |     2 +-
 contrib/modules/ximgproc/test/test_l0_smooth.cpp   |     2 +-
 .../ximgproc/test/test_rolling_guidance_filter.cpp |     2 +-
 .../test/test_sparse_match_interpolator.cpp        |     2 +-
 contrib/modules/ximgproc/test/test_thinning.cpp    |    54 +
 .../ximgproc/test/test_weighted_median_filter.cpp  |   107 +
 .../tutorials/disparity_filtering.markdown         |     2 +-
 contrib/modules/xobjdetect/CMakeLists.txt          |     2 +-
 contrib/modules/xobjdetect/README.md               |     5 +-
 contrib/modules/xobjdetect/src/precomp.hpp         |     1 -
 .../tools/waldboost_detector/CMakeLists.txt        |     3 +-
 contrib/modules/xphoto/doc/xphoto.bib              |     8 +
 contrib/modules/xphoto/include/opencv2/xphoto.hpp  |     1 +
 .../opencv2/xphoto/bm3d_image_denoising.hpp        |   186 +
 .../include/opencv2/xphoto/white_balance.hpp       |   223 +-
 contrib/modules/xphoto/perf/perf_grayworld.cpp     |     4 +-
 .../perf/perf_learning_based_color_balance.cpp     |    76 +
 .../xphoto/samples/bm3d_image_denoising.cpp        |    73 +
 contrib/modules/xphoto/samples/color_balance.cpp   |    68 +
 .../xphoto/samples/color_balance_benchmark.py      |   268 +
 .../xphoto/samples/grayworld_color_balance.cpp     |    62 -
 .../modules/xphoto/samples/learn_color_balance.py  |   290 +
 .../xphoto/samples/simple_color_balance.cpp        |    60 -
 .../xphoto/src/bm3d_denoising_invoker_commons.hpp  |   165 +
 .../xphoto/src/bm3d_denoising_invoker_step1.hpp    |   517 +
 .../xphoto/src/bm3d_denoising_invoker_step2.hpp    |   540 +
 .../xphoto/src/bm3d_denoising_invoker_structs.hpp  |   366 +
 .../xphoto/src/bm3d_denoising_transforms.hpp       |    73 +
 .../xphoto/src/bm3d_denoising_transforms_1D.hpp    |   376 +
 .../xphoto/src/bm3d_denoising_transforms_2D.hpp    |   511 +
 .../xphoto/src/bm3d_denoising_transforms_haar.hpp  |   290 +
 .../modules/xphoto/src/bm3d_image_denoising.cpp    |   347 +
 .../modules/xphoto/src/grayworld_white_balance.cpp |   413 +-
 contrib/modules/xphoto/src/inpainting.cpp          |     2 -
 contrib/modules/xphoto/src/kaiser_window.hpp       |   129 +
 .../xphoto/src/learning_based_color_balance.cpp    |   611 +
 .../src/learning_based_color_balance_model.hpp     |   365 +
 .../modules/xphoto/src/simple_color_balance.cpp    |   301 +-
 .../modules/xphoto/test/simple_color_balance.cpp   |    40 +-
 contrib/modules/xphoto/test/test_denoise_bm3d.cpp  |   465 +
 contrib/modules/xphoto/test/test_grayworld.cpp     |    12 +-
 .../test/test_learning_based_color_balance.cpp     |    42 +
 .../tutorials/training_white_balance.markdown      |    42 +
 contrib/samples/data/corridor.jpg                  |   Bin 0 -> 230220 bytes
 contrib/samples/python2/dis_opt_flow.py            |   114 +
 data/haarcascades/haarcascade_frontalcatface.xml   | 10587 +++--
 .../haarcascade_frontalcatface_extended.xml        |  9698 ++--
 data/haarcascades_cuda/haarcascade_upperbody.xml   |     2 +-
 data/lbpcascades/lbpcascade_frontalcatface.xml     |  3246 +-
 doc/CMakeLists.txt                                 |    20 +-
 doc/Doxyfile.in                                    |    14 +-
 doc/footer.html                                    |    69 +
 doc/header.html                                    |    30 +
 doc/mymath.js                                      |     3 +-
 doc/opencv.bib                                     |    25 +-
 doc/pattern_tools/gen_pattern.py                   |     2 +-
 .../py_bindings_basics/py_bindings_basics.markdown |     5 +-
 .../py_calibration/py_calibration.markdown         |    30 +-
 .../py_calib3d/py_pose/py_pose.markdown            |     6 +-
 .../py_core/py_basic_ops/py_basic_ops.markdown     |     2 +-
 .../py_image_arithmetics.markdown                  |     4 +-
 .../py_feature2d/py_brief/py_brief.markdown        |     8 +-
 .../py_feature2d/py_fast/py_fast.markdown          |    12 +-
 .../py_features_meaning.markdown                   |    56 +-
 .../py_feature2d/py_orb/py_orb.markdown            |     4 +-
 .../py_sift_intro/py_sift_intro.markdown           |     6 +-
 .../py_video_display/py_video_display.markdown     |     3 +-
 .../py_contour_features.markdown                   |     2 +-
 .../py_contours_more_functions.markdown            |     8 +-
 .../py_imgproc/py_filtering/py_filtering.markdown  |     2 +-
 .../py_geometric_transformations.markdown          |     2 +-
 .../py_imgproc/py_grabcut/py_grabcut.markdown      |     2 +-
 .../py_houghcircles/py_houghcircles.markdown       |     2 +-
 .../py_houghlines/py_houghlines.markdown           |     4 +-
 .../py_thresholding/py_thresholding.markdown       |     2 +-
 .../py_knn/py_knn_opencv/py_knn_opencv.markdown    |    12 +-
 .../py_knn_understanding.markdown                  |     8 +-
 .../py_svm/py_svm_opencv/py_svm_opencv.markdown    |    14 +-
 .../py_setup/py_intro/py_intro.markdown            |     2 +-
 .../py_setup_in_fedora/py_setup_in_fedora.markdown |     2 +-
 .../py_setup_in_windows.markdown                   |     2 +-
 .../camera_calibration/camera_calibration.markdown |     6 +-
 .../images/charuco_board.png                       |   Bin 0 -> 10393 bytes
 .../interactive_calibration/images/dualCircles.jpg |   Bin 0 -> 71938 bytes
 .../images/screen_charuco.jpg                      |   Bin 0 -> 85753 bytes
 .../images/screen_finish.jpg                       |   Bin 0 -> 79577 bytes
 .../interactive_calibration.markdown               |   198 +
 .../calib3d/table_of_content_calib3d.markdown      |    11 +
 .../core/adding_images/adding_images.markdown      |    62 +-
 .../basic_geometric_drawing.markdown               |   158 +-
 .../discrete_fourier_transform.markdown            |     4 +-
 .../file_input_output_with_xml_yml.markdown        |     2 +-
 .../how_to_scan_images/how_to_scan_images.markdown |     2 +-
 .../how_to_use_ippa_conversion.markdown            |     2 +-
 .../interoperability_with_OpenCV_1.markdown        |     4 +-
 .../mat_mask_operations.markdown                   |   206 +-
 .../mat_the_basic_image_container.markdown         |     2 +-
 doc/tutorials/core/table_of_content_core.markdown  |     2 +
 .../akaze_tracking/akaze_tracking.markdown         |     4 +-
 .../feature_homography/feature_homography.markdown |     2 +-
 .../corner_subpixeles/corner_subpixeles.markdown   |   101 +-
 .../generic_corner_detector.markdown               |     2 +-
 .../good_features_to_track.markdown                |    91 +-
 .../harris_detector/harris_detector.markdown       |    77 +-
 .../gpu_basics_similarity.markdown                 |     2 +-
 doc/tutorials/highgui/intelperc.markdown           |    82 -
 doc/tutorials/highgui/kinect_openni.markdown       |   138 -
 .../highgui/raster-gdal/raster_io_gdal.markdown    |   101 -
 .../highgui/table_of_content_highgui.markdown      |    33 +-
 doc/tutorials/highgui/trackbar/trackbar.markdown   |    96 +-
 .../video_input_psnr_ssim.markdown                 |   251 -
 .../highgui/video-write/video_write.markdown       |   160 -
 .../{highgui => imgcodecs}/images/gdal-io.jpg      |   Bin
 .../raster-gdal/images/gdal_flood-zone.jpg         |   Bin
 .../raster-gdal/images/gdal_heat-map.jpg           |   Bin
 .../raster-gdal/images/gdal_output.jpg             |   Bin
 .../imgcodecs/raster-gdal/raster_io_gdal.markdown  |    97 +
 .../imgcodecs/table_of_content_highgui.markdown    |    12 +
 .../erosion_dilatation/erosion_dilatation.markdown |    63 +-
 .../Morphology_1_Tutorial_Theory_Dilatation_2.png  |   Bin 0 -> 1558 bytes
 .../Morphology_1_Tutorial_Theory_Erosion_2.png     |   Bin 0 -> 1533 bytes
 .../gausian_median_blur_bilateral_filter.markdown  |   124 +-
 .../back_projection/back_projection.markdown       |     6 +-
 .../histogram_calculation.markdown                 |     2 +-
 .../histogram_comparison.markdown                  |     2 +-
 .../histogram_equalization.markdown                |     2 +-
 .../images/Template_Matching_Mask_Example.jpg      |   Bin 0 -> 79095 bytes
 .../template_matching/template_matching.markdown   |    55 +-
 .../canny_detector/canny_detector.markdown         |    61 +-
 .../copyMakeBorder/copyMakeBorder.markdown         |    58 +-
 .../distance_transform.markdown                    |     2 +-
 .../imgproc/imgtrans/filter_2d/filter_2d.markdown  |    89 +-
 .../imgtrans/hough_circle/hough_circle.markdown    |    54 +-
 .../imgtrans/hough_lines/hough_lines.markdown      |     4 +-
 .../laplace_operator/laplace_operator.markdown     |    38 +-
 .../imgproc/imgtrans/remap/remap.markdown          |     6 +-
 .../sobel_derivatives/sobel_derivatives.markdown   |    49 +-
 .../imgtrans/warp_affine/warp_affine.markdown      |     2 +-
 .../morph_lines_detection/moprh_lines_detection.md |     2 +-
 .../Morphology_2_Tutorial_Theory_Closing_2.png     |   Bin 0 -> 1383 bytes
 .../Morphology_2_Tutorial_Theory_Opening_2.png     |   Bin 0 -> 1341 bytes
 .../opening_closing_hats.markdown                  |   134 +-
 doc/tutorials/imgproc/pyramids/pyramids.markdown   |    57 +-
 .../bounding_rects_circles.markdown                |    45 +-
 .../bounding_rotated_ellipses.markdown             |     2 +-
 .../find_contours/find_contours.markdown           |     2 +-
 .../imgproc/shapedescriptors/hull/hull.markdown    |     2 +-
 .../shapedescriptors/moments/moments.markdown      |     2 +-
 .../point_polygon_test/point_polygon_test.markdown |     2 +-
 .../imgproc/table_of_content_imgproc.markdown      |     8 +
 doc/tutorials/imgproc/threshold/threshold.markdown |    44 +-
 .../Threshold_inRange_Tutorial_Result_input.jpeg   |   Bin 0 -> 35791 bytes
 .../Threshold_inRange_Tutorial_Result_output.jpeg  |   Bin 0 -> 10927 bytes
 .../threshold_inRange/threshold_inRange.markdown   |    56 +
 .../android_ocl_intro.markdown                     |     4 +-
 .../introduction/biicode/images/bii_lena.png       |   Bin 0 -> 102674 bytes
 .../building_tegra_cuda.markdown                   |   656 +
 .../clojure_dev_intro/clojure_dev_intro.markdown   |     2 +-
 .../arm_crosscompile_with_cmake.markdown           |     6 +-
 .../desktop_java/java_dev_intro.markdown           |     4 +-
 .../display_image/display_image.markdown           |     2 +-
 .../documentation_tutorial.markdown                |   100 +-
 .../introduction/ios_install/ios_install.markdown  |     4 +-
 .../introduction/linux_eclipse/images/a10.png      |   Bin 15321 -> 54961 bytes
 .../linux_eclipse/linux_eclipse.markdown           |     8 +-
 .../linux_install/linux_install.markdown           |    18 +-
 .../table_of_content_introduction.markdown         |     8 +
 .../transition_guide/transition_guide.markdown     |     2 +-
 .../windows_install/windows_install.markdown       |     9 +-
 .../windows_visual_studio_Opencv.markdown          |    10 +-
 .../introduction_to_pca.markdown                   |     4 +-
 .../ml/non_linear_svms/non_linear_svms.markdown    |     2 +-
 .../cascade_classifier/cascade_classifier.markdown |    90 +-
 .../images/visualisation_single_stage.png          |   Bin 0 -> 114233 bytes
 .../objdetect/images/visualisation_video.png       |   Bin 0 -> 284988 bytes
 doc/tutorials/objdetect/traincascade.markdown      |   354 +-
 doc/tutorials/stitching/stitcher/images/boat.jpg   |   Bin 0 -> 75172 bytes
 .../stitching/stitcher/images/budapest.jpg         |   Bin 0 -> 131409 bytes
 .../stitching/stitcher/images/newspaper.jpg        |   Bin 0 -> 129493 bytes
 doc/tutorials/stitching/stitcher/stitcher.markdown |   115 +
 .../stitching/table_of_content_stitching.markdown  |    15 +
 doc/tutorials/tutorials.markdown                   |    15 +-
 .../background_subtraction.markdown                |     2 +-
 .../images/video-input-psnr-ssim.png               |   Bin
 .../{highgui => videoio}/images/video-write.png    |   Bin
 doc/tutorials/videoio/intelperc.markdown           |    82 +
 doc/tutorials/videoio/kinect_openni.markdown       |   138 +
 .../videoio/table_of_content_videoio.markdown      |    23 +
 .../images/outputVideoInput.png                    |   Bin
 .../video_input_psnr_ssim.markdown                 |   251 +
 .../video-write/images/resultOutputWideoWrite.png  |   Bin
 .../video-write/images/videoCompressSelect.png     |   Bin
 .../video-write/images/videoFileStructure.png      |   Bin
 .../videoio/video-write/video_write.markdown       |   160 +
 .../viz/creating_widgets/creating_widgets.markdown |     2 +-
 .../viz/launching_viz/launching_viz.markdown       |     2 +-
 .../viz/transformations/transformations.markdown   |     2 +-
 doc/tutorials/viz/widget_pose/widget_pose.markdown |     2 +-
 include/opencv/cv.h                                |     4 +-
 include/opencv/cv.hpp                              |     4 +-
 include/opencv/cvaux.h                             |     4 +-
 include/opencv/cvaux.hpp                           |     4 +-
 include/opencv/cvwimage.h                          |     4 +-
 include/opencv/cxcore.h                            |     4 +-
 include/opencv/cxcore.hpp                          |     4 +-
 include/opencv/cxeigen.hpp                         |     4 +-
 include/opencv/cxmisc.h                            |     4 +-
 include/opencv/highgui.h                           |     4 +-
 include/opencv/ml.h                                |     4 +-
 include/opencv2/opencv.hpp                         |    94 +-
 modules/calib3d/doc/pics/distortion_examples.png   |   Bin 0 -> 36227 bytes
 modules/calib3d/doc/pics/pinhole_camera_model.png  |   Bin 0 -> 97238 bytes
 modules/calib3d/include/opencv2/calib3d.hpp        |   199 +-
 .../calib3d/include/opencv2/calib3d/calib3d_c.h    |     7 +-
 modules/calib3d/misc/java/test/Calib3dTest.java    |     4 +-
 modules/calib3d/perf/perf_affine2d.cpp             |   170 +
 modules/calib3d/src/calibinit.cpp                  |   734 +-
 modules/calib3d/src/calibration.cpp                |   593 +-
 modules/calib3d/src/checkchessboard.cpp            |   208 +-
 modules/calib3d/src/circlesgrid.cpp                |    20 +-
 modules/calib3d/src/compat_ptsetreg.cpp            |     2 +
 modules/calib3d/src/fisheye.cpp                    |   140 +-
 modules/calib3d/src/five-point.cpp                 |     8 +
 modules/calib3d/src/fundam.cpp                     |    50 +-
 modules/calib3d/src/homography_decomp.cpp          |     2 +-
 modules/calib3d/src/p3p.cpp                        |     2 +
 modules/calib3d/src/precomp.hpp                    |    26 +
 modules/calib3d/src/ptsetreg.cpp                   |   440 +-
 modules/calib3d/src/quadsubpix.cpp                 |     2 +
 modules/calib3d/src/rho.cpp                        |     4 +-
 modules/calib3d/src/solvepnp.cpp                   |     9 +-
 modules/calib3d/src/stereobm.cpp                   |    81 +-
 modules/calib3d/src/stereosgbm.cpp                 |   768 +-
 modules/calib3d/src/triangulate.cpp                |     4 +
 modules/calib3d/test/test_affine2d_estimator.cpp   |   130 +
 modules/calib3d/test/test_affine3d_estimator.cpp   |     2 +-
 .../test/test_affine_partial2d_estimator.cpp       |   140 +
 modules/calib3d/test/test_cameracalibration.cpp    |   260 +-
 modules/calib3d/test/test_chessboardgenerator.cpp  |     6 +-
 modules/calib3d/test/test_chesscorners.cpp         |    40 +-
 modules/calib3d/test/test_chesscorners_timing.cpp  |     6 +-
 modules/calib3d/test/test_cornerssubpix.cpp        |    14 +
 modules/calib3d/test/test_fisheye.cpp              |    42 +
 modules/calib3d/test/test_solvepnp_ransac.cpp      |    69 +-
 modules/core/CMakeLists.txt                        |     9 +-
 modules/core/doc/cuda.markdown                     |     2 +-
 modules/core/doc/intro.markdown                    |     2 +-
 modules/core/include/opencv2/core.hpp              |   236 +-
 modules/core/include/opencv2/core/affine.hpp       |    21 +-
 modules/core/include/opencv2/core/base.hpp         |     8 +-
 modules/core/include/opencv2/core/bufferpool.hpp   |     6 +-
 modules/core/include/opencv2/core/core_c.h         |    46 +-
 modules/core/include/opencv2/core/cuda.hpp         |    36 +-
 modules/core/include/opencv2/core/cuda.inl.hpp     |     6 +-
 modules/core/include/opencv2/core/cuda/block.hpp   |     6 +-
 .../opencv2/core/cuda/border_interpolate.hpp       |     6 +-
 modules/core/include/opencv2/core/cuda/color.hpp   |     6 +-
 modules/core/include/opencv2/core/cuda/common.hpp  |     6 +-
 .../include/opencv2/core/cuda/datamov_utils.hpp    |     6 +-
 .../opencv2/core/cuda/detail/color_detail.hpp      |     6 +-
 .../include/opencv2/core/cuda/detail/reduce.hpp    |    12 +-
 .../opencv2/core/cuda/detail/reduce_key_val.hpp    |     6 +-
 .../opencv2/core/cuda/detail/transform_detail.hpp  |     6 +-
 .../core/cuda/detail/type_traits_detail.hpp        |     6 +-
 .../core/cuda/detail/vec_distance_detail.hpp       |     6 +-
 .../include/opencv2/core/cuda/dynamic_smem.hpp     |     6 +-
 modules/core/include/opencv2/core/cuda/filters.hpp |     6 +-
 .../core/include/opencv2/core/cuda/funcattrib.hpp  |     6 +-
 .../core/include/opencv2/core/cuda/functional.hpp  |     6 +-
 modules/core/include/opencv2/core/cuda/limits.hpp  |     6 +-
 modules/core/include/opencv2/core/cuda/reduce.hpp  |    10 +-
 .../include/opencv2/core/cuda/saturate_cast.hpp    |    14 +-
 modules/core/include/opencv2/core/cuda/scan.hpp    |     6 +-
 .../include/opencv2/core/cuda/simd_functions.hpp   |     6 +-
 .../core/include/opencv2/core/cuda/transform.hpp   |     6 +-
 .../core/include/opencv2/core/cuda/type_traits.hpp |     6 +-
 modules/core/include/opencv2/core/cuda/utility.hpp |    15 +-
 .../include/opencv2/core/cuda/vec_distance.hpp     |     6 +-
 .../core/include/opencv2/core/cuda/vec_math.hpp    |     6 +-
 .../core/include/opencv2/core/cuda/vec_traits.hpp  |     6 +-
 modules/core/include/opencv2/core/cuda/warp.hpp    |     6 +-
 .../include/opencv2/core/cuda/warp_shuffle.hpp     |    24 +-
 .../include/opencv2/core/cuda_stream_accessor.hpp  |     6 +-
 modules/core/include/opencv2/core/cuda_types.hpp   |     6 +-
 modules/core/include/opencv2/core/cvdef.h          |   106 +-
 modules/core/include/opencv2/core/cvstd.hpp        |    19 +-
 modules/core/include/opencv2/core/cvstd.inl.hpp    |     6 +-
 modules/core/include/opencv2/core/directx.hpp      |     6 +-
 modules/core/include/opencv2/core/eigen.hpp        |     4 +-
 modules/core/include/opencv2/core/fast_math.hpp    |     5 +-
 modules/core/include/opencv2/core/hal/hal.hpp      |    76 +-
 modules/core/include/opencv2/core/hal/interface.h  |   151 +-
 modules/core/include/opencv2/core/hal/intrin.hpp   |    98 +-
 .../core/include/opencv2/core/hal/intrin_cpp.hpp   |   102 +-
 .../core/include/opencv2/core/hal/intrin_neon.hpp  |   408 +-
 .../core/include/opencv2/core/hal/intrin_sse.hpp   |   149 +-
 modules/core/include/opencv2/core/ippasync.hpp     |     4 +-
 modules/core/include/opencv2/core/mat.hpp          |   177 +-
 modules/core/include/opencv2/core/mat.inl.hpp      |    79 +-
 modules/core/include/opencv2/core/matx.hpp         |    20 +-
 modules/core/include/opencv2/core/neon_utils.hpp   |     6 +-
 modules/core/include/opencv2/core/ocl.hpp          |    20 +-
 modules/core/include/opencv2/core/ocl_genbase.hpp  |     4 +-
 .../include/opencv2/core/opencl/opencl_svm.hpp     |     6 +-
 .../runtime/autogenerated/opencl_clamdblas.hpp     |     2 +-
 .../runtime/autogenerated/opencl_clamdfft.hpp      |     2 +-
 .../opencl/runtime/autogenerated/opencl_core.hpp   |     6 +-
 .../runtime/autogenerated/opencl_core_wrappers.hpp |     2 +-
 .../opencl/runtime/autogenerated/opencl_gl.hpp     |    10 +-
 .../runtime/autogenerated/opencl_gl_wrappers.hpp   |     6 +-
 .../core/opencl/runtime/opencl_clamdblas.hpp       |     6 +-
 .../core/opencl/runtime/opencl_clamdfft.hpp        |     6 +-
 .../opencv2/core/opencl/runtime/opencl_core.hpp    |     6 +-
 .../core/opencl/runtime/opencl_core_wrappers.hpp   |     6 +-
 .../opencv2/core/opencl/runtime/opencl_gl.hpp      |     6 +-
 .../core/opencl/runtime/opencl_gl_wrappers.hpp     |     6 +-
 .../opencv2/core/opencl/runtime/opencl_svm_20.hpp  |     6 +-
 .../core/opencl/runtime/opencl_svm_definitions.hpp |     6 +-
 .../opencl/runtime/opencl_svm_hsa_extension.hpp    |     6 +-
 modules/core/include/opencv2/core/opengl.hpp       |     6 +-
 .../core/include/opencv2/core/openvx/ovx_defs.hpp  |    40 +
 modules/core/include/opencv2/core/operations.hpp   |     4 +-
 modules/core/include/opencv2/core/optim.hpp        |     4 +-
 modules/core/include/opencv2/core/ovx.hpp          |    28 +
 modules/core/include/opencv2/core/persistence.hpp  |   145 +-
 modules/core/include/opencv2/core/private.cuda.hpp |     8 +-
 modules/core/include/opencv2/core/private.hpp      |   218 +-
 modules/core/include/opencv2/core/ptr.inl.hpp      |    20 +-
 modules/core/include/opencv2/core/saturate.hpp     |     6 +-
 modules/core/include/opencv2/core/sse_utils.hpp    |     6 +-
 modules/core/include/opencv2/core/traits.hpp       |     6 +-
 modules/core/include/opencv2/core/types.hpp        |    44 +-
 modules/core/include/opencv2/core/types_c.h        |     9 +-
 modules/core/include/opencv2/core/utility.hpp      |   308 +-
 modules/core/include/opencv2/core/va_intel.hpp     |     6 +-
 modules/core/include/opencv2/core/version.hpp      |     8 +-
 modules/core/include/opencv2/core/wimage.hpp       |     4 +-
 modules/core/misc/java/test/CoreTest.java          |     2 +-
 modules/core/misc/java/test/MatTest.java           |     2 +-
 modules/core/perf/opencl/perf_arithm.cpp           |    31 +-
 modules/core/perf/perf_convertTo.cpp               |     8 +-
 modules/core/perf/perf_io_base64.cpp               |    86 +
 modules/core/perf/perf_math.cpp                    |    14 +
 modules/core/perf/perf_merge.cpp                   |     7 +-
 modules/core/perf/perf_split.cpp                   |     4 +
 modules/core/perf/perf_umat.cpp                    |     3 -
 modules/core/src/algorithm.cpp                     |     6 +-
 modules/core/src/arithm.cpp                        |   102 +-
 modules/core/src/arithm_core.hpp                   |    20 +-
 modules/core/src/arithm_simd.hpp                   |    28 +-
 modules/core/src/array.cpp                         |    20 +-
 modules/core/src/convert.cpp                       |   547 +-
 modules/core/src/copy.cpp                          |   183 +-
 modules/core/src/cuda/gpu_mat.cu                   |    88 +
 modules/core/src/cuda_info.cpp                     |     1 +
 modules/core/src/dxt.cpp                           |  2174 +-
 modules/core/src/glob.cpp                          |     2 +
 modules/core/src/hal_internal.cpp                  |   601 +
 modules/core/src/hal_internal.hpp                  |   103 +
 modules/core/src/hal_replacement.hpp               |   690 +-
 modules/core/src/kmeans.cpp                        |     2 +
 modules/core/src/lapack.cpp                        |    87 +-
 modules/core/src/lda.cpp                           |     4 +-
 modules/core/src/mathfuncs.cpp                     |   277 +-
 modules/core/src/mathfuncs_core.cpp                |   411 +-
 modules/core/src/matmul.cpp                        |   280 +-
 modules/core/src/matop.cpp                         |    92 +
 modules/core/src/matrix.cpp                        |   456 +-
 modules/core/src/matrix_decomp.cpp                 |   158 +-
 modules/core/src/ocl.cpp                           |    35 +-
 .../autogenerated/opencl_clamdblas_impl.hpp        |   822 +-
 .../runtime/autogenerated/opencl_clamdfft_impl.hpp |   393 +-
 .../runtime/autogenerated/opencl_core_impl.hpp     |   457 +-
 .../runtime/autogenerated/opencl_gl_impl.hpp       |   227 +-
 .../core/src/opencl/runtime/generator/common.py    |    44 +-
 .../core/src/opencl/runtime/generator/generate.sh  |     0
 .../generator/template/opencl_clamdblas.hpp.in     |     2 +-
 .../generator/template/opencl_clamdfft.hpp.in      |     2 +-
 .../runtime/generator/template/opencl_core.hpp.in  |     6 +-
 .../generator/template/opencl_core_wrappers.hpp.in |     2 +-
 .../runtime/generator/template/opencl_gl.hpp.in    |    10 +-
 .../generator/template/opencl_gl_impl.hpp.in       |     4 +
 .../generator/template/opencl_gl_wrappers.hpp.in   |     6 +-
 modules/core/src/opencl/runtime/opencl_core.cpp    |    64 +-
 modules/core/src/opengl.cpp                        |    15 +
 modules/core/src/ovx.cpp                           |    72 +
 modules/core/src/parallel.cpp                      |   112 +-
 modules/core/src/pca.cpp                           |    21 +-
 modules/core/src/persistence.cpp                   |  7325 ++-
 modules/core/src/precomp.hpp                       |    12 +-
 modules/core/src/rand.cpp                          |    42 +-
 modules/core/src/stat.cpp                          |   514 +-
 modules/core/src/system.cpp                        |   274 +-
 modules/core/src/types.cpp                         |     4 +
 modules/core/src/umatrix.cpp                       |    48 +
 modules/core/test/ocl/test_arithm.cpp              |    28 +-
 modules/core/test/ocl/test_matrix_operation.cpp    |     2 +-
 modules/core/test/test_arithm.cpp                  |   133 +-
 modules/core/test/test_ds.cpp                      |     2 +-
 modules/core/test/test_dxt.cpp                     |   119 +-
 modules/core/test/test_eigen.cpp                   |     2 +-
 modules/core/test/test_hal_core.cpp                |    24 +-
 modules/core/test/test_intrin.cpp                  |   176 +-
 modules/core/test/test_intrin_utils.hpp            |    76 -
 modules/core/test/test_io.cpp                      |   584 +-
 modules/core/test/test_ippasync.cpp                |     4 +-
 modules/core/test/test_mat.cpp                     |   103 +-
 modules/core/test/test_math.cpp                    |    81 +-
 modules/core/test/test_rand.cpp                    |    17 +
 modules/core/test/test_umat.cpp                    |    47 +-
 modules/core/test/test_utils.cpp                   |    14 +
 modules/cudaarithm/include/opencv2/cudaarithm.hpp  |    22 +-
 modules/cudaarithm/perf/perf_arithm.cpp            |     4 +
 modules/cudaarithm/perf/perf_reductions.cpp        |     2 +
 modules/cudaarithm/src/cuda/reduce.cu              |     2 +-
 modules/cudaarithm/src/cuda/threshold.cu           |     4 +-
 modules/cudaarithm/test/test_arithm.cpp            |     4 +
 modules/cudaarithm/test/test_core.cpp              |     4 +
 .../cudaarithm/test/test_element_operations.cpp    |    13 +-
 modules/cudaarithm/test/test_reductions.cpp        |     5 +-
 modules/cudabgsegm/include/opencv2/cudabgsegm.hpp  |     6 +-
 modules/cudabgsegm/perf/perf_precomp.hpp           |     4 +-
 modules/cudabgsegm/src/precomp.hpp                 |     6 +-
 modules/cudabgsegm/test/test_precomp.hpp           |     4 +-
 modules/cudacodec/CMakeLists.txt                   |     2 +
 modules/cudacodec/include/opencv2/cudacodec.hpp    |     6 +-
 modules/cudacodec/perf/perf_precomp.hpp            |     4 +-
 modules/cudacodec/src/precomp.hpp                  |    10 +-
 modules/cudacodec/src/video_writer.cpp             |     6 +-
 modules/cudacodec/test/test_precomp.hpp            |     4 +-
 .../include/opencv2/cudafeatures2d.hpp             |     6 +-
 modules/cudafeatures2d/src/cuda/orb.cu             |    30 +-
 modules/cudafeatures2d/src/fast.cpp                |     2 +-
 modules/cudafeatures2d/src/orb.cpp                 |   156 +-
 modules/cudafeatures2d/test/test_features2d.cpp    |     4 +
 .../cudafilters/include/opencv2/cudafilters.hpp    |    22 +-
 modules/cudafilters/perf/perf_filters.cpp          |    42 +-
 modules/cudafilters/src/cuda/median_filter.cu      |   348 +
 modules/cudafilters/src/filtering.cpp              |   164 +-
 modules/cudafilters/test/test_filters.cpp          |    72 +-
 .../cudaimgproc/include/opencv2/cudaimgproc.hpp    |     7 +-
 modules/cudaimgproc/src/canny.cpp                  |     1 +
 modules/cudaimgproc/src/cuda/gftt.cu               |    29 +-
 modules/cudaimgproc/src/generalized_hough.cpp      |    22 -
 modules/cudaimgproc/src/gftt.cpp                   |    23 +-
 modules/cudaimgproc/src/hough_circles.cpp          |     1 +
 modules/cudaimgproc/src/hough_lines.cpp            |     1 +
 modules/cudaimgproc/src/hough_segments.cpp         |     1 +
 modules/cudaimgproc/test/test_canny.cpp            |     4 +
 modules/cudaimgproc/test/test_histogram.cpp        |     4 +
 modules/cudaimgproc/test/test_hough.cpp            |     4 +
 modules/cudalegacy/include/opencv2/cudalegacy.hpp  |     6 +-
 .../include/opencv2/cudalegacy/private.hpp         |     6 +-
 modules/cudalegacy/src/graphcuts.cpp               |     3 +-
 modules/cudalegacy/test/NCVTest.hpp                |     4 +-
 .../cudalegacy/test/TestHaarCascadeApplication.cpp |     6 +-
 modules/cudalegacy/test/test_precomp.hpp           |     2 +-
 .../include/opencv2/cudaobjdetect.hpp              |     6 +-
 modules/cudaobjdetect/test/test_objdetect.cpp      |     4 +
 .../cudaoptflow/include/opencv2/cudaoptflow.hpp    |     6 +-
 modules/cudaoptflow/perf/perf_optflow.cpp          |    14 +-
 modules/cudaoptflow/src/cuda/pyrlk.cu              |   752 +-
 modules/cudaoptflow/src/farneback.cpp              |     4 +-
 modules/cudaoptflow/src/precomp.hpp                |     2 +-
 modules/cudaoptflow/src/pyrlk.cpp                  |   181 +-
 modules/cudaoptflow/test/test_optflow.cpp          |    54 +-
 modules/cudastereo/include/opencv2/cudastereo.hpp  |     6 +-
 modules/cudastereo/test/test_stereo.cpp            |     4 +
 .../cudawarping/include/opencv2/cudawarping.hpp    |     6 +-
 modules/cudawarping/src/cuda/pyr_down.cu           |     8 +-
 modules/cudawarping/src/pyramids.cpp               |     4 +-
 modules/cudev/CMakeLists.txt                       |    11 +-
 modules/cudev/include/opencv2/cudev.hpp            |     4 +-
 .../cudev/include/opencv2/cudev/block/block.hpp    |     4 +-
 .../include/opencv2/cudev/block/detail/reduce.hpp  |     4 +-
 .../opencv2/cudev/block/detail/reduce_key_val.hpp  |     4 +-
 .../include/opencv2/cudev/block/dynamic_smem.hpp   |     4 +-
 .../cudev/include/opencv2/cudev/block/reduce.hpp   |     4 +-
 modules/cudev/include/opencv2/cudev/block/scan.hpp |     4 +-
 .../include/opencv2/cudev/block/vec_distance.hpp   |     4 +-
 modules/cudev/include/opencv2/cudev/common.hpp     |     4 +-
 .../include/opencv2/cudev/expr/binary_func.hpp     |     4 +-
 .../cudev/include/opencv2/cudev/expr/binary_op.hpp |     4 +-
 modules/cudev/include/opencv2/cudev/expr/color.hpp |     4 +-
 modules/cudev/include/opencv2/cudev/expr/deriv.hpp |     4 +-
 modules/cudev/include/opencv2/cudev/expr/expr.hpp  |     4 +-
 .../opencv2/cudev/expr/per_element_func.hpp        |     4 +-
 .../cudev/include/opencv2/cudev/expr/reduction.hpp |     4 +-
 .../include/opencv2/cudev/expr/unary_func.hpp      |     4 +-
 .../cudev/include/opencv2/cudev/expr/unary_op.hpp  |     4 +-
 .../cudev/include/opencv2/cudev/expr/warping.hpp   |     4 +-
 .../include/opencv2/cudev/functional/color_cvt.hpp |     4 +-
 .../opencv2/cudev/functional/detail/color_cvt.hpp  |     4 +-
 .../opencv2/cudev/functional/functional.hpp        |    25 +-
 .../opencv2/cudev/functional/tuple_adapter.hpp     |     4 +-
 modules/cudev/include/opencv2/cudev/grid/copy.hpp  |     4 +-
 .../include/opencv2/cudev/grid/detail/copy.hpp     |     4 +-
 .../opencv2/cudev/grid/detail/histogram.hpp        |     4 +-
 .../include/opencv2/cudev/grid/detail/integral.hpp |     4 +-
 .../opencv2/cudev/grid/detail/minmaxloc.hpp        |     4 +-
 .../include/opencv2/cudev/grid/detail/pyr_down.hpp |     4 +-
 .../include/opencv2/cudev/grid/detail/pyr_up.hpp   |     4 +-
 .../include/opencv2/cudev/grid/detail/reduce.hpp   |     4 +-
 .../opencv2/cudev/grid/detail/reduce_to_column.hpp |     4 +-
 .../opencv2/cudev/grid/detail/reduce_to_row.hpp    |     4 +-
 .../opencv2/cudev/grid/detail/split_merge.hpp      |     4 +-
 .../opencv2/cudev/grid/detail/transform.hpp        |     4 +-
 .../opencv2/cudev/grid/detail/transpose.hpp        |     4 +-
 .../cudev/include/opencv2/cudev/grid/histogram.hpp |     4 +-
 .../cudev/include/opencv2/cudev/grid/integral.hpp  |     4 +-
 .../cudev/include/opencv2/cudev/grid/pyramids.hpp  |     4 +-
 .../cudev/include/opencv2/cudev/grid/reduce.hpp    |     4 +-
 .../include/opencv2/cudev/grid/reduce_to_vec.hpp   |     8 +-
 .../include/opencv2/cudev/grid/split_merge.hpp     |     4 +-
 .../cudev/include/opencv2/cudev/grid/transform.hpp |     4 +-
 .../cudev/include/opencv2/cudev/grid/transpose.hpp |     4 +-
 .../cudev/include/opencv2/cudev/ptr2d/constant.hpp |     4 +-
 .../cudev/include/opencv2/cudev/ptr2d/deriv.hpp    |     4 +-
 .../include/opencv2/cudev/ptr2d/detail/gpumat.hpp  |     4 +-
 .../include/opencv2/cudev/ptr2d/extrapolation.hpp  |     4 +-
 modules/cudev/include/opencv2/cudev/ptr2d/glob.hpp |     4 +-
 .../cudev/include/opencv2/cudev/ptr2d/gpumat.hpp   |     4 +-
 .../include/opencv2/cudev/ptr2d/interpolation.hpp  |     4 +-
 modules/cudev/include/opencv2/cudev/ptr2d/lut.hpp  |     4 +-
 modules/cudev/include/opencv2/cudev/ptr2d/mask.hpp |     4 +-
 .../cudev/include/opencv2/cudev/ptr2d/remap.hpp    |     4 +-
 .../cudev/include/opencv2/cudev/ptr2d/resize.hpp   |     4 +-
 .../cudev/include/opencv2/cudev/ptr2d/texture.hpp  |     4 +-
 .../cudev/include/opencv2/cudev/ptr2d/traits.hpp   |     4 +-
 .../include/opencv2/cudev/ptr2d/transform.hpp      |     4 +-
 .../cudev/include/opencv2/cudev/ptr2d/warping.hpp  |     4 +-
 modules/cudev/include/opencv2/cudev/ptr2d/zip.hpp  |     4 +-
 .../cudev/include/opencv2/cudev/util/atomic.hpp    |     4 +-
 .../include/opencv2/cudev/util/detail/tuple.hpp    |     4 +-
 .../opencv2/cudev/util/detail/type_traits.hpp      |     4 +-
 .../cudev/include/opencv2/cudev/util/limits.hpp    |     4 +-
 .../include/opencv2/cudev/util/saturate_cast.hpp   |    15 +-
 .../include/opencv2/cudev/util/simd_functions.hpp  |     4 +-
 modules/cudev/include/opencv2/cudev/util/tuple.hpp |     4 +-
 .../include/opencv2/cudev/util/type_traits.hpp     |     4 +-
 .../cudev/include/opencv2/cudev/util/vec_math.hpp  |     4 +-
 .../include/opencv2/cudev/util/vec_traits.hpp      |     4 +-
 .../include/opencv2/cudev/warp/detail/reduce.hpp   |     4 +-
 .../opencv2/cudev/warp/detail/reduce_key_val.hpp   |     4 +-
 .../cudev/include/opencv2/cudev/warp/reduce.hpp    |     4 +-
 modules/cudev/include/opencv2/cudev/warp/scan.hpp  |     4 +-
 .../cudev/include/opencv2/cudev/warp/shuffle.hpp   |     4 +-
 modules/cudev/include/opencv2/cudev/warp/warp.hpp  |     4 +-
 modules/cudev/test/CMakeLists.txt                  |    15 +-
 modules/cudev/test/test_cvt.cu                     |    67 +
 modules/cudev/test/test_reduction.cu               |    12 -
 modules/features2d/doc/agast.txt                   |   170 +-
 modules/features2d/doc/agast_score.txt             |   112 +-
 modules/features2d/include/opencv2/features2d.hpp  |    76 +-
 modules/features2d/misc/java/filelist              |     1 +
 modules/features2d/misc/java/filelist_common       |     1 +
 .../misc/java/src/cpp/features2d_converters.hpp    |     3 +-
 .../misc/java/src/cpp/features2d_manual.hpp        |   137 +-
 .../java/test/BRIEFDescriptorExtractorTest.java    |    14 +-
 .../java/test/BruteForceDescriptorMatcherTest.java |    21 +-
 .../BruteForceHammingDescriptorMatcherTest.java    |    11 +-
 .../BruteForceHammingLUTDescriptorMatcherTest.java |     9 +-
 .../test/BruteForceL1DescriptorMatcherTest.java    |    23 +-
 .../test/BruteForceSL2DescriptorMatcherTest.java   |    21 +-
 .../java/test/DynamicDENSEFeatureDetectorTest.java |    39 -
 .../java/test/DynamicFASTFeatureDetectorTest.java  |    39 -
 .../java/test/DynamicGFTTFeatureDetectorTest.java  |    39 -
 .../test/DynamicHARRISFeatureDetectorTest.java     |    39 -
 .../java/test/DynamicMSERFeatureDetectorTest.java  |    39 -
 .../java/test/DynamicORBFeatureDetectorTest.java   |    39 -
 .../java/test/DynamicSIFTFeatureDetectorTest.java  |    39 -
 .../test/DynamicSIMPLEBLOBFeatureDetectorTest.java |    39 -
 .../java/test/DynamicSTARFeatureDetectorTest.java  |    39 -
 .../java/test/DynamicSURFFeatureDetectorTest.java  |    39 -
 .../misc/java/test/FASTFeatureDetectorTest.java    |    13 +-
 .../features2d/misc/java/test/Features2dTest.java  |    11 +-
 .../test/FernGenericDescriptorMatcherTest.java     |   127 -
 .../java/test/FlannBasedDescriptorMatcherTest.java |    23 +-
 .../java/test/GridDENSEFeatureDetectorTest.java    |    39 -
 .../java/test/GridFASTFeatureDetectorTest.java     |    39 -
 .../java/test/GridGFTTFeatureDetectorTest.java     |    39 -
 .../java/test/GridHARRISFeatureDetectorTest.java   |    39 -
 .../java/test/GridMSERFeatureDetectorTest.java     |    39 -
 .../misc/java/test/GridORBFeatureDetectorTest.java |    39 -
 .../java/test/GridSIFTFeatureDetectorTest.java     |    39 -
 .../test/GridSIMPLEBLOBFeatureDetectorTest.java    |    39 -
 .../java/test/GridSTARFeatureDetectorTest.java     |    39 -
 .../java/test/GridSURFFeatureDetectorTest.java     |    39 -
 .../misc/java/test/ORBDescriptorExtractorTest.java |    21 +-
 .../test/OneWayGenericDescriptorMatcherTest.java   |   127 -
 .../test/OpponentBRIEFDescriptorExtractorTest.java |    39 -
 .../test/OpponentORBDescriptorExtractorTest.java   |    39 -
 .../test/OpponentSIFTDescriptorExtractorTest.java  |    39 -
 .../test/OpponentSURFDescriptorExtractorTest.java  |    39 -
 .../java/test/PyramidDENSEFeatureDetectorTest.java |    39 -
 .../java/test/PyramidFASTFeatureDetectorTest.java  |    39 -
 .../java/test/PyramidGFTTFeatureDetectorTest.java  |    39 -
 .../test/PyramidHARRISFeatureDetectorTest.java     |    39 -
 .../java/test/PyramidMSERFeatureDetectorTest.java  |    39 -
 .../java/test/PyramidORBFeatureDetectorTest.java   |    39 -
 .../java/test/PyramidSIFTFeatureDetectorTest.java  |    39 -
 .../test/PyramidSIMPLEBLOBFeatureDetectorTest.java |    39 -
 .../java/test/PyramidSTARFeatureDetectorTest.java  |    39 -
 .../java/test/PyramidSURFFeatureDetectorTest.java  |    39 -
 .../java/test/SIFTDescriptorExtractorTest.java     |    16 +-
 .../misc/java/test/STARFeatureDetectorTest.java    |    18 +-
 .../java/test/SURFDescriptorExtractorTest.java     |    23 +-
 .../misc/java/test/SURFFeatureDetectorTest.java    |    42 +-
 .../features2d/misc/python/pyopencv_features2d.hpp |     3 +
 modules/features2d/perf/opencl/perf_orb.cpp        |    21 +-
 modules/features2d/perf/perf_orb.cpp               |    17 +-
 modules/features2d/src/agast.cpp                   |   234 +-
 modules/features2d/src/agast_score.cpp             |   122 +-
 modules/features2d/src/akaze.cpp                   |     5 +
 modules/features2d/src/bagofwords.cpp              |    14 +-
 modules/features2d/src/blobdetector.cpp            |     5 +
 modules/features2d/src/brisk.cpp                   |     4 +-
 modules/features2d/src/draw.cpp                    |     2 +
 modules/features2d/src/evaluation.cpp              |    12 +
 modules/features2d/src/fast.cpp                    |    71 +
 modules/features2d/src/feature2d.cpp               |    30 +
 modules/features2d/src/gftt.cpp                    |     2 +
 modules/features2d/src/kaze.cpp                    |     3 +
 modules/features2d/src/kaze/AKAZEFeatures.cpp      |    25 +-
 modules/features2d/src/kaze/AKAZEFeatures.h        |     1 +
 modules/features2d/src/matchers.cpp                |   113 +-
 modules/features2d/src/mser.cpp                    |    70 +-
 modules/features2d/src/orb.cpp                     |     8 +-
 .../features2d/test/test_detectors_regression.cpp  |    20 +
 modules/features2d/test/test_mser.cpp              |     2 +-
 modules/features2d/test/test_orb.cpp               |    33 +
 .../test/test_rotation_and_scale_invariance.cpp    |    78 +-
 modules/flann/include/opencv2/flann.hpp            |   236 +-
 modules/flann/include/opencv2/flann/any.h          |     3 +-
 modules/flann/include/opencv2/flann/kmeans_index.h |     2 +
 modules/flann/include/opencv2/flann/lsh_table.h    |     2 +-
 modules/flann/include/opencv2/flann/miniflann.hpp  |     4 +-
 modules/flann/misc/python/pyopencv_flann.hpp       |    79 +
 modules/flann/src/miniflann.cpp                    |    24 +-
 modules/flann/src/precomp.hpp                      |     4 +-
 modules/flann/test/test_precomp.hpp                |     4 +-
 modules/highgui/CMakeLists.txt                     |     4 +-
 modules/highgui/include/opencv2/highgui.hpp        |    66 +-
 .../highgui/include/opencv2/highgui/highgui_c.h    |     9 +-
 modules/highgui/src/precomp.hpp                    |    17 +-
 modules/highgui/src/window.cpp                     |    62 +-
 modules/highgui/src/window_QT.cpp                  |   307 +-
 modules/highgui/src/window_QT.h                    |    48 +-
 modules/highgui/src/window_cocoa.mm                |    77 +-
 modules/highgui/src/window_gtk.cpp                 |   120 +-
 modules/highgui/test/test_precomp.hpp              |    12 -
 modules/imgcodecs/CMakeLists.txt                   |    12 +-
 modules/imgcodecs/include/opencv2/imgcodecs.hpp    |    26 +-
 .../include/opencv2/imgcodecs/imgcodecs_c.h        |    21 +-
 modules/imgcodecs/src/exif.cpp                     |   625 +
 modules/imgcodecs/src/exif.hpp                     |   253 +
 modules/imgcodecs/src/grfmt_gdal.cpp               |     2 +-
 modules/imgcodecs/src/grfmt_gdcm.cpp               |   197 +
 modules/imgcodecs/src/grfmt_gdcm.hpp               |    70 +
 modules/imgcodecs/src/grfmt_jpeg.cpp               |    59 -
 modules/imgcodecs/src/grfmt_jpeg.hpp               |     6 -
 modules/imgcodecs/src/grfmt_jpeg2000.cpp           |     2 +-
 modules/imgcodecs/src/grfmt_pam.cpp                |   719 +
 modules/imgcodecs/src/grfmt_pam.hpp                |    99 +
 modules/imgcodecs/src/grfmt_png.cpp                |    28 +-
 modules/imgcodecs/src/grfmt_pxm.cpp                |     9 +-
 modules/imgcodecs/src/grfmts.hpp                   |     2 +
 modules/imgcodecs/src/ios_conversions.mm           |     6 +-
 modules/imgcodecs/src/jpeg_exif.cpp                |   611 -
 modules/imgcodecs/src/jpeg_exif.hpp                |   253 -
 modules/imgcodecs/src/loadsave.cpp                 |    92 +-
 modules/imgcodecs/src/precomp.hpp                  |     8 -
 modules/imgcodecs/src/rgbe.cpp                     |     4 +-
 modules/imgcodecs/test/test_drawing.cpp            |   528 -
 modules/imgcodecs/test/test_grfmt.cpp              |    52 +-
 modules/imgproc/doc/colors.markdown                |     2 +-
 modules/imgproc/doc/pics/delaunay_voronoi.png      |   Bin 0 -> 14648 bytes
 modules/imgproc/doc/pics/polar_remap_doc.png       |   Bin 0 -> 303653 bytes
 modules/imgproc/doc/pics/polar_remap_doc.svg       |  3776 ++
 modules/imgproc/include/opencv2/imgproc.hpp        |   487 +-
 .../opencv2/imgproc/detail/distortion_model.hpp    |     6 +-
 .../imgproc/include/opencv2/imgproc/hal/hal.hpp    |   189 +
 .../include/opencv2/imgproc/hal/interface.h        |    26 +
 .../imgproc/include/opencv2/imgproc/imgproc_c.h    |     4 +-
 modules/imgproc/include/opencv2/imgproc/types_c.h  |     4 +-
 .../misc/java/src/java/imgproc+Moments.java        |    20 +-
 modules/imgproc/misc/java/test/ImgprocTest.java    |    12 +-
 modules/imgproc/perf/opencl/perf_imgproc.cpp       |    21 +-
 modules/imgproc/perf/perf_blur.cpp                 |     2 -
 modules/imgproc/perf/perf_houghLines.cpp           |    48 +-
 modules/imgproc/perf/perf_threshold.cpp            |     2 +-
 modules/imgproc/src/accum.cpp                      |  1508 +-
 modules/imgproc/src/approx.cpp                     |     2 +
 modules/imgproc/src/blend.cpp                      |     2 +
 modules/imgproc/src/canny.cpp                      |   832 +-
 modules/imgproc/src/clahe.cpp                      |    28 +-
 modules/imgproc/src/color.cpp                      |  4791 +-
 modules/imgproc/src/colormap.cpp                   |    15 +-
 modules/imgproc/src/connectedcomponents.cpp        |  1401 +-
 modules/imgproc/src/contours.cpp                   |   342 +-
 modules/imgproc/src/convhull.cpp                   |    13 +-
 modules/imgproc/src/corner.cpp                     |    34 +-
 modules/imgproc/src/cornersubpix.cpp               |     2 +
 modules/imgproc/src/demosaicing.cpp                |     2 +
 modules/imgproc/src/deriv.cpp                      |   340 +-
 modules/imgproc/src/distransform.cpp               |    14 +-
 modules/imgproc/src/drawing.cpp                    |   451 +-
 modules/imgproc/src/emd.cpp                        |    12 +-
 modules/imgproc/src/featureselect.cpp              |   103 +-
 modules/imgproc/src/filter.cpp                     |  1046 +-
 modules/imgproc/src/filterengine.hpp               |    14 +-
 modules/imgproc/src/floodfill.cpp                  |     6 +-
 modules/imgproc/src/generalized_hough.cpp          |     2 +
 modules/imgproc/src/geometry.cpp                   |     4 +
 modules/imgproc/src/grabcut.cpp                    |     4 +-
 modules/imgproc/src/hal_replacement.hpp            |   647 +
 modules/imgproc/src/histogram.cpp                  |   136 +-
 modules/imgproc/src/hough.cpp                      |    14 +-
 modules/imgproc/src/imgwarp.cpp                    |   847 +-
 modules/imgproc/src/intersection.cpp               |     2 +
 modules/imgproc/src/linefit.cpp                    |     2 +
 modules/imgproc/src/lsd.cpp                        |   210 +-
 modules/imgproc/src/matchcontours.cpp              |     2 +
 modules/imgproc/src/moments.cpp                    |    83 +-
 modules/imgproc/src/morph.cpp                      |   718 +-
 modules/imgproc/src/opencl/boxFilter3x3.cl         |   127 +
 modules/imgproc/src/opencl/canny.cl                |     7 +-
 modules/imgproc/src/opencl/clahe.cl                |     5 +-
 modules/imgproc/src/opencl/cvtcolor.cl             |   123 +-
 modules/imgproc/src/opencl/filterSmall.cl          |     1 +
 modules/imgproc/src/opencl/gaussianBlur3x3.cl      |   133 +
 modules/imgproc/src/opencl/gaussianBlur5x5.cl      |   198 +
 modules/imgproc/src/opencl/hough_lines.cl          |     8 +-
 modules/imgproc/src/opencl/integral_sum.cl         |     2 +-
 modules/imgproc/src/opencl/laplacian3.cl           |   134 +
 modules/imgproc/src/opencl/linearPolar.cl          |    69 +
 modules/imgproc/src/opencl/logPolar.cl             |    69 +
 modules/imgproc/src/opencl/match_template.cl       |     8 +-
 modules/imgproc/src/opencl/morph3x3.cl             |   119 +
 modules/imgproc/src/opencl/pyr_down.cl             |     2 +
 modules/imgproc/src/opencl/pyramid_up.cl           |   114 +
 modules/imgproc/src/opencl/remap.cl                |     4 +-
 modules/imgproc/src/opencl/sepFilter3x3.cl         |   135 +
 modules/imgproc/src/opencl/warp_affine.cl          |    14 +-
 modules/imgproc/src/opencl/warp_transform.cl       |   408 +
 modules/imgproc/src/phasecorr.cpp                  |     7 +
 modules/imgproc/src/precomp.hpp                    |     2 +
 modules/imgproc/src/pyramids.cpp                   |   124 +-
 modules/imgproc/src/rotcalipers.cpp                |     4 +
 modules/imgproc/src/samplers.cpp                   |    10 +-
 modules/imgproc/src/segmentation.cpp               |     4 +
 modules/imgproc/src/shapedescr.cpp                 |    10 +
 modules/imgproc/src/smooth.cpp                     |  1151 +-
 modules/imgproc/src/spatialgradient.cpp            |   268 +-
 modules/imgproc/src/subdivision2d.cpp              |    30 +
 modules/imgproc/src/sumpixels.cpp                  |   210 +-
 modules/imgproc/src/templmatch.cpp                 |    44 +-
 modules/imgproc/src/thresh.cpp                     |  1158 +-
 modules/imgproc/src/undistort.cpp                  |    66 +-
 modules/imgproc/test/ocl/test_boxfilter.cpp        |    74 +
 modules/imgproc/test/ocl/test_canny.cpp            |    43 +-
 modules/imgproc/test/ocl/test_color.cpp            |    24 +-
 modules/imgproc/test/ocl/test_filters.cpp          |   326 +-
 modules/imgproc/test/ocl/test_histogram.cpp        |     4 +-
 modules/imgproc/test/ocl/test_houghlines.cpp       |    10 +-
 modules/imgproc/test/ocl/test_imgproc.cpp          |     6 +-
 modules/imgproc/test/ocl/test_match_template.cpp   |     2 +-
 modules/imgproc/test/ocl/test_medianfilter.cpp     |     2 +-
 modules/imgproc/test/ocl/test_pyramids.cpp         |    25 +
 modules/imgproc/test/ocl/test_warp.cpp             |   106 +
 modules/imgproc/test/test_canny.cpp                |   150 +-
 modules/imgproc/test/test_connectedcomponents.cpp  |    85 +-
 modules/imgproc/test/test_contours.cpp             |   106 +-
 modules/imgproc/test/test_convhull.cpp             |    57 +
 modules/imgproc/test/test_drawing.cpp              |   729 +
 modules/imgproc/test/test_filter.cpp               |    50 +
 modules/imgproc/test/test_fitellipse.cpp           |    70 +
 modules/imgproc/test/test_floodfill.cpp            |    14 +
 modules/imgproc/test/test_houghLines.cpp           |     2 +-
 modules/imgproc/test/test_imgwarp.cpp              |    82 +
 modules/imgproc/test/test_imgwarp_strict.cpp       |    31 +
 modules/imgproc/test/test_thresh.cpp               |    86 +-
 modules/java/CMakeLists.txt                        |    44 +-
 .../src/org/opencv/test/OpenCVTestCase.java        |   127 +-
 modules/java/generator/gen_java.py                 |   101 +-
 modules/java/generator/src/cpp/Mat.cpp             |   220 +-
 .../src/java/android+CameraBridgeViewBase.java     |     4 +-
 .../generator/src/java/android+JavaCameraView.java |     4 +-
 .../generator/src/java/android+OpenCVLoader.java   |    14 +
 modules/java/pure_test/build.xml                   |     5 +-
 .../src/org/opencv/test/OpenCVTestCase.java        |   126 +-
 modules/ml/include/opencv2/ml.hpp                  |   191 +-
 modules/ml/misc/python/pyopencv_ml.hpp             |    22 +
 modules/ml/src/ann_mlp.cpp                         |    28 +-
 modules/ml/src/boost.cpp                           |     1 +
 modules/ml/src/data.cpp                            |    50 +-
 modules/ml/src/em.cpp                              |     6 +-
 modules/ml/src/inner_functions.cpp                 |    38 +-
 modules/ml/src/knearest.cpp                        |     1 +
 modules/ml/src/lr.cpp                              |   181 +-
 modules/ml/src/nbayes.cpp                          |     3 +-
 modules/ml/src/rtrees.cpp                          |     3 +
 modules/ml/src/svm.cpp                             |    20 +-
 modules/ml/src/svmsgd.cpp                          |   511 +
 modules/ml/src/testset.cpp                         |     2 +-
 modules/ml/src/tree.cpp                            |     9 +-
 modules/ml/test/test_mltests.cpp                   |    44 +
 modules/ml/test/test_mltests2.cpp                  |    44 +-
 modules/ml/test/test_precomp.hpp                   |     2 +
 modules/ml/test/test_save_load.cpp                 |    16 +-
 modules/ml/test/test_svmsgd.cpp                    |   318 +
 modules/objdetect/include/opencv2/objdetect.hpp    |    12 +-
 .../opencv2/objdetect/detection_based_tracker.hpp  |     8 +-
 .../include/opencv2/objdetect/objdetect_c.h        |     6 +-
 modules/objdetect/src/cascadedetect.cpp            |   136 +-
 modules/objdetect/src/detection_based_tracker.cpp  |    83 +-
 modules/objdetect/src/haar.cpp                     |    14 +-
 modules/objdetect/src/hog.cpp                      |   245 +-
 modules/objdetect/src/opencl/cascadedetect.cl      |    16 +-
 modules/objdetect/test/test_cascadeandhog.cpp      |    15 +-
 modules/photo/include/opencv2/photo.hpp            |     4 +-
 modules/photo/include/opencv2/photo/cuda.hpp       |     6 +-
 modules/photo/include/opencv2/photo/photo_c.h      |     6 +-
 modules/photo/src/align.cpp                        |    11 +
 modules/photo/src/calibrate.cpp                    |     6 +
 modules/photo/src/contrast_preserve.cpp            |     2 +
 modules/photo/src/denoising.cpp                    |    12 +
 modules/photo/src/inpaint.cpp                      |     5 +-
 modules/photo/src/merge.cpp                        |    15 +-
 modules/photo/src/npr.cpp                          |     8 +
 modules/photo/src/seamless_cloning.cpp             |     8 +
 modules/photo/src/seamless_cloning_impl.cpp        |     2 +
 modules/photo/src/tonemap.cpp                      |    15 +
 modules/photo/test/ocl/test_denoising.cpp          |     2 +-
 modules/photo/test/test_decolor.cpp                |    12 +-
 modules/python/common.cmake                        |   101 +-
 modules/python/python2/CMakeLists.txt              |    19 +-
 modules/python/python3/CMakeLists.txt              |    19 +-
 modules/python/src2/cv2.cpp                        |   361 +-
 modules/python/src2/gen2.py                        |    26 +-
 modules/python/src2/hdr_parser.py                  |    55 +-
 modules/python/test/calchist.py                    |    53 -
 modules/python/test/camera_calibration.py          |   360 -
 modules/python/test/findstereocorrespondence.py    |    25 -
 modules/python/test/goodfeatures.py                |    36 -
 modules/python/test/leak1.py                       |     9 -
 modules/python/test/leak2.py                       |    12 -
 modules/python/test/leak3.py                       |     8 -
 modules/python/test/leak4.py                       |    11 -
 modules/python/test/precornerdetect.py             |    16 -
 modules/python/test/test.py                        |   104 +-
 modules/python/test/test_calibration.py            |    71 +
 modules/python/test/test_camshift.py               |    92 +
 modules/python/test/test_dft.py                    |    46 +
 modules/python/test/test_digits.py                 |   197 +
 modules/python/test/test_facedetect.py             |    90 +
 modules/python/test/test_feature_homography.py     |   160 +
 modules/python/test/test_fitline.py                |    66 +
 modules/python/test/test_gaussian_mix.py           |    60 +
 modules/python/test/test_goodfeatures.py           |    36 +
 modules/python/test/test_grabcut.py                |    67 +
 modules/python/test/test_houghcircles.py           |    81 +
 modules/python/test/test_houghlines.py             |    65 +
 modules/python/test/test_kmeans.py                 |    70 +
 modules/python/test/test_letter_recog.py           |   167 +
 modules/python/test/test_lk_homography.py          |    96 +
 modules/python/test/test_lk_track.py               |   111 +
 modules/python/test/test_morphology.py             |    51 +
 modules/python/test/test_mser.py                   |    69 +
 modules/python/test/test_peopledetect.py           |    62 +
 modules/python/test/test_squares.py                |    96 +
 modules/python/test/test_texture_flow.py           |    44 +
 modules/python/test/test_watershed.py              |    33 +
 modules/python/test/tests_common.py                |    80 +
 modules/python/test/ticket_6.py                    |    78 -
 modules/python/test/tickets.py                     |    91 -
 modules/python/test/transformations.py             |  1707 -
 modules/python/test/tst_scene_render.py            |   119 +
 modules/shape/include/opencv2/shape.hpp            |     4 +-
 modules/shape/include/opencv2/shape/emdL1.hpp      |     4 +-
 modules/shape/include/opencv2/shape/hist_cost.hpp  |     4 +-
 .../shape/include/opencv2/shape/shape_distance.hpp |     4 +-
 .../include/opencv2/shape/shape_transformer.hpp    |     4 +-
 modules/shape/src/aff_trans.cpp                    |     7 +
 modules/shape/src/emdL1.cpp                        |     2 +
 modules/shape/src/haus_dis.cpp                     |     3 +
 modules/shape/src/hist_cost.cpp                    |    12 +
 modules/shape/src/sc_dis.cpp                       |    15 +-
 modules/shape/src/tps_trans.cpp                    |     7 +
 modules/stitching/include/opencv2/stitching.hpp    |    71 +-
 .../include/opencv2/stitching/detail/autocalib.hpp |     6 +-
 .../include/opencv2/stitching/detail/blenders.hpp  |    10 +-
 .../include/opencv2/stitching/detail/camera.hpp    |     6 +-
 .../stitching/detail/exposure_compensate.hpp       |    10 +-
 .../include/opencv2/stitching/detail/matchers.hpp  |    90 +-
 .../opencv2/stitching/detail/motion_estimators.hpp |    89 +-
 .../opencv2/stitching/detail/seam_finders.hpp      |     6 +-
 .../opencv2/stitching/detail/timelapsers.hpp       |     6 +-
 .../include/opencv2/stitching/detail/util.hpp      |    56 +-
 .../include/opencv2/stitching/detail/util_inl.hpp  |     6 +-
 .../include/opencv2/stitching/detail/warpers.hpp   |    40 +-
 .../opencv2/stitching/detail/warpers_inl.hpp       |    42 +-
 .../include/opencv2/stitching/warpers.hpp          |    15 +-
 .../stitching/misc/python/pyopencv_stitching.hpp   |     9 +
 modules/stitching/perf/opencl/perf_stitch.cpp      |    12 +-
 modules/stitching/perf/opencl/perf_warpers.cpp     |     7 +-
 modules/stitching/perf/perf_estimators.cpp         |   100 +
 modules/stitching/perf/perf_matchers.cpp           |   301 +
 modules/stitching/perf/perf_stich.cpp              |   155 +-
 modules/stitching/src/autocalib.cpp                |     3 -
 modules/stitching/src/exposure_compensate.cpp      |     4 +
 modules/stitching/src/matchers.cpp                 |   157 +
 modules/stitching/src/motion_estimators.cpp        |   284 +
 modules/stitching/src/precomp.hpp                  |     2 +
 modules/stitching/src/seam_finders.cpp             |     4 +-
 modules/stitching/src/stitcher.cpp                 |   117 +-
 modules/stitching/src/timelapsers.cpp              |     2 +
 modules/stitching/src/util_log.hpp                 |    58 +
 modules/stitching/src/warpers.cpp                  |    52 +
 modules/stitching/test/ocl/test_warpers.cpp        |    23 +-
 modules/stitching/test/test_matchers.cpp           |    29 +-
 modules/superres/include/opencv2/superres.hpp      |     6 +-
 .../include/opencv2/superres/optical_flow.hpp      |     6 +-
 modules/superres/src/btv_l1.cpp                    |     8 +
 modules/superres/src/input_array_utility.cpp       |     4 +
 modules/superres/src/optical_flow.cpp              |    12 +
 modules/superres/src/super_resolution.cpp          |     2 +
 modules/ts/CMakeLists.txt                          |    20 +
 modules/ts/include/opencv2/ts.hpp                  |    67 +-
 modules/ts/include/opencv2/ts/cuda_perf.hpp        |     6 +-
 modules/ts/include/opencv2/ts/cuda_test.hpp        |    24 +-
 modules/ts/include/opencv2/ts/ocl_perf.hpp         |    12 +-
 modules/ts/include/opencv2/ts/ocl_test.hpp         |    13 +-
 modules/ts/include/opencv2/ts/ts_ext.hpp           |    49 +-
 modules/ts/include/opencv2/ts/ts_gtest.h           |  2361 +-
 modules/ts/include/opencv2/ts/ts_perf.hpp          |    49 +-
 modules/ts/misc/run_long.py                        |    92 +
 modules/ts/misc/run_suite.py                       |    44 +-
 modules/ts/misc/run_utils.py                       |    24 +-
 modules/ts/src/ocl_test.cpp                        |     4 +-
 modules/ts/src/ts.cpp                              |   149 +-
 modules/ts/src/ts_func.cpp                         |    27 +-
 modules/ts/src/ts_gtest.cpp                        |  1497 +-
 modules/ts/src/ts_perf.cpp                         |   269 +-
 modules/video/include/opencv2/video.hpp            |     6 +-
 .../include/opencv2/video/background_segm.hpp      |     4 +-
 modules/video/include/opencv2/video/tracking.hpp   |   169 +-
 modules/video/include/opencv2/video/tracking_c.h   |     6 +-
 modules/video/perf/opencl/perf_optflow_pyrlk.cpp   |     3 -
 modules/video/perf/perf_tvl1optflow.cpp            |     4 +-
 modules/video/src/bgfg_KNN.cpp                     |    11 +-
 modules/video/src/bgfg_gaussmix2.cpp               |    92 +-
 modules/video/src/camshift.cpp                     |     4 +
 modules/video/src/kalman.cpp                       |     4 +
 modules/video/src/lkpyramid.cpp                    |   451 +-
 modules/video/src/opencl/bgfg_mog2.cl              |    23 +-
 modules/video/src/opencl/optical_flow_tvl1.cl      |     2 +-
 modules/video/src/opencl/pyrlk.cl                  |     4 +-
 modules/video/src/optflowgf.cpp                    |   233 +-
 modules/video/src/tvl1flow.cpp                     |    23 +
 modules/video/test/ocl/test_bgfg_mog2.cpp          |    32 +-
 modules/video/test/test_accum.cpp                  |     6 +-
 modules/video/test/test_ecc.cpp                    |     2 +-
 modules/video/test/test_optflowpyrlk.cpp           |    17 +-
 modules/video/test/test_tvl1optflow.cpp            |    38 +-
 modules/videoio/CMakeLists.txt                     |    21 +-
 modules/videoio/doc/pics/videoio_overview.svg      |   877 +
 modules/videoio/doc/videoio_overview.markdown      |    94 +
 modules/videoio/include/opencv2/videoio.hpp        |   873 +-
 modules/videoio/include/opencv2/videoio/cap_ios.h  |    42 +-
 .../videoio/include/opencv2/videoio/videoio_c.h    |   124 +-
 modules/videoio/src/cap.cpp                        |   209 +-
 modules/videoio/src/cap_aravis.cpp                 |   592 +
 modules/videoio/src/cap_avfoundation_mac.mm        |  1320 +
 modules/videoio/src/cap_dc1394.cpp                 |    42 +-
 modules/videoio/src/cap_dshow.cpp                  |    50 +-
 modules/videoio/src/cap_ffmpeg.cpp                 |    56 +-
 modules/videoio/src/cap_ffmpeg_impl.hpp            |   530 +-
 modules/videoio/src/cap_gphoto2.cpp                |     2 +-
 modules/videoio/src/cap_gstreamer.cpp              |    50 +-
 modules/videoio/src/cap_images.cpp                 |    23 +-
 modules/videoio/src/cap_ios_abstract_camera.mm     |    45 +-
 modules/videoio/src/cap_ios_photo_camera.mm        |    17 +-
 modules/videoio/src/cap_ios_video_camera.mm        |    69 +-
 modules/videoio/src/cap_libv4l.cpp                 |   146 +-
 modules/videoio/src/cap_mjpeg_decoder.cpp          |     2 +-
 modules/videoio/src/cap_msmf.cpp                   |    36 +-
 modules/videoio/src/cap_openni.cpp                 |     4 -
 modules/videoio/src/cap_openni2.cpp                |   480 +-
 modules/videoio/src/cap_qtkit.mm                   |     7 +
 modules/videoio/src/cap_v4l.cpp                    |   146 +-
 modules/videoio/src/cap_vfw.cpp                    |    13 +-
 modules/videoio/src/cap_ximea.cpp                  |   105 +-
 modules/videoio/src/ffmpeg_codecs.hpp              |    19 +-
 modules/videoio/src/precomp.hpp                    |     7 +-
 modules/videoio/test/test_ffmpeg.cpp               |     3 +
 modules/videostab/CMakeLists.txt                   |     2 +-
 modules/videostab/include/opencv2/videostab.hpp    |     8 +-
 .../include/opencv2/videostab/deblurring.hpp       |     4 +-
 .../include/opencv2/videostab/fast_marching.hpp    |     4 +-
 .../opencv2/videostab/fast_marching_inl.hpp        |     4 +-
 .../include/opencv2/videostab/frame_source.hpp     |     4 +-
 .../include/opencv2/videostab/global_motion.hpp    |     4 +-
 .../include/opencv2/videostab/inpainting.hpp       |     4 +-
 .../videostab/include/opencv2/videostab/log.hpp    |     4 +-
 .../include/opencv2/videostab/motion_core.hpp      |     4 +-
 .../opencv2/videostab/motion_stabilizing.hpp       |     4 +-
 .../include/opencv2/videostab/optical_flow.hpp     |     4 +-
 .../opencv2/videostab/outlier_rejection.hpp        |     4 +-
 .../include/opencv2/videostab/ring_buffer.hpp      |     4 +-
 .../include/opencv2/videostab/stabilizer.hpp       |     4 +-
 .../opencv2/videostab/wobble_suppression.hpp       |     4 +-
 modules/videostab/src/deblurring.cpp               |     4 +
 modules/videostab/src/global_motion.cpp            |     6 +
 modules/videostab/src/inpainting.cpp               |    14 +
 modules/videostab/src/motion_stabilizing.cpp       |     7 +-
 modules/videostab/src/outlier_rejection.cpp        |    25 +-
 modules/viz/include/opencv2/viz.hpp                |     6 +-
 modules/viz/include/opencv2/viz/types.hpp          |     4 +-
 modules/viz/include/opencv2/viz/viz3d.hpp          |     4 +-
 modules/viz/include/opencv2/viz/vizcore.hpp        |     6 +-
 .../viz/include/opencv2/viz/widget_accessor.hpp    |     4 +-
 modules/viz/include/opencv2/viz/widgets.hpp        |     7 +-
 modules/viz/src/precomp.hpp                        |     2 +-
 modules/viz/src/vtk/vtkCloudMatSink.cpp            |     2 +-
 modules/viz/src/vtk/vtkCloudMatSource.cpp          |     4 +-
 modules/viz/src/vtk/vtkCocoaInteractorFix.mm       |   248 +-
 modules/viz/src/vtk/vtkImageMatSource.cpp          |     2 +-
 modules/viz/src/vtk/vtkImageMatSource.h            |     2 +-
 modules/viz/src/vtk/vtkOBJWriter.cpp               |     2 +-
 modules/viz/src/vtk/vtkTrajectorySource.cpp        |     2 +-
 modules/viz/src/vtk/vtkVizInteractorStyle.cpp      |     2 +-
 modules/viz/src/vtk/vtkXYZReader.cpp               |     2 +-
 modules/viz/src/vtk/vtkXYZWriter.cpp               |     2 +-
 modules/viz/src/widget.cpp                         |     8 +
 modules/world/CMakeLists.txt                       |     5 +-
 modules/world/include/opencv2/world.hpp            |     4 +-
 platforms/android/android.toolchain.cmake          |    25 +-
 platforms/android/build-tests/test_cmake_build.py  |     5 +
 platforms/android/build_sdk.py                     |    32 +-
 .../android/service/engine/AndroidManifest.xml     |     4 +-
 .../src/org/opencv/engine/OpenCVEngineService.java |     2 +-
 platforms/android/service/readme.txt               |    20 +-
 platforms/ios/build_framework.py                   |    34 +-
 .../Toolchains/Toolchain-iPhoneOS_Xcode.cmake      |    35 +-
 .../Toolchain-iPhoneSimulator_Xcode.cmake          |    35 +-
 .../cmake/Toolchains/common-ios-toolchain.cmake    |   137 +
 platforms/linux/aarch64-gnu.toolchain.cmake        |     4 +
 platforms/linux/arm-gnueabi.toolchain.cmake        |    91 +-
 platforms/linux/arm.toolchain.cmake                |    97 +
 platforms/linux/gnu.toolchain.cmake                |   106 +
 platforms/maven/README.md                          |    64 +
 platforms/maven/pom.xml                            |   263 +
 platforms/maven/scripts/deb_package_check          |    42 +
 platforms/maven/scripts/properties                 |    90 +
 platforms/osx/build_framework.py                   |     3 +-
 platforms/scripts/valgrind.supp                    |     7 +
 platforms/winrt/readme.txt                         |     2 +-
 samples/CMakeLists.txt                             |     4 +
 samples/android/CMakeLists.txt                     |     4 +-
 .../CameraCalibrationActivity.java                 |     2 +-
 .../jni/DetectionBasedTracker_jni.cpp              |     2 +-
 .../tutorial-2-mixedprocessing/jni/jni_part.cpp    |     6 +-
 samples/cpp/3calibration.cpp                       |    10 +-
 samples/cpp/CMakeLists.txt                         |    13 +-
 samples/cpp/calibration.cpp                        |     8 +-
 samples/cpp/camshiftdemo.cpp                       |     7 +-
 samples/cpp/cloning_gui.cpp                        |     2 +-
 samples/cpp/contours2.cpp                          |     4 +-
 samples/cpp/convexhull.cpp                         |     8 +-
 samples/cpp/cout_mat.cpp                           |     2 +-
 samples/cpp/dbt_face_detection.cpp                 |    32 +-
 samples/cpp/delaunay2.cpp                          |     4 +-
 samples/cpp/detect_blob.cpp                        |    24 +-
 samples/cpp/detect_mser.cpp                        |    40 +-
 samples/cpp/distrans.cpp                           |     2 +-
 samples/cpp/edge.cpp                               |    31 +-
 samples/cpp/facedetect.cpp                         |    20 +-
 samples/cpp/facial_features.cpp                    |    10 +-
 samples/cpp/fback.cpp                              |     6 +-
 samples/cpp/ffilldemo.cpp                          |    12 +-
 samples/cpp/filestorage.cpp                        |     2 +-
 samples/cpp/filestorage_base64.cpp                 |    71 +
 samples/cpp/fitellipse.cpp                         |     5 +-
 samples/cpp/grabcut.cpp                            |     8 +-
 samples/cpp/houghcircles.cpp                       |    41 +-
 samples/cpp/houghlines.cpp                         |     4 +-
 samples/cpp/image.cpp                              |     4 +-
 samples/cpp/image_sequence.cpp                     |     6 +-
 samples/cpp/imagelist_creator.cpp                  |     4 +-
 samples/cpp/inpaint.cpp                            |     6 +-
 samples/cpp/intelperc_capture.cpp                  |     4 +-
 samples/cpp/kalman.cpp                             |     2 +-
 samples/cpp/laplace.cpp                            |    10 +-
 samples/cpp/letter_recog.cpp                       |     4 +-
 samples/cpp/lkdemo.cpp                             |     6 +-
 samples/cpp/lsd_lines.cpp                          |    10 +-
 samples/cpp/matchmethod_orb_akaze_brisk.cpp        |    12 +-
 samples/cpp/minarea.cpp                            |     4 +-
 samples/cpp/morphology2.cpp                        |    20 +-
 samples/cpp/neural_network.cpp                     |    65 +
 samples/cpp/openni_capture.cpp                     |    81 +-
 samples/cpp/pca.cpp                                |     8 +-
 samples/cpp/peopledetect.cpp                       |   177 +
 samples/cpp/phase_corr.cpp                         |    14 +-
 samples/cpp/points_classifier.cpp                  |     2 +-
 samples/cpp/polar_transforms.cpp                   |    96 +-
 samples/cpp/segment_objects.cpp                    |     8 +-
 samples/cpp/select3dobj.cpp                        |     6 +-
 samples/cpp/smiledetect.cpp                        |     4 +-
 samples/cpp/squares.cpp                            |    23 +-
 samples/cpp/starter_imagelist.cpp                  |     2 +-
 samples/cpp/starter_video.cpp                      |    94 -
 samples/cpp/stereo_calib.cpp                       |    20 +-
 samples/cpp/stereo_match.cpp                       |     6 +-
 samples/cpp/stitching.cpp                          |    24 +-
 samples/cpp/stitching_detailed.cpp                 |    74 +-
 samples/cpp/train_svmsgd.cpp                       |   210 +
 samples/cpp/tree_engine.cpp                        |     4 +-
 .../tutorial_code/HighGUI/AddingImagesTrackbar.cpp |    17 +-
 .../HighGUI/BasicLinearTransformsTrackbar.cpp      |     2 +-
 .../tutorial_code/HighGUI/GDAL_IO/gdal-image.cpp   |   242 -
 .../video-input-psnr-ssim.cpp                      |   208 -
 .../HighGUI/video-write/video-write.cpp            |    95 -
 .../Histograms_Matching/EqualizeHist_Demo.cpp      |     9 +-
 .../Histograms_Matching/MatchTemplate_Demo.cpp     |    39 +-
 .../Histograms_Matching/calcBackProject_Demo1.cpp  |    12 +-
 .../Histograms_Matching/calcBackProject_Demo2.cpp  |     6 +-
 .../Histograms_Matching/calcHist_Demo.cpp          |    16 +-
 .../Histograms_Matching/compareHist_Demo.cpp       |    19 +-
 samples/cpp/tutorial_code/ImgProc/AddingImages.cpp |    52 -
 .../ImgProc/BasicLinearTransforms.cpp              |     2 +-
 samples/cpp/tutorial_code/ImgProc/Morphology_1.cpp |    16 +-
 samples/cpp/tutorial_code/ImgProc/Morphology_2.cpp |    27 +-
 samples/cpp/tutorial_code/ImgProc/Pyramids.cpp     |    36 +-
 samples/cpp/tutorial_code/ImgProc/Smoothing.cpp    |    20 +-
 samples/cpp/tutorial_code/ImgProc/Threshold.cpp    |    40 +-
 .../tutorial_code/ImgProc/Threshold_inRange.cpp    |   102 +
 .../tutorial_code/ImgTrans/CannyDetector_Demo.cpp  |    36 +-
 .../ImgTrans/Geometric_Transforms_Demo.cpp         |     7 +-
 .../tutorial_code/ImgTrans/HoughCircle_Demo.cpp    |    10 +-
 .../cpp/tutorial_code/ImgTrans/HoughLines_Demo.cpp |     7 +-
 .../cpp/tutorial_code/ImgTrans/Laplace_Demo.cpp    |    36 +-
 samples/cpp/tutorial_code/ImgTrans/Remap_Demo.cpp  |    11 +-
 samples/cpp/tutorial_code/ImgTrans/Sobel_Demo.cpp  |    38 +-
 .../tutorial_code/ImgTrans/copyMakeBorder_demo.cpp |    42 +-
 .../cpp/tutorial_code/ImgTrans/filter2D_demo.cpp   |    27 +-
 .../ShapeDescriptors/findContours_demo.cpp         |     8 +-
 .../ShapeDescriptors/generalContours_demo1.cpp     |    62 +-
 .../ShapeDescriptors/generalContours_demo2.cpp     |     8 +-
 .../tutorial_code/ShapeDescriptors/hull_demo.cpp   |     9 +-
 .../ShapeDescriptors/moments_demo.cpp              |     8 +-
 .../ShapeDescriptors/pointPolygonTest_demo.cpp     |     6 +-
 .../TrackingMotion/cornerDetector_Demo.cpp         |     9 +-
 .../TrackingMotion/cornerHarris_Demo.cpp           |     8 +-
 .../TrackingMotion/cornerSubPix_Demo.cpp           |     8 +-
 .../TrackingMotion/goodFeaturesToTrack_Demo.cpp    |     8 +-
 .../camera_calibration/camera_calibration.cpp      |   104 +-
 .../calib3d/camera_calibration/in_VID5.xml         |    13 +-
 .../real_time_pose_estimation/src/Utils.cpp        |     4 +-
 .../src/main_detection.cpp                         |    10 +-
 .../src/main_registration.cpp                      |     8 +-
 .../tutorial_code/calib3d/stereoBM/SBM_Sample.cpp  |     6 +-
 .../core/AddingImages/AddingImages.cpp             |    53 +
 .../cpp/tutorial_code/core/Matrix/Drawing_1.cpp    |    35 +-
 .../discrete_fourier_transform.cpp                 |     6 +-
 .../core/file_input_output/file_input_output.cpp   |     2 +-
 .../core/how_to_scan_images/how_to_scan_images.cpp |     2 +-
 .../interoperability_with_OpenCV_1.cpp             |     7 +-
 .../mat_mask_operations/mat_mask_operations.cpp    |    46 +-
 .../mat_the_basic_image_container.cpp              |     4 +-
 .../features2D/AKAZE_tracking/planar_tracking.cpp  |    81 +-
 .../features2D/AKAZE_tracking/utils.h              |    55 +
 .../tutorial_code/imgcodecs/GDAL_IO/gdal-image.cpp |   246 +
 .../introduction/display_image/display_image.cpp   |     8 +-
 .../introduction/documentation/documentation.cpp   |    14 +
 .../ml/non_linear_svms/non_linear_svms.cpp         |     2 +-
 .../objectDetection/objectDetection.cpp            |     4 +-
 .../objectDetection/objectDetection2.cpp           |     4 +-
 .../tutorial_code/photo/decolorization/decolor.cpp |    10 +-
 .../non_photorealistic_rendering/npr_demo.cpp      |    12 +-
 .../photo/seamless_cloning/cloning_gui.cpp         |     2 +-
 samples/cpp/tutorial_code/video/bg_sub.cpp         |    18 +-
 .../video-input-psnr-ssim.cpp                      |   207 +
 .../videoio/video-write/video-write.cpp            |    95 +
 samples/cpp/tutorial_code/viz/creating_widgets.cpp |    11 +-
 samples/cpp/tutorial_code/viz/launching_viz.cpp    |     4 +-
 samples/cpp/tutorial_code/viz/transformations.cpp  |     6 +-
 samples/cpp/tutorial_code/viz/widget_pose.cpp      |     2 +-
 samples/cpp/tvl1_optical_flow.cpp                  |     2 +-
 samples/cpp/videocapture_basic.cpp                 |    52 +
 samples/cpp/videocapture_starter.cpp               |    93 +
 samples/cpp/videostab.cpp                          |     4 +
 samples/cpp/videowriter_basic.cpp                  |    65 +
 samples/cpp/watershed.cpp                          |     8 +-
 .../video => data}/Megamind.avi                    |   Bin
 .../video => data}/Megamind_bugy.avi               |   Bin
 samples/data/apple.jpg                             |   Bin 0 -> 51705 bytes
 samples/data/gradient.png                          |   Bin 0 -> 55964 bytes
 samples/data/lena_tmpl.jpg                         |   Bin 0 -> 79467 bytes
 samples/data/ml.png                                |   Bin 0 -> 81483 bytes
 samples/data/opencv-logo-white.png                 |   Bin 0 -> 8099 bytes
 samples/data/opencv-logo.png                       |   Bin 14287 -> 24903 bytes
 samples/data/orange.jpg                            |   Bin 0 -> 50036 bytes
 samples/data/sudoku.png                            |   Bin 0 -> 250720 bytes
 samples/data/tree.avi                              |   Bin 1310720 -> 1250680 bytes
 samples/data/{768x576.avi => vtest.avi}            |   Bin
 samples/gpu/CMakeLists.txt                         |    10 +-
 samples/gpu/alpha_comp.cpp                         |     2 +-
 samples/gpu/bgfg_segm.cpp                          |    10 +-
 samples/gpu/cascadeclassifier.cpp                  |     8 +-
 samples/gpu/driver_api_multi.cpp                   |    15 +-
 samples/gpu/driver_api_stereo_multi.cpp            |    17 +-
 samples/gpu/generalized_hough.cpp                  |     2 -
 samples/gpu/multi.cpp                              |    15 +-
 samples/gpu/opengl.cpp                             |     8 +-
 samples/gpu/opticalflow_nvidia_api.cpp             |     3 +-
 samples/gpu/performance/tests.cpp                  |     4 +-
 samples/gpu/stereo_multi.cpp                       |     2 -
 samples/gpu/super_resolution.cpp                   |     2 -
 samples/gpu/surf_keypoint_matcher.cpp              |     6 +-
 samples/gpu/tick_meter.hpp                         |    48 -
 samples/gpu/video_reader.cpp                       |     4 +-
 samples/gpu/video_writer.cpp                       |     3 +-
 samples/hal/README.md                              |     3 +-
 samples/hal/c_hal/CMakeLists.txt                   |    21 +-
 samples/hal/c_hal/config.cmake                     |     5 +
 samples/hal/c_hal/impl.c                           |    14 +-
 samples/hal/c_hal/impl.h                           |    14 +-
 samples/hal/slow_hal/CMakeLists.txt                |    21 +-
 samples/hal/slow_hal/config.cmake                  |     5 +
 .../mat_mask_operations/MatMaskOperations.java     |   139 +
 .../introduction/documentation/Documentation.java  |     9 +
 samples/openvx/CMakeLists.txt                      |    37 +
 samples/openvx/no_wrappers.cpp                     |   385 +
 samples/openvx/wrappers.cpp                        |   214 +
 samples/openvx/wrappers_video.cpp                  |   250 +
 samples/python/asift.py                            |     2 +-
 samples/python/camshift.py                         |    34 +-
 samples/python/coherence.py                        |     2 +-
 samples/python/color_histogram.py                  |     2 +-
 samples/python/common.py                           |     1 +
 samples/python/contours.py                         |     2 +-
 samples/python/deconvolution.py                    |     2 +-
 samples/python/demo.py                             |     5 +-
 samples/python/digits.py                           |     2 +-
 samples/python/digits_video.py                     |     9 +-
 samples/python/distrans.py                         |     2 +-
 samples/python/edge.py                             |     2 +-
 samples/python/facedetect.py                       |     2 +-
 samples/python/feature_homography.py               |     3 +-
 samples/python/find_obj.py                         |     8 +-
 samples/python/fitline.py                          |     2 +-
 samples/python/floodfill.py                        |     2 +-
 samples/python/gaussian_mix.py                     |     4 +-
 samples/python/grabcut.py                          |     2 +-
 samples/python/hist.py                             |     2 +-
 samples/python/houghcircles.py                     |    13 +-
 samples/python/houghlines.py                       |    24 +-
 samples/python/inpaint.py                          |     2 +-
 samples/python/kalman.py                           |     8 +-
 samples/python/kmeans.py                           |     2 +-
 samples/python/lappyr.py                           |     2 +-
 samples/python/letter_recog.py                     |    61 +-
 samples/python/lk_homography.py                    |     5 +-
 samples/python/lk_track.py                         |     2 +-
 samples/python/morphology.py                       |     2 +-
 samples/python/mosse.py                            |     2 +-
 samples/python/mouse_and_match.py                  |     2 +-
 samples/python/mser.py                             |     9 +-
 samples/python/opt_flow.py                         |     2 +-
 samples/python/peopledetect.py                     |     2 +-
 samples/python/plane_ar.py                         |     7 +-
 samples/python/plane_tracker.py                    |     5 +-
 samples/python/squares.py                          |     2 +-
 samples/python/tst_scene_render.py                 |   116 +
 samples/python/turing.py                           |     2 +-
 .../mat_mask_operations/mat_mask_operations.py     |    57 +
 .../introduction/documentation/documentation.py    |     5 +
 samples/python/video.py                            |    33 +-
 samples/python/video_threaded.py                   |     2 +-
 samples/python/video_v4l2.py                       |     6 +-
 samples/python/watershed.py                        |     4 +-
 samples/tapi/bgfg_segm.cpp                         |    10 +-
 samples/tapi/camshift.cpp                          |     6 +-
 samples/tapi/clahe.cpp                             |     8 +-
 samples/tapi/hog.cpp                               |     8 +-
 samples/tapi/pyrlk_optical_flow.cpp                |     2 +-
 samples/tapi/squares.cpp                           |     8 +-
 samples/tapi/tvl1_optical_flow.cpp                 |     8 +-
 samples/tapi/ufacedetect.cpp                       |    14 +-
 .../FaceDetection/FaceDetection/MainPage.xaml.cpp  |     8 +-
 .../MediaExtensions/OcvTransform/OcvTransform.cpp  |     6 +-
 .../OcvImageProcessing/MainPage.xaml.cpp           |     4 +-
 .../PhoneTutorial/MainPage.xaml.cpp                |     4 +-
 .../PhoneXamlDirect3DApp1Comp/Direct3DInterop.cpp  |     6 +-
 .../OpenCVXaml/OpenCVComponent/OpenCVComponent.cpp |     7 +-
 1886 files changed, 223377 insertions(+), 47496 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 3ee50ff..cc45f6f 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -68,6 +68,10 @@ if(WINRT)
   endif()
 endif()
 
+if(POLICY CMP0020)
+  cmake_policy(SET CMP0020 OLD)
+endif()
+
 if(POLICY CMP0022)
   cmake_policy(SET CMP0022 OLD)
 endif()
@@ -77,13 +81,14 @@ if(POLICY CMP0026)
   cmake_policy(SET CMP0026 OLD)
 endif()
 
-if (POLICY CMP0042)
-  # silence cmake 3.0+ warnings about MACOSX_RPATH
-  cmake_policy(SET CMP0042 OLD)
+if(POLICY CMP0042)
+  cmake_policy(SET CMP0042 NEW)
 endif()
 
+include(cmake/OpenCVUtils.cmake)
+
 # must go before the project command
-set(CMAKE_CONFIGURATION_TYPES "Debug;Release" CACHE STRING "Configs" FORCE)
+ocv_update(CMAKE_CONFIGURATION_TYPES "Debug;Release" CACHE STRING "Configs" FORCE)
 if(DEFINED CMAKE_BUILD_TYPE)
   set_property( CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS ${CMAKE_CONFIGURATION_TYPES} )
 endif()
@@ -96,7 +101,7 @@ if(MSVC)
   set(CMAKE_USE_RELATIVE_PATHS ON CACHE INTERNAL "" FORCE)
 endif()
 
-include(cmake/OpenCVUtils.cmake)
+ocv_cmake_eval(DEBUG_PRE ONCE)
 
 ocv_clear_vars(OpenCVModules_TARGETS)
 
@@ -159,11 +164,14 @@ endif()
 # OpenCV cmake options
 # ----------------------------------------------------------------------------
 
+OCV_OPTION(OPENCV_ENABLE_NONFREE "Enable non-free algorithms" OFF)
+
 # Optional 3rd party components
 # ===================================================
 OCV_OPTION(WITH_1394           "Include IEEE1394 support"                    ON   IF (NOT ANDROID AND NOT IOS AND NOT WINRT) )
-OCV_OPTION(WITH_AVFOUNDATION   "Use AVFoundation for Video I/O"              ON   IF IOS)
+OCV_OPTION(WITH_AVFOUNDATION   "Use AVFoundation for Video I/O (iOS/Mac)"    ON   IF APPLE)
 OCV_OPTION(WITH_CARBON         "Use Carbon for UI instead of Cocoa"          OFF  IF APPLE )
+OCV_OPTION(WITH_CAROTENE       "Use NVidia carotene acceleration library for ARM platform"                   ON  IF (ARM OR AARCH64) AND NOT IOS AND NOT (CMAKE_VERSION VERSION_LESS "2.8.11"))
 OCV_OPTION(WITH_VTK            "Include VTK library support (and build opencv_viz module eiher)"             ON  IF (NOT ANDROID AND NOT IOS AND NOT WINRT AND NOT CMAKE_CROSSCOMPILING) )
 OCV_OPTION(WITH_CUDA           "Include NVidia Cuda Runtime support"                                         ON  IF (NOT IOS AND NOT WINRT) )
 OCV_OPTION(WITH_CUFFT          "Include NVidia Cuda Fast Fourier Transform (FFT) library support"            ON  IF (NOT IOS AND NOT WINRT) )
@@ -182,14 +190,18 @@ OCV_OPTION(WITH_JPEG           "Include JPEG support"                        ON)
 OCV_OPTION(WITH_WEBP           "Include WebP support"                        ON   IF (NOT IOS AND NOT WINRT) )
 OCV_OPTION(WITH_OPENEXR        "Include ILM support via OpenEXR"             ON   IF (NOT IOS AND NOT WINRT) )
 OCV_OPTION(WITH_OPENGL         "Include OpenGL support"                      OFF  IF (NOT ANDROID AND NOT WINRT) )
+OCV_OPTION(WITH_OPENVX         "Include OpenVX support"                      OFF)
 OCV_OPTION(WITH_OPENNI         "Include OpenNI support"                      OFF  IF (NOT ANDROID AND NOT IOS AND NOT WINRT) )
 OCV_OPTION(WITH_OPENNI2        "Include OpenNI2 support"                     OFF  IF (NOT ANDROID AND NOT IOS AND NOT WINRT) )
 OCV_OPTION(WITH_PNG            "Include PNG support"                         ON)
-OCV_OPTION(WITH_PVAPI          "Include Prosilica GigE support"              ON   IF (NOT ANDROID AND NOT IOS AND NOT WINRT) )
-OCV_OPTION(WITH_GIGEAPI        "Include Smartek GigE support"                ON   IF (NOT ANDROID AND NOT IOS AND NOT WINRT) )
+OCV_OPTION(WITH_GDCM           "Include DICOM support"                       OFF)
+OCV_OPTION(WITH_PVAPI          "Include Prosilica GigE support"              OFF   IF (NOT ANDROID AND NOT IOS AND NOT WINRT) )
+OCV_OPTION(WITH_GIGEAPI        "Include Smartek GigE support"                OFF   IF (NOT ANDROID AND NOT IOS AND NOT WINRT) )
+OCV_OPTION(WITH_ARAVIS         "Include Aravis GigE support"                 OFF   IF (NOT ANDROID AND NOT IOS AND NOT WINRT AND NOT WIN32) )
 OCV_OPTION(WITH_QT             "Build with Qt Backend support"               OFF  IF (NOT ANDROID AND NOT IOS AND NOT WINRT) )
 OCV_OPTION(WITH_WIN32UI        "Build with Win32 UI Backend support"         ON   IF WIN32 AND NOT WINRT)
-OCV_OPTION(WITH_QUICKTIME      "Use QuickTime for Video I/O insted of QTKit" OFF  IF APPLE )
+OCV_OPTION(WITH_QUICKTIME      "Use QuickTime for Video I/O"                 OFF  IF APPLE )
+OCV_OPTION(WITH_QTKIT          "Use QTKit Video I/O backend"                 OFF  IF APPLE )
 OCV_OPTION(WITH_TBB            "Include Intel TBB support"                   OFF  IF (NOT IOS AND NOT WINRT) )
 OCV_OPTION(WITH_OPENMP         "Include OpenMP support"                      OFF)
 OCV_OPTION(WITH_CSTRIPES       "Include C= support"                          OFF  IF (WIN32 AND NOT WINRT)  )
@@ -197,7 +209,7 @@ OCV_OPTION(WITH_PTHREADS_PF    "Use pthreads-based parallel_for"             ON
 OCV_OPTION(WITH_TIFF           "Include TIFF support"                        ON   IF (NOT IOS) )
 OCV_OPTION(WITH_UNICAP         "Include Unicap support (GPL)"                OFF  IF (UNIX AND NOT APPLE AND NOT ANDROID) )
 OCV_OPTION(WITH_V4L            "Include Video 4 Linux support"               ON   IF (UNIX AND NOT ANDROID) )
-OCV_OPTION(WITH_LIBV4L         "Use libv4l for Video 4 Linux support"        ON   IF (UNIX AND NOT ANDROID) )
+OCV_OPTION(WITH_LIBV4L         "Use libv4l for Video 4 Linux support"        OFF  IF (UNIX AND NOT ANDROID) )
 OCV_OPTION(WITH_DSHOW          "Build VideoIO with DirectShow support"       ON   IF (WIN32 AND NOT ARM AND NOT WINRT) )
 OCV_OPTION(WITH_MSMF           "Build VideoIO with Media Foundation support" OFF  IF WIN32 )
 OCV_OPTION(WITH_XIMEA          "Include XIMEA cameras support"               OFF  IF (NOT ANDROID AND NOT WINRT) )
@@ -215,6 +227,7 @@ OCV_OPTION(WITH_VA             "Include VA support"                          OFF
 OCV_OPTION(WITH_VA_INTEL       "Include Intel VA-API/OpenCL support"         OFF  IF (UNIX AND NOT ANDROID) )
 OCV_OPTION(WITH_GDAL           "Include GDAL Support"                        OFF  IF (NOT ANDROID AND NOT IOS AND NOT WINRT) )
 OCV_OPTION(WITH_GPHOTO2        "Include gPhoto2 library support"             ON   IF (UNIX AND NOT ANDROID) )
+OCV_OPTION(WITH_LAPACK         "Include Lapack library support"              ON   IF (NOT ANDROID AND NOT IOS) )
 
 # OpenCV build components
 # ===================================================
@@ -253,7 +266,8 @@ OCV_OPTION(INSTALL_TESTS            "Install accuracy and performance test binar
 
 # OpenCV build options
 # ===================================================
-OCV_OPTION(ENABLE_PRECOMPILED_HEADERS "Use precompiled headers"                                  ON   IF (NOT IOS) )
+OCV_OPTION(ENABLE_CCACHE              "Use ccache"                                               (UNIX AND NOT IOS AND (CMAKE_GENERATOR MATCHES "Makefile" OR CMAKE_GENERATOR MATCHES "Ninja")) )
+OCV_OPTION(ENABLE_PRECOMPILED_HEADERS "Use precompiled headers"                                  ON IF (NOT IOS AND NOT CMAKE_CROSSCOMPILING) )
 OCV_OPTION(ENABLE_SOLUTION_FOLDERS    "Solution folder in Visual Studio or in other IDEs"        (MSVC_IDE OR CMAKE_GENERATOR MATCHES Xcode) )
 OCV_OPTION(ENABLE_PROFILING           "Enable profiling in the GCC compiler (Add flags: -g -pg)" OFF  IF CMAKE_COMPILER_IS_GNUCXX )
 OCV_OPTION(ENABLE_COVERAGE            "Enable coverage collection with  GCov"                    OFF  IF CMAKE_COMPILER_IS_GNUCXX )
@@ -276,6 +290,7 @@ OCV_OPTION(ENABLE_NOISY_WARNINGS      "Show all warnings even if they are too no
 OCV_OPTION(OPENCV_WARNINGS_ARE_ERRORS "Treat warnings as errors"                                 OFF )
 OCV_OPTION(ANDROID_EXAMPLES_WITH_LIBS "Build binaries of Android examples with native libraries" OFF  IF ANDROID )
 OCV_OPTION(ENABLE_IMPL_COLLECTION     "Collect implementation data on function call"             OFF )
+OCV_OPTION(ENABLE_INSTRUMENTATION     "Instrument functions to collect calls trace and performance" OFF )
 OCV_OPTION(GENERATE_ABI_DESCRIPTOR    "Generate XML file for abi_compliance_checker tool" OFF IF UNIX)
 
 OCV_OPTION(DOWNLOAD_EXTERNAL_TEST_DATA "Download external test data (Python executable and OPENCV_TEST_DATA_PATH environment variable may be required)" OFF )
@@ -297,118 +312,124 @@ include(cmake/OpenCVVersion.cmake)
 # ----------------------------------------------------------------------------
 
 # Save libs and executables in the same place
-set(EXECUTABLE_OUTPUT_PATH "${CMAKE_BINARY_DIR}/bin" CACHE PATH "Output directory for applications" )
+set(EXECUTABLE_OUTPUT_PATH "${CMAKE_BINARY_DIR}/bin" CACHE PATH "Output directory for applications")
 
-if (ANDROID)
-  if (ANDROID_ABI MATCHES "NEON")
+if(ANDROID)
+  if(ANDROID_ABI MATCHES "NEON")
     set(ENABLE_NEON ON)
   endif()
-  if (ANDROID_ABI MATCHES "VFPV3")
+  if(ANDROID_ABI MATCHES "VFPV3")
     set(ENABLE_VFPV3 ON)
   endif()
 endif()
 
 if(ANDROID OR WIN32)
-  set(OPENCV_DOC_INSTALL_PATH doc)
+  ocv_update(OPENCV_DOC_INSTALL_PATH doc)
 else()
-  set(OPENCV_DOC_INSTALL_PATH share/OpenCV/doc)
+  ocv_update(OPENCV_DOC_INSTALL_PATH share/OpenCV/doc)
 endif()
 
 if(WIN32 AND CMAKE_HOST_SYSTEM_NAME MATCHES Windows)
   if(DEFINED OpenCV_RUNTIME AND DEFINED OpenCV_ARCH)
-    set(OpenCV_INSTALL_BINARIES_PREFIX "${OpenCV_ARCH}/${OpenCV_RUNTIME}/")
+    ocv_update(OpenCV_INSTALL_BINARIES_PREFIX "${OpenCV_ARCH}/${OpenCV_RUNTIME}/")
   else()
     message(STATUS "Can't detect runtime and/or arch")
-    set(OpenCV_INSTALL_BINARIES_PREFIX "")
+    ocv_update(OpenCV_INSTALL_BINARIES_PREFIX "")
   endif()
 elseif(ANDROID)
-  set(OpenCV_INSTALL_BINARIES_PREFIX "sdk/native/")
+  ocv_update(OpenCV_INSTALL_BINARIES_PREFIX "sdk/native/")
 else()
-  set(OpenCV_INSTALL_BINARIES_PREFIX "")
+  ocv_update(OpenCV_INSTALL_BINARIES_PREFIX "")
 endif()
 
 if(ANDROID)
-  set(OPENCV_SAMPLES_BIN_INSTALL_PATH "${OpenCV_INSTALL_BINARIES_PREFIX}samples/${ANDROID_NDK_ABI_NAME}")
+  ocv_update(OPENCV_SAMPLES_BIN_INSTALL_PATH "${OpenCV_INSTALL_BINARIES_PREFIX}samples/${ANDROID_NDK_ABI_NAME}")
 else()
-  set(OPENCV_SAMPLES_BIN_INSTALL_PATH "${OpenCV_INSTALL_BINARIES_PREFIX}samples")
+  ocv_update(OPENCV_SAMPLES_BIN_INSTALL_PATH "${OpenCV_INSTALL_BINARIES_PREFIX}samples")
 endif()
 
 if(ANDROID)
-  set(OPENCV_BIN_INSTALL_PATH "${OpenCV_INSTALL_BINARIES_PREFIX}bin/${ANDROID_NDK_ABI_NAME}")
+  ocv_update(OPENCV_BIN_INSTALL_PATH "${OpenCV_INSTALL_BINARIES_PREFIX}bin/${ANDROID_NDK_ABI_NAME}")
 else()
-  set(OPENCV_BIN_INSTALL_PATH "${OpenCV_INSTALL_BINARIES_PREFIX}bin")
+  ocv_update(OPENCV_BIN_INSTALL_PATH "${OpenCV_INSTALL_BINARIES_PREFIX}bin")
 endif()
 
 if(NOT OPENCV_TEST_INSTALL_PATH)
-  set(OPENCV_TEST_INSTALL_PATH "${OPENCV_BIN_INSTALL_PATH}")
+  ocv_update(OPENCV_TEST_INSTALL_PATH "${OPENCV_BIN_INSTALL_PATH}")
 endif()
 
 if (OPENCV_TEST_DATA_PATH)
   get_filename_component(OPENCV_TEST_DATA_PATH ${OPENCV_TEST_DATA_PATH} ABSOLUTE)
 endif()
 
-if(OPENCV_TEST_DATA_PATH AND NOT OPENCV_TEST_DATA_INSTALL_PATH)
-  if(ANDROID)
-    set(OPENCV_TEST_DATA_INSTALL_PATH "sdk/etc/testdata")
-  elseif(WIN32)
-    set(OPENCV_TEST_DATA_INSTALL_PATH "testdata")
-  else()
-    set(OPENCV_TEST_DATA_INSTALL_PATH "share/OpenCV/testdata")
-  endif()
+if(ANDROID)
+  ocv_update(OPENCV_TEST_DATA_INSTALL_PATH "sdk/etc/testdata")
+elseif(WIN32)
+  ocv_update(OPENCV_TEST_DATA_INSTALL_PATH "testdata")
+else()
+  ocv_update(OPENCV_TEST_DATA_INSTALL_PATH "share/OpenCV/testdata")
 endif()
 
 if(ANDROID)
-  set(LIBRARY_OUTPUT_PATH         "${OpenCV_BINARY_DIR}/lib/${ANDROID_NDK_ABI_NAME}")
-  set(3P_LIBRARY_OUTPUT_PATH      "${OpenCV_BINARY_DIR}/3rdparty/lib/${ANDROID_NDK_ABI_NAME}")
-  set(OPENCV_LIB_INSTALL_PATH     sdk/native/libs/${ANDROID_NDK_ABI_NAME})
-  set(OPENCV_3P_LIB_INSTALL_PATH  sdk/native/3rdparty/libs/${ANDROID_NDK_ABI_NAME})
-  set(OPENCV_CONFIG_INSTALL_PATH  sdk/native/jni)
-  set(OPENCV_INCLUDE_INSTALL_PATH sdk/native/jni/include)
-  set(OPENCV_SAMPLES_SRC_INSTALL_PATH samples/native)
-  set(OPENCV_OTHER_INSTALL_PATH   sdk/etc)
+  set(LIBRARY_OUTPUT_PATH                "${OpenCV_BINARY_DIR}/lib/${ANDROID_NDK_ABI_NAME}")
+  ocv_update(3P_LIBRARY_OUTPUT_PATH      "${OpenCV_BINARY_DIR}/3rdparty/lib/${ANDROID_NDK_ABI_NAME}")
+  ocv_update(OPENCV_LIB_INSTALL_PATH     sdk/native/libs/${ANDROID_NDK_ABI_NAME})
+  ocv_update(OPENCV_3P_LIB_INSTALL_PATH  sdk/native/3rdparty/libs/${ANDROID_NDK_ABI_NAME})
+  ocv_update(OPENCV_CONFIG_INSTALL_PATH  sdk/native/jni)
+  ocv_update(OPENCV_INCLUDE_INSTALL_PATH sdk/native/jni/include)
+  ocv_update(OPENCV_SAMPLES_SRC_INSTALL_PATH samples/native)
+  ocv_update(OPENCV_OTHER_INSTALL_PATH   sdk/etc)
 else()
-  set(LIBRARY_OUTPUT_PATH         "${OpenCV_BINARY_DIR}/lib")
-  set(3P_LIBRARY_OUTPUT_PATH      "${OpenCV_BINARY_DIR}/3rdparty/lib${LIB_SUFFIX}")
+  set(LIBRARY_OUTPUT_PATH                "${OpenCV_BINARY_DIR}/lib")
+  ocv_update(3P_LIBRARY_OUTPUT_PATH      "${OpenCV_BINARY_DIR}/3rdparty/lib${LIB_SUFFIX}")
 
   if(WIN32 AND CMAKE_HOST_SYSTEM_NAME MATCHES Windows)
     if(OpenCV_STATIC)
-      set(OPENCV_LIB_INSTALL_PATH   "${OpenCV_INSTALL_BINARIES_PREFIX}staticlib${LIB_SUFFIX}")
+      ocv_update(OPENCV_LIB_INSTALL_PATH   "${OpenCV_INSTALL_BINARIES_PREFIX}staticlib${LIB_SUFFIX}")
     else()
-      set(OPENCV_LIB_INSTALL_PATH   "${OpenCV_INSTALL_BINARIES_PREFIX}lib${LIB_SUFFIX}")
+      ocv_update(OPENCV_LIB_INSTALL_PATH   "${OpenCV_INSTALL_BINARIES_PREFIX}lib${LIB_SUFFIX}")
     endif()
-    set(OPENCV_3P_LIB_INSTALL_PATH  "${OpenCV_INSTALL_BINARIES_PREFIX}staticlib${LIB_SUFFIX}")
-    set(OPENCV_SAMPLES_SRC_INSTALL_PATH    samples/native)
-    set(OPENCV_JAR_INSTALL_PATH java)
-    set(OPENCV_OTHER_INSTALL_PATH   etc)
+    ocv_update(OPENCV_3P_LIB_INSTALL_PATH  "${OpenCV_INSTALL_BINARIES_PREFIX}staticlib${LIB_SUFFIX}")
+    ocv_update(OPENCV_SAMPLES_SRC_INSTALL_PATH    samples/native)
+    ocv_update(OPENCV_JAR_INSTALL_PATH java)
+    ocv_update(OPENCV_OTHER_INSTALL_PATH   etc)
+    ocv_update(OPENCV_CONFIG_INSTALL_PATH  ".")
   else()
-    set(OPENCV_LIB_INSTALL_PATH     lib${LIB_SUFFIX})
-    set(OPENCV_3P_LIB_INSTALL_PATH  share/OpenCV/3rdparty/${OPENCV_LIB_INSTALL_PATH})
-    set(OPENCV_SAMPLES_SRC_INSTALL_PATH    share/OpenCV/samples)
-    set(OPENCV_JAR_INSTALL_PATH share/OpenCV/java)
-    set(OPENCV_OTHER_INSTALL_PATH   share/OpenCV)
-  endif()
-  set(OPENCV_INCLUDE_INSTALL_PATH "include")
-
-  math(EXPR SIZEOF_VOID_P_BITS "8 * ${CMAKE_SIZEOF_VOID_P}")
-  if(LIB_SUFFIX AND NOT SIZEOF_VOID_P_BITS EQUAL LIB_SUFFIX)
-    set(OPENCV_CONFIG_INSTALL_PATH lib${LIB_SUFFIX}/cmake/opencv)
-  else()
-    set(OPENCV_CONFIG_INSTALL_PATH share/OpenCV)
+    ocv_update(OPENCV_LIB_INSTALL_PATH     lib${LIB_SUFFIX})
+    ocv_update(OPENCV_3P_LIB_INSTALL_PATH  share/OpenCV/3rdparty/${OPENCV_LIB_INSTALL_PATH})
+    ocv_update(OPENCV_SAMPLES_SRC_INSTALL_PATH    share/OpenCV/samples)
+    ocv_update(OPENCV_JAR_INSTALL_PATH share/OpenCV/java)
+    ocv_update(OPENCV_OTHER_INSTALL_PATH   share/OpenCV)
+
+    if(NOT DEFINED OPENCV_CONFIG_INSTALL_PATH)
+      math(EXPR SIZEOF_VOID_P_BITS "8 * ${CMAKE_SIZEOF_VOID_P}")
+      if(LIB_SUFFIX AND NOT SIZEOF_VOID_P_BITS EQUAL LIB_SUFFIX)
+        ocv_update(OPENCV_CONFIG_INSTALL_PATH lib${LIB_SUFFIX}/cmake/opencv)
+      else()
+        ocv_update(OPENCV_CONFIG_INSTALL_PATH share/OpenCV)
+      endif()
+    endif()
   endif()
+  ocv_update(OPENCV_INCLUDE_INSTALL_PATH "include")
 endif()
 
-set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/${OPENCV_LIB_INSTALL_PATH}")
+ocv_update(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/${OPENCV_LIB_INSTALL_PATH}")
 set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
 
 if(INSTALL_TO_MANGLED_PATHS)
   set(OPENCV_INCLUDE_INSTALL_PATH ${OPENCV_INCLUDE_INSTALL_PATH}/opencv-${OPENCV_VERSION})
-  string(REPLACE "OpenCV" "OpenCV-${OPENCV_VERSION}" OPENCV_3P_LIB_INSTALL_PATH "${OPENCV_3P_LIB_INSTALL_PATH}")
-  string(REPLACE "OpenCV" "OpenCV-${OPENCV_VERSION}" OPENCV_SAMPLES_SRC_INSTALL_PATH "${OPENCV_SAMPLES_SRC_INSTALL_PATH}")
-  string(REPLACE "OpenCV" "OpenCV-${OPENCV_VERSION}" OPENCV_CONFIG_INSTALL_PATH "${OPENCV_CONFIG_INSTALL_PATH}")
-  string(REPLACE "OpenCV" "OpenCV-${OPENCV_VERSION}" OPENCV_DOC_INSTALL_PATH "${OPENCV_DOC_INSTALL_PATH}")
-  string(REPLACE "OpenCV" "OpenCV-${OPENCV_VERSION}" OPENCV_JAR_INSTALL_PATH "${OPENCV_JAR_INSTALL_PATH}")
-  string(REPLACE "OpenCV" "OpenCV-${OPENCV_VERSION}" OPENCV_TEST_DATA_INSTALL_PATH "${OPENCV_TEST_DATA_INSTALL_PATH}")
-  string(REPLACE "OpenCV" "OpenCV-${OPENCV_VERSION}" OPENCV_OTHER_INSTALL_PATH "${OPENCV_OTHER_INSTALL_PATH}")
+  foreach(v
+      OPENCV_3P_LIB_INSTALL_PATH
+      OPENCV_SAMPLES_SRC_INSTALL_PATH
+      OPENCV_CONFIG_INSTALL_PATH
+      OPENCV_DOC_INSTALL_PATH
+      OPENCV_JAR_INSTALL_PATH
+      OPENCV_TEST_DATA_INSTALL_PATH
+      OPENCV_OTHER_INSTALL_PATH
+    )
+    string(REPLACE "OpenCV" "OpenCV-${OPENCV_VERSION}" ${v} "${${v}}")
+    string(REPLACE "opencv" "opencv-${OPENCV_VERSION}" ${v} "${${v}}")
+  endforeach()
 endif()
 
 
@@ -433,7 +454,7 @@ endif()
 # ----------------------------------------------------------------------------
 #  Path for build/platform -specific headers
 # ----------------------------------------------------------------------------
-set(OPENCV_CONFIG_FILE_INCLUDE_DIR "${CMAKE_BINARY_DIR}/" CACHE PATH "Where to create the platform-dependant cvconfig.h")
+ocv_update(OPENCV_CONFIG_FILE_INCLUDE_DIR "${CMAKE_BINARY_DIR}/" CACHE PATH "Where to create the platform-dependant cvconfig.h")
 ocv_include_directories(${OPENCV_CONFIG_FILE_INCLUDE_DIR})
 
 # ----------------------------------------------------------------------------
@@ -446,7 +467,7 @@ set(OPENCV_EXTRA_MODULES_PATH "" CACHE PATH "Where to look for additional OpenCV
 # ----------------------------------------------------------------------------
 find_host_package(Git QUIET)
 
-if(GIT_FOUND)
+if(NOT DEFINED OPENCV_VCSVERSION AND GIT_FOUND)
   execute_process(COMMAND "${GIT_EXECUTABLE}" describe --tags --always --dirty --match "[0-9].[0-9].[0-9]*"
     WORKING_DIRECTORY "${OpenCV_SOURCE_DIR}"
     OUTPUT_VARIABLE OPENCV_VCSVERSION
@@ -457,7 +478,7 @@ if(GIT_FOUND)
   if(NOT GIT_RESULT EQUAL 0)
     set(OPENCV_VCSVERSION "unknown")
   endif()
-else()
+elseif(NOT DEFINED OPENCV_VCSVERSION)
   # We don't have git:
   set(OPENCV_VCSVERSION "unknown")
 endif()
@@ -535,28 +556,18 @@ include(cmake/OpenCVFindLibsGrfmt.cmake)
 include(cmake/OpenCVFindLibsGUI.cmake)
 include(cmake/OpenCVFindLibsVideo.cmake)
 include(cmake/OpenCVFindLibsPerf.cmake)
+include(cmake/OpenCVFindLAPACK.cmake)
 
 # ----------------------------------------------------------------------------
 #  Detect other 3rd-party libraries/tools
 # ----------------------------------------------------------------------------
 
-# --- Doxygen and PlantUML for documentation ---
-unset(DOXYGEN_FOUND CACHE)
+# --- Doxygen for documentation ---
 if(BUILD_DOCS)
   find_package(Doxygen)
-  if (PLANTUML_JAR)
-    message(STATUS "Using PlantUML path from command line: ${PLANTUML_JAR}")
-  elseif(DEFINED ENV{PLANTUML_JAR})
-    set(PLANTUML_JAR $ENV{PLANTUML_JAR})
-    message(STATUS "Using PLantUML path from environment: ${PLANTUML_JAR}")
-  else()
-    message(STATUS "To enable PlantUML support, set PLANTUML_JAR environment variable or pass -DPLANTUML_JAR=<filepath> option to cmake")
-  endif()
-  if (PLANTUML_JAR AND DOXYGEN_VERSION VERSION_LESS 1.8.8)
-    message(STATUS "You need Doxygen version 1.8.8 or later to use PlantUML")
-    unset(PLANTUML_JAR)
-  endif()
-endif(BUILD_DOCS)
+else()
+  unset(DOXYGEN_FOUND CACHE)
+endif()
 
 # --- Python Support ---
 include(cmake/OpenCVDetectPython.cmake)
@@ -596,30 +607,69 @@ endif()
 
 include(cmake/OpenCVDetectVTK.cmake)
 
-# -- Custom HAL replacement --
-set(_includes "")
-# assuming OPENCV_HAL_HEADERS and OPENCV_HAL_LIBS are lists of files:
-# option example: -DOPENCV_HAL_HEADERS="<some-path>/header1.h;<some-path>/header2.h"
-if (OPENCV_HAL_HEADERS AND OPENCV_HAL_LIBS)
-  foreach (h ${OPENCV_HAL_HEADERS})
-    get_filename_component(h "${h}" ABSOLUTE)
-    set(_includes "${_includes}\n#include \"${h}\"")
+if(WITH_OPENVX)
+  include(cmake/FindOpenVX.cmake)
+endif()
+
+# ----------------------------------------------------------------------------
+# OpenCV HAL
+# ----------------------------------------------------------------------------
+set(_hal_includes "")
+macro(ocv_hal_register HAL_LIBRARIES_VAR HAL_HEADERS_VAR HAL_INCLUDE_DIRS_VAR)
+  # 1. libraries
+  foreach (l ${${HAL_LIBRARIES_VAR}})
+    if(NOT TARGET ${l})
+      get_filename_component(l "${l}" ABSOLUTE)
+    endif()
+    list(APPEND OPENCV_HAL_LINKER_LIBS ${l})
   endforeach()
-  foreach (l ${OPENCV_HAL_LIBS})
-    get_filename_component(l "${l}" ABSOLUTE)
-    set(OPENCV_LINKER_LIBS ${OPENCV_LINKER_LIBS} ${l})
-    # TODO: install?
-    # ocv_install_target(${l} EXPORT OpenCVModules ARCHIVE DESTINATION ${OPENCV_3P_LIB_INSTALL_PATH} COMPONENT dev)
+  # 2. headers
+  foreach (h ${${HAL_HEADERS_VAR}})
+    set(_hal_includes "${_hal_includes}\n#include \"${h}\"")
   endforeach()
-else()
-  set(_includes "// using default HAL")
-  unset(OPENCV_HAL_HEADERS CACHE)
-  unset(OPENCV_HAL_LIBS CACHE)
+  # 3. include paths
+  ocv_include_directories(${${HAL_INCLUDE_DIRS_VAR}})
+endmacro()
+
+if(NOT DEFINED OpenCV_HAL)
+  set(OpenCV_HAL "OpenCV_HAL")
+endif()
+
+if(HAVE_OPENVX)
+  if(NOT ";${OpenCV_HAL};" MATCHES ";openvx;")
+    set(OpenCV_HAL "openvx;${OpenCV_HAL}")
+  endif()
+endif()
+
+if(WITH_CAROTENE)
+  ocv_debug_message(STATUS "Enable carotene acceleration")
+  if(NOT ";${OpenCV_HAL};" MATCHES ";carotene;")
+    set(OpenCV_HAL "carotene;${OpenCV_HAL}")
+  endif()
 endif()
-set(OPENCV_HAL_HEADERS "${OPENCV_HAL_HEADERS}" CACHE STRING "Headers with custom HAL implementation")
-set(OPENCV_HAL_LIBS "${OPENCV_HAL_LIBS}" CACHE STRING "Libraries with custom HAL implementation")
+
+foreach(hal ${OpenCV_HAL})
+  if(hal STREQUAL "carotene")
+    add_subdirectory(3rdparty/carotene/hal)
+    ocv_hal_register(CAROTENE_HAL_LIBRARIES CAROTENE_HAL_HEADERS CAROTENE_HAL_INCLUDE_DIRS)
+    list(APPEND OpenCV_USED_HAL "carotene (ver ${CAROTENE_HAL_VERSION})")
+  elseif(hal STREQUAL "openvx")
+    add_subdirectory(3rdparty/openvx)
+    ocv_hal_register(OPENVX_HAL_LIBRARIES OPENVX_HAL_HEADERS OPENVX_HAL_INCLUDE_DIRS)
+    list(APPEND OpenCV_USED_HAL "openvx (ver ${OPENVX_HAL_VERSION})")
+  else()
+    ocv_debug_message(STATUS "OpenCV HAL: ${hal} ...")
+    ocv_clear_vars(OpenCV_HAL_LIBRARIES OpenCV_HAL_HEADERS OpenCV_HAL_INCLUDE_DIRS)
+    find_package(${hal} NO_MODULE QUIET)
+    if(${hal}_FOUND)
+      ocv_hal_register(OpenCV_HAL_LIBRARIES OpenCV_HAL_HEADERS OpenCV_HAL_INCLUDE_DIRS)
+      list(APPEND OpenCV_USED_HAL "${hal} (ver ${${hal}_VERSION})")
+    endif()
+  endif()
+endforeach()
 configure_file("${OpenCV_SOURCE_DIR}/cmake/templates/custom_hal.hpp.in" "${CMAKE_BINARY_DIR}/custom_hal.hpp" @ONLY)
-unset(_includes)
+unset(_hal_includes)
+
 
 # ----------------------------------------------------------------------------
 # Add CUDA libraries (needed for apps/tools, samples)
@@ -633,7 +683,7 @@ if(HAVE_CUDA)
     set(OPENCV_LINKER_LIBS ${OPENCV_LINKER_LIBS} ${CUDA_cufft_LIBRARY})
   endif()
   foreach(p ${CUDA_LIBS_PATH})
-    set(OPENCV_LINKER_LIBS ${OPENCV_LINKER_LIBS} -L${p})
+    set(OPENCV_LINKER_LIBS ${OPENCV_LINKER_LIBS} ${CMAKE_LIBRARY_PATH_FLAG}${p})
   endforeach()
 endif()
 # ----------------------------------------------------------------------------
@@ -691,7 +741,7 @@ include(cmake/OpenCVGenPkgconfig.cmake)
 # Generate OpenCV.mk for ndk-build (Android build tool)
 include(cmake/OpenCVGenAndroidMK.cmake)
 
-# Generate OpenCVСonfig.cmake and OpenCVConfig-version.cmake for cmake projects
+# Generate OpenCVConfig.cmake and OpenCVConfig-version.cmake for cmake projects
 include(cmake/OpenCVGenConfig.cmake)
 
 # Generate Info.plist for the IOS framework
@@ -709,7 +759,7 @@ if(INSTALL_TESTS AND OPENCV_TEST_DATA_PATH)
     configure_file("${CMAKE_CURRENT_SOURCE_DIR}/cmake/templates/opencv_run_all_tests_android.sh.in"
                    "${CMAKE_BINARY_DIR}/unix-install/opencv_run_all_tests.sh" @ONLY)
     install(PROGRAMS "${CMAKE_BINARY_DIR}/unix-install/opencv_run_all_tests.sh"
-            DESTINATION ${CMAKE_INSTALL_PREFIX} COMPONENT tests)
+            DESTINATION ./ COMPONENT tests)
   elseif(WIN32)
     configure_file("${CMAKE_CURRENT_SOURCE_DIR}/cmake/templates/opencv_run_all_tests_windows.cmd.in"
                    "${CMAKE_BINARY_DIR}/win-install/opencv_run_all_tests.cmd" @ONLY)
@@ -737,11 +787,11 @@ endif()
 if(ANDROID OR NOT UNIX)
   install(FILES ${OPENCV_LICENSE_FILE}
         PERMISSIONS OWNER_READ GROUP_READ WORLD_READ
-        DESTINATION ${CMAKE_INSTALL_PREFIX} COMPONENT libs)
+        DESTINATION ./ COMPONENT libs)
   if(OPENCV_README_FILE)
     install(FILES ${OPENCV_README_FILE}
             PERMISSIONS OWNER_READ GROUP_READ WORLD_READ
-            DESTINATION ${CMAKE_INSTALL_PREFIX} COMPONENT libs)
+            DESTINATION ./ COMPONENT libs)
   endif()
 endif()
 
@@ -753,10 +803,46 @@ status("General configuration for OpenCV ${OPENCV_VERSION} =====================
 if(OPENCV_VCSVERSION)
   status("  Version control:" ${OPENCV_VCSVERSION})
 endif()
+if(OPENCV_EXTRA_MODULES_PATH AND NOT BUILD_INFO_SKIP_EXTRA_MODULES)
+  set(__dump_extra_header OFF)
+  foreach(p ${OPENCV_EXTRA_MODULES_PATH})
+    if(EXISTS ${p})
+      if(NOT __dump_extra_header)
+        set(__dump_extra_header ON)
+        status("")
+        status("  Extra modules:")
+      else()
+        status("")
+      endif()
+      set(EXTRA_MODULES_VCSVERSION "unknown")
+      if(GIT_FOUND)
+        execute_process(COMMAND "${GIT_EXECUTABLE}" describe --tags --always --dirty --match "[0-9].[0-9].[0-9]*"
+          WORKING_DIRECTORY "${p}"
+          OUTPUT_VARIABLE EXTRA_MODULES_VCSVERSION
+          RESULT_VARIABLE GIT_RESULT
+          ERROR_QUIET
+          OUTPUT_STRIP_TRAILING_WHITESPACE
+        )
+        if(NOT GIT_RESULT EQUAL 0)
+          set(EXTRA_MODULES_VCSVERSION "unknown")
+        endif()
+      endif()
+      status("    Location (extra):" ${p})
+      status("    Version control (extra):" ${EXTRA_MODULES_VCSVERSION})
+    endif()
+  endforeach()
+  unset(__dump_extra_header)
+endif()
 
 # ========================== build platform ==========================
 status("")
 status("  Platform:")
+if(NOT CMAKE_VERSION VERSION_LESS 2.8.11 AND NOT BUILD_INFO_SKIP_TIMESTAMP)
+  string(TIMESTAMP TIMESTAMP "" UTC)
+  if(TIMESTAMP)
+    status("    Timestamp:"    ${TIMESTAMP})
+  endif()
+endif()
 status("    Host:"             ${CMAKE_HOST_SYSTEM_NAME} ${CMAKE_HOST_SYSTEM_VERSION} ${CMAKE_HOST_SYSTEM_PROCESSOR})
 if(CMAKE_CROSSCOMPILING)
   status("    Target:"         ${CMAKE_SYSTEM_NAME} ${CMAKE_SYSTEM_VERSION} ${CMAKE_SYSTEM_PROCESSOR})
@@ -802,6 +888,7 @@ else()
   status("    Linker flags (Release):" ${CMAKE_SHARED_LINKER_FLAGS} ${CMAKE_SHARED_LINKER_FLAGS_RELEASE})
   status("    Linker flags (Debug):"   ${CMAKE_SHARED_LINKER_FLAGS} ${CMAKE_SHARED_LINKER_FLAGS_DEBUG})
 endif()
+status("    ccache:"                  CMAKE_COMPILER_IS_CCACHE THEN YES ELSE NO)
 status("    Precompiled headers:"     PCHSupport_FOUND AND ENABLE_PRECOMPILED_HEADERS THEN YES ELSE NO)
 
 # ========================== Dependencies ============================
@@ -836,6 +923,11 @@ status("    Disabled:"               OPENCV_MODULES_DISABLED_USER  THEN ${OPENCV
 status("    Disabled by dependency:" OPENCV_MODULES_DISABLED_AUTO  THEN ${OPENCV_MODULES_DISABLED_AUTO_ST}  ELSE "-")
 status("    Unavailable:"            OPENCV_MODULES_DISABLED_FORCE THEN ${OPENCV_MODULES_DISABLED_FORCE_ST} ELSE "-")
 
+if(OPENCV_ENABLE_NONFREE)
+  status("")
+  status("  Non-free algorithms are enabled")
+endif()
+
 # ========================== Android details ==========================
 if(ANDROID)
   status("")
@@ -931,6 +1023,7 @@ if(WITH_PNG)
 else()
   status("    PNG:"        "NO")
 endif()
+
 if(WITH_TIFF)
   if(TIFF_VERSION_STRING AND TIFF_FOUND)
     status("    TIFF:"     "${TIFF_LIBRARY} (ver ${TIFF_VERSION} - ${TIFF_VERSION_STRING})")
@@ -957,6 +1050,12 @@ else()
   status("    GDAL:"     "NO")
 endif()
 
+if(WITH_GDCM)
+  status("    GDCM:"   GDCM_FOUND THEN "YES (ver ${GDCM_VERSION})" ELSE "NO")
+else()
+  status("    GDCM:"     "NO")
+endif()
+
 # ========================== VIDEO IO ==========================
 status("")
 status("  Video I/O:")
@@ -970,23 +1069,18 @@ if(DEFINED WITH_1394)
   status("    DC1394 2.x:"     HAVE_DC1394_2       THEN "YES (ver ${ALIASOF_libdc1394-2_VERSION})" ELSE NO)
 endif(DEFINED WITH_1394)
 
-if(DEFINED WITH_AVFOUNDATION)
-  status("    AVFoundation:"   WITH_AVFOUNDATION   THEN YES                                        ELSE NO)
-endif(DEFINED WITH_AVFOUNDATION)
-
-if(DEFINED WITH_FFMPEG)
+if(DEFINED WITH_FFMPEG OR HAVE_FFMPEG)
   if(WIN32)
     status("    FFMPEG:"       WITH_FFMPEG         THEN "YES (prebuilt binaries)"                  ELSE NO)
   else()
     status("    FFMPEG:"       HAVE_FFMPEG         THEN YES ELSE NO)
   endif()
-  status("      codec:"        HAVE_FFMPEG_CODEC   THEN "YES (ver ${ALIASOF_libavcodec_VERSION})"  ELSE NO)
-  status("      format:"       HAVE_FFMPEG_FORMAT  THEN "YES (ver ${ALIASOF_libavformat_VERSION})" ELSE NO)
-  status("      util:"         HAVE_FFMPEG_UTIL    THEN "YES (ver ${ALIASOF_libavutil_VERSION})"   ELSE NO)
-  status("      swscale:"      HAVE_FFMPEG_SWSCALE THEN "YES (ver ${ALIASOF_libswscale_VERSION})"  ELSE NO)
-  status("      resample:"     HAVE_FFMPEG_RESAMPLE THEN "YES (ver ${ALIASOF_libavresample_VERSION})"  ELSE NO)
-  status("      gentoo-style:" HAVE_GENTOO_FFMPEG  THEN YES                                        ELSE NO)
-endif(DEFINED WITH_FFMPEG)
+  status("      avcodec:"      FFMPEG_libavcodec_FOUND    THEN "YES (ver ${FFMPEG_libavcodec_VERSION})"    ELSE NO)
+  status("      avformat:"     FFMPEG_libavformat_FOUND   THEN "YES (ver ${FFMPEG_libavformat_VERSION})"   ELSE NO)
+  status("      avutil:"       FFMPEG_libavutil_FOUND     THEN "YES (ver ${FFMPEG_libavutil_VERSION})"     ELSE NO)
+  status("      swscale:"      FFMPEG_libswscale_FOUND    THEN "YES (ver ${FFMPEG_libswscale_VERSION})"    ELSE NO)
+  status("      avresample:"   FFMPEG_libavresample_FOUND THEN "YES (ver ${FFMPEG_libavresample_VERSION})" ELSE NO)
+endif()
 
 if(DEFINED WITH_GSTREAMER)
   status("    GStreamer:"      HAVE_GSTREAMER      THEN ""                                         ELSE NO)
@@ -1007,7 +1101,7 @@ if(DEFINED WITH_OPENNI)
 endif(DEFINED WITH_OPENNI)
 
 if(DEFINED WITH_OPENNI2)
-  status("    OpenNI2:"		   HAVE_OPENNI2	   THEN "YES (ver ${OPENNI2_VERSION_STRING}, build ${OPENNI2_VERSION_BUILD})"
+  status("    OpenNI2:"        HAVE_OPENNI2    THEN "YES (ver ${OPENNI2_VERSION_STRING}, build ${OPENNI2_VERSION_BUILD})"
                                                                                                    ELSE NO)
 endif(DEFINED WITH_OPENNI2)
 
@@ -1019,10 +1113,19 @@ if(DEFINED WITH_GIGEAPI)
   status("    GigEVisionSDK:"  HAVE_GIGE_API       THEN YES                                        ELSE NO)
 endif(DEFINED WITH_GIGEAPI)
 
-if(DEFINED WITH_QUICKTIME)
+if(DEFINED WITH_ARAVIS)
+  status("    Aravis SDK:"     HAVE_ARAVIS_API     THEN "YES (${ARAVIS_LIBRARIES})"                ELSE NO)
+endif(DEFINED WITH_ARAVIS)
+
+if(DEFINED APPLE)
+  status("    AVFoundation:"   HAVE_AVFOUNDATION   THEN YES                                        ELSE NO)
+  if(WITH_QUICKTIME OR HAVE_QUICKTIME)
   status("    QuickTime:"      HAVE_QUICKTIME      THEN YES                                        ELSE NO)
-  status("    QTKit:"          HAVE_QTKIT          THEN YES                                        ELSE NO)
-endif(DEFINED WITH_QUICKTIME)
+  endif()
+  if(WITH_QTKIT OR HAVE_QTKIT)
+  status("    QTKit:"          HAVE_QTKIT          THEN "YES (deprecated)"                         ELSE NO)
+  endif()
+endif(DEFINED APPLE)
 
 if(DEFINED WITH_UNICAP)
   status("    UniCap:"         HAVE_UNICAP         THEN "YES (ver ${ALIASOF_libunicap_VERSION})"   ELSE NO)
@@ -1119,10 +1222,15 @@ if(DEFINED WITH_VA_INTEL)
 status("    Use Intel VA-API/OpenCL:"  HAVE_VA_INTEL       THEN "YES (MSDK: ${VA_INTEL_MSDK_ROOT}  OpenCL: ${VA_INTEL_IOCL_ROOT})" ELSE NO)
 endif(DEFINED WITH_VA_INTEL)
 
+if(DEFINED WITH_LAPACK)
+status("    Use Lapack:"      HAVE_LAPACK     THEN "YES (${LAPACK_LIBRARIES})" ELSE NO)
+endif(DEFINED WITH_LAPACK)
+
 status("    Use Eigen:"      HAVE_EIGEN       THEN "YES (ver ${EIGEN_WORLD_VERSION}.${EIGEN_MAJOR_VERSION}.${EIGEN_MINOR_VERSION})" ELSE NO)
 status("    Use Cuda:"       HAVE_CUDA        THEN "YES (ver ${CUDA_VERSION_STRING})" ELSE NO)
 status("    Use OpenCL:"     HAVE_OPENCL      THEN YES ELSE NO)
-status("    Use custom HAL:" OPENCV_HAL_HEADERS AND OPENCV_HAL_LIBS THEN "YES (${OPENCV_HAL_HEADERS}; ${OPENCV_HAL_LIBS})" ELSE "NO")
+status("    Use OpenVX:"     HAVE_OPENVX      THEN "YES (${OPENVX_LIBRARIES})" ELSE "NO")
+status("    Use custom HAL:" OpenCV_USED_HAL  THEN "YES (${OpenCV_USED_HAL})" ELSE "NO")
 
 if(HAVE_CUDA)
   status("")
@@ -1138,14 +1246,13 @@ endif()
 
 if(HAVE_OPENCL)
   status("")
-  status("  OpenCL:")
   if(HAVE_OPENCL_STATIC)
-    set(__opencl_ver "static")
+    set(__opencl_type "<Link with OpenCL library>")
   else()
-    set(__opencl_ver "dynamic")
+    set(__opencl_type "<Dynamic loading of OpenCL library>")
   endif()
-  status("    Version:"       ${__opencl_ver})
-  if(OPENCL_INCLUDE_DIR)
+  status("  OpenCL:"                 ${__opencl_type})
+  if(OPENCL_INCLUDE_DIRS)
     status("    Include path:"       ${OPENCL_INCLUDE_DIRS})
   endif()
   if(OPENCL_LIBRARIES)
@@ -1162,7 +1269,7 @@ if(HAVE_OPENCL)
         list(APPEND __libs "${l}")
       endif()
     endforeach()
-    status("    libraries:"          ${__libs})
+    status("    Link libraries:"          ${__libs})
   endif()
   status("    Use AMDFFT:"           HAVE_CLAMDFFT  THEN YES ELSE NO)
   status("    Use AMDBLAS:"          HAVE_CLAMDBLAS THEN YES ELSE NO)
@@ -1223,7 +1330,6 @@ if(BUILD_DOCS)
   status("")
   status("  Documentation:")
   status("    Doxygen:"             DOXYGEN_FOUND             THEN "${DOXYGEN_EXECUTABLE} (ver ${DOXYGEN_VERSION})" ELSE NO)
-  status("    PlantUML:"            PLANTUML_JAR              THEN "${PLANTUML_JAR}" ELSE NO)
 endif()
 
 # ========================== samples and tests ==========================
@@ -1255,3 +1361,7 @@ endif()
 # ----------------------------------------------------------------------------
 
 include(cmake/OpenCVPackaging.cmake)
+
+# This should be the last command
+ocv_cmake_dump_vars("" TOFILE "CMakeVars.txt")
+ocv_cmake_eval(DEBUG_POST ONCE)
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 1e13c89..318e9ac 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -1,3 +1,3 @@
 ## Contributing guidelines
 
-All guidelines for contributing to the OpenCV repository can be found at [`How to contribute guideline`](https://github.com/Itseez/opencv/wiki/How_to_contribute).
+All guidelines for contributing to the OpenCV repository can be found at [`How to contribute guideline`](https://github.com/opencv/opencv/wiki/How_to_contribute).
diff --git a/LICENSE b/LICENSE
index ab58eeb..fce70d7 100644
--- a/LICENSE
+++ b/LICENSE
@@ -7,12 +7,12 @@ copy or use the software.
                For Open Source Computer Vision Library
                        (3-clause BSD License)
 
-Copyright (C) 2000-2015, Intel Corporation, all rights reserved.
+Copyright (C) 2000-2016, Intel Corporation, all rights reserved.
 Copyright (C) 2009-2011, Willow Garage Inc., all rights reserved.
-Copyright (C) 2009-2015, NVIDIA Corporation, all rights reserved.
+Copyright (C) 2009-2016, NVIDIA Corporation, all rights reserved.
 Copyright (C) 2010-2013, Advanced Micro Devices, Inc., all rights reserved.
-Copyright (C) 2015, OpenCV Foundation, all rights reserved.
-Copyright (C) 2015, Itseez Inc., all rights reserved.
+Copyright (C) 2015-2016, OpenCV Foundation, all rights reserved.
+Copyright (C) 2015-2016, Itseez Inc., all rights reserved.
 Third party copyrights are property of their respective owners.
 
 Redistribution and use in source and binary forms, with or without modification,
diff --git a/README.md b/README.md
index da3c961..37543b6 100644
--- a/README.md
+++ b/README.md
@@ -1,17 +1,15 @@
 ### OpenCV: Open Source Computer Vision Library
 
-[![Gittip](http://img.shields.io/gittip/OpenCV.png)](https://www.gittip.com/OpenCV/)
-
 #### Resources
 
 * Homepage: <http://opencv.org>
 * Docs: <http://docs.opencv.org/master/>
 * Q&A forum: <http://answers.opencv.org>
-* Issue tracking: <https://github.com/Itseez/opencv/issues>
+* Issue tracking: <https://github.com/opencv/opencv/issues>
 
 #### Contributing
 
-Please read before starting work on a pull request: <https://github.com/Itseez/opencv/wiki/How_to_contribute>
+Please read before starting work on a pull request: <https://github.com/opencv/opencv/wiki/How_to_contribute>
 
 Summary of guidelines:
 
diff --git a/apps/CMakeLists.txt b/apps/CMakeLists.txt
index 095c7fc..f2cdc87 100644
--- a/apps/CMakeLists.txt
+++ b/apps/CMakeLists.txt
@@ -4,3 +4,6 @@ link_libraries(${OPENCV_LINKER_LIBS})
 add_subdirectory(traincascade)
 add_subdirectory(createsamples)
 add_subdirectory(annotation)
+add_subdirectory(visualisation)
+add_subdirectory(interactive-calibration)
+add_subdirectory(version)
diff --git a/apps/annotation/CMakeLists.txt b/apps/annotation/CMakeLists.txt
index 57b133d..9288e86 100644
--- a/apps/annotation/CMakeLists.txt
+++ b/apps/annotation/CMakeLists.txt
@@ -21,7 +21,6 @@ set_target_properties(${the_target} PROPERTIES
                       DEBUG_POSTFIX "${OPENCV_DEBUG_POSTFIX}"
                       ARCHIVE_OUTPUT_DIRECTORY ${LIBRARY_OUTPUT_PATH}
                       RUNTIME_OUTPUT_DIRECTORY ${EXECUTABLE_OUTPUT_PATH}
-                      INSTALL_NAME_DIR lib
                       OUTPUT_NAME "opencv_annotation")
 
 if(ENABLE_SOLUTION_FOLDERS)
diff --git a/apps/annotation/opencv_annotation.cpp b/apps/annotation/opencv_annotation.cpp
index c94d6c3..febe9fc 100644
--- a/apps/annotation/opencv_annotation.cpp
+++ b/apps/annotation/opencv_annotation.cpp
@@ -46,6 +46,9 @@ USAGE:
 ./opencv_annotation -images <folder location> -annotations <ouput file>
 
 Created by: Puttemans Steven - February 2015
+Adapted by: Puttemans Steven - April 2016 - Vectorize the process to enable better processing
+                                               + early leave and store by pressing an ESC key
+                                               + enable delete `d` button, to remove last annotation
 *****************************************************************************************************/
 
 #include <opencv2/core.hpp>
@@ -68,16 +71,15 @@ using namespace cv;
 
 // Function prototypes
 void on_mouse(int, int, int, int, void*);
-string int2string(int);
-void get_annotations(Mat, stringstream*);
+vector<Rect> get_annotations(Mat);
 
 // Public parameters
 Mat image;
 int roi_x0 = 0, roi_y0 = 0, roi_x1 = 0, roi_y1 = 0, num_of_rec = 0;
-bool start_draw = false;
+bool start_draw = false, stop = false;
 
 // Window name for visualisation purposes
-const string window_name="OpenCV Based Annotation Tool";
+const string window_name = "OpenCV Based Annotation Tool";
 
 // FUNCTION : Mouse response for selecting objects in images
 // If left button is clicked, start drawing a rectangle as long as mouse moves
@@ -98,7 +100,8 @@ void on_mouse(int event, int x, int y, int , void * )
             start_draw = false;
         }
     }
-    // Action when mouse is moving
+
+    // Action when mouse is moving and drawing is enabled
     if((event == EVENT_MOUSEMOVE) && start_draw)
     {
         // Redraw bounding box for annotation
@@ -109,42 +112,34 @@ void on_mouse(int event, int x, int y, int , void * )
     }
 }
 
-// FUNCTION : snippet to convert an integer value to a string using a clean function
-// instead of creating a stringstream each time inside the main code
-string int2string(int num)
-{
-    stringstream temp_stream;
-    temp_stream << num;
-    return temp_stream.str();
-}
-
-// FUNCTION : given an image containing positive object instances, add all the object
-// annotations to a known stringstream
-void get_annotations(Mat input_image, stringstream* output_stream)
+// FUNCTION : returns a vector of Rect objects given an image containing positive object instances
+vector<Rect> get_annotations(Mat input_image)
 {
-    // Make it possible to exit the annotation
-    bool stop = false;
+    vector<Rect> current_annotations;
 
-    // Reset the num_of_rec element at each iteration
-    // Make sure the global image is set to the current image
-    num_of_rec = 0;
-    image = input_image;
+    // Make it possible to exit the annotation process
+    stop = false;
 
     // Init window interface and couple mouse actions
     namedWindow(window_name, WINDOW_AUTOSIZE);
     setMouseCallback(window_name, on_mouse);
 
+    image = input_image;
     imshow(window_name, image);
-    stringstream temp_stream;
     int key_pressed = 0;
 
     do
     {
+        // Get a temporary image clone
+        Mat temp_image = input_image.clone();
+        Rect currentRect(0, 0, 0, 0);
+
         // Keys for processing
         // You need to select one for confirming a selection and one to continue to the next image
         // Based on the universal ASCII code of the keystroke: http://www.asciitable.com/
         //      c = 99		    add rectangle to current image
         //	    n = 110		    save added rectangles and show next image
+        //      d = 100         delete the last annotation made
         //	    <ESC> = 27      exit program
         key_pressed = 0xFF & waitKey(0);
         switch( key_pressed )
@@ -152,32 +147,53 @@ void get_annotations(Mat input_image, stringstream* output_stream)
         case 27:
                 destroyWindow(window_name);
                 stop = true;
+                break;
         case 99:
-                // Add a rectangle to the list
-                num_of_rec++;
                 // Draw initiated from top left corner
                 if(roi_x0<roi_x1 && roi_y0<roi_y1)
                 {
-                    temp_stream << " " << int2string(roi_x0) << " " << int2string(roi_y0) << " " << int2string(roi_x1-roi_x0) << " " << int2string(roi_y1-roi_y0);
+                    currentRect.x = roi_x0;
+                    currentRect.y = roi_y0;
+                    currentRect.width = roi_x1-roi_x0;
+                    currentRect.height = roi_y1-roi_y0;
                 }
                 // Draw initiated from bottom right corner
                 if(roi_x0>roi_x1 && roi_y0>roi_y1)
                 {
-                    temp_stream << " " << int2string(roi_x1) << " " << int2string(roi_y1) << " " << int2string(roi_x0-roi_x1) << " " << int2string(roi_y0-roi_y1);
+                    currentRect.x = roi_x1;
+                    currentRect.y = roi_y1;
+                    currentRect.width = roi_x0-roi_x1;
+                    currentRect.height = roi_y0-roi_y1;
                 }
                 // Draw initiated from top right corner
                 if(roi_x0>roi_x1 && roi_y0<roi_y1)
                 {
-                    temp_stream << " " << int2string(roi_x1) << " " << int2string(roi_y0) << " " << int2string(roi_x0-roi_x1) << " " << int2string(roi_y1-roi_y0);
+                    currentRect.x = roi_x1;
+                    currentRect.y = roi_y0;
+                    currentRect.width = roi_x0-roi_x1;
+                    currentRect.height = roi_y1-roi_y0;
                 }
                 // Draw initiated from bottom left corner
                 if(roi_x0<roi_x1 && roi_y0>roi_y1)
                 {
-                    temp_stream << " " << int2string(roi_x0) << " " << int2string(roi_y1) << " " << int2string(roi_x1-roi_x0) << " " << int2string(roi_y0-roi_y1);
+                    currentRect.x = roi_x0;
+                    currentRect.y = roi_y1;
+                    currentRect.width = roi_x1-roi_x0;
+                    currentRect.height = roi_y0-roi_y1;
+                }
+                // Draw the rectangle on the canvas
+                // Add the rectangle to the vector of annotations
+                current_annotations.push_back(currentRect);
+                break;
+        case 100:
+                // Remove the last annotation
+                if(current_annotations.size() > 0){
+                    current_annotations.pop_back();
                 }
-
-                rectangle(input_image, Point(roi_x0,roi_y0), Point(roi_x1,roi_y1), Scalar(0,255,0), 1);
-
+                break;
+        default:
+                // Default case --> do nothing at all
+                // Other keystrokes can simply be ignored
                 break;
         }
 
@@ -186,46 +202,52 @@ void get_annotations(Mat input_image, stringstream* output_stream)
         {
             break;
         }
+
+        // Draw all the current rectangles onto the top image and make sure that the global image is linked
+        for(int i=0; i < (int)current_annotations.size(); i++){
+            rectangle(temp_image, current_annotations[i], Scalar(0,255,0), 1);
+        }
+        image = temp_image;
+
+        // Force an explicit redraw of the canvas --> necessary to visualize delete correctly
+        imshow(window_name, image);
     }
     // Continue as long as the next image key has not been pressed
     while(key_pressed != 110);
 
-    // If there are annotations AND the next image key is pressed
-    // Write the image annotations to the file
-    if(num_of_rec>0 && key_pressed==110)
-    {
-        *output_stream << " " << num_of_rec << temp_stream.str() << endl;
-    }
-
     // Close down the window
     destroyWindow(window_name);
+
+    // Return the data
+    return current_annotations;
 }
 
 int main( int argc, const char** argv )
 {
-    // If no arguments are given, then supply some information on how this tool works
-    if( argc == 1 ){
-        cout << "Usage: " << argv[0] << endl;
-        cout << " -images <folder_location> [example - /data/testimages/]" << endl;
-        cout << " -annotations <ouput_file> [example - /data/annotations.txt]" << endl;
-
+    // Use the cmdlineparser to process input arguments
+    CommandLineParser parser(argc, argv,
+        "{ help h usage ? |      | show this message }"
+        "{ images i       |      | (required) path to image folder [example - /data/testimages/] }"
+        "{ annotations a  |      | (required) path to annotations txt file [example - /data/annotations.txt] }"
+        "{ maxWindowHeight m  |  -1   | (optional) images larger in height than this value will be scaled down }"
+        "{ resizeFactor r  |  2  | (optional) factor for scaling down [default = half the size] }"
+    );
+    // Read in the input arguments
+    if (parser.has("help")){
+        parser.printMessage();
+        cerr << "TIP: Use absolute paths to avoid any problems with the software!" << endl;
+        return 0;
+    }
+    string image_folder(parser.get<string>("images"));
+    string annotations_file(parser.get<string>("annotations"));
+    if (image_folder.empty() || annotations_file.empty()){
+        parser.printMessage();
+        cerr << "TIP: Use absolute paths to avoid any problems with the software!" << endl;
         return -1;
     }
 
-    // Read in the input arguments
-    string image_folder;
-    string annotations;
-    for(int i = 1; i < argc; ++i )
-    {
-        if( !strcmp( argv[i], "-images" ) )
-        {
-            image_folder = argv[++i];
-        }
-        else if( !strcmp( argv[i], "-annotations" ) )
-        {
-            annotations = argv[++i];
-        }
-    }
+    int resizeFactor = parser.get<int>("resizeFactor");
+    int const maxWindowHeight = parser.get<int>("maxWindowHeight") > 0 ? parser.get<int>("maxWindowHeight") : -1;
 
     // Check if the folder actually exists
     // If -1 is returned then the folder actually exists, and thus you can continue
@@ -248,14 +270,9 @@ int main( int argc, const char** argv )
     }
     #endif
 
-    // Create the outputfilestream
-    ofstream output(annotations.c_str());
-    if ( !output.is_open() ){
-        cerr << "The path for the output file contains an error and could not be opened. Please check again!" << endl;
-        return 0;
-    }
-
+    // Start by processing the data
     // Return the image filenames inside the image folder
+    vector< vector<Rect> > annotations;
     vector<String> filenames;
     String folder(image_folder);
     glob(folder, filenames);
@@ -266,6 +283,7 @@ int main( int argc, const char** argv )
     for (size_t i = 0; i < filenames.size(); i++){
         // Read in an image
         Mat current_image = imread(filenames[i]);
+        bool const resize_bool = (maxWindowHeight > 0) && (current_image.rows > maxWindowHeight);
 
         // Check if the image is actually read - avoid other files in the folder, because glob() takes them all
         // If not then simply skip this iteration
@@ -273,14 +291,45 @@ int main( int argc, const char** argv )
             continue;
         }
 
-        // Perform annotations & generate corresponding output
-        stringstream output_stream;
-        get_annotations(current_image, &output_stream);
+        if(resize_bool){
+            resize(current_image, current_image, Size(current_image.cols/resizeFactor, current_image.rows/resizeFactor));
+        }
+
+        // Perform annotations & store the result inside the vectorized structure
+        // If the image was resized before, then resize the found annotations back to original dimensions
+        vector<Rect> current_annotations = get_annotations(current_image);
+        if(resize_bool){
+            for(int j =0; j < (int)current_annotations.size(); j++){
+                current_annotations[j].x = current_annotations[j].x * resizeFactor;
+                current_annotations[j].y = current_annotations[j].y * resizeFactor;
+                current_annotations[j].width = current_annotations[j].width * resizeFactor;
+                current_annotations[j].height = current_annotations[j].height * resizeFactor;
+            }
+        }
+        annotations.push_back(current_annotations);
+
+        // Check if the ESC key was hit, then exit earlier then expected
+        if(stop){
+            break;
+        }
+    }
+
+    // When all data is processed, store the data gathered inside the proper file
+    // This now even gets called when the ESC button was hit to store preliminary results
+    ofstream output(annotations_file.c_str());
+    if ( !output.is_open() ){
+        cerr << "The path for the output file contains an error and could not be opened. Please check again!" << endl;
+        return 0;
+    }
 
-        // Store the annotations, write to the output file
-        if (output_stream.str() != ""){
-            output << filenames[i] << output_stream.str();
+    // Store the annotations, write to the output file
+    for(int i = 0; i < (int)annotations.size(); i++){
+        output << filenames[i] << " " << annotations[i].size();
+        for(int j=0; j < (int)annotations[i].size(); j++){
+            Rect temp = annotations[i][j];
+            output << " " << temp.x << " " << temp.y << " " << temp.width << " " << temp.height;
         }
+        output << endl;
     }
 
     return 0;
diff --git a/apps/createsamples/CMakeLists.txt b/apps/createsamples/CMakeLists.txt
index 2450623..a285c69 100644
--- a/apps/createsamples/CMakeLists.txt
+++ b/apps/createsamples/CMakeLists.txt
@@ -23,7 +23,6 @@ set_target_properties(${the_target} PROPERTIES
                       DEBUG_POSTFIX "${OPENCV_DEBUG_POSTFIX}"
                       ARCHIVE_OUTPUT_DIRECTORY ${LIBRARY_OUTPUT_PATH}
                       RUNTIME_OUTPUT_DIRECTORY ${EXECUTABLE_OUTPUT_PATH}
-                      INSTALL_NAME_DIR lib
                       OUTPUT_NAME "opencv_createsamples")
 
 if(ENABLE_SOLUTION_FOLDERS)
diff --git a/apps/createsamples/createsamples.cpp b/apps/createsamples/createsamples.cpp
index 9f05e41..1660ade 100644
--- a/apps/createsamples/createsamples.cpp
+++ b/apps/createsamples/createsamples.cpp
@@ -76,6 +76,7 @@ int main( int argc, char* argv[] )
     double scale = 4.0;
     int width  = 24;
     int height = 24;
+    double maxscale = -1.0;
 
     srand((unsigned int)time(0));
 
@@ -92,9 +93,10 @@ int main( int argc, char* argv[] )
                 "  [-maxyangle <max_y_rotation_angle = %f>]\n"
                 "  [-maxzangle <max_z_rotation_angle = %f>]\n"
                 "  [-show [<scale = %f>]]\n"
-                "  [-w <sample_width = %d>]\n  [-h <sample_height = %d>]\n",
+                "  [-w <sample_width = %d>]\n  [-h <sample_height = %d>]\n"
+                "  [-maxscale <max sample scale = %f>]\n",
                 argv[0], num, bgcolor, bgthreshold, maxintensitydev,
-                maxxangle, maxyangle, maxzangle, scale, width, height );
+                maxxangle, maxyangle, maxzangle, scale, width, height, maxscale );
 
         return 0;
     }
@@ -172,6 +174,10 @@ int main( int argc, char* argv[] )
         {
             height = atoi( argv[++i] );
         }
+        else if( !strcmp( argv[i], "-maxscale" ) )
+        {
+            maxscale = atof( argv[++i] );
+        }
     }
 
     printf( "Info file name: %s\n", ((infoname == NULL) ?   nullname : infoname ) );
@@ -194,6 +200,7 @@ int main( int argc, char* argv[] )
     }
     printf( "Width: %d\n", width );
     printf( "Height: %d\n", height );
+    printf( "Max Scale: %g\n", maxscale);
 
     /* determine action */
     if( imagename && vecname )
@@ -213,7 +220,7 @@ int main( int argc, char* argv[] )
 
         cvCreateTestSamples( infoname, imagename, bgcolor, bgthreshold, bgfilename, num,
             invert, maxintensitydev,
-            maxxangle, maxyangle, maxzangle, showsamples, width, height );
+            maxxangle, maxyangle, maxzangle, showsamples, width, height, maxscale);
 
         printf( "Done\n" );
     }
diff --git a/apps/createsamples/utility.cpp b/apps/createsamples/utility.cpp
index b5834f3..2226cd8 100644
--- a/apps/createsamples/utility.cpp
+++ b/apps/createsamples/utility.cpp
@@ -38,7 +38,6 @@
 // the use of this software, even if advised of the possibility of such damage.
 //
 //M*/
-
 #include <cstring>
 #include <ctime>
 
@@ -1271,7 +1270,7 @@ void cvCreateTrainingSamples( const char* filename,
                 if( showsamples )
                 {
                     cvShowImage( "Sample", &sample );
-                    if( cvWaitKey( 0 ) == 27 )
+                    if( (cvWaitKey( 0 ) & 0xFF) == 27 )
                     {
                         showsamples = 0;
                     }
@@ -1308,7 +1307,7 @@ void cvCreateTestSamples( const char* infoname,
                           int invert, int maxintensitydev,
                           double maxxangle, double maxyangle, double maxzangle,
                           int showsamples,
-                          int winwidth, int winheight )
+                          int winwidth, int winheight, double maxscale )
 {
     CvSampleDistortionData data;
 
@@ -1337,7 +1336,6 @@ void cvCreateTestSamples( const char* infoname,
             int i;
             int x, y, width, height;
             float scale;
-            float maxscale;
             int inverse;
 
             if( showsamples )
@@ -1366,12 +1364,16 @@ void cvCreateTestSamples( const char* infoname,
             for( i = 0; i < count; i++ )
             {
                 icvGetNextFromBackgroundData( cvbgdata, cvbgreader );
-
-                maxscale = MIN( 0.7F * cvbgreader->src.cols / winwidth,
+                if( maxscale < 0.0 )
+                {
+                    maxscale = MIN( 0.7F * cvbgreader->src.cols / winwidth,
                                    0.7F * cvbgreader->src.rows / winheight );
+                }
+
                 if( maxscale < 1.0F ) continue;
 
-                scale = (maxscale - 1.0F) * rand() / RAND_MAX + 1.0F;
+                scale = ((float)maxscale - 1.0F) * rand() / RAND_MAX + 1.0F;
+
                 width = (int) (scale * winwidth);
                 height = (int) (scale * winheight);
                 x = (int) ((0.1+0.8 * rand()/RAND_MAX) * (cvbgreader->src.cols - width));
@@ -1400,7 +1402,7 @@ void cvCreateTestSamples( const char* infoname,
                 if( showsamples )
                 {
                     cvShowImage( "Image", &cvbgreader->src );
-                    if( cvWaitKey( 0 ) == 27 )
+                    if( (cvWaitKey( 0 ) & 0xFF) == 27 )
                     {
                         showsamples = 0;
                     }
@@ -1523,7 +1525,7 @@ int cvCreateTrainingSamplesFromInfo( const char* infoname, const char* vecfilena
             if( showsamples )
             {
                 cvShowImage( "Sample", sample );
-                if( cvWaitKey( 0 ) == 27 )
+                if( (cvWaitKey( 0 ) & 0xFF) == 27 )
                 {
                     showsamples = 0;
                 }
@@ -1670,7 +1672,7 @@ void cvShowVecSamples( const char* filename, int winwidth, int winheight,
                 icvGetTraininDataFromVec( sample, &file );
                 if( scale != 1.0 ) cvResize( sample, scaled_sample, CV_INTER_LINEAR);
                 cvShowImage( "Sample", scaled_sample );
-                if( cvWaitKey( 0 ) == 27 ) break;
+                if( (cvWaitKey( 0 ) & 0xFF) == 27 ) break;
             }
             if( scaled_sample && scaled_sample != sample ) cvReleaseMat( &scaled_sample );
             cvReleaseMat( &sample );
@@ -1678,4 +1680,4 @@ void cvShowVecSamples( const char* filename, int winwidth, int winheight,
         }
         fclose( file.input );
     }
-}
\ No newline at end of file
+}
diff --git a/apps/createsamples/utility.hpp b/apps/createsamples/utility.hpp
index 9367778..d04947c 100644
--- a/apps/createsamples/utility.hpp
+++ b/apps/createsamples/utility.hpp
@@ -86,7 +86,7 @@ void cvCreateTestSamples( const char* infoname,
                           int invert, int maxintensitydev,
                           double maxxangle, double maxyangle, double maxzangle,
                           int showsamples,
-                          int winwidth, int winheight );
+                          int winwidth, int winheight, double maxscale );
 
 /*
  * cvCreateTrainingSamplesFromInfo
diff --git a/apps/interactive-calibration/CMakeLists.txt b/apps/interactive-calibration/CMakeLists.txt
new file mode 100644
index 0000000..735c453
--- /dev/null
+++ b/apps/interactive-calibration/CMakeLists.txt
@@ -0,0 +1,39 @@
+set(OPENCV_INTERACTIVECALIBRATION_DEPS opencv_core opencv_imgproc opencv_features2d opencv_aruco opencv_highgui opencv_calib3d opencv_videoio)
+ocv_check_dependencies(${OPENCV_INTERACTIVECALIBRATION_DEPS})
+
+if(NOT OCV_DEPENDENCIES_FOUND)
+  return()
+endif()
+
+project(interactive-calibration)
+set(the_target opencv_interactive-calibration)
+
+ocv_target_include_directories(${the_target} PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}" "${OpenCV_SOURCE_DIR}/include/opencv")
+ocv_target_include_modules_recurse(${the_target} ${OPENCV_INTERACTIVECALIBRATION_DEPS})
+
+file(GLOB SRCS *.cpp)
+file(GLOB HDRS *.h*)
+
+set(interactive-calibration_files ${SRCS} ${HDRS})
+
+ocv_add_executable(${the_target} ${interactive-calibration_files})
+ocv_target_link_libraries(${the_target} ${OPENCV_INTERACTIVECALIBRATION_DEPS})
+
+set_target_properties(${the_target} PROPERTIES
+                      DEBUG_POSTFIX "${OPENCV_DEBUG_POSTFIX}"
+                      ARCHIVE_OUTPUT_DIRECTORY ${LIBRARY_OUTPUT_PATH}
+                      RUNTIME_OUTPUT_DIRECTORY ${EXECUTABLE_OUTPUT_PATH}
+                      INSTALL_NAME_DIR lib
+                    OUTPUT_NAME "opencv_interactive-calibration")
+
+if(ENABLE_SOLUTION_FOLDERS)
+  set_target_properties(${the_target} PROPERTIES FOLDER "applications")
+endif()
+
+if(INSTALL_CREATE_DISTRIB)
+  if(BUILD_SHARED_LIBS)
+    install(TARGETS ${the_target} RUNTIME DESTINATION ${OPENCV_BIN_INSTALL_PATH} CONFIGURATIONS Release COMPONENT dev)
+  endif()
+else()
+  install(TARGETS ${the_target} OPTIONAL RUNTIME DESTINATION ${OPENCV_BIN_INSTALL_PATH} COMPONENT dev)
+endif()
diff --git a/apps/interactive-calibration/calibCommon.hpp b/apps/interactive-calibration/calibCommon.hpp
new file mode 100644
index 0000000..6acf610
--- /dev/null
+++ b/apps/interactive-calibration/calibCommon.hpp
@@ -0,0 +1,123 @@
+// This file is part of OpenCV project.
+// It is subject to the license terms in the LICENSE file found in the top-level directory
+// of this distribution and at http://opencv.org/license.html.
+
+#ifndef CALIB_COMMON_HPP
+#define CALIB_COMMON_HPP
+
+#include <opencv2/core.hpp>
+
+#include <memory>
+#include <vector>
+#include <string>
+
+namespace calib
+{
+    #define OVERLAY_DELAY 1000
+    #define IMAGE_MAX_WIDTH 1280
+    #define IMAGE_MAX_HEIGHT 960
+
+    bool showOverlayMessage(const std::string& message);
+
+    enum InputType { Video, Pictures };
+    enum InputVideoSource { Camera, File };
+    enum TemplateType { AcirclesGrid, Chessboard, chAruco, DoubleAcirclesGrid };
+
+    static const std::string mainWindowName = "Calibration";
+    static const std::string gridWindowName = "Board locations";
+    static const std::string consoleHelp = "Hot keys:\nesc - exit application\n"
+                              "s - save current data to .xml file\n"
+                              "r - delete last frame\n"
+                              "u - enable/disable applying undistortion\n"
+                              "d - delete all frames\n"
+                              "v - switch visualization";
+
+    static const double sigmaMult = 1.96;
+
+    struct calibrationData
+    {
+        cv::Mat cameraMatrix;
+        cv::Mat distCoeffs;
+        cv::Mat stdDeviations;
+        cv::Mat perViewErrors;
+        std::vector<cv::Mat> rvecs;
+        std::vector<cv::Mat> tvecs;
+        double totalAvgErr;
+        cv::Size imageSize;
+
+        std::vector<std::vector<cv::Point2f> > imagePoints;
+        std::vector< std::vector<cv::Point3f> > objectPoints;
+
+        std::vector<cv::Mat> allCharucoCorners;
+        std::vector<cv::Mat> allCharucoIds;
+
+        cv::Mat undistMap1, undistMap2;
+
+        calibrationData()
+        {
+            imageSize = cv::Size(IMAGE_MAX_WIDTH, IMAGE_MAX_HEIGHT);
+        }
+    };
+
+    struct cameraParameters
+    {
+        cv::Mat cameraMatrix;
+        cv::Mat distCoeffs;
+        cv::Mat stdDeviations;
+        double avgError;
+
+        cameraParameters(){}
+        cameraParameters(cv::Mat& _cameraMatrix, cv::Mat& _distCoeffs, cv::Mat& _stdDeviations, double _avgError = 0) :
+            cameraMatrix(_cameraMatrix), distCoeffs(_distCoeffs), stdDeviations(_stdDeviations), avgError(_avgError)
+        {}
+    };
+
+    struct captureParameters
+    {
+        InputType captureMethod;
+        InputVideoSource source;
+        TemplateType board;
+        cv::Size boardSize;
+        int charucoDictName;
+        int calibrationStep;
+        float charucoSquareLenght, charucoMarkerSize;
+        float captureDelay;
+        float squareSize;
+        float templDst;
+        std::string videoFileName;
+        bool flipVertical;
+        int camID;
+        int fps;
+        cv::Size cameraResolution;
+        int maxFramesNum;
+        int minFramesNum;
+
+        captureParameters()
+        {
+            calibrationStep = 1;
+            captureDelay = 500.f;
+            maxFramesNum = 30;
+            minFramesNum = 10;
+            fps = 30;
+            cameraResolution = cv::Size(IMAGE_MAX_WIDTH, IMAGE_MAX_HEIGHT);
+        }
+    };
+
+    struct internalParameters
+    {
+        double solverEps;
+        int solverMaxIters;
+        bool fastSolving;
+        double filterAlpha;
+
+        internalParameters()
+        {
+            solverEps = 1e-7;
+            solverMaxIters = 30;
+            fastSolving = false;
+            filterAlpha = 0.1;
+        }
+    };
+}
+
+#endif
diff --git a/apps/interactive-calibration/calibController.cpp b/apps/interactive-calibration/calibController.cpp
new file mode 100644
index 0000000..1888ee5
--- /dev/null
+++ b/apps/interactive-calibration/calibController.cpp
@@ -0,0 +1,332 @@
+// This file is part of OpenCV project.
+// It is subject to the license terms in the LICENSE file found in the top-level directory
+// of this distribution and at http://opencv.org/license.html.
+
+#include "calibController.hpp"
+
+#include <algorithm>
+#include <cmath>
+#include <ctime>
+
+#include <opencv2/calib3d.hpp>
+#include <opencv2/imgproc.hpp>
+
+double calib::calibController::estimateCoverageQuality()
+{
+    int gridSize = 10;
+    int xGridStep = mCalibData->imageSize.width / gridSize;
+    int yGridStep = mCalibData->imageSize.height / gridSize;
+    std::vector<int> pointsInCell(gridSize*gridSize);
+
+    std::fill(pointsInCell.begin(), pointsInCell.end(), 0);
+
+    for(std::vector<std::vector<cv::Point2f> >::iterator it = mCalibData->imagePoints.begin(); it != mCalibData->imagePoints.end(); ++it)
+        for(std::vector<cv::Point2f>::iterator pointIt = (*it).begin(); pointIt != (*it).end(); ++pointIt) {
+            int i = (int)((*pointIt).x / xGridStep);
+            int j = (int)((*pointIt).y / yGridStep);
+            pointsInCell[i*gridSize + j]++;
+        }
+
+    for(std::vector<cv::Mat>::iterator it = mCalibData->allCharucoCorners.begin(); it != mCalibData->allCharucoCorners.end(); ++it)
+        for(int l = 0; l < (*it).size[0]; l++) {
+            int i = (int)((*it).at<float>(l, 0) / xGridStep);
+            int j = (int)((*it).at<float>(l, 1) / yGridStep);
+            pointsInCell[i*gridSize + j]++;
+        }
+
+    cv::Mat mean, stdDev;
+    cv::meanStdDev(pointsInCell, mean, stdDev);
+
+    return mean.at<double>(0) / (stdDev.at<double>(0) + 1e-7);
+}
+
+calib::calibController::calibController()
+{
+    mCalibFlags = 0;
+}
+
+calib::calibController::calibController(cv::Ptr<calib::calibrationData> data, int initialFlags, bool autoTuning, int minFramesNum) :
+    mCalibData(data)
+{
+    mCalibFlags = initialFlags;
+    mNeedTuning = autoTuning;
+    mMinFramesNum = minFramesNum;
+    mConfIntervalsState = false;
+    mCoverageQualityState = false;
+}
+
+void calib::calibController::updateState()
+{
+    if(mCalibData->cameraMatrix.total()) {
+        const double relErrEps = 0.05;
+        bool fConfState = false, cConfState = false, dConfState = true;
+        if(sigmaMult*mCalibData->stdDeviations.at<double>(0) / mCalibData->cameraMatrix.at<double>(0,0) < relErrEps &&
+                sigmaMult*mCalibData->stdDeviations.at<double>(1) / mCalibData->cameraMatrix.at<double>(1,1) < relErrEps)
+            fConfState = true;
+        if(sigmaMult*mCalibData->stdDeviations.at<double>(2) / mCalibData->cameraMatrix.at<double>(0,2) < relErrEps &&
+                sigmaMult*mCalibData->stdDeviations.at<double>(3) / mCalibData->cameraMatrix.at<double>(1,2) < relErrEps)
+            cConfState = true;
+
+        for(int i = 0; i < 5; i++)
+            if(mCalibData->stdDeviations.at<double>(4+i) / fabs(mCalibData->distCoeffs.at<double>(i)) > 1)
+                dConfState = false;
+
+        mConfIntervalsState = fConfState && cConfState && dConfState;
+    }
+
+    if(getFramesNumberState())
+        mCoverageQualityState = estimateCoverageQuality() > 1.8 ? true : false;
+
+    if (getFramesNumberState() && mNeedTuning) {
+        if( !(mCalibFlags & cv::CALIB_FIX_ASPECT_RATIO) &&
+            mCalibData->cameraMatrix.total()) {
+            double fDiff = fabs(mCalibData->cameraMatrix.at<double>(0,0) -
+                                mCalibData->cameraMatrix.at<double>(1,1));
+
+            if (fDiff < 3*mCalibData->stdDeviations.at<double>(0) &&
+                    fDiff < 3*mCalibData->stdDeviations.at<double>(1)) {
+                mCalibFlags |= cv::CALIB_FIX_ASPECT_RATIO;
+                mCalibData->cameraMatrix.at<double>(0,0) =
+                        mCalibData->cameraMatrix.at<double>(1,1);
+            }
+        }
+
+        if(!(mCalibFlags & cv::CALIB_ZERO_TANGENT_DIST)) {
+            const double eps = 0.005;
+            if(fabs(mCalibData->distCoeffs.at<double>(2)) < eps &&
+                    fabs(mCalibData->distCoeffs.at<double>(3)) < eps)
+                mCalibFlags |= cv::CALIB_ZERO_TANGENT_DIST;
+        }
+
+        if(!(mCalibFlags & cv::CALIB_FIX_K1)) {
+            const double eps = 0.005;
+            if(fabs(mCalibData->distCoeffs.at<double>(0)) < eps)
+                mCalibFlags |= cv::CALIB_FIX_K1;
+        }
+
+        if(!(mCalibFlags & cv::CALIB_FIX_K2)) {
+            const double eps = 0.005;
+            if(fabs(mCalibData->distCoeffs.at<double>(1)) < eps)
+                mCalibFlags |= cv::CALIB_FIX_K2;
+        }
+
+        if(!(mCalibFlags & cv::CALIB_FIX_K3)) {
+            const double eps = 0.005;
+            if(fabs(mCalibData->distCoeffs.at<double>(4)) < eps)
+                mCalibFlags |= cv::CALIB_FIX_K3;
+        }
+
+    }
+}
+
+bool calib::calibController::getCommonCalibrationState() const
+{
+    int rating = (int)getFramesNumberState() + (int)getConfidenceIntrervalsState() +
+            (int)getRMSState() + (int)mCoverageQualityState;
+    return rating == 4;
+}
+
+bool calib::calibController::getFramesNumberState() const
+{
+    return std::max(mCalibData->imagePoints.size(), mCalibData->allCharucoCorners.size()) > mMinFramesNum;
+}
+
+bool calib::calibController::getConfidenceIntrervalsState() const
+{
+    return mConfIntervalsState;
+}
+
+bool calib::calibController::getRMSState() const
+{
+    return mCalibData->totalAvgErr < 0.5;
+}
+
+int calib::calibController::getNewFlags() const
+{
+    return mCalibFlags;
+}
+
+
+//////////////////// calibDataController
+
+double calib::calibDataController::estimateGridSubsetQuality(size_t excludedIndex)
+{
+    {
+        int gridSize = 10;
+        int xGridStep = mCalibData->imageSize.width / gridSize;
+        int yGridStep = mCalibData->imageSize.height / gridSize;
+        std::vector<int> pointsInCell(gridSize*gridSize);
+
+        std::fill(pointsInCell.begin(), pointsInCell.end(), 0);
+
+        for(size_t k = 0; k < mCalibData->imagePoints.size(); k++)
+            if(k != excludedIndex)
+                for(std::vector<cv::Point2f>::iterator pointIt = mCalibData->imagePoints[k].begin(); pointIt != mCalibData->imagePoints[k].end(); ++pointIt) {
+                    int i = (int)((*pointIt).x / xGridStep);
+                    int j = (int)((*pointIt).y / yGridStep);
+                    pointsInCell[i*gridSize + j]++;
+                }
+
+        for(size_t k = 0; k < mCalibData->allCharucoCorners.size(); k++)
+            if(k != excludedIndex)
+                for(int l = 0; l <  mCalibData->allCharucoCorners[k].size[0]; l++) {
+                    int i = (int)(mCalibData->allCharucoCorners[k].at<float>(l, 0) / xGridStep);
+                    int j = (int)(mCalibData->allCharucoCorners[k].at<float>(l, 1) / yGridStep);
+                    pointsInCell[i*gridSize + j]++;
+                }
+
+        cv::Mat mean, stdDev;
+        cv::meanStdDev(pointsInCell, mean, stdDev);
+
+        return mean.at<double>(0) / (stdDev.at<double>(0) + 1e-7);
+    }
+}
+
+calib::calibDataController::calibDataController(cv::Ptr<calib::calibrationData> data, int maxFrames, double convParameter) :
+    mCalibData(data), mParamsFileName("CamParams.xml")
+{
+    mMaxFramesNum = maxFrames;
+    mAlpha = convParameter;
+}
+
+calib::calibDataController::calibDataController()
+{
+
+}
+
+void calib::calibDataController::filterFrames()
+{
+    size_t numberOfFrames = std::max(mCalibData->allCharucoIds.size(), mCalibData->imagePoints.size());
+    CV_Assert(numberOfFrames == mCalibData->perViewErrors.total());
+    if(numberOfFrames >= mMaxFramesNum) {
+
+        double worstValue = -HUGE_VAL, maxQuality = estimateGridSubsetQuality(numberOfFrames);
+        size_t worstElemIndex = 0;
+        for(size_t i = 0; i < numberOfFrames; i++) {
+            double gridQDelta = estimateGridSubsetQuality(i) - maxQuality;
+            double currentValue = mCalibData->perViewErrors.at<double>((int)i)*mAlpha + gridQDelta*(1. - mAlpha);
+            if(currentValue > worstValue) {
+                worstValue = currentValue;
+                worstElemIndex = i;
+            }
+        }
+        showOverlayMessage(cv::format("Frame %d is worst", worstElemIndex + 1));
+
+        if(mCalibData->imagePoints.size()) {
+            mCalibData->imagePoints.erase(mCalibData->imagePoints.begin() + worstElemIndex);
+            mCalibData->objectPoints.erase(mCalibData->objectPoints.begin() + worstElemIndex);
+        }
+        else {
+            mCalibData->allCharucoCorners.erase(mCalibData->allCharucoCorners.begin() + worstElemIndex);
+            mCalibData->allCharucoIds.erase(mCalibData->allCharucoIds.begin() + worstElemIndex);
+        }
+
+        cv::Mat newErrorsVec = cv::Mat((int)numberOfFrames - 1, 1, CV_64F);
+        std::copy(mCalibData->perViewErrors.ptr<double>(0),
+                  mCalibData->perViewErrors.ptr<double>((int)worstElemIndex), newErrorsVec.ptr<double>(0));
+        std::copy(mCalibData->perViewErrors.ptr<double>((int)worstElemIndex + 1), mCalibData->perViewErrors.ptr<double>((int)numberOfFrames),
+                    newErrorsVec.ptr<double>((int)worstElemIndex));
+        mCalibData->perViewErrors = newErrorsVec;
+    }
+}
+
+void calib::calibDataController::setParametersFileName(const std::string &name)
+{
+    mParamsFileName = name;
+}
+
+void calib::calibDataController::deleteLastFrame()
+{
+    if( !mCalibData->imagePoints.empty()) {
+        mCalibData->imagePoints.pop_back();
+        mCalibData->objectPoints.pop_back();
+    }
+
+    if (!mCalibData->allCharucoCorners.empty()) {
+        mCalibData->allCharucoCorners.pop_back();
+        mCalibData->allCharucoIds.pop_back();
+    }
+
+    if(!mParamsStack.empty()) {
+        mCalibData->cameraMatrix = (mParamsStack.top()).cameraMatrix;
+        mCalibData->distCoeffs = (mParamsStack.top()).distCoeffs;
+        mCalibData->stdDeviations = (mParamsStack.top()).stdDeviations;
+        mCalibData->totalAvgErr = (mParamsStack.top()).avgError;
+        mParamsStack.pop();
+    }
+}
+
+void calib::calibDataController::rememberCurrentParameters()
+{
+    cv::Mat oldCameraMat, oldDistcoeefs, oldStdDevs;
+    mCalibData->cameraMatrix.copyTo(oldCameraMat);
+    mCalibData->distCoeffs.copyTo(oldDistcoeefs);
+    mCalibData->stdDeviations.copyTo(oldStdDevs);
+    mParamsStack.push(cameraParameters(oldCameraMat, oldDistcoeefs, oldStdDevs, mCalibData->totalAvgErr));
+}
+
+void calib::calibDataController::deleteAllData()
+{
+    mCalibData->imagePoints.clear();
+    mCalibData->objectPoints.clear();
+    mCalibData->allCharucoCorners.clear();
+    mCalibData->allCharucoIds.clear();
+    mCalibData->cameraMatrix = mCalibData->distCoeffs = cv::Mat();
+    mParamsStack = std::stack<cameraParameters>();
+    rememberCurrentParameters();
+}
+
+bool calib::calibDataController::saveCurrentCameraParameters() const
+{
+    bool success = false;
+    if(mCalibData->cameraMatrix.total()) {
+            cv::FileStorage parametersWriter(mParamsFileName, cv::FileStorage::WRITE);
+            if(parametersWriter.isOpened()) {
+                time_t rawtime;
+                time(&rawtime);
+                char buf[256];
+                strftime(buf, sizeof(buf)-1, "%c", localtime(&rawtime));
+
+                parametersWriter << "calibrationDate" << buf;
+                parametersWriter << "framesCount" << std::max((int)mCalibData->objectPoints.size(), (int)mCalibData->allCharucoCorners.size());
+                parametersWriter << "cameraResolution" << mCalibData->imageSize;
+                parametersWriter << "cameraMatrix" << mCalibData->cameraMatrix;
+                parametersWriter << "cameraMatrix_std_dev" << mCalibData->stdDeviations.rowRange(cv::Range(0, 4));
+                parametersWriter << "dist_coeffs" << mCalibData->distCoeffs;
+                parametersWriter << "dist_coeffs_std_dev" << mCalibData->stdDeviations.rowRange(cv::Range(4, 9));
+                parametersWriter << "avg_reprojection_error" << mCalibData->totalAvgErr;
+
+                parametersWriter.release();
+                success = true;
+        }
+    }
+    return success;
+}
+
+void calib::calibDataController::printParametersToConsole(std::ostream &output) const
+{
+    const char* border = "---------------------------------------------------";
+    output << border << std::endl;
+    output << "Frames used for calibration: " << std::max(mCalibData->objectPoints.size(), mCalibData->allCharucoCorners.size())
+           << " \t RMS = " << mCalibData->totalAvgErr << std::endl;
+    if(mCalibData->cameraMatrix.at<double>(0,0) == mCalibData->cameraMatrix.at<double>(1,1))
+        output << "F = " << mCalibData->cameraMatrix.at<double>(1,1) << " +- " << sigmaMult*mCalibData->stdDeviations.at<double>(1) << std::endl;
+    else
+        output << "Fx = " << mCalibData->cameraMatrix.at<double>(0,0) << " +- " << sigmaMult*mCalibData->stdDeviations.at<double>(0) << " \t "
+               << "Fy = " << mCalibData->cameraMatrix.at<double>(1,1) << " +- " << sigmaMult*mCalibData->stdDeviations.at<double>(1) << std::endl;
+    output << "Cx = " << mCalibData->cameraMatrix.at<double>(0,2) << " +- " << sigmaMult*mCalibData->stdDeviations.at<double>(2) << " \t"
+           << "Cy = " << mCalibData->cameraMatrix.at<double>(1,2) << " +- " << sigmaMult*mCalibData->stdDeviations.at<double>(3) << std::endl;
+    output << "K1 = " << mCalibData->distCoeffs.at<double>(0) << " +- " << sigmaMult*mCalibData->stdDeviations.at<double>(4) << std::endl;
+    output << "K2 = " << mCalibData->distCoeffs.at<double>(1) << " +- " << sigmaMult*mCalibData->stdDeviations.at<double>(5) << std::endl;
+    output << "K3 = " << mCalibData->distCoeffs.at<double>(4) << " +- " << sigmaMult*mCalibData->stdDeviations.at<double>(8) << std::endl;
+    output << "TD1 = " << mCalibData->distCoeffs.at<double>(2) << " +- " << sigmaMult*mCalibData->stdDeviations.at<double>(6) << std::endl;
+    output << "TD2 = " << mCalibData->distCoeffs.at<double>(3) << " +- " << sigmaMult*mCalibData->stdDeviations.at<double>(7) << std::endl;
+}
+
+void calib::calibDataController::updateUndistortMap()
+{
+    cv::initUndistortRectifyMap(mCalibData->cameraMatrix, mCalibData->distCoeffs, cv::noArray(),
+                                cv::getOptimalNewCameraMatrix(mCalibData->cameraMatrix, mCalibData->distCoeffs, mCalibData->imageSize, 0.0, mCalibData->imageSize),
+                                mCalibData->imageSize, CV_16SC2, mCalibData->undistMap1, mCalibData->undistMap2);
+
+}
diff --git a/apps/interactive-calibration/calibController.hpp b/apps/interactive-calibration/calibController.hpp
new file mode 100644
index 0000000..7a0f3f7
--- /dev/null
+++ b/apps/interactive-calibration/calibController.hpp
@@ -0,0 +1,69 @@
+// This file is part of OpenCV project.
+// It is subject to the license terms in the LICENSE file found in the top-level directory
+// of this distribution and at http://opencv.org/license.html.
+
+#ifndef CALIB_CONTROLLER_HPP
+#define CALIB_CONTROLLER_HPP
+
+#include "calibCommon.hpp"
+
+#include <stack>
+#include <string>
+#include <ostream>
+
+namespace calib {
+
+    class calibController
+    {
+    protected:
+        cv::Ptr<calibrationData> mCalibData;
+        int mCalibFlags;
+        unsigned mMinFramesNum;
+        bool mNeedTuning;
+        bool mConfIntervalsState;
+        bool mCoverageQualityState;
+
+        double estimateCoverageQuality();
+    public:
+        calibController();
+        calibController(cv::Ptr<calibrationData> data, int initialFlags, bool autoTuning,
+                        int minFramesNum);
+
+        void updateState();
+
+        bool getCommonCalibrationState() const;
+
+        bool getFramesNumberState() const;
+        bool getConfidenceIntrervalsState() const;
+        bool getRMSState() const;
+        bool getPointsCoverageState() const;
+        int getNewFlags() const;
+    };
+
+    class calibDataController
+    {
+    protected:
+        cv::Ptr<calibrationData> mCalibData;
+        std::stack<cameraParameters> mParamsStack;
+        std::string mParamsFileName;
+        unsigned mMaxFramesNum;
+        double mAlpha;
+
+        double estimateGridSubsetQuality(size_t excludedIndex);
+    public:
+        calibDataController(cv::Ptr<calibrationData> data, int maxFrames, double convParameter);
+        calibDataController();
+
+        void filterFrames();
+        void setParametersFileName(const std::string& name);
+        void deleteLastFrame();
+        void rememberCurrentParameters();
+        void deleteAllData();
+        bool saveCurrentCameraParameters() const;
+        void printParametersToConsole(std::ostream &output) const;
+        void updateUndistortMap();
+    };
+
+}
+
+#endif
diff --git a/apps/interactive-calibration/calibPipeline.cpp b/apps/interactive-calibration/calibPipeline.cpp
new file mode 100644
index 0000000..a92dbff
--- /dev/null
+++ b/apps/interactive-calibration/calibPipeline.cpp
@@ -0,0 +1,97 @@
+// This file is part of OpenCV project.
+// It is subject to the license terms in the LICENSE file found in the top-level directory
+// of this distribution and at http://opencv.org/license.html.
+
+#include "calibPipeline.hpp"
+
+#include <opencv2/highgui.hpp>
+
+#include <stdexcept>
+
+using namespace calib;
+
+#define CAP_DELAY 10
+
+cv::Size CalibPipeline::getCameraResolution()
+{
+    mCapture.set(cv::CAP_PROP_FRAME_WIDTH, 10000);
+    mCapture.set(cv::CAP_PROP_FRAME_HEIGHT, 10000);
+    int w = (int)mCapture.get(cv::CAP_PROP_FRAME_WIDTH);
+    int h = (int)mCapture.get(cv::CAP_PROP_FRAME_HEIGHT);
+    return cv::Size(w,h);
+}
+
+CalibPipeline::CalibPipeline(captureParameters params) :
+    mCaptureParams(params)
+{
+
+}
+
+PipelineExitStatus CalibPipeline::start(std::vector<cv::Ptr<FrameProcessor> > processors)
+{
+    if(mCaptureParams.source == Camera && !mCapture.isOpened())
+    {
+        mCapture.open(mCaptureParams.camID);
+        cv::Size maxRes = getCameraResolution();
+        cv::Size neededRes = mCaptureParams.cameraResolution;
+
+        if(maxRes.width < neededRes.width) {
+            double aR = (double)maxRes.width / maxRes.height;
+            mCapture.set(cv::CAP_PROP_FRAME_WIDTH, neededRes.width);
+            mCapture.set(cv::CAP_PROP_FRAME_HEIGHT, neededRes.width/aR);
+        }
+        else if(maxRes.height < neededRes.height) {
+            double aR = (double)maxRes.width / maxRes.height;
+            mCapture.set(cv::CAP_PROP_FRAME_HEIGHT, neededRes.height);
+            mCapture.set(cv::CAP_PROP_FRAME_WIDTH, neededRes.height*aR);
+        }
+        else {
+            mCapture.set(cv::CAP_PROP_FRAME_HEIGHT, neededRes.height);
+            mCapture.set(cv::CAP_PROP_FRAME_WIDTH, neededRes.width);
+        }
+        mCapture.set(cv::CAP_PROP_AUTOFOCUS, 0);
+    }
+    else if (mCaptureParams.source == File && !mCapture.isOpened())
+        mCapture.open(mCaptureParams.videoFileName);
+    mImageSize = cv::Size((int)mCapture.get(cv::CAP_PROP_FRAME_WIDTH), (int)mCapture.get(cv::CAP_PROP_FRAME_HEIGHT));
+
+    if(!mCapture.isOpened())
+        throw std::runtime_error("Unable to open video source");
+
+    cv::Mat frame, processedFrame;
+    while(mCapture.grab()) {
+        mCapture.retrieve(frame);
+        if(mCaptureParams.flipVertical)
+            cv::flip(frame, frame, -1);
+
+        frame.copyTo(processedFrame);
+        for (std::vector<cv::Ptr<FrameProcessor> >::iterator it = processors.begin(); it != processors.end(); ++it)
+            processedFrame = (*it)->processFrame(processedFrame);
+        cv::imshow(mainWindowName, processedFrame);
+        char key = (char)cv::waitKey(CAP_DELAY);
+
+        if(key == 27) // esc
+            return Finished;
+        else if (key == 114) // r
+            return DeleteLastFrame;
+        else if (key == 100) // d
+            return DeleteAllFrames;
+        else if (key == 115) // s
+            return SaveCurrentData;
+        else if (key == 117) // u
+            return SwitchUndistort;
+        else if (key == 118) // v
+            return SwitchVisualisation;
+
+        for (std::vector<cv::Ptr<FrameProcessor> >::iterator it = processors.begin(); it != processors.end(); ++it)
+            if((*it)->isProcessed())
+                return Calibrate;
+    }
+
+    return Finished;
+}
+
+cv::Size CalibPipeline::getImageSize() const
+{
+    return mImageSize;
+}
diff --git a/apps/interactive-calibration/calibPipeline.hpp b/apps/interactive-calibration/calibPipeline.hpp
new file mode 100644
index 0000000..1c22b0d
--- /dev/null
+++ b/apps/interactive-calibration/calibPipeline.hpp
@@ -0,0 +1,45 @@
+// This file is part of OpenCV project.
+// It is subject to the license terms in the LICENSE file found in the top-level directory
+// of this distribution and at http://opencv.org/license.html.
+
+
+#ifndef CALIB_PIPELINE_HPP
+#define CALIB_PIPELINE_HPP
+
+#include <vector>
+
+#include <opencv2/highgui.hpp>
+
+#include "calibCommon.hpp"
+#include "frameProcessor.hpp"
+
+namespace calib
+{
+
+enum PipelineExitStatus { Finished,
+                                DeleteLastFrame,
+                                Calibrate,
+                                DeleteAllFrames,
+                                SaveCurrentData,
+                                SwitchUndistort,
+                                SwitchVisualisation
+                              };
+
+class CalibPipeline
+{
+protected:
+    captureParameters mCaptureParams;
+    cv::Size mImageSize;
+    cv::VideoCapture mCapture;
+
+    cv::Size getCameraResolution();
+
+public:
+    CalibPipeline(captureParameters params);
+    PipelineExitStatus start(std::vector<cv::Ptr<FrameProcessor> > processors);
+    cv::Size getImageSize() const;
+};
+
+}
+
+#endif
diff --git a/apps/interactive-calibration/defaultConfig.xml b/apps/interactive-calibration/defaultConfig.xml
new file mode 100644
index 0000000..d14ba86
--- /dev/null
+++ b/apps/interactive-calibration/defaultConfig.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0"?>
+<opencv_storage>
+<charuco_dict>0</charuco_dict>
+<charuco_square_lenght>200</charuco_square_lenght>
+<charuco_marker_size>100</charuco_marker_size>
+<calibration_step>1</calibration_step>
+<max_frames_num>30</max_frames_num>
+<min_frames_num>10</min_frames_num>
+<solver_eps>1e-7</solver_eps>
+<solver_max_iters>30</solver_max_iters>
+<fast_solver>0</fast_solver>
+<frame_filter_conv_param>0.1</frame_filter_conv_param>
+<camera_resolution>800 600</camera_resolution>
+</opencv_storage>
\ No newline at end of file
diff --git a/apps/interactive-calibration/frameProcessor.cpp b/apps/interactive-calibration/frameProcessor.cpp
new file mode 100644
index 0000000..1e672b0
--- /dev/null
+++ b/apps/interactive-calibration/frameProcessor.cpp
@@ -0,0 +1,523 @@
+// This file is part of OpenCV project.
+// It is subject to the license terms in the LICENSE file found in the top-level directory
+// of this distribution and at http://opencv.org/license.html.
+
+#include "frameProcessor.hpp"
+#include "rotationConverters.hpp"
+
+#include <opencv2/calib3d.hpp>
+#include <opencv2/imgproc.hpp>
+#include <opencv2/aruco/charuco.hpp>
+#include <opencv2/highgui.hpp>
+
+#include <vector>
+#include <string>
+#include <algorithm>
+#include <limits>
+
+using namespace calib;
+
+#define VIDEO_TEXT_SIZE 4
+#define POINT_SIZE 5
+
+static cv::SimpleBlobDetector::Params getDetectorParams()
+{
+    cv::SimpleBlobDetector::Params detectorParams;
+
+    detectorParams.thresholdStep = 40;
+    detectorParams.minThreshold = 20;
+    detectorParams.maxThreshold = 500;
+    detectorParams.minRepeatability = 2;
+    detectorParams.minDistBetweenBlobs = 5;
+
+    detectorParams.filterByColor = true;
+    detectorParams.blobColor = 0;
+
+    detectorParams.filterByArea = true;
+    detectorParams.minArea = 5;
+    detectorParams.maxArea = 5000;
+
+    detectorParams.filterByCircularity = false;
+    detectorParams.minCircularity = 0.8f;
+    detectorParams.maxCircularity = std::numeric_limits<float>::max();
+
+    detectorParams.filterByInertia = true;
+    detectorParams.minInertiaRatio = 0.1f;
+    detectorParams.maxInertiaRatio = std::numeric_limits<float>::max();
+
+    detectorParams.filterByConvexity = true;
+    detectorParams.minConvexity = 0.8f;
+    detectorParams.maxConvexity = std::numeric_limits<float>::max();
+
+    return detectorParams;
+}
+
+FrameProcessor::~FrameProcessor()
+{
+
+}
+
+bool CalibProcessor::detectAndParseChessboard(const cv::Mat &frame)
+{
+    int chessBoardFlags = cv::CALIB_CB_ADAPTIVE_THRESH | cv::CALIB_CB_NORMALIZE_IMAGE | cv::CALIB_CB_FAST_CHECK;
+    bool isTemplateFound = cv::findChessboardCorners(frame, mBoardSize, mCurrentImagePoints, chessBoardFlags);
+
+    if (isTemplateFound) {
+        cv::Mat viewGray;
+        cv::cvtColor(frame, viewGray, cv::COLOR_BGR2GRAY);
+        cv::cornerSubPix(viewGray, mCurrentImagePoints, cv::Size(11,11),
+            cv::Size(-1,-1), cv::TermCriteria( cv::TermCriteria::EPS+cv::TermCriteria::COUNT, 30, 0.1 ));
+        cv::drawChessboardCorners(frame, mBoardSize, cv::Mat(mCurrentImagePoints), isTemplateFound);
+        mTemplateLocations.insert(mTemplateLocations.begin(), mCurrentImagePoints[0]);
+    }
+    return isTemplateFound;
+}
+
+bool CalibProcessor::detectAndParseChAruco(const cv::Mat &frame)
+{
+    cv::Ptr<cv::aruco::Board> board = mCharucoBoard.staticCast<cv::aruco::Board>();
+
+    std::vector<std::vector<cv::Point2f> > corners, rejected;
+    std::vector<int> ids;
+    cv::aruco::detectMarkers(frame, mArucoDictionary, corners, ids, cv::aruco::DetectorParameters::create(), rejected);
+    cv::aruco::refineDetectedMarkers(frame, board, corners, ids, rejected);
+    cv::Mat currentCharucoCorners, currentCharucoIds;
+    if(ids.size() > 0)
+        cv::aruco::interpolateCornersCharuco(corners, ids, frame, mCharucoBoard, currentCharucoCorners,
+                                         currentCharucoIds);
+    if(ids.size() > 0) cv::aruco::drawDetectedMarkers(frame, corners);
+
+    if(currentCharucoCorners.total() > 3) {
+        float centerX = 0, centerY = 0;
+        for (int i = 0; i < currentCharucoCorners.size[0]; i++) {
+            centerX += currentCharucoCorners.at<float>(i, 0);
+            centerY += currentCharucoCorners.at<float>(i, 1);
+        }
+        centerX /= currentCharucoCorners.size[0];
+        centerY /= currentCharucoCorners.size[0];
+        //cv::circle(frame, cv::Point2f(centerX, centerY), 10, cv::Scalar(0, 255, 0), 10);
+        mTemplateLocations.insert(mTemplateLocations.begin(), cv::Point2f(centerX, centerY));
+        cv::aruco::drawDetectedCornersCharuco(frame, currentCharucoCorners, currentCharucoIds);
+        mCurrentCharucoCorners = currentCharucoCorners;
+        mCurrentCharucoIds = currentCharucoIds;
+        return true;
+    }
+
+    return false;
+}
+
+bool CalibProcessor::detectAndParseACircles(const cv::Mat &frame)
+{
+    bool isTemplateFound = findCirclesGrid(frame, mBoardSize, mCurrentImagePoints, cv::CALIB_CB_ASYMMETRIC_GRID, mBlobDetectorPtr);
+    if(isTemplateFound) {
+        mTemplateLocations.insert(mTemplateLocations.begin(), mCurrentImagePoints[0]);
+        cv::drawChessboardCorners(frame, mBoardSize, cv::Mat(mCurrentImagePoints), isTemplateFound);
+    }
+    return isTemplateFound;
+}
+
+bool CalibProcessor::detectAndParseDualACircles(const cv::Mat &frame)
+{
+    std::vector<cv::Point2f> blackPointbuf;
+
+    cv::Mat invertedView;
+    cv::bitwise_not(frame, invertedView);
+    bool isWhiteGridFound = cv::findCirclesGrid(frame, mBoardSize, mCurrentImagePoints, cv::CALIB_CB_ASYMMETRIC_GRID, mBlobDetectorPtr);
+    if(!isWhiteGridFound)
+        return false;
+    bool isBlackGridFound = cv::findCirclesGrid(invertedView, mBoardSize, blackPointbuf, cv::CALIB_CB_ASYMMETRIC_GRID, mBlobDetectorPtr);
+
+    if(!isBlackGridFound)
+    {
+        mCurrentImagePoints.clear();
+        return false;
+    }
+    cv::drawChessboardCorners(frame, mBoardSize, cv::Mat(mCurrentImagePoints), isWhiteGridFound);
+    cv::drawChessboardCorners(frame, mBoardSize, cv::Mat(blackPointbuf), isBlackGridFound);
+    mCurrentImagePoints.insert(mCurrentImagePoints.end(), blackPointbuf.begin(), blackPointbuf.end());
+    mTemplateLocations.insert(mTemplateLocations.begin(), mCurrentImagePoints[0]);
+
+    return true;
+}
+
+void CalibProcessor::saveFrameData()
+{
+    std::vector<cv::Point3f> objectPoints;
+
+    switch(mBoardType)
+    {
+    case Chessboard:
+        objectPoints.reserve(mBoardSize.height*mBoardSize.width);
+        for( int i = 0; i < mBoardSize.height; ++i )
+            for( int j = 0; j < mBoardSize.width; ++j )
+                objectPoints.push_back(cv::Point3f(j*mSquareSize, i*mSquareSize, 0));
+        mCalibData->imagePoints.push_back(mCurrentImagePoints);
+        mCalibData->objectPoints.push_back(objectPoints);
+        break;
+    case chAruco:
+        mCalibData->allCharucoCorners.push_back(mCurrentCharucoCorners);
+        mCalibData->allCharucoIds.push_back(mCurrentCharucoIds);
+        break;
+    case AcirclesGrid:
+        objectPoints.reserve(mBoardSize.height*mBoardSize.width);
+        for( int i = 0; i < mBoardSize.height; i++ )
+            for( int j = 0; j < mBoardSize.width; j++ )
+                objectPoints.push_back(cv::Point3f((2*j + i % 2)*mSquareSize, i*mSquareSize, 0));
+        mCalibData->imagePoints.push_back(mCurrentImagePoints);
+        mCalibData->objectPoints.push_back(objectPoints);
+        break;
+    case DoubleAcirclesGrid:
+    {
+        float gridCenterX = (2*((float)mBoardSize.width - 1) + 1)*mSquareSize + mTemplDist / 2;
+        float gridCenterY = (mBoardSize.height - 1)*mSquareSize / 2;
+        objectPoints.reserve(2*mBoardSize.height*mBoardSize.width);
+
+        //white part
+        for( int i = 0; i < mBoardSize.height; i++ )
+            for( int j = 0; j < mBoardSize.width; j++ )
+                objectPoints.push_back(
+                            cv::Point3f(-float((2*j + i % 2)*mSquareSize + mTemplDist +
+                                               (2*(mBoardSize.width - 1) + 1)*mSquareSize - gridCenterX),
+                                        -float(i*mSquareSize) - gridCenterY,
+                                        0));
+        //black part
+        for( int i = 0; i < mBoardSize.height; i++ )
+            for( int j = 0; j < mBoardSize.width; j++ )
+                objectPoints.push_back(cv::Point3f(-float((2*j + i % 2)*mSquareSize - gridCenterX),
+                                          -float(i*mSquareSize) - gridCenterY, 0));
+
+        mCalibData->imagePoints.push_back(mCurrentImagePoints);
+        mCalibData->objectPoints.push_back(objectPoints);
+    }
+        break;
+    }
+}
+
+void CalibProcessor::showCaptureMessage(const cv::Mat& frame, const std::string &message)
+{
+    cv::Point textOrigin(100, 100);
+    double textSize = VIDEO_TEXT_SIZE * frame.cols / (double) IMAGE_MAX_WIDTH;
+    cv::bitwise_not(frame, frame);
+    cv::putText(frame, message, textOrigin, 1, textSize, cv::Scalar(0,0,255), 2, cv::LINE_AA);
+    cv::imshow(mainWindowName, frame);
+    cv::waitKey(300);
+}
+
+bool CalibProcessor::checkLastFrame()
+{
+    bool isFrameBad = false;
+    cv::Mat tmpCamMatrix;
+    const double badAngleThresh = 40;
+
+    if(!mCalibData->cameraMatrix.total()) {
+        tmpCamMatrix = cv::Mat::eye(3, 3, CV_64F);
+        tmpCamMatrix.at<double>(0,0) = 20000;
+        tmpCamMatrix.at<double>(1,1) = 20000;
+        tmpCamMatrix.at<double>(0,2) = mCalibData->imageSize.height/2;
+        tmpCamMatrix.at<double>(1,2) = mCalibData->imageSize.width/2;
+    }
+    else
+        mCalibData->cameraMatrix.copyTo(tmpCamMatrix);
+
+    if(mBoardType != chAruco) {
+        cv::Mat r, t, angles;
+        cv::solvePnP(mCalibData->objectPoints.back(), mCurrentImagePoints, tmpCamMatrix, mCalibData->distCoeffs, r, t);
+        RodriguesToEuler(r, angles, CALIB_DEGREES);
+
+        if(fabs(angles.at<double>(0)) > badAngleThresh || fabs(angles.at<double>(1)) > badAngleThresh) {
+            mCalibData->objectPoints.pop_back();
+            mCalibData->imagePoints.pop_back();
+            isFrameBad = true;
+        }
+    }
+    else {
+        cv::Mat r, t, angles;
+        std::vector<cv::Point3f> allObjPoints;
+        allObjPoints.reserve(mCurrentCharucoIds.total());
+        for(size_t i = 0; i < mCurrentCharucoIds.total(); i++) {
+            int pointID = mCurrentCharucoIds.at<int>((int)i);
+            CV_Assert(pointID >= 0 && pointID < (int)mCharucoBoard->chessboardCorners.size());
+            allObjPoints.push_back(mCharucoBoard->chessboardCorners[pointID]);
+        }
+
+        cv::solvePnP(allObjPoints, mCurrentCharucoCorners, tmpCamMatrix, mCalibData->distCoeffs, r, t);
+        RodriguesToEuler(r, angles, CALIB_DEGREES);
+
+        if(180.0 - fabs(angles.at<double>(0)) > badAngleThresh || fabs(angles.at<double>(1)) > badAngleThresh) {
+            isFrameBad = true;
+            mCalibData->allCharucoCorners.pop_back();
+            mCalibData->allCharucoIds.pop_back();
+        }
+    }
+    return isFrameBad;
+}
+
+CalibProcessor::CalibProcessor(cv::Ptr<calibrationData> data, captureParameters &capParams) :
+    mCalibData(data), mBoardType(capParams.board), mBoardSize(capParams.boardSize)
+{
+    mCapuredFrames = 0;
+    mNeededFramesNum = capParams.calibrationStep;
+    mDelayBetweenCaptures = static_cast<int>(capParams.captureDelay * capParams.fps);
+    mMaxTemplateOffset = std::sqrt(static_cast<float>(mCalibData->imageSize.height * mCalibData->imageSize.height) +
+                                   static_cast<float>(mCalibData->imageSize.width * mCalibData->imageSize.width)) / 20.0;
+    mSquareSize = capParams.squareSize;
+    mTemplDist = capParams.templDst;
+
+    switch(mBoardType)
+    {
+    case chAruco:
+        mArucoDictionary = cv::aruco::getPredefinedDictionary(
+                    cv::aruco::PREDEFINED_DICTIONARY_NAME(capParams.charucoDictName));
+        mCharucoBoard = cv::aruco::CharucoBoard::create(mBoardSize.width, mBoardSize.height, capParams.charucoSquareLenght,
+                                                        capParams.charucoMarkerSize, mArucoDictionary);
+        break;
+    case AcirclesGrid:
+        mBlobDetectorPtr = cv::SimpleBlobDetector::create();
+        break;
+    case DoubleAcirclesGrid:
+        mBlobDetectorPtr = cv::SimpleBlobDetector::create(getDetectorParams());
+        break;
+    case Chessboard:
+        break;
+    }
+}
+
+cv::Mat CalibProcessor::processFrame(const cv::Mat &frame)
+{
+    cv::Mat frameCopy;
+    frame.copyTo(frameCopy);
+    bool isTemplateFound = false;
+    mCurrentImagePoints.clear();
+
+    switch(mBoardType)
+    {
+    case Chessboard:
+        isTemplateFound = detectAndParseChessboard(frameCopy);
+        break;
+    case chAruco:
+        isTemplateFound = detectAndParseChAruco(frameCopy);
+        break;
+    case AcirclesGrid:
+        isTemplateFound = detectAndParseACircles(frameCopy);
+        break;
+    case DoubleAcirclesGrid:
+        isTemplateFound = detectAndParseDualACircles(frameCopy);
+        break;
+    }
+
+    if(mTemplateLocations.size() > mDelayBetweenCaptures)
+        mTemplateLocations.pop_back();
+    if(mTemplateLocations.size() == mDelayBetweenCaptures && isTemplateFound) {
+        if(cv::norm(mTemplateLocations.front() - mTemplateLocations.back()) < mMaxTemplateOffset) {
+            saveFrameData();
+            bool isFrameBad = checkLastFrame();
+            if (!isFrameBad) {
+                std::string displayMessage = cv::format("Frame # %d captured", std::max(mCalibData->imagePoints.size(),
+                                                                                        mCalibData->allCharucoCorners.size()));
+                if(!showOverlayMessage(displayMessage))
+                    showCaptureMessage(frame, displayMessage);
+                mCapuredFrames++;
+            }
+            else {
+                std::string displayMessage = "Frame rejected";
+                if(!showOverlayMessage(displayMessage))
+                    showCaptureMessage(frame, displayMessage);
+            }
+            mTemplateLocations.clear();
+            mTemplateLocations.reserve(mDelayBetweenCaptures);
+        }
+    }
+
+    return frameCopy;
+}
+
+bool CalibProcessor::isProcessed() const
+{
+    if(mCapuredFrames < mNeededFramesNum)
+        return false;
+    else
+        return true;
+}
+
+void CalibProcessor::resetState()
+{
+    mCapuredFrames = 0;
+    mTemplateLocations.clear();
+}
+
+CalibProcessor::~CalibProcessor()
+{
+
+}
+
+////////////////////////////////////////////
+
+void ShowProcessor::drawBoard(cv::Mat &img, cv::InputArray points)
+{
+    cv::Mat tmpView = cv::Mat::zeros(img.rows, img.cols, CV_8UC3);
+    std::vector<cv::Point2f> templateHull;
+    std::vector<cv::Point> poly;
+    cv::convexHull(points, templateHull);
+    poly.resize(templateHull.size());
+    for(size_t i=0; i<templateHull.size();i++)
+        poly[i] = cv::Point((int)(templateHull[i].x*mGridViewScale), (int)(templateHull[i].y*mGridViewScale));
+    cv::fillConvexPoly(tmpView, poly, cv::Scalar(0, 255, 0), cv::LINE_AA);
+    cv::addWeighted(tmpView, .2, img, 1, 0, img);
+}
+
+void ShowProcessor::drawGridPoints(const cv::Mat &frame)
+{
+    if(mBoardType != chAruco)
+        for(std::vector<std::vector<cv::Point2f> >::iterator it = mCalibdata->imagePoints.begin(); it != mCalibdata->imagePoints.end(); ++it)
+            for(std::vector<cv::Point2f>::iterator pointIt = (*it).begin(); pointIt != (*it).end(); ++pointIt)
+                cv::circle(frame, *pointIt, POINT_SIZE, cv::Scalar(0, 255, 0), 1, cv::LINE_AA);
+    else
+        for(std::vector<cv::Mat>::iterator it = mCalibdata->allCharucoCorners.begin(); it != mCalibdata->allCharucoCorners.end(); ++it)
+            for(int i = 0; i < (*it).size[0]; i++)
+                cv::circle(frame, cv::Point((int)(*it).at<float>(i, 0), (int)(*it).at<float>(i, 1)),
+                           POINT_SIZE, cv::Scalar(0, 255, 0), 1, cv::LINE_AA);
+}
+
+ShowProcessor::ShowProcessor(cv::Ptr<calibrationData> data, cv::Ptr<calibController> controller, TemplateType board) :
+    mCalibdata(data), mController(controller), mBoardType(board)
+{
+    mNeedUndistort = true;
+    mVisMode = Grid;
+    mGridViewScale = 0.5;
+    mTextSize = VIDEO_TEXT_SIZE;
+}
+
+cv::Mat ShowProcessor::processFrame(const cv::Mat &frame)
+{
+    if(mCalibdata->cameraMatrix.size[0] && mCalibdata->distCoeffs.size[0]) {
+        mTextSize = VIDEO_TEXT_SIZE * (double) frame.cols / IMAGE_MAX_WIDTH;
+        cv::Scalar textColor = cv::Scalar(0,0,255);
+        cv::Mat frameCopy;
+
+        if (mNeedUndistort && mController->getFramesNumberState()) {
+            if(mVisMode == Grid)
+                drawGridPoints(frame);
+            cv::remap(frame, frameCopy, mCalibdata->undistMap1, mCalibdata->undistMap2, cv::INTER_LINEAR);
+            int baseLine = 100;
+            cv::Size textSize = cv::getTextSize("Undistorted view", 1, mTextSize, 2, &baseLine);
+            cv::Point textOrigin(baseLine, frame.rows - (int)(2.5*textSize.height));
+            cv::putText(frameCopy, "Undistorted view", textOrigin, 1, mTextSize, textColor, 2, cv::LINE_AA);
+        }
+        else {
+            frame.copyTo(frameCopy);
+            if(mVisMode == Grid)
+                drawGridPoints(frameCopy);
+        }
+        std::string displayMessage;
+        if(mCalibdata->stdDeviations.at<double>(0) == 0)
+            displayMessage = cv::format("F = %d RMS = %.3f", (int)mCalibdata->cameraMatrix.at<double>(0,0), mCalibdata->totalAvgErr);
+        else
+            displayMessage = cv::format("Fx = %d Fy = %d RMS = %.3f", (int)mCalibdata->cameraMatrix.at<double>(0,0),
+                                            (int)mCalibdata->cameraMatrix.at<double>(1,1), mCalibdata->totalAvgErr);
+        if(mController->getRMSState() && mController->getFramesNumberState())
+            displayMessage.append(" OK");
+
+        int baseLine = 100;
+        cv::Size textSize = cv::getTextSize(displayMessage, 1, mTextSize - 1, 2, &baseLine);
+        cv::Point textOrigin = cv::Point(baseLine, 2*textSize.height);
+        cv::putText(frameCopy, displayMessage, textOrigin, 1, mTextSize - 1, textColor, 2, cv::LINE_AA);
+
+        if(mCalibdata->stdDeviations.at<double>(0) == 0)
+            displayMessage = cv::format("DF = %.2f", mCalibdata->stdDeviations.at<double>(1)*sigmaMult);
+        else
+            displayMessage = cv::format("DFx = %.2f DFy = %.2f", mCalibdata->stdDeviations.at<double>(0)*sigmaMult,
+                                                    mCalibdata->stdDeviations.at<double>(1)*sigmaMult);
+        if(mController->getConfidenceIntrervalsState() && mController->getFramesNumberState())
+            displayMessage.append(" OK");
+        cv::putText(frameCopy, displayMessage, cv::Point(baseLine, 4*textSize.height), 1, mTextSize - 1, textColor, 2, cv::LINE_AA);
+
+        if(mController->getCommonCalibrationState()) {
+            displayMessage = cv::format("Calibration is done");
+            cv::putText(frameCopy, displayMessage, cv::Point(baseLine, 6*textSize.height), 1, mTextSize - 1, textColor, 2, cv::LINE_AA);
+        }
+        int calibFlags = mController->getNewFlags();
+        displayMessage = "";
+        if(!(calibFlags & cv::CALIB_FIX_ASPECT_RATIO))
+            displayMessage.append(cv::format("AR=%.3f ", mCalibdata->cameraMatrix.at<double>(0,0)/mCalibdata->cameraMatrix.at<double>(1,1)));
+        if(calibFlags & cv::CALIB_ZERO_TANGENT_DIST)
+            displayMessage.append("TD=0 ");
+        displayMessage.append(cv::format("K1=%.2f K2=%.2f K3=%.2f", mCalibdata->distCoeffs.at<double>(0), mCalibdata->distCoeffs.at<double>(1),
+                                         mCalibdata->distCoeffs.at<double>(4)));
+        cv::putText(frameCopy, displayMessage, cv::Point(baseLine, frameCopy.rows - (int)(1.5*textSize.height)),
+                    1, mTextSize - 1, textColor, 2, cv::LINE_AA);
+        return frameCopy;
+    }
+
+    return frame;
+}
+
+bool ShowProcessor::isProcessed() const
+{
+    return false;
+}
+
+void ShowProcessor::resetState()
+{
+
+}
+
+void ShowProcessor::setVisualizationMode(visualisationMode mode)
+{
+    mVisMode = mode;
+}
+
+void ShowProcessor::switchVisualizationMode()
+{
+    if(mVisMode == Grid) {
+        mVisMode = Window;
+        updateBoardsView();
+    }
+    else {
+        mVisMode = Grid;
+        cv::destroyWindow(gridWindowName);
+    }
+}
+
+void ShowProcessor::clearBoardsView()
+{
+    cv::imshow(gridWindowName, cv::Mat());
+}
+
+void ShowProcessor::updateBoardsView()
+{
+    if(mVisMode == Window) {
+        cv::Size originSize = mCalibdata->imageSize;
+        cv::Mat altGridView = cv::Mat::zeros((int)(originSize.height*mGridViewScale), (int)(originSize.width*mGridViewScale), CV_8UC3);
+        if(mBoardType != chAruco)
+            for(std::vector<std::vector<cv::Point2f> >::iterator it = mCalibdata->imagePoints.begin(); it != mCalibdata->imagePoints.end(); ++it)
+                if(mBoardType != DoubleAcirclesGrid)
+                    drawBoard(altGridView, *it);
+                else {
+                    size_t pointsNum = (*it).size()/2;
+                    std::vector<cv::Point2f> points(pointsNum);
+                    std::copy((*it).begin(), (*it).begin() + pointsNum, points.begin());
+                    drawBoard(altGridView, points);
+                    std::copy((*it).begin() + pointsNum, (*it).begin() + 2*pointsNum, points.begin());
+                    drawBoard(altGridView, points);
+                }
+        else
+            for(std::vector<cv::Mat>::iterator it = mCalibdata->allCharucoCorners.begin(); it != mCalibdata->allCharucoCorners.end(); ++it)
+                drawBoard(altGridView, *it);
+        cv::imshow(gridWindowName, altGridView);
+    }
+}
+
+void ShowProcessor::switchUndistort()
+{
+    mNeedUndistort = !mNeedUndistort;
+}
+
+void ShowProcessor::setUndistort(bool isEnabled)
+{
+    mNeedUndistort = isEnabled;
+}
+
+ShowProcessor::~ShowProcessor()
+{
+
+}
diff --git a/apps/interactive-calibration/frameProcessor.hpp b/apps/interactive-calibration/frameProcessor.hpp
new file mode 100644
index 0000000..4dbb8ab
--- /dev/null
+++ b/apps/interactive-calibration/frameProcessor.hpp
@@ -0,0 +1,100 @@
+// This file is part of OpenCV project.
+// It is subject to the license terms in the LICENSE file found in the top-level directory
+// of this distribution and at http://opencv.org/license.html.
+
+#ifndef FRAME_PROCESSOR_HPP
+#define FRAME_PROCESSOR_HPP
+
+#include <opencv2/core.hpp>
+#include <opencv2/aruco/charuco.hpp>
+#include <opencv2/calib3d.hpp>
+
+#include "calibCommon.hpp"
+#include "calibController.hpp"
+
+namespace calib
+{
+class FrameProcessor
+{
+protected:
+
+public:
+    virtual ~FrameProcessor();
+    virtual cv::Mat processFrame(const cv::Mat& frame) = 0;
+    virtual bool isProcessed() const = 0;
+    virtual void resetState() = 0;
+};
+
+class CalibProcessor : public FrameProcessor
+{
+protected:
+    cv::Ptr<calibrationData> mCalibData;
+    TemplateType mBoardType;
+    cv::Size mBoardSize;
+    std::vector<cv::Point2f> mTemplateLocations;
+    std::vector<cv::Point2f> mCurrentImagePoints;
+    cv::Mat mCurrentCharucoCorners;
+    cv::Mat mCurrentCharucoIds;
+
+    cv::Ptr<cv::SimpleBlobDetector> mBlobDetectorPtr;
+    cv::Ptr<cv::aruco::Dictionary> mArucoDictionary;
+    cv::Ptr<cv::aruco::CharucoBoard> mCharucoBoard;
+
+    int mNeededFramesNum;
+    unsigned mDelayBetweenCaptures;
+    int mCapuredFrames;
+    double mMaxTemplateOffset;
+    float mSquareSize;
+    float mTemplDist;
+
+    bool detectAndParseChessboard(const cv::Mat& frame);
+    bool detectAndParseChAruco(const cv::Mat& frame);
+    bool detectAndParseACircles(const cv::Mat& frame);
+    bool detectAndParseDualACircles(const cv::Mat& frame);
+    void saveFrameData();
+    void showCaptureMessage(const cv::Mat &frame, const std::string& message);
+    bool checkLastFrame();
+
+public:
+    CalibProcessor(cv::Ptr<calibrationData> data, captureParameters& capParams);
+    virtual cv::Mat processFrame(const cv::Mat& frame);
+    virtual bool isProcessed() const;
+    virtual void resetState();
+    ~CalibProcessor();
+};
+
+enum visualisationMode {Grid, Window};
+
+class ShowProcessor : public FrameProcessor
+{
+protected:
+    cv::Ptr<calibrationData> mCalibdata;
+    cv::Ptr<calibController> mController;
+    TemplateType mBoardType;
+    visualisationMode mVisMode;
+    bool mNeedUndistort;
+    double mGridViewScale;
+    double mTextSize;
+
+    void drawBoard(cv::Mat& img, cv::InputArray points);
+    void drawGridPoints(const cv::Mat& frame);
+public:
+    ShowProcessor(cv::Ptr<calibrationData> data, cv::Ptr<calibController> controller, TemplateType board);
+    virtual cv::Mat processFrame(const cv::Mat& frame);
+    virtual bool isProcessed() const;
+    virtual void resetState();
+
+    void setVisualizationMode(visualisationMode mode);
+    void switchVisualizationMode();
+    void clearBoardsView();
+    void updateBoardsView();
+
+    void switchUndistort();
+    void setUndistort(bool isEnabled);
+    ~ShowProcessor();
+};
+
+}
+
+
+#endif
diff --git a/apps/interactive-calibration/main.cpp b/apps/interactive-calibration/main.cpp
new file mode 100644
index 0000000..af62d4e
--- /dev/null
+++ b/apps/interactive-calibration/main.cpp
@@ -0,0 +1,219 @@
+// This file is part of OpenCV project.
+// It is subject to the license terms in the LICENSE file found in the top-level directory
+// of this distribution and at http://opencv.org/license.html.
+
+#include <opencv2/core.hpp>
+#include <opencv2/calib3d.hpp>
+#include <opencv2/aruco/charuco.hpp>
+#include <opencv2/cvconfig.h>
+#include <opencv2/highgui.hpp>
+
+#include <string>
+#include <vector>
+#include <stdexcept>
+#include <algorithm>
+#include <iostream>
+
+#include "calibCommon.hpp"
+#include "calibPipeline.hpp"
+#include "frameProcessor.hpp"
+#include "calibController.hpp"
+#include "parametersController.hpp"
+#include "rotationConverters.hpp"
+
+using namespace calib;
+
+const std::string keys  =
+        "{v        |         | Input from video file }"
+        "{ci       | 0       | Default camera id }"
+        "{flip     | false   | Vertical flip of input frames }"
+        "{t        | circles | Template for calibration (circles, chessboard, dualCircles, charuco) }"
+        "{sz       | 16.3    | Distance between two nearest centers of circles or squares on calibration board}"
+        "{dst      | 295     | Distance between white and black parts of daulCircles template}"
+        "{w        |         | Width of template (in corners or circles)}"
+        "{h        |         | Height of template (in corners or circles)}"
+        "{of       | cameraParameters.xml | Output file name}"
+        "{ft       | true    | Auto tuning of calibration flags}"
+        "{vis      | grid    | Captured boards visualisation (grid, window)}"
+        "{d        | 0.8     | Min delay between captures}"
+        "{pf       | defaultConfig.xml| Advanced application parameters}"
+        "{help     |         | Print help}";
+
+bool calib::showOverlayMessage(const std::string& message)
+{
+#ifdef HAVE_QT
+    cv::displayOverlay(mainWindowName, message, OVERLAY_DELAY);
+    return true;
+#else
+    std::cout << message << std::endl;
+    return false;
+#endif
+}
+
+static void deleteButton(int state, void* data)
+{
+    state++; //to avoid gcc warnings
+    (static_cast<cv::Ptr<calibDataController>*>(data))->get()->deleteLastFrame();
+    calib::showOverlayMessage("Last frame deleted");
+}
+
+static void deleteAllButton(int state, void* data)
+{
+    state++;
+    (static_cast<cv::Ptr<calibDataController>*>(data))->get()->deleteAllData();
+    calib::showOverlayMessage("All frames deleted");
+}
+
+static void saveCurrentParamsButton(int state, void* data)
+{
+    state++;
+    if((static_cast<cv::Ptr<calibDataController>*>(data))->get()->saveCurrentCameraParameters())
+        calib::showOverlayMessage("Calibration parameters saved");
+}
+
+#ifdef HAVE_QT
+static void switchVisualizationModeButton(int state, void* data)
+{
+    state++;
+    ShowProcessor* processor = static_cast<ShowProcessor*>(((cv::Ptr<FrameProcessor>*)data)->get());
+    processor->switchVisualizationMode();
+}
+
+static void undistortButton(int state, void* data)
+{
+    ShowProcessor* processor = static_cast<ShowProcessor*>(((cv::Ptr<FrameProcessor>*)data)->get());
+    processor->setUndistort(static_cast<bool>(state));
+    calib::showOverlayMessage(std::string("Undistort is ") +
+                       (static_cast<bool>(state) ? std::string("on") : std::string("off")));
+}
+#endif //HAVE_QT
+
+int main(int argc, char** argv)
+{
+    cv::CommandLineParser parser(argc, argv, keys);
+    if(parser.has("help")) {
+        parser.printMessage();
+        return 0;
+    }
+    std::cout << consoleHelp << std::endl;
+    parametersController paramsController;
+
+    if(!paramsController.loadFromParser(parser))
+        return 0;
+
+    captureParameters capParams = paramsController.getCaptureParameters();
+    internalParameters intParams = paramsController.getInternalParameters();
+
+    cv::TermCriteria solverTermCrit = cv::TermCriteria(cv::TermCriteria::COUNT+cv::TermCriteria::EPS,
+                                                       intParams.solverMaxIters, intParams.solverEps);
+    cv::Ptr<calibrationData> globalData(new calibrationData);
+    if(!parser.has("v")) globalData->imageSize = capParams.cameraResolution;
+
+    int calibrationFlags = 0;
+    if(intParams.fastSolving) calibrationFlags |= cv::CALIB_USE_QR;
+    cv::Ptr<calibController> controller(new calibController(globalData, calibrationFlags,
+                                                         parser.get<bool>("ft"), capParams.minFramesNum));
+    cv::Ptr<calibDataController> dataController(new calibDataController(globalData, capParams.maxFramesNum,
+                                                                     intParams.filterAlpha));
+    dataController->setParametersFileName(parser.get<std::string>("of"));
+
+    cv::Ptr<FrameProcessor> capProcessor, showProcessor;
+    capProcessor = cv::Ptr<FrameProcessor>(new CalibProcessor(globalData, capParams));
+    showProcessor = cv::Ptr<FrameProcessor>(new ShowProcessor(globalData, controller, capParams.board));
+
+    if(parser.get<std::string>("vis").find("window") == 0) {
+        static_cast<ShowProcessor*>(showProcessor.get())->setVisualizationMode(Window);
+        cv::namedWindow(gridWindowName);
+        cv::moveWindow(gridWindowName, 1280, 500);
+    }
+
+    cv::Ptr<CalibPipeline> pipeline(new CalibPipeline(capParams));
+    std::vector<cv::Ptr<FrameProcessor> > processors;
+    processors.push_back(capProcessor);
+    processors.push_back(showProcessor);
+
+    cv::namedWindow(mainWindowName);
+    cv::moveWindow(mainWindowName, 10, 10);
+#ifdef HAVE_QT
+    cv::createButton("Delete last frame", deleteButton, &dataController,
+                     cv::QT_PUSH_BUTTON | cv::QT_NEW_BUTTONBAR);
+    cv::createButton("Delete all frames", deleteAllButton, &dataController,
+                     cv::QT_PUSH_BUTTON | cv::QT_NEW_BUTTONBAR);
+    cv::createButton("Undistort", undistortButton, &showProcessor,
+                     cv::QT_CHECKBOX | cv::QT_NEW_BUTTONBAR, false);
+    cv::createButton("Save current parameters", saveCurrentParamsButton, &dataController,
+                     cv::QT_PUSH_BUTTON | cv::QT_NEW_BUTTONBAR);
+    cv::createButton("Switch visualisation mode", switchVisualizationModeButton, &showProcessor,
+                     cv::QT_PUSH_BUTTON | cv::QT_NEW_BUTTONBAR);
+#endif //HAVE_QT
+    try {
+        bool pipelineFinished = false;
+        while(!pipelineFinished)
+        {
+            PipelineExitStatus exitStatus = pipeline->start(processors);
+            if (exitStatus == Finished) {
+                if(controller->getCommonCalibrationState())
+                    saveCurrentParamsButton(0, &dataController);
+                pipelineFinished = true;
+                continue;
+            }
+            else if (exitStatus == Calibrate) {
+
+                dataController->rememberCurrentParameters();
+                globalData->imageSize = pipeline->getImageSize();
+                calibrationFlags = controller->getNewFlags();
+
+                if(capParams.board != chAruco) {
+                    globalData->totalAvgErr =
+                            cv::calibrateCamera(globalData->objectPoints, globalData->imagePoints,
+                                                    globalData->imageSize, globalData->cameraMatrix,
+                                                    globalData->distCoeffs, cv::noArray(), cv::noArray(),
+                                                    globalData->stdDeviations, cv::noArray(), globalData->perViewErrors,
+                                                    calibrationFlags, solverTermCrit);
+                }
+                else {
+                    cv::Ptr<cv::aruco::Dictionary> dictionary =
+                            cv::aruco::getPredefinedDictionary(cv::aruco::PREDEFINED_DICTIONARY_NAME(capParams.charucoDictName));
+                    cv::Ptr<cv::aruco::CharucoBoard> charucoboard =
+                                cv::aruco::CharucoBoard::create(capParams.boardSize.width, capParams.boardSize.height,
+                                                                capParams.charucoSquareLenght, capParams.charucoMarkerSize, dictionary);
+                    globalData->totalAvgErr =
+                            cv::aruco::calibrateCameraCharuco(globalData->allCharucoCorners, globalData->allCharucoIds,
+                                                           charucoboard, globalData->imageSize,
+                                                           globalData->cameraMatrix, globalData->distCoeffs,
+                                                           cv::noArray(), cv::noArray(), globalData->stdDeviations, cv::noArray(),
+                                                           globalData->perViewErrors, calibrationFlags, solverTermCrit);
+                }
+                dataController->updateUndistortMap();
+                dataController->printParametersToConsole(std::cout);
+                controller->updateState();
+                for(int j = 0; j < capParams.calibrationStep; j++)
+                    dataController->filterFrames();
+                static_cast<ShowProcessor*>(showProcessor.get())->updateBoardsView();
+            }
+            else if (exitStatus == DeleteLastFrame) {
+                deleteButton(0, &dataController);
+                static_cast<ShowProcessor*>(showProcessor.get())->updateBoardsView();
+            }
+            else if (exitStatus == DeleteAllFrames) {
+                deleteAllButton(0, &dataController);
+                static_cast<ShowProcessor*>(showProcessor.get())->updateBoardsView();
+            }
+            else if (exitStatus == SaveCurrentData) {
+                saveCurrentParamsButton(0, &dataController);
+            }
+            else if (exitStatus == SwitchUndistort)
+                static_cast<ShowProcessor*>(showProcessor.get())->switchUndistort();
+            else if (exitStatus == SwitchVisualisation)
+                static_cast<ShowProcessor*>(showProcessor.get())->switchVisualizationMode();
+
+            for (std::vector<cv::Ptr<FrameProcessor> >::iterator it = processors.begin(); it != processors.end(); ++it)
+                (*it)->resetState();
+        }
+    }
+    catch (std::runtime_error exp) {
+        std::cout << exp.what() << std::endl;
+    }
+
+    return 0;
+}
diff --git a/apps/interactive-calibration/parametersController.cpp b/apps/interactive-calibration/parametersController.cpp
new file mode 100644
index 0000000..d581582
--- /dev/null
+++ b/apps/interactive-calibration/parametersController.cpp
@@ -0,0 +1,143 @@
+// This file is part of OpenCV project.
+// It is subject to the license terms in the LICENSE file found in the top-level directory
+// of this distribution and at http://opencv.org/license.html.
+
+#include "parametersController.hpp"
+
+#include <iostream>
+
+template <typename T>
+static bool readFromNode(cv::FileNode node, T& value)
+{
+    if(!node.isNone()) {
+        node >> value;
+        return true;
+    }
+    else
+        return false;
+}
+
+static bool checkAssertion(bool value, const std::string& msg)
+{
+    if(!value)
+        std::cerr << "Error: " << msg << std::endl;
+
+    return value;
+}
+
+bool calib::parametersController::loadFromFile(const std::string &inputFileName)
+{
+    cv::FileStorage reader;
+    reader.open(inputFileName, cv::FileStorage::READ);
+
+    if(!reader.isOpened()) {
+        std::cerr << "Warning: Unable to open " << inputFileName <<
+                     " Applicatioin stated with default advanced parameters" << std::endl;
+        return true;
+    }
+
+    readFromNode(reader["charuco_dict"], mCapParams.charucoDictName);
+    readFromNode(reader["charuco_square_lenght"], mCapParams.charucoSquareLenght);
+    readFromNode(reader["charuco_marker_size"], mCapParams.charucoMarkerSize);
+    readFromNode(reader["camera_resolution"], mCapParams.cameraResolution);
+    readFromNode(reader["calibration_step"], mCapParams.calibrationStep);
+    readFromNode(reader["max_frames_num"], mCapParams.maxFramesNum);
+    readFromNode(reader["min_frames_num"], mCapParams.minFramesNum);
+    readFromNode(reader["solver_eps"], mInternalParameters.solverEps);
+    readFromNode(reader["solver_max_iters"], mInternalParameters.solverMaxIters);
+    readFromNode(reader["fast_solver"], mInternalParameters.fastSolving);
+    readFromNode(reader["frame_filter_conv_param"], mInternalParameters.filterAlpha);
+
+    bool retValue =
+            checkAssertion(mCapParams.charucoDictName >= 0, "Dict name must be >= 0") &&
+            checkAssertion(mCapParams.charucoMarkerSize > 0, "Marker size must be positive") &&
+            checkAssertion(mCapParams.charucoSquareLenght > 0, "Square size must be positive") &&
+            checkAssertion(mCapParams.minFramesNum > 1, "Minimal number of frames for calibration < 1") &&
+            checkAssertion(mCapParams.calibrationStep > 0, "Calibration step must be positive") &&
+            checkAssertion(mCapParams.maxFramesNum > mCapParams.minFramesNum, "maxFramesNum < minFramesNum") &&
+            checkAssertion(mInternalParameters.solverEps > 0, "Solver precision must be positive") &&
+            checkAssertion(mInternalParameters.solverMaxIters > 0, "Max solver iterations number must be positive") &&
+            checkAssertion(mInternalParameters.filterAlpha >=0 && mInternalParameters.filterAlpha <=1 ,
+                           "Frame filter convolution parameter must be in [0,1] interval") &&
+            checkAssertion(mCapParams.cameraResolution.width > 0 && mCapParams.cameraResolution.height > 0,
+                           "Wrong camera resolution values");
+
+    reader.release();
+    return retValue;
+}
+
+calib::parametersController::parametersController()
+{
+}
+
+calib::captureParameters calib::parametersController::getCaptureParameters() const
+{
+    return mCapParams;
+}
+
+calib::internalParameters calib::parametersController::getInternalParameters() const
+{
+    return mInternalParameters;
+}
+
+bool calib::parametersController::loadFromParser(cv::CommandLineParser &parser)
+{
+    mCapParams.flipVertical = parser.get<bool>("flip");
+    mCapParams.captureDelay = parser.get<float>("d");
+    mCapParams.squareSize = parser.get<float>("sz");
+    mCapParams.templDst = parser.get<float>("dst");
+
+    if(!checkAssertion(mCapParams.squareSize > 0, "Distance between corners or circles must be positive"))
+        return false;
+    if(!checkAssertion(mCapParams.templDst > 0, "Distance betwen parts of dual template must be positive"))
+        return false;
+
+    if (parser.has("v")) {
+        mCapParams.source = File;
+        mCapParams.videoFileName = parser.get<std::string>("v");
+    }
+    else {
+        mCapParams.source = Camera;
+        mCapParams.camID = parser.get<int>("ci");
+    }
+
+    std::string templateType = parser.get<std::string>("t");
+
+    if(templateType.find("circles", 0) == 0) {
+        mCapParams.board = AcirclesGrid;
+        mCapParams.boardSize = cv::Size(4, 11);
+    }
+    else if(templateType.find("chessboard", 0) == 0) {
+        mCapParams.board = Chessboard;
+        mCapParams.boardSize = cv::Size(7, 7);
+    }
+    else if(templateType.find("dualcircles", 0) == 0) {
+        mCapParams.board = DoubleAcirclesGrid;
+        mCapParams.boardSize = cv::Size(4, 11);
+    }
+    else if(templateType.find("charuco", 0) == 0) {
+        mCapParams.board = chAruco;
+        mCapParams.boardSize = cv::Size(6, 8);
+        mCapParams.charucoDictName = 0;
+        mCapParams.charucoSquareLenght = 200;
+        mCapParams.charucoMarkerSize = 100;
+    }
+    else {
+        std::cerr << "Wrong template name\n";
+        return false;
+    }
+
+    if(parser.has("w") && parser.has("h")) {
+        mCapParams.boardSize = cv::Size(parser.get<int>("w"), parser.get<int>("h"));
+        if(!checkAssertion(mCapParams.boardSize.width > 0 || mCapParams.boardSize.height > 0,
+                           "Board size must be positive"))
+            return false;
+    }
+
+    if(!checkAssertion(parser.get<std::string>("of").find(".xml") > 0,
+                       "Wrong output file name: correct format is [name].xml"))
+        return false;
+
+    loadFromFile(parser.get<std::string>("pf"));
+    return true;
+}
diff --git a/apps/interactive-calibration/parametersController.hpp b/apps/interactive-calibration/parametersController.hpp
new file mode 100644
index 0000000..616f4e7
--- /dev/null
+++ b/apps/interactive-calibration/parametersController.hpp
@@ -0,0 +1,35 @@
+// This file is part of OpenCV project.
+// It is subject to the license terms in the LICENSE file found in the top-level directory
+// of this distribution and at http://opencv.org/license.html.
+
+#ifndef PARAMETERS_CONTROLLER_HPP
+#define PARAMETERS_CONTROLLER_HPP
+
+#include <string>
+
+#include <opencv2/core.hpp>
+
+#include "calibCommon.hpp"
+
+namespace calib {
+
+class parametersController
+{
+protected:
+    captureParameters mCapParams;
+    internalParameters mInternalParameters;
+
+    bool loadFromFile(const std::string& inputFileName);
+public:
+    parametersController();
+    parametersController(cv::Ptr<captureParameters> params);
+
+    captureParameters getCaptureParameters() const;
+    internalParameters getInternalParameters() const;
+
+    bool loadFromParser(cv::CommandLineParser& parser);
+};
+
+}
+
+#endif
diff --git a/apps/interactive-calibration/rotationConverters.cpp b/apps/interactive-calibration/rotationConverters.cpp
new file mode 100644
index 0000000..ff31c9e
--- /dev/null
+++ b/apps/interactive-calibration/rotationConverters.cpp
@@ -0,0 +1,126 @@
+// This file is part of OpenCV project.
+// It is subject to the license terms in the LICENSE file found in the top-level directory
+// of this distribution and at http://opencv.org/license.html.
+
+#include "rotationConverters.hpp"
+
+#include <cmath>
+
+#include <opencv2/calib3d.hpp>
+#include <opencv2/core.hpp>
+
+#define CALIB_PI 3.14159265358979323846
+#define CALIB_PI_2 1.57079632679489661923
+
+void calib::Euler(const cv::Mat& src, cv::Mat& dst, int argType)
+{
+    if((src.rows == 3) && (src.cols == 3))
+    {
+        //convert rotaion matrix to 3 angles (pitch, yaw, roll)
+        dst = cv::Mat(3, 1, CV_64F);
+        double pitch, yaw, roll;
+
+        if(src.at<double>(0,2) < -0.998)
+        {
+            pitch = -atan2(src.at<double>(1,0), src.at<double>(1,1));
+            yaw = -CALIB_PI_2;
+            roll = 0.;
+        }
+        else if(src.at<double>(0,2) > 0.998)
+        {
+            pitch = atan2(src.at<double>(1,0), src.at<double>(1,1));
+            yaw = CALIB_PI_2;
+            roll = 0.;
+        }
+        else
+        {
+            pitch = atan2(-src.at<double>(1,2), src.at<double>(2,2));
+            yaw = asin(src.at<double>(0,2));
+            roll = atan2(-src.at<double>(0,1), src.at<double>(0,0));
+        }
+
+        if(argType == CALIB_DEGREES)
+        {
+            pitch *= 180./CALIB_PI;
+            yaw *= 180./CALIB_PI;
+            roll *= 180./CALIB_PI;
+        }
+        else if(argType != CALIB_RADIANS)
+            CV_Error(cv::Error::StsBadFlag, "Invalid argument type");
+
+        dst.at<double>(0,0) = pitch;
+        dst.at<double>(1,0) = yaw;
+        dst.at<double>(2,0) = roll;
+    }
+    else if( (src.cols == 1 && src.rows == 3) ||
+             (src.cols == 3 && src.rows == 1 ) )
+    {
+        //convert vector which contains 3 angles (pitch, yaw, roll) to rotaion matrix
+        double pitch, yaw, roll;
+        if(src.cols == 1 && src.rows == 3)
+        {
+            pitch = src.at<double>(0,0);
+            yaw = src.at<double>(1,0);
+            roll = src.at<double>(2,0);
+        }
+        else{
+            pitch = src.at<double>(0,0);
+            yaw = src.at<double>(0,1);
+            roll = src.at<double>(0,2);
+        }
+
+        if(argType == CALIB_DEGREES)
+        {
+            pitch *= CALIB_PI / 180.;
+            yaw *= CALIB_PI / 180.;
+            roll *= CALIB_PI / 180.;
+        }
+        else if(argType != CALIB_RADIANS)
+            CV_Error(cv::Error::StsBadFlag, "Invalid argument type");
+
+        dst = cv::Mat(3, 3, CV_64F);
+        cv::Mat M(3, 3, CV_64F);
+        cv::Mat i = cv::Mat::eye(3, 3, CV_64F);
+        i.copyTo(dst);
+        i.copyTo(M);
+
+        double* pR = dst.ptr<double>();
+        pR[4] = cos(pitch);
+        pR[7] = sin(pitch);
+        pR[8] = pR[4];
+        pR[5] = -pR[7];
+
+        double* pM = M.ptr<double>();
+        pM[0] = cos(yaw);
+        pM[2] = sin(yaw);
+        pM[8] = pM[0];
+        pM[6] = -pM[2];
+
+        dst *= M;
+        i.copyTo(M);
+        pM[0] = cos(roll);
+        pM[3] = sin(roll);
+        pM[4] = pM[0];
+        pM[1] = -pM[3];
+
+        dst *= M;
+    }
+    else
+        CV_Error(cv::Error::StsBadFlag, "Input matrix must be 1x3, 3x1 or 3x3" );
+}
+
+void calib::RodriguesToEuler(const cv::Mat& src, cv::Mat& dst, int argType)
+{
+    CV_Assert((src.cols == 1 && src.rows == 3) || (src.cols == 3 && src.rows == 1));
+    cv::Mat R;
+    cv::Rodrigues(src, R);
+    Euler(R, dst, argType);
+}
+
+void calib::EulerToRodrigues(const cv::Mat& src, cv::Mat& dst, int argType)
+{
+    CV_Assert((src.cols == 1 && src.rows == 3) || (src.cols == 3 && src.rows == 1));
+    cv::Mat R;
+    Euler(src, R, argType);
+    cv::Rodrigues(R, dst);
+}
diff --git a/apps/interactive-calibration/rotationConverters.hpp b/apps/interactive-calibration/rotationConverters.hpp
new file mode 100644
index 0000000..fcb5bcc
--- /dev/null
+++ b/apps/interactive-calibration/rotationConverters.hpp
@@ -0,0 +1,20 @@
+// This file is part of OpenCV project.
+// It is subject to the license terms in the LICENSE file found in the top-level directory
+// of this distribution and at http://opencv.org/license.html.
+
+#ifndef ROTATION_CONVERTERS_HPP
+#define ROTATION_CONVERTERS_HPP
+
+#include <opencv2/core.hpp>
+
+namespace calib
+{
+#define CALIB_RADIANS 0
+#define CALIB_DEGREES 1
+
+    void Euler(const cv::Mat& src, cv::Mat& dst, int argType = CALIB_RADIANS);
+    void RodriguesToEuler(const cv::Mat& src, cv::Mat& dst, int argType = CALIB_RADIANS);
+    void EulerToRodrigues(const cv::Mat& src, cv::Mat& dst, int argType = CALIB_RADIANS);
+
+}
+#endif
diff --git a/apps/traincascade/CMakeLists.txt b/apps/traincascade/CMakeLists.txt
index b21fb87..e4d6548 100644
--- a/apps/traincascade/CMakeLists.txt
+++ b/apps/traincascade/CMakeLists.txt
@@ -8,6 +8,8 @@ endif()
 project(traincascade)
 set(the_target opencv_traincascade)
 
+ocv_warnings_disable(CMAKE_CXX_FLAGS -Woverloaded-virtual)
+
 ocv_target_include_directories(${the_target} PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}" "${OpenCV_SOURCE_DIR}/include/opencv")
 ocv_target_include_modules_recurse(${the_target} ${OPENCV_TRAINCASCADE_DEPS})
 
@@ -23,7 +25,6 @@ set_target_properties(${the_target} PROPERTIES
                       DEBUG_POSTFIX "${OPENCV_DEBUG_POSTFIX}"
                       ARCHIVE_OUTPUT_DIRECTORY ${LIBRARY_OUTPUT_PATH}
                       RUNTIME_OUTPUT_DIRECTORY ${EXECUTABLE_OUTPUT_PATH}
-                      INSTALL_NAME_DIR lib
                       OUTPUT_NAME "opencv_traincascade")
 
 if(ENABLE_SOLUTION_FOLDERS)
diff --git a/apps/traincascade/boost.cpp b/apps/traincascade/boost.cpp
index c2e7fb7..f53caad 100644
--- a/apps/traincascade/boost.cpp
+++ b/apps/traincascade/boost.cpp
@@ -33,16 +33,12 @@ using cv::ParallelLoopBody;
 #include "cxmisc.h"
 
 #include "cvconfig.h"
+
 #ifdef HAVE_TBB
-#  include "tbb/tbb_stddef.h"
-#  if TBB_VERSION_MAJOR*100 + TBB_VERSION_MINOR >= 202
-#    include "tbb/tbb.h"
-#    include "tbb/task.h"
-#    undef min
-#    undef max
-#  else
-#    undef HAVE_TBB
-#  endif
+#  include "tbb/tbb.h"
+#  include "tbb/task.h"
+#  undef min
+#  undef max
 #endif
 
 #ifdef HAVE_TBB
diff --git a/apps/traincascade/cascadeclassifier.cpp b/apps/traincascade/cascadeclassifier.cpp
index 2924fe3..ebfb43e 100644
--- a/apps/traincascade/cascadeclassifier.cpp
+++ b/apps/traincascade/cascadeclassifier.cpp
@@ -190,6 +190,7 @@ bool CvCascadeClassifier::train( const string _cascadeDirName,
     cascadeParams.printAttrs();
     stageParams->printAttrs();
     featureParams->printAttrs();
+    cout << "Number of unique features given windowSize [" << _cascadeParams.winSize.width << "," << _cascadeParams.winSize.height << "] : " << featureEvaluator->getNumFeatures() << "" << endl;
 
     int startNumStages = (int)stageClassifiers.size();
     if ( startNumStages > 1 )
@@ -289,7 +290,7 @@ int CvCascadeClassifier::predict( int sampleIdx )
 {
     CV_DbgAssert( sampleIdx < numPos + numNeg );
     for (vector< Ptr<CvCascadeBoost> >::iterator it = stageClassifiers.begin();
-        it != stageClassifiers.end(); it++ )
+        it != stageClassifiers.end();++it )
     {
         if ( (*it)->predict( sampleIdx ) == 0.f )
             return 0;
@@ -309,7 +310,8 @@ bool CvCascadeClassifier::updateTrainingSet( double minimumAcceptanceRatio, doub
     int proNumNeg = cvRound( ( ((double)numNeg) * ((double)posCount) ) / numPos ); // apply only a fraction of negative samples. double is required since overflow is possible
     int negCount = fillPassedSamples( posCount, proNumNeg, false, minimumAcceptanceRatio, negConsumed );
     if ( !negCount )
-        return false;
+        if ( !(negConsumed > 0 && ((double)negCount+1)/(double)negConsumed <= minimumAcceptanceRatio) )
+            return false;
 
     curNumSamples = posCount + negCount;
     acceptanceRatio = negConsumed == 0 ? 0 : ( (double)negCount/(double)(int64)negConsumed );
@@ -364,7 +366,7 @@ void CvCascadeClassifier::writeStages( FileStorage &fs, const Mat& featureMap )
     int i = 0;
     fs << CC_STAGES << "[";
     for( vector< Ptr<CvCascadeBoost> >::const_iterator it = stageClassifiers.begin();
-        it != stageClassifiers.end(); it++, i++ )
+        it != stageClassifiers.end();++it, ++i )
     {
         sprintf( cmnt, "stage %d", i );
         cvWriteComment( fs.fs, cmnt, 0 );
@@ -410,6 +412,7 @@ bool CvCascadeClassifier::readStages( const FileNode &node)
 }
 
 // For old Haar Classifier file saving
+#define ICV_HAAR_TYPE_ID              "opencv-haar-classifier"
 #define ICV_HAAR_SIZE_NAME            "size"
 #define ICV_HAAR_STAGES_NAME          "stages"
 #define ICV_HAAR_TREES_NAME             "trees"
@@ -432,11 +435,12 @@ void CvCascadeClassifier::save( const string filename, bool baseFormat )
     if ( !fs.isOpened() )
         return;
 
-    fs << FileStorage::getDefaultObjectName(filename) << "{";
+    fs << FileStorage::getDefaultObjectName(filename);
     if ( !baseFormat )
     {
         Mat featureMap;
         getUsedFeaturesIdxMap( featureMap );
+        fs << "{";
         writeParams( fs );
         fs << CC_STAGE_NUM << (int)stageClassifiers.size();
         writeStages( fs, featureMap );
@@ -448,6 +452,7 @@ void CvCascadeClassifier::save( const string filename, bool baseFormat )
         CvSeq* weak;
         if ( cascadeParams.featureType != CvFeatureParams::HAAR )
             CV_Error( CV_StsBadFunc, "old file format is used for Haar-like features only");
+        fs << "{:" ICV_HAAR_TYPE_ID;
         fs << ICV_HAAR_SIZE_NAME << "[:" << cascadeParams.winSize.width <<
             cascadeParams.winSize.height << "]";
         fs << ICV_HAAR_STAGES_NAME << "[";
@@ -556,7 +561,7 @@ void CvCascadeClassifier::getUsedFeaturesIdxMap( Mat& featureMap )
     featureMap.setTo(Scalar(-1));
 
     for( vector< Ptr<CvCascadeBoost> >::const_iterator it = stageClassifiers.begin();
-        it != stageClassifiers.end(); it++ )
+        it != stageClassifiers.end();++it )
         (*it)->markUsedFeaturesInMap( featureMap );
 
     for( int fi = 0, idx = 0; fi < varCount; fi++ )
diff --git a/apps/traincascade/imagestorage.cpp b/apps/traincascade/imagestorage.cpp
index fdaa33b..420d997 100644
--- a/apps/traincascade/imagestorage.cpp
+++ b/apps/traincascade/imagestorage.cpp
@@ -28,7 +28,7 @@ CvCascadeImageReader::NegReader::NegReader()
 
 bool CvCascadeImageReader::NegReader::create( const string _filename, Size _winSize )
 {
-    string dirname, str;
+    string str;
     std::ifstream file(_filename.c_str());
     if ( !file.is_open() )
         return false;
@@ -36,6 +36,7 @@ bool CvCascadeImageReader::NegReader::create( const string _filename, Size _winS
     while( !file.eof() )
     {
         std::getline(file, str);
+        str.erase(str.find_last_not_of(" \n\r\t")+1);
         if (str.empty()) break;
         if (str.at(0) == '#' ) continue; /* comment */
         imgFilenames.push_back(str);
diff --git a/apps/traincascade/old_ml.hpp b/apps/traincascade/old_ml.hpp
index bf0cd15..1fe8b1a 100644
--- a/apps/traincascade/old_ml.hpp
+++ b/apps/traincascade/old_ml.hpp
@@ -38,8 +38,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_ML_HPP__
-#define __OPENCV_ML_HPP__
+#ifndef OPENCV_ML_HPP
+#define OPENCV_ML_HPP
 
 #ifdef __cplusplus
 #  include "opencv2/core.hpp"
@@ -2063,6 +2063,6 @@ template<> void DefaultDeleter<CvDTreeSplit>::operator ()(CvDTreeSplit* obj) con
 }
 
 #endif // __cplusplus
-#endif // __OPENCV_ML_HPP__
+#endif // OPENCV_ML_HPP
 
 /* End of file. */
diff --git a/apps/traincascade/old_ml_precomp.hpp b/apps/traincascade/old_ml_precomp.hpp
index 32ae269..003c1f7 100644
--- a/apps/traincascade/old_ml_precomp.hpp
+++ b/apps/traincascade/old_ml_precomp.hpp
@@ -38,8 +38,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_PRECOMP_H__
-#define __OPENCV_PRECOMP_H__
+#ifndef OPENCV_PRECOMP_H
+#define OPENCV_PRECOMP_H
 
 #include "opencv2/core.hpp"
 #include "old_ml.hpp"
diff --git a/apps/version/CMakeLists.txt b/apps/version/CMakeLists.txt
new file mode 100644
index 0000000..6ced527
--- /dev/null
+++ b/apps/version/CMakeLists.txt
@@ -0,0 +1,32 @@
+SET(OPENCV_APPLICATION_DEPS opencv_core opencv_highgui opencv_imgproc opencv_imgcodecs opencv_videoio)
+ocv_check_dependencies(${OPENCV_APPLICATION_DEPS})
+
+if(NOT OCV_DEPENDENCIES_FOUND)
+  return()
+endif()
+
+project(opencv_version)
+set(the_target opencv_version)
+
+ocv_target_include_directories(${the_target} PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}" "${OpenCV_SOURCE_DIR}/include/opencv")
+ocv_target_include_modules_recurse(${the_target} ${OPENCV_APPLICATION_DEPS})
+
+file(GLOB SRCS *.cpp)
+
+ocv_add_executable(${the_target} ${SRCS})
+ocv_target_link_libraries(${the_target} ${OPENCV_APPLICATION_DEPS})
+
+set_target_properties(${the_target} PROPERTIES
+                      DEBUG_POSTFIX "${OPENCV_DEBUG_POSTFIX}"
+                      RUNTIME_OUTPUT_DIRECTORY ${EXECUTABLE_OUTPUT_PATH}
+                      OUTPUT_NAME "opencv_version")
+
+set_target_properties(${the_target} PROPERTIES FOLDER "applications")
+
+if(INSTALL_CREATE_DISTRIB)
+  if(BUILD_SHARED_LIBS)
+    install(TARGETS ${the_target} RUNTIME DESTINATION ${OPENCV_BIN_INSTALL_PATH} CONFIGURATIONS Release COMPONENT libs)
+  endif()
+else()
+  install(TARGETS ${the_target} RUNTIME DESTINATION ${OPENCV_BIN_INSTALL_PATH} COMPONENT libs)
+endif()
diff --git a/apps/version/opencv_version.cpp b/apps/version/opencv_version.cpp
new file mode 100644
index 0000000..78f2810
--- /dev/null
+++ b/apps/version/opencv_version.cpp
@@ -0,0 +1,28 @@
+// This file is part of OpenCV project.
+// It is subject to the license terms in the LICENSE file found in the top-level directory
+// of this distribution and at http://opencv.org/license.html.
+
+#include <iostream>
+
+#include <opencv2/core.hpp>
+
+int main(int argc, const char** argv)
+{
+    cv::CommandLineParser parser(argc, argv,
+        "{ help h usage ? |      | show this help message }"
+        "{ verbose v      |      | show build configuration log }"
+    );
+    if (parser.has("help"))
+    {
+        parser.printMessage();
+    }
+    else if (parser.has("verbose"))
+    {
+        std::cout << cv::getBuildInformation().c_str() << std::endl;
+    }
+    else
+    {
+        std::cout << CV_VERSION << std::endl;
+    }
+    return 0;
+}
diff --git a/apps/visualisation/CMakeLists.txt b/apps/visualisation/CMakeLists.txt
new file mode 100644
index 0000000..7c4d6e0
--- /dev/null
+++ b/apps/visualisation/CMakeLists.txt
@@ -0,0 +1,37 @@
+SET(OPENCV_VISUALISATION_DEPS opencv_core opencv_highgui opencv_imgproc opencv_videoio opencv_imgcodecs)
+ocv_check_dependencies(${OPENCV_VISUALISATION_DEPS})
+
+if(NOT OCV_DEPENDENCIES_FOUND)
+   return()
+endif()
+
+project(visualisation)
+set(the_target opencv_visualisation)
+
+ocv_target_include_directories(${the_target} PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}" "${OpenCV_SOURCE_DIR}/include/opencv")
+ocv_target_include_modules_recurse(${the_target} ${OPENCV_VISUALISATION_DEPS})
+
+file(GLOB SRCS *.cpp)
+
+set(visualisation_files ${SRCS})
+ocv_add_executable(${the_target} ${visualisation_files})
+ocv_target_link_libraries(${the_target} ${OPENCV_VISUALISATION_DEPS})
+
+set_target_properties(${the_target} PROPERTIES
+                      DEBUG_POSTFIX "${OPENCV_DEBUG_POSTFIX}"
+                      ARCHIVE_OUTPUT_DIRECTORY ${LIBRARY_OUTPUT_PATH}
+                      RUNTIME_OUTPUT_DIRECTORY ${EXECUTABLE_OUTPUT_PATH}
+                      INSTALL_NAME_DIR lib
+                      OUTPUT_NAME "opencv_visualisation")
+
+if(ENABLE_SOLUTION_FOLDERS)
+   set_target_properties(${the_target} PROPERTIES FOLDER "applications")
+endif()
+
+if(INSTALL_CREATE_DISTRIB)
+   if(BUILD_SHARED_LIBS)
+      install(TARGETS ${the_target} RUNTIME DESTINATION ${OPENCV_BIN_INSTALL_PATH} CONFIGURATIONS Release COMPONENT dev)
+   endif()
+else()
+   install(TARGETS ${the_target} RUNTIME DESTINATION ${OPENCV_BIN_INSTALL_PATH} COMPONENT dev)
+endif()
diff --git a/apps/visualisation/opencv_visualisation.cpp b/apps/visualisation/opencv_visualisation.cpp
new file mode 100644
index 0000000..68ebd65
--- /dev/null
+++ b/apps/visualisation/opencv_visualisation.cpp
@@ -0,0 +1,364 @@
+////////////////////////////////////////////////////////////////////////////////////////
+//
+//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+//  By downloading, copying, installing or using the software you agree to this license.
+//  If you do not agree to this license, do not download, install,
+//  copy or use the software.
+//
+//
+//                          License Agreement
+//                For Open Source Computer Vision Library
+//
+// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
+// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
+// Copyright (C) 2013, OpenCV Foundation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+//   * Redistribution's of source code must retain the above copyright notice,
+//     this list of conditions and the following disclaimer.
+//
+//   * Redistribution's in binary form must reproduce the above copyright notice,
+//     this list of conditions and the following disclaimer in the documentation
+//     and/or other materials provided with the distribution.
+//
+//   * The name of the copyright holders may not be used to endorse or promote products
+//     derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+////////////////////////////////////////////////////////////////////////////////////////
+
+/*****************************************************************************************************
+
+Software for visualising cascade classifier models trained by OpenCV and to get a better
+understanding of the used features.
+
+USAGE:
+./opencv_visualisation --model=<model.xml> --image=<ref.png> --data=<video output folder>
+
+Created by: Puttemans Steven - April 2016
+*****************************************************************************************************/
+
+#include <opencv2/core.hpp>
+#include <opencv2/highgui.hpp>
+#include <opencv2/imgproc.hpp>
+#include <opencv2/imgcodecs.hpp>
+#include <opencv2/videoio.hpp>
+
+#include <fstream>
+#include <iostream>
+
+using namespace std;
+using namespace cv;
+
+struct rect_data{
+    int x;
+    int y;
+    int w;
+    int h;
+    float weight;
+};
+
+static void printLimits(){
+    cerr << "Limits of the current interface:" << endl;
+    cerr << " - Only handles cascade classifier models, trained with the opencv_traincascade tool, containing stumps as decision trees [default settings]." << endl;
+    cerr << " - The image provided needs to be a sample window with the original model dimensions, passed to the --image parameter." << endl;
+    cerr << " - ONLY handles HAAR and LBP features." << endl;
+}
+
+int main( int argc, const char** argv )
+{
+    CommandLineParser parser(argc, argv,
+        "{ help h usage ? |      | show this message }"
+        "{ image i        |      | (required) path to reference image }"
+        "{ model m        |      | (required) path to cascade xml file }"
+        "{ data d         |      | (optional) path to video output folder }"
+    );
+    // Read in the input arguments
+    if (parser.has("help")){
+        parser.printMessage();
+        printLimits();
+        return 0;
+    }
+    string model(parser.get<string>("model"));
+    string output_folder(parser.get<string>("data"));
+    string image_ref = (parser.get<string>("image"));
+    if (model.empty() || image_ref.empty()){
+        parser.printMessage();
+        printLimits();
+        return -1;
+    }
+
+    // Value for timing
+    // You can increase this to have a better visualisation during the generation
+    int timing = 1;
+
+    // Value for cols of storing elements
+    int cols_prefered = 5;
+
+    // Open the XML model
+    FileStorage fs;
+    bool model_ok = fs.open(model, FileStorage::READ);
+    if (!model_ok){
+        cerr << "the cascade file '" << model << "' could not be loaded." << endl;
+        return  -1;
+    }
+    // Get a the required information
+    // First decide which feature type we are using
+    FileNode cascade = fs["cascade"];
+    string feature_type = cascade["featureType"];
+    bool haar = false, lbp = false;
+    if (feature_type.compare("HAAR") == 0){
+        haar = true;
+    }
+    if (feature_type.compare("LBP") == 0){
+        lbp = true;
+    }
+    if ( feature_type.compare("HAAR") != 0 && feature_type.compare("LBP")){
+        cerr << "The model is not an HAAR or LBP feature based model!" << endl;
+        cerr << "Please select a model that can be visualized by the software." << endl;
+        return -1;
+    }
+
+    // We make a visualisation mask - which increases the window to make it at least a bit more visible
+    int resize_factor = 10;
+    int resize_storage_factor = 10;
+    Mat reference_image = imread(image_ref, IMREAD_GRAYSCALE );
+    if (reference_image.empty()){
+        cerr << "the reference image '" << image_ref << "'' could not be loaded." << endl;
+        return -1;
+    }
+    Mat visualization;
+    resize(reference_image, visualization, Size(reference_image.cols * resize_factor, reference_image.rows * resize_factor));
+
+    // First recover for each stage the number of weak features and their index
+    // Important since it is NOT sequential when using LBP features
+    vector< vector<int> > stage_features;
+    FileNode stages = cascade["stages"];
+    FileNodeIterator it_stages = stages.begin(), it_stages_end = stages.end();
+    int idx = 0;
+    for( ; it_stages != it_stages_end; it_stages++, idx++ ){
+        vector<int> current_feature_indexes;
+        FileNode weak_classifiers = (*it_stages)["weakClassifiers"];
+        FileNodeIterator it_weak = weak_classifiers.begin(), it_weak_end = weak_classifiers.end();
+        vector<int> values;
+        for(int idy = 0; it_weak != it_weak_end; it_weak++, idy++ ){
+            (*it_weak)["internalNodes"] >> values;
+            current_feature_indexes.push_back( (int)values[2] );
+        }
+        stage_features.push_back(current_feature_indexes);
+    }
+
+    // If the output option has been chosen than we will store a combined image plane for
+    // each stage, containing all weak classifiers for that stage.
+    bool draw_planes = false;
+    stringstream output_video;
+    output_video << output_folder << "model_visualization.avi";
+    VideoWriter result_video;
+    if( output_folder.compare("") != 0 ){
+        draw_planes = true;
+        result_video.open(output_video.str(), VideoWriter::fourcc('X','V','I','D'), 15, Size(reference_image.cols * resize_factor, reference_image.rows * resize_factor), false);
+    }
+
+    if(haar){
+        // Grab the corresponding features dimensions and weights
+        FileNode features = cascade["features"];
+        vector< vector< rect_data > > feature_data;
+        FileNodeIterator it_features = features.begin(), it_features_end = features.end();
+        for(int idf = 0; it_features != it_features_end; it_features++, idf++ ){
+            vector< rect_data > current_feature_rectangles;
+            FileNode rectangles = (*it_features)["rects"];
+            int nrects = (int)rectangles.size();
+            for(int k = 0; k < nrects; k++){
+                rect_data current_data;
+                FileNode single_rect = rectangles[k];
+                current_data.x = (int)single_rect[0];
+                current_data.y = (int)single_rect[1];
+                current_data.w = (int)single_rect[2];
+                current_data.h = (int)single_rect[3];
+                current_data.weight = (float)single_rect[4];
+                current_feature_rectangles.push_back(current_data);
+            }
+            feature_data.push_back(current_feature_rectangles);
+        }
+
+        // Loop over each possible feature on its index, visualise on the mask and wait a bit,
+        // then continue to the next feature.
+        // If visualisations should be stored then do the in between calculations
+        Mat image_plane;
+        Mat metadata = Mat::zeros(150, 1000, CV_8UC1);
+        vector< rect_data > current_rects;
+        for(int sid = 0; sid < (int)stage_features.size(); sid ++){
+            if(draw_planes){
+                int features_nmbr = (int)stage_features[sid].size();
+                int cols = cols_prefered;
+                int rows = features_nmbr / cols;
+                if( (features_nmbr % cols) > 0){
+                    rows++;
+                }
+                image_plane = Mat::zeros(reference_image.rows * resize_storage_factor * rows, reference_image.cols * resize_storage_factor * cols, CV_8UC1);
+            }
+            for(int fid = 0; fid < (int)stage_features[sid].size(); fid++){
+                stringstream meta1, meta2;
+                meta1 << "Stage " << sid << " / Feature " << fid;
+                meta2 << "Rectangles: ";
+                Mat temp_window = visualization.clone();
+                Mat temp_metadata = metadata.clone();
+                int current_feature_index = stage_features[sid][fid];
+                current_rects = feature_data[current_feature_index];
+                Mat single_feature = reference_image.clone();
+                resize(single_feature, single_feature, Size(), resize_storage_factor, resize_storage_factor);
+                for(int i = 0; i < (int)current_rects.size(); i++){
+                    rect_data local = current_rects[i];
+                    if(draw_planes){
+                        if(local.weight >= 0){
+                            rectangle(single_feature, Rect(local.x * resize_storage_factor, local.y * resize_storage_factor, local.w * resize_storage_factor, local.h * resize_storage_factor), Scalar(0), FILLED);
+                        }else{
+                            rectangle(single_feature, Rect(local.x * resize_storage_factor, local.y * resize_storage_factor, local.w * resize_storage_factor, local.h * resize_storage_factor), Scalar(255), FILLED);
+                        }
+                    }
+                    Rect part(local.x * resize_factor, local.y * resize_factor, local.w * resize_factor, local.h * resize_factor);
+                    meta2 << part << " (w " << local.weight << ") ";
+                    if(local.weight >= 0){
+                        rectangle(temp_window, part, Scalar(0), FILLED);
+                    }else{
+                        rectangle(temp_window, part, Scalar(255), FILLED);
+                    }
+                }
+                imshow("features", temp_window);
+                putText(temp_window, meta1.str(), Point(15,15), FONT_HERSHEY_SIMPLEX, 0.5, Scalar(255));
+                result_video.write(temp_window);
+                // Copy the feature image if needed
+                if(draw_planes){
+                    single_feature.copyTo(image_plane(Rect(0 + (fid%cols_prefered)*single_feature.cols, 0 + (fid/cols_prefered) * single_feature.rows, single_feature.cols, single_feature.rows)));
+                }
+                putText(temp_metadata, meta1.str(), Point(15,15), FONT_HERSHEY_SIMPLEX, 0.5, Scalar(255));
+                putText(temp_metadata, meta2.str(), Point(15,40), FONT_HERSHEY_SIMPLEX, 0.5, Scalar(255));
+                imshow("metadata", temp_metadata);
+                waitKey(timing);
+            }
+            //Store the stage image if needed
+            if(draw_planes){
+                stringstream save_location;
+                save_location << output_folder << "stage_" << sid << ".png";
+                imwrite(save_location.str(), image_plane);
+            }
+        }
+    }
+
+    if(lbp){
+        // Grab the corresponding features dimensions and weights
+        FileNode features = cascade["features"];
+        vector<Rect> feature_data;
+        FileNodeIterator it_features = features.begin(), it_features_end = features.end();
+        for(int idf = 0; it_features != it_features_end; it_features++, idf++ ){
+            FileNode rectangle = (*it_features)["rect"];
+            Rect current_feature ((int)rectangle[0], (int)rectangle[1], (int)rectangle[2], (int)rectangle[3]);
+            feature_data.push_back(current_feature);
+        }
+
+        // Loop over each possible feature on its index, visualise on the mask and wait a bit,
+        // then continue to the next feature.
+        Mat image_plane;
+        Mat metadata = Mat::zeros(150, 1000, CV_8UC1);
+        for(int sid = 0; sid < (int)stage_features.size(); sid ++){
+            if(draw_planes){
+                int features_nmbr = (int)stage_features[sid].size();
+                int cols = cols_prefered;
+                int rows = features_nmbr / cols;
+                if( (features_nmbr % cols) > 0){
+                    rows++;
+                }
+                image_plane = Mat::zeros(reference_image.rows * resize_storage_factor * rows, reference_image.cols * resize_storage_factor * cols, CV_8UC1);
+            }
+            for(int fid = 0; fid < (int)stage_features[sid].size(); fid++){
+                stringstream meta1, meta2;
+                meta1 << "Stage " << sid << " / Feature " << fid;
+                meta2 << "Rectangle: ";
+                Mat temp_window = visualization.clone();
+                Mat temp_metadata = metadata.clone();
+                int current_feature_index = stage_features[sid][fid];
+                Rect current_rect = feature_data[current_feature_index];
+                Mat single_feature = reference_image.clone();
+                resize(single_feature, single_feature, Size(), resize_storage_factor, resize_storage_factor);
+
+                // VISUALISATION
+                // The rectangle is the top left one of a 3x3 block LBP constructor
+                Rect resized(current_rect.x * resize_factor, current_rect.y * resize_factor, current_rect.width * resize_factor, current_rect.height * resize_factor);
+                meta2 << resized;
+                // Top left
+                rectangle(temp_window, resized, Scalar(255), 1);
+                // Top middle
+                rectangle(temp_window, Rect(resized.x + resized.width, resized.y, resized.width, resized.height), Scalar(255), 1);
+                // Top right
+                rectangle(temp_window, Rect(resized.x + 2*resized.width, resized.y, resized.width, resized.height), Scalar(255), 1);
+                // Middle left
+                rectangle(temp_window, Rect(resized.x, resized.y + resized.height, resized.width, resized.height), Scalar(255), 1);
+                // Middle middle
+                rectangle(temp_window, Rect(resized.x + resized.width, resized.y + resized.height, resized.width, resized.height), Scalar(255), FILLED);
+                // Middle right
+                rectangle(temp_window, Rect(resized.x + 2*resized.width, resized.y + resized.height, resized.width, resized.height), Scalar(255), 1);
+                // Bottom left
+                rectangle(temp_window, Rect(resized.x, resized.y + 2*resized.height, resized.width, resized.height), Scalar(255), 1);
+                // Bottom middle
+                rectangle(temp_window, Rect(resized.x + resized.width, resized.y + 2*resized.height, resized.width, resized.height), Scalar(255), 1);
+                // Bottom right
+                rectangle(temp_window, Rect(resized.x + 2*resized.width, resized.y + 2*resized.height, resized.width, resized.height), Scalar(255), 1);
+
+                if(draw_planes){
+                    Rect resized_inner(current_rect.x * resize_storage_factor, current_rect.y * resize_storage_factor, current_rect.width * resize_storage_factor, current_rect.height * resize_storage_factor);
+                    // Top left
+                    rectangle(single_feature, resized_inner, Scalar(255), 1);
+                    // Top middle
+                    rectangle(single_feature, Rect(resized_inner.x + resized_inner.width, resized_inner.y, resized_inner.width, resized_inner.height), Scalar(255), 1);
+                    // Top right
+                    rectangle(single_feature, Rect(resized_inner.x + 2*resized_inner.width, resized_inner.y, resized_inner.width, resized_inner.height), Scalar(255), 1);
+                    // Middle left
+                    rectangle(single_feature, Rect(resized_inner.x, resized_inner.y + resized_inner.height, resized_inner.width, resized_inner.height), Scalar(255), 1);
+                    // Middle middle
+                    rectangle(single_feature, Rect(resized_inner.x + resized_inner.width, resized_inner.y + resized_inner.height, resized_inner.width, resized_inner.height), Scalar(255), FILLED);
+                    // Middle right
+                    rectangle(single_feature, Rect(resized_inner.x + 2*resized_inner.width, resized_inner.y + resized_inner.height, resized_inner.width, resized_inner.height), Scalar(255), 1);
+                    // Bottom left
+                    rectangle(single_feature, Rect(resized_inner.x, resized_inner.y + 2*resized_inner.height, resized_inner.width, resized_inner.height), Scalar(255), 1);
+                    // Bottom middle
+                    rectangle(single_feature, Rect(resized_inner.x + resized_inner.width, resized_inner.y + 2*resized_inner.height, resized_inner.width, resized_inner.height), Scalar(255), 1);
+                    // Bottom right
+                    rectangle(single_feature, Rect(resized_inner.x + 2*resized_inner.width, resized_inner.y + 2*resized_inner.height, resized_inner.width, resized_inner.height), Scalar(255), 1);
+
+                    single_feature.copyTo(image_plane(Rect(0 + (fid%cols_prefered)*single_feature.cols, 0 + (fid/cols_prefered) * single_feature.rows, single_feature.cols, single_feature.rows)));
+                }
+
+                putText(temp_metadata, meta1.str(), Point(15,15), FONT_HERSHEY_SIMPLEX, 0.5, Scalar(255));
+                putText(temp_metadata, meta2.str(), Point(15,40), FONT_HERSHEY_SIMPLEX, 0.5, Scalar(255));
+                imshow("metadata", temp_metadata);
+                imshow("features", temp_window);
+                putText(temp_window, meta1.str(), Point(15,15), FONT_HERSHEY_SIMPLEX, 0.5, Scalar(255));
+                result_video.write(temp_window);
+
+                waitKey(timing);
+            }
+
+            //Store the stage image if needed
+            if(draw_planes){
+                stringstream save_location;
+                save_location << output_folder << "stage_" << sid << ".png";
+                imwrite(save_location.str(), image_plane);
+            }
+        }
+    }
+    return 0;
+}
diff --git a/cmake/FindGstreamerWindows.cmake b/cmake/FindGstreamerWindows.cmake
index c37fecd..055e8a6 100644
--- a/cmake/FindGstreamerWindows.cmake
+++ b/cmake/FindGstreamerWindows.cmake
@@ -15,7 +15,7 @@ FIND_PATH(GSTREAMER_glibconfig_INCLUDE_DIR glibconfig.h
     ENV INCLUDE DOC "Directory containing glibconfig.h include file")
 
 FIND_PATH(GSTREAMER_gstconfig_INCLUDE_DIR gst/gstconfig.h
-                                          PATHS ${GSTREAMER_DIR}/lib/gstreamer-1.0/include ${GSTREAMER_DIR}/include ${GSTREAMER_DIR}/lib/include /usr/local/include/gstreamer-1.0 /usr/include/gstreamer-1.0 /usr/local/lib/include/gstreamer-1.0 /usr/lib/include/gstreamer-1.0
+                                          PATHS ${GSTREAMER_DIR}/lib/gstreamer-1.0/include ${GSTREAMER_DIR}/include ${GSTREAMER_DIR}/include/gstreamer-1.0 ${GSTREAMER_DIR}/lib/include /usr/local/include/gstreamer-1.0 /usr/include/gstreamer-1.0 /usr/local/lib/include/gstreamer-1.0 /usr/lib/include/gstreamer-1.0
                                           ENV INCLUDE DOC "Directory containing gst/gstconfig.h include file")
 
 FIND_LIBRARY(GSTREAMER_gstaudio_LIBRARY NAMES gstaudio libgstaudio-1.0 gstaudio-1.0
diff --git a/cmake/FindOpenVX.cmake b/cmake/FindOpenVX.cmake
new file mode 100644
index 0000000..0a55e95
--- /dev/null
+++ b/cmake/FindOpenVX.cmake
@@ -0,0 +1,32 @@
+ocv_clear_vars(HAVE_OPENVX)
+
+set(OPENVX_ROOT "" CACHE PATH "OpenVX install directory")
+set(OPENVX_LIB_CANDIDATES "openvx;vxu" CACHE STRING "OpenVX library candidates list")
+
+function(find_openvx_libs _found)
+  foreach(one ${OPENVX_LIB_CANDIDATES})
+    find_library(OPENVX_${one}_LIBRARY ${one} PATHS "${OPENVX_ROOT}/lib" "${OPENVX_ROOT}/bin")
+    if(OPENVX_${one}_LIBRARY)
+      list(APPEND _list ${OPENVX_${one}_LIBRARY})
+    endif()
+  endforeach()
+  set(${_found} ${_list} PARENT_SCOPE)
+endfunction()
+
+if(OPENVX_ROOT)
+  find_path(OPENVX_INCLUDE_DIR "VX/vx.h" PATHS "${OPENVX_ROOT}/include" DOC "OpenVX include path")
+  if(NOT DEFINED OPENVX_LIBRARIES)
+    find_openvx_libs(found)
+    if(found)
+      set(OPENVX_LIBRARIES "${found}" CACHE STRING "OpenVX libraries")
+    endif()
+  endif()
+endif()
+
+if(OPENVX_INCLUDE_DIR AND OPENVX_LIBRARIES)
+  set(HAVE_OPENVX TRUE)
+endif()
+
+if(NOT HAVE_OPENVX)
+  ocv_clear_vars(HAVE_OPENVX OPENVX_LIBRARIES OPENVX_INCLUDE_DIR)
+endif()
diff --git a/cmake/OpenCVCompilerOptions.cmake b/cmake/OpenCVCompilerOptions.cmake
index 0dcf7ed..5bb0479 100644
--- a/cmake/OpenCVCompilerOptions.cmake
+++ b/cmake/OpenCVCompilerOptions.cmake
@@ -1,3 +1,33 @@
+if(ENABLE_CCACHE AND NOT CMAKE_COMPILER_IS_CCACHE)
+  # This works fine with Unix Makefiles and Ninja generators
+  find_host_program(CCACHE_PROGRAM ccache)
+  if(CCACHE_PROGRAM)
+    message(STATUS "Looking for ccache - found (${CCACHE_PROGRAM})")
+    get_property(__OLD_RULE_LAUNCH_COMPILE GLOBAL PROPERTY RULE_LAUNCH_COMPILE)
+    if(__OLD_RULE_LAUNCH_COMPILE)
+      message(STATUS "Can't replace CMake compiler launcher")
+    else()
+      set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE "${CCACHE_PROGRAM}")
+      # NOTE: Actually this check doesn't work as expected.
+      # "RULE_LAUNCH_COMPILE" is ignored by CMake during try_compile() step.
+      # ocv_check_compiler_flag(CXX "" IS_CCACHE_WORKS)
+      set(IS_CCACHE_WORKS 1)
+      if(IS_CCACHE_WORKS)
+        set(CMAKE_COMPILER_IS_CCACHE 1)
+      else()
+        message(STATUS "Unable to compile program with enabled ccache, reverting...")
+        set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE "${__OLD_RULE_LAUNCH_COMPILE}")
+      endif()
+    else()
+      message(STATUS "Looking for ccache - not found")
+    endif()
+  endif()
+endif()
+
+if((CMAKE_COMPILER_IS_CLANGCXX OR CMAKE_COMPILER_IS_CLANGCC OR CMAKE_COMPILER_IS_CCACHE) AND NOT CMAKE_GENERATOR MATCHES "Xcode")
+  set(ENABLE_PRECOMPILED_HEADERS OFF CACHE BOOL "" FORCE)
+endif()
+
 if(MINGW OR (X86 AND UNIX AND NOT APPLE))
   # mingw compiler is known to produce unstable SSE code with -O3 hence we are trying to use -O2 instead
   if(CMAKE_COMPILER_IS_GNUCXX)
@@ -71,6 +101,10 @@ if(MINGW)
   endif()
 endif()
 
+if(CV_ICC AND NOT ENABLE_FAST_MATH)
+  add_extra_compiler_option("-fp-model precise")
+endif()
+
 if(CMAKE_COMPILER_IS_GNUCXX)
   # High level of warnings.
   add_extra_compiler_option(-W)
@@ -97,6 +131,7 @@ if(CMAKE_COMPILER_IS_GNUCXX)
     add_extra_compiler_option(-Wno-narrowing)
     add_extra_compiler_option(-Wno-delete-non-virtual-dtor)
     add_extra_compiler_option(-Wno-unnamed-type-template-args)
+    add_extra_compiler_option(-Wno-comment)
   endif()
   add_extra_compiler_option(-fdiagnostics-show-option)
 
@@ -146,6 +181,9 @@ if(CMAKE_COMPILER_IS_GNUCXX)
   elseif(X86 OR X86_64)
     add_extra_compiler_option(-mno-sse2)
   endif()
+  if(ARM)
+    add_extra_compiler_option("-mfp16-format=ieee")
+  endif(ARM)
   if(ENABLE_NEON)
     add_extra_compiler_option("-mfpu=neon")
   endif()
@@ -229,6 +267,11 @@ if(CMAKE_COMPILER_IS_GNUCXX)
     set(OPENCV_EXTRA_CXX_FLAGS "${OPENCV_EXTRA_CXX_FLAGS} --coverage")
   endif()
 
+  if(ENABLE_INSTRUMENTATION)
+    set(OPENCV_EXTRA_CXX_FLAGS "${OPENCV_EXTRA_CXX_FLAGS} --std=c++11")
+    set(WITH_VTK OFF) # There are issues with VTK 6.0
+  endif()
+
   set(OPENCV_EXTRA_FLAGS_RELEASE "${OPENCV_EXTRA_FLAGS_RELEASE} -DNDEBUG")
   set(OPENCV_EXTRA_FLAGS_DEBUG "${OPENCV_EXTRA_FLAGS_DEBUG} -O0 -DDEBUG -D_DEBUG")
 endif()
@@ -327,6 +370,34 @@ if(CMAKE_COMPILER_IS_GNUCXX AND CMAKE_OPENCV_GCC_VERSION_NUM GREATER 399)
   add_extra_compiler_option(-fvisibility-inlines-hidden)
 endif()
 
+if(NOT OPENCV_FP16_DISABLE AND NOT IOS)
+  if(ARM AND ENABLE_NEON)
+    set(FP16_OPTION "-mfpu=neon-fp16")
+  elseif((X86 OR X86_64) AND NOT MSVC AND ENABLE_AVX)
+    set(FP16_OPTION "-mf16c")
+  endif()
+  try_compile(__VALID_FP16
+    "${OpenCV_BINARY_DIR}"
+    "${OpenCV_SOURCE_DIR}/cmake/checks/fp16.cpp"
+    COMPILE_DEFINITIONS "-DCHECK_FP16" "${FP16_OPTION}"
+    OUTPUT_VARIABLE TRY_OUT
+    )
+  if(NOT __VALID_FP16)
+    if((X86 OR X86_64) AND NOT MSVC AND NOT ENABLE_AVX)
+      # GCC enables AVX when mf16c is passed
+      message(STATUS "FP16: Feature disabled")
+    else()
+      message(STATUS "FP16: Compiler support is not available")
+    endif()
+  else()
+    message(STATUS "FP16: Compiler support is available")
+    set(HAVE_FP16 1)
+    if(NOT ${FP16_OPTION} STREQUAL "")
+      add_extra_compiler_option(${FP16_OPTION})
+    endif()
+  endif()
+endif()
+
 #combine all "extra" options
 set(CMAKE_C_FLAGS           "${CMAKE_C_FLAGS} ${OPENCV_EXTRA_FLAGS} ${OPENCV_EXTRA_C_FLAGS}")
 set(CMAKE_CXX_FLAGS         "${CMAKE_CXX_FLAGS} ${OPENCV_EXTRA_FLAGS} ${OPENCV_EXTRA_CXX_FLAGS}")
@@ -347,8 +418,13 @@ if(MSVC)
   string(REPLACE "/W3" "/W4" CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE}")
   string(REPLACE "/W3" "/W4" CMAKE_CXX_FLAGS_DEBUG   "${CMAKE_CXX_FLAGS_DEBUG}")
 
-  if(NOT ENABLE_NOISY_WARNINGS AND MSVC_VERSION EQUAL 1400)
-    ocv_warnings_disable(CMAKE_CXX_FLAGS /wd4510 /wd4610 /wd4312 /wd4201 /wd4244 /wd4328 /wd4267)
+  if(NOT ENABLE_NOISY_WARNINGS)
+    if(MSVC_VERSION EQUAL 1400)
+      ocv_warnings_disable(CMAKE_CXX_FLAGS /wd4510 /wd4610 /wd4312 /wd4201 /wd4244 /wd4328 /wd4267)
+    endif()
+    if(MSVC_VERSION LESS 1900) # MSVS2015
+      ocv_warnings_disable(CMAKE_CXX_FLAGS /wd4127) # warning C4127: conditional expression is constant
+    endif()
   endif()
 
   # allow extern "C" functions throw exceptions
@@ -365,4 +441,15 @@ if(MSVC)
     ocv_warnings_disable(CMAKE_CXX_FLAGS /wd4275) # non dll-interface class 'std::exception' used as base for dll-interface class 'cv::Exception'
     ocv_warnings_disable(CMAKE_CXX_FLAGS /wd4589) # Constructor of abstract class 'cv::ORB' ignores initializer for virtual base class 'cv::Algorithm'
   endif()
+
+  if(CV_ICC AND NOT ENABLE_NOISY_WARNINGS)
+    foreach(flags CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_RELEASE CMAKE_CXX_FLAGS_DEBUG CMAKE_C_FLAGS CMAKE_C_FLAGS_RELEASE CMAKE_C_FLAGS_DEBUG)
+      string(REGEX REPLACE "( |^)/W[0-9]+( |$)" "\\1\\2" ${flags} "${${flags}}")
+    endforeach()
+    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /Qwd673") # PCH warning
+  endif()
+endif()
+
+if(APPLE AND NOT CMAKE_CROSSCOMPILING AND NOT DEFINED ENV{LDFLAGS} AND EXISTS "/usr/local/lib")
+  link_directories("/usr/local/lib")
 endif()
diff --git a/cmake/OpenCVConfig.cmake b/cmake/OpenCVConfig.cmake
deleted file mode 100644
index 83bcb39..0000000
--- a/cmake/OpenCVConfig.cmake
+++ /dev/null
@@ -1,173 +0,0 @@
-# ===================================================================================
-#  The OpenCV CMake configuration file
-#
-#             ** File generated automatically, do not modify **
-#
-#  Usage from an external project:
-#    In your CMakeLists.txt, add these lines:
-#
-#    FIND_PACKAGE(OpenCV REQUIRED)
-#    TARGET_LINK_LIBRARIES(MY_TARGET_NAME ${OpenCV_LIBS})
-#
-#    Or you can search for specific OpenCV modules:
-#
-#    FIND_PACKAGE(OpenCV REQUIRED core imgcodecs)
-#
-#    If the module is found then OPENCV_<MODULE>_FOUND is set to TRUE.
-#
-#    This file will define the following variables:
-#      - OpenCV_LIBS                     : The list of libraries to link against.
-#      - OpenCV_LIB_DIR                  : The directory(es) where lib files are. Calling LINK_DIRECTORIES
-#                                          with this path is NOT needed.
-#      - OpenCV_INCLUDE_DIRS             : The OpenCV include directories.
-#      - OpenCV_COMPUTE_CAPABILITIES     : The version of compute capability
-#      - OpenCV_ANDROID_NATIVE_API_LEVEL : Minimum required level of Android API
-#      - OpenCV_VERSION                  : The version of this OpenCV build. Example: "2.4.0"
-#      - OpenCV_VERSION_MAJOR            : Major version part of OpenCV_VERSION. Example: "2"
-#      - OpenCV_VERSION_MINOR            : Minor version part of OpenCV_VERSION. Example: "4"
-#      - OpenCV_VERSION_PATCH            : Patch version part of OpenCV_VERSION. Example: "0"
-#
-#    Advanced variables:
-#      - OpenCV_SHARED
-#      - OpenCV_CONFIG_PATH
-#      - OpenCV_LIB_COMPONENTS
-#
-# ===================================================================================
-#
-#    Windows pack specific options:
-#      - OpenCV_STATIC
-#      - OpenCV_CUDA
-
-if(CMAKE_VERSION VERSION_GREATER 2.6)
-  get_property(OpenCV_LANGUAGES GLOBAL PROPERTY ENABLED_LANGUAGES)
-  if(NOT ";${OpenCV_LANGUAGES};" MATCHES ";CXX;")
-    enable_language(CXX)
-  endif()
-endif()
-
-if(NOT DEFINED OpenCV_STATIC)
-  # look for global setting
-  if(BUILD_SHARED_LIBS)
-    set(OpenCV_STATIC OFF)
-  else()
-    set(OpenCV_STATIC ON)
-  endif()
-endif()
-
-if(NOT DEFINED OpenCV_CUDA)
-  # if user' app uses CUDA, then it probably wants CUDA-enabled OpenCV binaries
-  if(CUDA_FOUND)
-    set(OpenCV_CUDA ON)
-  endif()
-endif()
-
-if(MSVC)
-  if(CMAKE_CL_64)
-    set(OpenCV_ARCH x64)
-    set(OpenCV_TBB_ARCH intel64)
-  elseif((CMAKE_GENERATOR MATCHES "ARM") OR ("${arch_hint}" STREQUAL "ARM") OR (CMAKE_VS_EFFECTIVE_PLATFORMS MATCHES "ARM|arm"))
-    # see Modules/CmakeGenericSystem.cmake
-    set(OpenCV_ARCH ARM)
-  else()
-    set(OpenCV_ARCH x86)
-    set(OpenCV_TBB_ARCH ia32)
-  endif()
-  if(MSVC_VERSION EQUAL 1400)
-    set(OpenCV_RUNTIME vc8)
-  elseif(MSVC_VERSION EQUAL 1500)
-    set(OpenCV_RUNTIME vc9)
-  elseif(MSVC_VERSION EQUAL 1600)
-    set(OpenCV_RUNTIME vc10)
-  elseif(MSVC_VERSION EQUAL 1700)
-    set(OpenCV_RUNTIME vc11)
-  elseif(MSVC_VERSION EQUAL 1800)
-    set(OpenCV_RUNTIME vc12)
-  elseif(MSVC_VERSION EQUAL 1900)
-    set(OpenCV_RUNTIME vc14)
-  endif()
-elseif(MINGW)
-  set(OpenCV_RUNTIME mingw)
-
-  execute_process(COMMAND ${CMAKE_CXX_COMPILER} -dumpmachine
-                  OUTPUT_VARIABLE OPENCV_GCC_TARGET_MACHINE
-                  OUTPUT_STRIP_TRAILING_WHITESPACE)
-  if(OPENCV_GCC_TARGET_MACHINE MATCHES "amd64|x86_64|AMD64")
-    set(MINGW64 1)
-    set(OpenCV_ARCH x64)
-  else()
-    set(OpenCV_ARCH x86)
-  endif()
-endif()
-
-if(CMAKE_VERSION VERSION_GREATER 2.6.2)
-  unset(OpenCV_CONFIG_PATH CACHE)
-endif()
-
-if(NOT OpenCV_FIND_QUIETLY)
-  message(STATUS "OpenCV ARCH: ${OpenCV_ARCH}")
-  message(STATUS "OpenCV RUNTIME: ${OpenCV_RUNTIME}")
-  message(STATUS "OpenCV STATIC: ${OpenCV_STATIC}")
-endif()
-
-get_filename_component(OpenCV_CONFIG_PATH "${CMAKE_CURRENT_LIST_FILE}" PATH CACHE)
-if(OpenCV_RUNTIME AND OpenCV_ARCH)
-  if(OpenCV_STATIC AND EXISTS "${OpenCV_CONFIG_PATH}/${OpenCV_ARCH}/${OpenCV_RUNTIME}/staticlib/OpenCVConfig.cmake")
-    if(OpenCV_CUDA AND EXISTS "${OpenCV_CONFIG_PATH}/gpu/${OpenCV_ARCH}/${OpenCV_RUNTIME}/staticlib/OpenCVConfig.cmake")
-      set(OpenCV_LIB_PATH "${OpenCV_CONFIG_PATH}/gpu/${OpenCV_ARCH}/${OpenCV_RUNTIME}/staticlib")
-    else()
-      set(OpenCV_LIB_PATH "${OpenCV_CONFIG_PATH}/${OpenCV_ARCH}/${OpenCV_RUNTIME}/staticlib")
-    endif()
-  elseif(EXISTS "${OpenCV_CONFIG_PATH}/${OpenCV_ARCH}/${OpenCV_RUNTIME}/lib/OpenCVConfig.cmake")
-    if(OpenCV_CUDA AND EXISTS "${OpenCV_CONFIG_PATH}/gpu/${OpenCV_ARCH}/${OpenCV_RUNTIME}/lib/OpenCVConfig.cmake")
-      set(OpenCV_LIB_PATH "${OpenCV_CONFIG_PATH}/gpu/${OpenCV_ARCH}/${OpenCV_RUNTIME}/lib")
-    else()
-      set(OpenCV_LIB_PATH "${OpenCV_CONFIG_PATH}/${OpenCV_ARCH}/${OpenCV_RUNTIME}/lib")
-    endif()
-  endif()
-endif()
-
-if(OpenCV_LIB_PATH AND EXISTS "${OpenCV_LIB_PATH}/OpenCVConfig.cmake")
-  set(OpenCV_LIB_DIR_OPT "${OpenCV_LIB_PATH}" CACHE PATH "Path where release OpenCV libraries are located" FORCE)
-  set(OpenCV_LIB_DIR_DBG "${OpenCV_LIB_PATH}" CACHE PATH "Path where debug OpenCV libraries are located" FORCE)
-  set(OpenCV_3RDPARTY_LIB_DIR_OPT "${OpenCV_LIB_PATH}" CACHE PATH "Path where release 3rdparty OpenCV dependencies are located" FORCE)
-  set(OpenCV_3RDPARTY_LIB_DIR_DBG "${OpenCV_LIB_PATH}" CACHE PATH "Path where debug 3rdparty OpenCV dependencies are located" FORCE)
-
-  include("${OpenCV_LIB_PATH}/OpenCVConfig.cmake")
-
-  if(OpenCV_CUDA)
-    set(_OpenCV_LIBS "")
-    foreach(_lib ${OpenCV_LIBS})
-      string(REPLACE "${OpenCV_CONFIG_PATH}/gpu/${OpenCV_ARCH}/${OpenCV_RUNTIME}" "${OpenCV_CONFIG_PATH}/${OpenCV_ARCH}/${OpenCV_RUNTIME}" _lib2 "${_lib}")
-      if(NOT EXISTS "${_lib}" AND EXISTS "${_lib2}")
-        list(APPEND _OpenCV_LIBS "${_lib2}")
-      else()
-        list(APPEND _OpenCV_LIBS "${_lib}")
-      endif()
-    endforeach()
-    set(OpenCV_LIBS ${_OpenCV_LIBS})
-  endif()
-  set(OpenCV_FOUND TRUE CACHE BOOL "" FORCE)
-  set(OPENCV_FOUND TRUE CACHE BOOL "" FORCE)
-
-  if(NOT OpenCV_FIND_QUIETLY)
-    message(STATUS "Found OpenCV ${OpenCV_VERSION} in ${OpenCV_LIB_PATH}")
-    if(NOT OpenCV_LIB_PATH MATCHES "/staticlib")
-      get_filename_component(_OpenCV_LIB_PATH "${OpenCV_LIB_PATH}/../bin" ABSOLUTE)
-      file(TO_NATIVE_PATH "${_OpenCV_LIB_PATH}" _OpenCV_LIB_PATH)
-      message(STATUS "You might need to add ${_OpenCV_LIB_PATH} to your PATH to be able to run your applications.")
-      if(OpenCV_LIB_PATH MATCHES "/gpu/")
-        string(REPLACE "\\gpu" "" _OpenCV_LIB_PATH2 "${_OpenCV_LIB_PATH}")
-        message(STATUS "GPU support is enabled so you might also need ${_OpenCV_LIB_PATH2} in your PATH (it must go after the ${_OpenCV_LIB_PATH}).")
-      endif()
-    endif()
-  endif()
-else()
-  if(NOT OpenCV_FIND_QUIETLY)
-    message(WARNING
-"Found OpenCV Windows Pack but it has no binaries compatible with your configuration.
-You should manually point CMake variable OpenCV_DIR to your build of OpenCV library."
-    )
-  endif()
-  set(OpenCV_FOUND FALSE CACHE BOOL "" FORCE)
-  set(OPENCV_FOUND FALSE CACHE BOOL "" FORCE)
-endif()
diff --git a/cmake/OpenCVDetectAndroidSDK.cmake b/cmake/OpenCVDetectAndroidSDK.cmake
index 58a9559..c8f7cba 100644
--- a/cmake/OpenCVDetectAndroidSDK.cmake
+++ b/cmake/OpenCVDetectAndroidSDK.cmake
@@ -287,7 +287,7 @@ macro(add_android_project target path)
           set(android_proj_NATIVE_DEPS ${android_proj_NATIVE_DEPS} android)
         endif()
 
-        add_library(${JNI_LIB_NAME} MODULE ${android_proj_jni_files})
+        add_library(${JNI_LIB_NAME} SHARED ${android_proj_jni_files})
         ocv_target_include_modules_recurse(${JNI_LIB_NAME} ${android_proj_NATIVE_DEPS})
         ocv_target_include_directories(${JNI_LIB_NAME} "${path}/jni")
         ocv_target_link_libraries(${JNI_LIB_NAME} ${OPENCV_LINKER_LIBS} ${android_proj_NATIVE_DEPS})
diff --git a/cmake/OpenCVDetectCUDA.cmake b/cmake/OpenCVDetectCUDA.cmake
index c1cb958..3116d9f 100644
--- a/cmake/OpenCVDetectCUDA.cmake
+++ b/cmake/OpenCVDetectCUDA.cmake
@@ -33,12 +33,17 @@ if(CUDA_FOUND)
     if(WIN32)
       find_cuda_helper_libs(nvcuvenc)
     endif()
-    set(HAVE_NVCUVID 1)
+    if(CUDA_nvcuvid_LIBRARY)
+      set(HAVE_NVCUVID 1)
+    endif()
+    if(CUDA_nvcuvenc_LIBRARY)
+      set(HAVE_NVCUVENC 1)
+    endif()
   endif()
 
   message(STATUS "CUDA detected: " ${CUDA_VERSION})
 
-  set(_generations "Fermi" "Kepler")
+  set(_generations "Fermi" "Kepler" "Maxwell" "Pascal")
   if(NOT CMAKE_CROSSCOMPILING)
     list(APPEND _generations "Auto")
   endif()
@@ -58,13 +63,13 @@ if(CUDA_FOUND)
 
   set(__cuda_arch_ptx "")
   if(CUDA_GENERATION STREQUAL "Fermi")
-    set(__cuda_arch_bin "2.0 2.1(2.0)")
+    set(__cuda_arch_bin "2.0")
   elseif(CUDA_GENERATION STREQUAL "Kepler")
-    if(${CUDA_VERSION} VERSION_LESS "5.0")
-      set(__cuda_arch_bin "3.0")
-    else()
-      set(__cuda_arch_bin "3.0 3.5")
-    endif()
+    set(__cuda_arch_bin "3.0 3.5 3.7")
+  elseif(CUDA_GENERATION STREQUAL "Maxwell")
+    set(__cuda_arch_bin "5.0 5.2")
+  elseif(CUDA_GENERATION STREQUAL "Pascal")
+    set(__cuda_arch_bin "6.0 6.1")
   elseif(CUDA_GENERATION STREQUAL "Auto")
     execute_process( COMMAND "${CUDA_NVCC_EXECUTABLE}" "${OpenCV_SOURCE_DIR}/cmake/checks/OpenCVDetectCudaArch.cu" "--run"
                      WORKING_DIRECTORY "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/"
@@ -86,14 +91,12 @@ if(CUDA_FOUND)
       set(__cuda_arch_bin "5.3")
       set(__cuda_arch_ptx "")
     else()
-      if(${CUDA_VERSION} VERSION_LESS "5.0")
-        set(__cuda_arch_bin "1.1 1.2 1.3 2.0 2.1(2.0) 3.0")
-      elseif(${CUDA_VERSION} VERSION_GREATER "6.5")
-        set(__cuda_arch_bin "2.0 2.1(2.0) 3.0 3.5")
+      if(${CUDA_VERSION} VERSION_LESS "8.0")
+        set(__cuda_arch_bin "2.0 3.0 3.5 3.7 5.0 5.2")
       else()
-        set(__cuda_arch_bin "1.1 1.2 1.3 2.0 2.1(2.0) 3.0 3.5")
+        set(__cuda_arch_bin "2.0 3.0 3.5 3.7 5.0 5.2 6.0 6.1")
       endif()
-      set(__cuda_arch_ptx "3.0")
+      set(__cuda_arch_ptx "")
     endif()
   endif()
 
@@ -133,6 +136,7 @@ if(CUDA_FOUND)
       set(OPENCV_CUDA_ARCH_FEATURES "${OPENCV_CUDA_ARCH_FEATURES} ${ARCH}")
     endif()
   endforeach()
+  set(NVCC_FLAGS_EXTRA ${NVCC_FLAGS_EXTRA} -D_FORCE_INLINES)
 
   # Tell NVCC to add PTX intermediate code for the specified architectures
   string(REGEX MATCHALL "[0-9]+" ARCH_LIST "${ARCH_PTX_NO_POINTS}")
@@ -160,7 +164,7 @@ if(CUDA_FOUND)
 
   mark_as_advanced(CUDA_BUILD_CUBIN CUDA_BUILD_EMULATION CUDA_VERBOSE_BUILD CUDA_SDK_ROOT_DIR)
 
-  macro(ocv_cuda_compile VAR)
+  macro(ocv_cuda_filter_options)
     foreach(var CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_RELEASE CMAKE_CXX_FLAGS_DEBUG)
       set(${var}_backup_in_cuda_compile_ "${${var}}")
 
@@ -186,6 +190,10 @@ if(CUDA_FOUND)
 
       string(REPLACE "-fvisibility-inlines-hidden" "" ${var} "${${var}}")
     endforeach()
+  endmacro()
+
+  macro(ocv_cuda_compile VAR)
+    ocv_cuda_filter_options()
 
     if(BUILD_SHARED_LIBS)
       set(CUDA_NVCC_FLAGS ${CUDA_NVCC_FLAGS} -Xcompiler -DCVAPI_EXPORTS)
diff --git a/cmake/OpenCVDetectCXXCompiler.cmake b/cmake/OpenCVDetectCXXCompiler.cmake
index 5cf4c85..8ecf4d8 100644
--- a/cmake/OpenCVDetectCXXCompiler.cmake
+++ b/cmake/OpenCVDetectCXXCompiler.cmake
@@ -17,10 +17,6 @@ if("${CMAKE_CXX_COMPILER};${CMAKE_C_COMPILER}" MATCHES "ccache")
   set(CMAKE_COMPILER_IS_CCACHE 1)
 endif()
 
-if((CMAKE_COMPILER_IS_CLANGCXX OR CMAKE_COMPILER_IS_CLANGCC OR CMAKE_COMPILER_IS_CCACHE) AND NOT CMAKE_GENERATOR MATCHES "Xcode")
-  set(ENABLE_PRECOMPILED_HEADERS OFF CACHE BOOL "" FORCE)
-endif()
-
 # ----------------------------------------------------------------------------
 # Detect Intel ICC compiler -- for -fPIC in 3rdparty ( UNIX ONLY ):
 #  see  include/opencv/cxtypes.h file for related   ICC & CV_ICC defines.
@@ -45,7 +41,7 @@ if(UNIX)
   endif()
 endif()
 
-if(MSVC AND CMAKE_C_COMPILER MATCHES "icc")
+if(MSVC AND CMAKE_C_COMPILER MATCHES "icc|icl")
   set(CV_ICC   __INTEL_COMPILER_FOR_WINDOWS)
 endif()
 
@@ -164,6 +160,8 @@ if(MSVC)
     set(OpenCV_RUNTIME vc12)
   elseif(MSVC_VERSION EQUAL 1900)
     set(OpenCV_RUNTIME vc14)
+  elseif(MSVC_VERSION EQUAL 1910)
+    set(OpenCV_RUNTIME vc15)
   endif()
 elseif(MINGW)
   set(OpenCV_RUNTIME mingw)
diff --git a/cmake/OpenCVDetectOpenCL.cmake b/cmake/OpenCVDetectOpenCL.cmake
index 67e10ed..433f244 100644
--- a/cmake/OpenCVDetectOpenCL.cmake
+++ b/cmake/OpenCVDetectOpenCL.cmake
@@ -1,21 +1,21 @@
+set(OPENCL_FOUND ON CACHE BOOL "OpenCL library is found")
 if(APPLE)
-  set(OPENCL_FOUND YES)
   set(OPENCL_LIBRARY "-framework OpenCL" CACHE STRING "OpenCL library")
-  set(OPENCL_INCLUDE_DIR "" CACHE STRING "OpenCL include directory")
-  mark_as_advanced(OPENCL_INCLUDE_DIR OPENCL_LIBRARY)
-  set(HAVE_OPENCL_STATIC ON)
+  set(OPENCL_INCLUDE_DIR "" CACHE PATH "OpenCL include directory")
 else(APPLE)
-  set(OPENCL_FOUND YES)
-  set(HAVE_OPENCL_STATIC OFF)
-  set(OPENCL_INCLUDE_DIR "${OpenCV_SOURCE_DIR}/3rdparty/include/opencl/1.2")
+  set(OPENCL_LIBRARY "" CACHE STRING "OpenCL library")
+  set(OPENCL_INCLUDE_DIR "${OpenCV_SOURCE_DIR}/3rdparty/include/opencl/1.2" CACHE PATH "OpenCL include directory")
 endif(APPLE)
-
-if(WINRT)
-  set(OPENCL_FOUND NO)
-  set(HAVE_OPENCL_STATIC OFF)
-endif(WINRT)
+mark_as_advanced(OPENCL_INCLUDE_DIR OPENCL_LIBRARY)
 
 if(OPENCL_FOUND)
+  if(OPENCL_LIBRARY)
+    set(HAVE_OPENCL_STATIC ON)
+    set(OPENCL_LIBRARIES "${OPENCL_LIBRARY}")
+  else()
+    set(HAVE_OPENCL_STATIC OFF)
+  endif()
+
   if(NOT HAVE_OPENCL_STATIC)
     try_compile(__VALID_OPENCL
       "${OpenCV_BINARY_DIR}"
@@ -29,20 +29,12 @@ if(OPENCL_FOUND)
     endif()
   endif()
 
-  if(NOT WINRT)
-    set(HAVE_OPENCL 1)
-  endif()
+  set(HAVE_OPENCL 1)
 
   if(WITH_OPENCL_SVM)
     set(HAVE_OPENCL_SVM 1)
   endif()
 
-  if(HAVE_OPENCL_STATIC)
-    set(OPENCL_LIBRARIES "${OPENCL_LIBRARY}")
-  else()
-    unset(OPENCL_LIBRARIES)
-  endif()
-
   set(OPENCL_INCLUDE_DIRS ${OPENCL_INCLUDE_DIR})
 
   if(WITH_OPENCLAMDFFT)
diff --git a/cmake/OpenCVDetectPython.cmake b/cmake/OpenCVDetectPython.cmake
index 9493133..6dec76f 100644
--- a/cmake/OpenCVDetectPython.cmake
+++ b/cmake/OpenCVDetectPython.cmake
@@ -26,7 +26,7 @@ function(find_python preferred_version min_version library_env include_dir_env
          libs_found libs_version_string libraries library debug_libraries
          debug_library include_path include_dir include_dir2 packages_path
          numpy_include_dirs numpy_version)
-
+if(NOT ${found})
   ocv_check_environment_variables(${executable})
   if(${executable})
     set(PYTHON_EXECUTABLE "${${executable}}")
@@ -47,19 +47,24 @@ function(find_python preferred_version min_version library_env include_dir_env
     endforeach()
   endif()
 
+  string(REGEX MATCH "^[0-9]+" _preferred_version_major ${preferred_version})
+
   find_host_package(PythonInterp "${preferred_version}")
   if(NOT PYTHONINTERP_FOUND)
     find_host_package(PythonInterp "${min_version}")
   endif()
 
   if(PYTHONINTERP_FOUND)
-    # Copy outputs
-    set(_found ${PYTHONINTERP_FOUND})
-    set(_executable ${PYTHON_EXECUTABLE})
-    set(_version_string ${PYTHON_VERSION_STRING})
-    set(_version_major ${PYTHON_VERSION_MAJOR})
-    set(_version_minor ${PYTHON_VERSION_MINOR})
-    set(_version_patch ${PYTHON_VERSION_PATCH})
+    # Check if python major version is correct
+    if(${_preferred_version_major} EQUAL ${PYTHON_VERSION_MAJOR})
+      # Copy outputs
+      set(_found ${PYTHONINTERP_FOUND})
+      set(_executable ${PYTHON_EXECUTABLE})
+      set(_version_string ${PYTHON_VERSION_STRING})
+      set(_version_major ${PYTHON_VERSION_MAJOR})
+      set(_version_minor ${PYTHON_VERSION_MINOR})
+      set(_version_patch ${PYTHON_VERSION_PATCH})
+    endif()
 
     # Clear find_host_package side effects
     unset(PYTHONINTERP_FOUND)
@@ -75,10 +80,10 @@ function(find_python preferred_version min_version library_env include_dir_env
 
     if(NOT ANDROID AND NOT APPLE_FRAMEWORK)
       ocv_check_environment_variables(${library_env} ${include_dir_env})
-      if(NOT ${${library_env}} EQUAL "")
+      if(NOT ${${library_env}} STREQUAL "")
           set(PYTHON_LIBRARY "${${library_env}}")
       endif()
-      if(NOT ${${include_dir_env}} EQUAL "")
+      if(NOT ${${include_dir_env}} STREQUAL "")
           set(PYTHON_INCLUDE_DIR "${${include_dir_env}}")
       endif()
 
@@ -162,10 +167,10 @@ function(find_python preferred_version min_version library_env include_dir_env
           message(STATUS "Cannot probe for Python/Numpy support (because we are cross-compiling OpenCV)")
           message(STATUS "If you want to enable Python/Numpy support, set the following variables:")
           message(STATUS "  PYTHON2_INCLUDE_PATH")
-          message(STATUS "  PYTHON2_LIBRARIES")
+          message(STATUS "  PYTHON2_LIBRARIES (optional on Unix-like systems)")
           message(STATUS "  PYTHON2_NUMPY_INCLUDE_DIRS")
           message(STATUS "  PYTHON3_INCLUDE_PATH")
-          message(STATUS "  PYTHON3_LIBRARIES")
+          message(STATUS "  PYTHON3_LIBRARIES (optional on Unix-like systems)")
           message(STATUS "  PYTHON3_NUMPY_INCLUDE_DIRS")
         else()
           # Attempt to discover the NumPy include directory. If this succeeds, then build python API with NumPy
@@ -197,23 +202,24 @@ function(find_python preferred_version min_version library_env include_dir_env
   endif()
 
   # Export return values
-  set(${found} "${_found}" PARENT_SCOPE)
+  set(${found} "${_found}" CACHE INTERNAL "")
   set(${executable} "${_executable}" CACHE FILEPATH "Path to Python interpretor")
-  set(${version_string} "${_version_string}" PARENT_SCOPE)
-  set(${version_major} "${_version_major}" PARENT_SCOPE)
-  set(${version_minor} "${_version_minor}" PARENT_SCOPE)
-  set(${libs_found} "${_libs_found}" PARENT_SCOPE)
-  set(${libs_version_string} "${_libs_version_string}" PARENT_SCOPE)
-  set(${libraries} "${_libraries}" PARENT_SCOPE)
+  set(${version_string} "${_version_string}" CACHE INTERNAL "")
+  set(${version_major} "${_version_major}" CACHE INTERNAL "")
+  set(${version_minor} "${_version_minor}" CACHE INTERNAL "")
+  set(${libs_found} "${_libs_found}" CACHE INTERNAL "")
+  set(${libs_version_string} "${_libs_version_string}" CACHE INTERNAL "")
+  set(${libraries} "${_libraries}" CACHE INTERNAL "Python libraries")
   set(${library} "${_library}" CACHE FILEPATH "Path to Python library")
-  set(${debug_libraries} "${_debug_libraries}" PARENT_SCOPE)
+  set(${debug_libraries} "${_debug_libraries}" CACHE INTERNAL "")
   set(${debug_library} "${_debug_library}" CACHE FILEPATH "Path to Python debug")
-  set(${include_path} "${_include_path}" PARENT_SCOPE)
+  set(${include_path} "${_include_path}" CACHE INTERNAL "")
   set(${include_dir} "${_include_dir}" CACHE PATH "Python include dir")
   set(${include_dir2} "${_include_dir2}" CACHE PATH "Python include dir 2")
   set(${packages_path} "${_packages_path}" CACHE PATH "Where to install the python packages.")
   set(${numpy_include_dirs} ${_numpy_include_dirs} CACHE PATH "Path to numpy headers")
-  set(${numpy_version} "${_numpy_version}" PARENT_SCOPE)
+  set(${numpy_version} "${_numpy_version}" CACHE INTERNAL "")
+endif()
 endfunction(find_python)
 
 find_python(2.7 "${MIN_VER_PYTHON2}" PYTHON2_LIBRARY PYTHON2_INCLUDE_DIR
@@ -238,7 +244,7 @@ if(PYTHON_DEFAULT_EXECUTABLE)
 elseif(PYTHON2INTERP_FOUND) # Use Python 2 as default Python interpreter
     set(PYTHON_DEFAULT_AVAILABLE "TRUE")
     set(PYTHON_DEFAULT_EXECUTABLE "${PYTHON2_EXECUTABLE}")
-elseif(PYTHON3INTERP_FOUND) # Use Python 2 as fallback Python interpreter (if there is no Python 2)
+elseif(PYTHON3INTERP_FOUND) # Use Python 3 as fallback Python interpreter (if there is no Python 2)
     set(PYTHON_DEFAULT_AVAILABLE "TRUE")
     set(PYTHON_DEFAULT_EXECUTABLE "${PYTHON3_EXECUTABLE}")
 endif()
diff --git a/cmake/OpenCVDetectTBB.cmake b/cmake/OpenCVDetectTBB.cmake
index 6e7493f..89e4970 100644
--- a/cmake/OpenCVDetectTBB.cmake
+++ b/cmake/OpenCVDetectTBB.cmake
@@ -1,92 +1,85 @@
-if(BUILD_TBB)
-  add_subdirectory("${OpenCV_SOURCE_DIR}/3rdparty/tbb")
-  include_directories(SYSTEM ${TBB_INCLUDE_DIRS})
-  set(OPENCV_LINKER_LIBS ${OPENCV_LINKER_LIBS} tbb)
-  add_definitions(-DTBB_USE_GCC_BUILTINS=1 -D__TBB_GCC_BUILTIN_ATOMICS_PRESENT=1)
-  if(tbb_need_GENERIC_DWORD_LOAD_STORE)
-    add_definitions(-D__TBB_USE_GENERIC_DWORD_LOAD_STORE=1)
-  endif()
-  set(HAVE_TBB 1)
-elseif(UNIX AND NOT APPLE)
-  PKG_CHECK_MODULES(TBB tbb)
+# Search TBB library (4.1 - 4.4, 2017)
+#
+# Own TBB (3rdparty/tbb):
+# - set cmake option BUILD_TBB to ON
+#
+# External TBB (from system):
+# - Fedora: install 'tbb-devel' package
+# - Ubuntu: install 'libtbb-dev' package
+#
+# External TBB (from official site):
+# - Linux/OSX:
+#   - in tbbvars.sh replace 'SUBSTITUTE_INSTALL_DIR_HERE' with absolute path to TBB dir
+#   - in terminal run 'source tbbvars.sh intel64 linux' ('source tbbvars.sh' in OSX)
+# - Windows:
+#   - in terminal run 'tbbvars.bat intel64 vs2015'
+#
+# Return:
+#   - HAVE_TBB set to TRUE
+#   - "tbb" target exists and added to OPENCV_LINKER_LIBS
 
-  if(TBB_FOUND)
-    set(HAVE_TBB 1)
-    if(NOT ${TBB_INCLUDE_DIRS} STREQUAL "")
-      ocv_include_directories(${TBB_INCLUDE_DIRS})
+function(ocv_tbb_verify)
+  if (NOT "$ENV{TBBROOT}" STREQUAL "")
+    # check that library and include dir are inside TBBROOT location
+    get_filename_component(_root "$ENV{TBBROOT}" ABSOLUTE)
+    get_filename_component(_lib "${TBB_ENV_LIB}" ABSOLUTE)
+    get_filename_component(_inc "${TBB_ENV_INCLUDE}" ABSOLUTE)
+    string(FIND "${_lib}" "${_root}" _lib_pos)
+    string(FIND "${_inc}" "${_root}" _inc_pos)
+    if (NOT (_lib_pos EQUAL 0 AND _inc_pos EQUAL 0))
+      message(SEND_ERROR
+        "Possible issue with TBB detection - TBBROOT is set, "
+        "but library/include path is not inside it:\n "
+        "TBBROOT: $ENV{TBBROOT}\n "
+        "(absolute): ${_root}\n "
+        "INCLUDE: ${_inc}\n "
+        "LIBRARY: ${_lib}\n")
     endif()
-    link_directories(${TBB_LIBRARY_DIRS})
-    set(OPENCV_LINKER_LIBS ${OPENCV_LINKER_LIBS} ${TBB_LIBRARIES})
   endif()
-endif()
+endfunction()
 
-if(NOT HAVE_TBB)
-  set(TBB_DEFAULT_INCLUDE_DIRS
-    "/opt/intel/tbb/include" "/usr/local/include" "/usr/include"
-    "C:/Program Files/Intel/TBB" "C:/Program Files (x86)/Intel/TBB"
-    "C:/Program Files/tbb/include"
-    "C:/Program Files (x86)/tbb/include"
-    "${CMAKE_INSTALL_PREFIX}/include")
+function(ocv_tbb_env_guess _found)
+  find_path(TBB_ENV_INCLUDE NAMES "tbb/tbb.h" PATHS ENV CPATH NO_DEFAULT_PATH)
+  find_path(TBB_ENV_INCLUDE NAMES "tbb/tbb.h")
+  find_library(TBB_ENV_LIB NAMES "tbb" PATHS ENV LIBRARY_PATH ENV LD_LIBRARY_PATH NO_DEFAULT_PATH)
+  find_library(TBB_ENV_LIB NAMES "tbb")
+  find_library(TBB_ENV_LIB_DEBUG NAMES "tbb_debug" PATHS ENV LIBRARY_PATH ENV LD_LIBRARY_PATH NO_DEFAULT_PATH)
+  find_library(TBB_ENV_LIB_DEBUG NAMES "tbb_debug")
+  if (TBB_ENV_INCLUDE AND TBB_ENV_LIB)
+    ocv_tbb_verify()
+    ocv_tbb_read_version("${TBB_ENV_INCLUDE}")
+    add_library(tbb UNKNOWN IMPORTED)
+    set_target_properties(tbb PROPERTIES
+      IMPORTED_LOCATION "${TBB_ENV_LIB}"
+      IMPORTED_LOCATION_DEBUG "${TBB_ENV_LIB_DEBUG}"
+      INTERFACE_INCLUDE_DIRECTORIES "${TBB_ENV_INCLUDE}"
+    )
+    message(STATUS "Found TBB: ${TBB_ENV_LIB}")
+    set(${_found} TRUE PARENT_SCOPE)
+  endif()
+endfunction()
 
-  find_path(TBB_INCLUDE_DIRS "tbb/tbb.h" PATHS ${TBB_INCLUDE_DIR} ${TBB_DEFAULT_INCLUDE_DIRS} DOC "The path to TBB headers")
-  if(TBB_INCLUDE_DIRS)
-    if(UNIX)
-      set(TBB_LIB_DIR "${TBB_INCLUDE_DIRS}/../lib" CACHE PATH "Full path of TBB library directory")
-      link_directories("${TBB_LIB_DIR}")
-    endif()
-    if(APPLE)
-      set(OPENCV_LINKER_LIBS ${OPENCV_LINKER_LIBS} libtbb.dylib)
-    elseif(ANDROID)
-      set(OPENCV_LINKER_LIBS ${OPENCV_LINKER_LIBS}  tbb)
-      add_definitions(-DTBB_USE_GCC_BUILTINS)
-    elseif (UNIX)
-      set(OPENCV_LINKER_LIBS ${OPENCV_LINKER_LIBS} tbb)
-    elseif (WIN32)
-      if(CMAKE_COMPILER_IS_GNUCXX)
-        set(TBB_LIB_DIR "${TBB_INCLUDE_DIRS}/../lib" CACHE PATH "Full path of TBB library directory")
-        link_directories("${TBB_LIB_DIR}")
-        set(OPENCV_LINKER_LIBS ${OPENCV_LINKER_LIBS} tbb)
-      else()
-        get_filename_component(_TBB_LIB_PATH "${TBB_INCLUDE_DIRS}/../lib" ABSOLUTE)
+function(ocv_tbb_read_version _path)
+  find_file(TBB_VER_FILE tbb/tbb_stddef.h "${_path}" NO_DEFAULT_PATH CMAKE_FIND_ROOT_PATH_BOTH)
+  ocv_parse_header("${TBB_VER_FILE}" TBB_VERSION_LINES TBB_VERSION_MAJOR TBB_VERSION_MINOR TBB_INTERFACE_VERSION CACHE)
+endfunction()
 
-        if(CMAKE_SYSTEM_PROCESSOR MATCHES amd64*|x86_64* OR MSVC64)
-          set(_TBB_LIB_PATH "${_TBB_LIB_PATH}/intel64")
-        else()
-          set(_TBB_LIB_PATH "${_TBB_LIB_PATH}/ia32")
-        endif()
+#=====================================================================
 
-        if(MSVC80)
-          set(_TBB_LIB_PATH "${_TBB_LIB_PATH}/vc8")
-        elseif(MSVC90)
-          set(_TBB_LIB_PATH "${_TBB_LIB_PATH}/vc9")
-        elseif(MSVC10)
-          set(_TBB_LIB_PATH "${_TBB_LIB_PATH}/vc10")
-        elseif(MSVC11)
-          set(_TBB_LIB_PATH "${_TBB_LIB_PATH}/vc11")
-        elseif(MSVC12)
-          set(_TBB_LIB_PATH "${_TBB_LIB_PATH}/vc12")
-        endif()
-        set(TBB_LIB_DIR "${_TBB_LIB_PATH}" CACHE PATH "Full path of TBB library directory")
-        link_directories("${TBB_LIB_DIR}")
-      endif()
-    endif()
+if(BUILD_TBB)
+  add_subdirectory("${OpenCV_SOURCE_DIR}/3rdparty/tbb")
+  message(STATUS "Found TBB: build")
+  set(HAVE_TBB TRUE)
+endif()
 
-    set(HAVE_TBB 1)
-    if(NOT "${TBB_INCLUDE_DIRS}" STREQUAL "")
-      ocv_include_directories("${TBB_INCLUDE_DIRS}")
-    endif()
-  endif(TBB_INCLUDE_DIRS)
-endif(NOT HAVE_TBB)
+if(NOT HAVE_TBB)
+  ocv_tbb_env_guess(HAVE_TBB)
+endif()
 
-# get TBB version
-if(HAVE_TBB)
-  find_file(TBB_STDDEF_PATH tbb/tbb_stddef.h "${TBB_INCLUDE_DIRS}")
-  mark_as_advanced(TBB _STDDEF_PATH)
+if(TBB_INTERFACE_VERSION LESS 6000) # drop support of versions < 4.0
+  set(HAVE_TBB FALSE)
 endif()
-if(HAVE_TBB AND TBB_STDDEF_PATH)
-  ocv_parse_header("${TBB_STDDEF_PATH}" TBB_VERSION_LINES TBB_VERSION_MAJOR TBB_VERSION_MINOR TBB_INTERFACE_VERSION)
-else()
-  unset(TBB_VERSION_MAJOR)
-  unset(TBB_VERSION_MINOR)
-  unset(TBB_INTERFACE_VERSION)
+
+if(HAVE_TBB)
+  list(APPEND OPENCV_LINKER_LIBS tbb)
 endif()
diff --git a/cmake/OpenCVDetectVTK.cmake b/cmake/OpenCVDetectVTK.cmake
index 66dcdd0..c92174f 100644
--- a/cmake/OpenCVDetectVTK.cmake
+++ b/cmake/OpenCVDetectVTK.cmake
@@ -3,7 +3,14 @@ if(NOT WITH_VTK)
 endif()
 
 # VTK 6.x components
-find_package(VTK QUIET COMPONENTS vtkRenderingOpenGL vtkInteractionStyle vtkRenderingLOD vtkIOPLY vtkFiltersTexture vtkRenderingFreeType vtkIOExport NO_MODULE)
+find_package(VTK QUIET COMPONENTS vtkInteractionStyle vtkRenderingLOD vtkIOPLY vtkFiltersTexture vtkRenderingFreeType vtkIOExport NO_MODULE)
+IF(VTK_FOUND)
+  IF(VTK_RENDERING_BACKEND) #in vtk 7, the rendering backend is exported as a var.
+      find_package(VTK QUIET COMPONENTS vtkRendering${VTK_RENDERING_BACKEND} vtkInteractionStyle vtkRenderingLOD vtkIOPLY vtkFiltersTexture vtkRenderingFreeType vtkIOExport vtkIOGeometry NO_MODULE)
+  ELSE(VTK_RENDERING_BACKEND)
+      find_package(VTK QUIET COMPONENTS vtkRenderingOpenGL vtkInteractionStyle vtkRenderingLOD vtkIOPLY vtkFiltersTexture vtkRenderingFreeType vtkIOExport NO_MODULE)
+  ENDIF(VTK_RENDERING_BACKEND)
+ENDIF(VTK_FOUND)
 
 # VTK 5.x components
 if(NOT VTK_FOUND)
diff --git a/cmake/OpenCVFindAtlas.cmake b/cmake/OpenCVFindAtlas.cmake
new file mode 100644
index 0000000..4fc7317
--- /dev/null
+++ b/cmake/OpenCVFindAtlas.cmake
@@ -0,0 +1,97 @@
+#COPYRIGHT
+#
+#All contributions by the University of California:
+#Copyright (c) 2014, 2015, The Regents of the University of California (Regents)
+#All rights reserved.
+#
+#All other contributions:
+#Copyright (c) 2014, 2015, the respective contributors
+#All rights reserved.
+#
+#Caffe uses a shared copyright model: each contributor holds copyright over
+#their contributions to Caffe. The project versioning records all such
+#contribution and copyright details. If a contributor wants to further mark
+#their specific copyright on a particular contribution, they should indicate
+#their copyright solely in the commit message of the change when it is
+#committed.
+#
+#LICENSE
+#
+#Redistribution and use in source and binary forms, with or without
+#modification, are permitted provided that the following conditions are met:
+#
+#1. Redistributions of source code must retain the above copyright notice, this
+#   list of conditions and the following disclaimer.
+#2. Redistributions in binary form must reproduce the above copyright notice,
+#   this list of conditions and the following disclaimer in the documentation
+#   and/or other materials provided with the distribution.
+#
+#THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+#ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+#WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+#DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+#ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+#(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+#LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+#ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+#(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+#SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+#CONTRIBUTION AGREEMENT
+#
+#By contributing to the BVLC/caffe repository through pull-request, comment,
+#or otherwise, the contributor releases their content to the
+#license and copyright terms herein.
+
+
+# Find the Atlas (and Lapack) libraries
+#
+# The following variables are optionally searched for defaults
+#  Atlas_ROOT_DIR:            Base directory where all Atlas components are found
+#
+# The following are set after configuration is done:
+#  Atlas_FOUND
+#  Atlas_INCLUDE_DIRS
+#  Atlas_LIBRARIES
+#  Atlas_LIBRARYRARY_DIRS
+
+set(Atlas_INCLUDE_SEARCH_PATHS
+  /usr/include/atlas
+  /usr/include/atlas-base
+  $ENV{Atlas_ROOT_DIR}
+  $ENV{Atlas_ROOT_DIR}/include
+)
+
+set(Atlas_LIB_SEARCH_PATHS
+  /usr/lib/atlas
+  /usr/lib/atlas-base
+  $ENV{Atlas_ROOT_DIR}
+  $ENV{Atlas_ROOT_DIR}/lib
+)
+
+find_path(Atlas_CBLAS_INCLUDE_DIR   NAMES cblas.h   PATHS ${Atlas_INCLUDE_SEARCH_PATHS})
+find_path(Atlas_CLAPACK_INCLUDE_DIR NAMES lapacke.h PATHS ${Atlas_INCLUDE_SEARCH_PATHS})
+
+find_library(Atlas_CBLAS_LIBRARY NAMES  ptcblas_r ptcblas cblas_r cblas PATHS ${Atlas_LIB_SEARCH_PATHS})
+find_library(Atlas_BLAS_LIBRARY NAMES   atlas_r   atlas                 PATHS ${Atlas_LIB_SEARCH_PATHS})
+find_library(Atlas_LAPACK_LIBRARY NAMES lapack alapack_r alapack lapack_atlas  PATHS ${Atlas_LIB_SEARCH_PATHS})
+
+set(LOOKED_FOR
+  Atlas_CBLAS_INCLUDE_DIR
+  Atlas_CLAPACK_INCLUDE_DIR
+
+  Atlas_CBLAS_LIBRARY
+  Atlas_BLAS_LIBRARY
+  Atlas_LAPACK_LIBRARY
+)
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(Atlas DEFAULT_MSG ${LOOKED_FOR})
+
+if(ATLAS_FOUND)
+  set(Atlas_INCLUDE_DIR ${Atlas_CBLAS_INCLUDE_DIR} ${Atlas_CLAPACK_INCLUDE_DIR})
+  set(Atlas_LIBRARIES ${Atlas_LAPACK_LIBRARY} ${Atlas_CBLAS_LIBRARY} ${Atlas_BLAS_LIBRARY})
+  mark_as_advanced(${LOOKED_FOR})
+
+  message(STATUS "Found Atlas (include: ${Atlas_CBLAS_INCLUDE_DIR}, library: ${Atlas_BLAS_LIBRARY})")
+endif(ATLAS_FOUND)
\ No newline at end of file
diff --git a/cmake/OpenCVFindIPP.cmake b/cmake/OpenCVFindIPP.cmake
index 3bff766..6913052 100644
--- a/cmake/OpenCVFindIPP.cmake
+++ b/cmake/OpenCVFindIPP.cmake
@@ -146,7 +146,7 @@ macro(ipp_detect_version)
           IMPORTED_LOCATION ${IPP_LIBRARY_DIR}/${IPP_LIB_PREFIX}${IPP_PREFIX}${name}${IPP_SUFFIX}${IPP_LIB_SUFFIX}
         )
         list(APPEND IPP_LIBRARIES ipp${name})
-        if (NOT BUILD_SHARED_LIBS OR NOT INSTALL_CREATE_DISTRIB)
+        if (NOT BUILD_SHARED_LIBS)
           # CMake doesn't support "install(TARGETS ${IPP_PREFIX}${name} " command with imported targets
           install(FILES ${IPP_LIBRARY_DIR}/${IPP_LIB_PREFIX}${IPP_PREFIX}${name}${IPP_SUFFIX}${IPP_LIB_SUFFIX}
                   DESTINATION ${OPENCV_3P_LIB_INSTALL_PATH} COMPONENT dev)
@@ -234,6 +234,12 @@ if(DEFINED ENV{OPENCV_IPP_PATH} AND NOT DEFINED IPPROOT)
   set(IPPROOT "$ENV{OPENCV_IPP_PATH}")
 endif()
 if(NOT DEFINED IPPROOT)
+  if(IOS AND NOT x86_64)
+    # 2016/10: There is an issue with MacOS binary .a file.
+    # It is fat multiarch library, and can't be "merged" multiple times.
+    # So try to ignore i386 version
+    return()
+  endif()
   include("${OpenCV_SOURCE_DIR}/3rdparty/ippicv/downloader.cmake")
   if(DEFINED OPENCV_ICV_PATH)
     set(IPPROOT "${OPENCV_ICV_PATH}")
diff --git a/cmake/OpenCVFindLAPACK.cmake b/cmake/OpenCVFindLAPACK.cmake
new file mode 100644
index 0000000..dfacf24
--- /dev/null
+++ b/cmake/OpenCVFindLAPACK.cmake
@@ -0,0 +1,78 @@
+macro(_find_file_in_dirs VAR NAME DIRS)
+    find_path(${VAR} ${NAME} ${DIRS} NO_DEFAULT_PATH)
+    set(${VAR} ${${VAR}}/${NAME})
+    unset(${VAR} CACHE)
+endmacro()
+
+if(WITH_LAPACK)
+    ocv_update(LAPACK_IMPL "Unknown")
+    if(NOT LAPACK_LIBRARIES)
+        include(cmake/OpenCVFindMKL.cmake)
+        if(HAVE_MKL)
+            set(LAPACK_INCLUDE_DIR  ${MKL_INCLUDE_DIRS})
+            set(LAPACK_LIBRARIES    ${MKL_LIBRARIES}   )
+            set(LAPACK_CBLAS_H      "mkl_cblas.h"      )
+            set(LAPACK_LAPACKE_H    "mkl_lapack.h"    )
+            set(LAPACK_IMPL         "MKL")
+        endif()
+    endif()
+    if(NOT LAPACK_LIBRARIES)
+        include(cmake/OpenCVFindOpenBLAS.cmake)
+        if(OpenBLAS_FOUND)
+            set(LAPACK_INCLUDE_DIR  ${OpenBLAS_INCLUDE_DIR} )
+            set(LAPACK_LIBRARIES    ${OpenBLAS_LIB}         )
+            set(LAPACK_CBLAS_H      "cblas.h"      )
+            set(LAPACK_LAPACKE_H    "lapacke.h"    )
+            set(LAPACK_IMPL         "OpenBLAS")
+        endif()
+    endif()
+    if(NOT LAPACK_LIBRARIES AND UNIX)
+        include(cmake/OpenCVFindAtlas.cmake)
+        if(ATLAS_FOUND)
+            set(LAPACK_INCLUDE_DIR  ${Atlas_INCLUDE_DIR})
+            set(LAPACK_LIBRARIES    ${Atlas_LIBRARIES}  )
+            set(LAPACK_CBLAS_H      "cblas.h"      )
+            set(LAPACK_LAPACKE_H    "lapacke.h"    )
+            set(LAPACK_IMPL "Atlas")
+        endif()
+    endif()
+
+    if(NOT LAPACK_LIBRARIES AND APPLE)
+        set(LAPACK_INCLUDE_DIR  "Accelerate")
+        set(LAPACK_LIBRARIES    "-framework Accelerate")
+        set(LAPACK_CBLAS_H      "cblas.h"      )
+        set(LAPACK_LAPACKE_H    "lapacke.h"    )
+        set(LAPACK_IMPL         "Apple")
+    endif()
+
+    set(LAPACK_INCLUDE_DIR  ${LAPACK_INCLUDE_DIR}            CACHE PATH      "Path to BLAS include dir" FORCE)
+    set(LAPACK_CBLAS_H      ${LAPACK_CBLAS_H}     CACHE STRING    "Alternative name of cblas.h" FORCE)
+    set(LAPACK_LAPACKE_H    ${LAPACK_LAPACKE_H}   CACHE STRING    "Alternative name of lapacke.h" FORCE)
+    set(LAPACK_LIBRARIES    ${LAPACK_LIBRARIES}            CACHE STRING    "Names of BLAS & LAPACK binaries (.so, .dll, .a, .lib)" FORCE)
+    set(LAPACK_IMPL ${LAPACK_IMPL} CACHE STRING "Lapack implementation id" FORCE)
+
+    if(LAPACK_LIBRARIES) #adding proxy cblas.h header
+        message(STATUS "LAPACK_IMPL: ${LAPACK_IMPL}, LAPACK_LIBRARIES: ${LAPACK_LIBRARIES}")
+        if("${LAPACK_IMPL}" STREQUAL "Apple")
+            set(CBLAS_H_PATH "Accelerate/Accelerate.h")
+            set(LAPACKE_H_PATH "Accelerate/Accelerate.h")
+        else()
+            _find_file_in_dirs(CBLAS_H_PATH "${LAPACK_CBLAS_H}" "${LAPACK_INCLUDE_DIR}")
+            _find_file_in_dirs(LAPACKE_H_PATH "${LAPACK_LAPACKE_H}" "${LAPACK_INCLUDE_DIR}")
+        endif()
+        if(NOT CBLAS_H_PATH OR NOT LAPACKE_H_PATH)
+            message(WARNING "CBLAS/LAPACK headers are not found in '${LAPACK_INCLUDE_DIR}'")
+        endif()
+        ocv_include_directories(${LAPACK_INCLUDE_DIR})
+        list(APPEND OPENCV_LINKER_LIBS ${LAPACK_LIBRARIES})
+        set(HAVE_LAPACK 1)
+
+        set(CBLAS_H_PROXY_PATH ${CMAKE_BINARY_DIR}/opencv_lapack.h)
+        set(_include_str "\#include \"${CBLAS_H_PATH}\"")
+        if("${CBLAS_H_PATH}" STREQUAL "${LAPACKE_H_PATH}")
+        else()
+            set(_include_str "${_include_str}\n\#include \"${LAPACKE_H_PATH}\"")
+        endif()
+        file(WRITE ${CBLAS_H_PROXY_PATH} ${_include_str})
+    endif()
+endif()
diff --git a/cmake/OpenCVFindLibsGrfmt.cmake b/cmake/OpenCVFindLibsGrfmt.cmake
index 614f844..cc82575 100644
--- a/cmake/OpenCVFindLibsGrfmt.cmake
+++ b/cmake/OpenCVFindLibsGrfmt.cmake
@@ -202,7 +202,7 @@ endif()
 
 # --- GDAL (optional) ---
 if(WITH_GDAL)
-    find_package(GDAL)
+    find_package(GDAL QUIET)
 
     if(NOT GDAL_FOUND)
         ocv_clear_vars(GDAL_LIBRARY GDAL_INCLUDE_DIR)
@@ -212,3 +212,15 @@ if(WITH_GDAL)
         ocv_include_directories(${GDAL_INCLUDE_DIR})
     endif()
 endif()
+
+if (WITH_GDCM)
+  find_package(GDCM QUIET)
+  if(NOT GDCM_FOUND)
+    set(HAVE_GDCM NO)
+    ocv_clear_vars(GDCM_VERSION GDCM_LIBRARIES)
+  else()
+    set(HAVE_GDCM YES)
+    # include(${GDCM_USE_FILE})
+    set(GDCM_LIBRARIES gdcmMSFF) # GDCM does not set this variable for some reason
+  endif()
+endif()
diff --git a/cmake/OpenCVFindLibsPerf.cmake b/cmake/OpenCVFindLibsPerf.cmake
index d1bc541..70b6cf5 100644
--- a/cmake/OpenCVFindLibsPerf.cmake
+++ b/cmake/OpenCVFindLibsPerf.cmake
@@ -2,6 +2,31 @@
 #  Detect other 3rd-party performance and math libraries
 # ----------------------------------------------------------------------------
 
+# --- Lapack ---
+# if(WITH_LAPACK)
+#   if(WIN32)
+#     set(BLA_STATIC 1)
+#   endif()
+#   find_package(LAPACK)
+#   if(LAPACK_FOUND)
+#     find_path(LAPACKE_INCLUDE_DIR "lapacke.h")
+#     find_path(MKL_LAPACKE_INCLUDE_DIR "mkl_lapack.h")
+#     if(LAPACKE_INCLUDE_DIR)
+#       ocv_include_directories(${LAPACKE_INCLUDE_DIR})
+#       set(HAVE_LAPACK 1)
+#       set(HAVE_LAPACK_GENERIC 1)
+#     elseif(MKL_LAPACKE_INCLUDE_DIR)
+#       ocv_include_directories(${MKL_LAPACKE_INCLUDE_DIR})
+#       set(HAVE_LAPACK 1)
+#       set(HAVE_LAPACK_MKL 1)
+#     elseif(APPLE)
+#       set(HAVE_LAPACK 1)
+#       set(HAVE_LAPACK_APPLE 1)
+#     endif()
+#     list(APPEND OPENCV_LINKER_LIBS ${LAPACK_LIBRARIES})
+#   endif()
+# endif()
+
 # --- TBB ---
 if(WITH_TBB)
   include("${OpenCV_SOURCE_DIR}/cmake/OpenCVDetectTBB.cmake")
diff --git a/cmake/OpenCVFindLibsVideo.cmake b/cmake/OpenCVFindLibsVideo.cmake
index 2e09cf2..1eff03b 100644
--- a/cmake/OpenCVFindLibsVideo.cmake
+++ b/cmake/OpenCVFindLibsVideo.cmake
@@ -124,6 +124,19 @@ if(WITH_GIGEAPI)
   endif()
 endif(WITH_GIGEAPI)
 
+# --- Aravis SDK ---
+ocv_clear_vars(HAVE_ARAVIS_API)
+if(WITH_ARAVIS)
+  find_path(ARAVIS_INCLUDE_PATH "arv.h"
+            PATHS /usr/local /var /opt /usr ENV ProgramFiles ENV ProgramW6432
+            PATH_SUFFIXES include "aravis-0.6" "aravis-0.4"
+            DOC "The path to Aravis SDK headers")
+  find_library(ARAVIS_LIBRARIES NAMES "aravis-0.6" "aravis-0.4" )
+  if(ARAVIS_LIBRARIES AND ARAVIS_INCLUDE_PATH)
+    set(HAVE_ARAVIS_API TRUE)
+  endif()
+endif(WITH_ARAVIS)
+
 # --- Dc1394 ---
 ocv_clear_vars(HAVE_DC1394 HAVE_DC1394_2)
 if(WITH_1394)
@@ -200,83 +213,36 @@ if(WITH_XIMEA)
 endif(WITH_XIMEA)
 
 # --- FFMPEG ---
-ocv_clear_vars(HAVE_FFMPEG HAVE_FFMPEG_CODEC HAVE_FFMPEG_FORMAT HAVE_FFMPEG_UTIL HAVE_FFMPEG_SWSCALE HAVE_FFMPEG_RESAMPLE HAVE_GENTOO_FFMPEG HAVE_FFMPEG_FFMPEG)
+ocv_clear_vars(HAVE_FFMPEG)
 if(WITH_FFMPEG)
   if(WIN32 AND NOT ARM)
     include("${OpenCV_SOURCE_DIR}/3rdparty/ffmpeg/ffmpeg.cmake")
-  elseif(UNIX)
-    CHECK_MODULE(libavcodec HAVE_FFMPEG_CODEC)
-    CHECK_MODULE(libavformat HAVE_FFMPEG_FORMAT)
-    CHECK_MODULE(libavutil HAVE_FFMPEG_UTIL)
-    CHECK_MODULE(libswscale HAVE_FFMPEG_SWSCALE)
-    CHECK_MODULE(libavresample HAVE_FFMPEG_RESAMPLE)
-
-    CHECK_INCLUDE_FILE(libavformat/avformat.h HAVE_GENTOO_FFMPEG)
-    CHECK_INCLUDE_FILE(ffmpeg/avformat.h HAVE_FFMPEG_FFMPEG)
-    if(NOT HAVE_GENTOO_FFMPEG AND NOT HAVE_FFMPEG_FFMPEG)
-      if(EXISTS /usr/include/ffmpeg/libavformat/avformat.h OR HAVE_FFMPEG_SWSCALE)
-        set(HAVE_GENTOO_FFMPEG TRUE)
-      endif()
+    set(HAVE_FFMPEG TRUE)
+  elseif(PKG_CONFIG_FOUND)
+    ocv_check_modules(FFMPEG libavcodec libavformat libavutil libswscale)
+    ocv_check_modules(FFMPEG_libavresample libavresample)
+    if(FFMPEG_libavresample_FOUND)
+      ocv_append_build_options(FFMPEG FFMPEG_libavresample)
     endif()
-    if(HAVE_FFMPEG_CODEC AND HAVE_FFMPEG_FORMAT AND HAVE_FFMPEG_UTIL AND HAVE_FFMPEG_SWSCALE)
-      set(HAVE_FFMPEG TRUE)
-    endif()
-
     if(HAVE_FFMPEG)
-      # Find the bzip2 library because it is required on some systems
-      FIND_LIBRARY(BZIP2_LIBRARIES NAMES bz2 bzip2)
-      if(NOT BZIP2_LIBRARIES)
-        # Do an other trial
-        FIND_FILE(BZIP2_LIBRARIES NAMES libbz2.so.1 PATHS /lib)
+      try_compile(__VALID_FFMPEG
+          "${OpenCV_BINARY_DIR}"
+          "${OpenCV_SOURCE_DIR}/cmake/checks/ffmpeg_test.cpp"
+          CMAKE_FLAGS "-DINCLUDE_DIRECTORIES:STRING=${FFMPEG_INCLUDE_DIRS}"
+                      "-DLINK_DIRECTORIES:STRING=${FFMPEG_LIBRARY_DIRS}"
+                      "-DLINK_LIBRARIES:STRING=${FFMPEG_LIBRARIES}"
+          OUTPUT_VARIABLE TRY_OUT
+      )
+      if(NOT __VALID_FFMPEG)
+        #message(FATAL_ERROR "FFMPEG: test check build log:\n${TRY_OUT}")
+        message(STATUS "WARNING: Can't build ffmpeg test code")
+        set(HAVE_FFMPEG FALSE)
+      else()
+        ocv_append_build_options(VIDEOIO FFMPEG)
       endif()
-    else()
-      find_path(FFMPEG_INCLUDE_DIR "libavformat/avformat.h"
-                PATHS /usr/local /usr /opt
-                PATH_SUFFIXES include
-                DOC "The path to FFMPEG headers")
-      if(FFMPEG_INCLUDE_DIR)
-        set(HAVE_GENTOO_FFMPEG TRUE)
-        set(FFMPEG_LIB_DIR "${FFMPEG_INCLUDE_DIR}/../lib" CACHE PATH "Full path of FFMPEG library directory")
-        find_library(FFMPEG_CODEC_LIB "avcodec" HINTS "${FFMPEG_LIB_DIR}")
-        find_library(FFMPEG_FORMAT_LIB "avformat" HINTS "${FFMPEG_LIB_DIR}")
-        find_library(FFMPEG_UTIL_LIB "avutil" HINTS "${FFMPEG_LIB_DIR}")
-        find_library(FFMPEG_SWSCALE_LIB "swscale" HINTS "${FFMPEG_LIB_DIR}")
-        find_library(FFMPEG_RESAMPLE_LIB "avresample" HINTS "${FFMPEG_LIB_DIR}")
-        if(FFMPEG_CODEC_LIB)
-          set(HAVE_FFMPEG_CODEC 1)
-        endif()
-        if(FFMPEG_FORMAT_LIB)
-          set(HAVE_FFMPEG_FORMAT 1)
-        endif()
-        if(FFMPEG_UTIL_LIB)
-          set(HAVE_FFMPEG_UTIL 1)
-        endif()
-        if(FFMPEG_SWSCALE_LIB)
-          set(HAVE_FFMPEG_SWSCALE 1)
-        endif()
-        if(FFMPEG_CODEC_LIB AND FFMPEG_FORMAT_LIB AND
-           FFMPEG_UTIL_LIB AND FFMPEG_SWSCALE_LIB)
-          set(ALIASOF_libavcodec_VERSION "Unknown")
-          set(ALIASOF_libavformat_VERSION "Unknown")
-          set(ALIASOF_libavutil_VERSION "Unknown")
-          set(ALIASOF_libswscale_VERSION "Unknown")
-          set(HAVE_FFMPEG 1)
-          if(FFMPEG_RESAMPLE_LIB)
-            set(HAVE_FFMPEG_RESAMPLE 1)
-            set(ALIASOF_libavresample_VERSION "Unknown")
-          endif()
-        endif()
-      endif(FFMPEG_INCLUDE_DIR)
-      if(HAVE_FFMPEG)
-        set(VIDEOIO_LIBRARIES ${VIDEOIO_LIBRARIES} "${FFMPEG_LIB_DIR}/libavcodec.a"
-            "${FFMPEG_LIB_DIR}/libavformat.a" "${FFMPEG_LIB_DIR}/libavutil.a"
-            "${FFMPEG_LIB_DIR}/libswscale.a")
-        if(HAVE_FFMPEG_RESAMPLE)
-          set(VIDEOIO_LIBRARIES ${VIDEOIO_LIBRARIES} "${FFMPEG_LIB_DIR}/libavresample.a")
-        endif()
-        ocv_include_directories(${FFMPEG_INCLUDE_DIR})
-      endif(HAVE_FFMPEG)
     endif()
+  else()
+    message(STATUS "Can't find ffmpeg - 'pkg-config' utility is missing")
   endif()
 endif(WITH_FFMPEG)
 
@@ -306,19 +272,18 @@ if(WIN32)
   endif()
 endif(WIN32)
 
-# --- Apple AV Foundation ---
-if(WITH_AVFOUNDATION)
-  set(HAVE_AVFOUNDATION YES)
-endif()
-
-# --- QuickTime ---
-if (NOT IOS)
-  if(WITH_QUICKTIME)
-    set(HAVE_QUICKTIME YES)
-  elseif(APPLE AND CMAKE_COMPILER_IS_CLANGCXX)
-    set(HAVE_QTKIT YES)
+if(APPLE)
+  if(WITH_AVFOUNDATION)
+    set(HAVE_AVFOUNDATION YES)
+  endif()
+  if(NOT IOS)
+    if(WITH_QUICKTIME)
+      set(HAVE_QUICKTIME YES)
+    elseif(WITH_QTKIT)
+      set(HAVE_QTKIT YES)
+    endif()
   endif()
-endif()
+endif(APPLE)
 
 # --- Intel Perceptual Computing SDK ---
 if(WITH_INTELPERC)
diff --git a/cmake/OpenCVFindMKL.cmake b/cmake/OpenCVFindMKL.cmake
new file mode 100644
index 0000000..f43ce9c
--- /dev/null
+++ b/cmake/OpenCVFindMKL.cmake
@@ -0,0 +1,136 @@
+#
+# The script to detect Intel(R) Math Kernel Library (MKL)
+# installation/package
+#
+# Parameters:
+# MKL_WITH_TBB
+#
+# On return this will define:
+#
+# HAVE_MKL          - True if Intel IPP found
+# MKL_ROOT_DIR      - root of IPP installation
+# MKL_INCLUDE_DIRS  - IPP include folder
+# MKL_LIBRARIES     - IPP libraries that are used by OpenCV
+#
+
+macro (mkl_find_lib VAR NAME DIRS)
+    find_path(${VAR} ${NAME} ${DIRS} NO_DEFAULT_PATH)
+    set(${VAR} ${${VAR}}/${NAME})
+    unset(${VAR} CACHE)
+endmacro()
+
+macro(mkl_fail)
+    set(HAVE_MKL OFF CACHE BOOL "True if MKL found")
+    set(MKL_ROOT_DIR ${MKL_ROOT_DIR} CACHE PATH "Path to MKL directory")
+    unset(MKL_INCLUDE_DIRS CACHE)
+    unset(MKL_LIBRARIES CACHE)
+    return()
+endmacro()
+
+macro(get_mkl_version VERSION_FILE)
+    # read MKL version info from file
+    file(STRINGS ${VERSION_FILE} STR1 REGEX "__INTEL_MKL__")
+    file(STRINGS ${VERSION_FILE} STR2 REGEX "__INTEL_MKL_MINOR__")
+    file(STRINGS ${VERSION_FILE} STR3 REGEX "__INTEL_MKL_UPDATE__")
+    #file(STRINGS ${VERSION_FILE} STR4 REGEX "INTEL_MKL_VERSION")
+
+    # extract info and assign to variables
+    string(REGEX MATCHALL "[0-9]+" MKL_VERSION_MAJOR ${STR1})
+    string(REGEX MATCHALL "[0-9]+" MKL_VERSION_MINOR ${STR2})
+    string(REGEX MATCHALL "[0-9]+" MKL_VERSION_UPDATE ${STR3})
+    set(MKL_VERSION_STR "${MKL_VERSION_MAJOR}.${MKL_VERSION_MINOR}.${MKL_VERSION_UPDATE}" CACHE STRING "MKL version" FORCE)
+endmacro()
+
+
+if(NOT DEFINED MKL_USE_MULTITHREAD)
+    OCV_OPTION(MKL_WITH_TBB "Use MKL with TBB multithreading" OFF)#ON IF WITH_TBB)
+    OCV_OPTION(MKL_WITH_OPENMP "Use MKL with OpenMP multithreading" OFF)#ON IF WITH_OPENMP)
+endif()
+
+#check current MKL_ROOT_DIR
+if(NOT MKL_ROOT_DIR OR NOT EXISTS ${MKL_ROOT_DIR}/include/mkl.h)
+    set(mkl_root_paths ${MKL_ROOT_DIR})
+    if(DEFINED $ENV{MKLROOT})
+        list(APPEND mkl_root_paths $ENV{MKLROOT})
+    endif()
+    if(WIN32)
+        set(ProgramFilesx86 "ProgramFiles(x86)")
+        list(APPEND mkl_root_paths $ENV{${ProgramFilesx86}}/IntelSWTools/compilers_and_libraries/windows/mkl)
+    endif()
+    if(UNIX)
+        list(APPEND mkl_root_paths "/opt/intel/mkl")
+    endif()
+
+    find_path(MKL_ROOT_DIR include/mkl.h PATHS ${mkl_root_paths})
+endif()
+
+if(NOT MKL_ROOT_DIR)
+    mkl_fail()
+endif()
+
+set(MKL_INCLUDE_DIRS ${MKL_ROOT_DIR}/include)
+get_mkl_version(${MKL_INCLUDE_DIRS}/mkl_version.h)
+
+#determine arch
+if(CMAKE_CXX_SIZEOF_DATA_PTR EQUAL 8)
+    set(MKL_X64 1)
+    set(MKL_ARCH "intel64")
+
+    include(CheckTypeSize)
+    CHECK_TYPE_SIZE(int _sizeof_int)
+    if (_sizeof_int EQUAL 4)
+        set(MKL_LP64 "lp64")
+    else()
+        set(MKL_LP64 "ilp64")
+    endif()
+else()
+    set(MKL_ARCH "ia32")
+endif()
+
+if(${MKL_VERSION_STR} VERSION_GREATER "11.3.0" OR ${MKL_VERSION_STR} VERSION_EQUAL "11.3.0")
+    set(mkl_lib_find_paths
+        ${MKL_ROOT_DIR}/lib
+        ${MKL_ROOT_DIR}/lib/${MKL_ARCH} ${MKL_ROOT_DIR}/../tbb/lib/${MKL_ARCH})
+
+    set(mkl_lib_list
+        mkl_core
+        mkl_intel_${MKL_LP64})
+
+    if(MKL_WITH_TBB)
+        list(APPEND mkl_lib_list mkl_tbb_thread tbb)
+    elseif(MKL_WITH_OPENMP)
+        if(MSVC)
+            list(APPEND mkl_lib_list mkl_intel_thread libiomp5md)
+        else()
+            list(APPEND mkl_lib_list libmkl_gnu_thread)
+        endif()
+    else()
+        list(APPEND mkl_lib_list mkl_sequential)
+    endif()
+else()
+    message(STATUS "MKL version ${MKL_VERSION_STR} is not supported")
+    mkl_fail()
+endif()
+
+
+set(MKL_LIBRARIES "")
+foreach(lib ${mkl_lib_list})
+    find_library(${lib} ${lib} ${mkl_lib_find_paths})
+    mark_as_advanced(${lib})
+    if(NOT ${lib})
+        mkl_fail()
+    endif()
+    list(APPEND MKL_LIBRARIES ${${lib}})
+endforeach()
+
+message(STATUS "Found MKL ${MKL_VERSION_STR} at: ${MKL_ROOT_DIR}")
+set(HAVE_MKL ON CACHE BOOL "True if MKL found")
+set(MKL_ROOT_DIR ${MKL_ROOT_DIR} CACHE PATH "Path to MKL directory")
+set(MKL_INCLUDE_DIRS ${MKL_INCLUDE_DIRS} CACHE PATH "Path to MKL include directory")
+if(NOT UNIX)
+    set(MKL_LIBRARIES ${MKL_LIBRARIES} CACHE FILEPATH "MKL libarries")
+else()
+    #it's ugly but helps to avoid cyclic lib problem
+    set(MKL_LIBRARIES ${MKL_LIBRARIES} ${MKL_LIBRARIES} ${MKL_LIBRARIES} "-lpthread" "-lm" "-ldl")
+    set(MKL_LIBRARIES ${MKL_LIBRARIES} CACHE STRING "MKL libarries")
+endif()
\ No newline at end of file
diff --git a/cmake/OpenCVFindMatlab.cmake b/cmake/OpenCVFindMatlab.cmake
index 65ad965..ffe8857 100644
--- a/cmake/OpenCVFindMatlab.cmake
+++ b/cmake/OpenCVFindMatlab.cmake
@@ -62,7 +62,7 @@ function(locate_matlab_root)
     # possible root locations, in order of likelihood
     set(SEARCH_DIRS_ /Applications /usr/local /opt/local /usr /opt)
     foreach (DIR_ ${SEARCH_DIRS_})
-      file(GLOB MATLAB_ROOT_DIR_ ${DIR_}/MATLAB/R*)
+      file(GLOB MATLAB_ROOT_DIR_ ${DIR_}/MATLAB/R* ${DIR_}/MATLAB_R*)
       if (MATLAB_ROOT_DIR_)
         # sort in order from highest to lowest
         # normally it's in the format MATLAB_R[20XX][A/B]
diff --git a/cmake/OpenCVFindOpenBLAS.cmake b/cmake/OpenCVFindOpenBLAS.cmake
new file mode 100644
index 0000000..60594de
--- /dev/null
+++ b/cmake/OpenCVFindOpenBLAS.cmake
@@ -0,0 +1,106 @@
+#COPYRIGHT
+#
+#All contributions by the University of California:
+#Copyright (c) 2014, 2015, The Regents of the University of California (Regents)
+#All rights reserved.
+#
+#All other contributions:
+#Copyright (c) 2014, 2015, the respective contributors
+#All rights reserved.
+#
+#Caffe uses a shared copyright model: each contributor holds copyright over
+#their contributions to Caffe. The project versioning records all such
+#contribution and copyright details. If a contributor wants to further mark
+#their specific copyright on a particular contribution, they should indicate
+#their copyright solely in the commit message of the change when it is
+#committed.
+#
+#LICENSE
+#
+#Redistribution and use in source and binary forms, with or without
+#modification, are permitted provided that the following conditions are met:
+#
+#1. Redistributions of source code must retain the above copyright notice, this
+#   list of conditions and the following disclaimer.
+#2. Redistributions in binary form must reproduce the above copyright notice,
+#   this list of conditions and the following disclaimer in the documentation
+#   and/or other materials provided with the distribution.
+#
+#THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+#ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+#WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+#DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+#ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+#(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+#LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+#ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+#(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+#SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+#CONTRIBUTION AGREEMENT
+#
+#By contributing to the BVLC/caffe repository through pull-request, comment,
+#or otherwise, the contributor releases their content to the
+#license and copyright terms herein.
+
+SET(Open_BLAS_INCLUDE_SEARCH_PATHS
+  /usr/include
+  /usr/include/openblas
+  /usr/include/openblas-base
+  /usr/local/include
+  /usr/local/include/openblas
+  /usr/local/include/openblas-base
+  /opt/OpenBLAS/include
+  $ENV{OpenBLAS_HOME}
+  $ENV{OpenBLAS_HOME}/include
+)
+
+SET(Open_BLAS_LIB_SEARCH_PATHS
+        /lib/
+        /lib/openblas-base
+        /lib64/
+        /usr/lib
+        /usr/lib/openblas-base
+        /usr/lib64
+        /usr/local/lib
+        /usr/local/lib64
+        /opt/OpenBLAS/lib
+        $ENV{OpenBLAS}cd
+        $ENV{OpenBLAS}/lib
+        $ENV{OpenBLAS_HOME}
+        $ENV{OpenBLAS_HOME}/lib
+ )
+
+FIND_PATH(OpenBLAS_INCLUDE_DIR NAMES cblas.h PATHS ${Open_BLAS_INCLUDE_SEARCH_PATHS})
+FIND_LIBRARY(OpenBLAS_LIB NAMES openblas PATHS ${Open_BLAS_LIB_SEARCH_PATHS})
+
+SET(OpenBLAS_FOUND ON)
+
+#    Check include files
+IF(NOT OpenBLAS_INCLUDE_DIR)
+    SET(OpenBLAS_FOUND OFF)
+    MESSAGE(STATUS "Could not find OpenBLAS include. Turning OpenBLAS_FOUND off")
+ENDIF()
+
+#    Check libraries
+IF(NOT OpenBLAS_LIB)
+    SET(OpenBLAS_FOUND OFF)
+    MESSAGE(STATUS "Could not find OpenBLAS lib. Turning OpenBLAS_FOUND off")
+ENDIF()
+
+IF (OpenBLAS_FOUND)
+  IF (NOT OpenBLAS_FIND_QUIETLY)
+    MESSAGE(STATUS "Found OpenBLAS libraries: ${OpenBLAS_LIB}")
+    MESSAGE(STATUS "Found OpenBLAS include: ${OpenBLAS_INCLUDE_DIR}")
+  ENDIF (NOT OpenBLAS_FIND_QUIETLY)
+ELSE (OpenBLAS_FOUND)
+  IF (OpenBLAS_FIND_REQUIRED)
+    MESSAGE(FATAL_ERROR "Could not find OpenBLAS")
+  ENDIF (OpenBLAS_FIND_REQUIRED)
+ENDIF (OpenBLAS_FOUND)
+
+MARK_AS_ADVANCED(
+    OpenBLAS_INCLUDE_DIR
+    OpenBLAS_LIB
+    OpenBLAS
+)
\ No newline at end of file
diff --git a/cmake/OpenCVGenABI.cmake b/cmake/OpenCVGenABI.cmake
index 35cc10d..86aa78b 100644
--- a/cmake/OpenCVGenABI.cmake
+++ b/cmake/OpenCVGenABI.cmake
@@ -43,7 +43,7 @@ string(REPLACE ";" "\n    " OPENCV_ABI_SKIP_HEADERS "${OPENCV_ABI_SKIP_HEADERS}"
 string(REPLACE ";" "\n    " OPENCV_ABI_SKIP_LIBRARIES "${OPENCV_ABI_SKIP_LIBRARIES}")
 
 # Options
-set(OPENCV_ABI_GCC_OPTIONS "${CMAKE_CXX_FLAGS} ${CMAKE_CXX_FLAGS_RELEASE}")
+set(OPENCV_ABI_GCC_OPTIONS "${CMAKE_CXX_FLAGS} ${CMAKE_CXX_FLAGS_RELEASE} -DOPENCV_ABI_CHECK=1")
 string(REGEX REPLACE "([^ ]) +([^ ])" "\\1\\n    \\2" OPENCV_ABI_GCC_OPTIONS "${OPENCV_ABI_GCC_OPTIONS}")
 
 configure_file("${CMAKE_CURRENT_SOURCE_DIR}/cmake/templates/opencv_abi.xml.in" "${path1}")
diff --git a/cmake/OpenCVGenConfig.cmake b/cmake/OpenCVGenConfig.cmake
index dbfd7ca..206acfd 100644
--- a/cmake/OpenCVGenConfig.cmake
+++ b/cmake/OpenCVGenConfig.cmake
@@ -11,47 +11,20 @@ else()
   set(OpenCV_USE_MANGLED_PATHS_CONFIGCMAKE FALSE)
 endif()
 
-if(NOT OpenCV_CUDA_CC)
-  set(OpenCV_CUDA_CC_CONFIGCMAKE "\"\"")
-  set(OpenCV_CUDA_VERSION "")
-else()
-  set(OpenCV_CUDA_CC_CONFIGCMAKE "${OpenCV_CUDA_CC}")
-  set(OpenCV_CUDA_VERSION ${CUDA_VERSION_STRING})
-endif()
-
-if(NOT ANDROID_NATIVE_API_LEVEL)
-  set(OpenCV_ANDROID_NATIVE_API_LEVEL_CONFIGCMAKE 0)
-else()
-  set(OpenCV_ANDROID_NATIVE_API_LEVEL_CONFIGCMAKE "${ANDROID_NATIVE_API_LEVEL}")
+if(HAVE_CUDA)
+  ocv_cmake_configure("${CMAKE_CURRENT_LIST_DIR}/templates/OpenCVConfig-CUDA.cmake.in" CUDA_CONFIGCMAKE @ONLY)
 endif()
 
-if(CMAKE_GENERATOR MATCHES "Visual" OR CMAKE_GENERATOR MATCHES "Xcode")
-  set(OpenCV_ADD_DEBUG_RELEASE_CONFIGCMAKE TRUE)
-else()
-  set(OpenCV_ADD_DEBUG_RELEASE_CONFIGCMAKE FALSE)
-endif()
-
-
-
-if(WIN32)
-  if(MINGW)
-    set(OPENCV_LINK_LIBRARY_SUFFIX ".dll.a")
+if(ANDROID)
+  if(NOT ANDROID_NATIVE_API_LEVEL)
+    set(OpenCV_ANDROID_NATIVE_API_LEVEL_CONFIGCMAKE 0)
   else()
-    set(OPENCV_LINK_LIBRARY_SUFFIX ".lib")
+    set(OpenCV_ANDROID_NATIVE_API_LEVEL_CONFIGCMAKE "${ANDROID_NATIVE_API_LEVEL}")
   endif()
+  ocv_cmake_configure("${CMAKE_CURRENT_LIST_DIR}/templates/OpenCVConfig-ANDROID.cmake.in" ANDROID_CONFIGCMAKE @ONLY)
 endif()
 
-#build list of modules available for the OpenCV user
-set(OpenCV_LIB_COMPONENTS "")
-foreach(m ${OPENCV_MODULES_PUBLIC})
-  list(INSERT OpenCV_LIB_COMPONENTS 0 ${${m}_MODULE_DEPS_OPT} ${m})
-endforeach()
-ocv_list_unique(OpenCV_LIB_COMPONENTS)
-set(OPENCV_MODULES_CONFIGCMAKE ${OpenCV_LIB_COMPONENTS})
-ocv_list_filterout(OpenCV_LIB_COMPONENTS "^opencv_")
-if(OpenCV_LIB_COMPONENTS)
-  list(REMOVE_ITEM OPENCV_MODULES_CONFIGCMAKE ${OpenCV_LIB_COMPONENTS})
-endif()
+set(OPENCV_MODULES_CONFIGCMAKE ${OPENCV_MODULES_PUBLIC})
 
 if(BUILD_FAT_JAVA_LIB AND HAVE_opencv_java)
   list(APPEND OPENCV_MODULES_CONFIGCMAKE opencv_java)
@@ -62,33 +35,20 @@ endif()
 # -------------------------------------------------------------------------------------------
 set(OpenCV_INCLUDE_DIRS_CONFIGCMAKE "\"${OPENCV_CONFIG_FILE_INCLUDE_DIR}\" \"${OpenCV_SOURCE_DIR}/include\" \"${OpenCV_SOURCE_DIR}/include/opencv\"")
 
-set(OpenCV2_INCLUDE_DIRS_CONFIGCMAKE "")
 foreach(m ${OPENCV_MODULES_BUILD})
   if(EXISTS "${OPENCV_MODULE_${m}_LOCATION}/include")
-    list(APPEND OpenCV2_INCLUDE_DIRS_CONFIGCMAKE "${OPENCV_MODULE_${m}_LOCATION}/include")
+    set(OpenCV_INCLUDE_DIRS_CONFIGCMAKE "${OpenCV_INCLUDE_DIRS_CONFIGCMAKE} \"${OPENCV_MODULE_${m}_LOCATION}/include\"")
   endif()
 endforeach()
 
-if(ANDROID AND NOT BUILD_SHARED_LIBS AND HAVE_TBB)
-  #export TBB headers location because static linkage of TBB might be troublesome if application wants to use TBB itself
-  list(APPEND OpenCV2_INCLUDE_DIRS_CONFIGCMAKE ${TBB_INCLUDE_DIRS})
-endif()
-
-set(modules_file_suffix "")
-if(ANDROID)
-  # the REPLACE here is needed, because OpenCVModules_armeabi.cmake includes
-  # OpenCVModules_armeabi-*.cmake, which would match OpenCVModules_armeabi-v7a*.cmake.
-  string(REPLACE - _ modules_file_suffix "_${ANDROID_NDK_ABI_NAME}")
-endif()
+export(TARGETS ${OpenCVModules_TARGETS} FILE "${CMAKE_BINARY_DIR}/OpenCVModules.cmake")
 
-export(TARGETS ${OpenCVModules_TARGETS} FILE "${CMAKE_BINARY_DIR}/OpenCVModules${modules_file_suffix}.cmake")
-
-if(TARGET ippicv AND (NOT BUILD_SHARED_LIBS OR NOT INSTALL_CREATE_DISTRIB))
+if(TARGET ippicv AND NOT BUILD_SHARED_LIBS)
   set(USE_IPPICV TRUE)
-  file(RELATIVE_PATH INSTALL_PATH_RELATIVE_IPPICV ${CMAKE_BINARY_DIR} ${IPPICV_LOCATION_PATH})
+  file(RELATIVE_PATH IPPICV_INSTALL_PATH_RELATIVE_CONFIGCMAKE ${CMAKE_BINARY_DIR} ${IPPICV_LOCATION_PATH})
+  ocv_cmake_configure("${CMAKE_CURRENT_LIST_DIR}/templates/OpenCVConfig-IPPICV.cmake.in" IPPICV_CONFIGCMAKE @ONLY)
 else()
   set(USE_IPPICV FALSE)
-  set(INSTALL_PATH_RELATIVE_IPPICV "non-existed-path")
 endif()
 
 configure_file("${OpenCV_SOURCE_DIR}/cmake/templates/OpenCVConfig.cmake.in" "${CMAKE_BINARY_DIR}/OpenCVConfig.cmake" @ONLY)
@@ -98,58 +58,60 @@ configure_file("${OpenCV_SOURCE_DIR}/cmake/templates/OpenCVConfig-version.cmake.
 # --------------------------------------------------------------------------------------------
 #  Part 2/3: ${BIN_DIR}/unix-install/OpenCVConfig.cmake -> For use *with* "make install"
 # -------------------------------------------------------------------------------------------
-set(OpenCV_INCLUDE_DIRS_CONFIGCMAKE "\"\${OpenCV_INSTALL_PATH}/${OPENCV_INCLUDE_INSTALL_PATH}/opencv" "\${OpenCV_INSTALL_PATH}/${OPENCV_INCLUDE_INSTALL_PATH}\"")
-
-set(OpenCV2_INCLUDE_DIRS_CONFIGCMAKE "\"\"")
-set(OpenCV_3RDPARTY_LIB_DIRS_CONFIGCMAKE "\"\${OpenCV_INSTALL_PATH}/${OPENCV_3P_LIB_INSTALL_PATH}\"")
-
-if(UNIX) # ANDROID configuration is created here also
-  #http://www.vtk.org/Wiki/CMake/Tutorials/Packaging reference
-  # For a command "find_package(<name> [major[.minor]] [EXACT] [REQUIRED|QUIET])"
-  # cmake will look in the following dir on unix:
-  #                <prefix>/(share|lib)/cmake/<name>*/                     (U)
-  #                <prefix>/(share|lib)/<name>*/                           (U)
-  #                <prefix>/(share|lib)/<name>*/(cmake|CMake)/             (U)
-  if(USE_IPPICV)
-    file(RELATIVE_PATH INSTALL_PATH_RELATIVE_IPPICV "${CMAKE_INSTALL_PREFIX}/${OPENCV_CONFIG_INSTALL_PATH}/" ${IPPICV_INSTALL_PATH})
+file(RELATIVE_PATH OpenCV_INSTALL_PATH_RELATIVE_CONFIGCMAKE "${CMAKE_INSTALL_PREFIX}/${OPENCV_CONFIG_INSTALL_PATH}/" ${CMAKE_INSTALL_PREFIX})
+set(OpenCV_INCLUDE_DIRS_CONFIGCMAKE "\"\${OpenCV_INSTALL_PATH}/${OPENCV_INCLUDE_INSTALL_PATH}\" \"\${OpenCV_INSTALL_PATH}/${OPENCV_INCLUDE_INSTALL_PATH}/opencv\"")
+
+if(USE_IPPICV)
+  file(RELATIVE_PATH IPPICV_INSTALL_PATH_RELATIVE_CONFIGCMAKE "${CMAKE_INSTALL_PREFIX}" ${IPPICV_INSTALL_PATH})
+  ocv_cmake_configure("${CMAKE_CURRENT_LIST_DIR}/templates/OpenCVConfig-IPPICV.cmake.in" IPPICV_CONFIGCMAKE @ONLY)
+endif()
+
+function(ocv_gen_config TMP_DIR NESTED_PATH ROOT_NAME)
+  ocv_path_join(__install_nested "${OPENCV_CONFIG_INSTALL_PATH}" "${NESTED_PATH}")
+  ocv_path_join(__tmp_nested "${TMP_DIR}" "${NESTED_PATH}")
+
+  file(RELATIVE_PATH OpenCV_INSTALL_PATH_RELATIVE_CONFIGCMAKE "${CMAKE_INSTALL_PREFIX}/${__install_nested}" "${CMAKE_INSTALL_PREFIX}/")
+
+  configure_file("${OpenCV_SOURCE_DIR}/cmake/templates/OpenCVConfig-version.cmake.in" "${TMP_DIR}/OpenCVConfig-version.cmake" @ONLY)
+
+  configure_file("${OpenCV_SOURCE_DIR}/cmake/templates/OpenCVConfig.cmake.in" "${__tmp_nested}/OpenCVConfig.cmake" @ONLY)
+  install(EXPORT OpenCVModules DESTINATION "${__install_nested}" FILE OpenCVModules.cmake COMPONENT dev)
+  install(FILES
+      "${TMP_DIR}/OpenCVConfig-version.cmake"
+      "${__tmp_nested}/OpenCVConfig.cmake"
+      DESTINATION "${__install_nested}" COMPONENT dev)
+
+  if(ROOT_NAME)
+    # Root config file
+    configure_file("${OpenCV_SOURCE_DIR}/cmake/templates/${ROOT_NAME}" "${TMP_DIR}/OpenCVConfig.cmake" @ONLY)
+    install(FILES
+        "${TMP_DIR}/OpenCVConfig-version.cmake"
+        "${TMP_DIR}/OpenCVConfig.cmake"
+        DESTINATION "${OPENCV_CONFIG_INSTALL_PATH}" COMPONENT dev)
   endif()
-  configure_file("${OpenCV_SOURCE_DIR}/cmake/templates/OpenCVConfig.cmake.in" "${CMAKE_BINARY_DIR}/unix-install/OpenCVConfig.cmake" @ONLY)
-  configure_file("${OpenCV_SOURCE_DIR}/cmake/templates/OpenCVConfig-version.cmake.in" "${CMAKE_BINARY_DIR}/unix-install/OpenCVConfig-version.cmake" @ONLY)
-  install(FILES "${CMAKE_BINARY_DIR}/unix-install/OpenCVConfig.cmake" DESTINATION ${OPENCV_CONFIG_INSTALL_PATH}/ COMPONENT dev)
-  install(FILES ${CMAKE_BINARY_DIR}/unix-install/OpenCVConfig-version.cmake DESTINATION ${OPENCV_CONFIG_INSTALL_PATH}/ COMPONENT dev)
-  install(EXPORT OpenCVModules DESTINATION ${OPENCV_CONFIG_INSTALL_PATH}/ FILE OpenCVModules${modules_file_suffix}.cmake COMPONENT dev)
+endfunction()
+
+if(UNIX AND NOT ANDROID)
+  ocv_gen_config("${CMAKE_BINARY_DIR}/unix-install" "" "")
 endif()
 
 if(ANDROID)
-  install(FILES "${OpenCV_SOURCE_DIR}/platforms/android/android.toolchain.cmake" DESTINATION ${OPENCV_CONFIG_INSTALL_PATH}/ COMPONENT dev)
+  ocv_gen_config("${CMAKE_BINARY_DIR}/unix-install" "abi-${ANDROID_NDK_ABI_NAME}" "OpenCVConfig.root-ANDROID.cmake.in")
+  install(FILES "${OpenCV_SOURCE_DIR}/platforms/android/android.toolchain.cmake" DESTINATION "${OPENCV_CONFIG_INSTALL_PATH}" COMPONENT dev)
 endif()
 
 # --------------------------------------------------------------------------------------------
 #  Part 3/3: ${BIN_DIR}/win-install/OpenCVConfig.cmake  -> For use within binary installers/packages
 # --------------------------------------------------------------------------------------------
 if(WIN32)
-  set(OpenCV_INCLUDE_DIRS_CONFIGCMAKE "\"\${OpenCV_CONFIG_PATH}/include\" \"\${OpenCV_CONFIG_PATH}/include/opencv\"")
-  set(OpenCV2_INCLUDE_DIRS_CONFIGCMAKE "\"\"")
-
-  exec_program(mkdir ARGS "-p \"${CMAKE_BINARY_DIR}/win-install/\"" OUTPUT_VARIABLE RET_VAL)
-  if(USE_IPPICV)
-    file(RELATIVE_PATH INSTALL_PATH_RELATIVE_IPPICV "${CMAKE_INSTALL_PREFIX}/${OpenCV_INSTALL_BINARIES_PREFIX}staticlib" ${IPPICV_INSTALL_PATH})
-  endif()
-  configure_file("${OpenCV_SOURCE_DIR}/cmake/templates/OpenCVConfig.cmake.in" "${CMAKE_BINARY_DIR}/win-install/OpenCVConfig.cmake" @ONLY)
-  configure_file("${OpenCV_SOURCE_DIR}/cmake/templates/OpenCVConfig-version.cmake.in" "${CMAKE_BINARY_DIR}/win-install/OpenCVConfig-version.cmake" @ONLY)
-  if (CMAKE_HOST_SYSTEM_NAME MATCHES Windows)
+  if(CMAKE_HOST_SYSTEM_NAME MATCHES Windows)
     if(BUILD_SHARED_LIBS)
-      install(FILES "${CMAKE_BINARY_DIR}/win-install/OpenCVConfig.cmake" DESTINATION "${OpenCV_INSTALL_BINARIES_PREFIX}lib" COMPONENT dev)
-      install(EXPORT OpenCVModules DESTINATION "${OpenCV_INSTALL_BINARIES_PREFIX}lib" FILE OpenCVModules${modules_file_suffix}.cmake COMPONENT dev)
+      set(_lib_suffix "lib")
     else()
-      install(FILES "${CMAKE_BINARY_DIR}/win-install/OpenCVConfig.cmake" DESTINATION "${OpenCV_INSTALL_BINARIES_PREFIX}staticlib" COMPONENT dev)
-      install(EXPORT OpenCVModules DESTINATION "${OpenCV_INSTALL_BINARIES_PREFIX}staticlib" FILE OpenCVModules${modules_file_suffix}.cmake COMPONENT dev)
+      set(_lib_suffix "staticlib")
     endif()
-    install(FILES "${CMAKE_BINARY_DIR}/win-install/OpenCVConfig-version.cmake" DESTINATION "${CMAKE_INSTALL_PREFIX}" COMPONENT dev)
-    install(FILES "${OpenCV_SOURCE_DIR}/cmake/OpenCVConfig.cmake" DESTINATION "${CMAKE_INSTALL_PREFIX}/" COMPONENT dev)
-  else ()
-    install(FILES "${CMAKE_BINARY_DIR}/win-install/OpenCVConfig.cmake" DESTINATION "${OpenCV_INSTALL_BINARIES_PREFIX}lib/cmake/opencv-${OPENCV_VERSION}" COMPONENT dev)
-    install(EXPORT OpenCVModules DESTINATION "${OpenCV_INSTALL_BINARIES_PREFIX}lib/cmake/opencv-${OPENCV_VERSION}" FILE OpenCVModules${modules_file_suffix}.cmake COMPONENT dev)
-    install(FILES "${CMAKE_BINARY_DIR}/win-install/OpenCVConfig-version.cmake" DESTINATION "${CMAKE_INSTALL_PREFIX}/lib/cmake/opencv-${OPENCV_VERSION}" COMPONENT dev)
-  endif ()
+    ocv_gen_config("${CMAKE_BINARY_DIR}/win-install" "${OpenCV_INSTALL_BINARIES_PREFIX}${_lib_suffix}" "OpenCVConfig.root-WIN32.cmake.in")
+  else()
+    ocv_gen_config("${CMAKE_BINARY_DIR}/win-install" "" "")
+  endif()
 endif()
diff --git a/cmake/OpenCVMinDepVersions.cmake b/cmake/OpenCVMinDepVersions.cmake
index e8591e2..44dbf6e 100644
--- a/cmake/OpenCVMinDepVersions.cmake
+++ b/cmake/OpenCVMinDepVersions.cmake
@@ -1,5 +1,5 @@
 set(MIN_VER_CMAKE 2.8.7)
-set(MIN_VER_CUDA 4.2)
+set(MIN_VER_CUDA 6.5)
 set(MIN_VER_PYTHON2 2.6)
 set(MIN_VER_PYTHON3 3.2)
 set(MIN_VER_ZLIB 1.2.3)
diff --git a/cmake/OpenCVModule.cmake b/cmake/OpenCVModule.cmake
index 3385385..742a287 100644
--- a/cmake/OpenCVModule.cmake
+++ b/cmake/OpenCVModule.cmake
@@ -701,7 +701,6 @@ macro(ocv_glob_module_sources)
   )
   if(cl_kernels)
     set(OCL_NAME opencl_kernels_${name})
-    ocv_include_directories(${OPENCL_INCLUDE_DIRS})
     add_custom_command(
       OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${OCL_NAME}.cpp" "${CMAKE_CURRENT_BINARY_DIR}/${OCL_NAME}.hpp"
       COMMAND ${CMAKE_COMMAND} "-DMODULE_NAME=${name}" "-DCL_DIR=${CMAKE_CURRENT_LIST_DIR}/src/opencl" "-DOUTPUT=${CMAKE_CURRENT_BINARY_DIR}/${OCL_NAME}.cpp" -P "${OpenCV_SOURCE_DIR}/cmake/cl2cpp.cmake"
@@ -780,6 +779,8 @@ macro(_ocv_create_module)
     endforeach()
   endif()
 
+  source_group("Include" FILES "${OPENCV_CONFIG_FILE_INCLUDE_DIR}/cvconfig.h" "${OPENCV_CONFIG_FILE_INCLUDE_DIR}/opencv2/opencv_modules.hpp")
+  source_group("Src" FILES "${${the_module}_pch}")
   ocv_add_library(${the_module} ${OPENCV_MODULE_TYPE} ${OPENCV_MODULE_${the_module}_HEADERS} ${OPENCV_MODULE_${the_module}_SOURCES}
     "${OPENCV_CONFIG_FILE_INCLUDE_DIR}/cvconfig.h" "${OPENCV_CONFIG_FILE_INCLUDE_DIR}/opencv2/opencv_modules.hpp"
     ${${the_module}_pch} ${sub_objs})
@@ -834,7 +835,6 @@ macro(_ocv_create_module)
     COMPILE_PDB_OUTPUT_DIRECTORY ${LIBRARY_OUTPUT_PATH}
     LIBRARY_OUTPUT_DIRECTORY ${LIBRARY_OUTPUT_PATH}
     RUNTIME_OUTPUT_DIRECTORY ${EXECUTABLE_OUTPUT_PATH}
-    INSTALL_NAME_DIR lib
   )
 
   # For dynamic link numbering convenions
@@ -861,7 +861,8 @@ macro(_ocv_create_module)
   endif()
 
   get_target_property(_target_type ${the_module} TYPE)
-  if("${_target_type}" STREQUAL "SHARED_LIBRARY" OR (NOT BUILD_SHARED_LIBS OR NOT INSTALL_CREATE_DISTRIB))
+  if(OPENCV_MODULE_${the_module}_CLASS STREQUAL "PUBLIC" AND
+      ("${_target_type}" STREQUAL "SHARED_LIBRARY" OR (NOT BUILD_SHARED_LIBS OR NOT INSTALL_CREATE_DISTRIB)))
     ocv_install_target(${the_module} EXPORT OpenCVModules OPTIONAL
       RUNTIME DESTINATION ${OPENCV_BIN_INSTALL_PATH} COMPONENT libs
       LIBRARY DESTINATION ${OPENCV_LIB_INSTALL_PATH} COMPONENT libs NAMELINK_SKIP
@@ -1016,6 +1017,7 @@ function(ocv_add_perf_tests)
         get_native_precompiled_header(${the_target} perf_precomp.hpp)
       endif()
 
+      source_group("Src" FILES "${${the_target}_pch}")
       ocv_add_executable(${the_target} ${OPENCV_PERF_${the_module}_SOURCES} ${${the_target}_pch})
       ocv_target_include_modules(${the_target} ${perf_deps} "${perf_path}")
       ocv_target_link_libraries(${the_target} ${perf_deps} ${OPENCV_MODULE_${the_module}_DEPS} ${OPENCV_LINKER_LIBS})
@@ -1092,6 +1094,7 @@ function(ocv_add_accuracy_tests)
         get_native_precompiled_header(${the_target} test_precomp.hpp)
       endif()
 
+      source_group("Src" FILES "${${the_target}_pch}")
       ocv_add_executable(${the_target} ${OPENCV_TEST_${the_module}_SOURCES} ${${the_target}_pch})
       ocv_target_include_modules(${the_target} ${test_deps} "${test_path}")
       ocv_target_link_libraries(${the_target} ${test_deps} ${OPENCV_MODULE_${the_module}_DEPS} ${OPENCV_LINKER_LIBS})
@@ -1111,6 +1114,10 @@ function(ocv_add_accuracy_tests)
         set_target_properties(${the_target} PROPERTIES FOLDER "tests accuracy")
       endif()
 
+      if(OPENCV_TEST_BIGDATA)
+        ocv_append_target_property(${the_target} COMPILE_DEFINITIONS "OPENCV_TEST_BIGDATA=1")
+      endif()
+
       if(NOT BUILD_opencv_world)
         _ocv_add_precompiled_headers(${the_target})
       endif()
diff --git a/cmake/OpenCVPCHSupport.cmake b/cmake/OpenCVPCHSupport.cmake
index 28ccc1c..90437cb 100644
--- a/cmake/OpenCVPCHSupport.cmake
+++ b/cmake/OpenCVPCHSupport.cmake
@@ -14,12 +14,7 @@
 
 IF(CMAKE_COMPILER_IS_GNUCXX)
 
-    EXEC_PROGRAM(
-        ${CMAKE_CXX_COMPILER}
-        ARGS ${CMAKE_CXX_COMPILER_ARG1} -dumpversion
-        OUTPUT_VARIABLE gcc_compiler_version)
-    #MESSAGE("GCC Version: ${gcc_compiler_version}")
-    IF(gcc_compiler_version VERSION_GREATER "4.2.-1")
+    IF(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS "4.2.0")
         SET(PCHSupport_FOUND TRUE)
     ENDIF()
 
@@ -67,7 +62,8 @@ MACRO(_PCH_GET_COMPILE_FLAGS _out_compile_flags)
 
     GET_DIRECTORY_PROPERTY(DIRINC INCLUDE_DIRECTORIES )
     FOREACH(item ${DIRINC})
-        if(item MATCHES "^${OpenCV_SOURCE_DIR}/modules/")
+        ocv_is_opencv_directory(__result ${item})
+        if(__result)
           LIST(APPEND ${_out_compile_flags} "${_PCH_include_prefix}\"${item}\"")
         else()
           LIST(APPEND ${_out_compile_flags} "${_PCH_isystem_prefix}\"${item}\"")
@@ -76,7 +72,8 @@ MACRO(_PCH_GET_COMPILE_FLAGS _out_compile_flags)
 
     get_target_property(DIRINC ${_PCH_current_target} INCLUDE_DIRECTORIES )
     FOREACH(item ${DIRINC})
-        if(item MATCHES "^${OpenCV_SOURCE_DIR}/modules/")
+        ocv_is_opencv_directory(__result ${item})
+        if(__result)
           LIST(APPEND ${_out_compile_flags} "${_PCH_include_prefix}\"${item}\"")
         else()
           LIST(APPEND ${_out_compile_flags} "${_PCH_isystem_prefix}\"${item}\"")
@@ -92,29 +89,21 @@ ENDMACRO(_PCH_GET_COMPILE_FLAGS)
 
 MACRO(_PCH_WRITE_PCHDEP_CXX _targetName _include_file _dephelp)
 
-    SET(${_dephelp} ${CMAKE_CURRENT_BINARY_DIR}/${_targetName}_pch_dephelp.cxx)
-    IF(CMAKE_HOST_WIN32)
-        ADD_CUSTOM_COMMAND(
-          OUTPUT "${${_dephelp}}"
-          COMMAND ${CMAKE_COMMAND} -E echo "#include \\\"${_include_file}\\\"" >  "${${_dephelp}}"
-          COMMAND ${CMAKE_COMMAND} -E echo "int testfunction();"               >> "${${_dephelp}}"
-          COMMAND ${CMAKE_COMMAND} -E echo "int testfunction()"                >> "${${_dephelp}}"
-          COMMAND ${CMAKE_COMMAND} -E echo "{"                                 >> "${${_dephelp}}"
-          COMMAND ${CMAKE_COMMAND} -E echo "    return 0;"                     >> "${${_dephelp}}"
-          COMMAND ${CMAKE_COMMAND} -E echo "}"                                 >> "${${_dephelp}}"
-          DEPENDS "${_include_file}"
-          )
-    else()
-        ADD_CUSTOM_COMMAND(
-          OUTPUT "${${_dephelp}}"
-          COMMAND ${CMAKE_COMMAND} -E echo "\\#include \\\"${_include_file}\\\"" >  "${${_dephelp}}"
-          COMMAND ${CMAKE_COMMAND} -E echo "int testfunction\\(\\)\\;"         >> "${${_dephelp}}"
-          COMMAND ${CMAKE_COMMAND} -E echo "int testfunction\\(\\)"            >> "${${_dephelp}}"
-          COMMAND ${CMAKE_COMMAND} -E echo "{"                                 >> "${${_dephelp}}"
-          COMMAND ${CMAKE_COMMAND} -E echo "    \\return 0\\;"                 >> "${${_dephelp}}"
-          COMMAND ${CMAKE_COMMAND} -E echo "}"                                 >> "${${_dephelp}}"
-          DEPENDS "${_include_file}"
-          )
+    set(${_dephelp} "${CMAKE_CURRENT_BINARY_DIR}/${_targetName}_pch_dephelp.cxx")
+    set(_content "")
+    if(EXISTS "${_dephelp}")
+      file(READ "${_dephelp}" _content)
+    endif()
+    set(_dummy_str
+"#include \"${_include_file}\"
+int testfunction();
+int testfunction()
+{
+    return 0;
+}
+")
+    if(NOT _content STREQUAL _dummy_str)
+      file(WRITE "${${_dephelp}}" "${_dummy_str}")
     endif()
 
 ENDMACRO(_PCH_WRITE_PCHDEP_CXX )
@@ -164,9 +153,9 @@ MACRO(_PCH_GET_TARGET_COMPILE_FLAGS _cflags  _header_name _pch_path _dowarn )
         # if you have different versions of the headers for different build types
         # you may set _pch_dowarn
         IF (_dowarn)
-            SET(${_cflags} "${PCH_ADDITIONAL_COMPILER_FLAGS} -include \"${CMAKE_CURRENT_BINARY_DIR}/${_header_name}\" -Winvalid-pch " )
+            SET(${_cflags} "${PCH_ADDITIONAL_COMPILER_FLAGS} -Winvalid-pch " )
         ELSE (_dowarn)
-            SET(${_cflags} "${PCH_ADDITIONAL_COMPILER_FLAGS} -include \"${CMAKE_CURRENT_BINARY_DIR}/${_header_name}\" " )
+            SET(${_cflags} "${PCH_ADDITIONAL_COMPILER_FLAGS} " )
         ENDIF (_dowarn)
 
     ELSE(CMAKE_COMPILER_IS_GNUCXX)
@@ -289,6 +278,19 @@ MACRO(ADD_PRECOMPILED_HEADER _targetName _input)
       DEPENDS ${_targetName}_pch_dephelp
       )
 
+    get_target_property(_sources ${_targetName} SOURCES)
+    foreach(src ${_sources})
+      if(NOT "${src}" MATCHES "\\.mm$")
+        get_source_file_property(oldProps "${src}" COMPILE_FLAGS)
+        if(NOT oldProps)
+          set(newProperties "-include \"${CMAKE_CURRENT_BINARY_DIR}/${_name}\"")
+          set_source_files_properties("${src}" PROPERTIES COMPILE_FLAGS "${newProperties}")
+        else()
+          ocv_debug_message("Skip PCH, flags: ${oldProps} , file: ${src}")
+        endif()
+      endif()
+    endforeach()
+
     ADD_PRECOMPILED_HEADER_TO_TARGET(${_targetName} ${_input}  ${_output} ${_dowarn})
 
 ENDMACRO(ADD_PRECOMPILED_HEADER)
@@ -302,15 +304,7 @@ ENDMACRO(ADD_PRECOMPILED_HEADER)
 MACRO(GET_NATIVE_PRECOMPILED_HEADER _targetName _input)
 
     if(CMAKE_GENERATOR MATCHES "^Visual.*$")
-        set(_dummy_str "#include \"${_input}\"\n")
-
         set(${_targetName}_pch ${CMAKE_CURRENT_BINARY_DIR}/${_targetName}_pch.cpp)
-        if(EXISTS ${${_targetName}_pch})
-            # Check if contents is the same, if not rewrite
-            # todo
-        else()
-            FILE(WRITE ${${_targetName}_pch} ${_dummy_str})
-        endif()
     endif()
 
 ENDMACRO(GET_NATIVE_PRECOMPILED_HEADER)
@@ -330,17 +324,35 @@ MACRO(ADD_NATIVE_PRECOMPILED_HEADER _targetName _input)
         # precompiled is specified at the target level
         # and I don't want to specifiy /F- for each moc/res/ui generated files (using Qt)
 
+        get_target_property(_sources ${_targetName} SOURCES)
+        foreach(src ${_sources})
+          if(NOT "${src}" MATCHES "\\.mm$")
+            get_source_file_property(oldProps "${src}" COMPILE_FLAGS)
+            if(NOT oldProps)
+              set(newProperties "/Yu\"${_input}\" /FI\"${_input}\"")
+              set_source_files_properties("${src}" PROPERTIES COMPILE_FLAGS "${newProperties}")
+            else()
+              ocv_debug_message("Skip PCH, flags: ${oldProps} , file: ${src}")
+            endif()
+          endif()
+        endforeach()
+
+        #also inlude ${oldProps} to have the same compile options
         GET_TARGET_PROPERTY(oldProps ${_targetName} COMPILE_FLAGS)
         if (oldProps MATCHES NOTFOUND)
             SET(oldProps "")
         endif()
-
-        SET(newProperties "${oldProps} /Yu\"${_input}\" /FI\"${_input}\"")
-        SET_TARGET_PROPERTIES(${_targetName} PROPERTIES COMPILE_FLAGS "${newProperties}")
-
-        #also inlude ${oldProps} to have the same compile options
         SET_SOURCE_FILES_PROPERTIES(${${_targetName}_pch} PROPERTIES COMPILE_FLAGS "${oldProps} /Yc\"${_input}\"")
 
+        set(_dummy_str "#include \"${_input}\"\n")
+        set(${_targetName}_pch ${CMAKE_CURRENT_BINARY_DIR}/${_targetName}_pch.cpp)
+        if(EXISTS ${${_targetName}_pch})
+            file(READ "${${_targetName}_pch}" _contents)
+        endif()
+        if(NOT _dummy_str STREQUAL "${_contents}")
+            file(WRITE ${${_targetName}_pch} ${_dummy_str})
+        endif()
+
     elseif (CMAKE_GENERATOR MATCHES Xcode)
 
         # For Xcode, cmake needs my patch to process
diff --git a/cmake/OpenCVUtils.cmake b/cmake/OpenCVUtils.cmake
index 3a23cd7..cdf257d 100644
--- a/cmake/OpenCVUtils.cmake
+++ b/cmake/OpenCVUtils.cmake
@@ -1,11 +1,15 @@
+include(CMakeParseArguments)
+
 # Debugging function
 function(ocv_cmake_dump_vars)
+  set(VARS "")
+  get_cmake_property(_variableNames VARIABLES)
   cmake_parse_arguments(DUMP "" "TOFILE" "" ${ARGN})
   set(regex "${DUMP_UNPARSED_ARGUMENTS}")
-  get_cmake_property(_variableNames VARIABLES)
-  set(VARS "")
+  string(TOLOWER "${regex}" regex_lower)
   foreach(_variableName ${_variableNames})
-    if(_variableName MATCHES "${regex}")
+    string(TOLOWER "${_variableName}" _variableName_lower)
+    if(_variableName MATCHES "${regex}" OR _variableName_lower MATCHES "${regex_lower}")
       set(VARS "${VARS}${_variableName}=${${_variableName}}\n")
     endif()
   endforeach()
@@ -16,6 +20,28 @@ function(ocv_cmake_dump_vars)
   endif()
 endfunction()
 
+function(ocv_cmake_eval var_name)
+  if(DEFINED ${var_name})
+    file(WRITE "${CMAKE_BINARY_DIR}/CMakeCommand-${var_name}.cmake" ${${var_name}})
+    include("${CMAKE_BINARY_DIR}/CMakeCommand-${var_name}.cmake")
+  endif()
+  if(";${ARGN};" MATCHES ";ONCE;")
+    unset(${var_name} CACHE)
+  endif()
+endfunction()
+
+macro(ocv_cmake_configure file_name var_name)
+  configure_file(${file_name} "${CMAKE_BINARY_DIR}/CMakeConfig-${var_name}.cmake" ${ARGN})
+  file(READ "${CMAKE_BINARY_DIR}/CMakeConfig-${var_name}.cmake" ${var_name})
+endmacro()
+
+macro(ocv_update VAR)
+  if(NOT DEFINED ${VAR})
+    set(${VAR} ${ARGN})
+  else()
+    #ocv_debug_message("Preserve old value for ${VAR}: ${${VAR}}")
+  endif()
+endmacro()
 
 # Search packages for host system instead of packages for target system
 # in case of cross compilation thess macro should be defined by toolchain file
@@ -58,6 +84,24 @@ macro(ocv_check_environment_variables)
   endforeach()
 endmacro()
 
+macro(ocv_path_join result_var P1 P2_)
+  string(REGEX REPLACE "^[/]+" "" P2 "${P2_}")
+  if("${P1}" STREQUAL "" OR "${P1}" STREQUAL ".")
+    set(${result_var} "${P2}")
+  elseif("${P1}" STREQUAL "/")
+    set(${result_var} "/${P2}")
+  elseif("${P2}" STREQUAL "")
+    set(${result_var} "${P1}")
+  else()
+    set(${result_var} "${P1}/${P2}")
+  endif()
+  string(REGEX REPLACE "([/\\]?)[\\.][/\\]" "\\1" ${result_var} "${${result_var}}")
+  if("${${result_var}}" STREQUAL "")
+    set(${result_var} ".")
+  endif()
+  #message(STATUS "'${P1}' '${P2_}' => '${${result_var}}'")
+endmacro()
+
 # rename modules target to world if needed
 macro(_ocv_fix_target target_var)
   if(BUILD_opencv_world)
@@ -67,14 +111,29 @@ macro(_ocv_fix_target target_var)
   endif()
 endmacro()
 
+function(ocv_is_opencv_directory result_var dir)
+  get_filename_component(__abs_dir "${dir}" ABSOLUTE)
+  if("${__abs_dir}" MATCHES "^${OpenCV_SOURCE_DIR}"
+      OR "${__abs_dir}" MATCHES "^${OpenCV_BINARY_DIR}"
+      OR (OPENCV_EXTRA_MODULES_PATH AND "${__abs_dir}" MATCHES "^${OPENCV_EXTRA_MODULES_PATH}"))
+    set(${result_var} 1 PARENT_SCOPE)
+  else()
+    set(${result_var} 0 PARENT_SCOPE)
+  endif()
+endfunction()
+
+
 # adds include directories in such way that directories from the OpenCV source tree go first
 function(ocv_include_directories)
   ocv_debug_message("ocv_include_directories( ${ARGN} )")
   set(__add_before "")
   foreach(dir ${ARGN})
-    get_filename_component(__abs_dir "${dir}" ABSOLUTE)
-    if("${__abs_dir}" MATCHES "^${OpenCV_SOURCE_DIR}" OR "${__abs_dir}" MATCHES "^${OpenCV_BINARY_DIR}")
+    ocv_is_opencv_directory(__is_opencv_dir "${dir}")
+    if(__is_opencv_dir)
       list(APPEND __add_before "${dir}")
+    elseif(CMAKE_COMPILER_IS_GNUCXX AND NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS "6.0" AND
+           dir MATCHES "/usr/include$")
+      # workaround for GCC 6.x bug
     else()
       include_directories(AFTER SYSTEM "${dir}")
     endif()
@@ -82,13 +141,28 @@ function(ocv_include_directories)
   include_directories(BEFORE ${__add_before})
 endfunction()
 
+function(ocv_append_target_property target prop)
+  get_target_property(val ${target} ${prop})
+  if(val)
+    set(val "${val} ${ARGN}")
+    set_target_properties(${target} PROPERTIES ${prop} "${val}")
+  else()
+    set_target_properties(${target} PROPERTIES ${prop} "${ARGN}")
+  endif()
+endfunction()
+
 # adds include directories in such way that directories from the OpenCV source tree go first
 function(ocv_target_include_directories target)
   _ocv_fix_target(target)
   set(__params "")
+  if(CMAKE_COMPILER_IS_GNUCXX AND NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS "6.0" AND
+      ";${ARGN};" MATCHES "/usr/include;")
+    return() # workaround for GCC 6.x bug
+  endif()
   foreach(dir ${ARGN})
     get_filename_component(__abs_dir "${dir}" ABSOLUTE)
-    if("${__abs_dir}" MATCHES "^${OpenCV_SOURCE_DIR}" OR "${__abs_dir}" MATCHES "^${OpenCV_BINARY_DIR}")
+    ocv_is_opencv_directory(__is_opencv_dir "${dir}")
+    if(__is_opencv_dir)
       list(APPEND __params "${__abs_dir}")
     else()
       list(APPEND __params "${dir}")
@@ -109,6 +183,7 @@ endfunction()
 # clears all passed variables
 macro(ocv_clear_vars)
   foreach(_var ${ARGN})
+    unset(${_var})
     unset(${_var} CACHE)
   endforeach()
 endmacro()
@@ -124,7 +199,7 @@ set(OCV_COMPILER_FAIL_REGEX
     "[Uu]nknown option"                         # HP
     "[Ww]arning: [Oo]ption"                     # SunPro
     "command option .* is not recognized"       # XL
-    "not supported in this configuration; ignored"       # AIX
+    "not supported in this configuration, ignored"       # AIX (';' is replaced with ',')
     "File with unknown suffix passed to linker" # PGI
     "WARNING: unknown flag:"                    # Open64
   )
@@ -163,12 +238,25 @@ MACRO(ocv_check_compiler_flag LANG FLAG RESULT)
         COMPILE_DEFINITIONS "${FLAG}"
         OUTPUT_VARIABLE OUTPUT)
 
-      FOREACH(_regex ${OCV_COMPILER_FAIL_REGEX})
-        IF("${OUTPUT}" MATCHES "${_regex}")
-          SET(${RESULT} 0)
-          break()
-        ENDIF()
-      ENDFOREACH()
+      if(${RESULT})
+        string(REPLACE ";" "," OUTPUT_LINES "${OUTPUT}")
+        string(REPLACE "\n" ";" OUTPUT_LINES "${OUTPUT_LINES}")
+        foreach(_regex ${OCV_COMPILER_FAIL_REGEX})
+          if(NOT ${RESULT})
+            break()
+          endif()
+          foreach(_line ${OUTPUT_LINES})
+            if("${_line}" MATCHES "${_regex}")
+              file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
+                  "Build output check failed:\n"
+                  "    Regex: '${_regex}'\n"
+                  "    Output line: '${_line}'\n")
+              set(${RESULT} 0)
+              break()
+            endif()
+          endforeach()
+        endforeach()
+      endif()
 
       IF(${RESULT})
         SET(${RESULT} 1 CACHE INTERNAL "Test ${RESULT}")
@@ -176,6 +264,13 @@ MACRO(ocv_check_compiler_flag LANG FLAG RESULT)
       ELSE(${RESULT})
         MESSAGE(STATUS "Performing Test ${RESULT} - Failed")
         SET(${RESULT} "" CACHE INTERNAL "Test ${RESULT}")
+        file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
+            "Compilation failed:\n"
+            "    source file: '${_fname}'\n"
+            "    check option: '${FLAG}'\n"
+            "===== BUILD LOG =====\n"
+            "${OUTPUT}\n"
+            "===== END =====\n\n")
       ENDIF(${RESULT})
     else()
       SET(${RESULT} 0)
@@ -207,6 +302,7 @@ macro(ocv_warnings_disable)
     set(_flag_vars "")
     set(_msvc_warnings "")
     set(_gxx_warnings "")
+    set(_icc_warnings "")
     foreach(arg ${ARGN})
       if(arg MATCHES "^CMAKE_")
         list(APPEND _flag_vars ${arg})
@@ -214,6 +310,8 @@ macro(ocv_warnings_disable)
         list(APPEND _msvc_warnings ${arg})
       elseif(arg MATCHES "^-W")
         list(APPEND _gxx_warnings ${arg})
+      elseif(arg MATCHES "^-wd" OR arg MATCHES "^-Qwd" OR arg MATCHES "^/Qwd")
+        list(APPEND _icc_warnings ${arg})
       endif()
     endforeach()
     if(MSVC AND _msvc_warnings AND _flag_vars)
@@ -236,9 +334,25 @@ macro(ocv_warnings_disable)
         endforeach()
       endforeach()
     endif()
+    if(CV_ICC AND _icc_warnings AND _flag_vars)
+      foreach(var ${_flag_vars})
+        foreach(warning ${_icc_warnings})
+          if(UNIX)
+            string(REPLACE "-Qwd" "-wd" warning "${warning}")
+          else()
+            string(REPLACE "-wd" "-Qwd" warning "${warning}")
+          endif()
+          ocv_check_flag_support(${var} "${warning}" _varname)
+          if(${_varname})
+            set(${var} "${${var}} ${warning}")
+          endif()
+        endforeach()
+      endforeach()
+    endif()
     unset(_flag_vars)
     unset(_msvc_warnings)
     unset(_gxx_warnings)
+    unset(_icc_warnings)
   endif(NOT ENABLE_NOISY_WARNINGS)
 endmacro()
 
@@ -303,6 +417,44 @@ macro(OCV_OPTION variable description value)
   unset(__value)
 endmacro()
 
+# Usage: ocv_append_build_options(HIGHGUI FFMPEG)
+macro(ocv_append_build_options var_prefix pkg_prefix)
+  foreach(suffix INCLUDE_DIRS LIBRARIES LIBRARY_DIRS)
+    if(${pkg_prefix}_${suffix})
+      list(APPEND ${var_prefix}_${suffix} ${${pkg_prefix}_${suffix}})
+      list(REMOVE_DUPLICATES ${var_prefix}_${suffix})
+    endif()
+  endforeach()
+endmacro()
+
+# Usage is similar to CMake 'pkg_check_modules' command
+# It additionally controls HAVE_${define} and ${define}_${modname}_FOUND variables
+macro(ocv_check_modules define)
+  unset(HAVE_${define})
+  foreach(m ${ARGN})
+    if (m MATCHES "(.*[^><])(>=|=|<=)(.*)")
+      set(__modname "${CMAKE_MATCH_1}")
+    else()
+      set(__modname "${m}")
+    endif()
+    unset(${define}_${__modname}_FOUND)
+  endforeach()
+  pkg_check_modules(${define} ${ARGN})
+  if(${define}_FOUND)
+    set(HAVE_${define} 1)
+  endif()
+  foreach(m ${ARGN})
+    if (m MATCHES "(.*[^><])(>=|=|<=)(.*)")
+      set(__modname "${CMAKE_MATCH_1}")
+    else()
+      set(__modname "${m}")
+    endif()
+    if(NOT DEFINED ${define}_${__modname}_FOUND AND ${define}_FOUND)
+      set(${define}_${__modname}_FOUND 1)
+    endif()
+  endforeach()
+endmacro()
+
 
 # Macros that checks if module have been installed.
 # After it adds module to build and define
@@ -341,7 +493,7 @@ macro(CHECK_MODULE module_name define)
 endmacro()
 
 
-set(OPENCV_BUILD_INFO_FILE "${OpenCV_BINARY_DIR}/version_string.tmp")
+set(OPENCV_BUILD_INFO_FILE "${CMAKE_BINARY_DIR}/version_string.tmp")
 file(REMOVE "${OPENCV_BUILD_INFO_FILE}")
 function(ocv_output_status msg)
   message(STATUS "${msg}")
@@ -539,8 +691,11 @@ function(ocv_install_target)
     set(${__package}_TARGETS "${${__package}_TARGETS}" CACHE INTERNAL "List of ${__package} targets")
   endif()
 
-  if(INSTALL_CREATE_DISTRIB)
-    if(MSVC AND NOT BUILD_SHARED_LIBS)
+  if(MSVS)
+    if(NOT INSTALL_IGNORE_PDB AND
+        (INSTALL_PDB OR
+          (INSTALL_CREATE_DISTRIB AND NOT BUILD_SHARED_LIBS)
+        ))
       set(__target "${ARGV0}")
 
       set(isArchive 0)
@@ -568,13 +723,13 @@ function(ocv_install_target)
           get_target_property(fname ${__target} LOCATION_DEBUG)
           if(fname MATCHES "\\.lib$")
             string(REGEX REPLACE "\\.lib$" ".pdb" fname "${fname}")
-            install(FILES "${fname}" DESTINATION "${__dst}" CONFIGURATIONS Debug)
+            install(FILES "${fname}" DESTINATION "${__dst}" CONFIGURATIONS Debug OPTIONAL)
           endif()
 
           get_target_property(fname ${__target} LOCATION_RELEASE)
           if(fname MATCHES "\\.lib$")
             string(REGEX REPLACE "\\.lib$" ".pdb" fname "${fname}")
-            install(FILES "${fname}" DESTINATION "${__dst}" CONFIGURATIONS Release)
+            install(FILES "${fname}" DESTINATION "${__dst}" CONFIGURATIONS Release OPTIONAL)
           endif()
         else()
           # CMake 2.8.12 broke PDB support for STATIC libraries from MSVS, fix was introduced in CMake 3.1.0.
@@ -592,9 +747,9 @@ macro(ocv_parse_header FILENAME FILE_VAR)
   set(__parnet_scope OFF)
   set(__add_cache OFF)
   foreach(name ${ARGN})
-    if("${name}" STREQUAL "PARENT_SCOPE")
+    if(${name} STREQUAL "PARENT_SCOPE")
       set(__parnet_scope ON)
-    elseif("${name}" STREQUAL "CACHE")
+    elseif(${name} STREQUAL "CACHE")
       set(__add_cache ON)
     elseif(vars_regex)
       set(vars_regex "${vars_regex}|${name}")
@@ -608,7 +763,7 @@ macro(ocv_parse_header FILENAME FILE_VAR)
     unset(${FILE_VAR})
   endif()
   foreach(name ${ARGN})
-    if(NOT "${name}" STREQUAL "PARENT_SCOPE" AND NOT "${name}" STREQUAL "CACHE")
+    if(NOT ${name} STREQUAL "PARENT_SCOPE" AND NOT ${name} STREQUAL "CACHE")
       if(${FILE_VAR})
         if(${FILE_VAR} MATCHES ".+[ \t]${name}[ \t]+([0-9]+).*")
           string(REGEX REPLACE ".+[ \t]${name}[ \t]+([0-9]+).*" "\\1" ${name} "${${FILE_VAR}}")
@@ -747,33 +902,23 @@ function(ocv_add_executable target)
 endfunction()
 
 function(ocv_add_library target)
-  set(cuda_objs "")
-  if(HAVE_CUDA)
-    set(cuda_srcs "")
-
-    foreach(var ${ARGN})
-      if(var MATCHES ".cu")
-        list(APPEND cuda_srcs ${var})
-      endif()
-    endforeach()
-
-    if(cuda_srcs)
-      ocv_include_directories(${CUDA_INCLUDE_DIRS})
-      ocv_cuda_compile(cuda_objs ${lib_cuda_srcs} ${lib_cuda_hdrs})
-    endif()
+  if(HAVE_CUDA AND ARGN MATCHES "\\.cu")
+    ocv_include_directories(${CUDA_INCLUDE_DIRS})
+    ocv_cuda_compile(cuda_objs ${ARGN})
     set(OPENCV_MODULE_${target}_CUDA_OBJECTS ${cuda_objs} CACHE INTERNAL "Compiled CUDA object files")
   endif()
 
   add_library(${target} ${ARGN} ${cuda_objs})
 
   # Add OBJECT library (added in cmake 2.8.8) to use in compound modules
-  if (NOT CMAKE_VERSION VERSION_LESS "2.8.8"
+  if (NOT CMAKE_VERSION VERSION_LESS "2.8.8" AND OPENCV_ENABLE_OBJECT_TARGETS
       AND NOT OPENCV_MODULE_${target}_CHILDREN
       AND NOT OPENCV_MODULE_${target}_CLASS STREQUAL "BINDINGS"
       AND NOT ${target} STREQUAL "opencv_ts"
+      AND (NOT BUILD_opencv_world OR NOT HAVE_CUDA)
     )
     set(sources ${ARGN})
-    ocv_list_filterout(sources "\\\\.(cl|inc)$")
+    ocv_list_filterout(sources "\\\\.(cl|inc|cu)$")
     add_library(${target}_object OBJECT ${sources})
     set_target_properties(${target}_object PROPERTIES
       EXCLUDE_FROM_ALL True
@@ -806,7 +951,13 @@ macro(ocv_get_all_libs _modules _extra _3rdparty)
     else()
       set(deps "")
     endif()
-    list(INSERT ${_modules} 0 ${deps} ${m})
+    set(_rev_deps "${deps};${m}")
+    ocv_list_reverse(_rev_deps)
+    foreach (dep ${_rev_deps})
+      if(DEFINED OPENCV_MODULE_${dep}_LOCATION)
+        list(INSERT ${_modules} 0 ${dep})
+      endif()
+    endforeach()
     foreach (dep ${deps} ${OPENCV_LINKER_LIBS})
       if (NOT DEFINED OPENCV_MODULE_${dep}_LOCATION)
         if (TARGET ${dep})
@@ -832,9 +983,6 @@ macro(ocv_get_all_libs _modules _extra _3rdparty)
     endif()
   endif()
 
-  # split 3rdparty libs and modules
-  list(REMOVE_ITEM ${_modules} ${${_3rdparty}} ${${_extra}} non_empty_list)
-
   ocv_list_filterout(${_modules} "^[\$]<")
   ocv_list_filterout(${_3rdparty} "^[\$]<")
   ocv_list_filterout(${_extra} "^[\$]<")
@@ -947,3 +1095,21 @@ function(ocv_add_test_from_target test_name test_kind the_target)
     endif()
   endif()
 endfunction()
+
+macro(ocv_add_testdata basedir dest_subdir)
+  if(BUILD_TESTS)
+    if(NOT CMAKE_CROSSCOMPILING AND NOT INSTALL_TESTS)
+      file(COPY ${basedir}/
+           DESTINATION ${CMAKE_BINARY_DIR}/${OPENCV_TEST_DATA_INSTALL_PATH}/${dest_subdir}
+           ${ARGN}
+      )
+    endif()
+    if(INSTALL_TESTS)
+      install(DIRECTORY ${basedir}/
+              DESTINATION ${OPENCV_TEST_DATA_INSTALL_PATH}/contrib/text
+              COMPONENT "tests"
+              ${ARGN}
+      )
+    endif()
+  endif()
+endmacro()
diff --git a/cmake/checks/ffmpeg_test.cpp b/cmake/checks/ffmpeg_test.cpp
new file mode 100644
index 0000000..7b49c38
--- /dev/null
+++ b/cmake/checks/ffmpeg_test.cpp
@@ -0,0 +1,24 @@
+#include <stdlib.h>
+
+extern "C" {
+#include <libavformat/avformat.h>
+#include <libavcodec/avcodec.h>
+#include <libswscale/swscale.h>
+}
+
+#define CALC_FFMPEG_VERSION(a,b,c) ( a<<16 | b<<8 | c )
+
+static void test()
+{
+  AVFormatContext* c = 0;
+  AVCodec* avcodec = 0;
+  AVFrame* frame = 0;
+
+#if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(52, 111, 0)
+  int err = avformat_open_input(&c, "", NULL, NULL);
+#else
+  int err = av_open_input_file(&c, "", NULL, 0, NULL);
+#endif
+}
+
+int main() { test(); return 0; }
diff --git a/cmake/checks/fp16.cpp b/cmake/checks/fp16.cpp
new file mode 100644
index 0000000..c77c844
--- /dev/null
+++ b/cmake/checks/fp16.cpp
@@ -0,0 +1,33 @@
+#include <stdio.h>
+
+#if defined __F16C__ || (defined _MSC_VER && _MSC_VER >= 1700)
+#include <immintrin.h>
+int test()
+{
+    const float src[] = { 0.0f, 0.0f, 0.0f, 0.0f };
+    short dst[8];
+    __m128 v_src = _mm_load_ps(src);
+    __m128i v_dst = _mm_cvtps_ph(v_src, 0);
+    _mm_storel_epi64((__m128i*)dst, v_dst);
+    return (int)dst[0];
+}
+#elif defined __GNUC__ && (defined __arm__ || defined __aarch64__)
+#include "arm_neon.h"
+int test()
+{
+    const float src[] = { 0.0f, 0.0f, 0.0f, 0.0f };
+    short dst[8];
+    float32x4_t v_src = *(float32x4_t*)src;
+    float16x4_t v_dst = vcvt_f16_f32(v_src);
+    *(float16x4_t*)dst = v_dst;
+    return (int)dst[0];
+}
+#else
+#error "FP16 is not supported"
+#endif
+
+int main()
+{
+  printf("%d\n", test());
+  return 0;
+}
diff --git a/cmake/checks/opencl.cpp b/cmake/checks/opencl.cpp
index 95a36f3..b71b92f 100644
--- a/cmake/checks/opencl.cpp
+++ b/cmake/checks/opencl.cpp
@@ -1,8 +1,5 @@
-#if defined __APPLE__
-#include <OpenCL/cl.h>
-#else
+// custom OpenCL headers are located in "CL" subfolder (3rdparty/include/...)
 #include <CL/cl.h>
-#endif
 
 #ifndef _MSC_VER
 #ifdef CL_VERSION_1_2
diff --git a/cmake/templates/OpenCVConfig-ANDROID.cmake.in b/cmake/templates/OpenCVConfig-ANDROID.cmake.in
new file mode 100644
index 0000000..1787aca
--- /dev/null
+++ b/cmake/templates/OpenCVConfig-ANDROID.cmake.in
@@ -0,0 +1,13 @@
+# Android API level from which OpenCV has been compiled is remembered
+set(OpenCV_ANDROID_NATIVE_API_LEVEL "@OpenCV_ANDROID_NATIVE_API_LEVEL_CONFIGCMAKE@")
+
+# ==============================================================
+#  Check OpenCV availability
+# ==============================================================
+if(OpenCV_ANDROID_NATIVE_API_LEVEL GREATER ANDROID_NATIVE_API_LEVEL)
+  if(NOT OpenCV_FIND_QUIETLY)
+    message(WARNING "Minimum required by OpenCV API level is android-${OpenCV_ANDROID_NATIVE_API_LEVEL}")
+  endif()
+  set(OpenCV_FOUND 0)
+  return()
+endif()
diff --git a/cmake/templates/OpenCVConfig-CUDA.cmake.in b/cmake/templates/OpenCVConfig-CUDA.cmake.in
new file mode 100644
index 0000000..0d261dd
--- /dev/null
+++ b/cmake/templates/OpenCVConfig-CUDA.cmake.in
@@ -0,0 +1,53 @@
+# Version Compute Capability from which OpenCV has been compiled is remembered
+set(OpenCV_COMPUTE_CAPABILITIES "@OpenCV_CUDA_CC@")
+
+set(OpenCV_CUDA_VERSION "@CUDA_VERSION_STRING@")
+set(OpenCV_USE_CUBLAS   "@HAVE_CUBLAS@")
+set(OpenCV_USE_CUFFT    "@HAVE_CUFFT@")
+set(OpenCV_USE_NVCUVID  "@HAVE_NVCUVID@")
+
+if(NOT CUDA_FOUND)
+  find_host_package(CUDA ${OpenCV_CUDA_VERSION} EXACT REQUIRED)
+else()
+  if(NOT CUDA_VERSION_STRING VERSION_EQUAL OpenCV_CUDA_VERSION)
+    message(FATAL_ERROR "OpenCV static library was compiled with CUDA ${OpenCV_CUDA_VERSION} support. Please, use the same version or rebuild OpenCV with CUDA ${CUDA_VERSION_STRING}")
+  endif()
+endif()
+
+set(OpenCV_CUDA_LIBS_ABSPATH ${CUDA_LIBRARIES})
+
+if(${CUDA_VERSION} VERSION_LESS "5.5")
+  list(APPEND OpenCV_CUDA_LIBS_ABSPATH ${CUDA_npp_LIBRARY})
+else()
+  find_cuda_helper_libs(nppc)
+  find_cuda_helper_libs(nppi)
+  find_cuda_helper_libs(npps)
+  list(APPEND OpenCV_CUDA_LIBS_ABSPATH ${CUDA_nppc_LIBRARY} ${CUDA_nppi_LIBRARY} ${CUDA_npps_LIBRARY})
+endif()
+
+if(OpenCV_USE_CUBLAS)
+  list(APPEND OpenCV_CUDA_LIBS_ABSPATH ${CUDA_CUBLAS_LIBRARIES})
+endif()
+
+if(OpenCV_USE_CUFFT)
+  list(APPEND OpenCV_CUDA_LIBS_ABSPATH ${CUDA_CUFFT_LIBRARIES})
+endif()
+
+if(OpenCV_USE_NVCUVID)
+  list(APPEND OpenCV_CUDA_LIBS_ABSPATH ${CUDA_nvcuvid_LIBRARIES})
+endif()
+
+if(WIN32)
+  list(APPEND OpenCV_CUDA_LIBS_ABSPATH ${CUDA_nvcuvenc_LIBRARIES})
+endif()
+
+set(OpenCV_CUDA_LIBS_RELPATH "")
+foreach(l ${OpenCV_CUDA_LIBS_ABSPATH})
+  get_filename_component(_tmp ${l} PATH)
+  if(NOT ${_tmp} MATCHES "-Wl.*")
+    list(APPEND OpenCV_CUDA_LIBS_RELPATH ${_tmp})
+  endif()
+endforeach()
+
+list(REMOVE_DUPLICATES OpenCV_CUDA_LIBS_RELPATH)
+link_directories(${OpenCV_CUDA_LIBS_RELPATH})
diff --git a/cmake/templates/OpenCVConfig-IPPICV.cmake.in b/cmake/templates/OpenCVConfig-IPPICV.cmake.in
new file mode 100644
index 0000000..33cf2d4
--- /dev/null
+++ b/cmake/templates/OpenCVConfig-IPPICV.cmake.in
@@ -0,0 +1,7 @@
+if(NOT TARGET ippicv)
+  add_library(ippicv STATIC IMPORTED)
+  set_target_properties(ippicv PROPERTIES
+    IMPORTED_LINK_INTERFACE_LIBRARIES ""
+    IMPORTED_LOCATION "${OpenCV_INSTALL_PATH}/@IPPICV_INSTALL_PATH_RELATIVE_CONFIGCMAKE@"
+  )
+endif()
diff --git a/cmake/templates/OpenCVConfig.cmake.in b/cmake/templates/OpenCVConfig.cmake.in
index 80ffbaf..47751f5 100644
--- a/cmake/templates/OpenCVConfig.cmake.in
+++ b/cmake/templates/OpenCVConfig.cmake.in
@@ -14,6 +14,10 @@
 #
 #    find_package(OpenCV REQUIRED core videoio)
 #
+#    You can also mark OpenCV components as optional:
+
+#    find_package(OpenCV REQUIRED core OPTIONAL_COMPONENTS viz)
+#
 #    If the module is found then OPENCV_<MODULE>_FOUND is set to TRUE.
 #
 #    This file will define the following variables:
@@ -29,79 +33,70 @@
 #
 #    Advanced variables:
 #      - OpenCV_SHARED                   : Use OpenCV as shared library
-#      - OpenCV_CONFIG_PATH              : Path to this OpenCVConfig.cmake
-#      - OpenCV_INSTALL_PATH             : OpenCV location (not set on Windows)
+#      - OpenCV_INSTALL_PATH             : OpenCV location
 #      - OpenCV_LIB_COMPONENTS           : Present OpenCV modules list
 #      - OpenCV_USE_MANGLED_PATHS        : Mangled OpenCV path flag
-#      - OpenCV_MODULES_SUFFIX           : The suffix for OpenCVModules-XXX.cmake file
 #
 #    Deprecated variables:
 #      - OpenCV_VERSION_TWEAK            : Always "0"
 #
 # ===================================================================================
 
+# ======================================================
+#  Version variables:
+# ======================================================
+SET(OpenCV_VERSION @OPENCV_VERSION_PLAIN@)
+SET(OpenCV_VERSION_MAJOR  @OPENCV_VERSION_MAJOR@)
+SET(OpenCV_VERSION_MINOR  @OPENCV_VERSION_MINOR@)
+SET(OpenCV_VERSION_PATCH  @OPENCV_VERSION_PATCH@)
+SET(OpenCV_VERSION_TWEAK  0)
+SET(OpenCV_VERSION_STATUS "@OPENCV_VERSION_STATUS@")
+
+include(FindPackageHandleStandardArgs)
+
+if(NOT CMAKE_VERSION VERSION_LESS 2.8.8
+    AND OpenCV_FIND_COMPONENTS  # prevent excessive output
+)
+  # HANDLE_COMPONENTS was introduced in CMake 2.8.8
+  list(APPEND _OpenCV_FPHSA_ARGS HANDLE_COMPONENTS)
+  # The missing components will be handled by the FindPackageHandleStandardArgs
+  # module.
+  set(_OpenCV_HANDLE_COMPONENTS_MANUALLY FALSE)
+else()
+  # The missing components will be handled by this config.
+  set(_OpenCV_HANDLE_COMPONENTS_MANUALLY TRUE)
+endif()
+
+# Extract directory name from full path of the file currently being processed.
+# Note that CMake 2.8.3 introduced CMAKE_CURRENT_LIST_DIR. We reimplement it
+# for older versions of CMake to support these as well.
+if(CMAKE_VERSION VERSION_LESS "2.8.3")
+  get_filename_component(CMAKE_CURRENT_LIST_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH)
+endif()
+
+# Extract the directory where *this* file has been installed (determined at cmake run-time)
+# Get the absolute path with no ../.. relative marks, to eliminate implicit linker warnings
+set(OpenCV_CONFIG_PATH "${CMAKE_CURRENT_LIST_DIR}")
+get_filename_component(OpenCV_INSTALL_PATH "${OpenCV_CONFIG_PATH}/@OpenCV_INSTALL_PATH_RELATIVE_CONFIGCMAKE@" REALPATH)
+
 # Search packages for host system instead of packages for target system.
 # in case of cross compilation thess macro should be defined by toolchain file
-
 if(NOT COMMAND find_host_package)
     macro(find_host_package)
         find_package(${ARGN})
     endmacro()
 endif()
-
 if(NOT COMMAND find_host_program)
     macro(find_host_program)
         find_program(${ARGN})
     endmacro()
 endif()
 
-if(NOT DEFINED OpenCV_MODULES_SUFFIX)
-  if(ANDROID)
-    string(REPLACE - _ OpenCV_MODULES_SUFFIX "_${ANDROID_NDK_ABI_NAME}")
-  else()
-    set(OpenCV_MODULES_SUFFIX "")
-  endif()
-endif()
-
-if("@USE_IPPICV@" STREQUAL "TRUE") # value is defined by package builder (use STREQUAL to comply new CMake policy CMP0012)
-  if(NOT TARGET ippicv)
-    if(EXISTS "${CMAKE_CURRENT_LIST_DIR}/@INSTALL_PATH_RELATIVE_IPPICV@")
-      add_library(ippicv STATIC IMPORTED)
-      set_target_properties(ippicv PROPERTIES
-        IMPORTED_LINK_INTERFACE_LIBRARIES ""
-        IMPORTED_LOCATION "${CMAKE_CURRENT_LIST_DIR}/@INSTALL_PATH_RELATIVE_IPPICV@"
-      )
-    endif()
-  endif()
-endif()
-
-if(NOT TARGET opencv_core)
-  # Extract directory name from full path of the file currently being processed.
-  # Note that CMake 2.8.3 introduced CMAKE_CURRENT_LIST_DIR. We reimplement it
-  # for older versions of CMake to support these as well.
-  if(CMAKE_VERSION VERSION_LESS "2.8.3")
-    get_filename_component(CMAKE_CURRENT_LIST_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH)
-  endif()
-
-  include(${CMAKE_CURRENT_LIST_DIR}/OpenCVModules${OpenCV_MODULES_SUFFIX}.cmake)
-endif()
-
-# TODO All things below should be reviewed. What is about of moving this code into related modules (special vars/hooks/files)
 
-# Version Compute Capability from which OpenCV has been compiled is remembered
-set(OpenCV_COMPUTE_CAPABILITIES @OpenCV_CUDA_CC_CONFIGCMAKE@)
+ at CUDA_CONFIGCMAKE@
+ at ANDROID_CONFIGCMAKE@
 
-set(OpenCV_CUDA_VERSION @OpenCV_CUDA_VERSION@)
-set(OpenCV_USE_CUBLAS   @HAVE_CUBLAS@)
-set(OpenCV_USE_CUFFT    @HAVE_CUFFT@)
-set(OpenCV_USE_NVCUVID  @HAVE_NVCUVID@)
-
-# Android API level from which OpenCV has been compiled is remembered
-if(ANDROID)
-  set(OpenCV_ANDROID_NATIVE_API_LEVEL @OpenCV_ANDROID_NATIVE_API_LEVEL_CONFIGCMAKE@)
-else()
-  set(OpenCV_ANDROID_NATIVE_API_LEVEL 0)
-endif()
+ at IPPICV_CONFIGCMAKE@
 
 # Some additional settings are required if OpenCV is built as static libs
 set(OpenCV_SHARED @BUILD_SHARED_LIBS@)
@@ -109,73 +104,11 @@ set(OpenCV_SHARED @BUILD_SHARED_LIBS@)
 # Enables mangled install paths, that help with side by side installs
 set(OpenCV_USE_MANGLED_PATHS @OpenCV_USE_MANGLED_PATHS_CONFIGCMAKE@)
 
-# Extract the directory where *this* file has been installed (determined at cmake run-time)
-get_filename_component(OpenCV_CONFIG_PATH "${CMAKE_CURRENT_LIST_FILE}" PATH CACHE)
-
-if(NOT WIN32 OR ANDROID)
-  if(ANDROID)
-    set(OpenCV_INSTALL_PATH "${OpenCV_CONFIG_PATH}/../../..")
-  else()
-    set(OpenCV_INSTALL_PATH "${OpenCV_CONFIG_PATH}/../..")
-  endif()
-  # Get the absolute path with no ../.. relative marks, to eliminate implicit linker warnings
-  if(${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION} VERSION_LESS 2.8)
-    get_filename_component(OpenCV_INSTALL_PATH "${OpenCV_INSTALL_PATH}" ABSOLUTE)
-  else()
-    get_filename_component(OpenCV_INSTALL_PATH "${OpenCV_INSTALL_PATH}" REALPATH)
-  endif()
-endif()
-
-# ======================================================
-# Include directories to add to the user project:
-# ======================================================
-
-# Provide the include directories to the caller
+set(OpenCV_LIB_COMPONENTS @OPENCV_MODULES_CONFIGCMAKE@)
 set(OpenCV_INCLUDE_DIRS @OpenCV_INCLUDE_DIRS_CONFIGCMAKE@)
 
-# ======================================================
-# Link directories to add to the user project:
-# ======================================================
-
-# Provide the libs directories to the caller
-set(OpenCV_LIB_DIR_OPT @OpenCV_LIB_DIRS_CONFIGCMAKE@ CACHE PATH "Path where release OpenCV libraries are located")
-set(OpenCV_LIB_DIR_DBG @OpenCV_LIB_DIRS_CONFIGCMAKE@ CACHE PATH "Path where debug OpenCV libraries are located")
-set(OpenCV_3RDPARTY_LIB_DIR_OPT @OpenCV_3RDPARTY_LIB_DIRS_CONFIGCMAKE@ CACHE PATH "Path where release 3rdparty OpenCV dependencies are located")
-set(OpenCV_3RDPARTY_LIB_DIR_DBG @OpenCV_3RDPARTY_LIB_DIRS_CONFIGCMAKE@ CACHE PATH "Path where debug 3rdparty OpenCV dependencies are located")
-mark_as_advanced(FORCE OpenCV_LIB_DIR_OPT OpenCV_LIB_DIR_DBG OpenCV_3RDPARTY_LIB_DIR_OPT OpenCV_3RDPARTY_LIB_DIR_DBG OpenCV_CONFIG_PATH)
-
-# ======================================================
-#  Version variables:
-# ======================================================
-SET(OpenCV_VERSION @OPENCV_VERSION_PLAIN@)
-SET(OpenCV_VERSION_MAJOR  @OPENCV_VERSION_MAJOR@)
-SET(OpenCV_VERSION_MINOR  @OPENCV_VERSION_MINOR@)
-SET(OpenCV_VERSION_PATCH  @OPENCV_VERSION_PATCH@)
-SET(OpenCV_VERSION_TWEAK  0)
-SET(OpenCV_VERSION_STATUS "@OPENCV_VERSION_STATUS@")
-
-# ====================================================================
-# Link libraries: e.g. opencv_core;opencv_imgproc; etc...
-# ====================================================================
-
-SET(OpenCV_LIB_COMPONENTS @OPENCV_MODULES_CONFIGCMAKE@)
-list(REMOVE_ITEM OpenCV_LIB_COMPONENTS opencv_hal)
-SET(OpenCV_WORLD_COMPONENTS @OPENCV_WORLD_MODULES@)
-
-# ==============================================================
-#  Extra include directories, needed by OpenCV 2 new structure
-# ==============================================================
-SET(OpenCV2_INCLUDE_DIRS @OpenCV2_INCLUDE_DIRS_CONFIGCMAKE@)
-if(OpenCV2_INCLUDE_DIRS)
-  list(APPEND OpenCV_INCLUDE_DIRS ${OpenCV2_INCLUDE_DIRS})
-
-  set(OpenCV_ADD_DEBUG_RELEASE @OpenCV_ADD_DEBUG_RELEASE_CONFIGCMAKE@)
-  if(OpenCV_ADD_DEBUG_RELEASE)
-    set(OpenCV_LIB_DIR_OPT "${OpenCV_LIB_DIR_OPT}/Release")
-    set(OpenCV_LIB_DIR_DBG "${OpenCV_LIB_DIR_DBG}/Debug")
-    set(OpenCV_3RDPARTY_LIB_DIR_OPT "${OpenCV_3RDPARTY_LIB_DIR_OPT}/Release")
-    set(OpenCV_3RDPARTY_LIB_DIR_DBG "${OpenCV_3RDPARTY_LIB_DIR_DBG}/Debug")
-  endif()
+if(NOT TARGET opencv_core)
+  include(${CMAKE_CURRENT_LIST_DIR}/OpenCVModules${OpenCV_MODULES_SUFFIX}.cmake)
 endif()
 
 if(NOT CMAKE_VERSION VERSION_LESS "2.8.11")
@@ -193,22 +126,6 @@ if(NOT CMAKE_VERSION VERSION_LESS "2.8.11")
 endif()
 
 # ==============================================================
-#  Check OpenCV availability
-# ==============================================================
-if(ANDROID AND OpenCV_ANDROID_NATIVE_API_LEVEL GREATER ANDROID_NATIVE_API_LEVEL)
-  message(FATAL_ERROR "Minimum required by OpenCV API level is android-${OpenCV_ANDROID_NATIVE_API_LEVEL}")
-  #always FATAL_ERROR because we can't say to the caller that OpenCV is not found
-  #http://www.mail-archive.com/cmake@cmake.org/msg37831.html
-  if(OpenCV_FIND_REQUIRED)
-    message(FATAL_ERROR "Minimum required by OpenCV API level is android-${OpenCV_ANDROID_NATIVE_API_LEVEL}")
-  elseif(NOT OpenCV_FIND_QUIETLY)
-    message(WARNING "Minimum required by OpenCV API level is android-${OpenCV_ANDROID_NATIVE_API_LEVEL}")
-  endif()
-  set(OpenCV_FOUND "OpenCV_FOUND-NOTFOUND")
-  return()#Android toolchain requires CMake > 2.6
-endif()
-
-# ==============================================================
 #  Form list of modules (components) to find
 # ==============================================================
 if(NOT OpenCV_FIND_COMPONENTS)
@@ -219,25 +136,36 @@ if(NOT OpenCV_FIND_COMPONENTS)
   endif()
 endif()
 
+set(OpenCV_WORLD_COMPONENTS @OPENCV_WORLD_MODULES@)
+
 # expand short module names and see if requested components exist
-set(OpenCV_FIND_COMPONENTS_ "")
 foreach(__cvcomponent ${OpenCV_FIND_COMPONENTS})
+  # Store the name of the original component so we can set the
+  # OpenCV_<component>_FOUND variable which can be checked by the user.
+  set (__original_cvcomponent ${__cvcomponent})
   if(NOT __cvcomponent MATCHES "^opencv_")
     set(__cvcomponent opencv_${__cvcomponent})
   endif()
   list(FIND OpenCV_LIB_COMPONENTS ${__cvcomponent} __cvcomponentIdx)
   if(__cvcomponentIdx LESS 0)
-    #requested component is not found...
-    if(OpenCV_FIND_REQUIRED)
-      message(FATAL_ERROR "${__cvcomponent} is required but was not found")
-    elseif(NOT OpenCV_FIND_QUIETLY)
-      message(WARNING "${__cvcomponent} is required but was not found")
-    endif()
+    if(_OpenCV_HANDLE_COMPONENTS_MANUALLY)
+      # Either the component is required or the user did not set any components at
+      # all. In the latter case, the OpenCV_FIND_REQUIRED_<component> variable
+      # will not be defined since it is not set by this config. So let's assume
+      # the implicitly set components are always required.
+      if(NOT DEFINED OpenCV_FIND_REQUIRED_${__original_cvcomponent} OR
+          OpenCV_FIND_REQUIRED_${__original_cvcomponent})
+        message(FATAL_ERROR "${__cvcomponent} is required but was not found")
+      elseif(NOT OpenCV_FIND_QUIETLY)
+        # The component was marked as optional using OPTIONAL_COMPONENTS
+        message(WARNING "Optional component ${__cvcomponent} was not found")
+      endif()
+    endif(_OpenCV_HANDLE_COMPONENTS_MANUALLY)
     #indicate that module is NOT found
     string(TOUPPER "${__cvcomponent}" __cvcomponentUP)
     set(${__cvcomponentUP}_FOUND "${__cvcomponentUP}_FOUND-NOTFOUND")
+    set(OpenCV_${__original_cvcomponent}_FOUND FALSE)
   else()
-    list(APPEND OpenCV_FIND_COMPONENTS_ ${__cvcomponent})
     # Not using list(APPEND) here, because OpenCV_LIBS may not exist yet.
     # Also not clearing OpenCV_LIBS anywhere, so that multiple calls
     # to find_package(OpenCV) with different component lists add up.
@@ -245,6 +173,7 @@ foreach(__cvcomponent ${OpenCV_FIND_COMPONENTS})
     #indicate that module is found
     string(TOUPPER "${__cvcomponent}" __cvcomponentUP)
     set(${__cvcomponentUP}_FOUND 1)
+    set(OpenCV_${__original_cvcomponent}_FOUND TRUE)
   endif()
   if(OpenCV_SHARED AND ";${OpenCV_WORLD_COMPONENTS};" MATCHES ";${__cvcomponent};" AND NOT TARGET ${__cvcomponent})
     get_target_property(__implib_dbg opencv_world IMPORTED_IMPLIB_DEBUG)
@@ -270,91 +199,12 @@ foreach(__cvcomponent ${OpenCV_FIND_COMPONENTS})
     endif()
   endif()
 endforeach()
-set(OpenCV_FIND_COMPONENTS ${OpenCV_FIND_COMPONENTS_})
-
-# ==============================================================
-#  Resolve dependencies
-# ==============================================================
-if(OpenCV_USE_MANGLED_PATHS)
-  set(OpenCV_LIB_SUFFIX ".${OpenCV_VERSION_MAJOR}.${OpenCV_VERSION_MINOR}.${OpenCV_VERSION_PATCH}")
-else()
-  set(OpenCV_LIB_SUFFIX "")
-endif()
-
-foreach(__opttype OPT DBG)
-  SET(OpenCV_LIBS_${__opttype} "${OpenCV_LIBS}")
-  SET(OpenCV_EXTRA_LIBS_${__opttype} "")
-
-  # CUDA
-  if(OpenCV_CUDA_VERSION)
-    if(NOT CUDA_FOUND)
-      find_host_package(CUDA ${OpenCV_CUDA_VERSION} EXACT REQUIRED)
-    else()
-      if(NOT CUDA_VERSION_STRING VERSION_EQUAL OpenCV_CUDA_VERSION)
-        message(FATAL_ERROR "OpenCV static library was compiled with CUDA ${OpenCV_CUDA_VERSION} support. Please, use the same version or rebuild OpenCV with CUDA ${CUDA_VERSION_STRING}")
-      endif()
-    endif()
-
-    set(OpenCV_CUDA_LIBS_ABSPATH ${CUDA_LIBRARIES})
-
-    if(${CUDA_VERSION} VERSION_LESS "5.5")
-      list(APPEND OpenCV_CUDA_LIBS_ABSPATH ${CUDA_npp_LIBRARY})
-    else()
-      find_cuda_helper_libs(nppc)
-      find_cuda_helper_libs(nppi)
-      find_cuda_helper_libs(npps)
-      list(APPEND OpenCV_CUDA_LIBS_ABSPATH ${CUDA_nppc_LIBRARY} ${CUDA_nppi_LIBRARY} ${CUDA_npps_LIBRARY})
-    endif()
-
-    if(OpenCV_USE_CUBLAS)
-      list(APPEND OpenCV_CUDA_LIBS_ABSPATH ${CUDA_CUBLAS_LIBRARIES})
-    endif()
-
-    if(OpenCV_USE_CUFFT)
-      list(APPEND OpenCV_CUDA_LIBS_ABSPATH ${CUDA_CUFFT_LIBRARIES})
-    endif()
-
-    if(OpenCV_USE_NVCUVID)
-      list(APPEND OpenCV_CUDA_LIBS_ABSPATH ${CUDA_nvcuvid_LIBRARIES})
-    endif()
-
-    if(WIN32)
-      list(APPEND OpenCV_CUDA_LIBS_ABSPATH ${CUDA_nvcuvenc_LIBRARIES})
-    endif()
-
-    set(OpenCV_CUDA_LIBS_RELPATH "")
-    foreach(l ${OpenCV_CUDA_LIBS_ABSPATH})
-      get_filename_component(_tmp ${l} PATH)
-      if(NOT ${_tmp} MATCHES "-Wl.*")
-          list(APPEND OpenCV_CUDA_LIBS_RELPATH ${_tmp})
-      endif()
-    endforeach()
-
-    list(REMOVE_DUPLICATES OpenCV_CUDA_LIBS_RELPATH)
-    link_directories(${OpenCV_CUDA_LIBS_RELPATH})
-  endif()
-endforeach()
 
 # ==============================================================
 # Compatibility stuff
 # ==============================================================
-if(CMAKE_BUILD_TYPE MATCHES "Debug")
-  SET(OpenCV_LIB_DIR ${OpenCV_LIB_DIR_DBG} ${OpenCV_3RDPARTY_LIB_DIR_DBG})
-else()
-  SET(OpenCV_LIB_DIR ${OpenCV_LIB_DIR_OPT} ${OpenCV_3RDPARTY_LIB_DIR_OPT})
-endif()
 set(OpenCV_LIBRARIES ${OpenCV_LIBS})
 
-if(CMAKE_CROSSCOMPILING AND OpenCV_SHARED AND (CMAKE_SYSTEM_NAME MATCHES "Linux"))
-  foreach(dir ${OpenCV_LIB_DIR})
-    set(CMAKE_EXE_LINKER_FLAGS    "${CMAKE_EXE_LINKER_FLAGS}    -Wl,-rpath-link,${dir}")
-    set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,-rpath-link,${dir}")
-    set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -Wl,-rpath-link,${dir}")
-  endforeach()
-endif()
-
-
-
 #
 # Some macroses for samples
 #
@@ -372,7 +222,7 @@ endmacro()
 # adds include directories in such way that directories from the OpenCV source tree go first
 function(ocv_include_directories)
   set(__add_before "")
-  file(TO_CMAKE_PATH "${OpenCV_DIR}" __baseDir)
+  file(TO_CMAKE_PATH "${OpenCV_INSTALL_PATH}" __baseDir)
   foreach(dir ${ARGN})
     get_filename_component(__abs_dir "${dir}" ABSOLUTE)
     if("${__abs_dir}" MATCHES "^${__baseDir}")
@@ -404,3 +254,8 @@ macro(ocv_list_filterout lst regex)
     endif()
   endforeach()
 endmacro()
+
+# We do not actually need REQUIRED_VARS to be checked for. Just use the
+# installation directory for the status.
+find_package_handle_standard_args(OpenCV REQUIRED_VARS OpenCV_INSTALL_PATH
+                                  VERSION_VAR OpenCV_VERSION ${_OpenCV_FPHSA_ARGS})
diff --git a/cmake/templates/OpenCVConfig.root-ANDROID.cmake.in b/cmake/templates/OpenCVConfig.root-ANDROID.cmake.in
new file mode 100644
index 0000000..7ceeec4
--- /dev/null
+++ b/cmake/templates/OpenCVConfig.root-ANDROID.cmake.in
@@ -0,0 +1,50 @@
+# ===================================================================================
+#  The OpenCV CMake configuration file
+#
+#             ** File generated automatically, do not modify **
+#
+#  Usage from an external project:
+#    In your CMakeLists.txt, add these lines:
+#
+#    find_package(OpenCV REQUIRED)
+#    include_directories(${OpenCV_INCLUDE_DIRS}) # Not needed for CMake >= 2.8.11
+#    target_link_libraries(MY_TARGET_NAME ${OpenCV_LIBS})
+#
+#    Or you can search for specific OpenCV modules:
+#
+#    find_package(OpenCV REQUIRED core videoio)
+#
+#    If the module is found then OPENCV_<MODULE>_FOUND is set to TRUE.
+#
+#    This file will define the following variables:
+#      - OpenCV_LIBS                     : The list of all imported targets for OpenCV modules.
+#      - OpenCV_INCLUDE_DIRS             : The OpenCV include directories.
+#      - OpenCV_ANDROID_NATIVE_API_LEVEL : Minimum required level of Android API.
+#      - OpenCV_VERSION                  : The version of this OpenCV build: "@OPENCV_VERSION_PLAIN@"
+#      - OpenCV_VERSION_MAJOR            : Major version part of OpenCV_VERSION: "@OPENCV_VERSION_MAJOR@"
+#      - OpenCV_VERSION_MINOR            : Minor version part of OpenCV_VERSION: "@OPENCV_VERSION_MINOR@"
+#      - OpenCV_VERSION_PATCH            : Patch version part of OpenCV_VERSION: "@OPENCV_VERSION_PATCH@"
+#      - OpenCV_VERSION_STATUS           : Development status of this build: "@OPENCV_VERSION_STATUS@"
+#
+# ===================================================================================
+
+# Extract directory name from full path of the file currently being processed.
+# Note that CMake 2.8.3 introduced CMAKE_CURRENT_LIST_DIR. We reimplement it
+# for older versions of CMake to support these as well.
+if(CMAKE_VERSION VERSION_LESS "2.8.3")
+  get_filename_component(CMAKE_CURRENT_LIST_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH)
+endif()
+
+if(NOT DEFINED OpenCV_CONFIG_SUBDIR)
+  set(OpenCV_CONFIG_SUBDIR "/abi-${ANDROID_NDK_ABI_NAME}")
+endif()
+
+set(OpenCV_CONFIG_PATH "${CMAKE_CURRENT_LIST_DIR}${OpenCV_CONFIG_SUBDIR}")
+if(EXISTS "${OpenCV_CONFIG_PATH}/OpenCVConfig.cmake")
+  include("${OpenCV_CONFIG_PATH}/OpenCVConfig.cmake")
+else()
+  if(NOT OpenCV_FIND_QUIETLY)
+    message(WARNING "Found OpenCV Android Pack but it has no binaries compatible with your ABI (can't find: ${OpenCV_CONFIG_SUBDIR})")
+  endif()
+  set(OpenCV_FOUND FALSE)
+endif()
diff --git a/cmake/templates/OpenCVConfig.root-WIN32.cmake.in b/cmake/templates/OpenCVConfig.root-WIN32.cmake.in
new file mode 100644
index 0000000..bd98b71
--- /dev/null
+++ b/cmake/templates/OpenCVConfig.root-WIN32.cmake.in
@@ -0,0 +1,144 @@
+# ===================================================================================
+#  The OpenCV CMake configuration file
+#
+#             ** File generated automatically, do not modify **
+#
+#  Usage from an external project:
+#    In your CMakeLists.txt, add these lines:
+#
+#    FIND_PACKAGE(OpenCV REQUIRED)
+#    TARGET_LINK_LIBRARIES(MY_TARGET_NAME ${OpenCV_LIBS})
+#
+#    Or you can search for specific OpenCV modules:
+#
+#    FIND_PACKAGE(OpenCV REQUIRED core imgcodecs)
+#
+#    If the module is found then OPENCV_<MODULE>_FOUND is set to TRUE.
+#
+#    This file will define the following variables:
+#      - OpenCV_LIBS                     : The list of libraries to link against.
+#      - OpenCV_INCLUDE_DIRS             : The OpenCV include directories.
+#      - OpenCV_COMPUTE_CAPABILITIES     : The version of compute capability
+#      - OpenCV_VERSION                  : The version of this OpenCV build: "@OPENCV_VERSION_PLAIN@"
+#      - OpenCV_VERSION_MAJOR            : Major version part of OpenCV_VERSION: "@OPENCV_VERSION_MAJOR@"
+#      - OpenCV_VERSION_MINOR            : Minor version part of OpenCV_VERSION: "@OPENCV_VERSION_MINOR@"
+#      - OpenCV_VERSION_PATCH            : Patch version part of OpenCV_VERSION: "@OPENCV_VERSION_PATCH@"
+#      - OpenCV_VERSION_STATUS           : Development status of this build: "@OPENCV_VERSION_STATUS@"
+#
+#    Advanced variables:
+#      - OpenCV_SHARED
+#
+# ===================================================================================
+#
+#    Windows pack specific options:
+#      - OpenCV_STATIC
+#      - OpenCV_CUDA
+
+if(CMAKE_VERSION VERSION_GREATER 2.6)
+  get_property(OpenCV_LANGUAGES GLOBAL PROPERTY ENABLED_LANGUAGES)
+  if(NOT ";${OpenCV_LANGUAGES};" MATCHES ";CXX;")
+    enable_language(CXX)
+  endif()
+endif()
+
+if(NOT DEFINED OpenCV_STATIC)
+  # look for global setting
+  if(BUILD_SHARED_LIBS)
+    set(OpenCV_STATIC OFF)
+  else()
+    set(OpenCV_STATIC ON)
+  endif()
+endif()
+
+if(NOT DEFINED OpenCV_CUDA)
+  # if user' app uses CUDA, then it probably wants CUDA-enabled OpenCV binaries
+  if(CUDA_FOUND)
+    set(OpenCV_CUDA ON)
+  endif()
+endif()
+
+if(MSVC)
+  if(CMAKE_CL_64)
+    set(OpenCV_ARCH x64)
+  elseif((CMAKE_GENERATOR MATCHES "ARM") OR ("${arch_hint}" STREQUAL "ARM") OR (CMAKE_VS_EFFECTIVE_PLATFORMS MATCHES "ARM|arm"))
+    # see Modules/CmakeGenericSystem.cmake
+    set(OpenCV_ARCH ARM)
+  else()
+    set(OpenCV_ARCH x86)
+  endif()
+  if(MSVC_VERSION EQUAL 1400)
+    set(OpenCV_RUNTIME vc8)
+  elseif(MSVC_VERSION EQUAL 1500)
+    set(OpenCV_RUNTIME vc9)
+  elseif(MSVC_VERSION EQUAL 1600)
+    set(OpenCV_RUNTIME vc10)
+  elseif(MSVC_VERSION EQUAL 1700)
+    set(OpenCV_RUNTIME vc11)
+  elseif(MSVC_VERSION EQUAL 1800)
+    set(OpenCV_RUNTIME vc12)
+  elseif(MSVC_VERSION EQUAL 1900)
+    set(OpenCV_RUNTIME vc14)
+  elseif(MSVC_VERSION EQUAL 1910)
+    set(OpenCV_RUNTIME vc15)
+  endif()
+elseif(MINGW)
+  set(OpenCV_RUNTIME mingw)
+
+  execute_process(COMMAND ${CMAKE_CXX_COMPILER} -dumpmachine
+                  OUTPUT_VARIABLE OPENCV_GCC_TARGET_MACHINE
+                  OUTPUT_STRIP_TRAILING_WHITESPACE)
+  if(OPENCV_GCC_TARGET_MACHINE MATCHES "amd64|x86_64|AMD64")
+    set(MINGW64 1)
+    set(OpenCV_ARCH x64)
+  else()
+    set(OpenCV_ARCH x86)
+  endif()
+endif()
+
+if(NOT OpenCV_FIND_QUIETLY)
+  message(STATUS "OpenCV ARCH: ${OpenCV_ARCH}")
+  message(STATUS "OpenCV RUNTIME: ${OpenCV_RUNTIME}")
+  message(STATUS "OpenCV STATIC: ${OpenCV_STATIC}")
+endif()
+
+get_filename_component(OpenCV_CONFIG_PATH "${CMAKE_CURRENT_LIST_FILE}" PATH)
+if(OpenCV_RUNTIME AND OpenCV_ARCH)
+  if(OpenCV_STATIC AND EXISTS "${OpenCV_CONFIG_PATH}/${OpenCV_ARCH}/${OpenCV_RUNTIME}/staticlib/OpenCVConfig.cmake")
+    if(OpenCV_CUDA AND EXISTS "${OpenCV_CONFIG_PATH}/gpu/${OpenCV_ARCH}/${OpenCV_RUNTIME}/staticlib/OpenCVConfig.cmake")
+      set(OpenCV_LIB_PATH "${OpenCV_CONFIG_PATH}/gpu/${OpenCV_ARCH}/${OpenCV_RUNTIME}/staticlib")
+    else()
+      set(OpenCV_LIB_PATH "${OpenCV_CONFIG_PATH}/${OpenCV_ARCH}/${OpenCV_RUNTIME}/staticlib")
+    endif()
+  elseif(EXISTS "${OpenCV_CONFIG_PATH}/${OpenCV_ARCH}/${OpenCV_RUNTIME}/lib/OpenCVConfig.cmake")
+    if(OpenCV_CUDA AND EXISTS "${OpenCV_CONFIG_PATH}/gpu/${OpenCV_ARCH}/${OpenCV_RUNTIME}/lib/OpenCVConfig.cmake")
+      set(OpenCV_LIB_PATH "${OpenCV_CONFIG_PATH}/gpu/${OpenCV_ARCH}/${OpenCV_RUNTIME}/lib")
+    else()
+      set(OpenCV_LIB_PATH "${OpenCV_CONFIG_PATH}/${OpenCV_ARCH}/${OpenCV_RUNTIME}/lib")
+    endif()
+  endif()
+endif()
+
+if(OpenCV_LIB_PATH AND EXISTS "${OpenCV_LIB_PATH}/OpenCVConfig.cmake")
+  include("${OpenCV_LIB_PATH}/OpenCVConfig.cmake")
+
+  if(NOT OpenCV_FIND_QUIETLY)
+    message(STATUS "Found OpenCV ${OpenCV_VERSION} in ${OpenCV_LIB_PATH}")
+    if(NOT OpenCV_LIB_PATH MATCHES "/staticlib")
+      get_filename_component(_OpenCV_LIB_PATH "${OpenCV_LIB_PATH}/../bin" ABSOLUTE)
+      file(TO_NATIVE_PATH "${_OpenCV_LIB_PATH}" _OpenCV_LIB_PATH)
+      message(STATUS "You might need to add ${_OpenCV_LIB_PATH} to your PATH to be able to run your applications.")
+      if(OpenCV_LIB_PATH MATCHES "/gpu/")
+        string(REPLACE "\\gpu" "" _OpenCV_LIB_PATH2 "${_OpenCV_LIB_PATH}")
+        message(STATUS "GPU support is enabled so you might also need ${_OpenCV_LIB_PATH2} in your PATH (it must go after the ${_OpenCV_LIB_PATH}).")
+      endif()
+    endif()
+  endif()
+else()
+  if(NOT OpenCV_FIND_QUIETLY)
+    message(WARNING
+"Found OpenCV Windows Pack but it has no binaries compatible with your configuration.
+You should manually point CMake variable OpenCV_DIR to your build of OpenCV library."
+    )
+  endif()
+  set(OpenCV_FOUND FALSE)
+endif()
diff --git a/cmake/templates/custom_hal.hpp.in b/cmake/templates/custom_hal.hpp.in
index f1c6515..c62f17d 100644
--- a/cmake/templates/custom_hal.hpp.in
+++ b/cmake/templates/custom_hal.hpp.in
@@ -1,6 +1,6 @@
 #ifndef _CUSTOM_HAL_INCLUDED_
 #define _CUSTOM_HAL_INCLUDED_
 
- at _includes@
+ at _hal_includes@
 
 #endif
diff --git a/cmake/templates/cvconfig.h.in b/cmake/templates/cvconfig.h.in
index 6083729..05add9e 100644
--- a/cmake/templates/cvconfig.h.in
+++ b/cmake/templates/cvconfig.h.in
@@ -71,12 +71,6 @@
 /* FFMpeg video library */
 #cmakedefine HAVE_FFMPEG
 
-/* ffmpeg's libswscale */
-#cmakedefine HAVE_FFMPEG_SWSCALE
-
-/* ffmpeg in Gentoo */
-#cmakedefine HAVE_GENTOO_FFMPEG
-
 /* Geospatial Data Abstraction Library */
 #cmakedefine HAVE_GDAL
 
@@ -111,6 +105,9 @@
 /* libpng/png.h needs to be included */
 #cmakedefine HAVE_LIBPNG_PNG_H
 
+/* GDCM DICOM codec */
+#cmakedefine HAVE_GDCM
+
 /* V4L/V4L2 capturing support via libv4l */
 #cmakedefine HAVE_LIBV4L
 
@@ -120,6 +117,9 @@
 /* NVidia Video Decoding API*/
 #cmakedefine HAVE_NVCUVID
 
+/* NVidia Video Encoding API*/
+#cmakedefine HAVE_NVCUVENC
+
 /* OpenCL Support */
 #cmakedefine HAVE_OPENCL
 #cmakedefine HAVE_OPENCL_STATIC
@@ -194,3 +194,15 @@
 
 /* Intel VA-API/OpenCL */
 #cmakedefine HAVE_VA_INTEL
+
+/* Lapack */
+#cmakedefine HAVE_LAPACK
+
+/* FP16 */
+#cmakedefine HAVE_FP16
+
+/* Library was compiled with functions instrumentation */
+#cmakedefine ENABLE_INSTRUMENTATION
+
+/* OpenVX */
+#cmakedefine HAVE_OPENVX
diff --git a/cmake/templates/opencv_modules.hpp.in b/cmake/templates/opencv_modules.hpp.in
index 1498715..6696bb4 100644
--- a/cmake/templates/opencv_modules.hpp.in
+++ b/cmake/templates/opencv_modules.hpp.in
@@ -6,4 +6,8 @@
  *
 */
 
+// This definition means that OpenCV is built with enabled non-free code.
+// For example, patented algorithms for non-profit/non-commercial use only.
+#cmakedefine OPENCV_ENABLE_NONFREE
+
 @OPENCV_MODULE_DEFINITIONS_CONFIGMAKE@
diff --git a/contrib/.github/ISSUE_TEMPLATE.md b/contrib/.github/ISSUE_TEMPLATE.md
new file mode 100644
index 0000000..e72c70d
--- /dev/null
+++ b/contrib/.github/ISSUE_TEMPLATE.md
@@ -0,0 +1,30 @@
+<!--
+If you have a question rather than reporting a bug please go to http://answers.opencv.org where you get much faster responses.
+If you need further assistance please read [How To Contribute](https://github.com/opencv/opencv/wiki/How_to_contribute).
+
+This is a template helping you to create an issue which can be processed as quickly as possible. This is the bug reporting section for the OpenCV library.
+-->
+
+##### System information (version)
+<!-- Example
+- OpenCV => 3.1
+- Operating System / Platform => Windows 64 Bit
+- Compiler => Visual Studio 2015
+-->
+
+- OpenCV => :grey_question:
+- Operating System / Platform => :grey_question:
+- Compiler => :grey_question:
+
+##### Detailed description
+
+<!-- your description -->
+
+##### Steps to reproduce
+
+<!-- to add code example fence it with triple backticks and optional file extension
+    ```.cpp
+    // C++ code example
+    ```
+ or attach as .txt or .zip file
+-->
\ No newline at end of file
diff --git a/contrib/.github/PULL_REQUEST_TEMPLATE.md b/contrib/.github/PULL_REQUEST_TEMPLATE.md
new file mode 100644
index 0000000..210a253
--- /dev/null
+++ b/contrib/.github/PULL_REQUEST_TEMPLATE.md
@@ -0,0 +1,9 @@
+<!-- Please use this line to close one or multiple issues when this pullrequest gets merged
+You can add another line right under the first one:
+resolves #1234
+resolves #1235
+-->
+
+### This pullrequest changes
+
+<!-- Please describe what your pullrequest is changing -->
diff --git a/contrib/.gitignore b/contrib/.gitignore
new file mode 100644
index 0000000..bb42d2a
--- /dev/null
+++ b/contrib/.gitignore
@@ -0,0 +1,12 @@
+*.autosave
+*.pyc
+*.user
+*~
+.*.swp
+.DS_Store
+.sw[a-z]
+Thumbs.db
+tags
+tegra/
+*.i
+.download*
diff --git a/contrib/.travis.yml b/contrib/.travis.yml
index 23b3aba..5c603ef 100644
--- a/contrib/.travis.yml
+++ b/contrib/.travis.yml
@@ -4,7 +4,7 @@ compiler:
   - clang
 before_script:
   - cd ../
-  - git clone https://github.com/Itseez/opencv.git
+  - git clone https://github.com/opencv/opencv.git
   - mkdir build-opencv
   - cd build-opencv
   - cmake -DOPENCV_EXTRA_MODULES_PATH=../opencv_contrib/modules ../opencv
diff --git a/contrib/CONTRIBUTING.md b/contrib/CONTRIBUTING.md
index 1e13c89..318e9ac 100644
--- a/contrib/CONTRIBUTING.md
+++ b/contrib/CONTRIBUTING.md
@@ -1,3 +1,3 @@
 ## Contributing guidelines
 
-All guidelines for contributing to the OpenCV repository can be found at [`How to contribute guideline`](https://github.com/Itseez/opencv/wiki/How_to_contribute).
+All guidelines for contributing to the OpenCV repository can be found at [`How to contribute guideline`](https://github.com/opencv/opencv/wiki/How_to_contribute).
diff --git a/contrib/README.md b/contrib/README.md
index c345623..e769041 100644
--- a/contrib/README.md
+++ b/contrib/README.md
@@ -13,7 +13,8 @@ provides production quality support for this module.
 
 ### How to build OpenCV with extra modules
 
-You can build OpenCV, so it will include the modules from this repository.
+You can build OpenCV, so it will include the modules from this repository. Contrib modules are under constant development and it is recommended to use them alongside the master branch or latest releases of OpenCV.
+
 Here is the CMake command for you:
 
 ```
@@ -46,10 +47,12 @@ If you prefer using the gui version of cmake (cmake-gui), then, you can add `ope
 
 7. build the `opencv` core with the method you chose (make and make install if you chose Unix makfile at step 6) 
 
+8. to run, linker flags to contrib modules will need to be added to use them in your code/IDE. For example to use the aruco module, "-lopencv_aruco" flag will be added.
+
 ### Update the repository documentation
 
 In order to keep a clean overview containing all contributed modules the following files need to be created/adapted.
 
 1. Update the README.md file under the modules folder. Here you add your model with a single line description.
 
-2. Add a README.md inside your own module folder. This README explains which functionality (seperate functions) is available, links to the corresponding samples and explains in somewhat more detail what the module is expected to do. If any extra requirements are needed to build the module without problems, add them here also.
\ No newline at end of file
+2. Add a README.md inside your own module folder. This README explains which functionality (seperate functions) is available, links to the corresponding samples and explains in somewhat more detail what the module is expected to do. If any extra requirements are needed to build the module without problems, add them here also.
diff --git a/contrib/modules/README.md b/contrib/modules/README.md
index de6c35a..8a42492 100644
--- a/contrib/modules/README.md
+++ b/contrib/modules/README.md
@@ -1,59 +1,73 @@
-An overview of the contrib modules and a small explanation
-----------------------------------------------------------
+An overview of the opencv_contrib modules
+-----------------------------------------
 
 This list gives an overview of all modules available inside the contrib repository.
-These are also the correct names for disabling the building of a specific module by adding
+To turn off building one of these module repositories, set the names in bold below to <reponame>
 
 ```
-$ cmake -D OPENCV_EXTRA_MODULES_PATH=<opencv_contrib>/modules -D BUILD_opencv_reponame=OFF <opencv_source_directory>
+$ cmake -D OPENCV_EXTRA_MODULES_PATH=<opencv_contrib>/modules -D BUILD_opencv_<reponame>=OFF <opencv_source_directory>
 ```
 
-1. **opencv_adas**: Advanced Driver Assistance Systems module with Forward Collision Warning.
+- **aruco**: ArUco and ChArUco Markers -- Augmented reality ArUco marker and "ChARUco" markers where ArUco markers embedded inside the white areas of the checker board.
 
-2. **opencv_bgsegm**: Improved Adaptive Background Mixture Model for Real-time Tracking / Visual Tracking of Human Visitors under Variable-Lighting Conditions.
+- **bgsegm**: Background Segmentation -- Improved Adaptive Background Mixture Model and use for real time human tracking under Variable-Lighting Conditions.
 
-3. **opencv_bioinspired**: Biologically inspired vision models and derivated tools.
+- **bioinspired**: Biological Vision -- Biologically inspired vision model: minimize noise and luminance variance, transient event segmentation, high dynamic range tone mapping methods.
 
-4. **opencv_ ccalib**: Custom Calibration Pattern for 3D reconstruction.
+- **ccalib**: Custom Calibration -- Patterns for 3D reconstruction, omnidirectional camera calibration, random pattern calibration and multi-camera calibration.
 
-5. **opencv_cvv**: GUI for Interactive Visual Debugging of Computer Vision Programs.
+- **cnn_3dobj**: Deep Object Recognition and Pose -- Uses Caffe Deep Neural Net library to build, train and test a CNN model of visual object recognition and pose.
 
-6. **opencv_datasets**: Interface for interfacing with existing computer vision databases.
+- **contrib_world**: opencv_contrib holder -- contrib_world is the module that when built, contains all other opencv_contrib modules. It may be used for the more convenient redistribution of opencv binaries.
 
-7. **opencv_datasettools**: Tools for working with different datasets.
+- **cvv**: Computer Vision Debugger -- Simple code that you can add to your program that pops up a GUI allowing you to interactively and visually debug computer vision programs.
 
-8. **opencv_face**: Recently added face recognition software which is not yet stabalized.
+- **datasets**: Datasets Reader -- Code for reading existing computer vision databases and samples of using the readers to train, test and run using that dataset's data.
 
-9. **opencv_latentsvm**: Implementation of the LatentSVM detector algorithm.
+- **dnn**: Deep Neural Networks (DNNs) -- This module can read in image recogniton networks trained in the Caffe neural netowrk library and run them efficiently on CPU.
 
-10. **opencv_line_descriptor**: Binary descriptors for lines extracted from an image.
+- **dnns_easily_fooled**: Subvert DNNs -- This code can use the activations in a network to fool the networks into recognizing something else.
 
-11. **opencv_matlab**: OpenCV Matlab Code Generator.
+- **dpm**: Deformable Part Model -- Felzenszwalb's Cascade with deformable parts object recognition code.
 
-12. **opencv_optflow**: Optical Flow Algorithms for tracking points.
+- **face**: Face Recognition -- Face recognition techniques: Eigen, Fisher and Local Binary Pattern Histograms LBPH methods.
 
-13. **opencv_reg**: Image Registration module.
+- **fuzzy**: Fuzzy Logic in Vision -- Fuzzy logic image transform and inverse; Fuzzy image processing.
 
-14. **opencv_rgbd**: RGB-Depth Processing module.
+- **freetype**: Drawing text using freetype and harfbuzz.
 
-15. **opencv_saliency**: Saliency API, understanding where humans focus given a scene.
+- **hdf**: Hierarchical Data Storage -- This module contains I/O routines for Hierarchical Data Format: https://en.m.wikipedia.org/wiki/Hierarchical_Data_Format meant to store large amounts of data.
 
-16. **opencv_surface_matching**: Surface Matching Algorithm Through 3D Features.
+- **line_descriptor**: Line Segment Extract and Match -- Methods of extracting, describing and latching line segments using binary descriptors.
 
-17. **opencv_text**: Scene Text Detection and Recognition in Natural Scene Images.
+- **matlab**: Matlab Interface -- OpenCV Matlab Mex wrapper code generator for certain opencv core modules.
 
-18. **opencv_tracking**: Long-term optical tracking API.
+- **optflow**: Optical Flow -- Algorithms for running and evaluating deepflow, simpleflow, sparsetodenseflow and motion templates (silhouette flow).
 
-19. **opencv_xfeatures2d**: Extra 2D Features Framework containing experimental and non-free 2D feature algorithms.
+- **plot**: Plotting -- The plot module allows you to easily plot data in 1D or 2D.
 
-20. **opencv_ximgproc**: Extended Image Processing: Structured Forests / Domain Transform Filter / Guided Filter / Adaptive Manifold Filter / Joint Bilateral Filter / Superpixels.
+- **reg**: Image Registration -- Pixels based image registration for precise alignment. Follows the paper "Image Alignment and Stitching: A Tutorial", by Richard Szeliski.
 
-21. **opencv_xobjdetect**: Integral Channel Features Detector Framework.
+- **rgbd**: RGB-Depth Processing module -- Linemod 3D object recognition; Fast surface normals and 3D plane finding. 3D visual odometry
 
-22. **opencv_xphoto**: Additional photo processing algorithms: Color balance / Denoising / Inpainting.
+- **saliency**: Saliency API -- Where humans would look in a scene. Has routines for static, motion and "objectness" saliency.
 
-23. **opencv_stereo**: Stereo Correspondence done with different descriptors: Census / CS-Census / MCT / BRIEF / MV.
+- **sfm**: Structure from Motion -- This module contains algorithms to perform 3d reconstruction from 2d images. The core of the module is a light version of Libmv.
 
-24. **opencv_hdf**: Hierarchical Data Format I/O.
+- **stereo**: Stereo Correspondence -- Stereo matching done with different descriptors: Census / CS-Census / MCT / BRIEF / MV.
 
-25. **opencv_fuzzy**: New module focused on the fuzzy image processing.
+- **structured_light**: Structured Light Use -- How to generate and project gray code patterns and use them to find dense depth in a scene.
+
+- **surface_matching**: Point Pair Features -- Implements 3d object detection and localization using multimodal point pair features.
+
+- **text**: Visual Text Matching -- In a visual scene, detect text, segment words and recognise the text.
+
+- **tracking**: Vision Based Object Tracking -- Use and/or evaluate one of 5 different visual object tracking techniques.
+
+- **xfeatures2d**: Features2D extra -- Extra 2D Features Framework containing experimental and non-free 2D feature detector/descriptor algorithms. SURF, SIFT, BRIEF, Censure, Freak, LUCID, Daisy, Self-similar.
+
+- **ximgproc**: Extended Image Processing -- Structured Forests / Domain Transform Filter / Guided Filter / Adaptive Manifold Filter / Joint Bilateral Filter / Superpixels.
+
+- **xobjdetect**: Boosted 2D Object Detection -- Uses a Waldboost cascade and local binary patterns computed as integral features for 2D object detection.
+
+- **xphoto**: Extra Computational Photography -- Additional photo processing algorithms: Color balance / Denoising / Inpainting.
diff --git a/contrib/modules/aruco/CMakeLists.txt b/contrib/modules/aruco/CMakeLists.txt
index 0b62416..568a10a 100644
--- a/contrib/modules/aruco/CMakeLists.txt
+++ b/contrib/modules/aruco/CMakeLists.txt
@@ -1,2 +1,2 @@
 set(the_description "ArUco Marker Detection")
-ocv_define_module(aruco opencv_core opencv_imgproc opencv_calib3d WRAP python)
+ocv_define_module(aruco opencv_core opencv_imgproc opencv_calib3d WRAP python java)
diff --git a/contrib/modules/aruco/README.md b/contrib/modules/aruco/README.md
index 48eec14..d40ae78 100644
--- a/contrib/modules/aruco/README.md
+++ b/contrib/modules/aruco/README.md
@@ -1,2 +1,12 @@
 ArUco Marker Detection
 ======================
+
+**ArUco**
+
+ArUco markers are easy to detect pattern grids that yield up to 1024 different patterns. They were built for augmented reality and later used for camera calibration. Since the grid uniquely orients the square, the detection algorithm can determing the pose of the grid.
+
+**ChArUco**
+
+ArUco markers were improved by interspersing them inside a checkerboard called ChArUco. Checkerboard corner intersectionsa provide more stable corners because the edge location bias on one square is countered by the opposite edge orientation in the connecting square. By interspersing ArUco markers inside the checkerboard, each checkerboard corner gets a label which enables it to be used in complex calibration or pose scenarios where you cannot see all the corners of the checkerboard.
+
+The smallest ChArUco board is 5 checkers and 4 markers called a "Diamond Marker".
diff --git a/contrib/modules/aruco/include/opencv2/aruco.hpp b/contrib/modules/aruco/include/opencv2/aruco.hpp
index 5707c7e..e9e88c5 100644
--- a/contrib/modules/aruco/include/opencv2/aruco.hpp
+++ b/contrib/modules/aruco/include/opencv2/aruco.hpp
@@ -121,30 +121,32 @@ namespace aruco {
  * - errorCorrectionRate error correction rate respect to the maximun error correction capability
  *   for each dictionary. (default 0.6).
  */
-struct CV_EXPORTS DetectorParameters {
+struct CV_EXPORTS_W DetectorParameters {
 
     DetectorParameters();
 
-    int adaptiveThreshWinSizeMin;
-    int adaptiveThreshWinSizeMax;
-    int adaptiveThreshWinSizeStep;
-    double adaptiveThreshConstant;
-    double minMarkerPerimeterRate;
-    double maxMarkerPerimeterRate;
-    double polygonalApproxAccuracyRate;
-    double minCornerDistanceRate;
-    int minDistanceToBorder;
-    double minMarkerDistanceRate;
-    bool doCornerRefinement;
-    int cornerRefinementWinSize;
-    int cornerRefinementMaxIterations;
-    double cornerRefinementMinAccuracy;
-    int markerBorderBits;
-    int perspectiveRemovePixelPerCell;
-    double perspectiveRemoveIgnoredMarginPerCell;
-    double maxErroneousBitsInBorderRate;
-    double minOtsuStdDev;
-    double errorCorrectionRate;
+    CV_WRAP static Ptr<DetectorParameters> create();
+
+    CV_PROP_RW int adaptiveThreshWinSizeMin;
+    CV_PROP_RW int adaptiveThreshWinSizeMax;
+    CV_PROP_RW int adaptiveThreshWinSizeStep;
+    CV_PROP_RW double adaptiveThreshConstant;
+    CV_PROP_RW double minMarkerPerimeterRate;
+    CV_PROP_RW double maxMarkerPerimeterRate;
+    CV_PROP_RW double polygonalApproxAccuracyRate;
+    CV_PROP_RW double minCornerDistanceRate;
+    CV_PROP_RW int minDistanceToBorder;
+    CV_PROP_RW double minMarkerDistanceRate;
+    CV_PROP_RW bool doCornerRefinement;
+    CV_PROP_RW int cornerRefinementWinSize;
+    CV_PROP_RW int cornerRefinementMaxIterations;
+    CV_PROP_RW double cornerRefinementMinAccuracy;
+    CV_PROP_RW int markerBorderBits;
+    CV_PROP_RW int perspectiveRemovePixelPerCell;
+    CV_PROP_RW double perspectiveRemoveIgnoredMarginPerCell;
+    CV_PROP_RW double maxErroneousBitsInBorderRate;
+    CV_PROP_RW double minOtsuStdDev;
+    CV_PROP_RW double errorCorrectionRate;
 };
 
 
@@ -171,9 +173,9 @@ struct CV_EXPORTS DetectorParameters {
  * @sa estimatePoseSingleMarkers,  estimatePoseBoard
  *
  */
-CV_EXPORTS void detectMarkers(InputArray image, Dictionary dictionary, OutputArrayOfArrays corners,
-                              OutputArray ids, DetectorParameters parameters = DetectorParameters(),
-                              OutputArrayOfArrays rejectedImgPoints = noArray());
+CV_EXPORTS_W void detectMarkers(InputArray image, const Ptr<Dictionary> &dictionary, OutputArrayOfArrays corners,
+                                OutputArray ids, const Ptr<DetectorParameters> &parameters = DetectorParameters::create(),
+                                OutputArrayOfArrays rejectedImgPoints = noArray());
 
 
 
@@ -190,9 +192,9 @@ CV_EXPORTS void detectMarkers(InputArray image, Dictionary dictionary, OutputArr
  * \f$A = \vecthreethree{f_x}{0}{c_x}{0}{f_y}{c_y}{0}{0}{1}\f$
  * @param distCoeffs vector of distortion coefficients
  * \f$(k_1, k_2, p_1, p_2[, k_3[, k_4, k_5, k_6],[s_1, s_2, s_3, s_4]])\f$ of 4, 5, 8 or 12 elements
- * @param rvecs array of output rotation vectors (@sa Rodrigues) (e.g. std::vector<cv::Vec3d>>).
+ * @param rvecs array of output rotation vectors (@sa Rodrigues) (e.g. std::vector<cv::Vec3d>).
  * Each element in rvecs corresponds to the specific marker in imgPoints.
- * @param tvecs array of output translation vectors (e.g. std::vector<cv::Vec3d>>).
+ * @param tvecs array of output translation vectors (e.g. std::vector<cv::Vec3d>).
  * Each element in tvecs corresponds to the specific marker in imgPoints.
  *
  * This function receives the detected markers and returns their pose estimation respect to
@@ -205,9 +207,9 @@ CV_EXPORTS void detectMarkers(InputArray image, Dictionary dictionary, OutputArr
  * (-markerLength/2, markerLength/2, 0), (markerLength/2, markerLength/2, 0),
  * (markerLength/2, -markerLength/2, 0), (-markerLength/2, -markerLength/2, 0)
  */
-CV_EXPORTS void estimatePoseSingleMarkers(InputArrayOfArrays corners, float markerLength,
-                                          InputArray cameraMatrix, InputArray distCoeffs,
-                                          OutputArrayOfArrays rvecs, OutputArrayOfArrays tvecs);
+CV_EXPORTS_W void estimatePoseSingleMarkers(InputArrayOfArrays corners, float markerLength,
+                                            InputArray cameraMatrix, InputArray distCoeffs,
+                                            OutputArray rvecs, OutputArray tvecs);
 
 
 
@@ -221,19 +223,28 @@ CV_EXPORTS void estimatePoseSingleMarkers(InputArrayOfArrays corners, float mark
  * - The dictionary which indicates the type of markers of the board
  * - The identifier of all the markers in the board.
  */
-class CV_EXPORTS Board {
+class CV_EXPORTS_W Board {
 
     public:
-    // array of object points of all the marker corners in the board
-    // each marker include its 4 corners, i.e. for M markers, the size is Mx4
-    std::vector< std::vector< Point3f > > objPoints;
-
-    // the dictionary of markers employed for this board
-    Dictionary dictionary;
-
-    // vector of the identifiers of the markers in the board (same size than objPoints)
-    // The identifiers refers to the board dictionary
-    std::vector< int > ids;
+    /**
+    * @brief Provide way to create Board by passing nessesary data. Specially needed in Python.
+    *
+    * @param objPoints array of object points of all the marker corners in the board
+    * @param dictionary the dictionary of markers employed for this board
+    * @param ids vector of the identifiers of the markers in the board
+    *
+    */
+    CV_WRAP static Ptr<Board> create(InputArrayOfArrays objPoints, const Ptr<Dictionary> &dictionary, InputArray ids);
+    /// array of object points of all the marker corners in the board
+    /// each marker include its 4 corners in CCW order. For M markers, the size is Mx4.
+    CV_PROP std::vector< std::vector< Point3f > > objPoints;
+
+    /// the dictionary of markers employed for this board
+    CV_PROP Ptr<Dictionary> dictionary;
+
+    /// vector of the identifiers of the markers in the board (same size than objPoints)
+    /// The identifiers refers to the board dictionary
+    CV_PROP std::vector< int > ids;
 };
 
 
@@ -243,7 +254,7 @@ class CV_EXPORTS Board {
  * More common type of board. All markers are placed in the same plane in a grid arrangment.
  * The board can be drawn using drawPlanarBoard() function (@sa drawPlanarBoard)
  */
-class CV_EXPORTS GridBoard : public Board {
+class CV_EXPORTS_W GridBoard : public Board {
 
     public:
     /**
@@ -257,7 +268,7 @@ class CV_EXPORTS GridBoard : public Board {
      *
      * This function return the image of the GridBoard, ready to be printed.
      */
-    void draw(Size outSize, OutputArray img, int marginSize = 0, int borderBits = 1);
+    CV_WRAP void draw(Size outSize, OutputArray img, int marginSize = 0, int borderBits = 1);
 
 
     /**
@@ -266,31 +277,31 @@ class CV_EXPORTS GridBoard : public Board {
      * @param markersX number of markers in X direction
      * @param markersY number of markers in Y direction
      * @param markerLength marker side length (normally in meters)
-     * @param markerSeparation separation between two markers (same unit than markerLenght)
-     * @param dictionary dictionary of markers indicating the type of markers.
-     * The first markersX*markersY markers in the dictionary are used.
+     * @param markerSeparation separation between two markers (same unit as markerLength)
+     * @param dictionary dictionary of markers indicating the type of markers
+     * @param firstMarker id of first marker in dictionary to use on board.
      * @return the output GridBoard object
      *
      * This functions creates a GridBoard object given the number of markers in each direction and
      * the marker size and marker separation.
      */
-    static GridBoard create(int markersX, int markersY, float markerLength, float markerSeparation,
-                            Dictionary dictionary);
+    CV_WRAP static Ptr<GridBoard> create(int markersX, int markersY, float markerLength,
+                                         float markerSeparation, const Ptr<Dictionary> &dictionary, int firstMarker = 0);
 
     /**
       *
       */
-    Size getGridSize() const { return Size(_markersX, _markersY); }
+    CV_WRAP Size getGridSize() const { return Size(_markersX, _markersY); }
 
     /**
       *
       */
-    float getMarkerLength() const { return _markerLength; }
+    CV_WRAP float getMarkerLength() const { return _markerLength; }
 
     /**
       *
       */
-    float getMarkerSeparation() const { return _markerSeparation; }
+    CV_WRAP float getMarkerSeparation() const { return _markerSeparation; }
 
 
     private:
@@ -320,8 +331,9 @@ class CV_EXPORTS GridBoard : public Board {
  * @param distCoeffs vector of distortion coefficients
  * \f$(k_1, k_2, p_1, p_2[, k_3[, k_4, k_5, k_6],[s_1, s_2, s_3, s_4]])\f$ of 4, 5, 8 or 12 elements
  * @param rvec Output vector (e.g. cv::Mat) corresponding to the rotation vector of the board
- * (@sa Rodrigues).
+ * (@sa Rodrigues). Used as initial guess if not empty.
  * @param tvec Output vector (e.g. cv::Mat) corresponding to the translation vector of the board.
+ * Used as initial guess if not empty.
  *
  * This function receives the detected markers and returns the pose of a marker board composed
  * by those markers.
@@ -332,9 +344,9 @@ class CV_EXPORTS GridBoard : public Board {
  * The function returns the number of markers from the input employed for the board pose estimation.
  * Note that returning a 0 means the pose has not been estimated.
  */
-CV_EXPORTS int estimatePoseBoard(InputArrayOfArrays corners, InputArray ids, const Board &board,
-                                 InputArray cameraMatrix, InputArray distCoeffs, OutputArray rvec,
-                                 OutputArray tvec);
+CV_EXPORTS_W int estimatePoseBoard(InputArrayOfArrays corners, InputArray ids, const Ptr<Board> &board,
+                                   InputArray cameraMatrix, InputArray distCoeffs, OutputArray rvec,
+                                   OutputArray tvec);
 
 
 
@@ -370,12 +382,12 @@ CV_EXPORTS int estimatePoseBoard(InputArrayOfArrays corners, InputArray ids, con
  * using projectPoint function. If not, missing marker projections are interpolated using global
  * homography, and all the marker corners in the board must have the same Z coordinate.
  */
-CV_EXPORTS void refineDetectedMarkers(
-    InputArray image, const Board &board, InputOutputArrayOfArrays detectedCorners,
-    InputOutputArray detectedIds, InputOutputArray rejectedCorners,
+CV_EXPORTS_W void refineDetectedMarkers(
+    InputArray image,const  Ptr<Board> &board, InputOutputArrayOfArrays detectedCorners,
+    InputOutputArray detectedIds, InputOutputArrayOfArrays rejectedCorners,
     InputArray cameraMatrix = noArray(), InputArray distCoeffs = noArray(),
     float minRepDistance = 10.f, float errorCorrectionRate = 3.f, bool checkAllOrders = true,
-    OutputArray recoveredIdxs = noArray(), DetectorParameters parameters = DetectorParameters());
+    OutputArray recoveredIdxs = noArray(), const Ptr<DetectorParameters> &parameters = DetectorParameters::create());
 
 
 
@@ -396,9 +408,9 @@ CV_EXPORTS void refineDetectedMarkers(
  * the markers in the image. The marker borders are painted and the markers identifiers if provided.
  * Useful for debugging purposes.
  */
-CV_EXPORTS void drawDetectedMarkers(InputOutputArray image, InputArrayOfArrays corners,
-                                    InputArray ids = noArray(),
-                                    Scalar borderColor = Scalar(0, 255, 0));
+CV_EXPORTS_W void drawDetectedMarkers(InputOutputArray image, InputArrayOfArrays corners,
+                                      InputArray ids = noArray(),
+                                      Scalar borderColor = Scalar(0, 255, 0));
 
 
 
@@ -418,8 +430,8 @@ CV_EXPORTS void drawDetectedMarkers(InputOutputArray image, InputArrayOfArrays c
  * Given the pose estimation of a marker or board, this function draws the axis of the world
  * coordinate system, i.e. the system centered on the marker/board. Useful for debugging purposes.
  */
-CV_EXPORTS void drawAxis(InputOutputArray image, InputArray cameraMatrix, InputArray distCoeffs,
-                         InputArray rvec, InputArray tvec, float length);
+CV_EXPORTS_W void drawAxis(InputOutputArray image, InputArray cameraMatrix, InputArray distCoeffs,
+                           InputArray rvec, InputArray tvec, float length);
 
 
 
@@ -435,13 +447,14 @@ CV_EXPORTS void drawAxis(InputOutputArray image, InputArray cameraMatrix, InputA
  *
  * This function returns a marker image in its canonical form (i.e. ready to be printed)
  */
-CV_EXPORTS void drawMarker(Dictionary dictionary, int id, int sidePixels, OutputArray img,
-                           int borderBits = 1);
+CV_EXPORTS_W void drawMarker(const Ptr<Dictionary> &dictionary, int id, int sidePixels, OutputArray img,
+                             int borderBits = 1);
 
 
 
 /**
  * @brief Draw a planar board
+ * @sa _drawPlanarBoardImpl
  *
  * @param board layout of the board that will be drawn. The board should be planar,
  * z coordinate is ignored
@@ -454,8 +467,16 @@ CV_EXPORTS void drawMarker(Dictionary dictionary, int id, int sidePixels, Output
  * This function return the image of a planar board, ready to be printed. It assumes
  * the Board layout specified is planar by ignoring the z coordinates of the object points.
  */
-CV_EXPORTS void drawPlanarBoard(const Board &board, Size outSize, OutputArray img,
-                                int marginSize = 0, int borderBits = 1);
+CV_EXPORTS_W void drawPlanarBoard(const Ptr<Board> &board, Size outSize, OutputArray img,
+                                  int marginSize = 0, int borderBits = 1);
+
+
+
+/**
+ * @brief Implementation of drawPlanarBoard that accepts a raw Board pointer.
+ */
+void _drawPlanarBoardImpl(Board *board, Size outSize, OutputArray img,
+                          int marginSize = 0, int borderBits = 1);
 
 
 
@@ -463,7 +484,7 @@ CV_EXPORTS void drawPlanarBoard(const Board &board, Size outSize, OutputArray im
  * @brief Calibrate a camera using aruco markers
  *
  * @param corners vector of detected marker corners in all frames.
- * The corners should have the same format returned by detectMarkers (@sa detectMarkers).
+ * The corners should have the same format returned by detectMarkers (see #detectMarkers).
  * @param ids list of identifiers for each marker in corners
  * @param counter number of markers in each frame so that corners and ids can be split
  * @param board Marker Board layout
@@ -480,20 +501,38 @@ CV_EXPORTS void drawPlanarBoard(const Board &board, Size outSize, OutputArray im
  * from the model coordinate space (in which object points are specified) to the world coordinate
  * space, that is, a real position of the board pattern in the k-th pattern view (k=0.. *M* -1).
  * @param tvecs Output vector of translation vectors estimated for each pattern view.
- * @param flags flags Different flags  for the calibration process (@sa calibrateCamera)
+ * @param stdDeviationsIntrinsics Output vector of standard deviations estimated for intrinsic parameters.
+ * Order of deviations values:
+ * \f$(f_x, f_y, c_x, c_y, k_1, k_2, p_1, p_2, k_3, k_4, k_5, k_6 , s_1, s_2, s_3,
+ * s_4, \tau_x, \tau_y)\f$ If one of parameters is not estimated, it's deviation is equals to zero.
+ * @param stdDeviationsExtrinsics Output vector of standard deviations estimated for extrinsic parameters.
+ * Order of deviations values: \f$(R_1, T_1, \dotsc , R_M, T_M)\f$ where M is number of pattern views,
+ * \f$R_i, T_i\f$ are concatenated 1x3 vectors.
+ * @param perViewErrors Output vector of average re-projection errors estimated for each pattern view.
+ * @param flags flags Different flags  for the calibration process (see #calibrateCamera for details).
  * @param criteria Termination criteria for the iterative optimization algorithm.
  *
  * This function calibrates a camera using an Aruco Board. The function receives a list of
  * detected markers from several views of the Board. The process is similar to the chessboard
  * calibration in calibrateCamera(). The function returns the final re-projection error.
  */
-CV_EXPORTS double calibrateCameraAruco(
-    InputArrayOfArrays corners, InputArray ids, InputArray counter, const Board &board,
+CV_EXPORTS_AS(calibrateCameraArucoExtended) double calibrateCameraAruco(
+    InputArrayOfArrays corners, InputArray ids, InputArray counter, const Ptr<Board> &board,
     Size imageSize, InputOutputArray cameraMatrix, InputOutputArray distCoeffs,
-    OutputArrayOfArrays rvecs = noArray(), OutputArrayOfArrays tvecs = noArray(), int flags = 0,
+    OutputArrayOfArrays rvecs, OutputArrayOfArrays tvecs,
+    OutputArray stdDeviationsIntrinsics, OutputArray stdDeviationsExtrinsics,
+    OutputArray perViewErrors, int flags = 0,
     TermCriteria criteria = TermCriteria(TermCriteria::COUNT + TermCriteria::EPS, 30, DBL_EPSILON));
 
 
+/** @brief It's the same function as #calibrateCameraAruco but without calibration error estimation.
+ */
+CV_EXPORTS_W double calibrateCameraAruco(
+  InputArrayOfArrays corners, InputArray ids, InputArray counter, const Ptr<Board> &board,
+  Size imageSize, InputOutputArray cameraMatrix, InputOutputArray distCoeffs,
+  OutputArrayOfArrays rvecs = noArray(), OutputArrayOfArrays tvecs = noArray(), int flags = 0,
+  TermCriteria criteria = TermCriteria(TermCriteria::COUNT + TermCriteria::EPS, 30, DBL_EPSILON));
+
 
 //! @}
 }
diff --git a/contrib/modules/aruco/include/opencv2/aruco/charuco.hpp b/contrib/modules/aruco/include/opencv2/aruco/charuco.hpp
index 81c90fb..7be82ed 100644
--- a/contrib/modules/aruco/include/opencv2/aruco/charuco.hpp
+++ b/contrib/modules/aruco/include/opencv2/aruco/charuco.hpp
@@ -59,15 +59,15 @@ namespace aruco {
  * calibration and pose estimation.
  * This class also allows the easy creation and drawing of ChArUco boards.
  */
-class CV_EXPORTS CharucoBoard : public Board {
+class CV_EXPORTS_W CharucoBoard : public Board {
 
     public:
     // vector of chessboard 3D corners precalculated
-    std::vector< Point3f > chessboardCorners;
+    CV_PROP std::vector< Point3f > chessboardCorners;
 
     // for each charuco corner, nearest marker id and nearest marker corner id of each marker
-    std::vector< std::vector< int > > nearestMarkerIdx;
-    std::vector< std::vector< int > > nearestMarkerCorners;
+    CV_PROP std::vector< std::vector< int > > nearestMarkerIdx;
+    CV_PROP std::vector< std::vector< int > > nearestMarkerCorners;
 
     /**
      * @brief Draw a ChArUco board
@@ -80,7 +80,7 @@ class CV_EXPORTS CharucoBoard : public Board {
      *
      * This function return the image of the ChArUco board, ready to be printed.
      */
-    void draw(Size outSize, OutputArray img, int marginSize = 0, int borderBits = 1);
+    CV_WRAP void draw(Size outSize, OutputArray img, int marginSize = 0, int borderBits = 1);
 
 
     /**
@@ -97,23 +97,23 @@ class CV_EXPORTS CharucoBoard : public Board {
      * This functions creates a CharucoBoard object given the number of squares in each direction
      * and the size of the markers and chessboard squares.
      */
-    static CharucoBoard create(int squaresX, int squaresY, float squareLength, float markerLength,
-                               Dictionary dictionary);
+    CV_WRAP static Ptr<CharucoBoard> create(int squaresX, int squaresY, float squareLength,
+                                            float markerLength, const Ptr<Dictionary> &dictionary);
 
     /**
       *
       */
-    Size getChessboardSize() const { return Size(_squaresX, _squaresY); }
+    CV_WRAP Size getChessboardSize() const { return Size(_squaresX, _squaresY); }
 
     /**
       *
       */
-    float getSquareLength() const { return _squareLength; }
+    CV_WRAP float getSquareLength() const { return _squareLength; }
 
     /**
       *
       */
-    float getMarkerLength() const { return _markerLength; }
+    CV_WRAP float getMarkerLength() const { return _markerLength; }
 
     private:
     void _getNearestMarkerCorners();
@@ -146,6 +146,7 @@ class CV_EXPORTS CharucoBoard : public Board {
  * \f$A = \vecthreethree{f_x}{0}{c_x}{0}{f_y}{c_y}{0}{0}{1}\f$
  * @param distCoeffs optional vector of distortion coefficients
  * \f$(k_1, k_2, p_1, p_2[, k_3[, k_4, k_5, k_6],[s_1, s_2, s_3, s_4]])\f$ of 4, 5, 8 or 12 elements
+ * @param minMarkers number of adjacent markers that must be detected to return a charuco corner
  *
  * This function receives the detected markers and returns the 2D position of the chessboard corners
  * from a ChArUco board using the detected Aruco markers. If camera parameters are provided,
@@ -154,11 +155,11 @@ class CV_EXPORTS CharucoBoard : public Board {
  * also returned in charucoIds.
  * The function returns the number of interpolated corners.
  */
-CV_EXPORTS int interpolateCornersCharuco(InputArrayOfArrays markerCorners, InputArray markerIds,
-                                         InputArray image, const CharucoBoard &board,
-                                         OutputArray charucoCorners, OutputArray charucoIds,
-                                         InputArray cameraMatrix = noArray(),
-                                         InputArray distCoeffs = noArray());
+CV_EXPORTS_W int interpolateCornersCharuco(InputArrayOfArrays markerCorners, InputArray markerIds,
+                                           InputArray image, const Ptr<CharucoBoard> &board,
+                                           OutputArray charucoCorners, OutputArray charucoIds,
+                                           InputArray cameraMatrix = noArray(),
+                                           InputArray distCoeffs = noArray(), int minMarkers = 2);
 
 
 
@@ -180,9 +181,9 @@ CV_EXPORTS int interpolateCornersCharuco(InputArrayOfArrays markerCorners, Input
  * The function checks if the input corners are enough and valid to perform pose estimation.
  * If pose estimation is valid, returns true, else returns false.
  */
-CV_EXPORTS bool estimatePoseCharucoBoard(InputArray charucoCorners, InputArray charucoIds,
-                                         CharucoBoard &board, InputArray cameraMatrix,
-                                         InputArray distCoeffs, OutputArray rvec, OutputArray tvec);
+CV_EXPORTS_W bool estimatePoseCharucoBoard(InputArray charucoCorners, InputArray charucoIds,
+                                           const Ptr<CharucoBoard> &board, InputArray cameraMatrix,
+                                           InputArray distCoeffs, OutputArray rvec, OutputArray tvec);
 
 
 
@@ -198,9 +199,9 @@ CV_EXPORTS bool estimatePoseCharucoBoard(InputArray charucoCorners, InputArray c
  * This function draws a set of detected Charuco corners. If identifiers vector is provided, it also
  * draws the id of each corner.
  */
-CV_EXPORTS void drawDetectedCornersCharuco(InputOutputArray image, InputArray charucoCorners,
-                                           InputArray charucoIds = noArray(),
-                                           Scalar cornerColor = Scalar(255, 0, 0));
+CV_EXPORTS_W void drawDetectedCornersCharuco(InputOutputArray image, InputArray charucoCorners,
+                                             InputArray charucoIds = noArray(),
+                                             Scalar cornerColor = Scalar(255, 0, 0));
 
 
 
@@ -223,19 +224,36 @@ CV_EXPORTS void drawDetectedCornersCharuco(InputOutputArray image, InputArray ch
  * from the model coordinate space (in which object points are specified) to the world coordinate
  * space, that is, a real position of the board pattern in the k-th pattern view (k=0.. *M* -1).
  * @param tvecs Output vector of translation vectors estimated for each pattern view.
- * @param flags flags Different flags  for the calibration process (@sa calibrateCamera)
+ * @param stdDeviationsIntrinsics Output vector of standard deviations estimated for intrinsic parameters.
+ * Order of deviations values:
+ * \f$(f_x, f_y, c_x, c_y, k_1, k_2, p_1, p_2, k_3, k_4, k_5, k_6 , s_1, s_2, s_3,
+ * s_4, \tau_x, \tau_y)\f$ If one of parameters is not estimated, it's deviation is equals to zero.
+ * @param stdDeviationsExtrinsics Output vector of standard deviations estimated for extrinsic parameters.
+ * Order of deviations values: \f$(R_1, T_1, \dotsc , R_M, T_M)\f$ where M is number of pattern views,
+ * \f$R_i, T_i\f$ are concatenated 1x3 vectors.
+ * @param perViewErrors Output vector of average re-projection errors estimated for each pattern view.
+ * @param flags flags Different flags  for the calibration process (see #calibrateCamera for details).
  * @param criteria Termination criteria for the iterative optimization algorithm.
  *
  * This function calibrates a camera using a set of corners of a  Charuco Board. The function
  * receives a list of detected corners and its identifiers from several views of the Board.
  * The function returns the final re-projection error.
  */
-CV_EXPORTS double calibrateCameraCharuco(
-    InputArrayOfArrays charucoCorners, InputArrayOfArrays charucoIds, const CharucoBoard &board,
+CV_EXPORTS_AS(calibrateCameraCharucoExtended) double calibrateCameraCharuco(
+    InputArrayOfArrays charucoCorners, InputArrayOfArrays charucoIds, const Ptr<CharucoBoard> &board,
     Size imageSize, InputOutputArray cameraMatrix, InputOutputArray distCoeffs,
-    OutputArrayOfArrays rvecs = noArray(), OutputArrayOfArrays tvecs = noArray(), int flags = 0,
+    OutputArrayOfArrays rvecs, OutputArrayOfArrays tvecs,
+    OutputArray stdDeviationsIntrinsics, OutputArray stdDeviationsExtrinsics,
+    OutputArray perViewErrors, int flags = 0,
     TermCriteria criteria = TermCriteria(TermCriteria::COUNT + TermCriteria::EPS, 30, DBL_EPSILON));
 
+/** @brief It's the same function as #calibrateCameraCharuco but without calibration error estimation.
+*/
+CV_EXPORTS_W double calibrateCameraCharuco(
+  InputArrayOfArrays charucoCorners, InputArrayOfArrays charucoIds, const Ptr<CharucoBoard> &board,
+  Size imageSize, InputOutputArray cameraMatrix, InputOutputArray distCoeffs,
+  OutputArrayOfArrays rvecs = noArray(), OutputArrayOfArrays tvecs = noArray(), int flags = 0,
+  TermCriteria criteria = TermCriteria(TermCriteria::COUNT + TermCriteria::EPS, 30, DBL_EPSILON));
 
 
 
@@ -261,11 +279,11 @@ CV_EXPORTS double calibrateCameraCharuco(
  * are provided, the diamond search is based on reprojection. If not, diamond search is based on
  * homography. Homography is faster than reprojection but can slightly reduce the detection rate.
  */
-CV_EXPORTS void detectCharucoDiamond(InputArray image, InputArrayOfArrays markerCorners,
-                                     InputArray markerIds, float squareMarkerLengthRate,
-                                     OutputArrayOfArrays diamondCorners, OutputArray diamondIds,
-                                     InputArray cameraMatrix = noArray(),
-                                     InputArray distCoeffs = noArray());
+CV_EXPORTS_W void detectCharucoDiamond(InputArray image, InputArrayOfArrays markerCorners,
+                                       InputArray markerIds, float squareMarkerLengthRate,
+                                       OutputArrayOfArrays diamondCorners, OutputArray diamondIds,
+                                       InputArray cameraMatrix = noArray(),
+                                       InputArray distCoeffs = noArray());
 
 
 
@@ -287,9 +305,9 @@ CV_EXPORTS void detectCharucoDiamond(InputArray image, InputArrayOfArrays marker
  * are painted and the markers identifiers if provided.
  * Useful for debugging purposes.
  */
-CV_EXPORTS void drawDetectedDiamonds(InputOutputArray image, InputArrayOfArrays diamondCorners,
-                                     InputArray diamondIds = noArray(),
-                                     Scalar borderColor = Scalar(0, 0, 255));
+CV_EXPORTS_W void drawDetectedDiamonds(InputOutputArray image, InputArrayOfArrays diamondCorners,
+                                       InputArray diamondIds = noArray(),
+                                       Scalar borderColor = Scalar(0, 0, 255));
 
 
 
@@ -308,7 +326,8 @@ CV_EXPORTS void drawDetectedDiamonds(InputOutputArray image, InputArrayOfArrays
  *
  * This function return the image of a ChArUco marker, ready to be printed.
  */
-CV_EXPORTS void drawCharucoDiamond(Dictionary dictionary, Vec4i ids, int squareLength,
+// TODO cannot be exported yet; conversion from/to Vec4i is not wrapped in core
+CV_EXPORTS void drawCharucoDiamond(const Ptr<Dictionary> &dictionary, Vec4i ids, int squareLength,
                                    int markerLength, OutputArray img, int marginSize = 0,
                                    int borderBits = 1);
 
diff --git a/contrib/modules/aruco/include/opencv2/aruco/dictionary.hpp b/contrib/modules/aruco/include/opencv2/aruco/dictionary.hpp
index 52bcf67..b94ee25 100644
--- a/contrib/modules/aruco/include/opencv2/aruco/dictionary.hpp
+++ b/contrib/modules/aruco/include/opencv2/aruco/dictionary.hpp
@@ -58,12 +58,12 @@ namespace aruco {
  *
  * `bytesList.ptr(i)[k*nbytes + j]` is then the j-th byte of i-th marker, in its k-th rotation.
  */
-class CV_EXPORTS Dictionary {
+class CV_EXPORTS_W Dictionary {
 
     public:
-    Mat bytesList;         // marker code information
-    int markerSize;        // number of bits per dimension
-    int maxCorrectionBits; // maximum number of bits that can be corrected
+    CV_PROP Mat bytesList;         // marker code information
+    CV_PROP int markerSize;        // number of bits per dimension
+    CV_PROP int maxCorrectionBits; // maximum number of bits that can be corrected
 
 
     /**
@@ -71,6 +71,32 @@ class CV_EXPORTS Dictionary {
     Dictionary(const Mat &_bytesList = Mat(), int _markerSize = 0, int _maxcorr = 0);
 
 
+    /**
+    Dictionary(const Dictionary &_dictionary);
+    */
+
+
+    /**
+      */
+    Dictionary(const Ptr<Dictionary> &_dictionary);
+
+
+    /**
+     * @see generateCustomDictionary
+     */
+    CV_WRAP_AS(create) static Ptr<Dictionary> create(int nMarkers, int markerSize);
+
+
+    /**
+     * @see generateCustomDictionary
+     */
+    CV_WRAP_AS(create_from) static Ptr<Dictionary> create(int nMarkers, int markerSize,
+            const Ptr<Dictionary> &baseDictionary);
+
+    /**
+     * @see getPredefinedDictionary
+     */
+    CV_WRAP static Ptr<Dictionary> get(int dict);
 
     /**
      * @brief Given a matrix of bits. Returns whether if marker is identified or not.
@@ -88,7 +114,7 @@ class CV_EXPORTS Dictionary {
     /**
      * @brief Draw a canonical marker image
      */
-    void drawMarker(int id, int sidePixels, OutputArray _img, int borderBits = 1) const;
+    CV_WRAP void drawMarker(int id, int sidePixels, OutputArray _img, int borderBits = 1) const;
 
 
     /**
@@ -109,9 +135,10 @@ class CV_EXPORTS Dictionary {
 /**
  * @brief Predefined markers dictionaries/sets
  * Each dictionary indicates the number of bits and the number of markers contained
- * - DICT_ARUCO: standard ArUco Library Markers. 1024 markers, 5x5 bits, 0 minimum distance
+ * - DICT_ARUCO_ORIGINAL: standard ArUco Library Markers. 1024 markers, 5x5 bits, 0 minimum
+                          distance
  */
-enum PREDEFINED_DICTIONARY_NAME {
+enum CV_EXPORTS_W_SIMPLE PREDEFINED_DICTIONARY_NAME {
     DICT_4X4_50 = 0,
     DICT_4X4_100,
     DICT_4X4_250,
@@ -135,7 +162,21 @@ enum PREDEFINED_DICTIONARY_NAME {
 /**
   * @brief Returns one of the predefined dictionaries defined in PREDEFINED_DICTIONARY_NAME
   */
-CV_EXPORTS const Dictionary &getPredefinedDictionary(PREDEFINED_DICTIONARY_NAME name);
+CV_EXPORTS Ptr<Dictionary> getPredefinedDictionary(PREDEFINED_DICTIONARY_NAME name);
+
+
+/**
+  * @brief Returns one of the predefined dictionaries referenced by DICT_*.
+  */
+CV_EXPORTS_W Ptr<Dictionary> getPredefinedDictionary(int dict);
+
+
+/**
+  * @see generateCustomDictionary
+  */
+CV_EXPORTS_AS(custom_dictionary) Ptr<Dictionary> generateCustomDictionary(
+        int nMarkers,
+        int markerSize);
 
 
 /**
@@ -150,8 +191,10 @@ CV_EXPORTS const Dictionary &getPredefinedDictionary(PREDEFINED_DICTIONARY_NAME
   * included and the rest are generated based on them. If the size of baseDictionary is higher
   * than nMarkers, only the first nMarkers in baseDictionary are taken and no new marker is added.
   */
-CV_EXPORTS Dictionary generateCustomDictionary(int nMarkers, int markerSize,
-                                               const Dictionary &baseDictionary = Dictionary());
+CV_EXPORTS_AS(custom_dictionary_from) Ptr<Dictionary> generateCustomDictionary(
+        int nMarkers,
+        int markerSize,
+        const Ptr<Dictionary> &baseDictionary);
 
 
 
diff --git a/contrib/modules/aruco/samples/calibrate_camera.cpp b/contrib/modules/aruco/samples/calibrate_camera.cpp
index c4b6a84..f0cf77f 100644
--- a/contrib/modules/aruco/samples/calibrate_camera.cpp
+++ b/contrib/modules/aruco/samples/calibrate_camera.cpp
@@ -58,7 +58,7 @@ const char* about =
 const char* keys  =
         "{w        |       | Number of squares in X direction }"
         "{h        |       | Number of squares in Y direction }"
-        "{l        |       | Marker side lenght (in meters) }"
+        "{l        |       | Marker side length (in meters) }"
         "{s        |       | Separation between two consecutive markers in the grid (in meters) }"
         "{d        |       | dictionary: DICT_4X4_50=0, DICT_4X4_100=1, DICT_4X4_250=2,"
         "DICT_4X4_1000=3, DICT_5X5_50=4, DICT_5X5_100=5, DICT_5X5_250=6, DICT_5X5_1000=7, "
@@ -76,30 +76,30 @@ const char* keys  =
 
 /**
  */
-static bool readDetectorParameters(string filename, aruco::DetectorParameters &params) {
+static bool readDetectorParameters(string filename, Ptr<aruco::DetectorParameters> &params) {
     FileStorage fs(filename, FileStorage::READ);
     if(!fs.isOpened())
         return false;
-    fs["adaptiveThreshWinSizeMin"] >> params.adaptiveThreshWinSizeMin;
-    fs["adaptiveThreshWinSizeMax"] >> params.adaptiveThreshWinSizeMax;
-    fs["adaptiveThreshWinSizeStep"] >> params.adaptiveThreshWinSizeStep;
-    fs["adaptiveThreshConstant"] >> params.adaptiveThreshConstant;
-    fs["minMarkerPerimeterRate"] >> params.minMarkerPerimeterRate;
-    fs["maxMarkerPerimeterRate"] >> params.maxMarkerPerimeterRate;
-    fs["polygonalApproxAccuracyRate"] >> params.polygonalApproxAccuracyRate;
-    fs["minCornerDistanceRate"] >> params.minCornerDistanceRate;
-    fs["minDistanceToBorder"] >> params.minDistanceToBorder;
-    fs["minMarkerDistanceRate"] >> params.minMarkerDistanceRate;
-    fs["doCornerRefinement"] >> params.doCornerRefinement;
-    fs["cornerRefinementWinSize"] >> params.cornerRefinementWinSize;
-    fs["cornerRefinementMaxIterations"] >> params.cornerRefinementMaxIterations;
-    fs["cornerRefinementMinAccuracy"] >> params.cornerRefinementMinAccuracy;
-    fs["markerBorderBits"] >> params.markerBorderBits;
-    fs["perspectiveRemovePixelPerCell"] >> params.perspectiveRemovePixelPerCell;
-    fs["perspectiveRemoveIgnoredMarginPerCell"] >> params.perspectiveRemoveIgnoredMarginPerCell;
-    fs["maxErroneousBitsInBorderRate"] >> params.maxErroneousBitsInBorderRate;
-    fs["minOtsuStdDev"] >> params.minOtsuStdDev;
-    fs["errorCorrectionRate"] >> params.errorCorrectionRate;
+    fs["adaptiveThreshWinSizeMin"] >> params->adaptiveThreshWinSizeMin;
+    fs["adaptiveThreshWinSizeMax"] >> params->adaptiveThreshWinSizeMax;
+    fs["adaptiveThreshWinSizeStep"] >> params->adaptiveThreshWinSizeStep;
+    fs["adaptiveThreshConstant"] >> params->adaptiveThreshConstant;
+    fs["minMarkerPerimeterRate"] >> params->minMarkerPerimeterRate;
+    fs["maxMarkerPerimeterRate"] >> params->maxMarkerPerimeterRate;
+    fs["polygonalApproxAccuracyRate"] >> params->polygonalApproxAccuracyRate;
+    fs["minCornerDistanceRate"] >> params->minCornerDistanceRate;
+    fs["minDistanceToBorder"] >> params->minDistanceToBorder;
+    fs["minMarkerDistanceRate"] >> params->minMarkerDistanceRate;
+    fs["doCornerRefinement"] >> params->doCornerRefinement;
+    fs["cornerRefinementWinSize"] >> params->cornerRefinementWinSize;
+    fs["cornerRefinementMaxIterations"] >> params->cornerRefinementMaxIterations;
+    fs["cornerRefinementMinAccuracy"] >> params->cornerRefinementMinAccuracy;
+    fs["markerBorderBits"] >> params->markerBorderBits;
+    fs["perspectiveRemovePixelPerCell"] >> params->perspectiveRemovePixelPerCell;
+    fs["perspectiveRemoveIgnoredMarginPerCell"] >> params->perspectiveRemoveIgnoredMarginPerCell;
+    fs["maxErroneousBitsInBorderRate"] >> params->maxErroneousBitsInBorderRate;
+    fs["minOtsuStdDev"] >> params->minOtsuStdDev;
+    fs["errorCorrectionRate"] >> params->errorCorrectionRate;
     return true;
 }
 
@@ -158,7 +158,7 @@ int main(int argc, char *argv[]) {
     }
 
     int markersX = parser.get<int>("w");
-    int markersY = parser.get<int>("w");
+    int markersY = parser.get<int>("h");
     float markerLength = parser.get<float>("l");
     float markerSeparation = parser.get<float>("s");
     int dictionaryId = parser.get<int>("d");
@@ -173,7 +173,7 @@ int main(int argc, char *argv[]) {
     if(parser.get<bool>("zt")) calibrationFlags |= CALIB_ZERO_TANGENT_DIST;
     if(parser.get<bool>("pc")) calibrationFlags |= CALIB_FIX_PRINCIPAL_POINT;
 
-    aruco::DetectorParameters detectorParams;
+    Ptr<aruco::DetectorParameters> detectorParams = aruco::DetectorParameters::create();
     if(parser.has("dp")) {
         bool readOk = readDetectorParameters(parser.get<string>("dp"), detectorParams);
         if(!readOk) {
@@ -205,12 +205,13 @@ int main(int argc, char *argv[]) {
         waitTime = 10;
     }
 
-    aruco::Dictionary dictionary =
+    Ptr<aruco::Dictionary> dictionary =
         aruco::getPredefinedDictionary(aruco::PREDEFINED_DICTIONARY_NAME(dictionaryId));
 
     // create board object
-    aruco::GridBoard board =
-        aruco::GridBoard::create(markersX, markersY, markerLength, markerSeparation, dictionary);
+    Ptr<aruco::GridBoard> gridboard =
+            aruco::GridBoard::create(markersX, markersY, markerLength, markerSeparation, dictionary);
+    Ptr<aruco::Board> board = gridboard.staticCast<aruco::Board>();
 
     // collected frames for calibration
     vector< vector< vector< Point2f > > > allCorners;
diff --git a/contrib/modules/aruco/samples/calibrate_camera_charuco.cpp b/contrib/modules/aruco/samples/calibrate_camera_charuco.cpp
index fb763f5..0b29349 100644
--- a/contrib/modules/aruco/samples/calibrate_camera_charuco.cpp
+++ b/contrib/modules/aruco/samples/calibrate_camera_charuco.cpp
@@ -57,8 +57,8 @@ const char* about =
 const char* keys  =
         "{w        |       | Number of squares in X direction }"
         "{h        |       | Number of squares in Y direction }"
-        "{sl       |       | Square side lenght (in pixels) }"
-        "{ml       |       | Marker side lenght (in pixels) }"
+        "{sl       |       | Square side length (in meters) }"
+        "{ml       |       | Marker side length (in meters) }"
         "{d        |       | dictionary: DICT_4X4_50=0, DICT_4X4_100=1, DICT_4X4_250=2,"
         "DICT_4X4_1000=3, DICT_5X5_50=4, DICT_5X5_100=5, DICT_5X5_250=6, DICT_5X5_1000=7, "
         "DICT_6X6_50=8, DICT_6X6_100=9, DICT_6X6_250=10, DICT_6X6_1000=11, DICT_7X7_50=12,"
@@ -76,30 +76,30 @@ const char* keys  =
 
 /**
  */
-static bool readDetectorParameters(string filename, aruco::DetectorParameters &params) {
+static bool readDetectorParameters(string filename, Ptr<aruco::DetectorParameters> &params) {
     FileStorage fs(filename, FileStorage::READ);
     if(!fs.isOpened())
         return false;
-    fs["adaptiveThreshWinSizeMin"] >> params.adaptiveThreshWinSizeMin;
-    fs["adaptiveThreshWinSizeMax"] >> params.adaptiveThreshWinSizeMax;
-    fs["adaptiveThreshWinSizeStep"] >> params.adaptiveThreshWinSizeStep;
-    fs["adaptiveThreshConstant"] >> params.adaptiveThreshConstant;
-    fs["minMarkerPerimeterRate"] >> params.minMarkerPerimeterRate;
-    fs["maxMarkerPerimeterRate"] >> params.maxMarkerPerimeterRate;
-    fs["polygonalApproxAccuracyRate"] >> params.polygonalApproxAccuracyRate;
-    fs["minCornerDistanceRate"] >> params.minCornerDistanceRate;
-    fs["minDistanceToBorder"] >> params.minDistanceToBorder;
-    fs["minMarkerDistanceRate"] >> params.minMarkerDistanceRate;
-    fs["doCornerRefinement"] >> params.doCornerRefinement;
-    fs["cornerRefinementWinSize"] >> params.cornerRefinementWinSize;
-    fs["cornerRefinementMaxIterations"] >> params.cornerRefinementMaxIterations;
-    fs["cornerRefinementMinAccuracy"] >> params.cornerRefinementMinAccuracy;
-    fs["markerBorderBits"] >> params.markerBorderBits;
-    fs["perspectiveRemovePixelPerCell"] >> params.perspectiveRemovePixelPerCell;
-    fs["perspectiveRemoveIgnoredMarginPerCell"] >> params.perspectiveRemoveIgnoredMarginPerCell;
-    fs["maxErroneousBitsInBorderRate"] >> params.maxErroneousBitsInBorderRate;
-    fs["minOtsuStdDev"] >> params.minOtsuStdDev;
-    fs["errorCorrectionRate"] >> params.errorCorrectionRate;
+    fs["adaptiveThreshWinSizeMin"] >> params->adaptiveThreshWinSizeMin;
+    fs["adaptiveThreshWinSizeMax"] >> params->adaptiveThreshWinSizeMax;
+    fs["adaptiveThreshWinSizeStep"] >> params->adaptiveThreshWinSizeStep;
+    fs["adaptiveThreshConstant"] >> params->adaptiveThreshConstant;
+    fs["minMarkerPerimeterRate"] >> params->minMarkerPerimeterRate;
+    fs["maxMarkerPerimeterRate"] >> params->maxMarkerPerimeterRate;
+    fs["polygonalApproxAccuracyRate"] >> params->polygonalApproxAccuracyRate;
+    fs["minCornerDistanceRate"] >> params->minCornerDistanceRate;
+    fs["minDistanceToBorder"] >> params->minDistanceToBorder;
+    fs["minMarkerDistanceRate"] >> params->minMarkerDistanceRate;
+    fs["doCornerRefinement"] >> params->doCornerRefinement;
+    fs["cornerRefinementWinSize"] >> params->cornerRefinementWinSize;
+    fs["cornerRefinementMaxIterations"] >> params->cornerRefinementMaxIterations;
+    fs["cornerRefinementMinAccuracy"] >> params->cornerRefinementMinAccuracy;
+    fs["markerBorderBits"] >> params->markerBorderBits;
+    fs["perspectiveRemovePixelPerCell"] >> params->perspectiveRemovePixelPerCell;
+    fs["perspectiveRemoveIgnoredMarginPerCell"] >> params->perspectiveRemoveIgnoredMarginPerCell;
+    fs["maxErroneousBitsInBorderRate"] >> params->maxErroneousBitsInBorderRate;
+    fs["minOtsuStdDev"] >> params->minOtsuStdDev;
+    fs["errorCorrectionRate"] >> params->errorCorrectionRate;
     return true;
 }
 
@@ -175,7 +175,7 @@ int main(int argc, char *argv[]) {
     if(parser.get<bool>("zt")) calibrationFlags |= CALIB_ZERO_TANGENT_DIST;
     if(parser.get<bool>("pc")) calibrationFlags |= CALIB_FIX_PRINCIPAL_POINT;
 
-    aruco::DetectorParameters detectorParams;
+    Ptr<aruco::DetectorParameters> detectorParams = aruco::DetectorParameters::create();
     if(parser.has("dp")) {
         bool readOk = readDetectorParameters(parser.get<string>("dp"), detectorParams);
         if(!readOk) {
@@ -207,12 +207,13 @@ int main(int argc, char *argv[]) {
         waitTime = 10;
     }
 
-    aruco::Dictionary dictionary =
+    Ptr<aruco::Dictionary> dictionary =
         aruco::getPredefinedDictionary(aruco::PREDEFINED_DICTIONARY_NAME(dictionaryId));
 
     // create charuco board object
-    aruco::CharucoBoard board =
-        aruco::CharucoBoard::create(squaresX, squaresY, squareLength, markerLength, dictionary);
+    Ptr<aruco::CharucoBoard> charucoboard =
+            aruco::CharucoBoard::create(squaresX, squaresY, squareLength, markerLength, dictionary);
+    Ptr<aruco::Board> board = charucoboard.staticCast<aruco::Board>();
 
     // collect data from each frame
     vector< vector< vector< Point2f > > > allCorners;
@@ -236,7 +237,7 @@ int main(int argc, char *argv[]) {
         // interpolate charuco corners
         Mat currentCharucoCorners, currentCharucoIds;
         if(ids.size() > 0)
-            aruco::interpolateCornersCharuco(corners, ids, image, board, currentCharucoCorners,
+            aruco::interpolateCornersCharuco(corners, ids, image, charucoboard, currentCharucoCorners,
                                              currentCharucoIds);
 
         // draw results
@@ -305,7 +306,7 @@ int main(int argc, char *argv[]) {
     for(int i = 0; i < nFrames; i++) {
         // interpolate using camera parameters
         Mat currentCharucoCorners, currentCharucoIds;
-        aruco::interpolateCornersCharuco(allCorners[i], allIds[i], allImgs[i], board,
+        aruco::interpolateCornersCharuco(allCorners[i], allIds[i], allImgs[i], charucoboard,
                                          currentCharucoCorners, currentCharucoIds, cameraMatrix,
                                          distCoeffs);
 
@@ -321,7 +322,7 @@ int main(int argc, char *argv[]) {
 
     // calibrate camera using charuco
     repError =
-        aruco::calibrateCameraCharuco(allCharucoCorners, allCharucoIds, board, imgSize,
+        aruco::calibrateCameraCharuco(allCharucoCorners, allCharucoIds, charucoboard, imgSize,
                                       cameraMatrix, distCoeffs, rvecs, tvecs, calibrationFlags);
 
     bool saveOk =  saveCameraParams(outputFile, imgSize, aspectRatio, calibrationFlags,
diff --git a/contrib/modules/aruco/samples/create_board.cpp b/contrib/modules/aruco/samples/create_board.cpp
index 7aeb2cc..937fe5b 100644
--- a/contrib/modules/aruco/samples/create_board.cpp
+++ b/contrib/modules/aruco/samples/create_board.cpp
@@ -48,7 +48,7 @@ const char* keys  =
         "{@outfile |<none> | Output image }"
         "{w        |       | Number of markers in X direction }"
         "{h        |       | Number of markers in Y direction }"
-        "{l        |       | Marker side lenght (in pixels) }"
+        "{l        |       | Marker side length (in pixels) }"
         "{s        |       | Separation between two consecutive markers in the grid (in pixels)}"
         "{d        |       | dictionary: DICT_4X4_50=0, DICT_4X4_100=1, DICT_4X4_250=2,"
         "DICT_4X4_1000=3, DICT_5X5_50=4, DICT_5X5_100=5, DICT_5X5_250=6, DICT_5X5_1000=7, "
@@ -93,15 +93,15 @@ int main(int argc, char *argv[]) {
     imageSize.height =
         markersY * (markerLength + markerSeparation) - markerSeparation + 2 * margins;
 
-    aruco::Dictionary dictionary =
+    Ptr<aruco::Dictionary> dictionary =
         aruco::getPredefinedDictionary(aruco::PREDEFINED_DICTIONARY_NAME(dictionaryId));
 
-    aruco::GridBoard board = aruco::GridBoard::create(markersX, markersY, float(markerLength),
+    Ptr<aruco::GridBoard> board = aruco::GridBoard::create(markersX, markersY, float(markerLength),
                                                       float(markerSeparation), dictionary);
 
     // show created board
     Mat boardImage;
-    board.draw(imageSize, boardImage, margins, borderBits);
+    board->draw(imageSize, boardImage, margins, borderBits);
 
     if(showImage) {
         imshow("board", boardImage);
diff --git a/contrib/modules/aruco/samples/create_board_charuco.cpp b/contrib/modules/aruco/samples/create_board_charuco.cpp
index 75f8f3a..1131382 100644
--- a/contrib/modules/aruco/samples/create_board_charuco.cpp
+++ b/contrib/modules/aruco/samples/create_board_charuco.cpp
@@ -48,8 +48,8 @@ const char* keys  =
         "{@outfile |<none> | Output image }"
         "{w        |       | Number of squares in X direction }"
         "{h        |       | Number of squares in Y direction }"
-        "{sl       |       | Square side lenght (in pixels) }"
-        "{ml       |       | Marker side lenght (in pixels) }"
+        "{sl       |       | Square side length (in pixels) }"
+        "{ml       |       | Marker side length (in pixels) }"
         "{d        |       | dictionary: DICT_4X4_50=0, DICT_4X4_100=1, DICT_4X4_250=2,"
         "DICT_4X4_1000=3, DICT_5X5_50=4, DICT_5X5_100=5, DICT_5X5_250=6, DICT_5X5_1000=7, "
         "DICT_6X6_50=8, DICT_6X6_100=9, DICT_6X6_250=10, DICT_6X6_1000=11, DICT_7X7_50=12,"
@@ -88,19 +88,19 @@ int main(int argc, char *argv[]) {
         return 0;
     }
 
-    aruco::Dictionary dictionary =
+    Ptr<aruco::Dictionary> dictionary =
         aruco::getPredefinedDictionary(aruco::PREDEFINED_DICTIONARY_NAME(dictionaryId));
 
     Size imageSize;
     imageSize.width = squaresX * squareLength + 2 * margins;
     imageSize.height = squaresY * squareLength + 2 * margins;
 
-    aruco::CharucoBoard board = aruco::CharucoBoard::create(squaresX, squaresY, (float)squareLength,
+    Ptr<aruco::CharucoBoard> board = aruco::CharucoBoard::create(squaresX, squaresY, (float)squareLength,
                                                             (float)markerLength, dictionary);
 
     // show created board
     Mat boardImage;
-    board.draw(imageSize, boardImage, margins, borderBits);
+    board->draw(imageSize, boardImage, margins, borderBits);
 
     if(showImage) {
         imshow("board", boardImage);
diff --git a/contrib/modules/aruco/samples/create_diamond.cpp b/contrib/modules/aruco/samples/create_diamond.cpp
index 5cb7f0b..66aec22 100644
--- a/contrib/modules/aruco/samples/create_diamond.cpp
+++ b/contrib/modules/aruco/samples/create_diamond.cpp
@@ -49,8 +49,8 @@ namespace {
 const char* about = "Create a ChArUco marker image";
 const char* keys  =
         "{@outfile |<none> | Output image }"
-        "{sl       |       | Square side lenght (in pixels) }"
-        "{ml       |       | Marker side lenght (in pixels) }"
+        "{sl       |       | Square side length (in pixels) }"
+        "{ml       |       | Marker side length (in pixels) }"
         "{d        |       | dictionary: DICT_4X4_50=0, DICT_4X4_100=1, DICT_4X4_250=2,"
         "DICT_4X4_1000=3, DICT_5X5_50=4, DICT_5X5_100=5, DICT_5X5_250=6, DICT_5X5_1000=7, "
         "DICT_6X6_50=8, DICT_6X6_100=9, DICT_6X6_250=10, DICT_6X6_1000=11, DICT_7X7_50=12,"
@@ -86,7 +86,7 @@ int main(int argc, char *argv[]) {
         return 0;
     }
 
-    aruco::Dictionary dictionary =
+    Ptr<aruco::Dictionary> dictionary =
         aruco::getPredefinedDictionary(aruco::PREDEFINED_DICTIONARY_NAME(dictionaryId));
 
     istringstream ss(idsString);
diff --git a/contrib/modules/aruco/samples/create_marker.cpp b/contrib/modules/aruco/samples/create_marker.cpp
index 922b238..4053742 100644
--- a/contrib/modules/aruco/samples/create_marker.cpp
+++ b/contrib/modules/aruco/samples/create_marker.cpp
@@ -79,7 +79,7 @@ int main(int argc, char *argv[]) {
         return 0;
     }
 
-    aruco::Dictionary dictionary =
+    Ptr<aruco::Dictionary> dictionary =
         aruco::getPredefinedDictionary(aruco::PREDEFINED_DICTIONARY_NAME(dictionaryId));
 
     Mat markerImg;
diff --git a/contrib/modules/aruco/samples/detect_board.cpp b/contrib/modules/aruco/samples/detect_board.cpp
index 534bd3c..5b173cc 100644
--- a/contrib/modules/aruco/samples/detect_board.cpp
+++ b/contrib/modules/aruco/samples/detect_board.cpp
@@ -79,30 +79,30 @@ static bool readCameraParameters(string filename, Mat &camMatrix, Mat &distCoeff
 
 /**
  */
-static bool readDetectorParameters(string filename, aruco::DetectorParameters &params) {
+static bool readDetectorParameters(string filename, Ptr<aruco::DetectorParameters> &params) {
     FileStorage fs(filename, FileStorage::READ);
     if(!fs.isOpened())
         return false;
-    fs["adaptiveThreshWinSizeMin"] >> params.adaptiveThreshWinSizeMin;
-    fs["adaptiveThreshWinSizeMax"] >> params.adaptiveThreshWinSizeMax;
-    fs["adaptiveThreshWinSizeStep"] >> params.adaptiveThreshWinSizeStep;
-    fs["adaptiveThreshConstant"] >> params.adaptiveThreshConstant;
-    fs["minMarkerPerimeterRate"] >> params.minMarkerPerimeterRate;
-    fs["maxMarkerPerimeterRate"] >> params.maxMarkerPerimeterRate;
-    fs["polygonalApproxAccuracyRate"] >> params.polygonalApproxAccuracyRate;
-    fs["minCornerDistanceRate"] >> params.minCornerDistanceRate;
-    fs["minDistanceToBorder"] >> params.minDistanceToBorder;
-    fs["minMarkerDistanceRate"] >> params.minMarkerDistanceRate;
-    fs["doCornerRefinement"] >> params.doCornerRefinement;
-    fs["cornerRefinementWinSize"] >> params.cornerRefinementWinSize;
-    fs["cornerRefinementMaxIterations"] >> params.cornerRefinementMaxIterations;
-    fs["cornerRefinementMinAccuracy"] >> params.cornerRefinementMinAccuracy;
-    fs["markerBorderBits"] >> params.markerBorderBits;
-    fs["perspectiveRemovePixelPerCell"] >> params.perspectiveRemovePixelPerCell;
-    fs["perspectiveRemoveIgnoredMarginPerCell"] >> params.perspectiveRemoveIgnoredMarginPerCell;
-    fs["maxErroneousBitsInBorderRate"] >> params.maxErroneousBitsInBorderRate;
-    fs["minOtsuStdDev"] >> params.minOtsuStdDev;
-    fs["errorCorrectionRate"] >> params.errorCorrectionRate;
+    fs["adaptiveThreshWinSizeMin"] >> params->adaptiveThreshWinSizeMin;
+    fs["adaptiveThreshWinSizeMax"] >> params->adaptiveThreshWinSizeMax;
+    fs["adaptiveThreshWinSizeStep"] >> params->adaptiveThreshWinSizeStep;
+    fs["adaptiveThreshConstant"] >> params->adaptiveThreshConstant;
+    fs["minMarkerPerimeterRate"] >> params->minMarkerPerimeterRate;
+    fs["maxMarkerPerimeterRate"] >> params->maxMarkerPerimeterRate;
+    fs["polygonalApproxAccuracyRate"] >> params->polygonalApproxAccuracyRate;
+    fs["minCornerDistanceRate"] >> params->minCornerDistanceRate;
+    fs["minDistanceToBorder"] >> params->minDistanceToBorder;
+    fs["minMarkerDistanceRate"] >> params->minMarkerDistanceRate;
+    fs["doCornerRefinement"] >> params->doCornerRefinement;
+    fs["cornerRefinementWinSize"] >> params->cornerRefinementWinSize;
+    fs["cornerRefinementMaxIterations"] >> params->cornerRefinementMaxIterations;
+    fs["cornerRefinementMinAccuracy"] >> params->cornerRefinementMinAccuracy;
+    fs["markerBorderBits"] >> params->markerBorderBits;
+    fs["perspectiveRemovePixelPerCell"] >> params->perspectiveRemovePixelPerCell;
+    fs["perspectiveRemoveIgnoredMarginPerCell"] >> params->perspectiveRemoveIgnoredMarginPerCell;
+    fs["maxErroneousBitsInBorderRate"] >> params->maxErroneousBitsInBorderRate;
+    fs["minOtsuStdDev"] >> params->minOtsuStdDev;
+    fs["errorCorrectionRate"] >> params->errorCorrectionRate;
     return true;
 }
 
@@ -137,7 +137,7 @@ int main(int argc, char *argv[]) {
         }
     }
 
-    aruco::DetectorParameters detectorParams;
+    Ptr<aruco::DetectorParameters> detectorParams = aruco::DetectorParameters::create();
     if(parser.has("dp")) {
         bool readOk = readDetectorParameters(parser.get<string>("dp"), detectorParams);
         if(!readOk) {
@@ -145,7 +145,7 @@ int main(int argc, char *argv[]) {
             return 0;
         }
     }
-    detectorParams.doCornerRefinement = true; // do corner refinement in markers
+    detectorParams->doCornerRefinement = true; // do corner refinement in markers
 
     String video;
     if(parser.has("v")) {
@@ -157,7 +157,7 @@ int main(int argc, char *argv[]) {
         return 0;
     }
 
-    aruco::Dictionary dictionary =
+    Ptr<aruco::Dictionary> dictionary =
         aruco::getPredefinedDictionary(aruco::PREDEFINED_DICTIONARY_NAME(dictionaryId));
 
     VideoCapture inputVideo;
@@ -174,8 +174,9 @@ int main(int argc, char *argv[]) {
                                markerSeparation);
 
     // create board object
-    aruco::GridBoard board =
+    Ptr<aruco::GridBoard> gridboard =
         aruco::GridBoard::create(markersX, markersY, markerLength, markerSeparation, dictionary);
+    Ptr<aruco::Board> board = gridboard.staticCast<aruco::Board>();
 
     double totalTime = 0;
     int totalIterations = 0;
diff --git a/contrib/modules/aruco/samples/detect_board_charuco.cpp b/contrib/modules/aruco/samples/detect_board_charuco.cpp
index 4c72e26..57f0c0d 100644
--- a/contrib/modules/aruco/samples/detect_board_charuco.cpp
+++ b/contrib/modules/aruco/samples/detect_board_charuco.cpp
@@ -51,8 +51,8 @@ const char* about = "Pose estimation using a ChArUco board";
 const char* keys  =
         "{w        |       | Number of squares in X direction }"
         "{h        |       | Number of squares in Y direction }"
-        "{sl       |       | Square side lenght (in pixels) }"
-        "{ml       |       | Marker side lenght (in pixels) }"
+        "{sl       |       | Square side length (in meters) }"
+        "{ml       |       | Marker side length (in meters) }"
         "{d        |       | dictionary: DICT_4X4_50=0, DICT_4X4_100=1, DICT_4X4_250=2,"
         "DICT_4X4_1000=3, DICT_5X5_50=4, DICT_5X5_100=5, DICT_5X5_250=6, DICT_5X5_1000=7, "
         "DICT_6X6_50=8, DICT_6X6_100=9, DICT_6X6_250=10, DICT_6X6_1000=11, DICT_7X7_50=12,"
@@ -79,30 +79,30 @@ static bool readCameraParameters(string filename, Mat &camMatrix, Mat &distCoeff
 
 /**
  */
-static bool readDetectorParameters(string filename, aruco::DetectorParameters &params) {
+static bool readDetectorParameters(string filename, Ptr<aruco::DetectorParameters> &params) {
     FileStorage fs(filename, FileStorage::READ);
     if(!fs.isOpened())
         return false;
-    fs["adaptiveThreshWinSizeMin"] >> params.adaptiveThreshWinSizeMin;
-    fs["adaptiveThreshWinSizeMax"] >> params.adaptiveThreshWinSizeMax;
-    fs["adaptiveThreshWinSizeStep"] >> params.adaptiveThreshWinSizeStep;
-    fs["adaptiveThreshConstant"] >> params.adaptiveThreshConstant;
-    fs["minMarkerPerimeterRate"] >> params.minMarkerPerimeterRate;
-    fs["maxMarkerPerimeterRate"] >> params.maxMarkerPerimeterRate;
-    fs["polygonalApproxAccuracyRate"] >> params.polygonalApproxAccuracyRate;
-    fs["minCornerDistanceRate"] >> params.minCornerDistanceRate;
-    fs["minDistanceToBorder"] >> params.minDistanceToBorder;
-    fs["minMarkerDistanceRate"] >> params.minMarkerDistanceRate;
-    fs["doCornerRefinement"] >> params.doCornerRefinement;
-    fs["cornerRefinementWinSize"] >> params.cornerRefinementWinSize;
-    fs["cornerRefinementMaxIterations"] >> params.cornerRefinementMaxIterations;
-    fs["cornerRefinementMinAccuracy"] >> params.cornerRefinementMinAccuracy;
-    fs["markerBorderBits"] >> params.markerBorderBits;
-    fs["perspectiveRemovePixelPerCell"] >> params.perspectiveRemovePixelPerCell;
-    fs["perspectiveRemoveIgnoredMarginPerCell"] >> params.perspectiveRemoveIgnoredMarginPerCell;
-    fs["maxErroneousBitsInBorderRate"] >> params.maxErroneousBitsInBorderRate;
-    fs["minOtsuStdDev"] >> params.minOtsuStdDev;
-    fs["errorCorrectionRate"] >> params.errorCorrectionRate;
+    fs["adaptiveThreshWinSizeMin"] >> params->adaptiveThreshWinSizeMin;
+    fs["adaptiveThreshWinSizeMax"] >> params->adaptiveThreshWinSizeMax;
+    fs["adaptiveThreshWinSizeStep"] >> params->adaptiveThreshWinSizeStep;
+    fs["adaptiveThreshConstant"] >> params->adaptiveThreshConstant;
+    fs["minMarkerPerimeterRate"] >> params->minMarkerPerimeterRate;
+    fs["maxMarkerPerimeterRate"] >> params->maxMarkerPerimeterRate;
+    fs["polygonalApproxAccuracyRate"] >> params->polygonalApproxAccuracyRate;
+    fs["minCornerDistanceRate"] >> params->minCornerDistanceRate;
+    fs["minDistanceToBorder"] >> params->minDistanceToBorder;
+    fs["minMarkerDistanceRate"] >> params->minMarkerDistanceRate;
+    fs["doCornerRefinement"] >> params->doCornerRefinement;
+    fs["cornerRefinementWinSize"] >> params->cornerRefinementWinSize;
+    fs["cornerRefinementMaxIterations"] >> params->cornerRefinementMaxIterations;
+    fs["cornerRefinementMinAccuracy"] >> params->cornerRefinementMinAccuracy;
+    fs["markerBorderBits"] >> params->markerBorderBits;
+    fs["perspectiveRemovePixelPerCell"] >> params->perspectiveRemovePixelPerCell;
+    fs["perspectiveRemoveIgnoredMarginPerCell"] >> params->perspectiveRemoveIgnoredMarginPerCell;
+    fs["maxErroneousBitsInBorderRate"] >> params->maxErroneousBitsInBorderRate;
+    fs["minOtsuStdDev"] >> params->minOtsuStdDev;
+    fs["errorCorrectionRate"] >> params->errorCorrectionRate;
     return true;
 }
 
@@ -141,7 +141,7 @@ int main(int argc, char *argv[]) {
         }
     }
 
-    aruco::DetectorParameters detectorParams;
+    Ptr<aruco::DetectorParameters> detectorParams = aruco::DetectorParameters::create();
     if(parser.has("dp")) {
         bool readOk = readDetectorParameters(parser.get<string>("dp"), detectorParams);
         if(!readOk) {
@@ -155,7 +155,7 @@ int main(int argc, char *argv[]) {
         return 0;
     }
 
-    aruco::Dictionary dictionary =
+    Ptr<aruco::Dictionary> dictionary =
         aruco::getPredefinedDictionary(aruco::PREDEFINED_DICTIONARY_NAME(dictionaryId));
 
     VideoCapture inputVideo;
@@ -171,8 +171,9 @@ int main(int argc, char *argv[]) {
     float axisLength = 0.5f * ((float)min(squaresX, squaresY) * (squareLength));
 
     // create charuco board object
-    aruco::CharucoBoard board =
+    Ptr<aruco::CharucoBoard> charucoboard =
         aruco::CharucoBoard::create(squaresX, squaresY, squareLength, markerLength, dictionary);
+    Ptr<aruco::Board> board = charucoboard.staticCast<aruco::Board>();
 
     double totalTime = 0;
     int totalIterations = 0;
@@ -201,13 +202,13 @@ int main(int argc, char *argv[]) {
         int interpolatedCorners = 0;
         if(markerIds.size() > 0)
             interpolatedCorners =
-                aruco::interpolateCornersCharuco(markerCorners, markerIds, image, board,
+                aruco::interpolateCornersCharuco(markerCorners, markerIds, image, charucoboard,
                                                  charucoCorners, charucoIds, camMatrix, distCoeffs);
 
         // estimate charuco board pose
         bool validPose = false;
         if(camMatrix.total() != 0)
-            validPose = aruco::estimatePoseCharucoBoard(charucoCorners, charucoIds, board,
+            validPose = aruco::estimatePoseCharucoBoard(charucoCorners, charucoIds, charucoboard,
                                                         camMatrix, distCoeffs, rvec, tvec);
 
 
diff --git a/contrib/modules/aruco/samples/detect_diamonds.cpp b/contrib/modules/aruco/samples/detect_diamonds.cpp
index d19418e..eda0dfc 100644
--- a/contrib/modules/aruco/samples/detect_diamonds.cpp
+++ b/contrib/modules/aruco/samples/detect_diamonds.cpp
@@ -49,8 +49,8 @@ using namespace cv;
 namespace {
 const char* about = "Detect ChArUco markers";
 const char* keys  =
-        "{sl       |       | Square side lenght (in pixels) }"
-        "{ml       |       | Marker side lenght (in pixels) }"
+        "{sl       |       | Square side length (in meters) }"
+        "{ml       |       | Marker side length (in meters) }"
         "{d        |       | dictionary: DICT_4X4_50=0, DICT_4X4_100=1, DICT_4X4_250=2,"
         "DICT_4X4_1000=3, DICT_5X5_50=4, DICT_5X5_100=5, DICT_5X5_250=6, DICT_5X5_1000=7, "
         "DICT_6X6_50=8, DICT_6X6_100=9, DICT_6X6_250=10, DICT_6X6_1000=11, DICT_7X7_50=12,"
@@ -80,30 +80,30 @@ static bool readCameraParameters(string filename, Mat &camMatrix, Mat &distCoeff
 
 /**
  */
-static bool readDetectorParameters(string filename, aruco::DetectorParameters &params) {
+static bool readDetectorParameters(string filename, Ptr<aruco::DetectorParameters> &params) {
     FileStorage fs(filename, FileStorage::READ);
     if(!fs.isOpened())
         return false;
-    fs["adaptiveThreshWinSizeMin"] >> params.adaptiveThreshWinSizeMin;
-    fs["adaptiveThreshWinSizeMax"] >> params.adaptiveThreshWinSizeMax;
-    fs["adaptiveThreshWinSizeStep"] >> params.adaptiveThreshWinSizeStep;
-    fs["adaptiveThreshConstant"] >> params.adaptiveThreshConstant;
-    fs["minMarkerPerimeterRate"] >> params.minMarkerPerimeterRate;
-    fs["maxMarkerPerimeterRate"] >> params.maxMarkerPerimeterRate;
-    fs["polygonalApproxAccuracyRate"] >> params.polygonalApproxAccuracyRate;
-    fs["minCornerDistanceRate"] >> params.minCornerDistanceRate;
-    fs["minDistanceToBorder"] >> params.minDistanceToBorder;
-    fs["minMarkerDistanceRate"] >> params.minMarkerDistanceRate;
-    fs["doCornerRefinement"] >> params.doCornerRefinement;
-    fs["cornerRefinementWinSize"] >> params.cornerRefinementWinSize;
-    fs["cornerRefinementMaxIterations"] >> params.cornerRefinementMaxIterations;
-    fs["cornerRefinementMinAccuracy"] >> params.cornerRefinementMinAccuracy;
-    fs["markerBorderBits"] >> params.markerBorderBits;
-    fs["perspectiveRemovePixelPerCell"] >> params.perspectiveRemovePixelPerCell;
-    fs["perspectiveRemoveIgnoredMarginPerCell"] >> params.perspectiveRemoveIgnoredMarginPerCell;
-    fs["maxErroneousBitsInBorderRate"] >> params.maxErroneousBitsInBorderRate;
-    fs["minOtsuStdDev"] >> params.minOtsuStdDev;
-    fs["errorCorrectionRate"] >> params.errorCorrectionRate;
+    fs["adaptiveThreshWinSizeMin"] >> params->adaptiveThreshWinSizeMin;
+    fs["adaptiveThreshWinSizeMax"] >> params->adaptiveThreshWinSizeMax;
+    fs["adaptiveThreshWinSizeStep"] >> params->adaptiveThreshWinSizeStep;
+    fs["adaptiveThreshConstant"] >> params->adaptiveThreshConstant;
+    fs["minMarkerPerimeterRate"] >> params->minMarkerPerimeterRate;
+    fs["maxMarkerPerimeterRate"] >> params->maxMarkerPerimeterRate;
+    fs["polygonalApproxAccuracyRate"] >> params->polygonalApproxAccuracyRate;
+    fs["minCornerDistanceRate"] >> params->minCornerDistanceRate;
+    fs["minDistanceToBorder"] >> params->minDistanceToBorder;
+    fs["minMarkerDistanceRate"] >> params->minMarkerDistanceRate;
+    fs["doCornerRefinement"] >> params->doCornerRefinement;
+    fs["cornerRefinementWinSize"] >> params->cornerRefinementWinSize;
+    fs["cornerRefinementMaxIterations"] >> params->cornerRefinementMaxIterations;
+    fs["cornerRefinementMinAccuracy"] >> params->cornerRefinementMinAccuracy;
+    fs["markerBorderBits"] >> params->markerBorderBits;
+    fs["perspectiveRemovePixelPerCell"] >> params->perspectiveRemovePixelPerCell;
+    fs["perspectiveRemoveIgnoredMarginPerCell"] >> params->perspectiveRemoveIgnoredMarginPerCell;
+    fs["maxErroneousBitsInBorderRate"] >> params->maxErroneousBitsInBorderRate;
+    fs["minOtsuStdDev"] >> params->minOtsuStdDev;
+    fs["errorCorrectionRate"] >> params->errorCorrectionRate;
     return true;
 }
 
@@ -127,7 +127,7 @@ int main(int argc, char *argv[]) {
     bool autoScale = parser.has("as");
     float autoScaleFactor = autoScale ? parser.get<float>("as") : 1.f;
 
-    aruco::DetectorParameters detectorParams;
+    Ptr<aruco::DetectorParameters> detectorParams = aruco::DetectorParameters::create();
     if(parser.has("dp")) {
         bool readOk = readDetectorParameters(parser.get<string>("dp"), detectorParams);
         if(!readOk) {
@@ -148,7 +148,7 @@ int main(int argc, char *argv[]) {
         return 0;
     }
 
-    aruco::Dictionary dictionary =
+    Ptr<aruco::Dictionary> dictionary =
         aruco::getPredefinedDictionary(aruco::PREDEFINED_DICTIONARY_NAME(dictionaryId));
 
     Mat camMatrix, distCoeffs;
diff --git a/contrib/modules/aruco/samples/detect_markers.cpp b/contrib/modules/aruco/samples/detect_markers.cpp
index 02882bf..d006a98 100644
--- a/contrib/modules/aruco/samples/detect_markers.cpp
+++ b/contrib/modules/aruco/samples/detect_markers.cpp
@@ -74,30 +74,30 @@ static bool readCameraParameters(string filename, Mat &camMatrix, Mat &distCoeff
 
 /**
  */
-static bool readDetectorParameters(string filename, aruco::DetectorParameters &params) {
+static bool readDetectorParameters(string filename, Ptr<aruco::DetectorParameters> &params) {
     FileStorage fs(filename, FileStorage::READ);
     if(!fs.isOpened())
         return false;
-    fs["adaptiveThreshWinSizeMin"] >> params.adaptiveThreshWinSizeMin;
-    fs["adaptiveThreshWinSizeMax"] >> params.adaptiveThreshWinSizeMax;
-    fs["adaptiveThreshWinSizeStep"] >> params.adaptiveThreshWinSizeStep;
-    fs["adaptiveThreshConstant"] >> params.adaptiveThreshConstant;
-    fs["minMarkerPerimeterRate"] >> params.minMarkerPerimeterRate;
-    fs["maxMarkerPerimeterRate"] >> params.maxMarkerPerimeterRate;
-    fs["polygonalApproxAccuracyRate"] >> params.polygonalApproxAccuracyRate;
-    fs["minCornerDistanceRate"] >> params.minCornerDistanceRate;
-    fs["minDistanceToBorder"] >> params.minDistanceToBorder;
-    fs["minMarkerDistanceRate"] >> params.minMarkerDistanceRate;
-    fs["doCornerRefinement"] >> params.doCornerRefinement;
-    fs["cornerRefinementWinSize"] >> params.cornerRefinementWinSize;
-    fs["cornerRefinementMaxIterations"] >> params.cornerRefinementMaxIterations;
-    fs["cornerRefinementMinAccuracy"] >> params.cornerRefinementMinAccuracy;
-    fs["markerBorderBits"] >> params.markerBorderBits;
-    fs["perspectiveRemovePixelPerCell"] >> params.perspectiveRemovePixelPerCell;
-    fs["perspectiveRemoveIgnoredMarginPerCell"] >> params.perspectiveRemoveIgnoredMarginPerCell;
-    fs["maxErroneousBitsInBorderRate"] >> params.maxErroneousBitsInBorderRate;
-    fs["minOtsuStdDev"] >> params.minOtsuStdDev;
-    fs["errorCorrectionRate"] >> params.errorCorrectionRate;
+    fs["adaptiveThreshWinSizeMin"] >> params->adaptiveThreshWinSizeMin;
+    fs["adaptiveThreshWinSizeMax"] >> params->adaptiveThreshWinSizeMax;
+    fs["adaptiveThreshWinSizeStep"] >> params->adaptiveThreshWinSizeStep;
+    fs["adaptiveThreshConstant"] >> params->adaptiveThreshConstant;
+    fs["minMarkerPerimeterRate"] >> params->minMarkerPerimeterRate;
+    fs["maxMarkerPerimeterRate"] >> params->maxMarkerPerimeterRate;
+    fs["polygonalApproxAccuracyRate"] >> params->polygonalApproxAccuracyRate;
+    fs["minCornerDistanceRate"] >> params->minCornerDistanceRate;
+    fs["minDistanceToBorder"] >> params->minDistanceToBorder;
+    fs["minMarkerDistanceRate"] >> params->minMarkerDistanceRate;
+    fs["doCornerRefinement"] >> params->doCornerRefinement;
+    fs["cornerRefinementWinSize"] >> params->cornerRefinementWinSize;
+    fs["cornerRefinementMaxIterations"] >> params->cornerRefinementMaxIterations;
+    fs["cornerRefinementMinAccuracy"] >> params->cornerRefinementMinAccuracy;
+    fs["markerBorderBits"] >> params->markerBorderBits;
+    fs["perspectiveRemovePixelPerCell"] >> params->perspectiveRemovePixelPerCell;
+    fs["perspectiveRemoveIgnoredMarginPerCell"] >> params->perspectiveRemoveIgnoredMarginPerCell;
+    fs["maxErroneousBitsInBorderRate"] >> params->maxErroneousBitsInBorderRate;
+    fs["minOtsuStdDev"] >> params->minOtsuStdDev;
+    fs["errorCorrectionRate"] >> params->errorCorrectionRate;
     return true;
 }
 
@@ -119,7 +119,7 @@ int main(int argc, char *argv[]) {
     bool estimatePose = parser.has("c");
     float markerLength = parser.get<float>("l");
 
-    aruco::DetectorParameters detectorParams;
+    Ptr<aruco::DetectorParameters> detectorParams = aruco::DetectorParameters::create();
     if(parser.has("dp")) {
         bool readOk = readDetectorParameters(parser.get<string>("dp"), detectorParams);
         if(!readOk) {
@@ -127,7 +127,7 @@ int main(int argc, char *argv[]) {
             return 0;
         }
     }
-    detectorParams.doCornerRefinement = true; // do corner refinement in markers
+    detectorParams->doCornerRefinement = true; // do corner refinement in markers
 
     int camId = parser.get<int>("ci");
 
@@ -141,7 +141,7 @@ int main(int argc, char *argv[]) {
         return 0;
     }
 
-    aruco::Dictionary dictionary =
+    Ptr<aruco::Dictionary> dictionary =
         aruco::getPredefinedDictionary(aruco::PREDEFINED_DICTIONARY_NAME(dictionaryId));
 
     Mat camMatrix, distCoeffs;
diff --git a/contrib/modules/aruco/samples/detector_params.yml b/contrib/modules/aruco/samples/detector_params.yml
index 764c717..ab94c03 100644
--- a/contrib/modules/aruco/samples/detector_params.yml
+++ b/contrib/modules/aruco/samples/detector_params.yml
@@ -1,5 +1,8 @@
 %YAML:1.0
 nmarkers: 1024
+adaptiveThreshWinSizeMin: 3
+adaptiveThreshWinSizeMax: 23
+adaptiveThreshWinSizeStep: 10
 adaptiveThreshWinSize: 21
 adaptiveThreshConstant: 7
 minMarkerPerimeterRate: 0.03
@@ -8,6 +11,8 @@ polygonalApproxAccuracyRate: 0.05
 minCornerDistance: 10.0
 minDistanceToBorder: 3
 minMarkerDistance: 10.0
+minMarkerDistanceRate: 0.05
+doCornerRefinement: false
 cornerRefinementWinSize: 5
 cornerRefinementMaxIterations: 30
 cornerRefinementMinAccuracy: 0.1
@@ -15,3 +20,5 @@ markerBorderBits: 1
 perspectiveRemovePixelPerCell: 8
 perspectiveRemoveIgnoredMarginPerCell: 0.13
 maxErroneousBitsInBorderRate: 0.04
+minOtsuStdDev: 5.0
+errorCorrectionRate: 0.6
diff --git a/contrib/modules/aruco/src/aruco.cpp b/contrib/modules/aruco/src/aruco.cpp
index 17e4977..f71aeca 100644
--- a/contrib/modules/aruco/src/aruco.cpp
+++ b/contrib/modules/aruco/src/aruco.cpp
@@ -41,7 +41,6 @@ the use of this software, even if advised of the possibility of such damage.
 #include <opencv2/core.hpp>
 #include <opencv2/imgproc.hpp>
 
-
 namespace cv {
 namespace aruco {
 
@@ -77,6 +76,15 @@ DetectorParameters::DetectorParameters()
 
 
 /**
+  * @brief Create a new set of DetectorParameters with default values.
+  */
+Ptr<DetectorParameters> DetectorParameters::create() {
+    Ptr<DetectorParameters> params = makePtr<DetectorParameters>();
+    return params;
+}
+
+
+/**
   * @brief Convert input image to gray if it is a 3-channels image
   */
 static void _convertToGrey(InputArray _in, OutputArray _out) {
@@ -206,7 +214,7 @@ static void _filterTooCloseCandidates(const vector< vector< Point2f > > &candida
 
             int minimumPerimeter = min((int)contoursIn[i].size(), (int)contoursIn[j].size() );
 
-            // fc is the first corner considered on one of the markers, 4 combinatios are posible
+            // fc is the first corner considered on one of the markers, 4 combinations are possible
             for(int fc = 0; fc < 4; fc++) {
                 double distSq = 0;
                 for(int c = 0; c < 4; c++) {
@@ -244,7 +252,7 @@ static void _filterTooCloseCandidates(const vector< vector< Point2f > > &candida
 
     // remove extra candidates
     candidatesOut.clear();
-    int totalRemaining = 0;
+    unsigned long totalRemaining = 0;
     for(unsigned int i = 0; i < toRemove.size(); i++)
         if(!toRemove[i]) totalRemaining++;
     candidatesOut.resize(totalRemaining);
@@ -267,7 +275,7 @@ class DetectInitialCandidatesParallel : public ParallelLoopBody {
     DetectInitialCandidatesParallel(const Mat *_grey,
                                     vector< vector< vector< Point2f > > > *_candidatesArrays,
                                     vector< vector< vector< Point > > > *_contoursArrays,
-                                    DetectorParameters *_params)
+                                    const Ptr<DetectorParameters> &_params)
         : grey(_grey), candidatesArrays(_candidatesArrays), contoursArrays(_contoursArrays),
           params(_params) {}
 
@@ -296,7 +304,7 @@ class DetectInitialCandidatesParallel : public ParallelLoopBody {
     const Mat *grey;
     vector< vector< vector< Point2f > > > *candidatesArrays;
     vector< vector< vector< Point > > > *contoursArrays;
-    DetectorParameters *params;
+    const Ptr<DetectorParameters> ¶ms;
 };
 
 
@@ -305,18 +313,18 @@ class DetectInitialCandidatesParallel : public ParallelLoopBody {
  */
 static void _detectInitialCandidates(const Mat &grey, vector< vector< Point2f > > &candidates,
                                      vector< vector< Point > > &contours,
-                                     DetectorParameters params) {
+                                     const Ptr<DetectorParameters> &params) {
 
-    CV_Assert(params.adaptiveThreshWinSizeMin >= 3 && params.adaptiveThreshWinSizeMax >= 3);
-    CV_Assert(params.adaptiveThreshWinSizeMax >= params.adaptiveThreshWinSizeMin);
-    CV_Assert(params.adaptiveThreshWinSizeStep > 0);
+    CV_Assert(params->adaptiveThreshWinSizeMin >= 3 && params->adaptiveThreshWinSizeMax >= 3);
+    CV_Assert(params->adaptiveThreshWinSizeMax >= params->adaptiveThreshWinSizeMin);
+    CV_Assert(params->adaptiveThreshWinSizeStep > 0);
 
     // number of window sizes (scales) to apply adaptive thresholding
-    int nScales = (params.adaptiveThreshWinSizeMax - params.adaptiveThreshWinSizeMin) /
-                      params.adaptiveThreshWinSizeStep + 1;
+    int nScales =  (params->adaptiveThreshWinSizeMax - params->adaptiveThreshWinSizeMin) /
+                      params->adaptiveThreshWinSizeStep + 1;
 
-    vector< vector< vector< Point2f > > > candidatesArrays(nScales);
-    vector< vector< vector< Point > > > contoursArrays(nScales);
+    vector< vector< vector< Point2f > > > candidatesArrays((size_t) nScales);
+    vector< vector< vector< Point > > > contoursArrays((size_t) nScales);
 
     ////for each value in the interval of thresholding window sizes
     // for(int i = 0; i < nScales; i++) {
@@ -333,7 +341,7 @@ static void _detectInitialCandidates(const Mat &grey, vector< vector< Point2f >
 
     // this is the parallel call for the previous commented loop (result is equivalent)
     parallel_for_(Range(0, nScales), DetectInitialCandidatesParallel(&grey, &candidatesArrays,
-                                                                     &contoursArrays, &params));
+                                                                     &contoursArrays, params));
 
     // join candidates
     for(int i = 0; i < nScales; i++) {
@@ -348,8 +356,8 @@ static void _detectInitialCandidates(const Mat &grey, vector< vector< Point2f >
 /**
  * @brief Detect square candidates in the input image
  */
-static void _detectCandidates(InputArray _image, OutputArrayOfArrays _candidates,
-                              OutputArrayOfArrays _contours, DetectorParameters params) {
+static void _detectCandidates(InputArray _image, vector< vector< Point2f > >& candidatesOut,
+                              vector< vector< Point > >& contoursOut, const Ptr<DetectorParameters> &_params) {
 
     Mat image = _image.getMat();
     CV_Assert(image.total() != 0);
@@ -361,31 +369,14 @@ static void _detectCandidates(InputArray _image, OutputArrayOfArrays _candidates
     vector< vector< Point2f > > candidates;
     vector< vector< Point > > contours;
     /// 2. DETECT FIRST SET OF CANDIDATES
-    _detectInitialCandidates(grey, candidates, contours, params);
+    _detectInitialCandidates(grey, candidates, contours, _params);
 
     /// 3. SORT CORNERS
     _reorderCandidatesCorners(candidates);
 
     /// 4. FILTER OUT NEAR CANDIDATE PAIRS
-    vector< vector< Point2f > > candidatesOut;
-    vector< vector< Point > > contoursOut;
     _filterTooCloseCandidates(candidates, candidatesOut, contours, contoursOut,
-                              params.minMarkerDistanceRate);
-
-    // parse output
-    _candidates.create((int)candidatesOut.size(), 1, CV_32FC2);
-    _contours.create((int)contoursOut.size(), 1, CV_32SC2);
-    for(int i = 0; i < (int)candidatesOut.size(); i++) {
-        _candidates.create(4, 1, CV_32FC2, i, true);
-        Mat m = _candidates.getMat(i);
-        for(int j = 0; j < 4; j++)
-            m.ptr< Vec2f >(0)[j] = candidatesOut[i][j];
-
-        _contours.create((int)contoursOut[i].size(), 1, CV_32SC2, i, true);
-        Mat c = _contours.getMat(i);
-        for(unsigned int j = 0; j < contoursOut[i].size(); j++)
-            c.ptr< Point2i >()[j] = contoursOut[i][j];
-    }
+                              _params->minMarkerDistanceRate);
 }
 
 
@@ -450,7 +441,7 @@ static Mat _extractBits(InputArray _image, InputArray _corners, int markerSize,
             Mat square = resultImg(Rect(Xstart, Ystart, cellSize - 2 * cellMarginPixels,
                                         cellSize - 2 * cellMarginPixels));
             // count white pixels on each cell to assign its value
-            unsigned int nZ = countNonZero(square);
+            size_t nZ = (size_t) countNonZero(square);
             if(nZ > square.total() / 2) bits.at< unsigned char >(y, x) = 1;
         }
     }
@@ -489,35 +480,35 @@ static int _getBorderErrors(const Mat &bits, int markerSize, int borderSize) {
 /**
  * @brief Tries to identify one candidate given the dictionary
  */
-static bool _identifyOneCandidate(const Dictionary &dictionary, InputArray _image,
-                                  InputOutputArray _corners, int &idx, DetectorParameters params) {
+static bool _identifyOneCandidate(const Ptr<Dictionary> &dictionary, InputArray _image,
+                                  InputOutputArray _corners, int &idx, const Ptr<DetectorParameters> &params) {
 
     CV_Assert(_corners.total() == 4);
     CV_Assert(_image.getMat().total() != 0);
-    CV_Assert(params.markerBorderBits > 0);
+    CV_Assert(params->markerBorderBits > 0);
 
     // get bits
     Mat candidateBits =
-        _extractBits(_image, _corners, dictionary.markerSize, params.markerBorderBits,
-                     params.perspectiveRemovePixelPerCell,
-                     params.perspectiveRemoveIgnoredMarginPerCell, params.minOtsuStdDev);
+        _extractBits(_image, _corners, dictionary->markerSize, params->markerBorderBits,
+                     params->perspectiveRemovePixelPerCell,
+                     params->perspectiveRemoveIgnoredMarginPerCell, params->minOtsuStdDev);
 
     // analyze border bits
     int maximumErrorsInBorder =
-        int(dictionary.markerSize * dictionary.markerSize * params.maxErroneousBitsInBorderRate);
+        int(dictionary->markerSize * dictionary->markerSize * params->maxErroneousBitsInBorderRate);
     int borderErrors =
-        _getBorderErrors(candidateBits, dictionary.markerSize, params.markerBorderBits);
+        _getBorderErrors(candidateBits, dictionary->markerSize, params->markerBorderBits);
     if(borderErrors > maximumErrorsInBorder) return false; // border is wrong
 
     // take only inner bits
     Mat onlyBits =
-        candidateBits.rowRange(params.markerBorderBits,
-                               candidateBits.rows - params.markerBorderBits)
-            .colRange(params.markerBorderBits, candidateBits.rows - params.markerBorderBits);
+        candidateBits.rowRange(params->markerBorderBits,
+                               candidateBits.rows - params->markerBorderBits)
+            .colRange(params->markerBorderBits, candidateBits.rows - params->markerBorderBits);
 
     // try to indentify the marker
     int rotation;
-    if(!dictionary.identify(onlyBits, idx, rotation, params.errorCorrectionRate))
+    if(!dictionary->identify(onlyBits, idx, rotation, params->errorCorrectionRate))
         return false;
     else {
         // shift corner positions to the correct rotation
@@ -538,10 +529,10 @@ static bool _identifyOneCandidate(const Dictionary &dictionary, InputArray _imag
   */
 class IdentifyCandidatesParallel : public ParallelLoopBody {
     public:
-    IdentifyCandidatesParallel(const Mat *_grey, InputArrayOfArrays _candidates,
-                               InputArrayOfArrays _contours, const Dictionary *_dictionary,
-                               vector< int > *_idsTmp, vector< char > *_validCandidates,
-                               DetectorParameters *_params)
+    IdentifyCandidatesParallel(const Mat& _grey, InputArrayOfArrays _candidates,
+                               InputArrayOfArrays _contours, const Ptr<Dictionary> &_dictionary,
+                               vector< int >& _idsTmp, vector< char >& _validCandidates,
+                               const Ptr<DetectorParameters> &_params)
         : grey(_grey), candidates(_candidates), contours(_contours), dictionary(_dictionary),
           idsTmp(_idsTmp), validCandidates(_validCandidates), params(_params) {}
 
@@ -552,9 +543,9 @@ class IdentifyCandidatesParallel : public ParallelLoopBody {
         for(int i = begin; i < end; i++) {
             int currId;
             Mat currentCandidate = candidates.getMat(i);
-            if(_identifyOneCandidate(*dictionary, *grey, currentCandidate, currId, *params)) {
-                (*validCandidates)[i] = 1;
-                (*idsTmp)[i] = currId;
+            if(_identifyOneCandidate(dictionary, grey, currentCandidate, currId, params)) {
+                validCandidates[i] = 1;
+                idsTmp[i] = currId;
             }
         }
     }
@@ -562,30 +553,64 @@ class IdentifyCandidatesParallel : public ParallelLoopBody {
     private:
     IdentifyCandidatesParallel &operator=(const IdentifyCandidatesParallel &); // to quiet MSVC
 
-    const Mat *grey;
+    const Mat &grey;
     InputArrayOfArrays candidates, contours;
-    const Dictionary *dictionary;
-    vector< int > *idsTmp;
-    vector< char > *validCandidates;
-    DetectorParameters *params;
+    const Ptr<Dictionary> &dictionary;
+    vector< int > &idsTmp;
+    vector< char > &validCandidates;
+    const Ptr<DetectorParameters> ¶ms;
 };
 
 
 
 /**
+ * @brief Copy the contents of a corners vector to an OutputArray, settings its size.
+ */
+static void _copyVector2Output(vector< vector< Point2f > > &vec, OutputArrayOfArrays out) {
+    out.create((int)vec.size(), 1, CV_32FC2);
+
+    if(out.isMatVector()) {
+        for (unsigned int i = 0; i < vec.size(); i++) {
+            out.create(4, 1, CV_32FC2, i);
+            Mat &m = out.getMatRef(i);
+            Mat(Mat(vec[i]).t()).copyTo(m);
+        }
+    }
+    else if(out.isUMatVector()) {
+        for (unsigned int i = 0; i < vec.size(); i++) {
+            out.create(4, 1, CV_32FC2, i);
+            UMat &m = out.getUMatRef(i);
+            Mat(Mat(vec[i]).t()).copyTo(m);
+        }
+    }
+    else if(out.kind() == _OutputArray::STD_VECTOR_VECTOR){
+        for (unsigned int i = 0; i < vec.size(); i++) {
+            out.create(4, 1, CV_32FC2, i);
+            Mat m = out.getMat(i);
+            Mat(Mat(vec[i]).t()).copyTo(m);
+        }
+    }
+    else {
+        CV_Error(cv::Error::StsNotImplemented,
+                 "Only Mat vector, UMat vector, and vector<vector> OutputArrays are currently supported.");
+    }
+}
+
+
+
+/**
  * @brief Identify square candidates according to a marker dictionary
  */
-static void _identifyCandidates(InputArray _image, InputArrayOfArrays _candidates,
-                                InputArrayOfArrays _contours, const Dictionary &dictionary,
-                                OutputArrayOfArrays _accepted, OutputArray _ids,
-                                DetectorParameters params,
+static void _identifyCandidates(InputArray _image, vector< vector< Point2f > >& _candidates,
+                                InputArrayOfArrays _contours, const Ptr<Dictionary> &_dictionary,
+                                vector< vector< Point2f > >& _accepted, vector< int >& ids,
+                                const Ptr<DetectorParameters> &params,
                                 OutputArrayOfArrays _rejected = noArray()) {
 
-    int ncandidates = (int)_candidates.total();
+    int ncandidates = (int)_candidates.size();
 
-    vector< Mat > accepted;
-    vector< Mat > rejected;
-    vector< int > ids;
+    vector< vector< Point2f > > accepted;
+    vector< vector< Point2f > > rejected;
 
     CV_Assert(_image.getMat().total() != 0);
 
@@ -607,37 +632,23 @@ static void _identifyCandidates(InputArray _image, InputArrayOfArrays _candidate
 
     // this is the parallel call for the previous commented loop (result is equivalent)
     parallel_for_(Range(0, ncandidates),
-                  IdentifyCandidatesParallel(&grey, _candidates, _contours, &dictionary, &idsTmp,
-                                             &validCandidates, &params));
+                  IdentifyCandidatesParallel(grey, _candidates, _contours, _dictionary, idsTmp,
+                                             validCandidates, params));
 
     for(int i = 0; i < ncandidates; i++) {
         if(validCandidates[i] == 1) {
-            accepted.push_back(_candidates.getMat(i));
+            accepted.push_back(_candidates[i]);
             ids.push_back(idsTmp[i]);
         } else {
-            rejected.push_back(_candidates.getMat(i));
+            rejected.push_back(_candidates[i]);
         }
     }
 
     // parse output
-    _accepted.create((int)accepted.size(), 1, CV_32FC2);
-    for(unsigned int i = 0; i < accepted.size(); i++) {
-        _accepted.create(4, 1, CV_32FC2, i, true);
-        Mat m = _accepted.getMat(i);
-        accepted[i].copyTo(m);
-    }
-
-    _ids.create((int)ids.size(), 1, CV_32SC1);
-    for(unsigned int i = 0; i < ids.size(); i++)
-        _ids.getMat().ptr< int >(0)[i] = ids[i];
+    _accepted = accepted;
 
     if(_rejected.needed()) {
-        _rejected.create((int)rejected.size(), 1, CV_32FC2);
-        for(unsigned int i = 0; i < rejected.size(); i++) {
-            _rejected.create(4, 1, CV_32FC2, i, true);
-            Mat m = _rejected.getMat(i);
-            rejected[i].copyTo(m);
-        }
+        _copyVector2Output(rejected, _rejected);
     }
 }
 
@@ -645,26 +656,25 @@ static void _identifyCandidates(InputArray _image, InputArrayOfArrays _candidate
 /**
   * @brief Final filter of markers after its identification
   */
-static void _filterDetectedMarkers(InputArrayOfArrays _inCorners, InputArray _inIds,
-                                   OutputArrayOfArrays _outCorners, OutputArray _outIds) {
+static void _filterDetectedMarkers(vector< vector< Point2f > >& _corners, vector< int >& _ids) {
 
-    CV_Assert(_inCorners.total() == _inIds.total());
-    if(_inCorners.total() == 0) return;
+    CV_Assert(_corners.size() == _ids.size());
+    if(_corners.empty()) return;
 
     // mark markers that will be removed
-    vector< bool > toRemove(_inCorners.total(), false);
+    vector< bool > toRemove(_corners.size(), false);
     bool atLeastOneRemove = false;
 
     // remove repeated markers with same id, if one contains the other (doble border bug)
-    for(unsigned int i = 0; i < _inCorners.total() - 1; i++) {
-        for(unsigned int j = i + 1; j < _inCorners.total(); j++) {
-            if(_inIds.getMat().ptr< int >(0)[i] != _inIds.getMat().ptr< int >(0)[j]) continue;
+    for(unsigned int i = 0; i < _corners.size() - 1; i++) {
+        for(unsigned int j = i + 1; j < _corners.size(); j++) {
+            if(_ids[i] != _ids[j]) continue;
 
             // check if first marker is inside second
             bool inside = true;
             for(unsigned int p = 0; p < 4; p++) {
-                Point2f point = _inCorners.getMat(j).ptr< Point2f >(0)[p];
-                if(pointPolygonTest(_inCorners.getMat(i), point, false) < 0) {
+                Point2f point = _corners[j][p];
+                if(pointPolygonTest(_corners[i], point, false) < 0) {
                     inside = false;
                     break;
                 }
@@ -678,8 +688,8 @@ static void _filterDetectedMarkers(InputArrayOfArrays _inCorners, InputArray _in
             // check the second marker
             inside = true;
             for(unsigned int p = 0; p < 4; p++) {
-                Point2f point = _inCorners.getMat(i).ptr< Point2f >(0)[p];
-                if(pointPolygonTest(_inCorners.getMat(j), point, false) < 0) {
+                Point2f point = _corners[i][p];
+                if(pointPolygonTest(_corners[j], point, false) < 0) {
                     inside = false;
                     break;
                 }
@@ -694,25 +704,18 @@ static void _filterDetectedMarkers(InputArrayOfArrays _inCorners, InputArray _in
 
     // parse output
     if(atLeastOneRemove) {
-        vector< Mat > filteredCorners;
-        vector< int > filteredIds;
+        vector< vector< Point2f > >::iterator filteredCorners = _corners.begin();
+        vector< int >::iterator filteredIds = _ids.begin();
 
         for(unsigned int i = 0; i < toRemove.size(); i++) {
             if(!toRemove[i]) {
-                filteredCorners.push_back(_inCorners.getMat(i).clone());
-                filteredIds.push_back(_inIds.getMat().ptr< int >(0)[i]);
+                *filteredCorners++ = _corners[i];
+                *filteredIds++ = _ids[i];
             }
         }
 
-        _outIds.create((int)filteredIds.size(), 1, CV_32SC1);
-        for(unsigned int i = 0; i < filteredIds.size(); i++)
-            _outIds.getMat().ptr< int >(0)[i] = filteredIds[i];
-
-        _outCorners.create((int)filteredCorners.size(), 1, CV_32FC2);
-        for(unsigned int i = 0; i < filteredCorners.size(); i++) {
-            _outCorners.create(4, 1, CV_32FC2, i, true);
-            filteredCorners[i].copyTo(_outCorners.getMat(i));
-        }
+        _ids.erase(filteredIds, _ids.end());
+        _corners.erase(filteredCorners, _corners.end());
     }
 }
 
@@ -744,7 +747,7 @@ static void _getSingleMarkerObjectPoints(float markerLength, OutputArray _objPoi
 class MarkerSubpixelParallel : public ParallelLoopBody {
     public:
     MarkerSubpixelParallel(const Mat *_grey, OutputArrayOfArrays _corners,
-                           DetectorParameters *_params)
+                           const Ptr<DetectorParameters> &_params)
         : grey(_grey), corners(_corners), params(_params) {}
 
     void operator()(const Range &range) const {
@@ -765,18 +768,18 @@ class MarkerSubpixelParallel : public ParallelLoopBody {
 
     const Mat *grey;
     OutputArrayOfArrays corners;
-    DetectorParameters *params;
+    const Ptr<DetectorParameters> ¶ms;
 };
 
 
 
 /**
   */
-void detectMarkers(InputArray _image, Dictionary dictionary, OutputArrayOfArrays _corners,
-                   OutputArray _ids, DetectorParameters params,
+void detectMarkers(InputArray _image, const Ptr<Dictionary> &_dictionary, OutputArrayOfArrays _corners,
+                   OutputArray _ids, const Ptr<DetectorParameters> &_params,
                    OutputArrayOfArrays _rejectedImgPoints) {
 
-    CV_Assert(_image.getMat().total() != 0);
+    CV_Assert(!_image.empty());
 
     Mat grey;
     _convertToGrey(_image.getMat(), grey);
@@ -784,22 +787,27 @@ void detectMarkers(InputArray _image, Dictionary dictionary, OutputArrayOfArrays
     /// STEP 1: Detect marker candidates
     vector< vector< Point2f > > candidates;
     vector< vector< Point > > contours;
-    _detectCandidates(grey, candidates, contours, params);
+    vector< int > ids;
+    _detectCandidates(grey, candidates, contours, _params);
 
     /// STEP 2: Check candidate codification (identify markers)
-    _identifyCandidates(grey, candidates, contours, dictionary, _corners, _ids, params,
+    _identifyCandidates(grey, candidates, contours, _dictionary, candidates, ids, _params,
                         _rejectedImgPoints);
 
     /// STEP 3: Filter detected markers;
-    _filterDetectedMarkers(_corners, _ids, _corners, _ids);
+    _filterDetectedMarkers(candidates, ids);
+
+    // copy to output arrays
+    _copyVector2Output(candidates, _corners);
+    Mat(ids).copyTo(_ids);
 
     /// STEP 4: Corner refinement
-    if(params.doCornerRefinement) {
-        CV_Assert(params.cornerRefinementWinSize > 0 && params.cornerRefinementMaxIterations > 0 &&
-                  params.cornerRefinementMinAccuracy > 0);
+    if(_params->doCornerRefinement) {
+        CV_Assert(_params->cornerRefinementWinSize > 0 && _params->cornerRefinementMaxIterations > 0 &&
+                  _params->cornerRefinementMinAccuracy > 0);
 
         //// do corner refinement for each of the detected markers
-        // for (unsigned int i = 0; i < _corners.total(); i++) {
+        // for (unsigned int i = 0; i < _corners.cols(); i++) {
         //    cornerSubPix(grey, _corners.getMat(i),
         //                 Size(params.cornerRefinementWinSize, params.cornerRefinementWinSize),
         //                 Size(-1, -1), TermCriteria(TermCriteria::MAX_ITER | TermCriteria::EPS,
@@ -808,8 +816,8 @@ void detectMarkers(InputArray _image, Dictionary dictionary, OutputArrayOfArrays
         //}
 
         // this is the parallel call for the previous commented loop (result is equivalent)
-        parallel_for_(Range(0, (int)_corners.total()),
-                      MarkerSubpixelParallel(&grey, _corners, &params));
+        parallel_for_(Range(0, _corners.cols()),
+                      MarkerSubpixelParallel(&grey, _corners, _params));
     }
 }
 
@@ -833,7 +841,7 @@ class SinglePoseEstimationParallel : public ParallelLoopBody {
 
         for(int i = begin; i < end; i++) {
             solvePnP(markerObjPoints, corners.getMat(i), cameraMatrix, distCoeffs,
-                    rvecs.at<Vec3d>(0, i), tvecs.at<Vec3d>(0, i));
+                    rvecs.at<Vec3d>(i), tvecs.at<Vec3d>(i));
         }
     }
 
@@ -853,7 +861,7 @@ class SinglePoseEstimationParallel : public ParallelLoopBody {
   */
 void estimatePoseSingleMarkers(InputArrayOfArrays _corners, float markerLength,
                                InputArray _cameraMatrix, InputArray _distCoeffs,
-                               OutputArrayOfArrays _rvecs, OutputArrayOfArrays _tvecs) {
+                               OutputArray _rvecs, OutputArray _tvecs) {
 
     CV_Assert(markerLength > 0);
 
@@ -883,14 +891,14 @@ void estimatePoseSingleMarkers(InputArrayOfArrays _corners, float markerLength,
   * @brief Given a board configuration and a set of detected markers, returns the corresponding
   * image points and object points to call solvePnP
   */
-static void _getBoardObjectAndImagePoints(const Board &board, InputArray _detectedIds,
+static void _getBoardObjectAndImagePoints(const Ptr<Board> &_board, InputArray _detectedIds,
                                           InputArrayOfArrays _detectedCorners,
                                           OutputArray _imgPoints, OutputArray _objPoints) {
 
-    CV_Assert(board.ids.size() == board.objPoints.size());
+    CV_Assert(_board->ids.size() == _board->objPoints.size());
     CV_Assert(_detectedIds.total() == _detectedCorners.total());
 
-    int nDetectedMarkers = (int)_detectedIds.total();
+    size_t nDetectedMarkers = _detectedIds.total();
 
     vector< Point3f > objPnts;
     objPnts.reserve(nDetectedMarkers);
@@ -899,12 +907,12 @@ static void _getBoardObjectAndImagePoints(const Board &board, InputArray _detect
     imgPnts.reserve(nDetectedMarkers);
 
     // look for detected markers that belong to the board and get their information
-    for(int i = 0; i < nDetectedMarkers; i++) {
+    for(unsigned int i = 0; i < nDetectedMarkers; i++) {
         int currentId = _detectedIds.getMat().ptr< int >(0)[i];
-        for(unsigned int j = 0; j < board.ids.size(); j++) {
-            if(currentId == board.ids[j]) {
+        for(unsigned int j = 0; j < _board->ids.size(); j++) {
+            if(currentId == _board->ids[j]) {
                 for(int p = 0; p < 4; p++) {
-                    objPnts.push_back(board.objPoints[j][p]);
+                    objPnts.push_back(_board->objPoints[j][p]);
                     imgPnts.push_back(_detectedCorners.getMat(i).ptr< Point2f >(0)[p]);
                 }
             }
@@ -912,13 +920,8 @@ static void _getBoardObjectAndImagePoints(const Board &board, InputArray _detect
     }
 
     // create output
-    _objPoints.create((int)objPnts.size(), 1, CV_32FC3);
-    for(unsigned int i = 0; i < objPnts.size(); i++)
-        _objPoints.getMat().ptr< Point3f >(0)[i] = objPnts[i];
-
-    _imgPoints.create((int)objPnts.size(), 1, CV_32FC2);
-    for(unsigned int i = 0; i < imgPnts.size(); i++)
-        _imgPoints.getMat().ptr< Point2f >(0)[i] = imgPnts[i];
+    Mat(objPnts).copyTo(_objPoints);
+    Mat(imgPnts).copyTo(_imgPoints);
 }
 
 
@@ -926,16 +929,16 @@ static void _getBoardObjectAndImagePoints(const Board &board, InputArray _detect
 /**
   * Project board markers that are not included in the list of detected markers
   */
-static void _projectUndetectedMarkers(const Board &board, InputOutputArrayOfArrays _detectedCorners,
+static void _projectUndetectedMarkers(const Ptr<Board> &_board, InputOutputArrayOfArrays _detectedCorners,
                                       InputOutputArray _detectedIds, InputArray _cameraMatrix,
                                       InputArray _distCoeffs,
-                                      OutputArrayOfArrays _undetectedMarkersProjectedCorners,
+                                      vector< vector< Point2f > >& _undetectedMarkersProjectedCorners,
                                       OutputArray _undetectedMarkersIds) {
 
     // first estimate board pose with the current avaible markers
     Mat rvec, tvec;
     int boardDetectedMarkers;
-    boardDetectedMarkers = aruco::estimatePoseBoard(_detectedCorners, _detectedIds, board,
+    boardDetectedMarkers = aruco::estimatePoseBoard(_detectedCorners, _detectedIds, _board,
                                                     _cameraMatrix, _distCoeffs, rvec, tvec);
 
     // at least one marker from board so rvec and tvec are valid
@@ -944,10 +947,10 @@ static void _projectUndetectedMarkers(const Board &board, InputOutputArrayOfArra
     // search undetected markers and project them using the previous pose
     vector< vector< Point2f > > undetectedCorners;
     vector< int > undetectedIds;
-    for(unsigned int i = 0; i < board.ids.size(); i++) {
+    for(unsigned int i = 0; i < _board->ids.size(); i++) {
         int foundIdx = -1;
         for(unsigned int j = 0; j < _detectedIds.total(); j++) {
-            if(board.ids[i] == _detectedIds.getMat().ptr< int >()[j]) {
+            if(_board->ids[i] == _detectedIds.getMat().ptr< int >()[j]) {
                 foundIdx = j;
                 break;
             }
@@ -956,26 +959,16 @@ static void _projectUndetectedMarkers(const Board &board, InputOutputArrayOfArra
         // not detected
         if(foundIdx == -1) {
             undetectedCorners.push_back(vector< Point2f >());
-            undetectedIds.push_back(board.ids[i]);
-            projectPoints(board.objPoints[i], rvec, tvec, _cameraMatrix, _distCoeffs,
+            undetectedIds.push_back(_board->ids[i]);
+            projectPoints(_board->objPoints[i], rvec, tvec, _cameraMatrix, _distCoeffs,
                           undetectedCorners.back());
         }
     }
 
 
     // parse output
-    _undetectedMarkersIds.create((int)undetectedIds.size(), 1, CV_32SC1);
-    for(unsigned int i = 0; i < undetectedIds.size(); i++)
-        _undetectedMarkersIds.getMat().ptr< int >(0)[i] = undetectedIds[i];
-
-    _undetectedMarkersProjectedCorners.create((int)undetectedCorners.size(), 1, CV_32FC2);
-    for(unsigned int i = 0; i < undetectedCorners.size(); i++) {
-        _undetectedMarkersProjectedCorners.create(4, 1, CV_32FC2, i, true);
-        for(int j = 0; j < 4; j++) {
-            _undetectedMarkersProjectedCorners.getMat(i).ptr< Point2f >()[j] =
-                undetectedCorners[i][j];
-        }
-    }
+    Mat(undetectedIds).copyTo(_undetectedMarkersIds);
+    _undetectedMarkersProjectedCorners = undetectedCorners;
 }
 
 
@@ -984,19 +977,19 @@ static void _projectUndetectedMarkers(const Board &board, InputOutputArrayOfArra
   * Interpolate board markers that are not included in the list of detected markers using
   * global homography
   */
-static void _projectUndetectedMarkers(const Board &board, InputOutputArrayOfArrays _detectedCorners,
+static void _projectUndetectedMarkers(const Ptr<Board> &_board, InputOutputArrayOfArrays _detectedCorners,
                                       InputOutputArray _detectedIds,
-                                      OutputArrayOfArrays _undetectedMarkersProjectedCorners,
+                                      vector< vector< Point2f > >& _undetectedMarkersProjectedCorners,
                                       OutputArray _undetectedMarkersIds) {
 
 
     // check board points are in the same plane, if not, global homography cannot be applied
-    CV_Assert(board.objPoints.size() > 0);
-    CV_Assert(board.objPoints[0].size() > 0);
-    float boardZ = board.objPoints[0][0].z;
-    for(unsigned int i = 0; i < board.objPoints.size(); i++) {
-        for(unsigned int j = 0; j < board.objPoints[i].size(); j++) {
-            CV_Assert(boardZ == board.objPoints[i][j].z);
+    CV_Assert(_board->objPoints.size() > 0);
+    CV_Assert(_board->objPoints[0].size() > 0);
+    float boardZ = _board->objPoints[0][0].z;
+    for(unsigned int i = 0; i < _board->objPoints.size(); i++) {
+        for(unsigned int j = 0; j < _board->objPoints[i].size(); j++) {
+            CV_Assert(boardZ == _board->objPoints[i][j].z);
         }
     }
 
@@ -1007,14 +1000,14 @@ static void _projectUndetectedMarkers(const Board &board, InputOutputArrayOfArra
                                                         // missing markers in different vectors
     vector< int > undetectedMarkersIds; // ids of missing markers
     // find markers included in board, and missing markers from board. Fill the previous vectors
-    for(unsigned int j = 0; j < board.ids.size(); j++) {
+    for(unsigned int j = 0; j < _board->ids.size(); j++) {
         bool found = false;
         for(unsigned int i = 0; i < _detectedIds.total(); i++) {
-            if(_detectedIds.getMat().ptr< int >()[i] == board.ids[j]) {
+            if(_detectedIds.getMat().ptr< int >()[i] == _board->ids[j]) {
                 for(int c = 0; c < 4; c++) {
                     imageCornersAll.push_back(_detectedCorners.getMat(i).ptr< Point2f >()[c]);
                     detectedMarkersObj2DAll.push_back(
-                        Point2f(board.objPoints[j][c].x, board.objPoints[j][c].y));
+                        Point2f(_board->objPoints[j][c].x, _board->objPoints[j][c].y));
                 }
                 found = true;
                 break;
@@ -1024,9 +1017,9 @@ static void _projectUndetectedMarkers(const Board &board, InputOutputArrayOfArra
             undetectedMarkersObj2D.push_back(vector< Point2f >());
             for(int c = 0; c < 4; c++) {
                 undetectedMarkersObj2D.back().push_back(
-                    Point2f(board.objPoints[j][c].x, board.objPoints[j][c].y));
+                    Point2f(_board->objPoints[j][c].x, _board->objPoints[j][c].y));
             }
-            undetectedMarkersIds.push_back(board.ids[j]);
+            undetectedMarkersIds.push_back(_board->ids[j]);
         }
     }
     if(imageCornersAll.size() == 0) return;
@@ -1034,48 +1027,44 @@ static void _projectUndetectedMarkers(const Board &board, InputOutputArrayOfArra
     // get homography from detected markers
     Mat transformation = findHomography(detectedMarkersObj2DAll, imageCornersAll);
 
-    _undetectedMarkersProjectedCorners.create((int)undetectedMarkersIds.size(), 1, CV_32FC2);
+    _undetectedMarkersProjectedCorners.resize(undetectedMarkersIds.size());
 
     // for each undetected marker, apply transformation
     for(unsigned int i = 0; i < undetectedMarkersObj2D.size(); i++) {
-        Mat projectedMarker;
-        perspectiveTransform(undetectedMarkersObj2D[i], projectedMarker, transformation);
-
-        _undetectedMarkersProjectedCorners.create(4, 1, CV_32FC2, i, true);
-        projectedMarker.copyTo(_undetectedMarkersProjectedCorners.getMat(i));
+        perspectiveTransform(undetectedMarkersObj2D[i], _undetectedMarkersProjectedCorners[i], transformation);
     }
 
-    _undetectedMarkersIds.create((int)undetectedMarkersIds.size(), 1, CV_32SC1);
-    for(unsigned int i = 0; i < undetectedMarkersIds.size(); i++)
-        _undetectedMarkersIds.getMat().ptr< int >(0)[i] = undetectedMarkersIds[i];
+    Mat(undetectedMarkersIds).copyTo(_undetectedMarkersIds);
 }
 
 
 
 /**
   */
-void refineDetectedMarkers(InputArray _image, const Board &board,
+void refineDetectedMarkers(InputArray _image, const Ptr<Board> &_board,
                            InputOutputArrayOfArrays _detectedCorners, InputOutputArray _detectedIds,
-                           InputOutputArray _rejectedCorners, InputArray _cameraMatrix,
+                           InputOutputArrayOfArrays _rejectedCorners, InputArray _cameraMatrix,
                            InputArray _distCoeffs, float minRepDistance, float errorCorrectionRate,
                            bool checkAllOrders, OutputArray _recoveredIdxs,
-                           DetectorParameters params) {
+                           const Ptr<DetectorParameters> &_params) {
 
     CV_Assert(minRepDistance > 0);
 
     if(_detectedIds.total() == 0 || _rejectedCorners.total() == 0) return;
 
+    DetectorParameters &params = *_params;
+
     // get projections of missing markers in the board
     vector< vector< Point2f > > undetectedMarkersCorners;
     vector< int > undetectedMarkersIds;
     if(_cameraMatrix.total() != 0) {
         // reproject based on camera projection model
-        _projectUndetectedMarkers(board, _detectedCorners, _detectedIds, _cameraMatrix, _distCoeffs,
+        _projectUndetectedMarkers(_board, _detectedCorners, _detectedIds, _cameraMatrix, _distCoeffs,
                                   undetectedMarkersCorners, undetectedMarkersIds);
 
     } else {
         // reproject based on global homography
-        _projectUndetectedMarkers(board, _detectedCorners, _detectedIds, undetectedMarkersCorners,
+        _projectUndetectedMarkers(_board, _detectedCorners, _detectedIds, undetectedMarkersCorners,
                                   undetectedMarkersIds);
     }
 
@@ -1083,8 +1072,9 @@ void refineDetectedMarkers(InputArray _image, const Board &board,
     vector< bool > alreadyIdentified(_rejectedCorners.total(), false);
 
     // maximum bits that can be corrected
+    Dictionary &dictionary = *(_board->dictionary);
     int maxCorrectionRecalculated =
-        int(double(board.dictionary.maxCorrectionBits) * errorCorrectionRate);
+        int(double(dictionary.maxCorrectionBits) * errorCorrectionRate);
 
     Mat grey;
     _convertToGrey(_image, grey);
@@ -1152,7 +1142,7 @@ void refineDetectedMarkers(InputArray _image, const Board &board,
 
                 // extract bits
                 Mat bits = _extractBits(
-                    grey, rotatedMarker, board.dictionary.markerSize, params.markerBorderBits,
+                    grey, rotatedMarker, dictionary.markerSize, params.markerBorderBits,
                     params.perspectiveRemovePixelPerCell,
                     params.perspectiveRemoveIgnoredMarginPerCell, params.minOtsuStdDev);
 
@@ -1161,7 +1151,7 @@ void refineDetectedMarkers(InputArray _image, const Board &board,
                         .colRange(params.markerBorderBits, bits.rows - params.markerBorderBits);
 
                 codeDistance =
-                    board.dictionary.getDistanceToId(onlyBits, undetectedMarkersIds[i], false);
+                    dictionary.getDistanceToId(onlyBits, undetectedMarkersIds[i], false);
             }
 
             // if everythin is ok, assign values to current best match
@@ -1205,9 +1195,7 @@ void refineDetectedMarkers(InputArray _image, const Board &board,
         _detectedIds.clear();
 
         // parse output
-        _detectedIds.create((int)finalAcceptedIds.size(), 1, CV_32SC1);
-        for(unsigned int i = 0; i < finalAcceptedIds.size(); i++)
-            _detectedIds.getMat().ptr< int >(0)[i] = finalAcceptedIds[i];
+        Mat(finalAcceptedIds).copyTo(_detectedIds);
 
         _detectedCorners.create((int)finalAcceptedCorners.size(), 1, CV_32FC2);
         for(unsigned int i = 0; i < finalAcceptedCorners.size(); i++) {
@@ -1237,10 +1225,7 @@ void refineDetectedMarkers(InputArray _image, const Board &board,
         }
 
         if(_recoveredIdxs.needed()) {
-            _recoveredIdxs.create((int)recoveredIdxs.size(), 1, CV_32SC1);
-            for(unsigned int i = 0; i < recoveredIdxs.size(); i++) {
-                _recoveredIdxs.getMat().ptr< int >()[i] = recoveredIdxs[i];
-            }
+            Mat(recoveredIdxs).copyTo(_recoveredIdxs);
         }
     }
 }
@@ -1250,7 +1235,7 @@ void refineDetectedMarkers(InputArray _image, const Board &board,
 
 /**
   */
-int estimatePoseBoard(InputArrayOfArrays _corners, InputArray _ids, const Board &board,
+int estimatePoseBoard(InputArrayOfArrays _corners, InputArray _ids, const Ptr<Board> &board,
                       InputArray _cameraMatrix, InputArray _distCoeffs, OutputArray _rvec,
                       OutputArray _tvec) {
 
@@ -1265,9 +1250,14 @@ int estimatePoseBoard(InputArrayOfArrays _corners, InputArray _ids, const Board
     if(objPoints.total() == 0) // 0 of the detected markers in board
         return 0;
 
-    _rvec.create(3, 1, CV_64FC1);
-    _tvec.create(3, 1, CV_64FC1);
-    solvePnP(objPoints, imgPoints, _cameraMatrix, _distCoeffs, _rvec, _tvec);
+    bool useExtrinsicGuess = true;
+    if (_rvec.empty() || _tvec.empty())
+    {
+        _rvec.create(3, 1, CV_64FC1);
+        _tvec.create(3, 1, CV_64FC1);
+        useExtrinsicGuess = false;
+    }
+    solvePnP(objPoints, imgPoints, _cameraMatrix, _distCoeffs, _rvec, _tvec, useExtrinsicGuess);
 
     // divide by four since all the four corners are concatenated in the array for each marker
     return (int)objPoints.total() / 4;
@@ -1279,33 +1269,57 @@ int estimatePoseBoard(InputArrayOfArrays _corners, InputArray _ids, const Board
 /**
  */
 void GridBoard::draw(Size outSize, OutputArray _img, int marginSize, int borderBits) {
-    aruco::drawPlanarBoard((*this), outSize, _img, marginSize, borderBits);
+    _drawPlanarBoardImpl(this, outSize, _img, marginSize, borderBits);
 }
 
 
+/**
+*/
+Ptr<Board> Board::create(InputArrayOfArrays objPoints, const Ptr<Dictionary> &dictionary, InputArray ids) {
+
+    CV_Assert(objPoints.total() == ids.total());
+    CV_Assert(objPoints.type() == CV_32FC3);
+
+    std::vector< std::vector< Point3f > > obj_points_vector;
+    for (unsigned int i = 0; i < objPoints.total(); i++) {
+        std::vector<Point3f> corners;
+        Mat corners_mat = objPoints.getMat(i);
+        for (int j = 0; j < 4; j++) {
+            corners.push_back(corners_mat.at<Point3f>(j));
+        }
+        obj_points_vector.push_back(corners);
+    }
+
+    Ptr<Board> res = makePtr<Board>();
+    ids.copyTo(res->ids);
+    res->objPoints = obj_points_vector;
+    res->dictionary = cv::makePtr<Dictionary>(dictionary);
+    return res;
+}
 
 /**
  */
-GridBoard GridBoard::create(int markersX, int markersY, float markerLength, float markerSeparation,
-                            Dictionary _dictionary) {
-
-    GridBoard res;
+Ptr<GridBoard> GridBoard::create(int markersX, int markersY, float markerLength, float markerSeparation,
+                            const Ptr<Dictionary> &dictionary, int firstMarker) {
 
     CV_Assert(markersX > 0 && markersY > 0 && markerLength > 0 && markerSeparation > 0);
 
-    res._markersX = markersX;
-    res._markersY = markersY;
-    res._markerLength = markerLength;
-    res._markerSeparation = markerSeparation;
-    res.dictionary = _dictionary;
+    Ptr<GridBoard> res = makePtr<GridBoard>();
+
+    res->_markersX = markersX;
+    res->_markersY = markersY;
+    res->_markerLength = markerLength;
+    res->_markerSeparation = markerSeparation;
+    res->dictionary = dictionary;
 
-    int totalMarkers = markersX * markersY;
-    res.ids.resize(totalMarkers);
-    res.objPoints.reserve(totalMarkers);
+    size_t totalMarkers = (size_t) markersX * markersY;
+    res->ids.resize(totalMarkers);
+    res->objPoints.reserve(totalMarkers);
 
     // fill ids with first identifiers
-    for(int i = 0; i < totalMarkers; i++)
-        res.ids[i] = i;
+    for(unsigned int i = 0; i < totalMarkers; i++) {
+        res->ids[i] = i + firstMarker;
+    }
 
     // calculate Board objPoints
     float maxY = (float)markersY * markerLength + (markersY - 1) * markerSeparation;
@@ -1318,7 +1332,7 @@ GridBoard GridBoard::create(int markersX, int markersY, float markerLength, floa
             corners[1] = corners[0] + Point3f(markerLength, 0, 0);
             corners[2] = corners[0] + Point3f(markerLength, -markerLength, 0);
             corners[3] = corners[0] + Point3f(0, -markerLength, 0);
-            res.objPoints.push_back(corners);
+            res->objPoints.push_back(corners);
         }
     }
 
@@ -1402,15 +1416,13 @@ void drawAxis(InputOutputArray _image, InputArray _cameraMatrix, InputArray _dis
 
 /**
  */
-void drawMarker(Dictionary dictionary, int id, int sidePixels, OutputArray _img, int borderBits) {
-    dictionary.drawMarker(id, sidePixels, _img, borderBits);
+void drawMarker(const Ptr<Dictionary> &dictionary, int id, int sidePixels, OutputArray _img, int borderBits) {
+    dictionary->drawMarker(id, sidePixels, _img, borderBits);
 }
 
 
 
-/**
- */
-void drawPlanarBoard(const Board &board, Size outSize, OutputArray _img, int marginSize,
+void _drawPlanarBoardImpl(Board *_board, Size outSize, OutputArray _img, int marginSize,
                      int borderBits) {
 
     CV_Assert(outSize.area() > 0);
@@ -1419,110 +1431,115 @@ void drawPlanarBoard(const Board &board, Size outSize, OutputArray _img, int mar
     _img.create(outSize, CV_8UC1);
     Mat out = _img.getMat();
     out.setTo(Scalar::all(255));
-    Mat outNoMargins =
-        out.colRange(marginSize, out.cols - marginSize).rowRange(marginSize, out.rows - marginSize);
+    out.adjustROI(-marginSize, -marginSize, -marginSize, -marginSize);
 
     // calculate max and min values in XY plane
-    CV_Assert(board.objPoints.size() > 0);
+    CV_Assert(_board->objPoints.size() > 0);
     float minX, maxX, minY, maxY;
-    minX = maxX = board.objPoints[0][0].x;
-    minY = maxY = board.objPoints[0][0].y;
+    minX = maxX = _board->objPoints[0][0].x;
+    minY = maxY = _board->objPoints[0][0].y;
 
-    for(unsigned int i = 0; i < board.objPoints.size(); i++) {
+    for(unsigned int i = 0; i < _board->objPoints.size(); i++) {
         for(int j = 0; j < 4; j++) {
-            minX = min(minX, board.objPoints[i][j].x);
-            maxX = max(maxX, board.objPoints[i][j].x);
-            minY = min(minY, board.objPoints[i][j].y);
-            maxY = max(maxY, board.objPoints[i][j].y);
+            minX = min(minX, _board->objPoints[i][j].x);
+            maxX = max(maxX, _board->objPoints[i][j].x);
+            minY = min(minY, _board->objPoints[i][j].y);
+            maxY = max(maxY, _board->objPoints[i][j].y);
         }
     }
 
-    float sizeX, sizeY;
-    sizeX = maxX - minX;
-    sizeY = maxY - minY;
+    float sizeX = maxX - minX;
+    float sizeY = maxY - minY;
 
     // proportion transformations
-    float xReduction = sizeX / float(outNoMargins.cols);
-    float yReduction = sizeY / float(outNoMargins.rows);
+    float xReduction = sizeX / float(out.cols);
+    float yReduction = sizeY / float(out.rows);
 
     // determine the zone where the markers are placed
-    Mat markerZone;
     if(xReduction > yReduction) {
         int nRows = int(sizeY / xReduction);
-        int rowsMargins = (outNoMargins.rows - nRows) / 2;
-        markerZone = outNoMargins.rowRange(rowsMargins, outNoMargins.rows - rowsMargins);
+        int rowsMargins = (out.rows - nRows) / 2;
+        out.adjustROI(-rowsMargins, -rowsMargins, 0, 0);
     } else {
         int nCols = int(sizeX / yReduction);
-        int colsMargins = (outNoMargins.cols - nCols) / 2;
-        markerZone = outNoMargins.colRange(colsMargins, outNoMargins.cols - colsMargins);
+        int colsMargins = (out.cols - nCols) / 2;
+        out.adjustROI(0, 0, -colsMargins, -colsMargins);
     }
 
     // now paint each marker
-    for(unsigned int m = 0; m < board.objPoints.size(); m++) {
-
+    Dictionary &dictionary = *(_board->dictionary);
+    Mat marker;
+    Point2f outCorners[3];
+    Point2f inCorners[3];
+    for(unsigned int m = 0; m < _board->objPoints.size(); m++) {
         // transform corners to markerZone coordinates
-        vector< Point2f > outCorners;
-        outCorners.resize(4);
-        for(int j = 0; j < 4; j++) {
-            Point2f p0, p1, pf;
-            p0 = Point2f(board.objPoints[m][j].x, board.objPoints[m][j].y);
-            // remove negativity
-            p1.x = p0.x - minX;
-            p1.y = p0.y - minY;
-            pf.x = p1.x * float(markerZone.cols - 1) / sizeX;
-            pf.y = float(markerZone.rows - 1) - p1.y * float(markerZone.rows - 1) / sizeY;
+        for(int j = 0; j < 3; j++) {
+            Point2f pf = Point2f(_board->objPoints[m][j].x, _board->objPoints[m][j].y);
+            // move top left to 0, 0
+            pf -= Point2f(minX, minY);
+            pf.x = pf.x / sizeX * float(out.cols);
+            pf.y = (1.0f - pf.y / sizeY) * float(out.rows);
             outCorners[j] = pf;
         }
 
-        // get tiny marker
-        int tinyMarkerSize = 10 * board.dictionary.markerSize + 2;
-        Mat tinyMarker;
-        board.dictionary.drawMarker(board.ids[m], tinyMarkerSize, tinyMarker, borderBits);
+        // get marker
+        Size dst_sz(outCorners[2] - outCorners[0]); // assuming CCW order
+        dictionary.drawMarker(_board->ids[m], dst_sz.width, marker, borderBits);
+
+        if((outCorners[0].y == outCorners[1].y) && (outCorners[1].x == outCorners[2].x)) {
+            // marker is aligned to image axes
+            marker.copyTo(out(Rect(outCorners[0], dst_sz)));
+            continue;
+        }
 
         // interpolate tiny marker to marker position in markerZone
-        Mat inCorners(4, 1, CV_32FC2);
-        inCorners.ptr< Point2f >(0)[0] = Point2f(0, 0);
-        inCorners.ptr< Point2f >(0)[1] = Point2f((float)tinyMarker.cols, 0);
-        inCorners.ptr< Point2f >(0)[2] = Point2f((float)tinyMarker.cols, (float)tinyMarker.rows);
-        inCorners.ptr< Point2f >(0)[3] = Point2f(0, (float)tinyMarker.rows);
+        inCorners[0] = Point2f(-0.5f, -0.5f);
+        inCorners[1] = Point2f(marker.cols - 0.5f, -0.5f);
+        inCorners[2] = Point2f(marker.cols - 0.5f, marker.rows - 0.5f);
 
         // remove perspective
-        Mat transformation = getPerspectiveTransform(inCorners, outCorners);
-        Mat aux;
-        const char borderValue = 127;
-        warpPerspective(tinyMarker, aux, transformation, markerZone.size(), INTER_NEAREST,
-                        BORDER_CONSTANT, Scalar::all(borderValue));
-
-        // copy only not-border pixels
-        for(int y = 0; y < aux.rows; y++) {
-            for(int x = 0; x < aux.cols; x++) {
-                if(aux.at< unsigned char >(y, x) == borderValue) continue;
-                markerZone.at< unsigned char >(y, x) = aux.at< unsigned char >(y, x);
-            }
-        }
+        Mat transformation = getAffineTransform(inCorners, outCorners);
+        warpAffine(marker, out, transformation, out.size(), INTER_LINEAR,
+                        BORDER_TRANSPARENT);
     }
 }
 
 
 
 /**
-  */
+ */
+void drawPlanarBoard(const Ptr<Board> &_board, Size outSize, OutputArray _img, int marginSize,
+                     int borderBits) {
+    _drawPlanarBoardImpl(_board, outSize, _img, marginSize, borderBits);
+}
+
+
+
+/**
+ */
 double calibrateCameraAruco(InputArrayOfArrays _corners, InputArray _ids, InputArray _counter,
-                            const Board &board, Size imageSize, InputOutputArray _cameraMatrix,
+                            const Ptr<Board> &board, Size imageSize, InputOutputArray _cameraMatrix,
                             InputOutputArray _distCoeffs, OutputArrayOfArrays _rvecs,
-                            OutputArrayOfArrays _tvecs, int flags, TermCriteria criteria) {
+                            OutputArrayOfArrays _tvecs,
+                            OutputArray _stdDeviationsIntrinsics,
+                            OutputArray _stdDeviationsExtrinsics,
+                            OutputArray _perViewErrors,
+                            int flags, TermCriteria criteria) {
 
     // for each frame, get properly processed imagePoints and objectPoints for the calibrateCamera
     // function
     vector< Mat > processedObjectPoints, processedImagePoints;
-    int nFrames = (int)_counter.total();
+    size_t nFrames = _counter.total();
     int markerCounter = 0;
-    for(int frame = 0; frame < nFrames; frame++) {
-        int nMarkersInThisFrame = _counter.getMat().ptr< int >()[frame];
+    for(size_t frame = 0; frame < nFrames; frame++) {
+        int nMarkersInThisFrame =  _counter.getMat().ptr< int >()[frame];
         vector< Mat > thisFrameCorners;
         vector< int > thisFrameIds;
-        thisFrameCorners.reserve(nMarkersInThisFrame);
-        thisFrameIds.reserve(nMarkersInThisFrame);
+
+        CV_Assert(nMarkersInThisFrame > 0);
+
+        thisFrameCorners.reserve((size_t) nMarkersInThisFrame);
+        thisFrameIds.reserve((size_t) nMarkersInThisFrame);
         for(int j = markerCounter; j < markerCounter + nMarkersInThisFrame; j++) {
             thisFrameCorners.push_back(_corners.getMat(j));
             thisFrameIds.push_back(_ids.getMat().ptr< int >()[j]);
@@ -1538,7 +1555,23 @@ double calibrateCameraAruco(InputArrayOfArrays _corners, InputArray _ids, InputA
     }
 
     return calibrateCamera(processedObjectPoints, processedImagePoints, imageSize, _cameraMatrix,
-                           _distCoeffs, _rvecs, _tvecs, flags, criteria);
+                           _distCoeffs, _rvecs, _tvecs, _stdDeviationsIntrinsics, _stdDeviationsExtrinsics,
+                           _perViewErrors, flags, criteria);
 }
+
+
+
+/**
+ */
+double calibrateCameraAruco(InputArrayOfArrays _corners, InputArray _ids, InputArray _counter,
+  const Ptr<Board> &board, Size imageSize, InputOutputArray _cameraMatrix,
+  InputOutputArray _distCoeffs, OutputArrayOfArrays _rvecs,
+  OutputArrayOfArrays _tvecs, int flags, TermCriteria criteria) {
+    return calibrateCameraAruco(_corners, _ids, _counter, board, imageSize, _cameraMatrix, _distCoeffs, _rvecs, _tvecs,
+      noArray(), noArray(), noArray(), flags, criteria);
+}
+
+
+
 }
 }
diff --git a/contrib/modules/aruco/src/charuco.cpp b/contrib/modules/aruco/src/charuco.cpp
index a8f77a7..9b9dea1 100644
--- a/contrib/modules/aruco/src/charuco.cpp
+++ b/contrib/modules/aruco/src/charuco.cpp
@@ -93,8 +93,8 @@ void CharucoBoard::draw(Size outSize, OutputArray _img, int marginSize, int bord
 
     // draw markers
     Mat markersImg;
-    aruco::drawPlanarBoard((*this), chessboardZoneImg.size(), markersImg,
-                           diffSquareMarkerLengthPixels, borderBits);
+    aruco::_drawPlanarBoardImpl(this, chessboardZoneImg.size(), markersImg,
+                                diffSquareMarkerLengthPixels, borderBits);
 
     markersImg.copyTo(chessboardZoneImg);
 
@@ -120,17 +120,17 @@ void CharucoBoard::draw(Size outSize, OutputArray _img, int marginSize, int bord
 
 /**
  */
-CharucoBoard CharucoBoard::create(int squaresX, int squaresY, float squareLength,
-                                  float markerLength, Dictionary dictionary) {
+Ptr<CharucoBoard> CharucoBoard::create(int squaresX, int squaresY, float squareLength,
+                                  float markerLength, const Ptr<Dictionary> &dictionary) {
 
     CV_Assert(squaresX > 1 && squaresY > 1 && markerLength > 0 && squareLength > markerLength);
-    CharucoBoard res;
+    Ptr<CharucoBoard> res = makePtr<CharucoBoard>();
 
-    res._squaresX = squaresX;
-    res._squaresY = squaresY;
-    res._squareLength = squareLength;
-    res._markerLength = markerLength;
-    res.dictionary = dictionary;
+    res->_squaresX = squaresX;
+    res->_squaresY = squaresY;
+    res->_squareLength = squareLength;
+    res->_markerLength = markerLength;
+    res->dictionary = dictionary;
 
     float diffSquareMarkerLength = (squareLength - markerLength) / 2;
 
@@ -147,10 +147,10 @@ CharucoBoard CharucoBoard::create(int squaresX, int squaresY, float squareLength
             corners[1] = corners[0] + Point3f(markerLength, 0, 0);
             corners[2] = corners[0] + Point3f(markerLength, -markerLength, 0);
             corners[3] = corners[0] + Point3f(0, -markerLength, 0);
-            res.objPoints.push_back(corners);
+            res->objPoints.push_back(corners);
             // first ids in dictionary
-            int nextId = (int)res.ids.size();
-            res.ids.push_back(nextId);
+            int nextId = (int)res->ids.size();
+            res->ids.push_back(nextId);
         }
     }
 
@@ -161,11 +161,11 @@ CharucoBoard CharucoBoard::create(int squaresX, int squaresY, float squareLength
             corner.x = (x + 1) * squareLength;
             corner.y = (y + 1) * squareLength;
             corner.z = 0;
-            res.chessboardCorners.push_back(corner);
+            res->chessboardCorners.push_back(corner);
         }
     }
 
-    res._getNearestMarkerCorners();
+    res->_getNearestMarkerCorners();
 
     return res;
 }
@@ -230,7 +230,7 @@ void CharucoBoard::_getNearestMarkerCorners() {
 /**
   * Remove charuco corners if any of their minMarkers closest markers has not been detected
   */
-static unsigned int _filterCornersWithoutMinMarkers(const CharucoBoard &board,
+static int _filterCornersWithoutMinMarkers(const Ptr<CharucoBoard> &_board,
                                                     InputArray _allCharucoCorners,
                                                     InputArray _allCharucoIds,
                                                     InputArray _allArucoIds, int minMarkers,
@@ -243,14 +243,14 @@ static unsigned int _filterCornersWithoutMinMarkers(const CharucoBoard &board,
     vector< int > filteredCharucoIds;
     // for each charuco corner
     for(unsigned int i = 0; i < _allCharucoIds.getMat().total(); i++) {
-        int currentCharucoId = _allCharucoIds.getMat().ptr< int >(0)[i];
+        int currentCharucoId = _allCharucoIds.getMat().at< int >(i);
         int totalMarkers = 0; // nomber of closest marker detected
         // look for closest markers
-        for(unsigned int m = 0; m < board.nearestMarkerIdx[currentCharucoId].size(); m++) {
-            int markerId = board.ids[board.nearestMarkerIdx[currentCharucoId][m]];
+        for(unsigned int m = 0; m < _board->nearestMarkerIdx[currentCharucoId].size(); m++) {
+            int markerId = _board->ids[_board->nearestMarkerIdx[currentCharucoId][m]];
             bool found = false;
             for(unsigned int k = 0; k < _allArucoIds.getMat().total(); k++) {
-                if(_allArucoIds.getMat().ptr< int >(0)[k] == markerId) {
+                if(_allArucoIds.getMat().at< int >(k) == markerId) {
                     found = true;
                     break;
                 }
@@ -260,22 +260,14 @@ static unsigned int _filterCornersWithoutMinMarkers(const CharucoBoard &board,
         // if enough markers detected, add the charuco corner to the final list
         if(totalMarkers >= minMarkers) {
             filteredCharucoIds.push_back(currentCharucoId);
-            filteredCharucoCorners.push_back(_allCharucoCorners.getMat().ptr< Point2f >(0)[i]);
+            filteredCharucoCorners.push_back(_allCharucoCorners.getMat().at< Point2f >(i));
         }
     }
 
     // parse output
-    _filteredCharucoCorners.create((int)filteredCharucoCorners.size(), 1, CV_32FC2);
-    for(unsigned int i = 0; i < filteredCharucoCorners.size(); i++) {
-        _filteredCharucoCorners.getMat().ptr< Point2f >(0)[i] = filteredCharucoCorners[i];
-    }
-
-    _filteredCharucoIds.create((int)filteredCharucoIds.size(), 1, CV_32SC1);
-    for(unsigned int i = 0; i < filteredCharucoIds.size(); i++) {
-        _filteredCharucoIds.getMat().ptr< int >(0)[i] = filteredCharucoIds[i];
-    }
-
-    return (unsigned int)filteredCharucoCorners.size();
+    Mat(filteredCharucoCorners).copyTo(_filteredCharucoCorners);
+    Mat(filteredCharucoIds).copyTo(_filteredCharucoIds);
+    return (int)_filteredCharucoIds.total();
 }
 
 
@@ -286,7 +278,7 @@ static unsigned int _filterCornersWithoutMinMarkers(const CharucoBoard &board,
 class CharucoSubpixelParallel : public ParallelLoopBody {
     public:
     CharucoSubpixelParallel(const Mat *_grey, vector< Point2f > *_filteredChessboardImgPoints,
-                            vector< Size > *_filteredWinSizes, DetectorParameters *_params)
+                            vector< Size > *_filteredWinSizes, const Ptr<DetectorParameters> &_params)
         : grey(_grey), filteredChessboardImgPoints(_filteredChessboardImgPoints),
           filteredWinSizes(_filteredWinSizes), params(_params) {}
 
@@ -316,7 +308,7 @@ class CharucoSubpixelParallel : public ParallelLoopBody {
     const Mat *grey;
     vector< Point2f > *filteredChessboardImgPoints;
     vector< Size > *filteredWinSizes;
-    DetectorParameters *params;
+    const Ptr<DetectorParameters> ¶ms;
 };
 
 
@@ -326,7 +318,7 @@ class CharucoSubpixelParallel : public ParallelLoopBody {
   * @brief From all projected chessboard corners, select those inside the image and apply subpixel
   * refinement. Returns number of valid corners.
   */
-static unsigned int _selectAndRefineChessboardCorners(InputArray _allCorners, InputArray _image,
+static int _selectAndRefineChessboardCorners(InputArray _allCorners, InputArray _image,
                                                       OutputArray _selectedCorners,
                                                       OutputArray _selectedIds,
                                                       const vector< Size > &winSizes) {
@@ -341,8 +333,8 @@ static unsigned int _selectAndRefineChessboardCorners(InputArray _allCorners, In
     Rect innerRect(minDistToBorder, minDistToBorder, _image.getMat().cols - 2 * minDistToBorder,
                    _image.getMat().rows - 2 * minDistToBorder);
     for(unsigned int i = 0; i < _allCorners.getMat().total(); i++) {
-        if(innerRect.contains(_allCorners.getMat().ptr< Point2f >(0)[i])) {
-            filteredChessboardImgPoints.push_back(_allCorners.getMat().ptr< Point2f >(0)[i]);
+        if(innerRect.contains(_allCorners.getMat().at< Point2f >(i))) {
+            filteredChessboardImgPoints.push_back(_allCorners.getMat().at< Point2f >(i));
             filteredIds.push_back(i);
             filteredWinSizes.push_back(winSizes[i]);
         }
@@ -358,7 +350,7 @@ static unsigned int _selectAndRefineChessboardCorners(InputArray _allCorners, In
     else
         _image.getMat().copyTo(grey);
 
-    DetectorParameters params; // use default params for corner refinement
+    const Ptr<DetectorParameters> params = DetectorParameters::create(); // use default params for corner refinement
 
     //// For each of the charuco corners, apply subpixel refinement using its correspondind winSize
     // for(unsigned int i=0; i<filteredChessboardImgPoints.size(); i++) {
@@ -377,20 +369,12 @@ static unsigned int _selectAndRefineChessboardCorners(InputArray _allCorners, In
     // this is the parallel call for the previous commented loop (result is equivalent)
     parallel_for_(
         Range(0, (int)filteredChessboardImgPoints.size()),
-        CharucoSubpixelParallel(&grey, &filteredChessboardImgPoints, &filteredWinSizes, &params));
+        CharucoSubpixelParallel(&grey, &filteredChessboardImgPoints, &filteredWinSizes, params));
 
     // parse output
-    _selectedCorners.create((int)filteredChessboardImgPoints.size(), 1, CV_32FC2);
-    for(unsigned int i = 0; i < filteredChessboardImgPoints.size(); i++) {
-        _selectedCorners.getMat().ptr< Point2f >(0)[i] = filteredChessboardImgPoints[i];
-    }
-
-    _selectedIds.create((int)filteredIds.size(), 1, CV_32SC1);
-    for(unsigned int i = 0; i < filteredIds.size(); i++) {
-        _selectedIds.getMat().ptr< int >(0)[i] = filteredIds[i];
-    }
-
-    return (unsigned int)filteredChessboardImgPoints.size();
+    Mat(filteredChessboardImgPoints).copyTo(_selectedCorners);
+    Mat(filteredIds).copyTo(_selectedIds);
+    return (int)filteredChessboardImgPoints.size();
 }
 
 
@@ -399,34 +383,34 @@ static unsigned int _selectAndRefineChessboardCorners(InputArray _allCorners, In
   * distance to their closest markers
   */
 static void _getMaximumSubPixWindowSizes(InputArrayOfArrays markerCorners, InputArray markerIds,
-                                         InputArray charucoCorners, const CharucoBoard &board,
+                                         InputArray charucoCorners, const Ptr<CharucoBoard> &board,
                                          vector< Size > &sizes) {
 
     unsigned int nCharucoCorners = (unsigned int)charucoCorners.getMat().total();
     sizes.resize(nCharucoCorners, Size(-1, -1));
 
     for(unsigned int i = 0; i < nCharucoCorners; i++) {
-        if(charucoCorners.getMat().ptr< Point2f >(0)[i] == Point2f(-1, -1)) continue;
-        if(board.nearestMarkerIdx[i].size() == 0) continue;
+        if(charucoCorners.getMat().at< Point2f >(i) == Point2f(-1, -1)) continue;
+        if(board->nearestMarkerIdx[i].size() == 0) continue;
 
         double minDist = -1;
         int counter = 0;
 
         // calculate the distance to each of the closest corner of each closest marker
-        for(unsigned int j = 0; j < board.nearestMarkerIdx[i].size(); j++) {
+        for(unsigned int j = 0; j < board->nearestMarkerIdx[i].size(); j++) {
             // find marker
-            int markerId = board.ids[board.nearestMarkerIdx[i][j]];
+            int markerId = board->ids[board->nearestMarkerIdx[i][j]];
             int markerIdx = -1;
             for(unsigned int k = 0; k < markerIds.getMat().total(); k++) {
-                if(markerIds.getMat().ptr< int >(0)[k] == markerId) {
+                if(markerIds.getMat().at< int >(k) == markerId) {
                     markerIdx = k;
                     break;
                 }
             }
             if(markerIdx == -1) continue;
             Point2f markerCorner =
-                markerCorners.getMat(markerIdx).ptr< Point2f >(0)[board.nearestMarkerCorners[i][j]];
-            Point2f charucoCorner = charucoCorners.getMat().ptr< Point2f >(0)[i];
+                markerCorners.getMat(markerIdx).at< Point2f >(board->nearestMarkerCorners[i][j]);
+            Point2f charucoCorner = charucoCorners.getMat().at< Point2f >(i);
             double dist = norm(markerCorner - charucoCorner);
             if(minDist == -1) minDist = dist; // if first distance, just assign it
             minDist = min(dist, minDist);
@@ -453,7 +437,7 @@ static void _getMaximumSubPixWindowSizes(InputArrayOfArrays markerCorners, Input
   */
 static int _interpolateCornersCharucoApproxCalib(InputArrayOfArrays _markerCorners,
                                                  InputArray _markerIds, InputArray _image,
-                                                 const CharucoBoard &board,
+                                                 const Ptr<CharucoBoard> &_board,
                                                  InputArray _cameraMatrix, InputArray _distCoeffs,
                                                  OutputArray _charucoCorners,
                                                  OutputArray _charucoIds) {
@@ -465,34 +449,29 @@ static int _interpolateCornersCharucoApproxCalib(InputArrayOfArrays _markerCorne
     // approximated pose estimation using marker corners
     Mat approximatedRvec, approximatedTvec;
     int detectedBoardMarkers;
+    Ptr<Board> _b = _board.staticCast<Board>();
     detectedBoardMarkers =
-        aruco::estimatePoseBoard(_markerCorners, _markerIds, board, _cameraMatrix, _distCoeffs,
-                                 approximatedRvec, approximatedTvec);
+        aruco::estimatePoseBoard(_markerCorners, _markerIds, _b,
+                                 _cameraMatrix, _distCoeffs, approximatedRvec, approximatedTvec);
 
     if(detectedBoardMarkers == 0) return 0;
 
     // project chessboard corners
     vector< Point2f > allChessboardImgPoints;
-    projectPoints(board.chessboardCorners, approximatedRvec, approximatedTvec, _cameraMatrix,
+
+    projectPoints(_board->chessboardCorners, approximatedRvec, approximatedTvec, _cameraMatrix,
                   _distCoeffs, allChessboardImgPoints);
 
 
     // calculate maximum window sizes for subpixel refinement. The size is limited by the distance
     // to the closes marker corner to avoid erroneous displacements to marker corners
     vector< Size > subPixWinSizes;
-    _getMaximumSubPixWindowSizes(_markerCorners, _markerIds, allChessboardImgPoints, board,
+    _getMaximumSubPixWindowSizes(_markerCorners, _markerIds, allChessboardImgPoints, _board,
                                  subPixWinSizes);
 
     // filter corners outside the image and subpixel-refine charuco corners
-    unsigned int nRefinedCorners;
-    nRefinedCorners = _selectAndRefineChessboardCorners(
-        allChessboardImgPoints, _image, _charucoCorners, _charucoIds, subPixWinSizes);
-
-    // to return a charuco corner, its two closes aruco markers should have been detected
-    nRefinedCorners = _filterCornersWithoutMinMarkers(board, _charucoCorners, _charucoIds,
-                                                      _markerIds, 2, _charucoCorners, _charucoIds);
-
-    return nRefinedCorners;
+    return _selectAndRefineChessboardCorners(allChessboardImgPoints, _image, _charucoCorners,
+                                             _charucoIds, subPixWinSizes);
 }
 
 
@@ -502,7 +481,7 @@ static int _interpolateCornersCharucoApproxCalib(InputArrayOfArrays _markerCorne
   */
 static int _interpolateCornersCharucoLocalHom(InputArrayOfArrays _markerCorners,
                                               InputArray _markerIds, InputArray _image,
-                                              const CharucoBoard &board,
+                                              const Ptr<CharucoBoard> &_board,
                                               OutputArray _charucoCorners,
                                               OutputArray _charucoIds) {
 
@@ -517,32 +496,32 @@ static int _interpolateCornersCharucoLocalHom(InputArrayOfArrays _markerCorners,
     transformations.resize(nMarkers);
     for(unsigned int i = 0; i < nMarkers; i++) {
         vector< Point2f > markerObjPoints2D;
-        int markerId = _markerIds.getMat().ptr< int >(0)[i];
-        vector< int >::const_iterator it = find(board.ids.begin(), board.ids.end(), markerId);
-        if(it == board.ids.end()) continue;
-        int boardIdx = (int)std::distance(board.ids.begin(), it);
+        int markerId = _markerIds.getMat().at< int >(i);
+        vector< int >::const_iterator it = find(_board->ids.begin(), _board->ids.end(), markerId);
+        if(it == _board->ids.end()) continue;
+        int boardIdx = (int)std::distance<std::vector<int>::const_iterator>(_board->ids.begin(), it);
         markerObjPoints2D.resize(4);
         for(unsigned int j = 0; j < 4; j++)
             markerObjPoints2D[j] =
-                Point2f(board.objPoints[boardIdx][j].x, board.objPoints[boardIdx][j].y);
+                Point2f(_board->objPoints[boardIdx][j].x, _board->objPoints[boardIdx][j].y);
 
         transformations[i] = getPerspectiveTransform(markerObjPoints2D, _markerCorners.getMat(i));
     }
 
-    unsigned int nCharucoCorners = (unsigned int)board.chessboardCorners.size();
+    unsigned int nCharucoCorners = (unsigned int)_board->chessboardCorners.size();
     vector< Point2f > allChessboardImgPoints(nCharucoCorners, Point2f(-1, -1));
 
     // for each charuco corner, calculate its interpolation position based on the closest markers
     // homographies
     for(unsigned int i = 0; i < nCharucoCorners; i++) {
-        Point2f objPoint2D = Point2f(board.chessboardCorners[i].x, board.chessboardCorners[i].y);
+        Point2f objPoint2D = Point2f(_board->chessboardCorners[i].x, _board->chessboardCorners[i].y);
 
         vector< Point2f > interpolatedPositions;
-        for(unsigned int j = 0; j < board.nearestMarkerIdx[i].size(); j++) {
-            int markerId = board.ids[board.nearestMarkerIdx[i][j]];
+        for(unsigned int j = 0; j < _board->nearestMarkerIdx[i].size(); j++) {
+            int markerId = _board->ids[_board->nearestMarkerIdx[i][j]];
             int markerIdx = -1;
             for(unsigned int k = 0; k < _markerIds.getMat().total(); k++) {
-                if(_markerIds.getMat().ptr< int >(0)[k] == markerId) {
+                if(_markerIds.getMat().at< int >(k) == markerId) {
                     markerIdx = k;
                     break;
                 }
@@ -569,20 +548,13 @@ static int _interpolateCornersCharucoLocalHom(InputArrayOfArrays _markerCorners,
     // calculate maximum window sizes for subpixel refinement. The size is limited by the distance
     // to the closes marker corner to avoid erroneous displacements to marker corners
     vector< Size > subPixWinSizes;
-    _getMaximumSubPixWindowSizes(_markerCorners, _markerIds, allChessboardImgPoints, board,
+    _getMaximumSubPixWindowSizes(_markerCorners, _markerIds, allChessboardImgPoints, _board,
                                  subPixWinSizes);
 
 
     // filter corners outside the image and subpixel-refine charuco corners
-    unsigned int nRefinedCorners;
-    nRefinedCorners = _selectAndRefineChessboardCorners(
-        allChessboardImgPoints, _image, _charucoCorners, _charucoIds, subPixWinSizes);
-
-    // to return a charuco corner, its two closes aruco markers should have been detected
-    nRefinedCorners = _filterCornersWithoutMinMarkers(board, _charucoCorners, _charucoIds,
-                                                      _markerIds, 2, _charucoCorners, _charucoIds);
-
-    return nRefinedCorners;
+    return _selectAndRefineChessboardCorners(allChessboardImgPoints, _image, _charucoCorners,
+                                             _charucoIds, subPixWinSizes);
 }
 
 
@@ -590,21 +562,25 @@ static int _interpolateCornersCharucoLocalHom(InputArrayOfArrays _markerCorners,
 /**
   */
 int interpolateCornersCharuco(InputArrayOfArrays _markerCorners, InputArray _markerIds,
-                              InputArray _image, const CharucoBoard &board,
+                              InputArray _image, const Ptr<CharucoBoard> &_board,
                               OutputArray _charucoCorners, OutputArray _charucoIds,
-                              InputArray _cameraMatrix, InputArray _distCoeffs) {
+                              InputArray _cameraMatrix, InputArray _distCoeffs, int minMarkers) {
 
     // if camera parameters are avaible, use approximated calibration
     if(_cameraMatrix.total() != 0) {
-        return _interpolateCornersCharucoApproxCalib(_markerCorners, _markerIds, _image, board,
+        _interpolateCornersCharucoApproxCalib(_markerCorners, _markerIds, _image, _board,
                                                      _cameraMatrix, _distCoeffs, _charucoCorners,
                                                      _charucoIds);
     }
     // else use local homography
     else {
-        return _interpolateCornersCharucoLocalHom(_markerCorners, _markerIds, _image, board,
+        _interpolateCornersCharucoLocalHom(_markerCorners, _markerIds, _image, _board,
                                                   _charucoCorners, _charucoIds);
     }
+
+    // to return a charuco corner, its closest aruco markers should have been detected
+    return _filterCornersWithoutMinMarkers(_board, _charucoCorners, _charucoIds, _markerIds,
+                                           minMarkers, _charucoCorners, _charucoIds);
 }
 
 
@@ -621,14 +597,14 @@ void drawDetectedCornersCharuco(InputOutputArray _image, InputArray _charucoCorn
 
     unsigned int nCorners = (unsigned int)_charucoCorners.getMat().total();
     for(unsigned int i = 0; i < nCorners; i++) {
-        Point2f corner = _charucoCorners.getMat().ptr< Point2f >(0)[i];
+        Point2f corner = _charucoCorners.getMat().at< Point2f >(i);
 
         // draw first corner mark
         rectangle(_image, corner - Point2f(3, 3), corner + Point2f(3, 3), cornerColor, 1, LINE_AA);
 
         // draw ID
         if(_charucoIds.total() != 0) {
-            int id = _charucoIds.getMat().ptr< int >(0)[i];
+            int id = _charucoIds.getMat().at< int >(i);
             stringstream s;
             s << "id=" << id;
             putText(_image, s.str(), corner + Point2f(5, -5), FONT_HERSHEY_SIMPLEX, 0.5,
@@ -679,7 +655,7 @@ static bool _arePointsEnoughForPoseEstimation(const vector< Point3f > &points) {
 /**
   */
 bool estimatePoseCharucoBoard(InputArray _charucoCorners, InputArray _charucoIds,
-                              CharucoBoard &board, InputArray _cameraMatrix, InputArray _distCoeffs,
+                              const Ptr<CharucoBoard> &_board, InputArray _cameraMatrix, InputArray _distCoeffs,
                               OutputArray _rvec, OutputArray _tvec) {
 
     CV_Assert((_charucoCorners.getMat().total() == _charucoIds.getMat().total()));
@@ -690,9 +666,9 @@ bool estimatePoseCharucoBoard(InputArray _charucoCorners, InputArray _charucoIds
     vector< Point3f > objPoints;
     objPoints.reserve(_charucoIds.getMat().total());
     for(unsigned int i = 0; i < _charucoIds.getMat().total(); i++) {
-        int currId = _charucoIds.getMat().ptr< int >(0)[i];
-        CV_Assert(currId >= 0 && currId < (int)board.chessboardCorners.size());
-        objPoints.push_back(board.chessboardCorners[currId]);
+        int currId = _charucoIds.getMat().at< int >(i);
+        CV_Assert(currId >= 0 && currId < (int)_board->chessboardCorners.size());
+        objPoints.push_back(_board->chessboardCorners[currId]);
     }
 
     // points need to be in different lines, check if detected points are enough
@@ -709,11 +685,13 @@ bool estimatePoseCharucoBoard(InputArray _charucoCorners, InputArray _charucoIds
 /**
   */
 double calibrateCameraCharuco(InputArrayOfArrays _charucoCorners, InputArrayOfArrays _charucoIds,
-                              const CharucoBoard &board, Size imageSize,
+                              const Ptr<CharucoBoard> &_board, Size imageSize,
                               InputOutputArray _cameraMatrix, InputOutputArray _distCoeffs,
-                              OutputArrayOfArrays _rvecs, OutputArrayOfArrays _tvecs, int flags,
-                              TermCriteria criteria) {
-
+                              OutputArrayOfArrays _rvecs, OutputArrayOfArrays _tvecs,
+                              OutputArray _stdDeviationsIntrinsics,
+                              OutputArray _stdDeviationsExtrinsics,
+                              OutputArray _perViewErrors,
+                              int flags, TermCriteria criteria) {
 
     CV_Assert(_charucoIds.total() > 0 && (_charucoIds.total() == _charucoCorners.total()));
 
@@ -726,20 +704,33 @@ double calibrateCameraCharuco(InputArrayOfArrays _charucoCorners, InputArrayOfAr
         allObjPoints[i].reserve(nCorners);
 
         for(unsigned int j = 0; j < nCorners; j++) {
-            int pointId = _charucoIds.getMat(i).ptr< int >(0)[j];
-            CV_Assert(pointId >= 0 && pointId < (int)board.chessboardCorners.size());
-            allObjPoints[i].push_back(board.chessboardCorners[pointId]);
+            int pointId = _charucoIds.getMat(i).at< int >(j);
+            CV_Assert(pointId >= 0 && pointId < (int)_board->chessboardCorners.size());
+            allObjPoints[i].push_back(_board->chessboardCorners[pointId]);
         }
     }
 
     return calibrateCamera(allObjPoints, _charucoCorners, imageSize, _cameraMatrix, _distCoeffs,
-                           _rvecs, _tvecs, flags, criteria);
+                           _rvecs, _tvecs, _stdDeviationsIntrinsics, _stdDeviationsExtrinsics,
+                           _perViewErrors, flags, criteria);
 }
 
 
 
 /**
  */
+double calibrateCameraCharuco(InputArrayOfArrays _charucoCorners, InputArrayOfArrays _charucoIds,
+  const Ptr<CharucoBoard> &_board, Size imageSize,
+  InputOutputArray _cameraMatrix, InputOutputArray _distCoeffs,
+  OutputArrayOfArrays _rvecs, OutputArrayOfArrays _tvecs, int flags,
+  TermCriteria criteria) {
+    return calibrateCameraCharuco(_charucoCorners, _charucoIds, _board, imageSize, _cameraMatrix, _distCoeffs, _rvecs,
+      _tvecs, noArray(), noArray(), noArray(), flags, criteria);
+}
+
+
+/**
+ */
 void detectCharucoDiamond(InputArray _image, InputArrayOfArrays _markerCorners,
                           InputArray _markerIds, float squareMarkerLengthRate,
                           OutputArrayOfArrays _diamondCorners, OutputArray _diamondIds,
@@ -750,9 +741,9 @@ void detectCharucoDiamond(InputArray _image, InputArrayOfArrays _markerCorners,
     const float minRepDistanceRate = 0.12f;
 
     // create Charuco board layout for diamond (3x3 layout)
-    CharucoBoard charucoDiamondLayout;
-    Dictionary dict = getPredefinedDictionary(PREDEFINED_DICTIONARY_NAME(0));
-    charucoDiamondLayout = CharucoBoard::create(3, 3, squareMarkerLengthRate, 1., dict);
+    Ptr<Dictionary> dict = getPredefinedDictionary(PREDEFINED_DICTIONARY_NAME(0));
+    Ptr<CharucoBoard> _charucoDiamondLayout = CharucoBoard::create(3, 3, squareMarkerLengthRate, 1., dict);
+
 
     vector< vector< Point2f > > diamondCorners;
     vector< Vec4i > diamondIds;
@@ -776,16 +767,13 @@ void detectCharucoDiamond(InputArray _image, InputArrayOfArrays _markerCorners,
         float perimeterSq = 0;
         Mat corners = _markerCorners.getMat(i);
         for(int c = 0; c < 4; c++) {
-            perimeterSq +=
-                (corners.ptr< Point2f >()[c].x - corners.ptr< Point2f >()[(c + 1) % 4].x) *
-                    (corners.ptr< Point2f >()[c].x - corners.ptr< Point2f >()[(c + 1) % 4].x) +
-                (corners.ptr< Point2f >()[c].y - corners.ptr< Point2f >()[(c + 1) % 4].y) *
-                    (corners.ptr< Point2f >()[c].y - corners.ptr< Point2f >()[(c + 1) % 4].y);
+          Point2f edge = corners.at< Point2f >(c) - corners.at< Point2f >((c + 1) % 4);
+          perimeterSq += edge.x*edge.x + edge.y*edge.y;
         }
         // maximum reprojection error relative to perimeter
         float minRepDistance = perimeterSq * minRepDistanceRate * minRepDistanceRate;
 
-        int currentId = _markerIds.getMat().ptr< int >()[i];
+        int currentId = _markerIds.getMat().at< int >(i);
 
         // prepare data to call refineDetectedMarkers()
         // detected markers (only the current one)
@@ -808,13 +796,15 @@ void detectCharucoDiamond(InputArray _image, InputArrayOfArrays _markerCorners,
 
         // modify charuco layout id to make sure all the ids are different than current id
         for(int k = 1; k < 4; k++)
-            charucoDiamondLayout.ids[k] = currentId + 1 + k;
+            _charucoDiamondLayout->ids[k] = currentId + 1 + k;
         // current id is assigned to [0], so it is the marker on the top
-        charucoDiamondLayout.ids[0] = currentId;
+        _charucoDiamondLayout->ids[0] = currentId;
 
         // try to find the rest of markers in the diamond
         vector< int > acceptedIdxs;
-        aruco::refineDetectedMarkers(grey, charucoDiamondLayout, currentMarker, currentMarkerId,
+        Ptr<Board> _b = _charucoDiamondLayout.staticCast<Board>();
+        aruco::refineDetectedMarkers(grey, _b,
+                                     currentMarker, currentMarkerId,
                                      candidates, noArray(), noArray(), minRepDistance, -1, false,
                                      acceptedIdxs);
 
@@ -829,14 +819,14 @@ void detectCharucoDiamond(InputArray _image, InputArrayOfArrays _markerCorners,
             markerId[0] = currentId;
             for(int k = 1; k < 4; k++) {
                 int currentMarkerIdx = candidatesIdxs[acceptedIdxs[k - 1]];
-                markerId[k] = _markerIds.getMat().ptr< int >()[currentMarkerIdx];
+                markerId[k] = _markerIds.getMat().at< int >(currentMarkerIdx);
                 assigned[currentMarkerIdx] = true;
             }
 
             // interpolate the charuco corners of the diamond
             vector< Point2f > currentMarkerCorners;
             Mat aux;
-            interpolateCornersCharuco(currentMarker, currentMarkerId, grey, charucoDiamondLayout,
+            interpolateCornersCharuco(currentMarker, currentMarkerId, grey, _charucoDiamondLayout,
                                       currentMarkerCorners, aux, _cameraMatrix, _distCoeffs);
 
             // if everything is ok, save the diamond
@@ -857,17 +847,14 @@ void detectCharucoDiamond(InputArray _image, InputArrayOfArrays _markerCorners,
 
 
     if(diamondIds.size() > 0) {
-
         // parse output
-        _diamondIds.create((int)diamondIds.size(), 1, CV_32SC4);
-        for(unsigned int i = 0; i < diamondIds.size(); i++)
-            _diamondIds.getMat().ptr< Vec4i >(0)[i] = diamondIds[i];
+        Mat(diamondIds).copyTo(_diamondIds);
 
         _diamondCorners.create((int)diamondCorners.size(), 1, CV_32FC2);
         for(unsigned int i = 0; i < diamondCorners.size(); i++) {
             _diamondCorners.create(4, 1, CV_32FC2, i, true);
             for(int j = 0; j < 4; j++) {
-                _diamondCorners.getMat(i).ptr< Point2f >()[j] = diamondCorners[i][j];
+                _diamondCorners.getMat(i).at< Point2f >(j) = diamondCorners[i][j];
             }
         }
     }
@@ -878,22 +865,22 @@ void detectCharucoDiamond(InputArray _image, InputArrayOfArrays _markerCorners,
 
 /**
   */
-void drawCharucoDiamond(Dictionary dictionary, Vec4i ids, int squareLength, int markerLength,
+void drawCharucoDiamond(const Ptr<Dictionary> &dictionary, Vec4i ids, int squareLength, int markerLength,
                         OutputArray _img, int marginSize, int borderBits) {
 
     CV_Assert(squareLength > 0 && markerLength > 0 && squareLength > markerLength);
     CV_Assert(marginSize >= 0 && borderBits > 0);
 
     // create a charuco board similar to a charuco marker and print it
-    CharucoBoard board =
+    Ptr<CharucoBoard> board =
         CharucoBoard::create(3, 3, (float)squareLength, (float)markerLength, dictionary);
 
     // assign the charuco marker ids
     for(int i = 0; i < 4; i++)
-        board.ids[i] = ids[i];
+        board->ids[i] = ids[i];
 
     Size outSize(3 * squareLength + 2 * marginSize, 3 * squareLength + 2 * marginSize);
-    board.draw(outSize, _img, marginSize, borderBits);
+    board->draw(outSize, _img, marginSize, borderBits);
 }
 
 
@@ -921,23 +908,23 @@ void drawDetectedDiamonds(InputOutputArray _image, InputArrayOfArrays _corners,
         // draw marker sides
         for(int j = 0; j < 4; j++) {
             Point2f p0, p1;
-            p0 = currentMarker.ptr< Point2f >(0)[j];
-            p1 = currentMarker.ptr< Point2f >(0)[(j + 1) % 4];
+            p0 = currentMarker.at< Point2f >(j);
+            p1 = currentMarker.at< Point2f >((j + 1) % 4);
             line(_image, p0, p1, borderColor, 1);
         }
 
         // draw first corner mark
-        rectangle(_image, currentMarker.ptr< Point2f >(0)[0] - Point2f(3, 3),
-                  currentMarker.ptr< Point2f >(0)[0] + Point2f(3, 3), cornerColor, 1, LINE_AA);
+        rectangle(_image, currentMarker.at< Point2f >(0) - Point2f(3, 3),
+                  currentMarker.at< Point2f >(0) + Point2f(3, 3), cornerColor, 1, LINE_AA);
 
         // draw id composed by four numbers
         if(_ids.total() != 0) {
             Point2f cent(0, 0);
             for(int p = 0; p < 4; p++)
-                cent += currentMarker.ptr< Point2f >(0)[p];
+                cent += currentMarker.at< Point2f >(p);
             cent = cent / 4.;
             stringstream s;
-            s << "id=" << _ids.getMat().ptr< Vec4i >(0)[i];
+            s << "id=" << _ids.getMat().at< Vec4i >(i);
             putText(_image, s.str(), cent, FONT_HERSHEY_SIMPLEX, 0.5, textColor, 2);
         }
     }
diff --git a/contrib/modules/aruco/src/dictionary.cpp b/contrib/modules/aruco/src/dictionary.cpp
index acdae4f..207ae6f 100644
--- a/contrib/modules/aruco/src/dictionary.cpp
+++ b/contrib/modules/aruco/src/dictionary.cpp
@@ -48,6 +48,16 @@ namespace aruco {
 
 using namespace std;
 
+
+/**
+  */
+Dictionary::Dictionary(const Ptr<Dictionary> &_dictionary) {
+    markerSize = _dictionary->markerSize;
+    maxCorrectionBits = _dictionary->maxCorrectionBits;
+    bytesList = _dictionary->bytesList.clone();
+}
+
+
 /**
   */
 Dictionary::Dictionary(const Mat &_bytesList, int _markerSize, int _maxcorr) {
@@ -57,6 +67,28 @@ Dictionary::Dictionary(const Mat &_bytesList, int _markerSize, int _maxcorr) {
 }
 
 
+/**
+ */
+Ptr<Dictionary> Dictionary::create(int nMarkers, int markerSize) {
+    const Ptr<Dictionary> baseDictionary = makePtr<Dictionary>();
+    return create(nMarkers, markerSize, baseDictionary);
+}
+
+
+/**
+ */
+Ptr<Dictionary> Dictionary::create(int nMarkers, int markerSize,
+                                   const Ptr<Dictionary> &baseDictionary) {
+    return generateCustomDictionary(nMarkers, markerSize, baseDictionary);
+}
+
+
+/**
+ */
+Ptr<Dictionary> Dictionary::get(int dict) {
+    return getPredefinedDictionary(dict);
+}
+
 
 /**
  */
@@ -131,7 +163,7 @@ int Dictionary::getDistanceToId(InputArray bits, int id, bool allRotations) cons
  */
 void Dictionary::drawMarker(int id, int sidePixels, OutputArray _img, int borderBits) const {
 
-    CV_Assert(sidePixels > markerSize);
+    CV_Assert(sidePixels >= (markerSize + 2*borderBits));
     CV_Assert(id < bytesList.rows);
     CV_Assert(borderBits > 0);
 
@@ -259,50 +291,55 @@ const Dictionary DICT_7X7_250_DATA = Dictionary(Mat(250, (7*7 + 7)/8 ,CV_8UC4, (
 const Dictionary DICT_7X7_1000_DATA = Dictionary(Mat(1000, (7*7 + 7)/8 ,CV_8UC4, (uchar*)DICT_7X7_1000_BYTES), 7, 6);
 
 
-const Dictionary &getPredefinedDictionary(PREDEFINED_DICTIONARY_NAME name) {
+Ptr<Dictionary> getPredefinedDictionary(PREDEFINED_DICTIONARY_NAME name) {
     switch(name) {
 
     case DICT_ARUCO_ORIGINAL:
-        return DICT_ARUCO_DATA;
+        return makePtr<Dictionary>(DICT_ARUCO_DATA);
 
     case DICT_4X4_50:
-        return DICT_4X4_50_DATA;
+        return makePtr<Dictionary>(DICT_4X4_50_DATA);
     case DICT_4X4_100:
-        return DICT_4X4_100_DATA;
+        return makePtr<Dictionary>(DICT_4X4_100_DATA);
     case DICT_4X4_250:
-        return DICT_4X4_250_DATA;
+        return makePtr<Dictionary>(DICT_4X4_250_DATA);
     case DICT_4X4_1000:
-        return DICT_4X4_1000_DATA;
+        return makePtr<Dictionary>(DICT_4X4_1000_DATA);
 
     case DICT_5X5_50:
-        return DICT_5X5_50_DATA;
+        return makePtr<Dictionary>(DICT_5X5_50_DATA);
     case DICT_5X5_100:
-        return DICT_5X5_100_DATA;
+        return makePtr<Dictionary>(DICT_5X5_100_DATA);
     case DICT_5X5_250:
-        return DICT_5X5_250_DATA;
+        return makePtr<Dictionary>(DICT_5X5_250_DATA);
     case DICT_5X5_1000:
-        return DICT_5X5_1000_DATA;
+        return makePtr<Dictionary>(DICT_5X5_1000_DATA);
 
     case DICT_6X6_50:
-        return DICT_6X6_50_DATA;
+        return makePtr<Dictionary>(DICT_6X6_50_DATA);
     case DICT_6X6_100:
-        return DICT_6X6_100_DATA;
+        return makePtr<Dictionary>(DICT_6X6_100_DATA);
     case DICT_6X6_250:
-        return DICT_6X6_250_DATA;
+        return makePtr<Dictionary>(DICT_6X6_250_DATA);
     case DICT_6X6_1000:
-        return DICT_6X6_1000_DATA;
+        return makePtr<Dictionary>(DICT_6X6_1000_DATA);
 
     case DICT_7X7_50:
-        return DICT_7X7_50_DATA;
+        return makePtr<Dictionary>(DICT_7X7_50_DATA);
     case DICT_7X7_100:
-        return DICT_7X7_100_DATA;
+        return makePtr<Dictionary>(DICT_7X7_100_DATA);
     case DICT_7X7_250:
-        return DICT_7X7_250_DATA;
+        return makePtr<Dictionary>(DICT_7X7_250_DATA);
     case DICT_7X7_1000:
-        return DICT_7X7_1000_DATA;
+        return makePtr<Dictionary>(DICT_7X7_1000_DATA);
 
     }
-    return DICT_4X4_50_DATA;
+    return makePtr<Dictionary>(DICT_4X4_50_DATA);
+}
+
+
+Ptr<Dictionary> getPredefinedDictionary(int dict) {
+    return getPredefinedDictionary(PREDEFINED_DICTIONARY_NAME(dict));
 }
 
 
@@ -313,7 +350,7 @@ static Mat _generateRandomMarker(int markerSize) {
     Mat marker(markerSize, markerSize, CV_8UC1, Scalar::all(0));
     for(int i = 0; i < markerSize; i++) {
         for(int j = 0; j < markerSize; j++) {
-            unsigned char bit = rand() % 2;
+            unsigned char bit = (unsigned char) (rand() % 2);
             marker.at< unsigned char >(i, j) = bit;
         }
     }
@@ -339,11 +376,11 @@ static int _getSelfDistance(const Mat &marker) {
 
 /**
  */
-Dictionary generateCustomDictionary(int nMarkers, int markerSize,
-                                    const Dictionary &baseDictionary) {
+Ptr<Dictionary> generateCustomDictionary(int nMarkers, int markerSize,
+                                         const Ptr<Dictionary> &baseDictionary) {
 
-    Dictionary out;
-    out.markerSize = markerSize;
+    Ptr<Dictionary> out = makePtr<Dictionary>();
+    out->markerSize = markerSize;
 
     // theoretical maximum intermarker distance
     // See S. Garrido-Jurado, R. Muñoz-Salinas, F. J. Madrid-Cuevas, and M. J. Marín-Jiménez. 2014.
@@ -353,17 +390,17 @@ Dictionary generateCustomDictionary(int nMarkers, int markerSize,
     int tau = 2 * (int)std::floor(float(C) * 4.f / 3.f);
 
     // if baseDictionary is provided, calculate its intermarker distance
-    if(baseDictionary.bytesList.rows > 0) {
-        CV_Assert(baseDictionary.markerSize == markerSize);
-        out.bytesList = baseDictionary.bytesList.clone();
+    if(baseDictionary->bytesList.rows > 0) {
+        CV_Assert(baseDictionary->markerSize == markerSize);
+        out->bytesList = baseDictionary->bytesList.clone();
 
         int minDistance = markerSize * markerSize + 1;
-        for(int i = 0; i < out.bytesList.rows; i++) {
-            Mat markerBytes = out.bytesList.rowRange(i, i + 1);
+        for(int i = 0; i < out->bytesList.rows; i++) {
+            Mat markerBytes = out->bytesList.rowRange(i, i + 1);
             Mat markerBits = Dictionary::getBitsFromByteList(markerBytes, markerSize);
             minDistance = min(minDistance, _getSelfDistance(markerBits));
-            for(int j = i + 1; j < out.bytesList.rows; j++) {
-                minDistance = min(minDistance, out.getDistanceToId(markerBits, j));
+            for(int j = i + 1; j < out->bytesList.rows; j++) {
+                minDistance = min(minDistance, out->getDistanceToId(markerBits, j));
             }
         }
         tau = minDistance;
@@ -377,7 +414,7 @@ Dictionary generateCustomDictionary(int nMarkers, int markerSize,
     const int maxUnproductiveIterations = 5000;
     int unproductiveIterations = 0;
 
-    while(out.bytesList.rows < nMarkers) {
+    while(out->bytesList.rows < nMarkers) {
         Mat currentMarker = _generateRandomMarker(markerSize);
 
         int selfDistance = _getSelfDistance(currentMarker);
@@ -386,8 +423,8 @@ Dictionary generateCustomDictionary(int nMarkers, int markerSize,
         // if self distance is better or equal than current best option, calculate distance
         // to previous accepted markers
         if(selfDistance >= bestTau) {
-            for(int i = 0; i < out.bytesList.rows; i++) {
-                int currentDistance = out.getDistanceToId(currentMarker, i);
+            for(int i = 0; i < out->bytesList.rows; i++) {
+                int currentDistance = out->getDistanceToId(currentMarker, i);
                 minDistance = min(currentDistance, minDistance);
                 if(minDistance <= bestTau) {
                     break;
@@ -400,7 +437,7 @@ Dictionary generateCustomDictionary(int nMarkers, int markerSize,
             unproductiveIterations = 0;
             bestTau = 0;
             Mat bytes = Dictionary::getByteListFromBits(currentMarker);
-            out.bytesList.push_back(bytes);
+            out->bytesList.push_back(bytes);
         } else {
             unproductiveIterations++;
 
@@ -416,15 +453,25 @@ Dictionary generateCustomDictionary(int nMarkers, int markerSize,
                 tau = bestTau;
                 bestTau = 0;
                 Mat bytes = Dictionary::getByteListFromBits(bestMarker);
-                out.bytesList.push_back(bytes);
+                out->bytesList.push_back(bytes);
             }
         }
     }
 
     // update the maximum number of correction bits for the generated dictionary
-    out.maxCorrectionBits = (tau - 1) / 2;
+    out->maxCorrectionBits = (tau - 1) / 2;
 
     return out;
 }
+
+
+/**
+ */
+Ptr<Dictionary> generateCustomDictionary(int nMarkers, int markerSize) {
+    Ptr<Dictionary> baseDictionary = makePtr<Dictionary>();
+    return generateCustomDictionary(nMarkers, markerSize, baseDictionary);
+}
+
+
 }
 }
diff --git a/contrib/modules/aruco/test/test_arucodetection.cpp b/contrib/modules/aruco/test/test_arucodetection.cpp
index 0f73049..9d92388 100644
--- a/contrib/modules/aruco/test/test_arucodetection.cpp
+++ b/contrib/modules/aruco/test/test_arucodetection.cpp
@@ -62,7 +62,7 @@ CV_ArucoDetectionSimple::CV_ArucoDetectionSimple() {}
 
 void CV_ArucoDetectionSimple::run(int) {
 
-    aruco::Dictionary dictionary = aruco::getPredefinedDictionary(aruco::DICT_6X6_250);
+    Ptr<aruco::Dictionary> dictionary = aruco::getPredefinedDictionary(aruco::DICT_6X6_250);
 
     // 20 images
     for(int i = 0; i < 20; i++) {
@@ -99,7 +99,7 @@ void CV_ArucoDetectionSimple::run(int) {
         // detect markers
         vector< vector< Point2f > > corners;
         vector< int > ids;
-        aruco::DetectorParameters params;
+        Ptr<aruco::DetectorParameters> params = aruco::DetectorParameters::create();
         aruco::detectMarkers(img, dictionary, corners, ids, params);
 
         // check detection results
@@ -183,7 +183,7 @@ static void getSyntheticRT(double yaw, double pitch, double distance, Mat &rvec,
 /**
  * @brief Create a synthetic image of a marker with perspective
  */
-static Mat projectMarker(aruco::Dictionary dictionary, int id, Mat cameraMatrix, double yaw,
+static Mat projectMarker(Ptr<aruco::Dictionary> &dictionary, int id, Mat cameraMatrix, double yaw,
                          double pitch, double distance, Size imageSize, int markerBorder,
                          vector< Point2f > &corners) {
 
@@ -257,7 +257,7 @@ void CV_ArucoDetectionPerspective::run(int) {
     cameraMatrix.at< double >(0, 0) = cameraMatrix.at< double >(1, 1) = 650;
     cameraMatrix.at< double >(0, 2) = imgSize.width / 2;
     cameraMatrix.at< double >(1, 2) = imgSize.height / 2;
-    aruco::Dictionary dictionary = aruco::getPredefinedDictionary(aruco::DICT_6X6_250);
+    Ptr<aruco::Dictionary> dictionary = aruco::getPredefinedDictionary(aruco::DICT_6X6_250);
 
     // detect from different positions
     for(double distance = 0.1; distance <= 0.5; distance += 0.2) {
@@ -275,9 +275,9 @@ void CV_ArucoDetectionPerspective::run(int) {
                 // detect markers
                 vector< vector< Point2f > > corners;
                 vector< int > ids;
-                aruco::DetectorParameters params;
-                params.minDistanceToBorder = 1;
-                params.markerBorderBits = markerBorder;
+                Ptr<aruco::DetectorParameters> params = aruco::DetectorParameters::create();
+                params->minDistanceToBorder = 1;
+                params->markerBorderBits = markerBorder;
                 aruco::detectMarkers(img, dictionary, corners, ids, params);
 
                 // check results
@@ -320,7 +320,7 @@ CV_ArucoDetectionMarkerSize::CV_ArucoDetectionMarkerSize() {}
 
 void CV_ArucoDetectionMarkerSize::run(int) {
 
-    aruco::Dictionary dictionary = aruco::getPredefinedDictionary(aruco::DICT_6X6_250);
+    Ptr<aruco::Dictionary> dictionary = aruco::getPredefinedDictionary(aruco::DICT_6X6_250);
     int markerSide = 20;
     int imageSize = 200;
 
@@ -337,10 +337,10 @@ void CV_ArucoDetectionMarkerSize::run(int) {
 
         vector< vector< Point2f > > corners;
         vector< int > ids;
-        aruco::DetectorParameters params;
+        Ptr<aruco::DetectorParameters> params = aruco::DetectorParameters::create();
 
         // set a invalid minMarkerPerimeterRate
-        params.minMarkerPerimeterRate = min(4., (4. * markerSide) / float(imageSize) + 0.1);
+        params->minMarkerPerimeterRate = min(4., (4. * markerSide) / float(imageSize) + 0.1);
         aruco::detectMarkers(img, dictionary, corners, ids, params);
         if(corners.size() != 0) {
             ts->printf(cvtest::TS::LOG, "Error in DetectorParameters::minMarkerPerimeterRate");
@@ -349,7 +349,7 @@ void CV_ArucoDetectionMarkerSize::run(int) {
         }
 
         // set an valid minMarkerPerimeterRate
-        params.minMarkerPerimeterRate = max(0., (4. * markerSide) / float(imageSize) - 0.1);
+        params->minMarkerPerimeterRate = max(0., (4. * markerSide) / float(imageSize) - 0.1);
         aruco::detectMarkers(img, dictionary, corners, ids, params);
         if(corners.size() != 1 || (corners.size() == 1 && ids[0] != id)) {
             ts->printf(cvtest::TS::LOG, "Error in DetectorParameters::minMarkerPerimeterRate");
@@ -358,7 +358,7 @@ void CV_ArucoDetectionMarkerSize::run(int) {
         }
 
         // set a invalid maxMarkerPerimeterRate
-        params.maxMarkerPerimeterRate = min(4., (4. * markerSide) / float(imageSize) - 0.1);
+        params->maxMarkerPerimeterRate = min(4., (4. * markerSide) / float(imageSize) - 0.1);
         aruco::detectMarkers(img, dictionary, corners, ids, params);
         if(corners.size() != 0) {
             ts->printf(cvtest::TS::LOG, "Error in DetectorParameters::maxMarkerPerimeterRate");
@@ -367,7 +367,7 @@ void CV_ArucoDetectionMarkerSize::run(int) {
         }
 
         // set an valid maxMarkerPerimeterRate
-        params.maxMarkerPerimeterRate = max(0., (4. * markerSide) / float(imageSize) + 0.1);
+        params->maxMarkerPerimeterRate = max(0., (4. * markerSide) / float(imageSize) + 0.1);
         aruco::detectMarkers(img, dictionary, corners, ids, params);
         if(corners.size() != 1 || (corners.size() == 1 && ids[0] != id)) {
             ts->printf(cvtest::TS::LOG, "Error in DetectorParameters::maxMarkerPerimeterRate");
@@ -395,11 +395,12 @@ CV_ArucoBitCorrection::CV_ArucoBitCorrection() {}
 
 void CV_ArucoBitCorrection::run(int) {
 
-    aruco::Dictionary dictionary = aruco::getPredefinedDictionary(aruco::DICT_6X6_250);
-    aruco::Dictionary dictionary2 = dictionary;
+    Ptr<aruco::Dictionary> _dictionary = aruco::getPredefinedDictionary(aruco::DICT_6X6_250);
+    aruco::Dictionary &dictionary = *_dictionary;
+    aruco::Dictionary dictionary2 = *_dictionary;
     int markerSide = 50;
     int imageSize = 150;
-    aruco::DetectorParameters params;
+    Ptr<aruco::DetectorParameters> params = aruco::DetectorParameters::create();
 
     // 10 markers
     for(int l = 0; l < 10; l++) {
@@ -411,9 +412,9 @@ void CV_ArucoBitCorrection::run(int) {
         // 5 valid cases
         for(int i = 0; i < 5; i++) {
             // how many bit errors (the error is low enough so it can be corrected)
-            params.errorCorrectionRate = 0.2 + i * 0.1;
+            params->errorCorrectionRate = 0.2 + i * 0.1;
             int errors =
-                (int)std::floor(dictionary.maxCorrectionBits * params.errorCorrectionRate - 1.);
+                (int)std::floor(dictionary.maxCorrectionBits * params->errorCorrectionRate - 1.);
 
             // create erroneous marker in currentCodeBits
             Mat currentCodeBits =
@@ -427,14 +428,14 @@ void CV_ArucoBitCorrection::run(int) {
             Mat currentCodeBytesError = aruco::Dictionary::getByteListFromBits(currentCodeBits);
             currentCodeBytesError.copyTo(dictionary2.bytesList.rowRange(id, id + 1));
             Mat img = Mat(imageSize, imageSize, CV_8UC1, Scalar::all(255));
-            aruco::drawMarker(dictionary2, id, markerSide, marker);
+            dictionary2.drawMarker(id, markerSide, marker);
             Mat aux = img.colRange(30, 30 + markerSide).rowRange(50, 50 + markerSide);
             marker.copyTo(aux);
 
             // try to detect using original dictionary
             vector< vector< Point2f > > corners;
             vector< int > ids;
-            aruco::detectMarkers(img, dictionary, corners, ids, params);
+            aruco::detectMarkers(img, _dictionary, corners, ids, params);
             if(corners.size() != 1 || (corners.size() == 1 && ids[0] != id)) {
                 ts->printf(cvtest::TS::LOG, "Error in bit correction");
                 ts->set_failed_test_info(cvtest::TS::FAIL_BAD_ACCURACY);
@@ -445,9 +446,9 @@ void CV_ArucoBitCorrection::run(int) {
         // 5 invalid cases
         for(int i = 0; i < 5; i++) {
             // how many bit errors (the error is too high to be corrected)
-            params.errorCorrectionRate = 0.2 + i * 0.1;
+            params->errorCorrectionRate = 0.2 + i * 0.1;
             int errors =
-                (int)std::floor(dictionary.maxCorrectionBits * params.errorCorrectionRate + 1.);
+                (int)std::floor(dictionary.maxCorrectionBits * params->errorCorrectionRate + 1.);
 
             // create erroneous marker in currentCodeBits
             Mat currentCodeBits =
@@ -458,21 +459,23 @@ void CV_ArucoBitCorrection::run(int) {
             }
 
             // dictionary3 is only composed by the modified marker (in its original form)
-            aruco::Dictionary dictionary3 = dictionary;
-            dictionary3.bytesList = dictionary2.bytesList.rowRange(id, id + 1).clone();
+            Ptr<aruco::Dictionary> _dictionary3 = makePtr<aruco::Dictionary>(
+                    dictionary2.bytesList.rowRange(id, id + 1).clone(),
+                    dictionary.markerSize,
+                    dictionary.maxCorrectionBits);
 
             // add erroneous marker to dictionary2 in order to create the erroneous marker image
             Mat currentCodeBytesError = aruco::Dictionary::getByteListFromBits(currentCodeBits);
             currentCodeBytesError.copyTo(dictionary2.bytesList.rowRange(id, id + 1));
             Mat img = Mat(imageSize, imageSize, CV_8UC1, Scalar::all(255));
-            aruco::drawMarker(dictionary2, id, markerSide, marker);
+            dictionary2.drawMarker(id, markerSide, marker);
             Mat aux = img.colRange(30, 30 + markerSide).rowRange(50, 50 + markerSide);
             marker.copyTo(aux);
 
             // try to detect using dictionary3, it should fail
             vector< vector< Point2f > > corners;
             vector< int > ids;
-            aruco::detectMarkers(img, dictionary3, corners, ids, params);
+            aruco::detectMarkers(img, _dictionary3, corners, ids, params);
             if(corners.size() != 0) {
                 ts->printf(cvtest::TS::LOG, "Error in DetectorParameters::errorCorrectionRate");
                 ts->set_failed_test_info(cvtest::TS::FAIL_BAD_ACCURACY);
diff --git a/contrib/modules/aruco/test/test_boarddetection.cpp b/contrib/modules/aruco/test/test_boarddetection.cpp
index c6f6f45..e5a2bd4 100644
--- a/contrib/modules/aruco/test/test_boarddetection.cpp
+++ b/contrib/modules/aruco/test/test_boarddetection.cpp
@@ -98,7 +98,7 @@ static void getSyntheticRT(double yaw, double pitch, double distance, Mat &rvec,
 /**
  * @brief Project a synthetic marker
  */
-static void projectMarker(Mat &img, aruco::Dictionary dictionary, int id,
+static void projectMarker(Mat &img, Ptr<aruco::Dictionary> &dictionary, int id,
                           vector< Point3f > markerObjPoints, Mat cameraMatrix, Mat rvec, Mat tvec,
                           int markerBorder) {
 
@@ -140,15 +140,15 @@ static void projectMarker(Mat &img, aruco::Dictionary dictionary, int id,
 /**
  * @brief Get a synthetic image of GridBoard in perspective
  */
-static Mat projectBoard(aruco::GridBoard board, Mat cameraMatrix, double yaw, double pitch,
+static Mat projectBoard(Ptr<aruco::GridBoard> &board, Mat cameraMatrix, double yaw, double pitch,
                         double distance, Size imageSize, int markerBorder) {
 
     Mat rvec, tvec;
     getSyntheticRT(yaw, pitch, distance, rvec, tvec);
 
     Mat img = Mat(imageSize, CV_8UC1, Scalar::all(255));
-    for(unsigned int m = 0; m < board.ids.size(); m++) {
-        projectMarker(img, board.dictionary, board.ids[m], board.objPoints[m], cameraMatrix, rvec,
+    for(unsigned int m = 0; m < board->ids.size(); m++) {
+        projectMarker(img, board->dictionary, board->ids[m], board->objPoints[m], cameraMatrix, rvec,
                       tvec, markerBorder);
     }
 
@@ -177,8 +177,9 @@ void CV_ArucoBoardPose::run(int) {
     int iter = 0;
     Mat cameraMatrix = Mat::eye(3, 3, CV_64FC1);
     Size imgSize(500, 500);
-    aruco::Dictionary dictionary = aruco::getPredefinedDictionary(aruco::DICT_6X6_250);
-    aruco::GridBoard board = aruco::GridBoard::create(3, 3, 0.02f, 0.005f, dictionary);
+    Ptr<aruco::Dictionary> dictionary = aruco::getPredefinedDictionary(aruco::DICT_6X6_250);
+    Ptr<aruco::GridBoard> gridboard = aruco::GridBoard::create(3, 3, 0.02f, 0.005f, dictionary);
+    Ptr<aruco::Board> board = gridboard.staticCast<aruco::Board>();
     cameraMatrix.at< double >(0, 0) = cameraMatrix.at< double >(1, 1) = 650;
     cameraMatrix.at< double >(0, 2) = imgSize.width / 2;
     cameraMatrix.at< double >(1, 2) = imgSize.height / 2;
@@ -188,21 +189,21 @@ void CV_ArucoBoardPose::run(int) {
     for(double distance = 0.2; distance <= 0.4; distance += 0.2) {
         for(int yaw = 0; yaw < 360; yaw += 100) {
             for(int pitch = 30; pitch <= 90; pitch += 50) {
-                for(unsigned int i = 0; i < board.ids.size(); i++)
-                    board.ids[i] = (iter + int(i)) % 250;
+                for(unsigned int i = 0; i < gridboard->ids.size(); i++)
+                    gridboard->ids[i] = (iter + int(i)) % 250;
                 int markerBorder = iter % 2 + 1;
                 iter++;
 
                 // create synthetic image
-                Mat img = projectBoard(board, cameraMatrix, deg2rad(pitch), deg2rad(yaw), distance,
+                Mat img = projectBoard(gridboard, cameraMatrix, deg2rad(pitch), deg2rad(yaw), distance,
                                        imgSize, markerBorder);
 
 
                 vector< vector< Point2f > > corners;
                 vector< int > ids;
-                aruco::DetectorParameters params;
-                params.minDistanceToBorder = 3;
-                params.markerBorderBits = markerBorder;
+                Ptr<aruco::DetectorParameters> params = aruco::DetectorParameters::create();
+                params->minDistanceToBorder = 3;
+                params->markerBorderBits = markerBorder;
                 aruco::detectMarkers(img, dictionary, corners, ids, params);
 
                 if(ids.size() == 0) {
@@ -218,8 +219,8 @@ void CV_ArucoBoardPose::run(int) {
                 // check result
                 for(unsigned int i = 0; i < ids.size(); i++) {
                     int foundIdx = -1;
-                    for(unsigned int j = 0; j < board.ids.size(); j++) {
-                        if(board.ids[j] == ids[i]) {
+                    for(unsigned int j = 0; j < gridboard->ids.size(); j++) {
+                        if(gridboard->ids[j] == ids[i]) {
                             foundIdx = int(j);
                             break;
                         }
@@ -232,7 +233,7 @@ void CV_ArucoBoardPose::run(int) {
                     }
 
                     vector< Point2f > projectedCorners;
-                    projectPoints(board.objPoints[foundIdx], rvec, tvec, cameraMatrix, distCoeffs,
+                    projectPoints(gridboard->objPoints[foundIdx], rvec, tvec, cameraMatrix, distCoeffs,
                                   projectedCorners);
 
                     for(int c = 0; c < 4; c++) {
@@ -271,8 +272,9 @@ void CV_ArucoRefine::run(int) {
     int iter = 0;
     Mat cameraMatrix = Mat::eye(3, 3, CV_64FC1);
     Size imgSize(500, 500);
-    aruco::Dictionary dictionary = aruco::getPredefinedDictionary(aruco::DICT_6X6_250);
-    aruco::GridBoard board = aruco::GridBoard::create(3, 3, 0.02f, 0.005f, dictionary);
+    Ptr<aruco::Dictionary> dictionary = aruco::getPredefinedDictionary(aruco::DICT_6X6_250);
+    Ptr<aruco::GridBoard> gridboard = aruco::GridBoard::create(3, 3, 0.02f, 0.005f, dictionary);
+    Ptr<aruco::Board> board = gridboard.staticCast<aruco::Board>();
     cameraMatrix.at< double >(0, 0) = cameraMatrix.at< double >(1, 1) = 650;
     cameraMatrix.at< double >(0, 2) = imgSize.width / 2;
     cameraMatrix.at< double >(1, 2) = imgSize.height / 2;
@@ -282,23 +284,23 @@ void CV_ArucoRefine::run(int) {
     for(double distance = 0.2; distance <= 0.4; distance += 0.2) {
         for(int yaw = 0; yaw < 360; yaw += 100) {
             for(int pitch = 30; pitch <= 90; pitch += 50) {
-                for(unsigned int i = 0; i < board.ids.size(); i++)
-                    board.ids[i] = (iter + int(i)) % 250;
+                for(unsigned int i = 0; i < gridboard->ids.size(); i++)
+                    gridboard->ids[i] = (iter + int(i)) % 250;
                 int markerBorder = iter % 2 + 1;
                 iter++;
 
                 // create synthetic image
-                Mat img = projectBoard(board, cameraMatrix, deg2rad(pitch), deg2rad(yaw), distance,
+                Mat img = projectBoard(gridboard, cameraMatrix, deg2rad(pitch), deg2rad(yaw), distance,
                                        imgSize, markerBorder);
 
 
                 // detect markers
                 vector< vector< Point2f > > corners, rejected;
                 vector< int > ids;
-                aruco::DetectorParameters params;
-                params.minDistanceToBorder = 3;
-                params.doCornerRefinement = true;
-                params.markerBorderBits = markerBorder;
+                Ptr<aruco::DetectorParameters> params = aruco::DetectorParameters::create();
+                params->minDistanceToBorder = 3;
+                params->doCornerRefinement = true;
+                params->markerBorderBits = markerBorder;
                 aruco::detectMarkers(img, dictionary, corners, ids, params, rejected);
 
                 // remove a marker from detection
@@ -336,3 +338,72 @@ TEST(CV_ArucoRefine, accuracy) {
     CV_ArucoRefine test;
     test.safe_run();
 }
+
+TEST(CV_ArucoBoardPose, CheckNegativeZ)
+{
+    double matrixData[9] = { -3.9062571886921410e+02, 0., 4.2350000000000000e+02,
+                              0., 3.9062571886921410e+02, 2.3950000000000000e+02,
+                              0., 0., 1 };
+    cv::Mat cameraMatrix = cv::Mat(3, 3, CV_64F, matrixData);
+
+    cv::Ptr<cv::aruco::Board> boardPtr(new cv::aruco::Board);
+    cv::aruco::Board& board = *boardPtr;
+    board.ids.push_back(0);
+    board.ids.push_back(1);
+
+    vector<cv::Point3f> pts3d;
+    pts3d.push_back(cv::Point3f(0.326198f, -0.030621f, 0.303620f));
+    pts3d.push_back(cv::Point3f(0.325340f, -0.100594f, 0.301862f));
+    pts3d.push_back(cv::Point3f(0.255859f, -0.099530f, 0.293416f));
+    pts3d.push_back(cv::Point3f(0.256717f, -0.029557f, 0.295174f));
+    board.objPoints.push_back(pts3d);
+    pts3d.clear();
+    pts3d.push_back(cv::Point3f(-0.033144f, -0.034819f, 0.245216f));
+    pts3d.push_back(cv::Point3f(-0.035507f, -0.104705f, 0.241987f));
+    pts3d.push_back(cv::Point3f(-0.105289f, -0.102120f, 0.237120f));
+    pts3d.push_back(cv::Point3f(-0.102926f, -0.032235f, 0.240349f));
+    board.objPoints.push_back(pts3d);
+
+    vector<vector<Point2f> > corners;
+    vector<Point2f> pts2d;
+    pts2d.push_back(cv::Point2f(37.7f, 203.3f));
+    pts2d.push_back(cv::Point2f(38.5f, 120.5f));
+    pts2d.push_back(cv::Point2f(105.5f, 115.8f));
+    pts2d.push_back(cv::Point2f(104.2f, 202.7f));
+    corners.push_back(pts2d);
+    pts2d.clear();
+    pts2d.push_back(cv::Point2f(476.0f, 184.2f));
+    pts2d.push_back(cv::Point2f(479.6f, 73.8f));
+    pts2d.push_back(cv::Point2f(590.9f, 77.0f));
+    pts2d.push_back(cv::Point2f(587.5f, 188.1f));
+    corners.push_back(pts2d);
+
+    Vec3d rvec, tvec;
+    int nUsed = cv::aruco::estimatePoseBoard(corners, board.ids, boardPtr, cameraMatrix, Mat(), rvec, tvec);
+    ASSERT_EQ(nUsed, 2);
+
+    cv::Matx33d rotm; cv::Point3d out;
+    cv::Rodrigues(rvec, rotm);
+    out = cv::Point3d(tvec) + rotm*Point3d(board.objPoints[0][0]);
+    ASSERT_GT(out.z, 0);
+
+    corners.clear(); pts2d.clear();
+    pts2d.push_back(cv::Point2f(38.4f, 204.5f));
+    pts2d.push_back(cv::Point2f(40.0f, 124.7f));
+    pts2d.push_back(cv::Point2f(102.0f, 119.1f));
+    pts2d.push_back(cv::Point2f(99.9f, 203.6f));
+    corners.push_back(pts2d);
+    pts2d.clear();
+    pts2d.push_back(cv::Point2f(476.0f, 184.3f));
+    pts2d.push_back(cv::Point2f(479.2f, 75.1f));
+    pts2d.push_back(cv::Point2f(588.7f, 79.2f));
+    pts2d.push_back(cv::Point2f(586.3f, 188.5f));
+    corners.push_back(pts2d);
+
+    nUsed = cv::aruco::estimatePoseBoard(corners, board.ids, boardPtr, cameraMatrix, Mat(), rvec, tvec);
+    ASSERT_EQ(nUsed, 2);
+
+    cv::Rodrigues(rvec, rotm);
+    out = cv::Point3d(tvec) + rotm*Point3d(board.objPoints[0][0]);
+    ASSERT_GT(out.z, 0);
+}
diff --git a/contrib/modules/aruco/test/test_charucodetection.cpp b/contrib/modules/aruco/test/test_charucodetection.cpp
index c8bbc91..1f506ba 100644
--- a/contrib/modules/aruco/test/test_charucodetection.cpp
+++ b/contrib/modules/aruco/test/test_charucodetection.cpp
@@ -98,7 +98,7 @@ static void getSyntheticRT(double yaw, double pitch, double distance, Mat &rvec,
 /**
  * @brief Project a synthetic marker
  */
-static void projectMarker(Mat &img, aruco::Dictionary dictionary, int id,
+static void projectMarker(Mat &img, Ptr<aruco::Dictionary> dictionary, int id,
                           vector< Point3f > markerObjPoints, Mat cameraMatrix, Mat rvec, Mat tvec,
                           int markerBorder) {
 
@@ -176,7 +176,7 @@ static Mat projectChessboard(int squaresX, int squaresY, float squareSize, Size
 /**
  * @brief Check pose estimation of charuco board
  */
-static Mat projectCharucoBoard(aruco::CharucoBoard board, Mat cameraMatrix, double yaw,
+static Mat projectCharucoBoard(Ptr<aruco::CharucoBoard> &board, Mat cameraMatrix, double yaw,
                                double pitch, double distance, Size imageSize, int markerBorder,
                                Mat &rvec, Mat &tvec) {
 
@@ -184,15 +184,15 @@ static Mat projectCharucoBoard(aruco::CharucoBoard board, Mat cameraMatrix, doub
 
     // project markers
     Mat img = Mat(imageSize, CV_8UC1, Scalar::all(255));
-    for(unsigned int m = 0; m < board.ids.size(); m++) {
-        projectMarker(img, board.dictionary, board.ids[m], board.objPoints[m], cameraMatrix, rvec,
+    for(unsigned int m = 0; m < board->ids.size(); m++) {
+        projectMarker(img, board->dictionary, board->ids[m], board->objPoints[m], cameraMatrix, rvec,
                       tvec, markerBorder);
     }
 
     // project chessboard
     Mat chessboard =
-        projectChessboard(board.getChessboardSize().width, board.getChessboardSize().height,
-                          board.getSquareLength(), imageSize, cameraMatrix, rvec, tvec);
+        projectChessboard(board->getChessboardSize().width, board->getChessboardSize().height,
+                          board->getSquareLength(), imageSize, cameraMatrix, rvec, tvec);
 
     for(unsigned int i = 0; i < chessboard.total(); i++) {
         if(chessboard.ptr< unsigned char >()[i] == 0) {
@@ -226,8 +226,8 @@ void CV_CharucoDetection::run(int) {
     int iter = 0;
     Mat cameraMatrix = Mat::eye(3, 3, CV_64FC1);
     Size imgSize(500, 500);
-    aruco::Dictionary dictionary = aruco::getPredefinedDictionary(aruco::DICT_6X6_250);
-    aruco::CharucoBoard board = aruco::CharucoBoard::create(4, 4, 0.03f, 0.015f, dictionary);
+    Ptr<aruco::Dictionary> dictionary = aruco::getPredefinedDictionary(aruco::DICT_6X6_250);
+    Ptr<aruco::CharucoBoard> board = aruco::CharucoBoard::create(4, 4, 0.03f, 0.015f, dictionary);
 
     cameraMatrix.at< double >(0, 0) = cameraMatrix.at< double >(1, 1) = 650;
     cameraMatrix.at< double >(0, 2) = imgSize.width / 2;
@@ -251,9 +251,9 @@ void CV_CharucoDetection::run(int) {
                 // detect markers
                 vector< vector< Point2f > > corners;
                 vector< int > ids;
-                aruco::DetectorParameters params;
-                params.minDistanceToBorder = 3;
-                params.markerBorderBits = markerBorder;
+                Ptr<aruco::DetectorParameters> params = aruco::DetectorParameters::create();
+                params->minDistanceToBorder = 3;
+                params->markerBorderBits = markerBorder;
                 aruco::detectMarkers(img, dictionary, corners, ids, params);
 
                 if(ids.size() == 0) {
@@ -276,14 +276,14 @@ void CV_CharucoDetection::run(int) {
 
                 // check results
                 vector< Point2f > projectedCharucoCorners;
-                projectPoints(board.chessboardCorners, rvec, tvec, cameraMatrix, distCoeffs,
+                projectPoints(board->chessboardCorners, rvec, tvec, cameraMatrix, distCoeffs,
                               projectedCharucoCorners);
 
                 for(unsigned int i = 0; i < charucoIds.size(); i++) {
 
                     int currentId = charucoIds[i];
 
-                    if(currentId >= (int)board.chessboardCorners.size()) {
+                    if(currentId >= (int)board->chessboardCorners.size()) {
                         ts->printf(cvtest::TS::LOG, "Invalid Charuco corner id");
                         ts->set_failed_test_info(cvtest::TS::FAIL_MISMATCH);
                         return;
@@ -325,8 +325,8 @@ void CV_CharucoPoseEstimation::run(int) {
     int iter = 0;
     Mat cameraMatrix = Mat::eye(3, 3, CV_64FC1);
     Size imgSize(500, 500);
-    aruco::Dictionary dictionary = aruco::getPredefinedDictionary(aruco::DICT_6X6_250);
-    aruco::CharucoBoard board = aruco::CharucoBoard::create(4, 4, 0.03f, 0.015f, dictionary);
+    Ptr<aruco::Dictionary> dictionary = aruco::getPredefinedDictionary(aruco::DICT_6X6_250);
+    Ptr<aruco::CharucoBoard> board = aruco::CharucoBoard::create(4, 4, 0.03f, 0.015f, dictionary);
 
     cameraMatrix.at< double >(0, 0) = cameraMatrix.at< double >(1, 1) = 650;
     cameraMatrix.at< double >(0, 2) = imgSize.width / 2;
@@ -349,9 +349,9 @@ void CV_CharucoPoseEstimation::run(int) {
                 // detect markers
                 vector< vector< Point2f > > corners;
                 vector< int > ids;
-                aruco::DetectorParameters params;
-                params.minDistanceToBorder = 3;
-                params.markerBorderBits = markerBorder;
+                Ptr<aruco::DetectorParameters> params = aruco::DetectorParameters::create();
+                params->minDistanceToBorder = 3;
+                params->markerBorderBits = markerBorder;
                 aruco::detectMarkers(img, dictionary, corners, ids, params);
 
                 if(ids.size() == 0) {
@@ -381,14 +381,14 @@ void CV_CharucoPoseEstimation::run(int) {
 
                 // check result
                 vector< Point2f > projectedCharucoCorners;
-                projectPoints(board.chessboardCorners, rvec, tvec, cameraMatrix, distCoeffs,
+                projectPoints(board->chessboardCorners, rvec, tvec, cameraMatrix, distCoeffs,
                               projectedCharucoCorners);
 
                 for(unsigned int i = 0; i < charucoIds.size(); i++) {
 
                     int currentId = charucoIds[i];
 
-                    if(currentId >= (int)board.chessboardCorners.size()) {
+                    if(currentId >= (int)board->chessboardCorners.size()) {
                         ts->printf(cvtest::TS::LOG, "Invalid Charuco corner id");
                         ts->set_failed_test_info(cvtest::TS::FAIL_MISMATCH);
                         return;
@@ -429,10 +429,10 @@ void CV_CharucoDiamondDetection::run(int) {
     int iter = 0;
     Mat cameraMatrix = Mat::eye(3, 3, CV_64FC1);
     Size imgSize(500, 500);
-    aruco::Dictionary dictionary = aruco::getPredefinedDictionary(aruco::DICT_6X6_250);
+    Ptr<aruco::Dictionary> dictionary = aruco::getPredefinedDictionary(aruco::DICT_6X6_250);
     float squareLength = 0.03f;
     float markerLength = 0.015f;
-    aruco::CharucoBoard board =
+    Ptr<aruco::CharucoBoard> board =
         aruco::CharucoBoard::create(3, 3, squareLength, markerLength, dictionary);
 
     cameraMatrix.at< double >(0, 0) = cameraMatrix.at< double >(1, 1) = 650;
@@ -447,7 +447,7 @@ void CV_CharucoDiamondDetection::run(int) {
 
                 int markerBorder = iter % 2 + 1;
                 for(int i = 0; i < 4; i++)
-                    board.ids[i] = 4 * iter + i;
+                    board->ids[i] = 4 * iter + i;
                 iter++;
 
                 // get synthetic image
@@ -458,9 +458,9 @@ void CV_CharucoDiamondDetection::run(int) {
                 // detect markers
                 vector< vector< Point2f > > corners;
                 vector< int > ids;
-                aruco::DetectorParameters params;
-                params.minDistanceToBorder = 0;
-                params.markerBorderBits = markerBorder;
+                Ptr<aruco::DetectorParameters> params = aruco::DetectorParameters::create();
+                params->minDistanceToBorder = 0;
+                params->markerBorderBits = markerBorder;
                 aruco::detectMarkers(img, dictionary, corners, ids, params);
 
                 if(ids.size() != 4) {
@@ -483,7 +483,7 @@ void CV_CharucoDiamondDetection::run(int) {
                 }
 
                 for(int i = 0; i < 4; i++) {
-                    if(diamondIds[0][i] != board.ids[i]) {
+                    if(diamondIds[0][i] != board->ids[i]) {
                         ts->printf(cvtest::TS::LOG, "Incorrect diamond ids");
                         ts->set_failed_test_info(cvtest::TS::FAIL_MISMATCH);
                         return;
@@ -492,7 +492,7 @@ void CV_CharucoDiamondDetection::run(int) {
 
 
                 vector< Point2f > projectedDiamondCorners;
-                projectPoints(board.chessboardCorners, rvec, tvec, cameraMatrix, distCoeffs,
+                projectPoints(board->chessboardCorners, rvec, tvec, cameraMatrix, distCoeffs,
                               projectedDiamondCorners);
 
                 vector< Point2f > projectedDiamondCornersReorder(4);
diff --git a/contrib/modules/aruco/tutorials/aruco_board_detection/aruco_board_detection.markdown b/contrib/modules/aruco/tutorials/aruco_board_detection/aruco_board_detection.markdown
index 279bc32..c4eeb40 100644
--- a/contrib/modules/aruco/tutorials/aruco_board_detection/aruco_board_detection.markdown
+++ b/contrib/modules/aruco/tutorials/aruco_board_detection/aruco_board_detection.markdown
@@ -74,7 +74,7 @@ The parameters of estimatePoseBoard are:
 - ```markerCorners``` and ```markerIds```: structures of detected markers from ```detectMarkers()``` function.
 - ```board```: the ```Board``` object that defines the board layout and its ids
 - ```cameraMatrix``` and ```distCoeffs```: camera calibration parameters necessary for pose estimation.
-- ```rvec``` and ```tvec```: estimated pose of the Board.
+- ```rvec``` and ```tvec```: estimated pose of the Board. If not empty then treated as initial guess.
 - The function returns the total number of markers employed for estimating the board pose. Note that not all the
  markers provided in ```markerCorners``` and ```markerIds``` should be used, since only the markers whose ids are
 listed in the ```Board::ids``` structure are considered.
@@ -155,6 +155,11 @@ The output image will be something like this:
 
 A full working example of board creation is included in the ```create_board.cpp``` inside the module samples folder.
 
+Note: The samples now take input via commandline via the [OpenCV Commandline Parser](http://docs.opencv.org/trunk/d0/d2e/classcv_1_1CommandLineParser.html#gsc.tab=0). For this file the example parameters will look like
+``` c++
+    "_output path_/aboard.png" -w=5 -h=7 -l=100 -s=10 -d=10
+```
+
 Finally, a full example of board detection:
 
 ``` c++
@@ -198,10 +203,18 @@ Finally, a full example of board detection:
 
 Sample video:
 
-[![Board Detection video](http://img.youtube.com/vi/Q1HlJEjW_j0/0.jpg)](https://youtu.be/Q1HlJEjW_j0)
+ at htmlonly
+<iframe width="420" height="315" src="https://www.youtube.com/embed/Q1HlJEjW_j0" frameborder="0" allowfullscreen></iframe>
+ at endhtmlonly
 
 A full working example is included in the ```detect_board.cpp``` inside the module samples folder.
 
+Note: The samples now take input via commandline via the [OpenCV Commandline Parser](http://docs.opencv.org/trunk/d0/d2e/classcv_1_1CommandLineParser.html#gsc.tab=0). For this file the example parameters will look like
+``` c++
+    -c="_path_"/calib.txt" "_path_/aboard.png" -w=5 -h=7 -l=100 -s=10 -d=10
+```
+
+
 
 Refine marker detection
 -----
diff --git a/contrib/modules/aruco/tutorials/aruco_board_detection/images/board.jpg b/contrib/modules/aruco/tutorials/aruco_board_detection/images/board.jpg
index 2edc06f..0f2c25b 100644
Binary files a/contrib/modules/aruco/tutorials/aruco_board_detection/images/board.jpg and b/contrib/modules/aruco/tutorials/aruco_board_detection/images/board.jpg differ
diff --git a/contrib/modules/aruco/tutorials/aruco_calibration/aruco_calibration.markdown b/contrib/modules/aruco/tutorials/aruco_calibration/aruco_calibration.markdown
index 4c3d726..e9f6e36 100644
--- a/contrib/modules/aruco/tutorials/aruco_calibration/aruco_calibration.markdown
+++ b/contrib/modules/aruco/tutorials/aruco_calibration/aruco_calibration.markdown
@@ -61,6 +61,11 @@ Finally, the ```calibrationFlags``` parameter determines some of the options for
 
 A full working example is included in the ```calibrate_camera_charuco.cpp``` inside the module samples folder.
 
+Note: The samples now take input via commandline via the [OpenCV Commandline Parser](http://docs.opencv.org/trunk/d0/d2e/classcv_1_1CommandLineParser.html#gsc.tab=0). For this file the example parameters will look like
+``` c++
+    _output path_" -dp="_path_/detector_params.yml" -w=5 -h=7 -sl=0.04 -ml=0.02 -d=10
+```
+
 
 
 Calibration with ArUco Boards
@@ -100,3 +105,8 @@ The rest of parameters are the same than in ```calibrateCameraCharuco()```, exce
 any ```Board``` object.
 
 A full working example is included in the ```calibrate_camera.cpp``` inside the module samples folder.
+
+Note: The samples now take input via commandline via the [OpenCV Commandline Parser](http://docs.opencv.org/trunk/d0/d2e/classcv_1_1CommandLineParser.html#gsc.tab=0). For this file the example parameters will look like
+``` c++
+    "_path_/calib.txt" -w=5 -h=7 -l=100 -s=10 -d=10
+```
diff --git a/contrib/modules/aruco/tutorials/aruco_detection/aruco_detection.markdown b/contrib/modules/aruco/tutorials/aruco_detection/aruco_detection.markdown
index c3e197f..4ebda3e 100644
--- a/contrib/modules/aruco/tutorials/aruco_detection/aruco_detection.markdown
+++ b/contrib/modules/aruco/tutorials/aruco_detection/aruco_detection.markdown
@@ -103,6 +103,10 @@ The generated image is:
 
 A full working example is included in the ```create_marker.cpp``` inside the module samples folder.
 
+Note: The samples now take input via commandline via the [OpenCV Commandline Parser](http://docs.opencv.org/trunk/d0/d2e/classcv_1_1CommandLineParser.html#gsc.tab=0). For this file the example parameters will look like
+``` c++
+    "/Users/Sarthak/Dropbox/OpenCV_GSoC/marker.png" -d=10 -id=1
+```
 
 Marker Detection
 ------
@@ -226,6 +230,11 @@ output vector of rejected candidates.
 
 A full working example is included in the ```detect_markers.cpp``` inside the module samples folder.
 
+Note: The samples now take input via commandline via the [OpenCV Commandline Parser](http://docs.opencv.org/trunk/d0/d2e/classcv_1_1CommandLineParser.html#gsc.tab=0). For this file the example parameters will look like
+``` c++
+    -c="_path_/calib.txt" -d=10
+```
+
 
 
 Pose Estimation
@@ -325,10 +334,18 @@ A basic full example for pose estimation from single markers:
 
 Sample video:
 
-[![ArUco markers detection video](http://img.youtube.com/vi/IsXWrcB_Hvs/0.jpg)](https://youtu.be/IsXWrcB_Hvs)
+ at htmlonly
+<iframe width="420" height="315" src="https://www.youtube.com/embed/IsXWrcB_Hvs" frameborder="0" allowfullscreen></iframe>
+ at endhtmlonly
 
 A full working example is included in the ```detect_markers.cpp``` inside the module samples folder.
 
+Note: The samples now take input via commandline via the [OpenCV Commandline Parser](http://docs.opencv.org/trunk/d0/d2e/classcv_1_1CommandLineParser.html#gsc.tab=0). For this file the example parameters will look like
+``` c++
+    -c="_path_/calib.txt" -d=10
+```
+
+
 
 Selecting a dictionary
 ------
diff --git a/contrib/modules/aruco/tutorials/aruco_detection/images/marker23.jpg b/contrib/modules/aruco/tutorials/aruco_detection/images/marker23.jpg
index 4e9addd..c2de747 100644
Binary files a/contrib/modules/aruco/tutorials/aruco_detection/images/marker23.jpg and b/contrib/modules/aruco/tutorials/aruco_detection/images/marker23.jpg differ
diff --git a/contrib/modules/aruco/tutorials/charuco_detection/charuco_detection.markdown b/contrib/modules/aruco/tutorials/charuco_detection/charuco_detection.markdown
index 65ffefc..1d66970 100644
--- a/contrib/modules/aruco/tutorials/charuco_detection/charuco_detection.markdown
+++ b/contrib/modules/aruco/tutorials/charuco_detection/charuco_detection.markdown
@@ -78,6 +78,11 @@ The output image will be something like this:
 
 A full working example is included in the ```create_board_charuco.cpp``` inside the module samples folder.
 
+Note: The samples now take input via commandline via the [OpenCV Commandline Parser](http://docs.opencv.org/trunk/d0/d2e/classcv_1_1CommandLineParser.html#gsc.tab=0). For this file the example parameters will look like
+``` c++
+    "_ output path_/chboard.png" -w=5 -h=7 -sl=200 -ml=120 -d=10
+```
+
 
 ChArUco Board Detection
 ------
@@ -234,10 +239,17 @@ Finally, this is a full example of ChArUco detection (without using calibration
 
 Sample video:
 
-[![ChArUco board detection video](http://img.youtube.com/vi/Nj44m_N_9FY/0.jpg)](https://youtu.be/Nj44m_N_9FY)
+ at htmlonly
+<iframe width="420" height="315" src="https://www.youtube.com/embed/Nj44m_N_9FY" frameborder="0" allowfullscreen></iframe>
+ at endhtmlonly
 
 A full working example is included in the ```detect_board_charuco.cpp``` inside the module samples folder.
 
+Note: The samples now take input via commandline via the [OpenCV Commandline Parser](http://docs.opencv.org/trunk/d0/d2e/classcv_1_1CommandLineParser.html#gsc.tab=0). For this file the example parameters will look like
+``` c++
+    -c="_path_/calib.txt" -dp="_path_/detector_params.yml" -w=5 -h=7 -sl=0.04 -ml=0.02 -d=10
+```
+
 ChArUco Pose Estimation
 ------
 
@@ -310,3 +322,8 @@ A full example of ChArUco detection with pose estimation:
 ```
 
 A full working example is included in the ```detect_board_charuco.cpp``` inside the module samples folder.
+
+Note: The samples now take input via commandline via the [OpenCV Commandline Parser](http://docs.opencv.org/trunk/d0/d2e/classcv_1_1CommandLineParser.html#gsc.tab=0). For this file the example parameters will look like
+``` c++
+    "_path_/calib.txt" -dp="_path_/detector_params.yml" -w=5 -h=7 -sl=0.04 -ml=0.02 -d=10
+```
diff --git a/contrib/modules/aruco/tutorials/charuco_detection/images/board.jpg b/contrib/modules/aruco/tutorials/charuco_detection/images/board.jpg
new file mode 100644
index 0000000..eda7c86
Binary files /dev/null and b/contrib/modules/aruco/tutorials/charuco_detection/images/board.jpg differ
diff --git a/contrib/modules/aruco/tutorials/charuco_detection/images/charucoboard.jpg b/contrib/modules/aruco/tutorials/charuco_detection/images/charucoboard.jpg
deleted file mode 100644
index c0e7a85..0000000
Binary files a/contrib/modules/aruco/tutorials/charuco_detection/images/charucoboard.jpg and /dev/null differ
diff --git a/contrib/modules/aruco/tutorials/charuco_diamond_detection/charuco_diamond_detection.markdown b/contrib/modules/aruco/tutorials/charuco_diamond_detection/charuco_diamond_detection.markdown
index e1212f8..9f56cc2 100644
--- a/contrib/modules/aruco/tutorials/charuco_diamond_detection/charuco_diamond_detection.markdown
+++ b/contrib/modules/aruco/tutorials/charuco_diamond_detection/charuco_diamond_detection.markdown
@@ -60,6 +60,10 @@ The image produced will be:
 
 A full working example is included in the ```create_diamond.cpp``` inside the module samples folder.
 
+Note: The samples now take input via commandline via the [OpenCV Commandline Parser](http://docs.opencv.org/trunk/d0/d2e/classcv_1_1CommandLineParser.html#gsc.tab=0). For this file the example parameters will look like
+``` c++
+    "_path_/mydiamond.png" -sl=200 -ml=120 -d=10 -ids=45,68,28,74
+```
 
 ChArUco Diamond Detection
 ------
@@ -116,6 +120,10 @@ The result is the same that the one produced by ```drawDetectedMarkers()```, but
 
 A full working example is included in the ```detect_diamonds.cpp``` inside the module samples folder.
 
+Note: The samples now take input via commandline via the [OpenCV Commandline Parser](http://docs.opencv.org/trunk/d0/d2e/classcv_1_1CommandLineParser.html#gsc.tab=0). For this file the example parameters will look like
+``` c++
+    -c="_path_/calib.txt" -dp="_path_/detector_params.yml" -sl=0.04 -ml=0.02 -d=10
+```
 
 ChArUco Diamond Pose Estimation
 ------
@@ -154,6 +162,13 @@ as in a simple ArUco marker pose estimation.
 
 Sample video:
 
-[![Diamond markers detection video](http://img.youtube.com/vi/OqKpBnglH7k/0.jpg)](https://youtu.be/OqKpBnglH7k)
+ at htmlonly
+<iframe width="420" height="315" src="https://www.youtube.com/embed/OqKpBnglH7k" frameborder="0" allowfullscreen></iframe>
+ at endhtmlonly
 
 A full working example is included in the ```detect_diamonds.cpp``` inside the module samples folder.
+
+Note: The samples now take input via commandline via the [OpenCV Commandline Parser](http://docs.opencv.org/trunk/d0/d2e/classcv_1_1CommandLineParser.html#gsc.tab=0). For this file the example parameters will look like
+``` c++
+    -c="_output path_/calib.txt" -dp="_path_/detector_params.yml" -sl=0.04 -ml=0.02 -d=10
+```
diff --git a/contrib/modules/bioinspired/include/opencv2/bioinspired/retina.hpp b/contrib/modules/bioinspired/include/opencv2/bioinspired/retina.hpp
index 4ed6f3a..e531614 100644
--- a/contrib/modules/bioinspired/include/opencv2/bioinspired/retina.hpp
+++ b/contrib/modules/bioinspired/include/opencv2/bioinspired/retina.hpp
@@ -226,8 +226,9 @@ public:
     - warning, Exceptions are thrown if read XML file is not valid
     @param retinaParameterFile the parameters filename
     @param applyDefaultSetupOnFailure set to true if an error must be thrown on error
-    You can retreive the current parameers structure using method Retina::getParameters and update
-    it before running method Retina::setup
+
+    You can retrieve the current parameters structure using the method Retina::getParameters and update
+    it before running method Retina::setup.
      */
     CV_WRAP virtual void setup(String retinaParameterFile="", const bool applyDefaultSetupOnFailure=true)=0;
 
diff --git a/contrib/modules/bioinspired/src/opencl/retina_kernel.cl b/contrib/modules/bioinspired/src/opencl/retina_kernel.cl
index 169be4d..02b7a83 100644
--- a/contrib/modules/bioinspired/src/opencl/retina_kernel.cl
+++ b/contrib/modules/bioinspired/src/opencl/retina_kernel.cl
@@ -47,7 +47,7 @@
 #define WIDTH_MULTIPLE (32 >> 2)
 
 /////////////////////////////////////////////////////////
-//*******************************************************
+//------------------------------------------------------
 // basicretinafilter
 //////////////// _spatiotemporalLPfilter ////////////////
 //_horizontalCausalFilter_addInput
@@ -380,13 +380,13 @@ kernel void localLuminanceAdaptation(
     output[offset] = (_maxInputValue + X0) * input_val / (input_val + X0 + 0.00000000001f);
 }
 // end of basicretinafilter
-//*******************************************************
+//------------------------------------------------------
 /////////////////////////////////////////////////////////
 
 
 
 /////////////////////////////////////////////////////////
-//******************************************************
+//------------------------------------------------------
 // magno
 // TODO: this kernel has too many buffer accesses, better to make it
 //   vector read/write for fetch efficiency
@@ -427,7 +427,7 @@ kernel void amacrineCellsComputing(
 }
 
 /////////////////////////////////////////////////////////
-//******************************************************
+//------------------------------------------------------
 // parvo
 // TODO: this kernel has too many buffer accesses, needs optimization
 kernel void OPL_OnOffWaysComputing(
@@ -473,7 +473,7 @@ kernel void OPL_OnOffWaysComputing(
 }
 
 /////////////////////////////////////////////////////////
-//******************************************************
+//------------------------------------------------------
 // retinacolor
 inline int bayerSampleOffset(int step, int rows, int x, int y)
 {
diff --git a/contrib/modules/bioinspired/src/retina.cpp b/contrib/modules/bioinspired/src/retina.cpp
index 9bd37a1..1e518f8 100644
--- a/contrib/modules/bioinspired/src/retina.cpp
+++ b/contrib/modules/bioinspired/src/retina.cpp
@@ -86,18 +86,18 @@ public:
      * Main constructor with most commun use setup : create an instance of color ready retina model
      * @param inputSize : the input frame size
      */
-    RetinaImpl(Size inputSize);
+    RetinaImpl(const Size inputSize);
 
     /**
      * Complete Retina filter constructor which allows all basic structural parameters definition
-         * @param inputSize : the input frame size
+     * @param inputSize : the input frame size
      * @param colorMode : the chosen processing mode : with or without color processing
      * @param colorSamplingMethod: specifies which kind of color sampling will be used
      * @param useRetinaLogSampling: activate retina log sampling, if true, the 2 following parameters can be used
      * @param reductionFactor: only usefull if param useRetinaLogSampling=true, specifies the reduction factor of the output frame (as the center (fovea) is high resolution and corners can be underscaled, then a reduction of the output is allowed without precision leak
      * @param samplingStrenght: only usefull if param useRetinaLogSampling=true, specifies the strenght of the log scale that is applied
      */
-    RetinaImpl(Size inputSize, const bool colorMode, int colorSamplingMethod=RETINA_COLOR_BAYER, const bool useRetinaLogSampling=false, const float reductionFactor=1.0f, const float samplingStrenght=10.0f);
+    RetinaImpl(const Size inputSize, const bool colorMode, int colorSamplingMethod=RETINA_COLOR_BAYER, const bool useRetinaLogSampling=false, const float reductionFactor=1.0f, const float samplingStrenght=10.0f);
 
     virtual ~RetinaImpl();
     /**
@@ -115,7 +115,7 @@ public:
      * => if the xml file does not exist, then default setup is applied
      * => warning, Exceptions are thrown if read XML file is not valid
      * @param retinaParameterFile : the parameters filename
-         * @param applyDefaultSetupOnFailure : set to true if an error must be thrown on error
+     * @param applyDefaultSetupOnFailure : set to true if an error must be thrown on error
      */
     void setup(String retinaParameterFile="", const bool applyDefaultSetupOnFailure=true);
 
@@ -125,7 +125,7 @@ public:
      * => if the xml file does not exist, then default setup is applied
      * => warning, Exceptions are thrown if read XML file is not valid
      * @param fs : the open Filestorage which contains retina parameters
-         * @param applyDefaultSetupOnFailure : set to true if an error must be thrown on error
+     * @param applyDefaultSetupOnFailure : set to true if an error must be thrown on error
      */
     void setup(cv::FileStorage &fs, const bool applyDefaultSetupOnFailure=true);
 
@@ -134,7 +134,7 @@ public:
      * => if the xml file does not exist, then default setup is applied
      * => warning, Exceptions are thrown if read XML file is not valid
      * @param newParameters : a parameters structures updated with the new target configuration
-         * @param applyDefaultSetupOnFailure : set to true if an error must be thrown on error
+     * @param applyDefaultSetupOnFailure : set to true if an error must be thrown on error
      */
     void setup(RetinaParameters newParameters);
 
@@ -411,9 +411,6 @@ void RetinaImpl::setup(cv::FileStorage &fs, const bool applyDefaultSetupOnFailur
         printf("Retina::setup: wrong/unappropriate xml parameter file : error report :`n=>%s\n", e.what());
         printf("=> keeping current parameters\n");
     }
-
-    // report current configuration
-    printf("%s\n", printSetup().c_str());
 }
 
 void RetinaImpl::setup(RetinaParameters newConfiguration)
@@ -615,7 +612,7 @@ const Mat RetinaImpl::getParvoRAW() const {
     return Mat((int)_retinaFilter->getContours().size(), 1, CV_32F, (void*)get_data(_retinaFilter->getContours()));
 }
 
-// private method called by constructirs
+// private method called by constructors
 void RetinaImpl::_init(const cv::Size inputSz, const bool colorMode, int colorSamplingMethod, const bool useRetinaLogSampling, const float reductionFactor, const float samplingStrenght)
 {
     // basic error check
@@ -637,9 +634,6 @@ void RetinaImpl::_init(const cv::Size inputSz, const bool colorMode, int colorSa
 
     // init retina
     _retinaFilter->clearAllBuffers();
-
-    // report current configuration
-    printf("%s\n", printSetup().c_str());
 }
 
 void RetinaImpl::_convertValarrayBuffer2cvMat(const std::valarray<float> &grayMatrixToConvert, const unsigned int nbRows, const unsigned int nbColumns, const bool colorMode, OutputArray outBuffer)
diff --git a/contrib/modules/bioinspired/src/transientareassegmentationmodule.cpp b/contrib/modules/bioinspired/src/transientareassegmentationmodule.cpp
index 185cc11..45e41fe 100644
--- a/contrib/modules/bioinspired/src/transientareassegmentationmodule.cpp
+++ b/contrib/modules/bioinspired/src/transientareassegmentationmodule.cpp
@@ -86,8 +86,7 @@ namespace cv
 namespace bioinspired
 {
 
-class TransientAreasSegmentationModuleImpl :
-	protected BasicRetinaFilter
+class TransientAreasSegmentationModuleImpl : protected BasicRetinaFilter
 {
 public:
 
@@ -105,7 +104,7 @@ public:
     /**
      * @return the size of the manage input and output images
      */
-    Size getSize(){return cv::Size(getNBcolumns(), getNBrows());};
+    Size getSize(){return cv::Size(getNBcolumns(), getNBrows());}
 
     /**
      * try to open an XML segmentation parameters file to adjust current segmentation instance setup
@@ -189,19 +188,19 @@ protected:
      * access function
      * @return the local motion energy level picture (experimental, not usefull)
      */
-    inline const std::valarray<float> &getLocalMotionPicture() const {return _localMotion;};
+    inline const std::valarray<float> &getLocalMotionPicture() const {return _localMotion;}
 
     /**
      * access function
      * @return the neighborhood motion energy level picture (experimental, not usefull)
      */
-    inline const std::valarray<float> &getNeighborhoodMotionPicture() const {return _neighborhoodMotion;};
+    inline const std::valarray<float> &getNeighborhoodMotionPicture() const {return _neighborhoodMotion;}
 
     /**
      * access function
      * @return the motion energy context level picture (experimental, not usefull)
      */
-    inline const std::valarray<float> &getMotionContextPicture() const {return _contextMotionEnergy;};
+    inline const std::valarray<float> &getMotionContextPicture() const {return _contextMotionEnergy;}
 
     struct cv::bioinspired::SegmentationParameters _segmentationParameters;
     // template buffers and related acess pointers
@@ -220,25 +219,25 @@ protected:
     // Buffer conversion utilities
     void _convertValarrayBuffer2cvMat(const std::valarray<bool> &grayMatrixToConvert, const unsigned int nbRows, const unsigned int nbColumns, OutputArray outBuffer);
     bool _convertCvMat2ValarrayBuffer(InputArray inputMat, std::valarray<float> &outputValarrayMatrix);
-	
+
     const TransientAreasSegmentationModuleImpl & operator = (const TransientAreasSegmentationModuleImpl &);
 };
 
 class TransientAreasSegmentationModuleImpl_: public  TransientAreasSegmentationModule
 {
 public:
-	TransientAreasSegmentationModuleImpl_(const Size size):_segmTool(size){};
-    inline virtual Size getSize(){return _segmTool.getSize();};
-    inline virtual void write( cv::FileStorage& fs ) const{_segmTool.write(fs);};
-    inline virtual void setup(String segmentationParameterFile, const bool applyDefaultSetupOnFailure){_segmTool.setup(segmentationParameterFile, applyDefaultSetupOnFailure);};
-    inline virtual void setup(cv::FileStorage &fs, const bool applyDefaultSetupOnFailure){_segmTool.setup(fs, applyDefaultSetupOnFailure);};
-    inline virtual void setup(SegmentationParameters newParameters){_segmTool.setup(newParameters);};
-    inline virtual const String printSetup(){return _segmTool.printSetup();};
-    inline virtual struct SegmentationParameters getParameters(){return _segmTool.getParameters();};
-    inline virtual void write( String fs ) const{_segmTool.write(fs);};
-    inline virtual void run(InputArray inputToSegment, const int channelIndex){_segmTool.run(inputToSegment, channelIndex);};
-    inline virtual void getSegmentationPicture(OutputArray transientAreas){return _segmTool.getSegmentationPicture(transientAreas);};
-    inline virtual void clearAllBuffers(){_segmTool.clearAllBuffers();};
+    TransientAreasSegmentationModuleImpl_(const Size size):_segmTool(size){}
+    inline virtual Size getSize(){return _segmTool.getSize();}
+    inline virtual void write( cv::FileStorage& fs ) const{_segmTool.write(fs);}
+    inline virtual void setup(String segmentationParameterFile, const bool applyDefaultSetupOnFailure){_segmTool.setup(segmentationParameterFile, applyDefaultSetupOnFailure);}
+    inline virtual void setup(cv::FileStorage &fs, const bool applyDefaultSetupOnFailure){_segmTool.setup(fs, applyDefaultSetupOnFailure);}
+    inline virtual void setup(SegmentationParameters newParameters){_segmTool.setup(newParameters);}
+    inline virtual const String printSetup(){return _segmTool.printSetup();}
+    inline virtual struct SegmentationParameters getParameters(){return _segmTool.getParameters();}
+    inline virtual void write( String fs ) const{_segmTool.write(fs);}
+    inline virtual void run(InputArray inputToSegment, const int channelIndex){_segmTool.run(inputToSegment, channelIndex);}
+    inline virtual void getSegmentationPicture(OutputArray transientAreas){return _segmTool.getSegmentationPicture(transientAreas);}
+    inline virtual void clearAllBuffers(){_segmTool.clearAllBuffers();}
 
 private:
     TransientAreasSegmentationModuleImpl _segmTool;
@@ -250,7 +249,7 @@ private:
 */
 Ptr<TransientAreasSegmentationModule> createTransientAreasSegmentationModule(Size inputSize){
     return makePtr<TransientAreasSegmentationModuleImpl_>(inputSize);
-};
+}
 
 // Constructor and destructors
 TransientAreasSegmentationModuleImpl::TransientAreasSegmentationModuleImpl(const Size size)
@@ -288,8 +287,8 @@ void TransientAreasSegmentationModuleImpl::clearAllBuffers()
 
 struct SegmentationParameters TransientAreasSegmentationModuleImpl::getParameters()
 {
-	return _segmentationParameters;
-};
+    return _segmentationParameters;
+}
 
 // setup from XML file
 void TransientAreasSegmentationModuleImpl::setup(String segmentationParameterFile, const bool applyDefaultSetupOnFailure)
@@ -350,9 +349,6 @@ void TransientAreasSegmentationModuleImpl::setup(cv::FileStorage &fs, const bool
         std::cout<<"SegmentationModule::setup: wrong/unappropriate xml parameter file : error report :`n=>"<<e.what()<<std::endl;
         std::cout<<"=> keeping current parameters"<<std::endl;
     }
-
-    // report current configuration
-    printf("%s\n", printSetup().c_str());
 }
 
 // setup parameters for the 2 filters that allow the segmentation
@@ -592,9 +588,3 @@ bool TransientAreasSegmentationModuleImpl::_convertCvMat2ValarrayBuffer(InputArr
 }
 
 }} //namespaces end : cv and bioinspired
-
-
-
-
-
-
diff --git a/contrib/modules/bioinspired/tutorials/retina_illusion/images/checkershadow_illusion4med.jpg b/contrib/modules/bioinspired/tutorials/retina_illusion/images/checkershadow_illusion4med.jpg
new file mode 100644
index 0000000..ad6162d
Binary files /dev/null and b/contrib/modules/bioinspired/tutorials/retina_illusion/images/checkershadow_illusion4med.jpg differ
diff --git a/contrib/modules/bioinspired/tutorials/retina_illusion/images/checkershadow_illusion4med_proof.jpg b/contrib/modules/bioinspired/tutorials/retina_illusion/images/checkershadow_illusion4med_proof.jpg
new file mode 100644
index 0000000..f32a4a2
Binary files /dev/null and b/contrib/modules/bioinspired/tutorials/retina_illusion/images/checkershadow_illusion4med_proof.jpg differ
diff --git a/contrib/modules/bioinspired/tutorials/retina_illusion/images/checkershadow_parvo.png b/contrib/modules/bioinspired/tutorials/retina_illusion/images/checkershadow_parvo.png
new file mode 100644
index 0000000..8d4ddb6
Binary files /dev/null and b/contrib/modules/bioinspired/tutorials/retina_illusion/images/checkershadow_parvo.png differ
diff --git a/contrib/modules/bioinspired/tutorials/retina_illusion/images/checkershadow_parvo_proof.png b/contrib/modules/bioinspired/tutorials/retina_illusion/images/checkershadow_parvo_proof.png
new file mode 100644
index 0000000..3180e8a
Binary files /dev/null and b/contrib/modules/bioinspired/tutorials/retina_illusion/images/checkershadow_parvo_proof.png differ
diff --git a/contrib/modules/bioinspired/tutorials/retina_illusion/retina_illusion.markdown b/contrib/modules/bioinspired/tutorials/retina_illusion/retina_illusion.markdown
new file mode 100644
index 0000000..db5f9ed
--- /dev/null
+++ b/contrib/modules/bioinspired/tutorials/retina_illusion/retina_illusion.markdown
@@ -0,0 +1,187 @@
+Processing images causing optical illusions {#tutorial_bioinspired_retina_illusion}
+=============================================================
+
+Goal
+----
+
+I will show here how the bioinspired module can reproduce a well-known optical illusion that
+our eyes perceive in certain light condition: The Adelson checkerboard.
+
+The Adelson checkerboard
+------------------------
+
+Looking at the checkerboard image below, human eyes perceive the "B" square lighter than the
+"A" square, although they are pictured in the very same RGB color.
+Of course in the physical world, checkerboard has a "B" square which is lighter than "A", but in this image the
+shadow of the green cylinder casting over the "B" square ends up in making the "A" and "B"
+squares actually having the same luminance.
+
+![Adelson checkerboard](images/checkershadow_illusion4med.jpg)
+
+Our visual system does "compensate" for the shadow, making us perceive the "B" square lighter,
+as the shadow wouldn't be there. This is due to local adaptation process that is performed in the
+foveal area.
+
+You may find the original Adelson's explanation [here](http://web.mit.edu/persci/people/adelson/checkershadow_description.html).
+
+Proof: You can convince yourself by using an image manipulation program, cutting out a portion
+of the two squares, and looking at them without any background. You can also measure the RGB
+values of the two squares with the picker tool.
+
+In this image I've cropped a little piece of the A and B squares and I've put them side-by-side.
+It should be quite evident they have the same luminance.
+![Adelson checkerboard proof](images/checkershadow_illusion4med_proof.jpg)
+
+It's worth to know that this illusion works because the checkerboard image, as you may see it
+on your laptop, casts on your retina with dimensions that cause the retina local adaptation to take
+into account both the two squares at the same time.
+
+The foveal vision area is something like one inch at one meter (and because your eye moves
+continuously, with the so called "saccades", your brain is able to reconstruct the entire
+color scene in real time). This means that one single letter, either A or B, can hit
+your fovea at any time.
+
+The point is that, even if you can't see both letters at the same time in a single eye fixation,
+when looking at one letter your fovea also takes into account light information from what is around it.
+This means that the fovea actually perceives also the neighboring cells.
+
+The net effect is that when looking at one area, your eye locally adapts to luminance, filters noise,
+enforces contours, etc. considering what *surrounds* this area, and this makes the illusion work. We
+say that *the retina works in a "center surround" manner*.
+
+So, the "A" cell being surrounded by lighter cells can be perceived darker. As a comparison, cell "B" 's
+neighborhood is darker and the cell "B" is then perceived lighter.
+
+Finally, since shadow edges are soft, retina eliminates this information. Then shadows do not disrupt the overall chessboard observation making possible to "confidently being fooled" by the perceived cells luminance.
+
+Reproducing the illusion
+------------------------
+The bioinspired module does mimic (also) the parvocellular retina process, that is our foveal
+vision, and it does reproduce our eyes' local adaptation.
+
+This means we can expect the parvo channel output to really contain luminance values
+similar to those we perceive with our eyes. Specifically, in this case we expect the "B" square
+RGB values to be actually lighter than the "A" ones.
+
+To correctly mimic what our eye does we need opencv to do the local adaptation on the right
+image portion. This means we have to ensure that the opencv's notion of "local" does match with our
+image's dimensions, otherwise the local adaptation wouldn't work as expected.
+
+For this reason we may have to adjust the **hcellsSpatialConstant** parameter (that technically
+specifies the low spatial cut frequency, or slow luminance changes sensitivity) depending by
+the image resolution.
+
+For the image in this tutorial, the default retina parameters should be fine.
+
+In order to feed the image to the bioinspired module, you can use either your own code or
+the *example_bioinspired_retinaDemo* example that comes with the bioinspired module.
+
+Running
+ at code{.sh}
+example_bioinspired_retinaDemo -image checkershadow_illusion4med.jpg
+ at endcode
+
+will cause our image to be processed in both parvocellular and magnocellular channels (we are interested
+just in the first one).
+
+If you choose to use your own code, please note that the parvocellular (and magnocellular)
+channel does require some iterations (frames to be processed) before actually getting steady.
+
+Actually parvo (and magno) channel do cares about temporal information. That is, when you start
+feeding frames, it is similar to you with closed eyes; then you open them and you see the chessboard.
+
+This is a static image but your retina just starts moving to a new context (eyes opening) and
+has to adapt.
+
+While in this transient state the luminance information do matters, and you see more or less
+the absolute luminance values. Absolute luminance is exactly what you need **not** to look at in
+order to reproduce the illusion..
+
+As soon as steady state is reached, you receive more contextual luminance information. Your eyes work
+in a center-surround manner and take into account the neighborhood luminance to evaluate the
+region of interest luminance level. And that's when our illusion comes out !
+
+This is something that you don't need to worry about when you process videos, because you are
+naturally feeding the virtual retina with several frames, but you have to take care of it in
+order to process a single frame.
+
+What you will actually need to do when processing a single frame, and you only need steady state response,
+is to repeatedly feed the retina with the same frame (this is what the example code does), as you
+would do with a still video. Alternatively you can set retina temporal parameters to 0 to get steady state immediately
+(**photoreceptorsTemporalConstant** and **hcellsTemporalConstant** parameters of the xml file); however
+in this case you should be aware that you are now making experiments with something that is
+deliberately less accurate in reproducing the behaviour of a real retina!
+
+Here there is a small fragment of python code we used to process the image. It does 20
+iterations. This is an arbitrary number that we found experimentally to be (more than)
+enough
+
+ at code{.py}
+import cv2
+
+inputImage = cv2.imread('checkershadow_illusion4med.jpg', 1)
+retina = cv2.bioinspired.createRetina((inputImage.shape[1], inputImage.shape[0]))
+
+# the retina object is created with default parameters. If you want to read
+# the parameters from an external XML file, uncomment the next line
+#retina.setup('MyRetinaParameters.xml')
+
+# feed the retina with several frames, in order to reach 'steady' state
+for i in range(20):
+    retina.run(inputImage)
+
+# get our processed image :)
+retinaOut_parvo = retina.getParvo()
+
+# show both the original image and the processed one
+cv2.imshow('image', inputImage)
+cv2.imshow('retina parvo out', retinaOut_parvo)
+
+# wait for a key to be pressed and exit
+cv2.waitKey(0)
+cv2.destroyAllWindows()
+
+# write the output image on a file
+cv2.imwrite('checkershadow_parvo.png', retinaOut_parvo)
+ at endcode
+
+Whatever method you used to process the image, you should end up
+with something like this:
+
+![Parvo output for adelson checkerboard](images/checkershadow_parvo.png)
+
+Analyzing the results
+----------------------
+
+We expected that the "B" pixels in the parvo channel output are lighter than "A" ones.
+
+.. And in fact that is!
+
+Looking at the resulting image might not tell us so much at a first glance: the "B" square looks
+lighter than "A" to our eyes, as it did in the input image. The difference is that, contrarily to
+the input image, now the RGB values of the pixels are actually lighter; note that when looking at
+the output image, we are actually  applying the parvocellular process
+two times: first in the bioinspired module, then in our eyes.
+We can convince ourselves that the illusion appeared
+in the computed image by measuring the squares' luminance with the image manipulation program
+and the picker tool, or by cropping pieces of the squares and putting them side-by-side.
+
+In the following image I cropped a portion of square "A" and a portion of square "B", and I placed
+them side-by-side, as I did for the original Adelson image.
+
+![Illusion reproduced](images/checkershadow_parvo_proof.png)
+
+It should be quite evident that the "B" square is really lighter than the "A" square! Congratulations: you have
+just reproduced the Adelson illusion with the Bioinspired module!
+
+Credits
+-------
+
+I want to thank:
+
+**Alexandre Benoit** - for being so kind of explaining me how this whole thing works, for giving me the
+opportunity of writing this tutorial, and for reviewing it.
+
+**Edward Adelson** - for allowing me to freely use his checkerboard image.
+
+**Antonio Cuni**  - for reviewing this tutorial and for writing the Python code.
\ No newline at end of file
diff --git a/contrib/modules/bioinspired/tutorials/retina_model.markdown b/contrib/modules/bioinspired/tutorials/retina_model.markdown
deleted file mode 100644
index afb337c..0000000
--- a/contrib/modules/bioinspired/tutorials/retina_model.markdown
+++ /dev/null
@@ -1,478 +0,0 @@
-Discovering the human retina and its use for image processing {#tutorial_bioinspired_retina_model}
-=============================================================
-
-Goal
-----
-
-I present here a model of human retina that shows some interesting properties for image
-preprocessing and enhancement. In this tutorial you will learn how to:
-
--   discover the main two channels outing from your retina
--   see the basics to use the retina model
--   discover some parameters tweaks
-
-General overview
-----------------
-
-The proposed model originates from Jeanny Herault's research @cite Herault2010 at
-[Gipsa](http://www.gipsa-lab.inpg.fr). It is involved in image processing applications with
-[Listic](http://www.listic.univ-savoie.fr) (code maintainer and user) lab. This is not a complete
-model but it already present interesting properties that can be involved for enhanced image
-processing experience. The model allows the following human retina properties to be used :
-
--   spectral whitening that has 3 important effects: high spatio-temporal frequency signals
-    canceling (noise), mid-frequencies details enhancement and low frequencies luminance energy
-    reduction. This *all in one* property directly allows visual signals cleaning of classical
-    undesired distortions introduced by image sensors and input luminance range.
--   local logarithmic luminance compression allows details to be enhanced even in low light
-    conditions.
--   decorrelation of the details information (Parvocellular output channel) and transient
-    information (events, motion made available at the Magnocellular output channel).
-
-The first two points are illustrated below :
-
-In the figure below, the OpenEXR image sample *CrissyField.exr*, a High Dynamic Range image is
-shown. In order to make it visible on this web-page, the original input image is linearly rescaled
-to the classical image luminance range [0-255] and is converted to 8bit/channel format. Such strong
-conversion hides many details because of too strong local contrasts. Furthermore, noise energy is
-also strong and pollutes visual information.
-
-![image](images/retina_TreeHdr_small.jpg)
-
-In the following image, applying the ideas proposed in @cite Benoit2010, as your retina does, local
-luminance adaptation, spatial noise removal and spectral whitening work together and transmit
-accurate information on lower range 8bit data channels. On this picture, noise in significantly
-removed, local details hidden by strong luminance contrasts are enhanced. Output image keeps its
-naturalness and visual content is enhanced. Color processing is based on the color
-multiplexing/demultiplexing method proposed in @cite Chaix2007 .
-
-![image](images/retina_TreeHdr_retina.jpg)
-
-*Note :* image sample can be downloaded from the [OpenEXR website](http://www.openexr.com).
-Regarding this demonstration, before retina processing, input image has been linearly rescaled
-within 0-255 keeping its channels float format. 5% of its histogram ends has been cut (mostly
-removes wrong HDR pixels). Check out the sample
-*opencv/samples/cpp/OpenEXRimages_HighDynamicRange_Retina_toneMapping.cpp* for similar
-processing. The following demonstration will only consider classical 8bit/channel images.
-
-The retina model output channels
---------------------------------
-
-The retina model presents two outputs that benefit from the above cited behaviors.
-
--   The first one is called the Parvocellular channel. It is mainly active in the foveal retina area
-    (high resolution central vision with color sensitive photo-receptors), its aim is to provide
-    accurate color vision for visual details remaining static on the retina. On the other hand
-    objects moving on the retina projection are blurred.
--   The second well known channel is the Magnocellular channel. It is mainly active in the retina
-    peripheral vision and send signals related to change events (motion, transient events, etc.).
-    These outing signals also help visual system to focus/center retina on 'transient'/moving areas
-    for more detailed analysis thus improving visual scene context and object classification.
-
-**NOTE :** regarding the proposed model, contrary to the real retina, we apply these two channels on
-the entire input images using the same resolution. This allows enhanced visual details and motion
-information to be extracted on all the considered images... but remember, that these two channels
-are complementary. For example, if Magnocellular channel gives strong energy in an area, then, the
-Parvocellular channel is certainly blurred there since there is a transient event.
-
-As an illustration, we apply in the following the retina model on a webcam video stream of a dark
-visual scene. In this visual scene, captured in an amphitheater of the university, some students are
-moving while talking to the teacher.
-
-In this video sequence, because of the dark ambiance, signal to noise ratio is low and color
-artifacts are present on visual features edges because of the low quality image capture tool-chain.
-
-![image](images/studentsSample_input.jpg)
-
-Below is shown the retina foveal vision applied on the entire image. In the used retina
-configuration, global luminance is preserved and local contrasts are enhanced. Also, signal to noise
-ratio is improved : since high frequency spatio-temporal noise is reduced, enhanced details are not
-corrupted by any enhanced noise.
-
-![image](images/studentsSample_parvo.jpg)
-
-Below is the output of the Magnocellular output of the retina model. Its signals are strong where
-transient events occur. Here, a student is moving at the bottom of the image thus generating high
-energy. The remaining of the image is static however, it is corrupted by a strong noise. Here, the
-retina filters out most of the noise thus generating low false motion area 'alarms'. This channel
-can be used as a transient/moving areas detector : it would provide relevant information for a low
-cost segmentation tool that would highlight areas in which an event is occurring.
-
-![image](images/studentsSample_magno.jpg)
-
-Retina use case
----------------
-
-This model can be used basically for spatio-temporal video effects but also in the aim of :
-
--   performing texture analysis with enhanced signal to noise ratio and enhanced details robust
-    against input images luminance ranges (check out the Parvocellular retina channel output)
--   performing motion analysis also taking benefit of the previously cited properties.
-
-Literature
-----------
-
-For more information, refer to the following papers : @cite Benoit2010
-
--   Please have a look at the reference work of Jeanny Herault that you can read in his book @cite Herault2010
-
-This retina filter code includes the research contributions of phd/research colleagues from which
-code has been redrawn by the author :
-
--   take a look at the *retinacolor.hpp* module to discover Brice Chaix de Lavarene phD color
-    mosaicing/demosaicing and his reference paper @cite Chaix2007
-
--   take a look at *imagelogpolprojection.hpp* to discover retina spatial log sampling which
-    originates from Barthelemy Durette phd with Jeanny Herault. A Retina / V1 cortex projection is
-    also proposed and originates from Jeanny's discussions. More informations in the above cited
-    Jeanny Heraults's book.
-
-Code tutorial
--------------
-
-Please refer to the original tutorial source code in file
-*opencv_folder/samples/cpp/tutorial_code/bioinspired/retina_tutorial.cpp*.
-
- at note do not forget that the retina model is included in the following namespace: cv::bioinspired
-
-To compile it, assuming OpenCV is correctly installed, use the following command. It requires the
-opencv_core *(cv::Mat and friends objects management)*, opencv_highgui *(display and image/video
-read)* and opencv_bioinspired *(Retina description)* libraries to compile.
-
- at code{.sh}
-// compile
-gcc retina_tutorial.cpp -o Retina_tuto -lopencv_core -lopencv_highgui -lopencv_bioinspired -lopencv_videoio -lopencv_imgcodecs
-
-// Run commands : add 'log' as a last parameter to apply a spatial log sampling (simulates retina sampling)
-// run on webcam
-./Retina_tuto -video
-// run on video file
-./Retina_tuto -video myVideo.avi
-// run on an image
-./Retina_tuto -image myPicture.jpg
-// run on an image with log sampling
-./Retina_tuto -image myPicture.jpg log
- at endcode
-
-Here is a code explanation :
-
-Retina definition is present in the bioinspired package and a simple include allows to use it. You
-can rather use the specific header : *opencv2/bioinspired.hpp* if you prefer but then include the
-other required openv modules : *opencv2/core.hpp* and *opencv2/highgui.hpp*
- at code{.cpp}
-#include "opencv2/opencv.hpp"
- at endcode
-Provide user some hints to run the program with a help function
- at code{.cpp}
-// the help procedure
-static void help(std::string errorMessage)
-{
- std::cout<<"Program init error : "<<errorMessage<<std::endl;
- std::cout<<"\nProgram call procedure : retinaDemo [processing mode] [Optional : media target] [Optional LAST parameter: \"log\" to activate retina log sampling]"<<std::endl;
- std::cout<<"\t[processing mode] :"<<std::endl;
- std::cout<<"\t -image : for still image processing"<<std::endl;
- std::cout<<"\t -video : for video stream processing"<<std::endl;
- std::cout<<"\t[Optional : media target] :"<<std::endl;
- std::cout<<"\t if processing an image or video file, then, specify the path and filename of the target to process"<<std::endl;
- std::cout<<"\t leave empty if processing video stream coming from a connected video device"<<std::endl;
- std::cout<<"\t[Optional : activate retina log sampling] : an optional last parameter can be specified for retina spatial log sampling"<<std::endl;
- std::cout<<"\t set \"log\" without quotes to activate this sampling, output frame size will be divided by 4"<<std::endl;
- std::cout<<"\nExamples:"<<std::endl;
- std::cout<<"\t-Image processing : ./retinaDemo -image lena.jpg"<<std::endl;
- std::cout<<"\t-Image processing with log sampling : ./retinaDemo -image lena.jpg log"<<std::endl;
- std::cout<<"\t-Video processing : ./retinaDemo -video myMovie.mp4"<<std::endl;
- std::cout<<"\t-Live video processing : ./retinaDemo -video"<<std::endl;
- std::cout<<"\nPlease start again with new parameters"<<std::endl;
- std::cout<<"****************************************************"<<std::endl;
- std::cout<<" NOTE : this program generates the default retina parameters file 'RetinaDefaultParameters.xml'"<<std::endl;
- std::cout<<" => you can use this to fine tune parameters and load them if you save to file 'RetinaSpecificParameters.xml'"<<std::endl;
-}
- at endcode
-Then, start the main program and first declare a *cv::Mat* matrix in which input images will be
-loaded. Also allocate a *cv::VideoCapture* object ready to load video streams (if necessary)
- at code{.cpp}
-int main(int argc, char* argv[]) {
-  // declare the retina input buffer... that will be fed differently in regard of the input media
-  cv::Mat inputFrame;
-  cv::VideoCapture videoCapture; // in case a video media is used, its manager is declared here
- at endcode
-In the main program, before processing, first check input command parameters. Here it loads a first
-input image coming from a single loaded image (if user chose command *-image*) or from a video
-stream (if user chose command *-video*). Also, if the user added *log* command at the end of its
-program call, the spatial logarithmic image sampling performed by the retina is taken into account
-by the Boolean flag *useLogSampling*.
- at code{.cpp}
-// welcome message
-  std::cout<<"****************************************************"<<std::endl;
-  std::cout<<"* Retina demonstration : demonstrates the use of is a wrapper class of the Gipsa/Listic Labs retina model."<<std::endl;
-  std::cout<<"* This demo will try to load the file 'RetinaSpecificParameters.xml' (if exists).\nTo create it, copy the autogenerated template 'RetinaDefaultParameters.xml'.\nThen tweak it with your own retina parameters."<<std::endl;
-  // basic input arguments checking
-  if (argc<2)
-  {
-      help("bad number of parameter");
-      return -1;
-  }
-
-  bool useLogSampling = !strcmp(argv[argc-1], "log"); // check if user wants retina log sampling processing
-
-  std::string inputMediaType=argv[1];
-
-  //////////////////////////////////////////////////////////////////////////////
-  // checking input media type (still image, video file, live video acquisition)
-  if (!strcmp(inputMediaType.c_str(), "-image") && argc >= 3)
-  {
-      std::cout<<"RetinaDemo: processing image "<<argv[2]<<std::endl;
-      // image processing case
-      inputFrame = cv::imread(std::string(argv[2]), 1); // load image in RGB mode
-  }else
-      if (!strcmp(inputMediaType.c_str(), "-video"))
-      {
-          if (argc == 2 || (argc == 3 && useLogSampling)) // attempt to grab images from a video capture device
-          {
-              videoCapture.open(0);
-          }else// attempt to grab images from a video filestream
-          {
-              std::cout<<"RetinaDemo: processing video stream "<<argv[2]<<std::endl;
-              videoCapture.open(argv[2]);
-          }
-
-          // grab a first frame to check if everything is ok
-          videoCapture>>inputFrame;
-      }else
-      {
-          // bad command parameter
-          help("bad command parameter");
-          return -1;
-      }
- at endcode
-Once all input parameters are processed, a first image should have been loaded, if not, display
-error and stop program :
- at code{.cpp}
-if (inputFrame.empty())
-{
-    help("Input media could not be loaded, aborting");
-    return -1;
-}
- at endcode
-Now, everything is ready to run the retina model. I propose here to allocate a retina instance and
-to manage the eventual log sampling option. The Retina constructor expects at least a cv::Size
-object that shows the input data size that will have to be managed. One can activate other options
-such as color and its related color multiplexing strategy (here Bayer multiplexing is chosen using
-*enum cv::bioinspired::RETINA_COLOR_BAYER*). If using log sampling, the image reduction factor
-(smaller output images) and log sampling strength can be adjusted.
- at code{.cpp}
-// pointer to a retina object
-cv::Ptr<cv::bioinspired::Retina> myRetina;
-
-// if the last parameter is 'log', then activate log sampling (favour foveal vision and subsamples peripheral vision)
-if (useLogSampling)
-{
-    myRetina = cv::bioinspired::createRetina(inputFrame.size(), true, cv::bioinspired::RETINA_COLOR_BAYER, true, 2.0, 10.0);
-}
-else// -> else allocate "classical" retina :
-    myRetina = cv::bioinspired::createRetina(inputFrame.size());
- at endcode
-Once done, the proposed code writes a default xml file that contains the default parameters of the
-retina. This is useful to make your own config using this template. Here generated template xml file
-is called *RetinaDefaultParameters.xml*.
- at code{.cpp}
-// save default retina parameters file in order to let you see this and maybe modify it and reload using method "setup"
-myRetina->write("RetinaDefaultParameters.xml");
- at endcode
-In the following line, the retina attempts to load another xml file called
-*RetinaSpecificParameters.xml*. If you created it and introduced your own setup, it will be loaded,
-in the other case, default retina parameters are used.
- at code{.cpp}
-// load parameters if file exists
-myRetina->setup("RetinaSpecificParameters.xml");
- at endcode
-It is not required here but just to show it is possible, you can reset the retina buffers to zero to
-force it to forget past events.
- at code{.cpp}
-// reset all retina buffers (imagine you close your eyes for a long time)
-myRetina->clearBuffers();
- at endcode
-Now, it is time to run the retina ! First create some output buffers ready to receive the two retina
-channels outputs
- at code{.cpp}
-// declare retina output buffers
-cv::Mat retinaOutput_parvo;
-cv::Mat retinaOutput_magno;
- at endcode
-Then, run retina in a loop, load new frames from video sequence if necessary and get retina outputs
-back to dedicated buffers.
- at code{.cpp}
-// processing loop with no stop condition
-while(true)
-{
-    // if using video stream, then, grabbing a new frame, else, input remains the same
-    if (videoCapture.isOpened())
-        videoCapture>>inputFrame;
-
-    // run retina filter on the loaded input frame
-    myRetina->run(inputFrame);
-    // Retrieve and display retina output
-    myRetina->getParvo(retinaOutput_parvo);
-    myRetina->getMagno(retinaOutput_magno);
-    cv::imshow("retina input", inputFrame);
-    cv::imshow("Retina Parvo", retinaOutput_parvo);
-    cv::imshow("Retina Magno", retinaOutput_magno);
-    cv::waitKey(10);
-}
- at endcode
-That's done ! But if you want to secure the system, take care and manage Exceptions. The retina can
-throw some when it sees irrelevant data (no input frame, wrong setup, etc.). Then, i recommend to
-surround all the retina code by a try/catch system like this :
- at code{.cpp}
-try{
-     // pointer to a retina object
-     cv::Ptr<cv::Retina> myRetina;
-     [---]
-     // processing loop with no stop condition
-     while(true)
-     {
-         [---]
-     }
-
-}catch(cv::Exception e)
-{
-    std::cerr<<"Error using Retina : "<<e.what()<<std::endl;
-}
- at endcode
-
-Retina parameters, what to do ?
--------------------------------
-
-First, it is recommended to read the reference paper @cite Benoit2010
-
-Once done open the configuration file *RetinaDefaultParameters.xml* generated by the demo and let's
-have a look at it.
- at code{.cpp}
-<?xml version="1.0"?>
-<opencv_storage>
-<OPLandIPLparvo>
-    <colorMode>1</colorMode>
-    <normaliseOutput>1</normaliseOutput>
-    <photoreceptorsLocalAdaptationSensitivity>7.5e-01</photoreceptorsLocalAdaptationSensitivity>
-    <photoreceptorsTemporalConstant>9.0e-01</photoreceptorsTemporalConstant>
-    <photoreceptorsSpatialConstant>5.7e-01</photoreceptorsSpatialConstant>
-    <horizontalCellsGain>0.01</horizontalCellsGain>
-    <hcellsTemporalConstant>0.5</hcellsTemporalConstant>
-    <hcellsSpatialConstant>7.</hcellsSpatialConstant>
-    <ganglionCellsSensitivity>7.5e-01</ganglionCellsSensitivity></OPLandIPLparvo>
-<IPLmagno>
-    <normaliseOutput>1</normaliseOutput>
-    <parasolCells_beta>0.</parasolCells_beta>
-    <parasolCells_tau>0.</parasolCells_tau>
-    <parasolCells_k>7.</parasolCells_k>
-    <amacrinCellsTemporalCutFrequency>2.0e+00</amacrinCellsTemporalCutFrequency>
-    <V0CompressionParameter>9.5e-01</V0CompressionParameter>
-    <localAdaptintegration_tau>0.</localAdaptintegration_tau>
-    <localAdaptintegration_k>7.</localAdaptintegration_k></IPLmagno>
-</opencv_storage>
- at endcode
-Here are some hints but actually, the best parameter setup depends more on what you want to do with
-the retina rather than the images input that you give to retina. Apart from the more specific case
-of High Dynamic Range images (HDR) that require more specific setup for specific luminance
-compression objective, the retina behaviors should be rather stable from content to content. Note
-that OpenCV is able to manage such HDR format thanks to the OpenEXR images compatibility.
-
-Then, if the application target requires details enhancement prior to specific image processing, you
-need to know if mean luminance information is required or not. If not, the the retina can cancel or
-significantly reduce its energy thus giving more visibility to higher spatial frequency details.
-
-
-#### Basic parameters
-
-The simplest parameters are as follows :
-
--   **colorMode** : let the retina process color information (if 1) or gray scale images (if 0). In
-    that last case, only the first channels of the input will be processed.
--   **normaliseOutput** : each channel has such parameter: if the value is set to 1, then the considered
-    channel's output is rescaled between 0 and 255. Be aware at this case of the Magnocellular output
-    level (motion/transient channel detection). Residual noise will also be rescaled !
-
-**Note :** using color requires color channels multiplexing/demultipexing which also demands more
-processing. You can expect much faster processing using gray levels : it would require around 30
-product per pixel for all of the retina processes and it has recently been parallelized for multicore
-architectures.
-
-#### Photo-receptors parameters
-
-The following parameters act on the entry point of the retina - photo-receptors - and has impact on all
- of the following processes. These sensors are low pass spatio-temporal filters that smooth temporal and
-spatial data and also adjust their sensitivity to local luminance,thus, leads to improving details extraction
-and high frequency noise canceling.
-
--   **photoreceptorsLocalAdaptationSensitivity** between 0 and 1. Values close to 1 allow high
-    luminance log compression's effect at the photo-receptors level. Values closer to 0 provide a more
-    linear sensitivity. Increased alone, it can burn the *Parvo (details channel)* output image. If
-    adjusted in collaboration with **ganglionCellsSensitivity**,images can be very contrasted
-    whatever the local luminance there is... at the cost of a naturalness decrease.
--   **photoreceptorsTemporalConstant** this setups the temporal constant of the low pass filter
-    effect at the entry of the retina. High value leads to strong temporal smoothing effect : moving
-    objects are blurred and can disappear while static object are favored. But when starting the
-    retina processing, stable state is reached later.
--   **photoreceptorsSpatialConstant** specifies the spatial constant related to photo-receptors' low
-    pass filter's effect. Those parameters specify the minimum value of the spatial signal period allowed 
-    in what follows. Typically, this filter should cut high frequency noise. On the other hand, a 0 value 
-    cuts none of the noise while higher values start to cut high spatial frequencies, and progressively 
-    lower frequencies... Be aware to not go to high levels if you want to see some details of the input images !
-    A good compromise for color images is a 0.53 value since such choice won't affect too much the color spectrum.
-    Higher values would lead to gray and blurred output images.
-
-#### Horizontal cells parameters
-
-This parameter set tunes the neural network connected to the photo-receptors, the horizontal cells.
-It modulates photo-receptors sensitivity and completes the processing for final spectral whitening
-(part of the spatial band pass effect thus favoring visual details enhancement).
-
--   **horizontalCellsGain** here is a critical parameter ! If you are not interested with the mean
-    luminance and want just to focus on details enhancement, then, set this parameterto zero. However, if 
-    you want to keep some environment luminance's data, let some low spatial frequencies pass into the system and set a
-    higher value (\<1).
--   **hcellsTemporalConstant** similar to photo-receptors, this parameter acts on the temporal constant of a
-    low pass temporal filter that smoothes input data. Here, a high value generates a high retina
-    after effect while a lower value makes the retina more reactive. This value should be lower than
-    **photoreceptorsTemporalConstant** to limit strong retina after effects.
--   **hcellsSpatialConstant** is the spatial constant of these cells filter's low pass one.
-    It specifies the lowest spatial frequency allowed in what follows. Visually, a high value leads
-    to very low spatial frequencies processing and leads to salient halo effects. Lower values
-    reduce this effect but has the limit of not go lower than the value of
-    **photoreceptorsSpatialConstant**. Those 2 parameters actually specify the spatial band-pass of
-    the retina.
-
-**NOTE** Once the processing managed by the previous parameters is done, input data is cleaned from noise
-and luminance is already partly enhanced. The following parameters act on the last processing stages
-of the two outing retina signals.
-
-#### Parvo (details channel) dedicated parameter
-
--   **ganglionCellsSensitivity** specifies the strength of the final local adaptation occurring at
-    the output of this details' dedicated channel. Parameter values remain between 0 and 1. Low value
-    tend to give a linear response while higher values enforce the remaining low contrasted areas.
-
-**Note :** this parameter can correct eventual burned images by favoring low energetic details of
-the visual scene, even in bright areas.
-
-#### IPL Magno (motion/transient channel) parameters
-
-Once image's information are cleaned, this channel acts as a high pass temporal filter that  
-selects only the signals related to transient signals (events, motion, etc.). A low pass spatial filter
-smoothes extracted transient data while a final logarithmic compression enhances low transient events
-thus enhancing event sensitivity.
-
--   **parasolCells_beta** generally set to zero, can be considered as an amplifier gain at the
-    entry point of this processing stage. Generally set to 0.
--   **parasolCells_tau** the temporal smoothing effect that can be added
--   **parasolCells_k** the spatial constant of the spatial filtering effect, set it at a high value
-    to favor low spatial frequency signals that are lower subject for residual noise.
--   **amacrinCellsTemporalCutFrequency** specifies the temporal constant of the high pass filter.
-    High values let slow transient events to be selected.
--   **V0CompressionParameter** specifies the strength of the log compression. Similar behaviors to
-    previous description but here  enforces sensitivity of transient events.
--   **localAdaptintegration_tau** generally set to 0, has no real use actually in here. 
--   **localAdaptintegration_k** specifies the size of the area on which local adaptation is
-    performed. Low values lead to short range local adaptation (higher sensitivity to noise), high
-    values secure log compression.
-
diff --git a/contrib/modules/bioinspired/tutorials/images/retina_TreeHdr_retina.jpg b/contrib/modules/bioinspired/tutorials/retina_model/images/retina_TreeHdr_retina.jpg
similarity index 100%
rename from contrib/modules/bioinspired/tutorials/images/retina_TreeHdr_retina.jpg
rename to contrib/modules/bioinspired/tutorials/retina_model/images/retina_TreeHdr_retina.jpg
diff --git a/contrib/modules/bioinspired/tutorials/images/retina_TreeHdr_small.jpg b/contrib/modules/bioinspired/tutorials/retina_model/images/retina_TreeHdr_small.jpg
similarity index 100%
rename from contrib/modules/bioinspired/tutorials/images/retina_TreeHdr_small.jpg
rename to contrib/modules/bioinspired/tutorials/retina_model/images/retina_TreeHdr_small.jpg
diff --git a/contrib/modules/bioinspired/tutorials/images/studentsSample_input.jpg b/contrib/modules/bioinspired/tutorials/retina_model/images/studentsSample_input.jpg
similarity index 100%
rename from contrib/modules/bioinspired/tutorials/images/studentsSample_input.jpg
rename to contrib/modules/bioinspired/tutorials/retina_model/images/studentsSample_input.jpg
diff --git a/contrib/modules/bioinspired/tutorials/images/studentsSample_magno.jpg b/contrib/modules/bioinspired/tutorials/retina_model/images/studentsSample_magno.jpg
similarity index 100%
rename from contrib/modules/bioinspired/tutorials/images/studentsSample_magno.jpg
rename to contrib/modules/bioinspired/tutorials/retina_model/images/studentsSample_magno.jpg
diff --git a/contrib/modules/bioinspired/tutorials/images/studentsSample_parvo.jpg b/contrib/modules/bioinspired/tutorials/retina_model/images/studentsSample_parvo.jpg
similarity index 100%
rename from contrib/modules/bioinspired/tutorials/images/studentsSample_parvo.jpg
rename to contrib/modules/bioinspired/tutorials/retina_model/images/studentsSample_parvo.jpg
diff --git a/contrib/modules/bioinspired/tutorials/retina_model/retina_model.markdown b/contrib/modules/bioinspired/tutorials/retina_model/retina_model.markdown
new file mode 100644
index 0000000..37285bf
--- /dev/null
+++ b/contrib/modules/bioinspired/tutorials/retina_model/retina_model.markdown
@@ -0,0 +1,477 @@
+Retina and real-world vision {#tutorial_bioinspired_retina_model}
+=============================================================
+
+Goal
+----
+
+I present here a model of human retina that shows some interesting properties for image
+preprocessing and enhancement. In this tutorial you will learn how to:
+
+-   discover the main two channels outing from your retina
+-   see the basics to use the retina model
+-   discover some parameters tweaks
+
+General overview
+----------------
+
+The proposed model originates from Jeanny Herault's research @cite Herault2010 at
+[Gipsa](http://www.gipsa-lab.inpg.fr). It is involved in image processing applications with
+[Listic](http://www.listic.univ-savoie.fr) (code maintainer and user) lab. This is not a complete
+model but it already present interesting properties that can be involved for enhanced image
+processing experience. The model allows the following human retina properties to be used :
+
+-   spectral whitening that has 3 important effects: high spatio-temporal frequency signals
+    canceling (noise), mid-frequencies details enhancement and low frequencies luminance energy
+    reduction. This *all in one* property directly allows visual signals cleaning of classical
+    undesired distortions introduced by image sensors and input luminance range.
+-   local logarithmic luminance compression allows details to be enhanced even in low light
+    conditions.
+-   decorrelation of the details information (Parvocellular output channel) and transient
+    information (events, motion made available at the Magnocellular output channel).
+
+The first two points are illustrated below :
+
+In the figure below, the OpenEXR image sample *CrissyField.exr*, a High Dynamic Range image is
+shown. In order to make it visible on this web-page, the original input image is linearly rescaled
+to the classical image luminance range [0-255] and is converted to 8bit/channel format. Such strong
+conversion hides many details because of too strong local contrasts. Furthermore, noise energy is
+also strong and pollutes visual information.
+
+![image](images/retina_TreeHdr_small.jpg)
+
+In the following image, applying the ideas proposed in @cite Benoit2010, as your retina does, local
+luminance adaptation, spatial noise removal and spectral whitening work together and transmit
+accurate information on lower range 8bit data channels. On this picture, noise in significantly
+removed, local details hidden by strong luminance contrasts are enhanced. Output image keeps its
+naturalness and visual content is enhanced. Color processing is based on the color
+multiplexing/demultiplexing method proposed in @cite Chaix2007 .
+
+![image](images/retina_TreeHdr_retina.jpg)
+
+*Note :* image sample can be downloaded from the [OpenEXR website](http://www.openexr.com).
+Regarding this demonstration, before retina processing, input image has been linearly rescaled
+within 0-255 keeping its channels float format. 5% of its histogram ends has been cut (mostly
+removes wrong HDR pixels). Check out the sample
+*opencv/samples/cpp/OpenEXRimages_HighDynamicRange_Retina_toneMapping.cpp* for similar
+processing. The following demonstration will only consider classical 8bit/channel images.
+
+The retina model output channels
+--------------------------------
+
+The retina model presents two outputs that benefit from the above cited behaviors.
+
+-   The first one is called the Parvocellular channel. It is mainly active in the foveal retina area
+    (high resolution central vision with color sensitive photo-receptors), its aim is to provide
+    accurate color vision for visual details remaining static on the retina. On the other hand
+    objects moving on the retina projection are blurred.
+-   The second well known channel is the Magnocellular channel. It is mainly active in the retina
+    peripheral vision and send signals related to change events (motion, transient events, etc.).
+    These outing signals also help visual system to focus/center retina on 'transient'/moving areas
+    for more detailed analysis thus improving visual scene context and object classification.
+
+**NOTE :** regarding the proposed model, contrary to the real retina, we apply these two channels on
+the entire input images using the same resolution. This allows enhanced visual details and motion
+information to be extracted on all the considered images... but remember, that these two channels
+are complementary. For example, if Magnocellular channel gives strong energy in an area, then, the
+Parvocellular channel is certainly blurred there since there is a transient event.
+
+As an illustration, we apply in the following the retina model on a webcam video stream of a dark
+visual scene. In this visual scene, captured in an amphitheater of the university, some students are
+moving while talking to the teacher.
+
+In this video sequence, because of the dark ambiance, signal to noise ratio is low and color
+artifacts are present on visual features edges because of the low quality image capture tool-chain.
+
+![image](images/studentsSample_input.jpg)
+
+Below is shown the retina foveal vision applied on the entire image. In the used retina
+configuration, global luminance is preserved and local contrasts are enhanced. Also, signal to noise
+ratio is improved : since high frequency spatio-temporal noise is reduced, enhanced details are not
+corrupted by any enhanced noise.
+
+![image](images/studentsSample_parvo.jpg)
+
+Below is the output of the Magnocellular output of the retina model. Its signals are strong where
+transient events occur. Here, a student is moving at the bottom of the image thus generating high
+energy. The remaining of the image is static however, it is corrupted by a strong noise. Here, the
+retina filters out most of the noise thus generating low false motion area 'alarms'. This channel
+can be used as a transient/moving areas detector : it would provide relevant information for a low
+cost segmentation tool that would highlight areas in which an event is occurring.
+
+![image](images/studentsSample_magno.jpg)
+
+Retina use case
+---------------
+
+This model can be used basically for spatio-temporal video effects but also in the aim of :
+
+-   performing texture analysis with enhanced signal to noise ratio and enhanced details robust
+    against input images luminance ranges (check out the Parvocellular retina channel output)
+-   performing motion analysis also taking benefit of the previously cited properties.
+
+Literature
+----------
+
+For more information, refer to the following papers : @cite Benoit2010
+
+-   Please have a look at the reference work of Jeanny Herault that you can read in his book @cite Herault2010
+
+This retina filter code includes the research contributions of phd/research colleagues from which
+code has been redrawn by the author :
+
+-   take a look at the *retinacolor.hpp* module to discover Brice Chaix de Lavarene phD color
+    mosaicing/demosaicing and his reference paper @cite Chaix2007
+
+-   take a look at *imagelogpolprojection.hpp* to discover retina spatial log sampling which
+    originates from Barthelemy Durette phd with Jeanny Herault. A Retina / V1 cortex projection is
+    also proposed and originates from Jeanny's discussions. More informations in the above cited
+    Jeanny Heraults's book.
+
+Code tutorial
+-------------
+
+Please refer to the original tutorial source code in file
+*opencv_folder/samples/cpp/tutorial_code/bioinspired/retina_tutorial.cpp*.
+
+ at note do not forget that the retina model is included in the following namespace: cv::bioinspired
+
+To compile it, assuming OpenCV is correctly installed, use the following command. It requires the
+opencv_core *(cv::Mat and friends objects management)*, opencv_highgui *(display and image/video
+read)* and opencv_bioinspired *(Retina description)* libraries to compile.
+
+ at code{.sh}
+// compile
+gcc retina_tutorial.cpp -o Retina_tuto -lopencv_core -lopencv_highgui -lopencv_bioinspired -lopencv_videoio -lopencv_imgcodecs
+
+// Run commands : add 'log' as a last parameter to apply a spatial log sampling (simulates retina sampling)
+// run on webcam
+./Retina_tuto -video
+// run on video file
+./Retina_tuto -video myVideo.avi
+// run on an image
+./Retina_tuto -image myPicture.jpg
+// run on an image with log sampling
+./Retina_tuto -image myPicture.jpg log
+ at endcode
+
+Here is a code explanation :
+
+Retina definition is present in the bioinspired package and a simple include allows to use it. You
+can rather use the specific header : *opencv2/bioinspired.hpp* if you prefer but then include the
+other required openv modules : *opencv2/core.hpp* and *opencv2/highgui.hpp*
+ at code{.cpp}
+#include "opencv2/opencv.hpp"
+ at endcode
+Provide user some hints to run the program with a help function
+ at code{.cpp}
+// the help procedure
+static void help(std::string errorMessage)
+{
+ std::cout<<"Program init error : "<<errorMessage<<std::endl;
+ std::cout<<"\nProgram call procedure : retinaDemo [processing mode] [Optional : media target] [Optional LAST parameter: \"log\" to activate retina log sampling]"<<std::endl;
+ std::cout<<"\t[processing mode] :"<<std::endl;
+ std::cout<<"\t -image : for still image processing"<<std::endl;
+ std::cout<<"\t -video : for video stream processing"<<std::endl;
+ std::cout<<"\t[Optional : media target] :"<<std::endl;
+ std::cout<<"\t if processing an image or video file, then, specify the path and filename of the target to process"<<std::endl;
+ std::cout<<"\t leave empty if processing video stream coming from a connected video device"<<std::endl;
+ std::cout<<"\t[Optional : activate retina log sampling] : an optional last parameter can be specified for retina spatial log sampling"<<std::endl;
+ std::cout<<"\t set \"log\" without quotes to activate this sampling, output frame size will be divided by 4"<<std::endl;
+ std::cout<<"\nExamples:"<<std::endl;
+ std::cout<<"\t-Image processing : ./retinaDemo -image lena.jpg"<<std::endl;
+ std::cout<<"\t-Image processing with log sampling : ./retinaDemo -image lena.jpg log"<<std::endl;
+ std::cout<<"\t-Video processing : ./retinaDemo -video myMovie.mp4"<<std::endl;
+ std::cout<<"\t-Live video processing : ./retinaDemo -video"<<std::endl;
+ std::cout<<"\nPlease start again with new parameters"<<std::endl;
+ std::cout<<"****************************************************"<<std::endl;
+ std::cout<<" NOTE : this program generates the default retina parameters file 'RetinaDefaultParameters.xml'"<<std::endl;
+ std::cout<<" => you can use this to fine tune parameters and load them if you save to file 'RetinaSpecificParameters.xml'"<<std::endl;
+}
+ at endcode
+Then, start the main program and first declare a *cv::Mat* matrix in which input images will be
+loaded. Also allocate a *cv::VideoCapture* object ready to load video streams (if necessary)
+ at code{.cpp}
+int main(int argc, char* argv[]) {
+  // declare the retina input buffer... that will be fed differently in regard of the input media
+  cv::Mat inputFrame;
+  cv::VideoCapture videoCapture; // in case a video media is used, its manager is declared here
+ at endcode
+In the main program, before processing, first check input command parameters. Here it loads a first
+input image coming from a single loaded image (if user chose command *-image*) or from a video
+stream (if user chose command *-video*). Also, if the user added *log* command at the end of its
+program call, the spatial logarithmic image sampling performed by the retina is taken into account
+by the Boolean flag *useLogSampling*.
+ at code{.cpp}
+// welcome message
+  std::cout<<"****************************************************"<<std::endl;
+  std::cout<<"* Retina demonstration : demonstrates the use of is a wrapper class of the Gipsa/Listic Labs retina model."<<std::endl;
+  std::cout<<"* This demo will try to load the file 'RetinaSpecificParameters.xml' (if exists).\nTo create it, copy the autogenerated template 'RetinaDefaultParameters.xml'.\nThen tweak it with your own retina parameters."<<std::endl;
+  // basic input arguments checking
+  if (argc<2)
+  {
+      help("bad number of parameter");
+      return -1;
+  }
+
+  bool useLogSampling = !strcmp(argv[argc-1], "log"); // check if user wants retina log sampling processing
+
+  std::string inputMediaType=argv[1];
+
+  //////////////////////////////////////////////////////////////////////////////
+  // checking input media type (still image, video file, live video acquisition)
+  if (!strcmp(inputMediaType.c_str(), "-image") && argc >= 3)
+  {
+      std::cout<<"RetinaDemo: processing image "<<argv[2]<<std::endl;
+      // image processing case
+      inputFrame = cv::imread(std::string(argv[2]), 1); // load image in RGB mode
+  }else
+      if (!strcmp(inputMediaType.c_str(), "-video"))
+      {
+          if (argc == 2 || (argc == 3 && useLogSampling)) // attempt to grab images from a video capture device
+          {
+              videoCapture.open(0);
+          }else// attempt to grab images from a video filestream
+          {
+              std::cout<<"RetinaDemo: processing video stream "<<argv[2]<<std::endl;
+              videoCapture.open(argv[2]);
+          }
+
+          // grab a first frame to check if everything is ok
+          videoCapture>>inputFrame;
+      }else
+      {
+          // bad command parameter
+          help("bad command parameter");
+          return -1;
+      }
+ at endcode
+Once all input parameters are processed, a first image should have been loaded, if not, display
+error and stop program :
+ at code{.cpp}
+if (inputFrame.empty())
+{
+    help("Input media could not be loaded, aborting");
+    return -1;
+}
+ at endcode
+Now, everything is ready to run the retina model. I propose here to allocate a retina instance and
+to manage the eventual log sampling option. The Retina constructor expects at least a cv::Size
+object that shows the input data size that will have to be managed. One can activate other options
+such as color and its related color multiplexing strategy (here Bayer multiplexing is chosen using
+*enum cv::bioinspired::RETINA_COLOR_BAYER*). If using log sampling, the image reduction factor
+(smaller output images) and log sampling strength can be adjusted.
+ at code{.cpp}
+// pointer to a retina object
+cv::Ptr<cv::bioinspired::Retina> myRetina;
+
+// if the last parameter is 'log', then activate log sampling (favour foveal vision and subsamples peripheral vision)
+if (useLogSampling)
+{
+    myRetina = cv::bioinspired::createRetina(inputFrame.size(), true, cv::bioinspired::RETINA_COLOR_BAYER, true, 2.0, 10.0);
+}
+else// -> else allocate "classical" retina :
+    myRetina = cv::bioinspired::createRetina(inputFrame.size());
+ at endcode
+Once done, the proposed code writes a default xml file that contains the default parameters of the
+retina. This is useful to make your own config using this template. Here generated template xml file
+is called *RetinaDefaultParameters.xml*.
+ at code{.cpp}
+// save default retina parameters file in order to let you see this and maybe modify it and reload using method "setup"
+myRetina->write("RetinaDefaultParameters.xml");
+ at endcode
+In the following line, the retina attempts to load another xml file called
+*RetinaSpecificParameters.xml*. If you created it and introduced your own setup, it will be loaded,
+in the other case, default retina parameters are used.
+ at code{.cpp}
+// load parameters if file exists
+myRetina->setup("RetinaSpecificParameters.xml");
+ at endcode
+It is not required here but just to show it is possible, you can reset the retina buffers to zero to
+force it to forget past events.
+ at code{.cpp}
+// reset all retina buffers (imagine you close your eyes for a long time)
+myRetina->clearBuffers();
+ at endcode
+Now, it is time to run the retina ! First create some output buffers ready to receive the two retina
+channels outputs
+ at code{.cpp}
+// declare retina output buffers
+cv::Mat retinaOutput_parvo;
+cv::Mat retinaOutput_magno;
+ at endcode
+Then, run retina in a loop, load new frames from video sequence if necessary and get retina outputs
+back to dedicated buffers.
+ at code{.cpp}
+// processing loop with no stop condition
+while(true)
+{
+    // if using video stream, then, grabbing a new frame, else, input remains the same
+    if (videoCapture.isOpened())
+        videoCapture>>inputFrame;
+
+    // run retina filter on the loaded input frame
+    myRetina->run(inputFrame);
+    // Retrieve and display retina output
+    myRetina->getParvo(retinaOutput_parvo);
+    myRetina->getMagno(retinaOutput_magno);
+    cv::imshow("retina input", inputFrame);
+    cv::imshow("Retina Parvo", retinaOutput_parvo);
+    cv::imshow("Retina Magno", retinaOutput_magno);
+    cv::waitKey(10);
+}
+ at endcode
+That's done ! But if you want to secure the system, take care and manage Exceptions. The retina can
+throw some when it sees irrelevant data (no input frame, wrong setup, etc.). Then, i recommend to
+surround all the retina code by a try/catch system like this :
+ at code{.cpp}
+try{
+     // pointer to a retina object
+     cv::Ptr<cv::Retina> myRetina;
+     [---]
+     // processing loop with no stop condition
+     while(true)
+     {
+         [---]
+     }
+
+}catch(cv::Exception e)
+{
+    std::cerr<<"Error using Retina : "<<e.what()<<std::endl;
+}
+ at endcode
+
+Retina parameters, what to do ?
+-------------------------------
+
+First, it is recommended to read the reference paper @cite Benoit2010
+
+Once done open the configuration file *RetinaDefaultParameters.xml* generated by the demo and let's
+have a look at it.
+ at code{.cpp}
+<?xml version="1.0"?>
+<opencv_storage>
+<OPLandIPLparvo>
+    <colorMode>1</colorMode>
+    <normaliseOutput>1</normaliseOutput>
+    <photoreceptorsLocalAdaptationSensitivity>7.5e-01</photoreceptorsLocalAdaptationSensitivity>
+    <photoreceptorsTemporalConstant>9.0e-01</photoreceptorsTemporalConstant>
+    <photoreceptorsSpatialConstant>5.7e-01</photoreceptorsSpatialConstant>
+    <horizontalCellsGain>0.01</horizontalCellsGain>
+    <hcellsTemporalConstant>0.5</hcellsTemporalConstant>
+    <hcellsSpatialConstant>7.</hcellsSpatialConstant>
+    <ganglionCellsSensitivity>7.5e-01</ganglionCellsSensitivity></OPLandIPLparvo>
+<IPLmagno>
+    <normaliseOutput>1</normaliseOutput>
+    <parasolCells_beta>0.</parasolCells_beta>
+    <parasolCells_tau>0.</parasolCells_tau>
+    <parasolCells_k>7.</parasolCells_k>
+    <amacrinCellsTemporalCutFrequency>2.0e+00</amacrinCellsTemporalCutFrequency>
+    <V0CompressionParameter>9.5e-01</V0CompressionParameter>
+    <localAdaptintegration_tau>0.</localAdaptintegration_tau>
+    <localAdaptintegration_k>7.</localAdaptintegration_k></IPLmagno>
+</opencv_storage>
+ at endcode
+Here are some hints but actually, the best parameter setup depends more on what you want to do with
+the retina rather than the images input that you give to retina. Apart from the more specific case
+of High Dynamic Range images (HDR) that require more specific setup for specific luminance
+compression objective, the retina behaviors should be rather stable from content to content. Note
+that OpenCV is able to manage such HDR format thanks to the OpenEXR images compatibility.
+
+Then, if the application target requires details enhancement prior to specific image processing, you
+need to know if mean luminance information is required or not. If not, the the retina can cancel or
+significantly reduce its energy thus giving more visibility to higher spatial frequency details.
+
+
+#### Basic parameters
+
+The simplest parameters are as follows :
+
+-   **colorMode** : let the retina process color information (if 1) or gray scale images (if 0). In
+    that last case, only the first channels of the input will be processed.
+-   **normaliseOutput** : each channel has such parameter: if the value is set to 1, then the considered
+    channel's output is rescaled between 0 and 255. Be aware at this case of the Magnocellular output
+    level (motion/transient channel detection). Residual noise will also be rescaled !
+
+**Note :** using color requires color channels multiplexing/demultipexing which also demands more
+processing. You can expect much faster processing using gray levels : it would require around 30
+product per pixel for all of the retina processes and it has recently been parallelized for multicore
+architectures.
+
+#### Photo-receptors parameters
+
+The following parameters act on the entry point of the retina - photo-receptors - and has impact on all
+ of the following processes. These sensors are low pass spatio-temporal filters that smooth temporal and
+spatial data and also adjust their sensitivity to local luminance,thus, leads to improving details extraction
+and high frequency noise canceling.
+
+-   **photoreceptorsLocalAdaptationSensitivity** between 0 and 1. Values close to 1 allow high
+    luminance log compression's effect at the photo-receptors level. Values closer to 0 provide a more
+    linear sensitivity. Increased alone, it can burn the *Parvo (details channel)* output image. If
+    adjusted in collaboration with **ganglionCellsSensitivity**,images can be very contrasted
+    whatever the local luminance there is... at the cost of a naturalness decrease.
+-   **photoreceptorsTemporalConstant** this setups the temporal constant of the low pass filter
+    effect at the entry of the retina. High value leads to strong temporal smoothing effect : moving
+    objects are blurred and can disappear while static object are favored. But when starting the
+    retina processing, stable state is reached later.
+-   **photoreceptorsSpatialConstant** specifies the spatial constant related to photo-receptors' low
+    pass filter's effect. Those parameters specify the minimum value of the spatial signal period allowed
+    in what follows. Typically, this filter should cut high frequency noise. On the other hand, a 0 value
+    cuts none of the noise while higher values start to cut high spatial frequencies, and progressively
+    lower frequencies... Be aware to not go to high levels if you want to see some details of the input images !
+    A good compromise for color images is a 0.53 value since such choice won't affect too much the color spectrum.
+    Higher values would lead to gray and blurred output images.
+
+#### Horizontal cells parameters
+
+This parameter set tunes the neural network connected to the photo-receptors, the horizontal cells.
+It modulates photo-receptors sensitivity and completes the processing for final spectral whitening
+(part of the spatial band pass effect thus favoring visual details enhancement).
+
+-   **horizontalCellsGain** here is a critical parameter ! If you are not interested with the mean
+    luminance and want just to focus on details enhancement, then, set this parameterto zero. However, if
+    you want to keep some environment luminance's data, let some low spatial frequencies pass into the system and set a
+    higher value (\<1).
+-   **hcellsTemporalConstant** similar to photo-receptors, this parameter acts on the temporal constant of a
+    low pass temporal filter that smoothes input data. Here, a high value generates a high retina
+    after effect while a lower value makes the retina more reactive. This value should be lower than
+    **photoreceptorsTemporalConstant** to limit strong retina after effects.
+-   **hcellsSpatialConstant** is the spatial constant of these cells filter's low pass one.
+    It specifies the lowest spatial frequency allowed in what follows. Visually, a high value leads
+    to very low spatial frequencies processing and leads to salient halo effects. Lower values
+    reduce this effect but has the limit of not go lower than the value of
+    **photoreceptorsSpatialConstant**. Those 2 parameters actually specify the spatial band-pass of
+    the retina.
+
+**NOTE** Once the processing managed by the previous parameters is done, input data is cleaned from noise
+and luminance is already partly enhanced. The following parameters act on the last processing stages
+of the two outing retina signals.
+
+#### Parvo (details channel) dedicated parameter
+
+-   **ganglionCellsSensitivity** specifies the strength of the final local adaptation occurring at
+    the output of this details' dedicated channel. Parameter values remain between 0 and 1. Low value
+    tend to give a linear response while higher values enforce the remaining low contrasted areas.
+
+**Note :** this parameter can correct eventual burned images by favoring low energetic details of
+the visual scene, even in bright areas.
+
+#### IPL Magno (motion/transient channel) parameters
+
+Once image's information are cleaned, this channel acts as a high pass temporal filter that
+selects only the signals related to transient signals (events, motion, etc.). A low pass spatial filter
+smoothes extracted transient data while a final logarithmic compression enhances low transient events
+thus enhancing event sensitivity.
+
+-   **parasolCells_beta** generally set to zero, can be considered as an amplifier gain at the
+    entry point of this processing stage. Generally set to 0.
+-   **parasolCells_tau** the temporal smoothing effect that can be added
+-   **parasolCells_k** the spatial constant of the spatial filtering effect, set it at a high value
+    to favor low spatial frequency signals that are lower subject for residual noise.
+-   **amacrinCellsTemporalCutFrequency** specifies the temporal constant of the high pass filter.
+    High values let slow transient events to be selected.
+-   **V0CompressionParameter** specifies the strength of the log compression. Similar behaviors to
+    previous description but here  enforces sensitivity of transient events.
+-   **localAdaptintegration_tau** generally set to 0, has no real use actually in here.
+-   **localAdaptintegration_k** specifies the size of the area on which local adaptation is
+    performed. Low values lead to short range local adaptation (higher sensitivity to noise), high
+    values secure log compression.
diff --git a/contrib/modules/bioinspired/tutorials/table_of_content_retina.markdown b/contrib/modules/bioinspired/tutorials/table_of_content_retina.markdown
new file mode 100644
index 0000000..b0f6e19
--- /dev/null
+++ b/contrib/modules/bioinspired/tutorials/table_of_content_retina.markdown
@@ -0,0 +1,14 @@
+Discovering the human retina and its use for image processing {#tutorial_table_of_content_retina}
+============================
+
+-   @subpage tutorial_bioinspired_retina_model
+
+    *Author:* Alexandre Benoit
+
+    Processing regular images
+
+-   @subpage tutorial_bioinspired_retina_illusion
+
+    *Author:* Andrea Merello
+
+    See how to reproduce human eye optical illusions
\ No newline at end of file
diff --git a/contrib/modules/ccalib/include/opencv2/ccalib/omnidir.hpp b/contrib/modules/ccalib/include/opencv2/ccalib/omnidir.hpp
index 25c41bf..9663c18 100644
--- a/contrib/modules/ccalib/include/opencv2/ccalib/omnidir.hpp
+++ b/contrib/modules/ccalib/include/opencv2/ccalib/omnidir.hpp
@@ -168,7 +168,7 @@ namespace omnidir
     @param idx Indices of images that pass initialization, which are really used in calibration. So the size of rvecs is the
     same as idx.total().
     */
-    CV_EXPORTS_W double calibrate(InputArray objectPoints, InputArray imagePoints, Size size,
+    CV_EXPORTS_W double calibrate(InputArrayOfArrays objectPoints, InputArrayOfArrays imagePoints, Size size,
         InputOutputArray K, InputOutputArray xi, InputOutputArray D, OutputArrayOfArrays rvecs, OutputArrayOfArrays tvecs,
         int flags, TermCriteria criteria, OutputArray idx=noArray());
 
diff --git a/contrib/modules/ccalib/src/omnidir.cpp b/contrib/modules/ccalib/src/omnidir.cpp
index 8c9e1d7..177929d 100644
--- a/contrib/modules/ccalib/src/omnidir.cpp
+++ b/contrib/modules/ccalib/src/omnidir.cpp
@@ -1058,7 +1058,7 @@ void cv::omnidir::internal::compose_motion(InputArray _om1, InputArray _T1, Inpu
     dT3dom1 = Mat::zeros(3, 3, CV_64FC1);
 }
 
-double cv::omnidir::calibrate(InputArray patternPoints, InputArray imagePoints, Size size,
+double cv::omnidir::calibrate(InputArrayOfArrays patternPoints, InputArrayOfArrays imagePoints, Size size,
     InputOutputArray K, InputOutputArray xi, InputOutputArray D, OutputArrayOfArrays omAll, OutputArrayOfArrays tAll,
     int flags, TermCriteria criteria, OutputArray idx)
 {
@@ -1306,8 +1306,8 @@ double cv::omnidir::stereoCalibrate(InputOutputArrayOfArrays objectPoints, Input
     }
     if (om.empty())
     {
-        om.create(1, 3, CV_64F);
-        T.create(1, 3, CV_64F);
+        om.create(3, 1, CV_64F);
+        T.create(3, 1, CV_64F);
     }
     if (omL.empty())
     {
@@ -2307,4 +2307,4 @@ void cv::omnidir::internal::getInterset(InputArray idx1, InputArray idx2, Output
     {
         inter_ori.getMat().at<int>(i) = _inter_ori[i];
     }
-}
\ No newline at end of file
+}
diff --git a/contrib/modules/ccalib/tutorial/omnidir_tutorial.markdown b/contrib/modules/ccalib/tutorial/omnidir_tutorial.markdown
deleted file mode 100644
index 388fcb6..0000000
--- a/contrib/modules/ccalib/tutorial/omnidir_tutorial.markdown
+++ /dev/null
@@ -1,185 +0,0 @@
-Omnidirectional Cameara Calibration {#tutorial_omnidir_calib_main}
-======================
-
-This module includes calibration, rectification and stereo reconstruction of omnidirectional camearas. The camera model is described in this paper:
-
-*C. Mei and P. Rives, Single view point omnidirectional camera calibration from planar grids, in ICRA 2007.*
-
-The model is capable of modeling catadioptric cameras and fisheye cameras, which may both have very large field of view.
-
-The implementation of the calibration part is based on Li's calibration toolbox:
-
-*B. Li, L. Heng, K. Kevin and M. Pollefeys, "A Multiple-Camera System Calibration Toolbox Using A Feature Descriptor-Based Calibration Pattern", in IROS 2013.*
-
-This tutorial will introduce the following parts of omnidirectional camera calibartion module:
-
--    calibrate a single camera.
--    calibrate a stereo pair of cameras.
--    rectify images so that large distoration is removed.
--    reconstruct 3D from two stereo images, with large filed of view.
--    comparison with fisheye model in opencv/calib3d/
-
-Single Camera Calibration
----------------------
-
-The first step to calibrate camera is to get a calibration pattern and take some photos. Several kinds of patterns are supported by OpenCV, like checkerborad and circle grid. A new pattern named random pattern can also be used, you can refer to opencv_contrib/modules/ccalib for more details.
-
-Next step is to extract corners from calibration pattern. For checkerboard, use OpenCV function ```cv::findChessboardCorners```; for circle grid, use ```cv::findCirclesGrid```, for random pattern, use the ```randomPatternCornerFinder``` class in opencv_contrib/modules/ccalib/src/randomPattern.hpp. Save the positions of corners in images in a variable like ```imagePoints```. The type of ```imagePoints``` may be ```std::vector<std::vector<cv::Vec2f>>```, the first vector stores corners in  [...]
-
-Also, the corresponding 3D points in world (pattern) coordinate are required. You can compute they for yourself if you know the physical size of your pattern. Save 3D points in ```objectPoints```, similar to ```imagePoints```, it can be ```std::vector<std::vector<Vec3f>>``` or ```std::vector<cv::Mat>``` where ```cv::Mat``` is of type ```CV_32FC3```. Note the size of ```objectPoints``` and ```imagePoints``` must be the same because they are corresponding to each other.
-
-Another thing you should input is the size of images. The file opencv_contrib/modules/ccalib/tutorial/data/omni_calib_data.xml stores an example of objectPoints, imagePoints and imageSize. Use the following code to load them:
-
-```
-cv::FileStorage fs("omni_calib_data.xml", cv::FileStorage::READ);
-std::vector<cv::Mat> objectPoints, imagePoints;
-cv::Size imgSize;
-fs["objectPoints"] >> objectPoints;
-fs["imagePoints"] >> imagePoints;
-fs["imageSize"] >> imgSize;
-```
-
-Then define some variables to store the output parameters and run the calibration function like:
-
-```
-cv::Mat K, xi, D, idx;
-int flags = 0;
-cv::TermCriteria critia(cv::TermCriteria::COUNT + cv::TermCriteria::EPS, 200, 0.0001);
-std::vector<cv::Mat> rvecs, tvecs;
-double rms = cv::omnidir::calibrate(objectPoints, imagePoints, imgSize, K, xi, D, rvecs, tvecs, flags, critia, idx);
-```
-
-```K```, ```xi```, ```D``` are internal parameters and  ```rvecs```, ```tvecs``` are external parameters that store the pose of patterns. All of them have  depth of ```CV_64F```. The ```xi``` is a single value variable of Mei's model. ```idx``` is a ```CV_32S``` Mat that stores indices of images that are really used in calibration. This is due to some images are failed in the initialization step so they are not used in the final optimization. The returned value *rms* is the root mean squ [...]
-
-The calibration supports some features, *flags* is a enumeration for some features, including:
-
--    cv::omnidir::CALIB_FIX_SKEW
--    cv::omnidir::CALIB_FIX_K1
--    cv::omnidir::CALIB_FIX_K2
--    cv::omnidir::CALIB_FIX_P1
--    cv::omnidir::CALIB_FIX_P2
--    cv::omnidir::CALIB_FIX_XI
--    cv::omnidir::CALIB_FIX_GAMMA
--    cv::omnidir::CALIB_FIX_CENTER
-
-Your can specify ```flags``` to fix parameters during calibration. Use 'plus' operator to set multiple features. For example, ```CALIB_FIX_SKEW+CALIB_FIX_K1``` means fixing skew and K1.
-
-```critia``` is the stopping critia during optimization, set it to be, for example, cv::TermCriteria(cv::TermCriteria::COUNT + cv::TermCriteria::EPS, 200, 0.0001), which means using 200 iterations and stopping when relative change is smaller than 0.0001.
-
-Stereo Calibration
---------------------------
-Stereo calibration is to calibrate two cameras together. The output parameters include camera parameters of two cameras and the relative pose of them. To recover the relative pose, two cameras must observe the same pattern at the same time, so the ```objectPoints``` of two cameras are the same.
-
-Now detect image corners for both cameras as discussed above to get ```imagePoints1``` and ```imagePoints2```. Then compute the shared ```objectPoints```.
-
-An example of of stereo calibration data is stored in opencv_contrib/modules/ccalib/tutorial/data/omni_stereocalib_data.xml. Load the data by
-```
-cv::FileStorage fs("omni_stereocalib_data.xml", cv::FileStorage::READ);
-std::vector<cv::Mat> objectPoints, imagePoints1, imagePoints2;
-cv::Size imgSize1, imgSize2;
-fs["objectPoints"] >> objectPoints;
-fs["imagePoints1"] >> imagePoints1;
-fs["imagePoints2"] >> imagePoints2;
-fs["imageSize1"] >> imgSize1;
-fs["imageSize2"] >> imgSize2;
-```
-
-Then do stereo calibration by
-```
-cv::Mat K1, K2, xi1, xi2, D1, D2;
-int flags = 0;
-cv::TermCriteria critia(cv::TermCriteria::COUNT + cv::TermCriteria::EPS, 200, 0.0001);
-std::vector<cv::Mat> rvecsL, tvecsL;
-cv::Mat rvec, tvec;
-double rms = cv::omnidir::calibrate(objectPoints, imagePoints1, imagePoints2, imgSize1, imgSize2, K1, xi1, D1, K2, xi2, D2, rvec, tvec, rvecsL, tvecsL, flags, critia, idx);
-```
-Here ```rvec``` and ```tvec``` are the transform between the first and the second camera. ```rvecsL``` and ```tvecsL``` are the transforms between patterns and the first camera.
-
-Image Rectificaiton
----------------------------
-
-Omnidirectional images have very large distortion, so it is not compatible with human's eye balls. For better view, rectification can be applied if camera parameters are known. Here is an example of omnidirectional image of 360 degrees of horizontal field of view.
-
-![image](img/sample.jpg)
-
-After rectification, a perspective like view is generated. Here is one example to run image rectification in this module:
-
-```
-cv::omnidir::undistortImage(distorted, undistorted, K, D, xi, int flags, Knew, new_size)
-```
-
-The variable *distorted* and *undistorted* are the origional image and rectified image perspectively. *K*, *D*, *xi* are camera parameters. *KNew* and *new_size* are the camera matrix and image size for rectified image. *flags* is the rectification type, it can be:
-
--    RECTIFY_PERSPECTIVE: rectify to perspective images, which will lose some filed of view.
--    RECTIFY_CYLINDRICAL: rectify to cylindrical images that preserve all view.
--    RECTIFY_STEREOGRAPHIC: rectify to stereographic images that may lose a little view.
--    RECTIFY_LONGLATI: rectify to longitude-latitude map like a world map of the earth. This rectification can be used to stereo reconstruction but may not be friendly for view. This map is described in paper:
-*Li S. Binocular spherical stereo[J]. Intelligent Transportation Systems, IEEE Transactions on, 2008, 9(4): 589-600.*
-
-The following four images are four types of rectified images discribed above:
-
-![image](img/sample_rec_per.jpg)
-
-![image](img/sample_rec_cyl.jpg)
-
-![image](img/sample_rec_ste.jpg)
-
-![image](img/sample_rec_log.jpg)
-
-It can be observed that perspective rectified image perserves only a little field of view and is not goodlooking. Cylindrical rectification preserves all field of view and scene is unnatural only in the middle of bottom. The distortion of stereographic in the middle of bottom is smaller than cylindrical but the distortion of other places are larger, and it can not preserve all field of view. For images with very large distortion, the longitude-latitude rectification does not give a good  [...]
-
-**Note**: To have a better result, you should carefully choose ```Knew``` and it is related to your camera. In general, a smaller focal length leads to a smaller field of view and vice versa. Here are recommonded settings.
-
-For RECTIFY_PERSPECTIVE
-```
-Knew = Matx33f(new_size.width/4, 0, new_size.width/2,
-               0, new_size.height/4, new_size.height/2,
-               0, 0, 1);
-```
-For RECTIFY_CYLINDRICAL, RECTIFY_STEREOGRAPHIC, RECTIFY_LONGLATI
-```
-Knew = Matx33f(new_size.width/3.1415, 0, 0,
-               0, new_size.height/3.1415, 0,
-               0, 0, 1);
-```
-
-Maybe you need to change ```(u0, v0)``` to get a better view.
-
-Stereo Reconstruction
-------------------------------
-Stereo reconstruction is to reconstruct 3D points from a calibrated stereo camera pair. It is a basic problem of computer vison. However, for omnidirectional camera, it is not very popular because of the large distortion make it a little difficult. Conventional methods rectify images to perspective ones and do stereo reconstruction in perspective images. However, the last section shows that recifying to perspective images lose too much field of view, which waste the advantage of omnidire [...]
-
-The first step of stereo reconstruction is stereo rectification so that epipolar lines are horizontal lines. Here, we use longitude-latitude rectification to preserve all filed of view, or perspective rectification which is available but is not recommended. The second step is stereo matching to get a disparity map. At last, 3D points can be generated from disparity map.
-
-The API of stereo reconstruction for omnidrectional camera is ```omnidir::stereoReconstruct```. Here we use an example to show how it works.
-
-First, calibrate a stereo pair of cameras as describe above and get parameters like ```K1```, ```D1```, ```xi1```, ```K2```, ```D2```, ```xi2```, ```rvec```, ```tvec```. Then read two images from the first and second camera respectively, for instance, ```image1``` and ```image2```, which are shown below.
-
-![image](img/imgs.jpg)
-
-Second, run ```omnidir::stereoReconstruct``` like:
-```
-cv::Size imgSize = img1.size();
-int numDisparities = 16*5;
-int SADWindowSize = 5;
-cv::Mat disMap;
-int flag = cv::omnidir::RECTIFY_LONGLATI;
-int pointType = omnidir::XYZRGB;
-// the range of theta is (0, pi) and the range of phi is (0, pi)
-cv::Matx33d KNew(imgSize.width / 3.1415, 0, 0, 0, imgSize.height / 3.1415, 0, 0, 0, 1);
-Mat imageRec1, imageRec2, pointCloud;
-
-cv::omnidir::stereoReconstruct(img1, img2, K1, D1, xi1, K2, D2, xi2, R, T, flag, numDisparities, SADWindowSize, imageRec1, imageRec2, disMap, imgSize, KNew, pointCloud);
-```
-
-Here variable ```flag``` indicates the recectify type, only ```RECTIFY_LONGLATI```(recommend) and ```RECTIFY_PERSPECTIVE``` make sense. ```numDisparities``` is the max disparity value and ```SADWindowSize``` is the window size of ```cv::StereoSGBM```. ```pointType``` is a flag to define the type of point cloud, ```omnidir::XYZRGB``` each point is a 6-dimensional vector, the first three elements are xyz coordinate, the last three elements are rgb color information. Another type ```omnidir [...]
-
-Moreover, ```imageRec1``` and ```imagerec2``` are rectified versions of the first and second images. The epipolar lines of them have the same y-coordinate so that stereo matching becomes easy. Here are an example of them:
-
-![image](img/lines.jpg)
-It can be observed that they are well aligned. The variable ```disMap``` is the disparity map computed by ```cv::StereoSGBM``` from ```imageRec1``` and ```imageRec2```. The disparity map of the above two images is:
-
-![image](img/disparity.jpg)
-
-After we have disparity, we can compute 3D location for each pixel. The point cloud is stored in ```pointCloud```, which is a 3-channel or 6-channel ```cv::Mat```. We show the point cloud in the following image.
-![image](img/pointCloud.jpg)
diff --git a/contrib/modules/ccalib/tutorial/data/omni_calib_data.xml b/contrib/modules/ccalib/tutorials/data/omni_calib_data.xml
similarity index 100%
rename from contrib/modules/ccalib/tutorial/data/omni_calib_data.xml
rename to contrib/modules/ccalib/tutorials/data/omni_calib_data.xml
diff --git a/contrib/modules/ccalib/tutorial/data/omni_stereocalib_data.xml b/contrib/modules/ccalib/tutorials/data/omni_stereocalib_data.xml
similarity index 100%
rename from contrib/modules/ccalib/tutorial/data/omni_stereocalib_data.xml
rename to contrib/modules/ccalib/tutorials/data/omni_stereocalib_data.xml
diff --git a/contrib/modules/ccalib/tutorial/img/disparity.jpg b/contrib/modules/ccalib/tutorials/img/disparity.jpg
similarity index 100%
rename from contrib/modules/ccalib/tutorial/img/disparity.jpg
rename to contrib/modules/ccalib/tutorials/img/disparity.jpg
diff --git a/contrib/modules/ccalib/tutorial/img/imgs.jpg b/contrib/modules/ccalib/tutorials/img/imgs.jpg
similarity index 100%
rename from contrib/modules/ccalib/tutorial/img/imgs.jpg
rename to contrib/modules/ccalib/tutorials/img/imgs.jpg
diff --git a/contrib/modules/ccalib/tutorial/img/lines.jpg b/contrib/modules/ccalib/tutorials/img/lines.jpg
similarity index 100%
rename from contrib/modules/ccalib/tutorial/img/lines.jpg
rename to contrib/modules/ccalib/tutorials/img/lines.jpg
diff --git a/contrib/modules/ccalib/tutorial/img/pattern_img.jpg b/contrib/modules/ccalib/tutorials/img/pattern_img.jpg
similarity index 100%
rename from contrib/modules/ccalib/tutorial/img/pattern_img.jpg
rename to contrib/modules/ccalib/tutorials/img/pattern_img.jpg
diff --git a/contrib/modules/ccalib/tutorial/img/pointCloud.jpg b/contrib/modules/ccalib/tutorials/img/pointCloud.jpg
similarity index 100%
rename from contrib/modules/ccalib/tutorial/img/pointCloud.jpg
rename to contrib/modules/ccalib/tutorials/img/pointCloud.jpg
diff --git a/contrib/modules/ccalib/tutorial/img/random_pattern.jpg b/contrib/modules/ccalib/tutorials/img/random_pattern.jpg
similarity index 100%
rename from contrib/modules/ccalib/tutorial/img/random_pattern.jpg
rename to contrib/modules/ccalib/tutorials/img/random_pattern.jpg
diff --git a/contrib/modules/ccalib/tutorial/img/sample.jpg b/contrib/modules/ccalib/tutorials/img/sample.jpg
similarity index 100%
rename from contrib/modules/ccalib/tutorial/img/sample.jpg
rename to contrib/modules/ccalib/tutorials/img/sample.jpg
diff --git a/contrib/modules/ccalib/tutorial/img/sample_rec_cyl.jpg b/contrib/modules/ccalib/tutorials/img/sample_rec_cyl.jpg
similarity index 100%
rename from contrib/modules/ccalib/tutorial/img/sample_rec_cyl.jpg
rename to contrib/modules/ccalib/tutorials/img/sample_rec_cyl.jpg
diff --git a/contrib/modules/ccalib/tutorial/img/sample_rec_log.jpg b/contrib/modules/ccalib/tutorials/img/sample_rec_log.jpg
similarity index 100%
rename from contrib/modules/ccalib/tutorial/img/sample_rec_log.jpg
rename to contrib/modules/ccalib/tutorials/img/sample_rec_log.jpg
diff --git a/contrib/modules/ccalib/tutorial/img/sample_rec_per.jpg b/contrib/modules/ccalib/tutorials/img/sample_rec_per.jpg
similarity index 100%
rename from contrib/modules/ccalib/tutorial/img/sample_rec_per.jpg
rename to contrib/modules/ccalib/tutorials/img/sample_rec_per.jpg
diff --git a/contrib/modules/ccalib/tutorial/img/sample_rec_ste.jpg b/contrib/modules/ccalib/tutorials/img/sample_rec_ste.jpg
similarity index 100%
rename from contrib/modules/ccalib/tutorial/img/sample_rec_ste.jpg
rename to contrib/modules/ccalib/tutorials/img/sample_rec_ste.jpg
diff --git a/contrib/modules/ccalib/tutorial/multi_camera_tutorial.markdown b/contrib/modules/ccalib/tutorials/multi_camera_tutorial.markdown
similarity index 100%
rename from contrib/modules/ccalib/tutorial/multi_camera_tutorial.markdown
rename to contrib/modules/ccalib/tutorials/multi_camera_tutorial.markdown
diff --git a/contrib/modules/ccalib/tutorials/omnidir_tutorial.markdown b/contrib/modules/ccalib/tutorials/omnidir_tutorial.markdown
new file mode 100644
index 0000000..4460d43
--- /dev/null
+++ b/contrib/modules/ccalib/tutorials/omnidir_tutorial.markdown
@@ -0,0 +1,185 @@
+Omnidirectional Cameara Calibration {#tutorial_omnidir_calib_main}
+======================
+
+This module includes calibration, rectification and stereo reconstruction of omnidirectional camearas. The camera model is described in this paper:
+
+*C. Mei and P. Rives, Single view point omnidirectional camera calibration from planar grids, in ICRA 2007.*
+
+The model is capable of modeling catadioptric cameras and fisheye cameras, which may both have very large field of view.
+
+The implementation of the calibration part is based on Li's calibration toolbox:
+
+*B. Li, L. Heng, K. Kevin and M. Pollefeys, "A Multiple-Camera System Calibration Toolbox Using A Feature Descriptor-Based Calibration Pattern", in IROS 2013.*
+
+This tutorial will introduce the following parts of omnidirectional camera calibartion module:
+
+-    calibrate a single camera.
+-    calibrate a stereo pair of cameras.
+-    rectify images so that large distoration is removed.
+-    reconstruct 3D from two stereo images, with large filed of view.
+-    comparison with fisheye model in opencv/calib3d/
+
+Single Camera Calibration
+---------------------
+
+The first step to calibrate camera is to get a calibration pattern and take some photos. Several kinds of patterns are supported by OpenCV, like checkerborad and circle grid. A new pattern named random pattern can also be used, you can refer to opencv_contrib/modules/ccalib for more details.
+
+Next step is to extract corners from calibration pattern. For checkerboard, use OpenCV function ```cv::findChessboardCorners```; for circle grid, use ```cv::findCirclesGrid```, for random pattern, use the ```randomPatternCornerFinder``` class in opencv_contrib/modules/ccalib/src/randomPattern.hpp. Save the positions of corners in images in a variable like ```imagePoints```. The type of ```imagePoints``` may be ```std::vector<std::vector<cv::Vec2f>>```, the first vector stores corners in  [...]
+
+Also, the corresponding 3D points in world (pattern) coordinate are required. You can compute they for yourself if you know the physical size of your pattern. Save 3D points in ```objectPoints```, similar to ```imagePoints```, it can be ```std::vector<std::vector<Vec3f>>``` or ```std::vector<cv::Mat>``` where ```cv::Mat``` is of type ```CV_32FC3```. Note the size of ```objectPoints``` and ```imagePoints``` must be the same because they are corresponding to each other.
+
+Another thing you should input is the size of images. The file opencv_contrib/modules/ccalib/tutorial/data/omni_calib_data.xml stores an example of objectPoints, imagePoints and imageSize. Use the following code to load them:
+
+```
+cv::FileStorage fs("omni_calib_data.xml", cv::FileStorage::READ);
+std::vector<cv::Mat> objectPoints, imagePoints;
+cv::Size imgSize;
+fs["objectPoints"] >> objectPoints;
+fs["imagePoints"] >> imagePoints;
+fs["imageSize"] >> imgSize;
+```
+
+Then define some variables to store the output parameters and run the calibration function like:
+
+```
+cv::Mat K, xi, D, idx;
+int flags = 0;
+cv::TermCriteria critia(cv::TermCriteria::COUNT + cv::TermCriteria::EPS, 200, 0.0001);
+std::vector<cv::Mat> rvecs, tvecs;
+double rms = cv::omnidir::calibrate(objectPoints, imagePoints, imgSize, K, xi, D, rvecs, tvecs, flags, critia, idx);
+```
+
+`K`, ```xi```, ```D``` are internal parameters and  ```rvecs```, ```tvecs``` are external parameters that store the pose of patterns. All of them have  depth of ```CV_64F```. The ```xi``` is a single value variable of Mei's model. ```idx``` is a ```CV_32S``` Mat that stores indices of images that are really used in calibration. This is due to some images are failed in the initialization step so they are not used in the final optimization. The returned value *rms* is the root mean square  [...]
+
+The calibration supports some features, *flags* is a enumeration for some features, including:
+
+-    cv::omnidir::CALIB_FIX_SKEW
+-    cv::omnidir::CALIB_FIX_K1
+-    cv::omnidir::CALIB_FIX_K2
+-    cv::omnidir::CALIB_FIX_P1
+-    cv::omnidir::CALIB_FIX_P2
+-    cv::omnidir::CALIB_FIX_XI
+-    cv::omnidir::CALIB_FIX_GAMMA
+-    cv::omnidir::CALIB_FIX_CENTER
+
+Your can specify ```flags``` to fix parameters during calibration. Use 'plus' operator to set multiple features. For example, ```CALIB_FIX_SKEW+CALIB_FIX_K1``` means fixing skew and K1.
+
+`criteria` is the stopping criteria during optimization, set it to be, for example, cv::TermCriteria(cv::TermCriteria::COUNT + cv::TermCriteria::EPS, 200, 0.0001), which means using 200 iterations and stopping when relative change is smaller than 0.0001.
+
+Stereo Calibration
+--------------------------
+Stereo calibration is to calibrate two cameras together. The output parameters include camera parameters of two cameras and the relative pose of them. To recover the relative pose, two cameras must observe the same pattern at the same time, so the ```objectPoints``` of two cameras are the same.
+
+Now detect image corners for both cameras as discussed above to get ```imagePoints1``` and ```imagePoints2```. Then compute the shared ```objectPoints```.
+
+An example of of stereo calibration data is stored in opencv_contrib/modules/ccalib/tutorial/data/omni_stereocalib_data.xml. Load the data by
+```
+cv::FileStorage fs("omni_stereocalib_data.xml", cv::FileStorage::READ);
+std::vector<cv::Mat> objectPoints, imagePoints1, imagePoints2;
+cv::Size imgSize1, imgSize2;
+fs["objectPoints"] >> objectPoints;
+fs["imagePoints1"] >> imagePoints1;
+fs["imagePoints2"] >> imagePoints2;
+fs["imageSize1"] >> imgSize1;
+fs["imageSize2"] >> imgSize2;
+```
+
+Then do stereo calibration by
+```
+cv::Mat K1, K2, xi1, xi2, D1, D2;
+int flags = 0;
+cv::TermCriteria critia(cv::TermCriteria::COUNT + cv::TermCriteria::EPS, 200, 0.0001);
+std::vector<cv::Mat> rvecsL, tvecsL;
+cv::Mat rvec, tvec;
+double rms = cv::omnidir::stereoCalibrate(objectPoints, imagePoints1, imagePoints2, imgSize1, imgSize2, K1, xi1, D1, K2, xi2, D2, rvec, tvec, rvecsL, tvecsL, flags, critia, idx);
+```
+Here ```rvec``` and ```tvec``` are the transform between the first and the second camera. ```rvecsL``` and ```tvecsL``` are the transforms between patterns and the first camera.
+
+Image Rectificaiton
+---------------------------
+
+Omnidirectional images have very large distortion, so it is not compatible with human's eye balls. For better view, rectification can be applied if camera parameters are known. Here is an example of omnidirectional image of 360 degrees of horizontal field of view.
+
+![image](img/sample.jpg)
+
+After rectification, a perspective like view is generated. Here is one example to run image rectification in this module:
+
+```
+cv::omnidir::undistortImage(distorted, undistorted, K, D, xi, int flags, Knew, new_size)
+```
+
+The variable *distorted* and *undistorted* are the origional image and rectified image perspectively. *K*, *D*, *xi* are camera parameters. *KNew* and *new_size* are the camera matrix and image size for rectified image. *flags* is the rectification type, it can be:
+
+-    RECTIFY_PERSPECTIVE: rectify to perspective images, which will lose some filed of view.
+-    RECTIFY_CYLINDRICAL: rectify to cylindrical images that preserve all view.
+-    RECTIFY_STEREOGRAPHIC: rectify to stereographic images that may lose a little view.
+-    RECTIFY_LONGLATI: rectify to longitude-latitude map like a world map of the earth. This rectification can be used to stereo reconstruction but may not be friendly for view. This map is described in paper:
+*Li S. Binocular spherical stereo[J]. Intelligent Transportation Systems, IEEE Transactions on, 2008, 9(4): 589-600.*
+
+The following four images are four types of rectified images discribed above:
+
+![image](img/sample_rec_per.jpg)
+
+![image](img/sample_rec_cyl.jpg)
+
+![image](img/sample_rec_ste.jpg)
+
+![image](img/sample_rec_log.jpg)
+
+It can be observed that perspective rectified image perserves only a little field of view and is not goodlooking. Cylindrical rectification preserves all field of view and scene is unnatural only in the middle of bottom. The distortion of stereographic in the middle of bottom is smaller than cylindrical but the distortion of other places are larger, and it can not preserve all field of view. For images with very large distortion, the longitude-latitude rectification does not give a good  [...]
+
+**Note**: To have a better result, you should carefully choose ```Knew``` and it is related to your camera. In general, a smaller focal length leads to a smaller field of view and vice versa. Here are recommonded settings.
+
+For RECTIFY_PERSPECTIVE
+```
+Knew = Matx33f(new_size.width/4, 0, new_size.width/2,
+               0, new_size.height/4, new_size.height/2,
+               0, 0, 1);
+```
+For RECTIFY_CYLINDRICAL, RECTIFY_STEREOGRAPHIC, RECTIFY_LONGLATI
+```
+Knew = Matx33f(new_size.width/3.1415, 0, 0,
+               0, new_size.height/3.1415, 0,
+               0, 0, 1);
+```
+
+Maybe you need to change ```(u0, v0)``` to get a better view.
+
+Stereo Reconstruction
+------------------------------
+Stereo reconstruction is to reconstruct 3D points from a calibrated stereo camera pair. It is a basic problem of computer vison. However, for omnidirectional camera, it is not very popular because of the large distortion make it a little difficult. Conventional methods rectify images to perspective ones and do stereo reconstruction in perspective images. However, the last section shows that recifying to perspective images lose too much field of view, which waste the advantage of omnidire [...]
+
+The first step of stereo reconstruction is stereo rectification so that epipolar lines are horizontal lines. Here, we use longitude-latitude rectification to preserve all filed of view, or perspective rectification which is available but is not recommended. The second step is stereo matching to get a disparity map. At last, 3D points can be generated from disparity map.
+
+The API of stereo reconstruction for omnidrectional camera is ```omnidir::stereoReconstruct```. Here we use an example to show how it works.
+
+First, calibrate a stereo pair of cameras as describe above and get parameters like ```K1```, ```D1```, ```xi1```, ```K2```, ```D2```, ```xi2```, ```rvec```, ```tvec```. Then read two images from the first and second camera respectively, for instance, ```image1``` and ```image2```, which are shown below.
+
+![image](img/imgs.jpg)
+
+Second, run ```omnidir::stereoReconstruct``` like:
+```
+cv::Size imgSize = img1.size();
+int numDisparities = 16*5;
+int SADWindowSize = 5;
+cv::Mat disMap;
+int flag = cv::omnidir::RECTIFY_LONGLATI;
+int pointType = omnidir::XYZRGB;
+// the range of theta is (0, pi) and the range of phi is (0, pi)
+cv::Matx33d KNew(imgSize.width / 3.1415, 0, 0, 0, imgSize.height / 3.1415, 0, 0, 0, 1);
+Mat imageRec1, imageRec2, pointCloud;
+
+cv::omnidir::stereoReconstruct(img1, img2, K1, D1, xi1, K2, D2, xi2, R, T, flag, numDisparities, SADWindowSize, imageRec1, imageRec2, disMap, imgSize, KNew, pointCloud);
+```
+
+Here variable ```flag``` indicates the recectify type, only ```RECTIFY_LONGLATI```(recommend) and ```RECTIFY_PERSPECTIVE``` make sense. ```numDisparities``` is the max disparity value and ```SADWindowSize``` is the window size of ```cv::StereoSGBM```. ```pointType``` is a flag to define the type of point cloud, ```omnidir::XYZRGB``` each point is a 6-dimensional vector, the first three elements are xyz coordinate, the last three elements are rgb color information. Another type ```omnidir [...]
+
+Moreover, ```imageRec1``` and ```imagerec2``` are rectified versions of the first and second images. The epipolar lines of them have the same y-coordinate so that stereo matching becomes easy. Here are an example of them:
+
+![image](img/lines.jpg)
+It can be observed that they are well aligned. The variable ```disMap``` is the disparity map computed by ```cv::StereoSGBM``` from ```imageRec1``` and ```imageRec2```. The disparity map of the above two images is:
+
+![image](img/disparity.jpg)
+
+After we have disparity, we can compute 3D location for each pixel. The point cloud is stored in ```pointCloud```, which is a 3-channel or 6-channel ```cv::Mat```. We show the point cloud in the following image.
+![image](img/pointCloud.jpg)
diff --git a/contrib/modules/cnn_3dobj/CMakeLists.txt b/contrib/modules/cnn_3dobj/CMakeLists.txt
index a255cc2..88319d5 100755
--- a/contrib/modules/cnn_3dobj/CMakeLists.txt
+++ b/contrib/modules/cnn_3dobj/CMakeLists.txt
@@ -24,19 +24,24 @@ else()
   message(STATUS "Glog:   NO")
 endif()
 
-if(HAVE_CAFFE)
-configure_file(${CMAKE_CURRENT_SOURCE_DIR}/cnn_3dobj_config.hpp.in
-               ${CMAKE_CURRENT_SOURCE_DIR}/include/opencv2/cnn_3dobj_config.hpp @ONLY)
+if(NOT HAVE_CAFFE)
+    ocv_module_disable(cnn_3dobj)
+else()
 
 include_directories(${CMAKE_CURRENT_BINARY_DIR})
 
-if(${Caffe_FOUND})
-  include_directories(${Caffe_INCLUDE_DIR})
-endif()
-  set(the_description "CNN for 3D object recognition and pose estimation including a completed Sphere View on 3D objects")
-  ocv_define_module(cnn_3dobj opencv_core opencv_imgproc opencv_viz opencv_highgui OPTIONAL WRAP python)
+include_directories(${Caffe_INCLUDE_DIR})
+set(the_description "CNN for 3D object recognition and pose estimation including a completed Sphere View on 3D objects")
+ocv_define_module(cnn_3dobj opencv_core opencv_imgproc ${Caffe_LIBS} ${Glog_LIBS} ${Protobuf_LIBS} OPTIONAL opencv_features2d opencv_viz opencv_calib3d WRAP python)
+ocv_add_testdata(testdata/cv contrib/cnn_3dobj)
 
-if(${Caffe_FOUND})
-  target_link_libraries(opencv_cnn_3dobj ${Caffe_LIBS} ${Glog_LIBS} ${Protobuf_LIBS})
+if(TARGET opencv_test_cnn_3dobj)
+  target_link_libraries(opencv_test_cnn_3dobj boost_system)
 endif()
+
+foreach(exe_TGT  classify video sphereview_data model_analysis)
+    if(TARGET example_cnn_3dobj_${exe_TGT})
+      target_link_libraries(example_cnn_3dobj_${exe_TGT} boost_system)
+    endif()
+endforeach()
 endif()
diff --git a/contrib/modules/cnn_3dobj/FindCaffe.cmake b/contrib/modules/cnn_3dobj/FindCaffe.cmake
index 12948f6..21fa95c 100755
--- a/contrib/modules/cnn_3dobj/FindCaffe.cmake
+++ b/contrib/modules/cnn_3dobj/FindCaffe.cmake
@@ -1,7 +1,7 @@
 # Caffe package for CNN Triplet training
 unset(Caffe_FOUND)
 
-find_path(Caffe_INCLUDE_DIR NAMES caffe/caffe.hpp caffe/common.hpp caffe/net.hpp caffe/proto/caffe.pb.h caffe/util/io.hpp caffe/vision_layers.hpp
+find_path(Caffe_INCLUDE_DIR NAMES caffe/caffe.hpp caffe/common.hpp caffe/net.hpp caffe/proto/caffe.pb.h caffe/util/io.hpp
   HINTS
   /usr/local/include)
 
diff --git a/contrib/modules/cnn_3dobj/README.md b/contrib/modules/cnn_3dobj/README.md
index 88e4667..76598a0 100755
--- a/contrib/modules/cnn_3dobj/README.md
+++ b/contrib/modules/cnn_3dobj/README.md
@@ -1,20 +1,20 @@
-#Convolutional Neural Network for 3D object classification and pose estimation.
+#Convolutional Neural Networks for 3D object classification and pose estimation.
 ===========================================================
 #Module Description on cnn_3dobj:
-####This learning structure construction and feature extraction concept is based on Convolutional Neural Network, the main reference paper could be found at:
+####This module uses Convolutional Neural Networks (Caffe) to train and recognize 3D poses of objects using triplet networks. The main reference paper can be found at:
 <https://cvarlab.icg.tugraz.at/pubs/wohlhart_cvpr15.pdf>.
-####The author provided Codes on Theano on:
+####The author provided Theano code for this on:
 <https://cvarlab.icg.tugraz.at/projects/3d_object_detection/>.
-####I implemented the training and feature extraction codes mainly based on CAFFE project(<http://caffe.berkeleyvision.org/>) which will be compiled as libcaffe for the cnn_3dobj OpenCV module, codes are mainly concentrating on triplet and pair-wise jointed loss layer, the training data arrangement is also important which basic training information.
-####Codes about my triplet version of caffe are released on Github:
+####This implements training and feature extraction code mainly using CAFFE (<http://caffe.berkeleyvision.org/>) which will be compiled as libcaffe for the cnn_3dobj OpenCV module. The code mainly concentrats on triplet networks using pair-wise jointed loss function layers. The training data arrangement is also important and there is basic information about that.
+####Code for the triplet version of Caffe are on my (Yilda Wang's) Github:
 <https://github.com/Wangyida/caffe/tree/cnn_triplet>.
-####You can git it through:
+####You can get it through:
 ```
 $ git clone https://github.com/Wangyida/caffe/tree/cnn_triplet.
 ```
 ===========================================================
 #Module Building Process:
-####Prerequisite for this module: protobuf and caffe, for the libcaffe installation, you can install it on standard system path for the aim of being able to be linked by this OpenCV module when compiling and function using. Using: -D CMAKE_INSTALL_PREFIX=/usr/local as an building option when you cmake, the building process on Caffe on system could be like this:
+####Prerequisites for this module are protobuf and Caffe. For libcaffe installation, you can install it on the standard system path so that it can be linked by this OpenCV module when compiling and linking using: -D CMAKE_INSTALL_PREFIX=/usr/local as an build option when you cmake. The building process on Caffe on system could be like this:
 ```
 $ cd <caffe_source_directory>
 $ mkdir biuld
@@ -23,7 +23,7 @@ $ cmake -D CMAKE_INSTALL_PREFIX=/usr/local ..
 $ make all -j4
 $ sudo make install
 ```
-####After all these steps, the headers and libs of CAFFE will be set on /usr/local/ path, and when you compiling opencv with opencv_contrib modules as below, the protobuf and caffe will be recognized as already installed while building. Protobuf is needed.
+####After the above steps, the headers and libs of CAFFE will be set on /usr/local/ path so that when you compile opencv with opencv_contrib modules as below, the protobuf and caffe libs will be recognized as already installed while building. Obviously protobuf is also needed.
 
 #Compiling OpenCV
 ```
@@ -35,78 +35,57 @@ $ make -j4
 $ sudo make install
 ```
 ##Tips on compiling problems:
-####If you encouter the no declaration errors when you 'make', it might becaused that you have installed the older version of cnn_3dobj module and the header file changed in a newly released version of codes. This problem is the cmake and make can't detect the header should be updated and it keeps the older header remains in /usr/local/include/opencv2 whithout updating. This error could be solved by remove the installed older version of cnn_3dobj module by:
+####If you encouter the no declaration errors when you 'make', it might becaused that you have installed the older version of the cnn_3dobj module and the header file changed in a newly released version of the code. This problem is cmake and make can't detect that the header should be updated and it keeps the older header in /usr/local/include/opencv2 whithout updating. This error could be solved by removing the installed older version of the cnn_3dobj module using:
 ```
 $ cd /
 $ cd usr/local/include/opencv2/
 $ sudo rm -rf cnn_3dobj.hpp
 ```
-####And redo the compiling steps above again.
-===========================================================
-#Building samples
-```
-$ cd <opencv_contrib>/modules/cnn_3dobj/samples
-$ mkdir build
-$ cd build
-$ cmake ..
-$ make
-```
-===========================================================
+####And then redo the compiling steps above again.
 #Demos
-##Demo1: training data generation
-####Imagas generation from different pose, by default there are 4 models used, there will be 276 images in all which each class contains 69 iamges, if you want to use additional .ply models, it is necessary to change the class number parameter to the new class number and also give it a new class label. If you will train net work and extract feature from RGB images set the parameter rgb_use as 1.
-```
-$ ./sphereview_test -plymodel=../data/3Dmodel/ape.ply -label_class=0 -cam_head_x=0 -cam_head_y=0 -cam_head_z=1
-```
-####press 'Q' to start 2D image genaration
-```
-$ ./sphereview_test -plymodel=../data/3Dmodel/ant.ply -label_class=1 -cam_head_x=0 -cam_head_y=-1 -cam_head_z=0
-```
-```
-$ ./sphereview_test -plymodel=../data/3Dmodel/cow.ply -label_class=2 -cam_head_x=0 -cam_head_y=-1 -cam_head_z=0
-```
-```
-$ ./sphereview_test -plymodel=../data/3Dmodel/plane.ply -label_class=3 -cam_head_x=0 -cam_head_y=-1 -cam_head_z=0
-```
-```
-$ ./sphereview_test -plymodel=../data/3Dmodel/bunny.ply -label_class=4 -cam_head_x=0 -cam_head_y=-1 -cam_head_z=0
-```
+##Demo1: Training set data generation
+####Image generation for different poses: by default, there are 4 models used and there will be 276 images in all in which each class contains 69 iamges. If you want to use additional .ply models, it is necessary to change the class number parameter to the new class number and also give it a new class label. If you want to train the network and extract feature from RGB images, set the parameter rgb_use as 1.
 ```
-$ ./sphereview_test -plymodel=../data/3Dmodel/horse.ply -label_class=5 -cam_head_x=0 -cam_head_y=0 -cam_head_z=-1
+$ ./example_cnn_3dobj_sphereview_data -plymodel=../data/3Dmodel/ape.ply -label_class=0 -cam_head_x=0 -cam_head_y=0 -cam_head_z=1
+$ ./example_cnn_3dobj_sphereview_data -plymodel=../data/3Dmodel/ant.ply -label_class=1 -cam_head_x=0 -cam_head_y=-1 -cam_head_z=0
+$ ./example_cnn_3dobj_sphereview_data -plymodel=../data/3Dmodel/cow.ply -label_class=2 -cam_head_x=0 -cam_head_y=-1 -cam_head_z=0
+$ ./example_cnn_3dobj_sphereview_data -plymodel=../data/3Dmodel/plane.ply -label_class=3 -cam_head_x=0 -cam_head_y=-1 -cam_head_z=0
+$ ./example_cnn_3dobj_sphereview_data -plymodel=../data/3Dmodel/bunny.ply -label_class=4 -cam_head_x=0 -cam_head_y=-1 -cam_head_z=0
+$ ./example_cnn_3dobj_sphereview_data -plymodel=../data/3Dmodel/horse.ply -label_class=5 -cam_head_x=0 -cam_head_y=0 -cam_head_z=-1
 ```
-####When all images are created in images_all folder as a collection of training images for network tranining and as a gallery of reference images for the classification part, then proceed on.
-####After this demo, the binary files of images and labels will be stored as 'binary_image' and 'binary_label' in current path, you should copy them into the leveldb folder in Caffe triplet training, for example: copy these 2 files in <caffe_source_directory>/data/linemod and rename them as 'binary_image_train', 'binary_image_test' and 'binary_label_train', 'binary_label_train'. Here I use the same as trianing and testing data, you can use different data for training and testing the perf [...]
-####You could start triplet tranining using Caffe like this:
+####When all images are created in images_all folder as a collection of training images for network tranining and as a gallery of reference images for classification, then proceed onward.
+####After this demo, the binary files of images and labels will be stored as 'binary_image' and 'binary_label' in current path. You should copy them into the leveldb folder for Caffe triplet training. For example: copy these 2 files in <caffe_source_directory>/data/linemod and rename them as 'binary_image_train', 'binary_image_test' and 'binary_label_train', 'binary_label_train'. Here I use the same as trianing and testing data but you can use different data for training and testing. It' [...]
+####Start triplet tranining using Caffe like this:
 ```
 $ cd
 $ cd <caffe_source_directory>
 $ ./examples/triplet/create_3d_triplet.sh
 $ ./examples/triplet/train_3d_triplet.sh
 ```
-####After doing this, you will get .caffemodel files as the trained parameter of net work. I have already provide the net definition .prototxt files and the pretrained .caffemodel in <opencv_contrib>/modules/cnn_3dobj/testdata/cv folder, you could just use them without training in caffe.
+####After doing this, you will get .caffemodel files as the trained parameters of the network. I have already provide the network definition .prototxt files and the pretrained .caffemodel in <opencv_contrib>/modules/cnn_3dobj/testdata/cv folder, so you could just use them instead of training with Caffe.
 ===========================================================
-##Demo2: feature extraction and classification
+##Demo2: Feature extraction and classification
 ```
 $ cd
 $ cd <opencv_contrib>/modules/cnn_3dobj/samples/build
 ```
-####Classifier, this will extracting the feature of a single image and compare it with features of gallery samples for prediction. This demo uses a set of images for feature extraction in a given path, these features will be a reference for prediction on target image. The caffe model and network prototxt file is attached in <opencv_contrib>/modules/cnn_3dobj/testdata/cv. Just run:
+####Classification: This will extract features of a single image and compare it with features of a gallery of samples for prediction. This demo uses a set of images for feature extraction in a given path, these features will be a reference for prediction on the target image. The Caffe model and the network prototxt file are in <opencv_contrib>/modules/cnn_3dobj/testdata/cv. Just run:
 ```
-$ ./classify_test
+$ ./example_cnn_3dobj_classify
 ```
-####if the classification and pose estimation issue need to extract mean got from all training images, you can run this:
+####if you want to extract mean classification and pose estimation performance from all the training images, you can run this:
 ```
-$ ./classify_test -mean_file=../data/images_mean/triplet_mean.binaryproto
+$ ./example_cnn_3dobj_classify -mean_file=../data/images_mean/triplet_mean.binaryproto
 ```
 ===========================================================
-##Demo3: model performance test
-####This demo will have a test on the performance of trained CNN model on several images. If the the model fail on telling different samples from seperate classes or confused on samples with similar pose but from different classes, it will give some information on the model analysis.
+##Demo3: Model performance test
+####This demo will run a performance test of a trained CNN model on several images. If the the model fails on telling different samples from seperate classes apart, or is confused on samples with similar pose but from different classes, this will give some information for model analysis.
 ```
-$ ./model_test
+$ ./example_cnn_3dobj_model_analysis
 ```
 ===========================================================
 #Test
-####If you want to have a test on cnn_3dobj module, the path of test data must be set in advance:
+####If you want to run a test on the cnn_3dobj module, the path of test data must be set in advance:
 ```
 $ export OPENCV_TEST_DATA_PATH=<opencv_contrib>/modules/cnn_3dobj/testdata
 ```
diff --git a/contrib/modules/cnn_3dobj/cnn_3dobj_config.hpp.in b/contrib/modules/cnn_3dobj/cnn_3dobj_config.hpp.in
deleted file mode 100755
index ad30a32..0000000
--- a/contrib/modules/cnn_3dobj/cnn_3dobj_config.hpp.in
+++ /dev/null
@@ -1,5 +0,0 @@
-#ifndef __OPENCV_CNN_3DOBJ_CONFIG_HPP__
-#define __OPENCV_CNN_3DOBJ_CONFIG_HPP__
-// HAVE CAFFE
-#cmakedefine HAVE_CAFFE
-#endif
diff --git a/contrib/modules/cnn_3dobj/include/opencv2/cnn_3dobj.hpp b/contrib/modules/cnn_3dobj/include/opencv2/cnn_3dobj.hpp
index 3855a9c..1dc2c36 100755
--- a/contrib/modules/cnn_3dobj/include/opencv2/cnn_3dobj.hpp
+++ b/contrib/modules/cnn_3dobj/include/opencv2/cnn_3dobj.hpp
@@ -58,24 +58,17 @@ the use of this software, even if advised of the possibility of such damage.
 #include <dirent.h>
 #define CPU_ONLY
 
-#include <opencv2/cnn_3dobj_config.hpp>
-#ifdef HAVE_CAFFE
 #include <caffe/blob.hpp>
 #include <caffe/common.hpp>
 #include <caffe/net.hpp>
 #include <caffe/proto/caffe.pb.h>
 #include <caffe/util/io.hpp>
-#include <caffe/vision_layers.hpp>
-#endif
 
 #include "opencv2/viz/vizcore.hpp"
 #include "opencv2/highgui.hpp"
 #include "opencv2/highgui/highgui_c.h"
 #include "opencv2/imgproc.hpp"
-using caffe::Blob;
-using caffe::Caffe;
-using caffe::Datum;
-using caffe::Net;
+
 /** @defgroup cnn_3dobj 3D object recognition and pose estimation API
 
 As CNN based learning algorithm shows better performance on the classification issues,
diff --git a/contrib/modules/cnn_3dobj/include/opencv2/cnn_3dobj_config.hpp b/contrib/modules/cnn_3dobj/include/opencv2/cnn_3dobj_config.hpp
deleted file mode 100755
index e69de29..0000000
diff --git a/contrib/modules/cnn_3dobj/samples/CMakeLists.txt b/contrib/modules/cnn_3dobj/samples/CMakeLists.txt
deleted file mode 100755
index 6151f89..0000000
--- a/contrib/modules/cnn_3dobj/samples/CMakeLists.txt
+++ /dev/null
@@ -1,21 +0,0 @@
-cmake_minimum_required(VERSION 2.8)
-SET(CMAKE_CXX_FLAGS_DEBUG "$ENV{CXXFLAGS} -O0 -Wall -g -ggdb ")
-SET(CMAKE_CXX_FLAGS_RELEASE "$ENV{CXXFLAGS} -O3 -Wall")
-project(cnn_3dobj)
-find_package(OpenCV REQUIRED)
-set(SOURCES_generator demo_sphereview_data.cpp)
-include_directories(${OpenCV_INCLUDE_DIRS})
-add_executable(sphereview_test ${SOURCES_generator})
-target_link_libraries(sphereview_test opencv_core opencv_imgproc opencv_highgui opencv_cnn_3dobj opencv_xfeatures2d)
-
-set(SOURCES_classifier demo_classify.cpp)
-add_executable(classify_test ${SOURCES_classifier})
-target_link_libraries(classify_test opencv_core opencv_imgproc opencv_highgui opencv_cnn_3dobj opencv_xfeatures2d)
-
-set(SOURCES_modelanalysis demo_model_analysis.cpp)
-add_executable(model_test ${SOURCES_modelanalysis})
-target_link_libraries(model_test opencv_core opencv_imgproc opencv_highgui opencv_cnn_3dobj opencv_xfeatures2d)
-
-set(SOURCES_video demo_video.cpp)
-add_executable(video_test ${SOURCES_video})
-target_link_libraries(video_test opencv_core opencv_imgproc opencv_highgui opencv_cnn_3dobj opencv_xfeatures2d)
diff --git a/contrib/modules/cnn_3dobj/samples/classify.cpp b/contrib/modules/cnn_3dobj/samples/classify.cpp
new file mode 100755
index 0000000..978b9af
--- /dev/null
+++ b/contrib/modules/cnn_3dobj/samples/classify.cpp
@@ -0,0 +1,200 @@
+/*
+ * Software License Agreement (BSD License)
+ *
+ *  Copyright (c) 2009, Willow Garage, Inc.
+ *  All rights reserved.
+ *
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions
+ *  are met:
+ *
+ *   * Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *   * Redistributions in binary form must reproduce the above
+ *     copyright notice, this list of conditions and the following
+ *     disclaimer in the documentation and/or other materials provided
+ *     with the distribution.
+ *   * Neither the name of Willow Garage, Inc. nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ *  POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+/**
+ * @file demo_classify.cpp
+ * @brief Feature extraction and classification.
+ * @author Yida Wang
+ */
+#include <opencv2/cnn_3dobj.hpp>
+#include <opencv2/features2d.hpp>
+#include <iomanip>
+using namespace cv;
+using namespace std;
+using namespace cv::cnn_3dobj;
+
+/**
+ * @function listDir
+ * @brief Making all files names under a directory into a list
+ */
+static void listDir(const char *path, std::vector<String>& files, bool r)
+{
+    DIR *pDir;
+    struct dirent *ent;
+    char childpath[512];
+    pDir = opendir(path);
+    memset(childpath, 0, sizeof(childpath));
+    while ((ent = readdir(pDir)) != NULL)
+    {
+        if (ent->d_type & DT_DIR)
+        {
+            if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0 || strcmp(ent->d_name, ".DS_Store") == 0)
+            {
+                continue;
+            }
+            if (r)
+            {
+                sprintf(childpath, "%s/%s", path, ent->d_name);
+                listDir(childpath,files,false);
+            }
+        }
+        else
+        {
+            if (strcmp(ent->d_name, ".DS_Store") != 0)
+                files.push_back(ent->d_name);
+        }
+    }
+    sort(files.begin(),files.end());
+};
+
+/**
+ * @function featureWrite
+ * @brief Writing features of gallery images into binary files
+ */
+static int featureWrite(const Mat &features, const String &fname)
+{
+    ofstream ouF;
+    ouF.open(fname.c_str(), std::ofstream::binary);
+    if (!ouF)
+    {
+        cerr << "failed to open the file : " << fname << endl;
+        return 0;
+    }
+    for (int r = 0; r < features.rows; r++)
+    {
+        ouF.write(reinterpret_cast<const char*>(features.ptr(r)), features.cols*features.elemSize());
+    }
+    ouF.close();
+    return 1;
+}
+
+/**
+ * @function main
+ */
+int main(int argc, char** argv)
+{
+    const String keys = "{help | | This sample will extract features from reference images and target image for classification. You can add a mean_file if there little variance in data such as human faces, otherwise it is not so useful}"
+    "{src_dir | ../data/images_all/ | Source direction of the images ready for being used for extract feature as gallery.}"
+    "{caffemodel | ../../testdata/cv/3d_triplet_iter_30000.caffemodel | caffe model for feature exrtaction.}"
+    "{network_forIMG | ../../testdata/cv/3d_triplet_testIMG.prototxt | Network definition file used for extracting feature from a single image and making a classification}"
+    "{mean_file | no | The mean file generated by Caffe from all gallery images, this could be used for mean value substraction from all images. If you want to use the mean file, you can set this as ../data/images_mean/triplet_mean.binaryproto.}"
+    "{target_img | ../data/images_all/4_78.png | Path of image waiting to be classified.}"
+    "{feature_blob | feat | Name of layer which will represent as the feature, in this network, ip1 or feat is well.}"
+    "{num_candidate | 15 | Number of candidates in gallery as the prediction result.}"
+    "{device | CPU | Device type: CPU or GPU}"
+    "{dev_id | 0 | Device id}"
+    "{gallery_out | 0 | Option on output binary features on gallery images}";
+    /* get parameters from comand line */
+    cv::CommandLineParser parser(argc, argv, keys);
+    parser.about("Feature extraction and classification");
+    if (parser.has("help"))
+    {
+        parser.printMessage();
+        return 0;
+    }
+    String src_dir = parser.get<String>("src_dir");
+    String caffemodel = parser.get<String>("caffemodel");
+    String network_forIMG   = parser.get<String>("network_forIMG");
+    String mean_file    = parser.get<String>("mean_file");
+    String target_img   = parser.get<String>("target_img");
+    String feature_blob = parser.get<String>("feature_blob");
+    int num_candidate = parser.get<int>("num_candidate");
+    String device = parser.get<String>("device");
+    int gallery_out = parser.get<int>("gallery_out");
+    /* Initialize a net work with Device */
+    cv::cnn_3dobj::descriptorExtractor descriptor(device);
+    std::cout << "Using" << descriptor.getDeviceType() << std::endl;
+    /* Load net with the caffe trained net work parameter and structure */
+    if (strcmp(mean_file.c_str(), "no") == 0)
+        descriptor.loadNet(network_forIMG, caffemodel);
+    else
+        descriptor.loadNet(network_forIMG, caffemodel, mean_file);
+    std::vector<String> name_gallery;
+    /* List the file names under a given path */
+    listDir(src_dir.c_str(), name_gallery, false);
+    if (gallery_out)
+    {
+        ofstream namelist_out("gallelist.txt");
+        /* Writing name of the reference images. */
+        for (unsigned int i = 0; i < name_gallery.size(); i++)
+            namelist_out << name_gallery.at(i) << endl;
+    }
+    for (unsigned int i = 0; i < name_gallery.size(); i++)
+    {
+        name_gallery[i] = src_dir + name_gallery[i];
+    }
+    std::vector<cv::Mat> img_gallery;
+    cv::Mat feature_reference;
+    for (unsigned int i = 0; i < name_gallery.size(); i++)
+    {
+        img_gallery.push_back(cv::imread(name_gallery[i]));
+    }
+    /* Extract feature from a set of images */
+    descriptor.extract(img_gallery, feature_reference, feature_blob);
+    if (gallery_out)
+    {
+        std::cout << std::endl << "---------- Features of gallery images ----------" << std::endl;
+        /* Print features of the reference images. */
+        for (int i = 0; i < feature_reference.rows; i++)
+            std::cout << feature_reference.row(i) << endl;
+        std::cout << std::endl << "---------- Saving features of gallery images into feature.bin ----------" << std::endl;
+        featureWrite(feature_reference, "feature.bin");
+    }
+    else
+    {
+        std::cout << std::endl << "---------- Prediction for " << target_img << " ----------" << std::endl;
+        cv::Mat img = cv::imread(target_img);
+        std::cout << std::endl << "---------- Features of gallery images ----------" << std::endl;
+        std::vector<std::pair<String, float> > prediction;
+        /* Print features of the reference images. */
+        for (int i = 0; i < feature_reference.rows; i++)
+            std::cout << feature_reference.row(i) << endl;
+        cv::Mat feature_test;
+        descriptor.extract(img, feature_test, feature_blob);
+        /* Initialize a matcher which using L2 distance. */
+        cv::BFMatcher matcher(NORM_L2);
+        std::vector<std::vector<cv::DMatch> > matches;
+        /* Have a KNN match on the target and reference images. */
+        matcher.knnMatch(feature_test, feature_reference, matches, num_candidate);
+        /* Print feature of the target image waiting to be classified. */
+        std::cout << std::endl << "---------- Features of target image: " << target_img << "----------" << endl << feature_test << std::endl;
+        /* Print the top N prediction. */
+        std::cout << std::endl << "---------- Prediction result(Distance - File Name in Gallery) ----------" << std::endl;
+        for (size_t i = 0; i < matches[0].size(); ++i)
+        {
+            std::cout << i << " - " << std::fixed << std::setprecision(2) << name_gallery[matches[0][i].trainIdx] << " - \""  << matches[0][i].distance << "\"" << std::endl;
+        }
+    }
+    return 0;
+}
diff --git a/contrib/modules/cnn_3dobj/samples/demo_classify.cpp b/contrib/modules/cnn_3dobj/samples/demo_classify.cpp
deleted file mode 100755
index 5aa64ed..0000000
--- a/contrib/modules/cnn_3dobj/samples/demo_classify.cpp
+++ /dev/null
@@ -1,201 +0,0 @@
-/*
- * Software License Agreement (BSD License)
- *
- *  Copyright (c) 2009, Willow Garage, Inc.
- *  All rights reserved.
- *
- *  Redistribution and use in source and binary forms, with or without
- *  modification, are permitted provided that the following conditions
- *  are met:
- *
- *   * Redistributions of source code must retain the above copyright
- *     notice, this list of conditions and the following disclaimer.
- *   * Redistributions in binary form must reproduce the above
- *     copyright notice, this list of conditions and the following
- *     disclaimer in the documentation and/or other materials provided
- *     with the distribution.
- *   * Neither the name of Willow Garage, Inc. nor the names of its
- *     contributors may be used to endorse or promote products derived
- *     from this software without specific prior written permission.
- *
- *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
- *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- *  POSSIBILITY OF SUCH DAMAGE.
- *
- */
-/**
- * @file demo_classify.cpp
- * @brief Feature extraction and classification.
- * @author Yida Wang
- */
-#include <opencv2/cnn_3dobj.hpp>
-#include <opencv2/features2d/features2d.hpp>
-#include <iomanip>
-using namespace cv;
-using namespace std;
-using namespace cv::cnn_3dobj;
-
-/**
- * @function listDir
- * @brief Making all files names under a directory into a list
- */
-void listDir(const char *path, std::vector<String>& files, bool r)
-{
-    DIR *pDir;
-    struct dirent *ent;
-    char childpath[512];
-    pDir = opendir(path);
-    memset(childpath, 0, sizeof(childpath));
-    while ((ent = readdir(pDir)) != NULL)
-    {
-        if (ent->d_type & DT_DIR)
-        {
-            if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0 || strcmp(ent->d_name, ".DS_Store") == 0)
-            {
-                continue;
-            }
-            if (r)
-            {
-                sprintf(childpath, "%s/%s", path, ent->d_name);
-                listDir(childpath,files,false);
-            }
-        }
-        else
-        {
-            if (strcmp(ent->d_name, ".DS_Store") != 0)
-                files.push_back(ent->d_name);
-        }
-    }
-    sort(files.begin(),files.end());
-};
-
-/**
- * @function featureWrite
- * @brief Writing features of gallery images into binary files
- */
-int featureWrite(const Mat &features, const String &fname)
-{
-    ofstream ouF;
-    ouF.open(fname.c_str(), std::ofstream::binary);
-    if (!ouF)
-    {
-        cerr << "failed to open the file : " << fname << endl;
-        return 0;
-    }
-    for (int r = 0; r < features.rows; r++)
-    {
-        ouF.write(reinterpret_cast<const char*>(features.ptr(r)), features.cols*features.elemSize());
-    }
-    ouF.close();
-    return 1;
-}
-
-/**
- * @function main
- */
-int main(int argc, char** argv)
-{
-    const String keys = "{help | | This sample will extract features from reference images and target image for classification. You can add a mean_file if there little variance in data such as human faces, otherwise it is not so useful}"
-    "{src_dir | ../data/images_all/ | Source direction of the images ready for being used for extract feature as gallery.}"
-    "{caffemodel | ../../testdata/cv/3d_triplet_iter_30000.caffemodel | caffe model for feature exrtaction.}"
-    "{network_forIMG | ../../testdata/cv/3d_triplet_testIMG.prototxt | Network definition file used for extracting feature from a single image and making a classification}"
-    "{mean_file | no | The mean file generated by Caffe from all gallery images, this could be used for mean value substraction from all images. If you want to use the mean file, you can set this as ../data/images_mean/triplet_mean.binaryproto.}"
-    "{target_img | ../data/images_all/4_78.png | Path of image waiting to be classified.}"
-    "{feature_blob | feat | Name of layer which will represent as the feature, in this network, ip1 or feat is well.}"
-    "{num_candidate | 15 | Number of candidates in gallery as the prediction result.}"
-    "{device | CPU | Device type: CPU or GPU}"
-    "{dev_id | 0 | Device id}"
-    "{gallery_out | 0 | Option on output binary features on gallery images}";
-    /* get parameters from comand line */
-    cv::CommandLineParser parser(argc, argv, keys);
-    parser.about("Feature extraction and classification");
-    if (parser.has("help"))
-    {
-        parser.printMessage();
-        return 0;
-    }
-    String src_dir = parser.get<String>("src_dir");
-    String caffemodel = parser.get<String>("caffemodel");
-    String network_forIMG   = parser.get<String>("network_forIMG");
-    String mean_file    = parser.get<String>("mean_file");
-    String target_img   = parser.get<String>("target_img");
-    String feature_blob = parser.get<String>("feature_blob");
-    int num_candidate = parser.get<int>("num_candidate");
-    String device = parser.get<String>("device");
-    int dev_id = parser.get<int>("dev_id");
-    int gallery_out = parser.get<int>("gallery_out");
-    /* Initialize a net work with Device */
-    cv::cnn_3dobj::descriptorExtractor descriptor(device);
-    std::cout << "Using" << descriptor.getDeviceType() << std::endl;
-    /* Load net with the caffe trained net work parameter and structure */
-    if (strcmp(mean_file.c_str(), "no") == 0)
-        descriptor.loadNet(network_forIMG, caffemodel);
-    else
-        descriptor.loadNet(network_forIMG, caffemodel, mean_file);
-    std::vector<String> name_gallery;
-    /* List the file names under a given path */
-    listDir(src_dir.c_str(), name_gallery, false);
-    if (gallery_out)
-    {
-        ofstream namelist_out("gallelist.txt");
-        /* Writing name of the reference images. */
-        for (unsigned int i = 0; i < name_gallery.size(); i++)
-            namelist_out << name_gallery.at(i) << endl;
-    }
-    for (unsigned int i = 0; i < name_gallery.size(); i++)
-    {
-        name_gallery[i] = src_dir + name_gallery[i];
-    }
-    std::vector<cv::Mat> img_gallery;
-    cv::Mat feature_reference;
-    for (unsigned int i = 0; i < name_gallery.size(); i++)
-    {
-        img_gallery.push_back(cv::imread(name_gallery[i]));
-    }
-    /* Extract feature from a set of images */
-    descriptor.extract(img_gallery, feature_reference, feature_blob);
-    if (gallery_out)
-    {
-        std::cout << std::endl << "---------- Features of gallery images ----------" << std::endl;
-        /* Print features of the reference images. */
-        for (unsigned int i = 0; i < feature_reference.rows; i++)
-            std::cout << feature_reference.row(i) << endl;
-        std::cout << std::endl << "---------- Saving features of gallery images into feature.bin ----------" << std::endl;
-        featureWrite(feature_reference, "feature.bin");
-    }
-    else
-    {
-        std::cout << std::endl << "---------- Prediction for " << target_img << " ----------" << std::endl;
-        cv::Mat img = cv::imread(target_img);
-        std::cout << std::endl << "---------- Features of gallery images ----------" << std::endl;
-        std::vector<std::pair<String, float> > prediction;
-        /* Print features of the reference images. */
-        for (unsigned int i = 0; i < feature_reference.rows; i++)
-            std::cout << feature_reference.row(i) << endl;
-        cv::Mat feature_test;
-        descriptor.extract(img, feature_test, feature_blob);
-        /* Initialize a matcher which using L2 distance. */
-        cv::BFMatcher matcher(NORM_L2);
-        std::vector<std::vector<cv::DMatch> > matches;
-        /* Have a KNN match on the target and reference images. */
-        matcher.knnMatch(feature_test, feature_reference, matches, num_candidate);
-        /* Print feature of the target image waiting to be classified. */
-        std::cout << std::endl << "---------- Features of target image: " << target_img << "----------" << endl << feature_test << std::endl;
-        /* Print the top N prediction. */
-        std::cout << std::endl << "---------- Prediction result(Distance - File Name in Gallery) ----------" << std::endl;
-        for (size_t i = 0; i < matches[0].size(); ++i)
-        {
-            std::cout << i << " - " << std::fixed << std::setprecision(2) << name_gallery[matches[0][i].trainIdx] << " - \""  << matches[0][i].distance << "\"" << std::endl;
-        }
-    }
-    return 0;
-}
\ No newline at end of file
diff --git a/contrib/modules/cnn_3dobj/samples/demo_sphereview_data.cpp b/contrib/modules/cnn_3dobj/samples/demo_sphereview_data.cpp
deleted file mode 100755
index 4f12e03..0000000
--- a/contrib/modules/cnn_3dobj/samples/demo_sphereview_data.cpp
+++ /dev/null
@@ -1,333 +0,0 @@
-/*
- * Software License Agreement (BSD License)
- *
- *  Copyright (c) 2009, Willow Garage, Inc.
- *  All rights reserved.
- *
- *  Redistribution and use in source and binary forms, with or without
- *  modification, are permitted provided that the following conditions
- *  are met:
- *
- *   * Redistributions of source code must retain the above copyright
- *     notice, this list of conditions and the following disclaimer.
- *   * Redistributions in binary form must reproduce the above
- *     copyright notice, this list of conditions and the following
- *     disclaimer in the documentation and/or other materials provided
- *     with the distribution.
- *   * Neither the name of Willow Garage, Inc. nor the names of its
- *     contributors may be used to endorse or promote products derived
- *     from this software without specific prior written permission.
- *
- *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
- *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- *  POSSIBILITY OF SUCH DAMAGE.
- *
- */
-/**
- * @file demo_sphereview_data.cpp
- * @brief Generating training data for CNN with triplet loss.
- * @author Yida Wang
- */
-#include <opencv2/cnn_3dobj.hpp>
-#include <opencv2/viz/vizcore.hpp>
-#include <iostream>
-#include <stdlib.h>
-#include <time.h>
-using namespace cv;
-using namespace std;
-using namespace cv::cnn_3dobj;
-
-/**
- * @function listDir
- * @brief Making all files names under a directory into a list
- */
-void listDir(const char *path, std::vector<String>& files, bool r)
-{
-    DIR *pDir;
-    struct dirent *ent;
-    char childpath[512];
-    pDir = opendir(path);
-    memset(childpath, 0, sizeof(childpath));
-    while ((ent = readdir(pDir)) != NULL)
-    {
-        if (ent->d_type & DT_DIR)
-        {
-            if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0 || strcmp(ent->d_name, ".DS_Store") == 0)
-            {
-                continue;
-            }
-            if (r)
-            {
-                sprintf(childpath, "%s/%s", path, ent->d_name);
-                listDir(childpath,files,false);
-            }
-        }
-        else
-        {
-            if (strcmp(ent->d_name, ".DS_Store") != 0)
-                files.push_back(ent->d_name);
-        }
-    }
-    sort(files.begin(),files.end());
-};
-
-int main(int argc, char *argv[])
-{
-    const String keys = "{help | | demo :$ ./sphereview_test -ite_depth=2 -plymodel=../data/3Dmodel/ape.ply -imagedir=../data/images_all/ -labeldir=../data/label_all.txt -num_class=6 -label_class=0, then press 'q' to run the demo for images generation when you see the gray background and a coordinate.}"
-    "{ite_depth | 3 | Iteration of sphere generation.}"
-    "{plymodel | ../data/3Dmodel/ape.ply | Path of the '.ply' file for image rendering. }"
-    "{imagedir | ../data/images_all/ | Path of the generated images for one particular .ply model. }"
-    "{labeldir | ../data/label_all.txt | Path of the generated images for one particular .ply model. }"
-    "{bakgrdir | | Path of the backgroud images sets. }"
-    "{cam_head_x | 0 | Head of the camera. }"
-    "{cam_head_y | 0 | Head of the camera. }"
-    "{cam_head_z | -1 | Head of the camera. }"
-    "{semisphere | 1 | Camera only has positions on half of the whole sphere. }"
-    "{z_range | 0.6 | Maximum camera position on z axis. }"
-    "{center_gen | 0 | Find center from all points. }"
-    "{image_size | 128 | Size of captured images. }"
-    "{label_class |  | Class label of current .ply model. }"
-    "{label_item |  | Item label of current .ply model. }"
-    "{rgb_use | 0 | Use RGB image or grayscale. }"
-    "{num_class | 6 | Total number of classes of models. }"
-    "{binary_out | 0 | Produce binaryfiles for images and label. }"
-    "{view_region | 0 | Take a special view of front or back angle}";
-    /* Get parameters from comand line. */
-    cv::CommandLineParser parser(argc, argv, keys);
-    parser.about("Generating training data for CNN with triplet loss");
-    if (parser.has("help"))
-    {
-        parser.printMessage();
-        return 0;
-    }
-    int ite_depth = parser.get<int>("ite_depth");
-    String plymodel = parser.get<String>("plymodel");
-    String imagedir = parser.get<String>("imagedir");
-    string labeldir = parser.get<String>("labeldir");
-    String bakgrdir = parser.get<string>("bakgrdir");
-    int label_class = parser.get<int>("label_class");
-    int label_item = parser.get<int>("label_item");
-    float cam_head_x = parser.get<float>("cam_head_x");
-    float cam_head_y = parser.get<float>("cam_head_y");
-    float cam_head_z = parser.get<float>("cam_head_z");
-    int semisphere = parser.get<int>("semisphere");
-    float z_range = parser.get<float>("z_range");
-    int center_gen = parser.get<int>("center_gen");
-    int image_size = parser.get<int>("image_size");
-    int rgb_use = parser.get<int>("rgb_use");
-    int num_class = parser.get<int>("num_class");
-    int binary_out = parser.get<int>("binary_out");
-    int view_region = parser.get<int>("view_region");
-    double obj_dist, bg_dist, y_range;
-    if (view_region == 1 || view_region == 2)
-    {
-        /* Set for TV */
-        if (label_class == 12)
-            obj_dist = 340;
-        else
-            obj_dist = 250;
-        ite_depth = ite_depth + 1;
-        bg_dist = 700;
-        y_range = 0.85;
-    }
-    else if (view_region == 0)
-    {
-        obj_dist = 370;
-        bg_dist = 400;
-    }
-    if (label_class == 5 | label_class == 10 | label_class == 11 | label_class == 12)
-        ite_depth = ite_depth + 1;
-    cv::cnn_3dobj::icoSphere ViewSphere(10,ite_depth);
-    std::vector<cv::Point3d> campos;
-    std::vector<cv::Point3d> campos_temp = ViewSphere.CameraPos;
-    /* Regular objects on the ground using a semisphere view system */
-    if (semisphere == 1)
-    {
-        if (view_region == 1)
-        {
-            for (int pose = 0; pose < static_cast<int>(campos_temp.size()); pose++)
-            {
-                if (campos_temp.at(pose).z >= 0 && campos_temp.at(pose).z < z_range && campos_temp.at(pose).y < -y_range)
-                    campos.push_back(campos_temp.at(pose));
-            }
-        }
-        else if (view_region == 2)
-        {
-            for (int pose = 0; pose < static_cast<int>(campos_temp.size()); pose++)
-            {
-                if (campos_temp.at(pose).z >= 0 && campos_temp.at(pose).z < z_range && campos_temp.at(pose).y > y_range)
-                campos.push_back(campos_temp.at(pose));
-            }
-        }
-        else
-        {
-            /* Set for sofa */
-            if (label_class == 10)
-            {
-                for (int pose = 0; pose < static_cast<int>(campos_temp.size()); pose++)
-                {
-                    if (campos_temp.at(pose).z >= 0 && campos_temp.at(pose).z < z_range && campos_temp.at(pose).y < -0.4)
-                    campos.push_back(campos_temp.at(pose));
-                }
-            }
-            else
-            {
-                for (int pose = 0; pose < static_cast<int>(campos_temp.size()); pose++)
-                {
-                    if (campos_temp.at(pose).z >= 0 && campos_temp.at(pose).z < z_range)
-                        campos.push_back(campos_temp.at(pose));
-                }
-            }
-        }
-    }
-    /* Special object such as plane using a full space of view sphere */
-    else
-    {
-        if (view_region == 1)
-        {
-            for (int pose = 0; pose < static_cast<int>(campos_temp.size()); pose++)
-            {
-                if (campos_temp.at(pose).z < 0.2 && campos_temp.at(pose).z > -0.2 && campos_temp.at(pose).y < -y_range)
-                    campos.push_back(campos_temp.at(pose));
-            }
-        }
-        else if (view_region == 2)
-        {
-            for (int pose = 0; pose < static_cast<int>(campos_temp.size()); pose++)
-            {
-                if (campos_temp.at(pose).z < 0.2 && campos_temp.at(pose).z > -0.2 && campos_temp.at(pose).y > y_range)
-                campos.push_back(campos_temp.at(pose));
-            }
-        }
-        else
-        {
-            for (int pose = 0; pose < static_cast<int>(campos_temp.size()); pose++)
-            {
-                if (campos_temp.at(pose).z < 0.2 && campos_temp.at(pose).z > -0.6)
-                    campos.push_back(campos_temp.at(pose));
-            }
-        }
-    }
-    std::fstream imglabel;
-    char* p=(char*)labeldir.data();
-    imglabel.open(p, fstream::app|fstream::out);
-    bool camera_pov = true;
-    /* Create a window using viz. */
-    viz::Viz3d myWindow("Coordinate Frame");
-    /* Set window size. */
-    myWindow.setWindowSize(Size(image_size,image_size));
-    /* Set background color. */
-    myWindow.setBackgroundColor(viz::Color::gray());
-    myWindow.spin();
-    /* Create a Mesh widget, loading .ply models. */
-    viz::Mesh objmesh = viz::Mesh::load(plymodel);
-    /* Get the center of the generated mesh widget, cause some .ply files, this could be ignored if you are using PASCAL database*/
-    Point3d cam_focal_point;
-    if (center_gen)
-        cam_focal_point = ViewSphere.getCenter(objmesh.cloud);
-    else
-        cam_focal_point = Point3d(0,0,0);
-    const char* headerPath = "../data/header_for_";
-    const char* binaryPath = "../data/binary_";
-    if (binary_out)
-    {
-        ViewSphere.createHeader(static_cast<int>(campos.size()), image_size, image_size, headerPath);
-    }
-    float radius = ViewSphere.getRadius(objmesh.cloud, cam_focal_point);
-    objmesh.cloud = objmesh.cloud/radius*100;
-    cam_focal_point = cam_focal_point/radius*100;
-    Point3d cam_y_dir;
-    cam_y_dir.x = cam_head_x;
-    cam_y_dir.y = cam_head_y;
-    cam_y_dir.z = cam_head_z;
-    char* temp = new char;
-    char* bgname = new char;
-    std::vector<String> name_bkg;
-    if (bakgrdir.size() != 0)
-    {
-        /* List the file names under a given path */
-        listDir(bakgrdir.c_str(), name_bkg, false);
-        for (unsigned int i = 0; i < name_bkg.size(); i++)
-        {
-            name_bkg.at(i) = bakgrdir + name_bkg.at(i);
-        }
-    }
-    /* Images will be saved as .png files. */
-    int cnt_img;
-    srand((int)time(0));
-    do
-    {
-        cnt_img = 0;
-        for(int pose = 0; pose < static_cast<int>(campos.size()); pose++){
-            /* Add light. */
-            // double alpha1 = rand()%(314/2)/100;
-            // double alpha2 = rand()%(314*2)/100;
-            // printf("%f %f %f/n", ceil(10000*sqrt(1 - sin(alpha1)*sin(alpha1))*sin(alpha2)), 10000*sqrt(1 - sin(alpha1)*sin(alpha1))*cos(alpha2), sin(alpha1)*10000);
-            // myWindow.addLight(Vec3d(10000*sqrt(1 - sin(alpha1)*sin(alpha1))*sin(alpha2),10000*sqrt(1 - sin(alpha1)*sin(alpha1))*cos(alpha2),sin(alpha1)*10000), Vec3d(0,0,0), viz::Color::white(), viz::Color::white(), viz::Color::black(), viz::Color::white());
-            int label_x, label_y, label_z;
-            label_x = static_cast<int>(campos.at(pose).x*100);
-            label_y = static_cast<int>(campos.at(pose).y*100);
-            label_z = static_cast<int>(campos.at(pose).z*100);
-            sprintf (temp,"%02i_%02i_%04i_%04i_%04i_%02i", label_class, label_item, label_x, label_y, label_z, static_cast<int>(obj_dist/100));
-            String filename = temp;
-            filename += ".png";
-            imglabel << filename << ' ' << label_class << endl;
-            filename = imagedir + filename;
-            /* Get the pose of the camera using makeCameraPoses. */
-            if (view_region != 0)
-            {
-                cam_focal_point.x = cam_focal_point.y - label_x/5;
-            }
-            Affine3f cam_pose = viz::makeCameraPose(campos.at(pose)*obj_dist+cam_focal_point, cam_focal_point, cam_y_dir*obj_dist+cam_focal_point);
-            /* Get the transformation matrix from camera coordinate system to global. */
-            Affine3f transform = viz::makeTransformToGlobal(Vec3f(1.0f,0.0f,0.0f), Vec3f(0.0f,1.0f,0.0f), Vec3f(0.0f,0.0f,1.0f), campos.at(pose));
-            viz::WMesh mesh_widget(objmesh);
-            /* Pose of the widget in camera frame. */
-            Affine3f cloud_pose = Affine3f().translate(Vec3f(1.0f,1.0f,1.0f));
-            /* Pose of the widget in global frame. */
-            Affine3f cloud_pose_global = transform * cloud_pose;
-            /* Visualize camera frame. */
-            if (!camera_pov)
-            {
-                viz::WCameraPosition cpw(1); // Coordinate axes
-                viz::WCameraPosition cpw_frustum(Vec2f(0.5, 0.5)); // Camera frustum
-                myWindow.showWidget("CPW", cpw, cam_pose);
-                myWindow.showWidget("CPW_FRUSTUM", cpw_frustum, cam_pose);
-            }
-
-            /* Visualize widget. */
-            if (bakgrdir.size() != 0)
-            {
-                cv::Mat img_bg = cv::imread(name_bkg.at(rand()%name_bkg.size()));
-                /* Back ground images has a distance of 2 times of radius of camera view distance */
-                cv::viz::WImage3D background_widget(img_bg, Size2d(image_size*4.2, image_size*4.2), Vec3d(-campos.at(pose)*bg_dist+cam_focal_point), Vec3d(campos.at(pose)*bg_dist-cam_focal_point), Vec3d(0,0,-1)*bg_dist+Vec3d(0,2*cam_focal_point.y,0));
-                myWindow.showWidget("bgwidget", background_widget, cloud_pose_global);
-            }
-            // mesh_widget.setRenderingProperty(viz::LINE_WIDTH, 4.0);
-            myWindow.showWidget("targetwidget", mesh_widget, cloud_pose_global);
-
-            /* Set the viewer pose to that of camera. */
-            if (camera_pov)
-                myWindow.setViewerPose(cam_pose);
-            /* Save screen shot as images. */
-            myWindow.saveScreenshot(filename);
-            if (binary_out)
-            {
-            /* Write images into binary files for further using in CNN training. */
-                ViewSphere.writeBinaryfile(filename, binaryPath, headerPath,static_cast<int>(campos.size())*num_class, label_class, static_cast<int>(campos.at(pose).x*100), static_cast<int>(campos.at(pose).y*100), static_cast<int>(campos.at(pose).z*100), rgb_use);
-            }
-            cnt_img++;
-        }
-    } while (cnt_img != campos.size());
-    imglabel.close();
-    return 1;
-};
diff --git a/contrib/modules/cnn_3dobj/samples/demo_video.cpp b/contrib/modules/cnn_3dobj/samples/demo_video.cpp
deleted file mode 100755
index 5f603d0..0000000
--- a/contrib/modules/cnn_3dobj/samples/demo_video.cpp
+++ /dev/null
@@ -1,391 +0,0 @@
-#include <opencv2/viz/vizcore.hpp>
-#include <opencv2/calib3d/calib3d.hpp>
-#include <iostream>
-#include <fstream>
-#include <opencv2/cnn_3dobj.hpp>
-#include <opencv2/features2d/features2d.hpp>
-#include <iomanip>
-using namespace cv;
-using namespace std;
-using namespace cv::cnn_3dobj;
-/**
- * @function listDir
- * @brief Making all files names under a directory into a list
- */
-void listDir(const char *path, std::vector<String>& files, bool r)
-{
-    DIR *pDir;
-    struct dirent *ent;
-    char childpath[512];
-    pDir = opendir(path);
-    memset(childpath, 0, sizeof(childpath));
-    while ((ent = readdir(pDir)) != NULL)
-    {
-        if (ent->d_type & DT_DIR)
-        {
-            if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
-            {
-                continue;
-            }
-            if(r)
-            {
-                sprintf(childpath, "%s/%s", path, ent->d_name);
-                listDir(childpath,files,false);
-            }
-        }
-        else
-        {
-            files.push_back(ent->d_name);
-        }
-    }
-    sort(files.begin(),files.end());
-};
-
-
-/**
- * @function cvcloud_load
- * @brief load bunny.ply
- */
-Mat cvcloud_load(Mat feature_reference)
-{
-    Mat cloud(1, feature_reference.rows, CV_32FC3);
-    Point3f* data = cloud.ptr<cv::Point3f>();
-    float dummy1, dummy2;
-    for(size_t i = 0; i < feature_reference.rows; ++i)
-    {
-        data[i].x = feature_reference.at<float>(i,0);
-        data[i].y = feature_reference.at<float>(i,1);
-        data[i].z = feature_reference.at<float>(i,2);
-    }
-    cloud *= 5.0f;
-    return cloud;
-}
-
-/**
- * @function main
- */
-int main(int argc, char **argv)
-{
-    const String keys = "{help | | This sample will extract featrues from reference images and target image for classification. You can add a mean_file if there little variance in data such as human faces, otherwise it is not so useful}"
-    "{src_dir | ../data/images_all/ | Source direction of the images ready for being used for extract feature as gallery.}"
-    "{caffemodellist | ../../testdata/cv/caffemodel_list.txt | caffe model for feature exrtaction.}"
-    "{network_forIMG | ../../testdata/cv/3d_triplet_testIMG.prototxt | Network definition file used for extracting feature from a single image and making a classification}"
-    "{mean_file | no | The mean file generated by Caffe from all gallery images, this could be used for mean value substraction from all images. If you want to use the mean file, you can set this as ../data/images_mean/triplet_mean.binaryproto.}"
-    "{target_img1 | ../data/images_all/0_48.png | Path of image waiting to be classified.}"
-    "{target_img2 | ../data/images_all/1_339.png | Path of image waiting to be classified.}"
-    "{target_img3 | ../data/images_all/2_296.png | Path of image waiting to be classified.}"
-    "{target_img4 | ../data/images_all/3_466.png | Path of image waiting to be classified.}"
-    "{target_img5 | ../data/images_all/4_117.png | Path of image waiting to be classified.}"
-    "{target_img6 | ../data/images_all/5_236.png | Path of image waiting to be classified.}"
-    "{feature_blob | feat | Name of layer which will represent as the feature, in this network, ip1 or feat is well.}"
-    "{num_candidate | 4 | Number of candidates in gallery as the prediction result.}"
-    "{device | CPU | Device type: CPU or GPU}"
-    "{dev_id | 0 | Device id}";
-    /* get parameters from comand line */
-    cv::CommandLineParser parser(argc, argv, keys);
-    parser.about("Feature extraction and classification");
-    if (parser.has("help"))
-    {
-        parser.printMessage();
-        return 0;
-    }
-    String src_dir = parser.get<String>("src_dir");
-    String caffemodellist = parser.get<String>("caffemodellist");
-    String network_forIMG   = parser.get<String>("network_forIMG");
-    String mean_file    = parser.get<String>("mean_file");
-    String target_img1   = parser.get<String>("target_img1");
-    String target_img2   = parser.get<String>("target_img2");
-    String target_img3   = parser.get<String>("target_img3");
-    String target_img4   = parser.get<String>("target_img4");
-    String target_img5   = parser.get<String>("target_img5");
-    String target_img6   = parser.get<String>("target_img6");
-    String feature_blob = parser.get<String>("feature_blob");
-    int num_candidate = parser.get<int>("num_candidate");
-    String device = parser.get<String>("device");
-    int dev_id = parser.get<int>("dev_id");
-    ifstream namelist_model(caffemodellist.c_str(), ios::in);
-    vector<String> caffemodel;
-    char *buf = new char[512];
-    int number_model = 0;
-    while (!namelist_model.eof())
-    {
-        namelist_model.getline(buf, 512);
-        caffemodel.push_back(buf);
-        number_model++;
-    }
-    /* List the file names under a given path */
-    std::vector<String> name_gallery;
-    listDir(src_dir.c_str(), name_gallery, false);
-    for (unsigned int i = 0; i < name_gallery.size(); i++)
-    {
-        name_gallery[i] = src_dir + name_gallery[i];
-    }
-    std::vector<cv::Mat> img_gallery;
-    cv::Mat temp_feat;
-    vector<cv::Mat> feature_reference;
-    vector<cv::Mat> feature_test1;
-    vector<cv::Mat> feature_test2;
-    vector<cv::Mat> feature_test3;
-    vector<cv::Mat> feature_test4;
-    vector<cv::Mat> feature_test5;
-    vector<cv::Mat> feature_test6;
-    cv::Mat img_test1 = cv::imread(target_img1, -1);
-    cv::Mat img_test2 = cv::imread(target_img2, -1);
-    cv::Mat img_test3 = cv::imread(target_img3, -1);
-    cv::Mat img_test4 = cv::imread(target_img4, -1);
-    cv::Mat img_test5 = cv::imread(target_img5, -1);
-    cv::Mat img_test6 = cv::imread(target_img6, -1);
-    for (int num_model = 0; num_model < number_model; ++num_model)
-    {
-        feature_reference.push_back(temp_feat);
-        feature_test1.push_back(temp_feat);
-        feature_test2.push_back(temp_feat);
-        feature_test3.push_back(temp_feat);
-        feature_test4.push_back(temp_feat);
-        feature_test5.push_back(temp_feat);
-        feature_test6.push_back(temp_feat);
-    }
-    for (unsigned int i = 0; i < name_gallery.size(); i++)
-    {
-        img_gallery.push_back(cv::imread(name_gallery[i], -1));
-    }
-    /* Initialize a net work with Device */
-    cv::cnn_3dobj::descriptorExtractor descriptor(device);
-    std::cout << "Using" << descriptor.getDeviceType() << std::endl;
-    /* Load net with the caffe trained net work parameter and structure */
-    for (int num_model = 0; num_model < number_model; ++num_model)
-    {
-        if (strcmp(mean_file.c_str(), "no") == 0)
-            descriptor.loadNet(network_forIMG, caffemodel[num_model]);
-        else
-            descriptor.loadNet(network_forIMG, caffemodel[num_model], mean_file);
-        /* Part1: Extract feature from a set of images and a single image*/
-        descriptor.extract(img_gallery, feature_reference[num_model], feature_blob);
-        descriptor.extract(img_test1, feature_test1[num_model], feature_blob);
-        descriptor.extract(img_test2, feature_test2[num_model], feature_blob);
-        descriptor.extract(img_test3, feature_test3[num_model], feature_blob);
-        descriptor.extract(img_test4, feature_test4[num_model], feature_blob);
-        descriptor.extract(img_test5, feature_test5[num_model], feature_blob);
-        descriptor.extract(img_test6, feature_test6[num_model], feature_blob);
-    }
-    /* Initialize a matcher which using L2 distance. */
-    cv::BFMatcher matcher(NORM_L2);
-    vector<vector<vector<cv::DMatch> > > matches1;
-    vector<vector<vector<cv::DMatch> > > matches2;
-    vector<vector<vector<cv::DMatch> > > matches3;
-    vector<vector<vector<cv::DMatch> > > matches4;
-    vector<vector<vector<cv::DMatch> > > matches5;
-    vector<vector<vector<cv::DMatch> > > matches6;
-    vector<vector<cv::DMatch> > matches_temp;
-    for (int num_model = 0; num_model < number_model; ++num_model)
-    {
-        matches1.push_back(matches_temp);
-        matches2.push_back(matches_temp);
-        matches3.push_back(matches_temp);
-        matches4.push_back(matches_temp);
-        matches5.push_back(matches_temp);
-        matches6.push_back(matches_temp);
-    }
-    /* Have a KNN match on the target and reference images. */
-    for (int num_model = 0; num_model < number_model; ++num_model)
-    {
-        matcher.knnMatch(feature_test1[num_model], feature_reference[num_model], matches1[num_model], num_candidate+1);
-        matcher.knnMatch(feature_test2[num_model], feature_reference[num_model], matches2[num_model], num_candidate+1);
-        matcher.knnMatch(feature_test3[num_model], feature_reference[num_model], matches3[num_model], num_candidate+1);
-        matcher.knnMatch(feature_test4[num_model], feature_reference[num_model], matches4[num_model], num_candidate+1);
-        matcher.knnMatch(feature_test5[num_model], feature_reference[num_model], matches5[num_model], num_candidate+1);
-        matcher.knnMatch(feature_test6[num_model], feature_reference[num_model], matches6[num_model], num_candidate+1);
-    }
-    vector<Mat> img_merge;
-    /* Part2: Start to have a show */
-    bool camera_pov = true;
-    viz::Viz3d myWindow0("Instruction");
-    viz::Viz3d myWindow1("Point Cloud");
-    viz::Viz3d myWindow2("Prediction sample");
-    /* Set window size as 1024*1024, we use this scale as default. */
-    myWindow0.setWindowSize(Size(1300,100));
-    myWindow0.setWindowPosition(Point(0,800));
-    myWindow1.setWindowSize(Size(700,600));
-    myWindow1.setWindowPosition(Point(600,0));
-    myWindow2.setWindowSize(Size(600,600));
-    myWindow2.setWindowPosition(Point(-20,0));
-    /* Pose of the widget in camera frame */
-    Affine3f cloud_pose = Affine3f().translate(Vec3f(1.0f,1.0f,1.0f));
-    Point3d campos(1,0,0);
-    /* Get the transformation matrix from camera coordinate system to global. */
-    Affine3f transform = viz::makeTransformToGlobal(Vec3f(1.0f,0.0f,0.0f), Vec3f(0.0f,1.0f,0.0f), Vec3f(0.0f,0.0f,1.0f), campos);
-    /* Pose of the widget in global frame */
-    Affine3f cloud_pose_global = transform * cloud_pose;
-    /* Set background color. */
-    myWindow0.setBackgroundColor(viz::Color::white());
-    myWindow1.setBackgroundColor(viz::Color::white());
-    myWindow2.setBackgroundColor(viz::Color::white());
-    Point3d cam_y_dir(0.0f,0.0f,1.0f);
-    cv::cnn_3dobj::icoSphere ViewSphere(1,0);
-    Mat bunny_cloud;
-    Point3d cam_focal_point;
-    float radius;
-    float translation_phase = 0.0;
-    int count_pre, num_rotate, max_rotate;
-    String titlename, Hint, Pred("prediction: ");
-    vector<viz::WImageOverlay> imagepredict;
-    String widgename[24] = {"1","2","3","4","5","6","7","8","9","10","11","12","13","14","15","16","17","18","19","20","21","22","23","24"};
-    vector<Mat> slide;
-    slide.push_back(imread("1.png"));
-    slide.push_back(imread("2.png"));
-    slide.push_back(imread("3.png"));
-    slide.push_back(imread("4.png"));
-    slide.push_back(imread("5.png"));
-    slide.push_back(imread("6.png"));
-    slide.push_back(imread("7.png"));
-    slide.push_back(imread("8.png"));
-    slide.push_back(imread("9.png"));
-    slide.push_back(imread("10.png"));
-    /// Create a window
-    viz::Viz3d myWindowS("Slide Show");
-    myWindowS.setWindowSize(Size(1300,700));
-    myWindowS.setWindowPosition(Point(0,0));
-    myWindowS.setBackgroundColor(viz::Color::white());
-    for (int i = 0; i < slide.size(); ++i)
-    {
-        /// Create a triangle widget
-        viz::WImageOverlay slide1(slide[i],Rect(0, 0, 1300, 700));
-        /// Show widget in the visualizer window
-        num_rotate = 0;
-        if (i == 0)
-            max_rotate = 2000;
-        else
-            max_rotate = 230;
-        while (num_rotate != max_rotate)
-        {
-            myWindowS.showWidget("Slide1", slide1);
-            /// Start event loop
-            myWindowS.spinOnce(1, true);
-            num_rotate++;
-        }
-    }
-    for (int num_model = 0; num_model < number_model; ++num_model)
-    {
-        if (num_model == 0)
-            Hint = "Start training.";
-        else if (num_model == 28)
-            Hint = "Different Classes Are Clustered.";
-        else if(num_model == 40)
-            Hint = "Poses Are Set apart.";
-        else if(num_model == 42)
-            Hint = "Finished. Model could: tell both classes and poses.";
-        titlename = caffemodel[num_model];
-        titlename = "Prediction Result of Model Trained on Iteration " + titlename.substr(34, titlename.length() - 44);
-        viz::WText title(titlename, Point(100, 50), 30, viz::Color::black());
-        viz::WText hint(Hint, Point(400, 20), 25, viz::Color::black());
-        viz::WImageOverlay image3d1(img_test1, Rect(20, 40, img_test4.rows, img_test4.cols));
-        viz::WText arrow1(Pred, Point(90,60), 15, viz::Color::red());
-        viz::WImageOverlay image3d2(img_test2, Rect(20, 40+75, img_test4.rows, img_test4.cols));
-        viz::WText arrow2(Pred, Point(90,60+75), 15, viz::Color::green());
-        viz::WImageOverlay image3d3(img_test3, Rect(20, 40+75*2, img_test4.rows, img_test4.cols));
-        viz::WText arrow3(Pred, Point(90,60+75*2), 15, viz::Color::purple());
-        viz::WImageOverlay image3d4(img_test4, Rect(20, 40+75*3, img_test4.rows, img_test4.cols));
-        viz::WText arrow4(Pred, Point(90,60+75*3), 15, viz::Color::blue());
-        viz::WImageOverlay image3d5(img_test5, Rect(20, 40+75*4, img_test4.rows, img_test4.cols));
-        viz::WText arrow5(Pred, Point(90,60+75*4), 15, viz::Color::yellow());
-        viz::WImageOverlay image3d6(img_test6, Rect(20, 40+75*5, img_test4.rows, img_test4.cols));
-        viz::WText arrow6(Pred, Point(90,60+75*5), 15, viz::Color::orange());
-        viz::WText text_target(String("Query Image"), Point2d(20,530), 20, viz::Color::purple());
-        viz::WText text_pred(String("Predicted Images using 4 NN"), Point2d(80+110,530), 20, viz::Color::purple());
-        viz::WText text3d1(String("1st"), Point2d(80 + 110,500), 20, viz::Color::orange());
-        viz::WText text3d2(String("2nd"), Point2d(80 + 2*110,500), 20, viz::Color::orange());
-        viz::WText text3d3(String("3rd"), Point2d(80 + 3*110,500), 20, viz::Color::orange());
-        viz::WText text3d4(String("4th"), Point2d(80 + 4*110,500), 20, viz::Color::orange());
-        viz::WText classname1(String("ape: red"), Point2d(20,10), 11, viz::Color::red());
-        viz::WText classname2(String("ant: green"), Point2d(120,10), 11, viz::Color::green());
-        viz::WText classname3(String("cow: purple"), Point2d(220,10), 11, viz::Color::purple());
-        viz::WText classname4(String("plane: blue"), Point2d(320,10), 11, viz::Color::blue());
-        viz::WText classname5(String("bunny: yellow"), Point2d(420,10), 11, viz::Color::yellow());
-        viz::WText classname6(String("horse: orange"), Point2d(500,10), 11, viz::Color::orange());
-        myWindow0.showWidget("title", title, Affine3f().translate(Vec3f(0.0f,0.0f,0.0f)));
-        myWindow0.showWidget("hint", hint, Affine3f().translate(Vec3f(0.0f,0.0f,0.0f)));
-        myWindow2.showWidget("image3d1", image3d1, Affine3f().translate(Vec3f(1.0f,1.0f,1.0f)));
-        myWindow2.showWidget("image3d2", image3d2, Affine3f().translate(Vec3f(1.0f,1.0f,1.0f)));
-        myWindow2.showWidget("image3d3", image3d3, Affine3f().translate(Vec3f(1.0f,1.0f,1.0f)));
-        myWindow2.showWidget("image3d4", image3d4, Affine3f().translate(Vec3f(1.0f,1.0f,1.0f)));
-        myWindow2.showWidget("image3d5", image3d5, Affine3f().translate(Vec3f(1.0f,1.0f,1.0f)));
-        myWindow2.showWidget("image3d6", image3d6, Affine3f().translate(Vec3f(1.0f,1.0f,1.0f)));
-        myWindow2.showWidget("arrow1", arrow1, Affine3f().translate(Vec3f(1.0f,1.0f,1.0f)));
-        myWindow2.showWidget("arrow2", arrow2, Affine3f().translate(Vec3f(1.0f,1.0f,1.0f)));
-        myWindow2.showWidget("arrow3", arrow3, Affine3f().translate(Vec3f(1.0f,1.0f,1.0f)));
-        myWindow2.showWidget("arrow4", arrow4, Affine3f().translate(Vec3f(1.0f,1.0f,1.0f)));
-        myWindow2.showWidget("arrow5", arrow5, Affine3f().translate(Vec3f(1.0f,1.0f,1.0f)));
-        myWindow2.showWidget("arrow6", arrow6, Affine3f().translate(Vec3f(1.0f,1.0f,1.0f)));
-        myWindow2.showWidget("text_target", text_target, Affine3f().translate(Vec3f(0.0f,0.0f,0.0f)));
-        myWindow2.showWidget("text_pred", text_pred, Affine3f().translate(Vec3f(0.0f,0.0f,0.0f)));
-        myWindow2.showWidget("text3d1", text3d1, Affine3f().translate(Vec3f(0.0f,0.0f,0.0f)));
-        myWindow2.showWidget("text3d2", text3d2, Affine3f().translate(Vec3f(0.0f,0.0f,0.0f)));
-        myWindow2.showWidget("text3d3", text3d3, Affine3f().translate(Vec3f(0.0f,0.0f,0.0f)));
-        myWindow2.showWidget("text3d4", text3d4, Affine3f().translate(Vec3f(0.0f,0.0f,0.0f)));
-        myWindow2.showWidget("classname1", classname1, Affine3f().translate(Vec3f(0.0f,0.0f,0.0f)));
-        myWindow2.showWidget("classname2", classname2, Affine3f().translate(Vec3f(0.0f,0.0f,0.0f)));
-        myWindow2.showWidget("classname3", classname3, Affine3f().translate(Vec3f(0.0f,0.0f,0.0f)));
-        myWindow2.showWidget("classname4", classname4, Affine3f().translate(Vec3f(0.0f,0.0f,0.0f)));
-        myWindow2.showWidget("classname5", classname5, Affine3f().translate(Vec3f(0.0f,0.0f,0.0f)));
-        myWindow2.showWidget("classname6", classname6, Affine3f().translate(Vec3f(0.0f,0.0f,0.0f)));
-        bunny_cloud = cvcloud_load(feature_reference[num_model]);
-        cam_focal_point = ViewSphere.getCenter(bunny_cloud);
-        radius = ViewSphere.getRadius(bunny_cloud, cam_focal_point);
-        viz::WCloud cloud_widget1(bunny_cloud.colRange(Range(0,641)), viz::Color::red());
-        viz::WCloud cloud_widget2(bunny_cloud.colRange(Range(642,642*2-1)), viz::Color::green());
-        viz::WCloud cloud_widget3(bunny_cloud.colRange(Range(642*2,642*3-1)), viz::Color::purple());
-        viz::WCloud cloud_widget4(bunny_cloud.colRange(Range(642*3,642*4-1)), viz::Color::blue());
-        viz::WCloud cloud_widget5(bunny_cloud.colRange(Range(642*4,642*5-1)), viz::Color::yellow());
-        viz::WCloud cloud_widget6(bunny_cloud.colRange(Range(642*5,642*6-1)), viz::Color::orange());
-        myWindow1.showWidget("obj1", cloud_widget1, cloud_pose_global);
-        myWindow1.setRenderingProperty("obj1",0,3);
-        myWindow1.showWidget("obj2", cloud_widget2, cloud_pose_global);
-        myWindow1.setRenderingProperty("obj2",0,3);
-        myWindow1.showWidget("obj3", cloud_widget3, cloud_pose_global);
-        myWindow1.setRenderingProperty("obj3",0,3);
-        myWindow1.showWidget("obj4", cloud_widget4, cloud_pose_global);
-        myWindow1.setRenderingProperty("obj4",0,3);
-        myWindow1.showWidget("obj5", cloud_widget5, cloud_pose_global);
-        myWindow1.setRenderingProperty("obj5",0,3);
-        myWindow1.showWidget("obj6", cloud_widget6, cloud_pose_global);
-        myWindow1.setRenderingProperty("obj6",0,3);
-        count_pre = 0;
-        for (int j = 1; j < num_candidate+1; ++j)
-        {
-            myWindow2.showWidget(widgename[count_pre], viz::WImageOverlay(img_gallery[matches1[num_model][0][j].trainIdx], Rect(80+110*j, 40+75*0, img_test4.rows, img_test4.cols)), Affine3f().translate(Vec3f(1.0f,1.0f,1.0f)));
-            count_pre++;
-            myWindow2.showWidget(widgename[count_pre], viz::WImageOverlay(img_gallery[matches2[num_model][0][j].trainIdx], Rect(80+110*j, 40+75*1, img_test4.rows, img_test4.cols)), Affine3f().translate(Vec3f(1.0f,1.0f,1.0f)));
-            count_pre++;
-            myWindow2.showWidget(widgename[count_pre], viz::WImageOverlay(img_gallery[matches3[num_model][0][j].trainIdx], Rect(80+110*j, 40+75*2, img_test4.rows, img_test4.cols)), Affine3f().translate(Vec3f(1.0f,1.0f,1.0f)));
-            count_pre++;
-            myWindow2.showWidget(widgename[count_pre], viz::WImageOverlay(img_gallery[matches4[num_model][0][j].trainIdx], Rect(80+110*j, 40+75*3, img_test4.rows, img_test4.cols)), Affine3f().translate(Vec3f(1.0f,1.0f,1.0f)));
-            count_pre++;
-            myWindow2.showWidget(widgename[count_pre], viz::WImageOverlay(img_gallery[matches5[num_model][0][j].trainIdx], Rect(80+110*j, 40+75*4, img_test4.rows, img_test4.cols)), Affine3f().translate(Vec3f(1.0f,1.0f,1.0f)));
-            count_pre++;
-            myWindow2.showWidget(widgename[count_pre], viz::WImageOverlay(img_gallery[matches6[num_model][0][j].trainIdx], Rect(80+110*j, 40+75*5, img_test4.rows, img_test4.cols)), Affine3f().translate(Vec3f(1.0f,1.0f,1.0f)));
-            count_pre++;
-        }
-        num_rotate = 0;
-        max_rotate = 15;
-        if (num_model == number_model-1)
-            max_rotate = 30000;
-        while (num_rotate != max_rotate)
-        {
-            translation_phase += CV_PI * 0.01f;
-            campos.x = sin(translation_phase);
-            campos.y = cos(translation_phase);
-            campos.z = 0;
-            /* Get the pose of the camera using makeCameraPoses. */
-            Affine3f cam_pose = viz::makeCameraPose(campos*radius*3.5+cam_focal_point, cam_focal_point, cam_y_dir*radius*3.5+cam_focal_point);
-            myWindow1.setViewerPose(cam_pose);
-            myWindow1.spinOnce(1, true);
-            myWindow2.spinOnce(1, true);
-            myWindow0.spinOnce(1, true);
-            num_rotate++;
-        }
-        myWindow0.removeAllWidgets();
-        myWindow1.removeAllWidgets();
-        myWindow2.removeAllWidgets();
-    }
-    return 0;
-}
\ No newline at end of file
diff --git a/contrib/modules/cnn_3dobj/samples/demo_model_analysis.cpp b/contrib/modules/cnn_3dobj/samples/model_analysis.cpp
similarity index 100%
rename from contrib/modules/cnn_3dobj/samples/demo_model_analysis.cpp
rename to contrib/modules/cnn_3dobj/samples/model_analysis.cpp
diff --git a/contrib/modules/cnn_3dobj/samples/sphereview_data.cpp b/contrib/modules/cnn_3dobj/samples/sphereview_data.cpp
new file mode 100755
index 0000000..db70439
--- /dev/null
+++ b/contrib/modules/cnn_3dobj/samples/sphereview_data.cpp
@@ -0,0 +1,331 @@
+/*
+ * Software License Agreement (BSD License)
+ *
+ *  Copyright (c) 2009, Willow Garage, Inc.
+ *  All rights reserved.
+ *
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions
+ *  are met:
+ *
+ *   * Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *   * Redistributions in binary form must reproduce the above
+ *     copyright notice, this list of conditions and the following
+ *     disclaimer in the documentation and/or other materials provided
+ *     with the distribution.
+ *   * Neither the name of Willow Garage, Inc. nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ *  POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+/**
+ * @file demo_sphereview_data.cpp
+ * @brief Generating training data for CNN with triplet loss.
+ * @author Yida Wang
+ */
+#include <opencv2/cnn_3dobj.hpp>
+#include <opencv2/viz/vizcore.hpp>
+#include <iostream>
+#include <stdlib.h>
+#include <time.h>
+using namespace cv;
+using namespace std;
+using namespace cv::cnn_3dobj;
+
+/**
+ * @function listDir
+ * @brief Making all files names under a directory into a list
+ */
+static void listDir(const char *path, std::vector<String>& files, bool r)
+{
+    DIR *pDir;
+    struct dirent *ent;
+    char childpath[512];
+    pDir = opendir(path);
+    memset(childpath, 0, sizeof(childpath));
+    while ((ent = readdir(pDir)) != NULL)
+    {
+        if (ent->d_type & DT_DIR)
+        {
+            if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0 || strcmp(ent->d_name, ".DS_Store") == 0)
+            {
+                continue;
+            }
+            if (r)
+            {
+                sprintf(childpath, "%s/%s", path, ent->d_name);
+                listDir(childpath,files,false);
+            }
+        }
+        else
+        {
+            if (strcmp(ent->d_name, ".DS_Store") != 0)
+                files.push_back(ent->d_name);
+        }
+    }
+    sort(files.begin(),files.end());
+};
+
+int main(int argc, char *argv[])
+{
+    const String keys = "{help | | demo :$ ./sphereview_test -ite_depth=2 -plymodel=../data/3Dmodel/ape.ply -imagedir=../data/images_all/ -labeldir=../data/label_all.txt -num_class=6 -label_class=0, then press 'q' to run the demo for images generation when you see the gray background and a coordinate.}"
+    "{ite_depth | 3 | Iteration of sphere generation.}"
+    "{plymodel | ../data/3Dmodel/ape.ply | Path of the '.ply' file for image rendering. }"
+    "{imagedir | ../data/images_all/ | Path of the generated images for one particular .ply model. }"
+    "{labeldir | ../data/label_all.txt | Path of the generated images for one particular .ply model. }"
+    "{bakgrdir | | Path of the backgroud images sets. }"
+    "{cam_head_x | 0 | Head of the camera. }"
+    "{cam_head_y | 0 | Head of the camera. }"
+    "{cam_head_z | -1 | Head of the camera. }"
+    "{semisphere | 1 | Camera only has positions on half of the whole sphere. }"
+    "{z_range | 0.6 | Maximum camera position on z axis. }"
+    "{center_gen | 0 | Find center from all points. }"
+    "{image_size | 128 | Size of captured images. }"
+    "{label_class |  | Class label of current .ply model. }"
+    "{label_item |  | Item label of current .ply model. }"
+    "{rgb_use | 0 | Use RGB image or grayscale. }"
+    "{num_class | 6 | Total number of classes of models. }"
+    "{binary_out | 0 | Produce binaryfiles for images and label. }"
+    "{view_region | 0 | Take a special view of front or back angle}";
+    /* Get parameters from comand line. */
+    cv::CommandLineParser parser(argc, argv, keys);
+    parser.about("Generating training data for CNN with triplet loss");
+    if (parser.has("help"))
+    {
+        parser.printMessage();
+        return 0;
+    }
+    int ite_depth = parser.get<int>("ite_depth");
+    String plymodel = parser.get<String>("plymodel");
+    String imagedir = parser.get<String>("imagedir");
+    String labeldir = parser.get<String>("labeldir");
+    String bakgrdir = parser.get<String>("bakgrdir");
+    int label_class = parser.get<int>("label_class");
+    int label_item = parser.get<int>("label_item");
+    float cam_head_x = parser.get<float>("cam_head_x");
+    float cam_head_y = parser.get<float>("cam_head_y");
+    float cam_head_z = parser.get<float>("cam_head_z");
+    int semisphere = parser.get<int>("semisphere");
+    float z_range = parser.get<float>("z_range");
+    int center_gen = parser.get<int>("center_gen");
+    int image_size = parser.get<int>("image_size");
+    int rgb_use = parser.get<int>("rgb_use");
+    int num_class = parser.get<int>("num_class");
+    int binary_out = parser.get<int>("binary_out");
+    int view_region = parser.get<int>("view_region");
+    double obj_dist, bg_dist, y_range;
+    if (view_region == 1 || view_region == 2)
+    {
+        /* Set for TV */
+        if (label_class == 12)
+            obj_dist = 340;
+        else
+            obj_dist = 250;
+        ite_depth = ite_depth + 1;
+        bg_dist = 700;
+        y_range = 0.85;
+    }
+    else if (view_region == 0)
+    {
+        obj_dist = 370;
+        bg_dist = 400;
+    }
+    if (label_class == 5 || label_class == 10 || label_class == 11 || label_class == 12)
+        ite_depth = ite_depth + 1;
+    cv::cnn_3dobj::icoSphere ViewSphere(10,ite_depth);
+    std::vector<cv::Point3d> campos;
+    std::vector<cv::Point3d> campos_temp = ViewSphere.CameraPos;
+    /* Regular objects on the ground using a semisphere view system */
+    if (semisphere == 1)
+    {
+        if (view_region == 1)
+        {
+            for (int pose = 0; pose < static_cast<int>(campos_temp.size()); pose++)
+            {
+                if (campos_temp.at(pose).z >= 0 && campos_temp.at(pose).z < z_range && campos_temp.at(pose).y < -y_range)
+                    campos.push_back(campos_temp.at(pose));
+            }
+        }
+        else if (view_region == 2)
+        {
+            for (int pose = 0; pose < static_cast<int>(campos_temp.size()); pose++)
+            {
+                if (campos_temp.at(pose).z >= 0 && campos_temp.at(pose).z < z_range && campos_temp.at(pose).y > y_range)
+                campos.push_back(campos_temp.at(pose));
+            }
+        }
+        else
+        {
+            /* Set for sofa */
+            if (label_class == 10)
+            {
+                for (int pose = 0; pose < static_cast<int>(campos_temp.size()); pose++)
+                {
+                    if (campos_temp.at(pose).z >= 0 && campos_temp.at(pose).z < z_range && campos_temp.at(pose).y < -0.4)
+                    campos.push_back(campos_temp.at(pose));
+                }
+            }
+            else
+            {
+                for (int pose = 0; pose < static_cast<int>(campos_temp.size()); pose++)
+                {
+                    if (campos_temp.at(pose).z >= 0 && campos_temp.at(pose).z < z_range)
+                        campos.push_back(campos_temp.at(pose));
+                }
+            }
+        }
+    }
+    /* Special object such as plane using a full space of view sphere */
+    else
+    {
+        if (view_region == 1)
+        {
+            for (int pose = 0; pose < static_cast<int>(campos_temp.size()); pose++)
+            {
+                if (campos_temp.at(pose).z < 0.2 && campos_temp.at(pose).z > -0.2 && campos_temp.at(pose).y < -y_range)
+                    campos.push_back(campos_temp.at(pose));
+            }
+        }
+        else if (view_region == 2)
+        {
+            for (int pose = 0; pose < static_cast<int>(campos_temp.size()); pose++)
+            {
+                if (campos_temp.at(pose).z < 0.2 && campos_temp.at(pose).z > -0.2 && campos_temp.at(pose).y > y_range)
+                campos.push_back(campos_temp.at(pose));
+            }
+        }
+        else
+        {
+            for (int pose = 0; pose < static_cast<int>(campos_temp.size()); pose++)
+            {
+                if (campos_temp.at(pose).z < 0.2 && campos_temp.at(pose).z > -0.6)
+                    campos.push_back(campos_temp.at(pose));
+            }
+        }
+    }
+    std::fstream imglabel;
+    imglabel.open(labeldir.c_str(), fstream::app|fstream::out);
+    bool camera_pov = true;
+    /* Create a window using viz. */
+    viz::Viz3d myWindow("Coordinate Frame");
+    /* Set window size. */
+    myWindow.setWindowSize(Size(image_size,image_size));
+    /* Set background color. */
+    myWindow.setBackgroundColor(viz::Color::gray());
+    myWindow.spinOnce();
+    /* Create a Mesh widget, loading .ply models. */
+    viz::Mesh objmesh = viz::Mesh::load(plymodel);
+    /* Get the center of the generated mesh widget, cause some .ply files, this could be ignored if you are using PASCAL database*/
+    Point3d cam_focal_point;
+    if (center_gen)
+        cam_focal_point = ViewSphere.getCenter(objmesh.cloud);
+    else
+        cam_focal_point = Point3d(0,0,0);
+    const char* headerPath = "../data/header_for_";
+    const char* binaryPath = "../data/binary_";
+    if (binary_out)
+    {
+        ViewSphere.createHeader(static_cast<int>(campos.size()), image_size, image_size, headerPath);
+    }
+    float radius = ViewSphere.getRadius(objmesh.cloud, cam_focal_point);
+    objmesh.cloud = objmesh.cloud/radius*100;
+    cam_focal_point = cam_focal_point/radius*100;
+    Point3d cam_y_dir;
+    cam_y_dir.x = cam_head_x;
+    cam_y_dir.y = cam_head_y;
+    cam_y_dir.z = cam_head_z;
+    char temp[1024];
+    std::vector<String> name_bkg;
+    if (bakgrdir.size() != 0)
+    {
+        /* List the file names under a given path */
+        listDir(bakgrdir.c_str(), name_bkg, false);
+        for (unsigned int i = 0; i < name_bkg.size(); i++)
+        {
+            name_bkg.at(i) = bakgrdir + name_bkg.at(i);
+        }
+    }
+    /* Images will be saved as .png files. */
+    size_t cnt_img;
+    srand((int)time(0));
+    do
+    {
+        cnt_img = 0;
+        for(int pose = 0; pose < static_cast<int>(campos.size()); pose++){
+            /* Add light. */
+            // double alpha1 = rand()%(314/2)/100;
+            // double alpha2 = rand()%(314*2)/100;
+            // printf("%f %f %f/n", ceil(10000*sqrt(1 - sin(alpha1)*sin(alpha1))*sin(alpha2)), 10000*sqrt(1 - sin(alpha1)*sin(alpha1))*cos(alpha2), sin(alpha1)*10000);
+            // myWindow.addLight(Vec3d(10000*sqrt(1 - sin(alpha1)*sin(alpha1))*sin(alpha2),10000*sqrt(1 - sin(alpha1)*sin(alpha1))*cos(alpha2),sin(alpha1)*10000), Vec3d(0,0,0), viz::Color::white(), viz::Color::white(), viz::Color::black(), viz::Color::white());
+            int label_x, label_y, label_z;
+            label_x = static_cast<int>(campos.at(pose).x*100);
+            label_y = static_cast<int>(campos.at(pose).y*100);
+            label_z = static_cast<int>(campos.at(pose).z*100);
+            sprintf (temp,"%02i_%02i_%04i_%04i_%04i_%02i", label_class, label_item, label_x, label_y, label_z, static_cast<int>(obj_dist/100));
+            String filename = temp;
+            filename += ".png";
+            imglabel << filename << ' ' << label_class << endl;
+            filename = imagedir + filename;
+            /* Get the pose of the camera using makeCameraPoses. */
+            if (view_region != 0)
+            {
+                cam_focal_point.x = cam_focal_point.y - label_x/5;
+            }
+            Affine3f cam_pose = viz::makeCameraPose(campos.at(pose)*obj_dist+cam_focal_point, cam_focal_point, cam_y_dir*obj_dist+cam_focal_point);
+            /* Get the transformation matrix from camera coordinate system to global. */
+            Affine3f transform = viz::makeTransformToGlobal(Vec3f(1.0f,0.0f,0.0f), Vec3f(0.0f,1.0f,0.0f), Vec3f(0.0f,0.0f,1.0f), campos.at(pose));
+            viz::WMesh mesh_widget(objmesh);
+            /* Pose of the widget in camera frame. */
+            Affine3f cloud_pose = Affine3f().translate(Vec3f(1.0f,1.0f,1.0f));
+            /* Pose of the widget in global frame. */
+            Affine3f cloud_pose_global = transform * cloud_pose;
+            /* Visualize camera frame. */
+            if (!camera_pov)
+            {
+                viz::WCameraPosition cpw(1); // Coordinate axes
+                viz::WCameraPosition cpw_frustum(Vec2f(0.5, 0.5)); // Camera frustum
+                myWindow.showWidget("CPW", cpw, cam_pose);
+                myWindow.showWidget("CPW_FRUSTUM", cpw_frustum, cam_pose);
+            }
+
+            /* Visualize widget. */
+            if (bakgrdir.size() != 0)
+            {
+                cv::Mat img_bg = cv::imread(name_bkg.at(rand()%name_bkg.size()));
+                /* Back ground images has a distance of 2 times of radius of camera view distance */
+                cv::viz::WImage3D background_widget(img_bg, Size2d(image_size*4.2, image_size*4.2), Vec3d(-campos.at(pose)*bg_dist+cam_focal_point), Vec3d(campos.at(pose)*bg_dist-cam_focal_point), Vec3d(0,0,-1)*bg_dist+Vec3d(0,2*cam_focal_point.y,0));
+                myWindow.showWidget("bgwidget", background_widget, cloud_pose_global);
+            }
+            // mesh_widget.setRenderingProperty(viz::LINE_WIDTH, 4.0);
+            myWindow.showWidget("targetwidget", mesh_widget, cloud_pose_global);
+
+            /* Set the viewer pose to that of camera. */
+            if (camera_pov)
+                myWindow.setViewerPose(cam_pose);
+            /* Save screen shot as images. */
+            myWindow.saveScreenshot(filename);
+            if (binary_out)
+            {
+            /* Write images into binary files for further using in CNN training. */
+                ViewSphere.writeBinaryfile(filename, binaryPath, headerPath,static_cast<int>(campos.size())*num_class, label_class, static_cast<int>(campos.at(pose).x*100), static_cast<int>(campos.at(pose).y*100), static_cast<int>(campos.at(pose).z*100), rgb_use);
+            }
+            cnt_img++;
+        }
+    } while (cnt_img != campos.size());
+    imglabel.close();
+    return 1;
+};
diff --git a/contrib/modules/cnn_3dobj/samples/video.cpp b/contrib/modules/cnn_3dobj/samples/video.cpp
new file mode 100755
index 0000000..b25cbef
--- /dev/null
+++ b/contrib/modules/cnn_3dobj/samples/video.cpp
@@ -0,0 +1,390 @@
+#include <opencv2/viz/vizcore.hpp>
+#include <opencv2/calib3d.hpp>
+#include <iostream>
+#include <fstream>
+#include <opencv2/cnn_3dobj.hpp>
+#include <opencv2/features2d.hpp>
+#include <iomanip>
+using namespace cv;
+using namespace std;
+using namespace cv::cnn_3dobj;
+/**
+ * @function listDir
+ * @brief Making all files names under a directory into a list
+ */
+static void listDir(const char *path, std::vector<String>& files, bool r)
+{
+    DIR *pDir;
+    struct dirent *ent;
+    char childpath[512];
+    pDir = opendir(path);
+    memset(childpath, 0, sizeof(childpath));
+    while ((ent = readdir(pDir)) != NULL)
+    {
+        if (ent->d_type & DT_DIR)
+        {
+            if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
+            {
+                continue;
+            }
+            if(r)
+            {
+                sprintf(childpath, "%s/%s", path, ent->d_name);
+                listDir(childpath,files,false);
+            }
+        }
+        else
+        {
+            files.push_back(ent->d_name);
+        }
+    }
+    sort(files.begin(),files.end());
+};
+
+
+/**
+ * @function cvcloud_load
+ * @brief load bunny.ply
+ */
+static Mat cvcloud_load(Mat feature_reference)
+{
+    Mat cloud(1, feature_reference.rows, CV_32FC3);
+    Point3f* data = cloud.ptr<cv::Point3f>();
+
+    for(int i = 0; i < feature_reference.rows; ++i)
+    {
+        data[i].x = feature_reference.at<float>(i,0);
+        data[i].y = feature_reference.at<float>(i,1);
+        data[i].z = feature_reference.at<float>(i,2);
+    }
+    cloud *= 5.0f;
+    return cloud;
+}
+
+/**
+ * @function main
+ */
+int main(int argc, char **argv)
+{
+    const String keys = "{help | | This sample will extract featrues from reference images and target image for classification. You can add a mean_file if there little variance in data such as human faces, otherwise it is not so useful}"
+    "{src_dir | ../data/images_all/ | Source direction of the images ready for being used for extract feature as gallery.}"
+    "{caffemodellist | ../../testdata/cv/caffemodel_list.txt | caffe model for feature exrtaction.}"
+    "{network_forIMG | ../../testdata/cv/3d_triplet_testIMG.prototxt | Network definition file used for extracting feature from a single image and making a classification}"
+    "{mean_file | no | The mean file generated by Caffe from all gallery images, this could be used for mean value substraction from all images. If you want to use the mean file, you can set this as ../data/images_mean/triplet_mean.binaryproto.}"
+    "{target_img1 | ../data/images_all/0_48.png | Path of image waiting to be classified.}"
+    "{target_img2 | ../data/images_all/1_339.png | Path of image waiting to be classified.}"
+    "{target_img3 | ../data/images_all/2_296.png | Path of image waiting to be classified.}"
+    "{target_img4 | ../data/images_all/3_466.png | Path of image waiting to be classified.}"
+    "{target_img5 | ../data/images_all/4_117.png | Path of image waiting to be classified.}"
+    "{target_img6 | ../data/images_all/5_236.png | Path of image waiting to be classified.}"
+    "{feature_blob | feat | Name of layer which will represent as the feature, in this network, ip1 or feat is well.}"
+    "{num_candidate | 4 | Number of candidates in gallery as the prediction result.}"
+    "{device | CPU | Device type: CPU or GPU}"
+    "{dev_id | 0 | Device id}";
+    /* get parameters from comand line */
+    cv::CommandLineParser parser(argc, argv, keys);
+    parser.about("Feature extraction and classification");
+    if (parser.has("help"))
+    {
+        parser.printMessage();
+        return 0;
+    }
+    String src_dir = parser.get<String>("src_dir");
+    String caffemodellist = parser.get<String>("caffemodellist");
+    String network_forIMG   = parser.get<String>("network_forIMG");
+    String mean_file    = parser.get<String>("mean_file");
+    String target_img1   = parser.get<String>("target_img1");
+    String target_img2   = parser.get<String>("target_img2");
+    String target_img3   = parser.get<String>("target_img3");
+    String target_img4   = parser.get<String>("target_img4");
+    String target_img5   = parser.get<String>("target_img5");
+    String target_img6   = parser.get<String>("target_img6");
+    String feature_blob = parser.get<String>("feature_blob");
+    int num_candidate = parser.get<int>("num_candidate");
+    String device = parser.get<String>("device");
+
+    ifstream namelist_model(caffemodellist.c_str(), ios::in);
+    vector<String> caffemodel;
+    char *buf = new char[512];
+    int number_model = 0;
+    while (!namelist_model.eof())
+    {
+        namelist_model.getline(buf, 512);
+        caffemodel.push_back(buf);
+        number_model++;
+    }
+    /* List the file names under a given path */
+    std::vector<String> name_gallery;
+    listDir(src_dir.c_str(), name_gallery, false);
+    for (unsigned int i = 0; i < name_gallery.size(); i++)
+    {
+        name_gallery[i] = src_dir + name_gallery[i];
+    }
+    std::vector<cv::Mat> img_gallery;
+    cv::Mat temp_feat;
+    vector<cv::Mat> feature_reference;
+    vector<cv::Mat> feature_test1;
+    vector<cv::Mat> feature_test2;
+    vector<cv::Mat> feature_test3;
+    vector<cv::Mat> feature_test4;
+    vector<cv::Mat> feature_test5;
+    vector<cv::Mat> feature_test6;
+    cv::Mat img_test1 = cv::imread(target_img1, -1);
+    cv::Mat img_test2 = cv::imread(target_img2, -1);
+    cv::Mat img_test3 = cv::imread(target_img3, -1);
+    cv::Mat img_test4 = cv::imread(target_img4, -1);
+    cv::Mat img_test5 = cv::imread(target_img5, -1);
+    cv::Mat img_test6 = cv::imread(target_img6, -1);
+    for (int num_model = 0; num_model < number_model; ++num_model)
+    {
+        feature_reference.push_back(temp_feat);
+        feature_test1.push_back(temp_feat);
+        feature_test2.push_back(temp_feat);
+        feature_test3.push_back(temp_feat);
+        feature_test4.push_back(temp_feat);
+        feature_test5.push_back(temp_feat);
+        feature_test6.push_back(temp_feat);
+    }
+    for (unsigned int i = 0; i < name_gallery.size(); i++)
+    {
+        img_gallery.push_back(cv::imread(name_gallery[i], -1));
+    }
+    /* Initialize a net work with Device */
+    cv::cnn_3dobj::descriptorExtractor descriptor(device);
+    std::cout << "Using" << descriptor.getDeviceType() << std::endl;
+    /* Load net with the caffe trained net work parameter and structure */
+    for (int num_model = 0; num_model < number_model; ++num_model)
+    {
+        if (strcmp(mean_file.c_str(), "no") == 0)
+            descriptor.loadNet(network_forIMG, caffemodel[num_model]);
+        else
+            descriptor.loadNet(network_forIMG, caffemodel[num_model], mean_file);
+        /* Part1: Extract feature from a set of images and a single image*/
+        descriptor.extract(img_gallery, feature_reference[num_model], feature_blob);
+        descriptor.extract(img_test1, feature_test1[num_model], feature_blob);
+        descriptor.extract(img_test2, feature_test2[num_model], feature_blob);
+        descriptor.extract(img_test3, feature_test3[num_model], feature_blob);
+        descriptor.extract(img_test4, feature_test4[num_model], feature_blob);
+        descriptor.extract(img_test5, feature_test5[num_model], feature_blob);
+        descriptor.extract(img_test6, feature_test6[num_model], feature_blob);
+    }
+    /* Initialize a matcher which using L2 distance. */
+    cv::BFMatcher matcher(NORM_L2);
+    vector<vector<vector<cv::DMatch> > > matches1;
+    vector<vector<vector<cv::DMatch> > > matches2;
+    vector<vector<vector<cv::DMatch> > > matches3;
+    vector<vector<vector<cv::DMatch> > > matches4;
+    vector<vector<vector<cv::DMatch> > > matches5;
+    vector<vector<vector<cv::DMatch> > > matches6;
+    vector<vector<cv::DMatch> > matches_temp;
+    for (int num_model = 0; num_model < number_model; ++num_model)
+    {
+        matches1.push_back(matches_temp);
+        matches2.push_back(matches_temp);
+        matches3.push_back(matches_temp);
+        matches4.push_back(matches_temp);
+        matches5.push_back(matches_temp);
+        matches6.push_back(matches_temp);
+    }
+    /* Have a KNN match on the target and reference images. */
+    for (int num_model = 0; num_model < number_model; ++num_model)
+    {
+        matcher.knnMatch(feature_test1[num_model], feature_reference[num_model], matches1[num_model], num_candidate+1);
+        matcher.knnMatch(feature_test2[num_model], feature_reference[num_model], matches2[num_model], num_candidate+1);
+        matcher.knnMatch(feature_test3[num_model], feature_reference[num_model], matches3[num_model], num_candidate+1);
+        matcher.knnMatch(feature_test4[num_model], feature_reference[num_model], matches4[num_model], num_candidate+1);
+        matcher.knnMatch(feature_test5[num_model], feature_reference[num_model], matches5[num_model], num_candidate+1);
+        matcher.knnMatch(feature_test6[num_model], feature_reference[num_model], matches6[num_model], num_candidate+1);
+    }
+    vector<Mat> img_merge;
+    /* Part2: Start to have a show */
+    viz::Viz3d myWindow0("Instruction");
+    viz::Viz3d myWindow1("Point Cloud");
+    viz::Viz3d myWindow2("Prediction sample");
+    /* Set window size as 1024*1024, we use this scale as default. */
+    myWindow0.setWindowSize(Size(1300,100));
+    myWindow0.setWindowPosition(Point(0,800));
+    myWindow1.setWindowSize(Size(700,600));
+    myWindow1.setWindowPosition(Point(600,0));
+    myWindow2.setWindowSize(Size(600,600));
+    myWindow2.setWindowPosition(Point(-20,0));
+    /* Pose of the widget in camera frame */
+    Affine3f cloud_pose = Affine3f().translate(Vec3f(1.0f,1.0f,1.0f));
+    Point3d campos(1,0,0);
+    /* Get the transformation matrix from camera coordinate system to global. */
+    Affine3f transform = viz::makeTransformToGlobal(Vec3f(1.0f,0.0f,0.0f), Vec3f(0.0f,1.0f,0.0f), Vec3f(0.0f,0.0f,1.0f), campos);
+    /* Pose of the widget in global frame */
+    Affine3f cloud_pose_global = transform * cloud_pose;
+    /* Set background color. */
+    myWindow0.setBackgroundColor(viz::Color::white());
+    myWindow1.setBackgroundColor(viz::Color::white());
+    myWindow2.setBackgroundColor(viz::Color::white());
+    Point3d cam_y_dir(0.0f,0.0f,1.0f);
+    cv::cnn_3dobj::icoSphere ViewSphere(1,0);
+    Mat bunny_cloud;
+    Point3d cam_focal_point;
+    float radius;
+    float translation_phase = 0.0;
+    int count_pre, num_rotate, max_rotate;
+    String titlename, Hint, Pred("prediction: ");
+    vector<viz::WImageOverlay> imagepredict;
+    String widgename[24] = {"1","2","3","4","5","6","7","8","9","10","11","12","13","14","15","16","17","18","19","20","21","22","23","24"};
+    vector<Mat> slide;
+    slide.push_back(imread("1.png"));
+    slide.push_back(imread("2.png"));
+    slide.push_back(imread("3.png"));
+    slide.push_back(imread("4.png"));
+    slide.push_back(imread("5.png"));
+    slide.push_back(imread("6.png"));
+    slide.push_back(imread("7.png"));
+    slide.push_back(imread("8.png"));
+    slide.push_back(imread("9.png"));
+    slide.push_back(imread("10.png"));
+    /// Create a window
+    viz::Viz3d myWindowS("Slide Show");
+    myWindowS.setWindowSize(Size(1300,700));
+    myWindowS.setWindowPosition(Point(0,0));
+    myWindowS.setBackgroundColor(viz::Color::white());
+    for (size_t i = 0; i < slide.size(); ++i)
+    {
+        /// Create a triangle widget
+        viz::WImageOverlay slide1(slide[i],Rect(0, 0, 1300, 700));
+        /// Show widget in the visualizer window
+        num_rotate = 0;
+        if (i == 0)
+            max_rotate = 2000;
+        else
+            max_rotate = 230;
+        while (num_rotate != max_rotate)
+        {
+            myWindowS.showWidget("Slide1", slide1);
+            /// Start event loop
+            myWindowS.spinOnce(1, true);
+            num_rotate++;
+        }
+    }
+    for (int num_model = 0; num_model < number_model; ++num_model)
+    {
+        if (num_model == 0)
+            Hint = "Start training.";
+        else if (num_model == 28)
+            Hint = "Different Classes Are Clustered.";
+        else if(num_model == 40)
+            Hint = "Poses Are Set apart.";
+        else if(num_model == 42)
+            Hint = "Finished. Model could: tell both classes and poses.";
+        titlename = caffemodel[num_model];
+        titlename = "Prediction Result of Model Trained on Iteration " + titlename.substr(34, titlename.length() - 44);
+        viz::WText title(titlename, Point(100, 50), 30, viz::Color::black());
+        viz::WText hint(Hint, Point(400, 20), 25, viz::Color::black());
+        viz::WImageOverlay image3d1(img_test1, Rect(20, 40, img_test4.rows, img_test4.cols));
+        viz::WText arrow1(Pred, Point(90,60), 15, viz::Color::red());
+        viz::WImageOverlay image3d2(img_test2, Rect(20, 40+75, img_test4.rows, img_test4.cols));
+        viz::WText arrow2(Pred, Point(90,60+75), 15, viz::Color::green());
+        viz::WImageOverlay image3d3(img_test3, Rect(20, 40+75*2, img_test4.rows, img_test4.cols));
+        viz::WText arrow3(Pred, Point(90,60+75*2), 15, viz::Color::purple());
+        viz::WImageOverlay image3d4(img_test4, Rect(20, 40+75*3, img_test4.rows, img_test4.cols));
+        viz::WText arrow4(Pred, Point(90,60+75*3), 15, viz::Color::blue());
+        viz::WImageOverlay image3d5(img_test5, Rect(20, 40+75*4, img_test4.rows, img_test4.cols));
+        viz::WText arrow5(Pred, Point(90,60+75*4), 15, viz::Color::yellow());
+        viz::WImageOverlay image3d6(img_test6, Rect(20, 40+75*5, img_test4.rows, img_test4.cols));
+        viz::WText arrow6(Pred, Point(90,60+75*5), 15, viz::Color::orange());
+        viz::WText text_target(String("Query Image"), Point2d(20,530), 20, viz::Color::purple());
+        viz::WText text_pred(String("Predicted Images using 4 NN"), Point2d(80+110,530), 20, viz::Color::purple());
+        viz::WText text3d1(String("1st"), Point2d(80 + 110,500), 20, viz::Color::orange());
+        viz::WText text3d2(String("2nd"), Point2d(80 + 2*110,500), 20, viz::Color::orange());
+        viz::WText text3d3(String("3rd"), Point2d(80 + 3*110,500), 20, viz::Color::orange());
+        viz::WText text3d4(String("4th"), Point2d(80 + 4*110,500), 20, viz::Color::orange());
+        viz::WText classname1(String("ape: red"), Point2d(20,10), 11, viz::Color::red());
+        viz::WText classname2(String("ant: green"), Point2d(120,10), 11, viz::Color::green());
+        viz::WText classname3(String("cow: purple"), Point2d(220,10), 11, viz::Color::purple());
+        viz::WText classname4(String("plane: blue"), Point2d(320,10), 11, viz::Color::blue());
+        viz::WText classname5(String("bunny: yellow"), Point2d(420,10), 11, viz::Color::yellow());
+        viz::WText classname6(String("horse: orange"), Point2d(500,10), 11, viz::Color::orange());
+        myWindow0.showWidget("title", title, Affine3f().translate(Vec3f(0.0f,0.0f,0.0f)));
+        myWindow0.showWidget("hint", hint, Affine3f().translate(Vec3f(0.0f,0.0f,0.0f)));
+        myWindow2.showWidget("image3d1", image3d1, Affine3f().translate(Vec3f(1.0f,1.0f,1.0f)));
+        myWindow2.showWidget("image3d2", image3d2, Affine3f().translate(Vec3f(1.0f,1.0f,1.0f)));
+        myWindow2.showWidget("image3d3", image3d3, Affine3f().translate(Vec3f(1.0f,1.0f,1.0f)));
+        myWindow2.showWidget("image3d4", image3d4, Affine3f().translate(Vec3f(1.0f,1.0f,1.0f)));
+        myWindow2.showWidget("image3d5", image3d5, Affine3f().translate(Vec3f(1.0f,1.0f,1.0f)));
+        myWindow2.showWidget("image3d6", image3d6, Affine3f().translate(Vec3f(1.0f,1.0f,1.0f)));
+        myWindow2.showWidget("arrow1", arrow1, Affine3f().translate(Vec3f(1.0f,1.0f,1.0f)));
+        myWindow2.showWidget("arrow2", arrow2, Affine3f().translate(Vec3f(1.0f,1.0f,1.0f)));
+        myWindow2.showWidget("arrow3", arrow3, Affine3f().translate(Vec3f(1.0f,1.0f,1.0f)));
+        myWindow2.showWidget("arrow4", arrow4, Affine3f().translate(Vec3f(1.0f,1.0f,1.0f)));
+        myWindow2.showWidget("arrow5", arrow5, Affine3f().translate(Vec3f(1.0f,1.0f,1.0f)));
+        myWindow2.showWidget("arrow6", arrow6, Affine3f().translate(Vec3f(1.0f,1.0f,1.0f)));
+        myWindow2.showWidget("text_target", text_target, Affine3f().translate(Vec3f(0.0f,0.0f,0.0f)));
+        myWindow2.showWidget("text_pred", text_pred, Affine3f().translate(Vec3f(0.0f,0.0f,0.0f)));
+        myWindow2.showWidget("text3d1", text3d1, Affine3f().translate(Vec3f(0.0f,0.0f,0.0f)));
+        myWindow2.showWidget("text3d2", text3d2, Affine3f().translate(Vec3f(0.0f,0.0f,0.0f)));
+        myWindow2.showWidget("text3d3", text3d3, Affine3f().translate(Vec3f(0.0f,0.0f,0.0f)));
+        myWindow2.showWidget("text3d4", text3d4, Affine3f().translate(Vec3f(0.0f,0.0f,0.0f)));
+        myWindow2.showWidget("classname1", classname1, Affine3f().translate(Vec3f(0.0f,0.0f,0.0f)));
+        myWindow2.showWidget("classname2", classname2, Affine3f().translate(Vec3f(0.0f,0.0f,0.0f)));
+        myWindow2.showWidget("classname3", classname3, Affine3f().translate(Vec3f(0.0f,0.0f,0.0f)));
+        myWindow2.showWidget("classname4", classname4, Affine3f().translate(Vec3f(0.0f,0.0f,0.0f)));
+        myWindow2.showWidget("classname5", classname5, Affine3f().translate(Vec3f(0.0f,0.0f,0.0f)));
+        myWindow2.showWidget("classname6", classname6, Affine3f().translate(Vec3f(0.0f,0.0f,0.0f)));
+        bunny_cloud = cvcloud_load(feature_reference[num_model]);
+        cam_focal_point = ViewSphere.getCenter(bunny_cloud);
+        radius = ViewSphere.getRadius(bunny_cloud, cam_focal_point);
+        viz::WCloud cloud_widget1(bunny_cloud.colRange(Range(0,641)), viz::Color::red());
+        viz::WCloud cloud_widget2(bunny_cloud.colRange(Range(642,642*2-1)), viz::Color::green());
+        viz::WCloud cloud_widget3(bunny_cloud.colRange(Range(642*2,642*3-1)), viz::Color::purple());
+        viz::WCloud cloud_widget4(bunny_cloud.colRange(Range(642*3,642*4-1)), viz::Color::blue());
+        viz::WCloud cloud_widget5(bunny_cloud.colRange(Range(642*4,642*5-1)), viz::Color::yellow());
+        viz::WCloud cloud_widget6(bunny_cloud.colRange(Range(642*5,642*6-1)), viz::Color::orange());
+        myWindow1.showWidget("obj1", cloud_widget1, cloud_pose_global);
+        myWindow1.setRenderingProperty("obj1",0,3);
+        myWindow1.showWidget("obj2", cloud_widget2, cloud_pose_global);
+        myWindow1.setRenderingProperty("obj2",0,3);
+        myWindow1.showWidget("obj3", cloud_widget3, cloud_pose_global);
+        myWindow1.setRenderingProperty("obj3",0,3);
+        myWindow1.showWidget("obj4", cloud_widget4, cloud_pose_global);
+        myWindow1.setRenderingProperty("obj4",0,3);
+        myWindow1.showWidget("obj5", cloud_widget5, cloud_pose_global);
+        myWindow1.setRenderingProperty("obj5",0,3);
+        myWindow1.showWidget("obj6", cloud_widget6, cloud_pose_global);
+        myWindow1.setRenderingProperty("obj6",0,3);
+        count_pre = 0;
+        for (int j = 1; j < num_candidate+1; ++j)
+        {
+            myWindow2.showWidget(widgename[count_pre], viz::WImageOverlay(img_gallery[matches1[num_model][0][j].trainIdx], Rect(80+110*j, 40+75*0, img_test4.rows, img_test4.cols)), Affine3f().translate(Vec3f(1.0f,1.0f,1.0f)));
+            count_pre++;
+            myWindow2.showWidget(widgename[count_pre], viz::WImageOverlay(img_gallery[matches2[num_model][0][j].trainIdx], Rect(80+110*j, 40+75*1, img_test4.rows, img_test4.cols)), Affine3f().translate(Vec3f(1.0f,1.0f,1.0f)));
+            count_pre++;
+            myWindow2.showWidget(widgename[count_pre], viz::WImageOverlay(img_gallery[matches3[num_model][0][j].trainIdx], Rect(80+110*j, 40+75*2, img_test4.rows, img_test4.cols)), Affine3f().translate(Vec3f(1.0f,1.0f,1.0f)));
+            count_pre++;
+            myWindow2.showWidget(widgename[count_pre], viz::WImageOverlay(img_gallery[matches4[num_model][0][j].trainIdx], Rect(80+110*j, 40+75*3, img_test4.rows, img_test4.cols)), Affine3f().translate(Vec3f(1.0f,1.0f,1.0f)));
+            count_pre++;
+            myWindow2.showWidget(widgename[count_pre], viz::WImageOverlay(img_gallery[matches5[num_model][0][j].trainIdx], Rect(80+110*j, 40+75*4, img_test4.rows, img_test4.cols)), Affine3f().translate(Vec3f(1.0f,1.0f,1.0f)));
+            count_pre++;
+            myWindow2.showWidget(widgename[count_pre], viz::WImageOverlay(img_gallery[matches6[num_model][0][j].trainIdx], Rect(80+110*j, 40+75*5, img_test4.rows, img_test4.cols)), Affine3f().translate(Vec3f(1.0f,1.0f,1.0f)));
+            count_pre++;
+        }
+        num_rotate = 0;
+        max_rotate = 15;
+        if (num_model == number_model-1)
+            max_rotate = 30000;
+        while (num_rotate != max_rotate)
+        {
+            translation_phase += CV_PI * 0.01f;
+            campos.x = sin(translation_phase);
+            campos.y = cos(translation_phase);
+            campos.z = 0;
+            /* Get the pose of the camera using makeCameraPoses. */
+            Affine3f cam_pose = viz::makeCameraPose(campos*radius*3.5+cam_focal_point, cam_focal_point, cam_y_dir*radius*3.5+cam_focal_point);
+            myWindow1.setViewerPose(cam_pose);
+            myWindow1.spinOnce(1, true);
+            myWindow2.spinOnce(1, true);
+            myWindow0.spinOnce(1, true);
+            num_rotate++;
+        }
+        myWindow0.removeAllWidgets();
+        myWindow1.removeAllWidgets();
+        myWindow2.removeAllWidgets();
+    }
+    return 0;
+}
diff --git a/contrib/modules/cnn_3dobj/test/test_cnn_3dobj_feature_extract.cpp b/contrib/modules/cnn_3dobj/test/test_cnn_3dobj_feature_extract.cpp
index c08d110..b43f6f2 100755
--- a/contrib/modules/cnn_3dobj/test/test_cnn_3dobj_feature_extract.cpp
+++ b/contrib/modules/cnn_3dobj/test/test_cnn_3dobj_feature_extract.cpp
@@ -26,11 +26,11 @@ CV_CNN_Feature_Test::CV_CNN_Feature_Test()
  */
 void CV_CNN_Feature_Test::run(int)
 {
-    String caffemodel = String(ts->get_data_path()) + "3d_triplet_iter_30000.caffemodel";
-    String network_forIMG = cvtest::TS::ptr()->get_data_path() + "3d_triplet_testIMG.prototxt";
+    String caffemodel = cvtest::findDataFile("contrib/cnn_3dobj/3d_triplet_iter_30000.caffemodel");
+    String network_forIMG = cvtest::findDataFile("contrib/cnn_3dobj/3d_triplet_testIMG.prototxt");
     String mean_file = "no";
     std::vector<String> ref_img;
-    String target_img = String(ts->get_data_path()) + "1_8.png";
+    String target_img = cvtest::findDataFile("contrib/cnn_3dobj/4_78.png");
     String feature_blob = "feat";
     String device = "CPU";
     int dev_id = 0;
@@ -43,15 +43,16 @@ void CV_CNN_Feature_Test::run(int)
         return;
     }
     cv::cnn_3dobj::descriptorExtractor descriptor(device, dev_id);
-    if (strcmp(mean_file.c_str(), "no") == 0)
+    if (mean_file == "no")
         descriptor.loadNet(network_forIMG, caffemodel);
     else
         descriptor.loadNet(network_forIMG, caffemodel, mean_file);
 
     cv::Mat feature_test;
     descriptor.extract(img_base, feature_test, feature_blob);
-    Mat feature_reference = (Mat_<float>(1,16) << -134.03548, -203.48265, -105.96752, 55.343075, -211.36378, 487.85968, -182.15063, 62.229042, 297.19876, 206.07578, 291.74951, -19.906454, -464.09152, 135.79895, 420.43616, 2.2887282);
-    printf("Reference feature is computed by Caffe extract_features tool by \n To generate values for different images, use extract_features \n with the resetted image list in prototxt.");
+    // Reference feature is computed by Caffe extract_features tool.
+    // To generate values for different images, use extract_features with the resetted image list in prototxt.
+    Mat feature_reference = (Mat_<float>(1,3) << -312.4805, 8.4768486, -224.98953);
     float dist = norm(feature_test - feature_reference);
     if (dist > 5) {
       ts->printf(cvtest::TS::LOG, "Extracted featrue is not the same from the one extracted from Caffe.");
diff --git a/contrib/modules/cnn_3dobj/test/test_precomp.hpp b/contrib/modules/cnn_3dobj/test/test_precomp.hpp
index 4d4227b..ebb7d40 100755
--- a/contrib/modules/cnn_3dobj/test/test_precomp.hpp
+++ b/contrib/modules/cnn_3dobj/test/test_precomp.hpp
@@ -12,7 +12,6 @@
 #include <iostream>
 #include "opencv2/ts.hpp"
 #include "opencv2/imgproc.hpp"
-#include "opencv2/cnn_3dobj_config.hpp"
 #include "opencv2/cnn_3dobj.hpp"
 
 #endif
diff --git a/contrib/modules/cnn_3dobj/tutorials/data_generation/data_generation.markdown b/contrib/modules/cnn_3dobj/tutorials/data_generation/data_generation.markdown
index 34de7f3..5501465 100755
--- a/contrib/modules/cnn_3dobj/tutorials/data_generation/data_generation.markdown
+++ b/contrib/modules/cnn_3dobj/tutorials/data_generation/data_generation.markdown
@@ -12,8 +12,7 @@ In this tutorial you will learn how to
 Code
 ----
 
-You can download the code from [here ](https://github.com/Wangyida/opencv_contrib/blob/cnn_3dobj/samples/demo_sphereview_data.cpp).
- at include cnn_3dobj/samples/demo_sphereview_data.cpp
+ at include cnn_3dobj/samples/sphereview_data.cpp
 
 Explanation
 -----------
diff --git a/contrib/modules/cnn_3dobj/tutorials/feature_classification/classify.markdown b/contrib/modules/cnn_3dobj/tutorials/feature_classification/classify.markdown
index e155765..5bf8288 100755
--- a/contrib/modules/cnn_3dobj/tutorials/feature_classification/classify.markdown
+++ b/contrib/modules/cnn_3dobj/tutorials/feature_classification/classify.markdown
@@ -1,4 +1,4 @@
-Classify {#tutorial_classify}
+Classify {#tutorial_feature_classification}
 ===============
 
 Goal
@@ -13,8 +13,7 @@ In this tutorial you will learn how to
 Code
 ----
 
-You can download the code from [here ](https://github.com/Wangyida/opencv_contrib/blob/cnn_3dobj/samples/demo_classify.cpp).
- at include cnn_3dobj/samples/demo_classify.cpp
+ at include cnn_3dobj/samples/classify.cpp
 
 Explanation
 -----------
diff --git a/contrib/modules/cnn_3dobj/tutorials/model_analysis/model_analysis.markdown b/contrib/modules/cnn_3dobj/tutorials/model_analysis/model_analysis.markdown
index 3292e1a..197834b 100755
--- a/contrib/modules/cnn_3dobj/tutorials/model_analysis/model_analysis.markdown
+++ b/contrib/modules/cnn_3dobj/tutorials/model_analysis/model_analysis.markdown
@@ -1,4 +1,4 @@
-Training data generation using Icosphere {#tutorial_model_analysis}
+Training Model Analysis {#tutorial_model_analysis}
 =============
 
 Goal
@@ -12,8 +12,7 @@ In this tutorial you will learn how to
 Code
 ----
 
-You can download the code from [here ](https://github.com/Wangyida/opencv_contrib/blob/cnn_3dobj/samples/demo_model_analysis.cpp).
- at include cnn_3dobj/samples/demo_model_analysis.cpp
+ at include cnn_3dobj/samples/model_analysis.cpp
 
 Explanation
 -----------
diff --git a/contrib/modules/cnn_3dobj/tutorials/table_of_content_cnn_3dobj.markdown b/contrib/modules/cnn_3dobj/tutorials/table_of_content_cnn_3dobj.markdown
index 64e01bc..d543ee5 100755
--- a/contrib/modules/cnn_3dobj/tutorials/table_of_content_cnn_3dobj.markdown
+++ b/contrib/modules/cnn_3dobj/tutorials/table_of_content_cnn_3dobj.markdown
@@ -23,4 +23,4 @@ CNN for 3D Object Classification and Pose Estimation {#tutorial_table_of_content
 
     *Author:* Yida Wang
 
-    You will learn how to have an analysis on performance of the trained Model.
+    You will learn how to analyze performance of a trained Model.
diff --git a/contrib/modules/contrib_world/CMakeLists.txt b/contrib/modules/contrib_world/CMakeLists.txt
index dafe6d5..17e4bba 100644
--- a/contrib/modules/contrib_world/CMakeLists.txt
+++ b/contrib/modules/contrib_world/CMakeLists.txt
@@ -5,18 +5,26 @@ set(BUILD_opencv_contrib_world_INIT OFF) # disabled by default
 
 # add new submodules to this list
 set(OPENCV_MODULE_CHILDREN
+  aruco
   bgsegm
   bioinspired
   ccalib
   cvv
   datasets
+  dnn
+  dpm
   face
-  latentsvm
+  fuzzy
+  hdf
   line_descriptor
   optflow
+  plot
   reg
   rgbd
   saliency
+  sfm
+  stereo
+  structured_light
   surface_matching
   text
   tracking
diff --git a/contrib/modules/contrib_world/README.md b/contrib/modules/contrib_world/README.md
new file mode 100644
index 0000000..a9929f9
--- /dev/null
+++ b/contrib/modules/contrib_world/README.md
@@ -0,0 +1,5 @@
+contrib_world -- opencv_contrib container
+=========================================
+
+contrib_world is the module that when built, contains all other opencv_contrib modules.
+It may be used for the more convenient redistribution of opencv binaries.
diff --git a/contrib/modules/cvv/.gitignore b/contrib/modules/cvv/.gitignore
new file mode 100644
index 0000000..51bccc5
--- /dev/null
+++ b/contrib/modules/cvv/.gitignore
@@ -0,0 +1,10 @@
+build/
+CMakeLists.txt.user
+.ycm_extra_conf.py
+.ycm_extra_conf.pyc
+test.sh
+release.sh
+*.swp
+*.swo
+src/dbg/dbg.hpp
+*~
diff --git a/contrib/modules/cvv/CMakeLists.txt b/contrib/modules/cvv/CMakeLists.txt
index 6c32241..4eba9fd 100644
--- a/contrib/modules/cvv/CMakeLists.txt
+++ b/contrib/modules/cvv/CMakeLists.txt
@@ -3,8 +3,16 @@ if(NOT HAVE_QT5)
   return()
 endif()
 
+set(the_description "Debug visualization framework")
+ocv_add_module(cvv opencv_core opencv_imgproc opencv_features2d WRAP python)
+
 # we need C++11 and want warnings:
-set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wall -Wextra -pedantic")
+if(MSVC)
+  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /Qstd=c++11 /W4")
+  add_definitions(/D__func__=__FUNCTION__)
+else()
+  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wall -Wextra -pedantic")
+endif()
 ocv_warnings_disable(CMAKE_CXX_FLAGS -Wshadow -Wmissing-declarations)
 
 # Qt5
@@ -16,5 +24,9 @@ foreach(dt5_dep Core Gui Widgets)
   list(APPEND CVV_LIBRARIES ${Qt5${dt5_dep}_LIBRARIES})
 endforeach()
 
-set(the_description "Debug visualization framework")
-ocv_define_module(cvv opencv_core opencv_imgproc opencv_features2d ${CVV_LIBRARIES} WRAP python)
+ocv_glob_module_sources()
+ocv_module_include_directories()
+ocv_create_module(${CVV_LIBRARIES})
+ocv_add_accuracy_tests()
+ocv_add_perf_tests()
+ocv_add_samples()
diff --git a/contrib/modules/cvv/README.md b/contrib/modules/cvv/README.md
index f6f58ac..9fb0c9a 100644
--- a/contrib/modules/cvv/README.md
+++ b/contrib/modules/cvv/README.md
@@ -1,2 +1,4 @@
 GUI for Interactive Visual Debugging of Computer Vision Programs
 ================================================================
+
+Simple code that you can add to your program that pops up a GUI allowing you to interactively and visually debug computer vision programs.
diff --git a/contrib/modules/cvv/src/impl/filter_call.cpp b/contrib/modules/cvv/src/impl/filter_call.cpp
index ccdd7de..38eb69f 100644
--- a/contrib/modules/cvv/src/impl/filter_call.cpp
+++ b/contrib/modules/cvv/src/impl/filter_call.cpp
@@ -12,8 +12,8 @@ namespace impl
 FilterCall::FilterCall(cv::InputArray in, cv::InputArray out,
                        impl::CallMetaData data, QString type,
                        QString description, QString requestedView)
-    : Call{ data,                   std::move(type),
-	    std::move(description), std::move(requestedView) },
+    : Call( data,                   std::move(type),
+	    std::move(description), std::move(requestedView) ),
       input_{ in.getMat().clone() }, output_{ out.getMat().clone() }
 {
 }
diff --git a/contrib/modules/cvv/src/impl/match_call.cpp b/contrib/modules/cvv/src/impl/match_call.cpp
index d46b4ec..10a7591 100644
--- a/contrib/modules/cvv/src/impl/match_call.cpp
+++ b/contrib/modules/cvv/src/impl/match_call.cpp
@@ -18,8 +18,8 @@ MatchCall::MatchCall(cv::InputArray img1, std::vector<cv::KeyPoint> keypoints1,
                      std::vector<cv::DMatch> matches, impl::CallMetaData data,
                      QString type, QString description, QString requestedView,
                      bool useTrainDescriptor)
-    : Call{ data,                   std::move(type),
-	    std::move(description), std::move(requestedView) },
+    : Call( data,                   std::move(type),
+	    std::move(description), std::move(requestedView) ),
       img1_{ img1.getMat().clone() }, keypoints1_{ std::move(keypoints1) },
       img2_{ img2.getMat().clone() }, keypoints2_{ std::move(keypoints2) },
       matches_{ std::move(matches) }, usesTrainDescriptor_{ useTrainDescriptor }
diff --git a/contrib/modules/cvv/src/impl/single_image_call.cpp b/contrib/modules/cvv/src/impl/single_image_call.cpp
index b9447e5..8bb3633 100644
--- a/contrib/modules/cvv/src/impl/single_image_call.cpp
+++ b/contrib/modules/cvv/src/impl/single_image_call.cpp
@@ -14,8 +14,8 @@ namespace impl
 SingleImageCall::SingleImageCall(cv::InputArray img, impl::CallMetaData data,
                                  QString type, QString description,
                                  QString requestedView)
-    : Call{ data,                   std::move(type),
-	    std::move(description), std::move(requestedView) },
+    : Call( data,                   std::move(type),
+	    std::move(description), std::move(requestedView) ),
       img{ img.getMat().clone() }
 {
 }
diff --git a/contrib/modules/cvv/src/qtutil/matchview/colorutil.hpp b/contrib/modules/cvv/src/qtutil/matchview/colorutil.hpp
index bdc3a66..13f93e2 100644
--- a/contrib/modules/cvv/src/qtutil/matchview/colorutil.hpp
+++ b/contrib/modules/cvv/src/qtutil/matchview/colorutil.hpp
@@ -1,6 +1,7 @@
 #ifndef CVVISUAL_COLOR_UTIL
 #define CVVISUAL_COLOR_UTIL
 
+#include <cstdint>
 #include <vector>
 
 #include <QColor>
diff --git a/contrib/modules/cvv/src/qtutil/util.cpp b/contrib/modules/cvv/src/qtutil/util.cpp
index b1c59f3..26f5266 100644
--- a/contrib/modules/cvv/src/qtutil/util.cpp
+++ b/contrib/modules/cvv/src/qtutil/util.cpp
@@ -4,6 +4,7 @@
 #include <stdexcept>
 #include <thread>
 #include <functional>
+#include <memory>
 
 #include <QDesktopServices>
 #include <QUrl>
diff --git a/contrib/modules/cvv/src/qtutil/zoomableimage.cpp b/contrib/modules/cvv/src/qtutil/zoomableimage.cpp
index 6f9220c..762adb2 100644
--- a/contrib/modules/cvv/src/qtutil/zoomableimage.cpp
+++ b/contrib/modules/cvv/src/qtutil/zoomableimage.cpp
@@ -64,8 +64,8 @@ template <int depth, int channels>
 std::string printPixel(const cv::Mat &mat, int spalte, int zeile)
 {
 	std::stringstream ss{};
-	auto p = mat.at<cv::Vec<cvv::qtutil::DepthType<depth>, channels>>(
-	    zeile, spalte);
+	typedef cv::Vec<cvv::qtutil::DepthType<depth>, channels> VecType;
+	const VecType &p = mat.at<VecType>(zeile, spalte);
 
 	putInStream<depth>(ss, p[0]);
 	for (int c = 1; c < mat.channels(); c++)
diff --git a/contrib/modules/cvv/src/view/defaultfilterview.cpp b/contrib/modules/cvv/src/view/defaultfilterview.cpp
index b5f4799..b7f90b6 100644
--- a/contrib/modules/cvv/src/view/defaultfilterview.cpp
+++ b/contrib/modules/cvv/src/view/defaultfilterview.cpp
@@ -19,7 +19,7 @@ namespace view
 
 DefaultFilterView::DefaultFilterView(const std::vector<cv::Mat> &images,
 				     QWidget *parent)
-    : FilterView{ parent }
+    : FilterView( parent )
 {
 
 	auto layout = util::make_unique<QHBoxLayout>();
diff --git a/contrib/modules/cvv/src/view/dual_filter_view.cpp b/contrib/modules/cvv/src/view/dual_filter_view.cpp
index 37e0fa3..4e5d360 100644
--- a/contrib/modules/cvv/src/view/dual_filter_view.cpp
+++ b/contrib/modules/cvv/src/view/dual_filter_view.cpp
@@ -31,7 +31,7 @@ namespace view
 
 // neuer Konstruktor
 DualFilterView::DualFilterView(std::array<cv::Mat, 2> images, QWidget *parent)
-    : FilterView{ parent }, rawImages_(images)
+    : FilterView( parent ), rawImages_(images)
 {
 	auto layout = util::make_unique<QHBoxLayout>();
 	auto imageLayout = util::make_unique<QHBoxLayout>();
diff --git a/contrib/modules/cvv/src/view/linematchview.cpp b/contrib/modules/cvv/src/view/linematchview.cpp
index ca4c711..3caa365 100644
--- a/contrib/modules/cvv/src/view/linematchview.cpp
+++ b/contrib/modules/cvv/src/view/linematchview.cpp
@@ -24,7 +24,7 @@ LineMatchView::LineMatchView(std::vector<cv::KeyPoint> leftKeyPoints,
 			     std::vector<cv::KeyPoint> rightKeyPoints,
 			     std::vector<cv::DMatch> matches, cv::Mat leftIm,
 			     cv::Mat rightIm, bool usetrainIdx, QWidget *parent)
-    : MatchView{ parent }
+    : MatchView( parent )
 {
 	std::vector<cv::KeyPoint> allkeypoints;
 	for(auto key:rightKeyPoints)
diff --git a/contrib/modules/cvv/src/view/pointmatchview.cpp b/contrib/modules/cvv/src/view/pointmatchview.cpp
index a6ac469..b787418 100644
--- a/contrib/modules/cvv/src/view/pointmatchview.cpp
+++ b/contrib/modules/cvv/src/view/pointmatchview.cpp
@@ -21,7 +21,7 @@ PointMatchView::PointMatchView(std::vector<cv::KeyPoint> leftKeyPoints,
 			       std::vector<cv::DMatch> matches, cv::Mat leftIm,
 			       cv::Mat rightIm, bool usetrainIdx,
 			       QWidget *parent)
-    : MatchView{ parent }
+    : MatchView( parent )
 {
 	auto layout = util::make_unique<QHBoxLayout>();
 	auto accor = util::make_unique<qtutil::Accordion>();
diff --git a/contrib/modules/cvv/src/view/singlefilterview.cpp b/contrib/modules/cvv/src/view/singlefilterview.cpp
index 3fcc69d..7eb9d4d 100644
--- a/contrib/modules/cvv/src/view/singlefilterview.cpp
+++ b/contrib/modules/cvv/src/view/singlefilterview.cpp
@@ -20,7 +20,7 @@ namespace view
 
 SingleFilterView::SingleFilterView(const std::vector<cv::Mat> &images,
 				   QWidget *parent)
-    : FilterView{ parent }
+    : FilterView( parent )
 {
 	auto imwid = util::make_unique<QWidget>();
 	auto accor = util::make_unique<qtutil::Accordion>();
diff --git a/contrib/modules/cvv/src/view/translationsmatchview.cpp b/contrib/modules/cvv/src/view/translationsmatchview.cpp
index 804c9e7..d0fe0ac 100644
--- a/contrib/modules/cvv/src/view/translationsmatchview.cpp
+++ b/contrib/modules/cvv/src/view/translationsmatchview.cpp
@@ -19,7 +19,7 @@ TranslationMatchView::TranslationMatchView(
     std::vector<cv::KeyPoint> leftKeyPoints,
     std::vector<cv::KeyPoint> rightKeyPoints, std::vector<cv::DMatch> matches,
     cv::Mat leftIm, cv::Mat rightIm, bool usetrainIdx, QWidget *parent)
-    : MatchView{ parent }
+    : MatchView( parent )
 {
 	std::vector<cv::KeyPoint> allkeypoints;
 	for(auto key:rightKeyPoints)
diff --git a/contrib/modules/cvv/test/test_location.cpp b/contrib/modules/cvv/test/test_location.cpp
index 0c53c92..0131c69 100644
--- a/contrib/modules/cvv/test/test_location.cpp
+++ b/contrib/modules/cvv/test/test_location.cpp
@@ -10,7 +10,7 @@
 TEST(LocationTest, FileLineFunction)
 {
 	auto locationMacroResult = CVVISUAL_LOCATION;
-	auto line = __LINE__ - 1;
+	size_t line = __LINE__ - 1;
 	auto file = __FILE__;
 	auto fun = CVVISUAL_FUNCTION_NAME_MACRO;
 	EXPECT_EQ(locationMacroResult.isKnown, true);
diff --git a/contrib/modules/cvv/test/test_main.cpp b/contrib/modules/cvv/test/test_main.cpp
index cbf5d88..6118d17 100644
--- a/contrib/modules/cvv/test/test_main.cpp
+++ b/contrib/modules/cvv/test/test_main.cpp
@@ -1,3 +1,3 @@
 #include "test_precomp.hpp"
 
-CV_TEST_MAIN(".")
+CV_TEST_MAIN(".", /*Empty VA_ARGS for C++11*/)
diff --git a/contrib/modules/datasets/README.md b/contrib/modules/datasets/README.md
index 54a3a54..4b2fd1a 100644
--- a/contrib/modules/datasets/README.md
+++ b/contrib/modules/datasets/README.md
@@ -1,2 +1,6 @@
 Interface for interfacing with existing computer vision databases 
 =================================================================
+
+In the src directory, there is code for reading many of the existing computer vision databases.
+
+In the samples directory, there are examples of using the above code to read, train and test on the data.
diff --git a/contrib/modules/datasets/include/opencv2/datasets/track_alov.hpp b/contrib/modules/datasets/include/opencv2/datasets/track_alov.hpp
new file mode 100644
index 0000000..276e2f1
--- /dev/null
+++ b/contrib/modules/datasets/include/opencv2/datasets/track_alov.hpp
@@ -0,0 +1,107 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+//  By downloading, copying, installing or using the software you agree to this license.
+//  If you do not agree to this license, do not download, install,
+//  copy or use the software.
+//
+//
+//                           License Agreement
+//                For Open Source Computer Vision Library
+//
+// Copyright (C) 2014, Itseez Inc, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+//   * Redistribution's of source code must retain the above copyright notice,
+//     this list of conditions and the following disclaimer.
+//
+//   * Redistribution's in binary form must reproduce the above copyright notice,
+//     this list of conditions and the following disclaimer in the documentation
+//     and/or other materials provided with the distribution.
+//
+//   * The name of the copyright holders may not be used to endorse or promote products
+//     derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Itseez Inc or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#ifndef OPENCV_DATASETS_TRACK_ALOV_HPP
+#define OPENCV_DATASETS_TRACK_ALOV_HPP
+
+#include <string>
+#include <vector>
+
+#include "opencv2/datasets/dataset.hpp"
+#include "opencv2/datasets/util.hpp"
+
+using namespace std;
+
+namespace cv
+{
+namespace datasets
+{
+
+//! @addtogroup datasets_track
+//! @{
+
+struct TRACK_alovObj : public Object
+{
+    int id;
+    std::string imagePath;
+    vector <Point2f> gtbb;
+};
+
+const string sectionNames[] = { "01-Light", "02-SurfaceCover", "03-Specularity", "04-Transparency", "05-Shape", "06-MotionSmoothness", "07-MotionCoherence",
+"08-Clutter", "09-Confusion", "10-LowContrast", "11-Occlusion", "12-MovingCamera", "13-ZoomingCamera", "14-LongDuration" };
+
+const int sectionSizes[] = { 33, 15, 18, 20, 24, 22, 12, 15, 37, 23, 34, 22, 29, 10 };
+
+class CV_EXPORTS TRACK_alov : public Dataset
+{
+public:
+    static Ptr<TRACK_alov> create();
+
+    virtual void load(const std::string &path) = 0;
+
+    //Load only frames with annotations (~every 5-th frame)
+    virtual void loadAnnotatedOnly(const std::string &path) = 0;
+
+    virtual int getDatasetsNum() = 0;
+
+    virtual int getDatasetLength(int id) = 0;
+
+    virtual bool initDataset(int id) = 0;
+
+    virtual bool getNextFrame(Mat &frame) = 0;
+    virtual vector <Point2f> getNextGT() = 0;
+
+    //Get frame/GT by datasetID (1..N) frameID (1..K)
+    virtual bool getFrame(Mat &frame, int datasetID, int frameID) = 0;
+    virtual vector <Point2f> getGT(int datasetID, int frameID) = 0;
+
+protected:
+    vector <vector <Ptr<TRACK_alovObj> > > data;
+    int activeDatasetID;
+    int frameCounter;
+};
+
+//! @}
+
+}
+}
+
+#endif
diff --git a/contrib/modules/datasets/src/or_pascal.cpp b/contrib/modules/datasets/src/or_pascal.cpp
index 112a8e5..9afdf1d 100644
--- a/contrib/modules/datasets/src/or_pascal.cpp
+++ b/contrib/modules/datasets/src/or_pascal.cpp
@@ -61,8 +61,8 @@ public:
 
 private:
     void loadDataset(const string &path, const string &nameImageSet, vector< Ptr<Object> > &imageSet);
-    Ptr<Object> parseAnnotation(const string path, const string id);
-    const char*  parseNodeText(XMLElement* node, const string nodeName, const string defaultValue);
+    Ptr<Object> parseAnnotation(const string &path, const string &id);
+    const char*  parseNodeText(XMLElement* node, const string &nodeName, const string &defaultValue);
 };
 
 
@@ -105,17 +105,20 @@ void OR_pascalImp::loadDataset(const string &path, const string &nameImageSet, v
     }
 }
 
-const char* OR_pascalImp::parseNodeText(XMLElement* node, const string nodeName, const string defaultValue)
+const char* OR_pascalImp::parseNodeText(XMLElement* node, const string &nodeName, const string &defaultValue)
 {
-    const char* e = node->FirstChildElement(nodeName.c_str())->GetText();
+    XMLElement* child = node->FirstChildElement(nodeName.c_str());
+    if ( child == 0 )
+        return defaultValue.c_str();
 
-    if( e != 0 )
-        return e ;
-    else
+    const char* e = child->GetText();
+    if( e == 0 )
         return defaultValue.c_str();
+
+    return e ;
 }
 
-Ptr<Object> OR_pascalImp::parseAnnotation(const string path, const string id)
+Ptr<Object> OR_pascalImp::parseAnnotation(const string &path, const string &id)
 {
     string pathAnnotations(path + "Annotations/");
     string pathImages(path + "JPEGImages/");
diff --git a/contrib/modules/datasets/src/track_alov.cpp b/contrib/modules/datasets/src/track_alov.cpp
new file mode 100644
index 0000000..0cdd521
--- /dev/null
+++ b/contrib/modules/datasets/src/track_alov.cpp
@@ -0,0 +1,384 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+//  By downloading, copying, installing or using the software you agree to this license.
+//  If you do not agree to this license, do not download, install,
+//  copy or use the software.
+//
+//
+//                           License Agreement
+//                For Open Source Computer Vision Library
+//
+// Copyright (C) 2014, Itseez Inc, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+//   * Redistribution's of source code must retain the above copyright notice,
+//     this list of conditions and the following disclaimer.
+//
+//   * Redistribution's in binary form must reproduce the above copyright notice,
+//     this list of conditions and the following disclaimer in the documentation
+//     and/or other materials provided with the distribution.
+//
+//   * The name of the copyright holders may not be used to endorse or promote products
+//     derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Itseez Inc or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "opencv2/datasets/track_alov.hpp"
+
+#include <sys/stat.h>
+#include <opencv2/core.hpp>
+#include <opencv2/highgui.hpp>
+
+using namespace std;
+
+namespace cv
+{
+namespace datasets
+{
+
+class TRACK_alovImpl : public TRACK_alov
+{
+public:
+    //Constructor
+    TRACK_alovImpl()
+    {
+        activeDatasetID = 1;
+        frameCounter = 0;
+    }
+    //Destructor
+    virtual ~TRACK_alovImpl() {}
+
+    //Load Dataset
+    virtual void load(const string &path);
+    virtual void loadAnnotatedOnly(const std::string &path);
+
+protected:
+    virtual int getDatasetsNum();
+
+    virtual int getDatasetLength(int id);
+
+    virtual bool initDataset(int id);
+
+    virtual bool getNextFrame(Mat &frame);
+    virtual bool getFrame(Mat &frame, int datasetID, int frameID);
+
+    virtual vector <Point2f> getNextGT();
+    virtual vector <Point2f> getGT(int datasetID, int frameID);
+
+    void loadDataset(const string &path);
+    void loadDatasetAnnotatedOnly(const string &path);
+
+    string fullFramePath(string rootPath, int sectionID, int videoID, int frameID);
+    string fullAnnoPath(string rootPath, int sectionID, int videoID);
+};
+
+
+void TRACK_alovImpl::load(const string &path)
+{
+    loadDataset(path);
+}
+
+void TRACK_alovImpl::loadAnnotatedOnly(const string &path)
+{
+    loadDatasetAnnotatedOnly(path);
+}
+
+string TRACK_alovImpl::fullFramePath(string rootPath, int sectionID, int videoID, int frameID)
+{
+    string out;
+    char videoNum[9];
+    sprintf(videoNum, "%u", videoID+1);
+    char frameNum[9];
+    sprintf(frameNum, "%u", frameID);
+    out = rootPath + "/imagedata++/" + sectionNames[sectionID] + "/" + sectionNames[sectionID] + "_video";
+
+    for (unsigned int i = 0; i < 5 - strlen(videoNum); ++i)
+    {
+        out += "0";
+    }
+
+    out += videoNum;
+    out += "/";
+
+    for (unsigned int i = 0; i < 8 - strlen(frameNum); ++i)
+    {
+        out += "0";
+    }
+
+    out += frameNum;
+    out += ".jpg";
+    return out;
+}
+
+string TRACK_alovImpl::fullAnnoPath(string rootPath, int sectionID, int videoID)
+{
+    string out;
+    char videoNum[9];
+    sprintf(videoNum, "%u", videoID+1);
+    out = rootPath + "/alov300++_rectangleAnnotation_full/" + sectionNames[sectionID] + "/" + sectionNames[sectionID] + "_video";
+
+    for (unsigned int i = 0; i < 5 - strlen(videoNum); ++i)
+    {
+        out += "0";
+    }
+
+    out += videoNum;
+    out += ".ann";
+    return out;
+}
+
+inline bool fileExists(const std::string& name)
+{
+    struct stat buffer;
+    return (stat(name.c_str(), &buffer) == 0);
+}
+
+void TRACK_alovImpl::loadDataset(const string &rootPath)
+{
+    vector <int> datasetsLengths;
+
+    printf("ALOV300++ Dataset Initialization...\n");
+
+    //Load frames
+    //Loop for all sections of ALOV300++ (14 sections)
+    for (int i = 0; i < 14; i++)
+    {
+        //Loop for all videos in section
+        for (int k = 0; k < sectionSizes[i]; k++)
+        {
+            vector <Ptr<TRACK_alovObj> > objects;
+
+            //Make a list of datasets lengths
+            int currFrameID = 0;
+
+            for (;;)
+            {
+                currFrameID++;
+                string fullPath = fullFramePath(rootPath, i, k, currFrameID);
+                if (!fileExists(fullPath))
+                    break;
+
+                //Make ALOV300++ Object
+                Ptr<TRACK_alovObj> currObj(new TRACK_alovObj);
+                currObj->imagePath = fullPath;
+                currObj->id = currFrameID;
+
+                currObj->gtbb.push_back(Point2d(0, 0));
+                currObj->gtbb.push_back(Point2d(0, 0));
+                currObj->gtbb.push_back(Point2d(0, 0));
+                currObj->gtbb.push_back(Point2d(0, 0));
+
+                //Add object to storage
+                objects.push_back(currObj);
+
+            }
+
+            datasetsLengths.push_back(currFrameID - 1);
+            data.push_back(objects);
+        }
+    }
+
+    //Load annotations
+    //Loop for all sections of ALOV300++ (14 sections)
+    int currDatasetID = 0;
+    for (int i = 0; i < 14; i++)
+    {
+        //Loop for all videos in section
+        for (int k = 0; k < sectionSizes[i]; k++)
+        {
+            currDatasetID++;
+
+            //Open dataset's ground truth (annotation) file
+            string annoPath = fullAnnoPath(rootPath, i, k);
+            ifstream annoList(annoPath.c_str());
+            if (!annoList.is_open())
+            {
+                printf("Error: Can't open annotation file *.ANN!!!\n");
+                break;
+            }
+
+            //Ground Truth data
+            int n = 0;
+            double    x1 = 0, y1 = 0,
+                x2 = 0, y2 = 0,
+                x3 = 0, y3 = 0,
+                x4 = 0, y4 = 0;
+
+            do
+            {
+                //Make ALOV300++ Object
+                string tmp;
+
+                getline(annoList, tmp);
+                std::istringstream in(tmp);
+                in >> n >> x1 >> y1 >> x2 >> y2 >> x3 >> y3 >> x4 >> y4;
+
+                Ptr<TRACK_alovObj> currObj = data[currDatasetID-1][n-1];
+
+                currObj->gtbb.clear();
+                currObj->gtbb.push_back(Point2d(x1, y1));
+                currObj->gtbb.push_back(Point2d(x2, y2));
+                currObj->gtbb.push_back(Point2d(x3, y3));
+                currObj->gtbb.push_back(Point2d(x4, y4));
+
+            } while (annoList.good());
+        }
+    }
+
+    return;
+}
+
+void TRACK_alovImpl::loadDatasetAnnotatedOnly(const string &rootPath)
+{
+    vector <int> datasetsLengths;
+    int currDatasetID = 0;
+
+    printf("ALOV300++ Annotated Dataset Initialization...\n");
+
+    //Loop for all sections of ALOV300++ (14 sections)
+    for (int i = 0; i < 14; i++)
+    {
+        //Loop for all videos in section
+        for (int k = 0; k < sectionSizes[i]; k++)
+        {
+            vector <Ptr<TRACK_alovObj> > objects;
+            currDatasetID++;
+
+            //Open dataset's ground truth (annotation) file
+            string annoPath = fullAnnoPath(rootPath, i, k);
+            ifstream annoList(annoPath.c_str());
+            if (!annoList.is_open())
+            {
+                printf("Error: Can't open annotation file *.ANN!!!\n");
+                break;
+            }
+
+            int framesNum = 0;
+
+            do
+            {
+                //Make  ALOV300++ Object
+                Ptr<TRACK_alovObj> currObj(new TRACK_alovObj);
+                string tmp;
+                framesNum++;
+
+                //Ground Truth data
+                int    n = 0;
+                double x1 = 0, y1 = 0,
+                    x2 = 0, y2 = 0,
+                    x3 = 0, y3 = 0,
+                    x4 = 0, y4 = 0;
+
+                getline(annoList, tmp);
+                std::istringstream in(tmp);
+                in >> n >> x1 >> y1 >> x2 >> y2 >> x3 >> y3 >> x4 >> y4;
+
+                currObj->gtbb.push_back(Point2d(x1, y1));
+                currObj->gtbb.push_back(Point2d(x2, y2));
+                currObj->gtbb.push_back(Point2d(x3, y3));
+                currObj->gtbb.push_back(Point2d(x4, y4));
+
+                string fullPath = fullFramePath(rootPath, i, k, n);
+                if (!fileExists(fullPath))
+                    break;
+
+                currObj->imagePath = fullPath;
+                currObj->id = n;
+
+                //Add object to storage
+                objects.push_back(currObj);
+
+            } while (annoList.good());
+
+            datasetsLengths.push_back(framesNum-1);
+            data.push_back(objects);
+        }
+    }
+
+    return;
+}
+
+int TRACK_alovImpl::getDatasetsNum()
+{
+    return (int)(data.size());
+}
+
+int TRACK_alovImpl::getDatasetLength(int id)
+{
+    if (id > 0 && id <= (int)data.size())
+        return (int)(data[id - 1].size());
+    else
+    {
+        printf("Dataset ID is out of range...\nAllowed IDs are: 1~%d\n", (int)data.size());
+        return -1;
+    }
+}
+
+bool TRACK_alovImpl::initDataset(int id)
+{
+    if (id > 0 && id <= (int)data.size())
+    {
+        activeDatasetID = id;
+        return true;
+    }
+    else
+    {
+        printf("Dataset ID is out of range...\nAllowed IDs are: 1~%d\n", (int)data.size());
+        return false;
+    }
+}
+
+bool  TRACK_alovImpl::getNextFrame(Mat &frame)
+{
+    if (frameCounter >= (int)data[activeDatasetID - 1].size())
+        return false;
+    string imgPath = data[activeDatasetID - 1][frameCounter]->imagePath;
+    frame = imread(imgPath);
+    frameCounter++;
+    return !frame.empty();
+}
+
+bool  TRACK_alovImpl::getFrame(Mat &frame, int datasetID, int frameID)
+{
+    if (frameID > (int)data[datasetID-1].size())
+        return false;
+    string imgPath = data[datasetID-1][frameID-1]->imagePath;
+    frame = imread(imgPath);
+    return !frame.empty();
+}
+
+Ptr<TRACK_alov> TRACK_alov::create()
+{
+    return Ptr<TRACK_alovImpl>(new TRACK_alovImpl);
+}
+
+vector <Point2f> TRACK_alovImpl::getNextGT()
+{
+    Ptr <TRACK_alovObj> currObj = data[activeDatasetID - 1][frameCounter - 1];
+    return currObj->gtbb;
+}
+
+vector <Point2f> TRACK_alovImpl::getGT(int datasetID, int frameID)
+{
+    Ptr <TRACK_alovObj> currObj = data[datasetID - 1][frameID - 1];
+    return currObj->gtbb;
+}
+
+}
+}
diff --git a/contrib/modules/dnn/3rdparty/protobuf/CMakeLists.txt b/contrib/modules/dnn/3rdparty/protobuf/CMakeLists.txt
new file mode 100644
index 0000000..9c4a9ed
--- /dev/null
+++ b/contrib/modules/dnn/3rdparty/protobuf/CMakeLists.txt
@@ -0,0 +1,151 @@
+project(libprotobuf)
+
+include(CheckIncludeFiles)
+
+if(NOT MSVC)
+  check_include_files("pthread.h" HAVE_PTHREAD)
+  if(HAVE_PTHREAD)
+    add_definitions(-DHAVE_PTHREAD=1)
+  endif()
+endif()
+
+if(MSVC)
+  add_definitions( -D_CRT_SECURE_NO_WARNINGS=1 )
+  ocv_warnings_disable(CMAKE_CXX_FLAGS /wd4244 /wd4267 /wd4018 /wd4355 /wd4800 /wd4251 /wd4996 /wd4146
+                                       /wd4305 /wd4127 /wd4100 /wd4512 /wd4125 /wd4389 /wd4510 /wd4610
+                                       /wd4702 /wd4456 /wd4457 /wd4065 /wd4310 /wd4661 /wd4506
+  )
+else()
+  ocv_warnings_disable(CMAKE_CXX_FLAGS -Wno-deprecated -Wmissing-prototypes -Wmissing-declarations -Wshadow
+                                       -Wunused-parameter -Wunused-local-typedefs -Wsign-compare -Wsign-promo
+                                       -Wundef -Wtautological-undefined-compare -Wignored-qualifiers -Wextra
+                                       -Wunused-function -Wunused-const-variable
+  )
+endif()
+if(CV_ICC)
+  ocv_warnings_disable(CMAKE_CXX_FLAGS
+      -wd265 -wd858 -wd873 -wd2196
+  )
+endif()
+
+# Easier to support different versions of protobufs
+function(append_if_exist OUTPUT_LIST)
+    set(${OUTPUT_LIST})
+    foreach(fil ${ARGN})
+        if(EXISTS ${fil})
+            list(APPEND ${OUTPUT_LIST} "${fil}")
+        else()
+            message(WARNING "file missing: ${fil}")
+        endif()
+    endforeach()
+    set(${OUTPUT_LIST} ${${OUTPUT_LIST}} PARENT_SCOPE)
+endfunction()
+
+set(PROTOBUF_ROOT "${PROTOBUF_CPP_PATH}/protobuf-3.1.0")
+
+if(MSVC)
+  set(ATOMICOPS_INTERNALS ${PROTOBUF_ROOT}/src/google/protobuf/stubs/atomicops_internals_x86_msvc.cc)
+else()
+  set(ATOMICOPS_INTERNALS ${PROTOBUF_ROOT}/src/google/protobuf/stubs/atomicops_internals_x86_gcc.cc)
+endif()
+
+
+append_if_exist(PROTOBUF_SRCS
+# libprotobuf-lite
+  ${PROTOBUF_ROOT}/src/google/protobuf/arena.cc
+  ${PROTOBUF_ROOT}/src/google/protobuf/arenastring.cc
+  ${PROTOBUF_ROOT}/src/google/protobuf/extension_set.cc
+  ${PROTOBUF_ROOT}/src/google/protobuf/generated_message_util.cc
+  ${PROTOBUF_ROOT}/src/google/protobuf/io/coded_stream.cc
+  ${PROTOBUF_ROOT}/src/google/protobuf/io/zero_copy_stream.cc
+  ${PROTOBUF_ROOT}/src/google/protobuf/io/zero_copy_stream_impl_lite.cc
+  ${PROTOBUF_ROOT}/src/google/protobuf/message_lite.cc
+  ${PROTOBUF_ROOT}/src/google/protobuf/repeated_field.cc
+  ${ATOMICOPS_INTERNALS}
+  ${PROTOBUF_ROOT}/src/google/protobuf/stubs/bytestream.cc
+  ${PROTOBUF_ROOT}/src/google/protobuf/stubs/common.cc
+  ${PROTOBUF_ROOT}/src/google/protobuf/stubs/int128.cc
+  ${PROTOBUF_ROOT}/src/google/protobuf/stubs/once.cc
+  ${PROTOBUF_ROOT}/src/google/protobuf/stubs/status.cc
+  ${PROTOBUF_ROOT}/src/google/protobuf/stubs/statusor.cc
+  ${PROTOBUF_ROOT}/src/google/protobuf/stubs/stringpiece.cc
+  ${PROTOBUF_ROOT}/src/google/protobuf/stubs/stringprintf.cc
+  ${PROTOBUF_ROOT}/src/google/protobuf/stubs/structurally_valid.cc
+  ${PROTOBUF_ROOT}/src/google/protobuf/stubs/strutil.cc
+  ${PROTOBUF_ROOT}/src/google/protobuf/stubs/time.cc
+  ${PROTOBUF_ROOT}/src/google/protobuf/wire_format_lite.cc
+# libprotobuf
+  ${PROTOBUF_ROOT}/src/google/protobuf/any.cc
+  ${PROTOBUF_ROOT}/src/google/protobuf/any.pb.cc
+  ${PROTOBUF_ROOT}/src/google/protobuf/api.pb.cc
+#  ${PROTOBUF_ROOT}/src/google/protobuf/compiler/importer.cc
+#  ${PROTOBUF_ROOT}/src/google/protobuf/compiler/parser.cc
+  ${PROTOBUF_ROOT}/src/google/protobuf/descriptor.cc
+  ${PROTOBUF_ROOT}/src/google/protobuf/descriptor.pb.cc
+  ${PROTOBUF_ROOT}/src/google/protobuf/descriptor_database.cc
+  ${PROTOBUF_ROOT}/src/google/protobuf/duration.pb.cc
+  ${PROTOBUF_ROOT}/src/google/protobuf/dynamic_message.cc
+  ${PROTOBUF_ROOT}/src/google/protobuf/empty.pb.cc
+  ${PROTOBUF_ROOT}/src/google/protobuf/extension_set_heavy.cc
+  ${PROTOBUF_ROOT}/src/google/protobuf/field_mask.pb.cc
+  ${PROTOBUF_ROOT}/src/google/protobuf/generated_message_reflection.cc
+  ${PROTOBUF_ROOT}/src/google/protobuf/io/gzip_stream.cc
+  ${PROTOBUF_ROOT}/src/google/protobuf/io/printer.cc
+  ${PROTOBUF_ROOT}/src/google/protobuf/io/strtod.cc
+  ${PROTOBUF_ROOT}/src/google/protobuf/io/tokenizer.cc
+  ${PROTOBUF_ROOT}/src/google/protobuf/io/zero_copy_stream_impl.cc
+  ${PROTOBUF_ROOT}/src/google/protobuf/map_field.cc
+  ${PROTOBUF_ROOT}/src/google/protobuf/message.cc
+  ${PROTOBUF_ROOT}/src/google/protobuf/reflection_ops.cc
+  ${PROTOBUF_ROOT}/src/google/protobuf/service.cc
+  ${PROTOBUF_ROOT}/src/google/protobuf/source_context.pb.cc
+  ${PROTOBUF_ROOT}/src/google/protobuf/struct.pb.cc
+  ${PROTOBUF_ROOT}/src/google/protobuf/stubs/mathlimits.cc
+  ${PROTOBUF_ROOT}/src/google/protobuf/stubs/substitute.cc
+  ${PROTOBUF_ROOT}/src/google/protobuf/text_format.cc
+  ${PROTOBUF_ROOT}/src/google/protobuf/timestamp.pb.cc
+  ${PROTOBUF_ROOT}/src/google/protobuf/type.pb.cc
+  ${PROTOBUF_ROOT}/src/google/protobuf/unknown_field_set.cc
+  ${PROTOBUF_ROOT}/src/google/protobuf/util/field_comparator.cc
+  ${PROTOBUF_ROOT}/src/google/protobuf/util/field_mask_util.cc
+  ${PROTOBUF_ROOT}/src/google/protobuf/util/internal/datapiece.cc
+  ${PROTOBUF_ROOT}/src/google/protobuf/util/internal/default_value_objectwriter.cc
+#  ${PROTOBUF_ROOT}/src/google/protobuf/util/internal/error_listener.cc
+  ${PROTOBUF_ROOT}/src/google/protobuf/util/internal/field_mask_utility.cc
+  ${PROTOBUF_ROOT}/src/google/protobuf/util/internal/json_escaping.cc
+  ${PROTOBUF_ROOT}/src/google/protobuf/util/internal/json_objectwriter.cc
+  ${PROTOBUF_ROOT}/src/google/protobuf/util/internal/json_stream_parser.cc
+  ${PROTOBUF_ROOT}/src/google/protobuf/util/internal/object_writer.cc
+  ${PROTOBUF_ROOT}/src/google/protobuf/util/internal/proto_writer.cc
+  ${PROTOBUF_ROOT}/src/google/protobuf/util/internal/protostream_objectsource.cc
+  ${PROTOBUF_ROOT}/src/google/protobuf/util/internal/protostream_objectwriter.cc
+  ${PROTOBUF_ROOT}/src/google/protobuf/util/internal/type_info.cc
+#  ${PROTOBUF_ROOT}/src/google/protobuf/util/internal/type_info_test_helper.cc
+  ${PROTOBUF_ROOT}/src/google/protobuf/util/internal/utility.cc
+  ${PROTOBUF_ROOT}/src/google/protobuf/util/json_util.cc
+  ${PROTOBUF_ROOT}/src/google/protobuf/util/message_differencer.cc
+  ${PROTOBUF_ROOT}/src/google/protobuf/util/time_util.cc
+  ${PROTOBUF_ROOT}/src/google/protobuf/util/type_resolver_util.cc
+  ${PROTOBUF_ROOT}/src/google/protobuf/wire_format.cc
+  ${PROTOBUF_ROOT}/src/google/protobuf/wrappers.pb.cc
+)
+
+if(CMAKE_VERSION VERSION_LESS 2.8.9 AND UNIX)
+  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC")
+endif()
+
+add_library(libprotobuf STATIC ${PROTOBUF_SRCS})
+include_directories(${PROTOBUF_ROOT}/src)
+
+set_target_properties(libprotobuf
+    PROPERTIES
+    FOLDER "3rdparty"
+    POSITION_INDEPENDENT_CODE 1    # CMake 2.8.9+
+    OUTPUT_NAME libprotobuf
+    DEBUG_POSTFIX "${OPENCV_DEBUG_POSTFIX}"
+    ARCHIVE_OUTPUT_DIRECTORY ${3P_LIBRARY_OUTPUT_PATH}
+    )
+
+if(NOT BUILD_SHARED_LIBS)
+  ocv_install_target(libprotobuf EXPORT OpenCVModules ARCHIVE DESTINATION ${OPENCV_3P_LIB_INSTALL_PATH} COMPONENT dev)
+endif()
diff --git a/contrib/modules/dnn/CMakeLists.txt b/contrib/modules/dnn/CMakeLists.txt
index 1dc7ff2..7e7a471 100644
--- a/contrib/modules/dnn/CMakeLists.txt
+++ b/contrib/modules/dnn/CMakeLists.txt
@@ -1,6 +1,8 @@
 cmake_minimum_required(VERSION 2.8)
 
-if(IOS OR WINRT)
+if(APPLE_FRAMEWORK OR WINRT
+    OR AARCH64 # protobuf doesn't know this platform
+)
   ocv_module_disable(dnn)
 endif()
 
@@ -8,17 +10,33 @@ set(the_description "Deep neural network module. It allows to load models from d
 set(OPENCV_MODULE_IS_PART_OF_WORLD OFF)
 
 ocv_add_module(dnn opencv_core opencv_imgproc WRAP python matlab)
-ocv_warnings_disable(CMAKE_CXX_FLAGS -Wno-shadow -Wno-parentheses -Wmaybe-uninitialized -Wsign-promo -Wmissing-declarations -Wmissing-prototypes)
-ocv_warnings_disable(CMAKE_CXX_FLAGS /wd4701)
+ocv_warnings_disable(CMAKE_CXX_FLAGS -Wno-shadow -Wno-parentheses -Wmaybe-uninitialized -Wsign-promo
+                                     -Wmissing-declarations -Wmissing-prototypes
+)
+ocv_warnings_disable(CMAKE_CXX_FLAGS /wd4701 /wd4100)
+
+if(MSVC)
+  add_definitions( -D_CRT_SECURE_NO_WARNINGS=1 )
+  ocv_warnings_disable(CMAKE_CXX_FLAGS /wd4244 /wd4267 /wd4018 /wd4355 /wd4800 /wd4251 /wd4996 /wd4146
+                                       /wd4305 /wd4127 /wd4100 /wd4512 /wd4125 /wd4389 /wd4510 /wd4610
+                                       /wd4702 /wd4456 /wd4457 /wd4065 /wd4310 /wd4661 /wd4506
+  )
+else()
+  ocv_warnings_disable(CMAKE_CXX_FLAGS -Wno-deprecated -Wmissing-prototypes -Wmissing-declarations -Wshadow
+                                       -Wunused-parameter -Wunused-local-typedefs -Wsign-compare -Wsign-promo
+                                       -Wundef -Wtautological-undefined-compare -Wignored-qualifiers -Wextra
+                                       -Wunused-function -Wunused-const-variable -Wdeprecated-declarations
+  )
+endif()
 
 # ----------------------------------------------------------------------------
 # Resolve libprotobuf dependency
 # ----------------------------------------------------------------------------
 include(cmake/OpenCVFindLibProtobuf.cmake)
-ocv_glob_module_sources(${PROTOBUF_SRCS} ${PROTOBUF_HDRS})
 ocv_source_group("Src\\protobuf" FILES ${PROTOBUF_SRCS} ${PROTOBUF_HDRS})
 ocv_module_include_directories(include ${PROTOBUF_INCLUDE_DIR})
 
+ocv_glob_module_sources(${PROTOBUF_SRCS} ${PROTOBUF_HDRS} ${CBLAS_H_PROXY_PATH})
 ocv_create_module(${PROTOBUF_LIBRARIES})
 ocv_add_samples()
 ocv_add_accuracy_tests()
@@ -27,12 +45,10 @@ ocv_add_perf_tests()
 # ----------------------------------------------------------------------------
 # Download pre-trained models for complex testing on GoogLeNet and AlexNet
 # ----------------------------------------------------------------------------
-OCV_OPTION(${the_module}_DOWNLOAD_CAFFE_MODELS "Use GoogLeNet Caffe model for testing" OFF IF BUILD_TESTS AND PYTHON2_EXECUTABLE AND DEFINED ENV{OPENCV_TEST_DATA_PATH})
-if(BUILD_TESTS AND PYTHON2_EXECUTABLE AND DEFINED ENV{OPENCV_TEST_DATA_PATH}
-        AND (DOWNLOAD_EXTERNAL_TEST_DATA OR ${the_module}_DOWNLOAD_CAFFE_MODELS))
+OCV_OPTION(${the_module}_DOWNLOAD_CAFFE_MODELS "Use GoogLeNet Caffe model for testing" OFF IF BUILD_TESTS AND DEFINED ENV{OPENCV_TEST_DATA_PATH})
+if(BUILD_TESTS AND DEFINED ENV{OPENCV_TEST_DATA_PATH} AND (DOWNLOAD_EXTERNAL_TEST_DATA OR ${the_module}_DOWNLOAD_CAFFE_MODELS))
     add_custom_command( TARGET opencv_test_${name} POST_BUILD
-                        COMMAND ${PYTHON2_EXECUTABLE} download_model.py test_models.json
-                        WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/scripts )
+                        COMMAND ${CMAKE_COMMAND} -Dmodel=GoogleNet -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/download_model.cmake)
     add_definitions(-DENABLE_CAFFE_MODEL_TESTS=1)
 endif()
 
@@ -43,21 +59,29 @@ OCV_OPTION(${the_module}_BUILD_TORCH_IMPORTER "Build Torch model importer (exper
 if(${the_module}_BUILD_TORCH_IMPORTER)
     add_definitions(-DENABLE_TORCH_IMPORTER=1)
     ocv_warnings_disable(CMAKE_CXX_FLAGS /wd4702 /wd4127 /wd4267) #supress warnings in original torch files
+
+    if(NOT DEFINED HAVE_TORCH_EXE)
+        execute_process(COMMAND th ${CMAKE_CURRENT_SOURCE_DIR}/testdata/dnn/torch/torch_nn_echo.lua RESULT_VARIABLE TORCH_EXE_STATUS)
+        set(HAVE_TORCH_EXE OFF)
+        if(${TORCH_EXE_STATUS} EQUAL 0)
+            set(HAVE_TORCH_EXE ON)
+        endif()
+        set(HAVE_TORCH_EXE ${HAVE_TORCH_EXE} CACHE INTERNAL "Have torch binary")
+    endif()
 endif()
 
 # ----------------------------------------------------------------------------
 # Generating test data for Torch importer
 # ----------------------------------------------------------------------------
-OCV_OPTION(${the_module}_BUILD_TORCH_TESTS "Build Torch tests (installed torch7 with nn module is required)" ON IF BUILD_TESTS AND ${the_module}_BUILD_TORCH_IMPORTER)
+OCV_OPTION(${the_module}_BUILD_TORCH_TESTS "Build Torch tests (installed torch7 with nn module is required)" ON IF BUILD_TESTS AND ${the_module}_BUILD_TORCH_IMPORTER AND HAVE_TORCH_EXE)
 if(${the_module}_BUILD_TORCH_TESTS)
 
     if(NOT DEFINED ENV{OPENCV_TEST_DATA_PATH})
         message(FATAL_ERROR "OPENCV_TEST_DATA_PATH environment variable was not specified")
     endif()
 
-    execute_process(COMMAND th ${CMAKE_CURRENT_SOURCE_DIR}/testdata/dnn/torch/torch_nn_echo.lua RESULT_VARIABLE TORCH_STATUS)
-    if(TORCH_STATUS)
-        message(FATAL_ERROR "Torch executable \"th\" not found (status: ${TORCH_STATUS}) or nn module not found")
+    if(NOT HAVE_TORCH_EXE)
+        message(FATAL_ERROR "Torch executable \"th\" not found or nn module not found")
     endif()
 
     add_custom_command( TARGET opencv_test_${name} POST_BUILD
diff --git a/contrib/modules/dnn/cmake/OpenCVFindLibProtobuf.cmake b/contrib/modules/dnn/cmake/OpenCVFindLibProtobuf.cmake
index b6a038c..eb2a729 100644
--- a/contrib/modules/dnn/cmake/OpenCVFindLibProtobuf.cmake
+++ b/contrib/modules/dnn/cmake/OpenCVFindLibProtobuf.cmake
@@ -1,43 +1,56 @@
-OCV_OPTION(BUILD_LIBPROTOBUF_FROM_SOURCES "Force to build libprotobuf from sources (don't try to find it in system)" OFF)
+# By default, we use built-in protobuf sources and pre-generated .proto files
+# Note: In case of .proto model updates these variables should be used:
+# - PROTOBUF_PROTOC_EXECUTABLE (required)
+# - PROTOBUF_INCLUDE_DIR
+# - PROTOBUF_LIBRARIES or PROTOBUF_LIBRARY / PROTOBUF_LIBRARY_DEBUG for find_package()
+OCV_OPTION(BUILD_PROTOBUF "Force to build libprotobuf from sources" ON)
+OCV_OPTION(UPDATE_PROTO_FILES "Force to rebuild .proto files" OFF)
 
-if(NOT BUILD_LIBPROTOBUF_FROM_SOURCES)
-  find_package(Protobuf)
-endif()
-
-if(NOT BUILD_LIBPROTOBUF_FROM_SOURCES AND PROTOBUF_FOUND AND EXISTS ${PROTOBUF_PROTOC_EXECUTABLE})
-  message(STATUS "The protocol buffer compiler and libprotobuf were found")
-  PROTOBUF_GENERATE_CPP(PROTOBUF_HDRS PROTOBUF_SRCS src/caffe/caffe.proto)
-  add_definitions(-DHAVE_PROTOBUF=1)
-else()
-  message(STATUS "Build libprotobuf from sources:")
-  if(NOT PROTOBUF_FOUND)
-  message(STATUS "    libprotobuf not found into system")
+if(UPDATE_PROTO_FILES)
+  if(NOT DEFINED PROTOBUF_PROTOC_EXECUTABLE)
+    find_package(Protobuf QUIET)
   endif()
-  if(NOT EXISTS ${PROTOBUF_PROTOC_EXECUTABLE})
-  message(STATUS "    The protocol buffer compiler not found")
+  if(DEFINED PROTOBUF_PROTOC_EXECUTABLE AND EXISTS ${PROTOBUF_PROTOC_EXECUTABLE})
+    message(STATUS "The protocol buffer compiler is found (${PROTOBUF_PROTOC_EXECUTABLE})")
+    file(GLOB proto_files src/tensorflow/*.proto)
+    list(APPEND proto_files src/caffe/caffe.proto)
+    PROTOBUF_GENERATE_CPP(PROTOBUF_HDRS PROTOBUF_SRCS ${proto_files})
+  else()
+    message(FATAL_ERROR "The protocol buffer compiler is not found (PROTOBUF_PROTOC_EXECUTABLE='${PROTOBUF_PROTOC_EXECUTABLE}')")
   endif()
+endif()
 
-  #take into account OpenCV two-pass module addition scheme
-  if(NOT OPENCV_INITIAL_PASS) #TODO: it looks like a hack
-  add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/protobuf)
-  endif()
+if(NOT BUILD_PROTOBUF AND NOT (DEFINED PROTOBUF_INCLUDE_DIR AND DEFINED PROTOBUF_LIBRARIES))
+  find_package(Protobuf QUIET)
+endif()
 
+if(PROTOBUF_FOUND)
+  # nothing
+else()
+  include(${CMAKE_CURRENT_LIST_DIR}/download_protobuf.cmake)
+  add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/protobuf)
   set(PROTOBUF_LIBRARIES libprotobuf)
-  set(PROTOBUF_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/protobuf/src ${CMAKE_CURRENT_BINARY_DIR})
-  set(PROTOBUF_SRCS ${CMAKE_CURRENT_BINARY_DIR}/caffe.pb.cc)
-  set(PROTOBUF_HDRS ${CMAKE_CURRENT_BINARY_DIR}/caffe.pb.h)
-  add_definitions(-DHAVE_PROTOBUF=1)
+  set(PROTOBUF_INCLUDE_DIR ${PROTOBUF_CPP_PATH}/protobuf-3.1.0/src)
+endif()
+
+if(NOT UPDATE_PROTO_FILES)
+  file(GLOB fw_srcs ${CMAKE_CURRENT_SOURCE_DIR}/misc/tensorflow/*.cc)
+  file(GLOB fw_hdrs ${CMAKE_CURRENT_SOURCE_DIR}/misc/tensorflow/*.h)
+  list(APPEND fw_srcs ${CMAKE_CURRENT_SOURCE_DIR}/misc/caffe/caffe.pb.cc)
+  list(APPEND fw_hdrs ${CMAKE_CURRENT_SOURCE_DIR}/misc/caffe/caffe.pb.h)
+  list(APPEND PROTOBUF_SRCS ${fw_srcs})
+  list(APPEND PROTOBUF_HDRS ${fw_hdrs})
+  list(APPEND PROTOBUF_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/misc/caffe)
+  list(APPEND PROTOBUF_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/misc/tensorflow)
+endif()
 
-  add_custom_command(
-    OUTPUT ${PROTOBUF_SRCS} ${PROTOBUF_HDRS}
-    COMMAND ${CMAKE_COMMAND} -E tar xzf ${CMAKE_CURRENT_SOURCE_DIR}/src/caffe/compiled/caffe.tar.gz
-    WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
-    COMMENT "Unpacking compiled caffe protobuf files"
-    VERBATIM
-  )
-  set_source_files_properties(${PROTOBUF_SRCS} ${PROTOBUF_HDRS} PROPERTIES GENERATED TRUE)
+add_definitions(-DHAVE_PROTOBUF=1)
 
-  #supress warnings in autogenerated caffe.pb.* files
-  ocv_warnings_disable(CMAKE_CXX_FLAGS -Wunused-parameter)
-  ocv_warnings_disable(CMAKE_CXX_FLAGS /wd4125 /wd4267 /wd4127 /wd4244 /wd4512 /wd4702)
-endif()
\ No newline at end of file
+#supress warnings in autogenerated caffe.pb.* files
+ocv_warnings_disable(CMAKE_CXX_FLAGS
+    -Wunused-parameter -Wundef -Wignored-qualifiers -Wno-enum-compare
+    -Wdeprecated-declarations
+    /wd4125 /wd4267 /wd4127 /wd4244 /wd4512 /wd4702
+    /wd4456 /wd4510 /wd4610 /wd4800
+    -wd858 -wd2196
+)
diff --git a/contrib/modules/dnn/cmake/download_model.cmake b/contrib/modules/dnn/cmake/download_model.cmake
new file mode 100644
index 0000000..ebe57d9
--- /dev/null
+++ b/contrib/modules/dnn/cmake/download_model.cmake
@@ -0,0 +1,31 @@
+set(GoogleNet_url "http://dl.caffe.berkeleyvision.org/bvlc_googlenet.caffemodel")
+set(GoogleNet_dst "$ENV{OPENCV_TEST_DATA_PATH}/dnn/bvlc_googlenet.caffemodel")
+set(GoogleNet_sha "405fc5acd08a3bb12de8ee5e23a96bec22f08204")
+
+set(VGG16_url "http://www.robots.ox.ac.uk/~vgg/software/very_deep/caffe/VGG_ILSVRC_16_layers.caffemodel")
+set(GG16_dst "$ENV{OPENCV_TEST_DATA_PATH}/dnn/VGG_ILSVRC_16_layers.caffemodel")
+
+set(voc-fcn32s_url "http://dl.caffe.berkeleyvision.org/fcn32s-heavy-pascal.caffemodel")
+set(voc-fcn32s_dst "$ENV{OPENCV_TEST_DATA_PATH}/dnn/fcn32s-heavy-pascal.caffemodel")
+
+if(NOT model)
+    set(model "GoogleNet")
+endif()
+
+message(STATUS "Downloading ${${model}_url} to ${${model}_dst}")
+
+if(NOT EXISTS ${${model}_dst})
+    if(${${model}_sha})
+        file(DOWNLOAD ${${model}_url} ${${model}_dst} SHOW_PROGRESS EXPECTED_HASH SHA1=${${model}_sha} STATUS status_vec)
+    else()
+        file(DOWNLOAD ${${model}_url} ${${model}_dst} SHOW_PROGRESS STATUS status_vec)
+    endif()
+
+    list(GET status_vec 0 status)
+    list(GET status_vec 1 status_msg)
+    if(status EQUAL 0)
+        message(STATUS "Ok! ${status_msg}")
+    else()
+        message(STATUS "Fail! ${status_msg}")
+    endif()
+endif()
diff --git a/contrib/modules/dnn/cmake/download_protobuf.cmake b/contrib/modules/dnn/cmake/download_protobuf.cmake
new file mode 100644
index 0000000..66ca853
--- /dev/null
+++ b/contrib/modules/dnn/cmake/download_protobuf.cmake
@@ -0,0 +1,51 @@
+set(PROTOBUF_CPP_NAME "libprotobuf")
+set(PROTOBUF_CPP_DOWNLOAD_HASH "bd5e3eed635a8d32e2b99658633815ef")
+set(PROTOBUF_CPP_PATH "${CMAKE_CURRENT_BINARY_DIR}/3rdparty/protobuf/sources") # /protobuf-3.1.0 subdirectory
+
+set(OPENCV_PROTOBUF_CPP_DOWNLOAD_URL ${OPENCV_PROTOBUF_URL};$ENV{OPENCV_PROTOBUF_URL};https://github.com/google/protobuf/releases/download/)
+
+function(ocv_protobuf_download file ID)
+  if(DEFINED ${ID}_DOWNLOADED_HASH
+       AND ${ID}_DOWNLOADED_HASH STREQUAL ${ID}_DOWNLOAD_HASH
+       AND EXISTS ${${ID}_PATH})
+    # Files have been downloaded and checked by the previous CMake run
+    return()
+  else()
+    if(EXISTS ${${ID}_PATH})
+      message(STATUS "${${ID}_NAME}: Removing previous unpacked files: ${${ID}_PATH}")
+      file(REMOVE_RECURSE ${${ID}_PATH})
+    endif()
+  endif()
+  unset(${ID}_DOWNLOADED_HASH CACHE)
+
+  file(MAKE_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/.download)
+  file(WRITE "${CMAKE_CURRENT_SOURCE_DIR}/.download/.gitignore" "*\n")
+  ocv_download(PACKAGE ${file}
+               HASH ${${ID}_DOWNLOAD_HASH}
+               URL ${OPENCV_${ID}_DOWNLOAD_URL}
+               DOWNLOAD_DIR ${CMAKE_CURRENT_SOURCE_DIR}/.download)
+  set(${ID}_ARCHIVE "${DOWNLOAD_PACKAGE_LOCATION}")
+
+  ocv_assert(EXISTS "${${ID}_ARCHIVE}")
+  ocv_assert(NOT EXISTS "${${ID}_PATH}")
+  file(MAKE_DIRECTORY ${${ID}_PATH})
+  ocv_assert(EXISTS "${${ID}_PATH}")
+  file(WRITE "${${ID}_PATH}/.gitignore" "*\n")
+
+  message(STATUS "${${ID}_NAME}: Unpacking ${file} to ${${ID}_PATH}...")
+  execute_process(COMMAND ${CMAKE_COMMAND} -E tar xz "${${ID}_ARCHIVE}"
+                  WORKING_DIRECTORY "${${ID}_PATH}"
+                  RESULT_VARIABLE __result)
+
+  if(NOT __result EQUAL 0)
+    message(FATAL_ERROR "${${ID}_NAME}: Failed to unpack ${ID} archive from ${${ID}_ARCHIVE} to ${${ID}_PATH} with error ${__result}")
+  endif()
+
+  ocv_assert(EXISTS "${${ID}_PATH}")
+
+  set(${ID}_DOWNLOADED_HASH "${${ID}_DOWNLOAD_HASH}" CACHE INTERNAL "${ID} hash")
+
+  #message(STATUS "${${ID}_NAME}: Successfully downloaded")
+endfunction()
+
+ocv_protobuf_download(v3.1.0/protobuf-cpp-3.1.0.tar.gz PROTOBUF_CPP)
diff --git a/contrib/modules/dnn/include/opencv2/dnn/all_layers.hpp b/contrib/modules/dnn/include/opencv2/dnn/all_layers.hpp
new file mode 100644
index 0000000..ace63dd
--- /dev/null
+++ b/contrib/modules/dnn/include/opencv2/dnn/all_layers.hpp
@@ -0,0 +1,405 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+//  By downloading, copying, installing or using the software you agree to this license.
+//  If you do not agree to this license, do not download, install,
+//  copy or use the software.
+//
+//
+//                           License Agreement
+//                For Open Source Computer Vision Library
+//
+// Copyright (C) 2013, OpenCV Foundation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+//   * Redistribution's of source code must retain the above copyright notice,
+//     this list of conditions and the following disclaimer.
+//
+//   * Redistribution's in binary form must reproduce the above copyright notice,
+//     this list of conditions and the following disclaimer in the documentation
+//     and/or other materials provided with the distribution.
+//
+//   * The name of the copyright holders may not be used to endorse or promote products
+//     derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#ifndef __OPENCV_DNN_DNN_ALL_LAYERS_HPP__
+#define __OPENCV_DNN_DNN_ALL_LAYERS_HPP__
+#include <opencv2/dnn.hpp>
+
+namespace cv
+{
+namespace dnn
+{
+//! @addtogroup dnn
+//! @{
+
+/** @defgroup dnnLayerList Partial List of Implemented Layers
+  @{
+  This subsection of dnn module contains information about bult-in layers and their descriptions.
+
+  Classes listed here, in fact, provides C++ API for creating intances of bult-in layers.
+  In addition to this way of layers instantiation, there is a more common factory API (see @ref dnnLayerFactory), it allows to create layers dynamically (by name) and register new ones.
+  You can use both API, but factory API is less convinient for native C++ programming and basically designed for use inside importers (see @ref Importer, @ref createCaffeImporter(), @ref createTorchImporter()).
+
+  Bult-in layers partially reproduce functionality of corresponding Caffe and Torch7 layers.
+  In partuclar, the following layers and Caffe @ref Importer were tested to reproduce <a href="http://caffe.berkeleyvision.org/tutorial/layers.html">Caffe</a> functionality:
+  - Convolution
+  - Deconvolution
+  - Pooling
+  - InnerProduct
+  - TanH, ReLU, Sigmoid, BNLL, Power, AbsVal
+  - Softmax
+  - Reshape, Flatten, Slice, Split
+  - LRN
+  - MVN
+  - Dropout (since it does nothing on forward pass -))
+*/
+
+    //! LSTM recurrent layer
+    class CV_EXPORTS_W LSTMLayer : public Layer
+    {
+    public:
+        /** Creates instance of LSTM layer */
+        static CV_WRAP Ptr<LSTMLayer> create();
+
+        /** Set trained weights for LSTM layer.
+        LSTM behavior on each step is defined by current input, previous output, previous cell state and learned weights.
+
+        Let @f$x_t at f$ be current input, @f$h_t at f$ be current output, @f$c_t at f$ be current state.
+        Than current output and current cell state is computed as follows:
+        @f{eqnarray*}{
+        h_t &= o_t \odot tanh(c_t),               \\
+        c_t &= f_t \odot c_{t-1} + i_t \odot g_t, \\
+        @f}
+        where @f$\odot at f$ is per-element multiply operation and @f$i_t, f_t, o_t, g_t at f$ is internal gates that are computed using learned wights.
+
+        Gates are computed as follows:
+        @f{eqnarray*}{
+        i_t &= sigmoid&(W_{xi} x_t + W_{hi} h_{t-1} + b_i), \\
+        f_t &= sigmoid&(W_{xf} x_t + W_{hf} h_{t-1} + b_f), \\
+        o_t &= sigmoid&(W_{xo} x_t + W_{ho} h_{t-1} + b_o), \\
+        g_t &= tanh   &(W_{xg} x_t + W_{hg} h_{t-1} + b_g), \\
+        @f}
+        where @f$W_{x?}@f$, @f$W_{h?}@f$ and @f$b_{?}@f$ are learned weights represented as matrices:
+        @f$W_{x?} \in R^{N_h \times N_x}@f$, @f$W_{h?} \in R^{N_h \times N_h}@f$, @f$b_? \in R^{N_h}@f$.
+
+        For simplicity and performance purposes we use @f$ W_x = [W_{xi}; W_{xf}; W_{xo}, W_{xg}] @f$
+        (i.e. @f$W_x at f$ is vertical contacentaion of @f$ W_{x?} @f$), @f$ W_x \in R^{4N_h \times N_x} @f$.
+        The same for @f$ W_h = [W_{hi}; W_{hf}; W_{ho}, W_{hg}], W_h \in R^{4N_h \times N_h} @f$
+        and for @f$ b = [b_i; b_f, b_o, b_g]@f$, @f$b \in R^{4N_h} @f$.
+
+        @param Wh is matrix defining how previous output is transformed to internal gates (i.e. according to abovemtioned notation is @f$ W_h @f$)
+        @param Wx is matrix defining how current input is transformed to internal gates (i.e. according to abovemtioned notation is @f$ W_x @f$)
+        @param b  is bias vector (i.e. according to abovemtioned notation is @f$ b @f$)
+        */
+        CV_WRAP virtual void setWeights(const Blob &Wh, const Blob &Wx, const Blob &b) = 0;
+
+        /** @brief Specifies shape of output blob which will be [[`T`], `N`] + @p outTailShape.
+          * @details If this parameter is empty or unset then @p outTailShape = [`Wh`.size(0)] will be used,
+          * where `Wh` is parameter from setWeights().
+          */
+        CV_WRAP virtual void setOutShape(const BlobShape &outTailShape = BlobShape::empty()) = 0;
+
+        /** @brief Set @f$ h_{t-1} @f$ value that will be used in next forward() calls.
+          * @details By-default @f$ h_{t-1} @f$ is inited by zeros and updated after each forward() call.
+          */
+        CV_WRAP virtual void setH(const Blob &H) = 0;
+        /** @brief Returns current @f$ h_{t-1} @f$ value (deep copy). */
+        CV_WRAP virtual Blob getH() const = 0;
+
+        /** @brief Set @f$ c_{t-1} @f$ value that will be used in next forward() calls.
+          * @details By-default @f$ c_{t-1} @f$ is inited by zeros and updated after each forward() call.
+          */
+        CV_WRAP virtual void setC(const Blob &C) = 0;
+        /** @brief Returns current @f$ c_{t-1} @f$ value (deep copy). */
+        CV_WRAP virtual Blob getC() const = 0;
+
+        /** @brief Specifies either interpet first dimension of input blob as timestamp dimenion either as sample.
+          *
+          * If flag is set to true then shape of input blob will be interpeted as [`T`, `N`, `[data dims]`] where `T` specifies number of timpestamps, `N` is number of independent streams.
+          * In this case each forward() call will iterate through `T` timestamps and update layer's state `T` times.
+          *
+          * If flag is set to false then shape of input blob will be interpeted as [`N`, `[data dims]`].
+          * In this case each forward() call will make one iteration and produce one timestamp with shape [`N`, `[out dims]`].
+          */
+        CV_WRAP virtual void setUseTimstampsDim(bool use = true) = 0;
+
+        /** @brief If this flag is set to true then layer will produce @f$ c_t @f$ as second output.
+         * @details Shape of the second output is the same as first output.
+         */
+        CV_WRAP virtual void setProduceCellOutput(bool produce = false) = 0;
+
+        /** In common case it use single input with @f$x_t at f$ values to compute output(s) @f$h_t at f$ (and @f$c_t at f$).
+         * @param input should contain packed values @f$x_t at f$
+         * @param output contains computed outputs: @f$h_t at f$ (and @f$c_t at f$ if setProduceCellOutput() flag was set to true).
+         *
+         * If setUseTimstampsDim() is set to true then @p input[0] should has at least two dimensions with the following shape: [`T`, `N`, `[data dims]`],
+         * where `T` specifies number of timpestamps, `N` is number of independent streams (i.e. @f$ x_{t_0 + t}^{stream} @f$ is stored inside @p input[0][t, stream, ...]).
+         *
+         * If setUseTimstampsDim() is set to fase then @p input[0] should contain single timestamp, its shape should has form [`N`, `[data dims]`] with at least one dimension.
+         * (i.e. @f$ x_{t}^{stream} @f$ is stored inside @p input[0][stream, ...]).
+        */
+        void forward(std::vector<Blob*> &input, std::vector<Blob> &output);
+
+        int inputNameToIndex(String inputName);
+
+        int outputNameToIndex(String outputName);
+    };
+
+    //! Classical recurrent layer
+    class CV_EXPORTS_W RNNLayer : public Layer
+    {
+    public:
+        /** Creates instance of RNNLayer */
+        static CV_WRAP Ptr<RNNLayer> create();
+
+        /** Setups learned weights.
+
+        Recurrent-layer behavior on each step is defined by current input @f$ x_t @f$, previous state @f$ h_t @f$ and learned weights as follows:
+        @f{eqnarray*}{
+        h_t &= tanh&(W_{hh} h_{t-1} + W_{xh} x_t + b_h),  \\
+        o_t &= tanh&(W_{ho} h_t + b_o),
+        @f}
+
+        @param Wxh is @f$ W_{xh} @f$ matrix
+        @param bh  is @f$ b_{h}  @f$ vector
+        @param Whh is @f$ W_{hh} @f$ matrix
+        @param Who is @f$ W_{xo} @f$ matrix
+        @param bo  is @f$ b_{o}  @f$ vector
+        */
+        CV_WRAP virtual void setWeights(const Blob &Wxh, const Blob &bh, const Blob &Whh, const Blob &Who, const Blob &bo) = 0;
+
+        /** @brief If this flag is set to true then layer will produce @f$ h_t @f$ as second output.
+         * @details Shape of the second output is the same as first output.
+         */
+        CV_WRAP virtual void setProduceHiddenOutput(bool produce = false) = 0;
+
+        /** Accepts two inputs @f$x_t at f$ and @f$h_{t-1}@f$ and compute two outputs @f$o_t at f$ and @f$h_t at f$.
+
+        @param input should contain packed input @f$x_t at f$.
+        @param output should contain output @f$o_t at f$ (and @f$h_t at f$ if setProduceHiddenOutput() is set to true).
+
+        @p input[0] should have shape [`T`, `N`, `data_dims`] where `T` and `N` is number of timestamps and number of independent samples of @f$x_t at f$ respectively.
+
+        @p output[0] will have shape [`T`, `N`, @f$N_o at f$], where @f$N_o at f$ is number of rows in @f$ W_{xo} @f$ matrix.
+
+        If setProduceHiddenOutput() is set to true then @p output[1] will contain a Blob with shape [`T`, `N`, @f$N_h at f$], where @f$N_h at f$ is number of rows in @f$ W_{hh} @f$ matrix.
+        */
+        void forward(std::vector<Blob*> &input, std::vector<Blob> &output);
+    };
+
+    class CV_EXPORTS_W BaseConvolutionLayer : public Layer
+    {
+    public:
+
+        CV_PROP_RW Size kernel, stride, pad, dilation;
+        CV_PROP_RW String padMode;
+    };
+
+    class CV_EXPORTS_W ConvolutionLayer : public BaseConvolutionLayer
+    {
+    public:
+
+        static CV_WRAP Ptr<BaseConvolutionLayer> create(Size kernel = Size(3, 3), Size stride = Size(1, 1), Size pad = Size(0, 0), Size dilation = Size(1, 1));
+    };
+
+    class CV_EXPORTS_W DeconvolutionLayer : public BaseConvolutionLayer
+    {
+    public:
+
+        static CV_WRAP Ptr<BaseConvolutionLayer> create(Size kernel = Size(3, 3), Size stride = Size(1, 1), Size pad = Size(0, 0), Size dilation = Size(1, 1));
+    };
+
+    class CV_EXPORTS_W LRNLayer : public Layer
+    {
+    public:
+
+        enum Type
+        {
+            CHANNEL_NRM,
+            SPATIAL_NRM
+        };
+        CV_PROP_RW int type;
+
+        CV_PROP_RW int size;
+        CV_PROP_RW double alpha, beta, bias;
+        CV_PROP_RW bool normBySize;
+
+        static CV_WRAP Ptr<LRNLayer> create(int type = LRNLayer::CHANNEL_NRM, int size = 5,
+                                            double alpha = 1, double beta = 0.75, double bias = 1,
+                                            bool normBySize = true);
+    };
+
+    class CV_EXPORTS_W PoolingLayer : public Layer
+    {
+    public:
+
+        enum Type
+        {
+            MAX,
+            AVE,
+            STOCHASTIC
+        };
+
+        CV_PROP_RW int type;
+        CV_PROP_RW Size kernel, stride, pad;
+        CV_PROP_RW bool globalPooling;
+        CV_PROP_RW String padMode;
+
+        static CV_WRAP Ptr<PoolingLayer> create(int type = PoolingLayer::MAX, Size kernel = Size(2, 2),
+                                                Size stride = Size(1, 1), Size pad = Size(0, 0),
+                                                const cv::String& padMode = "");
+        static CV_WRAP Ptr<PoolingLayer> createGlobal(int type = PoolingLayer::MAX);
+    };
+
+    class CV_EXPORTS_W SoftmaxLayer : public Layer
+    {
+    public:
+
+        static CV_WRAP Ptr<SoftmaxLayer> create(int axis = 1);
+    };
+
+    class CV_EXPORTS_W InnerProductLayer : public Layer
+    {
+    public:
+        CV_PROP_RW int axis;
+
+        static CV_WRAP Ptr<InnerProductLayer> create(int axis = 1);
+    };
+
+    class CV_EXPORTS_W MVNLayer : public Layer
+    {
+    public:
+        CV_PROP_RW double eps;
+        CV_PROP_RW bool normVariance, acrossChannels;
+
+        static CV_WRAP Ptr<MVNLayer> create(bool normVariance = true, bool acrossChannels = false, double eps = 1e-9);
+    };
+
+    /* Reshaping */
+
+    class CV_EXPORTS_W ReshapeLayer : public Layer
+    {
+    public:
+        CV_PROP_RW BlobShape newShapeDesc;
+        CV_PROP_RW Range newShapeRange;
+
+        static CV_WRAP Ptr<ReshapeLayer> create(const BlobShape &newShape, Range applyingRange = Range::all(),
+                                                bool enableReordering = false);
+    };
+
+    class CV_EXPORTS_W ConcatLayer : public Layer
+    {
+    public:
+        int axis;
+
+        static CV_WRAP Ptr<ConcatLayer> create(int axis = 1);
+    };
+
+    class CV_EXPORTS_W SplitLayer : public Layer
+    {
+    public:
+        int outputsCount; //!< Number of copies that will be produced (is ignored when negative).
+
+        static CV_WRAP Ptr<SplitLayer> create(int outputsCount = -1);
+    };
+
+    class CV_EXPORTS_W SliceLayer : public Layer
+    {
+    public:
+        CV_PROP_RW int axis;
+        CV_PROP std::vector<int> sliceIndices;
+
+        static CV_WRAP Ptr<SliceLayer> create(int axis);
+        static CV_WRAP Ptr<SliceLayer> create(int axis, const std::vector<int> &sliceIndices);
+    };
+
+    /* Activations */
+
+    class CV_EXPORTS_W ReLULayer : public Layer
+    {
+    public:
+        CV_PROP_RW double negativeSlope;
+
+        static CV_WRAP Ptr<ReLULayer> create(double negativeSlope = 0);
+    };
+
+    class CV_EXPORTS_W TanHLayer : public Layer
+    {
+    public:
+        static CV_WRAP Ptr<TanHLayer> create();
+    };
+
+    class CV_EXPORTS_W SigmoidLayer : public Layer
+    {
+    public:
+        static CV_WRAP Ptr<SigmoidLayer> create();
+    };
+
+    class CV_EXPORTS_W BNLLLayer : public Layer
+    {
+    public:
+        static CV_WRAP Ptr<BNLLLayer> create();
+    };
+
+    class CV_EXPORTS_W AbsLayer : public Layer
+    {
+    public:
+        static CV_WRAP Ptr<AbsLayer> create();
+    };
+
+    class CV_EXPORTS_W PowerLayer : public Layer
+    {
+    public:
+        CV_PROP_RW double power, scale, shift;
+
+        static CV_WRAP Ptr<PowerLayer> create(double power = 1, double scale = 1, double shift = 0);
+    };
+
+    /* Layers using in semantic segmentation */
+
+    class CV_EXPORTS_W CropLayer : public Layer
+    {
+    public:
+        CV_PROP int startAxis;
+        CV_PROP std::vector<int> offset;
+
+        static Ptr<CropLayer> create(int start_axis, const std::vector<int> &offset);
+    };
+
+    class CV_EXPORTS_W EltwiseLayer : public Layer
+    {
+    public:
+        enum EltwiseOp
+        {
+            PROD = 0,
+            SUM = 1,
+            MAX = 2,
+        };
+
+        static Ptr<EltwiseLayer> create(EltwiseOp op, const std::vector<int> &coeffs);
+    };
+
+//! @}
+//! @}
+
+}
+}
+#endif
diff --git a/contrib/modules/dnn/include/opencv2/dnn/blob.hpp b/contrib/modules/dnn/include/opencv2/dnn/blob.hpp
index bc582c8..71e929d 100644
--- a/contrib/modules/dnn/include/opencv2/dnn/blob.hpp
+++ b/contrib/modules/dnn/include/opencv2/dnn/blob.hpp
@@ -44,6 +44,7 @@
 #include <opencv2/core.hpp>
 #include <vector>
 #include <ostream>
+#include <iostream>
 
 namespace cv
 {
@@ -53,15 +54,23 @@ namespace dnn
 //! @{
 
     /** @brief Lightweight class for storing and processing a shape of blob (or anything else). */
-    struct BlobShape
+    struct CV_EXPORTS_W BlobShape
     {
-        explicit BlobShape(int ndims = 4, int fill = 1);    //!< Creates n-dim shape and fill its by @p fill
+        BlobShape();                                        //!< Creates [1, 1, 1, 1] shape @todo Make more clearer behavior.
+        explicit BlobShape(int s0);                         //!< Creates 1-dim shape [@p s0]
+        BlobShape(int s0, int s1);                          //!< @overload
+        BlobShape(int s0, int s1, int s2);                  //!< @overload
         BlobShape(int num, int cn, int rows, int cols);     //!< Creates 4-dim shape [@p num, @p cn, @p rows, @p cols]
-        BlobShape(int ndims, const int *sizes);             //!< Creates n-dim shape from the @p sizes array
+
+        //! Creates n-dim shape from the @p sizes array; if @p sizes is NULL then shape will contain unspecified data
+        BlobShape(int ndims, const int *sizes);
         BlobShape(const std::vector<int> &sizes);           //!< Creates n-dim shape from the @p sizes vector
         template<int n>
         BlobShape(const Vec<int, n> &shape);                //!< Creates n-dim shape from @ref cv::Vec
 
+        //! Creates n-dim shape and fill its by @p fill
+        static BlobShape all(int ndims, int fill = 1);
+
         /** @brief Returns number of dimensions. */
         int dims() const;
 
@@ -88,16 +97,41 @@ namespace dnn
          */
         int xsize(int axis) const;
 
+        /** @brief Converts @p axis index to canonical format (where 0 <= @p axis < dims()). */
+        int canonicalAxis(int axis) const;
+
         /** @brief Returns the product of all sizes of axes. */
-        ptrdiff_t total();
+        ptrdiff_t total() const;
+
+        /** @brief Computes the product of sizes of axes among the specified axes range [@p startAxis; @p endAxis).
+         * @details Negative axis indexing can be used. @sa Blob::total(int,int)
+         */
+        ptrdiff_t total(int startAxis, int endAxis = INT_MAX) const;
+
+        /** @brief Constructs new shape from axes in range [@p startAxis; @p endAxis).
+         * @details Negative axis indexing can be used. @sa Blob::total(int,int)
+         */
+        BlobShape slice(int startAxis, int endAxis = INT_MAX) const;
 
         /** @brief Returns pointer to the first element of continuous size array. */
         const int *ptr() const;
+        /** @overload */
+        int *ptr();
+
+        bool equal(const BlobShape &other) const;       //!< Checks equality of two shapes.
+        bool operator== (const BlobShape &r) const;     //!< @sa equal()
+
+        BlobShape operator+ (const BlobShape &r) const; //!< Contacenates two shapes.
+
+        static BlobShape like(const Mat &m);    //!< Returns shape of passed Mat.
+        static BlobShape like(const UMat &m);   //!< Returns shape of passed UMat.
 
-        /** @brief Checks equality of two shapes. */
-        bool equal(const BlobShape &other) const;
+        static BlobShape empty();               //!< Returns empty shape [].
+        bool isEmpty() const;                   //!< Returns true if shape is empty (i.e []).
 
-        bool operator== (const BlobShape &r) const;
+#ifdef CV_CXX_MOVE_SEMANTICS
+        //TBD
+#endif
 
     private:
         cv::AutoBuffer<int,4> sz;
@@ -109,34 +143,57 @@ namespace dnn
      * The class is realized as a wrapper over @ref cv::Mat and @ref cv::UMat.
      * It will support methods for switching and logical synchronization between CPU and GPU.
     */
-    class CV_EXPORTS Blob
+    class CV_EXPORTS_W Blob
     {
     public:
-        explicit Blob();
+        Blob();
 
         /** @brief Constructs blob with specified @p shape and @p type. */
-        explicit Blob(const BlobShape &shape, int type = CV_32F);
+        explicit Blob(const BlobShape &shape, int type = CV_32F, int allocFlags = ALLOC_MAT);
+
+        /** @brief Constructs Blob from existing Mat or UMat. */
+        Blob(InputArray data);
+
+        /** @brief Constructs 4-dimensional blob (so-called batch) from image or array of images.
+         * @param image 2-dimensional multi-channel or 3-dimensional single-channel image (or array of such images)
+         * @param dstCn specifies size of second axis of ouptut blob
+         */
+        static Blob fromImages(InputArray image, int dstCn = -1);
 
-        /** @brief Constucts 4-dimensional blob (so-called batch) from image or array of images.
-         * @param image 2-dimensional multi-channel or 3-dimensional single-channel image (or array of images)
-         * @param dstCn specify size of second axis of ouptut blob
-        */
-        explicit Blob(InputArray image, int dstCn = -1);
+        /** @brief Works like Blob::fromImages() but in-place. */
+        void batchFromImages(InputArray image, int dstCn = -1);
 
         /** @brief Creates blob with specified @p shape and @p type. */
-        void create(const BlobShape &shape, int type = CV_32F);
+        void create(const BlobShape &shape, int type = CV_32F, int allocFlags = ALLOC_MAT);
 
-        /** @brief Creates blob from cv::Mat or cv::UMat without copying the data */
+        /** @brief Creates blob from Mat or UMat without copying the data.
+          * @details If in is Mat then Mat data is populated, otherwise - UMat.
+          */
         void fill(InputArray in);
+
         /** @brief Creates blob from user data.
          *  @details If @p deepCopy is false then CPU data will not be allocated.
          */
         void fill(const BlobShape &shape, int type, void *data, bool deepCopy = true);
 
-        Mat& matRef();                      //!< Returns reference to cv::Mat, containing blob data.
-        const Mat& matRefConst() const;     //!< Returns reference to cv::Mat, containing blob data, for read-only purposes.
-        UMat &umatRef();                    //!< Returns reference to cv::UMat, containing blob data (not implemented yet).
-        const UMat &umatRefConst() const;   //!< Returns reference to cv::UMat, containing blob data, for read-only purposes (not implemented yet).
+        /** @brief Sets @p value to the last used data (if @p allocFlags = -1).
+         * @details If @p allocFlags != -1 then destination data (Mat or UMat) is determined by flags from AllocFlag enum like in create().
+         */
+        void setTo(InputArray value, int allocFlags = -1);
+
+        Mat& matRef(bool writeOnly = true);     //!< Returns reference to cv::Mat, containing blob data.
+        const Mat& matRefConst() const;         //!< Returns reference to cv::Mat, containing blob data, for read-only purposes.
+        UMat &umatRef(bool writeOnly = true);   //!< Returns reference to cv::UMat, containing blob data.
+        const UMat &umatRefConst() const;       //!< Returns reference to cv::UMat, containing blob data, for read-only purposes.
+
+        template<typename XMat>
+        XMat &getRef(bool writeOnly = true);
+        template<typename XMat>
+        const XMat &getRefConst() const;
+
+        void updateMat(bool syncData = true) const;     //!< Actualizes data stored inside Mat of Blob; if @p syncData is false then only shape will be actualized.
+        void updateUMat(bool syncData = true) const;    //!< Actualizes data stored inside Mat of Blob; if @p syncData is false then only shape will be actualized.
+        void sync() const;                              //!< Updates Mat and UMat of Blob.
 
         /** @brief Returns number of blob dimensions. */
         int dims() const;
@@ -163,7 +220,7 @@ namespace dnn
          */
         size_t total(int startAxis = 0, int endAxis = INT_MAX) const;
 
-        /** @brief Converts @p axis index to canonical format (where 0 <= axis < dims()). */
+        /** @brief Converts @p axis index to canonical format (where 0 <= @p axis < dims()). */
         int canonicalAxis(int axis) const;
 
         /** @brief Returns shape of the blob. */
@@ -177,6 +234,13 @@ namespace dnn
          */
         Mat getPlane(int n, int cn);
 
+        /** @brief Returns slice of first dimension.
+         *  @details The behaviour is similar to getPlane(), but returns all
+         * channels * rows * cols values, corresponding to the n-th value
+         * of the first dimension.
+         */
+        Mat getPlanes(int n);
+
         /* Shape getters of 4-dimensional blobs. */
         int cols() const;       //!< Returns size of the fourth axis blob.
         int rows() const;       //!< Returns size of the thrid  axis blob.
@@ -204,8 +268,8 @@ namespace dnn
          */
         uchar *ptr(int n = 0, int cn = 0, int row = 0, int col = 0);
         /** @overload */
-        template<typename TFloat>
-        TFloat *ptr(int n = 0, int cn = 0, int row = 0, int col = 0);
+        template<typename Type>
+        Type *ptr(int n = 0, int cn = 0, int row = 0, int col = 0);
         /** @overload ptr<float>() */
         float *ptrf(int n = 0, int cn = 0, int row = 0, int col = 0);
         //TODO: add const ptr methods
@@ -220,13 +284,52 @@ namespace dnn
          */
         Blob &reshape(const BlobShape &shape);
 
-        /** @brief Returns type of the blob. */
-        int type() const;
+        /** @brief Changes shape of the blob without copying the data.
+         * @returns shallow copy of original blob with new shape.
+         */
+        Blob reshaped(const BlobShape &newShape) const;
+
+        int type() const;       //!< Returns type of the blob.
+        int elemSize() const;   //!< Returns size of single element in bytes.
+        int getState() const;   //!< Returns current state of the blob, @see DataState.
 
     private:
         const int *sizes() const;
 
+#   define CV_DNN_UMAT //DBG
+#ifdef HAVE_OPENCL
+#   define CV_DNN_UMAT
+#endif
+
+#ifdef CV_DNN_UMAT
+#   define CV_DNN_UMAT_ONLY(expr) (expr)
+#else
+#   define CV_DNN_UMAT_ONLY(expr)
+#endif
+
+#ifndef CV_DNN_UMAT
         Mat m;
+#else
+        mutable Mat m;
+        mutable UMat um;
+        mutable uchar state;
+#endif
+
+public:
+        enum DataState
+        {
+            UNINITIALIZED   = 0,
+            HEAD_AT_MAT     = 1 << 0,
+            HEAD_AT_UMAT    = 1 << 1,
+            SYNCED          = HEAD_AT_MAT | HEAD_AT_UMAT
+        };
+
+        enum AllocFlag
+        {
+            ALLOC_MAT  = HEAD_AT_MAT,
+            ALLOC_UMAT = HEAD_AT_UMAT,
+            ALLOC_BOTH = SYNCED
+        };
     };
 
 //! @}
diff --git a/contrib/modules/dnn/include/opencv2/dnn/blob.inl.hpp b/contrib/modules/dnn/include/opencv2/dnn/blob.inl.hpp
index 4a6de48..b7f741e 100644
--- a/contrib/modules/dnn/include/opencv2/dnn/blob.inl.hpp
+++ b/contrib/modules/dnn/include/opencv2/dnn/blob.inl.hpp
@@ -48,20 +48,50 @@ namespace cv
 namespace dnn
 {
 
-inline BlobShape::BlobShape(int ndims, int fill) : sz( (size_t)std::max(ndims, 0) )
+inline BlobShape::BlobShape()
+{
+    sz.allocate(4);
+    for (size_t i = 0; i < sz.size(); i++)
+        sz[i] = 1;
+}
+
+inline BlobShape BlobShape::all(int ndims, int fill)
 {
     CV_Assert(ndims >= 0);
+    BlobShape res;
+    res.sz.allocate(ndims);
     for (int i = 0; i < ndims; i++)
-        sz[i] = fill;
+        res.sz[i] = fill;
+    return res;
 }
 
 inline BlobShape::BlobShape(int ndims, const int *sizes) : sz( (size_t)std::max(ndims, 0) )
 {
     CV_Assert(ndims >= 0);
+    if (!sizes)
+        return;
     for (int i = 0; i < ndims; i++)
         sz[i] = sizes[i];
 }
 
+inline BlobShape::BlobShape(int s0) : sz(1)
+{
+    sz[0] = s0;
+}
+
+inline BlobShape::BlobShape(int s0, int s1) : sz(2)
+{
+    sz[0] = s0;
+    sz[1] = s1;
+}
+
+inline BlobShape::BlobShape(int s0, int s1, int s2) : sz(3)
+{
+    sz[0] = s0;
+    sz[1] = s1;
+    sz[2] = s2;
+}
+
 inline BlobShape::BlobShape(int num, int cn, int rows, int cols) : sz(4)
 {
     sz[0] = num;
@@ -120,7 +150,13 @@ inline int &BlobShape::operator[] (int axis)
     return sz[(axis < 0) ? axis + dims() : axis];
 }
 
-inline ptrdiff_t BlobShape::total()
+inline int BlobShape::canonicalAxis(int axis) const
+{
+    CV_Assert(-dims() <= axis && axis < dims());
+    return (axis < 0) ? axis + dims() : axis;
+}
+
+inline ptrdiff_t BlobShape::total() const
 {
     if (dims() == 0)
         return 0;
@@ -131,11 +167,52 @@ inline ptrdiff_t BlobShape::total()
     return res;
 }
 
+inline ptrdiff_t BlobShape::total(int startAxis, int endAxis) const
+{
+    if (isEmpty())
+        return 0;
+
+    if (endAxis == INT_MAX)
+        endAxis = dims();
+    else if (endAxis < 0)
+        endAxis += dims();
+    startAxis = (startAxis < 0) ? startAxis + dims() : startAxis;
+    CV_Assert(0 <= startAxis && startAxis <= endAxis && endAxis <= dims());
+
+    ptrdiff_t res = 1;
+    for (int i = startAxis; i < endAxis; i++)
+        res *= sz[i];
+    return res;
+}
+
+inline BlobShape BlobShape::slice(int startAxis, int endAxis) const
+{
+    if (isEmpty())
+        return BlobShape::empty();
+
+    if (endAxis == INT_MAX)
+        endAxis = dims();
+    else if (endAxis < 0)
+        endAxis += dims();
+    startAxis = (startAxis < 0) ? startAxis + dims() : startAxis;
+    CV_Assert(0 <= startAxis && startAxis <= endAxis && endAxis <= dims());
+
+    BlobShape res(endAxis - startAxis, (const int*)NULL);
+    for (int i = startAxis; i < endAxis; i++)
+        res[i - startAxis] = sz[i];
+    return res;
+}
+
 inline const int *BlobShape::ptr() const
 {
     return sz;
 }
 
+inline int *BlobShape::ptr()
+{
+    return sz;
+}
+
 inline bool BlobShape::equal(const BlobShape &other) const
 {
     if (this->dims() != other.dims())
@@ -155,19 +232,83 @@ inline bool BlobShape::operator==(const BlobShape &r) const
     return this->equal(r);
 }
 
+inline BlobShape BlobShape::like(const Mat &m)
+{
+    return BlobShape(m.dims, (const int*)m.size);
+}
+
+inline BlobShape BlobShape::like(const UMat &m)
+{
+    return BlobShape(m.dims, (const int*)m.size);
+}
+
+inline BlobShape BlobShape::empty()
+{
+    return BlobShape(0, (const int*)NULL);
+}
+
+inline bool BlobShape::isEmpty() const
+{
+    return dims() == 0;
+}
+
+inline BlobShape BlobShape::operator+(const BlobShape &r) const
+{
+    BlobShape newShape(this->dims() + r.dims(), (int*)NULL);
+    for (int i = 0; i < this->dims(); i++)
+        newShape[i] = (*this)[i];
+    for (int i = 0; i < r.dims(); i++)
+        newShape[this->dims() + i] = r[i];
+    return newShape;
+}
+
 CV_EXPORTS std::ostream &operator<< (std::ostream &stream, const BlobShape &shape);
 
 /////////////////////////////////////////////////////////////////////
 
-inline int Blob::canonicalAxis(int axis) const
+#ifndef CV_DNN_UMAT
+#   define CV_DNN_SWITCH_MU(cpu_expr, gpu_expr) (cpu_expr)
+#else
+#   define CV_DNN_SWITCH_MU(cpu_expr, gpu_expr) ((state == HEAD_AT_UMAT) ? (gpu_expr) : (cpu_expr))
+#endif
+
+
+inline int Blob::dims() const
 {
-    CV_Assert(-dims() <= axis && axis < dims());
-    return (axis < 0) ? axis + dims() : axis;
+    return CV_DNN_SWITCH_MU(m.dims, um.dims);
 }
 
-inline int Blob::dims() const
+inline const int * Blob::sizes() const
+{
+    return CV_DNN_SWITCH_MU((const int*)m.size, (const int*)um.size);
+}
+
+inline int Blob::type() const
+{
+    return CV_DNN_SWITCH_MU(m.type(), um.type());
+}
+
+template<int n>
+inline size_t Blob::offset(const Vec<int, n> &pos) const
+{
+    const MatStep &step = CV_DNN_SWITCH_MU(m.step, um.step);
+    size_t ofs = 0;
+    int i;
+    for (i = 0; i < std::min(n, dims()); i++)
+    {
+        CV_DbgAssert(pos[i] >= 0 && pos[i] < size(i));
+        ofs += step[i] * pos[i];
+    }
+    for (; i < dims(); i++)
+        CV_DbgAssert(pos[i] == 0);
+    CV_DbgAssert(ofs % elemSize() == 0);
+    return ofs / elemSize();
+}
+
+inline int Blob::canonicalAxis(int axis) const
 {
-    return m.dims;
+    CV_Assert(-dims() <= axis && axis < dims());
+    return (axis < 0) ? axis + dims() : axis;
 }
 
 inline int Blob::xsize(int axis) const
@@ -196,27 +337,11 @@ inline size_t Blob::total(int startAxis, int endAxis) const
 
     CV_Assert(0 <= startAxis && startAxis <= endAxis && endAxis <= dims());
 
-    size_t size = 1; //fix: assume that slice isn't empty
+    size_t cnt = 1; //fix: assume that slice isn't empty
     for (int i = startAxis; i < endAxis; i++)
-        size *= (size_t)sizes()[i];
+        cnt *= (size_t)sizes()[i];
 
-    return size;
-}
-
-
-template<int n>
-inline size_t Blob::offset(const Vec<int, n> &pos) const
-{
-    size_t ofs = 0;
-    int i;
-    for (i = 0; i < std::min(n, dims()); i++)
-    {
-        CV_DbgAssert(pos[i] >= 0 && pos[i] < size(i));
-        ofs = ofs * (size_t)size(i) + pos[i];
-    }
-    for (; i < dims(); i++)
-        ofs *= (size_t)size(i);
-    return ofs;
+    return cnt;
 }
 
 inline size_t Blob::offset(int n, int cn, int row, int col) const
@@ -226,20 +351,20 @@ inline size_t Blob::offset(int n, int cn, int row, int col) const
 
 inline float *Blob::ptrf(int n, int cn, int row, int col)
 {
-    CV_Assert(type() == CV_32F);
-    return (float*)m.data + offset(n, cn, row, col);
+    return matRef(false).ptr<float>() + offset(n, cn, row, col);
 }
 
 inline uchar *Blob::ptr(int n, int cn, int row, int col)
 {
-    return m.data + m.elemSize() * offset(n, cn, row, col);
+    Mat &mat = matRef(false);
+    return mat.ptr() + mat.elemSize() * offset(n, cn, row, col);
 }
 
-template<typename TFloat>
-inline TFloat* Blob::ptr(int n, int cn, int row, int col)
+template<typename Dtype>
+inline Dtype* Blob::ptr(int n, int cn, int row, int col)
 {
-    CV_Assert(type() == cv::DataDepth<TFloat>::value);
-    return (TFloat*) ptr(n, cn, row, col);
+    CV_Assert(type() == cv::DataDepth<Dtype>::value);
+    return (Dtype*) ptr(n, cn, row, col);
 }
 
 inline BlobShape Blob::shape() const
@@ -260,26 +385,69 @@ inline bool Blob::equalShape(const Blob &other) const
     return true;
 }
 
-inline Mat& Blob::matRef()
+inline Mat& Blob::matRef(bool writeOnly)
 {
+#ifdef CV_DNN_UMAT
+    updateMat(!writeOnly);
+    state = HEAD_AT_MAT;
+#else
+    (void)writeOnly;
+#endif
     return m;
 }
 
 inline const Mat& Blob::matRefConst() const
 {
+    CV_DNN_UMAT_ONLY( updateMat() );
     return m;
 }
 
-inline UMat &Blob::umatRef()
+inline UMat &Blob::umatRef(bool writeOnly)
 {
-    CV_Error(Error::StsNotImplemented, "");
+#ifndef CV_DNN_UMAT
+    CV_Error(Error::GpuNotSupported, "");
+    (void)writeOnly;
     return *(new UMat());
+#else
+    updateUMat(!writeOnly);
+    state = HEAD_AT_UMAT;
+    return um;
+#endif
 }
 
 inline const UMat &Blob::umatRefConst() const
 {
-    CV_Error(Error::StsNotImplemented, "");
+#ifndef CV_DNN_UMAT
+    CV_Error(Error::GpuNotSupported, "");
     return *(new UMat());
+#else
+    updateUMat();
+    return um;
+#endif
+}
+
+template<>
+inline Mat &Blob::getRef<Mat>(bool writeOnly)
+{
+    return matRef(writeOnly);
+}
+
+template<>
+inline UMat &Blob::getRef<UMat>(bool writeOnly)
+{
+    return umatRef(writeOnly);
+}
+
+template<>
+inline const Mat &Blob::getRefConst<Mat>() const
+{
+    return matRefConst();
+}
+
+template<>
+inline const UMat &Blob::getRefConst<UMat>() const
+{
+    return umatRefConst();
 }
 
 inline Mat Blob::getPlane(int n, int cn)
@@ -288,6 +456,12 @@ inline Mat Blob::getPlane(int n, int cn)
     return Mat(dims() - 2, sizes() + 2, type(), ptr(n, cn));
 }
 
+inline Mat Blob::getPlanes(int n)
+{
+    CV_Assert(dims() > 3);
+    return Mat(dims() - 1, sizes() + 1, type(), ptr(n));
+}
+
 inline int Blob::cols() const
 {
     return xsize(3);
@@ -313,27 +487,44 @@ inline Size Blob::size2() const
     return Size(cols(), rows());
 }
 
-inline int Blob::type() const
+inline Blob &Blob::shareFrom(const Blob &blob)
 {
-    return m.depth();
+    this->m = blob.m;
+#ifdef CV_DNN_UMAT
+    this->um = blob.um;
+    this->state = blob.state;
+#endif
+    return *this;
 }
 
-inline const int * Blob::sizes() const
+inline Blob &Blob::reshape(const BlobShape &newShape)
 {
-    return &m.size[0];
+    if (!m.empty()) m = m.reshape(1, newShape.dims(), newShape.ptr());
+#ifdef CV_DNN_UMAT
+    if (!um.empty()) um = um.reshape(1, newShape.dims(), newShape.ptr());
+#endif
+    return *this;
 }
 
+inline Blob Blob::reshaped(const BlobShape &newShape) const
+{
+    Blob res(*this); //also, res.shareFrom(*this) could be used
+    res.reshape(newShape);
+    return res;
+}
 
-inline Blob &Blob::shareFrom(const Blob &blob)
+inline int Blob::elemSize() const
 {
-    this->m = blob.m;
-    return *this;
+    return CV_ELEM_SIZE(type());
 }
 
-inline Blob &Blob::reshape(const BlobShape &shape)
+inline int Blob::getState() const
 {
-    m = m.reshape(1, shape.dims(), shape.ptr());
-    return *this;
+#ifdef CV_DNN_UMAT
+    return this->state;
+#else
+    return m.empty() ? UNINITIALIZED : HEAD_AT_MAT;
+#endif
 }
 
 }
diff --git a/contrib/modules/dnn/include/opencv2/dnn/dict.hpp b/contrib/modules/dnn/include/opencv2/dnn/dict.hpp
index 61db133..f7cd0f2 100644
--- a/contrib/modules/dnn/include/opencv2/dnn/dict.hpp
+++ b/contrib/modules/dnn/include/opencv2/dnn/dict.hpp
@@ -59,10 +59,12 @@ namespace dnn
 struct DictValue
 {
     DictValue(const DictValue &r);
-    DictValue(int p = 0)        : type(Param::INT), pi(new AutoBuffer<int64,1>) { (*pi)[0] = p; }       //!< Constructs integer scalar
+    DictValue(int64 i = 0)      : type(Param::INT), pi(new AutoBuffer<int64,1>) { (*pi)[0] = i; }       //!< Constructs integer scalar
+    DictValue(int i)            : type(Param::INT), pi(new AutoBuffer<int64,1>) { (*pi)[0] = i; }       //!< Constructs integer scalar
     DictValue(unsigned p)       : type(Param::INT), pi(new AutoBuffer<int64,1>) { (*pi)[0] = p; }       //!< Constructs integer scalar
     DictValue(double p)         : type(Param::REAL), pd(new AutoBuffer<double,1>) { (*pd)[0] = p; }     //!< Constructs floating point scalar
-    DictValue(const String &p)  : type(Param::STRING), ps(new AutoBuffer<String,1>) { (*ps)[0] = p; }   //!< Constructs string scalar
+    DictValue(const String &s)  : type(Param::STRING), ps(new AutoBuffer<String,1>) { (*ps)[0] = s; }   //!< Constructs string scalar
+    DictValue(const char *s)    : type(Param::STRING), ps(new AutoBuffer<String,1>) { (*ps)[0] = s; }   //!< @overload
 
     template<typename TypeIter>
     static DictValue arrayInt(TypeIter begin, int size);    //!< Constructs integer array
@@ -95,10 +97,10 @@ private:
         AutoBuffer<int64, 1> *pi;
         AutoBuffer<double, 1> *pd;
         AutoBuffer<String, 1> *ps;
-        void *p;
+        void *pv;
     };
 
-    DictValue(int _type, void *_p) : type(_type), p(_p) {}
+    DictValue(int _type, void *_p) : type(_type), pv(_p) {}
     void release();
 };
 
@@ -111,7 +113,7 @@ class CV_EXPORTS Dict
 public:
 
     //! Checks a presence of the @p key in the dictionary.
-    bool has(const String &key);
+    bool has(const String &key) const;
 
     //! If the @p key in the dictionary then returns pointer to its value, else returns NULL.
     DictValue *ptr(const String &key);
diff --git a/contrib/modules/dnn/include/opencv2/dnn/dnn.hpp b/contrib/modules/dnn/include/opencv2/dnn/dnn.hpp
index 1d1244d..ca4a6ab 100644
--- a/contrib/modules/dnn/include/opencv2/dnn/dnn.hpp
+++ b/contrib/modules/dnn/include/opencv2/dnn/dnn.hpp
@@ -59,15 +59,17 @@ namespace dnn //! This namespace is used for dnn module functionlaity.
      * This function automatically called on most of OpenCV builds,
      * but you need to call it manually on some specific configurations (iOS for example).
      */
-    CV_EXPORTS void initModule();
+    CV_EXPORTS_W void initModule();
 
     /** @brief This class provides all data needed to initialize layer.
      *
      * It includes dictionary with scalar params (which can be readed by using Dict interface),
      * blob params #blobs and optional meta information: #name and #type of layer instance.
     */
-    struct CV_EXPORTS LayerParams : public Dict
+    class CV_EXPORTS LayerParams : public Dict
     {
+    public:
+        //TODO: Add ability to name blob params
         std::vector<Blob> blobs; //!< List of learned parameters stored as blobs.
 
         String name; //!< Name of the layer instance (optional, can be used internal purposes).
@@ -77,12 +79,14 @@ namespace dnn //! This namespace is used for dnn module functionlaity.
     /** @brief This interface class allows to build new Layers - are building blocks of networks.
      *
      * Each class, derived from Layer, must implement allocate() methods to declare own outputs and forward() to compute outputs.
-     * Also before using the new layer into networks you must register your layer by using one of @ref LayerFactoryModule "LayerFactory" macros.
+     * Also before using the new layer into networks you must register your layer by using one of @ref dnnLayerFactory "LayerFactory" macros.
      */
-    struct CV_EXPORTS Layer
+    class CV_EXPORTS_W Layer
     {
+    public:
+
         //! List of learned parameters must be stored here to allow read them by using Net::getParam().
-        std::vector<Blob> blobs;
+        CV_PROP_RW std::vector<Blob> blobs;
 
         /** @brief Allocates internal buffers and output blobs with respect to the shape of inputs.
          *  @param[in]  input  vector of already allocated input blobs
@@ -100,6 +104,18 @@ namespace dnn //! This namespace is used for dnn module functionlaity.
          */
         virtual void forward(std::vector<Blob*> &input, std::vector<Blob> &output) = 0;
 
+        /** @brief @overload */
+        CV_WRAP void allocate(const std::vector<Blob> &inputs, CV_OUT std::vector<Blob> &outputs);
+
+        /** @brief @overload */
+        CV_WRAP std::vector<Blob> allocate(const std::vector<Blob> &inputs);
+
+        /** @brief @overload */
+        CV_WRAP void forward(const std::vector<Blob> &inputs, CV_IN_OUT std::vector<Blob> &outputs);
+
+        /** @brief Allocates layer and computes output. */
+        CV_WRAP void run(const std::vector<Blob> &inputs, CV_OUT std::vector<Blob> &outputs);
+
         /** @brief Returns index of input blob into the input array.
          *  @param inputName label of input blob
          *
@@ -112,11 +128,12 @@ namespace dnn //! This namespace is used for dnn module functionlaity.
          */
         virtual int outputNameToIndex(String outputName);
 
-        String name; //!< Name of the layer instance, can be used for logging or other internal purposes.
-        String type; //!< Type name which was used for creating layer by layer factory.
+        CV_PROP String name; //!< Name of the layer instance, can be used for logging or other internal purposes.
+        CV_PROP String type; //!< Type name which was used for creating layer by layer factory.
 
         Layer();
-        explicit Layer(const LayerParams &params); //!< Initialize only #name, #type and #blobs fields.
+        explicit Layer(const LayerParams &params);      //!< Initializes only #name, #type and #blobs fields.
+        void setParamsFrom(const LayerParams &params);  //!< Initializes only #name, #type and #blobs fields.
         virtual ~Layer();
     };
 
@@ -130,12 +147,15 @@ namespace dnn //! This namespace is used for dnn module functionlaity.
      *
      * This class supports reference counting of its instances, i. e. copies point to the same instance.
      */
-    class CV_EXPORTS Net
+    class CV_EXPORTS_W_SIMPLE Net
     {
     public:
 
-        Net();  //!< Default constructor.
-        ~Net(); //!< Destructor frees the net only if there aren't references to the net anymore.
+        CV_WRAP Net();  //!< Default constructor.
+        CV_WRAP ~Net(); //!< Destructor frees the net only if there aren't references to the net anymore.
+
+        /** Returns true if there are no layers in the network. */
+        CV_WRAP bool empty() const;
 
         /** @brief Adds new layer to the net.
          *  @param name   unique name of the adding layer.
@@ -152,13 +172,18 @@ namespace dnn //! This namespace is used for dnn module functionlaity.
         /** @brief Converts string name of the layer to the integer identifier.
          *  @returns id of the layer, or -1 if the layer wasn't found.
          */
-        int getLayerId(const String &layer);
+        CV_WRAP int getLayerId(const String &layer);
+
+        CV_WRAP std::vector<String> getLayerNames() const;
 
         /** @brief Container for strings and integers. */
         typedef DictValue LayerId;
 
+        /** @brief Returns pointer to layer with specified name which the network use. */
+        CV_WRAP Ptr<Layer> getLayer(LayerId layerId);
+
         /** @brief Delete layer for the network (not implemented yet) */
-        void deleteLayer(LayerId layer);
+        CV_WRAP void deleteLayer(LayerId layer);
 
         /** @brief Connects output of the first layer to input of the second layer.
          *  @param outPin descriptor of the first layer output.
@@ -173,7 +198,8 @@ namespace dnn //! This namespace is used for dnn module functionlaity.
          *
          *  @see setNetInputs(), Layer::inputNameToIndex(), Layer::outputNameToIndex()
          */
-        void connect(String outPin, String inpPin);
+        CV_WRAP void connect(String outPin, String inpPin);
+
         /** @brief Connects #@p outNum output of the first layer to #@p inNum input of the second layer.
          *  @param outLayerId identifier of the first layer
          *  @param inpLayerId identifier of the second layer
@@ -181,19 +207,23 @@ namespace dnn //! This namespace is used for dnn module functionlaity.
          *  @param inpNum number of the second layer input
          */
         void connect(int outLayerId, int outNum, int inpLayerId, int inpNum);
-        /** @brief Sets ouputs names of the network input pseudo layer.
+
+        /** @brief Sets outputs names of the network input pseudo layer.
          *
          * Each net always has special own the network input pseudo layer with id=0.
          * This layer stores the user blobs only and don't make any computations.
          * In fact, this layer provides the only way to pass user data into the network.
          * As any other layer, this layer can label its outputs and this function provides an easy way to do this.
          */
-        void setNetInputs(const std::vector<String> &inputBlobNames);
+        CV_WRAP void setNetInputs(const std::vector<String> &inputBlobNames);
+
+        /** @brief Initializes and allocates all layers. */
+        CV_WRAP void allocate();
 
-        /** @brief Runs forward pass for the whole network */
-        void forward();
-        /** @brief Runs forward pass to compute output of layer @p toLayer */
-        void forward(LayerId toLayer);
+        /** @brief Runs forward pass to compute output of layer @p toLayer.
+          * @details By default runs forward pass for the whole network.
+          */
+        CV_WRAP void forward(LayerId toLayer = String());
         /** @brief Runs forward pass to compute output of layer @p toLayer, but computations start from @p startLayer */
         void forward(LayerId startLayer, LayerId toLayer);
         /** @overload */
@@ -215,12 +245,13 @@ namespace dnn //! This namespace is used for dnn module functionlaity.
          *  @note If updating blob is not empty then @p blob must have the same shape,
          *  because network reshaping is not implemented yet.
          */
-        void setBlob(String outputName, const Blob &blob);
+        CV_WRAP void setBlob(String outputName, const Blob &blob);
+
         /** @brief Returns the layer output blob.
          *  @param outputName the descriptor of the returning layer output blob.
          *  @see connect(String, String)
          */
-        Blob getBlob(String outputName);
+        CV_WRAP Blob getBlob(String outputName);
 
         /** @brief Sets the new value for the learned param of the layer.
          *  @param layer name or id of the layer.
@@ -230,13 +261,14 @@ namespace dnn //! This namespace is used for dnn module functionlaity.
          *  @note If shape of the new blob differs from the previous shape,
          *  then the following forward pass may fail.
         */
-        void setParam(LayerId layer, int numParam, const Blob &blob);
+        CV_WRAP void setParam(LayerId layer, int numParam, const Blob &blob);
+
         /** @brief Returns parameter blob of the layer.
          *  @param layer name or id of the layer.
          *  @param numParam index of the layer parameter in the Layer::blobs array.
          *  @see Layer::blobs
          */
-        Blob getParam(LayerId layer, int numParam = 0);
+        CV_WRAP Blob getParam(LayerId layer, int numParam = 0);
 
     private:
 
@@ -245,12 +277,12 @@ namespace dnn //! This namespace is used for dnn module functionlaity.
     };
 
     /** @brief Small interface class for loading trained serialized models of different dnn-frameworks. */
-    class Importer
+    class CV_EXPORTS_W Importer
     {
     public:
 
-        /** @brief Adds loaded layers into the @p net and sets connetions between them. */
-        virtual void populateNet(Net net) = 0;
+        /** @brief Adds loaded layers into the @p net and sets connections between them. */
+        CV_WRAP virtual void populateNet(Net net) = 0;
 
         virtual ~Importer();
     };
@@ -260,17 +292,28 @@ namespace dnn //! This namespace is used for dnn module functionlaity.
      *  @param caffeModel path to the .caffemodel file with learned network.
      *  @returns Pointer to the created importer, NULL in failure cases.
      */
-    CV_EXPORTS Ptr<Importer> createCaffeImporter(const String &prototxt, const String &caffeModel = String());
+    CV_EXPORTS_W Ptr<Importer> createCaffeImporter(const String &prototxt, const String &caffeModel = String());
+
+    /** @brief Reads a network model stored in Caffe model files.
+      * @details This is shortcut consisting from createCaffeImporter and Net::populateNet calls.
+      */
+    CV_EXPORTS_W Net readNetFromCaffe(const String &prototxt, const String &caffeModel = String());
+
+    /** @brief Creates the importer of <a href="http://www.tensorflow.org">TensorFlow</a> framework network.
+     *  @param model   path to the .pb file with binary protobuf description of the network architecture.
+     *  @returns Pointer to the created importer, NULL in failure cases.
+     */
+    CV_EXPORTS Ptr<Importer> createTensorflowImporter(const String &model);
 
     /** @brief Creates the importer of <a href="http://torch.ch">Torch7</a> framework network.
      *  @param filename path to the file, dumped from Torch by using torch.save() function.
      *  @param isBinary specifies whether the network was serialized in ascii mode or binary.
      *  @returns Pointer to the created importer, NULL in failure cases.
      *
-     *  @warning Torch7 importer is experimental now, you need explicitly set CMake opencv_dnn_BUILD_TORCH_IMPORTER flag to compile its.
+     *  @warning Torch7 importer is experimental now, you need explicitly set CMake `opencv_dnn_BUILD_TORCH_IMPORTER` flag to compile its.
      *
-     *  @note Ascii mode of Torch serializer is more preferable, because binary mode extensively use long type of C language,
-     *  which has different bit-length on different systems.
+     *  @note Ascii mode of Torch serializer is more preferable, because binary mode extensively use `long` type of C language,
+     *  which has various bit-length on different systems.
      *
      * The loading file must contain serialized <a href="https://github.com/torch/nn/blob/master/doc/module.md">nn.Module</a> object
      * with importing network. Try to eliminate a custom objects from serialazing data to avoid importing errors.
@@ -287,12 +330,12 @@ namespace dnn //! This namespace is used for dnn module functionlaity.
      *
      * Also some equivalents of these classes from cunn, cudnn, and fbcunn may be successfully imported.
      */
-    CV_EXPORTS Ptr<Importer> createTorchImporter(const String &filename, bool isBinary = true);
+    CV_EXPORTS_W Ptr<Importer> createTorchImporter(const String &filename, bool isBinary = true);
 
     /** @brief Loads blob which was serialized as torch.Tensor object of Torch7 framework.
      *  @warning This function has the same limitations as createTorchImporter().
      */
-    CV_EXPORTS Blob readTorchBlob(const String &filename, bool isBinary = true);
+    CV_EXPORTS_W Blob readTorchBlob(const String &filename, bool isBinary = true);
 
 //! @}
 }
diff --git a/contrib/modules/dnn/include/opencv2/dnn/dnn.inl.hpp b/contrib/modules/dnn/include/opencv2/dnn/dnn.inl.hpp
index 300ae58..a272044 100644
--- a/contrib/modules/dnn/include/opencv2/dnn/dnn.inl.hpp
+++ b/contrib/modules/dnn/include/opencv2/dnn/dnn.inl.hpp
@@ -86,7 +86,7 @@ inline DictValue DictValue::get<DictValue>(int idx) const
 template<>
 inline int64 DictValue::get<int64>(int idx) const
 {
-    CV_Assert(idx == -1 && size() == 1 || idx >= 0 && idx < size());
+    CV_Assert((idx == -1 && size() == 1) || (idx >= 0 && idx < size()));
     idx = (idx == -1) ? 0 : idx;
 
     if (type == Param::INT)
@@ -131,7 +131,7 @@ inline bool DictValue::get<bool>(int idx) const
 template<>
 inline double DictValue::get<double>(int idx) const
 {
-    CV_Assert(idx == -1 && size() == 1 || idx >= 0 && idx < size());
+    CV_Assert((idx == -1 && size() == 1) || (idx >= 0 && idx < size()));
     idx = (idx == -1) ? 0 : idx;
 
     if (type == Param::REAL)
@@ -159,7 +159,7 @@ template<>
 inline String DictValue::get<String>(int idx) const
 {
     CV_Assert(isString());
-    CV_Assert(idx == -1 && ps->size() == 1 || idx >= 0 && idx < (int)ps->size());
+    CV_Assert((idx == -1 && ps->size() == 1) || (idx >= 0 && idx < (int)ps->size()));
     return (*ps)[(idx == -1) ? 0 : idx];
 }
 
@@ -287,7 +287,7 @@ inline std::ostream &operator<<(std::ostream &stream, const DictValue &dictv)
 
 /////////////////////////////////////////////////////////////////
 
-inline bool Dict::has(const String &key)
+inline bool Dict::has(const String &key) const
 {
     return dict.count(key) != 0;
 }
diff --git a/contrib/modules/dnn/include/opencv2/dnn/layer.hpp b/contrib/modules/dnn/include/opencv2/dnn/layer.hpp
index b28b6ac..e051041 100644
--- a/contrib/modules/dnn/include/opencv2/dnn/layer.hpp
+++ b/contrib/modules/dnn/include/opencv2/dnn/layer.hpp
@@ -50,7 +50,7 @@ namespace dnn
 //! @addtogroup dnn
 //! @{
 //!
-//! @defgroup LayerFactoryModule Utilities for new layers registration
+//! @defgroup dnnLayerFactory Utilities for New Layers Registration
 //! @{
 
 /** @brief %Layer factory allows to create instances of registered layers. */
@@ -86,7 +86,7 @@ private:
 *   @details This macros must be placed inside the function code.
 */
 #define REG_RUNTIME_LAYER_FUNC(type, constuctorFunc) \
-    LayerFactory::registerLayer(#type, constuctorFunc);
+    cv::dnn::LayerFactory::registerLayer(#type, constuctorFunc);
 
 /** @brief Registers layer class in runtime.
  *  @param type string, containing type name of the layer.
@@ -94,7 +94,7 @@ private:
  *  @details This macros must be placed inside the function code.
  */
 #define REG_RUNTIME_LAYER_CLASS(type, class) \
-    LayerFactory::registerLayer(#type, _layerDynamicRegisterer<class>);
+    cv::dnn::LayerFactory::registerLayer(#type, _layerDynamicRegisterer<class>);
 
 /** @brief Registers layer constructor on module load time.
 *   @param type string, containing type name of the layer.
@@ -102,7 +102,7 @@ private:
 *   @details This macros must be placed outside the function code.
 */
 #define REG_STATIC_LAYER_FUNC(type, constuctorFunc) \
-static _LayerStaticRegisterer __LayerStaticRegisterer_##type(#type, constuctorFunc);
+static cv::dnn::_LayerStaticRegisterer __LayerStaticRegisterer_##type(#type, constuctorFunc);
 
 /** @brief Registers layer class on module load time.
  *  @param type string, containing type name of the layer.
@@ -126,14 +126,15 @@ Ptr<Layer> _layerDynamicRegisterer(LayerParams &params)
 }
 
 //allows automatically register created layer on module load time
-struct _LayerStaticRegisterer
+class _LayerStaticRegisterer
 {
     String type;
+public:
 
-    _LayerStaticRegisterer(const String &type, LayerFactory::Constuctor constuctor)
+    _LayerStaticRegisterer(const String &layerType, LayerFactory::Constuctor layerConstuctor)
     {
-        this->type = type;
-        LayerFactory::registerLayer(type, constuctor);
+        this->type = layerType;
+        LayerFactory::registerLayer(layerType, layerConstuctor);
     }
 
     ~_LayerStaticRegisterer()
diff --git a/contrib/modules/dnn/include/opencv2/dnn/shape_utils.hpp b/contrib/modules/dnn/include/opencv2/dnn/shape_utils.hpp
new file mode 100644
index 0000000..f52e5b9
--- /dev/null
+++ b/contrib/modules/dnn/include/opencv2/dnn/shape_utils.hpp
@@ -0,0 +1,137 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+//  By downloading, copying, installing or using the software you agree to this license.
+//  If you do not agree to this license, do not download, install,
+//  copy or use the software.
+//
+//
+//                           License Agreement
+//                For Open Source Computer Vision Library
+//
+// Copyright (C) 2013, OpenCV Foundation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+//   * Redistribution's of source code must retain the above copyright notice,
+//     this list of conditions and the following disclaimer.
+//
+//   * Redistribution's in binary form must reproduce the above copyright notice,
+//     this list of conditions and the following disclaimer in the documentation
+//     and/or other materials provided with the distribution.
+//
+//   * The name of the copyright holders may not be used to endorse or promote products
+//     derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#ifndef __OPENCV_DNN_DNN_SHAPE_UTILS_HPP__
+#define __OPENCV_DNN_DNN_SHAPE_UTILS_HPP__
+
+#include <opencv2/core.hpp>
+#include <ostream>
+
+namespace cv {
+namespace dnn {
+
+//Useful shortcut
+typedef BlobShape Shape;
+
+inline std::ostream &operator<< (std::ostream &s, cv::Range &r)
+{
+    return s << "[" << r.start << ", " << r.end << ")";
+}
+
+//Reshaping
+//TODO: add -1 specifier for automatic size inferring
+
+template<typename Mat>
+void reshape(Mat &m, const BlobShape &shape)
+{
+    m = m.reshape(1, shape.dims(), shape.ptr());
+}
+
+template<typename Mat>
+Mat reshaped(const Mat &m, const BlobShape &shape)
+{
+    return m.reshape(1, shape.dims(), shape.ptr());
+}
+
+
+//Slicing
+
+struct _Range : public cv::Range
+{
+    _Range(const Range &r) : cv::Range(r) {}
+    _Range(int start, int size = 1) : cv::Range(start, start + size) {}
+};
+
+template<typename Mat>
+Mat slice(const Mat &m, const _Range &r0)
+{
+    //CV_Assert(m.dims >= 1);
+    cv::AutoBuffer<cv::Range, 4> ranges(m.dims);
+    for (int i = 1; i < m.dims; i++)
+        ranges[i] = Range::all();
+    ranges[0] = r0;
+    return m(&ranges[0]);
+}
+
+template<typename Mat>
+Mat slice(const Mat &m, const _Range &r0, const _Range &r1)
+{
+    CV_Assert(m.dims >= 2);
+    cv::AutoBuffer<cv::Range, 4> ranges(m.dims);
+    for (int i = 2; i < m.dims; i++)
+        ranges[i] = Range::all();
+    ranges[0] = r0;
+    ranges[1] = r1;
+    return m(&ranges[0]);
+}
+
+template<typename Mat>
+Mat slice(const Mat &m, const _Range &r0, const _Range &r1, const _Range &r2)
+{
+    CV_Assert(m.dims <= 3);
+    cv::AutoBuffer<cv::Range, 4> ranges(m.dims);
+    for (int i = 3; i < m.dims; i++)
+        ranges[i] = Range::all();
+    ranges[0] = r0;
+    ranges[1] = r1;
+    ranges[2] = r2;
+    return m(&ranges[0]);
+}
+
+template<typename Mat>
+Mat slice(const Mat &m, const _Range &r0, const _Range &r1, const _Range &r2, const _Range &r3)
+{
+    CV_Assert(m.dims <= 4);
+    cv::AutoBuffer<cv::Range, 4> ranges(m.dims);
+    for (int i = 4; i < m.dims; i++)
+        ranges[i] = Range::all();
+    ranges[0] = r0;
+    ranges[1] = r1;
+    ranges[2] = r2;
+    ranges[3] = r3;
+    return m(&ranges[0]);
+}
+
+BlobShape computeShapeByReshapeMask(const BlobShape &srcShape, const BlobShape &maskShape, Range srcRange = Range::all());
+
+}
+}
+#endif
diff --git a/contrib/modules/dnn/misc/caffe/caffe.pb.cc b/contrib/modules/dnn/misc/caffe/caffe.pb.cc
new file mode 100644
index 0000000..7bd91f1
--- /dev/null
+++ b/contrib/modules/dnn/misc/caffe/caffe.pb.cc
@@ -0,0 +1,45683 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: caffe.proto
+
+#define INTERNAL_SUPPRESS_PROTOBUF_FIELD_DEPRECATION
+#include "caffe.pb.h"
+
+#include <algorithm>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/port.h>
+#include <google/protobuf/stubs/once.h>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/wire_format_lite_inl.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/generated_message_reflection.h>
+#include <google/protobuf/reflection_ops.h>
+#include <google/protobuf/wire_format.h>
+// @@protoc_insertion_point(includes)
+
+namespace caffe {
+
+namespace {
+
+const ::google::protobuf::Descriptor* BlobShape_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+  BlobShape_reflection_ = NULL;
+const ::google::protobuf::Descriptor* BlobProto_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+  BlobProto_reflection_ = NULL;
+const ::google::protobuf::Descriptor* BlobProtoVector_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+  BlobProtoVector_reflection_ = NULL;
+const ::google::protobuf::Descriptor* CropParameter_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+  CropParameter_reflection_ = NULL;
+const ::google::protobuf::Descriptor* PermuteParameter_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+  PermuteParameter_reflection_ = NULL;
+const ::google::protobuf::Descriptor* NormalizeBBoxParameter_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+  NormalizeBBoxParameter_reflection_ = NULL;
+const ::google::protobuf::Descriptor* PriorBoxParameter_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+  PriorBoxParameter_reflection_ = NULL;
+const ::google::protobuf::EnumDescriptor* PriorBoxParameter_CodeType_descriptor_ = NULL;
+const ::google::protobuf::Descriptor* DetectionOutputParameter_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+  DetectionOutputParameter_reflection_ = NULL;
+const ::google::protobuf::Descriptor* Datum_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+  Datum_reflection_ = NULL;
+const ::google::protobuf::Descriptor* FillerParameter_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+  FillerParameter_reflection_ = NULL;
+const ::google::protobuf::EnumDescriptor* FillerParameter_VarianceNorm_descriptor_ = NULL;
+const ::google::protobuf::Descriptor* NetParameter_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+  NetParameter_reflection_ = NULL;
+const ::google::protobuf::Descriptor* SolverParameter_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+  SolverParameter_reflection_ = NULL;
+const ::google::protobuf::EnumDescriptor* SolverParameter_SolverMode_descriptor_ = NULL;
+const ::google::protobuf::EnumDescriptor* SolverParameter_SolverType_descriptor_ = NULL;
+const ::google::protobuf::Descriptor* SolverState_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+  SolverState_reflection_ = NULL;
+const ::google::protobuf::Descriptor* NetState_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+  NetState_reflection_ = NULL;
+const ::google::protobuf::Descriptor* NetStateRule_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+  NetStateRule_reflection_ = NULL;
+const ::google::protobuf::Descriptor* ParamSpec_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+  ParamSpec_reflection_ = NULL;
+const ::google::protobuf::EnumDescriptor* ParamSpec_DimCheckMode_descriptor_ = NULL;
+const ::google::protobuf::Descriptor* LayerParameter_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+  LayerParameter_reflection_ = NULL;
+const ::google::protobuf::Descriptor* TransformationParameter_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+  TransformationParameter_reflection_ = NULL;
+const ::google::protobuf::Descriptor* LossParameter_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+  LossParameter_reflection_ = NULL;
+const ::google::protobuf::Descriptor* AccuracyParameter_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+  AccuracyParameter_reflection_ = NULL;
+const ::google::protobuf::Descriptor* ArgMaxParameter_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+  ArgMaxParameter_reflection_ = NULL;
+const ::google::protobuf::Descriptor* ConcatParameter_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+  ConcatParameter_reflection_ = NULL;
+const ::google::protobuf::Descriptor* ContrastiveLossParameter_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+  ContrastiveLossParameter_reflection_ = NULL;
+const ::google::protobuf::Descriptor* ConvolutionParameter_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+  ConvolutionParameter_reflection_ = NULL;
+const ::google::protobuf::EnumDescriptor* ConvolutionParameter_Engine_descriptor_ = NULL;
+const ::google::protobuf::Descriptor* DataParameter_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+  DataParameter_reflection_ = NULL;
+const ::google::protobuf::EnumDescriptor* DataParameter_DB_descriptor_ = NULL;
+const ::google::protobuf::Descriptor* DropoutParameter_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+  DropoutParameter_reflection_ = NULL;
+const ::google::protobuf::Descriptor* DummyDataParameter_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+  DummyDataParameter_reflection_ = NULL;
+const ::google::protobuf::Descriptor* EltwiseParameter_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+  EltwiseParameter_reflection_ = NULL;
+const ::google::protobuf::EnumDescriptor* EltwiseParameter_EltwiseOp_descriptor_ = NULL;
+const ::google::protobuf::Descriptor* ExpParameter_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+  ExpParameter_reflection_ = NULL;
+const ::google::protobuf::Descriptor* FlattenParameter_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+  FlattenParameter_reflection_ = NULL;
+const ::google::protobuf::Descriptor* HDF5DataParameter_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+  HDF5DataParameter_reflection_ = NULL;
+const ::google::protobuf::Descriptor* HDF5OutputParameter_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+  HDF5OutputParameter_reflection_ = NULL;
+const ::google::protobuf::Descriptor* HingeLossParameter_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+  HingeLossParameter_reflection_ = NULL;
+const ::google::protobuf::EnumDescriptor* HingeLossParameter_Norm_descriptor_ = NULL;
+const ::google::protobuf::Descriptor* ImageDataParameter_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+  ImageDataParameter_reflection_ = NULL;
+const ::google::protobuf::Descriptor* InfogainLossParameter_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+  InfogainLossParameter_reflection_ = NULL;
+const ::google::protobuf::Descriptor* InnerProductParameter_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+  InnerProductParameter_reflection_ = NULL;
+const ::google::protobuf::Descriptor* LogParameter_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+  LogParameter_reflection_ = NULL;
+const ::google::protobuf::Descriptor* LRNParameter_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+  LRNParameter_reflection_ = NULL;
+const ::google::protobuf::EnumDescriptor* LRNParameter_NormRegion_descriptor_ = NULL;
+const ::google::protobuf::Descriptor* MemoryDataParameter_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+  MemoryDataParameter_reflection_ = NULL;
+const ::google::protobuf::Descriptor* MVNParameter_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+  MVNParameter_reflection_ = NULL;
+const ::google::protobuf::Descriptor* PoolingParameter_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+  PoolingParameter_reflection_ = NULL;
+const ::google::protobuf::EnumDescriptor* PoolingParameter_PoolMethod_descriptor_ = NULL;
+const ::google::protobuf::EnumDescriptor* PoolingParameter_Engine_descriptor_ = NULL;
+const ::google::protobuf::Descriptor* PowerParameter_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+  PowerParameter_reflection_ = NULL;
+const ::google::protobuf::Descriptor* PythonParameter_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+  PythonParameter_reflection_ = NULL;
+const ::google::protobuf::Descriptor* ReductionParameter_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+  ReductionParameter_reflection_ = NULL;
+const ::google::protobuf::EnumDescriptor* ReductionParameter_ReductionOp_descriptor_ = NULL;
+const ::google::protobuf::Descriptor* ReLUParameter_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+  ReLUParameter_reflection_ = NULL;
+const ::google::protobuf::EnumDescriptor* ReLUParameter_Engine_descriptor_ = NULL;
+const ::google::protobuf::Descriptor* ReshapeParameter_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+  ReshapeParameter_reflection_ = NULL;
+const ::google::protobuf::Descriptor* SigmoidParameter_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+  SigmoidParameter_reflection_ = NULL;
+const ::google::protobuf::EnumDescriptor* SigmoidParameter_Engine_descriptor_ = NULL;
+const ::google::protobuf::Descriptor* SliceParameter_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+  SliceParameter_reflection_ = NULL;
+const ::google::protobuf::Descriptor* SoftmaxParameter_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+  SoftmaxParameter_reflection_ = NULL;
+const ::google::protobuf::EnumDescriptor* SoftmaxParameter_Engine_descriptor_ = NULL;
+const ::google::protobuf::Descriptor* TanHParameter_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+  TanHParameter_reflection_ = NULL;
+const ::google::protobuf::EnumDescriptor* TanHParameter_Engine_descriptor_ = NULL;
+const ::google::protobuf::Descriptor* ThresholdParameter_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+  ThresholdParameter_reflection_ = NULL;
+const ::google::protobuf::Descriptor* WindowDataParameter_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+  WindowDataParameter_reflection_ = NULL;
+const ::google::protobuf::Descriptor* SPPParameter_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+  SPPParameter_reflection_ = NULL;
+const ::google::protobuf::EnumDescriptor* SPPParameter_PoolMethod_descriptor_ = NULL;
+const ::google::protobuf::EnumDescriptor* SPPParameter_Engine_descriptor_ = NULL;
+const ::google::protobuf::Descriptor* V1LayerParameter_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+  V1LayerParameter_reflection_ = NULL;
+const ::google::protobuf::EnumDescriptor* V1LayerParameter_LayerType_descriptor_ = NULL;
+const ::google::protobuf::EnumDescriptor* V1LayerParameter_DimCheckMode_descriptor_ = NULL;
+const ::google::protobuf::Descriptor* V0LayerParameter_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+  V0LayerParameter_reflection_ = NULL;
+const ::google::protobuf::EnumDescriptor* V0LayerParameter_PoolMethod_descriptor_ = NULL;
+const ::google::protobuf::Descriptor* PReLUParameter_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+  PReLUParameter_reflection_ = NULL;
+const ::google::protobuf::Descriptor* NormalizedBBox_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+  NormalizedBBox_reflection_ = NULL;
+const ::google::protobuf::EnumDescriptor* Phase_descriptor_ = NULL;
+
+}  // namespace
+
+
+void protobuf_AssignDesc_caffe_2eproto() GOOGLE_ATTRIBUTE_COLD;
+void protobuf_AssignDesc_caffe_2eproto() {
+  protobuf_AddDesc_caffe_2eproto();
+  const ::google::protobuf::FileDescriptor* file =
+    ::google::protobuf::DescriptorPool::generated_pool()->FindFileByName(
+      "caffe.proto");
+  GOOGLE_CHECK(file != NULL);
+  BlobShape_descriptor_ = file->message_type(0);
+  static const int BlobShape_offsets_[1] = {
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(BlobShape, dim_),
+  };
+  BlobShape_reflection_ =
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
+      BlobShape_descriptor_,
+      BlobShape::internal_default_instance(),
+      BlobShape_offsets_,
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(BlobShape, _has_bits_),
+      -1,
+      -1,
+      sizeof(BlobShape),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(BlobShape, _internal_metadata_));
+  BlobProto_descriptor_ = file->message_type(1);
+  static const int BlobProto_offsets_[7] = {
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(BlobProto, shape_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(BlobProto, data_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(BlobProto, diff_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(BlobProto, num_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(BlobProto, channels_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(BlobProto, height_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(BlobProto, width_),
+  };
+  BlobProto_reflection_ =
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
+      BlobProto_descriptor_,
+      BlobProto::internal_default_instance(),
+      BlobProto_offsets_,
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(BlobProto, _has_bits_),
+      -1,
+      -1,
+      sizeof(BlobProto),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(BlobProto, _internal_metadata_));
+  BlobProtoVector_descriptor_ = file->message_type(2);
+  static const int BlobProtoVector_offsets_[1] = {
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(BlobProtoVector, blobs_),
+  };
+  BlobProtoVector_reflection_ =
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
+      BlobProtoVector_descriptor_,
+      BlobProtoVector::internal_default_instance(),
+      BlobProtoVector_offsets_,
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(BlobProtoVector, _has_bits_),
+      -1,
+      -1,
+      sizeof(BlobProtoVector),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(BlobProtoVector, _internal_metadata_));
+  CropParameter_descriptor_ = file->message_type(3);
+  static const int CropParameter_offsets_[2] = {
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(CropParameter, axis_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(CropParameter, offset_),
+  };
+  CropParameter_reflection_ =
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
+      CropParameter_descriptor_,
+      CropParameter::internal_default_instance(),
+      CropParameter_offsets_,
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(CropParameter, _has_bits_),
+      -1,
+      -1,
+      sizeof(CropParameter),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(CropParameter, _internal_metadata_));
+  PermuteParameter_descriptor_ = file->message_type(4);
+  static const int PermuteParameter_offsets_[1] = {
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(PermuteParameter, order_),
+  };
+  PermuteParameter_reflection_ =
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
+      PermuteParameter_descriptor_,
+      PermuteParameter::internal_default_instance(),
+      PermuteParameter_offsets_,
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(PermuteParameter, _has_bits_),
+      -1,
+      -1,
+      sizeof(PermuteParameter),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(PermuteParameter, _internal_metadata_));
+  NormalizeBBoxParameter_descriptor_ = file->message_type(5);
+  static const int NormalizeBBoxParameter_offsets_[4] = {
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(NormalizeBBoxParameter, across_spatial_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(NormalizeBBoxParameter, scale_filler_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(NormalizeBBoxParameter, channel_shared_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(NormalizeBBoxParameter, eps_),
+  };
+  NormalizeBBoxParameter_reflection_ =
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
+      NormalizeBBoxParameter_descriptor_,
+      NormalizeBBoxParameter::internal_default_instance(),
+      NormalizeBBoxParameter_offsets_,
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(NormalizeBBoxParameter, _has_bits_),
+      -1,
+      -1,
+      sizeof(NormalizeBBoxParameter),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(NormalizeBBoxParameter, _internal_metadata_));
+  PriorBoxParameter_descriptor_ = file->message_type(6);
+  static const int PriorBoxParameter_offsets_[6] = {
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(PriorBoxParameter, min_size_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(PriorBoxParameter, max_size_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(PriorBoxParameter, aspect_ratio_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(PriorBoxParameter, flip_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(PriorBoxParameter, clip_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(PriorBoxParameter, variance_),
+  };
+  PriorBoxParameter_reflection_ =
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
+      PriorBoxParameter_descriptor_,
+      PriorBoxParameter::internal_default_instance(),
+      PriorBoxParameter_offsets_,
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(PriorBoxParameter, _has_bits_),
+      -1,
+      -1,
+      sizeof(PriorBoxParameter),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(PriorBoxParameter, _internal_metadata_));
+  PriorBoxParameter_CodeType_descriptor_ = PriorBoxParameter_descriptor_->enum_type(0);
+  DetectionOutputParameter_descriptor_ = file->message_type(7);
+  static const int DetectionOutputParameter_offsets_[9] = {
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DetectionOutputParameter, num_classes_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DetectionOutputParameter, share_location_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DetectionOutputParameter, background_label_id_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DetectionOutputParameter, code_type_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DetectionOutputParameter, variance_encoded_in_target_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DetectionOutputParameter, keep_top_k_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DetectionOutputParameter, confidence_threshold_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DetectionOutputParameter, nms_threshold_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DetectionOutputParameter, top_k_),
+  };
+  DetectionOutputParameter_reflection_ =
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
+      DetectionOutputParameter_descriptor_,
+      DetectionOutputParameter::internal_default_instance(),
+      DetectionOutputParameter_offsets_,
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DetectionOutputParameter, _has_bits_),
+      -1,
+      -1,
+      sizeof(DetectionOutputParameter),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DetectionOutputParameter, _internal_metadata_));
+  Datum_descriptor_ = file->message_type(8);
+  static const int Datum_offsets_[7] = {
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Datum, channels_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Datum, height_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Datum, width_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Datum, data_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Datum, label_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Datum, float_data_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Datum, encoded_),
+  };
+  Datum_reflection_ =
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
+      Datum_descriptor_,
+      Datum::internal_default_instance(),
+      Datum_offsets_,
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Datum, _has_bits_),
+      -1,
+      -1,
+      sizeof(Datum),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Datum, _internal_metadata_));
+  FillerParameter_descriptor_ = file->message_type(9);
+  static const int FillerParameter_offsets_[8] = {
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FillerParameter, type_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FillerParameter, value_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FillerParameter, min_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FillerParameter, max_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FillerParameter, mean_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FillerParameter, std_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FillerParameter, sparse_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FillerParameter, variance_norm_),
+  };
+  FillerParameter_reflection_ =
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
+      FillerParameter_descriptor_,
+      FillerParameter::internal_default_instance(),
+      FillerParameter_offsets_,
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FillerParameter, _has_bits_),
+      -1,
+      -1,
+      sizeof(FillerParameter),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FillerParameter, _internal_metadata_));
+  FillerParameter_VarianceNorm_descriptor_ = FillerParameter_descriptor_->enum_type(0);
+  NetParameter_descriptor_ = file->message_type(10);
+  static const int NetParameter_offsets_[9] = {
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(NetParameter, name_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(NetParameter, input_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(NetParameter, input_shape_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(NetParameter, input_dim_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(NetParameter, force_backward_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(NetParameter, state_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(NetParameter, debug_info_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(NetParameter, layer_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(NetParameter, layers_),
+  };
+  NetParameter_reflection_ =
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
+      NetParameter_descriptor_,
+      NetParameter::internal_default_instance(),
+      NetParameter_offsets_,
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(NetParameter, _has_bits_),
+      -1,
+      -1,
+      sizeof(NetParameter),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(NetParameter, _internal_metadata_));
+  SolverParameter_descriptor_ = file->message_type(11);
+  static const int SolverParameter_offsets_[36] = {
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SolverParameter, net_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SolverParameter, net_param_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SolverParameter, train_net_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SolverParameter, test_net_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SolverParameter, train_net_param_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SolverParameter, test_net_param_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SolverParameter, train_state_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SolverParameter, test_state_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SolverParameter, test_iter_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SolverParameter, test_interval_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SolverParameter, test_compute_loss_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SolverParameter, test_initialization_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SolverParameter, base_lr_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SolverParameter, display_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SolverParameter, average_loss_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SolverParameter, max_iter_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SolverParameter, iter_size_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SolverParameter, lr_policy_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SolverParameter, gamma_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SolverParameter, power_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SolverParameter, momentum_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SolverParameter, weight_decay_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SolverParameter, regularization_type_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SolverParameter, stepsize_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SolverParameter, stepvalue_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SolverParameter, clip_gradients_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SolverParameter, snapshot_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SolverParameter, snapshot_prefix_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SolverParameter, snapshot_diff_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SolverParameter, solver_mode_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SolverParameter, device_id_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SolverParameter, random_seed_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SolverParameter, solver_type_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SolverParameter, delta_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SolverParameter, debug_info_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SolverParameter, snapshot_after_train_),
+  };
+  SolverParameter_reflection_ =
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
+      SolverParameter_descriptor_,
+      SolverParameter::internal_default_instance(),
+      SolverParameter_offsets_,
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SolverParameter, _has_bits_),
+      -1,
+      -1,
+      sizeof(SolverParameter),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SolverParameter, _internal_metadata_));
+  SolverParameter_SolverMode_descriptor_ = SolverParameter_descriptor_->enum_type(0);
+  SolverParameter_SolverType_descriptor_ = SolverParameter_descriptor_->enum_type(1);
+  SolverState_descriptor_ = file->message_type(12);
+  static const int SolverState_offsets_[4] = {
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SolverState, iter_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SolverState, learned_net_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SolverState, history_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SolverState, current_step_),
+  };
+  SolverState_reflection_ =
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
+      SolverState_descriptor_,
+      SolverState::internal_default_instance(),
+      SolverState_offsets_,
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SolverState, _has_bits_),
+      -1,
+      -1,
+      sizeof(SolverState),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SolverState, _internal_metadata_));
+  NetState_descriptor_ = file->message_type(13);
+  static const int NetState_offsets_[3] = {
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(NetState, phase_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(NetState, level_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(NetState, stage_),
+  };
+  NetState_reflection_ =
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
+      NetState_descriptor_,
+      NetState::internal_default_instance(),
+      NetState_offsets_,
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(NetState, _has_bits_),
+      -1,
+      -1,
+      sizeof(NetState),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(NetState, _internal_metadata_));
+  NetStateRule_descriptor_ = file->message_type(14);
+  static const int NetStateRule_offsets_[5] = {
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(NetStateRule, phase_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(NetStateRule, min_level_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(NetStateRule, max_level_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(NetStateRule, stage_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(NetStateRule, not_stage_),
+  };
+  NetStateRule_reflection_ =
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
+      NetStateRule_descriptor_,
+      NetStateRule::internal_default_instance(),
+      NetStateRule_offsets_,
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(NetStateRule, _has_bits_),
+      -1,
+      -1,
+      sizeof(NetStateRule),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(NetStateRule, _internal_metadata_));
+  ParamSpec_descriptor_ = file->message_type(15);
+  static const int ParamSpec_offsets_[4] = {
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ParamSpec, name_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ParamSpec, share_mode_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ParamSpec, lr_mult_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ParamSpec, decay_mult_),
+  };
+  ParamSpec_reflection_ =
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
+      ParamSpec_descriptor_,
+      ParamSpec::internal_default_instance(),
+      ParamSpec_offsets_,
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ParamSpec, _has_bits_),
+      -1,
+      -1,
+      sizeof(ParamSpec),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ParamSpec, _internal_metadata_));
+  ParamSpec_DimCheckMode_descriptor_ = ParamSpec_descriptor_->enum_type(0);
+  LayerParameter_descriptor_ = file->message_type(16);
+  static const int LayerParameter_offsets_[53] = {
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(LayerParameter, name_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(LayerParameter, type_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(LayerParameter, bottom_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(LayerParameter, top_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(LayerParameter, phase_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(LayerParameter, loss_weight_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(LayerParameter, param_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(LayerParameter, blobs_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(LayerParameter, propagate_down_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(LayerParameter, include_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(LayerParameter, exclude_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(LayerParameter, transform_param_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(LayerParameter, loss_param_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(LayerParameter, accuracy_param_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(LayerParameter, argmax_param_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(LayerParameter, concat_param_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(LayerParameter, contrastive_loss_param_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(LayerParameter, convolution_param_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(LayerParameter, crop_param_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(LayerParameter, data_param_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(LayerParameter, detection_output_param_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(LayerParameter, dropout_param_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(LayerParameter, dummy_data_param_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(LayerParameter, eltwise_param_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(LayerParameter, exp_param_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(LayerParameter, flatten_param_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(LayerParameter, hdf5_data_param_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(LayerParameter, hdf5_output_param_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(LayerParameter, hinge_loss_param_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(LayerParameter, image_data_param_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(LayerParameter, infogain_loss_param_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(LayerParameter, inner_product_param_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(LayerParameter, log_param_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(LayerParameter, lrn_param_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(LayerParameter, memory_data_param_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(LayerParameter, mvn_param_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(LayerParameter, normalize_bbox_param_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(LayerParameter, permute_param_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(LayerParameter, pooling_param_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(LayerParameter, power_param_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(LayerParameter, prelu_param_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(LayerParameter, prior_box_param_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(LayerParameter, python_param_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(LayerParameter, reduction_param_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(LayerParameter, relu_param_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(LayerParameter, reshape_param_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(LayerParameter, sigmoid_param_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(LayerParameter, slice_param_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(LayerParameter, softmax_param_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(LayerParameter, spp_param_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(LayerParameter, tanh_param_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(LayerParameter, threshold_param_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(LayerParameter, window_data_param_),
+  };
+  LayerParameter_reflection_ =
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
+      LayerParameter_descriptor_,
+      LayerParameter::internal_default_instance(),
+      LayerParameter_offsets_,
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(LayerParameter, _has_bits_),
+      -1,
+      -1,
+      sizeof(LayerParameter),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(LayerParameter, _internal_metadata_));
+  TransformationParameter_descriptor_ = file->message_type(17);
+  static const int TransformationParameter_offsets_[7] = {
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(TransformationParameter, scale_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(TransformationParameter, mirror_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(TransformationParameter, crop_size_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(TransformationParameter, mean_file_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(TransformationParameter, mean_value_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(TransformationParameter, force_color_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(TransformationParameter, force_gray_),
+  };
+  TransformationParameter_reflection_ =
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
+      TransformationParameter_descriptor_,
+      TransformationParameter::internal_default_instance(),
+      TransformationParameter_offsets_,
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(TransformationParameter, _has_bits_),
+      -1,
+      -1,
+      sizeof(TransformationParameter),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(TransformationParameter, _internal_metadata_));
+  LossParameter_descriptor_ = file->message_type(18);
+  static const int LossParameter_offsets_[2] = {
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(LossParameter, ignore_label_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(LossParameter, normalize_),
+  };
+  LossParameter_reflection_ =
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
+      LossParameter_descriptor_,
+      LossParameter::internal_default_instance(),
+      LossParameter_offsets_,
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(LossParameter, _has_bits_),
+      -1,
+      -1,
+      sizeof(LossParameter),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(LossParameter, _internal_metadata_));
+  AccuracyParameter_descriptor_ = file->message_type(19);
+  static const int AccuracyParameter_offsets_[3] = {
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(AccuracyParameter, top_k_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(AccuracyParameter, axis_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(AccuracyParameter, ignore_label_),
+  };
+  AccuracyParameter_reflection_ =
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
+      AccuracyParameter_descriptor_,
+      AccuracyParameter::internal_default_instance(),
+      AccuracyParameter_offsets_,
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(AccuracyParameter, _has_bits_),
+      -1,
+      -1,
+      sizeof(AccuracyParameter),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(AccuracyParameter, _internal_metadata_));
+  ArgMaxParameter_descriptor_ = file->message_type(20);
+  static const int ArgMaxParameter_offsets_[2] = {
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ArgMaxParameter, out_max_val_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ArgMaxParameter, top_k_),
+  };
+  ArgMaxParameter_reflection_ =
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
+      ArgMaxParameter_descriptor_,
+      ArgMaxParameter::internal_default_instance(),
+      ArgMaxParameter_offsets_,
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ArgMaxParameter, _has_bits_),
+      -1,
+      -1,
+      sizeof(ArgMaxParameter),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ArgMaxParameter, _internal_metadata_));
+  ConcatParameter_descriptor_ = file->message_type(21);
+  static const int ConcatParameter_offsets_[2] = {
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ConcatParameter, axis_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ConcatParameter, concat_dim_),
+  };
+  ConcatParameter_reflection_ =
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
+      ConcatParameter_descriptor_,
+      ConcatParameter::internal_default_instance(),
+      ConcatParameter_offsets_,
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ConcatParameter, _has_bits_),
+      -1,
+      -1,
+      sizeof(ConcatParameter),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ConcatParameter, _internal_metadata_));
+  ContrastiveLossParameter_descriptor_ = file->message_type(22);
+  static const int ContrastiveLossParameter_offsets_[2] = {
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ContrastiveLossParameter, margin_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ContrastiveLossParameter, legacy_version_),
+  };
+  ContrastiveLossParameter_reflection_ =
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
+      ContrastiveLossParameter_descriptor_,
+      ContrastiveLossParameter::internal_default_instance(),
+      ContrastiveLossParameter_offsets_,
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ContrastiveLossParameter, _has_bits_),
+      -1,
+      -1,
+      sizeof(ContrastiveLossParameter),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ContrastiveLossParameter, _internal_metadata_));
+  ConvolutionParameter_descriptor_ = file->message_type(23);
+  static const int ConvolutionParameter_offsets_[18] = {
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ConvolutionParameter, num_output_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ConvolutionParameter, bias_term_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ConvolutionParameter, pad_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ConvolutionParameter, pad_h_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ConvolutionParameter, pad_w_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ConvolutionParameter, kernel_size_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ConvolutionParameter, kernel_h_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ConvolutionParameter, kernel_w_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ConvolutionParameter, group_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ConvolutionParameter, stride_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ConvolutionParameter, stride_h_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ConvolutionParameter, stride_w_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ConvolutionParameter, weight_filler_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ConvolutionParameter, bias_filler_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ConvolutionParameter, engine_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ConvolutionParameter, dilation_h_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ConvolutionParameter, dilation_w_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ConvolutionParameter, dilation_),
+  };
+  ConvolutionParameter_reflection_ =
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
+      ConvolutionParameter_descriptor_,
+      ConvolutionParameter::internal_default_instance(),
+      ConvolutionParameter_offsets_,
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ConvolutionParameter, _has_bits_),
+      -1,
+      -1,
+      sizeof(ConvolutionParameter),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ConvolutionParameter, _internal_metadata_));
+  ConvolutionParameter_Engine_descriptor_ = ConvolutionParameter_descriptor_->enum_type(0);
+  DataParameter_descriptor_ = file->message_type(24);
+  static const int DataParameter_offsets_[9] = {
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DataParameter, source_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DataParameter, batch_size_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DataParameter, rand_skip_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DataParameter, backend_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DataParameter, scale_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DataParameter, mean_file_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DataParameter, crop_size_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DataParameter, mirror_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DataParameter, force_encoded_color_),
+  };
+  DataParameter_reflection_ =
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
+      DataParameter_descriptor_,
+      DataParameter::internal_default_instance(),
+      DataParameter_offsets_,
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DataParameter, _has_bits_),
+      -1,
+      -1,
+      sizeof(DataParameter),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DataParameter, _internal_metadata_));
+  DataParameter_DB_descriptor_ = DataParameter_descriptor_->enum_type(0);
+  DropoutParameter_descriptor_ = file->message_type(25);
+  static const int DropoutParameter_offsets_[1] = {
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DropoutParameter, dropout_ratio_),
+  };
+  DropoutParameter_reflection_ =
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
+      DropoutParameter_descriptor_,
+      DropoutParameter::internal_default_instance(),
+      DropoutParameter_offsets_,
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DropoutParameter, _has_bits_),
+      -1,
+      -1,
+      sizeof(DropoutParameter),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DropoutParameter, _internal_metadata_));
+  DummyDataParameter_descriptor_ = file->message_type(26);
+  static const int DummyDataParameter_offsets_[6] = {
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DummyDataParameter, data_filler_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DummyDataParameter, shape_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DummyDataParameter, num_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DummyDataParameter, channels_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DummyDataParameter, height_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DummyDataParameter, width_),
+  };
+  DummyDataParameter_reflection_ =
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
+      DummyDataParameter_descriptor_,
+      DummyDataParameter::internal_default_instance(),
+      DummyDataParameter_offsets_,
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DummyDataParameter, _has_bits_),
+      -1,
+      -1,
+      sizeof(DummyDataParameter),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DummyDataParameter, _internal_metadata_));
+  EltwiseParameter_descriptor_ = file->message_type(27);
+  static const int EltwiseParameter_offsets_[3] = {
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EltwiseParameter, operation_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EltwiseParameter, coeff_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EltwiseParameter, stable_prod_grad_),
+  };
+  EltwiseParameter_reflection_ =
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
+      EltwiseParameter_descriptor_,
+      EltwiseParameter::internal_default_instance(),
+      EltwiseParameter_offsets_,
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EltwiseParameter, _has_bits_),
+      -1,
+      -1,
+      sizeof(EltwiseParameter),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EltwiseParameter, _internal_metadata_));
+  EltwiseParameter_EltwiseOp_descriptor_ = EltwiseParameter_descriptor_->enum_type(0);
+  ExpParameter_descriptor_ = file->message_type(28);
+  static const int ExpParameter_offsets_[3] = {
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ExpParameter, base_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ExpParameter, scale_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ExpParameter, shift_),
+  };
+  ExpParameter_reflection_ =
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
+      ExpParameter_descriptor_,
+      ExpParameter::internal_default_instance(),
+      ExpParameter_offsets_,
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ExpParameter, _has_bits_),
+      -1,
+      -1,
+      sizeof(ExpParameter),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ExpParameter, _internal_metadata_));
+  FlattenParameter_descriptor_ = file->message_type(29);
+  static const int FlattenParameter_offsets_[2] = {
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FlattenParameter, axis_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FlattenParameter, end_axis_),
+  };
+  FlattenParameter_reflection_ =
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
+      FlattenParameter_descriptor_,
+      FlattenParameter::internal_default_instance(),
+      FlattenParameter_offsets_,
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FlattenParameter, _has_bits_),
+      -1,
+      -1,
+      sizeof(FlattenParameter),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FlattenParameter, _internal_metadata_));
+  HDF5DataParameter_descriptor_ = file->message_type(30);
+  static const int HDF5DataParameter_offsets_[3] = {
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(HDF5DataParameter, source_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(HDF5DataParameter, batch_size_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(HDF5DataParameter, shuffle_),
+  };
+  HDF5DataParameter_reflection_ =
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
+      HDF5DataParameter_descriptor_,
+      HDF5DataParameter::internal_default_instance(),
+      HDF5DataParameter_offsets_,
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(HDF5DataParameter, _has_bits_),
+      -1,
+      -1,
+      sizeof(HDF5DataParameter),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(HDF5DataParameter, _internal_metadata_));
+  HDF5OutputParameter_descriptor_ = file->message_type(31);
+  static const int HDF5OutputParameter_offsets_[1] = {
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(HDF5OutputParameter, file_name_),
+  };
+  HDF5OutputParameter_reflection_ =
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
+      HDF5OutputParameter_descriptor_,
+      HDF5OutputParameter::internal_default_instance(),
+      HDF5OutputParameter_offsets_,
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(HDF5OutputParameter, _has_bits_),
+      -1,
+      -1,
+      sizeof(HDF5OutputParameter),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(HDF5OutputParameter, _internal_metadata_));
+  HingeLossParameter_descriptor_ = file->message_type(32);
+  static const int HingeLossParameter_offsets_[1] = {
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(HingeLossParameter, norm_),
+  };
+  HingeLossParameter_reflection_ =
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
+      HingeLossParameter_descriptor_,
+      HingeLossParameter::internal_default_instance(),
+      HingeLossParameter_offsets_,
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(HingeLossParameter, _has_bits_),
+      -1,
+      -1,
+      sizeof(HingeLossParameter),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(HingeLossParameter, _internal_metadata_));
+  HingeLossParameter_Norm_descriptor_ = HingeLossParameter_descriptor_->enum_type(0);
+  ImageDataParameter_descriptor_ = file->message_type(33);
+  static const int ImageDataParameter_offsets_[12] = {
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ImageDataParameter, source_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ImageDataParameter, batch_size_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ImageDataParameter, rand_skip_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ImageDataParameter, shuffle_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ImageDataParameter, new_height_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ImageDataParameter, new_width_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ImageDataParameter, is_color_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ImageDataParameter, scale_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ImageDataParameter, mean_file_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ImageDataParameter, crop_size_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ImageDataParameter, mirror_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ImageDataParameter, root_folder_),
+  };
+  ImageDataParameter_reflection_ =
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
+      ImageDataParameter_descriptor_,
+      ImageDataParameter::internal_default_instance(),
+      ImageDataParameter_offsets_,
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ImageDataParameter, _has_bits_),
+      -1,
+      -1,
+      sizeof(ImageDataParameter),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ImageDataParameter, _internal_metadata_));
+  InfogainLossParameter_descriptor_ = file->message_type(34);
+  static const int InfogainLossParameter_offsets_[1] = {
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(InfogainLossParameter, source_),
+  };
+  InfogainLossParameter_reflection_ =
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
+      InfogainLossParameter_descriptor_,
+      InfogainLossParameter::internal_default_instance(),
+      InfogainLossParameter_offsets_,
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(InfogainLossParameter, _has_bits_),
+      -1,
+      -1,
+      sizeof(InfogainLossParameter),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(InfogainLossParameter, _internal_metadata_));
+  InnerProductParameter_descriptor_ = file->message_type(35);
+  static const int InnerProductParameter_offsets_[5] = {
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(InnerProductParameter, num_output_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(InnerProductParameter, bias_term_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(InnerProductParameter, weight_filler_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(InnerProductParameter, bias_filler_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(InnerProductParameter, axis_),
+  };
+  InnerProductParameter_reflection_ =
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
+      InnerProductParameter_descriptor_,
+      InnerProductParameter::internal_default_instance(),
+      InnerProductParameter_offsets_,
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(InnerProductParameter, _has_bits_),
+      -1,
+      -1,
+      sizeof(InnerProductParameter),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(InnerProductParameter, _internal_metadata_));
+  LogParameter_descriptor_ = file->message_type(36);
+  static const int LogParameter_offsets_[3] = {
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(LogParameter, base_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(LogParameter, scale_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(LogParameter, shift_),
+  };
+  LogParameter_reflection_ =
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
+      LogParameter_descriptor_,
+      LogParameter::internal_default_instance(),
+      LogParameter_offsets_,
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(LogParameter, _has_bits_),
+      -1,
+      -1,
+      sizeof(LogParameter),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(LogParameter, _internal_metadata_));
+  LRNParameter_descriptor_ = file->message_type(37);
+  static const int LRNParameter_offsets_[5] = {
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(LRNParameter, local_size_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(LRNParameter, alpha_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(LRNParameter, beta_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(LRNParameter, norm_region_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(LRNParameter, k_),
+  };
+  LRNParameter_reflection_ =
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
+      LRNParameter_descriptor_,
+      LRNParameter::internal_default_instance(),
+      LRNParameter_offsets_,
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(LRNParameter, _has_bits_),
+      -1,
+      -1,
+      sizeof(LRNParameter),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(LRNParameter, _internal_metadata_));
+  LRNParameter_NormRegion_descriptor_ = LRNParameter_descriptor_->enum_type(0);
+  MemoryDataParameter_descriptor_ = file->message_type(38);
+  static const int MemoryDataParameter_offsets_[4] = {
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MemoryDataParameter, batch_size_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MemoryDataParameter, channels_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MemoryDataParameter, height_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MemoryDataParameter, width_),
+  };
+  MemoryDataParameter_reflection_ =
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
+      MemoryDataParameter_descriptor_,
+      MemoryDataParameter::internal_default_instance(),
+      MemoryDataParameter_offsets_,
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MemoryDataParameter, _has_bits_),
+      -1,
+      -1,
+      sizeof(MemoryDataParameter),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MemoryDataParameter, _internal_metadata_));
+  MVNParameter_descriptor_ = file->message_type(39);
+  static const int MVNParameter_offsets_[3] = {
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MVNParameter, normalize_variance_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MVNParameter, across_channels_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MVNParameter, eps_),
+  };
+  MVNParameter_reflection_ =
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
+      MVNParameter_descriptor_,
+      MVNParameter::internal_default_instance(),
+      MVNParameter_offsets_,
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MVNParameter, _has_bits_),
+      -1,
+      -1,
+      sizeof(MVNParameter),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MVNParameter, _internal_metadata_));
+  PoolingParameter_descriptor_ = file->message_type(40);
+  static const int PoolingParameter_offsets_[12] = {
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(PoolingParameter, pool_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(PoolingParameter, pad_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(PoolingParameter, pad_h_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(PoolingParameter, pad_w_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(PoolingParameter, kernel_size_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(PoolingParameter, kernel_h_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(PoolingParameter, kernel_w_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(PoolingParameter, stride_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(PoolingParameter, stride_h_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(PoolingParameter, stride_w_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(PoolingParameter, engine_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(PoolingParameter, global_pooling_),
+  };
+  PoolingParameter_reflection_ =
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
+      PoolingParameter_descriptor_,
+      PoolingParameter::internal_default_instance(),
+      PoolingParameter_offsets_,
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(PoolingParameter, _has_bits_),
+      -1,
+      -1,
+      sizeof(PoolingParameter),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(PoolingParameter, _internal_metadata_));
+  PoolingParameter_PoolMethod_descriptor_ = PoolingParameter_descriptor_->enum_type(0);
+  PoolingParameter_Engine_descriptor_ = PoolingParameter_descriptor_->enum_type(1);
+  PowerParameter_descriptor_ = file->message_type(41);
+  static const int PowerParameter_offsets_[3] = {
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(PowerParameter, power_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(PowerParameter, scale_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(PowerParameter, shift_),
+  };
+  PowerParameter_reflection_ =
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
+      PowerParameter_descriptor_,
+      PowerParameter::internal_default_instance(),
+      PowerParameter_offsets_,
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(PowerParameter, _has_bits_),
+      -1,
+      -1,
+      sizeof(PowerParameter),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(PowerParameter, _internal_metadata_));
+  PythonParameter_descriptor_ = file->message_type(42);
+  static const int PythonParameter_offsets_[2] = {
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(PythonParameter, module_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(PythonParameter, layer_),
+  };
+  PythonParameter_reflection_ =
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
+      PythonParameter_descriptor_,
+      PythonParameter::internal_default_instance(),
+      PythonParameter_offsets_,
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(PythonParameter, _has_bits_),
+      -1,
+      -1,
+      sizeof(PythonParameter),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(PythonParameter, _internal_metadata_));
+  ReductionParameter_descriptor_ = file->message_type(43);
+  static const int ReductionParameter_offsets_[3] = {
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ReductionParameter, operation_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ReductionParameter, axis_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ReductionParameter, coeff_),
+  };
+  ReductionParameter_reflection_ =
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
+      ReductionParameter_descriptor_,
+      ReductionParameter::internal_default_instance(),
+      ReductionParameter_offsets_,
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ReductionParameter, _has_bits_),
+      -1,
+      -1,
+      sizeof(ReductionParameter),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ReductionParameter, _internal_metadata_));
+  ReductionParameter_ReductionOp_descriptor_ = ReductionParameter_descriptor_->enum_type(0);
+  ReLUParameter_descriptor_ = file->message_type(44);
+  static const int ReLUParameter_offsets_[2] = {
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ReLUParameter, negative_slope_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ReLUParameter, engine_),
+  };
+  ReLUParameter_reflection_ =
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
+      ReLUParameter_descriptor_,
+      ReLUParameter::internal_default_instance(),
+      ReLUParameter_offsets_,
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ReLUParameter, _has_bits_),
+      -1,
+      -1,
+      sizeof(ReLUParameter),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ReLUParameter, _internal_metadata_));
+  ReLUParameter_Engine_descriptor_ = ReLUParameter_descriptor_->enum_type(0);
+  ReshapeParameter_descriptor_ = file->message_type(45);
+  static const int ReshapeParameter_offsets_[3] = {
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ReshapeParameter, shape_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ReshapeParameter, axis_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ReshapeParameter, num_axes_),
+  };
+  ReshapeParameter_reflection_ =
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
+      ReshapeParameter_descriptor_,
+      ReshapeParameter::internal_default_instance(),
+      ReshapeParameter_offsets_,
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ReshapeParameter, _has_bits_),
+      -1,
+      -1,
+      sizeof(ReshapeParameter),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ReshapeParameter, _internal_metadata_));
+  SigmoidParameter_descriptor_ = file->message_type(46);
+  static const int SigmoidParameter_offsets_[1] = {
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SigmoidParameter, engine_),
+  };
+  SigmoidParameter_reflection_ =
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
+      SigmoidParameter_descriptor_,
+      SigmoidParameter::internal_default_instance(),
+      SigmoidParameter_offsets_,
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SigmoidParameter, _has_bits_),
+      -1,
+      -1,
+      sizeof(SigmoidParameter),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SigmoidParameter, _internal_metadata_));
+  SigmoidParameter_Engine_descriptor_ = SigmoidParameter_descriptor_->enum_type(0);
+  SliceParameter_descriptor_ = file->message_type(47);
+  static const int SliceParameter_offsets_[3] = {
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SliceParameter, axis_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SliceParameter, slice_point_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SliceParameter, slice_dim_),
+  };
+  SliceParameter_reflection_ =
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
+      SliceParameter_descriptor_,
+      SliceParameter::internal_default_instance(),
+      SliceParameter_offsets_,
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SliceParameter, _has_bits_),
+      -1,
+      -1,
+      sizeof(SliceParameter),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SliceParameter, _internal_metadata_));
+  SoftmaxParameter_descriptor_ = file->message_type(48);
+  static const int SoftmaxParameter_offsets_[2] = {
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SoftmaxParameter, engine_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SoftmaxParameter, axis_),
+  };
+  SoftmaxParameter_reflection_ =
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
+      SoftmaxParameter_descriptor_,
+      SoftmaxParameter::internal_default_instance(),
+      SoftmaxParameter_offsets_,
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SoftmaxParameter, _has_bits_),
+      -1,
+      -1,
+      sizeof(SoftmaxParameter),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SoftmaxParameter, _internal_metadata_));
+  SoftmaxParameter_Engine_descriptor_ = SoftmaxParameter_descriptor_->enum_type(0);
+  TanHParameter_descriptor_ = file->message_type(49);
+  static const int TanHParameter_offsets_[1] = {
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(TanHParameter, engine_),
+  };
+  TanHParameter_reflection_ =
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
+      TanHParameter_descriptor_,
+      TanHParameter::internal_default_instance(),
+      TanHParameter_offsets_,
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(TanHParameter, _has_bits_),
+      -1,
+      -1,
+      sizeof(TanHParameter),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(TanHParameter, _internal_metadata_));
+  TanHParameter_Engine_descriptor_ = TanHParameter_descriptor_->enum_type(0);
+  ThresholdParameter_descriptor_ = file->message_type(50);
+  static const int ThresholdParameter_offsets_[1] = {
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ThresholdParameter, threshold_),
+  };
+  ThresholdParameter_reflection_ =
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
+      ThresholdParameter_descriptor_,
+      ThresholdParameter::internal_default_instance(),
+      ThresholdParameter_offsets_,
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ThresholdParameter, _has_bits_),
+      -1,
+      -1,
+      sizeof(ThresholdParameter),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ThresholdParameter, _internal_metadata_));
+  WindowDataParameter_descriptor_ = file->message_type(51);
+  static const int WindowDataParameter_offsets_[13] = {
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(WindowDataParameter, source_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(WindowDataParameter, scale_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(WindowDataParameter, mean_file_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(WindowDataParameter, batch_size_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(WindowDataParameter, crop_size_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(WindowDataParameter, mirror_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(WindowDataParameter, fg_threshold_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(WindowDataParameter, bg_threshold_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(WindowDataParameter, fg_fraction_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(WindowDataParameter, context_pad_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(WindowDataParameter, crop_mode_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(WindowDataParameter, cache_images_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(WindowDataParameter, root_folder_),
+  };
+  WindowDataParameter_reflection_ =
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
+      WindowDataParameter_descriptor_,
+      WindowDataParameter::internal_default_instance(),
+      WindowDataParameter_offsets_,
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(WindowDataParameter, _has_bits_),
+      -1,
+      -1,
+      sizeof(WindowDataParameter),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(WindowDataParameter, _internal_metadata_));
+  SPPParameter_descriptor_ = file->message_type(52);
+  static const int SPPParameter_offsets_[3] = {
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SPPParameter, pyramid_height_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SPPParameter, pool_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SPPParameter, engine_),
+  };
+  SPPParameter_reflection_ =
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
+      SPPParameter_descriptor_,
+      SPPParameter::internal_default_instance(),
+      SPPParameter_offsets_,
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SPPParameter, _has_bits_),
+      -1,
+      -1,
+      sizeof(SPPParameter),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SPPParameter, _internal_metadata_));
+  SPPParameter_PoolMethod_descriptor_ = SPPParameter_descriptor_->enum_type(0);
+  SPPParameter_Engine_descriptor_ = SPPParameter_descriptor_->enum_type(1);
+  V1LayerParameter_descriptor_ = file->message_type(53);
+  static const int V1LayerParameter_offsets_[43] = {
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(V1LayerParameter, bottom_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(V1LayerParameter, top_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(V1LayerParameter, name_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(V1LayerParameter, include_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(V1LayerParameter, exclude_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(V1LayerParameter, type_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(V1LayerParameter, blobs_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(V1LayerParameter, param_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(V1LayerParameter, blob_share_mode_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(V1LayerParameter, blobs_lr_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(V1LayerParameter, weight_decay_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(V1LayerParameter, loss_weight_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(V1LayerParameter, accuracy_param_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(V1LayerParameter, argmax_param_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(V1LayerParameter, concat_param_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(V1LayerParameter, contrastive_loss_param_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(V1LayerParameter, convolution_param_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(V1LayerParameter, data_param_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(V1LayerParameter, dropout_param_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(V1LayerParameter, dummy_data_param_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(V1LayerParameter, eltwise_param_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(V1LayerParameter, exp_param_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(V1LayerParameter, hdf5_data_param_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(V1LayerParameter, hdf5_output_param_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(V1LayerParameter, hinge_loss_param_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(V1LayerParameter, image_data_param_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(V1LayerParameter, infogain_loss_param_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(V1LayerParameter, inner_product_param_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(V1LayerParameter, lrn_param_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(V1LayerParameter, memory_data_param_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(V1LayerParameter, mvn_param_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(V1LayerParameter, pooling_param_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(V1LayerParameter, power_param_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(V1LayerParameter, relu_param_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(V1LayerParameter, sigmoid_param_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(V1LayerParameter, softmax_param_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(V1LayerParameter, slice_param_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(V1LayerParameter, tanh_param_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(V1LayerParameter, threshold_param_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(V1LayerParameter, window_data_param_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(V1LayerParameter, transform_param_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(V1LayerParameter, loss_param_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(V1LayerParameter, layer_),
+  };
+  V1LayerParameter_reflection_ =
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
+      V1LayerParameter_descriptor_,
+      V1LayerParameter::internal_default_instance(),
+      V1LayerParameter_offsets_,
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(V1LayerParameter, _has_bits_),
+      -1,
+      -1,
+      sizeof(V1LayerParameter),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(V1LayerParameter, _internal_metadata_));
+  V1LayerParameter_LayerType_descriptor_ = V1LayerParameter_descriptor_->enum_type(0);
+  V1LayerParameter_DimCheckMode_descriptor_ = V1LayerParameter_descriptor_->enum_type(1);
+  V0LayerParameter_descriptor_ = file->message_type(54);
+  static const int V0LayerParameter_offsets_[38] = {
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(V0LayerParameter, name_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(V0LayerParameter, type_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(V0LayerParameter, num_output_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(V0LayerParameter, biasterm_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(V0LayerParameter, weight_filler_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(V0LayerParameter, bias_filler_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(V0LayerParameter, pad_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(V0LayerParameter, kernelsize_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(V0LayerParameter, group_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(V0LayerParameter, stride_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(V0LayerParameter, pool_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(V0LayerParameter, dropout_ratio_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(V0LayerParameter, local_size_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(V0LayerParameter, alpha_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(V0LayerParameter, beta_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(V0LayerParameter, k_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(V0LayerParameter, source_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(V0LayerParameter, scale_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(V0LayerParameter, meanfile_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(V0LayerParameter, batchsize_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(V0LayerParameter, cropsize_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(V0LayerParameter, mirror_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(V0LayerParameter, blobs_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(V0LayerParameter, blobs_lr_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(V0LayerParameter, weight_decay_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(V0LayerParameter, rand_skip_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(V0LayerParameter, det_fg_threshold_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(V0LayerParameter, det_bg_threshold_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(V0LayerParameter, det_fg_fraction_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(V0LayerParameter, det_context_pad_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(V0LayerParameter, det_crop_mode_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(V0LayerParameter, new_num_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(V0LayerParameter, new_channels_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(V0LayerParameter, new_height_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(V0LayerParameter, new_width_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(V0LayerParameter, shuffle_images_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(V0LayerParameter, concat_dim_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(V0LayerParameter, hdf5_output_param_),
+  };
+  V0LayerParameter_reflection_ =
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
+      V0LayerParameter_descriptor_,
+      V0LayerParameter::internal_default_instance(),
+      V0LayerParameter_offsets_,
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(V0LayerParameter, _has_bits_),
+      -1,
+      -1,
+      sizeof(V0LayerParameter),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(V0LayerParameter, _internal_metadata_));
+  V0LayerParameter_PoolMethod_descriptor_ = V0LayerParameter_descriptor_->enum_type(0);
+  PReLUParameter_descriptor_ = file->message_type(55);
+  static const int PReLUParameter_offsets_[2] = {
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(PReLUParameter, filler_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(PReLUParameter, channel_shared_),
+  };
+  PReLUParameter_reflection_ =
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
+      PReLUParameter_descriptor_,
+      PReLUParameter::internal_default_instance(),
+      PReLUParameter_offsets_,
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(PReLUParameter, _has_bits_),
+      -1,
+      -1,
+      sizeof(PReLUParameter),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(PReLUParameter, _internal_metadata_));
+  NormalizedBBox_descriptor_ = file->message_type(56);
+  static const int NormalizedBBox_offsets_[8] = {
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(NormalizedBBox, xmin_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(NormalizedBBox, ymin_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(NormalizedBBox, xmax_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(NormalizedBBox, ymax_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(NormalizedBBox, label_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(NormalizedBBox, difficult_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(NormalizedBBox, score_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(NormalizedBBox, size_),
+  };
+  NormalizedBBox_reflection_ =
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
+      NormalizedBBox_descriptor_,
+      NormalizedBBox::internal_default_instance(),
+      NormalizedBBox_offsets_,
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(NormalizedBBox, _has_bits_),
+      -1,
+      -1,
+      sizeof(NormalizedBBox),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(NormalizedBBox, _internal_metadata_));
+  Phase_descriptor_ = file->enum_type(0);
+}
+
+namespace {
+
+GOOGLE_PROTOBUF_DECLARE_ONCE(protobuf_AssignDescriptors_once_);
+void protobuf_AssignDescriptorsOnce() {
+  ::google::protobuf::GoogleOnceInit(&protobuf_AssignDescriptors_once_,
+                 &protobuf_AssignDesc_caffe_2eproto);
+}
+
+void protobuf_RegisterTypes(const ::std::string&) GOOGLE_ATTRIBUTE_COLD;
+void protobuf_RegisterTypes(const ::std::string&) {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+      BlobShape_descriptor_, BlobShape::internal_default_instance());
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+      BlobProto_descriptor_, BlobProto::internal_default_instance());
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+      BlobProtoVector_descriptor_, BlobProtoVector::internal_default_instance());
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+      CropParameter_descriptor_, CropParameter::internal_default_instance());
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+      PermuteParameter_descriptor_, PermuteParameter::internal_default_instance());
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+      NormalizeBBoxParameter_descriptor_, NormalizeBBoxParameter::internal_default_instance());
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+      PriorBoxParameter_descriptor_, PriorBoxParameter::internal_default_instance());
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+      DetectionOutputParameter_descriptor_, DetectionOutputParameter::internal_default_instance());
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+      Datum_descriptor_, Datum::internal_default_instance());
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+      FillerParameter_descriptor_, FillerParameter::internal_default_instance());
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+      NetParameter_descriptor_, NetParameter::internal_default_instance());
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+      SolverParameter_descriptor_, SolverParameter::internal_default_instance());
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+      SolverState_descriptor_, SolverState::internal_default_instance());
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+      NetState_descriptor_, NetState::internal_default_instance());
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+      NetStateRule_descriptor_, NetStateRule::internal_default_instance());
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+      ParamSpec_descriptor_, ParamSpec::internal_default_instance());
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+      LayerParameter_descriptor_, LayerParameter::internal_default_instance());
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+      TransformationParameter_descriptor_, TransformationParameter::internal_default_instance());
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+      LossParameter_descriptor_, LossParameter::internal_default_instance());
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+      AccuracyParameter_descriptor_, AccuracyParameter::internal_default_instance());
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+      ArgMaxParameter_descriptor_, ArgMaxParameter::internal_default_instance());
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+      ConcatParameter_descriptor_, ConcatParameter::internal_default_instance());
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+      ContrastiveLossParameter_descriptor_, ContrastiveLossParameter::internal_default_instance());
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+      ConvolutionParameter_descriptor_, ConvolutionParameter::internal_default_instance());
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+      DataParameter_descriptor_, DataParameter::internal_default_instance());
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+      DropoutParameter_descriptor_, DropoutParameter::internal_default_instance());
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+      DummyDataParameter_descriptor_, DummyDataParameter::internal_default_instance());
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+      EltwiseParameter_descriptor_, EltwiseParameter::internal_default_instance());
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+      ExpParameter_descriptor_, ExpParameter::internal_default_instance());
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+      FlattenParameter_descriptor_, FlattenParameter::internal_default_instance());
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+      HDF5DataParameter_descriptor_, HDF5DataParameter::internal_default_instance());
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+      HDF5OutputParameter_descriptor_, HDF5OutputParameter::internal_default_instance());
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+      HingeLossParameter_descriptor_, HingeLossParameter::internal_default_instance());
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+      ImageDataParameter_descriptor_, ImageDataParameter::internal_default_instance());
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+      InfogainLossParameter_descriptor_, InfogainLossParameter::internal_default_instance());
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+      InnerProductParameter_descriptor_, InnerProductParameter::internal_default_instance());
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+      LogParameter_descriptor_, LogParameter::internal_default_instance());
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+      LRNParameter_descriptor_, LRNParameter::internal_default_instance());
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+      MemoryDataParameter_descriptor_, MemoryDataParameter::internal_default_instance());
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+      MVNParameter_descriptor_, MVNParameter::internal_default_instance());
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+      PoolingParameter_descriptor_, PoolingParameter::internal_default_instance());
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+      PowerParameter_descriptor_, PowerParameter::internal_default_instance());
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+      PythonParameter_descriptor_, PythonParameter::internal_default_instance());
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+      ReductionParameter_descriptor_, ReductionParameter::internal_default_instance());
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+      ReLUParameter_descriptor_, ReLUParameter::internal_default_instance());
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+      ReshapeParameter_descriptor_, ReshapeParameter::internal_default_instance());
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+      SigmoidParameter_descriptor_, SigmoidParameter::internal_default_instance());
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+      SliceParameter_descriptor_, SliceParameter::internal_default_instance());
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+      SoftmaxParameter_descriptor_, SoftmaxParameter::internal_default_instance());
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+      TanHParameter_descriptor_, TanHParameter::internal_default_instance());
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+      ThresholdParameter_descriptor_, ThresholdParameter::internal_default_instance());
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+      WindowDataParameter_descriptor_, WindowDataParameter::internal_default_instance());
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+      SPPParameter_descriptor_, SPPParameter::internal_default_instance());
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+      V1LayerParameter_descriptor_, V1LayerParameter::internal_default_instance());
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+      V0LayerParameter_descriptor_, V0LayerParameter::internal_default_instance());
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+      PReLUParameter_descriptor_, PReLUParameter::internal_default_instance());
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+      NormalizedBBox_descriptor_, NormalizedBBox::internal_default_instance());
+}
+
+}  // namespace
+
+void protobuf_ShutdownFile_caffe_2eproto() {
+  BlobShape_default_instance_.Shutdown();
+  delete BlobShape_reflection_;
+  BlobProto_default_instance_.Shutdown();
+  delete BlobProto_reflection_;
+  BlobProtoVector_default_instance_.Shutdown();
+  delete BlobProtoVector_reflection_;
+  CropParameter_default_instance_.Shutdown();
+  delete CropParameter_reflection_;
+  PermuteParameter_default_instance_.Shutdown();
+  delete PermuteParameter_reflection_;
+  NormalizeBBoxParameter_default_instance_.Shutdown();
+  delete NormalizeBBoxParameter_reflection_;
+  PriorBoxParameter_default_instance_.Shutdown();
+  delete PriorBoxParameter_reflection_;
+  DetectionOutputParameter_default_instance_.Shutdown();
+  delete DetectionOutputParameter_reflection_;
+  Datum_default_instance_.Shutdown();
+  delete Datum_reflection_;
+  FillerParameter_default_instance_.Shutdown();
+  delete FillerParameter_reflection_;
+  delete FillerParameter::_default_type_;
+  NetParameter_default_instance_.Shutdown();
+  delete NetParameter_reflection_;
+  SolverParameter_default_instance_.Shutdown();
+  delete SolverParameter_reflection_;
+  delete SolverParameter::_default_regularization_type_;
+  SolverState_default_instance_.Shutdown();
+  delete SolverState_reflection_;
+  NetState_default_instance_.Shutdown();
+  delete NetState_reflection_;
+  NetStateRule_default_instance_.Shutdown();
+  delete NetStateRule_reflection_;
+  ParamSpec_default_instance_.Shutdown();
+  delete ParamSpec_reflection_;
+  LayerParameter_default_instance_.Shutdown();
+  delete LayerParameter_reflection_;
+  TransformationParameter_default_instance_.Shutdown();
+  delete TransformationParameter_reflection_;
+  LossParameter_default_instance_.Shutdown();
+  delete LossParameter_reflection_;
+  AccuracyParameter_default_instance_.Shutdown();
+  delete AccuracyParameter_reflection_;
+  ArgMaxParameter_default_instance_.Shutdown();
+  delete ArgMaxParameter_reflection_;
+  ConcatParameter_default_instance_.Shutdown();
+  delete ConcatParameter_reflection_;
+  ContrastiveLossParameter_default_instance_.Shutdown();
+  delete ContrastiveLossParameter_reflection_;
+  ConvolutionParameter_default_instance_.Shutdown();
+  delete ConvolutionParameter_reflection_;
+  DataParameter_default_instance_.Shutdown();
+  delete DataParameter_reflection_;
+  DropoutParameter_default_instance_.Shutdown();
+  delete DropoutParameter_reflection_;
+  DummyDataParameter_default_instance_.Shutdown();
+  delete DummyDataParameter_reflection_;
+  EltwiseParameter_default_instance_.Shutdown();
+  delete EltwiseParameter_reflection_;
+  ExpParameter_default_instance_.Shutdown();
+  delete ExpParameter_reflection_;
+  FlattenParameter_default_instance_.Shutdown();
+  delete FlattenParameter_reflection_;
+  HDF5DataParameter_default_instance_.Shutdown();
+  delete HDF5DataParameter_reflection_;
+  HDF5OutputParameter_default_instance_.Shutdown();
+  delete HDF5OutputParameter_reflection_;
+  HingeLossParameter_default_instance_.Shutdown();
+  delete HingeLossParameter_reflection_;
+  ImageDataParameter_default_instance_.Shutdown();
+  delete ImageDataParameter_reflection_;
+  InfogainLossParameter_default_instance_.Shutdown();
+  delete InfogainLossParameter_reflection_;
+  InnerProductParameter_default_instance_.Shutdown();
+  delete InnerProductParameter_reflection_;
+  LogParameter_default_instance_.Shutdown();
+  delete LogParameter_reflection_;
+  LRNParameter_default_instance_.Shutdown();
+  delete LRNParameter_reflection_;
+  MemoryDataParameter_default_instance_.Shutdown();
+  delete MemoryDataParameter_reflection_;
+  MVNParameter_default_instance_.Shutdown();
+  delete MVNParameter_reflection_;
+  PoolingParameter_default_instance_.Shutdown();
+  delete PoolingParameter_reflection_;
+  PowerParameter_default_instance_.Shutdown();
+  delete PowerParameter_reflection_;
+  PythonParameter_default_instance_.Shutdown();
+  delete PythonParameter_reflection_;
+  ReductionParameter_default_instance_.Shutdown();
+  delete ReductionParameter_reflection_;
+  ReLUParameter_default_instance_.Shutdown();
+  delete ReLUParameter_reflection_;
+  ReshapeParameter_default_instance_.Shutdown();
+  delete ReshapeParameter_reflection_;
+  SigmoidParameter_default_instance_.Shutdown();
+  delete SigmoidParameter_reflection_;
+  SliceParameter_default_instance_.Shutdown();
+  delete SliceParameter_reflection_;
+  SoftmaxParameter_default_instance_.Shutdown();
+  delete SoftmaxParameter_reflection_;
+  TanHParameter_default_instance_.Shutdown();
+  delete TanHParameter_reflection_;
+  ThresholdParameter_default_instance_.Shutdown();
+  delete ThresholdParameter_reflection_;
+  WindowDataParameter_default_instance_.Shutdown();
+  delete WindowDataParameter_reflection_;
+  delete WindowDataParameter::_default_crop_mode_;
+  SPPParameter_default_instance_.Shutdown();
+  delete SPPParameter_reflection_;
+  V1LayerParameter_default_instance_.Shutdown();
+  delete V1LayerParameter_reflection_;
+  V0LayerParameter_default_instance_.Shutdown();
+  delete V0LayerParameter_reflection_;
+  delete V0LayerParameter::_default_det_crop_mode_;
+  PReLUParameter_default_instance_.Shutdown();
+  delete PReLUParameter_reflection_;
+  NormalizedBBox_default_instance_.Shutdown();
+  delete NormalizedBBox_reflection_;
+}
+
+void protobuf_InitDefaults_caffe_2eproto_impl() {
+  GOOGLE_PROTOBUF_VERIFY_VERSION;
+
+  BlobShape_default_instance_.DefaultConstruct();
+  BlobProto_default_instance_.DefaultConstruct();
+  BlobProtoVector_default_instance_.DefaultConstruct();
+  CropParameter_default_instance_.DefaultConstruct();
+  PermuteParameter_default_instance_.DefaultConstruct();
+  NormalizeBBoxParameter_default_instance_.DefaultConstruct();
+  PriorBoxParameter_default_instance_.DefaultConstruct();
+  DetectionOutputParameter_default_instance_.DefaultConstruct();
+  ::google::protobuf::internal::GetEmptyString();
+  Datum_default_instance_.DefaultConstruct();
+  ::google::protobuf::internal::GetEmptyString();
+  FillerParameter::_default_type_ =
+      new ::std::string("constant", 8);
+  FillerParameter_default_instance_.DefaultConstruct();
+  ::google::protobuf::internal::GetEmptyString();
+  NetParameter_default_instance_.DefaultConstruct();
+  ::google::protobuf::internal::GetEmptyString();
+  SolverParameter::_default_regularization_type_ =
+      new ::std::string("L2", 2);
+  SolverParameter_default_instance_.DefaultConstruct();
+  ::google::protobuf::internal::GetEmptyString();
+  SolverState_default_instance_.DefaultConstruct();
+  ::google::protobuf::internal::GetEmptyString();
+  NetState_default_instance_.DefaultConstruct();
+  ::google::protobuf::internal::GetEmptyString();
+  NetStateRule_default_instance_.DefaultConstruct();
+  ::google::protobuf::internal::GetEmptyString();
+  ParamSpec_default_instance_.DefaultConstruct();
+  ::google::protobuf::internal::GetEmptyString();
+  LayerParameter_default_instance_.DefaultConstruct();
+  ::google::protobuf::internal::GetEmptyString();
+  TransformationParameter_default_instance_.DefaultConstruct();
+  LossParameter_default_instance_.DefaultConstruct();
+  AccuracyParameter_default_instance_.DefaultConstruct();
+  ArgMaxParameter_default_instance_.DefaultConstruct();
+  ConcatParameter_default_instance_.DefaultConstruct();
+  ContrastiveLossParameter_default_instance_.DefaultConstruct();
+  ConvolutionParameter_default_instance_.DefaultConstruct();
+  ::google::protobuf::internal::GetEmptyString();
+  DataParameter_default_instance_.DefaultConstruct();
+  DropoutParameter_default_instance_.DefaultConstruct();
+  DummyDataParameter_default_instance_.DefaultConstruct();
+  EltwiseParameter_default_instance_.DefaultConstruct();
+  ExpParameter_default_instance_.DefaultConstruct();
+  FlattenParameter_default_instance_.DefaultConstruct();
+  ::google::protobuf::internal::GetEmptyString();
+  HDF5DataParameter_default_instance_.DefaultConstruct();
+  ::google::protobuf::internal::GetEmptyString();
+  HDF5OutputParameter_default_instance_.DefaultConstruct();
+  HingeLossParameter_default_instance_.DefaultConstruct();
+  ::google::protobuf::internal::GetEmptyString();
+  ImageDataParameter_default_instance_.DefaultConstruct();
+  ::google::protobuf::internal::GetEmptyString();
+  InfogainLossParameter_default_instance_.DefaultConstruct();
+  InnerProductParameter_default_instance_.DefaultConstruct();
+  LogParameter_default_instance_.DefaultConstruct();
+  LRNParameter_default_instance_.DefaultConstruct();
+  MemoryDataParameter_default_instance_.DefaultConstruct();
+  MVNParameter_default_instance_.DefaultConstruct();
+  PoolingParameter_default_instance_.DefaultConstruct();
+  PowerParameter_default_instance_.DefaultConstruct();
+  ::google::protobuf::internal::GetEmptyString();
+  PythonParameter_default_instance_.DefaultConstruct();
+  ReductionParameter_default_instance_.DefaultConstruct();
+  ReLUParameter_default_instance_.DefaultConstruct();
+  ReshapeParameter_default_instance_.DefaultConstruct();
+  SigmoidParameter_default_instance_.DefaultConstruct();
+  SliceParameter_default_instance_.DefaultConstruct();
+  SoftmaxParameter_default_instance_.DefaultConstruct();
+  TanHParameter_default_instance_.DefaultConstruct();
+  ThresholdParameter_default_instance_.DefaultConstruct();
+  ::google::protobuf::internal::GetEmptyString();
+  WindowDataParameter::_default_crop_mode_ =
+      new ::std::string("warp", 4);
+  WindowDataParameter_default_instance_.DefaultConstruct();
+  SPPParameter_default_instance_.DefaultConstruct();
+  ::google::protobuf::internal::GetEmptyString();
+  V1LayerParameter_default_instance_.DefaultConstruct();
+  ::google::protobuf::internal::GetEmptyString();
+  V0LayerParameter::_default_det_crop_mode_ =
+      new ::std::string("warp", 4);
+  V0LayerParameter_default_instance_.DefaultConstruct();
+  PReLUParameter_default_instance_.DefaultConstruct();
+  NormalizedBBox_default_instance_.DefaultConstruct();
+  BlobShape_default_instance_.get_mutable()->InitAsDefaultInstance();
+  BlobProto_default_instance_.get_mutable()->InitAsDefaultInstance();
+  BlobProtoVector_default_instance_.get_mutable()->InitAsDefaultInstance();
+  CropParameter_default_instance_.get_mutable()->InitAsDefaultInstance();
+  PermuteParameter_default_instance_.get_mutable()->InitAsDefaultInstance();
+  NormalizeBBoxParameter_default_instance_.get_mutable()->InitAsDefaultInstance();
+  PriorBoxParameter_default_instance_.get_mutable()->InitAsDefaultInstance();
+  DetectionOutputParameter_default_instance_.get_mutable()->InitAsDefaultInstance();
+  Datum_default_instance_.get_mutable()->InitAsDefaultInstance();
+  FillerParameter_default_instance_.get_mutable()->InitAsDefaultInstance();
+  NetParameter_default_instance_.get_mutable()->InitAsDefaultInstance();
+  SolverParameter_default_instance_.get_mutable()->InitAsDefaultInstance();
+  SolverState_default_instance_.get_mutable()->InitAsDefaultInstance();
+  NetState_default_instance_.get_mutable()->InitAsDefaultInstance();
+  NetStateRule_default_instance_.get_mutable()->InitAsDefaultInstance();
+  ParamSpec_default_instance_.get_mutable()->InitAsDefaultInstance();
+  LayerParameter_default_instance_.get_mutable()->InitAsDefaultInstance();
+  TransformationParameter_default_instance_.get_mutable()->InitAsDefaultInstance();
+  LossParameter_default_instance_.get_mutable()->InitAsDefaultInstance();
+  AccuracyParameter_default_instance_.get_mutable()->InitAsDefaultInstance();
+  ArgMaxParameter_default_instance_.get_mutable()->InitAsDefaultInstance();
+  ConcatParameter_default_instance_.get_mutable()->InitAsDefaultInstance();
+  ContrastiveLossParameter_default_instance_.get_mutable()->InitAsDefaultInstance();
+  ConvolutionParameter_default_instance_.get_mutable()->InitAsDefaultInstance();
+  DataParameter_default_instance_.get_mutable()->InitAsDefaultInstance();
+  DropoutParameter_default_instance_.get_mutable()->InitAsDefaultInstance();
+  DummyDataParameter_default_instance_.get_mutable()->InitAsDefaultInstance();
+  EltwiseParameter_default_instance_.get_mutable()->InitAsDefaultInstance();
+  ExpParameter_default_instance_.get_mutable()->InitAsDefaultInstance();
+  FlattenParameter_default_instance_.get_mutable()->InitAsDefaultInstance();
+  HDF5DataParameter_default_instance_.get_mutable()->InitAsDefaultInstance();
+  HDF5OutputParameter_default_instance_.get_mutable()->InitAsDefaultInstance();
+  HingeLossParameter_default_instance_.get_mutable()->InitAsDefaultInstance();
+  ImageDataParameter_default_instance_.get_mutable()->InitAsDefaultInstance();
+  InfogainLossParameter_default_instance_.get_mutable()->InitAsDefaultInstance();
+  InnerProductParameter_default_instance_.get_mutable()->InitAsDefaultInstance();
+  LogParameter_default_instance_.get_mutable()->InitAsDefaultInstance();
+  LRNParameter_default_instance_.get_mutable()->InitAsDefaultInstance();
+  MemoryDataParameter_default_instance_.get_mutable()->InitAsDefaultInstance();
+  MVNParameter_default_instance_.get_mutable()->InitAsDefaultInstance();
+  PoolingParameter_default_instance_.get_mutable()->InitAsDefaultInstance();
+  PowerParameter_default_instance_.get_mutable()->InitAsDefaultInstance();
+  PythonParameter_default_instance_.get_mutable()->InitAsDefaultInstance();
+  ReductionParameter_default_instance_.get_mutable()->InitAsDefaultInstance();
+  ReLUParameter_default_instance_.get_mutable()->InitAsDefaultInstance();
+  ReshapeParameter_default_instance_.get_mutable()->InitAsDefaultInstance();
+  SigmoidParameter_default_instance_.get_mutable()->InitAsDefaultInstance();
+  SliceParameter_default_instance_.get_mutable()->InitAsDefaultInstance();
+  SoftmaxParameter_default_instance_.get_mutable()->InitAsDefaultInstance();
+  TanHParameter_default_instance_.get_mutable()->InitAsDefaultInstance();
+  ThresholdParameter_default_instance_.get_mutable()->InitAsDefaultInstance();
+  WindowDataParameter_default_instance_.get_mutable()->InitAsDefaultInstance();
+  SPPParameter_default_instance_.get_mutable()->InitAsDefaultInstance();
+  V1LayerParameter_default_instance_.get_mutable()->InitAsDefaultInstance();
+  V0LayerParameter_default_instance_.get_mutable()->InitAsDefaultInstance();
+  PReLUParameter_default_instance_.get_mutable()->InitAsDefaultInstance();
+  NormalizedBBox_default_instance_.get_mutable()->InitAsDefaultInstance();
+}
+
+GOOGLE_PROTOBUF_DECLARE_ONCE(protobuf_InitDefaults_caffe_2eproto_once_);
+void protobuf_InitDefaults_caffe_2eproto() {
+  ::google::protobuf::GoogleOnceInit(&protobuf_InitDefaults_caffe_2eproto_once_,
+                 &protobuf_InitDefaults_caffe_2eproto_impl);
+}
+void protobuf_AddDesc_caffe_2eproto_impl() {
+  GOOGLE_PROTOBUF_VERIFY_VERSION;
+
+  protobuf_InitDefaults_caffe_2eproto();
+  ::google::protobuf::DescriptorPool::InternalAddGeneratedFile(
+    "\n\013caffe.proto\022\005caffe\"\034\n\tBlobShape\022\017\n\003dim"
+    "\030\001 \003(\003B\002\020\001\"\232\001\n\tBlobProto\022\037\n\005shape\030\007 \001(\0132"
+    "\020.caffe.BlobShape\022\020\n\004data\030\005 \003(\002B\002\020\001\022\020\n\004d"
+    "iff\030\006 \003(\002B\002\020\001\022\016\n\003num\030\001 \001(\005:\0010\022\023\n\010channel"
+    "s\030\002 \001(\005:\0010\022\021\n\006height\030\003 \001(\005:\0010\022\020\n\005width\030\004"
+    " \001(\005:\0010\"2\n\017BlobProtoVector\022\037\n\005blobs\030\001 \003("
+    "\0132\020.caffe.BlobProto\"0\n\rCropParameter\022\017\n\004"
+    "axis\030\001 \001(\005:\0012\022\016\n\006offset\030\002 \003(\r\"!\n\020Permute"
+    "Parameter\022\r\n\005order\030\001 \003(\r\"\226\001\n\026NormalizeBB"
+    "oxParameter\022\034\n\016across_spatial\030\001 \001(\010:\004tru"
+    "e\022,\n\014scale_filler\030\002 \001(\0132\026.caffe.FillerPa"
+    "rameter\022\034\n\016channel_shared\030\003 \001(\010:\004true\022\022\n"
+    "\003eps\030\004 \001(\002:\0051e-10\"\260\001\n\021PriorBoxParameter\022"
+    "\020\n\010min_size\030\001 \001(\002\022\020\n\010max_size\030\002 \001(\002\022\024\n\014a"
+    "spect_ratio\030\003 \003(\002\022\022\n\004flip\030\004 \001(\010:\004true\022\022\n"
+    "\004clip\030\005 \001(\010:\004true\022\020\n\010variance\030\006 \003(\002\"\'\n\010C"
+    "odeType\022\n\n\006CORNER\020\001\022\017\n\013CENTER_SIZE\020\002\"\267\002\n"
+    "\030DetectionOutputParameter\022\023\n\013num_classes"
+    "\030\001 \001(\r\022\034\n\016share_location\030\002 \001(\010:\004true\022\036\n\023"
+    "background_label_id\030\003 \001(\005:\0010\022<\n\tcode_typ"
+    "e\030\006 \001(\0162!.caffe.PriorBoxParameter.CodeTy"
+    "pe:\006CORNER\022)\n\032variance_encoded_in_target"
+    "\030\010 \001(\010:\005false\022\026\n\nkeep_top_k\030\007 \001(\005:\002-1\022\034\n"
+    "\024confidence_threshold\030\t \001(\002\022\032\n\rnms_thres"
+    "hold\030\n \001(\002:\0030.3\022\r\n\005top_k\030\013 \001(\005\"\201\001\n\005Datum"
+    "\022\020\n\010channels\030\001 \001(\005\022\016\n\006height\030\002 \001(\005\022\r\n\005wi"
+    "dth\030\003 \001(\005\022\014\n\004data\030\004 \001(\014\022\r\n\005label\030\005 \001(\005\022\022"
+    "\n\nfloat_data\030\006 \003(\002\022\026\n\007encoded\030\007 \001(\010:\005fal"
+    "se\"\212\002\n\017FillerParameter\022\026\n\004type\030\001 \001(\t:\010co"
+    "nstant\022\020\n\005value\030\002 \001(\002:\0010\022\016\n\003min\030\003 \001(\002:\0010"
+    "\022\016\n\003max\030\004 \001(\002:\0011\022\017\n\004mean\030\005 \001(\002:\0010\022\016\n\003std"
+    "\030\006 \001(\002:\0011\022\022\n\006sparse\030\007 \001(\005:\002-1\022B\n\rvarianc"
+    "e_norm\030\010 \001(\0162#.caffe.FillerParameter.Var"
+    "ianceNorm:\006FAN_IN\"4\n\014VarianceNorm\022\n\n\006FAN"
+    "_IN\020\000\022\013\n\007FAN_OUT\020\001\022\013\n\007AVERAGE\020\002\"\216\002\n\014NetP"
+    "arameter\022\014\n\004name\030\001 \001(\t\022\r\n\005input\030\003 \003(\t\022%\n"
+    "\013input_shape\030\010 \003(\0132\020.caffe.BlobShape\022\021\n\t"
+    "input_dim\030\004 \003(\005\022\035\n\016force_backward\030\005 \001(\010:"
+    "\005false\022\036\n\005state\030\006 \001(\0132\017.caffe.NetState\022\031"
+    "\n\ndebug_info\030\007 \001(\010:\005false\022$\n\005layer\030d \003(\013"
+    "2\025.caffe.LayerParameter\022\'\n\006layers\030\002 \003(\0132"
+    "\027.caffe.V1LayerParameter\"\275\010\n\017SolverParam"
+    "eter\022\013\n\003net\030\030 \001(\t\022&\n\tnet_param\030\031 \001(\0132\023.c"
+    "affe.NetParameter\022\021\n\ttrain_net\030\001 \001(\t\022\020\n\010"
+    "test_net\030\002 \003(\t\022,\n\017train_net_param\030\025 \001(\0132"
+    "\023.caffe.NetParameter\022+\n\016test_net_param\030\026"
+    " \003(\0132\023.caffe.NetParameter\022$\n\013train_state"
+    "\030\032 \001(\0132\017.caffe.NetState\022#\n\ntest_state\030\033 "
+    "\003(\0132\017.caffe.NetState\022\021\n\ttest_iter\030\003 \003(\005\022"
+    "\030\n\rtest_interval\030\004 \001(\005:\0010\022 \n\021test_comput"
+    "e_loss\030\023 \001(\010:\005false\022!\n\023test_initializati"
+    "on\030  \001(\010:\004true\022\017\n\007base_lr\030\005 \001(\002\022\017\n\007displ"
+    "ay\030\006 \001(\005\022\027\n\014average_loss\030! \001(\005:\0011\022\020\n\010max"
+    "_iter\030\007 \001(\005\022\024\n\titer_size\030$ \001(\005:\0011\022\021\n\tlr_"
+    "policy\030\010 \001(\t\022\r\n\005gamma\030\t \001(\002\022\r\n\005power\030\n \001"
+    "(\002\022\020\n\010momentum\030\013 \001(\002\022\024\n\014weight_decay\030\014 \001"
+    "(\002\022\037\n\023regularization_type\030\035 \001(\t:\002L2\022\020\n\010s"
+    "tepsize\030\r \001(\005\022\021\n\tstepvalue\030\" \003(\005\022\032\n\016clip"
+    "_gradients\030# \001(\002:\002-1\022\023\n\010snapshot\030\016 \001(\005:\001"
+    "0\022\027\n\017snapshot_prefix\030\017 \001(\t\022\034\n\rsnapshot_d"
+    "iff\030\020 \001(\010:\005false\022;\n\013solver_mode\030\021 \001(\0162!."
+    "caffe.SolverParameter.SolverMode:\003GPU\022\024\n"
+    "\tdevice_id\030\022 \001(\005:\0010\022\027\n\013random_seed\030\024 \001(\003"
+    ":\002-1\022;\n\013solver_type\030\036 \001(\0162!.caffe.Solver"
+    "Parameter.SolverType:\003SGD\022\024\n\005delta\030\037 \001(\002"
+    ":\0051e-08\022\031\n\ndebug_info\030\027 \001(\010:\005false\022\"\n\024sn"
+    "apshot_after_train\030\034 \001(\010:\004true\"\036\n\nSolver"
+    "Mode\022\007\n\003CPU\020\000\022\007\n\003GPU\020\001\"0\n\nSolverType\022\007\n\003"
+    "SGD\020\000\022\014\n\010NESTEROV\020\001\022\013\n\007ADAGRAD\020\002\"l\n\013Solv"
+    "erState\022\014\n\004iter\030\001 \001(\005\022\023\n\013learned_net\030\002 \001"
+    "(\t\022!\n\007history\030\003 \003(\0132\020.caffe.BlobProto\022\027\n"
+    "\014current_step\030\004 \001(\005:\0010\"N\n\010NetState\022!\n\005ph"
+    "ase\030\001 \001(\0162\014.caffe.Phase:\004TEST\022\020\n\005level\030\002"
+    " \001(\005:\0010\022\r\n\005stage\030\003 \003(\t\"s\n\014NetStateRule\022\033"
+    "\n\005phase\030\001 \001(\0162\014.caffe.Phase\022\021\n\tmin_level"
+    "\030\002 \001(\005\022\021\n\tmax_level\030\003 \001(\005\022\r\n\005stage\030\004 \003(\t"
+    "\022\021\n\tnot_stage\030\005 \003(\t\"\243\001\n\tParamSpec\022\014\n\004nam"
+    "e\030\001 \001(\t\0221\n\nshare_mode\030\002 \001(\0162\035.caffe.Para"
+    "mSpec.DimCheckMode\022\022\n\007lr_mult\030\003 \001(\002:\0011\022\025"
+    "\n\ndecay_mult\030\004 \001(\002:\0011\"*\n\014DimCheckMode\022\n\n"
+    "\006STRICT\020\000\022\016\n\nPERMISSIVE\020\001\"\301\022\n\016LayerParam"
+    "eter\022\014\n\004name\030\001 \001(\t\022\014\n\004type\030\002 \001(\t\022\016\n\006bott"
+    "om\030\003 \003(\t\022\013\n\003top\030\004 \003(\t\022\033\n\005phase\030\n \001(\0162\014.c"
+    "affe.Phase\022\023\n\013loss_weight\030\005 \003(\002\022\037\n\005param"
+    "\030\006 \003(\0132\020.caffe.ParamSpec\022\037\n\005blobs\030\007 \003(\0132"
+    "\020.caffe.BlobProto\022\026\n\016propagate_down\030\013 \003("
+    "\010\022$\n\007include\030\010 \003(\0132\023.caffe.NetStateRule\022"
+    "$\n\007exclude\030\t \003(\0132\023.caffe.NetStateRule\0227\n"
+    "\017transform_param\030d \001(\0132\036.caffe.Transform"
+    "ationParameter\022(\n\nloss_param\030e \001(\0132\024.caf"
+    "fe.LossParameter\0220\n\016accuracy_param\030f \001(\013"
+    "2\030.caffe.AccuracyParameter\022,\n\014argmax_par"
+    "am\030g \001(\0132\026.caffe.ArgMaxParameter\022,\n\014conc"
+    "at_param\030h \001(\0132\026.caffe.ConcatParameter\022\?"
+    "\n\026contrastive_loss_param\030i \001(\0132\037.caffe.C"
+    "ontrastiveLossParameter\0226\n\021convolution_p"
+    "aram\030j \001(\0132\033.caffe.ConvolutionParameter\022"
+    ")\n\ncrop_param\030\211\001 \001(\0132\024.caffe.CropParamet"
+    "er\022(\n\ndata_param\030k \001(\0132\024.caffe.DataParam"
+    "eter\022@\n\026detection_output_param\030\215\001 \001(\0132\037."
+    "caffe.DetectionOutputParameter\022.\n\rdropou"
+    "t_param\030l \001(\0132\027.caffe.DropoutParameter\0223"
+    "\n\020dummy_data_param\030m \001(\0132\031.caffe.DummyDa"
+    "taParameter\022.\n\reltwise_param\030n \001(\0132\027.caf"
+    "fe.EltwiseParameter\022&\n\texp_param\030o \001(\0132\023"
+    ".caffe.ExpParameter\022/\n\rflatten_param\030\207\001 "
+    "\001(\0132\027.caffe.FlattenParameter\0221\n\017hdf5_dat"
+    "a_param\030p \001(\0132\030.caffe.HDF5DataParameter\022"
+    "5\n\021hdf5_output_param\030q \001(\0132\032.caffe.HDF5O"
+    "utputParameter\0223\n\020hinge_loss_param\030r \001(\013"
+    "2\031.caffe.HingeLossParameter\0223\n\020image_dat"
+    "a_param\030s \001(\0132\031.caffe.ImageDataParameter"
+    "\0229\n\023infogain_loss_param\030t \001(\0132\034.caffe.In"
+    "fogainLossParameter\0229\n\023inner_product_par"
+    "am\030u \001(\0132\034.caffe.InnerProductParameter\022\'"
+    "\n\tlog_param\030\206\001 \001(\0132\023.caffe.LogParameter\022"
+    "&\n\tlrn_param\030v \001(\0132\023.caffe.LRNParameter\022"
+    "5\n\021memory_data_param\030w \001(\0132\032.caffe.Memor"
+    "yDataParameter\022&\n\tmvn_param\030x \001(\0132\023.caff"
+    "e.MVNParameter\022<\n\024normalize_bbox_param\030\213"
+    "\001 \001(\0132\035.caffe.NormalizeBBoxParameter\022/\n\r"
+    "permute_param\030\212\001 \001(\0132\027.caffe.PermutePara"
+    "meter\022.\n\rpooling_param\030y \001(\0132\027.caffe.Poo"
+    "lingParameter\022*\n\013power_param\030z \001(\0132\025.caf"
+    "fe.PowerParameter\022+\n\013prelu_param\030\203\001 \001(\0132"
+    "\025.caffe.PReLUParameter\0222\n\017prior_box_para"
+    "m\030\214\001 \001(\0132\030.caffe.PriorBoxParameter\022-\n\014py"
+    "thon_param\030\202\001 \001(\0132\026.caffe.PythonParamete"
+    "r\0223\n\017reduction_param\030\210\001 \001(\0132\031.caffe.Redu"
+    "ctionParameter\022(\n\nrelu_param\030{ \001(\0132\024.caf"
+    "fe.ReLUParameter\022/\n\rreshape_param\030\205\001 \001(\013"
+    "2\027.caffe.ReshapeParameter\022.\n\rsigmoid_par"
+    "am\030| \001(\0132\027.caffe.SigmoidParameter\022*\n\013sli"
+    "ce_param\030~ \001(\0132\025.caffe.SliceParameter\022.\n"
+    "\rsoftmax_param\030} \001(\0132\027.caffe.SoftmaxPara"
+    "meter\022\'\n\tspp_param\030\204\001 \001(\0132\023.caffe.SPPPar"
+    "ameter\022(\n\ntanh_param\030\177 \001(\0132\024.caffe.TanHP"
+    "arameter\0223\n\017threshold_param\030\200\001 \001(\0132\031.caf"
+    "fe.ThresholdParameter\0226\n\021window_data_par"
+    "am\030\201\001 \001(\0132\032.caffe.WindowDataParameter\"\266\001"
+    "\n\027TransformationParameter\022\020\n\005scale\030\001 \001(\002"
+    ":\0011\022\025\n\006mirror\030\002 \001(\010:\005false\022\024\n\tcrop_size\030"
+    "\003 \001(\r:\0010\022\021\n\tmean_file\030\004 \001(\t\022\022\n\nmean_valu"
+    "e\030\005 \003(\002\022\032\n\013force_color\030\006 \001(\010:\005false\022\031\n\nf"
+    "orce_gray\030\007 \001(\010:\005false\">\n\rLossParameter\022"
+    "\024\n\014ignore_label\030\001 \001(\005\022\027\n\tnormalize\030\002 \001(\010"
+    ":\004true\"L\n\021AccuracyParameter\022\020\n\005top_k\030\001 \001"
+    "(\r:\0011\022\017\n\004axis\030\002 \001(\005:\0011\022\024\n\014ignore_label\030\003"
+    " \001(\005\"\?\n\017ArgMaxParameter\022\032\n\013out_max_val\030\001"
+    " \001(\010:\005false\022\020\n\005top_k\030\002 \001(\r:\0011\"9\n\017ConcatP"
+    "arameter\022\017\n\004axis\030\002 \001(\005:\0011\022\025\n\nconcat_dim\030"
+    "\001 \001(\r:\0011\"L\n\030ContrastiveLossParameter\022\021\n\006"
+    "margin\030\001 \001(\002:\0011\022\035\n\016legacy_version\030\002 \001(\010:"
+    "\005false\"\371\003\n\024ConvolutionParameter\022\022\n\nnum_o"
+    "utput\030\001 \001(\r\022\027\n\tbias_term\030\002 \001(\010:\004true\022\016\n\003"
+    "pad\030\003 \001(\r:\0010\022\020\n\005pad_h\030\t \001(\r:\0010\022\020\n\005pad_w\030"
+    "\n \001(\r:\0010\022\023\n\013kernel_size\030\004 \001(\r\022\020\n\010kernel_"
+    "h\030\013 \001(\r\022\020\n\010kernel_w\030\014 \001(\r\022\020\n\005group\030\005 \001(\r"
+    ":\0011\022\021\n\006stride\030\006 \001(\r:\0011\022\020\n\010stride_h\030\r \001(\r"
+    "\022\020\n\010stride_w\030\016 \001(\r\022-\n\rweight_filler\030\007 \001("
+    "\0132\026.caffe.FillerParameter\022+\n\013bias_filler"
+    "\030\010 \001(\0132\026.caffe.FillerParameter\022;\n\006engine"
+    "\030\017 \001(\0162\".caffe.ConvolutionParameter.Engi"
+    "ne:\007DEFAULT\022\022\n\ndilation_h\030\022 \001(\r\022\022\n\ndilat"
+    "ion_w\030\023 \001(\r\022\020\n\010dilation\030\024 \001(\r\"+\n\006Engine\022"
+    "\013\n\007DEFAULT\020\000\022\t\n\005CAFFE\020\001\022\t\n\005CUDNN\020\002\"\217\002\n\rD"
+    "ataParameter\022\016\n\006source\030\001 \001(\t\022\022\n\nbatch_si"
+    "ze\030\004 \001(\r\022\024\n\trand_skip\030\007 \001(\r:\0010\0221\n\007backen"
+    "d\030\010 \001(\0162\027.caffe.DataParameter.DB:\007LEVELD"
+    "B\022\020\n\005scale\030\002 \001(\002:\0011\022\021\n\tmean_file\030\003 \001(\t\022\024"
+    "\n\tcrop_size\030\005 \001(\r:\0010\022\025\n\006mirror\030\006 \001(\010:\005fa"
+    "lse\022\"\n\023force_encoded_color\030\t \001(\010:\005false\""
+    "\033\n\002DB\022\013\n\007LEVELDB\020\000\022\010\n\004LMDB\020\001\".\n\020DropoutP"
+    "arameter\022\032\n\rdropout_ratio\030\001 \001(\002:\0030.5\"\240\001\n"
+    "\022DummyDataParameter\022+\n\013data_filler\030\001 \003(\013"
+    "2\026.caffe.FillerParameter\022\037\n\005shape\030\006 \003(\0132"
+    "\020.caffe.BlobShape\022\013\n\003num\030\002 \003(\r\022\020\n\010channe"
+    "ls\030\003 \003(\r\022\016\n\006height\030\004 \003(\r\022\r\n\005width\030\005 \003(\r\""
+    "\245\001\n\020EltwiseParameter\0229\n\toperation\030\001 \001(\0162"
+    "!.caffe.EltwiseParameter.EltwiseOp:\003SUM\022"
+    "\r\n\005coeff\030\002 \003(\002\022\036\n\020stable_prod_grad\030\003 \001(\010"
+    ":\004true\"\'\n\tEltwiseOp\022\010\n\004PROD\020\000\022\007\n\003SUM\020\001\022\007"
+    "\n\003MAX\020\002\"D\n\014ExpParameter\022\020\n\004base\030\001 \001(\002:\002-"
+    "1\022\020\n\005scale\030\002 \001(\002:\0011\022\020\n\005shift\030\003 \001(\002:\0010\"9\n"
+    "\020FlattenParameter\022\017\n\004axis\030\001 \001(\005:\0011\022\024\n\010en"
+    "d_axis\030\002 \001(\005:\002-1\"O\n\021HDF5DataParameter\022\016\n"
+    "\006source\030\001 \001(\t\022\022\n\nbatch_size\030\002 \001(\r\022\026\n\007shu"
+    "ffle\030\003 \001(\010:\005false\"(\n\023HDF5OutputParameter"
+    "\022\021\n\tfile_name\030\001 \001(\t\"^\n\022HingeLossParamete"
+    "r\0220\n\004norm\030\001 \001(\0162\036.caffe.HingeLossParamet"
+    "er.Norm:\002L1\"\026\n\004Norm\022\006\n\002L1\020\001\022\006\n\002L2\020\002\"\224\002\n\022"
+    "ImageDataParameter\022\016\n\006source\030\001 \001(\t\022\022\n\nba"
+    "tch_size\030\004 \001(\r\022\024\n\trand_skip\030\007 \001(\r:\0010\022\026\n\007"
+    "shuffle\030\010 \001(\010:\005false\022\025\n\nnew_height\030\t \001(\r"
+    ":\0010\022\024\n\tnew_width\030\n \001(\r:\0010\022\026\n\010is_color\030\013 "
+    "\001(\010:\004true\022\020\n\005scale\030\002 \001(\002:\0011\022\021\n\tmean_file"
+    "\030\003 \001(\t\022\024\n\tcrop_size\030\005 \001(\r:\0010\022\025\n\006mirror\030\006"
+    " \001(\010:\005false\022\025\n\013root_folder\030\014 \001(\t:\000\"\'\n\025In"
+    "fogainLossParameter\022\016\n\006source\030\001 \001(\t\"\261\001\n\025"
+    "InnerProductParameter\022\022\n\nnum_output\030\001 \001("
+    "\r\022\027\n\tbias_term\030\002 \001(\010:\004true\022-\n\rweight_fil"
+    "ler\030\003 \001(\0132\026.caffe.FillerParameter\022+\n\013bia"
+    "s_filler\030\004 \001(\0132\026.caffe.FillerParameter\022\017"
+    "\n\004axis\030\005 \001(\005:\0011\"D\n\014LogParameter\022\020\n\004base\030"
+    "\001 \001(\002:\002-1\022\020\n\005scale\030\002 \001(\002:\0011\022\020\n\005shift\030\003 \001"
+    "(\002:\0010\"\326\001\n\014LRNParameter\022\025\n\nlocal_size\030\001 \001"
+    "(\r:\0015\022\020\n\005alpha\030\002 \001(\002:\0011\022\022\n\004beta\030\003 \001(\002:\0040"
+    ".75\022D\n\013norm_region\030\004 \001(\0162\036.caffe.LRNPara"
+    "meter.NormRegion:\017ACROSS_CHANNELS\022\014\n\001k\030\005"
+    " \001(\002:\0011\"5\n\nNormRegion\022\023\n\017ACROSS_CHANNELS"
+    "\020\000\022\022\n\016WITHIN_CHANNEL\020\001\"Z\n\023MemoryDataPara"
+    "meter\022\022\n\nbatch_size\030\001 \001(\r\022\020\n\010channels\030\002 "
+    "\001(\r\022\016\n\006height\030\003 \001(\r\022\r\n\005width\030\004 \001(\r\"d\n\014MV"
+    "NParameter\022 \n\022normalize_variance\030\001 \001(\010:\004"
+    "true\022\036\n\017across_channels\030\002 \001(\010:\005false\022\022\n\003"
+    "eps\030\003 \001(\002:\0051e-09\"\242\003\n\020PoolingParameter\0225\n"
+    "\004pool\030\001 \001(\0162\".caffe.PoolingParameter.Poo"
+    "lMethod:\003MAX\022\016\n\003pad\030\004 \001(\r:\0010\022\020\n\005pad_h\030\t "
+    "\001(\r:\0010\022\020\n\005pad_w\030\n \001(\r:\0010\022\023\n\013kernel_size\030"
+    "\002 \001(\r\022\020\n\010kernel_h\030\005 \001(\r\022\020\n\010kernel_w\030\006 \001("
+    "\r\022\021\n\006stride\030\003 \001(\r:\0011\022\020\n\010stride_h\030\007 \001(\r\022\020"
+    "\n\010stride_w\030\010 \001(\r\0227\n\006engine\030\013 \001(\0162\036.caffe"
+    ".PoolingParameter.Engine:\007DEFAULT\022\035\n\016glo"
+    "bal_pooling\030\014 \001(\010:\005false\".\n\nPoolMethod\022\007"
+    "\n\003MAX\020\000\022\007\n\003AVE\020\001\022\016\n\nSTOCHASTIC\020\002\"+\n\006Engi"
+    "ne\022\013\n\007DEFAULT\020\000\022\t\n\005CAFFE\020\001\022\t\n\005CUDNN\020\002\"F\n"
+    "\016PowerParameter\022\020\n\005power\030\001 \001(\002:\0011\022\020\n\005sca"
+    "le\030\002 \001(\002:\0011\022\020\n\005shift\030\003 \001(\002:\0010\"0\n\017PythonP"
+    "arameter\022\016\n\006module\030\001 \001(\t\022\r\n\005layer\030\002 \001(\t\""
+    "\255\001\n\022ReductionParameter\022=\n\toperation\030\001 \001("
+    "\0162%.caffe.ReductionParameter.ReductionOp"
+    ":\003SUM\022\017\n\004axis\030\002 \001(\005:\0010\022\020\n\005coeff\030\003 \001(\002:\0011"
+    "\"5\n\013ReductionOp\022\007\n\003SUM\020\001\022\010\n\004ASUM\020\002\022\t\n\005SU"
+    "MSQ\020\003\022\010\n\004MEAN\020\004\"\215\001\n\rReLUParameter\022\031\n\016neg"
+    "ative_slope\030\001 \001(\002:\0010\0224\n\006engine\030\002 \001(\0162\033.c"
+    "affe.ReLUParameter.Engine:\007DEFAULT\"+\n\006En"
+    "gine\022\013\n\007DEFAULT\020\000\022\t\n\005CAFFE\020\001\022\t\n\005CUDNN\020\002\""
+    "Z\n\020ReshapeParameter\022\037\n\005shape\030\001 \001(\0132\020.caf"
+    "fe.BlobShape\022\017\n\004axis\030\002 \001(\005:\0010\022\024\n\010num_axe"
+    "s\030\003 \001(\005:\002-1\"x\n\020SigmoidParameter\0227\n\006engin"
+    "e\030\001 \001(\0162\036.caffe.SigmoidParameter.Engine:"
+    "\007DEFAULT\"+\n\006Engine\022\013\n\007DEFAULT\020\000\022\t\n\005CAFFE"
+    "\020\001\022\t\n\005CUDNN\020\002\"L\n\016SliceParameter\022\017\n\004axis\030"
+    "\003 \001(\005:\0011\022\023\n\013slice_point\030\002 \003(\r\022\024\n\tslice_d"
+    "im\030\001 \001(\r:\0011\"\211\001\n\020SoftmaxParameter\0227\n\006engi"
+    "ne\030\001 \001(\0162\036.caffe.SoftmaxParameter.Engine"
+    ":\007DEFAULT\022\017\n\004axis\030\002 \001(\005:\0011\"+\n\006Engine\022\013\n\007"
+    "DEFAULT\020\000\022\t\n\005CAFFE\020\001\022\t\n\005CUDNN\020\002\"r\n\rTanHP"
+    "arameter\0224\n\006engine\030\001 \001(\0162\033.caffe.TanHPar"
+    "ameter.Engine:\007DEFAULT\"+\n\006Engine\022\013\n\007DEFA"
+    "ULT\020\000\022\t\n\005CAFFE\020\001\022\t\n\005CUDNN\020\002\"*\n\022Threshold"
+    "Parameter\022\024\n\tthreshold\030\001 \001(\002:\0010\"\301\002\n\023Wind"
+    "owDataParameter\022\016\n\006source\030\001 \001(\t\022\020\n\005scale"
+    "\030\002 \001(\002:\0011\022\021\n\tmean_file\030\003 \001(\t\022\022\n\nbatch_si"
+    "ze\030\004 \001(\r\022\024\n\tcrop_size\030\005 \001(\r:\0010\022\025\n\006mirror"
+    "\030\006 \001(\010:\005false\022\031\n\014fg_threshold\030\007 \001(\002:\0030.5"
+    "\022\031\n\014bg_threshold\030\010 \001(\002:\0030.5\022\031\n\013fg_fracti"
+    "on\030\t \001(\002:\0040.25\022\026\n\013context_pad\030\n \001(\r:\0010\022\027"
+    "\n\tcrop_mode\030\013 \001(\t:\004warp\022\033\n\014cache_images\030"
+    "\014 \001(\010:\005false\022\025\n\013root_folder\030\r \001(\t:\000\"\353\001\n\014"
+    "SPPParameter\022\026\n\016pyramid_height\030\001 \001(\r\0221\n\004"
+    "pool\030\002 \001(\0162\036.caffe.SPPParameter.PoolMeth"
+    "od:\003MAX\0223\n\006engine\030\006 \001(\0162\032.caffe.SPPParam"
+    "eter.Engine:\007DEFAULT\".\n\nPoolMethod\022\007\n\003MA"
+    "X\020\000\022\007\n\003AVE\020\001\022\016\n\nSTOCHASTIC\020\002\"+\n\006Engine\022\013"
+    "\n\007DEFAULT\020\000\022\t\n\005CAFFE\020\001\022\t\n\005CUDNN\020\002\"\340\023\n\020V1"
+    "LayerParameter\022\016\n\006bottom\030\002 \003(\t\022\013\n\003top\030\003 "
+    "\003(\t\022\014\n\004name\030\004 \001(\t\022$\n\007include\030  \003(\0132\023.caf"
+    "fe.NetStateRule\022$\n\007exclude\030! \003(\0132\023.caffe"
+    ".NetStateRule\022/\n\004type\030\005 \001(\0162!.caffe.V1La"
+    "yerParameter.LayerType\022\037\n\005blobs\030\006 \003(\0132\020."
+    "caffe.BlobProto\022\016\n\005param\030\351\007 \003(\t\022>\n\017blob_"
+    "share_mode\030\352\007 \003(\0162$.caffe.V1LayerParamet"
+    "er.DimCheckMode\022\020\n\010blobs_lr\030\007 \003(\002\022\024\n\014wei"
+    "ght_decay\030\010 \003(\002\022\023\n\013loss_weight\030# \003(\002\0220\n\016"
+    "accuracy_param\030\033 \001(\0132\030.caffe.AccuracyPar"
+    "ameter\022,\n\014argmax_param\030\027 \001(\0132\026.caffe.Arg"
+    "MaxParameter\022,\n\014concat_param\030\t \001(\0132\026.caf"
+    "fe.ConcatParameter\022\?\n\026contrastive_loss_p"
+    "aram\030( \001(\0132\037.caffe.ContrastiveLossParame"
+    "ter\0226\n\021convolution_param\030\n \001(\0132\033.caffe.C"
+    "onvolutionParameter\022(\n\ndata_param\030\013 \001(\0132"
+    "\024.caffe.DataParameter\022.\n\rdropout_param\030\014"
+    " \001(\0132\027.caffe.DropoutParameter\0223\n\020dummy_d"
+    "ata_param\030\032 \001(\0132\031.caffe.DummyDataParamet"
+    "er\022.\n\reltwise_param\030\030 \001(\0132\027.caffe.Eltwis"
+    "eParameter\022&\n\texp_param\030) \001(\0132\023.caffe.Ex"
+    "pParameter\0221\n\017hdf5_data_param\030\r \001(\0132\030.ca"
+    "ffe.HDF5DataParameter\0225\n\021hdf5_output_par"
+    "am\030\016 \001(\0132\032.caffe.HDF5OutputParameter\0223\n\020"
+    "hinge_loss_param\030\035 \001(\0132\031.caffe.HingeLoss"
+    "Parameter\0223\n\020image_data_param\030\017 \001(\0132\031.ca"
+    "ffe.ImageDataParameter\0229\n\023infogain_loss_"
+    "param\030\020 \001(\0132\034.caffe.InfogainLossParamete"
+    "r\0229\n\023inner_product_param\030\021 \001(\0132\034.caffe.I"
+    "nnerProductParameter\022&\n\tlrn_param\030\022 \001(\0132"
+    "\023.caffe.LRNParameter\0225\n\021memory_data_para"
+    "m\030\026 \001(\0132\032.caffe.MemoryDataParameter\022&\n\tm"
+    "vn_param\030\" \001(\0132\023.caffe.MVNParameter\022.\n\rp"
+    "ooling_param\030\023 \001(\0132\027.caffe.PoolingParame"
+    "ter\022*\n\013power_param\030\025 \001(\0132\025.caffe.PowerPa"
+    "rameter\022(\n\nrelu_param\030\036 \001(\0132\024.caffe.ReLU"
+    "Parameter\022.\n\rsigmoid_param\030& \001(\0132\027.caffe"
+    ".SigmoidParameter\022.\n\rsoftmax_param\030\' \001(\013"
+    "2\027.caffe.SoftmaxParameter\022*\n\013slice_param"
+    "\030\037 \001(\0132\025.caffe.SliceParameter\022(\n\ntanh_pa"
+    "ram\030% \001(\0132\024.caffe.TanHParameter\0222\n\017thres"
+    "hold_param\030\031 \001(\0132\031.caffe.ThresholdParame"
+    "ter\0225\n\021window_data_param\030\024 \001(\0132\032.caffe.W"
+    "indowDataParameter\0227\n\017transform_param\030$ "
+    "\001(\0132\036.caffe.TransformationParameter\022(\n\nl"
+    "oss_param\030* \001(\0132\024.caffe.LossParameter\022&\n"
+    "\005layer\030\001 \001(\0132\027.caffe.V0LayerParameter\"\330\004"
+    "\n\tLayerType\022\010\n\004NONE\020\000\022\n\n\006ABSVAL\020#\022\014\n\010ACC"
+    "URACY\020\001\022\n\n\006ARGMAX\020\036\022\010\n\004BNLL\020\002\022\n\n\006CONCAT\020"
+    "\003\022\024\n\020CONTRASTIVE_LOSS\020%\022\017\n\013CONVOLUTION\020\004"
+    "\022\010\n\004DATA\020\005\022\021\n\rDECONVOLUTION\020\'\022\013\n\007DROPOUT"
+    "\020\006\022\016\n\nDUMMY_DATA\020 \022\022\n\016EUCLIDEAN_LOSS\020\007\022\013"
+    "\n\007ELTWISE\020\031\022\007\n\003EXP\020&\022\013\n\007FLATTEN\020\010\022\r\n\tHDF"
+    "5_DATA\020\t\022\017\n\013HDF5_OUTPUT\020\n\022\016\n\nHINGE_LOSS\020"
+    "\034\022\n\n\006IM2COL\020\013\022\016\n\nIMAGE_DATA\020\014\022\021\n\rINFOGAI"
+    "N_LOSS\020\r\022\021\n\rINNER_PRODUCT\020\016\022\007\n\003LRN\020\017\022\017\n\013"
+    "MEMORY_DATA\020\035\022\035\n\031MULTINOMIAL_LOGISTIC_LO"
+    "SS\020\020\022\007\n\003MVN\020\"\022\013\n\007POOLING\020\021\022\t\n\005POWER\020\032\022\010\n"
+    "\004RELU\020\022\022\013\n\007SIGMOID\020\023\022\036\n\032SIGMOID_CROSS_EN"
+    "TROPY_LOSS\020\033\022\013\n\007SILENCE\020$\022\013\n\007SOFTMAX\020\024\022\020"
+    "\n\014SOFTMAX_LOSS\020\025\022\t\n\005SPLIT\020\026\022\t\n\005SLICE\020!\022\010"
+    "\n\004TANH\020\027\022\017\n\013WINDOW_DATA\020\030\022\r\n\tTHRESHOLD\020\037"
+    "\"*\n\014DimCheckMode\022\n\n\006STRICT\020\000\022\016\n\nPERMISSI"
+    "VE\020\001\"\375\007\n\020V0LayerParameter\022\014\n\004name\030\001 \001(\t\022"
+    "\014\n\004type\030\002 \001(\t\022\022\n\nnum_output\030\003 \001(\r\022\026\n\010bia"
+    "sterm\030\004 \001(\010:\004true\022-\n\rweight_filler\030\005 \001(\013"
+    "2\026.caffe.FillerParameter\022+\n\013bias_filler\030"
+    "\006 \001(\0132\026.caffe.FillerParameter\022\016\n\003pad\030\007 \001"
+    "(\r:\0010\022\022\n\nkernelsize\030\010 \001(\r\022\020\n\005group\030\t \001(\r"
+    ":\0011\022\021\n\006stride\030\n \001(\r:\0011\0225\n\004pool\030\013 \001(\0162\".c"
+    "affe.V0LayerParameter.PoolMethod:\003MAX\022\032\n"
+    "\rdropout_ratio\030\014 \001(\002:\0030.5\022\025\n\nlocal_size\030"
+    "\r \001(\r:\0015\022\020\n\005alpha\030\016 \001(\002:\0011\022\022\n\004beta\030\017 \001(\002"
+    ":\0040.75\022\014\n\001k\030\026 \001(\002:\0011\022\016\n\006source\030\020 \001(\t\022\020\n\005"
+    "scale\030\021 \001(\002:\0011\022\020\n\010meanfile\030\022 \001(\t\022\021\n\tbatc"
+    "hsize\030\023 \001(\r\022\023\n\010cropsize\030\024 \001(\r:\0010\022\025\n\006mirr"
+    "or\030\025 \001(\010:\005false\022\037\n\005blobs\0302 \003(\0132\020.caffe.B"
+    "lobProto\022\020\n\010blobs_lr\0303 \003(\002\022\024\n\014weight_dec"
+    "ay\0304 \003(\002\022\024\n\trand_skip\0305 \001(\r:\0010\022\035\n\020det_fg"
+    "_threshold\0306 \001(\002:\0030.5\022\035\n\020det_bg_threshol"
+    "d\0307 \001(\002:\0030.5\022\035\n\017det_fg_fraction\0308 \001(\002:\0040"
+    ".25\022\032\n\017det_context_pad\030: \001(\r:\0010\022\033\n\rdet_c"
+    "rop_mode\030; \001(\t:\004warp\022\022\n\007new_num\030< \001(\005:\0010"
+    "\022\027\n\014new_channels\030= \001(\005:\0010\022\025\n\nnew_height\030"
+    "> \001(\005:\0010\022\024\n\tnew_width\030\? \001(\005:\0010\022\035\n\016shuffl"
+    "e_images\030@ \001(\010:\005false\022\025\n\nconcat_dim\030A \001("
+    "\r:\0011\0226\n\021hdf5_output_param\030\351\007 \001(\0132\032.caffe"
+    ".HDF5OutputParameter\".\n\nPoolMethod\022\007\n\003MA"
+    "X\020\000\022\007\n\003AVE\020\001\022\016\n\nSTOCHASTIC\020\002\"W\n\016PReLUPar"
+    "ameter\022&\n\006filler\030\001 \001(\0132\026.caffe.FillerPar"
+    "ameter\022\035\n\016channel_shared\030\002 \001(\010:\005false\"\207\001"
+    "\n\016NormalizedBBox\022\014\n\004xmin\030\001 \001(\002\022\014\n\004ymin\030\002"
+    " \001(\002\022\014\n\004xmax\030\003 \001(\002\022\014\n\004ymax\030\004 \001(\002\022\r\n\005labe"
+    "l\030\005 \001(\005\022\021\n\tdifficult\030\006 \001(\010\022\r\n\005score\030\007 \001("
+    "\002\022\014\n\004size\030\010 \001(\002*\034\n\005Phase\022\t\n\005TRAIN\020\000\022\010\n\004T"
+    "EST\020\001", 14445);
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedFile(
+    "caffe.proto", &protobuf_RegisterTypes);
+  ::google::protobuf::internal::OnShutdown(&protobuf_ShutdownFile_caffe_2eproto);
+}
+
+GOOGLE_PROTOBUF_DECLARE_ONCE(protobuf_AddDesc_caffe_2eproto_once_);
+void protobuf_AddDesc_caffe_2eproto() {
+  ::google::protobuf::GoogleOnceInit(&protobuf_AddDesc_caffe_2eproto_once_,
+                 &protobuf_AddDesc_caffe_2eproto_impl);
+}
+// Force AddDescriptors() to be called at static initialization time.
+struct StaticDescriptorInitializer_caffe_2eproto {
+  StaticDescriptorInitializer_caffe_2eproto() {
+    protobuf_AddDesc_caffe_2eproto();
+  }
+} static_descriptor_initializer_caffe_2eproto_;
+const ::google::protobuf::EnumDescriptor* Phase_descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return Phase_descriptor_;
+}
+bool Phase_IsValid(int value) {
+  switch (value) {
+    case 0:
+    case 1:
+      return true;
+    default:
+      return false;
+  }
+}
+
+
+namespace {
+
+static void MergeFromFail(int line) GOOGLE_ATTRIBUTE_COLD GOOGLE_ATTRIBUTE_NORETURN;
+static void MergeFromFail(int line) {
+  ::google::protobuf::internal::MergeFromFail(__FILE__, line);
+}
+
+}  // namespace
+
+
+// ===================================================================
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const int BlobShape::kDimFieldNumber;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+
+BlobShape::BlobShape()
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+  if (this != internal_default_instance()) protobuf_InitDefaults_caffe_2eproto();
+  SharedCtor();
+  // @@protoc_insertion_point(constructor:caffe.BlobShape)
+}
+
+void BlobShape::InitAsDefaultInstance() {
+}
+
+BlobShape::BlobShape(const BlobShape& from)
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
+  SharedCtor();
+  UnsafeMergeFrom(from);
+  // @@protoc_insertion_point(copy_constructor:caffe.BlobShape)
+}
+
+void BlobShape::SharedCtor() {
+  _cached_size_ = 0;
+}
+
+BlobShape::~BlobShape() {
+  // @@protoc_insertion_point(destructor:caffe.BlobShape)
+  SharedDtor();
+}
+
+void BlobShape::SharedDtor() {
+}
+
+void BlobShape::SetCachedSize(int size) const {
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* BlobShape::descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return BlobShape_descriptor_;
+}
+
+const BlobShape& BlobShape::default_instance() {
+  protobuf_InitDefaults_caffe_2eproto();
+  return *internal_default_instance();
+}
+
+::google::protobuf::internal::ExplicitlyConstructed<BlobShape> BlobShape_default_instance_;
+
+BlobShape* BlobShape::New(::google::protobuf::Arena* arena) const {
+  BlobShape* n = new BlobShape;
+  if (arena != NULL) {
+    arena->Own(n);
+  }
+  return n;
+}
+
+void BlobShape::Clear() {
+// @@protoc_insertion_point(message_clear_start:caffe.BlobShape)
+  dim_.Clear();
+  _has_bits_.Clear();
+  if (_internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->Clear();
+  }
+}
+
+bool BlobShape::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
+  ::google::protobuf::uint32 tag;
+  // @@protoc_insertion_point(parse_start:caffe.BlobShape)
+  for (;;) {
+    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+    tag = p.first;
+    if (!p.second) goto handle_unusual;
+    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+      // repeated int64 dim = 1 [packed = true];
+      case 1: {
+        if (tag == 10) {
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPackedPrimitive<
+                   ::google::protobuf::int64, ::google::protobuf::internal::WireFormatLite::TYPE_INT64>(
+                 input, this->mutable_dim())));
+        } else if (tag == 8) {
+          DO_((::google::protobuf::internal::WireFormatLite::ReadRepeatedPrimitiveNoInline<
+                   ::google::protobuf::int64, ::google::protobuf::internal::WireFormatLite::TYPE_INT64>(
+                 1, 10, input, this->mutable_dim())));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectAtEnd()) goto success;
+        break;
+      }
+
+      default: {
+      handle_unusual:
+        if (tag == 0 ||
+            ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+          goto success;
+        }
+        DO_(::google::protobuf::internal::WireFormat::SkipField(
+              input, tag, mutable_unknown_fields()));
+        break;
+      }
+    }
+  }
+success:
+  // @@protoc_insertion_point(parse_success:caffe.BlobShape)
+  return true;
+failure:
+  // @@protoc_insertion_point(parse_failure:caffe.BlobShape)
+  return false;
+#undef DO_
+}
+
+void BlobShape::SerializeWithCachedSizes(
+    ::google::protobuf::io::CodedOutputStream* output) const {
+  // @@protoc_insertion_point(serialize_start:caffe.BlobShape)
+  // repeated int64 dim = 1 [packed = true];
+  if (this->dim_size() > 0) {
+    ::google::protobuf::internal::WireFormatLite::WriteTag(1, ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED, output);
+    output->WriteVarint32(_dim_cached_byte_size_);
+  }
+  for (int i = 0; i < this->dim_size(); i++) {
+    ::google::protobuf::internal::WireFormatLite::WriteInt64NoTag(
+      this->dim(i), output);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
+        unknown_fields(), output);
+  }
+  // @@protoc_insertion_point(serialize_end:caffe.BlobShape)
+}
+
+::google::protobuf::uint8* BlobShape::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
+  (void)deterministic; // Unused
+  // @@protoc_insertion_point(serialize_to_array_start:caffe.BlobShape)
+  // repeated int64 dim = 1 [packed = true];
+  if (this->dim_size() > 0) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteTagToArray(
+      1,
+      ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED,
+      target);
+    target = ::google::protobuf::io::CodedOutputStream::WriteVarint32ToArray(
+      _dim_cached_byte_size_, target);
+  }
+  for (int i = 0; i < this->dim_size(); i++) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      WriteInt64NoTagToArray(this->dim(i), target);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
+        unknown_fields(), target);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:caffe.BlobShape)
+  return target;
+}
+
+size_t BlobShape::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:caffe.BlobShape)
+  size_t total_size = 0;
+
+  // repeated int64 dim = 1 [packed = true];
+  {
+    size_t data_size = 0;
+    unsigned int count = this->dim_size();
+    for (unsigned int i = 0; i < count; i++) {
+      data_size += ::google::protobuf::internal::WireFormatLite::
+        Int64Size(this->dim(i));
+    }
+    if (data_size > 0) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::Int32Size(data_size);
+    }
+    int cached_size = ::google::protobuf::internal::ToCachedSize(data_size);
+    GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+    _dim_cached_byte_size_ = cached_size;
+    GOOGLE_SAFE_CONCURRENT_WRITES_END();
+    total_size += data_size;
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    total_size +=
+      ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
+        unknown_fields());
+  }
+  int cached_size = ::google::protobuf::internal::ToCachedSize(total_size);
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = cached_size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+  return total_size;
+}
+
+void BlobShape::MergeFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_merge_from_start:caffe.BlobShape)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const BlobShape* source =
+      ::google::protobuf::internal::DynamicCastToGenerated<const BlobShape>(
+          &from);
+  if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:caffe.BlobShape)
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:caffe.BlobShape)
+    UnsafeMergeFrom(*source);
+  }
+}
+
+void BlobShape::MergeFrom(const BlobShape& from) {
+// @@protoc_insertion_point(class_specific_merge_from_start:caffe.BlobShape)
+  if (GOOGLE_PREDICT_TRUE(&from != this)) {
+    UnsafeMergeFrom(from);
+  } else {
+    MergeFromFail(__LINE__);
+  }
+}
+
+void BlobShape::UnsafeMergeFrom(const BlobShape& from) {
+  GOOGLE_DCHECK(&from != this);
+  dim_.UnsafeMergeFrom(from.dim_);
+  if (from._internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::UnknownFieldSet::MergeToInternalMetdata(
+      from.unknown_fields(), &_internal_metadata_);
+  }
+}
+
+void BlobShape::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:caffe.BlobShape)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void BlobShape::CopyFrom(const BlobShape& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:caffe.BlobShape)
+  if (&from == this) return;
+  Clear();
+  UnsafeMergeFrom(from);
+}
+
+bool BlobShape::IsInitialized() const {
+
+  return true;
+}
+
+void BlobShape::Swap(BlobShape* other) {
+  if (other == this) return;
+  InternalSwap(other);
+}
+void BlobShape::InternalSwap(BlobShape* other) {
+  dim_.UnsafeArenaSwap(&other->dim_);
+  std::swap(_has_bits_[0], other->_has_bits_[0]);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
+}
+
+::google::protobuf::Metadata BlobShape::GetMetadata() const {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::Metadata metadata;
+  metadata.descriptor = BlobShape_descriptor_;
+  metadata.reflection = BlobShape_reflection_;
+  return metadata;
+}
+
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// BlobShape
+
+// repeated int64 dim = 1 [packed = true];
+int BlobShape::dim_size() const {
+  return dim_.size();
+}
+void BlobShape::clear_dim() {
+  dim_.Clear();
+}
+::google::protobuf::int64 BlobShape::dim(int index) const {
+  // @@protoc_insertion_point(field_get:caffe.BlobShape.dim)
+  return dim_.Get(index);
+}
+void BlobShape::set_dim(int index, ::google::protobuf::int64 value) {
+  dim_.Set(index, value);
+  // @@protoc_insertion_point(field_set:caffe.BlobShape.dim)
+}
+void BlobShape::add_dim(::google::protobuf::int64 value) {
+  dim_.Add(value);
+  // @@protoc_insertion_point(field_add:caffe.BlobShape.dim)
+}
+const ::google::protobuf::RepeatedField< ::google::protobuf::int64 >&
+BlobShape::dim() const {
+  // @@protoc_insertion_point(field_list:caffe.BlobShape.dim)
+  return dim_;
+}
+::google::protobuf::RepeatedField< ::google::protobuf::int64 >*
+BlobShape::mutable_dim() {
+  // @@protoc_insertion_point(field_mutable_list:caffe.BlobShape.dim)
+  return &dim_;
+}
+
+inline const BlobShape* BlobShape::internal_default_instance() {
+  return &BlobShape_default_instance_.get();
+}
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
+
+// ===================================================================
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const int BlobProto::kShapeFieldNumber;
+const int BlobProto::kDataFieldNumber;
+const int BlobProto::kDiffFieldNumber;
+const int BlobProto::kNumFieldNumber;
+const int BlobProto::kChannelsFieldNumber;
+const int BlobProto::kHeightFieldNumber;
+const int BlobProto::kWidthFieldNumber;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+
+BlobProto::BlobProto()
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+  if (this != internal_default_instance()) protobuf_InitDefaults_caffe_2eproto();
+  SharedCtor();
+  // @@protoc_insertion_point(constructor:caffe.BlobProto)
+}
+
+void BlobProto::InitAsDefaultInstance() {
+  shape_ = const_cast< ::caffe::BlobShape*>(
+      ::caffe::BlobShape::internal_default_instance());
+}
+
+BlobProto::BlobProto(const BlobProto& from)
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
+  SharedCtor();
+  UnsafeMergeFrom(from);
+  // @@protoc_insertion_point(copy_constructor:caffe.BlobProto)
+}
+
+void BlobProto::SharedCtor() {
+  _cached_size_ = 0;
+  shape_ = NULL;
+  ::memset(&num_, 0, reinterpret_cast<char*>(&width_) -
+    reinterpret_cast<char*>(&num_) + sizeof(width_));
+}
+
+BlobProto::~BlobProto() {
+  // @@protoc_insertion_point(destructor:caffe.BlobProto)
+  SharedDtor();
+}
+
+void BlobProto::SharedDtor() {
+  if (this != &BlobProto_default_instance_.get()) {
+    delete shape_;
+  }
+}
+
+void BlobProto::SetCachedSize(int size) const {
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* BlobProto::descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return BlobProto_descriptor_;
+}
+
+const BlobProto& BlobProto::default_instance() {
+  protobuf_InitDefaults_caffe_2eproto();
+  return *internal_default_instance();
+}
+
+::google::protobuf::internal::ExplicitlyConstructed<BlobProto> BlobProto_default_instance_;
+
+BlobProto* BlobProto::New(::google::protobuf::Arena* arena) const {
+  BlobProto* n = new BlobProto;
+  if (arena != NULL) {
+    arena->Own(n);
+  }
+  return n;
+}
+
+void BlobProto::Clear() {
+// @@protoc_insertion_point(message_clear_start:caffe.BlobProto)
+#if defined(__clang__)
+#define ZR_HELPER_(f) \
+  _Pragma("clang diagnostic push") \
+  _Pragma("clang diagnostic ignored \"-Winvalid-offsetof\"") \
+  __builtin_offsetof(BlobProto, f) \
+  _Pragma("clang diagnostic pop")
+#else
+#define ZR_HELPER_(f) reinterpret_cast<char*>(\
+  &reinterpret_cast<BlobProto*>(16)->f)
+#endif
+
+#define ZR_(first, last) do {\
+  ::memset(&(first), 0,\
+           ZR_HELPER_(last) - ZR_HELPER_(first) + sizeof(last));\
+} while (0)
+
+  if (_has_bits_[0 / 32] & 121u) {
+    ZR_(num_, width_);
+    if (has_shape()) {
+      if (shape_ != NULL) shape_->::caffe::BlobShape::Clear();
+    }
+  }
+
+#undef ZR_HELPER_
+#undef ZR_
+
+  data_.Clear();
+  diff_.Clear();
+  _has_bits_.Clear();
+  if (_internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->Clear();
+  }
+}
+
+bool BlobProto::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
+  ::google::protobuf::uint32 tag;
+  // @@protoc_insertion_point(parse_start:caffe.BlobProto)
+  for (;;) {
+    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+    tag = p.first;
+    if (!p.second) goto handle_unusual;
+    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+      // optional int32 num = 1 [default = 0];
+      case 1: {
+        if (tag == 8) {
+          set_has_num();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
+                 input, &num_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(16)) goto parse_channels;
+        break;
+      }
+
+      // optional int32 channels = 2 [default = 0];
+      case 2: {
+        if (tag == 16) {
+         parse_channels:
+          set_has_channels();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
+                 input, &channels_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(24)) goto parse_height;
+        break;
+      }
+
+      // optional int32 height = 3 [default = 0];
+      case 3: {
+        if (tag == 24) {
+         parse_height:
+          set_has_height();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
+                 input, &height_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(32)) goto parse_width;
+        break;
+      }
+
+      // optional int32 width = 4 [default = 0];
+      case 4: {
+        if (tag == 32) {
+         parse_width:
+          set_has_width();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
+                 input, &width_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(42)) goto parse_data;
+        break;
+      }
+
+      // repeated float data = 5 [packed = true];
+      case 5: {
+        if (tag == 42) {
+         parse_data:
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPackedPrimitive<
+                   float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
+                 input, this->mutable_data())));
+        } else if (tag == 45) {
+          DO_((::google::protobuf::internal::WireFormatLite::ReadRepeatedPrimitiveNoInline<
+                   float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
+                 1, 42, input, this->mutable_data())));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(50)) goto parse_diff;
+        break;
+      }
+
+      // repeated float diff = 6 [packed = true];
+      case 6: {
+        if (tag == 50) {
+         parse_diff:
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPackedPrimitive<
+                   float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
+                 input, this->mutable_diff())));
+        } else if (tag == 53) {
+          DO_((::google::protobuf::internal::WireFormatLite::ReadRepeatedPrimitiveNoInline<
+                   float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
+                 1, 50, input, this->mutable_diff())));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(58)) goto parse_shape;
+        break;
+      }
+
+      // optional .caffe.BlobShape shape = 7;
+      case 7: {
+        if (tag == 58) {
+         parse_shape:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+               input, mutable_shape()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectAtEnd()) goto success;
+        break;
+      }
+
+      default: {
+      handle_unusual:
+        if (tag == 0 ||
+            ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+          goto success;
+        }
+        DO_(::google::protobuf::internal::WireFormat::SkipField(
+              input, tag, mutable_unknown_fields()));
+        break;
+      }
+    }
+  }
+success:
+  // @@protoc_insertion_point(parse_success:caffe.BlobProto)
+  return true;
+failure:
+  // @@protoc_insertion_point(parse_failure:caffe.BlobProto)
+  return false;
+#undef DO_
+}
+
+void BlobProto::SerializeWithCachedSizes(
+    ::google::protobuf::io::CodedOutputStream* output) const {
+  // @@protoc_insertion_point(serialize_start:caffe.BlobProto)
+  // optional int32 num = 1 [default = 0];
+  if (has_num()) {
+    ::google::protobuf::internal::WireFormatLite::WriteInt32(1, this->num(), output);
+  }
+
+  // optional int32 channels = 2 [default = 0];
+  if (has_channels()) {
+    ::google::protobuf::internal::WireFormatLite::WriteInt32(2, this->channels(), output);
+  }
+
+  // optional int32 height = 3 [default = 0];
+  if (has_height()) {
+    ::google::protobuf::internal::WireFormatLite::WriteInt32(3, this->height(), output);
+  }
+
+  // optional int32 width = 4 [default = 0];
+  if (has_width()) {
+    ::google::protobuf::internal::WireFormatLite::WriteInt32(4, this->width(), output);
+  }
+
+  // repeated float data = 5 [packed = true];
+  if (this->data_size() > 0) {
+    ::google::protobuf::internal::WireFormatLite::WriteTag(5, ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED, output);
+    output->WriteVarint32(_data_cached_byte_size_);
+  }
+  for (int i = 0; i < this->data_size(); i++) {
+    ::google::protobuf::internal::WireFormatLite::WriteFloatNoTag(
+      this->data(i), output);
+  }
+
+  // repeated float diff = 6 [packed = true];
+  if (this->diff_size() > 0) {
+    ::google::protobuf::internal::WireFormatLite::WriteTag(6, ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED, output);
+    output->WriteVarint32(_diff_cached_byte_size_);
+  }
+  for (int i = 0; i < this->diff_size(); i++) {
+    ::google::protobuf::internal::WireFormatLite::WriteFloatNoTag(
+      this->diff(i), output);
+  }
+
+  // optional .caffe.BlobShape shape = 7;
+  if (has_shape()) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      7, *this->shape_, output);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
+        unknown_fields(), output);
+  }
+  // @@protoc_insertion_point(serialize_end:caffe.BlobProto)
+}
+
+::google::protobuf::uint8* BlobProto::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
+  (void)deterministic; // Unused
+  // @@protoc_insertion_point(serialize_to_array_start:caffe.BlobProto)
+  // optional int32 num = 1 [default = 0];
+  if (has_num()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteInt32ToArray(1, this->num(), target);
+  }
+
+  // optional int32 channels = 2 [default = 0];
+  if (has_channels()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteInt32ToArray(2, this->channels(), target);
+  }
+
+  // optional int32 height = 3 [default = 0];
+  if (has_height()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteInt32ToArray(3, this->height(), target);
+  }
+
+  // optional int32 width = 4 [default = 0];
+  if (has_width()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteInt32ToArray(4, this->width(), target);
+  }
+
+  // repeated float data = 5 [packed = true];
+  if (this->data_size() > 0) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteTagToArray(
+      5,
+      ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED,
+      target);
+    target = ::google::protobuf::io::CodedOutputStream::WriteVarint32ToArray(
+      _data_cached_byte_size_, target);
+  }
+  for (int i = 0; i < this->data_size(); i++) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      WriteFloatNoTagToArray(this->data(i), target);
+  }
+
+  // repeated float diff = 6 [packed = true];
+  if (this->diff_size() > 0) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteTagToArray(
+      6,
+      ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED,
+      target);
+    target = ::google::protobuf::io::CodedOutputStream::WriteVarint32ToArray(
+      _diff_cached_byte_size_, target);
+  }
+  for (int i = 0; i < this->diff_size(); i++) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      WriteFloatNoTagToArray(this->diff(i), target);
+  }
+
+  // optional .caffe.BlobShape shape = 7;
+  if (has_shape()) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        7, *this->shape_, false, target);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
+        unknown_fields(), target);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:caffe.BlobProto)
+  return target;
+}
+
+size_t BlobProto::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:caffe.BlobProto)
+  size_t total_size = 0;
+
+  if (_has_bits_[0 / 32] & 121u) {
+    // optional .caffe.BlobShape shape = 7;
+    if (has_shape()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          *this->shape_);
+    }
+
+    // optional int32 num = 1 [default = 0];
+    if (has_num()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::Int32Size(
+          this->num());
+    }
+
+    // optional int32 channels = 2 [default = 0];
+    if (has_channels()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::Int32Size(
+          this->channels());
+    }
+
+    // optional int32 height = 3 [default = 0];
+    if (has_height()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::Int32Size(
+          this->height());
+    }
+
+    // optional int32 width = 4 [default = 0];
+    if (has_width()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::Int32Size(
+          this->width());
+    }
+
+  }
+  // repeated float data = 5 [packed = true];
+  {
+    size_t data_size = 0;
+    unsigned int count = this->data_size();
+    data_size = 4UL * count;
+    if (data_size > 0) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::Int32Size(data_size);
+    }
+    int cached_size = ::google::protobuf::internal::ToCachedSize(data_size);
+    GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+    _data_cached_byte_size_ = cached_size;
+    GOOGLE_SAFE_CONCURRENT_WRITES_END();
+    total_size += data_size;
+  }
+
+  // repeated float diff = 6 [packed = true];
+  {
+    size_t data_size = 0;
+    unsigned int count = this->diff_size();
+    data_size = 4UL * count;
+    if (data_size > 0) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::Int32Size(data_size);
+    }
+    int cached_size = ::google::protobuf::internal::ToCachedSize(data_size);
+    GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+    _diff_cached_byte_size_ = cached_size;
+    GOOGLE_SAFE_CONCURRENT_WRITES_END();
+    total_size += data_size;
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    total_size +=
+      ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
+        unknown_fields());
+  }
+  int cached_size = ::google::protobuf::internal::ToCachedSize(total_size);
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = cached_size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+  return total_size;
+}
+
+void BlobProto::MergeFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_merge_from_start:caffe.BlobProto)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const BlobProto* source =
+      ::google::protobuf::internal::DynamicCastToGenerated<const BlobProto>(
+          &from);
+  if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:caffe.BlobProto)
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:caffe.BlobProto)
+    UnsafeMergeFrom(*source);
+  }
+}
+
+void BlobProto::MergeFrom(const BlobProto& from) {
+// @@protoc_insertion_point(class_specific_merge_from_start:caffe.BlobProto)
+  if (GOOGLE_PREDICT_TRUE(&from != this)) {
+    UnsafeMergeFrom(from);
+  } else {
+    MergeFromFail(__LINE__);
+  }
+}
+
+void BlobProto::UnsafeMergeFrom(const BlobProto& from) {
+  GOOGLE_DCHECK(&from != this);
+  data_.UnsafeMergeFrom(from.data_);
+  diff_.UnsafeMergeFrom(from.diff_);
+  if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+    if (from.has_shape()) {
+      mutable_shape()->::caffe::BlobShape::MergeFrom(from.shape());
+    }
+    if (from.has_num()) {
+      set_num(from.num());
+    }
+    if (from.has_channels()) {
+      set_channels(from.channels());
+    }
+    if (from.has_height()) {
+      set_height(from.height());
+    }
+    if (from.has_width()) {
+      set_width(from.width());
+    }
+  }
+  if (from._internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::UnknownFieldSet::MergeToInternalMetdata(
+      from.unknown_fields(), &_internal_metadata_);
+  }
+}
+
+void BlobProto::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:caffe.BlobProto)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void BlobProto::CopyFrom(const BlobProto& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:caffe.BlobProto)
+  if (&from == this) return;
+  Clear();
+  UnsafeMergeFrom(from);
+}
+
+bool BlobProto::IsInitialized() const {
+
+  return true;
+}
+
+void BlobProto::Swap(BlobProto* other) {
+  if (other == this) return;
+  InternalSwap(other);
+}
+void BlobProto::InternalSwap(BlobProto* other) {
+  std::swap(shape_, other->shape_);
+  data_.UnsafeArenaSwap(&other->data_);
+  diff_.UnsafeArenaSwap(&other->diff_);
+  std::swap(num_, other->num_);
+  std::swap(channels_, other->channels_);
+  std::swap(height_, other->height_);
+  std::swap(width_, other->width_);
+  std::swap(_has_bits_[0], other->_has_bits_[0]);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
+}
+
+::google::protobuf::Metadata BlobProto::GetMetadata() const {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::Metadata metadata;
+  metadata.descriptor = BlobProto_descriptor_;
+  metadata.reflection = BlobProto_reflection_;
+  return metadata;
+}
+
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// BlobProto
+
+// optional .caffe.BlobShape shape = 7;
+bool BlobProto::has_shape() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+void BlobProto::set_has_shape() {
+  _has_bits_[0] |= 0x00000001u;
+}
+void BlobProto::clear_has_shape() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+void BlobProto::clear_shape() {
+  if (shape_ != NULL) shape_->::caffe::BlobShape::Clear();
+  clear_has_shape();
+}
+const ::caffe::BlobShape& BlobProto::shape() const {
+  // @@protoc_insertion_point(field_get:caffe.BlobProto.shape)
+  return shape_ != NULL ? *shape_
+                         : *::caffe::BlobShape::internal_default_instance();
+}
+::caffe::BlobShape* BlobProto::mutable_shape() {
+  set_has_shape();
+  if (shape_ == NULL) {
+    shape_ = new ::caffe::BlobShape;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.BlobProto.shape)
+  return shape_;
+}
+::caffe::BlobShape* BlobProto::release_shape() {
+  // @@protoc_insertion_point(field_release:caffe.BlobProto.shape)
+  clear_has_shape();
+  ::caffe::BlobShape* temp = shape_;
+  shape_ = NULL;
+  return temp;
+}
+void BlobProto::set_allocated_shape(::caffe::BlobShape* shape) {
+  delete shape_;
+  shape_ = shape;
+  if (shape) {
+    set_has_shape();
+  } else {
+    clear_has_shape();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.BlobProto.shape)
+}
+
+// repeated float data = 5 [packed = true];
+int BlobProto::data_size() const {
+  return data_.size();
+}
+void BlobProto::clear_data() {
+  data_.Clear();
+}
+float BlobProto::data(int index) const {
+  // @@protoc_insertion_point(field_get:caffe.BlobProto.data)
+  return data_.Get(index);
+}
+void BlobProto::set_data(int index, float value) {
+  data_.Set(index, value);
+  // @@protoc_insertion_point(field_set:caffe.BlobProto.data)
+}
+void BlobProto::add_data(float value) {
+  data_.Add(value);
+  // @@protoc_insertion_point(field_add:caffe.BlobProto.data)
+}
+const ::google::protobuf::RepeatedField< float >&
+BlobProto::data() const {
+  // @@protoc_insertion_point(field_list:caffe.BlobProto.data)
+  return data_;
+}
+::google::protobuf::RepeatedField< float >*
+BlobProto::mutable_data() {
+  // @@protoc_insertion_point(field_mutable_list:caffe.BlobProto.data)
+  return &data_;
+}
+
+// repeated float diff = 6 [packed = true];
+int BlobProto::diff_size() const {
+  return diff_.size();
+}
+void BlobProto::clear_diff() {
+  diff_.Clear();
+}
+float BlobProto::diff(int index) const {
+  // @@protoc_insertion_point(field_get:caffe.BlobProto.diff)
+  return diff_.Get(index);
+}
+void BlobProto::set_diff(int index, float value) {
+  diff_.Set(index, value);
+  // @@protoc_insertion_point(field_set:caffe.BlobProto.diff)
+}
+void BlobProto::add_diff(float value) {
+  diff_.Add(value);
+  // @@protoc_insertion_point(field_add:caffe.BlobProto.diff)
+}
+const ::google::protobuf::RepeatedField< float >&
+BlobProto::diff() const {
+  // @@protoc_insertion_point(field_list:caffe.BlobProto.diff)
+  return diff_;
+}
+::google::protobuf::RepeatedField< float >*
+BlobProto::mutable_diff() {
+  // @@protoc_insertion_point(field_mutable_list:caffe.BlobProto.diff)
+  return &diff_;
+}
+
+// optional int32 num = 1 [default = 0];
+bool BlobProto::has_num() const {
+  return (_has_bits_[0] & 0x00000008u) != 0;
+}
+void BlobProto::set_has_num() {
+  _has_bits_[0] |= 0x00000008u;
+}
+void BlobProto::clear_has_num() {
+  _has_bits_[0] &= ~0x00000008u;
+}
+void BlobProto::clear_num() {
+  num_ = 0;
+  clear_has_num();
+}
+::google::protobuf::int32 BlobProto::num() const {
+  // @@protoc_insertion_point(field_get:caffe.BlobProto.num)
+  return num_;
+}
+void BlobProto::set_num(::google::protobuf::int32 value) {
+  set_has_num();
+  num_ = value;
+  // @@protoc_insertion_point(field_set:caffe.BlobProto.num)
+}
+
+// optional int32 channels = 2 [default = 0];
+bool BlobProto::has_channels() const {
+  return (_has_bits_[0] & 0x00000010u) != 0;
+}
+void BlobProto::set_has_channels() {
+  _has_bits_[0] |= 0x00000010u;
+}
+void BlobProto::clear_has_channels() {
+  _has_bits_[0] &= ~0x00000010u;
+}
+void BlobProto::clear_channels() {
+  channels_ = 0;
+  clear_has_channels();
+}
+::google::protobuf::int32 BlobProto::channels() const {
+  // @@protoc_insertion_point(field_get:caffe.BlobProto.channels)
+  return channels_;
+}
+void BlobProto::set_channels(::google::protobuf::int32 value) {
+  set_has_channels();
+  channels_ = value;
+  // @@protoc_insertion_point(field_set:caffe.BlobProto.channels)
+}
+
+// optional int32 height = 3 [default = 0];
+bool BlobProto::has_height() const {
+  return (_has_bits_[0] & 0x00000020u) != 0;
+}
+void BlobProto::set_has_height() {
+  _has_bits_[0] |= 0x00000020u;
+}
+void BlobProto::clear_has_height() {
+  _has_bits_[0] &= ~0x00000020u;
+}
+void BlobProto::clear_height() {
+  height_ = 0;
+  clear_has_height();
+}
+::google::protobuf::int32 BlobProto::height() const {
+  // @@protoc_insertion_point(field_get:caffe.BlobProto.height)
+  return height_;
+}
+void BlobProto::set_height(::google::protobuf::int32 value) {
+  set_has_height();
+  height_ = value;
+  // @@protoc_insertion_point(field_set:caffe.BlobProto.height)
+}
+
+// optional int32 width = 4 [default = 0];
+bool BlobProto::has_width() const {
+  return (_has_bits_[0] & 0x00000040u) != 0;
+}
+void BlobProto::set_has_width() {
+  _has_bits_[0] |= 0x00000040u;
+}
+void BlobProto::clear_has_width() {
+  _has_bits_[0] &= ~0x00000040u;
+}
+void BlobProto::clear_width() {
+  width_ = 0;
+  clear_has_width();
+}
+::google::protobuf::int32 BlobProto::width() const {
+  // @@protoc_insertion_point(field_get:caffe.BlobProto.width)
+  return width_;
+}
+void BlobProto::set_width(::google::protobuf::int32 value) {
+  set_has_width();
+  width_ = value;
+  // @@protoc_insertion_point(field_set:caffe.BlobProto.width)
+}
+
+inline const BlobProto* BlobProto::internal_default_instance() {
+  return &BlobProto_default_instance_.get();
+}
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
+
+// ===================================================================
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const int BlobProtoVector::kBlobsFieldNumber;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+
+BlobProtoVector::BlobProtoVector()
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+  if (this != internal_default_instance()) protobuf_InitDefaults_caffe_2eproto();
+  SharedCtor();
+  // @@protoc_insertion_point(constructor:caffe.BlobProtoVector)
+}
+
+void BlobProtoVector::InitAsDefaultInstance() {
+}
+
+BlobProtoVector::BlobProtoVector(const BlobProtoVector& from)
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
+  SharedCtor();
+  UnsafeMergeFrom(from);
+  // @@protoc_insertion_point(copy_constructor:caffe.BlobProtoVector)
+}
+
+void BlobProtoVector::SharedCtor() {
+  _cached_size_ = 0;
+}
+
+BlobProtoVector::~BlobProtoVector() {
+  // @@protoc_insertion_point(destructor:caffe.BlobProtoVector)
+  SharedDtor();
+}
+
+void BlobProtoVector::SharedDtor() {
+}
+
+void BlobProtoVector::SetCachedSize(int size) const {
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* BlobProtoVector::descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return BlobProtoVector_descriptor_;
+}
+
+const BlobProtoVector& BlobProtoVector::default_instance() {
+  protobuf_InitDefaults_caffe_2eproto();
+  return *internal_default_instance();
+}
+
+::google::protobuf::internal::ExplicitlyConstructed<BlobProtoVector> BlobProtoVector_default_instance_;
+
+BlobProtoVector* BlobProtoVector::New(::google::protobuf::Arena* arena) const {
+  BlobProtoVector* n = new BlobProtoVector;
+  if (arena != NULL) {
+    arena->Own(n);
+  }
+  return n;
+}
+
+void BlobProtoVector::Clear() {
+// @@protoc_insertion_point(message_clear_start:caffe.BlobProtoVector)
+  blobs_.Clear();
+  _has_bits_.Clear();
+  if (_internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->Clear();
+  }
+}
+
+bool BlobProtoVector::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
+  ::google::protobuf::uint32 tag;
+  // @@protoc_insertion_point(parse_start:caffe.BlobProtoVector)
+  for (;;) {
+    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+    tag = p.first;
+    if (!p.second) goto handle_unusual;
+    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+      // repeated .caffe.BlobProto blobs = 1;
+      case 1: {
+        if (tag == 10) {
+          DO_(input->IncrementRecursionDepth());
+         parse_loop_blobs:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth(
+                input, add_blobs()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(10)) goto parse_loop_blobs;
+        input->UnsafeDecrementRecursionDepth();
+        if (input->ExpectAtEnd()) goto success;
+        break;
+      }
+
+      default: {
+      handle_unusual:
+        if (tag == 0 ||
+            ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+          goto success;
+        }
+        DO_(::google::protobuf::internal::WireFormat::SkipField(
+              input, tag, mutable_unknown_fields()));
+        break;
+      }
+    }
+  }
+success:
+  // @@protoc_insertion_point(parse_success:caffe.BlobProtoVector)
+  return true;
+failure:
+  // @@protoc_insertion_point(parse_failure:caffe.BlobProtoVector)
+  return false;
+#undef DO_
+}
+
+void BlobProtoVector::SerializeWithCachedSizes(
+    ::google::protobuf::io::CodedOutputStream* output) const {
+  // @@protoc_insertion_point(serialize_start:caffe.BlobProtoVector)
+  // repeated .caffe.BlobProto blobs = 1;
+  for (unsigned int i = 0, n = this->blobs_size(); i < n; i++) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      1, this->blobs(i), output);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
+        unknown_fields(), output);
+  }
+  // @@protoc_insertion_point(serialize_end:caffe.BlobProtoVector)
+}
+
+::google::protobuf::uint8* BlobProtoVector::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
+  (void)deterministic; // Unused
+  // @@protoc_insertion_point(serialize_to_array_start:caffe.BlobProtoVector)
+  // repeated .caffe.BlobProto blobs = 1;
+  for (unsigned int i = 0, n = this->blobs_size(); i < n; i++) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        1, this->blobs(i), false, target);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
+        unknown_fields(), target);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:caffe.BlobProtoVector)
+  return target;
+}
+
+size_t BlobProtoVector::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:caffe.BlobProtoVector)
+  size_t total_size = 0;
+
+  // repeated .caffe.BlobProto blobs = 1;
+  {
+    unsigned int count = this->blobs_size();
+    total_size += 1UL * count;
+    for (unsigned int i = 0; i < count; i++) {
+      total_size +=
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          this->blobs(i));
+    }
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    total_size +=
+      ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
+        unknown_fields());
+  }
+  int cached_size = ::google::protobuf::internal::ToCachedSize(total_size);
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = cached_size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+  return total_size;
+}
+
+void BlobProtoVector::MergeFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_merge_from_start:caffe.BlobProtoVector)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const BlobProtoVector* source =
+      ::google::protobuf::internal::DynamicCastToGenerated<const BlobProtoVector>(
+          &from);
+  if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:caffe.BlobProtoVector)
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:caffe.BlobProtoVector)
+    UnsafeMergeFrom(*source);
+  }
+}
+
+void BlobProtoVector::MergeFrom(const BlobProtoVector& from) {
+// @@protoc_insertion_point(class_specific_merge_from_start:caffe.BlobProtoVector)
+  if (GOOGLE_PREDICT_TRUE(&from != this)) {
+    UnsafeMergeFrom(from);
+  } else {
+    MergeFromFail(__LINE__);
+  }
+}
+
+void BlobProtoVector::UnsafeMergeFrom(const BlobProtoVector& from) {
+  GOOGLE_DCHECK(&from != this);
+  blobs_.MergeFrom(from.blobs_);
+  if (from._internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::UnknownFieldSet::MergeToInternalMetdata(
+      from.unknown_fields(), &_internal_metadata_);
+  }
+}
+
+void BlobProtoVector::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:caffe.BlobProtoVector)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void BlobProtoVector::CopyFrom(const BlobProtoVector& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:caffe.BlobProtoVector)
+  if (&from == this) return;
+  Clear();
+  UnsafeMergeFrom(from);
+}
+
+bool BlobProtoVector::IsInitialized() const {
+
+  return true;
+}
+
+void BlobProtoVector::Swap(BlobProtoVector* other) {
+  if (other == this) return;
+  InternalSwap(other);
+}
+void BlobProtoVector::InternalSwap(BlobProtoVector* other) {
+  blobs_.UnsafeArenaSwap(&other->blobs_);
+  std::swap(_has_bits_[0], other->_has_bits_[0]);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
+}
+
+::google::protobuf::Metadata BlobProtoVector::GetMetadata() const {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::Metadata metadata;
+  metadata.descriptor = BlobProtoVector_descriptor_;
+  metadata.reflection = BlobProtoVector_reflection_;
+  return metadata;
+}
+
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// BlobProtoVector
+
+// repeated .caffe.BlobProto blobs = 1;
+int BlobProtoVector::blobs_size() const {
+  return blobs_.size();
+}
+void BlobProtoVector::clear_blobs() {
+  blobs_.Clear();
+}
+const ::caffe::BlobProto& BlobProtoVector::blobs(int index) const {
+  // @@protoc_insertion_point(field_get:caffe.BlobProtoVector.blobs)
+  return blobs_.Get(index);
+}
+::caffe::BlobProto* BlobProtoVector::mutable_blobs(int index) {
+  // @@protoc_insertion_point(field_mutable:caffe.BlobProtoVector.blobs)
+  return blobs_.Mutable(index);
+}
+::caffe::BlobProto* BlobProtoVector::add_blobs() {
+  // @@protoc_insertion_point(field_add:caffe.BlobProtoVector.blobs)
+  return blobs_.Add();
+}
+::google::protobuf::RepeatedPtrField< ::caffe::BlobProto >*
+BlobProtoVector::mutable_blobs() {
+  // @@protoc_insertion_point(field_mutable_list:caffe.BlobProtoVector.blobs)
+  return &blobs_;
+}
+const ::google::protobuf::RepeatedPtrField< ::caffe::BlobProto >&
+BlobProtoVector::blobs() const {
+  // @@protoc_insertion_point(field_list:caffe.BlobProtoVector.blobs)
+  return blobs_;
+}
+
+inline const BlobProtoVector* BlobProtoVector::internal_default_instance() {
+  return &BlobProtoVector_default_instance_.get();
+}
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
+
+// ===================================================================
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const int CropParameter::kAxisFieldNumber;
+const int CropParameter::kOffsetFieldNumber;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+
+CropParameter::CropParameter()
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+  if (this != internal_default_instance()) protobuf_InitDefaults_caffe_2eproto();
+  SharedCtor();
+  // @@protoc_insertion_point(constructor:caffe.CropParameter)
+}
+
+void CropParameter::InitAsDefaultInstance() {
+}
+
+CropParameter::CropParameter(const CropParameter& from)
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
+  SharedCtor();
+  UnsafeMergeFrom(from);
+  // @@protoc_insertion_point(copy_constructor:caffe.CropParameter)
+}
+
+void CropParameter::SharedCtor() {
+  _cached_size_ = 0;
+  axis_ = 2;
+}
+
+CropParameter::~CropParameter() {
+  // @@protoc_insertion_point(destructor:caffe.CropParameter)
+  SharedDtor();
+}
+
+void CropParameter::SharedDtor() {
+}
+
+void CropParameter::SetCachedSize(int size) const {
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* CropParameter::descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return CropParameter_descriptor_;
+}
+
+const CropParameter& CropParameter::default_instance() {
+  protobuf_InitDefaults_caffe_2eproto();
+  return *internal_default_instance();
+}
+
+::google::protobuf::internal::ExplicitlyConstructed<CropParameter> CropParameter_default_instance_;
+
+CropParameter* CropParameter::New(::google::protobuf::Arena* arena) const {
+  CropParameter* n = new CropParameter;
+  if (arena != NULL) {
+    arena->Own(n);
+  }
+  return n;
+}
+
+void CropParameter::Clear() {
+// @@protoc_insertion_point(message_clear_start:caffe.CropParameter)
+  axis_ = 2;
+  offset_.Clear();
+  _has_bits_.Clear();
+  if (_internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->Clear();
+  }
+}
+
+bool CropParameter::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
+  ::google::protobuf::uint32 tag;
+  // @@protoc_insertion_point(parse_start:caffe.CropParameter)
+  for (;;) {
+    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+    tag = p.first;
+    if (!p.second) goto handle_unusual;
+    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+      // optional int32 axis = 1 [default = 2];
+      case 1: {
+        if (tag == 8) {
+          set_has_axis();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
+                 input, &axis_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(16)) goto parse_offset;
+        break;
+      }
+
+      // repeated uint32 offset = 2;
+      case 2: {
+        if (tag == 16) {
+         parse_offset:
+          DO_((::google::protobuf::internal::WireFormatLite::ReadRepeatedPrimitive<
+                   ::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>(
+                 1, 16, input, this->mutable_offset())));
+        } else if (tag == 18) {
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPackedPrimitiveNoInline<
+                   ::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>(
+                 input, this->mutable_offset())));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(16)) goto parse_offset;
+        if (input->ExpectAtEnd()) goto success;
+        break;
+      }
+
+      default: {
+      handle_unusual:
+        if (tag == 0 ||
+            ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+          goto success;
+        }
+        DO_(::google::protobuf::internal::WireFormat::SkipField(
+              input, tag, mutable_unknown_fields()));
+        break;
+      }
+    }
+  }
+success:
+  // @@protoc_insertion_point(parse_success:caffe.CropParameter)
+  return true;
+failure:
+  // @@protoc_insertion_point(parse_failure:caffe.CropParameter)
+  return false;
+#undef DO_
+}
+
+void CropParameter::SerializeWithCachedSizes(
+    ::google::protobuf::io::CodedOutputStream* output) const {
+  // @@protoc_insertion_point(serialize_start:caffe.CropParameter)
+  // optional int32 axis = 1 [default = 2];
+  if (has_axis()) {
+    ::google::protobuf::internal::WireFormatLite::WriteInt32(1, this->axis(), output);
+  }
+
+  // repeated uint32 offset = 2;
+  for (int i = 0; i < this->offset_size(); i++) {
+    ::google::protobuf::internal::WireFormatLite::WriteUInt32(
+      2, this->offset(i), output);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
+        unknown_fields(), output);
+  }
+  // @@protoc_insertion_point(serialize_end:caffe.CropParameter)
+}
+
+::google::protobuf::uint8* CropParameter::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
+  (void)deterministic; // Unused
+  // @@protoc_insertion_point(serialize_to_array_start:caffe.CropParameter)
+  // optional int32 axis = 1 [default = 2];
+  if (has_axis()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteInt32ToArray(1, this->axis(), target);
+  }
+
+  // repeated uint32 offset = 2;
+  for (int i = 0; i < this->offset_size(); i++) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      WriteUInt32ToArray(2, this->offset(i), target);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
+        unknown_fields(), target);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:caffe.CropParameter)
+  return target;
+}
+
+size_t CropParameter::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:caffe.CropParameter)
+  size_t total_size = 0;
+
+  // optional int32 axis = 1 [default = 2];
+  if (has_axis()) {
+    total_size += 1 +
+      ::google::protobuf::internal::WireFormatLite::Int32Size(
+        this->axis());
+  }
+
+  // repeated uint32 offset = 2;
+  {
+    size_t data_size = 0;
+    unsigned int count = this->offset_size();
+    for (unsigned int i = 0; i < count; i++) {
+      data_size += ::google::protobuf::internal::WireFormatLite::
+        UInt32Size(this->offset(i));
+    }
+    total_size += 1 *
+                  ::google::protobuf::internal::FromIntSize(this->offset_size());
+    total_size += data_size;
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    total_size +=
+      ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
+        unknown_fields());
+  }
+  int cached_size = ::google::protobuf::internal::ToCachedSize(total_size);
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = cached_size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+  return total_size;
+}
+
+void CropParameter::MergeFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_merge_from_start:caffe.CropParameter)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const CropParameter* source =
+      ::google::protobuf::internal::DynamicCastToGenerated<const CropParameter>(
+          &from);
+  if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:caffe.CropParameter)
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:caffe.CropParameter)
+    UnsafeMergeFrom(*source);
+  }
+}
+
+void CropParameter::MergeFrom(const CropParameter& from) {
+// @@protoc_insertion_point(class_specific_merge_from_start:caffe.CropParameter)
+  if (GOOGLE_PREDICT_TRUE(&from != this)) {
+    UnsafeMergeFrom(from);
+  } else {
+    MergeFromFail(__LINE__);
+  }
+}
+
+void CropParameter::UnsafeMergeFrom(const CropParameter& from) {
+  GOOGLE_DCHECK(&from != this);
+  offset_.UnsafeMergeFrom(from.offset_);
+  if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+    if (from.has_axis()) {
+      set_axis(from.axis());
+    }
+  }
+  if (from._internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::UnknownFieldSet::MergeToInternalMetdata(
+      from.unknown_fields(), &_internal_metadata_);
+  }
+}
+
+void CropParameter::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:caffe.CropParameter)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void CropParameter::CopyFrom(const CropParameter& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:caffe.CropParameter)
+  if (&from == this) return;
+  Clear();
+  UnsafeMergeFrom(from);
+}
+
+bool CropParameter::IsInitialized() const {
+
+  return true;
+}
+
+void CropParameter::Swap(CropParameter* other) {
+  if (other == this) return;
+  InternalSwap(other);
+}
+void CropParameter::InternalSwap(CropParameter* other) {
+  std::swap(axis_, other->axis_);
+  offset_.UnsafeArenaSwap(&other->offset_);
+  std::swap(_has_bits_[0], other->_has_bits_[0]);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
+}
+
+::google::protobuf::Metadata CropParameter::GetMetadata() const {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::Metadata metadata;
+  metadata.descriptor = CropParameter_descriptor_;
+  metadata.reflection = CropParameter_reflection_;
+  return metadata;
+}
+
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// CropParameter
+
+// optional int32 axis = 1 [default = 2];
+bool CropParameter::has_axis() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+void CropParameter::set_has_axis() {
+  _has_bits_[0] |= 0x00000001u;
+}
+void CropParameter::clear_has_axis() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+void CropParameter::clear_axis() {
+  axis_ = 2;
+  clear_has_axis();
+}
+::google::protobuf::int32 CropParameter::axis() const {
+  // @@protoc_insertion_point(field_get:caffe.CropParameter.axis)
+  return axis_;
+}
+void CropParameter::set_axis(::google::protobuf::int32 value) {
+  set_has_axis();
+  axis_ = value;
+  // @@protoc_insertion_point(field_set:caffe.CropParameter.axis)
+}
+
+// repeated uint32 offset = 2;
+int CropParameter::offset_size() const {
+  return offset_.size();
+}
+void CropParameter::clear_offset() {
+  offset_.Clear();
+}
+::google::protobuf::uint32 CropParameter::offset(int index) const {
+  // @@protoc_insertion_point(field_get:caffe.CropParameter.offset)
+  return offset_.Get(index);
+}
+void CropParameter::set_offset(int index, ::google::protobuf::uint32 value) {
+  offset_.Set(index, value);
+  // @@protoc_insertion_point(field_set:caffe.CropParameter.offset)
+}
+void CropParameter::add_offset(::google::protobuf::uint32 value) {
+  offset_.Add(value);
+  // @@protoc_insertion_point(field_add:caffe.CropParameter.offset)
+}
+const ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >&
+CropParameter::offset() const {
+  // @@protoc_insertion_point(field_list:caffe.CropParameter.offset)
+  return offset_;
+}
+::google::protobuf::RepeatedField< ::google::protobuf::uint32 >*
+CropParameter::mutable_offset() {
+  // @@protoc_insertion_point(field_mutable_list:caffe.CropParameter.offset)
+  return &offset_;
+}
+
+inline const CropParameter* CropParameter::internal_default_instance() {
+  return &CropParameter_default_instance_.get();
+}
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
+
+// ===================================================================
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const int PermuteParameter::kOrderFieldNumber;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+
+PermuteParameter::PermuteParameter()
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+  if (this != internal_default_instance()) protobuf_InitDefaults_caffe_2eproto();
+  SharedCtor();
+  // @@protoc_insertion_point(constructor:caffe.PermuteParameter)
+}
+
+void PermuteParameter::InitAsDefaultInstance() {
+}
+
+PermuteParameter::PermuteParameter(const PermuteParameter& from)
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
+  SharedCtor();
+  UnsafeMergeFrom(from);
+  // @@protoc_insertion_point(copy_constructor:caffe.PermuteParameter)
+}
+
+void PermuteParameter::SharedCtor() {
+  _cached_size_ = 0;
+}
+
+PermuteParameter::~PermuteParameter() {
+  // @@protoc_insertion_point(destructor:caffe.PermuteParameter)
+  SharedDtor();
+}
+
+void PermuteParameter::SharedDtor() {
+}
+
+void PermuteParameter::SetCachedSize(int size) const {
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* PermuteParameter::descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return PermuteParameter_descriptor_;
+}
+
+const PermuteParameter& PermuteParameter::default_instance() {
+  protobuf_InitDefaults_caffe_2eproto();
+  return *internal_default_instance();
+}
+
+::google::protobuf::internal::ExplicitlyConstructed<PermuteParameter> PermuteParameter_default_instance_;
+
+PermuteParameter* PermuteParameter::New(::google::protobuf::Arena* arena) const {
+  PermuteParameter* n = new PermuteParameter;
+  if (arena != NULL) {
+    arena->Own(n);
+  }
+  return n;
+}
+
+void PermuteParameter::Clear() {
+// @@protoc_insertion_point(message_clear_start:caffe.PermuteParameter)
+  order_.Clear();
+  _has_bits_.Clear();
+  if (_internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->Clear();
+  }
+}
+
+bool PermuteParameter::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
+  ::google::protobuf::uint32 tag;
+  // @@protoc_insertion_point(parse_start:caffe.PermuteParameter)
+  for (;;) {
+    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+    tag = p.first;
+    if (!p.second) goto handle_unusual;
+    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+      // repeated uint32 order = 1;
+      case 1: {
+        if (tag == 8) {
+         parse_order:
+          DO_((::google::protobuf::internal::WireFormatLite::ReadRepeatedPrimitive<
+                   ::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>(
+                 1, 8, input, this->mutable_order())));
+        } else if (tag == 10) {
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPackedPrimitiveNoInline<
+                   ::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>(
+                 input, this->mutable_order())));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(8)) goto parse_order;
+        if (input->ExpectAtEnd()) goto success;
+        break;
+      }
+
+      default: {
+      handle_unusual:
+        if (tag == 0 ||
+            ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+          goto success;
+        }
+        DO_(::google::protobuf::internal::WireFormat::SkipField(
+              input, tag, mutable_unknown_fields()));
+        break;
+      }
+    }
+  }
+success:
+  // @@protoc_insertion_point(parse_success:caffe.PermuteParameter)
+  return true;
+failure:
+  // @@protoc_insertion_point(parse_failure:caffe.PermuteParameter)
+  return false;
+#undef DO_
+}
+
+void PermuteParameter::SerializeWithCachedSizes(
+    ::google::protobuf::io::CodedOutputStream* output) const {
+  // @@protoc_insertion_point(serialize_start:caffe.PermuteParameter)
+  // repeated uint32 order = 1;
+  for (int i = 0; i < this->order_size(); i++) {
+    ::google::protobuf::internal::WireFormatLite::WriteUInt32(
+      1, this->order(i), output);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
+        unknown_fields(), output);
+  }
+  // @@protoc_insertion_point(serialize_end:caffe.PermuteParameter)
+}
+
+::google::protobuf::uint8* PermuteParameter::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
+  (void)deterministic; // Unused
+  // @@protoc_insertion_point(serialize_to_array_start:caffe.PermuteParameter)
+  // repeated uint32 order = 1;
+  for (int i = 0; i < this->order_size(); i++) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      WriteUInt32ToArray(1, this->order(i), target);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
+        unknown_fields(), target);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:caffe.PermuteParameter)
+  return target;
+}
+
+size_t PermuteParameter::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:caffe.PermuteParameter)
+  size_t total_size = 0;
+
+  // repeated uint32 order = 1;
+  {
+    size_t data_size = 0;
+    unsigned int count = this->order_size();
+    for (unsigned int i = 0; i < count; i++) {
+      data_size += ::google::protobuf::internal::WireFormatLite::
+        UInt32Size(this->order(i));
+    }
+    total_size += 1 *
+                  ::google::protobuf::internal::FromIntSize(this->order_size());
+    total_size += data_size;
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    total_size +=
+      ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
+        unknown_fields());
+  }
+  int cached_size = ::google::protobuf::internal::ToCachedSize(total_size);
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = cached_size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+  return total_size;
+}
+
+void PermuteParameter::MergeFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_merge_from_start:caffe.PermuteParameter)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const PermuteParameter* source =
+      ::google::protobuf::internal::DynamicCastToGenerated<const PermuteParameter>(
+          &from);
+  if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:caffe.PermuteParameter)
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:caffe.PermuteParameter)
+    UnsafeMergeFrom(*source);
+  }
+}
+
+void PermuteParameter::MergeFrom(const PermuteParameter& from) {
+// @@protoc_insertion_point(class_specific_merge_from_start:caffe.PermuteParameter)
+  if (GOOGLE_PREDICT_TRUE(&from != this)) {
+    UnsafeMergeFrom(from);
+  } else {
+    MergeFromFail(__LINE__);
+  }
+}
+
+void PermuteParameter::UnsafeMergeFrom(const PermuteParameter& from) {
+  GOOGLE_DCHECK(&from != this);
+  order_.UnsafeMergeFrom(from.order_);
+  if (from._internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::UnknownFieldSet::MergeToInternalMetdata(
+      from.unknown_fields(), &_internal_metadata_);
+  }
+}
+
+void PermuteParameter::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:caffe.PermuteParameter)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void PermuteParameter::CopyFrom(const PermuteParameter& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:caffe.PermuteParameter)
+  if (&from == this) return;
+  Clear();
+  UnsafeMergeFrom(from);
+}
+
+bool PermuteParameter::IsInitialized() const {
+
+  return true;
+}
+
+void PermuteParameter::Swap(PermuteParameter* other) {
+  if (other == this) return;
+  InternalSwap(other);
+}
+void PermuteParameter::InternalSwap(PermuteParameter* other) {
+  order_.UnsafeArenaSwap(&other->order_);
+  std::swap(_has_bits_[0], other->_has_bits_[0]);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
+}
+
+::google::protobuf::Metadata PermuteParameter::GetMetadata() const {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::Metadata metadata;
+  metadata.descriptor = PermuteParameter_descriptor_;
+  metadata.reflection = PermuteParameter_reflection_;
+  return metadata;
+}
+
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// PermuteParameter
+
+// repeated uint32 order = 1;
+int PermuteParameter::order_size() const {
+  return order_.size();
+}
+void PermuteParameter::clear_order() {
+  order_.Clear();
+}
+::google::protobuf::uint32 PermuteParameter::order(int index) const {
+  // @@protoc_insertion_point(field_get:caffe.PermuteParameter.order)
+  return order_.Get(index);
+}
+void PermuteParameter::set_order(int index, ::google::protobuf::uint32 value) {
+  order_.Set(index, value);
+  // @@protoc_insertion_point(field_set:caffe.PermuteParameter.order)
+}
+void PermuteParameter::add_order(::google::protobuf::uint32 value) {
+  order_.Add(value);
+  // @@protoc_insertion_point(field_add:caffe.PermuteParameter.order)
+}
+const ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >&
+PermuteParameter::order() const {
+  // @@protoc_insertion_point(field_list:caffe.PermuteParameter.order)
+  return order_;
+}
+::google::protobuf::RepeatedField< ::google::protobuf::uint32 >*
+PermuteParameter::mutable_order() {
+  // @@protoc_insertion_point(field_mutable_list:caffe.PermuteParameter.order)
+  return &order_;
+}
+
+inline const PermuteParameter* PermuteParameter::internal_default_instance() {
+  return &PermuteParameter_default_instance_.get();
+}
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
+
+// ===================================================================
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const int NormalizeBBoxParameter::kAcrossSpatialFieldNumber;
+const int NormalizeBBoxParameter::kScaleFillerFieldNumber;
+const int NormalizeBBoxParameter::kChannelSharedFieldNumber;
+const int NormalizeBBoxParameter::kEpsFieldNumber;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+
+NormalizeBBoxParameter::NormalizeBBoxParameter()
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+  if (this != internal_default_instance()) protobuf_InitDefaults_caffe_2eproto();
+  SharedCtor();
+  // @@protoc_insertion_point(constructor:caffe.NormalizeBBoxParameter)
+}
+
+void NormalizeBBoxParameter::InitAsDefaultInstance() {
+  scale_filler_ = const_cast< ::caffe::FillerParameter*>(
+      ::caffe::FillerParameter::internal_default_instance());
+}
+
+NormalizeBBoxParameter::NormalizeBBoxParameter(const NormalizeBBoxParameter& from)
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
+  SharedCtor();
+  UnsafeMergeFrom(from);
+  // @@protoc_insertion_point(copy_constructor:caffe.NormalizeBBoxParameter)
+}
+
+void NormalizeBBoxParameter::SharedCtor() {
+  _cached_size_ = 0;
+  scale_filler_ = NULL;
+  across_spatial_ = true;
+  channel_shared_ = true;
+  eps_ = 1e-10f;
+}
+
+NormalizeBBoxParameter::~NormalizeBBoxParameter() {
+  // @@protoc_insertion_point(destructor:caffe.NormalizeBBoxParameter)
+  SharedDtor();
+}
+
+void NormalizeBBoxParameter::SharedDtor() {
+  if (this != &NormalizeBBoxParameter_default_instance_.get()) {
+    delete scale_filler_;
+  }
+}
+
+void NormalizeBBoxParameter::SetCachedSize(int size) const {
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* NormalizeBBoxParameter::descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return NormalizeBBoxParameter_descriptor_;
+}
+
+const NormalizeBBoxParameter& NormalizeBBoxParameter::default_instance() {
+  protobuf_InitDefaults_caffe_2eproto();
+  return *internal_default_instance();
+}
+
+::google::protobuf::internal::ExplicitlyConstructed<NormalizeBBoxParameter> NormalizeBBoxParameter_default_instance_;
+
+NormalizeBBoxParameter* NormalizeBBoxParameter::New(::google::protobuf::Arena* arena) const {
+  NormalizeBBoxParameter* n = new NormalizeBBoxParameter;
+  if (arena != NULL) {
+    arena->Own(n);
+  }
+  return n;
+}
+
+void NormalizeBBoxParameter::Clear() {
+// @@protoc_insertion_point(message_clear_start:caffe.NormalizeBBoxParameter)
+  if (_has_bits_[0 / 32] & 15u) {
+    across_spatial_ = true;
+    if (has_scale_filler()) {
+      if (scale_filler_ != NULL) scale_filler_->::caffe::FillerParameter::Clear();
+    }
+    channel_shared_ = true;
+    eps_ = 1e-10f;
+  }
+  _has_bits_.Clear();
+  if (_internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->Clear();
+  }
+}
+
+bool NormalizeBBoxParameter::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
+  ::google::protobuf::uint32 tag;
+  // @@protoc_insertion_point(parse_start:caffe.NormalizeBBoxParameter)
+  for (;;) {
+    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+    tag = p.first;
+    if (!p.second) goto handle_unusual;
+    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+      // optional bool across_spatial = 1 [default = true];
+      case 1: {
+        if (tag == 8) {
+          set_has_across_spatial();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>(
+                 input, &across_spatial_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(18)) goto parse_scale_filler;
+        break;
+      }
+
+      // optional .caffe.FillerParameter scale_filler = 2;
+      case 2: {
+        if (tag == 18) {
+         parse_scale_filler:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+               input, mutable_scale_filler()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(24)) goto parse_channel_shared;
+        break;
+      }
+
+      // optional bool channel_shared = 3 [default = true];
+      case 3: {
+        if (tag == 24) {
+         parse_channel_shared:
+          set_has_channel_shared();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>(
+                 input, &channel_shared_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(37)) goto parse_eps;
+        break;
+      }
+
+      // optional float eps = 4 [default = 1e-10];
+      case 4: {
+        if (tag == 37) {
+         parse_eps:
+          set_has_eps();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
+                 input, &eps_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectAtEnd()) goto success;
+        break;
+      }
+
+      default: {
+      handle_unusual:
+        if (tag == 0 ||
+            ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+          goto success;
+        }
+        DO_(::google::protobuf::internal::WireFormat::SkipField(
+              input, tag, mutable_unknown_fields()));
+        break;
+      }
+    }
+  }
+success:
+  // @@protoc_insertion_point(parse_success:caffe.NormalizeBBoxParameter)
+  return true;
+failure:
+  // @@protoc_insertion_point(parse_failure:caffe.NormalizeBBoxParameter)
+  return false;
+#undef DO_
+}
+
+void NormalizeBBoxParameter::SerializeWithCachedSizes(
+    ::google::protobuf::io::CodedOutputStream* output) const {
+  // @@protoc_insertion_point(serialize_start:caffe.NormalizeBBoxParameter)
+  // optional bool across_spatial = 1 [default = true];
+  if (has_across_spatial()) {
+    ::google::protobuf::internal::WireFormatLite::WriteBool(1, this->across_spatial(), output);
+  }
+
+  // optional .caffe.FillerParameter scale_filler = 2;
+  if (has_scale_filler()) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      2, *this->scale_filler_, output);
+  }
+
+  // optional bool channel_shared = 3 [default = true];
+  if (has_channel_shared()) {
+    ::google::protobuf::internal::WireFormatLite::WriteBool(3, this->channel_shared(), output);
+  }
+
+  // optional float eps = 4 [default = 1e-10];
+  if (has_eps()) {
+    ::google::protobuf::internal::WireFormatLite::WriteFloat(4, this->eps(), output);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
+        unknown_fields(), output);
+  }
+  // @@protoc_insertion_point(serialize_end:caffe.NormalizeBBoxParameter)
+}
+
+::google::protobuf::uint8* NormalizeBBoxParameter::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
+  (void)deterministic; // Unused
+  // @@protoc_insertion_point(serialize_to_array_start:caffe.NormalizeBBoxParameter)
+  // optional bool across_spatial = 1 [default = true];
+  if (has_across_spatial()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(1, this->across_spatial(), target);
+  }
+
+  // optional .caffe.FillerParameter scale_filler = 2;
+  if (has_scale_filler()) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        2, *this->scale_filler_, false, target);
+  }
+
+  // optional bool channel_shared = 3 [default = true];
+  if (has_channel_shared()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(3, this->channel_shared(), target);
+  }
+
+  // optional float eps = 4 [default = 1e-10];
+  if (has_eps()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteFloatToArray(4, this->eps(), target);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
+        unknown_fields(), target);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:caffe.NormalizeBBoxParameter)
+  return target;
+}
+
+size_t NormalizeBBoxParameter::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:caffe.NormalizeBBoxParameter)
+  size_t total_size = 0;
+
+  if (_has_bits_[0 / 32] & 15u) {
+    // optional bool across_spatial = 1 [default = true];
+    if (has_across_spatial()) {
+      total_size += 1 + 1;
+    }
+
+    // optional .caffe.FillerParameter scale_filler = 2;
+    if (has_scale_filler()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          *this->scale_filler_);
+    }
+
+    // optional bool channel_shared = 3 [default = true];
+    if (has_channel_shared()) {
+      total_size += 1 + 1;
+    }
+
+    // optional float eps = 4 [default = 1e-10];
+    if (has_eps()) {
+      total_size += 1 + 4;
+    }
+
+  }
+  if (_internal_metadata_.have_unknown_fields()) {
+    total_size +=
+      ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
+        unknown_fields());
+  }
+  int cached_size = ::google::protobuf::internal::ToCachedSize(total_size);
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = cached_size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+  return total_size;
+}
+
+void NormalizeBBoxParameter::MergeFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_merge_from_start:caffe.NormalizeBBoxParameter)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const NormalizeBBoxParameter* source =
+      ::google::protobuf::internal::DynamicCastToGenerated<const NormalizeBBoxParameter>(
+          &from);
+  if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:caffe.NormalizeBBoxParameter)
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:caffe.NormalizeBBoxParameter)
+    UnsafeMergeFrom(*source);
+  }
+}
+
+void NormalizeBBoxParameter::MergeFrom(const NormalizeBBoxParameter& from) {
+// @@protoc_insertion_point(class_specific_merge_from_start:caffe.NormalizeBBoxParameter)
+  if (GOOGLE_PREDICT_TRUE(&from != this)) {
+    UnsafeMergeFrom(from);
+  } else {
+    MergeFromFail(__LINE__);
+  }
+}
+
+void NormalizeBBoxParameter::UnsafeMergeFrom(const NormalizeBBoxParameter& from) {
+  GOOGLE_DCHECK(&from != this);
+  if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+    if (from.has_across_spatial()) {
+      set_across_spatial(from.across_spatial());
+    }
+    if (from.has_scale_filler()) {
+      mutable_scale_filler()->::caffe::FillerParameter::MergeFrom(from.scale_filler());
+    }
+    if (from.has_channel_shared()) {
+      set_channel_shared(from.channel_shared());
+    }
+    if (from.has_eps()) {
+      set_eps(from.eps());
+    }
+  }
+  if (from._internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::UnknownFieldSet::MergeToInternalMetdata(
+      from.unknown_fields(), &_internal_metadata_);
+  }
+}
+
+void NormalizeBBoxParameter::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:caffe.NormalizeBBoxParameter)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void NormalizeBBoxParameter::CopyFrom(const NormalizeBBoxParameter& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:caffe.NormalizeBBoxParameter)
+  if (&from == this) return;
+  Clear();
+  UnsafeMergeFrom(from);
+}
+
+bool NormalizeBBoxParameter::IsInitialized() const {
+
+  return true;
+}
+
+void NormalizeBBoxParameter::Swap(NormalizeBBoxParameter* other) {
+  if (other == this) return;
+  InternalSwap(other);
+}
+void NormalizeBBoxParameter::InternalSwap(NormalizeBBoxParameter* other) {
+  std::swap(across_spatial_, other->across_spatial_);
+  std::swap(scale_filler_, other->scale_filler_);
+  std::swap(channel_shared_, other->channel_shared_);
+  std::swap(eps_, other->eps_);
+  std::swap(_has_bits_[0], other->_has_bits_[0]);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
+}
+
+::google::protobuf::Metadata NormalizeBBoxParameter::GetMetadata() const {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::Metadata metadata;
+  metadata.descriptor = NormalizeBBoxParameter_descriptor_;
+  metadata.reflection = NormalizeBBoxParameter_reflection_;
+  return metadata;
+}
+
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// NormalizeBBoxParameter
+
+// optional bool across_spatial = 1 [default = true];
+bool NormalizeBBoxParameter::has_across_spatial() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+void NormalizeBBoxParameter::set_has_across_spatial() {
+  _has_bits_[0] |= 0x00000001u;
+}
+void NormalizeBBoxParameter::clear_has_across_spatial() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+void NormalizeBBoxParameter::clear_across_spatial() {
+  across_spatial_ = true;
+  clear_has_across_spatial();
+}
+bool NormalizeBBoxParameter::across_spatial() const {
+  // @@protoc_insertion_point(field_get:caffe.NormalizeBBoxParameter.across_spatial)
+  return across_spatial_;
+}
+void NormalizeBBoxParameter::set_across_spatial(bool value) {
+  set_has_across_spatial();
+  across_spatial_ = value;
+  // @@protoc_insertion_point(field_set:caffe.NormalizeBBoxParameter.across_spatial)
+}
+
+// optional .caffe.FillerParameter scale_filler = 2;
+bool NormalizeBBoxParameter::has_scale_filler() const {
+  return (_has_bits_[0] & 0x00000002u) != 0;
+}
+void NormalizeBBoxParameter::set_has_scale_filler() {
+  _has_bits_[0] |= 0x00000002u;
+}
+void NormalizeBBoxParameter::clear_has_scale_filler() {
+  _has_bits_[0] &= ~0x00000002u;
+}
+void NormalizeBBoxParameter::clear_scale_filler() {
+  if (scale_filler_ != NULL) scale_filler_->::caffe::FillerParameter::Clear();
+  clear_has_scale_filler();
+}
+const ::caffe::FillerParameter& NormalizeBBoxParameter::scale_filler() const {
+  // @@protoc_insertion_point(field_get:caffe.NormalizeBBoxParameter.scale_filler)
+  return scale_filler_ != NULL ? *scale_filler_
+                         : *::caffe::FillerParameter::internal_default_instance();
+}
+::caffe::FillerParameter* NormalizeBBoxParameter::mutable_scale_filler() {
+  set_has_scale_filler();
+  if (scale_filler_ == NULL) {
+    scale_filler_ = new ::caffe::FillerParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.NormalizeBBoxParameter.scale_filler)
+  return scale_filler_;
+}
+::caffe::FillerParameter* NormalizeBBoxParameter::release_scale_filler() {
+  // @@protoc_insertion_point(field_release:caffe.NormalizeBBoxParameter.scale_filler)
+  clear_has_scale_filler();
+  ::caffe::FillerParameter* temp = scale_filler_;
+  scale_filler_ = NULL;
+  return temp;
+}
+void NormalizeBBoxParameter::set_allocated_scale_filler(::caffe::FillerParameter* scale_filler) {
+  delete scale_filler_;
+  scale_filler_ = scale_filler;
+  if (scale_filler) {
+    set_has_scale_filler();
+  } else {
+    clear_has_scale_filler();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.NormalizeBBoxParameter.scale_filler)
+}
+
+// optional bool channel_shared = 3 [default = true];
+bool NormalizeBBoxParameter::has_channel_shared() const {
+  return (_has_bits_[0] & 0x00000004u) != 0;
+}
+void NormalizeBBoxParameter::set_has_channel_shared() {
+  _has_bits_[0] |= 0x00000004u;
+}
+void NormalizeBBoxParameter::clear_has_channel_shared() {
+  _has_bits_[0] &= ~0x00000004u;
+}
+void NormalizeBBoxParameter::clear_channel_shared() {
+  channel_shared_ = true;
+  clear_has_channel_shared();
+}
+bool NormalizeBBoxParameter::channel_shared() const {
+  // @@protoc_insertion_point(field_get:caffe.NormalizeBBoxParameter.channel_shared)
+  return channel_shared_;
+}
+void NormalizeBBoxParameter::set_channel_shared(bool value) {
+  set_has_channel_shared();
+  channel_shared_ = value;
+  // @@protoc_insertion_point(field_set:caffe.NormalizeBBoxParameter.channel_shared)
+}
+
+// optional float eps = 4 [default = 1e-10];
+bool NormalizeBBoxParameter::has_eps() const {
+  return (_has_bits_[0] & 0x00000008u) != 0;
+}
+void NormalizeBBoxParameter::set_has_eps() {
+  _has_bits_[0] |= 0x00000008u;
+}
+void NormalizeBBoxParameter::clear_has_eps() {
+  _has_bits_[0] &= ~0x00000008u;
+}
+void NormalizeBBoxParameter::clear_eps() {
+  eps_ = 1e-10f;
+  clear_has_eps();
+}
+float NormalizeBBoxParameter::eps() const {
+  // @@protoc_insertion_point(field_get:caffe.NormalizeBBoxParameter.eps)
+  return eps_;
+}
+void NormalizeBBoxParameter::set_eps(float value) {
+  set_has_eps();
+  eps_ = value;
+  // @@protoc_insertion_point(field_set:caffe.NormalizeBBoxParameter.eps)
+}
+
+inline const NormalizeBBoxParameter* NormalizeBBoxParameter::internal_default_instance() {
+  return &NormalizeBBoxParameter_default_instance_.get();
+}
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
+
+// ===================================================================
+
+const ::google::protobuf::EnumDescriptor* PriorBoxParameter_CodeType_descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return PriorBoxParameter_CodeType_descriptor_;
+}
+bool PriorBoxParameter_CodeType_IsValid(int value) {
+  switch (value) {
+    case 1:
+    case 2:
+      return true;
+    default:
+      return false;
+  }
+}
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const PriorBoxParameter_CodeType PriorBoxParameter::CORNER;
+const PriorBoxParameter_CodeType PriorBoxParameter::CENTER_SIZE;
+const PriorBoxParameter_CodeType PriorBoxParameter::CodeType_MIN;
+const PriorBoxParameter_CodeType PriorBoxParameter::CodeType_MAX;
+const int PriorBoxParameter::CodeType_ARRAYSIZE;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const int PriorBoxParameter::kMinSizeFieldNumber;
+const int PriorBoxParameter::kMaxSizeFieldNumber;
+const int PriorBoxParameter::kAspectRatioFieldNumber;
+const int PriorBoxParameter::kFlipFieldNumber;
+const int PriorBoxParameter::kClipFieldNumber;
+const int PriorBoxParameter::kVarianceFieldNumber;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+
+PriorBoxParameter::PriorBoxParameter()
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+  if (this != internal_default_instance()) protobuf_InitDefaults_caffe_2eproto();
+  SharedCtor();
+  // @@protoc_insertion_point(constructor:caffe.PriorBoxParameter)
+}
+
+void PriorBoxParameter::InitAsDefaultInstance() {
+}
+
+PriorBoxParameter::PriorBoxParameter(const PriorBoxParameter& from)
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
+  SharedCtor();
+  UnsafeMergeFrom(from);
+  // @@protoc_insertion_point(copy_constructor:caffe.PriorBoxParameter)
+}
+
+void PriorBoxParameter::SharedCtor() {
+  _cached_size_ = 0;
+  ::memset(&min_size_, 0, reinterpret_cast<char*>(&max_size_) -
+    reinterpret_cast<char*>(&min_size_) + sizeof(max_size_));
+  flip_ = true;
+  clip_ = true;
+}
+
+PriorBoxParameter::~PriorBoxParameter() {
+  // @@protoc_insertion_point(destructor:caffe.PriorBoxParameter)
+  SharedDtor();
+}
+
+void PriorBoxParameter::SharedDtor() {
+}
+
+void PriorBoxParameter::SetCachedSize(int size) const {
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* PriorBoxParameter::descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return PriorBoxParameter_descriptor_;
+}
+
+const PriorBoxParameter& PriorBoxParameter::default_instance() {
+  protobuf_InitDefaults_caffe_2eproto();
+  return *internal_default_instance();
+}
+
+::google::protobuf::internal::ExplicitlyConstructed<PriorBoxParameter> PriorBoxParameter_default_instance_;
+
+PriorBoxParameter* PriorBoxParameter::New(::google::protobuf::Arena* arena) const {
+  PriorBoxParameter* n = new PriorBoxParameter;
+  if (arena != NULL) {
+    arena->Own(n);
+  }
+  return n;
+}
+
+void PriorBoxParameter::Clear() {
+// @@protoc_insertion_point(message_clear_start:caffe.PriorBoxParameter)
+#if defined(__clang__)
+#define ZR_HELPER_(f) \
+  _Pragma("clang diagnostic push") \
+  _Pragma("clang diagnostic ignored \"-Winvalid-offsetof\"") \
+  __builtin_offsetof(PriorBoxParameter, f) \
+  _Pragma("clang diagnostic pop")
+#else
+#define ZR_HELPER_(f) reinterpret_cast<char*>(\
+  &reinterpret_cast<PriorBoxParameter*>(16)->f)
+#endif
+
+#define ZR_(first, last) do {\
+  ::memset(&(first), 0,\
+           ZR_HELPER_(last) - ZR_HELPER_(first) + sizeof(last));\
+} while (0)
+
+  if (_has_bits_[0 / 32] & 27u) {
+    ZR_(min_size_, max_size_);
+    flip_ = true;
+    clip_ = true;
+  }
+
+#undef ZR_HELPER_
+#undef ZR_
+
+  aspect_ratio_.Clear();
+  variance_.Clear();
+  _has_bits_.Clear();
+  if (_internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->Clear();
+  }
+}
+
+bool PriorBoxParameter::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
+  ::google::protobuf::uint32 tag;
+  // @@protoc_insertion_point(parse_start:caffe.PriorBoxParameter)
+  for (;;) {
+    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+    tag = p.first;
+    if (!p.second) goto handle_unusual;
+    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+      // optional float min_size = 1;
+      case 1: {
+        if (tag == 13) {
+          set_has_min_size();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
+                 input, &min_size_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(21)) goto parse_max_size;
+        break;
+      }
+
+      // optional float max_size = 2;
+      case 2: {
+        if (tag == 21) {
+         parse_max_size:
+          set_has_max_size();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
+                 input, &max_size_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(29)) goto parse_aspect_ratio;
+        break;
+      }
+
+      // repeated float aspect_ratio = 3;
+      case 3: {
+        if (tag == 29) {
+         parse_aspect_ratio:
+          DO_((::google::protobuf::internal::WireFormatLite::ReadRepeatedPrimitive<
+                   float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
+                 1, 29, input, this->mutable_aspect_ratio())));
+        } else if (tag == 26) {
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPackedPrimitiveNoInline<
+                   float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
+                 input, this->mutable_aspect_ratio())));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(29)) goto parse_aspect_ratio;
+        if (input->ExpectTag(32)) goto parse_flip;
+        break;
+      }
+
+      // optional bool flip = 4 [default = true];
+      case 4: {
+        if (tag == 32) {
+         parse_flip:
+          set_has_flip();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>(
+                 input, &flip_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(40)) goto parse_clip;
+        break;
+      }
+
+      // optional bool clip = 5 [default = true];
+      case 5: {
+        if (tag == 40) {
+         parse_clip:
+          set_has_clip();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>(
+                 input, &clip_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(53)) goto parse_variance;
+        break;
+      }
+
+      // repeated float variance = 6;
+      case 6: {
+        if (tag == 53) {
+         parse_variance:
+          DO_((::google::protobuf::internal::WireFormatLite::ReadRepeatedPrimitive<
+                   float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
+                 1, 53, input, this->mutable_variance())));
+        } else if (tag == 50) {
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPackedPrimitiveNoInline<
+                   float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
+                 input, this->mutable_variance())));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(53)) goto parse_variance;
+        if (input->ExpectAtEnd()) goto success;
+        break;
+      }
+
+      default: {
+      handle_unusual:
+        if (tag == 0 ||
+            ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+          goto success;
+        }
+        DO_(::google::protobuf::internal::WireFormat::SkipField(
+              input, tag, mutable_unknown_fields()));
+        break;
+      }
+    }
+  }
+success:
+  // @@protoc_insertion_point(parse_success:caffe.PriorBoxParameter)
+  return true;
+failure:
+  // @@protoc_insertion_point(parse_failure:caffe.PriorBoxParameter)
+  return false;
+#undef DO_
+}
+
+void PriorBoxParameter::SerializeWithCachedSizes(
+    ::google::protobuf::io::CodedOutputStream* output) const {
+  // @@protoc_insertion_point(serialize_start:caffe.PriorBoxParameter)
+  // optional float min_size = 1;
+  if (has_min_size()) {
+    ::google::protobuf::internal::WireFormatLite::WriteFloat(1, this->min_size(), output);
+  }
+
+  // optional float max_size = 2;
+  if (has_max_size()) {
+    ::google::protobuf::internal::WireFormatLite::WriteFloat(2, this->max_size(), output);
+  }
+
+  // repeated float aspect_ratio = 3;
+  for (int i = 0; i < this->aspect_ratio_size(); i++) {
+    ::google::protobuf::internal::WireFormatLite::WriteFloat(
+      3, this->aspect_ratio(i), output);
+  }
+
+  // optional bool flip = 4 [default = true];
+  if (has_flip()) {
+    ::google::protobuf::internal::WireFormatLite::WriteBool(4, this->flip(), output);
+  }
+
+  // optional bool clip = 5 [default = true];
+  if (has_clip()) {
+    ::google::protobuf::internal::WireFormatLite::WriteBool(5, this->clip(), output);
+  }
+
+  // repeated float variance = 6;
+  for (int i = 0; i < this->variance_size(); i++) {
+    ::google::protobuf::internal::WireFormatLite::WriteFloat(
+      6, this->variance(i), output);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
+        unknown_fields(), output);
+  }
+  // @@protoc_insertion_point(serialize_end:caffe.PriorBoxParameter)
+}
+
+::google::protobuf::uint8* PriorBoxParameter::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
+  (void)deterministic; // Unused
+  // @@protoc_insertion_point(serialize_to_array_start:caffe.PriorBoxParameter)
+  // optional float min_size = 1;
+  if (has_min_size()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteFloatToArray(1, this->min_size(), target);
+  }
+
+  // optional float max_size = 2;
+  if (has_max_size()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteFloatToArray(2, this->max_size(), target);
+  }
+
+  // repeated float aspect_ratio = 3;
+  for (int i = 0; i < this->aspect_ratio_size(); i++) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      WriteFloatToArray(3, this->aspect_ratio(i), target);
+  }
+
+  // optional bool flip = 4 [default = true];
+  if (has_flip()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(4, this->flip(), target);
+  }
+
+  // optional bool clip = 5 [default = true];
+  if (has_clip()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(5, this->clip(), target);
+  }
+
+  // repeated float variance = 6;
+  for (int i = 0; i < this->variance_size(); i++) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      WriteFloatToArray(6, this->variance(i), target);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
+        unknown_fields(), target);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:caffe.PriorBoxParameter)
+  return target;
+}
+
+size_t PriorBoxParameter::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:caffe.PriorBoxParameter)
+  size_t total_size = 0;
+
+  if (_has_bits_[0 / 32] & 27u) {
+    // optional float min_size = 1;
+    if (has_min_size()) {
+      total_size += 1 + 4;
+    }
+
+    // optional float max_size = 2;
+    if (has_max_size()) {
+      total_size += 1 + 4;
+    }
+
+    // optional bool flip = 4 [default = true];
+    if (has_flip()) {
+      total_size += 1 + 1;
+    }
+
+    // optional bool clip = 5 [default = true];
+    if (has_clip()) {
+      total_size += 1 + 1;
+    }
+
+  }
+  // repeated float aspect_ratio = 3;
+  {
+    size_t data_size = 0;
+    unsigned int count = this->aspect_ratio_size();
+    data_size = 4UL * count;
+    total_size += 1 *
+                  ::google::protobuf::internal::FromIntSize(this->aspect_ratio_size());
+    total_size += data_size;
+  }
+
+  // repeated float variance = 6;
+  {
+    size_t data_size = 0;
+    unsigned int count = this->variance_size();
+    data_size = 4UL * count;
+    total_size += 1 *
+                  ::google::protobuf::internal::FromIntSize(this->variance_size());
+    total_size += data_size;
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    total_size +=
+      ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
+        unknown_fields());
+  }
+  int cached_size = ::google::protobuf::internal::ToCachedSize(total_size);
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = cached_size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+  return total_size;
+}
+
+void PriorBoxParameter::MergeFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_merge_from_start:caffe.PriorBoxParameter)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const PriorBoxParameter* source =
+      ::google::protobuf::internal::DynamicCastToGenerated<const PriorBoxParameter>(
+          &from);
+  if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:caffe.PriorBoxParameter)
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:caffe.PriorBoxParameter)
+    UnsafeMergeFrom(*source);
+  }
+}
+
+void PriorBoxParameter::MergeFrom(const PriorBoxParameter& from) {
+// @@protoc_insertion_point(class_specific_merge_from_start:caffe.PriorBoxParameter)
+  if (GOOGLE_PREDICT_TRUE(&from != this)) {
+    UnsafeMergeFrom(from);
+  } else {
+    MergeFromFail(__LINE__);
+  }
+}
+
+void PriorBoxParameter::UnsafeMergeFrom(const PriorBoxParameter& from) {
+  GOOGLE_DCHECK(&from != this);
+  aspect_ratio_.UnsafeMergeFrom(from.aspect_ratio_);
+  variance_.UnsafeMergeFrom(from.variance_);
+  if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+    if (from.has_min_size()) {
+      set_min_size(from.min_size());
+    }
+    if (from.has_max_size()) {
+      set_max_size(from.max_size());
+    }
+    if (from.has_flip()) {
+      set_flip(from.flip());
+    }
+    if (from.has_clip()) {
+      set_clip(from.clip());
+    }
+  }
+  if (from._internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::UnknownFieldSet::MergeToInternalMetdata(
+      from.unknown_fields(), &_internal_metadata_);
+  }
+}
+
+void PriorBoxParameter::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:caffe.PriorBoxParameter)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void PriorBoxParameter::CopyFrom(const PriorBoxParameter& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:caffe.PriorBoxParameter)
+  if (&from == this) return;
+  Clear();
+  UnsafeMergeFrom(from);
+}
+
+bool PriorBoxParameter::IsInitialized() const {
+
+  return true;
+}
+
+void PriorBoxParameter::Swap(PriorBoxParameter* other) {
+  if (other == this) return;
+  InternalSwap(other);
+}
+void PriorBoxParameter::InternalSwap(PriorBoxParameter* other) {
+  std::swap(min_size_, other->min_size_);
+  std::swap(max_size_, other->max_size_);
+  aspect_ratio_.UnsafeArenaSwap(&other->aspect_ratio_);
+  std::swap(flip_, other->flip_);
+  std::swap(clip_, other->clip_);
+  variance_.UnsafeArenaSwap(&other->variance_);
+  std::swap(_has_bits_[0], other->_has_bits_[0]);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
+}
+
+::google::protobuf::Metadata PriorBoxParameter::GetMetadata() const {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::Metadata metadata;
+  metadata.descriptor = PriorBoxParameter_descriptor_;
+  metadata.reflection = PriorBoxParameter_reflection_;
+  return metadata;
+}
+
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// PriorBoxParameter
+
+// optional float min_size = 1;
+bool PriorBoxParameter::has_min_size() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+void PriorBoxParameter::set_has_min_size() {
+  _has_bits_[0] |= 0x00000001u;
+}
+void PriorBoxParameter::clear_has_min_size() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+void PriorBoxParameter::clear_min_size() {
+  min_size_ = 0;
+  clear_has_min_size();
+}
+float PriorBoxParameter::min_size() const {
+  // @@protoc_insertion_point(field_get:caffe.PriorBoxParameter.min_size)
+  return min_size_;
+}
+void PriorBoxParameter::set_min_size(float value) {
+  set_has_min_size();
+  min_size_ = value;
+  // @@protoc_insertion_point(field_set:caffe.PriorBoxParameter.min_size)
+}
+
+// optional float max_size = 2;
+bool PriorBoxParameter::has_max_size() const {
+  return (_has_bits_[0] & 0x00000002u) != 0;
+}
+void PriorBoxParameter::set_has_max_size() {
+  _has_bits_[0] |= 0x00000002u;
+}
+void PriorBoxParameter::clear_has_max_size() {
+  _has_bits_[0] &= ~0x00000002u;
+}
+void PriorBoxParameter::clear_max_size() {
+  max_size_ = 0;
+  clear_has_max_size();
+}
+float PriorBoxParameter::max_size() const {
+  // @@protoc_insertion_point(field_get:caffe.PriorBoxParameter.max_size)
+  return max_size_;
+}
+void PriorBoxParameter::set_max_size(float value) {
+  set_has_max_size();
+  max_size_ = value;
+  // @@protoc_insertion_point(field_set:caffe.PriorBoxParameter.max_size)
+}
+
+// repeated float aspect_ratio = 3;
+int PriorBoxParameter::aspect_ratio_size() const {
+  return aspect_ratio_.size();
+}
+void PriorBoxParameter::clear_aspect_ratio() {
+  aspect_ratio_.Clear();
+}
+float PriorBoxParameter::aspect_ratio(int index) const {
+  // @@protoc_insertion_point(field_get:caffe.PriorBoxParameter.aspect_ratio)
+  return aspect_ratio_.Get(index);
+}
+void PriorBoxParameter::set_aspect_ratio(int index, float value) {
+  aspect_ratio_.Set(index, value);
+  // @@protoc_insertion_point(field_set:caffe.PriorBoxParameter.aspect_ratio)
+}
+void PriorBoxParameter::add_aspect_ratio(float value) {
+  aspect_ratio_.Add(value);
+  // @@protoc_insertion_point(field_add:caffe.PriorBoxParameter.aspect_ratio)
+}
+const ::google::protobuf::RepeatedField< float >&
+PriorBoxParameter::aspect_ratio() const {
+  // @@protoc_insertion_point(field_list:caffe.PriorBoxParameter.aspect_ratio)
+  return aspect_ratio_;
+}
+::google::protobuf::RepeatedField< float >*
+PriorBoxParameter::mutable_aspect_ratio() {
+  // @@protoc_insertion_point(field_mutable_list:caffe.PriorBoxParameter.aspect_ratio)
+  return &aspect_ratio_;
+}
+
+// optional bool flip = 4 [default = true];
+bool PriorBoxParameter::has_flip() const {
+  return (_has_bits_[0] & 0x00000008u) != 0;
+}
+void PriorBoxParameter::set_has_flip() {
+  _has_bits_[0] |= 0x00000008u;
+}
+void PriorBoxParameter::clear_has_flip() {
+  _has_bits_[0] &= ~0x00000008u;
+}
+void PriorBoxParameter::clear_flip() {
+  flip_ = true;
+  clear_has_flip();
+}
+bool PriorBoxParameter::flip() const {
+  // @@protoc_insertion_point(field_get:caffe.PriorBoxParameter.flip)
+  return flip_;
+}
+void PriorBoxParameter::set_flip(bool value) {
+  set_has_flip();
+  flip_ = value;
+  // @@protoc_insertion_point(field_set:caffe.PriorBoxParameter.flip)
+}
+
+// optional bool clip = 5 [default = true];
+bool PriorBoxParameter::has_clip() const {
+  return (_has_bits_[0] & 0x00000010u) != 0;
+}
+void PriorBoxParameter::set_has_clip() {
+  _has_bits_[0] |= 0x00000010u;
+}
+void PriorBoxParameter::clear_has_clip() {
+  _has_bits_[0] &= ~0x00000010u;
+}
+void PriorBoxParameter::clear_clip() {
+  clip_ = true;
+  clear_has_clip();
+}
+bool PriorBoxParameter::clip() const {
+  // @@protoc_insertion_point(field_get:caffe.PriorBoxParameter.clip)
+  return clip_;
+}
+void PriorBoxParameter::set_clip(bool value) {
+  set_has_clip();
+  clip_ = value;
+  // @@protoc_insertion_point(field_set:caffe.PriorBoxParameter.clip)
+}
+
+// repeated float variance = 6;
+int PriorBoxParameter::variance_size() const {
+  return variance_.size();
+}
+void PriorBoxParameter::clear_variance() {
+  variance_.Clear();
+}
+float PriorBoxParameter::variance(int index) const {
+  // @@protoc_insertion_point(field_get:caffe.PriorBoxParameter.variance)
+  return variance_.Get(index);
+}
+void PriorBoxParameter::set_variance(int index, float value) {
+  variance_.Set(index, value);
+  // @@protoc_insertion_point(field_set:caffe.PriorBoxParameter.variance)
+}
+void PriorBoxParameter::add_variance(float value) {
+  variance_.Add(value);
+  // @@protoc_insertion_point(field_add:caffe.PriorBoxParameter.variance)
+}
+const ::google::protobuf::RepeatedField< float >&
+PriorBoxParameter::variance() const {
+  // @@protoc_insertion_point(field_list:caffe.PriorBoxParameter.variance)
+  return variance_;
+}
+::google::protobuf::RepeatedField< float >*
+PriorBoxParameter::mutable_variance() {
+  // @@protoc_insertion_point(field_mutable_list:caffe.PriorBoxParameter.variance)
+  return &variance_;
+}
+
+inline const PriorBoxParameter* PriorBoxParameter::internal_default_instance() {
+  return &PriorBoxParameter_default_instance_.get();
+}
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
+
+// ===================================================================
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const int DetectionOutputParameter::kNumClassesFieldNumber;
+const int DetectionOutputParameter::kShareLocationFieldNumber;
+const int DetectionOutputParameter::kBackgroundLabelIdFieldNumber;
+const int DetectionOutputParameter::kCodeTypeFieldNumber;
+const int DetectionOutputParameter::kVarianceEncodedInTargetFieldNumber;
+const int DetectionOutputParameter::kKeepTopKFieldNumber;
+const int DetectionOutputParameter::kConfidenceThresholdFieldNumber;
+const int DetectionOutputParameter::kNmsThresholdFieldNumber;
+const int DetectionOutputParameter::kTopKFieldNumber;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+
+DetectionOutputParameter::DetectionOutputParameter()
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+  if (this != internal_default_instance()) protobuf_InitDefaults_caffe_2eproto();
+  SharedCtor();
+  // @@protoc_insertion_point(constructor:caffe.DetectionOutputParameter)
+}
+
+void DetectionOutputParameter::InitAsDefaultInstance() {
+}
+
+DetectionOutputParameter::DetectionOutputParameter(const DetectionOutputParameter& from)
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
+  SharedCtor();
+  UnsafeMergeFrom(from);
+  // @@protoc_insertion_point(copy_constructor:caffe.DetectionOutputParameter)
+}
+
+void DetectionOutputParameter::SharedCtor() {
+  _cached_size_ = 0;
+  ::memset(&num_classes_, 0, reinterpret_cast<char*>(&top_k_) -
+    reinterpret_cast<char*>(&num_classes_) + sizeof(top_k_));
+  share_location_ = true;
+  code_type_ = 1;
+  keep_top_k_ = -1;
+  nms_threshold_ = 0.3f;
+}
+
+DetectionOutputParameter::~DetectionOutputParameter() {
+  // @@protoc_insertion_point(destructor:caffe.DetectionOutputParameter)
+  SharedDtor();
+}
+
+void DetectionOutputParameter::SharedDtor() {
+}
+
+void DetectionOutputParameter::SetCachedSize(int size) const {
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* DetectionOutputParameter::descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return DetectionOutputParameter_descriptor_;
+}
+
+const DetectionOutputParameter& DetectionOutputParameter::default_instance() {
+  protobuf_InitDefaults_caffe_2eproto();
+  return *internal_default_instance();
+}
+
+::google::protobuf::internal::ExplicitlyConstructed<DetectionOutputParameter> DetectionOutputParameter_default_instance_;
+
+DetectionOutputParameter* DetectionOutputParameter::New(::google::protobuf::Arena* arena) const {
+  DetectionOutputParameter* n = new DetectionOutputParameter;
+  if (arena != NULL) {
+    arena->Own(n);
+  }
+  return n;
+}
+
+void DetectionOutputParameter::Clear() {
+// @@protoc_insertion_point(message_clear_start:caffe.DetectionOutputParameter)
+#if defined(__clang__)
+#define ZR_HELPER_(f) \
+  _Pragma("clang diagnostic push") \
+  _Pragma("clang diagnostic ignored \"-Winvalid-offsetof\"") \
+  __builtin_offsetof(DetectionOutputParameter, f) \
+  _Pragma("clang diagnostic pop")
+#else
+#define ZR_HELPER_(f) reinterpret_cast<char*>(\
+  &reinterpret_cast<DetectionOutputParameter*>(16)->f)
+#endif
+
+#define ZR_(first, last) do {\
+  ::memset(&(first), 0,\
+           ZR_HELPER_(last) - ZR_HELPER_(first) + sizeof(last));\
+} while (0)
+
+  if (_has_bits_[0 / 32] & 255u) {
+    ZR_(num_classes_, confidence_threshold_);
+    share_location_ = true;
+    code_type_ = 1;
+    keep_top_k_ = -1;
+    nms_threshold_ = 0.3f;
+  }
+  top_k_ = 0;
+
+#undef ZR_HELPER_
+#undef ZR_
+
+  _has_bits_.Clear();
+  if (_internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->Clear();
+  }
+}
+
+bool DetectionOutputParameter::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
+  ::google::protobuf::uint32 tag;
+  // @@protoc_insertion_point(parse_start:caffe.DetectionOutputParameter)
+  for (;;) {
+    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+    tag = p.first;
+    if (!p.second) goto handle_unusual;
+    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+      // optional uint32 num_classes = 1;
+      case 1: {
+        if (tag == 8) {
+          set_has_num_classes();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>(
+                 input, &num_classes_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(16)) goto parse_share_location;
+        break;
+      }
+
+      // optional bool share_location = 2 [default = true];
+      case 2: {
+        if (tag == 16) {
+         parse_share_location:
+          set_has_share_location();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>(
+                 input, &share_location_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(24)) goto parse_background_label_id;
+        break;
+      }
+
+      // optional int32 background_label_id = 3 [default = 0];
+      case 3: {
+        if (tag == 24) {
+         parse_background_label_id:
+          set_has_background_label_id();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
+                 input, &background_label_id_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(48)) goto parse_code_type;
+        break;
+      }
+
+      // optional .caffe.PriorBoxParameter.CodeType code_type = 6 [default = CORNER];
+      case 6: {
+        if (tag == 48) {
+         parse_code_type:
+          int value;
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>(
+                 input, &value)));
+          if (::caffe::PriorBoxParameter_CodeType_IsValid(value)) {
+            set_code_type(static_cast< ::caffe::PriorBoxParameter_CodeType >(value));
+          } else {
+            mutable_unknown_fields()->AddVarint(6, value);
+          }
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(56)) goto parse_keep_top_k;
+        break;
+      }
+
+      // optional int32 keep_top_k = 7 [default = -1];
+      case 7: {
+        if (tag == 56) {
+         parse_keep_top_k:
+          set_has_keep_top_k();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
+                 input, &keep_top_k_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(64)) goto parse_variance_encoded_in_target;
+        break;
+      }
+
+      // optional bool variance_encoded_in_target = 8 [default = false];
+      case 8: {
+        if (tag == 64) {
+         parse_variance_encoded_in_target:
+          set_has_variance_encoded_in_target();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>(
+                 input, &variance_encoded_in_target_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(77)) goto parse_confidence_threshold;
+        break;
+      }
+
+      // optional float confidence_threshold = 9;
+      case 9: {
+        if (tag == 77) {
+         parse_confidence_threshold:
+          set_has_confidence_threshold();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
+                 input, &confidence_threshold_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(85)) goto parse_nms_threshold;
+        break;
+      }
+
+      // optional float nms_threshold = 10 [default = 0.3];
+      case 10: {
+        if (tag == 85) {
+         parse_nms_threshold:
+          set_has_nms_threshold();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
+                 input, &nms_threshold_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(88)) goto parse_top_k;
+        break;
+      }
+
+      // optional int32 top_k = 11;
+      case 11: {
+        if (tag == 88) {
+         parse_top_k:
+          set_has_top_k();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
+                 input, &top_k_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectAtEnd()) goto success;
+        break;
+      }
+
+      default: {
+      handle_unusual:
+        if (tag == 0 ||
+            ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+          goto success;
+        }
+        DO_(::google::protobuf::internal::WireFormat::SkipField(
+              input, tag, mutable_unknown_fields()));
+        break;
+      }
+    }
+  }
+success:
+  // @@protoc_insertion_point(parse_success:caffe.DetectionOutputParameter)
+  return true;
+failure:
+  // @@protoc_insertion_point(parse_failure:caffe.DetectionOutputParameter)
+  return false;
+#undef DO_
+}
+
+void DetectionOutputParameter::SerializeWithCachedSizes(
+    ::google::protobuf::io::CodedOutputStream* output) const {
+  // @@protoc_insertion_point(serialize_start:caffe.DetectionOutputParameter)
+  // optional uint32 num_classes = 1;
+  if (has_num_classes()) {
+    ::google::protobuf::internal::WireFormatLite::WriteUInt32(1, this->num_classes(), output);
+  }
+
+  // optional bool share_location = 2 [default = true];
+  if (has_share_location()) {
+    ::google::protobuf::internal::WireFormatLite::WriteBool(2, this->share_location(), output);
+  }
+
+  // optional int32 background_label_id = 3 [default = 0];
+  if (has_background_label_id()) {
+    ::google::protobuf::internal::WireFormatLite::WriteInt32(3, this->background_label_id(), output);
+  }
+
+  // optional .caffe.PriorBoxParameter.CodeType code_type = 6 [default = CORNER];
+  if (has_code_type()) {
+    ::google::protobuf::internal::WireFormatLite::WriteEnum(
+      6, this->code_type(), output);
+  }
+
+  // optional int32 keep_top_k = 7 [default = -1];
+  if (has_keep_top_k()) {
+    ::google::protobuf::internal::WireFormatLite::WriteInt32(7, this->keep_top_k(), output);
+  }
+
+  // optional bool variance_encoded_in_target = 8 [default = false];
+  if (has_variance_encoded_in_target()) {
+    ::google::protobuf::internal::WireFormatLite::WriteBool(8, this->variance_encoded_in_target(), output);
+  }
+
+  // optional float confidence_threshold = 9;
+  if (has_confidence_threshold()) {
+    ::google::protobuf::internal::WireFormatLite::WriteFloat(9, this->confidence_threshold(), output);
+  }
+
+  // optional float nms_threshold = 10 [default = 0.3];
+  if (has_nms_threshold()) {
+    ::google::protobuf::internal::WireFormatLite::WriteFloat(10, this->nms_threshold(), output);
+  }
+
+  // optional int32 top_k = 11;
+  if (has_top_k()) {
+    ::google::protobuf::internal::WireFormatLite::WriteInt32(11, this->top_k(), output);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
+        unknown_fields(), output);
+  }
+  // @@protoc_insertion_point(serialize_end:caffe.DetectionOutputParameter)
+}
+
+::google::protobuf::uint8* DetectionOutputParameter::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
+  (void)deterministic; // Unused
+  // @@protoc_insertion_point(serialize_to_array_start:caffe.DetectionOutputParameter)
+  // optional uint32 num_classes = 1;
+  if (has_num_classes()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteUInt32ToArray(1, this->num_classes(), target);
+  }
+
+  // optional bool share_location = 2 [default = true];
+  if (has_share_location()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(2, this->share_location(), target);
+  }
+
+  // optional int32 background_label_id = 3 [default = 0];
+  if (has_background_label_id()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteInt32ToArray(3, this->background_label_id(), target);
+  }
+
+  // optional .caffe.PriorBoxParameter.CodeType code_type = 6 [default = CORNER];
+  if (has_code_type()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteEnumToArray(
+      6, this->code_type(), target);
+  }
+
+  // optional int32 keep_top_k = 7 [default = -1];
+  if (has_keep_top_k()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteInt32ToArray(7, this->keep_top_k(), target);
+  }
+
+  // optional bool variance_encoded_in_target = 8 [default = false];
+  if (has_variance_encoded_in_target()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(8, this->variance_encoded_in_target(), target);
+  }
+
+  // optional float confidence_threshold = 9;
+  if (has_confidence_threshold()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteFloatToArray(9, this->confidence_threshold(), target);
+  }
+
+  // optional float nms_threshold = 10 [default = 0.3];
+  if (has_nms_threshold()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteFloatToArray(10, this->nms_threshold(), target);
+  }
+
+  // optional int32 top_k = 11;
+  if (has_top_k()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteInt32ToArray(11, this->top_k(), target);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
+        unknown_fields(), target);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:caffe.DetectionOutputParameter)
+  return target;
+}
+
+size_t DetectionOutputParameter::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:caffe.DetectionOutputParameter)
+  size_t total_size = 0;
+
+  if (_has_bits_[0 / 32] & 255u) {
+    // optional uint32 num_classes = 1;
+    if (has_num_classes()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::UInt32Size(
+          this->num_classes());
+    }
+
+    // optional bool share_location = 2 [default = true];
+    if (has_share_location()) {
+      total_size += 1 + 1;
+    }
+
+    // optional int32 background_label_id = 3 [default = 0];
+    if (has_background_label_id()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::Int32Size(
+          this->background_label_id());
+    }
+
+    // optional .caffe.PriorBoxParameter.CodeType code_type = 6 [default = CORNER];
+    if (has_code_type()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::EnumSize(this->code_type());
+    }
+
+    // optional bool variance_encoded_in_target = 8 [default = false];
+    if (has_variance_encoded_in_target()) {
+      total_size += 1 + 1;
+    }
+
+    // optional int32 keep_top_k = 7 [default = -1];
+    if (has_keep_top_k()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::Int32Size(
+          this->keep_top_k());
+    }
+
+    // optional float confidence_threshold = 9;
+    if (has_confidence_threshold()) {
+      total_size += 1 + 4;
+    }
+
+    // optional float nms_threshold = 10 [default = 0.3];
+    if (has_nms_threshold()) {
+      total_size += 1 + 4;
+    }
+
+  }
+  // optional int32 top_k = 11;
+  if (has_top_k()) {
+    total_size += 1 +
+      ::google::protobuf::internal::WireFormatLite::Int32Size(
+        this->top_k());
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    total_size +=
+      ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
+        unknown_fields());
+  }
+  int cached_size = ::google::protobuf::internal::ToCachedSize(total_size);
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = cached_size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+  return total_size;
+}
+
+void DetectionOutputParameter::MergeFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_merge_from_start:caffe.DetectionOutputParameter)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const DetectionOutputParameter* source =
+      ::google::protobuf::internal::DynamicCastToGenerated<const DetectionOutputParameter>(
+          &from);
+  if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:caffe.DetectionOutputParameter)
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:caffe.DetectionOutputParameter)
+    UnsafeMergeFrom(*source);
+  }
+}
+
+void DetectionOutputParameter::MergeFrom(const DetectionOutputParameter& from) {
+// @@protoc_insertion_point(class_specific_merge_from_start:caffe.DetectionOutputParameter)
+  if (GOOGLE_PREDICT_TRUE(&from != this)) {
+    UnsafeMergeFrom(from);
+  } else {
+    MergeFromFail(__LINE__);
+  }
+}
+
+void DetectionOutputParameter::UnsafeMergeFrom(const DetectionOutputParameter& from) {
+  GOOGLE_DCHECK(&from != this);
+  if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+    if (from.has_num_classes()) {
+      set_num_classes(from.num_classes());
+    }
+    if (from.has_share_location()) {
+      set_share_location(from.share_location());
+    }
+    if (from.has_background_label_id()) {
+      set_background_label_id(from.background_label_id());
+    }
+    if (from.has_code_type()) {
+      set_code_type(from.code_type());
+    }
+    if (from.has_variance_encoded_in_target()) {
+      set_variance_encoded_in_target(from.variance_encoded_in_target());
+    }
+    if (from.has_keep_top_k()) {
+      set_keep_top_k(from.keep_top_k());
+    }
+    if (from.has_confidence_threshold()) {
+      set_confidence_threshold(from.confidence_threshold());
+    }
+    if (from.has_nms_threshold()) {
+      set_nms_threshold(from.nms_threshold());
+    }
+  }
+  if (from._has_bits_[8 / 32] & (0xffu << (8 % 32))) {
+    if (from.has_top_k()) {
+      set_top_k(from.top_k());
+    }
+  }
+  if (from._internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::UnknownFieldSet::MergeToInternalMetdata(
+      from.unknown_fields(), &_internal_metadata_);
+  }
+}
+
+void DetectionOutputParameter::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:caffe.DetectionOutputParameter)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void DetectionOutputParameter::CopyFrom(const DetectionOutputParameter& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:caffe.DetectionOutputParameter)
+  if (&from == this) return;
+  Clear();
+  UnsafeMergeFrom(from);
+}
+
+bool DetectionOutputParameter::IsInitialized() const {
+
+  return true;
+}
+
+void DetectionOutputParameter::Swap(DetectionOutputParameter* other) {
+  if (other == this) return;
+  InternalSwap(other);
+}
+void DetectionOutputParameter::InternalSwap(DetectionOutputParameter* other) {
+  std::swap(num_classes_, other->num_classes_);
+  std::swap(share_location_, other->share_location_);
+  std::swap(background_label_id_, other->background_label_id_);
+  std::swap(code_type_, other->code_type_);
+  std::swap(variance_encoded_in_target_, other->variance_encoded_in_target_);
+  std::swap(keep_top_k_, other->keep_top_k_);
+  std::swap(confidence_threshold_, other->confidence_threshold_);
+  std::swap(nms_threshold_, other->nms_threshold_);
+  std::swap(top_k_, other->top_k_);
+  std::swap(_has_bits_[0], other->_has_bits_[0]);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
+}
+
+::google::protobuf::Metadata DetectionOutputParameter::GetMetadata() const {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::Metadata metadata;
+  metadata.descriptor = DetectionOutputParameter_descriptor_;
+  metadata.reflection = DetectionOutputParameter_reflection_;
+  return metadata;
+}
+
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// DetectionOutputParameter
+
+// optional uint32 num_classes = 1;
+bool DetectionOutputParameter::has_num_classes() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+void DetectionOutputParameter::set_has_num_classes() {
+  _has_bits_[0] |= 0x00000001u;
+}
+void DetectionOutputParameter::clear_has_num_classes() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+void DetectionOutputParameter::clear_num_classes() {
+  num_classes_ = 0u;
+  clear_has_num_classes();
+}
+::google::protobuf::uint32 DetectionOutputParameter::num_classes() const {
+  // @@protoc_insertion_point(field_get:caffe.DetectionOutputParameter.num_classes)
+  return num_classes_;
+}
+void DetectionOutputParameter::set_num_classes(::google::protobuf::uint32 value) {
+  set_has_num_classes();
+  num_classes_ = value;
+  // @@protoc_insertion_point(field_set:caffe.DetectionOutputParameter.num_classes)
+}
+
+// optional bool share_location = 2 [default = true];
+bool DetectionOutputParameter::has_share_location() const {
+  return (_has_bits_[0] & 0x00000002u) != 0;
+}
+void DetectionOutputParameter::set_has_share_location() {
+  _has_bits_[0] |= 0x00000002u;
+}
+void DetectionOutputParameter::clear_has_share_location() {
+  _has_bits_[0] &= ~0x00000002u;
+}
+void DetectionOutputParameter::clear_share_location() {
+  share_location_ = true;
+  clear_has_share_location();
+}
+bool DetectionOutputParameter::share_location() const {
+  // @@protoc_insertion_point(field_get:caffe.DetectionOutputParameter.share_location)
+  return share_location_;
+}
+void DetectionOutputParameter::set_share_location(bool value) {
+  set_has_share_location();
+  share_location_ = value;
+  // @@protoc_insertion_point(field_set:caffe.DetectionOutputParameter.share_location)
+}
+
+// optional int32 background_label_id = 3 [default = 0];
+bool DetectionOutputParameter::has_background_label_id() const {
+  return (_has_bits_[0] & 0x00000004u) != 0;
+}
+void DetectionOutputParameter::set_has_background_label_id() {
+  _has_bits_[0] |= 0x00000004u;
+}
+void DetectionOutputParameter::clear_has_background_label_id() {
+  _has_bits_[0] &= ~0x00000004u;
+}
+void DetectionOutputParameter::clear_background_label_id() {
+  background_label_id_ = 0;
+  clear_has_background_label_id();
+}
+::google::protobuf::int32 DetectionOutputParameter::background_label_id() const {
+  // @@protoc_insertion_point(field_get:caffe.DetectionOutputParameter.background_label_id)
+  return background_label_id_;
+}
+void DetectionOutputParameter::set_background_label_id(::google::protobuf::int32 value) {
+  set_has_background_label_id();
+  background_label_id_ = value;
+  // @@protoc_insertion_point(field_set:caffe.DetectionOutputParameter.background_label_id)
+}
+
+// optional .caffe.PriorBoxParameter.CodeType code_type = 6 [default = CORNER];
+bool DetectionOutputParameter::has_code_type() const {
+  return (_has_bits_[0] & 0x00000008u) != 0;
+}
+void DetectionOutputParameter::set_has_code_type() {
+  _has_bits_[0] |= 0x00000008u;
+}
+void DetectionOutputParameter::clear_has_code_type() {
+  _has_bits_[0] &= ~0x00000008u;
+}
+void DetectionOutputParameter::clear_code_type() {
+  code_type_ = 1;
+  clear_has_code_type();
+}
+::caffe::PriorBoxParameter_CodeType DetectionOutputParameter::code_type() const {
+  // @@protoc_insertion_point(field_get:caffe.DetectionOutputParameter.code_type)
+  return static_cast< ::caffe::PriorBoxParameter_CodeType >(code_type_);
+}
+void DetectionOutputParameter::set_code_type(::caffe::PriorBoxParameter_CodeType value) {
+  assert(::caffe::PriorBoxParameter_CodeType_IsValid(value));
+  set_has_code_type();
+  code_type_ = value;
+  // @@protoc_insertion_point(field_set:caffe.DetectionOutputParameter.code_type)
+}
+
+// optional bool variance_encoded_in_target = 8 [default = false];
+bool DetectionOutputParameter::has_variance_encoded_in_target() const {
+  return (_has_bits_[0] & 0x00000010u) != 0;
+}
+void DetectionOutputParameter::set_has_variance_encoded_in_target() {
+  _has_bits_[0] |= 0x00000010u;
+}
+void DetectionOutputParameter::clear_has_variance_encoded_in_target() {
+  _has_bits_[0] &= ~0x00000010u;
+}
+void DetectionOutputParameter::clear_variance_encoded_in_target() {
+  variance_encoded_in_target_ = false;
+  clear_has_variance_encoded_in_target();
+}
+bool DetectionOutputParameter::variance_encoded_in_target() const {
+  // @@protoc_insertion_point(field_get:caffe.DetectionOutputParameter.variance_encoded_in_target)
+  return variance_encoded_in_target_;
+}
+void DetectionOutputParameter::set_variance_encoded_in_target(bool value) {
+  set_has_variance_encoded_in_target();
+  variance_encoded_in_target_ = value;
+  // @@protoc_insertion_point(field_set:caffe.DetectionOutputParameter.variance_encoded_in_target)
+}
+
+// optional int32 keep_top_k = 7 [default = -1];
+bool DetectionOutputParameter::has_keep_top_k() const {
+  return (_has_bits_[0] & 0x00000020u) != 0;
+}
+void DetectionOutputParameter::set_has_keep_top_k() {
+  _has_bits_[0] |= 0x00000020u;
+}
+void DetectionOutputParameter::clear_has_keep_top_k() {
+  _has_bits_[0] &= ~0x00000020u;
+}
+void DetectionOutputParameter::clear_keep_top_k() {
+  keep_top_k_ = -1;
+  clear_has_keep_top_k();
+}
+::google::protobuf::int32 DetectionOutputParameter::keep_top_k() const {
+  // @@protoc_insertion_point(field_get:caffe.DetectionOutputParameter.keep_top_k)
+  return keep_top_k_;
+}
+void DetectionOutputParameter::set_keep_top_k(::google::protobuf::int32 value) {
+  set_has_keep_top_k();
+  keep_top_k_ = value;
+  // @@protoc_insertion_point(field_set:caffe.DetectionOutputParameter.keep_top_k)
+}
+
+// optional float confidence_threshold = 9;
+bool DetectionOutputParameter::has_confidence_threshold() const {
+  return (_has_bits_[0] & 0x00000040u) != 0;
+}
+void DetectionOutputParameter::set_has_confidence_threshold() {
+  _has_bits_[0] |= 0x00000040u;
+}
+void DetectionOutputParameter::clear_has_confidence_threshold() {
+  _has_bits_[0] &= ~0x00000040u;
+}
+void DetectionOutputParameter::clear_confidence_threshold() {
+  confidence_threshold_ = 0;
+  clear_has_confidence_threshold();
+}
+float DetectionOutputParameter::confidence_threshold() const {
+  // @@protoc_insertion_point(field_get:caffe.DetectionOutputParameter.confidence_threshold)
+  return confidence_threshold_;
+}
+void DetectionOutputParameter::set_confidence_threshold(float value) {
+  set_has_confidence_threshold();
+  confidence_threshold_ = value;
+  // @@protoc_insertion_point(field_set:caffe.DetectionOutputParameter.confidence_threshold)
+}
+
+// optional float nms_threshold = 10 [default = 0.3];
+bool DetectionOutputParameter::has_nms_threshold() const {
+  return (_has_bits_[0] & 0x00000080u) != 0;
+}
+void DetectionOutputParameter::set_has_nms_threshold() {
+  _has_bits_[0] |= 0x00000080u;
+}
+void DetectionOutputParameter::clear_has_nms_threshold() {
+  _has_bits_[0] &= ~0x00000080u;
+}
+void DetectionOutputParameter::clear_nms_threshold() {
+  nms_threshold_ = 0.3f;
+  clear_has_nms_threshold();
+}
+float DetectionOutputParameter::nms_threshold() const {
+  // @@protoc_insertion_point(field_get:caffe.DetectionOutputParameter.nms_threshold)
+  return nms_threshold_;
+}
+void DetectionOutputParameter::set_nms_threshold(float value) {
+  set_has_nms_threshold();
+  nms_threshold_ = value;
+  // @@protoc_insertion_point(field_set:caffe.DetectionOutputParameter.nms_threshold)
+}
+
+// optional int32 top_k = 11;
+bool DetectionOutputParameter::has_top_k() const {
+  return (_has_bits_[0] & 0x00000100u) != 0;
+}
+void DetectionOutputParameter::set_has_top_k() {
+  _has_bits_[0] |= 0x00000100u;
+}
+void DetectionOutputParameter::clear_has_top_k() {
+  _has_bits_[0] &= ~0x00000100u;
+}
+void DetectionOutputParameter::clear_top_k() {
+  top_k_ = 0;
+  clear_has_top_k();
+}
+::google::protobuf::int32 DetectionOutputParameter::top_k() const {
+  // @@protoc_insertion_point(field_get:caffe.DetectionOutputParameter.top_k)
+  return top_k_;
+}
+void DetectionOutputParameter::set_top_k(::google::protobuf::int32 value) {
+  set_has_top_k();
+  top_k_ = value;
+  // @@protoc_insertion_point(field_set:caffe.DetectionOutputParameter.top_k)
+}
+
+inline const DetectionOutputParameter* DetectionOutputParameter::internal_default_instance() {
+  return &DetectionOutputParameter_default_instance_.get();
+}
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
+
+// ===================================================================
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const int Datum::kChannelsFieldNumber;
+const int Datum::kHeightFieldNumber;
+const int Datum::kWidthFieldNumber;
+const int Datum::kDataFieldNumber;
+const int Datum::kLabelFieldNumber;
+const int Datum::kFloatDataFieldNumber;
+const int Datum::kEncodedFieldNumber;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+
+Datum::Datum()
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+  if (this != internal_default_instance()) protobuf_InitDefaults_caffe_2eproto();
+  SharedCtor();
+  // @@protoc_insertion_point(constructor:caffe.Datum)
+}
+
+void Datum::InitAsDefaultInstance() {
+}
+
+Datum::Datum(const Datum& from)
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
+  SharedCtor();
+  UnsafeMergeFrom(from);
+  // @@protoc_insertion_point(copy_constructor:caffe.Datum)
+}
+
+void Datum::SharedCtor() {
+  _cached_size_ = 0;
+  data_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  ::memset(&channels_, 0, reinterpret_cast<char*>(&encoded_) -
+    reinterpret_cast<char*>(&channels_) + sizeof(encoded_));
+}
+
+Datum::~Datum() {
+  // @@protoc_insertion_point(destructor:caffe.Datum)
+  SharedDtor();
+}
+
+void Datum::SharedDtor() {
+  data_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+
+void Datum::SetCachedSize(int size) const {
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* Datum::descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return Datum_descriptor_;
+}
+
+const Datum& Datum::default_instance() {
+  protobuf_InitDefaults_caffe_2eproto();
+  return *internal_default_instance();
+}
+
+::google::protobuf::internal::ExplicitlyConstructed<Datum> Datum_default_instance_;
+
+Datum* Datum::New(::google::protobuf::Arena* arena) const {
+  Datum* n = new Datum;
+  if (arena != NULL) {
+    arena->Own(n);
+  }
+  return n;
+}
+
+void Datum::Clear() {
+// @@protoc_insertion_point(message_clear_start:caffe.Datum)
+#if defined(__clang__)
+#define ZR_HELPER_(f) \
+  _Pragma("clang diagnostic push") \
+  _Pragma("clang diagnostic ignored \"-Winvalid-offsetof\"") \
+  __builtin_offsetof(Datum, f) \
+  _Pragma("clang diagnostic pop")
+#else
+#define ZR_HELPER_(f) reinterpret_cast<char*>(\
+  &reinterpret_cast<Datum*>(16)->f)
+#endif
+
+#define ZR_(first, last) do {\
+  ::memset(&(first), 0,\
+           ZR_HELPER_(last) - ZR_HELPER_(first) + sizeof(last));\
+} while (0)
+
+  if (_has_bits_[0 / 32] & 95u) {
+    ZR_(channels_, encoded_);
+    if (has_data()) {
+      data_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+    }
+  }
+
+#undef ZR_HELPER_
+#undef ZR_
+
+  float_data_.Clear();
+  _has_bits_.Clear();
+  if (_internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->Clear();
+  }
+}
+
+bool Datum::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
+  ::google::protobuf::uint32 tag;
+  // @@protoc_insertion_point(parse_start:caffe.Datum)
+  for (;;) {
+    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+    tag = p.first;
+    if (!p.second) goto handle_unusual;
+    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+      // optional int32 channels = 1;
+      case 1: {
+        if (tag == 8) {
+          set_has_channels();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
+                 input, &channels_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(16)) goto parse_height;
+        break;
+      }
+
+      // optional int32 height = 2;
+      case 2: {
+        if (tag == 16) {
+         parse_height:
+          set_has_height();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
+                 input, &height_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(24)) goto parse_width;
+        break;
+      }
+
+      // optional int32 width = 3;
+      case 3: {
+        if (tag == 24) {
+         parse_width:
+          set_has_width();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
+                 input, &width_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(34)) goto parse_data;
+        break;
+      }
+
+      // optional bytes data = 4;
+      case 4: {
+        if (tag == 34) {
+         parse_data:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadBytes(
+                input, this->mutable_data()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(40)) goto parse_label;
+        break;
+      }
+
+      // optional int32 label = 5;
+      case 5: {
+        if (tag == 40) {
+         parse_label:
+          set_has_label();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
+                 input, &label_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(53)) goto parse_float_data;
+        break;
+      }
+
+      // repeated float float_data = 6;
+      case 6: {
+        if (tag == 53) {
+         parse_float_data:
+          DO_((::google::protobuf::internal::WireFormatLite::ReadRepeatedPrimitive<
+                   float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
+                 1, 53, input, this->mutable_float_data())));
+        } else if (tag == 50) {
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPackedPrimitiveNoInline<
+                   float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
+                 input, this->mutable_float_data())));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(53)) goto parse_float_data;
+        if (input->ExpectTag(56)) goto parse_encoded;
+        break;
+      }
+
+      // optional bool encoded = 7 [default = false];
+      case 7: {
+        if (tag == 56) {
+         parse_encoded:
+          set_has_encoded();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>(
+                 input, &encoded_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectAtEnd()) goto success;
+        break;
+      }
+
+      default: {
+      handle_unusual:
+        if (tag == 0 ||
+            ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+          goto success;
+        }
+        DO_(::google::protobuf::internal::WireFormat::SkipField(
+              input, tag, mutable_unknown_fields()));
+        break;
+      }
+    }
+  }
+success:
+  // @@protoc_insertion_point(parse_success:caffe.Datum)
+  return true;
+failure:
+  // @@protoc_insertion_point(parse_failure:caffe.Datum)
+  return false;
+#undef DO_
+}
+
+void Datum::SerializeWithCachedSizes(
+    ::google::protobuf::io::CodedOutputStream* output) const {
+  // @@protoc_insertion_point(serialize_start:caffe.Datum)
+  // optional int32 channels = 1;
+  if (has_channels()) {
+    ::google::protobuf::internal::WireFormatLite::WriteInt32(1, this->channels(), output);
+  }
+
+  // optional int32 height = 2;
+  if (has_height()) {
+    ::google::protobuf::internal::WireFormatLite::WriteInt32(2, this->height(), output);
+  }
+
+  // optional int32 width = 3;
+  if (has_width()) {
+    ::google::protobuf::internal::WireFormatLite::WriteInt32(3, this->width(), output);
+  }
+
+  // optional bytes data = 4;
+  if (has_data()) {
+    ::google::protobuf::internal::WireFormatLite::WriteBytesMaybeAliased(
+      4, this->data(), output);
+  }
+
+  // optional int32 label = 5;
+  if (has_label()) {
+    ::google::protobuf::internal::WireFormatLite::WriteInt32(5, this->label(), output);
+  }
+
+  // repeated float float_data = 6;
+  for (int i = 0; i < this->float_data_size(); i++) {
+    ::google::protobuf::internal::WireFormatLite::WriteFloat(
+      6, this->float_data(i), output);
+  }
+
+  // optional bool encoded = 7 [default = false];
+  if (has_encoded()) {
+    ::google::protobuf::internal::WireFormatLite::WriteBool(7, this->encoded(), output);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
+        unknown_fields(), output);
+  }
+  // @@protoc_insertion_point(serialize_end:caffe.Datum)
+}
+
+::google::protobuf::uint8* Datum::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
+  (void)deterministic; // Unused
+  // @@protoc_insertion_point(serialize_to_array_start:caffe.Datum)
+  // optional int32 channels = 1;
+  if (has_channels()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteInt32ToArray(1, this->channels(), target);
+  }
+
+  // optional int32 height = 2;
+  if (has_height()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteInt32ToArray(2, this->height(), target);
+  }
+
+  // optional int32 width = 3;
+  if (has_width()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteInt32ToArray(3, this->width(), target);
+  }
+
+  // optional bytes data = 4;
+  if (has_data()) {
+    target =
+      ::google::protobuf::internal::WireFormatLite::WriteBytesToArray(
+        4, this->data(), target);
+  }
+
+  // optional int32 label = 5;
+  if (has_label()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteInt32ToArray(5, this->label(), target);
+  }
+
+  // repeated float float_data = 6;
+  for (int i = 0; i < this->float_data_size(); i++) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      WriteFloatToArray(6, this->float_data(i), target);
+  }
+
+  // optional bool encoded = 7 [default = false];
+  if (has_encoded()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(7, this->encoded(), target);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
+        unknown_fields(), target);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:caffe.Datum)
+  return target;
+}
+
+size_t Datum::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:caffe.Datum)
+  size_t total_size = 0;
+
+  if (_has_bits_[0 / 32] & 95u) {
+    // optional int32 channels = 1;
+    if (has_channels()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::Int32Size(
+          this->channels());
+    }
+
+    // optional int32 height = 2;
+    if (has_height()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::Int32Size(
+          this->height());
+    }
+
+    // optional int32 width = 3;
+    if (has_width()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::Int32Size(
+          this->width());
+    }
+
+    // optional bytes data = 4;
+    if (has_data()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::BytesSize(
+          this->data());
+    }
+
+    // optional int32 label = 5;
+    if (has_label()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::Int32Size(
+          this->label());
+    }
+
+    // optional bool encoded = 7 [default = false];
+    if (has_encoded()) {
+      total_size += 1 + 1;
+    }
+
+  }
+  // repeated float float_data = 6;
+  {
+    size_t data_size = 0;
+    unsigned int count = this->float_data_size();
+    data_size = 4UL * count;
+    total_size += 1 *
+                  ::google::protobuf::internal::FromIntSize(this->float_data_size());
+    total_size += data_size;
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    total_size +=
+      ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
+        unknown_fields());
+  }
+  int cached_size = ::google::protobuf::internal::ToCachedSize(total_size);
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = cached_size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+  return total_size;
+}
+
+void Datum::MergeFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_merge_from_start:caffe.Datum)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const Datum* source =
+      ::google::protobuf::internal::DynamicCastToGenerated<const Datum>(
+          &from);
+  if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:caffe.Datum)
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:caffe.Datum)
+    UnsafeMergeFrom(*source);
+  }
+}
+
+void Datum::MergeFrom(const Datum& from) {
+// @@protoc_insertion_point(class_specific_merge_from_start:caffe.Datum)
+  if (GOOGLE_PREDICT_TRUE(&from != this)) {
+    UnsafeMergeFrom(from);
+  } else {
+    MergeFromFail(__LINE__);
+  }
+}
+
+void Datum::UnsafeMergeFrom(const Datum& from) {
+  GOOGLE_DCHECK(&from != this);
+  float_data_.UnsafeMergeFrom(from.float_data_);
+  if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+    if (from.has_channels()) {
+      set_channels(from.channels());
+    }
+    if (from.has_height()) {
+      set_height(from.height());
+    }
+    if (from.has_width()) {
+      set_width(from.width());
+    }
+    if (from.has_data()) {
+      set_has_data();
+      data_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.data_);
+    }
+    if (from.has_label()) {
+      set_label(from.label());
+    }
+    if (from.has_encoded()) {
+      set_encoded(from.encoded());
+    }
+  }
+  if (from._internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::UnknownFieldSet::MergeToInternalMetdata(
+      from.unknown_fields(), &_internal_metadata_);
+  }
+}
+
+void Datum::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:caffe.Datum)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void Datum::CopyFrom(const Datum& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:caffe.Datum)
+  if (&from == this) return;
+  Clear();
+  UnsafeMergeFrom(from);
+}
+
+bool Datum::IsInitialized() const {
+
+  return true;
+}
+
+void Datum::Swap(Datum* other) {
+  if (other == this) return;
+  InternalSwap(other);
+}
+void Datum::InternalSwap(Datum* other) {
+  std::swap(channels_, other->channels_);
+  std::swap(height_, other->height_);
+  std::swap(width_, other->width_);
+  data_.Swap(&other->data_);
+  std::swap(label_, other->label_);
+  float_data_.UnsafeArenaSwap(&other->float_data_);
+  std::swap(encoded_, other->encoded_);
+  std::swap(_has_bits_[0], other->_has_bits_[0]);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
+}
+
+::google::protobuf::Metadata Datum::GetMetadata() const {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::Metadata metadata;
+  metadata.descriptor = Datum_descriptor_;
+  metadata.reflection = Datum_reflection_;
+  return metadata;
+}
+
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// Datum
+
+// optional int32 channels = 1;
+bool Datum::has_channels() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+void Datum::set_has_channels() {
+  _has_bits_[0] |= 0x00000001u;
+}
+void Datum::clear_has_channels() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+void Datum::clear_channels() {
+  channels_ = 0;
+  clear_has_channels();
+}
+::google::protobuf::int32 Datum::channels() const {
+  // @@protoc_insertion_point(field_get:caffe.Datum.channels)
+  return channels_;
+}
+void Datum::set_channels(::google::protobuf::int32 value) {
+  set_has_channels();
+  channels_ = value;
+  // @@protoc_insertion_point(field_set:caffe.Datum.channels)
+}
+
+// optional int32 height = 2;
+bool Datum::has_height() const {
+  return (_has_bits_[0] & 0x00000002u) != 0;
+}
+void Datum::set_has_height() {
+  _has_bits_[0] |= 0x00000002u;
+}
+void Datum::clear_has_height() {
+  _has_bits_[0] &= ~0x00000002u;
+}
+void Datum::clear_height() {
+  height_ = 0;
+  clear_has_height();
+}
+::google::protobuf::int32 Datum::height() const {
+  // @@protoc_insertion_point(field_get:caffe.Datum.height)
+  return height_;
+}
+void Datum::set_height(::google::protobuf::int32 value) {
+  set_has_height();
+  height_ = value;
+  // @@protoc_insertion_point(field_set:caffe.Datum.height)
+}
+
+// optional int32 width = 3;
+bool Datum::has_width() const {
+  return (_has_bits_[0] & 0x00000004u) != 0;
+}
+void Datum::set_has_width() {
+  _has_bits_[0] |= 0x00000004u;
+}
+void Datum::clear_has_width() {
+  _has_bits_[0] &= ~0x00000004u;
+}
+void Datum::clear_width() {
+  width_ = 0;
+  clear_has_width();
+}
+::google::protobuf::int32 Datum::width() const {
+  // @@protoc_insertion_point(field_get:caffe.Datum.width)
+  return width_;
+}
+void Datum::set_width(::google::protobuf::int32 value) {
+  set_has_width();
+  width_ = value;
+  // @@protoc_insertion_point(field_set:caffe.Datum.width)
+}
+
+// optional bytes data = 4;
+bool Datum::has_data() const {
+  return (_has_bits_[0] & 0x00000008u) != 0;
+}
+void Datum::set_has_data() {
+  _has_bits_[0] |= 0x00000008u;
+}
+void Datum::clear_has_data() {
+  _has_bits_[0] &= ~0x00000008u;
+}
+void Datum::clear_data() {
+  data_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  clear_has_data();
+}
+const ::std::string& Datum::data() const {
+  // @@protoc_insertion_point(field_get:caffe.Datum.data)
+  return data_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+void Datum::set_data(const ::std::string& value) {
+  set_has_data();
+  data_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:caffe.Datum.data)
+}
+void Datum::set_data(const char* value) {
+  set_has_data();
+  data_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:caffe.Datum.data)
+}
+void Datum::set_data(const void* value, size_t size) {
+  set_has_data();
+  data_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:caffe.Datum.data)
+}
+::std::string* Datum::mutable_data() {
+  set_has_data();
+  // @@protoc_insertion_point(field_mutable:caffe.Datum.data)
+  return data_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+::std::string* Datum::release_data() {
+  // @@protoc_insertion_point(field_release:caffe.Datum.data)
+  clear_has_data();
+  return data_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+void Datum::set_allocated_data(::std::string* data) {
+  if (data != NULL) {
+    set_has_data();
+  } else {
+    clear_has_data();
+  }
+  data_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), data);
+  // @@protoc_insertion_point(field_set_allocated:caffe.Datum.data)
+}
+
+// optional int32 label = 5;
+bool Datum::has_label() const {
+  return (_has_bits_[0] & 0x00000010u) != 0;
+}
+void Datum::set_has_label() {
+  _has_bits_[0] |= 0x00000010u;
+}
+void Datum::clear_has_label() {
+  _has_bits_[0] &= ~0x00000010u;
+}
+void Datum::clear_label() {
+  label_ = 0;
+  clear_has_label();
+}
+::google::protobuf::int32 Datum::label() const {
+  // @@protoc_insertion_point(field_get:caffe.Datum.label)
+  return label_;
+}
+void Datum::set_label(::google::protobuf::int32 value) {
+  set_has_label();
+  label_ = value;
+  // @@protoc_insertion_point(field_set:caffe.Datum.label)
+}
+
+// repeated float float_data = 6;
+int Datum::float_data_size() const {
+  return float_data_.size();
+}
+void Datum::clear_float_data() {
+  float_data_.Clear();
+}
+float Datum::float_data(int index) const {
+  // @@protoc_insertion_point(field_get:caffe.Datum.float_data)
+  return float_data_.Get(index);
+}
+void Datum::set_float_data(int index, float value) {
+  float_data_.Set(index, value);
+  // @@protoc_insertion_point(field_set:caffe.Datum.float_data)
+}
+void Datum::add_float_data(float value) {
+  float_data_.Add(value);
+  // @@protoc_insertion_point(field_add:caffe.Datum.float_data)
+}
+const ::google::protobuf::RepeatedField< float >&
+Datum::float_data() const {
+  // @@protoc_insertion_point(field_list:caffe.Datum.float_data)
+  return float_data_;
+}
+::google::protobuf::RepeatedField< float >*
+Datum::mutable_float_data() {
+  // @@protoc_insertion_point(field_mutable_list:caffe.Datum.float_data)
+  return &float_data_;
+}
+
+// optional bool encoded = 7 [default = false];
+bool Datum::has_encoded() const {
+  return (_has_bits_[0] & 0x00000040u) != 0;
+}
+void Datum::set_has_encoded() {
+  _has_bits_[0] |= 0x00000040u;
+}
+void Datum::clear_has_encoded() {
+  _has_bits_[0] &= ~0x00000040u;
+}
+void Datum::clear_encoded() {
+  encoded_ = false;
+  clear_has_encoded();
+}
+bool Datum::encoded() const {
+  // @@protoc_insertion_point(field_get:caffe.Datum.encoded)
+  return encoded_;
+}
+void Datum::set_encoded(bool value) {
+  set_has_encoded();
+  encoded_ = value;
+  // @@protoc_insertion_point(field_set:caffe.Datum.encoded)
+}
+
+inline const Datum* Datum::internal_default_instance() {
+  return &Datum_default_instance_.get();
+}
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
+
+// ===================================================================
+
+const ::google::protobuf::EnumDescriptor* FillerParameter_VarianceNorm_descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return FillerParameter_VarianceNorm_descriptor_;
+}
+bool FillerParameter_VarianceNorm_IsValid(int value) {
+  switch (value) {
+    case 0:
+    case 1:
+    case 2:
+      return true;
+    default:
+      return false;
+  }
+}
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const FillerParameter_VarianceNorm FillerParameter::FAN_IN;
+const FillerParameter_VarianceNorm FillerParameter::FAN_OUT;
+const FillerParameter_VarianceNorm FillerParameter::AVERAGE;
+const FillerParameter_VarianceNorm FillerParameter::VarianceNorm_MIN;
+const FillerParameter_VarianceNorm FillerParameter::VarianceNorm_MAX;
+const int FillerParameter::VarianceNorm_ARRAYSIZE;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+::std::string* FillerParameter::_default_type_ = NULL;
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const int FillerParameter::kTypeFieldNumber;
+const int FillerParameter::kValueFieldNumber;
+const int FillerParameter::kMinFieldNumber;
+const int FillerParameter::kMaxFieldNumber;
+const int FillerParameter::kMeanFieldNumber;
+const int FillerParameter::kStdFieldNumber;
+const int FillerParameter::kSparseFieldNumber;
+const int FillerParameter::kVarianceNormFieldNumber;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+
+FillerParameter::FillerParameter()
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+  if (this != internal_default_instance()) protobuf_InitDefaults_caffe_2eproto();
+  SharedCtor();
+  // @@protoc_insertion_point(constructor:caffe.FillerParameter)
+}
+
+void FillerParameter::InitAsDefaultInstance() {
+}
+
+FillerParameter::FillerParameter(const FillerParameter& from)
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
+  SharedCtor();
+  UnsafeMergeFrom(from);
+  // @@protoc_insertion_point(copy_constructor:caffe.FillerParameter)
+}
+
+void FillerParameter::SharedCtor() {
+  _cached_size_ = 0;
+  type_.UnsafeSetDefault(_default_type_);
+  ::memset(&value_, 0, reinterpret_cast<char*>(&variance_norm_) -
+    reinterpret_cast<char*>(&value_) + sizeof(variance_norm_));
+  sparse_ = -1;
+  max_ = 1;
+  std_ = 1;
+}
+
+FillerParameter::~FillerParameter() {
+  // @@protoc_insertion_point(destructor:caffe.FillerParameter)
+  SharedDtor();
+}
+
+void FillerParameter::SharedDtor() {
+  type_.DestroyNoArena(_default_type_);
+}
+
+void FillerParameter::SetCachedSize(int size) const {
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* FillerParameter::descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return FillerParameter_descriptor_;
+}
+
+const FillerParameter& FillerParameter::default_instance() {
+  protobuf_InitDefaults_caffe_2eproto();
+  return *internal_default_instance();
+}
+
+::google::protobuf::internal::ExplicitlyConstructed<FillerParameter> FillerParameter_default_instance_;
+
+FillerParameter* FillerParameter::New(::google::protobuf::Arena* arena) const {
+  FillerParameter* n = new FillerParameter;
+  if (arena != NULL) {
+    arena->Own(n);
+  }
+  return n;
+}
+
+void FillerParameter::Clear() {
+// @@protoc_insertion_point(message_clear_start:caffe.FillerParameter)
+#if defined(__clang__)
+#define ZR_HELPER_(f) \
+  _Pragma("clang diagnostic push") \
+  _Pragma("clang diagnostic ignored \"-Winvalid-offsetof\"") \
+  __builtin_offsetof(FillerParameter, f) \
+  _Pragma("clang diagnostic pop")
+#else
+#define ZR_HELPER_(f) reinterpret_cast<char*>(\
+  &reinterpret_cast<FillerParameter*>(16)->f)
+#endif
+
+#define ZR_(first, last) do {\
+  ::memset(&(first), 0,\
+           ZR_HELPER_(last) - ZR_HELPER_(first) + sizeof(last));\
+} while (0)
+
+  if (_has_bits_[0 / 32] & 255u) {
+    ZR_(value_, variance_norm_);
+    if (has_type()) {
+      type_.ClearToDefaultNoArena(_default_type_);
+    }
+    max_ = 1;
+    std_ = 1;
+    sparse_ = -1;
+  }
+
+#undef ZR_HELPER_
+#undef ZR_
+
+  _has_bits_.Clear();
+  if (_internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->Clear();
+  }
+}
+
+bool FillerParameter::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
+  ::google::protobuf::uint32 tag;
+  // @@protoc_insertion_point(parse_start:caffe.FillerParameter)
+  for (;;) {
+    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+    tag = p.first;
+    if (!p.second) goto handle_unusual;
+    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+      // optional string type = 1 [default = "constant"];
+      case 1: {
+        if (tag == 10) {
+          DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+                input, this->mutable_type()));
+          ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+            this->type().data(), this->type().length(),
+            ::google::protobuf::internal::WireFormat::PARSE,
+            "caffe.FillerParameter.type");
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(21)) goto parse_value;
+        break;
+      }
+
+      // optional float value = 2 [default = 0];
+      case 2: {
+        if (tag == 21) {
+         parse_value:
+          set_has_value();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
+                 input, &value_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(29)) goto parse_min;
+        break;
+      }
+
+      // optional float min = 3 [default = 0];
+      case 3: {
+        if (tag == 29) {
+         parse_min:
+          set_has_min();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
+                 input, &min_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(37)) goto parse_max;
+        break;
+      }
+
+      // optional float max = 4 [default = 1];
+      case 4: {
+        if (tag == 37) {
+         parse_max:
+          set_has_max();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
+                 input, &max_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(45)) goto parse_mean;
+        break;
+      }
+
+      // optional float mean = 5 [default = 0];
+      case 5: {
+        if (tag == 45) {
+         parse_mean:
+          set_has_mean();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
+                 input, &mean_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(53)) goto parse_std;
+        break;
+      }
+
+      // optional float std = 6 [default = 1];
+      case 6: {
+        if (tag == 53) {
+         parse_std:
+          set_has_std();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
+                 input, &std_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(56)) goto parse_sparse;
+        break;
+      }
+
+      // optional int32 sparse = 7 [default = -1];
+      case 7: {
+        if (tag == 56) {
+         parse_sparse:
+          set_has_sparse();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
+                 input, &sparse_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(64)) goto parse_variance_norm;
+        break;
+      }
+
+      // optional .caffe.FillerParameter.VarianceNorm variance_norm = 8 [default = FAN_IN];
+      case 8: {
+        if (tag == 64) {
+         parse_variance_norm:
+          int value;
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>(
+                 input, &value)));
+          if (::caffe::FillerParameter_VarianceNorm_IsValid(value)) {
+            set_variance_norm(static_cast< ::caffe::FillerParameter_VarianceNorm >(value));
+          } else {
+            mutable_unknown_fields()->AddVarint(8, value);
+          }
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectAtEnd()) goto success;
+        break;
+      }
+
+      default: {
+      handle_unusual:
+        if (tag == 0 ||
+            ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+          goto success;
+        }
+        DO_(::google::protobuf::internal::WireFormat::SkipField(
+              input, tag, mutable_unknown_fields()));
+        break;
+      }
+    }
+  }
+success:
+  // @@protoc_insertion_point(parse_success:caffe.FillerParameter)
+  return true;
+failure:
+  // @@protoc_insertion_point(parse_failure:caffe.FillerParameter)
+  return false;
+#undef DO_
+}
+
+void FillerParameter::SerializeWithCachedSizes(
+    ::google::protobuf::io::CodedOutputStream* output) const {
+  // @@protoc_insertion_point(serialize_start:caffe.FillerParameter)
+  // optional string type = 1 [default = "constant"];
+  if (has_type()) {
+    ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->type().data(), this->type().length(),
+      ::google::protobuf::internal::WireFormat::SERIALIZE,
+      "caffe.FillerParameter.type");
+    ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
+      1, this->type(), output);
+  }
+
+  // optional float value = 2 [default = 0];
+  if (has_value()) {
+    ::google::protobuf::internal::WireFormatLite::WriteFloat(2, this->value(), output);
+  }
+
+  // optional float min = 3 [default = 0];
+  if (has_min()) {
+    ::google::protobuf::internal::WireFormatLite::WriteFloat(3, this->min(), output);
+  }
+
+  // optional float max = 4 [default = 1];
+  if (has_max()) {
+    ::google::protobuf::internal::WireFormatLite::WriteFloat(4, this->max(), output);
+  }
+
+  // optional float mean = 5 [default = 0];
+  if (has_mean()) {
+    ::google::protobuf::internal::WireFormatLite::WriteFloat(5, this->mean(), output);
+  }
+
+  // optional float std = 6 [default = 1];
+  if (has_std()) {
+    ::google::protobuf::internal::WireFormatLite::WriteFloat(6, this->std(), output);
+  }
+
+  // optional int32 sparse = 7 [default = -1];
+  if (has_sparse()) {
+    ::google::protobuf::internal::WireFormatLite::WriteInt32(7, this->sparse(), output);
+  }
+
+  // optional .caffe.FillerParameter.VarianceNorm variance_norm = 8 [default = FAN_IN];
+  if (has_variance_norm()) {
+    ::google::protobuf::internal::WireFormatLite::WriteEnum(
+      8, this->variance_norm(), output);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
+        unknown_fields(), output);
+  }
+  // @@protoc_insertion_point(serialize_end:caffe.FillerParameter)
+}
+
+::google::protobuf::uint8* FillerParameter::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
+  (void)deterministic; // Unused
+  // @@protoc_insertion_point(serialize_to_array_start:caffe.FillerParameter)
+  // optional string type = 1 [default = "constant"];
+  if (has_type()) {
+    ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->type().data(), this->type().length(),
+      ::google::protobuf::internal::WireFormat::SERIALIZE,
+      "caffe.FillerParameter.type");
+    target =
+      ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
+        1, this->type(), target);
+  }
+
+  // optional float value = 2 [default = 0];
+  if (has_value()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteFloatToArray(2, this->value(), target);
+  }
+
+  // optional float min = 3 [default = 0];
+  if (has_min()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteFloatToArray(3, this->min(), target);
+  }
+
+  // optional float max = 4 [default = 1];
+  if (has_max()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteFloatToArray(4, this->max(), target);
+  }
+
+  // optional float mean = 5 [default = 0];
+  if (has_mean()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteFloatToArray(5, this->mean(), target);
+  }
+
+  // optional float std = 6 [default = 1];
+  if (has_std()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteFloatToArray(6, this->std(), target);
+  }
+
+  // optional int32 sparse = 7 [default = -1];
+  if (has_sparse()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteInt32ToArray(7, this->sparse(), target);
+  }
+
+  // optional .caffe.FillerParameter.VarianceNorm variance_norm = 8 [default = FAN_IN];
+  if (has_variance_norm()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteEnumToArray(
+      8, this->variance_norm(), target);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
+        unknown_fields(), target);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:caffe.FillerParameter)
+  return target;
+}
+
+size_t FillerParameter::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:caffe.FillerParameter)
+  size_t total_size = 0;
+
+  if (_has_bits_[0 / 32] & 255u) {
+    // optional string type = 1 [default = "constant"];
+    if (has_type()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::StringSize(
+          this->type());
+    }
+
+    // optional float value = 2 [default = 0];
+    if (has_value()) {
+      total_size += 1 + 4;
+    }
+
+    // optional float min = 3 [default = 0];
+    if (has_min()) {
+      total_size += 1 + 4;
+    }
+
+    // optional float max = 4 [default = 1];
+    if (has_max()) {
+      total_size += 1 + 4;
+    }
+
+    // optional float mean = 5 [default = 0];
+    if (has_mean()) {
+      total_size += 1 + 4;
+    }
+
+    // optional float std = 6 [default = 1];
+    if (has_std()) {
+      total_size += 1 + 4;
+    }
+
+    // optional int32 sparse = 7 [default = -1];
+    if (has_sparse()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::Int32Size(
+          this->sparse());
+    }
+
+    // optional .caffe.FillerParameter.VarianceNorm variance_norm = 8 [default = FAN_IN];
+    if (has_variance_norm()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::EnumSize(this->variance_norm());
+    }
+
+  }
+  if (_internal_metadata_.have_unknown_fields()) {
+    total_size +=
+      ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
+        unknown_fields());
+  }
+  int cached_size = ::google::protobuf::internal::ToCachedSize(total_size);
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = cached_size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+  return total_size;
+}
+
+void FillerParameter::MergeFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_merge_from_start:caffe.FillerParameter)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const FillerParameter* source =
+      ::google::protobuf::internal::DynamicCastToGenerated<const FillerParameter>(
+          &from);
+  if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:caffe.FillerParameter)
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:caffe.FillerParameter)
+    UnsafeMergeFrom(*source);
+  }
+}
+
+void FillerParameter::MergeFrom(const FillerParameter& from) {
+// @@protoc_insertion_point(class_specific_merge_from_start:caffe.FillerParameter)
+  if (GOOGLE_PREDICT_TRUE(&from != this)) {
+    UnsafeMergeFrom(from);
+  } else {
+    MergeFromFail(__LINE__);
+  }
+}
+
+void FillerParameter::UnsafeMergeFrom(const FillerParameter& from) {
+  GOOGLE_DCHECK(&from != this);
+  if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+    if (from.has_type()) {
+      set_has_type();
+      type_.AssignWithDefault(_default_type_, from.type_);
+    }
+    if (from.has_value()) {
+      set_value(from.value());
+    }
+    if (from.has_min()) {
+      set_min(from.min());
+    }
+    if (from.has_max()) {
+      set_max(from.max());
+    }
+    if (from.has_mean()) {
+      set_mean(from.mean());
+    }
+    if (from.has_std()) {
+      set_std(from.std());
+    }
+    if (from.has_sparse()) {
+      set_sparse(from.sparse());
+    }
+    if (from.has_variance_norm()) {
+      set_variance_norm(from.variance_norm());
+    }
+  }
+  if (from._internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::UnknownFieldSet::MergeToInternalMetdata(
+      from.unknown_fields(), &_internal_metadata_);
+  }
+}
+
+void FillerParameter::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:caffe.FillerParameter)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void FillerParameter::CopyFrom(const FillerParameter& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:caffe.FillerParameter)
+  if (&from == this) return;
+  Clear();
+  UnsafeMergeFrom(from);
+}
+
+bool FillerParameter::IsInitialized() const {
+
+  return true;
+}
+
+void FillerParameter::Swap(FillerParameter* other) {
+  if (other == this) return;
+  InternalSwap(other);
+}
+void FillerParameter::InternalSwap(FillerParameter* other) {
+  type_.Swap(&other->type_);
+  std::swap(value_, other->value_);
+  std::swap(min_, other->min_);
+  std::swap(max_, other->max_);
+  std::swap(mean_, other->mean_);
+  std::swap(std_, other->std_);
+  std::swap(sparse_, other->sparse_);
+  std::swap(variance_norm_, other->variance_norm_);
+  std::swap(_has_bits_[0], other->_has_bits_[0]);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
+}
+
+::google::protobuf::Metadata FillerParameter::GetMetadata() const {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::Metadata metadata;
+  metadata.descriptor = FillerParameter_descriptor_;
+  metadata.reflection = FillerParameter_reflection_;
+  return metadata;
+}
+
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// FillerParameter
+
+// optional string type = 1 [default = "constant"];
+bool FillerParameter::has_type() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+void FillerParameter::set_has_type() {
+  _has_bits_[0] |= 0x00000001u;
+}
+void FillerParameter::clear_has_type() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+void FillerParameter::clear_type() {
+  type_.ClearToDefaultNoArena(_default_type_);
+  clear_has_type();
+}
+const ::std::string& FillerParameter::type() const {
+  // @@protoc_insertion_point(field_get:caffe.FillerParameter.type)
+  return type_.GetNoArena(_default_type_);
+}
+void FillerParameter::set_type(const ::std::string& value) {
+  set_has_type();
+  type_.SetNoArena(_default_type_, value);
+  // @@protoc_insertion_point(field_set:caffe.FillerParameter.type)
+}
+void FillerParameter::set_type(const char* value) {
+  set_has_type();
+  type_.SetNoArena(_default_type_, ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:caffe.FillerParameter.type)
+}
+void FillerParameter::set_type(const char* value, size_t size) {
+  set_has_type();
+  type_.SetNoArena(_default_type_,
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:caffe.FillerParameter.type)
+}
+::std::string* FillerParameter::mutable_type() {
+  set_has_type();
+  // @@protoc_insertion_point(field_mutable:caffe.FillerParameter.type)
+  return type_.MutableNoArena(_default_type_);
+}
+::std::string* FillerParameter::release_type() {
+  // @@protoc_insertion_point(field_release:caffe.FillerParameter.type)
+  clear_has_type();
+  return type_.ReleaseNoArena(_default_type_);
+}
+void FillerParameter::set_allocated_type(::std::string* type) {
+  if (type != NULL) {
+    set_has_type();
+  } else {
+    clear_has_type();
+  }
+  type_.SetAllocatedNoArena(_default_type_, type);
+  // @@protoc_insertion_point(field_set_allocated:caffe.FillerParameter.type)
+}
+
+// optional float value = 2 [default = 0];
+bool FillerParameter::has_value() const {
+  return (_has_bits_[0] & 0x00000002u) != 0;
+}
+void FillerParameter::set_has_value() {
+  _has_bits_[0] |= 0x00000002u;
+}
+void FillerParameter::clear_has_value() {
+  _has_bits_[0] &= ~0x00000002u;
+}
+void FillerParameter::clear_value() {
+  value_ = 0;
+  clear_has_value();
+}
+float FillerParameter::value() const {
+  // @@protoc_insertion_point(field_get:caffe.FillerParameter.value)
+  return value_;
+}
+void FillerParameter::set_value(float value) {
+  set_has_value();
+  value_ = value;
+  // @@protoc_insertion_point(field_set:caffe.FillerParameter.value)
+}
+
+// optional float min = 3 [default = 0];
+bool FillerParameter::has_min() const {
+  return (_has_bits_[0] & 0x00000004u) != 0;
+}
+void FillerParameter::set_has_min() {
+  _has_bits_[0] |= 0x00000004u;
+}
+void FillerParameter::clear_has_min() {
+  _has_bits_[0] &= ~0x00000004u;
+}
+void FillerParameter::clear_min() {
+  min_ = 0;
+  clear_has_min();
+}
+float FillerParameter::min() const {
+  // @@protoc_insertion_point(field_get:caffe.FillerParameter.min)
+  return min_;
+}
+void FillerParameter::set_min(float value) {
+  set_has_min();
+  min_ = value;
+  // @@protoc_insertion_point(field_set:caffe.FillerParameter.min)
+}
+
+// optional float max = 4 [default = 1];
+bool FillerParameter::has_max() const {
+  return (_has_bits_[0] & 0x00000008u) != 0;
+}
+void FillerParameter::set_has_max() {
+  _has_bits_[0] |= 0x00000008u;
+}
+void FillerParameter::clear_has_max() {
+  _has_bits_[0] &= ~0x00000008u;
+}
+void FillerParameter::clear_max() {
+  max_ = 1;
+  clear_has_max();
+}
+float FillerParameter::max() const {
+  // @@protoc_insertion_point(field_get:caffe.FillerParameter.max)
+  return max_;
+}
+void FillerParameter::set_max(float value) {
+  set_has_max();
+  max_ = value;
+  // @@protoc_insertion_point(field_set:caffe.FillerParameter.max)
+}
+
+// optional float mean = 5 [default = 0];
+bool FillerParameter::has_mean() const {
+  return (_has_bits_[0] & 0x00000010u) != 0;
+}
+void FillerParameter::set_has_mean() {
+  _has_bits_[0] |= 0x00000010u;
+}
+void FillerParameter::clear_has_mean() {
+  _has_bits_[0] &= ~0x00000010u;
+}
+void FillerParameter::clear_mean() {
+  mean_ = 0;
+  clear_has_mean();
+}
+float FillerParameter::mean() const {
+  // @@protoc_insertion_point(field_get:caffe.FillerParameter.mean)
+  return mean_;
+}
+void FillerParameter::set_mean(float value) {
+  set_has_mean();
+  mean_ = value;
+  // @@protoc_insertion_point(field_set:caffe.FillerParameter.mean)
+}
+
+// optional float std = 6 [default = 1];
+bool FillerParameter::has_std() const {
+  return (_has_bits_[0] & 0x00000020u) != 0;
+}
+void FillerParameter::set_has_std() {
+  _has_bits_[0] |= 0x00000020u;
+}
+void FillerParameter::clear_has_std() {
+  _has_bits_[0] &= ~0x00000020u;
+}
+void FillerParameter::clear_std() {
+  std_ = 1;
+  clear_has_std();
+}
+float FillerParameter::std() const {
+  // @@protoc_insertion_point(field_get:caffe.FillerParameter.std)
+  return std_;
+}
+void FillerParameter::set_std(float value) {
+  set_has_std();
+  std_ = value;
+  // @@protoc_insertion_point(field_set:caffe.FillerParameter.std)
+}
+
+// optional int32 sparse = 7 [default = -1];
+bool FillerParameter::has_sparse() const {
+  return (_has_bits_[0] & 0x00000040u) != 0;
+}
+void FillerParameter::set_has_sparse() {
+  _has_bits_[0] |= 0x00000040u;
+}
+void FillerParameter::clear_has_sparse() {
+  _has_bits_[0] &= ~0x00000040u;
+}
+void FillerParameter::clear_sparse() {
+  sparse_ = -1;
+  clear_has_sparse();
+}
+::google::protobuf::int32 FillerParameter::sparse() const {
+  // @@protoc_insertion_point(field_get:caffe.FillerParameter.sparse)
+  return sparse_;
+}
+void FillerParameter::set_sparse(::google::protobuf::int32 value) {
+  set_has_sparse();
+  sparse_ = value;
+  // @@protoc_insertion_point(field_set:caffe.FillerParameter.sparse)
+}
+
+// optional .caffe.FillerParameter.VarianceNorm variance_norm = 8 [default = FAN_IN];
+bool FillerParameter::has_variance_norm() const {
+  return (_has_bits_[0] & 0x00000080u) != 0;
+}
+void FillerParameter::set_has_variance_norm() {
+  _has_bits_[0] |= 0x00000080u;
+}
+void FillerParameter::clear_has_variance_norm() {
+  _has_bits_[0] &= ~0x00000080u;
+}
+void FillerParameter::clear_variance_norm() {
+  variance_norm_ = 0;
+  clear_has_variance_norm();
+}
+::caffe::FillerParameter_VarianceNorm FillerParameter::variance_norm() const {
+  // @@protoc_insertion_point(field_get:caffe.FillerParameter.variance_norm)
+  return static_cast< ::caffe::FillerParameter_VarianceNorm >(variance_norm_);
+}
+void FillerParameter::set_variance_norm(::caffe::FillerParameter_VarianceNorm value) {
+  assert(::caffe::FillerParameter_VarianceNorm_IsValid(value));
+  set_has_variance_norm();
+  variance_norm_ = value;
+  // @@protoc_insertion_point(field_set:caffe.FillerParameter.variance_norm)
+}
+
+inline const FillerParameter* FillerParameter::internal_default_instance() {
+  return &FillerParameter_default_instance_.get();
+}
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
+
+// ===================================================================
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const int NetParameter::kNameFieldNumber;
+const int NetParameter::kInputFieldNumber;
+const int NetParameter::kInputShapeFieldNumber;
+const int NetParameter::kInputDimFieldNumber;
+const int NetParameter::kForceBackwardFieldNumber;
+const int NetParameter::kStateFieldNumber;
+const int NetParameter::kDebugInfoFieldNumber;
+const int NetParameter::kLayerFieldNumber;
+const int NetParameter::kLayersFieldNumber;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+
+NetParameter::NetParameter()
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+  if (this != internal_default_instance()) protobuf_InitDefaults_caffe_2eproto();
+  SharedCtor();
+  // @@protoc_insertion_point(constructor:caffe.NetParameter)
+}
+
+void NetParameter::InitAsDefaultInstance() {
+  state_ = const_cast< ::caffe::NetState*>(
+      ::caffe::NetState::internal_default_instance());
+}
+
+NetParameter::NetParameter(const NetParameter& from)
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
+  SharedCtor();
+  UnsafeMergeFrom(from);
+  // @@protoc_insertion_point(copy_constructor:caffe.NetParameter)
+}
+
+void NetParameter::SharedCtor() {
+  _cached_size_ = 0;
+  name_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  state_ = NULL;
+  ::memset(&force_backward_, 0, reinterpret_cast<char*>(&debug_info_) -
+    reinterpret_cast<char*>(&force_backward_) + sizeof(debug_info_));
+}
+
+NetParameter::~NetParameter() {
+  // @@protoc_insertion_point(destructor:caffe.NetParameter)
+  SharedDtor();
+}
+
+void NetParameter::SharedDtor() {
+  name_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  if (this != &NetParameter_default_instance_.get()) {
+    delete state_;
+  }
+}
+
+void NetParameter::SetCachedSize(int size) const {
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* NetParameter::descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return NetParameter_descriptor_;
+}
+
+const NetParameter& NetParameter::default_instance() {
+  protobuf_InitDefaults_caffe_2eproto();
+  return *internal_default_instance();
+}
+
+::google::protobuf::internal::ExplicitlyConstructed<NetParameter> NetParameter_default_instance_;
+
+NetParameter* NetParameter::New(::google::protobuf::Arena* arena) const {
+  NetParameter* n = new NetParameter;
+  if (arena != NULL) {
+    arena->Own(n);
+  }
+  return n;
+}
+
+void NetParameter::Clear() {
+// @@protoc_insertion_point(message_clear_start:caffe.NetParameter)
+#if defined(__clang__)
+#define ZR_HELPER_(f) \
+  _Pragma("clang diagnostic push") \
+  _Pragma("clang diagnostic ignored \"-Winvalid-offsetof\"") \
+  __builtin_offsetof(NetParameter, f) \
+  _Pragma("clang diagnostic pop")
+#else
+#define ZR_HELPER_(f) reinterpret_cast<char*>(\
+  &reinterpret_cast<NetParameter*>(16)->f)
+#endif
+
+#define ZR_(first, last) do {\
+  ::memset(&(first), 0,\
+           ZR_HELPER_(last) - ZR_HELPER_(first) + sizeof(last));\
+} while (0)
+
+  if (_has_bits_[0 / 32] & 113u) {
+    ZR_(force_backward_, debug_info_);
+    if (has_name()) {
+      name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+    }
+    if (has_state()) {
+      if (state_ != NULL) state_->::caffe::NetState::Clear();
+    }
+  }
+
+#undef ZR_HELPER_
+#undef ZR_
+
+  input_.Clear();
+  input_shape_.Clear();
+  input_dim_.Clear();
+  layer_.Clear();
+  layers_.Clear();
+  _has_bits_.Clear();
+  if (_internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->Clear();
+  }
+}
+
+bool NetParameter::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
+  ::google::protobuf::uint32 tag;
+  // @@protoc_insertion_point(parse_start:caffe.NetParameter)
+  for (;;) {
+    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(16383);
+    tag = p.first;
+    if (!p.second) goto handle_unusual;
+    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+      // optional string name = 1;
+      case 1: {
+        if (tag == 10) {
+          DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+                input, this->mutable_name()));
+          ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+            this->name().data(), this->name().length(),
+            ::google::protobuf::internal::WireFormat::PARSE,
+            "caffe.NetParameter.name");
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(18)) goto parse_layers;
+        break;
+      }
+
+      // repeated .caffe.V1LayerParameter layers = 2;
+      case 2: {
+        if (tag == 18) {
+         parse_layers:
+          DO_(input->IncrementRecursionDepth());
+         parse_loop_layers:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth(
+                input, add_layers()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(18)) goto parse_loop_layers;
+        input->UnsafeDecrementRecursionDepth();
+        if (input->ExpectTag(26)) goto parse_input;
+        break;
+      }
+
+      // repeated string input = 3;
+      case 3: {
+        if (tag == 26) {
+         parse_input:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+                input, this->add_input()));
+          ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+            this->input(this->input_size() - 1).data(),
+            this->input(this->input_size() - 1).length(),
+            ::google::protobuf::internal::WireFormat::PARSE,
+            "caffe.NetParameter.input");
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(26)) goto parse_input;
+        if (input->ExpectTag(32)) goto parse_input_dim;
+        break;
+      }
+
+      // repeated int32 input_dim = 4;
+      case 4: {
+        if (tag == 32) {
+         parse_input_dim:
+          DO_((::google::protobuf::internal::WireFormatLite::ReadRepeatedPrimitive<
+                   ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
+                 1, 32, input, this->mutable_input_dim())));
+        } else if (tag == 34) {
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPackedPrimitiveNoInline<
+                   ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
+                 input, this->mutable_input_dim())));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(32)) goto parse_input_dim;
+        if (input->ExpectTag(40)) goto parse_force_backward;
+        break;
+      }
+
+      // optional bool force_backward = 5 [default = false];
+      case 5: {
+        if (tag == 40) {
+         parse_force_backward:
+          set_has_force_backward();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>(
+                 input, &force_backward_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(50)) goto parse_state;
+        break;
+      }
+
+      // optional .caffe.NetState state = 6;
+      case 6: {
+        if (tag == 50) {
+         parse_state:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+               input, mutable_state()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(56)) goto parse_debug_info;
+        break;
+      }
+
+      // optional bool debug_info = 7 [default = false];
+      case 7: {
+        if (tag == 56) {
+         parse_debug_info:
+          set_has_debug_info();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>(
+                 input, &debug_info_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(66)) goto parse_input_shape;
+        break;
+      }
+
+      // repeated .caffe.BlobShape input_shape = 8;
+      case 8: {
+        if (tag == 66) {
+         parse_input_shape:
+          DO_(input->IncrementRecursionDepth());
+         parse_loop_input_shape:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth(
+                input, add_input_shape()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(66)) goto parse_loop_input_shape;
+        if (input->ExpectTag(802)) goto parse_loop_layer;
+        input->UnsafeDecrementRecursionDepth();
+        break;
+      }
+
+      // repeated .caffe.LayerParameter layer = 100;
+      case 100: {
+        if (tag == 802) {
+          DO_(input->IncrementRecursionDepth());
+         parse_loop_layer:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth(
+                input, add_layer()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(802)) goto parse_loop_layer;
+        input->UnsafeDecrementRecursionDepth();
+        if (input->ExpectAtEnd()) goto success;
+        break;
+      }
+
+      default: {
+      handle_unusual:
+        if (tag == 0 ||
+            ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+          goto success;
+        }
+        DO_(::google::protobuf::internal::WireFormat::SkipField(
+              input, tag, mutable_unknown_fields()));
+        break;
+      }
+    }
+  }
+success:
+  // @@protoc_insertion_point(parse_success:caffe.NetParameter)
+  return true;
+failure:
+  // @@protoc_insertion_point(parse_failure:caffe.NetParameter)
+  return false;
+#undef DO_
+}
+
+void NetParameter::SerializeWithCachedSizes(
+    ::google::protobuf::io::CodedOutputStream* output) const {
+  // @@protoc_insertion_point(serialize_start:caffe.NetParameter)
+  // optional string name = 1;
+  if (has_name()) {
+    ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->name().data(), this->name().length(),
+      ::google::protobuf::internal::WireFormat::SERIALIZE,
+      "caffe.NetParameter.name");
+    ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
+      1, this->name(), output);
+  }
+
+  // repeated .caffe.V1LayerParameter layers = 2;
+  for (unsigned int i = 0, n = this->layers_size(); i < n; i++) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      2, this->layers(i), output);
+  }
+
+  // repeated string input = 3;
+  for (int i = 0; i < this->input_size(); i++) {
+    ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->input(i).data(), this->input(i).length(),
+      ::google::protobuf::internal::WireFormat::SERIALIZE,
+      "caffe.NetParameter.input");
+    ::google::protobuf::internal::WireFormatLite::WriteString(
+      3, this->input(i), output);
+  }
+
+  // repeated int32 input_dim = 4;
+  for (int i = 0; i < this->input_dim_size(); i++) {
+    ::google::protobuf::internal::WireFormatLite::WriteInt32(
+      4, this->input_dim(i), output);
+  }
+
+  // optional bool force_backward = 5 [default = false];
+  if (has_force_backward()) {
+    ::google::protobuf::internal::WireFormatLite::WriteBool(5, this->force_backward(), output);
+  }
+
+  // optional .caffe.NetState state = 6;
+  if (has_state()) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      6, *this->state_, output);
+  }
+
+  // optional bool debug_info = 7 [default = false];
+  if (has_debug_info()) {
+    ::google::protobuf::internal::WireFormatLite::WriteBool(7, this->debug_info(), output);
+  }
+
+  // repeated .caffe.BlobShape input_shape = 8;
+  for (unsigned int i = 0, n = this->input_shape_size(); i < n; i++) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      8, this->input_shape(i), output);
+  }
+
+  // repeated .caffe.LayerParameter layer = 100;
+  for (unsigned int i = 0, n = this->layer_size(); i < n; i++) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      100, this->layer(i), output);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
+        unknown_fields(), output);
+  }
+  // @@protoc_insertion_point(serialize_end:caffe.NetParameter)
+}
+
+::google::protobuf::uint8* NetParameter::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
+  (void)deterministic; // Unused
+  // @@protoc_insertion_point(serialize_to_array_start:caffe.NetParameter)
+  // optional string name = 1;
+  if (has_name()) {
+    ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->name().data(), this->name().length(),
+      ::google::protobuf::internal::WireFormat::SERIALIZE,
+      "caffe.NetParameter.name");
+    target =
+      ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
+        1, this->name(), target);
+  }
+
+  // repeated .caffe.V1LayerParameter layers = 2;
+  for (unsigned int i = 0, n = this->layers_size(); i < n; i++) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        2, this->layers(i), false, target);
+  }
+
+  // repeated string input = 3;
+  for (int i = 0; i < this->input_size(); i++) {
+    ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->input(i).data(), this->input(i).length(),
+      ::google::protobuf::internal::WireFormat::SERIALIZE,
+      "caffe.NetParameter.input");
+    target = ::google::protobuf::internal::WireFormatLite::
+      WriteStringToArray(3, this->input(i), target);
+  }
+
+  // repeated int32 input_dim = 4;
+  for (int i = 0; i < this->input_dim_size(); i++) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      WriteInt32ToArray(4, this->input_dim(i), target);
+  }
+
+  // optional bool force_backward = 5 [default = false];
+  if (has_force_backward()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(5, this->force_backward(), target);
+  }
+
+  // optional .caffe.NetState state = 6;
+  if (has_state()) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        6, *this->state_, false, target);
+  }
+
+  // optional bool debug_info = 7 [default = false];
+  if (has_debug_info()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(7, this->debug_info(), target);
+  }
+
+  // repeated .caffe.BlobShape input_shape = 8;
+  for (unsigned int i = 0, n = this->input_shape_size(); i < n; i++) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        8, this->input_shape(i), false, target);
+  }
+
+  // repeated .caffe.LayerParameter layer = 100;
+  for (unsigned int i = 0, n = this->layer_size(); i < n; i++) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        100, this->layer(i), false, target);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
+        unknown_fields(), target);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:caffe.NetParameter)
+  return target;
+}
+
+size_t NetParameter::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:caffe.NetParameter)
+  size_t total_size = 0;
+
+  if (_has_bits_[0 / 32] & 113u) {
+    // optional string name = 1;
+    if (has_name()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::StringSize(
+          this->name());
+    }
+
+    // optional bool force_backward = 5 [default = false];
+    if (has_force_backward()) {
+      total_size += 1 + 1;
+    }
+
+    // optional .caffe.NetState state = 6;
+    if (has_state()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          *this->state_);
+    }
+
+    // optional bool debug_info = 7 [default = false];
+    if (has_debug_info()) {
+      total_size += 1 + 1;
+    }
+
+  }
+  // repeated string input = 3;
+  total_size += 1 *
+      ::google::protobuf::internal::FromIntSize(this->input_size());
+  for (int i = 0; i < this->input_size(); i++) {
+    total_size += ::google::protobuf::internal::WireFormatLite::StringSize(
+      this->input(i));
+  }
+
+  // repeated .caffe.BlobShape input_shape = 8;
+  {
+    unsigned int count = this->input_shape_size();
+    total_size += 1UL * count;
+    for (unsigned int i = 0; i < count; i++) {
+      total_size +=
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          this->input_shape(i));
+    }
+  }
+
+  // repeated int32 input_dim = 4;
+  {
+    size_t data_size = 0;
+    unsigned int count = this->input_dim_size();
+    for (unsigned int i = 0; i < count; i++) {
+      data_size += ::google::protobuf::internal::WireFormatLite::
+        Int32Size(this->input_dim(i));
+    }
+    total_size += 1 *
+                  ::google::protobuf::internal::FromIntSize(this->input_dim_size());
+    total_size += data_size;
+  }
+
+  // repeated .caffe.LayerParameter layer = 100;
+  {
+    unsigned int count = this->layer_size();
+    total_size += 2UL * count;
+    for (unsigned int i = 0; i < count; i++) {
+      total_size +=
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          this->layer(i));
+    }
+  }
+
+  // repeated .caffe.V1LayerParameter layers = 2;
+  {
+    unsigned int count = this->layers_size();
+    total_size += 1UL * count;
+    for (unsigned int i = 0; i < count; i++) {
+      total_size +=
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          this->layers(i));
+    }
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    total_size +=
+      ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
+        unknown_fields());
+  }
+  int cached_size = ::google::protobuf::internal::ToCachedSize(total_size);
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = cached_size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+  return total_size;
+}
+
+void NetParameter::MergeFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_merge_from_start:caffe.NetParameter)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const NetParameter* source =
+      ::google::protobuf::internal::DynamicCastToGenerated<const NetParameter>(
+          &from);
+  if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:caffe.NetParameter)
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:caffe.NetParameter)
+    UnsafeMergeFrom(*source);
+  }
+}
+
+void NetParameter::MergeFrom(const NetParameter& from) {
+// @@protoc_insertion_point(class_specific_merge_from_start:caffe.NetParameter)
+  if (GOOGLE_PREDICT_TRUE(&from != this)) {
+    UnsafeMergeFrom(from);
+  } else {
+    MergeFromFail(__LINE__);
+  }
+}
+
+void NetParameter::UnsafeMergeFrom(const NetParameter& from) {
+  GOOGLE_DCHECK(&from != this);
+  input_.UnsafeMergeFrom(from.input_);
+  input_shape_.MergeFrom(from.input_shape_);
+  input_dim_.UnsafeMergeFrom(from.input_dim_);
+  layer_.MergeFrom(from.layer_);
+  layers_.MergeFrom(from.layers_);
+  if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+    if (from.has_name()) {
+      set_has_name();
+      name_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.name_);
+    }
+    if (from.has_force_backward()) {
+      set_force_backward(from.force_backward());
+    }
+    if (from.has_state()) {
+      mutable_state()->::caffe::NetState::MergeFrom(from.state());
+    }
+    if (from.has_debug_info()) {
+      set_debug_info(from.debug_info());
+    }
+  }
+  if (from._internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::UnknownFieldSet::MergeToInternalMetdata(
+      from.unknown_fields(), &_internal_metadata_);
+  }
+}
+
+void NetParameter::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:caffe.NetParameter)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void NetParameter::CopyFrom(const NetParameter& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:caffe.NetParameter)
+  if (&from == this) return;
+  Clear();
+  UnsafeMergeFrom(from);
+}
+
+bool NetParameter::IsInitialized() const {
+
+  return true;
+}
+
+void NetParameter::Swap(NetParameter* other) {
+  if (other == this) return;
+  InternalSwap(other);
+}
+void NetParameter::InternalSwap(NetParameter* other) {
+  name_.Swap(&other->name_);
+  input_.UnsafeArenaSwap(&other->input_);
+  input_shape_.UnsafeArenaSwap(&other->input_shape_);
+  input_dim_.UnsafeArenaSwap(&other->input_dim_);
+  std::swap(force_backward_, other->force_backward_);
+  std::swap(state_, other->state_);
+  std::swap(debug_info_, other->debug_info_);
+  layer_.UnsafeArenaSwap(&other->layer_);
+  layers_.UnsafeArenaSwap(&other->layers_);
+  std::swap(_has_bits_[0], other->_has_bits_[0]);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
+}
+
+::google::protobuf::Metadata NetParameter::GetMetadata() const {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::Metadata metadata;
+  metadata.descriptor = NetParameter_descriptor_;
+  metadata.reflection = NetParameter_reflection_;
+  return metadata;
+}
+
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// NetParameter
+
+// optional string name = 1;
+bool NetParameter::has_name() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+void NetParameter::set_has_name() {
+  _has_bits_[0] |= 0x00000001u;
+}
+void NetParameter::clear_has_name() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+void NetParameter::clear_name() {
+  name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  clear_has_name();
+}
+const ::std::string& NetParameter::name() const {
+  // @@protoc_insertion_point(field_get:caffe.NetParameter.name)
+  return name_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+void NetParameter::set_name(const ::std::string& value) {
+  set_has_name();
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:caffe.NetParameter.name)
+}
+void NetParameter::set_name(const char* value) {
+  set_has_name();
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:caffe.NetParameter.name)
+}
+void NetParameter::set_name(const char* value, size_t size) {
+  set_has_name();
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:caffe.NetParameter.name)
+}
+::std::string* NetParameter::mutable_name() {
+  set_has_name();
+  // @@protoc_insertion_point(field_mutable:caffe.NetParameter.name)
+  return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+::std::string* NetParameter::release_name() {
+  // @@protoc_insertion_point(field_release:caffe.NetParameter.name)
+  clear_has_name();
+  return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+void NetParameter::set_allocated_name(::std::string* name) {
+  if (name != NULL) {
+    set_has_name();
+  } else {
+    clear_has_name();
+  }
+  name_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), name);
+  // @@protoc_insertion_point(field_set_allocated:caffe.NetParameter.name)
+}
+
+// repeated string input = 3;
+int NetParameter::input_size() const {
+  return input_.size();
+}
+void NetParameter::clear_input() {
+  input_.Clear();
+}
+const ::std::string& NetParameter::input(int index) const {
+  // @@protoc_insertion_point(field_get:caffe.NetParameter.input)
+  return input_.Get(index);
+}
+::std::string* NetParameter::mutable_input(int index) {
+  // @@protoc_insertion_point(field_mutable:caffe.NetParameter.input)
+  return input_.Mutable(index);
+}
+void NetParameter::set_input(int index, const ::std::string& value) {
+  // @@protoc_insertion_point(field_set:caffe.NetParameter.input)
+  input_.Mutable(index)->assign(value);
+}
+void NetParameter::set_input(int index, const char* value) {
+  input_.Mutable(index)->assign(value);
+  // @@protoc_insertion_point(field_set_char:caffe.NetParameter.input)
+}
+void NetParameter::set_input(int index, const char* value, size_t size) {
+  input_.Mutable(index)->assign(
+    reinterpret_cast<const char*>(value), size);
+  // @@protoc_insertion_point(field_set_pointer:caffe.NetParameter.input)
+}
+::std::string* NetParameter::add_input() {
+  // @@protoc_insertion_point(field_add_mutable:caffe.NetParameter.input)
+  return input_.Add();
+}
+void NetParameter::add_input(const ::std::string& value) {
+  input_.Add()->assign(value);
+  // @@protoc_insertion_point(field_add:caffe.NetParameter.input)
+}
+void NetParameter::add_input(const char* value) {
+  input_.Add()->assign(value);
+  // @@protoc_insertion_point(field_add_char:caffe.NetParameter.input)
+}
+void NetParameter::add_input(const char* value, size_t size) {
+  input_.Add()->assign(reinterpret_cast<const char*>(value), size);
+  // @@protoc_insertion_point(field_add_pointer:caffe.NetParameter.input)
+}
+const ::google::protobuf::RepeatedPtrField< ::std::string>&
+NetParameter::input() const {
+  // @@protoc_insertion_point(field_list:caffe.NetParameter.input)
+  return input_;
+}
+::google::protobuf::RepeatedPtrField< ::std::string>*
+NetParameter::mutable_input() {
+  // @@protoc_insertion_point(field_mutable_list:caffe.NetParameter.input)
+  return &input_;
+}
+
+// repeated .caffe.BlobShape input_shape = 8;
+int NetParameter::input_shape_size() const {
+  return input_shape_.size();
+}
+void NetParameter::clear_input_shape() {
+  input_shape_.Clear();
+}
+const ::caffe::BlobShape& NetParameter::input_shape(int index) const {
+  // @@protoc_insertion_point(field_get:caffe.NetParameter.input_shape)
+  return input_shape_.Get(index);
+}
+::caffe::BlobShape* NetParameter::mutable_input_shape(int index) {
+  // @@protoc_insertion_point(field_mutable:caffe.NetParameter.input_shape)
+  return input_shape_.Mutable(index);
+}
+::caffe::BlobShape* NetParameter::add_input_shape() {
+  // @@protoc_insertion_point(field_add:caffe.NetParameter.input_shape)
+  return input_shape_.Add();
+}
+::google::protobuf::RepeatedPtrField< ::caffe::BlobShape >*
+NetParameter::mutable_input_shape() {
+  // @@protoc_insertion_point(field_mutable_list:caffe.NetParameter.input_shape)
+  return &input_shape_;
+}
+const ::google::protobuf::RepeatedPtrField< ::caffe::BlobShape >&
+NetParameter::input_shape() const {
+  // @@protoc_insertion_point(field_list:caffe.NetParameter.input_shape)
+  return input_shape_;
+}
+
+// repeated int32 input_dim = 4;
+int NetParameter::input_dim_size() const {
+  return input_dim_.size();
+}
+void NetParameter::clear_input_dim() {
+  input_dim_.Clear();
+}
+::google::protobuf::int32 NetParameter::input_dim(int index) const {
+  // @@protoc_insertion_point(field_get:caffe.NetParameter.input_dim)
+  return input_dim_.Get(index);
+}
+void NetParameter::set_input_dim(int index, ::google::protobuf::int32 value) {
+  input_dim_.Set(index, value);
+  // @@protoc_insertion_point(field_set:caffe.NetParameter.input_dim)
+}
+void NetParameter::add_input_dim(::google::protobuf::int32 value) {
+  input_dim_.Add(value);
+  // @@protoc_insertion_point(field_add:caffe.NetParameter.input_dim)
+}
+const ::google::protobuf::RepeatedField< ::google::protobuf::int32 >&
+NetParameter::input_dim() const {
+  // @@protoc_insertion_point(field_list:caffe.NetParameter.input_dim)
+  return input_dim_;
+}
+::google::protobuf::RepeatedField< ::google::protobuf::int32 >*
+NetParameter::mutable_input_dim() {
+  // @@protoc_insertion_point(field_mutable_list:caffe.NetParameter.input_dim)
+  return &input_dim_;
+}
+
+// optional bool force_backward = 5 [default = false];
+bool NetParameter::has_force_backward() const {
+  return (_has_bits_[0] & 0x00000010u) != 0;
+}
+void NetParameter::set_has_force_backward() {
+  _has_bits_[0] |= 0x00000010u;
+}
+void NetParameter::clear_has_force_backward() {
+  _has_bits_[0] &= ~0x00000010u;
+}
+void NetParameter::clear_force_backward() {
+  force_backward_ = false;
+  clear_has_force_backward();
+}
+bool NetParameter::force_backward() const {
+  // @@protoc_insertion_point(field_get:caffe.NetParameter.force_backward)
+  return force_backward_;
+}
+void NetParameter::set_force_backward(bool value) {
+  set_has_force_backward();
+  force_backward_ = value;
+  // @@protoc_insertion_point(field_set:caffe.NetParameter.force_backward)
+}
+
+// optional .caffe.NetState state = 6;
+bool NetParameter::has_state() const {
+  return (_has_bits_[0] & 0x00000020u) != 0;
+}
+void NetParameter::set_has_state() {
+  _has_bits_[0] |= 0x00000020u;
+}
+void NetParameter::clear_has_state() {
+  _has_bits_[0] &= ~0x00000020u;
+}
+void NetParameter::clear_state() {
+  if (state_ != NULL) state_->::caffe::NetState::Clear();
+  clear_has_state();
+}
+const ::caffe::NetState& NetParameter::state() const {
+  // @@protoc_insertion_point(field_get:caffe.NetParameter.state)
+  return state_ != NULL ? *state_
+                         : *::caffe::NetState::internal_default_instance();
+}
+::caffe::NetState* NetParameter::mutable_state() {
+  set_has_state();
+  if (state_ == NULL) {
+    state_ = new ::caffe::NetState;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.NetParameter.state)
+  return state_;
+}
+::caffe::NetState* NetParameter::release_state() {
+  // @@protoc_insertion_point(field_release:caffe.NetParameter.state)
+  clear_has_state();
+  ::caffe::NetState* temp = state_;
+  state_ = NULL;
+  return temp;
+}
+void NetParameter::set_allocated_state(::caffe::NetState* state) {
+  delete state_;
+  state_ = state;
+  if (state) {
+    set_has_state();
+  } else {
+    clear_has_state();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.NetParameter.state)
+}
+
+// optional bool debug_info = 7 [default = false];
+bool NetParameter::has_debug_info() const {
+  return (_has_bits_[0] & 0x00000040u) != 0;
+}
+void NetParameter::set_has_debug_info() {
+  _has_bits_[0] |= 0x00000040u;
+}
+void NetParameter::clear_has_debug_info() {
+  _has_bits_[0] &= ~0x00000040u;
+}
+void NetParameter::clear_debug_info() {
+  debug_info_ = false;
+  clear_has_debug_info();
+}
+bool NetParameter::debug_info() const {
+  // @@protoc_insertion_point(field_get:caffe.NetParameter.debug_info)
+  return debug_info_;
+}
+void NetParameter::set_debug_info(bool value) {
+  set_has_debug_info();
+  debug_info_ = value;
+  // @@protoc_insertion_point(field_set:caffe.NetParameter.debug_info)
+}
+
+// repeated .caffe.LayerParameter layer = 100;
+int NetParameter::layer_size() const {
+  return layer_.size();
+}
+void NetParameter::clear_layer() {
+  layer_.Clear();
+}
+const ::caffe::LayerParameter& NetParameter::layer(int index) const {
+  // @@protoc_insertion_point(field_get:caffe.NetParameter.layer)
+  return layer_.Get(index);
+}
+::caffe::LayerParameter* NetParameter::mutable_layer(int index) {
+  // @@protoc_insertion_point(field_mutable:caffe.NetParameter.layer)
+  return layer_.Mutable(index);
+}
+::caffe::LayerParameter* NetParameter::add_layer() {
+  // @@protoc_insertion_point(field_add:caffe.NetParameter.layer)
+  return layer_.Add();
+}
+::google::protobuf::RepeatedPtrField< ::caffe::LayerParameter >*
+NetParameter::mutable_layer() {
+  // @@protoc_insertion_point(field_mutable_list:caffe.NetParameter.layer)
+  return &layer_;
+}
+const ::google::protobuf::RepeatedPtrField< ::caffe::LayerParameter >&
+NetParameter::layer() const {
+  // @@protoc_insertion_point(field_list:caffe.NetParameter.layer)
+  return layer_;
+}
+
+// repeated .caffe.V1LayerParameter layers = 2;
+int NetParameter::layers_size() const {
+  return layers_.size();
+}
+void NetParameter::clear_layers() {
+  layers_.Clear();
+}
+const ::caffe::V1LayerParameter& NetParameter::layers(int index) const {
+  // @@protoc_insertion_point(field_get:caffe.NetParameter.layers)
+  return layers_.Get(index);
+}
+::caffe::V1LayerParameter* NetParameter::mutable_layers(int index) {
+  // @@protoc_insertion_point(field_mutable:caffe.NetParameter.layers)
+  return layers_.Mutable(index);
+}
+::caffe::V1LayerParameter* NetParameter::add_layers() {
+  // @@protoc_insertion_point(field_add:caffe.NetParameter.layers)
+  return layers_.Add();
+}
+::google::protobuf::RepeatedPtrField< ::caffe::V1LayerParameter >*
+NetParameter::mutable_layers() {
+  // @@protoc_insertion_point(field_mutable_list:caffe.NetParameter.layers)
+  return &layers_;
+}
+const ::google::protobuf::RepeatedPtrField< ::caffe::V1LayerParameter >&
+NetParameter::layers() const {
+  // @@protoc_insertion_point(field_list:caffe.NetParameter.layers)
+  return layers_;
+}
+
+inline const NetParameter* NetParameter::internal_default_instance() {
+  return &NetParameter_default_instance_.get();
+}
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
+
+// ===================================================================
+
+const ::google::protobuf::EnumDescriptor* SolverParameter_SolverMode_descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return SolverParameter_SolverMode_descriptor_;
+}
+bool SolverParameter_SolverMode_IsValid(int value) {
+  switch (value) {
+    case 0:
+    case 1:
+      return true;
+    default:
+      return false;
+  }
+}
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const SolverParameter_SolverMode SolverParameter::CPU;
+const SolverParameter_SolverMode SolverParameter::GPU;
+const SolverParameter_SolverMode SolverParameter::SolverMode_MIN;
+const SolverParameter_SolverMode SolverParameter::SolverMode_MAX;
+const int SolverParameter::SolverMode_ARRAYSIZE;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+const ::google::protobuf::EnumDescriptor* SolverParameter_SolverType_descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return SolverParameter_SolverType_descriptor_;
+}
+bool SolverParameter_SolverType_IsValid(int value) {
+  switch (value) {
+    case 0:
+    case 1:
+    case 2:
+      return true;
+    default:
+      return false;
+  }
+}
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const SolverParameter_SolverType SolverParameter::SGD;
+const SolverParameter_SolverType SolverParameter::NESTEROV;
+const SolverParameter_SolverType SolverParameter::ADAGRAD;
+const SolverParameter_SolverType SolverParameter::SolverType_MIN;
+const SolverParameter_SolverType SolverParameter::SolverType_MAX;
+const int SolverParameter::SolverType_ARRAYSIZE;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+::std::string* SolverParameter::_default_regularization_type_ = NULL;
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const int SolverParameter::kNetFieldNumber;
+const int SolverParameter::kNetParamFieldNumber;
+const int SolverParameter::kTrainNetFieldNumber;
+const int SolverParameter::kTestNetFieldNumber;
+const int SolverParameter::kTrainNetParamFieldNumber;
+const int SolverParameter::kTestNetParamFieldNumber;
+const int SolverParameter::kTrainStateFieldNumber;
+const int SolverParameter::kTestStateFieldNumber;
+const int SolverParameter::kTestIterFieldNumber;
+const int SolverParameter::kTestIntervalFieldNumber;
+const int SolverParameter::kTestComputeLossFieldNumber;
+const int SolverParameter::kTestInitializationFieldNumber;
+const int SolverParameter::kBaseLrFieldNumber;
+const int SolverParameter::kDisplayFieldNumber;
+const int SolverParameter::kAverageLossFieldNumber;
+const int SolverParameter::kMaxIterFieldNumber;
+const int SolverParameter::kIterSizeFieldNumber;
+const int SolverParameter::kLrPolicyFieldNumber;
+const int SolverParameter::kGammaFieldNumber;
+const int SolverParameter::kPowerFieldNumber;
+const int SolverParameter::kMomentumFieldNumber;
+const int SolverParameter::kWeightDecayFieldNumber;
+const int SolverParameter::kRegularizationTypeFieldNumber;
+const int SolverParameter::kStepsizeFieldNumber;
+const int SolverParameter::kStepvalueFieldNumber;
+const int SolverParameter::kClipGradientsFieldNumber;
+const int SolverParameter::kSnapshotFieldNumber;
+const int SolverParameter::kSnapshotPrefixFieldNumber;
+const int SolverParameter::kSnapshotDiffFieldNumber;
+const int SolverParameter::kSolverModeFieldNumber;
+const int SolverParameter::kDeviceIdFieldNumber;
+const int SolverParameter::kRandomSeedFieldNumber;
+const int SolverParameter::kSolverTypeFieldNumber;
+const int SolverParameter::kDeltaFieldNumber;
+const int SolverParameter::kDebugInfoFieldNumber;
+const int SolverParameter::kSnapshotAfterTrainFieldNumber;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+
+SolverParameter::SolverParameter()
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+  if (this != internal_default_instance()) protobuf_InitDefaults_caffe_2eproto();
+  SharedCtor();
+  // @@protoc_insertion_point(constructor:caffe.SolverParameter)
+}
+
+void SolverParameter::InitAsDefaultInstance() {
+  net_param_ = const_cast< ::caffe::NetParameter*>(
+      ::caffe::NetParameter::internal_default_instance());
+  train_net_param_ = const_cast< ::caffe::NetParameter*>(
+      ::caffe::NetParameter::internal_default_instance());
+  train_state_ = const_cast< ::caffe::NetState*>(
+      ::caffe::NetState::internal_default_instance());
+}
+
+SolverParameter::SolverParameter(const SolverParameter& from)
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
+  SharedCtor();
+  UnsafeMergeFrom(from);
+  // @@protoc_insertion_point(copy_constructor:caffe.SolverParameter)
+}
+
+void SolverParameter::SharedCtor() {
+  net_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  train_net_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  lr_policy_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  regularization_type_.UnsafeSetDefault(_default_regularization_type_);
+  snapshot_prefix_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  net_param_ = NULL;
+  train_net_param_ = NULL;
+  train_state_ = NULL;
+  ::memset(&test_interval_, 0, reinterpret_cast<char*>(&solver_type_) -
+    reinterpret_cast<char*>(&test_interval_) + sizeof(solver_type_));
+  average_loss_ = 1;
+  iter_size_ = 1;
+  test_initialization_ = true;
+  snapshot_after_train_ = true;
+  clip_gradients_ = -1;
+  random_seed_ = GOOGLE_LONGLONG(-1);
+  solver_mode_ = 1;
+  delta_ = 1e-08f;
+  _cached_size_ = 0;
+}
+
+SolverParameter::~SolverParameter() {
+  // @@protoc_insertion_point(destructor:caffe.SolverParameter)
+  SharedDtor();
+}
+
+void SolverParameter::SharedDtor() {
+  net_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  train_net_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  lr_policy_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  regularization_type_.DestroyNoArena(_default_regularization_type_);
+  snapshot_prefix_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  if (this != &SolverParameter_default_instance_.get()) {
+    delete net_param_;
+    delete train_net_param_;
+    delete train_state_;
+  }
+}
+
+void SolverParameter::SetCachedSize(int size) const {
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* SolverParameter::descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return SolverParameter_descriptor_;
+}
+
+const SolverParameter& SolverParameter::default_instance() {
+  protobuf_InitDefaults_caffe_2eproto();
+  return *internal_default_instance();
+}
+
+::google::protobuf::internal::ExplicitlyConstructed<SolverParameter> SolverParameter_default_instance_;
+
+SolverParameter* SolverParameter::New(::google::protobuf::Arena* arena) const {
+  SolverParameter* n = new SolverParameter;
+  if (arena != NULL) {
+    arena->Own(n);
+  }
+  return n;
+}
+
+void SolverParameter::Clear() {
+// @@protoc_insertion_point(message_clear_start:caffe.SolverParameter)
+#if defined(__clang__)
+#define ZR_HELPER_(f) \
+  _Pragma("clang diagnostic push") \
+  _Pragma("clang diagnostic ignored \"-Winvalid-offsetof\"") \
+  __builtin_offsetof(SolverParameter, f) \
+  _Pragma("clang diagnostic pop")
+#else
+#define ZR_HELPER_(f) reinterpret_cast<char*>(\
+  &reinterpret_cast<SolverParameter*>(16)->f)
+#endif
+
+#define ZR_(first, last) do {\
+  ::memset(&(first), 0,\
+           ZR_HELPER_(last) - ZR_HELPER_(first) + sizeof(last));\
+} while (0)
+
+  if (_has_bits_[0 / 32] & 87u) {
+    if (has_net()) {
+      net_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+    }
+    if (has_net_param()) {
+      if (net_param_ != NULL) net_param_->::caffe::NetParameter::Clear();
+    }
+    if (has_train_net()) {
+      train_net_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+    }
+    if (has_train_net_param()) {
+      if (train_net_param_ != NULL) train_net_param_->::caffe::NetParameter::Clear();
+    }
+    if (has_train_state()) {
+      if (train_state_ != NULL) train_state_->::caffe::NetState::Clear();
+    }
+  }
+  if (_has_bits_[8 / 32] & 65024u) {
+    ZR_(test_interval_, max_iter_);
+    test_compute_loss_ = false;
+    test_initialization_ = true;
+    average_loss_ = 1;
+  }
+  if (_has_bits_[16 / 32] & 16711680u) {
+    ZR_(gamma_, stepsize_);
+    iter_size_ = 1;
+    if (has_lr_policy()) {
+      lr_policy_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+    }
+    if (has_regularization_type()) {
+      regularization_type_.ClearToDefaultNoArena(_default_regularization_type_);
+    }
+  }
+  if (_has_bits_[24 / 32] & 4261412864u) {
+    ZR_(snapshot_, device_id_);
+    clip_gradients_ = -1;
+    if (has_snapshot_prefix()) {
+      snapshot_prefix_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+    }
+    snapshot_diff_ = false;
+    solver_mode_ = 1;
+    random_seed_ = GOOGLE_LONGLONG(-1);
+  }
+  if (_has_bits_[32 / 32] & 15u) {
+    solver_type_ = 0;
+    delta_ = 1e-08f;
+    debug_info_ = false;
+    snapshot_after_train_ = true;
+  }
+
+#undef ZR_HELPER_
+#undef ZR_
+
+  test_net_.Clear();
+  test_net_param_.Clear();
+  test_state_.Clear();
+  test_iter_.Clear();
+  stepvalue_.Clear();
+  _has_bits_.Clear();
+  if (_internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->Clear();
+  }
+}
+
+bool SolverParameter::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
+  ::google::protobuf::uint32 tag;
+  // @@protoc_insertion_point(parse_start:caffe.SolverParameter)
+  for (;;) {
+    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(16383);
+    tag = p.first;
+    if (!p.second) goto handle_unusual;
+    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+      // optional string train_net = 1;
+      case 1: {
+        if (tag == 10) {
+          DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+                input, this->mutable_train_net()));
+          ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+            this->train_net().data(), this->train_net().length(),
+            ::google::protobuf::internal::WireFormat::PARSE,
+            "caffe.SolverParameter.train_net");
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(18)) goto parse_test_net;
+        break;
+      }
+
+      // repeated string test_net = 2;
+      case 2: {
+        if (tag == 18) {
+         parse_test_net:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+                input, this->add_test_net()));
+          ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+            this->test_net(this->test_net_size() - 1).data(),
+            this->test_net(this->test_net_size() - 1).length(),
+            ::google::protobuf::internal::WireFormat::PARSE,
+            "caffe.SolverParameter.test_net");
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(18)) goto parse_test_net;
+        if (input->ExpectTag(24)) goto parse_test_iter;
+        break;
+      }
+
+      // repeated int32 test_iter = 3;
+      case 3: {
+        if (tag == 24) {
+         parse_test_iter:
+          DO_((::google::protobuf::internal::WireFormatLite::ReadRepeatedPrimitive<
+                   ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
+                 1, 24, input, this->mutable_test_iter())));
+        } else if (tag == 26) {
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPackedPrimitiveNoInline<
+                   ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
+                 input, this->mutable_test_iter())));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(24)) goto parse_test_iter;
+        if (input->ExpectTag(32)) goto parse_test_interval;
+        break;
+      }
+
+      // optional int32 test_interval = 4 [default = 0];
+      case 4: {
+        if (tag == 32) {
+         parse_test_interval:
+          set_has_test_interval();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
+                 input, &test_interval_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(45)) goto parse_base_lr;
+        break;
+      }
+
+      // optional float base_lr = 5;
+      case 5: {
+        if (tag == 45) {
+         parse_base_lr:
+          set_has_base_lr();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
+                 input, &base_lr_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(48)) goto parse_display;
+        break;
+      }
+
+      // optional int32 display = 6;
+      case 6: {
+        if (tag == 48) {
+         parse_display:
+          set_has_display();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
+                 input, &display_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(56)) goto parse_max_iter;
+        break;
+      }
+
+      // optional int32 max_iter = 7;
+      case 7: {
+        if (tag == 56) {
+         parse_max_iter:
+          set_has_max_iter();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
+                 input, &max_iter_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(66)) goto parse_lr_policy;
+        break;
+      }
+
+      // optional string lr_policy = 8;
+      case 8: {
+        if (tag == 66) {
+         parse_lr_policy:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+                input, this->mutable_lr_policy()));
+          ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+            this->lr_policy().data(), this->lr_policy().length(),
+            ::google::protobuf::internal::WireFormat::PARSE,
+            "caffe.SolverParameter.lr_policy");
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(77)) goto parse_gamma;
+        break;
+      }
+
+      // optional float gamma = 9;
+      case 9: {
+        if (tag == 77) {
+         parse_gamma:
+          set_has_gamma();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
+                 input, &gamma_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(85)) goto parse_power;
+        break;
+      }
+
+      // optional float power = 10;
+      case 10: {
+        if (tag == 85) {
+         parse_power:
+          set_has_power();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
+                 input, &power_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(93)) goto parse_momentum;
+        break;
+      }
+
+      // optional float momentum = 11;
+      case 11: {
+        if (tag == 93) {
+         parse_momentum:
+          set_has_momentum();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
+                 input, &momentum_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(101)) goto parse_weight_decay;
+        break;
+      }
+
+      // optional float weight_decay = 12;
+      case 12: {
+        if (tag == 101) {
+         parse_weight_decay:
+          set_has_weight_decay();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
+                 input, &weight_decay_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(104)) goto parse_stepsize;
+        break;
+      }
+
+      // optional int32 stepsize = 13;
+      case 13: {
+        if (tag == 104) {
+         parse_stepsize:
+          set_has_stepsize();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
+                 input, &stepsize_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(112)) goto parse_snapshot;
+        break;
+      }
+
+      // optional int32 snapshot = 14 [default = 0];
+      case 14: {
+        if (tag == 112) {
+         parse_snapshot:
+          set_has_snapshot();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
+                 input, &snapshot_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(122)) goto parse_snapshot_prefix;
+        break;
+      }
+
+      // optional string snapshot_prefix = 15;
+      case 15: {
+        if (tag == 122) {
+         parse_snapshot_prefix:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+                input, this->mutable_snapshot_prefix()));
+          ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+            this->snapshot_prefix().data(), this->snapshot_prefix().length(),
+            ::google::protobuf::internal::WireFormat::PARSE,
+            "caffe.SolverParameter.snapshot_prefix");
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(128)) goto parse_snapshot_diff;
+        break;
+      }
+
+      // optional bool snapshot_diff = 16 [default = false];
+      case 16: {
+        if (tag == 128) {
+         parse_snapshot_diff:
+          set_has_snapshot_diff();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>(
+                 input, &snapshot_diff_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(136)) goto parse_solver_mode;
+        break;
+      }
+
+      // optional .caffe.SolverParameter.SolverMode solver_mode = 17 [default = GPU];
+      case 17: {
+        if (tag == 136) {
+         parse_solver_mode:
+          int value;
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>(
+                 input, &value)));
+          if (::caffe::SolverParameter_SolverMode_IsValid(value)) {
+            set_solver_mode(static_cast< ::caffe::SolverParameter_SolverMode >(value));
+          } else {
+            mutable_unknown_fields()->AddVarint(17, value);
+          }
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(144)) goto parse_device_id;
+        break;
+      }
+
+      // optional int32 device_id = 18 [default = 0];
+      case 18: {
+        if (tag == 144) {
+         parse_device_id:
+          set_has_device_id();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
+                 input, &device_id_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(152)) goto parse_test_compute_loss;
+        break;
+      }
+
+      // optional bool test_compute_loss = 19 [default = false];
+      case 19: {
+        if (tag == 152) {
+         parse_test_compute_loss:
+          set_has_test_compute_loss();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>(
+                 input, &test_compute_loss_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(160)) goto parse_random_seed;
+        break;
+      }
+
+      // optional int64 random_seed = 20 [default = -1];
+      case 20: {
+        if (tag == 160) {
+         parse_random_seed:
+          set_has_random_seed();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::int64, ::google::protobuf::internal::WireFormatLite::TYPE_INT64>(
+                 input, &random_seed_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(170)) goto parse_train_net_param;
+        break;
+      }
+
+      // optional .caffe.NetParameter train_net_param = 21;
+      case 21: {
+        if (tag == 170) {
+         parse_train_net_param:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+               input, mutable_train_net_param()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(178)) goto parse_test_net_param;
+        break;
+      }
+
+      // repeated .caffe.NetParameter test_net_param = 22;
+      case 22: {
+        if (tag == 178) {
+         parse_test_net_param:
+          DO_(input->IncrementRecursionDepth());
+         parse_loop_test_net_param:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth(
+                input, add_test_net_param()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(178)) goto parse_loop_test_net_param;
+        input->UnsafeDecrementRecursionDepth();
+        if (input->ExpectTag(184)) goto parse_debug_info;
+        break;
+      }
+
+      // optional bool debug_info = 23 [default = false];
+      case 23: {
+        if (tag == 184) {
+         parse_debug_info:
+          set_has_debug_info();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>(
+                 input, &debug_info_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(194)) goto parse_net;
+        break;
+      }
+
+      // optional string net = 24;
+      case 24: {
+        if (tag == 194) {
+         parse_net:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+                input, this->mutable_net()));
+          ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+            this->net().data(), this->net().length(),
+            ::google::protobuf::internal::WireFormat::PARSE,
+            "caffe.SolverParameter.net");
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(202)) goto parse_net_param;
+        break;
+      }
+
+      // optional .caffe.NetParameter net_param = 25;
+      case 25: {
+        if (tag == 202) {
+         parse_net_param:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+               input, mutable_net_param()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(210)) goto parse_train_state;
+        break;
+      }
+
+      // optional .caffe.NetState train_state = 26;
+      case 26: {
+        if (tag == 210) {
+         parse_train_state:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+               input, mutable_train_state()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(218)) goto parse_test_state;
+        break;
+      }
+
+      // repeated .caffe.NetState test_state = 27;
+      case 27: {
+        if (tag == 218) {
+         parse_test_state:
+          DO_(input->IncrementRecursionDepth());
+         parse_loop_test_state:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth(
+                input, add_test_state()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(218)) goto parse_loop_test_state;
+        input->UnsafeDecrementRecursionDepth();
+        if (input->ExpectTag(224)) goto parse_snapshot_after_train;
+        break;
+      }
+
+      // optional bool snapshot_after_train = 28 [default = true];
+      case 28: {
+        if (tag == 224) {
+         parse_snapshot_after_train:
+          set_has_snapshot_after_train();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>(
+                 input, &snapshot_after_train_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(234)) goto parse_regularization_type;
+        break;
+      }
+
+      // optional string regularization_type = 29 [default = "L2"];
+      case 29: {
+        if (tag == 234) {
+         parse_regularization_type:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+                input, this->mutable_regularization_type()));
+          ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+            this->regularization_type().data(), this->regularization_type().length(),
+            ::google::protobuf::internal::WireFormat::PARSE,
+            "caffe.SolverParameter.regularization_type");
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(240)) goto parse_solver_type;
+        break;
+      }
+
+      // optional .caffe.SolverParameter.SolverType solver_type = 30 [default = SGD];
+      case 30: {
+        if (tag == 240) {
+         parse_solver_type:
+          int value;
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>(
+                 input, &value)));
+          if (::caffe::SolverParameter_SolverType_IsValid(value)) {
+            set_solver_type(static_cast< ::caffe::SolverParameter_SolverType >(value));
+          } else {
+            mutable_unknown_fields()->AddVarint(30, value);
+          }
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(253)) goto parse_delta;
+        break;
+      }
+
+      // optional float delta = 31 [default = 1e-08];
+      case 31: {
+        if (tag == 253) {
+         parse_delta:
+          set_has_delta();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
+                 input, &delta_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(256)) goto parse_test_initialization;
+        break;
+      }
+
+      // optional bool test_initialization = 32 [default = true];
+      case 32: {
+        if (tag == 256) {
+         parse_test_initialization:
+          set_has_test_initialization();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>(
+                 input, &test_initialization_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(264)) goto parse_average_loss;
+        break;
+      }
+
+      // optional int32 average_loss = 33 [default = 1];
+      case 33: {
+        if (tag == 264) {
+         parse_average_loss:
+          set_has_average_loss();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
+                 input, &average_loss_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(272)) goto parse_stepvalue;
+        break;
+      }
+
+      // repeated int32 stepvalue = 34;
+      case 34: {
+        if (tag == 272) {
+         parse_stepvalue:
+          DO_((::google::protobuf::internal::WireFormatLite::ReadRepeatedPrimitive<
+                   ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
+                 2, 272, input, this->mutable_stepvalue())));
+        } else if (tag == 274) {
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPackedPrimitiveNoInline<
+                   ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
+                 input, this->mutable_stepvalue())));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(272)) goto parse_stepvalue;
+        if (input->ExpectTag(285)) goto parse_clip_gradients;
+        break;
+      }
+
+      // optional float clip_gradients = 35 [default = -1];
+      case 35: {
+        if (tag == 285) {
+         parse_clip_gradients:
+          set_has_clip_gradients();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
+                 input, &clip_gradients_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(288)) goto parse_iter_size;
+        break;
+      }
+
+      // optional int32 iter_size = 36 [default = 1];
+      case 36: {
+        if (tag == 288) {
+         parse_iter_size:
+          set_has_iter_size();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
+                 input, &iter_size_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectAtEnd()) goto success;
+        break;
+      }
+
+      default: {
+      handle_unusual:
+        if (tag == 0 ||
+            ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+          goto success;
+        }
+        DO_(::google::protobuf::internal::WireFormat::SkipField(
+              input, tag, mutable_unknown_fields()));
+        break;
+      }
+    }
+  }
+success:
+  // @@protoc_insertion_point(parse_success:caffe.SolverParameter)
+  return true;
+failure:
+  // @@protoc_insertion_point(parse_failure:caffe.SolverParameter)
+  return false;
+#undef DO_
+}
+
+void SolverParameter::SerializeWithCachedSizes(
+    ::google::protobuf::io::CodedOutputStream* output) const {
+  // @@protoc_insertion_point(serialize_start:caffe.SolverParameter)
+  // optional string train_net = 1;
+  if (has_train_net()) {
+    ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->train_net().data(), this->train_net().length(),
+      ::google::protobuf::internal::WireFormat::SERIALIZE,
+      "caffe.SolverParameter.train_net");
+    ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
+      1, this->train_net(), output);
+  }
+
+  // repeated string test_net = 2;
+  for (int i = 0; i < this->test_net_size(); i++) {
+    ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->test_net(i).data(), this->test_net(i).length(),
+      ::google::protobuf::internal::WireFormat::SERIALIZE,
+      "caffe.SolverParameter.test_net");
+    ::google::protobuf::internal::WireFormatLite::WriteString(
+      2, this->test_net(i), output);
+  }
+
+  // repeated int32 test_iter = 3;
+  for (int i = 0; i < this->test_iter_size(); i++) {
+    ::google::protobuf::internal::WireFormatLite::WriteInt32(
+      3, this->test_iter(i), output);
+  }
+
+  // optional int32 test_interval = 4 [default = 0];
+  if (has_test_interval()) {
+    ::google::protobuf::internal::WireFormatLite::WriteInt32(4, this->test_interval(), output);
+  }
+
+  // optional float base_lr = 5;
+  if (has_base_lr()) {
+    ::google::protobuf::internal::WireFormatLite::WriteFloat(5, this->base_lr(), output);
+  }
+
+  // optional int32 display = 6;
+  if (has_display()) {
+    ::google::protobuf::internal::WireFormatLite::WriteInt32(6, this->display(), output);
+  }
+
+  // optional int32 max_iter = 7;
+  if (has_max_iter()) {
+    ::google::protobuf::internal::WireFormatLite::WriteInt32(7, this->max_iter(), output);
+  }
+
+  // optional string lr_policy = 8;
+  if (has_lr_policy()) {
+    ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->lr_policy().data(), this->lr_policy().length(),
+      ::google::protobuf::internal::WireFormat::SERIALIZE,
+      "caffe.SolverParameter.lr_policy");
+    ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
+      8, this->lr_policy(), output);
+  }
+
+  // optional float gamma = 9;
+  if (has_gamma()) {
+    ::google::protobuf::internal::WireFormatLite::WriteFloat(9, this->gamma(), output);
+  }
+
+  // optional float power = 10;
+  if (has_power()) {
+    ::google::protobuf::internal::WireFormatLite::WriteFloat(10, this->power(), output);
+  }
+
+  // optional float momentum = 11;
+  if (has_momentum()) {
+    ::google::protobuf::internal::WireFormatLite::WriteFloat(11, this->momentum(), output);
+  }
+
+  // optional float weight_decay = 12;
+  if (has_weight_decay()) {
+    ::google::protobuf::internal::WireFormatLite::WriteFloat(12, this->weight_decay(), output);
+  }
+
+  // optional int32 stepsize = 13;
+  if (has_stepsize()) {
+    ::google::protobuf::internal::WireFormatLite::WriteInt32(13, this->stepsize(), output);
+  }
+
+  // optional int32 snapshot = 14 [default = 0];
+  if (has_snapshot()) {
+    ::google::protobuf::internal::WireFormatLite::WriteInt32(14, this->snapshot(), output);
+  }
+
+  // optional string snapshot_prefix = 15;
+  if (has_snapshot_prefix()) {
+    ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->snapshot_prefix().data(), this->snapshot_prefix().length(),
+      ::google::protobuf::internal::WireFormat::SERIALIZE,
+      "caffe.SolverParameter.snapshot_prefix");
+    ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
+      15, this->snapshot_prefix(), output);
+  }
+
+  // optional bool snapshot_diff = 16 [default = false];
+  if (has_snapshot_diff()) {
+    ::google::protobuf::internal::WireFormatLite::WriteBool(16, this->snapshot_diff(), output);
+  }
+
+  // optional .caffe.SolverParameter.SolverMode solver_mode = 17 [default = GPU];
+  if (has_solver_mode()) {
+    ::google::protobuf::internal::WireFormatLite::WriteEnum(
+      17, this->solver_mode(), output);
+  }
+
+  // optional int32 device_id = 18 [default = 0];
+  if (has_device_id()) {
+    ::google::protobuf::internal::WireFormatLite::WriteInt32(18, this->device_id(), output);
+  }
+
+  // optional bool test_compute_loss = 19 [default = false];
+  if (has_test_compute_loss()) {
+    ::google::protobuf::internal::WireFormatLite::WriteBool(19, this->test_compute_loss(), output);
+  }
+
+  // optional int64 random_seed = 20 [default = -1];
+  if (has_random_seed()) {
+    ::google::protobuf::internal::WireFormatLite::WriteInt64(20, this->random_seed(), output);
+  }
+
+  // optional .caffe.NetParameter train_net_param = 21;
+  if (has_train_net_param()) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      21, *this->train_net_param_, output);
+  }
+
+  // repeated .caffe.NetParameter test_net_param = 22;
+  for (unsigned int i = 0, n = this->test_net_param_size(); i < n; i++) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      22, this->test_net_param(i), output);
+  }
+
+  // optional bool debug_info = 23 [default = false];
+  if (has_debug_info()) {
+    ::google::protobuf::internal::WireFormatLite::WriteBool(23, this->debug_info(), output);
+  }
+
+  // optional string net = 24;
+  if (has_net()) {
+    ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->net().data(), this->net().length(),
+      ::google::protobuf::internal::WireFormat::SERIALIZE,
+      "caffe.SolverParameter.net");
+    ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
+      24, this->net(), output);
+  }
+
+  // optional .caffe.NetParameter net_param = 25;
+  if (has_net_param()) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      25, *this->net_param_, output);
+  }
+
+  // optional .caffe.NetState train_state = 26;
+  if (has_train_state()) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      26, *this->train_state_, output);
+  }
+
+  // repeated .caffe.NetState test_state = 27;
+  for (unsigned int i = 0, n = this->test_state_size(); i < n; i++) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      27, this->test_state(i), output);
+  }
+
+  // optional bool snapshot_after_train = 28 [default = true];
+  if (has_snapshot_after_train()) {
+    ::google::protobuf::internal::WireFormatLite::WriteBool(28, this->snapshot_after_train(), output);
+  }
+
+  // optional string regularization_type = 29 [default = "L2"];
+  if (has_regularization_type()) {
+    ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->regularization_type().data(), this->regularization_type().length(),
+      ::google::protobuf::internal::WireFormat::SERIALIZE,
+      "caffe.SolverParameter.regularization_type");
+    ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
+      29, this->regularization_type(), output);
+  }
+
+  // optional .caffe.SolverParameter.SolverType solver_type = 30 [default = SGD];
+  if (has_solver_type()) {
+    ::google::protobuf::internal::WireFormatLite::WriteEnum(
+      30, this->solver_type(), output);
+  }
+
+  // optional float delta = 31 [default = 1e-08];
+  if (has_delta()) {
+    ::google::protobuf::internal::WireFormatLite::WriteFloat(31, this->delta(), output);
+  }
+
+  // optional bool test_initialization = 32 [default = true];
+  if (has_test_initialization()) {
+    ::google::protobuf::internal::WireFormatLite::WriteBool(32, this->test_initialization(), output);
+  }
+
+  // optional int32 average_loss = 33 [default = 1];
+  if (has_average_loss()) {
+    ::google::protobuf::internal::WireFormatLite::WriteInt32(33, this->average_loss(), output);
+  }
+
+  // repeated int32 stepvalue = 34;
+  for (int i = 0; i < this->stepvalue_size(); i++) {
+    ::google::protobuf::internal::WireFormatLite::WriteInt32(
+      34, this->stepvalue(i), output);
+  }
+
+  // optional float clip_gradients = 35 [default = -1];
+  if (has_clip_gradients()) {
+    ::google::protobuf::internal::WireFormatLite::WriteFloat(35, this->clip_gradients(), output);
+  }
+
+  // optional int32 iter_size = 36 [default = 1];
+  if (has_iter_size()) {
+    ::google::protobuf::internal::WireFormatLite::WriteInt32(36, this->iter_size(), output);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
+        unknown_fields(), output);
+  }
+  // @@protoc_insertion_point(serialize_end:caffe.SolverParameter)
+}
+
+::google::protobuf::uint8* SolverParameter::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
+  (void)deterministic; // Unused
+  // @@protoc_insertion_point(serialize_to_array_start:caffe.SolverParameter)
+  // optional string train_net = 1;
+  if (has_train_net()) {
+    ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->train_net().data(), this->train_net().length(),
+      ::google::protobuf::internal::WireFormat::SERIALIZE,
+      "caffe.SolverParameter.train_net");
+    target =
+      ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
+        1, this->train_net(), target);
+  }
+
+  // repeated string test_net = 2;
+  for (int i = 0; i < this->test_net_size(); i++) {
+    ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->test_net(i).data(), this->test_net(i).length(),
+      ::google::protobuf::internal::WireFormat::SERIALIZE,
+      "caffe.SolverParameter.test_net");
+    target = ::google::protobuf::internal::WireFormatLite::
+      WriteStringToArray(2, this->test_net(i), target);
+  }
+
+  // repeated int32 test_iter = 3;
+  for (int i = 0; i < this->test_iter_size(); i++) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      WriteInt32ToArray(3, this->test_iter(i), target);
+  }
+
+  // optional int32 test_interval = 4 [default = 0];
+  if (has_test_interval()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteInt32ToArray(4, this->test_interval(), target);
+  }
+
+  // optional float base_lr = 5;
+  if (has_base_lr()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteFloatToArray(5, this->base_lr(), target);
+  }
+
+  // optional int32 display = 6;
+  if (has_display()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteInt32ToArray(6, this->display(), target);
+  }
+
+  // optional int32 max_iter = 7;
+  if (has_max_iter()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteInt32ToArray(7, this->max_iter(), target);
+  }
+
+  // optional string lr_policy = 8;
+  if (has_lr_policy()) {
+    ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->lr_policy().data(), this->lr_policy().length(),
+      ::google::protobuf::internal::WireFormat::SERIALIZE,
+      "caffe.SolverParameter.lr_policy");
+    target =
+      ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
+        8, this->lr_policy(), target);
+  }
+
+  // optional float gamma = 9;
+  if (has_gamma()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteFloatToArray(9, this->gamma(), target);
+  }
+
+  // optional float power = 10;
+  if (has_power()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteFloatToArray(10, this->power(), target);
+  }
+
+  // optional float momentum = 11;
+  if (has_momentum()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteFloatToArray(11, this->momentum(), target);
+  }
+
+  // optional float weight_decay = 12;
+  if (has_weight_decay()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteFloatToArray(12, this->weight_decay(), target);
+  }
+
+  // optional int32 stepsize = 13;
+  if (has_stepsize()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteInt32ToArray(13, this->stepsize(), target);
+  }
+
+  // optional int32 snapshot = 14 [default = 0];
+  if (has_snapshot()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteInt32ToArray(14, this->snapshot(), target);
+  }
+
+  // optional string snapshot_prefix = 15;
+  if (has_snapshot_prefix()) {
+    ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->snapshot_prefix().data(), this->snapshot_prefix().length(),
+      ::google::protobuf::internal::WireFormat::SERIALIZE,
+      "caffe.SolverParameter.snapshot_prefix");
+    target =
+      ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
+        15, this->snapshot_prefix(), target);
+  }
+
+  // optional bool snapshot_diff = 16 [default = false];
+  if (has_snapshot_diff()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(16, this->snapshot_diff(), target);
+  }
+
+  // optional .caffe.SolverParameter.SolverMode solver_mode = 17 [default = GPU];
+  if (has_solver_mode()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteEnumToArray(
+      17, this->solver_mode(), target);
+  }
+
+  // optional int32 device_id = 18 [default = 0];
+  if (has_device_id()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteInt32ToArray(18, this->device_id(), target);
+  }
+
+  // optional bool test_compute_loss = 19 [default = false];
+  if (has_test_compute_loss()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(19, this->test_compute_loss(), target);
+  }
+
+  // optional int64 random_seed = 20 [default = -1];
+  if (has_random_seed()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteInt64ToArray(20, this->random_seed(), target);
+  }
+
+  // optional .caffe.NetParameter train_net_param = 21;
+  if (has_train_net_param()) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        21, *this->train_net_param_, false, target);
+  }
+
+  // repeated .caffe.NetParameter test_net_param = 22;
+  for (unsigned int i = 0, n = this->test_net_param_size(); i < n; i++) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        22, this->test_net_param(i), false, target);
+  }
+
+  // optional bool debug_info = 23 [default = false];
+  if (has_debug_info()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(23, this->debug_info(), target);
+  }
+
+  // optional string net = 24;
+  if (has_net()) {
+    ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->net().data(), this->net().length(),
+      ::google::protobuf::internal::WireFormat::SERIALIZE,
+      "caffe.SolverParameter.net");
+    target =
+      ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
+        24, this->net(), target);
+  }
+
+  // optional .caffe.NetParameter net_param = 25;
+  if (has_net_param()) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        25, *this->net_param_, false, target);
+  }
+
+  // optional .caffe.NetState train_state = 26;
+  if (has_train_state()) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        26, *this->train_state_, false, target);
+  }
+
+  // repeated .caffe.NetState test_state = 27;
+  for (unsigned int i = 0, n = this->test_state_size(); i < n; i++) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        27, this->test_state(i), false, target);
+  }
+
+  // optional bool snapshot_after_train = 28 [default = true];
+  if (has_snapshot_after_train()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(28, this->snapshot_after_train(), target);
+  }
+
+  // optional string regularization_type = 29 [default = "L2"];
+  if (has_regularization_type()) {
+    ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->regularization_type().data(), this->regularization_type().length(),
+      ::google::protobuf::internal::WireFormat::SERIALIZE,
+      "caffe.SolverParameter.regularization_type");
+    target =
+      ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
+        29, this->regularization_type(), target);
+  }
+
+  // optional .caffe.SolverParameter.SolverType solver_type = 30 [default = SGD];
+  if (has_solver_type()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteEnumToArray(
+      30, this->solver_type(), target);
+  }
+
+  // optional float delta = 31 [default = 1e-08];
+  if (has_delta()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteFloatToArray(31, this->delta(), target);
+  }
+
+  // optional bool test_initialization = 32 [default = true];
+  if (has_test_initialization()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(32, this->test_initialization(), target);
+  }
+
+  // optional int32 average_loss = 33 [default = 1];
+  if (has_average_loss()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteInt32ToArray(33, this->average_loss(), target);
+  }
+
+  // repeated int32 stepvalue = 34;
+  for (int i = 0; i < this->stepvalue_size(); i++) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      WriteInt32ToArray(34, this->stepvalue(i), target);
+  }
+
+  // optional float clip_gradients = 35 [default = -1];
+  if (has_clip_gradients()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteFloatToArray(35, this->clip_gradients(), target);
+  }
+
+  // optional int32 iter_size = 36 [default = 1];
+  if (has_iter_size()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteInt32ToArray(36, this->iter_size(), target);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
+        unknown_fields(), target);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:caffe.SolverParameter)
+  return target;
+}
+
+size_t SolverParameter::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:caffe.SolverParameter)
+  size_t total_size = 0;
+
+  if (_has_bits_[0 / 32] & 87u) {
+    // optional string net = 24;
+    if (has_net()) {
+      total_size += 2 +
+        ::google::protobuf::internal::WireFormatLite::StringSize(
+          this->net());
+    }
+
+    // optional .caffe.NetParameter net_param = 25;
+    if (has_net_param()) {
+      total_size += 2 +
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          *this->net_param_);
+    }
+
+    // optional string train_net = 1;
+    if (has_train_net()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::StringSize(
+          this->train_net());
+    }
+
+    // optional .caffe.NetParameter train_net_param = 21;
+    if (has_train_net_param()) {
+      total_size += 2 +
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          *this->train_net_param_);
+    }
+
+    // optional .caffe.NetState train_state = 26;
+    if (has_train_state()) {
+      total_size += 2 +
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          *this->train_state_);
+    }
+
+  }
+  if (_has_bits_[9 / 32] & 65024u) {
+    // optional int32 test_interval = 4 [default = 0];
+    if (has_test_interval()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::Int32Size(
+          this->test_interval());
+    }
+
+    // optional bool test_compute_loss = 19 [default = false];
+    if (has_test_compute_loss()) {
+      total_size += 2 + 1;
+    }
+
+    // optional bool test_initialization = 32 [default = true];
+    if (has_test_initialization()) {
+      total_size += 2 + 1;
+    }
+
+    // optional float base_lr = 5;
+    if (has_base_lr()) {
+      total_size += 1 + 4;
+    }
+
+    // optional int32 display = 6;
+    if (has_display()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::Int32Size(
+          this->display());
+    }
+
+    // optional int32 average_loss = 33 [default = 1];
+    if (has_average_loss()) {
+      total_size += 2 +
+        ::google::protobuf::internal::WireFormatLite::Int32Size(
+          this->average_loss());
+    }
+
+    // optional int32 max_iter = 7;
+    if (has_max_iter()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::Int32Size(
+          this->max_iter());
+    }
+
+  }
+  if (_has_bits_[16 / 32] & 16711680u) {
+    // optional int32 iter_size = 36 [default = 1];
+    if (has_iter_size()) {
+      total_size += 2 +
+        ::google::protobuf::internal::WireFormatLite::Int32Size(
+          this->iter_size());
+    }
+
+    // optional string lr_policy = 8;
+    if (has_lr_policy()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::StringSize(
+          this->lr_policy());
+    }
+
+    // optional float gamma = 9;
+    if (has_gamma()) {
+      total_size += 1 + 4;
+    }
+
+    // optional float power = 10;
+    if (has_power()) {
+      total_size += 1 + 4;
+    }
+
+    // optional float momentum = 11;
+    if (has_momentum()) {
+      total_size += 1 + 4;
+    }
+
+    // optional float weight_decay = 12;
+    if (has_weight_decay()) {
+      total_size += 1 + 4;
+    }
+
+    // optional string regularization_type = 29 [default = "L2"];
+    if (has_regularization_type()) {
+      total_size += 2 +
+        ::google::protobuf::internal::WireFormatLite::StringSize(
+          this->regularization_type());
+    }
+
+    // optional int32 stepsize = 13;
+    if (has_stepsize()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::Int32Size(
+          this->stepsize());
+    }
+
+  }
+  if (_has_bits_[25 / 32] & 4261412864u) {
+    // optional float clip_gradients = 35 [default = -1];
+    if (has_clip_gradients()) {
+      total_size += 2 + 4;
+    }
+
+    // optional int32 snapshot = 14 [default = 0];
+    if (has_snapshot()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::Int32Size(
+          this->snapshot());
+    }
+
+    // optional string snapshot_prefix = 15;
+    if (has_snapshot_prefix()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::StringSize(
+          this->snapshot_prefix());
+    }
+
+    // optional bool snapshot_diff = 16 [default = false];
+    if (has_snapshot_diff()) {
+      total_size += 2 + 1;
+    }
+
+    // optional .caffe.SolverParameter.SolverMode solver_mode = 17 [default = GPU];
+    if (has_solver_mode()) {
+      total_size += 2 +
+        ::google::protobuf::internal::WireFormatLite::EnumSize(this->solver_mode());
+    }
+
+    // optional int32 device_id = 18 [default = 0];
+    if (has_device_id()) {
+      total_size += 2 +
+        ::google::protobuf::internal::WireFormatLite::Int32Size(
+          this->device_id());
+    }
+
+    // optional int64 random_seed = 20 [default = -1];
+    if (has_random_seed()) {
+      total_size += 2 +
+        ::google::protobuf::internal::WireFormatLite::Int64Size(
+          this->random_seed());
+    }
+
+  }
+  if (_has_bits_[32 / 32] & 15u) {
+    // optional .caffe.SolverParameter.SolverType solver_type = 30 [default = SGD];
+    if (has_solver_type()) {
+      total_size += 2 +
+        ::google::protobuf::internal::WireFormatLite::EnumSize(this->solver_type());
+    }
+
+    // optional float delta = 31 [default = 1e-08];
+    if (has_delta()) {
+      total_size += 2 + 4;
+    }
+
+    // optional bool debug_info = 23 [default = false];
+    if (has_debug_info()) {
+      total_size += 2 + 1;
+    }
+
+    // optional bool snapshot_after_train = 28 [default = true];
+    if (has_snapshot_after_train()) {
+      total_size += 2 + 1;
+    }
+
+  }
+  // repeated string test_net = 2;
+  total_size += 1 *
+      ::google::protobuf::internal::FromIntSize(this->test_net_size());
+  for (int i = 0; i < this->test_net_size(); i++) {
+    total_size += ::google::protobuf::internal::WireFormatLite::StringSize(
+      this->test_net(i));
+  }
+
+  // repeated .caffe.NetParameter test_net_param = 22;
+  {
+    unsigned int count = this->test_net_param_size();
+    total_size += 2UL * count;
+    for (unsigned int i = 0; i < count; i++) {
+      total_size +=
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          this->test_net_param(i));
+    }
+  }
+
+  // repeated .caffe.NetState test_state = 27;
+  {
+    unsigned int count = this->test_state_size();
+    total_size += 2UL * count;
+    for (unsigned int i = 0; i < count; i++) {
+      total_size +=
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          this->test_state(i));
+    }
+  }
+
+  // repeated int32 test_iter = 3;
+  {
+    size_t data_size = 0;
+    unsigned int count = this->test_iter_size();
+    for (unsigned int i = 0; i < count; i++) {
+      data_size += ::google::protobuf::internal::WireFormatLite::
+        Int32Size(this->test_iter(i));
+    }
+    total_size += 1 *
+                  ::google::protobuf::internal::FromIntSize(this->test_iter_size());
+    total_size += data_size;
+  }
+
+  // repeated int32 stepvalue = 34;
+  {
+    size_t data_size = 0;
+    unsigned int count = this->stepvalue_size();
+    for (unsigned int i = 0; i < count; i++) {
+      data_size += ::google::protobuf::internal::WireFormatLite::
+        Int32Size(this->stepvalue(i));
+    }
+    total_size += 2 *
+                  ::google::protobuf::internal::FromIntSize(this->stepvalue_size());
+    total_size += data_size;
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    total_size +=
+      ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
+        unknown_fields());
+  }
+  int cached_size = ::google::protobuf::internal::ToCachedSize(total_size);
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = cached_size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+  return total_size;
+}
+
+void SolverParameter::MergeFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_merge_from_start:caffe.SolverParameter)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const SolverParameter* source =
+      ::google::protobuf::internal::DynamicCastToGenerated<const SolverParameter>(
+          &from);
+  if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:caffe.SolverParameter)
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:caffe.SolverParameter)
+    UnsafeMergeFrom(*source);
+  }
+}
+
+void SolverParameter::MergeFrom(const SolverParameter& from) {
+// @@protoc_insertion_point(class_specific_merge_from_start:caffe.SolverParameter)
+  if (GOOGLE_PREDICT_TRUE(&from != this)) {
+    UnsafeMergeFrom(from);
+  } else {
+    MergeFromFail(__LINE__);
+  }
+}
+
+void SolverParameter::UnsafeMergeFrom(const SolverParameter& from) {
+  GOOGLE_DCHECK(&from != this);
+  test_net_.UnsafeMergeFrom(from.test_net_);
+  test_net_param_.MergeFrom(from.test_net_param_);
+  test_state_.MergeFrom(from.test_state_);
+  test_iter_.UnsafeMergeFrom(from.test_iter_);
+  stepvalue_.UnsafeMergeFrom(from.stepvalue_);
+  if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+    if (from.has_net()) {
+      set_has_net();
+      net_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.net_);
+    }
+    if (from.has_net_param()) {
+      mutable_net_param()->::caffe::NetParameter::MergeFrom(from.net_param());
+    }
+    if (from.has_train_net()) {
+      set_has_train_net();
+      train_net_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.train_net_);
+    }
+    if (from.has_train_net_param()) {
+      mutable_train_net_param()->::caffe::NetParameter::MergeFrom(from.train_net_param());
+    }
+    if (from.has_train_state()) {
+      mutable_train_state()->::caffe::NetState::MergeFrom(from.train_state());
+    }
+  }
+  if (from._has_bits_[9 / 32] & (0xffu << (9 % 32))) {
+    if (from.has_test_interval()) {
+      set_test_interval(from.test_interval());
+    }
+    if (from.has_test_compute_loss()) {
+      set_test_compute_loss(from.test_compute_loss());
+    }
+    if (from.has_test_initialization()) {
+      set_test_initialization(from.test_initialization());
+    }
+    if (from.has_base_lr()) {
+      set_base_lr(from.base_lr());
+    }
+    if (from.has_display()) {
+      set_display(from.display());
+    }
+    if (from.has_average_loss()) {
+      set_average_loss(from.average_loss());
+    }
+    if (from.has_max_iter()) {
+      set_max_iter(from.max_iter());
+    }
+  }
+  if (from._has_bits_[16 / 32] & (0xffu << (16 % 32))) {
+    if (from.has_iter_size()) {
+      set_iter_size(from.iter_size());
+    }
+    if (from.has_lr_policy()) {
+      set_has_lr_policy();
+      lr_policy_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.lr_policy_);
+    }
+    if (from.has_gamma()) {
+      set_gamma(from.gamma());
+    }
+    if (from.has_power()) {
+      set_power(from.power());
+    }
+    if (from.has_momentum()) {
+      set_momentum(from.momentum());
+    }
+    if (from.has_weight_decay()) {
+      set_weight_decay(from.weight_decay());
+    }
+    if (from.has_regularization_type()) {
+      set_has_regularization_type();
+      regularization_type_.AssignWithDefault(_default_regularization_type_, from.regularization_type_);
+    }
+    if (from.has_stepsize()) {
+      set_stepsize(from.stepsize());
+    }
+  }
+  if (from._has_bits_[25 / 32] & (0xffu << (25 % 32))) {
+    if (from.has_clip_gradients()) {
+      set_clip_gradients(from.clip_gradients());
+    }
+    if (from.has_snapshot()) {
+      set_snapshot(from.snapshot());
+    }
+    if (from.has_snapshot_prefix()) {
+      set_has_snapshot_prefix();
+      snapshot_prefix_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.snapshot_prefix_);
+    }
+    if (from.has_snapshot_diff()) {
+      set_snapshot_diff(from.snapshot_diff());
+    }
+    if (from.has_solver_mode()) {
+      set_solver_mode(from.solver_mode());
+    }
+    if (from.has_device_id()) {
+      set_device_id(from.device_id());
+    }
+    if (from.has_random_seed()) {
+      set_random_seed(from.random_seed());
+    }
+  }
+  if (from._has_bits_[32 / 32] & (0xffu << (32 % 32))) {
+    if (from.has_solver_type()) {
+      set_solver_type(from.solver_type());
+    }
+    if (from.has_delta()) {
+      set_delta(from.delta());
+    }
+    if (from.has_debug_info()) {
+      set_debug_info(from.debug_info());
+    }
+    if (from.has_snapshot_after_train()) {
+      set_snapshot_after_train(from.snapshot_after_train());
+    }
+  }
+  if (from._internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::UnknownFieldSet::MergeToInternalMetdata(
+      from.unknown_fields(), &_internal_metadata_);
+  }
+}
+
+void SolverParameter::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:caffe.SolverParameter)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void SolverParameter::CopyFrom(const SolverParameter& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:caffe.SolverParameter)
+  if (&from == this) return;
+  Clear();
+  UnsafeMergeFrom(from);
+}
+
+bool SolverParameter::IsInitialized() const {
+
+  return true;
+}
+
+void SolverParameter::Swap(SolverParameter* other) {
+  if (other == this) return;
+  InternalSwap(other);
+}
+void SolverParameter::InternalSwap(SolverParameter* other) {
+  net_.Swap(&other->net_);
+  std::swap(net_param_, other->net_param_);
+  train_net_.Swap(&other->train_net_);
+  test_net_.UnsafeArenaSwap(&other->test_net_);
+  std::swap(train_net_param_, other->train_net_param_);
+  test_net_param_.UnsafeArenaSwap(&other->test_net_param_);
+  std::swap(train_state_, other->train_state_);
+  test_state_.UnsafeArenaSwap(&other->test_state_);
+  test_iter_.UnsafeArenaSwap(&other->test_iter_);
+  std::swap(test_interval_, other->test_interval_);
+  std::swap(test_compute_loss_, other->test_compute_loss_);
+  std::swap(test_initialization_, other->test_initialization_);
+  std::swap(base_lr_, other->base_lr_);
+  std::swap(display_, other->display_);
+  std::swap(average_loss_, other->average_loss_);
+  std::swap(max_iter_, other->max_iter_);
+  std::swap(iter_size_, other->iter_size_);
+  lr_policy_.Swap(&other->lr_policy_);
+  std::swap(gamma_, other->gamma_);
+  std::swap(power_, other->power_);
+  std::swap(momentum_, other->momentum_);
+  std::swap(weight_decay_, other->weight_decay_);
+  regularization_type_.Swap(&other->regularization_type_);
+  std::swap(stepsize_, other->stepsize_);
+  stepvalue_.UnsafeArenaSwap(&other->stepvalue_);
+  std::swap(clip_gradients_, other->clip_gradients_);
+  std::swap(snapshot_, other->snapshot_);
+  snapshot_prefix_.Swap(&other->snapshot_prefix_);
+  std::swap(snapshot_diff_, other->snapshot_diff_);
+  std::swap(solver_mode_, other->solver_mode_);
+  std::swap(device_id_, other->device_id_);
+  std::swap(random_seed_, other->random_seed_);
+  std::swap(solver_type_, other->solver_type_);
+  std::swap(delta_, other->delta_);
+  std::swap(debug_info_, other->debug_info_);
+  std::swap(snapshot_after_train_, other->snapshot_after_train_);
+  std::swap(_has_bits_[0], other->_has_bits_[0]);
+  std::swap(_has_bits_[1], other->_has_bits_[1]);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
+}
+
+::google::protobuf::Metadata SolverParameter::GetMetadata() const {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::Metadata metadata;
+  metadata.descriptor = SolverParameter_descriptor_;
+  metadata.reflection = SolverParameter_reflection_;
+  return metadata;
+}
+
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// SolverParameter
+
+// optional string net = 24;
+bool SolverParameter::has_net() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+void SolverParameter::set_has_net() {
+  _has_bits_[0] |= 0x00000001u;
+}
+void SolverParameter::clear_has_net() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+void SolverParameter::clear_net() {
+  net_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  clear_has_net();
+}
+const ::std::string& SolverParameter::net() const {
+  // @@protoc_insertion_point(field_get:caffe.SolverParameter.net)
+  return net_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+void SolverParameter::set_net(const ::std::string& value) {
+  set_has_net();
+  net_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:caffe.SolverParameter.net)
+}
+void SolverParameter::set_net(const char* value) {
+  set_has_net();
+  net_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:caffe.SolverParameter.net)
+}
+void SolverParameter::set_net(const char* value, size_t size) {
+  set_has_net();
+  net_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:caffe.SolverParameter.net)
+}
+::std::string* SolverParameter::mutable_net() {
+  set_has_net();
+  // @@protoc_insertion_point(field_mutable:caffe.SolverParameter.net)
+  return net_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+::std::string* SolverParameter::release_net() {
+  // @@protoc_insertion_point(field_release:caffe.SolverParameter.net)
+  clear_has_net();
+  return net_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+void SolverParameter::set_allocated_net(::std::string* net) {
+  if (net != NULL) {
+    set_has_net();
+  } else {
+    clear_has_net();
+  }
+  net_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), net);
+  // @@protoc_insertion_point(field_set_allocated:caffe.SolverParameter.net)
+}
+
+// optional .caffe.NetParameter net_param = 25;
+bool SolverParameter::has_net_param() const {
+  return (_has_bits_[0] & 0x00000002u) != 0;
+}
+void SolverParameter::set_has_net_param() {
+  _has_bits_[0] |= 0x00000002u;
+}
+void SolverParameter::clear_has_net_param() {
+  _has_bits_[0] &= ~0x00000002u;
+}
+void SolverParameter::clear_net_param() {
+  if (net_param_ != NULL) net_param_->::caffe::NetParameter::Clear();
+  clear_has_net_param();
+}
+const ::caffe::NetParameter& SolverParameter::net_param() const {
+  // @@protoc_insertion_point(field_get:caffe.SolverParameter.net_param)
+  return net_param_ != NULL ? *net_param_
+                         : *::caffe::NetParameter::internal_default_instance();
+}
+::caffe::NetParameter* SolverParameter::mutable_net_param() {
+  set_has_net_param();
+  if (net_param_ == NULL) {
+    net_param_ = new ::caffe::NetParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.SolverParameter.net_param)
+  return net_param_;
+}
+::caffe::NetParameter* SolverParameter::release_net_param() {
+  // @@protoc_insertion_point(field_release:caffe.SolverParameter.net_param)
+  clear_has_net_param();
+  ::caffe::NetParameter* temp = net_param_;
+  net_param_ = NULL;
+  return temp;
+}
+void SolverParameter::set_allocated_net_param(::caffe::NetParameter* net_param) {
+  delete net_param_;
+  net_param_ = net_param;
+  if (net_param) {
+    set_has_net_param();
+  } else {
+    clear_has_net_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.SolverParameter.net_param)
+}
+
+// optional string train_net = 1;
+bool SolverParameter::has_train_net() const {
+  return (_has_bits_[0] & 0x00000004u) != 0;
+}
+void SolverParameter::set_has_train_net() {
+  _has_bits_[0] |= 0x00000004u;
+}
+void SolverParameter::clear_has_train_net() {
+  _has_bits_[0] &= ~0x00000004u;
+}
+void SolverParameter::clear_train_net() {
+  train_net_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  clear_has_train_net();
+}
+const ::std::string& SolverParameter::train_net() const {
+  // @@protoc_insertion_point(field_get:caffe.SolverParameter.train_net)
+  return train_net_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+void SolverParameter::set_train_net(const ::std::string& value) {
+  set_has_train_net();
+  train_net_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:caffe.SolverParameter.train_net)
+}
+void SolverParameter::set_train_net(const char* value) {
+  set_has_train_net();
+  train_net_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:caffe.SolverParameter.train_net)
+}
+void SolverParameter::set_train_net(const char* value, size_t size) {
+  set_has_train_net();
+  train_net_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:caffe.SolverParameter.train_net)
+}
+::std::string* SolverParameter::mutable_train_net() {
+  set_has_train_net();
+  // @@protoc_insertion_point(field_mutable:caffe.SolverParameter.train_net)
+  return train_net_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+::std::string* SolverParameter::release_train_net() {
+  // @@protoc_insertion_point(field_release:caffe.SolverParameter.train_net)
+  clear_has_train_net();
+  return train_net_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+void SolverParameter::set_allocated_train_net(::std::string* train_net) {
+  if (train_net != NULL) {
+    set_has_train_net();
+  } else {
+    clear_has_train_net();
+  }
+  train_net_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), train_net);
+  // @@protoc_insertion_point(field_set_allocated:caffe.SolverParameter.train_net)
+}
+
+// repeated string test_net = 2;
+int SolverParameter::test_net_size() const {
+  return test_net_.size();
+}
+void SolverParameter::clear_test_net() {
+  test_net_.Clear();
+}
+const ::std::string& SolverParameter::test_net(int index) const {
+  // @@protoc_insertion_point(field_get:caffe.SolverParameter.test_net)
+  return test_net_.Get(index);
+}
+::std::string* SolverParameter::mutable_test_net(int index) {
+  // @@protoc_insertion_point(field_mutable:caffe.SolverParameter.test_net)
+  return test_net_.Mutable(index);
+}
+void SolverParameter::set_test_net(int index, const ::std::string& value) {
+  // @@protoc_insertion_point(field_set:caffe.SolverParameter.test_net)
+  test_net_.Mutable(index)->assign(value);
+}
+void SolverParameter::set_test_net(int index, const char* value) {
+  test_net_.Mutable(index)->assign(value);
+  // @@protoc_insertion_point(field_set_char:caffe.SolverParameter.test_net)
+}
+void SolverParameter::set_test_net(int index, const char* value, size_t size) {
+  test_net_.Mutable(index)->assign(
+    reinterpret_cast<const char*>(value), size);
+  // @@protoc_insertion_point(field_set_pointer:caffe.SolverParameter.test_net)
+}
+::std::string* SolverParameter::add_test_net() {
+  // @@protoc_insertion_point(field_add_mutable:caffe.SolverParameter.test_net)
+  return test_net_.Add();
+}
+void SolverParameter::add_test_net(const ::std::string& value) {
+  test_net_.Add()->assign(value);
+  // @@protoc_insertion_point(field_add:caffe.SolverParameter.test_net)
+}
+void SolverParameter::add_test_net(const char* value) {
+  test_net_.Add()->assign(value);
+  // @@protoc_insertion_point(field_add_char:caffe.SolverParameter.test_net)
+}
+void SolverParameter::add_test_net(const char* value, size_t size) {
+  test_net_.Add()->assign(reinterpret_cast<const char*>(value), size);
+  // @@protoc_insertion_point(field_add_pointer:caffe.SolverParameter.test_net)
+}
+const ::google::protobuf::RepeatedPtrField< ::std::string>&
+SolverParameter::test_net() const {
+  // @@protoc_insertion_point(field_list:caffe.SolverParameter.test_net)
+  return test_net_;
+}
+::google::protobuf::RepeatedPtrField< ::std::string>*
+SolverParameter::mutable_test_net() {
+  // @@protoc_insertion_point(field_mutable_list:caffe.SolverParameter.test_net)
+  return &test_net_;
+}
+
+// optional .caffe.NetParameter train_net_param = 21;
+bool SolverParameter::has_train_net_param() const {
+  return (_has_bits_[0] & 0x00000010u) != 0;
+}
+void SolverParameter::set_has_train_net_param() {
+  _has_bits_[0] |= 0x00000010u;
+}
+void SolverParameter::clear_has_train_net_param() {
+  _has_bits_[0] &= ~0x00000010u;
+}
+void SolverParameter::clear_train_net_param() {
+  if (train_net_param_ != NULL) train_net_param_->::caffe::NetParameter::Clear();
+  clear_has_train_net_param();
+}
+const ::caffe::NetParameter& SolverParameter::train_net_param() const {
+  // @@protoc_insertion_point(field_get:caffe.SolverParameter.train_net_param)
+  return train_net_param_ != NULL ? *train_net_param_
+                         : *::caffe::NetParameter::internal_default_instance();
+}
+::caffe::NetParameter* SolverParameter::mutable_train_net_param() {
+  set_has_train_net_param();
+  if (train_net_param_ == NULL) {
+    train_net_param_ = new ::caffe::NetParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.SolverParameter.train_net_param)
+  return train_net_param_;
+}
+::caffe::NetParameter* SolverParameter::release_train_net_param() {
+  // @@protoc_insertion_point(field_release:caffe.SolverParameter.train_net_param)
+  clear_has_train_net_param();
+  ::caffe::NetParameter* temp = train_net_param_;
+  train_net_param_ = NULL;
+  return temp;
+}
+void SolverParameter::set_allocated_train_net_param(::caffe::NetParameter* train_net_param) {
+  delete train_net_param_;
+  train_net_param_ = train_net_param;
+  if (train_net_param) {
+    set_has_train_net_param();
+  } else {
+    clear_has_train_net_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.SolverParameter.train_net_param)
+}
+
+// repeated .caffe.NetParameter test_net_param = 22;
+int SolverParameter::test_net_param_size() const {
+  return test_net_param_.size();
+}
+void SolverParameter::clear_test_net_param() {
+  test_net_param_.Clear();
+}
+const ::caffe::NetParameter& SolverParameter::test_net_param(int index) const {
+  // @@protoc_insertion_point(field_get:caffe.SolverParameter.test_net_param)
+  return test_net_param_.Get(index);
+}
+::caffe::NetParameter* SolverParameter::mutable_test_net_param(int index) {
+  // @@protoc_insertion_point(field_mutable:caffe.SolverParameter.test_net_param)
+  return test_net_param_.Mutable(index);
+}
+::caffe::NetParameter* SolverParameter::add_test_net_param() {
+  // @@protoc_insertion_point(field_add:caffe.SolverParameter.test_net_param)
+  return test_net_param_.Add();
+}
+::google::protobuf::RepeatedPtrField< ::caffe::NetParameter >*
+SolverParameter::mutable_test_net_param() {
+  // @@protoc_insertion_point(field_mutable_list:caffe.SolverParameter.test_net_param)
+  return &test_net_param_;
+}
+const ::google::protobuf::RepeatedPtrField< ::caffe::NetParameter >&
+SolverParameter::test_net_param() const {
+  // @@protoc_insertion_point(field_list:caffe.SolverParameter.test_net_param)
+  return test_net_param_;
+}
+
+// optional .caffe.NetState train_state = 26;
+bool SolverParameter::has_train_state() const {
+  return (_has_bits_[0] & 0x00000040u) != 0;
+}
+void SolverParameter::set_has_train_state() {
+  _has_bits_[0] |= 0x00000040u;
+}
+void SolverParameter::clear_has_train_state() {
+  _has_bits_[0] &= ~0x00000040u;
+}
+void SolverParameter::clear_train_state() {
+  if (train_state_ != NULL) train_state_->::caffe::NetState::Clear();
+  clear_has_train_state();
+}
+const ::caffe::NetState& SolverParameter::train_state() const {
+  // @@protoc_insertion_point(field_get:caffe.SolverParameter.train_state)
+  return train_state_ != NULL ? *train_state_
+                         : *::caffe::NetState::internal_default_instance();
+}
+::caffe::NetState* SolverParameter::mutable_train_state() {
+  set_has_train_state();
+  if (train_state_ == NULL) {
+    train_state_ = new ::caffe::NetState;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.SolverParameter.train_state)
+  return train_state_;
+}
+::caffe::NetState* SolverParameter::release_train_state() {
+  // @@protoc_insertion_point(field_release:caffe.SolverParameter.train_state)
+  clear_has_train_state();
+  ::caffe::NetState* temp = train_state_;
+  train_state_ = NULL;
+  return temp;
+}
+void SolverParameter::set_allocated_train_state(::caffe::NetState* train_state) {
+  delete train_state_;
+  train_state_ = train_state;
+  if (train_state) {
+    set_has_train_state();
+  } else {
+    clear_has_train_state();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.SolverParameter.train_state)
+}
+
+// repeated .caffe.NetState test_state = 27;
+int SolverParameter::test_state_size() const {
+  return test_state_.size();
+}
+void SolverParameter::clear_test_state() {
+  test_state_.Clear();
+}
+const ::caffe::NetState& SolverParameter::test_state(int index) const {
+  // @@protoc_insertion_point(field_get:caffe.SolverParameter.test_state)
+  return test_state_.Get(index);
+}
+::caffe::NetState* SolverParameter::mutable_test_state(int index) {
+  // @@protoc_insertion_point(field_mutable:caffe.SolverParameter.test_state)
+  return test_state_.Mutable(index);
+}
+::caffe::NetState* SolverParameter::add_test_state() {
+  // @@protoc_insertion_point(field_add:caffe.SolverParameter.test_state)
+  return test_state_.Add();
+}
+::google::protobuf::RepeatedPtrField< ::caffe::NetState >*
+SolverParameter::mutable_test_state() {
+  // @@protoc_insertion_point(field_mutable_list:caffe.SolverParameter.test_state)
+  return &test_state_;
+}
+const ::google::protobuf::RepeatedPtrField< ::caffe::NetState >&
+SolverParameter::test_state() const {
+  // @@protoc_insertion_point(field_list:caffe.SolverParameter.test_state)
+  return test_state_;
+}
+
+// repeated int32 test_iter = 3;
+int SolverParameter::test_iter_size() const {
+  return test_iter_.size();
+}
+void SolverParameter::clear_test_iter() {
+  test_iter_.Clear();
+}
+::google::protobuf::int32 SolverParameter::test_iter(int index) const {
+  // @@protoc_insertion_point(field_get:caffe.SolverParameter.test_iter)
+  return test_iter_.Get(index);
+}
+void SolverParameter::set_test_iter(int index, ::google::protobuf::int32 value) {
+  test_iter_.Set(index, value);
+  // @@protoc_insertion_point(field_set:caffe.SolverParameter.test_iter)
+}
+void SolverParameter::add_test_iter(::google::protobuf::int32 value) {
+  test_iter_.Add(value);
+  // @@protoc_insertion_point(field_add:caffe.SolverParameter.test_iter)
+}
+const ::google::protobuf::RepeatedField< ::google::protobuf::int32 >&
+SolverParameter::test_iter() const {
+  // @@protoc_insertion_point(field_list:caffe.SolverParameter.test_iter)
+  return test_iter_;
+}
+::google::protobuf::RepeatedField< ::google::protobuf::int32 >*
+SolverParameter::mutable_test_iter() {
+  // @@protoc_insertion_point(field_mutable_list:caffe.SolverParameter.test_iter)
+  return &test_iter_;
+}
+
+// optional int32 test_interval = 4 [default = 0];
+bool SolverParameter::has_test_interval() const {
+  return (_has_bits_[0] & 0x00000200u) != 0;
+}
+void SolverParameter::set_has_test_interval() {
+  _has_bits_[0] |= 0x00000200u;
+}
+void SolverParameter::clear_has_test_interval() {
+  _has_bits_[0] &= ~0x00000200u;
+}
+void SolverParameter::clear_test_interval() {
+  test_interval_ = 0;
+  clear_has_test_interval();
+}
+::google::protobuf::int32 SolverParameter::test_interval() const {
+  // @@protoc_insertion_point(field_get:caffe.SolverParameter.test_interval)
+  return test_interval_;
+}
+void SolverParameter::set_test_interval(::google::protobuf::int32 value) {
+  set_has_test_interval();
+  test_interval_ = value;
+  // @@protoc_insertion_point(field_set:caffe.SolverParameter.test_interval)
+}
+
+// optional bool test_compute_loss = 19 [default = false];
+bool SolverParameter::has_test_compute_loss() const {
+  return (_has_bits_[0] & 0x00000400u) != 0;
+}
+void SolverParameter::set_has_test_compute_loss() {
+  _has_bits_[0] |= 0x00000400u;
+}
+void SolverParameter::clear_has_test_compute_loss() {
+  _has_bits_[0] &= ~0x00000400u;
+}
+void SolverParameter::clear_test_compute_loss() {
+  test_compute_loss_ = false;
+  clear_has_test_compute_loss();
+}
+bool SolverParameter::test_compute_loss() const {
+  // @@protoc_insertion_point(field_get:caffe.SolverParameter.test_compute_loss)
+  return test_compute_loss_;
+}
+void SolverParameter::set_test_compute_loss(bool value) {
+  set_has_test_compute_loss();
+  test_compute_loss_ = value;
+  // @@protoc_insertion_point(field_set:caffe.SolverParameter.test_compute_loss)
+}
+
+// optional bool test_initialization = 32 [default = true];
+bool SolverParameter::has_test_initialization() const {
+  return (_has_bits_[0] & 0x00000800u) != 0;
+}
+void SolverParameter::set_has_test_initialization() {
+  _has_bits_[0] |= 0x00000800u;
+}
+void SolverParameter::clear_has_test_initialization() {
+  _has_bits_[0] &= ~0x00000800u;
+}
+void SolverParameter::clear_test_initialization() {
+  test_initialization_ = true;
+  clear_has_test_initialization();
+}
+bool SolverParameter::test_initialization() const {
+  // @@protoc_insertion_point(field_get:caffe.SolverParameter.test_initialization)
+  return test_initialization_;
+}
+void SolverParameter::set_test_initialization(bool value) {
+  set_has_test_initialization();
+  test_initialization_ = value;
+  // @@protoc_insertion_point(field_set:caffe.SolverParameter.test_initialization)
+}
+
+// optional float base_lr = 5;
+bool SolverParameter::has_base_lr() const {
+  return (_has_bits_[0] & 0x00001000u) != 0;
+}
+void SolverParameter::set_has_base_lr() {
+  _has_bits_[0] |= 0x00001000u;
+}
+void SolverParameter::clear_has_base_lr() {
+  _has_bits_[0] &= ~0x00001000u;
+}
+void SolverParameter::clear_base_lr() {
+  base_lr_ = 0;
+  clear_has_base_lr();
+}
+float SolverParameter::base_lr() const {
+  // @@protoc_insertion_point(field_get:caffe.SolverParameter.base_lr)
+  return base_lr_;
+}
+void SolverParameter::set_base_lr(float value) {
+  set_has_base_lr();
+  base_lr_ = value;
+  // @@protoc_insertion_point(field_set:caffe.SolverParameter.base_lr)
+}
+
+// optional int32 display = 6;
+bool SolverParameter::has_display() const {
+  return (_has_bits_[0] & 0x00002000u) != 0;
+}
+void SolverParameter::set_has_display() {
+  _has_bits_[0] |= 0x00002000u;
+}
+void SolverParameter::clear_has_display() {
+  _has_bits_[0] &= ~0x00002000u;
+}
+void SolverParameter::clear_display() {
+  display_ = 0;
+  clear_has_display();
+}
+::google::protobuf::int32 SolverParameter::display() const {
+  // @@protoc_insertion_point(field_get:caffe.SolverParameter.display)
+  return display_;
+}
+void SolverParameter::set_display(::google::protobuf::int32 value) {
+  set_has_display();
+  display_ = value;
+  // @@protoc_insertion_point(field_set:caffe.SolverParameter.display)
+}
+
+// optional int32 average_loss = 33 [default = 1];
+bool SolverParameter::has_average_loss() const {
+  return (_has_bits_[0] & 0x00004000u) != 0;
+}
+void SolverParameter::set_has_average_loss() {
+  _has_bits_[0] |= 0x00004000u;
+}
+void SolverParameter::clear_has_average_loss() {
+  _has_bits_[0] &= ~0x00004000u;
+}
+void SolverParameter::clear_average_loss() {
+  average_loss_ = 1;
+  clear_has_average_loss();
+}
+::google::protobuf::int32 SolverParameter::average_loss() const {
+  // @@protoc_insertion_point(field_get:caffe.SolverParameter.average_loss)
+  return average_loss_;
+}
+void SolverParameter::set_average_loss(::google::protobuf::int32 value) {
+  set_has_average_loss();
+  average_loss_ = value;
+  // @@protoc_insertion_point(field_set:caffe.SolverParameter.average_loss)
+}
+
+// optional int32 max_iter = 7;
+bool SolverParameter::has_max_iter() const {
+  return (_has_bits_[0] & 0x00008000u) != 0;
+}
+void SolverParameter::set_has_max_iter() {
+  _has_bits_[0] |= 0x00008000u;
+}
+void SolverParameter::clear_has_max_iter() {
+  _has_bits_[0] &= ~0x00008000u;
+}
+void SolverParameter::clear_max_iter() {
+  max_iter_ = 0;
+  clear_has_max_iter();
+}
+::google::protobuf::int32 SolverParameter::max_iter() const {
+  // @@protoc_insertion_point(field_get:caffe.SolverParameter.max_iter)
+  return max_iter_;
+}
+void SolverParameter::set_max_iter(::google::protobuf::int32 value) {
+  set_has_max_iter();
+  max_iter_ = value;
+  // @@protoc_insertion_point(field_set:caffe.SolverParameter.max_iter)
+}
+
+// optional int32 iter_size = 36 [default = 1];
+bool SolverParameter::has_iter_size() const {
+  return (_has_bits_[0] & 0x00010000u) != 0;
+}
+void SolverParameter::set_has_iter_size() {
+  _has_bits_[0] |= 0x00010000u;
+}
+void SolverParameter::clear_has_iter_size() {
+  _has_bits_[0] &= ~0x00010000u;
+}
+void SolverParameter::clear_iter_size() {
+  iter_size_ = 1;
+  clear_has_iter_size();
+}
+::google::protobuf::int32 SolverParameter::iter_size() const {
+  // @@protoc_insertion_point(field_get:caffe.SolverParameter.iter_size)
+  return iter_size_;
+}
+void SolverParameter::set_iter_size(::google::protobuf::int32 value) {
+  set_has_iter_size();
+  iter_size_ = value;
+  // @@protoc_insertion_point(field_set:caffe.SolverParameter.iter_size)
+}
+
+// optional string lr_policy = 8;
+bool SolverParameter::has_lr_policy() const {
+  return (_has_bits_[0] & 0x00020000u) != 0;
+}
+void SolverParameter::set_has_lr_policy() {
+  _has_bits_[0] |= 0x00020000u;
+}
+void SolverParameter::clear_has_lr_policy() {
+  _has_bits_[0] &= ~0x00020000u;
+}
+void SolverParameter::clear_lr_policy() {
+  lr_policy_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  clear_has_lr_policy();
+}
+const ::std::string& SolverParameter::lr_policy() const {
+  // @@protoc_insertion_point(field_get:caffe.SolverParameter.lr_policy)
+  return lr_policy_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+void SolverParameter::set_lr_policy(const ::std::string& value) {
+  set_has_lr_policy();
+  lr_policy_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:caffe.SolverParameter.lr_policy)
+}
+void SolverParameter::set_lr_policy(const char* value) {
+  set_has_lr_policy();
+  lr_policy_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:caffe.SolverParameter.lr_policy)
+}
+void SolverParameter::set_lr_policy(const char* value, size_t size) {
+  set_has_lr_policy();
+  lr_policy_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:caffe.SolverParameter.lr_policy)
+}
+::std::string* SolverParameter::mutable_lr_policy() {
+  set_has_lr_policy();
+  // @@protoc_insertion_point(field_mutable:caffe.SolverParameter.lr_policy)
+  return lr_policy_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+::std::string* SolverParameter::release_lr_policy() {
+  // @@protoc_insertion_point(field_release:caffe.SolverParameter.lr_policy)
+  clear_has_lr_policy();
+  return lr_policy_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+void SolverParameter::set_allocated_lr_policy(::std::string* lr_policy) {
+  if (lr_policy != NULL) {
+    set_has_lr_policy();
+  } else {
+    clear_has_lr_policy();
+  }
+  lr_policy_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), lr_policy);
+  // @@protoc_insertion_point(field_set_allocated:caffe.SolverParameter.lr_policy)
+}
+
+// optional float gamma = 9;
+bool SolverParameter::has_gamma() const {
+  return (_has_bits_[0] & 0x00040000u) != 0;
+}
+void SolverParameter::set_has_gamma() {
+  _has_bits_[0] |= 0x00040000u;
+}
+void SolverParameter::clear_has_gamma() {
+  _has_bits_[0] &= ~0x00040000u;
+}
+void SolverParameter::clear_gamma() {
+  gamma_ = 0;
+  clear_has_gamma();
+}
+float SolverParameter::gamma() const {
+  // @@protoc_insertion_point(field_get:caffe.SolverParameter.gamma)
+  return gamma_;
+}
+void SolverParameter::set_gamma(float value) {
+  set_has_gamma();
+  gamma_ = value;
+  // @@protoc_insertion_point(field_set:caffe.SolverParameter.gamma)
+}
+
+// optional float power = 10;
+bool SolverParameter::has_power() const {
+  return (_has_bits_[0] & 0x00080000u) != 0;
+}
+void SolverParameter::set_has_power() {
+  _has_bits_[0] |= 0x00080000u;
+}
+void SolverParameter::clear_has_power() {
+  _has_bits_[0] &= ~0x00080000u;
+}
+void SolverParameter::clear_power() {
+  power_ = 0;
+  clear_has_power();
+}
+float SolverParameter::power() const {
+  // @@protoc_insertion_point(field_get:caffe.SolverParameter.power)
+  return power_;
+}
+void SolverParameter::set_power(float value) {
+  set_has_power();
+  power_ = value;
+  // @@protoc_insertion_point(field_set:caffe.SolverParameter.power)
+}
+
+// optional float momentum = 11;
+bool SolverParameter::has_momentum() const {
+  return (_has_bits_[0] & 0x00100000u) != 0;
+}
+void SolverParameter::set_has_momentum() {
+  _has_bits_[0] |= 0x00100000u;
+}
+void SolverParameter::clear_has_momentum() {
+  _has_bits_[0] &= ~0x00100000u;
+}
+void SolverParameter::clear_momentum() {
+  momentum_ = 0;
+  clear_has_momentum();
+}
+float SolverParameter::momentum() const {
+  // @@protoc_insertion_point(field_get:caffe.SolverParameter.momentum)
+  return momentum_;
+}
+void SolverParameter::set_momentum(float value) {
+  set_has_momentum();
+  momentum_ = value;
+  // @@protoc_insertion_point(field_set:caffe.SolverParameter.momentum)
+}
+
+// optional float weight_decay = 12;
+bool SolverParameter::has_weight_decay() const {
+  return (_has_bits_[0] & 0x00200000u) != 0;
+}
+void SolverParameter::set_has_weight_decay() {
+  _has_bits_[0] |= 0x00200000u;
+}
+void SolverParameter::clear_has_weight_decay() {
+  _has_bits_[0] &= ~0x00200000u;
+}
+void SolverParameter::clear_weight_decay() {
+  weight_decay_ = 0;
+  clear_has_weight_decay();
+}
+float SolverParameter::weight_decay() const {
+  // @@protoc_insertion_point(field_get:caffe.SolverParameter.weight_decay)
+  return weight_decay_;
+}
+void SolverParameter::set_weight_decay(float value) {
+  set_has_weight_decay();
+  weight_decay_ = value;
+  // @@protoc_insertion_point(field_set:caffe.SolverParameter.weight_decay)
+}
+
+// optional string regularization_type = 29 [default = "L2"];
+bool SolverParameter::has_regularization_type() const {
+  return (_has_bits_[0] & 0x00400000u) != 0;
+}
+void SolverParameter::set_has_regularization_type() {
+  _has_bits_[0] |= 0x00400000u;
+}
+void SolverParameter::clear_has_regularization_type() {
+  _has_bits_[0] &= ~0x00400000u;
+}
+void SolverParameter::clear_regularization_type() {
+  regularization_type_.ClearToDefaultNoArena(_default_regularization_type_);
+  clear_has_regularization_type();
+}
+const ::std::string& SolverParameter::regularization_type() const {
+  // @@protoc_insertion_point(field_get:caffe.SolverParameter.regularization_type)
+  return regularization_type_.GetNoArena(_default_regularization_type_);
+}
+void SolverParameter::set_regularization_type(const ::std::string& value) {
+  set_has_regularization_type();
+  regularization_type_.SetNoArena(_default_regularization_type_, value);
+  // @@protoc_insertion_point(field_set:caffe.SolverParameter.regularization_type)
+}
+void SolverParameter::set_regularization_type(const char* value) {
+  set_has_regularization_type();
+  regularization_type_.SetNoArena(_default_regularization_type_, ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:caffe.SolverParameter.regularization_type)
+}
+void SolverParameter::set_regularization_type(const char* value, size_t size) {
+  set_has_regularization_type();
+  regularization_type_.SetNoArena(_default_regularization_type_,
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:caffe.SolverParameter.regularization_type)
+}
+::std::string* SolverParameter::mutable_regularization_type() {
+  set_has_regularization_type();
+  // @@protoc_insertion_point(field_mutable:caffe.SolverParameter.regularization_type)
+  return regularization_type_.MutableNoArena(_default_regularization_type_);
+}
+::std::string* SolverParameter::release_regularization_type() {
+  // @@protoc_insertion_point(field_release:caffe.SolverParameter.regularization_type)
+  clear_has_regularization_type();
+  return regularization_type_.ReleaseNoArena(_default_regularization_type_);
+}
+void SolverParameter::set_allocated_regularization_type(::std::string* regularization_type) {
+  if (regularization_type != NULL) {
+    set_has_regularization_type();
+  } else {
+    clear_has_regularization_type();
+  }
+  regularization_type_.SetAllocatedNoArena(_default_regularization_type_, regularization_type);
+  // @@protoc_insertion_point(field_set_allocated:caffe.SolverParameter.regularization_type)
+}
+
+// optional int32 stepsize = 13;
+bool SolverParameter::has_stepsize() const {
+  return (_has_bits_[0] & 0x00800000u) != 0;
+}
+void SolverParameter::set_has_stepsize() {
+  _has_bits_[0] |= 0x00800000u;
+}
+void SolverParameter::clear_has_stepsize() {
+  _has_bits_[0] &= ~0x00800000u;
+}
+void SolverParameter::clear_stepsize() {
+  stepsize_ = 0;
+  clear_has_stepsize();
+}
+::google::protobuf::int32 SolverParameter::stepsize() const {
+  // @@protoc_insertion_point(field_get:caffe.SolverParameter.stepsize)
+  return stepsize_;
+}
+void SolverParameter::set_stepsize(::google::protobuf::int32 value) {
+  set_has_stepsize();
+  stepsize_ = value;
+  // @@protoc_insertion_point(field_set:caffe.SolverParameter.stepsize)
+}
+
+// repeated int32 stepvalue = 34;
+int SolverParameter::stepvalue_size() const {
+  return stepvalue_.size();
+}
+void SolverParameter::clear_stepvalue() {
+  stepvalue_.Clear();
+}
+::google::protobuf::int32 SolverParameter::stepvalue(int index) const {
+  // @@protoc_insertion_point(field_get:caffe.SolverParameter.stepvalue)
+  return stepvalue_.Get(index);
+}
+void SolverParameter::set_stepvalue(int index, ::google::protobuf::int32 value) {
+  stepvalue_.Set(index, value);
+  // @@protoc_insertion_point(field_set:caffe.SolverParameter.stepvalue)
+}
+void SolverParameter::add_stepvalue(::google::protobuf::int32 value) {
+  stepvalue_.Add(value);
+  // @@protoc_insertion_point(field_add:caffe.SolverParameter.stepvalue)
+}
+const ::google::protobuf::RepeatedField< ::google::protobuf::int32 >&
+SolverParameter::stepvalue() const {
+  // @@protoc_insertion_point(field_list:caffe.SolverParameter.stepvalue)
+  return stepvalue_;
+}
+::google::protobuf::RepeatedField< ::google::protobuf::int32 >*
+SolverParameter::mutable_stepvalue() {
+  // @@protoc_insertion_point(field_mutable_list:caffe.SolverParameter.stepvalue)
+  return &stepvalue_;
+}
+
+// optional float clip_gradients = 35 [default = -1];
+bool SolverParameter::has_clip_gradients() const {
+  return (_has_bits_[0] & 0x02000000u) != 0;
+}
+void SolverParameter::set_has_clip_gradients() {
+  _has_bits_[0] |= 0x02000000u;
+}
+void SolverParameter::clear_has_clip_gradients() {
+  _has_bits_[0] &= ~0x02000000u;
+}
+void SolverParameter::clear_clip_gradients() {
+  clip_gradients_ = -1;
+  clear_has_clip_gradients();
+}
+float SolverParameter::clip_gradients() const {
+  // @@protoc_insertion_point(field_get:caffe.SolverParameter.clip_gradients)
+  return clip_gradients_;
+}
+void SolverParameter::set_clip_gradients(float value) {
+  set_has_clip_gradients();
+  clip_gradients_ = value;
+  // @@protoc_insertion_point(field_set:caffe.SolverParameter.clip_gradients)
+}
+
+// optional int32 snapshot = 14 [default = 0];
+bool SolverParameter::has_snapshot() const {
+  return (_has_bits_[0] & 0x04000000u) != 0;
+}
+void SolverParameter::set_has_snapshot() {
+  _has_bits_[0] |= 0x04000000u;
+}
+void SolverParameter::clear_has_snapshot() {
+  _has_bits_[0] &= ~0x04000000u;
+}
+void SolverParameter::clear_snapshot() {
+  snapshot_ = 0;
+  clear_has_snapshot();
+}
+::google::protobuf::int32 SolverParameter::snapshot() const {
+  // @@protoc_insertion_point(field_get:caffe.SolverParameter.snapshot)
+  return snapshot_;
+}
+void SolverParameter::set_snapshot(::google::protobuf::int32 value) {
+  set_has_snapshot();
+  snapshot_ = value;
+  // @@protoc_insertion_point(field_set:caffe.SolverParameter.snapshot)
+}
+
+// optional string snapshot_prefix = 15;
+bool SolverParameter::has_snapshot_prefix() const {
+  return (_has_bits_[0] & 0x08000000u) != 0;
+}
+void SolverParameter::set_has_snapshot_prefix() {
+  _has_bits_[0] |= 0x08000000u;
+}
+void SolverParameter::clear_has_snapshot_prefix() {
+  _has_bits_[0] &= ~0x08000000u;
+}
+void SolverParameter::clear_snapshot_prefix() {
+  snapshot_prefix_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  clear_has_snapshot_prefix();
+}
+const ::std::string& SolverParameter::snapshot_prefix() const {
+  // @@protoc_insertion_point(field_get:caffe.SolverParameter.snapshot_prefix)
+  return snapshot_prefix_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+void SolverParameter::set_snapshot_prefix(const ::std::string& value) {
+  set_has_snapshot_prefix();
+  snapshot_prefix_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:caffe.SolverParameter.snapshot_prefix)
+}
+void SolverParameter::set_snapshot_prefix(const char* value) {
+  set_has_snapshot_prefix();
+  snapshot_prefix_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:caffe.SolverParameter.snapshot_prefix)
+}
+void SolverParameter::set_snapshot_prefix(const char* value, size_t size) {
+  set_has_snapshot_prefix();
+  snapshot_prefix_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:caffe.SolverParameter.snapshot_prefix)
+}
+::std::string* SolverParameter::mutable_snapshot_prefix() {
+  set_has_snapshot_prefix();
+  // @@protoc_insertion_point(field_mutable:caffe.SolverParameter.snapshot_prefix)
+  return snapshot_prefix_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+::std::string* SolverParameter::release_snapshot_prefix() {
+  // @@protoc_insertion_point(field_release:caffe.SolverParameter.snapshot_prefix)
+  clear_has_snapshot_prefix();
+  return snapshot_prefix_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+void SolverParameter::set_allocated_snapshot_prefix(::std::string* snapshot_prefix) {
+  if (snapshot_prefix != NULL) {
+    set_has_snapshot_prefix();
+  } else {
+    clear_has_snapshot_prefix();
+  }
+  snapshot_prefix_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), snapshot_prefix);
+  // @@protoc_insertion_point(field_set_allocated:caffe.SolverParameter.snapshot_prefix)
+}
+
+// optional bool snapshot_diff = 16 [default = false];
+bool SolverParameter::has_snapshot_diff() const {
+  return (_has_bits_[0] & 0x10000000u) != 0;
+}
+void SolverParameter::set_has_snapshot_diff() {
+  _has_bits_[0] |= 0x10000000u;
+}
+void SolverParameter::clear_has_snapshot_diff() {
+  _has_bits_[0] &= ~0x10000000u;
+}
+void SolverParameter::clear_snapshot_diff() {
+  snapshot_diff_ = false;
+  clear_has_snapshot_diff();
+}
+bool SolverParameter::snapshot_diff() const {
+  // @@protoc_insertion_point(field_get:caffe.SolverParameter.snapshot_diff)
+  return snapshot_diff_;
+}
+void SolverParameter::set_snapshot_diff(bool value) {
+  set_has_snapshot_diff();
+  snapshot_diff_ = value;
+  // @@protoc_insertion_point(field_set:caffe.SolverParameter.snapshot_diff)
+}
+
+// optional .caffe.SolverParameter.SolverMode solver_mode = 17 [default = GPU];
+bool SolverParameter::has_solver_mode() const {
+  return (_has_bits_[0] & 0x20000000u) != 0;
+}
+void SolverParameter::set_has_solver_mode() {
+  _has_bits_[0] |= 0x20000000u;
+}
+void SolverParameter::clear_has_solver_mode() {
+  _has_bits_[0] &= ~0x20000000u;
+}
+void SolverParameter::clear_solver_mode() {
+  solver_mode_ = 1;
+  clear_has_solver_mode();
+}
+::caffe::SolverParameter_SolverMode SolverParameter::solver_mode() const {
+  // @@protoc_insertion_point(field_get:caffe.SolverParameter.solver_mode)
+  return static_cast< ::caffe::SolverParameter_SolverMode >(solver_mode_);
+}
+void SolverParameter::set_solver_mode(::caffe::SolverParameter_SolverMode value) {
+  assert(::caffe::SolverParameter_SolverMode_IsValid(value));
+  set_has_solver_mode();
+  solver_mode_ = value;
+  // @@protoc_insertion_point(field_set:caffe.SolverParameter.solver_mode)
+}
+
+// optional int32 device_id = 18 [default = 0];
+bool SolverParameter::has_device_id() const {
+  return (_has_bits_[0] & 0x40000000u) != 0;
+}
+void SolverParameter::set_has_device_id() {
+  _has_bits_[0] |= 0x40000000u;
+}
+void SolverParameter::clear_has_device_id() {
+  _has_bits_[0] &= ~0x40000000u;
+}
+void SolverParameter::clear_device_id() {
+  device_id_ = 0;
+  clear_has_device_id();
+}
+::google::protobuf::int32 SolverParameter::device_id() const {
+  // @@protoc_insertion_point(field_get:caffe.SolverParameter.device_id)
+  return device_id_;
+}
+void SolverParameter::set_device_id(::google::protobuf::int32 value) {
+  set_has_device_id();
+  device_id_ = value;
+  // @@protoc_insertion_point(field_set:caffe.SolverParameter.device_id)
+}
+
+// optional int64 random_seed = 20 [default = -1];
+bool SolverParameter::has_random_seed() const {
+  return (_has_bits_[0] & 0x80000000u) != 0;
+}
+void SolverParameter::set_has_random_seed() {
+  _has_bits_[0] |= 0x80000000u;
+}
+void SolverParameter::clear_has_random_seed() {
+  _has_bits_[0] &= ~0x80000000u;
+}
+void SolverParameter::clear_random_seed() {
+  random_seed_ = GOOGLE_LONGLONG(-1);
+  clear_has_random_seed();
+}
+::google::protobuf::int64 SolverParameter::random_seed() const {
+  // @@protoc_insertion_point(field_get:caffe.SolverParameter.random_seed)
+  return random_seed_;
+}
+void SolverParameter::set_random_seed(::google::protobuf::int64 value) {
+  set_has_random_seed();
+  random_seed_ = value;
+  // @@protoc_insertion_point(field_set:caffe.SolverParameter.random_seed)
+}
+
+// optional .caffe.SolverParameter.SolverType solver_type = 30 [default = SGD];
+bool SolverParameter::has_solver_type() const {
+  return (_has_bits_[1] & 0x00000001u) != 0;
+}
+void SolverParameter::set_has_solver_type() {
+  _has_bits_[1] |= 0x00000001u;
+}
+void SolverParameter::clear_has_solver_type() {
+  _has_bits_[1] &= ~0x00000001u;
+}
+void SolverParameter::clear_solver_type() {
+  solver_type_ = 0;
+  clear_has_solver_type();
+}
+::caffe::SolverParameter_SolverType SolverParameter::solver_type() const {
+  // @@protoc_insertion_point(field_get:caffe.SolverParameter.solver_type)
+  return static_cast< ::caffe::SolverParameter_SolverType >(solver_type_);
+}
+void SolverParameter::set_solver_type(::caffe::SolverParameter_SolverType value) {
+  assert(::caffe::SolverParameter_SolverType_IsValid(value));
+  set_has_solver_type();
+  solver_type_ = value;
+  // @@protoc_insertion_point(field_set:caffe.SolverParameter.solver_type)
+}
+
+// optional float delta = 31 [default = 1e-08];
+bool SolverParameter::has_delta() const {
+  return (_has_bits_[1] & 0x00000002u) != 0;
+}
+void SolverParameter::set_has_delta() {
+  _has_bits_[1] |= 0x00000002u;
+}
+void SolverParameter::clear_has_delta() {
+  _has_bits_[1] &= ~0x00000002u;
+}
+void SolverParameter::clear_delta() {
+  delta_ = 1e-08f;
+  clear_has_delta();
+}
+float SolverParameter::delta() const {
+  // @@protoc_insertion_point(field_get:caffe.SolverParameter.delta)
+  return delta_;
+}
+void SolverParameter::set_delta(float value) {
+  set_has_delta();
+  delta_ = value;
+  // @@protoc_insertion_point(field_set:caffe.SolverParameter.delta)
+}
+
+// optional bool debug_info = 23 [default = false];
+bool SolverParameter::has_debug_info() const {
+  return (_has_bits_[1] & 0x00000004u) != 0;
+}
+void SolverParameter::set_has_debug_info() {
+  _has_bits_[1] |= 0x00000004u;
+}
+void SolverParameter::clear_has_debug_info() {
+  _has_bits_[1] &= ~0x00000004u;
+}
+void SolverParameter::clear_debug_info() {
+  debug_info_ = false;
+  clear_has_debug_info();
+}
+bool SolverParameter::debug_info() const {
+  // @@protoc_insertion_point(field_get:caffe.SolverParameter.debug_info)
+  return debug_info_;
+}
+void SolverParameter::set_debug_info(bool value) {
+  set_has_debug_info();
+  debug_info_ = value;
+  // @@protoc_insertion_point(field_set:caffe.SolverParameter.debug_info)
+}
+
+// optional bool snapshot_after_train = 28 [default = true];
+bool SolverParameter::has_snapshot_after_train() const {
+  return (_has_bits_[1] & 0x00000008u) != 0;
+}
+void SolverParameter::set_has_snapshot_after_train() {
+  _has_bits_[1] |= 0x00000008u;
+}
+void SolverParameter::clear_has_snapshot_after_train() {
+  _has_bits_[1] &= ~0x00000008u;
+}
+void SolverParameter::clear_snapshot_after_train() {
+  snapshot_after_train_ = true;
+  clear_has_snapshot_after_train();
+}
+bool SolverParameter::snapshot_after_train() const {
+  // @@protoc_insertion_point(field_get:caffe.SolverParameter.snapshot_after_train)
+  return snapshot_after_train_;
+}
+void SolverParameter::set_snapshot_after_train(bool value) {
+  set_has_snapshot_after_train();
+  snapshot_after_train_ = value;
+  // @@protoc_insertion_point(field_set:caffe.SolverParameter.snapshot_after_train)
+}
+
+inline const SolverParameter* SolverParameter::internal_default_instance() {
+  return &SolverParameter_default_instance_.get();
+}
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
+
+// ===================================================================
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const int SolverState::kIterFieldNumber;
+const int SolverState::kLearnedNetFieldNumber;
+const int SolverState::kHistoryFieldNumber;
+const int SolverState::kCurrentStepFieldNumber;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+
+SolverState::SolverState()
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+  if (this != internal_default_instance()) protobuf_InitDefaults_caffe_2eproto();
+  SharedCtor();
+  // @@protoc_insertion_point(constructor:caffe.SolverState)
+}
+
+void SolverState::InitAsDefaultInstance() {
+}
+
+SolverState::SolverState(const SolverState& from)
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
+  SharedCtor();
+  UnsafeMergeFrom(from);
+  // @@protoc_insertion_point(copy_constructor:caffe.SolverState)
+}
+
+void SolverState::SharedCtor() {
+  _cached_size_ = 0;
+  learned_net_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  ::memset(&iter_, 0, reinterpret_cast<char*>(&current_step_) -
+    reinterpret_cast<char*>(&iter_) + sizeof(current_step_));
+}
+
+SolverState::~SolverState() {
+  // @@protoc_insertion_point(destructor:caffe.SolverState)
+  SharedDtor();
+}
+
+void SolverState::SharedDtor() {
+  learned_net_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+
+void SolverState::SetCachedSize(int size) const {
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* SolverState::descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return SolverState_descriptor_;
+}
+
+const SolverState& SolverState::default_instance() {
+  protobuf_InitDefaults_caffe_2eproto();
+  return *internal_default_instance();
+}
+
+::google::protobuf::internal::ExplicitlyConstructed<SolverState> SolverState_default_instance_;
+
+SolverState* SolverState::New(::google::protobuf::Arena* arena) const {
+  SolverState* n = new SolverState;
+  if (arena != NULL) {
+    arena->Own(n);
+  }
+  return n;
+}
+
+void SolverState::Clear() {
+// @@protoc_insertion_point(message_clear_start:caffe.SolverState)
+#if defined(__clang__)
+#define ZR_HELPER_(f) \
+  _Pragma("clang diagnostic push") \
+  _Pragma("clang diagnostic ignored \"-Winvalid-offsetof\"") \
+  __builtin_offsetof(SolverState, f) \
+  _Pragma("clang diagnostic pop")
+#else
+#define ZR_HELPER_(f) reinterpret_cast<char*>(\
+  &reinterpret_cast<SolverState*>(16)->f)
+#endif
+
+#define ZR_(first, last) do {\
+  ::memset(&(first), 0,\
+           ZR_HELPER_(last) - ZR_HELPER_(first) + sizeof(last));\
+} while (0)
+
+  if (_has_bits_[0 / 32] & 11u) {
+    ZR_(iter_, current_step_);
+    if (has_learned_net()) {
+      learned_net_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+    }
+  }
+
+#undef ZR_HELPER_
+#undef ZR_
+
+  history_.Clear();
+  _has_bits_.Clear();
+  if (_internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->Clear();
+  }
+}
+
+bool SolverState::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
+  ::google::protobuf::uint32 tag;
+  // @@protoc_insertion_point(parse_start:caffe.SolverState)
+  for (;;) {
+    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+    tag = p.first;
+    if (!p.second) goto handle_unusual;
+    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+      // optional int32 iter = 1;
+      case 1: {
+        if (tag == 8) {
+          set_has_iter();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
+                 input, &iter_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(18)) goto parse_learned_net;
+        break;
+      }
+
+      // optional string learned_net = 2;
+      case 2: {
+        if (tag == 18) {
+         parse_learned_net:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+                input, this->mutable_learned_net()));
+          ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+            this->learned_net().data(), this->learned_net().length(),
+            ::google::protobuf::internal::WireFormat::PARSE,
+            "caffe.SolverState.learned_net");
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(26)) goto parse_history;
+        break;
+      }
+
+      // repeated .caffe.BlobProto history = 3;
+      case 3: {
+        if (tag == 26) {
+         parse_history:
+          DO_(input->IncrementRecursionDepth());
+         parse_loop_history:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth(
+                input, add_history()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(26)) goto parse_loop_history;
+        input->UnsafeDecrementRecursionDepth();
+        if (input->ExpectTag(32)) goto parse_current_step;
+        break;
+      }
+
+      // optional int32 current_step = 4 [default = 0];
+      case 4: {
+        if (tag == 32) {
+         parse_current_step:
+          set_has_current_step();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
+                 input, &current_step_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectAtEnd()) goto success;
+        break;
+      }
+
+      default: {
+      handle_unusual:
+        if (tag == 0 ||
+            ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+          goto success;
+        }
+        DO_(::google::protobuf::internal::WireFormat::SkipField(
+              input, tag, mutable_unknown_fields()));
+        break;
+      }
+    }
+  }
+success:
+  // @@protoc_insertion_point(parse_success:caffe.SolverState)
+  return true;
+failure:
+  // @@protoc_insertion_point(parse_failure:caffe.SolverState)
+  return false;
+#undef DO_
+}
+
+void SolverState::SerializeWithCachedSizes(
+    ::google::protobuf::io::CodedOutputStream* output) const {
+  // @@protoc_insertion_point(serialize_start:caffe.SolverState)
+  // optional int32 iter = 1;
+  if (has_iter()) {
+    ::google::protobuf::internal::WireFormatLite::WriteInt32(1, this->iter(), output);
+  }
+
+  // optional string learned_net = 2;
+  if (has_learned_net()) {
+    ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->learned_net().data(), this->learned_net().length(),
+      ::google::protobuf::internal::WireFormat::SERIALIZE,
+      "caffe.SolverState.learned_net");
+    ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
+      2, this->learned_net(), output);
+  }
+
+  // repeated .caffe.BlobProto history = 3;
+  for (unsigned int i = 0, n = this->history_size(); i < n; i++) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      3, this->history(i), output);
+  }
+
+  // optional int32 current_step = 4 [default = 0];
+  if (has_current_step()) {
+    ::google::protobuf::internal::WireFormatLite::WriteInt32(4, this->current_step(), output);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
+        unknown_fields(), output);
+  }
+  // @@protoc_insertion_point(serialize_end:caffe.SolverState)
+}
+
+::google::protobuf::uint8* SolverState::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
+  (void)deterministic; // Unused
+  // @@protoc_insertion_point(serialize_to_array_start:caffe.SolverState)
+  // optional int32 iter = 1;
+  if (has_iter()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteInt32ToArray(1, this->iter(), target);
+  }
+
+  // optional string learned_net = 2;
+  if (has_learned_net()) {
+    ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->learned_net().data(), this->learned_net().length(),
+      ::google::protobuf::internal::WireFormat::SERIALIZE,
+      "caffe.SolverState.learned_net");
+    target =
+      ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
+        2, this->learned_net(), target);
+  }
+
+  // repeated .caffe.BlobProto history = 3;
+  for (unsigned int i = 0, n = this->history_size(); i < n; i++) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        3, this->history(i), false, target);
+  }
+
+  // optional int32 current_step = 4 [default = 0];
+  if (has_current_step()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteInt32ToArray(4, this->current_step(), target);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
+        unknown_fields(), target);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:caffe.SolverState)
+  return target;
+}
+
+size_t SolverState::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:caffe.SolverState)
+  size_t total_size = 0;
+
+  if (_has_bits_[0 / 32] & 11u) {
+    // optional int32 iter = 1;
+    if (has_iter()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::Int32Size(
+          this->iter());
+    }
+
+    // optional string learned_net = 2;
+    if (has_learned_net()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::StringSize(
+          this->learned_net());
+    }
+
+    // optional int32 current_step = 4 [default = 0];
+    if (has_current_step()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::Int32Size(
+          this->current_step());
+    }
+
+  }
+  // repeated .caffe.BlobProto history = 3;
+  {
+    unsigned int count = this->history_size();
+    total_size += 1UL * count;
+    for (unsigned int i = 0; i < count; i++) {
+      total_size +=
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          this->history(i));
+    }
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    total_size +=
+      ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
+        unknown_fields());
+  }
+  int cached_size = ::google::protobuf::internal::ToCachedSize(total_size);
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = cached_size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+  return total_size;
+}
+
+void SolverState::MergeFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_merge_from_start:caffe.SolverState)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const SolverState* source =
+      ::google::protobuf::internal::DynamicCastToGenerated<const SolverState>(
+          &from);
+  if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:caffe.SolverState)
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:caffe.SolverState)
+    UnsafeMergeFrom(*source);
+  }
+}
+
+void SolverState::MergeFrom(const SolverState& from) {
+// @@protoc_insertion_point(class_specific_merge_from_start:caffe.SolverState)
+  if (GOOGLE_PREDICT_TRUE(&from != this)) {
+    UnsafeMergeFrom(from);
+  } else {
+    MergeFromFail(__LINE__);
+  }
+}
+
+void SolverState::UnsafeMergeFrom(const SolverState& from) {
+  GOOGLE_DCHECK(&from != this);
+  history_.MergeFrom(from.history_);
+  if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+    if (from.has_iter()) {
+      set_iter(from.iter());
+    }
+    if (from.has_learned_net()) {
+      set_has_learned_net();
+      learned_net_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.learned_net_);
+    }
+    if (from.has_current_step()) {
+      set_current_step(from.current_step());
+    }
+  }
+  if (from._internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::UnknownFieldSet::MergeToInternalMetdata(
+      from.unknown_fields(), &_internal_metadata_);
+  }
+}
+
+void SolverState::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:caffe.SolverState)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void SolverState::CopyFrom(const SolverState& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:caffe.SolverState)
+  if (&from == this) return;
+  Clear();
+  UnsafeMergeFrom(from);
+}
+
+bool SolverState::IsInitialized() const {
+
+  return true;
+}
+
+void SolverState::Swap(SolverState* other) {
+  if (other == this) return;
+  InternalSwap(other);
+}
+void SolverState::InternalSwap(SolverState* other) {
+  std::swap(iter_, other->iter_);
+  learned_net_.Swap(&other->learned_net_);
+  history_.UnsafeArenaSwap(&other->history_);
+  std::swap(current_step_, other->current_step_);
+  std::swap(_has_bits_[0], other->_has_bits_[0]);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
+}
+
+::google::protobuf::Metadata SolverState::GetMetadata() const {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::Metadata metadata;
+  metadata.descriptor = SolverState_descriptor_;
+  metadata.reflection = SolverState_reflection_;
+  return metadata;
+}
+
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// SolverState
+
+// optional int32 iter = 1;
+bool SolverState::has_iter() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+void SolverState::set_has_iter() {
+  _has_bits_[0] |= 0x00000001u;
+}
+void SolverState::clear_has_iter() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+void SolverState::clear_iter() {
+  iter_ = 0;
+  clear_has_iter();
+}
+::google::protobuf::int32 SolverState::iter() const {
+  // @@protoc_insertion_point(field_get:caffe.SolverState.iter)
+  return iter_;
+}
+void SolverState::set_iter(::google::protobuf::int32 value) {
+  set_has_iter();
+  iter_ = value;
+  // @@protoc_insertion_point(field_set:caffe.SolverState.iter)
+}
+
+// optional string learned_net = 2;
+bool SolverState::has_learned_net() const {
+  return (_has_bits_[0] & 0x00000002u) != 0;
+}
+void SolverState::set_has_learned_net() {
+  _has_bits_[0] |= 0x00000002u;
+}
+void SolverState::clear_has_learned_net() {
+  _has_bits_[0] &= ~0x00000002u;
+}
+void SolverState::clear_learned_net() {
+  learned_net_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  clear_has_learned_net();
+}
+const ::std::string& SolverState::learned_net() const {
+  // @@protoc_insertion_point(field_get:caffe.SolverState.learned_net)
+  return learned_net_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+void SolverState::set_learned_net(const ::std::string& value) {
+  set_has_learned_net();
+  learned_net_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:caffe.SolverState.learned_net)
+}
+void SolverState::set_learned_net(const char* value) {
+  set_has_learned_net();
+  learned_net_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:caffe.SolverState.learned_net)
+}
+void SolverState::set_learned_net(const char* value, size_t size) {
+  set_has_learned_net();
+  learned_net_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:caffe.SolverState.learned_net)
+}
+::std::string* SolverState::mutable_learned_net() {
+  set_has_learned_net();
+  // @@protoc_insertion_point(field_mutable:caffe.SolverState.learned_net)
+  return learned_net_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+::std::string* SolverState::release_learned_net() {
+  // @@protoc_insertion_point(field_release:caffe.SolverState.learned_net)
+  clear_has_learned_net();
+  return learned_net_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+void SolverState::set_allocated_learned_net(::std::string* learned_net) {
+  if (learned_net != NULL) {
+    set_has_learned_net();
+  } else {
+    clear_has_learned_net();
+  }
+  learned_net_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), learned_net);
+  // @@protoc_insertion_point(field_set_allocated:caffe.SolverState.learned_net)
+}
+
+// repeated .caffe.BlobProto history = 3;
+int SolverState::history_size() const {
+  return history_.size();
+}
+void SolverState::clear_history() {
+  history_.Clear();
+}
+const ::caffe::BlobProto& SolverState::history(int index) const {
+  // @@protoc_insertion_point(field_get:caffe.SolverState.history)
+  return history_.Get(index);
+}
+::caffe::BlobProto* SolverState::mutable_history(int index) {
+  // @@protoc_insertion_point(field_mutable:caffe.SolverState.history)
+  return history_.Mutable(index);
+}
+::caffe::BlobProto* SolverState::add_history() {
+  // @@protoc_insertion_point(field_add:caffe.SolverState.history)
+  return history_.Add();
+}
+::google::protobuf::RepeatedPtrField< ::caffe::BlobProto >*
+SolverState::mutable_history() {
+  // @@protoc_insertion_point(field_mutable_list:caffe.SolverState.history)
+  return &history_;
+}
+const ::google::protobuf::RepeatedPtrField< ::caffe::BlobProto >&
+SolverState::history() const {
+  // @@protoc_insertion_point(field_list:caffe.SolverState.history)
+  return history_;
+}
+
+// optional int32 current_step = 4 [default = 0];
+bool SolverState::has_current_step() const {
+  return (_has_bits_[0] & 0x00000008u) != 0;
+}
+void SolverState::set_has_current_step() {
+  _has_bits_[0] |= 0x00000008u;
+}
+void SolverState::clear_has_current_step() {
+  _has_bits_[0] &= ~0x00000008u;
+}
+void SolverState::clear_current_step() {
+  current_step_ = 0;
+  clear_has_current_step();
+}
+::google::protobuf::int32 SolverState::current_step() const {
+  // @@protoc_insertion_point(field_get:caffe.SolverState.current_step)
+  return current_step_;
+}
+void SolverState::set_current_step(::google::protobuf::int32 value) {
+  set_has_current_step();
+  current_step_ = value;
+  // @@protoc_insertion_point(field_set:caffe.SolverState.current_step)
+}
+
+inline const SolverState* SolverState::internal_default_instance() {
+  return &SolverState_default_instance_.get();
+}
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
+
+// ===================================================================
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const int NetState::kPhaseFieldNumber;
+const int NetState::kLevelFieldNumber;
+const int NetState::kStageFieldNumber;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+
+NetState::NetState()
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+  if (this != internal_default_instance()) protobuf_InitDefaults_caffe_2eproto();
+  SharedCtor();
+  // @@protoc_insertion_point(constructor:caffe.NetState)
+}
+
+void NetState::InitAsDefaultInstance() {
+}
+
+NetState::NetState(const NetState& from)
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
+  SharedCtor();
+  UnsafeMergeFrom(from);
+  // @@protoc_insertion_point(copy_constructor:caffe.NetState)
+}
+
+void NetState::SharedCtor() {
+  _cached_size_ = 0;
+  level_ = 0;
+  phase_ = 1;
+}
+
+NetState::~NetState() {
+  // @@protoc_insertion_point(destructor:caffe.NetState)
+  SharedDtor();
+}
+
+void NetState::SharedDtor() {
+}
+
+void NetState::SetCachedSize(int size) const {
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* NetState::descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return NetState_descriptor_;
+}
+
+const NetState& NetState::default_instance() {
+  protobuf_InitDefaults_caffe_2eproto();
+  return *internal_default_instance();
+}
+
+::google::protobuf::internal::ExplicitlyConstructed<NetState> NetState_default_instance_;
+
+NetState* NetState::New(::google::protobuf::Arena* arena) const {
+  NetState* n = new NetState;
+  if (arena != NULL) {
+    arena->Own(n);
+  }
+  return n;
+}
+
+void NetState::Clear() {
+// @@protoc_insertion_point(message_clear_start:caffe.NetState)
+  if (_has_bits_[0 / 32] & 3u) {
+    phase_ = 1;
+    level_ = 0;
+  }
+  stage_.Clear();
+  _has_bits_.Clear();
+  if (_internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->Clear();
+  }
+}
+
+bool NetState::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
+  ::google::protobuf::uint32 tag;
+  // @@protoc_insertion_point(parse_start:caffe.NetState)
+  for (;;) {
+    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+    tag = p.first;
+    if (!p.second) goto handle_unusual;
+    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+      // optional .caffe.Phase phase = 1 [default = TEST];
+      case 1: {
+        if (tag == 8) {
+          int value;
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>(
+                 input, &value)));
+          if (::caffe::Phase_IsValid(value)) {
+            set_phase(static_cast< ::caffe::Phase >(value));
+          } else {
+            mutable_unknown_fields()->AddVarint(1, value);
+          }
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(16)) goto parse_level;
+        break;
+      }
+
+      // optional int32 level = 2 [default = 0];
+      case 2: {
+        if (tag == 16) {
+         parse_level:
+          set_has_level();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
+                 input, &level_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(26)) goto parse_stage;
+        break;
+      }
+
+      // repeated string stage = 3;
+      case 3: {
+        if (tag == 26) {
+         parse_stage:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+                input, this->add_stage()));
+          ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+            this->stage(this->stage_size() - 1).data(),
+            this->stage(this->stage_size() - 1).length(),
+            ::google::protobuf::internal::WireFormat::PARSE,
+            "caffe.NetState.stage");
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(26)) goto parse_stage;
+        if (input->ExpectAtEnd()) goto success;
+        break;
+      }
+
+      default: {
+      handle_unusual:
+        if (tag == 0 ||
+            ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+          goto success;
+        }
+        DO_(::google::protobuf::internal::WireFormat::SkipField(
+              input, tag, mutable_unknown_fields()));
+        break;
+      }
+    }
+  }
+success:
+  // @@protoc_insertion_point(parse_success:caffe.NetState)
+  return true;
+failure:
+  // @@protoc_insertion_point(parse_failure:caffe.NetState)
+  return false;
+#undef DO_
+}
+
+void NetState::SerializeWithCachedSizes(
+    ::google::protobuf::io::CodedOutputStream* output) const {
+  // @@protoc_insertion_point(serialize_start:caffe.NetState)
+  // optional .caffe.Phase phase = 1 [default = TEST];
+  if (has_phase()) {
+    ::google::protobuf::internal::WireFormatLite::WriteEnum(
+      1, this->phase(), output);
+  }
+
+  // optional int32 level = 2 [default = 0];
+  if (has_level()) {
+    ::google::protobuf::internal::WireFormatLite::WriteInt32(2, this->level(), output);
+  }
+
+  // repeated string stage = 3;
+  for (int i = 0; i < this->stage_size(); i++) {
+    ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->stage(i).data(), this->stage(i).length(),
+      ::google::protobuf::internal::WireFormat::SERIALIZE,
+      "caffe.NetState.stage");
+    ::google::protobuf::internal::WireFormatLite::WriteString(
+      3, this->stage(i), output);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
+        unknown_fields(), output);
+  }
+  // @@protoc_insertion_point(serialize_end:caffe.NetState)
+}
+
+::google::protobuf::uint8* NetState::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
+  (void)deterministic; // Unused
+  // @@protoc_insertion_point(serialize_to_array_start:caffe.NetState)
+  // optional .caffe.Phase phase = 1 [default = TEST];
+  if (has_phase()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteEnumToArray(
+      1, this->phase(), target);
+  }
+
+  // optional int32 level = 2 [default = 0];
+  if (has_level()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteInt32ToArray(2, this->level(), target);
+  }
+
+  // repeated string stage = 3;
+  for (int i = 0; i < this->stage_size(); i++) {
+    ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->stage(i).data(), this->stage(i).length(),
+      ::google::protobuf::internal::WireFormat::SERIALIZE,
+      "caffe.NetState.stage");
+    target = ::google::protobuf::internal::WireFormatLite::
+      WriteStringToArray(3, this->stage(i), target);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
+        unknown_fields(), target);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:caffe.NetState)
+  return target;
+}
+
+size_t NetState::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:caffe.NetState)
+  size_t total_size = 0;
+
+  if (_has_bits_[0 / 32] & 3u) {
+    // optional .caffe.Phase phase = 1 [default = TEST];
+    if (has_phase()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::EnumSize(this->phase());
+    }
+
+    // optional int32 level = 2 [default = 0];
+    if (has_level()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::Int32Size(
+          this->level());
+    }
+
+  }
+  // repeated string stage = 3;
+  total_size += 1 *
+      ::google::protobuf::internal::FromIntSize(this->stage_size());
+  for (int i = 0; i < this->stage_size(); i++) {
+    total_size += ::google::protobuf::internal::WireFormatLite::StringSize(
+      this->stage(i));
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    total_size +=
+      ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
+        unknown_fields());
+  }
+  int cached_size = ::google::protobuf::internal::ToCachedSize(total_size);
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = cached_size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+  return total_size;
+}
+
+void NetState::MergeFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_merge_from_start:caffe.NetState)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const NetState* source =
+      ::google::protobuf::internal::DynamicCastToGenerated<const NetState>(
+          &from);
+  if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:caffe.NetState)
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:caffe.NetState)
+    UnsafeMergeFrom(*source);
+  }
+}
+
+void NetState::MergeFrom(const NetState& from) {
+// @@protoc_insertion_point(class_specific_merge_from_start:caffe.NetState)
+  if (GOOGLE_PREDICT_TRUE(&from != this)) {
+    UnsafeMergeFrom(from);
+  } else {
+    MergeFromFail(__LINE__);
+  }
+}
+
+void NetState::UnsafeMergeFrom(const NetState& from) {
+  GOOGLE_DCHECK(&from != this);
+  stage_.UnsafeMergeFrom(from.stage_);
+  if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+    if (from.has_phase()) {
+      set_phase(from.phase());
+    }
+    if (from.has_level()) {
+      set_level(from.level());
+    }
+  }
+  if (from._internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::UnknownFieldSet::MergeToInternalMetdata(
+      from.unknown_fields(), &_internal_metadata_);
+  }
+}
+
+void NetState::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:caffe.NetState)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void NetState::CopyFrom(const NetState& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:caffe.NetState)
+  if (&from == this) return;
+  Clear();
+  UnsafeMergeFrom(from);
+}
+
+bool NetState::IsInitialized() const {
+
+  return true;
+}
+
+void NetState::Swap(NetState* other) {
+  if (other == this) return;
+  InternalSwap(other);
+}
+void NetState::InternalSwap(NetState* other) {
+  std::swap(phase_, other->phase_);
+  std::swap(level_, other->level_);
+  stage_.UnsafeArenaSwap(&other->stage_);
+  std::swap(_has_bits_[0], other->_has_bits_[0]);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
+}
+
+::google::protobuf::Metadata NetState::GetMetadata() const {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::Metadata metadata;
+  metadata.descriptor = NetState_descriptor_;
+  metadata.reflection = NetState_reflection_;
+  return metadata;
+}
+
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// NetState
+
+// optional .caffe.Phase phase = 1 [default = TEST];
+bool NetState::has_phase() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+void NetState::set_has_phase() {
+  _has_bits_[0] |= 0x00000001u;
+}
+void NetState::clear_has_phase() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+void NetState::clear_phase() {
+  phase_ = 1;
+  clear_has_phase();
+}
+::caffe::Phase NetState::phase() const {
+  // @@protoc_insertion_point(field_get:caffe.NetState.phase)
+  return static_cast< ::caffe::Phase >(phase_);
+}
+void NetState::set_phase(::caffe::Phase value) {
+  assert(::caffe::Phase_IsValid(value));
+  set_has_phase();
+  phase_ = value;
+  // @@protoc_insertion_point(field_set:caffe.NetState.phase)
+}
+
+// optional int32 level = 2 [default = 0];
+bool NetState::has_level() const {
+  return (_has_bits_[0] & 0x00000002u) != 0;
+}
+void NetState::set_has_level() {
+  _has_bits_[0] |= 0x00000002u;
+}
+void NetState::clear_has_level() {
+  _has_bits_[0] &= ~0x00000002u;
+}
+void NetState::clear_level() {
+  level_ = 0;
+  clear_has_level();
+}
+::google::protobuf::int32 NetState::level() const {
+  // @@protoc_insertion_point(field_get:caffe.NetState.level)
+  return level_;
+}
+void NetState::set_level(::google::protobuf::int32 value) {
+  set_has_level();
+  level_ = value;
+  // @@protoc_insertion_point(field_set:caffe.NetState.level)
+}
+
+// repeated string stage = 3;
+int NetState::stage_size() const {
+  return stage_.size();
+}
+void NetState::clear_stage() {
+  stage_.Clear();
+}
+const ::std::string& NetState::stage(int index) const {
+  // @@protoc_insertion_point(field_get:caffe.NetState.stage)
+  return stage_.Get(index);
+}
+::std::string* NetState::mutable_stage(int index) {
+  // @@protoc_insertion_point(field_mutable:caffe.NetState.stage)
+  return stage_.Mutable(index);
+}
+void NetState::set_stage(int index, const ::std::string& value) {
+  // @@protoc_insertion_point(field_set:caffe.NetState.stage)
+  stage_.Mutable(index)->assign(value);
+}
+void NetState::set_stage(int index, const char* value) {
+  stage_.Mutable(index)->assign(value);
+  // @@protoc_insertion_point(field_set_char:caffe.NetState.stage)
+}
+void NetState::set_stage(int index, const char* value, size_t size) {
+  stage_.Mutable(index)->assign(
+    reinterpret_cast<const char*>(value), size);
+  // @@protoc_insertion_point(field_set_pointer:caffe.NetState.stage)
+}
+::std::string* NetState::add_stage() {
+  // @@protoc_insertion_point(field_add_mutable:caffe.NetState.stage)
+  return stage_.Add();
+}
+void NetState::add_stage(const ::std::string& value) {
+  stage_.Add()->assign(value);
+  // @@protoc_insertion_point(field_add:caffe.NetState.stage)
+}
+void NetState::add_stage(const char* value) {
+  stage_.Add()->assign(value);
+  // @@protoc_insertion_point(field_add_char:caffe.NetState.stage)
+}
+void NetState::add_stage(const char* value, size_t size) {
+  stage_.Add()->assign(reinterpret_cast<const char*>(value), size);
+  // @@protoc_insertion_point(field_add_pointer:caffe.NetState.stage)
+}
+const ::google::protobuf::RepeatedPtrField< ::std::string>&
+NetState::stage() const {
+  // @@protoc_insertion_point(field_list:caffe.NetState.stage)
+  return stage_;
+}
+::google::protobuf::RepeatedPtrField< ::std::string>*
+NetState::mutable_stage() {
+  // @@protoc_insertion_point(field_mutable_list:caffe.NetState.stage)
+  return &stage_;
+}
+
+inline const NetState* NetState::internal_default_instance() {
+  return &NetState_default_instance_.get();
+}
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
+
+// ===================================================================
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const int NetStateRule::kPhaseFieldNumber;
+const int NetStateRule::kMinLevelFieldNumber;
+const int NetStateRule::kMaxLevelFieldNumber;
+const int NetStateRule::kStageFieldNumber;
+const int NetStateRule::kNotStageFieldNumber;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+
+NetStateRule::NetStateRule()
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+  if (this != internal_default_instance()) protobuf_InitDefaults_caffe_2eproto();
+  SharedCtor();
+  // @@protoc_insertion_point(constructor:caffe.NetStateRule)
+}
+
+void NetStateRule::InitAsDefaultInstance() {
+}
+
+NetStateRule::NetStateRule(const NetStateRule& from)
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
+  SharedCtor();
+  UnsafeMergeFrom(from);
+  // @@protoc_insertion_point(copy_constructor:caffe.NetStateRule)
+}
+
+void NetStateRule::SharedCtor() {
+  _cached_size_ = 0;
+  ::memset(&phase_, 0, reinterpret_cast<char*>(&max_level_) -
+    reinterpret_cast<char*>(&phase_) + sizeof(max_level_));
+}
+
+NetStateRule::~NetStateRule() {
+  // @@protoc_insertion_point(destructor:caffe.NetStateRule)
+  SharedDtor();
+}
+
+void NetStateRule::SharedDtor() {
+}
+
+void NetStateRule::SetCachedSize(int size) const {
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* NetStateRule::descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return NetStateRule_descriptor_;
+}
+
+const NetStateRule& NetStateRule::default_instance() {
+  protobuf_InitDefaults_caffe_2eproto();
+  return *internal_default_instance();
+}
+
+::google::protobuf::internal::ExplicitlyConstructed<NetStateRule> NetStateRule_default_instance_;
+
+NetStateRule* NetStateRule::New(::google::protobuf::Arena* arena) const {
+  NetStateRule* n = new NetStateRule;
+  if (arena != NULL) {
+    arena->Own(n);
+  }
+  return n;
+}
+
+void NetStateRule::Clear() {
+// @@protoc_insertion_point(message_clear_start:caffe.NetStateRule)
+#if defined(__clang__)
+#define ZR_HELPER_(f) \
+  _Pragma("clang diagnostic push") \
+  _Pragma("clang diagnostic ignored \"-Winvalid-offsetof\"") \
+  __builtin_offsetof(NetStateRule, f) \
+  _Pragma("clang diagnostic pop")
+#else
+#define ZR_HELPER_(f) reinterpret_cast<char*>(\
+  &reinterpret_cast<NetStateRule*>(16)->f)
+#endif
+
+#define ZR_(first, last) do {\
+  ::memset(&(first), 0,\
+           ZR_HELPER_(last) - ZR_HELPER_(first) + sizeof(last));\
+} while (0)
+
+  ZR_(phase_, max_level_);
+
+#undef ZR_HELPER_
+#undef ZR_
+
+  stage_.Clear();
+  not_stage_.Clear();
+  _has_bits_.Clear();
+  if (_internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->Clear();
+  }
+}
+
+bool NetStateRule::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
+  ::google::protobuf::uint32 tag;
+  // @@protoc_insertion_point(parse_start:caffe.NetStateRule)
+  for (;;) {
+    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+    tag = p.first;
+    if (!p.second) goto handle_unusual;
+    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+      // optional .caffe.Phase phase = 1;
+      case 1: {
+        if (tag == 8) {
+          int value;
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>(
+                 input, &value)));
+          if (::caffe::Phase_IsValid(value)) {
+            set_phase(static_cast< ::caffe::Phase >(value));
+          } else {
+            mutable_unknown_fields()->AddVarint(1, value);
+          }
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(16)) goto parse_min_level;
+        break;
+      }
+
+      // optional int32 min_level = 2;
+      case 2: {
+        if (tag == 16) {
+         parse_min_level:
+          set_has_min_level();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
+                 input, &min_level_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(24)) goto parse_max_level;
+        break;
+      }
+
+      // optional int32 max_level = 3;
+      case 3: {
+        if (tag == 24) {
+         parse_max_level:
+          set_has_max_level();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
+                 input, &max_level_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(34)) goto parse_stage;
+        break;
+      }
+
+      // repeated string stage = 4;
+      case 4: {
+        if (tag == 34) {
+         parse_stage:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+                input, this->add_stage()));
+          ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+            this->stage(this->stage_size() - 1).data(),
+            this->stage(this->stage_size() - 1).length(),
+            ::google::protobuf::internal::WireFormat::PARSE,
+            "caffe.NetStateRule.stage");
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(34)) goto parse_stage;
+        if (input->ExpectTag(42)) goto parse_not_stage;
+        break;
+      }
+
+      // repeated string not_stage = 5;
+      case 5: {
+        if (tag == 42) {
+         parse_not_stage:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+                input, this->add_not_stage()));
+          ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+            this->not_stage(this->not_stage_size() - 1).data(),
+            this->not_stage(this->not_stage_size() - 1).length(),
+            ::google::protobuf::internal::WireFormat::PARSE,
+            "caffe.NetStateRule.not_stage");
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(42)) goto parse_not_stage;
+        if (input->ExpectAtEnd()) goto success;
+        break;
+      }
+
+      default: {
+      handle_unusual:
+        if (tag == 0 ||
+            ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+          goto success;
+        }
+        DO_(::google::protobuf::internal::WireFormat::SkipField(
+              input, tag, mutable_unknown_fields()));
+        break;
+      }
+    }
+  }
+success:
+  // @@protoc_insertion_point(parse_success:caffe.NetStateRule)
+  return true;
+failure:
+  // @@protoc_insertion_point(parse_failure:caffe.NetStateRule)
+  return false;
+#undef DO_
+}
+
+void NetStateRule::SerializeWithCachedSizes(
+    ::google::protobuf::io::CodedOutputStream* output) const {
+  // @@protoc_insertion_point(serialize_start:caffe.NetStateRule)
+  // optional .caffe.Phase phase = 1;
+  if (has_phase()) {
+    ::google::protobuf::internal::WireFormatLite::WriteEnum(
+      1, this->phase(), output);
+  }
+
+  // optional int32 min_level = 2;
+  if (has_min_level()) {
+    ::google::protobuf::internal::WireFormatLite::WriteInt32(2, this->min_level(), output);
+  }
+
+  // optional int32 max_level = 3;
+  if (has_max_level()) {
+    ::google::protobuf::internal::WireFormatLite::WriteInt32(3, this->max_level(), output);
+  }
+
+  // repeated string stage = 4;
+  for (int i = 0; i < this->stage_size(); i++) {
+    ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->stage(i).data(), this->stage(i).length(),
+      ::google::protobuf::internal::WireFormat::SERIALIZE,
+      "caffe.NetStateRule.stage");
+    ::google::protobuf::internal::WireFormatLite::WriteString(
+      4, this->stage(i), output);
+  }
+
+  // repeated string not_stage = 5;
+  for (int i = 0; i < this->not_stage_size(); i++) {
+    ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->not_stage(i).data(), this->not_stage(i).length(),
+      ::google::protobuf::internal::WireFormat::SERIALIZE,
+      "caffe.NetStateRule.not_stage");
+    ::google::protobuf::internal::WireFormatLite::WriteString(
+      5, this->not_stage(i), output);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
+        unknown_fields(), output);
+  }
+  // @@protoc_insertion_point(serialize_end:caffe.NetStateRule)
+}
+
+::google::protobuf::uint8* NetStateRule::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
+  (void)deterministic; // Unused
+  // @@protoc_insertion_point(serialize_to_array_start:caffe.NetStateRule)
+  // optional .caffe.Phase phase = 1;
+  if (has_phase()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteEnumToArray(
+      1, this->phase(), target);
+  }
+
+  // optional int32 min_level = 2;
+  if (has_min_level()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteInt32ToArray(2, this->min_level(), target);
+  }
+
+  // optional int32 max_level = 3;
+  if (has_max_level()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteInt32ToArray(3, this->max_level(), target);
+  }
+
+  // repeated string stage = 4;
+  for (int i = 0; i < this->stage_size(); i++) {
+    ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->stage(i).data(), this->stage(i).length(),
+      ::google::protobuf::internal::WireFormat::SERIALIZE,
+      "caffe.NetStateRule.stage");
+    target = ::google::protobuf::internal::WireFormatLite::
+      WriteStringToArray(4, this->stage(i), target);
+  }
+
+  // repeated string not_stage = 5;
+  for (int i = 0; i < this->not_stage_size(); i++) {
+    ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->not_stage(i).data(), this->not_stage(i).length(),
+      ::google::protobuf::internal::WireFormat::SERIALIZE,
+      "caffe.NetStateRule.not_stage");
+    target = ::google::protobuf::internal::WireFormatLite::
+      WriteStringToArray(5, this->not_stage(i), target);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
+        unknown_fields(), target);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:caffe.NetStateRule)
+  return target;
+}
+
+size_t NetStateRule::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:caffe.NetStateRule)
+  size_t total_size = 0;
+
+  if (_has_bits_[0 / 32] & 7u) {
+    // optional .caffe.Phase phase = 1;
+    if (has_phase()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::EnumSize(this->phase());
+    }
+
+    // optional int32 min_level = 2;
+    if (has_min_level()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::Int32Size(
+          this->min_level());
+    }
+
+    // optional int32 max_level = 3;
+    if (has_max_level()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::Int32Size(
+          this->max_level());
+    }
+
+  }
+  // repeated string stage = 4;
+  total_size += 1 *
+      ::google::protobuf::internal::FromIntSize(this->stage_size());
+  for (int i = 0; i < this->stage_size(); i++) {
+    total_size += ::google::protobuf::internal::WireFormatLite::StringSize(
+      this->stage(i));
+  }
+
+  // repeated string not_stage = 5;
+  total_size += 1 *
+      ::google::protobuf::internal::FromIntSize(this->not_stage_size());
+  for (int i = 0; i < this->not_stage_size(); i++) {
+    total_size += ::google::protobuf::internal::WireFormatLite::StringSize(
+      this->not_stage(i));
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    total_size +=
+      ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
+        unknown_fields());
+  }
+  int cached_size = ::google::protobuf::internal::ToCachedSize(total_size);
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = cached_size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+  return total_size;
+}
+
+void NetStateRule::MergeFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_merge_from_start:caffe.NetStateRule)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const NetStateRule* source =
+      ::google::protobuf::internal::DynamicCastToGenerated<const NetStateRule>(
+          &from);
+  if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:caffe.NetStateRule)
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:caffe.NetStateRule)
+    UnsafeMergeFrom(*source);
+  }
+}
+
+void NetStateRule::MergeFrom(const NetStateRule& from) {
+// @@protoc_insertion_point(class_specific_merge_from_start:caffe.NetStateRule)
+  if (GOOGLE_PREDICT_TRUE(&from != this)) {
+    UnsafeMergeFrom(from);
+  } else {
+    MergeFromFail(__LINE__);
+  }
+}
+
+void NetStateRule::UnsafeMergeFrom(const NetStateRule& from) {
+  GOOGLE_DCHECK(&from != this);
+  stage_.UnsafeMergeFrom(from.stage_);
+  not_stage_.UnsafeMergeFrom(from.not_stage_);
+  if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+    if (from.has_phase()) {
+      set_phase(from.phase());
+    }
+    if (from.has_min_level()) {
+      set_min_level(from.min_level());
+    }
+    if (from.has_max_level()) {
+      set_max_level(from.max_level());
+    }
+  }
+  if (from._internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::UnknownFieldSet::MergeToInternalMetdata(
+      from.unknown_fields(), &_internal_metadata_);
+  }
+}
+
+void NetStateRule::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:caffe.NetStateRule)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void NetStateRule::CopyFrom(const NetStateRule& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:caffe.NetStateRule)
+  if (&from == this) return;
+  Clear();
+  UnsafeMergeFrom(from);
+}
+
+bool NetStateRule::IsInitialized() const {
+
+  return true;
+}
+
+void NetStateRule::Swap(NetStateRule* other) {
+  if (other == this) return;
+  InternalSwap(other);
+}
+void NetStateRule::InternalSwap(NetStateRule* other) {
+  std::swap(phase_, other->phase_);
+  std::swap(min_level_, other->min_level_);
+  std::swap(max_level_, other->max_level_);
+  stage_.UnsafeArenaSwap(&other->stage_);
+  not_stage_.UnsafeArenaSwap(&other->not_stage_);
+  std::swap(_has_bits_[0], other->_has_bits_[0]);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
+}
+
+::google::protobuf::Metadata NetStateRule::GetMetadata() const {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::Metadata metadata;
+  metadata.descriptor = NetStateRule_descriptor_;
+  metadata.reflection = NetStateRule_reflection_;
+  return metadata;
+}
+
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// NetStateRule
+
+// optional .caffe.Phase phase = 1;
+bool NetStateRule::has_phase() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+void NetStateRule::set_has_phase() {
+  _has_bits_[0] |= 0x00000001u;
+}
+void NetStateRule::clear_has_phase() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+void NetStateRule::clear_phase() {
+  phase_ = 0;
+  clear_has_phase();
+}
+::caffe::Phase NetStateRule::phase() const {
+  // @@protoc_insertion_point(field_get:caffe.NetStateRule.phase)
+  return static_cast< ::caffe::Phase >(phase_);
+}
+void NetStateRule::set_phase(::caffe::Phase value) {
+  assert(::caffe::Phase_IsValid(value));
+  set_has_phase();
+  phase_ = value;
+  // @@protoc_insertion_point(field_set:caffe.NetStateRule.phase)
+}
+
+// optional int32 min_level = 2;
+bool NetStateRule::has_min_level() const {
+  return (_has_bits_[0] & 0x00000002u) != 0;
+}
+void NetStateRule::set_has_min_level() {
+  _has_bits_[0] |= 0x00000002u;
+}
+void NetStateRule::clear_has_min_level() {
+  _has_bits_[0] &= ~0x00000002u;
+}
+void NetStateRule::clear_min_level() {
+  min_level_ = 0;
+  clear_has_min_level();
+}
+::google::protobuf::int32 NetStateRule::min_level() const {
+  // @@protoc_insertion_point(field_get:caffe.NetStateRule.min_level)
+  return min_level_;
+}
+void NetStateRule::set_min_level(::google::protobuf::int32 value) {
+  set_has_min_level();
+  min_level_ = value;
+  // @@protoc_insertion_point(field_set:caffe.NetStateRule.min_level)
+}
+
+// optional int32 max_level = 3;
+bool NetStateRule::has_max_level() const {
+  return (_has_bits_[0] & 0x00000004u) != 0;
+}
+void NetStateRule::set_has_max_level() {
+  _has_bits_[0] |= 0x00000004u;
+}
+void NetStateRule::clear_has_max_level() {
+  _has_bits_[0] &= ~0x00000004u;
+}
+void NetStateRule::clear_max_level() {
+  max_level_ = 0;
+  clear_has_max_level();
+}
+::google::protobuf::int32 NetStateRule::max_level() const {
+  // @@protoc_insertion_point(field_get:caffe.NetStateRule.max_level)
+  return max_level_;
+}
+void NetStateRule::set_max_level(::google::protobuf::int32 value) {
+  set_has_max_level();
+  max_level_ = value;
+  // @@protoc_insertion_point(field_set:caffe.NetStateRule.max_level)
+}
+
+// repeated string stage = 4;
+int NetStateRule::stage_size() const {
+  return stage_.size();
+}
+void NetStateRule::clear_stage() {
+  stage_.Clear();
+}
+const ::std::string& NetStateRule::stage(int index) const {
+  // @@protoc_insertion_point(field_get:caffe.NetStateRule.stage)
+  return stage_.Get(index);
+}
+::std::string* NetStateRule::mutable_stage(int index) {
+  // @@protoc_insertion_point(field_mutable:caffe.NetStateRule.stage)
+  return stage_.Mutable(index);
+}
+void NetStateRule::set_stage(int index, const ::std::string& value) {
+  // @@protoc_insertion_point(field_set:caffe.NetStateRule.stage)
+  stage_.Mutable(index)->assign(value);
+}
+void NetStateRule::set_stage(int index, const char* value) {
+  stage_.Mutable(index)->assign(value);
+  // @@protoc_insertion_point(field_set_char:caffe.NetStateRule.stage)
+}
+void NetStateRule::set_stage(int index, const char* value, size_t size) {
+  stage_.Mutable(index)->assign(
+    reinterpret_cast<const char*>(value), size);
+  // @@protoc_insertion_point(field_set_pointer:caffe.NetStateRule.stage)
+}
+::std::string* NetStateRule::add_stage() {
+  // @@protoc_insertion_point(field_add_mutable:caffe.NetStateRule.stage)
+  return stage_.Add();
+}
+void NetStateRule::add_stage(const ::std::string& value) {
+  stage_.Add()->assign(value);
+  // @@protoc_insertion_point(field_add:caffe.NetStateRule.stage)
+}
+void NetStateRule::add_stage(const char* value) {
+  stage_.Add()->assign(value);
+  // @@protoc_insertion_point(field_add_char:caffe.NetStateRule.stage)
+}
+void NetStateRule::add_stage(const char* value, size_t size) {
+  stage_.Add()->assign(reinterpret_cast<const char*>(value), size);
+  // @@protoc_insertion_point(field_add_pointer:caffe.NetStateRule.stage)
+}
+const ::google::protobuf::RepeatedPtrField< ::std::string>&
+NetStateRule::stage() const {
+  // @@protoc_insertion_point(field_list:caffe.NetStateRule.stage)
+  return stage_;
+}
+::google::protobuf::RepeatedPtrField< ::std::string>*
+NetStateRule::mutable_stage() {
+  // @@protoc_insertion_point(field_mutable_list:caffe.NetStateRule.stage)
+  return &stage_;
+}
+
+// repeated string not_stage = 5;
+int NetStateRule::not_stage_size() const {
+  return not_stage_.size();
+}
+void NetStateRule::clear_not_stage() {
+  not_stage_.Clear();
+}
+const ::std::string& NetStateRule::not_stage(int index) const {
+  // @@protoc_insertion_point(field_get:caffe.NetStateRule.not_stage)
+  return not_stage_.Get(index);
+}
+::std::string* NetStateRule::mutable_not_stage(int index) {
+  // @@protoc_insertion_point(field_mutable:caffe.NetStateRule.not_stage)
+  return not_stage_.Mutable(index);
+}
+void NetStateRule::set_not_stage(int index, const ::std::string& value) {
+  // @@protoc_insertion_point(field_set:caffe.NetStateRule.not_stage)
+  not_stage_.Mutable(index)->assign(value);
+}
+void NetStateRule::set_not_stage(int index, const char* value) {
+  not_stage_.Mutable(index)->assign(value);
+  // @@protoc_insertion_point(field_set_char:caffe.NetStateRule.not_stage)
+}
+void NetStateRule::set_not_stage(int index, const char* value, size_t size) {
+  not_stage_.Mutable(index)->assign(
+    reinterpret_cast<const char*>(value), size);
+  // @@protoc_insertion_point(field_set_pointer:caffe.NetStateRule.not_stage)
+}
+::std::string* NetStateRule::add_not_stage() {
+  // @@protoc_insertion_point(field_add_mutable:caffe.NetStateRule.not_stage)
+  return not_stage_.Add();
+}
+void NetStateRule::add_not_stage(const ::std::string& value) {
+  not_stage_.Add()->assign(value);
+  // @@protoc_insertion_point(field_add:caffe.NetStateRule.not_stage)
+}
+void NetStateRule::add_not_stage(const char* value) {
+  not_stage_.Add()->assign(value);
+  // @@protoc_insertion_point(field_add_char:caffe.NetStateRule.not_stage)
+}
+void NetStateRule::add_not_stage(const char* value, size_t size) {
+  not_stage_.Add()->assign(reinterpret_cast<const char*>(value), size);
+  // @@protoc_insertion_point(field_add_pointer:caffe.NetStateRule.not_stage)
+}
+const ::google::protobuf::RepeatedPtrField< ::std::string>&
+NetStateRule::not_stage() const {
+  // @@protoc_insertion_point(field_list:caffe.NetStateRule.not_stage)
+  return not_stage_;
+}
+::google::protobuf::RepeatedPtrField< ::std::string>*
+NetStateRule::mutable_not_stage() {
+  // @@protoc_insertion_point(field_mutable_list:caffe.NetStateRule.not_stage)
+  return &not_stage_;
+}
+
+inline const NetStateRule* NetStateRule::internal_default_instance() {
+  return &NetStateRule_default_instance_.get();
+}
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
+
+// ===================================================================
+
+const ::google::protobuf::EnumDescriptor* ParamSpec_DimCheckMode_descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return ParamSpec_DimCheckMode_descriptor_;
+}
+bool ParamSpec_DimCheckMode_IsValid(int value) {
+  switch (value) {
+    case 0:
+    case 1:
+      return true;
+    default:
+      return false;
+  }
+}
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const ParamSpec_DimCheckMode ParamSpec::STRICT;
+const ParamSpec_DimCheckMode ParamSpec::PERMISSIVE;
+const ParamSpec_DimCheckMode ParamSpec::DimCheckMode_MIN;
+const ParamSpec_DimCheckMode ParamSpec::DimCheckMode_MAX;
+const int ParamSpec::DimCheckMode_ARRAYSIZE;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const int ParamSpec::kNameFieldNumber;
+const int ParamSpec::kShareModeFieldNumber;
+const int ParamSpec::kLrMultFieldNumber;
+const int ParamSpec::kDecayMultFieldNumber;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+
+ParamSpec::ParamSpec()
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+  if (this != internal_default_instance()) protobuf_InitDefaults_caffe_2eproto();
+  SharedCtor();
+  // @@protoc_insertion_point(constructor:caffe.ParamSpec)
+}
+
+void ParamSpec::InitAsDefaultInstance() {
+}
+
+ParamSpec::ParamSpec(const ParamSpec& from)
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
+  SharedCtor();
+  UnsafeMergeFrom(from);
+  // @@protoc_insertion_point(copy_constructor:caffe.ParamSpec)
+}
+
+void ParamSpec::SharedCtor() {
+  _cached_size_ = 0;
+  name_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  share_mode_ = 0;
+  lr_mult_ = 1;
+  decay_mult_ = 1;
+}
+
+ParamSpec::~ParamSpec() {
+  // @@protoc_insertion_point(destructor:caffe.ParamSpec)
+  SharedDtor();
+}
+
+void ParamSpec::SharedDtor() {
+  name_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+
+void ParamSpec::SetCachedSize(int size) const {
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* ParamSpec::descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return ParamSpec_descriptor_;
+}
+
+const ParamSpec& ParamSpec::default_instance() {
+  protobuf_InitDefaults_caffe_2eproto();
+  return *internal_default_instance();
+}
+
+::google::protobuf::internal::ExplicitlyConstructed<ParamSpec> ParamSpec_default_instance_;
+
+ParamSpec* ParamSpec::New(::google::protobuf::Arena* arena) const {
+  ParamSpec* n = new ParamSpec;
+  if (arena != NULL) {
+    arena->Own(n);
+  }
+  return n;
+}
+
+void ParamSpec::Clear() {
+// @@protoc_insertion_point(message_clear_start:caffe.ParamSpec)
+  if (_has_bits_[0 / 32] & 15u) {
+    if (has_name()) {
+      name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+    }
+    share_mode_ = 0;
+    lr_mult_ = 1;
+    decay_mult_ = 1;
+  }
+  _has_bits_.Clear();
+  if (_internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->Clear();
+  }
+}
+
+bool ParamSpec::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
+  ::google::protobuf::uint32 tag;
+  // @@protoc_insertion_point(parse_start:caffe.ParamSpec)
+  for (;;) {
+    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+    tag = p.first;
+    if (!p.second) goto handle_unusual;
+    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+      // optional string name = 1;
+      case 1: {
+        if (tag == 10) {
+          DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+                input, this->mutable_name()));
+          ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+            this->name().data(), this->name().length(),
+            ::google::protobuf::internal::WireFormat::PARSE,
+            "caffe.ParamSpec.name");
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(16)) goto parse_share_mode;
+        break;
+      }
+
+      // optional .caffe.ParamSpec.DimCheckMode share_mode = 2;
+      case 2: {
+        if (tag == 16) {
+         parse_share_mode:
+          int value;
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>(
+                 input, &value)));
+          if (::caffe::ParamSpec_DimCheckMode_IsValid(value)) {
+            set_share_mode(static_cast< ::caffe::ParamSpec_DimCheckMode >(value));
+          } else {
+            mutable_unknown_fields()->AddVarint(2, value);
+          }
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(29)) goto parse_lr_mult;
+        break;
+      }
+
+      // optional float lr_mult = 3 [default = 1];
+      case 3: {
+        if (tag == 29) {
+         parse_lr_mult:
+          set_has_lr_mult();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
+                 input, &lr_mult_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(37)) goto parse_decay_mult;
+        break;
+      }
+
+      // optional float decay_mult = 4 [default = 1];
+      case 4: {
+        if (tag == 37) {
+         parse_decay_mult:
+          set_has_decay_mult();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
+                 input, &decay_mult_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectAtEnd()) goto success;
+        break;
+      }
+
+      default: {
+      handle_unusual:
+        if (tag == 0 ||
+            ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+          goto success;
+        }
+        DO_(::google::protobuf::internal::WireFormat::SkipField(
+              input, tag, mutable_unknown_fields()));
+        break;
+      }
+    }
+  }
+success:
+  // @@protoc_insertion_point(parse_success:caffe.ParamSpec)
+  return true;
+failure:
+  // @@protoc_insertion_point(parse_failure:caffe.ParamSpec)
+  return false;
+#undef DO_
+}
+
+void ParamSpec::SerializeWithCachedSizes(
+    ::google::protobuf::io::CodedOutputStream* output) const {
+  // @@protoc_insertion_point(serialize_start:caffe.ParamSpec)
+  // optional string name = 1;
+  if (has_name()) {
+    ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->name().data(), this->name().length(),
+      ::google::protobuf::internal::WireFormat::SERIALIZE,
+      "caffe.ParamSpec.name");
+    ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
+      1, this->name(), output);
+  }
+
+  // optional .caffe.ParamSpec.DimCheckMode share_mode = 2;
+  if (has_share_mode()) {
+    ::google::protobuf::internal::WireFormatLite::WriteEnum(
+      2, this->share_mode(), output);
+  }
+
+  // optional float lr_mult = 3 [default = 1];
+  if (has_lr_mult()) {
+    ::google::protobuf::internal::WireFormatLite::WriteFloat(3, this->lr_mult(), output);
+  }
+
+  // optional float decay_mult = 4 [default = 1];
+  if (has_decay_mult()) {
+    ::google::protobuf::internal::WireFormatLite::WriteFloat(4, this->decay_mult(), output);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
+        unknown_fields(), output);
+  }
+  // @@protoc_insertion_point(serialize_end:caffe.ParamSpec)
+}
+
+::google::protobuf::uint8* ParamSpec::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
+  (void)deterministic; // Unused
+  // @@protoc_insertion_point(serialize_to_array_start:caffe.ParamSpec)
+  // optional string name = 1;
+  if (has_name()) {
+    ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->name().data(), this->name().length(),
+      ::google::protobuf::internal::WireFormat::SERIALIZE,
+      "caffe.ParamSpec.name");
+    target =
+      ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
+        1, this->name(), target);
+  }
+
+  // optional .caffe.ParamSpec.DimCheckMode share_mode = 2;
+  if (has_share_mode()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteEnumToArray(
+      2, this->share_mode(), target);
+  }
+
+  // optional float lr_mult = 3 [default = 1];
+  if (has_lr_mult()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteFloatToArray(3, this->lr_mult(), target);
+  }
+
+  // optional float decay_mult = 4 [default = 1];
+  if (has_decay_mult()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteFloatToArray(4, this->decay_mult(), target);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
+        unknown_fields(), target);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:caffe.ParamSpec)
+  return target;
+}
+
+size_t ParamSpec::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:caffe.ParamSpec)
+  size_t total_size = 0;
+
+  if (_has_bits_[0 / 32] & 15u) {
+    // optional string name = 1;
+    if (has_name()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::StringSize(
+          this->name());
+    }
+
+    // optional .caffe.ParamSpec.DimCheckMode share_mode = 2;
+    if (has_share_mode()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::EnumSize(this->share_mode());
+    }
+
+    // optional float lr_mult = 3 [default = 1];
+    if (has_lr_mult()) {
+      total_size += 1 + 4;
+    }
+
+    // optional float decay_mult = 4 [default = 1];
+    if (has_decay_mult()) {
+      total_size += 1 + 4;
+    }
+
+  }
+  if (_internal_metadata_.have_unknown_fields()) {
+    total_size +=
+      ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
+        unknown_fields());
+  }
+  int cached_size = ::google::protobuf::internal::ToCachedSize(total_size);
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = cached_size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+  return total_size;
+}
+
+void ParamSpec::MergeFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_merge_from_start:caffe.ParamSpec)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const ParamSpec* source =
+      ::google::protobuf::internal::DynamicCastToGenerated<const ParamSpec>(
+          &from);
+  if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:caffe.ParamSpec)
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:caffe.ParamSpec)
+    UnsafeMergeFrom(*source);
+  }
+}
+
+void ParamSpec::MergeFrom(const ParamSpec& from) {
+// @@protoc_insertion_point(class_specific_merge_from_start:caffe.ParamSpec)
+  if (GOOGLE_PREDICT_TRUE(&from != this)) {
+    UnsafeMergeFrom(from);
+  } else {
+    MergeFromFail(__LINE__);
+  }
+}
+
+void ParamSpec::UnsafeMergeFrom(const ParamSpec& from) {
+  GOOGLE_DCHECK(&from != this);
+  if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+    if (from.has_name()) {
+      set_has_name();
+      name_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.name_);
+    }
+    if (from.has_share_mode()) {
+      set_share_mode(from.share_mode());
+    }
+    if (from.has_lr_mult()) {
+      set_lr_mult(from.lr_mult());
+    }
+    if (from.has_decay_mult()) {
+      set_decay_mult(from.decay_mult());
+    }
+  }
+  if (from._internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::UnknownFieldSet::MergeToInternalMetdata(
+      from.unknown_fields(), &_internal_metadata_);
+  }
+}
+
+void ParamSpec::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:caffe.ParamSpec)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void ParamSpec::CopyFrom(const ParamSpec& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:caffe.ParamSpec)
+  if (&from == this) return;
+  Clear();
+  UnsafeMergeFrom(from);
+}
+
+bool ParamSpec::IsInitialized() const {
+
+  return true;
+}
+
+void ParamSpec::Swap(ParamSpec* other) {
+  if (other == this) return;
+  InternalSwap(other);
+}
+void ParamSpec::InternalSwap(ParamSpec* other) {
+  name_.Swap(&other->name_);
+  std::swap(share_mode_, other->share_mode_);
+  std::swap(lr_mult_, other->lr_mult_);
+  std::swap(decay_mult_, other->decay_mult_);
+  std::swap(_has_bits_[0], other->_has_bits_[0]);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
+}
+
+::google::protobuf::Metadata ParamSpec::GetMetadata() const {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::Metadata metadata;
+  metadata.descriptor = ParamSpec_descriptor_;
+  metadata.reflection = ParamSpec_reflection_;
+  return metadata;
+}
+
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// ParamSpec
+
+// optional string name = 1;
+bool ParamSpec::has_name() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+void ParamSpec::set_has_name() {
+  _has_bits_[0] |= 0x00000001u;
+}
+void ParamSpec::clear_has_name() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+void ParamSpec::clear_name() {
+  name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  clear_has_name();
+}
+const ::std::string& ParamSpec::name() const {
+  // @@protoc_insertion_point(field_get:caffe.ParamSpec.name)
+  return name_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+void ParamSpec::set_name(const ::std::string& value) {
+  set_has_name();
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:caffe.ParamSpec.name)
+}
+void ParamSpec::set_name(const char* value) {
+  set_has_name();
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:caffe.ParamSpec.name)
+}
+void ParamSpec::set_name(const char* value, size_t size) {
+  set_has_name();
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:caffe.ParamSpec.name)
+}
+::std::string* ParamSpec::mutable_name() {
+  set_has_name();
+  // @@protoc_insertion_point(field_mutable:caffe.ParamSpec.name)
+  return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+::std::string* ParamSpec::release_name() {
+  // @@protoc_insertion_point(field_release:caffe.ParamSpec.name)
+  clear_has_name();
+  return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+void ParamSpec::set_allocated_name(::std::string* name) {
+  if (name != NULL) {
+    set_has_name();
+  } else {
+    clear_has_name();
+  }
+  name_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), name);
+  // @@protoc_insertion_point(field_set_allocated:caffe.ParamSpec.name)
+}
+
+// optional .caffe.ParamSpec.DimCheckMode share_mode = 2;
+bool ParamSpec::has_share_mode() const {
+  return (_has_bits_[0] & 0x00000002u) != 0;
+}
+void ParamSpec::set_has_share_mode() {
+  _has_bits_[0] |= 0x00000002u;
+}
+void ParamSpec::clear_has_share_mode() {
+  _has_bits_[0] &= ~0x00000002u;
+}
+void ParamSpec::clear_share_mode() {
+  share_mode_ = 0;
+  clear_has_share_mode();
+}
+::caffe::ParamSpec_DimCheckMode ParamSpec::share_mode() const {
+  // @@protoc_insertion_point(field_get:caffe.ParamSpec.share_mode)
+  return static_cast< ::caffe::ParamSpec_DimCheckMode >(share_mode_);
+}
+void ParamSpec::set_share_mode(::caffe::ParamSpec_DimCheckMode value) {
+  assert(::caffe::ParamSpec_DimCheckMode_IsValid(value));
+  set_has_share_mode();
+  share_mode_ = value;
+  // @@protoc_insertion_point(field_set:caffe.ParamSpec.share_mode)
+}
+
+// optional float lr_mult = 3 [default = 1];
+bool ParamSpec::has_lr_mult() const {
+  return (_has_bits_[0] & 0x00000004u) != 0;
+}
+void ParamSpec::set_has_lr_mult() {
+  _has_bits_[0] |= 0x00000004u;
+}
+void ParamSpec::clear_has_lr_mult() {
+  _has_bits_[0] &= ~0x00000004u;
+}
+void ParamSpec::clear_lr_mult() {
+  lr_mult_ = 1;
+  clear_has_lr_mult();
+}
+float ParamSpec::lr_mult() const {
+  // @@protoc_insertion_point(field_get:caffe.ParamSpec.lr_mult)
+  return lr_mult_;
+}
+void ParamSpec::set_lr_mult(float value) {
+  set_has_lr_mult();
+  lr_mult_ = value;
+  // @@protoc_insertion_point(field_set:caffe.ParamSpec.lr_mult)
+}
+
+// optional float decay_mult = 4 [default = 1];
+bool ParamSpec::has_decay_mult() const {
+  return (_has_bits_[0] & 0x00000008u) != 0;
+}
+void ParamSpec::set_has_decay_mult() {
+  _has_bits_[0] |= 0x00000008u;
+}
+void ParamSpec::clear_has_decay_mult() {
+  _has_bits_[0] &= ~0x00000008u;
+}
+void ParamSpec::clear_decay_mult() {
+  decay_mult_ = 1;
+  clear_has_decay_mult();
+}
+float ParamSpec::decay_mult() const {
+  // @@protoc_insertion_point(field_get:caffe.ParamSpec.decay_mult)
+  return decay_mult_;
+}
+void ParamSpec::set_decay_mult(float value) {
+  set_has_decay_mult();
+  decay_mult_ = value;
+  // @@protoc_insertion_point(field_set:caffe.ParamSpec.decay_mult)
+}
+
+inline const ParamSpec* ParamSpec::internal_default_instance() {
+  return &ParamSpec_default_instance_.get();
+}
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
+
+// ===================================================================
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const int LayerParameter::kNameFieldNumber;
+const int LayerParameter::kTypeFieldNumber;
+const int LayerParameter::kBottomFieldNumber;
+const int LayerParameter::kTopFieldNumber;
+const int LayerParameter::kPhaseFieldNumber;
+const int LayerParameter::kLossWeightFieldNumber;
+const int LayerParameter::kParamFieldNumber;
+const int LayerParameter::kBlobsFieldNumber;
+const int LayerParameter::kPropagateDownFieldNumber;
+const int LayerParameter::kIncludeFieldNumber;
+const int LayerParameter::kExcludeFieldNumber;
+const int LayerParameter::kTransformParamFieldNumber;
+const int LayerParameter::kLossParamFieldNumber;
+const int LayerParameter::kAccuracyParamFieldNumber;
+const int LayerParameter::kArgmaxParamFieldNumber;
+const int LayerParameter::kConcatParamFieldNumber;
+const int LayerParameter::kContrastiveLossParamFieldNumber;
+const int LayerParameter::kConvolutionParamFieldNumber;
+const int LayerParameter::kCropParamFieldNumber;
+const int LayerParameter::kDataParamFieldNumber;
+const int LayerParameter::kDetectionOutputParamFieldNumber;
+const int LayerParameter::kDropoutParamFieldNumber;
+const int LayerParameter::kDummyDataParamFieldNumber;
+const int LayerParameter::kEltwiseParamFieldNumber;
+const int LayerParameter::kExpParamFieldNumber;
+const int LayerParameter::kFlattenParamFieldNumber;
+const int LayerParameter::kHdf5DataParamFieldNumber;
+const int LayerParameter::kHdf5OutputParamFieldNumber;
+const int LayerParameter::kHingeLossParamFieldNumber;
+const int LayerParameter::kImageDataParamFieldNumber;
+const int LayerParameter::kInfogainLossParamFieldNumber;
+const int LayerParameter::kInnerProductParamFieldNumber;
+const int LayerParameter::kLogParamFieldNumber;
+const int LayerParameter::kLrnParamFieldNumber;
+const int LayerParameter::kMemoryDataParamFieldNumber;
+const int LayerParameter::kMvnParamFieldNumber;
+const int LayerParameter::kNormalizeBboxParamFieldNumber;
+const int LayerParameter::kPermuteParamFieldNumber;
+const int LayerParameter::kPoolingParamFieldNumber;
+const int LayerParameter::kPowerParamFieldNumber;
+const int LayerParameter::kPreluParamFieldNumber;
+const int LayerParameter::kPriorBoxParamFieldNumber;
+const int LayerParameter::kPythonParamFieldNumber;
+const int LayerParameter::kReductionParamFieldNumber;
+const int LayerParameter::kReluParamFieldNumber;
+const int LayerParameter::kReshapeParamFieldNumber;
+const int LayerParameter::kSigmoidParamFieldNumber;
+const int LayerParameter::kSliceParamFieldNumber;
+const int LayerParameter::kSoftmaxParamFieldNumber;
+const int LayerParameter::kSppParamFieldNumber;
+const int LayerParameter::kTanhParamFieldNumber;
+const int LayerParameter::kThresholdParamFieldNumber;
+const int LayerParameter::kWindowDataParamFieldNumber;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+
+LayerParameter::LayerParameter()
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+  if (this != internal_default_instance()) protobuf_InitDefaults_caffe_2eproto();
+  SharedCtor();
+  // @@protoc_insertion_point(constructor:caffe.LayerParameter)
+}
+
+void LayerParameter::InitAsDefaultInstance() {
+  transform_param_ = const_cast< ::caffe::TransformationParameter*>(
+      ::caffe::TransformationParameter::internal_default_instance());
+  loss_param_ = const_cast< ::caffe::LossParameter*>(
+      ::caffe::LossParameter::internal_default_instance());
+  accuracy_param_ = const_cast< ::caffe::AccuracyParameter*>(
+      ::caffe::AccuracyParameter::internal_default_instance());
+  argmax_param_ = const_cast< ::caffe::ArgMaxParameter*>(
+      ::caffe::ArgMaxParameter::internal_default_instance());
+  concat_param_ = const_cast< ::caffe::ConcatParameter*>(
+      ::caffe::ConcatParameter::internal_default_instance());
+  contrastive_loss_param_ = const_cast< ::caffe::ContrastiveLossParameter*>(
+      ::caffe::ContrastiveLossParameter::internal_default_instance());
+  convolution_param_ = const_cast< ::caffe::ConvolutionParameter*>(
+      ::caffe::ConvolutionParameter::internal_default_instance());
+  crop_param_ = const_cast< ::caffe::CropParameter*>(
+      ::caffe::CropParameter::internal_default_instance());
+  data_param_ = const_cast< ::caffe::DataParameter*>(
+      ::caffe::DataParameter::internal_default_instance());
+  detection_output_param_ = const_cast< ::caffe::DetectionOutputParameter*>(
+      ::caffe::DetectionOutputParameter::internal_default_instance());
+  dropout_param_ = const_cast< ::caffe::DropoutParameter*>(
+      ::caffe::DropoutParameter::internal_default_instance());
+  dummy_data_param_ = const_cast< ::caffe::DummyDataParameter*>(
+      ::caffe::DummyDataParameter::internal_default_instance());
+  eltwise_param_ = const_cast< ::caffe::EltwiseParameter*>(
+      ::caffe::EltwiseParameter::internal_default_instance());
+  exp_param_ = const_cast< ::caffe::ExpParameter*>(
+      ::caffe::ExpParameter::internal_default_instance());
+  flatten_param_ = const_cast< ::caffe::FlattenParameter*>(
+      ::caffe::FlattenParameter::internal_default_instance());
+  hdf5_data_param_ = const_cast< ::caffe::HDF5DataParameter*>(
+      ::caffe::HDF5DataParameter::internal_default_instance());
+  hdf5_output_param_ = const_cast< ::caffe::HDF5OutputParameter*>(
+      ::caffe::HDF5OutputParameter::internal_default_instance());
+  hinge_loss_param_ = const_cast< ::caffe::HingeLossParameter*>(
+      ::caffe::HingeLossParameter::internal_default_instance());
+  image_data_param_ = const_cast< ::caffe::ImageDataParameter*>(
+      ::caffe::ImageDataParameter::internal_default_instance());
+  infogain_loss_param_ = const_cast< ::caffe::InfogainLossParameter*>(
+      ::caffe::InfogainLossParameter::internal_default_instance());
+  inner_product_param_ = const_cast< ::caffe::InnerProductParameter*>(
+      ::caffe::InnerProductParameter::internal_default_instance());
+  log_param_ = const_cast< ::caffe::LogParameter*>(
+      ::caffe::LogParameter::internal_default_instance());
+  lrn_param_ = const_cast< ::caffe::LRNParameter*>(
+      ::caffe::LRNParameter::internal_default_instance());
+  memory_data_param_ = const_cast< ::caffe::MemoryDataParameter*>(
+      ::caffe::MemoryDataParameter::internal_default_instance());
+  mvn_param_ = const_cast< ::caffe::MVNParameter*>(
+      ::caffe::MVNParameter::internal_default_instance());
+  normalize_bbox_param_ = const_cast< ::caffe::NormalizeBBoxParameter*>(
+      ::caffe::NormalizeBBoxParameter::internal_default_instance());
+  permute_param_ = const_cast< ::caffe::PermuteParameter*>(
+      ::caffe::PermuteParameter::internal_default_instance());
+  pooling_param_ = const_cast< ::caffe::PoolingParameter*>(
+      ::caffe::PoolingParameter::internal_default_instance());
+  power_param_ = const_cast< ::caffe::PowerParameter*>(
+      ::caffe::PowerParameter::internal_default_instance());
+  prelu_param_ = const_cast< ::caffe::PReLUParameter*>(
+      ::caffe::PReLUParameter::internal_default_instance());
+  prior_box_param_ = const_cast< ::caffe::PriorBoxParameter*>(
+      ::caffe::PriorBoxParameter::internal_default_instance());
+  python_param_ = const_cast< ::caffe::PythonParameter*>(
+      ::caffe::PythonParameter::internal_default_instance());
+  reduction_param_ = const_cast< ::caffe::ReductionParameter*>(
+      ::caffe::ReductionParameter::internal_default_instance());
+  relu_param_ = const_cast< ::caffe::ReLUParameter*>(
+      ::caffe::ReLUParameter::internal_default_instance());
+  reshape_param_ = const_cast< ::caffe::ReshapeParameter*>(
+      ::caffe::ReshapeParameter::internal_default_instance());
+  sigmoid_param_ = const_cast< ::caffe::SigmoidParameter*>(
+      ::caffe::SigmoidParameter::internal_default_instance());
+  slice_param_ = const_cast< ::caffe::SliceParameter*>(
+      ::caffe::SliceParameter::internal_default_instance());
+  softmax_param_ = const_cast< ::caffe::SoftmaxParameter*>(
+      ::caffe::SoftmaxParameter::internal_default_instance());
+  spp_param_ = const_cast< ::caffe::SPPParameter*>(
+      ::caffe::SPPParameter::internal_default_instance());
+  tanh_param_ = const_cast< ::caffe::TanHParameter*>(
+      ::caffe::TanHParameter::internal_default_instance());
+  threshold_param_ = const_cast< ::caffe::ThresholdParameter*>(
+      ::caffe::ThresholdParameter::internal_default_instance());
+  window_data_param_ = const_cast< ::caffe::WindowDataParameter*>(
+      ::caffe::WindowDataParameter::internal_default_instance());
+}
+
+LayerParameter::LayerParameter(const LayerParameter& from)
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
+  SharedCtor();
+  UnsafeMergeFrom(from);
+  // @@protoc_insertion_point(copy_constructor:caffe.LayerParameter)
+}
+
+void LayerParameter::SharedCtor() {
+  name_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  type_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  transform_param_ = NULL;
+  loss_param_ = NULL;
+  accuracy_param_ = NULL;
+  argmax_param_ = NULL;
+  concat_param_ = NULL;
+  contrastive_loss_param_ = NULL;
+  convolution_param_ = NULL;
+  crop_param_ = NULL;
+  data_param_ = NULL;
+  detection_output_param_ = NULL;
+  dropout_param_ = NULL;
+  dummy_data_param_ = NULL;
+  eltwise_param_ = NULL;
+  exp_param_ = NULL;
+  flatten_param_ = NULL;
+  hdf5_data_param_ = NULL;
+  hdf5_output_param_ = NULL;
+  hinge_loss_param_ = NULL;
+  image_data_param_ = NULL;
+  infogain_loss_param_ = NULL;
+  inner_product_param_ = NULL;
+  log_param_ = NULL;
+  lrn_param_ = NULL;
+  memory_data_param_ = NULL;
+  mvn_param_ = NULL;
+  normalize_bbox_param_ = NULL;
+  permute_param_ = NULL;
+  pooling_param_ = NULL;
+  power_param_ = NULL;
+  prelu_param_ = NULL;
+  prior_box_param_ = NULL;
+  python_param_ = NULL;
+  reduction_param_ = NULL;
+  relu_param_ = NULL;
+  reshape_param_ = NULL;
+  sigmoid_param_ = NULL;
+  slice_param_ = NULL;
+  softmax_param_ = NULL;
+  spp_param_ = NULL;
+  tanh_param_ = NULL;
+  threshold_param_ = NULL;
+  window_data_param_ = NULL;
+  phase_ = 0;
+  _cached_size_ = 0;
+}
+
+LayerParameter::~LayerParameter() {
+  // @@protoc_insertion_point(destructor:caffe.LayerParameter)
+  SharedDtor();
+}
+
+void LayerParameter::SharedDtor() {
+  name_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  type_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  if (this != &LayerParameter_default_instance_.get()) {
+    delete transform_param_;
+    delete loss_param_;
+    delete accuracy_param_;
+    delete argmax_param_;
+    delete concat_param_;
+    delete contrastive_loss_param_;
+    delete convolution_param_;
+    delete crop_param_;
+    delete data_param_;
+    delete detection_output_param_;
+    delete dropout_param_;
+    delete dummy_data_param_;
+    delete eltwise_param_;
+    delete exp_param_;
+    delete flatten_param_;
+    delete hdf5_data_param_;
+    delete hdf5_output_param_;
+    delete hinge_loss_param_;
+    delete image_data_param_;
+    delete infogain_loss_param_;
+    delete inner_product_param_;
+    delete log_param_;
+    delete lrn_param_;
+    delete memory_data_param_;
+    delete mvn_param_;
+    delete normalize_bbox_param_;
+    delete permute_param_;
+    delete pooling_param_;
+    delete power_param_;
+    delete prelu_param_;
+    delete prior_box_param_;
+    delete python_param_;
+    delete reduction_param_;
+    delete relu_param_;
+    delete reshape_param_;
+    delete sigmoid_param_;
+    delete slice_param_;
+    delete softmax_param_;
+    delete spp_param_;
+    delete tanh_param_;
+    delete threshold_param_;
+    delete window_data_param_;
+  }
+}
+
+void LayerParameter::SetCachedSize(int size) const {
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* LayerParameter::descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return LayerParameter_descriptor_;
+}
+
+const LayerParameter& LayerParameter::default_instance() {
+  protobuf_InitDefaults_caffe_2eproto();
+  return *internal_default_instance();
+}
+
+::google::protobuf::internal::ExplicitlyConstructed<LayerParameter> LayerParameter_default_instance_;
+
+LayerParameter* LayerParameter::New(::google::protobuf::Arena* arena) const {
+  LayerParameter* n = new LayerParameter;
+  if (arena != NULL) {
+    arena->Own(n);
+  }
+  return n;
+}
+
+void LayerParameter::Clear() {
+// @@protoc_insertion_point(message_clear_start:caffe.LayerParameter)
+  if (_has_bits_[0 / 32] & 19u) {
+    if (has_name()) {
+      name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+    }
+    if (has_type()) {
+      type_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+    }
+    phase_ = 0;
+  }
+  if (_has_bits_[8 / 32] & 63488u) {
+    if (has_transform_param()) {
+      if (transform_param_ != NULL) transform_param_->::caffe::TransformationParameter::Clear();
+    }
+    if (has_loss_param()) {
+      if (loss_param_ != NULL) loss_param_->::caffe::LossParameter::Clear();
+    }
+    if (has_accuracy_param()) {
+      if (accuracy_param_ != NULL) accuracy_param_->::caffe::AccuracyParameter::Clear();
+    }
+    if (has_argmax_param()) {
+      if (argmax_param_ != NULL) argmax_param_->::caffe::ArgMaxParameter::Clear();
+    }
+    if (has_concat_param()) {
+      if (concat_param_ != NULL) concat_param_->::caffe::ConcatParameter::Clear();
+    }
+  }
+  if (_has_bits_[16 / 32] & 16711680u) {
+    if (has_contrastive_loss_param()) {
+      if (contrastive_loss_param_ != NULL) contrastive_loss_param_->::caffe::ContrastiveLossParameter::Clear();
+    }
+    if (has_convolution_param()) {
+      if (convolution_param_ != NULL) convolution_param_->::caffe::ConvolutionParameter::Clear();
+    }
+    if (has_crop_param()) {
+      if (crop_param_ != NULL) crop_param_->::caffe::CropParameter::Clear();
+    }
+    if (has_data_param()) {
+      if (data_param_ != NULL) data_param_->::caffe::DataParameter::Clear();
+    }
+    if (has_detection_output_param()) {
+      if (detection_output_param_ != NULL) detection_output_param_->::caffe::DetectionOutputParameter::Clear();
+    }
+    if (has_dropout_param()) {
+      if (dropout_param_ != NULL) dropout_param_->::caffe::DropoutParameter::Clear();
+    }
+    if (has_dummy_data_param()) {
+      if (dummy_data_param_ != NULL) dummy_data_param_->::caffe::DummyDataParameter::Clear();
+    }
+    if (has_eltwise_param()) {
+      if (eltwise_param_ != NULL) eltwise_param_->::caffe::EltwiseParameter::Clear();
+    }
+  }
+  if (_has_bits_[24 / 32] & 4278190080u) {
+    if (has_exp_param()) {
+      if (exp_param_ != NULL) exp_param_->::caffe::ExpParameter::Clear();
+    }
+    if (has_flatten_param()) {
+      if (flatten_param_ != NULL) flatten_param_->::caffe::FlattenParameter::Clear();
+    }
+    if (has_hdf5_data_param()) {
+      if (hdf5_data_param_ != NULL) hdf5_data_param_->::caffe::HDF5DataParameter::Clear();
+    }
+    if (has_hdf5_output_param()) {
+      if (hdf5_output_param_ != NULL) hdf5_output_param_->::caffe::HDF5OutputParameter::Clear();
+    }
+    if (has_hinge_loss_param()) {
+      if (hinge_loss_param_ != NULL) hinge_loss_param_->::caffe::HingeLossParameter::Clear();
+    }
+    if (has_image_data_param()) {
+      if (image_data_param_ != NULL) image_data_param_->::caffe::ImageDataParameter::Clear();
+    }
+    if (has_infogain_loss_param()) {
+      if (infogain_loss_param_ != NULL) infogain_loss_param_->::caffe::InfogainLossParameter::Clear();
+    }
+    if (has_inner_product_param()) {
+      if (inner_product_param_ != NULL) inner_product_param_->::caffe::InnerProductParameter::Clear();
+    }
+  }
+  if (_has_bits_[32 / 32] & 255u) {
+    if (has_log_param()) {
+      if (log_param_ != NULL) log_param_->::caffe::LogParameter::Clear();
+    }
+    if (has_lrn_param()) {
+      if (lrn_param_ != NULL) lrn_param_->::caffe::LRNParameter::Clear();
+    }
+    if (has_memory_data_param()) {
+      if (memory_data_param_ != NULL) memory_data_param_->::caffe::MemoryDataParameter::Clear();
+    }
+    if (has_mvn_param()) {
+      if (mvn_param_ != NULL) mvn_param_->::caffe::MVNParameter::Clear();
+    }
+    if (has_normalize_bbox_param()) {
+      if (normalize_bbox_param_ != NULL) normalize_bbox_param_->::caffe::NormalizeBBoxParameter::Clear();
+    }
+    if (has_permute_param()) {
+      if (permute_param_ != NULL) permute_param_->::caffe::PermuteParameter::Clear();
+    }
+    if (has_pooling_param()) {
+      if (pooling_param_ != NULL) pooling_param_->::caffe::PoolingParameter::Clear();
+    }
+    if (has_power_param()) {
+      if (power_param_ != NULL) power_param_->::caffe::PowerParameter::Clear();
+    }
+  }
+  if (_has_bits_[40 / 32] & 65280u) {
+    if (has_prelu_param()) {
+      if (prelu_param_ != NULL) prelu_param_->::caffe::PReLUParameter::Clear();
+    }
+    if (has_prior_box_param()) {
+      if (prior_box_param_ != NULL) prior_box_param_->::caffe::PriorBoxParameter::Clear();
+    }
+    if (has_python_param()) {
+      if (python_param_ != NULL) python_param_->::caffe::PythonParameter::Clear();
+    }
+    if (has_reduction_param()) {
+      if (reduction_param_ != NULL) reduction_param_->::caffe::ReductionParameter::Clear();
+    }
+    if (has_relu_param()) {
+      if (relu_param_ != NULL) relu_param_->::caffe::ReLUParameter::Clear();
+    }
+    if (has_reshape_param()) {
+      if (reshape_param_ != NULL) reshape_param_->::caffe::ReshapeParameter::Clear();
+    }
+    if (has_sigmoid_param()) {
+      if (sigmoid_param_ != NULL) sigmoid_param_->::caffe::SigmoidParameter::Clear();
+    }
+    if (has_slice_param()) {
+      if (slice_param_ != NULL) slice_param_->::caffe::SliceParameter::Clear();
+    }
+  }
+  if (_has_bits_[48 / 32] & 2031616u) {
+    if (has_softmax_param()) {
+      if (softmax_param_ != NULL) softmax_param_->::caffe::SoftmaxParameter::Clear();
+    }
+    if (has_spp_param()) {
+      if (spp_param_ != NULL) spp_param_->::caffe::SPPParameter::Clear();
+    }
+    if (has_tanh_param()) {
+      if (tanh_param_ != NULL) tanh_param_->::caffe::TanHParameter::Clear();
+    }
+    if (has_threshold_param()) {
+      if (threshold_param_ != NULL) threshold_param_->::caffe::ThresholdParameter::Clear();
+    }
+    if (has_window_data_param()) {
+      if (window_data_param_ != NULL) window_data_param_->::caffe::WindowDataParameter::Clear();
+    }
+  }
+  bottom_.Clear();
+  top_.Clear();
+  loss_weight_.Clear();
+  param_.Clear();
+  blobs_.Clear();
+  propagate_down_.Clear();
+  include_.Clear();
+  exclude_.Clear();
+  _has_bits_.Clear();
+  if (_internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->Clear();
+  }
+}
+
+bool LayerParameter::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
+  ::google::protobuf::uint32 tag;
+  // @@protoc_insertion_point(parse_start:caffe.LayerParameter)
+  for (;;) {
+    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(16383);
+    tag = p.first;
+    if (!p.second) goto handle_unusual;
+    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+      // optional string name = 1;
+      case 1: {
+        if (tag == 10) {
+          DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+                input, this->mutable_name()));
+          ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+            this->name().data(), this->name().length(),
+            ::google::protobuf::internal::WireFormat::PARSE,
+            "caffe.LayerParameter.name");
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(18)) goto parse_type;
+        break;
+      }
+
+      // optional string type = 2;
+      case 2: {
+        if (tag == 18) {
+         parse_type:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+                input, this->mutable_type()));
+          ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+            this->type().data(), this->type().length(),
+            ::google::protobuf::internal::WireFormat::PARSE,
+            "caffe.LayerParameter.type");
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(26)) goto parse_bottom;
+        break;
+      }
+
+      // repeated string bottom = 3;
+      case 3: {
+        if (tag == 26) {
+         parse_bottom:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+                input, this->add_bottom()));
+          ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+            this->bottom(this->bottom_size() - 1).data(),
+            this->bottom(this->bottom_size() - 1).length(),
+            ::google::protobuf::internal::WireFormat::PARSE,
+            "caffe.LayerParameter.bottom");
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(26)) goto parse_bottom;
+        if (input->ExpectTag(34)) goto parse_top;
+        break;
+      }
+
+      // repeated string top = 4;
+      case 4: {
+        if (tag == 34) {
+         parse_top:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+                input, this->add_top()));
+          ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+            this->top(this->top_size() - 1).data(),
+            this->top(this->top_size() - 1).length(),
+            ::google::protobuf::internal::WireFormat::PARSE,
+            "caffe.LayerParameter.top");
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(34)) goto parse_top;
+        if (input->ExpectTag(45)) goto parse_loss_weight;
+        break;
+      }
+
+      // repeated float loss_weight = 5;
+      case 5: {
+        if (tag == 45) {
+         parse_loss_weight:
+          DO_((::google::protobuf::internal::WireFormatLite::ReadRepeatedPrimitive<
+                   float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
+                 1, 45, input, this->mutable_loss_weight())));
+        } else if (tag == 42) {
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPackedPrimitiveNoInline<
+                   float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
+                 input, this->mutable_loss_weight())));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(45)) goto parse_loss_weight;
+        if (input->ExpectTag(50)) goto parse_param;
+        break;
+      }
+
+      // repeated .caffe.ParamSpec param = 6;
+      case 6: {
+        if (tag == 50) {
+         parse_param:
+          DO_(input->IncrementRecursionDepth());
+         parse_loop_param:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth(
+                input, add_param()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(50)) goto parse_loop_param;
+        if (input->ExpectTag(58)) goto parse_loop_blobs;
+        input->UnsafeDecrementRecursionDepth();
+        break;
+      }
+
+      // repeated .caffe.BlobProto blobs = 7;
+      case 7: {
+        if (tag == 58) {
+          DO_(input->IncrementRecursionDepth());
+         parse_loop_blobs:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth(
+                input, add_blobs()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(58)) goto parse_loop_blobs;
+        if (input->ExpectTag(66)) goto parse_loop_include;
+        input->UnsafeDecrementRecursionDepth();
+        break;
+      }
+
+      // repeated .caffe.NetStateRule include = 8;
+      case 8: {
+        if (tag == 66) {
+          DO_(input->IncrementRecursionDepth());
+         parse_loop_include:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth(
+                input, add_include()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(66)) goto parse_loop_include;
+        if (input->ExpectTag(74)) goto parse_loop_exclude;
+        input->UnsafeDecrementRecursionDepth();
+        break;
+      }
+
+      // repeated .caffe.NetStateRule exclude = 9;
+      case 9: {
+        if (tag == 74) {
+          DO_(input->IncrementRecursionDepth());
+         parse_loop_exclude:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth(
+                input, add_exclude()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(74)) goto parse_loop_exclude;
+        input->UnsafeDecrementRecursionDepth();
+        if (input->ExpectTag(80)) goto parse_phase;
+        break;
+      }
+
+      // optional .caffe.Phase phase = 10;
+      case 10: {
+        if (tag == 80) {
+         parse_phase:
+          int value;
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>(
+                 input, &value)));
+          if (::caffe::Phase_IsValid(value)) {
+            set_phase(static_cast< ::caffe::Phase >(value));
+          } else {
+            mutable_unknown_fields()->AddVarint(10, value);
+          }
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(88)) goto parse_propagate_down;
+        break;
+      }
+
+      // repeated bool propagate_down = 11;
+      case 11: {
+        if (tag == 88) {
+         parse_propagate_down:
+          DO_((::google::protobuf::internal::WireFormatLite::ReadRepeatedPrimitive<
+                   bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>(
+                 1, 88, input, this->mutable_propagate_down())));
+        } else if (tag == 90) {
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPackedPrimitiveNoInline<
+                   bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>(
+                 input, this->mutable_propagate_down())));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(88)) goto parse_propagate_down;
+        if (input->ExpectTag(802)) goto parse_transform_param;
+        break;
+      }
+
+      // optional .caffe.TransformationParameter transform_param = 100;
+      case 100: {
+        if (tag == 802) {
+         parse_transform_param:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+               input, mutable_transform_param()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(810)) goto parse_loss_param;
+        break;
+      }
+
+      // optional .caffe.LossParameter loss_param = 101;
+      case 101: {
+        if (tag == 810) {
+         parse_loss_param:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+               input, mutable_loss_param()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(818)) goto parse_accuracy_param;
+        break;
+      }
+
+      // optional .caffe.AccuracyParameter accuracy_param = 102;
+      case 102: {
+        if (tag == 818) {
+         parse_accuracy_param:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+               input, mutable_accuracy_param()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(826)) goto parse_argmax_param;
+        break;
+      }
+
+      // optional .caffe.ArgMaxParameter argmax_param = 103;
+      case 103: {
+        if (tag == 826) {
+         parse_argmax_param:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+               input, mutable_argmax_param()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(834)) goto parse_concat_param;
+        break;
+      }
+
+      // optional .caffe.ConcatParameter concat_param = 104;
+      case 104: {
+        if (tag == 834) {
+         parse_concat_param:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+               input, mutable_concat_param()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(842)) goto parse_contrastive_loss_param;
+        break;
+      }
+
+      // optional .caffe.ContrastiveLossParameter contrastive_loss_param = 105;
+      case 105: {
+        if (tag == 842) {
+         parse_contrastive_loss_param:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+               input, mutable_contrastive_loss_param()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(850)) goto parse_convolution_param;
+        break;
+      }
+
+      // optional .caffe.ConvolutionParameter convolution_param = 106;
+      case 106: {
+        if (tag == 850) {
+         parse_convolution_param:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+               input, mutable_convolution_param()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(858)) goto parse_data_param;
+        break;
+      }
+
+      // optional .caffe.DataParameter data_param = 107;
+      case 107: {
+        if (tag == 858) {
+         parse_data_param:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+               input, mutable_data_param()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(866)) goto parse_dropout_param;
+        break;
+      }
+
+      // optional .caffe.DropoutParameter dropout_param = 108;
+      case 108: {
+        if (tag == 866) {
+         parse_dropout_param:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+               input, mutable_dropout_param()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(874)) goto parse_dummy_data_param;
+        break;
+      }
+
+      // optional .caffe.DummyDataParameter dummy_data_param = 109;
+      case 109: {
+        if (tag == 874) {
+         parse_dummy_data_param:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+               input, mutable_dummy_data_param()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(882)) goto parse_eltwise_param;
+        break;
+      }
+
+      // optional .caffe.EltwiseParameter eltwise_param = 110;
+      case 110: {
+        if (tag == 882) {
+         parse_eltwise_param:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+               input, mutable_eltwise_param()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(890)) goto parse_exp_param;
+        break;
+      }
+
+      // optional .caffe.ExpParameter exp_param = 111;
+      case 111: {
+        if (tag == 890) {
+         parse_exp_param:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+               input, mutable_exp_param()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(898)) goto parse_hdf5_data_param;
+        break;
+      }
+
+      // optional .caffe.HDF5DataParameter hdf5_data_param = 112;
+      case 112: {
+        if (tag == 898) {
+         parse_hdf5_data_param:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+               input, mutable_hdf5_data_param()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(906)) goto parse_hdf5_output_param;
+        break;
+      }
+
+      // optional .caffe.HDF5OutputParameter hdf5_output_param = 113;
+      case 113: {
+        if (tag == 906) {
+         parse_hdf5_output_param:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+               input, mutable_hdf5_output_param()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(914)) goto parse_hinge_loss_param;
+        break;
+      }
+
+      // optional .caffe.HingeLossParameter hinge_loss_param = 114;
+      case 114: {
+        if (tag == 914) {
+         parse_hinge_loss_param:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+               input, mutable_hinge_loss_param()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(922)) goto parse_image_data_param;
+        break;
+      }
+
+      // optional .caffe.ImageDataParameter image_data_param = 115;
+      case 115: {
+        if (tag == 922) {
+         parse_image_data_param:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+               input, mutable_image_data_param()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(930)) goto parse_infogain_loss_param;
+        break;
+      }
+
+      // optional .caffe.InfogainLossParameter infogain_loss_param = 116;
+      case 116: {
+        if (tag == 930) {
+         parse_infogain_loss_param:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+               input, mutable_infogain_loss_param()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(938)) goto parse_inner_product_param;
+        break;
+      }
+
+      // optional .caffe.InnerProductParameter inner_product_param = 117;
+      case 117: {
+        if (tag == 938) {
+         parse_inner_product_param:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+               input, mutable_inner_product_param()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(946)) goto parse_lrn_param;
+        break;
+      }
+
+      // optional .caffe.LRNParameter lrn_param = 118;
+      case 118: {
+        if (tag == 946) {
+         parse_lrn_param:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+               input, mutable_lrn_param()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(954)) goto parse_memory_data_param;
+        break;
+      }
+
+      // optional .caffe.MemoryDataParameter memory_data_param = 119;
+      case 119: {
+        if (tag == 954) {
+         parse_memory_data_param:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+               input, mutable_memory_data_param()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(962)) goto parse_mvn_param;
+        break;
+      }
+
+      // optional .caffe.MVNParameter mvn_param = 120;
+      case 120: {
+        if (tag == 962) {
+         parse_mvn_param:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+               input, mutable_mvn_param()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(970)) goto parse_pooling_param;
+        break;
+      }
+
+      // optional .caffe.PoolingParameter pooling_param = 121;
+      case 121: {
+        if (tag == 970) {
+         parse_pooling_param:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+               input, mutable_pooling_param()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(978)) goto parse_power_param;
+        break;
+      }
+
+      // optional .caffe.PowerParameter power_param = 122;
+      case 122: {
+        if (tag == 978) {
+         parse_power_param:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+               input, mutable_power_param()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(986)) goto parse_relu_param;
+        break;
+      }
+
+      // optional .caffe.ReLUParameter relu_param = 123;
+      case 123: {
+        if (tag == 986) {
+         parse_relu_param:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+               input, mutable_relu_param()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(994)) goto parse_sigmoid_param;
+        break;
+      }
+
+      // optional .caffe.SigmoidParameter sigmoid_param = 124;
+      case 124: {
+        if (tag == 994) {
+         parse_sigmoid_param:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+               input, mutable_sigmoid_param()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(1002)) goto parse_softmax_param;
+        break;
+      }
+
+      // optional .caffe.SoftmaxParameter softmax_param = 125;
+      case 125: {
+        if (tag == 1002) {
+         parse_softmax_param:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+               input, mutable_softmax_param()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(1010)) goto parse_slice_param;
+        break;
+      }
+
+      // optional .caffe.SliceParameter slice_param = 126;
+      case 126: {
+        if (tag == 1010) {
+         parse_slice_param:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+               input, mutable_slice_param()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(1018)) goto parse_tanh_param;
+        break;
+      }
+
+      // optional .caffe.TanHParameter tanh_param = 127;
+      case 127: {
+        if (tag == 1018) {
+         parse_tanh_param:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+               input, mutable_tanh_param()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(1026)) goto parse_threshold_param;
+        break;
+      }
+
+      // optional .caffe.ThresholdParameter threshold_param = 128;
+      case 128: {
+        if (tag == 1026) {
+         parse_threshold_param:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+               input, mutable_threshold_param()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(1034)) goto parse_window_data_param;
+        break;
+      }
+
+      // optional .caffe.WindowDataParameter window_data_param = 129;
+      case 129: {
+        if (tag == 1034) {
+         parse_window_data_param:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+               input, mutable_window_data_param()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(1042)) goto parse_python_param;
+        break;
+      }
+
+      // optional .caffe.PythonParameter python_param = 130;
+      case 130: {
+        if (tag == 1042) {
+         parse_python_param:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+               input, mutable_python_param()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(1050)) goto parse_prelu_param;
+        break;
+      }
+
+      // optional .caffe.PReLUParameter prelu_param = 131;
+      case 131: {
+        if (tag == 1050) {
+         parse_prelu_param:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+               input, mutable_prelu_param()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(1058)) goto parse_spp_param;
+        break;
+      }
+
+      // optional .caffe.SPPParameter spp_param = 132;
+      case 132: {
+        if (tag == 1058) {
+         parse_spp_param:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+               input, mutable_spp_param()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(1066)) goto parse_reshape_param;
+        break;
+      }
+
+      // optional .caffe.ReshapeParameter reshape_param = 133;
+      case 133: {
+        if (tag == 1066) {
+         parse_reshape_param:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+               input, mutable_reshape_param()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(1074)) goto parse_log_param;
+        break;
+      }
+
+      // optional .caffe.LogParameter log_param = 134;
+      case 134: {
+        if (tag == 1074) {
+         parse_log_param:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+               input, mutable_log_param()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(1082)) goto parse_flatten_param;
+        break;
+      }
+
+      // optional .caffe.FlattenParameter flatten_param = 135;
+      case 135: {
+        if (tag == 1082) {
+         parse_flatten_param:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+               input, mutable_flatten_param()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(1090)) goto parse_reduction_param;
+        break;
+      }
+
+      // optional .caffe.ReductionParameter reduction_param = 136;
+      case 136: {
+        if (tag == 1090) {
+         parse_reduction_param:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+               input, mutable_reduction_param()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(1098)) goto parse_crop_param;
+        break;
+      }
+
+      // optional .caffe.CropParameter crop_param = 137;
+      case 137: {
+        if (tag == 1098) {
+         parse_crop_param:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+               input, mutable_crop_param()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(1106)) goto parse_permute_param;
+        break;
+      }
+
+      // optional .caffe.PermuteParameter permute_param = 138;
+      case 138: {
+        if (tag == 1106) {
+         parse_permute_param:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+               input, mutable_permute_param()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(1114)) goto parse_normalize_bbox_param;
+        break;
+      }
+
+      // optional .caffe.NormalizeBBoxParameter normalize_bbox_param = 139;
+      case 139: {
+        if (tag == 1114) {
+         parse_normalize_bbox_param:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+               input, mutable_normalize_bbox_param()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(1122)) goto parse_prior_box_param;
+        break;
+      }
+
+      // optional .caffe.PriorBoxParameter prior_box_param = 140;
+      case 140: {
+        if (tag == 1122) {
+         parse_prior_box_param:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+               input, mutable_prior_box_param()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(1130)) goto parse_detection_output_param;
+        break;
+      }
+
+      // optional .caffe.DetectionOutputParameter detection_output_param = 141;
+      case 141: {
+        if (tag == 1130) {
+         parse_detection_output_param:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+               input, mutable_detection_output_param()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectAtEnd()) goto success;
+        break;
+      }
+
+      default: {
+      handle_unusual:
+        if (tag == 0 ||
+            ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+          goto success;
+        }
+        DO_(::google::protobuf::internal::WireFormat::SkipField(
+              input, tag, mutable_unknown_fields()));
+        break;
+      }
+    }
+  }
+success:
+  // @@protoc_insertion_point(parse_success:caffe.LayerParameter)
+  return true;
+failure:
+  // @@protoc_insertion_point(parse_failure:caffe.LayerParameter)
+  return false;
+#undef DO_
+}
+
+void LayerParameter::SerializeWithCachedSizes(
+    ::google::protobuf::io::CodedOutputStream* output) const {
+  // @@protoc_insertion_point(serialize_start:caffe.LayerParameter)
+  // optional string name = 1;
+  if (has_name()) {
+    ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->name().data(), this->name().length(),
+      ::google::protobuf::internal::WireFormat::SERIALIZE,
+      "caffe.LayerParameter.name");
+    ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
+      1, this->name(), output);
+  }
+
+  // optional string type = 2;
+  if (has_type()) {
+    ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->type().data(), this->type().length(),
+      ::google::protobuf::internal::WireFormat::SERIALIZE,
+      "caffe.LayerParameter.type");
+    ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
+      2, this->type(), output);
+  }
+
+  // repeated string bottom = 3;
+  for (int i = 0; i < this->bottom_size(); i++) {
+    ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->bottom(i).data(), this->bottom(i).length(),
+      ::google::protobuf::internal::WireFormat::SERIALIZE,
+      "caffe.LayerParameter.bottom");
+    ::google::protobuf::internal::WireFormatLite::WriteString(
+      3, this->bottom(i), output);
+  }
+
+  // repeated string top = 4;
+  for (int i = 0; i < this->top_size(); i++) {
+    ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->top(i).data(), this->top(i).length(),
+      ::google::protobuf::internal::WireFormat::SERIALIZE,
+      "caffe.LayerParameter.top");
+    ::google::protobuf::internal::WireFormatLite::WriteString(
+      4, this->top(i), output);
+  }
+
+  // repeated float loss_weight = 5;
+  for (int i = 0; i < this->loss_weight_size(); i++) {
+    ::google::protobuf::internal::WireFormatLite::WriteFloat(
+      5, this->loss_weight(i), output);
+  }
+
+  // repeated .caffe.ParamSpec param = 6;
+  for (unsigned int i = 0, n = this->param_size(); i < n; i++) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      6, this->param(i), output);
+  }
+
+  // repeated .caffe.BlobProto blobs = 7;
+  for (unsigned int i = 0, n = this->blobs_size(); i < n; i++) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      7, this->blobs(i), output);
+  }
+
+  // repeated .caffe.NetStateRule include = 8;
+  for (unsigned int i = 0, n = this->include_size(); i < n; i++) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      8, this->include(i), output);
+  }
+
+  // repeated .caffe.NetStateRule exclude = 9;
+  for (unsigned int i = 0, n = this->exclude_size(); i < n; i++) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      9, this->exclude(i), output);
+  }
+
+  // optional .caffe.Phase phase = 10;
+  if (has_phase()) {
+    ::google::protobuf::internal::WireFormatLite::WriteEnum(
+      10, this->phase(), output);
+  }
+
+  // repeated bool propagate_down = 11;
+  for (int i = 0; i < this->propagate_down_size(); i++) {
+    ::google::protobuf::internal::WireFormatLite::WriteBool(
+      11, this->propagate_down(i), output);
+  }
+
+  // optional .caffe.TransformationParameter transform_param = 100;
+  if (has_transform_param()) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      100, *this->transform_param_, output);
+  }
+
+  // optional .caffe.LossParameter loss_param = 101;
+  if (has_loss_param()) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      101, *this->loss_param_, output);
+  }
+
+  // optional .caffe.AccuracyParameter accuracy_param = 102;
+  if (has_accuracy_param()) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      102, *this->accuracy_param_, output);
+  }
+
+  // optional .caffe.ArgMaxParameter argmax_param = 103;
+  if (has_argmax_param()) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      103, *this->argmax_param_, output);
+  }
+
+  // optional .caffe.ConcatParameter concat_param = 104;
+  if (has_concat_param()) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      104, *this->concat_param_, output);
+  }
+
+  // optional .caffe.ContrastiveLossParameter contrastive_loss_param = 105;
+  if (has_contrastive_loss_param()) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      105, *this->contrastive_loss_param_, output);
+  }
+
+  // optional .caffe.ConvolutionParameter convolution_param = 106;
+  if (has_convolution_param()) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      106, *this->convolution_param_, output);
+  }
+
+  // optional .caffe.DataParameter data_param = 107;
+  if (has_data_param()) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      107, *this->data_param_, output);
+  }
+
+  // optional .caffe.DropoutParameter dropout_param = 108;
+  if (has_dropout_param()) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      108, *this->dropout_param_, output);
+  }
+
+  // optional .caffe.DummyDataParameter dummy_data_param = 109;
+  if (has_dummy_data_param()) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      109, *this->dummy_data_param_, output);
+  }
+
+  // optional .caffe.EltwiseParameter eltwise_param = 110;
+  if (has_eltwise_param()) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      110, *this->eltwise_param_, output);
+  }
+
+  // optional .caffe.ExpParameter exp_param = 111;
+  if (has_exp_param()) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      111, *this->exp_param_, output);
+  }
+
+  // optional .caffe.HDF5DataParameter hdf5_data_param = 112;
+  if (has_hdf5_data_param()) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      112, *this->hdf5_data_param_, output);
+  }
+
+  // optional .caffe.HDF5OutputParameter hdf5_output_param = 113;
+  if (has_hdf5_output_param()) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      113, *this->hdf5_output_param_, output);
+  }
+
+  // optional .caffe.HingeLossParameter hinge_loss_param = 114;
+  if (has_hinge_loss_param()) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      114, *this->hinge_loss_param_, output);
+  }
+
+  // optional .caffe.ImageDataParameter image_data_param = 115;
+  if (has_image_data_param()) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      115, *this->image_data_param_, output);
+  }
+
+  // optional .caffe.InfogainLossParameter infogain_loss_param = 116;
+  if (has_infogain_loss_param()) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      116, *this->infogain_loss_param_, output);
+  }
+
+  // optional .caffe.InnerProductParameter inner_product_param = 117;
+  if (has_inner_product_param()) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      117, *this->inner_product_param_, output);
+  }
+
+  // optional .caffe.LRNParameter lrn_param = 118;
+  if (has_lrn_param()) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      118, *this->lrn_param_, output);
+  }
+
+  // optional .caffe.MemoryDataParameter memory_data_param = 119;
+  if (has_memory_data_param()) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      119, *this->memory_data_param_, output);
+  }
+
+  // optional .caffe.MVNParameter mvn_param = 120;
+  if (has_mvn_param()) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      120, *this->mvn_param_, output);
+  }
+
+  // optional .caffe.PoolingParameter pooling_param = 121;
+  if (has_pooling_param()) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      121, *this->pooling_param_, output);
+  }
+
+  // optional .caffe.PowerParameter power_param = 122;
+  if (has_power_param()) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      122, *this->power_param_, output);
+  }
+
+  // optional .caffe.ReLUParameter relu_param = 123;
+  if (has_relu_param()) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      123, *this->relu_param_, output);
+  }
+
+  // optional .caffe.SigmoidParameter sigmoid_param = 124;
+  if (has_sigmoid_param()) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      124, *this->sigmoid_param_, output);
+  }
+
+  // optional .caffe.SoftmaxParameter softmax_param = 125;
+  if (has_softmax_param()) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      125, *this->softmax_param_, output);
+  }
+
+  // optional .caffe.SliceParameter slice_param = 126;
+  if (has_slice_param()) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      126, *this->slice_param_, output);
+  }
+
+  // optional .caffe.TanHParameter tanh_param = 127;
+  if (has_tanh_param()) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      127, *this->tanh_param_, output);
+  }
+
+  // optional .caffe.ThresholdParameter threshold_param = 128;
+  if (has_threshold_param()) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      128, *this->threshold_param_, output);
+  }
+
+  // optional .caffe.WindowDataParameter window_data_param = 129;
+  if (has_window_data_param()) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      129, *this->window_data_param_, output);
+  }
+
+  // optional .caffe.PythonParameter python_param = 130;
+  if (has_python_param()) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      130, *this->python_param_, output);
+  }
+
+  // optional .caffe.PReLUParameter prelu_param = 131;
+  if (has_prelu_param()) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      131, *this->prelu_param_, output);
+  }
+
+  // optional .caffe.SPPParameter spp_param = 132;
+  if (has_spp_param()) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      132, *this->spp_param_, output);
+  }
+
+  // optional .caffe.ReshapeParameter reshape_param = 133;
+  if (has_reshape_param()) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      133, *this->reshape_param_, output);
+  }
+
+  // optional .caffe.LogParameter log_param = 134;
+  if (has_log_param()) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      134, *this->log_param_, output);
+  }
+
+  // optional .caffe.FlattenParameter flatten_param = 135;
+  if (has_flatten_param()) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      135, *this->flatten_param_, output);
+  }
+
+  // optional .caffe.ReductionParameter reduction_param = 136;
+  if (has_reduction_param()) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      136, *this->reduction_param_, output);
+  }
+
+  // optional .caffe.CropParameter crop_param = 137;
+  if (has_crop_param()) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      137, *this->crop_param_, output);
+  }
+
+  // optional .caffe.PermuteParameter permute_param = 138;
+  if (has_permute_param()) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      138, *this->permute_param_, output);
+  }
+
+  // optional .caffe.NormalizeBBoxParameter normalize_bbox_param = 139;
+  if (has_normalize_bbox_param()) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      139, *this->normalize_bbox_param_, output);
+  }
+
+  // optional .caffe.PriorBoxParameter prior_box_param = 140;
+  if (has_prior_box_param()) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      140, *this->prior_box_param_, output);
+  }
+
+  // optional .caffe.DetectionOutputParameter detection_output_param = 141;
+  if (has_detection_output_param()) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      141, *this->detection_output_param_, output);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
+        unknown_fields(), output);
+  }
+  // @@protoc_insertion_point(serialize_end:caffe.LayerParameter)
+}
+
+::google::protobuf::uint8* LayerParameter::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
+  (void)deterministic; // Unused
+  // @@protoc_insertion_point(serialize_to_array_start:caffe.LayerParameter)
+  // optional string name = 1;
+  if (has_name()) {
+    ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->name().data(), this->name().length(),
+      ::google::protobuf::internal::WireFormat::SERIALIZE,
+      "caffe.LayerParameter.name");
+    target =
+      ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
+        1, this->name(), target);
+  }
+
+  // optional string type = 2;
+  if (has_type()) {
+    ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->type().data(), this->type().length(),
+      ::google::protobuf::internal::WireFormat::SERIALIZE,
+      "caffe.LayerParameter.type");
+    target =
+      ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
+        2, this->type(), target);
+  }
+
+  // repeated string bottom = 3;
+  for (int i = 0; i < this->bottom_size(); i++) {
+    ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->bottom(i).data(), this->bottom(i).length(),
+      ::google::protobuf::internal::WireFormat::SERIALIZE,
+      "caffe.LayerParameter.bottom");
+    target = ::google::protobuf::internal::WireFormatLite::
+      WriteStringToArray(3, this->bottom(i), target);
+  }
+
+  // repeated string top = 4;
+  for (int i = 0; i < this->top_size(); i++) {
+    ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->top(i).data(), this->top(i).length(),
+      ::google::protobuf::internal::WireFormat::SERIALIZE,
+      "caffe.LayerParameter.top");
+    target = ::google::protobuf::internal::WireFormatLite::
+      WriteStringToArray(4, this->top(i), target);
+  }
+
+  // repeated float loss_weight = 5;
+  for (int i = 0; i < this->loss_weight_size(); i++) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      WriteFloatToArray(5, this->loss_weight(i), target);
+  }
+
+  // repeated .caffe.ParamSpec param = 6;
+  for (unsigned int i = 0, n = this->param_size(); i < n; i++) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        6, this->param(i), false, target);
+  }
+
+  // repeated .caffe.BlobProto blobs = 7;
+  for (unsigned int i = 0, n = this->blobs_size(); i < n; i++) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        7, this->blobs(i), false, target);
+  }
+
+  // repeated .caffe.NetStateRule include = 8;
+  for (unsigned int i = 0, n = this->include_size(); i < n; i++) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        8, this->include(i), false, target);
+  }
+
+  // repeated .caffe.NetStateRule exclude = 9;
+  for (unsigned int i = 0, n = this->exclude_size(); i < n; i++) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        9, this->exclude(i), false, target);
+  }
+
+  // optional .caffe.Phase phase = 10;
+  if (has_phase()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteEnumToArray(
+      10, this->phase(), target);
+  }
+
+  // repeated bool propagate_down = 11;
+  for (int i = 0; i < this->propagate_down_size(); i++) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      WriteBoolToArray(11, this->propagate_down(i), target);
+  }
+
+  // optional .caffe.TransformationParameter transform_param = 100;
+  if (has_transform_param()) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        100, *this->transform_param_, false, target);
+  }
+
+  // optional .caffe.LossParameter loss_param = 101;
+  if (has_loss_param()) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        101, *this->loss_param_, false, target);
+  }
+
+  // optional .caffe.AccuracyParameter accuracy_param = 102;
+  if (has_accuracy_param()) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        102, *this->accuracy_param_, false, target);
+  }
+
+  // optional .caffe.ArgMaxParameter argmax_param = 103;
+  if (has_argmax_param()) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        103, *this->argmax_param_, false, target);
+  }
+
+  // optional .caffe.ConcatParameter concat_param = 104;
+  if (has_concat_param()) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        104, *this->concat_param_, false, target);
+  }
+
+  // optional .caffe.ContrastiveLossParameter contrastive_loss_param = 105;
+  if (has_contrastive_loss_param()) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        105, *this->contrastive_loss_param_, false, target);
+  }
+
+  // optional .caffe.ConvolutionParameter convolution_param = 106;
+  if (has_convolution_param()) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        106, *this->convolution_param_, false, target);
+  }
+
+  // optional .caffe.DataParameter data_param = 107;
+  if (has_data_param()) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        107, *this->data_param_, false, target);
+  }
+
+  // optional .caffe.DropoutParameter dropout_param = 108;
+  if (has_dropout_param()) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        108, *this->dropout_param_, false, target);
+  }
+
+  // optional .caffe.DummyDataParameter dummy_data_param = 109;
+  if (has_dummy_data_param()) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        109, *this->dummy_data_param_, false, target);
+  }
+
+  // optional .caffe.EltwiseParameter eltwise_param = 110;
+  if (has_eltwise_param()) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        110, *this->eltwise_param_, false, target);
+  }
+
+  // optional .caffe.ExpParameter exp_param = 111;
+  if (has_exp_param()) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        111, *this->exp_param_, false, target);
+  }
+
+  // optional .caffe.HDF5DataParameter hdf5_data_param = 112;
+  if (has_hdf5_data_param()) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        112, *this->hdf5_data_param_, false, target);
+  }
+
+  // optional .caffe.HDF5OutputParameter hdf5_output_param = 113;
+  if (has_hdf5_output_param()) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        113, *this->hdf5_output_param_, false, target);
+  }
+
+  // optional .caffe.HingeLossParameter hinge_loss_param = 114;
+  if (has_hinge_loss_param()) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        114, *this->hinge_loss_param_, false, target);
+  }
+
+  // optional .caffe.ImageDataParameter image_data_param = 115;
+  if (has_image_data_param()) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        115, *this->image_data_param_, false, target);
+  }
+
+  // optional .caffe.InfogainLossParameter infogain_loss_param = 116;
+  if (has_infogain_loss_param()) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        116, *this->infogain_loss_param_, false, target);
+  }
+
+  // optional .caffe.InnerProductParameter inner_product_param = 117;
+  if (has_inner_product_param()) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        117, *this->inner_product_param_, false, target);
+  }
+
+  // optional .caffe.LRNParameter lrn_param = 118;
+  if (has_lrn_param()) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        118, *this->lrn_param_, false, target);
+  }
+
+  // optional .caffe.MemoryDataParameter memory_data_param = 119;
+  if (has_memory_data_param()) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        119, *this->memory_data_param_, false, target);
+  }
+
+  // optional .caffe.MVNParameter mvn_param = 120;
+  if (has_mvn_param()) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        120, *this->mvn_param_, false, target);
+  }
+
+  // optional .caffe.PoolingParameter pooling_param = 121;
+  if (has_pooling_param()) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        121, *this->pooling_param_, false, target);
+  }
+
+  // optional .caffe.PowerParameter power_param = 122;
+  if (has_power_param()) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        122, *this->power_param_, false, target);
+  }
+
+  // optional .caffe.ReLUParameter relu_param = 123;
+  if (has_relu_param()) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        123, *this->relu_param_, false, target);
+  }
+
+  // optional .caffe.SigmoidParameter sigmoid_param = 124;
+  if (has_sigmoid_param()) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        124, *this->sigmoid_param_, false, target);
+  }
+
+  // optional .caffe.SoftmaxParameter softmax_param = 125;
+  if (has_softmax_param()) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        125, *this->softmax_param_, false, target);
+  }
+
+  // optional .caffe.SliceParameter slice_param = 126;
+  if (has_slice_param()) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        126, *this->slice_param_, false, target);
+  }
+
+  // optional .caffe.TanHParameter tanh_param = 127;
+  if (has_tanh_param()) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        127, *this->tanh_param_, false, target);
+  }
+
+  // optional .caffe.ThresholdParameter threshold_param = 128;
+  if (has_threshold_param()) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        128, *this->threshold_param_, false, target);
+  }
+
+  // optional .caffe.WindowDataParameter window_data_param = 129;
+  if (has_window_data_param()) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        129, *this->window_data_param_, false, target);
+  }
+
+  // optional .caffe.PythonParameter python_param = 130;
+  if (has_python_param()) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        130, *this->python_param_, false, target);
+  }
+
+  // optional .caffe.PReLUParameter prelu_param = 131;
+  if (has_prelu_param()) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        131, *this->prelu_param_, false, target);
+  }
+
+  // optional .caffe.SPPParameter spp_param = 132;
+  if (has_spp_param()) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        132, *this->spp_param_, false, target);
+  }
+
+  // optional .caffe.ReshapeParameter reshape_param = 133;
+  if (has_reshape_param()) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        133, *this->reshape_param_, false, target);
+  }
+
+  // optional .caffe.LogParameter log_param = 134;
+  if (has_log_param()) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        134, *this->log_param_, false, target);
+  }
+
+  // optional .caffe.FlattenParameter flatten_param = 135;
+  if (has_flatten_param()) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        135, *this->flatten_param_, false, target);
+  }
+
+  // optional .caffe.ReductionParameter reduction_param = 136;
+  if (has_reduction_param()) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        136, *this->reduction_param_, false, target);
+  }
+
+  // optional .caffe.CropParameter crop_param = 137;
+  if (has_crop_param()) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        137, *this->crop_param_, false, target);
+  }
+
+  // optional .caffe.PermuteParameter permute_param = 138;
+  if (has_permute_param()) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        138, *this->permute_param_, false, target);
+  }
+
+  // optional .caffe.NormalizeBBoxParameter normalize_bbox_param = 139;
+  if (has_normalize_bbox_param()) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        139, *this->normalize_bbox_param_, false, target);
+  }
+
+  // optional .caffe.PriorBoxParameter prior_box_param = 140;
+  if (has_prior_box_param()) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        140, *this->prior_box_param_, false, target);
+  }
+
+  // optional .caffe.DetectionOutputParameter detection_output_param = 141;
+  if (has_detection_output_param()) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        141, *this->detection_output_param_, false, target);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
+        unknown_fields(), target);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:caffe.LayerParameter)
+  return target;
+}
+
+size_t LayerParameter::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:caffe.LayerParameter)
+  size_t total_size = 0;
+
+  if (_has_bits_[0 / 32] & 19u) {
+    // optional string name = 1;
+    if (has_name()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::StringSize(
+          this->name());
+    }
+
+    // optional string type = 2;
+    if (has_type()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::StringSize(
+          this->type());
+    }
+
+    // optional .caffe.Phase phase = 10;
+    if (has_phase()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::EnumSize(this->phase());
+    }
+
+  }
+  if (_has_bits_[11 / 32] & 63488u) {
+    // optional .caffe.TransformationParameter transform_param = 100;
+    if (has_transform_param()) {
+      total_size += 2 +
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          *this->transform_param_);
+    }
+
+    // optional .caffe.LossParameter loss_param = 101;
+    if (has_loss_param()) {
+      total_size += 2 +
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          *this->loss_param_);
+    }
+
+    // optional .caffe.AccuracyParameter accuracy_param = 102;
+    if (has_accuracy_param()) {
+      total_size += 2 +
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          *this->accuracy_param_);
+    }
+
+    // optional .caffe.ArgMaxParameter argmax_param = 103;
+    if (has_argmax_param()) {
+      total_size += 2 +
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          *this->argmax_param_);
+    }
+
+    // optional .caffe.ConcatParameter concat_param = 104;
+    if (has_concat_param()) {
+      total_size += 2 +
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          *this->concat_param_);
+    }
+
+  }
+  if (_has_bits_[16 / 32] & 16711680u) {
+    // optional .caffe.ContrastiveLossParameter contrastive_loss_param = 105;
+    if (has_contrastive_loss_param()) {
+      total_size += 2 +
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          *this->contrastive_loss_param_);
+    }
+
+    // optional .caffe.ConvolutionParameter convolution_param = 106;
+    if (has_convolution_param()) {
+      total_size += 2 +
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          *this->convolution_param_);
+    }
+
+    // optional .caffe.CropParameter crop_param = 137;
+    if (has_crop_param()) {
+      total_size += 2 +
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          *this->crop_param_);
+    }
+
+    // optional .caffe.DataParameter data_param = 107;
+    if (has_data_param()) {
+      total_size += 2 +
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          *this->data_param_);
+    }
+
+    // optional .caffe.DetectionOutputParameter detection_output_param = 141;
+    if (has_detection_output_param()) {
+      total_size += 2 +
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          *this->detection_output_param_);
+    }
+
+    // optional .caffe.DropoutParameter dropout_param = 108;
+    if (has_dropout_param()) {
+      total_size += 2 +
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          *this->dropout_param_);
+    }
+
+    // optional .caffe.DummyDataParameter dummy_data_param = 109;
+    if (has_dummy_data_param()) {
+      total_size += 2 +
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          *this->dummy_data_param_);
+    }
+
+    // optional .caffe.EltwiseParameter eltwise_param = 110;
+    if (has_eltwise_param()) {
+      total_size += 2 +
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          *this->eltwise_param_);
+    }
+
+  }
+  if (_has_bits_[24 / 32] & 4278190080u) {
+    // optional .caffe.ExpParameter exp_param = 111;
+    if (has_exp_param()) {
+      total_size += 2 +
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          *this->exp_param_);
+    }
+
+    // optional .caffe.FlattenParameter flatten_param = 135;
+    if (has_flatten_param()) {
+      total_size += 2 +
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          *this->flatten_param_);
+    }
+
+    // optional .caffe.HDF5DataParameter hdf5_data_param = 112;
+    if (has_hdf5_data_param()) {
+      total_size += 2 +
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          *this->hdf5_data_param_);
+    }
+
+    // optional .caffe.HDF5OutputParameter hdf5_output_param = 113;
+    if (has_hdf5_output_param()) {
+      total_size += 2 +
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          *this->hdf5_output_param_);
+    }
+
+    // optional .caffe.HingeLossParameter hinge_loss_param = 114;
+    if (has_hinge_loss_param()) {
+      total_size += 2 +
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          *this->hinge_loss_param_);
+    }
+
+    // optional .caffe.ImageDataParameter image_data_param = 115;
+    if (has_image_data_param()) {
+      total_size += 2 +
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          *this->image_data_param_);
+    }
+
+    // optional .caffe.InfogainLossParameter infogain_loss_param = 116;
+    if (has_infogain_loss_param()) {
+      total_size += 2 +
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          *this->infogain_loss_param_);
+    }
+
+    // optional .caffe.InnerProductParameter inner_product_param = 117;
+    if (has_inner_product_param()) {
+      total_size += 2 +
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          *this->inner_product_param_);
+    }
+
+  }
+  if (_has_bits_[32 / 32] & 255u) {
+    // optional .caffe.LogParameter log_param = 134;
+    if (has_log_param()) {
+      total_size += 2 +
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          *this->log_param_);
+    }
+
+    // optional .caffe.LRNParameter lrn_param = 118;
+    if (has_lrn_param()) {
+      total_size += 2 +
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          *this->lrn_param_);
+    }
+
+    // optional .caffe.MemoryDataParameter memory_data_param = 119;
+    if (has_memory_data_param()) {
+      total_size += 2 +
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          *this->memory_data_param_);
+    }
+
+    // optional .caffe.MVNParameter mvn_param = 120;
+    if (has_mvn_param()) {
+      total_size += 2 +
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          *this->mvn_param_);
+    }
+
+    // optional .caffe.NormalizeBBoxParameter normalize_bbox_param = 139;
+    if (has_normalize_bbox_param()) {
+      total_size += 2 +
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          *this->normalize_bbox_param_);
+    }
+
+    // optional .caffe.PermuteParameter permute_param = 138;
+    if (has_permute_param()) {
+      total_size += 2 +
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          *this->permute_param_);
+    }
+
+    // optional .caffe.PoolingParameter pooling_param = 121;
+    if (has_pooling_param()) {
+      total_size += 2 +
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          *this->pooling_param_);
+    }
+
+    // optional .caffe.PowerParameter power_param = 122;
+    if (has_power_param()) {
+      total_size += 2 +
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          *this->power_param_);
+    }
+
+  }
+  if (_has_bits_[40 / 32] & 65280u) {
+    // optional .caffe.PReLUParameter prelu_param = 131;
+    if (has_prelu_param()) {
+      total_size += 2 +
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          *this->prelu_param_);
+    }
+
+    // optional .caffe.PriorBoxParameter prior_box_param = 140;
+    if (has_prior_box_param()) {
+      total_size += 2 +
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          *this->prior_box_param_);
+    }
+
+    // optional .caffe.PythonParameter python_param = 130;
+    if (has_python_param()) {
+      total_size += 2 +
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          *this->python_param_);
+    }
+
+    // optional .caffe.ReductionParameter reduction_param = 136;
+    if (has_reduction_param()) {
+      total_size += 2 +
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          *this->reduction_param_);
+    }
+
+    // optional .caffe.ReLUParameter relu_param = 123;
+    if (has_relu_param()) {
+      total_size += 2 +
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          *this->relu_param_);
+    }
+
+    // optional .caffe.ReshapeParameter reshape_param = 133;
+    if (has_reshape_param()) {
+      total_size += 2 +
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          *this->reshape_param_);
+    }
+
+    // optional .caffe.SigmoidParameter sigmoid_param = 124;
+    if (has_sigmoid_param()) {
+      total_size += 2 +
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          *this->sigmoid_param_);
+    }
+
+    // optional .caffe.SliceParameter slice_param = 126;
+    if (has_slice_param()) {
+      total_size += 2 +
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          *this->slice_param_);
+    }
+
+  }
+  if (_has_bits_[48 / 32] & 2031616u) {
+    // optional .caffe.SoftmaxParameter softmax_param = 125;
+    if (has_softmax_param()) {
+      total_size += 2 +
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          *this->softmax_param_);
+    }
+
+    // optional .caffe.SPPParameter spp_param = 132;
+    if (has_spp_param()) {
+      total_size += 2 +
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          *this->spp_param_);
+    }
+
+    // optional .caffe.TanHParameter tanh_param = 127;
+    if (has_tanh_param()) {
+      total_size += 2 +
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          *this->tanh_param_);
+    }
+
+    // optional .caffe.ThresholdParameter threshold_param = 128;
+    if (has_threshold_param()) {
+      total_size += 2 +
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          *this->threshold_param_);
+    }
+
+    // optional .caffe.WindowDataParameter window_data_param = 129;
+    if (has_window_data_param()) {
+      total_size += 2 +
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          *this->window_data_param_);
+    }
+
+  }
+  // repeated string bottom = 3;
+  total_size += 1 *
+      ::google::protobuf::internal::FromIntSize(this->bottom_size());
+  for (int i = 0; i < this->bottom_size(); i++) {
+    total_size += ::google::protobuf::internal::WireFormatLite::StringSize(
+      this->bottom(i));
+  }
+
+  // repeated string top = 4;
+  total_size += 1 *
+      ::google::protobuf::internal::FromIntSize(this->top_size());
+  for (int i = 0; i < this->top_size(); i++) {
+    total_size += ::google::protobuf::internal::WireFormatLite::StringSize(
+      this->top(i));
+  }
+
+  // repeated float loss_weight = 5;
+  {
+    size_t data_size = 0;
+    unsigned int count = this->loss_weight_size();
+    data_size = 4UL * count;
+    total_size += 1 *
+                  ::google::protobuf::internal::FromIntSize(this->loss_weight_size());
+    total_size += data_size;
+  }
+
+  // repeated .caffe.ParamSpec param = 6;
+  {
+    unsigned int count = this->param_size();
+    total_size += 1UL * count;
+    for (unsigned int i = 0; i < count; i++) {
+      total_size +=
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          this->param(i));
+    }
+  }
+
+  // repeated .caffe.BlobProto blobs = 7;
+  {
+    unsigned int count = this->blobs_size();
+    total_size += 1UL * count;
+    for (unsigned int i = 0; i < count; i++) {
+      total_size +=
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          this->blobs(i));
+    }
+  }
+
+  // repeated bool propagate_down = 11;
+  {
+    size_t data_size = 0;
+    unsigned int count = this->propagate_down_size();
+    data_size = 1UL * count;
+    total_size += 1 *
+                  ::google::protobuf::internal::FromIntSize(this->propagate_down_size());
+    total_size += data_size;
+  }
+
+  // repeated .caffe.NetStateRule include = 8;
+  {
+    unsigned int count = this->include_size();
+    total_size += 1UL * count;
+    for (unsigned int i = 0; i < count; i++) {
+      total_size +=
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          this->include(i));
+    }
+  }
+
+  // repeated .caffe.NetStateRule exclude = 9;
+  {
+    unsigned int count = this->exclude_size();
+    total_size += 1UL * count;
+    for (unsigned int i = 0; i < count; i++) {
+      total_size +=
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          this->exclude(i));
+    }
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    total_size +=
+      ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
+        unknown_fields());
+  }
+  int cached_size = ::google::protobuf::internal::ToCachedSize(total_size);
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = cached_size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+  return total_size;
+}
+
+void LayerParameter::MergeFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_merge_from_start:caffe.LayerParameter)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const LayerParameter* source =
+      ::google::protobuf::internal::DynamicCastToGenerated<const LayerParameter>(
+          &from);
+  if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:caffe.LayerParameter)
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:caffe.LayerParameter)
+    UnsafeMergeFrom(*source);
+  }
+}
+
+void LayerParameter::MergeFrom(const LayerParameter& from) {
+// @@protoc_insertion_point(class_specific_merge_from_start:caffe.LayerParameter)
+  if (GOOGLE_PREDICT_TRUE(&from != this)) {
+    UnsafeMergeFrom(from);
+  } else {
+    MergeFromFail(__LINE__);
+  }
+}
+
+void LayerParameter::UnsafeMergeFrom(const LayerParameter& from) {
+  GOOGLE_DCHECK(&from != this);
+  bottom_.UnsafeMergeFrom(from.bottom_);
+  top_.UnsafeMergeFrom(from.top_);
+  loss_weight_.UnsafeMergeFrom(from.loss_weight_);
+  param_.MergeFrom(from.param_);
+  blobs_.MergeFrom(from.blobs_);
+  propagate_down_.UnsafeMergeFrom(from.propagate_down_);
+  include_.MergeFrom(from.include_);
+  exclude_.MergeFrom(from.exclude_);
+  if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+    if (from.has_name()) {
+      set_has_name();
+      name_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.name_);
+    }
+    if (from.has_type()) {
+      set_has_type();
+      type_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.type_);
+    }
+    if (from.has_phase()) {
+      set_phase(from.phase());
+    }
+  }
+  if (from._has_bits_[11 / 32] & (0xffu << (11 % 32))) {
+    if (from.has_transform_param()) {
+      mutable_transform_param()->::caffe::TransformationParameter::MergeFrom(from.transform_param());
+    }
+    if (from.has_loss_param()) {
+      mutable_loss_param()->::caffe::LossParameter::MergeFrom(from.loss_param());
+    }
+    if (from.has_accuracy_param()) {
+      mutable_accuracy_param()->::caffe::AccuracyParameter::MergeFrom(from.accuracy_param());
+    }
+    if (from.has_argmax_param()) {
+      mutable_argmax_param()->::caffe::ArgMaxParameter::MergeFrom(from.argmax_param());
+    }
+    if (from.has_concat_param()) {
+      mutable_concat_param()->::caffe::ConcatParameter::MergeFrom(from.concat_param());
+    }
+  }
+  if (from._has_bits_[16 / 32] & (0xffu << (16 % 32))) {
+    if (from.has_contrastive_loss_param()) {
+      mutable_contrastive_loss_param()->::caffe::ContrastiveLossParameter::MergeFrom(from.contrastive_loss_param());
+    }
+    if (from.has_convolution_param()) {
+      mutable_convolution_param()->::caffe::ConvolutionParameter::MergeFrom(from.convolution_param());
+    }
+    if (from.has_crop_param()) {
+      mutable_crop_param()->::caffe::CropParameter::MergeFrom(from.crop_param());
+    }
+    if (from.has_data_param()) {
+      mutable_data_param()->::caffe::DataParameter::MergeFrom(from.data_param());
+    }
+    if (from.has_detection_output_param()) {
+      mutable_detection_output_param()->::caffe::DetectionOutputParameter::MergeFrom(from.detection_output_param());
+    }
+    if (from.has_dropout_param()) {
+      mutable_dropout_param()->::caffe::DropoutParameter::MergeFrom(from.dropout_param());
+    }
+    if (from.has_dummy_data_param()) {
+      mutable_dummy_data_param()->::caffe::DummyDataParameter::MergeFrom(from.dummy_data_param());
+    }
+    if (from.has_eltwise_param()) {
+      mutable_eltwise_param()->::caffe::EltwiseParameter::MergeFrom(from.eltwise_param());
+    }
+  }
+  if (from._has_bits_[24 / 32] & (0xffu << (24 % 32))) {
+    if (from.has_exp_param()) {
+      mutable_exp_param()->::caffe::ExpParameter::MergeFrom(from.exp_param());
+    }
+    if (from.has_flatten_param()) {
+      mutable_flatten_param()->::caffe::FlattenParameter::MergeFrom(from.flatten_param());
+    }
+    if (from.has_hdf5_data_param()) {
+      mutable_hdf5_data_param()->::caffe::HDF5DataParameter::MergeFrom(from.hdf5_data_param());
+    }
+    if (from.has_hdf5_output_param()) {
+      mutable_hdf5_output_param()->::caffe::HDF5OutputParameter::MergeFrom(from.hdf5_output_param());
+    }
+    if (from.has_hinge_loss_param()) {
+      mutable_hinge_loss_param()->::caffe::HingeLossParameter::MergeFrom(from.hinge_loss_param());
+    }
+    if (from.has_image_data_param()) {
+      mutable_image_data_param()->::caffe::ImageDataParameter::MergeFrom(from.image_data_param());
+    }
+    if (from.has_infogain_loss_param()) {
+      mutable_infogain_loss_param()->::caffe::InfogainLossParameter::MergeFrom(from.infogain_loss_param());
+    }
+    if (from.has_inner_product_param()) {
+      mutable_inner_product_param()->::caffe::InnerProductParameter::MergeFrom(from.inner_product_param());
+    }
+  }
+  if (from._has_bits_[32 / 32] & (0xffu << (32 % 32))) {
+    if (from.has_log_param()) {
+      mutable_log_param()->::caffe::LogParameter::MergeFrom(from.log_param());
+    }
+    if (from.has_lrn_param()) {
+      mutable_lrn_param()->::caffe::LRNParameter::MergeFrom(from.lrn_param());
+    }
+    if (from.has_memory_data_param()) {
+      mutable_memory_data_param()->::caffe::MemoryDataParameter::MergeFrom(from.memory_data_param());
+    }
+    if (from.has_mvn_param()) {
+      mutable_mvn_param()->::caffe::MVNParameter::MergeFrom(from.mvn_param());
+    }
+    if (from.has_normalize_bbox_param()) {
+      mutable_normalize_bbox_param()->::caffe::NormalizeBBoxParameter::MergeFrom(from.normalize_bbox_param());
+    }
+    if (from.has_permute_param()) {
+      mutable_permute_param()->::caffe::PermuteParameter::MergeFrom(from.permute_param());
+    }
+    if (from.has_pooling_param()) {
+      mutable_pooling_param()->::caffe::PoolingParameter::MergeFrom(from.pooling_param());
+    }
+    if (from.has_power_param()) {
+      mutable_power_param()->::caffe::PowerParameter::MergeFrom(from.power_param());
+    }
+  }
+  if (from._has_bits_[40 / 32] & (0xffu << (40 % 32))) {
+    if (from.has_prelu_param()) {
+      mutable_prelu_param()->::caffe::PReLUParameter::MergeFrom(from.prelu_param());
+    }
+    if (from.has_prior_box_param()) {
+      mutable_prior_box_param()->::caffe::PriorBoxParameter::MergeFrom(from.prior_box_param());
+    }
+    if (from.has_python_param()) {
+      mutable_python_param()->::caffe::PythonParameter::MergeFrom(from.python_param());
+    }
+    if (from.has_reduction_param()) {
+      mutable_reduction_param()->::caffe::ReductionParameter::MergeFrom(from.reduction_param());
+    }
+    if (from.has_relu_param()) {
+      mutable_relu_param()->::caffe::ReLUParameter::MergeFrom(from.relu_param());
+    }
+    if (from.has_reshape_param()) {
+      mutable_reshape_param()->::caffe::ReshapeParameter::MergeFrom(from.reshape_param());
+    }
+    if (from.has_sigmoid_param()) {
+      mutable_sigmoid_param()->::caffe::SigmoidParameter::MergeFrom(from.sigmoid_param());
+    }
+    if (from.has_slice_param()) {
+      mutable_slice_param()->::caffe::SliceParameter::MergeFrom(from.slice_param());
+    }
+  }
+  if (from._has_bits_[48 / 32] & (0xffu << (48 % 32))) {
+    if (from.has_softmax_param()) {
+      mutable_softmax_param()->::caffe::SoftmaxParameter::MergeFrom(from.softmax_param());
+    }
+    if (from.has_spp_param()) {
+      mutable_spp_param()->::caffe::SPPParameter::MergeFrom(from.spp_param());
+    }
+    if (from.has_tanh_param()) {
+      mutable_tanh_param()->::caffe::TanHParameter::MergeFrom(from.tanh_param());
+    }
+    if (from.has_threshold_param()) {
+      mutable_threshold_param()->::caffe::ThresholdParameter::MergeFrom(from.threshold_param());
+    }
+    if (from.has_window_data_param()) {
+      mutable_window_data_param()->::caffe::WindowDataParameter::MergeFrom(from.window_data_param());
+    }
+  }
+  if (from._internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::UnknownFieldSet::MergeToInternalMetdata(
+      from.unknown_fields(), &_internal_metadata_);
+  }
+}
+
+void LayerParameter::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:caffe.LayerParameter)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void LayerParameter::CopyFrom(const LayerParameter& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:caffe.LayerParameter)
+  if (&from == this) return;
+  Clear();
+  UnsafeMergeFrom(from);
+}
+
+bool LayerParameter::IsInitialized() const {
+
+  return true;
+}
+
+void LayerParameter::Swap(LayerParameter* other) {
+  if (other == this) return;
+  InternalSwap(other);
+}
+void LayerParameter::InternalSwap(LayerParameter* other) {
+  name_.Swap(&other->name_);
+  type_.Swap(&other->type_);
+  bottom_.UnsafeArenaSwap(&other->bottom_);
+  top_.UnsafeArenaSwap(&other->top_);
+  std::swap(phase_, other->phase_);
+  loss_weight_.UnsafeArenaSwap(&other->loss_weight_);
+  param_.UnsafeArenaSwap(&other->param_);
+  blobs_.UnsafeArenaSwap(&other->blobs_);
+  propagate_down_.UnsafeArenaSwap(&other->propagate_down_);
+  include_.UnsafeArenaSwap(&other->include_);
+  exclude_.UnsafeArenaSwap(&other->exclude_);
+  std::swap(transform_param_, other->transform_param_);
+  std::swap(loss_param_, other->loss_param_);
+  std::swap(accuracy_param_, other->accuracy_param_);
+  std::swap(argmax_param_, other->argmax_param_);
+  std::swap(concat_param_, other->concat_param_);
+  std::swap(contrastive_loss_param_, other->contrastive_loss_param_);
+  std::swap(convolution_param_, other->convolution_param_);
+  std::swap(crop_param_, other->crop_param_);
+  std::swap(data_param_, other->data_param_);
+  std::swap(detection_output_param_, other->detection_output_param_);
+  std::swap(dropout_param_, other->dropout_param_);
+  std::swap(dummy_data_param_, other->dummy_data_param_);
+  std::swap(eltwise_param_, other->eltwise_param_);
+  std::swap(exp_param_, other->exp_param_);
+  std::swap(flatten_param_, other->flatten_param_);
+  std::swap(hdf5_data_param_, other->hdf5_data_param_);
+  std::swap(hdf5_output_param_, other->hdf5_output_param_);
+  std::swap(hinge_loss_param_, other->hinge_loss_param_);
+  std::swap(image_data_param_, other->image_data_param_);
+  std::swap(infogain_loss_param_, other->infogain_loss_param_);
+  std::swap(inner_product_param_, other->inner_product_param_);
+  std::swap(log_param_, other->log_param_);
+  std::swap(lrn_param_, other->lrn_param_);
+  std::swap(memory_data_param_, other->memory_data_param_);
+  std::swap(mvn_param_, other->mvn_param_);
+  std::swap(normalize_bbox_param_, other->normalize_bbox_param_);
+  std::swap(permute_param_, other->permute_param_);
+  std::swap(pooling_param_, other->pooling_param_);
+  std::swap(power_param_, other->power_param_);
+  std::swap(prelu_param_, other->prelu_param_);
+  std::swap(prior_box_param_, other->prior_box_param_);
+  std::swap(python_param_, other->python_param_);
+  std::swap(reduction_param_, other->reduction_param_);
+  std::swap(relu_param_, other->relu_param_);
+  std::swap(reshape_param_, other->reshape_param_);
+  std::swap(sigmoid_param_, other->sigmoid_param_);
+  std::swap(slice_param_, other->slice_param_);
+  std::swap(softmax_param_, other->softmax_param_);
+  std::swap(spp_param_, other->spp_param_);
+  std::swap(tanh_param_, other->tanh_param_);
+  std::swap(threshold_param_, other->threshold_param_);
+  std::swap(window_data_param_, other->window_data_param_);
+  std::swap(_has_bits_[0], other->_has_bits_[0]);
+  std::swap(_has_bits_[1], other->_has_bits_[1]);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
+}
+
+::google::protobuf::Metadata LayerParameter::GetMetadata() const {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::Metadata metadata;
+  metadata.descriptor = LayerParameter_descriptor_;
+  metadata.reflection = LayerParameter_reflection_;
+  return metadata;
+}
+
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// LayerParameter
+
+// optional string name = 1;
+bool LayerParameter::has_name() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+void LayerParameter::set_has_name() {
+  _has_bits_[0] |= 0x00000001u;
+}
+void LayerParameter::clear_has_name() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+void LayerParameter::clear_name() {
+  name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  clear_has_name();
+}
+const ::std::string& LayerParameter::name() const {
+  // @@protoc_insertion_point(field_get:caffe.LayerParameter.name)
+  return name_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+void LayerParameter::set_name(const ::std::string& value) {
+  set_has_name();
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:caffe.LayerParameter.name)
+}
+void LayerParameter::set_name(const char* value) {
+  set_has_name();
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:caffe.LayerParameter.name)
+}
+void LayerParameter::set_name(const char* value, size_t size) {
+  set_has_name();
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:caffe.LayerParameter.name)
+}
+::std::string* LayerParameter::mutable_name() {
+  set_has_name();
+  // @@protoc_insertion_point(field_mutable:caffe.LayerParameter.name)
+  return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+::std::string* LayerParameter::release_name() {
+  // @@protoc_insertion_point(field_release:caffe.LayerParameter.name)
+  clear_has_name();
+  return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+void LayerParameter::set_allocated_name(::std::string* name) {
+  if (name != NULL) {
+    set_has_name();
+  } else {
+    clear_has_name();
+  }
+  name_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), name);
+  // @@protoc_insertion_point(field_set_allocated:caffe.LayerParameter.name)
+}
+
+// optional string type = 2;
+bool LayerParameter::has_type() const {
+  return (_has_bits_[0] & 0x00000002u) != 0;
+}
+void LayerParameter::set_has_type() {
+  _has_bits_[0] |= 0x00000002u;
+}
+void LayerParameter::clear_has_type() {
+  _has_bits_[0] &= ~0x00000002u;
+}
+void LayerParameter::clear_type() {
+  type_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  clear_has_type();
+}
+const ::std::string& LayerParameter::type() const {
+  // @@protoc_insertion_point(field_get:caffe.LayerParameter.type)
+  return type_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+void LayerParameter::set_type(const ::std::string& value) {
+  set_has_type();
+  type_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:caffe.LayerParameter.type)
+}
+void LayerParameter::set_type(const char* value) {
+  set_has_type();
+  type_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:caffe.LayerParameter.type)
+}
+void LayerParameter::set_type(const char* value, size_t size) {
+  set_has_type();
+  type_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:caffe.LayerParameter.type)
+}
+::std::string* LayerParameter::mutable_type() {
+  set_has_type();
+  // @@protoc_insertion_point(field_mutable:caffe.LayerParameter.type)
+  return type_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+::std::string* LayerParameter::release_type() {
+  // @@protoc_insertion_point(field_release:caffe.LayerParameter.type)
+  clear_has_type();
+  return type_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+void LayerParameter::set_allocated_type(::std::string* type) {
+  if (type != NULL) {
+    set_has_type();
+  } else {
+    clear_has_type();
+  }
+  type_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), type);
+  // @@protoc_insertion_point(field_set_allocated:caffe.LayerParameter.type)
+}
+
+// repeated string bottom = 3;
+int LayerParameter::bottom_size() const {
+  return bottom_.size();
+}
+void LayerParameter::clear_bottom() {
+  bottom_.Clear();
+}
+const ::std::string& LayerParameter::bottom(int index) const {
+  // @@protoc_insertion_point(field_get:caffe.LayerParameter.bottom)
+  return bottom_.Get(index);
+}
+::std::string* LayerParameter::mutable_bottom(int index) {
+  // @@protoc_insertion_point(field_mutable:caffe.LayerParameter.bottom)
+  return bottom_.Mutable(index);
+}
+void LayerParameter::set_bottom(int index, const ::std::string& value) {
+  // @@protoc_insertion_point(field_set:caffe.LayerParameter.bottom)
+  bottom_.Mutable(index)->assign(value);
+}
+void LayerParameter::set_bottom(int index, const char* value) {
+  bottom_.Mutable(index)->assign(value);
+  // @@protoc_insertion_point(field_set_char:caffe.LayerParameter.bottom)
+}
+void LayerParameter::set_bottom(int index, const char* value, size_t size) {
+  bottom_.Mutable(index)->assign(
+    reinterpret_cast<const char*>(value), size);
+  // @@protoc_insertion_point(field_set_pointer:caffe.LayerParameter.bottom)
+}
+::std::string* LayerParameter::add_bottom() {
+  // @@protoc_insertion_point(field_add_mutable:caffe.LayerParameter.bottom)
+  return bottom_.Add();
+}
+void LayerParameter::add_bottom(const ::std::string& value) {
+  bottom_.Add()->assign(value);
+  // @@protoc_insertion_point(field_add:caffe.LayerParameter.bottom)
+}
+void LayerParameter::add_bottom(const char* value) {
+  bottom_.Add()->assign(value);
+  // @@protoc_insertion_point(field_add_char:caffe.LayerParameter.bottom)
+}
+void LayerParameter::add_bottom(const char* value, size_t size) {
+  bottom_.Add()->assign(reinterpret_cast<const char*>(value), size);
+  // @@protoc_insertion_point(field_add_pointer:caffe.LayerParameter.bottom)
+}
+const ::google::protobuf::RepeatedPtrField< ::std::string>&
+LayerParameter::bottom() const {
+  // @@protoc_insertion_point(field_list:caffe.LayerParameter.bottom)
+  return bottom_;
+}
+::google::protobuf::RepeatedPtrField< ::std::string>*
+LayerParameter::mutable_bottom() {
+  // @@protoc_insertion_point(field_mutable_list:caffe.LayerParameter.bottom)
+  return &bottom_;
+}
+
+// repeated string top = 4;
+int LayerParameter::top_size() const {
+  return top_.size();
+}
+void LayerParameter::clear_top() {
+  top_.Clear();
+}
+const ::std::string& LayerParameter::top(int index) const {
+  // @@protoc_insertion_point(field_get:caffe.LayerParameter.top)
+  return top_.Get(index);
+}
+::std::string* LayerParameter::mutable_top(int index) {
+  // @@protoc_insertion_point(field_mutable:caffe.LayerParameter.top)
+  return top_.Mutable(index);
+}
+void LayerParameter::set_top(int index, const ::std::string& value) {
+  // @@protoc_insertion_point(field_set:caffe.LayerParameter.top)
+  top_.Mutable(index)->assign(value);
+}
+void LayerParameter::set_top(int index, const char* value) {
+  top_.Mutable(index)->assign(value);
+  // @@protoc_insertion_point(field_set_char:caffe.LayerParameter.top)
+}
+void LayerParameter::set_top(int index, const char* value, size_t size) {
+  top_.Mutable(index)->assign(
+    reinterpret_cast<const char*>(value), size);
+  // @@protoc_insertion_point(field_set_pointer:caffe.LayerParameter.top)
+}
+::std::string* LayerParameter::add_top() {
+  // @@protoc_insertion_point(field_add_mutable:caffe.LayerParameter.top)
+  return top_.Add();
+}
+void LayerParameter::add_top(const ::std::string& value) {
+  top_.Add()->assign(value);
+  // @@protoc_insertion_point(field_add:caffe.LayerParameter.top)
+}
+void LayerParameter::add_top(const char* value) {
+  top_.Add()->assign(value);
+  // @@protoc_insertion_point(field_add_char:caffe.LayerParameter.top)
+}
+void LayerParameter::add_top(const char* value, size_t size) {
+  top_.Add()->assign(reinterpret_cast<const char*>(value), size);
+  // @@protoc_insertion_point(field_add_pointer:caffe.LayerParameter.top)
+}
+const ::google::protobuf::RepeatedPtrField< ::std::string>&
+LayerParameter::top() const {
+  // @@protoc_insertion_point(field_list:caffe.LayerParameter.top)
+  return top_;
+}
+::google::protobuf::RepeatedPtrField< ::std::string>*
+LayerParameter::mutable_top() {
+  // @@protoc_insertion_point(field_mutable_list:caffe.LayerParameter.top)
+  return &top_;
+}
+
+// optional .caffe.Phase phase = 10;
+bool LayerParameter::has_phase() const {
+  return (_has_bits_[0] & 0x00000010u) != 0;
+}
+void LayerParameter::set_has_phase() {
+  _has_bits_[0] |= 0x00000010u;
+}
+void LayerParameter::clear_has_phase() {
+  _has_bits_[0] &= ~0x00000010u;
+}
+void LayerParameter::clear_phase() {
+  phase_ = 0;
+  clear_has_phase();
+}
+::caffe::Phase LayerParameter::phase() const {
+  // @@protoc_insertion_point(field_get:caffe.LayerParameter.phase)
+  return static_cast< ::caffe::Phase >(phase_);
+}
+void LayerParameter::set_phase(::caffe::Phase value) {
+  assert(::caffe::Phase_IsValid(value));
+  set_has_phase();
+  phase_ = value;
+  // @@protoc_insertion_point(field_set:caffe.LayerParameter.phase)
+}
+
+// repeated float loss_weight = 5;
+int LayerParameter::loss_weight_size() const {
+  return loss_weight_.size();
+}
+void LayerParameter::clear_loss_weight() {
+  loss_weight_.Clear();
+}
+float LayerParameter::loss_weight(int index) const {
+  // @@protoc_insertion_point(field_get:caffe.LayerParameter.loss_weight)
+  return loss_weight_.Get(index);
+}
+void LayerParameter::set_loss_weight(int index, float value) {
+  loss_weight_.Set(index, value);
+  // @@protoc_insertion_point(field_set:caffe.LayerParameter.loss_weight)
+}
+void LayerParameter::add_loss_weight(float value) {
+  loss_weight_.Add(value);
+  // @@protoc_insertion_point(field_add:caffe.LayerParameter.loss_weight)
+}
+const ::google::protobuf::RepeatedField< float >&
+LayerParameter::loss_weight() const {
+  // @@protoc_insertion_point(field_list:caffe.LayerParameter.loss_weight)
+  return loss_weight_;
+}
+::google::protobuf::RepeatedField< float >*
+LayerParameter::mutable_loss_weight() {
+  // @@protoc_insertion_point(field_mutable_list:caffe.LayerParameter.loss_weight)
+  return &loss_weight_;
+}
+
+// repeated .caffe.ParamSpec param = 6;
+int LayerParameter::param_size() const {
+  return param_.size();
+}
+void LayerParameter::clear_param() {
+  param_.Clear();
+}
+const ::caffe::ParamSpec& LayerParameter::param(int index) const {
+  // @@protoc_insertion_point(field_get:caffe.LayerParameter.param)
+  return param_.Get(index);
+}
+::caffe::ParamSpec* LayerParameter::mutable_param(int index) {
+  // @@protoc_insertion_point(field_mutable:caffe.LayerParameter.param)
+  return param_.Mutable(index);
+}
+::caffe::ParamSpec* LayerParameter::add_param() {
+  // @@protoc_insertion_point(field_add:caffe.LayerParameter.param)
+  return param_.Add();
+}
+::google::protobuf::RepeatedPtrField< ::caffe::ParamSpec >*
+LayerParameter::mutable_param() {
+  // @@protoc_insertion_point(field_mutable_list:caffe.LayerParameter.param)
+  return &param_;
+}
+const ::google::protobuf::RepeatedPtrField< ::caffe::ParamSpec >&
+LayerParameter::param() const {
+  // @@protoc_insertion_point(field_list:caffe.LayerParameter.param)
+  return param_;
+}
+
+// repeated .caffe.BlobProto blobs = 7;
+int LayerParameter::blobs_size() const {
+  return blobs_.size();
+}
+void LayerParameter::clear_blobs() {
+  blobs_.Clear();
+}
+const ::caffe::BlobProto& LayerParameter::blobs(int index) const {
+  // @@protoc_insertion_point(field_get:caffe.LayerParameter.blobs)
+  return blobs_.Get(index);
+}
+::caffe::BlobProto* LayerParameter::mutable_blobs(int index) {
+  // @@protoc_insertion_point(field_mutable:caffe.LayerParameter.blobs)
+  return blobs_.Mutable(index);
+}
+::caffe::BlobProto* LayerParameter::add_blobs() {
+  // @@protoc_insertion_point(field_add:caffe.LayerParameter.blobs)
+  return blobs_.Add();
+}
+::google::protobuf::RepeatedPtrField< ::caffe::BlobProto >*
+LayerParameter::mutable_blobs() {
+  // @@protoc_insertion_point(field_mutable_list:caffe.LayerParameter.blobs)
+  return &blobs_;
+}
+const ::google::protobuf::RepeatedPtrField< ::caffe::BlobProto >&
+LayerParameter::blobs() const {
+  // @@protoc_insertion_point(field_list:caffe.LayerParameter.blobs)
+  return blobs_;
+}
+
+// repeated bool propagate_down = 11;
+int LayerParameter::propagate_down_size() const {
+  return propagate_down_.size();
+}
+void LayerParameter::clear_propagate_down() {
+  propagate_down_.Clear();
+}
+bool LayerParameter::propagate_down(int index) const {
+  // @@protoc_insertion_point(field_get:caffe.LayerParameter.propagate_down)
+  return propagate_down_.Get(index);
+}
+void LayerParameter::set_propagate_down(int index, bool value) {
+  propagate_down_.Set(index, value);
+  // @@protoc_insertion_point(field_set:caffe.LayerParameter.propagate_down)
+}
+void LayerParameter::add_propagate_down(bool value) {
+  propagate_down_.Add(value);
+  // @@protoc_insertion_point(field_add:caffe.LayerParameter.propagate_down)
+}
+const ::google::protobuf::RepeatedField< bool >&
+LayerParameter::propagate_down() const {
+  // @@protoc_insertion_point(field_list:caffe.LayerParameter.propagate_down)
+  return propagate_down_;
+}
+::google::protobuf::RepeatedField< bool >*
+LayerParameter::mutable_propagate_down() {
+  // @@protoc_insertion_point(field_mutable_list:caffe.LayerParameter.propagate_down)
+  return &propagate_down_;
+}
+
+// repeated .caffe.NetStateRule include = 8;
+int LayerParameter::include_size() const {
+  return include_.size();
+}
+void LayerParameter::clear_include() {
+  include_.Clear();
+}
+const ::caffe::NetStateRule& LayerParameter::include(int index) const {
+  // @@protoc_insertion_point(field_get:caffe.LayerParameter.include)
+  return include_.Get(index);
+}
+::caffe::NetStateRule* LayerParameter::mutable_include(int index) {
+  // @@protoc_insertion_point(field_mutable:caffe.LayerParameter.include)
+  return include_.Mutable(index);
+}
+::caffe::NetStateRule* LayerParameter::add_include() {
+  // @@protoc_insertion_point(field_add:caffe.LayerParameter.include)
+  return include_.Add();
+}
+::google::protobuf::RepeatedPtrField< ::caffe::NetStateRule >*
+LayerParameter::mutable_include() {
+  // @@protoc_insertion_point(field_mutable_list:caffe.LayerParameter.include)
+  return &include_;
+}
+const ::google::protobuf::RepeatedPtrField< ::caffe::NetStateRule >&
+LayerParameter::include() const {
+  // @@protoc_insertion_point(field_list:caffe.LayerParameter.include)
+  return include_;
+}
+
+// repeated .caffe.NetStateRule exclude = 9;
+int LayerParameter::exclude_size() const {
+  return exclude_.size();
+}
+void LayerParameter::clear_exclude() {
+  exclude_.Clear();
+}
+const ::caffe::NetStateRule& LayerParameter::exclude(int index) const {
+  // @@protoc_insertion_point(field_get:caffe.LayerParameter.exclude)
+  return exclude_.Get(index);
+}
+::caffe::NetStateRule* LayerParameter::mutable_exclude(int index) {
+  // @@protoc_insertion_point(field_mutable:caffe.LayerParameter.exclude)
+  return exclude_.Mutable(index);
+}
+::caffe::NetStateRule* LayerParameter::add_exclude() {
+  // @@protoc_insertion_point(field_add:caffe.LayerParameter.exclude)
+  return exclude_.Add();
+}
+::google::protobuf::RepeatedPtrField< ::caffe::NetStateRule >*
+LayerParameter::mutable_exclude() {
+  // @@protoc_insertion_point(field_mutable_list:caffe.LayerParameter.exclude)
+  return &exclude_;
+}
+const ::google::protobuf::RepeatedPtrField< ::caffe::NetStateRule >&
+LayerParameter::exclude() const {
+  // @@protoc_insertion_point(field_list:caffe.LayerParameter.exclude)
+  return exclude_;
+}
+
+// optional .caffe.TransformationParameter transform_param = 100;
+bool LayerParameter::has_transform_param() const {
+  return (_has_bits_[0] & 0x00000800u) != 0;
+}
+void LayerParameter::set_has_transform_param() {
+  _has_bits_[0] |= 0x00000800u;
+}
+void LayerParameter::clear_has_transform_param() {
+  _has_bits_[0] &= ~0x00000800u;
+}
+void LayerParameter::clear_transform_param() {
+  if (transform_param_ != NULL) transform_param_->::caffe::TransformationParameter::Clear();
+  clear_has_transform_param();
+}
+const ::caffe::TransformationParameter& LayerParameter::transform_param() const {
+  // @@protoc_insertion_point(field_get:caffe.LayerParameter.transform_param)
+  return transform_param_ != NULL ? *transform_param_
+                         : *::caffe::TransformationParameter::internal_default_instance();
+}
+::caffe::TransformationParameter* LayerParameter::mutable_transform_param() {
+  set_has_transform_param();
+  if (transform_param_ == NULL) {
+    transform_param_ = new ::caffe::TransformationParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.LayerParameter.transform_param)
+  return transform_param_;
+}
+::caffe::TransformationParameter* LayerParameter::release_transform_param() {
+  // @@protoc_insertion_point(field_release:caffe.LayerParameter.transform_param)
+  clear_has_transform_param();
+  ::caffe::TransformationParameter* temp = transform_param_;
+  transform_param_ = NULL;
+  return temp;
+}
+void LayerParameter::set_allocated_transform_param(::caffe::TransformationParameter* transform_param) {
+  delete transform_param_;
+  transform_param_ = transform_param;
+  if (transform_param) {
+    set_has_transform_param();
+  } else {
+    clear_has_transform_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.LayerParameter.transform_param)
+}
+
+// optional .caffe.LossParameter loss_param = 101;
+bool LayerParameter::has_loss_param() const {
+  return (_has_bits_[0] & 0x00001000u) != 0;
+}
+void LayerParameter::set_has_loss_param() {
+  _has_bits_[0] |= 0x00001000u;
+}
+void LayerParameter::clear_has_loss_param() {
+  _has_bits_[0] &= ~0x00001000u;
+}
+void LayerParameter::clear_loss_param() {
+  if (loss_param_ != NULL) loss_param_->::caffe::LossParameter::Clear();
+  clear_has_loss_param();
+}
+const ::caffe::LossParameter& LayerParameter::loss_param() const {
+  // @@protoc_insertion_point(field_get:caffe.LayerParameter.loss_param)
+  return loss_param_ != NULL ? *loss_param_
+                         : *::caffe::LossParameter::internal_default_instance();
+}
+::caffe::LossParameter* LayerParameter::mutable_loss_param() {
+  set_has_loss_param();
+  if (loss_param_ == NULL) {
+    loss_param_ = new ::caffe::LossParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.LayerParameter.loss_param)
+  return loss_param_;
+}
+::caffe::LossParameter* LayerParameter::release_loss_param() {
+  // @@protoc_insertion_point(field_release:caffe.LayerParameter.loss_param)
+  clear_has_loss_param();
+  ::caffe::LossParameter* temp = loss_param_;
+  loss_param_ = NULL;
+  return temp;
+}
+void LayerParameter::set_allocated_loss_param(::caffe::LossParameter* loss_param) {
+  delete loss_param_;
+  loss_param_ = loss_param;
+  if (loss_param) {
+    set_has_loss_param();
+  } else {
+    clear_has_loss_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.LayerParameter.loss_param)
+}
+
+// optional .caffe.AccuracyParameter accuracy_param = 102;
+bool LayerParameter::has_accuracy_param() const {
+  return (_has_bits_[0] & 0x00002000u) != 0;
+}
+void LayerParameter::set_has_accuracy_param() {
+  _has_bits_[0] |= 0x00002000u;
+}
+void LayerParameter::clear_has_accuracy_param() {
+  _has_bits_[0] &= ~0x00002000u;
+}
+void LayerParameter::clear_accuracy_param() {
+  if (accuracy_param_ != NULL) accuracy_param_->::caffe::AccuracyParameter::Clear();
+  clear_has_accuracy_param();
+}
+const ::caffe::AccuracyParameter& LayerParameter::accuracy_param() const {
+  // @@protoc_insertion_point(field_get:caffe.LayerParameter.accuracy_param)
+  return accuracy_param_ != NULL ? *accuracy_param_
+                         : *::caffe::AccuracyParameter::internal_default_instance();
+}
+::caffe::AccuracyParameter* LayerParameter::mutable_accuracy_param() {
+  set_has_accuracy_param();
+  if (accuracy_param_ == NULL) {
+    accuracy_param_ = new ::caffe::AccuracyParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.LayerParameter.accuracy_param)
+  return accuracy_param_;
+}
+::caffe::AccuracyParameter* LayerParameter::release_accuracy_param() {
+  // @@protoc_insertion_point(field_release:caffe.LayerParameter.accuracy_param)
+  clear_has_accuracy_param();
+  ::caffe::AccuracyParameter* temp = accuracy_param_;
+  accuracy_param_ = NULL;
+  return temp;
+}
+void LayerParameter::set_allocated_accuracy_param(::caffe::AccuracyParameter* accuracy_param) {
+  delete accuracy_param_;
+  accuracy_param_ = accuracy_param;
+  if (accuracy_param) {
+    set_has_accuracy_param();
+  } else {
+    clear_has_accuracy_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.LayerParameter.accuracy_param)
+}
+
+// optional .caffe.ArgMaxParameter argmax_param = 103;
+bool LayerParameter::has_argmax_param() const {
+  return (_has_bits_[0] & 0x00004000u) != 0;
+}
+void LayerParameter::set_has_argmax_param() {
+  _has_bits_[0] |= 0x00004000u;
+}
+void LayerParameter::clear_has_argmax_param() {
+  _has_bits_[0] &= ~0x00004000u;
+}
+void LayerParameter::clear_argmax_param() {
+  if (argmax_param_ != NULL) argmax_param_->::caffe::ArgMaxParameter::Clear();
+  clear_has_argmax_param();
+}
+const ::caffe::ArgMaxParameter& LayerParameter::argmax_param() const {
+  // @@protoc_insertion_point(field_get:caffe.LayerParameter.argmax_param)
+  return argmax_param_ != NULL ? *argmax_param_
+                         : *::caffe::ArgMaxParameter::internal_default_instance();
+}
+::caffe::ArgMaxParameter* LayerParameter::mutable_argmax_param() {
+  set_has_argmax_param();
+  if (argmax_param_ == NULL) {
+    argmax_param_ = new ::caffe::ArgMaxParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.LayerParameter.argmax_param)
+  return argmax_param_;
+}
+::caffe::ArgMaxParameter* LayerParameter::release_argmax_param() {
+  // @@protoc_insertion_point(field_release:caffe.LayerParameter.argmax_param)
+  clear_has_argmax_param();
+  ::caffe::ArgMaxParameter* temp = argmax_param_;
+  argmax_param_ = NULL;
+  return temp;
+}
+void LayerParameter::set_allocated_argmax_param(::caffe::ArgMaxParameter* argmax_param) {
+  delete argmax_param_;
+  argmax_param_ = argmax_param;
+  if (argmax_param) {
+    set_has_argmax_param();
+  } else {
+    clear_has_argmax_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.LayerParameter.argmax_param)
+}
+
+// optional .caffe.ConcatParameter concat_param = 104;
+bool LayerParameter::has_concat_param() const {
+  return (_has_bits_[0] & 0x00008000u) != 0;
+}
+void LayerParameter::set_has_concat_param() {
+  _has_bits_[0] |= 0x00008000u;
+}
+void LayerParameter::clear_has_concat_param() {
+  _has_bits_[0] &= ~0x00008000u;
+}
+void LayerParameter::clear_concat_param() {
+  if (concat_param_ != NULL) concat_param_->::caffe::ConcatParameter::Clear();
+  clear_has_concat_param();
+}
+const ::caffe::ConcatParameter& LayerParameter::concat_param() const {
+  // @@protoc_insertion_point(field_get:caffe.LayerParameter.concat_param)
+  return concat_param_ != NULL ? *concat_param_
+                         : *::caffe::ConcatParameter::internal_default_instance();
+}
+::caffe::ConcatParameter* LayerParameter::mutable_concat_param() {
+  set_has_concat_param();
+  if (concat_param_ == NULL) {
+    concat_param_ = new ::caffe::ConcatParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.LayerParameter.concat_param)
+  return concat_param_;
+}
+::caffe::ConcatParameter* LayerParameter::release_concat_param() {
+  // @@protoc_insertion_point(field_release:caffe.LayerParameter.concat_param)
+  clear_has_concat_param();
+  ::caffe::ConcatParameter* temp = concat_param_;
+  concat_param_ = NULL;
+  return temp;
+}
+void LayerParameter::set_allocated_concat_param(::caffe::ConcatParameter* concat_param) {
+  delete concat_param_;
+  concat_param_ = concat_param;
+  if (concat_param) {
+    set_has_concat_param();
+  } else {
+    clear_has_concat_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.LayerParameter.concat_param)
+}
+
+// optional .caffe.ContrastiveLossParameter contrastive_loss_param = 105;
+bool LayerParameter::has_contrastive_loss_param() const {
+  return (_has_bits_[0] & 0x00010000u) != 0;
+}
+void LayerParameter::set_has_contrastive_loss_param() {
+  _has_bits_[0] |= 0x00010000u;
+}
+void LayerParameter::clear_has_contrastive_loss_param() {
+  _has_bits_[0] &= ~0x00010000u;
+}
+void LayerParameter::clear_contrastive_loss_param() {
+  if (contrastive_loss_param_ != NULL) contrastive_loss_param_->::caffe::ContrastiveLossParameter::Clear();
+  clear_has_contrastive_loss_param();
+}
+const ::caffe::ContrastiveLossParameter& LayerParameter::contrastive_loss_param() const {
+  // @@protoc_insertion_point(field_get:caffe.LayerParameter.contrastive_loss_param)
+  return contrastive_loss_param_ != NULL ? *contrastive_loss_param_
+                         : *::caffe::ContrastiveLossParameter::internal_default_instance();
+}
+::caffe::ContrastiveLossParameter* LayerParameter::mutable_contrastive_loss_param() {
+  set_has_contrastive_loss_param();
+  if (contrastive_loss_param_ == NULL) {
+    contrastive_loss_param_ = new ::caffe::ContrastiveLossParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.LayerParameter.contrastive_loss_param)
+  return contrastive_loss_param_;
+}
+::caffe::ContrastiveLossParameter* LayerParameter::release_contrastive_loss_param() {
+  // @@protoc_insertion_point(field_release:caffe.LayerParameter.contrastive_loss_param)
+  clear_has_contrastive_loss_param();
+  ::caffe::ContrastiveLossParameter* temp = contrastive_loss_param_;
+  contrastive_loss_param_ = NULL;
+  return temp;
+}
+void LayerParameter::set_allocated_contrastive_loss_param(::caffe::ContrastiveLossParameter* contrastive_loss_param) {
+  delete contrastive_loss_param_;
+  contrastive_loss_param_ = contrastive_loss_param;
+  if (contrastive_loss_param) {
+    set_has_contrastive_loss_param();
+  } else {
+    clear_has_contrastive_loss_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.LayerParameter.contrastive_loss_param)
+}
+
+// optional .caffe.ConvolutionParameter convolution_param = 106;
+bool LayerParameter::has_convolution_param() const {
+  return (_has_bits_[0] & 0x00020000u) != 0;
+}
+void LayerParameter::set_has_convolution_param() {
+  _has_bits_[0] |= 0x00020000u;
+}
+void LayerParameter::clear_has_convolution_param() {
+  _has_bits_[0] &= ~0x00020000u;
+}
+void LayerParameter::clear_convolution_param() {
+  if (convolution_param_ != NULL) convolution_param_->::caffe::ConvolutionParameter::Clear();
+  clear_has_convolution_param();
+}
+const ::caffe::ConvolutionParameter& LayerParameter::convolution_param() const {
+  // @@protoc_insertion_point(field_get:caffe.LayerParameter.convolution_param)
+  return convolution_param_ != NULL ? *convolution_param_
+                         : *::caffe::ConvolutionParameter::internal_default_instance();
+}
+::caffe::ConvolutionParameter* LayerParameter::mutable_convolution_param() {
+  set_has_convolution_param();
+  if (convolution_param_ == NULL) {
+    convolution_param_ = new ::caffe::ConvolutionParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.LayerParameter.convolution_param)
+  return convolution_param_;
+}
+::caffe::ConvolutionParameter* LayerParameter::release_convolution_param() {
+  // @@protoc_insertion_point(field_release:caffe.LayerParameter.convolution_param)
+  clear_has_convolution_param();
+  ::caffe::ConvolutionParameter* temp = convolution_param_;
+  convolution_param_ = NULL;
+  return temp;
+}
+void LayerParameter::set_allocated_convolution_param(::caffe::ConvolutionParameter* convolution_param) {
+  delete convolution_param_;
+  convolution_param_ = convolution_param;
+  if (convolution_param) {
+    set_has_convolution_param();
+  } else {
+    clear_has_convolution_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.LayerParameter.convolution_param)
+}
+
+// optional .caffe.CropParameter crop_param = 137;
+bool LayerParameter::has_crop_param() const {
+  return (_has_bits_[0] & 0x00040000u) != 0;
+}
+void LayerParameter::set_has_crop_param() {
+  _has_bits_[0] |= 0x00040000u;
+}
+void LayerParameter::clear_has_crop_param() {
+  _has_bits_[0] &= ~0x00040000u;
+}
+void LayerParameter::clear_crop_param() {
+  if (crop_param_ != NULL) crop_param_->::caffe::CropParameter::Clear();
+  clear_has_crop_param();
+}
+const ::caffe::CropParameter& LayerParameter::crop_param() const {
+  // @@protoc_insertion_point(field_get:caffe.LayerParameter.crop_param)
+  return crop_param_ != NULL ? *crop_param_
+                         : *::caffe::CropParameter::internal_default_instance();
+}
+::caffe::CropParameter* LayerParameter::mutable_crop_param() {
+  set_has_crop_param();
+  if (crop_param_ == NULL) {
+    crop_param_ = new ::caffe::CropParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.LayerParameter.crop_param)
+  return crop_param_;
+}
+::caffe::CropParameter* LayerParameter::release_crop_param() {
+  // @@protoc_insertion_point(field_release:caffe.LayerParameter.crop_param)
+  clear_has_crop_param();
+  ::caffe::CropParameter* temp = crop_param_;
+  crop_param_ = NULL;
+  return temp;
+}
+void LayerParameter::set_allocated_crop_param(::caffe::CropParameter* crop_param) {
+  delete crop_param_;
+  crop_param_ = crop_param;
+  if (crop_param) {
+    set_has_crop_param();
+  } else {
+    clear_has_crop_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.LayerParameter.crop_param)
+}
+
+// optional .caffe.DataParameter data_param = 107;
+bool LayerParameter::has_data_param() const {
+  return (_has_bits_[0] & 0x00080000u) != 0;
+}
+void LayerParameter::set_has_data_param() {
+  _has_bits_[0] |= 0x00080000u;
+}
+void LayerParameter::clear_has_data_param() {
+  _has_bits_[0] &= ~0x00080000u;
+}
+void LayerParameter::clear_data_param() {
+  if (data_param_ != NULL) data_param_->::caffe::DataParameter::Clear();
+  clear_has_data_param();
+}
+const ::caffe::DataParameter& LayerParameter::data_param() const {
+  // @@protoc_insertion_point(field_get:caffe.LayerParameter.data_param)
+  return data_param_ != NULL ? *data_param_
+                         : *::caffe::DataParameter::internal_default_instance();
+}
+::caffe::DataParameter* LayerParameter::mutable_data_param() {
+  set_has_data_param();
+  if (data_param_ == NULL) {
+    data_param_ = new ::caffe::DataParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.LayerParameter.data_param)
+  return data_param_;
+}
+::caffe::DataParameter* LayerParameter::release_data_param() {
+  // @@protoc_insertion_point(field_release:caffe.LayerParameter.data_param)
+  clear_has_data_param();
+  ::caffe::DataParameter* temp = data_param_;
+  data_param_ = NULL;
+  return temp;
+}
+void LayerParameter::set_allocated_data_param(::caffe::DataParameter* data_param) {
+  delete data_param_;
+  data_param_ = data_param;
+  if (data_param) {
+    set_has_data_param();
+  } else {
+    clear_has_data_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.LayerParameter.data_param)
+}
+
+// optional .caffe.DetectionOutputParameter detection_output_param = 141;
+bool LayerParameter::has_detection_output_param() const {
+  return (_has_bits_[0] & 0x00100000u) != 0;
+}
+void LayerParameter::set_has_detection_output_param() {
+  _has_bits_[0] |= 0x00100000u;
+}
+void LayerParameter::clear_has_detection_output_param() {
+  _has_bits_[0] &= ~0x00100000u;
+}
+void LayerParameter::clear_detection_output_param() {
+  if (detection_output_param_ != NULL) detection_output_param_->::caffe::DetectionOutputParameter::Clear();
+  clear_has_detection_output_param();
+}
+const ::caffe::DetectionOutputParameter& LayerParameter::detection_output_param() const {
+  // @@protoc_insertion_point(field_get:caffe.LayerParameter.detection_output_param)
+  return detection_output_param_ != NULL ? *detection_output_param_
+                         : *::caffe::DetectionOutputParameter::internal_default_instance();
+}
+::caffe::DetectionOutputParameter* LayerParameter::mutable_detection_output_param() {
+  set_has_detection_output_param();
+  if (detection_output_param_ == NULL) {
+    detection_output_param_ = new ::caffe::DetectionOutputParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.LayerParameter.detection_output_param)
+  return detection_output_param_;
+}
+::caffe::DetectionOutputParameter* LayerParameter::release_detection_output_param() {
+  // @@protoc_insertion_point(field_release:caffe.LayerParameter.detection_output_param)
+  clear_has_detection_output_param();
+  ::caffe::DetectionOutputParameter* temp = detection_output_param_;
+  detection_output_param_ = NULL;
+  return temp;
+}
+void LayerParameter::set_allocated_detection_output_param(::caffe::DetectionOutputParameter* detection_output_param) {
+  delete detection_output_param_;
+  detection_output_param_ = detection_output_param;
+  if (detection_output_param) {
+    set_has_detection_output_param();
+  } else {
+    clear_has_detection_output_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.LayerParameter.detection_output_param)
+}
+
+// optional .caffe.DropoutParameter dropout_param = 108;
+bool LayerParameter::has_dropout_param() const {
+  return (_has_bits_[0] & 0x00200000u) != 0;
+}
+void LayerParameter::set_has_dropout_param() {
+  _has_bits_[0] |= 0x00200000u;
+}
+void LayerParameter::clear_has_dropout_param() {
+  _has_bits_[0] &= ~0x00200000u;
+}
+void LayerParameter::clear_dropout_param() {
+  if (dropout_param_ != NULL) dropout_param_->::caffe::DropoutParameter::Clear();
+  clear_has_dropout_param();
+}
+const ::caffe::DropoutParameter& LayerParameter::dropout_param() const {
+  // @@protoc_insertion_point(field_get:caffe.LayerParameter.dropout_param)
+  return dropout_param_ != NULL ? *dropout_param_
+                         : *::caffe::DropoutParameter::internal_default_instance();
+}
+::caffe::DropoutParameter* LayerParameter::mutable_dropout_param() {
+  set_has_dropout_param();
+  if (dropout_param_ == NULL) {
+    dropout_param_ = new ::caffe::DropoutParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.LayerParameter.dropout_param)
+  return dropout_param_;
+}
+::caffe::DropoutParameter* LayerParameter::release_dropout_param() {
+  // @@protoc_insertion_point(field_release:caffe.LayerParameter.dropout_param)
+  clear_has_dropout_param();
+  ::caffe::DropoutParameter* temp = dropout_param_;
+  dropout_param_ = NULL;
+  return temp;
+}
+void LayerParameter::set_allocated_dropout_param(::caffe::DropoutParameter* dropout_param) {
+  delete dropout_param_;
+  dropout_param_ = dropout_param;
+  if (dropout_param) {
+    set_has_dropout_param();
+  } else {
+    clear_has_dropout_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.LayerParameter.dropout_param)
+}
+
+// optional .caffe.DummyDataParameter dummy_data_param = 109;
+bool LayerParameter::has_dummy_data_param() const {
+  return (_has_bits_[0] & 0x00400000u) != 0;
+}
+void LayerParameter::set_has_dummy_data_param() {
+  _has_bits_[0] |= 0x00400000u;
+}
+void LayerParameter::clear_has_dummy_data_param() {
+  _has_bits_[0] &= ~0x00400000u;
+}
+void LayerParameter::clear_dummy_data_param() {
+  if (dummy_data_param_ != NULL) dummy_data_param_->::caffe::DummyDataParameter::Clear();
+  clear_has_dummy_data_param();
+}
+const ::caffe::DummyDataParameter& LayerParameter::dummy_data_param() const {
+  // @@protoc_insertion_point(field_get:caffe.LayerParameter.dummy_data_param)
+  return dummy_data_param_ != NULL ? *dummy_data_param_
+                         : *::caffe::DummyDataParameter::internal_default_instance();
+}
+::caffe::DummyDataParameter* LayerParameter::mutable_dummy_data_param() {
+  set_has_dummy_data_param();
+  if (dummy_data_param_ == NULL) {
+    dummy_data_param_ = new ::caffe::DummyDataParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.LayerParameter.dummy_data_param)
+  return dummy_data_param_;
+}
+::caffe::DummyDataParameter* LayerParameter::release_dummy_data_param() {
+  // @@protoc_insertion_point(field_release:caffe.LayerParameter.dummy_data_param)
+  clear_has_dummy_data_param();
+  ::caffe::DummyDataParameter* temp = dummy_data_param_;
+  dummy_data_param_ = NULL;
+  return temp;
+}
+void LayerParameter::set_allocated_dummy_data_param(::caffe::DummyDataParameter* dummy_data_param) {
+  delete dummy_data_param_;
+  dummy_data_param_ = dummy_data_param;
+  if (dummy_data_param) {
+    set_has_dummy_data_param();
+  } else {
+    clear_has_dummy_data_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.LayerParameter.dummy_data_param)
+}
+
+// optional .caffe.EltwiseParameter eltwise_param = 110;
+bool LayerParameter::has_eltwise_param() const {
+  return (_has_bits_[0] & 0x00800000u) != 0;
+}
+void LayerParameter::set_has_eltwise_param() {
+  _has_bits_[0] |= 0x00800000u;
+}
+void LayerParameter::clear_has_eltwise_param() {
+  _has_bits_[0] &= ~0x00800000u;
+}
+void LayerParameter::clear_eltwise_param() {
+  if (eltwise_param_ != NULL) eltwise_param_->::caffe::EltwiseParameter::Clear();
+  clear_has_eltwise_param();
+}
+const ::caffe::EltwiseParameter& LayerParameter::eltwise_param() const {
+  // @@protoc_insertion_point(field_get:caffe.LayerParameter.eltwise_param)
+  return eltwise_param_ != NULL ? *eltwise_param_
+                         : *::caffe::EltwiseParameter::internal_default_instance();
+}
+::caffe::EltwiseParameter* LayerParameter::mutable_eltwise_param() {
+  set_has_eltwise_param();
+  if (eltwise_param_ == NULL) {
+    eltwise_param_ = new ::caffe::EltwiseParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.LayerParameter.eltwise_param)
+  return eltwise_param_;
+}
+::caffe::EltwiseParameter* LayerParameter::release_eltwise_param() {
+  // @@protoc_insertion_point(field_release:caffe.LayerParameter.eltwise_param)
+  clear_has_eltwise_param();
+  ::caffe::EltwiseParameter* temp = eltwise_param_;
+  eltwise_param_ = NULL;
+  return temp;
+}
+void LayerParameter::set_allocated_eltwise_param(::caffe::EltwiseParameter* eltwise_param) {
+  delete eltwise_param_;
+  eltwise_param_ = eltwise_param;
+  if (eltwise_param) {
+    set_has_eltwise_param();
+  } else {
+    clear_has_eltwise_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.LayerParameter.eltwise_param)
+}
+
+// optional .caffe.ExpParameter exp_param = 111;
+bool LayerParameter::has_exp_param() const {
+  return (_has_bits_[0] & 0x01000000u) != 0;
+}
+void LayerParameter::set_has_exp_param() {
+  _has_bits_[0] |= 0x01000000u;
+}
+void LayerParameter::clear_has_exp_param() {
+  _has_bits_[0] &= ~0x01000000u;
+}
+void LayerParameter::clear_exp_param() {
+  if (exp_param_ != NULL) exp_param_->::caffe::ExpParameter::Clear();
+  clear_has_exp_param();
+}
+const ::caffe::ExpParameter& LayerParameter::exp_param() const {
+  // @@protoc_insertion_point(field_get:caffe.LayerParameter.exp_param)
+  return exp_param_ != NULL ? *exp_param_
+                         : *::caffe::ExpParameter::internal_default_instance();
+}
+::caffe::ExpParameter* LayerParameter::mutable_exp_param() {
+  set_has_exp_param();
+  if (exp_param_ == NULL) {
+    exp_param_ = new ::caffe::ExpParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.LayerParameter.exp_param)
+  return exp_param_;
+}
+::caffe::ExpParameter* LayerParameter::release_exp_param() {
+  // @@protoc_insertion_point(field_release:caffe.LayerParameter.exp_param)
+  clear_has_exp_param();
+  ::caffe::ExpParameter* temp = exp_param_;
+  exp_param_ = NULL;
+  return temp;
+}
+void LayerParameter::set_allocated_exp_param(::caffe::ExpParameter* exp_param) {
+  delete exp_param_;
+  exp_param_ = exp_param;
+  if (exp_param) {
+    set_has_exp_param();
+  } else {
+    clear_has_exp_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.LayerParameter.exp_param)
+}
+
+// optional .caffe.FlattenParameter flatten_param = 135;
+bool LayerParameter::has_flatten_param() const {
+  return (_has_bits_[0] & 0x02000000u) != 0;
+}
+void LayerParameter::set_has_flatten_param() {
+  _has_bits_[0] |= 0x02000000u;
+}
+void LayerParameter::clear_has_flatten_param() {
+  _has_bits_[0] &= ~0x02000000u;
+}
+void LayerParameter::clear_flatten_param() {
+  if (flatten_param_ != NULL) flatten_param_->::caffe::FlattenParameter::Clear();
+  clear_has_flatten_param();
+}
+const ::caffe::FlattenParameter& LayerParameter::flatten_param() const {
+  // @@protoc_insertion_point(field_get:caffe.LayerParameter.flatten_param)
+  return flatten_param_ != NULL ? *flatten_param_
+                         : *::caffe::FlattenParameter::internal_default_instance();
+}
+::caffe::FlattenParameter* LayerParameter::mutable_flatten_param() {
+  set_has_flatten_param();
+  if (flatten_param_ == NULL) {
+    flatten_param_ = new ::caffe::FlattenParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.LayerParameter.flatten_param)
+  return flatten_param_;
+}
+::caffe::FlattenParameter* LayerParameter::release_flatten_param() {
+  // @@protoc_insertion_point(field_release:caffe.LayerParameter.flatten_param)
+  clear_has_flatten_param();
+  ::caffe::FlattenParameter* temp = flatten_param_;
+  flatten_param_ = NULL;
+  return temp;
+}
+void LayerParameter::set_allocated_flatten_param(::caffe::FlattenParameter* flatten_param) {
+  delete flatten_param_;
+  flatten_param_ = flatten_param;
+  if (flatten_param) {
+    set_has_flatten_param();
+  } else {
+    clear_has_flatten_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.LayerParameter.flatten_param)
+}
+
+// optional .caffe.HDF5DataParameter hdf5_data_param = 112;
+bool LayerParameter::has_hdf5_data_param() const {
+  return (_has_bits_[0] & 0x04000000u) != 0;
+}
+void LayerParameter::set_has_hdf5_data_param() {
+  _has_bits_[0] |= 0x04000000u;
+}
+void LayerParameter::clear_has_hdf5_data_param() {
+  _has_bits_[0] &= ~0x04000000u;
+}
+void LayerParameter::clear_hdf5_data_param() {
+  if (hdf5_data_param_ != NULL) hdf5_data_param_->::caffe::HDF5DataParameter::Clear();
+  clear_has_hdf5_data_param();
+}
+const ::caffe::HDF5DataParameter& LayerParameter::hdf5_data_param() const {
+  // @@protoc_insertion_point(field_get:caffe.LayerParameter.hdf5_data_param)
+  return hdf5_data_param_ != NULL ? *hdf5_data_param_
+                         : *::caffe::HDF5DataParameter::internal_default_instance();
+}
+::caffe::HDF5DataParameter* LayerParameter::mutable_hdf5_data_param() {
+  set_has_hdf5_data_param();
+  if (hdf5_data_param_ == NULL) {
+    hdf5_data_param_ = new ::caffe::HDF5DataParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.LayerParameter.hdf5_data_param)
+  return hdf5_data_param_;
+}
+::caffe::HDF5DataParameter* LayerParameter::release_hdf5_data_param() {
+  // @@protoc_insertion_point(field_release:caffe.LayerParameter.hdf5_data_param)
+  clear_has_hdf5_data_param();
+  ::caffe::HDF5DataParameter* temp = hdf5_data_param_;
+  hdf5_data_param_ = NULL;
+  return temp;
+}
+void LayerParameter::set_allocated_hdf5_data_param(::caffe::HDF5DataParameter* hdf5_data_param) {
+  delete hdf5_data_param_;
+  hdf5_data_param_ = hdf5_data_param;
+  if (hdf5_data_param) {
+    set_has_hdf5_data_param();
+  } else {
+    clear_has_hdf5_data_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.LayerParameter.hdf5_data_param)
+}
+
+// optional .caffe.HDF5OutputParameter hdf5_output_param = 113;
+bool LayerParameter::has_hdf5_output_param() const {
+  return (_has_bits_[0] & 0x08000000u) != 0;
+}
+void LayerParameter::set_has_hdf5_output_param() {
+  _has_bits_[0] |= 0x08000000u;
+}
+void LayerParameter::clear_has_hdf5_output_param() {
+  _has_bits_[0] &= ~0x08000000u;
+}
+void LayerParameter::clear_hdf5_output_param() {
+  if (hdf5_output_param_ != NULL) hdf5_output_param_->::caffe::HDF5OutputParameter::Clear();
+  clear_has_hdf5_output_param();
+}
+const ::caffe::HDF5OutputParameter& LayerParameter::hdf5_output_param() const {
+  // @@protoc_insertion_point(field_get:caffe.LayerParameter.hdf5_output_param)
+  return hdf5_output_param_ != NULL ? *hdf5_output_param_
+                         : *::caffe::HDF5OutputParameter::internal_default_instance();
+}
+::caffe::HDF5OutputParameter* LayerParameter::mutable_hdf5_output_param() {
+  set_has_hdf5_output_param();
+  if (hdf5_output_param_ == NULL) {
+    hdf5_output_param_ = new ::caffe::HDF5OutputParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.LayerParameter.hdf5_output_param)
+  return hdf5_output_param_;
+}
+::caffe::HDF5OutputParameter* LayerParameter::release_hdf5_output_param() {
+  // @@protoc_insertion_point(field_release:caffe.LayerParameter.hdf5_output_param)
+  clear_has_hdf5_output_param();
+  ::caffe::HDF5OutputParameter* temp = hdf5_output_param_;
+  hdf5_output_param_ = NULL;
+  return temp;
+}
+void LayerParameter::set_allocated_hdf5_output_param(::caffe::HDF5OutputParameter* hdf5_output_param) {
+  delete hdf5_output_param_;
+  hdf5_output_param_ = hdf5_output_param;
+  if (hdf5_output_param) {
+    set_has_hdf5_output_param();
+  } else {
+    clear_has_hdf5_output_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.LayerParameter.hdf5_output_param)
+}
+
+// optional .caffe.HingeLossParameter hinge_loss_param = 114;
+bool LayerParameter::has_hinge_loss_param() const {
+  return (_has_bits_[0] & 0x10000000u) != 0;
+}
+void LayerParameter::set_has_hinge_loss_param() {
+  _has_bits_[0] |= 0x10000000u;
+}
+void LayerParameter::clear_has_hinge_loss_param() {
+  _has_bits_[0] &= ~0x10000000u;
+}
+void LayerParameter::clear_hinge_loss_param() {
+  if (hinge_loss_param_ != NULL) hinge_loss_param_->::caffe::HingeLossParameter::Clear();
+  clear_has_hinge_loss_param();
+}
+const ::caffe::HingeLossParameter& LayerParameter::hinge_loss_param() const {
+  // @@protoc_insertion_point(field_get:caffe.LayerParameter.hinge_loss_param)
+  return hinge_loss_param_ != NULL ? *hinge_loss_param_
+                         : *::caffe::HingeLossParameter::internal_default_instance();
+}
+::caffe::HingeLossParameter* LayerParameter::mutable_hinge_loss_param() {
+  set_has_hinge_loss_param();
+  if (hinge_loss_param_ == NULL) {
+    hinge_loss_param_ = new ::caffe::HingeLossParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.LayerParameter.hinge_loss_param)
+  return hinge_loss_param_;
+}
+::caffe::HingeLossParameter* LayerParameter::release_hinge_loss_param() {
+  // @@protoc_insertion_point(field_release:caffe.LayerParameter.hinge_loss_param)
+  clear_has_hinge_loss_param();
+  ::caffe::HingeLossParameter* temp = hinge_loss_param_;
+  hinge_loss_param_ = NULL;
+  return temp;
+}
+void LayerParameter::set_allocated_hinge_loss_param(::caffe::HingeLossParameter* hinge_loss_param) {
+  delete hinge_loss_param_;
+  hinge_loss_param_ = hinge_loss_param;
+  if (hinge_loss_param) {
+    set_has_hinge_loss_param();
+  } else {
+    clear_has_hinge_loss_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.LayerParameter.hinge_loss_param)
+}
+
+// optional .caffe.ImageDataParameter image_data_param = 115;
+bool LayerParameter::has_image_data_param() const {
+  return (_has_bits_[0] & 0x20000000u) != 0;
+}
+void LayerParameter::set_has_image_data_param() {
+  _has_bits_[0] |= 0x20000000u;
+}
+void LayerParameter::clear_has_image_data_param() {
+  _has_bits_[0] &= ~0x20000000u;
+}
+void LayerParameter::clear_image_data_param() {
+  if (image_data_param_ != NULL) image_data_param_->::caffe::ImageDataParameter::Clear();
+  clear_has_image_data_param();
+}
+const ::caffe::ImageDataParameter& LayerParameter::image_data_param() const {
+  // @@protoc_insertion_point(field_get:caffe.LayerParameter.image_data_param)
+  return image_data_param_ != NULL ? *image_data_param_
+                         : *::caffe::ImageDataParameter::internal_default_instance();
+}
+::caffe::ImageDataParameter* LayerParameter::mutable_image_data_param() {
+  set_has_image_data_param();
+  if (image_data_param_ == NULL) {
+    image_data_param_ = new ::caffe::ImageDataParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.LayerParameter.image_data_param)
+  return image_data_param_;
+}
+::caffe::ImageDataParameter* LayerParameter::release_image_data_param() {
+  // @@protoc_insertion_point(field_release:caffe.LayerParameter.image_data_param)
+  clear_has_image_data_param();
+  ::caffe::ImageDataParameter* temp = image_data_param_;
+  image_data_param_ = NULL;
+  return temp;
+}
+void LayerParameter::set_allocated_image_data_param(::caffe::ImageDataParameter* image_data_param) {
+  delete image_data_param_;
+  image_data_param_ = image_data_param;
+  if (image_data_param) {
+    set_has_image_data_param();
+  } else {
+    clear_has_image_data_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.LayerParameter.image_data_param)
+}
+
+// optional .caffe.InfogainLossParameter infogain_loss_param = 116;
+bool LayerParameter::has_infogain_loss_param() const {
+  return (_has_bits_[0] & 0x40000000u) != 0;
+}
+void LayerParameter::set_has_infogain_loss_param() {
+  _has_bits_[0] |= 0x40000000u;
+}
+void LayerParameter::clear_has_infogain_loss_param() {
+  _has_bits_[0] &= ~0x40000000u;
+}
+void LayerParameter::clear_infogain_loss_param() {
+  if (infogain_loss_param_ != NULL) infogain_loss_param_->::caffe::InfogainLossParameter::Clear();
+  clear_has_infogain_loss_param();
+}
+const ::caffe::InfogainLossParameter& LayerParameter::infogain_loss_param() const {
+  // @@protoc_insertion_point(field_get:caffe.LayerParameter.infogain_loss_param)
+  return infogain_loss_param_ != NULL ? *infogain_loss_param_
+                         : *::caffe::InfogainLossParameter::internal_default_instance();
+}
+::caffe::InfogainLossParameter* LayerParameter::mutable_infogain_loss_param() {
+  set_has_infogain_loss_param();
+  if (infogain_loss_param_ == NULL) {
+    infogain_loss_param_ = new ::caffe::InfogainLossParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.LayerParameter.infogain_loss_param)
+  return infogain_loss_param_;
+}
+::caffe::InfogainLossParameter* LayerParameter::release_infogain_loss_param() {
+  // @@protoc_insertion_point(field_release:caffe.LayerParameter.infogain_loss_param)
+  clear_has_infogain_loss_param();
+  ::caffe::InfogainLossParameter* temp = infogain_loss_param_;
+  infogain_loss_param_ = NULL;
+  return temp;
+}
+void LayerParameter::set_allocated_infogain_loss_param(::caffe::InfogainLossParameter* infogain_loss_param) {
+  delete infogain_loss_param_;
+  infogain_loss_param_ = infogain_loss_param;
+  if (infogain_loss_param) {
+    set_has_infogain_loss_param();
+  } else {
+    clear_has_infogain_loss_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.LayerParameter.infogain_loss_param)
+}
+
+// optional .caffe.InnerProductParameter inner_product_param = 117;
+bool LayerParameter::has_inner_product_param() const {
+  return (_has_bits_[0] & 0x80000000u) != 0;
+}
+void LayerParameter::set_has_inner_product_param() {
+  _has_bits_[0] |= 0x80000000u;
+}
+void LayerParameter::clear_has_inner_product_param() {
+  _has_bits_[0] &= ~0x80000000u;
+}
+void LayerParameter::clear_inner_product_param() {
+  if (inner_product_param_ != NULL) inner_product_param_->::caffe::InnerProductParameter::Clear();
+  clear_has_inner_product_param();
+}
+const ::caffe::InnerProductParameter& LayerParameter::inner_product_param() const {
+  // @@protoc_insertion_point(field_get:caffe.LayerParameter.inner_product_param)
+  return inner_product_param_ != NULL ? *inner_product_param_
+                         : *::caffe::InnerProductParameter::internal_default_instance();
+}
+::caffe::InnerProductParameter* LayerParameter::mutable_inner_product_param() {
+  set_has_inner_product_param();
+  if (inner_product_param_ == NULL) {
+    inner_product_param_ = new ::caffe::InnerProductParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.LayerParameter.inner_product_param)
+  return inner_product_param_;
+}
+::caffe::InnerProductParameter* LayerParameter::release_inner_product_param() {
+  // @@protoc_insertion_point(field_release:caffe.LayerParameter.inner_product_param)
+  clear_has_inner_product_param();
+  ::caffe::InnerProductParameter* temp = inner_product_param_;
+  inner_product_param_ = NULL;
+  return temp;
+}
+void LayerParameter::set_allocated_inner_product_param(::caffe::InnerProductParameter* inner_product_param) {
+  delete inner_product_param_;
+  inner_product_param_ = inner_product_param;
+  if (inner_product_param) {
+    set_has_inner_product_param();
+  } else {
+    clear_has_inner_product_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.LayerParameter.inner_product_param)
+}
+
+// optional .caffe.LogParameter log_param = 134;
+bool LayerParameter::has_log_param() const {
+  return (_has_bits_[1] & 0x00000001u) != 0;
+}
+void LayerParameter::set_has_log_param() {
+  _has_bits_[1] |= 0x00000001u;
+}
+void LayerParameter::clear_has_log_param() {
+  _has_bits_[1] &= ~0x00000001u;
+}
+void LayerParameter::clear_log_param() {
+  if (log_param_ != NULL) log_param_->::caffe::LogParameter::Clear();
+  clear_has_log_param();
+}
+const ::caffe::LogParameter& LayerParameter::log_param() const {
+  // @@protoc_insertion_point(field_get:caffe.LayerParameter.log_param)
+  return log_param_ != NULL ? *log_param_
+                         : *::caffe::LogParameter::internal_default_instance();
+}
+::caffe::LogParameter* LayerParameter::mutable_log_param() {
+  set_has_log_param();
+  if (log_param_ == NULL) {
+    log_param_ = new ::caffe::LogParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.LayerParameter.log_param)
+  return log_param_;
+}
+::caffe::LogParameter* LayerParameter::release_log_param() {
+  // @@protoc_insertion_point(field_release:caffe.LayerParameter.log_param)
+  clear_has_log_param();
+  ::caffe::LogParameter* temp = log_param_;
+  log_param_ = NULL;
+  return temp;
+}
+void LayerParameter::set_allocated_log_param(::caffe::LogParameter* log_param) {
+  delete log_param_;
+  log_param_ = log_param;
+  if (log_param) {
+    set_has_log_param();
+  } else {
+    clear_has_log_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.LayerParameter.log_param)
+}
+
+// optional .caffe.LRNParameter lrn_param = 118;
+bool LayerParameter::has_lrn_param() const {
+  return (_has_bits_[1] & 0x00000002u) != 0;
+}
+void LayerParameter::set_has_lrn_param() {
+  _has_bits_[1] |= 0x00000002u;
+}
+void LayerParameter::clear_has_lrn_param() {
+  _has_bits_[1] &= ~0x00000002u;
+}
+void LayerParameter::clear_lrn_param() {
+  if (lrn_param_ != NULL) lrn_param_->::caffe::LRNParameter::Clear();
+  clear_has_lrn_param();
+}
+const ::caffe::LRNParameter& LayerParameter::lrn_param() const {
+  // @@protoc_insertion_point(field_get:caffe.LayerParameter.lrn_param)
+  return lrn_param_ != NULL ? *lrn_param_
+                         : *::caffe::LRNParameter::internal_default_instance();
+}
+::caffe::LRNParameter* LayerParameter::mutable_lrn_param() {
+  set_has_lrn_param();
+  if (lrn_param_ == NULL) {
+    lrn_param_ = new ::caffe::LRNParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.LayerParameter.lrn_param)
+  return lrn_param_;
+}
+::caffe::LRNParameter* LayerParameter::release_lrn_param() {
+  // @@protoc_insertion_point(field_release:caffe.LayerParameter.lrn_param)
+  clear_has_lrn_param();
+  ::caffe::LRNParameter* temp = lrn_param_;
+  lrn_param_ = NULL;
+  return temp;
+}
+void LayerParameter::set_allocated_lrn_param(::caffe::LRNParameter* lrn_param) {
+  delete lrn_param_;
+  lrn_param_ = lrn_param;
+  if (lrn_param) {
+    set_has_lrn_param();
+  } else {
+    clear_has_lrn_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.LayerParameter.lrn_param)
+}
+
+// optional .caffe.MemoryDataParameter memory_data_param = 119;
+bool LayerParameter::has_memory_data_param() const {
+  return (_has_bits_[1] & 0x00000004u) != 0;
+}
+void LayerParameter::set_has_memory_data_param() {
+  _has_bits_[1] |= 0x00000004u;
+}
+void LayerParameter::clear_has_memory_data_param() {
+  _has_bits_[1] &= ~0x00000004u;
+}
+void LayerParameter::clear_memory_data_param() {
+  if (memory_data_param_ != NULL) memory_data_param_->::caffe::MemoryDataParameter::Clear();
+  clear_has_memory_data_param();
+}
+const ::caffe::MemoryDataParameter& LayerParameter::memory_data_param() const {
+  // @@protoc_insertion_point(field_get:caffe.LayerParameter.memory_data_param)
+  return memory_data_param_ != NULL ? *memory_data_param_
+                         : *::caffe::MemoryDataParameter::internal_default_instance();
+}
+::caffe::MemoryDataParameter* LayerParameter::mutable_memory_data_param() {
+  set_has_memory_data_param();
+  if (memory_data_param_ == NULL) {
+    memory_data_param_ = new ::caffe::MemoryDataParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.LayerParameter.memory_data_param)
+  return memory_data_param_;
+}
+::caffe::MemoryDataParameter* LayerParameter::release_memory_data_param() {
+  // @@protoc_insertion_point(field_release:caffe.LayerParameter.memory_data_param)
+  clear_has_memory_data_param();
+  ::caffe::MemoryDataParameter* temp = memory_data_param_;
+  memory_data_param_ = NULL;
+  return temp;
+}
+void LayerParameter::set_allocated_memory_data_param(::caffe::MemoryDataParameter* memory_data_param) {
+  delete memory_data_param_;
+  memory_data_param_ = memory_data_param;
+  if (memory_data_param) {
+    set_has_memory_data_param();
+  } else {
+    clear_has_memory_data_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.LayerParameter.memory_data_param)
+}
+
+// optional .caffe.MVNParameter mvn_param = 120;
+bool LayerParameter::has_mvn_param() const {
+  return (_has_bits_[1] & 0x00000008u) != 0;
+}
+void LayerParameter::set_has_mvn_param() {
+  _has_bits_[1] |= 0x00000008u;
+}
+void LayerParameter::clear_has_mvn_param() {
+  _has_bits_[1] &= ~0x00000008u;
+}
+void LayerParameter::clear_mvn_param() {
+  if (mvn_param_ != NULL) mvn_param_->::caffe::MVNParameter::Clear();
+  clear_has_mvn_param();
+}
+const ::caffe::MVNParameter& LayerParameter::mvn_param() const {
+  // @@protoc_insertion_point(field_get:caffe.LayerParameter.mvn_param)
+  return mvn_param_ != NULL ? *mvn_param_
+                         : *::caffe::MVNParameter::internal_default_instance();
+}
+::caffe::MVNParameter* LayerParameter::mutable_mvn_param() {
+  set_has_mvn_param();
+  if (mvn_param_ == NULL) {
+    mvn_param_ = new ::caffe::MVNParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.LayerParameter.mvn_param)
+  return mvn_param_;
+}
+::caffe::MVNParameter* LayerParameter::release_mvn_param() {
+  // @@protoc_insertion_point(field_release:caffe.LayerParameter.mvn_param)
+  clear_has_mvn_param();
+  ::caffe::MVNParameter* temp = mvn_param_;
+  mvn_param_ = NULL;
+  return temp;
+}
+void LayerParameter::set_allocated_mvn_param(::caffe::MVNParameter* mvn_param) {
+  delete mvn_param_;
+  mvn_param_ = mvn_param;
+  if (mvn_param) {
+    set_has_mvn_param();
+  } else {
+    clear_has_mvn_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.LayerParameter.mvn_param)
+}
+
+// optional .caffe.NormalizeBBoxParameter normalize_bbox_param = 139;
+bool LayerParameter::has_normalize_bbox_param() const {
+  return (_has_bits_[1] & 0x00000010u) != 0;
+}
+void LayerParameter::set_has_normalize_bbox_param() {
+  _has_bits_[1] |= 0x00000010u;
+}
+void LayerParameter::clear_has_normalize_bbox_param() {
+  _has_bits_[1] &= ~0x00000010u;
+}
+void LayerParameter::clear_normalize_bbox_param() {
+  if (normalize_bbox_param_ != NULL) normalize_bbox_param_->::caffe::NormalizeBBoxParameter::Clear();
+  clear_has_normalize_bbox_param();
+}
+const ::caffe::NormalizeBBoxParameter& LayerParameter::normalize_bbox_param() const {
+  // @@protoc_insertion_point(field_get:caffe.LayerParameter.normalize_bbox_param)
+  return normalize_bbox_param_ != NULL ? *normalize_bbox_param_
+                         : *::caffe::NormalizeBBoxParameter::internal_default_instance();
+}
+::caffe::NormalizeBBoxParameter* LayerParameter::mutable_normalize_bbox_param() {
+  set_has_normalize_bbox_param();
+  if (normalize_bbox_param_ == NULL) {
+    normalize_bbox_param_ = new ::caffe::NormalizeBBoxParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.LayerParameter.normalize_bbox_param)
+  return normalize_bbox_param_;
+}
+::caffe::NormalizeBBoxParameter* LayerParameter::release_normalize_bbox_param() {
+  // @@protoc_insertion_point(field_release:caffe.LayerParameter.normalize_bbox_param)
+  clear_has_normalize_bbox_param();
+  ::caffe::NormalizeBBoxParameter* temp = normalize_bbox_param_;
+  normalize_bbox_param_ = NULL;
+  return temp;
+}
+void LayerParameter::set_allocated_normalize_bbox_param(::caffe::NormalizeBBoxParameter* normalize_bbox_param) {
+  delete normalize_bbox_param_;
+  normalize_bbox_param_ = normalize_bbox_param;
+  if (normalize_bbox_param) {
+    set_has_normalize_bbox_param();
+  } else {
+    clear_has_normalize_bbox_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.LayerParameter.normalize_bbox_param)
+}
+
+// optional .caffe.PermuteParameter permute_param = 138;
+bool LayerParameter::has_permute_param() const {
+  return (_has_bits_[1] & 0x00000020u) != 0;
+}
+void LayerParameter::set_has_permute_param() {
+  _has_bits_[1] |= 0x00000020u;
+}
+void LayerParameter::clear_has_permute_param() {
+  _has_bits_[1] &= ~0x00000020u;
+}
+void LayerParameter::clear_permute_param() {
+  if (permute_param_ != NULL) permute_param_->::caffe::PermuteParameter::Clear();
+  clear_has_permute_param();
+}
+const ::caffe::PermuteParameter& LayerParameter::permute_param() const {
+  // @@protoc_insertion_point(field_get:caffe.LayerParameter.permute_param)
+  return permute_param_ != NULL ? *permute_param_
+                         : *::caffe::PermuteParameter::internal_default_instance();
+}
+::caffe::PermuteParameter* LayerParameter::mutable_permute_param() {
+  set_has_permute_param();
+  if (permute_param_ == NULL) {
+    permute_param_ = new ::caffe::PermuteParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.LayerParameter.permute_param)
+  return permute_param_;
+}
+::caffe::PermuteParameter* LayerParameter::release_permute_param() {
+  // @@protoc_insertion_point(field_release:caffe.LayerParameter.permute_param)
+  clear_has_permute_param();
+  ::caffe::PermuteParameter* temp = permute_param_;
+  permute_param_ = NULL;
+  return temp;
+}
+void LayerParameter::set_allocated_permute_param(::caffe::PermuteParameter* permute_param) {
+  delete permute_param_;
+  permute_param_ = permute_param;
+  if (permute_param) {
+    set_has_permute_param();
+  } else {
+    clear_has_permute_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.LayerParameter.permute_param)
+}
+
+// optional .caffe.PoolingParameter pooling_param = 121;
+bool LayerParameter::has_pooling_param() const {
+  return (_has_bits_[1] & 0x00000040u) != 0;
+}
+void LayerParameter::set_has_pooling_param() {
+  _has_bits_[1] |= 0x00000040u;
+}
+void LayerParameter::clear_has_pooling_param() {
+  _has_bits_[1] &= ~0x00000040u;
+}
+void LayerParameter::clear_pooling_param() {
+  if (pooling_param_ != NULL) pooling_param_->::caffe::PoolingParameter::Clear();
+  clear_has_pooling_param();
+}
+const ::caffe::PoolingParameter& LayerParameter::pooling_param() const {
+  // @@protoc_insertion_point(field_get:caffe.LayerParameter.pooling_param)
+  return pooling_param_ != NULL ? *pooling_param_
+                         : *::caffe::PoolingParameter::internal_default_instance();
+}
+::caffe::PoolingParameter* LayerParameter::mutable_pooling_param() {
+  set_has_pooling_param();
+  if (pooling_param_ == NULL) {
+    pooling_param_ = new ::caffe::PoolingParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.LayerParameter.pooling_param)
+  return pooling_param_;
+}
+::caffe::PoolingParameter* LayerParameter::release_pooling_param() {
+  // @@protoc_insertion_point(field_release:caffe.LayerParameter.pooling_param)
+  clear_has_pooling_param();
+  ::caffe::PoolingParameter* temp = pooling_param_;
+  pooling_param_ = NULL;
+  return temp;
+}
+void LayerParameter::set_allocated_pooling_param(::caffe::PoolingParameter* pooling_param) {
+  delete pooling_param_;
+  pooling_param_ = pooling_param;
+  if (pooling_param) {
+    set_has_pooling_param();
+  } else {
+    clear_has_pooling_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.LayerParameter.pooling_param)
+}
+
+// optional .caffe.PowerParameter power_param = 122;
+bool LayerParameter::has_power_param() const {
+  return (_has_bits_[1] & 0x00000080u) != 0;
+}
+void LayerParameter::set_has_power_param() {
+  _has_bits_[1] |= 0x00000080u;
+}
+void LayerParameter::clear_has_power_param() {
+  _has_bits_[1] &= ~0x00000080u;
+}
+void LayerParameter::clear_power_param() {
+  if (power_param_ != NULL) power_param_->::caffe::PowerParameter::Clear();
+  clear_has_power_param();
+}
+const ::caffe::PowerParameter& LayerParameter::power_param() const {
+  // @@protoc_insertion_point(field_get:caffe.LayerParameter.power_param)
+  return power_param_ != NULL ? *power_param_
+                         : *::caffe::PowerParameter::internal_default_instance();
+}
+::caffe::PowerParameter* LayerParameter::mutable_power_param() {
+  set_has_power_param();
+  if (power_param_ == NULL) {
+    power_param_ = new ::caffe::PowerParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.LayerParameter.power_param)
+  return power_param_;
+}
+::caffe::PowerParameter* LayerParameter::release_power_param() {
+  // @@protoc_insertion_point(field_release:caffe.LayerParameter.power_param)
+  clear_has_power_param();
+  ::caffe::PowerParameter* temp = power_param_;
+  power_param_ = NULL;
+  return temp;
+}
+void LayerParameter::set_allocated_power_param(::caffe::PowerParameter* power_param) {
+  delete power_param_;
+  power_param_ = power_param;
+  if (power_param) {
+    set_has_power_param();
+  } else {
+    clear_has_power_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.LayerParameter.power_param)
+}
+
+// optional .caffe.PReLUParameter prelu_param = 131;
+bool LayerParameter::has_prelu_param() const {
+  return (_has_bits_[1] & 0x00000100u) != 0;
+}
+void LayerParameter::set_has_prelu_param() {
+  _has_bits_[1] |= 0x00000100u;
+}
+void LayerParameter::clear_has_prelu_param() {
+  _has_bits_[1] &= ~0x00000100u;
+}
+void LayerParameter::clear_prelu_param() {
+  if (prelu_param_ != NULL) prelu_param_->::caffe::PReLUParameter::Clear();
+  clear_has_prelu_param();
+}
+const ::caffe::PReLUParameter& LayerParameter::prelu_param() const {
+  // @@protoc_insertion_point(field_get:caffe.LayerParameter.prelu_param)
+  return prelu_param_ != NULL ? *prelu_param_
+                         : *::caffe::PReLUParameter::internal_default_instance();
+}
+::caffe::PReLUParameter* LayerParameter::mutable_prelu_param() {
+  set_has_prelu_param();
+  if (prelu_param_ == NULL) {
+    prelu_param_ = new ::caffe::PReLUParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.LayerParameter.prelu_param)
+  return prelu_param_;
+}
+::caffe::PReLUParameter* LayerParameter::release_prelu_param() {
+  // @@protoc_insertion_point(field_release:caffe.LayerParameter.prelu_param)
+  clear_has_prelu_param();
+  ::caffe::PReLUParameter* temp = prelu_param_;
+  prelu_param_ = NULL;
+  return temp;
+}
+void LayerParameter::set_allocated_prelu_param(::caffe::PReLUParameter* prelu_param) {
+  delete prelu_param_;
+  prelu_param_ = prelu_param;
+  if (prelu_param) {
+    set_has_prelu_param();
+  } else {
+    clear_has_prelu_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.LayerParameter.prelu_param)
+}
+
+// optional .caffe.PriorBoxParameter prior_box_param = 140;
+bool LayerParameter::has_prior_box_param() const {
+  return (_has_bits_[1] & 0x00000200u) != 0;
+}
+void LayerParameter::set_has_prior_box_param() {
+  _has_bits_[1] |= 0x00000200u;
+}
+void LayerParameter::clear_has_prior_box_param() {
+  _has_bits_[1] &= ~0x00000200u;
+}
+void LayerParameter::clear_prior_box_param() {
+  if (prior_box_param_ != NULL) prior_box_param_->::caffe::PriorBoxParameter::Clear();
+  clear_has_prior_box_param();
+}
+const ::caffe::PriorBoxParameter& LayerParameter::prior_box_param() const {
+  // @@protoc_insertion_point(field_get:caffe.LayerParameter.prior_box_param)
+  return prior_box_param_ != NULL ? *prior_box_param_
+                         : *::caffe::PriorBoxParameter::internal_default_instance();
+}
+::caffe::PriorBoxParameter* LayerParameter::mutable_prior_box_param() {
+  set_has_prior_box_param();
+  if (prior_box_param_ == NULL) {
+    prior_box_param_ = new ::caffe::PriorBoxParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.LayerParameter.prior_box_param)
+  return prior_box_param_;
+}
+::caffe::PriorBoxParameter* LayerParameter::release_prior_box_param() {
+  // @@protoc_insertion_point(field_release:caffe.LayerParameter.prior_box_param)
+  clear_has_prior_box_param();
+  ::caffe::PriorBoxParameter* temp = prior_box_param_;
+  prior_box_param_ = NULL;
+  return temp;
+}
+void LayerParameter::set_allocated_prior_box_param(::caffe::PriorBoxParameter* prior_box_param) {
+  delete prior_box_param_;
+  prior_box_param_ = prior_box_param;
+  if (prior_box_param) {
+    set_has_prior_box_param();
+  } else {
+    clear_has_prior_box_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.LayerParameter.prior_box_param)
+}
+
+// optional .caffe.PythonParameter python_param = 130;
+bool LayerParameter::has_python_param() const {
+  return (_has_bits_[1] & 0x00000400u) != 0;
+}
+void LayerParameter::set_has_python_param() {
+  _has_bits_[1] |= 0x00000400u;
+}
+void LayerParameter::clear_has_python_param() {
+  _has_bits_[1] &= ~0x00000400u;
+}
+void LayerParameter::clear_python_param() {
+  if (python_param_ != NULL) python_param_->::caffe::PythonParameter::Clear();
+  clear_has_python_param();
+}
+const ::caffe::PythonParameter& LayerParameter::python_param() const {
+  // @@protoc_insertion_point(field_get:caffe.LayerParameter.python_param)
+  return python_param_ != NULL ? *python_param_
+                         : *::caffe::PythonParameter::internal_default_instance();
+}
+::caffe::PythonParameter* LayerParameter::mutable_python_param() {
+  set_has_python_param();
+  if (python_param_ == NULL) {
+    python_param_ = new ::caffe::PythonParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.LayerParameter.python_param)
+  return python_param_;
+}
+::caffe::PythonParameter* LayerParameter::release_python_param() {
+  // @@protoc_insertion_point(field_release:caffe.LayerParameter.python_param)
+  clear_has_python_param();
+  ::caffe::PythonParameter* temp = python_param_;
+  python_param_ = NULL;
+  return temp;
+}
+void LayerParameter::set_allocated_python_param(::caffe::PythonParameter* python_param) {
+  delete python_param_;
+  python_param_ = python_param;
+  if (python_param) {
+    set_has_python_param();
+  } else {
+    clear_has_python_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.LayerParameter.python_param)
+}
+
+// optional .caffe.ReductionParameter reduction_param = 136;
+bool LayerParameter::has_reduction_param() const {
+  return (_has_bits_[1] & 0x00000800u) != 0;
+}
+void LayerParameter::set_has_reduction_param() {
+  _has_bits_[1] |= 0x00000800u;
+}
+void LayerParameter::clear_has_reduction_param() {
+  _has_bits_[1] &= ~0x00000800u;
+}
+void LayerParameter::clear_reduction_param() {
+  if (reduction_param_ != NULL) reduction_param_->::caffe::ReductionParameter::Clear();
+  clear_has_reduction_param();
+}
+const ::caffe::ReductionParameter& LayerParameter::reduction_param() const {
+  // @@protoc_insertion_point(field_get:caffe.LayerParameter.reduction_param)
+  return reduction_param_ != NULL ? *reduction_param_
+                         : *::caffe::ReductionParameter::internal_default_instance();
+}
+::caffe::ReductionParameter* LayerParameter::mutable_reduction_param() {
+  set_has_reduction_param();
+  if (reduction_param_ == NULL) {
+    reduction_param_ = new ::caffe::ReductionParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.LayerParameter.reduction_param)
+  return reduction_param_;
+}
+::caffe::ReductionParameter* LayerParameter::release_reduction_param() {
+  // @@protoc_insertion_point(field_release:caffe.LayerParameter.reduction_param)
+  clear_has_reduction_param();
+  ::caffe::ReductionParameter* temp = reduction_param_;
+  reduction_param_ = NULL;
+  return temp;
+}
+void LayerParameter::set_allocated_reduction_param(::caffe::ReductionParameter* reduction_param) {
+  delete reduction_param_;
+  reduction_param_ = reduction_param;
+  if (reduction_param) {
+    set_has_reduction_param();
+  } else {
+    clear_has_reduction_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.LayerParameter.reduction_param)
+}
+
+// optional .caffe.ReLUParameter relu_param = 123;
+bool LayerParameter::has_relu_param() const {
+  return (_has_bits_[1] & 0x00001000u) != 0;
+}
+void LayerParameter::set_has_relu_param() {
+  _has_bits_[1] |= 0x00001000u;
+}
+void LayerParameter::clear_has_relu_param() {
+  _has_bits_[1] &= ~0x00001000u;
+}
+void LayerParameter::clear_relu_param() {
+  if (relu_param_ != NULL) relu_param_->::caffe::ReLUParameter::Clear();
+  clear_has_relu_param();
+}
+const ::caffe::ReLUParameter& LayerParameter::relu_param() const {
+  // @@protoc_insertion_point(field_get:caffe.LayerParameter.relu_param)
+  return relu_param_ != NULL ? *relu_param_
+                         : *::caffe::ReLUParameter::internal_default_instance();
+}
+::caffe::ReLUParameter* LayerParameter::mutable_relu_param() {
+  set_has_relu_param();
+  if (relu_param_ == NULL) {
+    relu_param_ = new ::caffe::ReLUParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.LayerParameter.relu_param)
+  return relu_param_;
+}
+::caffe::ReLUParameter* LayerParameter::release_relu_param() {
+  // @@protoc_insertion_point(field_release:caffe.LayerParameter.relu_param)
+  clear_has_relu_param();
+  ::caffe::ReLUParameter* temp = relu_param_;
+  relu_param_ = NULL;
+  return temp;
+}
+void LayerParameter::set_allocated_relu_param(::caffe::ReLUParameter* relu_param) {
+  delete relu_param_;
+  relu_param_ = relu_param;
+  if (relu_param) {
+    set_has_relu_param();
+  } else {
+    clear_has_relu_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.LayerParameter.relu_param)
+}
+
+// optional .caffe.ReshapeParameter reshape_param = 133;
+bool LayerParameter::has_reshape_param() const {
+  return (_has_bits_[1] & 0x00002000u) != 0;
+}
+void LayerParameter::set_has_reshape_param() {
+  _has_bits_[1] |= 0x00002000u;
+}
+void LayerParameter::clear_has_reshape_param() {
+  _has_bits_[1] &= ~0x00002000u;
+}
+void LayerParameter::clear_reshape_param() {
+  if (reshape_param_ != NULL) reshape_param_->::caffe::ReshapeParameter::Clear();
+  clear_has_reshape_param();
+}
+const ::caffe::ReshapeParameter& LayerParameter::reshape_param() const {
+  // @@protoc_insertion_point(field_get:caffe.LayerParameter.reshape_param)
+  return reshape_param_ != NULL ? *reshape_param_
+                         : *::caffe::ReshapeParameter::internal_default_instance();
+}
+::caffe::ReshapeParameter* LayerParameter::mutable_reshape_param() {
+  set_has_reshape_param();
+  if (reshape_param_ == NULL) {
+    reshape_param_ = new ::caffe::ReshapeParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.LayerParameter.reshape_param)
+  return reshape_param_;
+}
+::caffe::ReshapeParameter* LayerParameter::release_reshape_param() {
+  // @@protoc_insertion_point(field_release:caffe.LayerParameter.reshape_param)
+  clear_has_reshape_param();
+  ::caffe::ReshapeParameter* temp = reshape_param_;
+  reshape_param_ = NULL;
+  return temp;
+}
+void LayerParameter::set_allocated_reshape_param(::caffe::ReshapeParameter* reshape_param) {
+  delete reshape_param_;
+  reshape_param_ = reshape_param;
+  if (reshape_param) {
+    set_has_reshape_param();
+  } else {
+    clear_has_reshape_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.LayerParameter.reshape_param)
+}
+
+// optional .caffe.SigmoidParameter sigmoid_param = 124;
+bool LayerParameter::has_sigmoid_param() const {
+  return (_has_bits_[1] & 0x00004000u) != 0;
+}
+void LayerParameter::set_has_sigmoid_param() {
+  _has_bits_[1] |= 0x00004000u;
+}
+void LayerParameter::clear_has_sigmoid_param() {
+  _has_bits_[1] &= ~0x00004000u;
+}
+void LayerParameter::clear_sigmoid_param() {
+  if (sigmoid_param_ != NULL) sigmoid_param_->::caffe::SigmoidParameter::Clear();
+  clear_has_sigmoid_param();
+}
+const ::caffe::SigmoidParameter& LayerParameter::sigmoid_param() const {
+  // @@protoc_insertion_point(field_get:caffe.LayerParameter.sigmoid_param)
+  return sigmoid_param_ != NULL ? *sigmoid_param_
+                         : *::caffe::SigmoidParameter::internal_default_instance();
+}
+::caffe::SigmoidParameter* LayerParameter::mutable_sigmoid_param() {
+  set_has_sigmoid_param();
+  if (sigmoid_param_ == NULL) {
+    sigmoid_param_ = new ::caffe::SigmoidParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.LayerParameter.sigmoid_param)
+  return sigmoid_param_;
+}
+::caffe::SigmoidParameter* LayerParameter::release_sigmoid_param() {
+  // @@protoc_insertion_point(field_release:caffe.LayerParameter.sigmoid_param)
+  clear_has_sigmoid_param();
+  ::caffe::SigmoidParameter* temp = sigmoid_param_;
+  sigmoid_param_ = NULL;
+  return temp;
+}
+void LayerParameter::set_allocated_sigmoid_param(::caffe::SigmoidParameter* sigmoid_param) {
+  delete sigmoid_param_;
+  sigmoid_param_ = sigmoid_param;
+  if (sigmoid_param) {
+    set_has_sigmoid_param();
+  } else {
+    clear_has_sigmoid_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.LayerParameter.sigmoid_param)
+}
+
+// optional .caffe.SliceParameter slice_param = 126;
+bool LayerParameter::has_slice_param() const {
+  return (_has_bits_[1] & 0x00008000u) != 0;
+}
+void LayerParameter::set_has_slice_param() {
+  _has_bits_[1] |= 0x00008000u;
+}
+void LayerParameter::clear_has_slice_param() {
+  _has_bits_[1] &= ~0x00008000u;
+}
+void LayerParameter::clear_slice_param() {
+  if (slice_param_ != NULL) slice_param_->::caffe::SliceParameter::Clear();
+  clear_has_slice_param();
+}
+const ::caffe::SliceParameter& LayerParameter::slice_param() const {
+  // @@protoc_insertion_point(field_get:caffe.LayerParameter.slice_param)
+  return slice_param_ != NULL ? *slice_param_
+                         : *::caffe::SliceParameter::internal_default_instance();
+}
+::caffe::SliceParameter* LayerParameter::mutable_slice_param() {
+  set_has_slice_param();
+  if (slice_param_ == NULL) {
+    slice_param_ = new ::caffe::SliceParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.LayerParameter.slice_param)
+  return slice_param_;
+}
+::caffe::SliceParameter* LayerParameter::release_slice_param() {
+  // @@protoc_insertion_point(field_release:caffe.LayerParameter.slice_param)
+  clear_has_slice_param();
+  ::caffe::SliceParameter* temp = slice_param_;
+  slice_param_ = NULL;
+  return temp;
+}
+void LayerParameter::set_allocated_slice_param(::caffe::SliceParameter* slice_param) {
+  delete slice_param_;
+  slice_param_ = slice_param;
+  if (slice_param) {
+    set_has_slice_param();
+  } else {
+    clear_has_slice_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.LayerParameter.slice_param)
+}
+
+// optional .caffe.SoftmaxParameter softmax_param = 125;
+bool LayerParameter::has_softmax_param() const {
+  return (_has_bits_[1] & 0x00010000u) != 0;
+}
+void LayerParameter::set_has_softmax_param() {
+  _has_bits_[1] |= 0x00010000u;
+}
+void LayerParameter::clear_has_softmax_param() {
+  _has_bits_[1] &= ~0x00010000u;
+}
+void LayerParameter::clear_softmax_param() {
+  if (softmax_param_ != NULL) softmax_param_->::caffe::SoftmaxParameter::Clear();
+  clear_has_softmax_param();
+}
+const ::caffe::SoftmaxParameter& LayerParameter::softmax_param() const {
+  // @@protoc_insertion_point(field_get:caffe.LayerParameter.softmax_param)
+  return softmax_param_ != NULL ? *softmax_param_
+                         : *::caffe::SoftmaxParameter::internal_default_instance();
+}
+::caffe::SoftmaxParameter* LayerParameter::mutable_softmax_param() {
+  set_has_softmax_param();
+  if (softmax_param_ == NULL) {
+    softmax_param_ = new ::caffe::SoftmaxParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.LayerParameter.softmax_param)
+  return softmax_param_;
+}
+::caffe::SoftmaxParameter* LayerParameter::release_softmax_param() {
+  // @@protoc_insertion_point(field_release:caffe.LayerParameter.softmax_param)
+  clear_has_softmax_param();
+  ::caffe::SoftmaxParameter* temp = softmax_param_;
+  softmax_param_ = NULL;
+  return temp;
+}
+void LayerParameter::set_allocated_softmax_param(::caffe::SoftmaxParameter* softmax_param) {
+  delete softmax_param_;
+  softmax_param_ = softmax_param;
+  if (softmax_param) {
+    set_has_softmax_param();
+  } else {
+    clear_has_softmax_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.LayerParameter.softmax_param)
+}
+
+// optional .caffe.SPPParameter spp_param = 132;
+bool LayerParameter::has_spp_param() const {
+  return (_has_bits_[1] & 0x00020000u) != 0;
+}
+void LayerParameter::set_has_spp_param() {
+  _has_bits_[1] |= 0x00020000u;
+}
+void LayerParameter::clear_has_spp_param() {
+  _has_bits_[1] &= ~0x00020000u;
+}
+void LayerParameter::clear_spp_param() {
+  if (spp_param_ != NULL) spp_param_->::caffe::SPPParameter::Clear();
+  clear_has_spp_param();
+}
+const ::caffe::SPPParameter& LayerParameter::spp_param() const {
+  // @@protoc_insertion_point(field_get:caffe.LayerParameter.spp_param)
+  return spp_param_ != NULL ? *spp_param_
+                         : *::caffe::SPPParameter::internal_default_instance();
+}
+::caffe::SPPParameter* LayerParameter::mutable_spp_param() {
+  set_has_spp_param();
+  if (spp_param_ == NULL) {
+    spp_param_ = new ::caffe::SPPParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.LayerParameter.spp_param)
+  return spp_param_;
+}
+::caffe::SPPParameter* LayerParameter::release_spp_param() {
+  // @@protoc_insertion_point(field_release:caffe.LayerParameter.spp_param)
+  clear_has_spp_param();
+  ::caffe::SPPParameter* temp = spp_param_;
+  spp_param_ = NULL;
+  return temp;
+}
+void LayerParameter::set_allocated_spp_param(::caffe::SPPParameter* spp_param) {
+  delete spp_param_;
+  spp_param_ = spp_param;
+  if (spp_param) {
+    set_has_spp_param();
+  } else {
+    clear_has_spp_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.LayerParameter.spp_param)
+}
+
+// optional .caffe.TanHParameter tanh_param = 127;
+bool LayerParameter::has_tanh_param() const {
+  return (_has_bits_[1] & 0x00040000u) != 0;
+}
+void LayerParameter::set_has_tanh_param() {
+  _has_bits_[1] |= 0x00040000u;
+}
+void LayerParameter::clear_has_tanh_param() {
+  _has_bits_[1] &= ~0x00040000u;
+}
+void LayerParameter::clear_tanh_param() {
+  if (tanh_param_ != NULL) tanh_param_->::caffe::TanHParameter::Clear();
+  clear_has_tanh_param();
+}
+const ::caffe::TanHParameter& LayerParameter::tanh_param() const {
+  // @@protoc_insertion_point(field_get:caffe.LayerParameter.tanh_param)
+  return tanh_param_ != NULL ? *tanh_param_
+                         : *::caffe::TanHParameter::internal_default_instance();
+}
+::caffe::TanHParameter* LayerParameter::mutable_tanh_param() {
+  set_has_tanh_param();
+  if (tanh_param_ == NULL) {
+    tanh_param_ = new ::caffe::TanHParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.LayerParameter.tanh_param)
+  return tanh_param_;
+}
+::caffe::TanHParameter* LayerParameter::release_tanh_param() {
+  // @@protoc_insertion_point(field_release:caffe.LayerParameter.tanh_param)
+  clear_has_tanh_param();
+  ::caffe::TanHParameter* temp = tanh_param_;
+  tanh_param_ = NULL;
+  return temp;
+}
+void LayerParameter::set_allocated_tanh_param(::caffe::TanHParameter* tanh_param) {
+  delete tanh_param_;
+  tanh_param_ = tanh_param;
+  if (tanh_param) {
+    set_has_tanh_param();
+  } else {
+    clear_has_tanh_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.LayerParameter.tanh_param)
+}
+
+// optional .caffe.ThresholdParameter threshold_param = 128;
+bool LayerParameter::has_threshold_param() const {
+  return (_has_bits_[1] & 0x00080000u) != 0;
+}
+void LayerParameter::set_has_threshold_param() {
+  _has_bits_[1] |= 0x00080000u;
+}
+void LayerParameter::clear_has_threshold_param() {
+  _has_bits_[1] &= ~0x00080000u;
+}
+void LayerParameter::clear_threshold_param() {
+  if (threshold_param_ != NULL) threshold_param_->::caffe::ThresholdParameter::Clear();
+  clear_has_threshold_param();
+}
+const ::caffe::ThresholdParameter& LayerParameter::threshold_param() const {
+  // @@protoc_insertion_point(field_get:caffe.LayerParameter.threshold_param)
+  return threshold_param_ != NULL ? *threshold_param_
+                         : *::caffe::ThresholdParameter::internal_default_instance();
+}
+::caffe::ThresholdParameter* LayerParameter::mutable_threshold_param() {
+  set_has_threshold_param();
+  if (threshold_param_ == NULL) {
+    threshold_param_ = new ::caffe::ThresholdParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.LayerParameter.threshold_param)
+  return threshold_param_;
+}
+::caffe::ThresholdParameter* LayerParameter::release_threshold_param() {
+  // @@protoc_insertion_point(field_release:caffe.LayerParameter.threshold_param)
+  clear_has_threshold_param();
+  ::caffe::ThresholdParameter* temp = threshold_param_;
+  threshold_param_ = NULL;
+  return temp;
+}
+void LayerParameter::set_allocated_threshold_param(::caffe::ThresholdParameter* threshold_param) {
+  delete threshold_param_;
+  threshold_param_ = threshold_param;
+  if (threshold_param) {
+    set_has_threshold_param();
+  } else {
+    clear_has_threshold_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.LayerParameter.threshold_param)
+}
+
+// optional .caffe.WindowDataParameter window_data_param = 129;
+bool LayerParameter::has_window_data_param() const {
+  return (_has_bits_[1] & 0x00100000u) != 0;
+}
+void LayerParameter::set_has_window_data_param() {
+  _has_bits_[1] |= 0x00100000u;
+}
+void LayerParameter::clear_has_window_data_param() {
+  _has_bits_[1] &= ~0x00100000u;
+}
+void LayerParameter::clear_window_data_param() {
+  if (window_data_param_ != NULL) window_data_param_->::caffe::WindowDataParameter::Clear();
+  clear_has_window_data_param();
+}
+const ::caffe::WindowDataParameter& LayerParameter::window_data_param() const {
+  // @@protoc_insertion_point(field_get:caffe.LayerParameter.window_data_param)
+  return window_data_param_ != NULL ? *window_data_param_
+                         : *::caffe::WindowDataParameter::internal_default_instance();
+}
+::caffe::WindowDataParameter* LayerParameter::mutable_window_data_param() {
+  set_has_window_data_param();
+  if (window_data_param_ == NULL) {
+    window_data_param_ = new ::caffe::WindowDataParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.LayerParameter.window_data_param)
+  return window_data_param_;
+}
+::caffe::WindowDataParameter* LayerParameter::release_window_data_param() {
+  // @@protoc_insertion_point(field_release:caffe.LayerParameter.window_data_param)
+  clear_has_window_data_param();
+  ::caffe::WindowDataParameter* temp = window_data_param_;
+  window_data_param_ = NULL;
+  return temp;
+}
+void LayerParameter::set_allocated_window_data_param(::caffe::WindowDataParameter* window_data_param) {
+  delete window_data_param_;
+  window_data_param_ = window_data_param;
+  if (window_data_param) {
+    set_has_window_data_param();
+  } else {
+    clear_has_window_data_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.LayerParameter.window_data_param)
+}
+
+inline const LayerParameter* LayerParameter::internal_default_instance() {
+  return &LayerParameter_default_instance_.get();
+}
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
+
+// ===================================================================
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const int TransformationParameter::kScaleFieldNumber;
+const int TransformationParameter::kMirrorFieldNumber;
+const int TransformationParameter::kCropSizeFieldNumber;
+const int TransformationParameter::kMeanFileFieldNumber;
+const int TransformationParameter::kMeanValueFieldNumber;
+const int TransformationParameter::kForceColorFieldNumber;
+const int TransformationParameter::kForceGrayFieldNumber;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+
+TransformationParameter::TransformationParameter()
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+  if (this != internal_default_instance()) protobuf_InitDefaults_caffe_2eproto();
+  SharedCtor();
+  // @@protoc_insertion_point(constructor:caffe.TransformationParameter)
+}
+
+void TransformationParameter::InitAsDefaultInstance() {
+}
+
+TransformationParameter::TransformationParameter(const TransformationParameter& from)
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
+  SharedCtor();
+  UnsafeMergeFrom(from);
+  // @@protoc_insertion_point(copy_constructor:caffe.TransformationParameter)
+}
+
+void TransformationParameter::SharedCtor() {
+  _cached_size_ = 0;
+  mean_file_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  ::memset(&crop_size_, 0, reinterpret_cast<char*>(&force_gray_) -
+    reinterpret_cast<char*>(&crop_size_) + sizeof(force_gray_));
+  scale_ = 1;
+}
+
+TransformationParameter::~TransformationParameter() {
+  // @@protoc_insertion_point(destructor:caffe.TransformationParameter)
+  SharedDtor();
+}
+
+void TransformationParameter::SharedDtor() {
+  mean_file_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+
+void TransformationParameter::SetCachedSize(int size) const {
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* TransformationParameter::descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return TransformationParameter_descriptor_;
+}
+
+const TransformationParameter& TransformationParameter::default_instance() {
+  protobuf_InitDefaults_caffe_2eproto();
+  return *internal_default_instance();
+}
+
+::google::protobuf::internal::ExplicitlyConstructed<TransformationParameter> TransformationParameter_default_instance_;
+
+TransformationParameter* TransformationParameter::New(::google::protobuf::Arena* arena) const {
+  TransformationParameter* n = new TransformationParameter;
+  if (arena != NULL) {
+    arena->Own(n);
+  }
+  return n;
+}
+
+void TransformationParameter::Clear() {
+// @@protoc_insertion_point(message_clear_start:caffe.TransformationParameter)
+#if defined(__clang__)
+#define ZR_HELPER_(f) \
+  _Pragma("clang diagnostic push") \
+  _Pragma("clang diagnostic ignored \"-Winvalid-offsetof\"") \
+  __builtin_offsetof(TransformationParameter, f) \
+  _Pragma("clang diagnostic pop")
+#else
+#define ZR_HELPER_(f) reinterpret_cast<char*>(\
+  &reinterpret_cast<TransformationParameter*>(16)->f)
+#endif
+
+#define ZR_(first, last) do {\
+  ::memset(&(first), 0,\
+           ZR_HELPER_(last) - ZR_HELPER_(first) + sizeof(last));\
+} while (0)
+
+  if (_has_bits_[0 / 32] & 111u) {
+    ZR_(crop_size_, force_gray_);
+    scale_ = 1;
+    if (has_mean_file()) {
+      mean_file_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+    }
+  }
+
+#undef ZR_HELPER_
+#undef ZR_
+
+  mean_value_.Clear();
+  _has_bits_.Clear();
+  if (_internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->Clear();
+  }
+}
+
+bool TransformationParameter::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
+  ::google::protobuf::uint32 tag;
+  // @@protoc_insertion_point(parse_start:caffe.TransformationParameter)
+  for (;;) {
+    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+    tag = p.first;
+    if (!p.second) goto handle_unusual;
+    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+      // optional float scale = 1 [default = 1];
+      case 1: {
+        if (tag == 13) {
+          set_has_scale();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
+                 input, &scale_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(16)) goto parse_mirror;
+        break;
+      }
+
+      // optional bool mirror = 2 [default = false];
+      case 2: {
+        if (tag == 16) {
+         parse_mirror:
+          set_has_mirror();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>(
+                 input, &mirror_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(24)) goto parse_crop_size;
+        break;
+      }
+
+      // optional uint32 crop_size = 3 [default = 0];
+      case 3: {
+        if (tag == 24) {
+         parse_crop_size:
+          set_has_crop_size();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>(
+                 input, &crop_size_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(34)) goto parse_mean_file;
+        break;
+      }
+
+      // optional string mean_file = 4;
+      case 4: {
+        if (tag == 34) {
+         parse_mean_file:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+                input, this->mutable_mean_file()));
+          ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+            this->mean_file().data(), this->mean_file().length(),
+            ::google::protobuf::internal::WireFormat::PARSE,
+            "caffe.TransformationParameter.mean_file");
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(45)) goto parse_mean_value;
+        break;
+      }
+
+      // repeated float mean_value = 5;
+      case 5: {
+        if (tag == 45) {
+         parse_mean_value:
+          DO_((::google::protobuf::internal::WireFormatLite::ReadRepeatedPrimitive<
+                   float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
+                 1, 45, input, this->mutable_mean_value())));
+        } else if (tag == 42) {
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPackedPrimitiveNoInline<
+                   float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
+                 input, this->mutable_mean_value())));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(45)) goto parse_mean_value;
+        if (input->ExpectTag(48)) goto parse_force_color;
+        break;
+      }
+
+      // optional bool force_color = 6 [default = false];
+      case 6: {
+        if (tag == 48) {
+         parse_force_color:
+          set_has_force_color();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>(
+                 input, &force_color_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(56)) goto parse_force_gray;
+        break;
+      }
+
+      // optional bool force_gray = 7 [default = false];
+      case 7: {
+        if (tag == 56) {
+         parse_force_gray:
+          set_has_force_gray();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>(
+                 input, &force_gray_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectAtEnd()) goto success;
+        break;
+      }
+
+      default: {
+      handle_unusual:
+        if (tag == 0 ||
+            ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+          goto success;
+        }
+        DO_(::google::protobuf::internal::WireFormat::SkipField(
+              input, tag, mutable_unknown_fields()));
+        break;
+      }
+    }
+  }
+success:
+  // @@protoc_insertion_point(parse_success:caffe.TransformationParameter)
+  return true;
+failure:
+  // @@protoc_insertion_point(parse_failure:caffe.TransformationParameter)
+  return false;
+#undef DO_
+}
+
+void TransformationParameter::SerializeWithCachedSizes(
+    ::google::protobuf::io::CodedOutputStream* output) const {
+  // @@protoc_insertion_point(serialize_start:caffe.TransformationParameter)
+  // optional float scale = 1 [default = 1];
+  if (has_scale()) {
+    ::google::protobuf::internal::WireFormatLite::WriteFloat(1, this->scale(), output);
+  }
+
+  // optional bool mirror = 2 [default = false];
+  if (has_mirror()) {
+    ::google::protobuf::internal::WireFormatLite::WriteBool(2, this->mirror(), output);
+  }
+
+  // optional uint32 crop_size = 3 [default = 0];
+  if (has_crop_size()) {
+    ::google::protobuf::internal::WireFormatLite::WriteUInt32(3, this->crop_size(), output);
+  }
+
+  // optional string mean_file = 4;
+  if (has_mean_file()) {
+    ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->mean_file().data(), this->mean_file().length(),
+      ::google::protobuf::internal::WireFormat::SERIALIZE,
+      "caffe.TransformationParameter.mean_file");
+    ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
+      4, this->mean_file(), output);
+  }
+
+  // repeated float mean_value = 5;
+  for (int i = 0; i < this->mean_value_size(); i++) {
+    ::google::protobuf::internal::WireFormatLite::WriteFloat(
+      5, this->mean_value(i), output);
+  }
+
+  // optional bool force_color = 6 [default = false];
+  if (has_force_color()) {
+    ::google::protobuf::internal::WireFormatLite::WriteBool(6, this->force_color(), output);
+  }
+
+  // optional bool force_gray = 7 [default = false];
+  if (has_force_gray()) {
+    ::google::protobuf::internal::WireFormatLite::WriteBool(7, this->force_gray(), output);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
+        unknown_fields(), output);
+  }
+  // @@protoc_insertion_point(serialize_end:caffe.TransformationParameter)
+}
+
+::google::protobuf::uint8* TransformationParameter::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
+  (void)deterministic; // Unused
+  // @@protoc_insertion_point(serialize_to_array_start:caffe.TransformationParameter)
+  // optional float scale = 1 [default = 1];
+  if (has_scale()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteFloatToArray(1, this->scale(), target);
+  }
+
+  // optional bool mirror = 2 [default = false];
+  if (has_mirror()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(2, this->mirror(), target);
+  }
+
+  // optional uint32 crop_size = 3 [default = 0];
+  if (has_crop_size()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteUInt32ToArray(3, this->crop_size(), target);
+  }
+
+  // optional string mean_file = 4;
+  if (has_mean_file()) {
+    ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->mean_file().data(), this->mean_file().length(),
+      ::google::protobuf::internal::WireFormat::SERIALIZE,
+      "caffe.TransformationParameter.mean_file");
+    target =
+      ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
+        4, this->mean_file(), target);
+  }
+
+  // repeated float mean_value = 5;
+  for (int i = 0; i < this->mean_value_size(); i++) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      WriteFloatToArray(5, this->mean_value(i), target);
+  }
+
+  // optional bool force_color = 6 [default = false];
+  if (has_force_color()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(6, this->force_color(), target);
+  }
+
+  // optional bool force_gray = 7 [default = false];
+  if (has_force_gray()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(7, this->force_gray(), target);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
+        unknown_fields(), target);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:caffe.TransformationParameter)
+  return target;
+}
+
+size_t TransformationParameter::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:caffe.TransformationParameter)
+  size_t total_size = 0;
+
+  if (_has_bits_[0 / 32] & 111u) {
+    // optional float scale = 1 [default = 1];
+    if (has_scale()) {
+      total_size += 1 + 4;
+    }
+
+    // optional bool mirror = 2 [default = false];
+    if (has_mirror()) {
+      total_size += 1 + 1;
+    }
+
+    // optional uint32 crop_size = 3 [default = 0];
+    if (has_crop_size()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::UInt32Size(
+          this->crop_size());
+    }
+
+    // optional string mean_file = 4;
+    if (has_mean_file()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::StringSize(
+          this->mean_file());
+    }
+
+    // optional bool force_color = 6 [default = false];
+    if (has_force_color()) {
+      total_size += 1 + 1;
+    }
+
+    // optional bool force_gray = 7 [default = false];
+    if (has_force_gray()) {
+      total_size += 1 + 1;
+    }
+
+  }
+  // repeated float mean_value = 5;
+  {
+    size_t data_size = 0;
+    unsigned int count = this->mean_value_size();
+    data_size = 4UL * count;
+    total_size += 1 *
+                  ::google::protobuf::internal::FromIntSize(this->mean_value_size());
+    total_size += data_size;
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    total_size +=
+      ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
+        unknown_fields());
+  }
+  int cached_size = ::google::protobuf::internal::ToCachedSize(total_size);
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = cached_size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+  return total_size;
+}
+
+void TransformationParameter::MergeFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_merge_from_start:caffe.TransformationParameter)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const TransformationParameter* source =
+      ::google::protobuf::internal::DynamicCastToGenerated<const TransformationParameter>(
+          &from);
+  if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:caffe.TransformationParameter)
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:caffe.TransformationParameter)
+    UnsafeMergeFrom(*source);
+  }
+}
+
+void TransformationParameter::MergeFrom(const TransformationParameter& from) {
+// @@protoc_insertion_point(class_specific_merge_from_start:caffe.TransformationParameter)
+  if (GOOGLE_PREDICT_TRUE(&from != this)) {
+    UnsafeMergeFrom(from);
+  } else {
+    MergeFromFail(__LINE__);
+  }
+}
+
+void TransformationParameter::UnsafeMergeFrom(const TransformationParameter& from) {
+  GOOGLE_DCHECK(&from != this);
+  mean_value_.UnsafeMergeFrom(from.mean_value_);
+  if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+    if (from.has_scale()) {
+      set_scale(from.scale());
+    }
+    if (from.has_mirror()) {
+      set_mirror(from.mirror());
+    }
+    if (from.has_crop_size()) {
+      set_crop_size(from.crop_size());
+    }
+    if (from.has_mean_file()) {
+      set_has_mean_file();
+      mean_file_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.mean_file_);
+    }
+    if (from.has_force_color()) {
+      set_force_color(from.force_color());
+    }
+    if (from.has_force_gray()) {
+      set_force_gray(from.force_gray());
+    }
+  }
+  if (from._internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::UnknownFieldSet::MergeToInternalMetdata(
+      from.unknown_fields(), &_internal_metadata_);
+  }
+}
+
+void TransformationParameter::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:caffe.TransformationParameter)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void TransformationParameter::CopyFrom(const TransformationParameter& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:caffe.TransformationParameter)
+  if (&from == this) return;
+  Clear();
+  UnsafeMergeFrom(from);
+}
+
+bool TransformationParameter::IsInitialized() const {
+
+  return true;
+}
+
+void TransformationParameter::Swap(TransformationParameter* other) {
+  if (other == this) return;
+  InternalSwap(other);
+}
+void TransformationParameter::InternalSwap(TransformationParameter* other) {
+  std::swap(scale_, other->scale_);
+  std::swap(mirror_, other->mirror_);
+  std::swap(crop_size_, other->crop_size_);
+  mean_file_.Swap(&other->mean_file_);
+  mean_value_.UnsafeArenaSwap(&other->mean_value_);
+  std::swap(force_color_, other->force_color_);
+  std::swap(force_gray_, other->force_gray_);
+  std::swap(_has_bits_[0], other->_has_bits_[0]);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
+}
+
+::google::protobuf::Metadata TransformationParameter::GetMetadata() const {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::Metadata metadata;
+  metadata.descriptor = TransformationParameter_descriptor_;
+  metadata.reflection = TransformationParameter_reflection_;
+  return metadata;
+}
+
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// TransformationParameter
+
+// optional float scale = 1 [default = 1];
+bool TransformationParameter::has_scale() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+void TransformationParameter::set_has_scale() {
+  _has_bits_[0] |= 0x00000001u;
+}
+void TransformationParameter::clear_has_scale() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+void TransformationParameter::clear_scale() {
+  scale_ = 1;
+  clear_has_scale();
+}
+float TransformationParameter::scale() const {
+  // @@protoc_insertion_point(field_get:caffe.TransformationParameter.scale)
+  return scale_;
+}
+void TransformationParameter::set_scale(float value) {
+  set_has_scale();
+  scale_ = value;
+  // @@protoc_insertion_point(field_set:caffe.TransformationParameter.scale)
+}
+
+// optional bool mirror = 2 [default = false];
+bool TransformationParameter::has_mirror() const {
+  return (_has_bits_[0] & 0x00000002u) != 0;
+}
+void TransformationParameter::set_has_mirror() {
+  _has_bits_[0] |= 0x00000002u;
+}
+void TransformationParameter::clear_has_mirror() {
+  _has_bits_[0] &= ~0x00000002u;
+}
+void TransformationParameter::clear_mirror() {
+  mirror_ = false;
+  clear_has_mirror();
+}
+bool TransformationParameter::mirror() const {
+  // @@protoc_insertion_point(field_get:caffe.TransformationParameter.mirror)
+  return mirror_;
+}
+void TransformationParameter::set_mirror(bool value) {
+  set_has_mirror();
+  mirror_ = value;
+  // @@protoc_insertion_point(field_set:caffe.TransformationParameter.mirror)
+}
+
+// optional uint32 crop_size = 3 [default = 0];
+bool TransformationParameter::has_crop_size() const {
+  return (_has_bits_[0] & 0x00000004u) != 0;
+}
+void TransformationParameter::set_has_crop_size() {
+  _has_bits_[0] |= 0x00000004u;
+}
+void TransformationParameter::clear_has_crop_size() {
+  _has_bits_[0] &= ~0x00000004u;
+}
+void TransformationParameter::clear_crop_size() {
+  crop_size_ = 0u;
+  clear_has_crop_size();
+}
+::google::protobuf::uint32 TransformationParameter::crop_size() const {
+  // @@protoc_insertion_point(field_get:caffe.TransformationParameter.crop_size)
+  return crop_size_;
+}
+void TransformationParameter::set_crop_size(::google::protobuf::uint32 value) {
+  set_has_crop_size();
+  crop_size_ = value;
+  // @@protoc_insertion_point(field_set:caffe.TransformationParameter.crop_size)
+}
+
+// optional string mean_file = 4;
+bool TransformationParameter::has_mean_file() const {
+  return (_has_bits_[0] & 0x00000008u) != 0;
+}
+void TransformationParameter::set_has_mean_file() {
+  _has_bits_[0] |= 0x00000008u;
+}
+void TransformationParameter::clear_has_mean_file() {
+  _has_bits_[0] &= ~0x00000008u;
+}
+void TransformationParameter::clear_mean_file() {
+  mean_file_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  clear_has_mean_file();
+}
+const ::std::string& TransformationParameter::mean_file() const {
+  // @@protoc_insertion_point(field_get:caffe.TransformationParameter.mean_file)
+  return mean_file_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+void TransformationParameter::set_mean_file(const ::std::string& value) {
+  set_has_mean_file();
+  mean_file_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:caffe.TransformationParameter.mean_file)
+}
+void TransformationParameter::set_mean_file(const char* value) {
+  set_has_mean_file();
+  mean_file_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:caffe.TransformationParameter.mean_file)
+}
+void TransformationParameter::set_mean_file(const char* value, size_t size) {
+  set_has_mean_file();
+  mean_file_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:caffe.TransformationParameter.mean_file)
+}
+::std::string* TransformationParameter::mutable_mean_file() {
+  set_has_mean_file();
+  // @@protoc_insertion_point(field_mutable:caffe.TransformationParameter.mean_file)
+  return mean_file_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+::std::string* TransformationParameter::release_mean_file() {
+  // @@protoc_insertion_point(field_release:caffe.TransformationParameter.mean_file)
+  clear_has_mean_file();
+  return mean_file_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+void TransformationParameter::set_allocated_mean_file(::std::string* mean_file) {
+  if (mean_file != NULL) {
+    set_has_mean_file();
+  } else {
+    clear_has_mean_file();
+  }
+  mean_file_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), mean_file);
+  // @@protoc_insertion_point(field_set_allocated:caffe.TransformationParameter.mean_file)
+}
+
+// repeated float mean_value = 5;
+int TransformationParameter::mean_value_size() const {
+  return mean_value_.size();
+}
+void TransformationParameter::clear_mean_value() {
+  mean_value_.Clear();
+}
+float TransformationParameter::mean_value(int index) const {
+  // @@protoc_insertion_point(field_get:caffe.TransformationParameter.mean_value)
+  return mean_value_.Get(index);
+}
+void TransformationParameter::set_mean_value(int index, float value) {
+  mean_value_.Set(index, value);
+  // @@protoc_insertion_point(field_set:caffe.TransformationParameter.mean_value)
+}
+void TransformationParameter::add_mean_value(float value) {
+  mean_value_.Add(value);
+  // @@protoc_insertion_point(field_add:caffe.TransformationParameter.mean_value)
+}
+const ::google::protobuf::RepeatedField< float >&
+TransformationParameter::mean_value() const {
+  // @@protoc_insertion_point(field_list:caffe.TransformationParameter.mean_value)
+  return mean_value_;
+}
+::google::protobuf::RepeatedField< float >*
+TransformationParameter::mutable_mean_value() {
+  // @@protoc_insertion_point(field_mutable_list:caffe.TransformationParameter.mean_value)
+  return &mean_value_;
+}
+
+// optional bool force_color = 6 [default = false];
+bool TransformationParameter::has_force_color() const {
+  return (_has_bits_[0] & 0x00000020u) != 0;
+}
+void TransformationParameter::set_has_force_color() {
+  _has_bits_[0] |= 0x00000020u;
+}
+void TransformationParameter::clear_has_force_color() {
+  _has_bits_[0] &= ~0x00000020u;
+}
+void TransformationParameter::clear_force_color() {
+  force_color_ = false;
+  clear_has_force_color();
+}
+bool TransformationParameter::force_color() const {
+  // @@protoc_insertion_point(field_get:caffe.TransformationParameter.force_color)
+  return force_color_;
+}
+void TransformationParameter::set_force_color(bool value) {
+  set_has_force_color();
+  force_color_ = value;
+  // @@protoc_insertion_point(field_set:caffe.TransformationParameter.force_color)
+}
+
+// optional bool force_gray = 7 [default = false];
+bool TransformationParameter::has_force_gray() const {
+  return (_has_bits_[0] & 0x00000040u) != 0;
+}
+void TransformationParameter::set_has_force_gray() {
+  _has_bits_[0] |= 0x00000040u;
+}
+void TransformationParameter::clear_has_force_gray() {
+  _has_bits_[0] &= ~0x00000040u;
+}
+void TransformationParameter::clear_force_gray() {
+  force_gray_ = false;
+  clear_has_force_gray();
+}
+bool TransformationParameter::force_gray() const {
+  // @@protoc_insertion_point(field_get:caffe.TransformationParameter.force_gray)
+  return force_gray_;
+}
+void TransformationParameter::set_force_gray(bool value) {
+  set_has_force_gray();
+  force_gray_ = value;
+  // @@protoc_insertion_point(field_set:caffe.TransformationParameter.force_gray)
+}
+
+inline const TransformationParameter* TransformationParameter::internal_default_instance() {
+  return &TransformationParameter_default_instance_.get();
+}
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
+
+// ===================================================================
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const int LossParameter::kIgnoreLabelFieldNumber;
+const int LossParameter::kNormalizeFieldNumber;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+
+LossParameter::LossParameter()
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+  if (this != internal_default_instance()) protobuf_InitDefaults_caffe_2eproto();
+  SharedCtor();
+  // @@protoc_insertion_point(constructor:caffe.LossParameter)
+}
+
+void LossParameter::InitAsDefaultInstance() {
+}
+
+LossParameter::LossParameter(const LossParameter& from)
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
+  SharedCtor();
+  UnsafeMergeFrom(from);
+  // @@protoc_insertion_point(copy_constructor:caffe.LossParameter)
+}
+
+void LossParameter::SharedCtor() {
+  _cached_size_ = 0;
+  ignore_label_ = 0;
+  normalize_ = true;
+}
+
+LossParameter::~LossParameter() {
+  // @@protoc_insertion_point(destructor:caffe.LossParameter)
+  SharedDtor();
+}
+
+void LossParameter::SharedDtor() {
+}
+
+void LossParameter::SetCachedSize(int size) const {
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* LossParameter::descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return LossParameter_descriptor_;
+}
+
+const LossParameter& LossParameter::default_instance() {
+  protobuf_InitDefaults_caffe_2eproto();
+  return *internal_default_instance();
+}
+
+::google::protobuf::internal::ExplicitlyConstructed<LossParameter> LossParameter_default_instance_;
+
+LossParameter* LossParameter::New(::google::protobuf::Arena* arena) const {
+  LossParameter* n = new LossParameter;
+  if (arena != NULL) {
+    arena->Own(n);
+  }
+  return n;
+}
+
+void LossParameter::Clear() {
+// @@protoc_insertion_point(message_clear_start:caffe.LossParameter)
+  if (_has_bits_[0 / 32] & 3u) {
+    ignore_label_ = 0;
+    normalize_ = true;
+  }
+  _has_bits_.Clear();
+  if (_internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->Clear();
+  }
+}
+
+bool LossParameter::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
+  ::google::protobuf::uint32 tag;
+  // @@protoc_insertion_point(parse_start:caffe.LossParameter)
+  for (;;) {
+    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+    tag = p.first;
+    if (!p.second) goto handle_unusual;
+    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+      // optional int32 ignore_label = 1;
+      case 1: {
+        if (tag == 8) {
+          set_has_ignore_label();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
+                 input, &ignore_label_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(16)) goto parse_normalize;
+        break;
+      }
+
+      // optional bool normalize = 2 [default = true];
+      case 2: {
+        if (tag == 16) {
+         parse_normalize:
+          set_has_normalize();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>(
+                 input, &normalize_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectAtEnd()) goto success;
+        break;
+      }
+
+      default: {
+      handle_unusual:
+        if (tag == 0 ||
+            ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+          goto success;
+        }
+        DO_(::google::protobuf::internal::WireFormat::SkipField(
+              input, tag, mutable_unknown_fields()));
+        break;
+      }
+    }
+  }
+success:
+  // @@protoc_insertion_point(parse_success:caffe.LossParameter)
+  return true;
+failure:
+  // @@protoc_insertion_point(parse_failure:caffe.LossParameter)
+  return false;
+#undef DO_
+}
+
+void LossParameter::SerializeWithCachedSizes(
+    ::google::protobuf::io::CodedOutputStream* output) const {
+  // @@protoc_insertion_point(serialize_start:caffe.LossParameter)
+  // optional int32 ignore_label = 1;
+  if (has_ignore_label()) {
+    ::google::protobuf::internal::WireFormatLite::WriteInt32(1, this->ignore_label(), output);
+  }
+
+  // optional bool normalize = 2 [default = true];
+  if (has_normalize()) {
+    ::google::protobuf::internal::WireFormatLite::WriteBool(2, this->normalize(), output);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
+        unknown_fields(), output);
+  }
+  // @@protoc_insertion_point(serialize_end:caffe.LossParameter)
+}
+
+::google::protobuf::uint8* LossParameter::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
+  (void)deterministic; // Unused
+  // @@protoc_insertion_point(serialize_to_array_start:caffe.LossParameter)
+  // optional int32 ignore_label = 1;
+  if (has_ignore_label()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteInt32ToArray(1, this->ignore_label(), target);
+  }
+
+  // optional bool normalize = 2 [default = true];
+  if (has_normalize()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(2, this->normalize(), target);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
+        unknown_fields(), target);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:caffe.LossParameter)
+  return target;
+}
+
+size_t LossParameter::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:caffe.LossParameter)
+  size_t total_size = 0;
+
+  if (_has_bits_[0 / 32] & 3u) {
+    // optional int32 ignore_label = 1;
+    if (has_ignore_label()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::Int32Size(
+          this->ignore_label());
+    }
+
+    // optional bool normalize = 2 [default = true];
+    if (has_normalize()) {
+      total_size += 1 + 1;
+    }
+
+  }
+  if (_internal_metadata_.have_unknown_fields()) {
+    total_size +=
+      ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
+        unknown_fields());
+  }
+  int cached_size = ::google::protobuf::internal::ToCachedSize(total_size);
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = cached_size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+  return total_size;
+}
+
+void LossParameter::MergeFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_merge_from_start:caffe.LossParameter)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const LossParameter* source =
+      ::google::protobuf::internal::DynamicCastToGenerated<const LossParameter>(
+          &from);
+  if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:caffe.LossParameter)
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:caffe.LossParameter)
+    UnsafeMergeFrom(*source);
+  }
+}
+
+void LossParameter::MergeFrom(const LossParameter& from) {
+// @@protoc_insertion_point(class_specific_merge_from_start:caffe.LossParameter)
+  if (GOOGLE_PREDICT_TRUE(&from != this)) {
+    UnsafeMergeFrom(from);
+  } else {
+    MergeFromFail(__LINE__);
+  }
+}
+
+void LossParameter::UnsafeMergeFrom(const LossParameter& from) {
+  GOOGLE_DCHECK(&from != this);
+  if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+    if (from.has_ignore_label()) {
+      set_ignore_label(from.ignore_label());
+    }
+    if (from.has_normalize()) {
+      set_normalize(from.normalize());
+    }
+  }
+  if (from._internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::UnknownFieldSet::MergeToInternalMetdata(
+      from.unknown_fields(), &_internal_metadata_);
+  }
+}
+
+void LossParameter::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:caffe.LossParameter)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void LossParameter::CopyFrom(const LossParameter& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:caffe.LossParameter)
+  if (&from == this) return;
+  Clear();
+  UnsafeMergeFrom(from);
+}
+
+bool LossParameter::IsInitialized() const {
+
+  return true;
+}
+
+void LossParameter::Swap(LossParameter* other) {
+  if (other == this) return;
+  InternalSwap(other);
+}
+void LossParameter::InternalSwap(LossParameter* other) {
+  std::swap(ignore_label_, other->ignore_label_);
+  std::swap(normalize_, other->normalize_);
+  std::swap(_has_bits_[0], other->_has_bits_[0]);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
+}
+
+::google::protobuf::Metadata LossParameter::GetMetadata() const {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::Metadata metadata;
+  metadata.descriptor = LossParameter_descriptor_;
+  metadata.reflection = LossParameter_reflection_;
+  return metadata;
+}
+
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// LossParameter
+
+// optional int32 ignore_label = 1;
+bool LossParameter::has_ignore_label() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+void LossParameter::set_has_ignore_label() {
+  _has_bits_[0] |= 0x00000001u;
+}
+void LossParameter::clear_has_ignore_label() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+void LossParameter::clear_ignore_label() {
+  ignore_label_ = 0;
+  clear_has_ignore_label();
+}
+::google::protobuf::int32 LossParameter::ignore_label() const {
+  // @@protoc_insertion_point(field_get:caffe.LossParameter.ignore_label)
+  return ignore_label_;
+}
+void LossParameter::set_ignore_label(::google::protobuf::int32 value) {
+  set_has_ignore_label();
+  ignore_label_ = value;
+  // @@protoc_insertion_point(field_set:caffe.LossParameter.ignore_label)
+}
+
+// optional bool normalize = 2 [default = true];
+bool LossParameter::has_normalize() const {
+  return (_has_bits_[0] & 0x00000002u) != 0;
+}
+void LossParameter::set_has_normalize() {
+  _has_bits_[0] |= 0x00000002u;
+}
+void LossParameter::clear_has_normalize() {
+  _has_bits_[0] &= ~0x00000002u;
+}
+void LossParameter::clear_normalize() {
+  normalize_ = true;
+  clear_has_normalize();
+}
+bool LossParameter::normalize() const {
+  // @@protoc_insertion_point(field_get:caffe.LossParameter.normalize)
+  return normalize_;
+}
+void LossParameter::set_normalize(bool value) {
+  set_has_normalize();
+  normalize_ = value;
+  // @@protoc_insertion_point(field_set:caffe.LossParameter.normalize)
+}
+
+inline const LossParameter* LossParameter::internal_default_instance() {
+  return &LossParameter_default_instance_.get();
+}
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
+
+// ===================================================================
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const int AccuracyParameter::kTopKFieldNumber;
+const int AccuracyParameter::kAxisFieldNumber;
+const int AccuracyParameter::kIgnoreLabelFieldNumber;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+
+AccuracyParameter::AccuracyParameter()
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+  if (this != internal_default_instance()) protobuf_InitDefaults_caffe_2eproto();
+  SharedCtor();
+  // @@protoc_insertion_point(constructor:caffe.AccuracyParameter)
+}
+
+void AccuracyParameter::InitAsDefaultInstance() {
+}
+
+AccuracyParameter::AccuracyParameter(const AccuracyParameter& from)
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
+  SharedCtor();
+  UnsafeMergeFrom(from);
+  // @@protoc_insertion_point(copy_constructor:caffe.AccuracyParameter)
+}
+
+void AccuracyParameter::SharedCtor() {
+  _cached_size_ = 0;
+  ignore_label_ = 0;
+  top_k_ = 1u;
+  axis_ = 1;
+}
+
+AccuracyParameter::~AccuracyParameter() {
+  // @@protoc_insertion_point(destructor:caffe.AccuracyParameter)
+  SharedDtor();
+}
+
+void AccuracyParameter::SharedDtor() {
+}
+
+void AccuracyParameter::SetCachedSize(int size) const {
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* AccuracyParameter::descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return AccuracyParameter_descriptor_;
+}
+
+const AccuracyParameter& AccuracyParameter::default_instance() {
+  protobuf_InitDefaults_caffe_2eproto();
+  return *internal_default_instance();
+}
+
+::google::protobuf::internal::ExplicitlyConstructed<AccuracyParameter> AccuracyParameter_default_instance_;
+
+AccuracyParameter* AccuracyParameter::New(::google::protobuf::Arena* arena) const {
+  AccuracyParameter* n = new AccuracyParameter;
+  if (arena != NULL) {
+    arena->Own(n);
+  }
+  return n;
+}
+
+void AccuracyParameter::Clear() {
+// @@protoc_insertion_point(message_clear_start:caffe.AccuracyParameter)
+  if (_has_bits_[0 / 32] & 7u) {
+    top_k_ = 1u;
+    axis_ = 1;
+    ignore_label_ = 0;
+  }
+  _has_bits_.Clear();
+  if (_internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->Clear();
+  }
+}
+
+bool AccuracyParameter::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
+  ::google::protobuf::uint32 tag;
+  // @@protoc_insertion_point(parse_start:caffe.AccuracyParameter)
+  for (;;) {
+    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+    tag = p.first;
+    if (!p.second) goto handle_unusual;
+    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+      // optional uint32 top_k = 1 [default = 1];
+      case 1: {
+        if (tag == 8) {
+          set_has_top_k();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>(
+                 input, &top_k_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(16)) goto parse_axis;
+        break;
+      }
+
+      // optional int32 axis = 2 [default = 1];
+      case 2: {
+        if (tag == 16) {
+         parse_axis:
+          set_has_axis();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
+                 input, &axis_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(24)) goto parse_ignore_label;
+        break;
+      }
+
+      // optional int32 ignore_label = 3;
+      case 3: {
+        if (tag == 24) {
+         parse_ignore_label:
+          set_has_ignore_label();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
+                 input, &ignore_label_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectAtEnd()) goto success;
+        break;
+      }
+
+      default: {
+      handle_unusual:
+        if (tag == 0 ||
+            ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+          goto success;
+        }
+        DO_(::google::protobuf::internal::WireFormat::SkipField(
+              input, tag, mutable_unknown_fields()));
+        break;
+      }
+    }
+  }
+success:
+  // @@protoc_insertion_point(parse_success:caffe.AccuracyParameter)
+  return true;
+failure:
+  // @@protoc_insertion_point(parse_failure:caffe.AccuracyParameter)
+  return false;
+#undef DO_
+}
+
+void AccuracyParameter::SerializeWithCachedSizes(
+    ::google::protobuf::io::CodedOutputStream* output) const {
+  // @@protoc_insertion_point(serialize_start:caffe.AccuracyParameter)
+  // optional uint32 top_k = 1 [default = 1];
+  if (has_top_k()) {
+    ::google::protobuf::internal::WireFormatLite::WriteUInt32(1, this->top_k(), output);
+  }
+
+  // optional int32 axis = 2 [default = 1];
+  if (has_axis()) {
+    ::google::protobuf::internal::WireFormatLite::WriteInt32(2, this->axis(), output);
+  }
+
+  // optional int32 ignore_label = 3;
+  if (has_ignore_label()) {
+    ::google::protobuf::internal::WireFormatLite::WriteInt32(3, this->ignore_label(), output);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
+        unknown_fields(), output);
+  }
+  // @@protoc_insertion_point(serialize_end:caffe.AccuracyParameter)
+}
+
+::google::protobuf::uint8* AccuracyParameter::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
+  (void)deterministic; // Unused
+  // @@protoc_insertion_point(serialize_to_array_start:caffe.AccuracyParameter)
+  // optional uint32 top_k = 1 [default = 1];
+  if (has_top_k()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteUInt32ToArray(1, this->top_k(), target);
+  }
+
+  // optional int32 axis = 2 [default = 1];
+  if (has_axis()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteInt32ToArray(2, this->axis(), target);
+  }
+
+  // optional int32 ignore_label = 3;
+  if (has_ignore_label()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteInt32ToArray(3, this->ignore_label(), target);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
+        unknown_fields(), target);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:caffe.AccuracyParameter)
+  return target;
+}
+
+size_t AccuracyParameter::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:caffe.AccuracyParameter)
+  size_t total_size = 0;
+
+  if (_has_bits_[0 / 32] & 7u) {
+    // optional uint32 top_k = 1 [default = 1];
+    if (has_top_k()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::UInt32Size(
+          this->top_k());
+    }
+
+    // optional int32 axis = 2 [default = 1];
+    if (has_axis()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::Int32Size(
+          this->axis());
+    }
+
+    // optional int32 ignore_label = 3;
+    if (has_ignore_label()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::Int32Size(
+          this->ignore_label());
+    }
+
+  }
+  if (_internal_metadata_.have_unknown_fields()) {
+    total_size +=
+      ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
+        unknown_fields());
+  }
+  int cached_size = ::google::protobuf::internal::ToCachedSize(total_size);
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = cached_size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+  return total_size;
+}
+
+void AccuracyParameter::MergeFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_merge_from_start:caffe.AccuracyParameter)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const AccuracyParameter* source =
+      ::google::protobuf::internal::DynamicCastToGenerated<const AccuracyParameter>(
+          &from);
+  if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:caffe.AccuracyParameter)
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:caffe.AccuracyParameter)
+    UnsafeMergeFrom(*source);
+  }
+}
+
+void AccuracyParameter::MergeFrom(const AccuracyParameter& from) {
+// @@protoc_insertion_point(class_specific_merge_from_start:caffe.AccuracyParameter)
+  if (GOOGLE_PREDICT_TRUE(&from != this)) {
+    UnsafeMergeFrom(from);
+  } else {
+    MergeFromFail(__LINE__);
+  }
+}
+
+void AccuracyParameter::UnsafeMergeFrom(const AccuracyParameter& from) {
+  GOOGLE_DCHECK(&from != this);
+  if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+    if (from.has_top_k()) {
+      set_top_k(from.top_k());
+    }
+    if (from.has_axis()) {
+      set_axis(from.axis());
+    }
+    if (from.has_ignore_label()) {
+      set_ignore_label(from.ignore_label());
+    }
+  }
+  if (from._internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::UnknownFieldSet::MergeToInternalMetdata(
+      from.unknown_fields(), &_internal_metadata_);
+  }
+}
+
+void AccuracyParameter::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:caffe.AccuracyParameter)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void AccuracyParameter::CopyFrom(const AccuracyParameter& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:caffe.AccuracyParameter)
+  if (&from == this) return;
+  Clear();
+  UnsafeMergeFrom(from);
+}
+
+bool AccuracyParameter::IsInitialized() const {
+
+  return true;
+}
+
+void AccuracyParameter::Swap(AccuracyParameter* other) {
+  if (other == this) return;
+  InternalSwap(other);
+}
+void AccuracyParameter::InternalSwap(AccuracyParameter* other) {
+  std::swap(top_k_, other->top_k_);
+  std::swap(axis_, other->axis_);
+  std::swap(ignore_label_, other->ignore_label_);
+  std::swap(_has_bits_[0], other->_has_bits_[0]);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
+}
+
+::google::protobuf::Metadata AccuracyParameter::GetMetadata() const {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::Metadata metadata;
+  metadata.descriptor = AccuracyParameter_descriptor_;
+  metadata.reflection = AccuracyParameter_reflection_;
+  return metadata;
+}
+
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// AccuracyParameter
+
+// optional uint32 top_k = 1 [default = 1];
+bool AccuracyParameter::has_top_k() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+void AccuracyParameter::set_has_top_k() {
+  _has_bits_[0] |= 0x00000001u;
+}
+void AccuracyParameter::clear_has_top_k() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+void AccuracyParameter::clear_top_k() {
+  top_k_ = 1u;
+  clear_has_top_k();
+}
+::google::protobuf::uint32 AccuracyParameter::top_k() const {
+  // @@protoc_insertion_point(field_get:caffe.AccuracyParameter.top_k)
+  return top_k_;
+}
+void AccuracyParameter::set_top_k(::google::protobuf::uint32 value) {
+  set_has_top_k();
+  top_k_ = value;
+  // @@protoc_insertion_point(field_set:caffe.AccuracyParameter.top_k)
+}
+
+// optional int32 axis = 2 [default = 1];
+bool AccuracyParameter::has_axis() const {
+  return (_has_bits_[0] & 0x00000002u) != 0;
+}
+void AccuracyParameter::set_has_axis() {
+  _has_bits_[0] |= 0x00000002u;
+}
+void AccuracyParameter::clear_has_axis() {
+  _has_bits_[0] &= ~0x00000002u;
+}
+void AccuracyParameter::clear_axis() {
+  axis_ = 1;
+  clear_has_axis();
+}
+::google::protobuf::int32 AccuracyParameter::axis() const {
+  // @@protoc_insertion_point(field_get:caffe.AccuracyParameter.axis)
+  return axis_;
+}
+void AccuracyParameter::set_axis(::google::protobuf::int32 value) {
+  set_has_axis();
+  axis_ = value;
+  // @@protoc_insertion_point(field_set:caffe.AccuracyParameter.axis)
+}
+
+// optional int32 ignore_label = 3;
+bool AccuracyParameter::has_ignore_label() const {
+  return (_has_bits_[0] & 0x00000004u) != 0;
+}
+void AccuracyParameter::set_has_ignore_label() {
+  _has_bits_[0] |= 0x00000004u;
+}
+void AccuracyParameter::clear_has_ignore_label() {
+  _has_bits_[0] &= ~0x00000004u;
+}
+void AccuracyParameter::clear_ignore_label() {
+  ignore_label_ = 0;
+  clear_has_ignore_label();
+}
+::google::protobuf::int32 AccuracyParameter::ignore_label() const {
+  // @@protoc_insertion_point(field_get:caffe.AccuracyParameter.ignore_label)
+  return ignore_label_;
+}
+void AccuracyParameter::set_ignore_label(::google::protobuf::int32 value) {
+  set_has_ignore_label();
+  ignore_label_ = value;
+  // @@protoc_insertion_point(field_set:caffe.AccuracyParameter.ignore_label)
+}
+
+inline const AccuracyParameter* AccuracyParameter::internal_default_instance() {
+  return &AccuracyParameter_default_instance_.get();
+}
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
+
+// ===================================================================
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const int ArgMaxParameter::kOutMaxValFieldNumber;
+const int ArgMaxParameter::kTopKFieldNumber;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+
+ArgMaxParameter::ArgMaxParameter()
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+  if (this != internal_default_instance()) protobuf_InitDefaults_caffe_2eproto();
+  SharedCtor();
+  // @@protoc_insertion_point(constructor:caffe.ArgMaxParameter)
+}
+
+void ArgMaxParameter::InitAsDefaultInstance() {
+}
+
+ArgMaxParameter::ArgMaxParameter(const ArgMaxParameter& from)
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
+  SharedCtor();
+  UnsafeMergeFrom(from);
+  // @@protoc_insertion_point(copy_constructor:caffe.ArgMaxParameter)
+}
+
+void ArgMaxParameter::SharedCtor() {
+  _cached_size_ = 0;
+  out_max_val_ = false;
+  top_k_ = 1u;
+}
+
+ArgMaxParameter::~ArgMaxParameter() {
+  // @@protoc_insertion_point(destructor:caffe.ArgMaxParameter)
+  SharedDtor();
+}
+
+void ArgMaxParameter::SharedDtor() {
+}
+
+void ArgMaxParameter::SetCachedSize(int size) const {
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* ArgMaxParameter::descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return ArgMaxParameter_descriptor_;
+}
+
+const ArgMaxParameter& ArgMaxParameter::default_instance() {
+  protobuf_InitDefaults_caffe_2eproto();
+  return *internal_default_instance();
+}
+
+::google::protobuf::internal::ExplicitlyConstructed<ArgMaxParameter> ArgMaxParameter_default_instance_;
+
+ArgMaxParameter* ArgMaxParameter::New(::google::protobuf::Arena* arena) const {
+  ArgMaxParameter* n = new ArgMaxParameter;
+  if (arena != NULL) {
+    arena->Own(n);
+  }
+  return n;
+}
+
+void ArgMaxParameter::Clear() {
+// @@protoc_insertion_point(message_clear_start:caffe.ArgMaxParameter)
+  if (_has_bits_[0 / 32] & 3u) {
+    out_max_val_ = false;
+    top_k_ = 1u;
+  }
+  _has_bits_.Clear();
+  if (_internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->Clear();
+  }
+}
+
+bool ArgMaxParameter::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
+  ::google::protobuf::uint32 tag;
+  // @@protoc_insertion_point(parse_start:caffe.ArgMaxParameter)
+  for (;;) {
+    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+    tag = p.first;
+    if (!p.second) goto handle_unusual;
+    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+      // optional bool out_max_val = 1 [default = false];
+      case 1: {
+        if (tag == 8) {
+          set_has_out_max_val();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>(
+                 input, &out_max_val_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(16)) goto parse_top_k;
+        break;
+      }
+
+      // optional uint32 top_k = 2 [default = 1];
+      case 2: {
+        if (tag == 16) {
+         parse_top_k:
+          set_has_top_k();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>(
+                 input, &top_k_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectAtEnd()) goto success;
+        break;
+      }
+
+      default: {
+      handle_unusual:
+        if (tag == 0 ||
+            ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+          goto success;
+        }
+        DO_(::google::protobuf::internal::WireFormat::SkipField(
+              input, tag, mutable_unknown_fields()));
+        break;
+      }
+    }
+  }
+success:
+  // @@protoc_insertion_point(parse_success:caffe.ArgMaxParameter)
+  return true;
+failure:
+  // @@protoc_insertion_point(parse_failure:caffe.ArgMaxParameter)
+  return false;
+#undef DO_
+}
+
+void ArgMaxParameter::SerializeWithCachedSizes(
+    ::google::protobuf::io::CodedOutputStream* output) const {
+  // @@protoc_insertion_point(serialize_start:caffe.ArgMaxParameter)
+  // optional bool out_max_val = 1 [default = false];
+  if (has_out_max_val()) {
+    ::google::protobuf::internal::WireFormatLite::WriteBool(1, this->out_max_val(), output);
+  }
+
+  // optional uint32 top_k = 2 [default = 1];
+  if (has_top_k()) {
+    ::google::protobuf::internal::WireFormatLite::WriteUInt32(2, this->top_k(), output);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
+        unknown_fields(), output);
+  }
+  // @@protoc_insertion_point(serialize_end:caffe.ArgMaxParameter)
+}
+
+::google::protobuf::uint8* ArgMaxParameter::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
+  (void)deterministic; // Unused
+  // @@protoc_insertion_point(serialize_to_array_start:caffe.ArgMaxParameter)
+  // optional bool out_max_val = 1 [default = false];
+  if (has_out_max_val()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(1, this->out_max_val(), target);
+  }
+
+  // optional uint32 top_k = 2 [default = 1];
+  if (has_top_k()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteUInt32ToArray(2, this->top_k(), target);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
+        unknown_fields(), target);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:caffe.ArgMaxParameter)
+  return target;
+}
+
+size_t ArgMaxParameter::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:caffe.ArgMaxParameter)
+  size_t total_size = 0;
+
+  if (_has_bits_[0 / 32] & 3u) {
+    // optional bool out_max_val = 1 [default = false];
+    if (has_out_max_val()) {
+      total_size += 1 + 1;
+    }
+
+    // optional uint32 top_k = 2 [default = 1];
+    if (has_top_k()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::UInt32Size(
+          this->top_k());
+    }
+
+  }
+  if (_internal_metadata_.have_unknown_fields()) {
+    total_size +=
+      ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
+        unknown_fields());
+  }
+  int cached_size = ::google::protobuf::internal::ToCachedSize(total_size);
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = cached_size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+  return total_size;
+}
+
+void ArgMaxParameter::MergeFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_merge_from_start:caffe.ArgMaxParameter)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const ArgMaxParameter* source =
+      ::google::protobuf::internal::DynamicCastToGenerated<const ArgMaxParameter>(
+          &from);
+  if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:caffe.ArgMaxParameter)
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:caffe.ArgMaxParameter)
+    UnsafeMergeFrom(*source);
+  }
+}
+
+void ArgMaxParameter::MergeFrom(const ArgMaxParameter& from) {
+// @@protoc_insertion_point(class_specific_merge_from_start:caffe.ArgMaxParameter)
+  if (GOOGLE_PREDICT_TRUE(&from != this)) {
+    UnsafeMergeFrom(from);
+  } else {
+    MergeFromFail(__LINE__);
+  }
+}
+
+void ArgMaxParameter::UnsafeMergeFrom(const ArgMaxParameter& from) {
+  GOOGLE_DCHECK(&from != this);
+  if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+    if (from.has_out_max_val()) {
+      set_out_max_val(from.out_max_val());
+    }
+    if (from.has_top_k()) {
+      set_top_k(from.top_k());
+    }
+  }
+  if (from._internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::UnknownFieldSet::MergeToInternalMetdata(
+      from.unknown_fields(), &_internal_metadata_);
+  }
+}
+
+void ArgMaxParameter::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:caffe.ArgMaxParameter)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void ArgMaxParameter::CopyFrom(const ArgMaxParameter& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:caffe.ArgMaxParameter)
+  if (&from == this) return;
+  Clear();
+  UnsafeMergeFrom(from);
+}
+
+bool ArgMaxParameter::IsInitialized() const {
+
+  return true;
+}
+
+void ArgMaxParameter::Swap(ArgMaxParameter* other) {
+  if (other == this) return;
+  InternalSwap(other);
+}
+void ArgMaxParameter::InternalSwap(ArgMaxParameter* other) {
+  std::swap(out_max_val_, other->out_max_val_);
+  std::swap(top_k_, other->top_k_);
+  std::swap(_has_bits_[0], other->_has_bits_[0]);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
+}
+
+::google::protobuf::Metadata ArgMaxParameter::GetMetadata() const {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::Metadata metadata;
+  metadata.descriptor = ArgMaxParameter_descriptor_;
+  metadata.reflection = ArgMaxParameter_reflection_;
+  return metadata;
+}
+
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// ArgMaxParameter
+
+// optional bool out_max_val = 1 [default = false];
+bool ArgMaxParameter::has_out_max_val() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+void ArgMaxParameter::set_has_out_max_val() {
+  _has_bits_[0] |= 0x00000001u;
+}
+void ArgMaxParameter::clear_has_out_max_val() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+void ArgMaxParameter::clear_out_max_val() {
+  out_max_val_ = false;
+  clear_has_out_max_val();
+}
+bool ArgMaxParameter::out_max_val() const {
+  // @@protoc_insertion_point(field_get:caffe.ArgMaxParameter.out_max_val)
+  return out_max_val_;
+}
+void ArgMaxParameter::set_out_max_val(bool value) {
+  set_has_out_max_val();
+  out_max_val_ = value;
+  // @@protoc_insertion_point(field_set:caffe.ArgMaxParameter.out_max_val)
+}
+
+// optional uint32 top_k = 2 [default = 1];
+bool ArgMaxParameter::has_top_k() const {
+  return (_has_bits_[0] & 0x00000002u) != 0;
+}
+void ArgMaxParameter::set_has_top_k() {
+  _has_bits_[0] |= 0x00000002u;
+}
+void ArgMaxParameter::clear_has_top_k() {
+  _has_bits_[0] &= ~0x00000002u;
+}
+void ArgMaxParameter::clear_top_k() {
+  top_k_ = 1u;
+  clear_has_top_k();
+}
+::google::protobuf::uint32 ArgMaxParameter::top_k() const {
+  // @@protoc_insertion_point(field_get:caffe.ArgMaxParameter.top_k)
+  return top_k_;
+}
+void ArgMaxParameter::set_top_k(::google::protobuf::uint32 value) {
+  set_has_top_k();
+  top_k_ = value;
+  // @@protoc_insertion_point(field_set:caffe.ArgMaxParameter.top_k)
+}
+
+inline const ArgMaxParameter* ArgMaxParameter::internal_default_instance() {
+  return &ArgMaxParameter_default_instance_.get();
+}
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
+
+// ===================================================================
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const int ConcatParameter::kAxisFieldNumber;
+const int ConcatParameter::kConcatDimFieldNumber;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+
+ConcatParameter::ConcatParameter()
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+  if (this != internal_default_instance()) protobuf_InitDefaults_caffe_2eproto();
+  SharedCtor();
+  // @@protoc_insertion_point(constructor:caffe.ConcatParameter)
+}
+
+void ConcatParameter::InitAsDefaultInstance() {
+}
+
+ConcatParameter::ConcatParameter(const ConcatParameter& from)
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
+  SharedCtor();
+  UnsafeMergeFrom(from);
+  // @@protoc_insertion_point(copy_constructor:caffe.ConcatParameter)
+}
+
+void ConcatParameter::SharedCtor() {
+  _cached_size_ = 0;
+  axis_ = 1;
+  concat_dim_ = 1u;
+}
+
+ConcatParameter::~ConcatParameter() {
+  // @@protoc_insertion_point(destructor:caffe.ConcatParameter)
+  SharedDtor();
+}
+
+void ConcatParameter::SharedDtor() {
+}
+
+void ConcatParameter::SetCachedSize(int size) const {
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* ConcatParameter::descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return ConcatParameter_descriptor_;
+}
+
+const ConcatParameter& ConcatParameter::default_instance() {
+  protobuf_InitDefaults_caffe_2eproto();
+  return *internal_default_instance();
+}
+
+::google::protobuf::internal::ExplicitlyConstructed<ConcatParameter> ConcatParameter_default_instance_;
+
+ConcatParameter* ConcatParameter::New(::google::protobuf::Arena* arena) const {
+  ConcatParameter* n = new ConcatParameter;
+  if (arena != NULL) {
+    arena->Own(n);
+  }
+  return n;
+}
+
+void ConcatParameter::Clear() {
+// @@protoc_insertion_point(message_clear_start:caffe.ConcatParameter)
+  if (_has_bits_[0 / 32] & 3u) {
+    axis_ = 1;
+    concat_dim_ = 1u;
+  }
+  _has_bits_.Clear();
+  if (_internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->Clear();
+  }
+}
+
+bool ConcatParameter::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
+  ::google::protobuf::uint32 tag;
+  // @@protoc_insertion_point(parse_start:caffe.ConcatParameter)
+  for (;;) {
+    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+    tag = p.first;
+    if (!p.second) goto handle_unusual;
+    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+      // optional uint32 concat_dim = 1 [default = 1];
+      case 1: {
+        if (tag == 8) {
+          set_has_concat_dim();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>(
+                 input, &concat_dim_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(16)) goto parse_axis;
+        break;
+      }
+
+      // optional int32 axis = 2 [default = 1];
+      case 2: {
+        if (tag == 16) {
+         parse_axis:
+          set_has_axis();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
+                 input, &axis_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectAtEnd()) goto success;
+        break;
+      }
+
+      default: {
+      handle_unusual:
+        if (tag == 0 ||
+            ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+          goto success;
+        }
+        DO_(::google::protobuf::internal::WireFormat::SkipField(
+              input, tag, mutable_unknown_fields()));
+        break;
+      }
+    }
+  }
+success:
+  // @@protoc_insertion_point(parse_success:caffe.ConcatParameter)
+  return true;
+failure:
+  // @@protoc_insertion_point(parse_failure:caffe.ConcatParameter)
+  return false;
+#undef DO_
+}
+
+void ConcatParameter::SerializeWithCachedSizes(
+    ::google::protobuf::io::CodedOutputStream* output) const {
+  // @@protoc_insertion_point(serialize_start:caffe.ConcatParameter)
+  // optional uint32 concat_dim = 1 [default = 1];
+  if (has_concat_dim()) {
+    ::google::protobuf::internal::WireFormatLite::WriteUInt32(1, this->concat_dim(), output);
+  }
+
+  // optional int32 axis = 2 [default = 1];
+  if (has_axis()) {
+    ::google::protobuf::internal::WireFormatLite::WriteInt32(2, this->axis(), output);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
+        unknown_fields(), output);
+  }
+  // @@protoc_insertion_point(serialize_end:caffe.ConcatParameter)
+}
+
+::google::protobuf::uint8* ConcatParameter::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
+  (void)deterministic; // Unused
+  // @@protoc_insertion_point(serialize_to_array_start:caffe.ConcatParameter)
+  // optional uint32 concat_dim = 1 [default = 1];
+  if (has_concat_dim()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteUInt32ToArray(1, this->concat_dim(), target);
+  }
+
+  // optional int32 axis = 2 [default = 1];
+  if (has_axis()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteInt32ToArray(2, this->axis(), target);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
+        unknown_fields(), target);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:caffe.ConcatParameter)
+  return target;
+}
+
+size_t ConcatParameter::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:caffe.ConcatParameter)
+  size_t total_size = 0;
+
+  if (_has_bits_[0 / 32] & 3u) {
+    // optional int32 axis = 2 [default = 1];
+    if (has_axis()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::Int32Size(
+          this->axis());
+    }
+
+    // optional uint32 concat_dim = 1 [default = 1];
+    if (has_concat_dim()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::UInt32Size(
+          this->concat_dim());
+    }
+
+  }
+  if (_internal_metadata_.have_unknown_fields()) {
+    total_size +=
+      ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
+        unknown_fields());
+  }
+  int cached_size = ::google::protobuf::internal::ToCachedSize(total_size);
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = cached_size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+  return total_size;
+}
+
+void ConcatParameter::MergeFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_merge_from_start:caffe.ConcatParameter)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const ConcatParameter* source =
+      ::google::protobuf::internal::DynamicCastToGenerated<const ConcatParameter>(
+          &from);
+  if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:caffe.ConcatParameter)
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:caffe.ConcatParameter)
+    UnsafeMergeFrom(*source);
+  }
+}
+
+void ConcatParameter::MergeFrom(const ConcatParameter& from) {
+// @@protoc_insertion_point(class_specific_merge_from_start:caffe.ConcatParameter)
+  if (GOOGLE_PREDICT_TRUE(&from != this)) {
+    UnsafeMergeFrom(from);
+  } else {
+    MergeFromFail(__LINE__);
+  }
+}
+
+void ConcatParameter::UnsafeMergeFrom(const ConcatParameter& from) {
+  GOOGLE_DCHECK(&from != this);
+  if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+    if (from.has_axis()) {
+      set_axis(from.axis());
+    }
+    if (from.has_concat_dim()) {
+      set_concat_dim(from.concat_dim());
+    }
+  }
+  if (from._internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::UnknownFieldSet::MergeToInternalMetdata(
+      from.unknown_fields(), &_internal_metadata_);
+  }
+}
+
+void ConcatParameter::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:caffe.ConcatParameter)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void ConcatParameter::CopyFrom(const ConcatParameter& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:caffe.ConcatParameter)
+  if (&from == this) return;
+  Clear();
+  UnsafeMergeFrom(from);
+}
+
+bool ConcatParameter::IsInitialized() const {
+
+  return true;
+}
+
+void ConcatParameter::Swap(ConcatParameter* other) {
+  if (other == this) return;
+  InternalSwap(other);
+}
+void ConcatParameter::InternalSwap(ConcatParameter* other) {
+  std::swap(axis_, other->axis_);
+  std::swap(concat_dim_, other->concat_dim_);
+  std::swap(_has_bits_[0], other->_has_bits_[0]);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
+}
+
+::google::protobuf::Metadata ConcatParameter::GetMetadata() const {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::Metadata metadata;
+  metadata.descriptor = ConcatParameter_descriptor_;
+  metadata.reflection = ConcatParameter_reflection_;
+  return metadata;
+}
+
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// ConcatParameter
+
+// optional int32 axis = 2 [default = 1];
+bool ConcatParameter::has_axis() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+void ConcatParameter::set_has_axis() {
+  _has_bits_[0] |= 0x00000001u;
+}
+void ConcatParameter::clear_has_axis() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+void ConcatParameter::clear_axis() {
+  axis_ = 1;
+  clear_has_axis();
+}
+::google::protobuf::int32 ConcatParameter::axis() const {
+  // @@protoc_insertion_point(field_get:caffe.ConcatParameter.axis)
+  return axis_;
+}
+void ConcatParameter::set_axis(::google::protobuf::int32 value) {
+  set_has_axis();
+  axis_ = value;
+  // @@protoc_insertion_point(field_set:caffe.ConcatParameter.axis)
+}
+
+// optional uint32 concat_dim = 1 [default = 1];
+bool ConcatParameter::has_concat_dim() const {
+  return (_has_bits_[0] & 0x00000002u) != 0;
+}
+void ConcatParameter::set_has_concat_dim() {
+  _has_bits_[0] |= 0x00000002u;
+}
+void ConcatParameter::clear_has_concat_dim() {
+  _has_bits_[0] &= ~0x00000002u;
+}
+void ConcatParameter::clear_concat_dim() {
+  concat_dim_ = 1u;
+  clear_has_concat_dim();
+}
+::google::protobuf::uint32 ConcatParameter::concat_dim() const {
+  // @@protoc_insertion_point(field_get:caffe.ConcatParameter.concat_dim)
+  return concat_dim_;
+}
+void ConcatParameter::set_concat_dim(::google::protobuf::uint32 value) {
+  set_has_concat_dim();
+  concat_dim_ = value;
+  // @@protoc_insertion_point(field_set:caffe.ConcatParameter.concat_dim)
+}
+
+inline const ConcatParameter* ConcatParameter::internal_default_instance() {
+  return &ConcatParameter_default_instance_.get();
+}
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
+
+// ===================================================================
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const int ContrastiveLossParameter::kMarginFieldNumber;
+const int ContrastiveLossParameter::kLegacyVersionFieldNumber;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+
+ContrastiveLossParameter::ContrastiveLossParameter()
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+  if (this != internal_default_instance()) protobuf_InitDefaults_caffe_2eproto();
+  SharedCtor();
+  // @@protoc_insertion_point(constructor:caffe.ContrastiveLossParameter)
+}
+
+void ContrastiveLossParameter::InitAsDefaultInstance() {
+}
+
+ContrastiveLossParameter::ContrastiveLossParameter(const ContrastiveLossParameter& from)
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
+  SharedCtor();
+  UnsafeMergeFrom(from);
+  // @@protoc_insertion_point(copy_constructor:caffe.ContrastiveLossParameter)
+}
+
+void ContrastiveLossParameter::SharedCtor() {
+  _cached_size_ = 0;
+  legacy_version_ = false;
+  margin_ = 1;
+}
+
+ContrastiveLossParameter::~ContrastiveLossParameter() {
+  // @@protoc_insertion_point(destructor:caffe.ContrastiveLossParameter)
+  SharedDtor();
+}
+
+void ContrastiveLossParameter::SharedDtor() {
+}
+
+void ContrastiveLossParameter::SetCachedSize(int size) const {
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* ContrastiveLossParameter::descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return ContrastiveLossParameter_descriptor_;
+}
+
+const ContrastiveLossParameter& ContrastiveLossParameter::default_instance() {
+  protobuf_InitDefaults_caffe_2eproto();
+  return *internal_default_instance();
+}
+
+::google::protobuf::internal::ExplicitlyConstructed<ContrastiveLossParameter> ContrastiveLossParameter_default_instance_;
+
+ContrastiveLossParameter* ContrastiveLossParameter::New(::google::protobuf::Arena* arena) const {
+  ContrastiveLossParameter* n = new ContrastiveLossParameter;
+  if (arena != NULL) {
+    arena->Own(n);
+  }
+  return n;
+}
+
+void ContrastiveLossParameter::Clear() {
+// @@protoc_insertion_point(message_clear_start:caffe.ContrastiveLossParameter)
+  if (_has_bits_[0 / 32] & 3u) {
+    margin_ = 1;
+    legacy_version_ = false;
+  }
+  _has_bits_.Clear();
+  if (_internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->Clear();
+  }
+}
+
+bool ContrastiveLossParameter::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
+  ::google::protobuf::uint32 tag;
+  // @@protoc_insertion_point(parse_start:caffe.ContrastiveLossParameter)
+  for (;;) {
+    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+    tag = p.first;
+    if (!p.second) goto handle_unusual;
+    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+      // optional float margin = 1 [default = 1];
+      case 1: {
+        if (tag == 13) {
+          set_has_margin();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
+                 input, &margin_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(16)) goto parse_legacy_version;
+        break;
+      }
+
+      // optional bool legacy_version = 2 [default = false];
+      case 2: {
+        if (tag == 16) {
+         parse_legacy_version:
+          set_has_legacy_version();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>(
+                 input, &legacy_version_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectAtEnd()) goto success;
+        break;
+      }
+
+      default: {
+      handle_unusual:
+        if (tag == 0 ||
+            ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+          goto success;
+        }
+        DO_(::google::protobuf::internal::WireFormat::SkipField(
+              input, tag, mutable_unknown_fields()));
+        break;
+      }
+    }
+  }
+success:
+  // @@protoc_insertion_point(parse_success:caffe.ContrastiveLossParameter)
+  return true;
+failure:
+  // @@protoc_insertion_point(parse_failure:caffe.ContrastiveLossParameter)
+  return false;
+#undef DO_
+}
+
+void ContrastiveLossParameter::SerializeWithCachedSizes(
+    ::google::protobuf::io::CodedOutputStream* output) const {
+  // @@protoc_insertion_point(serialize_start:caffe.ContrastiveLossParameter)
+  // optional float margin = 1 [default = 1];
+  if (has_margin()) {
+    ::google::protobuf::internal::WireFormatLite::WriteFloat(1, this->margin(), output);
+  }
+
+  // optional bool legacy_version = 2 [default = false];
+  if (has_legacy_version()) {
+    ::google::protobuf::internal::WireFormatLite::WriteBool(2, this->legacy_version(), output);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
+        unknown_fields(), output);
+  }
+  // @@protoc_insertion_point(serialize_end:caffe.ContrastiveLossParameter)
+}
+
+::google::protobuf::uint8* ContrastiveLossParameter::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
+  (void)deterministic; // Unused
+  // @@protoc_insertion_point(serialize_to_array_start:caffe.ContrastiveLossParameter)
+  // optional float margin = 1 [default = 1];
+  if (has_margin()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteFloatToArray(1, this->margin(), target);
+  }
+
+  // optional bool legacy_version = 2 [default = false];
+  if (has_legacy_version()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(2, this->legacy_version(), target);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
+        unknown_fields(), target);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:caffe.ContrastiveLossParameter)
+  return target;
+}
+
+size_t ContrastiveLossParameter::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:caffe.ContrastiveLossParameter)
+  size_t total_size = 0;
+
+  if (_has_bits_[0 / 32] & 3u) {
+    // optional float margin = 1 [default = 1];
+    if (has_margin()) {
+      total_size += 1 + 4;
+    }
+
+    // optional bool legacy_version = 2 [default = false];
+    if (has_legacy_version()) {
+      total_size += 1 + 1;
+    }
+
+  }
+  if (_internal_metadata_.have_unknown_fields()) {
+    total_size +=
+      ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
+        unknown_fields());
+  }
+  int cached_size = ::google::protobuf::internal::ToCachedSize(total_size);
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = cached_size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+  return total_size;
+}
+
+void ContrastiveLossParameter::MergeFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_merge_from_start:caffe.ContrastiveLossParameter)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const ContrastiveLossParameter* source =
+      ::google::protobuf::internal::DynamicCastToGenerated<const ContrastiveLossParameter>(
+          &from);
+  if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:caffe.ContrastiveLossParameter)
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:caffe.ContrastiveLossParameter)
+    UnsafeMergeFrom(*source);
+  }
+}
+
+void ContrastiveLossParameter::MergeFrom(const ContrastiveLossParameter& from) {
+// @@protoc_insertion_point(class_specific_merge_from_start:caffe.ContrastiveLossParameter)
+  if (GOOGLE_PREDICT_TRUE(&from != this)) {
+    UnsafeMergeFrom(from);
+  } else {
+    MergeFromFail(__LINE__);
+  }
+}
+
+void ContrastiveLossParameter::UnsafeMergeFrom(const ContrastiveLossParameter& from) {
+  GOOGLE_DCHECK(&from != this);
+  if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+    if (from.has_margin()) {
+      set_margin(from.margin());
+    }
+    if (from.has_legacy_version()) {
+      set_legacy_version(from.legacy_version());
+    }
+  }
+  if (from._internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::UnknownFieldSet::MergeToInternalMetdata(
+      from.unknown_fields(), &_internal_metadata_);
+  }
+}
+
+void ContrastiveLossParameter::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:caffe.ContrastiveLossParameter)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void ContrastiveLossParameter::CopyFrom(const ContrastiveLossParameter& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:caffe.ContrastiveLossParameter)
+  if (&from == this) return;
+  Clear();
+  UnsafeMergeFrom(from);
+}
+
+bool ContrastiveLossParameter::IsInitialized() const {
+
+  return true;
+}
+
+void ContrastiveLossParameter::Swap(ContrastiveLossParameter* other) {
+  if (other == this) return;
+  InternalSwap(other);
+}
+void ContrastiveLossParameter::InternalSwap(ContrastiveLossParameter* other) {
+  std::swap(margin_, other->margin_);
+  std::swap(legacy_version_, other->legacy_version_);
+  std::swap(_has_bits_[0], other->_has_bits_[0]);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
+}
+
+::google::protobuf::Metadata ContrastiveLossParameter::GetMetadata() const {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::Metadata metadata;
+  metadata.descriptor = ContrastiveLossParameter_descriptor_;
+  metadata.reflection = ContrastiveLossParameter_reflection_;
+  return metadata;
+}
+
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// ContrastiveLossParameter
+
+// optional float margin = 1 [default = 1];
+bool ContrastiveLossParameter::has_margin() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+void ContrastiveLossParameter::set_has_margin() {
+  _has_bits_[0] |= 0x00000001u;
+}
+void ContrastiveLossParameter::clear_has_margin() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+void ContrastiveLossParameter::clear_margin() {
+  margin_ = 1;
+  clear_has_margin();
+}
+float ContrastiveLossParameter::margin() const {
+  // @@protoc_insertion_point(field_get:caffe.ContrastiveLossParameter.margin)
+  return margin_;
+}
+void ContrastiveLossParameter::set_margin(float value) {
+  set_has_margin();
+  margin_ = value;
+  // @@protoc_insertion_point(field_set:caffe.ContrastiveLossParameter.margin)
+}
+
+// optional bool legacy_version = 2 [default = false];
+bool ContrastiveLossParameter::has_legacy_version() const {
+  return (_has_bits_[0] & 0x00000002u) != 0;
+}
+void ContrastiveLossParameter::set_has_legacy_version() {
+  _has_bits_[0] |= 0x00000002u;
+}
+void ContrastiveLossParameter::clear_has_legacy_version() {
+  _has_bits_[0] &= ~0x00000002u;
+}
+void ContrastiveLossParameter::clear_legacy_version() {
+  legacy_version_ = false;
+  clear_has_legacy_version();
+}
+bool ContrastiveLossParameter::legacy_version() const {
+  // @@protoc_insertion_point(field_get:caffe.ContrastiveLossParameter.legacy_version)
+  return legacy_version_;
+}
+void ContrastiveLossParameter::set_legacy_version(bool value) {
+  set_has_legacy_version();
+  legacy_version_ = value;
+  // @@protoc_insertion_point(field_set:caffe.ContrastiveLossParameter.legacy_version)
+}
+
+inline const ContrastiveLossParameter* ContrastiveLossParameter::internal_default_instance() {
+  return &ContrastiveLossParameter_default_instance_.get();
+}
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
+
+// ===================================================================
+
+const ::google::protobuf::EnumDescriptor* ConvolutionParameter_Engine_descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return ConvolutionParameter_Engine_descriptor_;
+}
+bool ConvolutionParameter_Engine_IsValid(int value) {
+  switch (value) {
+    case 0:
+    case 1:
+    case 2:
+      return true;
+    default:
+      return false;
+  }
+}
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const ConvolutionParameter_Engine ConvolutionParameter::DEFAULT;
+const ConvolutionParameter_Engine ConvolutionParameter::CAFFE;
+const ConvolutionParameter_Engine ConvolutionParameter::CUDNN;
+const ConvolutionParameter_Engine ConvolutionParameter::Engine_MIN;
+const ConvolutionParameter_Engine ConvolutionParameter::Engine_MAX;
+const int ConvolutionParameter::Engine_ARRAYSIZE;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const int ConvolutionParameter::kNumOutputFieldNumber;
+const int ConvolutionParameter::kBiasTermFieldNumber;
+const int ConvolutionParameter::kPadFieldNumber;
+const int ConvolutionParameter::kPadHFieldNumber;
+const int ConvolutionParameter::kPadWFieldNumber;
+const int ConvolutionParameter::kKernelSizeFieldNumber;
+const int ConvolutionParameter::kKernelHFieldNumber;
+const int ConvolutionParameter::kKernelWFieldNumber;
+const int ConvolutionParameter::kGroupFieldNumber;
+const int ConvolutionParameter::kStrideFieldNumber;
+const int ConvolutionParameter::kStrideHFieldNumber;
+const int ConvolutionParameter::kStrideWFieldNumber;
+const int ConvolutionParameter::kWeightFillerFieldNumber;
+const int ConvolutionParameter::kBiasFillerFieldNumber;
+const int ConvolutionParameter::kEngineFieldNumber;
+const int ConvolutionParameter::kDilationHFieldNumber;
+const int ConvolutionParameter::kDilationWFieldNumber;
+const int ConvolutionParameter::kDilationFieldNumber;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+
+ConvolutionParameter::ConvolutionParameter()
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+  if (this != internal_default_instance()) protobuf_InitDefaults_caffe_2eproto();
+  SharedCtor();
+  // @@protoc_insertion_point(constructor:caffe.ConvolutionParameter)
+}
+
+void ConvolutionParameter::InitAsDefaultInstance() {
+  weight_filler_ = const_cast< ::caffe::FillerParameter*>(
+      ::caffe::FillerParameter::internal_default_instance());
+  bias_filler_ = const_cast< ::caffe::FillerParameter*>(
+      ::caffe::FillerParameter::internal_default_instance());
+}
+
+ConvolutionParameter::ConvolutionParameter(const ConvolutionParameter& from)
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
+  SharedCtor();
+  UnsafeMergeFrom(from);
+  // @@protoc_insertion_point(copy_constructor:caffe.ConvolutionParameter)
+}
+
+void ConvolutionParameter::SharedCtor() {
+  _cached_size_ = 0;
+  weight_filler_ = NULL;
+  bias_filler_ = NULL;
+  ::memset(&num_output_, 0, reinterpret_cast<char*>(&dilation_) -
+    reinterpret_cast<char*>(&num_output_) + sizeof(dilation_));
+  stride_ = 1u;
+  bias_term_ = true;
+  group_ = 1u;
+}
+
+ConvolutionParameter::~ConvolutionParameter() {
+  // @@protoc_insertion_point(destructor:caffe.ConvolutionParameter)
+  SharedDtor();
+}
+
+void ConvolutionParameter::SharedDtor() {
+  if (this != &ConvolutionParameter_default_instance_.get()) {
+    delete weight_filler_;
+    delete bias_filler_;
+  }
+}
+
+void ConvolutionParameter::SetCachedSize(int size) const {
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* ConvolutionParameter::descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return ConvolutionParameter_descriptor_;
+}
+
+const ConvolutionParameter& ConvolutionParameter::default_instance() {
+  protobuf_InitDefaults_caffe_2eproto();
+  return *internal_default_instance();
+}
+
+::google::protobuf::internal::ExplicitlyConstructed<ConvolutionParameter> ConvolutionParameter_default_instance_;
+
+ConvolutionParameter* ConvolutionParameter::New(::google::protobuf::Arena* arena) const {
+  ConvolutionParameter* n = new ConvolutionParameter;
+  if (arena != NULL) {
+    arena->Own(n);
+  }
+  return n;
+}
+
+void ConvolutionParameter::Clear() {
+// @@protoc_insertion_point(message_clear_start:caffe.ConvolutionParameter)
+#if defined(__clang__)
+#define ZR_HELPER_(f) \
+  _Pragma("clang diagnostic push") \
+  _Pragma("clang diagnostic ignored \"-Winvalid-offsetof\"") \
+  __builtin_offsetof(ConvolutionParameter, f) \
+  _Pragma("clang diagnostic pop")
+#else
+#define ZR_HELPER_(f) reinterpret_cast<char*>(\
+  &reinterpret_cast<ConvolutionParameter*>(16)->f)
+#endif
+
+#define ZR_(first, last) do {\
+  ::memset(&(first), 0,\
+           ZR_HELPER_(last) - ZR_HELPER_(first) + sizeof(last));\
+} while (0)
+
+  if (_has_bits_[0 / 32] & 255u) {
+    ZR_(num_output_, kernel_w_);
+    bias_term_ = true;
+  }
+  if (_has_bits_[8 / 32] & 65280u) {
+    ZR_(stride_h_, dilation_h_);
+    group_ = 1u;
+    stride_ = 1u;
+    if (has_weight_filler()) {
+      if (weight_filler_ != NULL) weight_filler_->::caffe::FillerParameter::Clear();
+    }
+    if (has_bias_filler()) {
+      if (bias_filler_ != NULL) bias_filler_->::caffe::FillerParameter::Clear();
+    }
+  }
+  ZR_(dilation_w_, dilation_);
+
+#undef ZR_HELPER_
+#undef ZR_
+
+  _has_bits_.Clear();
+  if (_internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->Clear();
+  }
+}
+
+bool ConvolutionParameter::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
+  ::google::protobuf::uint32 tag;
+  // @@protoc_insertion_point(parse_start:caffe.ConvolutionParameter)
+  for (;;) {
+    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(16383);
+    tag = p.first;
+    if (!p.second) goto handle_unusual;
+    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+      // optional uint32 num_output = 1;
+      case 1: {
+        if (tag == 8) {
+          set_has_num_output();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>(
+                 input, &num_output_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(16)) goto parse_bias_term;
+        break;
+      }
+
+      // optional bool bias_term = 2 [default = true];
+      case 2: {
+        if (tag == 16) {
+         parse_bias_term:
+          set_has_bias_term();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>(
+                 input, &bias_term_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(24)) goto parse_pad;
+        break;
+      }
+
+      // optional uint32 pad = 3 [default = 0];
+      case 3: {
+        if (tag == 24) {
+         parse_pad:
+          set_has_pad();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>(
+                 input, &pad_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(32)) goto parse_kernel_size;
+        break;
+      }
+
+      // optional uint32 kernel_size = 4;
+      case 4: {
+        if (tag == 32) {
+         parse_kernel_size:
+          set_has_kernel_size();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>(
+                 input, &kernel_size_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(40)) goto parse_group;
+        break;
+      }
+
+      // optional uint32 group = 5 [default = 1];
+      case 5: {
+        if (tag == 40) {
+         parse_group:
+          set_has_group();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>(
+                 input, &group_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(48)) goto parse_stride;
+        break;
+      }
+
+      // optional uint32 stride = 6 [default = 1];
+      case 6: {
+        if (tag == 48) {
+         parse_stride:
+          set_has_stride();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>(
+                 input, &stride_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(58)) goto parse_weight_filler;
+        break;
+      }
+
+      // optional .caffe.FillerParameter weight_filler = 7;
+      case 7: {
+        if (tag == 58) {
+         parse_weight_filler:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+               input, mutable_weight_filler()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(66)) goto parse_bias_filler;
+        break;
+      }
+
+      // optional .caffe.FillerParameter bias_filler = 8;
+      case 8: {
+        if (tag == 66) {
+         parse_bias_filler:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+               input, mutable_bias_filler()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(72)) goto parse_pad_h;
+        break;
+      }
+
+      // optional uint32 pad_h = 9 [default = 0];
+      case 9: {
+        if (tag == 72) {
+         parse_pad_h:
+          set_has_pad_h();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>(
+                 input, &pad_h_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(80)) goto parse_pad_w;
+        break;
+      }
+
+      // optional uint32 pad_w = 10 [default = 0];
+      case 10: {
+        if (tag == 80) {
+         parse_pad_w:
+          set_has_pad_w();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>(
+                 input, &pad_w_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(88)) goto parse_kernel_h;
+        break;
+      }
+
+      // optional uint32 kernel_h = 11;
+      case 11: {
+        if (tag == 88) {
+         parse_kernel_h:
+          set_has_kernel_h();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>(
+                 input, &kernel_h_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(96)) goto parse_kernel_w;
+        break;
+      }
+
+      // optional uint32 kernel_w = 12;
+      case 12: {
+        if (tag == 96) {
+         parse_kernel_w:
+          set_has_kernel_w();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>(
+                 input, &kernel_w_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(104)) goto parse_stride_h;
+        break;
+      }
+
+      // optional uint32 stride_h = 13;
+      case 13: {
+        if (tag == 104) {
+         parse_stride_h:
+          set_has_stride_h();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>(
+                 input, &stride_h_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(112)) goto parse_stride_w;
+        break;
+      }
+
+      // optional uint32 stride_w = 14;
+      case 14: {
+        if (tag == 112) {
+         parse_stride_w:
+          set_has_stride_w();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>(
+                 input, &stride_w_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(120)) goto parse_engine;
+        break;
+      }
+
+      // optional .caffe.ConvolutionParameter.Engine engine = 15 [default = DEFAULT];
+      case 15: {
+        if (tag == 120) {
+         parse_engine:
+          int value;
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>(
+                 input, &value)));
+          if (::caffe::ConvolutionParameter_Engine_IsValid(value)) {
+            set_engine(static_cast< ::caffe::ConvolutionParameter_Engine >(value));
+          } else {
+            mutable_unknown_fields()->AddVarint(15, value);
+          }
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(144)) goto parse_dilation_h;
+        break;
+      }
+
+      // optional uint32 dilation_h = 18;
+      case 18: {
+        if (tag == 144) {
+         parse_dilation_h:
+          set_has_dilation_h();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>(
+                 input, &dilation_h_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(152)) goto parse_dilation_w;
+        break;
+      }
+
+      // optional uint32 dilation_w = 19;
+      case 19: {
+        if (tag == 152) {
+         parse_dilation_w:
+          set_has_dilation_w();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>(
+                 input, &dilation_w_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(160)) goto parse_dilation;
+        break;
+      }
+
+      // optional uint32 dilation = 20;
+      case 20: {
+        if (tag == 160) {
+         parse_dilation:
+          set_has_dilation();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>(
+                 input, &dilation_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectAtEnd()) goto success;
+        break;
+      }
+
+      default: {
+      handle_unusual:
+        if (tag == 0 ||
+            ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+          goto success;
+        }
+        DO_(::google::protobuf::internal::WireFormat::SkipField(
+              input, tag, mutable_unknown_fields()));
+        break;
+      }
+    }
+  }
+success:
+  // @@protoc_insertion_point(parse_success:caffe.ConvolutionParameter)
+  return true;
+failure:
+  // @@protoc_insertion_point(parse_failure:caffe.ConvolutionParameter)
+  return false;
+#undef DO_
+}
+
+void ConvolutionParameter::SerializeWithCachedSizes(
+    ::google::protobuf::io::CodedOutputStream* output) const {
+  // @@protoc_insertion_point(serialize_start:caffe.ConvolutionParameter)
+  // optional uint32 num_output = 1;
+  if (has_num_output()) {
+    ::google::protobuf::internal::WireFormatLite::WriteUInt32(1, this->num_output(), output);
+  }
+
+  // optional bool bias_term = 2 [default = true];
+  if (has_bias_term()) {
+    ::google::protobuf::internal::WireFormatLite::WriteBool(2, this->bias_term(), output);
+  }
+
+  // optional uint32 pad = 3 [default = 0];
+  if (has_pad()) {
+    ::google::protobuf::internal::WireFormatLite::WriteUInt32(3, this->pad(), output);
+  }
+
+  // optional uint32 kernel_size = 4;
+  if (has_kernel_size()) {
+    ::google::protobuf::internal::WireFormatLite::WriteUInt32(4, this->kernel_size(), output);
+  }
+
+  // optional uint32 group = 5 [default = 1];
+  if (has_group()) {
+    ::google::protobuf::internal::WireFormatLite::WriteUInt32(5, this->group(), output);
+  }
+
+  // optional uint32 stride = 6 [default = 1];
+  if (has_stride()) {
+    ::google::protobuf::internal::WireFormatLite::WriteUInt32(6, this->stride(), output);
+  }
+
+  // optional .caffe.FillerParameter weight_filler = 7;
+  if (has_weight_filler()) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      7, *this->weight_filler_, output);
+  }
+
+  // optional .caffe.FillerParameter bias_filler = 8;
+  if (has_bias_filler()) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      8, *this->bias_filler_, output);
+  }
+
+  // optional uint32 pad_h = 9 [default = 0];
+  if (has_pad_h()) {
+    ::google::protobuf::internal::WireFormatLite::WriteUInt32(9, this->pad_h(), output);
+  }
+
+  // optional uint32 pad_w = 10 [default = 0];
+  if (has_pad_w()) {
+    ::google::protobuf::internal::WireFormatLite::WriteUInt32(10, this->pad_w(), output);
+  }
+
+  // optional uint32 kernel_h = 11;
+  if (has_kernel_h()) {
+    ::google::protobuf::internal::WireFormatLite::WriteUInt32(11, this->kernel_h(), output);
+  }
+
+  // optional uint32 kernel_w = 12;
+  if (has_kernel_w()) {
+    ::google::protobuf::internal::WireFormatLite::WriteUInt32(12, this->kernel_w(), output);
+  }
+
+  // optional uint32 stride_h = 13;
+  if (has_stride_h()) {
+    ::google::protobuf::internal::WireFormatLite::WriteUInt32(13, this->stride_h(), output);
+  }
+
+  // optional uint32 stride_w = 14;
+  if (has_stride_w()) {
+    ::google::protobuf::internal::WireFormatLite::WriteUInt32(14, this->stride_w(), output);
+  }
+
+  // optional .caffe.ConvolutionParameter.Engine engine = 15 [default = DEFAULT];
+  if (has_engine()) {
+    ::google::protobuf::internal::WireFormatLite::WriteEnum(
+      15, this->engine(), output);
+  }
+
+  // optional uint32 dilation_h = 18;
+  if (has_dilation_h()) {
+    ::google::protobuf::internal::WireFormatLite::WriteUInt32(18, this->dilation_h(), output);
+  }
+
+  // optional uint32 dilation_w = 19;
+  if (has_dilation_w()) {
+    ::google::protobuf::internal::WireFormatLite::WriteUInt32(19, this->dilation_w(), output);
+  }
+
+  // optional uint32 dilation = 20;
+  if (has_dilation()) {
+    ::google::protobuf::internal::WireFormatLite::WriteUInt32(20, this->dilation(), output);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
+        unknown_fields(), output);
+  }
+  // @@protoc_insertion_point(serialize_end:caffe.ConvolutionParameter)
+}
+
+::google::protobuf::uint8* ConvolutionParameter::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
+  (void)deterministic; // Unused
+  // @@protoc_insertion_point(serialize_to_array_start:caffe.ConvolutionParameter)
+  // optional uint32 num_output = 1;
+  if (has_num_output()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteUInt32ToArray(1, this->num_output(), target);
+  }
+
+  // optional bool bias_term = 2 [default = true];
+  if (has_bias_term()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(2, this->bias_term(), target);
+  }
+
+  // optional uint32 pad = 3 [default = 0];
+  if (has_pad()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteUInt32ToArray(3, this->pad(), target);
+  }
+
+  // optional uint32 kernel_size = 4;
+  if (has_kernel_size()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteUInt32ToArray(4, this->kernel_size(), target);
+  }
+
+  // optional uint32 group = 5 [default = 1];
+  if (has_group()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteUInt32ToArray(5, this->group(), target);
+  }
+
+  // optional uint32 stride = 6 [default = 1];
+  if (has_stride()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteUInt32ToArray(6, this->stride(), target);
+  }
+
+  // optional .caffe.FillerParameter weight_filler = 7;
+  if (has_weight_filler()) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        7, *this->weight_filler_, false, target);
+  }
+
+  // optional .caffe.FillerParameter bias_filler = 8;
+  if (has_bias_filler()) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        8, *this->bias_filler_, false, target);
+  }
+
+  // optional uint32 pad_h = 9 [default = 0];
+  if (has_pad_h()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteUInt32ToArray(9, this->pad_h(), target);
+  }
+
+  // optional uint32 pad_w = 10 [default = 0];
+  if (has_pad_w()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteUInt32ToArray(10, this->pad_w(), target);
+  }
+
+  // optional uint32 kernel_h = 11;
+  if (has_kernel_h()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteUInt32ToArray(11, this->kernel_h(), target);
+  }
+
+  // optional uint32 kernel_w = 12;
+  if (has_kernel_w()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteUInt32ToArray(12, this->kernel_w(), target);
+  }
+
+  // optional uint32 stride_h = 13;
+  if (has_stride_h()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteUInt32ToArray(13, this->stride_h(), target);
+  }
+
+  // optional uint32 stride_w = 14;
+  if (has_stride_w()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteUInt32ToArray(14, this->stride_w(), target);
+  }
+
+  // optional .caffe.ConvolutionParameter.Engine engine = 15 [default = DEFAULT];
+  if (has_engine()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteEnumToArray(
+      15, this->engine(), target);
+  }
+
+  // optional uint32 dilation_h = 18;
+  if (has_dilation_h()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteUInt32ToArray(18, this->dilation_h(), target);
+  }
+
+  // optional uint32 dilation_w = 19;
+  if (has_dilation_w()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteUInt32ToArray(19, this->dilation_w(), target);
+  }
+
+  // optional uint32 dilation = 20;
+  if (has_dilation()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteUInt32ToArray(20, this->dilation(), target);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
+        unknown_fields(), target);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:caffe.ConvolutionParameter)
+  return target;
+}
+
+size_t ConvolutionParameter::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:caffe.ConvolutionParameter)
+  size_t total_size = 0;
+
+  if (_has_bits_[0 / 32] & 255u) {
+    // optional uint32 num_output = 1;
+    if (has_num_output()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::UInt32Size(
+          this->num_output());
+    }
+
+    // optional bool bias_term = 2 [default = true];
+    if (has_bias_term()) {
+      total_size += 1 + 1;
+    }
+
+    // optional uint32 pad = 3 [default = 0];
+    if (has_pad()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::UInt32Size(
+          this->pad());
+    }
+
+    // optional uint32 pad_h = 9 [default = 0];
+    if (has_pad_h()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::UInt32Size(
+          this->pad_h());
+    }
+
+    // optional uint32 pad_w = 10 [default = 0];
+    if (has_pad_w()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::UInt32Size(
+          this->pad_w());
+    }
+
+    // optional uint32 kernel_size = 4;
+    if (has_kernel_size()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::UInt32Size(
+          this->kernel_size());
+    }
+
+    // optional uint32 kernel_h = 11;
+    if (has_kernel_h()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::UInt32Size(
+          this->kernel_h());
+    }
+
+    // optional uint32 kernel_w = 12;
+    if (has_kernel_w()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::UInt32Size(
+          this->kernel_w());
+    }
+
+  }
+  if (_has_bits_[8 / 32] & 65280u) {
+    // optional uint32 group = 5 [default = 1];
+    if (has_group()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::UInt32Size(
+          this->group());
+    }
+
+    // optional uint32 stride = 6 [default = 1];
+    if (has_stride()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::UInt32Size(
+          this->stride());
+    }
+
+    // optional uint32 stride_h = 13;
+    if (has_stride_h()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::UInt32Size(
+          this->stride_h());
+    }
+
+    // optional uint32 stride_w = 14;
+    if (has_stride_w()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::UInt32Size(
+          this->stride_w());
+    }
+
+    // optional .caffe.FillerParameter weight_filler = 7;
+    if (has_weight_filler()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          *this->weight_filler_);
+    }
+
+    // optional .caffe.FillerParameter bias_filler = 8;
+    if (has_bias_filler()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          *this->bias_filler_);
+    }
+
+    // optional .caffe.ConvolutionParameter.Engine engine = 15 [default = DEFAULT];
+    if (has_engine()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::EnumSize(this->engine());
+    }
+
+    // optional uint32 dilation_h = 18;
+    if (has_dilation_h()) {
+      total_size += 2 +
+        ::google::protobuf::internal::WireFormatLite::UInt32Size(
+          this->dilation_h());
+    }
+
+  }
+  if (_has_bits_[16 / 32] & 196608u) {
+    // optional uint32 dilation_w = 19;
+    if (has_dilation_w()) {
+      total_size += 2 +
+        ::google::protobuf::internal::WireFormatLite::UInt32Size(
+          this->dilation_w());
+    }
+
+    // optional uint32 dilation = 20;
+    if (has_dilation()) {
+      total_size += 2 +
+        ::google::protobuf::internal::WireFormatLite::UInt32Size(
+          this->dilation());
+    }
+
+  }
+  if (_internal_metadata_.have_unknown_fields()) {
+    total_size +=
+      ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
+        unknown_fields());
+  }
+  int cached_size = ::google::protobuf::internal::ToCachedSize(total_size);
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = cached_size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+  return total_size;
+}
+
+void ConvolutionParameter::MergeFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_merge_from_start:caffe.ConvolutionParameter)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const ConvolutionParameter* source =
+      ::google::protobuf::internal::DynamicCastToGenerated<const ConvolutionParameter>(
+          &from);
+  if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:caffe.ConvolutionParameter)
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:caffe.ConvolutionParameter)
+    UnsafeMergeFrom(*source);
+  }
+}
+
+void ConvolutionParameter::MergeFrom(const ConvolutionParameter& from) {
+// @@protoc_insertion_point(class_specific_merge_from_start:caffe.ConvolutionParameter)
+  if (GOOGLE_PREDICT_TRUE(&from != this)) {
+    UnsafeMergeFrom(from);
+  } else {
+    MergeFromFail(__LINE__);
+  }
+}
+
+void ConvolutionParameter::UnsafeMergeFrom(const ConvolutionParameter& from) {
+  GOOGLE_DCHECK(&from != this);
+  if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+    if (from.has_num_output()) {
+      set_num_output(from.num_output());
+    }
+    if (from.has_bias_term()) {
+      set_bias_term(from.bias_term());
+    }
+    if (from.has_pad()) {
+      set_pad(from.pad());
+    }
+    if (from.has_pad_h()) {
+      set_pad_h(from.pad_h());
+    }
+    if (from.has_pad_w()) {
+      set_pad_w(from.pad_w());
+    }
+    if (from.has_kernel_size()) {
+      set_kernel_size(from.kernel_size());
+    }
+    if (from.has_kernel_h()) {
+      set_kernel_h(from.kernel_h());
+    }
+    if (from.has_kernel_w()) {
+      set_kernel_w(from.kernel_w());
+    }
+  }
+  if (from._has_bits_[8 / 32] & (0xffu << (8 % 32))) {
+    if (from.has_group()) {
+      set_group(from.group());
+    }
+    if (from.has_stride()) {
+      set_stride(from.stride());
+    }
+    if (from.has_stride_h()) {
+      set_stride_h(from.stride_h());
+    }
+    if (from.has_stride_w()) {
+      set_stride_w(from.stride_w());
+    }
+    if (from.has_weight_filler()) {
+      mutable_weight_filler()->::caffe::FillerParameter::MergeFrom(from.weight_filler());
+    }
+    if (from.has_bias_filler()) {
+      mutable_bias_filler()->::caffe::FillerParameter::MergeFrom(from.bias_filler());
+    }
+    if (from.has_engine()) {
+      set_engine(from.engine());
+    }
+    if (from.has_dilation_h()) {
+      set_dilation_h(from.dilation_h());
+    }
+  }
+  if (from._has_bits_[16 / 32] & (0xffu << (16 % 32))) {
+    if (from.has_dilation_w()) {
+      set_dilation_w(from.dilation_w());
+    }
+    if (from.has_dilation()) {
+      set_dilation(from.dilation());
+    }
+  }
+  if (from._internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::UnknownFieldSet::MergeToInternalMetdata(
+      from.unknown_fields(), &_internal_metadata_);
+  }
+}
+
+void ConvolutionParameter::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:caffe.ConvolutionParameter)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void ConvolutionParameter::CopyFrom(const ConvolutionParameter& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:caffe.ConvolutionParameter)
+  if (&from == this) return;
+  Clear();
+  UnsafeMergeFrom(from);
+}
+
+bool ConvolutionParameter::IsInitialized() const {
+
+  return true;
+}
+
+void ConvolutionParameter::Swap(ConvolutionParameter* other) {
+  if (other == this) return;
+  InternalSwap(other);
+}
+void ConvolutionParameter::InternalSwap(ConvolutionParameter* other) {
+  std::swap(num_output_, other->num_output_);
+  std::swap(bias_term_, other->bias_term_);
+  std::swap(pad_, other->pad_);
+  std::swap(pad_h_, other->pad_h_);
+  std::swap(pad_w_, other->pad_w_);
+  std::swap(kernel_size_, other->kernel_size_);
+  std::swap(kernel_h_, other->kernel_h_);
+  std::swap(kernel_w_, other->kernel_w_);
+  std::swap(group_, other->group_);
+  std::swap(stride_, other->stride_);
+  std::swap(stride_h_, other->stride_h_);
+  std::swap(stride_w_, other->stride_w_);
+  std::swap(weight_filler_, other->weight_filler_);
+  std::swap(bias_filler_, other->bias_filler_);
+  std::swap(engine_, other->engine_);
+  std::swap(dilation_h_, other->dilation_h_);
+  std::swap(dilation_w_, other->dilation_w_);
+  std::swap(dilation_, other->dilation_);
+  std::swap(_has_bits_[0], other->_has_bits_[0]);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
+}
+
+::google::protobuf::Metadata ConvolutionParameter::GetMetadata() const {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::Metadata metadata;
+  metadata.descriptor = ConvolutionParameter_descriptor_;
+  metadata.reflection = ConvolutionParameter_reflection_;
+  return metadata;
+}
+
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// ConvolutionParameter
+
+// optional uint32 num_output = 1;
+bool ConvolutionParameter::has_num_output() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+void ConvolutionParameter::set_has_num_output() {
+  _has_bits_[0] |= 0x00000001u;
+}
+void ConvolutionParameter::clear_has_num_output() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+void ConvolutionParameter::clear_num_output() {
+  num_output_ = 0u;
+  clear_has_num_output();
+}
+::google::protobuf::uint32 ConvolutionParameter::num_output() const {
+  // @@protoc_insertion_point(field_get:caffe.ConvolutionParameter.num_output)
+  return num_output_;
+}
+void ConvolutionParameter::set_num_output(::google::protobuf::uint32 value) {
+  set_has_num_output();
+  num_output_ = value;
+  // @@protoc_insertion_point(field_set:caffe.ConvolutionParameter.num_output)
+}
+
+// optional bool bias_term = 2 [default = true];
+bool ConvolutionParameter::has_bias_term() const {
+  return (_has_bits_[0] & 0x00000002u) != 0;
+}
+void ConvolutionParameter::set_has_bias_term() {
+  _has_bits_[0] |= 0x00000002u;
+}
+void ConvolutionParameter::clear_has_bias_term() {
+  _has_bits_[0] &= ~0x00000002u;
+}
+void ConvolutionParameter::clear_bias_term() {
+  bias_term_ = true;
+  clear_has_bias_term();
+}
+bool ConvolutionParameter::bias_term() const {
+  // @@protoc_insertion_point(field_get:caffe.ConvolutionParameter.bias_term)
+  return bias_term_;
+}
+void ConvolutionParameter::set_bias_term(bool value) {
+  set_has_bias_term();
+  bias_term_ = value;
+  // @@protoc_insertion_point(field_set:caffe.ConvolutionParameter.bias_term)
+}
+
+// optional uint32 pad = 3 [default = 0];
+bool ConvolutionParameter::has_pad() const {
+  return (_has_bits_[0] & 0x00000004u) != 0;
+}
+void ConvolutionParameter::set_has_pad() {
+  _has_bits_[0] |= 0x00000004u;
+}
+void ConvolutionParameter::clear_has_pad() {
+  _has_bits_[0] &= ~0x00000004u;
+}
+void ConvolutionParameter::clear_pad() {
+  pad_ = 0u;
+  clear_has_pad();
+}
+::google::protobuf::uint32 ConvolutionParameter::pad() const {
+  // @@protoc_insertion_point(field_get:caffe.ConvolutionParameter.pad)
+  return pad_;
+}
+void ConvolutionParameter::set_pad(::google::protobuf::uint32 value) {
+  set_has_pad();
+  pad_ = value;
+  // @@protoc_insertion_point(field_set:caffe.ConvolutionParameter.pad)
+}
+
+// optional uint32 pad_h = 9 [default = 0];
+bool ConvolutionParameter::has_pad_h() const {
+  return (_has_bits_[0] & 0x00000008u) != 0;
+}
+void ConvolutionParameter::set_has_pad_h() {
+  _has_bits_[0] |= 0x00000008u;
+}
+void ConvolutionParameter::clear_has_pad_h() {
+  _has_bits_[0] &= ~0x00000008u;
+}
+void ConvolutionParameter::clear_pad_h() {
+  pad_h_ = 0u;
+  clear_has_pad_h();
+}
+::google::protobuf::uint32 ConvolutionParameter::pad_h() const {
+  // @@protoc_insertion_point(field_get:caffe.ConvolutionParameter.pad_h)
+  return pad_h_;
+}
+void ConvolutionParameter::set_pad_h(::google::protobuf::uint32 value) {
+  set_has_pad_h();
+  pad_h_ = value;
+  // @@protoc_insertion_point(field_set:caffe.ConvolutionParameter.pad_h)
+}
+
+// optional uint32 pad_w = 10 [default = 0];
+bool ConvolutionParameter::has_pad_w() const {
+  return (_has_bits_[0] & 0x00000010u) != 0;
+}
+void ConvolutionParameter::set_has_pad_w() {
+  _has_bits_[0] |= 0x00000010u;
+}
+void ConvolutionParameter::clear_has_pad_w() {
+  _has_bits_[0] &= ~0x00000010u;
+}
+void ConvolutionParameter::clear_pad_w() {
+  pad_w_ = 0u;
+  clear_has_pad_w();
+}
+::google::protobuf::uint32 ConvolutionParameter::pad_w() const {
+  // @@protoc_insertion_point(field_get:caffe.ConvolutionParameter.pad_w)
+  return pad_w_;
+}
+void ConvolutionParameter::set_pad_w(::google::protobuf::uint32 value) {
+  set_has_pad_w();
+  pad_w_ = value;
+  // @@protoc_insertion_point(field_set:caffe.ConvolutionParameter.pad_w)
+}
+
+// optional uint32 kernel_size = 4;
+bool ConvolutionParameter::has_kernel_size() const {
+  return (_has_bits_[0] & 0x00000020u) != 0;
+}
+void ConvolutionParameter::set_has_kernel_size() {
+  _has_bits_[0] |= 0x00000020u;
+}
+void ConvolutionParameter::clear_has_kernel_size() {
+  _has_bits_[0] &= ~0x00000020u;
+}
+void ConvolutionParameter::clear_kernel_size() {
+  kernel_size_ = 0u;
+  clear_has_kernel_size();
+}
+::google::protobuf::uint32 ConvolutionParameter::kernel_size() const {
+  // @@protoc_insertion_point(field_get:caffe.ConvolutionParameter.kernel_size)
+  return kernel_size_;
+}
+void ConvolutionParameter::set_kernel_size(::google::protobuf::uint32 value) {
+  set_has_kernel_size();
+  kernel_size_ = value;
+  // @@protoc_insertion_point(field_set:caffe.ConvolutionParameter.kernel_size)
+}
+
+// optional uint32 kernel_h = 11;
+bool ConvolutionParameter::has_kernel_h() const {
+  return (_has_bits_[0] & 0x00000040u) != 0;
+}
+void ConvolutionParameter::set_has_kernel_h() {
+  _has_bits_[0] |= 0x00000040u;
+}
+void ConvolutionParameter::clear_has_kernel_h() {
+  _has_bits_[0] &= ~0x00000040u;
+}
+void ConvolutionParameter::clear_kernel_h() {
+  kernel_h_ = 0u;
+  clear_has_kernel_h();
+}
+::google::protobuf::uint32 ConvolutionParameter::kernel_h() const {
+  // @@protoc_insertion_point(field_get:caffe.ConvolutionParameter.kernel_h)
+  return kernel_h_;
+}
+void ConvolutionParameter::set_kernel_h(::google::protobuf::uint32 value) {
+  set_has_kernel_h();
+  kernel_h_ = value;
+  // @@protoc_insertion_point(field_set:caffe.ConvolutionParameter.kernel_h)
+}
+
+// optional uint32 kernel_w = 12;
+bool ConvolutionParameter::has_kernel_w() const {
+  return (_has_bits_[0] & 0x00000080u) != 0;
+}
+void ConvolutionParameter::set_has_kernel_w() {
+  _has_bits_[0] |= 0x00000080u;
+}
+void ConvolutionParameter::clear_has_kernel_w() {
+  _has_bits_[0] &= ~0x00000080u;
+}
+void ConvolutionParameter::clear_kernel_w() {
+  kernel_w_ = 0u;
+  clear_has_kernel_w();
+}
+::google::protobuf::uint32 ConvolutionParameter::kernel_w() const {
+  // @@protoc_insertion_point(field_get:caffe.ConvolutionParameter.kernel_w)
+  return kernel_w_;
+}
+void ConvolutionParameter::set_kernel_w(::google::protobuf::uint32 value) {
+  set_has_kernel_w();
+  kernel_w_ = value;
+  // @@protoc_insertion_point(field_set:caffe.ConvolutionParameter.kernel_w)
+}
+
+// optional uint32 group = 5 [default = 1];
+bool ConvolutionParameter::has_group() const {
+  return (_has_bits_[0] & 0x00000100u) != 0;
+}
+void ConvolutionParameter::set_has_group() {
+  _has_bits_[0] |= 0x00000100u;
+}
+void ConvolutionParameter::clear_has_group() {
+  _has_bits_[0] &= ~0x00000100u;
+}
+void ConvolutionParameter::clear_group() {
+  group_ = 1u;
+  clear_has_group();
+}
+::google::protobuf::uint32 ConvolutionParameter::group() const {
+  // @@protoc_insertion_point(field_get:caffe.ConvolutionParameter.group)
+  return group_;
+}
+void ConvolutionParameter::set_group(::google::protobuf::uint32 value) {
+  set_has_group();
+  group_ = value;
+  // @@protoc_insertion_point(field_set:caffe.ConvolutionParameter.group)
+}
+
+// optional uint32 stride = 6 [default = 1];
+bool ConvolutionParameter::has_stride() const {
+  return (_has_bits_[0] & 0x00000200u) != 0;
+}
+void ConvolutionParameter::set_has_stride() {
+  _has_bits_[0] |= 0x00000200u;
+}
+void ConvolutionParameter::clear_has_stride() {
+  _has_bits_[0] &= ~0x00000200u;
+}
+void ConvolutionParameter::clear_stride() {
+  stride_ = 1u;
+  clear_has_stride();
+}
+::google::protobuf::uint32 ConvolutionParameter::stride() const {
+  // @@protoc_insertion_point(field_get:caffe.ConvolutionParameter.stride)
+  return stride_;
+}
+void ConvolutionParameter::set_stride(::google::protobuf::uint32 value) {
+  set_has_stride();
+  stride_ = value;
+  // @@protoc_insertion_point(field_set:caffe.ConvolutionParameter.stride)
+}
+
+// optional uint32 stride_h = 13;
+bool ConvolutionParameter::has_stride_h() const {
+  return (_has_bits_[0] & 0x00000400u) != 0;
+}
+void ConvolutionParameter::set_has_stride_h() {
+  _has_bits_[0] |= 0x00000400u;
+}
+void ConvolutionParameter::clear_has_stride_h() {
+  _has_bits_[0] &= ~0x00000400u;
+}
+void ConvolutionParameter::clear_stride_h() {
+  stride_h_ = 0u;
+  clear_has_stride_h();
+}
+::google::protobuf::uint32 ConvolutionParameter::stride_h() const {
+  // @@protoc_insertion_point(field_get:caffe.ConvolutionParameter.stride_h)
+  return stride_h_;
+}
+void ConvolutionParameter::set_stride_h(::google::protobuf::uint32 value) {
+  set_has_stride_h();
+  stride_h_ = value;
+  // @@protoc_insertion_point(field_set:caffe.ConvolutionParameter.stride_h)
+}
+
+// optional uint32 stride_w = 14;
+bool ConvolutionParameter::has_stride_w() const {
+  return (_has_bits_[0] & 0x00000800u) != 0;
+}
+void ConvolutionParameter::set_has_stride_w() {
+  _has_bits_[0] |= 0x00000800u;
+}
+void ConvolutionParameter::clear_has_stride_w() {
+  _has_bits_[0] &= ~0x00000800u;
+}
+void ConvolutionParameter::clear_stride_w() {
+  stride_w_ = 0u;
+  clear_has_stride_w();
+}
+::google::protobuf::uint32 ConvolutionParameter::stride_w() const {
+  // @@protoc_insertion_point(field_get:caffe.ConvolutionParameter.stride_w)
+  return stride_w_;
+}
+void ConvolutionParameter::set_stride_w(::google::protobuf::uint32 value) {
+  set_has_stride_w();
+  stride_w_ = value;
+  // @@protoc_insertion_point(field_set:caffe.ConvolutionParameter.stride_w)
+}
+
+// optional .caffe.FillerParameter weight_filler = 7;
+bool ConvolutionParameter::has_weight_filler() const {
+  return (_has_bits_[0] & 0x00001000u) != 0;
+}
+void ConvolutionParameter::set_has_weight_filler() {
+  _has_bits_[0] |= 0x00001000u;
+}
+void ConvolutionParameter::clear_has_weight_filler() {
+  _has_bits_[0] &= ~0x00001000u;
+}
+void ConvolutionParameter::clear_weight_filler() {
+  if (weight_filler_ != NULL) weight_filler_->::caffe::FillerParameter::Clear();
+  clear_has_weight_filler();
+}
+const ::caffe::FillerParameter& ConvolutionParameter::weight_filler() const {
+  // @@protoc_insertion_point(field_get:caffe.ConvolutionParameter.weight_filler)
+  return weight_filler_ != NULL ? *weight_filler_
+                         : *::caffe::FillerParameter::internal_default_instance();
+}
+::caffe::FillerParameter* ConvolutionParameter::mutable_weight_filler() {
+  set_has_weight_filler();
+  if (weight_filler_ == NULL) {
+    weight_filler_ = new ::caffe::FillerParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.ConvolutionParameter.weight_filler)
+  return weight_filler_;
+}
+::caffe::FillerParameter* ConvolutionParameter::release_weight_filler() {
+  // @@protoc_insertion_point(field_release:caffe.ConvolutionParameter.weight_filler)
+  clear_has_weight_filler();
+  ::caffe::FillerParameter* temp = weight_filler_;
+  weight_filler_ = NULL;
+  return temp;
+}
+void ConvolutionParameter::set_allocated_weight_filler(::caffe::FillerParameter* weight_filler) {
+  delete weight_filler_;
+  weight_filler_ = weight_filler;
+  if (weight_filler) {
+    set_has_weight_filler();
+  } else {
+    clear_has_weight_filler();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.ConvolutionParameter.weight_filler)
+}
+
+// optional .caffe.FillerParameter bias_filler = 8;
+bool ConvolutionParameter::has_bias_filler() const {
+  return (_has_bits_[0] & 0x00002000u) != 0;
+}
+void ConvolutionParameter::set_has_bias_filler() {
+  _has_bits_[0] |= 0x00002000u;
+}
+void ConvolutionParameter::clear_has_bias_filler() {
+  _has_bits_[0] &= ~0x00002000u;
+}
+void ConvolutionParameter::clear_bias_filler() {
+  if (bias_filler_ != NULL) bias_filler_->::caffe::FillerParameter::Clear();
+  clear_has_bias_filler();
+}
+const ::caffe::FillerParameter& ConvolutionParameter::bias_filler() const {
+  // @@protoc_insertion_point(field_get:caffe.ConvolutionParameter.bias_filler)
+  return bias_filler_ != NULL ? *bias_filler_
+                         : *::caffe::FillerParameter::internal_default_instance();
+}
+::caffe::FillerParameter* ConvolutionParameter::mutable_bias_filler() {
+  set_has_bias_filler();
+  if (bias_filler_ == NULL) {
+    bias_filler_ = new ::caffe::FillerParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.ConvolutionParameter.bias_filler)
+  return bias_filler_;
+}
+::caffe::FillerParameter* ConvolutionParameter::release_bias_filler() {
+  // @@protoc_insertion_point(field_release:caffe.ConvolutionParameter.bias_filler)
+  clear_has_bias_filler();
+  ::caffe::FillerParameter* temp = bias_filler_;
+  bias_filler_ = NULL;
+  return temp;
+}
+void ConvolutionParameter::set_allocated_bias_filler(::caffe::FillerParameter* bias_filler) {
+  delete bias_filler_;
+  bias_filler_ = bias_filler;
+  if (bias_filler) {
+    set_has_bias_filler();
+  } else {
+    clear_has_bias_filler();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.ConvolutionParameter.bias_filler)
+}
+
+// optional .caffe.ConvolutionParameter.Engine engine = 15 [default = DEFAULT];
+bool ConvolutionParameter::has_engine() const {
+  return (_has_bits_[0] & 0x00004000u) != 0;
+}
+void ConvolutionParameter::set_has_engine() {
+  _has_bits_[0] |= 0x00004000u;
+}
+void ConvolutionParameter::clear_has_engine() {
+  _has_bits_[0] &= ~0x00004000u;
+}
+void ConvolutionParameter::clear_engine() {
+  engine_ = 0;
+  clear_has_engine();
+}
+::caffe::ConvolutionParameter_Engine ConvolutionParameter::engine() const {
+  // @@protoc_insertion_point(field_get:caffe.ConvolutionParameter.engine)
+  return static_cast< ::caffe::ConvolutionParameter_Engine >(engine_);
+}
+void ConvolutionParameter::set_engine(::caffe::ConvolutionParameter_Engine value) {
+  assert(::caffe::ConvolutionParameter_Engine_IsValid(value));
+  set_has_engine();
+  engine_ = value;
+  // @@protoc_insertion_point(field_set:caffe.ConvolutionParameter.engine)
+}
+
+// optional uint32 dilation_h = 18;
+bool ConvolutionParameter::has_dilation_h() const {
+  return (_has_bits_[0] & 0x00008000u) != 0;
+}
+void ConvolutionParameter::set_has_dilation_h() {
+  _has_bits_[0] |= 0x00008000u;
+}
+void ConvolutionParameter::clear_has_dilation_h() {
+  _has_bits_[0] &= ~0x00008000u;
+}
+void ConvolutionParameter::clear_dilation_h() {
+  dilation_h_ = 0u;
+  clear_has_dilation_h();
+}
+::google::protobuf::uint32 ConvolutionParameter::dilation_h() const {
+  // @@protoc_insertion_point(field_get:caffe.ConvolutionParameter.dilation_h)
+  return dilation_h_;
+}
+void ConvolutionParameter::set_dilation_h(::google::protobuf::uint32 value) {
+  set_has_dilation_h();
+  dilation_h_ = value;
+  // @@protoc_insertion_point(field_set:caffe.ConvolutionParameter.dilation_h)
+}
+
+// optional uint32 dilation_w = 19;
+bool ConvolutionParameter::has_dilation_w() const {
+  return (_has_bits_[0] & 0x00010000u) != 0;
+}
+void ConvolutionParameter::set_has_dilation_w() {
+  _has_bits_[0] |= 0x00010000u;
+}
+void ConvolutionParameter::clear_has_dilation_w() {
+  _has_bits_[0] &= ~0x00010000u;
+}
+void ConvolutionParameter::clear_dilation_w() {
+  dilation_w_ = 0u;
+  clear_has_dilation_w();
+}
+::google::protobuf::uint32 ConvolutionParameter::dilation_w() const {
+  // @@protoc_insertion_point(field_get:caffe.ConvolutionParameter.dilation_w)
+  return dilation_w_;
+}
+void ConvolutionParameter::set_dilation_w(::google::protobuf::uint32 value) {
+  set_has_dilation_w();
+  dilation_w_ = value;
+  // @@protoc_insertion_point(field_set:caffe.ConvolutionParameter.dilation_w)
+}
+
+// optional uint32 dilation = 20;
+bool ConvolutionParameter::has_dilation() const {
+  return (_has_bits_[0] & 0x00020000u) != 0;
+}
+void ConvolutionParameter::set_has_dilation() {
+  _has_bits_[0] |= 0x00020000u;
+}
+void ConvolutionParameter::clear_has_dilation() {
+  _has_bits_[0] &= ~0x00020000u;
+}
+void ConvolutionParameter::clear_dilation() {
+  dilation_ = 0u;
+  clear_has_dilation();
+}
+::google::protobuf::uint32 ConvolutionParameter::dilation() const {
+  // @@protoc_insertion_point(field_get:caffe.ConvolutionParameter.dilation)
+  return dilation_;
+}
+void ConvolutionParameter::set_dilation(::google::protobuf::uint32 value) {
+  set_has_dilation();
+  dilation_ = value;
+  // @@protoc_insertion_point(field_set:caffe.ConvolutionParameter.dilation)
+}
+
+inline const ConvolutionParameter* ConvolutionParameter::internal_default_instance() {
+  return &ConvolutionParameter_default_instance_.get();
+}
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
+
+// ===================================================================
+
+const ::google::protobuf::EnumDescriptor* DataParameter_DB_descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return DataParameter_DB_descriptor_;
+}
+bool DataParameter_DB_IsValid(int value) {
+  switch (value) {
+    case 0:
+    case 1:
+      return true;
+    default:
+      return false;
+  }
+}
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const DataParameter_DB DataParameter::LEVELDB;
+const DataParameter_DB DataParameter::LMDB;
+const DataParameter_DB DataParameter::DB_MIN;
+const DataParameter_DB DataParameter::DB_MAX;
+const int DataParameter::DB_ARRAYSIZE;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const int DataParameter::kSourceFieldNumber;
+const int DataParameter::kBatchSizeFieldNumber;
+const int DataParameter::kRandSkipFieldNumber;
+const int DataParameter::kBackendFieldNumber;
+const int DataParameter::kScaleFieldNumber;
+const int DataParameter::kMeanFileFieldNumber;
+const int DataParameter::kCropSizeFieldNumber;
+const int DataParameter::kMirrorFieldNumber;
+const int DataParameter::kForceEncodedColorFieldNumber;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+
+DataParameter::DataParameter()
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+  if (this != internal_default_instance()) protobuf_InitDefaults_caffe_2eproto();
+  SharedCtor();
+  // @@protoc_insertion_point(constructor:caffe.DataParameter)
+}
+
+void DataParameter::InitAsDefaultInstance() {
+}
+
+DataParameter::DataParameter(const DataParameter& from)
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
+  SharedCtor();
+  UnsafeMergeFrom(from);
+  // @@protoc_insertion_point(copy_constructor:caffe.DataParameter)
+}
+
+void DataParameter::SharedCtor() {
+  _cached_size_ = 0;
+  source_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  mean_file_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  ::memset(&batch_size_, 0, reinterpret_cast<char*>(&force_encoded_color_) -
+    reinterpret_cast<char*>(&batch_size_) + sizeof(force_encoded_color_));
+  scale_ = 1;
+}
+
+DataParameter::~DataParameter() {
+  // @@protoc_insertion_point(destructor:caffe.DataParameter)
+  SharedDtor();
+}
+
+void DataParameter::SharedDtor() {
+  source_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  mean_file_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+
+void DataParameter::SetCachedSize(int size) const {
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* DataParameter::descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return DataParameter_descriptor_;
+}
+
+const DataParameter& DataParameter::default_instance() {
+  protobuf_InitDefaults_caffe_2eproto();
+  return *internal_default_instance();
+}
+
+::google::protobuf::internal::ExplicitlyConstructed<DataParameter> DataParameter_default_instance_;
+
+DataParameter* DataParameter::New(::google::protobuf::Arena* arena) const {
+  DataParameter* n = new DataParameter;
+  if (arena != NULL) {
+    arena->Own(n);
+  }
+  return n;
+}
+
+void DataParameter::Clear() {
+// @@protoc_insertion_point(message_clear_start:caffe.DataParameter)
+#if defined(__clang__)
+#define ZR_HELPER_(f) \
+  _Pragma("clang diagnostic push") \
+  _Pragma("clang diagnostic ignored \"-Winvalid-offsetof\"") \
+  __builtin_offsetof(DataParameter, f) \
+  _Pragma("clang diagnostic pop")
+#else
+#define ZR_HELPER_(f) reinterpret_cast<char*>(\
+  &reinterpret_cast<DataParameter*>(16)->f)
+#endif
+
+#define ZR_(first, last) do {\
+  ::memset(&(first), 0,\
+           ZR_HELPER_(last) - ZR_HELPER_(first) + sizeof(last));\
+} while (0)
+
+  if (_has_bits_[0 / 32] & 255u) {
+    ZR_(batch_size_, mirror_);
+    if (has_source()) {
+      source_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+    }
+    scale_ = 1;
+    if (has_mean_file()) {
+      mean_file_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+    }
+  }
+  force_encoded_color_ = false;
+
+#undef ZR_HELPER_
+#undef ZR_
+
+  _has_bits_.Clear();
+  if (_internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->Clear();
+  }
+}
+
+bool DataParameter::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
+  ::google::protobuf::uint32 tag;
+  // @@protoc_insertion_point(parse_start:caffe.DataParameter)
+  for (;;) {
+    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+    tag = p.first;
+    if (!p.second) goto handle_unusual;
+    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+      // optional string source = 1;
+      case 1: {
+        if (tag == 10) {
+          DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+                input, this->mutable_source()));
+          ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+            this->source().data(), this->source().length(),
+            ::google::protobuf::internal::WireFormat::PARSE,
+            "caffe.DataParameter.source");
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(21)) goto parse_scale;
+        break;
+      }
+
+      // optional float scale = 2 [default = 1];
+      case 2: {
+        if (tag == 21) {
+         parse_scale:
+          set_has_scale();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
+                 input, &scale_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(26)) goto parse_mean_file;
+        break;
+      }
+
+      // optional string mean_file = 3;
+      case 3: {
+        if (tag == 26) {
+         parse_mean_file:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+                input, this->mutable_mean_file()));
+          ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+            this->mean_file().data(), this->mean_file().length(),
+            ::google::protobuf::internal::WireFormat::PARSE,
+            "caffe.DataParameter.mean_file");
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(32)) goto parse_batch_size;
+        break;
+      }
+
+      // optional uint32 batch_size = 4;
+      case 4: {
+        if (tag == 32) {
+         parse_batch_size:
+          set_has_batch_size();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>(
+                 input, &batch_size_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(40)) goto parse_crop_size;
+        break;
+      }
+
+      // optional uint32 crop_size = 5 [default = 0];
+      case 5: {
+        if (tag == 40) {
+         parse_crop_size:
+          set_has_crop_size();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>(
+                 input, &crop_size_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(48)) goto parse_mirror;
+        break;
+      }
+
+      // optional bool mirror = 6 [default = false];
+      case 6: {
+        if (tag == 48) {
+         parse_mirror:
+          set_has_mirror();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>(
+                 input, &mirror_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(56)) goto parse_rand_skip;
+        break;
+      }
+
+      // optional uint32 rand_skip = 7 [default = 0];
+      case 7: {
+        if (tag == 56) {
+         parse_rand_skip:
+          set_has_rand_skip();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>(
+                 input, &rand_skip_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(64)) goto parse_backend;
+        break;
+      }
+
+      // optional .caffe.DataParameter.DB backend = 8 [default = LEVELDB];
+      case 8: {
+        if (tag == 64) {
+         parse_backend:
+          int value;
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>(
+                 input, &value)));
+          if (::caffe::DataParameter_DB_IsValid(value)) {
+            set_backend(static_cast< ::caffe::DataParameter_DB >(value));
+          } else {
+            mutable_unknown_fields()->AddVarint(8, value);
+          }
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(72)) goto parse_force_encoded_color;
+        break;
+      }
+
+      // optional bool force_encoded_color = 9 [default = false];
+      case 9: {
+        if (tag == 72) {
+         parse_force_encoded_color:
+          set_has_force_encoded_color();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>(
+                 input, &force_encoded_color_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectAtEnd()) goto success;
+        break;
+      }
+
+      default: {
+      handle_unusual:
+        if (tag == 0 ||
+            ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+          goto success;
+        }
+        DO_(::google::protobuf::internal::WireFormat::SkipField(
+              input, tag, mutable_unknown_fields()));
+        break;
+      }
+    }
+  }
+success:
+  // @@protoc_insertion_point(parse_success:caffe.DataParameter)
+  return true;
+failure:
+  // @@protoc_insertion_point(parse_failure:caffe.DataParameter)
+  return false;
+#undef DO_
+}
+
+void DataParameter::SerializeWithCachedSizes(
+    ::google::protobuf::io::CodedOutputStream* output) const {
+  // @@protoc_insertion_point(serialize_start:caffe.DataParameter)
+  // optional string source = 1;
+  if (has_source()) {
+    ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->source().data(), this->source().length(),
+      ::google::protobuf::internal::WireFormat::SERIALIZE,
+      "caffe.DataParameter.source");
+    ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
+      1, this->source(), output);
+  }
+
+  // optional float scale = 2 [default = 1];
+  if (has_scale()) {
+    ::google::protobuf::internal::WireFormatLite::WriteFloat(2, this->scale(), output);
+  }
+
+  // optional string mean_file = 3;
+  if (has_mean_file()) {
+    ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->mean_file().data(), this->mean_file().length(),
+      ::google::protobuf::internal::WireFormat::SERIALIZE,
+      "caffe.DataParameter.mean_file");
+    ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
+      3, this->mean_file(), output);
+  }
+
+  // optional uint32 batch_size = 4;
+  if (has_batch_size()) {
+    ::google::protobuf::internal::WireFormatLite::WriteUInt32(4, this->batch_size(), output);
+  }
+
+  // optional uint32 crop_size = 5 [default = 0];
+  if (has_crop_size()) {
+    ::google::protobuf::internal::WireFormatLite::WriteUInt32(5, this->crop_size(), output);
+  }
+
+  // optional bool mirror = 6 [default = false];
+  if (has_mirror()) {
+    ::google::protobuf::internal::WireFormatLite::WriteBool(6, this->mirror(), output);
+  }
+
+  // optional uint32 rand_skip = 7 [default = 0];
+  if (has_rand_skip()) {
+    ::google::protobuf::internal::WireFormatLite::WriteUInt32(7, this->rand_skip(), output);
+  }
+
+  // optional .caffe.DataParameter.DB backend = 8 [default = LEVELDB];
+  if (has_backend()) {
+    ::google::protobuf::internal::WireFormatLite::WriteEnum(
+      8, this->backend(), output);
+  }
+
+  // optional bool force_encoded_color = 9 [default = false];
+  if (has_force_encoded_color()) {
+    ::google::protobuf::internal::WireFormatLite::WriteBool(9, this->force_encoded_color(), output);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
+        unknown_fields(), output);
+  }
+  // @@protoc_insertion_point(serialize_end:caffe.DataParameter)
+}
+
+::google::protobuf::uint8* DataParameter::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
+  (void)deterministic; // Unused
+  // @@protoc_insertion_point(serialize_to_array_start:caffe.DataParameter)
+  // optional string source = 1;
+  if (has_source()) {
+    ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->source().data(), this->source().length(),
+      ::google::protobuf::internal::WireFormat::SERIALIZE,
+      "caffe.DataParameter.source");
+    target =
+      ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
+        1, this->source(), target);
+  }
+
+  // optional float scale = 2 [default = 1];
+  if (has_scale()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteFloatToArray(2, this->scale(), target);
+  }
+
+  // optional string mean_file = 3;
+  if (has_mean_file()) {
+    ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->mean_file().data(), this->mean_file().length(),
+      ::google::protobuf::internal::WireFormat::SERIALIZE,
+      "caffe.DataParameter.mean_file");
+    target =
+      ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
+        3, this->mean_file(), target);
+  }
+
+  // optional uint32 batch_size = 4;
+  if (has_batch_size()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteUInt32ToArray(4, this->batch_size(), target);
+  }
+
+  // optional uint32 crop_size = 5 [default = 0];
+  if (has_crop_size()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteUInt32ToArray(5, this->crop_size(), target);
+  }
+
+  // optional bool mirror = 6 [default = false];
+  if (has_mirror()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(6, this->mirror(), target);
+  }
+
+  // optional uint32 rand_skip = 7 [default = 0];
+  if (has_rand_skip()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteUInt32ToArray(7, this->rand_skip(), target);
+  }
+
+  // optional .caffe.DataParameter.DB backend = 8 [default = LEVELDB];
+  if (has_backend()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteEnumToArray(
+      8, this->backend(), target);
+  }
+
+  // optional bool force_encoded_color = 9 [default = false];
+  if (has_force_encoded_color()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(9, this->force_encoded_color(), target);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
+        unknown_fields(), target);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:caffe.DataParameter)
+  return target;
+}
+
+size_t DataParameter::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:caffe.DataParameter)
+  size_t total_size = 0;
+
+  if (_has_bits_[0 / 32] & 255u) {
+    // optional string source = 1;
+    if (has_source()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::StringSize(
+          this->source());
+    }
+
+    // optional uint32 batch_size = 4;
+    if (has_batch_size()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::UInt32Size(
+          this->batch_size());
+    }
+
+    // optional uint32 rand_skip = 7 [default = 0];
+    if (has_rand_skip()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::UInt32Size(
+          this->rand_skip());
+    }
+
+    // optional .caffe.DataParameter.DB backend = 8 [default = LEVELDB];
+    if (has_backend()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::EnumSize(this->backend());
+    }
+
+    // optional float scale = 2 [default = 1];
+    if (has_scale()) {
+      total_size += 1 + 4;
+    }
+
+    // optional string mean_file = 3;
+    if (has_mean_file()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::StringSize(
+          this->mean_file());
+    }
+
+    // optional uint32 crop_size = 5 [default = 0];
+    if (has_crop_size()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::UInt32Size(
+          this->crop_size());
+    }
+
+    // optional bool mirror = 6 [default = false];
+    if (has_mirror()) {
+      total_size += 1 + 1;
+    }
+
+  }
+  // optional bool force_encoded_color = 9 [default = false];
+  if (has_force_encoded_color()) {
+    total_size += 1 + 1;
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    total_size +=
+      ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
+        unknown_fields());
+  }
+  int cached_size = ::google::protobuf::internal::ToCachedSize(total_size);
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = cached_size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+  return total_size;
+}
+
+void DataParameter::MergeFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_merge_from_start:caffe.DataParameter)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const DataParameter* source =
+      ::google::protobuf::internal::DynamicCastToGenerated<const DataParameter>(
+          &from);
+  if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:caffe.DataParameter)
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:caffe.DataParameter)
+    UnsafeMergeFrom(*source);
+  }
+}
+
+void DataParameter::MergeFrom(const DataParameter& from) {
+// @@protoc_insertion_point(class_specific_merge_from_start:caffe.DataParameter)
+  if (GOOGLE_PREDICT_TRUE(&from != this)) {
+    UnsafeMergeFrom(from);
+  } else {
+    MergeFromFail(__LINE__);
+  }
+}
+
+void DataParameter::UnsafeMergeFrom(const DataParameter& from) {
+  GOOGLE_DCHECK(&from != this);
+  if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+    if (from.has_source()) {
+      set_has_source();
+      source_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.source_);
+    }
+    if (from.has_batch_size()) {
+      set_batch_size(from.batch_size());
+    }
+    if (from.has_rand_skip()) {
+      set_rand_skip(from.rand_skip());
+    }
+    if (from.has_backend()) {
+      set_backend(from.backend());
+    }
+    if (from.has_scale()) {
+      set_scale(from.scale());
+    }
+    if (from.has_mean_file()) {
+      set_has_mean_file();
+      mean_file_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.mean_file_);
+    }
+    if (from.has_crop_size()) {
+      set_crop_size(from.crop_size());
+    }
+    if (from.has_mirror()) {
+      set_mirror(from.mirror());
+    }
+  }
+  if (from._has_bits_[8 / 32] & (0xffu << (8 % 32))) {
+    if (from.has_force_encoded_color()) {
+      set_force_encoded_color(from.force_encoded_color());
+    }
+  }
+  if (from._internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::UnknownFieldSet::MergeToInternalMetdata(
+      from.unknown_fields(), &_internal_metadata_);
+  }
+}
+
+void DataParameter::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:caffe.DataParameter)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void DataParameter::CopyFrom(const DataParameter& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:caffe.DataParameter)
+  if (&from == this) return;
+  Clear();
+  UnsafeMergeFrom(from);
+}
+
+bool DataParameter::IsInitialized() const {
+
+  return true;
+}
+
+void DataParameter::Swap(DataParameter* other) {
+  if (other == this) return;
+  InternalSwap(other);
+}
+void DataParameter::InternalSwap(DataParameter* other) {
+  source_.Swap(&other->source_);
+  std::swap(batch_size_, other->batch_size_);
+  std::swap(rand_skip_, other->rand_skip_);
+  std::swap(backend_, other->backend_);
+  std::swap(scale_, other->scale_);
+  mean_file_.Swap(&other->mean_file_);
+  std::swap(crop_size_, other->crop_size_);
+  std::swap(mirror_, other->mirror_);
+  std::swap(force_encoded_color_, other->force_encoded_color_);
+  std::swap(_has_bits_[0], other->_has_bits_[0]);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
+}
+
+::google::protobuf::Metadata DataParameter::GetMetadata() const {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::Metadata metadata;
+  metadata.descriptor = DataParameter_descriptor_;
+  metadata.reflection = DataParameter_reflection_;
+  return metadata;
+}
+
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// DataParameter
+
+// optional string source = 1;
+bool DataParameter::has_source() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+void DataParameter::set_has_source() {
+  _has_bits_[0] |= 0x00000001u;
+}
+void DataParameter::clear_has_source() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+void DataParameter::clear_source() {
+  source_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  clear_has_source();
+}
+const ::std::string& DataParameter::source() const {
+  // @@protoc_insertion_point(field_get:caffe.DataParameter.source)
+  return source_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+void DataParameter::set_source(const ::std::string& value) {
+  set_has_source();
+  source_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:caffe.DataParameter.source)
+}
+void DataParameter::set_source(const char* value) {
+  set_has_source();
+  source_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:caffe.DataParameter.source)
+}
+void DataParameter::set_source(const char* value, size_t size) {
+  set_has_source();
+  source_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:caffe.DataParameter.source)
+}
+::std::string* DataParameter::mutable_source() {
+  set_has_source();
+  // @@protoc_insertion_point(field_mutable:caffe.DataParameter.source)
+  return source_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+::std::string* DataParameter::release_source() {
+  // @@protoc_insertion_point(field_release:caffe.DataParameter.source)
+  clear_has_source();
+  return source_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+void DataParameter::set_allocated_source(::std::string* source) {
+  if (source != NULL) {
+    set_has_source();
+  } else {
+    clear_has_source();
+  }
+  source_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), source);
+  // @@protoc_insertion_point(field_set_allocated:caffe.DataParameter.source)
+}
+
+// optional uint32 batch_size = 4;
+bool DataParameter::has_batch_size() const {
+  return (_has_bits_[0] & 0x00000002u) != 0;
+}
+void DataParameter::set_has_batch_size() {
+  _has_bits_[0] |= 0x00000002u;
+}
+void DataParameter::clear_has_batch_size() {
+  _has_bits_[0] &= ~0x00000002u;
+}
+void DataParameter::clear_batch_size() {
+  batch_size_ = 0u;
+  clear_has_batch_size();
+}
+::google::protobuf::uint32 DataParameter::batch_size() const {
+  // @@protoc_insertion_point(field_get:caffe.DataParameter.batch_size)
+  return batch_size_;
+}
+void DataParameter::set_batch_size(::google::protobuf::uint32 value) {
+  set_has_batch_size();
+  batch_size_ = value;
+  // @@protoc_insertion_point(field_set:caffe.DataParameter.batch_size)
+}
+
+// optional uint32 rand_skip = 7 [default = 0];
+bool DataParameter::has_rand_skip() const {
+  return (_has_bits_[0] & 0x00000004u) != 0;
+}
+void DataParameter::set_has_rand_skip() {
+  _has_bits_[0] |= 0x00000004u;
+}
+void DataParameter::clear_has_rand_skip() {
+  _has_bits_[0] &= ~0x00000004u;
+}
+void DataParameter::clear_rand_skip() {
+  rand_skip_ = 0u;
+  clear_has_rand_skip();
+}
+::google::protobuf::uint32 DataParameter::rand_skip() const {
+  // @@protoc_insertion_point(field_get:caffe.DataParameter.rand_skip)
+  return rand_skip_;
+}
+void DataParameter::set_rand_skip(::google::protobuf::uint32 value) {
+  set_has_rand_skip();
+  rand_skip_ = value;
+  // @@protoc_insertion_point(field_set:caffe.DataParameter.rand_skip)
+}
+
+// optional .caffe.DataParameter.DB backend = 8 [default = LEVELDB];
+bool DataParameter::has_backend() const {
+  return (_has_bits_[0] & 0x00000008u) != 0;
+}
+void DataParameter::set_has_backend() {
+  _has_bits_[0] |= 0x00000008u;
+}
+void DataParameter::clear_has_backend() {
+  _has_bits_[0] &= ~0x00000008u;
+}
+void DataParameter::clear_backend() {
+  backend_ = 0;
+  clear_has_backend();
+}
+::caffe::DataParameter_DB DataParameter::backend() const {
+  // @@protoc_insertion_point(field_get:caffe.DataParameter.backend)
+  return static_cast< ::caffe::DataParameter_DB >(backend_);
+}
+void DataParameter::set_backend(::caffe::DataParameter_DB value) {
+  assert(::caffe::DataParameter_DB_IsValid(value));
+  set_has_backend();
+  backend_ = value;
+  // @@protoc_insertion_point(field_set:caffe.DataParameter.backend)
+}
+
+// optional float scale = 2 [default = 1];
+bool DataParameter::has_scale() const {
+  return (_has_bits_[0] & 0x00000010u) != 0;
+}
+void DataParameter::set_has_scale() {
+  _has_bits_[0] |= 0x00000010u;
+}
+void DataParameter::clear_has_scale() {
+  _has_bits_[0] &= ~0x00000010u;
+}
+void DataParameter::clear_scale() {
+  scale_ = 1;
+  clear_has_scale();
+}
+float DataParameter::scale() const {
+  // @@protoc_insertion_point(field_get:caffe.DataParameter.scale)
+  return scale_;
+}
+void DataParameter::set_scale(float value) {
+  set_has_scale();
+  scale_ = value;
+  // @@protoc_insertion_point(field_set:caffe.DataParameter.scale)
+}
+
+// optional string mean_file = 3;
+bool DataParameter::has_mean_file() const {
+  return (_has_bits_[0] & 0x00000020u) != 0;
+}
+void DataParameter::set_has_mean_file() {
+  _has_bits_[0] |= 0x00000020u;
+}
+void DataParameter::clear_has_mean_file() {
+  _has_bits_[0] &= ~0x00000020u;
+}
+void DataParameter::clear_mean_file() {
+  mean_file_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  clear_has_mean_file();
+}
+const ::std::string& DataParameter::mean_file() const {
+  // @@protoc_insertion_point(field_get:caffe.DataParameter.mean_file)
+  return mean_file_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+void DataParameter::set_mean_file(const ::std::string& value) {
+  set_has_mean_file();
+  mean_file_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:caffe.DataParameter.mean_file)
+}
+void DataParameter::set_mean_file(const char* value) {
+  set_has_mean_file();
+  mean_file_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:caffe.DataParameter.mean_file)
+}
+void DataParameter::set_mean_file(const char* value, size_t size) {
+  set_has_mean_file();
+  mean_file_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:caffe.DataParameter.mean_file)
+}
+::std::string* DataParameter::mutable_mean_file() {
+  set_has_mean_file();
+  // @@protoc_insertion_point(field_mutable:caffe.DataParameter.mean_file)
+  return mean_file_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+::std::string* DataParameter::release_mean_file() {
+  // @@protoc_insertion_point(field_release:caffe.DataParameter.mean_file)
+  clear_has_mean_file();
+  return mean_file_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+void DataParameter::set_allocated_mean_file(::std::string* mean_file) {
+  if (mean_file != NULL) {
+    set_has_mean_file();
+  } else {
+    clear_has_mean_file();
+  }
+  mean_file_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), mean_file);
+  // @@protoc_insertion_point(field_set_allocated:caffe.DataParameter.mean_file)
+}
+
+// optional uint32 crop_size = 5 [default = 0];
+bool DataParameter::has_crop_size() const {
+  return (_has_bits_[0] & 0x00000040u) != 0;
+}
+void DataParameter::set_has_crop_size() {
+  _has_bits_[0] |= 0x00000040u;
+}
+void DataParameter::clear_has_crop_size() {
+  _has_bits_[0] &= ~0x00000040u;
+}
+void DataParameter::clear_crop_size() {
+  crop_size_ = 0u;
+  clear_has_crop_size();
+}
+::google::protobuf::uint32 DataParameter::crop_size() const {
+  // @@protoc_insertion_point(field_get:caffe.DataParameter.crop_size)
+  return crop_size_;
+}
+void DataParameter::set_crop_size(::google::protobuf::uint32 value) {
+  set_has_crop_size();
+  crop_size_ = value;
+  // @@protoc_insertion_point(field_set:caffe.DataParameter.crop_size)
+}
+
+// optional bool mirror = 6 [default = false];
+bool DataParameter::has_mirror() const {
+  return (_has_bits_[0] & 0x00000080u) != 0;
+}
+void DataParameter::set_has_mirror() {
+  _has_bits_[0] |= 0x00000080u;
+}
+void DataParameter::clear_has_mirror() {
+  _has_bits_[0] &= ~0x00000080u;
+}
+void DataParameter::clear_mirror() {
+  mirror_ = false;
+  clear_has_mirror();
+}
+bool DataParameter::mirror() const {
+  // @@protoc_insertion_point(field_get:caffe.DataParameter.mirror)
+  return mirror_;
+}
+void DataParameter::set_mirror(bool value) {
+  set_has_mirror();
+  mirror_ = value;
+  // @@protoc_insertion_point(field_set:caffe.DataParameter.mirror)
+}
+
+// optional bool force_encoded_color = 9 [default = false];
+bool DataParameter::has_force_encoded_color() const {
+  return (_has_bits_[0] & 0x00000100u) != 0;
+}
+void DataParameter::set_has_force_encoded_color() {
+  _has_bits_[0] |= 0x00000100u;
+}
+void DataParameter::clear_has_force_encoded_color() {
+  _has_bits_[0] &= ~0x00000100u;
+}
+void DataParameter::clear_force_encoded_color() {
+  force_encoded_color_ = false;
+  clear_has_force_encoded_color();
+}
+bool DataParameter::force_encoded_color() const {
+  // @@protoc_insertion_point(field_get:caffe.DataParameter.force_encoded_color)
+  return force_encoded_color_;
+}
+void DataParameter::set_force_encoded_color(bool value) {
+  set_has_force_encoded_color();
+  force_encoded_color_ = value;
+  // @@protoc_insertion_point(field_set:caffe.DataParameter.force_encoded_color)
+}
+
+inline const DataParameter* DataParameter::internal_default_instance() {
+  return &DataParameter_default_instance_.get();
+}
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
+
+// ===================================================================
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const int DropoutParameter::kDropoutRatioFieldNumber;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+
+DropoutParameter::DropoutParameter()
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+  if (this != internal_default_instance()) protobuf_InitDefaults_caffe_2eproto();
+  SharedCtor();
+  // @@protoc_insertion_point(constructor:caffe.DropoutParameter)
+}
+
+void DropoutParameter::InitAsDefaultInstance() {
+}
+
+DropoutParameter::DropoutParameter(const DropoutParameter& from)
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
+  SharedCtor();
+  UnsafeMergeFrom(from);
+  // @@protoc_insertion_point(copy_constructor:caffe.DropoutParameter)
+}
+
+void DropoutParameter::SharedCtor() {
+  _cached_size_ = 0;
+  dropout_ratio_ = 0.5f;
+}
+
+DropoutParameter::~DropoutParameter() {
+  // @@protoc_insertion_point(destructor:caffe.DropoutParameter)
+  SharedDtor();
+}
+
+void DropoutParameter::SharedDtor() {
+}
+
+void DropoutParameter::SetCachedSize(int size) const {
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* DropoutParameter::descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return DropoutParameter_descriptor_;
+}
+
+const DropoutParameter& DropoutParameter::default_instance() {
+  protobuf_InitDefaults_caffe_2eproto();
+  return *internal_default_instance();
+}
+
+::google::protobuf::internal::ExplicitlyConstructed<DropoutParameter> DropoutParameter_default_instance_;
+
+DropoutParameter* DropoutParameter::New(::google::protobuf::Arena* arena) const {
+  DropoutParameter* n = new DropoutParameter;
+  if (arena != NULL) {
+    arena->Own(n);
+  }
+  return n;
+}
+
+void DropoutParameter::Clear() {
+// @@protoc_insertion_point(message_clear_start:caffe.DropoutParameter)
+  dropout_ratio_ = 0.5f;
+  _has_bits_.Clear();
+  if (_internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->Clear();
+  }
+}
+
+bool DropoutParameter::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
+  ::google::protobuf::uint32 tag;
+  // @@protoc_insertion_point(parse_start:caffe.DropoutParameter)
+  for (;;) {
+    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+    tag = p.first;
+    if (!p.second) goto handle_unusual;
+    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+      // optional float dropout_ratio = 1 [default = 0.5];
+      case 1: {
+        if (tag == 13) {
+          set_has_dropout_ratio();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
+                 input, &dropout_ratio_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectAtEnd()) goto success;
+        break;
+      }
+
+      default: {
+      handle_unusual:
+        if (tag == 0 ||
+            ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+          goto success;
+        }
+        DO_(::google::protobuf::internal::WireFormat::SkipField(
+              input, tag, mutable_unknown_fields()));
+        break;
+      }
+    }
+  }
+success:
+  // @@protoc_insertion_point(parse_success:caffe.DropoutParameter)
+  return true;
+failure:
+  // @@protoc_insertion_point(parse_failure:caffe.DropoutParameter)
+  return false;
+#undef DO_
+}
+
+void DropoutParameter::SerializeWithCachedSizes(
+    ::google::protobuf::io::CodedOutputStream* output) const {
+  // @@protoc_insertion_point(serialize_start:caffe.DropoutParameter)
+  // optional float dropout_ratio = 1 [default = 0.5];
+  if (has_dropout_ratio()) {
+    ::google::protobuf::internal::WireFormatLite::WriteFloat(1, this->dropout_ratio(), output);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
+        unknown_fields(), output);
+  }
+  // @@protoc_insertion_point(serialize_end:caffe.DropoutParameter)
+}
+
+::google::protobuf::uint8* DropoutParameter::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
+  (void)deterministic; // Unused
+  // @@protoc_insertion_point(serialize_to_array_start:caffe.DropoutParameter)
+  // optional float dropout_ratio = 1 [default = 0.5];
+  if (has_dropout_ratio()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteFloatToArray(1, this->dropout_ratio(), target);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
+        unknown_fields(), target);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:caffe.DropoutParameter)
+  return target;
+}
+
+size_t DropoutParameter::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:caffe.DropoutParameter)
+  size_t total_size = 0;
+
+  // optional float dropout_ratio = 1 [default = 0.5];
+  if (has_dropout_ratio()) {
+    total_size += 1 + 4;
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    total_size +=
+      ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
+        unknown_fields());
+  }
+  int cached_size = ::google::protobuf::internal::ToCachedSize(total_size);
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = cached_size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+  return total_size;
+}
+
+void DropoutParameter::MergeFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_merge_from_start:caffe.DropoutParameter)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const DropoutParameter* source =
+      ::google::protobuf::internal::DynamicCastToGenerated<const DropoutParameter>(
+          &from);
+  if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:caffe.DropoutParameter)
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:caffe.DropoutParameter)
+    UnsafeMergeFrom(*source);
+  }
+}
+
+void DropoutParameter::MergeFrom(const DropoutParameter& from) {
+// @@protoc_insertion_point(class_specific_merge_from_start:caffe.DropoutParameter)
+  if (GOOGLE_PREDICT_TRUE(&from != this)) {
+    UnsafeMergeFrom(from);
+  } else {
+    MergeFromFail(__LINE__);
+  }
+}
+
+void DropoutParameter::UnsafeMergeFrom(const DropoutParameter& from) {
+  GOOGLE_DCHECK(&from != this);
+  if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+    if (from.has_dropout_ratio()) {
+      set_dropout_ratio(from.dropout_ratio());
+    }
+  }
+  if (from._internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::UnknownFieldSet::MergeToInternalMetdata(
+      from.unknown_fields(), &_internal_metadata_);
+  }
+}
+
+void DropoutParameter::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:caffe.DropoutParameter)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void DropoutParameter::CopyFrom(const DropoutParameter& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:caffe.DropoutParameter)
+  if (&from == this) return;
+  Clear();
+  UnsafeMergeFrom(from);
+}
+
+bool DropoutParameter::IsInitialized() const {
+
+  return true;
+}
+
+void DropoutParameter::Swap(DropoutParameter* other) {
+  if (other == this) return;
+  InternalSwap(other);
+}
+void DropoutParameter::InternalSwap(DropoutParameter* other) {
+  std::swap(dropout_ratio_, other->dropout_ratio_);
+  std::swap(_has_bits_[0], other->_has_bits_[0]);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
+}
+
+::google::protobuf::Metadata DropoutParameter::GetMetadata() const {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::Metadata metadata;
+  metadata.descriptor = DropoutParameter_descriptor_;
+  metadata.reflection = DropoutParameter_reflection_;
+  return metadata;
+}
+
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// DropoutParameter
+
+// optional float dropout_ratio = 1 [default = 0.5];
+bool DropoutParameter::has_dropout_ratio() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+void DropoutParameter::set_has_dropout_ratio() {
+  _has_bits_[0] |= 0x00000001u;
+}
+void DropoutParameter::clear_has_dropout_ratio() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+void DropoutParameter::clear_dropout_ratio() {
+  dropout_ratio_ = 0.5f;
+  clear_has_dropout_ratio();
+}
+float DropoutParameter::dropout_ratio() const {
+  // @@protoc_insertion_point(field_get:caffe.DropoutParameter.dropout_ratio)
+  return dropout_ratio_;
+}
+void DropoutParameter::set_dropout_ratio(float value) {
+  set_has_dropout_ratio();
+  dropout_ratio_ = value;
+  // @@protoc_insertion_point(field_set:caffe.DropoutParameter.dropout_ratio)
+}
+
+inline const DropoutParameter* DropoutParameter::internal_default_instance() {
+  return &DropoutParameter_default_instance_.get();
+}
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
+
+// ===================================================================
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const int DummyDataParameter::kDataFillerFieldNumber;
+const int DummyDataParameter::kShapeFieldNumber;
+const int DummyDataParameter::kNumFieldNumber;
+const int DummyDataParameter::kChannelsFieldNumber;
+const int DummyDataParameter::kHeightFieldNumber;
+const int DummyDataParameter::kWidthFieldNumber;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+
+DummyDataParameter::DummyDataParameter()
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+  if (this != internal_default_instance()) protobuf_InitDefaults_caffe_2eproto();
+  SharedCtor();
+  // @@protoc_insertion_point(constructor:caffe.DummyDataParameter)
+}
+
+void DummyDataParameter::InitAsDefaultInstance() {
+}
+
+DummyDataParameter::DummyDataParameter(const DummyDataParameter& from)
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
+  SharedCtor();
+  UnsafeMergeFrom(from);
+  // @@protoc_insertion_point(copy_constructor:caffe.DummyDataParameter)
+}
+
+void DummyDataParameter::SharedCtor() {
+  _cached_size_ = 0;
+}
+
+DummyDataParameter::~DummyDataParameter() {
+  // @@protoc_insertion_point(destructor:caffe.DummyDataParameter)
+  SharedDtor();
+}
+
+void DummyDataParameter::SharedDtor() {
+}
+
+void DummyDataParameter::SetCachedSize(int size) const {
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* DummyDataParameter::descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return DummyDataParameter_descriptor_;
+}
+
+const DummyDataParameter& DummyDataParameter::default_instance() {
+  protobuf_InitDefaults_caffe_2eproto();
+  return *internal_default_instance();
+}
+
+::google::protobuf::internal::ExplicitlyConstructed<DummyDataParameter> DummyDataParameter_default_instance_;
+
+DummyDataParameter* DummyDataParameter::New(::google::protobuf::Arena* arena) const {
+  DummyDataParameter* n = new DummyDataParameter;
+  if (arena != NULL) {
+    arena->Own(n);
+  }
+  return n;
+}
+
+void DummyDataParameter::Clear() {
+// @@protoc_insertion_point(message_clear_start:caffe.DummyDataParameter)
+  data_filler_.Clear();
+  shape_.Clear();
+  num_.Clear();
+  channels_.Clear();
+  height_.Clear();
+  width_.Clear();
+  _has_bits_.Clear();
+  if (_internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->Clear();
+  }
+}
+
+bool DummyDataParameter::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
+  ::google::protobuf::uint32 tag;
+  // @@protoc_insertion_point(parse_start:caffe.DummyDataParameter)
+  for (;;) {
+    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+    tag = p.first;
+    if (!p.second) goto handle_unusual;
+    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+      // repeated .caffe.FillerParameter data_filler = 1;
+      case 1: {
+        if (tag == 10) {
+          DO_(input->IncrementRecursionDepth());
+         parse_loop_data_filler:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth(
+                input, add_data_filler()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(10)) goto parse_loop_data_filler;
+        input->UnsafeDecrementRecursionDepth();
+        if (input->ExpectTag(16)) goto parse_num;
+        break;
+      }
+
+      // repeated uint32 num = 2;
+      case 2: {
+        if (tag == 16) {
+         parse_num:
+          DO_((::google::protobuf::internal::WireFormatLite::ReadRepeatedPrimitive<
+                   ::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>(
+                 1, 16, input, this->mutable_num())));
+        } else if (tag == 18) {
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPackedPrimitiveNoInline<
+                   ::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>(
+                 input, this->mutable_num())));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(16)) goto parse_num;
+        if (input->ExpectTag(24)) goto parse_channels;
+        break;
+      }
+
+      // repeated uint32 channels = 3;
+      case 3: {
+        if (tag == 24) {
+         parse_channels:
+          DO_((::google::protobuf::internal::WireFormatLite::ReadRepeatedPrimitive<
+                   ::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>(
+                 1, 24, input, this->mutable_channels())));
+        } else if (tag == 26) {
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPackedPrimitiveNoInline<
+                   ::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>(
+                 input, this->mutable_channels())));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(24)) goto parse_channels;
+        if (input->ExpectTag(32)) goto parse_height;
+        break;
+      }
+
+      // repeated uint32 height = 4;
+      case 4: {
+        if (tag == 32) {
+         parse_height:
+          DO_((::google::protobuf::internal::WireFormatLite::ReadRepeatedPrimitive<
+                   ::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>(
+                 1, 32, input, this->mutable_height())));
+        } else if (tag == 34) {
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPackedPrimitiveNoInline<
+                   ::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>(
+                 input, this->mutable_height())));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(32)) goto parse_height;
+        if (input->ExpectTag(40)) goto parse_width;
+        break;
+      }
+
+      // repeated uint32 width = 5;
+      case 5: {
+        if (tag == 40) {
+         parse_width:
+          DO_((::google::protobuf::internal::WireFormatLite::ReadRepeatedPrimitive<
+                   ::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>(
+                 1, 40, input, this->mutable_width())));
+        } else if (tag == 42) {
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPackedPrimitiveNoInline<
+                   ::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>(
+                 input, this->mutable_width())));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(40)) goto parse_width;
+        if (input->ExpectTag(50)) goto parse_shape;
+        break;
+      }
+
+      // repeated .caffe.BlobShape shape = 6;
+      case 6: {
+        if (tag == 50) {
+         parse_shape:
+          DO_(input->IncrementRecursionDepth());
+         parse_loop_shape:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth(
+                input, add_shape()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(50)) goto parse_loop_shape;
+        input->UnsafeDecrementRecursionDepth();
+        if (input->ExpectAtEnd()) goto success;
+        break;
+      }
+
+      default: {
+      handle_unusual:
+        if (tag == 0 ||
+            ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+          goto success;
+        }
+        DO_(::google::protobuf::internal::WireFormat::SkipField(
+              input, tag, mutable_unknown_fields()));
+        break;
+      }
+    }
+  }
+success:
+  // @@protoc_insertion_point(parse_success:caffe.DummyDataParameter)
+  return true;
+failure:
+  // @@protoc_insertion_point(parse_failure:caffe.DummyDataParameter)
+  return false;
+#undef DO_
+}
+
+void DummyDataParameter::SerializeWithCachedSizes(
+    ::google::protobuf::io::CodedOutputStream* output) const {
+  // @@protoc_insertion_point(serialize_start:caffe.DummyDataParameter)
+  // repeated .caffe.FillerParameter data_filler = 1;
+  for (unsigned int i = 0, n = this->data_filler_size(); i < n; i++) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      1, this->data_filler(i), output);
+  }
+
+  // repeated uint32 num = 2;
+  for (int i = 0; i < this->num_size(); i++) {
+    ::google::protobuf::internal::WireFormatLite::WriteUInt32(
+      2, this->num(i), output);
+  }
+
+  // repeated uint32 channels = 3;
+  for (int i = 0; i < this->channels_size(); i++) {
+    ::google::protobuf::internal::WireFormatLite::WriteUInt32(
+      3, this->channels(i), output);
+  }
+
+  // repeated uint32 height = 4;
+  for (int i = 0; i < this->height_size(); i++) {
+    ::google::protobuf::internal::WireFormatLite::WriteUInt32(
+      4, this->height(i), output);
+  }
+
+  // repeated uint32 width = 5;
+  for (int i = 0; i < this->width_size(); i++) {
+    ::google::protobuf::internal::WireFormatLite::WriteUInt32(
+      5, this->width(i), output);
+  }
+
+  // repeated .caffe.BlobShape shape = 6;
+  for (unsigned int i = 0, n = this->shape_size(); i < n; i++) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      6, this->shape(i), output);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
+        unknown_fields(), output);
+  }
+  // @@protoc_insertion_point(serialize_end:caffe.DummyDataParameter)
+}
+
+::google::protobuf::uint8* DummyDataParameter::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
+  (void)deterministic; // Unused
+  // @@protoc_insertion_point(serialize_to_array_start:caffe.DummyDataParameter)
+  // repeated .caffe.FillerParameter data_filler = 1;
+  for (unsigned int i = 0, n = this->data_filler_size(); i < n; i++) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        1, this->data_filler(i), false, target);
+  }
+
+  // repeated uint32 num = 2;
+  for (int i = 0; i < this->num_size(); i++) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      WriteUInt32ToArray(2, this->num(i), target);
+  }
+
+  // repeated uint32 channels = 3;
+  for (int i = 0; i < this->channels_size(); i++) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      WriteUInt32ToArray(3, this->channels(i), target);
+  }
+
+  // repeated uint32 height = 4;
+  for (int i = 0; i < this->height_size(); i++) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      WriteUInt32ToArray(4, this->height(i), target);
+  }
+
+  // repeated uint32 width = 5;
+  for (int i = 0; i < this->width_size(); i++) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      WriteUInt32ToArray(5, this->width(i), target);
+  }
+
+  // repeated .caffe.BlobShape shape = 6;
+  for (unsigned int i = 0, n = this->shape_size(); i < n; i++) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        6, this->shape(i), false, target);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
+        unknown_fields(), target);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:caffe.DummyDataParameter)
+  return target;
+}
+
+size_t DummyDataParameter::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:caffe.DummyDataParameter)
+  size_t total_size = 0;
+
+  // repeated .caffe.FillerParameter data_filler = 1;
+  {
+    unsigned int count = this->data_filler_size();
+    total_size += 1UL * count;
+    for (unsigned int i = 0; i < count; i++) {
+      total_size +=
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          this->data_filler(i));
+    }
+  }
+
+  // repeated .caffe.BlobShape shape = 6;
+  {
+    unsigned int count = this->shape_size();
+    total_size += 1UL * count;
+    for (unsigned int i = 0; i < count; i++) {
+      total_size +=
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          this->shape(i));
+    }
+  }
+
+  // repeated uint32 num = 2;
+  {
+    size_t data_size = 0;
+    unsigned int count = this->num_size();
+    for (unsigned int i = 0; i < count; i++) {
+      data_size += ::google::protobuf::internal::WireFormatLite::
+        UInt32Size(this->num(i));
+    }
+    total_size += 1 *
+                  ::google::protobuf::internal::FromIntSize(this->num_size());
+    total_size += data_size;
+  }
+
+  // repeated uint32 channels = 3;
+  {
+    size_t data_size = 0;
+    unsigned int count = this->channels_size();
+    for (unsigned int i = 0; i < count; i++) {
+      data_size += ::google::protobuf::internal::WireFormatLite::
+        UInt32Size(this->channels(i));
+    }
+    total_size += 1 *
+                  ::google::protobuf::internal::FromIntSize(this->channels_size());
+    total_size += data_size;
+  }
+
+  // repeated uint32 height = 4;
+  {
+    size_t data_size = 0;
+    unsigned int count = this->height_size();
+    for (unsigned int i = 0; i < count; i++) {
+      data_size += ::google::protobuf::internal::WireFormatLite::
+        UInt32Size(this->height(i));
+    }
+    total_size += 1 *
+                  ::google::protobuf::internal::FromIntSize(this->height_size());
+    total_size += data_size;
+  }
+
+  // repeated uint32 width = 5;
+  {
+    size_t data_size = 0;
+    unsigned int count = this->width_size();
+    for (unsigned int i = 0; i < count; i++) {
+      data_size += ::google::protobuf::internal::WireFormatLite::
+        UInt32Size(this->width(i));
+    }
+    total_size += 1 *
+                  ::google::protobuf::internal::FromIntSize(this->width_size());
+    total_size += data_size;
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    total_size +=
+      ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
+        unknown_fields());
+  }
+  int cached_size = ::google::protobuf::internal::ToCachedSize(total_size);
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = cached_size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+  return total_size;
+}
+
+void DummyDataParameter::MergeFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_merge_from_start:caffe.DummyDataParameter)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const DummyDataParameter* source =
+      ::google::protobuf::internal::DynamicCastToGenerated<const DummyDataParameter>(
+          &from);
+  if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:caffe.DummyDataParameter)
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:caffe.DummyDataParameter)
+    UnsafeMergeFrom(*source);
+  }
+}
+
+void DummyDataParameter::MergeFrom(const DummyDataParameter& from) {
+// @@protoc_insertion_point(class_specific_merge_from_start:caffe.DummyDataParameter)
+  if (GOOGLE_PREDICT_TRUE(&from != this)) {
+    UnsafeMergeFrom(from);
+  } else {
+    MergeFromFail(__LINE__);
+  }
+}
+
+void DummyDataParameter::UnsafeMergeFrom(const DummyDataParameter& from) {
+  GOOGLE_DCHECK(&from != this);
+  data_filler_.MergeFrom(from.data_filler_);
+  shape_.MergeFrom(from.shape_);
+  num_.UnsafeMergeFrom(from.num_);
+  channels_.UnsafeMergeFrom(from.channels_);
+  height_.UnsafeMergeFrom(from.height_);
+  width_.UnsafeMergeFrom(from.width_);
+  if (from._internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::UnknownFieldSet::MergeToInternalMetdata(
+      from.unknown_fields(), &_internal_metadata_);
+  }
+}
+
+void DummyDataParameter::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:caffe.DummyDataParameter)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void DummyDataParameter::CopyFrom(const DummyDataParameter& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:caffe.DummyDataParameter)
+  if (&from == this) return;
+  Clear();
+  UnsafeMergeFrom(from);
+}
+
+bool DummyDataParameter::IsInitialized() const {
+
+  return true;
+}
+
+void DummyDataParameter::Swap(DummyDataParameter* other) {
+  if (other == this) return;
+  InternalSwap(other);
+}
+void DummyDataParameter::InternalSwap(DummyDataParameter* other) {
+  data_filler_.UnsafeArenaSwap(&other->data_filler_);
+  shape_.UnsafeArenaSwap(&other->shape_);
+  num_.UnsafeArenaSwap(&other->num_);
+  channels_.UnsafeArenaSwap(&other->channels_);
+  height_.UnsafeArenaSwap(&other->height_);
+  width_.UnsafeArenaSwap(&other->width_);
+  std::swap(_has_bits_[0], other->_has_bits_[0]);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
+}
+
+::google::protobuf::Metadata DummyDataParameter::GetMetadata() const {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::Metadata metadata;
+  metadata.descriptor = DummyDataParameter_descriptor_;
+  metadata.reflection = DummyDataParameter_reflection_;
+  return metadata;
+}
+
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// DummyDataParameter
+
+// repeated .caffe.FillerParameter data_filler = 1;
+int DummyDataParameter::data_filler_size() const {
+  return data_filler_.size();
+}
+void DummyDataParameter::clear_data_filler() {
+  data_filler_.Clear();
+}
+const ::caffe::FillerParameter& DummyDataParameter::data_filler(int index) const {
+  // @@protoc_insertion_point(field_get:caffe.DummyDataParameter.data_filler)
+  return data_filler_.Get(index);
+}
+::caffe::FillerParameter* DummyDataParameter::mutable_data_filler(int index) {
+  // @@protoc_insertion_point(field_mutable:caffe.DummyDataParameter.data_filler)
+  return data_filler_.Mutable(index);
+}
+::caffe::FillerParameter* DummyDataParameter::add_data_filler() {
+  // @@protoc_insertion_point(field_add:caffe.DummyDataParameter.data_filler)
+  return data_filler_.Add();
+}
+::google::protobuf::RepeatedPtrField< ::caffe::FillerParameter >*
+DummyDataParameter::mutable_data_filler() {
+  // @@protoc_insertion_point(field_mutable_list:caffe.DummyDataParameter.data_filler)
+  return &data_filler_;
+}
+const ::google::protobuf::RepeatedPtrField< ::caffe::FillerParameter >&
+DummyDataParameter::data_filler() const {
+  // @@protoc_insertion_point(field_list:caffe.DummyDataParameter.data_filler)
+  return data_filler_;
+}
+
+// repeated .caffe.BlobShape shape = 6;
+int DummyDataParameter::shape_size() const {
+  return shape_.size();
+}
+void DummyDataParameter::clear_shape() {
+  shape_.Clear();
+}
+const ::caffe::BlobShape& DummyDataParameter::shape(int index) const {
+  // @@protoc_insertion_point(field_get:caffe.DummyDataParameter.shape)
+  return shape_.Get(index);
+}
+::caffe::BlobShape* DummyDataParameter::mutable_shape(int index) {
+  // @@protoc_insertion_point(field_mutable:caffe.DummyDataParameter.shape)
+  return shape_.Mutable(index);
+}
+::caffe::BlobShape* DummyDataParameter::add_shape() {
+  // @@protoc_insertion_point(field_add:caffe.DummyDataParameter.shape)
+  return shape_.Add();
+}
+::google::protobuf::RepeatedPtrField< ::caffe::BlobShape >*
+DummyDataParameter::mutable_shape() {
+  // @@protoc_insertion_point(field_mutable_list:caffe.DummyDataParameter.shape)
+  return &shape_;
+}
+const ::google::protobuf::RepeatedPtrField< ::caffe::BlobShape >&
+DummyDataParameter::shape() const {
+  // @@protoc_insertion_point(field_list:caffe.DummyDataParameter.shape)
+  return shape_;
+}
+
+// repeated uint32 num = 2;
+int DummyDataParameter::num_size() const {
+  return num_.size();
+}
+void DummyDataParameter::clear_num() {
+  num_.Clear();
+}
+::google::protobuf::uint32 DummyDataParameter::num(int index) const {
+  // @@protoc_insertion_point(field_get:caffe.DummyDataParameter.num)
+  return num_.Get(index);
+}
+void DummyDataParameter::set_num(int index, ::google::protobuf::uint32 value) {
+  num_.Set(index, value);
+  // @@protoc_insertion_point(field_set:caffe.DummyDataParameter.num)
+}
+void DummyDataParameter::add_num(::google::protobuf::uint32 value) {
+  num_.Add(value);
+  // @@protoc_insertion_point(field_add:caffe.DummyDataParameter.num)
+}
+const ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >&
+DummyDataParameter::num() const {
+  // @@protoc_insertion_point(field_list:caffe.DummyDataParameter.num)
+  return num_;
+}
+::google::protobuf::RepeatedField< ::google::protobuf::uint32 >*
+DummyDataParameter::mutable_num() {
+  // @@protoc_insertion_point(field_mutable_list:caffe.DummyDataParameter.num)
+  return &num_;
+}
+
+// repeated uint32 channels = 3;
+int DummyDataParameter::channels_size() const {
+  return channels_.size();
+}
+void DummyDataParameter::clear_channels() {
+  channels_.Clear();
+}
+::google::protobuf::uint32 DummyDataParameter::channels(int index) const {
+  // @@protoc_insertion_point(field_get:caffe.DummyDataParameter.channels)
+  return channels_.Get(index);
+}
+void DummyDataParameter::set_channels(int index, ::google::protobuf::uint32 value) {
+  channels_.Set(index, value);
+  // @@protoc_insertion_point(field_set:caffe.DummyDataParameter.channels)
+}
+void DummyDataParameter::add_channels(::google::protobuf::uint32 value) {
+  channels_.Add(value);
+  // @@protoc_insertion_point(field_add:caffe.DummyDataParameter.channels)
+}
+const ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >&
+DummyDataParameter::channels() const {
+  // @@protoc_insertion_point(field_list:caffe.DummyDataParameter.channels)
+  return channels_;
+}
+::google::protobuf::RepeatedField< ::google::protobuf::uint32 >*
+DummyDataParameter::mutable_channels() {
+  // @@protoc_insertion_point(field_mutable_list:caffe.DummyDataParameter.channels)
+  return &channels_;
+}
+
+// repeated uint32 height = 4;
+int DummyDataParameter::height_size() const {
+  return height_.size();
+}
+void DummyDataParameter::clear_height() {
+  height_.Clear();
+}
+::google::protobuf::uint32 DummyDataParameter::height(int index) const {
+  // @@protoc_insertion_point(field_get:caffe.DummyDataParameter.height)
+  return height_.Get(index);
+}
+void DummyDataParameter::set_height(int index, ::google::protobuf::uint32 value) {
+  height_.Set(index, value);
+  // @@protoc_insertion_point(field_set:caffe.DummyDataParameter.height)
+}
+void DummyDataParameter::add_height(::google::protobuf::uint32 value) {
+  height_.Add(value);
+  // @@protoc_insertion_point(field_add:caffe.DummyDataParameter.height)
+}
+const ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >&
+DummyDataParameter::height() const {
+  // @@protoc_insertion_point(field_list:caffe.DummyDataParameter.height)
+  return height_;
+}
+::google::protobuf::RepeatedField< ::google::protobuf::uint32 >*
+DummyDataParameter::mutable_height() {
+  // @@protoc_insertion_point(field_mutable_list:caffe.DummyDataParameter.height)
+  return &height_;
+}
+
+// repeated uint32 width = 5;
+int DummyDataParameter::width_size() const {
+  return width_.size();
+}
+void DummyDataParameter::clear_width() {
+  width_.Clear();
+}
+::google::protobuf::uint32 DummyDataParameter::width(int index) const {
+  // @@protoc_insertion_point(field_get:caffe.DummyDataParameter.width)
+  return width_.Get(index);
+}
+void DummyDataParameter::set_width(int index, ::google::protobuf::uint32 value) {
+  width_.Set(index, value);
+  // @@protoc_insertion_point(field_set:caffe.DummyDataParameter.width)
+}
+void DummyDataParameter::add_width(::google::protobuf::uint32 value) {
+  width_.Add(value);
+  // @@protoc_insertion_point(field_add:caffe.DummyDataParameter.width)
+}
+const ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >&
+DummyDataParameter::width() const {
+  // @@protoc_insertion_point(field_list:caffe.DummyDataParameter.width)
+  return width_;
+}
+::google::protobuf::RepeatedField< ::google::protobuf::uint32 >*
+DummyDataParameter::mutable_width() {
+  // @@protoc_insertion_point(field_mutable_list:caffe.DummyDataParameter.width)
+  return &width_;
+}
+
+inline const DummyDataParameter* DummyDataParameter::internal_default_instance() {
+  return &DummyDataParameter_default_instance_.get();
+}
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
+
+// ===================================================================
+
+const ::google::protobuf::EnumDescriptor* EltwiseParameter_EltwiseOp_descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return EltwiseParameter_EltwiseOp_descriptor_;
+}
+bool EltwiseParameter_EltwiseOp_IsValid(int value) {
+  switch (value) {
+    case 0:
+    case 1:
+    case 2:
+      return true;
+    default:
+      return false;
+  }
+}
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const EltwiseParameter_EltwiseOp EltwiseParameter::PROD;
+const EltwiseParameter_EltwiseOp EltwiseParameter::SUM;
+const EltwiseParameter_EltwiseOp EltwiseParameter::MAX;
+const EltwiseParameter_EltwiseOp EltwiseParameter::EltwiseOp_MIN;
+const EltwiseParameter_EltwiseOp EltwiseParameter::EltwiseOp_MAX;
+const int EltwiseParameter::EltwiseOp_ARRAYSIZE;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const int EltwiseParameter::kOperationFieldNumber;
+const int EltwiseParameter::kCoeffFieldNumber;
+const int EltwiseParameter::kStableProdGradFieldNumber;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+
+EltwiseParameter::EltwiseParameter()
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+  if (this != internal_default_instance()) protobuf_InitDefaults_caffe_2eproto();
+  SharedCtor();
+  // @@protoc_insertion_point(constructor:caffe.EltwiseParameter)
+}
+
+void EltwiseParameter::InitAsDefaultInstance() {
+}
+
+EltwiseParameter::EltwiseParameter(const EltwiseParameter& from)
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
+  SharedCtor();
+  UnsafeMergeFrom(from);
+  // @@protoc_insertion_point(copy_constructor:caffe.EltwiseParameter)
+}
+
+void EltwiseParameter::SharedCtor() {
+  _cached_size_ = 0;
+  operation_ = 1;
+  stable_prod_grad_ = true;
+}
+
+EltwiseParameter::~EltwiseParameter() {
+  // @@protoc_insertion_point(destructor:caffe.EltwiseParameter)
+  SharedDtor();
+}
+
+void EltwiseParameter::SharedDtor() {
+}
+
+void EltwiseParameter::SetCachedSize(int size) const {
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* EltwiseParameter::descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return EltwiseParameter_descriptor_;
+}
+
+const EltwiseParameter& EltwiseParameter::default_instance() {
+  protobuf_InitDefaults_caffe_2eproto();
+  return *internal_default_instance();
+}
+
+::google::protobuf::internal::ExplicitlyConstructed<EltwiseParameter> EltwiseParameter_default_instance_;
+
+EltwiseParameter* EltwiseParameter::New(::google::protobuf::Arena* arena) const {
+  EltwiseParameter* n = new EltwiseParameter;
+  if (arena != NULL) {
+    arena->Own(n);
+  }
+  return n;
+}
+
+void EltwiseParameter::Clear() {
+// @@protoc_insertion_point(message_clear_start:caffe.EltwiseParameter)
+  if (_has_bits_[0 / 32] & 5u) {
+    operation_ = 1;
+    stable_prod_grad_ = true;
+  }
+  coeff_.Clear();
+  _has_bits_.Clear();
+  if (_internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->Clear();
+  }
+}
+
+bool EltwiseParameter::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
+  ::google::protobuf::uint32 tag;
+  // @@protoc_insertion_point(parse_start:caffe.EltwiseParameter)
+  for (;;) {
+    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+    tag = p.first;
+    if (!p.second) goto handle_unusual;
+    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+      // optional .caffe.EltwiseParameter.EltwiseOp operation = 1 [default = SUM];
+      case 1: {
+        if (tag == 8) {
+          int value;
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>(
+                 input, &value)));
+          if (::caffe::EltwiseParameter_EltwiseOp_IsValid(value)) {
+            set_operation(static_cast< ::caffe::EltwiseParameter_EltwiseOp >(value));
+          } else {
+            mutable_unknown_fields()->AddVarint(1, value);
+          }
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(21)) goto parse_coeff;
+        break;
+      }
+
+      // repeated float coeff = 2;
+      case 2: {
+        if (tag == 21) {
+         parse_coeff:
+          DO_((::google::protobuf::internal::WireFormatLite::ReadRepeatedPrimitive<
+                   float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
+                 1, 21, input, this->mutable_coeff())));
+        } else if (tag == 18) {
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPackedPrimitiveNoInline<
+                   float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
+                 input, this->mutable_coeff())));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(21)) goto parse_coeff;
+        if (input->ExpectTag(24)) goto parse_stable_prod_grad;
+        break;
+      }
+
+      // optional bool stable_prod_grad = 3 [default = true];
+      case 3: {
+        if (tag == 24) {
+         parse_stable_prod_grad:
+          set_has_stable_prod_grad();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>(
+                 input, &stable_prod_grad_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectAtEnd()) goto success;
+        break;
+      }
+
+      default: {
+      handle_unusual:
+        if (tag == 0 ||
+            ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+          goto success;
+        }
+        DO_(::google::protobuf::internal::WireFormat::SkipField(
+              input, tag, mutable_unknown_fields()));
+        break;
+      }
+    }
+  }
+success:
+  // @@protoc_insertion_point(parse_success:caffe.EltwiseParameter)
+  return true;
+failure:
+  // @@protoc_insertion_point(parse_failure:caffe.EltwiseParameter)
+  return false;
+#undef DO_
+}
+
+void EltwiseParameter::SerializeWithCachedSizes(
+    ::google::protobuf::io::CodedOutputStream* output) const {
+  // @@protoc_insertion_point(serialize_start:caffe.EltwiseParameter)
+  // optional .caffe.EltwiseParameter.EltwiseOp operation = 1 [default = SUM];
+  if (has_operation()) {
+    ::google::protobuf::internal::WireFormatLite::WriteEnum(
+      1, this->operation(), output);
+  }
+
+  // repeated float coeff = 2;
+  for (int i = 0; i < this->coeff_size(); i++) {
+    ::google::protobuf::internal::WireFormatLite::WriteFloat(
+      2, this->coeff(i), output);
+  }
+
+  // optional bool stable_prod_grad = 3 [default = true];
+  if (has_stable_prod_grad()) {
+    ::google::protobuf::internal::WireFormatLite::WriteBool(3, this->stable_prod_grad(), output);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
+        unknown_fields(), output);
+  }
+  // @@protoc_insertion_point(serialize_end:caffe.EltwiseParameter)
+}
+
+::google::protobuf::uint8* EltwiseParameter::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
+  (void)deterministic; // Unused
+  // @@protoc_insertion_point(serialize_to_array_start:caffe.EltwiseParameter)
+  // optional .caffe.EltwiseParameter.EltwiseOp operation = 1 [default = SUM];
+  if (has_operation()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteEnumToArray(
+      1, this->operation(), target);
+  }
+
+  // repeated float coeff = 2;
+  for (int i = 0; i < this->coeff_size(); i++) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      WriteFloatToArray(2, this->coeff(i), target);
+  }
+
+  // optional bool stable_prod_grad = 3 [default = true];
+  if (has_stable_prod_grad()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(3, this->stable_prod_grad(), target);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
+        unknown_fields(), target);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:caffe.EltwiseParameter)
+  return target;
+}
+
+size_t EltwiseParameter::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:caffe.EltwiseParameter)
+  size_t total_size = 0;
+
+  if (_has_bits_[0 / 32] & 5u) {
+    // optional .caffe.EltwiseParameter.EltwiseOp operation = 1 [default = SUM];
+    if (has_operation()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::EnumSize(this->operation());
+    }
+
+    // optional bool stable_prod_grad = 3 [default = true];
+    if (has_stable_prod_grad()) {
+      total_size += 1 + 1;
+    }
+
+  }
+  // repeated float coeff = 2;
+  {
+    size_t data_size = 0;
+    unsigned int count = this->coeff_size();
+    data_size = 4UL * count;
+    total_size += 1 *
+                  ::google::protobuf::internal::FromIntSize(this->coeff_size());
+    total_size += data_size;
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    total_size +=
+      ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
+        unknown_fields());
+  }
+  int cached_size = ::google::protobuf::internal::ToCachedSize(total_size);
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = cached_size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+  return total_size;
+}
+
+void EltwiseParameter::MergeFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_merge_from_start:caffe.EltwiseParameter)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const EltwiseParameter* source =
+      ::google::protobuf::internal::DynamicCastToGenerated<const EltwiseParameter>(
+          &from);
+  if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:caffe.EltwiseParameter)
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:caffe.EltwiseParameter)
+    UnsafeMergeFrom(*source);
+  }
+}
+
+void EltwiseParameter::MergeFrom(const EltwiseParameter& from) {
+// @@protoc_insertion_point(class_specific_merge_from_start:caffe.EltwiseParameter)
+  if (GOOGLE_PREDICT_TRUE(&from != this)) {
+    UnsafeMergeFrom(from);
+  } else {
+    MergeFromFail(__LINE__);
+  }
+}
+
+void EltwiseParameter::UnsafeMergeFrom(const EltwiseParameter& from) {
+  GOOGLE_DCHECK(&from != this);
+  coeff_.UnsafeMergeFrom(from.coeff_);
+  if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+    if (from.has_operation()) {
+      set_operation(from.operation());
+    }
+    if (from.has_stable_prod_grad()) {
+      set_stable_prod_grad(from.stable_prod_grad());
+    }
+  }
+  if (from._internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::UnknownFieldSet::MergeToInternalMetdata(
+      from.unknown_fields(), &_internal_metadata_);
+  }
+}
+
+void EltwiseParameter::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:caffe.EltwiseParameter)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void EltwiseParameter::CopyFrom(const EltwiseParameter& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:caffe.EltwiseParameter)
+  if (&from == this) return;
+  Clear();
+  UnsafeMergeFrom(from);
+}
+
+bool EltwiseParameter::IsInitialized() const {
+
+  return true;
+}
+
+void EltwiseParameter::Swap(EltwiseParameter* other) {
+  if (other == this) return;
+  InternalSwap(other);
+}
+void EltwiseParameter::InternalSwap(EltwiseParameter* other) {
+  std::swap(operation_, other->operation_);
+  coeff_.UnsafeArenaSwap(&other->coeff_);
+  std::swap(stable_prod_grad_, other->stable_prod_grad_);
+  std::swap(_has_bits_[0], other->_has_bits_[0]);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
+}
+
+::google::protobuf::Metadata EltwiseParameter::GetMetadata() const {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::Metadata metadata;
+  metadata.descriptor = EltwiseParameter_descriptor_;
+  metadata.reflection = EltwiseParameter_reflection_;
+  return metadata;
+}
+
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// EltwiseParameter
+
+// optional .caffe.EltwiseParameter.EltwiseOp operation = 1 [default = SUM];
+bool EltwiseParameter::has_operation() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+void EltwiseParameter::set_has_operation() {
+  _has_bits_[0] |= 0x00000001u;
+}
+void EltwiseParameter::clear_has_operation() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+void EltwiseParameter::clear_operation() {
+  operation_ = 1;
+  clear_has_operation();
+}
+::caffe::EltwiseParameter_EltwiseOp EltwiseParameter::operation() const {
+  // @@protoc_insertion_point(field_get:caffe.EltwiseParameter.operation)
+  return static_cast< ::caffe::EltwiseParameter_EltwiseOp >(operation_);
+}
+void EltwiseParameter::set_operation(::caffe::EltwiseParameter_EltwiseOp value) {
+  assert(::caffe::EltwiseParameter_EltwiseOp_IsValid(value));
+  set_has_operation();
+  operation_ = value;
+  // @@protoc_insertion_point(field_set:caffe.EltwiseParameter.operation)
+}
+
+// repeated float coeff = 2;
+int EltwiseParameter::coeff_size() const {
+  return coeff_.size();
+}
+void EltwiseParameter::clear_coeff() {
+  coeff_.Clear();
+}
+float EltwiseParameter::coeff(int index) const {
+  // @@protoc_insertion_point(field_get:caffe.EltwiseParameter.coeff)
+  return coeff_.Get(index);
+}
+void EltwiseParameter::set_coeff(int index, float value) {
+  coeff_.Set(index, value);
+  // @@protoc_insertion_point(field_set:caffe.EltwiseParameter.coeff)
+}
+void EltwiseParameter::add_coeff(float value) {
+  coeff_.Add(value);
+  // @@protoc_insertion_point(field_add:caffe.EltwiseParameter.coeff)
+}
+const ::google::protobuf::RepeatedField< float >&
+EltwiseParameter::coeff() const {
+  // @@protoc_insertion_point(field_list:caffe.EltwiseParameter.coeff)
+  return coeff_;
+}
+::google::protobuf::RepeatedField< float >*
+EltwiseParameter::mutable_coeff() {
+  // @@protoc_insertion_point(field_mutable_list:caffe.EltwiseParameter.coeff)
+  return &coeff_;
+}
+
+// optional bool stable_prod_grad = 3 [default = true];
+bool EltwiseParameter::has_stable_prod_grad() const {
+  return (_has_bits_[0] & 0x00000004u) != 0;
+}
+void EltwiseParameter::set_has_stable_prod_grad() {
+  _has_bits_[0] |= 0x00000004u;
+}
+void EltwiseParameter::clear_has_stable_prod_grad() {
+  _has_bits_[0] &= ~0x00000004u;
+}
+void EltwiseParameter::clear_stable_prod_grad() {
+  stable_prod_grad_ = true;
+  clear_has_stable_prod_grad();
+}
+bool EltwiseParameter::stable_prod_grad() const {
+  // @@protoc_insertion_point(field_get:caffe.EltwiseParameter.stable_prod_grad)
+  return stable_prod_grad_;
+}
+void EltwiseParameter::set_stable_prod_grad(bool value) {
+  set_has_stable_prod_grad();
+  stable_prod_grad_ = value;
+  // @@protoc_insertion_point(field_set:caffe.EltwiseParameter.stable_prod_grad)
+}
+
+inline const EltwiseParameter* EltwiseParameter::internal_default_instance() {
+  return &EltwiseParameter_default_instance_.get();
+}
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
+
+// ===================================================================
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const int ExpParameter::kBaseFieldNumber;
+const int ExpParameter::kScaleFieldNumber;
+const int ExpParameter::kShiftFieldNumber;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+
+ExpParameter::ExpParameter()
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+  if (this != internal_default_instance()) protobuf_InitDefaults_caffe_2eproto();
+  SharedCtor();
+  // @@protoc_insertion_point(constructor:caffe.ExpParameter)
+}
+
+void ExpParameter::InitAsDefaultInstance() {
+}
+
+ExpParameter::ExpParameter(const ExpParameter& from)
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
+  SharedCtor();
+  UnsafeMergeFrom(from);
+  // @@protoc_insertion_point(copy_constructor:caffe.ExpParameter)
+}
+
+void ExpParameter::SharedCtor() {
+  _cached_size_ = 0;
+  shift_ = 0;
+  base_ = -1;
+  scale_ = 1;
+}
+
+ExpParameter::~ExpParameter() {
+  // @@protoc_insertion_point(destructor:caffe.ExpParameter)
+  SharedDtor();
+}
+
+void ExpParameter::SharedDtor() {
+}
+
+void ExpParameter::SetCachedSize(int size) const {
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* ExpParameter::descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return ExpParameter_descriptor_;
+}
+
+const ExpParameter& ExpParameter::default_instance() {
+  protobuf_InitDefaults_caffe_2eproto();
+  return *internal_default_instance();
+}
+
+::google::protobuf::internal::ExplicitlyConstructed<ExpParameter> ExpParameter_default_instance_;
+
+ExpParameter* ExpParameter::New(::google::protobuf::Arena* arena) const {
+  ExpParameter* n = new ExpParameter;
+  if (arena != NULL) {
+    arena->Own(n);
+  }
+  return n;
+}
+
+void ExpParameter::Clear() {
+// @@protoc_insertion_point(message_clear_start:caffe.ExpParameter)
+  if (_has_bits_[0 / 32] & 7u) {
+    base_ = -1;
+    scale_ = 1;
+    shift_ = 0;
+  }
+  _has_bits_.Clear();
+  if (_internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->Clear();
+  }
+}
+
+bool ExpParameter::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
+  ::google::protobuf::uint32 tag;
+  // @@protoc_insertion_point(parse_start:caffe.ExpParameter)
+  for (;;) {
+    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+    tag = p.first;
+    if (!p.second) goto handle_unusual;
+    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+      // optional float base = 1 [default = -1];
+      case 1: {
+        if (tag == 13) {
+          set_has_base();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
+                 input, &base_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(21)) goto parse_scale;
+        break;
+      }
+
+      // optional float scale = 2 [default = 1];
+      case 2: {
+        if (tag == 21) {
+         parse_scale:
+          set_has_scale();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
+                 input, &scale_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(29)) goto parse_shift;
+        break;
+      }
+
+      // optional float shift = 3 [default = 0];
+      case 3: {
+        if (tag == 29) {
+         parse_shift:
+          set_has_shift();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
+                 input, &shift_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectAtEnd()) goto success;
+        break;
+      }
+
+      default: {
+      handle_unusual:
+        if (tag == 0 ||
+            ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+          goto success;
+        }
+        DO_(::google::protobuf::internal::WireFormat::SkipField(
+              input, tag, mutable_unknown_fields()));
+        break;
+      }
+    }
+  }
+success:
+  // @@protoc_insertion_point(parse_success:caffe.ExpParameter)
+  return true;
+failure:
+  // @@protoc_insertion_point(parse_failure:caffe.ExpParameter)
+  return false;
+#undef DO_
+}
+
+void ExpParameter::SerializeWithCachedSizes(
+    ::google::protobuf::io::CodedOutputStream* output) const {
+  // @@protoc_insertion_point(serialize_start:caffe.ExpParameter)
+  // optional float base = 1 [default = -1];
+  if (has_base()) {
+    ::google::protobuf::internal::WireFormatLite::WriteFloat(1, this->base(), output);
+  }
+
+  // optional float scale = 2 [default = 1];
+  if (has_scale()) {
+    ::google::protobuf::internal::WireFormatLite::WriteFloat(2, this->scale(), output);
+  }
+
+  // optional float shift = 3 [default = 0];
+  if (has_shift()) {
+    ::google::protobuf::internal::WireFormatLite::WriteFloat(3, this->shift(), output);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
+        unknown_fields(), output);
+  }
+  // @@protoc_insertion_point(serialize_end:caffe.ExpParameter)
+}
+
+::google::protobuf::uint8* ExpParameter::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
+  (void)deterministic; // Unused
+  // @@protoc_insertion_point(serialize_to_array_start:caffe.ExpParameter)
+  // optional float base = 1 [default = -1];
+  if (has_base()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteFloatToArray(1, this->base(), target);
+  }
+
+  // optional float scale = 2 [default = 1];
+  if (has_scale()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteFloatToArray(2, this->scale(), target);
+  }
+
+  // optional float shift = 3 [default = 0];
+  if (has_shift()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteFloatToArray(3, this->shift(), target);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
+        unknown_fields(), target);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:caffe.ExpParameter)
+  return target;
+}
+
+size_t ExpParameter::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:caffe.ExpParameter)
+  size_t total_size = 0;
+
+  if (_has_bits_[0 / 32] & 7u) {
+    // optional float base = 1 [default = -1];
+    if (has_base()) {
+      total_size += 1 + 4;
+    }
+
+    // optional float scale = 2 [default = 1];
+    if (has_scale()) {
+      total_size += 1 + 4;
+    }
+
+    // optional float shift = 3 [default = 0];
+    if (has_shift()) {
+      total_size += 1 + 4;
+    }
+
+  }
+  if (_internal_metadata_.have_unknown_fields()) {
+    total_size +=
+      ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
+        unknown_fields());
+  }
+  int cached_size = ::google::protobuf::internal::ToCachedSize(total_size);
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = cached_size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+  return total_size;
+}
+
+void ExpParameter::MergeFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_merge_from_start:caffe.ExpParameter)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const ExpParameter* source =
+      ::google::protobuf::internal::DynamicCastToGenerated<const ExpParameter>(
+          &from);
+  if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:caffe.ExpParameter)
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:caffe.ExpParameter)
+    UnsafeMergeFrom(*source);
+  }
+}
+
+void ExpParameter::MergeFrom(const ExpParameter& from) {
+// @@protoc_insertion_point(class_specific_merge_from_start:caffe.ExpParameter)
+  if (GOOGLE_PREDICT_TRUE(&from != this)) {
+    UnsafeMergeFrom(from);
+  } else {
+    MergeFromFail(__LINE__);
+  }
+}
+
+void ExpParameter::UnsafeMergeFrom(const ExpParameter& from) {
+  GOOGLE_DCHECK(&from != this);
+  if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+    if (from.has_base()) {
+      set_base(from.base());
+    }
+    if (from.has_scale()) {
+      set_scale(from.scale());
+    }
+    if (from.has_shift()) {
+      set_shift(from.shift());
+    }
+  }
+  if (from._internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::UnknownFieldSet::MergeToInternalMetdata(
+      from.unknown_fields(), &_internal_metadata_);
+  }
+}
+
+void ExpParameter::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:caffe.ExpParameter)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void ExpParameter::CopyFrom(const ExpParameter& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:caffe.ExpParameter)
+  if (&from == this) return;
+  Clear();
+  UnsafeMergeFrom(from);
+}
+
+bool ExpParameter::IsInitialized() const {
+
+  return true;
+}
+
+void ExpParameter::Swap(ExpParameter* other) {
+  if (other == this) return;
+  InternalSwap(other);
+}
+void ExpParameter::InternalSwap(ExpParameter* other) {
+  std::swap(base_, other->base_);
+  std::swap(scale_, other->scale_);
+  std::swap(shift_, other->shift_);
+  std::swap(_has_bits_[0], other->_has_bits_[0]);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
+}
+
+::google::protobuf::Metadata ExpParameter::GetMetadata() const {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::Metadata metadata;
+  metadata.descriptor = ExpParameter_descriptor_;
+  metadata.reflection = ExpParameter_reflection_;
+  return metadata;
+}
+
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// ExpParameter
+
+// optional float base = 1 [default = -1];
+bool ExpParameter::has_base() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+void ExpParameter::set_has_base() {
+  _has_bits_[0] |= 0x00000001u;
+}
+void ExpParameter::clear_has_base() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+void ExpParameter::clear_base() {
+  base_ = -1;
+  clear_has_base();
+}
+float ExpParameter::base() const {
+  // @@protoc_insertion_point(field_get:caffe.ExpParameter.base)
+  return base_;
+}
+void ExpParameter::set_base(float value) {
+  set_has_base();
+  base_ = value;
+  // @@protoc_insertion_point(field_set:caffe.ExpParameter.base)
+}
+
+// optional float scale = 2 [default = 1];
+bool ExpParameter::has_scale() const {
+  return (_has_bits_[0] & 0x00000002u) != 0;
+}
+void ExpParameter::set_has_scale() {
+  _has_bits_[0] |= 0x00000002u;
+}
+void ExpParameter::clear_has_scale() {
+  _has_bits_[0] &= ~0x00000002u;
+}
+void ExpParameter::clear_scale() {
+  scale_ = 1;
+  clear_has_scale();
+}
+float ExpParameter::scale() const {
+  // @@protoc_insertion_point(field_get:caffe.ExpParameter.scale)
+  return scale_;
+}
+void ExpParameter::set_scale(float value) {
+  set_has_scale();
+  scale_ = value;
+  // @@protoc_insertion_point(field_set:caffe.ExpParameter.scale)
+}
+
+// optional float shift = 3 [default = 0];
+bool ExpParameter::has_shift() const {
+  return (_has_bits_[0] & 0x00000004u) != 0;
+}
+void ExpParameter::set_has_shift() {
+  _has_bits_[0] |= 0x00000004u;
+}
+void ExpParameter::clear_has_shift() {
+  _has_bits_[0] &= ~0x00000004u;
+}
+void ExpParameter::clear_shift() {
+  shift_ = 0;
+  clear_has_shift();
+}
+float ExpParameter::shift() const {
+  // @@protoc_insertion_point(field_get:caffe.ExpParameter.shift)
+  return shift_;
+}
+void ExpParameter::set_shift(float value) {
+  set_has_shift();
+  shift_ = value;
+  // @@protoc_insertion_point(field_set:caffe.ExpParameter.shift)
+}
+
+inline const ExpParameter* ExpParameter::internal_default_instance() {
+  return &ExpParameter_default_instance_.get();
+}
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
+
+// ===================================================================
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const int FlattenParameter::kAxisFieldNumber;
+const int FlattenParameter::kEndAxisFieldNumber;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+
+FlattenParameter::FlattenParameter()
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+  if (this != internal_default_instance()) protobuf_InitDefaults_caffe_2eproto();
+  SharedCtor();
+  // @@protoc_insertion_point(constructor:caffe.FlattenParameter)
+}
+
+void FlattenParameter::InitAsDefaultInstance() {
+}
+
+FlattenParameter::FlattenParameter(const FlattenParameter& from)
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
+  SharedCtor();
+  UnsafeMergeFrom(from);
+  // @@protoc_insertion_point(copy_constructor:caffe.FlattenParameter)
+}
+
+void FlattenParameter::SharedCtor() {
+  _cached_size_ = 0;
+  axis_ = 1;
+  end_axis_ = -1;
+}
+
+FlattenParameter::~FlattenParameter() {
+  // @@protoc_insertion_point(destructor:caffe.FlattenParameter)
+  SharedDtor();
+}
+
+void FlattenParameter::SharedDtor() {
+}
+
+void FlattenParameter::SetCachedSize(int size) const {
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* FlattenParameter::descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return FlattenParameter_descriptor_;
+}
+
+const FlattenParameter& FlattenParameter::default_instance() {
+  protobuf_InitDefaults_caffe_2eproto();
+  return *internal_default_instance();
+}
+
+::google::protobuf::internal::ExplicitlyConstructed<FlattenParameter> FlattenParameter_default_instance_;
+
+FlattenParameter* FlattenParameter::New(::google::protobuf::Arena* arena) const {
+  FlattenParameter* n = new FlattenParameter;
+  if (arena != NULL) {
+    arena->Own(n);
+  }
+  return n;
+}
+
+void FlattenParameter::Clear() {
+// @@protoc_insertion_point(message_clear_start:caffe.FlattenParameter)
+  if (_has_bits_[0 / 32] & 3u) {
+    axis_ = 1;
+    end_axis_ = -1;
+  }
+  _has_bits_.Clear();
+  if (_internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->Clear();
+  }
+}
+
+bool FlattenParameter::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
+  ::google::protobuf::uint32 tag;
+  // @@protoc_insertion_point(parse_start:caffe.FlattenParameter)
+  for (;;) {
+    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+    tag = p.first;
+    if (!p.second) goto handle_unusual;
+    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+      // optional int32 axis = 1 [default = 1];
+      case 1: {
+        if (tag == 8) {
+          set_has_axis();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
+                 input, &axis_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(16)) goto parse_end_axis;
+        break;
+      }
+
+      // optional int32 end_axis = 2 [default = -1];
+      case 2: {
+        if (tag == 16) {
+         parse_end_axis:
+          set_has_end_axis();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
+                 input, &end_axis_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectAtEnd()) goto success;
+        break;
+      }
+
+      default: {
+      handle_unusual:
+        if (tag == 0 ||
+            ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+          goto success;
+        }
+        DO_(::google::protobuf::internal::WireFormat::SkipField(
+              input, tag, mutable_unknown_fields()));
+        break;
+      }
+    }
+  }
+success:
+  // @@protoc_insertion_point(parse_success:caffe.FlattenParameter)
+  return true;
+failure:
+  // @@protoc_insertion_point(parse_failure:caffe.FlattenParameter)
+  return false;
+#undef DO_
+}
+
+void FlattenParameter::SerializeWithCachedSizes(
+    ::google::protobuf::io::CodedOutputStream* output) const {
+  // @@protoc_insertion_point(serialize_start:caffe.FlattenParameter)
+  // optional int32 axis = 1 [default = 1];
+  if (has_axis()) {
+    ::google::protobuf::internal::WireFormatLite::WriteInt32(1, this->axis(), output);
+  }
+
+  // optional int32 end_axis = 2 [default = -1];
+  if (has_end_axis()) {
+    ::google::protobuf::internal::WireFormatLite::WriteInt32(2, this->end_axis(), output);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
+        unknown_fields(), output);
+  }
+  // @@protoc_insertion_point(serialize_end:caffe.FlattenParameter)
+}
+
+::google::protobuf::uint8* FlattenParameter::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
+  (void)deterministic; // Unused
+  // @@protoc_insertion_point(serialize_to_array_start:caffe.FlattenParameter)
+  // optional int32 axis = 1 [default = 1];
+  if (has_axis()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteInt32ToArray(1, this->axis(), target);
+  }
+
+  // optional int32 end_axis = 2 [default = -1];
+  if (has_end_axis()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteInt32ToArray(2, this->end_axis(), target);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
+        unknown_fields(), target);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:caffe.FlattenParameter)
+  return target;
+}
+
+size_t FlattenParameter::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:caffe.FlattenParameter)
+  size_t total_size = 0;
+
+  if (_has_bits_[0 / 32] & 3u) {
+    // optional int32 axis = 1 [default = 1];
+    if (has_axis()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::Int32Size(
+          this->axis());
+    }
+
+    // optional int32 end_axis = 2 [default = -1];
+    if (has_end_axis()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::Int32Size(
+          this->end_axis());
+    }
+
+  }
+  if (_internal_metadata_.have_unknown_fields()) {
+    total_size +=
+      ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
+        unknown_fields());
+  }
+  int cached_size = ::google::protobuf::internal::ToCachedSize(total_size);
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = cached_size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+  return total_size;
+}
+
+void FlattenParameter::MergeFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_merge_from_start:caffe.FlattenParameter)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const FlattenParameter* source =
+      ::google::protobuf::internal::DynamicCastToGenerated<const FlattenParameter>(
+          &from);
+  if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:caffe.FlattenParameter)
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:caffe.FlattenParameter)
+    UnsafeMergeFrom(*source);
+  }
+}
+
+void FlattenParameter::MergeFrom(const FlattenParameter& from) {
+// @@protoc_insertion_point(class_specific_merge_from_start:caffe.FlattenParameter)
+  if (GOOGLE_PREDICT_TRUE(&from != this)) {
+    UnsafeMergeFrom(from);
+  } else {
+    MergeFromFail(__LINE__);
+  }
+}
+
+void FlattenParameter::UnsafeMergeFrom(const FlattenParameter& from) {
+  GOOGLE_DCHECK(&from != this);
+  if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+    if (from.has_axis()) {
+      set_axis(from.axis());
+    }
+    if (from.has_end_axis()) {
+      set_end_axis(from.end_axis());
+    }
+  }
+  if (from._internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::UnknownFieldSet::MergeToInternalMetdata(
+      from.unknown_fields(), &_internal_metadata_);
+  }
+}
+
+void FlattenParameter::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:caffe.FlattenParameter)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void FlattenParameter::CopyFrom(const FlattenParameter& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:caffe.FlattenParameter)
+  if (&from == this) return;
+  Clear();
+  UnsafeMergeFrom(from);
+}
+
+bool FlattenParameter::IsInitialized() const {
+
+  return true;
+}
+
+void FlattenParameter::Swap(FlattenParameter* other) {
+  if (other == this) return;
+  InternalSwap(other);
+}
+void FlattenParameter::InternalSwap(FlattenParameter* other) {
+  std::swap(axis_, other->axis_);
+  std::swap(end_axis_, other->end_axis_);
+  std::swap(_has_bits_[0], other->_has_bits_[0]);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
+}
+
+::google::protobuf::Metadata FlattenParameter::GetMetadata() const {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::Metadata metadata;
+  metadata.descriptor = FlattenParameter_descriptor_;
+  metadata.reflection = FlattenParameter_reflection_;
+  return metadata;
+}
+
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// FlattenParameter
+
+// optional int32 axis = 1 [default = 1];
+bool FlattenParameter::has_axis() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+void FlattenParameter::set_has_axis() {
+  _has_bits_[0] |= 0x00000001u;
+}
+void FlattenParameter::clear_has_axis() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+void FlattenParameter::clear_axis() {
+  axis_ = 1;
+  clear_has_axis();
+}
+::google::protobuf::int32 FlattenParameter::axis() const {
+  // @@protoc_insertion_point(field_get:caffe.FlattenParameter.axis)
+  return axis_;
+}
+void FlattenParameter::set_axis(::google::protobuf::int32 value) {
+  set_has_axis();
+  axis_ = value;
+  // @@protoc_insertion_point(field_set:caffe.FlattenParameter.axis)
+}
+
+// optional int32 end_axis = 2 [default = -1];
+bool FlattenParameter::has_end_axis() const {
+  return (_has_bits_[0] & 0x00000002u) != 0;
+}
+void FlattenParameter::set_has_end_axis() {
+  _has_bits_[0] |= 0x00000002u;
+}
+void FlattenParameter::clear_has_end_axis() {
+  _has_bits_[0] &= ~0x00000002u;
+}
+void FlattenParameter::clear_end_axis() {
+  end_axis_ = -1;
+  clear_has_end_axis();
+}
+::google::protobuf::int32 FlattenParameter::end_axis() const {
+  // @@protoc_insertion_point(field_get:caffe.FlattenParameter.end_axis)
+  return end_axis_;
+}
+void FlattenParameter::set_end_axis(::google::protobuf::int32 value) {
+  set_has_end_axis();
+  end_axis_ = value;
+  // @@protoc_insertion_point(field_set:caffe.FlattenParameter.end_axis)
+}
+
+inline const FlattenParameter* FlattenParameter::internal_default_instance() {
+  return &FlattenParameter_default_instance_.get();
+}
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
+
+// ===================================================================
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const int HDF5DataParameter::kSourceFieldNumber;
+const int HDF5DataParameter::kBatchSizeFieldNumber;
+const int HDF5DataParameter::kShuffleFieldNumber;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+
+HDF5DataParameter::HDF5DataParameter()
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+  if (this != internal_default_instance()) protobuf_InitDefaults_caffe_2eproto();
+  SharedCtor();
+  // @@protoc_insertion_point(constructor:caffe.HDF5DataParameter)
+}
+
+void HDF5DataParameter::InitAsDefaultInstance() {
+}
+
+HDF5DataParameter::HDF5DataParameter(const HDF5DataParameter& from)
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
+  SharedCtor();
+  UnsafeMergeFrom(from);
+  // @@protoc_insertion_point(copy_constructor:caffe.HDF5DataParameter)
+}
+
+void HDF5DataParameter::SharedCtor() {
+  _cached_size_ = 0;
+  source_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  ::memset(&batch_size_, 0, reinterpret_cast<char*>(&shuffle_) -
+    reinterpret_cast<char*>(&batch_size_) + sizeof(shuffle_));
+}
+
+HDF5DataParameter::~HDF5DataParameter() {
+  // @@protoc_insertion_point(destructor:caffe.HDF5DataParameter)
+  SharedDtor();
+}
+
+void HDF5DataParameter::SharedDtor() {
+  source_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+
+void HDF5DataParameter::SetCachedSize(int size) const {
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* HDF5DataParameter::descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return HDF5DataParameter_descriptor_;
+}
+
+const HDF5DataParameter& HDF5DataParameter::default_instance() {
+  protobuf_InitDefaults_caffe_2eproto();
+  return *internal_default_instance();
+}
+
+::google::protobuf::internal::ExplicitlyConstructed<HDF5DataParameter> HDF5DataParameter_default_instance_;
+
+HDF5DataParameter* HDF5DataParameter::New(::google::protobuf::Arena* arena) const {
+  HDF5DataParameter* n = new HDF5DataParameter;
+  if (arena != NULL) {
+    arena->Own(n);
+  }
+  return n;
+}
+
+void HDF5DataParameter::Clear() {
+// @@protoc_insertion_point(message_clear_start:caffe.HDF5DataParameter)
+#if defined(__clang__)
+#define ZR_HELPER_(f) \
+  _Pragma("clang diagnostic push") \
+  _Pragma("clang diagnostic ignored \"-Winvalid-offsetof\"") \
+  __builtin_offsetof(HDF5DataParameter, f) \
+  _Pragma("clang diagnostic pop")
+#else
+#define ZR_HELPER_(f) reinterpret_cast<char*>(\
+  &reinterpret_cast<HDF5DataParameter*>(16)->f)
+#endif
+
+#define ZR_(first, last) do {\
+  ::memset(&(first), 0,\
+           ZR_HELPER_(last) - ZR_HELPER_(first) + sizeof(last));\
+} while (0)
+
+  if (_has_bits_[0 / 32] & 7u) {
+    ZR_(batch_size_, shuffle_);
+    if (has_source()) {
+      source_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+    }
+  }
+
+#undef ZR_HELPER_
+#undef ZR_
+
+  _has_bits_.Clear();
+  if (_internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->Clear();
+  }
+}
+
+bool HDF5DataParameter::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
+  ::google::protobuf::uint32 tag;
+  // @@protoc_insertion_point(parse_start:caffe.HDF5DataParameter)
+  for (;;) {
+    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+    tag = p.first;
+    if (!p.second) goto handle_unusual;
+    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+      // optional string source = 1;
+      case 1: {
+        if (tag == 10) {
+          DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+                input, this->mutable_source()));
+          ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+            this->source().data(), this->source().length(),
+            ::google::protobuf::internal::WireFormat::PARSE,
+            "caffe.HDF5DataParameter.source");
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(16)) goto parse_batch_size;
+        break;
+      }
+
+      // optional uint32 batch_size = 2;
+      case 2: {
+        if (tag == 16) {
+         parse_batch_size:
+          set_has_batch_size();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>(
+                 input, &batch_size_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(24)) goto parse_shuffle;
+        break;
+      }
+
+      // optional bool shuffle = 3 [default = false];
+      case 3: {
+        if (tag == 24) {
+         parse_shuffle:
+          set_has_shuffle();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>(
+                 input, &shuffle_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectAtEnd()) goto success;
+        break;
+      }
+
+      default: {
+      handle_unusual:
+        if (tag == 0 ||
+            ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+          goto success;
+        }
+        DO_(::google::protobuf::internal::WireFormat::SkipField(
+              input, tag, mutable_unknown_fields()));
+        break;
+      }
+    }
+  }
+success:
+  // @@protoc_insertion_point(parse_success:caffe.HDF5DataParameter)
+  return true;
+failure:
+  // @@protoc_insertion_point(parse_failure:caffe.HDF5DataParameter)
+  return false;
+#undef DO_
+}
+
+void HDF5DataParameter::SerializeWithCachedSizes(
+    ::google::protobuf::io::CodedOutputStream* output) const {
+  // @@protoc_insertion_point(serialize_start:caffe.HDF5DataParameter)
+  // optional string source = 1;
+  if (has_source()) {
+    ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->source().data(), this->source().length(),
+      ::google::protobuf::internal::WireFormat::SERIALIZE,
+      "caffe.HDF5DataParameter.source");
+    ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
+      1, this->source(), output);
+  }
+
+  // optional uint32 batch_size = 2;
+  if (has_batch_size()) {
+    ::google::protobuf::internal::WireFormatLite::WriteUInt32(2, this->batch_size(), output);
+  }
+
+  // optional bool shuffle = 3 [default = false];
+  if (has_shuffle()) {
+    ::google::protobuf::internal::WireFormatLite::WriteBool(3, this->shuffle(), output);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
+        unknown_fields(), output);
+  }
+  // @@protoc_insertion_point(serialize_end:caffe.HDF5DataParameter)
+}
+
+::google::protobuf::uint8* HDF5DataParameter::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
+  (void)deterministic; // Unused
+  // @@protoc_insertion_point(serialize_to_array_start:caffe.HDF5DataParameter)
+  // optional string source = 1;
+  if (has_source()) {
+    ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->source().data(), this->source().length(),
+      ::google::protobuf::internal::WireFormat::SERIALIZE,
+      "caffe.HDF5DataParameter.source");
+    target =
+      ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
+        1, this->source(), target);
+  }
+
+  // optional uint32 batch_size = 2;
+  if (has_batch_size()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteUInt32ToArray(2, this->batch_size(), target);
+  }
+
+  // optional bool shuffle = 3 [default = false];
+  if (has_shuffle()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(3, this->shuffle(), target);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
+        unknown_fields(), target);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:caffe.HDF5DataParameter)
+  return target;
+}
+
+size_t HDF5DataParameter::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:caffe.HDF5DataParameter)
+  size_t total_size = 0;
+
+  if (_has_bits_[0 / 32] & 7u) {
+    // optional string source = 1;
+    if (has_source()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::StringSize(
+          this->source());
+    }
+
+    // optional uint32 batch_size = 2;
+    if (has_batch_size()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::UInt32Size(
+          this->batch_size());
+    }
+
+    // optional bool shuffle = 3 [default = false];
+    if (has_shuffle()) {
+      total_size += 1 + 1;
+    }
+
+  }
+  if (_internal_metadata_.have_unknown_fields()) {
+    total_size +=
+      ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
+        unknown_fields());
+  }
+  int cached_size = ::google::protobuf::internal::ToCachedSize(total_size);
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = cached_size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+  return total_size;
+}
+
+void HDF5DataParameter::MergeFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_merge_from_start:caffe.HDF5DataParameter)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const HDF5DataParameter* source =
+      ::google::protobuf::internal::DynamicCastToGenerated<const HDF5DataParameter>(
+          &from);
+  if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:caffe.HDF5DataParameter)
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:caffe.HDF5DataParameter)
+    UnsafeMergeFrom(*source);
+  }
+}
+
+void HDF5DataParameter::MergeFrom(const HDF5DataParameter& from) {
+// @@protoc_insertion_point(class_specific_merge_from_start:caffe.HDF5DataParameter)
+  if (GOOGLE_PREDICT_TRUE(&from != this)) {
+    UnsafeMergeFrom(from);
+  } else {
+    MergeFromFail(__LINE__);
+  }
+}
+
+void HDF5DataParameter::UnsafeMergeFrom(const HDF5DataParameter& from) {
+  GOOGLE_DCHECK(&from != this);
+  if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+    if (from.has_source()) {
+      set_has_source();
+      source_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.source_);
+    }
+    if (from.has_batch_size()) {
+      set_batch_size(from.batch_size());
+    }
+    if (from.has_shuffle()) {
+      set_shuffle(from.shuffle());
+    }
+  }
+  if (from._internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::UnknownFieldSet::MergeToInternalMetdata(
+      from.unknown_fields(), &_internal_metadata_);
+  }
+}
+
+void HDF5DataParameter::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:caffe.HDF5DataParameter)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void HDF5DataParameter::CopyFrom(const HDF5DataParameter& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:caffe.HDF5DataParameter)
+  if (&from == this) return;
+  Clear();
+  UnsafeMergeFrom(from);
+}
+
+bool HDF5DataParameter::IsInitialized() const {
+
+  return true;
+}
+
+void HDF5DataParameter::Swap(HDF5DataParameter* other) {
+  if (other == this) return;
+  InternalSwap(other);
+}
+void HDF5DataParameter::InternalSwap(HDF5DataParameter* other) {
+  source_.Swap(&other->source_);
+  std::swap(batch_size_, other->batch_size_);
+  std::swap(shuffle_, other->shuffle_);
+  std::swap(_has_bits_[0], other->_has_bits_[0]);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
+}
+
+::google::protobuf::Metadata HDF5DataParameter::GetMetadata() const {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::Metadata metadata;
+  metadata.descriptor = HDF5DataParameter_descriptor_;
+  metadata.reflection = HDF5DataParameter_reflection_;
+  return metadata;
+}
+
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// HDF5DataParameter
+
+// optional string source = 1;
+bool HDF5DataParameter::has_source() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+void HDF5DataParameter::set_has_source() {
+  _has_bits_[0] |= 0x00000001u;
+}
+void HDF5DataParameter::clear_has_source() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+void HDF5DataParameter::clear_source() {
+  source_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  clear_has_source();
+}
+const ::std::string& HDF5DataParameter::source() const {
+  // @@protoc_insertion_point(field_get:caffe.HDF5DataParameter.source)
+  return source_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+void HDF5DataParameter::set_source(const ::std::string& value) {
+  set_has_source();
+  source_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:caffe.HDF5DataParameter.source)
+}
+void HDF5DataParameter::set_source(const char* value) {
+  set_has_source();
+  source_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:caffe.HDF5DataParameter.source)
+}
+void HDF5DataParameter::set_source(const char* value, size_t size) {
+  set_has_source();
+  source_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:caffe.HDF5DataParameter.source)
+}
+::std::string* HDF5DataParameter::mutable_source() {
+  set_has_source();
+  // @@protoc_insertion_point(field_mutable:caffe.HDF5DataParameter.source)
+  return source_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+::std::string* HDF5DataParameter::release_source() {
+  // @@protoc_insertion_point(field_release:caffe.HDF5DataParameter.source)
+  clear_has_source();
+  return source_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+void HDF5DataParameter::set_allocated_source(::std::string* source) {
+  if (source != NULL) {
+    set_has_source();
+  } else {
+    clear_has_source();
+  }
+  source_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), source);
+  // @@protoc_insertion_point(field_set_allocated:caffe.HDF5DataParameter.source)
+}
+
+// optional uint32 batch_size = 2;
+bool HDF5DataParameter::has_batch_size() const {
+  return (_has_bits_[0] & 0x00000002u) != 0;
+}
+void HDF5DataParameter::set_has_batch_size() {
+  _has_bits_[0] |= 0x00000002u;
+}
+void HDF5DataParameter::clear_has_batch_size() {
+  _has_bits_[0] &= ~0x00000002u;
+}
+void HDF5DataParameter::clear_batch_size() {
+  batch_size_ = 0u;
+  clear_has_batch_size();
+}
+::google::protobuf::uint32 HDF5DataParameter::batch_size() const {
+  // @@protoc_insertion_point(field_get:caffe.HDF5DataParameter.batch_size)
+  return batch_size_;
+}
+void HDF5DataParameter::set_batch_size(::google::protobuf::uint32 value) {
+  set_has_batch_size();
+  batch_size_ = value;
+  // @@protoc_insertion_point(field_set:caffe.HDF5DataParameter.batch_size)
+}
+
+// optional bool shuffle = 3 [default = false];
+bool HDF5DataParameter::has_shuffle() const {
+  return (_has_bits_[0] & 0x00000004u) != 0;
+}
+void HDF5DataParameter::set_has_shuffle() {
+  _has_bits_[0] |= 0x00000004u;
+}
+void HDF5DataParameter::clear_has_shuffle() {
+  _has_bits_[0] &= ~0x00000004u;
+}
+void HDF5DataParameter::clear_shuffle() {
+  shuffle_ = false;
+  clear_has_shuffle();
+}
+bool HDF5DataParameter::shuffle() const {
+  // @@protoc_insertion_point(field_get:caffe.HDF5DataParameter.shuffle)
+  return shuffle_;
+}
+void HDF5DataParameter::set_shuffle(bool value) {
+  set_has_shuffle();
+  shuffle_ = value;
+  // @@protoc_insertion_point(field_set:caffe.HDF5DataParameter.shuffle)
+}
+
+inline const HDF5DataParameter* HDF5DataParameter::internal_default_instance() {
+  return &HDF5DataParameter_default_instance_.get();
+}
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
+
+// ===================================================================
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const int HDF5OutputParameter::kFileNameFieldNumber;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+
+HDF5OutputParameter::HDF5OutputParameter()
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+  if (this != internal_default_instance()) protobuf_InitDefaults_caffe_2eproto();
+  SharedCtor();
+  // @@protoc_insertion_point(constructor:caffe.HDF5OutputParameter)
+}
+
+void HDF5OutputParameter::InitAsDefaultInstance() {
+}
+
+HDF5OutputParameter::HDF5OutputParameter(const HDF5OutputParameter& from)
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
+  SharedCtor();
+  UnsafeMergeFrom(from);
+  // @@protoc_insertion_point(copy_constructor:caffe.HDF5OutputParameter)
+}
+
+void HDF5OutputParameter::SharedCtor() {
+  _cached_size_ = 0;
+  file_name_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+
+HDF5OutputParameter::~HDF5OutputParameter() {
+  // @@protoc_insertion_point(destructor:caffe.HDF5OutputParameter)
+  SharedDtor();
+}
+
+void HDF5OutputParameter::SharedDtor() {
+  file_name_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+
+void HDF5OutputParameter::SetCachedSize(int size) const {
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* HDF5OutputParameter::descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return HDF5OutputParameter_descriptor_;
+}
+
+const HDF5OutputParameter& HDF5OutputParameter::default_instance() {
+  protobuf_InitDefaults_caffe_2eproto();
+  return *internal_default_instance();
+}
+
+::google::protobuf::internal::ExplicitlyConstructed<HDF5OutputParameter> HDF5OutputParameter_default_instance_;
+
+HDF5OutputParameter* HDF5OutputParameter::New(::google::protobuf::Arena* arena) const {
+  HDF5OutputParameter* n = new HDF5OutputParameter;
+  if (arena != NULL) {
+    arena->Own(n);
+  }
+  return n;
+}
+
+void HDF5OutputParameter::Clear() {
+// @@protoc_insertion_point(message_clear_start:caffe.HDF5OutputParameter)
+  if (has_file_name()) {
+    file_name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  }
+  _has_bits_.Clear();
+  if (_internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->Clear();
+  }
+}
+
+bool HDF5OutputParameter::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
+  ::google::protobuf::uint32 tag;
+  // @@protoc_insertion_point(parse_start:caffe.HDF5OutputParameter)
+  for (;;) {
+    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+    tag = p.first;
+    if (!p.second) goto handle_unusual;
+    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+      // optional string file_name = 1;
+      case 1: {
+        if (tag == 10) {
+          DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+                input, this->mutable_file_name()));
+          ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+            this->file_name().data(), this->file_name().length(),
+            ::google::protobuf::internal::WireFormat::PARSE,
+            "caffe.HDF5OutputParameter.file_name");
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectAtEnd()) goto success;
+        break;
+      }
+
+      default: {
+      handle_unusual:
+        if (tag == 0 ||
+            ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+          goto success;
+        }
+        DO_(::google::protobuf::internal::WireFormat::SkipField(
+              input, tag, mutable_unknown_fields()));
+        break;
+      }
+    }
+  }
+success:
+  // @@protoc_insertion_point(parse_success:caffe.HDF5OutputParameter)
+  return true;
+failure:
+  // @@protoc_insertion_point(parse_failure:caffe.HDF5OutputParameter)
+  return false;
+#undef DO_
+}
+
+void HDF5OutputParameter::SerializeWithCachedSizes(
+    ::google::protobuf::io::CodedOutputStream* output) const {
+  // @@protoc_insertion_point(serialize_start:caffe.HDF5OutputParameter)
+  // optional string file_name = 1;
+  if (has_file_name()) {
+    ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->file_name().data(), this->file_name().length(),
+      ::google::protobuf::internal::WireFormat::SERIALIZE,
+      "caffe.HDF5OutputParameter.file_name");
+    ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
+      1, this->file_name(), output);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
+        unknown_fields(), output);
+  }
+  // @@protoc_insertion_point(serialize_end:caffe.HDF5OutputParameter)
+}
+
+::google::protobuf::uint8* HDF5OutputParameter::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
+  (void)deterministic; // Unused
+  // @@protoc_insertion_point(serialize_to_array_start:caffe.HDF5OutputParameter)
+  // optional string file_name = 1;
+  if (has_file_name()) {
+    ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->file_name().data(), this->file_name().length(),
+      ::google::protobuf::internal::WireFormat::SERIALIZE,
+      "caffe.HDF5OutputParameter.file_name");
+    target =
+      ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
+        1, this->file_name(), target);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
+        unknown_fields(), target);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:caffe.HDF5OutputParameter)
+  return target;
+}
+
+size_t HDF5OutputParameter::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:caffe.HDF5OutputParameter)
+  size_t total_size = 0;
+
+  // optional string file_name = 1;
+  if (has_file_name()) {
+    total_size += 1 +
+      ::google::protobuf::internal::WireFormatLite::StringSize(
+        this->file_name());
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    total_size +=
+      ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
+        unknown_fields());
+  }
+  int cached_size = ::google::protobuf::internal::ToCachedSize(total_size);
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = cached_size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+  return total_size;
+}
+
+void HDF5OutputParameter::MergeFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_merge_from_start:caffe.HDF5OutputParameter)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const HDF5OutputParameter* source =
+      ::google::protobuf::internal::DynamicCastToGenerated<const HDF5OutputParameter>(
+          &from);
+  if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:caffe.HDF5OutputParameter)
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:caffe.HDF5OutputParameter)
+    UnsafeMergeFrom(*source);
+  }
+}
+
+void HDF5OutputParameter::MergeFrom(const HDF5OutputParameter& from) {
+// @@protoc_insertion_point(class_specific_merge_from_start:caffe.HDF5OutputParameter)
+  if (GOOGLE_PREDICT_TRUE(&from != this)) {
+    UnsafeMergeFrom(from);
+  } else {
+    MergeFromFail(__LINE__);
+  }
+}
+
+void HDF5OutputParameter::UnsafeMergeFrom(const HDF5OutputParameter& from) {
+  GOOGLE_DCHECK(&from != this);
+  if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+    if (from.has_file_name()) {
+      set_has_file_name();
+      file_name_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.file_name_);
+    }
+  }
+  if (from._internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::UnknownFieldSet::MergeToInternalMetdata(
+      from.unknown_fields(), &_internal_metadata_);
+  }
+}
+
+void HDF5OutputParameter::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:caffe.HDF5OutputParameter)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void HDF5OutputParameter::CopyFrom(const HDF5OutputParameter& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:caffe.HDF5OutputParameter)
+  if (&from == this) return;
+  Clear();
+  UnsafeMergeFrom(from);
+}
+
+bool HDF5OutputParameter::IsInitialized() const {
+
+  return true;
+}
+
+void HDF5OutputParameter::Swap(HDF5OutputParameter* other) {
+  if (other == this) return;
+  InternalSwap(other);
+}
+void HDF5OutputParameter::InternalSwap(HDF5OutputParameter* other) {
+  file_name_.Swap(&other->file_name_);
+  std::swap(_has_bits_[0], other->_has_bits_[0]);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
+}
+
+::google::protobuf::Metadata HDF5OutputParameter::GetMetadata() const {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::Metadata metadata;
+  metadata.descriptor = HDF5OutputParameter_descriptor_;
+  metadata.reflection = HDF5OutputParameter_reflection_;
+  return metadata;
+}
+
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// HDF5OutputParameter
+
+// optional string file_name = 1;
+bool HDF5OutputParameter::has_file_name() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+void HDF5OutputParameter::set_has_file_name() {
+  _has_bits_[0] |= 0x00000001u;
+}
+void HDF5OutputParameter::clear_has_file_name() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+void HDF5OutputParameter::clear_file_name() {
+  file_name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  clear_has_file_name();
+}
+const ::std::string& HDF5OutputParameter::file_name() const {
+  // @@protoc_insertion_point(field_get:caffe.HDF5OutputParameter.file_name)
+  return file_name_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+void HDF5OutputParameter::set_file_name(const ::std::string& value) {
+  set_has_file_name();
+  file_name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:caffe.HDF5OutputParameter.file_name)
+}
+void HDF5OutputParameter::set_file_name(const char* value) {
+  set_has_file_name();
+  file_name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:caffe.HDF5OutputParameter.file_name)
+}
+void HDF5OutputParameter::set_file_name(const char* value, size_t size) {
+  set_has_file_name();
+  file_name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:caffe.HDF5OutputParameter.file_name)
+}
+::std::string* HDF5OutputParameter::mutable_file_name() {
+  set_has_file_name();
+  // @@protoc_insertion_point(field_mutable:caffe.HDF5OutputParameter.file_name)
+  return file_name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+::std::string* HDF5OutputParameter::release_file_name() {
+  // @@protoc_insertion_point(field_release:caffe.HDF5OutputParameter.file_name)
+  clear_has_file_name();
+  return file_name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+void HDF5OutputParameter::set_allocated_file_name(::std::string* file_name) {
+  if (file_name != NULL) {
+    set_has_file_name();
+  } else {
+    clear_has_file_name();
+  }
+  file_name_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), file_name);
+  // @@protoc_insertion_point(field_set_allocated:caffe.HDF5OutputParameter.file_name)
+}
+
+inline const HDF5OutputParameter* HDF5OutputParameter::internal_default_instance() {
+  return &HDF5OutputParameter_default_instance_.get();
+}
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
+
+// ===================================================================
+
+const ::google::protobuf::EnumDescriptor* HingeLossParameter_Norm_descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return HingeLossParameter_Norm_descriptor_;
+}
+bool HingeLossParameter_Norm_IsValid(int value) {
+  switch (value) {
+    case 1:
+    case 2:
+      return true;
+    default:
+      return false;
+  }
+}
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const HingeLossParameter_Norm HingeLossParameter::L1;
+const HingeLossParameter_Norm HingeLossParameter::L2;
+const HingeLossParameter_Norm HingeLossParameter::Norm_MIN;
+const HingeLossParameter_Norm HingeLossParameter::Norm_MAX;
+const int HingeLossParameter::Norm_ARRAYSIZE;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const int HingeLossParameter::kNormFieldNumber;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+
+HingeLossParameter::HingeLossParameter()
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+  if (this != internal_default_instance()) protobuf_InitDefaults_caffe_2eproto();
+  SharedCtor();
+  // @@protoc_insertion_point(constructor:caffe.HingeLossParameter)
+}
+
+void HingeLossParameter::InitAsDefaultInstance() {
+}
+
+HingeLossParameter::HingeLossParameter(const HingeLossParameter& from)
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
+  SharedCtor();
+  UnsafeMergeFrom(from);
+  // @@protoc_insertion_point(copy_constructor:caffe.HingeLossParameter)
+}
+
+void HingeLossParameter::SharedCtor() {
+  _cached_size_ = 0;
+  norm_ = 1;
+}
+
+HingeLossParameter::~HingeLossParameter() {
+  // @@protoc_insertion_point(destructor:caffe.HingeLossParameter)
+  SharedDtor();
+}
+
+void HingeLossParameter::SharedDtor() {
+}
+
+void HingeLossParameter::SetCachedSize(int size) const {
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* HingeLossParameter::descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return HingeLossParameter_descriptor_;
+}
+
+const HingeLossParameter& HingeLossParameter::default_instance() {
+  protobuf_InitDefaults_caffe_2eproto();
+  return *internal_default_instance();
+}
+
+::google::protobuf::internal::ExplicitlyConstructed<HingeLossParameter> HingeLossParameter_default_instance_;
+
+HingeLossParameter* HingeLossParameter::New(::google::protobuf::Arena* arena) const {
+  HingeLossParameter* n = new HingeLossParameter;
+  if (arena != NULL) {
+    arena->Own(n);
+  }
+  return n;
+}
+
+void HingeLossParameter::Clear() {
+// @@protoc_insertion_point(message_clear_start:caffe.HingeLossParameter)
+  norm_ = 1;
+  _has_bits_.Clear();
+  if (_internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->Clear();
+  }
+}
+
+bool HingeLossParameter::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
+  ::google::protobuf::uint32 tag;
+  // @@protoc_insertion_point(parse_start:caffe.HingeLossParameter)
+  for (;;) {
+    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+    tag = p.first;
+    if (!p.second) goto handle_unusual;
+    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+      // optional .caffe.HingeLossParameter.Norm norm = 1 [default = L1];
+      case 1: {
+        if (tag == 8) {
+          int value;
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>(
+                 input, &value)));
+          if (::caffe::HingeLossParameter_Norm_IsValid(value)) {
+            set_norm(static_cast< ::caffe::HingeLossParameter_Norm >(value));
+          } else {
+            mutable_unknown_fields()->AddVarint(1, value);
+          }
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectAtEnd()) goto success;
+        break;
+      }
+
+      default: {
+      handle_unusual:
+        if (tag == 0 ||
+            ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+          goto success;
+        }
+        DO_(::google::protobuf::internal::WireFormat::SkipField(
+              input, tag, mutable_unknown_fields()));
+        break;
+      }
+    }
+  }
+success:
+  // @@protoc_insertion_point(parse_success:caffe.HingeLossParameter)
+  return true;
+failure:
+  // @@protoc_insertion_point(parse_failure:caffe.HingeLossParameter)
+  return false;
+#undef DO_
+}
+
+void HingeLossParameter::SerializeWithCachedSizes(
+    ::google::protobuf::io::CodedOutputStream* output) const {
+  // @@protoc_insertion_point(serialize_start:caffe.HingeLossParameter)
+  // optional .caffe.HingeLossParameter.Norm norm = 1 [default = L1];
+  if (has_norm()) {
+    ::google::protobuf::internal::WireFormatLite::WriteEnum(
+      1, this->norm(), output);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
+        unknown_fields(), output);
+  }
+  // @@protoc_insertion_point(serialize_end:caffe.HingeLossParameter)
+}
+
+::google::protobuf::uint8* HingeLossParameter::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
+  (void)deterministic; // Unused
+  // @@protoc_insertion_point(serialize_to_array_start:caffe.HingeLossParameter)
+  // optional .caffe.HingeLossParameter.Norm norm = 1 [default = L1];
+  if (has_norm()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteEnumToArray(
+      1, this->norm(), target);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
+        unknown_fields(), target);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:caffe.HingeLossParameter)
+  return target;
+}
+
+size_t HingeLossParameter::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:caffe.HingeLossParameter)
+  size_t total_size = 0;
+
+  // optional .caffe.HingeLossParameter.Norm norm = 1 [default = L1];
+  if (has_norm()) {
+    total_size += 1 +
+      ::google::protobuf::internal::WireFormatLite::EnumSize(this->norm());
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    total_size +=
+      ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
+        unknown_fields());
+  }
+  int cached_size = ::google::protobuf::internal::ToCachedSize(total_size);
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = cached_size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+  return total_size;
+}
+
+void HingeLossParameter::MergeFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_merge_from_start:caffe.HingeLossParameter)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const HingeLossParameter* source =
+      ::google::protobuf::internal::DynamicCastToGenerated<const HingeLossParameter>(
+          &from);
+  if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:caffe.HingeLossParameter)
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:caffe.HingeLossParameter)
+    UnsafeMergeFrom(*source);
+  }
+}
+
+void HingeLossParameter::MergeFrom(const HingeLossParameter& from) {
+// @@protoc_insertion_point(class_specific_merge_from_start:caffe.HingeLossParameter)
+  if (GOOGLE_PREDICT_TRUE(&from != this)) {
+    UnsafeMergeFrom(from);
+  } else {
+    MergeFromFail(__LINE__);
+  }
+}
+
+void HingeLossParameter::UnsafeMergeFrom(const HingeLossParameter& from) {
+  GOOGLE_DCHECK(&from != this);
+  if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+    if (from.has_norm()) {
+      set_norm(from.norm());
+    }
+  }
+  if (from._internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::UnknownFieldSet::MergeToInternalMetdata(
+      from.unknown_fields(), &_internal_metadata_);
+  }
+}
+
+void HingeLossParameter::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:caffe.HingeLossParameter)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void HingeLossParameter::CopyFrom(const HingeLossParameter& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:caffe.HingeLossParameter)
+  if (&from == this) return;
+  Clear();
+  UnsafeMergeFrom(from);
+}
+
+bool HingeLossParameter::IsInitialized() const {
+
+  return true;
+}
+
+void HingeLossParameter::Swap(HingeLossParameter* other) {
+  if (other == this) return;
+  InternalSwap(other);
+}
+void HingeLossParameter::InternalSwap(HingeLossParameter* other) {
+  std::swap(norm_, other->norm_);
+  std::swap(_has_bits_[0], other->_has_bits_[0]);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
+}
+
+::google::protobuf::Metadata HingeLossParameter::GetMetadata() const {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::Metadata metadata;
+  metadata.descriptor = HingeLossParameter_descriptor_;
+  metadata.reflection = HingeLossParameter_reflection_;
+  return metadata;
+}
+
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// HingeLossParameter
+
+// optional .caffe.HingeLossParameter.Norm norm = 1 [default = L1];
+bool HingeLossParameter::has_norm() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+void HingeLossParameter::set_has_norm() {
+  _has_bits_[0] |= 0x00000001u;
+}
+void HingeLossParameter::clear_has_norm() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+void HingeLossParameter::clear_norm() {
+  norm_ = 1;
+  clear_has_norm();
+}
+::caffe::HingeLossParameter_Norm HingeLossParameter::norm() const {
+  // @@protoc_insertion_point(field_get:caffe.HingeLossParameter.norm)
+  return static_cast< ::caffe::HingeLossParameter_Norm >(norm_);
+}
+void HingeLossParameter::set_norm(::caffe::HingeLossParameter_Norm value) {
+  assert(::caffe::HingeLossParameter_Norm_IsValid(value));
+  set_has_norm();
+  norm_ = value;
+  // @@protoc_insertion_point(field_set:caffe.HingeLossParameter.norm)
+}
+
+inline const HingeLossParameter* HingeLossParameter::internal_default_instance() {
+  return &HingeLossParameter_default_instance_.get();
+}
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
+
+// ===================================================================
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const int ImageDataParameter::kSourceFieldNumber;
+const int ImageDataParameter::kBatchSizeFieldNumber;
+const int ImageDataParameter::kRandSkipFieldNumber;
+const int ImageDataParameter::kShuffleFieldNumber;
+const int ImageDataParameter::kNewHeightFieldNumber;
+const int ImageDataParameter::kNewWidthFieldNumber;
+const int ImageDataParameter::kIsColorFieldNumber;
+const int ImageDataParameter::kScaleFieldNumber;
+const int ImageDataParameter::kMeanFileFieldNumber;
+const int ImageDataParameter::kCropSizeFieldNumber;
+const int ImageDataParameter::kMirrorFieldNumber;
+const int ImageDataParameter::kRootFolderFieldNumber;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+
+ImageDataParameter::ImageDataParameter()
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+  if (this != internal_default_instance()) protobuf_InitDefaults_caffe_2eproto();
+  SharedCtor();
+  // @@protoc_insertion_point(constructor:caffe.ImageDataParameter)
+}
+
+void ImageDataParameter::InitAsDefaultInstance() {
+}
+
+ImageDataParameter::ImageDataParameter(const ImageDataParameter& from)
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
+  SharedCtor();
+  UnsafeMergeFrom(from);
+  // @@protoc_insertion_point(copy_constructor:caffe.ImageDataParameter)
+}
+
+void ImageDataParameter::SharedCtor() {
+  _cached_size_ = 0;
+  source_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  mean_file_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  root_folder_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  ::memset(&batch_size_, 0, reinterpret_cast<char*>(&crop_size_) -
+    reinterpret_cast<char*>(&batch_size_) + sizeof(crop_size_));
+  is_color_ = true;
+  scale_ = 1;
+}
+
+ImageDataParameter::~ImageDataParameter() {
+  // @@protoc_insertion_point(destructor:caffe.ImageDataParameter)
+  SharedDtor();
+}
+
+void ImageDataParameter::SharedDtor() {
+  source_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  mean_file_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  root_folder_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+
+void ImageDataParameter::SetCachedSize(int size) const {
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* ImageDataParameter::descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return ImageDataParameter_descriptor_;
+}
+
+const ImageDataParameter& ImageDataParameter::default_instance() {
+  protobuf_InitDefaults_caffe_2eproto();
+  return *internal_default_instance();
+}
+
+::google::protobuf::internal::ExplicitlyConstructed<ImageDataParameter> ImageDataParameter_default_instance_;
+
+ImageDataParameter* ImageDataParameter::New(::google::protobuf::Arena* arena) const {
+  ImageDataParameter* n = new ImageDataParameter;
+  if (arena != NULL) {
+    arena->Own(n);
+  }
+  return n;
+}
+
+void ImageDataParameter::Clear() {
+// @@protoc_insertion_point(message_clear_start:caffe.ImageDataParameter)
+#if defined(__clang__)
+#define ZR_HELPER_(f) \
+  _Pragma("clang diagnostic push") \
+  _Pragma("clang diagnostic ignored \"-Winvalid-offsetof\"") \
+  __builtin_offsetof(ImageDataParameter, f) \
+  _Pragma("clang diagnostic pop")
+#else
+#define ZR_HELPER_(f) reinterpret_cast<char*>(\
+  &reinterpret_cast<ImageDataParameter*>(16)->f)
+#endif
+
+#define ZR_(first, last) do {\
+  ::memset(&(first), 0,\
+           ZR_HELPER_(last) - ZR_HELPER_(first) + sizeof(last));\
+} while (0)
+
+  if (_has_bits_[0 / 32] & 255u) {
+    ZR_(batch_size_, shuffle_);
+    if (has_source()) {
+      source_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+    }
+    is_color_ = true;
+    scale_ = 1;
+  }
+  if (_has_bits_[8 / 32] & 3840u) {
+    ZR_(mirror_, crop_size_);
+    if (has_mean_file()) {
+      mean_file_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+    }
+    if (has_root_folder()) {
+      root_folder_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+    }
+  }
+
+#undef ZR_HELPER_
+#undef ZR_
+
+  _has_bits_.Clear();
+  if (_internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->Clear();
+  }
+}
+
+bool ImageDataParameter::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
+  ::google::protobuf::uint32 tag;
+  // @@protoc_insertion_point(parse_start:caffe.ImageDataParameter)
+  for (;;) {
+    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+    tag = p.first;
+    if (!p.second) goto handle_unusual;
+    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+      // optional string source = 1;
+      case 1: {
+        if (tag == 10) {
+          DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+                input, this->mutable_source()));
+          ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+            this->source().data(), this->source().length(),
+            ::google::protobuf::internal::WireFormat::PARSE,
+            "caffe.ImageDataParameter.source");
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(21)) goto parse_scale;
+        break;
+      }
+
+      // optional float scale = 2 [default = 1];
+      case 2: {
+        if (tag == 21) {
+         parse_scale:
+          set_has_scale();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
+                 input, &scale_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(26)) goto parse_mean_file;
+        break;
+      }
+
+      // optional string mean_file = 3;
+      case 3: {
+        if (tag == 26) {
+         parse_mean_file:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+                input, this->mutable_mean_file()));
+          ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+            this->mean_file().data(), this->mean_file().length(),
+            ::google::protobuf::internal::WireFormat::PARSE,
+            "caffe.ImageDataParameter.mean_file");
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(32)) goto parse_batch_size;
+        break;
+      }
+
+      // optional uint32 batch_size = 4;
+      case 4: {
+        if (tag == 32) {
+         parse_batch_size:
+          set_has_batch_size();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>(
+                 input, &batch_size_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(40)) goto parse_crop_size;
+        break;
+      }
+
+      // optional uint32 crop_size = 5 [default = 0];
+      case 5: {
+        if (tag == 40) {
+         parse_crop_size:
+          set_has_crop_size();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>(
+                 input, &crop_size_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(48)) goto parse_mirror;
+        break;
+      }
+
+      // optional bool mirror = 6 [default = false];
+      case 6: {
+        if (tag == 48) {
+         parse_mirror:
+          set_has_mirror();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>(
+                 input, &mirror_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(56)) goto parse_rand_skip;
+        break;
+      }
+
+      // optional uint32 rand_skip = 7 [default = 0];
+      case 7: {
+        if (tag == 56) {
+         parse_rand_skip:
+          set_has_rand_skip();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>(
+                 input, &rand_skip_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(64)) goto parse_shuffle;
+        break;
+      }
+
+      // optional bool shuffle = 8 [default = false];
+      case 8: {
+        if (tag == 64) {
+         parse_shuffle:
+          set_has_shuffle();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>(
+                 input, &shuffle_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(72)) goto parse_new_height;
+        break;
+      }
+
+      // optional uint32 new_height = 9 [default = 0];
+      case 9: {
+        if (tag == 72) {
+         parse_new_height:
+          set_has_new_height();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>(
+                 input, &new_height_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(80)) goto parse_new_width;
+        break;
+      }
+
+      // optional uint32 new_width = 10 [default = 0];
+      case 10: {
+        if (tag == 80) {
+         parse_new_width:
+          set_has_new_width();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>(
+                 input, &new_width_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(88)) goto parse_is_color;
+        break;
+      }
+
+      // optional bool is_color = 11 [default = true];
+      case 11: {
+        if (tag == 88) {
+         parse_is_color:
+          set_has_is_color();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>(
+                 input, &is_color_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(98)) goto parse_root_folder;
+        break;
+      }
+
+      // optional string root_folder = 12 [default = ""];
+      case 12: {
+        if (tag == 98) {
+         parse_root_folder:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+                input, this->mutable_root_folder()));
+          ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+            this->root_folder().data(), this->root_folder().length(),
+            ::google::protobuf::internal::WireFormat::PARSE,
+            "caffe.ImageDataParameter.root_folder");
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectAtEnd()) goto success;
+        break;
+      }
+
+      default: {
+      handle_unusual:
+        if (tag == 0 ||
+            ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+          goto success;
+        }
+        DO_(::google::protobuf::internal::WireFormat::SkipField(
+              input, tag, mutable_unknown_fields()));
+        break;
+      }
+    }
+  }
+success:
+  // @@protoc_insertion_point(parse_success:caffe.ImageDataParameter)
+  return true;
+failure:
+  // @@protoc_insertion_point(parse_failure:caffe.ImageDataParameter)
+  return false;
+#undef DO_
+}
+
+void ImageDataParameter::SerializeWithCachedSizes(
+    ::google::protobuf::io::CodedOutputStream* output) const {
+  // @@protoc_insertion_point(serialize_start:caffe.ImageDataParameter)
+  // optional string source = 1;
+  if (has_source()) {
+    ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->source().data(), this->source().length(),
+      ::google::protobuf::internal::WireFormat::SERIALIZE,
+      "caffe.ImageDataParameter.source");
+    ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
+      1, this->source(), output);
+  }
+
+  // optional float scale = 2 [default = 1];
+  if (has_scale()) {
+    ::google::protobuf::internal::WireFormatLite::WriteFloat(2, this->scale(), output);
+  }
+
+  // optional string mean_file = 3;
+  if (has_mean_file()) {
+    ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->mean_file().data(), this->mean_file().length(),
+      ::google::protobuf::internal::WireFormat::SERIALIZE,
+      "caffe.ImageDataParameter.mean_file");
+    ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
+      3, this->mean_file(), output);
+  }
+
+  // optional uint32 batch_size = 4;
+  if (has_batch_size()) {
+    ::google::protobuf::internal::WireFormatLite::WriteUInt32(4, this->batch_size(), output);
+  }
+
+  // optional uint32 crop_size = 5 [default = 0];
+  if (has_crop_size()) {
+    ::google::protobuf::internal::WireFormatLite::WriteUInt32(5, this->crop_size(), output);
+  }
+
+  // optional bool mirror = 6 [default = false];
+  if (has_mirror()) {
+    ::google::protobuf::internal::WireFormatLite::WriteBool(6, this->mirror(), output);
+  }
+
+  // optional uint32 rand_skip = 7 [default = 0];
+  if (has_rand_skip()) {
+    ::google::protobuf::internal::WireFormatLite::WriteUInt32(7, this->rand_skip(), output);
+  }
+
+  // optional bool shuffle = 8 [default = false];
+  if (has_shuffle()) {
+    ::google::protobuf::internal::WireFormatLite::WriteBool(8, this->shuffle(), output);
+  }
+
+  // optional uint32 new_height = 9 [default = 0];
+  if (has_new_height()) {
+    ::google::protobuf::internal::WireFormatLite::WriteUInt32(9, this->new_height(), output);
+  }
+
+  // optional uint32 new_width = 10 [default = 0];
+  if (has_new_width()) {
+    ::google::protobuf::internal::WireFormatLite::WriteUInt32(10, this->new_width(), output);
+  }
+
+  // optional bool is_color = 11 [default = true];
+  if (has_is_color()) {
+    ::google::protobuf::internal::WireFormatLite::WriteBool(11, this->is_color(), output);
+  }
+
+  // optional string root_folder = 12 [default = ""];
+  if (has_root_folder()) {
+    ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->root_folder().data(), this->root_folder().length(),
+      ::google::protobuf::internal::WireFormat::SERIALIZE,
+      "caffe.ImageDataParameter.root_folder");
+    ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
+      12, this->root_folder(), output);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
+        unknown_fields(), output);
+  }
+  // @@protoc_insertion_point(serialize_end:caffe.ImageDataParameter)
+}
+
+::google::protobuf::uint8* ImageDataParameter::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
+  (void)deterministic; // Unused
+  // @@protoc_insertion_point(serialize_to_array_start:caffe.ImageDataParameter)
+  // optional string source = 1;
+  if (has_source()) {
+    ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->source().data(), this->source().length(),
+      ::google::protobuf::internal::WireFormat::SERIALIZE,
+      "caffe.ImageDataParameter.source");
+    target =
+      ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
+        1, this->source(), target);
+  }
+
+  // optional float scale = 2 [default = 1];
+  if (has_scale()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteFloatToArray(2, this->scale(), target);
+  }
+
+  // optional string mean_file = 3;
+  if (has_mean_file()) {
+    ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->mean_file().data(), this->mean_file().length(),
+      ::google::protobuf::internal::WireFormat::SERIALIZE,
+      "caffe.ImageDataParameter.mean_file");
+    target =
+      ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
+        3, this->mean_file(), target);
+  }
+
+  // optional uint32 batch_size = 4;
+  if (has_batch_size()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteUInt32ToArray(4, this->batch_size(), target);
+  }
+
+  // optional uint32 crop_size = 5 [default = 0];
+  if (has_crop_size()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteUInt32ToArray(5, this->crop_size(), target);
+  }
+
+  // optional bool mirror = 6 [default = false];
+  if (has_mirror()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(6, this->mirror(), target);
+  }
+
+  // optional uint32 rand_skip = 7 [default = 0];
+  if (has_rand_skip()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteUInt32ToArray(7, this->rand_skip(), target);
+  }
+
+  // optional bool shuffle = 8 [default = false];
+  if (has_shuffle()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(8, this->shuffle(), target);
+  }
+
+  // optional uint32 new_height = 9 [default = 0];
+  if (has_new_height()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteUInt32ToArray(9, this->new_height(), target);
+  }
+
+  // optional uint32 new_width = 10 [default = 0];
+  if (has_new_width()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteUInt32ToArray(10, this->new_width(), target);
+  }
+
+  // optional bool is_color = 11 [default = true];
+  if (has_is_color()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(11, this->is_color(), target);
+  }
+
+  // optional string root_folder = 12 [default = ""];
+  if (has_root_folder()) {
+    ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->root_folder().data(), this->root_folder().length(),
+      ::google::protobuf::internal::WireFormat::SERIALIZE,
+      "caffe.ImageDataParameter.root_folder");
+    target =
+      ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
+        12, this->root_folder(), target);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
+        unknown_fields(), target);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:caffe.ImageDataParameter)
+  return target;
+}
+
+size_t ImageDataParameter::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:caffe.ImageDataParameter)
+  size_t total_size = 0;
+
+  if (_has_bits_[0 / 32] & 255u) {
+    // optional string source = 1;
+    if (has_source()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::StringSize(
+          this->source());
+    }
+
+    // optional uint32 batch_size = 4;
+    if (has_batch_size()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::UInt32Size(
+          this->batch_size());
+    }
+
+    // optional uint32 rand_skip = 7 [default = 0];
+    if (has_rand_skip()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::UInt32Size(
+          this->rand_skip());
+    }
+
+    // optional bool shuffle = 8 [default = false];
+    if (has_shuffle()) {
+      total_size += 1 + 1;
+    }
+
+    // optional uint32 new_height = 9 [default = 0];
+    if (has_new_height()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::UInt32Size(
+          this->new_height());
+    }
+
+    // optional uint32 new_width = 10 [default = 0];
+    if (has_new_width()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::UInt32Size(
+          this->new_width());
+    }
+
+    // optional bool is_color = 11 [default = true];
+    if (has_is_color()) {
+      total_size += 1 + 1;
+    }
+
+    // optional float scale = 2 [default = 1];
+    if (has_scale()) {
+      total_size += 1 + 4;
+    }
+
+  }
+  if (_has_bits_[8 / 32] & 3840u) {
+    // optional string mean_file = 3;
+    if (has_mean_file()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::StringSize(
+          this->mean_file());
+    }
+
+    // optional uint32 crop_size = 5 [default = 0];
+    if (has_crop_size()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::UInt32Size(
+          this->crop_size());
+    }
+
+    // optional bool mirror = 6 [default = false];
+    if (has_mirror()) {
+      total_size += 1 + 1;
+    }
+
+    // optional string root_folder = 12 [default = ""];
+    if (has_root_folder()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::StringSize(
+          this->root_folder());
+    }
+
+  }
+  if (_internal_metadata_.have_unknown_fields()) {
+    total_size +=
+      ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
+        unknown_fields());
+  }
+  int cached_size = ::google::protobuf::internal::ToCachedSize(total_size);
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = cached_size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+  return total_size;
+}
+
+void ImageDataParameter::MergeFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_merge_from_start:caffe.ImageDataParameter)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const ImageDataParameter* source =
+      ::google::protobuf::internal::DynamicCastToGenerated<const ImageDataParameter>(
+          &from);
+  if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:caffe.ImageDataParameter)
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:caffe.ImageDataParameter)
+    UnsafeMergeFrom(*source);
+  }
+}
+
+void ImageDataParameter::MergeFrom(const ImageDataParameter& from) {
+// @@protoc_insertion_point(class_specific_merge_from_start:caffe.ImageDataParameter)
+  if (GOOGLE_PREDICT_TRUE(&from != this)) {
+    UnsafeMergeFrom(from);
+  } else {
+    MergeFromFail(__LINE__);
+  }
+}
+
+void ImageDataParameter::UnsafeMergeFrom(const ImageDataParameter& from) {
+  GOOGLE_DCHECK(&from != this);
+  if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+    if (from.has_source()) {
+      set_has_source();
+      source_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.source_);
+    }
+    if (from.has_batch_size()) {
+      set_batch_size(from.batch_size());
+    }
+    if (from.has_rand_skip()) {
+      set_rand_skip(from.rand_skip());
+    }
+    if (from.has_shuffle()) {
+      set_shuffle(from.shuffle());
+    }
+    if (from.has_new_height()) {
+      set_new_height(from.new_height());
+    }
+    if (from.has_new_width()) {
+      set_new_width(from.new_width());
+    }
+    if (from.has_is_color()) {
+      set_is_color(from.is_color());
+    }
+    if (from.has_scale()) {
+      set_scale(from.scale());
+    }
+  }
+  if (from._has_bits_[8 / 32] & (0xffu << (8 % 32))) {
+    if (from.has_mean_file()) {
+      set_has_mean_file();
+      mean_file_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.mean_file_);
+    }
+    if (from.has_crop_size()) {
+      set_crop_size(from.crop_size());
+    }
+    if (from.has_mirror()) {
+      set_mirror(from.mirror());
+    }
+    if (from.has_root_folder()) {
+      set_has_root_folder();
+      root_folder_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.root_folder_);
+    }
+  }
+  if (from._internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::UnknownFieldSet::MergeToInternalMetdata(
+      from.unknown_fields(), &_internal_metadata_);
+  }
+}
+
+void ImageDataParameter::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:caffe.ImageDataParameter)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void ImageDataParameter::CopyFrom(const ImageDataParameter& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:caffe.ImageDataParameter)
+  if (&from == this) return;
+  Clear();
+  UnsafeMergeFrom(from);
+}
+
+bool ImageDataParameter::IsInitialized() const {
+
+  return true;
+}
+
+void ImageDataParameter::Swap(ImageDataParameter* other) {
+  if (other == this) return;
+  InternalSwap(other);
+}
+void ImageDataParameter::InternalSwap(ImageDataParameter* other) {
+  source_.Swap(&other->source_);
+  std::swap(batch_size_, other->batch_size_);
+  std::swap(rand_skip_, other->rand_skip_);
+  std::swap(shuffle_, other->shuffle_);
+  std::swap(new_height_, other->new_height_);
+  std::swap(new_width_, other->new_width_);
+  std::swap(is_color_, other->is_color_);
+  std::swap(scale_, other->scale_);
+  mean_file_.Swap(&other->mean_file_);
+  std::swap(crop_size_, other->crop_size_);
+  std::swap(mirror_, other->mirror_);
+  root_folder_.Swap(&other->root_folder_);
+  std::swap(_has_bits_[0], other->_has_bits_[0]);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
+}
+
+::google::protobuf::Metadata ImageDataParameter::GetMetadata() const {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::Metadata metadata;
+  metadata.descriptor = ImageDataParameter_descriptor_;
+  metadata.reflection = ImageDataParameter_reflection_;
+  return metadata;
+}
+
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// ImageDataParameter
+
+// optional string source = 1;
+bool ImageDataParameter::has_source() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+void ImageDataParameter::set_has_source() {
+  _has_bits_[0] |= 0x00000001u;
+}
+void ImageDataParameter::clear_has_source() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+void ImageDataParameter::clear_source() {
+  source_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  clear_has_source();
+}
+const ::std::string& ImageDataParameter::source() const {
+  // @@protoc_insertion_point(field_get:caffe.ImageDataParameter.source)
+  return source_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+void ImageDataParameter::set_source(const ::std::string& value) {
+  set_has_source();
+  source_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:caffe.ImageDataParameter.source)
+}
+void ImageDataParameter::set_source(const char* value) {
+  set_has_source();
+  source_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:caffe.ImageDataParameter.source)
+}
+void ImageDataParameter::set_source(const char* value, size_t size) {
+  set_has_source();
+  source_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:caffe.ImageDataParameter.source)
+}
+::std::string* ImageDataParameter::mutable_source() {
+  set_has_source();
+  // @@protoc_insertion_point(field_mutable:caffe.ImageDataParameter.source)
+  return source_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+::std::string* ImageDataParameter::release_source() {
+  // @@protoc_insertion_point(field_release:caffe.ImageDataParameter.source)
+  clear_has_source();
+  return source_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+void ImageDataParameter::set_allocated_source(::std::string* source) {
+  if (source != NULL) {
+    set_has_source();
+  } else {
+    clear_has_source();
+  }
+  source_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), source);
+  // @@protoc_insertion_point(field_set_allocated:caffe.ImageDataParameter.source)
+}
+
+// optional uint32 batch_size = 4;
+bool ImageDataParameter::has_batch_size() const {
+  return (_has_bits_[0] & 0x00000002u) != 0;
+}
+void ImageDataParameter::set_has_batch_size() {
+  _has_bits_[0] |= 0x00000002u;
+}
+void ImageDataParameter::clear_has_batch_size() {
+  _has_bits_[0] &= ~0x00000002u;
+}
+void ImageDataParameter::clear_batch_size() {
+  batch_size_ = 0u;
+  clear_has_batch_size();
+}
+::google::protobuf::uint32 ImageDataParameter::batch_size() const {
+  // @@protoc_insertion_point(field_get:caffe.ImageDataParameter.batch_size)
+  return batch_size_;
+}
+void ImageDataParameter::set_batch_size(::google::protobuf::uint32 value) {
+  set_has_batch_size();
+  batch_size_ = value;
+  // @@protoc_insertion_point(field_set:caffe.ImageDataParameter.batch_size)
+}
+
+// optional uint32 rand_skip = 7 [default = 0];
+bool ImageDataParameter::has_rand_skip() const {
+  return (_has_bits_[0] & 0x00000004u) != 0;
+}
+void ImageDataParameter::set_has_rand_skip() {
+  _has_bits_[0] |= 0x00000004u;
+}
+void ImageDataParameter::clear_has_rand_skip() {
+  _has_bits_[0] &= ~0x00000004u;
+}
+void ImageDataParameter::clear_rand_skip() {
+  rand_skip_ = 0u;
+  clear_has_rand_skip();
+}
+::google::protobuf::uint32 ImageDataParameter::rand_skip() const {
+  // @@protoc_insertion_point(field_get:caffe.ImageDataParameter.rand_skip)
+  return rand_skip_;
+}
+void ImageDataParameter::set_rand_skip(::google::protobuf::uint32 value) {
+  set_has_rand_skip();
+  rand_skip_ = value;
+  // @@protoc_insertion_point(field_set:caffe.ImageDataParameter.rand_skip)
+}
+
+// optional bool shuffle = 8 [default = false];
+bool ImageDataParameter::has_shuffle() const {
+  return (_has_bits_[0] & 0x00000008u) != 0;
+}
+void ImageDataParameter::set_has_shuffle() {
+  _has_bits_[0] |= 0x00000008u;
+}
+void ImageDataParameter::clear_has_shuffle() {
+  _has_bits_[0] &= ~0x00000008u;
+}
+void ImageDataParameter::clear_shuffle() {
+  shuffle_ = false;
+  clear_has_shuffle();
+}
+bool ImageDataParameter::shuffle() const {
+  // @@protoc_insertion_point(field_get:caffe.ImageDataParameter.shuffle)
+  return shuffle_;
+}
+void ImageDataParameter::set_shuffle(bool value) {
+  set_has_shuffle();
+  shuffle_ = value;
+  // @@protoc_insertion_point(field_set:caffe.ImageDataParameter.shuffle)
+}
+
+// optional uint32 new_height = 9 [default = 0];
+bool ImageDataParameter::has_new_height() const {
+  return (_has_bits_[0] & 0x00000010u) != 0;
+}
+void ImageDataParameter::set_has_new_height() {
+  _has_bits_[0] |= 0x00000010u;
+}
+void ImageDataParameter::clear_has_new_height() {
+  _has_bits_[0] &= ~0x00000010u;
+}
+void ImageDataParameter::clear_new_height() {
+  new_height_ = 0u;
+  clear_has_new_height();
+}
+::google::protobuf::uint32 ImageDataParameter::new_height() const {
+  // @@protoc_insertion_point(field_get:caffe.ImageDataParameter.new_height)
+  return new_height_;
+}
+void ImageDataParameter::set_new_height(::google::protobuf::uint32 value) {
+  set_has_new_height();
+  new_height_ = value;
+  // @@protoc_insertion_point(field_set:caffe.ImageDataParameter.new_height)
+}
+
+// optional uint32 new_width = 10 [default = 0];
+bool ImageDataParameter::has_new_width() const {
+  return (_has_bits_[0] & 0x00000020u) != 0;
+}
+void ImageDataParameter::set_has_new_width() {
+  _has_bits_[0] |= 0x00000020u;
+}
+void ImageDataParameter::clear_has_new_width() {
+  _has_bits_[0] &= ~0x00000020u;
+}
+void ImageDataParameter::clear_new_width() {
+  new_width_ = 0u;
+  clear_has_new_width();
+}
+::google::protobuf::uint32 ImageDataParameter::new_width() const {
+  // @@protoc_insertion_point(field_get:caffe.ImageDataParameter.new_width)
+  return new_width_;
+}
+void ImageDataParameter::set_new_width(::google::protobuf::uint32 value) {
+  set_has_new_width();
+  new_width_ = value;
+  // @@protoc_insertion_point(field_set:caffe.ImageDataParameter.new_width)
+}
+
+// optional bool is_color = 11 [default = true];
+bool ImageDataParameter::has_is_color() const {
+  return (_has_bits_[0] & 0x00000040u) != 0;
+}
+void ImageDataParameter::set_has_is_color() {
+  _has_bits_[0] |= 0x00000040u;
+}
+void ImageDataParameter::clear_has_is_color() {
+  _has_bits_[0] &= ~0x00000040u;
+}
+void ImageDataParameter::clear_is_color() {
+  is_color_ = true;
+  clear_has_is_color();
+}
+bool ImageDataParameter::is_color() const {
+  // @@protoc_insertion_point(field_get:caffe.ImageDataParameter.is_color)
+  return is_color_;
+}
+void ImageDataParameter::set_is_color(bool value) {
+  set_has_is_color();
+  is_color_ = value;
+  // @@protoc_insertion_point(field_set:caffe.ImageDataParameter.is_color)
+}
+
+// optional float scale = 2 [default = 1];
+bool ImageDataParameter::has_scale() const {
+  return (_has_bits_[0] & 0x00000080u) != 0;
+}
+void ImageDataParameter::set_has_scale() {
+  _has_bits_[0] |= 0x00000080u;
+}
+void ImageDataParameter::clear_has_scale() {
+  _has_bits_[0] &= ~0x00000080u;
+}
+void ImageDataParameter::clear_scale() {
+  scale_ = 1;
+  clear_has_scale();
+}
+float ImageDataParameter::scale() const {
+  // @@protoc_insertion_point(field_get:caffe.ImageDataParameter.scale)
+  return scale_;
+}
+void ImageDataParameter::set_scale(float value) {
+  set_has_scale();
+  scale_ = value;
+  // @@protoc_insertion_point(field_set:caffe.ImageDataParameter.scale)
+}
+
+// optional string mean_file = 3;
+bool ImageDataParameter::has_mean_file() const {
+  return (_has_bits_[0] & 0x00000100u) != 0;
+}
+void ImageDataParameter::set_has_mean_file() {
+  _has_bits_[0] |= 0x00000100u;
+}
+void ImageDataParameter::clear_has_mean_file() {
+  _has_bits_[0] &= ~0x00000100u;
+}
+void ImageDataParameter::clear_mean_file() {
+  mean_file_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  clear_has_mean_file();
+}
+const ::std::string& ImageDataParameter::mean_file() const {
+  // @@protoc_insertion_point(field_get:caffe.ImageDataParameter.mean_file)
+  return mean_file_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+void ImageDataParameter::set_mean_file(const ::std::string& value) {
+  set_has_mean_file();
+  mean_file_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:caffe.ImageDataParameter.mean_file)
+}
+void ImageDataParameter::set_mean_file(const char* value) {
+  set_has_mean_file();
+  mean_file_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:caffe.ImageDataParameter.mean_file)
+}
+void ImageDataParameter::set_mean_file(const char* value, size_t size) {
+  set_has_mean_file();
+  mean_file_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:caffe.ImageDataParameter.mean_file)
+}
+::std::string* ImageDataParameter::mutable_mean_file() {
+  set_has_mean_file();
+  // @@protoc_insertion_point(field_mutable:caffe.ImageDataParameter.mean_file)
+  return mean_file_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+::std::string* ImageDataParameter::release_mean_file() {
+  // @@protoc_insertion_point(field_release:caffe.ImageDataParameter.mean_file)
+  clear_has_mean_file();
+  return mean_file_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+void ImageDataParameter::set_allocated_mean_file(::std::string* mean_file) {
+  if (mean_file != NULL) {
+    set_has_mean_file();
+  } else {
+    clear_has_mean_file();
+  }
+  mean_file_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), mean_file);
+  // @@protoc_insertion_point(field_set_allocated:caffe.ImageDataParameter.mean_file)
+}
+
+// optional uint32 crop_size = 5 [default = 0];
+bool ImageDataParameter::has_crop_size() const {
+  return (_has_bits_[0] & 0x00000200u) != 0;
+}
+void ImageDataParameter::set_has_crop_size() {
+  _has_bits_[0] |= 0x00000200u;
+}
+void ImageDataParameter::clear_has_crop_size() {
+  _has_bits_[0] &= ~0x00000200u;
+}
+void ImageDataParameter::clear_crop_size() {
+  crop_size_ = 0u;
+  clear_has_crop_size();
+}
+::google::protobuf::uint32 ImageDataParameter::crop_size() const {
+  // @@protoc_insertion_point(field_get:caffe.ImageDataParameter.crop_size)
+  return crop_size_;
+}
+void ImageDataParameter::set_crop_size(::google::protobuf::uint32 value) {
+  set_has_crop_size();
+  crop_size_ = value;
+  // @@protoc_insertion_point(field_set:caffe.ImageDataParameter.crop_size)
+}
+
+// optional bool mirror = 6 [default = false];
+bool ImageDataParameter::has_mirror() const {
+  return (_has_bits_[0] & 0x00000400u) != 0;
+}
+void ImageDataParameter::set_has_mirror() {
+  _has_bits_[0] |= 0x00000400u;
+}
+void ImageDataParameter::clear_has_mirror() {
+  _has_bits_[0] &= ~0x00000400u;
+}
+void ImageDataParameter::clear_mirror() {
+  mirror_ = false;
+  clear_has_mirror();
+}
+bool ImageDataParameter::mirror() const {
+  // @@protoc_insertion_point(field_get:caffe.ImageDataParameter.mirror)
+  return mirror_;
+}
+void ImageDataParameter::set_mirror(bool value) {
+  set_has_mirror();
+  mirror_ = value;
+  // @@protoc_insertion_point(field_set:caffe.ImageDataParameter.mirror)
+}
+
+// optional string root_folder = 12 [default = ""];
+bool ImageDataParameter::has_root_folder() const {
+  return (_has_bits_[0] & 0x00000800u) != 0;
+}
+void ImageDataParameter::set_has_root_folder() {
+  _has_bits_[0] |= 0x00000800u;
+}
+void ImageDataParameter::clear_has_root_folder() {
+  _has_bits_[0] &= ~0x00000800u;
+}
+void ImageDataParameter::clear_root_folder() {
+  root_folder_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  clear_has_root_folder();
+}
+const ::std::string& ImageDataParameter::root_folder() const {
+  // @@protoc_insertion_point(field_get:caffe.ImageDataParameter.root_folder)
+  return root_folder_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+void ImageDataParameter::set_root_folder(const ::std::string& value) {
+  set_has_root_folder();
+  root_folder_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:caffe.ImageDataParameter.root_folder)
+}
+void ImageDataParameter::set_root_folder(const char* value) {
+  set_has_root_folder();
+  root_folder_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:caffe.ImageDataParameter.root_folder)
+}
+void ImageDataParameter::set_root_folder(const char* value, size_t size) {
+  set_has_root_folder();
+  root_folder_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:caffe.ImageDataParameter.root_folder)
+}
+::std::string* ImageDataParameter::mutable_root_folder() {
+  set_has_root_folder();
+  // @@protoc_insertion_point(field_mutable:caffe.ImageDataParameter.root_folder)
+  return root_folder_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+::std::string* ImageDataParameter::release_root_folder() {
+  // @@protoc_insertion_point(field_release:caffe.ImageDataParameter.root_folder)
+  clear_has_root_folder();
+  return root_folder_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+void ImageDataParameter::set_allocated_root_folder(::std::string* root_folder) {
+  if (root_folder != NULL) {
+    set_has_root_folder();
+  } else {
+    clear_has_root_folder();
+  }
+  root_folder_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), root_folder);
+  // @@protoc_insertion_point(field_set_allocated:caffe.ImageDataParameter.root_folder)
+}
+
+inline const ImageDataParameter* ImageDataParameter::internal_default_instance() {
+  return &ImageDataParameter_default_instance_.get();
+}
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
+
+// ===================================================================
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const int InfogainLossParameter::kSourceFieldNumber;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+
+InfogainLossParameter::InfogainLossParameter()
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+  if (this != internal_default_instance()) protobuf_InitDefaults_caffe_2eproto();
+  SharedCtor();
+  // @@protoc_insertion_point(constructor:caffe.InfogainLossParameter)
+}
+
+void InfogainLossParameter::InitAsDefaultInstance() {
+}
+
+InfogainLossParameter::InfogainLossParameter(const InfogainLossParameter& from)
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
+  SharedCtor();
+  UnsafeMergeFrom(from);
+  // @@protoc_insertion_point(copy_constructor:caffe.InfogainLossParameter)
+}
+
+void InfogainLossParameter::SharedCtor() {
+  _cached_size_ = 0;
+  source_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+
+InfogainLossParameter::~InfogainLossParameter() {
+  // @@protoc_insertion_point(destructor:caffe.InfogainLossParameter)
+  SharedDtor();
+}
+
+void InfogainLossParameter::SharedDtor() {
+  source_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+
+void InfogainLossParameter::SetCachedSize(int size) const {
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* InfogainLossParameter::descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return InfogainLossParameter_descriptor_;
+}
+
+const InfogainLossParameter& InfogainLossParameter::default_instance() {
+  protobuf_InitDefaults_caffe_2eproto();
+  return *internal_default_instance();
+}
+
+::google::protobuf::internal::ExplicitlyConstructed<InfogainLossParameter> InfogainLossParameter_default_instance_;
+
+InfogainLossParameter* InfogainLossParameter::New(::google::protobuf::Arena* arena) const {
+  InfogainLossParameter* n = new InfogainLossParameter;
+  if (arena != NULL) {
+    arena->Own(n);
+  }
+  return n;
+}
+
+void InfogainLossParameter::Clear() {
+// @@protoc_insertion_point(message_clear_start:caffe.InfogainLossParameter)
+  if (has_source()) {
+    source_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  }
+  _has_bits_.Clear();
+  if (_internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->Clear();
+  }
+}
+
+bool InfogainLossParameter::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
+  ::google::protobuf::uint32 tag;
+  // @@protoc_insertion_point(parse_start:caffe.InfogainLossParameter)
+  for (;;) {
+    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+    tag = p.first;
+    if (!p.second) goto handle_unusual;
+    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+      // optional string source = 1;
+      case 1: {
+        if (tag == 10) {
+          DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+                input, this->mutable_source()));
+          ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+            this->source().data(), this->source().length(),
+            ::google::protobuf::internal::WireFormat::PARSE,
+            "caffe.InfogainLossParameter.source");
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectAtEnd()) goto success;
+        break;
+      }
+
+      default: {
+      handle_unusual:
+        if (tag == 0 ||
+            ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+          goto success;
+        }
+        DO_(::google::protobuf::internal::WireFormat::SkipField(
+              input, tag, mutable_unknown_fields()));
+        break;
+      }
+    }
+  }
+success:
+  // @@protoc_insertion_point(parse_success:caffe.InfogainLossParameter)
+  return true;
+failure:
+  // @@protoc_insertion_point(parse_failure:caffe.InfogainLossParameter)
+  return false;
+#undef DO_
+}
+
+void InfogainLossParameter::SerializeWithCachedSizes(
+    ::google::protobuf::io::CodedOutputStream* output) const {
+  // @@protoc_insertion_point(serialize_start:caffe.InfogainLossParameter)
+  // optional string source = 1;
+  if (has_source()) {
+    ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->source().data(), this->source().length(),
+      ::google::protobuf::internal::WireFormat::SERIALIZE,
+      "caffe.InfogainLossParameter.source");
+    ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
+      1, this->source(), output);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
+        unknown_fields(), output);
+  }
+  // @@protoc_insertion_point(serialize_end:caffe.InfogainLossParameter)
+}
+
+::google::protobuf::uint8* InfogainLossParameter::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
+  (void)deterministic; // Unused
+  // @@protoc_insertion_point(serialize_to_array_start:caffe.InfogainLossParameter)
+  // optional string source = 1;
+  if (has_source()) {
+    ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->source().data(), this->source().length(),
+      ::google::protobuf::internal::WireFormat::SERIALIZE,
+      "caffe.InfogainLossParameter.source");
+    target =
+      ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
+        1, this->source(), target);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
+        unknown_fields(), target);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:caffe.InfogainLossParameter)
+  return target;
+}
+
+size_t InfogainLossParameter::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:caffe.InfogainLossParameter)
+  size_t total_size = 0;
+
+  // optional string source = 1;
+  if (has_source()) {
+    total_size += 1 +
+      ::google::protobuf::internal::WireFormatLite::StringSize(
+        this->source());
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    total_size +=
+      ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
+        unknown_fields());
+  }
+  int cached_size = ::google::protobuf::internal::ToCachedSize(total_size);
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = cached_size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+  return total_size;
+}
+
+void InfogainLossParameter::MergeFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_merge_from_start:caffe.InfogainLossParameter)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const InfogainLossParameter* source =
+      ::google::protobuf::internal::DynamicCastToGenerated<const InfogainLossParameter>(
+          &from);
+  if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:caffe.InfogainLossParameter)
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:caffe.InfogainLossParameter)
+    UnsafeMergeFrom(*source);
+  }
+}
+
+void InfogainLossParameter::MergeFrom(const InfogainLossParameter& from) {
+// @@protoc_insertion_point(class_specific_merge_from_start:caffe.InfogainLossParameter)
+  if (GOOGLE_PREDICT_TRUE(&from != this)) {
+    UnsafeMergeFrom(from);
+  } else {
+    MergeFromFail(__LINE__);
+  }
+}
+
+void InfogainLossParameter::UnsafeMergeFrom(const InfogainLossParameter& from) {
+  GOOGLE_DCHECK(&from != this);
+  if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+    if (from.has_source()) {
+      set_has_source();
+      source_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.source_);
+    }
+  }
+  if (from._internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::UnknownFieldSet::MergeToInternalMetdata(
+      from.unknown_fields(), &_internal_metadata_);
+  }
+}
+
+void InfogainLossParameter::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:caffe.InfogainLossParameter)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void InfogainLossParameter::CopyFrom(const InfogainLossParameter& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:caffe.InfogainLossParameter)
+  if (&from == this) return;
+  Clear();
+  UnsafeMergeFrom(from);
+}
+
+bool InfogainLossParameter::IsInitialized() const {
+
+  return true;
+}
+
+void InfogainLossParameter::Swap(InfogainLossParameter* other) {
+  if (other == this) return;
+  InternalSwap(other);
+}
+void InfogainLossParameter::InternalSwap(InfogainLossParameter* other) {
+  source_.Swap(&other->source_);
+  std::swap(_has_bits_[0], other->_has_bits_[0]);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
+}
+
+::google::protobuf::Metadata InfogainLossParameter::GetMetadata() const {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::Metadata metadata;
+  metadata.descriptor = InfogainLossParameter_descriptor_;
+  metadata.reflection = InfogainLossParameter_reflection_;
+  return metadata;
+}
+
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// InfogainLossParameter
+
+// optional string source = 1;
+bool InfogainLossParameter::has_source() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+void InfogainLossParameter::set_has_source() {
+  _has_bits_[0] |= 0x00000001u;
+}
+void InfogainLossParameter::clear_has_source() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+void InfogainLossParameter::clear_source() {
+  source_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  clear_has_source();
+}
+const ::std::string& InfogainLossParameter::source() const {
+  // @@protoc_insertion_point(field_get:caffe.InfogainLossParameter.source)
+  return source_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+void InfogainLossParameter::set_source(const ::std::string& value) {
+  set_has_source();
+  source_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:caffe.InfogainLossParameter.source)
+}
+void InfogainLossParameter::set_source(const char* value) {
+  set_has_source();
+  source_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:caffe.InfogainLossParameter.source)
+}
+void InfogainLossParameter::set_source(const char* value, size_t size) {
+  set_has_source();
+  source_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:caffe.InfogainLossParameter.source)
+}
+::std::string* InfogainLossParameter::mutable_source() {
+  set_has_source();
+  // @@protoc_insertion_point(field_mutable:caffe.InfogainLossParameter.source)
+  return source_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+::std::string* InfogainLossParameter::release_source() {
+  // @@protoc_insertion_point(field_release:caffe.InfogainLossParameter.source)
+  clear_has_source();
+  return source_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+void InfogainLossParameter::set_allocated_source(::std::string* source) {
+  if (source != NULL) {
+    set_has_source();
+  } else {
+    clear_has_source();
+  }
+  source_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), source);
+  // @@protoc_insertion_point(field_set_allocated:caffe.InfogainLossParameter.source)
+}
+
+inline const InfogainLossParameter* InfogainLossParameter::internal_default_instance() {
+  return &InfogainLossParameter_default_instance_.get();
+}
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
+
+// ===================================================================
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const int InnerProductParameter::kNumOutputFieldNumber;
+const int InnerProductParameter::kBiasTermFieldNumber;
+const int InnerProductParameter::kWeightFillerFieldNumber;
+const int InnerProductParameter::kBiasFillerFieldNumber;
+const int InnerProductParameter::kAxisFieldNumber;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+
+InnerProductParameter::InnerProductParameter()
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+  if (this != internal_default_instance()) protobuf_InitDefaults_caffe_2eproto();
+  SharedCtor();
+  // @@protoc_insertion_point(constructor:caffe.InnerProductParameter)
+}
+
+void InnerProductParameter::InitAsDefaultInstance() {
+  weight_filler_ = const_cast< ::caffe::FillerParameter*>(
+      ::caffe::FillerParameter::internal_default_instance());
+  bias_filler_ = const_cast< ::caffe::FillerParameter*>(
+      ::caffe::FillerParameter::internal_default_instance());
+}
+
+InnerProductParameter::InnerProductParameter(const InnerProductParameter& from)
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
+  SharedCtor();
+  UnsafeMergeFrom(from);
+  // @@protoc_insertion_point(copy_constructor:caffe.InnerProductParameter)
+}
+
+void InnerProductParameter::SharedCtor() {
+  _cached_size_ = 0;
+  weight_filler_ = NULL;
+  bias_filler_ = NULL;
+  num_output_ = 0u;
+  bias_term_ = true;
+  axis_ = 1;
+}
+
+InnerProductParameter::~InnerProductParameter() {
+  // @@protoc_insertion_point(destructor:caffe.InnerProductParameter)
+  SharedDtor();
+}
+
+void InnerProductParameter::SharedDtor() {
+  if (this != &InnerProductParameter_default_instance_.get()) {
+    delete weight_filler_;
+    delete bias_filler_;
+  }
+}
+
+void InnerProductParameter::SetCachedSize(int size) const {
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* InnerProductParameter::descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return InnerProductParameter_descriptor_;
+}
+
+const InnerProductParameter& InnerProductParameter::default_instance() {
+  protobuf_InitDefaults_caffe_2eproto();
+  return *internal_default_instance();
+}
+
+::google::protobuf::internal::ExplicitlyConstructed<InnerProductParameter> InnerProductParameter_default_instance_;
+
+InnerProductParameter* InnerProductParameter::New(::google::protobuf::Arena* arena) const {
+  InnerProductParameter* n = new InnerProductParameter;
+  if (arena != NULL) {
+    arena->Own(n);
+  }
+  return n;
+}
+
+void InnerProductParameter::Clear() {
+// @@protoc_insertion_point(message_clear_start:caffe.InnerProductParameter)
+  if (_has_bits_[0 / 32] & 31u) {
+    num_output_ = 0u;
+    bias_term_ = true;
+    if (has_weight_filler()) {
+      if (weight_filler_ != NULL) weight_filler_->::caffe::FillerParameter::Clear();
+    }
+    if (has_bias_filler()) {
+      if (bias_filler_ != NULL) bias_filler_->::caffe::FillerParameter::Clear();
+    }
+    axis_ = 1;
+  }
+  _has_bits_.Clear();
+  if (_internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->Clear();
+  }
+}
+
+bool InnerProductParameter::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
+  ::google::protobuf::uint32 tag;
+  // @@protoc_insertion_point(parse_start:caffe.InnerProductParameter)
+  for (;;) {
+    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+    tag = p.first;
+    if (!p.second) goto handle_unusual;
+    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+      // optional uint32 num_output = 1;
+      case 1: {
+        if (tag == 8) {
+          set_has_num_output();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>(
+                 input, &num_output_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(16)) goto parse_bias_term;
+        break;
+      }
+
+      // optional bool bias_term = 2 [default = true];
+      case 2: {
+        if (tag == 16) {
+         parse_bias_term:
+          set_has_bias_term();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>(
+                 input, &bias_term_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(26)) goto parse_weight_filler;
+        break;
+      }
+
+      // optional .caffe.FillerParameter weight_filler = 3;
+      case 3: {
+        if (tag == 26) {
+         parse_weight_filler:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+               input, mutable_weight_filler()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(34)) goto parse_bias_filler;
+        break;
+      }
+
+      // optional .caffe.FillerParameter bias_filler = 4;
+      case 4: {
+        if (tag == 34) {
+         parse_bias_filler:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+               input, mutable_bias_filler()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(40)) goto parse_axis;
+        break;
+      }
+
+      // optional int32 axis = 5 [default = 1];
+      case 5: {
+        if (tag == 40) {
+         parse_axis:
+          set_has_axis();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
+                 input, &axis_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectAtEnd()) goto success;
+        break;
+      }
+
+      default: {
+      handle_unusual:
+        if (tag == 0 ||
+            ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+          goto success;
+        }
+        DO_(::google::protobuf::internal::WireFormat::SkipField(
+              input, tag, mutable_unknown_fields()));
+        break;
+      }
+    }
+  }
+success:
+  // @@protoc_insertion_point(parse_success:caffe.InnerProductParameter)
+  return true;
+failure:
+  // @@protoc_insertion_point(parse_failure:caffe.InnerProductParameter)
+  return false;
+#undef DO_
+}
+
+void InnerProductParameter::SerializeWithCachedSizes(
+    ::google::protobuf::io::CodedOutputStream* output) const {
+  // @@protoc_insertion_point(serialize_start:caffe.InnerProductParameter)
+  // optional uint32 num_output = 1;
+  if (has_num_output()) {
+    ::google::protobuf::internal::WireFormatLite::WriteUInt32(1, this->num_output(), output);
+  }
+
+  // optional bool bias_term = 2 [default = true];
+  if (has_bias_term()) {
+    ::google::protobuf::internal::WireFormatLite::WriteBool(2, this->bias_term(), output);
+  }
+
+  // optional .caffe.FillerParameter weight_filler = 3;
+  if (has_weight_filler()) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      3, *this->weight_filler_, output);
+  }
+
+  // optional .caffe.FillerParameter bias_filler = 4;
+  if (has_bias_filler()) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      4, *this->bias_filler_, output);
+  }
+
+  // optional int32 axis = 5 [default = 1];
+  if (has_axis()) {
+    ::google::protobuf::internal::WireFormatLite::WriteInt32(5, this->axis(), output);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
+        unknown_fields(), output);
+  }
+  // @@protoc_insertion_point(serialize_end:caffe.InnerProductParameter)
+}
+
+::google::protobuf::uint8* InnerProductParameter::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
+  (void)deterministic; // Unused
+  // @@protoc_insertion_point(serialize_to_array_start:caffe.InnerProductParameter)
+  // optional uint32 num_output = 1;
+  if (has_num_output()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteUInt32ToArray(1, this->num_output(), target);
+  }
+
+  // optional bool bias_term = 2 [default = true];
+  if (has_bias_term()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(2, this->bias_term(), target);
+  }
+
+  // optional .caffe.FillerParameter weight_filler = 3;
+  if (has_weight_filler()) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        3, *this->weight_filler_, false, target);
+  }
+
+  // optional .caffe.FillerParameter bias_filler = 4;
+  if (has_bias_filler()) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        4, *this->bias_filler_, false, target);
+  }
+
+  // optional int32 axis = 5 [default = 1];
+  if (has_axis()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteInt32ToArray(5, this->axis(), target);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
+        unknown_fields(), target);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:caffe.InnerProductParameter)
+  return target;
+}
+
+size_t InnerProductParameter::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:caffe.InnerProductParameter)
+  size_t total_size = 0;
+
+  if (_has_bits_[0 / 32] & 31u) {
+    // optional uint32 num_output = 1;
+    if (has_num_output()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::UInt32Size(
+          this->num_output());
+    }
+
+    // optional bool bias_term = 2 [default = true];
+    if (has_bias_term()) {
+      total_size += 1 + 1;
+    }
+
+    // optional .caffe.FillerParameter weight_filler = 3;
+    if (has_weight_filler()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          *this->weight_filler_);
+    }
+
+    // optional .caffe.FillerParameter bias_filler = 4;
+    if (has_bias_filler()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          *this->bias_filler_);
+    }
+
+    // optional int32 axis = 5 [default = 1];
+    if (has_axis()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::Int32Size(
+          this->axis());
+    }
+
+  }
+  if (_internal_metadata_.have_unknown_fields()) {
+    total_size +=
+      ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
+        unknown_fields());
+  }
+  int cached_size = ::google::protobuf::internal::ToCachedSize(total_size);
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = cached_size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+  return total_size;
+}
+
+void InnerProductParameter::MergeFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_merge_from_start:caffe.InnerProductParameter)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const InnerProductParameter* source =
+      ::google::protobuf::internal::DynamicCastToGenerated<const InnerProductParameter>(
+          &from);
+  if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:caffe.InnerProductParameter)
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:caffe.InnerProductParameter)
+    UnsafeMergeFrom(*source);
+  }
+}
+
+void InnerProductParameter::MergeFrom(const InnerProductParameter& from) {
+// @@protoc_insertion_point(class_specific_merge_from_start:caffe.InnerProductParameter)
+  if (GOOGLE_PREDICT_TRUE(&from != this)) {
+    UnsafeMergeFrom(from);
+  } else {
+    MergeFromFail(__LINE__);
+  }
+}
+
+void InnerProductParameter::UnsafeMergeFrom(const InnerProductParameter& from) {
+  GOOGLE_DCHECK(&from != this);
+  if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+    if (from.has_num_output()) {
+      set_num_output(from.num_output());
+    }
+    if (from.has_bias_term()) {
+      set_bias_term(from.bias_term());
+    }
+    if (from.has_weight_filler()) {
+      mutable_weight_filler()->::caffe::FillerParameter::MergeFrom(from.weight_filler());
+    }
+    if (from.has_bias_filler()) {
+      mutable_bias_filler()->::caffe::FillerParameter::MergeFrom(from.bias_filler());
+    }
+    if (from.has_axis()) {
+      set_axis(from.axis());
+    }
+  }
+  if (from._internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::UnknownFieldSet::MergeToInternalMetdata(
+      from.unknown_fields(), &_internal_metadata_);
+  }
+}
+
+void InnerProductParameter::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:caffe.InnerProductParameter)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void InnerProductParameter::CopyFrom(const InnerProductParameter& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:caffe.InnerProductParameter)
+  if (&from == this) return;
+  Clear();
+  UnsafeMergeFrom(from);
+}
+
+bool InnerProductParameter::IsInitialized() const {
+
+  return true;
+}
+
+void InnerProductParameter::Swap(InnerProductParameter* other) {
+  if (other == this) return;
+  InternalSwap(other);
+}
+void InnerProductParameter::InternalSwap(InnerProductParameter* other) {
+  std::swap(num_output_, other->num_output_);
+  std::swap(bias_term_, other->bias_term_);
+  std::swap(weight_filler_, other->weight_filler_);
+  std::swap(bias_filler_, other->bias_filler_);
+  std::swap(axis_, other->axis_);
+  std::swap(_has_bits_[0], other->_has_bits_[0]);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
+}
+
+::google::protobuf::Metadata InnerProductParameter::GetMetadata() const {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::Metadata metadata;
+  metadata.descriptor = InnerProductParameter_descriptor_;
+  metadata.reflection = InnerProductParameter_reflection_;
+  return metadata;
+}
+
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// InnerProductParameter
+
+// optional uint32 num_output = 1;
+bool InnerProductParameter::has_num_output() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+void InnerProductParameter::set_has_num_output() {
+  _has_bits_[0] |= 0x00000001u;
+}
+void InnerProductParameter::clear_has_num_output() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+void InnerProductParameter::clear_num_output() {
+  num_output_ = 0u;
+  clear_has_num_output();
+}
+::google::protobuf::uint32 InnerProductParameter::num_output() const {
+  // @@protoc_insertion_point(field_get:caffe.InnerProductParameter.num_output)
+  return num_output_;
+}
+void InnerProductParameter::set_num_output(::google::protobuf::uint32 value) {
+  set_has_num_output();
+  num_output_ = value;
+  // @@protoc_insertion_point(field_set:caffe.InnerProductParameter.num_output)
+}
+
+// optional bool bias_term = 2 [default = true];
+bool InnerProductParameter::has_bias_term() const {
+  return (_has_bits_[0] & 0x00000002u) != 0;
+}
+void InnerProductParameter::set_has_bias_term() {
+  _has_bits_[0] |= 0x00000002u;
+}
+void InnerProductParameter::clear_has_bias_term() {
+  _has_bits_[0] &= ~0x00000002u;
+}
+void InnerProductParameter::clear_bias_term() {
+  bias_term_ = true;
+  clear_has_bias_term();
+}
+bool InnerProductParameter::bias_term() const {
+  // @@protoc_insertion_point(field_get:caffe.InnerProductParameter.bias_term)
+  return bias_term_;
+}
+void InnerProductParameter::set_bias_term(bool value) {
+  set_has_bias_term();
+  bias_term_ = value;
+  // @@protoc_insertion_point(field_set:caffe.InnerProductParameter.bias_term)
+}
+
+// optional .caffe.FillerParameter weight_filler = 3;
+bool InnerProductParameter::has_weight_filler() const {
+  return (_has_bits_[0] & 0x00000004u) != 0;
+}
+void InnerProductParameter::set_has_weight_filler() {
+  _has_bits_[0] |= 0x00000004u;
+}
+void InnerProductParameter::clear_has_weight_filler() {
+  _has_bits_[0] &= ~0x00000004u;
+}
+void InnerProductParameter::clear_weight_filler() {
+  if (weight_filler_ != NULL) weight_filler_->::caffe::FillerParameter::Clear();
+  clear_has_weight_filler();
+}
+const ::caffe::FillerParameter& InnerProductParameter::weight_filler() const {
+  // @@protoc_insertion_point(field_get:caffe.InnerProductParameter.weight_filler)
+  return weight_filler_ != NULL ? *weight_filler_
+                         : *::caffe::FillerParameter::internal_default_instance();
+}
+::caffe::FillerParameter* InnerProductParameter::mutable_weight_filler() {
+  set_has_weight_filler();
+  if (weight_filler_ == NULL) {
+    weight_filler_ = new ::caffe::FillerParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.InnerProductParameter.weight_filler)
+  return weight_filler_;
+}
+::caffe::FillerParameter* InnerProductParameter::release_weight_filler() {
+  // @@protoc_insertion_point(field_release:caffe.InnerProductParameter.weight_filler)
+  clear_has_weight_filler();
+  ::caffe::FillerParameter* temp = weight_filler_;
+  weight_filler_ = NULL;
+  return temp;
+}
+void InnerProductParameter::set_allocated_weight_filler(::caffe::FillerParameter* weight_filler) {
+  delete weight_filler_;
+  weight_filler_ = weight_filler;
+  if (weight_filler) {
+    set_has_weight_filler();
+  } else {
+    clear_has_weight_filler();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.InnerProductParameter.weight_filler)
+}
+
+// optional .caffe.FillerParameter bias_filler = 4;
+bool InnerProductParameter::has_bias_filler() const {
+  return (_has_bits_[0] & 0x00000008u) != 0;
+}
+void InnerProductParameter::set_has_bias_filler() {
+  _has_bits_[0] |= 0x00000008u;
+}
+void InnerProductParameter::clear_has_bias_filler() {
+  _has_bits_[0] &= ~0x00000008u;
+}
+void InnerProductParameter::clear_bias_filler() {
+  if (bias_filler_ != NULL) bias_filler_->::caffe::FillerParameter::Clear();
+  clear_has_bias_filler();
+}
+const ::caffe::FillerParameter& InnerProductParameter::bias_filler() const {
+  // @@protoc_insertion_point(field_get:caffe.InnerProductParameter.bias_filler)
+  return bias_filler_ != NULL ? *bias_filler_
+                         : *::caffe::FillerParameter::internal_default_instance();
+}
+::caffe::FillerParameter* InnerProductParameter::mutable_bias_filler() {
+  set_has_bias_filler();
+  if (bias_filler_ == NULL) {
+    bias_filler_ = new ::caffe::FillerParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.InnerProductParameter.bias_filler)
+  return bias_filler_;
+}
+::caffe::FillerParameter* InnerProductParameter::release_bias_filler() {
+  // @@protoc_insertion_point(field_release:caffe.InnerProductParameter.bias_filler)
+  clear_has_bias_filler();
+  ::caffe::FillerParameter* temp = bias_filler_;
+  bias_filler_ = NULL;
+  return temp;
+}
+void InnerProductParameter::set_allocated_bias_filler(::caffe::FillerParameter* bias_filler) {
+  delete bias_filler_;
+  bias_filler_ = bias_filler;
+  if (bias_filler) {
+    set_has_bias_filler();
+  } else {
+    clear_has_bias_filler();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.InnerProductParameter.bias_filler)
+}
+
+// optional int32 axis = 5 [default = 1];
+bool InnerProductParameter::has_axis() const {
+  return (_has_bits_[0] & 0x00000010u) != 0;
+}
+void InnerProductParameter::set_has_axis() {
+  _has_bits_[0] |= 0x00000010u;
+}
+void InnerProductParameter::clear_has_axis() {
+  _has_bits_[0] &= ~0x00000010u;
+}
+void InnerProductParameter::clear_axis() {
+  axis_ = 1;
+  clear_has_axis();
+}
+::google::protobuf::int32 InnerProductParameter::axis() const {
+  // @@protoc_insertion_point(field_get:caffe.InnerProductParameter.axis)
+  return axis_;
+}
+void InnerProductParameter::set_axis(::google::protobuf::int32 value) {
+  set_has_axis();
+  axis_ = value;
+  // @@protoc_insertion_point(field_set:caffe.InnerProductParameter.axis)
+}
+
+inline const InnerProductParameter* InnerProductParameter::internal_default_instance() {
+  return &InnerProductParameter_default_instance_.get();
+}
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
+
+// ===================================================================
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const int LogParameter::kBaseFieldNumber;
+const int LogParameter::kScaleFieldNumber;
+const int LogParameter::kShiftFieldNumber;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+
+LogParameter::LogParameter()
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+  if (this != internal_default_instance()) protobuf_InitDefaults_caffe_2eproto();
+  SharedCtor();
+  // @@protoc_insertion_point(constructor:caffe.LogParameter)
+}
+
+void LogParameter::InitAsDefaultInstance() {
+}
+
+LogParameter::LogParameter(const LogParameter& from)
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
+  SharedCtor();
+  UnsafeMergeFrom(from);
+  // @@protoc_insertion_point(copy_constructor:caffe.LogParameter)
+}
+
+void LogParameter::SharedCtor() {
+  _cached_size_ = 0;
+  shift_ = 0;
+  base_ = -1;
+  scale_ = 1;
+}
+
+LogParameter::~LogParameter() {
+  // @@protoc_insertion_point(destructor:caffe.LogParameter)
+  SharedDtor();
+}
+
+void LogParameter::SharedDtor() {
+}
+
+void LogParameter::SetCachedSize(int size) const {
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* LogParameter::descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return LogParameter_descriptor_;
+}
+
+const LogParameter& LogParameter::default_instance() {
+  protobuf_InitDefaults_caffe_2eproto();
+  return *internal_default_instance();
+}
+
+::google::protobuf::internal::ExplicitlyConstructed<LogParameter> LogParameter_default_instance_;
+
+LogParameter* LogParameter::New(::google::protobuf::Arena* arena) const {
+  LogParameter* n = new LogParameter;
+  if (arena != NULL) {
+    arena->Own(n);
+  }
+  return n;
+}
+
+void LogParameter::Clear() {
+// @@protoc_insertion_point(message_clear_start:caffe.LogParameter)
+  if (_has_bits_[0 / 32] & 7u) {
+    base_ = -1;
+    scale_ = 1;
+    shift_ = 0;
+  }
+  _has_bits_.Clear();
+  if (_internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->Clear();
+  }
+}
+
+bool LogParameter::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
+  ::google::protobuf::uint32 tag;
+  // @@protoc_insertion_point(parse_start:caffe.LogParameter)
+  for (;;) {
+    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+    tag = p.first;
+    if (!p.second) goto handle_unusual;
+    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+      // optional float base = 1 [default = -1];
+      case 1: {
+        if (tag == 13) {
+          set_has_base();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
+                 input, &base_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(21)) goto parse_scale;
+        break;
+      }
+
+      // optional float scale = 2 [default = 1];
+      case 2: {
+        if (tag == 21) {
+         parse_scale:
+          set_has_scale();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
+                 input, &scale_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(29)) goto parse_shift;
+        break;
+      }
+
+      // optional float shift = 3 [default = 0];
+      case 3: {
+        if (tag == 29) {
+         parse_shift:
+          set_has_shift();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
+                 input, &shift_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectAtEnd()) goto success;
+        break;
+      }
+
+      default: {
+      handle_unusual:
+        if (tag == 0 ||
+            ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+          goto success;
+        }
+        DO_(::google::protobuf::internal::WireFormat::SkipField(
+              input, tag, mutable_unknown_fields()));
+        break;
+      }
+    }
+  }
+success:
+  // @@protoc_insertion_point(parse_success:caffe.LogParameter)
+  return true;
+failure:
+  // @@protoc_insertion_point(parse_failure:caffe.LogParameter)
+  return false;
+#undef DO_
+}
+
+void LogParameter::SerializeWithCachedSizes(
+    ::google::protobuf::io::CodedOutputStream* output) const {
+  // @@protoc_insertion_point(serialize_start:caffe.LogParameter)
+  // optional float base = 1 [default = -1];
+  if (has_base()) {
+    ::google::protobuf::internal::WireFormatLite::WriteFloat(1, this->base(), output);
+  }
+
+  // optional float scale = 2 [default = 1];
+  if (has_scale()) {
+    ::google::protobuf::internal::WireFormatLite::WriteFloat(2, this->scale(), output);
+  }
+
+  // optional float shift = 3 [default = 0];
+  if (has_shift()) {
+    ::google::protobuf::internal::WireFormatLite::WriteFloat(3, this->shift(), output);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
+        unknown_fields(), output);
+  }
+  // @@protoc_insertion_point(serialize_end:caffe.LogParameter)
+}
+
+::google::protobuf::uint8* LogParameter::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
+  (void)deterministic; // Unused
+  // @@protoc_insertion_point(serialize_to_array_start:caffe.LogParameter)
+  // optional float base = 1 [default = -1];
+  if (has_base()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteFloatToArray(1, this->base(), target);
+  }
+
+  // optional float scale = 2 [default = 1];
+  if (has_scale()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteFloatToArray(2, this->scale(), target);
+  }
+
+  // optional float shift = 3 [default = 0];
+  if (has_shift()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteFloatToArray(3, this->shift(), target);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
+        unknown_fields(), target);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:caffe.LogParameter)
+  return target;
+}
+
+size_t LogParameter::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:caffe.LogParameter)
+  size_t total_size = 0;
+
+  if (_has_bits_[0 / 32] & 7u) {
+    // optional float base = 1 [default = -1];
+    if (has_base()) {
+      total_size += 1 + 4;
+    }
+
+    // optional float scale = 2 [default = 1];
+    if (has_scale()) {
+      total_size += 1 + 4;
+    }
+
+    // optional float shift = 3 [default = 0];
+    if (has_shift()) {
+      total_size += 1 + 4;
+    }
+
+  }
+  if (_internal_metadata_.have_unknown_fields()) {
+    total_size +=
+      ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
+        unknown_fields());
+  }
+  int cached_size = ::google::protobuf::internal::ToCachedSize(total_size);
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = cached_size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+  return total_size;
+}
+
+void LogParameter::MergeFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_merge_from_start:caffe.LogParameter)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const LogParameter* source =
+      ::google::protobuf::internal::DynamicCastToGenerated<const LogParameter>(
+          &from);
+  if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:caffe.LogParameter)
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:caffe.LogParameter)
+    UnsafeMergeFrom(*source);
+  }
+}
+
+void LogParameter::MergeFrom(const LogParameter& from) {
+// @@protoc_insertion_point(class_specific_merge_from_start:caffe.LogParameter)
+  if (GOOGLE_PREDICT_TRUE(&from != this)) {
+    UnsafeMergeFrom(from);
+  } else {
+    MergeFromFail(__LINE__);
+  }
+}
+
+void LogParameter::UnsafeMergeFrom(const LogParameter& from) {
+  GOOGLE_DCHECK(&from != this);
+  if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+    if (from.has_base()) {
+      set_base(from.base());
+    }
+    if (from.has_scale()) {
+      set_scale(from.scale());
+    }
+    if (from.has_shift()) {
+      set_shift(from.shift());
+    }
+  }
+  if (from._internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::UnknownFieldSet::MergeToInternalMetdata(
+      from.unknown_fields(), &_internal_metadata_);
+  }
+}
+
+void LogParameter::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:caffe.LogParameter)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void LogParameter::CopyFrom(const LogParameter& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:caffe.LogParameter)
+  if (&from == this) return;
+  Clear();
+  UnsafeMergeFrom(from);
+}
+
+bool LogParameter::IsInitialized() const {
+
+  return true;
+}
+
+void LogParameter::Swap(LogParameter* other) {
+  if (other == this) return;
+  InternalSwap(other);
+}
+void LogParameter::InternalSwap(LogParameter* other) {
+  std::swap(base_, other->base_);
+  std::swap(scale_, other->scale_);
+  std::swap(shift_, other->shift_);
+  std::swap(_has_bits_[0], other->_has_bits_[0]);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
+}
+
+::google::protobuf::Metadata LogParameter::GetMetadata() const {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::Metadata metadata;
+  metadata.descriptor = LogParameter_descriptor_;
+  metadata.reflection = LogParameter_reflection_;
+  return metadata;
+}
+
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// LogParameter
+
+// optional float base = 1 [default = -1];
+bool LogParameter::has_base() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+void LogParameter::set_has_base() {
+  _has_bits_[0] |= 0x00000001u;
+}
+void LogParameter::clear_has_base() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+void LogParameter::clear_base() {
+  base_ = -1;
+  clear_has_base();
+}
+float LogParameter::base() const {
+  // @@protoc_insertion_point(field_get:caffe.LogParameter.base)
+  return base_;
+}
+void LogParameter::set_base(float value) {
+  set_has_base();
+  base_ = value;
+  // @@protoc_insertion_point(field_set:caffe.LogParameter.base)
+}
+
+// optional float scale = 2 [default = 1];
+bool LogParameter::has_scale() const {
+  return (_has_bits_[0] & 0x00000002u) != 0;
+}
+void LogParameter::set_has_scale() {
+  _has_bits_[0] |= 0x00000002u;
+}
+void LogParameter::clear_has_scale() {
+  _has_bits_[0] &= ~0x00000002u;
+}
+void LogParameter::clear_scale() {
+  scale_ = 1;
+  clear_has_scale();
+}
+float LogParameter::scale() const {
+  // @@protoc_insertion_point(field_get:caffe.LogParameter.scale)
+  return scale_;
+}
+void LogParameter::set_scale(float value) {
+  set_has_scale();
+  scale_ = value;
+  // @@protoc_insertion_point(field_set:caffe.LogParameter.scale)
+}
+
+// optional float shift = 3 [default = 0];
+bool LogParameter::has_shift() const {
+  return (_has_bits_[0] & 0x00000004u) != 0;
+}
+void LogParameter::set_has_shift() {
+  _has_bits_[0] |= 0x00000004u;
+}
+void LogParameter::clear_has_shift() {
+  _has_bits_[0] &= ~0x00000004u;
+}
+void LogParameter::clear_shift() {
+  shift_ = 0;
+  clear_has_shift();
+}
+float LogParameter::shift() const {
+  // @@protoc_insertion_point(field_get:caffe.LogParameter.shift)
+  return shift_;
+}
+void LogParameter::set_shift(float value) {
+  set_has_shift();
+  shift_ = value;
+  // @@protoc_insertion_point(field_set:caffe.LogParameter.shift)
+}
+
+inline const LogParameter* LogParameter::internal_default_instance() {
+  return &LogParameter_default_instance_.get();
+}
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
+
+// ===================================================================
+
+const ::google::protobuf::EnumDescriptor* LRNParameter_NormRegion_descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return LRNParameter_NormRegion_descriptor_;
+}
+bool LRNParameter_NormRegion_IsValid(int value) {
+  switch (value) {
+    case 0:
+    case 1:
+      return true;
+    default:
+      return false;
+  }
+}
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const LRNParameter_NormRegion LRNParameter::ACROSS_CHANNELS;
+const LRNParameter_NormRegion LRNParameter::WITHIN_CHANNEL;
+const LRNParameter_NormRegion LRNParameter::NormRegion_MIN;
+const LRNParameter_NormRegion LRNParameter::NormRegion_MAX;
+const int LRNParameter::NormRegion_ARRAYSIZE;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const int LRNParameter::kLocalSizeFieldNumber;
+const int LRNParameter::kAlphaFieldNumber;
+const int LRNParameter::kBetaFieldNumber;
+const int LRNParameter::kNormRegionFieldNumber;
+const int LRNParameter::kKFieldNumber;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+
+LRNParameter::LRNParameter()
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+  if (this != internal_default_instance()) protobuf_InitDefaults_caffe_2eproto();
+  SharedCtor();
+  // @@protoc_insertion_point(constructor:caffe.LRNParameter)
+}
+
+void LRNParameter::InitAsDefaultInstance() {
+}
+
+LRNParameter::LRNParameter(const LRNParameter& from)
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
+  SharedCtor();
+  UnsafeMergeFrom(from);
+  // @@protoc_insertion_point(copy_constructor:caffe.LRNParameter)
+}
+
+void LRNParameter::SharedCtor() {
+  _cached_size_ = 0;
+  norm_region_ = 0;
+  local_size_ = 5u;
+  alpha_ = 1;
+  beta_ = 0.75f;
+  k_ = 1;
+}
+
+LRNParameter::~LRNParameter() {
+  // @@protoc_insertion_point(destructor:caffe.LRNParameter)
+  SharedDtor();
+}
+
+void LRNParameter::SharedDtor() {
+}
+
+void LRNParameter::SetCachedSize(int size) const {
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* LRNParameter::descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return LRNParameter_descriptor_;
+}
+
+const LRNParameter& LRNParameter::default_instance() {
+  protobuf_InitDefaults_caffe_2eproto();
+  return *internal_default_instance();
+}
+
+::google::protobuf::internal::ExplicitlyConstructed<LRNParameter> LRNParameter_default_instance_;
+
+LRNParameter* LRNParameter::New(::google::protobuf::Arena* arena) const {
+  LRNParameter* n = new LRNParameter;
+  if (arena != NULL) {
+    arena->Own(n);
+  }
+  return n;
+}
+
+void LRNParameter::Clear() {
+// @@protoc_insertion_point(message_clear_start:caffe.LRNParameter)
+  if (_has_bits_[0 / 32] & 31u) {
+    local_size_ = 5u;
+    alpha_ = 1;
+    beta_ = 0.75f;
+    norm_region_ = 0;
+    k_ = 1;
+  }
+  _has_bits_.Clear();
+  if (_internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->Clear();
+  }
+}
+
+bool LRNParameter::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
+  ::google::protobuf::uint32 tag;
+  // @@protoc_insertion_point(parse_start:caffe.LRNParameter)
+  for (;;) {
+    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+    tag = p.first;
+    if (!p.second) goto handle_unusual;
+    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+      // optional uint32 local_size = 1 [default = 5];
+      case 1: {
+        if (tag == 8) {
+          set_has_local_size();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>(
+                 input, &local_size_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(21)) goto parse_alpha;
+        break;
+      }
+
+      // optional float alpha = 2 [default = 1];
+      case 2: {
+        if (tag == 21) {
+         parse_alpha:
+          set_has_alpha();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
+                 input, &alpha_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(29)) goto parse_beta;
+        break;
+      }
+
+      // optional float beta = 3 [default = 0.75];
+      case 3: {
+        if (tag == 29) {
+         parse_beta:
+          set_has_beta();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
+                 input, &beta_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(32)) goto parse_norm_region;
+        break;
+      }
+
+      // optional .caffe.LRNParameter.NormRegion norm_region = 4 [default = ACROSS_CHANNELS];
+      case 4: {
+        if (tag == 32) {
+         parse_norm_region:
+          int value;
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>(
+                 input, &value)));
+          if (::caffe::LRNParameter_NormRegion_IsValid(value)) {
+            set_norm_region(static_cast< ::caffe::LRNParameter_NormRegion >(value));
+          } else {
+            mutable_unknown_fields()->AddVarint(4, value);
+          }
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(45)) goto parse_k;
+        break;
+      }
+
+      // optional float k = 5 [default = 1];
+      case 5: {
+        if (tag == 45) {
+         parse_k:
+          set_has_k();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
+                 input, &k_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectAtEnd()) goto success;
+        break;
+      }
+
+      default: {
+      handle_unusual:
+        if (tag == 0 ||
+            ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+          goto success;
+        }
+        DO_(::google::protobuf::internal::WireFormat::SkipField(
+              input, tag, mutable_unknown_fields()));
+        break;
+      }
+    }
+  }
+success:
+  // @@protoc_insertion_point(parse_success:caffe.LRNParameter)
+  return true;
+failure:
+  // @@protoc_insertion_point(parse_failure:caffe.LRNParameter)
+  return false;
+#undef DO_
+}
+
+void LRNParameter::SerializeWithCachedSizes(
+    ::google::protobuf::io::CodedOutputStream* output) const {
+  // @@protoc_insertion_point(serialize_start:caffe.LRNParameter)
+  // optional uint32 local_size = 1 [default = 5];
+  if (has_local_size()) {
+    ::google::protobuf::internal::WireFormatLite::WriteUInt32(1, this->local_size(), output);
+  }
+
+  // optional float alpha = 2 [default = 1];
+  if (has_alpha()) {
+    ::google::protobuf::internal::WireFormatLite::WriteFloat(2, this->alpha(), output);
+  }
+
+  // optional float beta = 3 [default = 0.75];
+  if (has_beta()) {
+    ::google::protobuf::internal::WireFormatLite::WriteFloat(3, this->beta(), output);
+  }
+
+  // optional .caffe.LRNParameter.NormRegion norm_region = 4 [default = ACROSS_CHANNELS];
+  if (has_norm_region()) {
+    ::google::protobuf::internal::WireFormatLite::WriteEnum(
+      4, this->norm_region(), output);
+  }
+
+  // optional float k = 5 [default = 1];
+  if (has_k()) {
+    ::google::protobuf::internal::WireFormatLite::WriteFloat(5, this->k(), output);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
+        unknown_fields(), output);
+  }
+  // @@protoc_insertion_point(serialize_end:caffe.LRNParameter)
+}
+
+::google::protobuf::uint8* LRNParameter::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
+  (void)deterministic; // Unused
+  // @@protoc_insertion_point(serialize_to_array_start:caffe.LRNParameter)
+  // optional uint32 local_size = 1 [default = 5];
+  if (has_local_size()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteUInt32ToArray(1, this->local_size(), target);
+  }
+
+  // optional float alpha = 2 [default = 1];
+  if (has_alpha()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteFloatToArray(2, this->alpha(), target);
+  }
+
+  // optional float beta = 3 [default = 0.75];
+  if (has_beta()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteFloatToArray(3, this->beta(), target);
+  }
+
+  // optional .caffe.LRNParameter.NormRegion norm_region = 4 [default = ACROSS_CHANNELS];
+  if (has_norm_region()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteEnumToArray(
+      4, this->norm_region(), target);
+  }
+
+  // optional float k = 5 [default = 1];
+  if (has_k()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteFloatToArray(5, this->k(), target);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
+        unknown_fields(), target);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:caffe.LRNParameter)
+  return target;
+}
+
+size_t LRNParameter::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:caffe.LRNParameter)
+  size_t total_size = 0;
+
+  if (_has_bits_[0 / 32] & 31u) {
+    // optional uint32 local_size = 1 [default = 5];
+    if (has_local_size()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::UInt32Size(
+          this->local_size());
+    }
+
+    // optional float alpha = 2 [default = 1];
+    if (has_alpha()) {
+      total_size += 1 + 4;
+    }
+
+    // optional float beta = 3 [default = 0.75];
+    if (has_beta()) {
+      total_size += 1 + 4;
+    }
+
+    // optional .caffe.LRNParameter.NormRegion norm_region = 4 [default = ACROSS_CHANNELS];
+    if (has_norm_region()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::EnumSize(this->norm_region());
+    }
+
+    // optional float k = 5 [default = 1];
+    if (has_k()) {
+      total_size += 1 + 4;
+    }
+
+  }
+  if (_internal_metadata_.have_unknown_fields()) {
+    total_size +=
+      ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
+        unknown_fields());
+  }
+  int cached_size = ::google::protobuf::internal::ToCachedSize(total_size);
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = cached_size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+  return total_size;
+}
+
+void LRNParameter::MergeFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_merge_from_start:caffe.LRNParameter)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const LRNParameter* source =
+      ::google::protobuf::internal::DynamicCastToGenerated<const LRNParameter>(
+          &from);
+  if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:caffe.LRNParameter)
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:caffe.LRNParameter)
+    UnsafeMergeFrom(*source);
+  }
+}
+
+void LRNParameter::MergeFrom(const LRNParameter& from) {
+// @@protoc_insertion_point(class_specific_merge_from_start:caffe.LRNParameter)
+  if (GOOGLE_PREDICT_TRUE(&from != this)) {
+    UnsafeMergeFrom(from);
+  } else {
+    MergeFromFail(__LINE__);
+  }
+}
+
+void LRNParameter::UnsafeMergeFrom(const LRNParameter& from) {
+  GOOGLE_DCHECK(&from != this);
+  if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+    if (from.has_local_size()) {
+      set_local_size(from.local_size());
+    }
+    if (from.has_alpha()) {
+      set_alpha(from.alpha());
+    }
+    if (from.has_beta()) {
+      set_beta(from.beta());
+    }
+    if (from.has_norm_region()) {
+      set_norm_region(from.norm_region());
+    }
+    if (from.has_k()) {
+      set_k(from.k());
+    }
+  }
+  if (from._internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::UnknownFieldSet::MergeToInternalMetdata(
+      from.unknown_fields(), &_internal_metadata_);
+  }
+}
+
+void LRNParameter::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:caffe.LRNParameter)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void LRNParameter::CopyFrom(const LRNParameter& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:caffe.LRNParameter)
+  if (&from == this) return;
+  Clear();
+  UnsafeMergeFrom(from);
+}
+
+bool LRNParameter::IsInitialized() const {
+
+  return true;
+}
+
+void LRNParameter::Swap(LRNParameter* other) {
+  if (other == this) return;
+  InternalSwap(other);
+}
+void LRNParameter::InternalSwap(LRNParameter* other) {
+  std::swap(local_size_, other->local_size_);
+  std::swap(alpha_, other->alpha_);
+  std::swap(beta_, other->beta_);
+  std::swap(norm_region_, other->norm_region_);
+  std::swap(k_, other->k_);
+  std::swap(_has_bits_[0], other->_has_bits_[0]);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
+}
+
+::google::protobuf::Metadata LRNParameter::GetMetadata() const {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::Metadata metadata;
+  metadata.descriptor = LRNParameter_descriptor_;
+  metadata.reflection = LRNParameter_reflection_;
+  return metadata;
+}
+
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// LRNParameter
+
+// optional uint32 local_size = 1 [default = 5];
+bool LRNParameter::has_local_size() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+void LRNParameter::set_has_local_size() {
+  _has_bits_[0] |= 0x00000001u;
+}
+void LRNParameter::clear_has_local_size() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+void LRNParameter::clear_local_size() {
+  local_size_ = 5u;
+  clear_has_local_size();
+}
+::google::protobuf::uint32 LRNParameter::local_size() const {
+  // @@protoc_insertion_point(field_get:caffe.LRNParameter.local_size)
+  return local_size_;
+}
+void LRNParameter::set_local_size(::google::protobuf::uint32 value) {
+  set_has_local_size();
+  local_size_ = value;
+  // @@protoc_insertion_point(field_set:caffe.LRNParameter.local_size)
+}
+
+// optional float alpha = 2 [default = 1];
+bool LRNParameter::has_alpha() const {
+  return (_has_bits_[0] & 0x00000002u) != 0;
+}
+void LRNParameter::set_has_alpha() {
+  _has_bits_[0] |= 0x00000002u;
+}
+void LRNParameter::clear_has_alpha() {
+  _has_bits_[0] &= ~0x00000002u;
+}
+void LRNParameter::clear_alpha() {
+  alpha_ = 1;
+  clear_has_alpha();
+}
+float LRNParameter::alpha() const {
+  // @@protoc_insertion_point(field_get:caffe.LRNParameter.alpha)
+  return alpha_;
+}
+void LRNParameter::set_alpha(float value) {
+  set_has_alpha();
+  alpha_ = value;
+  // @@protoc_insertion_point(field_set:caffe.LRNParameter.alpha)
+}
+
+// optional float beta = 3 [default = 0.75];
+bool LRNParameter::has_beta() const {
+  return (_has_bits_[0] & 0x00000004u) != 0;
+}
+void LRNParameter::set_has_beta() {
+  _has_bits_[0] |= 0x00000004u;
+}
+void LRNParameter::clear_has_beta() {
+  _has_bits_[0] &= ~0x00000004u;
+}
+void LRNParameter::clear_beta() {
+  beta_ = 0.75f;
+  clear_has_beta();
+}
+float LRNParameter::beta() const {
+  // @@protoc_insertion_point(field_get:caffe.LRNParameter.beta)
+  return beta_;
+}
+void LRNParameter::set_beta(float value) {
+  set_has_beta();
+  beta_ = value;
+  // @@protoc_insertion_point(field_set:caffe.LRNParameter.beta)
+}
+
+// optional .caffe.LRNParameter.NormRegion norm_region = 4 [default = ACROSS_CHANNELS];
+bool LRNParameter::has_norm_region() const {
+  return (_has_bits_[0] & 0x00000008u) != 0;
+}
+void LRNParameter::set_has_norm_region() {
+  _has_bits_[0] |= 0x00000008u;
+}
+void LRNParameter::clear_has_norm_region() {
+  _has_bits_[0] &= ~0x00000008u;
+}
+void LRNParameter::clear_norm_region() {
+  norm_region_ = 0;
+  clear_has_norm_region();
+}
+::caffe::LRNParameter_NormRegion LRNParameter::norm_region() const {
+  // @@protoc_insertion_point(field_get:caffe.LRNParameter.norm_region)
+  return static_cast< ::caffe::LRNParameter_NormRegion >(norm_region_);
+}
+void LRNParameter::set_norm_region(::caffe::LRNParameter_NormRegion value) {
+  assert(::caffe::LRNParameter_NormRegion_IsValid(value));
+  set_has_norm_region();
+  norm_region_ = value;
+  // @@protoc_insertion_point(field_set:caffe.LRNParameter.norm_region)
+}
+
+// optional float k = 5 [default = 1];
+bool LRNParameter::has_k() const {
+  return (_has_bits_[0] & 0x00000010u) != 0;
+}
+void LRNParameter::set_has_k() {
+  _has_bits_[0] |= 0x00000010u;
+}
+void LRNParameter::clear_has_k() {
+  _has_bits_[0] &= ~0x00000010u;
+}
+void LRNParameter::clear_k() {
+  k_ = 1;
+  clear_has_k();
+}
+float LRNParameter::k() const {
+  // @@protoc_insertion_point(field_get:caffe.LRNParameter.k)
+  return k_;
+}
+void LRNParameter::set_k(float value) {
+  set_has_k();
+  k_ = value;
+  // @@protoc_insertion_point(field_set:caffe.LRNParameter.k)
+}
+
+inline const LRNParameter* LRNParameter::internal_default_instance() {
+  return &LRNParameter_default_instance_.get();
+}
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
+
+// ===================================================================
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const int MemoryDataParameter::kBatchSizeFieldNumber;
+const int MemoryDataParameter::kChannelsFieldNumber;
+const int MemoryDataParameter::kHeightFieldNumber;
+const int MemoryDataParameter::kWidthFieldNumber;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+
+MemoryDataParameter::MemoryDataParameter()
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+  if (this != internal_default_instance()) protobuf_InitDefaults_caffe_2eproto();
+  SharedCtor();
+  // @@protoc_insertion_point(constructor:caffe.MemoryDataParameter)
+}
+
+void MemoryDataParameter::InitAsDefaultInstance() {
+}
+
+MemoryDataParameter::MemoryDataParameter(const MemoryDataParameter& from)
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
+  SharedCtor();
+  UnsafeMergeFrom(from);
+  // @@protoc_insertion_point(copy_constructor:caffe.MemoryDataParameter)
+}
+
+void MemoryDataParameter::SharedCtor() {
+  _cached_size_ = 0;
+  ::memset(&batch_size_, 0, reinterpret_cast<char*>(&width_) -
+    reinterpret_cast<char*>(&batch_size_) + sizeof(width_));
+}
+
+MemoryDataParameter::~MemoryDataParameter() {
+  // @@protoc_insertion_point(destructor:caffe.MemoryDataParameter)
+  SharedDtor();
+}
+
+void MemoryDataParameter::SharedDtor() {
+}
+
+void MemoryDataParameter::SetCachedSize(int size) const {
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* MemoryDataParameter::descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return MemoryDataParameter_descriptor_;
+}
+
+const MemoryDataParameter& MemoryDataParameter::default_instance() {
+  protobuf_InitDefaults_caffe_2eproto();
+  return *internal_default_instance();
+}
+
+::google::protobuf::internal::ExplicitlyConstructed<MemoryDataParameter> MemoryDataParameter_default_instance_;
+
+MemoryDataParameter* MemoryDataParameter::New(::google::protobuf::Arena* arena) const {
+  MemoryDataParameter* n = new MemoryDataParameter;
+  if (arena != NULL) {
+    arena->Own(n);
+  }
+  return n;
+}
+
+void MemoryDataParameter::Clear() {
+// @@protoc_insertion_point(message_clear_start:caffe.MemoryDataParameter)
+#if defined(__clang__)
+#define ZR_HELPER_(f) \
+  _Pragma("clang diagnostic push") \
+  _Pragma("clang diagnostic ignored \"-Winvalid-offsetof\"") \
+  __builtin_offsetof(MemoryDataParameter, f) \
+  _Pragma("clang diagnostic pop")
+#else
+#define ZR_HELPER_(f) reinterpret_cast<char*>(\
+  &reinterpret_cast<MemoryDataParameter*>(16)->f)
+#endif
+
+#define ZR_(first, last) do {\
+  ::memset(&(first), 0,\
+           ZR_HELPER_(last) - ZR_HELPER_(first) + sizeof(last));\
+} while (0)
+
+  ZR_(batch_size_, width_);
+
+#undef ZR_HELPER_
+#undef ZR_
+
+  _has_bits_.Clear();
+  if (_internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->Clear();
+  }
+}
+
+bool MemoryDataParameter::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
+  ::google::protobuf::uint32 tag;
+  // @@protoc_insertion_point(parse_start:caffe.MemoryDataParameter)
+  for (;;) {
+    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+    tag = p.first;
+    if (!p.second) goto handle_unusual;
+    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+      // optional uint32 batch_size = 1;
+      case 1: {
+        if (tag == 8) {
+          set_has_batch_size();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>(
+                 input, &batch_size_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(16)) goto parse_channels;
+        break;
+      }
+
+      // optional uint32 channels = 2;
+      case 2: {
+        if (tag == 16) {
+         parse_channels:
+          set_has_channels();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>(
+                 input, &channels_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(24)) goto parse_height;
+        break;
+      }
+
+      // optional uint32 height = 3;
+      case 3: {
+        if (tag == 24) {
+         parse_height:
+          set_has_height();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>(
+                 input, &height_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(32)) goto parse_width;
+        break;
+      }
+
+      // optional uint32 width = 4;
+      case 4: {
+        if (tag == 32) {
+         parse_width:
+          set_has_width();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>(
+                 input, &width_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectAtEnd()) goto success;
+        break;
+      }
+
+      default: {
+      handle_unusual:
+        if (tag == 0 ||
+            ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+          goto success;
+        }
+        DO_(::google::protobuf::internal::WireFormat::SkipField(
+              input, tag, mutable_unknown_fields()));
+        break;
+      }
+    }
+  }
+success:
+  // @@protoc_insertion_point(parse_success:caffe.MemoryDataParameter)
+  return true;
+failure:
+  // @@protoc_insertion_point(parse_failure:caffe.MemoryDataParameter)
+  return false;
+#undef DO_
+}
+
+void MemoryDataParameter::SerializeWithCachedSizes(
+    ::google::protobuf::io::CodedOutputStream* output) const {
+  // @@protoc_insertion_point(serialize_start:caffe.MemoryDataParameter)
+  // optional uint32 batch_size = 1;
+  if (has_batch_size()) {
+    ::google::protobuf::internal::WireFormatLite::WriteUInt32(1, this->batch_size(), output);
+  }
+
+  // optional uint32 channels = 2;
+  if (has_channels()) {
+    ::google::protobuf::internal::WireFormatLite::WriteUInt32(2, this->channels(), output);
+  }
+
+  // optional uint32 height = 3;
+  if (has_height()) {
+    ::google::protobuf::internal::WireFormatLite::WriteUInt32(3, this->height(), output);
+  }
+
+  // optional uint32 width = 4;
+  if (has_width()) {
+    ::google::protobuf::internal::WireFormatLite::WriteUInt32(4, this->width(), output);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
+        unknown_fields(), output);
+  }
+  // @@protoc_insertion_point(serialize_end:caffe.MemoryDataParameter)
+}
+
+::google::protobuf::uint8* MemoryDataParameter::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
+  (void)deterministic; // Unused
+  // @@protoc_insertion_point(serialize_to_array_start:caffe.MemoryDataParameter)
+  // optional uint32 batch_size = 1;
+  if (has_batch_size()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteUInt32ToArray(1, this->batch_size(), target);
+  }
+
+  // optional uint32 channels = 2;
+  if (has_channels()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteUInt32ToArray(2, this->channels(), target);
+  }
+
+  // optional uint32 height = 3;
+  if (has_height()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteUInt32ToArray(3, this->height(), target);
+  }
+
+  // optional uint32 width = 4;
+  if (has_width()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteUInt32ToArray(4, this->width(), target);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
+        unknown_fields(), target);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:caffe.MemoryDataParameter)
+  return target;
+}
+
+size_t MemoryDataParameter::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:caffe.MemoryDataParameter)
+  size_t total_size = 0;
+
+  if (_has_bits_[0 / 32] & 15u) {
+    // optional uint32 batch_size = 1;
+    if (has_batch_size()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::UInt32Size(
+          this->batch_size());
+    }
+
+    // optional uint32 channels = 2;
+    if (has_channels()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::UInt32Size(
+          this->channels());
+    }
+
+    // optional uint32 height = 3;
+    if (has_height()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::UInt32Size(
+          this->height());
+    }
+
+    // optional uint32 width = 4;
+    if (has_width()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::UInt32Size(
+          this->width());
+    }
+
+  }
+  if (_internal_metadata_.have_unknown_fields()) {
+    total_size +=
+      ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
+        unknown_fields());
+  }
+  int cached_size = ::google::protobuf::internal::ToCachedSize(total_size);
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = cached_size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+  return total_size;
+}
+
+void MemoryDataParameter::MergeFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_merge_from_start:caffe.MemoryDataParameter)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const MemoryDataParameter* source =
+      ::google::protobuf::internal::DynamicCastToGenerated<const MemoryDataParameter>(
+          &from);
+  if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:caffe.MemoryDataParameter)
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:caffe.MemoryDataParameter)
+    UnsafeMergeFrom(*source);
+  }
+}
+
+void MemoryDataParameter::MergeFrom(const MemoryDataParameter& from) {
+// @@protoc_insertion_point(class_specific_merge_from_start:caffe.MemoryDataParameter)
+  if (GOOGLE_PREDICT_TRUE(&from != this)) {
+    UnsafeMergeFrom(from);
+  } else {
+    MergeFromFail(__LINE__);
+  }
+}
+
+void MemoryDataParameter::UnsafeMergeFrom(const MemoryDataParameter& from) {
+  GOOGLE_DCHECK(&from != this);
+  if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+    if (from.has_batch_size()) {
+      set_batch_size(from.batch_size());
+    }
+    if (from.has_channels()) {
+      set_channels(from.channels());
+    }
+    if (from.has_height()) {
+      set_height(from.height());
+    }
+    if (from.has_width()) {
+      set_width(from.width());
+    }
+  }
+  if (from._internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::UnknownFieldSet::MergeToInternalMetdata(
+      from.unknown_fields(), &_internal_metadata_);
+  }
+}
+
+void MemoryDataParameter::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:caffe.MemoryDataParameter)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void MemoryDataParameter::CopyFrom(const MemoryDataParameter& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:caffe.MemoryDataParameter)
+  if (&from == this) return;
+  Clear();
+  UnsafeMergeFrom(from);
+}
+
+bool MemoryDataParameter::IsInitialized() const {
+
+  return true;
+}
+
+void MemoryDataParameter::Swap(MemoryDataParameter* other) {
+  if (other == this) return;
+  InternalSwap(other);
+}
+void MemoryDataParameter::InternalSwap(MemoryDataParameter* other) {
+  std::swap(batch_size_, other->batch_size_);
+  std::swap(channels_, other->channels_);
+  std::swap(height_, other->height_);
+  std::swap(width_, other->width_);
+  std::swap(_has_bits_[0], other->_has_bits_[0]);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
+}
+
+::google::protobuf::Metadata MemoryDataParameter::GetMetadata() const {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::Metadata metadata;
+  metadata.descriptor = MemoryDataParameter_descriptor_;
+  metadata.reflection = MemoryDataParameter_reflection_;
+  return metadata;
+}
+
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// MemoryDataParameter
+
+// optional uint32 batch_size = 1;
+bool MemoryDataParameter::has_batch_size() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+void MemoryDataParameter::set_has_batch_size() {
+  _has_bits_[0] |= 0x00000001u;
+}
+void MemoryDataParameter::clear_has_batch_size() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+void MemoryDataParameter::clear_batch_size() {
+  batch_size_ = 0u;
+  clear_has_batch_size();
+}
+::google::protobuf::uint32 MemoryDataParameter::batch_size() const {
+  // @@protoc_insertion_point(field_get:caffe.MemoryDataParameter.batch_size)
+  return batch_size_;
+}
+void MemoryDataParameter::set_batch_size(::google::protobuf::uint32 value) {
+  set_has_batch_size();
+  batch_size_ = value;
+  // @@protoc_insertion_point(field_set:caffe.MemoryDataParameter.batch_size)
+}
+
+// optional uint32 channels = 2;
+bool MemoryDataParameter::has_channels() const {
+  return (_has_bits_[0] & 0x00000002u) != 0;
+}
+void MemoryDataParameter::set_has_channels() {
+  _has_bits_[0] |= 0x00000002u;
+}
+void MemoryDataParameter::clear_has_channels() {
+  _has_bits_[0] &= ~0x00000002u;
+}
+void MemoryDataParameter::clear_channels() {
+  channels_ = 0u;
+  clear_has_channels();
+}
+::google::protobuf::uint32 MemoryDataParameter::channels() const {
+  // @@protoc_insertion_point(field_get:caffe.MemoryDataParameter.channels)
+  return channels_;
+}
+void MemoryDataParameter::set_channels(::google::protobuf::uint32 value) {
+  set_has_channels();
+  channels_ = value;
+  // @@protoc_insertion_point(field_set:caffe.MemoryDataParameter.channels)
+}
+
+// optional uint32 height = 3;
+bool MemoryDataParameter::has_height() const {
+  return (_has_bits_[0] & 0x00000004u) != 0;
+}
+void MemoryDataParameter::set_has_height() {
+  _has_bits_[0] |= 0x00000004u;
+}
+void MemoryDataParameter::clear_has_height() {
+  _has_bits_[0] &= ~0x00000004u;
+}
+void MemoryDataParameter::clear_height() {
+  height_ = 0u;
+  clear_has_height();
+}
+::google::protobuf::uint32 MemoryDataParameter::height() const {
+  // @@protoc_insertion_point(field_get:caffe.MemoryDataParameter.height)
+  return height_;
+}
+void MemoryDataParameter::set_height(::google::protobuf::uint32 value) {
+  set_has_height();
+  height_ = value;
+  // @@protoc_insertion_point(field_set:caffe.MemoryDataParameter.height)
+}
+
+// optional uint32 width = 4;
+bool MemoryDataParameter::has_width() const {
+  return (_has_bits_[0] & 0x00000008u) != 0;
+}
+void MemoryDataParameter::set_has_width() {
+  _has_bits_[0] |= 0x00000008u;
+}
+void MemoryDataParameter::clear_has_width() {
+  _has_bits_[0] &= ~0x00000008u;
+}
+void MemoryDataParameter::clear_width() {
+  width_ = 0u;
+  clear_has_width();
+}
+::google::protobuf::uint32 MemoryDataParameter::width() const {
+  // @@protoc_insertion_point(field_get:caffe.MemoryDataParameter.width)
+  return width_;
+}
+void MemoryDataParameter::set_width(::google::protobuf::uint32 value) {
+  set_has_width();
+  width_ = value;
+  // @@protoc_insertion_point(field_set:caffe.MemoryDataParameter.width)
+}
+
+inline const MemoryDataParameter* MemoryDataParameter::internal_default_instance() {
+  return &MemoryDataParameter_default_instance_.get();
+}
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
+
+// ===================================================================
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const int MVNParameter::kNormalizeVarianceFieldNumber;
+const int MVNParameter::kAcrossChannelsFieldNumber;
+const int MVNParameter::kEpsFieldNumber;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+
+MVNParameter::MVNParameter()
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+  if (this != internal_default_instance()) protobuf_InitDefaults_caffe_2eproto();
+  SharedCtor();
+  // @@protoc_insertion_point(constructor:caffe.MVNParameter)
+}
+
+void MVNParameter::InitAsDefaultInstance() {
+}
+
+MVNParameter::MVNParameter(const MVNParameter& from)
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
+  SharedCtor();
+  UnsafeMergeFrom(from);
+  // @@protoc_insertion_point(copy_constructor:caffe.MVNParameter)
+}
+
+void MVNParameter::SharedCtor() {
+  _cached_size_ = 0;
+  across_channels_ = false;
+  normalize_variance_ = true;
+  eps_ = 1e-09f;
+}
+
+MVNParameter::~MVNParameter() {
+  // @@protoc_insertion_point(destructor:caffe.MVNParameter)
+  SharedDtor();
+}
+
+void MVNParameter::SharedDtor() {
+}
+
+void MVNParameter::SetCachedSize(int size) const {
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* MVNParameter::descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return MVNParameter_descriptor_;
+}
+
+const MVNParameter& MVNParameter::default_instance() {
+  protobuf_InitDefaults_caffe_2eproto();
+  return *internal_default_instance();
+}
+
+::google::protobuf::internal::ExplicitlyConstructed<MVNParameter> MVNParameter_default_instance_;
+
+MVNParameter* MVNParameter::New(::google::protobuf::Arena* arena) const {
+  MVNParameter* n = new MVNParameter;
+  if (arena != NULL) {
+    arena->Own(n);
+  }
+  return n;
+}
+
+void MVNParameter::Clear() {
+// @@protoc_insertion_point(message_clear_start:caffe.MVNParameter)
+  if (_has_bits_[0 / 32] & 7u) {
+    normalize_variance_ = true;
+    across_channels_ = false;
+    eps_ = 1e-09f;
+  }
+  _has_bits_.Clear();
+  if (_internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->Clear();
+  }
+}
+
+bool MVNParameter::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
+  ::google::protobuf::uint32 tag;
+  // @@protoc_insertion_point(parse_start:caffe.MVNParameter)
+  for (;;) {
+    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+    tag = p.first;
+    if (!p.second) goto handle_unusual;
+    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+      // optional bool normalize_variance = 1 [default = true];
+      case 1: {
+        if (tag == 8) {
+          set_has_normalize_variance();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>(
+                 input, &normalize_variance_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(16)) goto parse_across_channels;
+        break;
+      }
+
+      // optional bool across_channels = 2 [default = false];
+      case 2: {
+        if (tag == 16) {
+         parse_across_channels:
+          set_has_across_channels();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>(
+                 input, &across_channels_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(29)) goto parse_eps;
+        break;
+      }
+
+      // optional float eps = 3 [default = 1e-09];
+      case 3: {
+        if (tag == 29) {
+         parse_eps:
+          set_has_eps();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
+                 input, &eps_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectAtEnd()) goto success;
+        break;
+      }
+
+      default: {
+      handle_unusual:
+        if (tag == 0 ||
+            ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+          goto success;
+        }
+        DO_(::google::protobuf::internal::WireFormat::SkipField(
+              input, tag, mutable_unknown_fields()));
+        break;
+      }
+    }
+  }
+success:
+  // @@protoc_insertion_point(parse_success:caffe.MVNParameter)
+  return true;
+failure:
+  // @@protoc_insertion_point(parse_failure:caffe.MVNParameter)
+  return false;
+#undef DO_
+}
+
+void MVNParameter::SerializeWithCachedSizes(
+    ::google::protobuf::io::CodedOutputStream* output) const {
+  // @@protoc_insertion_point(serialize_start:caffe.MVNParameter)
+  // optional bool normalize_variance = 1 [default = true];
+  if (has_normalize_variance()) {
+    ::google::protobuf::internal::WireFormatLite::WriteBool(1, this->normalize_variance(), output);
+  }
+
+  // optional bool across_channels = 2 [default = false];
+  if (has_across_channels()) {
+    ::google::protobuf::internal::WireFormatLite::WriteBool(2, this->across_channels(), output);
+  }
+
+  // optional float eps = 3 [default = 1e-09];
+  if (has_eps()) {
+    ::google::protobuf::internal::WireFormatLite::WriteFloat(3, this->eps(), output);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
+        unknown_fields(), output);
+  }
+  // @@protoc_insertion_point(serialize_end:caffe.MVNParameter)
+}
+
+::google::protobuf::uint8* MVNParameter::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
+  (void)deterministic; // Unused
+  // @@protoc_insertion_point(serialize_to_array_start:caffe.MVNParameter)
+  // optional bool normalize_variance = 1 [default = true];
+  if (has_normalize_variance()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(1, this->normalize_variance(), target);
+  }
+
+  // optional bool across_channels = 2 [default = false];
+  if (has_across_channels()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(2, this->across_channels(), target);
+  }
+
+  // optional float eps = 3 [default = 1e-09];
+  if (has_eps()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteFloatToArray(3, this->eps(), target);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
+        unknown_fields(), target);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:caffe.MVNParameter)
+  return target;
+}
+
+size_t MVNParameter::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:caffe.MVNParameter)
+  size_t total_size = 0;
+
+  if (_has_bits_[0 / 32] & 7u) {
+    // optional bool normalize_variance = 1 [default = true];
+    if (has_normalize_variance()) {
+      total_size += 1 + 1;
+    }
+
+    // optional bool across_channels = 2 [default = false];
+    if (has_across_channels()) {
+      total_size += 1 + 1;
+    }
+
+    // optional float eps = 3 [default = 1e-09];
+    if (has_eps()) {
+      total_size += 1 + 4;
+    }
+
+  }
+  if (_internal_metadata_.have_unknown_fields()) {
+    total_size +=
+      ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
+        unknown_fields());
+  }
+  int cached_size = ::google::protobuf::internal::ToCachedSize(total_size);
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = cached_size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+  return total_size;
+}
+
+void MVNParameter::MergeFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_merge_from_start:caffe.MVNParameter)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const MVNParameter* source =
+      ::google::protobuf::internal::DynamicCastToGenerated<const MVNParameter>(
+          &from);
+  if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:caffe.MVNParameter)
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:caffe.MVNParameter)
+    UnsafeMergeFrom(*source);
+  }
+}
+
+void MVNParameter::MergeFrom(const MVNParameter& from) {
+// @@protoc_insertion_point(class_specific_merge_from_start:caffe.MVNParameter)
+  if (GOOGLE_PREDICT_TRUE(&from != this)) {
+    UnsafeMergeFrom(from);
+  } else {
+    MergeFromFail(__LINE__);
+  }
+}
+
+void MVNParameter::UnsafeMergeFrom(const MVNParameter& from) {
+  GOOGLE_DCHECK(&from != this);
+  if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+    if (from.has_normalize_variance()) {
+      set_normalize_variance(from.normalize_variance());
+    }
+    if (from.has_across_channels()) {
+      set_across_channels(from.across_channels());
+    }
+    if (from.has_eps()) {
+      set_eps(from.eps());
+    }
+  }
+  if (from._internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::UnknownFieldSet::MergeToInternalMetdata(
+      from.unknown_fields(), &_internal_metadata_);
+  }
+}
+
+void MVNParameter::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:caffe.MVNParameter)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void MVNParameter::CopyFrom(const MVNParameter& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:caffe.MVNParameter)
+  if (&from == this) return;
+  Clear();
+  UnsafeMergeFrom(from);
+}
+
+bool MVNParameter::IsInitialized() const {
+
+  return true;
+}
+
+void MVNParameter::Swap(MVNParameter* other) {
+  if (other == this) return;
+  InternalSwap(other);
+}
+void MVNParameter::InternalSwap(MVNParameter* other) {
+  std::swap(normalize_variance_, other->normalize_variance_);
+  std::swap(across_channels_, other->across_channels_);
+  std::swap(eps_, other->eps_);
+  std::swap(_has_bits_[0], other->_has_bits_[0]);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
+}
+
+::google::protobuf::Metadata MVNParameter::GetMetadata() const {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::Metadata metadata;
+  metadata.descriptor = MVNParameter_descriptor_;
+  metadata.reflection = MVNParameter_reflection_;
+  return metadata;
+}
+
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// MVNParameter
+
+// optional bool normalize_variance = 1 [default = true];
+bool MVNParameter::has_normalize_variance() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+void MVNParameter::set_has_normalize_variance() {
+  _has_bits_[0] |= 0x00000001u;
+}
+void MVNParameter::clear_has_normalize_variance() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+void MVNParameter::clear_normalize_variance() {
+  normalize_variance_ = true;
+  clear_has_normalize_variance();
+}
+bool MVNParameter::normalize_variance() const {
+  // @@protoc_insertion_point(field_get:caffe.MVNParameter.normalize_variance)
+  return normalize_variance_;
+}
+void MVNParameter::set_normalize_variance(bool value) {
+  set_has_normalize_variance();
+  normalize_variance_ = value;
+  // @@protoc_insertion_point(field_set:caffe.MVNParameter.normalize_variance)
+}
+
+// optional bool across_channels = 2 [default = false];
+bool MVNParameter::has_across_channels() const {
+  return (_has_bits_[0] & 0x00000002u) != 0;
+}
+void MVNParameter::set_has_across_channels() {
+  _has_bits_[0] |= 0x00000002u;
+}
+void MVNParameter::clear_has_across_channels() {
+  _has_bits_[0] &= ~0x00000002u;
+}
+void MVNParameter::clear_across_channels() {
+  across_channels_ = false;
+  clear_has_across_channels();
+}
+bool MVNParameter::across_channels() const {
+  // @@protoc_insertion_point(field_get:caffe.MVNParameter.across_channels)
+  return across_channels_;
+}
+void MVNParameter::set_across_channels(bool value) {
+  set_has_across_channels();
+  across_channels_ = value;
+  // @@protoc_insertion_point(field_set:caffe.MVNParameter.across_channels)
+}
+
+// optional float eps = 3 [default = 1e-09];
+bool MVNParameter::has_eps() const {
+  return (_has_bits_[0] & 0x00000004u) != 0;
+}
+void MVNParameter::set_has_eps() {
+  _has_bits_[0] |= 0x00000004u;
+}
+void MVNParameter::clear_has_eps() {
+  _has_bits_[0] &= ~0x00000004u;
+}
+void MVNParameter::clear_eps() {
+  eps_ = 1e-09f;
+  clear_has_eps();
+}
+float MVNParameter::eps() const {
+  // @@protoc_insertion_point(field_get:caffe.MVNParameter.eps)
+  return eps_;
+}
+void MVNParameter::set_eps(float value) {
+  set_has_eps();
+  eps_ = value;
+  // @@protoc_insertion_point(field_set:caffe.MVNParameter.eps)
+}
+
+inline const MVNParameter* MVNParameter::internal_default_instance() {
+  return &MVNParameter_default_instance_.get();
+}
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
+
+// ===================================================================
+
+const ::google::protobuf::EnumDescriptor* PoolingParameter_PoolMethod_descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return PoolingParameter_PoolMethod_descriptor_;
+}
+bool PoolingParameter_PoolMethod_IsValid(int value) {
+  switch (value) {
+    case 0:
+    case 1:
+    case 2:
+      return true;
+    default:
+      return false;
+  }
+}
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const PoolingParameter_PoolMethod PoolingParameter::MAX;
+const PoolingParameter_PoolMethod PoolingParameter::AVE;
+const PoolingParameter_PoolMethod PoolingParameter::STOCHASTIC;
+const PoolingParameter_PoolMethod PoolingParameter::PoolMethod_MIN;
+const PoolingParameter_PoolMethod PoolingParameter::PoolMethod_MAX;
+const int PoolingParameter::PoolMethod_ARRAYSIZE;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+const ::google::protobuf::EnumDescriptor* PoolingParameter_Engine_descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return PoolingParameter_Engine_descriptor_;
+}
+bool PoolingParameter_Engine_IsValid(int value) {
+  switch (value) {
+    case 0:
+    case 1:
+    case 2:
+      return true;
+    default:
+      return false;
+  }
+}
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const PoolingParameter_Engine PoolingParameter::DEFAULT;
+const PoolingParameter_Engine PoolingParameter::CAFFE;
+const PoolingParameter_Engine PoolingParameter::CUDNN;
+const PoolingParameter_Engine PoolingParameter::Engine_MIN;
+const PoolingParameter_Engine PoolingParameter::Engine_MAX;
+const int PoolingParameter::Engine_ARRAYSIZE;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const int PoolingParameter::kPoolFieldNumber;
+const int PoolingParameter::kPadFieldNumber;
+const int PoolingParameter::kPadHFieldNumber;
+const int PoolingParameter::kPadWFieldNumber;
+const int PoolingParameter::kKernelSizeFieldNumber;
+const int PoolingParameter::kKernelHFieldNumber;
+const int PoolingParameter::kKernelWFieldNumber;
+const int PoolingParameter::kStrideFieldNumber;
+const int PoolingParameter::kStrideHFieldNumber;
+const int PoolingParameter::kStrideWFieldNumber;
+const int PoolingParameter::kEngineFieldNumber;
+const int PoolingParameter::kGlobalPoolingFieldNumber;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+
+PoolingParameter::PoolingParameter()
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+  if (this != internal_default_instance()) protobuf_InitDefaults_caffe_2eproto();
+  SharedCtor();
+  // @@protoc_insertion_point(constructor:caffe.PoolingParameter)
+}
+
+void PoolingParameter::InitAsDefaultInstance() {
+}
+
+PoolingParameter::PoolingParameter(const PoolingParameter& from)
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
+  SharedCtor();
+  UnsafeMergeFrom(from);
+  // @@protoc_insertion_point(copy_constructor:caffe.PoolingParameter)
+}
+
+void PoolingParameter::SharedCtor() {
+  _cached_size_ = 0;
+  ::memset(&pool_, 0, reinterpret_cast<char*>(&global_pooling_) -
+    reinterpret_cast<char*>(&pool_) + sizeof(global_pooling_));
+  stride_ = 1u;
+}
+
+PoolingParameter::~PoolingParameter() {
+  // @@protoc_insertion_point(destructor:caffe.PoolingParameter)
+  SharedDtor();
+}
+
+void PoolingParameter::SharedDtor() {
+}
+
+void PoolingParameter::SetCachedSize(int size) const {
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* PoolingParameter::descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return PoolingParameter_descriptor_;
+}
+
+const PoolingParameter& PoolingParameter::default_instance() {
+  protobuf_InitDefaults_caffe_2eproto();
+  return *internal_default_instance();
+}
+
+::google::protobuf::internal::ExplicitlyConstructed<PoolingParameter> PoolingParameter_default_instance_;
+
+PoolingParameter* PoolingParameter::New(::google::protobuf::Arena* arena) const {
+  PoolingParameter* n = new PoolingParameter;
+  if (arena != NULL) {
+    arena->Own(n);
+  }
+  return n;
+}
+
+void PoolingParameter::Clear() {
+// @@protoc_insertion_point(message_clear_start:caffe.PoolingParameter)
+#if defined(__clang__)
+#define ZR_HELPER_(f) \
+  _Pragma("clang diagnostic push") \
+  _Pragma("clang diagnostic ignored \"-Winvalid-offsetof\"") \
+  __builtin_offsetof(PoolingParameter, f) \
+  _Pragma("clang diagnostic pop")
+#else
+#define ZR_HELPER_(f) reinterpret_cast<char*>(\
+  &reinterpret_cast<PoolingParameter*>(16)->f)
+#endif
+
+#define ZR_(first, last) do {\
+  ::memset(&(first), 0,\
+           ZR_HELPER_(last) - ZR_HELPER_(first) + sizeof(last));\
+} while (0)
+
+  if (_has_bits_[0 / 32] & 255u) {
+    ZR_(pool_, kernel_w_);
+    stride_ = 1u;
+  }
+  ZR_(stride_h_, global_pooling_);
+
+#undef ZR_HELPER_
+#undef ZR_
+
+  _has_bits_.Clear();
+  if (_internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->Clear();
+  }
+}
+
+bool PoolingParameter::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
+  ::google::protobuf::uint32 tag;
+  // @@protoc_insertion_point(parse_start:caffe.PoolingParameter)
+  for (;;) {
+    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+    tag = p.first;
+    if (!p.second) goto handle_unusual;
+    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+      // optional .caffe.PoolingParameter.PoolMethod pool = 1 [default = MAX];
+      case 1: {
+        if (tag == 8) {
+          int value;
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>(
+                 input, &value)));
+          if (::caffe::PoolingParameter_PoolMethod_IsValid(value)) {
+            set_pool(static_cast< ::caffe::PoolingParameter_PoolMethod >(value));
+          } else {
+            mutable_unknown_fields()->AddVarint(1, value);
+          }
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(16)) goto parse_kernel_size;
+        break;
+      }
+
+      // optional uint32 kernel_size = 2;
+      case 2: {
+        if (tag == 16) {
+         parse_kernel_size:
+          set_has_kernel_size();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>(
+                 input, &kernel_size_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(24)) goto parse_stride;
+        break;
+      }
+
+      // optional uint32 stride = 3 [default = 1];
+      case 3: {
+        if (tag == 24) {
+         parse_stride:
+          set_has_stride();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>(
+                 input, &stride_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(32)) goto parse_pad;
+        break;
+      }
+
+      // optional uint32 pad = 4 [default = 0];
+      case 4: {
+        if (tag == 32) {
+         parse_pad:
+          set_has_pad();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>(
+                 input, &pad_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(40)) goto parse_kernel_h;
+        break;
+      }
+
+      // optional uint32 kernel_h = 5;
+      case 5: {
+        if (tag == 40) {
+         parse_kernel_h:
+          set_has_kernel_h();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>(
+                 input, &kernel_h_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(48)) goto parse_kernel_w;
+        break;
+      }
+
+      // optional uint32 kernel_w = 6;
+      case 6: {
+        if (tag == 48) {
+         parse_kernel_w:
+          set_has_kernel_w();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>(
+                 input, &kernel_w_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(56)) goto parse_stride_h;
+        break;
+      }
+
+      // optional uint32 stride_h = 7;
+      case 7: {
+        if (tag == 56) {
+         parse_stride_h:
+          set_has_stride_h();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>(
+                 input, &stride_h_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(64)) goto parse_stride_w;
+        break;
+      }
+
+      // optional uint32 stride_w = 8;
+      case 8: {
+        if (tag == 64) {
+         parse_stride_w:
+          set_has_stride_w();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>(
+                 input, &stride_w_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(72)) goto parse_pad_h;
+        break;
+      }
+
+      // optional uint32 pad_h = 9 [default = 0];
+      case 9: {
+        if (tag == 72) {
+         parse_pad_h:
+          set_has_pad_h();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>(
+                 input, &pad_h_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(80)) goto parse_pad_w;
+        break;
+      }
+
+      // optional uint32 pad_w = 10 [default = 0];
+      case 10: {
+        if (tag == 80) {
+         parse_pad_w:
+          set_has_pad_w();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>(
+                 input, &pad_w_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(88)) goto parse_engine;
+        break;
+      }
+
+      // optional .caffe.PoolingParameter.Engine engine = 11 [default = DEFAULT];
+      case 11: {
+        if (tag == 88) {
+         parse_engine:
+          int value;
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>(
+                 input, &value)));
+          if (::caffe::PoolingParameter_Engine_IsValid(value)) {
+            set_engine(static_cast< ::caffe::PoolingParameter_Engine >(value));
+          } else {
+            mutable_unknown_fields()->AddVarint(11, value);
+          }
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(96)) goto parse_global_pooling;
+        break;
+      }
+
+      // optional bool global_pooling = 12 [default = false];
+      case 12: {
+        if (tag == 96) {
+         parse_global_pooling:
+          set_has_global_pooling();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>(
+                 input, &global_pooling_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectAtEnd()) goto success;
+        break;
+      }
+
+      default: {
+      handle_unusual:
+        if (tag == 0 ||
+            ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+          goto success;
+        }
+        DO_(::google::protobuf::internal::WireFormat::SkipField(
+              input, tag, mutable_unknown_fields()));
+        break;
+      }
+    }
+  }
+success:
+  // @@protoc_insertion_point(parse_success:caffe.PoolingParameter)
+  return true;
+failure:
+  // @@protoc_insertion_point(parse_failure:caffe.PoolingParameter)
+  return false;
+#undef DO_
+}
+
+void PoolingParameter::SerializeWithCachedSizes(
+    ::google::protobuf::io::CodedOutputStream* output) const {
+  // @@protoc_insertion_point(serialize_start:caffe.PoolingParameter)
+  // optional .caffe.PoolingParameter.PoolMethod pool = 1 [default = MAX];
+  if (has_pool()) {
+    ::google::protobuf::internal::WireFormatLite::WriteEnum(
+      1, this->pool(), output);
+  }
+
+  // optional uint32 kernel_size = 2;
+  if (has_kernel_size()) {
+    ::google::protobuf::internal::WireFormatLite::WriteUInt32(2, this->kernel_size(), output);
+  }
+
+  // optional uint32 stride = 3 [default = 1];
+  if (has_stride()) {
+    ::google::protobuf::internal::WireFormatLite::WriteUInt32(3, this->stride(), output);
+  }
+
+  // optional uint32 pad = 4 [default = 0];
+  if (has_pad()) {
+    ::google::protobuf::internal::WireFormatLite::WriteUInt32(4, this->pad(), output);
+  }
+
+  // optional uint32 kernel_h = 5;
+  if (has_kernel_h()) {
+    ::google::protobuf::internal::WireFormatLite::WriteUInt32(5, this->kernel_h(), output);
+  }
+
+  // optional uint32 kernel_w = 6;
+  if (has_kernel_w()) {
+    ::google::protobuf::internal::WireFormatLite::WriteUInt32(6, this->kernel_w(), output);
+  }
+
+  // optional uint32 stride_h = 7;
+  if (has_stride_h()) {
+    ::google::protobuf::internal::WireFormatLite::WriteUInt32(7, this->stride_h(), output);
+  }
+
+  // optional uint32 stride_w = 8;
+  if (has_stride_w()) {
+    ::google::protobuf::internal::WireFormatLite::WriteUInt32(8, this->stride_w(), output);
+  }
+
+  // optional uint32 pad_h = 9 [default = 0];
+  if (has_pad_h()) {
+    ::google::protobuf::internal::WireFormatLite::WriteUInt32(9, this->pad_h(), output);
+  }
+
+  // optional uint32 pad_w = 10 [default = 0];
+  if (has_pad_w()) {
+    ::google::protobuf::internal::WireFormatLite::WriteUInt32(10, this->pad_w(), output);
+  }
+
+  // optional .caffe.PoolingParameter.Engine engine = 11 [default = DEFAULT];
+  if (has_engine()) {
+    ::google::protobuf::internal::WireFormatLite::WriteEnum(
+      11, this->engine(), output);
+  }
+
+  // optional bool global_pooling = 12 [default = false];
+  if (has_global_pooling()) {
+    ::google::protobuf::internal::WireFormatLite::WriteBool(12, this->global_pooling(), output);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
+        unknown_fields(), output);
+  }
+  // @@protoc_insertion_point(serialize_end:caffe.PoolingParameter)
+}
+
+::google::protobuf::uint8* PoolingParameter::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
+  (void)deterministic; // Unused
+  // @@protoc_insertion_point(serialize_to_array_start:caffe.PoolingParameter)
+  // optional .caffe.PoolingParameter.PoolMethod pool = 1 [default = MAX];
+  if (has_pool()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteEnumToArray(
+      1, this->pool(), target);
+  }
+
+  // optional uint32 kernel_size = 2;
+  if (has_kernel_size()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteUInt32ToArray(2, this->kernel_size(), target);
+  }
+
+  // optional uint32 stride = 3 [default = 1];
+  if (has_stride()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteUInt32ToArray(3, this->stride(), target);
+  }
+
+  // optional uint32 pad = 4 [default = 0];
+  if (has_pad()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteUInt32ToArray(4, this->pad(), target);
+  }
+
+  // optional uint32 kernel_h = 5;
+  if (has_kernel_h()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteUInt32ToArray(5, this->kernel_h(), target);
+  }
+
+  // optional uint32 kernel_w = 6;
+  if (has_kernel_w()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteUInt32ToArray(6, this->kernel_w(), target);
+  }
+
+  // optional uint32 stride_h = 7;
+  if (has_stride_h()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteUInt32ToArray(7, this->stride_h(), target);
+  }
+
+  // optional uint32 stride_w = 8;
+  if (has_stride_w()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteUInt32ToArray(8, this->stride_w(), target);
+  }
+
+  // optional uint32 pad_h = 9 [default = 0];
+  if (has_pad_h()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteUInt32ToArray(9, this->pad_h(), target);
+  }
+
+  // optional uint32 pad_w = 10 [default = 0];
+  if (has_pad_w()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteUInt32ToArray(10, this->pad_w(), target);
+  }
+
+  // optional .caffe.PoolingParameter.Engine engine = 11 [default = DEFAULT];
+  if (has_engine()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteEnumToArray(
+      11, this->engine(), target);
+  }
+
+  // optional bool global_pooling = 12 [default = false];
+  if (has_global_pooling()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(12, this->global_pooling(), target);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
+        unknown_fields(), target);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:caffe.PoolingParameter)
+  return target;
+}
+
+size_t PoolingParameter::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:caffe.PoolingParameter)
+  size_t total_size = 0;
+
+  if (_has_bits_[0 / 32] & 255u) {
+    // optional .caffe.PoolingParameter.PoolMethod pool = 1 [default = MAX];
+    if (has_pool()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::EnumSize(this->pool());
+    }
+
+    // optional uint32 pad = 4 [default = 0];
+    if (has_pad()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::UInt32Size(
+          this->pad());
+    }
+
+    // optional uint32 pad_h = 9 [default = 0];
+    if (has_pad_h()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::UInt32Size(
+          this->pad_h());
+    }
+
+    // optional uint32 pad_w = 10 [default = 0];
+    if (has_pad_w()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::UInt32Size(
+          this->pad_w());
+    }
+
+    // optional uint32 kernel_size = 2;
+    if (has_kernel_size()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::UInt32Size(
+          this->kernel_size());
+    }
+
+    // optional uint32 kernel_h = 5;
+    if (has_kernel_h()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::UInt32Size(
+          this->kernel_h());
+    }
+
+    // optional uint32 kernel_w = 6;
+    if (has_kernel_w()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::UInt32Size(
+          this->kernel_w());
+    }
+
+    // optional uint32 stride = 3 [default = 1];
+    if (has_stride()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::UInt32Size(
+          this->stride());
+    }
+
+  }
+  if (_has_bits_[8 / 32] & 3840u) {
+    // optional uint32 stride_h = 7;
+    if (has_stride_h()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::UInt32Size(
+          this->stride_h());
+    }
+
+    // optional uint32 stride_w = 8;
+    if (has_stride_w()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::UInt32Size(
+          this->stride_w());
+    }
+
+    // optional .caffe.PoolingParameter.Engine engine = 11 [default = DEFAULT];
+    if (has_engine()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::EnumSize(this->engine());
+    }
+
+    // optional bool global_pooling = 12 [default = false];
+    if (has_global_pooling()) {
+      total_size += 1 + 1;
+    }
+
+  }
+  if (_internal_metadata_.have_unknown_fields()) {
+    total_size +=
+      ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
+        unknown_fields());
+  }
+  int cached_size = ::google::protobuf::internal::ToCachedSize(total_size);
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = cached_size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+  return total_size;
+}
+
+void PoolingParameter::MergeFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_merge_from_start:caffe.PoolingParameter)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const PoolingParameter* source =
+      ::google::protobuf::internal::DynamicCastToGenerated<const PoolingParameter>(
+          &from);
+  if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:caffe.PoolingParameter)
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:caffe.PoolingParameter)
+    UnsafeMergeFrom(*source);
+  }
+}
+
+void PoolingParameter::MergeFrom(const PoolingParameter& from) {
+// @@protoc_insertion_point(class_specific_merge_from_start:caffe.PoolingParameter)
+  if (GOOGLE_PREDICT_TRUE(&from != this)) {
+    UnsafeMergeFrom(from);
+  } else {
+    MergeFromFail(__LINE__);
+  }
+}
+
+void PoolingParameter::UnsafeMergeFrom(const PoolingParameter& from) {
+  GOOGLE_DCHECK(&from != this);
+  if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+    if (from.has_pool()) {
+      set_pool(from.pool());
+    }
+    if (from.has_pad()) {
+      set_pad(from.pad());
+    }
+    if (from.has_pad_h()) {
+      set_pad_h(from.pad_h());
+    }
+    if (from.has_pad_w()) {
+      set_pad_w(from.pad_w());
+    }
+    if (from.has_kernel_size()) {
+      set_kernel_size(from.kernel_size());
+    }
+    if (from.has_kernel_h()) {
+      set_kernel_h(from.kernel_h());
+    }
+    if (from.has_kernel_w()) {
+      set_kernel_w(from.kernel_w());
+    }
+    if (from.has_stride()) {
+      set_stride(from.stride());
+    }
+  }
+  if (from._has_bits_[8 / 32] & (0xffu << (8 % 32))) {
+    if (from.has_stride_h()) {
+      set_stride_h(from.stride_h());
+    }
+    if (from.has_stride_w()) {
+      set_stride_w(from.stride_w());
+    }
+    if (from.has_engine()) {
+      set_engine(from.engine());
+    }
+    if (from.has_global_pooling()) {
+      set_global_pooling(from.global_pooling());
+    }
+  }
+  if (from._internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::UnknownFieldSet::MergeToInternalMetdata(
+      from.unknown_fields(), &_internal_metadata_);
+  }
+}
+
+void PoolingParameter::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:caffe.PoolingParameter)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void PoolingParameter::CopyFrom(const PoolingParameter& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:caffe.PoolingParameter)
+  if (&from == this) return;
+  Clear();
+  UnsafeMergeFrom(from);
+}
+
+bool PoolingParameter::IsInitialized() const {
+
+  return true;
+}
+
+void PoolingParameter::Swap(PoolingParameter* other) {
+  if (other == this) return;
+  InternalSwap(other);
+}
+void PoolingParameter::InternalSwap(PoolingParameter* other) {
+  std::swap(pool_, other->pool_);
+  std::swap(pad_, other->pad_);
+  std::swap(pad_h_, other->pad_h_);
+  std::swap(pad_w_, other->pad_w_);
+  std::swap(kernel_size_, other->kernel_size_);
+  std::swap(kernel_h_, other->kernel_h_);
+  std::swap(kernel_w_, other->kernel_w_);
+  std::swap(stride_, other->stride_);
+  std::swap(stride_h_, other->stride_h_);
+  std::swap(stride_w_, other->stride_w_);
+  std::swap(engine_, other->engine_);
+  std::swap(global_pooling_, other->global_pooling_);
+  std::swap(_has_bits_[0], other->_has_bits_[0]);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
+}
+
+::google::protobuf::Metadata PoolingParameter::GetMetadata() const {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::Metadata metadata;
+  metadata.descriptor = PoolingParameter_descriptor_;
+  metadata.reflection = PoolingParameter_reflection_;
+  return metadata;
+}
+
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// PoolingParameter
+
+// optional .caffe.PoolingParameter.PoolMethod pool = 1 [default = MAX];
+bool PoolingParameter::has_pool() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+void PoolingParameter::set_has_pool() {
+  _has_bits_[0] |= 0x00000001u;
+}
+void PoolingParameter::clear_has_pool() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+void PoolingParameter::clear_pool() {
+  pool_ = 0;
+  clear_has_pool();
+}
+::caffe::PoolingParameter_PoolMethod PoolingParameter::pool() const {
+  // @@protoc_insertion_point(field_get:caffe.PoolingParameter.pool)
+  return static_cast< ::caffe::PoolingParameter_PoolMethod >(pool_);
+}
+void PoolingParameter::set_pool(::caffe::PoolingParameter_PoolMethod value) {
+  assert(::caffe::PoolingParameter_PoolMethod_IsValid(value));
+  set_has_pool();
+  pool_ = value;
+  // @@protoc_insertion_point(field_set:caffe.PoolingParameter.pool)
+}
+
+// optional uint32 pad = 4 [default = 0];
+bool PoolingParameter::has_pad() const {
+  return (_has_bits_[0] & 0x00000002u) != 0;
+}
+void PoolingParameter::set_has_pad() {
+  _has_bits_[0] |= 0x00000002u;
+}
+void PoolingParameter::clear_has_pad() {
+  _has_bits_[0] &= ~0x00000002u;
+}
+void PoolingParameter::clear_pad() {
+  pad_ = 0u;
+  clear_has_pad();
+}
+::google::protobuf::uint32 PoolingParameter::pad() const {
+  // @@protoc_insertion_point(field_get:caffe.PoolingParameter.pad)
+  return pad_;
+}
+void PoolingParameter::set_pad(::google::protobuf::uint32 value) {
+  set_has_pad();
+  pad_ = value;
+  // @@protoc_insertion_point(field_set:caffe.PoolingParameter.pad)
+}
+
+// optional uint32 pad_h = 9 [default = 0];
+bool PoolingParameter::has_pad_h() const {
+  return (_has_bits_[0] & 0x00000004u) != 0;
+}
+void PoolingParameter::set_has_pad_h() {
+  _has_bits_[0] |= 0x00000004u;
+}
+void PoolingParameter::clear_has_pad_h() {
+  _has_bits_[0] &= ~0x00000004u;
+}
+void PoolingParameter::clear_pad_h() {
+  pad_h_ = 0u;
+  clear_has_pad_h();
+}
+::google::protobuf::uint32 PoolingParameter::pad_h() const {
+  // @@protoc_insertion_point(field_get:caffe.PoolingParameter.pad_h)
+  return pad_h_;
+}
+void PoolingParameter::set_pad_h(::google::protobuf::uint32 value) {
+  set_has_pad_h();
+  pad_h_ = value;
+  // @@protoc_insertion_point(field_set:caffe.PoolingParameter.pad_h)
+}
+
+// optional uint32 pad_w = 10 [default = 0];
+bool PoolingParameter::has_pad_w() const {
+  return (_has_bits_[0] & 0x00000008u) != 0;
+}
+void PoolingParameter::set_has_pad_w() {
+  _has_bits_[0] |= 0x00000008u;
+}
+void PoolingParameter::clear_has_pad_w() {
+  _has_bits_[0] &= ~0x00000008u;
+}
+void PoolingParameter::clear_pad_w() {
+  pad_w_ = 0u;
+  clear_has_pad_w();
+}
+::google::protobuf::uint32 PoolingParameter::pad_w() const {
+  // @@protoc_insertion_point(field_get:caffe.PoolingParameter.pad_w)
+  return pad_w_;
+}
+void PoolingParameter::set_pad_w(::google::protobuf::uint32 value) {
+  set_has_pad_w();
+  pad_w_ = value;
+  // @@protoc_insertion_point(field_set:caffe.PoolingParameter.pad_w)
+}
+
+// optional uint32 kernel_size = 2;
+bool PoolingParameter::has_kernel_size() const {
+  return (_has_bits_[0] & 0x00000010u) != 0;
+}
+void PoolingParameter::set_has_kernel_size() {
+  _has_bits_[0] |= 0x00000010u;
+}
+void PoolingParameter::clear_has_kernel_size() {
+  _has_bits_[0] &= ~0x00000010u;
+}
+void PoolingParameter::clear_kernel_size() {
+  kernel_size_ = 0u;
+  clear_has_kernel_size();
+}
+::google::protobuf::uint32 PoolingParameter::kernel_size() const {
+  // @@protoc_insertion_point(field_get:caffe.PoolingParameter.kernel_size)
+  return kernel_size_;
+}
+void PoolingParameter::set_kernel_size(::google::protobuf::uint32 value) {
+  set_has_kernel_size();
+  kernel_size_ = value;
+  // @@protoc_insertion_point(field_set:caffe.PoolingParameter.kernel_size)
+}
+
+// optional uint32 kernel_h = 5;
+bool PoolingParameter::has_kernel_h() const {
+  return (_has_bits_[0] & 0x00000020u) != 0;
+}
+void PoolingParameter::set_has_kernel_h() {
+  _has_bits_[0] |= 0x00000020u;
+}
+void PoolingParameter::clear_has_kernel_h() {
+  _has_bits_[0] &= ~0x00000020u;
+}
+void PoolingParameter::clear_kernel_h() {
+  kernel_h_ = 0u;
+  clear_has_kernel_h();
+}
+::google::protobuf::uint32 PoolingParameter::kernel_h() const {
+  // @@protoc_insertion_point(field_get:caffe.PoolingParameter.kernel_h)
+  return kernel_h_;
+}
+void PoolingParameter::set_kernel_h(::google::protobuf::uint32 value) {
+  set_has_kernel_h();
+  kernel_h_ = value;
+  // @@protoc_insertion_point(field_set:caffe.PoolingParameter.kernel_h)
+}
+
+// optional uint32 kernel_w = 6;
+bool PoolingParameter::has_kernel_w() const {
+  return (_has_bits_[0] & 0x00000040u) != 0;
+}
+void PoolingParameter::set_has_kernel_w() {
+  _has_bits_[0] |= 0x00000040u;
+}
+void PoolingParameter::clear_has_kernel_w() {
+  _has_bits_[0] &= ~0x00000040u;
+}
+void PoolingParameter::clear_kernel_w() {
+  kernel_w_ = 0u;
+  clear_has_kernel_w();
+}
+::google::protobuf::uint32 PoolingParameter::kernel_w() const {
+  // @@protoc_insertion_point(field_get:caffe.PoolingParameter.kernel_w)
+  return kernel_w_;
+}
+void PoolingParameter::set_kernel_w(::google::protobuf::uint32 value) {
+  set_has_kernel_w();
+  kernel_w_ = value;
+  // @@protoc_insertion_point(field_set:caffe.PoolingParameter.kernel_w)
+}
+
+// optional uint32 stride = 3 [default = 1];
+bool PoolingParameter::has_stride() const {
+  return (_has_bits_[0] & 0x00000080u) != 0;
+}
+void PoolingParameter::set_has_stride() {
+  _has_bits_[0] |= 0x00000080u;
+}
+void PoolingParameter::clear_has_stride() {
+  _has_bits_[0] &= ~0x00000080u;
+}
+void PoolingParameter::clear_stride() {
+  stride_ = 1u;
+  clear_has_stride();
+}
+::google::protobuf::uint32 PoolingParameter::stride() const {
+  // @@protoc_insertion_point(field_get:caffe.PoolingParameter.stride)
+  return stride_;
+}
+void PoolingParameter::set_stride(::google::protobuf::uint32 value) {
+  set_has_stride();
+  stride_ = value;
+  // @@protoc_insertion_point(field_set:caffe.PoolingParameter.stride)
+}
+
+// optional uint32 stride_h = 7;
+bool PoolingParameter::has_stride_h() const {
+  return (_has_bits_[0] & 0x00000100u) != 0;
+}
+void PoolingParameter::set_has_stride_h() {
+  _has_bits_[0] |= 0x00000100u;
+}
+void PoolingParameter::clear_has_stride_h() {
+  _has_bits_[0] &= ~0x00000100u;
+}
+void PoolingParameter::clear_stride_h() {
+  stride_h_ = 0u;
+  clear_has_stride_h();
+}
+::google::protobuf::uint32 PoolingParameter::stride_h() const {
+  // @@protoc_insertion_point(field_get:caffe.PoolingParameter.stride_h)
+  return stride_h_;
+}
+void PoolingParameter::set_stride_h(::google::protobuf::uint32 value) {
+  set_has_stride_h();
+  stride_h_ = value;
+  // @@protoc_insertion_point(field_set:caffe.PoolingParameter.stride_h)
+}
+
+// optional uint32 stride_w = 8;
+bool PoolingParameter::has_stride_w() const {
+  return (_has_bits_[0] & 0x00000200u) != 0;
+}
+void PoolingParameter::set_has_stride_w() {
+  _has_bits_[0] |= 0x00000200u;
+}
+void PoolingParameter::clear_has_stride_w() {
+  _has_bits_[0] &= ~0x00000200u;
+}
+void PoolingParameter::clear_stride_w() {
+  stride_w_ = 0u;
+  clear_has_stride_w();
+}
+::google::protobuf::uint32 PoolingParameter::stride_w() const {
+  // @@protoc_insertion_point(field_get:caffe.PoolingParameter.stride_w)
+  return stride_w_;
+}
+void PoolingParameter::set_stride_w(::google::protobuf::uint32 value) {
+  set_has_stride_w();
+  stride_w_ = value;
+  // @@protoc_insertion_point(field_set:caffe.PoolingParameter.stride_w)
+}
+
+// optional .caffe.PoolingParameter.Engine engine = 11 [default = DEFAULT];
+bool PoolingParameter::has_engine() const {
+  return (_has_bits_[0] & 0x00000400u) != 0;
+}
+void PoolingParameter::set_has_engine() {
+  _has_bits_[0] |= 0x00000400u;
+}
+void PoolingParameter::clear_has_engine() {
+  _has_bits_[0] &= ~0x00000400u;
+}
+void PoolingParameter::clear_engine() {
+  engine_ = 0;
+  clear_has_engine();
+}
+::caffe::PoolingParameter_Engine PoolingParameter::engine() const {
+  // @@protoc_insertion_point(field_get:caffe.PoolingParameter.engine)
+  return static_cast< ::caffe::PoolingParameter_Engine >(engine_);
+}
+void PoolingParameter::set_engine(::caffe::PoolingParameter_Engine value) {
+  assert(::caffe::PoolingParameter_Engine_IsValid(value));
+  set_has_engine();
+  engine_ = value;
+  // @@protoc_insertion_point(field_set:caffe.PoolingParameter.engine)
+}
+
+// optional bool global_pooling = 12 [default = false];
+bool PoolingParameter::has_global_pooling() const {
+  return (_has_bits_[0] & 0x00000800u) != 0;
+}
+void PoolingParameter::set_has_global_pooling() {
+  _has_bits_[0] |= 0x00000800u;
+}
+void PoolingParameter::clear_has_global_pooling() {
+  _has_bits_[0] &= ~0x00000800u;
+}
+void PoolingParameter::clear_global_pooling() {
+  global_pooling_ = false;
+  clear_has_global_pooling();
+}
+bool PoolingParameter::global_pooling() const {
+  // @@protoc_insertion_point(field_get:caffe.PoolingParameter.global_pooling)
+  return global_pooling_;
+}
+void PoolingParameter::set_global_pooling(bool value) {
+  set_has_global_pooling();
+  global_pooling_ = value;
+  // @@protoc_insertion_point(field_set:caffe.PoolingParameter.global_pooling)
+}
+
+inline const PoolingParameter* PoolingParameter::internal_default_instance() {
+  return &PoolingParameter_default_instance_.get();
+}
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
+
+// ===================================================================
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const int PowerParameter::kPowerFieldNumber;
+const int PowerParameter::kScaleFieldNumber;
+const int PowerParameter::kShiftFieldNumber;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+
+PowerParameter::PowerParameter()
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+  if (this != internal_default_instance()) protobuf_InitDefaults_caffe_2eproto();
+  SharedCtor();
+  // @@protoc_insertion_point(constructor:caffe.PowerParameter)
+}
+
+void PowerParameter::InitAsDefaultInstance() {
+}
+
+PowerParameter::PowerParameter(const PowerParameter& from)
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
+  SharedCtor();
+  UnsafeMergeFrom(from);
+  // @@protoc_insertion_point(copy_constructor:caffe.PowerParameter)
+}
+
+void PowerParameter::SharedCtor() {
+  _cached_size_ = 0;
+  shift_ = 0;
+  power_ = 1;
+  scale_ = 1;
+}
+
+PowerParameter::~PowerParameter() {
+  // @@protoc_insertion_point(destructor:caffe.PowerParameter)
+  SharedDtor();
+}
+
+void PowerParameter::SharedDtor() {
+}
+
+void PowerParameter::SetCachedSize(int size) const {
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* PowerParameter::descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return PowerParameter_descriptor_;
+}
+
+const PowerParameter& PowerParameter::default_instance() {
+  protobuf_InitDefaults_caffe_2eproto();
+  return *internal_default_instance();
+}
+
+::google::protobuf::internal::ExplicitlyConstructed<PowerParameter> PowerParameter_default_instance_;
+
+PowerParameter* PowerParameter::New(::google::protobuf::Arena* arena) const {
+  PowerParameter* n = new PowerParameter;
+  if (arena != NULL) {
+    arena->Own(n);
+  }
+  return n;
+}
+
+void PowerParameter::Clear() {
+// @@protoc_insertion_point(message_clear_start:caffe.PowerParameter)
+  if (_has_bits_[0 / 32] & 7u) {
+    power_ = 1;
+    scale_ = 1;
+    shift_ = 0;
+  }
+  _has_bits_.Clear();
+  if (_internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->Clear();
+  }
+}
+
+bool PowerParameter::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
+  ::google::protobuf::uint32 tag;
+  // @@protoc_insertion_point(parse_start:caffe.PowerParameter)
+  for (;;) {
+    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+    tag = p.first;
+    if (!p.second) goto handle_unusual;
+    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+      // optional float power = 1 [default = 1];
+      case 1: {
+        if (tag == 13) {
+          set_has_power();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
+                 input, &power_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(21)) goto parse_scale;
+        break;
+      }
+
+      // optional float scale = 2 [default = 1];
+      case 2: {
+        if (tag == 21) {
+         parse_scale:
+          set_has_scale();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
+                 input, &scale_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(29)) goto parse_shift;
+        break;
+      }
+
+      // optional float shift = 3 [default = 0];
+      case 3: {
+        if (tag == 29) {
+         parse_shift:
+          set_has_shift();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
+                 input, &shift_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectAtEnd()) goto success;
+        break;
+      }
+
+      default: {
+      handle_unusual:
+        if (tag == 0 ||
+            ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+          goto success;
+        }
+        DO_(::google::protobuf::internal::WireFormat::SkipField(
+              input, tag, mutable_unknown_fields()));
+        break;
+      }
+    }
+  }
+success:
+  // @@protoc_insertion_point(parse_success:caffe.PowerParameter)
+  return true;
+failure:
+  // @@protoc_insertion_point(parse_failure:caffe.PowerParameter)
+  return false;
+#undef DO_
+}
+
+void PowerParameter::SerializeWithCachedSizes(
+    ::google::protobuf::io::CodedOutputStream* output) const {
+  // @@protoc_insertion_point(serialize_start:caffe.PowerParameter)
+  // optional float power = 1 [default = 1];
+  if (has_power()) {
+    ::google::protobuf::internal::WireFormatLite::WriteFloat(1, this->power(), output);
+  }
+
+  // optional float scale = 2 [default = 1];
+  if (has_scale()) {
+    ::google::protobuf::internal::WireFormatLite::WriteFloat(2, this->scale(), output);
+  }
+
+  // optional float shift = 3 [default = 0];
+  if (has_shift()) {
+    ::google::protobuf::internal::WireFormatLite::WriteFloat(3, this->shift(), output);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
+        unknown_fields(), output);
+  }
+  // @@protoc_insertion_point(serialize_end:caffe.PowerParameter)
+}
+
+::google::protobuf::uint8* PowerParameter::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
+  (void)deterministic; // Unused
+  // @@protoc_insertion_point(serialize_to_array_start:caffe.PowerParameter)
+  // optional float power = 1 [default = 1];
+  if (has_power()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteFloatToArray(1, this->power(), target);
+  }
+
+  // optional float scale = 2 [default = 1];
+  if (has_scale()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteFloatToArray(2, this->scale(), target);
+  }
+
+  // optional float shift = 3 [default = 0];
+  if (has_shift()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteFloatToArray(3, this->shift(), target);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
+        unknown_fields(), target);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:caffe.PowerParameter)
+  return target;
+}
+
+size_t PowerParameter::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:caffe.PowerParameter)
+  size_t total_size = 0;
+
+  if (_has_bits_[0 / 32] & 7u) {
+    // optional float power = 1 [default = 1];
+    if (has_power()) {
+      total_size += 1 + 4;
+    }
+
+    // optional float scale = 2 [default = 1];
+    if (has_scale()) {
+      total_size += 1 + 4;
+    }
+
+    // optional float shift = 3 [default = 0];
+    if (has_shift()) {
+      total_size += 1 + 4;
+    }
+
+  }
+  if (_internal_metadata_.have_unknown_fields()) {
+    total_size +=
+      ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
+        unknown_fields());
+  }
+  int cached_size = ::google::protobuf::internal::ToCachedSize(total_size);
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = cached_size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+  return total_size;
+}
+
+void PowerParameter::MergeFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_merge_from_start:caffe.PowerParameter)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const PowerParameter* source =
+      ::google::protobuf::internal::DynamicCastToGenerated<const PowerParameter>(
+          &from);
+  if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:caffe.PowerParameter)
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:caffe.PowerParameter)
+    UnsafeMergeFrom(*source);
+  }
+}
+
+void PowerParameter::MergeFrom(const PowerParameter& from) {
+// @@protoc_insertion_point(class_specific_merge_from_start:caffe.PowerParameter)
+  if (GOOGLE_PREDICT_TRUE(&from != this)) {
+    UnsafeMergeFrom(from);
+  } else {
+    MergeFromFail(__LINE__);
+  }
+}
+
+void PowerParameter::UnsafeMergeFrom(const PowerParameter& from) {
+  GOOGLE_DCHECK(&from != this);
+  if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+    if (from.has_power()) {
+      set_power(from.power());
+    }
+    if (from.has_scale()) {
+      set_scale(from.scale());
+    }
+    if (from.has_shift()) {
+      set_shift(from.shift());
+    }
+  }
+  if (from._internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::UnknownFieldSet::MergeToInternalMetdata(
+      from.unknown_fields(), &_internal_metadata_);
+  }
+}
+
+void PowerParameter::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:caffe.PowerParameter)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void PowerParameter::CopyFrom(const PowerParameter& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:caffe.PowerParameter)
+  if (&from == this) return;
+  Clear();
+  UnsafeMergeFrom(from);
+}
+
+bool PowerParameter::IsInitialized() const {
+
+  return true;
+}
+
+void PowerParameter::Swap(PowerParameter* other) {
+  if (other == this) return;
+  InternalSwap(other);
+}
+void PowerParameter::InternalSwap(PowerParameter* other) {
+  std::swap(power_, other->power_);
+  std::swap(scale_, other->scale_);
+  std::swap(shift_, other->shift_);
+  std::swap(_has_bits_[0], other->_has_bits_[0]);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
+}
+
+::google::protobuf::Metadata PowerParameter::GetMetadata() const {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::Metadata metadata;
+  metadata.descriptor = PowerParameter_descriptor_;
+  metadata.reflection = PowerParameter_reflection_;
+  return metadata;
+}
+
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// PowerParameter
+
+// optional float power = 1 [default = 1];
+bool PowerParameter::has_power() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+void PowerParameter::set_has_power() {
+  _has_bits_[0] |= 0x00000001u;
+}
+void PowerParameter::clear_has_power() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+void PowerParameter::clear_power() {
+  power_ = 1;
+  clear_has_power();
+}
+float PowerParameter::power() const {
+  // @@protoc_insertion_point(field_get:caffe.PowerParameter.power)
+  return power_;
+}
+void PowerParameter::set_power(float value) {
+  set_has_power();
+  power_ = value;
+  // @@protoc_insertion_point(field_set:caffe.PowerParameter.power)
+}
+
+// optional float scale = 2 [default = 1];
+bool PowerParameter::has_scale() const {
+  return (_has_bits_[0] & 0x00000002u) != 0;
+}
+void PowerParameter::set_has_scale() {
+  _has_bits_[0] |= 0x00000002u;
+}
+void PowerParameter::clear_has_scale() {
+  _has_bits_[0] &= ~0x00000002u;
+}
+void PowerParameter::clear_scale() {
+  scale_ = 1;
+  clear_has_scale();
+}
+float PowerParameter::scale() const {
+  // @@protoc_insertion_point(field_get:caffe.PowerParameter.scale)
+  return scale_;
+}
+void PowerParameter::set_scale(float value) {
+  set_has_scale();
+  scale_ = value;
+  // @@protoc_insertion_point(field_set:caffe.PowerParameter.scale)
+}
+
+// optional float shift = 3 [default = 0];
+bool PowerParameter::has_shift() const {
+  return (_has_bits_[0] & 0x00000004u) != 0;
+}
+void PowerParameter::set_has_shift() {
+  _has_bits_[0] |= 0x00000004u;
+}
+void PowerParameter::clear_has_shift() {
+  _has_bits_[0] &= ~0x00000004u;
+}
+void PowerParameter::clear_shift() {
+  shift_ = 0;
+  clear_has_shift();
+}
+float PowerParameter::shift() const {
+  // @@protoc_insertion_point(field_get:caffe.PowerParameter.shift)
+  return shift_;
+}
+void PowerParameter::set_shift(float value) {
+  set_has_shift();
+  shift_ = value;
+  // @@protoc_insertion_point(field_set:caffe.PowerParameter.shift)
+}
+
+inline const PowerParameter* PowerParameter::internal_default_instance() {
+  return &PowerParameter_default_instance_.get();
+}
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
+
+// ===================================================================
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const int PythonParameter::kModuleFieldNumber;
+const int PythonParameter::kLayerFieldNumber;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+
+PythonParameter::PythonParameter()
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+  if (this != internal_default_instance()) protobuf_InitDefaults_caffe_2eproto();
+  SharedCtor();
+  // @@protoc_insertion_point(constructor:caffe.PythonParameter)
+}
+
+void PythonParameter::InitAsDefaultInstance() {
+}
+
+PythonParameter::PythonParameter(const PythonParameter& from)
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
+  SharedCtor();
+  UnsafeMergeFrom(from);
+  // @@protoc_insertion_point(copy_constructor:caffe.PythonParameter)
+}
+
+void PythonParameter::SharedCtor() {
+  _cached_size_ = 0;
+  module_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  layer_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+
+PythonParameter::~PythonParameter() {
+  // @@protoc_insertion_point(destructor:caffe.PythonParameter)
+  SharedDtor();
+}
+
+void PythonParameter::SharedDtor() {
+  module_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  layer_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+
+void PythonParameter::SetCachedSize(int size) const {
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* PythonParameter::descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return PythonParameter_descriptor_;
+}
+
+const PythonParameter& PythonParameter::default_instance() {
+  protobuf_InitDefaults_caffe_2eproto();
+  return *internal_default_instance();
+}
+
+::google::protobuf::internal::ExplicitlyConstructed<PythonParameter> PythonParameter_default_instance_;
+
+PythonParameter* PythonParameter::New(::google::protobuf::Arena* arena) const {
+  PythonParameter* n = new PythonParameter;
+  if (arena != NULL) {
+    arena->Own(n);
+  }
+  return n;
+}
+
+void PythonParameter::Clear() {
+// @@protoc_insertion_point(message_clear_start:caffe.PythonParameter)
+  if (_has_bits_[0 / 32] & 3u) {
+    if (has_module()) {
+      module_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+    }
+    if (has_layer()) {
+      layer_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+    }
+  }
+  _has_bits_.Clear();
+  if (_internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->Clear();
+  }
+}
+
+bool PythonParameter::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
+  ::google::protobuf::uint32 tag;
+  // @@protoc_insertion_point(parse_start:caffe.PythonParameter)
+  for (;;) {
+    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+    tag = p.first;
+    if (!p.second) goto handle_unusual;
+    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+      // optional string module = 1;
+      case 1: {
+        if (tag == 10) {
+          DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+                input, this->mutable_module()));
+          ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+            this->module().data(), this->module().length(),
+            ::google::protobuf::internal::WireFormat::PARSE,
+            "caffe.PythonParameter.module");
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(18)) goto parse_layer;
+        break;
+      }
+
+      // optional string layer = 2;
+      case 2: {
+        if (tag == 18) {
+         parse_layer:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+                input, this->mutable_layer()));
+          ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+            this->layer().data(), this->layer().length(),
+            ::google::protobuf::internal::WireFormat::PARSE,
+            "caffe.PythonParameter.layer");
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectAtEnd()) goto success;
+        break;
+      }
+
+      default: {
+      handle_unusual:
+        if (tag == 0 ||
+            ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+          goto success;
+        }
+        DO_(::google::protobuf::internal::WireFormat::SkipField(
+              input, tag, mutable_unknown_fields()));
+        break;
+      }
+    }
+  }
+success:
+  // @@protoc_insertion_point(parse_success:caffe.PythonParameter)
+  return true;
+failure:
+  // @@protoc_insertion_point(parse_failure:caffe.PythonParameter)
+  return false;
+#undef DO_
+}
+
+void PythonParameter::SerializeWithCachedSizes(
+    ::google::protobuf::io::CodedOutputStream* output) const {
+  // @@protoc_insertion_point(serialize_start:caffe.PythonParameter)
+  // optional string module = 1;
+  if (has_module()) {
+    ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->module().data(), this->module().length(),
+      ::google::protobuf::internal::WireFormat::SERIALIZE,
+      "caffe.PythonParameter.module");
+    ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
+      1, this->module(), output);
+  }
+
+  // optional string layer = 2;
+  if (has_layer()) {
+    ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->layer().data(), this->layer().length(),
+      ::google::protobuf::internal::WireFormat::SERIALIZE,
+      "caffe.PythonParameter.layer");
+    ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
+      2, this->layer(), output);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
+        unknown_fields(), output);
+  }
+  // @@protoc_insertion_point(serialize_end:caffe.PythonParameter)
+}
+
+::google::protobuf::uint8* PythonParameter::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
+  (void)deterministic; // Unused
+  // @@protoc_insertion_point(serialize_to_array_start:caffe.PythonParameter)
+  // optional string module = 1;
+  if (has_module()) {
+    ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->module().data(), this->module().length(),
+      ::google::protobuf::internal::WireFormat::SERIALIZE,
+      "caffe.PythonParameter.module");
+    target =
+      ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
+        1, this->module(), target);
+  }
+
+  // optional string layer = 2;
+  if (has_layer()) {
+    ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->layer().data(), this->layer().length(),
+      ::google::protobuf::internal::WireFormat::SERIALIZE,
+      "caffe.PythonParameter.layer");
+    target =
+      ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
+        2, this->layer(), target);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
+        unknown_fields(), target);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:caffe.PythonParameter)
+  return target;
+}
+
+size_t PythonParameter::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:caffe.PythonParameter)
+  size_t total_size = 0;
+
+  if (_has_bits_[0 / 32] & 3u) {
+    // optional string module = 1;
+    if (has_module()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::StringSize(
+          this->module());
+    }
+
+    // optional string layer = 2;
+    if (has_layer()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::StringSize(
+          this->layer());
+    }
+
+  }
+  if (_internal_metadata_.have_unknown_fields()) {
+    total_size +=
+      ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
+        unknown_fields());
+  }
+  int cached_size = ::google::protobuf::internal::ToCachedSize(total_size);
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = cached_size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+  return total_size;
+}
+
+void PythonParameter::MergeFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_merge_from_start:caffe.PythonParameter)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const PythonParameter* source =
+      ::google::protobuf::internal::DynamicCastToGenerated<const PythonParameter>(
+          &from);
+  if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:caffe.PythonParameter)
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:caffe.PythonParameter)
+    UnsafeMergeFrom(*source);
+  }
+}
+
+void PythonParameter::MergeFrom(const PythonParameter& from) {
+// @@protoc_insertion_point(class_specific_merge_from_start:caffe.PythonParameter)
+  if (GOOGLE_PREDICT_TRUE(&from != this)) {
+    UnsafeMergeFrom(from);
+  } else {
+    MergeFromFail(__LINE__);
+  }
+}
+
+void PythonParameter::UnsafeMergeFrom(const PythonParameter& from) {
+  GOOGLE_DCHECK(&from != this);
+  if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+    if (from.has_module()) {
+      set_has_module();
+      module_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.module_);
+    }
+    if (from.has_layer()) {
+      set_has_layer();
+      layer_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.layer_);
+    }
+  }
+  if (from._internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::UnknownFieldSet::MergeToInternalMetdata(
+      from.unknown_fields(), &_internal_metadata_);
+  }
+}
+
+void PythonParameter::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:caffe.PythonParameter)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void PythonParameter::CopyFrom(const PythonParameter& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:caffe.PythonParameter)
+  if (&from == this) return;
+  Clear();
+  UnsafeMergeFrom(from);
+}
+
+bool PythonParameter::IsInitialized() const {
+
+  return true;
+}
+
+void PythonParameter::Swap(PythonParameter* other) {
+  if (other == this) return;
+  InternalSwap(other);
+}
+void PythonParameter::InternalSwap(PythonParameter* other) {
+  module_.Swap(&other->module_);
+  layer_.Swap(&other->layer_);
+  std::swap(_has_bits_[0], other->_has_bits_[0]);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
+}
+
+::google::protobuf::Metadata PythonParameter::GetMetadata() const {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::Metadata metadata;
+  metadata.descriptor = PythonParameter_descriptor_;
+  metadata.reflection = PythonParameter_reflection_;
+  return metadata;
+}
+
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// PythonParameter
+
+// optional string module = 1;
+bool PythonParameter::has_module() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+void PythonParameter::set_has_module() {
+  _has_bits_[0] |= 0x00000001u;
+}
+void PythonParameter::clear_has_module() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+void PythonParameter::clear_module() {
+  module_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  clear_has_module();
+}
+const ::std::string& PythonParameter::module() const {
+  // @@protoc_insertion_point(field_get:caffe.PythonParameter.module)
+  return module_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+void PythonParameter::set_module(const ::std::string& value) {
+  set_has_module();
+  module_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:caffe.PythonParameter.module)
+}
+void PythonParameter::set_module(const char* value) {
+  set_has_module();
+  module_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:caffe.PythonParameter.module)
+}
+void PythonParameter::set_module(const char* value, size_t size) {
+  set_has_module();
+  module_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:caffe.PythonParameter.module)
+}
+::std::string* PythonParameter::mutable_module() {
+  set_has_module();
+  // @@protoc_insertion_point(field_mutable:caffe.PythonParameter.module)
+  return module_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+::std::string* PythonParameter::release_module() {
+  // @@protoc_insertion_point(field_release:caffe.PythonParameter.module)
+  clear_has_module();
+  return module_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+void PythonParameter::set_allocated_module(::std::string* module) {
+  if (module != NULL) {
+    set_has_module();
+  } else {
+    clear_has_module();
+  }
+  module_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), module);
+  // @@protoc_insertion_point(field_set_allocated:caffe.PythonParameter.module)
+}
+
+// optional string layer = 2;
+bool PythonParameter::has_layer() const {
+  return (_has_bits_[0] & 0x00000002u) != 0;
+}
+void PythonParameter::set_has_layer() {
+  _has_bits_[0] |= 0x00000002u;
+}
+void PythonParameter::clear_has_layer() {
+  _has_bits_[0] &= ~0x00000002u;
+}
+void PythonParameter::clear_layer() {
+  layer_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  clear_has_layer();
+}
+const ::std::string& PythonParameter::layer() const {
+  // @@protoc_insertion_point(field_get:caffe.PythonParameter.layer)
+  return layer_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+void PythonParameter::set_layer(const ::std::string& value) {
+  set_has_layer();
+  layer_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:caffe.PythonParameter.layer)
+}
+void PythonParameter::set_layer(const char* value) {
+  set_has_layer();
+  layer_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:caffe.PythonParameter.layer)
+}
+void PythonParameter::set_layer(const char* value, size_t size) {
+  set_has_layer();
+  layer_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:caffe.PythonParameter.layer)
+}
+::std::string* PythonParameter::mutable_layer() {
+  set_has_layer();
+  // @@protoc_insertion_point(field_mutable:caffe.PythonParameter.layer)
+  return layer_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+::std::string* PythonParameter::release_layer() {
+  // @@protoc_insertion_point(field_release:caffe.PythonParameter.layer)
+  clear_has_layer();
+  return layer_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+void PythonParameter::set_allocated_layer(::std::string* layer) {
+  if (layer != NULL) {
+    set_has_layer();
+  } else {
+    clear_has_layer();
+  }
+  layer_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), layer);
+  // @@protoc_insertion_point(field_set_allocated:caffe.PythonParameter.layer)
+}
+
+inline const PythonParameter* PythonParameter::internal_default_instance() {
+  return &PythonParameter_default_instance_.get();
+}
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
+
+// ===================================================================
+
+const ::google::protobuf::EnumDescriptor* ReductionParameter_ReductionOp_descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return ReductionParameter_ReductionOp_descriptor_;
+}
+bool ReductionParameter_ReductionOp_IsValid(int value) {
+  switch (value) {
+    case 1:
+    case 2:
+    case 3:
+    case 4:
+      return true;
+    default:
+      return false;
+  }
+}
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const ReductionParameter_ReductionOp ReductionParameter::SUM;
+const ReductionParameter_ReductionOp ReductionParameter::ASUM;
+const ReductionParameter_ReductionOp ReductionParameter::SUMSQ;
+const ReductionParameter_ReductionOp ReductionParameter::MEAN;
+const ReductionParameter_ReductionOp ReductionParameter::ReductionOp_MIN;
+const ReductionParameter_ReductionOp ReductionParameter::ReductionOp_MAX;
+const int ReductionParameter::ReductionOp_ARRAYSIZE;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const int ReductionParameter::kOperationFieldNumber;
+const int ReductionParameter::kAxisFieldNumber;
+const int ReductionParameter::kCoeffFieldNumber;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+
+ReductionParameter::ReductionParameter()
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+  if (this != internal_default_instance()) protobuf_InitDefaults_caffe_2eproto();
+  SharedCtor();
+  // @@protoc_insertion_point(constructor:caffe.ReductionParameter)
+}
+
+void ReductionParameter::InitAsDefaultInstance() {
+}
+
+ReductionParameter::ReductionParameter(const ReductionParameter& from)
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
+  SharedCtor();
+  UnsafeMergeFrom(from);
+  // @@protoc_insertion_point(copy_constructor:caffe.ReductionParameter)
+}
+
+void ReductionParameter::SharedCtor() {
+  _cached_size_ = 0;
+  axis_ = 0;
+  operation_ = 1;
+  coeff_ = 1;
+}
+
+ReductionParameter::~ReductionParameter() {
+  // @@protoc_insertion_point(destructor:caffe.ReductionParameter)
+  SharedDtor();
+}
+
+void ReductionParameter::SharedDtor() {
+}
+
+void ReductionParameter::SetCachedSize(int size) const {
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* ReductionParameter::descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return ReductionParameter_descriptor_;
+}
+
+const ReductionParameter& ReductionParameter::default_instance() {
+  protobuf_InitDefaults_caffe_2eproto();
+  return *internal_default_instance();
+}
+
+::google::protobuf::internal::ExplicitlyConstructed<ReductionParameter> ReductionParameter_default_instance_;
+
+ReductionParameter* ReductionParameter::New(::google::protobuf::Arena* arena) const {
+  ReductionParameter* n = new ReductionParameter;
+  if (arena != NULL) {
+    arena->Own(n);
+  }
+  return n;
+}
+
+void ReductionParameter::Clear() {
+// @@protoc_insertion_point(message_clear_start:caffe.ReductionParameter)
+  if (_has_bits_[0 / 32] & 7u) {
+    operation_ = 1;
+    axis_ = 0;
+    coeff_ = 1;
+  }
+  _has_bits_.Clear();
+  if (_internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->Clear();
+  }
+}
+
+bool ReductionParameter::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
+  ::google::protobuf::uint32 tag;
+  // @@protoc_insertion_point(parse_start:caffe.ReductionParameter)
+  for (;;) {
+    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+    tag = p.first;
+    if (!p.second) goto handle_unusual;
+    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+      // optional .caffe.ReductionParameter.ReductionOp operation = 1 [default = SUM];
+      case 1: {
+        if (tag == 8) {
+          int value;
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>(
+                 input, &value)));
+          if (::caffe::ReductionParameter_ReductionOp_IsValid(value)) {
+            set_operation(static_cast< ::caffe::ReductionParameter_ReductionOp >(value));
+          } else {
+            mutable_unknown_fields()->AddVarint(1, value);
+          }
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(16)) goto parse_axis;
+        break;
+      }
+
+      // optional int32 axis = 2 [default = 0];
+      case 2: {
+        if (tag == 16) {
+         parse_axis:
+          set_has_axis();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
+                 input, &axis_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(29)) goto parse_coeff;
+        break;
+      }
+
+      // optional float coeff = 3 [default = 1];
+      case 3: {
+        if (tag == 29) {
+         parse_coeff:
+          set_has_coeff();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
+                 input, &coeff_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectAtEnd()) goto success;
+        break;
+      }
+
+      default: {
+      handle_unusual:
+        if (tag == 0 ||
+            ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+          goto success;
+        }
+        DO_(::google::protobuf::internal::WireFormat::SkipField(
+              input, tag, mutable_unknown_fields()));
+        break;
+      }
+    }
+  }
+success:
+  // @@protoc_insertion_point(parse_success:caffe.ReductionParameter)
+  return true;
+failure:
+  // @@protoc_insertion_point(parse_failure:caffe.ReductionParameter)
+  return false;
+#undef DO_
+}
+
+void ReductionParameter::SerializeWithCachedSizes(
+    ::google::protobuf::io::CodedOutputStream* output) const {
+  // @@protoc_insertion_point(serialize_start:caffe.ReductionParameter)
+  // optional .caffe.ReductionParameter.ReductionOp operation = 1 [default = SUM];
+  if (has_operation()) {
+    ::google::protobuf::internal::WireFormatLite::WriteEnum(
+      1, this->operation(), output);
+  }
+
+  // optional int32 axis = 2 [default = 0];
+  if (has_axis()) {
+    ::google::protobuf::internal::WireFormatLite::WriteInt32(2, this->axis(), output);
+  }
+
+  // optional float coeff = 3 [default = 1];
+  if (has_coeff()) {
+    ::google::protobuf::internal::WireFormatLite::WriteFloat(3, this->coeff(), output);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
+        unknown_fields(), output);
+  }
+  // @@protoc_insertion_point(serialize_end:caffe.ReductionParameter)
+}
+
+::google::protobuf::uint8* ReductionParameter::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
+  (void)deterministic; // Unused
+  // @@protoc_insertion_point(serialize_to_array_start:caffe.ReductionParameter)
+  // optional .caffe.ReductionParameter.ReductionOp operation = 1 [default = SUM];
+  if (has_operation()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteEnumToArray(
+      1, this->operation(), target);
+  }
+
+  // optional int32 axis = 2 [default = 0];
+  if (has_axis()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteInt32ToArray(2, this->axis(), target);
+  }
+
+  // optional float coeff = 3 [default = 1];
+  if (has_coeff()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteFloatToArray(3, this->coeff(), target);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
+        unknown_fields(), target);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:caffe.ReductionParameter)
+  return target;
+}
+
+size_t ReductionParameter::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:caffe.ReductionParameter)
+  size_t total_size = 0;
+
+  if (_has_bits_[0 / 32] & 7u) {
+    // optional .caffe.ReductionParameter.ReductionOp operation = 1 [default = SUM];
+    if (has_operation()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::EnumSize(this->operation());
+    }
+
+    // optional int32 axis = 2 [default = 0];
+    if (has_axis()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::Int32Size(
+          this->axis());
+    }
+
+    // optional float coeff = 3 [default = 1];
+    if (has_coeff()) {
+      total_size += 1 + 4;
+    }
+
+  }
+  if (_internal_metadata_.have_unknown_fields()) {
+    total_size +=
+      ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
+        unknown_fields());
+  }
+  int cached_size = ::google::protobuf::internal::ToCachedSize(total_size);
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = cached_size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+  return total_size;
+}
+
+void ReductionParameter::MergeFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_merge_from_start:caffe.ReductionParameter)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const ReductionParameter* source =
+      ::google::protobuf::internal::DynamicCastToGenerated<const ReductionParameter>(
+          &from);
+  if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:caffe.ReductionParameter)
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:caffe.ReductionParameter)
+    UnsafeMergeFrom(*source);
+  }
+}
+
+void ReductionParameter::MergeFrom(const ReductionParameter& from) {
+// @@protoc_insertion_point(class_specific_merge_from_start:caffe.ReductionParameter)
+  if (GOOGLE_PREDICT_TRUE(&from != this)) {
+    UnsafeMergeFrom(from);
+  } else {
+    MergeFromFail(__LINE__);
+  }
+}
+
+void ReductionParameter::UnsafeMergeFrom(const ReductionParameter& from) {
+  GOOGLE_DCHECK(&from != this);
+  if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+    if (from.has_operation()) {
+      set_operation(from.operation());
+    }
+    if (from.has_axis()) {
+      set_axis(from.axis());
+    }
+    if (from.has_coeff()) {
+      set_coeff(from.coeff());
+    }
+  }
+  if (from._internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::UnknownFieldSet::MergeToInternalMetdata(
+      from.unknown_fields(), &_internal_metadata_);
+  }
+}
+
+void ReductionParameter::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:caffe.ReductionParameter)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void ReductionParameter::CopyFrom(const ReductionParameter& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:caffe.ReductionParameter)
+  if (&from == this) return;
+  Clear();
+  UnsafeMergeFrom(from);
+}
+
+bool ReductionParameter::IsInitialized() const {
+
+  return true;
+}
+
+void ReductionParameter::Swap(ReductionParameter* other) {
+  if (other == this) return;
+  InternalSwap(other);
+}
+void ReductionParameter::InternalSwap(ReductionParameter* other) {
+  std::swap(operation_, other->operation_);
+  std::swap(axis_, other->axis_);
+  std::swap(coeff_, other->coeff_);
+  std::swap(_has_bits_[0], other->_has_bits_[0]);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
+}
+
+::google::protobuf::Metadata ReductionParameter::GetMetadata() const {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::Metadata metadata;
+  metadata.descriptor = ReductionParameter_descriptor_;
+  metadata.reflection = ReductionParameter_reflection_;
+  return metadata;
+}
+
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// ReductionParameter
+
+// optional .caffe.ReductionParameter.ReductionOp operation = 1 [default = SUM];
+bool ReductionParameter::has_operation() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+void ReductionParameter::set_has_operation() {
+  _has_bits_[0] |= 0x00000001u;
+}
+void ReductionParameter::clear_has_operation() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+void ReductionParameter::clear_operation() {
+  operation_ = 1;
+  clear_has_operation();
+}
+::caffe::ReductionParameter_ReductionOp ReductionParameter::operation() const {
+  // @@protoc_insertion_point(field_get:caffe.ReductionParameter.operation)
+  return static_cast< ::caffe::ReductionParameter_ReductionOp >(operation_);
+}
+void ReductionParameter::set_operation(::caffe::ReductionParameter_ReductionOp value) {
+  assert(::caffe::ReductionParameter_ReductionOp_IsValid(value));
+  set_has_operation();
+  operation_ = value;
+  // @@protoc_insertion_point(field_set:caffe.ReductionParameter.operation)
+}
+
+// optional int32 axis = 2 [default = 0];
+bool ReductionParameter::has_axis() const {
+  return (_has_bits_[0] & 0x00000002u) != 0;
+}
+void ReductionParameter::set_has_axis() {
+  _has_bits_[0] |= 0x00000002u;
+}
+void ReductionParameter::clear_has_axis() {
+  _has_bits_[0] &= ~0x00000002u;
+}
+void ReductionParameter::clear_axis() {
+  axis_ = 0;
+  clear_has_axis();
+}
+::google::protobuf::int32 ReductionParameter::axis() const {
+  // @@protoc_insertion_point(field_get:caffe.ReductionParameter.axis)
+  return axis_;
+}
+void ReductionParameter::set_axis(::google::protobuf::int32 value) {
+  set_has_axis();
+  axis_ = value;
+  // @@protoc_insertion_point(field_set:caffe.ReductionParameter.axis)
+}
+
+// optional float coeff = 3 [default = 1];
+bool ReductionParameter::has_coeff() const {
+  return (_has_bits_[0] & 0x00000004u) != 0;
+}
+void ReductionParameter::set_has_coeff() {
+  _has_bits_[0] |= 0x00000004u;
+}
+void ReductionParameter::clear_has_coeff() {
+  _has_bits_[0] &= ~0x00000004u;
+}
+void ReductionParameter::clear_coeff() {
+  coeff_ = 1;
+  clear_has_coeff();
+}
+float ReductionParameter::coeff() const {
+  // @@protoc_insertion_point(field_get:caffe.ReductionParameter.coeff)
+  return coeff_;
+}
+void ReductionParameter::set_coeff(float value) {
+  set_has_coeff();
+  coeff_ = value;
+  // @@protoc_insertion_point(field_set:caffe.ReductionParameter.coeff)
+}
+
+inline const ReductionParameter* ReductionParameter::internal_default_instance() {
+  return &ReductionParameter_default_instance_.get();
+}
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
+
+// ===================================================================
+
+const ::google::protobuf::EnumDescriptor* ReLUParameter_Engine_descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return ReLUParameter_Engine_descriptor_;
+}
+bool ReLUParameter_Engine_IsValid(int value) {
+  switch (value) {
+    case 0:
+    case 1:
+    case 2:
+      return true;
+    default:
+      return false;
+  }
+}
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const ReLUParameter_Engine ReLUParameter::DEFAULT;
+const ReLUParameter_Engine ReLUParameter::CAFFE;
+const ReLUParameter_Engine ReLUParameter::CUDNN;
+const ReLUParameter_Engine ReLUParameter::Engine_MIN;
+const ReLUParameter_Engine ReLUParameter::Engine_MAX;
+const int ReLUParameter::Engine_ARRAYSIZE;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const int ReLUParameter::kNegativeSlopeFieldNumber;
+const int ReLUParameter::kEngineFieldNumber;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+
+ReLUParameter::ReLUParameter()
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+  if (this != internal_default_instance()) protobuf_InitDefaults_caffe_2eproto();
+  SharedCtor();
+  // @@protoc_insertion_point(constructor:caffe.ReLUParameter)
+}
+
+void ReLUParameter::InitAsDefaultInstance() {
+}
+
+ReLUParameter::ReLUParameter(const ReLUParameter& from)
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
+  SharedCtor();
+  UnsafeMergeFrom(from);
+  // @@protoc_insertion_point(copy_constructor:caffe.ReLUParameter)
+}
+
+void ReLUParameter::SharedCtor() {
+  _cached_size_ = 0;
+  ::memset(&negative_slope_, 0, reinterpret_cast<char*>(&engine_) -
+    reinterpret_cast<char*>(&negative_slope_) + sizeof(engine_));
+}
+
+ReLUParameter::~ReLUParameter() {
+  // @@protoc_insertion_point(destructor:caffe.ReLUParameter)
+  SharedDtor();
+}
+
+void ReLUParameter::SharedDtor() {
+}
+
+void ReLUParameter::SetCachedSize(int size) const {
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* ReLUParameter::descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return ReLUParameter_descriptor_;
+}
+
+const ReLUParameter& ReLUParameter::default_instance() {
+  protobuf_InitDefaults_caffe_2eproto();
+  return *internal_default_instance();
+}
+
+::google::protobuf::internal::ExplicitlyConstructed<ReLUParameter> ReLUParameter_default_instance_;
+
+ReLUParameter* ReLUParameter::New(::google::protobuf::Arena* arena) const {
+  ReLUParameter* n = new ReLUParameter;
+  if (arena != NULL) {
+    arena->Own(n);
+  }
+  return n;
+}
+
+void ReLUParameter::Clear() {
+// @@protoc_insertion_point(message_clear_start:caffe.ReLUParameter)
+#if defined(__clang__)
+#define ZR_HELPER_(f) \
+  _Pragma("clang diagnostic push") \
+  _Pragma("clang diagnostic ignored \"-Winvalid-offsetof\"") \
+  __builtin_offsetof(ReLUParameter, f) \
+  _Pragma("clang diagnostic pop")
+#else
+#define ZR_HELPER_(f) reinterpret_cast<char*>(\
+  &reinterpret_cast<ReLUParameter*>(16)->f)
+#endif
+
+#define ZR_(first, last) do {\
+  ::memset(&(first), 0,\
+           ZR_HELPER_(last) - ZR_HELPER_(first) + sizeof(last));\
+} while (0)
+
+  ZR_(negative_slope_, engine_);
+
+#undef ZR_HELPER_
+#undef ZR_
+
+  _has_bits_.Clear();
+  if (_internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->Clear();
+  }
+}
+
+bool ReLUParameter::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
+  ::google::protobuf::uint32 tag;
+  // @@protoc_insertion_point(parse_start:caffe.ReLUParameter)
+  for (;;) {
+    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+    tag = p.first;
+    if (!p.second) goto handle_unusual;
+    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+      // optional float negative_slope = 1 [default = 0];
+      case 1: {
+        if (tag == 13) {
+          set_has_negative_slope();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
+                 input, &negative_slope_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(16)) goto parse_engine;
+        break;
+      }
+
+      // optional .caffe.ReLUParameter.Engine engine = 2 [default = DEFAULT];
+      case 2: {
+        if (tag == 16) {
+         parse_engine:
+          int value;
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>(
+                 input, &value)));
+          if (::caffe::ReLUParameter_Engine_IsValid(value)) {
+            set_engine(static_cast< ::caffe::ReLUParameter_Engine >(value));
+          } else {
+            mutable_unknown_fields()->AddVarint(2, value);
+          }
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectAtEnd()) goto success;
+        break;
+      }
+
+      default: {
+      handle_unusual:
+        if (tag == 0 ||
+            ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+          goto success;
+        }
+        DO_(::google::protobuf::internal::WireFormat::SkipField(
+              input, tag, mutable_unknown_fields()));
+        break;
+      }
+    }
+  }
+success:
+  // @@protoc_insertion_point(parse_success:caffe.ReLUParameter)
+  return true;
+failure:
+  // @@protoc_insertion_point(parse_failure:caffe.ReLUParameter)
+  return false;
+#undef DO_
+}
+
+void ReLUParameter::SerializeWithCachedSizes(
+    ::google::protobuf::io::CodedOutputStream* output) const {
+  // @@protoc_insertion_point(serialize_start:caffe.ReLUParameter)
+  // optional float negative_slope = 1 [default = 0];
+  if (has_negative_slope()) {
+    ::google::protobuf::internal::WireFormatLite::WriteFloat(1, this->negative_slope(), output);
+  }
+
+  // optional .caffe.ReLUParameter.Engine engine = 2 [default = DEFAULT];
+  if (has_engine()) {
+    ::google::protobuf::internal::WireFormatLite::WriteEnum(
+      2, this->engine(), output);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
+        unknown_fields(), output);
+  }
+  // @@protoc_insertion_point(serialize_end:caffe.ReLUParameter)
+}
+
+::google::protobuf::uint8* ReLUParameter::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
+  (void)deterministic; // Unused
+  // @@protoc_insertion_point(serialize_to_array_start:caffe.ReLUParameter)
+  // optional float negative_slope = 1 [default = 0];
+  if (has_negative_slope()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteFloatToArray(1, this->negative_slope(), target);
+  }
+
+  // optional .caffe.ReLUParameter.Engine engine = 2 [default = DEFAULT];
+  if (has_engine()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteEnumToArray(
+      2, this->engine(), target);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
+        unknown_fields(), target);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:caffe.ReLUParameter)
+  return target;
+}
+
+size_t ReLUParameter::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:caffe.ReLUParameter)
+  size_t total_size = 0;
+
+  if (_has_bits_[0 / 32] & 3u) {
+    // optional float negative_slope = 1 [default = 0];
+    if (has_negative_slope()) {
+      total_size += 1 + 4;
+    }
+
+    // optional .caffe.ReLUParameter.Engine engine = 2 [default = DEFAULT];
+    if (has_engine()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::EnumSize(this->engine());
+    }
+
+  }
+  if (_internal_metadata_.have_unknown_fields()) {
+    total_size +=
+      ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
+        unknown_fields());
+  }
+  int cached_size = ::google::protobuf::internal::ToCachedSize(total_size);
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = cached_size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+  return total_size;
+}
+
+void ReLUParameter::MergeFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_merge_from_start:caffe.ReLUParameter)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const ReLUParameter* source =
+      ::google::protobuf::internal::DynamicCastToGenerated<const ReLUParameter>(
+          &from);
+  if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:caffe.ReLUParameter)
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:caffe.ReLUParameter)
+    UnsafeMergeFrom(*source);
+  }
+}
+
+void ReLUParameter::MergeFrom(const ReLUParameter& from) {
+// @@protoc_insertion_point(class_specific_merge_from_start:caffe.ReLUParameter)
+  if (GOOGLE_PREDICT_TRUE(&from != this)) {
+    UnsafeMergeFrom(from);
+  } else {
+    MergeFromFail(__LINE__);
+  }
+}
+
+void ReLUParameter::UnsafeMergeFrom(const ReLUParameter& from) {
+  GOOGLE_DCHECK(&from != this);
+  if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+    if (from.has_negative_slope()) {
+      set_negative_slope(from.negative_slope());
+    }
+    if (from.has_engine()) {
+      set_engine(from.engine());
+    }
+  }
+  if (from._internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::UnknownFieldSet::MergeToInternalMetdata(
+      from.unknown_fields(), &_internal_metadata_);
+  }
+}
+
+void ReLUParameter::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:caffe.ReLUParameter)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void ReLUParameter::CopyFrom(const ReLUParameter& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:caffe.ReLUParameter)
+  if (&from == this) return;
+  Clear();
+  UnsafeMergeFrom(from);
+}
+
+bool ReLUParameter::IsInitialized() const {
+
+  return true;
+}
+
+void ReLUParameter::Swap(ReLUParameter* other) {
+  if (other == this) return;
+  InternalSwap(other);
+}
+void ReLUParameter::InternalSwap(ReLUParameter* other) {
+  std::swap(negative_slope_, other->negative_slope_);
+  std::swap(engine_, other->engine_);
+  std::swap(_has_bits_[0], other->_has_bits_[0]);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
+}
+
+::google::protobuf::Metadata ReLUParameter::GetMetadata() const {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::Metadata metadata;
+  metadata.descriptor = ReLUParameter_descriptor_;
+  metadata.reflection = ReLUParameter_reflection_;
+  return metadata;
+}
+
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// ReLUParameter
+
+// optional float negative_slope = 1 [default = 0];
+bool ReLUParameter::has_negative_slope() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+void ReLUParameter::set_has_negative_slope() {
+  _has_bits_[0] |= 0x00000001u;
+}
+void ReLUParameter::clear_has_negative_slope() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+void ReLUParameter::clear_negative_slope() {
+  negative_slope_ = 0;
+  clear_has_negative_slope();
+}
+float ReLUParameter::negative_slope() const {
+  // @@protoc_insertion_point(field_get:caffe.ReLUParameter.negative_slope)
+  return negative_slope_;
+}
+void ReLUParameter::set_negative_slope(float value) {
+  set_has_negative_slope();
+  negative_slope_ = value;
+  // @@protoc_insertion_point(field_set:caffe.ReLUParameter.negative_slope)
+}
+
+// optional .caffe.ReLUParameter.Engine engine = 2 [default = DEFAULT];
+bool ReLUParameter::has_engine() const {
+  return (_has_bits_[0] & 0x00000002u) != 0;
+}
+void ReLUParameter::set_has_engine() {
+  _has_bits_[0] |= 0x00000002u;
+}
+void ReLUParameter::clear_has_engine() {
+  _has_bits_[0] &= ~0x00000002u;
+}
+void ReLUParameter::clear_engine() {
+  engine_ = 0;
+  clear_has_engine();
+}
+::caffe::ReLUParameter_Engine ReLUParameter::engine() const {
+  // @@protoc_insertion_point(field_get:caffe.ReLUParameter.engine)
+  return static_cast< ::caffe::ReLUParameter_Engine >(engine_);
+}
+void ReLUParameter::set_engine(::caffe::ReLUParameter_Engine value) {
+  assert(::caffe::ReLUParameter_Engine_IsValid(value));
+  set_has_engine();
+  engine_ = value;
+  // @@protoc_insertion_point(field_set:caffe.ReLUParameter.engine)
+}
+
+inline const ReLUParameter* ReLUParameter::internal_default_instance() {
+  return &ReLUParameter_default_instance_.get();
+}
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
+
+// ===================================================================
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const int ReshapeParameter::kShapeFieldNumber;
+const int ReshapeParameter::kAxisFieldNumber;
+const int ReshapeParameter::kNumAxesFieldNumber;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+
+ReshapeParameter::ReshapeParameter()
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+  if (this != internal_default_instance()) protobuf_InitDefaults_caffe_2eproto();
+  SharedCtor();
+  // @@protoc_insertion_point(constructor:caffe.ReshapeParameter)
+}
+
+void ReshapeParameter::InitAsDefaultInstance() {
+  shape_ = const_cast< ::caffe::BlobShape*>(
+      ::caffe::BlobShape::internal_default_instance());
+}
+
+ReshapeParameter::ReshapeParameter(const ReshapeParameter& from)
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
+  SharedCtor();
+  UnsafeMergeFrom(from);
+  // @@protoc_insertion_point(copy_constructor:caffe.ReshapeParameter)
+}
+
+void ReshapeParameter::SharedCtor() {
+  _cached_size_ = 0;
+  shape_ = NULL;
+  axis_ = 0;
+  num_axes_ = -1;
+}
+
+ReshapeParameter::~ReshapeParameter() {
+  // @@protoc_insertion_point(destructor:caffe.ReshapeParameter)
+  SharedDtor();
+}
+
+void ReshapeParameter::SharedDtor() {
+  if (this != &ReshapeParameter_default_instance_.get()) {
+    delete shape_;
+  }
+}
+
+void ReshapeParameter::SetCachedSize(int size) const {
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* ReshapeParameter::descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return ReshapeParameter_descriptor_;
+}
+
+const ReshapeParameter& ReshapeParameter::default_instance() {
+  protobuf_InitDefaults_caffe_2eproto();
+  return *internal_default_instance();
+}
+
+::google::protobuf::internal::ExplicitlyConstructed<ReshapeParameter> ReshapeParameter_default_instance_;
+
+ReshapeParameter* ReshapeParameter::New(::google::protobuf::Arena* arena) const {
+  ReshapeParameter* n = new ReshapeParameter;
+  if (arena != NULL) {
+    arena->Own(n);
+  }
+  return n;
+}
+
+void ReshapeParameter::Clear() {
+// @@protoc_insertion_point(message_clear_start:caffe.ReshapeParameter)
+  if (_has_bits_[0 / 32] & 7u) {
+    if (has_shape()) {
+      if (shape_ != NULL) shape_->::caffe::BlobShape::Clear();
+    }
+    axis_ = 0;
+    num_axes_ = -1;
+  }
+  _has_bits_.Clear();
+  if (_internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->Clear();
+  }
+}
+
+bool ReshapeParameter::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
+  ::google::protobuf::uint32 tag;
+  // @@protoc_insertion_point(parse_start:caffe.ReshapeParameter)
+  for (;;) {
+    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+    tag = p.first;
+    if (!p.second) goto handle_unusual;
+    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+      // optional .caffe.BlobShape shape = 1;
+      case 1: {
+        if (tag == 10) {
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+               input, mutable_shape()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(16)) goto parse_axis;
+        break;
+      }
+
+      // optional int32 axis = 2 [default = 0];
+      case 2: {
+        if (tag == 16) {
+         parse_axis:
+          set_has_axis();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
+                 input, &axis_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(24)) goto parse_num_axes;
+        break;
+      }
+
+      // optional int32 num_axes = 3 [default = -1];
+      case 3: {
+        if (tag == 24) {
+         parse_num_axes:
+          set_has_num_axes();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
+                 input, &num_axes_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectAtEnd()) goto success;
+        break;
+      }
+
+      default: {
+      handle_unusual:
+        if (tag == 0 ||
+            ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+          goto success;
+        }
+        DO_(::google::protobuf::internal::WireFormat::SkipField(
+              input, tag, mutable_unknown_fields()));
+        break;
+      }
+    }
+  }
+success:
+  // @@protoc_insertion_point(parse_success:caffe.ReshapeParameter)
+  return true;
+failure:
+  // @@protoc_insertion_point(parse_failure:caffe.ReshapeParameter)
+  return false;
+#undef DO_
+}
+
+void ReshapeParameter::SerializeWithCachedSizes(
+    ::google::protobuf::io::CodedOutputStream* output) const {
+  // @@protoc_insertion_point(serialize_start:caffe.ReshapeParameter)
+  // optional .caffe.BlobShape shape = 1;
+  if (has_shape()) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      1, *this->shape_, output);
+  }
+
+  // optional int32 axis = 2 [default = 0];
+  if (has_axis()) {
+    ::google::protobuf::internal::WireFormatLite::WriteInt32(2, this->axis(), output);
+  }
+
+  // optional int32 num_axes = 3 [default = -1];
+  if (has_num_axes()) {
+    ::google::protobuf::internal::WireFormatLite::WriteInt32(3, this->num_axes(), output);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
+        unknown_fields(), output);
+  }
+  // @@protoc_insertion_point(serialize_end:caffe.ReshapeParameter)
+}
+
+::google::protobuf::uint8* ReshapeParameter::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
+  (void)deterministic; // Unused
+  // @@protoc_insertion_point(serialize_to_array_start:caffe.ReshapeParameter)
+  // optional .caffe.BlobShape shape = 1;
+  if (has_shape()) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        1, *this->shape_, false, target);
+  }
+
+  // optional int32 axis = 2 [default = 0];
+  if (has_axis()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteInt32ToArray(2, this->axis(), target);
+  }
+
+  // optional int32 num_axes = 3 [default = -1];
+  if (has_num_axes()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteInt32ToArray(3, this->num_axes(), target);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
+        unknown_fields(), target);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:caffe.ReshapeParameter)
+  return target;
+}
+
+size_t ReshapeParameter::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:caffe.ReshapeParameter)
+  size_t total_size = 0;
+
+  if (_has_bits_[0 / 32] & 7u) {
+    // optional .caffe.BlobShape shape = 1;
+    if (has_shape()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          *this->shape_);
+    }
+
+    // optional int32 axis = 2 [default = 0];
+    if (has_axis()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::Int32Size(
+          this->axis());
+    }
+
+    // optional int32 num_axes = 3 [default = -1];
+    if (has_num_axes()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::Int32Size(
+          this->num_axes());
+    }
+
+  }
+  if (_internal_metadata_.have_unknown_fields()) {
+    total_size +=
+      ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
+        unknown_fields());
+  }
+  int cached_size = ::google::protobuf::internal::ToCachedSize(total_size);
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = cached_size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+  return total_size;
+}
+
+void ReshapeParameter::MergeFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_merge_from_start:caffe.ReshapeParameter)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const ReshapeParameter* source =
+      ::google::protobuf::internal::DynamicCastToGenerated<const ReshapeParameter>(
+          &from);
+  if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:caffe.ReshapeParameter)
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:caffe.ReshapeParameter)
+    UnsafeMergeFrom(*source);
+  }
+}
+
+void ReshapeParameter::MergeFrom(const ReshapeParameter& from) {
+// @@protoc_insertion_point(class_specific_merge_from_start:caffe.ReshapeParameter)
+  if (GOOGLE_PREDICT_TRUE(&from != this)) {
+    UnsafeMergeFrom(from);
+  } else {
+    MergeFromFail(__LINE__);
+  }
+}
+
+void ReshapeParameter::UnsafeMergeFrom(const ReshapeParameter& from) {
+  GOOGLE_DCHECK(&from != this);
+  if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+    if (from.has_shape()) {
+      mutable_shape()->::caffe::BlobShape::MergeFrom(from.shape());
+    }
+    if (from.has_axis()) {
+      set_axis(from.axis());
+    }
+    if (from.has_num_axes()) {
+      set_num_axes(from.num_axes());
+    }
+  }
+  if (from._internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::UnknownFieldSet::MergeToInternalMetdata(
+      from.unknown_fields(), &_internal_metadata_);
+  }
+}
+
+void ReshapeParameter::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:caffe.ReshapeParameter)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void ReshapeParameter::CopyFrom(const ReshapeParameter& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:caffe.ReshapeParameter)
+  if (&from == this) return;
+  Clear();
+  UnsafeMergeFrom(from);
+}
+
+bool ReshapeParameter::IsInitialized() const {
+
+  return true;
+}
+
+void ReshapeParameter::Swap(ReshapeParameter* other) {
+  if (other == this) return;
+  InternalSwap(other);
+}
+void ReshapeParameter::InternalSwap(ReshapeParameter* other) {
+  std::swap(shape_, other->shape_);
+  std::swap(axis_, other->axis_);
+  std::swap(num_axes_, other->num_axes_);
+  std::swap(_has_bits_[0], other->_has_bits_[0]);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
+}
+
+::google::protobuf::Metadata ReshapeParameter::GetMetadata() const {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::Metadata metadata;
+  metadata.descriptor = ReshapeParameter_descriptor_;
+  metadata.reflection = ReshapeParameter_reflection_;
+  return metadata;
+}
+
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// ReshapeParameter
+
+// optional .caffe.BlobShape shape = 1;
+bool ReshapeParameter::has_shape() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+void ReshapeParameter::set_has_shape() {
+  _has_bits_[0] |= 0x00000001u;
+}
+void ReshapeParameter::clear_has_shape() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+void ReshapeParameter::clear_shape() {
+  if (shape_ != NULL) shape_->::caffe::BlobShape::Clear();
+  clear_has_shape();
+}
+const ::caffe::BlobShape& ReshapeParameter::shape() const {
+  // @@protoc_insertion_point(field_get:caffe.ReshapeParameter.shape)
+  return shape_ != NULL ? *shape_
+                         : *::caffe::BlobShape::internal_default_instance();
+}
+::caffe::BlobShape* ReshapeParameter::mutable_shape() {
+  set_has_shape();
+  if (shape_ == NULL) {
+    shape_ = new ::caffe::BlobShape;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.ReshapeParameter.shape)
+  return shape_;
+}
+::caffe::BlobShape* ReshapeParameter::release_shape() {
+  // @@protoc_insertion_point(field_release:caffe.ReshapeParameter.shape)
+  clear_has_shape();
+  ::caffe::BlobShape* temp = shape_;
+  shape_ = NULL;
+  return temp;
+}
+void ReshapeParameter::set_allocated_shape(::caffe::BlobShape* shape) {
+  delete shape_;
+  shape_ = shape;
+  if (shape) {
+    set_has_shape();
+  } else {
+    clear_has_shape();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.ReshapeParameter.shape)
+}
+
+// optional int32 axis = 2 [default = 0];
+bool ReshapeParameter::has_axis() const {
+  return (_has_bits_[0] & 0x00000002u) != 0;
+}
+void ReshapeParameter::set_has_axis() {
+  _has_bits_[0] |= 0x00000002u;
+}
+void ReshapeParameter::clear_has_axis() {
+  _has_bits_[0] &= ~0x00000002u;
+}
+void ReshapeParameter::clear_axis() {
+  axis_ = 0;
+  clear_has_axis();
+}
+::google::protobuf::int32 ReshapeParameter::axis() const {
+  // @@protoc_insertion_point(field_get:caffe.ReshapeParameter.axis)
+  return axis_;
+}
+void ReshapeParameter::set_axis(::google::protobuf::int32 value) {
+  set_has_axis();
+  axis_ = value;
+  // @@protoc_insertion_point(field_set:caffe.ReshapeParameter.axis)
+}
+
+// optional int32 num_axes = 3 [default = -1];
+bool ReshapeParameter::has_num_axes() const {
+  return (_has_bits_[0] & 0x00000004u) != 0;
+}
+void ReshapeParameter::set_has_num_axes() {
+  _has_bits_[0] |= 0x00000004u;
+}
+void ReshapeParameter::clear_has_num_axes() {
+  _has_bits_[0] &= ~0x00000004u;
+}
+void ReshapeParameter::clear_num_axes() {
+  num_axes_ = -1;
+  clear_has_num_axes();
+}
+::google::protobuf::int32 ReshapeParameter::num_axes() const {
+  // @@protoc_insertion_point(field_get:caffe.ReshapeParameter.num_axes)
+  return num_axes_;
+}
+void ReshapeParameter::set_num_axes(::google::protobuf::int32 value) {
+  set_has_num_axes();
+  num_axes_ = value;
+  // @@protoc_insertion_point(field_set:caffe.ReshapeParameter.num_axes)
+}
+
+inline const ReshapeParameter* ReshapeParameter::internal_default_instance() {
+  return &ReshapeParameter_default_instance_.get();
+}
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
+
+// ===================================================================
+
+const ::google::protobuf::EnumDescriptor* SigmoidParameter_Engine_descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return SigmoidParameter_Engine_descriptor_;
+}
+bool SigmoidParameter_Engine_IsValid(int value) {
+  switch (value) {
+    case 0:
+    case 1:
+    case 2:
+      return true;
+    default:
+      return false;
+  }
+}
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const SigmoidParameter_Engine SigmoidParameter::DEFAULT;
+const SigmoidParameter_Engine SigmoidParameter::CAFFE;
+const SigmoidParameter_Engine SigmoidParameter::CUDNN;
+const SigmoidParameter_Engine SigmoidParameter::Engine_MIN;
+const SigmoidParameter_Engine SigmoidParameter::Engine_MAX;
+const int SigmoidParameter::Engine_ARRAYSIZE;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const int SigmoidParameter::kEngineFieldNumber;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+
+SigmoidParameter::SigmoidParameter()
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+  if (this != internal_default_instance()) protobuf_InitDefaults_caffe_2eproto();
+  SharedCtor();
+  // @@protoc_insertion_point(constructor:caffe.SigmoidParameter)
+}
+
+void SigmoidParameter::InitAsDefaultInstance() {
+}
+
+SigmoidParameter::SigmoidParameter(const SigmoidParameter& from)
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
+  SharedCtor();
+  UnsafeMergeFrom(from);
+  // @@protoc_insertion_point(copy_constructor:caffe.SigmoidParameter)
+}
+
+void SigmoidParameter::SharedCtor() {
+  _cached_size_ = 0;
+  engine_ = 0;
+}
+
+SigmoidParameter::~SigmoidParameter() {
+  // @@protoc_insertion_point(destructor:caffe.SigmoidParameter)
+  SharedDtor();
+}
+
+void SigmoidParameter::SharedDtor() {
+}
+
+void SigmoidParameter::SetCachedSize(int size) const {
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* SigmoidParameter::descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return SigmoidParameter_descriptor_;
+}
+
+const SigmoidParameter& SigmoidParameter::default_instance() {
+  protobuf_InitDefaults_caffe_2eproto();
+  return *internal_default_instance();
+}
+
+::google::protobuf::internal::ExplicitlyConstructed<SigmoidParameter> SigmoidParameter_default_instance_;
+
+SigmoidParameter* SigmoidParameter::New(::google::protobuf::Arena* arena) const {
+  SigmoidParameter* n = new SigmoidParameter;
+  if (arena != NULL) {
+    arena->Own(n);
+  }
+  return n;
+}
+
+void SigmoidParameter::Clear() {
+// @@protoc_insertion_point(message_clear_start:caffe.SigmoidParameter)
+  engine_ = 0;
+  _has_bits_.Clear();
+  if (_internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->Clear();
+  }
+}
+
+bool SigmoidParameter::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
+  ::google::protobuf::uint32 tag;
+  // @@protoc_insertion_point(parse_start:caffe.SigmoidParameter)
+  for (;;) {
+    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+    tag = p.first;
+    if (!p.second) goto handle_unusual;
+    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+      // optional .caffe.SigmoidParameter.Engine engine = 1 [default = DEFAULT];
+      case 1: {
+        if (tag == 8) {
+          int value;
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>(
+                 input, &value)));
+          if (::caffe::SigmoidParameter_Engine_IsValid(value)) {
+            set_engine(static_cast< ::caffe::SigmoidParameter_Engine >(value));
+          } else {
+            mutable_unknown_fields()->AddVarint(1, value);
+          }
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectAtEnd()) goto success;
+        break;
+      }
+
+      default: {
+      handle_unusual:
+        if (tag == 0 ||
+            ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+          goto success;
+        }
+        DO_(::google::protobuf::internal::WireFormat::SkipField(
+              input, tag, mutable_unknown_fields()));
+        break;
+      }
+    }
+  }
+success:
+  // @@protoc_insertion_point(parse_success:caffe.SigmoidParameter)
+  return true;
+failure:
+  // @@protoc_insertion_point(parse_failure:caffe.SigmoidParameter)
+  return false;
+#undef DO_
+}
+
+void SigmoidParameter::SerializeWithCachedSizes(
+    ::google::protobuf::io::CodedOutputStream* output) const {
+  // @@protoc_insertion_point(serialize_start:caffe.SigmoidParameter)
+  // optional .caffe.SigmoidParameter.Engine engine = 1 [default = DEFAULT];
+  if (has_engine()) {
+    ::google::protobuf::internal::WireFormatLite::WriteEnum(
+      1, this->engine(), output);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
+        unknown_fields(), output);
+  }
+  // @@protoc_insertion_point(serialize_end:caffe.SigmoidParameter)
+}
+
+::google::protobuf::uint8* SigmoidParameter::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
+  (void)deterministic; // Unused
+  // @@protoc_insertion_point(serialize_to_array_start:caffe.SigmoidParameter)
+  // optional .caffe.SigmoidParameter.Engine engine = 1 [default = DEFAULT];
+  if (has_engine()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteEnumToArray(
+      1, this->engine(), target);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
+        unknown_fields(), target);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:caffe.SigmoidParameter)
+  return target;
+}
+
+size_t SigmoidParameter::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:caffe.SigmoidParameter)
+  size_t total_size = 0;
+
+  // optional .caffe.SigmoidParameter.Engine engine = 1 [default = DEFAULT];
+  if (has_engine()) {
+    total_size += 1 +
+      ::google::protobuf::internal::WireFormatLite::EnumSize(this->engine());
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    total_size +=
+      ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
+        unknown_fields());
+  }
+  int cached_size = ::google::protobuf::internal::ToCachedSize(total_size);
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = cached_size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+  return total_size;
+}
+
+void SigmoidParameter::MergeFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_merge_from_start:caffe.SigmoidParameter)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const SigmoidParameter* source =
+      ::google::protobuf::internal::DynamicCastToGenerated<const SigmoidParameter>(
+          &from);
+  if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:caffe.SigmoidParameter)
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:caffe.SigmoidParameter)
+    UnsafeMergeFrom(*source);
+  }
+}
+
+void SigmoidParameter::MergeFrom(const SigmoidParameter& from) {
+// @@protoc_insertion_point(class_specific_merge_from_start:caffe.SigmoidParameter)
+  if (GOOGLE_PREDICT_TRUE(&from != this)) {
+    UnsafeMergeFrom(from);
+  } else {
+    MergeFromFail(__LINE__);
+  }
+}
+
+void SigmoidParameter::UnsafeMergeFrom(const SigmoidParameter& from) {
+  GOOGLE_DCHECK(&from != this);
+  if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+    if (from.has_engine()) {
+      set_engine(from.engine());
+    }
+  }
+  if (from._internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::UnknownFieldSet::MergeToInternalMetdata(
+      from.unknown_fields(), &_internal_metadata_);
+  }
+}
+
+void SigmoidParameter::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:caffe.SigmoidParameter)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void SigmoidParameter::CopyFrom(const SigmoidParameter& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:caffe.SigmoidParameter)
+  if (&from == this) return;
+  Clear();
+  UnsafeMergeFrom(from);
+}
+
+bool SigmoidParameter::IsInitialized() const {
+
+  return true;
+}
+
+void SigmoidParameter::Swap(SigmoidParameter* other) {
+  if (other == this) return;
+  InternalSwap(other);
+}
+void SigmoidParameter::InternalSwap(SigmoidParameter* other) {
+  std::swap(engine_, other->engine_);
+  std::swap(_has_bits_[0], other->_has_bits_[0]);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
+}
+
+::google::protobuf::Metadata SigmoidParameter::GetMetadata() const {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::Metadata metadata;
+  metadata.descriptor = SigmoidParameter_descriptor_;
+  metadata.reflection = SigmoidParameter_reflection_;
+  return metadata;
+}
+
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// SigmoidParameter
+
+// optional .caffe.SigmoidParameter.Engine engine = 1 [default = DEFAULT];
+bool SigmoidParameter::has_engine() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+void SigmoidParameter::set_has_engine() {
+  _has_bits_[0] |= 0x00000001u;
+}
+void SigmoidParameter::clear_has_engine() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+void SigmoidParameter::clear_engine() {
+  engine_ = 0;
+  clear_has_engine();
+}
+::caffe::SigmoidParameter_Engine SigmoidParameter::engine() const {
+  // @@protoc_insertion_point(field_get:caffe.SigmoidParameter.engine)
+  return static_cast< ::caffe::SigmoidParameter_Engine >(engine_);
+}
+void SigmoidParameter::set_engine(::caffe::SigmoidParameter_Engine value) {
+  assert(::caffe::SigmoidParameter_Engine_IsValid(value));
+  set_has_engine();
+  engine_ = value;
+  // @@protoc_insertion_point(field_set:caffe.SigmoidParameter.engine)
+}
+
+inline const SigmoidParameter* SigmoidParameter::internal_default_instance() {
+  return &SigmoidParameter_default_instance_.get();
+}
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
+
+// ===================================================================
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const int SliceParameter::kAxisFieldNumber;
+const int SliceParameter::kSlicePointFieldNumber;
+const int SliceParameter::kSliceDimFieldNumber;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+
+SliceParameter::SliceParameter()
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+  if (this != internal_default_instance()) protobuf_InitDefaults_caffe_2eproto();
+  SharedCtor();
+  // @@protoc_insertion_point(constructor:caffe.SliceParameter)
+}
+
+void SliceParameter::InitAsDefaultInstance() {
+}
+
+SliceParameter::SliceParameter(const SliceParameter& from)
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
+  SharedCtor();
+  UnsafeMergeFrom(from);
+  // @@protoc_insertion_point(copy_constructor:caffe.SliceParameter)
+}
+
+void SliceParameter::SharedCtor() {
+  _cached_size_ = 0;
+  axis_ = 1;
+  slice_dim_ = 1u;
+}
+
+SliceParameter::~SliceParameter() {
+  // @@protoc_insertion_point(destructor:caffe.SliceParameter)
+  SharedDtor();
+}
+
+void SliceParameter::SharedDtor() {
+}
+
+void SliceParameter::SetCachedSize(int size) const {
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* SliceParameter::descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return SliceParameter_descriptor_;
+}
+
+const SliceParameter& SliceParameter::default_instance() {
+  protobuf_InitDefaults_caffe_2eproto();
+  return *internal_default_instance();
+}
+
+::google::protobuf::internal::ExplicitlyConstructed<SliceParameter> SliceParameter_default_instance_;
+
+SliceParameter* SliceParameter::New(::google::protobuf::Arena* arena) const {
+  SliceParameter* n = new SliceParameter;
+  if (arena != NULL) {
+    arena->Own(n);
+  }
+  return n;
+}
+
+void SliceParameter::Clear() {
+// @@protoc_insertion_point(message_clear_start:caffe.SliceParameter)
+  if (_has_bits_[0 / 32] & 5u) {
+    axis_ = 1;
+    slice_dim_ = 1u;
+  }
+  slice_point_.Clear();
+  _has_bits_.Clear();
+  if (_internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->Clear();
+  }
+}
+
+bool SliceParameter::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
+  ::google::protobuf::uint32 tag;
+  // @@protoc_insertion_point(parse_start:caffe.SliceParameter)
+  for (;;) {
+    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+    tag = p.first;
+    if (!p.second) goto handle_unusual;
+    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+      // optional uint32 slice_dim = 1 [default = 1];
+      case 1: {
+        if (tag == 8) {
+          set_has_slice_dim();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>(
+                 input, &slice_dim_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(16)) goto parse_slice_point;
+        break;
+      }
+
+      // repeated uint32 slice_point = 2;
+      case 2: {
+        if (tag == 16) {
+         parse_slice_point:
+          DO_((::google::protobuf::internal::WireFormatLite::ReadRepeatedPrimitive<
+                   ::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>(
+                 1, 16, input, this->mutable_slice_point())));
+        } else if (tag == 18) {
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPackedPrimitiveNoInline<
+                   ::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>(
+                 input, this->mutable_slice_point())));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(16)) goto parse_slice_point;
+        if (input->ExpectTag(24)) goto parse_axis;
+        break;
+      }
+
+      // optional int32 axis = 3 [default = 1];
+      case 3: {
+        if (tag == 24) {
+         parse_axis:
+          set_has_axis();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
+                 input, &axis_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectAtEnd()) goto success;
+        break;
+      }
+
+      default: {
+      handle_unusual:
+        if (tag == 0 ||
+            ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+          goto success;
+        }
+        DO_(::google::protobuf::internal::WireFormat::SkipField(
+              input, tag, mutable_unknown_fields()));
+        break;
+      }
+    }
+  }
+success:
+  // @@protoc_insertion_point(parse_success:caffe.SliceParameter)
+  return true;
+failure:
+  // @@protoc_insertion_point(parse_failure:caffe.SliceParameter)
+  return false;
+#undef DO_
+}
+
+void SliceParameter::SerializeWithCachedSizes(
+    ::google::protobuf::io::CodedOutputStream* output) const {
+  // @@protoc_insertion_point(serialize_start:caffe.SliceParameter)
+  // optional uint32 slice_dim = 1 [default = 1];
+  if (has_slice_dim()) {
+    ::google::protobuf::internal::WireFormatLite::WriteUInt32(1, this->slice_dim(), output);
+  }
+
+  // repeated uint32 slice_point = 2;
+  for (int i = 0; i < this->slice_point_size(); i++) {
+    ::google::protobuf::internal::WireFormatLite::WriteUInt32(
+      2, this->slice_point(i), output);
+  }
+
+  // optional int32 axis = 3 [default = 1];
+  if (has_axis()) {
+    ::google::protobuf::internal::WireFormatLite::WriteInt32(3, this->axis(), output);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
+        unknown_fields(), output);
+  }
+  // @@protoc_insertion_point(serialize_end:caffe.SliceParameter)
+}
+
+::google::protobuf::uint8* SliceParameter::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
+  (void)deterministic; // Unused
+  // @@protoc_insertion_point(serialize_to_array_start:caffe.SliceParameter)
+  // optional uint32 slice_dim = 1 [default = 1];
+  if (has_slice_dim()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteUInt32ToArray(1, this->slice_dim(), target);
+  }
+
+  // repeated uint32 slice_point = 2;
+  for (int i = 0; i < this->slice_point_size(); i++) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      WriteUInt32ToArray(2, this->slice_point(i), target);
+  }
+
+  // optional int32 axis = 3 [default = 1];
+  if (has_axis()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteInt32ToArray(3, this->axis(), target);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
+        unknown_fields(), target);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:caffe.SliceParameter)
+  return target;
+}
+
+size_t SliceParameter::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:caffe.SliceParameter)
+  size_t total_size = 0;
+
+  if (_has_bits_[0 / 32] & 5u) {
+    // optional int32 axis = 3 [default = 1];
+    if (has_axis()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::Int32Size(
+          this->axis());
+    }
+
+    // optional uint32 slice_dim = 1 [default = 1];
+    if (has_slice_dim()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::UInt32Size(
+          this->slice_dim());
+    }
+
+  }
+  // repeated uint32 slice_point = 2;
+  {
+    size_t data_size = 0;
+    unsigned int count = this->slice_point_size();
+    for (unsigned int i = 0; i < count; i++) {
+      data_size += ::google::protobuf::internal::WireFormatLite::
+        UInt32Size(this->slice_point(i));
+    }
+    total_size += 1 *
+                  ::google::protobuf::internal::FromIntSize(this->slice_point_size());
+    total_size += data_size;
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    total_size +=
+      ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
+        unknown_fields());
+  }
+  int cached_size = ::google::protobuf::internal::ToCachedSize(total_size);
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = cached_size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+  return total_size;
+}
+
+void SliceParameter::MergeFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_merge_from_start:caffe.SliceParameter)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const SliceParameter* source =
+      ::google::protobuf::internal::DynamicCastToGenerated<const SliceParameter>(
+          &from);
+  if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:caffe.SliceParameter)
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:caffe.SliceParameter)
+    UnsafeMergeFrom(*source);
+  }
+}
+
+void SliceParameter::MergeFrom(const SliceParameter& from) {
+// @@protoc_insertion_point(class_specific_merge_from_start:caffe.SliceParameter)
+  if (GOOGLE_PREDICT_TRUE(&from != this)) {
+    UnsafeMergeFrom(from);
+  } else {
+    MergeFromFail(__LINE__);
+  }
+}
+
+void SliceParameter::UnsafeMergeFrom(const SliceParameter& from) {
+  GOOGLE_DCHECK(&from != this);
+  slice_point_.UnsafeMergeFrom(from.slice_point_);
+  if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+    if (from.has_axis()) {
+      set_axis(from.axis());
+    }
+    if (from.has_slice_dim()) {
+      set_slice_dim(from.slice_dim());
+    }
+  }
+  if (from._internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::UnknownFieldSet::MergeToInternalMetdata(
+      from.unknown_fields(), &_internal_metadata_);
+  }
+}
+
+void SliceParameter::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:caffe.SliceParameter)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void SliceParameter::CopyFrom(const SliceParameter& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:caffe.SliceParameter)
+  if (&from == this) return;
+  Clear();
+  UnsafeMergeFrom(from);
+}
+
+bool SliceParameter::IsInitialized() const {
+
+  return true;
+}
+
+void SliceParameter::Swap(SliceParameter* other) {
+  if (other == this) return;
+  InternalSwap(other);
+}
+void SliceParameter::InternalSwap(SliceParameter* other) {
+  std::swap(axis_, other->axis_);
+  slice_point_.UnsafeArenaSwap(&other->slice_point_);
+  std::swap(slice_dim_, other->slice_dim_);
+  std::swap(_has_bits_[0], other->_has_bits_[0]);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
+}
+
+::google::protobuf::Metadata SliceParameter::GetMetadata() const {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::Metadata metadata;
+  metadata.descriptor = SliceParameter_descriptor_;
+  metadata.reflection = SliceParameter_reflection_;
+  return metadata;
+}
+
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// SliceParameter
+
+// optional int32 axis = 3 [default = 1];
+bool SliceParameter::has_axis() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+void SliceParameter::set_has_axis() {
+  _has_bits_[0] |= 0x00000001u;
+}
+void SliceParameter::clear_has_axis() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+void SliceParameter::clear_axis() {
+  axis_ = 1;
+  clear_has_axis();
+}
+::google::protobuf::int32 SliceParameter::axis() const {
+  // @@protoc_insertion_point(field_get:caffe.SliceParameter.axis)
+  return axis_;
+}
+void SliceParameter::set_axis(::google::protobuf::int32 value) {
+  set_has_axis();
+  axis_ = value;
+  // @@protoc_insertion_point(field_set:caffe.SliceParameter.axis)
+}
+
+// repeated uint32 slice_point = 2;
+int SliceParameter::slice_point_size() const {
+  return slice_point_.size();
+}
+void SliceParameter::clear_slice_point() {
+  slice_point_.Clear();
+}
+::google::protobuf::uint32 SliceParameter::slice_point(int index) const {
+  // @@protoc_insertion_point(field_get:caffe.SliceParameter.slice_point)
+  return slice_point_.Get(index);
+}
+void SliceParameter::set_slice_point(int index, ::google::protobuf::uint32 value) {
+  slice_point_.Set(index, value);
+  // @@protoc_insertion_point(field_set:caffe.SliceParameter.slice_point)
+}
+void SliceParameter::add_slice_point(::google::protobuf::uint32 value) {
+  slice_point_.Add(value);
+  // @@protoc_insertion_point(field_add:caffe.SliceParameter.slice_point)
+}
+const ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >&
+SliceParameter::slice_point() const {
+  // @@protoc_insertion_point(field_list:caffe.SliceParameter.slice_point)
+  return slice_point_;
+}
+::google::protobuf::RepeatedField< ::google::protobuf::uint32 >*
+SliceParameter::mutable_slice_point() {
+  // @@protoc_insertion_point(field_mutable_list:caffe.SliceParameter.slice_point)
+  return &slice_point_;
+}
+
+// optional uint32 slice_dim = 1 [default = 1];
+bool SliceParameter::has_slice_dim() const {
+  return (_has_bits_[0] & 0x00000004u) != 0;
+}
+void SliceParameter::set_has_slice_dim() {
+  _has_bits_[0] |= 0x00000004u;
+}
+void SliceParameter::clear_has_slice_dim() {
+  _has_bits_[0] &= ~0x00000004u;
+}
+void SliceParameter::clear_slice_dim() {
+  slice_dim_ = 1u;
+  clear_has_slice_dim();
+}
+::google::protobuf::uint32 SliceParameter::slice_dim() const {
+  // @@protoc_insertion_point(field_get:caffe.SliceParameter.slice_dim)
+  return slice_dim_;
+}
+void SliceParameter::set_slice_dim(::google::protobuf::uint32 value) {
+  set_has_slice_dim();
+  slice_dim_ = value;
+  // @@protoc_insertion_point(field_set:caffe.SliceParameter.slice_dim)
+}
+
+inline const SliceParameter* SliceParameter::internal_default_instance() {
+  return &SliceParameter_default_instance_.get();
+}
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
+
+// ===================================================================
+
+const ::google::protobuf::EnumDescriptor* SoftmaxParameter_Engine_descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return SoftmaxParameter_Engine_descriptor_;
+}
+bool SoftmaxParameter_Engine_IsValid(int value) {
+  switch (value) {
+    case 0:
+    case 1:
+    case 2:
+      return true;
+    default:
+      return false;
+  }
+}
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const SoftmaxParameter_Engine SoftmaxParameter::DEFAULT;
+const SoftmaxParameter_Engine SoftmaxParameter::CAFFE;
+const SoftmaxParameter_Engine SoftmaxParameter::CUDNN;
+const SoftmaxParameter_Engine SoftmaxParameter::Engine_MIN;
+const SoftmaxParameter_Engine SoftmaxParameter::Engine_MAX;
+const int SoftmaxParameter::Engine_ARRAYSIZE;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const int SoftmaxParameter::kEngineFieldNumber;
+const int SoftmaxParameter::kAxisFieldNumber;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+
+SoftmaxParameter::SoftmaxParameter()
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+  if (this != internal_default_instance()) protobuf_InitDefaults_caffe_2eproto();
+  SharedCtor();
+  // @@protoc_insertion_point(constructor:caffe.SoftmaxParameter)
+}
+
+void SoftmaxParameter::InitAsDefaultInstance() {
+}
+
+SoftmaxParameter::SoftmaxParameter(const SoftmaxParameter& from)
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
+  SharedCtor();
+  UnsafeMergeFrom(from);
+  // @@protoc_insertion_point(copy_constructor:caffe.SoftmaxParameter)
+}
+
+void SoftmaxParameter::SharedCtor() {
+  _cached_size_ = 0;
+  engine_ = 0;
+  axis_ = 1;
+}
+
+SoftmaxParameter::~SoftmaxParameter() {
+  // @@protoc_insertion_point(destructor:caffe.SoftmaxParameter)
+  SharedDtor();
+}
+
+void SoftmaxParameter::SharedDtor() {
+}
+
+void SoftmaxParameter::SetCachedSize(int size) const {
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* SoftmaxParameter::descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return SoftmaxParameter_descriptor_;
+}
+
+const SoftmaxParameter& SoftmaxParameter::default_instance() {
+  protobuf_InitDefaults_caffe_2eproto();
+  return *internal_default_instance();
+}
+
+::google::protobuf::internal::ExplicitlyConstructed<SoftmaxParameter> SoftmaxParameter_default_instance_;
+
+SoftmaxParameter* SoftmaxParameter::New(::google::protobuf::Arena* arena) const {
+  SoftmaxParameter* n = new SoftmaxParameter;
+  if (arena != NULL) {
+    arena->Own(n);
+  }
+  return n;
+}
+
+void SoftmaxParameter::Clear() {
+// @@protoc_insertion_point(message_clear_start:caffe.SoftmaxParameter)
+  if (_has_bits_[0 / 32] & 3u) {
+    engine_ = 0;
+    axis_ = 1;
+  }
+  _has_bits_.Clear();
+  if (_internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->Clear();
+  }
+}
+
+bool SoftmaxParameter::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
+  ::google::protobuf::uint32 tag;
+  // @@protoc_insertion_point(parse_start:caffe.SoftmaxParameter)
+  for (;;) {
+    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+    tag = p.first;
+    if (!p.second) goto handle_unusual;
+    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+      // optional .caffe.SoftmaxParameter.Engine engine = 1 [default = DEFAULT];
+      case 1: {
+        if (tag == 8) {
+          int value;
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>(
+                 input, &value)));
+          if (::caffe::SoftmaxParameter_Engine_IsValid(value)) {
+            set_engine(static_cast< ::caffe::SoftmaxParameter_Engine >(value));
+          } else {
+            mutable_unknown_fields()->AddVarint(1, value);
+          }
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(16)) goto parse_axis;
+        break;
+      }
+
+      // optional int32 axis = 2 [default = 1];
+      case 2: {
+        if (tag == 16) {
+         parse_axis:
+          set_has_axis();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
+                 input, &axis_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectAtEnd()) goto success;
+        break;
+      }
+
+      default: {
+      handle_unusual:
+        if (tag == 0 ||
+            ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+          goto success;
+        }
+        DO_(::google::protobuf::internal::WireFormat::SkipField(
+              input, tag, mutable_unknown_fields()));
+        break;
+      }
+    }
+  }
+success:
+  // @@protoc_insertion_point(parse_success:caffe.SoftmaxParameter)
+  return true;
+failure:
+  // @@protoc_insertion_point(parse_failure:caffe.SoftmaxParameter)
+  return false;
+#undef DO_
+}
+
+void SoftmaxParameter::SerializeWithCachedSizes(
+    ::google::protobuf::io::CodedOutputStream* output) const {
+  // @@protoc_insertion_point(serialize_start:caffe.SoftmaxParameter)
+  // optional .caffe.SoftmaxParameter.Engine engine = 1 [default = DEFAULT];
+  if (has_engine()) {
+    ::google::protobuf::internal::WireFormatLite::WriteEnum(
+      1, this->engine(), output);
+  }
+
+  // optional int32 axis = 2 [default = 1];
+  if (has_axis()) {
+    ::google::protobuf::internal::WireFormatLite::WriteInt32(2, this->axis(), output);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
+        unknown_fields(), output);
+  }
+  // @@protoc_insertion_point(serialize_end:caffe.SoftmaxParameter)
+}
+
+::google::protobuf::uint8* SoftmaxParameter::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
+  (void)deterministic; // Unused
+  // @@protoc_insertion_point(serialize_to_array_start:caffe.SoftmaxParameter)
+  // optional .caffe.SoftmaxParameter.Engine engine = 1 [default = DEFAULT];
+  if (has_engine()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteEnumToArray(
+      1, this->engine(), target);
+  }
+
+  // optional int32 axis = 2 [default = 1];
+  if (has_axis()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteInt32ToArray(2, this->axis(), target);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
+        unknown_fields(), target);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:caffe.SoftmaxParameter)
+  return target;
+}
+
+size_t SoftmaxParameter::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:caffe.SoftmaxParameter)
+  size_t total_size = 0;
+
+  if (_has_bits_[0 / 32] & 3u) {
+    // optional .caffe.SoftmaxParameter.Engine engine = 1 [default = DEFAULT];
+    if (has_engine()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::EnumSize(this->engine());
+    }
+
+    // optional int32 axis = 2 [default = 1];
+    if (has_axis()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::Int32Size(
+          this->axis());
+    }
+
+  }
+  if (_internal_metadata_.have_unknown_fields()) {
+    total_size +=
+      ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
+        unknown_fields());
+  }
+  int cached_size = ::google::protobuf::internal::ToCachedSize(total_size);
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = cached_size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+  return total_size;
+}
+
+void SoftmaxParameter::MergeFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_merge_from_start:caffe.SoftmaxParameter)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const SoftmaxParameter* source =
+      ::google::protobuf::internal::DynamicCastToGenerated<const SoftmaxParameter>(
+          &from);
+  if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:caffe.SoftmaxParameter)
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:caffe.SoftmaxParameter)
+    UnsafeMergeFrom(*source);
+  }
+}
+
+void SoftmaxParameter::MergeFrom(const SoftmaxParameter& from) {
+// @@protoc_insertion_point(class_specific_merge_from_start:caffe.SoftmaxParameter)
+  if (GOOGLE_PREDICT_TRUE(&from != this)) {
+    UnsafeMergeFrom(from);
+  } else {
+    MergeFromFail(__LINE__);
+  }
+}
+
+void SoftmaxParameter::UnsafeMergeFrom(const SoftmaxParameter& from) {
+  GOOGLE_DCHECK(&from != this);
+  if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+    if (from.has_engine()) {
+      set_engine(from.engine());
+    }
+    if (from.has_axis()) {
+      set_axis(from.axis());
+    }
+  }
+  if (from._internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::UnknownFieldSet::MergeToInternalMetdata(
+      from.unknown_fields(), &_internal_metadata_);
+  }
+}
+
+void SoftmaxParameter::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:caffe.SoftmaxParameter)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void SoftmaxParameter::CopyFrom(const SoftmaxParameter& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:caffe.SoftmaxParameter)
+  if (&from == this) return;
+  Clear();
+  UnsafeMergeFrom(from);
+}
+
+bool SoftmaxParameter::IsInitialized() const {
+
+  return true;
+}
+
+void SoftmaxParameter::Swap(SoftmaxParameter* other) {
+  if (other == this) return;
+  InternalSwap(other);
+}
+void SoftmaxParameter::InternalSwap(SoftmaxParameter* other) {
+  std::swap(engine_, other->engine_);
+  std::swap(axis_, other->axis_);
+  std::swap(_has_bits_[0], other->_has_bits_[0]);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
+}
+
+::google::protobuf::Metadata SoftmaxParameter::GetMetadata() const {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::Metadata metadata;
+  metadata.descriptor = SoftmaxParameter_descriptor_;
+  metadata.reflection = SoftmaxParameter_reflection_;
+  return metadata;
+}
+
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// SoftmaxParameter
+
+// optional .caffe.SoftmaxParameter.Engine engine = 1 [default = DEFAULT];
+bool SoftmaxParameter::has_engine() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+void SoftmaxParameter::set_has_engine() {
+  _has_bits_[0] |= 0x00000001u;
+}
+void SoftmaxParameter::clear_has_engine() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+void SoftmaxParameter::clear_engine() {
+  engine_ = 0;
+  clear_has_engine();
+}
+::caffe::SoftmaxParameter_Engine SoftmaxParameter::engine() const {
+  // @@protoc_insertion_point(field_get:caffe.SoftmaxParameter.engine)
+  return static_cast< ::caffe::SoftmaxParameter_Engine >(engine_);
+}
+void SoftmaxParameter::set_engine(::caffe::SoftmaxParameter_Engine value) {
+  assert(::caffe::SoftmaxParameter_Engine_IsValid(value));
+  set_has_engine();
+  engine_ = value;
+  // @@protoc_insertion_point(field_set:caffe.SoftmaxParameter.engine)
+}
+
+// optional int32 axis = 2 [default = 1];
+bool SoftmaxParameter::has_axis() const {
+  return (_has_bits_[0] & 0x00000002u) != 0;
+}
+void SoftmaxParameter::set_has_axis() {
+  _has_bits_[0] |= 0x00000002u;
+}
+void SoftmaxParameter::clear_has_axis() {
+  _has_bits_[0] &= ~0x00000002u;
+}
+void SoftmaxParameter::clear_axis() {
+  axis_ = 1;
+  clear_has_axis();
+}
+::google::protobuf::int32 SoftmaxParameter::axis() const {
+  // @@protoc_insertion_point(field_get:caffe.SoftmaxParameter.axis)
+  return axis_;
+}
+void SoftmaxParameter::set_axis(::google::protobuf::int32 value) {
+  set_has_axis();
+  axis_ = value;
+  // @@protoc_insertion_point(field_set:caffe.SoftmaxParameter.axis)
+}
+
+inline const SoftmaxParameter* SoftmaxParameter::internal_default_instance() {
+  return &SoftmaxParameter_default_instance_.get();
+}
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
+
+// ===================================================================
+
+const ::google::protobuf::EnumDescriptor* TanHParameter_Engine_descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return TanHParameter_Engine_descriptor_;
+}
+bool TanHParameter_Engine_IsValid(int value) {
+  switch (value) {
+    case 0:
+    case 1:
+    case 2:
+      return true;
+    default:
+      return false;
+  }
+}
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const TanHParameter_Engine TanHParameter::DEFAULT;
+const TanHParameter_Engine TanHParameter::CAFFE;
+const TanHParameter_Engine TanHParameter::CUDNN;
+const TanHParameter_Engine TanHParameter::Engine_MIN;
+const TanHParameter_Engine TanHParameter::Engine_MAX;
+const int TanHParameter::Engine_ARRAYSIZE;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const int TanHParameter::kEngineFieldNumber;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+
+TanHParameter::TanHParameter()
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+  if (this != internal_default_instance()) protobuf_InitDefaults_caffe_2eproto();
+  SharedCtor();
+  // @@protoc_insertion_point(constructor:caffe.TanHParameter)
+}
+
+void TanHParameter::InitAsDefaultInstance() {
+}
+
+TanHParameter::TanHParameter(const TanHParameter& from)
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
+  SharedCtor();
+  UnsafeMergeFrom(from);
+  // @@protoc_insertion_point(copy_constructor:caffe.TanHParameter)
+}
+
+void TanHParameter::SharedCtor() {
+  _cached_size_ = 0;
+  engine_ = 0;
+}
+
+TanHParameter::~TanHParameter() {
+  // @@protoc_insertion_point(destructor:caffe.TanHParameter)
+  SharedDtor();
+}
+
+void TanHParameter::SharedDtor() {
+}
+
+void TanHParameter::SetCachedSize(int size) const {
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* TanHParameter::descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return TanHParameter_descriptor_;
+}
+
+const TanHParameter& TanHParameter::default_instance() {
+  protobuf_InitDefaults_caffe_2eproto();
+  return *internal_default_instance();
+}
+
+::google::protobuf::internal::ExplicitlyConstructed<TanHParameter> TanHParameter_default_instance_;
+
+TanHParameter* TanHParameter::New(::google::protobuf::Arena* arena) const {
+  TanHParameter* n = new TanHParameter;
+  if (arena != NULL) {
+    arena->Own(n);
+  }
+  return n;
+}
+
+void TanHParameter::Clear() {
+// @@protoc_insertion_point(message_clear_start:caffe.TanHParameter)
+  engine_ = 0;
+  _has_bits_.Clear();
+  if (_internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->Clear();
+  }
+}
+
+bool TanHParameter::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
+  ::google::protobuf::uint32 tag;
+  // @@protoc_insertion_point(parse_start:caffe.TanHParameter)
+  for (;;) {
+    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+    tag = p.first;
+    if (!p.second) goto handle_unusual;
+    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+      // optional .caffe.TanHParameter.Engine engine = 1 [default = DEFAULT];
+      case 1: {
+        if (tag == 8) {
+          int value;
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>(
+                 input, &value)));
+          if (::caffe::TanHParameter_Engine_IsValid(value)) {
+            set_engine(static_cast< ::caffe::TanHParameter_Engine >(value));
+          } else {
+            mutable_unknown_fields()->AddVarint(1, value);
+          }
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectAtEnd()) goto success;
+        break;
+      }
+
+      default: {
+      handle_unusual:
+        if (tag == 0 ||
+            ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+          goto success;
+        }
+        DO_(::google::protobuf::internal::WireFormat::SkipField(
+              input, tag, mutable_unknown_fields()));
+        break;
+      }
+    }
+  }
+success:
+  // @@protoc_insertion_point(parse_success:caffe.TanHParameter)
+  return true;
+failure:
+  // @@protoc_insertion_point(parse_failure:caffe.TanHParameter)
+  return false;
+#undef DO_
+}
+
+void TanHParameter::SerializeWithCachedSizes(
+    ::google::protobuf::io::CodedOutputStream* output) const {
+  // @@protoc_insertion_point(serialize_start:caffe.TanHParameter)
+  // optional .caffe.TanHParameter.Engine engine = 1 [default = DEFAULT];
+  if (has_engine()) {
+    ::google::protobuf::internal::WireFormatLite::WriteEnum(
+      1, this->engine(), output);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
+        unknown_fields(), output);
+  }
+  // @@protoc_insertion_point(serialize_end:caffe.TanHParameter)
+}
+
+::google::protobuf::uint8* TanHParameter::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
+  (void)deterministic; // Unused
+  // @@protoc_insertion_point(serialize_to_array_start:caffe.TanHParameter)
+  // optional .caffe.TanHParameter.Engine engine = 1 [default = DEFAULT];
+  if (has_engine()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteEnumToArray(
+      1, this->engine(), target);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
+        unknown_fields(), target);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:caffe.TanHParameter)
+  return target;
+}
+
+size_t TanHParameter::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:caffe.TanHParameter)
+  size_t total_size = 0;
+
+  // optional .caffe.TanHParameter.Engine engine = 1 [default = DEFAULT];
+  if (has_engine()) {
+    total_size += 1 +
+      ::google::protobuf::internal::WireFormatLite::EnumSize(this->engine());
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    total_size +=
+      ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
+        unknown_fields());
+  }
+  int cached_size = ::google::protobuf::internal::ToCachedSize(total_size);
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = cached_size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+  return total_size;
+}
+
+void TanHParameter::MergeFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_merge_from_start:caffe.TanHParameter)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const TanHParameter* source =
+      ::google::protobuf::internal::DynamicCastToGenerated<const TanHParameter>(
+          &from);
+  if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:caffe.TanHParameter)
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:caffe.TanHParameter)
+    UnsafeMergeFrom(*source);
+  }
+}
+
+void TanHParameter::MergeFrom(const TanHParameter& from) {
+// @@protoc_insertion_point(class_specific_merge_from_start:caffe.TanHParameter)
+  if (GOOGLE_PREDICT_TRUE(&from != this)) {
+    UnsafeMergeFrom(from);
+  } else {
+    MergeFromFail(__LINE__);
+  }
+}
+
+void TanHParameter::UnsafeMergeFrom(const TanHParameter& from) {
+  GOOGLE_DCHECK(&from != this);
+  if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+    if (from.has_engine()) {
+      set_engine(from.engine());
+    }
+  }
+  if (from._internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::UnknownFieldSet::MergeToInternalMetdata(
+      from.unknown_fields(), &_internal_metadata_);
+  }
+}
+
+void TanHParameter::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:caffe.TanHParameter)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void TanHParameter::CopyFrom(const TanHParameter& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:caffe.TanHParameter)
+  if (&from == this) return;
+  Clear();
+  UnsafeMergeFrom(from);
+}
+
+bool TanHParameter::IsInitialized() const {
+
+  return true;
+}
+
+void TanHParameter::Swap(TanHParameter* other) {
+  if (other == this) return;
+  InternalSwap(other);
+}
+void TanHParameter::InternalSwap(TanHParameter* other) {
+  std::swap(engine_, other->engine_);
+  std::swap(_has_bits_[0], other->_has_bits_[0]);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
+}
+
+::google::protobuf::Metadata TanHParameter::GetMetadata() const {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::Metadata metadata;
+  metadata.descriptor = TanHParameter_descriptor_;
+  metadata.reflection = TanHParameter_reflection_;
+  return metadata;
+}
+
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// TanHParameter
+
+// optional .caffe.TanHParameter.Engine engine = 1 [default = DEFAULT];
+bool TanHParameter::has_engine() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+void TanHParameter::set_has_engine() {
+  _has_bits_[0] |= 0x00000001u;
+}
+void TanHParameter::clear_has_engine() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+void TanHParameter::clear_engine() {
+  engine_ = 0;
+  clear_has_engine();
+}
+::caffe::TanHParameter_Engine TanHParameter::engine() const {
+  // @@protoc_insertion_point(field_get:caffe.TanHParameter.engine)
+  return static_cast< ::caffe::TanHParameter_Engine >(engine_);
+}
+void TanHParameter::set_engine(::caffe::TanHParameter_Engine value) {
+  assert(::caffe::TanHParameter_Engine_IsValid(value));
+  set_has_engine();
+  engine_ = value;
+  // @@protoc_insertion_point(field_set:caffe.TanHParameter.engine)
+}
+
+inline const TanHParameter* TanHParameter::internal_default_instance() {
+  return &TanHParameter_default_instance_.get();
+}
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
+
+// ===================================================================
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const int ThresholdParameter::kThresholdFieldNumber;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+
+ThresholdParameter::ThresholdParameter()
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+  if (this != internal_default_instance()) protobuf_InitDefaults_caffe_2eproto();
+  SharedCtor();
+  // @@protoc_insertion_point(constructor:caffe.ThresholdParameter)
+}
+
+void ThresholdParameter::InitAsDefaultInstance() {
+}
+
+ThresholdParameter::ThresholdParameter(const ThresholdParameter& from)
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
+  SharedCtor();
+  UnsafeMergeFrom(from);
+  // @@protoc_insertion_point(copy_constructor:caffe.ThresholdParameter)
+}
+
+void ThresholdParameter::SharedCtor() {
+  _cached_size_ = 0;
+  threshold_ = 0;
+}
+
+ThresholdParameter::~ThresholdParameter() {
+  // @@protoc_insertion_point(destructor:caffe.ThresholdParameter)
+  SharedDtor();
+}
+
+void ThresholdParameter::SharedDtor() {
+}
+
+void ThresholdParameter::SetCachedSize(int size) const {
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* ThresholdParameter::descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return ThresholdParameter_descriptor_;
+}
+
+const ThresholdParameter& ThresholdParameter::default_instance() {
+  protobuf_InitDefaults_caffe_2eproto();
+  return *internal_default_instance();
+}
+
+::google::protobuf::internal::ExplicitlyConstructed<ThresholdParameter> ThresholdParameter_default_instance_;
+
+ThresholdParameter* ThresholdParameter::New(::google::protobuf::Arena* arena) const {
+  ThresholdParameter* n = new ThresholdParameter;
+  if (arena != NULL) {
+    arena->Own(n);
+  }
+  return n;
+}
+
+void ThresholdParameter::Clear() {
+// @@protoc_insertion_point(message_clear_start:caffe.ThresholdParameter)
+  threshold_ = 0;
+  _has_bits_.Clear();
+  if (_internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->Clear();
+  }
+}
+
+bool ThresholdParameter::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
+  ::google::protobuf::uint32 tag;
+  // @@protoc_insertion_point(parse_start:caffe.ThresholdParameter)
+  for (;;) {
+    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+    tag = p.first;
+    if (!p.second) goto handle_unusual;
+    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+      // optional float threshold = 1 [default = 0];
+      case 1: {
+        if (tag == 13) {
+          set_has_threshold();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
+                 input, &threshold_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectAtEnd()) goto success;
+        break;
+      }
+
+      default: {
+      handle_unusual:
+        if (tag == 0 ||
+            ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+          goto success;
+        }
+        DO_(::google::protobuf::internal::WireFormat::SkipField(
+              input, tag, mutable_unknown_fields()));
+        break;
+      }
+    }
+  }
+success:
+  // @@protoc_insertion_point(parse_success:caffe.ThresholdParameter)
+  return true;
+failure:
+  // @@protoc_insertion_point(parse_failure:caffe.ThresholdParameter)
+  return false;
+#undef DO_
+}
+
+void ThresholdParameter::SerializeWithCachedSizes(
+    ::google::protobuf::io::CodedOutputStream* output) const {
+  // @@protoc_insertion_point(serialize_start:caffe.ThresholdParameter)
+  // optional float threshold = 1 [default = 0];
+  if (has_threshold()) {
+    ::google::protobuf::internal::WireFormatLite::WriteFloat(1, this->threshold(), output);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
+        unknown_fields(), output);
+  }
+  // @@protoc_insertion_point(serialize_end:caffe.ThresholdParameter)
+}
+
+::google::protobuf::uint8* ThresholdParameter::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
+  (void)deterministic; // Unused
+  // @@protoc_insertion_point(serialize_to_array_start:caffe.ThresholdParameter)
+  // optional float threshold = 1 [default = 0];
+  if (has_threshold()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteFloatToArray(1, this->threshold(), target);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
+        unknown_fields(), target);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:caffe.ThresholdParameter)
+  return target;
+}
+
+size_t ThresholdParameter::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:caffe.ThresholdParameter)
+  size_t total_size = 0;
+
+  // optional float threshold = 1 [default = 0];
+  if (has_threshold()) {
+    total_size += 1 + 4;
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    total_size +=
+      ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
+        unknown_fields());
+  }
+  int cached_size = ::google::protobuf::internal::ToCachedSize(total_size);
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = cached_size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+  return total_size;
+}
+
+void ThresholdParameter::MergeFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_merge_from_start:caffe.ThresholdParameter)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const ThresholdParameter* source =
+      ::google::protobuf::internal::DynamicCastToGenerated<const ThresholdParameter>(
+          &from);
+  if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:caffe.ThresholdParameter)
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:caffe.ThresholdParameter)
+    UnsafeMergeFrom(*source);
+  }
+}
+
+void ThresholdParameter::MergeFrom(const ThresholdParameter& from) {
+// @@protoc_insertion_point(class_specific_merge_from_start:caffe.ThresholdParameter)
+  if (GOOGLE_PREDICT_TRUE(&from != this)) {
+    UnsafeMergeFrom(from);
+  } else {
+    MergeFromFail(__LINE__);
+  }
+}
+
+void ThresholdParameter::UnsafeMergeFrom(const ThresholdParameter& from) {
+  GOOGLE_DCHECK(&from != this);
+  if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+    if (from.has_threshold()) {
+      set_threshold(from.threshold());
+    }
+  }
+  if (from._internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::UnknownFieldSet::MergeToInternalMetdata(
+      from.unknown_fields(), &_internal_metadata_);
+  }
+}
+
+void ThresholdParameter::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:caffe.ThresholdParameter)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void ThresholdParameter::CopyFrom(const ThresholdParameter& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:caffe.ThresholdParameter)
+  if (&from == this) return;
+  Clear();
+  UnsafeMergeFrom(from);
+}
+
+bool ThresholdParameter::IsInitialized() const {
+
+  return true;
+}
+
+void ThresholdParameter::Swap(ThresholdParameter* other) {
+  if (other == this) return;
+  InternalSwap(other);
+}
+void ThresholdParameter::InternalSwap(ThresholdParameter* other) {
+  std::swap(threshold_, other->threshold_);
+  std::swap(_has_bits_[0], other->_has_bits_[0]);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
+}
+
+::google::protobuf::Metadata ThresholdParameter::GetMetadata() const {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::Metadata metadata;
+  metadata.descriptor = ThresholdParameter_descriptor_;
+  metadata.reflection = ThresholdParameter_reflection_;
+  return metadata;
+}
+
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// ThresholdParameter
+
+// optional float threshold = 1 [default = 0];
+bool ThresholdParameter::has_threshold() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+void ThresholdParameter::set_has_threshold() {
+  _has_bits_[0] |= 0x00000001u;
+}
+void ThresholdParameter::clear_has_threshold() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+void ThresholdParameter::clear_threshold() {
+  threshold_ = 0;
+  clear_has_threshold();
+}
+float ThresholdParameter::threshold() const {
+  // @@protoc_insertion_point(field_get:caffe.ThresholdParameter.threshold)
+  return threshold_;
+}
+void ThresholdParameter::set_threshold(float value) {
+  set_has_threshold();
+  threshold_ = value;
+  // @@protoc_insertion_point(field_set:caffe.ThresholdParameter.threshold)
+}
+
+inline const ThresholdParameter* ThresholdParameter::internal_default_instance() {
+  return &ThresholdParameter_default_instance_.get();
+}
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
+
+// ===================================================================
+
+::std::string* WindowDataParameter::_default_crop_mode_ = NULL;
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const int WindowDataParameter::kSourceFieldNumber;
+const int WindowDataParameter::kScaleFieldNumber;
+const int WindowDataParameter::kMeanFileFieldNumber;
+const int WindowDataParameter::kBatchSizeFieldNumber;
+const int WindowDataParameter::kCropSizeFieldNumber;
+const int WindowDataParameter::kMirrorFieldNumber;
+const int WindowDataParameter::kFgThresholdFieldNumber;
+const int WindowDataParameter::kBgThresholdFieldNumber;
+const int WindowDataParameter::kFgFractionFieldNumber;
+const int WindowDataParameter::kContextPadFieldNumber;
+const int WindowDataParameter::kCropModeFieldNumber;
+const int WindowDataParameter::kCacheImagesFieldNumber;
+const int WindowDataParameter::kRootFolderFieldNumber;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+
+WindowDataParameter::WindowDataParameter()
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+  if (this != internal_default_instance()) protobuf_InitDefaults_caffe_2eproto();
+  SharedCtor();
+  // @@protoc_insertion_point(constructor:caffe.WindowDataParameter)
+}
+
+void WindowDataParameter::InitAsDefaultInstance() {
+}
+
+WindowDataParameter::WindowDataParameter(const WindowDataParameter& from)
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
+  SharedCtor();
+  UnsafeMergeFrom(from);
+  // @@protoc_insertion_point(copy_constructor:caffe.WindowDataParameter)
+}
+
+void WindowDataParameter::SharedCtor() {
+  _cached_size_ = 0;
+  source_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  mean_file_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  crop_mode_.UnsafeSetDefault(_default_crop_mode_);
+  root_folder_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  ::memset(&batch_size_, 0, reinterpret_cast<char*>(&context_pad_) -
+    reinterpret_cast<char*>(&batch_size_) + sizeof(context_pad_));
+  scale_ = 1;
+  fg_threshold_ = 0.5f;
+  bg_threshold_ = 0.5f;
+  fg_fraction_ = 0.25f;
+}
+
+WindowDataParameter::~WindowDataParameter() {
+  // @@protoc_insertion_point(destructor:caffe.WindowDataParameter)
+  SharedDtor();
+}
+
+void WindowDataParameter::SharedDtor() {
+  source_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  mean_file_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  crop_mode_.DestroyNoArena(_default_crop_mode_);
+  root_folder_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+
+void WindowDataParameter::SetCachedSize(int size) const {
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* WindowDataParameter::descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return WindowDataParameter_descriptor_;
+}
+
+const WindowDataParameter& WindowDataParameter::default_instance() {
+  protobuf_InitDefaults_caffe_2eproto();
+  return *internal_default_instance();
+}
+
+::google::protobuf::internal::ExplicitlyConstructed<WindowDataParameter> WindowDataParameter_default_instance_;
+
+WindowDataParameter* WindowDataParameter::New(::google::protobuf::Arena* arena) const {
+  WindowDataParameter* n = new WindowDataParameter;
+  if (arena != NULL) {
+    arena->Own(n);
+  }
+  return n;
+}
+
+void WindowDataParameter::Clear() {
+// @@protoc_insertion_point(message_clear_start:caffe.WindowDataParameter)
+#if defined(__clang__)
+#define ZR_HELPER_(f) \
+  _Pragma("clang diagnostic push") \
+  _Pragma("clang diagnostic ignored \"-Winvalid-offsetof\"") \
+  __builtin_offsetof(WindowDataParameter, f) \
+  _Pragma("clang diagnostic pop")
+#else
+#define ZR_HELPER_(f) reinterpret_cast<char*>(\
+  &reinterpret_cast<WindowDataParameter*>(16)->f)
+#endif
+
+#define ZR_(first, last) do {\
+  ::memset(&(first), 0,\
+           ZR_HELPER_(last) - ZR_HELPER_(first) + sizeof(last));\
+} while (0)
+
+  if (_has_bits_[0 / 32] & 255u) {
+    ZR_(batch_size_, mirror_);
+    if (has_source()) {
+      source_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+    }
+    scale_ = 1;
+    if (has_mean_file()) {
+      mean_file_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+    }
+    fg_threshold_ = 0.5f;
+    bg_threshold_ = 0.5f;
+  }
+  if (_has_bits_[8 / 32] & 7936u) {
+    ZR_(cache_images_, context_pad_);
+    fg_fraction_ = 0.25f;
+    if (has_crop_mode()) {
+      crop_mode_.ClearToDefaultNoArena(_default_crop_mode_);
+    }
+    if (has_root_folder()) {
+      root_folder_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+    }
+  }
+
+#undef ZR_HELPER_
+#undef ZR_
+
+  _has_bits_.Clear();
+  if (_internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->Clear();
+  }
+}
+
+bool WindowDataParameter::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
+  ::google::protobuf::uint32 tag;
+  // @@protoc_insertion_point(parse_start:caffe.WindowDataParameter)
+  for (;;) {
+    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+    tag = p.first;
+    if (!p.second) goto handle_unusual;
+    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+      // optional string source = 1;
+      case 1: {
+        if (tag == 10) {
+          DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+                input, this->mutable_source()));
+          ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+            this->source().data(), this->source().length(),
+            ::google::protobuf::internal::WireFormat::PARSE,
+            "caffe.WindowDataParameter.source");
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(21)) goto parse_scale;
+        break;
+      }
+
+      // optional float scale = 2 [default = 1];
+      case 2: {
+        if (tag == 21) {
+         parse_scale:
+          set_has_scale();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
+                 input, &scale_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(26)) goto parse_mean_file;
+        break;
+      }
+
+      // optional string mean_file = 3;
+      case 3: {
+        if (tag == 26) {
+         parse_mean_file:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+                input, this->mutable_mean_file()));
+          ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+            this->mean_file().data(), this->mean_file().length(),
+            ::google::protobuf::internal::WireFormat::PARSE,
+            "caffe.WindowDataParameter.mean_file");
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(32)) goto parse_batch_size;
+        break;
+      }
+
+      // optional uint32 batch_size = 4;
+      case 4: {
+        if (tag == 32) {
+         parse_batch_size:
+          set_has_batch_size();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>(
+                 input, &batch_size_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(40)) goto parse_crop_size;
+        break;
+      }
+
+      // optional uint32 crop_size = 5 [default = 0];
+      case 5: {
+        if (tag == 40) {
+         parse_crop_size:
+          set_has_crop_size();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>(
+                 input, &crop_size_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(48)) goto parse_mirror;
+        break;
+      }
+
+      // optional bool mirror = 6 [default = false];
+      case 6: {
+        if (tag == 48) {
+         parse_mirror:
+          set_has_mirror();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>(
+                 input, &mirror_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(61)) goto parse_fg_threshold;
+        break;
+      }
+
+      // optional float fg_threshold = 7 [default = 0.5];
+      case 7: {
+        if (tag == 61) {
+         parse_fg_threshold:
+          set_has_fg_threshold();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
+                 input, &fg_threshold_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(69)) goto parse_bg_threshold;
+        break;
+      }
+
+      // optional float bg_threshold = 8 [default = 0.5];
+      case 8: {
+        if (tag == 69) {
+         parse_bg_threshold:
+          set_has_bg_threshold();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
+                 input, &bg_threshold_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(77)) goto parse_fg_fraction;
+        break;
+      }
+
+      // optional float fg_fraction = 9 [default = 0.25];
+      case 9: {
+        if (tag == 77) {
+         parse_fg_fraction:
+          set_has_fg_fraction();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
+                 input, &fg_fraction_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(80)) goto parse_context_pad;
+        break;
+      }
+
+      // optional uint32 context_pad = 10 [default = 0];
+      case 10: {
+        if (tag == 80) {
+         parse_context_pad:
+          set_has_context_pad();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>(
+                 input, &context_pad_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(90)) goto parse_crop_mode;
+        break;
+      }
+
+      // optional string crop_mode = 11 [default = "warp"];
+      case 11: {
+        if (tag == 90) {
+         parse_crop_mode:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+                input, this->mutable_crop_mode()));
+          ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+            this->crop_mode().data(), this->crop_mode().length(),
+            ::google::protobuf::internal::WireFormat::PARSE,
+            "caffe.WindowDataParameter.crop_mode");
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(96)) goto parse_cache_images;
+        break;
+      }
+
+      // optional bool cache_images = 12 [default = false];
+      case 12: {
+        if (tag == 96) {
+         parse_cache_images:
+          set_has_cache_images();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>(
+                 input, &cache_images_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(106)) goto parse_root_folder;
+        break;
+      }
+
+      // optional string root_folder = 13 [default = ""];
+      case 13: {
+        if (tag == 106) {
+         parse_root_folder:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+                input, this->mutable_root_folder()));
+          ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+            this->root_folder().data(), this->root_folder().length(),
+            ::google::protobuf::internal::WireFormat::PARSE,
+            "caffe.WindowDataParameter.root_folder");
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectAtEnd()) goto success;
+        break;
+      }
+
+      default: {
+      handle_unusual:
+        if (tag == 0 ||
+            ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+          goto success;
+        }
+        DO_(::google::protobuf::internal::WireFormat::SkipField(
+              input, tag, mutable_unknown_fields()));
+        break;
+      }
+    }
+  }
+success:
+  // @@protoc_insertion_point(parse_success:caffe.WindowDataParameter)
+  return true;
+failure:
+  // @@protoc_insertion_point(parse_failure:caffe.WindowDataParameter)
+  return false;
+#undef DO_
+}
+
+void WindowDataParameter::SerializeWithCachedSizes(
+    ::google::protobuf::io::CodedOutputStream* output) const {
+  // @@protoc_insertion_point(serialize_start:caffe.WindowDataParameter)
+  // optional string source = 1;
+  if (has_source()) {
+    ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->source().data(), this->source().length(),
+      ::google::protobuf::internal::WireFormat::SERIALIZE,
+      "caffe.WindowDataParameter.source");
+    ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
+      1, this->source(), output);
+  }
+
+  // optional float scale = 2 [default = 1];
+  if (has_scale()) {
+    ::google::protobuf::internal::WireFormatLite::WriteFloat(2, this->scale(), output);
+  }
+
+  // optional string mean_file = 3;
+  if (has_mean_file()) {
+    ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->mean_file().data(), this->mean_file().length(),
+      ::google::protobuf::internal::WireFormat::SERIALIZE,
+      "caffe.WindowDataParameter.mean_file");
+    ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
+      3, this->mean_file(), output);
+  }
+
+  // optional uint32 batch_size = 4;
+  if (has_batch_size()) {
+    ::google::protobuf::internal::WireFormatLite::WriteUInt32(4, this->batch_size(), output);
+  }
+
+  // optional uint32 crop_size = 5 [default = 0];
+  if (has_crop_size()) {
+    ::google::protobuf::internal::WireFormatLite::WriteUInt32(5, this->crop_size(), output);
+  }
+
+  // optional bool mirror = 6 [default = false];
+  if (has_mirror()) {
+    ::google::protobuf::internal::WireFormatLite::WriteBool(6, this->mirror(), output);
+  }
+
+  // optional float fg_threshold = 7 [default = 0.5];
+  if (has_fg_threshold()) {
+    ::google::protobuf::internal::WireFormatLite::WriteFloat(7, this->fg_threshold(), output);
+  }
+
+  // optional float bg_threshold = 8 [default = 0.5];
+  if (has_bg_threshold()) {
+    ::google::protobuf::internal::WireFormatLite::WriteFloat(8, this->bg_threshold(), output);
+  }
+
+  // optional float fg_fraction = 9 [default = 0.25];
+  if (has_fg_fraction()) {
+    ::google::protobuf::internal::WireFormatLite::WriteFloat(9, this->fg_fraction(), output);
+  }
+
+  // optional uint32 context_pad = 10 [default = 0];
+  if (has_context_pad()) {
+    ::google::protobuf::internal::WireFormatLite::WriteUInt32(10, this->context_pad(), output);
+  }
+
+  // optional string crop_mode = 11 [default = "warp"];
+  if (has_crop_mode()) {
+    ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->crop_mode().data(), this->crop_mode().length(),
+      ::google::protobuf::internal::WireFormat::SERIALIZE,
+      "caffe.WindowDataParameter.crop_mode");
+    ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
+      11, this->crop_mode(), output);
+  }
+
+  // optional bool cache_images = 12 [default = false];
+  if (has_cache_images()) {
+    ::google::protobuf::internal::WireFormatLite::WriteBool(12, this->cache_images(), output);
+  }
+
+  // optional string root_folder = 13 [default = ""];
+  if (has_root_folder()) {
+    ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->root_folder().data(), this->root_folder().length(),
+      ::google::protobuf::internal::WireFormat::SERIALIZE,
+      "caffe.WindowDataParameter.root_folder");
+    ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
+      13, this->root_folder(), output);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
+        unknown_fields(), output);
+  }
+  // @@protoc_insertion_point(serialize_end:caffe.WindowDataParameter)
+}
+
+::google::protobuf::uint8* WindowDataParameter::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
+  (void)deterministic; // Unused
+  // @@protoc_insertion_point(serialize_to_array_start:caffe.WindowDataParameter)
+  // optional string source = 1;
+  if (has_source()) {
+    ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->source().data(), this->source().length(),
+      ::google::protobuf::internal::WireFormat::SERIALIZE,
+      "caffe.WindowDataParameter.source");
+    target =
+      ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
+        1, this->source(), target);
+  }
+
+  // optional float scale = 2 [default = 1];
+  if (has_scale()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteFloatToArray(2, this->scale(), target);
+  }
+
+  // optional string mean_file = 3;
+  if (has_mean_file()) {
+    ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->mean_file().data(), this->mean_file().length(),
+      ::google::protobuf::internal::WireFormat::SERIALIZE,
+      "caffe.WindowDataParameter.mean_file");
+    target =
+      ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
+        3, this->mean_file(), target);
+  }
+
+  // optional uint32 batch_size = 4;
+  if (has_batch_size()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteUInt32ToArray(4, this->batch_size(), target);
+  }
+
+  // optional uint32 crop_size = 5 [default = 0];
+  if (has_crop_size()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteUInt32ToArray(5, this->crop_size(), target);
+  }
+
+  // optional bool mirror = 6 [default = false];
+  if (has_mirror()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(6, this->mirror(), target);
+  }
+
+  // optional float fg_threshold = 7 [default = 0.5];
+  if (has_fg_threshold()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteFloatToArray(7, this->fg_threshold(), target);
+  }
+
+  // optional float bg_threshold = 8 [default = 0.5];
+  if (has_bg_threshold()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteFloatToArray(8, this->bg_threshold(), target);
+  }
+
+  // optional float fg_fraction = 9 [default = 0.25];
+  if (has_fg_fraction()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteFloatToArray(9, this->fg_fraction(), target);
+  }
+
+  // optional uint32 context_pad = 10 [default = 0];
+  if (has_context_pad()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteUInt32ToArray(10, this->context_pad(), target);
+  }
+
+  // optional string crop_mode = 11 [default = "warp"];
+  if (has_crop_mode()) {
+    ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->crop_mode().data(), this->crop_mode().length(),
+      ::google::protobuf::internal::WireFormat::SERIALIZE,
+      "caffe.WindowDataParameter.crop_mode");
+    target =
+      ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
+        11, this->crop_mode(), target);
+  }
+
+  // optional bool cache_images = 12 [default = false];
+  if (has_cache_images()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(12, this->cache_images(), target);
+  }
+
+  // optional string root_folder = 13 [default = ""];
+  if (has_root_folder()) {
+    ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->root_folder().data(), this->root_folder().length(),
+      ::google::protobuf::internal::WireFormat::SERIALIZE,
+      "caffe.WindowDataParameter.root_folder");
+    target =
+      ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
+        13, this->root_folder(), target);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
+        unknown_fields(), target);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:caffe.WindowDataParameter)
+  return target;
+}
+
+size_t WindowDataParameter::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:caffe.WindowDataParameter)
+  size_t total_size = 0;
+
+  if (_has_bits_[0 / 32] & 255u) {
+    // optional string source = 1;
+    if (has_source()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::StringSize(
+          this->source());
+    }
+
+    // optional float scale = 2 [default = 1];
+    if (has_scale()) {
+      total_size += 1 + 4;
+    }
+
+    // optional string mean_file = 3;
+    if (has_mean_file()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::StringSize(
+          this->mean_file());
+    }
+
+    // optional uint32 batch_size = 4;
+    if (has_batch_size()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::UInt32Size(
+          this->batch_size());
+    }
+
+    // optional uint32 crop_size = 5 [default = 0];
+    if (has_crop_size()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::UInt32Size(
+          this->crop_size());
+    }
+
+    // optional bool mirror = 6 [default = false];
+    if (has_mirror()) {
+      total_size += 1 + 1;
+    }
+
+    // optional float fg_threshold = 7 [default = 0.5];
+    if (has_fg_threshold()) {
+      total_size += 1 + 4;
+    }
+
+    // optional float bg_threshold = 8 [default = 0.5];
+    if (has_bg_threshold()) {
+      total_size += 1 + 4;
+    }
+
+  }
+  if (_has_bits_[8 / 32] & 7936u) {
+    // optional float fg_fraction = 9 [default = 0.25];
+    if (has_fg_fraction()) {
+      total_size += 1 + 4;
+    }
+
+    // optional uint32 context_pad = 10 [default = 0];
+    if (has_context_pad()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::UInt32Size(
+          this->context_pad());
+    }
+
+    // optional string crop_mode = 11 [default = "warp"];
+    if (has_crop_mode()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::StringSize(
+          this->crop_mode());
+    }
+
+    // optional bool cache_images = 12 [default = false];
+    if (has_cache_images()) {
+      total_size += 1 + 1;
+    }
+
+    // optional string root_folder = 13 [default = ""];
+    if (has_root_folder()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::StringSize(
+          this->root_folder());
+    }
+
+  }
+  if (_internal_metadata_.have_unknown_fields()) {
+    total_size +=
+      ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
+        unknown_fields());
+  }
+  int cached_size = ::google::protobuf::internal::ToCachedSize(total_size);
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = cached_size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+  return total_size;
+}
+
+void WindowDataParameter::MergeFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_merge_from_start:caffe.WindowDataParameter)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const WindowDataParameter* source =
+      ::google::protobuf::internal::DynamicCastToGenerated<const WindowDataParameter>(
+          &from);
+  if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:caffe.WindowDataParameter)
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:caffe.WindowDataParameter)
+    UnsafeMergeFrom(*source);
+  }
+}
+
+void WindowDataParameter::MergeFrom(const WindowDataParameter& from) {
+// @@protoc_insertion_point(class_specific_merge_from_start:caffe.WindowDataParameter)
+  if (GOOGLE_PREDICT_TRUE(&from != this)) {
+    UnsafeMergeFrom(from);
+  } else {
+    MergeFromFail(__LINE__);
+  }
+}
+
+void WindowDataParameter::UnsafeMergeFrom(const WindowDataParameter& from) {
+  GOOGLE_DCHECK(&from != this);
+  if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+    if (from.has_source()) {
+      set_has_source();
+      source_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.source_);
+    }
+    if (from.has_scale()) {
+      set_scale(from.scale());
+    }
+    if (from.has_mean_file()) {
+      set_has_mean_file();
+      mean_file_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.mean_file_);
+    }
+    if (from.has_batch_size()) {
+      set_batch_size(from.batch_size());
+    }
+    if (from.has_crop_size()) {
+      set_crop_size(from.crop_size());
+    }
+    if (from.has_mirror()) {
+      set_mirror(from.mirror());
+    }
+    if (from.has_fg_threshold()) {
+      set_fg_threshold(from.fg_threshold());
+    }
+    if (from.has_bg_threshold()) {
+      set_bg_threshold(from.bg_threshold());
+    }
+  }
+  if (from._has_bits_[8 / 32] & (0xffu << (8 % 32))) {
+    if (from.has_fg_fraction()) {
+      set_fg_fraction(from.fg_fraction());
+    }
+    if (from.has_context_pad()) {
+      set_context_pad(from.context_pad());
+    }
+    if (from.has_crop_mode()) {
+      set_has_crop_mode();
+      crop_mode_.AssignWithDefault(_default_crop_mode_, from.crop_mode_);
+    }
+    if (from.has_cache_images()) {
+      set_cache_images(from.cache_images());
+    }
+    if (from.has_root_folder()) {
+      set_has_root_folder();
+      root_folder_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.root_folder_);
+    }
+  }
+  if (from._internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::UnknownFieldSet::MergeToInternalMetdata(
+      from.unknown_fields(), &_internal_metadata_);
+  }
+}
+
+void WindowDataParameter::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:caffe.WindowDataParameter)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void WindowDataParameter::CopyFrom(const WindowDataParameter& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:caffe.WindowDataParameter)
+  if (&from == this) return;
+  Clear();
+  UnsafeMergeFrom(from);
+}
+
+bool WindowDataParameter::IsInitialized() const {
+
+  return true;
+}
+
+void WindowDataParameter::Swap(WindowDataParameter* other) {
+  if (other == this) return;
+  InternalSwap(other);
+}
+void WindowDataParameter::InternalSwap(WindowDataParameter* other) {
+  source_.Swap(&other->source_);
+  std::swap(scale_, other->scale_);
+  mean_file_.Swap(&other->mean_file_);
+  std::swap(batch_size_, other->batch_size_);
+  std::swap(crop_size_, other->crop_size_);
+  std::swap(mirror_, other->mirror_);
+  std::swap(fg_threshold_, other->fg_threshold_);
+  std::swap(bg_threshold_, other->bg_threshold_);
+  std::swap(fg_fraction_, other->fg_fraction_);
+  std::swap(context_pad_, other->context_pad_);
+  crop_mode_.Swap(&other->crop_mode_);
+  std::swap(cache_images_, other->cache_images_);
+  root_folder_.Swap(&other->root_folder_);
+  std::swap(_has_bits_[0], other->_has_bits_[0]);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
+}
+
+::google::protobuf::Metadata WindowDataParameter::GetMetadata() const {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::Metadata metadata;
+  metadata.descriptor = WindowDataParameter_descriptor_;
+  metadata.reflection = WindowDataParameter_reflection_;
+  return metadata;
+}
+
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// WindowDataParameter
+
+// optional string source = 1;
+bool WindowDataParameter::has_source() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+void WindowDataParameter::set_has_source() {
+  _has_bits_[0] |= 0x00000001u;
+}
+void WindowDataParameter::clear_has_source() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+void WindowDataParameter::clear_source() {
+  source_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  clear_has_source();
+}
+const ::std::string& WindowDataParameter::source() const {
+  // @@protoc_insertion_point(field_get:caffe.WindowDataParameter.source)
+  return source_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+void WindowDataParameter::set_source(const ::std::string& value) {
+  set_has_source();
+  source_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:caffe.WindowDataParameter.source)
+}
+void WindowDataParameter::set_source(const char* value) {
+  set_has_source();
+  source_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:caffe.WindowDataParameter.source)
+}
+void WindowDataParameter::set_source(const char* value, size_t size) {
+  set_has_source();
+  source_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:caffe.WindowDataParameter.source)
+}
+::std::string* WindowDataParameter::mutable_source() {
+  set_has_source();
+  // @@protoc_insertion_point(field_mutable:caffe.WindowDataParameter.source)
+  return source_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+::std::string* WindowDataParameter::release_source() {
+  // @@protoc_insertion_point(field_release:caffe.WindowDataParameter.source)
+  clear_has_source();
+  return source_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+void WindowDataParameter::set_allocated_source(::std::string* source) {
+  if (source != NULL) {
+    set_has_source();
+  } else {
+    clear_has_source();
+  }
+  source_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), source);
+  // @@protoc_insertion_point(field_set_allocated:caffe.WindowDataParameter.source)
+}
+
+// optional float scale = 2 [default = 1];
+bool WindowDataParameter::has_scale() const {
+  return (_has_bits_[0] & 0x00000002u) != 0;
+}
+void WindowDataParameter::set_has_scale() {
+  _has_bits_[0] |= 0x00000002u;
+}
+void WindowDataParameter::clear_has_scale() {
+  _has_bits_[0] &= ~0x00000002u;
+}
+void WindowDataParameter::clear_scale() {
+  scale_ = 1;
+  clear_has_scale();
+}
+float WindowDataParameter::scale() const {
+  // @@protoc_insertion_point(field_get:caffe.WindowDataParameter.scale)
+  return scale_;
+}
+void WindowDataParameter::set_scale(float value) {
+  set_has_scale();
+  scale_ = value;
+  // @@protoc_insertion_point(field_set:caffe.WindowDataParameter.scale)
+}
+
+// optional string mean_file = 3;
+bool WindowDataParameter::has_mean_file() const {
+  return (_has_bits_[0] & 0x00000004u) != 0;
+}
+void WindowDataParameter::set_has_mean_file() {
+  _has_bits_[0] |= 0x00000004u;
+}
+void WindowDataParameter::clear_has_mean_file() {
+  _has_bits_[0] &= ~0x00000004u;
+}
+void WindowDataParameter::clear_mean_file() {
+  mean_file_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  clear_has_mean_file();
+}
+const ::std::string& WindowDataParameter::mean_file() const {
+  // @@protoc_insertion_point(field_get:caffe.WindowDataParameter.mean_file)
+  return mean_file_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+void WindowDataParameter::set_mean_file(const ::std::string& value) {
+  set_has_mean_file();
+  mean_file_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:caffe.WindowDataParameter.mean_file)
+}
+void WindowDataParameter::set_mean_file(const char* value) {
+  set_has_mean_file();
+  mean_file_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:caffe.WindowDataParameter.mean_file)
+}
+void WindowDataParameter::set_mean_file(const char* value, size_t size) {
+  set_has_mean_file();
+  mean_file_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:caffe.WindowDataParameter.mean_file)
+}
+::std::string* WindowDataParameter::mutable_mean_file() {
+  set_has_mean_file();
+  // @@protoc_insertion_point(field_mutable:caffe.WindowDataParameter.mean_file)
+  return mean_file_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+::std::string* WindowDataParameter::release_mean_file() {
+  // @@protoc_insertion_point(field_release:caffe.WindowDataParameter.mean_file)
+  clear_has_mean_file();
+  return mean_file_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+void WindowDataParameter::set_allocated_mean_file(::std::string* mean_file) {
+  if (mean_file != NULL) {
+    set_has_mean_file();
+  } else {
+    clear_has_mean_file();
+  }
+  mean_file_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), mean_file);
+  // @@protoc_insertion_point(field_set_allocated:caffe.WindowDataParameter.mean_file)
+}
+
+// optional uint32 batch_size = 4;
+bool WindowDataParameter::has_batch_size() const {
+  return (_has_bits_[0] & 0x00000008u) != 0;
+}
+void WindowDataParameter::set_has_batch_size() {
+  _has_bits_[0] |= 0x00000008u;
+}
+void WindowDataParameter::clear_has_batch_size() {
+  _has_bits_[0] &= ~0x00000008u;
+}
+void WindowDataParameter::clear_batch_size() {
+  batch_size_ = 0u;
+  clear_has_batch_size();
+}
+::google::protobuf::uint32 WindowDataParameter::batch_size() const {
+  // @@protoc_insertion_point(field_get:caffe.WindowDataParameter.batch_size)
+  return batch_size_;
+}
+void WindowDataParameter::set_batch_size(::google::protobuf::uint32 value) {
+  set_has_batch_size();
+  batch_size_ = value;
+  // @@protoc_insertion_point(field_set:caffe.WindowDataParameter.batch_size)
+}
+
+// optional uint32 crop_size = 5 [default = 0];
+bool WindowDataParameter::has_crop_size() const {
+  return (_has_bits_[0] & 0x00000010u) != 0;
+}
+void WindowDataParameter::set_has_crop_size() {
+  _has_bits_[0] |= 0x00000010u;
+}
+void WindowDataParameter::clear_has_crop_size() {
+  _has_bits_[0] &= ~0x00000010u;
+}
+void WindowDataParameter::clear_crop_size() {
+  crop_size_ = 0u;
+  clear_has_crop_size();
+}
+::google::protobuf::uint32 WindowDataParameter::crop_size() const {
+  // @@protoc_insertion_point(field_get:caffe.WindowDataParameter.crop_size)
+  return crop_size_;
+}
+void WindowDataParameter::set_crop_size(::google::protobuf::uint32 value) {
+  set_has_crop_size();
+  crop_size_ = value;
+  // @@protoc_insertion_point(field_set:caffe.WindowDataParameter.crop_size)
+}
+
+// optional bool mirror = 6 [default = false];
+bool WindowDataParameter::has_mirror() const {
+  return (_has_bits_[0] & 0x00000020u) != 0;
+}
+void WindowDataParameter::set_has_mirror() {
+  _has_bits_[0] |= 0x00000020u;
+}
+void WindowDataParameter::clear_has_mirror() {
+  _has_bits_[0] &= ~0x00000020u;
+}
+void WindowDataParameter::clear_mirror() {
+  mirror_ = false;
+  clear_has_mirror();
+}
+bool WindowDataParameter::mirror() const {
+  // @@protoc_insertion_point(field_get:caffe.WindowDataParameter.mirror)
+  return mirror_;
+}
+void WindowDataParameter::set_mirror(bool value) {
+  set_has_mirror();
+  mirror_ = value;
+  // @@protoc_insertion_point(field_set:caffe.WindowDataParameter.mirror)
+}
+
+// optional float fg_threshold = 7 [default = 0.5];
+bool WindowDataParameter::has_fg_threshold() const {
+  return (_has_bits_[0] & 0x00000040u) != 0;
+}
+void WindowDataParameter::set_has_fg_threshold() {
+  _has_bits_[0] |= 0x00000040u;
+}
+void WindowDataParameter::clear_has_fg_threshold() {
+  _has_bits_[0] &= ~0x00000040u;
+}
+void WindowDataParameter::clear_fg_threshold() {
+  fg_threshold_ = 0.5f;
+  clear_has_fg_threshold();
+}
+float WindowDataParameter::fg_threshold() const {
+  // @@protoc_insertion_point(field_get:caffe.WindowDataParameter.fg_threshold)
+  return fg_threshold_;
+}
+void WindowDataParameter::set_fg_threshold(float value) {
+  set_has_fg_threshold();
+  fg_threshold_ = value;
+  // @@protoc_insertion_point(field_set:caffe.WindowDataParameter.fg_threshold)
+}
+
+// optional float bg_threshold = 8 [default = 0.5];
+bool WindowDataParameter::has_bg_threshold() const {
+  return (_has_bits_[0] & 0x00000080u) != 0;
+}
+void WindowDataParameter::set_has_bg_threshold() {
+  _has_bits_[0] |= 0x00000080u;
+}
+void WindowDataParameter::clear_has_bg_threshold() {
+  _has_bits_[0] &= ~0x00000080u;
+}
+void WindowDataParameter::clear_bg_threshold() {
+  bg_threshold_ = 0.5f;
+  clear_has_bg_threshold();
+}
+float WindowDataParameter::bg_threshold() const {
+  // @@protoc_insertion_point(field_get:caffe.WindowDataParameter.bg_threshold)
+  return bg_threshold_;
+}
+void WindowDataParameter::set_bg_threshold(float value) {
+  set_has_bg_threshold();
+  bg_threshold_ = value;
+  // @@protoc_insertion_point(field_set:caffe.WindowDataParameter.bg_threshold)
+}
+
+// optional float fg_fraction = 9 [default = 0.25];
+bool WindowDataParameter::has_fg_fraction() const {
+  return (_has_bits_[0] & 0x00000100u) != 0;
+}
+void WindowDataParameter::set_has_fg_fraction() {
+  _has_bits_[0] |= 0x00000100u;
+}
+void WindowDataParameter::clear_has_fg_fraction() {
+  _has_bits_[0] &= ~0x00000100u;
+}
+void WindowDataParameter::clear_fg_fraction() {
+  fg_fraction_ = 0.25f;
+  clear_has_fg_fraction();
+}
+float WindowDataParameter::fg_fraction() const {
+  // @@protoc_insertion_point(field_get:caffe.WindowDataParameter.fg_fraction)
+  return fg_fraction_;
+}
+void WindowDataParameter::set_fg_fraction(float value) {
+  set_has_fg_fraction();
+  fg_fraction_ = value;
+  // @@protoc_insertion_point(field_set:caffe.WindowDataParameter.fg_fraction)
+}
+
+// optional uint32 context_pad = 10 [default = 0];
+bool WindowDataParameter::has_context_pad() const {
+  return (_has_bits_[0] & 0x00000200u) != 0;
+}
+void WindowDataParameter::set_has_context_pad() {
+  _has_bits_[0] |= 0x00000200u;
+}
+void WindowDataParameter::clear_has_context_pad() {
+  _has_bits_[0] &= ~0x00000200u;
+}
+void WindowDataParameter::clear_context_pad() {
+  context_pad_ = 0u;
+  clear_has_context_pad();
+}
+::google::protobuf::uint32 WindowDataParameter::context_pad() const {
+  // @@protoc_insertion_point(field_get:caffe.WindowDataParameter.context_pad)
+  return context_pad_;
+}
+void WindowDataParameter::set_context_pad(::google::protobuf::uint32 value) {
+  set_has_context_pad();
+  context_pad_ = value;
+  // @@protoc_insertion_point(field_set:caffe.WindowDataParameter.context_pad)
+}
+
+// optional string crop_mode = 11 [default = "warp"];
+bool WindowDataParameter::has_crop_mode() const {
+  return (_has_bits_[0] & 0x00000400u) != 0;
+}
+void WindowDataParameter::set_has_crop_mode() {
+  _has_bits_[0] |= 0x00000400u;
+}
+void WindowDataParameter::clear_has_crop_mode() {
+  _has_bits_[0] &= ~0x00000400u;
+}
+void WindowDataParameter::clear_crop_mode() {
+  crop_mode_.ClearToDefaultNoArena(_default_crop_mode_);
+  clear_has_crop_mode();
+}
+const ::std::string& WindowDataParameter::crop_mode() const {
+  // @@protoc_insertion_point(field_get:caffe.WindowDataParameter.crop_mode)
+  return crop_mode_.GetNoArena(_default_crop_mode_);
+}
+void WindowDataParameter::set_crop_mode(const ::std::string& value) {
+  set_has_crop_mode();
+  crop_mode_.SetNoArena(_default_crop_mode_, value);
+  // @@protoc_insertion_point(field_set:caffe.WindowDataParameter.crop_mode)
+}
+void WindowDataParameter::set_crop_mode(const char* value) {
+  set_has_crop_mode();
+  crop_mode_.SetNoArena(_default_crop_mode_, ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:caffe.WindowDataParameter.crop_mode)
+}
+void WindowDataParameter::set_crop_mode(const char* value, size_t size) {
+  set_has_crop_mode();
+  crop_mode_.SetNoArena(_default_crop_mode_,
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:caffe.WindowDataParameter.crop_mode)
+}
+::std::string* WindowDataParameter::mutable_crop_mode() {
+  set_has_crop_mode();
+  // @@protoc_insertion_point(field_mutable:caffe.WindowDataParameter.crop_mode)
+  return crop_mode_.MutableNoArena(_default_crop_mode_);
+}
+::std::string* WindowDataParameter::release_crop_mode() {
+  // @@protoc_insertion_point(field_release:caffe.WindowDataParameter.crop_mode)
+  clear_has_crop_mode();
+  return crop_mode_.ReleaseNoArena(_default_crop_mode_);
+}
+void WindowDataParameter::set_allocated_crop_mode(::std::string* crop_mode) {
+  if (crop_mode != NULL) {
+    set_has_crop_mode();
+  } else {
+    clear_has_crop_mode();
+  }
+  crop_mode_.SetAllocatedNoArena(_default_crop_mode_, crop_mode);
+  // @@protoc_insertion_point(field_set_allocated:caffe.WindowDataParameter.crop_mode)
+}
+
+// optional bool cache_images = 12 [default = false];
+bool WindowDataParameter::has_cache_images() const {
+  return (_has_bits_[0] & 0x00000800u) != 0;
+}
+void WindowDataParameter::set_has_cache_images() {
+  _has_bits_[0] |= 0x00000800u;
+}
+void WindowDataParameter::clear_has_cache_images() {
+  _has_bits_[0] &= ~0x00000800u;
+}
+void WindowDataParameter::clear_cache_images() {
+  cache_images_ = false;
+  clear_has_cache_images();
+}
+bool WindowDataParameter::cache_images() const {
+  // @@protoc_insertion_point(field_get:caffe.WindowDataParameter.cache_images)
+  return cache_images_;
+}
+void WindowDataParameter::set_cache_images(bool value) {
+  set_has_cache_images();
+  cache_images_ = value;
+  // @@protoc_insertion_point(field_set:caffe.WindowDataParameter.cache_images)
+}
+
+// optional string root_folder = 13 [default = ""];
+bool WindowDataParameter::has_root_folder() const {
+  return (_has_bits_[0] & 0x00001000u) != 0;
+}
+void WindowDataParameter::set_has_root_folder() {
+  _has_bits_[0] |= 0x00001000u;
+}
+void WindowDataParameter::clear_has_root_folder() {
+  _has_bits_[0] &= ~0x00001000u;
+}
+void WindowDataParameter::clear_root_folder() {
+  root_folder_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  clear_has_root_folder();
+}
+const ::std::string& WindowDataParameter::root_folder() const {
+  // @@protoc_insertion_point(field_get:caffe.WindowDataParameter.root_folder)
+  return root_folder_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+void WindowDataParameter::set_root_folder(const ::std::string& value) {
+  set_has_root_folder();
+  root_folder_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:caffe.WindowDataParameter.root_folder)
+}
+void WindowDataParameter::set_root_folder(const char* value) {
+  set_has_root_folder();
+  root_folder_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:caffe.WindowDataParameter.root_folder)
+}
+void WindowDataParameter::set_root_folder(const char* value, size_t size) {
+  set_has_root_folder();
+  root_folder_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:caffe.WindowDataParameter.root_folder)
+}
+::std::string* WindowDataParameter::mutable_root_folder() {
+  set_has_root_folder();
+  // @@protoc_insertion_point(field_mutable:caffe.WindowDataParameter.root_folder)
+  return root_folder_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+::std::string* WindowDataParameter::release_root_folder() {
+  // @@protoc_insertion_point(field_release:caffe.WindowDataParameter.root_folder)
+  clear_has_root_folder();
+  return root_folder_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+void WindowDataParameter::set_allocated_root_folder(::std::string* root_folder) {
+  if (root_folder != NULL) {
+    set_has_root_folder();
+  } else {
+    clear_has_root_folder();
+  }
+  root_folder_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), root_folder);
+  // @@protoc_insertion_point(field_set_allocated:caffe.WindowDataParameter.root_folder)
+}
+
+inline const WindowDataParameter* WindowDataParameter::internal_default_instance() {
+  return &WindowDataParameter_default_instance_.get();
+}
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
+
+// ===================================================================
+
+const ::google::protobuf::EnumDescriptor* SPPParameter_PoolMethod_descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return SPPParameter_PoolMethod_descriptor_;
+}
+bool SPPParameter_PoolMethod_IsValid(int value) {
+  switch (value) {
+    case 0:
+    case 1:
+    case 2:
+      return true;
+    default:
+      return false;
+  }
+}
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const SPPParameter_PoolMethod SPPParameter::MAX;
+const SPPParameter_PoolMethod SPPParameter::AVE;
+const SPPParameter_PoolMethod SPPParameter::STOCHASTIC;
+const SPPParameter_PoolMethod SPPParameter::PoolMethod_MIN;
+const SPPParameter_PoolMethod SPPParameter::PoolMethod_MAX;
+const int SPPParameter::PoolMethod_ARRAYSIZE;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+const ::google::protobuf::EnumDescriptor* SPPParameter_Engine_descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return SPPParameter_Engine_descriptor_;
+}
+bool SPPParameter_Engine_IsValid(int value) {
+  switch (value) {
+    case 0:
+    case 1:
+    case 2:
+      return true;
+    default:
+      return false;
+  }
+}
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const SPPParameter_Engine SPPParameter::DEFAULT;
+const SPPParameter_Engine SPPParameter::CAFFE;
+const SPPParameter_Engine SPPParameter::CUDNN;
+const SPPParameter_Engine SPPParameter::Engine_MIN;
+const SPPParameter_Engine SPPParameter::Engine_MAX;
+const int SPPParameter::Engine_ARRAYSIZE;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const int SPPParameter::kPyramidHeightFieldNumber;
+const int SPPParameter::kPoolFieldNumber;
+const int SPPParameter::kEngineFieldNumber;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+
+SPPParameter::SPPParameter()
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+  if (this != internal_default_instance()) protobuf_InitDefaults_caffe_2eproto();
+  SharedCtor();
+  // @@protoc_insertion_point(constructor:caffe.SPPParameter)
+}
+
+void SPPParameter::InitAsDefaultInstance() {
+}
+
+SPPParameter::SPPParameter(const SPPParameter& from)
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
+  SharedCtor();
+  UnsafeMergeFrom(from);
+  // @@protoc_insertion_point(copy_constructor:caffe.SPPParameter)
+}
+
+void SPPParameter::SharedCtor() {
+  _cached_size_ = 0;
+  ::memset(&pyramid_height_, 0, reinterpret_cast<char*>(&engine_) -
+    reinterpret_cast<char*>(&pyramid_height_) + sizeof(engine_));
+}
+
+SPPParameter::~SPPParameter() {
+  // @@protoc_insertion_point(destructor:caffe.SPPParameter)
+  SharedDtor();
+}
+
+void SPPParameter::SharedDtor() {
+}
+
+void SPPParameter::SetCachedSize(int size) const {
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* SPPParameter::descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return SPPParameter_descriptor_;
+}
+
+const SPPParameter& SPPParameter::default_instance() {
+  protobuf_InitDefaults_caffe_2eproto();
+  return *internal_default_instance();
+}
+
+::google::protobuf::internal::ExplicitlyConstructed<SPPParameter> SPPParameter_default_instance_;
+
+SPPParameter* SPPParameter::New(::google::protobuf::Arena* arena) const {
+  SPPParameter* n = new SPPParameter;
+  if (arena != NULL) {
+    arena->Own(n);
+  }
+  return n;
+}
+
+void SPPParameter::Clear() {
+// @@protoc_insertion_point(message_clear_start:caffe.SPPParameter)
+#if defined(__clang__)
+#define ZR_HELPER_(f) \
+  _Pragma("clang diagnostic push") \
+  _Pragma("clang diagnostic ignored \"-Winvalid-offsetof\"") \
+  __builtin_offsetof(SPPParameter, f) \
+  _Pragma("clang diagnostic pop")
+#else
+#define ZR_HELPER_(f) reinterpret_cast<char*>(\
+  &reinterpret_cast<SPPParameter*>(16)->f)
+#endif
+
+#define ZR_(first, last) do {\
+  ::memset(&(first), 0,\
+           ZR_HELPER_(last) - ZR_HELPER_(first) + sizeof(last));\
+} while (0)
+
+  ZR_(pyramid_height_, engine_);
+
+#undef ZR_HELPER_
+#undef ZR_
+
+  _has_bits_.Clear();
+  if (_internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->Clear();
+  }
+}
+
+bool SPPParameter::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
+  ::google::protobuf::uint32 tag;
+  // @@protoc_insertion_point(parse_start:caffe.SPPParameter)
+  for (;;) {
+    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+    tag = p.first;
+    if (!p.second) goto handle_unusual;
+    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+      // optional uint32 pyramid_height = 1;
+      case 1: {
+        if (tag == 8) {
+          set_has_pyramid_height();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>(
+                 input, &pyramid_height_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(16)) goto parse_pool;
+        break;
+      }
+
+      // optional .caffe.SPPParameter.PoolMethod pool = 2 [default = MAX];
+      case 2: {
+        if (tag == 16) {
+         parse_pool:
+          int value;
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>(
+                 input, &value)));
+          if (::caffe::SPPParameter_PoolMethod_IsValid(value)) {
+            set_pool(static_cast< ::caffe::SPPParameter_PoolMethod >(value));
+          } else {
+            mutable_unknown_fields()->AddVarint(2, value);
+          }
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(48)) goto parse_engine;
+        break;
+      }
+
+      // optional .caffe.SPPParameter.Engine engine = 6 [default = DEFAULT];
+      case 6: {
+        if (tag == 48) {
+         parse_engine:
+          int value;
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>(
+                 input, &value)));
+          if (::caffe::SPPParameter_Engine_IsValid(value)) {
+            set_engine(static_cast< ::caffe::SPPParameter_Engine >(value));
+          } else {
+            mutable_unknown_fields()->AddVarint(6, value);
+          }
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectAtEnd()) goto success;
+        break;
+      }
+
+      default: {
+      handle_unusual:
+        if (tag == 0 ||
+            ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+          goto success;
+        }
+        DO_(::google::protobuf::internal::WireFormat::SkipField(
+              input, tag, mutable_unknown_fields()));
+        break;
+      }
+    }
+  }
+success:
+  // @@protoc_insertion_point(parse_success:caffe.SPPParameter)
+  return true;
+failure:
+  // @@protoc_insertion_point(parse_failure:caffe.SPPParameter)
+  return false;
+#undef DO_
+}
+
+void SPPParameter::SerializeWithCachedSizes(
+    ::google::protobuf::io::CodedOutputStream* output) const {
+  // @@protoc_insertion_point(serialize_start:caffe.SPPParameter)
+  // optional uint32 pyramid_height = 1;
+  if (has_pyramid_height()) {
+    ::google::protobuf::internal::WireFormatLite::WriteUInt32(1, this->pyramid_height(), output);
+  }
+
+  // optional .caffe.SPPParameter.PoolMethod pool = 2 [default = MAX];
+  if (has_pool()) {
+    ::google::protobuf::internal::WireFormatLite::WriteEnum(
+      2, this->pool(), output);
+  }
+
+  // optional .caffe.SPPParameter.Engine engine = 6 [default = DEFAULT];
+  if (has_engine()) {
+    ::google::protobuf::internal::WireFormatLite::WriteEnum(
+      6, this->engine(), output);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
+        unknown_fields(), output);
+  }
+  // @@protoc_insertion_point(serialize_end:caffe.SPPParameter)
+}
+
+::google::protobuf::uint8* SPPParameter::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
+  (void)deterministic; // Unused
+  // @@protoc_insertion_point(serialize_to_array_start:caffe.SPPParameter)
+  // optional uint32 pyramid_height = 1;
+  if (has_pyramid_height()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteUInt32ToArray(1, this->pyramid_height(), target);
+  }
+
+  // optional .caffe.SPPParameter.PoolMethod pool = 2 [default = MAX];
+  if (has_pool()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteEnumToArray(
+      2, this->pool(), target);
+  }
+
+  // optional .caffe.SPPParameter.Engine engine = 6 [default = DEFAULT];
+  if (has_engine()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteEnumToArray(
+      6, this->engine(), target);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
+        unknown_fields(), target);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:caffe.SPPParameter)
+  return target;
+}
+
+size_t SPPParameter::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:caffe.SPPParameter)
+  size_t total_size = 0;
+
+  if (_has_bits_[0 / 32] & 7u) {
+    // optional uint32 pyramid_height = 1;
+    if (has_pyramid_height()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::UInt32Size(
+          this->pyramid_height());
+    }
+
+    // optional .caffe.SPPParameter.PoolMethod pool = 2 [default = MAX];
+    if (has_pool()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::EnumSize(this->pool());
+    }
+
+    // optional .caffe.SPPParameter.Engine engine = 6 [default = DEFAULT];
+    if (has_engine()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::EnumSize(this->engine());
+    }
+
+  }
+  if (_internal_metadata_.have_unknown_fields()) {
+    total_size +=
+      ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
+        unknown_fields());
+  }
+  int cached_size = ::google::protobuf::internal::ToCachedSize(total_size);
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = cached_size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+  return total_size;
+}
+
+void SPPParameter::MergeFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_merge_from_start:caffe.SPPParameter)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const SPPParameter* source =
+      ::google::protobuf::internal::DynamicCastToGenerated<const SPPParameter>(
+          &from);
+  if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:caffe.SPPParameter)
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:caffe.SPPParameter)
+    UnsafeMergeFrom(*source);
+  }
+}
+
+void SPPParameter::MergeFrom(const SPPParameter& from) {
+// @@protoc_insertion_point(class_specific_merge_from_start:caffe.SPPParameter)
+  if (GOOGLE_PREDICT_TRUE(&from != this)) {
+    UnsafeMergeFrom(from);
+  } else {
+    MergeFromFail(__LINE__);
+  }
+}
+
+void SPPParameter::UnsafeMergeFrom(const SPPParameter& from) {
+  GOOGLE_DCHECK(&from != this);
+  if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+    if (from.has_pyramid_height()) {
+      set_pyramid_height(from.pyramid_height());
+    }
+    if (from.has_pool()) {
+      set_pool(from.pool());
+    }
+    if (from.has_engine()) {
+      set_engine(from.engine());
+    }
+  }
+  if (from._internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::UnknownFieldSet::MergeToInternalMetdata(
+      from.unknown_fields(), &_internal_metadata_);
+  }
+}
+
+void SPPParameter::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:caffe.SPPParameter)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void SPPParameter::CopyFrom(const SPPParameter& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:caffe.SPPParameter)
+  if (&from == this) return;
+  Clear();
+  UnsafeMergeFrom(from);
+}
+
+bool SPPParameter::IsInitialized() const {
+
+  return true;
+}
+
+void SPPParameter::Swap(SPPParameter* other) {
+  if (other == this) return;
+  InternalSwap(other);
+}
+void SPPParameter::InternalSwap(SPPParameter* other) {
+  std::swap(pyramid_height_, other->pyramid_height_);
+  std::swap(pool_, other->pool_);
+  std::swap(engine_, other->engine_);
+  std::swap(_has_bits_[0], other->_has_bits_[0]);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
+}
+
+::google::protobuf::Metadata SPPParameter::GetMetadata() const {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::Metadata metadata;
+  metadata.descriptor = SPPParameter_descriptor_;
+  metadata.reflection = SPPParameter_reflection_;
+  return metadata;
+}
+
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// SPPParameter
+
+// optional uint32 pyramid_height = 1;
+bool SPPParameter::has_pyramid_height() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+void SPPParameter::set_has_pyramid_height() {
+  _has_bits_[0] |= 0x00000001u;
+}
+void SPPParameter::clear_has_pyramid_height() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+void SPPParameter::clear_pyramid_height() {
+  pyramid_height_ = 0u;
+  clear_has_pyramid_height();
+}
+::google::protobuf::uint32 SPPParameter::pyramid_height() const {
+  // @@protoc_insertion_point(field_get:caffe.SPPParameter.pyramid_height)
+  return pyramid_height_;
+}
+void SPPParameter::set_pyramid_height(::google::protobuf::uint32 value) {
+  set_has_pyramid_height();
+  pyramid_height_ = value;
+  // @@protoc_insertion_point(field_set:caffe.SPPParameter.pyramid_height)
+}
+
+// optional .caffe.SPPParameter.PoolMethod pool = 2 [default = MAX];
+bool SPPParameter::has_pool() const {
+  return (_has_bits_[0] & 0x00000002u) != 0;
+}
+void SPPParameter::set_has_pool() {
+  _has_bits_[0] |= 0x00000002u;
+}
+void SPPParameter::clear_has_pool() {
+  _has_bits_[0] &= ~0x00000002u;
+}
+void SPPParameter::clear_pool() {
+  pool_ = 0;
+  clear_has_pool();
+}
+::caffe::SPPParameter_PoolMethod SPPParameter::pool() const {
+  // @@protoc_insertion_point(field_get:caffe.SPPParameter.pool)
+  return static_cast< ::caffe::SPPParameter_PoolMethod >(pool_);
+}
+void SPPParameter::set_pool(::caffe::SPPParameter_PoolMethod value) {
+  assert(::caffe::SPPParameter_PoolMethod_IsValid(value));
+  set_has_pool();
+  pool_ = value;
+  // @@protoc_insertion_point(field_set:caffe.SPPParameter.pool)
+}
+
+// optional .caffe.SPPParameter.Engine engine = 6 [default = DEFAULT];
+bool SPPParameter::has_engine() const {
+  return (_has_bits_[0] & 0x00000004u) != 0;
+}
+void SPPParameter::set_has_engine() {
+  _has_bits_[0] |= 0x00000004u;
+}
+void SPPParameter::clear_has_engine() {
+  _has_bits_[0] &= ~0x00000004u;
+}
+void SPPParameter::clear_engine() {
+  engine_ = 0;
+  clear_has_engine();
+}
+::caffe::SPPParameter_Engine SPPParameter::engine() const {
+  // @@protoc_insertion_point(field_get:caffe.SPPParameter.engine)
+  return static_cast< ::caffe::SPPParameter_Engine >(engine_);
+}
+void SPPParameter::set_engine(::caffe::SPPParameter_Engine value) {
+  assert(::caffe::SPPParameter_Engine_IsValid(value));
+  set_has_engine();
+  engine_ = value;
+  // @@protoc_insertion_point(field_set:caffe.SPPParameter.engine)
+}
+
+inline const SPPParameter* SPPParameter::internal_default_instance() {
+  return &SPPParameter_default_instance_.get();
+}
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
+
+// ===================================================================
+
+const ::google::protobuf::EnumDescriptor* V1LayerParameter_LayerType_descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return V1LayerParameter_LayerType_descriptor_;
+}
+bool V1LayerParameter_LayerType_IsValid(int value) {
+  switch (value) {
+    case 0:
+    case 1:
+    case 2:
+    case 3:
+    case 4:
+    case 5:
+    case 6:
+    case 7:
+    case 8:
+    case 9:
+    case 10:
+    case 11:
+    case 12:
+    case 13:
+    case 14:
+    case 15:
+    case 16:
+    case 17:
+    case 18:
+    case 19:
+    case 20:
+    case 21:
+    case 22:
+    case 23:
+    case 24:
+    case 25:
+    case 26:
+    case 27:
+    case 28:
+    case 29:
+    case 30:
+    case 31:
+    case 32:
+    case 33:
+    case 34:
+    case 35:
+    case 36:
+    case 37:
+    case 38:
+    case 39:
+      return true;
+    default:
+      return false;
+  }
+}
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const V1LayerParameter_LayerType V1LayerParameter::NONE;
+const V1LayerParameter_LayerType V1LayerParameter::ABSVAL;
+const V1LayerParameter_LayerType V1LayerParameter::ACCURACY;
+const V1LayerParameter_LayerType V1LayerParameter::ARGMAX;
+const V1LayerParameter_LayerType V1LayerParameter::BNLL;
+const V1LayerParameter_LayerType V1LayerParameter::CONCAT;
+const V1LayerParameter_LayerType V1LayerParameter::CONTRASTIVE_LOSS;
+const V1LayerParameter_LayerType V1LayerParameter::CONVOLUTION;
+const V1LayerParameter_LayerType V1LayerParameter::DATA;
+const V1LayerParameter_LayerType V1LayerParameter::DECONVOLUTION;
+const V1LayerParameter_LayerType V1LayerParameter::DROPOUT;
+const V1LayerParameter_LayerType V1LayerParameter::DUMMY_DATA;
+const V1LayerParameter_LayerType V1LayerParameter::EUCLIDEAN_LOSS;
+const V1LayerParameter_LayerType V1LayerParameter::ELTWISE;
+const V1LayerParameter_LayerType V1LayerParameter::EXP;
+const V1LayerParameter_LayerType V1LayerParameter::FLATTEN;
+const V1LayerParameter_LayerType V1LayerParameter::HDF5_DATA;
+const V1LayerParameter_LayerType V1LayerParameter::HDF5_OUTPUT;
+const V1LayerParameter_LayerType V1LayerParameter::HINGE_LOSS;
+const V1LayerParameter_LayerType V1LayerParameter::IM2COL;
+const V1LayerParameter_LayerType V1LayerParameter::IMAGE_DATA;
+const V1LayerParameter_LayerType V1LayerParameter::INFOGAIN_LOSS;
+const V1LayerParameter_LayerType V1LayerParameter::INNER_PRODUCT;
+const V1LayerParameter_LayerType V1LayerParameter::LRN;
+const V1LayerParameter_LayerType V1LayerParameter::MEMORY_DATA;
+const V1LayerParameter_LayerType V1LayerParameter::MULTINOMIAL_LOGISTIC_LOSS;
+const V1LayerParameter_LayerType V1LayerParameter::MVN;
+const V1LayerParameter_LayerType V1LayerParameter::POOLING;
+const V1LayerParameter_LayerType V1LayerParameter::POWER;
+const V1LayerParameter_LayerType V1LayerParameter::RELU;
+const V1LayerParameter_LayerType V1LayerParameter::SIGMOID;
+const V1LayerParameter_LayerType V1LayerParameter::SIGMOID_CROSS_ENTROPY_LOSS;
+const V1LayerParameter_LayerType V1LayerParameter::SILENCE;
+const V1LayerParameter_LayerType V1LayerParameter::SOFTMAX;
+const V1LayerParameter_LayerType V1LayerParameter::SOFTMAX_LOSS;
+const V1LayerParameter_LayerType V1LayerParameter::SPLIT;
+const V1LayerParameter_LayerType V1LayerParameter::SLICE;
+const V1LayerParameter_LayerType V1LayerParameter::TANH;
+const V1LayerParameter_LayerType V1LayerParameter::WINDOW_DATA;
+const V1LayerParameter_LayerType V1LayerParameter::THRESHOLD;
+const V1LayerParameter_LayerType V1LayerParameter::LayerType_MIN;
+const V1LayerParameter_LayerType V1LayerParameter::LayerType_MAX;
+const int V1LayerParameter::LayerType_ARRAYSIZE;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+const ::google::protobuf::EnumDescriptor* V1LayerParameter_DimCheckMode_descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return V1LayerParameter_DimCheckMode_descriptor_;
+}
+bool V1LayerParameter_DimCheckMode_IsValid(int value) {
+  switch (value) {
+    case 0:
+    case 1:
+      return true;
+    default:
+      return false;
+  }
+}
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const V1LayerParameter_DimCheckMode V1LayerParameter::STRICT;
+const V1LayerParameter_DimCheckMode V1LayerParameter::PERMISSIVE;
+const V1LayerParameter_DimCheckMode V1LayerParameter::DimCheckMode_MIN;
+const V1LayerParameter_DimCheckMode V1LayerParameter::DimCheckMode_MAX;
+const int V1LayerParameter::DimCheckMode_ARRAYSIZE;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const int V1LayerParameter::kBottomFieldNumber;
+const int V1LayerParameter::kTopFieldNumber;
+const int V1LayerParameter::kNameFieldNumber;
+const int V1LayerParameter::kIncludeFieldNumber;
+const int V1LayerParameter::kExcludeFieldNumber;
+const int V1LayerParameter::kTypeFieldNumber;
+const int V1LayerParameter::kBlobsFieldNumber;
+const int V1LayerParameter::kParamFieldNumber;
+const int V1LayerParameter::kBlobShareModeFieldNumber;
+const int V1LayerParameter::kBlobsLrFieldNumber;
+const int V1LayerParameter::kWeightDecayFieldNumber;
+const int V1LayerParameter::kLossWeightFieldNumber;
+const int V1LayerParameter::kAccuracyParamFieldNumber;
+const int V1LayerParameter::kArgmaxParamFieldNumber;
+const int V1LayerParameter::kConcatParamFieldNumber;
+const int V1LayerParameter::kContrastiveLossParamFieldNumber;
+const int V1LayerParameter::kConvolutionParamFieldNumber;
+const int V1LayerParameter::kDataParamFieldNumber;
+const int V1LayerParameter::kDropoutParamFieldNumber;
+const int V1LayerParameter::kDummyDataParamFieldNumber;
+const int V1LayerParameter::kEltwiseParamFieldNumber;
+const int V1LayerParameter::kExpParamFieldNumber;
+const int V1LayerParameter::kHdf5DataParamFieldNumber;
+const int V1LayerParameter::kHdf5OutputParamFieldNumber;
+const int V1LayerParameter::kHingeLossParamFieldNumber;
+const int V1LayerParameter::kImageDataParamFieldNumber;
+const int V1LayerParameter::kInfogainLossParamFieldNumber;
+const int V1LayerParameter::kInnerProductParamFieldNumber;
+const int V1LayerParameter::kLrnParamFieldNumber;
+const int V1LayerParameter::kMemoryDataParamFieldNumber;
+const int V1LayerParameter::kMvnParamFieldNumber;
+const int V1LayerParameter::kPoolingParamFieldNumber;
+const int V1LayerParameter::kPowerParamFieldNumber;
+const int V1LayerParameter::kReluParamFieldNumber;
+const int V1LayerParameter::kSigmoidParamFieldNumber;
+const int V1LayerParameter::kSoftmaxParamFieldNumber;
+const int V1LayerParameter::kSliceParamFieldNumber;
+const int V1LayerParameter::kTanhParamFieldNumber;
+const int V1LayerParameter::kThresholdParamFieldNumber;
+const int V1LayerParameter::kWindowDataParamFieldNumber;
+const int V1LayerParameter::kTransformParamFieldNumber;
+const int V1LayerParameter::kLossParamFieldNumber;
+const int V1LayerParameter::kLayerFieldNumber;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+
+V1LayerParameter::V1LayerParameter()
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+  if (this != internal_default_instance()) protobuf_InitDefaults_caffe_2eproto();
+  SharedCtor();
+  // @@protoc_insertion_point(constructor:caffe.V1LayerParameter)
+}
+
+void V1LayerParameter::InitAsDefaultInstance() {
+  accuracy_param_ = const_cast< ::caffe::AccuracyParameter*>(
+      ::caffe::AccuracyParameter::internal_default_instance());
+  argmax_param_ = const_cast< ::caffe::ArgMaxParameter*>(
+      ::caffe::ArgMaxParameter::internal_default_instance());
+  concat_param_ = const_cast< ::caffe::ConcatParameter*>(
+      ::caffe::ConcatParameter::internal_default_instance());
+  contrastive_loss_param_ = const_cast< ::caffe::ContrastiveLossParameter*>(
+      ::caffe::ContrastiveLossParameter::internal_default_instance());
+  convolution_param_ = const_cast< ::caffe::ConvolutionParameter*>(
+      ::caffe::ConvolutionParameter::internal_default_instance());
+  data_param_ = const_cast< ::caffe::DataParameter*>(
+      ::caffe::DataParameter::internal_default_instance());
+  dropout_param_ = const_cast< ::caffe::DropoutParameter*>(
+      ::caffe::DropoutParameter::internal_default_instance());
+  dummy_data_param_ = const_cast< ::caffe::DummyDataParameter*>(
+      ::caffe::DummyDataParameter::internal_default_instance());
+  eltwise_param_ = const_cast< ::caffe::EltwiseParameter*>(
+      ::caffe::EltwiseParameter::internal_default_instance());
+  exp_param_ = const_cast< ::caffe::ExpParameter*>(
+      ::caffe::ExpParameter::internal_default_instance());
+  hdf5_data_param_ = const_cast< ::caffe::HDF5DataParameter*>(
+      ::caffe::HDF5DataParameter::internal_default_instance());
+  hdf5_output_param_ = const_cast< ::caffe::HDF5OutputParameter*>(
+      ::caffe::HDF5OutputParameter::internal_default_instance());
+  hinge_loss_param_ = const_cast< ::caffe::HingeLossParameter*>(
+      ::caffe::HingeLossParameter::internal_default_instance());
+  image_data_param_ = const_cast< ::caffe::ImageDataParameter*>(
+      ::caffe::ImageDataParameter::internal_default_instance());
+  infogain_loss_param_ = const_cast< ::caffe::InfogainLossParameter*>(
+      ::caffe::InfogainLossParameter::internal_default_instance());
+  inner_product_param_ = const_cast< ::caffe::InnerProductParameter*>(
+      ::caffe::InnerProductParameter::internal_default_instance());
+  lrn_param_ = const_cast< ::caffe::LRNParameter*>(
+      ::caffe::LRNParameter::internal_default_instance());
+  memory_data_param_ = const_cast< ::caffe::MemoryDataParameter*>(
+      ::caffe::MemoryDataParameter::internal_default_instance());
+  mvn_param_ = const_cast< ::caffe::MVNParameter*>(
+      ::caffe::MVNParameter::internal_default_instance());
+  pooling_param_ = const_cast< ::caffe::PoolingParameter*>(
+      ::caffe::PoolingParameter::internal_default_instance());
+  power_param_ = const_cast< ::caffe::PowerParameter*>(
+      ::caffe::PowerParameter::internal_default_instance());
+  relu_param_ = const_cast< ::caffe::ReLUParameter*>(
+      ::caffe::ReLUParameter::internal_default_instance());
+  sigmoid_param_ = const_cast< ::caffe::SigmoidParameter*>(
+      ::caffe::SigmoidParameter::internal_default_instance());
+  softmax_param_ = const_cast< ::caffe::SoftmaxParameter*>(
+      ::caffe::SoftmaxParameter::internal_default_instance());
+  slice_param_ = const_cast< ::caffe::SliceParameter*>(
+      ::caffe::SliceParameter::internal_default_instance());
+  tanh_param_ = const_cast< ::caffe::TanHParameter*>(
+      ::caffe::TanHParameter::internal_default_instance());
+  threshold_param_ = const_cast< ::caffe::ThresholdParameter*>(
+      ::caffe::ThresholdParameter::internal_default_instance());
+  window_data_param_ = const_cast< ::caffe::WindowDataParameter*>(
+      ::caffe::WindowDataParameter::internal_default_instance());
+  transform_param_ = const_cast< ::caffe::TransformationParameter*>(
+      ::caffe::TransformationParameter::internal_default_instance());
+  loss_param_ = const_cast< ::caffe::LossParameter*>(
+      ::caffe::LossParameter::internal_default_instance());
+  layer_ = const_cast< ::caffe::V0LayerParameter*>(
+      ::caffe::V0LayerParameter::internal_default_instance());
+}
+
+V1LayerParameter::V1LayerParameter(const V1LayerParameter& from)
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
+  SharedCtor();
+  UnsafeMergeFrom(from);
+  // @@protoc_insertion_point(copy_constructor:caffe.V1LayerParameter)
+}
+
+void V1LayerParameter::SharedCtor() {
+  name_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  accuracy_param_ = NULL;
+  argmax_param_ = NULL;
+  concat_param_ = NULL;
+  contrastive_loss_param_ = NULL;
+  convolution_param_ = NULL;
+  data_param_ = NULL;
+  dropout_param_ = NULL;
+  dummy_data_param_ = NULL;
+  eltwise_param_ = NULL;
+  exp_param_ = NULL;
+  hdf5_data_param_ = NULL;
+  hdf5_output_param_ = NULL;
+  hinge_loss_param_ = NULL;
+  image_data_param_ = NULL;
+  infogain_loss_param_ = NULL;
+  inner_product_param_ = NULL;
+  lrn_param_ = NULL;
+  memory_data_param_ = NULL;
+  mvn_param_ = NULL;
+  pooling_param_ = NULL;
+  power_param_ = NULL;
+  relu_param_ = NULL;
+  sigmoid_param_ = NULL;
+  softmax_param_ = NULL;
+  slice_param_ = NULL;
+  tanh_param_ = NULL;
+  threshold_param_ = NULL;
+  window_data_param_ = NULL;
+  transform_param_ = NULL;
+  loss_param_ = NULL;
+  layer_ = NULL;
+  type_ = 0;
+  _cached_size_ = 0;
+}
+
+V1LayerParameter::~V1LayerParameter() {
+  // @@protoc_insertion_point(destructor:caffe.V1LayerParameter)
+  SharedDtor();
+}
+
+void V1LayerParameter::SharedDtor() {
+  name_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  if (this != &V1LayerParameter_default_instance_.get()) {
+    delete accuracy_param_;
+    delete argmax_param_;
+    delete concat_param_;
+    delete contrastive_loss_param_;
+    delete convolution_param_;
+    delete data_param_;
+    delete dropout_param_;
+    delete dummy_data_param_;
+    delete eltwise_param_;
+    delete exp_param_;
+    delete hdf5_data_param_;
+    delete hdf5_output_param_;
+    delete hinge_loss_param_;
+    delete image_data_param_;
+    delete infogain_loss_param_;
+    delete inner_product_param_;
+    delete lrn_param_;
+    delete memory_data_param_;
+    delete mvn_param_;
+    delete pooling_param_;
+    delete power_param_;
+    delete relu_param_;
+    delete sigmoid_param_;
+    delete softmax_param_;
+    delete slice_param_;
+    delete tanh_param_;
+    delete threshold_param_;
+    delete window_data_param_;
+    delete transform_param_;
+    delete loss_param_;
+    delete layer_;
+  }
+}
+
+void V1LayerParameter::SetCachedSize(int size) const {
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* V1LayerParameter::descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return V1LayerParameter_descriptor_;
+}
+
+const V1LayerParameter& V1LayerParameter::default_instance() {
+  protobuf_InitDefaults_caffe_2eproto();
+  return *internal_default_instance();
+}
+
+::google::protobuf::internal::ExplicitlyConstructed<V1LayerParameter> V1LayerParameter_default_instance_;
+
+V1LayerParameter* V1LayerParameter::New(::google::protobuf::Arena* arena) const {
+  V1LayerParameter* n = new V1LayerParameter;
+  if (arena != NULL) {
+    arena->Own(n);
+  }
+  return n;
+}
+
+void V1LayerParameter::Clear() {
+// @@protoc_insertion_point(message_clear_start:caffe.V1LayerParameter)
+  if (_has_bits_[0 / 32] & 36u) {
+    if (has_name()) {
+      name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+    }
+    type_ = 0;
+  }
+  if (_has_bits_[8 / 32] & 61440u) {
+    if (has_accuracy_param()) {
+      if (accuracy_param_ != NULL) accuracy_param_->::caffe::AccuracyParameter::Clear();
+    }
+    if (has_argmax_param()) {
+      if (argmax_param_ != NULL) argmax_param_->::caffe::ArgMaxParameter::Clear();
+    }
+    if (has_concat_param()) {
+      if (concat_param_ != NULL) concat_param_->::caffe::ConcatParameter::Clear();
+    }
+    if (has_contrastive_loss_param()) {
+      if (contrastive_loss_param_ != NULL) contrastive_loss_param_->::caffe::ContrastiveLossParameter::Clear();
+    }
+  }
+  if (_has_bits_[16 / 32] & 16711680u) {
+    if (has_convolution_param()) {
+      if (convolution_param_ != NULL) convolution_param_->::caffe::ConvolutionParameter::Clear();
+    }
+    if (has_data_param()) {
+      if (data_param_ != NULL) data_param_->::caffe::DataParameter::Clear();
+    }
+    if (has_dropout_param()) {
+      if (dropout_param_ != NULL) dropout_param_->::caffe::DropoutParameter::Clear();
+    }
+    if (has_dummy_data_param()) {
+      if (dummy_data_param_ != NULL) dummy_data_param_->::caffe::DummyDataParameter::Clear();
+    }
+    if (has_eltwise_param()) {
+      if (eltwise_param_ != NULL) eltwise_param_->::caffe::EltwiseParameter::Clear();
+    }
+    if (has_exp_param()) {
+      if (exp_param_ != NULL) exp_param_->::caffe::ExpParameter::Clear();
+    }
+    if (has_hdf5_data_param()) {
+      if (hdf5_data_param_ != NULL) hdf5_data_param_->::caffe::HDF5DataParameter::Clear();
+    }
+    if (has_hdf5_output_param()) {
+      if (hdf5_output_param_ != NULL) hdf5_output_param_->::caffe::HDF5OutputParameter::Clear();
+    }
+  }
+  if (_has_bits_[24 / 32] & 4278190080u) {
+    if (has_hinge_loss_param()) {
+      if (hinge_loss_param_ != NULL) hinge_loss_param_->::caffe::HingeLossParameter::Clear();
+    }
+    if (has_image_data_param()) {
+      if (image_data_param_ != NULL) image_data_param_->::caffe::ImageDataParameter::Clear();
+    }
+    if (has_infogain_loss_param()) {
+      if (infogain_loss_param_ != NULL) infogain_loss_param_->::caffe::InfogainLossParameter::Clear();
+    }
+    if (has_inner_product_param()) {
+      if (inner_product_param_ != NULL) inner_product_param_->::caffe::InnerProductParameter::Clear();
+    }
+    if (has_lrn_param()) {
+      if (lrn_param_ != NULL) lrn_param_->::caffe::LRNParameter::Clear();
+    }
+    if (has_memory_data_param()) {
+      if (memory_data_param_ != NULL) memory_data_param_->::caffe::MemoryDataParameter::Clear();
+    }
+    if (has_mvn_param()) {
+      if (mvn_param_ != NULL) mvn_param_->::caffe::MVNParameter::Clear();
+    }
+    if (has_pooling_param()) {
+      if (pooling_param_ != NULL) pooling_param_->::caffe::PoolingParameter::Clear();
+    }
+  }
+  if (_has_bits_[32 / 32] & 255u) {
+    if (has_power_param()) {
+      if (power_param_ != NULL) power_param_->::caffe::PowerParameter::Clear();
+    }
+    if (has_relu_param()) {
+      if (relu_param_ != NULL) relu_param_->::caffe::ReLUParameter::Clear();
+    }
+    if (has_sigmoid_param()) {
+      if (sigmoid_param_ != NULL) sigmoid_param_->::caffe::SigmoidParameter::Clear();
+    }
+    if (has_softmax_param()) {
+      if (softmax_param_ != NULL) softmax_param_->::caffe::SoftmaxParameter::Clear();
+    }
+    if (has_slice_param()) {
+      if (slice_param_ != NULL) slice_param_->::caffe::SliceParameter::Clear();
+    }
+    if (has_tanh_param()) {
+      if (tanh_param_ != NULL) tanh_param_->::caffe::TanHParameter::Clear();
+    }
+    if (has_threshold_param()) {
+      if (threshold_param_ != NULL) threshold_param_->::caffe::ThresholdParameter::Clear();
+    }
+    if (has_window_data_param()) {
+      if (window_data_param_ != NULL) window_data_param_->::caffe::WindowDataParameter::Clear();
+    }
+  }
+  if (_has_bits_[40 / 32] & 1792u) {
+    if (has_transform_param()) {
+      if (transform_param_ != NULL) transform_param_->::caffe::TransformationParameter::Clear();
+    }
+    if (has_loss_param()) {
+      if (loss_param_ != NULL) loss_param_->::caffe::LossParameter::Clear();
+    }
+    if (has_layer()) {
+      if (layer_ != NULL) layer_->::caffe::V0LayerParameter::Clear();
+    }
+  }
+  bottom_.Clear();
+  top_.Clear();
+  include_.Clear();
+  exclude_.Clear();
+  blobs_.Clear();
+  param_.Clear();
+  blob_share_mode_.Clear();
+  blobs_lr_.Clear();
+  weight_decay_.Clear();
+  loss_weight_.Clear();
+  _has_bits_.Clear();
+  if (_internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->Clear();
+  }
+}
+
+bool V1LayerParameter::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
+  ::google::protobuf::uint32 tag;
+  // @@protoc_insertion_point(parse_start:caffe.V1LayerParameter)
+  for (;;) {
+    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(16383);
+    tag = p.first;
+    if (!p.second) goto handle_unusual;
+    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+      // optional .caffe.V0LayerParameter layer = 1;
+      case 1: {
+        if (tag == 10) {
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+               input, mutable_layer()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(18)) goto parse_bottom;
+        break;
+      }
+
+      // repeated string bottom = 2;
+      case 2: {
+        if (tag == 18) {
+         parse_bottom:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+                input, this->add_bottom()));
+          ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+            this->bottom(this->bottom_size() - 1).data(),
+            this->bottom(this->bottom_size() - 1).length(),
+            ::google::protobuf::internal::WireFormat::PARSE,
+            "caffe.V1LayerParameter.bottom");
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(18)) goto parse_bottom;
+        if (input->ExpectTag(26)) goto parse_top;
+        break;
+      }
+
+      // repeated string top = 3;
+      case 3: {
+        if (tag == 26) {
+         parse_top:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+                input, this->add_top()));
+          ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+            this->top(this->top_size() - 1).data(),
+            this->top(this->top_size() - 1).length(),
+            ::google::protobuf::internal::WireFormat::PARSE,
+            "caffe.V1LayerParameter.top");
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(26)) goto parse_top;
+        if (input->ExpectTag(34)) goto parse_name;
+        break;
+      }
+
+      // optional string name = 4;
+      case 4: {
+        if (tag == 34) {
+         parse_name:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+                input, this->mutable_name()));
+          ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+            this->name().data(), this->name().length(),
+            ::google::protobuf::internal::WireFormat::PARSE,
+            "caffe.V1LayerParameter.name");
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(40)) goto parse_type;
+        break;
+      }
+
+      // optional .caffe.V1LayerParameter.LayerType type = 5;
+      case 5: {
+        if (tag == 40) {
+         parse_type:
+          int value;
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>(
+                 input, &value)));
+          if (::caffe::V1LayerParameter_LayerType_IsValid(value)) {
+            set_type(static_cast< ::caffe::V1LayerParameter_LayerType >(value));
+          } else {
+            mutable_unknown_fields()->AddVarint(5, value);
+          }
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(50)) goto parse_blobs;
+        break;
+      }
+
+      // repeated .caffe.BlobProto blobs = 6;
+      case 6: {
+        if (tag == 50) {
+         parse_blobs:
+          DO_(input->IncrementRecursionDepth());
+         parse_loop_blobs:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth(
+                input, add_blobs()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(50)) goto parse_loop_blobs;
+        input->UnsafeDecrementRecursionDepth();
+        if (input->ExpectTag(61)) goto parse_blobs_lr;
+        break;
+      }
+
+      // repeated float blobs_lr = 7;
+      case 7: {
+        if (tag == 61) {
+         parse_blobs_lr:
+          DO_((::google::protobuf::internal::WireFormatLite::ReadRepeatedPrimitive<
+                   float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
+                 1, 61, input, this->mutable_blobs_lr())));
+        } else if (tag == 58) {
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPackedPrimitiveNoInline<
+                   float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
+                 input, this->mutable_blobs_lr())));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(61)) goto parse_blobs_lr;
+        if (input->ExpectTag(69)) goto parse_weight_decay;
+        break;
+      }
+
+      // repeated float weight_decay = 8;
+      case 8: {
+        if (tag == 69) {
+         parse_weight_decay:
+          DO_((::google::protobuf::internal::WireFormatLite::ReadRepeatedPrimitive<
+                   float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
+                 1, 69, input, this->mutable_weight_decay())));
+        } else if (tag == 66) {
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPackedPrimitiveNoInline<
+                   float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
+                 input, this->mutable_weight_decay())));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(69)) goto parse_weight_decay;
+        if (input->ExpectTag(74)) goto parse_concat_param;
+        break;
+      }
+
+      // optional .caffe.ConcatParameter concat_param = 9;
+      case 9: {
+        if (tag == 74) {
+         parse_concat_param:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+               input, mutable_concat_param()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(82)) goto parse_convolution_param;
+        break;
+      }
+
+      // optional .caffe.ConvolutionParameter convolution_param = 10;
+      case 10: {
+        if (tag == 82) {
+         parse_convolution_param:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+               input, mutable_convolution_param()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(90)) goto parse_data_param;
+        break;
+      }
+
+      // optional .caffe.DataParameter data_param = 11;
+      case 11: {
+        if (tag == 90) {
+         parse_data_param:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+               input, mutable_data_param()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(98)) goto parse_dropout_param;
+        break;
+      }
+
+      // optional .caffe.DropoutParameter dropout_param = 12;
+      case 12: {
+        if (tag == 98) {
+         parse_dropout_param:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+               input, mutable_dropout_param()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(106)) goto parse_hdf5_data_param;
+        break;
+      }
+
+      // optional .caffe.HDF5DataParameter hdf5_data_param = 13;
+      case 13: {
+        if (tag == 106) {
+         parse_hdf5_data_param:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+               input, mutable_hdf5_data_param()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(114)) goto parse_hdf5_output_param;
+        break;
+      }
+
+      // optional .caffe.HDF5OutputParameter hdf5_output_param = 14;
+      case 14: {
+        if (tag == 114) {
+         parse_hdf5_output_param:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+               input, mutable_hdf5_output_param()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(122)) goto parse_image_data_param;
+        break;
+      }
+
+      // optional .caffe.ImageDataParameter image_data_param = 15;
+      case 15: {
+        if (tag == 122) {
+         parse_image_data_param:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+               input, mutable_image_data_param()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(130)) goto parse_infogain_loss_param;
+        break;
+      }
+
+      // optional .caffe.InfogainLossParameter infogain_loss_param = 16;
+      case 16: {
+        if (tag == 130) {
+         parse_infogain_loss_param:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+               input, mutable_infogain_loss_param()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(138)) goto parse_inner_product_param;
+        break;
+      }
+
+      // optional .caffe.InnerProductParameter inner_product_param = 17;
+      case 17: {
+        if (tag == 138) {
+         parse_inner_product_param:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+               input, mutable_inner_product_param()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(146)) goto parse_lrn_param;
+        break;
+      }
+
+      // optional .caffe.LRNParameter lrn_param = 18;
+      case 18: {
+        if (tag == 146) {
+         parse_lrn_param:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+               input, mutable_lrn_param()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(154)) goto parse_pooling_param;
+        break;
+      }
+
+      // optional .caffe.PoolingParameter pooling_param = 19;
+      case 19: {
+        if (tag == 154) {
+         parse_pooling_param:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+               input, mutable_pooling_param()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(162)) goto parse_window_data_param;
+        break;
+      }
+
+      // optional .caffe.WindowDataParameter window_data_param = 20;
+      case 20: {
+        if (tag == 162) {
+         parse_window_data_param:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+               input, mutable_window_data_param()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(170)) goto parse_power_param;
+        break;
+      }
+
+      // optional .caffe.PowerParameter power_param = 21;
+      case 21: {
+        if (tag == 170) {
+         parse_power_param:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+               input, mutable_power_param()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(178)) goto parse_memory_data_param;
+        break;
+      }
+
+      // optional .caffe.MemoryDataParameter memory_data_param = 22;
+      case 22: {
+        if (tag == 178) {
+         parse_memory_data_param:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+               input, mutable_memory_data_param()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(186)) goto parse_argmax_param;
+        break;
+      }
+
+      // optional .caffe.ArgMaxParameter argmax_param = 23;
+      case 23: {
+        if (tag == 186) {
+         parse_argmax_param:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+               input, mutable_argmax_param()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(194)) goto parse_eltwise_param;
+        break;
+      }
+
+      // optional .caffe.EltwiseParameter eltwise_param = 24;
+      case 24: {
+        if (tag == 194) {
+         parse_eltwise_param:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+               input, mutable_eltwise_param()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(202)) goto parse_threshold_param;
+        break;
+      }
+
+      // optional .caffe.ThresholdParameter threshold_param = 25;
+      case 25: {
+        if (tag == 202) {
+         parse_threshold_param:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+               input, mutable_threshold_param()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(210)) goto parse_dummy_data_param;
+        break;
+      }
+
+      // optional .caffe.DummyDataParameter dummy_data_param = 26;
+      case 26: {
+        if (tag == 210) {
+         parse_dummy_data_param:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+               input, mutable_dummy_data_param()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(218)) goto parse_accuracy_param;
+        break;
+      }
+
+      // optional .caffe.AccuracyParameter accuracy_param = 27;
+      case 27: {
+        if (tag == 218) {
+         parse_accuracy_param:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+               input, mutable_accuracy_param()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(234)) goto parse_hinge_loss_param;
+        break;
+      }
+
+      // optional .caffe.HingeLossParameter hinge_loss_param = 29;
+      case 29: {
+        if (tag == 234) {
+         parse_hinge_loss_param:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+               input, mutable_hinge_loss_param()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(242)) goto parse_relu_param;
+        break;
+      }
+
+      // optional .caffe.ReLUParameter relu_param = 30;
+      case 30: {
+        if (tag == 242) {
+         parse_relu_param:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+               input, mutable_relu_param()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(250)) goto parse_slice_param;
+        break;
+      }
+
+      // optional .caffe.SliceParameter slice_param = 31;
+      case 31: {
+        if (tag == 250) {
+         parse_slice_param:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+               input, mutable_slice_param()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(258)) goto parse_include;
+        break;
+      }
+
+      // repeated .caffe.NetStateRule include = 32;
+      case 32: {
+        if (tag == 258) {
+         parse_include:
+          DO_(input->IncrementRecursionDepth());
+         parse_loop_include:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth(
+                input, add_include()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(258)) goto parse_loop_include;
+        if (input->ExpectTag(266)) goto parse_loop_exclude;
+        input->UnsafeDecrementRecursionDepth();
+        break;
+      }
+
+      // repeated .caffe.NetStateRule exclude = 33;
+      case 33: {
+        if (tag == 266) {
+          DO_(input->IncrementRecursionDepth());
+         parse_loop_exclude:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth(
+                input, add_exclude()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(266)) goto parse_loop_exclude;
+        input->UnsafeDecrementRecursionDepth();
+        if (input->ExpectTag(274)) goto parse_mvn_param;
+        break;
+      }
+
+      // optional .caffe.MVNParameter mvn_param = 34;
+      case 34: {
+        if (tag == 274) {
+         parse_mvn_param:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+               input, mutable_mvn_param()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(285)) goto parse_loss_weight;
+        break;
+      }
+
+      // repeated float loss_weight = 35;
+      case 35: {
+        if (tag == 285) {
+         parse_loss_weight:
+          DO_((::google::protobuf::internal::WireFormatLite::ReadRepeatedPrimitive<
+                   float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
+                 2, 285, input, this->mutable_loss_weight())));
+        } else if (tag == 282) {
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPackedPrimitiveNoInline<
+                   float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
+                 input, this->mutable_loss_weight())));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(285)) goto parse_loss_weight;
+        if (input->ExpectTag(290)) goto parse_transform_param;
+        break;
+      }
+
+      // optional .caffe.TransformationParameter transform_param = 36;
+      case 36: {
+        if (tag == 290) {
+         parse_transform_param:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+               input, mutable_transform_param()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(298)) goto parse_tanh_param;
+        break;
+      }
+
+      // optional .caffe.TanHParameter tanh_param = 37;
+      case 37: {
+        if (tag == 298) {
+         parse_tanh_param:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+               input, mutable_tanh_param()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(306)) goto parse_sigmoid_param;
+        break;
+      }
+
+      // optional .caffe.SigmoidParameter sigmoid_param = 38;
+      case 38: {
+        if (tag == 306) {
+         parse_sigmoid_param:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+               input, mutable_sigmoid_param()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(314)) goto parse_softmax_param;
+        break;
+      }
+
+      // optional .caffe.SoftmaxParameter softmax_param = 39;
+      case 39: {
+        if (tag == 314) {
+         parse_softmax_param:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+               input, mutable_softmax_param()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(322)) goto parse_contrastive_loss_param;
+        break;
+      }
+
+      // optional .caffe.ContrastiveLossParameter contrastive_loss_param = 40;
+      case 40: {
+        if (tag == 322) {
+         parse_contrastive_loss_param:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+               input, mutable_contrastive_loss_param()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(330)) goto parse_exp_param;
+        break;
+      }
+
+      // optional .caffe.ExpParameter exp_param = 41;
+      case 41: {
+        if (tag == 330) {
+         parse_exp_param:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+               input, mutable_exp_param()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(338)) goto parse_loss_param;
+        break;
+      }
+
+      // optional .caffe.LossParameter loss_param = 42;
+      case 42: {
+        if (tag == 338) {
+         parse_loss_param:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+               input, mutable_loss_param()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(8010)) goto parse_param;
+        break;
+      }
+
+      // repeated string param = 1001;
+      case 1001: {
+        if (tag == 8010) {
+         parse_param:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+                input, this->add_param()));
+          ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+            this->param(this->param_size() - 1).data(),
+            this->param(this->param_size() - 1).length(),
+            ::google::protobuf::internal::WireFormat::PARSE,
+            "caffe.V1LayerParameter.param");
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(8010)) goto parse_param;
+        if (input->ExpectTag(8016)) goto parse_blob_share_mode;
+        break;
+      }
+
+      // repeated .caffe.V1LayerParameter.DimCheckMode blob_share_mode = 1002;
+      case 1002: {
+        if (tag == 8016) {
+         parse_blob_share_mode:
+          int value;
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>(
+                 input, &value)));
+          if (::caffe::V1LayerParameter_DimCheckMode_IsValid(value)) {
+            add_blob_share_mode(static_cast< ::caffe::V1LayerParameter_DimCheckMode >(value));
+          } else {
+            mutable_unknown_fields()->AddVarint(1002, value);
+          }
+        } else if (tag == 8018) {
+          DO_((::google::protobuf::internal::WireFormat::ReadPackedEnumPreserveUnknowns(
+                 input,
+                 1002,
+                 ::caffe::V1LayerParameter_DimCheckMode_IsValid,
+                 mutable_unknown_fields(),
+                 this->mutable_blob_share_mode())));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(8016)) goto parse_blob_share_mode;
+        if (input->ExpectAtEnd()) goto success;
+        break;
+      }
+
+      default: {
+      handle_unusual:
+        if (tag == 0 ||
+            ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+          goto success;
+        }
+        DO_(::google::protobuf::internal::WireFormat::SkipField(
+              input, tag, mutable_unknown_fields()));
+        break;
+      }
+    }
+  }
+success:
+  // @@protoc_insertion_point(parse_success:caffe.V1LayerParameter)
+  return true;
+failure:
+  // @@protoc_insertion_point(parse_failure:caffe.V1LayerParameter)
+  return false;
+#undef DO_
+}
+
+void V1LayerParameter::SerializeWithCachedSizes(
+    ::google::protobuf::io::CodedOutputStream* output) const {
+  // @@protoc_insertion_point(serialize_start:caffe.V1LayerParameter)
+  // optional .caffe.V0LayerParameter layer = 1;
+  if (has_layer()) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      1, *this->layer_, output);
+  }
+
+  // repeated string bottom = 2;
+  for (int i = 0; i < this->bottom_size(); i++) {
+    ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->bottom(i).data(), this->bottom(i).length(),
+      ::google::protobuf::internal::WireFormat::SERIALIZE,
+      "caffe.V1LayerParameter.bottom");
+    ::google::protobuf::internal::WireFormatLite::WriteString(
+      2, this->bottom(i), output);
+  }
+
+  // repeated string top = 3;
+  for (int i = 0; i < this->top_size(); i++) {
+    ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->top(i).data(), this->top(i).length(),
+      ::google::protobuf::internal::WireFormat::SERIALIZE,
+      "caffe.V1LayerParameter.top");
+    ::google::protobuf::internal::WireFormatLite::WriteString(
+      3, this->top(i), output);
+  }
+
+  // optional string name = 4;
+  if (has_name()) {
+    ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->name().data(), this->name().length(),
+      ::google::protobuf::internal::WireFormat::SERIALIZE,
+      "caffe.V1LayerParameter.name");
+    ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
+      4, this->name(), output);
+  }
+
+  // optional .caffe.V1LayerParameter.LayerType type = 5;
+  if (has_type()) {
+    ::google::protobuf::internal::WireFormatLite::WriteEnum(
+      5, this->type(), output);
+  }
+
+  // repeated .caffe.BlobProto blobs = 6;
+  for (unsigned int i = 0, n = this->blobs_size(); i < n; i++) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      6, this->blobs(i), output);
+  }
+
+  // repeated float blobs_lr = 7;
+  for (int i = 0; i < this->blobs_lr_size(); i++) {
+    ::google::protobuf::internal::WireFormatLite::WriteFloat(
+      7, this->blobs_lr(i), output);
+  }
+
+  // repeated float weight_decay = 8;
+  for (int i = 0; i < this->weight_decay_size(); i++) {
+    ::google::protobuf::internal::WireFormatLite::WriteFloat(
+      8, this->weight_decay(i), output);
+  }
+
+  // optional .caffe.ConcatParameter concat_param = 9;
+  if (has_concat_param()) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      9, *this->concat_param_, output);
+  }
+
+  // optional .caffe.ConvolutionParameter convolution_param = 10;
+  if (has_convolution_param()) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      10, *this->convolution_param_, output);
+  }
+
+  // optional .caffe.DataParameter data_param = 11;
+  if (has_data_param()) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      11, *this->data_param_, output);
+  }
+
+  // optional .caffe.DropoutParameter dropout_param = 12;
+  if (has_dropout_param()) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      12, *this->dropout_param_, output);
+  }
+
+  // optional .caffe.HDF5DataParameter hdf5_data_param = 13;
+  if (has_hdf5_data_param()) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      13, *this->hdf5_data_param_, output);
+  }
+
+  // optional .caffe.HDF5OutputParameter hdf5_output_param = 14;
+  if (has_hdf5_output_param()) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      14, *this->hdf5_output_param_, output);
+  }
+
+  // optional .caffe.ImageDataParameter image_data_param = 15;
+  if (has_image_data_param()) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      15, *this->image_data_param_, output);
+  }
+
+  // optional .caffe.InfogainLossParameter infogain_loss_param = 16;
+  if (has_infogain_loss_param()) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      16, *this->infogain_loss_param_, output);
+  }
+
+  // optional .caffe.InnerProductParameter inner_product_param = 17;
+  if (has_inner_product_param()) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      17, *this->inner_product_param_, output);
+  }
+
+  // optional .caffe.LRNParameter lrn_param = 18;
+  if (has_lrn_param()) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      18, *this->lrn_param_, output);
+  }
+
+  // optional .caffe.PoolingParameter pooling_param = 19;
+  if (has_pooling_param()) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      19, *this->pooling_param_, output);
+  }
+
+  // optional .caffe.WindowDataParameter window_data_param = 20;
+  if (has_window_data_param()) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      20, *this->window_data_param_, output);
+  }
+
+  // optional .caffe.PowerParameter power_param = 21;
+  if (has_power_param()) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      21, *this->power_param_, output);
+  }
+
+  // optional .caffe.MemoryDataParameter memory_data_param = 22;
+  if (has_memory_data_param()) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      22, *this->memory_data_param_, output);
+  }
+
+  // optional .caffe.ArgMaxParameter argmax_param = 23;
+  if (has_argmax_param()) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      23, *this->argmax_param_, output);
+  }
+
+  // optional .caffe.EltwiseParameter eltwise_param = 24;
+  if (has_eltwise_param()) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      24, *this->eltwise_param_, output);
+  }
+
+  // optional .caffe.ThresholdParameter threshold_param = 25;
+  if (has_threshold_param()) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      25, *this->threshold_param_, output);
+  }
+
+  // optional .caffe.DummyDataParameter dummy_data_param = 26;
+  if (has_dummy_data_param()) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      26, *this->dummy_data_param_, output);
+  }
+
+  // optional .caffe.AccuracyParameter accuracy_param = 27;
+  if (has_accuracy_param()) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      27, *this->accuracy_param_, output);
+  }
+
+  // optional .caffe.HingeLossParameter hinge_loss_param = 29;
+  if (has_hinge_loss_param()) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      29, *this->hinge_loss_param_, output);
+  }
+
+  // optional .caffe.ReLUParameter relu_param = 30;
+  if (has_relu_param()) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      30, *this->relu_param_, output);
+  }
+
+  // optional .caffe.SliceParameter slice_param = 31;
+  if (has_slice_param()) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      31, *this->slice_param_, output);
+  }
+
+  // repeated .caffe.NetStateRule include = 32;
+  for (unsigned int i = 0, n = this->include_size(); i < n; i++) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      32, this->include(i), output);
+  }
+
+  // repeated .caffe.NetStateRule exclude = 33;
+  for (unsigned int i = 0, n = this->exclude_size(); i < n; i++) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      33, this->exclude(i), output);
+  }
+
+  // optional .caffe.MVNParameter mvn_param = 34;
+  if (has_mvn_param()) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      34, *this->mvn_param_, output);
+  }
+
+  // repeated float loss_weight = 35;
+  for (int i = 0; i < this->loss_weight_size(); i++) {
+    ::google::protobuf::internal::WireFormatLite::WriteFloat(
+      35, this->loss_weight(i), output);
+  }
+
+  // optional .caffe.TransformationParameter transform_param = 36;
+  if (has_transform_param()) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      36, *this->transform_param_, output);
+  }
+
+  // optional .caffe.TanHParameter tanh_param = 37;
+  if (has_tanh_param()) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      37, *this->tanh_param_, output);
+  }
+
+  // optional .caffe.SigmoidParameter sigmoid_param = 38;
+  if (has_sigmoid_param()) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      38, *this->sigmoid_param_, output);
+  }
+
+  // optional .caffe.SoftmaxParameter softmax_param = 39;
+  if (has_softmax_param()) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      39, *this->softmax_param_, output);
+  }
+
+  // optional .caffe.ContrastiveLossParameter contrastive_loss_param = 40;
+  if (has_contrastive_loss_param()) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      40, *this->contrastive_loss_param_, output);
+  }
+
+  // optional .caffe.ExpParameter exp_param = 41;
+  if (has_exp_param()) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      41, *this->exp_param_, output);
+  }
+
+  // optional .caffe.LossParameter loss_param = 42;
+  if (has_loss_param()) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      42, *this->loss_param_, output);
+  }
+
+  // repeated string param = 1001;
+  for (int i = 0; i < this->param_size(); i++) {
+    ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->param(i).data(), this->param(i).length(),
+      ::google::protobuf::internal::WireFormat::SERIALIZE,
+      "caffe.V1LayerParameter.param");
+    ::google::protobuf::internal::WireFormatLite::WriteString(
+      1001, this->param(i), output);
+  }
+
+  // repeated .caffe.V1LayerParameter.DimCheckMode blob_share_mode = 1002;
+  for (int i = 0; i < this->blob_share_mode_size(); i++) {
+    ::google::protobuf::internal::WireFormatLite::WriteEnum(
+      1002, this->blob_share_mode(i), output);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
+        unknown_fields(), output);
+  }
+  // @@protoc_insertion_point(serialize_end:caffe.V1LayerParameter)
+}
+
+::google::protobuf::uint8* V1LayerParameter::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
+  (void)deterministic; // Unused
+  // @@protoc_insertion_point(serialize_to_array_start:caffe.V1LayerParameter)
+  // optional .caffe.V0LayerParameter layer = 1;
+  if (has_layer()) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        1, *this->layer_, false, target);
+  }
+
+  // repeated string bottom = 2;
+  for (int i = 0; i < this->bottom_size(); i++) {
+    ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->bottom(i).data(), this->bottom(i).length(),
+      ::google::protobuf::internal::WireFormat::SERIALIZE,
+      "caffe.V1LayerParameter.bottom");
+    target = ::google::protobuf::internal::WireFormatLite::
+      WriteStringToArray(2, this->bottom(i), target);
+  }
+
+  // repeated string top = 3;
+  for (int i = 0; i < this->top_size(); i++) {
+    ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->top(i).data(), this->top(i).length(),
+      ::google::protobuf::internal::WireFormat::SERIALIZE,
+      "caffe.V1LayerParameter.top");
+    target = ::google::protobuf::internal::WireFormatLite::
+      WriteStringToArray(3, this->top(i), target);
+  }
+
+  // optional string name = 4;
+  if (has_name()) {
+    ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->name().data(), this->name().length(),
+      ::google::protobuf::internal::WireFormat::SERIALIZE,
+      "caffe.V1LayerParameter.name");
+    target =
+      ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
+        4, this->name(), target);
+  }
+
+  // optional .caffe.V1LayerParameter.LayerType type = 5;
+  if (has_type()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteEnumToArray(
+      5, this->type(), target);
+  }
+
+  // repeated .caffe.BlobProto blobs = 6;
+  for (unsigned int i = 0, n = this->blobs_size(); i < n; i++) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        6, this->blobs(i), false, target);
+  }
+
+  // repeated float blobs_lr = 7;
+  for (int i = 0; i < this->blobs_lr_size(); i++) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      WriteFloatToArray(7, this->blobs_lr(i), target);
+  }
+
+  // repeated float weight_decay = 8;
+  for (int i = 0; i < this->weight_decay_size(); i++) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      WriteFloatToArray(8, this->weight_decay(i), target);
+  }
+
+  // optional .caffe.ConcatParameter concat_param = 9;
+  if (has_concat_param()) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        9, *this->concat_param_, false, target);
+  }
+
+  // optional .caffe.ConvolutionParameter convolution_param = 10;
+  if (has_convolution_param()) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        10, *this->convolution_param_, false, target);
+  }
+
+  // optional .caffe.DataParameter data_param = 11;
+  if (has_data_param()) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        11, *this->data_param_, false, target);
+  }
+
+  // optional .caffe.DropoutParameter dropout_param = 12;
+  if (has_dropout_param()) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        12, *this->dropout_param_, false, target);
+  }
+
+  // optional .caffe.HDF5DataParameter hdf5_data_param = 13;
+  if (has_hdf5_data_param()) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        13, *this->hdf5_data_param_, false, target);
+  }
+
+  // optional .caffe.HDF5OutputParameter hdf5_output_param = 14;
+  if (has_hdf5_output_param()) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        14, *this->hdf5_output_param_, false, target);
+  }
+
+  // optional .caffe.ImageDataParameter image_data_param = 15;
+  if (has_image_data_param()) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        15, *this->image_data_param_, false, target);
+  }
+
+  // optional .caffe.InfogainLossParameter infogain_loss_param = 16;
+  if (has_infogain_loss_param()) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        16, *this->infogain_loss_param_, false, target);
+  }
+
+  // optional .caffe.InnerProductParameter inner_product_param = 17;
+  if (has_inner_product_param()) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        17, *this->inner_product_param_, false, target);
+  }
+
+  // optional .caffe.LRNParameter lrn_param = 18;
+  if (has_lrn_param()) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        18, *this->lrn_param_, false, target);
+  }
+
+  // optional .caffe.PoolingParameter pooling_param = 19;
+  if (has_pooling_param()) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        19, *this->pooling_param_, false, target);
+  }
+
+  // optional .caffe.WindowDataParameter window_data_param = 20;
+  if (has_window_data_param()) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        20, *this->window_data_param_, false, target);
+  }
+
+  // optional .caffe.PowerParameter power_param = 21;
+  if (has_power_param()) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        21, *this->power_param_, false, target);
+  }
+
+  // optional .caffe.MemoryDataParameter memory_data_param = 22;
+  if (has_memory_data_param()) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        22, *this->memory_data_param_, false, target);
+  }
+
+  // optional .caffe.ArgMaxParameter argmax_param = 23;
+  if (has_argmax_param()) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        23, *this->argmax_param_, false, target);
+  }
+
+  // optional .caffe.EltwiseParameter eltwise_param = 24;
+  if (has_eltwise_param()) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        24, *this->eltwise_param_, false, target);
+  }
+
+  // optional .caffe.ThresholdParameter threshold_param = 25;
+  if (has_threshold_param()) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        25, *this->threshold_param_, false, target);
+  }
+
+  // optional .caffe.DummyDataParameter dummy_data_param = 26;
+  if (has_dummy_data_param()) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        26, *this->dummy_data_param_, false, target);
+  }
+
+  // optional .caffe.AccuracyParameter accuracy_param = 27;
+  if (has_accuracy_param()) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        27, *this->accuracy_param_, false, target);
+  }
+
+  // optional .caffe.HingeLossParameter hinge_loss_param = 29;
+  if (has_hinge_loss_param()) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        29, *this->hinge_loss_param_, false, target);
+  }
+
+  // optional .caffe.ReLUParameter relu_param = 30;
+  if (has_relu_param()) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        30, *this->relu_param_, false, target);
+  }
+
+  // optional .caffe.SliceParameter slice_param = 31;
+  if (has_slice_param()) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        31, *this->slice_param_, false, target);
+  }
+
+  // repeated .caffe.NetStateRule include = 32;
+  for (unsigned int i = 0, n = this->include_size(); i < n; i++) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        32, this->include(i), false, target);
+  }
+
+  // repeated .caffe.NetStateRule exclude = 33;
+  for (unsigned int i = 0, n = this->exclude_size(); i < n; i++) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        33, this->exclude(i), false, target);
+  }
+
+  // optional .caffe.MVNParameter mvn_param = 34;
+  if (has_mvn_param()) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        34, *this->mvn_param_, false, target);
+  }
+
+  // repeated float loss_weight = 35;
+  for (int i = 0; i < this->loss_weight_size(); i++) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      WriteFloatToArray(35, this->loss_weight(i), target);
+  }
+
+  // optional .caffe.TransformationParameter transform_param = 36;
+  if (has_transform_param()) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        36, *this->transform_param_, false, target);
+  }
+
+  // optional .caffe.TanHParameter tanh_param = 37;
+  if (has_tanh_param()) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        37, *this->tanh_param_, false, target);
+  }
+
+  // optional .caffe.SigmoidParameter sigmoid_param = 38;
+  if (has_sigmoid_param()) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        38, *this->sigmoid_param_, false, target);
+  }
+
+  // optional .caffe.SoftmaxParameter softmax_param = 39;
+  if (has_softmax_param()) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        39, *this->softmax_param_, false, target);
+  }
+
+  // optional .caffe.ContrastiveLossParameter contrastive_loss_param = 40;
+  if (has_contrastive_loss_param()) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        40, *this->contrastive_loss_param_, false, target);
+  }
+
+  // optional .caffe.ExpParameter exp_param = 41;
+  if (has_exp_param()) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        41, *this->exp_param_, false, target);
+  }
+
+  // optional .caffe.LossParameter loss_param = 42;
+  if (has_loss_param()) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        42, *this->loss_param_, false, target);
+  }
+
+  // repeated string param = 1001;
+  for (int i = 0; i < this->param_size(); i++) {
+    ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->param(i).data(), this->param(i).length(),
+      ::google::protobuf::internal::WireFormat::SERIALIZE,
+      "caffe.V1LayerParameter.param");
+    target = ::google::protobuf::internal::WireFormatLite::
+      WriteStringToArray(1001, this->param(i), target);
+  }
+
+  // repeated .caffe.V1LayerParameter.DimCheckMode blob_share_mode = 1002;
+  for (int i = 0; i < this->blob_share_mode_size(); i++) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteEnumToArray(
+      1002, this->blob_share_mode(i), target);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
+        unknown_fields(), target);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:caffe.V1LayerParameter)
+  return target;
+}
+
+size_t V1LayerParameter::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:caffe.V1LayerParameter)
+  size_t total_size = 0;
+
+  if (_has_bits_[2 / 32] & 36u) {
+    // optional string name = 4;
+    if (has_name()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::StringSize(
+          this->name());
+    }
+
+    // optional .caffe.V1LayerParameter.LayerType type = 5;
+    if (has_type()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::EnumSize(this->type());
+    }
+
+  }
+  if (_has_bits_[12 / 32] & 61440u) {
+    // optional .caffe.AccuracyParameter accuracy_param = 27;
+    if (has_accuracy_param()) {
+      total_size += 2 +
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          *this->accuracy_param_);
+    }
+
+    // optional .caffe.ArgMaxParameter argmax_param = 23;
+    if (has_argmax_param()) {
+      total_size += 2 +
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          *this->argmax_param_);
+    }
+
+    // optional .caffe.ConcatParameter concat_param = 9;
+    if (has_concat_param()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          *this->concat_param_);
+    }
+
+    // optional .caffe.ContrastiveLossParameter contrastive_loss_param = 40;
+    if (has_contrastive_loss_param()) {
+      total_size += 2 +
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          *this->contrastive_loss_param_);
+    }
+
+  }
+  if (_has_bits_[16 / 32] & 16711680u) {
+    // optional .caffe.ConvolutionParameter convolution_param = 10;
+    if (has_convolution_param()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          *this->convolution_param_);
+    }
+
+    // optional .caffe.DataParameter data_param = 11;
+    if (has_data_param()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          *this->data_param_);
+    }
+
+    // optional .caffe.DropoutParameter dropout_param = 12;
+    if (has_dropout_param()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          *this->dropout_param_);
+    }
+
+    // optional .caffe.DummyDataParameter dummy_data_param = 26;
+    if (has_dummy_data_param()) {
+      total_size += 2 +
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          *this->dummy_data_param_);
+    }
+
+    // optional .caffe.EltwiseParameter eltwise_param = 24;
+    if (has_eltwise_param()) {
+      total_size += 2 +
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          *this->eltwise_param_);
+    }
+
+    // optional .caffe.ExpParameter exp_param = 41;
+    if (has_exp_param()) {
+      total_size += 2 +
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          *this->exp_param_);
+    }
+
+    // optional .caffe.HDF5DataParameter hdf5_data_param = 13;
+    if (has_hdf5_data_param()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          *this->hdf5_data_param_);
+    }
+
+    // optional .caffe.HDF5OutputParameter hdf5_output_param = 14;
+    if (has_hdf5_output_param()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          *this->hdf5_output_param_);
+    }
+
+  }
+  if (_has_bits_[24 / 32] & 4278190080u) {
+    // optional .caffe.HingeLossParameter hinge_loss_param = 29;
+    if (has_hinge_loss_param()) {
+      total_size += 2 +
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          *this->hinge_loss_param_);
+    }
+
+    // optional .caffe.ImageDataParameter image_data_param = 15;
+    if (has_image_data_param()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          *this->image_data_param_);
+    }
+
+    // optional .caffe.InfogainLossParameter infogain_loss_param = 16;
+    if (has_infogain_loss_param()) {
+      total_size += 2 +
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          *this->infogain_loss_param_);
+    }
+
+    // optional .caffe.InnerProductParameter inner_product_param = 17;
+    if (has_inner_product_param()) {
+      total_size += 2 +
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          *this->inner_product_param_);
+    }
+
+    // optional .caffe.LRNParameter lrn_param = 18;
+    if (has_lrn_param()) {
+      total_size += 2 +
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          *this->lrn_param_);
+    }
+
+    // optional .caffe.MemoryDataParameter memory_data_param = 22;
+    if (has_memory_data_param()) {
+      total_size += 2 +
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          *this->memory_data_param_);
+    }
+
+    // optional .caffe.MVNParameter mvn_param = 34;
+    if (has_mvn_param()) {
+      total_size += 2 +
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          *this->mvn_param_);
+    }
+
+    // optional .caffe.PoolingParameter pooling_param = 19;
+    if (has_pooling_param()) {
+      total_size += 2 +
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          *this->pooling_param_);
+    }
+
+  }
+  if (_has_bits_[32 / 32] & 255u) {
+    // optional .caffe.PowerParameter power_param = 21;
+    if (has_power_param()) {
+      total_size += 2 +
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          *this->power_param_);
+    }
+
+    // optional .caffe.ReLUParameter relu_param = 30;
+    if (has_relu_param()) {
+      total_size += 2 +
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          *this->relu_param_);
+    }
+
+    // optional .caffe.SigmoidParameter sigmoid_param = 38;
+    if (has_sigmoid_param()) {
+      total_size += 2 +
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          *this->sigmoid_param_);
+    }
+
+    // optional .caffe.SoftmaxParameter softmax_param = 39;
+    if (has_softmax_param()) {
+      total_size += 2 +
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          *this->softmax_param_);
+    }
+
+    // optional .caffe.SliceParameter slice_param = 31;
+    if (has_slice_param()) {
+      total_size += 2 +
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          *this->slice_param_);
+    }
+
+    // optional .caffe.TanHParameter tanh_param = 37;
+    if (has_tanh_param()) {
+      total_size += 2 +
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          *this->tanh_param_);
+    }
+
+    // optional .caffe.ThresholdParameter threshold_param = 25;
+    if (has_threshold_param()) {
+      total_size += 2 +
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          *this->threshold_param_);
+    }
+
+    // optional .caffe.WindowDataParameter window_data_param = 20;
+    if (has_window_data_param()) {
+      total_size += 2 +
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          *this->window_data_param_);
+    }
+
+  }
+  if (_has_bits_[40 / 32] & 1792u) {
+    // optional .caffe.TransformationParameter transform_param = 36;
+    if (has_transform_param()) {
+      total_size += 2 +
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          *this->transform_param_);
+    }
+
+    // optional .caffe.LossParameter loss_param = 42;
+    if (has_loss_param()) {
+      total_size += 2 +
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          *this->loss_param_);
+    }
+
+    // optional .caffe.V0LayerParameter layer = 1;
+    if (has_layer()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          *this->layer_);
+    }
+
+  }
+  // repeated string bottom = 2;
+  total_size += 1 *
+      ::google::protobuf::internal::FromIntSize(this->bottom_size());
+  for (int i = 0; i < this->bottom_size(); i++) {
+    total_size += ::google::protobuf::internal::WireFormatLite::StringSize(
+      this->bottom(i));
+  }
+
+  // repeated string top = 3;
+  total_size += 1 *
+      ::google::protobuf::internal::FromIntSize(this->top_size());
+  for (int i = 0; i < this->top_size(); i++) {
+    total_size += ::google::protobuf::internal::WireFormatLite::StringSize(
+      this->top(i));
+  }
+
+  // repeated .caffe.NetStateRule include = 32;
+  {
+    unsigned int count = this->include_size();
+    total_size += 2UL * count;
+    for (unsigned int i = 0; i < count; i++) {
+      total_size +=
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          this->include(i));
+    }
+  }
+
+  // repeated .caffe.NetStateRule exclude = 33;
+  {
+    unsigned int count = this->exclude_size();
+    total_size += 2UL * count;
+    for (unsigned int i = 0; i < count; i++) {
+      total_size +=
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          this->exclude(i));
+    }
+  }
+
+  // repeated .caffe.BlobProto blobs = 6;
+  {
+    unsigned int count = this->blobs_size();
+    total_size += 1UL * count;
+    for (unsigned int i = 0; i < count; i++) {
+      total_size +=
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          this->blobs(i));
+    }
+  }
+
+  // repeated string param = 1001;
+  total_size += 2 *
+      ::google::protobuf::internal::FromIntSize(this->param_size());
+  for (int i = 0; i < this->param_size(); i++) {
+    total_size += ::google::protobuf::internal::WireFormatLite::StringSize(
+      this->param(i));
+  }
+
+  // repeated .caffe.V1LayerParameter.DimCheckMode blob_share_mode = 1002;
+  {
+    size_t data_size = 0;
+    unsigned int count = this->blob_share_mode_size();for (unsigned int i = 0; i < count; i++) {
+      data_size += ::google::protobuf::internal::WireFormatLite::EnumSize(
+        this->blob_share_mode(i));
+    }
+    total_size += (2UL * count) + data_size;
+  }
+
+  // repeated float blobs_lr = 7;
+  {
+    size_t data_size = 0;
+    unsigned int count = this->blobs_lr_size();
+    data_size = 4UL * count;
+    total_size += 1 *
+                  ::google::protobuf::internal::FromIntSize(this->blobs_lr_size());
+    total_size += data_size;
+  }
+
+  // repeated float weight_decay = 8;
+  {
+    size_t data_size = 0;
+    unsigned int count = this->weight_decay_size();
+    data_size = 4UL * count;
+    total_size += 1 *
+                  ::google::protobuf::internal::FromIntSize(this->weight_decay_size());
+    total_size += data_size;
+  }
+
+  // repeated float loss_weight = 35;
+  {
+    size_t data_size = 0;
+    unsigned int count = this->loss_weight_size();
+    data_size = 4UL * count;
+    total_size += 2 *
+                  ::google::protobuf::internal::FromIntSize(this->loss_weight_size());
+    total_size += data_size;
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    total_size +=
+      ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
+        unknown_fields());
+  }
+  int cached_size = ::google::protobuf::internal::ToCachedSize(total_size);
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = cached_size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+  return total_size;
+}
+
+void V1LayerParameter::MergeFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_merge_from_start:caffe.V1LayerParameter)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const V1LayerParameter* source =
+      ::google::protobuf::internal::DynamicCastToGenerated<const V1LayerParameter>(
+          &from);
+  if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:caffe.V1LayerParameter)
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:caffe.V1LayerParameter)
+    UnsafeMergeFrom(*source);
+  }
+}
+
+void V1LayerParameter::MergeFrom(const V1LayerParameter& from) {
+// @@protoc_insertion_point(class_specific_merge_from_start:caffe.V1LayerParameter)
+  if (GOOGLE_PREDICT_TRUE(&from != this)) {
+    UnsafeMergeFrom(from);
+  } else {
+    MergeFromFail(__LINE__);
+  }
+}
+
+void V1LayerParameter::UnsafeMergeFrom(const V1LayerParameter& from) {
+  GOOGLE_DCHECK(&from != this);
+  bottom_.UnsafeMergeFrom(from.bottom_);
+  top_.UnsafeMergeFrom(from.top_);
+  include_.MergeFrom(from.include_);
+  exclude_.MergeFrom(from.exclude_);
+  blobs_.MergeFrom(from.blobs_);
+  param_.UnsafeMergeFrom(from.param_);
+  blob_share_mode_.UnsafeMergeFrom(from.blob_share_mode_);
+  blobs_lr_.UnsafeMergeFrom(from.blobs_lr_);
+  weight_decay_.UnsafeMergeFrom(from.weight_decay_);
+  loss_weight_.UnsafeMergeFrom(from.loss_weight_);
+  if (from._has_bits_[2 / 32] & (0xffu << (2 % 32))) {
+    if (from.has_name()) {
+      set_has_name();
+      name_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.name_);
+    }
+    if (from.has_type()) {
+      set_type(from.type());
+    }
+  }
+  if (from._has_bits_[12 / 32] & (0xffu << (12 % 32))) {
+    if (from.has_accuracy_param()) {
+      mutable_accuracy_param()->::caffe::AccuracyParameter::MergeFrom(from.accuracy_param());
+    }
+    if (from.has_argmax_param()) {
+      mutable_argmax_param()->::caffe::ArgMaxParameter::MergeFrom(from.argmax_param());
+    }
+    if (from.has_concat_param()) {
+      mutable_concat_param()->::caffe::ConcatParameter::MergeFrom(from.concat_param());
+    }
+    if (from.has_contrastive_loss_param()) {
+      mutable_contrastive_loss_param()->::caffe::ContrastiveLossParameter::MergeFrom(from.contrastive_loss_param());
+    }
+  }
+  if (from._has_bits_[16 / 32] & (0xffu << (16 % 32))) {
+    if (from.has_convolution_param()) {
+      mutable_convolution_param()->::caffe::ConvolutionParameter::MergeFrom(from.convolution_param());
+    }
+    if (from.has_data_param()) {
+      mutable_data_param()->::caffe::DataParameter::MergeFrom(from.data_param());
+    }
+    if (from.has_dropout_param()) {
+      mutable_dropout_param()->::caffe::DropoutParameter::MergeFrom(from.dropout_param());
+    }
+    if (from.has_dummy_data_param()) {
+      mutable_dummy_data_param()->::caffe::DummyDataParameter::MergeFrom(from.dummy_data_param());
+    }
+    if (from.has_eltwise_param()) {
+      mutable_eltwise_param()->::caffe::EltwiseParameter::MergeFrom(from.eltwise_param());
+    }
+    if (from.has_exp_param()) {
+      mutable_exp_param()->::caffe::ExpParameter::MergeFrom(from.exp_param());
+    }
+    if (from.has_hdf5_data_param()) {
+      mutable_hdf5_data_param()->::caffe::HDF5DataParameter::MergeFrom(from.hdf5_data_param());
+    }
+    if (from.has_hdf5_output_param()) {
+      mutable_hdf5_output_param()->::caffe::HDF5OutputParameter::MergeFrom(from.hdf5_output_param());
+    }
+  }
+  if (from._has_bits_[24 / 32] & (0xffu << (24 % 32))) {
+    if (from.has_hinge_loss_param()) {
+      mutable_hinge_loss_param()->::caffe::HingeLossParameter::MergeFrom(from.hinge_loss_param());
+    }
+    if (from.has_image_data_param()) {
+      mutable_image_data_param()->::caffe::ImageDataParameter::MergeFrom(from.image_data_param());
+    }
+    if (from.has_infogain_loss_param()) {
+      mutable_infogain_loss_param()->::caffe::InfogainLossParameter::MergeFrom(from.infogain_loss_param());
+    }
+    if (from.has_inner_product_param()) {
+      mutable_inner_product_param()->::caffe::InnerProductParameter::MergeFrom(from.inner_product_param());
+    }
+    if (from.has_lrn_param()) {
+      mutable_lrn_param()->::caffe::LRNParameter::MergeFrom(from.lrn_param());
+    }
+    if (from.has_memory_data_param()) {
+      mutable_memory_data_param()->::caffe::MemoryDataParameter::MergeFrom(from.memory_data_param());
+    }
+    if (from.has_mvn_param()) {
+      mutable_mvn_param()->::caffe::MVNParameter::MergeFrom(from.mvn_param());
+    }
+    if (from.has_pooling_param()) {
+      mutable_pooling_param()->::caffe::PoolingParameter::MergeFrom(from.pooling_param());
+    }
+  }
+  if (from._has_bits_[32 / 32] & (0xffu << (32 % 32))) {
+    if (from.has_power_param()) {
+      mutable_power_param()->::caffe::PowerParameter::MergeFrom(from.power_param());
+    }
+    if (from.has_relu_param()) {
+      mutable_relu_param()->::caffe::ReLUParameter::MergeFrom(from.relu_param());
+    }
+    if (from.has_sigmoid_param()) {
+      mutable_sigmoid_param()->::caffe::SigmoidParameter::MergeFrom(from.sigmoid_param());
+    }
+    if (from.has_softmax_param()) {
+      mutable_softmax_param()->::caffe::SoftmaxParameter::MergeFrom(from.softmax_param());
+    }
+    if (from.has_slice_param()) {
+      mutable_slice_param()->::caffe::SliceParameter::MergeFrom(from.slice_param());
+    }
+    if (from.has_tanh_param()) {
+      mutable_tanh_param()->::caffe::TanHParameter::MergeFrom(from.tanh_param());
+    }
+    if (from.has_threshold_param()) {
+      mutable_threshold_param()->::caffe::ThresholdParameter::MergeFrom(from.threshold_param());
+    }
+    if (from.has_window_data_param()) {
+      mutable_window_data_param()->::caffe::WindowDataParameter::MergeFrom(from.window_data_param());
+    }
+  }
+  if (from._has_bits_[40 / 32] & (0xffu << (40 % 32))) {
+    if (from.has_transform_param()) {
+      mutable_transform_param()->::caffe::TransformationParameter::MergeFrom(from.transform_param());
+    }
+    if (from.has_loss_param()) {
+      mutable_loss_param()->::caffe::LossParameter::MergeFrom(from.loss_param());
+    }
+    if (from.has_layer()) {
+      mutable_layer()->::caffe::V0LayerParameter::MergeFrom(from.layer());
+    }
+  }
+  if (from._internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::UnknownFieldSet::MergeToInternalMetdata(
+      from.unknown_fields(), &_internal_metadata_);
+  }
+}
+
+void V1LayerParameter::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:caffe.V1LayerParameter)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void V1LayerParameter::CopyFrom(const V1LayerParameter& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:caffe.V1LayerParameter)
+  if (&from == this) return;
+  Clear();
+  UnsafeMergeFrom(from);
+}
+
+bool V1LayerParameter::IsInitialized() const {
+
+  return true;
+}
+
+void V1LayerParameter::Swap(V1LayerParameter* other) {
+  if (other == this) return;
+  InternalSwap(other);
+}
+void V1LayerParameter::InternalSwap(V1LayerParameter* other) {
+  bottom_.UnsafeArenaSwap(&other->bottom_);
+  top_.UnsafeArenaSwap(&other->top_);
+  name_.Swap(&other->name_);
+  include_.UnsafeArenaSwap(&other->include_);
+  exclude_.UnsafeArenaSwap(&other->exclude_);
+  std::swap(type_, other->type_);
+  blobs_.UnsafeArenaSwap(&other->blobs_);
+  param_.UnsafeArenaSwap(&other->param_);
+  blob_share_mode_.UnsafeArenaSwap(&other->blob_share_mode_);
+  blobs_lr_.UnsafeArenaSwap(&other->blobs_lr_);
+  weight_decay_.UnsafeArenaSwap(&other->weight_decay_);
+  loss_weight_.UnsafeArenaSwap(&other->loss_weight_);
+  std::swap(accuracy_param_, other->accuracy_param_);
+  std::swap(argmax_param_, other->argmax_param_);
+  std::swap(concat_param_, other->concat_param_);
+  std::swap(contrastive_loss_param_, other->contrastive_loss_param_);
+  std::swap(convolution_param_, other->convolution_param_);
+  std::swap(data_param_, other->data_param_);
+  std::swap(dropout_param_, other->dropout_param_);
+  std::swap(dummy_data_param_, other->dummy_data_param_);
+  std::swap(eltwise_param_, other->eltwise_param_);
+  std::swap(exp_param_, other->exp_param_);
+  std::swap(hdf5_data_param_, other->hdf5_data_param_);
+  std::swap(hdf5_output_param_, other->hdf5_output_param_);
+  std::swap(hinge_loss_param_, other->hinge_loss_param_);
+  std::swap(image_data_param_, other->image_data_param_);
+  std::swap(infogain_loss_param_, other->infogain_loss_param_);
+  std::swap(inner_product_param_, other->inner_product_param_);
+  std::swap(lrn_param_, other->lrn_param_);
+  std::swap(memory_data_param_, other->memory_data_param_);
+  std::swap(mvn_param_, other->mvn_param_);
+  std::swap(pooling_param_, other->pooling_param_);
+  std::swap(power_param_, other->power_param_);
+  std::swap(relu_param_, other->relu_param_);
+  std::swap(sigmoid_param_, other->sigmoid_param_);
+  std::swap(softmax_param_, other->softmax_param_);
+  std::swap(slice_param_, other->slice_param_);
+  std::swap(tanh_param_, other->tanh_param_);
+  std::swap(threshold_param_, other->threshold_param_);
+  std::swap(window_data_param_, other->window_data_param_);
+  std::swap(transform_param_, other->transform_param_);
+  std::swap(loss_param_, other->loss_param_);
+  std::swap(layer_, other->layer_);
+  std::swap(_has_bits_[0], other->_has_bits_[0]);
+  std::swap(_has_bits_[1], other->_has_bits_[1]);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
+}
+
+::google::protobuf::Metadata V1LayerParameter::GetMetadata() const {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::Metadata metadata;
+  metadata.descriptor = V1LayerParameter_descriptor_;
+  metadata.reflection = V1LayerParameter_reflection_;
+  return metadata;
+}
+
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// V1LayerParameter
+
+// repeated string bottom = 2;
+int V1LayerParameter::bottom_size() const {
+  return bottom_.size();
+}
+void V1LayerParameter::clear_bottom() {
+  bottom_.Clear();
+}
+const ::std::string& V1LayerParameter::bottom(int index) const {
+  // @@protoc_insertion_point(field_get:caffe.V1LayerParameter.bottom)
+  return bottom_.Get(index);
+}
+::std::string* V1LayerParameter::mutable_bottom(int index) {
+  // @@protoc_insertion_point(field_mutable:caffe.V1LayerParameter.bottom)
+  return bottom_.Mutable(index);
+}
+void V1LayerParameter::set_bottom(int index, const ::std::string& value) {
+  // @@protoc_insertion_point(field_set:caffe.V1LayerParameter.bottom)
+  bottom_.Mutable(index)->assign(value);
+}
+void V1LayerParameter::set_bottom(int index, const char* value) {
+  bottom_.Mutable(index)->assign(value);
+  // @@protoc_insertion_point(field_set_char:caffe.V1LayerParameter.bottom)
+}
+void V1LayerParameter::set_bottom(int index, const char* value, size_t size) {
+  bottom_.Mutable(index)->assign(
+    reinterpret_cast<const char*>(value), size);
+  // @@protoc_insertion_point(field_set_pointer:caffe.V1LayerParameter.bottom)
+}
+::std::string* V1LayerParameter::add_bottom() {
+  // @@protoc_insertion_point(field_add_mutable:caffe.V1LayerParameter.bottom)
+  return bottom_.Add();
+}
+void V1LayerParameter::add_bottom(const ::std::string& value) {
+  bottom_.Add()->assign(value);
+  // @@protoc_insertion_point(field_add:caffe.V1LayerParameter.bottom)
+}
+void V1LayerParameter::add_bottom(const char* value) {
+  bottom_.Add()->assign(value);
+  // @@protoc_insertion_point(field_add_char:caffe.V1LayerParameter.bottom)
+}
+void V1LayerParameter::add_bottom(const char* value, size_t size) {
+  bottom_.Add()->assign(reinterpret_cast<const char*>(value), size);
+  // @@protoc_insertion_point(field_add_pointer:caffe.V1LayerParameter.bottom)
+}
+const ::google::protobuf::RepeatedPtrField< ::std::string>&
+V1LayerParameter::bottom() const {
+  // @@protoc_insertion_point(field_list:caffe.V1LayerParameter.bottom)
+  return bottom_;
+}
+::google::protobuf::RepeatedPtrField< ::std::string>*
+V1LayerParameter::mutable_bottom() {
+  // @@protoc_insertion_point(field_mutable_list:caffe.V1LayerParameter.bottom)
+  return &bottom_;
+}
+
+// repeated string top = 3;
+int V1LayerParameter::top_size() const {
+  return top_.size();
+}
+void V1LayerParameter::clear_top() {
+  top_.Clear();
+}
+const ::std::string& V1LayerParameter::top(int index) const {
+  // @@protoc_insertion_point(field_get:caffe.V1LayerParameter.top)
+  return top_.Get(index);
+}
+::std::string* V1LayerParameter::mutable_top(int index) {
+  // @@protoc_insertion_point(field_mutable:caffe.V1LayerParameter.top)
+  return top_.Mutable(index);
+}
+void V1LayerParameter::set_top(int index, const ::std::string& value) {
+  // @@protoc_insertion_point(field_set:caffe.V1LayerParameter.top)
+  top_.Mutable(index)->assign(value);
+}
+void V1LayerParameter::set_top(int index, const char* value) {
+  top_.Mutable(index)->assign(value);
+  // @@protoc_insertion_point(field_set_char:caffe.V1LayerParameter.top)
+}
+void V1LayerParameter::set_top(int index, const char* value, size_t size) {
+  top_.Mutable(index)->assign(
+    reinterpret_cast<const char*>(value), size);
+  // @@protoc_insertion_point(field_set_pointer:caffe.V1LayerParameter.top)
+}
+::std::string* V1LayerParameter::add_top() {
+  // @@protoc_insertion_point(field_add_mutable:caffe.V1LayerParameter.top)
+  return top_.Add();
+}
+void V1LayerParameter::add_top(const ::std::string& value) {
+  top_.Add()->assign(value);
+  // @@protoc_insertion_point(field_add:caffe.V1LayerParameter.top)
+}
+void V1LayerParameter::add_top(const char* value) {
+  top_.Add()->assign(value);
+  // @@protoc_insertion_point(field_add_char:caffe.V1LayerParameter.top)
+}
+void V1LayerParameter::add_top(const char* value, size_t size) {
+  top_.Add()->assign(reinterpret_cast<const char*>(value), size);
+  // @@protoc_insertion_point(field_add_pointer:caffe.V1LayerParameter.top)
+}
+const ::google::protobuf::RepeatedPtrField< ::std::string>&
+V1LayerParameter::top() const {
+  // @@protoc_insertion_point(field_list:caffe.V1LayerParameter.top)
+  return top_;
+}
+::google::protobuf::RepeatedPtrField< ::std::string>*
+V1LayerParameter::mutable_top() {
+  // @@protoc_insertion_point(field_mutable_list:caffe.V1LayerParameter.top)
+  return &top_;
+}
+
+// optional string name = 4;
+bool V1LayerParameter::has_name() const {
+  return (_has_bits_[0] & 0x00000004u) != 0;
+}
+void V1LayerParameter::set_has_name() {
+  _has_bits_[0] |= 0x00000004u;
+}
+void V1LayerParameter::clear_has_name() {
+  _has_bits_[0] &= ~0x00000004u;
+}
+void V1LayerParameter::clear_name() {
+  name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  clear_has_name();
+}
+const ::std::string& V1LayerParameter::name() const {
+  // @@protoc_insertion_point(field_get:caffe.V1LayerParameter.name)
+  return name_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+void V1LayerParameter::set_name(const ::std::string& value) {
+  set_has_name();
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:caffe.V1LayerParameter.name)
+}
+void V1LayerParameter::set_name(const char* value) {
+  set_has_name();
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:caffe.V1LayerParameter.name)
+}
+void V1LayerParameter::set_name(const char* value, size_t size) {
+  set_has_name();
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:caffe.V1LayerParameter.name)
+}
+::std::string* V1LayerParameter::mutable_name() {
+  set_has_name();
+  // @@protoc_insertion_point(field_mutable:caffe.V1LayerParameter.name)
+  return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+::std::string* V1LayerParameter::release_name() {
+  // @@protoc_insertion_point(field_release:caffe.V1LayerParameter.name)
+  clear_has_name();
+  return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+void V1LayerParameter::set_allocated_name(::std::string* name) {
+  if (name != NULL) {
+    set_has_name();
+  } else {
+    clear_has_name();
+  }
+  name_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), name);
+  // @@protoc_insertion_point(field_set_allocated:caffe.V1LayerParameter.name)
+}
+
+// repeated .caffe.NetStateRule include = 32;
+int V1LayerParameter::include_size() const {
+  return include_.size();
+}
+void V1LayerParameter::clear_include() {
+  include_.Clear();
+}
+const ::caffe::NetStateRule& V1LayerParameter::include(int index) const {
+  // @@protoc_insertion_point(field_get:caffe.V1LayerParameter.include)
+  return include_.Get(index);
+}
+::caffe::NetStateRule* V1LayerParameter::mutable_include(int index) {
+  // @@protoc_insertion_point(field_mutable:caffe.V1LayerParameter.include)
+  return include_.Mutable(index);
+}
+::caffe::NetStateRule* V1LayerParameter::add_include() {
+  // @@protoc_insertion_point(field_add:caffe.V1LayerParameter.include)
+  return include_.Add();
+}
+::google::protobuf::RepeatedPtrField< ::caffe::NetStateRule >*
+V1LayerParameter::mutable_include() {
+  // @@protoc_insertion_point(field_mutable_list:caffe.V1LayerParameter.include)
+  return &include_;
+}
+const ::google::protobuf::RepeatedPtrField< ::caffe::NetStateRule >&
+V1LayerParameter::include() const {
+  // @@protoc_insertion_point(field_list:caffe.V1LayerParameter.include)
+  return include_;
+}
+
+// repeated .caffe.NetStateRule exclude = 33;
+int V1LayerParameter::exclude_size() const {
+  return exclude_.size();
+}
+void V1LayerParameter::clear_exclude() {
+  exclude_.Clear();
+}
+const ::caffe::NetStateRule& V1LayerParameter::exclude(int index) const {
+  // @@protoc_insertion_point(field_get:caffe.V1LayerParameter.exclude)
+  return exclude_.Get(index);
+}
+::caffe::NetStateRule* V1LayerParameter::mutable_exclude(int index) {
+  // @@protoc_insertion_point(field_mutable:caffe.V1LayerParameter.exclude)
+  return exclude_.Mutable(index);
+}
+::caffe::NetStateRule* V1LayerParameter::add_exclude() {
+  // @@protoc_insertion_point(field_add:caffe.V1LayerParameter.exclude)
+  return exclude_.Add();
+}
+::google::protobuf::RepeatedPtrField< ::caffe::NetStateRule >*
+V1LayerParameter::mutable_exclude() {
+  // @@protoc_insertion_point(field_mutable_list:caffe.V1LayerParameter.exclude)
+  return &exclude_;
+}
+const ::google::protobuf::RepeatedPtrField< ::caffe::NetStateRule >&
+V1LayerParameter::exclude() const {
+  // @@protoc_insertion_point(field_list:caffe.V1LayerParameter.exclude)
+  return exclude_;
+}
+
+// optional .caffe.V1LayerParameter.LayerType type = 5;
+bool V1LayerParameter::has_type() const {
+  return (_has_bits_[0] & 0x00000020u) != 0;
+}
+void V1LayerParameter::set_has_type() {
+  _has_bits_[0] |= 0x00000020u;
+}
+void V1LayerParameter::clear_has_type() {
+  _has_bits_[0] &= ~0x00000020u;
+}
+void V1LayerParameter::clear_type() {
+  type_ = 0;
+  clear_has_type();
+}
+::caffe::V1LayerParameter_LayerType V1LayerParameter::type() const {
+  // @@protoc_insertion_point(field_get:caffe.V1LayerParameter.type)
+  return static_cast< ::caffe::V1LayerParameter_LayerType >(type_);
+}
+void V1LayerParameter::set_type(::caffe::V1LayerParameter_LayerType value) {
+  assert(::caffe::V1LayerParameter_LayerType_IsValid(value));
+  set_has_type();
+  type_ = value;
+  // @@protoc_insertion_point(field_set:caffe.V1LayerParameter.type)
+}
+
+// repeated .caffe.BlobProto blobs = 6;
+int V1LayerParameter::blobs_size() const {
+  return blobs_.size();
+}
+void V1LayerParameter::clear_blobs() {
+  blobs_.Clear();
+}
+const ::caffe::BlobProto& V1LayerParameter::blobs(int index) const {
+  // @@protoc_insertion_point(field_get:caffe.V1LayerParameter.blobs)
+  return blobs_.Get(index);
+}
+::caffe::BlobProto* V1LayerParameter::mutable_blobs(int index) {
+  // @@protoc_insertion_point(field_mutable:caffe.V1LayerParameter.blobs)
+  return blobs_.Mutable(index);
+}
+::caffe::BlobProto* V1LayerParameter::add_blobs() {
+  // @@protoc_insertion_point(field_add:caffe.V1LayerParameter.blobs)
+  return blobs_.Add();
+}
+::google::protobuf::RepeatedPtrField< ::caffe::BlobProto >*
+V1LayerParameter::mutable_blobs() {
+  // @@protoc_insertion_point(field_mutable_list:caffe.V1LayerParameter.blobs)
+  return &blobs_;
+}
+const ::google::protobuf::RepeatedPtrField< ::caffe::BlobProto >&
+V1LayerParameter::blobs() const {
+  // @@protoc_insertion_point(field_list:caffe.V1LayerParameter.blobs)
+  return blobs_;
+}
+
+// repeated string param = 1001;
+int V1LayerParameter::param_size() const {
+  return param_.size();
+}
+void V1LayerParameter::clear_param() {
+  param_.Clear();
+}
+const ::std::string& V1LayerParameter::param(int index) const {
+  // @@protoc_insertion_point(field_get:caffe.V1LayerParameter.param)
+  return param_.Get(index);
+}
+::std::string* V1LayerParameter::mutable_param(int index) {
+  // @@protoc_insertion_point(field_mutable:caffe.V1LayerParameter.param)
+  return param_.Mutable(index);
+}
+void V1LayerParameter::set_param(int index, const ::std::string& value) {
+  // @@protoc_insertion_point(field_set:caffe.V1LayerParameter.param)
+  param_.Mutable(index)->assign(value);
+}
+void V1LayerParameter::set_param(int index, const char* value) {
+  param_.Mutable(index)->assign(value);
+  // @@protoc_insertion_point(field_set_char:caffe.V1LayerParameter.param)
+}
+void V1LayerParameter::set_param(int index, const char* value, size_t size) {
+  param_.Mutable(index)->assign(
+    reinterpret_cast<const char*>(value), size);
+  // @@protoc_insertion_point(field_set_pointer:caffe.V1LayerParameter.param)
+}
+::std::string* V1LayerParameter::add_param() {
+  // @@protoc_insertion_point(field_add_mutable:caffe.V1LayerParameter.param)
+  return param_.Add();
+}
+void V1LayerParameter::add_param(const ::std::string& value) {
+  param_.Add()->assign(value);
+  // @@protoc_insertion_point(field_add:caffe.V1LayerParameter.param)
+}
+void V1LayerParameter::add_param(const char* value) {
+  param_.Add()->assign(value);
+  // @@protoc_insertion_point(field_add_char:caffe.V1LayerParameter.param)
+}
+void V1LayerParameter::add_param(const char* value, size_t size) {
+  param_.Add()->assign(reinterpret_cast<const char*>(value), size);
+  // @@protoc_insertion_point(field_add_pointer:caffe.V1LayerParameter.param)
+}
+const ::google::protobuf::RepeatedPtrField< ::std::string>&
+V1LayerParameter::param() const {
+  // @@protoc_insertion_point(field_list:caffe.V1LayerParameter.param)
+  return param_;
+}
+::google::protobuf::RepeatedPtrField< ::std::string>*
+V1LayerParameter::mutable_param() {
+  // @@protoc_insertion_point(field_mutable_list:caffe.V1LayerParameter.param)
+  return &param_;
+}
+
+// repeated .caffe.V1LayerParameter.DimCheckMode blob_share_mode = 1002;
+int V1LayerParameter::blob_share_mode_size() const {
+  return blob_share_mode_.size();
+}
+void V1LayerParameter::clear_blob_share_mode() {
+  blob_share_mode_.Clear();
+}
+::caffe::V1LayerParameter_DimCheckMode V1LayerParameter::blob_share_mode(int index) const {
+  // @@protoc_insertion_point(field_get:caffe.V1LayerParameter.blob_share_mode)
+  return static_cast< ::caffe::V1LayerParameter_DimCheckMode >(blob_share_mode_.Get(index));
+}
+void V1LayerParameter::set_blob_share_mode(int index, ::caffe::V1LayerParameter_DimCheckMode value) {
+  assert(::caffe::V1LayerParameter_DimCheckMode_IsValid(value));
+  blob_share_mode_.Set(index, value);
+  // @@protoc_insertion_point(field_set:caffe.V1LayerParameter.blob_share_mode)
+}
+void V1LayerParameter::add_blob_share_mode(::caffe::V1LayerParameter_DimCheckMode value) {
+  assert(::caffe::V1LayerParameter_DimCheckMode_IsValid(value));
+  blob_share_mode_.Add(value);
+  // @@protoc_insertion_point(field_add:caffe.V1LayerParameter.blob_share_mode)
+}
+const ::google::protobuf::RepeatedField<int>&
+V1LayerParameter::blob_share_mode() const {
+  // @@protoc_insertion_point(field_list:caffe.V1LayerParameter.blob_share_mode)
+  return blob_share_mode_;
+}
+::google::protobuf::RepeatedField<int>*
+V1LayerParameter::mutable_blob_share_mode() {
+  // @@protoc_insertion_point(field_mutable_list:caffe.V1LayerParameter.blob_share_mode)
+  return &blob_share_mode_;
+}
+
+// repeated float blobs_lr = 7;
+int V1LayerParameter::blobs_lr_size() const {
+  return blobs_lr_.size();
+}
+void V1LayerParameter::clear_blobs_lr() {
+  blobs_lr_.Clear();
+}
+float V1LayerParameter::blobs_lr(int index) const {
+  // @@protoc_insertion_point(field_get:caffe.V1LayerParameter.blobs_lr)
+  return blobs_lr_.Get(index);
+}
+void V1LayerParameter::set_blobs_lr(int index, float value) {
+  blobs_lr_.Set(index, value);
+  // @@protoc_insertion_point(field_set:caffe.V1LayerParameter.blobs_lr)
+}
+void V1LayerParameter::add_blobs_lr(float value) {
+  blobs_lr_.Add(value);
+  // @@protoc_insertion_point(field_add:caffe.V1LayerParameter.blobs_lr)
+}
+const ::google::protobuf::RepeatedField< float >&
+V1LayerParameter::blobs_lr() const {
+  // @@protoc_insertion_point(field_list:caffe.V1LayerParameter.blobs_lr)
+  return blobs_lr_;
+}
+::google::protobuf::RepeatedField< float >*
+V1LayerParameter::mutable_blobs_lr() {
+  // @@protoc_insertion_point(field_mutable_list:caffe.V1LayerParameter.blobs_lr)
+  return &blobs_lr_;
+}
+
+// repeated float weight_decay = 8;
+int V1LayerParameter::weight_decay_size() const {
+  return weight_decay_.size();
+}
+void V1LayerParameter::clear_weight_decay() {
+  weight_decay_.Clear();
+}
+float V1LayerParameter::weight_decay(int index) const {
+  // @@protoc_insertion_point(field_get:caffe.V1LayerParameter.weight_decay)
+  return weight_decay_.Get(index);
+}
+void V1LayerParameter::set_weight_decay(int index, float value) {
+  weight_decay_.Set(index, value);
+  // @@protoc_insertion_point(field_set:caffe.V1LayerParameter.weight_decay)
+}
+void V1LayerParameter::add_weight_decay(float value) {
+  weight_decay_.Add(value);
+  // @@protoc_insertion_point(field_add:caffe.V1LayerParameter.weight_decay)
+}
+const ::google::protobuf::RepeatedField< float >&
+V1LayerParameter::weight_decay() const {
+  // @@protoc_insertion_point(field_list:caffe.V1LayerParameter.weight_decay)
+  return weight_decay_;
+}
+::google::protobuf::RepeatedField< float >*
+V1LayerParameter::mutable_weight_decay() {
+  // @@protoc_insertion_point(field_mutable_list:caffe.V1LayerParameter.weight_decay)
+  return &weight_decay_;
+}
+
+// repeated float loss_weight = 35;
+int V1LayerParameter::loss_weight_size() const {
+  return loss_weight_.size();
+}
+void V1LayerParameter::clear_loss_weight() {
+  loss_weight_.Clear();
+}
+float V1LayerParameter::loss_weight(int index) const {
+  // @@protoc_insertion_point(field_get:caffe.V1LayerParameter.loss_weight)
+  return loss_weight_.Get(index);
+}
+void V1LayerParameter::set_loss_weight(int index, float value) {
+  loss_weight_.Set(index, value);
+  // @@protoc_insertion_point(field_set:caffe.V1LayerParameter.loss_weight)
+}
+void V1LayerParameter::add_loss_weight(float value) {
+  loss_weight_.Add(value);
+  // @@protoc_insertion_point(field_add:caffe.V1LayerParameter.loss_weight)
+}
+const ::google::protobuf::RepeatedField< float >&
+V1LayerParameter::loss_weight() const {
+  // @@protoc_insertion_point(field_list:caffe.V1LayerParameter.loss_weight)
+  return loss_weight_;
+}
+::google::protobuf::RepeatedField< float >*
+V1LayerParameter::mutable_loss_weight() {
+  // @@protoc_insertion_point(field_mutable_list:caffe.V1LayerParameter.loss_weight)
+  return &loss_weight_;
+}
+
+// optional .caffe.AccuracyParameter accuracy_param = 27;
+bool V1LayerParameter::has_accuracy_param() const {
+  return (_has_bits_[0] & 0x00001000u) != 0;
+}
+void V1LayerParameter::set_has_accuracy_param() {
+  _has_bits_[0] |= 0x00001000u;
+}
+void V1LayerParameter::clear_has_accuracy_param() {
+  _has_bits_[0] &= ~0x00001000u;
+}
+void V1LayerParameter::clear_accuracy_param() {
+  if (accuracy_param_ != NULL) accuracy_param_->::caffe::AccuracyParameter::Clear();
+  clear_has_accuracy_param();
+}
+const ::caffe::AccuracyParameter& V1LayerParameter::accuracy_param() const {
+  // @@protoc_insertion_point(field_get:caffe.V1LayerParameter.accuracy_param)
+  return accuracy_param_ != NULL ? *accuracy_param_
+                         : *::caffe::AccuracyParameter::internal_default_instance();
+}
+::caffe::AccuracyParameter* V1LayerParameter::mutable_accuracy_param() {
+  set_has_accuracy_param();
+  if (accuracy_param_ == NULL) {
+    accuracy_param_ = new ::caffe::AccuracyParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.V1LayerParameter.accuracy_param)
+  return accuracy_param_;
+}
+::caffe::AccuracyParameter* V1LayerParameter::release_accuracy_param() {
+  // @@protoc_insertion_point(field_release:caffe.V1LayerParameter.accuracy_param)
+  clear_has_accuracy_param();
+  ::caffe::AccuracyParameter* temp = accuracy_param_;
+  accuracy_param_ = NULL;
+  return temp;
+}
+void V1LayerParameter::set_allocated_accuracy_param(::caffe::AccuracyParameter* accuracy_param) {
+  delete accuracy_param_;
+  accuracy_param_ = accuracy_param;
+  if (accuracy_param) {
+    set_has_accuracy_param();
+  } else {
+    clear_has_accuracy_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.V1LayerParameter.accuracy_param)
+}
+
+// optional .caffe.ArgMaxParameter argmax_param = 23;
+bool V1LayerParameter::has_argmax_param() const {
+  return (_has_bits_[0] & 0x00002000u) != 0;
+}
+void V1LayerParameter::set_has_argmax_param() {
+  _has_bits_[0] |= 0x00002000u;
+}
+void V1LayerParameter::clear_has_argmax_param() {
+  _has_bits_[0] &= ~0x00002000u;
+}
+void V1LayerParameter::clear_argmax_param() {
+  if (argmax_param_ != NULL) argmax_param_->::caffe::ArgMaxParameter::Clear();
+  clear_has_argmax_param();
+}
+const ::caffe::ArgMaxParameter& V1LayerParameter::argmax_param() const {
+  // @@protoc_insertion_point(field_get:caffe.V1LayerParameter.argmax_param)
+  return argmax_param_ != NULL ? *argmax_param_
+                         : *::caffe::ArgMaxParameter::internal_default_instance();
+}
+::caffe::ArgMaxParameter* V1LayerParameter::mutable_argmax_param() {
+  set_has_argmax_param();
+  if (argmax_param_ == NULL) {
+    argmax_param_ = new ::caffe::ArgMaxParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.V1LayerParameter.argmax_param)
+  return argmax_param_;
+}
+::caffe::ArgMaxParameter* V1LayerParameter::release_argmax_param() {
+  // @@protoc_insertion_point(field_release:caffe.V1LayerParameter.argmax_param)
+  clear_has_argmax_param();
+  ::caffe::ArgMaxParameter* temp = argmax_param_;
+  argmax_param_ = NULL;
+  return temp;
+}
+void V1LayerParameter::set_allocated_argmax_param(::caffe::ArgMaxParameter* argmax_param) {
+  delete argmax_param_;
+  argmax_param_ = argmax_param;
+  if (argmax_param) {
+    set_has_argmax_param();
+  } else {
+    clear_has_argmax_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.V1LayerParameter.argmax_param)
+}
+
+// optional .caffe.ConcatParameter concat_param = 9;
+bool V1LayerParameter::has_concat_param() const {
+  return (_has_bits_[0] & 0x00004000u) != 0;
+}
+void V1LayerParameter::set_has_concat_param() {
+  _has_bits_[0] |= 0x00004000u;
+}
+void V1LayerParameter::clear_has_concat_param() {
+  _has_bits_[0] &= ~0x00004000u;
+}
+void V1LayerParameter::clear_concat_param() {
+  if (concat_param_ != NULL) concat_param_->::caffe::ConcatParameter::Clear();
+  clear_has_concat_param();
+}
+const ::caffe::ConcatParameter& V1LayerParameter::concat_param() const {
+  // @@protoc_insertion_point(field_get:caffe.V1LayerParameter.concat_param)
+  return concat_param_ != NULL ? *concat_param_
+                         : *::caffe::ConcatParameter::internal_default_instance();
+}
+::caffe::ConcatParameter* V1LayerParameter::mutable_concat_param() {
+  set_has_concat_param();
+  if (concat_param_ == NULL) {
+    concat_param_ = new ::caffe::ConcatParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.V1LayerParameter.concat_param)
+  return concat_param_;
+}
+::caffe::ConcatParameter* V1LayerParameter::release_concat_param() {
+  // @@protoc_insertion_point(field_release:caffe.V1LayerParameter.concat_param)
+  clear_has_concat_param();
+  ::caffe::ConcatParameter* temp = concat_param_;
+  concat_param_ = NULL;
+  return temp;
+}
+void V1LayerParameter::set_allocated_concat_param(::caffe::ConcatParameter* concat_param) {
+  delete concat_param_;
+  concat_param_ = concat_param;
+  if (concat_param) {
+    set_has_concat_param();
+  } else {
+    clear_has_concat_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.V1LayerParameter.concat_param)
+}
+
+// optional .caffe.ContrastiveLossParameter contrastive_loss_param = 40;
+bool V1LayerParameter::has_contrastive_loss_param() const {
+  return (_has_bits_[0] & 0x00008000u) != 0;
+}
+void V1LayerParameter::set_has_contrastive_loss_param() {
+  _has_bits_[0] |= 0x00008000u;
+}
+void V1LayerParameter::clear_has_contrastive_loss_param() {
+  _has_bits_[0] &= ~0x00008000u;
+}
+void V1LayerParameter::clear_contrastive_loss_param() {
+  if (contrastive_loss_param_ != NULL) contrastive_loss_param_->::caffe::ContrastiveLossParameter::Clear();
+  clear_has_contrastive_loss_param();
+}
+const ::caffe::ContrastiveLossParameter& V1LayerParameter::contrastive_loss_param() const {
+  // @@protoc_insertion_point(field_get:caffe.V1LayerParameter.contrastive_loss_param)
+  return contrastive_loss_param_ != NULL ? *contrastive_loss_param_
+                         : *::caffe::ContrastiveLossParameter::internal_default_instance();
+}
+::caffe::ContrastiveLossParameter* V1LayerParameter::mutable_contrastive_loss_param() {
+  set_has_contrastive_loss_param();
+  if (contrastive_loss_param_ == NULL) {
+    contrastive_loss_param_ = new ::caffe::ContrastiveLossParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.V1LayerParameter.contrastive_loss_param)
+  return contrastive_loss_param_;
+}
+::caffe::ContrastiveLossParameter* V1LayerParameter::release_contrastive_loss_param() {
+  // @@protoc_insertion_point(field_release:caffe.V1LayerParameter.contrastive_loss_param)
+  clear_has_contrastive_loss_param();
+  ::caffe::ContrastiveLossParameter* temp = contrastive_loss_param_;
+  contrastive_loss_param_ = NULL;
+  return temp;
+}
+void V1LayerParameter::set_allocated_contrastive_loss_param(::caffe::ContrastiveLossParameter* contrastive_loss_param) {
+  delete contrastive_loss_param_;
+  contrastive_loss_param_ = contrastive_loss_param;
+  if (contrastive_loss_param) {
+    set_has_contrastive_loss_param();
+  } else {
+    clear_has_contrastive_loss_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.V1LayerParameter.contrastive_loss_param)
+}
+
+// optional .caffe.ConvolutionParameter convolution_param = 10;
+bool V1LayerParameter::has_convolution_param() const {
+  return (_has_bits_[0] & 0x00010000u) != 0;
+}
+void V1LayerParameter::set_has_convolution_param() {
+  _has_bits_[0] |= 0x00010000u;
+}
+void V1LayerParameter::clear_has_convolution_param() {
+  _has_bits_[0] &= ~0x00010000u;
+}
+void V1LayerParameter::clear_convolution_param() {
+  if (convolution_param_ != NULL) convolution_param_->::caffe::ConvolutionParameter::Clear();
+  clear_has_convolution_param();
+}
+const ::caffe::ConvolutionParameter& V1LayerParameter::convolution_param() const {
+  // @@protoc_insertion_point(field_get:caffe.V1LayerParameter.convolution_param)
+  return convolution_param_ != NULL ? *convolution_param_
+                         : *::caffe::ConvolutionParameter::internal_default_instance();
+}
+::caffe::ConvolutionParameter* V1LayerParameter::mutable_convolution_param() {
+  set_has_convolution_param();
+  if (convolution_param_ == NULL) {
+    convolution_param_ = new ::caffe::ConvolutionParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.V1LayerParameter.convolution_param)
+  return convolution_param_;
+}
+::caffe::ConvolutionParameter* V1LayerParameter::release_convolution_param() {
+  // @@protoc_insertion_point(field_release:caffe.V1LayerParameter.convolution_param)
+  clear_has_convolution_param();
+  ::caffe::ConvolutionParameter* temp = convolution_param_;
+  convolution_param_ = NULL;
+  return temp;
+}
+void V1LayerParameter::set_allocated_convolution_param(::caffe::ConvolutionParameter* convolution_param) {
+  delete convolution_param_;
+  convolution_param_ = convolution_param;
+  if (convolution_param) {
+    set_has_convolution_param();
+  } else {
+    clear_has_convolution_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.V1LayerParameter.convolution_param)
+}
+
+// optional .caffe.DataParameter data_param = 11;
+bool V1LayerParameter::has_data_param() const {
+  return (_has_bits_[0] & 0x00020000u) != 0;
+}
+void V1LayerParameter::set_has_data_param() {
+  _has_bits_[0] |= 0x00020000u;
+}
+void V1LayerParameter::clear_has_data_param() {
+  _has_bits_[0] &= ~0x00020000u;
+}
+void V1LayerParameter::clear_data_param() {
+  if (data_param_ != NULL) data_param_->::caffe::DataParameter::Clear();
+  clear_has_data_param();
+}
+const ::caffe::DataParameter& V1LayerParameter::data_param() const {
+  // @@protoc_insertion_point(field_get:caffe.V1LayerParameter.data_param)
+  return data_param_ != NULL ? *data_param_
+                         : *::caffe::DataParameter::internal_default_instance();
+}
+::caffe::DataParameter* V1LayerParameter::mutable_data_param() {
+  set_has_data_param();
+  if (data_param_ == NULL) {
+    data_param_ = new ::caffe::DataParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.V1LayerParameter.data_param)
+  return data_param_;
+}
+::caffe::DataParameter* V1LayerParameter::release_data_param() {
+  // @@protoc_insertion_point(field_release:caffe.V1LayerParameter.data_param)
+  clear_has_data_param();
+  ::caffe::DataParameter* temp = data_param_;
+  data_param_ = NULL;
+  return temp;
+}
+void V1LayerParameter::set_allocated_data_param(::caffe::DataParameter* data_param) {
+  delete data_param_;
+  data_param_ = data_param;
+  if (data_param) {
+    set_has_data_param();
+  } else {
+    clear_has_data_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.V1LayerParameter.data_param)
+}
+
+// optional .caffe.DropoutParameter dropout_param = 12;
+bool V1LayerParameter::has_dropout_param() const {
+  return (_has_bits_[0] & 0x00040000u) != 0;
+}
+void V1LayerParameter::set_has_dropout_param() {
+  _has_bits_[0] |= 0x00040000u;
+}
+void V1LayerParameter::clear_has_dropout_param() {
+  _has_bits_[0] &= ~0x00040000u;
+}
+void V1LayerParameter::clear_dropout_param() {
+  if (dropout_param_ != NULL) dropout_param_->::caffe::DropoutParameter::Clear();
+  clear_has_dropout_param();
+}
+const ::caffe::DropoutParameter& V1LayerParameter::dropout_param() const {
+  // @@protoc_insertion_point(field_get:caffe.V1LayerParameter.dropout_param)
+  return dropout_param_ != NULL ? *dropout_param_
+                         : *::caffe::DropoutParameter::internal_default_instance();
+}
+::caffe::DropoutParameter* V1LayerParameter::mutable_dropout_param() {
+  set_has_dropout_param();
+  if (dropout_param_ == NULL) {
+    dropout_param_ = new ::caffe::DropoutParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.V1LayerParameter.dropout_param)
+  return dropout_param_;
+}
+::caffe::DropoutParameter* V1LayerParameter::release_dropout_param() {
+  // @@protoc_insertion_point(field_release:caffe.V1LayerParameter.dropout_param)
+  clear_has_dropout_param();
+  ::caffe::DropoutParameter* temp = dropout_param_;
+  dropout_param_ = NULL;
+  return temp;
+}
+void V1LayerParameter::set_allocated_dropout_param(::caffe::DropoutParameter* dropout_param) {
+  delete dropout_param_;
+  dropout_param_ = dropout_param;
+  if (dropout_param) {
+    set_has_dropout_param();
+  } else {
+    clear_has_dropout_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.V1LayerParameter.dropout_param)
+}
+
+// optional .caffe.DummyDataParameter dummy_data_param = 26;
+bool V1LayerParameter::has_dummy_data_param() const {
+  return (_has_bits_[0] & 0x00080000u) != 0;
+}
+void V1LayerParameter::set_has_dummy_data_param() {
+  _has_bits_[0] |= 0x00080000u;
+}
+void V1LayerParameter::clear_has_dummy_data_param() {
+  _has_bits_[0] &= ~0x00080000u;
+}
+void V1LayerParameter::clear_dummy_data_param() {
+  if (dummy_data_param_ != NULL) dummy_data_param_->::caffe::DummyDataParameter::Clear();
+  clear_has_dummy_data_param();
+}
+const ::caffe::DummyDataParameter& V1LayerParameter::dummy_data_param() const {
+  // @@protoc_insertion_point(field_get:caffe.V1LayerParameter.dummy_data_param)
+  return dummy_data_param_ != NULL ? *dummy_data_param_
+                         : *::caffe::DummyDataParameter::internal_default_instance();
+}
+::caffe::DummyDataParameter* V1LayerParameter::mutable_dummy_data_param() {
+  set_has_dummy_data_param();
+  if (dummy_data_param_ == NULL) {
+    dummy_data_param_ = new ::caffe::DummyDataParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.V1LayerParameter.dummy_data_param)
+  return dummy_data_param_;
+}
+::caffe::DummyDataParameter* V1LayerParameter::release_dummy_data_param() {
+  // @@protoc_insertion_point(field_release:caffe.V1LayerParameter.dummy_data_param)
+  clear_has_dummy_data_param();
+  ::caffe::DummyDataParameter* temp = dummy_data_param_;
+  dummy_data_param_ = NULL;
+  return temp;
+}
+void V1LayerParameter::set_allocated_dummy_data_param(::caffe::DummyDataParameter* dummy_data_param) {
+  delete dummy_data_param_;
+  dummy_data_param_ = dummy_data_param;
+  if (dummy_data_param) {
+    set_has_dummy_data_param();
+  } else {
+    clear_has_dummy_data_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.V1LayerParameter.dummy_data_param)
+}
+
+// optional .caffe.EltwiseParameter eltwise_param = 24;
+bool V1LayerParameter::has_eltwise_param() const {
+  return (_has_bits_[0] & 0x00100000u) != 0;
+}
+void V1LayerParameter::set_has_eltwise_param() {
+  _has_bits_[0] |= 0x00100000u;
+}
+void V1LayerParameter::clear_has_eltwise_param() {
+  _has_bits_[0] &= ~0x00100000u;
+}
+void V1LayerParameter::clear_eltwise_param() {
+  if (eltwise_param_ != NULL) eltwise_param_->::caffe::EltwiseParameter::Clear();
+  clear_has_eltwise_param();
+}
+const ::caffe::EltwiseParameter& V1LayerParameter::eltwise_param() const {
+  // @@protoc_insertion_point(field_get:caffe.V1LayerParameter.eltwise_param)
+  return eltwise_param_ != NULL ? *eltwise_param_
+                         : *::caffe::EltwiseParameter::internal_default_instance();
+}
+::caffe::EltwiseParameter* V1LayerParameter::mutable_eltwise_param() {
+  set_has_eltwise_param();
+  if (eltwise_param_ == NULL) {
+    eltwise_param_ = new ::caffe::EltwiseParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.V1LayerParameter.eltwise_param)
+  return eltwise_param_;
+}
+::caffe::EltwiseParameter* V1LayerParameter::release_eltwise_param() {
+  // @@protoc_insertion_point(field_release:caffe.V1LayerParameter.eltwise_param)
+  clear_has_eltwise_param();
+  ::caffe::EltwiseParameter* temp = eltwise_param_;
+  eltwise_param_ = NULL;
+  return temp;
+}
+void V1LayerParameter::set_allocated_eltwise_param(::caffe::EltwiseParameter* eltwise_param) {
+  delete eltwise_param_;
+  eltwise_param_ = eltwise_param;
+  if (eltwise_param) {
+    set_has_eltwise_param();
+  } else {
+    clear_has_eltwise_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.V1LayerParameter.eltwise_param)
+}
+
+// optional .caffe.ExpParameter exp_param = 41;
+bool V1LayerParameter::has_exp_param() const {
+  return (_has_bits_[0] & 0x00200000u) != 0;
+}
+void V1LayerParameter::set_has_exp_param() {
+  _has_bits_[0] |= 0x00200000u;
+}
+void V1LayerParameter::clear_has_exp_param() {
+  _has_bits_[0] &= ~0x00200000u;
+}
+void V1LayerParameter::clear_exp_param() {
+  if (exp_param_ != NULL) exp_param_->::caffe::ExpParameter::Clear();
+  clear_has_exp_param();
+}
+const ::caffe::ExpParameter& V1LayerParameter::exp_param() const {
+  // @@protoc_insertion_point(field_get:caffe.V1LayerParameter.exp_param)
+  return exp_param_ != NULL ? *exp_param_
+                         : *::caffe::ExpParameter::internal_default_instance();
+}
+::caffe::ExpParameter* V1LayerParameter::mutable_exp_param() {
+  set_has_exp_param();
+  if (exp_param_ == NULL) {
+    exp_param_ = new ::caffe::ExpParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.V1LayerParameter.exp_param)
+  return exp_param_;
+}
+::caffe::ExpParameter* V1LayerParameter::release_exp_param() {
+  // @@protoc_insertion_point(field_release:caffe.V1LayerParameter.exp_param)
+  clear_has_exp_param();
+  ::caffe::ExpParameter* temp = exp_param_;
+  exp_param_ = NULL;
+  return temp;
+}
+void V1LayerParameter::set_allocated_exp_param(::caffe::ExpParameter* exp_param) {
+  delete exp_param_;
+  exp_param_ = exp_param;
+  if (exp_param) {
+    set_has_exp_param();
+  } else {
+    clear_has_exp_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.V1LayerParameter.exp_param)
+}
+
+// optional .caffe.HDF5DataParameter hdf5_data_param = 13;
+bool V1LayerParameter::has_hdf5_data_param() const {
+  return (_has_bits_[0] & 0x00400000u) != 0;
+}
+void V1LayerParameter::set_has_hdf5_data_param() {
+  _has_bits_[0] |= 0x00400000u;
+}
+void V1LayerParameter::clear_has_hdf5_data_param() {
+  _has_bits_[0] &= ~0x00400000u;
+}
+void V1LayerParameter::clear_hdf5_data_param() {
+  if (hdf5_data_param_ != NULL) hdf5_data_param_->::caffe::HDF5DataParameter::Clear();
+  clear_has_hdf5_data_param();
+}
+const ::caffe::HDF5DataParameter& V1LayerParameter::hdf5_data_param() const {
+  // @@protoc_insertion_point(field_get:caffe.V1LayerParameter.hdf5_data_param)
+  return hdf5_data_param_ != NULL ? *hdf5_data_param_
+                         : *::caffe::HDF5DataParameter::internal_default_instance();
+}
+::caffe::HDF5DataParameter* V1LayerParameter::mutable_hdf5_data_param() {
+  set_has_hdf5_data_param();
+  if (hdf5_data_param_ == NULL) {
+    hdf5_data_param_ = new ::caffe::HDF5DataParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.V1LayerParameter.hdf5_data_param)
+  return hdf5_data_param_;
+}
+::caffe::HDF5DataParameter* V1LayerParameter::release_hdf5_data_param() {
+  // @@protoc_insertion_point(field_release:caffe.V1LayerParameter.hdf5_data_param)
+  clear_has_hdf5_data_param();
+  ::caffe::HDF5DataParameter* temp = hdf5_data_param_;
+  hdf5_data_param_ = NULL;
+  return temp;
+}
+void V1LayerParameter::set_allocated_hdf5_data_param(::caffe::HDF5DataParameter* hdf5_data_param) {
+  delete hdf5_data_param_;
+  hdf5_data_param_ = hdf5_data_param;
+  if (hdf5_data_param) {
+    set_has_hdf5_data_param();
+  } else {
+    clear_has_hdf5_data_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.V1LayerParameter.hdf5_data_param)
+}
+
+// optional .caffe.HDF5OutputParameter hdf5_output_param = 14;
+bool V1LayerParameter::has_hdf5_output_param() const {
+  return (_has_bits_[0] & 0x00800000u) != 0;
+}
+void V1LayerParameter::set_has_hdf5_output_param() {
+  _has_bits_[0] |= 0x00800000u;
+}
+void V1LayerParameter::clear_has_hdf5_output_param() {
+  _has_bits_[0] &= ~0x00800000u;
+}
+void V1LayerParameter::clear_hdf5_output_param() {
+  if (hdf5_output_param_ != NULL) hdf5_output_param_->::caffe::HDF5OutputParameter::Clear();
+  clear_has_hdf5_output_param();
+}
+const ::caffe::HDF5OutputParameter& V1LayerParameter::hdf5_output_param() const {
+  // @@protoc_insertion_point(field_get:caffe.V1LayerParameter.hdf5_output_param)
+  return hdf5_output_param_ != NULL ? *hdf5_output_param_
+                         : *::caffe::HDF5OutputParameter::internal_default_instance();
+}
+::caffe::HDF5OutputParameter* V1LayerParameter::mutable_hdf5_output_param() {
+  set_has_hdf5_output_param();
+  if (hdf5_output_param_ == NULL) {
+    hdf5_output_param_ = new ::caffe::HDF5OutputParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.V1LayerParameter.hdf5_output_param)
+  return hdf5_output_param_;
+}
+::caffe::HDF5OutputParameter* V1LayerParameter::release_hdf5_output_param() {
+  // @@protoc_insertion_point(field_release:caffe.V1LayerParameter.hdf5_output_param)
+  clear_has_hdf5_output_param();
+  ::caffe::HDF5OutputParameter* temp = hdf5_output_param_;
+  hdf5_output_param_ = NULL;
+  return temp;
+}
+void V1LayerParameter::set_allocated_hdf5_output_param(::caffe::HDF5OutputParameter* hdf5_output_param) {
+  delete hdf5_output_param_;
+  hdf5_output_param_ = hdf5_output_param;
+  if (hdf5_output_param) {
+    set_has_hdf5_output_param();
+  } else {
+    clear_has_hdf5_output_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.V1LayerParameter.hdf5_output_param)
+}
+
+// optional .caffe.HingeLossParameter hinge_loss_param = 29;
+bool V1LayerParameter::has_hinge_loss_param() const {
+  return (_has_bits_[0] & 0x01000000u) != 0;
+}
+void V1LayerParameter::set_has_hinge_loss_param() {
+  _has_bits_[0] |= 0x01000000u;
+}
+void V1LayerParameter::clear_has_hinge_loss_param() {
+  _has_bits_[0] &= ~0x01000000u;
+}
+void V1LayerParameter::clear_hinge_loss_param() {
+  if (hinge_loss_param_ != NULL) hinge_loss_param_->::caffe::HingeLossParameter::Clear();
+  clear_has_hinge_loss_param();
+}
+const ::caffe::HingeLossParameter& V1LayerParameter::hinge_loss_param() const {
+  // @@protoc_insertion_point(field_get:caffe.V1LayerParameter.hinge_loss_param)
+  return hinge_loss_param_ != NULL ? *hinge_loss_param_
+                         : *::caffe::HingeLossParameter::internal_default_instance();
+}
+::caffe::HingeLossParameter* V1LayerParameter::mutable_hinge_loss_param() {
+  set_has_hinge_loss_param();
+  if (hinge_loss_param_ == NULL) {
+    hinge_loss_param_ = new ::caffe::HingeLossParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.V1LayerParameter.hinge_loss_param)
+  return hinge_loss_param_;
+}
+::caffe::HingeLossParameter* V1LayerParameter::release_hinge_loss_param() {
+  // @@protoc_insertion_point(field_release:caffe.V1LayerParameter.hinge_loss_param)
+  clear_has_hinge_loss_param();
+  ::caffe::HingeLossParameter* temp = hinge_loss_param_;
+  hinge_loss_param_ = NULL;
+  return temp;
+}
+void V1LayerParameter::set_allocated_hinge_loss_param(::caffe::HingeLossParameter* hinge_loss_param) {
+  delete hinge_loss_param_;
+  hinge_loss_param_ = hinge_loss_param;
+  if (hinge_loss_param) {
+    set_has_hinge_loss_param();
+  } else {
+    clear_has_hinge_loss_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.V1LayerParameter.hinge_loss_param)
+}
+
+// optional .caffe.ImageDataParameter image_data_param = 15;
+bool V1LayerParameter::has_image_data_param() const {
+  return (_has_bits_[0] & 0x02000000u) != 0;
+}
+void V1LayerParameter::set_has_image_data_param() {
+  _has_bits_[0] |= 0x02000000u;
+}
+void V1LayerParameter::clear_has_image_data_param() {
+  _has_bits_[0] &= ~0x02000000u;
+}
+void V1LayerParameter::clear_image_data_param() {
+  if (image_data_param_ != NULL) image_data_param_->::caffe::ImageDataParameter::Clear();
+  clear_has_image_data_param();
+}
+const ::caffe::ImageDataParameter& V1LayerParameter::image_data_param() const {
+  // @@protoc_insertion_point(field_get:caffe.V1LayerParameter.image_data_param)
+  return image_data_param_ != NULL ? *image_data_param_
+                         : *::caffe::ImageDataParameter::internal_default_instance();
+}
+::caffe::ImageDataParameter* V1LayerParameter::mutable_image_data_param() {
+  set_has_image_data_param();
+  if (image_data_param_ == NULL) {
+    image_data_param_ = new ::caffe::ImageDataParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.V1LayerParameter.image_data_param)
+  return image_data_param_;
+}
+::caffe::ImageDataParameter* V1LayerParameter::release_image_data_param() {
+  // @@protoc_insertion_point(field_release:caffe.V1LayerParameter.image_data_param)
+  clear_has_image_data_param();
+  ::caffe::ImageDataParameter* temp = image_data_param_;
+  image_data_param_ = NULL;
+  return temp;
+}
+void V1LayerParameter::set_allocated_image_data_param(::caffe::ImageDataParameter* image_data_param) {
+  delete image_data_param_;
+  image_data_param_ = image_data_param;
+  if (image_data_param) {
+    set_has_image_data_param();
+  } else {
+    clear_has_image_data_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.V1LayerParameter.image_data_param)
+}
+
+// optional .caffe.InfogainLossParameter infogain_loss_param = 16;
+bool V1LayerParameter::has_infogain_loss_param() const {
+  return (_has_bits_[0] & 0x04000000u) != 0;
+}
+void V1LayerParameter::set_has_infogain_loss_param() {
+  _has_bits_[0] |= 0x04000000u;
+}
+void V1LayerParameter::clear_has_infogain_loss_param() {
+  _has_bits_[0] &= ~0x04000000u;
+}
+void V1LayerParameter::clear_infogain_loss_param() {
+  if (infogain_loss_param_ != NULL) infogain_loss_param_->::caffe::InfogainLossParameter::Clear();
+  clear_has_infogain_loss_param();
+}
+const ::caffe::InfogainLossParameter& V1LayerParameter::infogain_loss_param() const {
+  // @@protoc_insertion_point(field_get:caffe.V1LayerParameter.infogain_loss_param)
+  return infogain_loss_param_ != NULL ? *infogain_loss_param_
+                         : *::caffe::InfogainLossParameter::internal_default_instance();
+}
+::caffe::InfogainLossParameter* V1LayerParameter::mutable_infogain_loss_param() {
+  set_has_infogain_loss_param();
+  if (infogain_loss_param_ == NULL) {
+    infogain_loss_param_ = new ::caffe::InfogainLossParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.V1LayerParameter.infogain_loss_param)
+  return infogain_loss_param_;
+}
+::caffe::InfogainLossParameter* V1LayerParameter::release_infogain_loss_param() {
+  // @@protoc_insertion_point(field_release:caffe.V1LayerParameter.infogain_loss_param)
+  clear_has_infogain_loss_param();
+  ::caffe::InfogainLossParameter* temp = infogain_loss_param_;
+  infogain_loss_param_ = NULL;
+  return temp;
+}
+void V1LayerParameter::set_allocated_infogain_loss_param(::caffe::InfogainLossParameter* infogain_loss_param) {
+  delete infogain_loss_param_;
+  infogain_loss_param_ = infogain_loss_param;
+  if (infogain_loss_param) {
+    set_has_infogain_loss_param();
+  } else {
+    clear_has_infogain_loss_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.V1LayerParameter.infogain_loss_param)
+}
+
+// optional .caffe.InnerProductParameter inner_product_param = 17;
+bool V1LayerParameter::has_inner_product_param() const {
+  return (_has_bits_[0] & 0x08000000u) != 0;
+}
+void V1LayerParameter::set_has_inner_product_param() {
+  _has_bits_[0] |= 0x08000000u;
+}
+void V1LayerParameter::clear_has_inner_product_param() {
+  _has_bits_[0] &= ~0x08000000u;
+}
+void V1LayerParameter::clear_inner_product_param() {
+  if (inner_product_param_ != NULL) inner_product_param_->::caffe::InnerProductParameter::Clear();
+  clear_has_inner_product_param();
+}
+const ::caffe::InnerProductParameter& V1LayerParameter::inner_product_param() const {
+  // @@protoc_insertion_point(field_get:caffe.V1LayerParameter.inner_product_param)
+  return inner_product_param_ != NULL ? *inner_product_param_
+                         : *::caffe::InnerProductParameter::internal_default_instance();
+}
+::caffe::InnerProductParameter* V1LayerParameter::mutable_inner_product_param() {
+  set_has_inner_product_param();
+  if (inner_product_param_ == NULL) {
+    inner_product_param_ = new ::caffe::InnerProductParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.V1LayerParameter.inner_product_param)
+  return inner_product_param_;
+}
+::caffe::InnerProductParameter* V1LayerParameter::release_inner_product_param() {
+  // @@protoc_insertion_point(field_release:caffe.V1LayerParameter.inner_product_param)
+  clear_has_inner_product_param();
+  ::caffe::InnerProductParameter* temp = inner_product_param_;
+  inner_product_param_ = NULL;
+  return temp;
+}
+void V1LayerParameter::set_allocated_inner_product_param(::caffe::InnerProductParameter* inner_product_param) {
+  delete inner_product_param_;
+  inner_product_param_ = inner_product_param;
+  if (inner_product_param) {
+    set_has_inner_product_param();
+  } else {
+    clear_has_inner_product_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.V1LayerParameter.inner_product_param)
+}
+
+// optional .caffe.LRNParameter lrn_param = 18;
+bool V1LayerParameter::has_lrn_param() const {
+  return (_has_bits_[0] & 0x10000000u) != 0;
+}
+void V1LayerParameter::set_has_lrn_param() {
+  _has_bits_[0] |= 0x10000000u;
+}
+void V1LayerParameter::clear_has_lrn_param() {
+  _has_bits_[0] &= ~0x10000000u;
+}
+void V1LayerParameter::clear_lrn_param() {
+  if (lrn_param_ != NULL) lrn_param_->::caffe::LRNParameter::Clear();
+  clear_has_lrn_param();
+}
+const ::caffe::LRNParameter& V1LayerParameter::lrn_param() const {
+  // @@protoc_insertion_point(field_get:caffe.V1LayerParameter.lrn_param)
+  return lrn_param_ != NULL ? *lrn_param_
+                         : *::caffe::LRNParameter::internal_default_instance();
+}
+::caffe::LRNParameter* V1LayerParameter::mutable_lrn_param() {
+  set_has_lrn_param();
+  if (lrn_param_ == NULL) {
+    lrn_param_ = new ::caffe::LRNParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.V1LayerParameter.lrn_param)
+  return lrn_param_;
+}
+::caffe::LRNParameter* V1LayerParameter::release_lrn_param() {
+  // @@protoc_insertion_point(field_release:caffe.V1LayerParameter.lrn_param)
+  clear_has_lrn_param();
+  ::caffe::LRNParameter* temp = lrn_param_;
+  lrn_param_ = NULL;
+  return temp;
+}
+void V1LayerParameter::set_allocated_lrn_param(::caffe::LRNParameter* lrn_param) {
+  delete lrn_param_;
+  lrn_param_ = lrn_param;
+  if (lrn_param) {
+    set_has_lrn_param();
+  } else {
+    clear_has_lrn_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.V1LayerParameter.lrn_param)
+}
+
+// optional .caffe.MemoryDataParameter memory_data_param = 22;
+bool V1LayerParameter::has_memory_data_param() const {
+  return (_has_bits_[0] & 0x20000000u) != 0;
+}
+void V1LayerParameter::set_has_memory_data_param() {
+  _has_bits_[0] |= 0x20000000u;
+}
+void V1LayerParameter::clear_has_memory_data_param() {
+  _has_bits_[0] &= ~0x20000000u;
+}
+void V1LayerParameter::clear_memory_data_param() {
+  if (memory_data_param_ != NULL) memory_data_param_->::caffe::MemoryDataParameter::Clear();
+  clear_has_memory_data_param();
+}
+const ::caffe::MemoryDataParameter& V1LayerParameter::memory_data_param() const {
+  // @@protoc_insertion_point(field_get:caffe.V1LayerParameter.memory_data_param)
+  return memory_data_param_ != NULL ? *memory_data_param_
+                         : *::caffe::MemoryDataParameter::internal_default_instance();
+}
+::caffe::MemoryDataParameter* V1LayerParameter::mutable_memory_data_param() {
+  set_has_memory_data_param();
+  if (memory_data_param_ == NULL) {
+    memory_data_param_ = new ::caffe::MemoryDataParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.V1LayerParameter.memory_data_param)
+  return memory_data_param_;
+}
+::caffe::MemoryDataParameter* V1LayerParameter::release_memory_data_param() {
+  // @@protoc_insertion_point(field_release:caffe.V1LayerParameter.memory_data_param)
+  clear_has_memory_data_param();
+  ::caffe::MemoryDataParameter* temp = memory_data_param_;
+  memory_data_param_ = NULL;
+  return temp;
+}
+void V1LayerParameter::set_allocated_memory_data_param(::caffe::MemoryDataParameter* memory_data_param) {
+  delete memory_data_param_;
+  memory_data_param_ = memory_data_param;
+  if (memory_data_param) {
+    set_has_memory_data_param();
+  } else {
+    clear_has_memory_data_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.V1LayerParameter.memory_data_param)
+}
+
+// optional .caffe.MVNParameter mvn_param = 34;
+bool V1LayerParameter::has_mvn_param() const {
+  return (_has_bits_[0] & 0x40000000u) != 0;
+}
+void V1LayerParameter::set_has_mvn_param() {
+  _has_bits_[0] |= 0x40000000u;
+}
+void V1LayerParameter::clear_has_mvn_param() {
+  _has_bits_[0] &= ~0x40000000u;
+}
+void V1LayerParameter::clear_mvn_param() {
+  if (mvn_param_ != NULL) mvn_param_->::caffe::MVNParameter::Clear();
+  clear_has_mvn_param();
+}
+const ::caffe::MVNParameter& V1LayerParameter::mvn_param() const {
+  // @@protoc_insertion_point(field_get:caffe.V1LayerParameter.mvn_param)
+  return mvn_param_ != NULL ? *mvn_param_
+                         : *::caffe::MVNParameter::internal_default_instance();
+}
+::caffe::MVNParameter* V1LayerParameter::mutable_mvn_param() {
+  set_has_mvn_param();
+  if (mvn_param_ == NULL) {
+    mvn_param_ = new ::caffe::MVNParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.V1LayerParameter.mvn_param)
+  return mvn_param_;
+}
+::caffe::MVNParameter* V1LayerParameter::release_mvn_param() {
+  // @@protoc_insertion_point(field_release:caffe.V1LayerParameter.mvn_param)
+  clear_has_mvn_param();
+  ::caffe::MVNParameter* temp = mvn_param_;
+  mvn_param_ = NULL;
+  return temp;
+}
+void V1LayerParameter::set_allocated_mvn_param(::caffe::MVNParameter* mvn_param) {
+  delete mvn_param_;
+  mvn_param_ = mvn_param;
+  if (mvn_param) {
+    set_has_mvn_param();
+  } else {
+    clear_has_mvn_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.V1LayerParameter.mvn_param)
+}
+
+// optional .caffe.PoolingParameter pooling_param = 19;
+bool V1LayerParameter::has_pooling_param() const {
+  return (_has_bits_[0] & 0x80000000u) != 0;
+}
+void V1LayerParameter::set_has_pooling_param() {
+  _has_bits_[0] |= 0x80000000u;
+}
+void V1LayerParameter::clear_has_pooling_param() {
+  _has_bits_[0] &= ~0x80000000u;
+}
+void V1LayerParameter::clear_pooling_param() {
+  if (pooling_param_ != NULL) pooling_param_->::caffe::PoolingParameter::Clear();
+  clear_has_pooling_param();
+}
+const ::caffe::PoolingParameter& V1LayerParameter::pooling_param() const {
+  // @@protoc_insertion_point(field_get:caffe.V1LayerParameter.pooling_param)
+  return pooling_param_ != NULL ? *pooling_param_
+                         : *::caffe::PoolingParameter::internal_default_instance();
+}
+::caffe::PoolingParameter* V1LayerParameter::mutable_pooling_param() {
+  set_has_pooling_param();
+  if (pooling_param_ == NULL) {
+    pooling_param_ = new ::caffe::PoolingParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.V1LayerParameter.pooling_param)
+  return pooling_param_;
+}
+::caffe::PoolingParameter* V1LayerParameter::release_pooling_param() {
+  // @@protoc_insertion_point(field_release:caffe.V1LayerParameter.pooling_param)
+  clear_has_pooling_param();
+  ::caffe::PoolingParameter* temp = pooling_param_;
+  pooling_param_ = NULL;
+  return temp;
+}
+void V1LayerParameter::set_allocated_pooling_param(::caffe::PoolingParameter* pooling_param) {
+  delete pooling_param_;
+  pooling_param_ = pooling_param;
+  if (pooling_param) {
+    set_has_pooling_param();
+  } else {
+    clear_has_pooling_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.V1LayerParameter.pooling_param)
+}
+
+// optional .caffe.PowerParameter power_param = 21;
+bool V1LayerParameter::has_power_param() const {
+  return (_has_bits_[1] & 0x00000001u) != 0;
+}
+void V1LayerParameter::set_has_power_param() {
+  _has_bits_[1] |= 0x00000001u;
+}
+void V1LayerParameter::clear_has_power_param() {
+  _has_bits_[1] &= ~0x00000001u;
+}
+void V1LayerParameter::clear_power_param() {
+  if (power_param_ != NULL) power_param_->::caffe::PowerParameter::Clear();
+  clear_has_power_param();
+}
+const ::caffe::PowerParameter& V1LayerParameter::power_param() const {
+  // @@protoc_insertion_point(field_get:caffe.V1LayerParameter.power_param)
+  return power_param_ != NULL ? *power_param_
+                         : *::caffe::PowerParameter::internal_default_instance();
+}
+::caffe::PowerParameter* V1LayerParameter::mutable_power_param() {
+  set_has_power_param();
+  if (power_param_ == NULL) {
+    power_param_ = new ::caffe::PowerParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.V1LayerParameter.power_param)
+  return power_param_;
+}
+::caffe::PowerParameter* V1LayerParameter::release_power_param() {
+  // @@protoc_insertion_point(field_release:caffe.V1LayerParameter.power_param)
+  clear_has_power_param();
+  ::caffe::PowerParameter* temp = power_param_;
+  power_param_ = NULL;
+  return temp;
+}
+void V1LayerParameter::set_allocated_power_param(::caffe::PowerParameter* power_param) {
+  delete power_param_;
+  power_param_ = power_param;
+  if (power_param) {
+    set_has_power_param();
+  } else {
+    clear_has_power_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.V1LayerParameter.power_param)
+}
+
+// optional .caffe.ReLUParameter relu_param = 30;
+bool V1LayerParameter::has_relu_param() const {
+  return (_has_bits_[1] & 0x00000002u) != 0;
+}
+void V1LayerParameter::set_has_relu_param() {
+  _has_bits_[1] |= 0x00000002u;
+}
+void V1LayerParameter::clear_has_relu_param() {
+  _has_bits_[1] &= ~0x00000002u;
+}
+void V1LayerParameter::clear_relu_param() {
+  if (relu_param_ != NULL) relu_param_->::caffe::ReLUParameter::Clear();
+  clear_has_relu_param();
+}
+const ::caffe::ReLUParameter& V1LayerParameter::relu_param() const {
+  // @@protoc_insertion_point(field_get:caffe.V1LayerParameter.relu_param)
+  return relu_param_ != NULL ? *relu_param_
+                         : *::caffe::ReLUParameter::internal_default_instance();
+}
+::caffe::ReLUParameter* V1LayerParameter::mutable_relu_param() {
+  set_has_relu_param();
+  if (relu_param_ == NULL) {
+    relu_param_ = new ::caffe::ReLUParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.V1LayerParameter.relu_param)
+  return relu_param_;
+}
+::caffe::ReLUParameter* V1LayerParameter::release_relu_param() {
+  // @@protoc_insertion_point(field_release:caffe.V1LayerParameter.relu_param)
+  clear_has_relu_param();
+  ::caffe::ReLUParameter* temp = relu_param_;
+  relu_param_ = NULL;
+  return temp;
+}
+void V1LayerParameter::set_allocated_relu_param(::caffe::ReLUParameter* relu_param) {
+  delete relu_param_;
+  relu_param_ = relu_param;
+  if (relu_param) {
+    set_has_relu_param();
+  } else {
+    clear_has_relu_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.V1LayerParameter.relu_param)
+}
+
+// optional .caffe.SigmoidParameter sigmoid_param = 38;
+bool V1LayerParameter::has_sigmoid_param() const {
+  return (_has_bits_[1] & 0x00000004u) != 0;
+}
+void V1LayerParameter::set_has_sigmoid_param() {
+  _has_bits_[1] |= 0x00000004u;
+}
+void V1LayerParameter::clear_has_sigmoid_param() {
+  _has_bits_[1] &= ~0x00000004u;
+}
+void V1LayerParameter::clear_sigmoid_param() {
+  if (sigmoid_param_ != NULL) sigmoid_param_->::caffe::SigmoidParameter::Clear();
+  clear_has_sigmoid_param();
+}
+const ::caffe::SigmoidParameter& V1LayerParameter::sigmoid_param() const {
+  // @@protoc_insertion_point(field_get:caffe.V1LayerParameter.sigmoid_param)
+  return sigmoid_param_ != NULL ? *sigmoid_param_
+                         : *::caffe::SigmoidParameter::internal_default_instance();
+}
+::caffe::SigmoidParameter* V1LayerParameter::mutable_sigmoid_param() {
+  set_has_sigmoid_param();
+  if (sigmoid_param_ == NULL) {
+    sigmoid_param_ = new ::caffe::SigmoidParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.V1LayerParameter.sigmoid_param)
+  return sigmoid_param_;
+}
+::caffe::SigmoidParameter* V1LayerParameter::release_sigmoid_param() {
+  // @@protoc_insertion_point(field_release:caffe.V1LayerParameter.sigmoid_param)
+  clear_has_sigmoid_param();
+  ::caffe::SigmoidParameter* temp = sigmoid_param_;
+  sigmoid_param_ = NULL;
+  return temp;
+}
+void V1LayerParameter::set_allocated_sigmoid_param(::caffe::SigmoidParameter* sigmoid_param) {
+  delete sigmoid_param_;
+  sigmoid_param_ = sigmoid_param;
+  if (sigmoid_param) {
+    set_has_sigmoid_param();
+  } else {
+    clear_has_sigmoid_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.V1LayerParameter.sigmoid_param)
+}
+
+// optional .caffe.SoftmaxParameter softmax_param = 39;
+bool V1LayerParameter::has_softmax_param() const {
+  return (_has_bits_[1] & 0x00000008u) != 0;
+}
+void V1LayerParameter::set_has_softmax_param() {
+  _has_bits_[1] |= 0x00000008u;
+}
+void V1LayerParameter::clear_has_softmax_param() {
+  _has_bits_[1] &= ~0x00000008u;
+}
+void V1LayerParameter::clear_softmax_param() {
+  if (softmax_param_ != NULL) softmax_param_->::caffe::SoftmaxParameter::Clear();
+  clear_has_softmax_param();
+}
+const ::caffe::SoftmaxParameter& V1LayerParameter::softmax_param() const {
+  // @@protoc_insertion_point(field_get:caffe.V1LayerParameter.softmax_param)
+  return softmax_param_ != NULL ? *softmax_param_
+                         : *::caffe::SoftmaxParameter::internal_default_instance();
+}
+::caffe::SoftmaxParameter* V1LayerParameter::mutable_softmax_param() {
+  set_has_softmax_param();
+  if (softmax_param_ == NULL) {
+    softmax_param_ = new ::caffe::SoftmaxParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.V1LayerParameter.softmax_param)
+  return softmax_param_;
+}
+::caffe::SoftmaxParameter* V1LayerParameter::release_softmax_param() {
+  // @@protoc_insertion_point(field_release:caffe.V1LayerParameter.softmax_param)
+  clear_has_softmax_param();
+  ::caffe::SoftmaxParameter* temp = softmax_param_;
+  softmax_param_ = NULL;
+  return temp;
+}
+void V1LayerParameter::set_allocated_softmax_param(::caffe::SoftmaxParameter* softmax_param) {
+  delete softmax_param_;
+  softmax_param_ = softmax_param;
+  if (softmax_param) {
+    set_has_softmax_param();
+  } else {
+    clear_has_softmax_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.V1LayerParameter.softmax_param)
+}
+
+// optional .caffe.SliceParameter slice_param = 31;
+bool V1LayerParameter::has_slice_param() const {
+  return (_has_bits_[1] & 0x00000010u) != 0;
+}
+void V1LayerParameter::set_has_slice_param() {
+  _has_bits_[1] |= 0x00000010u;
+}
+void V1LayerParameter::clear_has_slice_param() {
+  _has_bits_[1] &= ~0x00000010u;
+}
+void V1LayerParameter::clear_slice_param() {
+  if (slice_param_ != NULL) slice_param_->::caffe::SliceParameter::Clear();
+  clear_has_slice_param();
+}
+const ::caffe::SliceParameter& V1LayerParameter::slice_param() const {
+  // @@protoc_insertion_point(field_get:caffe.V1LayerParameter.slice_param)
+  return slice_param_ != NULL ? *slice_param_
+                         : *::caffe::SliceParameter::internal_default_instance();
+}
+::caffe::SliceParameter* V1LayerParameter::mutable_slice_param() {
+  set_has_slice_param();
+  if (slice_param_ == NULL) {
+    slice_param_ = new ::caffe::SliceParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.V1LayerParameter.slice_param)
+  return slice_param_;
+}
+::caffe::SliceParameter* V1LayerParameter::release_slice_param() {
+  // @@protoc_insertion_point(field_release:caffe.V1LayerParameter.slice_param)
+  clear_has_slice_param();
+  ::caffe::SliceParameter* temp = slice_param_;
+  slice_param_ = NULL;
+  return temp;
+}
+void V1LayerParameter::set_allocated_slice_param(::caffe::SliceParameter* slice_param) {
+  delete slice_param_;
+  slice_param_ = slice_param;
+  if (slice_param) {
+    set_has_slice_param();
+  } else {
+    clear_has_slice_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.V1LayerParameter.slice_param)
+}
+
+// optional .caffe.TanHParameter tanh_param = 37;
+bool V1LayerParameter::has_tanh_param() const {
+  return (_has_bits_[1] & 0x00000020u) != 0;
+}
+void V1LayerParameter::set_has_tanh_param() {
+  _has_bits_[1] |= 0x00000020u;
+}
+void V1LayerParameter::clear_has_tanh_param() {
+  _has_bits_[1] &= ~0x00000020u;
+}
+void V1LayerParameter::clear_tanh_param() {
+  if (tanh_param_ != NULL) tanh_param_->::caffe::TanHParameter::Clear();
+  clear_has_tanh_param();
+}
+const ::caffe::TanHParameter& V1LayerParameter::tanh_param() const {
+  // @@protoc_insertion_point(field_get:caffe.V1LayerParameter.tanh_param)
+  return tanh_param_ != NULL ? *tanh_param_
+                         : *::caffe::TanHParameter::internal_default_instance();
+}
+::caffe::TanHParameter* V1LayerParameter::mutable_tanh_param() {
+  set_has_tanh_param();
+  if (tanh_param_ == NULL) {
+    tanh_param_ = new ::caffe::TanHParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.V1LayerParameter.tanh_param)
+  return tanh_param_;
+}
+::caffe::TanHParameter* V1LayerParameter::release_tanh_param() {
+  // @@protoc_insertion_point(field_release:caffe.V1LayerParameter.tanh_param)
+  clear_has_tanh_param();
+  ::caffe::TanHParameter* temp = tanh_param_;
+  tanh_param_ = NULL;
+  return temp;
+}
+void V1LayerParameter::set_allocated_tanh_param(::caffe::TanHParameter* tanh_param) {
+  delete tanh_param_;
+  tanh_param_ = tanh_param;
+  if (tanh_param) {
+    set_has_tanh_param();
+  } else {
+    clear_has_tanh_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.V1LayerParameter.tanh_param)
+}
+
+// optional .caffe.ThresholdParameter threshold_param = 25;
+bool V1LayerParameter::has_threshold_param() const {
+  return (_has_bits_[1] & 0x00000040u) != 0;
+}
+void V1LayerParameter::set_has_threshold_param() {
+  _has_bits_[1] |= 0x00000040u;
+}
+void V1LayerParameter::clear_has_threshold_param() {
+  _has_bits_[1] &= ~0x00000040u;
+}
+void V1LayerParameter::clear_threshold_param() {
+  if (threshold_param_ != NULL) threshold_param_->::caffe::ThresholdParameter::Clear();
+  clear_has_threshold_param();
+}
+const ::caffe::ThresholdParameter& V1LayerParameter::threshold_param() const {
+  // @@protoc_insertion_point(field_get:caffe.V1LayerParameter.threshold_param)
+  return threshold_param_ != NULL ? *threshold_param_
+                         : *::caffe::ThresholdParameter::internal_default_instance();
+}
+::caffe::ThresholdParameter* V1LayerParameter::mutable_threshold_param() {
+  set_has_threshold_param();
+  if (threshold_param_ == NULL) {
+    threshold_param_ = new ::caffe::ThresholdParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.V1LayerParameter.threshold_param)
+  return threshold_param_;
+}
+::caffe::ThresholdParameter* V1LayerParameter::release_threshold_param() {
+  // @@protoc_insertion_point(field_release:caffe.V1LayerParameter.threshold_param)
+  clear_has_threshold_param();
+  ::caffe::ThresholdParameter* temp = threshold_param_;
+  threshold_param_ = NULL;
+  return temp;
+}
+void V1LayerParameter::set_allocated_threshold_param(::caffe::ThresholdParameter* threshold_param) {
+  delete threshold_param_;
+  threshold_param_ = threshold_param;
+  if (threshold_param) {
+    set_has_threshold_param();
+  } else {
+    clear_has_threshold_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.V1LayerParameter.threshold_param)
+}
+
+// optional .caffe.WindowDataParameter window_data_param = 20;
+bool V1LayerParameter::has_window_data_param() const {
+  return (_has_bits_[1] & 0x00000080u) != 0;
+}
+void V1LayerParameter::set_has_window_data_param() {
+  _has_bits_[1] |= 0x00000080u;
+}
+void V1LayerParameter::clear_has_window_data_param() {
+  _has_bits_[1] &= ~0x00000080u;
+}
+void V1LayerParameter::clear_window_data_param() {
+  if (window_data_param_ != NULL) window_data_param_->::caffe::WindowDataParameter::Clear();
+  clear_has_window_data_param();
+}
+const ::caffe::WindowDataParameter& V1LayerParameter::window_data_param() const {
+  // @@protoc_insertion_point(field_get:caffe.V1LayerParameter.window_data_param)
+  return window_data_param_ != NULL ? *window_data_param_
+                         : *::caffe::WindowDataParameter::internal_default_instance();
+}
+::caffe::WindowDataParameter* V1LayerParameter::mutable_window_data_param() {
+  set_has_window_data_param();
+  if (window_data_param_ == NULL) {
+    window_data_param_ = new ::caffe::WindowDataParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.V1LayerParameter.window_data_param)
+  return window_data_param_;
+}
+::caffe::WindowDataParameter* V1LayerParameter::release_window_data_param() {
+  // @@protoc_insertion_point(field_release:caffe.V1LayerParameter.window_data_param)
+  clear_has_window_data_param();
+  ::caffe::WindowDataParameter* temp = window_data_param_;
+  window_data_param_ = NULL;
+  return temp;
+}
+void V1LayerParameter::set_allocated_window_data_param(::caffe::WindowDataParameter* window_data_param) {
+  delete window_data_param_;
+  window_data_param_ = window_data_param;
+  if (window_data_param) {
+    set_has_window_data_param();
+  } else {
+    clear_has_window_data_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.V1LayerParameter.window_data_param)
+}
+
+// optional .caffe.TransformationParameter transform_param = 36;
+bool V1LayerParameter::has_transform_param() const {
+  return (_has_bits_[1] & 0x00000100u) != 0;
+}
+void V1LayerParameter::set_has_transform_param() {
+  _has_bits_[1] |= 0x00000100u;
+}
+void V1LayerParameter::clear_has_transform_param() {
+  _has_bits_[1] &= ~0x00000100u;
+}
+void V1LayerParameter::clear_transform_param() {
+  if (transform_param_ != NULL) transform_param_->::caffe::TransformationParameter::Clear();
+  clear_has_transform_param();
+}
+const ::caffe::TransformationParameter& V1LayerParameter::transform_param() const {
+  // @@protoc_insertion_point(field_get:caffe.V1LayerParameter.transform_param)
+  return transform_param_ != NULL ? *transform_param_
+                         : *::caffe::TransformationParameter::internal_default_instance();
+}
+::caffe::TransformationParameter* V1LayerParameter::mutable_transform_param() {
+  set_has_transform_param();
+  if (transform_param_ == NULL) {
+    transform_param_ = new ::caffe::TransformationParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.V1LayerParameter.transform_param)
+  return transform_param_;
+}
+::caffe::TransformationParameter* V1LayerParameter::release_transform_param() {
+  // @@protoc_insertion_point(field_release:caffe.V1LayerParameter.transform_param)
+  clear_has_transform_param();
+  ::caffe::TransformationParameter* temp = transform_param_;
+  transform_param_ = NULL;
+  return temp;
+}
+void V1LayerParameter::set_allocated_transform_param(::caffe::TransformationParameter* transform_param) {
+  delete transform_param_;
+  transform_param_ = transform_param;
+  if (transform_param) {
+    set_has_transform_param();
+  } else {
+    clear_has_transform_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.V1LayerParameter.transform_param)
+}
+
+// optional .caffe.LossParameter loss_param = 42;
+bool V1LayerParameter::has_loss_param() const {
+  return (_has_bits_[1] & 0x00000200u) != 0;
+}
+void V1LayerParameter::set_has_loss_param() {
+  _has_bits_[1] |= 0x00000200u;
+}
+void V1LayerParameter::clear_has_loss_param() {
+  _has_bits_[1] &= ~0x00000200u;
+}
+void V1LayerParameter::clear_loss_param() {
+  if (loss_param_ != NULL) loss_param_->::caffe::LossParameter::Clear();
+  clear_has_loss_param();
+}
+const ::caffe::LossParameter& V1LayerParameter::loss_param() const {
+  // @@protoc_insertion_point(field_get:caffe.V1LayerParameter.loss_param)
+  return loss_param_ != NULL ? *loss_param_
+                         : *::caffe::LossParameter::internal_default_instance();
+}
+::caffe::LossParameter* V1LayerParameter::mutable_loss_param() {
+  set_has_loss_param();
+  if (loss_param_ == NULL) {
+    loss_param_ = new ::caffe::LossParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.V1LayerParameter.loss_param)
+  return loss_param_;
+}
+::caffe::LossParameter* V1LayerParameter::release_loss_param() {
+  // @@protoc_insertion_point(field_release:caffe.V1LayerParameter.loss_param)
+  clear_has_loss_param();
+  ::caffe::LossParameter* temp = loss_param_;
+  loss_param_ = NULL;
+  return temp;
+}
+void V1LayerParameter::set_allocated_loss_param(::caffe::LossParameter* loss_param) {
+  delete loss_param_;
+  loss_param_ = loss_param;
+  if (loss_param) {
+    set_has_loss_param();
+  } else {
+    clear_has_loss_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.V1LayerParameter.loss_param)
+}
+
+// optional .caffe.V0LayerParameter layer = 1;
+bool V1LayerParameter::has_layer() const {
+  return (_has_bits_[1] & 0x00000400u) != 0;
+}
+void V1LayerParameter::set_has_layer() {
+  _has_bits_[1] |= 0x00000400u;
+}
+void V1LayerParameter::clear_has_layer() {
+  _has_bits_[1] &= ~0x00000400u;
+}
+void V1LayerParameter::clear_layer() {
+  if (layer_ != NULL) layer_->::caffe::V0LayerParameter::Clear();
+  clear_has_layer();
+}
+const ::caffe::V0LayerParameter& V1LayerParameter::layer() const {
+  // @@protoc_insertion_point(field_get:caffe.V1LayerParameter.layer)
+  return layer_ != NULL ? *layer_
+                         : *::caffe::V0LayerParameter::internal_default_instance();
+}
+::caffe::V0LayerParameter* V1LayerParameter::mutable_layer() {
+  set_has_layer();
+  if (layer_ == NULL) {
+    layer_ = new ::caffe::V0LayerParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.V1LayerParameter.layer)
+  return layer_;
+}
+::caffe::V0LayerParameter* V1LayerParameter::release_layer() {
+  // @@protoc_insertion_point(field_release:caffe.V1LayerParameter.layer)
+  clear_has_layer();
+  ::caffe::V0LayerParameter* temp = layer_;
+  layer_ = NULL;
+  return temp;
+}
+void V1LayerParameter::set_allocated_layer(::caffe::V0LayerParameter* layer) {
+  delete layer_;
+  layer_ = layer;
+  if (layer) {
+    set_has_layer();
+  } else {
+    clear_has_layer();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.V1LayerParameter.layer)
+}
+
+inline const V1LayerParameter* V1LayerParameter::internal_default_instance() {
+  return &V1LayerParameter_default_instance_.get();
+}
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
+
+// ===================================================================
+
+const ::google::protobuf::EnumDescriptor* V0LayerParameter_PoolMethod_descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return V0LayerParameter_PoolMethod_descriptor_;
+}
+bool V0LayerParameter_PoolMethod_IsValid(int value) {
+  switch (value) {
+    case 0:
+    case 1:
+    case 2:
+      return true;
+    default:
+      return false;
+  }
+}
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const V0LayerParameter_PoolMethod V0LayerParameter::MAX;
+const V0LayerParameter_PoolMethod V0LayerParameter::AVE;
+const V0LayerParameter_PoolMethod V0LayerParameter::STOCHASTIC;
+const V0LayerParameter_PoolMethod V0LayerParameter::PoolMethod_MIN;
+const V0LayerParameter_PoolMethod V0LayerParameter::PoolMethod_MAX;
+const int V0LayerParameter::PoolMethod_ARRAYSIZE;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+::std::string* V0LayerParameter::_default_det_crop_mode_ = NULL;
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const int V0LayerParameter::kNameFieldNumber;
+const int V0LayerParameter::kTypeFieldNumber;
+const int V0LayerParameter::kNumOutputFieldNumber;
+const int V0LayerParameter::kBiastermFieldNumber;
+const int V0LayerParameter::kWeightFillerFieldNumber;
+const int V0LayerParameter::kBiasFillerFieldNumber;
+const int V0LayerParameter::kPadFieldNumber;
+const int V0LayerParameter::kKernelsizeFieldNumber;
+const int V0LayerParameter::kGroupFieldNumber;
+const int V0LayerParameter::kStrideFieldNumber;
+const int V0LayerParameter::kPoolFieldNumber;
+const int V0LayerParameter::kDropoutRatioFieldNumber;
+const int V0LayerParameter::kLocalSizeFieldNumber;
+const int V0LayerParameter::kAlphaFieldNumber;
+const int V0LayerParameter::kBetaFieldNumber;
+const int V0LayerParameter::kKFieldNumber;
+const int V0LayerParameter::kSourceFieldNumber;
+const int V0LayerParameter::kScaleFieldNumber;
+const int V0LayerParameter::kMeanfileFieldNumber;
+const int V0LayerParameter::kBatchsizeFieldNumber;
+const int V0LayerParameter::kCropsizeFieldNumber;
+const int V0LayerParameter::kMirrorFieldNumber;
+const int V0LayerParameter::kBlobsFieldNumber;
+const int V0LayerParameter::kBlobsLrFieldNumber;
+const int V0LayerParameter::kWeightDecayFieldNumber;
+const int V0LayerParameter::kRandSkipFieldNumber;
+const int V0LayerParameter::kDetFgThresholdFieldNumber;
+const int V0LayerParameter::kDetBgThresholdFieldNumber;
+const int V0LayerParameter::kDetFgFractionFieldNumber;
+const int V0LayerParameter::kDetContextPadFieldNumber;
+const int V0LayerParameter::kDetCropModeFieldNumber;
+const int V0LayerParameter::kNewNumFieldNumber;
+const int V0LayerParameter::kNewChannelsFieldNumber;
+const int V0LayerParameter::kNewHeightFieldNumber;
+const int V0LayerParameter::kNewWidthFieldNumber;
+const int V0LayerParameter::kShuffleImagesFieldNumber;
+const int V0LayerParameter::kConcatDimFieldNumber;
+const int V0LayerParameter::kHdf5OutputParamFieldNumber;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+
+V0LayerParameter::V0LayerParameter()
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+  if (this != internal_default_instance()) protobuf_InitDefaults_caffe_2eproto();
+  SharedCtor();
+  // @@protoc_insertion_point(constructor:caffe.V0LayerParameter)
+}
+
+void V0LayerParameter::InitAsDefaultInstance() {
+  weight_filler_ = const_cast< ::caffe::FillerParameter*>(
+      ::caffe::FillerParameter::internal_default_instance());
+  bias_filler_ = const_cast< ::caffe::FillerParameter*>(
+      ::caffe::FillerParameter::internal_default_instance());
+  hdf5_output_param_ = const_cast< ::caffe::HDF5OutputParameter*>(
+      ::caffe::HDF5OutputParameter::internal_default_instance());
+}
+
+V0LayerParameter::V0LayerParameter(const V0LayerParameter& from)
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
+  SharedCtor();
+  UnsafeMergeFrom(from);
+  // @@protoc_insertion_point(copy_constructor:caffe.V0LayerParameter)
+}
+
+void V0LayerParameter::SharedCtor() {
+  name_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  type_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  source_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  meanfile_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  det_crop_mode_.UnsafeSetDefault(_default_det_crop_mode_);
+  weight_filler_ = NULL;
+  bias_filler_ = NULL;
+  hdf5_output_param_ = NULL;
+  ::memset(&num_output_, 0, reinterpret_cast<char*>(&new_width_) -
+    reinterpret_cast<char*>(&num_output_) + sizeof(new_width_));
+  concat_dim_ = 1u;
+  biasterm_ = true;
+  group_ = 1u;
+  stride_ = 1u;
+  dropout_ratio_ = 0.5f;
+  local_size_ = 5u;
+  alpha_ = 1;
+  beta_ = 0.75f;
+  k_ = 1;
+  scale_ = 1;
+  det_fg_threshold_ = 0.5f;
+  det_bg_threshold_ = 0.5f;
+  det_fg_fraction_ = 0.25f;
+  _cached_size_ = 0;
+}
+
+V0LayerParameter::~V0LayerParameter() {
+  // @@protoc_insertion_point(destructor:caffe.V0LayerParameter)
+  SharedDtor();
+}
+
+void V0LayerParameter::SharedDtor() {
+  name_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  type_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  source_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  meanfile_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  det_crop_mode_.DestroyNoArena(_default_det_crop_mode_);
+  if (this != &V0LayerParameter_default_instance_.get()) {
+    delete weight_filler_;
+    delete bias_filler_;
+    delete hdf5_output_param_;
+  }
+}
+
+void V0LayerParameter::SetCachedSize(int size) const {
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* V0LayerParameter::descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return V0LayerParameter_descriptor_;
+}
+
+const V0LayerParameter& V0LayerParameter::default_instance() {
+  protobuf_InitDefaults_caffe_2eproto();
+  return *internal_default_instance();
+}
+
+::google::protobuf::internal::ExplicitlyConstructed<V0LayerParameter> V0LayerParameter_default_instance_;
+
+V0LayerParameter* V0LayerParameter::New(::google::protobuf::Arena* arena) const {
+  V0LayerParameter* n = new V0LayerParameter;
+  if (arena != NULL) {
+    arena->Own(n);
+  }
+  return n;
+}
+
+void V0LayerParameter::Clear() {
+// @@protoc_insertion_point(message_clear_start:caffe.V0LayerParameter)
+#if defined(__clang__)
+#define ZR_HELPER_(f) \
+  _Pragma("clang diagnostic push") \
+  _Pragma("clang diagnostic ignored \"-Winvalid-offsetof\"") \
+  __builtin_offsetof(V0LayerParameter, f) \
+  _Pragma("clang diagnostic pop")
+#else
+#define ZR_HELPER_(f) reinterpret_cast<char*>(\
+  &reinterpret_cast<V0LayerParameter*>(16)->f)
+#endif
+
+#define ZR_(first, last) do {\
+  ::memset(&(first), 0,\
+           ZR_HELPER_(last) - ZR_HELPER_(first) + sizeof(last));\
+} while (0)
+
+  if (_has_bits_[0 / 32] & 255u) {
+    ZR_(num_output_, kernelsize_);
+    if (has_name()) {
+      name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+    }
+    if (has_type()) {
+      type_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+    }
+    biasterm_ = true;
+    if (has_weight_filler()) {
+      if (weight_filler_ != NULL) weight_filler_->::caffe::FillerParameter::Clear();
+    }
+    if (has_bias_filler()) {
+      if (bias_filler_ != NULL) bias_filler_->::caffe::FillerParameter::Clear();
+    }
+  }
+  if (_has_bits_[8 / 32] & 65280u) {
+    group_ = 1u;
+    stride_ = 1u;
+    pool_ = 0;
+    dropout_ratio_ = 0.5f;
+    local_size_ = 5u;
+    alpha_ = 1;
+    beta_ = 0.75f;
+    k_ = 1;
+  }
+  if (_has_bits_[16 / 32] & 4128768u) {
+    ZR_(batchsize_, cropsize_);
+    if (has_source()) {
+      source_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+    }
+    scale_ = 1;
+    if (has_meanfile()) {
+      meanfile_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+    }
+    mirror_ = false;
+  }
+  if (_has_bits_[24 / 32] & 4261412864u) {
+    ZR_(det_context_pad_, new_num_);
+    rand_skip_ = 0u;
+    det_fg_threshold_ = 0.5f;
+    det_bg_threshold_ = 0.5f;
+    det_fg_fraction_ = 0.25f;
+    if (has_det_crop_mode()) {
+      det_crop_mode_.ClearToDefaultNoArena(_default_det_crop_mode_);
+    }
+  }
+  if (_has_bits_[32 / 32] & 63u) {
+    ZR_(new_channels_, new_width_);
+    shuffle_images_ = false;
+    concat_dim_ = 1u;
+    if (has_hdf5_output_param()) {
+      if (hdf5_output_param_ != NULL) hdf5_output_param_->::caffe::HDF5OutputParameter::Clear();
+    }
+  }
+
+#undef ZR_HELPER_
+#undef ZR_
+
+  blobs_.Clear();
+  blobs_lr_.Clear();
+  weight_decay_.Clear();
+  _has_bits_.Clear();
+  if (_internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->Clear();
+  }
+}
+
+bool V0LayerParameter::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
+  ::google::protobuf::uint32 tag;
+  // @@protoc_insertion_point(parse_start:caffe.V0LayerParameter)
+  for (;;) {
+    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(16383);
+    tag = p.first;
+    if (!p.second) goto handle_unusual;
+    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+      // optional string name = 1;
+      case 1: {
+        if (tag == 10) {
+          DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+                input, this->mutable_name()));
+          ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+            this->name().data(), this->name().length(),
+            ::google::protobuf::internal::WireFormat::PARSE,
+            "caffe.V0LayerParameter.name");
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(18)) goto parse_type;
+        break;
+      }
+
+      // optional string type = 2;
+      case 2: {
+        if (tag == 18) {
+         parse_type:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+                input, this->mutable_type()));
+          ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+            this->type().data(), this->type().length(),
+            ::google::protobuf::internal::WireFormat::PARSE,
+            "caffe.V0LayerParameter.type");
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(24)) goto parse_num_output;
+        break;
+      }
+
+      // optional uint32 num_output = 3;
+      case 3: {
+        if (tag == 24) {
+         parse_num_output:
+          set_has_num_output();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>(
+                 input, &num_output_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(32)) goto parse_biasterm;
+        break;
+      }
+
+      // optional bool biasterm = 4 [default = true];
+      case 4: {
+        if (tag == 32) {
+         parse_biasterm:
+          set_has_biasterm();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>(
+                 input, &biasterm_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(42)) goto parse_weight_filler;
+        break;
+      }
+
+      // optional .caffe.FillerParameter weight_filler = 5;
+      case 5: {
+        if (tag == 42) {
+         parse_weight_filler:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+               input, mutable_weight_filler()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(50)) goto parse_bias_filler;
+        break;
+      }
+
+      // optional .caffe.FillerParameter bias_filler = 6;
+      case 6: {
+        if (tag == 50) {
+         parse_bias_filler:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+               input, mutable_bias_filler()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(56)) goto parse_pad;
+        break;
+      }
+
+      // optional uint32 pad = 7 [default = 0];
+      case 7: {
+        if (tag == 56) {
+         parse_pad:
+          set_has_pad();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>(
+                 input, &pad_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(64)) goto parse_kernelsize;
+        break;
+      }
+
+      // optional uint32 kernelsize = 8;
+      case 8: {
+        if (tag == 64) {
+         parse_kernelsize:
+          set_has_kernelsize();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>(
+                 input, &kernelsize_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(72)) goto parse_group;
+        break;
+      }
+
+      // optional uint32 group = 9 [default = 1];
+      case 9: {
+        if (tag == 72) {
+         parse_group:
+          set_has_group();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>(
+                 input, &group_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(80)) goto parse_stride;
+        break;
+      }
+
+      // optional uint32 stride = 10 [default = 1];
+      case 10: {
+        if (tag == 80) {
+         parse_stride:
+          set_has_stride();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>(
+                 input, &stride_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(88)) goto parse_pool;
+        break;
+      }
+
+      // optional .caffe.V0LayerParameter.PoolMethod pool = 11 [default = MAX];
+      case 11: {
+        if (tag == 88) {
+         parse_pool:
+          int value;
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>(
+                 input, &value)));
+          if (::caffe::V0LayerParameter_PoolMethod_IsValid(value)) {
+            set_pool(static_cast< ::caffe::V0LayerParameter_PoolMethod >(value));
+          } else {
+            mutable_unknown_fields()->AddVarint(11, value);
+          }
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(101)) goto parse_dropout_ratio;
+        break;
+      }
+
+      // optional float dropout_ratio = 12 [default = 0.5];
+      case 12: {
+        if (tag == 101) {
+         parse_dropout_ratio:
+          set_has_dropout_ratio();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
+                 input, &dropout_ratio_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(104)) goto parse_local_size;
+        break;
+      }
+
+      // optional uint32 local_size = 13 [default = 5];
+      case 13: {
+        if (tag == 104) {
+         parse_local_size:
+          set_has_local_size();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>(
+                 input, &local_size_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(117)) goto parse_alpha;
+        break;
+      }
+
+      // optional float alpha = 14 [default = 1];
+      case 14: {
+        if (tag == 117) {
+         parse_alpha:
+          set_has_alpha();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
+                 input, &alpha_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(125)) goto parse_beta;
+        break;
+      }
+
+      // optional float beta = 15 [default = 0.75];
+      case 15: {
+        if (tag == 125) {
+         parse_beta:
+          set_has_beta();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
+                 input, &beta_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(130)) goto parse_source;
+        break;
+      }
+
+      // optional string source = 16;
+      case 16: {
+        if (tag == 130) {
+         parse_source:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+                input, this->mutable_source()));
+          ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+            this->source().data(), this->source().length(),
+            ::google::protobuf::internal::WireFormat::PARSE,
+            "caffe.V0LayerParameter.source");
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(141)) goto parse_scale;
+        break;
+      }
+
+      // optional float scale = 17 [default = 1];
+      case 17: {
+        if (tag == 141) {
+         parse_scale:
+          set_has_scale();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
+                 input, &scale_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(146)) goto parse_meanfile;
+        break;
+      }
+
+      // optional string meanfile = 18;
+      case 18: {
+        if (tag == 146) {
+         parse_meanfile:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+                input, this->mutable_meanfile()));
+          ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+            this->meanfile().data(), this->meanfile().length(),
+            ::google::protobuf::internal::WireFormat::PARSE,
+            "caffe.V0LayerParameter.meanfile");
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(152)) goto parse_batchsize;
+        break;
+      }
+
+      // optional uint32 batchsize = 19;
+      case 19: {
+        if (tag == 152) {
+         parse_batchsize:
+          set_has_batchsize();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>(
+                 input, &batchsize_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(160)) goto parse_cropsize;
+        break;
+      }
+
+      // optional uint32 cropsize = 20 [default = 0];
+      case 20: {
+        if (tag == 160) {
+         parse_cropsize:
+          set_has_cropsize();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>(
+                 input, &cropsize_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(168)) goto parse_mirror;
+        break;
+      }
+
+      // optional bool mirror = 21 [default = false];
+      case 21: {
+        if (tag == 168) {
+         parse_mirror:
+          set_has_mirror();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>(
+                 input, &mirror_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(181)) goto parse_k;
+        break;
+      }
+
+      // optional float k = 22 [default = 1];
+      case 22: {
+        if (tag == 181) {
+         parse_k:
+          set_has_k();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
+                 input, &k_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(402)) goto parse_blobs;
+        break;
+      }
+
+      // repeated .caffe.BlobProto blobs = 50;
+      case 50: {
+        if (tag == 402) {
+         parse_blobs:
+          DO_(input->IncrementRecursionDepth());
+         parse_loop_blobs:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth(
+                input, add_blobs()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(402)) goto parse_loop_blobs;
+        input->UnsafeDecrementRecursionDepth();
+        if (input->ExpectTag(413)) goto parse_blobs_lr;
+        break;
+      }
+
+      // repeated float blobs_lr = 51;
+      case 51: {
+        if (tag == 413) {
+         parse_blobs_lr:
+          DO_((::google::protobuf::internal::WireFormatLite::ReadRepeatedPrimitive<
+                   float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
+                 2, 413, input, this->mutable_blobs_lr())));
+        } else if (tag == 410) {
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPackedPrimitiveNoInline<
+                   float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
+                 input, this->mutable_blobs_lr())));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(413)) goto parse_blobs_lr;
+        if (input->ExpectTag(421)) goto parse_weight_decay;
+        break;
+      }
+
+      // repeated float weight_decay = 52;
+      case 52: {
+        if (tag == 421) {
+         parse_weight_decay:
+          DO_((::google::protobuf::internal::WireFormatLite::ReadRepeatedPrimitive<
+                   float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
+                 2, 421, input, this->mutable_weight_decay())));
+        } else if (tag == 418) {
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPackedPrimitiveNoInline<
+                   float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
+                 input, this->mutable_weight_decay())));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(421)) goto parse_weight_decay;
+        if (input->ExpectTag(424)) goto parse_rand_skip;
+        break;
+      }
+
+      // optional uint32 rand_skip = 53 [default = 0];
+      case 53: {
+        if (tag == 424) {
+         parse_rand_skip:
+          set_has_rand_skip();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>(
+                 input, &rand_skip_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(437)) goto parse_det_fg_threshold;
+        break;
+      }
+
+      // optional float det_fg_threshold = 54 [default = 0.5];
+      case 54: {
+        if (tag == 437) {
+         parse_det_fg_threshold:
+          set_has_det_fg_threshold();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
+                 input, &det_fg_threshold_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(445)) goto parse_det_bg_threshold;
+        break;
+      }
+
+      // optional float det_bg_threshold = 55 [default = 0.5];
+      case 55: {
+        if (tag == 445) {
+         parse_det_bg_threshold:
+          set_has_det_bg_threshold();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
+                 input, &det_bg_threshold_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(453)) goto parse_det_fg_fraction;
+        break;
+      }
+
+      // optional float det_fg_fraction = 56 [default = 0.25];
+      case 56: {
+        if (tag == 453) {
+         parse_det_fg_fraction:
+          set_has_det_fg_fraction();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
+                 input, &det_fg_fraction_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(464)) goto parse_det_context_pad;
+        break;
+      }
+
+      // optional uint32 det_context_pad = 58 [default = 0];
+      case 58: {
+        if (tag == 464) {
+         parse_det_context_pad:
+          set_has_det_context_pad();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>(
+                 input, &det_context_pad_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(474)) goto parse_det_crop_mode;
+        break;
+      }
+
+      // optional string det_crop_mode = 59 [default = "warp"];
+      case 59: {
+        if (tag == 474) {
+         parse_det_crop_mode:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+                input, this->mutable_det_crop_mode()));
+          ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+            this->det_crop_mode().data(), this->det_crop_mode().length(),
+            ::google::protobuf::internal::WireFormat::PARSE,
+            "caffe.V0LayerParameter.det_crop_mode");
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(480)) goto parse_new_num;
+        break;
+      }
+
+      // optional int32 new_num = 60 [default = 0];
+      case 60: {
+        if (tag == 480) {
+         parse_new_num:
+          set_has_new_num();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
+                 input, &new_num_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(488)) goto parse_new_channels;
+        break;
+      }
+
+      // optional int32 new_channels = 61 [default = 0];
+      case 61: {
+        if (tag == 488) {
+         parse_new_channels:
+          set_has_new_channels();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
+                 input, &new_channels_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(496)) goto parse_new_height;
+        break;
+      }
+
+      // optional int32 new_height = 62 [default = 0];
+      case 62: {
+        if (tag == 496) {
+         parse_new_height:
+          set_has_new_height();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
+                 input, &new_height_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(504)) goto parse_new_width;
+        break;
+      }
+
+      // optional int32 new_width = 63 [default = 0];
+      case 63: {
+        if (tag == 504) {
+         parse_new_width:
+          set_has_new_width();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
+                 input, &new_width_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(512)) goto parse_shuffle_images;
+        break;
+      }
+
+      // optional bool shuffle_images = 64 [default = false];
+      case 64: {
+        if (tag == 512) {
+         parse_shuffle_images:
+          set_has_shuffle_images();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>(
+                 input, &shuffle_images_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(520)) goto parse_concat_dim;
+        break;
+      }
+
+      // optional uint32 concat_dim = 65 [default = 1];
+      case 65: {
+        if (tag == 520) {
+         parse_concat_dim:
+          set_has_concat_dim();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>(
+                 input, &concat_dim_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(8010)) goto parse_hdf5_output_param;
+        break;
+      }
+
+      // optional .caffe.HDF5OutputParameter hdf5_output_param = 1001;
+      case 1001: {
+        if (tag == 8010) {
+         parse_hdf5_output_param:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+               input, mutable_hdf5_output_param()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectAtEnd()) goto success;
+        break;
+      }
+
+      default: {
+      handle_unusual:
+        if (tag == 0 ||
+            ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+          goto success;
+        }
+        DO_(::google::protobuf::internal::WireFormat::SkipField(
+              input, tag, mutable_unknown_fields()));
+        break;
+      }
+    }
+  }
+success:
+  // @@protoc_insertion_point(parse_success:caffe.V0LayerParameter)
+  return true;
+failure:
+  // @@protoc_insertion_point(parse_failure:caffe.V0LayerParameter)
+  return false;
+#undef DO_
+}
+
+void V0LayerParameter::SerializeWithCachedSizes(
+    ::google::protobuf::io::CodedOutputStream* output) const {
+  // @@protoc_insertion_point(serialize_start:caffe.V0LayerParameter)
+  // optional string name = 1;
+  if (has_name()) {
+    ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->name().data(), this->name().length(),
+      ::google::protobuf::internal::WireFormat::SERIALIZE,
+      "caffe.V0LayerParameter.name");
+    ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
+      1, this->name(), output);
+  }
+
+  // optional string type = 2;
+  if (has_type()) {
+    ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->type().data(), this->type().length(),
+      ::google::protobuf::internal::WireFormat::SERIALIZE,
+      "caffe.V0LayerParameter.type");
+    ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
+      2, this->type(), output);
+  }
+
+  // optional uint32 num_output = 3;
+  if (has_num_output()) {
+    ::google::protobuf::internal::WireFormatLite::WriteUInt32(3, this->num_output(), output);
+  }
+
+  // optional bool biasterm = 4 [default = true];
+  if (has_biasterm()) {
+    ::google::protobuf::internal::WireFormatLite::WriteBool(4, this->biasterm(), output);
+  }
+
+  // optional .caffe.FillerParameter weight_filler = 5;
+  if (has_weight_filler()) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      5, *this->weight_filler_, output);
+  }
+
+  // optional .caffe.FillerParameter bias_filler = 6;
+  if (has_bias_filler()) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      6, *this->bias_filler_, output);
+  }
+
+  // optional uint32 pad = 7 [default = 0];
+  if (has_pad()) {
+    ::google::protobuf::internal::WireFormatLite::WriteUInt32(7, this->pad(), output);
+  }
+
+  // optional uint32 kernelsize = 8;
+  if (has_kernelsize()) {
+    ::google::protobuf::internal::WireFormatLite::WriteUInt32(8, this->kernelsize(), output);
+  }
+
+  // optional uint32 group = 9 [default = 1];
+  if (has_group()) {
+    ::google::protobuf::internal::WireFormatLite::WriteUInt32(9, this->group(), output);
+  }
+
+  // optional uint32 stride = 10 [default = 1];
+  if (has_stride()) {
+    ::google::protobuf::internal::WireFormatLite::WriteUInt32(10, this->stride(), output);
+  }
+
+  // optional .caffe.V0LayerParameter.PoolMethod pool = 11 [default = MAX];
+  if (has_pool()) {
+    ::google::protobuf::internal::WireFormatLite::WriteEnum(
+      11, this->pool(), output);
+  }
+
+  // optional float dropout_ratio = 12 [default = 0.5];
+  if (has_dropout_ratio()) {
+    ::google::protobuf::internal::WireFormatLite::WriteFloat(12, this->dropout_ratio(), output);
+  }
+
+  // optional uint32 local_size = 13 [default = 5];
+  if (has_local_size()) {
+    ::google::protobuf::internal::WireFormatLite::WriteUInt32(13, this->local_size(), output);
+  }
+
+  // optional float alpha = 14 [default = 1];
+  if (has_alpha()) {
+    ::google::protobuf::internal::WireFormatLite::WriteFloat(14, this->alpha(), output);
+  }
+
+  // optional float beta = 15 [default = 0.75];
+  if (has_beta()) {
+    ::google::protobuf::internal::WireFormatLite::WriteFloat(15, this->beta(), output);
+  }
+
+  // optional string source = 16;
+  if (has_source()) {
+    ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->source().data(), this->source().length(),
+      ::google::protobuf::internal::WireFormat::SERIALIZE,
+      "caffe.V0LayerParameter.source");
+    ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
+      16, this->source(), output);
+  }
+
+  // optional float scale = 17 [default = 1];
+  if (has_scale()) {
+    ::google::protobuf::internal::WireFormatLite::WriteFloat(17, this->scale(), output);
+  }
+
+  // optional string meanfile = 18;
+  if (has_meanfile()) {
+    ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->meanfile().data(), this->meanfile().length(),
+      ::google::protobuf::internal::WireFormat::SERIALIZE,
+      "caffe.V0LayerParameter.meanfile");
+    ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
+      18, this->meanfile(), output);
+  }
+
+  // optional uint32 batchsize = 19;
+  if (has_batchsize()) {
+    ::google::protobuf::internal::WireFormatLite::WriteUInt32(19, this->batchsize(), output);
+  }
+
+  // optional uint32 cropsize = 20 [default = 0];
+  if (has_cropsize()) {
+    ::google::protobuf::internal::WireFormatLite::WriteUInt32(20, this->cropsize(), output);
+  }
+
+  // optional bool mirror = 21 [default = false];
+  if (has_mirror()) {
+    ::google::protobuf::internal::WireFormatLite::WriteBool(21, this->mirror(), output);
+  }
+
+  // optional float k = 22 [default = 1];
+  if (has_k()) {
+    ::google::protobuf::internal::WireFormatLite::WriteFloat(22, this->k(), output);
+  }
+
+  // repeated .caffe.BlobProto blobs = 50;
+  for (unsigned int i = 0, n = this->blobs_size(); i < n; i++) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      50, this->blobs(i), output);
+  }
+
+  // repeated float blobs_lr = 51;
+  for (int i = 0; i < this->blobs_lr_size(); i++) {
+    ::google::protobuf::internal::WireFormatLite::WriteFloat(
+      51, this->blobs_lr(i), output);
+  }
+
+  // repeated float weight_decay = 52;
+  for (int i = 0; i < this->weight_decay_size(); i++) {
+    ::google::protobuf::internal::WireFormatLite::WriteFloat(
+      52, this->weight_decay(i), output);
+  }
+
+  // optional uint32 rand_skip = 53 [default = 0];
+  if (has_rand_skip()) {
+    ::google::protobuf::internal::WireFormatLite::WriteUInt32(53, this->rand_skip(), output);
+  }
+
+  // optional float det_fg_threshold = 54 [default = 0.5];
+  if (has_det_fg_threshold()) {
+    ::google::protobuf::internal::WireFormatLite::WriteFloat(54, this->det_fg_threshold(), output);
+  }
+
+  // optional float det_bg_threshold = 55 [default = 0.5];
+  if (has_det_bg_threshold()) {
+    ::google::protobuf::internal::WireFormatLite::WriteFloat(55, this->det_bg_threshold(), output);
+  }
+
+  // optional float det_fg_fraction = 56 [default = 0.25];
+  if (has_det_fg_fraction()) {
+    ::google::protobuf::internal::WireFormatLite::WriteFloat(56, this->det_fg_fraction(), output);
+  }
+
+  // optional uint32 det_context_pad = 58 [default = 0];
+  if (has_det_context_pad()) {
+    ::google::protobuf::internal::WireFormatLite::WriteUInt32(58, this->det_context_pad(), output);
+  }
+
+  // optional string det_crop_mode = 59 [default = "warp"];
+  if (has_det_crop_mode()) {
+    ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->det_crop_mode().data(), this->det_crop_mode().length(),
+      ::google::protobuf::internal::WireFormat::SERIALIZE,
+      "caffe.V0LayerParameter.det_crop_mode");
+    ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
+      59, this->det_crop_mode(), output);
+  }
+
+  // optional int32 new_num = 60 [default = 0];
+  if (has_new_num()) {
+    ::google::protobuf::internal::WireFormatLite::WriteInt32(60, this->new_num(), output);
+  }
+
+  // optional int32 new_channels = 61 [default = 0];
+  if (has_new_channels()) {
+    ::google::protobuf::internal::WireFormatLite::WriteInt32(61, this->new_channels(), output);
+  }
+
+  // optional int32 new_height = 62 [default = 0];
+  if (has_new_height()) {
+    ::google::protobuf::internal::WireFormatLite::WriteInt32(62, this->new_height(), output);
+  }
+
+  // optional int32 new_width = 63 [default = 0];
+  if (has_new_width()) {
+    ::google::protobuf::internal::WireFormatLite::WriteInt32(63, this->new_width(), output);
+  }
+
+  // optional bool shuffle_images = 64 [default = false];
+  if (has_shuffle_images()) {
+    ::google::protobuf::internal::WireFormatLite::WriteBool(64, this->shuffle_images(), output);
+  }
+
+  // optional uint32 concat_dim = 65 [default = 1];
+  if (has_concat_dim()) {
+    ::google::protobuf::internal::WireFormatLite::WriteUInt32(65, this->concat_dim(), output);
+  }
+
+  // optional .caffe.HDF5OutputParameter hdf5_output_param = 1001;
+  if (has_hdf5_output_param()) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      1001, *this->hdf5_output_param_, output);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
+        unknown_fields(), output);
+  }
+  // @@protoc_insertion_point(serialize_end:caffe.V0LayerParameter)
+}
+
+::google::protobuf::uint8* V0LayerParameter::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
+  (void)deterministic; // Unused
+  // @@protoc_insertion_point(serialize_to_array_start:caffe.V0LayerParameter)
+  // optional string name = 1;
+  if (has_name()) {
+    ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->name().data(), this->name().length(),
+      ::google::protobuf::internal::WireFormat::SERIALIZE,
+      "caffe.V0LayerParameter.name");
+    target =
+      ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
+        1, this->name(), target);
+  }
+
+  // optional string type = 2;
+  if (has_type()) {
+    ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->type().data(), this->type().length(),
+      ::google::protobuf::internal::WireFormat::SERIALIZE,
+      "caffe.V0LayerParameter.type");
+    target =
+      ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
+        2, this->type(), target);
+  }
+
+  // optional uint32 num_output = 3;
+  if (has_num_output()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteUInt32ToArray(3, this->num_output(), target);
+  }
+
+  // optional bool biasterm = 4 [default = true];
+  if (has_biasterm()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(4, this->biasterm(), target);
+  }
+
+  // optional .caffe.FillerParameter weight_filler = 5;
+  if (has_weight_filler()) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        5, *this->weight_filler_, false, target);
+  }
+
+  // optional .caffe.FillerParameter bias_filler = 6;
+  if (has_bias_filler()) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        6, *this->bias_filler_, false, target);
+  }
+
+  // optional uint32 pad = 7 [default = 0];
+  if (has_pad()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteUInt32ToArray(7, this->pad(), target);
+  }
+
+  // optional uint32 kernelsize = 8;
+  if (has_kernelsize()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteUInt32ToArray(8, this->kernelsize(), target);
+  }
+
+  // optional uint32 group = 9 [default = 1];
+  if (has_group()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteUInt32ToArray(9, this->group(), target);
+  }
+
+  // optional uint32 stride = 10 [default = 1];
+  if (has_stride()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteUInt32ToArray(10, this->stride(), target);
+  }
+
+  // optional .caffe.V0LayerParameter.PoolMethod pool = 11 [default = MAX];
+  if (has_pool()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteEnumToArray(
+      11, this->pool(), target);
+  }
+
+  // optional float dropout_ratio = 12 [default = 0.5];
+  if (has_dropout_ratio()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteFloatToArray(12, this->dropout_ratio(), target);
+  }
+
+  // optional uint32 local_size = 13 [default = 5];
+  if (has_local_size()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteUInt32ToArray(13, this->local_size(), target);
+  }
+
+  // optional float alpha = 14 [default = 1];
+  if (has_alpha()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteFloatToArray(14, this->alpha(), target);
+  }
+
+  // optional float beta = 15 [default = 0.75];
+  if (has_beta()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteFloatToArray(15, this->beta(), target);
+  }
+
+  // optional string source = 16;
+  if (has_source()) {
+    ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->source().data(), this->source().length(),
+      ::google::protobuf::internal::WireFormat::SERIALIZE,
+      "caffe.V0LayerParameter.source");
+    target =
+      ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
+        16, this->source(), target);
+  }
+
+  // optional float scale = 17 [default = 1];
+  if (has_scale()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteFloatToArray(17, this->scale(), target);
+  }
+
+  // optional string meanfile = 18;
+  if (has_meanfile()) {
+    ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->meanfile().data(), this->meanfile().length(),
+      ::google::protobuf::internal::WireFormat::SERIALIZE,
+      "caffe.V0LayerParameter.meanfile");
+    target =
+      ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
+        18, this->meanfile(), target);
+  }
+
+  // optional uint32 batchsize = 19;
+  if (has_batchsize()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteUInt32ToArray(19, this->batchsize(), target);
+  }
+
+  // optional uint32 cropsize = 20 [default = 0];
+  if (has_cropsize()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteUInt32ToArray(20, this->cropsize(), target);
+  }
+
+  // optional bool mirror = 21 [default = false];
+  if (has_mirror()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(21, this->mirror(), target);
+  }
+
+  // optional float k = 22 [default = 1];
+  if (has_k()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteFloatToArray(22, this->k(), target);
+  }
+
+  // repeated .caffe.BlobProto blobs = 50;
+  for (unsigned int i = 0, n = this->blobs_size(); i < n; i++) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        50, this->blobs(i), false, target);
+  }
+
+  // repeated float blobs_lr = 51;
+  for (int i = 0; i < this->blobs_lr_size(); i++) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      WriteFloatToArray(51, this->blobs_lr(i), target);
+  }
+
+  // repeated float weight_decay = 52;
+  for (int i = 0; i < this->weight_decay_size(); i++) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      WriteFloatToArray(52, this->weight_decay(i), target);
+  }
+
+  // optional uint32 rand_skip = 53 [default = 0];
+  if (has_rand_skip()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteUInt32ToArray(53, this->rand_skip(), target);
+  }
+
+  // optional float det_fg_threshold = 54 [default = 0.5];
+  if (has_det_fg_threshold()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteFloatToArray(54, this->det_fg_threshold(), target);
+  }
+
+  // optional float det_bg_threshold = 55 [default = 0.5];
+  if (has_det_bg_threshold()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteFloatToArray(55, this->det_bg_threshold(), target);
+  }
+
+  // optional float det_fg_fraction = 56 [default = 0.25];
+  if (has_det_fg_fraction()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteFloatToArray(56, this->det_fg_fraction(), target);
+  }
+
+  // optional uint32 det_context_pad = 58 [default = 0];
+  if (has_det_context_pad()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteUInt32ToArray(58, this->det_context_pad(), target);
+  }
+
+  // optional string det_crop_mode = 59 [default = "warp"];
+  if (has_det_crop_mode()) {
+    ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(
+      this->det_crop_mode().data(), this->det_crop_mode().length(),
+      ::google::protobuf::internal::WireFormat::SERIALIZE,
+      "caffe.V0LayerParameter.det_crop_mode");
+    target =
+      ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
+        59, this->det_crop_mode(), target);
+  }
+
+  // optional int32 new_num = 60 [default = 0];
+  if (has_new_num()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteInt32ToArray(60, this->new_num(), target);
+  }
+
+  // optional int32 new_channels = 61 [default = 0];
+  if (has_new_channels()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteInt32ToArray(61, this->new_channels(), target);
+  }
+
+  // optional int32 new_height = 62 [default = 0];
+  if (has_new_height()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteInt32ToArray(62, this->new_height(), target);
+  }
+
+  // optional int32 new_width = 63 [default = 0];
+  if (has_new_width()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteInt32ToArray(63, this->new_width(), target);
+  }
+
+  // optional bool shuffle_images = 64 [default = false];
+  if (has_shuffle_images()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(64, this->shuffle_images(), target);
+  }
+
+  // optional uint32 concat_dim = 65 [default = 1];
+  if (has_concat_dim()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteUInt32ToArray(65, this->concat_dim(), target);
+  }
+
+  // optional .caffe.HDF5OutputParameter hdf5_output_param = 1001;
+  if (has_hdf5_output_param()) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        1001, *this->hdf5_output_param_, false, target);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
+        unknown_fields(), target);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:caffe.V0LayerParameter)
+  return target;
+}
+
+size_t V0LayerParameter::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:caffe.V0LayerParameter)
+  size_t total_size = 0;
+
+  if (_has_bits_[0 / 32] & 255u) {
+    // optional string name = 1;
+    if (has_name()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::StringSize(
+          this->name());
+    }
+
+    // optional string type = 2;
+    if (has_type()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::StringSize(
+          this->type());
+    }
+
+    // optional uint32 num_output = 3;
+    if (has_num_output()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::UInt32Size(
+          this->num_output());
+    }
+
+    // optional bool biasterm = 4 [default = true];
+    if (has_biasterm()) {
+      total_size += 1 + 1;
+    }
+
+    // optional .caffe.FillerParameter weight_filler = 5;
+    if (has_weight_filler()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          *this->weight_filler_);
+    }
+
+    // optional .caffe.FillerParameter bias_filler = 6;
+    if (has_bias_filler()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          *this->bias_filler_);
+    }
+
+    // optional uint32 pad = 7 [default = 0];
+    if (has_pad()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::UInt32Size(
+          this->pad());
+    }
+
+    // optional uint32 kernelsize = 8;
+    if (has_kernelsize()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::UInt32Size(
+          this->kernelsize());
+    }
+
+  }
+  if (_has_bits_[8 / 32] & 65280u) {
+    // optional uint32 group = 9 [default = 1];
+    if (has_group()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::UInt32Size(
+          this->group());
+    }
+
+    // optional uint32 stride = 10 [default = 1];
+    if (has_stride()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::UInt32Size(
+          this->stride());
+    }
+
+    // optional .caffe.V0LayerParameter.PoolMethod pool = 11 [default = MAX];
+    if (has_pool()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::EnumSize(this->pool());
+    }
+
+    // optional float dropout_ratio = 12 [default = 0.5];
+    if (has_dropout_ratio()) {
+      total_size += 1 + 4;
+    }
+
+    // optional uint32 local_size = 13 [default = 5];
+    if (has_local_size()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::UInt32Size(
+          this->local_size());
+    }
+
+    // optional float alpha = 14 [default = 1];
+    if (has_alpha()) {
+      total_size += 1 + 4;
+    }
+
+    // optional float beta = 15 [default = 0.75];
+    if (has_beta()) {
+      total_size += 1 + 4;
+    }
+
+    // optional float k = 22 [default = 1];
+    if (has_k()) {
+      total_size += 2 + 4;
+    }
+
+  }
+  if (_has_bits_[16 / 32] & 4128768u) {
+    // optional string source = 16;
+    if (has_source()) {
+      total_size += 2 +
+        ::google::protobuf::internal::WireFormatLite::StringSize(
+          this->source());
+    }
+
+    // optional float scale = 17 [default = 1];
+    if (has_scale()) {
+      total_size += 2 + 4;
+    }
+
+    // optional string meanfile = 18;
+    if (has_meanfile()) {
+      total_size += 2 +
+        ::google::protobuf::internal::WireFormatLite::StringSize(
+          this->meanfile());
+    }
+
+    // optional uint32 batchsize = 19;
+    if (has_batchsize()) {
+      total_size += 2 +
+        ::google::protobuf::internal::WireFormatLite::UInt32Size(
+          this->batchsize());
+    }
+
+    // optional uint32 cropsize = 20 [default = 0];
+    if (has_cropsize()) {
+      total_size += 2 +
+        ::google::protobuf::internal::WireFormatLite::UInt32Size(
+          this->cropsize());
+    }
+
+    // optional bool mirror = 21 [default = false];
+    if (has_mirror()) {
+      total_size += 2 + 1;
+    }
+
+  }
+  if (_has_bits_[25 / 32] & 4261412864u) {
+    // optional uint32 rand_skip = 53 [default = 0];
+    if (has_rand_skip()) {
+      total_size += 2 +
+        ::google::protobuf::internal::WireFormatLite::UInt32Size(
+          this->rand_skip());
+    }
+
+    // optional float det_fg_threshold = 54 [default = 0.5];
+    if (has_det_fg_threshold()) {
+      total_size += 2 + 4;
+    }
+
+    // optional float det_bg_threshold = 55 [default = 0.5];
+    if (has_det_bg_threshold()) {
+      total_size += 2 + 4;
+    }
+
+    // optional float det_fg_fraction = 56 [default = 0.25];
+    if (has_det_fg_fraction()) {
+      total_size += 2 + 4;
+    }
+
+    // optional uint32 det_context_pad = 58 [default = 0];
+    if (has_det_context_pad()) {
+      total_size += 2 +
+        ::google::protobuf::internal::WireFormatLite::UInt32Size(
+          this->det_context_pad());
+    }
+
+    // optional string det_crop_mode = 59 [default = "warp"];
+    if (has_det_crop_mode()) {
+      total_size += 2 +
+        ::google::protobuf::internal::WireFormatLite::StringSize(
+          this->det_crop_mode());
+    }
+
+    // optional int32 new_num = 60 [default = 0];
+    if (has_new_num()) {
+      total_size += 2 +
+        ::google::protobuf::internal::WireFormatLite::Int32Size(
+          this->new_num());
+    }
+
+  }
+  if (_has_bits_[32 / 32] & 63u) {
+    // optional int32 new_channels = 61 [default = 0];
+    if (has_new_channels()) {
+      total_size += 2 +
+        ::google::protobuf::internal::WireFormatLite::Int32Size(
+          this->new_channels());
+    }
+
+    // optional int32 new_height = 62 [default = 0];
+    if (has_new_height()) {
+      total_size += 2 +
+        ::google::protobuf::internal::WireFormatLite::Int32Size(
+          this->new_height());
+    }
+
+    // optional int32 new_width = 63 [default = 0];
+    if (has_new_width()) {
+      total_size += 2 +
+        ::google::protobuf::internal::WireFormatLite::Int32Size(
+          this->new_width());
+    }
+
+    // optional bool shuffle_images = 64 [default = false];
+    if (has_shuffle_images()) {
+      total_size += 2 + 1;
+    }
+
+    // optional uint32 concat_dim = 65 [default = 1];
+    if (has_concat_dim()) {
+      total_size += 2 +
+        ::google::protobuf::internal::WireFormatLite::UInt32Size(
+          this->concat_dim());
+    }
+
+    // optional .caffe.HDF5OutputParameter hdf5_output_param = 1001;
+    if (has_hdf5_output_param()) {
+      total_size += 2 +
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          *this->hdf5_output_param_);
+    }
+
+  }
+  // repeated .caffe.BlobProto blobs = 50;
+  {
+    unsigned int count = this->blobs_size();
+    total_size += 2UL * count;
+    for (unsigned int i = 0; i < count; i++) {
+      total_size +=
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          this->blobs(i));
+    }
+  }
+
+  // repeated float blobs_lr = 51;
+  {
+    size_t data_size = 0;
+    unsigned int count = this->blobs_lr_size();
+    data_size = 4UL * count;
+    total_size += 2 *
+                  ::google::protobuf::internal::FromIntSize(this->blobs_lr_size());
+    total_size += data_size;
+  }
+
+  // repeated float weight_decay = 52;
+  {
+    size_t data_size = 0;
+    unsigned int count = this->weight_decay_size();
+    data_size = 4UL * count;
+    total_size += 2 *
+                  ::google::protobuf::internal::FromIntSize(this->weight_decay_size());
+    total_size += data_size;
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    total_size +=
+      ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
+        unknown_fields());
+  }
+  int cached_size = ::google::protobuf::internal::ToCachedSize(total_size);
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = cached_size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+  return total_size;
+}
+
+void V0LayerParameter::MergeFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_merge_from_start:caffe.V0LayerParameter)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const V0LayerParameter* source =
+      ::google::protobuf::internal::DynamicCastToGenerated<const V0LayerParameter>(
+          &from);
+  if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:caffe.V0LayerParameter)
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:caffe.V0LayerParameter)
+    UnsafeMergeFrom(*source);
+  }
+}
+
+void V0LayerParameter::MergeFrom(const V0LayerParameter& from) {
+// @@protoc_insertion_point(class_specific_merge_from_start:caffe.V0LayerParameter)
+  if (GOOGLE_PREDICT_TRUE(&from != this)) {
+    UnsafeMergeFrom(from);
+  } else {
+    MergeFromFail(__LINE__);
+  }
+}
+
+void V0LayerParameter::UnsafeMergeFrom(const V0LayerParameter& from) {
+  GOOGLE_DCHECK(&from != this);
+  blobs_.MergeFrom(from.blobs_);
+  blobs_lr_.UnsafeMergeFrom(from.blobs_lr_);
+  weight_decay_.UnsafeMergeFrom(from.weight_decay_);
+  if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+    if (from.has_name()) {
+      set_has_name();
+      name_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.name_);
+    }
+    if (from.has_type()) {
+      set_has_type();
+      type_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.type_);
+    }
+    if (from.has_num_output()) {
+      set_num_output(from.num_output());
+    }
+    if (from.has_biasterm()) {
+      set_biasterm(from.biasterm());
+    }
+    if (from.has_weight_filler()) {
+      mutable_weight_filler()->::caffe::FillerParameter::MergeFrom(from.weight_filler());
+    }
+    if (from.has_bias_filler()) {
+      mutable_bias_filler()->::caffe::FillerParameter::MergeFrom(from.bias_filler());
+    }
+    if (from.has_pad()) {
+      set_pad(from.pad());
+    }
+    if (from.has_kernelsize()) {
+      set_kernelsize(from.kernelsize());
+    }
+  }
+  if (from._has_bits_[8 / 32] & (0xffu << (8 % 32))) {
+    if (from.has_group()) {
+      set_group(from.group());
+    }
+    if (from.has_stride()) {
+      set_stride(from.stride());
+    }
+    if (from.has_pool()) {
+      set_pool(from.pool());
+    }
+    if (from.has_dropout_ratio()) {
+      set_dropout_ratio(from.dropout_ratio());
+    }
+    if (from.has_local_size()) {
+      set_local_size(from.local_size());
+    }
+    if (from.has_alpha()) {
+      set_alpha(from.alpha());
+    }
+    if (from.has_beta()) {
+      set_beta(from.beta());
+    }
+    if (from.has_k()) {
+      set_k(from.k());
+    }
+  }
+  if (from._has_bits_[16 / 32] & (0xffu << (16 % 32))) {
+    if (from.has_source()) {
+      set_has_source();
+      source_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.source_);
+    }
+    if (from.has_scale()) {
+      set_scale(from.scale());
+    }
+    if (from.has_meanfile()) {
+      set_has_meanfile();
+      meanfile_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.meanfile_);
+    }
+    if (from.has_batchsize()) {
+      set_batchsize(from.batchsize());
+    }
+    if (from.has_cropsize()) {
+      set_cropsize(from.cropsize());
+    }
+    if (from.has_mirror()) {
+      set_mirror(from.mirror());
+    }
+  }
+  if (from._has_bits_[25 / 32] & (0xffu << (25 % 32))) {
+    if (from.has_rand_skip()) {
+      set_rand_skip(from.rand_skip());
+    }
+    if (from.has_det_fg_threshold()) {
+      set_det_fg_threshold(from.det_fg_threshold());
+    }
+    if (from.has_det_bg_threshold()) {
+      set_det_bg_threshold(from.det_bg_threshold());
+    }
+    if (from.has_det_fg_fraction()) {
+      set_det_fg_fraction(from.det_fg_fraction());
+    }
+    if (from.has_det_context_pad()) {
+      set_det_context_pad(from.det_context_pad());
+    }
+    if (from.has_det_crop_mode()) {
+      set_has_det_crop_mode();
+      det_crop_mode_.AssignWithDefault(_default_det_crop_mode_, from.det_crop_mode_);
+    }
+    if (from.has_new_num()) {
+      set_new_num(from.new_num());
+    }
+  }
+  if (from._has_bits_[32 / 32] & (0xffu << (32 % 32))) {
+    if (from.has_new_channels()) {
+      set_new_channels(from.new_channels());
+    }
+    if (from.has_new_height()) {
+      set_new_height(from.new_height());
+    }
+    if (from.has_new_width()) {
+      set_new_width(from.new_width());
+    }
+    if (from.has_shuffle_images()) {
+      set_shuffle_images(from.shuffle_images());
+    }
+    if (from.has_concat_dim()) {
+      set_concat_dim(from.concat_dim());
+    }
+    if (from.has_hdf5_output_param()) {
+      mutable_hdf5_output_param()->::caffe::HDF5OutputParameter::MergeFrom(from.hdf5_output_param());
+    }
+  }
+  if (from._internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::UnknownFieldSet::MergeToInternalMetdata(
+      from.unknown_fields(), &_internal_metadata_);
+  }
+}
+
+void V0LayerParameter::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:caffe.V0LayerParameter)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void V0LayerParameter::CopyFrom(const V0LayerParameter& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:caffe.V0LayerParameter)
+  if (&from == this) return;
+  Clear();
+  UnsafeMergeFrom(from);
+}
+
+bool V0LayerParameter::IsInitialized() const {
+
+  return true;
+}
+
+void V0LayerParameter::Swap(V0LayerParameter* other) {
+  if (other == this) return;
+  InternalSwap(other);
+}
+void V0LayerParameter::InternalSwap(V0LayerParameter* other) {
+  name_.Swap(&other->name_);
+  type_.Swap(&other->type_);
+  std::swap(num_output_, other->num_output_);
+  std::swap(biasterm_, other->biasterm_);
+  std::swap(weight_filler_, other->weight_filler_);
+  std::swap(bias_filler_, other->bias_filler_);
+  std::swap(pad_, other->pad_);
+  std::swap(kernelsize_, other->kernelsize_);
+  std::swap(group_, other->group_);
+  std::swap(stride_, other->stride_);
+  std::swap(pool_, other->pool_);
+  std::swap(dropout_ratio_, other->dropout_ratio_);
+  std::swap(local_size_, other->local_size_);
+  std::swap(alpha_, other->alpha_);
+  std::swap(beta_, other->beta_);
+  std::swap(k_, other->k_);
+  source_.Swap(&other->source_);
+  std::swap(scale_, other->scale_);
+  meanfile_.Swap(&other->meanfile_);
+  std::swap(batchsize_, other->batchsize_);
+  std::swap(cropsize_, other->cropsize_);
+  std::swap(mirror_, other->mirror_);
+  blobs_.UnsafeArenaSwap(&other->blobs_);
+  blobs_lr_.UnsafeArenaSwap(&other->blobs_lr_);
+  weight_decay_.UnsafeArenaSwap(&other->weight_decay_);
+  std::swap(rand_skip_, other->rand_skip_);
+  std::swap(det_fg_threshold_, other->det_fg_threshold_);
+  std::swap(det_bg_threshold_, other->det_bg_threshold_);
+  std::swap(det_fg_fraction_, other->det_fg_fraction_);
+  std::swap(det_context_pad_, other->det_context_pad_);
+  det_crop_mode_.Swap(&other->det_crop_mode_);
+  std::swap(new_num_, other->new_num_);
+  std::swap(new_channels_, other->new_channels_);
+  std::swap(new_height_, other->new_height_);
+  std::swap(new_width_, other->new_width_);
+  std::swap(shuffle_images_, other->shuffle_images_);
+  std::swap(concat_dim_, other->concat_dim_);
+  std::swap(hdf5_output_param_, other->hdf5_output_param_);
+  std::swap(_has_bits_[0], other->_has_bits_[0]);
+  std::swap(_has_bits_[1], other->_has_bits_[1]);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
+}
+
+::google::protobuf::Metadata V0LayerParameter::GetMetadata() const {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::Metadata metadata;
+  metadata.descriptor = V0LayerParameter_descriptor_;
+  metadata.reflection = V0LayerParameter_reflection_;
+  return metadata;
+}
+
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// V0LayerParameter
+
+// optional string name = 1;
+bool V0LayerParameter::has_name() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+void V0LayerParameter::set_has_name() {
+  _has_bits_[0] |= 0x00000001u;
+}
+void V0LayerParameter::clear_has_name() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+void V0LayerParameter::clear_name() {
+  name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  clear_has_name();
+}
+const ::std::string& V0LayerParameter::name() const {
+  // @@protoc_insertion_point(field_get:caffe.V0LayerParameter.name)
+  return name_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+void V0LayerParameter::set_name(const ::std::string& value) {
+  set_has_name();
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:caffe.V0LayerParameter.name)
+}
+void V0LayerParameter::set_name(const char* value) {
+  set_has_name();
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:caffe.V0LayerParameter.name)
+}
+void V0LayerParameter::set_name(const char* value, size_t size) {
+  set_has_name();
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:caffe.V0LayerParameter.name)
+}
+::std::string* V0LayerParameter::mutable_name() {
+  set_has_name();
+  // @@protoc_insertion_point(field_mutable:caffe.V0LayerParameter.name)
+  return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+::std::string* V0LayerParameter::release_name() {
+  // @@protoc_insertion_point(field_release:caffe.V0LayerParameter.name)
+  clear_has_name();
+  return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+void V0LayerParameter::set_allocated_name(::std::string* name) {
+  if (name != NULL) {
+    set_has_name();
+  } else {
+    clear_has_name();
+  }
+  name_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), name);
+  // @@protoc_insertion_point(field_set_allocated:caffe.V0LayerParameter.name)
+}
+
+// optional string type = 2;
+bool V0LayerParameter::has_type() const {
+  return (_has_bits_[0] & 0x00000002u) != 0;
+}
+void V0LayerParameter::set_has_type() {
+  _has_bits_[0] |= 0x00000002u;
+}
+void V0LayerParameter::clear_has_type() {
+  _has_bits_[0] &= ~0x00000002u;
+}
+void V0LayerParameter::clear_type() {
+  type_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  clear_has_type();
+}
+const ::std::string& V0LayerParameter::type() const {
+  // @@protoc_insertion_point(field_get:caffe.V0LayerParameter.type)
+  return type_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+void V0LayerParameter::set_type(const ::std::string& value) {
+  set_has_type();
+  type_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:caffe.V0LayerParameter.type)
+}
+void V0LayerParameter::set_type(const char* value) {
+  set_has_type();
+  type_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:caffe.V0LayerParameter.type)
+}
+void V0LayerParameter::set_type(const char* value, size_t size) {
+  set_has_type();
+  type_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:caffe.V0LayerParameter.type)
+}
+::std::string* V0LayerParameter::mutable_type() {
+  set_has_type();
+  // @@protoc_insertion_point(field_mutable:caffe.V0LayerParameter.type)
+  return type_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+::std::string* V0LayerParameter::release_type() {
+  // @@protoc_insertion_point(field_release:caffe.V0LayerParameter.type)
+  clear_has_type();
+  return type_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+void V0LayerParameter::set_allocated_type(::std::string* type) {
+  if (type != NULL) {
+    set_has_type();
+  } else {
+    clear_has_type();
+  }
+  type_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), type);
+  // @@protoc_insertion_point(field_set_allocated:caffe.V0LayerParameter.type)
+}
+
+// optional uint32 num_output = 3;
+bool V0LayerParameter::has_num_output() const {
+  return (_has_bits_[0] & 0x00000004u) != 0;
+}
+void V0LayerParameter::set_has_num_output() {
+  _has_bits_[0] |= 0x00000004u;
+}
+void V0LayerParameter::clear_has_num_output() {
+  _has_bits_[0] &= ~0x00000004u;
+}
+void V0LayerParameter::clear_num_output() {
+  num_output_ = 0u;
+  clear_has_num_output();
+}
+::google::protobuf::uint32 V0LayerParameter::num_output() const {
+  // @@protoc_insertion_point(field_get:caffe.V0LayerParameter.num_output)
+  return num_output_;
+}
+void V0LayerParameter::set_num_output(::google::protobuf::uint32 value) {
+  set_has_num_output();
+  num_output_ = value;
+  // @@protoc_insertion_point(field_set:caffe.V0LayerParameter.num_output)
+}
+
+// optional bool biasterm = 4 [default = true];
+bool V0LayerParameter::has_biasterm() const {
+  return (_has_bits_[0] & 0x00000008u) != 0;
+}
+void V0LayerParameter::set_has_biasterm() {
+  _has_bits_[0] |= 0x00000008u;
+}
+void V0LayerParameter::clear_has_biasterm() {
+  _has_bits_[0] &= ~0x00000008u;
+}
+void V0LayerParameter::clear_biasterm() {
+  biasterm_ = true;
+  clear_has_biasterm();
+}
+bool V0LayerParameter::biasterm() const {
+  // @@protoc_insertion_point(field_get:caffe.V0LayerParameter.biasterm)
+  return biasterm_;
+}
+void V0LayerParameter::set_biasterm(bool value) {
+  set_has_biasterm();
+  biasterm_ = value;
+  // @@protoc_insertion_point(field_set:caffe.V0LayerParameter.biasterm)
+}
+
+// optional .caffe.FillerParameter weight_filler = 5;
+bool V0LayerParameter::has_weight_filler() const {
+  return (_has_bits_[0] & 0x00000010u) != 0;
+}
+void V0LayerParameter::set_has_weight_filler() {
+  _has_bits_[0] |= 0x00000010u;
+}
+void V0LayerParameter::clear_has_weight_filler() {
+  _has_bits_[0] &= ~0x00000010u;
+}
+void V0LayerParameter::clear_weight_filler() {
+  if (weight_filler_ != NULL) weight_filler_->::caffe::FillerParameter::Clear();
+  clear_has_weight_filler();
+}
+const ::caffe::FillerParameter& V0LayerParameter::weight_filler() const {
+  // @@protoc_insertion_point(field_get:caffe.V0LayerParameter.weight_filler)
+  return weight_filler_ != NULL ? *weight_filler_
+                         : *::caffe::FillerParameter::internal_default_instance();
+}
+::caffe::FillerParameter* V0LayerParameter::mutable_weight_filler() {
+  set_has_weight_filler();
+  if (weight_filler_ == NULL) {
+    weight_filler_ = new ::caffe::FillerParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.V0LayerParameter.weight_filler)
+  return weight_filler_;
+}
+::caffe::FillerParameter* V0LayerParameter::release_weight_filler() {
+  // @@protoc_insertion_point(field_release:caffe.V0LayerParameter.weight_filler)
+  clear_has_weight_filler();
+  ::caffe::FillerParameter* temp = weight_filler_;
+  weight_filler_ = NULL;
+  return temp;
+}
+void V0LayerParameter::set_allocated_weight_filler(::caffe::FillerParameter* weight_filler) {
+  delete weight_filler_;
+  weight_filler_ = weight_filler;
+  if (weight_filler) {
+    set_has_weight_filler();
+  } else {
+    clear_has_weight_filler();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.V0LayerParameter.weight_filler)
+}
+
+// optional .caffe.FillerParameter bias_filler = 6;
+bool V0LayerParameter::has_bias_filler() const {
+  return (_has_bits_[0] & 0x00000020u) != 0;
+}
+void V0LayerParameter::set_has_bias_filler() {
+  _has_bits_[0] |= 0x00000020u;
+}
+void V0LayerParameter::clear_has_bias_filler() {
+  _has_bits_[0] &= ~0x00000020u;
+}
+void V0LayerParameter::clear_bias_filler() {
+  if (bias_filler_ != NULL) bias_filler_->::caffe::FillerParameter::Clear();
+  clear_has_bias_filler();
+}
+const ::caffe::FillerParameter& V0LayerParameter::bias_filler() const {
+  // @@protoc_insertion_point(field_get:caffe.V0LayerParameter.bias_filler)
+  return bias_filler_ != NULL ? *bias_filler_
+                         : *::caffe::FillerParameter::internal_default_instance();
+}
+::caffe::FillerParameter* V0LayerParameter::mutable_bias_filler() {
+  set_has_bias_filler();
+  if (bias_filler_ == NULL) {
+    bias_filler_ = new ::caffe::FillerParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.V0LayerParameter.bias_filler)
+  return bias_filler_;
+}
+::caffe::FillerParameter* V0LayerParameter::release_bias_filler() {
+  // @@protoc_insertion_point(field_release:caffe.V0LayerParameter.bias_filler)
+  clear_has_bias_filler();
+  ::caffe::FillerParameter* temp = bias_filler_;
+  bias_filler_ = NULL;
+  return temp;
+}
+void V0LayerParameter::set_allocated_bias_filler(::caffe::FillerParameter* bias_filler) {
+  delete bias_filler_;
+  bias_filler_ = bias_filler;
+  if (bias_filler) {
+    set_has_bias_filler();
+  } else {
+    clear_has_bias_filler();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.V0LayerParameter.bias_filler)
+}
+
+// optional uint32 pad = 7 [default = 0];
+bool V0LayerParameter::has_pad() const {
+  return (_has_bits_[0] & 0x00000040u) != 0;
+}
+void V0LayerParameter::set_has_pad() {
+  _has_bits_[0] |= 0x00000040u;
+}
+void V0LayerParameter::clear_has_pad() {
+  _has_bits_[0] &= ~0x00000040u;
+}
+void V0LayerParameter::clear_pad() {
+  pad_ = 0u;
+  clear_has_pad();
+}
+::google::protobuf::uint32 V0LayerParameter::pad() const {
+  // @@protoc_insertion_point(field_get:caffe.V0LayerParameter.pad)
+  return pad_;
+}
+void V0LayerParameter::set_pad(::google::protobuf::uint32 value) {
+  set_has_pad();
+  pad_ = value;
+  // @@protoc_insertion_point(field_set:caffe.V0LayerParameter.pad)
+}
+
+// optional uint32 kernelsize = 8;
+bool V0LayerParameter::has_kernelsize() const {
+  return (_has_bits_[0] & 0x00000080u) != 0;
+}
+void V0LayerParameter::set_has_kernelsize() {
+  _has_bits_[0] |= 0x00000080u;
+}
+void V0LayerParameter::clear_has_kernelsize() {
+  _has_bits_[0] &= ~0x00000080u;
+}
+void V0LayerParameter::clear_kernelsize() {
+  kernelsize_ = 0u;
+  clear_has_kernelsize();
+}
+::google::protobuf::uint32 V0LayerParameter::kernelsize() const {
+  // @@protoc_insertion_point(field_get:caffe.V0LayerParameter.kernelsize)
+  return kernelsize_;
+}
+void V0LayerParameter::set_kernelsize(::google::protobuf::uint32 value) {
+  set_has_kernelsize();
+  kernelsize_ = value;
+  // @@protoc_insertion_point(field_set:caffe.V0LayerParameter.kernelsize)
+}
+
+// optional uint32 group = 9 [default = 1];
+bool V0LayerParameter::has_group() const {
+  return (_has_bits_[0] & 0x00000100u) != 0;
+}
+void V0LayerParameter::set_has_group() {
+  _has_bits_[0] |= 0x00000100u;
+}
+void V0LayerParameter::clear_has_group() {
+  _has_bits_[0] &= ~0x00000100u;
+}
+void V0LayerParameter::clear_group() {
+  group_ = 1u;
+  clear_has_group();
+}
+::google::protobuf::uint32 V0LayerParameter::group() const {
+  // @@protoc_insertion_point(field_get:caffe.V0LayerParameter.group)
+  return group_;
+}
+void V0LayerParameter::set_group(::google::protobuf::uint32 value) {
+  set_has_group();
+  group_ = value;
+  // @@protoc_insertion_point(field_set:caffe.V0LayerParameter.group)
+}
+
+// optional uint32 stride = 10 [default = 1];
+bool V0LayerParameter::has_stride() const {
+  return (_has_bits_[0] & 0x00000200u) != 0;
+}
+void V0LayerParameter::set_has_stride() {
+  _has_bits_[0] |= 0x00000200u;
+}
+void V0LayerParameter::clear_has_stride() {
+  _has_bits_[0] &= ~0x00000200u;
+}
+void V0LayerParameter::clear_stride() {
+  stride_ = 1u;
+  clear_has_stride();
+}
+::google::protobuf::uint32 V0LayerParameter::stride() const {
+  // @@protoc_insertion_point(field_get:caffe.V0LayerParameter.stride)
+  return stride_;
+}
+void V0LayerParameter::set_stride(::google::protobuf::uint32 value) {
+  set_has_stride();
+  stride_ = value;
+  // @@protoc_insertion_point(field_set:caffe.V0LayerParameter.stride)
+}
+
+// optional .caffe.V0LayerParameter.PoolMethod pool = 11 [default = MAX];
+bool V0LayerParameter::has_pool() const {
+  return (_has_bits_[0] & 0x00000400u) != 0;
+}
+void V0LayerParameter::set_has_pool() {
+  _has_bits_[0] |= 0x00000400u;
+}
+void V0LayerParameter::clear_has_pool() {
+  _has_bits_[0] &= ~0x00000400u;
+}
+void V0LayerParameter::clear_pool() {
+  pool_ = 0;
+  clear_has_pool();
+}
+::caffe::V0LayerParameter_PoolMethod V0LayerParameter::pool() const {
+  // @@protoc_insertion_point(field_get:caffe.V0LayerParameter.pool)
+  return static_cast< ::caffe::V0LayerParameter_PoolMethod >(pool_);
+}
+void V0LayerParameter::set_pool(::caffe::V0LayerParameter_PoolMethod value) {
+  assert(::caffe::V0LayerParameter_PoolMethod_IsValid(value));
+  set_has_pool();
+  pool_ = value;
+  // @@protoc_insertion_point(field_set:caffe.V0LayerParameter.pool)
+}
+
+// optional float dropout_ratio = 12 [default = 0.5];
+bool V0LayerParameter::has_dropout_ratio() const {
+  return (_has_bits_[0] & 0x00000800u) != 0;
+}
+void V0LayerParameter::set_has_dropout_ratio() {
+  _has_bits_[0] |= 0x00000800u;
+}
+void V0LayerParameter::clear_has_dropout_ratio() {
+  _has_bits_[0] &= ~0x00000800u;
+}
+void V0LayerParameter::clear_dropout_ratio() {
+  dropout_ratio_ = 0.5f;
+  clear_has_dropout_ratio();
+}
+float V0LayerParameter::dropout_ratio() const {
+  // @@protoc_insertion_point(field_get:caffe.V0LayerParameter.dropout_ratio)
+  return dropout_ratio_;
+}
+void V0LayerParameter::set_dropout_ratio(float value) {
+  set_has_dropout_ratio();
+  dropout_ratio_ = value;
+  // @@protoc_insertion_point(field_set:caffe.V0LayerParameter.dropout_ratio)
+}
+
+// optional uint32 local_size = 13 [default = 5];
+bool V0LayerParameter::has_local_size() const {
+  return (_has_bits_[0] & 0x00001000u) != 0;
+}
+void V0LayerParameter::set_has_local_size() {
+  _has_bits_[0] |= 0x00001000u;
+}
+void V0LayerParameter::clear_has_local_size() {
+  _has_bits_[0] &= ~0x00001000u;
+}
+void V0LayerParameter::clear_local_size() {
+  local_size_ = 5u;
+  clear_has_local_size();
+}
+::google::protobuf::uint32 V0LayerParameter::local_size() const {
+  // @@protoc_insertion_point(field_get:caffe.V0LayerParameter.local_size)
+  return local_size_;
+}
+void V0LayerParameter::set_local_size(::google::protobuf::uint32 value) {
+  set_has_local_size();
+  local_size_ = value;
+  // @@protoc_insertion_point(field_set:caffe.V0LayerParameter.local_size)
+}
+
+// optional float alpha = 14 [default = 1];
+bool V0LayerParameter::has_alpha() const {
+  return (_has_bits_[0] & 0x00002000u) != 0;
+}
+void V0LayerParameter::set_has_alpha() {
+  _has_bits_[0] |= 0x00002000u;
+}
+void V0LayerParameter::clear_has_alpha() {
+  _has_bits_[0] &= ~0x00002000u;
+}
+void V0LayerParameter::clear_alpha() {
+  alpha_ = 1;
+  clear_has_alpha();
+}
+float V0LayerParameter::alpha() const {
+  // @@protoc_insertion_point(field_get:caffe.V0LayerParameter.alpha)
+  return alpha_;
+}
+void V0LayerParameter::set_alpha(float value) {
+  set_has_alpha();
+  alpha_ = value;
+  // @@protoc_insertion_point(field_set:caffe.V0LayerParameter.alpha)
+}
+
+// optional float beta = 15 [default = 0.75];
+bool V0LayerParameter::has_beta() const {
+  return (_has_bits_[0] & 0x00004000u) != 0;
+}
+void V0LayerParameter::set_has_beta() {
+  _has_bits_[0] |= 0x00004000u;
+}
+void V0LayerParameter::clear_has_beta() {
+  _has_bits_[0] &= ~0x00004000u;
+}
+void V0LayerParameter::clear_beta() {
+  beta_ = 0.75f;
+  clear_has_beta();
+}
+float V0LayerParameter::beta() const {
+  // @@protoc_insertion_point(field_get:caffe.V0LayerParameter.beta)
+  return beta_;
+}
+void V0LayerParameter::set_beta(float value) {
+  set_has_beta();
+  beta_ = value;
+  // @@protoc_insertion_point(field_set:caffe.V0LayerParameter.beta)
+}
+
+// optional float k = 22 [default = 1];
+bool V0LayerParameter::has_k() const {
+  return (_has_bits_[0] & 0x00008000u) != 0;
+}
+void V0LayerParameter::set_has_k() {
+  _has_bits_[0] |= 0x00008000u;
+}
+void V0LayerParameter::clear_has_k() {
+  _has_bits_[0] &= ~0x00008000u;
+}
+void V0LayerParameter::clear_k() {
+  k_ = 1;
+  clear_has_k();
+}
+float V0LayerParameter::k() const {
+  // @@protoc_insertion_point(field_get:caffe.V0LayerParameter.k)
+  return k_;
+}
+void V0LayerParameter::set_k(float value) {
+  set_has_k();
+  k_ = value;
+  // @@protoc_insertion_point(field_set:caffe.V0LayerParameter.k)
+}
+
+// optional string source = 16;
+bool V0LayerParameter::has_source() const {
+  return (_has_bits_[0] & 0x00010000u) != 0;
+}
+void V0LayerParameter::set_has_source() {
+  _has_bits_[0] |= 0x00010000u;
+}
+void V0LayerParameter::clear_has_source() {
+  _has_bits_[0] &= ~0x00010000u;
+}
+void V0LayerParameter::clear_source() {
+  source_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  clear_has_source();
+}
+const ::std::string& V0LayerParameter::source() const {
+  // @@protoc_insertion_point(field_get:caffe.V0LayerParameter.source)
+  return source_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+void V0LayerParameter::set_source(const ::std::string& value) {
+  set_has_source();
+  source_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:caffe.V0LayerParameter.source)
+}
+void V0LayerParameter::set_source(const char* value) {
+  set_has_source();
+  source_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:caffe.V0LayerParameter.source)
+}
+void V0LayerParameter::set_source(const char* value, size_t size) {
+  set_has_source();
+  source_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:caffe.V0LayerParameter.source)
+}
+::std::string* V0LayerParameter::mutable_source() {
+  set_has_source();
+  // @@protoc_insertion_point(field_mutable:caffe.V0LayerParameter.source)
+  return source_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+::std::string* V0LayerParameter::release_source() {
+  // @@protoc_insertion_point(field_release:caffe.V0LayerParameter.source)
+  clear_has_source();
+  return source_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+void V0LayerParameter::set_allocated_source(::std::string* source) {
+  if (source != NULL) {
+    set_has_source();
+  } else {
+    clear_has_source();
+  }
+  source_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), source);
+  // @@protoc_insertion_point(field_set_allocated:caffe.V0LayerParameter.source)
+}
+
+// optional float scale = 17 [default = 1];
+bool V0LayerParameter::has_scale() const {
+  return (_has_bits_[0] & 0x00020000u) != 0;
+}
+void V0LayerParameter::set_has_scale() {
+  _has_bits_[0] |= 0x00020000u;
+}
+void V0LayerParameter::clear_has_scale() {
+  _has_bits_[0] &= ~0x00020000u;
+}
+void V0LayerParameter::clear_scale() {
+  scale_ = 1;
+  clear_has_scale();
+}
+float V0LayerParameter::scale() const {
+  // @@protoc_insertion_point(field_get:caffe.V0LayerParameter.scale)
+  return scale_;
+}
+void V0LayerParameter::set_scale(float value) {
+  set_has_scale();
+  scale_ = value;
+  // @@protoc_insertion_point(field_set:caffe.V0LayerParameter.scale)
+}
+
+// optional string meanfile = 18;
+bool V0LayerParameter::has_meanfile() const {
+  return (_has_bits_[0] & 0x00040000u) != 0;
+}
+void V0LayerParameter::set_has_meanfile() {
+  _has_bits_[0] |= 0x00040000u;
+}
+void V0LayerParameter::clear_has_meanfile() {
+  _has_bits_[0] &= ~0x00040000u;
+}
+void V0LayerParameter::clear_meanfile() {
+  meanfile_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  clear_has_meanfile();
+}
+const ::std::string& V0LayerParameter::meanfile() const {
+  // @@protoc_insertion_point(field_get:caffe.V0LayerParameter.meanfile)
+  return meanfile_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+void V0LayerParameter::set_meanfile(const ::std::string& value) {
+  set_has_meanfile();
+  meanfile_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:caffe.V0LayerParameter.meanfile)
+}
+void V0LayerParameter::set_meanfile(const char* value) {
+  set_has_meanfile();
+  meanfile_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:caffe.V0LayerParameter.meanfile)
+}
+void V0LayerParameter::set_meanfile(const char* value, size_t size) {
+  set_has_meanfile();
+  meanfile_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:caffe.V0LayerParameter.meanfile)
+}
+::std::string* V0LayerParameter::mutable_meanfile() {
+  set_has_meanfile();
+  // @@protoc_insertion_point(field_mutable:caffe.V0LayerParameter.meanfile)
+  return meanfile_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+::std::string* V0LayerParameter::release_meanfile() {
+  // @@protoc_insertion_point(field_release:caffe.V0LayerParameter.meanfile)
+  clear_has_meanfile();
+  return meanfile_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+void V0LayerParameter::set_allocated_meanfile(::std::string* meanfile) {
+  if (meanfile != NULL) {
+    set_has_meanfile();
+  } else {
+    clear_has_meanfile();
+  }
+  meanfile_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), meanfile);
+  // @@protoc_insertion_point(field_set_allocated:caffe.V0LayerParameter.meanfile)
+}
+
+// optional uint32 batchsize = 19;
+bool V0LayerParameter::has_batchsize() const {
+  return (_has_bits_[0] & 0x00080000u) != 0;
+}
+void V0LayerParameter::set_has_batchsize() {
+  _has_bits_[0] |= 0x00080000u;
+}
+void V0LayerParameter::clear_has_batchsize() {
+  _has_bits_[0] &= ~0x00080000u;
+}
+void V0LayerParameter::clear_batchsize() {
+  batchsize_ = 0u;
+  clear_has_batchsize();
+}
+::google::protobuf::uint32 V0LayerParameter::batchsize() const {
+  // @@protoc_insertion_point(field_get:caffe.V0LayerParameter.batchsize)
+  return batchsize_;
+}
+void V0LayerParameter::set_batchsize(::google::protobuf::uint32 value) {
+  set_has_batchsize();
+  batchsize_ = value;
+  // @@protoc_insertion_point(field_set:caffe.V0LayerParameter.batchsize)
+}
+
+// optional uint32 cropsize = 20 [default = 0];
+bool V0LayerParameter::has_cropsize() const {
+  return (_has_bits_[0] & 0x00100000u) != 0;
+}
+void V0LayerParameter::set_has_cropsize() {
+  _has_bits_[0] |= 0x00100000u;
+}
+void V0LayerParameter::clear_has_cropsize() {
+  _has_bits_[0] &= ~0x00100000u;
+}
+void V0LayerParameter::clear_cropsize() {
+  cropsize_ = 0u;
+  clear_has_cropsize();
+}
+::google::protobuf::uint32 V0LayerParameter::cropsize() const {
+  // @@protoc_insertion_point(field_get:caffe.V0LayerParameter.cropsize)
+  return cropsize_;
+}
+void V0LayerParameter::set_cropsize(::google::protobuf::uint32 value) {
+  set_has_cropsize();
+  cropsize_ = value;
+  // @@protoc_insertion_point(field_set:caffe.V0LayerParameter.cropsize)
+}
+
+// optional bool mirror = 21 [default = false];
+bool V0LayerParameter::has_mirror() const {
+  return (_has_bits_[0] & 0x00200000u) != 0;
+}
+void V0LayerParameter::set_has_mirror() {
+  _has_bits_[0] |= 0x00200000u;
+}
+void V0LayerParameter::clear_has_mirror() {
+  _has_bits_[0] &= ~0x00200000u;
+}
+void V0LayerParameter::clear_mirror() {
+  mirror_ = false;
+  clear_has_mirror();
+}
+bool V0LayerParameter::mirror() const {
+  // @@protoc_insertion_point(field_get:caffe.V0LayerParameter.mirror)
+  return mirror_;
+}
+void V0LayerParameter::set_mirror(bool value) {
+  set_has_mirror();
+  mirror_ = value;
+  // @@protoc_insertion_point(field_set:caffe.V0LayerParameter.mirror)
+}
+
+// repeated .caffe.BlobProto blobs = 50;
+int V0LayerParameter::blobs_size() const {
+  return blobs_.size();
+}
+void V0LayerParameter::clear_blobs() {
+  blobs_.Clear();
+}
+const ::caffe::BlobProto& V0LayerParameter::blobs(int index) const {
+  // @@protoc_insertion_point(field_get:caffe.V0LayerParameter.blobs)
+  return blobs_.Get(index);
+}
+::caffe::BlobProto* V0LayerParameter::mutable_blobs(int index) {
+  // @@protoc_insertion_point(field_mutable:caffe.V0LayerParameter.blobs)
+  return blobs_.Mutable(index);
+}
+::caffe::BlobProto* V0LayerParameter::add_blobs() {
+  // @@protoc_insertion_point(field_add:caffe.V0LayerParameter.blobs)
+  return blobs_.Add();
+}
+::google::protobuf::RepeatedPtrField< ::caffe::BlobProto >*
+V0LayerParameter::mutable_blobs() {
+  // @@protoc_insertion_point(field_mutable_list:caffe.V0LayerParameter.blobs)
+  return &blobs_;
+}
+const ::google::protobuf::RepeatedPtrField< ::caffe::BlobProto >&
+V0LayerParameter::blobs() const {
+  // @@protoc_insertion_point(field_list:caffe.V0LayerParameter.blobs)
+  return blobs_;
+}
+
+// repeated float blobs_lr = 51;
+int V0LayerParameter::blobs_lr_size() const {
+  return blobs_lr_.size();
+}
+void V0LayerParameter::clear_blobs_lr() {
+  blobs_lr_.Clear();
+}
+float V0LayerParameter::blobs_lr(int index) const {
+  // @@protoc_insertion_point(field_get:caffe.V0LayerParameter.blobs_lr)
+  return blobs_lr_.Get(index);
+}
+void V0LayerParameter::set_blobs_lr(int index, float value) {
+  blobs_lr_.Set(index, value);
+  // @@protoc_insertion_point(field_set:caffe.V0LayerParameter.blobs_lr)
+}
+void V0LayerParameter::add_blobs_lr(float value) {
+  blobs_lr_.Add(value);
+  // @@protoc_insertion_point(field_add:caffe.V0LayerParameter.blobs_lr)
+}
+const ::google::protobuf::RepeatedField< float >&
+V0LayerParameter::blobs_lr() const {
+  // @@protoc_insertion_point(field_list:caffe.V0LayerParameter.blobs_lr)
+  return blobs_lr_;
+}
+::google::protobuf::RepeatedField< float >*
+V0LayerParameter::mutable_blobs_lr() {
+  // @@protoc_insertion_point(field_mutable_list:caffe.V0LayerParameter.blobs_lr)
+  return &blobs_lr_;
+}
+
+// repeated float weight_decay = 52;
+int V0LayerParameter::weight_decay_size() const {
+  return weight_decay_.size();
+}
+void V0LayerParameter::clear_weight_decay() {
+  weight_decay_.Clear();
+}
+float V0LayerParameter::weight_decay(int index) const {
+  // @@protoc_insertion_point(field_get:caffe.V0LayerParameter.weight_decay)
+  return weight_decay_.Get(index);
+}
+void V0LayerParameter::set_weight_decay(int index, float value) {
+  weight_decay_.Set(index, value);
+  // @@protoc_insertion_point(field_set:caffe.V0LayerParameter.weight_decay)
+}
+void V0LayerParameter::add_weight_decay(float value) {
+  weight_decay_.Add(value);
+  // @@protoc_insertion_point(field_add:caffe.V0LayerParameter.weight_decay)
+}
+const ::google::protobuf::RepeatedField< float >&
+V0LayerParameter::weight_decay() const {
+  // @@protoc_insertion_point(field_list:caffe.V0LayerParameter.weight_decay)
+  return weight_decay_;
+}
+::google::protobuf::RepeatedField< float >*
+V0LayerParameter::mutable_weight_decay() {
+  // @@protoc_insertion_point(field_mutable_list:caffe.V0LayerParameter.weight_decay)
+  return &weight_decay_;
+}
+
+// optional uint32 rand_skip = 53 [default = 0];
+bool V0LayerParameter::has_rand_skip() const {
+  return (_has_bits_[0] & 0x02000000u) != 0;
+}
+void V0LayerParameter::set_has_rand_skip() {
+  _has_bits_[0] |= 0x02000000u;
+}
+void V0LayerParameter::clear_has_rand_skip() {
+  _has_bits_[0] &= ~0x02000000u;
+}
+void V0LayerParameter::clear_rand_skip() {
+  rand_skip_ = 0u;
+  clear_has_rand_skip();
+}
+::google::protobuf::uint32 V0LayerParameter::rand_skip() const {
+  // @@protoc_insertion_point(field_get:caffe.V0LayerParameter.rand_skip)
+  return rand_skip_;
+}
+void V0LayerParameter::set_rand_skip(::google::protobuf::uint32 value) {
+  set_has_rand_skip();
+  rand_skip_ = value;
+  // @@protoc_insertion_point(field_set:caffe.V0LayerParameter.rand_skip)
+}
+
+// optional float det_fg_threshold = 54 [default = 0.5];
+bool V0LayerParameter::has_det_fg_threshold() const {
+  return (_has_bits_[0] & 0x04000000u) != 0;
+}
+void V0LayerParameter::set_has_det_fg_threshold() {
+  _has_bits_[0] |= 0x04000000u;
+}
+void V0LayerParameter::clear_has_det_fg_threshold() {
+  _has_bits_[0] &= ~0x04000000u;
+}
+void V0LayerParameter::clear_det_fg_threshold() {
+  det_fg_threshold_ = 0.5f;
+  clear_has_det_fg_threshold();
+}
+float V0LayerParameter::det_fg_threshold() const {
+  // @@protoc_insertion_point(field_get:caffe.V0LayerParameter.det_fg_threshold)
+  return det_fg_threshold_;
+}
+void V0LayerParameter::set_det_fg_threshold(float value) {
+  set_has_det_fg_threshold();
+  det_fg_threshold_ = value;
+  // @@protoc_insertion_point(field_set:caffe.V0LayerParameter.det_fg_threshold)
+}
+
+// optional float det_bg_threshold = 55 [default = 0.5];
+bool V0LayerParameter::has_det_bg_threshold() const {
+  return (_has_bits_[0] & 0x08000000u) != 0;
+}
+void V0LayerParameter::set_has_det_bg_threshold() {
+  _has_bits_[0] |= 0x08000000u;
+}
+void V0LayerParameter::clear_has_det_bg_threshold() {
+  _has_bits_[0] &= ~0x08000000u;
+}
+void V0LayerParameter::clear_det_bg_threshold() {
+  det_bg_threshold_ = 0.5f;
+  clear_has_det_bg_threshold();
+}
+float V0LayerParameter::det_bg_threshold() const {
+  // @@protoc_insertion_point(field_get:caffe.V0LayerParameter.det_bg_threshold)
+  return det_bg_threshold_;
+}
+void V0LayerParameter::set_det_bg_threshold(float value) {
+  set_has_det_bg_threshold();
+  det_bg_threshold_ = value;
+  // @@protoc_insertion_point(field_set:caffe.V0LayerParameter.det_bg_threshold)
+}
+
+// optional float det_fg_fraction = 56 [default = 0.25];
+bool V0LayerParameter::has_det_fg_fraction() const {
+  return (_has_bits_[0] & 0x10000000u) != 0;
+}
+void V0LayerParameter::set_has_det_fg_fraction() {
+  _has_bits_[0] |= 0x10000000u;
+}
+void V0LayerParameter::clear_has_det_fg_fraction() {
+  _has_bits_[0] &= ~0x10000000u;
+}
+void V0LayerParameter::clear_det_fg_fraction() {
+  det_fg_fraction_ = 0.25f;
+  clear_has_det_fg_fraction();
+}
+float V0LayerParameter::det_fg_fraction() const {
+  // @@protoc_insertion_point(field_get:caffe.V0LayerParameter.det_fg_fraction)
+  return det_fg_fraction_;
+}
+void V0LayerParameter::set_det_fg_fraction(float value) {
+  set_has_det_fg_fraction();
+  det_fg_fraction_ = value;
+  // @@protoc_insertion_point(field_set:caffe.V0LayerParameter.det_fg_fraction)
+}
+
+// optional uint32 det_context_pad = 58 [default = 0];
+bool V0LayerParameter::has_det_context_pad() const {
+  return (_has_bits_[0] & 0x20000000u) != 0;
+}
+void V0LayerParameter::set_has_det_context_pad() {
+  _has_bits_[0] |= 0x20000000u;
+}
+void V0LayerParameter::clear_has_det_context_pad() {
+  _has_bits_[0] &= ~0x20000000u;
+}
+void V0LayerParameter::clear_det_context_pad() {
+  det_context_pad_ = 0u;
+  clear_has_det_context_pad();
+}
+::google::protobuf::uint32 V0LayerParameter::det_context_pad() const {
+  // @@protoc_insertion_point(field_get:caffe.V0LayerParameter.det_context_pad)
+  return det_context_pad_;
+}
+void V0LayerParameter::set_det_context_pad(::google::protobuf::uint32 value) {
+  set_has_det_context_pad();
+  det_context_pad_ = value;
+  // @@protoc_insertion_point(field_set:caffe.V0LayerParameter.det_context_pad)
+}
+
+// optional string det_crop_mode = 59 [default = "warp"];
+bool V0LayerParameter::has_det_crop_mode() const {
+  return (_has_bits_[0] & 0x40000000u) != 0;
+}
+void V0LayerParameter::set_has_det_crop_mode() {
+  _has_bits_[0] |= 0x40000000u;
+}
+void V0LayerParameter::clear_has_det_crop_mode() {
+  _has_bits_[0] &= ~0x40000000u;
+}
+void V0LayerParameter::clear_det_crop_mode() {
+  det_crop_mode_.ClearToDefaultNoArena(_default_det_crop_mode_);
+  clear_has_det_crop_mode();
+}
+const ::std::string& V0LayerParameter::det_crop_mode() const {
+  // @@protoc_insertion_point(field_get:caffe.V0LayerParameter.det_crop_mode)
+  return det_crop_mode_.GetNoArena(_default_det_crop_mode_);
+}
+void V0LayerParameter::set_det_crop_mode(const ::std::string& value) {
+  set_has_det_crop_mode();
+  det_crop_mode_.SetNoArena(_default_det_crop_mode_, value);
+  // @@protoc_insertion_point(field_set:caffe.V0LayerParameter.det_crop_mode)
+}
+void V0LayerParameter::set_det_crop_mode(const char* value) {
+  set_has_det_crop_mode();
+  det_crop_mode_.SetNoArena(_default_det_crop_mode_, ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:caffe.V0LayerParameter.det_crop_mode)
+}
+void V0LayerParameter::set_det_crop_mode(const char* value, size_t size) {
+  set_has_det_crop_mode();
+  det_crop_mode_.SetNoArena(_default_det_crop_mode_,
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:caffe.V0LayerParameter.det_crop_mode)
+}
+::std::string* V0LayerParameter::mutable_det_crop_mode() {
+  set_has_det_crop_mode();
+  // @@protoc_insertion_point(field_mutable:caffe.V0LayerParameter.det_crop_mode)
+  return det_crop_mode_.MutableNoArena(_default_det_crop_mode_);
+}
+::std::string* V0LayerParameter::release_det_crop_mode() {
+  // @@protoc_insertion_point(field_release:caffe.V0LayerParameter.det_crop_mode)
+  clear_has_det_crop_mode();
+  return det_crop_mode_.ReleaseNoArena(_default_det_crop_mode_);
+}
+void V0LayerParameter::set_allocated_det_crop_mode(::std::string* det_crop_mode) {
+  if (det_crop_mode != NULL) {
+    set_has_det_crop_mode();
+  } else {
+    clear_has_det_crop_mode();
+  }
+  det_crop_mode_.SetAllocatedNoArena(_default_det_crop_mode_, det_crop_mode);
+  // @@protoc_insertion_point(field_set_allocated:caffe.V0LayerParameter.det_crop_mode)
+}
+
+// optional int32 new_num = 60 [default = 0];
+bool V0LayerParameter::has_new_num() const {
+  return (_has_bits_[0] & 0x80000000u) != 0;
+}
+void V0LayerParameter::set_has_new_num() {
+  _has_bits_[0] |= 0x80000000u;
+}
+void V0LayerParameter::clear_has_new_num() {
+  _has_bits_[0] &= ~0x80000000u;
+}
+void V0LayerParameter::clear_new_num() {
+  new_num_ = 0;
+  clear_has_new_num();
+}
+::google::protobuf::int32 V0LayerParameter::new_num() const {
+  // @@protoc_insertion_point(field_get:caffe.V0LayerParameter.new_num)
+  return new_num_;
+}
+void V0LayerParameter::set_new_num(::google::protobuf::int32 value) {
+  set_has_new_num();
+  new_num_ = value;
+  // @@protoc_insertion_point(field_set:caffe.V0LayerParameter.new_num)
+}
+
+// optional int32 new_channels = 61 [default = 0];
+bool V0LayerParameter::has_new_channels() const {
+  return (_has_bits_[1] & 0x00000001u) != 0;
+}
+void V0LayerParameter::set_has_new_channels() {
+  _has_bits_[1] |= 0x00000001u;
+}
+void V0LayerParameter::clear_has_new_channels() {
+  _has_bits_[1] &= ~0x00000001u;
+}
+void V0LayerParameter::clear_new_channels() {
+  new_channels_ = 0;
+  clear_has_new_channels();
+}
+::google::protobuf::int32 V0LayerParameter::new_channels() const {
+  // @@protoc_insertion_point(field_get:caffe.V0LayerParameter.new_channels)
+  return new_channels_;
+}
+void V0LayerParameter::set_new_channels(::google::protobuf::int32 value) {
+  set_has_new_channels();
+  new_channels_ = value;
+  // @@protoc_insertion_point(field_set:caffe.V0LayerParameter.new_channels)
+}
+
+// optional int32 new_height = 62 [default = 0];
+bool V0LayerParameter::has_new_height() const {
+  return (_has_bits_[1] & 0x00000002u) != 0;
+}
+void V0LayerParameter::set_has_new_height() {
+  _has_bits_[1] |= 0x00000002u;
+}
+void V0LayerParameter::clear_has_new_height() {
+  _has_bits_[1] &= ~0x00000002u;
+}
+void V0LayerParameter::clear_new_height() {
+  new_height_ = 0;
+  clear_has_new_height();
+}
+::google::protobuf::int32 V0LayerParameter::new_height() const {
+  // @@protoc_insertion_point(field_get:caffe.V0LayerParameter.new_height)
+  return new_height_;
+}
+void V0LayerParameter::set_new_height(::google::protobuf::int32 value) {
+  set_has_new_height();
+  new_height_ = value;
+  // @@protoc_insertion_point(field_set:caffe.V0LayerParameter.new_height)
+}
+
+// optional int32 new_width = 63 [default = 0];
+bool V0LayerParameter::has_new_width() const {
+  return (_has_bits_[1] & 0x00000004u) != 0;
+}
+void V0LayerParameter::set_has_new_width() {
+  _has_bits_[1] |= 0x00000004u;
+}
+void V0LayerParameter::clear_has_new_width() {
+  _has_bits_[1] &= ~0x00000004u;
+}
+void V0LayerParameter::clear_new_width() {
+  new_width_ = 0;
+  clear_has_new_width();
+}
+::google::protobuf::int32 V0LayerParameter::new_width() const {
+  // @@protoc_insertion_point(field_get:caffe.V0LayerParameter.new_width)
+  return new_width_;
+}
+void V0LayerParameter::set_new_width(::google::protobuf::int32 value) {
+  set_has_new_width();
+  new_width_ = value;
+  // @@protoc_insertion_point(field_set:caffe.V0LayerParameter.new_width)
+}
+
+// optional bool shuffle_images = 64 [default = false];
+bool V0LayerParameter::has_shuffle_images() const {
+  return (_has_bits_[1] & 0x00000008u) != 0;
+}
+void V0LayerParameter::set_has_shuffle_images() {
+  _has_bits_[1] |= 0x00000008u;
+}
+void V0LayerParameter::clear_has_shuffle_images() {
+  _has_bits_[1] &= ~0x00000008u;
+}
+void V0LayerParameter::clear_shuffle_images() {
+  shuffle_images_ = false;
+  clear_has_shuffle_images();
+}
+bool V0LayerParameter::shuffle_images() const {
+  // @@protoc_insertion_point(field_get:caffe.V0LayerParameter.shuffle_images)
+  return shuffle_images_;
+}
+void V0LayerParameter::set_shuffle_images(bool value) {
+  set_has_shuffle_images();
+  shuffle_images_ = value;
+  // @@protoc_insertion_point(field_set:caffe.V0LayerParameter.shuffle_images)
+}
+
+// optional uint32 concat_dim = 65 [default = 1];
+bool V0LayerParameter::has_concat_dim() const {
+  return (_has_bits_[1] & 0x00000010u) != 0;
+}
+void V0LayerParameter::set_has_concat_dim() {
+  _has_bits_[1] |= 0x00000010u;
+}
+void V0LayerParameter::clear_has_concat_dim() {
+  _has_bits_[1] &= ~0x00000010u;
+}
+void V0LayerParameter::clear_concat_dim() {
+  concat_dim_ = 1u;
+  clear_has_concat_dim();
+}
+::google::protobuf::uint32 V0LayerParameter::concat_dim() const {
+  // @@protoc_insertion_point(field_get:caffe.V0LayerParameter.concat_dim)
+  return concat_dim_;
+}
+void V0LayerParameter::set_concat_dim(::google::protobuf::uint32 value) {
+  set_has_concat_dim();
+  concat_dim_ = value;
+  // @@protoc_insertion_point(field_set:caffe.V0LayerParameter.concat_dim)
+}
+
+// optional .caffe.HDF5OutputParameter hdf5_output_param = 1001;
+bool V0LayerParameter::has_hdf5_output_param() const {
+  return (_has_bits_[1] & 0x00000020u) != 0;
+}
+void V0LayerParameter::set_has_hdf5_output_param() {
+  _has_bits_[1] |= 0x00000020u;
+}
+void V0LayerParameter::clear_has_hdf5_output_param() {
+  _has_bits_[1] &= ~0x00000020u;
+}
+void V0LayerParameter::clear_hdf5_output_param() {
+  if (hdf5_output_param_ != NULL) hdf5_output_param_->::caffe::HDF5OutputParameter::Clear();
+  clear_has_hdf5_output_param();
+}
+const ::caffe::HDF5OutputParameter& V0LayerParameter::hdf5_output_param() const {
+  // @@protoc_insertion_point(field_get:caffe.V0LayerParameter.hdf5_output_param)
+  return hdf5_output_param_ != NULL ? *hdf5_output_param_
+                         : *::caffe::HDF5OutputParameter::internal_default_instance();
+}
+::caffe::HDF5OutputParameter* V0LayerParameter::mutable_hdf5_output_param() {
+  set_has_hdf5_output_param();
+  if (hdf5_output_param_ == NULL) {
+    hdf5_output_param_ = new ::caffe::HDF5OutputParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.V0LayerParameter.hdf5_output_param)
+  return hdf5_output_param_;
+}
+::caffe::HDF5OutputParameter* V0LayerParameter::release_hdf5_output_param() {
+  // @@protoc_insertion_point(field_release:caffe.V0LayerParameter.hdf5_output_param)
+  clear_has_hdf5_output_param();
+  ::caffe::HDF5OutputParameter* temp = hdf5_output_param_;
+  hdf5_output_param_ = NULL;
+  return temp;
+}
+void V0LayerParameter::set_allocated_hdf5_output_param(::caffe::HDF5OutputParameter* hdf5_output_param) {
+  delete hdf5_output_param_;
+  hdf5_output_param_ = hdf5_output_param;
+  if (hdf5_output_param) {
+    set_has_hdf5_output_param();
+  } else {
+    clear_has_hdf5_output_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.V0LayerParameter.hdf5_output_param)
+}
+
+inline const V0LayerParameter* V0LayerParameter::internal_default_instance() {
+  return &V0LayerParameter_default_instance_.get();
+}
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
+
+// ===================================================================
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const int PReLUParameter::kFillerFieldNumber;
+const int PReLUParameter::kChannelSharedFieldNumber;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+
+PReLUParameter::PReLUParameter()
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+  if (this != internal_default_instance()) protobuf_InitDefaults_caffe_2eproto();
+  SharedCtor();
+  // @@protoc_insertion_point(constructor:caffe.PReLUParameter)
+}
+
+void PReLUParameter::InitAsDefaultInstance() {
+  filler_ = const_cast< ::caffe::FillerParameter*>(
+      ::caffe::FillerParameter::internal_default_instance());
+}
+
+PReLUParameter::PReLUParameter(const PReLUParameter& from)
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
+  SharedCtor();
+  UnsafeMergeFrom(from);
+  // @@protoc_insertion_point(copy_constructor:caffe.PReLUParameter)
+}
+
+void PReLUParameter::SharedCtor() {
+  _cached_size_ = 0;
+  filler_ = NULL;
+  channel_shared_ = false;
+}
+
+PReLUParameter::~PReLUParameter() {
+  // @@protoc_insertion_point(destructor:caffe.PReLUParameter)
+  SharedDtor();
+}
+
+void PReLUParameter::SharedDtor() {
+  if (this != &PReLUParameter_default_instance_.get()) {
+    delete filler_;
+  }
+}
+
+void PReLUParameter::SetCachedSize(int size) const {
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* PReLUParameter::descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return PReLUParameter_descriptor_;
+}
+
+const PReLUParameter& PReLUParameter::default_instance() {
+  protobuf_InitDefaults_caffe_2eproto();
+  return *internal_default_instance();
+}
+
+::google::protobuf::internal::ExplicitlyConstructed<PReLUParameter> PReLUParameter_default_instance_;
+
+PReLUParameter* PReLUParameter::New(::google::protobuf::Arena* arena) const {
+  PReLUParameter* n = new PReLUParameter;
+  if (arena != NULL) {
+    arena->Own(n);
+  }
+  return n;
+}
+
+void PReLUParameter::Clear() {
+// @@protoc_insertion_point(message_clear_start:caffe.PReLUParameter)
+  if (_has_bits_[0 / 32] & 3u) {
+    if (has_filler()) {
+      if (filler_ != NULL) filler_->::caffe::FillerParameter::Clear();
+    }
+    channel_shared_ = false;
+  }
+  _has_bits_.Clear();
+  if (_internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->Clear();
+  }
+}
+
+bool PReLUParameter::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
+  ::google::protobuf::uint32 tag;
+  // @@protoc_insertion_point(parse_start:caffe.PReLUParameter)
+  for (;;) {
+    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+    tag = p.first;
+    if (!p.second) goto handle_unusual;
+    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+      // optional .caffe.FillerParameter filler = 1;
+      case 1: {
+        if (tag == 10) {
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+               input, mutable_filler()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(16)) goto parse_channel_shared;
+        break;
+      }
+
+      // optional bool channel_shared = 2 [default = false];
+      case 2: {
+        if (tag == 16) {
+         parse_channel_shared:
+          set_has_channel_shared();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>(
+                 input, &channel_shared_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectAtEnd()) goto success;
+        break;
+      }
+
+      default: {
+      handle_unusual:
+        if (tag == 0 ||
+            ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+          goto success;
+        }
+        DO_(::google::protobuf::internal::WireFormat::SkipField(
+              input, tag, mutable_unknown_fields()));
+        break;
+      }
+    }
+  }
+success:
+  // @@protoc_insertion_point(parse_success:caffe.PReLUParameter)
+  return true;
+failure:
+  // @@protoc_insertion_point(parse_failure:caffe.PReLUParameter)
+  return false;
+#undef DO_
+}
+
+void PReLUParameter::SerializeWithCachedSizes(
+    ::google::protobuf::io::CodedOutputStream* output) const {
+  // @@protoc_insertion_point(serialize_start:caffe.PReLUParameter)
+  // optional .caffe.FillerParameter filler = 1;
+  if (has_filler()) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      1, *this->filler_, output);
+  }
+
+  // optional bool channel_shared = 2 [default = false];
+  if (has_channel_shared()) {
+    ::google::protobuf::internal::WireFormatLite::WriteBool(2, this->channel_shared(), output);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
+        unknown_fields(), output);
+  }
+  // @@protoc_insertion_point(serialize_end:caffe.PReLUParameter)
+}
+
+::google::protobuf::uint8* PReLUParameter::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
+  (void)deterministic; // Unused
+  // @@protoc_insertion_point(serialize_to_array_start:caffe.PReLUParameter)
+  // optional .caffe.FillerParameter filler = 1;
+  if (has_filler()) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        1, *this->filler_, false, target);
+  }
+
+  // optional bool channel_shared = 2 [default = false];
+  if (has_channel_shared()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(2, this->channel_shared(), target);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
+        unknown_fields(), target);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:caffe.PReLUParameter)
+  return target;
+}
+
+size_t PReLUParameter::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:caffe.PReLUParameter)
+  size_t total_size = 0;
+
+  if (_has_bits_[0 / 32] & 3u) {
+    // optional .caffe.FillerParameter filler = 1;
+    if (has_filler()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          *this->filler_);
+    }
+
+    // optional bool channel_shared = 2 [default = false];
+    if (has_channel_shared()) {
+      total_size += 1 + 1;
+    }
+
+  }
+  if (_internal_metadata_.have_unknown_fields()) {
+    total_size +=
+      ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
+        unknown_fields());
+  }
+  int cached_size = ::google::protobuf::internal::ToCachedSize(total_size);
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = cached_size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+  return total_size;
+}
+
+void PReLUParameter::MergeFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_merge_from_start:caffe.PReLUParameter)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const PReLUParameter* source =
+      ::google::protobuf::internal::DynamicCastToGenerated<const PReLUParameter>(
+          &from);
+  if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:caffe.PReLUParameter)
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:caffe.PReLUParameter)
+    UnsafeMergeFrom(*source);
+  }
+}
+
+void PReLUParameter::MergeFrom(const PReLUParameter& from) {
+// @@protoc_insertion_point(class_specific_merge_from_start:caffe.PReLUParameter)
+  if (GOOGLE_PREDICT_TRUE(&from != this)) {
+    UnsafeMergeFrom(from);
+  } else {
+    MergeFromFail(__LINE__);
+  }
+}
+
+void PReLUParameter::UnsafeMergeFrom(const PReLUParameter& from) {
+  GOOGLE_DCHECK(&from != this);
+  if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+    if (from.has_filler()) {
+      mutable_filler()->::caffe::FillerParameter::MergeFrom(from.filler());
+    }
+    if (from.has_channel_shared()) {
+      set_channel_shared(from.channel_shared());
+    }
+  }
+  if (from._internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::UnknownFieldSet::MergeToInternalMetdata(
+      from.unknown_fields(), &_internal_metadata_);
+  }
+}
+
+void PReLUParameter::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:caffe.PReLUParameter)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void PReLUParameter::CopyFrom(const PReLUParameter& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:caffe.PReLUParameter)
+  if (&from == this) return;
+  Clear();
+  UnsafeMergeFrom(from);
+}
+
+bool PReLUParameter::IsInitialized() const {
+
+  return true;
+}
+
+void PReLUParameter::Swap(PReLUParameter* other) {
+  if (other == this) return;
+  InternalSwap(other);
+}
+void PReLUParameter::InternalSwap(PReLUParameter* other) {
+  std::swap(filler_, other->filler_);
+  std::swap(channel_shared_, other->channel_shared_);
+  std::swap(_has_bits_[0], other->_has_bits_[0]);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
+}
+
+::google::protobuf::Metadata PReLUParameter::GetMetadata() const {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::Metadata metadata;
+  metadata.descriptor = PReLUParameter_descriptor_;
+  metadata.reflection = PReLUParameter_reflection_;
+  return metadata;
+}
+
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// PReLUParameter
+
+// optional .caffe.FillerParameter filler = 1;
+bool PReLUParameter::has_filler() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+void PReLUParameter::set_has_filler() {
+  _has_bits_[0] |= 0x00000001u;
+}
+void PReLUParameter::clear_has_filler() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+void PReLUParameter::clear_filler() {
+  if (filler_ != NULL) filler_->::caffe::FillerParameter::Clear();
+  clear_has_filler();
+}
+const ::caffe::FillerParameter& PReLUParameter::filler() const {
+  // @@protoc_insertion_point(field_get:caffe.PReLUParameter.filler)
+  return filler_ != NULL ? *filler_
+                         : *::caffe::FillerParameter::internal_default_instance();
+}
+::caffe::FillerParameter* PReLUParameter::mutable_filler() {
+  set_has_filler();
+  if (filler_ == NULL) {
+    filler_ = new ::caffe::FillerParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.PReLUParameter.filler)
+  return filler_;
+}
+::caffe::FillerParameter* PReLUParameter::release_filler() {
+  // @@protoc_insertion_point(field_release:caffe.PReLUParameter.filler)
+  clear_has_filler();
+  ::caffe::FillerParameter* temp = filler_;
+  filler_ = NULL;
+  return temp;
+}
+void PReLUParameter::set_allocated_filler(::caffe::FillerParameter* filler) {
+  delete filler_;
+  filler_ = filler;
+  if (filler) {
+    set_has_filler();
+  } else {
+    clear_has_filler();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.PReLUParameter.filler)
+}
+
+// optional bool channel_shared = 2 [default = false];
+bool PReLUParameter::has_channel_shared() const {
+  return (_has_bits_[0] & 0x00000002u) != 0;
+}
+void PReLUParameter::set_has_channel_shared() {
+  _has_bits_[0] |= 0x00000002u;
+}
+void PReLUParameter::clear_has_channel_shared() {
+  _has_bits_[0] &= ~0x00000002u;
+}
+void PReLUParameter::clear_channel_shared() {
+  channel_shared_ = false;
+  clear_has_channel_shared();
+}
+bool PReLUParameter::channel_shared() const {
+  // @@protoc_insertion_point(field_get:caffe.PReLUParameter.channel_shared)
+  return channel_shared_;
+}
+void PReLUParameter::set_channel_shared(bool value) {
+  set_has_channel_shared();
+  channel_shared_ = value;
+  // @@protoc_insertion_point(field_set:caffe.PReLUParameter.channel_shared)
+}
+
+inline const PReLUParameter* PReLUParameter::internal_default_instance() {
+  return &PReLUParameter_default_instance_.get();
+}
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
+
+// ===================================================================
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const int NormalizedBBox::kXminFieldNumber;
+const int NormalizedBBox::kYminFieldNumber;
+const int NormalizedBBox::kXmaxFieldNumber;
+const int NormalizedBBox::kYmaxFieldNumber;
+const int NormalizedBBox::kLabelFieldNumber;
+const int NormalizedBBox::kDifficultFieldNumber;
+const int NormalizedBBox::kScoreFieldNumber;
+const int NormalizedBBox::kSizeFieldNumber;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+
+NormalizedBBox::NormalizedBBox()
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+  if (this != internal_default_instance()) protobuf_InitDefaults_caffe_2eproto();
+  SharedCtor();
+  // @@protoc_insertion_point(constructor:caffe.NormalizedBBox)
+}
+
+void NormalizedBBox::InitAsDefaultInstance() {
+}
+
+NormalizedBBox::NormalizedBBox(const NormalizedBBox& from)
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
+  SharedCtor();
+  UnsafeMergeFrom(from);
+  // @@protoc_insertion_point(copy_constructor:caffe.NormalizedBBox)
+}
+
+void NormalizedBBox::SharedCtor() {
+  _cached_size_ = 0;
+  ::memset(&xmin_, 0, reinterpret_cast<char*>(&size_) -
+    reinterpret_cast<char*>(&xmin_) + sizeof(size_));
+}
+
+NormalizedBBox::~NormalizedBBox() {
+  // @@protoc_insertion_point(destructor:caffe.NormalizedBBox)
+  SharedDtor();
+}
+
+void NormalizedBBox::SharedDtor() {
+}
+
+void NormalizedBBox::SetCachedSize(int size) const {
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* NormalizedBBox::descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return NormalizedBBox_descriptor_;
+}
+
+const NormalizedBBox& NormalizedBBox::default_instance() {
+  protobuf_InitDefaults_caffe_2eproto();
+  return *internal_default_instance();
+}
+
+::google::protobuf::internal::ExplicitlyConstructed<NormalizedBBox> NormalizedBBox_default_instance_;
+
+NormalizedBBox* NormalizedBBox::New(::google::protobuf::Arena* arena) const {
+  NormalizedBBox* n = new NormalizedBBox;
+  if (arena != NULL) {
+    arena->Own(n);
+  }
+  return n;
+}
+
+void NormalizedBBox::Clear() {
+// @@protoc_insertion_point(message_clear_start:caffe.NormalizedBBox)
+#if defined(__clang__)
+#define ZR_HELPER_(f) \
+  _Pragma("clang diagnostic push") \
+  _Pragma("clang diagnostic ignored \"-Winvalid-offsetof\"") \
+  __builtin_offsetof(NormalizedBBox, f) \
+  _Pragma("clang diagnostic pop")
+#else
+#define ZR_HELPER_(f) reinterpret_cast<char*>(\
+  &reinterpret_cast<NormalizedBBox*>(16)->f)
+#endif
+
+#define ZR_(first, last) do {\
+  ::memset(&(first), 0,\
+           ZR_HELPER_(last) - ZR_HELPER_(first) + sizeof(last));\
+} while (0)
+
+  ZR_(xmin_, size_);
+
+#undef ZR_HELPER_
+#undef ZR_
+
+  _has_bits_.Clear();
+  if (_internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->Clear();
+  }
+}
+
+bool NormalizedBBox::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
+  ::google::protobuf::uint32 tag;
+  // @@protoc_insertion_point(parse_start:caffe.NormalizedBBox)
+  for (;;) {
+    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+    tag = p.first;
+    if (!p.second) goto handle_unusual;
+    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+      // optional float xmin = 1;
+      case 1: {
+        if (tag == 13) {
+          set_has_xmin();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
+                 input, &xmin_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(21)) goto parse_ymin;
+        break;
+      }
+
+      // optional float ymin = 2;
+      case 2: {
+        if (tag == 21) {
+         parse_ymin:
+          set_has_ymin();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
+                 input, &ymin_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(29)) goto parse_xmax;
+        break;
+      }
+
+      // optional float xmax = 3;
+      case 3: {
+        if (tag == 29) {
+         parse_xmax:
+          set_has_xmax();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
+                 input, &xmax_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(37)) goto parse_ymax;
+        break;
+      }
+
+      // optional float ymax = 4;
+      case 4: {
+        if (tag == 37) {
+         parse_ymax:
+          set_has_ymax();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
+                 input, &ymax_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(40)) goto parse_label;
+        break;
+      }
+
+      // optional int32 label = 5;
+      case 5: {
+        if (tag == 40) {
+         parse_label:
+          set_has_label();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
+                 input, &label_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(48)) goto parse_difficult;
+        break;
+      }
+
+      // optional bool difficult = 6;
+      case 6: {
+        if (tag == 48) {
+         parse_difficult:
+          set_has_difficult();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>(
+                 input, &difficult_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(61)) goto parse_score;
+        break;
+      }
+
+      // optional float score = 7;
+      case 7: {
+        if (tag == 61) {
+         parse_score:
+          set_has_score();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
+                 input, &score_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(69)) goto parse_size;
+        break;
+      }
+
+      // optional float size = 8;
+      case 8: {
+        if (tag == 69) {
+         parse_size:
+          set_has_size();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
+                 input, &size_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectAtEnd()) goto success;
+        break;
+      }
+
+      default: {
+      handle_unusual:
+        if (tag == 0 ||
+            ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+          goto success;
+        }
+        DO_(::google::protobuf::internal::WireFormat::SkipField(
+              input, tag, mutable_unknown_fields()));
+        break;
+      }
+    }
+  }
+success:
+  // @@protoc_insertion_point(parse_success:caffe.NormalizedBBox)
+  return true;
+failure:
+  // @@protoc_insertion_point(parse_failure:caffe.NormalizedBBox)
+  return false;
+#undef DO_
+}
+
+void NormalizedBBox::SerializeWithCachedSizes(
+    ::google::protobuf::io::CodedOutputStream* output) const {
+  // @@protoc_insertion_point(serialize_start:caffe.NormalizedBBox)
+  // optional float xmin = 1;
+  if (has_xmin()) {
+    ::google::protobuf::internal::WireFormatLite::WriteFloat(1, this->xmin(), output);
+  }
+
+  // optional float ymin = 2;
+  if (has_ymin()) {
+    ::google::protobuf::internal::WireFormatLite::WriteFloat(2, this->ymin(), output);
+  }
+
+  // optional float xmax = 3;
+  if (has_xmax()) {
+    ::google::protobuf::internal::WireFormatLite::WriteFloat(3, this->xmax(), output);
+  }
+
+  // optional float ymax = 4;
+  if (has_ymax()) {
+    ::google::protobuf::internal::WireFormatLite::WriteFloat(4, this->ymax(), output);
+  }
+
+  // optional int32 label = 5;
+  if (has_label()) {
+    ::google::protobuf::internal::WireFormatLite::WriteInt32(5, this->label(), output);
+  }
+
+  // optional bool difficult = 6;
+  if (has_difficult()) {
+    ::google::protobuf::internal::WireFormatLite::WriteBool(6, this->difficult(), output);
+  }
+
+  // optional float score = 7;
+  if (has_score()) {
+    ::google::protobuf::internal::WireFormatLite::WriteFloat(7, this->score(), output);
+  }
+
+  // optional float size = 8;
+  if (has_size()) {
+    ::google::protobuf::internal::WireFormatLite::WriteFloat(8, this->size(), output);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
+        unknown_fields(), output);
+  }
+  // @@protoc_insertion_point(serialize_end:caffe.NormalizedBBox)
+}
+
+::google::protobuf::uint8* NormalizedBBox::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
+  (void)deterministic; // Unused
+  // @@protoc_insertion_point(serialize_to_array_start:caffe.NormalizedBBox)
+  // optional float xmin = 1;
+  if (has_xmin()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteFloatToArray(1, this->xmin(), target);
+  }
+
+  // optional float ymin = 2;
+  if (has_ymin()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteFloatToArray(2, this->ymin(), target);
+  }
+
+  // optional float xmax = 3;
+  if (has_xmax()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteFloatToArray(3, this->xmax(), target);
+  }
+
+  // optional float ymax = 4;
+  if (has_ymax()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteFloatToArray(4, this->ymax(), target);
+  }
+
+  // optional int32 label = 5;
+  if (has_label()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteInt32ToArray(5, this->label(), target);
+  }
+
+  // optional bool difficult = 6;
+  if (has_difficult()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(6, this->difficult(), target);
+  }
+
+  // optional float score = 7;
+  if (has_score()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteFloatToArray(7, this->score(), target);
+  }
+
+  // optional float size = 8;
+  if (has_size()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteFloatToArray(8, this->size(), target);
+  }
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
+        unknown_fields(), target);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:caffe.NormalizedBBox)
+  return target;
+}
+
+size_t NormalizedBBox::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:caffe.NormalizedBBox)
+  size_t total_size = 0;
+
+  if (_has_bits_[0 / 32] & 255u) {
+    // optional float xmin = 1;
+    if (has_xmin()) {
+      total_size += 1 + 4;
+    }
+
+    // optional float ymin = 2;
+    if (has_ymin()) {
+      total_size += 1 + 4;
+    }
+
+    // optional float xmax = 3;
+    if (has_xmax()) {
+      total_size += 1 + 4;
+    }
+
+    // optional float ymax = 4;
+    if (has_ymax()) {
+      total_size += 1 + 4;
+    }
+
+    // optional int32 label = 5;
+    if (has_label()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::Int32Size(
+          this->label());
+    }
+
+    // optional bool difficult = 6;
+    if (has_difficult()) {
+      total_size += 1 + 1;
+    }
+
+    // optional float score = 7;
+    if (has_score()) {
+      total_size += 1 + 4;
+    }
+
+    // optional float size = 8;
+    if (has_size()) {
+      total_size += 1 + 4;
+    }
+
+  }
+  if (_internal_metadata_.have_unknown_fields()) {
+    total_size +=
+      ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
+        unknown_fields());
+  }
+  int cached_size = ::google::protobuf::internal::ToCachedSize(total_size);
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = cached_size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+  return total_size;
+}
+
+void NormalizedBBox::MergeFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_merge_from_start:caffe.NormalizedBBox)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const NormalizedBBox* source =
+      ::google::protobuf::internal::DynamicCastToGenerated<const NormalizedBBox>(
+          &from);
+  if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:caffe.NormalizedBBox)
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:caffe.NormalizedBBox)
+    UnsafeMergeFrom(*source);
+  }
+}
+
+void NormalizedBBox::MergeFrom(const NormalizedBBox& from) {
+// @@protoc_insertion_point(class_specific_merge_from_start:caffe.NormalizedBBox)
+  if (GOOGLE_PREDICT_TRUE(&from != this)) {
+    UnsafeMergeFrom(from);
+  } else {
+    MergeFromFail(__LINE__);
+  }
+}
+
+void NormalizedBBox::UnsafeMergeFrom(const NormalizedBBox& from) {
+  GOOGLE_DCHECK(&from != this);
+  if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) {
+    if (from.has_xmin()) {
+      set_xmin(from.xmin());
+    }
+    if (from.has_ymin()) {
+      set_ymin(from.ymin());
+    }
+    if (from.has_xmax()) {
+      set_xmax(from.xmax());
+    }
+    if (from.has_ymax()) {
+      set_ymax(from.ymax());
+    }
+    if (from.has_label()) {
+      set_label(from.label());
+    }
+    if (from.has_difficult()) {
+      set_difficult(from.difficult());
+    }
+    if (from.has_score()) {
+      set_score(from.score());
+    }
+    if (from.has_size()) {
+      set_size(from.size());
+    }
+  }
+  if (from._internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::UnknownFieldSet::MergeToInternalMetdata(
+      from.unknown_fields(), &_internal_metadata_);
+  }
+}
+
+void NormalizedBBox::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:caffe.NormalizedBBox)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void NormalizedBBox::CopyFrom(const NormalizedBBox& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:caffe.NormalizedBBox)
+  if (&from == this) return;
+  Clear();
+  UnsafeMergeFrom(from);
+}
+
+bool NormalizedBBox::IsInitialized() const {
+
+  return true;
+}
+
+void NormalizedBBox::Swap(NormalizedBBox* other) {
+  if (other == this) return;
+  InternalSwap(other);
+}
+void NormalizedBBox::InternalSwap(NormalizedBBox* other) {
+  std::swap(xmin_, other->xmin_);
+  std::swap(ymin_, other->ymin_);
+  std::swap(xmax_, other->xmax_);
+  std::swap(ymax_, other->ymax_);
+  std::swap(label_, other->label_);
+  std::swap(difficult_, other->difficult_);
+  std::swap(score_, other->score_);
+  std::swap(size_, other->size_);
+  std::swap(_has_bits_[0], other->_has_bits_[0]);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
+}
+
+::google::protobuf::Metadata NormalizedBBox::GetMetadata() const {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::Metadata metadata;
+  metadata.descriptor = NormalizedBBox_descriptor_;
+  metadata.reflection = NormalizedBBox_reflection_;
+  return metadata;
+}
+
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// NormalizedBBox
+
+// optional float xmin = 1;
+bool NormalizedBBox::has_xmin() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+void NormalizedBBox::set_has_xmin() {
+  _has_bits_[0] |= 0x00000001u;
+}
+void NormalizedBBox::clear_has_xmin() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+void NormalizedBBox::clear_xmin() {
+  xmin_ = 0;
+  clear_has_xmin();
+}
+float NormalizedBBox::xmin() const {
+  // @@protoc_insertion_point(field_get:caffe.NormalizedBBox.xmin)
+  return xmin_;
+}
+void NormalizedBBox::set_xmin(float value) {
+  set_has_xmin();
+  xmin_ = value;
+  // @@protoc_insertion_point(field_set:caffe.NormalizedBBox.xmin)
+}
+
+// optional float ymin = 2;
+bool NormalizedBBox::has_ymin() const {
+  return (_has_bits_[0] & 0x00000002u) != 0;
+}
+void NormalizedBBox::set_has_ymin() {
+  _has_bits_[0] |= 0x00000002u;
+}
+void NormalizedBBox::clear_has_ymin() {
+  _has_bits_[0] &= ~0x00000002u;
+}
+void NormalizedBBox::clear_ymin() {
+  ymin_ = 0;
+  clear_has_ymin();
+}
+float NormalizedBBox::ymin() const {
+  // @@protoc_insertion_point(field_get:caffe.NormalizedBBox.ymin)
+  return ymin_;
+}
+void NormalizedBBox::set_ymin(float value) {
+  set_has_ymin();
+  ymin_ = value;
+  // @@protoc_insertion_point(field_set:caffe.NormalizedBBox.ymin)
+}
+
+// optional float xmax = 3;
+bool NormalizedBBox::has_xmax() const {
+  return (_has_bits_[0] & 0x00000004u) != 0;
+}
+void NormalizedBBox::set_has_xmax() {
+  _has_bits_[0] |= 0x00000004u;
+}
+void NormalizedBBox::clear_has_xmax() {
+  _has_bits_[0] &= ~0x00000004u;
+}
+void NormalizedBBox::clear_xmax() {
+  xmax_ = 0;
+  clear_has_xmax();
+}
+float NormalizedBBox::xmax() const {
+  // @@protoc_insertion_point(field_get:caffe.NormalizedBBox.xmax)
+  return xmax_;
+}
+void NormalizedBBox::set_xmax(float value) {
+  set_has_xmax();
+  xmax_ = value;
+  // @@protoc_insertion_point(field_set:caffe.NormalizedBBox.xmax)
+}
+
+// optional float ymax = 4;
+bool NormalizedBBox::has_ymax() const {
+  return (_has_bits_[0] & 0x00000008u) != 0;
+}
+void NormalizedBBox::set_has_ymax() {
+  _has_bits_[0] |= 0x00000008u;
+}
+void NormalizedBBox::clear_has_ymax() {
+  _has_bits_[0] &= ~0x00000008u;
+}
+void NormalizedBBox::clear_ymax() {
+  ymax_ = 0;
+  clear_has_ymax();
+}
+float NormalizedBBox::ymax() const {
+  // @@protoc_insertion_point(field_get:caffe.NormalizedBBox.ymax)
+  return ymax_;
+}
+void NormalizedBBox::set_ymax(float value) {
+  set_has_ymax();
+  ymax_ = value;
+  // @@protoc_insertion_point(field_set:caffe.NormalizedBBox.ymax)
+}
+
+// optional int32 label = 5;
+bool NormalizedBBox::has_label() const {
+  return (_has_bits_[0] & 0x00000010u) != 0;
+}
+void NormalizedBBox::set_has_label() {
+  _has_bits_[0] |= 0x00000010u;
+}
+void NormalizedBBox::clear_has_label() {
+  _has_bits_[0] &= ~0x00000010u;
+}
+void NormalizedBBox::clear_label() {
+  label_ = 0;
+  clear_has_label();
+}
+::google::protobuf::int32 NormalizedBBox::label() const {
+  // @@protoc_insertion_point(field_get:caffe.NormalizedBBox.label)
+  return label_;
+}
+void NormalizedBBox::set_label(::google::protobuf::int32 value) {
+  set_has_label();
+  label_ = value;
+  // @@protoc_insertion_point(field_set:caffe.NormalizedBBox.label)
+}
+
+// optional bool difficult = 6;
+bool NormalizedBBox::has_difficult() const {
+  return (_has_bits_[0] & 0x00000020u) != 0;
+}
+void NormalizedBBox::set_has_difficult() {
+  _has_bits_[0] |= 0x00000020u;
+}
+void NormalizedBBox::clear_has_difficult() {
+  _has_bits_[0] &= ~0x00000020u;
+}
+void NormalizedBBox::clear_difficult() {
+  difficult_ = false;
+  clear_has_difficult();
+}
+bool NormalizedBBox::difficult() const {
+  // @@protoc_insertion_point(field_get:caffe.NormalizedBBox.difficult)
+  return difficult_;
+}
+void NormalizedBBox::set_difficult(bool value) {
+  set_has_difficult();
+  difficult_ = value;
+  // @@protoc_insertion_point(field_set:caffe.NormalizedBBox.difficult)
+}
+
+// optional float score = 7;
+bool NormalizedBBox::has_score() const {
+  return (_has_bits_[0] & 0x00000040u) != 0;
+}
+void NormalizedBBox::set_has_score() {
+  _has_bits_[0] |= 0x00000040u;
+}
+void NormalizedBBox::clear_has_score() {
+  _has_bits_[0] &= ~0x00000040u;
+}
+void NormalizedBBox::clear_score() {
+  score_ = 0;
+  clear_has_score();
+}
+float NormalizedBBox::score() const {
+  // @@protoc_insertion_point(field_get:caffe.NormalizedBBox.score)
+  return score_;
+}
+void NormalizedBBox::set_score(float value) {
+  set_has_score();
+  score_ = value;
+  // @@protoc_insertion_point(field_set:caffe.NormalizedBBox.score)
+}
+
+// optional float size = 8;
+bool NormalizedBBox::has_size() const {
+  return (_has_bits_[0] & 0x00000080u) != 0;
+}
+void NormalizedBBox::set_has_size() {
+  _has_bits_[0] |= 0x00000080u;
+}
+void NormalizedBBox::clear_has_size() {
+  _has_bits_[0] &= ~0x00000080u;
+}
+void NormalizedBBox::clear_size() {
+  size_ = 0;
+  clear_has_size();
+}
+float NormalizedBBox::size() const {
+  // @@protoc_insertion_point(field_get:caffe.NormalizedBBox.size)
+  return size_;
+}
+void NormalizedBBox::set_size(float value) {
+  set_has_size();
+  size_ = value;
+  // @@protoc_insertion_point(field_set:caffe.NormalizedBBox.size)
+}
+
+inline const NormalizedBBox* NormalizedBBox::internal_default_instance() {
+  return &NormalizedBBox_default_instance_.get();
+}
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
+
+// @@protoc_insertion_point(namespace_scope)
+
+}  // namespace caffe
+
+// @@protoc_insertion_point(global_scope)
diff --git a/contrib/modules/dnn/misc/caffe/caffe.pb.h b/contrib/modules/dnn/misc/caffe/caffe.pb.h
new file mode 100644
index 0000000..84ee770
--- /dev/null
+++ b/contrib/modules/dnn/misc/caffe/caffe.pb.h
@@ -0,0 +1,24439 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: caffe.proto
+
+#ifndef PROTOBUF_caffe_2eproto__INCLUDED
+#define PROTOBUF_caffe_2eproto__INCLUDED
+
+#include <string>
+
+#include <google/protobuf/stubs/common.h>
+
+#if GOOGLE_PROTOBUF_VERSION < 3001000
+#error This file was generated by a newer version of protoc which is
+#error incompatible with your Protocol Buffer headers.  Please update
+#error your headers.
+#endif
+#if 3001000 < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION
+#error This file was generated by an older version of protoc which is
+#error incompatible with your Protocol Buffer headers.  Please
+#error regenerate this file with a newer version of protoc.
+#endif
+
+#include <google/protobuf/arena.h>
+#include <google/protobuf/arenastring.h>
+#include <google/protobuf/generated_message_util.h>
+#include <google/protobuf/metadata.h>
+#include <google/protobuf/message.h>
+#include <google/protobuf/repeated_field.h>
+#include <google/protobuf/extension_set.h>
+#include <google/protobuf/generated_enum_reflection.h>
+#include <google/protobuf/unknown_field_set.h>
+// @@protoc_insertion_point(includes)
+
+namespace caffe {
+
+// Internal implementation detail -- do not call these.
+void protobuf_AddDesc_caffe_2eproto();
+void protobuf_InitDefaults_caffe_2eproto();
+void protobuf_AssignDesc_caffe_2eproto();
+void protobuf_ShutdownFile_caffe_2eproto();
+
+class AccuracyParameter;
+class ArgMaxParameter;
+class BlobProto;
+class BlobProtoVector;
+class BlobShape;
+class ConcatParameter;
+class ContrastiveLossParameter;
+class ConvolutionParameter;
+class CropParameter;
+class DataParameter;
+class Datum;
+class DetectionOutputParameter;
+class DropoutParameter;
+class DummyDataParameter;
+class EltwiseParameter;
+class ExpParameter;
+class FillerParameter;
+class FlattenParameter;
+class HDF5DataParameter;
+class HDF5OutputParameter;
+class HingeLossParameter;
+class ImageDataParameter;
+class InfogainLossParameter;
+class InnerProductParameter;
+class LRNParameter;
+class LayerParameter;
+class LogParameter;
+class LossParameter;
+class MVNParameter;
+class MemoryDataParameter;
+class NetParameter;
+class NetState;
+class NetStateRule;
+class NormalizeBBoxParameter;
+class NormalizedBBox;
+class PReLUParameter;
+class ParamSpec;
+class PermuteParameter;
+class PoolingParameter;
+class PowerParameter;
+class PriorBoxParameter;
+class PythonParameter;
+class ReLUParameter;
+class ReductionParameter;
+class ReshapeParameter;
+class SPPParameter;
+class SigmoidParameter;
+class SliceParameter;
+class SoftmaxParameter;
+class SolverParameter;
+class SolverState;
+class TanHParameter;
+class ThresholdParameter;
+class TransformationParameter;
+class V0LayerParameter;
+class V1LayerParameter;
+class WindowDataParameter;
+
+enum PriorBoxParameter_CodeType {
+  PriorBoxParameter_CodeType_CORNER = 1,
+  PriorBoxParameter_CodeType_CENTER_SIZE = 2
+};
+bool PriorBoxParameter_CodeType_IsValid(int value);
+const PriorBoxParameter_CodeType PriorBoxParameter_CodeType_CodeType_MIN = PriorBoxParameter_CodeType_CORNER;
+const PriorBoxParameter_CodeType PriorBoxParameter_CodeType_CodeType_MAX = PriorBoxParameter_CodeType_CENTER_SIZE;
+const int PriorBoxParameter_CodeType_CodeType_ARRAYSIZE = PriorBoxParameter_CodeType_CodeType_MAX + 1;
+
+const ::google::protobuf::EnumDescriptor* PriorBoxParameter_CodeType_descriptor();
+inline const ::std::string& PriorBoxParameter_CodeType_Name(PriorBoxParameter_CodeType value) {
+  return ::google::protobuf::internal::NameOfEnum(
+    PriorBoxParameter_CodeType_descriptor(), value);
+}
+inline bool PriorBoxParameter_CodeType_Parse(
+    const ::std::string& name, PriorBoxParameter_CodeType* value) {
+  return ::google::protobuf::internal::ParseNamedEnum<PriorBoxParameter_CodeType>(
+    PriorBoxParameter_CodeType_descriptor(), name, value);
+}
+enum FillerParameter_VarianceNorm {
+  FillerParameter_VarianceNorm_FAN_IN = 0,
+  FillerParameter_VarianceNorm_FAN_OUT = 1,
+  FillerParameter_VarianceNorm_AVERAGE = 2
+};
+bool FillerParameter_VarianceNorm_IsValid(int value);
+const FillerParameter_VarianceNorm FillerParameter_VarianceNorm_VarianceNorm_MIN = FillerParameter_VarianceNorm_FAN_IN;
+const FillerParameter_VarianceNorm FillerParameter_VarianceNorm_VarianceNorm_MAX = FillerParameter_VarianceNorm_AVERAGE;
+const int FillerParameter_VarianceNorm_VarianceNorm_ARRAYSIZE = FillerParameter_VarianceNorm_VarianceNorm_MAX + 1;
+
+const ::google::protobuf::EnumDescriptor* FillerParameter_VarianceNorm_descriptor();
+inline const ::std::string& FillerParameter_VarianceNorm_Name(FillerParameter_VarianceNorm value) {
+  return ::google::protobuf::internal::NameOfEnum(
+    FillerParameter_VarianceNorm_descriptor(), value);
+}
+inline bool FillerParameter_VarianceNorm_Parse(
+    const ::std::string& name, FillerParameter_VarianceNorm* value) {
+  return ::google::protobuf::internal::ParseNamedEnum<FillerParameter_VarianceNorm>(
+    FillerParameter_VarianceNorm_descriptor(), name, value);
+}
+enum SolverParameter_SolverMode {
+  SolverParameter_SolverMode_CPU = 0,
+  SolverParameter_SolverMode_GPU = 1
+};
+bool SolverParameter_SolverMode_IsValid(int value);
+const SolverParameter_SolverMode SolverParameter_SolverMode_SolverMode_MIN = SolverParameter_SolverMode_CPU;
+const SolverParameter_SolverMode SolverParameter_SolverMode_SolverMode_MAX = SolverParameter_SolverMode_GPU;
+const int SolverParameter_SolverMode_SolverMode_ARRAYSIZE = SolverParameter_SolverMode_SolverMode_MAX + 1;
+
+const ::google::protobuf::EnumDescriptor* SolverParameter_SolverMode_descriptor();
+inline const ::std::string& SolverParameter_SolverMode_Name(SolverParameter_SolverMode value) {
+  return ::google::protobuf::internal::NameOfEnum(
+    SolverParameter_SolverMode_descriptor(), value);
+}
+inline bool SolverParameter_SolverMode_Parse(
+    const ::std::string& name, SolverParameter_SolverMode* value) {
+  return ::google::protobuf::internal::ParseNamedEnum<SolverParameter_SolverMode>(
+    SolverParameter_SolverMode_descriptor(), name, value);
+}
+enum SolverParameter_SolverType {
+  SolverParameter_SolverType_SGD = 0,
+  SolverParameter_SolverType_NESTEROV = 1,
+  SolverParameter_SolverType_ADAGRAD = 2
+};
+bool SolverParameter_SolverType_IsValid(int value);
+const SolverParameter_SolverType SolverParameter_SolverType_SolverType_MIN = SolverParameter_SolverType_SGD;
+const SolverParameter_SolverType SolverParameter_SolverType_SolverType_MAX = SolverParameter_SolverType_ADAGRAD;
+const int SolverParameter_SolverType_SolverType_ARRAYSIZE = SolverParameter_SolverType_SolverType_MAX + 1;
+
+const ::google::protobuf::EnumDescriptor* SolverParameter_SolverType_descriptor();
+inline const ::std::string& SolverParameter_SolverType_Name(SolverParameter_SolverType value) {
+  return ::google::protobuf::internal::NameOfEnum(
+    SolverParameter_SolverType_descriptor(), value);
+}
+inline bool SolverParameter_SolverType_Parse(
+    const ::std::string& name, SolverParameter_SolverType* value) {
+  return ::google::protobuf::internal::ParseNamedEnum<SolverParameter_SolverType>(
+    SolverParameter_SolverType_descriptor(), name, value);
+}
+enum ParamSpec_DimCheckMode {
+  ParamSpec_DimCheckMode_STRICT = 0,
+  ParamSpec_DimCheckMode_PERMISSIVE = 1
+};
+bool ParamSpec_DimCheckMode_IsValid(int value);
+const ParamSpec_DimCheckMode ParamSpec_DimCheckMode_DimCheckMode_MIN = ParamSpec_DimCheckMode_STRICT;
+const ParamSpec_DimCheckMode ParamSpec_DimCheckMode_DimCheckMode_MAX = ParamSpec_DimCheckMode_PERMISSIVE;
+const int ParamSpec_DimCheckMode_DimCheckMode_ARRAYSIZE = ParamSpec_DimCheckMode_DimCheckMode_MAX + 1;
+
+const ::google::protobuf::EnumDescriptor* ParamSpec_DimCheckMode_descriptor();
+inline const ::std::string& ParamSpec_DimCheckMode_Name(ParamSpec_DimCheckMode value) {
+  return ::google::protobuf::internal::NameOfEnum(
+    ParamSpec_DimCheckMode_descriptor(), value);
+}
+inline bool ParamSpec_DimCheckMode_Parse(
+    const ::std::string& name, ParamSpec_DimCheckMode* value) {
+  return ::google::protobuf::internal::ParseNamedEnum<ParamSpec_DimCheckMode>(
+    ParamSpec_DimCheckMode_descriptor(), name, value);
+}
+enum ConvolutionParameter_Engine {
+  ConvolutionParameter_Engine_DEFAULT = 0,
+  ConvolutionParameter_Engine_CAFFE = 1,
+  ConvolutionParameter_Engine_CUDNN = 2
+};
+bool ConvolutionParameter_Engine_IsValid(int value);
+const ConvolutionParameter_Engine ConvolutionParameter_Engine_Engine_MIN = ConvolutionParameter_Engine_DEFAULT;
+const ConvolutionParameter_Engine ConvolutionParameter_Engine_Engine_MAX = ConvolutionParameter_Engine_CUDNN;
+const int ConvolutionParameter_Engine_Engine_ARRAYSIZE = ConvolutionParameter_Engine_Engine_MAX + 1;
+
+const ::google::protobuf::EnumDescriptor* ConvolutionParameter_Engine_descriptor();
+inline const ::std::string& ConvolutionParameter_Engine_Name(ConvolutionParameter_Engine value) {
+  return ::google::protobuf::internal::NameOfEnum(
+    ConvolutionParameter_Engine_descriptor(), value);
+}
+inline bool ConvolutionParameter_Engine_Parse(
+    const ::std::string& name, ConvolutionParameter_Engine* value) {
+  return ::google::protobuf::internal::ParseNamedEnum<ConvolutionParameter_Engine>(
+    ConvolutionParameter_Engine_descriptor(), name, value);
+}
+enum DataParameter_DB {
+  DataParameter_DB_LEVELDB = 0,
+  DataParameter_DB_LMDB = 1
+};
+bool DataParameter_DB_IsValid(int value);
+const DataParameter_DB DataParameter_DB_DB_MIN = DataParameter_DB_LEVELDB;
+const DataParameter_DB DataParameter_DB_DB_MAX = DataParameter_DB_LMDB;
+const int DataParameter_DB_DB_ARRAYSIZE = DataParameter_DB_DB_MAX + 1;
+
+const ::google::protobuf::EnumDescriptor* DataParameter_DB_descriptor();
+inline const ::std::string& DataParameter_DB_Name(DataParameter_DB value) {
+  return ::google::protobuf::internal::NameOfEnum(
+    DataParameter_DB_descriptor(), value);
+}
+inline bool DataParameter_DB_Parse(
+    const ::std::string& name, DataParameter_DB* value) {
+  return ::google::protobuf::internal::ParseNamedEnum<DataParameter_DB>(
+    DataParameter_DB_descriptor(), name, value);
+}
+enum EltwiseParameter_EltwiseOp {
+  EltwiseParameter_EltwiseOp_PROD = 0,
+  EltwiseParameter_EltwiseOp_SUM = 1,
+  EltwiseParameter_EltwiseOp_MAX = 2
+};
+bool EltwiseParameter_EltwiseOp_IsValid(int value);
+const EltwiseParameter_EltwiseOp EltwiseParameter_EltwiseOp_EltwiseOp_MIN = EltwiseParameter_EltwiseOp_PROD;
+const EltwiseParameter_EltwiseOp EltwiseParameter_EltwiseOp_EltwiseOp_MAX = EltwiseParameter_EltwiseOp_MAX;
+const int EltwiseParameter_EltwiseOp_EltwiseOp_ARRAYSIZE = EltwiseParameter_EltwiseOp_EltwiseOp_MAX + 1;
+
+const ::google::protobuf::EnumDescriptor* EltwiseParameter_EltwiseOp_descriptor();
+inline const ::std::string& EltwiseParameter_EltwiseOp_Name(EltwiseParameter_EltwiseOp value) {
+  return ::google::protobuf::internal::NameOfEnum(
+    EltwiseParameter_EltwiseOp_descriptor(), value);
+}
+inline bool EltwiseParameter_EltwiseOp_Parse(
+    const ::std::string& name, EltwiseParameter_EltwiseOp* value) {
+  return ::google::protobuf::internal::ParseNamedEnum<EltwiseParameter_EltwiseOp>(
+    EltwiseParameter_EltwiseOp_descriptor(), name, value);
+}
+enum HingeLossParameter_Norm {
+  HingeLossParameter_Norm_L1 = 1,
+  HingeLossParameter_Norm_L2 = 2
+};
+bool HingeLossParameter_Norm_IsValid(int value);
+const HingeLossParameter_Norm HingeLossParameter_Norm_Norm_MIN = HingeLossParameter_Norm_L1;
+const HingeLossParameter_Norm HingeLossParameter_Norm_Norm_MAX = HingeLossParameter_Norm_L2;
+const int HingeLossParameter_Norm_Norm_ARRAYSIZE = HingeLossParameter_Norm_Norm_MAX + 1;
+
+const ::google::protobuf::EnumDescriptor* HingeLossParameter_Norm_descriptor();
+inline const ::std::string& HingeLossParameter_Norm_Name(HingeLossParameter_Norm value) {
+  return ::google::protobuf::internal::NameOfEnum(
+    HingeLossParameter_Norm_descriptor(), value);
+}
+inline bool HingeLossParameter_Norm_Parse(
+    const ::std::string& name, HingeLossParameter_Norm* value) {
+  return ::google::protobuf::internal::ParseNamedEnum<HingeLossParameter_Norm>(
+    HingeLossParameter_Norm_descriptor(), name, value);
+}
+enum LRNParameter_NormRegion {
+  LRNParameter_NormRegion_ACROSS_CHANNELS = 0,
+  LRNParameter_NormRegion_WITHIN_CHANNEL = 1
+};
+bool LRNParameter_NormRegion_IsValid(int value);
+const LRNParameter_NormRegion LRNParameter_NormRegion_NormRegion_MIN = LRNParameter_NormRegion_ACROSS_CHANNELS;
+const LRNParameter_NormRegion LRNParameter_NormRegion_NormRegion_MAX = LRNParameter_NormRegion_WITHIN_CHANNEL;
+const int LRNParameter_NormRegion_NormRegion_ARRAYSIZE = LRNParameter_NormRegion_NormRegion_MAX + 1;
+
+const ::google::protobuf::EnumDescriptor* LRNParameter_NormRegion_descriptor();
+inline const ::std::string& LRNParameter_NormRegion_Name(LRNParameter_NormRegion value) {
+  return ::google::protobuf::internal::NameOfEnum(
+    LRNParameter_NormRegion_descriptor(), value);
+}
+inline bool LRNParameter_NormRegion_Parse(
+    const ::std::string& name, LRNParameter_NormRegion* value) {
+  return ::google::protobuf::internal::ParseNamedEnum<LRNParameter_NormRegion>(
+    LRNParameter_NormRegion_descriptor(), name, value);
+}
+enum PoolingParameter_PoolMethod {
+  PoolingParameter_PoolMethod_MAX = 0,
+  PoolingParameter_PoolMethod_AVE = 1,
+  PoolingParameter_PoolMethod_STOCHASTIC = 2
+};
+bool PoolingParameter_PoolMethod_IsValid(int value);
+const PoolingParameter_PoolMethod PoolingParameter_PoolMethod_PoolMethod_MIN = PoolingParameter_PoolMethod_MAX;
+const PoolingParameter_PoolMethod PoolingParameter_PoolMethod_PoolMethod_MAX = PoolingParameter_PoolMethod_STOCHASTIC;
+const int PoolingParameter_PoolMethod_PoolMethod_ARRAYSIZE = PoolingParameter_PoolMethod_PoolMethod_MAX + 1;
+
+const ::google::protobuf::EnumDescriptor* PoolingParameter_PoolMethod_descriptor();
+inline const ::std::string& PoolingParameter_PoolMethod_Name(PoolingParameter_PoolMethod value) {
+  return ::google::protobuf::internal::NameOfEnum(
+    PoolingParameter_PoolMethod_descriptor(), value);
+}
+inline bool PoolingParameter_PoolMethod_Parse(
+    const ::std::string& name, PoolingParameter_PoolMethod* value) {
+  return ::google::protobuf::internal::ParseNamedEnum<PoolingParameter_PoolMethod>(
+    PoolingParameter_PoolMethod_descriptor(), name, value);
+}
+enum PoolingParameter_Engine {
+  PoolingParameter_Engine_DEFAULT = 0,
+  PoolingParameter_Engine_CAFFE = 1,
+  PoolingParameter_Engine_CUDNN = 2
+};
+bool PoolingParameter_Engine_IsValid(int value);
+const PoolingParameter_Engine PoolingParameter_Engine_Engine_MIN = PoolingParameter_Engine_DEFAULT;
+const PoolingParameter_Engine PoolingParameter_Engine_Engine_MAX = PoolingParameter_Engine_CUDNN;
+const int PoolingParameter_Engine_Engine_ARRAYSIZE = PoolingParameter_Engine_Engine_MAX + 1;
+
+const ::google::protobuf::EnumDescriptor* PoolingParameter_Engine_descriptor();
+inline const ::std::string& PoolingParameter_Engine_Name(PoolingParameter_Engine value) {
+  return ::google::protobuf::internal::NameOfEnum(
+    PoolingParameter_Engine_descriptor(), value);
+}
+inline bool PoolingParameter_Engine_Parse(
+    const ::std::string& name, PoolingParameter_Engine* value) {
+  return ::google::protobuf::internal::ParseNamedEnum<PoolingParameter_Engine>(
+    PoolingParameter_Engine_descriptor(), name, value);
+}
+enum ReductionParameter_ReductionOp {
+  ReductionParameter_ReductionOp_SUM = 1,
+  ReductionParameter_ReductionOp_ASUM = 2,
+  ReductionParameter_ReductionOp_SUMSQ = 3,
+  ReductionParameter_ReductionOp_MEAN = 4
+};
+bool ReductionParameter_ReductionOp_IsValid(int value);
+const ReductionParameter_ReductionOp ReductionParameter_ReductionOp_ReductionOp_MIN = ReductionParameter_ReductionOp_SUM;
+const ReductionParameter_ReductionOp ReductionParameter_ReductionOp_ReductionOp_MAX = ReductionParameter_ReductionOp_MEAN;
+const int ReductionParameter_ReductionOp_ReductionOp_ARRAYSIZE = ReductionParameter_ReductionOp_ReductionOp_MAX + 1;
+
+const ::google::protobuf::EnumDescriptor* ReductionParameter_ReductionOp_descriptor();
+inline const ::std::string& ReductionParameter_ReductionOp_Name(ReductionParameter_ReductionOp value) {
+  return ::google::protobuf::internal::NameOfEnum(
+    ReductionParameter_ReductionOp_descriptor(), value);
+}
+inline bool ReductionParameter_ReductionOp_Parse(
+    const ::std::string& name, ReductionParameter_ReductionOp* value) {
+  return ::google::protobuf::internal::ParseNamedEnum<ReductionParameter_ReductionOp>(
+    ReductionParameter_ReductionOp_descriptor(), name, value);
+}
+enum ReLUParameter_Engine {
+  ReLUParameter_Engine_DEFAULT = 0,
+  ReLUParameter_Engine_CAFFE = 1,
+  ReLUParameter_Engine_CUDNN = 2
+};
+bool ReLUParameter_Engine_IsValid(int value);
+const ReLUParameter_Engine ReLUParameter_Engine_Engine_MIN = ReLUParameter_Engine_DEFAULT;
+const ReLUParameter_Engine ReLUParameter_Engine_Engine_MAX = ReLUParameter_Engine_CUDNN;
+const int ReLUParameter_Engine_Engine_ARRAYSIZE = ReLUParameter_Engine_Engine_MAX + 1;
+
+const ::google::protobuf::EnumDescriptor* ReLUParameter_Engine_descriptor();
+inline const ::std::string& ReLUParameter_Engine_Name(ReLUParameter_Engine value) {
+  return ::google::protobuf::internal::NameOfEnum(
+    ReLUParameter_Engine_descriptor(), value);
+}
+inline bool ReLUParameter_Engine_Parse(
+    const ::std::string& name, ReLUParameter_Engine* value) {
+  return ::google::protobuf::internal::ParseNamedEnum<ReLUParameter_Engine>(
+    ReLUParameter_Engine_descriptor(), name, value);
+}
+enum SigmoidParameter_Engine {
+  SigmoidParameter_Engine_DEFAULT = 0,
+  SigmoidParameter_Engine_CAFFE = 1,
+  SigmoidParameter_Engine_CUDNN = 2
+};
+bool SigmoidParameter_Engine_IsValid(int value);
+const SigmoidParameter_Engine SigmoidParameter_Engine_Engine_MIN = SigmoidParameter_Engine_DEFAULT;
+const SigmoidParameter_Engine SigmoidParameter_Engine_Engine_MAX = SigmoidParameter_Engine_CUDNN;
+const int SigmoidParameter_Engine_Engine_ARRAYSIZE = SigmoidParameter_Engine_Engine_MAX + 1;
+
+const ::google::protobuf::EnumDescriptor* SigmoidParameter_Engine_descriptor();
+inline const ::std::string& SigmoidParameter_Engine_Name(SigmoidParameter_Engine value) {
+  return ::google::protobuf::internal::NameOfEnum(
+    SigmoidParameter_Engine_descriptor(), value);
+}
+inline bool SigmoidParameter_Engine_Parse(
+    const ::std::string& name, SigmoidParameter_Engine* value) {
+  return ::google::protobuf::internal::ParseNamedEnum<SigmoidParameter_Engine>(
+    SigmoidParameter_Engine_descriptor(), name, value);
+}
+enum SoftmaxParameter_Engine {
+  SoftmaxParameter_Engine_DEFAULT = 0,
+  SoftmaxParameter_Engine_CAFFE = 1,
+  SoftmaxParameter_Engine_CUDNN = 2
+};
+bool SoftmaxParameter_Engine_IsValid(int value);
+const SoftmaxParameter_Engine SoftmaxParameter_Engine_Engine_MIN = SoftmaxParameter_Engine_DEFAULT;
+const SoftmaxParameter_Engine SoftmaxParameter_Engine_Engine_MAX = SoftmaxParameter_Engine_CUDNN;
+const int SoftmaxParameter_Engine_Engine_ARRAYSIZE = SoftmaxParameter_Engine_Engine_MAX + 1;
+
+const ::google::protobuf::EnumDescriptor* SoftmaxParameter_Engine_descriptor();
+inline const ::std::string& SoftmaxParameter_Engine_Name(SoftmaxParameter_Engine value) {
+  return ::google::protobuf::internal::NameOfEnum(
+    SoftmaxParameter_Engine_descriptor(), value);
+}
+inline bool SoftmaxParameter_Engine_Parse(
+    const ::std::string& name, SoftmaxParameter_Engine* value) {
+  return ::google::protobuf::internal::ParseNamedEnum<SoftmaxParameter_Engine>(
+    SoftmaxParameter_Engine_descriptor(), name, value);
+}
+enum TanHParameter_Engine {
+  TanHParameter_Engine_DEFAULT = 0,
+  TanHParameter_Engine_CAFFE = 1,
+  TanHParameter_Engine_CUDNN = 2
+};
+bool TanHParameter_Engine_IsValid(int value);
+const TanHParameter_Engine TanHParameter_Engine_Engine_MIN = TanHParameter_Engine_DEFAULT;
+const TanHParameter_Engine TanHParameter_Engine_Engine_MAX = TanHParameter_Engine_CUDNN;
+const int TanHParameter_Engine_Engine_ARRAYSIZE = TanHParameter_Engine_Engine_MAX + 1;
+
+const ::google::protobuf::EnumDescriptor* TanHParameter_Engine_descriptor();
+inline const ::std::string& TanHParameter_Engine_Name(TanHParameter_Engine value) {
+  return ::google::protobuf::internal::NameOfEnum(
+    TanHParameter_Engine_descriptor(), value);
+}
+inline bool TanHParameter_Engine_Parse(
+    const ::std::string& name, TanHParameter_Engine* value) {
+  return ::google::protobuf::internal::ParseNamedEnum<TanHParameter_Engine>(
+    TanHParameter_Engine_descriptor(), name, value);
+}
+enum SPPParameter_PoolMethod {
+  SPPParameter_PoolMethod_MAX = 0,
+  SPPParameter_PoolMethod_AVE = 1,
+  SPPParameter_PoolMethod_STOCHASTIC = 2
+};
+bool SPPParameter_PoolMethod_IsValid(int value);
+const SPPParameter_PoolMethod SPPParameter_PoolMethod_PoolMethod_MIN = SPPParameter_PoolMethod_MAX;
+const SPPParameter_PoolMethod SPPParameter_PoolMethod_PoolMethod_MAX = SPPParameter_PoolMethod_STOCHASTIC;
+const int SPPParameter_PoolMethod_PoolMethod_ARRAYSIZE = SPPParameter_PoolMethod_PoolMethod_MAX + 1;
+
+const ::google::protobuf::EnumDescriptor* SPPParameter_PoolMethod_descriptor();
+inline const ::std::string& SPPParameter_PoolMethod_Name(SPPParameter_PoolMethod value) {
+  return ::google::protobuf::internal::NameOfEnum(
+    SPPParameter_PoolMethod_descriptor(), value);
+}
+inline bool SPPParameter_PoolMethod_Parse(
+    const ::std::string& name, SPPParameter_PoolMethod* value) {
+  return ::google::protobuf::internal::ParseNamedEnum<SPPParameter_PoolMethod>(
+    SPPParameter_PoolMethod_descriptor(), name, value);
+}
+enum SPPParameter_Engine {
+  SPPParameter_Engine_DEFAULT = 0,
+  SPPParameter_Engine_CAFFE = 1,
+  SPPParameter_Engine_CUDNN = 2
+};
+bool SPPParameter_Engine_IsValid(int value);
+const SPPParameter_Engine SPPParameter_Engine_Engine_MIN = SPPParameter_Engine_DEFAULT;
+const SPPParameter_Engine SPPParameter_Engine_Engine_MAX = SPPParameter_Engine_CUDNN;
+const int SPPParameter_Engine_Engine_ARRAYSIZE = SPPParameter_Engine_Engine_MAX + 1;
+
+const ::google::protobuf::EnumDescriptor* SPPParameter_Engine_descriptor();
+inline const ::std::string& SPPParameter_Engine_Name(SPPParameter_Engine value) {
+  return ::google::protobuf::internal::NameOfEnum(
+    SPPParameter_Engine_descriptor(), value);
+}
+inline bool SPPParameter_Engine_Parse(
+    const ::std::string& name, SPPParameter_Engine* value) {
+  return ::google::protobuf::internal::ParseNamedEnum<SPPParameter_Engine>(
+    SPPParameter_Engine_descriptor(), name, value);
+}
+enum V1LayerParameter_LayerType {
+  V1LayerParameter_LayerType_NONE = 0,
+  V1LayerParameter_LayerType_ABSVAL = 35,
+  V1LayerParameter_LayerType_ACCURACY = 1,
+  V1LayerParameter_LayerType_ARGMAX = 30,
+  V1LayerParameter_LayerType_BNLL = 2,
+  V1LayerParameter_LayerType_CONCAT = 3,
+  V1LayerParameter_LayerType_CONTRASTIVE_LOSS = 37,
+  V1LayerParameter_LayerType_CONVOLUTION = 4,
+  V1LayerParameter_LayerType_DATA = 5,
+  V1LayerParameter_LayerType_DECONVOLUTION = 39,
+  V1LayerParameter_LayerType_DROPOUT = 6,
+  V1LayerParameter_LayerType_DUMMY_DATA = 32,
+  V1LayerParameter_LayerType_EUCLIDEAN_LOSS = 7,
+  V1LayerParameter_LayerType_ELTWISE = 25,
+  V1LayerParameter_LayerType_EXP = 38,
+  V1LayerParameter_LayerType_FLATTEN = 8,
+  V1LayerParameter_LayerType_HDF5_DATA = 9,
+  V1LayerParameter_LayerType_HDF5_OUTPUT = 10,
+  V1LayerParameter_LayerType_HINGE_LOSS = 28,
+  V1LayerParameter_LayerType_IM2COL = 11,
+  V1LayerParameter_LayerType_IMAGE_DATA = 12,
+  V1LayerParameter_LayerType_INFOGAIN_LOSS = 13,
+  V1LayerParameter_LayerType_INNER_PRODUCT = 14,
+  V1LayerParameter_LayerType_LRN = 15,
+  V1LayerParameter_LayerType_MEMORY_DATA = 29,
+  V1LayerParameter_LayerType_MULTINOMIAL_LOGISTIC_LOSS = 16,
+  V1LayerParameter_LayerType_MVN = 34,
+  V1LayerParameter_LayerType_POOLING = 17,
+  V1LayerParameter_LayerType_POWER = 26,
+  V1LayerParameter_LayerType_RELU = 18,
+  V1LayerParameter_LayerType_SIGMOID = 19,
+  V1LayerParameter_LayerType_SIGMOID_CROSS_ENTROPY_LOSS = 27,
+  V1LayerParameter_LayerType_SILENCE = 36,
+  V1LayerParameter_LayerType_SOFTMAX = 20,
+  V1LayerParameter_LayerType_SOFTMAX_LOSS = 21,
+  V1LayerParameter_LayerType_SPLIT = 22,
+  V1LayerParameter_LayerType_SLICE = 33,
+  V1LayerParameter_LayerType_TANH = 23,
+  V1LayerParameter_LayerType_WINDOW_DATA = 24,
+  V1LayerParameter_LayerType_THRESHOLD = 31
+};
+bool V1LayerParameter_LayerType_IsValid(int value);
+const V1LayerParameter_LayerType V1LayerParameter_LayerType_LayerType_MIN = V1LayerParameter_LayerType_NONE;
+const V1LayerParameter_LayerType V1LayerParameter_LayerType_LayerType_MAX = V1LayerParameter_LayerType_DECONVOLUTION;
+const int V1LayerParameter_LayerType_LayerType_ARRAYSIZE = V1LayerParameter_LayerType_LayerType_MAX + 1;
+
+const ::google::protobuf::EnumDescriptor* V1LayerParameter_LayerType_descriptor();
+inline const ::std::string& V1LayerParameter_LayerType_Name(V1LayerParameter_LayerType value) {
+  return ::google::protobuf::internal::NameOfEnum(
+    V1LayerParameter_LayerType_descriptor(), value);
+}
+inline bool V1LayerParameter_LayerType_Parse(
+    const ::std::string& name, V1LayerParameter_LayerType* value) {
+  return ::google::protobuf::internal::ParseNamedEnum<V1LayerParameter_LayerType>(
+    V1LayerParameter_LayerType_descriptor(), name, value);
+}
+enum V1LayerParameter_DimCheckMode {
+  V1LayerParameter_DimCheckMode_STRICT = 0,
+  V1LayerParameter_DimCheckMode_PERMISSIVE = 1
+};
+bool V1LayerParameter_DimCheckMode_IsValid(int value);
+const V1LayerParameter_DimCheckMode V1LayerParameter_DimCheckMode_DimCheckMode_MIN = V1LayerParameter_DimCheckMode_STRICT;
+const V1LayerParameter_DimCheckMode V1LayerParameter_DimCheckMode_DimCheckMode_MAX = V1LayerParameter_DimCheckMode_PERMISSIVE;
+const int V1LayerParameter_DimCheckMode_DimCheckMode_ARRAYSIZE = V1LayerParameter_DimCheckMode_DimCheckMode_MAX + 1;
+
+const ::google::protobuf::EnumDescriptor* V1LayerParameter_DimCheckMode_descriptor();
+inline const ::std::string& V1LayerParameter_DimCheckMode_Name(V1LayerParameter_DimCheckMode value) {
+  return ::google::protobuf::internal::NameOfEnum(
+    V1LayerParameter_DimCheckMode_descriptor(), value);
+}
+inline bool V1LayerParameter_DimCheckMode_Parse(
+    const ::std::string& name, V1LayerParameter_DimCheckMode* value) {
+  return ::google::protobuf::internal::ParseNamedEnum<V1LayerParameter_DimCheckMode>(
+    V1LayerParameter_DimCheckMode_descriptor(), name, value);
+}
+enum V0LayerParameter_PoolMethod {
+  V0LayerParameter_PoolMethod_MAX = 0,
+  V0LayerParameter_PoolMethod_AVE = 1,
+  V0LayerParameter_PoolMethod_STOCHASTIC = 2
+};
+bool V0LayerParameter_PoolMethod_IsValid(int value);
+const V0LayerParameter_PoolMethod V0LayerParameter_PoolMethod_PoolMethod_MIN = V0LayerParameter_PoolMethod_MAX;
+const V0LayerParameter_PoolMethod V0LayerParameter_PoolMethod_PoolMethod_MAX = V0LayerParameter_PoolMethod_STOCHASTIC;
+const int V0LayerParameter_PoolMethod_PoolMethod_ARRAYSIZE = V0LayerParameter_PoolMethod_PoolMethod_MAX + 1;
+
+const ::google::protobuf::EnumDescriptor* V0LayerParameter_PoolMethod_descriptor();
+inline const ::std::string& V0LayerParameter_PoolMethod_Name(V0LayerParameter_PoolMethod value) {
+  return ::google::protobuf::internal::NameOfEnum(
+    V0LayerParameter_PoolMethod_descriptor(), value);
+}
+inline bool V0LayerParameter_PoolMethod_Parse(
+    const ::std::string& name, V0LayerParameter_PoolMethod* value) {
+  return ::google::protobuf::internal::ParseNamedEnum<V0LayerParameter_PoolMethod>(
+    V0LayerParameter_PoolMethod_descriptor(), name, value);
+}
+enum Phase {
+  TRAIN = 0,
+  TEST = 1
+};
+bool Phase_IsValid(int value);
+const Phase Phase_MIN = TRAIN;
+const Phase Phase_MAX = TEST;
+const int Phase_ARRAYSIZE = Phase_MAX + 1;
+
+const ::google::protobuf::EnumDescriptor* Phase_descriptor();
+inline const ::std::string& Phase_Name(Phase value) {
+  return ::google::protobuf::internal::NameOfEnum(
+    Phase_descriptor(), value);
+}
+inline bool Phase_Parse(
+    const ::std::string& name, Phase* value) {
+  return ::google::protobuf::internal::ParseNamedEnum<Phase>(
+    Phase_descriptor(), name, value);
+}
+// ===================================================================
+
+class BlobShape : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:caffe.BlobShape) */ {
+ public:
+  BlobShape();
+  virtual ~BlobShape();
+
+  BlobShape(const BlobShape& from);
+
+  inline BlobShape& operator=(const BlobShape& from) {
+    CopyFrom(from);
+    return *this;
+  }
+
+  inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields();
+  }
+
+  inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields();
+  }
+
+  static const ::google::protobuf::Descriptor* descriptor();
+  static const BlobShape& default_instance();
+
+  static const BlobShape* internal_default_instance();
+
+  void Swap(BlobShape* other);
+
+  // implements Message ----------------------------------------------
+
+  inline BlobShape* New() const { return New(NULL); }
+
+  BlobShape* New(::google::protobuf::Arena* arena) const;
+  void CopyFrom(const ::google::protobuf::Message& from);
+  void MergeFrom(const ::google::protobuf::Message& from);
+  void CopyFrom(const BlobShape& from);
+  void MergeFrom(const BlobShape& from);
+  void Clear();
+  bool IsInitialized() const;
+
+  size_t ByteSizeLong() const;
+  bool MergePartialFromCodedStream(
+      ::google::protobuf::io::CodedInputStream* input);
+  void SerializeWithCachedSizes(
+      ::google::protobuf::io::CodedOutputStream* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
+  int GetCachedSize() const { return _cached_size_; }
+  private:
+  void SharedCtor();
+  void SharedDtor();
+  void SetCachedSize(int size) const;
+  void InternalSwap(BlobShape* other);
+  void UnsafeMergeFrom(const BlobShape& from);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
+  public:
+
+  ::google::protobuf::Metadata GetMetadata() const;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  // repeated int64 dim = 1 [packed = true];
+  int dim_size() const;
+  void clear_dim();
+  static const int kDimFieldNumber = 1;
+  ::google::protobuf::int64 dim(int index) const;
+  void set_dim(int index, ::google::protobuf::int64 value);
+  void add_dim(::google::protobuf::int64 value);
+  const ::google::protobuf::RepeatedField< ::google::protobuf::int64 >&
+      dim() const;
+  ::google::protobuf::RepeatedField< ::google::protobuf::int64 >*
+      mutable_dim();
+
+  // @@protoc_insertion_point(class_scope:caffe.BlobShape)
+ private:
+
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  ::google::protobuf::internal::HasBits<1> _has_bits_;
+  mutable int _cached_size_;
+  ::google::protobuf::RepeatedField< ::google::protobuf::int64 > dim_;
+  mutable int _dim_cached_byte_size_;
+  friend void  protobuf_InitDefaults_caffe_2eproto_impl();
+  friend void  protobuf_AddDesc_caffe_2eproto_impl();
+  friend void protobuf_AssignDesc_caffe_2eproto();
+  friend void protobuf_ShutdownFile_caffe_2eproto();
+
+  void InitAsDefaultInstance();
+};
+extern ::google::protobuf::internal::ExplicitlyConstructed<BlobShape> BlobShape_default_instance_;
+
+// -------------------------------------------------------------------
+
+class BlobProto : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:caffe.BlobProto) */ {
+ public:
+  BlobProto();
+  virtual ~BlobProto();
+
+  BlobProto(const BlobProto& from);
+
+  inline BlobProto& operator=(const BlobProto& from) {
+    CopyFrom(from);
+    return *this;
+  }
+
+  inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields();
+  }
+
+  inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields();
+  }
+
+  static const ::google::protobuf::Descriptor* descriptor();
+  static const BlobProto& default_instance();
+
+  static const BlobProto* internal_default_instance();
+
+  void Swap(BlobProto* other);
+
+  // implements Message ----------------------------------------------
+
+  inline BlobProto* New() const { return New(NULL); }
+
+  BlobProto* New(::google::protobuf::Arena* arena) const;
+  void CopyFrom(const ::google::protobuf::Message& from);
+  void MergeFrom(const ::google::protobuf::Message& from);
+  void CopyFrom(const BlobProto& from);
+  void MergeFrom(const BlobProto& from);
+  void Clear();
+  bool IsInitialized() const;
+
+  size_t ByteSizeLong() const;
+  bool MergePartialFromCodedStream(
+      ::google::protobuf::io::CodedInputStream* input);
+  void SerializeWithCachedSizes(
+      ::google::protobuf::io::CodedOutputStream* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
+  int GetCachedSize() const { return _cached_size_; }
+  private:
+  void SharedCtor();
+  void SharedDtor();
+  void SetCachedSize(int size) const;
+  void InternalSwap(BlobProto* other);
+  void UnsafeMergeFrom(const BlobProto& from);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
+  public:
+
+  ::google::protobuf::Metadata GetMetadata() const;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  // optional .caffe.BlobShape shape = 7;
+  bool has_shape() const;
+  void clear_shape();
+  static const int kShapeFieldNumber = 7;
+  const ::caffe::BlobShape& shape() const;
+  ::caffe::BlobShape* mutable_shape();
+  ::caffe::BlobShape* release_shape();
+  void set_allocated_shape(::caffe::BlobShape* shape);
+
+  // repeated float data = 5 [packed = true];
+  int data_size() const;
+  void clear_data();
+  static const int kDataFieldNumber = 5;
+  float data(int index) const;
+  void set_data(int index, float value);
+  void add_data(float value);
+  const ::google::protobuf::RepeatedField< float >&
+      data() const;
+  ::google::protobuf::RepeatedField< float >*
+      mutable_data();
+
+  // repeated float diff = 6 [packed = true];
+  int diff_size() const;
+  void clear_diff();
+  static const int kDiffFieldNumber = 6;
+  float diff(int index) const;
+  void set_diff(int index, float value);
+  void add_diff(float value);
+  const ::google::protobuf::RepeatedField< float >&
+      diff() const;
+  ::google::protobuf::RepeatedField< float >*
+      mutable_diff();
+
+  // optional int32 num = 1 [default = 0];
+  bool has_num() const;
+  void clear_num();
+  static const int kNumFieldNumber = 1;
+  ::google::protobuf::int32 num() const;
+  void set_num(::google::protobuf::int32 value);
+
+  // optional int32 channels = 2 [default = 0];
+  bool has_channels() const;
+  void clear_channels();
+  static const int kChannelsFieldNumber = 2;
+  ::google::protobuf::int32 channels() const;
+  void set_channels(::google::protobuf::int32 value);
+
+  // optional int32 height = 3 [default = 0];
+  bool has_height() const;
+  void clear_height();
+  static const int kHeightFieldNumber = 3;
+  ::google::protobuf::int32 height() const;
+  void set_height(::google::protobuf::int32 value);
+
+  // optional int32 width = 4 [default = 0];
+  bool has_width() const;
+  void clear_width();
+  static const int kWidthFieldNumber = 4;
+  ::google::protobuf::int32 width() const;
+  void set_width(::google::protobuf::int32 value);
+
+  // @@protoc_insertion_point(class_scope:caffe.BlobProto)
+ private:
+  inline void set_has_shape();
+  inline void clear_has_shape();
+  inline void set_has_num();
+  inline void clear_has_num();
+  inline void set_has_channels();
+  inline void clear_has_channels();
+  inline void set_has_height();
+  inline void clear_has_height();
+  inline void set_has_width();
+  inline void clear_has_width();
+
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  ::google::protobuf::internal::HasBits<1> _has_bits_;
+  mutable int _cached_size_;
+  ::google::protobuf::RepeatedField< float > data_;
+  mutable int _data_cached_byte_size_;
+  ::google::protobuf::RepeatedField< float > diff_;
+  mutable int _diff_cached_byte_size_;
+  ::caffe::BlobShape* shape_;
+  ::google::protobuf::int32 num_;
+  ::google::protobuf::int32 channels_;
+  ::google::protobuf::int32 height_;
+  ::google::protobuf::int32 width_;
+  friend void  protobuf_InitDefaults_caffe_2eproto_impl();
+  friend void  protobuf_AddDesc_caffe_2eproto_impl();
+  friend void protobuf_AssignDesc_caffe_2eproto();
+  friend void protobuf_ShutdownFile_caffe_2eproto();
+
+  void InitAsDefaultInstance();
+};
+extern ::google::protobuf::internal::ExplicitlyConstructed<BlobProto> BlobProto_default_instance_;
+
+// -------------------------------------------------------------------
+
+class BlobProtoVector : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:caffe.BlobProtoVector) */ {
+ public:
+  BlobProtoVector();
+  virtual ~BlobProtoVector();
+
+  BlobProtoVector(const BlobProtoVector& from);
+
+  inline BlobProtoVector& operator=(const BlobProtoVector& from) {
+    CopyFrom(from);
+    return *this;
+  }
+
+  inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields();
+  }
+
+  inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields();
+  }
+
+  static const ::google::protobuf::Descriptor* descriptor();
+  static const BlobProtoVector& default_instance();
+
+  static const BlobProtoVector* internal_default_instance();
+
+  void Swap(BlobProtoVector* other);
+
+  // implements Message ----------------------------------------------
+
+  inline BlobProtoVector* New() const { return New(NULL); }
+
+  BlobProtoVector* New(::google::protobuf::Arena* arena) const;
+  void CopyFrom(const ::google::protobuf::Message& from);
+  void MergeFrom(const ::google::protobuf::Message& from);
+  void CopyFrom(const BlobProtoVector& from);
+  void MergeFrom(const BlobProtoVector& from);
+  void Clear();
+  bool IsInitialized() const;
+
+  size_t ByteSizeLong() const;
+  bool MergePartialFromCodedStream(
+      ::google::protobuf::io::CodedInputStream* input);
+  void SerializeWithCachedSizes(
+      ::google::protobuf::io::CodedOutputStream* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
+  int GetCachedSize() const { return _cached_size_; }
+  private:
+  void SharedCtor();
+  void SharedDtor();
+  void SetCachedSize(int size) const;
+  void InternalSwap(BlobProtoVector* other);
+  void UnsafeMergeFrom(const BlobProtoVector& from);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
+  public:
+
+  ::google::protobuf::Metadata GetMetadata() const;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  // repeated .caffe.BlobProto blobs = 1;
+  int blobs_size() const;
+  void clear_blobs();
+  static const int kBlobsFieldNumber = 1;
+  const ::caffe::BlobProto& blobs(int index) const;
+  ::caffe::BlobProto* mutable_blobs(int index);
+  ::caffe::BlobProto* add_blobs();
+  ::google::protobuf::RepeatedPtrField< ::caffe::BlobProto >*
+      mutable_blobs();
+  const ::google::protobuf::RepeatedPtrField< ::caffe::BlobProto >&
+      blobs() const;
+
+  // @@protoc_insertion_point(class_scope:caffe.BlobProtoVector)
+ private:
+
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  ::google::protobuf::internal::HasBits<1> _has_bits_;
+  mutable int _cached_size_;
+  ::google::protobuf::RepeatedPtrField< ::caffe::BlobProto > blobs_;
+  friend void  protobuf_InitDefaults_caffe_2eproto_impl();
+  friend void  protobuf_AddDesc_caffe_2eproto_impl();
+  friend void protobuf_AssignDesc_caffe_2eproto();
+  friend void protobuf_ShutdownFile_caffe_2eproto();
+
+  void InitAsDefaultInstance();
+};
+extern ::google::protobuf::internal::ExplicitlyConstructed<BlobProtoVector> BlobProtoVector_default_instance_;
+
+// -------------------------------------------------------------------
+
+class CropParameter : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:caffe.CropParameter) */ {
+ public:
+  CropParameter();
+  virtual ~CropParameter();
+
+  CropParameter(const CropParameter& from);
+
+  inline CropParameter& operator=(const CropParameter& from) {
+    CopyFrom(from);
+    return *this;
+  }
+
+  inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields();
+  }
+
+  inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields();
+  }
+
+  static const ::google::protobuf::Descriptor* descriptor();
+  static const CropParameter& default_instance();
+
+  static const CropParameter* internal_default_instance();
+
+  void Swap(CropParameter* other);
+
+  // implements Message ----------------------------------------------
+
+  inline CropParameter* New() const { return New(NULL); }
+
+  CropParameter* New(::google::protobuf::Arena* arena) const;
+  void CopyFrom(const ::google::protobuf::Message& from);
+  void MergeFrom(const ::google::protobuf::Message& from);
+  void CopyFrom(const CropParameter& from);
+  void MergeFrom(const CropParameter& from);
+  void Clear();
+  bool IsInitialized() const;
+
+  size_t ByteSizeLong() const;
+  bool MergePartialFromCodedStream(
+      ::google::protobuf::io::CodedInputStream* input);
+  void SerializeWithCachedSizes(
+      ::google::protobuf::io::CodedOutputStream* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
+  int GetCachedSize() const { return _cached_size_; }
+  private:
+  void SharedCtor();
+  void SharedDtor();
+  void SetCachedSize(int size) const;
+  void InternalSwap(CropParameter* other);
+  void UnsafeMergeFrom(const CropParameter& from);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
+  public:
+
+  ::google::protobuf::Metadata GetMetadata() const;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  // optional int32 axis = 1 [default = 2];
+  bool has_axis() const;
+  void clear_axis();
+  static const int kAxisFieldNumber = 1;
+  ::google::protobuf::int32 axis() const;
+  void set_axis(::google::protobuf::int32 value);
+
+  // repeated uint32 offset = 2;
+  int offset_size() const;
+  void clear_offset();
+  static const int kOffsetFieldNumber = 2;
+  ::google::protobuf::uint32 offset(int index) const;
+  void set_offset(int index, ::google::protobuf::uint32 value);
+  void add_offset(::google::protobuf::uint32 value);
+  const ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >&
+      offset() const;
+  ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >*
+      mutable_offset();
+
+  // @@protoc_insertion_point(class_scope:caffe.CropParameter)
+ private:
+  inline void set_has_axis();
+  inline void clear_has_axis();
+
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  ::google::protobuf::internal::HasBits<1> _has_bits_;
+  mutable int _cached_size_;
+  ::google::protobuf::RepeatedField< ::google::protobuf::uint32 > offset_;
+  ::google::protobuf::int32 axis_;
+  friend void  protobuf_InitDefaults_caffe_2eproto_impl();
+  friend void  protobuf_AddDesc_caffe_2eproto_impl();
+  friend void protobuf_AssignDesc_caffe_2eproto();
+  friend void protobuf_ShutdownFile_caffe_2eproto();
+
+  void InitAsDefaultInstance();
+};
+extern ::google::protobuf::internal::ExplicitlyConstructed<CropParameter> CropParameter_default_instance_;
+
+// -------------------------------------------------------------------
+
+class PermuteParameter : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:caffe.PermuteParameter) */ {
+ public:
+  PermuteParameter();
+  virtual ~PermuteParameter();
+
+  PermuteParameter(const PermuteParameter& from);
+
+  inline PermuteParameter& operator=(const PermuteParameter& from) {
+    CopyFrom(from);
+    return *this;
+  }
+
+  inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields();
+  }
+
+  inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields();
+  }
+
+  static const ::google::protobuf::Descriptor* descriptor();
+  static const PermuteParameter& default_instance();
+
+  static const PermuteParameter* internal_default_instance();
+
+  void Swap(PermuteParameter* other);
+
+  // implements Message ----------------------------------------------
+
+  inline PermuteParameter* New() const { return New(NULL); }
+
+  PermuteParameter* New(::google::protobuf::Arena* arena) const;
+  void CopyFrom(const ::google::protobuf::Message& from);
+  void MergeFrom(const ::google::protobuf::Message& from);
+  void CopyFrom(const PermuteParameter& from);
+  void MergeFrom(const PermuteParameter& from);
+  void Clear();
+  bool IsInitialized() const;
+
+  size_t ByteSizeLong() const;
+  bool MergePartialFromCodedStream(
+      ::google::protobuf::io::CodedInputStream* input);
+  void SerializeWithCachedSizes(
+      ::google::protobuf::io::CodedOutputStream* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
+  int GetCachedSize() const { return _cached_size_; }
+  private:
+  void SharedCtor();
+  void SharedDtor();
+  void SetCachedSize(int size) const;
+  void InternalSwap(PermuteParameter* other);
+  void UnsafeMergeFrom(const PermuteParameter& from);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
+  public:
+
+  ::google::protobuf::Metadata GetMetadata() const;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  // repeated uint32 order = 1;
+  int order_size() const;
+  void clear_order();
+  static const int kOrderFieldNumber = 1;
+  ::google::protobuf::uint32 order(int index) const;
+  void set_order(int index, ::google::protobuf::uint32 value);
+  void add_order(::google::protobuf::uint32 value);
+  const ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >&
+      order() const;
+  ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >*
+      mutable_order();
+
+  // @@protoc_insertion_point(class_scope:caffe.PermuteParameter)
+ private:
+
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  ::google::protobuf::internal::HasBits<1> _has_bits_;
+  mutable int _cached_size_;
+  ::google::protobuf::RepeatedField< ::google::protobuf::uint32 > order_;
+  friend void  protobuf_InitDefaults_caffe_2eproto_impl();
+  friend void  protobuf_AddDesc_caffe_2eproto_impl();
+  friend void protobuf_AssignDesc_caffe_2eproto();
+  friend void protobuf_ShutdownFile_caffe_2eproto();
+
+  void InitAsDefaultInstance();
+};
+extern ::google::protobuf::internal::ExplicitlyConstructed<PermuteParameter> PermuteParameter_default_instance_;
+
+// -------------------------------------------------------------------
+
+class NormalizeBBoxParameter : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:caffe.NormalizeBBoxParameter) */ {
+ public:
+  NormalizeBBoxParameter();
+  virtual ~NormalizeBBoxParameter();
+
+  NormalizeBBoxParameter(const NormalizeBBoxParameter& from);
+
+  inline NormalizeBBoxParameter& operator=(const NormalizeBBoxParameter& from) {
+    CopyFrom(from);
+    return *this;
+  }
+
+  inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields();
+  }
+
+  inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields();
+  }
+
+  static const ::google::protobuf::Descriptor* descriptor();
+  static const NormalizeBBoxParameter& default_instance();
+
+  static const NormalizeBBoxParameter* internal_default_instance();
+
+  void Swap(NormalizeBBoxParameter* other);
+
+  // implements Message ----------------------------------------------
+
+  inline NormalizeBBoxParameter* New() const { return New(NULL); }
+
+  NormalizeBBoxParameter* New(::google::protobuf::Arena* arena) const;
+  void CopyFrom(const ::google::protobuf::Message& from);
+  void MergeFrom(const ::google::protobuf::Message& from);
+  void CopyFrom(const NormalizeBBoxParameter& from);
+  void MergeFrom(const NormalizeBBoxParameter& from);
+  void Clear();
+  bool IsInitialized() const;
+
+  size_t ByteSizeLong() const;
+  bool MergePartialFromCodedStream(
+      ::google::protobuf::io::CodedInputStream* input);
+  void SerializeWithCachedSizes(
+      ::google::protobuf::io::CodedOutputStream* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
+  int GetCachedSize() const { return _cached_size_; }
+  private:
+  void SharedCtor();
+  void SharedDtor();
+  void SetCachedSize(int size) const;
+  void InternalSwap(NormalizeBBoxParameter* other);
+  void UnsafeMergeFrom(const NormalizeBBoxParameter& from);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
+  public:
+
+  ::google::protobuf::Metadata GetMetadata() const;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  // optional bool across_spatial = 1 [default = true];
+  bool has_across_spatial() const;
+  void clear_across_spatial();
+  static const int kAcrossSpatialFieldNumber = 1;
+  bool across_spatial() const;
+  void set_across_spatial(bool value);
+
+  // optional .caffe.FillerParameter scale_filler = 2;
+  bool has_scale_filler() const;
+  void clear_scale_filler();
+  static const int kScaleFillerFieldNumber = 2;
+  const ::caffe::FillerParameter& scale_filler() const;
+  ::caffe::FillerParameter* mutable_scale_filler();
+  ::caffe::FillerParameter* release_scale_filler();
+  void set_allocated_scale_filler(::caffe::FillerParameter* scale_filler);
+
+  // optional bool channel_shared = 3 [default = true];
+  bool has_channel_shared() const;
+  void clear_channel_shared();
+  static const int kChannelSharedFieldNumber = 3;
+  bool channel_shared() const;
+  void set_channel_shared(bool value);
+
+  // optional float eps = 4 [default = 1e-10];
+  bool has_eps() const;
+  void clear_eps();
+  static const int kEpsFieldNumber = 4;
+  float eps() const;
+  void set_eps(float value);
+
+  // @@protoc_insertion_point(class_scope:caffe.NormalizeBBoxParameter)
+ private:
+  inline void set_has_across_spatial();
+  inline void clear_has_across_spatial();
+  inline void set_has_scale_filler();
+  inline void clear_has_scale_filler();
+  inline void set_has_channel_shared();
+  inline void clear_has_channel_shared();
+  inline void set_has_eps();
+  inline void clear_has_eps();
+
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  ::google::protobuf::internal::HasBits<1> _has_bits_;
+  mutable int _cached_size_;
+  ::caffe::FillerParameter* scale_filler_;
+  bool across_spatial_;
+  bool channel_shared_;
+  float eps_;
+  friend void  protobuf_InitDefaults_caffe_2eproto_impl();
+  friend void  protobuf_AddDesc_caffe_2eproto_impl();
+  friend void protobuf_AssignDesc_caffe_2eproto();
+  friend void protobuf_ShutdownFile_caffe_2eproto();
+
+  void InitAsDefaultInstance();
+};
+extern ::google::protobuf::internal::ExplicitlyConstructed<NormalizeBBoxParameter> NormalizeBBoxParameter_default_instance_;
+
+// -------------------------------------------------------------------
+
+class PriorBoxParameter : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:caffe.PriorBoxParameter) */ {
+ public:
+  PriorBoxParameter();
+  virtual ~PriorBoxParameter();
+
+  PriorBoxParameter(const PriorBoxParameter& from);
+
+  inline PriorBoxParameter& operator=(const PriorBoxParameter& from) {
+    CopyFrom(from);
+    return *this;
+  }
+
+  inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields();
+  }
+
+  inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields();
+  }
+
+  static const ::google::protobuf::Descriptor* descriptor();
+  static const PriorBoxParameter& default_instance();
+
+  static const PriorBoxParameter* internal_default_instance();
+
+  void Swap(PriorBoxParameter* other);
+
+  // implements Message ----------------------------------------------
+
+  inline PriorBoxParameter* New() const { return New(NULL); }
+
+  PriorBoxParameter* New(::google::protobuf::Arena* arena) const;
+  void CopyFrom(const ::google::protobuf::Message& from);
+  void MergeFrom(const ::google::protobuf::Message& from);
+  void CopyFrom(const PriorBoxParameter& from);
+  void MergeFrom(const PriorBoxParameter& from);
+  void Clear();
+  bool IsInitialized() const;
+
+  size_t ByteSizeLong() const;
+  bool MergePartialFromCodedStream(
+      ::google::protobuf::io::CodedInputStream* input);
+  void SerializeWithCachedSizes(
+      ::google::protobuf::io::CodedOutputStream* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
+  int GetCachedSize() const { return _cached_size_; }
+  private:
+  void SharedCtor();
+  void SharedDtor();
+  void SetCachedSize(int size) const;
+  void InternalSwap(PriorBoxParameter* other);
+  void UnsafeMergeFrom(const PriorBoxParameter& from);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
+  public:
+
+  ::google::protobuf::Metadata GetMetadata() const;
+
+  // nested types ----------------------------------------------------
+
+  typedef PriorBoxParameter_CodeType CodeType;
+  static const CodeType CORNER =
+    PriorBoxParameter_CodeType_CORNER;
+  static const CodeType CENTER_SIZE =
+    PriorBoxParameter_CodeType_CENTER_SIZE;
+  static inline bool CodeType_IsValid(int value) {
+    return PriorBoxParameter_CodeType_IsValid(value);
+  }
+  static const CodeType CodeType_MIN =
+    PriorBoxParameter_CodeType_CodeType_MIN;
+  static const CodeType CodeType_MAX =
+    PriorBoxParameter_CodeType_CodeType_MAX;
+  static const int CodeType_ARRAYSIZE =
+    PriorBoxParameter_CodeType_CodeType_ARRAYSIZE;
+  static inline const ::google::protobuf::EnumDescriptor*
+  CodeType_descriptor() {
+    return PriorBoxParameter_CodeType_descriptor();
+  }
+  static inline const ::std::string& CodeType_Name(CodeType value) {
+    return PriorBoxParameter_CodeType_Name(value);
+  }
+  static inline bool CodeType_Parse(const ::std::string& name,
+      CodeType* value) {
+    return PriorBoxParameter_CodeType_Parse(name, value);
+  }
+
+  // accessors -------------------------------------------------------
+
+  // optional float min_size = 1;
+  bool has_min_size() const;
+  void clear_min_size();
+  static const int kMinSizeFieldNumber = 1;
+  float min_size() const;
+  void set_min_size(float value);
+
+  // optional float max_size = 2;
+  bool has_max_size() const;
+  void clear_max_size();
+  static const int kMaxSizeFieldNumber = 2;
+  float max_size() const;
+  void set_max_size(float value);
+
+  // repeated float aspect_ratio = 3;
+  int aspect_ratio_size() const;
+  void clear_aspect_ratio();
+  static const int kAspectRatioFieldNumber = 3;
+  float aspect_ratio(int index) const;
+  void set_aspect_ratio(int index, float value);
+  void add_aspect_ratio(float value);
+  const ::google::protobuf::RepeatedField< float >&
+      aspect_ratio() const;
+  ::google::protobuf::RepeatedField< float >*
+      mutable_aspect_ratio();
+
+  // optional bool flip = 4 [default = true];
+  bool has_flip() const;
+  void clear_flip();
+  static const int kFlipFieldNumber = 4;
+  bool flip() const;
+  void set_flip(bool value);
+
+  // optional bool clip = 5 [default = true];
+  bool has_clip() const;
+  void clear_clip();
+  static const int kClipFieldNumber = 5;
+  bool clip() const;
+  void set_clip(bool value);
+
+  // repeated float variance = 6;
+  int variance_size() const;
+  void clear_variance();
+  static const int kVarianceFieldNumber = 6;
+  float variance(int index) const;
+  void set_variance(int index, float value);
+  void add_variance(float value);
+  const ::google::protobuf::RepeatedField< float >&
+      variance() const;
+  ::google::protobuf::RepeatedField< float >*
+      mutable_variance();
+
+  // @@protoc_insertion_point(class_scope:caffe.PriorBoxParameter)
+ private:
+  inline void set_has_min_size();
+  inline void clear_has_min_size();
+  inline void set_has_max_size();
+  inline void clear_has_max_size();
+  inline void set_has_flip();
+  inline void clear_has_flip();
+  inline void set_has_clip();
+  inline void clear_has_clip();
+
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  ::google::protobuf::internal::HasBits<1> _has_bits_;
+  mutable int _cached_size_;
+  ::google::protobuf::RepeatedField< float > aspect_ratio_;
+  ::google::protobuf::RepeatedField< float > variance_;
+  float min_size_;
+  float max_size_;
+  bool flip_;
+  bool clip_;
+  friend void  protobuf_InitDefaults_caffe_2eproto_impl();
+  friend void  protobuf_AddDesc_caffe_2eproto_impl();
+  friend void protobuf_AssignDesc_caffe_2eproto();
+  friend void protobuf_ShutdownFile_caffe_2eproto();
+
+  void InitAsDefaultInstance();
+};
+extern ::google::protobuf::internal::ExplicitlyConstructed<PriorBoxParameter> PriorBoxParameter_default_instance_;
+
+// -------------------------------------------------------------------
+
+class DetectionOutputParameter : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:caffe.DetectionOutputParameter) */ {
+ public:
+  DetectionOutputParameter();
+  virtual ~DetectionOutputParameter();
+
+  DetectionOutputParameter(const DetectionOutputParameter& from);
+
+  inline DetectionOutputParameter& operator=(const DetectionOutputParameter& from) {
+    CopyFrom(from);
+    return *this;
+  }
+
+  inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields();
+  }
+
+  inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields();
+  }
+
+  static const ::google::protobuf::Descriptor* descriptor();
+  static const DetectionOutputParameter& default_instance();
+
+  static const DetectionOutputParameter* internal_default_instance();
+
+  void Swap(DetectionOutputParameter* other);
+
+  // implements Message ----------------------------------------------
+
+  inline DetectionOutputParameter* New() const { return New(NULL); }
+
+  DetectionOutputParameter* New(::google::protobuf::Arena* arena) const;
+  void CopyFrom(const ::google::protobuf::Message& from);
+  void MergeFrom(const ::google::protobuf::Message& from);
+  void CopyFrom(const DetectionOutputParameter& from);
+  void MergeFrom(const DetectionOutputParameter& from);
+  void Clear();
+  bool IsInitialized() const;
+
+  size_t ByteSizeLong() const;
+  bool MergePartialFromCodedStream(
+      ::google::protobuf::io::CodedInputStream* input);
+  void SerializeWithCachedSizes(
+      ::google::protobuf::io::CodedOutputStream* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
+  int GetCachedSize() const { return _cached_size_; }
+  private:
+  void SharedCtor();
+  void SharedDtor();
+  void SetCachedSize(int size) const;
+  void InternalSwap(DetectionOutputParameter* other);
+  void UnsafeMergeFrom(const DetectionOutputParameter& from);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
+  public:
+
+  ::google::protobuf::Metadata GetMetadata() const;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  // optional uint32 num_classes = 1;
+  bool has_num_classes() const;
+  void clear_num_classes();
+  static const int kNumClassesFieldNumber = 1;
+  ::google::protobuf::uint32 num_classes() const;
+  void set_num_classes(::google::protobuf::uint32 value);
+
+  // optional bool share_location = 2 [default = true];
+  bool has_share_location() const;
+  void clear_share_location();
+  static const int kShareLocationFieldNumber = 2;
+  bool share_location() const;
+  void set_share_location(bool value);
+
+  // optional int32 background_label_id = 3 [default = 0];
+  bool has_background_label_id() const;
+  void clear_background_label_id();
+  static const int kBackgroundLabelIdFieldNumber = 3;
+  ::google::protobuf::int32 background_label_id() const;
+  void set_background_label_id(::google::protobuf::int32 value);
+
+  // optional .caffe.PriorBoxParameter.CodeType code_type = 6 [default = CORNER];
+  bool has_code_type() const;
+  void clear_code_type();
+  static const int kCodeTypeFieldNumber = 6;
+  ::caffe::PriorBoxParameter_CodeType code_type() const;
+  void set_code_type(::caffe::PriorBoxParameter_CodeType value);
+
+  // optional bool variance_encoded_in_target = 8 [default = false];
+  bool has_variance_encoded_in_target() const;
+  void clear_variance_encoded_in_target();
+  static const int kVarianceEncodedInTargetFieldNumber = 8;
+  bool variance_encoded_in_target() const;
+  void set_variance_encoded_in_target(bool value);
+
+  // optional int32 keep_top_k = 7 [default = -1];
+  bool has_keep_top_k() const;
+  void clear_keep_top_k();
+  static const int kKeepTopKFieldNumber = 7;
+  ::google::protobuf::int32 keep_top_k() const;
+  void set_keep_top_k(::google::protobuf::int32 value);
+
+  // optional float confidence_threshold = 9;
+  bool has_confidence_threshold() const;
+  void clear_confidence_threshold();
+  static const int kConfidenceThresholdFieldNumber = 9;
+  float confidence_threshold() const;
+  void set_confidence_threshold(float value);
+
+  // optional float nms_threshold = 10 [default = 0.3];
+  bool has_nms_threshold() const;
+  void clear_nms_threshold();
+  static const int kNmsThresholdFieldNumber = 10;
+  float nms_threshold() const;
+  void set_nms_threshold(float value);
+
+  // optional int32 top_k = 11;
+  bool has_top_k() const;
+  void clear_top_k();
+  static const int kTopKFieldNumber = 11;
+  ::google::protobuf::int32 top_k() const;
+  void set_top_k(::google::protobuf::int32 value);
+
+  // @@protoc_insertion_point(class_scope:caffe.DetectionOutputParameter)
+ private:
+  inline void set_has_num_classes();
+  inline void clear_has_num_classes();
+  inline void set_has_share_location();
+  inline void clear_has_share_location();
+  inline void set_has_background_label_id();
+  inline void clear_has_background_label_id();
+  inline void set_has_code_type();
+  inline void clear_has_code_type();
+  inline void set_has_variance_encoded_in_target();
+  inline void clear_has_variance_encoded_in_target();
+  inline void set_has_keep_top_k();
+  inline void clear_has_keep_top_k();
+  inline void set_has_confidence_threshold();
+  inline void clear_has_confidence_threshold();
+  inline void set_has_nms_threshold();
+  inline void clear_has_nms_threshold();
+  inline void set_has_top_k();
+  inline void clear_has_top_k();
+
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  ::google::protobuf::internal::HasBits<1> _has_bits_;
+  mutable int _cached_size_;
+  ::google::protobuf::uint32 num_classes_;
+  ::google::protobuf::int32 background_label_id_;
+  bool variance_encoded_in_target_;
+  float confidence_threshold_;
+  ::google::protobuf::int32 top_k_;
+  bool share_location_;
+  int code_type_;
+  ::google::protobuf::int32 keep_top_k_;
+  float nms_threshold_;
+  friend void  protobuf_InitDefaults_caffe_2eproto_impl();
+  friend void  protobuf_AddDesc_caffe_2eproto_impl();
+  friend void protobuf_AssignDesc_caffe_2eproto();
+  friend void protobuf_ShutdownFile_caffe_2eproto();
+
+  void InitAsDefaultInstance();
+};
+extern ::google::protobuf::internal::ExplicitlyConstructed<DetectionOutputParameter> DetectionOutputParameter_default_instance_;
+
+// -------------------------------------------------------------------
+
+class Datum : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:caffe.Datum) */ {
+ public:
+  Datum();
+  virtual ~Datum();
+
+  Datum(const Datum& from);
+
+  inline Datum& operator=(const Datum& from) {
+    CopyFrom(from);
+    return *this;
+  }
+
+  inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields();
+  }
+
+  inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields();
+  }
+
+  static const ::google::protobuf::Descriptor* descriptor();
+  static const Datum& default_instance();
+
+  static const Datum* internal_default_instance();
+
+  void Swap(Datum* other);
+
+  // implements Message ----------------------------------------------
+
+  inline Datum* New() const { return New(NULL); }
+
+  Datum* New(::google::protobuf::Arena* arena) const;
+  void CopyFrom(const ::google::protobuf::Message& from);
+  void MergeFrom(const ::google::protobuf::Message& from);
+  void CopyFrom(const Datum& from);
+  void MergeFrom(const Datum& from);
+  void Clear();
+  bool IsInitialized() const;
+
+  size_t ByteSizeLong() const;
+  bool MergePartialFromCodedStream(
+      ::google::protobuf::io::CodedInputStream* input);
+  void SerializeWithCachedSizes(
+      ::google::protobuf::io::CodedOutputStream* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
+  int GetCachedSize() const { return _cached_size_; }
+  private:
+  void SharedCtor();
+  void SharedDtor();
+  void SetCachedSize(int size) const;
+  void InternalSwap(Datum* other);
+  void UnsafeMergeFrom(const Datum& from);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
+  public:
+
+  ::google::protobuf::Metadata GetMetadata() const;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  // optional int32 channels = 1;
+  bool has_channels() const;
+  void clear_channels();
+  static const int kChannelsFieldNumber = 1;
+  ::google::protobuf::int32 channels() const;
+  void set_channels(::google::protobuf::int32 value);
+
+  // optional int32 height = 2;
+  bool has_height() const;
+  void clear_height();
+  static const int kHeightFieldNumber = 2;
+  ::google::protobuf::int32 height() const;
+  void set_height(::google::protobuf::int32 value);
+
+  // optional int32 width = 3;
+  bool has_width() const;
+  void clear_width();
+  static const int kWidthFieldNumber = 3;
+  ::google::protobuf::int32 width() const;
+  void set_width(::google::protobuf::int32 value);
+
+  // optional bytes data = 4;
+  bool has_data() const;
+  void clear_data();
+  static const int kDataFieldNumber = 4;
+  const ::std::string& data() const;
+  void set_data(const ::std::string& value);
+  void set_data(const char* value);
+  void set_data(const void* value, size_t size);
+  ::std::string* mutable_data();
+  ::std::string* release_data();
+  void set_allocated_data(::std::string* data);
+
+  // optional int32 label = 5;
+  bool has_label() const;
+  void clear_label();
+  static const int kLabelFieldNumber = 5;
+  ::google::protobuf::int32 label() const;
+  void set_label(::google::protobuf::int32 value);
+
+  // repeated float float_data = 6;
+  int float_data_size() const;
+  void clear_float_data();
+  static const int kFloatDataFieldNumber = 6;
+  float float_data(int index) const;
+  void set_float_data(int index, float value);
+  void add_float_data(float value);
+  const ::google::protobuf::RepeatedField< float >&
+      float_data() const;
+  ::google::protobuf::RepeatedField< float >*
+      mutable_float_data();
+
+  // optional bool encoded = 7 [default = false];
+  bool has_encoded() const;
+  void clear_encoded();
+  static const int kEncodedFieldNumber = 7;
+  bool encoded() const;
+  void set_encoded(bool value);
+
+  // @@protoc_insertion_point(class_scope:caffe.Datum)
+ private:
+  inline void set_has_channels();
+  inline void clear_has_channels();
+  inline void set_has_height();
+  inline void clear_has_height();
+  inline void set_has_width();
+  inline void clear_has_width();
+  inline void set_has_data();
+  inline void clear_has_data();
+  inline void set_has_label();
+  inline void clear_has_label();
+  inline void set_has_encoded();
+  inline void clear_has_encoded();
+
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  ::google::protobuf::internal::HasBits<1> _has_bits_;
+  mutable int _cached_size_;
+  ::google::protobuf::RepeatedField< float > float_data_;
+  ::google::protobuf::internal::ArenaStringPtr data_;
+  ::google::protobuf::int32 channels_;
+  ::google::protobuf::int32 height_;
+  ::google::protobuf::int32 width_;
+  ::google::protobuf::int32 label_;
+  bool encoded_;
+  friend void  protobuf_InitDefaults_caffe_2eproto_impl();
+  friend void  protobuf_AddDesc_caffe_2eproto_impl();
+  friend void protobuf_AssignDesc_caffe_2eproto();
+  friend void protobuf_ShutdownFile_caffe_2eproto();
+
+  void InitAsDefaultInstance();
+};
+extern ::google::protobuf::internal::ExplicitlyConstructed<Datum> Datum_default_instance_;
+
+// -------------------------------------------------------------------
+
+class FillerParameter : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:caffe.FillerParameter) */ {
+ public:
+  FillerParameter();
+  virtual ~FillerParameter();
+
+  FillerParameter(const FillerParameter& from);
+
+  inline FillerParameter& operator=(const FillerParameter& from) {
+    CopyFrom(from);
+    return *this;
+  }
+
+  inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields();
+  }
+
+  inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields();
+  }
+
+  static const ::google::protobuf::Descriptor* descriptor();
+  static const FillerParameter& default_instance();
+
+  static const FillerParameter* internal_default_instance();
+
+  void Swap(FillerParameter* other);
+
+  // implements Message ----------------------------------------------
+
+  inline FillerParameter* New() const { return New(NULL); }
+
+  FillerParameter* New(::google::protobuf::Arena* arena) const;
+  void CopyFrom(const ::google::protobuf::Message& from);
+  void MergeFrom(const ::google::protobuf::Message& from);
+  void CopyFrom(const FillerParameter& from);
+  void MergeFrom(const FillerParameter& from);
+  void Clear();
+  bool IsInitialized() const;
+
+  size_t ByteSizeLong() const;
+  bool MergePartialFromCodedStream(
+      ::google::protobuf::io::CodedInputStream* input);
+  void SerializeWithCachedSizes(
+      ::google::protobuf::io::CodedOutputStream* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
+  int GetCachedSize() const { return _cached_size_; }
+  private:
+  void SharedCtor();
+  void SharedDtor();
+  void SetCachedSize(int size) const;
+  void InternalSwap(FillerParameter* other);
+  void UnsafeMergeFrom(const FillerParameter& from);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
+  public:
+
+  ::google::protobuf::Metadata GetMetadata() const;
+
+  // nested types ----------------------------------------------------
+
+  typedef FillerParameter_VarianceNorm VarianceNorm;
+  static const VarianceNorm FAN_IN =
+    FillerParameter_VarianceNorm_FAN_IN;
+  static const VarianceNorm FAN_OUT =
+    FillerParameter_VarianceNorm_FAN_OUT;
+  static const VarianceNorm AVERAGE =
+    FillerParameter_VarianceNorm_AVERAGE;
+  static inline bool VarianceNorm_IsValid(int value) {
+    return FillerParameter_VarianceNorm_IsValid(value);
+  }
+  static const VarianceNorm VarianceNorm_MIN =
+    FillerParameter_VarianceNorm_VarianceNorm_MIN;
+  static const VarianceNorm VarianceNorm_MAX =
+    FillerParameter_VarianceNorm_VarianceNorm_MAX;
+  static const int VarianceNorm_ARRAYSIZE =
+    FillerParameter_VarianceNorm_VarianceNorm_ARRAYSIZE;
+  static inline const ::google::protobuf::EnumDescriptor*
+  VarianceNorm_descriptor() {
+    return FillerParameter_VarianceNorm_descriptor();
+  }
+  static inline const ::std::string& VarianceNorm_Name(VarianceNorm value) {
+    return FillerParameter_VarianceNorm_Name(value);
+  }
+  static inline bool VarianceNorm_Parse(const ::std::string& name,
+      VarianceNorm* value) {
+    return FillerParameter_VarianceNorm_Parse(name, value);
+  }
+
+  // accessors -------------------------------------------------------
+
+  // optional string type = 1 [default = "constant"];
+  bool has_type() const;
+  void clear_type();
+  static const int kTypeFieldNumber = 1;
+  const ::std::string& type() const;
+  void set_type(const ::std::string& value);
+  void set_type(const char* value);
+  void set_type(const char* value, size_t size);
+  ::std::string* mutable_type();
+  ::std::string* release_type();
+  void set_allocated_type(::std::string* type);
+
+  // optional float value = 2 [default = 0];
+  bool has_value() const;
+  void clear_value();
+  static const int kValueFieldNumber = 2;
+  float value() const;
+  void set_value(float value);
+
+  // optional float min = 3 [default = 0];
+  bool has_min() const;
+  void clear_min();
+  static const int kMinFieldNumber = 3;
+  float min() const;
+  void set_min(float value);
+
+  // optional float max = 4 [default = 1];
+  bool has_max() const;
+  void clear_max();
+  static const int kMaxFieldNumber = 4;
+  float max() const;
+  void set_max(float value);
+
+  // optional float mean = 5 [default = 0];
+  bool has_mean() const;
+  void clear_mean();
+  static const int kMeanFieldNumber = 5;
+  float mean() const;
+  void set_mean(float value);
+
+  // optional float std = 6 [default = 1];
+  bool has_std() const;
+  void clear_std();
+  static const int kStdFieldNumber = 6;
+  float std() const;
+  void set_std(float value);
+
+  // optional int32 sparse = 7 [default = -1];
+  bool has_sparse() const;
+  void clear_sparse();
+  static const int kSparseFieldNumber = 7;
+  ::google::protobuf::int32 sparse() const;
+  void set_sparse(::google::protobuf::int32 value);
+
+  // optional .caffe.FillerParameter.VarianceNorm variance_norm = 8 [default = FAN_IN];
+  bool has_variance_norm() const;
+  void clear_variance_norm();
+  static const int kVarianceNormFieldNumber = 8;
+  ::caffe::FillerParameter_VarianceNorm variance_norm() const;
+  void set_variance_norm(::caffe::FillerParameter_VarianceNorm value);
+
+  // @@protoc_insertion_point(class_scope:caffe.FillerParameter)
+ private:
+  inline void set_has_type();
+  inline void clear_has_type();
+  inline void set_has_value();
+  inline void clear_has_value();
+  inline void set_has_min();
+  inline void clear_has_min();
+  inline void set_has_max();
+  inline void clear_has_max();
+  inline void set_has_mean();
+  inline void clear_has_mean();
+  inline void set_has_std();
+  inline void clear_has_std();
+  inline void set_has_sparse();
+  inline void clear_has_sparse();
+  inline void set_has_variance_norm();
+  inline void clear_has_variance_norm();
+
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  ::google::protobuf::internal::HasBits<1> _has_bits_;
+  mutable int _cached_size_;
+  static ::std::string* _default_type_;
+  ::google::protobuf::internal::ArenaStringPtr type_;
+  float value_;
+  float min_;
+  float mean_;
+  int variance_norm_;
+  ::google::protobuf::int32 sparse_;
+  float max_;
+  float std_;
+  friend void  protobuf_InitDefaults_caffe_2eproto_impl();
+  friend void  protobuf_AddDesc_caffe_2eproto_impl();
+  friend void protobuf_AssignDesc_caffe_2eproto();
+  friend void protobuf_ShutdownFile_caffe_2eproto();
+
+  void InitAsDefaultInstance();
+};
+extern ::google::protobuf::internal::ExplicitlyConstructed<FillerParameter> FillerParameter_default_instance_;
+
+// -------------------------------------------------------------------
+
+class NetParameter : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:caffe.NetParameter) */ {
+ public:
+  NetParameter();
+  virtual ~NetParameter();
+
+  NetParameter(const NetParameter& from);
+
+  inline NetParameter& operator=(const NetParameter& from) {
+    CopyFrom(from);
+    return *this;
+  }
+
+  inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields();
+  }
+
+  inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields();
+  }
+
+  static const ::google::protobuf::Descriptor* descriptor();
+  static const NetParameter& default_instance();
+
+  static const NetParameter* internal_default_instance();
+
+  void Swap(NetParameter* other);
+
+  // implements Message ----------------------------------------------
+
+  inline NetParameter* New() const { return New(NULL); }
+
+  NetParameter* New(::google::protobuf::Arena* arena) const;
+  void CopyFrom(const ::google::protobuf::Message& from);
+  void MergeFrom(const ::google::protobuf::Message& from);
+  void CopyFrom(const NetParameter& from);
+  void MergeFrom(const NetParameter& from);
+  void Clear();
+  bool IsInitialized() const;
+
+  size_t ByteSizeLong() const;
+  bool MergePartialFromCodedStream(
+      ::google::protobuf::io::CodedInputStream* input);
+  void SerializeWithCachedSizes(
+      ::google::protobuf::io::CodedOutputStream* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
+  int GetCachedSize() const { return _cached_size_; }
+  private:
+  void SharedCtor();
+  void SharedDtor();
+  void SetCachedSize(int size) const;
+  void InternalSwap(NetParameter* other);
+  void UnsafeMergeFrom(const NetParameter& from);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
+  public:
+
+  ::google::protobuf::Metadata GetMetadata() const;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  // optional string name = 1;
+  bool has_name() const;
+  void clear_name();
+  static const int kNameFieldNumber = 1;
+  const ::std::string& name() const;
+  void set_name(const ::std::string& value);
+  void set_name(const char* value);
+  void set_name(const char* value, size_t size);
+  ::std::string* mutable_name();
+  ::std::string* release_name();
+  void set_allocated_name(::std::string* name);
+
+  // repeated string input = 3;
+  int input_size() const;
+  void clear_input();
+  static const int kInputFieldNumber = 3;
+  const ::std::string& input(int index) const;
+  ::std::string* mutable_input(int index);
+  void set_input(int index, const ::std::string& value);
+  void set_input(int index, const char* value);
+  void set_input(int index, const char* value, size_t size);
+  ::std::string* add_input();
+  void add_input(const ::std::string& value);
+  void add_input(const char* value);
+  void add_input(const char* value, size_t size);
+  const ::google::protobuf::RepeatedPtrField< ::std::string>& input() const;
+  ::google::protobuf::RepeatedPtrField< ::std::string>* mutable_input();
+
+  // repeated .caffe.BlobShape input_shape = 8;
+  int input_shape_size() const;
+  void clear_input_shape();
+  static const int kInputShapeFieldNumber = 8;
+  const ::caffe::BlobShape& input_shape(int index) const;
+  ::caffe::BlobShape* mutable_input_shape(int index);
+  ::caffe::BlobShape* add_input_shape();
+  ::google::protobuf::RepeatedPtrField< ::caffe::BlobShape >*
+      mutable_input_shape();
+  const ::google::protobuf::RepeatedPtrField< ::caffe::BlobShape >&
+      input_shape() const;
+
+  // repeated int32 input_dim = 4;
+  int input_dim_size() const;
+  void clear_input_dim();
+  static const int kInputDimFieldNumber = 4;
+  ::google::protobuf::int32 input_dim(int index) const;
+  void set_input_dim(int index, ::google::protobuf::int32 value);
+  void add_input_dim(::google::protobuf::int32 value);
+  const ::google::protobuf::RepeatedField< ::google::protobuf::int32 >&
+      input_dim() const;
+  ::google::protobuf::RepeatedField< ::google::protobuf::int32 >*
+      mutable_input_dim();
+
+  // optional bool force_backward = 5 [default = false];
+  bool has_force_backward() const;
+  void clear_force_backward();
+  static const int kForceBackwardFieldNumber = 5;
+  bool force_backward() const;
+  void set_force_backward(bool value);
+
+  // optional .caffe.NetState state = 6;
+  bool has_state() const;
+  void clear_state();
+  static const int kStateFieldNumber = 6;
+  const ::caffe::NetState& state() const;
+  ::caffe::NetState* mutable_state();
+  ::caffe::NetState* release_state();
+  void set_allocated_state(::caffe::NetState* state);
+
+  // optional bool debug_info = 7 [default = false];
+  bool has_debug_info() const;
+  void clear_debug_info();
+  static const int kDebugInfoFieldNumber = 7;
+  bool debug_info() const;
+  void set_debug_info(bool value);
+
+  // repeated .caffe.LayerParameter layer = 100;
+  int layer_size() const;
+  void clear_layer();
+  static const int kLayerFieldNumber = 100;
+  const ::caffe::LayerParameter& layer(int index) const;
+  ::caffe::LayerParameter* mutable_layer(int index);
+  ::caffe::LayerParameter* add_layer();
+  ::google::protobuf::RepeatedPtrField< ::caffe::LayerParameter >*
+      mutable_layer();
+  const ::google::protobuf::RepeatedPtrField< ::caffe::LayerParameter >&
+      layer() const;
+
+  // repeated .caffe.V1LayerParameter layers = 2;
+  int layers_size() const;
+  void clear_layers();
+  static const int kLayersFieldNumber = 2;
+  const ::caffe::V1LayerParameter& layers(int index) const;
+  ::caffe::V1LayerParameter* mutable_layers(int index);
+  ::caffe::V1LayerParameter* add_layers();
+  ::google::protobuf::RepeatedPtrField< ::caffe::V1LayerParameter >*
+      mutable_layers();
+  const ::google::protobuf::RepeatedPtrField< ::caffe::V1LayerParameter >&
+      layers() const;
+
+  // @@protoc_insertion_point(class_scope:caffe.NetParameter)
+ private:
+  inline void set_has_name();
+  inline void clear_has_name();
+  inline void set_has_force_backward();
+  inline void clear_has_force_backward();
+  inline void set_has_state();
+  inline void clear_has_state();
+  inline void set_has_debug_info();
+  inline void clear_has_debug_info();
+
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  ::google::protobuf::internal::HasBits<1> _has_bits_;
+  mutable int _cached_size_;
+  ::google::protobuf::RepeatedPtrField< ::std::string> input_;
+  ::google::protobuf::RepeatedPtrField< ::caffe::BlobShape > input_shape_;
+  ::google::protobuf::RepeatedField< ::google::protobuf::int32 > input_dim_;
+  ::google::protobuf::RepeatedPtrField< ::caffe::LayerParameter > layer_;
+  ::google::protobuf::RepeatedPtrField< ::caffe::V1LayerParameter > layers_;
+  ::google::protobuf::internal::ArenaStringPtr name_;
+  ::caffe::NetState* state_;
+  bool force_backward_;
+  bool debug_info_;
+  friend void  protobuf_InitDefaults_caffe_2eproto_impl();
+  friend void  protobuf_AddDesc_caffe_2eproto_impl();
+  friend void protobuf_AssignDesc_caffe_2eproto();
+  friend void protobuf_ShutdownFile_caffe_2eproto();
+
+  void InitAsDefaultInstance();
+};
+extern ::google::protobuf::internal::ExplicitlyConstructed<NetParameter> NetParameter_default_instance_;
+
+// -------------------------------------------------------------------
+
+class SolverParameter : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:caffe.SolverParameter) */ {
+ public:
+  SolverParameter();
+  virtual ~SolverParameter();
+
+  SolverParameter(const SolverParameter& from);
+
+  inline SolverParameter& operator=(const SolverParameter& from) {
+    CopyFrom(from);
+    return *this;
+  }
+
+  inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields();
+  }
+
+  inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields();
+  }
+
+  static const ::google::protobuf::Descriptor* descriptor();
+  static const SolverParameter& default_instance();
+
+  static const SolverParameter* internal_default_instance();
+
+  void Swap(SolverParameter* other);
+
+  // implements Message ----------------------------------------------
+
+  inline SolverParameter* New() const { return New(NULL); }
+
+  SolverParameter* New(::google::protobuf::Arena* arena) const;
+  void CopyFrom(const ::google::protobuf::Message& from);
+  void MergeFrom(const ::google::protobuf::Message& from);
+  void CopyFrom(const SolverParameter& from);
+  void MergeFrom(const SolverParameter& from);
+  void Clear();
+  bool IsInitialized() const;
+
+  size_t ByteSizeLong() const;
+  bool MergePartialFromCodedStream(
+      ::google::protobuf::io::CodedInputStream* input);
+  void SerializeWithCachedSizes(
+      ::google::protobuf::io::CodedOutputStream* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
+  int GetCachedSize() const { return _cached_size_; }
+  private:
+  void SharedCtor();
+  void SharedDtor();
+  void SetCachedSize(int size) const;
+  void InternalSwap(SolverParameter* other);
+  void UnsafeMergeFrom(const SolverParameter& from);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
+  public:
+
+  ::google::protobuf::Metadata GetMetadata() const;
+
+  // nested types ----------------------------------------------------
+
+  typedef SolverParameter_SolverMode SolverMode;
+  static const SolverMode CPU =
+    SolverParameter_SolverMode_CPU;
+  static const SolverMode GPU =
+    SolverParameter_SolverMode_GPU;
+  static inline bool SolverMode_IsValid(int value) {
+    return SolverParameter_SolverMode_IsValid(value);
+  }
+  static const SolverMode SolverMode_MIN =
+    SolverParameter_SolverMode_SolverMode_MIN;
+  static const SolverMode SolverMode_MAX =
+    SolverParameter_SolverMode_SolverMode_MAX;
+  static const int SolverMode_ARRAYSIZE =
+    SolverParameter_SolverMode_SolverMode_ARRAYSIZE;
+  static inline const ::google::protobuf::EnumDescriptor*
+  SolverMode_descriptor() {
+    return SolverParameter_SolverMode_descriptor();
+  }
+  static inline const ::std::string& SolverMode_Name(SolverMode value) {
+    return SolverParameter_SolverMode_Name(value);
+  }
+  static inline bool SolverMode_Parse(const ::std::string& name,
+      SolverMode* value) {
+    return SolverParameter_SolverMode_Parse(name, value);
+  }
+
+  typedef SolverParameter_SolverType SolverType;
+  static const SolverType SGD =
+    SolverParameter_SolverType_SGD;
+  static const SolverType NESTEROV =
+    SolverParameter_SolverType_NESTEROV;
+  static const SolverType ADAGRAD =
+    SolverParameter_SolverType_ADAGRAD;
+  static inline bool SolverType_IsValid(int value) {
+    return SolverParameter_SolverType_IsValid(value);
+  }
+  static const SolverType SolverType_MIN =
+    SolverParameter_SolverType_SolverType_MIN;
+  static const SolverType SolverType_MAX =
+    SolverParameter_SolverType_SolverType_MAX;
+  static const int SolverType_ARRAYSIZE =
+    SolverParameter_SolverType_SolverType_ARRAYSIZE;
+  static inline const ::google::protobuf::EnumDescriptor*
+  SolverType_descriptor() {
+    return SolverParameter_SolverType_descriptor();
+  }
+  static inline const ::std::string& SolverType_Name(SolverType value) {
+    return SolverParameter_SolverType_Name(value);
+  }
+  static inline bool SolverType_Parse(const ::std::string& name,
+      SolverType* value) {
+    return SolverParameter_SolverType_Parse(name, value);
+  }
+
+  // accessors -------------------------------------------------------
+
+  // optional string net = 24;
+  bool has_net() const;
+  void clear_net();
+  static const int kNetFieldNumber = 24;
+  const ::std::string& net() const;
+  void set_net(const ::std::string& value);
+  void set_net(const char* value);
+  void set_net(const char* value, size_t size);
+  ::std::string* mutable_net();
+  ::std::string* release_net();
+  void set_allocated_net(::std::string* net);
+
+  // optional .caffe.NetParameter net_param = 25;
+  bool has_net_param() const;
+  void clear_net_param();
+  static const int kNetParamFieldNumber = 25;
+  const ::caffe::NetParameter& net_param() const;
+  ::caffe::NetParameter* mutable_net_param();
+  ::caffe::NetParameter* release_net_param();
+  void set_allocated_net_param(::caffe::NetParameter* net_param);
+
+  // optional string train_net = 1;
+  bool has_train_net() const;
+  void clear_train_net();
+  static const int kTrainNetFieldNumber = 1;
+  const ::std::string& train_net() const;
+  void set_train_net(const ::std::string& value);
+  void set_train_net(const char* value);
+  void set_train_net(const char* value, size_t size);
+  ::std::string* mutable_train_net();
+  ::std::string* release_train_net();
+  void set_allocated_train_net(::std::string* train_net);
+
+  // repeated string test_net = 2;
+  int test_net_size() const;
+  void clear_test_net();
+  static const int kTestNetFieldNumber = 2;
+  const ::std::string& test_net(int index) const;
+  ::std::string* mutable_test_net(int index);
+  void set_test_net(int index, const ::std::string& value);
+  void set_test_net(int index, const char* value);
+  void set_test_net(int index, const char* value, size_t size);
+  ::std::string* add_test_net();
+  void add_test_net(const ::std::string& value);
+  void add_test_net(const char* value);
+  void add_test_net(const char* value, size_t size);
+  const ::google::protobuf::RepeatedPtrField< ::std::string>& test_net() const;
+  ::google::protobuf::RepeatedPtrField< ::std::string>* mutable_test_net();
+
+  // optional .caffe.NetParameter train_net_param = 21;
+  bool has_train_net_param() const;
+  void clear_train_net_param();
+  static const int kTrainNetParamFieldNumber = 21;
+  const ::caffe::NetParameter& train_net_param() const;
+  ::caffe::NetParameter* mutable_train_net_param();
+  ::caffe::NetParameter* release_train_net_param();
+  void set_allocated_train_net_param(::caffe::NetParameter* train_net_param);
+
+  // repeated .caffe.NetParameter test_net_param = 22;
+  int test_net_param_size() const;
+  void clear_test_net_param();
+  static const int kTestNetParamFieldNumber = 22;
+  const ::caffe::NetParameter& test_net_param(int index) const;
+  ::caffe::NetParameter* mutable_test_net_param(int index);
+  ::caffe::NetParameter* add_test_net_param();
+  ::google::protobuf::RepeatedPtrField< ::caffe::NetParameter >*
+      mutable_test_net_param();
+  const ::google::protobuf::RepeatedPtrField< ::caffe::NetParameter >&
+      test_net_param() const;
+
+  // optional .caffe.NetState train_state = 26;
+  bool has_train_state() const;
+  void clear_train_state();
+  static const int kTrainStateFieldNumber = 26;
+  const ::caffe::NetState& train_state() const;
+  ::caffe::NetState* mutable_train_state();
+  ::caffe::NetState* release_train_state();
+  void set_allocated_train_state(::caffe::NetState* train_state);
+
+  // repeated .caffe.NetState test_state = 27;
+  int test_state_size() const;
+  void clear_test_state();
+  static const int kTestStateFieldNumber = 27;
+  const ::caffe::NetState& test_state(int index) const;
+  ::caffe::NetState* mutable_test_state(int index);
+  ::caffe::NetState* add_test_state();
+  ::google::protobuf::RepeatedPtrField< ::caffe::NetState >*
+      mutable_test_state();
+  const ::google::protobuf::RepeatedPtrField< ::caffe::NetState >&
+      test_state() const;
+
+  // repeated int32 test_iter = 3;
+  int test_iter_size() const;
+  void clear_test_iter();
+  static const int kTestIterFieldNumber = 3;
+  ::google::protobuf::int32 test_iter(int index) const;
+  void set_test_iter(int index, ::google::protobuf::int32 value);
+  void add_test_iter(::google::protobuf::int32 value);
+  const ::google::protobuf::RepeatedField< ::google::protobuf::int32 >&
+      test_iter() const;
+  ::google::protobuf::RepeatedField< ::google::protobuf::int32 >*
+      mutable_test_iter();
+
+  // optional int32 test_interval = 4 [default = 0];
+  bool has_test_interval() const;
+  void clear_test_interval();
+  static const int kTestIntervalFieldNumber = 4;
+  ::google::protobuf::int32 test_interval() const;
+  void set_test_interval(::google::protobuf::int32 value);
+
+  // optional bool test_compute_loss = 19 [default = false];
+  bool has_test_compute_loss() const;
+  void clear_test_compute_loss();
+  static const int kTestComputeLossFieldNumber = 19;
+  bool test_compute_loss() const;
+  void set_test_compute_loss(bool value);
+
+  // optional bool test_initialization = 32 [default = true];
+  bool has_test_initialization() const;
+  void clear_test_initialization();
+  static const int kTestInitializationFieldNumber = 32;
+  bool test_initialization() const;
+  void set_test_initialization(bool value);
+
+  // optional float base_lr = 5;
+  bool has_base_lr() const;
+  void clear_base_lr();
+  static const int kBaseLrFieldNumber = 5;
+  float base_lr() const;
+  void set_base_lr(float value);
+
+  // optional int32 display = 6;
+  bool has_display() const;
+  void clear_display();
+  static const int kDisplayFieldNumber = 6;
+  ::google::protobuf::int32 display() const;
+  void set_display(::google::protobuf::int32 value);
+
+  // optional int32 average_loss = 33 [default = 1];
+  bool has_average_loss() const;
+  void clear_average_loss();
+  static const int kAverageLossFieldNumber = 33;
+  ::google::protobuf::int32 average_loss() const;
+  void set_average_loss(::google::protobuf::int32 value);
+
+  // optional int32 max_iter = 7;
+  bool has_max_iter() const;
+  void clear_max_iter();
+  static const int kMaxIterFieldNumber = 7;
+  ::google::protobuf::int32 max_iter() const;
+  void set_max_iter(::google::protobuf::int32 value);
+
+  // optional int32 iter_size = 36 [default = 1];
+  bool has_iter_size() const;
+  void clear_iter_size();
+  static const int kIterSizeFieldNumber = 36;
+  ::google::protobuf::int32 iter_size() const;
+  void set_iter_size(::google::protobuf::int32 value);
+
+  // optional string lr_policy = 8;
+  bool has_lr_policy() const;
+  void clear_lr_policy();
+  static const int kLrPolicyFieldNumber = 8;
+  const ::std::string& lr_policy() const;
+  void set_lr_policy(const ::std::string& value);
+  void set_lr_policy(const char* value);
+  void set_lr_policy(const char* value, size_t size);
+  ::std::string* mutable_lr_policy();
+  ::std::string* release_lr_policy();
+  void set_allocated_lr_policy(::std::string* lr_policy);
+
+  // optional float gamma = 9;
+  bool has_gamma() const;
+  void clear_gamma();
+  static const int kGammaFieldNumber = 9;
+  float gamma() const;
+  void set_gamma(float value);
+
+  // optional float power = 10;
+  bool has_power() const;
+  void clear_power();
+  static const int kPowerFieldNumber = 10;
+  float power() const;
+  void set_power(float value);
+
+  // optional float momentum = 11;
+  bool has_momentum() const;
+  void clear_momentum();
+  static const int kMomentumFieldNumber = 11;
+  float momentum() const;
+  void set_momentum(float value);
+
+  // optional float weight_decay = 12;
+  bool has_weight_decay() const;
+  void clear_weight_decay();
+  static const int kWeightDecayFieldNumber = 12;
+  float weight_decay() const;
+  void set_weight_decay(float value);
+
+  // optional string regularization_type = 29 [default = "L2"];
+  bool has_regularization_type() const;
+  void clear_regularization_type();
+  static const int kRegularizationTypeFieldNumber = 29;
+  const ::std::string& regularization_type() const;
+  void set_regularization_type(const ::std::string& value);
+  void set_regularization_type(const char* value);
+  void set_regularization_type(const char* value, size_t size);
+  ::std::string* mutable_regularization_type();
+  ::std::string* release_regularization_type();
+  void set_allocated_regularization_type(::std::string* regularization_type);
+
+  // optional int32 stepsize = 13;
+  bool has_stepsize() const;
+  void clear_stepsize();
+  static const int kStepsizeFieldNumber = 13;
+  ::google::protobuf::int32 stepsize() const;
+  void set_stepsize(::google::protobuf::int32 value);
+
+  // repeated int32 stepvalue = 34;
+  int stepvalue_size() const;
+  void clear_stepvalue();
+  static const int kStepvalueFieldNumber = 34;
+  ::google::protobuf::int32 stepvalue(int index) const;
+  void set_stepvalue(int index, ::google::protobuf::int32 value);
+  void add_stepvalue(::google::protobuf::int32 value);
+  const ::google::protobuf::RepeatedField< ::google::protobuf::int32 >&
+      stepvalue() const;
+  ::google::protobuf::RepeatedField< ::google::protobuf::int32 >*
+      mutable_stepvalue();
+
+  // optional float clip_gradients = 35 [default = -1];
+  bool has_clip_gradients() const;
+  void clear_clip_gradients();
+  static const int kClipGradientsFieldNumber = 35;
+  float clip_gradients() const;
+  void set_clip_gradients(float value);
+
+  // optional int32 snapshot = 14 [default = 0];
+  bool has_snapshot() const;
+  void clear_snapshot();
+  static const int kSnapshotFieldNumber = 14;
+  ::google::protobuf::int32 snapshot() const;
+  void set_snapshot(::google::protobuf::int32 value);
+
+  // optional string snapshot_prefix = 15;
+  bool has_snapshot_prefix() const;
+  void clear_snapshot_prefix();
+  static const int kSnapshotPrefixFieldNumber = 15;
+  const ::std::string& snapshot_prefix() const;
+  void set_snapshot_prefix(const ::std::string& value);
+  void set_snapshot_prefix(const char* value);
+  void set_snapshot_prefix(const char* value, size_t size);
+  ::std::string* mutable_snapshot_prefix();
+  ::std::string* release_snapshot_prefix();
+  void set_allocated_snapshot_prefix(::std::string* snapshot_prefix);
+
+  // optional bool snapshot_diff = 16 [default = false];
+  bool has_snapshot_diff() const;
+  void clear_snapshot_diff();
+  static const int kSnapshotDiffFieldNumber = 16;
+  bool snapshot_diff() const;
+  void set_snapshot_diff(bool value);
+
+  // optional .caffe.SolverParameter.SolverMode solver_mode = 17 [default = GPU];
+  bool has_solver_mode() const;
+  void clear_solver_mode();
+  static const int kSolverModeFieldNumber = 17;
+  ::caffe::SolverParameter_SolverMode solver_mode() const;
+  void set_solver_mode(::caffe::SolverParameter_SolverMode value);
+
+  // optional int32 device_id = 18 [default = 0];
+  bool has_device_id() const;
+  void clear_device_id();
+  static const int kDeviceIdFieldNumber = 18;
+  ::google::protobuf::int32 device_id() const;
+  void set_device_id(::google::protobuf::int32 value);
+
+  // optional int64 random_seed = 20 [default = -1];
+  bool has_random_seed() const;
+  void clear_random_seed();
+  static const int kRandomSeedFieldNumber = 20;
+  ::google::protobuf::int64 random_seed() const;
+  void set_random_seed(::google::protobuf::int64 value);
+
+  // optional .caffe.SolverParameter.SolverType solver_type = 30 [default = SGD];
+  bool has_solver_type() const;
+  void clear_solver_type();
+  static const int kSolverTypeFieldNumber = 30;
+  ::caffe::SolverParameter_SolverType solver_type() const;
+  void set_solver_type(::caffe::SolverParameter_SolverType value);
+
+  // optional float delta = 31 [default = 1e-08];
+  bool has_delta() const;
+  void clear_delta();
+  static const int kDeltaFieldNumber = 31;
+  float delta() const;
+  void set_delta(float value);
+
+  // optional bool debug_info = 23 [default = false];
+  bool has_debug_info() const;
+  void clear_debug_info();
+  static const int kDebugInfoFieldNumber = 23;
+  bool debug_info() const;
+  void set_debug_info(bool value);
+
+  // optional bool snapshot_after_train = 28 [default = true];
+  bool has_snapshot_after_train() const;
+  void clear_snapshot_after_train();
+  static const int kSnapshotAfterTrainFieldNumber = 28;
+  bool snapshot_after_train() const;
+  void set_snapshot_after_train(bool value);
+
+  // @@protoc_insertion_point(class_scope:caffe.SolverParameter)
+ private:
+  inline void set_has_net();
+  inline void clear_has_net();
+  inline void set_has_net_param();
+  inline void clear_has_net_param();
+  inline void set_has_train_net();
+  inline void clear_has_train_net();
+  inline void set_has_train_net_param();
+  inline void clear_has_train_net_param();
+  inline void set_has_train_state();
+  inline void clear_has_train_state();
+  inline void set_has_test_interval();
+  inline void clear_has_test_interval();
+  inline void set_has_test_compute_loss();
+  inline void clear_has_test_compute_loss();
+  inline void set_has_test_initialization();
+  inline void clear_has_test_initialization();
+  inline void set_has_base_lr();
+  inline void clear_has_base_lr();
+  inline void set_has_display();
+  inline void clear_has_display();
+  inline void set_has_average_loss();
+  inline void clear_has_average_loss();
+  inline void set_has_max_iter();
+  inline void clear_has_max_iter();
+  inline void set_has_iter_size();
+  inline void clear_has_iter_size();
+  inline void set_has_lr_policy();
+  inline void clear_has_lr_policy();
+  inline void set_has_gamma();
+  inline void clear_has_gamma();
+  inline void set_has_power();
+  inline void clear_has_power();
+  inline void set_has_momentum();
+  inline void clear_has_momentum();
+  inline void set_has_weight_decay();
+  inline void clear_has_weight_decay();
+  inline void set_has_regularization_type();
+  inline void clear_has_regularization_type();
+  inline void set_has_stepsize();
+  inline void clear_has_stepsize();
+  inline void set_has_clip_gradients();
+  inline void clear_has_clip_gradients();
+  inline void set_has_snapshot();
+  inline void clear_has_snapshot();
+  inline void set_has_snapshot_prefix();
+  inline void clear_has_snapshot_prefix();
+  inline void set_has_snapshot_diff();
+  inline void clear_has_snapshot_diff();
+  inline void set_has_solver_mode();
+  inline void clear_has_solver_mode();
+  inline void set_has_device_id();
+  inline void clear_has_device_id();
+  inline void set_has_random_seed();
+  inline void clear_has_random_seed();
+  inline void set_has_solver_type();
+  inline void clear_has_solver_type();
+  inline void set_has_delta();
+  inline void clear_has_delta();
+  inline void set_has_debug_info();
+  inline void clear_has_debug_info();
+  inline void set_has_snapshot_after_train();
+  inline void clear_has_snapshot_after_train();
+
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  ::google::protobuf::internal::HasBits<2> _has_bits_;
+  ::google::protobuf::RepeatedPtrField< ::std::string> test_net_;
+  ::google::protobuf::RepeatedPtrField< ::caffe::NetParameter > test_net_param_;
+  ::google::protobuf::RepeatedPtrField< ::caffe::NetState > test_state_;
+  ::google::protobuf::RepeatedField< ::google::protobuf::int32 > test_iter_;
+  ::google::protobuf::RepeatedField< ::google::protobuf::int32 > stepvalue_;
+  ::google::protobuf::internal::ArenaStringPtr net_;
+  ::google::protobuf::internal::ArenaStringPtr train_net_;
+  ::google::protobuf::internal::ArenaStringPtr lr_policy_;
+  static ::std::string* _default_regularization_type_;
+  ::google::protobuf::internal::ArenaStringPtr regularization_type_;
+  ::google::protobuf::internal::ArenaStringPtr snapshot_prefix_;
+  ::caffe::NetParameter* net_param_;
+  ::caffe::NetParameter* train_net_param_;
+  ::caffe::NetState* train_state_;
+  ::google::protobuf::int32 test_interval_;
+  float base_lr_;
+  ::google::protobuf::int32 display_;
+  ::google::protobuf::int32 max_iter_;
+  float gamma_;
+  float power_;
+  float momentum_;
+  float weight_decay_;
+  ::google::protobuf::int32 stepsize_;
+  bool test_compute_loss_;
+  bool snapshot_diff_;
+  bool debug_info_;
+  ::google::protobuf::int32 snapshot_;
+  ::google::protobuf::int32 device_id_;
+  int solver_type_;
+  ::google::protobuf::int32 average_loss_;
+  ::google::protobuf::int32 iter_size_;
+  bool test_initialization_;
+  bool snapshot_after_train_;
+  float clip_gradients_;
+  ::google::protobuf::int64 random_seed_;
+  int solver_mode_;
+  float delta_;
+  mutable int _cached_size_;
+  friend void  protobuf_InitDefaults_caffe_2eproto_impl();
+  friend void  protobuf_AddDesc_caffe_2eproto_impl();
+  friend void protobuf_AssignDesc_caffe_2eproto();
+  friend void protobuf_ShutdownFile_caffe_2eproto();
+
+  void InitAsDefaultInstance();
+};
+extern ::google::protobuf::internal::ExplicitlyConstructed<SolverParameter> SolverParameter_default_instance_;
+
+// -------------------------------------------------------------------
+
+class SolverState : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:caffe.SolverState) */ {
+ public:
+  SolverState();
+  virtual ~SolverState();
+
+  SolverState(const SolverState& from);
+
+  inline SolverState& operator=(const SolverState& from) {
+    CopyFrom(from);
+    return *this;
+  }
+
+  inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields();
+  }
+
+  inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields();
+  }
+
+  static const ::google::protobuf::Descriptor* descriptor();
+  static const SolverState& default_instance();
+
+  static const SolverState* internal_default_instance();
+
+  void Swap(SolverState* other);
+
+  // implements Message ----------------------------------------------
+
+  inline SolverState* New() const { return New(NULL); }
+
+  SolverState* New(::google::protobuf::Arena* arena) const;
+  void CopyFrom(const ::google::protobuf::Message& from);
+  void MergeFrom(const ::google::protobuf::Message& from);
+  void CopyFrom(const SolverState& from);
+  void MergeFrom(const SolverState& from);
+  void Clear();
+  bool IsInitialized() const;
+
+  size_t ByteSizeLong() const;
+  bool MergePartialFromCodedStream(
+      ::google::protobuf::io::CodedInputStream* input);
+  void SerializeWithCachedSizes(
+      ::google::protobuf::io::CodedOutputStream* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
+  int GetCachedSize() const { return _cached_size_; }
+  private:
+  void SharedCtor();
+  void SharedDtor();
+  void SetCachedSize(int size) const;
+  void InternalSwap(SolverState* other);
+  void UnsafeMergeFrom(const SolverState& from);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
+  public:
+
+  ::google::protobuf::Metadata GetMetadata() const;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  // optional int32 iter = 1;
+  bool has_iter() const;
+  void clear_iter();
+  static const int kIterFieldNumber = 1;
+  ::google::protobuf::int32 iter() const;
+  void set_iter(::google::protobuf::int32 value);
+
+  // optional string learned_net = 2;
+  bool has_learned_net() const;
+  void clear_learned_net();
+  static const int kLearnedNetFieldNumber = 2;
+  const ::std::string& learned_net() const;
+  void set_learned_net(const ::std::string& value);
+  void set_learned_net(const char* value);
+  void set_learned_net(const char* value, size_t size);
+  ::std::string* mutable_learned_net();
+  ::std::string* release_learned_net();
+  void set_allocated_learned_net(::std::string* learned_net);
+
+  // repeated .caffe.BlobProto history = 3;
+  int history_size() const;
+  void clear_history();
+  static const int kHistoryFieldNumber = 3;
+  const ::caffe::BlobProto& history(int index) const;
+  ::caffe::BlobProto* mutable_history(int index);
+  ::caffe::BlobProto* add_history();
+  ::google::protobuf::RepeatedPtrField< ::caffe::BlobProto >*
+      mutable_history();
+  const ::google::protobuf::RepeatedPtrField< ::caffe::BlobProto >&
+      history() const;
+
+  // optional int32 current_step = 4 [default = 0];
+  bool has_current_step() const;
+  void clear_current_step();
+  static const int kCurrentStepFieldNumber = 4;
+  ::google::protobuf::int32 current_step() const;
+  void set_current_step(::google::protobuf::int32 value);
+
+  // @@protoc_insertion_point(class_scope:caffe.SolverState)
+ private:
+  inline void set_has_iter();
+  inline void clear_has_iter();
+  inline void set_has_learned_net();
+  inline void clear_has_learned_net();
+  inline void set_has_current_step();
+  inline void clear_has_current_step();
+
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  ::google::protobuf::internal::HasBits<1> _has_bits_;
+  mutable int _cached_size_;
+  ::google::protobuf::RepeatedPtrField< ::caffe::BlobProto > history_;
+  ::google::protobuf::internal::ArenaStringPtr learned_net_;
+  ::google::protobuf::int32 iter_;
+  ::google::protobuf::int32 current_step_;
+  friend void  protobuf_InitDefaults_caffe_2eproto_impl();
+  friend void  protobuf_AddDesc_caffe_2eproto_impl();
+  friend void protobuf_AssignDesc_caffe_2eproto();
+  friend void protobuf_ShutdownFile_caffe_2eproto();
+
+  void InitAsDefaultInstance();
+};
+extern ::google::protobuf::internal::ExplicitlyConstructed<SolverState> SolverState_default_instance_;
+
+// -------------------------------------------------------------------
+
+class NetState : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:caffe.NetState) */ {
+ public:
+  NetState();
+  virtual ~NetState();
+
+  NetState(const NetState& from);
+
+  inline NetState& operator=(const NetState& from) {
+    CopyFrom(from);
+    return *this;
+  }
+
+  inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields();
+  }
+
+  inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields();
+  }
+
+  static const ::google::protobuf::Descriptor* descriptor();
+  static const NetState& default_instance();
+
+  static const NetState* internal_default_instance();
+
+  void Swap(NetState* other);
+
+  // implements Message ----------------------------------------------
+
+  inline NetState* New() const { return New(NULL); }
+
+  NetState* New(::google::protobuf::Arena* arena) const;
+  void CopyFrom(const ::google::protobuf::Message& from);
+  void MergeFrom(const ::google::protobuf::Message& from);
+  void CopyFrom(const NetState& from);
+  void MergeFrom(const NetState& from);
+  void Clear();
+  bool IsInitialized() const;
+
+  size_t ByteSizeLong() const;
+  bool MergePartialFromCodedStream(
+      ::google::protobuf::io::CodedInputStream* input);
+  void SerializeWithCachedSizes(
+      ::google::protobuf::io::CodedOutputStream* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
+  int GetCachedSize() const { return _cached_size_; }
+  private:
+  void SharedCtor();
+  void SharedDtor();
+  void SetCachedSize(int size) const;
+  void InternalSwap(NetState* other);
+  void UnsafeMergeFrom(const NetState& from);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
+  public:
+
+  ::google::protobuf::Metadata GetMetadata() const;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  // optional .caffe.Phase phase = 1 [default = TEST];
+  bool has_phase() const;
+  void clear_phase();
+  static const int kPhaseFieldNumber = 1;
+  ::caffe::Phase phase() const;
+  void set_phase(::caffe::Phase value);
+
+  // optional int32 level = 2 [default = 0];
+  bool has_level() const;
+  void clear_level();
+  static const int kLevelFieldNumber = 2;
+  ::google::protobuf::int32 level() const;
+  void set_level(::google::protobuf::int32 value);
+
+  // repeated string stage = 3;
+  int stage_size() const;
+  void clear_stage();
+  static const int kStageFieldNumber = 3;
+  const ::std::string& stage(int index) const;
+  ::std::string* mutable_stage(int index);
+  void set_stage(int index, const ::std::string& value);
+  void set_stage(int index, const char* value);
+  void set_stage(int index, const char* value, size_t size);
+  ::std::string* add_stage();
+  void add_stage(const ::std::string& value);
+  void add_stage(const char* value);
+  void add_stage(const char* value, size_t size);
+  const ::google::protobuf::RepeatedPtrField< ::std::string>& stage() const;
+  ::google::protobuf::RepeatedPtrField< ::std::string>* mutable_stage();
+
+  // @@protoc_insertion_point(class_scope:caffe.NetState)
+ private:
+  inline void set_has_phase();
+  inline void clear_has_phase();
+  inline void set_has_level();
+  inline void clear_has_level();
+
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  ::google::protobuf::internal::HasBits<1> _has_bits_;
+  mutable int _cached_size_;
+  ::google::protobuf::RepeatedPtrField< ::std::string> stage_;
+  ::google::protobuf::int32 level_;
+  int phase_;
+  friend void  protobuf_InitDefaults_caffe_2eproto_impl();
+  friend void  protobuf_AddDesc_caffe_2eproto_impl();
+  friend void protobuf_AssignDesc_caffe_2eproto();
+  friend void protobuf_ShutdownFile_caffe_2eproto();
+
+  void InitAsDefaultInstance();
+};
+extern ::google::protobuf::internal::ExplicitlyConstructed<NetState> NetState_default_instance_;
+
+// -------------------------------------------------------------------
+
+class NetStateRule : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:caffe.NetStateRule) */ {
+ public:
+  NetStateRule();
+  virtual ~NetStateRule();
+
+  NetStateRule(const NetStateRule& from);
+
+  inline NetStateRule& operator=(const NetStateRule& from) {
+    CopyFrom(from);
+    return *this;
+  }
+
+  inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields();
+  }
+
+  inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields();
+  }
+
+  static const ::google::protobuf::Descriptor* descriptor();
+  static const NetStateRule& default_instance();
+
+  static const NetStateRule* internal_default_instance();
+
+  void Swap(NetStateRule* other);
+
+  // implements Message ----------------------------------------------
+
+  inline NetStateRule* New() const { return New(NULL); }
+
+  NetStateRule* New(::google::protobuf::Arena* arena) const;
+  void CopyFrom(const ::google::protobuf::Message& from);
+  void MergeFrom(const ::google::protobuf::Message& from);
+  void CopyFrom(const NetStateRule& from);
+  void MergeFrom(const NetStateRule& from);
+  void Clear();
+  bool IsInitialized() const;
+
+  size_t ByteSizeLong() const;
+  bool MergePartialFromCodedStream(
+      ::google::protobuf::io::CodedInputStream* input);
+  void SerializeWithCachedSizes(
+      ::google::protobuf::io::CodedOutputStream* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
+  int GetCachedSize() const { return _cached_size_; }
+  private:
+  void SharedCtor();
+  void SharedDtor();
+  void SetCachedSize(int size) const;
+  void InternalSwap(NetStateRule* other);
+  void UnsafeMergeFrom(const NetStateRule& from);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
+  public:
+
+  ::google::protobuf::Metadata GetMetadata() const;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  // optional .caffe.Phase phase = 1;
+  bool has_phase() const;
+  void clear_phase();
+  static const int kPhaseFieldNumber = 1;
+  ::caffe::Phase phase() const;
+  void set_phase(::caffe::Phase value);
+
+  // optional int32 min_level = 2;
+  bool has_min_level() const;
+  void clear_min_level();
+  static const int kMinLevelFieldNumber = 2;
+  ::google::protobuf::int32 min_level() const;
+  void set_min_level(::google::protobuf::int32 value);
+
+  // optional int32 max_level = 3;
+  bool has_max_level() const;
+  void clear_max_level();
+  static const int kMaxLevelFieldNumber = 3;
+  ::google::protobuf::int32 max_level() const;
+  void set_max_level(::google::protobuf::int32 value);
+
+  // repeated string stage = 4;
+  int stage_size() const;
+  void clear_stage();
+  static const int kStageFieldNumber = 4;
+  const ::std::string& stage(int index) const;
+  ::std::string* mutable_stage(int index);
+  void set_stage(int index, const ::std::string& value);
+  void set_stage(int index, const char* value);
+  void set_stage(int index, const char* value, size_t size);
+  ::std::string* add_stage();
+  void add_stage(const ::std::string& value);
+  void add_stage(const char* value);
+  void add_stage(const char* value, size_t size);
+  const ::google::protobuf::RepeatedPtrField< ::std::string>& stage() const;
+  ::google::protobuf::RepeatedPtrField< ::std::string>* mutable_stage();
+
+  // repeated string not_stage = 5;
+  int not_stage_size() const;
+  void clear_not_stage();
+  static const int kNotStageFieldNumber = 5;
+  const ::std::string& not_stage(int index) const;
+  ::std::string* mutable_not_stage(int index);
+  void set_not_stage(int index, const ::std::string& value);
+  void set_not_stage(int index, const char* value);
+  void set_not_stage(int index, const char* value, size_t size);
+  ::std::string* add_not_stage();
+  void add_not_stage(const ::std::string& value);
+  void add_not_stage(const char* value);
+  void add_not_stage(const char* value, size_t size);
+  const ::google::protobuf::RepeatedPtrField< ::std::string>& not_stage() const;
+  ::google::protobuf::RepeatedPtrField< ::std::string>* mutable_not_stage();
+
+  // @@protoc_insertion_point(class_scope:caffe.NetStateRule)
+ private:
+  inline void set_has_phase();
+  inline void clear_has_phase();
+  inline void set_has_min_level();
+  inline void clear_has_min_level();
+  inline void set_has_max_level();
+  inline void clear_has_max_level();
+
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  ::google::protobuf::internal::HasBits<1> _has_bits_;
+  mutable int _cached_size_;
+  ::google::protobuf::RepeatedPtrField< ::std::string> stage_;
+  ::google::protobuf::RepeatedPtrField< ::std::string> not_stage_;
+  int phase_;
+  ::google::protobuf::int32 min_level_;
+  ::google::protobuf::int32 max_level_;
+  friend void  protobuf_InitDefaults_caffe_2eproto_impl();
+  friend void  protobuf_AddDesc_caffe_2eproto_impl();
+  friend void protobuf_AssignDesc_caffe_2eproto();
+  friend void protobuf_ShutdownFile_caffe_2eproto();
+
+  void InitAsDefaultInstance();
+};
+extern ::google::protobuf::internal::ExplicitlyConstructed<NetStateRule> NetStateRule_default_instance_;
+
+// -------------------------------------------------------------------
+
+class ParamSpec : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:caffe.ParamSpec) */ {
+ public:
+  ParamSpec();
+  virtual ~ParamSpec();
+
+  ParamSpec(const ParamSpec& from);
+
+  inline ParamSpec& operator=(const ParamSpec& from) {
+    CopyFrom(from);
+    return *this;
+  }
+
+  inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields();
+  }
+
+  inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields();
+  }
+
+  static const ::google::protobuf::Descriptor* descriptor();
+  static const ParamSpec& default_instance();
+
+  static const ParamSpec* internal_default_instance();
+
+  void Swap(ParamSpec* other);
+
+  // implements Message ----------------------------------------------
+
+  inline ParamSpec* New() const { return New(NULL); }
+
+  ParamSpec* New(::google::protobuf::Arena* arena) const;
+  void CopyFrom(const ::google::protobuf::Message& from);
+  void MergeFrom(const ::google::protobuf::Message& from);
+  void CopyFrom(const ParamSpec& from);
+  void MergeFrom(const ParamSpec& from);
+  void Clear();
+  bool IsInitialized() const;
+
+  size_t ByteSizeLong() const;
+  bool MergePartialFromCodedStream(
+      ::google::protobuf::io::CodedInputStream* input);
+  void SerializeWithCachedSizes(
+      ::google::protobuf::io::CodedOutputStream* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
+  int GetCachedSize() const { return _cached_size_; }
+  private:
+  void SharedCtor();
+  void SharedDtor();
+  void SetCachedSize(int size) const;
+  void InternalSwap(ParamSpec* other);
+  void UnsafeMergeFrom(const ParamSpec& from);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
+  public:
+
+  ::google::protobuf::Metadata GetMetadata() const;
+
+  // nested types ----------------------------------------------------
+
+  typedef ParamSpec_DimCheckMode DimCheckMode;
+  static const DimCheckMode STRICT =
+    ParamSpec_DimCheckMode_STRICT;
+  static const DimCheckMode PERMISSIVE =
+    ParamSpec_DimCheckMode_PERMISSIVE;
+  static inline bool DimCheckMode_IsValid(int value) {
+    return ParamSpec_DimCheckMode_IsValid(value);
+  }
+  static const DimCheckMode DimCheckMode_MIN =
+    ParamSpec_DimCheckMode_DimCheckMode_MIN;
+  static const DimCheckMode DimCheckMode_MAX =
+    ParamSpec_DimCheckMode_DimCheckMode_MAX;
+  static const int DimCheckMode_ARRAYSIZE =
+    ParamSpec_DimCheckMode_DimCheckMode_ARRAYSIZE;
+  static inline const ::google::protobuf::EnumDescriptor*
+  DimCheckMode_descriptor() {
+    return ParamSpec_DimCheckMode_descriptor();
+  }
+  static inline const ::std::string& DimCheckMode_Name(DimCheckMode value) {
+    return ParamSpec_DimCheckMode_Name(value);
+  }
+  static inline bool DimCheckMode_Parse(const ::std::string& name,
+      DimCheckMode* value) {
+    return ParamSpec_DimCheckMode_Parse(name, value);
+  }
+
+  // accessors -------------------------------------------------------
+
+  // optional string name = 1;
+  bool has_name() const;
+  void clear_name();
+  static const int kNameFieldNumber = 1;
+  const ::std::string& name() const;
+  void set_name(const ::std::string& value);
+  void set_name(const char* value);
+  void set_name(const char* value, size_t size);
+  ::std::string* mutable_name();
+  ::std::string* release_name();
+  void set_allocated_name(::std::string* name);
+
+  // optional .caffe.ParamSpec.DimCheckMode share_mode = 2;
+  bool has_share_mode() const;
+  void clear_share_mode();
+  static const int kShareModeFieldNumber = 2;
+  ::caffe::ParamSpec_DimCheckMode share_mode() const;
+  void set_share_mode(::caffe::ParamSpec_DimCheckMode value);
+
+  // optional float lr_mult = 3 [default = 1];
+  bool has_lr_mult() const;
+  void clear_lr_mult();
+  static const int kLrMultFieldNumber = 3;
+  float lr_mult() const;
+  void set_lr_mult(float value);
+
+  // optional float decay_mult = 4 [default = 1];
+  bool has_decay_mult() const;
+  void clear_decay_mult();
+  static const int kDecayMultFieldNumber = 4;
+  float decay_mult() const;
+  void set_decay_mult(float value);
+
+  // @@protoc_insertion_point(class_scope:caffe.ParamSpec)
+ private:
+  inline void set_has_name();
+  inline void clear_has_name();
+  inline void set_has_share_mode();
+  inline void clear_has_share_mode();
+  inline void set_has_lr_mult();
+  inline void clear_has_lr_mult();
+  inline void set_has_decay_mult();
+  inline void clear_has_decay_mult();
+
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  ::google::protobuf::internal::HasBits<1> _has_bits_;
+  mutable int _cached_size_;
+  ::google::protobuf::internal::ArenaStringPtr name_;
+  int share_mode_;
+  float lr_mult_;
+  float decay_mult_;
+  friend void  protobuf_InitDefaults_caffe_2eproto_impl();
+  friend void  protobuf_AddDesc_caffe_2eproto_impl();
+  friend void protobuf_AssignDesc_caffe_2eproto();
+  friend void protobuf_ShutdownFile_caffe_2eproto();
+
+  void InitAsDefaultInstance();
+};
+extern ::google::protobuf::internal::ExplicitlyConstructed<ParamSpec> ParamSpec_default_instance_;
+
+// -------------------------------------------------------------------
+
+class LayerParameter : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:caffe.LayerParameter) */ {
+ public:
+  LayerParameter();
+  virtual ~LayerParameter();
+
+  LayerParameter(const LayerParameter& from);
+
+  inline LayerParameter& operator=(const LayerParameter& from) {
+    CopyFrom(from);
+    return *this;
+  }
+
+  inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields();
+  }
+
+  inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields();
+  }
+
+  static const ::google::protobuf::Descriptor* descriptor();
+  static const LayerParameter& default_instance();
+
+  static const LayerParameter* internal_default_instance();
+
+  void Swap(LayerParameter* other);
+
+  // implements Message ----------------------------------------------
+
+  inline LayerParameter* New() const { return New(NULL); }
+
+  LayerParameter* New(::google::protobuf::Arena* arena) const;
+  void CopyFrom(const ::google::protobuf::Message& from);
+  void MergeFrom(const ::google::protobuf::Message& from);
+  void CopyFrom(const LayerParameter& from);
+  void MergeFrom(const LayerParameter& from);
+  void Clear();
+  bool IsInitialized() const;
+
+  size_t ByteSizeLong() const;
+  bool MergePartialFromCodedStream(
+      ::google::protobuf::io::CodedInputStream* input);
+  void SerializeWithCachedSizes(
+      ::google::protobuf::io::CodedOutputStream* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
+  int GetCachedSize() const { return _cached_size_; }
+  private:
+  void SharedCtor();
+  void SharedDtor();
+  void SetCachedSize(int size) const;
+  void InternalSwap(LayerParameter* other);
+  void UnsafeMergeFrom(const LayerParameter& from);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
+  public:
+
+  ::google::protobuf::Metadata GetMetadata() const;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  // optional string name = 1;
+  bool has_name() const;
+  void clear_name();
+  static const int kNameFieldNumber = 1;
+  const ::std::string& name() const;
+  void set_name(const ::std::string& value);
+  void set_name(const char* value);
+  void set_name(const char* value, size_t size);
+  ::std::string* mutable_name();
+  ::std::string* release_name();
+  void set_allocated_name(::std::string* name);
+
+  // optional string type = 2;
+  bool has_type() const;
+  void clear_type();
+  static const int kTypeFieldNumber = 2;
+  const ::std::string& type() const;
+  void set_type(const ::std::string& value);
+  void set_type(const char* value);
+  void set_type(const char* value, size_t size);
+  ::std::string* mutable_type();
+  ::std::string* release_type();
+  void set_allocated_type(::std::string* type);
+
+  // repeated string bottom = 3;
+  int bottom_size() const;
+  void clear_bottom();
+  static const int kBottomFieldNumber = 3;
+  const ::std::string& bottom(int index) const;
+  ::std::string* mutable_bottom(int index);
+  void set_bottom(int index, const ::std::string& value);
+  void set_bottom(int index, const char* value);
+  void set_bottom(int index, const char* value, size_t size);
+  ::std::string* add_bottom();
+  void add_bottom(const ::std::string& value);
+  void add_bottom(const char* value);
+  void add_bottom(const char* value, size_t size);
+  const ::google::protobuf::RepeatedPtrField< ::std::string>& bottom() const;
+  ::google::protobuf::RepeatedPtrField< ::std::string>* mutable_bottom();
+
+  // repeated string top = 4;
+  int top_size() const;
+  void clear_top();
+  static const int kTopFieldNumber = 4;
+  const ::std::string& top(int index) const;
+  ::std::string* mutable_top(int index);
+  void set_top(int index, const ::std::string& value);
+  void set_top(int index, const char* value);
+  void set_top(int index, const char* value, size_t size);
+  ::std::string* add_top();
+  void add_top(const ::std::string& value);
+  void add_top(const char* value);
+  void add_top(const char* value, size_t size);
+  const ::google::protobuf::RepeatedPtrField< ::std::string>& top() const;
+  ::google::protobuf::RepeatedPtrField< ::std::string>* mutable_top();
+
+  // optional .caffe.Phase phase = 10;
+  bool has_phase() const;
+  void clear_phase();
+  static const int kPhaseFieldNumber = 10;
+  ::caffe::Phase phase() const;
+  void set_phase(::caffe::Phase value);
+
+  // repeated float loss_weight = 5;
+  int loss_weight_size() const;
+  void clear_loss_weight();
+  static const int kLossWeightFieldNumber = 5;
+  float loss_weight(int index) const;
+  void set_loss_weight(int index, float value);
+  void add_loss_weight(float value);
+  const ::google::protobuf::RepeatedField< float >&
+      loss_weight() const;
+  ::google::protobuf::RepeatedField< float >*
+      mutable_loss_weight();
+
+  // repeated .caffe.ParamSpec param = 6;
+  int param_size() const;
+  void clear_param();
+  static const int kParamFieldNumber = 6;
+  const ::caffe::ParamSpec& param(int index) const;
+  ::caffe::ParamSpec* mutable_param(int index);
+  ::caffe::ParamSpec* add_param();
+  ::google::protobuf::RepeatedPtrField< ::caffe::ParamSpec >*
+      mutable_param();
+  const ::google::protobuf::RepeatedPtrField< ::caffe::ParamSpec >&
+      param() const;
+
+  // repeated .caffe.BlobProto blobs = 7;
+  int blobs_size() const;
+  void clear_blobs();
+  static const int kBlobsFieldNumber = 7;
+  const ::caffe::BlobProto& blobs(int index) const;
+  ::caffe::BlobProto* mutable_blobs(int index);
+  ::caffe::BlobProto* add_blobs();
+  ::google::protobuf::RepeatedPtrField< ::caffe::BlobProto >*
+      mutable_blobs();
+  const ::google::protobuf::RepeatedPtrField< ::caffe::BlobProto >&
+      blobs() const;
+
+  // repeated bool propagate_down = 11;
+  int propagate_down_size() const;
+  void clear_propagate_down();
+  static const int kPropagateDownFieldNumber = 11;
+  bool propagate_down(int index) const;
+  void set_propagate_down(int index, bool value);
+  void add_propagate_down(bool value);
+  const ::google::protobuf::RepeatedField< bool >&
+      propagate_down() const;
+  ::google::protobuf::RepeatedField< bool >*
+      mutable_propagate_down();
+
+  // repeated .caffe.NetStateRule include = 8;
+  int include_size() const;
+  void clear_include();
+  static const int kIncludeFieldNumber = 8;
+  const ::caffe::NetStateRule& include(int index) const;
+  ::caffe::NetStateRule* mutable_include(int index);
+  ::caffe::NetStateRule* add_include();
+  ::google::protobuf::RepeatedPtrField< ::caffe::NetStateRule >*
+      mutable_include();
+  const ::google::protobuf::RepeatedPtrField< ::caffe::NetStateRule >&
+      include() const;
+
+  // repeated .caffe.NetStateRule exclude = 9;
+  int exclude_size() const;
+  void clear_exclude();
+  static const int kExcludeFieldNumber = 9;
+  const ::caffe::NetStateRule& exclude(int index) const;
+  ::caffe::NetStateRule* mutable_exclude(int index);
+  ::caffe::NetStateRule* add_exclude();
+  ::google::protobuf::RepeatedPtrField< ::caffe::NetStateRule >*
+      mutable_exclude();
+  const ::google::protobuf::RepeatedPtrField< ::caffe::NetStateRule >&
+      exclude() const;
+
+  // optional .caffe.TransformationParameter transform_param = 100;
+  bool has_transform_param() const;
+  void clear_transform_param();
+  static const int kTransformParamFieldNumber = 100;
+  const ::caffe::TransformationParameter& transform_param() const;
+  ::caffe::TransformationParameter* mutable_transform_param();
+  ::caffe::TransformationParameter* release_transform_param();
+  void set_allocated_transform_param(::caffe::TransformationParameter* transform_param);
+
+  // optional .caffe.LossParameter loss_param = 101;
+  bool has_loss_param() const;
+  void clear_loss_param();
+  static const int kLossParamFieldNumber = 101;
+  const ::caffe::LossParameter& loss_param() const;
+  ::caffe::LossParameter* mutable_loss_param();
+  ::caffe::LossParameter* release_loss_param();
+  void set_allocated_loss_param(::caffe::LossParameter* loss_param);
+
+  // optional .caffe.AccuracyParameter accuracy_param = 102;
+  bool has_accuracy_param() const;
+  void clear_accuracy_param();
+  static const int kAccuracyParamFieldNumber = 102;
+  const ::caffe::AccuracyParameter& accuracy_param() const;
+  ::caffe::AccuracyParameter* mutable_accuracy_param();
+  ::caffe::AccuracyParameter* release_accuracy_param();
+  void set_allocated_accuracy_param(::caffe::AccuracyParameter* accuracy_param);
+
+  // optional .caffe.ArgMaxParameter argmax_param = 103;
+  bool has_argmax_param() const;
+  void clear_argmax_param();
+  static const int kArgmaxParamFieldNumber = 103;
+  const ::caffe::ArgMaxParameter& argmax_param() const;
+  ::caffe::ArgMaxParameter* mutable_argmax_param();
+  ::caffe::ArgMaxParameter* release_argmax_param();
+  void set_allocated_argmax_param(::caffe::ArgMaxParameter* argmax_param);
+
+  // optional .caffe.ConcatParameter concat_param = 104;
+  bool has_concat_param() const;
+  void clear_concat_param();
+  static const int kConcatParamFieldNumber = 104;
+  const ::caffe::ConcatParameter& concat_param() const;
+  ::caffe::ConcatParameter* mutable_concat_param();
+  ::caffe::ConcatParameter* release_concat_param();
+  void set_allocated_concat_param(::caffe::ConcatParameter* concat_param);
+
+  // optional .caffe.ContrastiveLossParameter contrastive_loss_param = 105;
+  bool has_contrastive_loss_param() const;
+  void clear_contrastive_loss_param();
+  static const int kContrastiveLossParamFieldNumber = 105;
+  const ::caffe::ContrastiveLossParameter& contrastive_loss_param() const;
+  ::caffe::ContrastiveLossParameter* mutable_contrastive_loss_param();
+  ::caffe::ContrastiveLossParameter* release_contrastive_loss_param();
+  void set_allocated_contrastive_loss_param(::caffe::ContrastiveLossParameter* contrastive_loss_param);
+
+  // optional .caffe.ConvolutionParameter convolution_param = 106;
+  bool has_convolution_param() const;
+  void clear_convolution_param();
+  static const int kConvolutionParamFieldNumber = 106;
+  const ::caffe::ConvolutionParameter& convolution_param() const;
+  ::caffe::ConvolutionParameter* mutable_convolution_param();
+  ::caffe::ConvolutionParameter* release_convolution_param();
+  void set_allocated_convolution_param(::caffe::ConvolutionParameter* convolution_param);
+
+  // optional .caffe.CropParameter crop_param = 137;
+  bool has_crop_param() const;
+  void clear_crop_param();
+  static const int kCropParamFieldNumber = 137;
+  const ::caffe::CropParameter& crop_param() const;
+  ::caffe::CropParameter* mutable_crop_param();
+  ::caffe::CropParameter* release_crop_param();
+  void set_allocated_crop_param(::caffe::CropParameter* crop_param);
+
+  // optional .caffe.DataParameter data_param = 107;
+  bool has_data_param() const;
+  void clear_data_param();
+  static const int kDataParamFieldNumber = 107;
+  const ::caffe::DataParameter& data_param() const;
+  ::caffe::DataParameter* mutable_data_param();
+  ::caffe::DataParameter* release_data_param();
+  void set_allocated_data_param(::caffe::DataParameter* data_param);
+
+  // optional .caffe.DetectionOutputParameter detection_output_param = 141;
+  bool has_detection_output_param() const;
+  void clear_detection_output_param();
+  static const int kDetectionOutputParamFieldNumber = 141;
+  const ::caffe::DetectionOutputParameter& detection_output_param() const;
+  ::caffe::DetectionOutputParameter* mutable_detection_output_param();
+  ::caffe::DetectionOutputParameter* release_detection_output_param();
+  void set_allocated_detection_output_param(::caffe::DetectionOutputParameter* detection_output_param);
+
+  // optional .caffe.DropoutParameter dropout_param = 108;
+  bool has_dropout_param() const;
+  void clear_dropout_param();
+  static const int kDropoutParamFieldNumber = 108;
+  const ::caffe::DropoutParameter& dropout_param() const;
+  ::caffe::DropoutParameter* mutable_dropout_param();
+  ::caffe::DropoutParameter* release_dropout_param();
+  void set_allocated_dropout_param(::caffe::DropoutParameter* dropout_param);
+
+  // optional .caffe.DummyDataParameter dummy_data_param = 109;
+  bool has_dummy_data_param() const;
+  void clear_dummy_data_param();
+  static const int kDummyDataParamFieldNumber = 109;
+  const ::caffe::DummyDataParameter& dummy_data_param() const;
+  ::caffe::DummyDataParameter* mutable_dummy_data_param();
+  ::caffe::DummyDataParameter* release_dummy_data_param();
+  void set_allocated_dummy_data_param(::caffe::DummyDataParameter* dummy_data_param);
+
+  // optional .caffe.EltwiseParameter eltwise_param = 110;
+  bool has_eltwise_param() const;
+  void clear_eltwise_param();
+  static const int kEltwiseParamFieldNumber = 110;
+  const ::caffe::EltwiseParameter& eltwise_param() const;
+  ::caffe::EltwiseParameter* mutable_eltwise_param();
+  ::caffe::EltwiseParameter* release_eltwise_param();
+  void set_allocated_eltwise_param(::caffe::EltwiseParameter* eltwise_param);
+
+  // optional .caffe.ExpParameter exp_param = 111;
+  bool has_exp_param() const;
+  void clear_exp_param();
+  static const int kExpParamFieldNumber = 111;
+  const ::caffe::ExpParameter& exp_param() const;
+  ::caffe::ExpParameter* mutable_exp_param();
+  ::caffe::ExpParameter* release_exp_param();
+  void set_allocated_exp_param(::caffe::ExpParameter* exp_param);
+
+  // optional .caffe.FlattenParameter flatten_param = 135;
+  bool has_flatten_param() const;
+  void clear_flatten_param();
+  static const int kFlattenParamFieldNumber = 135;
+  const ::caffe::FlattenParameter& flatten_param() const;
+  ::caffe::FlattenParameter* mutable_flatten_param();
+  ::caffe::FlattenParameter* release_flatten_param();
+  void set_allocated_flatten_param(::caffe::FlattenParameter* flatten_param);
+
+  // optional .caffe.HDF5DataParameter hdf5_data_param = 112;
+  bool has_hdf5_data_param() const;
+  void clear_hdf5_data_param();
+  static const int kHdf5DataParamFieldNumber = 112;
+  const ::caffe::HDF5DataParameter& hdf5_data_param() const;
+  ::caffe::HDF5DataParameter* mutable_hdf5_data_param();
+  ::caffe::HDF5DataParameter* release_hdf5_data_param();
+  void set_allocated_hdf5_data_param(::caffe::HDF5DataParameter* hdf5_data_param);
+
+  // optional .caffe.HDF5OutputParameter hdf5_output_param = 113;
+  bool has_hdf5_output_param() const;
+  void clear_hdf5_output_param();
+  static const int kHdf5OutputParamFieldNumber = 113;
+  const ::caffe::HDF5OutputParameter& hdf5_output_param() const;
+  ::caffe::HDF5OutputParameter* mutable_hdf5_output_param();
+  ::caffe::HDF5OutputParameter* release_hdf5_output_param();
+  void set_allocated_hdf5_output_param(::caffe::HDF5OutputParameter* hdf5_output_param);
+
+  // optional .caffe.HingeLossParameter hinge_loss_param = 114;
+  bool has_hinge_loss_param() const;
+  void clear_hinge_loss_param();
+  static const int kHingeLossParamFieldNumber = 114;
+  const ::caffe::HingeLossParameter& hinge_loss_param() const;
+  ::caffe::HingeLossParameter* mutable_hinge_loss_param();
+  ::caffe::HingeLossParameter* release_hinge_loss_param();
+  void set_allocated_hinge_loss_param(::caffe::HingeLossParameter* hinge_loss_param);
+
+  // optional .caffe.ImageDataParameter image_data_param = 115;
+  bool has_image_data_param() const;
+  void clear_image_data_param();
+  static const int kImageDataParamFieldNumber = 115;
+  const ::caffe::ImageDataParameter& image_data_param() const;
+  ::caffe::ImageDataParameter* mutable_image_data_param();
+  ::caffe::ImageDataParameter* release_image_data_param();
+  void set_allocated_image_data_param(::caffe::ImageDataParameter* image_data_param);
+
+  // optional .caffe.InfogainLossParameter infogain_loss_param = 116;
+  bool has_infogain_loss_param() const;
+  void clear_infogain_loss_param();
+  static const int kInfogainLossParamFieldNumber = 116;
+  const ::caffe::InfogainLossParameter& infogain_loss_param() const;
+  ::caffe::InfogainLossParameter* mutable_infogain_loss_param();
+  ::caffe::InfogainLossParameter* release_infogain_loss_param();
+  void set_allocated_infogain_loss_param(::caffe::InfogainLossParameter* infogain_loss_param);
+
+  // optional .caffe.InnerProductParameter inner_product_param = 117;
+  bool has_inner_product_param() const;
+  void clear_inner_product_param();
+  static const int kInnerProductParamFieldNumber = 117;
+  const ::caffe::InnerProductParameter& inner_product_param() const;
+  ::caffe::InnerProductParameter* mutable_inner_product_param();
+  ::caffe::InnerProductParameter* release_inner_product_param();
+  void set_allocated_inner_product_param(::caffe::InnerProductParameter* inner_product_param);
+
+  // optional .caffe.LogParameter log_param = 134;
+  bool has_log_param() const;
+  void clear_log_param();
+  static const int kLogParamFieldNumber = 134;
+  const ::caffe::LogParameter& log_param() const;
+  ::caffe::LogParameter* mutable_log_param();
+  ::caffe::LogParameter* release_log_param();
+  void set_allocated_log_param(::caffe::LogParameter* log_param);
+
+  // optional .caffe.LRNParameter lrn_param = 118;
+  bool has_lrn_param() const;
+  void clear_lrn_param();
+  static const int kLrnParamFieldNumber = 118;
+  const ::caffe::LRNParameter& lrn_param() const;
+  ::caffe::LRNParameter* mutable_lrn_param();
+  ::caffe::LRNParameter* release_lrn_param();
+  void set_allocated_lrn_param(::caffe::LRNParameter* lrn_param);
+
+  // optional .caffe.MemoryDataParameter memory_data_param = 119;
+  bool has_memory_data_param() const;
+  void clear_memory_data_param();
+  static const int kMemoryDataParamFieldNumber = 119;
+  const ::caffe::MemoryDataParameter& memory_data_param() const;
+  ::caffe::MemoryDataParameter* mutable_memory_data_param();
+  ::caffe::MemoryDataParameter* release_memory_data_param();
+  void set_allocated_memory_data_param(::caffe::MemoryDataParameter* memory_data_param);
+
+  // optional .caffe.MVNParameter mvn_param = 120;
+  bool has_mvn_param() const;
+  void clear_mvn_param();
+  static const int kMvnParamFieldNumber = 120;
+  const ::caffe::MVNParameter& mvn_param() const;
+  ::caffe::MVNParameter* mutable_mvn_param();
+  ::caffe::MVNParameter* release_mvn_param();
+  void set_allocated_mvn_param(::caffe::MVNParameter* mvn_param);
+
+  // optional .caffe.NormalizeBBoxParameter normalize_bbox_param = 139;
+  bool has_normalize_bbox_param() const;
+  void clear_normalize_bbox_param();
+  static const int kNormalizeBboxParamFieldNumber = 139;
+  const ::caffe::NormalizeBBoxParameter& normalize_bbox_param() const;
+  ::caffe::NormalizeBBoxParameter* mutable_normalize_bbox_param();
+  ::caffe::NormalizeBBoxParameter* release_normalize_bbox_param();
+  void set_allocated_normalize_bbox_param(::caffe::NormalizeBBoxParameter* normalize_bbox_param);
+
+  // optional .caffe.PermuteParameter permute_param = 138;
+  bool has_permute_param() const;
+  void clear_permute_param();
+  static const int kPermuteParamFieldNumber = 138;
+  const ::caffe::PermuteParameter& permute_param() const;
+  ::caffe::PermuteParameter* mutable_permute_param();
+  ::caffe::PermuteParameter* release_permute_param();
+  void set_allocated_permute_param(::caffe::PermuteParameter* permute_param);
+
+  // optional .caffe.PoolingParameter pooling_param = 121;
+  bool has_pooling_param() const;
+  void clear_pooling_param();
+  static const int kPoolingParamFieldNumber = 121;
+  const ::caffe::PoolingParameter& pooling_param() const;
+  ::caffe::PoolingParameter* mutable_pooling_param();
+  ::caffe::PoolingParameter* release_pooling_param();
+  void set_allocated_pooling_param(::caffe::PoolingParameter* pooling_param);
+
+  // optional .caffe.PowerParameter power_param = 122;
+  bool has_power_param() const;
+  void clear_power_param();
+  static const int kPowerParamFieldNumber = 122;
+  const ::caffe::PowerParameter& power_param() const;
+  ::caffe::PowerParameter* mutable_power_param();
+  ::caffe::PowerParameter* release_power_param();
+  void set_allocated_power_param(::caffe::PowerParameter* power_param);
+
+  // optional .caffe.PReLUParameter prelu_param = 131;
+  bool has_prelu_param() const;
+  void clear_prelu_param();
+  static const int kPreluParamFieldNumber = 131;
+  const ::caffe::PReLUParameter& prelu_param() const;
+  ::caffe::PReLUParameter* mutable_prelu_param();
+  ::caffe::PReLUParameter* release_prelu_param();
+  void set_allocated_prelu_param(::caffe::PReLUParameter* prelu_param);
+
+  // optional .caffe.PriorBoxParameter prior_box_param = 140;
+  bool has_prior_box_param() const;
+  void clear_prior_box_param();
+  static const int kPriorBoxParamFieldNumber = 140;
+  const ::caffe::PriorBoxParameter& prior_box_param() const;
+  ::caffe::PriorBoxParameter* mutable_prior_box_param();
+  ::caffe::PriorBoxParameter* release_prior_box_param();
+  void set_allocated_prior_box_param(::caffe::PriorBoxParameter* prior_box_param);
+
+  // optional .caffe.PythonParameter python_param = 130;
+  bool has_python_param() const;
+  void clear_python_param();
+  static const int kPythonParamFieldNumber = 130;
+  const ::caffe::PythonParameter& python_param() const;
+  ::caffe::PythonParameter* mutable_python_param();
+  ::caffe::PythonParameter* release_python_param();
+  void set_allocated_python_param(::caffe::PythonParameter* python_param);
+
+  // optional .caffe.ReductionParameter reduction_param = 136;
+  bool has_reduction_param() const;
+  void clear_reduction_param();
+  static const int kReductionParamFieldNumber = 136;
+  const ::caffe::ReductionParameter& reduction_param() const;
+  ::caffe::ReductionParameter* mutable_reduction_param();
+  ::caffe::ReductionParameter* release_reduction_param();
+  void set_allocated_reduction_param(::caffe::ReductionParameter* reduction_param);
+
+  // optional .caffe.ReLUParameter relu_param = 123;
+  bool has_relu_param() const;
+  void clear_relu_param();
+  static const int kReluParamFieldNumber = 123;
+  const ::caffe::ReLUParameter& relu_param() const;
+  ::caffe::ReLUParameter* mutable_relu_param();
+  ::caffe::ReLUParameter* release_relu_param();
+  void set_allocated_relu_param(::caffe::ReLUParameter* relu_param);
+
+  // optional .caffe.ReshapeParameter reshape_param = 133;
+  bool has_reshape_param() const;
+  void clear_reshape_param();
+  static const int kReshapeParamFieldNumber = 133;
+  const ::caffe::ReshapeParameter& reshape_param() const;
+  ::caffe::ReshapeParameter* mutable_reshape_param();
+  ::caffe::ReshapeParameter* release_reshape_param();
+  void set_allocated_reshape_param(::caffe::ReshapeParameter* reshape_param);
+
+  // optional .caffe.SigmoidParameter sigmoid_param = 124;
+  bool has_sigmoid_param() const;
+  void clear_sigmoid_param();
+  static const int kSigmoidParamFieldNumber = 124;
+  const ::caffe::SigmoidParameter& sigmoid_param() const;
+  ::caffe::SigmoidParameter* mutable_sigmoid_param();
+  ::caffe::SigmoidParameter* release_sigmoid_param();
+  void set_allocated_sigmoid_param(::caffe::SigmoidParameter* sigmoid_param);
+
+  // optional .caffe.SliceParameter slice_param = 126;
+  bool has_slice_param() const;
+  void clear_slice_param();
+  static const int kSliceParamFieldNumber = 126;
+  const ::caffe::SliceParameter& slice_param() const;
+  ::caffe::SliceParameter* mutable_slice_param();
+  ::caffe::SliceParameter* release_slice_param();
+  void set_allocated_slice_param(::caffe::SliceParameter* slice_param);
+
+  // optional .caffe.SoftmaxParameter softmax_param = 125;
+  bool has_softmax_param() const;
+  void clear_softmax_param();
+  static const int kSoftmaxParamFieldNumber = 125;
+  const ::caffe::SoftmaxParameter& softmax_param() const;
+  ::caffe::SoftmaxParameter* mutable_softmax_param();
+  ::caffe::SoftmaxParameter* release_softmax_param();
+  void set_allocated_softmax_param(::caffe::SoftmaxParameter* softmax_param);
+
+  // optional .caffe.SPPParameter spp_param = 132;
+  bool has_spp_param() const;
+  void clear_spp_param();
+  static const int kSppParamFieldNumber = 132;
+  const ::caffe::SPPParameter& spp_param() const;
+  ::caffe::SPPParameter* mutable_spp_param();
+  ::caffe::SPPParameter* release_spp_param();
+  void set_allocated_spp_param(::caffe::SPPParameter* spp_param);
+
+  // optional .caffe.TanHParameter tanh_param = 127;
+  bool has_tanh_param() const;
+  void clear_tanh_param();
+  static const int kTanhParamFieldNumber = 127;
+  const ::caffe::TanHParameter& tanh_param() const;
+  ::caffe::TanHParameter* mutable_tanh_param();
+  ::caffe::TanHParameter* release_tanh_param();
+  void set_allocated_tanh_param(::caffe::TanHParameter* tanh_param);
+
+  // optional .caffe.ThresholdParameter threshold_param = 128;
+  bool has_threshold_param() const;
+  void clear_threshold_param();
+  static const int kThresholdParamFieldNumber = 128;
+  const ::caffe::ThresholdParameter& threshold_param() const;
+  ::caffe::ThresholdParameter* mutable_threshold_param();
+  ::caffe::ThresholdParameter* release_threshold_param();
+  void set_allocated_threshold_param(::caffe::ThresholdParameter* threshold_param);
+
+  // optional .caffe.WindowDataParameter window_data_param = 129;
+  bool has_window_data_param() const;
+  void clear_window_data_param();
+  static const int kWindowDataParamFieldNumber = 129;
+  const ::caffe::WindowDataParameter& window_data_param() const;
+  ::caffe::WindowDataParameter* mutable_window_data_param();
+  ::caffe::WindowDataParameter* release_window_data_param();
+  void set_allocated_window_data_param(::caffe::WindowDataParameter* window_data_param);
+
+  // @@protoc_insertion_point(class_scope:caffe.LayerParameter)
+ private:
+  inline void set_has_name();
+  inline void clear_has_name();
+  inline void set_has_type();
+  inline void clear_has_type();
+  inline void set_has_phase();
+  inline void clear_has_phase();
+  inline void set_has_transform_param();
+  inline void clear_has_transform_param();
+  inline void set_has_loss_param();
+  inline void clear_has_loss_param();
+  inline void set_has_accuracy_param();
+  inline void clear_has_accuracy_param();
+  inline void set_has_argmax_param();
+  inline void clear_has_argmax_param();
+  inline void set_has_concat_param();
+  inline void clear_has_concat_param();
+  inline void set_has_contrastive_loss_param();
+  inline void clear_has_contrastive_loss_param();
+  inline void set_has_convolution_param();
+  inline void clear_has_convolution_param();
+  inline void set_has_crop_param();
+  inline void clear_has_crop_param();
+  inline void set_has_data_param();
+  inline void clear_has_data_param();
+  inline void set_has_detection_output_param();
+  inline void clear_has_detection_output_param();
+  inline void set_has_dropout_param();
+  inline void clear_has_dropout_param();
+  inline void set_has_dummy_data_param();
+  inline void clear_has_dummy_data_param();
+  inline void set_has_eltwise_param();
+  inline void clear_has_eltwise_param();
+  inline void set_has_exp_param();
+  inline void clear_has_exp_param();
+  inline void set_has_flatten_param();
+  inline void clear_has_flatten_param();
+  inline void set_has_hdf5_data_param();
+  inline void clear_has_hdf5_data_param();
+  inline void set_has_hdf5_output_param();
+  inline void clear_has_hdf5_output_param();
+  inline void set_has_hinge_loss_param();
+  inline void clear_has_hinge_loss_param();
+  inline void set_has_image_data_param();
+  inline void clear_has_image_data_param();
+  inline void set_has_infogain_loss_param();
+  inline void clear_has_infogain_loss_param();
+  inline void set_has_inner_product_param();
+  inline void clear_has_inner_product_param();
+  inline void set_has_log_param();
+  inline void clear_has_log_param();
+  inline void set_has_lrn_param();
+  inline void clear_has_lrn_param();
+  inline void set_has_memory_data_param();
+  inline void clear_has_memory_data_param();
+  inline void set_has_mvn_param();
+  inline void clear_has_mvn_param();
+  inline void set_has_normalize_bbox_param();
+  inline void clear_has_normalize_bbox_param();
+  inline void set_has_permute_param();
+  inline void clear_has_permute_param();
+  inline void set_has_pooling_param();
+  inline void clear_has_pooling_param();
+  inline void set_has_power_param();
+  inline void clear_has_power_param();
+  inline void set_has_prelu_param();
+  inline void clear_has_prelu_param();
+  inline void set_has_prior_box_param();
+  inline void clear_has_prior_box_param();
+  inline void set_has_python_param();
+  inline void clear_has_python_param();
+  inline void set_has_reduction_param();
+  inline void clear_has_reduction_param();
+  inline void set_has_relu_param();
+  inline void clear_has_relu_param();
+  inline void set_has_reshape_param();
+  inline void clear_has_reshape_param();
+  inline void set_has_sigmoid_param();
+  inline void clear_has_sigmoid_param();
+  inline void set_has_slice_param();
+  inline void clear_has_slice_param();
+  inline void set_has_softmax_param();
+  inline void clear_has_softmax_param();
+  inline void set_has_spp_param();
+  inline void clear_has_spp_param();
+  inline void set_has_tanh_param();
+  inline void clear_has_tanh_param();
+  inline void set_has_threshold_param();
+  inline void clear_has_threshold_param();
+  inline void set_has_window_data_param();
+  inline void clear_has_window_data_param();
+
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  ::google::protobuf::internal::HasBits<2> _has_bits_;
+  ::google::protobuf::RepeatedPtrField< ::std::string> bottom_;
+  ::google::protobuf::RepeatedPtrField< ::std::string> top_;
+  ::google::protobuf::RepeatedField< float > loss_weight_;
+  ::google::protobuf::RepeatedPtrField< ::caffe::ParamSpec > param_;
+  ::google::protobuf::RepeatedPtrField< ::caffe::BlobProto > blobs_;
+  ::google::protobuf::RepeatedField< bool > propagate_down_;
+  ::google::protobuf::RepeatedPtrField< ::caffe::NetStateRule > include_;
+  ::google::protobuf::RepeatedPtrField< ::caffe::NetStateRule > exclude_;
+  ::google::protobuf::internal::ArenaStringPtr name_;
+  ::google::protobuf::internal::ArenaStringPtr type_;
+  ::caffe::TransformationParameter* transform_param_;
+  ::caffe::LossParameter* loss_param_;
+  ::caffe::AccuracyParameter* accuracy_param_;
+  ::caffe::ArgMaxParameter* argmax_param_;
+  ::caffe::ConcatParameter* concat_param_;
+  ::caffe::ContrastiveLossParameter* contrastive_loss_param_;
+  ::caffe::ConvolutionParameter* convolution_param_;
+  ::caffe::CropParameter* crop_param_;
+  ::caffe::DataParameter* data_param_;
+  ::caffe::DetectionOutputParameter* detection_output_param_;
+  ::caffe::DropoutParameter* dropout_param_;
+  ::caffe::DummyDataParameter* dummy_data_param_;
+  ::caffe::EltwiseParameter* eltwise_param_;
+  ::caffe::ExpParameter* exp_param_;
+  ::caffe::FlattenParameter* flatten_param_;
+  ::caffe::HDF5DataParameter* hdf5_data_param_;
+  ::caffe::HDF5OutputParameter* hdf5_output_param_;
+  ::caffe::HingeLossParameter* hinge_loss_param_;
+  ::caffe::ImageDataParameter* image_data_param_;
+  ::caffe::InfogainLossParameter* infogain_loss_param_;
+  ::caffe::InnerProductParameter* inner_product_param_;
+  ::caffe::LogParameter* log_param_;
+  ::caffe::LRNParameter* lrn_param_;
+  ::caffe::MemoryDataParameter* memory_data_param_;
+  ::caffe::MVNParameter* mvn_param_;
+  ::caffe::NormalizeBBoxParameter* normalize_bbox_param_;
+  ::caffe::PermuteParameter* permute_param_;
+  ::caffe::PoolingParameter* pooling_param_;
+  ::caffe::PowerParameter* power_param_;
+  ::caffe::PReLUParameter* prelu_param_;
+  ::caffe::PriorBoxParameter* prior_box_param_;
+  ::caffe::PythonParameter* python_param_;
+  ::caffe::ReductionParameter* reduction_param_;
+  ::caffe::ReLUParameter* relu_param_;
+  ::caffe::ReshapeParameter* reshape_param_;
+  ::caffe::SigmoidParameter* sigmoid_param_;
+  ::caffe::SliceParameter* slice_param_;
+  ::caffe::SoftmaxParameter* softmax_param_;
+  ::caffe::SPPParameter* spp_param_;
+  ::caffe::TanHParameter* tanh_param_;
+  ::caffe::ThresholdParameter* threshold_param_;
+  ::caffe::WindowDataParameter* window_data_param_;
+  int phase_;
+  mutable int _cached_size_;
+  friend void  protobuf_InitDefaults_caffe_2eproto_impl();
+  friend void  protobuf_AddDesc_caffe_2eproto_impl();
+  friend void protobuf_AssignDesc_caffe_2eproto();
+  friend void protobuf_ShutdownFile_caffe_2eproto();
+
+  void InitAsDefaultInstance();
+};
+extern ::google::protobuf::internal::ExplicitlyConstructed<LayerParameter> LayerParameter_default_instance_;
+
+// -------------------------------------------------------------------
+
+class TransformationParameter : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:caffe.TransformationParameter) */ {
+ public:
+  TransformationParameter();
+  virtual ~TransformationParameter();
+
+  TransformationParameter(const TransformationParameter& from);
+
+  inline TransformationParameter& operator=(const TransformationParameter& from) {
+    CopyFrom(from);
+    return *this;
+  }
+
+  inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields();
+  }
+
+  inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields();
+  }
+
+  static const ::google::protobuf::Descriptor* descriptor();
+  static const TransformationParameter& default_instance();
+
+  static const TransformationParameter* internal_default_instance();
+
+  void Swap(TransformationParameter* other);
+
+  // implements Message ----------------------------------------------
+
+  inline TransformationParameter* New() const { return New(NULL); }
+
+  TransformationParameter* New(::google::protobuf::Arena* arena) const;
+  void CopyFrom(const ::google::protobuf::Message& from);
+  void MergeFrom(const ::google::protobuf::Message& from);
+  void CopyFrom(const TransformationParameter& from);
+  void MergeFrom(const TransformationParameter& from);
+  void Clear();
+  bool IsInitialized() const;
+
+  size_t ByteSizeLong() const;
+  bool MergePartialFromCodedStream(
+      ::google::protobuf::io::CodedInputStream* input);
+  void SerializeWithCachedSizes(
+      ::google::protobuf::io::CodedOutputStream* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
+  int GetCachedSize() const { return _cached_size_; }
+  private:
+  void SharedCtor();
+  void SharedDtor();
+  void SetCachedSize(int size) const;
+  void InternalSwap(TransformationParameter* other);
+  void UnsafeMergeFrom(const TransformationParameter& from);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
+  public:
+
+  ::google::protobuf::Metadata GetMetadata() const;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  // optional float scale = 1 [default = 1];
+  bool has_scale() const;
+  void clear_scale();
+  static const int kScaleFieldNumber = 1;
+  float scale() const;
+  void set_scale(float value);
+
+  // optional bool mirror = 2 [default = false];
+  bool has_mirror() const;
+  void clear_mirror();
+  static const int kMirrorFieldNumber = 2;
+  bool mirror() const;
+  void set_mirror(bool value);
+
+  // optional uint32 crop_size = 3 [default = 0];
+  bool has_crop_size() const;
+  void clear_crop_size();
+  static const int kCropSizeFieldNumber = 3;
+  ::google::protobuf::uint32 crop_size() const;
+  void set_crop_size(::google::protobuf::uint32 value);
+
+  // optional string mean_file = 4;
+  bool has_mean_file() const;
+  void clear_mean_file();
+  static const int kMeanFileFieldNumber = 4;
+  const ::std::string& mean_file() const;
+  void set_mean_file(const ::std::string& value);
+  void set_mean_file(const char* value);
+  void set_mean_file(const char* value, size_t size);
+  ::std::string* mutable_mean_file();
+  ::std::string* release_mean_file();
+  void set_allocated_mean_file(::std::string* mean_file);
+
+  // repeated float mean_value = 5;
+  int mean_value_size() const;
+  void clear_mean_value();
+  static const int kMeanValueFieldNumber = 5;
+  float mean_value(int index) const;
+  void set_mean_value(int index, float value);
+  void add_mean_value(float value);
+  const ::google::protobuf::RepeatedField< float >&
+      mean_value() const;
+  ::google::protobuf::RepeatedField< float >*
+      mutable_mean_value();
+
+  // optional bool force_color = 6 [default = false];
+  bool has_force_color() const;
+  void clear_force_color();
+  static const int kForceColorFieldNumber = 6;
+  bool force_color() const;
+  void set_force_color(bool value);
+
+  // optional bool force_gray = 7 [default = false];
+  bool has_force_gray() const;
+  void clear_force_gray();
+  static const int kForceGrayFieldNumber = 7;
+  bool force_gray() const;
+  void set_force_gray(bool value);
+
+  // @@protoc_insertion_point(class_scope:caffe.TransformationParameter)
+ private:
+  inline void set_has_scale();
+  inline void clear_has_scale();
+  inline void set_has_mirror();
+  inline void clear_has_mirror();
+  inline void set_has_crop_size();
+  inline void clear_has_crop_size();
+  inline void set_has_mean_file();
+  inline void clear_has_mean_file();
+  inline void set_has_force_color();
+  inline void clear_has_force_color();
+  inline void set_has_force_gray();
+  inline void clear_has_force_gray();
+
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  ::google::protobuf::internal::HasBits<1> _has_bits_;
+  mutable int _cached_size_;
+  ::google::protobuf::RepeatedField< float > mean_value_;
+  ::google::protobuf::internal::ArenaStringPtr mean_file_;
+  ::google::protobuf::uint32 crop_size_;
+  bool mirror_;
+  bool force_color_;
+  bool force_gray_;
+  float scale_;
+  friend void  protobuf_InitDefaults_caffe_2eproto_impl();
+  friend void  protobuf_AddDesc_caffe_2eproto_impl();
+  friend void protobuf_AssignDesc_caffe_2eproto();
+  friend void protobuf_ShutdownFile_caffe_2eproto();
+
+  void InitAsDefaultInstance();
+};
+extern ::google::protobuf::internal::ExplicitlyConstructed<TransformationParameter> TransformationParameter_default_instance_;
+
+// -------------------------------------------------------------------
+
+class LossParameter : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:caffe.LossParameter) */ {
+ public:
+  LossParameter();
+  virtual ~LossParameter();
+
+  LossParameter(const LossParameter& from);
+
+  inline LossParameter& operator=(const LossParameter& from) {
+    CopyFrom(from);
+    return *this;
+  }
+
+  inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields();
+  }
+
+  inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields();
+  }
+
+  static const ::google::protobuf::Descriptor* descriptor();
+  static const LossParameter& default_instance();
+
+  static const LossParameter* internal_default_instance();
+
+  void Swap(LossParameter* other);
+
+  // implements Message ----------------------------------------------
+
+  inline LossParameter* New() const { return New(NULL); }
+
+  LossParameter* New(::google::protobuf::Arena* arena) const;
+  void CopyFrom(const ::google::protobuf::Message& from);
+  void MergeFrom(const ::google::protobuf::Message& from);
+  void CopyFrom(const LossParameter& from);
+  void MergeFrom(const LossParameter& from);
+  void Clear();
+  bool IsInitialized() const;
+
+  size_t ByteSizeLong() const;
+  bool MergePartialFromCodedStream(
+      ::google::protobuf::io::CodedInputStream* input);
+  void SerializeWithCachedSizes(
+      ::google::protobuf::io::CodedOutputStream* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
+  int GetCachedSize() const { return _cached_size_; }
+  private:
+  void SharedCtor();
+  void SharedDtor();
+  void SetCachedSize(int size) const;
+  void InternalSwap(LossParameter* other);
+  void UnsafeMergeFrom(const LossParameter& from);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
+  public:
+
+  ::google::protobuf::Metadata GetMetadata() const;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  // optional int32 ignore_label = 1;
+  bool has_ignore_label() const;
+  void clear_ignore_label();
+  static const int kIgnoreLabelFieldNumber = 1;
+  ::google::protobuf::int32 ignore_label() const;
+  void set_ignore_label(::google::protobuf::int32 value);
+
+  // optional bool normalize = 2 [default = true];
+  bool has_normalize() const;
+  void clear_normalize();
+  static const int kNormalizeFieldNumber = 2;
+  bool normalize() const;
+  void set_normalize(bool value);
+
+  // @@protoc_insertion_point(class_scope:caffe.LossParameter)
+ private:
+  inline void set_has_ignore_label();
+  inline void clear_has_ignore_label();
+  inline void set_has_normalize();
+  inline void clear_has_normalize();
+
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  ::google::protobuf::internal::HasBits<1> _has_bits_;
+  mutable int _cached_size_;
+  ::google::protobuf::int32 ignore_label_;
+  bool normalize_;
+  friend void  protobuf_InitDefaults_caffe_2eproto_impl();
+  friend void  protobuf_AddDesc_caffe_2eproto_impl();
+  friend void protobuf_AssignDesc_caffe_2eproto();
+  friend void protobuf_ShutdownFile_caffe_2eproto();
+
+  void InitAsDefaultInstance();
+};
+extern ::google::protobuf::internal::ExplicitlyConstructed<LossParameter> LossParameter_default_instance_;
+
+// -------------------------------------------------------------------
+
+class AccuracyParameter : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:caffe.AccuracyParameter) */ {
+ public:
+  AccuracyParameter();
+  virtual ~AccuracyParameter();
+
+  AccuracyParameter(const AccuracyParameter& from);
+
+  inline AccuracyParameter& operator=(const AccuracyParameter& from) {
+    CopyFrom(from);
+    return *this;
+  }
+
+  inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields();
+  }
+
+  inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields();
+  }
+
+  static const ::google::protobuf::Descriptor* descriptor();
+  static const AccuracyParameter& default_instance();
+
+  static const AccuracyParameter* internal_default_instance();
+
+  void Swap(AccuracyParameter* other);
+
+  // implements Message ----------------------------------------------
+
+  inline AccuracyParameter* New() const { return New(NULL); }
+
+  AccuracyParameter* New(::google::protobuf::Arena* arena) const;
+  void CopyFrom(const ::google::protobuf::Message& from);
+  void MergeFrom(const ::google::protobuf::Message& from);
+  void CopyFrom(const AccuracyParameter& from);
+  void MergeFrom(const AccuracyParameter& from);
+  void Clear();
+  bool IsInitialized() const;
+
+  size_t ByteSizeLong() const;
+  bool MergePartialFromCodedStream(
+      ::google::protobuf::io::CodedInputStream* input);
+  void SerializeWithCachedSizes(
+      ::google::protobuf::io::CodedOutputStream* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
+  int GetCachedSize() const { return _cached_size_; }
+  private:
+  void SharedCtor();
+  void SharedDtor();
+  void SetCachedSize(int size) const;
+  void InternalSwap(AccuracyParameter* other);
+  void UnsafeMergeFrom(const AccuracyParameter& from);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
+  public:
+
+  ::google::protobuf::Metadata GetMetadata() const;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  // optional uint32 top_k = 1 [default = 1];
+  bool has_top_k() const;
+  void clear_top_k();
+  static const int kTopKFieldNumber = 1;
+  ::google::protobuf::uint32 top_k() const;
+  void set_top_k(::google::protobuf::uint32 value);
+
+  // optional int32 axis = 2 [default = 1];
+  bool has_axis() const;
+  void clear_axis();
+  static const int kAxisFieldNumber = 2;
+  ::google::protobuf::int32 axis() const;
+  void set_axis(::google::protobuf::int32 value);
+
+  // optional int32 ignore_label = 3;
+  bool has_ignore_label() const;
+  void clear_ignore_label();
+  static const int kIgnoreLabelFieldNumber = 3;
+  ::google::protobuf::int32 ignore_label() const;
+  void set_ignore_label(::google::protobuf::int32 value);
+
+  // @@protoc_insertion_point(class_scope:caffe.AccuracyParameter)
+ private:
+  inline void set_has_top_k();
+  inline void clear_has_top_k();
+  inline void set_has_axis();
+  inline void clear_has_axis();
+  inline void set_has_ignore_label();
+  inline void clear_has_ignore_label();
+
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  ::google::protobuf::internal::HasBits<1> _has_bits_;
+  mutable int _cached_size_;
+  ::google::protobuf::int32 ignore_label_;
+  ::google::protobuf::uint32 top_k_;
+  ::google::protobuf::int32 axis_;
+  friend void  protobuf_InitDefaults_caffe_2eproto_impl();
+  friend void  protobuf_AddDesc_caffe_2eproto_impl();
+  friend void protobuf_AssignDesc_caffe_2eproto();
+  friend void protobuf_ShutdownFile_caffe_2eproto();
+
+  void InitAsDefaultInstance();
+};
+extern ::google::protobuf::internal::ExplicitlyConstructed<AccuracyParameter> AccuracyParameter_default_instance_;
+
+// -------------------------------------------------------------------
+
+class ArgMaxParameter : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:caffe.ArgMaxParameter) */ {
+ public:
+  ArgMaxParameter();
+  virtual ~ArgMaxParameter();
+
+  ArgMaxParameter(const ArgMaxParameter& from);
+
+  inline ArgMaxParameter& operator=(const ArgMaxParameter& from) {
+    CopyFrom(from);
+    return *this;
+  }
+
+  inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields();
+  }
+
+  inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields();
+  }
+
+  static const ::google::protobuf::Descriptor* descriptor();
+  static const ArgMaxParameter& default_instance();
+
+  static const ArgMaxParameter* internal_default_instance();
+
+  void Swap(ArgMaxParameter* other);
+
+  // implements Message ----------------------------------------------
+
+  inline ArgMaxParameter* New() const { return New(NULL); }
+
+  ArgMaxParameter* New(::google::protobuf::Arena* arena) const;
+  void CopyFrom(const ::google::protobuf::Message& from);
+  void MergeFrom(const ::google::protobuf::Message& from);
+  void CopyFrom(const ArgMaxParameter& from);
+  void MergeFrom(const ArgMaxParameter& from);
+  void Clear();
+  bool IsInitialized() const;
+
+  size_t ByteSizeLong() const;
+  bool MergePartialFromCodedStream(
+      ::google::protobuf::io::CodedInputStream* input);
+  void SerializeWithCachedSizes(
+      ::google::protobuf::io::CodedOutputStream* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
+  int GetCachedSize() const { return _cached_size_; }
+  private:
+  void SharedCtor();
+  void SharedDtor();
+  void SetCachedSize(int size) const;
+  void InternalSwap(ArgMaxParameter* other);
+  void UnsafeMergeFrom(const ArgMaxParameter& from);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
+  public:
+
+  ::google::protobuf::Metadata GetMetadata() const;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  // optional bool out_max_val = 1 [default = false];
+  bool has_out_max_val() const;
+  void clear_out_max_val();
+  static const int kOutMaxValFieldNumber = 1;
+  bool out_max_val() const;
+  void set_out_max_val(bool value);
+
+  // optional uint32 top_k = 2 [default = 1];
+  bool has_top_k() const;
+  void clear_top_k();
+  static const int kTopKFieldNumber = 2;
+  ::google::protobuf::uint32 top_k() const;
+  void set_top_k(::google::protobuf::uint32 value);
+
+  // @@protoc_insertion_point(class_scope:caffe.ArgMaxParameter)
+ private:
+  inline void set_has_out_max_val();
+  inline void clear_has_out_max_val();
+  inline void set_has_top_k();
+  inline void clear_has_top_k();
+
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  ::google::protobuf::internal::HasBits<1> _has_bits_;
+  mutable int _cached_size_;
+  bool out_max_val_;
+  ::google::protobuf::uint32 top_k_;
+  friend void  protobuf_InitDefaults_caffe_2eproto_impl();
+  friend void  protobuf_AddDesc_caffe_2eproto_impl();
+  friend void protobuf_AssignDesc_caffe_2eproto();
+  friend void protobuf_ShutdownFile_caffe_2eproto();
+
+  void InitAsDefaultInstance();
+};
+extern ::google::protobuf::internal::ExplicitlyConstructed<ArgMaxParameter> ArgMaxParameter_default_instance_;
+
+// -------------------------------------------------------------------
+
+class ConcatParameter : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:caffe.ConcatParameter) */ {
+ public:
+  ConcatParameter();
+  virtual ~ConcatParameter();
+
+  ConcatParameter(const ConcatParameter& from);
+
+  inline ConcatParameter& operator=(const ConcatParameter& from) {
+    CopyFrom(from);
+    return *this;
+  }
+
+  inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields();
+  }
+
+  inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields();
+  }
+
+  static const ::google::protobuf::Descriptor* descriptor();
+  static const ConcatParameter& default_instance();
+
+  static const ConcatParameter* internal_default_instance();
+
+  void Swap(ConcatParameter* other);
+
+  // implements Message ----------------------------------------------
+
+  inline ConcatParameter* New() const { return New(NULL); }
+
+  ConcatParameter* New(::google::protobuf::Arena* arena) const;
+  void CopyFrom(const ::google::protobuf::Message& from);
+  void MergeFrom(const ::google::protobuf::Message& from);
+  void CopyFrom(const ConcatParameter& from);
+  void MergeFrom(const ConcatParameter& from);
+  void Clear();
+  bool IsInitialized() const;
+
+  size_t ByteSizeLong() const;
+  bool MergePartialFromCodedStream(
+      ::google::protobuf::io::CodedInputStream* input);
+  void SerializeWithCachedSizes(
+      ::google::protobuf::io::CodedOutputStream* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
+  int GetCachedSize() const { return _cached_size_; }
+  private:
+  void SharedCtor();
+  void SharedDtor();
+  void SetCachedSize(int size) const;
+  void InternalSwap(ConcatParameter* other);
+  void UnsafeMergeFrom(const ConcatParameter& from);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
+  public:
+
+  ::google::protobuf::Metadata GetMetadata() const;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  // optional int32 axis = 2 [default = 1];
+  bool has_axis() const;
+  void clear_axis();
+  static const int kAxisFieldNumber = 2;
+  ::google::protobuf::int32 axis() const;
+  void set_axis(::google::protobuf::int32 value);
+
+  // optional uint32 concat_dim = 1 [default = 1];
+  bool has_concat_dim() const;
+  void clear_concat_dim();
+  static const int kConcatDimFieldNumber = 1;
+  ::google::protobuf::uint32 concat_dim() const;
+  void set_concat_dim(::google::protobuf::uint32 value);
+
+  // @@protoc_insertion_point(class_scope:caffe.ConcatParameter)
+ private:
+  inline void set_has_axis();
+  inline void clear_has_axis();
+  inline void set_has_concat_dim();
+  inline void clear_has_concat_dim();
+
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  ::google::protobuf::internal::HasBits<1> _has_bits_;
+  mutable int _cached_size_;
+  ::google::protobuf::int32 axis_;
+  ::google::protobuf::uint32 concat_dim_;
+  friend void  protobuf_InitDefaults_caffe_2eproto_impl();
+  friend void  protobuf_AddDesc_caffe_2eproto_impl();
+  friend void protobuf_AssignDesc_caffe_2eproto();
+  friend void protobuf_ShutdownFile_caffe_2eproto();
+
+  void InitAsDefaultInstance();
+};
+extern ::google::protobuf::internal::ExplicitlyConstructed<ConcatParameter> ConcatParameter_default_instance_;
+
+// -------------------------------------------------------------------
+
+class ContrastiveLossParameter : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:caffe.ContrastiveLossParameter) */ {
+ public:
+  ContrastiveLossParameter();
+  virtual ~ContrastiveLossParameter();
+
+  ContrastiveLossParameter(const ContrastiveLossParameter& from);
+
+  inline ContrastiveLossParameter& operator=(const ContrastiveLossParameter& from) {
+    CopyFrom(from);
+    return *this;
+  }
+
+  inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields();
+  }
+
+  inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields();
+  }
+
+  static const ::google::protobuf::Descriptor* descriptor();
+  static const ContrastiveLossParameter& default_instance();
+
+  static const ContrastiveLossParameter* internal_default_instance();
+
+  void Swap(ContrastiveLossParameter* other);
+
+  // implements Message ----------------------------------------------
+
+  inline ContrastiveLossParameter* New() const { return New(NULL); }
+
+  ContrastiveLossParameter* New(::google::protobuf::Arena* arena) const;
+  void CopyFrom(const ::google::protobuf::Message& from);
+  void MergeFrom(const ::google::protobuf::Message& from);
+  void CopyFrom(const ContrastiveLossParameter& from);
+  void MergeFrom(const ContrastiveLossParameter& from);
+  void Clear();
+  bool IsInitialized() const;
+
+  size_t ByteSizeLong() const;
+  bool MergePartialFromCodedStream(
+      ::google::protobuf::io::CodedInputStream* input);
+  void SerializeWithCachedSizes(
+      ::google::protobuf::io::CodedOutputStream* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
+  int GetCachedSize() const { return _cached_size_; }
+  private:
+  void SharedCtor();
+  void SharedDtor();
+  void SetCachedSize(int size) const;
+  void InternalSwap(ContrastiveLossParameter* other);
+  void UnsafeMergeFrom(const ContrastiveLossParameter& from);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
+  public:
+
+  ::google::protobuf::Metadata GetMetadata() const;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  // optional float margin = 1 [default = 1];
+  bool has_margin() const;
+  void clear_margin();
+  static const int kMarginFieldNumber = 1;
+  float margin() const;
+  void set_margin(float value);
+
+  // optional bool legacy_version = 2 [default = false];
+  bool has_legacy_version() const;
+  void clear_legacy_version();
+  static const int kLegacyVersionFieldNumber = 2;
+  bool legacy_version() const;
+  void set_legacy_version(bool value);
+
+  // @@protoc_insertion_point(class_scope:caffe.ContrastiveLossParameter)
+ private:
+  inline void set_has_margin();
+  inline void clear_has_margin();
+  inline void set_has_legacy_version();
+  inline void clear_has_legacy_version();
+
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  ::google::protobuf::internal::HasBits<1> _has_bits_;
+  mutable int _cached_size_;
+  bool legacy_version_;
+  float margin_;
+  friend void  protobuf_InitDefaults_caffe_2eproto_impl();
+  friend void  protobuf_AddDesc_caffe_2eproto_impl();
+  friend void protobuf_AssignDesc_caffe_2eproto();
+  friend void protobuf_ShutdownFile_caffe_2eproto();
+
+  void InitAsDefaultInstance();
+};
+extern ::google::protobuf::internal::ExplicitlyConstructed<ContrastiveLossParameter> ContrastiveLossParameter_default_instance_;
+
+// -------------------------------------------------------------------
+
+class ConvolutionParameter : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:caffe.ConvolutionParameter) */ {
+ public:
+  ConvolutionParameter();
+  virtual ~ConvolutionParameter();
+
+  ConvolutionParameter(const ConvolutionParameter& from);
+
+  inline ConvolutionParameter& operator=(const ConvolutionParameter& from) {
+    CopyFrom(from);
+    return *this;
+  }
+
+  inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields();
+  }
+
+  inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields();
+  }
+
+  static const ::google::protobuf::Descriptor* descriptor();
+  static const ConvolutionParameter& default_instance();
+
+  static const ConvolutionParameter* internal_default_instance();
+
+  void Swap(ConvolutionParameter* other);
+
+  // implements Message ----------------------------------------------
+
+  inline ConvolutionParameter* New() const { return New(NULL); }
+
+  ConvolutionParameter* New(::google::protobuf::Arena* arena) const;
+  void CopyFrom(const ::google::protobuf::Message& from);
+  void MergeFrom(const ::google::protobuf::Message& from);
+  void CopyFrom(const ConvolutionParameter& from);
+  void MergeFrom(const ConvolutionParameter& from);
+  void Clear();
+  bool IsInitialized() const;
+
+  size_t ByteSizeLong() const;
+  bool MergePartialFromCodedStream(
+      ::google::protobuf::io::CodedInputStream* input);
+  void SerializeWithCachedSizes(
+      ::google::protobuf::io::CodedOutputStream* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
+  int GetCachedSize() const { return _cached_size_; }
+  private:
+  void SharedCtor();
+  void SharedDtor();
+  void SetCachedSize(int size) const;
+  void InternalSwap(ConvolutionParameter* other);
+  void UnsafeMergeFrom(const ConvolutionParameter& from);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
+  public:
+
+  ::google::protobuf::Metadata GetMetadata() const;
+
+  // nested types ----------------------------------------------------
+
+  typedef ConvolutionParameter_Engine Engine;
+  static const Engine DEFAULT =
+    ConvolutionParameter_Engine_DEFAULT;
+  static const Engine CAFFE =
+    ConvolutionParameter_Engine_CAFFE;
+  static const Engine CUDNN =
+    ConvolutionParameter_Engine_CUDNN;
+  static inline bool Engine_IsValid(int value) {
+    return ConvolutionParameter_Engine_IsValid(value);
+  }
+  static const Engine Engine_MIN =
+    ConvolutionParameter_Engine_Engine_MIN;
+  static const Engine Engine_MAX =
+    ConvolutionParameter_Engine_Engine_MAX;
+  static const int Engine_ARRAYSIZE =
+    ConvolutionParameter_Engine_Engine_ARRAYSIZE;
+  static inline const ::google::protobuf::EnumDescriptor*
+  Engine_descriptor() {
+    return ConvolutionParameter_Engine_descriptor();
+  }
+  static inline const ::std::string& Engine_Name(Engine value) {
+    return ConvolutionParameter_Engine_Name(value);
+  }
+  static inline bool Engine_Parse(const ::std::string& name,
+      Engine* value) {
+    return ConvolutionParameter_Engine_Parse(name, value);
+  }
+
+  // accessors -------------------------------------------------------
+
+  // optional uint32 num_output = 1;
+  bool has_num_output() const;
+  void clear_num_output();
+  static const int kNumOutputFieldNumber = 1;
+  ::google::protobuf::uint32 num_output() const;
+  void set_num_output(::google::protobuf::uint32 value);
+
+  // optional bool bias_term = 2 [default = true];
+  bool has_bias_term() const;
+  void clear_bias_term();
+  static const int kBiasTermFieldNumber = 2;
+  bool bias_term() const;
+  void set_bias_term(bool value);
+
+  // optional uint32 pad = 3 [default = 0];
+  bool has_pad() const;
+  void clear_pad();
+  static const int kPadFieldNumber = 3;
+  ::google::protobuf::uint32 pad() const;
+  void set_pad(::google::protobuf::uint32 value);
+
+  // optional uint32 pad_h = 9 [default = 0];
+  bool has_pad_h() const;
+  void clear_pad_h();
+  static const int kPadHFieldNumber = 9;
+  ::google::protobuf::uint32 pad_h() const;
+  void set_pad_h(::google::protobuf::uint32 value);
+
+  // optional uint32 pad_w = 10 [default = 0];
+  bool has_pad_w() const;
+  void clear_pad_w();
+  static const int kPadWFieldNumber = 10;
+  ::google::protobuf::uint32 pad_w() const;
+  void set_pad_w(::google::protobuf::uint32 value);
+
+  // optional uint32 kernel_size = 4;
+  bool has_kernel_size() const;
+  void clear_kernel_size();
+  static const int kKernelSizeFieldNumber = 4;
+  ::google::protobuf::uint32 kernel_size() const;
+  void set_kernel_size(::google::protobuf::uint32 value);
+
+  // optional uint32 kernel_h = 11;
+  bool has_kernel_h() const;
+  void clear_kernel_h();
+  static const int kKernelHFieldNumber = 11;
+  ::google::protobuf::uint32 kernel_h() const;
+  void set_kernel_h(::google::protobuf::uint32 value);
+
+  // optional uint32 kernel_w = 12;
+  bool has_kernel_w() const;
+  void clear_kernel_w();
+  static const int kKernelWFieldNumber = 12;
+  ::google::protobuf::uint32 kernel_w() const;
+  void set_kernel_w(::google::protobuf::uint32 value);
+
+  // optional uint32 group = 5 [default = 1];
+  bool has_group() const;
+  void clear_group();
+  static const int kGroupFieldNumber = 5;
+  ::google::protobuf::uint32 group() const;
+  void set_group(::google::protobuf::uint32 value);
+
+  // optional uint32 stride = 6 [default = 1];
+  bool has_stride() const;
+  void clear_stride();
+  static const int kStrideFieldNumber = 6;
+  ::google::protobuf::uint32 stride() const;
+  void set_stride(::google::protobuf::uint32 value);
+
+  // optional uint32 stride_h = 13;
+  bool has_stride_h() const;
+  void clear_stride_h();
+  static const int kStrideHFieldNumber = 13;
+  ::google::protobuf::uint32 stride_h() const;
+  void set_stride_h(::google::protobuf::uint32 value);
+
+  // optional uint32 stride_w = 14;
+  bool has_stride_w() const;
+  void clear_stride_w();
+  static const int kStrideWFieldNumber = 14;
+  ::google::protobuf::uint32 stride_w() const;
+  void set_stride_w(::google::protobuf::uint32 value);
+
+  // optional .caffe.FillerParameter weight_filler = 7;
+  bool has_weight_filler() const;
+  void clear_weight_filler();
+  static const int kWeightFillerFieldNumber = 7;
+  const ::caffe::FillerParameter& weight_filler() const;
+  ::caffe::FillerParameter* mutable_weight_filler();
+  ::caffe::FillerParameter* release_weight_filler();
+  void set_allocated_weight_filler(::caffe::FillerParameter* weight_filler);
+
+  // optional .caffe.FillerParameter bias_filler = 8;
+  bool has_bias_filler() const;
+  void clear_bias_filler();
+  static const int kBiasFillerFieldNumber = 8;
+  const ::caffe::FillerParameter& bias_filler() const;
+  ::caffe::FillerParameter* mutable_bias_filler();
+  ::caffe::FillerParameter* release_bias_filler();
+  void set_allocated_bias_filler(::caffe::FillerParameter* bias_filler);
+
+  // optional .caffe.ConvolutionParameter.Engine engine = 15 [default = DEFAULT];
+  bool has_engine() const;
+  void clear_engine();
+  static const int kEngineFieldNumber = 15;
+  ::caffe::ConvolutionParameter_Engine engine() const;
+  void set_engine(::caffe::ConvolutionParameter_Engine value);
+
+  // optional uint32 dilation_h = 18;
+  bool has_dilation_h() const;
+  void clear_dilation_h();
+  static const int kDilationHFieldNumber = 18;
+  ::google::protobuf::uint32 dilation_h() const;
+  void set_dilation_h(::google::protobuf::uint32 value);
+
+  // optional uint32 dilation_w = 19;
+  bool has_dilation_w() const;
+  void clear_dilation_w();
+  static const int kDilationWFieldNumber = 19;
+  ::google::protobuf::uint32 dilation_w() const;
+  void set_dilation_w(::google::protobuf::uint32 value);
+
+  // optional uint32 dilation = 20;
+  bool has_dilation() const;
+  void clear_dilation();
+  static const int kDilationFieldNumber = 20;
+  ::google::protobuf::uint32 dilation() const;
+  void set_dilation(::google::protobuf::uint32 value);
+
+  // @@protoc_insertion_point(class_scope:caffe.ConvolutionParameter)
+ private:
+  inline void set_has_num_output();
+  inline void clear_has_num_output();
+  inline void set_has_bias_term();
+  inline void clear_has_bias_term();
+  inline void set_has_pad();
+  inline void clear_has_pad();
+  inline void set_has_pad_h();
+  inline void clear_has_pad_h();
+  inline void set_has_pad_w();
+  inline void clear_has_pad_w();
+  inline void set_has_kernel_size();
+  inline void clear_has_kernel_size();
+  inline void set_has_kernel_h();
+  inline void clear_has_kernel_h();
+  inline void set_has_kernel_w();
+  inline void clear_has_kernel_w();
+  inline void set_has_group();
+  inline void clear_has_group();
+  inline void set_has_stride();
+  inline void clear_has_stride();
+  inline void set_has_stride_h();
+  inline void clear_has_stride_h();
+  inline void set_has_stride_w();
+  inline void clear_has_stride_w();
+  inline void set_has_weight_filler();
+  inline void clear_has_weight_filler();
+  inline void set_has_bias_filler();
+  inline void clear_has_bias_filler();
+  inline void set_has_engine();
+  inline void clear_has_engine();
+  inline void set_has_dilation_h();
+  inline void clear_has_dilation_h();
+  inline void set_has_dilation_w();
+  inline void clear_has_dilation_w();
+  inline void set_has_dilation();
+  inline void clear_has_dilation();
+
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  ::google::protobuf::internal::HasBits<1> _has_bits_;
+  mutable int _cached_size_;
+  ::caffe::FillerParameter* weight_filler_;
+  ::caffe::FillerParameter* bias_filler_;
+  ::google::protobuf::uint32 num_output_;
+  ::google::protobuf::uint32 pad_;
+  ::google::protobuf::uint32 pad_h_;
+  ::google::protobuf::uint32 pad_w_;
+  ::google::protobuf::uint32 kernel_size_;
+  ::google::protobuf::uint32 kernel_h_;
+  ::google::protobuf::uint32 kernel_w_;
+  ::google::protobuf::uint32 stride_h_;
+  ::google::protobuf::uint32 stride_w_;
+  int engine_;
+  ::google::protobuf::uint32 dilation_h_;
+  ::google::protobuf::uint32 dilation_w_;
+  ::google::protobuf::uint32 dilation_;
+  ::google::protobuf::uint32 stride_;
+  bool bias_term_;
+  ::google::protobuf::uint32 group_;
+  friend void  protobuf_InitDefaults_caffe_2eproto_impl();
+  friend void  protobuf_AddDesc_caffe_2eproto_impl();
+  friend void protobuf_AssignDesc_caffe_2eproto();
+  friend void protobuf_ShutdownFile_caffe_2eproto();
+
+  void InitAsDefaultInstance();
+};
+extern ::google::protobuf::internal::ExplicitlyConstructed<ConvolutionParameter> ConvolutionParameter_default_instance_;
+
+// -------------------------------------------------------------------
+
+class DataParameter : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:caffe.DataParameter) */ {
+ public:
+  DataParameter();
+  virtual ~DataParameter();
+
+  DataParameter(const DataParameter& from);
+
+  inline DataParameter& operator=(const DataParameter& from) {
+    CopyFrom(from);
+    return *this;
+  }
+
+  inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields();
+  }
+
+  inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields();
+  }
+
+  static const ::google::protobuf::Descriptor* descriptor();
+  static const DataParameter& default_instance();
+
+  static const DataParameter* internal_default_instance();
+
+  void Swap(DataParameter* other);
+
+  // implements Message ----------------------------------------------
+
+  inline DataParameter* New() const { return New(NULL); }
+
+  DataParameter* New(::google::protobuf::Arena* arena) const;
+  void CopyFrom(const ::google::protobuf::Message& from);
+  void MergeFrom(const ::google::protobuf::Message& from);
+  void CopyFrom(const DataParameter& from);
+  void MergeFrom(const DataParameter& from);
+  void Clear();
+  bool IsInitialized() const;
+
+  size_t ByteSizeLong() const;
+  bool MergePartialFromCodedStream(
+      ::google::protobuf::io::CodedInputStream* input);
+  void SerializeWithCachedSizes(
+      ::google::protobuf::io::CodedOutputStream* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
+  int GetCachedSize() const { return _cached_size_; }
+  private:
+  void SharedCtor();
+  void SharedDtor();
+  void SetCachedSize(int size) const;
+  void InternalSwap(DataParameter* other);
+  void UnsafeMergeFrom(const DataParameter& from);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
+  public:
+
+  ::google::protobuf::Metadata GetMetadata() const;
+
+  // nested types ----------------------------------------------------
+
+  typedef DataParameter_DB DB;
+  static const DB LEVELDB =
+    DataParameter_DB_LEVELDB;
+  static const DB LMDB =
+    DataParameter_DB_LMDB;
+  static inline bool DB_IsValid(int value) {
+    return DataParameter_DB_IsValid(value);
+  }
+  static const DB DB_MIN =
+    DataParameter_DB_DB_MIN;
+  static const DB DB_MAX =
+    DataParameter_DB_DB_MAX;
+  static const int DB_ARRAYSIZE =
+    DataParameter_DB_DB_ARRAYSIZE;
+  static inline const ::google::protobuf::EnumDescriptor*
+  DB_descriptor() {
+    return DataParameter_DB_descriptor();
+  }
+  static inline const ::std::string& DB_Name(DB value) {
+    return DataParameter_DB_Name(value);
+  }
+  static inline bool DB_Parse(const ::std::string& name,
+      DB* value) {
+    return DataParameter_DB_Parse(name, value);
+  }
+
+  // accessors -------------------------------------------------------
+
+  // optional string source = 1;
+  bool has_source() const;
+  void clear_source();
+  static const int kSourceFieldNumber = 1;
+  const ::std::string& source() const;
+  void set_source(const ::std::string& value);
+  void set_source(const char* value);
+  void set_source(const char* value, size_t size);
+  ::std::string* mutable_source();
+  ::std::string* release_source();
+  void set_allocated_source(::std::string* source);
+
+  // optional uint32 batch_size = 4;
+  bool has_batch_size() const;
+  void clear_batch_size();
+  static const int kBatchSizeFieldNumber = 4;
+  ::google::protobuf::uint32 batch_size() const;
+  void set_batch_size(::google::protobuf::uint32 value);
+
+  // optional uint32 rand_skip = 7 [default = 0];
+  bool has_rand_skip() const;
+  void clear_rand_skip();
+  static const int kRandSkipFieldNumber = 7;
+  ::google::protobuf::uint32 rand_skip() const;
+  void set_rand_skip(::google::protobuf::uint32 value);
+
+  // optional .caffe.DataParameter.DB backend = 8 [default = LEVELDB];
+  bool has_backend() const;
+  void clear_backend();
+  static const int kBackendFieldNumber = 8;
+  ::caffe::DataParameter_DB backend() const;
+  void set_backend(::caffe::DataParameter_DB value);
+
+  // optional float scale = 2 [default = 1];
+  bool has_scale() const;
+  void clear_scale();
+  static const int kScaleFieldNumber = 2;
+  float scale() const;
+  void set_scale(float value);
+
+  // optional string mean_file = 3;
+  bool has_mean_file() const;
+  void clear_mean_file();
+  static const int kMeanFileFieldNumber = 3;
+  const ::std::string& mean_file() const;
+  void set_mean_file(const ::std::string& value);
+  void set_mean_file(const char* value);
+  void set_mean_file(const char* value, size_t size);
+  ::std::string* mutable_mean_file();
+  ::std::string* release_mean_file();
+  void set_allocated_mean_file(::std::string* mean_file);
+
+  // optional uint32 crop_size = 5 [default = 0];
+  bool has_crop_size() const;
+  void clear_crop_size();
+  static const int kCropSizeFieldNumber = 5;
+  ::google::protobuf::uint32 crop_size() const;
+  void set_crop_size(::google::protobuf::uint32 value);
+
+  // optional bool mirror = 6 [default = false];
+  bool has_mirror() const;
+  void clear_mirror();
+  static const int kMirrorFieldNumber = 6;
+  bool mirror() const;
+  void set_mirror(bool value);
+
+  // optional bool force_encoded_color = 9 [default = false];
+  bool has_force_encoded_color() const;
+  void clear_force_encoded_color();
+  static const int kForceEncodedColorFieldNumber = 9;
+  bool force_encoded_color() const;
+  void set_force_encoded_color(bool value);
+
+  // @@protoc_insertion_point(class_scope:caffe.DataParameter)
+ private:
+  inline void set_has_source();
+  inline void clear_has_source();
+  inline void set_has_batch_size();
+  inline void clear_has_batch_size();
+  inline void set_has_rand_skip();
+  inline void clear_has_rand_skip();
+  inline void set_has_backend();
+  inline void clear_has_backend();
+  inline void set_has_scale();
+  inline void clear_has_scale();
+  inline void set_has_mean_file();
+  inline void clear_has_mean_file();
+  inline void set_has_crop_size();
+  inline void clear_has_crop_size();
+  inline void set_has_mirror();
+  inline void clear_has_mirror();
+  inline void set_has_force_encoded_color();
+  inline void clear_has_force_encoded_color();
+
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  ::google::protobuf::internal::HasBits<1> _has_bits_;
+  mutable int _cached_size_;
+  ::google::protobuf::internal::ArenaStringPtr source_;
+  ::google::protobuf::internal::ArenaStringPtr mean_file_;
+  ::google::protobuf::uint32 batch_size_;
+  ::google::protobuf::uint32 rand_skip_;
+  int backend_;
+  ::google::protobuf::uint32 crop_size_;
+  bool mirror_;
+  bool force_encoded_color_;
+  float scale_;
+  friend void  protobuf_InitDefaults_caffe_2eproto_impl();
+  friend void  protobuf_AddDesc_caffe_2eproto_impl();
+  friend void protobuf_AssignDesc_caffe_2eproto();
+  friend void protobuf_ShutdownFile_caffe_2eproto();
+
+  void InitAsDefaultInstance();
+};
+extern ::google::protobuf::internal::ExplicitlyConstructed<DataParameter> DataParameter_default_instance_;
+
+// -------------------------------------------------------------------
+
+class DropoutParameter : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:caffe.DropoutParameter) */ {
+ public:
+  DropoutParameter();
+  virtual ~DropoutParameter();
+
+  DropoutParameter(const DropoutParameter& from);
+
+  inline DropoutParameter& operator=(const DropoutParameter& from) {
+    CopyFrom(from);
+    return *this;
+  }
+
+  inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields();
+  }
+
+  inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields();
+  }
+
+  static const ::google::protobuf::Descriptor* descriptor();
+  static const DropoutParameter& default_instance();
+
+  static const DropoutParameter* internal_default_instance();
+
+  void Swap(DropoutParameter* other);
+
+  // implements Message ----------------------------------------------
+
+  inline DropoutParameter* New() const { return New(NULL); }
+
+  DropoutParameter* New(::google::protobuf::Arena* arena) const;
+  void CopyFrom(const ::google::protobuf::Message& from);
+  void MergeFrom(const ::google::protobuf::Message& from);
+  void CopyFrom(const DropoutParameter& from);
+  void MergeFrom(const DropoutParameter& from);
+  void Clear();
+  bool IsInitialized() const;
+
+  size_t ByteSizeLong() const;
+  bool MergePartialFromCodedStream(
+      ::google::protobuf::io::CodedInputStream* input);
+  void SerializeWithCachedSizes(
+      ::google::protobuf::io::CodedOutputStream* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
+  int GetCachedSize() const { return _cached_size_; }
+  private:
+  void SharedCtor();
+  void SharedDtor();
+  void SetCachedSize(int size) const;
+  void InternalSwap(DropoutParameter* other);
+  void UnsafeMergeFrom(const DropoutParameter& from);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
+  public:
+
+  ::google::protobuf::Metadata GetMetadata() const;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  // optional float dropout_ratio = 1 [default = 0.5];
+  bool has_dropout_ratio() const;
+  void clear_dropout_ratio();
+  static const int kDropoutRatioFieldNumber = 1;
+  float dropout_ratio() const;
+  void set_dropout_ratio(float value);
+
+  // @@protoc_insertion_point(class_scope:caffe.DropoutParameter)
+ private:
+  inline void set_has_dropout_ratio();
+  inline void clear_has_dropout_ratio();
+
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  ::google::protobuf::internal::HasBits<1> _has_bits_;
+  mutable int _cached_size_;
+  float dropout_ratio_;
+  friend void  protobuf_InitDefaults_caffe_2eproto_impl();
+  friend void  protobuf_AddDesc_caffe_2eproto_impl();
+  friend void protobuf_AssignDesc_caffe_2eproto();
+  friend void protobuf_ShutdownFile_caffe_2eproto();
+
+  void InitAsDefaultInstance();
+};
+extern ::google::protobuf::internal::ExplicitlyConstructed<DropoutParameter> DropoutParameter_default_instance_;
+
+// -------------------------------------------------------------------
+
+class DummyDataParameter : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:caffe.DummyDataParameter) */ {
+ public:
+  DummyDataParameter();
+  virtual ~DummyDataParameter();
+
+  DummyDataParameter(const DummyDataParameter& from);
+
+  inline DummyDataParameter& operator=(const DummyDataParameter& from) {
+    CopyFrom(from);
+    return *this;
+  }
+
+  inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields();
+  }
+
+  inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields();
+  }
+
+  static const ::google::protobuf::Descriptor* descriptor();
+  static const DummyDataParameter& default_instance();
+
+  static const DummyDataParameter* internal_default_instance();
+
+  void Swap(DummyDataParameter* other);
+
+  // implements Message ----------------------------------------------
+
+  inline DummyDataParameter* New() const { return New(NULL); }
+
+  DummyDataParameter* New(::google::protobuf::Arena* arena) const;
+  void CopyFrom(const ::google::protobuf::Message& from);
+  void MergeFrom(const ::google::protobuf::Message& from);
+  void CopyFrom(const DummyDataParameter& from);
+  void MergeFrom(const DummyDataParameter& from);
+  void Clear();
+  bool IsInitialized() const;
+
+  size_t ByteSizeLong() const;
+  bool MergePartialFromCodedStream(
+      ::google::protobuf::io::CodedInputStream* input);
+  void SerializeWithCachedSizes(
+      ::google::protobuf::io::CodedOutputStream* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
+  int GetCachedSize() const { return _cached_size_; }
+  private:
+  void SharedCtor();
+  void SharedDtor();
+  void SetCachedSize(int size) const;
+  void InternalSwap(DummyDataParameter* other);
+  void UnsafeMergeFrom(const DummyDataParameter& from);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
+  public:
+
+  ::google::protobuf::Metadata GetMetadata() const;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  // repeated .caffe.FillerParameter data_filler = 1;
+  int data_filler_size() const;
+  void clear_data_filler();
+  static const int kDataFillerFieldNumber = 1;
+  const ::caffe::FillerParameter& data_filler(int index) const;
+  ::caffe::FillerParameter* mutable_data_filler(int index);
+  ::caffe::FillerParameter* add_data_filler();
+  ::google::protobuf::RepeatedPtrField< ::caffe::FillerParameter >*
+      mutable_data_filler();
+  const ::google::protobuf::RepeatedPtrField< ::caffe::FillerParameter >&
+      data_filler() const;
+
+  // repeated .caffe.BlobShape shape = 6;
+  int shape_size() const;
+  void clear_shape();
+  static const int kShapeFieldNumber = 6;
+  const ::caffe::BlobShape& shape(int index) const;
+  ::caffe::BlobShape* mutable_shape(int index);
+  ::caffe::BlobShape* add_shape();
+  ::google::protobuf::RepeatedPtrField< ::caffe::BlobShape >*
+      mutable_shape();
+  const ::google::protobuf::RepeatedPtrField< ::caffe::BlobShape >&
+      shape() const;
+
+  // repeated uint32 num = 2;
+  int num_size() const;
+  void clear_num();
+  static const int kNumFieldNumber = 2;
+  ::google::protobuf::uint32 num(int index) const;
+  void set_num(int index, ::google::protobuf::uint32 value);
+  void add_num(::google::protobuf::uint32 value);
+  const ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >&
+      num() const;
+  ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >*
+      mutable_num();
+
+  // repeated uint32 channels = 3;
+  int channels_size() const;
+  void clear_channels();
+  static const int kChannelsFieldNumber = 3;
+  ::google::protobuf::uint32 channels(int index) const;
+  void set_channels(int index, ::google::protobuf::uint32 value);
+  void add_channels(::google::protobuf::uint32 value);
+  const ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >&
+      channels() const;
+  ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >*
+      mutable_channels();
+
+  // repeated uint32 height = 4;
+  int height_size() const;
+  void clear_height();
+  static const int kHeightFieldNumber = 4;
+  ::google::protobuf::uint32 height(int index) const;
+  void set_height(int index, ::google::protobuf::uint32 value);
+  void add_height(::google::protobuf::uint32 value);
+  const ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >&
+      height() const;
+  ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >*
+      mutable_height();
+
+  // repeated uint32 width = 5;
+  int width_size() const;
+  void clear_width();
+  static const int kWidthFieldNumber = 5;
+  ::google::protobuf::uint32 width(int index) const;
+  void set_width(int index, ::google::protobuf::uint32 value);
+  void add_width(::google::protobuf::uint32 value);
+  const ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >&
+      width() const;
+  ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >*
+      mutable_width();
+
+  // @@protoc_insertion_point(class_scope:caffe.DummyDataParameter)
+ private:
+
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  ::google::protobuf::internal::HasBits<1> _has_bits_;
+  mutable int _cached_size_;
+  ::google::protobuf::RepeatedPtrField< ::caffe::FillerParameter > data_filler_;
+  ::google::protobuf::RepeatedPtrField< ::caffe::BlobShape > shape_;
+  ::google::protobuf::RepeatedField< ::google::protobuf::uint32 > num_;
+  ::google::protobuf::RepeatedField< ::google::protobuf::uint32 > channels_;
+  ::google::protobuf::RepeatedField< ::google::protobuf::uint32 > height_;
+  ::google::protobuf::RepeatedField< ::google::protobuf::uint32 > width_;
+  friend void  protobuf_InitDefaults_caffe_2eproto_impl();
+  friend void  protobuf_AddDesc_caffe_2eproto_impl();
+  friend void protobuf_AssignDesc_caffe_2eproto();
+  friend void protobuf_ShutdownFile_caffe_2eproto();
+
+  void InitAsDefaultInstance();
+};
+extern ::google::protobuf::internal::ExplicitlyConstructed<DummyDataParameter> DummyDataParameter_default_instance_;
+
+// -------------------------------------------------------------------
+
+class EltwiseParameter : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:caffe.EltwiseParameter) */ {
+ public:
+  EltwiseParameter();
+  virtual ~EltwiseParameter();
+
+  EltwiseParameter(const EltwiseParameter& from);
+
+  inline EltwiseParameter& operator=(const EltwiseParameter& from) {
+    CopyFrom(from);
+    return *this;
+  }
+
+  inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields();
+  }
+
+  inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields();
+  }
+
+  static const ::google::protobuf::Descriptor* descriptor();
+  static const EltwiseParameter& default_instance();
+
+  static const EltwiseParameter* internal_default_instance();
+
+  void Swap(EltwiseParameter* other);
+
+  // implements Message ----------------------------------------------
+
+  inline EltwiseParameter* New() const { return New(NULL); }
+
+  EltwiseParameter* New(::google::protobuf::Arena* arena) const;
+  void CopyFrom(const ::google::protobuf::Message& from);
+  void MergeFrom(const ::google::protobuf::Message& from);
+  void CopyFrom(const EltwiseParameter& from);
+  void MergeFrom(const EltwiseParameter& from);
+  void Clear();
+  bool IsInitialized() const;
+
+  size_t ByteSizeLong() const;
+  bool MergePartialFromCodedStream(
+      ::google::protobuf::io::CodedInputStream* input);
+  void SerializeWithCachedSizes(
+      ::google::protobuf::io::CodedOutputStream* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
+  int GetCachedSize() const { return _cached_size_; }
+  private:
+  void SharedCtor();
+  void SharedDtor();
+  void SetCachedSize(int size) const;
+  void InternalSwap(EltwiseParameter* other);
+  void UnsafeMergeFrom(const EltwiseParameter& from);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
+  public:
+
+  ::google::protobuf::Metadata GetMetadata() const;
+
+  // nested types ----------------------------------------------------
+
+  typedef EltwiseParameter_EltwiseOp EltwiseOp;
+  static const EltwiseOp PROD =
+    EltwiseParameter_EltwiseOp_PROD;
+  static const EltwiseOp SUM =
+    EltwiseParameter_EltwiseOp_SUM;
+  static const EltwiseOp MAX =
+    EltwiseParameter_EltwiseOp_MAX;
+  static inline bool EltwiseOp_IsValid(int value) {
+    return EltwiseParameter_EltwiseOp_IsValid(value);
+  }
+  static const EltwiseOp EltwiseOp_MIN =
+    EltwiseParameter_EltwiseOp_EltwiseOp_MIN;
+  static const EltwiseOp EltwiseOp_MAX =
+    EltwiseParameter_EltwiseOp_EltwiseOp_MAX;
+  static const int EltwiseOp_ARRAYSIZE =
+    EltwiseParameter_EltwiseOp_EltwiseOp_ARRAYSIZE;
+  static inline const ::google::protobuf::EnumDescriptor*
+  EltwiseOp_descriptor() {
+    return EltwiseParameter_EltwiseOp_descriptor();
+  }
+  static inline const ::std::string& EltwiseOp_Name(EltwiseOp value) {
+    return EltwiseParameter_EltwiseOp_Name(value);
+  }
+  static inline bool EltwiseOp_Parse(const ::std::string& name,
+      EltwiseOp* value) {
+    return EltwiseParameter_EltwiseOp_Parse(name, value);
+  }
+
+  // accessors -------------------------------------------------------
+
+  // optional .caffe.EltwiseParameter.EltwiseOp operation = 1 [default = SUM];
+  bool has_operation() const;
+  void clear_operation();
+  static const int kOperationFieldNumber = 1;
+  ::caffe::EltwiseParameter_EltwiseOp operation() const;
+  void set_operation(::caffe::EltwiseParameter_EltwiseOp value);
+
+  // repeated float coeff = 2;
+  int coeff_size() const;
+  void clear_coeff();
+  static const int kCoeffFieldNumber = 2;
+  float coeff(int index) const;
+  void set_coeff(int index, float value);
+  void add_coeff(float value);
+  const ::google::protobuf::RepeatedField< float >&
+      coeff() const;
+  ::google::protobuf::RepeatedField< float >*
+      mutable_coeff();
+
+  // optional bool stable_prod_grad = 3 [default = true];
+  bool has_stable_prod_grad() const;
+  void clear_stable_prod_grad();
+  static const int kStableProdGradFieldNumber = 3;
+  bool stable_prod_grad() const;
+  void set_stable_prod_grad(bool value);
+
+  // @@protoc_insertion_point(class_scope:caffe.EltwiseParameter)
+ private:
+  inline void set_has_operation();
+  inline void clear_has_operation();
+  inline void set_has_stable_prod_grad();
+  inline void clear_has_stable_prod_grad();
+
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  ::google::protobuf::internal::HasBits<1> _has_bits_;
+  mutable int _cached_size_;
+  ::google::protobuf::RepeatedField< float > coeff_;
+  int operation_;
+  bool stable_prod_grad_;
+  friend void  protobuf_InitDefaults_caffe_2eproto_impl();
+  friend void  protobuf_AddDesc_caffe_2eproto_impl();
+  friend void protobuf_AssignDesc_caffe_2eproto();
+  friend void protobuf_ShutdownFile_caffe_2eproto();
+
+  void InitAsDefaultInstance();
+};
+extern ::google::protobuf::internal::ExplicitlyConstructed<EltwiseParameter> EltwiseParameter_default_instance_;
+
+// -------------------------------------------------------------------
+
+class ExpParameter : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:caffe.ExpParameter) */ {
+ public:
+  ExpParameter();
+  virtual ~ExpParameter();
+
+  ExpParameter(const ExpParameter& from);
+
+  inline ExpParameter& operator=(const ExpParameter& from) {
+    CopyFrom(from);
+    return *this;
+  }
+
+  inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields();
+  }
+
+  inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields();
+  }
+
+  static const ::google::protobuf::Descriptor* descriptor();
+  static const ExpParameter& default_instance();
+
+  static const ExpParameter* internal_default_instance();
+
+  void Swap(ExpParameter* other);
+
+  // implements Message ----------------------------------------------
+
+  inline ExpParameter* New() const { return New(NULL); }
+
+  ExpParameter* New(::google::protobuf::Arena* arena) const;
+  void CopyFrom(const ::google::protobuf::Message& from);
+  void MergeFrom(const ::google::protobuf::Message& from);
+  void CopyFrom(const ExpParameter& from);
+  void MergeFrom(const ExpParameter& from);
+  void Clear();
+  bool IsInitialized() const;
+
+  size_t ByteSizeLong() const;
+  bool MergePartialFromCodedStream(
+      ::google::protobuf::io::CodedInputStream* input);
+  void SerializeWithCachedSizes(
+      ::google::protobuf::io::CodedOutputStream* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
+  int GetCachedSize() const { return _cached_size_; }
+  private:
+  void SharedCtor();
+  void SharedDtor();
+  void SetCachedSize(int size) const;
+  void InternalSwap(ExpParameter* other);
+  void UnsafeMergeFrom(const ExpParameter& from);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
+  public:
+
+  ::google::protobuf::Metadata GetMetadata() const;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  // optional float base = 1 [default = -1];
+  bool has_base() const;
+  void clear_base();
+  static const int kBaseFieldNumber = 1;
+  float base() const;
+  void set_base(float value);
+
+  // optional float scale = 2 [default = 1];
+  bool has_scale() const;
+  void clear_scale();
+  static const int kScaleFieldNumber = 2;
+  float scale() const;
+  void set_scale(float value);
+
+  // optional float shift = 3 [default = 0];
+  bool has_shift() const;
+  void clear_shift();
+  static const int kShiftFieldNumber = 3;
+  float shift() const;
+  void set_shift(float value);
+
+  // @@protoc_insertion_point(class_scope:caffe.ExpParameter)
+ private:
+  inline void set_has_base();
+  inline void clear_has_base();
+  inline void set_has_scale();
+  inline void clear_has_scale();
+  inline void set_has_shift();
+  inline void clear_has_shift();
+
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  ::google::protobuf::internal::HasBits<1> _has_bits_;
+  mutable int _cached_size_;
+  float shift_;
+  float base_;
+  float scale_;
+  friend void  protobuf_InitDefaults_caffe_2eproto_impl();
+  friend void  protobuf_AddDesc_caffe_2eproto_impl();
+  friend void protobuf_AssignDesc_caffe_2eproto();
+  friend void protobuf_ShutdownFile_caffe_2eproto();
+
+  void InitAsDefaultInstance();
+};
+extern ::google::protobuf::internal::ExplicitlyConstructed<ExpParameter> ExpParameter_default_instance_;
+
+// -------------------------------------------------------------------
+
+class FlattenParameter : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:caffe.FlattenParameter) */ {
+ public:
+  FlattenParameter();
+  virtual ~FlattenParameter();
+
+  FlattenParameter(const FlattenParameter& from);
+
+  inline FlattenParameter& operator=(const FlattenParameter& from) {
+    CopyFrom(from);
+    return *this;
+  }
+
+  inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields();
+  }
+
+  inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields();
+  }
+
+  static const ::google::protobuf::Descriptor* descriptor();
+  static const FlattenParameter& default_instance();
+
+  static const FlattenParameter* internal_default_instance();
+
+  void Swap(FlattenParameter* other);
+
+  // implements Message ----------------------------------------------
+
+  inline FlattenParameter* New() const { return New(NULL); }
+
+  FlattenParameter* New(::google::protobuf::Arena* arena) const;
+  void CopyFrom(const ::google::protobuf::Message& from);
+  void MergeFrom(const ::google::protobuf::Message& from);
+  void CopyFrom(const FlattenParameter& from);
+  void MergeFrom(const FlattenParameter& from);
+  void Clear();
+  bool IsInitialized() const;
+
+  size_t ByteSizeLong() const;
+  bool MergePartialFromCodedStream(
+      ::google::protobuf::io::CodedInputStream* input);
+  void SerializeWithCachedSizes(
+      ::google::protobuf::io::CodedOutputStream* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
+  int GetCachedSize() const { return _cached_size_; }
+  private:
+  void SharedCtor();
+  void SharedDtor();
+  void SetCachedSize(int size) const;
+  void InternalSwap(FlattenParameter* other);
+  void UnsafeMergeFrom(const FlattenParameter& from);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
+  public:
+
+  ::google::protobuf::Metadata GetMetadata() const;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  // optional int32 axis = 1 [default = 1];
+  bool has_axis() const;
+  void clear_axis();
+  static const int kAxisFieldNumber = 1;
+  ::google::protobuf::int32 axis() const;
+  void set_axis(::google::protobuf::int32 value);
+
+  // optional int32 end_axis = 2 [default = -1];
+  bool has_end_axis() const;
+  void clear_end_axis();
+  static const int kEndAxisFieldNumber = 2;
+  ::google::protobuf::int32 end_axis() const;
+  void set_end_axis(::google::protobuf::int32 value);
+
+  // @@protoc_insertion_point(class_scope:caffe.FlattenParameter)
+ private:
+  inline void set_has_axis();
+  inline void clear_has_axis();
+  inline void set_has_end_axis();
+  inline void clear_has_end_axis();
+
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  ::google::protobuf::internal::HasBits<1> _has_bits_;
+  mutable int _cached_size_;
+  ::google::protobuf::int32 axis_;
+  ::google::protobuf::int32 end_axis_;
+  friend void  protobuf_InitDefaults_caffe_2eproto_impl();
+  friend void  protobuf_AddDesc_caffe_2eproto_impl();
+  friend void protobuf_AssignDesc_caffe_2eproto();
+  friend void protobuf_ShutdownFile_caffe_2eproto();
+
+  void InitAsDefaultInstance();
+};
+extern ::google::protobuf::internal::ExplicitlyConstructed<FlattenParameter> FlattenParameter_default_instance_;
+
+// -------------------------------------------------------------------
+
+class HDF5DataParameter : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:caffe.HDF5DataParameter) */ {
+ public:
+  HDF5DataParameter();
+  virtual ~HDF5DataParameter();
+
+  HDF5DataParameter(const HDF5DataParameter& from);
+
+  inline HDF5DataParameter& operator=(const HDF5DataParameter& from) {
+    CopyFrom(from);
+    return *this;
+  }
+
+  inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields();
+  }
+
+  inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields();
+  }
+
+  static const ::google::protobuf::Descriptor* descriptor();
+  static const HDF5DataParameter& default_instance();
+
+  static const HDF5DataParameter* internal_default_instance();
+
+  void Swap(HDF5DataParameter* other);
+
+  // implements Message ----------------------------------------------
+
+  inline HDF5DataParameter* New() const { return New(NULL); }
+
+  HDF5DataParameter* New(::google::protobuf::Arena* arena) const;
+  void CopyFrom(const ::google::protobuf::Message& from);
+  void MergeFrom(const ::google::protobuf::Message& from);
+  void CopyFrom(const HDF5DataParameter& from);
+  void MergeFrom(const HDF5DataParameter& from);
+  void Clear();
+  bool IsInitialized() const;
+
+  size_t ByteSizeLong() const;
+  bool MergePartialFromCodedStream(
+      ::google::protobuf::io::CodedInputStream* input);
+  void SerializeWithCachedSizes(
+      ::google::protobuf::io::CodedOutputStream* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
+  int GetCachedSize() const { return _cached_size_; }
+  private:
+  void SharedCtor();
+  void SharedDtor();
+  void SetCachedSize(int size) const;
+  void InternalSwap(HDF5DataParameter* other);
+  void UnsafeMergeFrom(const HDF5DataParameter& from);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
+  public:
+
+  ::google::protobuf::Metadata GetMetadata() const;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  // optional string source = 1;
+  bool has_source() const;
+  void clear_source();
+  static const int kSourceFieldNumber = 1;
+  const ::std::string& source() const;
+  void set_source(const ::std::string& value);
+  void set_source(const char* value);
+  void set_source(const char* value, size_t size);
+  ::std::string* mutable_source();
+  ::std::string* release_source();
+  void set_allocated_source(::std::string* source);
+
+  // optional uint32 batch_size = 2;
+  bool has_batch_size() const;
+  void clear_batch_size();
+  static const int kBatchSizeFieldNumber = 2;
+  ::google::protobuf::uint32 batch_size() const;
+  void set_batch_size(::google::protobuf::uint32 value);
+
+  // optional bool shuffle = 3 [default = false];
+  bool has_shuffle() const;
+  void clear_shuffle();
+  static const int kShuffleFieldNumber = 3;
+  bool shuffle() const;
+  void set_shuffle(bool value);
+
+  // @@protoc_insertion_point(class_scope:caffe.HDF5DataParameter)
+ private:
+  inline void set_has_source();
+  inline void clear_has_source();
+  inline void set_has_batch_size();
+  inline void clear_has_batch_size();
+  inline void set_has_shuffle();
+  inline void clear_has_shuffle();
+
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  ::google::protobuf::internal::HasBits<1> _has_bits_;
+  mutable int _cached_size_;
+  ::google::protobuf::internal::ArenaStringPtr source_;
+  ::google::protobuf::uint32 batch_size_;
+  bool shuffle_;
+  friend void  protobuf_InitDefaults_caffe_2eproto_impl();
+  friend void  protobuf_AddDesc_caffe_2eproto_impl();
+  friend void protobuf_AssignDesc_caffe_2eproto();
+  friend void protobuf_ShutdownFile_caffe_2eproto();
+
+  void InitAsDefaultInstance();
+};
+extern ::google::protobuf::internal::ExplicitlyConstructed<HDF5DataParameter> HDF5DataParameter_default_instance_;
+
+// -------------------------------------------------------------------
+
+class HDF5OutputParameter : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:caffe.HDF5OutputParameter) */ {
+ public:
+  HDF5OutputParameter();
+  virtual ~HDF5OutputParameter();
+
+  HDF5OutputParameter(const HDF5OutputParameter& from);
+
+  inline HDF5OutputParameter& operator=(const HDF5OutputParameter& from) {
+    CopyFrom(from);
+    return *this;
+  }
+
+  inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields();
+  }
+
+  inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields();
+  }
+
+  static const ::google::protobuf::Descriptor* descriptor();
+  static const HDF5OutputParameter& default_instance();
+
+  static const HDF5OutputParameter* internal_default_instance();
+
+  void Swap(HDF5OutputParameter* other);
+
+  // implements Message ----------------------------------------------
+
+  inline HDF5OutputParameter* New() const { return New(NULL); }
+
+  HDF5OutputParameter* New(::google::protobuf::Arena* arena) const;
+  void CopyFrom(const ::google::protobuf::Message& from);
+  void MergeFrom(const ::google::protobuf::Message& from);
+  void CopyFrom(const HDF5OutputParameter& from);
+  void MergeFrom(const HDF5OutputParameter& from);
+  void Clear();
+  bool IsInitialized() const;
+
+  size_t ByteSizeLong() const;
+  bool MergePartialFromCodedStream(
+      ::google::protobuf::io::CodedInputStream* input);
+  void SerializeWithCachedSizes(
+      ::google::protobuf::io::CodedOutputStream* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
+  int GetCachedSize() const { return _cached_size_; }
+  private:
+  void SharedCtor();
+  void SharedDtor();
+  void SetCachedSize(int size) const;
+  void InternalSwap(HDF5OutputParameter* other);
+  void UnsafeMergeFrom(const HDF5OutputParameter& from);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
+  public:
+
+  ::google::protobuf::Metadata GetMetadata() const;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  // optional string file_name = 1;
+  bool has_file_name() const;
+  void clear_file_name();
+  static const int kFileNameFieldNumber = 1;
+  const ::std::string& file_name() const;
+  void set_file_name(const ::std::string& value);
+  void set_file_name(const char* value);
+  void set_file_name(const char* value, size_t size);
+  ::std::string* mutable_file_name();
+  ::std::string* release_file_name();
+  void set_allocated_file_name(::std::string* file_name);
+
+  // @@protoc_insertion_point(class_scope:caffe.HDF5OutputParameter)
+ private:
+  inline void set_has_file_name();
+  inline void clear_has_file_name();
+
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  ::google::protobuf::internal::HasBits<1> _has_bits_;
+  mutable int _cached_size_;
+  ::google::protobuf::internal::ArenaStringPtr file_name_;
+  friend void  protobuf_InitDefaults_caffe_2eproto_impl();
+  friend void  protobuf_AddDesc_caffe_2eproto_impl();
+  friend void protobuf_AssignDesc_caffe_2eproto();
+  friend void protobuf_ShutdownFile_caffe_2eproto();
+
+  void InitAsDefaultInstance();
+};
+extern ::google::protobuf::internal::ExplicitlyConstructed<HDF5OutputParameter> HDF5OutputParameter_default_instance_;
+
+// -------------------------------------------------------------------
+
+class HingeLossParameter : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:caffe.HingeLossParameter) */ {
+ public:
+  HingeLossParameter();
+  virtual ~HingeLossParameter();
+
+  HingeLossParameter(const HingeLossParameter& from);
+
+  inline HingeLossParameter& operator=(const HingeLossParameter& from) {
+    CopyFrom(from);
+    return *this;
+  }
+
+  inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields();
+  }
+
+  inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields();
+  }
+
+  static const ::google::protobuf::Descriptor* descriptor();
+  static const HingeLossParameter& default_instance();
+
+  static const HingeLossParameter* internal_default_instance();
+
+  void Swap(HingeLossParameter* other);
+
+  // implements Message ----------------------------------------------
+
+  inline HingeLossParameter* New() const { return New(NULL); }
+
+  HingeLossParameter* New(::google::protobuf::Arena* arena) const;
+  void CopyFrom(const ::google::protobuf::Message& from);
+  void MergeFrom(const ::google::protobuf::Message& from);
+  void CopyFrom(const HingeLossParameter& from);
+  void MergeFrom(const HingeLossParameter& from);
+  void Clear();
+  bool IsInitialized() const;
+
+  size_t ByteSizeLong() const;
+  bool MergePartialFromCodedStream(
+      ::google::protobuf::io::CodedInputStream* input);
+  void SerializeWithCachedSizes(
+      ::google::protobuf::io::CodedOutputStream* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
+  int GetCachedSize() const { return _cached_size_; }
+  private:
+  void SharedCtor();
+  void SharedDtor();
+  void SetCachedSize(int size) const;
+  void InternalSwap(HingeLossParameter* other);
+  void UnsafeMergeFrom(const HingeLossParameter& from);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
+  public:
+
+  ::google::protobuf::Metadata GetMetadata() const;
+
+  // nested types ----------------------------------------------------
+
+  typedef HingeLossParameter_Norm Norm;
+  static const Norm L1 =
+    HingeLossParameter_Norm_L1;
+  static const Norm L2 =
+    HingeLossParameter_Norm_L2;
+  static inline bool Norm_IsValid(int value) {
+    return HingeLossParameter_Norm_IsValid(value);
+  }
+  static const Norm Norm_MIN =
+    HingeLossParameter_Norm_Norm_MIN;
+  static const Norm Norm_MAX =
+    HingeLossParameter_Norm_Norm_MAX;
+  static const int Norm_ARRAYSIZE =
+    HingeLossParameter_Norm_Norm_ARRAYSIZE;
+  static inline const ::google::protobuf::EnumDescriptor*
+  Norm_descriptor() {
+    return HingeLossParameter_Norm_descriptor();
+  }
+  static inline const ::std::string& Norm_Name(Norm value) {
+    return HingeLossParameter_Norm_Name(value);
+  }
+  static inline bool Norm_Parse(const ::std::string& name,
+      Norm* value) {
+    return HingeLossParameter_Norm_Parse(name, value);
+  }
+
+  // accessors -------------------------------------------------------
+
+  // optional .caffe.HingeLossParameter.Norm norm = 1 [default = L1];
+  bool has_norm() const;
+  void clear_norm();
+  static const int kNormFieldNumber = 1;
+  ::caffe::HingeLossParameter_Norm norm() const;
+  void set_norm(::caffe::HingeLossParameter_Norm value);
+
+  // @@protoc_insertion_point(class_scope:caffe.HingeLossParameter)
+ private:
+  inline void set_has_norm();
+  inline void clear_has_norm();
+
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  ::google::protobuf::internal::HasBits<1> _has_bits_;
+  mutable int _cached_size_;
+  int norm_;
+  friend void  protobuf_InitDefaults_caffe_2eproto_impl();
+  friend void  protobuf_AddDesc_caffe_2eproto_impl();
+  friend void protobuf_AssignDesc_caffe_2eproto();
+  friend void protobuf_ShutdownFile_caffe_2eproto();
+
+  void InitAsDefaultInstance();
+};
+extern ::google::protobuf::internal::ExplicitlyConstructed<HingeLossParameter> HingeLossParameter_default_instance_;
+
+// -------------------------------------------------------------------
+
+class ImageDataParameter : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:caffe.ImageDataParameter) */ {
+ public:
+  ImageDataParameter();
+  virtual ~ImageDataParameter();
+
+  ImageDataParameter(const ImageDataParameter& from);
+
+  inline ImageDataParameter& operator=(const ImageDataParameter& from) {
+    CopyFrom(from);
+    return *this;
+  }
+
+  inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields();
+  }
+
+  inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields();
+  }
+
+  static const ::google::protobuf::Descriptor* descriptor();
+  static const ImageDataParameter& default_instance();
+
+  static const ImageDataParameter* internal_default_instance();
+
+  void Swap(ImageDataParameter* other);
+
+  // implements Message ----------------------------------------------
+
+  inline ImageDataParameter* New() const { return New(NULL); }
+
+  ImageDataParameter* New(::google::protobuf::Arena* arena) const;
+  void CopyFrom(const ::google::protobuf::Message& from);
+  void MergeFrom(const ::google::protobuf::Message& from);
+  void CopyFrom(const ImageDataParameter& from);
+  void MergeFrom(const ImageDataParameter& from);
+  void Clear();
+  bool IsInitialized() const;
+
+  size_t ByteSizeLong() const;
+  bool MergePartialFromCodedStream(
+      ::google::protobuf::io::CodedInputStream* input);
+  void SerializeWithCachedSizes(
+      ::google::protobuf::io::CodedOutputStream* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
+  int GetCachedSize() const { return _cached_size_; }
+  private:
+  void SharedCtor();
+  void SharedDtor();
+  void SetCachedSize(int size) const;
+  void InternalSwap(ImageDataParameter* other);
+  void UnsafeMergeFrom(const ImageDataParameter& from);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
+  public:
+
+  ::google::protobuf::Metadata GetMetadata() const;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  // optional string source = 1;
+  bool has_source() const;
+  void clear_source();
+  static const int kSourceFieldNumber = 1;
+  const ::std::string& source() const;
+  void set_source(const ::std::string& value);
+  void set_source(const char* value);
+  void set_source(const char* value, size_t size);
+  ::std::string* mutable_source();
+  ::std::string* release_source();
+  void set_allocated_source(::std::string* source);
+
+  // optional uint32 batch_size = 4;
+  bool has_batch_size() const;
+  void clear_batch_size();
+  static const int kBatchSizeFieldNumber = 4;
+  ::google::protobuf::uint32 batch_size() const;
+  void set_batch_size(::google::protobuf::uint32 value);
+
+  // optional uint32 rand_skip = 7 [default = 0];
+  bool has_rand_skip() const;
+  void clear_rand_skip();
+  static const int kRandSkipFieldNumber = 7;
+  ::google::protobuf::uint32 rand_skip() const;
+  void set_rand_skip(::google::protobuf::uint32 value);
+
+  // optional bool shuffle = 8 [default = false];
+  bool has_shuffle() const;
+  void clear_shuffle();
+  static const int kShuffleFieldNumber = 8;
+  bool shuffle() const;
+  void set_shuffle(bool value);
+
+  // optional uint32 new_height = 9 [default = 0];
+  bool has_new_height() const;
+  void clear_new_height();
+  static const int kNewHeightFieldNumber = 9;
+  ::google::protobuf::uint32 new_height() const;
+  void set_new_height(::google::protobuf::uint32 value);
+
+  // optional uint32 new_width = 10 [default = 0];
+  bool has_new_width() const;
+  void clear_new_width();
+  static const int kNewWidthFieldNumber = 10;
+  ::google::protobuf::uint32 new_width() const;
+  void set_new_width(::google::protobuf::uint32 value);
+
+  // optional bool is_color = 11 [default = true];
+  bool has_is_color() const;
+  void clear_is_color();
+  static const int kIsColorFieldNumber = 11;
+  bool is_color() const;
+  void set_is_color(bool value);
+
+  // optional float scale = 2 [default = 1];
+  bool has_scale() const;
+  void clear_scale();
+  static const int kScaleFieldNumber = 2;
+  float scale() const;
+  void set_scale(float value);
+
+  // optional string mean_file = 3;
+  bool has_mean_file() const;
+  void clear_mean_file();
+  static const int kMeanFileFieldNumber = 3;
+  const ::std::string& mean_file() const;
+  void set_mean_file(const ::std::string& value);
+  void set_mean_file(const char* value);
+  void set_mean_file(const char* value, size_t size);
+  ::std::string* mutable_mean_file();
+  ::std::string* release_mean_file();
+  void set_allocated_mean_file(::std::string* mean_file);
+
+  // optional uint32 crop_size = 5 [default = 0];
+  bool has_crop_size() const;
+  void clear_crop_size();
+  static const int kCropSizeFieldNumber = 5;
+  ::google::protobuf::uint32 crop_size() const;
+  void set_crop_size(::google::protobuf::uint32 value);
+
+  // optional bool mirror = 6 [default = false];
+  bool has_mirror() const;
+  void clear_mirror();
+  static const int kMirrorFieldNumber = 6;
+  bool mirror() const;
+  void set_mirror(bool value);
+
+  // optional string root_folder = 12 [default = ""];
+  bool has_root_folder() const;
+  void clear_root_folder();
+  static const int kRootFolderFieldNumber = 12;
+  const ::std::string& root_folder() const;
+  void set_root_folder(const ::std::string& value);
+  void set_root_folder(const char* value);
+  void set_root_folder(const char* value, size_t size);
+  ::std::string* mutable_root_folder();
+  ::std::string* release_root_folder();
+  void set_allocated_root_folder(::std::string* root_folder);
+
+  // @@protoc_insertion_point(class_scope:caffe.ImageDataParameter)
+ private:
+  inline void set_has_source();
+  inline void clear_has_source();
+  inline void set_has_batch_size();
+  inline void clear_has_batch_size();
+  inline void set_has_rand_skip();
+  inline void clear_has_rand_skip();
+  inline void set_has_shuffle();
+  inline void clear_has_shuffle();
+  inline void set_has_new_height();
+  inline void clear_has_new_height();
+  inline void set_has_new_width();
+  inline void clear_has_new_width();
+  inline void set_has_is_color();
+  inline void clear_has_is_color();
+  inline void set_has_scale();
+  inline void clear_has_scale();
+  inline void set_has_mean_file();
+  inline void clear_has_mean_file();
+  inline void set_has_crop_size();
+  inline void clear_has_crop_size();
+  inline void set_has_mirror();
+  inline void clear_has_mirror();
+  inline void set_has_root_folder();
+  inline void clear_has_root_folder();
+
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  ::google::protobuf::internal::HasBits<1> _has_bits_;
+  mutable int _cached_size_;
+  ::google::protobuf::internal::ArenaStringPtr source_;
+  ::google::protobuf::internal::ArenaStringPtr mean_file_;
+  ::google::protobuf::internal::ArenaStringPtr root_folder_;
+  ::google::protobuf::uint32 batch_size_;
+  ::google::protobuf::uint32 rand_skip_;
+  ::google::protobuf::uint32 new_height_;
+  ::google::protobuf::uint32 new_width_;
+  bool shuffle_;
+  bool mirror_;
+  ::google::protobuf::uint32 crop_size_;
+  bool is_color_;
+  float scale_;
+  friend void  protobuf_InitDefaults_caffe_2eproto_impl();
+  friend void  protobuf_AddDesc_caffe_2eproto_impl();
+  friend void protobuf_AssignDesc_caffe_2eproto();
+  friend void protobuf_ShutdownFile_caffe_2eproto();
+
+  void InitAsDefaultInstance();
+};
+extern ::google::protobuf::internal::ExplicitlyConstructed<ImageDataParameter> ImageDataParameter_default_instance_;
+
+// -------------------------------------------------------------------
+
+class InfogainLossParameter : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:caffe.InfogainLossParameter) */ {
+ public:
+  InfogainLossParameter();
+  virtual ~InfogainLossParameter();
+
+  InfogainLossParameter(const InfogainLossParameter& from);
+
+  inline InfogainLossParameter& operator=(const InfogainLossParameter& from) {
+    CopyFrom(from);
+    return *this;
+  }
+
+  inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields();
+  }
+
+  inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields();
+  }
+
+  static const ::google::protobuf::Descriptor* descriptor();
+  static const InfogainLossParameter& default_instance();
+
+  static const InfogainLossParameter* internal_default_instance();
+
+  void Swap(InfogainLossParameter* other);
+
+  // implements Message ----------------------------------------------
+
+  inline InfogainLossParameter* New() const { return New(NULL); }
+
+  InfogainLossParameter* New(::google::protobuf::Arena* arena) const;
+  void CopyFrom(const ::google::protobuf::Message& from);
+  void MergeFrom(const ::google::protobuf::Message& from);
+  void CopyFrom(const InfogainLossParameter& from);
+  void MergeFrom(const InfogainLossParameter& from);
+  void Clear();
+  bool IsInitialized() const;
+
+  size_t ByteSizeLong() const;
+  bool MergePartialFromCodedStream(
+      ::google::protobuf::io::CodedInputStream* input);
+  void SerializeWithCachedSizes(
+      ::google::protobuf::io::CodedOutputStream* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
+  int GetCachedSize() const { return _cached_size_; }
+  private:
+  void SharedCtor();
+  void SharedDtor();
+  void SetCachedSize(int size) const;
+  void InternalSwap(InfogainLossParameter* other);
+  void UnsafeMergeFrom(const InfogainLossParameter& from);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
+  public:
+
+  ::google::protobuf::Metadata GetMetadata() const;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  // optional string source = 1;
+  bool has_source() const;
+  void clear_source();
+  static const int kSourceFieldNumber = 1;
+  const ::std::string& source() const;
+  void set_source(const ::std::string& value);
+  void set_source(const char* value);
+  void set_source(const char* value, size_t size);
+  ::std::string* mutable_source();
+  ::std::string* release_source();
+  void set_allocated_source(::std::string* source);
+
+  // @@protoc_insertion_point(class_scope:caffe.InfogainLossParameter)
+ private:
+  inline void set_has_source();
+  inline void clear_has_source();
+
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  ::google::protobuf::internal::HasBits<1> _has_bits_;
+  mutable int _cached_size_;
+  ::google::protobuf::internal::ArenaStringPtr source_;
+  friend void  protobuf_InitDefaults_caffe_2eproto_impl();
+  friend void  protobuf_AddDesc_caffe_2eproto_impl();
+  friend void protobuf_AssignDesc_caffe_2eproto();
+  friend void protobuf_ShutdownFile_caffe_2eproto();
+
+  void InitAsDefaultInstance();
+};
+extern ::google::protobuf::internal::ExplicitlyConstructed<InfogainLossParameter> InfogainLossParameter_default_instance_;
+
+// -------------------------------------------------------------------
+
+class InnerProductParameter : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:caffe.InnerProductParameter) */ {
+ public:
+  InnerProductParameter();
+  virtual ~InnerProductParameter();
+
+  InnerProductParameter(const InnerProductParameter& from);
+
+  inline InnerProductParameter& operator=(const InnerProductParameter& from) {
+    CopyFrom(from);
+    return *this;
+  }
+
+  inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields();
+  }
+
+  inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields();
+  }
+
+  static const ::google::protobuf::Descriptor* descriptor();
+  static const InnerProductParameter& default_instance();
+
+  static const InnerProductParameter* internal_default_instance();
+
+  void Swap(InnerProductParameter* other);
+
+  // implements Message ----------------------------------------------
+
+  inline InnerProductParameter* New() const { return New(NULL); }
+
+  InnerProductParameter* New(::google::protobuf::Arena* arena) const;
+  void CopyFrom(const ::google::protobuf::Message& from);
+  void MergeFrom(const ::google::protobuf::Message& from);
+  void CopyFrom(const InnerProductParameter& from);
+  void MergeFrom(const InnerProductParameter& from);
+  void Clear();
+  bool IsInitialized() const;
+
+  size_t ByteSizeLong() const;
+  bool MergePartialFromCodedStream(
+      ::google::protobuf::io::CodedInputStream* input);
+  void SerializeWithCachedSizes(
+      ::google::protobuf::io::CodedOutputStream* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
+  int GetCachedSize() const { return _cached_size_; }
+  private:
+  void SharedCtor();
+  void SharedDtor();
+  void SetCachedSize(int size) const;
+  void InternalSwap(InnerProductParameter* other);
+  void UnsafeMergeFrom(const InnerProductParameter& from);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
+  public:
+
+  ::google::protobuf::Metadata GetMetadata() const;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  // optional uint32 num_output = 1;
+  bool has_num_output() const;
+  void clear_num_output();
+  static const int kNumOutputFieldNumber = 1;
+  ::google::protobuf::uint32 num_output() const;
+  void set_num_output(::google::protobuf::uint32 value);
+
+  // optional bool bias_term = 2 [default = true];
+  bool has_bias_term() const;
+  void clear_bias_term();
+  static const int kBiasTermFieldNumber = 2;
+  bool bias_term() const;
+  void set_bias_term(bool value);
+
+  // optional .caffe.FillerParameter weight_filler = 3;
+  bool has_weight_filler() const;
+  void clear_weight_filler();
+  static const int kWeightFillerFieldNumber = 3;
+  const ::caffe::FillerParameter& weight_filler() const;
+  ::caffe::FillerParameter* mutable_weight_filler();
+  ::caffe::FillerParameter* release_weight_filler();
+  void set_allocated_weight_filler(::caffe::FillerParameter* weight_filler);
+
+  // optional .caffe.FillerParameter bias_filler = 4;
+  bool has_bias_filler() const;
+  void clear_bias_filler();
+  static const int kBiasFillerFieldNumber = 4;
+  const ::caffe::FillerParameter& bias_filler() const;
+  ::caffe::FillerParameter* mutable_bias_filler();
+  ::caffe::FillerParameter* release_bias_filler();
+  void set_allocated_bias_filler(::caffe::FillerParameter* bias_filler);
+
+  // optional int32 axis = 5 [default = 1];
+  bool has_axis() const;
+  void clear_axis();
+  static const int kAxisFieldNumber = 5;
+  ::google::protobuf::int32 axis() const;
+  void set_axis(::google::protobuf::int32 value);
+
+  // @@protoc_insertion_point(class_scope:caffe.InnerProductParameter)
+ private:
+  inline void set_has_num_output();
+  inline void clear_has_num_output();
+  inline void set_has_bias_term();
+  inline void clear_has_bias_term();
+  inline void set_has_weight_filler();
+  inline void clear_has_weight_filler();
+  inline void set_has_bias_filler();
+  inline void clear_has_bias_filler();
+  inline void set_has_axis();
+  inline void clear_has_axis();
+
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  ::google::protobuf::internal::HasBits<1> _has_bits_;
+  mutable int _cached_size_;
+  ::caffe::FillerParameter* weight_filler_;
+  ::caffe::FillerParameter* bias_filler_;
+  ::google::protobuf::uint32 num_output_;
+  bool bias_term_;
+  ::google::protobuf::int32 axis_;
+  friend void  protobuf_InitDefaults_caffe_2eproto_impl();
+  friend void  protobuf_AddDesc_caffe_2eproto_impl();
+  friend void protobuf_AssignDesc_caffe_2eproto();
+  friend void protobuf_ShutdownFile_caffe_2eproto();
+
+  void InitAsDefaultInstance();
+};
+extern ::google::protobuf::internal::ExplicitlyConstructed<InnerProductParameter> InnerProductParameter_default_instance_;
+
+// -------------------------------------------------------------------
+
+class LogParameter : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:caffe.LogParameter) */ {
+ public:
+  LogParameter();
+  virtual ~LogParameter();
+
+  LogParameter(const LogParameter& from);
+
+  inline LogParameter& operator=(const LogParameter& from) {
+    CopyFrom(from);
+    return *this;
+  }
+
+  inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields();
+  }
+
+  inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields();
+  }
+
+  static const ::google::protobuf::Descriptor* descriptor();
+  static const LogParameter& default_instance();
+
+  static const LogParameter* internal_default_instance();
+
+  void Swap(LogParameter* other);
+
+  // implements Message ----------------------------------------------
+
+  inline LogParameter* New() const { return New(NULL); }
+
+  LogParameter* New(::google::protobuf::Arena* arena) const;
+  void CopyFrom(const ::google::protobuf::Message& from);
+  void MergeFrom(const ::google::protobuf::Message& from);
+  void CopyFrom(const LogParameter& from);
+  void MergeFrom(const LogParameter& from);
+  void Clear();
+  bool IsInitialized() const;
+
+  size_t ByteSizeLong() const;
+  bool MergePartialFromCodedStream(
+      ::google::protobuf::io::CodedInputStream* input);
+  void SerializeWithCachedSizes(
+      ::google::protobuf::io::CodedOutputStream* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
+  int GetCachedSize() const { return _cached_size_; }
+  private:
+  void SharedCtor();
+  void SharedDtor();
+  void SetCachedSize(int size) const;
+  void InternalSwap(LogParameter* other);
+  void UnsafeMergeFrom(const LogParameter& from);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
+  public:
+
+  ::google::protobuf::Metadata GetMetadata() const;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  // optional float base = 1 [default = -1];
+  bool has_base() const;
+  void clear_base();
+  static const int kBaseFieldNumber = 1;
+  float base() const;
+  void set_base(float value);
+
+  // optional float scale = 2 [default = 1];
+  bool has_scale() const;
+  void clear_scale();
+  static const int kScaleFieldNumber = 2;
+  float scale() const;
+  void set_scale(float value);
+
+  // optional float shift = 3 [default = 0];
+  bool has_shift() const;
+  void clear_shift();
+  static const int kShiftFieldNumber = 3;
+  float shift() const;
+  void set_shift(float value);
+
+  // @@protoc_insertion_point(class_scope:caffe.LogParameter)
+ private:
+  inline void set_has_base();
+  inline void clear_has_base();
+  inline void set_has_scale();
+  inline void clear_has_scale();
+  inline void set_has_shift();
+  inline void clear_has_shift();
+
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  ::google::protobuf::internal::HasBits<1> _has_bits_;
+  mutable int _cached_size_;
+  float shift_;
+  float base_;
+  float scale_;
+  friend void  protobuf_InitDefaults_caffe_2eproto_impl();
+  friend void  protobuf_AddDesc_caffe_2eproto_impl();
+  friend void protobuf_AssignDesc_caffe_2eproto();
+  friend void protobuf_ShutdownFile_caffe_2eproto();
+
+  void InitAsDefaultInstance();
+};
+extern ::google::protobuf::internal::ExplicitlyConstructed<LogParameter> LogParameter_default_instance_;
+
+// -------------------------------------------------------------------
+
+class LRNParameter : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:caffe.LRNParameter) */ {
+ public:
+  LRNParameter();
+  virtual ~LRNParameter();
+
+  LRNParameter(const LRNParameter& from);
+
+  inline LRNParameter& operator=(const LRNParameter& from) {
+    CopyFrom(from);
+    return *this;
+  }
+
+  inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields();
+  }
+
+  inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields();
+  }
+
+  static const ::google::protobuf::Descriptor* descriptor();
+  static const LRNParameter& default_instance();
+
+  static const LRNParameter* internal_default_instance();
+
+  void Swap(LRNParameter* other);
+
+  // implements Message ----------------------------------------------
+
+  inline LRNParameter* New() const { return New(NULL); }
+
+  LRNParameter* New(::google::protobuf::Arena* arena) const;
+  void CopyFrom(const ::google::protobuf::Message& from);
+  void MergeFrom(const ::google::protobuf::Message& from);
+  void CopyFrom(const LRNParameter& from);
+  void MergeFrom(const LRNParameter& from);
+  void Clear();
+  bool IsInitialized() const;
+
+  size_t ByteSizeLong() const;
+  bool MergePartialFromCodedStream(
+      ::google::protobuf::io::CodedInputStream* input);
+  void SerializeWithCachedSizes(
+      ::google::protobuf::io::CodedOutputStream* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
+  int GetCachedSize() const { return _cached_size_; }
+  private:
+  void SharedCtor();
+  void SharedDtor();
+  void SetCachedSize(int size) const;
+  void InternalSwap(LRNParameter* other);
+  void UnsafeMergeFrom(const LRNParameter& from);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
+  public:
+
+  ::google::protobuf::Metadata GetMetadata() const;
+
+  // nested types ----------------------------------------------------
+
+  typedef LRNParameter_NormRegion NormRegion;
+  static const NormRegion ACROSS_CHANNELS =
+    LRNParameter_NormRegion_ACROSS_CHANNELS;
+  static const NormRegion WITHIN_CHANNEL =
+    LRNParameter_NormRegion_WITHIN_CHANNEL;
+  static inline bool NormRegion_IsValid(int value) {
+    return LRNParameter_NormRegion_IsValid(value);
+  }
+  static const NormRegion NormRegion_MIN =
+    LRNParameter_NormRegion_NormRegion_MIN;
+  static const NormRegion NormRegion_MAX =
+    LRNParameter_NormRegion_NormRegion_MAX;
+  static const int NormRegion_ARRAYSIZE =
+    LRNParameter_NormRegion_NormRegion_ARRAYSIZE;
+  static inline const ::google::protobuf::EnumDescriptor*
+  NormRegion_descriptor() {
+    return LRNParameter_NormRegion_descriptor();
+  }
+  static inline const ::std::string& NormRegion_Name(NormRegion value) {
+    return LRNParameter_NormRegion_Name(value);
+  }
+  static inline bool NormRegion_Parse(const ::std::string& name,
+      NormRegion* value) {
+    return LRNParameter_NormRegion_Parse(name, value);
+  }
+
+  // accessors -------------------------------------------------------
+
+  // optional uint32 local_size = 1 [default = 5];
+  bool has_local_size() const;
+  void clear_local_size();
+  static const int kLocalSizeFieldNumber = 1;
+  ::google::protobuf::uint32 local_size() const;
+  void set_local_size(::google::protobuf::uint32 value);
+
+  // optional float alpha = 2 [default = 1];
+  bool has_alpha() const;
+  void clear_alpha();
+  static const int kAlphaFieldNumber = 2;
+  float alpha() const;
+  void set_alpha(float value);
+
+  // optional float beta = 3 [default = 0.75];
+  bool has_beta() const;
+  void clear_beta();
+  static const int kBetaFieldNumber = 3;
+  float beta() const;
+  void set_beta(float value);
+
+  // optional .caffe.LRNParameter.NormRegion norm_region = 4 [default = ACROSS_CHANNELS];
+  bool has_norm_region() const;
+  void clear_norm_region();
+  static const int kNormRegionFieldNumber = 4;
+  ::caffe::LRNParameter_NormRegion norm_region() const;
+  void set_norm_region(::caffe::LRNParameter_NormRegion value);
+
+  // optional float k = 5 [default = 1];
+  bool has_k() const;
+  void clear_k();
+  static const int kKFieldNumber = 5;
+  float k() const;
+  void set_k(float value);
+
+  // @@protoc_insertion_point(class_scope:caffe.LRNParameter)
+ private:
+  inline void set_has_local_size();
+  inline void clear_has_local_size();
+  inline void set_has_alpha();
+  inline void clear_has_alpha();
+  inline void set_has_beta();
+  inline void clear_has_beta();
+  inline void set_has_norm_region();
+  inline void clear_has_norm_region();
+  inline void set_has_k();
+  inline void clear_has_k();
+
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  ::google::protobuf::internal::HasBits<1> _has_bits_;
+  mutable int _cached_size_;
+  int norm_region_;
+  ::google::protobuf::uint32 local_size_;
+  float alpha_;
+  float beta_;
+  float k_;
+  friend void  protobuf_InitDefaults_caffe_2eproto_impl();
+  friend void  protobuf_AddDesc_caffe_2eproto_impl();
+  friend void protobuf_AssignDesc_caffe_2eproto();
+  friend void protobuf_ShutdownFile_caffe_2eproto();
+
+  void InitAsDefaultInstance();
+};
+extern ::google::protobuf::internal::ExplicitlyConstructed<LRNParameter> LRNParameter_default_instance_;
+
+// -------------------------------------------------------------------
+
+class MemoryDataParameter : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:caffe.MemoryDataParameter) */ {
+ public:
+  MemoryDataParameter();
+  virtual ~MemoryDataParameter();
+
+  MemoryDataParameter(const MemoryDataParameter& from);
+
+  inline MemoryDataParameter& operator=(const MemoryDataParameter& from) {
+    CopyFrom(from);
+    return *this;
+  }
+
+  inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields();
+  }
+
+  inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields();
+  }
+
+  static const ::google::protobuf::Descriptor* descriptor();
+  static const MemoryDataParameter& default_instance();
+
+  static const MemoryDataParameter* internal_default_instance();
+
+  void Swap(MemoryDataParameter* other);
+
+  // implements Message ----------------------------------------------
+
+  inline MemoryDataParameter* New() const { return New(NULL); }
+
+  MemoryDataParameter* New(::google::protobuf::Arena* arena) const;
+  void CopyFrom(const ::google::protobuf::Message& from);
+  void MergeFrom(const ::google::protobuf::Message& from);
+  void CopyFrom(const MemoryDataParameter& from);
+  void MergeFrom(const MemoryDataParameter& from);
+  void Clear();
+  bool IsInitialized() const;
+
+  size_t ByteSizeLong() const;
+  bool MergePartialFromCodedStream(
+      ::google::protobuf::io::CodedInputStream* input);
+  void SerializeWithCachedSizes(
+      ::google::protobuf::io::CodedOutputStream* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
+  int GetCachedSize() const { return _cached_size_; }
+  private:
+  void SharedCtor();
+  void SharedDtor();
+  void SetCachedSize(int size) const;
+  void InternalSwap(MemoryDataParameter* other);
+  void UnsafeMergeFrom(const MemoryDataParameter& from);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
+  public:
+
+  ::google::protobuf::Metadata GetMetadata() const;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  // optional uint32 batch_size = 1;
+  bool has_batch_size() const;
+  void clear_batch_size();
+  static const int kBatchSizeFieldNumber = 1;
+  ::google::protobuf::uint32 batch_size() const;
+  void set_batch_size(::google::protobuf::uint32 value);
+
+  // optional uint32 channels = 2;
+  bool has_channels() const;
+  void clear_channels();
+  static const int kChannelsFieldNumber = 2;
+  ::google::protobuf::uint32 channels() const;
+  void set_channels(::google::protobuf::uint32 value);
+
+  // optional uint32 height = 3;
+  bool has_height() const;
+  void clear_height();
+  static const int kHeightFieldNumber = 3;
+  ::google::protobuf::uint32 height() const;
+  void set_height(::google::protobuf::uint32 value);
+
+  // optional uint32 width = 4;
+  bool has_width() const;
+  void clear_width();
+  static const int kWidthFieldNumber = 4;
+  ::google::protobuf::uint32 width() const;
+  void set_width(::google::protobuf::uint32 value);
+
+  // @@protoc_insertion_point(class_scope:caffe.MemoryDataParameter)
+ private:
+  inline void set_has_batch_size();
+  inline void clear_has_batch_size();
+  inline void set_has_channels();
+  inline void clear_has_channels();
+  inline void set_has_height();
+  inline void clear_has_height();
+  inline void set_has_width();
+  inline void clear_has_width();
+
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  ::google::protobuf::internal::HasBits<1> _has_bits_;
+  mutable int _cached_size_;
+  ::google::protobuf::uint32 batch_size_;
+  ::google::protobuf::uint32 channels_;
+  ::google::protobuf::uint32 height_;
+  ::google::protobuf::uint32 width_;
+  friend void  protobuf_InitDefaults_caffe_2eproto_impl();
+  friend void  protobuf_AddDesc_caffe_2eproto_impl();
+  friend void protobuf_AssignDesc_caffe_2eproto();
+  friend void protobuf_ShutdownFile_caffe_2eproto();
+
+  void InitAsDefaultInstance();
+};
+extern ::google::protobuf::internal::ExplicitlyConstructed<MemoryDataParameter> MemoryDataParameter_default_instance_;
+
+// -------------------------------------------------------------------
+
+class MVNParameter : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:caffe.MVNParameter) */ {
+ public:
+  MVNParameter();
+  virtual ~MVNParameter();
+
+  MVNParameter(const MVNParameter& from);
+
+  inline MVNParameter& operator=(const MVNParameter& from) {
+    CopyFrom(from);
+    return *this;
+  }
+
+  inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields();
+  }
+
+  inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields();
+  }
+
+  static const ::google::protobuf::Descriptor* descriptor();
+  static const MVNParameter& default_instance();
+
+  static const MVNParameter* internal_default_instance();
+
+  void Swap(MVNParameter* other);
+
+  // implements Message ----------------------------------------------
+
+  inline MVNParameter* New() const { return New(NULL); }
+
+  MVNParameter* New(::google::protobuf::Arena* arena) const;
+  void CopyFrom(const ::google::protobuf::Message& from);
+  void MergeFrom(const ::google::protobuf::Message& from);
+  void CopyFrom(const MVNParameter& from);
+  void MergeFrom(const MVNParameter& from);
+  void Clear();
+  bool IsInitialized() const;
+
+  size_t ByteSizeLong() const;
+  bool MergePartialFromCodedStream(
+      ::google::protobuf::io::CodedInputStream* input);
+  void SerializeWithCachedSizes(
+      ::google::protobuf::io::CodedOutputStream* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
+  int GetCachedSize() const { return _cached_size_; }
+  private:
+  void SharedCtor();
+  void SharedDtor();
+  void SetCachedSize(int size) const;
+  void InternalSwap(MVNParameter* other);
+  void UnsafeMergeFrom(const MVNParameter& from);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
+  public:
+
+  ::google::protobuf::Metadata GetMetadata() const;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  // optional bool normalize_variance = 1 [default = true];
+  bool has_normalize_variance() const;
+  void clear_normalize_variance();
+  static const int kNormalizeVarianceFieldNumber = 1;
+  bool normalize_variance() const;
+  void set_normalize_variance(bool value);
+
+  // optional bool across_channels = 2 [default = false];
+  bool has_across_channels() const;
+  void clear_across_channels();
+  static const int kAcrossChannelsFieldNumber = 2;
+  bool across_channels() const;
+  void set_across_channels(bool value);
+
+  // optional float eps = 3 [default = 1e-09];
+  bool has_eps() const;
+  void clear_eps();
+  static const int kEpsFieldNumber = 3;
+  float eps() const;
+  void set_eps(float value);
+
+  // @@protoc_insertion_point(class_scope:caffe.MVNParameter)
+ private:
+  inline void set_has_normalize_variance();
+  inline void clear_has_normalize_variance();
+  inline void set_has_across_channels();
+  inline void clear_has_across_channels();
+  inline void set_has_eps();
+  inline void clear_has_eps();
+
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  ::google::protobuf::internal::HasBits<1> _has_bits_;
+  mutable int _cached_size_;
+  bool across_channels_;
+  bool normalize_variance_;
+  float eps_;
+  friend void  protobuf_InitDefaults_caffe_2eproto_impl();
+  friend void  protobuf_AddDesc_caffe_2eproto_impl();
+  friend void protobuf_AssignDesc_caffe_2eproto();
+  friend void protobuf_ShutdownFile_caffe_2eproto();
+
+  void InitAsDefaultInstance();
+};
+extern ::google::protobuf::internal::ExplicitlyConstructed<MVNParameter> MVNParameter_default_instance_;
+
+// -------------------------------------------------------------------
+
+class PoolingParameter : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:caffe.PoolingParameter) */ {
+ public:
+  PoolingParameter();
+  virtual ~PoolingParameter();
+
+  PoolingParameter(const PoolingParameter& from);
+
+  inline PoolingParameter& operator=(const PoolingParameter& from) {
+    CopyFrom(from);
+    return *this;
+  }
+
+  inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields();
+  }
+
+  inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields();
+  }
+
+  static const ::google::protobuf::Descriptor* descriptor();
+  static const PoolingParameter& default_instance();
+
+  static const PoolingParameter* internal_default_instance();
+
+  void Swap(PoolingParameter* other);
+
+  // implements Message ----------------------------------------------
+
+  inline PoolingParameter* New() const { return New(NULL); }
+
+  PoolingParameter* New(::google::protobuf::Arena* arena) const;
+  void CopyFrom(const ::google::protobuf::Message& from);
+  void MergeFrom(const ::google::protobuf::Message& from);
+  void CopyFrom(const PoolingParameter& from);
+  void MergeFrom(const PoolingParameter& from);
+  void Clear();
+  bool IsInitialized() const;
+
+  size_t ByteSizeLong() const;
+  bool MergePartialFromCodedStream(
+      ::google::protobuf::io::CodedInputStream* input);
+  void SerializeWithCachedSizes(
+      ::google::protobuf::io::CodedOutputStream* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
+  int GetCachedSize() const { return _cached_size_; }
+  private:
+  void SharedCtor();
+  void SharedDtor();
+  void SetCachedSize(int size) const;
+  void InternalSwap(PoolingParameter* other);
+  void UnsafeMergeFrom(const PoolingParameter& from);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
+  public:
+
+  ::google::protobuf::Metadata GetMetadata() const;
+
+  // nested types ----------------------------------------------------
+
+  typedef PoolingParameter_PoolMethod PoolMethod;
+  static const PoolMethod MAX =
+    PoolingParameter_PoolMethod_MAX;
+  static const PoolMethod AVE =
+    PoolingParameter_PoolMethod_AVE;
+  static const PoolMethod STOCHASTIC =
+    PoolingParameter_PoolMethod_STOCHASTIC;
+  static inline bool PoolMethod_IsValid(int value) {
+    return PoolingParameter_PoolMethod_IsValid(value);
+  }
+  static const PoolMethod PoolMethod_MIN =
+    PoolingParameter_PoolMethod_PoolMethod_MIN;
+  static const PoolMethod PoolMethod_MAX =
+    PoolingParameter_PoolMethod_PoolMethod_MAX;
+  static const int PoolMethod_ARRAYSIZE =
+    PoolingParameter_PoolMethod_PoolMethod_ARRAYSIZE;
+  static inline const ::google::protobuf::EnumDescriptor*
+  PoolMethod_descriptor() {
+    return PoolingParameter_PoolMethod_descriptor();
+  }
+  static inline const ::std::string& PoolMethod_Name(PoolMethod value) {
+    return PoolingParameter_PoolMethod_Name(value);
+  }
+  static inline bool PoolMethod_Parse(const ::std::string& name,
+      PoolMethod* value) {
+    return PoolingParameter_PoolMethod_Parse(name, value);
+  }
+
+  typedef PoolingParameter_Engine Engine;
+  static const Engine DEFAULT =
+    PoolingParameter_Engine_DEFAULT;
+  static const Engine CAFFE =
+    PoolingParameter_Engine_CAFFE;
+  static const Engine CUDNN =
+    PoolingParameter_Engine_CUDNN;
+  static inline bool Engine_IsValid(int value) {
+    return PoolingParameter_Engine_IsValid(value);
+  }
+  static const Engine Engine_MIN =
+    PoolingParameter_Engine_Engine_MIN;
+  static const Engine Engine_MAX =
+    PoolingParameter_Engine_Engine_MAX;
+  static const int Engine_ARRAYSIZE =
+    PoolingParameter_Engine_Engine_ARRAYSIZE;
+  static inline const ::google::protobuf::EnumDescriptor*
+  Engine_descriptor() {
+    return PoolingParameter_Engine_descriptor();
+  }
+  static inline const ::std::string& Engine_Name(Engine value) {
+    return PoolingParameter_Engine_Name(value);
+  }
+  static inline bool Engine_Parse(const ::std::string& name,
+      Engine* value) {
+    return PoolingParameter_Engine_Parse(name, value);
+  }
+
+  // accessors -------------------------------------------------------
+
+  // optional .caffe.PoolingParameter.PoolMethod pool = 1 [default = MAX];
+  bool has_pool() const;
+  void clear_pool();
+  static const int kPoolFieldNumber = 1;
+  ::caffe::PoolingParameter_PoolMethod pool() const;
+  void set_pool(::caffe::PoolingParameter_PoolMethod value);
+
+  // optional uint32 pad = 4 [default = 0];
+  bool has_pad() const;
+  void clear_pad();
+  static const int kPadFieldNumber = 4;
+  ::google::protobuf::uint32 pad() const;
+  void set_pad(::google::protobuf::uint32 value);
+
+  // optional uint32 pad_h = 9 [default = 0];
+  bool has_pad_h() const;
+  void clear_pad_h();
+  static const int kPadHFieldNumber = 9;
+  ::google::protobuf::uint32 pad_h() const;
+  void set_pad_h(::google::protobuf::uint32 value);
+
+  // optional uint32 pad_w = 10 [default = 0];
+  bool has_pad_w() const;
+  void clear_pad_w();
+  static const int kPadWFieldNumber = 10;
+  ::google::protobuf::uint32 pad_w() const;
+  void set_pad_w(::google::protobuf::uint32 value);
+
+  // optional uint32 kernel_size = 2;
+  bool has_kernel_size() const;
+  void clear_kernel_size();
+  static const int kKernelSizeFieldNumber = 2;
+  ::google::protobuf::uint32 kernel_size() const;
+  void set_kernel_size(::google::protobuf::uint32 value);
+
+  // optional uint32 kernel_h = 5;
+  bool has_kernel_h() const;
+  void clear_kernel_h();
+  static const int kKernelHFieldNumber = 5;
+  ::google::protobuf::uint32 kernel_h() const;
+  void set_kernel_h(::google::protobuf::uint32 value);
+
+  // optional uint32 kernel_w = 6;
+  bool has_kernel_w() const;
+  void clear_kernel_w();
+  static const int kKernelWFieldNumber = 6;
+  ::google::protobuf::uint32 kernel_w() const;
+  void set_kernel_w(::google::protobuf::uint32 value);
+
+  // optional uint32 stride = 3 [default = 1];
+  bool has_stride() const;
+  void clear_stride();
+  static const int kStrideFieldNumber = 3;
+  ::google::protobuf::uint32 stride() const;
+  void set_stride(::google::protobuf::uint32 value);
+
+  // optional uint32 stride_h = 7;
+  bool has_stride_h() const;
+  void clear_stride_h();
+  static const int kStrideHFieldNumber = 7;
+  ::google::protobuf::uint32 stride_h() const;
+  void set_stride_h(::google::protobuf::uint32 value);
+
+  // optional uint32 stride_w = 8;
+  bool has_stride_w() const;
+  void clear_stride_w();
+  static const int kStrideWFieldNumber = 8;
+  ::google::protobuf::uint32 stride_w() const;
+  void set_stride_w(::google::protobuf::uint32 value);
+
+  // optional .caffe.PoolingParameter.Engine engine = 11 [default = DEFAULT];
+  bool has_engine() const;
+  void clear_engine();
+  static const int kEngineFieldNumber = 11;
+  ::caffe::PoolingParameter_Engine engine() const;
+  void set_engine(::caffe::PoolingParameter_Engine value);
+
+  // optional bool global_pooling = 12 [default = false];
+  bool has_global_pooling() const;
+  void clear_global_pooling();
+  static const int kGlobalPoolingFieldNumber = 12;
+  bool global_pooling() const;
+  void set_global_pooling(bool value);
+
+  // @@protoc_insertion_point(class_scope:caffe.PoolingParameter)
+ private:
+  inline void set_has_pool();
+  inline void clear_has_pool();
+  inline void set_has_pad();
+  inline void clear_has_pad();
+  inline void set_has_pad_h();
+  inline void clear_has_pad_h();
+  inline void set_has_pad_w();
+  inline void clear_has_pad_w();
+  inline void set_has_kernel_size();
+  inline void clear_has_kernel_size();
+  inline void set_has_kernel_h();
+  inline void clear_has_kernel_h();
+  inline void set_has_kernel_w();
+  inline void clear_has_kernel_w();
+  inline void set_has_stride();
+  inline void clear_has_stride();
+  inline void set_has_stride_h();
+  inline void clear_has_stride_h();
+  inline void set_has_stride_w();
+  inline void clear_has_stride_w();
+  inline void set_has_engine();
+  inline void clear_has_engine();
+  inline void set_has_global_pooling();
+  inline void clear_has_global_pooling();
+
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  ::google::protobuf::internal::HasBits<1> _has_bits_;
+  mutable int _cached_size_;
+  int pool_;
+  ::google::protobuf::uint32 pad_;
+  ::google::protobuf::uint32 pad_h_;
+  ::google::protobuf::uint32 pad_w_;
+  ::google::protobuf::uint32 kernel_size_;
+  ::google::protobuf::uint32 kernel_h_;
+  ::google::protobuf::uint32 kernel_w_;
+  ::google::protobuf::uint32 stride_h_;
+  ::google::protobuf::uint32 stride_w_;
+  int engine_;
+  bool global_pooling_;
+  ::google::protobuf::uint32 stride_;
+  friend void  protobuf_InitDefaults_caffe_2eproto_impl();
+  friend void  protobuf_AddDesc_caffe_2eproto_impl();
+  friend void protobuf_AssignDesc_caffe_2eproto();
+  friend void protobuf_ShutdownFile_caffe_2eproto();
+
+  void InitAsDefaultInstance();
+};
+extern ::google::protobuf::internal::ExplicitlyConstructed<PoolingParameter> PoolingParameter_default_instance_;
+
+// -------------------------------------------------------------------
+
+class PowerParameter : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:caffe.PowerParameter) */ {
+ public:
+  PowerParameter();
+  virtual ~PowerParameter();
+
+  PowerParameter(const PowerParameter& from);
+
+  inline PowerParameter& operator=(const PowerParameter& from) {
+    CopyFrom(from);
+    return *this;
+  }
+
+  inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields();
+  }
+
+  inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields();
+  }
+
+  static const ::google::protobuf::Descriptor* descriptor();
+  static const PowerParameter& default_instance();
+
+  static const PowerParameter* internal_default_instance();
+
+  void Swap(PowerParameter* other);
+
+  // implements Message ----------------------------------------------
+
+  inline PowerParameter* New() const { return New(NULL); }
+
+  PowerParameter* New(::google::protobuf::Arena* arena) const;
+  void CopyFrom(const ::google::protobuf::Message& from);
+  void MergeFrom(const ::google::protobuf::Message& from);
+  void CopyFrom(const PowerParameter& from);
+  void MergeFrom(const PowerParameter& from);
+  void Clear();
+  bool IsInitialized() const;
+
+  size_t ByteSizeLong() const;
+  bool MergePartialFromCodedStream(
+      ::google::protobuf::io::CodedInputStream* input);
+  void SerializeWithCachedSizes(
+      ::google::protobuf::io::CodedOutputStream* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
+  int GetCachedSize() const { return _cached_size_; }
+  private:
+  void SharedCtor();
+  void SharedDtor();
+  void SetCachedSize(int size) const;
+  void InternalSwap(PowerParameter* other);
+  void UnsafeMergeFrom(const PowerParameter& from);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
+  public:
+
+  ::google::protobuf::Metadata GetMetadata() const;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  // optional float power = 1 [default = 1];
+  bool has_power() const;
+  void clear_power();
+  static const int kPowerFieldNumber = 1;
+  float power() const;
+  void set_power(float value);
+
+  // optional float scale = 2 [default = 1];
+  bool has_scale() const;
+  void clear_scale();
+  static const int kScaleFieldNumber = 2;
+  float scale() const;
+  void set_scale(float value);
+
+  // optional float shift = 3 [default = 0];
+  bool has_shift() const;
+  void clear_shift();
+  static const int kShiftFieldNumber = 3;
+  float shift() const;
+  void set_shift(float value);
+
+  // @@protoc_insertion_point(class_scope:caffe.PowerParameter)
+ private:
+  inline void set_has_power();
+  inline void clear_has_power();
+  inline void set_has_scale();
+  inline void clear_has_scale();
+  inline void set_has_shift();
+  inline void clear_has_shift();
+
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  ::google::protobuf::internal::HasBits<1> _has_bits_;
+  mutable int _cached_size_;
+  float shift_;
+  float power_;
+  float scale_;
+  friend void  protobuf_InitDefaults_caffe_2eproto_impl();
+  friend void  protobuf_AddDesc_caffe_2eproto_impl();
+  friend void protobuf_AssignDesc_caffe_2eproto();
+  friend void protobuf_ShutdownFile_caffe_2eproto();
+
+  void InitAsDefaultInstance();
+};
+extern ::google::protobuf::internal::ExplicitlyConstructed<PowerParameter> PowerParameter_default_instance_;
+
+// -------------------------------------------------------------------
+
+class PythonParameter : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:caffe.PythonParameter) */ {
+ public:
+  PythonParameter();
+  virtual ~PythonParameter();
+
+  PythonParameter(const PythonParameter& from);
+
+  inline PythonParameter& operator=(const PythonParameter& from) {
+    CopyFrom(from);
+    return *this;
+  }
+
+  inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields();
+  }
+
+  inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields();
+  }
+
+  static const ::google::protobuf::Descriptor* descriptor();
+  static const PythonParameter& default_instance();
+
+  static const PythonParameter* internal_default_instance();
+
+  void Swap(PythonParameter* other);
+
+  // implements Message ----------------------------------------------
+
+  inline PythonParameter* New() const { return New(NULL); }
+
+  PythonParameter* New(::google::protobuf::Arena* arena) const;
+  void CopyFrom(const ::google::protobuf::Message& from);
+  void MergeFrom(const ::google::protobuf::Message& from);
+  void CopyFrom(const PythonParameter& from);
+  void MergeFrom(const PythonParameter& from);
+  void Clear();
+  bool IsInitialized() const;
+
+  size_t ByteSizeLong() const;
+  bool MergePartialFromCodedStream(
+      ::google::protobuf::io::CodedInputStream* input);
+  void SerializeWithCachedSizes(
+      ::google::protobuf::io::CodedOutputStream* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
+  int GetCachedSize() const { return _cached_size_; }
+  private:
+  void SharedCtor();
+  void SharedDtor();
+  void SetCachedSize(int size) const;
+  void InternalSwap(PythonParameter* other);
+  void UnsafeMergeFrom(const PythonParameter& from);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
+  public:
+
+  ::google::protobuf::Metadata GetMetadata() const;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  // optional string module = 1;
+  bool has_module() const;
+  void clear_module();
+  static const int kModuleFieldNumber = 1;
+  const ::std::string& module() const;
+  void set_module(const ::std::string& value);
+  void set_module(const char* value);
+  void set_module(const char* value, size_t size);
+  ::std::string* mutable_module();
+  ::std::string* release_module();
+  void set_allocated_module(::std::string* module);
+
+  // optional string layer = 2;
+  bool has_layer() const;
+  void clear_layer();
+  static const int kLayerFieldNumber = 2;
+  const ::std::string& layer() const;
+  void set_layer(const ::std::string& value);
+  void set_layer(const char* value);
+  void set_layer(const char* value, size_t size);
+  ::std::string* mutable_layer();
+  ::std::string* release_layer();
+  void set_allocated_layer(::std::string* layer);
+
+  // @@protoc_insertion_point(class_scope:caffe.PythonParameter)
+ private:
+  inline void set_has_module();
+  inline void clear_has_module();
+  inline void set_has_layer();
+  inline void clear_has_layer();
+
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  ::google::protobuf::internal::HasBits<1> _has_bits_;
+  mutable int _cached_size_;
+  ::google::protobuf::internal::ArenaStringPtr module_;
+  ::google::protobuf::internal::ArenaStringPtr layer_;
+  friend void  protobuf_InitDefaults_caffe_2eproto_impl();
+  friend void  protobuf_AddDesc_caffe_2eproto_impl();
+  friend void protobuf_AssignDesc_caffe_2eproto();
+  friend void protobuf_ShutdownFile_caffe_2eproto();
+
+  void InitAsDefaultInstance();
+};
+extern ::google::protobuf::internal::ExplicitlyConstructed<PythonParameter> PythonParameter_default_instance_;
+
+// -------------------------------------------------------------------
+
+class ReductionParameter : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:caffe.ReductionParameter) */ {
+ public:
+  ReductionParameter();
+  virtual ~ReductionParameter();
+
+  ReductionParameter(const ReductionParameter& from);
+
+  inline ReductionParameter& operator=(const ReductionParameter& from) {
+    CopyFrom(from);
+    return *this;
+  }
+
+  inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields();
+  }
+
+  inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields();
+  }
+
+  static const ::google::protobuf::Descriptor* descriptor();
+  static const ReductionParameter& default_instance();
+
+  static const ReductionParameter* internal_default_instance();
+
+  void Swap(ReductionParameter* other);
+
+  // implements Message ----------------------------------------------
+
+  inline ReductionParameter* New() const { return New(NULL); }
+
+  ReductionParameter* New(::google::protobuf::Arena* arena) const;
+  void CopyFrom(const ::google::protobuf::Message& from);
+  void MergeFrom(const ::google::protobuf::Message& from);
+  void CopyFrom(const ReductionParameter& from);
+  void MergeFrom(const ReductionParameter& from);
+  void Clear();
+  bool IsInitialized() const;
+
+  size_t ByteSizeLong() const;
+  bool MergePartialFromCodedStream(
+      ::google::protobuf::io::CodedInputStream* input);
+  void SerializeWithCachedSizes(
+      ::google::protobuf::io::CodedOutputStream* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
+  int GetCachedSize() const { return _cached_size_; }
+  private:
+  void SharedCtor();
+  void SharedDtor();
+  void SetCachedSize(int size) const;
+  void InternalSwap(ReductionParameter* other);
+  void UnsafeMergeFrom(const ReductionParameter& from);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
+  public:
+
+  ::google::protobuf::Metadata GetMetadata() const;
+
+  // nested types ----------------------------------------------------
+
+  typedef ReductionParameter_ReductionOp ReductionOp;
+  static const ReductionOp SUM =
+    ReductionParameter_ReductionOp_SUM;
+  static const ReductionOp ASUM =
+    ReductionParameter_ReductionOp_ASUM;
+  static const ReductionOp SUMSQ =
+    ReductionParameter_ReductionOp_SUMSQ;
+  static const ReductionOp MEAN =
+    ReductionParameter_ReductionOp_MEAN;
+  static inline bool ReductionOp_IsValid(int value) {
+    return ReductionParameter_ReductionOp_IsValid(value);
+  }
+  static const ReductionOp ReductionOp_MIN =
+    ReductionParameter_ReductionOp_ReductionOp_MIN;
+  static const ReductionOp ReductionOp_MAX =
+    ReductionParameter_ReductionOp_ReductionOp_MAX;
+  static const int ReductionOp_ARRAYSIZE =
+    ReductionParameter_ReductionOp_ReductionOp_ARRAYSIZE;
+  static inline const ::google::protobuf::EnumDescriptor*
+  ReductionOp_descriptor() {
+    return ReductionParameter_ReductionOp_descriptor();
+  }
+  static inline const ::std::string& ReductionOp_Name(ReductionOp value) {
+    return ReductionParameter_ReductionOp_Name(value);
+  }
+  static inline bool ReductionOp_Parse(const ::std::string& name,
+      ReductionOp* value) {
+    return ReductionParameter_ReductionOp_Parse(name, value);
+  }
+
+  // accessors -------------------------------------------------------
+
+  // optional .caffe.ReductionParameter.ReductionOp operation = 1 [default = SUM];
+  bool has_operation() const;
+  void clear_operation();
+  static const int kOperationFieldNumber = 1;
+  ::caffe::ReductionParameter_ReductionOp operation() const;
+  void set_operation(::caffe::ReductionParameter_ReductionOp value);
+
+  // optional int32 axis = 2 [default = 0];
+  bool has_axis() const;
+  void clear_axis();
+  static const int kAxisFieldNumber = 2;
+  ::google::protobuf::int32 axis() const;
+  void set_axis(::google::protobuf::int32 value);
+
+  // optional float coeff = 3 [default = 1];
+  bool has_coeff() const;
+  void clear_coeff();
+  static const int kCoeffFieldNumber = 3;
+  float coeff() const;
+  void set_coeff(float value);
+
+  // @@protoc_insertion_point(class_scope:caffe.ReductionParameter)
+ private:
+  inline void set_has_operation();
+  inline void clear_has_operation();
+  inline void set_has_axis();
+  inline void clear_has_axis();
+  inline void set_has_coeff();
+  inline void clear_has_coeff();
+
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  ::google::protobuf::internal::HasBits<1> _has_bits_;
+  mutable int _cached_size_;
+  ::google::protobuf::int32 axis_;
+  int operation_;
+  float coeff_;
+  friend void  protobuf_InitDefaults_caffe_2eproto_impl();
+  friend void  protobuf_AddDesc_caffe_2eproto_impl();
+  friend void protobuf_AssignDesc_caffe_2eproto();
+  friend void protobuf_ShutdownFile_caffe_2eproto();
+
+  void InitAsDefaultInstance();
+};
+extern ::google::protobuf::internal::ExplicitlyConstructed<ReductionParameter> ReductionParameter_default_instance_;
+
+// -------------------------------------------------------------------
+
+class ReLUParameter : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:caffe.ReLUParameter) */ {
+ public:
+  ReLUParameter();
+  virtual ~ReLUParameter();
+
+  ReLUParameter(const ReLUParameter& from);
+
+  inline ReLUParameter& operator=(const ReLUParameter& from) {
+    CopyFrom(from);
+    return *this;
+  }
+
+  inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields();
+  }
+
+  inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields();
+  }
+
+  static const ::google::protobuf::Descriptor* descriptor();
+  static const ReLUParameter& default_instance();
+
+  static const ReLUParameter* internal_default_instance();
+
+  void Swap(ReLUParameter* other);
+
+  // implements Message ----------------------------------------------
+
+  inline ReLUParameter* New() const { return New(NULL); }
+
+  ReLUParameter* New(::google::protobuf::Arena* arena) const;
+  void CopyFrom(const ::google::protobuf::Message& from);
+  void MergeFrom(const ::google::protobuf::Message& from);
+  void CopyFrom(const ReLUParameter& from);
+  void MergeFrom(const ReLUParameter& from);
+  void Clear();
+  bool IsInitialized() const;
+
+  size_t ByteSizeLong() const;
+  bool MergePartialFromCodedStream(
+      ::google::protobuf::io::CodedInputStream* input);
+  void SerializeWithCachedSizes(
+      ::google::protobuf::io::CodedOutputStream* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
+  int GetCachedSize() const { return _cached_size_; }
+  private:
+  void SharedCtor();
+  void SharedDtor();
+  void SetCachedSize(int size) const;
+  void InternalSwap(ReLUParameter* other);
+  void UnsafeMergeFrom(const ReLUParameter& from);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
+  public:
+
+  ::google::protobuf::Metadata GetMetadata() const;
+
+  // nested types ----------------------------------------------------
+
+  typedef ReLUParameter_Engine Engine;
+  static const Engine DEFAULT =
+    ReLUParameter_Engine_DEFAULT;
+  static const Engine CAFFE =
+    ReLUParameter_Engine_CAFFE;
+  static const Engine CUDNN =
+    ReLUParameter_Engine_CUDNN;
+  static inline bool Engine_IsValid(int value) {
+    return ReLUParameter_Engine_IsValid(value);
+  }
+  static const Engine Engine_MIN =
+    ReLUParameter_Engine_Engine_MIN;
+  static const Engine Engine_MAX =
+    ReLUParameter_Engine_Engine_MAX;
+  static const int Engine_ARRAYSIZE =
+    ReLUParameter_Engine_Engine_ARRAYSIZE;
+  static inline const ::google::protobuf::EnumDescriptor*
+  Engine_descriptor() {
+    return ReLUParameter_Engine_descriptor();
+  }
+  static inline const ::std::string& Engine_Name(Engine value) {
+    return ReLUParameter_Engine_Name(value);
+  }
+  static inline bool Engine_Parse(const ::std::string& name,
+      Engine* value) {
+    return ReLUParameter_Engine_Parse(name, value);
+  }
+
+  // accessors -------------------------------------------------------
+
+  // optional float negative_slope = 1 [default = 0];
+  bool has_negative_slope() const;
+  void clear_negative_slope();
+  static const int kNegativeSlopeFieldNumber = 1;
+  float negative_slope() const;
+  void set_negative_slope(float value);
+
+  // optional .caffe.ReLUParameter.Engine engine = 2 [default = DEFAULT];
+  bool has_engine() const;
+  void clear_engine();
+  static const int kEngineFieldNumber = 2;
+  ::caffe::ReLUParameter_Engine engine() const;
+  void set_engine(::caffe::ReLUParameter_Engine value);
+
+  // @@protoc_insertion_point(class_scope:caffe.ReLUParameter)
+ private:
+  inline void set_has_negative_slope();
+  inline void clear_has_negative_slope();
+  inline void set_has_engine();
+  inline void clear_has_engine();
+
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  ::google::protobuf::internal::HasBits<1> _has_bits_;
+  mutable int _cached_size_;
+  float negative_slope_;
+  int engine_;
+  friend void  protobuf_InitDefaults_caffe_2eproto_impl();
+  friend void  protobuf_AddDesc_caffe_2eproto_impl();
+  friend void protobuf_AssignDesc_caffe_2eproto();
+  friend void protobuf_ShutdownFile_caffe_2eproto();
+
+  void InitAsDefaultInstance();
+};
+extern ::google::protobuf::internal::ExplicitlyConstructed<ReLUParameter> ReLUParameter_default_instance_;
+
+// -------------------------------------------------------------------
+
+class ReshapeParameter : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:caffe.ReshapeParameter) */ {
+ public:
+  ReshapeParameter();
+  virtual ~ReshapeParameter();
+
+  ReshapeParameter(const ReshapeParameter& from);
+
+  inline ReshapeParameter& operator=(const ReshapeParameter& from) {
+    CopyFrom(from);
+    return *this;
+  }
+
+  inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields();
+  }
+
+  inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields();
+  }
+
+  static const ::google::protobuf::Descriptor* descriptor();
+  static const ReshapeParameter& default_instance();
+
+  static const ReshapeParameter* internal_default_instance();
+
+  void Swap(ReshapeParameter* other);
+
+  // implements Message ----------------------------------------------
+
+  inline ReshapeParameter* New() const { return New(NULL); }
+
+  ReshapeParameter* New(::google::protobuf::Arena* arena) const;
+  void CopyFrom(const ::google::protobuf::Message& from);
+  void MergeFrom(const ::google::protobuf::Message& from);
+  void CopyFrom(const ReshapeParameter& from);
+  void MergeFrom(const ReshapeParameter& from);
+  void Clear();
+  bool IsInitialized() const;
+
+  size_t ByteSizeLong() const;
+  bool MergePartialFromCodedStream(
+      ::google::protobuf::io::CodedInputStream* input);
+  void SerializeWithCachedSizes(
+      ::google::protobuf::io::CodedOutputStream* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
+  int GetCachedSize() const { return _cached_size_; }
+  private:
+  void SharedCtor();
+  void SharedDtor();
+  void SetCachedSize(int size) const;
+  void InternalSwap(ReshapeParameter* other);
+  void UnsafeMergeFrom(const ReshapeParameter& from);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
+  public:
+
+  ::google::protobuf::Metadata GetMetadata() const;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  // optional .caffe.BlobShape shape = 1;
+  bool has_shape() const;
+  void clear_shape();
+  static const int kShapeFieldNumber = 1;
+  const ::caffe::BlobShape& shape() const;
+  ::caffe::BlobShape* mutable_shape();
+  ::caffe::BlobShape* release_shape();
+  void set_allocated_shape(::caffe::BlobShape* shape);
+
+  // optional int32 axis = 2 [default = 0];
+  bool has_axis() const;
+  void clear_axis();
+  static const int kAxisFieldNumber = 2;
+  ::google::protobuf::int32 axis() const;
+  void set_axis(::google::protobuf::int32 value);
+
+  // optional int32 num_axes = 3 [default = -1];
+  bool has_num_axes() const;
+  void clear_num_axes();
+  static const int kNumAxesFieldNumber = 3;
+  ::google::protobuf::int32 num_axes() const;
+  void set_num_axes(::google::protobuf::int32 value);
+
+  // @@protoc_insertion_point(class_scope:caffe.ReshapeParameter)
+ private:
+  inline void set_has_shape();
+  inline void clear_has_shape();
+  inline void set_has_axis();
+  inline void clear_has_axis();
+  inline void set_has_num_axes();
+  inline void clear_has_num_axes();
+
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  ::google::protobuf::internal::HasBits<1> _has_bits_;
+  mutable int _cached_size_;
+  ::caffe::BlobShape* shape_;
+  ::google::protobuf::int32 axis_;
+  ::google::protobuf::int32 num_axes_;
+  friend void  protobuf_InitDefaults_caffe_2eproto_impl();
+  friend void  protobuf_AddDesc_caffe_2eproto_impl();
+  friend void protobuf_AssignDesc_caffe_2eproto();
+  friend void protobuf_ShutdownFile_caffe_2eproto();
+
+  void InitAsDefaultInstance();
+};
+extern ::google::protobuf::internal::ExplicitlyConstructed<ReshapeParameter> ReshapeParameter_default_instance_;
+
+// -------------------------------------------------------------------
+
+class SigmoidParameter : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:caffe.SigmoidParameter) */ {
+ public:
+  SigmoidParameter();
+  virtual ~SigmoidParameter();
+
+  SigmoidParameter(const SigmoidParameter& from);
+
+  inline SigmoidParameter& operator=(const SigmoidParameter& from) {
+    CopyFrom(from);
+    return *this;
+  }
+
+  inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields();
+  }
+
+  inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields();
+  }
+
+  static const ::google::protobuf::Descriptor* descriptor();
+  static const SigmoidParameter& default_instance();
+
+  static const SigmoidParameter* internal_default_instance();
+
+  void Swap(SigmoidParameter* other);
+
+  // implements Message ----------------------------------------------
+
+  inline SigmoidParameter* New() const { return New(NULL); }
+
+  SigmoidParameter* New(::google::protobuf::Arena* arena) const;
+  void CopyFrom(const ::google::protobuf::Message& from);
+  void MergeFrom(const ::google::protobuf::Message& from);
+  void CopyFrom(const SigmoidParameter& from);
+  void MergeFrom(const SigmoidParameter& from);
+  void Clear();
+  bool IsInitialized() const;
+
+  size_t ByteSizeLong() const;
+  bool MergePartialFromCodedStream(
+      ::google::protobuf::io::CodedInputStream* input);
+  void SerializeWithCachedSizes(
+      ::google::protobuf::io::CodedOutputStream* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
+  int GetCachedSize() const { return _cached_size_; }
+  private:
+  void SharedCtor();
+  void SharedDtor();
+  void SetCachedSize(int size) const;
+  void InternalSwap(SigmoidParameter* other);
+  void UnsafeMergeFrom(const SigmoidParameter& from);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
+  public:
+
+  ::google::protobuf::Metadata GetMetadata() const;
+
+  // nested types ----------------------------------------------------
+
+  typedef SigmoidParameter_Engine Engine;
+  static const Engine DEFAULT =
+    SigmoidParameter_Engine_DEFAULT;
+  static const Engine CAFFE =
+    SigmoidParameter_Engine_CAFFE;
+  static const Engine CUDNN =
+    SigmoidParameter_Engine_CUDNN;
+  static inline bool Engine_IsValid(int value) {
+    return SigmoidParameter_Engine_IsValid(value);
+  }
+  static const Engine Engine_MIN =
+    SigmoidParameter_Engine_Engine_MIN;
+  static const Engine Engine_MAX =
+    SigmoidParameter_Engine_Engine_MAX;
+  static const int Engine_ARRAYSIZE =
+    SigmoidParameter_Engine_Engine_ARRAYSIZE;
+  static inline const ::google::protobuf::EnumDescriptor*
+  Engine_descriptor() {
+    return SigmoidParameter_Engine_descriptor();
+  }
+  static inline const ::std::string& Engine_Name(Engine value) {
+    return SigmoidParameter_Engine_Name(value);
+  }
+  static inline bool Engine_Parse(const ::std::string& name,
+      Engine* value) {
+    return SigmoidParameter_Engine_Parse(name, value);
+  }
+
+  // accessors -------------------------------------------------------
+
+  // optional .caffe.SigmoidParameter.Engine engine = 1 [default = DEFAULT];
+  bool has_engine() const;
+  void clear_engine();
+  static const int kEngineFieldNumber = 1;
+  ::caffe::SigmoidParameter_Engine engine() const;
+  void set_engine(::caffe::SigmoidParameter_Engine value);
+
+  // @@protoc_insertion_point(class_scope:caffe.SigmoidParameter)
+ private:
+  inline void set_has_engine();
+  inline void clear_has_engine();
+
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  ::google::protobuf::internal::HasBits<1> _has_bits_;
+  mutable int _cached_size_;
+  int engine_;
+  friend void  protobuf_InitDefaults_caffe_2eproto_impl();
+  friend void  protobuf_AddDesc_caffe_2eproto_impl();
+  friend void protobuf_AssignDesc_caffe_2eproto();
+  friend void protobuf_ShutdownFile_caffe_2eproto();
+
+  void InitAsDefaultInstance();
+};
+extern ::google::protobuf::internal::ExplicitlyConstructed<SigmoidParameter> SigmoidParameter_default_instance_;
+
+// -------------------------------------------------------------------
+
+class SliceParameter : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:caffe.SliceParameter) */ {
+ public:
+  SliceParameter();
+  virtual ~SliceParameter();
+
+  SliceParameter(const SliceParameter& from);
+
+  inline SliceParameter& operator=(const SliceParameter& from) {
+    CopyFrom(from);
+    return *this;
+  }
+
+  inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields();
+  }
+
+  inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields();
+  }
+
+  static const ::google::protobuf::Descriptor* descriptor();
+  static const SliceParameter& default_instance();
+
+  static const SliceParameter* internal_default_instance();
+
+  void Swap(SliceParameter* other);
+
+  // implements Message ----------------------------------------------
+
+  inline SliceParameter* New() const { return New(NULL); }
+
+  SliceParameter* New(::google::protobuf::Arena* arena) const;
+  void CopyFrom(const ::google::protobuf::Message& from);
+  void MergeFrom(const ::google::protobuf::Message& from);
+  void CopyFrom(const SliceParameter& from);
+  void MergeFrom(const SliceParameter& from);
+  void Clear();
+  bool IsInitialized() const;
+
+  size_t ByteSizeLong() const;
+  bool MergePartialFromCodedStream(
+      ::google::protobuf::io::CodedInputStream* input);
+  void SerializeWithCachedSizes(
+      ::google::protobuf::io::CodedOutputStream* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
+  int GetCachedSize() const { return _cached_size_; }
+  private:
+  void SharedCtor();
+  void SharedDtor();
+  void SetCachedSize(int size) const;
+  void InternalSwap(SliceParameter* other);
+  void UnsafeMergeFrom(const SliceParameter& from);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
+  public:
+
+  ::google::protobuf::Metadata GetMetadata() const;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  // optional int32 axis = 3 [default = 1];
+  bool has_axis() const;
+  void clear_axis();
+  static const int kAxisFieldNumber = 3;
+  ::google::protobuf::int32 axis() const;
+  void set_axis(::google::protobuf::int32 value);
+
+  // repeated uint32 slice_point = 2;
+  int slice_point_size() const;
+  void clear_slice_point();
+  static const int kSlicePointFieldNumber = 2;
+  ::google::protobuf::uint32 slice_point(int index) const;
+  void set_slice_point(int index, ::google::protobuf::uint32 value);
+  void add_slice_point(::google::protobuf::uint32 value);
+  const ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >&
+      slice_point() const;
+  ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >*
+      mutable_slice_point();
+
+  // optional uint32 slice_dim = 1 [default = 1];
+  bool has_slice_dim() const;
+  void clear_slice_dim();
+  static const int kSliceDimFieldNumber = 1;
+  ::google::protobuf::uint32 slice_dim() const;
+  void set_slice_dim(::google::protobuf::uint32 value);
+
+  // @@protoc_insertion_point(class_scope:caffe.SliceParameter)
+ private:
+  inline void set_has_axis();
+  inline void clear_has_axis();
+  inline void set_has_slice_dim();
+  inline void clear_has_slice_dim();
+
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  ::google::protobuf::internal::HasBits<1> _has_bits_;
+  mutable int _cached_size_;
+  ::google::protobuf::RepeatedField< ::google::protobuf::uint32 > slice_point_;
+  ::google::protobuf::int32 axis_;
+  ::google::protobuf::uint32 slice_dim_;
+  friend void  protobuf_InitDefaults_caffe_2eproto_impl();
+  friend void  protobuf_AddDesc_caffe_2eproto_impl();
+  friend void protobuf_AssignDesc_caffe_2eproto();
+  friend void protobuf_ShutdownFile_caffe_2eproto();
+
+  void InitAsDefaultInstance();
+};
+extern ::google::protobuf::internal::ExplicitlyConstructed<SliceParameter> SliceParameter_default_instance_;
+
+// -------------------------------------------------------------------
+
+class SoftmaxParameter : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:caffe.SoftmaxParameter) */ {
+ public:
+  SoftmaxParameter();
+  virtual ~SoftmaxParameter();
+
+  SoftmaxParameter(const SoftmaxParameter& from);
+
+  inline SoftmaxParameter& operator=(const SoftmaxParameter& from) {
+    CopyFrom(from);
+    return *this;
+  }
+
+  inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields();
+  }
+
+  inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields();
+  }
+
+  static const ::google::protobuf::Descriptor* descriptor();
+  static const SoftmaxParameter& default_instance();
+
+  static const SoftmaxParameter* internal_default_instance();
+
+  void Swap(SoftmaxParameter* other);
+
+  // implements Message ----------------------------------------------
+
+  inline SoftmaxParameter* New() const { return New(NULL); }
+
+  SoftmaxParameter* New(::google::protobuf::Arena* arena) const;
+  void CopyFrom(const ::google::protobuf::Message& from);
+  void MergeFrom(const ::google::protobuf::Message& from);
+  void CopyFrom(const SoftmaxParameter& from);
+  void MergeFrom(const SoftmaxParameter& from);
+  void Clear();
+  bool IsInitialized() const;
+
+  size_t ByteSizeLong() const;
+  bool MergePartialFromCodedStream(
+      ::google::protobuf::io::CodedInputStream* input);
+  void SerializeWithCachedSizes(
+      ::google::protobuf::io::CodedOutputStream* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
+  int GetCachedSize() const { return _cached_size_; }
+  private:
+  void SharedCtor();
+  void SharedDtor();
+  void SetCachedSize(int size) const;
+  void InternalSwap(SoftmaxParameter* other);
+  void UnsafeMergeFrom(const SoftmaxParameter& from);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
+  public:
+
+  ::google::protobuf::Metadata GetMetadata() const;
+
+  // nested types ----------------------------------------------------
+
+  typedef SoftmaxParameter_Engine Engine;
+  static const Engine DEFAULT =
+    SoftmaxParameter_Engine_DEFAULT;
+  static const Engine CAFFE =
+    SoftmaxParameter_Engine_CAFFE;
+  static const Engine CUDNN =
+    SoftmaxParameter_Engine_CUDNN;
+  static inline bool Engine_IsValid(int value) {
+    return SoftmaxParameter_Engine_IsValid(value);
+  }
+  static const Engine Engine_MIN =
+    SoftmaxParameter_Engine_Engine_MIN;
+  static const Engine Engine_MAX =
+    SoftmaxParameter_Engine_Engine_MAX;
+  static const int Engine_ARRAYSIZE =
+    SoftmaxParameter_Engine_Engine_ARRAYSIZE;
+  static inline const ::google::protobuf::EnumDescriptor*
+  Engine_descriptor() {
+    return SoftmaxParameter_Engine_descriptor();
+  }
+  static inline const ::std::string& Engine_Name(Engine value) {
+    return SoftmaxParameter_Engine_Name(value);
+  }
+  static inline bool Engine_Parse(const ::std::string& name,
+      Engine* value) {
+    return SoftmaxParameter_Engine_Parse(name, value);
+  }
+
+  // accessors -------------------------------------------------------
+
+  // optional .caffe.SoftmaxParameter.Engine engine = 1 [default = DEFAULT];
+  bool has_engine() const;
+  void clear_engine();
+  static const int kEngineFieldNumber = 1;
+  ::caffe::SoftmaxParameter_Engine engine() const;
+  void set_engine(::caffe::SoftmaxParameter_Engine value);
+
+  // optional int32 axis = 2 [default = 1];
+  bool has_axis() const;
+  void clear_axis();
+  static const int kAxisFieldNumber = 2;
+  ::google::protobuf::int32 axis() const;
+  void set_axis(::google::protobuf::int32 value);
+
+  // @@protoc_insertion_point(class_scope:caffe.SoftmaxParameter)
+ private:
+  inline void set_has_engine();
+  inline void clear_has_engine();
+  inline void set_has_axis();
+  inline void clear_has_axis();
+
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  ::google::protobuf::internal::HasBits<1> _has_bits_;
+  mutable int _cached_size_;
+  int engine_;
+  ::google::protobuf::int32 axis_;
+  friend void  protobuf_InitDefaults_caffe_2eproto_impl();
+  friend void  protobuf_AddDesc_caffe_2eproto_impl();
+  friend void protobuf_AssignDesc_caffe_2eproto();
+  friend void protobuf_ShutdownFile_caffe_2eproto();
+
+  void InitAsDefaultInstance();
+};
+extern ::google::protobuf::internal::ExplicitlyConstructed<SoftmaxParameter> SoftmaxParameter_default_instance_;
+
+// -------------------------------------------------------------------
+
+class TanHParameter : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:caffe.TanHParameter) */ {
+ public:
+  TanHParameter();
+  virtual ~TanHParameter();
+
+  TanHParameter(const TanHParameter& from);
+
+  inline TanHParameter& operator=(const TanHParameter& from) {
+    CopyFrom(from);
+    return *this;
+  }
+
+  inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields();
+  }
+
+  inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields();
+  }
+
+  static const ::google::protobuf::Descriptor* descriptor();
+  static const TanHParameter& default_instance();
+
+  static const TanHParameter* internal_default_instance();
+
+  void Swap(TanHParameter* other);
+
+  // implements Message ----------------------------------------------
+
+  inline TanHParameter* New() const { return New(NULL); }
+
+  TanHParameter* New(::google::protobuf::Arena* arena) const;
+  void CopyFrom(const ::google::protobuf::Message& from);
+  void MergeFrom(const ::google::protobuf::Message& from);
+  void CopyFrom(const TanHParameter& from);
+  void MergeFrom(const TanHParameter& from);
+  void Clear();
+  bool IsInitialized() const;
+
+  size_t ByteSizeLong() const;
+  bool MergePartialFromCodedStream(
+      ::google::protobuf::io::CodedInputStream* input);
+  void SerializeWithCachedSizes(
+      ::google::protobuf::io::CodedOutputStream* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
+  int GetCachedSize() const { return _cached_size_; }
+  private:
+  void SharedCtor();
+  void SharedDtor();
+  void SetCachedSize(int size) const;
+  void InternalSwap(TanHParameter* other);
+  void UnsafeMergeFrom(const TanHParameter& from);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
+  public:
+
+  ::google::protobuf::Metadata GetMetadata() const;
+
+  // nested types ----------------------------------------------------
+
+  typedef TanHParameter_Engine Engine;
+  static const Engine DEFAULT =
+    TanHParameter_Engine_DEFAULT;
+  static const Engine CAFFE =
+    TanHParameter_Engine_CAFFE;
+  static const Engine CUDNN =
+    TanHParameter_Engine_CUDNN;
+  static inline bool Engine_IsValid(int value) {
+    return TanHParameter_Engine_IsValid(value);
+  }
+  static const Engine Engine_MIN =
+    TanHParameter_Engine_Engine_MIN;
+  static const Engine Engine_MAX =
+    TanHParameter_Engine_Engine_MAX;
+  static const int Engine_ARRAYSIZE =
+    TanHParameter_Engine_Engine_ARRAYSIZE;
+  static inline const ::google::protobuf::EnumDescriptor*
+  Engine_descriptor() {
+    return TanHParameter_Engine_descriptor();
+  }
+  static inline const ::std::string& Engine_Name(Engine value) {
+    return TanHParameter_Engine_Name(value);
+  }
+  static inline bool Engine_Parse(const ::std::string& name,
+      Engine* value) {
+    return TanHParameter_Engine_Parse(name, value);
+  }
+
+  // accessors -------------------------------------------------------
+
+  // optional .caffe.TanHParameter.Engine engine = 1 [default = DEFAULT];
+  bool has_engine() const;
+  void clear_engine();
+  static const int kEngineFieldNumber = 1;
+  ::caffe::TanHParameter_Engine engine() const;
+  void set_engine(::caffe::TanHParameter_Engine value);
+
+  // @@protoc_insertion_point(class_scope:caffe.TanHParameter)
+ private:
+  inline void set_has_engine();
+  inline void clear_has_engine();
+
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  ::google::protobuf::internal::HasBits<1> _has_bits_;
+  mutable int _cached_size_;
+  int engine_;
+  friend void  protobuf_InitDefaults_caffe_2eproto_impl();
+  friend void  protobuf_AddDesc_caffe_2eproto_impl();
+  friend void protobuf_AssignDesc_caffe_2eproto();
+  friend void protobuf_ShutdownFile_caffe_2eproto();
+
+  void InitAsDefaultInstance();
+};
+extern ::google::protobuf::internal::ExplicitlyConstructed<TanHParameter> TanHParameter_default_instance_;
+
+// -------------------------------------------------------------------
+
+class ThresholdParameter : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:caffe.ThresholdParameter) */ {
+ public:
+  ThresholdParameter();
+  virtual ~ThresholdParameter();
+
+  ThresholdParameter(const ThresholdParameter& from);
+
+  inline ThresholdParameter& operator=(const ThresholdParameter& from) {
+    CopyFrom(from);
+    return *this;
+  }
+
+  inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields();
+  }
+
+  inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields();
+  }
+
+  static const ::google::protobuf::Descriptor* descriptor();
+  static const ThresholdParameter& default_instance();
+
+  static const ThresholdParameter* internal_default_instance();
+
+  void Swap(ThresholdParameter* other);
+
+  // implements Message ----------------------------------------------
+
+  inline ThresholdParameter* New() const { return New(NULL); }
+
+  ThresholdParameter* New(::google::protobuf::Arena* arena) const;
+  void CopyFrom(const ::google::protobuf::Message& from);
+  void MergeFrom(const ::google::protobuf::Message& from);
+  void CopyFrom(const ThresholdParameter& from);
+  void MergeFrom(const ThresholdParameter& from);
+  void Clear();
+  bool IsInitialized() const;
+
+  size_t ByteSizeLong() const;
+  bool MergePartialFromCodedStream(
+      ::google::protobuf::io::CodedInputStream* input);
+  void SerializeWithCachedSizes(
+      ::google::protobuf::io::CodedOutputStream* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
+  int GetCachedSize() const { return _cached_size_; }
+  private:
+  void SharedCtor();
+  void SharedDtor();
+  void SetCachedSize(int size) const;
+  void InternalSwap(ThresholdParameter* other);
+  void UnsafeMergeFrom(const ThresholdParameter& from);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
+  public:
+
+  ::google::protobuf::Metadata GetMetadata() const;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  // optional float threshold = 1 [default = 0];
+  bool has_threshold() const;
+  void clear_threshold();
+  static const int kThresholdFieldNumber = 1;
+  float threshold() const;
+  void set_threshold(float value);
+
+  // @@protoc_insertion_point(class_scope:caffe.ThresholdParameter)
+ private:
+  inline void set_has_threshold();
+  inline void clear_has_threshold();
+
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  ::google::protobuf::internal::HasBits<1> _has_bits_;
+  mutable int _cached_size_;
+  float threshold_;
+  friend void  protobuf_InitDefaults_caffe_2eproto_impl();
+  friend void  protobuf_AddDesc_caffe_2eproto_impl();
+  friend void protobuf_AssignDesc_caffe_2eproto();
+  friend void protobuf_ShutdownFile_caffe_2eproto();
+
+  void InitAsDefaultInstance();
+};
+extern ::google::protobuf::internal::ExplicitlyConstructed<ThresholdParameter> ThresholdParameter_default_instance_;
+
+// -------------------------------------------------------------------
+
+class WindowDataParameter : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:caffe.WindowDataParameter) */ {
+ public:
+  WindowDataParameter();
+  virtual ~WindowDataParameter();
+
+  WindowDataParameter(const WindowDataParameter& from);
+
+  inline WindowDataParameter& operator=(const WindowDataParameter& from) {
+    CopyFrom(from);
+    return *this;
+  }
+
+  inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields();
+  }
+
+  inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields();
+  }
+
+  static const ::google::protobuf::Descriptor* descriptor();
+  static const WindowDataParameter& default_instance();
+
+  static const WindowDataParameter* internal_default_instance();
+
+  void Swap(WindowDataParameter* other);
+
+  // implements Message ----------------------------------------------
+
+  inline WindowDataParameter* New() const { return New(NULL); }
+
+  WindowDataParameter* New(::google::protobuf::Arena* arena) const;
+  void CopyFrom(const ::google::protobuf::Message& from);
+  void MergeFrom(const ::google::protobuf::Message& from);
+  void CopyFrom(const WindowDataParameter& from);
+  void MergeFrom(const WindowDataParameter& from);
+  void Clear();
+  bool IsInitialized() const;
+
+  size_t ByteSizeLong() const;
+  bool MergePartialFromCodedStream(
+      ::google::protobuf::io::CodedInputStream* input);
+  void SerializeWithCachedSizes(
+      ::google::protobuf::io::CodedOutputStream* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
+  int GetCachedSize() const { return _cached_size_; }
+  private:
+  void SharedCtor();
+  void SharedDtor();
+  void SetCachedSize(int size) const;
+  void InternalSwap(WindowDataParameter* other);
+  void UnsafeMergeFrom(const WindowDataParameter& from);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
+  public:
+
+  ::google::protobuf::Metadata GetMetadata() const;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  // optional string source = 1;
+  bool has_source() const;
+  void clear_source();
+  static const int kSourceFieldNumber = 1;
+  const ::std::string& source() const;
+  void set_source(const ::std::string& value);
+  void set_source(const char* value);
+  void set_source(const char* value, size_t size);
+  ::std::string* mutable_source();
+  ::std::string* release_source();
+  void set_allocated_source(::std::string* source);
+
+  // optional float scale = 2 [default = 1];
+  bool has_scale() const;
+  void clear_scale();
+  static const int kScaleFieldNumber = 2;
+  float scale() const;
+  void set_scale(float value);
+
+  // optional string mean_file = 3;
+  bool has_mean_file() const;
+  void clear_mean_file();
+  static const int kMeanFileFieldNumber = 3;
+  const ::std::string& mean_file() const;
+  void set_mean_file(const ::std::string& value);
+  void set_mean_file(const char* value);
+  void set_mean_file(const char* value, size_t size);
+  ::std::string* mutable_mean_file();
+  ::std::string* release_mean_file();
+  void set_allocated_mean_file(::std::string* mean_file);
+
+  // optional uint32 batch_size = 4;
+  bool has_batch_size() const;
+  void clear_batch_size();
+  static const int kBatchSizeFieldNumber = 4;
+  ::google::protobuf::uint32 batch_size() const;
+  void set_batch_size(::google::protobuf::uint32 value);
+
+  // optional uint32 crop_size = 5 [default = 0];
+  bool has_crop_size() const;
+  void clear_crop_size();
+  static const int kCropSizeFieldNumber = 5;
+  ::google::protobuf::uint32 crop_size() const;
+  void set_crop_size(::google::protobuf::uint32 value);
+
+  // optional bool mirror = 6 [default = false];
+  bool has_mirror() const;
+  void clear_mirror();
+  static const int kMirrorFieldNumber = 6;
+  bool mirror() const;
+  void set_mirror(bool value);
+
+  // optional float fg_threshold = 7 [default = 0.5];
+  bool has_fg_threshold() const;
+  void clear_fg_threshold();
+  static const int kFgThresholdFieldNumber = 7;
+  float fg_threshold() const;
+  void set_fg_threshold(float value);
+
+  // optional float bg_threshold = 8 [default = 0.5];
+  bool has_bg_threshold() const;
+  void clear_bg_threshold();
+  static const int kBgThresholdFieldNumber = 8;
+  float bg_threshold() const;
+  void set_bg_threshold(float value);
+
+  // optional float fg_fraction = 9 [default = 0.25];
+  bool has_fg_fraction() const;
+  void clear_fg_fraction();
+  static const int kFgFractionFieldNumber = 9;
+  float fg_fraction() const;
+  void set_fg_fraction(float value);
+
+  // optional uint32 context_pad = 10 [default = 0];
+  bool has_context_pad() const;
+  void clear_context_pad();
+  static const int kContextPadFieldNumber = 10;
+  ::google::protobuf::uint32 context_pad() const;
+  void set_context_pad(::google::protobuf::uint32 value);
+
+  // optional string crop_mode = 11 [default = "warp"];
+  bool has_crop_mode() const;
+  void clear_crop_mode();
+  static const int kCropModeFieldNumber = 11;
+  const ::std::string& crop_mode() const;
+  void set_crop_mode(const ::std::string& value);
+  void set_crop_mode(const char* value);
+  void set_crop_mode(const char* value, size_t size);
+  ::std::string* mutable_crop_mode();
+  ::std::string* release_crop_mode();
+  void set_allocated_crop_mode(::std::string* crop_mode);
+
+  // optional bool cache_images = 12 [default = false];
+  bool has_cache_images() const;
+  void clear_cache_images();
+  static const int kCacheImagesFieldNumber = 12;
+  bool cache_images() const;
+  void set_cache_images(bool value);
+
+  // optional string root_folder = 13 [default = ""];
+  bool has_root_folder() const;
+  void clear_root_folder();
+  static const int kRootFolderFieldNumber = 13;
+  const ::std::string& root_folder() const;
+  void set_root_folder(const ::std::string& value);
+  void set_root_folder(const char* value);
+  void set_root_folder(const char* value, size_t size);
+  ::std::string* mutable_root_folder();
+  ::std::string* release_root_folder();
+  void set_allocated_root_folder(::std::string* root_folder);
+
+  // @@protoc_insertion_point(class_scope:caffe.WindowDataParameter)
+ private:
+  inline void set_has_source();
+  inline void clear_has_source();
+  inline void set_has_scale();
+  inline void clear_has_scale();
+  inline void set_has_mean_file();
+  inline void clear_has_mean_file();
+  inline void set_has_batch_size();
+  inline void clear_has_batch_size();
+  inline void set_has_crop_size();
+  inline void clear_has_crop_size();
+  inline void set_has_mirror();
+  inline void clear_has_mirror();
+  inline void set_has_fg_threshold();
+  inline void clear_has_fg_threshold();
+  inline void set_has_bg_threshold();
+  inline void clear_has_bg_threshold();
+  inline void set_has_fg_fraction();
+  inline void clear_has_fg_fraction();
+  inline void set_has_context_pad();
+  inline void clear_has_context_pad();
+  inline void set_has_crop_mode();
+  inline void clear_has_crop_mode();
+  inline void set_has_cache_images();
+  inline void clear_has_cache_images();
+  inline void set_has_root_folder();
+  inline void clear_has_root_folder();
+
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  ::google::protobuf::internal::HasBits<1> _has_bits_;
+  mutable int _cached_size_;
+  ::google::protobuf::internal::ArenaStringPtr source_;
+  ::google::protobuf::internal::ArenaStringPtr mean_file_;
+  static ::std::string* _default_crop_mode_;
+  ::google::protobuf::internal::ArenaStringPtr crop_mode_;
+  ::google::protobuf::internal::ArenaStringPtr root_folder_;
+  ::google::protobuf::uint32 batch_size_;
+  ::google::protobuf::uint32 crop_size_;
+  bool mirror_;
+  bool cache_images_;
+  ::google::protobuf::uint32 context_pad_;
+  float scale_;
+  float fg_threshold_;
+  float bg_threshold_;
+  float fg_fraction_;
+  friend void  protobuf_InitDefaults_caffe_2eproto_impl();
+  friend void  protobuf_AddDesc_caffe_2eproto_impl();
+  friend void protobuf_AssignDesc_caffe_2eproto();
+  friend void protobuf_ShutdownFile_caffe_2eproto();
+
+  void InitAsDefaultInstance();
+};
+extern ::google::protobuf::internal::ExplicitlyConstructed<WindowDataParameter> WindowDataParameter_default_instance_;
+
+// -------------------------------------------------------------------
+
+class SPPParameter : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:caffe.SPPParameter) */ {
+ public:
+  SPPParameter();
+  virtual ~SPPParameter();
+
+  SPPParameter(const SPPParameter& from);
+
+  inline SPPParameter& operator=(const SPPParameter& from) {
+    CopyFrom(from);
+    return *this;
+  }
+
+  inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields();
+  }
+
+  inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields();
+  }
+
+  static const ::google::protobuf::Descriptor* descriptor();
+  static const SPPParameter& default_instance();
+
+  static const SPPParameter* internal_default_instance();
+
+  void Swap(SPPParameter* other);
+
+  // implements Message ----------------------------------------------
+
+  inline SPPParameter* New() const { return New(NULL); }
+
+  SPPParameter* New(::google::protobuf::Arena* arena) const;
+  void CopyFrom(const ::google::protobuf::Message& from);
+  void MergeFrom(const ::google::protobuf::Message& from);
+  void CopyFrom(const SPPParameter& from);
+  void MergeFrom(const SPPParameter& from);
+  void Clear();
+  bool IsInitialized() const;
+
+  size_t ByteSizeLong() const;
+  bool MergePartialFromCodedStream(
+      ::google::protobuf::io::CodedInputStream* input);
+  void SerializeWithCachedSizes(
+      ::google::protobuf::io::CodedOutputStream* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
+  int GetCachedSize() const { return _cached_size_; }
+  private:
+  void SharedCtor();
+  void SharedDtor();
+  void SetCachedSize(int size) const;
+  void InternalSwap(SPPParameter* other);
+  void UnsafeMergeFrom(const SPPParameter& from);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
+  public:
+
+  ::google::protobuf::Metadata GetMetadata() const;
+
+  // nested types ----------------------------------------------------
+
+  typedef SPPParameter_PoolMethod PoolMethod;
+  static const PoolMethod MAX =
+    SPPParameter_PoolMethod_MAX;
+  static const PoolMethod AVE =
+    SPPParameter_PoolMethod_AVE;
+  static const PoolMethod STOCHASTIC =
+    SPPParameter_PoolMethod_STOCHASTIC;
+  static inline bool PoolMethod_IsValid(int value) {
+    return SPPParameter_PoolMethod_IsValid(value);
+  }
+  static const PoolMethod PoolMethod_MIN =
+    SPPParameter_PoolMethod_PoolMethod_MIN;
+  static const PoolMethod PoolMethod_MAX =
+    SPPParameter_PoolMethod_PoolMethod_MAX;
+  static const int PoolMethod_ARRAYSIZE =
+    SPPParameter_PoolMethod_PoolMethod_ARRAYSIZE;
+  static inline const ::google::protobuf::EnumDescriptor*
+  PoolMethod_descriptor() {
+    return SPPParameter_PoolMethod_descriptor();
+  }
+  static inline const ::std::string& PoolMethod_Name(PoolMethod value) {
+    return SPPParameter_PoolMethod_Name(value);
+  }
+  static inline bool PoolMethod_Parse(const ::std::string& name,
+      PoolMethod* value) {
+    return SPPParameter_PoolMethod_Parse(name, value);
+  }
+
+  typedef SPPParameter_Engine Engine;
+  static const Engine DEFAULT =
+    SPPParameter_Engine_DEFAULT;
+  static const Engine CAFFE =
+    SPPParameter_Engine_CAFFE;
+  static const Engine CUDNN =
+    SPPParameter_Engine_CUDNN;
+  static inline bool Engine_IsValid(int value) {
+    return SPPParameter_Engine_IsValid(value);
+  }
+  static const Engine Engine_MIN =
+    SPPParameter_Engine_Engine_MIN;
+  static const Engine Engine_MAX =
+    SPPParameter_Engine_Engine_MAX;
+  static const int Engine_ARRAYSIZE =
+    SPPParameter_Engine_Engine_ARRAYSIZE;
+  static inline const ::google::protobuf::EnumDescriptor*
+  Engine_descriptor() {
+    return SPPParameter_Engine_descriptor();
+  }
+  static inline const ::std::string& Engine_Name(Engine value) {
+    return SPPParameter_Engine_Name(value);
+  }
+  static inline bool Engine_Parse(const ::std::string& name,
+      Engine* value) {
+    return SPPParameter_Engine_Parse(name, value);
+  }
+
+  // accessors -------------------------------------------------------
+
+  // optional uint32 pyramid_height = 1;
+  bool has_pyramid_height() const;
+  void clear_pyramid_height();
+  static const int kPyramidHeightFieldNumber = 1;
+  ::google::protobuf::uint32 pyramid_height() const;
+  void set_pyramid_height(::google::protobuf::uint32 value);
+
+  // optional .caffe.SPPParameter.PoolMethod pool = 2 [default = MAX];
+  bool has_pool() const;
+  void clear_pool();
+  static const int kPoolFieldNumber = 2;
+  ::caffe::SPPParameter_PoolMethod pool() const;
+  void set_pool(::caffe::SPPParameter_PoolMethod value);
+
+  // optional .caffe.SPPParameter.Engine engine = 6 [default = DEFAULT];
+  bool has_engine() const;
+  void clear_engine();
+  static const int kEngineFieldNumber = 6;
+  ::caffe::SPPParameter_Engine engine() const;
+  void set_engine(::caffe::SPPParameter_Engine value);
+
+  // @@protoc_insertion_point(class_scope:caffe.SPPParameter)
+ private:
+  inline void set_has_pyramid_height();
+  inline void clear_has_pyramid_height();
+  inline void set_has_pool();
+  inline void clear_has_pool();
+  inline void set_has_engine();
+  inline void clear_has_engine();
+
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  ::google::protobuf::internal::HasBits<1> _has_bits_;
+  mutable int _cached_size_;
+  ::google::protobuf::uint32 pyramid_height_;
+  int pool_;
+  int engine_;
+  friend void  protobuf_InitDefaults_caffe_2eproto_impl();
+  friend void  protobuf_AddDesc_caffe_2eproto_impl();
+  friend void protobuf_AssignDesc_caffe_2eproto();
+  friend void protobuf_ShutdownFile_caffe_2eproto();
+
+  void InitAsDefaultInstance();
+};
+extern ::google::protobuf::internal::ExplicitlyConstructed<SPPParameter> SPPParameter_default_instance_;
+
+// -------------------------------------------------------------------
+
+class V1LayerParameter : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:caffe.V1LayerParameter) */ {
+ public:
+  V1LayerParameter();
+  virtual ~V1LayerParameter();
+
+  V1LayerParameter(const V1LayerParameter& from);
+
+  inline V1LayerParameter& operator=(const V1LayerParameter& from) {
+    CopyFrom(from);
+    return *this;
+  }
+
+  inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields();
+  }
+
+  inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields();
+  }
+
+  static const ::google::protobuf::Descriptor* descriptor();
+  static const V1LayerParameter& default_instance();
+
+  static const V1LayerParameter* internal_default_instance();
+
+  void Swap(V1LayerParameter* other);
+
+  // implements Message ----------------------------------------------
+
+  inline V1LayerParameter* New() const { return New(NULL); }
+
+  V1LayerParameter* New(::google::protobuf::Arena* arena) const;
+  void CopyFrom(const ::google::protobuf::Message& from);
+  void MergeFrom(const ::google::protobuf::Message& from);
+  void CopyFrom(const V1LayerParameter& from);
+  void MergeFrom(const V1LayerParameter& from);
+  void Clear();
+  bool IsInitialized() const;
+
+  size_t ByteSizeLong() const;
+  bool MergePartialFromCodedStream(
+      ::google::protobuf::io::CodedInputStream* input);
+  void SerializeWithCachedSizes(
+      ::google::protobuf::io::CodedOutputStream* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
+  int GetCachedSize() const { return _cached_size_; }
+  private:
+  void SharedCtor();
+  void SharedDtor();
+  void SetCachedSize(int size) const;
+  void InternalSwap(V1LayerParameter* other);
+  void UnsafeMergeFrom(const V1LayerParameter& from);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
+  public:
+
+  ::google::protobuf::Metadata GetMetadata() const;
+
+  // nested types ----------------------------------------------------
+
+  typedef V1LayerParameter_LayerType LayerType;
+  static const LayerType NONE =
+    V1LayerParameter_LayerType_NONE;
+  static const LayerType ABSVAL =
+    V1LayerParameter_LayerType_ABSVAL;
+  static const LayerType ACCURACY =
+    V1LayerParameter_LayerType_ACCURACY;
+  static const LayerType ARGMAX =
+    V1LayerParameter_LayerType_ARGMAX;
+  static const LayerType BNLL =
+    V1LayerParameter_LayerType_BNLL;
+  static const LayerType CONCAT =
+    V1LayerParameter_LayerType_CONCAT;
+  static const LayerType CONTRASTIVE_LOSS =
+    V1LayerParameter_LayerType_CONTRASTIVE_LOSS;
+  static const LayerType CONVOLUTION =
+    V1LayerParameter_LayerType_CONVOLUTION;
+  static const LayerType DATA =
+    V1LayerParameter_LayerType_DATA;
+  static const LayerType DECONVOLUTION =
+    V1LayerParameter_LayerType_DECONVOLUTION;
+  static const LayerType DROPOUT =
+    V1LayerParameter_LayerType_DROPOUT;
+  static const LayerType DUMMY_DATA =
+    V1LayerParameter_LayerType_DUMMY_DATA;
+  static const LayerType EUCLIDEAN_LOSS =
+    V1LayerParameter_LayerType_EUCLIDEAN_LOSS;
+  static const LayerType ELTWISE =
+    V1LayerParameter_LayerType_ELTWISE;
+  static const LayerType EXP =
+    V1LayerParameter_LayerType_EXP;
+  static const LayerType FLATTEN =
+    V1LayerParameter_LayerType_FLATTEN;
+  static const LayerType HDF5_DATA =
+    V1LayerParameter_LayerType_HDF5_DATA;
+  static const LayerType HDF5_OUTPUT =
+    V1LayerParameter_LayerType_HDF5_OUTPUT;
+  static const LayerType HINGE_LOSS =
+    V1LayerParameter_LayerType_HINGE_LOSS;
+  static const LayerType IM2COL =
+    V1LayerParameter_LayerType_IM2COL;
+  static const LayerType IMAGE_DATA =
+    V1LayerParameter_LayerType_IMAGE_DATA;
+  static const LayerType INFOGAIN_LOSS =
+    V1LayerParameter_LayerType_INFOGAIN_LOSS;
+  static const LayerType INNER_PRODUCT =
+    V1LayerParameter_LayerType_INNER_PRODUCT;
+  static const LayerType LRN =
+    V1LayerParameter_LayerType_LRN;
+  static const LayerType MEMORY_DATA =
+    V1LayerParameter_LayerType_MEMORY_DATA;
+  static const LayerType MULTINOMIAL_LOGISTIC_LOSS =
+    V1LayerParameter_LayerType_MULTINOMIAL_LOGISTIC_LOSS;
+  static const LayerType MVN =
+    V1LayerParameter_LayerType_MVN;
+  static const LayerType POOLING =
+    V1LayerParameter_LayerType_POOLING;
+  static const LayerType POWER =
+    V1LayerParameter_LayerType_POWER;
+  static const LayerType RELU =
+    V1LayerParameter_LayerType_RELU;
+  static const LayerType SIGMOID =
+    V1LayerParameter_LayerType_SIGMOID;
+  static const LayerType SIGMOID_CROSS_ENTROPY_LOSS =
+    V1LayerParameter_LayerType_SIGMOID_CROSS_ENTROPY_LOSS;
+  static const LayerType SILENCE =
+    V1LayerParameter_LayerType_SILENCE;
+  static const LayerType SOFTMAX =
+    V1LayerParameter_LayerType_SOFTMAX;
+  static const LayerType SOFTMAX_LOSS =
+    V1LayerParameter_LayerType_SOFTMAX_LOSS;
+  static const LayerType SPLIT =
+    V1LayerParameter_LayerType_SPLIT;
+  static const LayerType SLICE =
+    V1LayerParameter_LayerType_SLICE;
+  static const LayerType TANH =
+    V1LayerParameter_LayerType_TANH;
+  static const LayerType WINDOW_DATA =
+    V1LayerParameter_LayerType_WINDOW_DATA;
+  static const LayerType THRESHOLD =
+    V1LayerParameter_LayerType_THRESHOLD;
+  static inline bool LayerType_IsValid(int value) {
+    return V1LayerParameter_LayerType_IsValid(value);
+  }
+  static const LayerType LayerType_MIN =
+    V1LayerParameter_LayerType_LayerType_MIN;
+  static const LayerType LayerType_MAX =
+    V1LayerParameter_LayerType_LayerType_MAX;
+  static const int LayerType_ARRAYSIZE =
+    V1LayerParameter_LayerType_LayerType_ARRAYSIZE;
+  static inline const ::google::protobuf::EnumDescriptor*
+  LayerType_descriptor() {
+    return V1LayerParameter_LayerType_descriptor();
+  }
+  static inline const ::std::string& LayerType_Name(LayerType value) {
+    return V1LayerParameter_LayerType_Name(value);
+  }
+  static inline bool LayerType_Parse(const ::std::string& name,
+      LayerType* value) {
+    return V1LayerParameter_LayerType_Parse(name, value);
+  }
+
+  typedef V1LayerParameter_DimCheckMode DimCheckMode;
+  static const DimCheckMode STRICT =
+    V1LayerParameter_DimCheckMode_STRICT;
+  static const DimCheckMode PERMISSIVE =
+    V1LayerParameter_DimCheckMode_PERMISSIVE;
+  static inline bool DimCheckMode_IsValid(int value) {
+    return V1LayerParameter_DimCheckMode_IsValid(value);
+  }
+  static const DimCheckMode DimCheckMode_MIN =
+    V1LayerParameter_DimCheckMode_DimCheckMode_MIN;
+  static const DimCheckMode DimCheckMode_MAX =
+    V1LayerParameter_DimCheckMode_DimCheckMode_MAX;
+  static const int DimCheckMode_ARRAYSIZE =
+    V1LayerParameter_DimCheckMode_DimCheckMode_ARRAYSIZE;
+  static inline const ::google::protobuf::EnumDescriptor*
+  DimCheckMode_descriptor() {
+    return V1LayerParameter_DimCheckMode_descriptor();
+  }
+  static inline const ::std::string& DimCheckMode_Name(DimCheckMode value) {
+    return V1LayerParameter_DimCheckMode_Name(value);
+  }
+  static inline bool DimCheckMode_Parse(const ::std::string& name,
+      DimCheckMode* value) {
+    return V1LayerParameter_DimCheckMode_Parse(name, value);
+  }
+
+  // accessors -------------------------------------------------------
+
+  // repeated string bottom = 2;
+  int bottom_size() const;
+  void clear_bottom();
+  static const int kBottomFieldNumber = 2;
+  const ::std::string& bottom(int index) const;
+  ::std::string* mutable_bottom(int index);
+  void set_bottom(int index, const ::std::string& value);
+  void set_bottom(int index, const char* value);
+  void set_bottom(int index, const char* value, size_t size);
+  ::std::string* add_bottom();
+  void add_bottom(const ::std::string& value);
+  void add_bottom(const char* value);
+  void add_bottom(const char* value, size_t size);
+  const ::google::protobuf::RepeatedPtrField< ::std::string>& bottom() const;
+  ::google::protobuf::RepeatedPtrField< ::std::string>* mutable_bottom();
+
+  // repeated string top = 3;
+  int top_size() const;
+  void clear_top();
+  static const int kTopFieldNumber = 3;
+  const ::std::string& top(int index) const;
+  ::std::string* mutable_top(int index);
+  void set_top(int index, const ::std::string& value);
+  void set_top(int index, const char* value);
+  void set_top(int index, const char* value, size_t size);
+  ::std::string* add_top();
+  void add_top(const ::std::string& value);
+  void add_top(const char* value);
+  void add_top(const char* value, size_t size);
+  const ::google::protobuf::RepeatedPtrField< ::std::string>& top() const;
+  ::google::protobuf::RepeatedPtrField< ::std::string>* mutable_top();
+
+  // optional string name = 4;
+  bool has_name() const;
+  void clear_name();
+  static const int kNameFieldNumber = 4;
+  const ::std::string& name() const;
+  void set_name(const ::std::string& value);
+  void set_name(const char* value);
+  void set_name(const char* value, size_t size);
+  ::std::string* mutable_name();
+  ::std::string* release_name();
+  void set_allocated_name(::std::string* name);
+
+  // repeated .caffe.NetStateRule include = 32;
+  int include_size() const;
+  void clear_include();
+  static const int kIncludeFieldNumber = 32;
+  const ::caffe::NetStateRule& include(int index) const;
+  ::caffe::NetStateRule* mutable_include(int index);
+  ::caffe::NetStateRule* add_include();
+  ::google::protobuf::RepeatedPtrField< ::caffe::NetStateRule >*
+      mutable_include();
+  const ::google::protobuf::RepeatedPtrField< ::caffe::NetStateRule >&
+      include() const;
+
+  // repeated .caffe.NetStateRule exclude = 33;
+  int exclude_size() const;
+  void clear_exclude();
+  static const int kExcludeFieldNumber = 33;
+  const ::caffe::NetStateRule& exclude(int index) const;
+  ::caffe::NetStateRule* mutable_exclude(int index);
+  ::caffe::NetStateRule* add_exclude();
+  ::google::protobuf::RepeatedPtrField< ::caffe::NetStateRule >*
+      mutable_exclude();
+  const ::google::protobuf::RepeatedPtrField< ::caffe::NetStateRule >&
+      exclude() const;
+
+  // optional .caffe.V1LayerParameter.LayerType type = 5;
+  bool has_type() const;
+  void clear_type();
+  static const int kTypeFieldNumber = 5;
+  ::caffe::V1LayerParameter_LayerType type() const;
+  void set_type(::caffe::V1LayerParameter_LayerType value);
+
+  // repeated .caffe.BlobProto blobs = 6;
+  int blobs_size() const;
+  void clear_blobs();
+  static const int kBlobsFieldNumber = 6;
+  const ::caffe::BlobProto& blobs(int index) const;
+  ::caffe::BlobProto* mutable_blobs(int index);
+  ::caffe::BlobProto* add_blobs();
+  ::google::protobuf::RepeatedPtrField< ::caffe::BlobProto >*
+      mutable_blobs();
+  const ::google::protobuf::RepeatedPtrField< ::caffe::BlobProto >&
+      blobs() const;
+
+  // repeated string param = 1001;
+  int param_size() const;
+  void clear_param();
+  static const int kParamFieldNumber = 1001;
+  const ::std::string& param(int index) const;
+  ::std::string* mutable_param(int index);
+  void set_param(int index, const ::std::string& value);
+  void set_param(int index, const char* value);
+  void set_param(int index, const char* value, size_t size);
+  ::std::string* add_param();
+  void add_param(const ::std::string& value);
+  void add_param(const char* value);
+  void add_param(const char* value, size_t size);
+  const ::google::protobuf::RepeatedPtrField< ::std::string>& param() const;
+  ::google::protobuf::RepeatedPtrField< ::std::string>* mutable_param();
+
+  // repeated .caffe.V1LayerParameter.DimCheckMode blob_share_mode = 1002;
+  int blob_share_mode_size() const;
+  void clear_blob_share_mode();
+  static const int kBlobShareModeFieldNumber = 1002;
+  ::caffe::V1LayerParameter_DimCheckMode blob_share_mode(int index) const;
+  void set_blob_share_mode(int index, ::caffe::V1LayerParameter_DimCheckMode value);
+  void add_blob_share_mode(::caffe::V1LayerParameter_DimCheckMode value);
+  const ::google::protobuf::RepeatedField<int>& blob_share_mode() const;
+  ::google::protobuf::RepeatedField<int>* mutable_blob_share_mode();
+
+  // repeated float blobs_lr = 7;
+  int blobs_lr_size() const;
+  void clear_blobs_lr();
+  static const int kBlobsLrFieldNumber = 7;
+  float blobs_lr(int index) const;
+  void set_blobs_lr(int index, float value);
+  void add_blobs_lr(float value);
+  const ::google::protobuf::RepeatedField< float >&
+      blobs_lr() const;
+  ::google::protobuf::RepeatedField< float >*
+      mutable_blobs_lr();
+
+  // repeated float weight_decay = 8;
+  int weight_decay_size() const;
+  void clear_weight_decay();
+  static const int kWeightDecayFieldNumber = 8;
+  float weight_decay(int index) const;
+  void set_weight_decay(int index, float value);
+  void add_weight_decay(float value);
+  const ::google::protobuf::RepeatedField< float >&
+      weight_decay() const;
+  ::google::protobuf::RepeatedField< float >*
+      mutable_weight_decay();
+
+  // repeated float loss_weight = 35;
+  int loss_weight_size() const;
+  void clear_loss_weight();
+  static const int kLossWeightFieldNumber = 35;
+  float loss_weight(int index) const;
+  void set_loss_weight(int index, float value);
+  void add_loss_weight(float value);
+  const ::google::protobuf::RepeatedField< float >&
+      loss_weight() const;
+  ::google::protobuf::RepeatedField< float >*
+      mutable_loss_weight();
+
+  // optional .caffe.AccuracyParameter accuracy_param = 27;
+  bool has_accuracy_param() const;
+  void clear_accuracy_param();
+  static const int kAccuracyParamFieldNumber = 27;
+  const ::caffe::AccuracyParameter& accuracy_param() const;
+  ::caffe::AccuracyParameter* mutable_accuracy_param();
+  ::caffe::AccuracyParameter* release_accuracy_param();
+  void set_allocated_accuracy_param(::caffe::AccuracyParameter* accuracy_param);
+
+  // optional .caffe.ArgMaxParameter argmax_param = 23;
+  bool has_argmax_param() const;
+  void clear_argmax_param();
+  static const int kArgmaxParamFieldNumber = 23;
+  const ::caffe::ArgMaxParameter& argmax_param() const;
+  ::caffe::ArgMaxParameter* mutable_argmax_param();
+  ::caffe::ArgMaxParameter* release_argmax_param();
+  void set_allocated_argmax_param(::caffe::ArgMaxParameter* argmax_param);
+
+  // optional .caffe.ConcatParameter concat_param = 9;
+  bool has_concat_param() const;
+  void clear_concat_param();
+  static const int kConcatParamFieldNumber = 9;
+  const ::caffe::ConcatParameter& concat_param() const;
+  ::caffe::ConcatParameter* mutable_concat_param();
+  ::caffe::ConcatParameter* release_concat_param();
+  void set_allocated_concat_param(::caffe::ConcatParameter* concat_param);
+
+  // optional .caffe.ContrastiveLossParameter contrastive_loss_param = 40;
+  bool has_contrastive_loss_param() const;
+  void clear_contrastive_loss_param();
+  static const int kContrastiveLossParamFieldNumber = 40;
+  const ::caffe::ContrastiveLossParameter& contrastive_loss_param() const;
+  ::caffe::ContrastiveLossParameter* mutable_contrastive_loss_param();
+  ::caffe::ContrastiveLossParameter* release_contrastive_loss_param();
+  void set_allocated_contrastive_loss_param(::caffe::ContrastiveLossParameter* contrastive_loss_param);
+
+  // optional .caffe.ConvolutionParameter convolution_param = 10;
+  bool has_convolution_param() const;
+  void clear_convolution_param();
+  static const int kConvolutionParamFieldNumber = 10;
+  const ::caffe::ConvolutionParameter& convolution_param() const;
+  ::caffe::ConvolutionParameter* mutable_convolution_param();
+  ::caffe::ConvolutionParameter* release_convolution_param();
+  void set_allocated_convolution_param(::caffe::ConvolutionParameter* convolution_param);
+
+  // optional .caffe.DataParameter data_param = 11;
+  bool has_data_param() const;
+  void clear_data_param();
+  static const int kDataParamFieldNumber = 11;
+  const ::caffe::DataParameter& data_param() const;
+  ::caffe::DataParameter* mutable_data_param();
+  ::caffe::DataParameter* release_data_param();
+  void set_allocated_data_param(::caffe::DataParameter* data_param);
+
+  // optional .caffe.DropoutParameter dropout_param = 12;
+  bool has_dropout_param() const;
+  void clear_dropout_param();
+  static const int kDropoutParamFieldNumber = 12;
+  const ::caffe::DropoutParameter& dropout_param() const;
+  ::caffe::DropoutParameter* mutable_dropout_param();
+  ::caffe::DropoutParameter* release_dropout_param();
+  void set_allocated_dropout_param(::caffe::DropoutParameter* dropout_param);
+
+  // optional .caffe.DummyDataParameter dummy_data_param = 26;
+  bool has_dummy_data_param() const;
+  void clear_dummy_data_param();
+  static const int kDummyDataParamFieldNumber = 26;
+  const ::caffe::DummyDataParameter& dummy_data_param() const;
+  ::caffe::DummyDataParameter* mutable_dummy_data_param();
+  ::caffe::DummyDataParameter* release_dummy_data_param();
+  void set_allocated_dummy_data_param(::caffe::DummyDataParameter* dummy_data_param);
+
+  // optional .caffe.EltwiseParameter eltwise_param = 24;
+  bool has_eltwise_param() const;
+  void clear_eltwise_param();
+  static const int kEltwiseParamFieldNumber = 24;
+  const ::caffe::EltwiseParameter& eltwise_param() const;
+  ::caffe::EltwiseParameter* mutable_eltwise_param();
+  ::caffe::EltwiseParameter* release_eltwise_param();
+  void set_allocated_eltwise_param(::caffe::EltwiseParameter* eltwise_param);
+
+  // optional .caffe.ExpParameter exp_param = 41;
+  bool has_exp_param() const;
+  void clear_exp_param();
+  static const int kExpParamFieldNumber = 41;
+  const ::caffe::ExpParameter& exp_param() const;
+  ::caffe::ExpParameter* mutable_exp_param();
+  ::caffe::ExpParameter* release_exp_param();
+  void set_allocated_exp_param(::caffe::ExpParameter* exp_param);
+
+  // optional .caffe.HDF5DataParameter hdf5_data_param = 13;
+  bool has_hdf5_data_param() const;
+  void clear_hdf5_data_param();
+  static const int kHdf5DataParamFieldNumber = 13;
+  const ::caffe::HDF5DataParameter& hdf5_data_param() const;
+  ::caffe::HDF5DataParameter* mutable_hdf5_data_param();
+  ::caffe::HDF5DataParameter* release_hdf5_data_param();
+  void set_allocated_hdf5_data_param(::caffe::HDF5DataParameter* hdf5_data_param);
+
+  // optional .caffe.HDF5OutputParameter hdf5_output_param = 14;
+  bool has_hdf5_output_param() const;
+  void clear_hdf5_output_param();
+  static const int kHdf5OutputParamFieldNumber = 14;
+  const ::caffe::HDF5OutputParameter& hdf5_output_param() const;
+  ::caffe::HDF5OutputParameter* mutable_hdf5_output_param();
+  ::caffe::HDF5OutputParameter* release_hdf5_output_param();
+  void set_allocated_hdf5_output_param(::caffe::HDF5OutputParameter* hdf5_output_param);
+
+  // optional .caffe.HingeLossParameter hinge_loss_param = 29;
+  bool has_hinge_loss_param() const;
+  void clear_hinge_loss_param();
+  static const int kHingeLossParamFieldNumber = 29;
+  const ::caffe::HingeLossParameter& hinge_loss_param() const;
+  ::caffe::HingeLossParameter* mutable_hinge_loss_param();
+  ::caffe::HingeLossParameter* release_hinge_loss_param();
+  void set_allocated_hinge_loss_param(::caffe::HingeLossParameter* hinge_loss_param);
+
+  // optional .caffe.ImageDataParameter image_data_param = 15;
+  bool has_image_data_param() const;
+  void clear_image_data_param();
+  static const int kImageDataParamFieldNumber = 15;
+  const ::caffe::ImageDataParameter& image_data_param() const;
+  ::caffe::ImageDataParameter* mutable_image_data_param();
+  ::caffe::ImageDataParameter* release_image_data_param();
+  void set_allocated_image_data_param(::caffe::ImageDataParameter* image_data_param);
+
+  // optional .caffe.InfogainLossParameter infogain_loss_param = 16;
+  bool has_infogain_loss_param() const;
+  void clear_infogain_loss_param();
+  static const int kInfogainLossParamFieldNumber = 16;
+  const ::caffe::InfogainLossParameter& infogain_loss_param() const;
+  ::caffe::InfogainLossParameter* mutable_infogain_loss_param();
+  ::caffe::InfogainLossParameter* release_infogain_loss_param();
+  void set_allocated_infogain_loss_param(::caffe::InfogainLossParameter* infogain_loss_param);
+
+  // optional .caffe.InnerProductParameter inner_product_param = 17;
+  bool has_inner_product_param() const;
+  void clear_inner_product_param();
+  static const int kInnerProductParamFieldNumber = 17;
+  const ::caffe::InnerProductParameter& inner_product_param() const;
+  ::caffe::InnerProductParameter* mutable_inner_product_param();
+  ::caffe::InnerProductParameter* release_inner_product_param();
+  void set_allocated_inner_product_param(::caffe::InnerProductParameter* inner_product_param);
+
+  // optional .caffe.LRNParameter lrn_param = 18;
+  bool has_lrn_param() const;
+  void clear_lrn_param();
+  static const int kLrnParamFieldNumber = 18;
+  const ::caffe::LRNParameter& lrn_param() const;
+  ::caffe::LRNParameter* mutable_lrn_param();
+  ::caffe::LRNParameter* release_lrn_param();
+  void set_allocated_lrn_param(::caffe::LRNParameter* lrn_param);
+
+  // optional .caffe.MemoryDataParameter memory_data_param = 22;
+  bool has_memory_data_param() const;
+  void clear_memory_data_param();
+  static const int kMemoryDataParamFieldNumber = 22;
+  const ::caffe::MemoryDataParameter& memory_data_param() const;
+  ::caffe::MemoryDataParameter* mutable_memory_data_param();
+  ::caffe::MemoryDataParameter* release_memory_data_param();
+  void set_allocated_memory_data_param(::caffe::MemoryDataParameter* memory_data_param);
+
+  // optional .caffe.MVNParameter mvn_param = 34;
+  bool has_mvn_param() const;
+  void clear_mvn_param();
+  static const int kMvnParamFieldNumber = 34;
+  const ::caffe::MVNParameter& mvn_param() const;
+  ::caffe::MVNParameter* mutable_mvn_param();
+  ::caffe::MVNParameter* release_mvn_param();
+  void set_allocated_mvn_param(::caffe::MVNParameter* mvn_param);
+
+  // optional .caffe.PoolingParameter pooling_param = 19;
+  bool has_pooling_param() const;
+  void clear_pooling_param();
+  static const int kPoolingParamFieldNumber = 19;
+  const ::caffe::PoolingParameter& pooling_param() const;
+  ::caffe::PoolingParameter* mutable_pooling_param();
+  ::caffe::PoolingParameter* release_pooling_param();
+  void set_allocated_pooling_param(::caffe::PoolingParameter* pooling_param);
+
+  // optional .caffe.PowerParameter power_param = 21;
+  bool has_power_param() const;
+  void clear_power_param();
+  static const int kPowerParamFieldNumber = 21;
+  const ::caffe::PowerParameter& power_param() const;
+  ::caffe::PowerParameter* mutable_power_param();
+  ::caffe::PowerParameter* release_power_param();
+  void set_allocated_power_param(::caffe::PowerParameter* power_param);
+
+  // optional .caffe.ReLUParameter relu_param = 30;
+  bool has_relu_param() const;
+  void clear_relu_param();
+  static const int kReluParamFieldNumber = 30;
+  const ::caffe::ReLUParameter& relu_param() const;
+  ::caffe::ReLUParameter* mutable_relu_param();
+  ::caffe::ReLUParameter* release_relu_param();
+  void set_allocated_relu_param(::caffe::ReLUParameter* relu_param);
+
+  // optional .caffe.SigmoidParameter sigmoid_param = 38;
+  bool has_sigmoid_param() const;
+  void clear_sigmoid_param();
+  static const int kSigmoidParamFieldNumber = 38;
+  const ::caffe::SigmoidParameter& sigmoid_param() const;
+  ::caffe::SigmoidParameter* mutable_sigmoid_param();
+  ::caffe::SigmoidParameter* release_sigmoid_param();
+  void set_allocated_sigmoid_param(::caffe::SigmoidParameter* sigmoid_param);
+
+  // optional .caffe.SoftmaxParameter softmax_param = 39;
+  bool has_softmax_param() const;
+  void clear_softmax_param();
+  static const int kSoftmaxParamFieldNumber = 39;
+  const ::caffe::SoftmaxParameter& softmax_param() const;
+  ::caffe::SoftmaxParameter* mutable_softmax_param();
+  ::caffe::SoftmaxParameter* release_softmax_param();
+  void set_allocated_softmax_param(::caffe::SoftmaxParameter* softmax_param);
+
+  // optional .caffe.SliceParameter slice_param = 31;
+  bool has_slice_param() const;
+  void clear_slice_param();
+  static const int kSliceParamFieldNumber = 31;
+  const ::caffe::SliceParameter& slice_param() const;
+  ::caffe::SliceParameter* mutable_slice_param();
+  ::caffe::SliceParameter* release_slice_param();
+  void set_allocated_slice_param(::caffe::SliceParameter* slice_param);
+
+  // optional .caffe.TanHParameter tanh_param = 37;
+  bool has_tanh_param() const;
+  void clear_tanh_param();
+  static const int kTanhParamFieldNumber = 37;
+  const ::caffe::TanHParameter& tanh_param() const;
+  ::caffe::TanHParameter* mutable_tanh_param();
+  ::caffe::TanHParameter* release_tanh_param();
+  void set_allocated_tanh_param(::caffe::TanHParameter* tanh_param);
+
+  // optional .caffe.ThresholdParameter threshold_param = 25;
+  bool has_threshold_param() const;
+  void clear_threshold_param();
+  static const int kThresholdParamFieldNumber = 25;
+  const ::caffe::ThresholdParameter& threshold_param() const;
+  ::caffe::ThresholdParameter* mutable_threshold_param();
+  ::caffe::ThresholdParameter* release_threshold_param();
+  void set_allocated_threshold_param(::caffe::ThresholdParameter* threshold_param);
+
+  // optional .caffe.WindowDataParameter window_data_param = 20;
+  bool has_window_data_param() const;
+  void clear_window_data_param();
+  static const int kWindowDataParamFieldNumber = 20;
+  const ::caffe::WindowDataParameter& window_data_param() const;
+  ::caffe::WindowDataParameter* mutable_window_data_param();
+  ::caffe::WindowDataParameter* release_window_data_param();
+  void set_allocated_window_data_param(::caffe::WindowDataParameter* window_data_param);
+
+  // optional .caffe.TransformationParameter transform_param = 36;
+  bool has_transform_param() const;
+  void clear_transform_param();
+  static const int kTransformParamFieldNumber = 36;
+  const ::caffe::TransformationParameter& transform_param() const;
+  ::caffe::TransformationParameter* mutable_transform_param();
+  ::caffe::TransformationParameter* release_transform_param();
+  void set_allocated_transform_param(::caffe::TransformationParameter* transform_param);
+
+  // optional .caffe.LossParameter loss_param = 42;
+  bool has_loss_param() const;
+  void clear_loss_param();
+  static const int kLossParamFieldNumber = 42;
+  const ::caffe::LossParameter& loss_param() const;
+  ::caffe::LossParameter* mutable_loss_param();
+  ::caffe::LossParameter* release_loss_param();
+  void set_allocated_loss_param(::caffe::LossParameter* loss_param);
+
+  // optional .caffe.V0LayerParameter layer = 1;
+  bool has_layer() const;
+  void clear_layer();
+  static const int kLayerFieldNumber = 1;
+  const ::caffe::V0LayerParameter& layer() const;
+  ::caffe::V0LayerParameter* mutable_layer();
+  ::caffe::V0LayerParameter* release_layer();
+  void set_allocated_layer(::caffe::V0LayerParameter* layer);
+
+  // @@protoc_insertion_point(class_scope:caffe.V1LayerParameter)
+ private:
+  inline void set_has_name();
+  inline void clear_has_name();
+  inline void set_has_type();
+  inline void clear_has_type();
+  inline void set_has_accuracy_param();
+  inline void clear_has_accuracy_param();
+  inline void set_has_argmax_param();
+  inline void clear_has_argmax_param();
+  inline void set_has_concat_param();
+  inline void clear_has_concat_param();
+  inline void set_has_contrastive_loss_param();
+  inline void clear_has_contrastive_loss_param();
+  inline void set_has_convolution_param();
+  inline void clear_has_convolution_param();
+  inline void set_has_data_param();
+  inline void clear_has_data_param();
+  inline void set_has_dropout_param();
+  inline void clear_has_dropout_param();
+  inline void set_has_dummy_data_param();
+  inline void clear_has_dummy_data_param();
+  inline void set_has_eltwise_param();
+  inline void clear_has_eltwise_param();
+  inline void set_has_exp_param();
+  inline void clear_has_exp_param();
+  inline void set_has_hdf5_data_param();
+  inline void clear_has_hdf5_data_param();
+  inline void set_has_hdf5_output_param();
+  inline void clear_has_hdf5_output_param();
+  inline void set_has_hinge_loss_param();
+  inline void clear_has_hinge_loss_param();
+  inline void set_has_image_data_param();
+  inline void clear_has_image_data_param();
+  inline void set_has_infogain_loss_param();
+  inline void clear_has_infogain_loss_param();
+  inline void set_has_inner_product_param();
+  inline void clear_has_inner_product_param();
+  inline void set_has_lrn_param();
+  inline void clear_has_lrn_param();
+  inline void set_has_memory_data_param();
+  inline void clear_has_memory_data_param();
+  inline void set_has_mvn_param();
+  inline void clear_has_mvn_param();
+  inline void set_has_pooling_param();
+  inline void clear_has_pooling_param();
+  inline void set_has_power_param();
+  inline void clear_has_power_param();
+  inline void set_has_relu_param();
+  inline void clear_has_relu_param();
+  inline void set_has_sigmoid_param();
+  inline void clear_has_sigmoid_param();
+  inline void set_has_softmax_param();
+  inline void clear_has_softmax_param();
+  inline void set_has_slice_param();
+  inline void clear_has_slice_param();
+  inline void set_has_tanh_param();
+  inline void clear_has_tanh_param();
+  inline void set_has_threshold_param();
+  inline void clear_has_threshold_param();
+  inline void set_has_window_data_param();
+  inline void clear_has_window_data_param();
+  inline void set_has_transform_param();
+  inline void clear_has_transform_param();
+  inline void set_has_loss_param();
+  inline void clear_has_loss_param();
+  inline void set_has_layer();
+  inline void clear_has_layer();
+
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  ::google::protobuf::internal::HasBits<2> _has_bits_;
+  ::google::protobuf::RepeatedPtrField< ::std::string> bottom_;
+  ::google::protobuf::RepeatedPtrField< ::std::string> top_;
+  ::google::protobuf::RepeatedPtrField< ::caffe::NetStateRule > include_;
+  ::google::protobuf::RepeatedPtrField< ::caffe::NetStateRule > exclude_;
+  ::google::protobuf::RepeatedPtrField< ::caffe::BlobProto > blobs_;
+  ::google::protobuf::RepeatedPtrField< ::std::string> param_;
+  ::google::protobuf::RepeatedField<int> blob_share_mode_;
+  ::google::protobuf::RepeatedField< float > blobs_lr_;
+  ::google::protobuf::RepeatedField< float > weight_decay_;
+  ::google::protobuf::RepeatedField< float > loss_weight_;
+  ::google::protobuf::internal::ArenaStringPtr name_;
+  ::caffe::AccuracyParameter* accuracy_param_;
+  ::caffe::ArgMaxParameter* argmax_param_;
+  ::caffe::ConcatParameter* concat_param_;
+  ::caffe::ContrastiveLossParameter* contrastive_loss_param_;
+  ::caffe::ConvolutionParameter* convolution_param_;
+  ::caffe::DataParameter* data_param_;
+  ::caffe::DropoutParameter* dropout_param_;
+  ::caffe::DummyDataParameter* dummy_data_param_;
+  ::caffe::EltwiseParameter* eltwise_param_;
+  ::caffe::ExpParameter* exp_param_;
+  ::caffe::HDF5DataParameter* hdf5_data_param_;
+  ::caffe::HDF5OutputParameter* hdf5_output_param_;
+  ::caffe::HingeLossParameter* hinge_loss_param_;
+  ::caffe::ImageDataParameter* image_data_param_;
+  ::caffe::InfogainLossParameter* infogain_loss_param_;
+  ::caffe::InnerProductParameter* inner_product_param_;
+  ::caffe::LRNParameter* lrn_param_;
+  ::caffe::MemoryDataParameter* memory_data_param_;
+  ::caffe::MVNParameter* mvn_param_;
+  ::caffe::PoolingParameter* pooling_param_;
+  ::caffe::PowerParameter* power_param_;
+  ::caffe::ReLUParameter* relu_param_;
+  ::caffe::SigmoidParameter* sigmoid_param_;
+  ::caffe::SoftmaxParameter* softmax_param_;
+  ::caffe::SliceParameter* slice_param_;
+  ::caffe::TanHParameter* tanh_param_;
+  ::caffe::ThresholdParameter* threshold_param_;
+  ::caffe::WindowDataParameter* window_data_param_;
+  ::caffe::TransformationParameter* transform_param_;
+  ::caffe::LossParameter* loss_param_;
+  ::caffe::V0LayerParameter* layer_;
+  int type_;
+  mutable int _cached_size_;
+  friend void  protobuf_InitDefaults_caffe_2eproto_impl();
+  friend void  protobuf_AddDesc_caffe_2eproto_impl();
+  friend void protobuf_AssignDesc_caffe_2eproto();
+  friend void protobuf_ShutdownFile_caffe_2eproto();
+
+  void InitAsDefaultInstance();
+};
+extern ::google::protobuf::internal::ExplicitlyConstructed<V1LayerParameter> V1LayerParameter_default_instance_;
+
+// -------------------------------------------------------------------
+
+class V0LayerParameter : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:caffe.V0LayerParameter) */ {
+ public:
+  V0LayerParameter();
+  virtual ~V0LayerParameter();
+
+  V0LayerParameter(const V0LayerParameter& from);
+
+  inline V0LayerParameter& operator=(const V0LayerParameter& from) {
+    CopyFrom(from);
+    return *this;
+  }
+
+  inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields();
+  }
+
+  inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields();
+  }
+
+  static const ::google::protobuf::Descriptor* descriptor();
+  static const V0LayerParameter& default_instance();
+
+  static const V0LayerParameter* internal_default_instance();
+
+  void Swap(V0LayerParameter* other);
+
+  // implements Message ----------------------------------------------
+
+  inline V0LayerParameter* New() const { return New(NULL); }
+
+  V0LayerParameter* New(::google::protobuf::Arena* arena) const;
+  void CopyFrom(const ::google::protobuf::Message& from);
+  void MergeFrom(const ::google::protobuf::Message& from);
+  void CopyFrom(const V0LayerParameter& from);
+  void MergeFrom(const V0LayerParameter& from);
+  void Clear();
+  bool IsInitialized() const;
+
+  size_t ByteSizeLong() const;
+  bool MergePartialFromCodedStream(
+      ::google::protobuf::io::CodedInputStream* input);
+  void SerializeWithCachedSizes(
+      ::google::protobuf::io::CodedOutputStream* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
+  int GetCachedSize() const { return _cached_size_; }
+  private:
+  void SharedCtor();
+  void SharedDtor();
+  void SetCachedSize(int size) const;
+  void InternalSwap(V0LayerParameter* other);
+  void UnsafeMergeFrom(const V0LayerParameter& from);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
+  public:
+
+  ::google::protobuf::Metadata GetMetadata() const;
+
+  // nested types ----------------------------------------------------
+
+  typedef V0LayerParameter_PoolMethod PoolMethod;
+  static const PoolMethod MAX =
+    V0LayerParameter_PoolMethod_MAX;
+  static const PoolMethod AVE =
+    V0LayerParameter_PoolMethod_AVE;
+  static const PoolMethod STOCHASTIC =
+    V0LayerParameter_PoolMethod_STOCHASTIC;
+  static inline bool PoolMethod_IsValid(int value) {
+    return V0LayerParameter_PoolMethod_IsValid(value);
+  }
+  static const PoolMethod PoolMethod_MIN =
+    V0LayerParameter_PoolMethod_PoolMethod_MIN;
+  static const PoolMethod PoolMethod_MAX =
+    V0LayerParameter_PoolMethod_PoolMethod_MAX;
+  static const int PoolMethod_ARRAYSIZE =
+    V0LayerParameter_PoolMethod_PoolMethod_ARRAYSIZE;
+  static inline const ::google::protobuf::EnumDescriptor*
+  PoolMethod_descriptor() {
+    return V0LayerParameter_PoolMethod_descriptor();
+  }
+  static inline const ::std::string& PoolMethod_Name(PoolMethod value) {
+    return V0LayerParameter_PoolMethod_Name(value);
+  }
+  static inline bool PoolMethod_Parse(const ::std::string& name,
+      PoolMethod* value) {
+    return V0LayerParameter_PoolMethod_Parse(name, value);
+  }
+
+  // accessors -------------------------------------------------------
+
+  // optional string name = 1;
+  bool has_name() const;
+  void clear_name();
+  static const int kNameFieldNumber = 1;
+  const ::std::string& name() const;
+  void set_name(const ::std::string& value);
+  void set_name(const char* value);
+  void set_name(const char* value, size_t size);
+  ::std::string* mutable_name();
+  ::std::string* release_name();
+  void set_allocated_name(::std::string* name);
+
+  // optional string type = 2;
+  bool has_type() const;
+  void clear_type();
+  static const int kTypeFieldNumber = 2;
+  const ::std::string& type() const;
+  void set_type(const ::std::string& value);
+  void set_type(const char* value);
+  void set_type(const char* value, size_t size);
+  ::std::string* mutable_type();
+  ::std::string* release_type();
+  void set_allocated_type(::std::string* type);
+
+  // optional uint32 num_output = 3;
+  bool has_num_output() const;
+  void clear_num_output();
+  static const int kNumOutputFieldNumber = 3;
+  ::google::protobuf::uint32 num_output() const;
+  void set_num_output(::google::protobuf::uint32 value);
+
+  // optional bool biasterm = 4 [default = true];
+  bool has_biasterm() const;
+  void clear_biasterm();
+  static const int kBiastermFieldNumber = 4;
+  bool biasterm() const;
+  void set_biasterm(bool value);
+
+  // optional .caffe.FillerParameter weight_filler = 5;
+  bool has_weight_filler() const;
+  void clear_weight_filler();
+  static const int kWeightFillerFieldNumber = 5;
+  const ::caffe::FillerParameter& weight_filler() const;
+  ::caffe::FillerParameter* mutable_weight_filler();
+  ::caffe::FillerParameter* release_weight_filler();
+  void set_allocated_weight_filler(::caffe::FillerParameter* weight_filler);
+
+  // optional .caffe.FillerParameter bias_filler = 6;
+  bool has_bias_filler() const;
+  void clear_bias_filler();
+  static const int kBiasFillerFieldNumber = 6;
+  const ::caffe::FillerParameter& bias_filler() const;
+  ::caffe::FillerParameter* mutable_bias_filler();
+  ::caffe::FillerParameter* release_bias_filler();
+  void set_allocated_bias_filler(::caffe::FillerParameter* bias_filler);
+
+  // optional uint32 pad = 7 [default = 0];
+  bool has_pad() const;
+  void clear_pad();
+  static const int kPadFieldNumber = 7;
+  ::google::protobuf::uint32 pad() const;
+  void set_pad(::google::protobuf::uint32 value);
+
+  // optional uint32 kernelsize = 8;
+  bool has_kernelsize() const;
+  void clear_kernelsize();
+  static const int kKernelsizeFieldNumber = 8;
+  ::google::protobuf::uint32 kernelsize() const;
+  void set_kernelsize(::google::protobuf::uint32 value);
+
+  // optional uint32 group = 9 [default = 1];
+  bool has_group() const;
+  void clear_group();
+  static const int kGroupFieldNumber = 9;
+  ::google::protobuf::uint32 group() const;
+  void set_group(::google::protobuf::uint32 value);
+
+  // optional uint32 stride = 10 [default = 1];
+  bool has_stride() const;
+  void clear_stride();
+  static const int kStrideFieldNumber = 10;
+  ::google::protobuf::uint32 stride() const;
+  void set_stride(::google::protobuf::uint32 value);
+
+  // optional .caffe.V0LayerParameter.PoolMethod pool = 11 [default = MAX];
+  bool has_pool() const;
+  void clear_pool();
+  static const int kPoolFieldNumber = 11;
+  ::caffe::V0LayerParameter_PoolMethod pool() const;
+  void set_pool(::caffe::V0LayerParameter_PoolMethod value);
+
+  // optional float dropout_ratio = 12 [default = 0.5];
+  bool has_dropout_ratio() const;
+  void clear_dropout_ratio();
+  static const int kDropoutRatioFieldNumber = 12;
+  float dropout_ratio() const;
+  void set_dropout_ratio(float value);
+
+  // optional uint32 local_size = 13 [default = 5];
+  bool has_local_size() const;
+  void clear_local_size();
+  static const int kLocalSizeFieldNumber = 13;
+  ::google::protobuf::uint32 local_size() const;
+  void set_local_size(::google::protobuf::uint32 value);
+
+  // optional float alpha = 14 [default = 1];
+  bool has_alpha() const;
+  void clear_alpha();
+  static const int kAlphaFieldNumber = 14;
+  float alpha() const;
+  void set_alpha(float value);
+
+  // optional float beta = 15 [default = 0.75];
+  bool has_beta() const;
+  void clear_beta();
+  static const int kBetaFieldNumber = 15;
+  float beta() const;
+  void set_beta(float value);
+
+  // optional float k = 22 [default = 1];
+  bool has_k() const;
+  void clear_k();
+  static const int kKFieldNumber = 22;
+  float k() const;
+  void set_k(float value);
+
+  // optional string source = 16;
+  bool has_source() const;
+  void clear_source();
+  static const int kSourceFieldNumber = 16;
+  const ::std::string& source() const;
+  void set_source(const ::std::string& value);
+  void set_source(const char* value);
+  void set_source(const char* value, size_t size);
+  ::std::string* mutable_source();
+  ::std::string* release_source();
+  void set_allocated_source(::std::string* source);
+
+  // optional float scale = 17 [default = 1];
+  bool has_scale() const;
+  void clear_scale();
+  static const int kScaleFieldNumber = 17;
+  float scale() const;
+  void set_scale(float value);
+
+  // optional string meanfile = 18;
+  bool has_meanfile() const;
+  void clear_meanfile();
+  static const int kMeanfileFieldNumber = 18;
+  const ::std::string& meanfile() const;
+  void set_meanfile(const ::std::string& value);
+  void set_meanfile(const char* value);
+  void set_meanfile(const char* value, size_t size);
+  ::std::string* mutable_meanfile();
+  ::std::string* release_meanfile();
+  void set_allocated_meanfile(::std::string* meanfile);
+
+  // optional uint32 batchsize = 19;
+  bool has_batchsize() const;
+  void clear_batchsize();
+  static const int kBatchsizeFieldNumber = 19;
+  ::google::protobuf::uint32 batchsize() const;
+  void set_batchsize(::google::protobuf::uint32 value);
+
+  // optional uint32 cropsize = 20 [default = 0];
+  bool has_cropsize() const;
+  void clear_cropsize();
+  static const int kCropsizeFieldNumber = 20;
+  ::google::protobuf::uint32 cropsize() const;
+  void set_cropsize(::google::protobuf::uint32 value);
+
+  // optional bool mirror = 21 [default = false];
+  bool has_mirror() const;
+  void clear_mirror();
+  static const int kMirrorFieldNumber = 21;
+  bool mirror() const;
+  void set_mirror(bool value);
+
+  // repeated .caffe.BlobProto blobs = 50;
+  int blobs_size() const;
+  void clear_blobs();
+  static const int kBlobsFieldNumber = 50;
+  const ::caffe::BlobProto& blobs(int index) const;
+  ::caffe::BlobProto* mutable_blobs(int index);
+  ::caffe::BlobProto* add_blobs();
+  ::google::protobuf::RepeatedPtrField< ::caffe::BlobProto >*
+      mutable_blobs();
+  const ::google::protobuf::RepeatedPtrField< ::caffe::BlobProto >&
+      blobs() const;
+
+  // repeated float blobs_lr = 51;
+  int blobs_lr_size() const;
+  void clear_blobs_lr();
+  static const int kBlobsLrFieldNumber = 51;
+  float blobs_lr(int index) const;
+  void set_blobs_lr(int index, float value);
+  void add_blobs_lr(float value);
+  const ::google::protobuf::RepeatedField< float >&
+      blobs_lr() const;
+  ::google::protobuf::RepeatedField< float >*
+      mutable_blobs_lr();
+
+  // repeated float weight_decay = 52;
+  int weight_decay_size() const;
+  void clear_weight_decay();
+  static const int kWeightDecayFieldNumber = 52;
+  float weight_decay(int index) const;
+  void set_weight_decay(int index, float value);
+  void add_weight_decay(float value);
+  const ::google::protobuf::RepeatedField< float >&
+      weight_decay() const;
+  ::google::protobuf::RepeatedField< float >*
+      mutable_weight_decay();
+
+  // optional uint32 rand_skip = 53 [default = 0];
+  bool has_rand_skip() const;
+  void clear_rand_skip();
+  static const int kRandSkipFieldNumber = 53;
+  ::google::protobuf::uint32 rand_skip() const;
+  void set_rand_skip(::google::protobuf::uint32 value);
+
+  // optional float det_fg_threshold = 54 [default = 0.5];
+  bool has_det_fg_threshold() const;
+  void clear_det_fg_threshold();
+  static const int kDetFgThresholdFieldNumber = 54;
+  float det_fg_threshold() const;
+  void set_det_fg_threshold(float value);
+
+  // optional float det_bg_threshold = 55 [default = 0.5];
+  bool has_det_bg_threshold() const;
+  void clear_det_bg_threshold();
+  static const int kDetBgThresholdFieldNumber = 55;
+  float det_bg_threshold() const;
+  void set_det_bg_threshold(float value);
+
+  // optional float det_fg_fraction = 56 [default = 0.25];
+  bool has_det_fg_fraction() const;
+  void clear_det_fg_fraction();
+  static const int kDetFgFractionFieldNumber = 56;
+  float det_fg_fraction() const;
+  void set_det_fg_fraction(float value);
+
+  // optional uint32 det_context_pad = 58 [default = 0];
+  bool has_det_context_pad() const;
+  void clear_det_context_pad();
+  static const int kDetContextPadFieldNumber = 58;
+  ::google::protobuf::uint32 det_context_pad() const;
+  void set_det_context_pad(::google::protobuf::uint32 value);
+
+  // optional string det_crop_mode = 59 [default = "warp"];
+  bool has_det_crop_mode() const;
+  void clear_det_crop_mode();
+  static const int kDetCropModeFieldNumber = 59;
+  const ::std::string& det_crop_mode() const;
+  void set_det_crop_mode(const ::std::string& value);
+  void set_det_crop_mode(const char* value);
+  void set_det_crop_mode(const char* value, size_t size);
+  ::std::string* mutable_det_crop_mode();
+  ::std::string* release_det_crop_mode();
+  void set_allocated_det_crop_mode(::std::string* det_crop_mode);
+
+  // optional int32 new_num = 60 [default = 0];
+  bool has_new_num() const;
+  void clear_new_num();
+  static const int kNewNumFieldNumber = 60;
+  ::google::protobuf::int32 new_num() const;
+  void set_new_num(::google::protobuf::int32 value);
+
+  // optional int32 new_channels = 61 [default = 0];
+  bool has_new_channels() const;
+  void clear_new_channels();
+  static const int kNewChannelsFieldNumber = 61;
+  ::google::protobuf::int32 new_channels() const;
+  void set_new_channels(::google::protobuf::int32 value);
+
+  // optional int32 new_height = 62 [default = 0];
+  bool has_new_height() const;
+  void clear_new_height();
+  static const int kNewHeightFieldNumber = 62;
+  ::google::protobuf::int32 new_height() const;
+  void set_new_height(::google::protobuf::int32 value);
+
+  // optional int32 new_width = 63 [default = 0];
+  bool has_new_width() const;
+  void clear_new_width();
+  static const int kNewWidthFieldNumber = 63;
+  ::google::protobuf::int32 new_width() const;
+  void set_new_width(::google::protobuf::int32 value);
+
+  // optional bool shuffle_images = 64 [default = false];
+  bool has_shuffle_images() const;
+  void clear_shuffle_images();
+  static const int kShuffleImagesFieldNumber = 64;
+  bool shuffle_images() const;
+  void set_shuffle_images(bool value);
+
+  // optional uint32 concat_dim = 65 [default = 1];
+  bool has_concat_dim() const;
+  void clear_concat_dim();
+  static const int kConcatDimFieldNumber = 65;
+  ::google::protobuf::uint32 concat_dim() const;
+  void set_concat_dim(::google::protobuf::uint32 value);
+
+  // optional .caffe.HDF5OutputParameter hdf5_output_param = 1001;
+  bool has_hdf5_output_param() const;
+  void clear_hdf5_output_param();
+  static const int kHdf5OutputParamFieldNumber = 1001;
+  const ::caffe::HDF5OutputParameter& hdf5_output_param() const;
+  ::caffe::HDF5OutputParameter* mutable_hdf5_output_param();
+  ::caffe::HDF5OutputParameter* release_hdf5_output_param();
+  void set_allocated_hdf5_output_param(::caffe::HDF5OutputParameter* hdf5_output_param);
+
+  // @@protoc_insertion_point(class_scope:caffe.V0LayerParameter)
+ private:
+  inline void set_has_name();
+  inline void clear_has_name();
+  inline void set_has_type();
+  inline void clear_has_type();
+  inline void set_has_num_output();
+  inline void clear_has_num_output();
+  inline void set_has_biasterm();
+  inline void clear_has_biasterm();
+  inline void set_has_weight_filler();
+  inline void clear_has_weight_filler();
+  inline void set_has_bias_filler();
+  inline void clear_has_bias_filler();
+  inline void set_has_pad();
+  inline void clear_has_pad();
+  inline void set_has_kernelsize();
+  inline void clear_has_kernelsize();
+  inline void set_has_group();
+  inline void clear_has_group();
+  inline void set_has_stride();
+  inline void clear_has_stride();
+  inline void set_has_pool();
+  inline void clear_has_pool();
+  inline void set_has_dropout_ratio();
+  inline void clear_has_dropout_ratio();
+  inline void set_has_local_size();
+  inline void clear_has_local_size();
+  inline void set_has_alpha();
+  inline void clear_has_alpha();
+  inline void set_has_beta();
+  inline void clear_has_beta();
+  inline void set_has_k();
+  inline void clear_has_k();
+  inline void set_has_source();
+  inline void clear_has_source();
+  inline void set_has_scale();
+  inline void clear_has_scale();
+  inline void set_has_meanfile();
+  inline void clear_has_meanfile();
+  inline void set_has_batchsize();
+  inline void clear_has_batchsize();
+  inline void set_has_cropsize();
+  inline void clear_has_cropsize();
+  inline void set_has_mirror();
+  inline void clear_has_mirror();
+  inline void set_has_rand_skip();
+  inline void clear_has_rand_skip();
+  inline void set_has_det_fg_threshold();
+  inline void clear_has_det_fg_threshold();
+  inline void set_has_det_bg_threshold();
+  inline void clear_has_det_bg_threshold();
+  inline void set_has_det_fg_fraction();
+  inline void clear_has_det_fg_fraction();
+  inline void set_has_det_context_pad();
+  inline void clear_has_det_context_pad();
+  inline void set_has_det_crop_mode();
+  inline void clear_has_det_crop_mode();
+  inline void set_has_new_num();
+  inline void clear_has_new_num();
+  inline void set_has_new_channels();
+  inline void clear_has_new_channels();
+  inline void set_has_new_height();
+  inline void clear_has_new_height();
+  inline void set_has_new_width();
+  inline void clear_has_new_width();
+  inline void set_has_shuffle_images();
+  inline void clear_has_shuffle_images();
+  inline void set_has_concat_dim();
+  inline void clear_has_concat_dim();
+  inline void set_has_hdf5_output_param();
+  inline void clear_has_hdf5_output_param();
+
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  ::google::protobuf::internal::HasBits<2> _has_bits_;
+  ::google::protobuf::RepeatedPtrField< ::caffe::BlobProto > blobs_;
+  ::google::protobuf::RepeatedField< float > blobs_lr_;
+  ::google::protobuf::RepeatedField< float > weight_decay_;
+  ::google::protobuf::internal::ArenaStringPtr name_;
+  ::google::protobuf::internal::ArenaStringPtr type_;
+  ::google::protobuf::internal::ArenaStringPtr source_;
+  ::google::protobuf::internal::ArenaStringPtr meanfile_;
+  static ::std::string* _default_det_crop_mode_;
+  ::google::protobuf::internal::ArenaStringPtr det_crop_mode_;
+  ::caffe::FillerParameter* weight_filler_;
+  ::caffe::FillerParameter* bias_filler_;
+  ::caffe::HDF5OutputParameter* hdf5_output_param_;
+  ::google::protobuf::uint32 num_output_;
+  ::google::protobuf::uint32 pad_;
+  ::google::protobuf::uint32 kernelsize_;
+  int pool_;
+  ::google::protobuf::uint32 batchsize_;
+  ::google::protobuf::uint32 cropsize_;
+  ::google::protobuf::uint32 rand_skip_;
+  bool mirror_;
+  bool shuffle_images_;
+  ::google::protobuf::uint32 det_context_pad_;
+  ::google::protobuf::int32 new_num_;
+  ::google::protobuf::int32 new_channels_;
+  ::google::protobuf::int32 new_height_;
+  ::google::protobuf::int32 new_width_;
+  ::google::protobuf::uint32 concat_dim_;
+  bool biasterm_;
+  ::google::protobuf::uint32 group_;
+  ::google::protobuf::uint32 stride_;
+  float dropout_ratio_;
+  ::google::protobuf::uint32 local_size_;
+  float alpha_;
+  float beta_;
+  float k_;
+  float scale_;
+  float det_fg_threshold_;
+  float det_bg_threshold_;
+  float det_fg_fraction_;
+  mutable int _cached_size_;
+  friend void  protobuf_InitDefaults_caffe_2eproto_impl();
+  friend void  protobuf_AddDesc_caffe_2eproto_impl();
+  friend void protobuf_AssignDesc_caffe_2eproto();
+  friend void protobuf_ShutdownFile_caffe_2eproto();
+
+  void InitAsDefaultInstance();
+};
+extern ::google::protobuf::internal::ExplicitlyConstructed<V0LayerParameter> V0LayerParameter_default_instance_;
+
+// -------------------------------------------------------------------
+
+class PReLUParameter : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:caffe.PReLUParameter) */ {
+ public:
+  PReLUParameter();
+  virtual ~PReLUParameter();
+
+  PReLUParameter(const PReLUParameter& from);
+
+  inline PReLUParameter& operator=(const PReLUParameter& from) {
+    CopyFrom(from);
+    return *this;
+  }
+
+  inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields();
+  }
+
+  inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields();
+  }
+
+  static const ::google::protobuf::Descriptor* descriptor();
+  static const PReLUParameter& default_instance();
+
+  static const PReLUParameter* internal_default_instance();
+
+  void Swap(PReLUParameter* other);
+
+  // implements Message ----------------------------------------------
+
+  inline PReLUParameter* New() const { return New(NULL); }
+
+  PReLUParameter* New(::google::protobuf::Arena* arena) const;
+  void CopyFrom(const ::google::protobuf::Message& from);
+  void MergeFrom(const ::google::protobuf::Message& from);
+  void CopyFrom(const PReLUParameter& from);
+  void MergeFrom(const PReLUParameter& from);
+  void Clear();
+  bool IsInitialized() const;
+
+  size_t ByteSizeLong() const;
+  bool MergePartialFromCodedStream(
+      ::google::protobuf::io::CodedInputStream* input);
+  void SerializeWithCachedSizes(
+      ::google::protobuf::io::CodedOutputStream* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
+  int GetCachedSize() const { return _cached_size_; }
+  private:
+  void SharedCtor();
+  void SharedDtor();
+  void SetCachedSize(int size) const;
+  void InternalSwap(PReLUParameter* other);
+  void UnsafeMergeFrom(const PReLUParameter& from);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
+  public:
+
+  ::google::protobuf::Metadata GetMetadata() const;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  // optional .caffe.FillerParameter filler = 1;
+  bool has_filler() const;
+  void clear_filler();
+  static const int kFillerFieldNumber = 1;
+  const ::caffe::FillerParameter& filler() const;
+  ::caffe::FillerParameter* mutable_filler();
+  ::caffe::FillerParameter* release_filler();
+  void set_allocated_filler(::caffe::FillerParameter* filler);
+
+  // optional bool channel_shared = 2 [default = false];
+  bool has_channel_shared() const;
+  void clear_channel_shared();
+  static const int kChannelSharedFieldNumber = 2;
+  bool channel_shared() const;
+  void set_channel_shared(bool value);
+
+  // @@protoc_insertion_point(class_scope:caffe.PReLUParameter)
+ private:
+  inline void set_has_filler();
+  inline void clear_has_filler();
+  inline void set_has_channel_shared();
+  inline void clear_has_channel_shared();
+
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  ::google::protobuf::internal::HasBits<1> _has_bits_;
+  mutable int _cached_size_;
+  ::caffe::FillerParameter* filler_;
+  bool channel_shared_;
+  friend void  protobuf_InitDefaults_caffe_2eproto_impl();
+  friend void  protobuf_AddDesc_caffe_2eproto_impl();
+  friend void protobuf_AssignDesc_caffe_2eproto();
+  friend void protobuf_ShutdownFile_caffe_2eproto();
+
+  void InitAsDefaultInstance();
+};
+extern ::google::protobuf::internal::ExplicitlyConstructed<PReLUParameter> PReLUParameter_default_instance_;
+
+// -------------------------------------------------------------------
+
+class NormalizedBBox : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:caffe.NormalizedBBox) */ {
+ public:
+  NormalizedBBox();
+  virtual ~NormalizedBBox();
+
+  NormalizedBBox(const NormalizedBBox& from);
+
+  inline NormalizedBBox& operator=(const NormalizedBBox& from) {
+    CopyFrom(from);
+    return *this;
+  }
+
+  inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields();
+  }
+
+  inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields();
+  }
+
+  static const ::google::protobuf::Descriptor* descriptor();
+  static const NormalizedBBox& default_instance();
+
+  static const NormalizedBBox* internal_default_instance();
+
+  void Swap(NormalizedBBox* other);
+
+  // implements Message ----------------------------------------------
+
+  inline NormalizedBBox* New() const { return New(NULL); }
+
+  NormalizedBBox* New(::google::protobuf::Arena* arena) const;
+  void CopyFrom(const ::google::protobuf::Message& from);
+  void MergeFrom(const ::google::protobuf::Message& from);
+  void CopyFrom(const NormalizedBBox& from);
+  void MergeFrom(const NormalizedBBox& from);
+  void Clear();
+  bool IsInitialized() const;
+
+  size_t ByteSizeLong() const;
+  bool MergePartialFromCodedStream(
+      ::google::protobuf::io::CodedInputStream* input);
+  void SerializeWithCachedSizes(
+      ::google::protobuf::io::CodedOutputStream* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
+  int GetCachedSize() const { return _cached_size_; }
+  private:
+  void SharedCtor();
+  void SharedDtor();
+  void SetCachedSize(int size) const;
+  void InternalSwap(NormalizedBBox* other);
+  void UnsafeMergeFrom(const NormalizedBBox& from);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
+  public:
+
+  ::google::protobuf::Metadata GetMetadata() const;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  // optional float xmin = 1;
+  bool has_xmin() const;
+  void clear_xmin();
+  static const int kXminFieldNumber = 1;
+  float xmin() const;
+  void set_xmin(float value);
+
+  // optional float ymin = 2;
+  bool has_ymin() const;
+  void clear_ymin();
+  static const int kYminFieldNumber = 2;
+  float ymin() const;
+  void set_ymin(float value);
+
+  // optional float xmax = 3;
+  bool has_xmax() const;
+  void clear_xmax();
+  static const int kXmaxFieldNumber = 3;
+  float xmax() const;
+  void set_xmax(float value);
+
+  // optional float ymax = 4;
+  bool has_ymax() const;
+  void clear_ymax();
+  static const int kYmaxFieldNumber = 4;
+  float ymax() const;
+  void set_ymax(float value);
+
+  // optional int32 label = 5;
+  bool has_label() const;
+  void clear_label();
+  static const int kLabelFieldNumber = 5;
+  ::google::protobuf::int32 label() const;
+  void set_label(::google::protobuf::int32 value);
+
+  // optional bool difficult = 6;
+  bool has_difficult() const;
+  void clear_difficult();
+  static const int kDifficultFieldNumber = 6;
+  bool difficult() const;
+  void set_difficult(bool value);
+
+  // optional float score = 7;
+  bool has_score() const;
+  void clear_score();
+  static const int kScoreFieldNumber = 7;
+  float score() const;
+  void set_score(float value);
+
+  // optional float size = 8;
+  bool has_size() const;
+  void clear_size();
+  static const int kSizeFieldNumber = 8;
+  float size() const;
+  void set_size(float value);
+
+  // @@protoc_insertion_point(class_scope:caffe.NormalizedBBox)
+ private:
+  inline void set_has_xmin();
+  inline void clear_has_xmin();
+  inline void set_has_ymin();
+  inline void clear_has_ymin();
+  inline void set_has_xmax();
+  inline void clear_has_xmax();
+  inline void set_has_ymax();
+  inline void clear_has_ymax();
+  inline void set_has_label();
+  inline void clear_has_label();
+  inline void set_has_difficult();
+  inline void clear_has_difficult();
+  inline void set_has_score();
+  inline void clear_has_score();
+  inline void set_has_size();
+  inline void clear_has_size();
+
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  ::google::protobuf::internal::HasBits<1> _has_bits_;
+  mutable int _cached_size_;
+  float xmin_;
+  float ymin_;
+  float xmax_;
+  float ymax_;
+  ::google::protobuf::int32 label_;
+  bool difficult_;
+  float score_;
+  float size_;
+  friend void  protobuf_InitDefaults_caffe_2eproto_impl();
+  friend void  protobuf_AddDesc_caffe_2eproto_impl();
+  friend void protobuf_AssignDesc_caffe_2eproto();
+  friend void protobuf_ShutdownFile_caffe_2eproto();
+
+  void InitAsDefaultInstance();
+};
+extern ::google::protobuf::internal::ExplicitlyConstructed<NormalizedBBox> NormalizedBBox_default_instance_;
+
+// ===================================================================
+
+
+// ===================================================================
+
+#if !PROTOBUF_INLINE_NOT_IN_HEADERS
+// BlobShape
+
+// repeated int64 dim = 1 [packed = true];
+inline int BlobShape::dim_size() const {
+  return dim_.size();
+}
+inline void BlobShape::clear_dim() {
+  dim_.Clear();
+}
+inline ::google::protobuf::int64 BlobShape::dim(int index) const {
+  // @@protoc_insertion_point(field_get:caffe.BlobShape.dim)
+  return dim_.Get(index);
+}
+inline void BlobShape::set_dim(int index, ::google::protobuf::int64 value) {
+  dim_.Set(index, value);
+  // @@protoc_insertion_point(field_set:caffe.BlobShape.dim)
+}
+inline void BlobShape::add_dim(::google::protobuf::int64 value) {
+  dim_.Add(value);
+  // @@protoc_insertion_point(field_add:caffe.BlobShape.dim)
+}
+inline const ::google::protobuf::RepeatedField< ::google::protobuf::int64 >&
+BlobShape::dim() const {
+  // @@protoc_insertion_point(field_list:caffe.BlobShape.dim)
+  return dim_;
+}
+inline ::google::protobuf::RepeatedField< ::google::protobuf::int64 >*
+BlobShape::mutable_dim() {
+  // @@protoc_insertion_point(field_mutable_list:caffe.BlobShape.dim)
+  return &dim_;
+}
+
+inline const BlobShape* BlobShape::internal_default_instance() {
+  return &BlobShape_default_instance_.get();
+}
+// -------------------------------------------------------------------
+
+// BlobProto
+
+// optional .caffe.BlobShape shape = 7;
+inline bool BlobProto::has_shape() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+inline void BlobProto::set_has_shape() {
+  _has_bits_[0] |= 0x00000001u;
+}
+inline void BlobProto::clear_has_shape() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+inline void BlobProto::clear_shape() {
+  if (shape_ != NULL) shape_->::caffe::BlobShape::Clear();
+  clear_has_shape();
+}
+inline const ::caffe::BlobShape& BlobProto::shape() const {
+  // @@protoc_insertion_point(field_get:caffe.BlobProto.shape)
+  return shape_ != NULL ? *shape_
+                         : *::caffe::BlobShape::internal_default_instance();
+}
+inline ::caffe::BlobShape* BlobProto::mutable_shape() {
+  set_has_shape();
+  if (shape_ == NULL) {
+    shape_ = new ::caffe::BlobShape;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.BlobProto.shape)
+  return shape_;
+}
+inline ::caffe::BlobShape* BlobProto::release_shape() {
+  // @@protoc_insertion_point(field_release:caffe.BlobProto.shape)
+  clear_has_shape();
+  ::caffe::BlobShape* temp = shape_;
+  shape_ = NULL;
+  return temp;
+}
+inline void BlobProto::set_allocated_shape(::caffe::BlobShape* shape) {
+  delete shape_;
+  shape_ = shape;
+  if (shape) {
+    set_has_shape();
+  } else {
+    clear_has_shape();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.BlobProto.shape)
+}
+
+// repeated float data = 5 [packed = true];
+inline int BlobProto::data_size() const {
+  return data_.size();
+}
+inline void BlobProto::clear_data() {
+  data_.Clear();
+}
+inline float BlobProto::data(int index) const {
+  // @@protoc_insertion_point(field_get:caffe.BlobProto.data)
+  return data_.Get(index);
+}
+inline void BlobProto::set_data(int index, float value) {
+  data_.Set(index, value);
+  // @@protoc_insertion_point(field_set:caffe.BlobProto.data)
+}
+inline void BlobProto::add_data(float value) {
+  data_.Add(value);
+  // @@protoc_insertion_point(field_add:caffe.BlobProto.data)
+}
+inline const ::google::protobuf::RepeatedField< float >&
+BlobProto::data() const {
+  // @@protoc_insertion_point(field_list:caffe.BlobProto.data)
+  return data_;
+}
+inline ::google::protobuf::RepeatedField< float >*
+BlobProto::mutable_data() {
+  // @@protoc_insertion_point(field_mutable_list:caffe.BlobProto.data)
+  return &data_;
+}
+
+// repeated float diff = 6 [packed = true];
+inline int BlobProto::diff_size() const {
+  return diff_.size();
+}
+inline void BlobProto::clear_diff() {
+  diff_.Clear();
+}
+inline float BlobProto::diff(int index) const {
+  // @@protoc_insertion_point(field_get:caffe.BlobProto.diff)
+  return diff_.Get(index);
+}
+inline void BlobProto::set_diff(int index, float value) {
+  diff_.Set(index, value);
+  // @@protoc_insertion_point(field_set:caffe.BlobProto.diff)
+}
+inline void BlobProto::add_diff(float value) {
+  diff_.Add(value);
+  // @@protoc_insertion_point(field_add:caffe.BlobProto.diff)
+}
+inline const ::google::protobuf::RepeatedField< float >&
+BlobProto::diff() const {
+  // @@protoc_insertion_point(field_list:caffe.BlobProto.diff)
+  return diff_;
+}
+inline ::google::protobuf::RepeatedField< float >*
+BlobProto::mutable_diff() {
+  // @@protoc_insertion_point(field_mutable_list:caffe.BlobProto.diff)
+  return &diff_;
+}
+
+// optional int32 num = 1 [default = 0];
+inline bool BlobProto::has_num() const {
+  return (_has_bits_[0] & 0x00000008u) != 0;
+}
+inline void BlobProto::set_has_num() {
+  _has_bits_[0] |= 0x00000008u;
+}
+inline void BlobProto::clear_has_num() {
+  _has_bits_[0] &= ~0x00000008u;
+}
+inline void BlobProto::clear_num() {
+  num_ = 0;
+  clear_has_num();
+}
+inline ::google::protobuf::int32 BlobProto::num() const {
+  // @@protoc_insertion_point(field_get:caffe.BlobProto.num)
+  return num_;
+}
+inline void BlobProto::set_num(::google::protobuf::int32 value) {
+  set_has_num();
+  num_ = value;
+  // @@protoc_insertion_point(field_set:caffe.BlobProto.num)
+}
+
+// optional int32 channels = 2 [default = 0];
+inline bool BlobProto::has_channels() const {
+  return (_has_bits_[0] & 0x00000010u) != 0;
+}
+inline void BlobProto::set_has_channels() {
+  _has_bits_[0] |= 0x00000010u;
+}
+inline void BlobProto::clear_has_channels() {
+  _has_bits_[0] &= ~0x00000010u;
+}
+inline void BlobProto::clear_channels() {
+  channels_ = 0;
+  clear_has_channels();
+}
+inline ::google::protobuf::int32 BlobProto::channels() const {
+  // @@protoc_insertion_point(field_get:caffe.BlobProto.channels)
+  return channels_;
+}
+inline void BlobProto::set_channels(::google::protobuf::int32 value) {
+  set_has_channels();
+  channels_ = value;
+  // @@protoc_insertion_point(field_set:caffe.BlobProto.channels)
+}
+
+// optional int32 height = 3 [default = 0];
+inline bool BlobProto::has_height() const {
+  return (_has_bits_[0] & 0x00000020u) != 0;
+}
+inline void BlobProto::set_has_height() {
+  _has_bits_[0] |= 0x00000020u;
+}
+inline void BlobProto::clear_has_height() {
+  _has_bits_[0] &= ~0x00000020u;
+}
+inline void BlobProto::clear_height() {
+  height_ = 0;
+  clear_has_height();
+}
+inline ::google::protobuf::int32 BlobProto::height() const {
+  // @@protoc_insertion_point(field_get:caffe.BlobProto.height)
+  return height_;
+}
+inline void BlobProto::set_height(::google::protobuf::int32 value) {
+  set_has_height();
+  height_ = value;
+  // @@protoc_insertion_point(field_set:caffe.BlobProto.height)
+}
+
+// optional int32 width = 4 [default = 0];
+inline bool BlobProto::has_width() const {
+  return (_has_bits_[0] & 0x00000040u) != 0;
+}
+inline void BlobProto::set_has_width() {
+  _has_bits_[0] |= 0x00000040u;
+}
+inline void BlobProto::clear_has_width() {
+  _has_bits_[0] &= ~0x00000040u;
+}
+inline void BlobProto::clear_width() {
+  width_ = 0;
+  clear_has_width();
+}
+inline ::google::protobuf::int32 BlobProto::width() const {
+  // @@protoc_insertion_point(field_get:caffe.BlobProto.width)
+  return width_;
+}
+inline void BlobProto::set_width(::google::protobuf::int32 value) {
+  set_has_width();
+  width_ = value;
+  // @@protoc_insertion_point(field_set:caffe.BlobProto.width)
+}
+
+inline const BlobProto* BlobProto::internal_default_instance() {
+  return &BlobProto_default_instance_.get();
+}
+// -------------------------------------------------------------------
+
+// BlobProtoVector
+
+// repeated .caffe.BlobProto blobs = 1;
+inline int BlobProtoVector::blobs_size() const {
+  return blobs_.size();
+}
+inline void BlobProtoVector::clear_blobs() {
+  blobs_.Clear();
+}
+inline const ::caffe::BlobProto& BlobProtoVector::blobs(int index) const {
+  // @@protoc_insertion_point(field_get:caffe.BlobProtoVector.blobs)
+  return blobs_.Get(index);
+}
+inline ::caffe::BlobProto* BlobProtoVector::mutable_blobs(int index) {
+  // @@protoc_insertion_point(field_mutable:caffe.BlobProtoVector.blobs)
+  return blobs_.Mutable(index);
+}
+inline ::caffe::BlobProto* BlobProtoVector::add_blobs() {
+  // @@protoc_insertion_point(field_add:caffe.BlobProtoVector.blobs)
+  return blobs_.Add();
+}
+inline ::google::protobuf::RepeatedPtrField< ::caffe::BlobProto >*
+BlobProtoVector::mutable_blobs() {
+  // @@protoc_insertion_point(field_mutable_list:caffe.BlobProtoVector.blobs)
+  return &blobs_;
+}
+inline const ::google::protobuf::RepeatedPtrField< ::caffe::BlobProto >&
+BlobProtoVector::blobs() const {
+  // @@protoc_insertion_point(field_list:caffe.BlobProtoVector.blobs)
+  return blobs_;
+}
+
+inline const BlobProtoVector* BlobProtoVector::internal_default_instance() {
+  return &BlobProtoVector_default_instance_.get();
+}
+// -------------------------------------------------------------------
+
+// CropParameter
+
+// optional int32 axis = 1 [default = 2];
+inline bool CropParameter::has_axis() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+inline void CropParameter::set_has_axis() {
+  _has_bits_[0] |= 0x00000001u;
+}
+inline void CropParameter::clear_has_axis() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+inline void CropParameter::clear_axis() {
+  axis_ = 2;
+  clear_has_axis();
+}
+inline ::google::protobuf::int32 CropParameter::axis() const {
+  // @@protoc_insertion_point(field_get:caffe.CropParameter.axis)
+  return axis_;
+}
+inline void CropParameter::set_axis(::google::protobuf::int32 value) {
+  set_has_axis();
+  axis_ = value;
+  // @@protoc_insertion_point(field_set:caffe.CropParameter.axis)
+}
+
+// repeated uint32 offset = 2;
+inline int CropParameter::offset_size() const {
+  return offset_.size();
+}
+inline void CropParameter::clear_offset() {
+  offset_.Clear();
+}
+inline ::google::protobuf::uint32 CropParameter::offset(int index) const {
+  // @@protoc_insertion_point(field_get:caffe.CropParameter.offset)
+  return offset_.Get(index);
+}
+inline void CropParameter::set_offset(int index, ::google::protobuf::uint32 value) {
+  offset_.Set(index, value);
+  // @@protoc_insertion_point(field_set:caffe.CropParameter.offset)
+}
+inline void CropParameter::add_offset(::google::protobuf::uint32 value) {
+  offset_.Add(value);
+  // @@protoc_insertion_point(field_add:caffe.CropParameter.offset)
+}
+inline const ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >&
+CropParameter::offset() const {
+  // @@protoc_insertion_point(field_list:caffe.CropParameter.offset)
+  return offset_;
+}
+inline ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >*
+CropParameter::mutable_offset() {
+  // @@protoc_insertion_point(field_mutable_list:caffe.CropParameter.offset)
+  return &offset_;
+}
+
+inline const CropParameter* CropParameter::internal_default_instance() {
+  return &CropParameter_default_instance_.get();
+}
+// -------------------------------------------------------------------
+
+// PermuteParameter
+
+// repeated uint32 order = 1;
+inline int PermuteParameter::order_size() const {
+  return order_.size();
+}
+inline void PermuteParameter::clear_order() {
+  order_.Clear();
+}
+inline ::google::protobuf::uint32 PermuteParameter::order(int index) const {
+  // @@protoc_insertion_point(field_get:caffe.PermuteParameter.order)
+  return order_.Get(index);
+}
+inline void PermuteParameter::set_order(int index, ::google::protobuf::uint32 value) {
+  order_.Set(index, value);
+  // @@protoc_insertion_point(field_set:caffe.PermuteParameter.order)
+}
+inline void PermuteParameter::add_order(::google::protobuf::uint32 value) {
+  order_.Add(value);
+  // @@protoc_insertion_point(field_add:caffe.PermuteParameter.order)
+}
+inline const ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >&
+PermuteParameter::order() const {
+  // @@protoc_insertion_point(field_list:caffe.PermuteParameter.order)
+  return order_;
+}
+inline ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >*
+PermuteParameter::mutable_order() {
+  // @@protoc_insertion_point(field_mutable_list:caffe.PermuteParameter.order)
+  return &order_;
+}
+
+inline const PermuteParameter* PermuteParameter::internal_default_instance() {
+  return &PermuteParameter_default_instance_.get();
+}
+// -------------------------------------------------------------------
+
+// NormalizeBBoxParameter
+
+// optional bool across_spatial = 1 [default = true];
+inline bool NormalizeBBoxParameter::has_across_spatial() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+inline void NormalizeBBoxParameter::set_has_across_spatial() {
+  _has_bits_[0] |= 0x00000001u;
+}
+inline void NormalizeBBoxParameter::clear_has_across_spatial() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+inline void NormalizeBBoxParameter::clear_across_spatial() {
+  across_spatial_ = true;
+  clear_has_across_spatial();
+}
+inline bool NormalizeBBoxParameter::across_spatial() const {
+  // @@protoc_insertion_point(field_get:caffe.NormalizeBBoxParameter.across_spatial)
+  return across_spatial_;
+}
+inline void NormalizeBBoxParameter::set_across_spatial(bool value) {
+  set_has_across_spatial();
+  across_spatial_ = value;
+  // @@protoc_insertion_point(field_set:caffe.NormalizeBBoxParameter.across_spatial)
+}
+
+// optional .caffe.FillerParameter scale_filler = 2;
+inline bool NormalizeBBoxParameter::has_scale_filler() const {
+  return (_has_bits_[0] & 0x00000002u) != 0;
+}
+inline void NormalizeBBoxParameter::set_has_scale_filler() {
+  _has_bits_[0] |= 0x00000002u;
+}
+inline void NormalizeBBoxParameter::clear_has_scale_filler() {
+  _has_bits_[0] &= ~0x00000002u;
+}
+inline void NormalizeBBoxParameter::clear_scale_filler() {
+  if (scale_filler_ != NULL) scale_filler_->::caffe::FillerParameter::Clear();
+  clear_has_scale_filler();
+}
+inline const ::caffe::FillerParameter& NormalizeBBoxParameter::scale_filler() const {
+  // @@protoc_insertion_point(field_get:caffe.NormalizeBBoxParameter.scale_filler)
+  return scale_filler_ != NULL ? *scale_filler_
+                         : *::caffe::FillerParameter::internal_default_instance();
+}
+inline ::caffe::FillerParameter* NormalizeBBoxParameter::mutable_scale_filler() {
+  set_has_scale_filler();
+  if (scale_filler_ == NULL) {
+    scale_filler_ = new ::caffe::FillerParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.NormalizeBBoxParameter.scale_filler)
+  return scale_filler_;
+}
+inline ::caffe::FillerParameter* NormalizeBBoxParameter::release_scale_filler() {
+  // @@protoc_insertion_point(field_release:caffe.NormalizeBBoxParameter.scale_filler)
+  clear_has_scale_filler();
+  ::caffe::FillerParameter* temp = scale_filler_;
+  scale_filler_ = NULL;
+  return temp;
+}
+inline void NormalizeBBoxParameter::set_allocated_scale_filler(::caffe::FillerParameter* scale_filler) {
+  delete scale_filler_;
+  scale_filler_ = scale_filler;
+  if (scale_filler) {
+    set_has_scale_filler();
+  } else {
+    clear_has_scale_filler();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.NormalizeBBoxParameter.scale_filler)
+}
+
+// optional bool channel_shared = 3 [default = true];
+inline bool NormalizeBBoxParameter::has_channel_shared() const {
+  return (_has_bits_[0] & 0x00000004u) != 0;
+}
+inline void NormalizeBBoxParameter::set_has_channel_shared() {
+  _has_bits_[0] |= 0x00000004u;
+}
+inline void NormalizeBBoxParameter::clear_has_channel_shared() {
+  _has_bits_[0] &= ~0x00000004u;
+}
+inline void NormalizeBBoxParameter::clear_channel_shared() {
+  channel_shared_ = true;
+  clear_has_channel_shared();
+}
+inline bool NormalizeBBoxParameter::channel_shared() const {
+  // @@protoc_insertion_point(field_get:caffe.NormalizeBBoxParameter.channel_shared)
+  return channel_shared_;
+}
+inline void NormalizeBBoxParameter::set_channel_shared(bool value) {
+  set_has_channel_shared();
+  channel_shared_ = value;
+  // @@protoc_insertion_point(field_set:caffe.NormalizeBBoxParameter.channel_shared)
+}
+
+// optional float eps = 4 [default = 1e-10];
+inline bool NormalizeBBoxParameter::has_eps() const {
+  return (_has_bits_[0] & 0x00000008u) != 0;
+}
+inline void NormalizeBBoxParameter::set_has_eps() {
+  _has_bits_[0] |= 0x00000008u;
+}
+inline void NormalizeBBoxParameter::clear_has_eps() {
+  _has_bits_[0] &= ~0x00000008u;
+}
+inline void NormalizeBBoxParameter::clear_eps() {
+  eps_ = 1e-10f;
+  clear_has_eps();
+}
+inline float NormalizeBBoxParameter::eps() const {
+  // @@protoc_insertion_point(field_get:caffe.NormalizeBBoxParameter.eps)
+  return eps_;
+}
+inline void NormalizeBBoxParameter::set_eps(float value) {
+  set_has_eps();
+  eps_ = value;
+  // @@protoc_insertion_point(field_set:caffe.NormalizeBBoxParameter.eps)
+}
+
+inline const NormalizeBBoxParameter* NormalizeBBoxParameter::internal_default_instance() {
+  return &NormalizeBBoxParameter_default_instance_.get();
+}
+// -------------------------------------------------------------------
+
+// PriorBoxParameter
+
+// optional float min_size = 1;
+inline bool PriorBoxParameter::has_min_size() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+inline void PriorBoxParameter::set_has_min_size() {
+  _has_bits_[0] |= 0x00000001u;
+}
+inline void PriorBoxParameter::clear_has_min_size() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+inline void PriorBoxParameter::clear_min_size() {
+  min_size_ = 0;
+  clear_has_min_size();
+}
+inline float PriorBoxParameter::min_size() const {
+  // @@protoc_insertion_point(field_get:caffe.PriorBoxParameter.min_size)
+  return min_size_;
+}
+inline void PriorBoxParameter::set_min_size(float value) {
+  set_has_min_size();
+  min_size_ = value;
+  // @@protoc_insertion_point(field_set:caffe.PriorBoxParameter.min_size)
+}
+
+// optional float max_size = 2;
+inline bool PriorBoxParameter::has_max_size() const {
+  return (_has_bits_[0] & 0x00000002u) != 0;
+}
+inline void PriorBoxParameter::set_has_max_size() {
+  _has_bits_[0] |= 0x00000002u;
+}
+inline void PriorBoxParameter::clear_has_max_size() {
+  _has_bits_[0] &= ~0x00000002u;
+}
+inline void PriorBoxParameter::clear_max_size() {
+  max_size_ = 0;
+  clear_has_max_size();
+}
+inline float PriorBoxParameter::max_size() const {
+  // @@protoc_insertion_point(field_get:caffe.PriorBoxParameter.max_size)
+  return max_size_;
+}
+inline void PriorBoxParameter::set_max_size(float value) {
+  set_has_max_size();
+  max_size_ = value;
+  // @@protoc_insertion_point(field_set:caffe.PriorBoxParameter.max_size)
+}
+
+// repeated float aspect_ratio = 3;
+inline int PriorBoxParameter::aspect_ratio_size() const {
+  return aspect_ratio_.size();
+}
+inline void PriorBoxParameter::clear_aspect_ratio() {
+  aspect_ratio_.Clear();
+}
+inline float PriorBoxParameter::aspect_ratio(int index) const {
+  // @@protoc_insertion_point(field_get:caffe.PriorBoxParameter.aspect_ratio)
+  return aspect_ratio_.Get(index);
+}
+inline void PriorBoxParameter::set_aspect_ratio(int index, float value) {
+  aspect_ratio_.Set(index, value);
+  // @@protoc_insertion_point(field_set:caffe.PriorBoxParameter.aspect_ratio)
+}
+inline void PriorBoxParameter::add_aspect_ratio(float value) {
+  aspect_ratio_.Add(value);
+  // @@protoc_insertion_point(field_add:caffe.PriorBoxParameter.aspect_ratio)
+}
+inline const ::google::protobuf::RepeatedField< float >&
+PriorBoxParameter::aspect_ratio() const {
+  // @@protoc_insertion_point(field_list:caffe.PriorBoxParameter.aspect_ratio)
+  return aspect_ratio_;
+}
+inline ::google::protobuf::RepeatedField< float >*
+PriorBoxParameter::mutable_aspect_ratio() {
+  // @@protoc_insertion_point(field_mutable_list:caffe.PriorBoxParameter.aspect_ratio)
+  return &aspect_ratio_;
+}
+
+// optional bool flip = 4 [default = true];
+inline bool PriorBoxParameter::has_flip() const {
+  return (_has_bits_[0] & 0x00000008u) != 0;
+}
+inline void PriorBoxParameter::set_has_flip() {
+  _has_bits_[0] |= 0x00000008u;
+}
+inline void PriorBoxParameter::clear_has_flip() {
+  _has_bits_[0] &= ~0x00000008u;
+}
+inline void PriorBoxParameter::clear_flip() {
+  flip_ = true;
+  clear_has_flip();
+}
+inline bool PriorBoxParameter::flip() const {
+  // @@protoc_insertion_point(field_get:caffe.PriorBoxParameter.flip)
+  return flip_;
+}
+inline void PriorBoxParameter::set_flip(bool value) {
+  set_has_flip();
+  flip_ = value;
+  // @@protoc_insertion_point(field_set:caffe.PriorBoxParameter.flip)
+}
+
+// optional bool clip = 5 [default = true];
+inline bool PriorBoxParameter::has_clip() const {
+  return (_has_bits_[0] & 0x00000010u) != 0;
+}
+inline void PriorBoxParameter::set_has_clip() {
+  _has_bits_[0] |= 0x00000010u;
+}
+inline void PriorBoxParameter::clear_has_clip() {
+  _has_bits_[0] &= ~0x00000010u;
+}
+inline void PriorBoxParameter::clear_clip() {
+  clip_ = true;
+  clear_has_clip();
+}
+inline bool PriorBoxParameter::clip() const {
+  // @@protoc_insertion_point(field_get:caffe.PriorBoxParameter.clip)
+  return clip_;
+}
+inline void PriorBoxParameter::set_clip(bool value) {
+  set_has_clip();
+  clip_ = value;
+  // @@protoc_insertion_point(field_set:caffe.PriorBoxParameter.clip)
+}
+
+// repeated float variance = 6;
+inline int PriorBoxParameter::variance_size() const {
+  return variance_.size();
+}
+inline void PriorBoxParameter::clear_variance() {
+  variance_.Clear();
+}
+inline float PriorBoxParameter::variance(int index) const {
+  // @@protoc_insertion_point(field_get:caffe.PriorBoxParameter.variance)
+  return variance_.Get(index);
+}
+inline void PriorBoxParameter::set_variance(int index, float value) {
+  variance_.Set(index, value);
+  // @@protoc_insertion_point(field_set:caffe.PriorBoxParameter.variance)
+}
+inline void PriorBoxParameter::add_variance(float value) {
+  variance_.Add(value);
+  // @@protoc_insertion_point(field_add:caffe.PriorBoxParameter.variance)
+}
+inline const ::google::protobuf::RepeatedField< float >&
+PriorBoxParameter::variance() const {
+  // @@protoc_insertion_point(field_list:caffe.PriorBoxParameter.variance)
+  return variance_;
+}
+inline ::google::protobuf::RepeatedField< float >*
+PriorBoxParameter::mutable_variance() {
+  // @@protoc_insertion_point(field_mutable_list:caffe.PriorBoxParameter.variance)
+  return &variance_;
+}
+
+inline const PriorBoxParameter* PriorBoxParameter::internal_default_instance() {
+  return &PriorBoxParameter_default_instance_.get();
+}
+// -------------------------------------------------------------------
+
+// DetectionOutputParameter
+
+// optional uint32 num_classes = 1;
+inline bool DetectionOutputParameter::has_num_classes() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+inline void DetectionOutputParameter::set_has_num_classes() {
+  _has_bits_[0] |= 0x00000001u;
+}
+inline void DetectionOutputParameter::clear_has_num_classes() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+inline void DetectionOutputParameter::clear_num_classes() {
+  num_classes_ = 0u;
+  clear_has_num_classes();
+}
+inline ::google::protobuf::uint32 DetectionOutputParameter::num_classes() const {
+  // @@protoc_insertion_point(field_get:caffe.DetectionOutputParameter.num_classes)
+  return num_classes_;
+}
+inline void DetectionOutputParameter::set_num_classes(::google::protobuf::uint32 value) {
+  set_has_num_classes();
+  num_classes_ = value;
+  // @@protoc_insertion_point(field_set:caffe.DetectionOutputParameter.num_classes)
+}
+
+// optional bool share_location = 2 [default = true];
+inline bool DetectionOutputParameter::has_share_location() const {
+  return (_has_bits_[0] & 0x00000002u) != 0;
+}
+inline void DetectionOutputParameter::set_has_share_location() {
+  _has_bits_[0] |= 0x00000002u;
+}
+inline void DetectionOutputParameter::clear_has_share_location() {
+  _has_bits_[0] &= ~0x00000002u;
+}
+inline void DetectionOutputParameter::clear_share_location() {
+  share_location_ = true;
+  clear_has_share_location();
+}
+inline bool DetectionOutputParameter::share_location() const {
+  // @@protoc_insertion_point(field_get:caffe.DetectionOutputParameter.share_location)
+  return share_location_;
+}
+inline void DetectionOutputParameter::set_share_location(bool value) {
+  set_has_share_location();
+  share_location_ = value;
+  // @@protoc_insertion_point(field_set:caffe.DetectionOutputParameter.share_location)
+}
+
+// optional int32 background_label_id = 3 [default = 0];
+inline bool DetectionOutputParameter::has_background_label_id() const {
+  return (_has_bits_[0] & 0x00000004u) != 0;
+}
+inline void DetectionOutputParameter::set_has_background_label_id() {
+  _has_bits_[0] |= 0x00000004u;
+}
+inline void DetectionOutputParameter::clear_has_background_label_id() {
+  _has_bits_[0] &= ~0x00000004u;
+}
+inline void DetectionOutputParameter::clear_background_label_id() {
+  background_label_id_ = 0;
+  clear_has_background_label_id();
+}
+inline ::google::protobuf::int32 DetectionOutputParameter::background_label_id() const {
+  // @@protoc_insertion_point(field_get:caffe.DetectionOutputParameter.background_label_id)
+  return background_label_id_;
+}
+inline void DetectionOutputParameter::set_background_label_id(::google::protobuf::int32 value) {
+  set_has_background_label_id();
+  background_label_id_ = value;
+  // @@protoc_insertion_point(field_set:caffe.DetectionOutputParameter.background_label_id)
+}
+
+// optional .caffe.PriorBoxParameter.CodeType code_type = 6 [default = CORNER];
+inline bool DetectionOutputParameter::has_code_type() const {
+  return (_has_bits_[0] & 0x00000008u) != 0;
+}
+inline void DetectionOutputParameter::set_has_code_type() {
+  _has_bits_[0] |= 0x00000008u;
+}
+inline void DetectionOutputParameter::clear_has_code_type() {
+  _has_bits_[0] &= ~0x00000008u;
+}
+inline void DetectionOutputParameter::clear_code_type() {
+  code_type_ = 1;
+  clear_has_code_type();
+}
+inline ::caffe::PriorBoxParameter_CodeType DetectionOutputParameter::code_type() const {
+  // @@protoc_insertion_point(field_get:caffe.DetectionOutputParameter.code_type)
+  return static_cast< ::caffe::PriorBoxParameter_CodeType >(code_type_);
+}
+inline void DetectionOutputParameter::set_code_type(::caffe::PriorBoxParameter_CodeType value) {
+  assert(::caffe::PriorBoxParameter_CodeType_IsValid(value));
+  set_has_code_type();
+  code_type_ = value;
+  // @@protoc_insertion_point(field_set:caffe.DetectionOutputParameter.code_type)
+}
+
+// optional bool variance_encoded_in_target = 8 [default = false];
+inline bool DetectionOutputParameter::has_variance_encoded_in_target() const {
+  return (_has_bits_[0] & 0x00000010u) != 0;
+}
+inline void DetectionOutputParameter::set_has_variance_encoded_in_target() {
+  _has_bits_[0] |= 0x00000010u;
+}
+inline void DetectionOutputParameter::clear_has_variance_encoded_in_target() {
+  _has_bits_[0] &= ~0x00000010u;
+}
+inline void DetectionOutputParameter::clear_variance_encoded_in_target() {
+  variance_encoded_in_target_ = false;
+  clear_has_variance_encoded_in_target();
+}
+inline bool DetectionOutputParameter::variance_encoded_in_target() const {
+  // @@protoc_insertion_point(field_get:caffe.DetectionOutputParameter.variance_encoded_in_target)
+  return variance_encoded_in_target_;
+}
+inline void DetectionOutputParameter::set_variance_encoded_in_target(bool value) {
+  set_has_variance_encoded_in_target();
+  variance_encoded_in_target_ = value;
+  // @@protoc_insertion_point(field_set:caffe.DetectionOutputParameter.variance_encoded_in_target)
+}
+
+// optional int32 keep_top_k = 7 [default = -1];
+inline bool DetectionOutputParameter::has_keep_top_k() const {
+  return (_has_bits_[0] & 0x00000020u) != 0;
+}
+inline void DetectionOutputParameter::set_has_keep_top_k() {
+  _has_bits_[0] |= 0x00000020u;
+}
+inline void DetectionOutputParameter::clear_has_keep_top_k() {
+  _has_bits_[0] &= ~0x00000020u;
+}
+inline void DetectionOutputParameter::clear_keep_top_k() {
+  keep_top_k_ = -1;
+  clear_has_keep_top_k();
+}
+inline ::google::protobuf::int32 DetectionOutputParameter::keep_top_k() const {
+  // @@protoc_insertion_point(field_get:caffe.DetectionOutputParameter.keep_top_k)
+  return keep_top_k_;
+}
+inline void DetectionOutputParameter::set_keep_top_k(::google::protobuf::int32 value) {
+  set_has_keep_top_k();
+  keep_top_k_ = value;
+  // @@protoc_insertion_point(field_set:caffe.DetectionOutputParameter.keep_top_k)
+}
+
+// optional float confidence_threshold = 9;
+inline bool DetectionOutputParameter::has_confidence_threshold() const {
+  return (_has_bits_[0] & 0x00000040u) != 0;
+}
+inline void DetectionOutputParameter::set_has_confidence_threshold() {
+  _has_bits_[0] |= 0x00000040u;
+}
+inline void DetectionOutputParameter::clear_has_confidence_threshold() {
+  _has_bits_[0] &= ~0x00000040u;
+}
+inline void DetectionOutputParameter::clear_confidence_threshold() {
+  confidence_threshold_ = 0;
+  clear_has_confidence_threshold();
+}
+inline float DetectionOutputParameter::confidence_threshold() const {
+  // @@protoc_insertion_point(field_get:caffe.DetectionOutputParameter.confidence_threshold)
+  return confidence_threshold_;
+}
+inline void DetectionOutputParameter::set_confidence_threshold(float value) {
+  set_has_confidence_threshold();
+  confidence_threshold_ = value;
+  // @@protoc_insertion_point(field_set:caffe.DetectionOutputParameter.confidence_threshold)
+}
+
+// optional float nms_threshold = 10 [default = 0.3];
+inline bool DetectionOutputParameter::has_nms_threshold() const {
+  return (_has_bits_[0] & 0x00000080u) != 0;
+}
+inline void DetectionOutputParameter::set_has_nms_threshold() {
+  _has_bits_[0] |= 0x00000080u;
+}
+inline void DetectionOutputParameter::clear_has_nms_threshold() {
+  _has_bits_[0] &= ~0x00000080u;
+}
+inline void DetectionOutputParameter::clear_nms_threshold() {
+  nms_threshold_ = 0.3f;
+  clear_has_nms_threshold();
+}
+inline float DetectionOutputParameter::nms_threshold() const {
+  // @@protoc_insertion_point(field_get:caffe.DetectionOutputParameter.nms_threshold)
+  return nms_threshold_;
+}
+inline void DetectionOutputParameter::set_nms_threshold(float value) {
+  set_has_nms_threshold();
+  nms_threshold_ = value;
+  // @@protoc_insertion_point(field_set:caffe.DetectionOutputParameter.nms_threshold)
+}
+
+// optional int32 top_k = 11;
+inline bool DetectionOutputParameter::has_top_k() const {
+  return (_has_bits_[0] & 0x00000100u) != 0;
+}
+inline void DetectionOutputParameter::set_has_top_k() {
+  _has_bits_[0] |= 0x00000100u;
+}
+inline void DetectionOutputParameter::clear_has_top_k() {
+  _has_bits_[0] &= ~0x00000100u;
+}
+inline void DetectionOutputParameter::clear_top_k() {
+  top_k_ = 0;
+  clear_has_top_k();
+}
+inline ::google::protobuf::int32 DetectionOutputParameter::top_k() const {
+  // @@protoc_insertion_point(field_get:caffe.DetectionOutputParameter.top_k)
+  return top_k_;
+}
+inline void DetectionOutputParameter::set_top_k(::google::protobuf::int32 value) {
+  set_has_top_k();
+  top_k_ = value;
+  // @@protoc_insertion_point(field_set:caffe.DetectionOutputParameter.top_k)
+}
+
+inline const DetectionOutputParameter* DetectionOutputParameter::internal_default_instance() {
+  return &DetectionOutputParameter_default_instance_.get();
+}
+// -------------------------------------------------------------------
+
+// Datum
+
+// optional int32 channels = 1;
+inline bool Datum::has_channels() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+inline void Datum::set_has_channels() {
+  _has_bits_[0] |= 0x00000001u;
+}
+inline void Datum::clear_has_channels() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+inline void Datum::clear_channels() {
+  channels_ = 0;
+  clear_has_channels();
+}
+inline ::google::protobuf::int32 Datum::channels() const {
+  // @@protoc_insertion_point(field_get:caffe.Datum.channels)
+  return channels_;
+}
+inline void Datum::set_channels(::google::protobuf::int32 value) {
+  set_has_channels();
+  channels_ = value;
+  // @@protoc_insertion_point(field_set:caffe.Datum.channels)
+}
+
+// optional int32 height = 2;
+inline bool Datum::has_height() const {
+  return (_has_bits_[0] & 0x00000002u) != 0;
+}
+inline void Datum::set_has_height() {
+  _has_bits_[0] |= 0x00000002u;
+}
+inline void Datum::clear_has_height() {
+  _has_bits_[0] &= ~0x00000002u;
+}
+inline void Datum::clear_height() {
+  height_ = 0;
+  clear_has_height();
+}
+inline ::google::protobuf::int32 Datum::height() const {
+  // @@protoc_insertion_point(field_get:caffe.Datum.height)
+  return height_;
+}
+inline void Datum::set_height(::google::protobuf::int32 value) {
+  set_has_height();
+  height_ = value;
+  // @@protoc_insertion_point(field_set:caffe.Datum.height)
+}
+
+// optional int32 width = 3;
+inline bool Datum::has_width() const {
+  return (_has_bits_[0] & 0x00000004u) != 0;
+}
+inline void Datum::set_has_width() {
+  _has_bits_[0] |= 0x00000004u;
+}
+inline void Datum::clear_has_width() {
+  _has_bits_[0] &= ~0x00000004u;
+}
+inline void Datum::clear_width() {
+  width_ = 0;
+  clear_has_width();
+}
+inline ::google::protobuf::int32 Datum::width() const {
+  // @@protoc_insertion_point(field_get:caffe.Datum.width)
+  return width_;
+}
+inline void Datum::set_width(::google::protobuf::int32 value) {
+  set_has_width();
+  width_ = value;
+  // @@protoc_insertion_point(field_set:caffe.Datum.width)
+}
+
+// optional bytes data = 4;
+inline bool Datum::has_data() const {
+  return (_has_bits_[0] & 0x00000008u) != 0;
+}
+inline void Datum::set_has_data() {
+  _has_bits_[0] |= 0x00000008u;
+}
+inline void Datum::clear_has_data() {
+  _has_bits_[0] &= ~0x00000008u;
+}
+inline void Datum::clear_data() {
+  data_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  clear_has_data();
+}
+inline const ::std::string& Datum::data() const {
+  // @@protoc_insertion_point(field_get:caffe.Datum.data)
+  return data_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void Datum::set_data(const ::std::string& value) {
+  set_has_data();
+  data_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:caffe.Datum.data)
+}
+inline void Datum::set_data(const char* value) {
+  set_has_data();
+  data_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:caffe.Datum.data)
+}
+inline void Datum::set_data(const void* value, size_t size) {
+  set_has_data();
+  data_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:caffe.Datum.data)
+}
+inline ::std::string* Datum::mutable_data() {
+  set_has_data();
+  // @@protoc_insertion_point(field_mutable:caffe.Datum.data)
+  return data_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline ::std::string* Datum::release_data() {
+  // @@protoc_insertion_point(field_release:caffe.Datum.data)
+  clear_has_data();
+  return data_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void Datum::set_allocated_data(::std::string* data) {
+  if (data != NULL) {
+    set_has_data();
+  } else {
+    clear_has_data();
+  }
+  data_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), data);
+  // @@protoc_insertion_point(field_set_allocated:caffe.Datum.data)
+}
+
+// optional int32 label = 5;
+inline bool Datum::has_label() const {
+  return (_has_bits_[0] & 0x00000010u) != 0;
+}
+inline void Datum::set_has_label() {
+  _has_bits_[0] |= 0x00000010u;
+}
+inline void Datum::clear_has_label() {
+  _has_bits_[0] &= ~0x00000010u;
+}
+inline void Datum::clear_label() {
+  label_ = 0;
+  clear_has_label();
+}
+inline ::google::protobuf::int32 Datum::label() const {
+  // @@protoc_insertion_point(field_get:caffe.Datum.label)
+  return label_;
+}
+inline void Datum::set_label(::google::protobuf::int32 value) {
+  set_has_label();
+  label_ = value;
+  // @@protoc_insertion_point(field_set:caffe.Datum.label)
+}
+
+// repeated float float_data = 6;
+inline int Datum::float_data_size() const {
+  return float_data_.size();
+}
+inline void Datum::clear_float_data() {
+  float_data_.Clear();
+}
+inline float Datum::float_data(int index) const {
+  // @@protoc_insertion_point(field_get:caffe.Datum.float_data)
+  return float_data_.Get(index);
+}
+inline void Datum::set_float_data(int index, float value) {
+  float_data_.Set(index, value);
+  // @@protoc_insertion_point(field_set:caffe.Datum.float_data)
+}
+inline void Datum::add_float_data(float value) {
+  float_data_.Add(value);
+  // @@protoc_insertion_point(field_add:caffe.Datum.float_data)
+}
+inline const ::google::protobuf::RepeatedField< float >&
+Datum::float_data() const {
+  // @@protoc_insertion_point(field_list:caffe.Datum.float_data)
+  return float_data_;
+}
+inline ::google::protobuf::RepeatedField< float >*
+Datum::mutable_float_data() {
+  // @@protoc_insertion_point(field_mutable_list:caffe.Datum.float_data)
+  return &float_data_;
+}
+
+// optional bool encoded = 7 [default = false];
+inline bool Datum::has_encoded() const {
+  return (_has_bits_[0] & 0x00000040u) != 0;
+}
+inline void Datum::set_has_encoded() {
+  _has_bits_[0] |= 0x00000040u;
+}
+inline void Datum::clear_has_encoded() {
+  _has_bits_[0] &= ~0x00000040u;
+}
+inline void Datum::clear_encoded() {
+  encoded_ = false;
+  clear_has_encoded();
+}
+inline bool Datum::encoded() const {
+  // @@protoc_insertion_point(field_get:caffe.Datum.encoded)
+  return encoded_;
+}
+inline void Datum::set_encoded(bool value) {
+  set_has_encoded();
+  encoded_ = value;
+  // @@protoc_insertion_point(field_set:caffe.Datum.encoded)
+}
+
+inline const Datum* Datum::internal_default_instance() {
+  return &Datum_default_instance_.get();
+}
+// -------------------------------------------------------------------
+
+// FillerParameter
+
+// optional string type = 1 [default = "constant"];
+inline bool FillerParameter::has_type() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+inline void FillerParameter::set_has_type() {
+  _has_bits_[0] |= 0x00000001u;
+}
+inline void FillerParameter::clear_has_type() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+inline void FillerParameter::clear_type() {
+  type_.ClearToDefaultNoArena(_default_type_);
+  clear_has_type();
+}
+inline const ::std::string& FillerParameter::type() const {
+  // @@protoc_insertion_point(field_get:caffe.FillerParameter.type)
+  return type_.GetNoArena(_default_type_);
+}
+inline void FillerParameter::set_type(const ::std::string& value) {
+  set_has_type();
+  type_.SetNoArena(_default_type_, value);
+  // @@protoc_insertion_point(field_set:caffe.FillerParameter.type)
+}
+inline void FillerParameter::set_type(const char* value) {
+  set_has_type();
+  type_.SetNoArena(_default_type_, ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:caffe.FillerParameter.type)
+}
+inline void FillerParameter::set_type(const char* value, size_t size) {
+  set_has_type();
+  type_.SetNoArena(_default_type_,
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:caffe.FillerParameter.type)
+}
+inline ::std::string* FillerParameter::mutable_type() {
+  set_has_type();
+  // @@protoc_insertion_point(field_mutable:caffe.FillerParameter.type)
+  return type_.MutableNoArena(_default_type_);
+}
+inline ::std::string* FillerParameter::release_type() {
+  // @@protoc_insertion_point(field_release:caffe.FillerParameter.type)
+  clear_has_type();
+  return type_.ReleaseNoArena(_default_type_);
+}
+inline void FillerParameter::set_allocated_type(::std::string* type) {
+  if (type != NULL) {
+    set_has_type();
+  } else {
+    clear_has_type();
+  }
+  type_.SetAllocatedNoArena(_default_type_, type);
+  // @@protoc_insertion_point(field_set_allocated:caffe.FillerParameter.type)
+}
+
+// optional float value = 2 [default = 0];
+inline bool FillerParameter::has_value() const {
+  return (_has_bits_[0] & 0x00000002u) != 0;
+}
+inline void FillerParameter::set_has_value() {
+  _has_bits_[0] |= 0x00000002u;
+}
+inline void FillerParameter::clear_has_value() {
+  _has_bits_[0] &= ~0x00000002u;
+}
+inline void FillerParameter::clear_value() {
+  value_ = 0;
+  clear_has_value();
+}
+inline float FillerParameter::value() const {
+  // @@protoc_insertion_point(field_get:caffe.FillerParameter.value)
+  return value_;
+}
+inline void FillerParameter::set_value(float value) {
+  set_has_value();
+  value_ = value;
+  // @@protoc_insertion_point(field_set:caffe.FillerParameter.value)
+}
+
+// optional float min = 3 [default = 0];
+inline bool FillerParameter::has_min() const {
+  return (_has_bits_[0] & 0x00000004u) != 0;
+}
+inline void FillerParameter::set_has_min() {
+  _has_bits_[0] |= 0x00000004u;
+}
+inline void FillerParameter::clear_has_min() {
+  _has_bits_[0] &= ~0x00000004u;
+}
+inline void FillerParameter::clear_min() {
+  min_ = 0;
+  clear_has_min();
+}
+inline float FillerParameter::min() const {
+  // @@protoc_insertion_point(field_get:caffe.FillerParameter.min)
+  return min_;
+}
+inline void FillerParameter::set_min(float value) {
+  set_has_min();
+  min_ = value;
+  // @@protoc_insertion_point(field_set:caffe.FillerParameter.min)
+}
+
+// optional float max = 4 [default = 1];
+inline bool FillerParameter::has_max() const {
+  return (_has_bits_[0] & 0x00000008u) != 0;
+}
+inline void FillerParameter::set_has_max() {
+  _has_bits_[0] |= 0x00000008u;
+}
+inline void FillerParameter::clear_has_max() {
+  _has_bits_[0] &= ~0x00000008u;
+}
+inline void FillerParameter::clear_max() {
+  max_ = 1;
+  clear_has_max();
+}
+inline float FillerParameter::max() const {
+  // @@protoc_insertion_point(field_get:caffe.FillerParameter.max)
+  return max_;
+}
+inline void FillerParameter::set_max(float value) {
+  set_has_max();
+  max_ = value;
+  // @@protoc_insertion_point(field_set:caffe.FillerParameter.max)
+}
+
+// optional float mean = 5 [default = 0];
+inline bool FillerParameter::has_mean() const {
+  return (_has_bits_[0] & 0x00000010u) != 0;
+}
+inline void FillerParameter::set_has_mean() {
+  _has_bits_[0] |= 0x00000010u;
+}
+inline void FillerParameter::clear_has_mean() {
+  _has_bits_[0] &= ~0x00000010u;
+}
+inline void FillerParameter::clear_mean() {
+  mean_ = 0;
+  clear_has_mean();
+}
+inline float FillerParameter::mean() const {
+  // @@protoc_insertion_point(field_get:caffe.FillerParameter.mean)
+  return mean_;
+}
+inline void FillerParameter::set_mean(float value) {
+  set_has_mean();
+  mean_ = value;
+  // @@protoc_insertion_point(field_set:caffe.FillerParameter.mean)
+}
+
+// optional float std = 6 [default = 1];
+inline bool FillerParameter::has_std() const {
+  return (_has_bits_[0] & 0x00000020u) != 0;
+}
+inline void FillerParameter::set_has_std() {
+  _has_bits_[0] |= 0x00000020u;
+}
+inline void FillerParameter::clear_has_std() {
+  _has_bits_[0] &= ~0x00000020u;
+}
+inline void FillerParameter::clear_std() {
+  std_ = 1;
+  clear_has_std();
+}
+inline float FillerParameter::std() const {
+  // @@protoc_insertion_point(field_get:caffe.FillerParameter.std)
+  return std_;
+}
+inline void FillerParameter::set_std(float value) {
+  set_has_std();
+  std_ = value;
+  // @@protoc_insertion_point(field_set:caffe.FillerParameter.std)
+}
+
+// optional int32 sparse = 7 [default = -1];
+inline bool FillerParameter::has_sparse() const {
+  return (_has_bits_[0] & 0x00000040u) != 0;
+}
+inline void FillerParameter::set_has_sparse() {
+  _has_bits_[0] |= 0x00000040u;
+}
+inline void FillerParameter::clear_has_sparse() {
+  _has_bits_[0] &= ~0x00000040u;
+}
+inline void FillerParameter::clear_sparse() {
+  sparse_ = -1;
+  clear_has_sparse();
+}
+inline ::google::protobuf::int32 FillerParameter::sparse() const {
+  // @@protoc_insertion_point(field_get:caffe.FillerParameter.sparse)
+  return sparse_;
+}
+inline void FillerParameter::set_sparse(::google::protobuf::int32 value) {
+  set_has_sparse();
+  sparse_ = value;
+  // @@protoc_insertion_point(field_set:caffe.FillerParameter.sparse)
+}
+
+// optional .caffe.FillerParameter.VarianceNorm variance_norm = 8 [default = FAN_IN];
+inline bool FillerParameter::has_variance_norm() const {
+  return (_has_bits_[0] & 0x00000080u) != 0;
+}
+inline void FillerParameter::set_has_variance_norm() {
+  _has_bits_[0] |= 0x00000080u;
+}
+inline void FillerParameter::clear_has_variance_norm() {
+  _has_bits_[0] &= ~0x00000080u;
+}
+inline void FillerParameter::clear_variance_norm() {
+  variance_norm_ = 0;
+  clear_has_variance_norm();
+}
+inline ::caffe::FillerParameter_VarianceNorm FillerParameter::variance_norm() const {
+  // @@protoc_insertion_point(field_get:caffe.FillerParameter.variance_norm)
+  return static_cast< ::caffe::FillerParameter_VarianceNorm >(variance_norm_);
+}
+inline void FillerParameter::set_variance_norm(::caffe::FillerParameter_VarianceNorm value) {
+  assert(::caffe::FillerParameter_VarianceNorm_IsValid(value));
+  set_has_variance_norm();
+  variance_norm_ = value;
+  // @@protoc_insertion_point(field_set:caffe.FillerParameter.variance_norm)
+}
+
+inline const FillerParameter* FillerParameter::internal_default_instance() {
+  return &FillerParameter_default_instance_.get();
+}
+// -------------------------------------------------------------------
+
+// NetParameter
+
+// optional string name = 1;
+inline bool NetParameter::has_name() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+inline void NetParameter::set_has_name() {
+  _has_bits_[0] |= 0x00000001u;
+}
+inline void NetParameter::clear_has_name() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+inline void NetParameter::clear_name() {
+  name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  clear_has_name();
+}
+inline const ::std::string& NetParameter::name() const {
+  // @@protoc_insertion_point(field_get:caffe.NetParameter.name)
+  return name_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void NetParameter::set_name(const ::std::string& value) {
+  set_has_name();
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:caffe.NetParameter.name)
+}
+inline void NetParameter::set_name(const char* value) {
+  set_has_name();
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:caffe.NetParameter.name)
+}
+inline void NetParameter::set_name(const char* value, size_t size) {
+  set_has_name();
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:caffe.NetParameter.name)
+}
+inline ::std::string* NetParameter::mutable_name() {
+  set_has_name();
+  // @@protoc_insertion_point(field_mutable:caffe.NetParameter.name)
+  return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline ::std::string* NetParameter::release_name() {
+  // @@protoc_insertion_point(field_release:caffe.NetParameter.name)
+  clear_has_name();
+  return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void NetParameter::set_allocated_name(::std::string* name) {
+  if (name != NULL) {
+    set_has_name();
+  } else {
+    clear_has_name();
+  }
+  name_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), name);
+  // @@protoc_insertion_point(field_set_allocated:caffe.NetParameter.name)
+}
+
+// repeated string input = 3;
+inline int NetParameter::input_size() const {
+  return input_.size();
+}
+inline void NetParameter::clear_input() {
+  input_.Clear();
+}
+inline const ::std::string& NetParameter::input(int index) const {
+  // @@protoc_insertion_point(field_get:caffe.NetParameter.input)
+  return input_.Get(index);
+}
+inline ::std::string* NetParameter::mutable_input(int index) {
+  // @@protoc_insertion_point(field_mutable:caffe.NetParameter.input)
+  return input_.Mutable(index);
+}
+inline void NetParameter::set_input(int index, const ::std::string& value) {
+  // @@protoc_insertion_point(field_set:caffe.NetParameter.input)
+  input_.Mutable(index)->assign(value);
+}
+inline void NetParameter::set_input(int index, const char* value) {
+  input_.Mutable(index)->assign(value);
+  // @@protoc_insertion_point(field_set_char:caffe.NetParameter.input)
+}
+inline void NetParameter::set_input(int index, const char* value, size_t size) {
+  input_.Mutable(index)->assign(
+    reinterpret_cast<const char*>(value), size);
+  // @@protoc_insertion_point(field_set_pointer:caffe.NetParameter.input)
+}
+inline ::std::string* NetParameter::add_input() {
+  // @@protoc_insertion_point(field_add_mutable:caffe.NetParameter.input)
+  return input_.Add();
+}
+inline void NetParameter::add_input(const ::std::string& value) {
+  input_.Add()->assign(value);
+  // @@protoc_insertion_point(field_add:caffe.NetParameter.input)
+}
+inline void NetParameter::add_input(const char* value) {
+  input_.Add()->assign(value);
+  // @@protoc_insertion_point(field_add_char:caffe.NetParameter.input)
+}
+inline void NetParameter::add_input(const char* value, size_t size) {
+  input_.Add()->assign(reinterpret_cast<const char*>(value), size);
+  // @@protoc_insertion_point(field_add_pointer:caffe.NetParameter.input)
+}
+inline const ::google::protobuf::RepeatedPtrField< ::std::string>&
+NetParameter::input() const {
+  // @@protoc_insertion_point(field_list:caffe.NetParameter.input)
+  return input_;
+}
+inline ::google::protobuf::RepeatedPtrField< ::std::string>*
+NetParameter::mutable_input() {
+  // @@protoc_insertion_point(field_mutable_list:caffe.NetParameter.input)
+  return &input_;
+}
+
+// repeated .caffe.BlobShape input_shape = 8;
+inline int NetParameter::input_shape_size() const {
+  return input_shape_.size();
+}
+inline void NetParameter::clear_input_shape() {
+  input_shape_.Clear();
+}
+inline const ::caffe::BlobShape& NetParameter::input_shape(int index) const {
+  // @@protoc_insertion_point(field_get:caffe.NetParameter.input_shape)
+  return input_shape_.Get(index);
+}
+inline ::caffe::BlobShape* NetParameter::mutable_input_shape(int index) {
+  // @@protoc_insertion_point(field_mutable:caffe.NetParameter.input_shape)
+  return input_shape_.Mutable(index);
+}
+inline ::caffe::BlobShape* NetParameter::add_input_shape() {
+  // @@protoc_insertion_point(field_add:caffe.NetParameter.input_shape)
+  return input_shape_.Add();
+}
+inline ::google::protobuf::RepeatedPtrField< ::caffe::BlobShape >*
+NetParameter::mutable_input_shape() {
+  // @@protoc_insertion_point(field_mutable_list:caffe.NetParameter.input_shape)
+  return &input_shape_;
+}
+inline const ::google::protobuf::RepeatedPtrField< ::caffe::BlobShape >&
+NetParameter::input_shape() const {
+  // @@protoc_insertion_point(field_list:caffe.NetParameter.input_shape)
+  return input_shape_;
+}
+
+// repeated int32 input_dim = 4;
+inline int NetParameter::input_dim_size() const {
+  return input_dim_.size();
+}
+inline void NetParameter::clear_input_dim() {
+  input_dim_.Clear();
+}
+inline ::google::protobuf::int32 NetParameter::input_dim(int index) const {
+  // @@protoc_insertion_point(field_get:caffe.NetParameter.input_dim)
+  return input_dim_.Get(index);
+}
+inline void NetParameter::set_input_dim(int index, ::google::protobuf::int32 value) {
+  input_dim_.Set(index, value);
+  // @@protoc_insertion_point(field_set:caffe.NetParameter.input_dim)
+}
+inline void NetParameter::add_input_dim(::google::protobuf::int32 value) {
+  input_dim_.Add(value);
+  // @@protoc_insertion_point(field_add:caffe.NetParameter.input_dim)
+}
+inline const ::google::protobuf::RepeatedField< ::google::protobuf::int32 >&
+NetParameter::input_dim() const {
+  // @@protoc_insertion_point(field_list:caffe.NetParameter.input_dim)
+  return input_dim_;
+}
+inline ::google::protobuf::RepeatedField< ::google::protobuf::int32 >*
+NetParameter::mutable_input_dim() {
+  // @@protoc_insertion_point(field_mutable_list:caffe.NetParameter.input_dim)
+  return &input_dim_;
+}
+
+// optional bool force_backward = 5 [default = false];
+inline bool NetParameter::has_force_backward() const {
+  return (_has_bits_[0] & 0x00000010u) != 0;
+}
+inline void NetParameter::set_has_force_backward() {
+  _has_bits_[0] |= 0x00000010u;
+}
+inline void NetParameter::clear_has_force_backward() {
+  _has_bits_[0] &= ~0x00000010u;
+}
+inline void NetParameter::clear_force_backward() {
+  force_backward_ = false;
+  clear_has_force_backward();
+}
+inline bool NetParameter::force_backward() const {
+  // @@protoc_insertion_point(field_get:caffe.NetParameter.force_backward)
+  return force_backward_;
+}
+inline void NetParameter::set_force_backward(bool value) {
+  set_has_force_backward();
+  force_backward_ = value;
+  // @@protoc_insertion_point(field_set:caffe.NetParameter.force_backward)
+}
+
+// optional .caffe.NetState state = 6;
+inline bool NetParameter::has_state() const {
+  return (_has_bits_[0] & 0x00000020u) != 0;
+}
+inline void NetParameter::set_has_state() {
+  _has_bits_[0] |= 0x00000020u;
+}
+inline void NetParameter::clear_has_state() {
+  _has_bits_[0] &= ~0x00000020u;
+}
+inline void NetParameter::clear_state() {
+  if (state_ != NULL) state_->::caffe::NetState::Clear();
+  clear_has_state();
+}
+inline const ::caffe::NetState& NetParameter::state() const {
+  // @@protoc_insertion_point(field_get:caffe.NetParameter.state)
+  return state_ != NULL ? *state_
+                         : *::caffe::NetState::internal_default_instance();
+}
+inline ::caffe::NetState* NetParameter::mutable_state() {
+  set_has_state();
+  if (state_ == NULL) {
+    state_ = new ::caffe::NetState;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.NetParameter.state)
+  return state_;
+}
+inline ::caffe::NetState* NetParameter::release_state() {
+  // @@protoc_insertion_point(field_release:caffe.NetParameter.state)
+  clear_has_state();
+  ::caffe::NetState* temp = state_;
+  state_ = NULL;
+  return temp;
+}
+inline void NetParameter::set_allocated_state(::caffe::NetState* state) {
+  delete state_;
+  state_ = state;
+  if (state) {
+    set_has_state();
+  } else {
+    clear_has_state();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.NetParameter.state)
+}
+
+// optional bool debug_info = 7 [default = false];
+inline bool NetParameter::has_debug_info() const {
+  return (_has_bits_[0] & 0x00000040u) != 0;
+}
+inline void NetParameter::set_has_debug_info() {
+  _has_bits_[0] |= 0x00000040u;
+}
+inline void NetParameter::clear_has_debug_info() {
+  _has_bits_[0] &= ~0x00000040u;
+}
+inline void NetParameter::clear_debug_info() {
+  debug_info_ = false;
+  clear_has_debug_info();
+}
+inline bool NetParameter::debug_info() const {
+  // @@protoc_insertion_point(field_get:caffe.NetParameter.debug_info)
+  return debug_info_;
+}
+inline void NetParameter::set_debug_info(bool value) {
+  set_has_debug_info();
+  debug_info_ = value;
+  // @@protoc_insertion_point(field_set:caffe.NetParameter.debug_info)
+}
+
+// repeated .caffe.LayerParameter layer = 100;
+inline int NetParameter::layer_size() const {
+  return layer_.size();
+}
+inline void NetParameter::clear_layer() {
+  layer_.Clear();
+}
+inline const ::caffe::LayerParameter& NetParameter::layer(int index) const {
+  // @@protoc_insertion_point(field_get:caffe.NetParameter.layer)
+  return layer_.Get(index);
+}
+inline ::caffe::LayerParameter* NetParameter::mutable_layer(int index) {
+  // @@protoc_insertion_point(field_mutable:caffe.NetParameter.layer)
+  return layer_.Mutable(index);
+}
+inline ::caffe::LayerParameter* NetParameter::add_layer() {
+  // @@protoc_insertion_point(field_add:caffe.NetParameter.layer)
+  return layer_.Add();
+}
+inline ::google::protobuf::RepeatedPtrField< ::caffe::LayerParameter >*
+NetParameter::mutable_layer() {
+  // @@protoc_insertion_point(field_mutable_list:caffe.NetParameter.layer)
+  return &layer_;
+}
+inline const ::google::protobuf::RepeatedPtrField< ::caffe::LayerParameter >&
+NetParameter::layer() const {
+  // @@protoc_insertion_point(field_list:caffe.NetParameter.layer)
+  return layer_;
+}
+
+// repeated .caffe.V1LayerParameter layers = 2;
+inline int NetParameter::layers_size() const {
+  return layers_.size();
+}
+inline void NetParameter::clear_layers() {
+  layers_.Clear();
+}
+inline const ::caffe::V1LayerParameter& NetParameter::layers(int index) const {
+  // @@protoc_insertion_point(field_get:caffe.NetParameter.layers)
+  return layers_.Get(index);
+}
+inline ::caffe::V1LayerParameter* NetParameter::mutable_layers(int index) {
+  // @@protoc_insertion_point(field_mutable:caffe.NetParameter.layers)
+  return layers_.Mutable(index);
+}
+inline ::caffe::V1LayerParameter* NetParameter::add_layers() {
+  // @@protoc_insertion_point(field_add:caffe.NetParameter.layers)
+  return layers_.Add();
+}
+inline ::google::protobuf::RepeatedPtrField< ::caffe::V1LayerParameter >*
+NetParameter::mutable_layers() {
+  // @@protoc_insertion_point(field_mutable_list:caffe.NetParameter.layers)
+  return &layers_;
+}
+inline const ::google::protobuf::RepeatedPtrField< ::caffe::V1LayerParameter >&
+NetParameter::layers() const {
+  // @@protoc_insertion_point(field_list:caffe.NetParameter.layers)
+  return layers_;
+}
+
+inline const NetParameter* NetParameter::internal_default_instance() {
+  return &NetParameter_default_instance_.get();
+}
+// -------------------------------------------------------------------
+
+// SolverParameter
+
+// optional string net = 24;
+inline bool SolverParameter::has_net() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+inline void SolverParameter::set_has_net() {
+  _has_bits_[0] |= 0x00000001u;
+}
+inline void SolverParameter::clear_has_net() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+inline void SolverParameter::clear_net() {
+  net_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  clear_has_net();
+}
+inline const ::std::string& SolverParameter::net() const {
+  // @@protoc_insertion_point(field_get:caffe.SolverParameter.net)
+  return net_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void SolverParameter::set_net(const ::std::string& value) {
+  set_has_net();
+  net_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:caffe.SolverParameter.net)
+}
+inline void SolverParameter::set_net(const char* value) {
+  set_has_net();
+  net_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:caffe.SolverParameter.net)
+}
+inline void SolverParameter::set_net(const char* value, size_t size) {
+  set_has_net();
+  net_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:caffe.SolverParameter.net)
+}
+inline ::std::string* SolverParameter::mutable_net() {
+  set_has_net();
+  // @@protoc_insertion_point(field_mutable:caffe.SolverParameter.net)
+  return net_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline ::std::string* SolverParameter::release_net() {
+  // @@protoc_insertion_point(field_release:caffe.SolverParameter.net)
+  clear_has_net();
+  return net_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void SolverParameter::set_allocated_net(::std::string* net) {
+  if (net != NULL) {
+    set_has_net();
+  } else {
+    clear_has_net();
+  }
+  net_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), net);
+  // @@protoc_insertion_point(field_set_allocated:caffe.SolverParameter.net)
+}
+
+// optional .caffe.NetParameter net_param = 25;
+inline bool SolverParameter::has_net_param() const {
+  return (_has_bits_[0] & 0x00000002u) != 0;
+}
+inline void SolverParameter::set_has_net_param() {
+  _has_bits_[0] |= 0x00000002u;
+}
+inline void SolverParameter::clear_has_net_param() {
+  _has_bits_[0] &= ~0x00000002u;
+}
+inline void SolverParameter::clear_net_param() {
+  if (net_param_ != NULL) net_param_->::caffe::NetParameter::Clear();
+  clear_has_net_param();
+}
+inline const ::caffe::NetParameter& SolverParameter::net_param() const {
+  // @@protoc_insertion_point(field_get:caffe.SolverParameter.net_param)
+  return net_param_ != NULL ? *net_param_
+                         : *::caffe::NetParameter::internal_default_instance();
+}
+inline ::caffe::NetParameter* SolverParameter::mutable_net_param() {
+  set_has_net_param();
+  if (net_param_ == NULL) {
+    net_param_ = new ::caffe::NetParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.SolverParameter.net_param)
+  return net_param_;
+}
+inline ::caffe::NetParameter* SolverParameter::release_net_param() {
+  // @@protoc_insertion_point(field_release:caffe.SolverParameter.net_param)
+  clear_has_net_param();
+  ::caffe::NetParameter* temp = net_param_;
+  net_param_ = NULL;
+  return temp;
+}
+inline void SolverParameter::set_allocated_net_param(::caffe::NetParameter* net_param) {
+  delete net_param_;
+  net_param_ = net_param;
+  if (net_param) {
+    set_has_net_param();
+  } else {
+    clear_has_net_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.SolverParameter.net_param)
+}
+
+// optional string train_net = 1;
+inline bool SolverParameter::has_train_net() const {
+  return (_has_bits_[0] & 0x00000004u) != 0;
+}
+inline void SolverParameter::set_has_train_net() {
+  _has_bits_[0] |= 0x00000004u;
+}
+inline void SolverParameter::clear_has_train_net() {
+  _has_bits_[0] &= ~0x00000004u;
+}
+inline void SolverParameter::clear_train_net() {
+  train_net_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  clear_has_train_net();
+}
+inline const ::std::string& SolverParameter::train_net() const {
+  // @@protoc_insertion_point(field_get:caffe.SolverParameter.train_net)
+  return train_net_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void SolverParameter::set_train_net(const ::std::string& value) {
+  set_has_train_net();
+  train_net_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:caffe.SolverParameter.train_net)
+}
+inline void SolverParameter::set_train_net(const char* value) {
+  set_has_train_net();
+  train_net_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:caffe.SolverParameter.train_net)
+}
+inline void SolverParameter::set_train_net(const char* value, size_t size) {
+  set_has_train_net();
+  train_net_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:caffe.SolverParameter.train_net)
+}
+inline ::std::string* SolverParameter::mutable_train_net() {
+  set_has_train_net();
+  // @@protoc_insertion_point(field_mutable:caffe.SolverParameter.train_net)
+  return train_net_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline ::std::string* SolverParameter::release_train_net() {
+  // @@protoc_insertion_point(field_release:caffe.SolverParameter.train_net)
+  clear_has_train_net();
+  return train_net_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void SolverParameter::set_allocated_train_net(::std::string* train_net) {
+  if (train_net != NULL) {
+    set_has_train_net();
+  } else {
+    clear_has_train_net();
+  }
+  train_net_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), train_net);
+  // @@protoc_insertion_point(field_set_allocated:caffe.SolverParameter.train_net)
+}
+
+// repeated string test_net = 2;
+inline int SolverParameter::test_net_size() const {
+  return test_net_.size();
+}
+inline void SolverParameter::clear_test_net() {
+  test_net_.Clear();
+}
+inline const ::std::string& SolverParameter::test_net(int index) const {
+  // @@protoc_insertion_point(field_get:caffe.SolverParameter.test_net)
+  return test_net_.Get(index);
+}
+inline ::std::string* SolverParameter::mutable_test_net(int index) {
+  // @@protoc_insertion_point(field_mutable:caffe.SolverParameter.test_net)
+  return test_net_.Mutable(index);
+}
+inline void SolverParameter::set_test_net(int index, const ::std::string& value) {
+  // @@protoc_insertion_point(field_set:caffe.SolverParameter.test_net)
+  test_net_.Mutable(index)->assign(value);
+}
+inline void SolverParameter::set_test_net(int index, const char* value) {
+  test_net_.Mutable(index)->assign(value);
+  // @@protoc_insertion_point(field_set_char:caffe.SolverParameter.test_net)
+}
+inline void SolverParameter::set_test_net(int index, const char* value, size_t size) {
+  test_net_.Mutable(index)->assign(
+    reinterpret_cast<const char*>(value), size);
+  // @@protoc_insertion_point(field_set_pointer:caffe.SolverParameter.test_net)
+}
+inline ::std::string* SolverParameter::add_test_net() {
+  // @@protoc_insertion_point(field_add_mutable:caffe.SolverParameter.test_net)
+  return test_net_.Add();
+}
+inline void SolverParameter::add_test_net(const ::std::string& value) {
+  test_net_.Add()->assign(value);
+  // @@protoc_insertion_point(field_add:caffe.SolverParameter.test_net)
+}
+inline void SolverParameter::add_test_net(const char* value) {
+  test_net_.Add()->assign(value);
+  // @@protoc_insertion_point(field_add_char:caffe.SolverParameter.test_net)
+}
+inline void SolverParameter::add_test_net(const char* value, size_t size) {
+  test_net_.Add()->assign(reinterpret_cast<const char*>(value), size);
+  // @@protoc_insertion_point(field_add_pointer:caffe.SolverParameter.test_net)
+}
+inline const ::google::protobuf::RepeatedPtrField< ::std::string>&
+SolverParameter::test_net() const {
+  // @@protoc_insertion_point(field_list:caffe.SolverParameter.test_net)
+  return test_net_;
+}
+inline ::google::protobuf::RepeatedPtrField< ::std::string>*
+SolverParameter::mutable_test_net() {
+  // @@protoc_insertion_point(field_mutable_list:caffe.SolverParameter.test_net)
+  return &test_net_;
+}
+
+// optional .caffe.NetParameter train_net_param = 21;
+inline bool SolverParameter::has_train_net_param() const {
+  return (_has_bits_[0] & 0x00000010u) != 0;
+}
+inline void SolverParameter::set_has_train_net_param() {
+  _has_bits_[0] |= 0x00000010u;
+}
+inline void SolverParameter::clear_has_train_net_param() {
+  _has_bits_[0] &= ~0x00000010u;
+}
+inline void SolverParameter::clear_train_net_param() {
+  if (train_net_param_ != NULL) train_net_param_->::caffe::NetParameter::Clear();
+  clear_has_train_net_param();
+}
+inline const ::caffe::NetParameter& SolverParameter::train_net_param() const {
+  // @@protoc_insertion_point(field_get:caffe.SolverParameter.train_net_param)
+  return train_net_param_ != NULL ? *train_net_param_
+                         : *::caffe::NetParameter::internal_default_instance();
+}
+inline ::caffe::NetParameter* SolverParameter::mutable_train_net_param() {
+  set_has_train_net_param();
+  if (train_net_param_ == NULL) {
+    train_net_param_ = new ::caffe::NetParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.SolverParameter.train_net_param)
+  return train_net_param_;
+}
+inline ::caffe::NetParameter* SolverParameter::release_train_net_param() {
+  // @@protoc_insertion_point(field_release:caffe.SolverParameter.train_net_param)
+  clear_has_train_net_param();
+  ::caffe::NetParameter* temp = train_net_param_;
+  train_net_param_ = NULL;
+  return temp;
+}
+inline void SolverParameter::set_allocated_train_net_param(::caffe::NetParameter* train_net_param) {
+  delete train_net_param_;
+  train_net_param_ = train_net_param;
+  if (train_net_param) {
+    set_has_train_net_param();
+  } else {
+    clear_has_train_net_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.SolverParameter.train_net_param)
+}
+
+// repeated .caffe.NetParameter test_net_param = 22;
+inline int SolverParameter::test_net_param_size() const {
+  return test_net_param_.size();
+}
+inline void SolverParameter::clear_test_net_param() {
+  test_net_param_.Clear();
+}
+inline const ::caffe::NetParameter& SolverParameter::test_net_param(int index) const {
+  // @@protoc_insertion_point(field_get:caffe.SolverParameter.test_net_param)
+  return test_net_param_.Get(index);
+}
+inline ::caffe::NetParameter* SolverParameter::mutable_test_net_param(int index) {
+  // @@protoc_insertion_point(field_mutable:caffe.SolverParameter.test_net_param)
+  return test_net_param_.Mutable(index);
+}
+inline ::caffe::NetParameter* SolverParameter::add_test_net_param() {
+  // @@protoc_insertion_point(field_add:caffe.SolverParameter.test_net_param)
+  return test_net_param_.Add();
+}
+inline ::google::protobuf::RepeatedPtrField< ::caffe::NetParameter >*
+SolverParameter::mutable_test_net_param() {
+  // @@protoc_insertion_point(field_mutable_list:caffe.SolverParameter.test_net_param)
+  return &test_net_param_;
+}
+inline const ::google::protobuf::RepeatedPtrField< ::caffe::NetParameter >&
+SolverParameter::test_net_param() const {
+  // @@protoc_insertion_point(field_list:caffe.SolverParameter.test_net_param)
+  return test_net_param_;
+}
+
+// optional .caffe.NetState train_state = 26;
+inline bool SolverParameter::has_train_state() const {
+  return (_has_bits_[0] & 0x00000040u) != 0;
+}
+inline void SolverParameter::set_has_train_state() {
+  _has_bits_[0] |= 0x00000040u;
+}
+inline void SolverParameter::clear_has_train_state() {
+  _has_bits_[0] &= ~0x00000040u;
+}
+inline void SolverParameter::clear_train_state() {
+  if (train_state_ != NULL) train_state_->::caffe::NetState::Clear();
+  clear_has_train_state();
+}
+inline const ::caffe::NetState& SolverParameter::train_state() const {
+  // @@protoc_insertion_point(field_get:caffe.SolverParameter.train_state)
+  return train_state_ != NULL ? *train_state_
+                         : *::caffe::NetState::internal_default_instance();
+}
+inline ::caffe::NetState* SolverParameter::mutable_train_state() {
+  set_has_train_state();
+  if (train_state_ == NULL) {
+    train_state_ = new ::caffe::NetState;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.SolverParameter.train_state)
+  return train_state_;
+}
+inline ::caffe::NetState* SolverParameter::release_train_state() {
+  // @@protoc_insertion_point(field_release:caffe.SolverParameter.train_state)
+  clear_has_train_state();
+  ::caffe::NetState* temp = train_state_;
+  train_state_ = NULL;
+  return temp;
+}
+inline void SolverParameter::set_allocated_train_state(::caffe::NetState* train_state) {
+  delete train_state_;
+  train_state_ = train_state;
+  if (train_state) {
+    set_has_train_state();
+  } else {
+    clear_has_train_state();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.SolverParameter.train_state)
+}
+
+// repeated .caffe.NetState test_state = 27;
+inline int SolverParameter::test_state_size() const {
+  return test_state_.size();
+}
+inline void SolverParameter::clear_test_state() {
+  test_state_.Clear();
+}
+inline const ::caffe::NetState& SolverParameter::test_state(int index) const {
+  // @@protoc_insertion_point(field_get:caffe.SolverParameter.test_state)
+  return test_state_.Get(index);
+}
+inline ::caffe::NetState* SolverParameter::mutable_test_state(int index) {
+  // @@protoc_insertion_point(field_mutable:caffe.SolverParameter.test_state)
+  return test_state_.Mutable(index);
+}
+inline ::caffe::NetState* SolverParameter::add_test_state() {
+  // @@protoc_insertion_point(field_add:caffe.SolverParameter.test_state)
+  return test_state_.Add();
+}
+inline ::google::protobuf::RepeatedPtrField< ::caffe::NetState >*
+SolverParameter::mutable_test_state() {
+  // @@protoc_insertion_point(field_mutable_list:caffe.SolverParameter.test_state)
+  return &test_state_;
+}
+inline const ::google::protobuf::RepeatedPtrField< ::caffe::NetState >&
+SolverParameter::test_state() const {
+  // @@protoc_insertion_point(field_list:caffe.SolverParameter.test_state)
+  return test_state_;
+}
+
+// repeated int32 test_iter = 3;
+inline int SolverParameter::test_iter_size() const {
+  return test_iter_.size();
+}
+inline void SolverParameter::clear_test_iter() {
+  test_iter_.Clear();
+}
+inline ::google::protobuf::int32 SolverParameter::test_iter(int index) const {
+  // @@protoc_insertion_point(field_get:caffe.SolverParameter.test_iter)
+  return test_iter_.Get(index);
+}
+inline void SolverParameter::set_test_iter(int index, ::google::protobuf::int32 value) {
+  test_iter_.Set(index, value);
+  // @@protoc_insertion_point(field_set:caffe.SolverParameter.test_iter)
+}
+inline void SolverParameter::add_test_iter(::google::protobuf::int32 value) {
+  test_iter_.Add(value);
+  // @@protoc_insertion_point(field_add:caffe.SolverParameter.test_iter)
+}
+inline const ::google::protobuf::RepeatedField< ::google::protobuf::int32 >&
+SolverParameter::test_iter() const {
+  // @@protoc_insertion_point(field_list:caffe.SolverParameter.test_iter)
+  return test_iter_;
+}
+inline ::google::protobuf::RepeatedField< ::google::protobuf::int32 >*
+SolverParameter::mutable_test_iter() {
+  // @@protoc_insertion_point(field_mutable_list:caffe.SolverParameter.test_iter)
+  return &test_iter_;
+}
+
+// optional int32 test_interval = 4 [default = 0];
+inline bool SolverParameter::has_test_interval() const {
+  return (_has_bits_[0] & 0x00000200u) != 0;
+}
+inline void SolverParameter::set_has_test_interval() {
+  _has_bits_[0] |= 0x00000200u;
+}
+inline void SolverParameter::clear_has_test_interval() {
+  _has_bits_[0] &= ~0x00000200u;
+}
+inline void SolverParameter::clear_test_interval() {
+  test_interval_ = 0;
+  clear_has_test_interval();
+}
+inline ::google::protobuf::int32 SolverParameter::test_interval() const {
+  // @@protoc_insertion_point(field_get:caffe.SolverParameter.test_interval)
+  return test_interval_;
+}
+inline void SolverParameter::set_test_interval(::google::protobuf::int32 value) {
+  set_has_test_interval();
+  test_interval_ = value;
+  // @@protoc_insertion_point(field_set:caffe.SolverParameter.test_interval)
+}
+
+// optional bool test_compute_loss = 19 [default = false];
+inline bool SolverParameter::has_test_compute_loss() const {
+  return (_has_bits_[0] & 0x00000400u) != 0;
+}
+inline void SolverParameter::set_has_test_compute_loss() {
+  _has_bits_[0] |= 0x00000400u;
+}
+inline void SolverParameter::clear_has_test_compute_loss() {
+  _has_bits_[0] &= ~0x00000400u;
+}
+inline void SolverParameter::clear_test_compute_loss() {
+  test_compute_loss_ = false;
+  clear_has_test_compute_loss();
+}
+inline bool SolverParameter::test_compute_loss() const {
+  // @@protoc_insertion_point(field_get:caffe.SolverParameter.test_compute_loss)
+  return test_compute_loss_;
+}
+inline void SolverParameter::set_test_compute_loss(bool value) {
+  set_has_test_compute_loss();
+  test_compute_loss_ = value;
+  // @@protoc_insertion_point(field_set:caffe.SolverParameter.test_compute_loss)
+}
+
+// optional bool test_initialization = 32 [default = true];
+inline bool SolverParameter::has_test_initialization() const {
+  return (_has_bits_[0] & 0x00000800u) != 0;
+}
+inline void SolverParameter::set_has_test_initialization() {
+  _has_bits_[0] |= 0x00000800u;
+}
+inline void SolverParameter::clear_has_test_initialization() {
+  _has_bits_[0] &= ~0x00000800u;
+}
+inline void SolverParameter::clear_test_initialization() {
+  test_initialization_ = true;
+  clear_has_test_initialization();
+}
+inline bool SolverParameter::test_initialization() const {
+  // @@protoc_insertion_point(field_get:caffe.SolverParameter.test_initialization)
+  return test_initialization_;
+}
+inline void SolverParameter::set_test_initialization(bool value) {
+  set_has_test_initialization();
+  test_initialization_ = value;
+  // @@protoc_insertion_point(field_set:caffe.SolverParameter.test_initialization)
+}
+
+// optional float base_lr = 5;
+inline bool SolverParameter::has_base_lr() const {
+  return (_has_bits_[0] & 0x00001000u) != 0;
+}
+inline void SolverParameter::set_has_base_lr() {
+  _has_bits_[0] |= 0x00001000u;
+}
+inline void SolverParameter::clear_has_base_lr() {
+  _has_bits_[0] &= ~0x00001000u;
+}
+inline void SolverParameter::clear_base_lr() {
+  base_lr_ = 0;
+  clear_has_base_lr();
+}
+inline float SolverParameter::base_lr() const {
+  // @@protoc_insertion_point(field_get:caffe.SolverParameter.base_lr)
+  return base_lr_;
+}
+inline void SolverParameter::set_base_lr(float value) {
+  set_has_base_lr();
+  base_lr_ = value;
+  // @@protoc_insertion_point(field_set:caffe.SolverParameter.base_lr)
+}
+
+// optional int32 display = 6;
+inline bool SolverParameter::has_display() const {
+  return (_has_bits_[0] & 0x00002000u) != 0;
+}
+inline void SolverParameter::set_has_display() {
+  _has_bits_[0] |= 0x00002000u;
+}
+inline void SolverParameter::clear_has_display() {
+  _has_bits_[0] &= ~0x00002000u;
+}
+inline void SolverParameter::clear_display() {
+  display_ = 0;
+  clear_has_display();
+}
+inline ::google::protobuf::int32 SolverParameter::display() const {
+  // @@protoc_insertion_point(field_get:caffe.SolverParameter.display)
+  return display_;
+}
+inline void SolverParameter::set_display(::google::protobuf::int32 value) {
+  set_has_display();
+  display_ = value;
+  // @@protoc_insertion_point(field_set:caffe.SolverParameter.display)
+}
+
+// optional int32 average_loss = 33 [default = 1];
+inline bool SolverParameter::has_average_loss() const {
+  return (_has_bits_[0] & 0x00004000u) != 0;
+}
+inline void SolverParameter::set_has_average_loss() {
+  _has_bits_[0] |= 0x00004000u;
+}
+inline void SolverParameter::clear_has_average_loss() {
+  _has_bits_[0] &= ~0x00004000u;
+}
+inline void SolverParameter::clear_average_loss() {
+  average_loss_ = 1;
+  clear_has_average_loss();
+}
+inline ::google::protobuf::int32 SolverParameter::average_loss() const {
+  // @@protoc_insertion_point(field_get:caffe.SolverParameter.average_loss)
+  return average_loss_;
+}
+inline void SolverParameter::set_average_loss(::google::protobuf::int32 value) {
+  set_has_average_loss();
+  average_loss_ = value;
+  // @@protoc_insertion_point(field_set:caffe.SolverParameter.average_loss)
+}
+
+// optional int32 max_iter = 7;
+inline bool SolverParameter::has_max_iter() const {
+  return (_has_bits_[0] & 0x00008000u) != 0;
+}
+inline void SolverParameter::set_has_max_iter() {
+  _has_bits_[0] |= 0x00008000u;
+}
+inline void SolverParameter::clear_has_max_iter() {
+  _has_bits_[0] &= ~0x00008000u;
+}
+inline void SolverParameter::clear_max_iter() {
+  max_iter_ = 0;
+  clear_has_max_iter();
+}
+inline ::google::protobuf::int32 SolverParameter::max_iter() const {
+  // @@protoc_insertion_point(field_get:caffe.SolverParameter.max_iter)
+  return max_iter_;
+}
+inline void SolverParameter::set_max_iter(::google::protobuf::int32 value) {
+  set_has_max_iter();
+  max_iter_ = value;
+  // @@protoc_insertion_point(field_set:caffe.SolverParameter.max_iter)
+}
+
+// optional int32 iter_size = 36 [default = 1];
+inline bool SolverParameter::has_iter_size() const {
+  return (_has_bits_[0] & 0x00010000u) != 0;
+}
+inline void SolverParameter::set_has_iter_size() {
+  _has_bits_[0] |= 0x00010000u;
+}
+inline void SolverParameter::clear_has_iter_size() {
+  _has_bits_[0] &= ~0x00010000u;
+}
+inline void SolverParameter::clear_iter_size() {
+  iter_size_ = 1;
+  clear_has_iter_size();
+}
+inline ::google::protobuf::int32 SolverParameter::iter_size() const {
+  // @@protoc_insertion_point(field_get:caffe.SolverParameter.iter_size)
+  return iter_size_;
+}
+inline void SolverParameter::set_iter_size(::google::protobuf::int32 value) {
+  set_has_iter_size();
+  iter_size_ = value;
+  // @@protoc_insertion_point(field_set:caffe.SolverParameter.iter_size)
+}
+
+// optional string lr_policy = 8;
+inline bool SolverParameter::has_lr_policy() const {
+  return (_has_bits_[0] & 0x00020000u) != 0;
+}
+inline void SolverParameter::set_has_lr_policy() {
+  _has_bits_[0] |= 0x00020000u;
+}
+inline void SolverParameter::clear_has_lr_policy() {
+  _has_bits_[0] &= ~0x00020000u;
+}
+inline void SolverParameter::clear_lr_policy() {
+  lr_policy_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  clear_has_lr_policy();
+}
+inline const ::std::string& SolverParameter::lr_policy() const {
+  // @@protoc_insertion_point(field_get:caffe.SolverParameter.lr_policy)
+  return lr_policy_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void SolverParameter::set_lr_policy(const ::std::string& value) {
+  set_has_lr_policy();
+  lr_policy_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:caffe.SolverParameter.lr_policy)
+}
+inline void SolverParameter::set_lr_policy(const char* value) {
+  set_has_lr_policy();
+  lr_policy_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:caffe.SolverParameter.lr_policy)
+}
+inline void SolverParameter::set_lr_policy(const char* value, size_t size) {
+  set_has_lr_policy();
+  lr_policy_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:caffe.SolverParameter.lr_policy)
+}
+inline ::std::string* SolverParameter::mutable_lr_policy() {
+  set_has_lr_policy();
+  // @@protoc_insertion_point(field_mutable:caffe.SolverParameter.lr_policy)
+  return lr_policy_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline ::std::string* SolverParameter::release_lr_policy() {
+  // @@protoc_insertion_point(field_release:caffe.SolverParameter.lr_policy)
+  clear_has_lr_policy();
+  return lr_policy_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void SolverParameter::set_allocated_lr_policy(::std::string* lr_policy) {
+  if (lr_policy != NULL) {
+    set_has_lr_policy();
+  } else {
+    clear_has_lr_policy();
+  }
+  lr_policy_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), lr_policy);
+  // @@protoc_insertion_point(field_set_allocated:caffe.SolverParameter.lr_policy)
+}
+
+// optional float gamma = 9;
+inline bool SolverParameter::has_gamma() const {
+  return (_has_bits_[0] & 0x00040000u) != 0;
+}
+inline void SolverParameter::set_has_gamma() {
+  _has_bits_[0] |= 0x00040000u;
+}
+inline void SolverParameter::clear_has_gamma() {
+  _has_bits_[0] &= ~0x00040000u;
+}
+inline void SolverParameter::clear_gamma() {
+  gamma_ = 0;
+  clear_has_gamma();
+}
+inline float SolverParameter::gamma() const {
+  // @@protoc_insertion_point(field_get:caffe.SolverParameter.gamma)
+  return gamma_;
+}
+inline void SolverParameter::set_gamma(float value) {
+  set_has_gamma();
+  gamma_ = value;
+  // @@protoc_insertion_point(field_set:caffe.SolverParameter.gamma)
+}
+
+// optional float power = 10;
+inline bool SolverParameter::has_power() const {
+  return (_has_bits_[0] & 0x00080000u) != 0;
+}
+inline void SolverParameter::set_has_power() {
+  _has_bits_[0] |= 0x00080000u;
+}
+inline void SolverParameter::clear_has_power() {
+  _has_bits_[0] &= ~0x00080000u;
+}
+inline void SolverParameter::clear_power() {
+  power_ = 0;
+  clear_has_power();
+}
+inline float SolverParameter::power() const {
+  // @@protoc_insertion_point(field_get:caffe.SolverParameter.power)
+  return power_;
+}
+inline void SolverParameter::set_power(float value) {
+  set_has_power();
+  power_ = value;
+  // @@protoc_insertion_point(field_set:caffe.SolverParameter.power)
+}
+
+// optional float momentum = 11;
+inline bool SolverParameter::has_momentum() const {
+  return (_has_bits_[0] & 0x00100000u) != 0;
+}
+inline void SolverParameter::set_has_momentum() {
+  _has_bits_[0] |= 0x00100000u;
+}
+inline void SolverParameter::clear_has_momentum() {
+  _has_bits_[0] &= ~0x00100000u;
+}
+inline void SolverParameter::clear_momentum() {
+  momentum_ = 0;
+  clear_has_momentum();
+}
+inline float SolverParameter::momentum() const {
+  // @@protoc_insertion_point(field_get:caffe.SolverParameter.momentum)
+  return momentum_;
+}
+inline void SolverParameter::set_momentum(float value) {
+  set_has_momentum();
+  momentum_ = value;
+  // @@protoc_insertion_point(field_set:caffe.SolverParameter.momentum)
+}
+
+// optional float weight_decay = 12;
+inline bool SolverParameter::has_weight_decay() const {
+  return (_has_bits_[0] & 0x00200000u) != 0;
+}
+inline void SolverParameter::set_has_weight_decay() {
+  _has_bits_[0] |= 0x00200000u;
+}
+inline void SolverParameter::clear_has_weight_decay() {
+  _has_bits_[0] &= ~0x00200000u;
+}
+inline void SolverParameter::clear_weight_decay() {
+  weight_decay_ = 0;
+  clear_has_weight_decay();
+}
+inline float SolverParameter::weight_decay() const {
+  // @@protoc_insertion_point(field_get:caffe.SolverParameter.weight_decay)
+  return weight_decay_;
+}
+inline void SolverParameter::set_weight_decay(float value) {
+  set_has_weight_decay();
+  weight_decay_ = value;
+  // @@protoc_insertion_point(field_set:caffe.SolverParameter.weight_decay)
+}
+
+// optional string regularization_type = 29 [default = "L2"];
+inline bool SolverParameter::has_regularization_type() const {
+  return (_has_bits_[0] & 0x00400000u) != 0;
+}
+inline void SolverParameter::set_has_regularization_type() {
+  _has_bits_[0] |= 0x00400000u;
+}
+inline void SolverParameter::clear_has_regularization_type() {
+  _has_bits_[0] &= ~0x00400000u;
+}
+inline void SolverParameter::clear_regularization_type() {
+  regularization_type_.ClearToDefaultNoArena(_default_regularization_type_);
+  clear_has_regularization_type();
+}
+inline const ::std::string& SolverParameter::regularization_type() const {
+  // @@protoc_insertion_point(field_get:caffe.SolverParameter.regularization_type)
+  return regularization_type_.GetNoArena(_default_regularization_type_);
+}
+inline void SolverParameter::set_regularization_type(const ::std::string& value) {
+  set_has_regularization_type();
+  regularization_type_.SetNoArena(_default_regularization_type_, value);
+  // @@protoc_insertion_point(field_set:caffe.SolverParameter.regularization_type)
+}
+inline void SolverParameter::set_regularization_type(const char* value) {
+  set_has_regularization_type();
+  regularization_type_.SetNoArena(_default_regularization_type_, ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:caffe.SolverParameter.regularization_type)
+}
+inline void SolverParameter::set_regularization_type(const char* value, size_t size) {
+  set_has_regularization_type();
+  regularization_type_.SetNoArena(_default_regularization_type_,
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:caffe.SolverParameter.regularization_type)
+}
+inline ::std::string* SolverParameter::mutable_regularization_type() {
+  set_has_regularization_type();
+  // @@protoc_insertion_point(field_mutable:caffe.SolverParameter.regularization_type)
+  return regularization_type_.MutableNoArena(_default_regularization_type_);
+}
+inline ::std::string* SolverParameter::release_regularization_type() {
+  // @@protoc_insertion_point(field_release:caffe.SolverParameter.regularization_type)
+  clear_has_regularization_type();
+  return regularization_type_.ReleaseNoArena(_default_regularization_type_);
+}
+inline void SolverParameter::set_allocated_regularization_type(::std::string* regularization_type) {
+  if (regularization_type != NULL) {
+    set_has_regularization_type();
+  } else {
+    clear_has_regularization_type();
+  }
+  regularization_type_.SetAllocatedNoArena(_default_regularization_type_, regularization_type);
+  // @@protoc_insertion_point(field_set_allocated:caffe.SolverParameter.regularization_type)
+}
+
+// optional int32 stepsize = 13;
+inline bool SolverParameter::has_stepsize() const {
+  return (_has_bits_[0] & 0x00800000u) != 0;
+}
+inline void SolverParameter::set_has_stepsize() {
+  _has_bits_[0] |= 0x00800000u;
+}
+inline void SolverParameter::clear_has_stepsize() {
+  _has_bits_[0] &= ~0x00800000u;
+}
+inline void SolverParameter::clear_stepsize() {
+  stepsize_ = 0;
+  clear_has_stepsize();
+}
+inline ::google::protobuf::int32 SolverParameter::stepsize() const {
+  // @@protoc_insertion_point(field_get:caffe.SolverParameter.stepsize)
+  return stepsize_;
+}
+inline void SolverParameter::set_stepsize(::google::protobuf::int32 value) {
+  set_has_stepsize();
+  stepsize_ = value;
+  // @@protoc_insertion_point(field_set:caffe.SolverParameter.stepsize)
+}
+
+// repeated int32 stepvalue = 34;
+inline int SolverParameter::stepvalue_size() const {
+  return stepvalue_.size();
+}
+inline void SolverParameter::clear_stepvalue() {
+  stepvalue_.Clear();
+}
+inline ::google::protobuf::int32 SolverParameter::stepvalue(int index) const {
+  // @@protoc_insertion_point(field_get:caffe.SolverParameter.stepvalue)
+  return stepvalue_.Get(index);
+}
+inline void SolverParameter::set_stepvalue(int index, ::google::protobuf::int32 value) {
+  stepvalue_.Set(index, value);
+  // @@protoc_insertion_point(field_set:caffe.SolverParameter.stepvalue)
+}
+inline void SolverParameter::add_stepvalue(::google::protobuf::int32 value) {
+  stepvalue_.Add(value);
+  // @@protoc_insertion_point(field_add:caffe.SolverParameter.stepvalue)
+}
+inline const ::google::protobuf::RepeatedField< ::google::protobuf::int32 >&
+SolverParameter::stepvalue() const {
+  // @@protoc_insertion_point(field_list:caffe.SolverParameter.stepvalue)
+  return stepvalue_;
+}
+inline ::google::protobuf::RepeatedField< ::google::protobuf::int32 >*
+SolverParameter::mutable_stepvalue() {
+  // @@protoc_insertion_point(field_mutable_list:caffe.SolverParameter.stepvalue)
+  return &stepvalue_;
+}
+
+// optional float clip_gradients = 35 [default = -1];
+inline bool SolverParameter::has_clip_gradients() const {
+  return (_has_bits_[0] & 0x02000000u) != 0;
+}
+inline void SolverParameter::set_has_clip_gradients() {
+  _has_bits_[0] |= 0x02000000u;
+}
+inline void SolverParameter::clear_has_clip_gradients() {
+  _has_bits_[0] &= ~0x02000000u;
+}
+inline void SolverParameter::clear_clip_gradients() {
+  clip_gradients_ = -1;
+  clear_has_clip_gradients();
+}
+inline float SolverParameter::clip_gradients() const {
+  // @@protoc_insertion_point(field_get:caffe.SolverParameter.clip_gradients)
+  return clip_gradients_;
+}
+inline void SolverParameter::set_clip_gradients(float value) {
+  set_has_clip_gradients();
+  clip_gradients_ = value;
+  // @@protoc_insertion_point(field_set:caffe.SolverParameter.clip_gradients)
+}
+
+// optional int32 snapshot = 14 [default = 0];
+inline bool SolverParameter::has_snapshot() const {
+  return (_has_bits_[0] & 0x04000000u) != 0;
+}
+inline void SolverParameter::set_has_snapshot() {
+  _has_bits_[0] |= 0x04000000u;
+}
+inline void SolverParameter::clear_has_snapshot() {
+  _has_bits_[0] &= ~0x04000000u;
+}
+inline void SolverParameter::clear_snapshot() {
+  snapshot_ = 0;
+  clear_has_snapshot();
+}
+inline ::google::protobuf::int32 SolverParameter::snapshot() const {
+  // @@protoc_insertion_point(field_get:caffe.SolverParameter.snapshot)
+  return snapshot_;
+}
+inline void SolverParameter::set_snapshot(::google::protobuf::int32 value) {
+  set_has_snapshot();
+  snapshot_ = value;
+  // @@protoc_insertion_point(field_set:caffe.SolverParameter.snapshot)
+}
+
+// optional string snapshot_prefix = 15;
+inline bool SolverParameter::has_snapshot_prefix() const {
+  return (_has_bits_[0] & 0x08000000u) != 0;
+}
+inline void SolverParameter::set_has_snapshot_prefix() {
+  _has_bits_[0] |= 0x08000000u;
+}
+inline void SolverParameter::clear_has_snapshot_prefix() {
+  _has_bits_[0] &= ~0x08000000u;
+}
+inline void SolverParameter::clear_snapshot_prefix() {
+  snapshot_prefix_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  clear_has_snapshot_prefix();
+}
+inline const ::std::string& SolverParameter::snapshot_prefix() const {
+  // @@protoc_insertion_point(field_get:caffe.SolverParameter.snapshot_prefix)
+  return snapshot_prefix_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void SolverParameter::set_snapshot_prefix(const ::std::string& value) {
+  set_has_snapshot_prefix();
+  snapshot_prefix_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:caffe.SolverParameter.snapshot_prefix)
+}
+inline void SolverParameter::set_snapshot_prefix(const char* value) {
+  set_has_snapshot_prefix();
+  snapshot_prefix_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:caffe.SolverParameter.snapshot_prefix)
+}
+inline void SolverParameter::set_snapshot_prefix(const char* value, size_t size) {
+  set_has_snapshot_prefix();
+  snapshot_prefix_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:caffe.SolverParameter.snapshot_prefix)
+}
+inline ::std::string* SolverParameter::mutable_snapshot_prefix() {
+  set_has_snapshot_prefix();
+  // @@protoc_insertion_point(field_mutable:caffe.SolverParameter.snapshot_prefix)
+  return snapshot_prefix_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline ::std::string* SolverParameter::release_snapshot_prefix() {
+  // @@protoc_insertion_point(field_release:caffe.SolverParameter.snapshot_prefix)
+  clear_has_snapshot_prefix();
+  return snapshot_prefix_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void SolverParameter::set_allocated_snapshot_prefix(::std::string* snapshot_prefix) {
+  if (snapshot_prefix != NULL) {
+    set_has_snapshot_prefix();
+  } else {
+    clear_has_snapshot_prefix();
+  }
+  snapshot_prefix_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), snapshot_prefix);
+  // @@protoc_insertion_point(field_set_allocated:caffe.SolverParameter.snapshot_prefix)
+}
+
+// optional bool snapshot_diff = 16 [default = false];
+inline bool SolverParameter::has_snapshot_diff() const {
+  return (_has_bits_[0] & 0x10000000u) != 0;
+}
+inline void SolverParameter::set_has_snapshot_diff() {
+  _has_bits_[0] |= 0x10000000u;
+}
+inline void SolverParameter::clear_has_snapshot_diff() {
+  _has_bits_[0] &= ~0x10000000u;
+}
+inline void SolverParameter::clear_snapshot_diff() {
+  snapshot_diff_ = false;
+  clear_has_snapshot_diff();
+}
+inline bool SolverParameter::snapshot_diff() const {
+  // @@protoc_insertion_point(field_get:caffe.SolverParameter.snapshot_diff)
+  return snapshot_diff_;
+}
+inline void SolverParameter::set_snapshot_diff(bool value) {
+  set_has_snapshot_diff();
+  snapshot_diff_ = value;
+  // @@protoc_insertion_point(field_set:caffe.SolverParameter.snapshot_diff)
+}
+
+// optional .caffe.SolverParameter.SolverMode solver_mode = 17 [default = GPU];
+inline bool SolverParameter::has_solver_mode() const {
+  return (_has_bits_[0] & 0x20000000u) != 0;
+}
+inline void SolverParameter::set_has_solver_mode() {
+  _has_bits_[0] |= 0x20000000u;
+}
+inline void SolverParameter::clear_has_solver_mode() {
+  _has_bits_[0] &= ~0x20000000u;
+}
+inline void SolverParameter::clear_solver_mode() {
+  solver_mode_ = 1;
+  clear_has_solver_mode();
+}
+inline ::caffe::SolverParameter_SolverMode SolverParameter::solver_mode() const {
+  // @@protoc_insertion_point(field_get:caffe.SolverParameter.solver_mode)
+  return static_cast< ::caffe::SolverParameter_SolverMode >(solver_mode_);
+}
+inline void SolverParameter::set_solver_mode(::caffe::SolverParameter_SolverMode value) {
+  assert(::caffe::SolverParameter_SolverMode_IsValid(value));
+  set_has_solver_mode();
+  solver_mode_ = value;
+  // @@protoc_insertion_point(field_set:caffe.SolverParameter.solver_mode)
+}
+
+// optional int32 device_id = 18 [default = 0];
+inline bool SolverParameter::has_device_id() const {
+  return (_has_bits_[0] & 0x40000000u) != 0;
+}
+inline void SolverParameter::set_has_device_id() {
+  _has_bits_[0] |= 0x40000000u;
+}
+inline void SolverParameter::clear_has_device_id() {
+  _has_bits_[0] &= ~0x40000000u;
+}
+inline void SolverParameter::clear_device_id() {
+  device_id_ = 0;
+  clear_has_device_id();
+}
+inline ::google::protobuf::int32 SolverParameter::device_id() const {
+  // @@protoc_insertion_point(field_get:caffe.SolverParameter.device_id)
+  return device_id_;
+}
+inline void SolverParameter::set_device_id(::google::protobuf::int32 value) {
+  set_has_device_id();
+  device_id_ = value;
+  // @@protoc_insertion_point(field_set:caffe.SolverParameter.device_id)
+}
+
+// optional int64 random_seed = 20 [default = -1];
+inline bool SolverParameter::has_random_seed() const {
+  return (_has_bits_[0] & 0x80000000u) != 0;
+}
+inline void SolverParameter::set_has_random_seed() {
+  _has_bits_[0] |= 0x80000000u;
+}
+inline void SolverParameter::clear_has_random_seed() {
+  _has_bits_[0] &= ~0x80000000u;
+}
+inline void SolverParameter::clear_random_seed() {
+  random_seed_ = GOOGLE_LONGLONG(-1);
+  clear_has_random_seed();
+}
+inline ::google::protobuf::int64 SolverParameter::random_seed() const {
+  // @@protoc_insertion_point(field_get:caffe.SolverParameter.random_seed)
+  return random_seed_;
+}
+inline void SolverParameter::set_random_seed(::google::protobuf::int64 value) {
+  set_has_random_seed();
+  random_seed_ = value;
+  // @@protoc_insertion_point(field_set:caffe.SolverParameter.random_seed)
+}
+
+// optional .caffe.SolverParameter.SolverType solver_type = 30 [default = SGD];
+inline bool SolverParameter::has_solver_type() const {
+  return (_has_bits_[1] & 0x00000001u) != 0;
+}
+inline void SolverParameter::set_has_solver_type() {
+  _has_bits_[1] |= 0x00000001u;
+}
+inline void SolverParameter::clear_has_solver_type() {
+  _has_bits_[1] &= ~0x00000001u;
+}
+inline void SolverParameter::clear_solver_type() {
+  solver_type_ = 0;
+  clear_has_solver_type();
+}
+inline ::caffe::SolverParameter_SolverType SolverParameter::solver_type() const {
+  // @@protoc_insertion_point(field_get:caffe.SolverParameter.solver_type)
+  return static_cast< ::caffe::SolverParameter_SolverType >(solver_type_);
+}
+inline void SolverParameter::set_solver_type(::caffe::SolverParameter_SolverType value) {
+  assert(::caffe::SolverParameter_SolverType_IsValid(value));
+  set_has_solver_type();
+  solver_type_ = value;
+  // @@protoc_insertion_point(field_set:caffe.SolverParameter.solver_type)
+}
+
+// optional float delta = 31 [default = 1e-08];
+inline bool SolverParameter::has_delta() const {
+  return (_has_bits_[1] & 0x00000002u) != 0;
+}
+inline void SolverParameter::set_has_delta() {
+  _has_bits_[1] |= 0x00000002u;
+}
+inline void SolverParameter::clear_has_delta() {
+  _has_bits_[1] &= ~0x00000002u;
+}
+inline void SolverParameter::clear_delta() {
+  delta_ = 1e-08f;
+  clear_has_delta();
+}
+inline float SolverParameter::delta() const {
+  // @@protoc_insertion_point(field_get:caffe.SolverParameter.delta)
+  return delta_;
+}
+inline void SolverParameter::set_delta(float value) {
+  set_has_delta();
+  delta_ = value;
+  // @@protoc_insertion_point(field_set:caffe.SolverParameter.delta)
+}
+
+// optional bool debug_info = 23 [default = false];
+inline bool SolverParameter::has_debug_info() const {
+  return (_has_bits_[1] & 0x00000004u) != 0;
+}
+inline void SolverParameter::set_has_debug_info() {
+  _has_bits_[1] |= 0x00000004u;
+}
+inline void SolverParameter::clear_has_debug_info() {
+  _has_bits_[1] &= ~0x00000004u;
+}
+inline void SolverParameter::clear_debug_info() {
+  debug_info_ = false;
+  clear_has_debug_info();
+}
+inline bool SolverParameter::debug_info() const {
+  // @@protoc_insertion_point(field_get:caffe.SolverParameter.debug_info)
+  return debug_info_;
+}
+inline void SolverParameter::set_debug_info(bool value) {
+  set_has_debug_info();
+  debug_info_ = value;
+  // @@protoc_insertion_point(field_set:caffe.SolverParameter.debug_info)
+}
+
+// optional bool snapshot_after_train = 28 [default = true];
+inline bool SolverParameter::has_snapshot_after_train() const {
+  return (_has_bits_[1] & 0x00000008u) != 0;
+}
+inline void SolverParameter::set_has_snapshot_after_train() {
+  _has_bits_[1] |= 0x00000008u;
+}
+inline void SolverParameter::clear_has_snapshot_after_train() {
+  _has_bits_[1] &= ~0x00000008u;
+}
+inline void SolverParameter::clear_snapshot_after_train() {
+  snapshot_after_train_ = true;
+  clear_has_snapshot_after_train();
+}
+inline bool SolverParameter::snapshot_after_train() const {
+  // @@protoc_insertion_point(field_get:caffe.SolverParameter.snapshot_after_train)
+  return snapshot_after_train_;
+}
+inline void SolverParameter::set_snapshot_after_train(bool value) {
+  set_has_snapshot_after_train();
+  snapshot_after_train_ = value;
+  // @@protoc_insertion_point(field_set:caffe.SolverParameter.snapshot_after_train)
+}
+
+inline const SolverParameter* SolverParameter::internal_default_instance() {
+  return &SolverParameter_default_instance_.get();
+}
+// -------------------------------------------------------------------
+
+// SolverState
+
+// optional int32 iter = 1;
+inline bool SolverState::has_iter() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+inline void SolverState::set_has_iter() {
+  _has_bits_[0] |= 0x00000001u;
+}
+inline void SolverState::clear_has_iter() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+inline void SolverState::clear_iter() {
+  iter_ = 0;
+  clear_has_iter();
+}
+inline ::google::protobuf::int32 SolverState::iter() const {
+  // @@protoc_insertion_point(field_get:caffe.SolverState.iter)
+  return iter_;
+}
+inline void SolverState::set_iter(::google::protobuf::int32 value) {
+  set_has_iter();
+  iter_ = value;
+  // @@protoc_insertion_point(field_set:caffe.SolverState.iter)
+}
+
+// optional string learned_net = 2;
+inline bool SolverState::has_learned_net() const {
+  return (_has_bits_[0] & 0x00000002u) != 0;
+}
+inline void SolverState::set_has_learned_net() {
+  _has_bits_[0] |= 0x00000002u;
+}
+inline void SolverState::clear_has_learned_net() {
+  _has_bits_[0] &= ~0x00000002u;
+}
+inline void SolverState::clear_learned_net() {
+  learned_net_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  clear_has_learned_net();
+}
+inline const ::std::string& SolverState::learned_net() const {
+  // @@protoc_insertion_point(field_get:caffe.SolverState.learned_net)
+  return learned_net_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void SolverState::set_learned_net(const ::std::string& value) {
+  set_has_learned_net();
+  learned_net_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:caffe.SolverState.learned_net)
+}
+inline void SolverState::set_learned_net(const char* value) {
+  set_has_learned_net();
+  learned_net_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:caffe.SolverState.learned_net)
+}
+inline void SolverState::set_learned_net(const char* value, size_t size) {
+  set_has_learned_net();
+  learned_net_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:caffe.SolverState.learned_net)
+}
+inline ::std::string* SolverState::mutable_learned_net() {
+  set_has_learned_net();
+  // @@protoc_insertion_point(field_mutable:caffe.SolverState.learned_net)
+  return learned_net_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline ::std::string* SolverState::release_learned_net() {
+  // @@protoc_insertion_point(field_release:caffe.SolverState.learned_net)
+  clear_has_learned_net();
+  return learned_net_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void SolverState::set_allocated_learned_net(::std::string* learned_net) {
+  if (learned_net != NULL) {
+    set_has_learned_net();
+  } else {
+    clear_has_learned_net();
+  }
+  learned_net_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), learned_net);
+  // @@protoc_insertion_point(field_set_allocated:caffe.SolverState.learned_net)
+}
+
+// repeated .caffe.BlobProto history = 3;
+inline int SolverState::history_size() const {
+  return history_.size();
+}
+inline void SolverState::clear_history() {
+  history_.Clear();
+}
+inline const ::caffe::BlobProto& SolverState::history(int index) const {
+  // @@protoc_insertion_point(field_get:caffe.SolverState.history)
+  return history_.Get(index);
+}
+inline ::caffe::BlobProto* SolverState::mutable_history(int index) {
+  // @@protoc_insertion_point(field_mutable:caffe.SolverState.history)
+  return history_.Mutable(index);
+}
+inline ::caffe::BlobProto* SolverState::add_history() {
+  // @@protoc_insertion_point(field_add:caffe.SolverState.history)
+  return history_.Add();
+}
+inline ::google::protobuf::RepeatedPtrField< ::caffe::BlobProto >*
+SolverState::mutable_history() {
+  // @@protoc_insertion_point(field_mutable_list:caffe.SolverState.history)
+  return &history_;
+}
+inline const ::google::protobuf::RepeatedPtrField< ::caffe::BlobProto >&
+SolverState::history() const {
+  // @@protoc_insertion_point(field_list:caffe.SolverState.history)
+  return history_;
+}
+
+// optional int32 current_step = 4 [default = 0];
+inline bool SolverState::has_current_step() const {
+  return (_has_bits_[0] & 0x00000008u) != 0;
+}
+inline void SolverState::set_has_current_step() {
+  _has_bits_[0] |= 0x00000008u;
+}
+inline void SolverState::clear_has_current_step() {
+  _has_bits_[0] &= ~0x00000008u;
+}
+inline void SolverState::clear_current_step() {
+  current_step_ = 0;
+  clear_has_current_step();
+}
+inline ::google::protobuf::int32 SolverState::current_step() const {
+  // @@protoc_insertion_point(field_get:caffe.SolverState.current_step)
+  return current_step_;
+}
+inline void SolverState::set_current_step(::google::protobuf::int32 value) {
+  set_has_current_step();
+  current_step_ = value;
+  // @@protoc_insertion_point(field_set:caffe.SolverState.current_step)
+}
+
+inline const SolverState* SolverState::internal_default_instance() {
+  return &SolverState_default_instance_.get();
+}
+// -------------------------------------------------------------------
+
+// NetState
+
+// optional .caffe.Phase phase = 1 [default = TEST];
+inline bool NetState::has_phase() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+inline void NetState::set_has_phase() {
+  _has_bits_[0] |= 0x00000001u;
+}
+inline void NetState::clear_has_phase() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+inline void NetState::clear_phase() {
+  phase_ = 1;
+  clear_has_phase();
+}
+inline ::caffe::Phase NetState::phase() const {
+  // @@protoc_insertion_point(field_get:caffe.NetState.phase)
+  return static_cast< ::caffe::Phase >(phase_);
+}
+inline void NetState::set_phase(::caffe::Phase value) {
+  assert(::caffe::Phase_IsValid(value));
+  set_has_phase();
+  phase_ = value;
+  // @@protoc_insertion_point(field_set:caffe.NetState.phase)
+}
+
+// optional int32 level = 2 [default = 0];
+inline bool NetState::has_level() const {
+  return (_has_bits_[0] & 0x00000002u) != 0;
+}
+inline void NetState::set_has_level() {
+  _has_bits_[0] |= 0x00000002u;
+}
+inline void NetState::clear_has_level() {
+  _has_bits_[0] &= ~0x00000002u;
+}
+inline void NetState::clear_level() {
+  level_ = 0;
+  clear_has_level();
+}
+inline ::google::protobuf::int32 NetState::level() const {
+  // @@protoc_insertion_point(field_get:caffe.NetState.level)
+  return level_;
+}
+inline void NetState::set_level(::google::protobuf::int32 value) {
+  set_has_level();
+  level_ = value;
+  // @@protoc_insertion_point(field_set:caffe.NetState.level)
+}
+
+// repeated string stage = 3;
+inline int NetState::stage_size() const {
+  return stage_.size();
+}
+inline void NetState::clear_stage() {
+  stage_.Clear();
+}
+inline const ::std::string& NetState::stage(int index) const {
+  // @@protoc_insertion_point(field_get:caffe.NetState.stage)
+  return stage_.Get(index);
+}
+inline ::std::string* NetState::mutable_stage(int index) {
+  // @@protoc_insertion_point(field_mutable:caffe.NetState.stage)
+  return stage_.Mutable(index);
+}
+inline void NetState::set_stage(int index, const ::std::string& value) {
+  // @@protoc_insertion_point(field_set:caffe.NetState.stage)
+  stage_.Mutable(index)->assign(value);
+}
+inline void NetState::set_stage(int index, const char* value) {
+  stage_.Mutable(index)->assign(value);
+  // @@protoc_insertion_point(field_set_char:caffe.NetState.stage)
+}
+inline void NetState::set_stage(int index, const char* value, size_t size) {
+  stage_.Mutable(index)->assign(
+    reinterpret_cast<const char*>(value), size);
+  // @@protoc_insertion_point(field_set_pointer:caffe.NetState.stage)
+}
+inline ::std::string* NetState::add_stage() {
+  // @@protoc_insertion_point(field_add_mutable:caffe.NetState.stage)
+  return stage_.Add();
+}
+inline void NetState::add_stage(const ::std::string& value) {
+  stage_.Add()->assign(value);
+  // @@protoc_insertion_point(field_add:caffe.NetState.stage)
+}
+inline void NetState::add_stage(const char* value) {
+  stage_.Add()->assign(value);
+  // @@protoc_insertion_point(field_add_char:caffe.NetState.stage)
+}
+inline void NetState::add_stage(const char* value, size_t size) {
+  stage_.Add()->assign(reinterpret_cast<const char*>(value), size);
+  // @@protoc_insertion_point(field_add_pointer:caffe.NetState.stage)
+}
+inline const ::google::protobuf::RepeatedPtrField< ::std::string>&
+NetState::stage() const {
+  // @@protoc_insertion_point(field_list:caffe.NetState.stage)
+  return stage_;
+}
+inline ::google::protobuf::RepeatedPtrField< ::std::string>*
+NetState::mutable_stage() {
+  // @@protoc_insertion_point(field_mutable_list:caffe.NetState.stage)
+  return &stage_;
+}
+
+inline const NetState* NetState::internal_default_instance() {
+  return &NetState_default_instance_.get();
+}
+// -------------------------------------------------------------------
+
+// NetStateRule
+
+// optional .caffe.Phase phase = 1;
+inline bool NetStateRule::has_phase() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+inline void NetStateRule::set_has_phase() {
+  _has_bits_[0] |= 0x00000001u;
+}
+inline void NetStateRule::clear_has_phase() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+inline void NetStateRule::clear_phase() {
+  phase_ = 0;
+  clear_has_phase();
+}
+inline ::caffe::Phase NetStateRule::phase() const {
+  // @@protoc_insertion_point(field_get:caffe.NetStateRule.phase)
+  return static_cast< ::caffe::Phase >(phase_);
+}
+inline void NetStateRule::set_phase(::caffe::Phase value) {
+  assert(::caffe::Phase_IsValid(value));
+  set_has_phase();
+  phase_ = value;
+  // @@protoc_insertion_point(field_set:caffe.NetStateRule.phase)
+}
+
+// optional int32 min_level = 2;
+inline bool NetStateRule::has_min_level() const {
+  return (_has_bits_[0] & 0x00000002u) != 0;
+}
+inline void NetStateRule::set_has_min_level() {
+  _has_bits_[0] |= 0x00000002u;
+}
+inline void NetStateRule::clear_has_min_level() {
+  _has_bits_[0] &= ~0x00000002u;
+}
+inline void NetStateRule::clear_min_level() {
+  min_level_ = 0;
+  clear_has_min_level();
+}
+inline ::google::protobuf::int32 NetStateRule::min_level() const {
+  // @@protoc_insertion_point(field_get:caffe.NetStateRule.min_level)
+  return min_level_;
+}
+inline void NetStateRule::set_min_level(::google::protobuf::int32 value) {
+  set_has_min_level();
+  min_level_ = value;
+  // @@protoc_insertion_point(field_set:caffe.NetStateRule.min_level)
+}
+
+// optional int32 max_level = 3;
+inline bool NetStateRule::has_max_level() const {
+  return (_has_bits_[0] & 0x00000004u) != 0;
+}
+inline void NetStateRule::set_has_max_level() {
+  _has_bits_[0] |= 0x00000004u;
+}
+inline void NetStateRule::clear_has_max_level() {
+  _has_bits_[0] &= ~0x00000004u;
+}
+inline void NetStateRule::clear_max_level() {
+  max_level_ = 0;
+  clear_has_max_level();
+}
+inline ::google::protobuf::int32 NetStateRule::max_level() const {
+  // @@protoc_insertion_point(field_get:caffe.NetStateRule.max_level)
+  return max_level_;
+}
+inline void NetStateRule::set_max_level(::google::protobuf::int32 value) {
+  set_has_max_level();
+  max_level_ = value;
+  // @@protoc_insertion_point(field_set:caffe.NetStateRule.max_level)
+}
+
+// repeated string stage = 4;
+inline int NetStateRule::stage_size() const {
+  return stage_.size();
+}
+inline void NetStateRule::clear_stage() {
+  stage_.Clear();
+}
+inline const ::std::string& NetStateRule::stage(int index) const {
+  // @@protoc_insertion_point(field_get:caffe.NetStateRule.stage)
+  return stage_.Get(index);
+}
+inline ::std::string* NetStateRule::mutable_stage(int index) {
+  // @@protoc_insertion_point(field_mutable:caffe.NetStateRule.stage)
+  return stage_.Mutable(index);
+}
+inline void NetStateRule::set_stage(int index, const ::std::string& value) {
+  // @@protoc_insertion_point(field_set:caffe.NetStateRule.stage)
+  stage_.Mutable(index)->assign(value);
+}
+inline void NetStateRule::set_stage(int index, const char* value) {
+  stage_.Mutable(index)->assign(value);
+  // @@protoc_insertion_point(field_set_char:caffe.NetStateRule.stage)
+}
+inline void NetStateRule::set_stage(int index, const char* value, size_t size) {
+  stage_.Mutable(index)->assign(
+    reinterpret_cast<const char*>(value), size);
+  // @@protoc_insertion_point(field_set_pointer:caffe.NetStateRule.stage)
+}
+inline ::std::string* NetStateRule::add_stage() {
+  // @@protoc_insertion_point(field_add_mutable:caffe.NetStateRule.stage)
+  return stage_.Add();
+}
+inline void NetStateRule::add_stage(const ::std::string& value) {
+  stage_.Add()->assign(value);
+  // @@protoc_insertion_point(field_add:caffe.NetStateRule.stage)
+}
+inline void NetStateRule::add_stage(const char* value) {
+  stage_.Add()->assign(value);
+  // @@protoc_insertion_point(field_add_char:caffe.NetStateRule.stage)
+}
+inline void NetStateRule::add_stage(const char* value, size_t size) {
+  stage_.Add()->assign(reinterpret_cast<const char*>(value), size);
+  // @@protoc_insertion_point(field_add_pointer:caffe.NetStateRule.stage)
+}
+inline const ::google::protobuf::RepeatedPtrField< ::std::string>&
+NetStateRule::stage() const {
+  // @@protoc_insertion_point(field_list:caffe.NetStateRule.stage)
+  return stage_;
+}
+inline ::google::protobuf::RepeatedPtrField< ::std::string>*
+NetStateRule::mutable_stage() {
+  // @@protoc_insertion_point(field_mutable_list:caffe.NetStateRule.stage)
+  return &stage_;
+}
+
+// repeated string not_stage = 5;
+inline int NetStateRule::not_stage_size() const {
+  return not_stage_.size();
+}
+inline void NetStateRule::clear_not_stage() {
+  not_stage_.Clear();
+}
+inline const ::std::string& NetStateRule::not_stage(int index) const {
+  // @@protoc_insertion_point(field_get:caffe.NetStateRule.not_stage)
+  return not_stage_.Get(index);
+}
+inline ::std::string* NetStateRule::mutable_not_stage(int index) {
+  // @@protoc_insertion_point(field_mutable:caffe.NetStateRule.not_stage)
+  return not_stage_.Mutable(index);
+}
+inline void NetStateRule::set_not_stage(int index, const ::std::string& value) {
+  // @@protoc_insertion_point(field_set:caffe.NetStateRule.not_stage)
+  not_stage_.Mutable(index)->assign(value);
+}
+inline void NetStateRule::set_not_stage(int index, const char* value) {
+  not_stage_.Mutable(index)->assign(value);
+  // @@protoc_insertion_point(field_set_char:caffe.NetStateRule.not_stage)
+}
+inline void NetStateRule::set_not_stage(int index, const char* value, size_t size) {
+  not_stage_.Mutable(index)->assign(
+    reinterpret_cast<const char*>(value), size);
+  // @@protoc_insertion_point(field_set_pointer:caffe.NetStateRule.not_stage)
+}
+inline ::std::string* NetStateRule::add_not_stage() {
+  // @@protoc_insertion_point(field_add_mutable:caffe.NetStateRule.not_stage)
+  return not_stage_.Add();
+}
+inline void NetStateRule::add_not_stage(const ::std::string& value) {
+  not_stage_.Add()->assign(value);
+  // @@protoc_insertion_point(field_add:caffe.NetStateRule.not_stage)
+}
+inline void NetStateRule::add_not_stage(const char* value) {
+  not_stage_.Add()->assign(value);
+  // @@protoc_insertion_point(field_add_char:caffe.NetStateRule.not_stage)
+}
+inline void NetStateRule::add_not_stage(const char* value, size_t size) {
+  not_stage_.Add()->assign(reinterpret_cast<const char*>(value), size);
+  // @@protoc_insertion_point(field_add_pointer:caffe.NetStateRule.not_stage)
+}
+inline const ::google::protobuf::RepeatedPtrField< ::std::string>&
+NetStateRule::not_stage() const {
+  // @@protoc_insertion_point(field_list:caffe.NetStateRule.not_stage)
+  return not_stage_;
+}
+inline ::google::protobuf::RepeatedPtrField< ::std::string>*
+NetStateRule::mutable_not_stage() {
+  // @@protoc_insertion_point(field_mutable_list:caffe.NetStateRule.not_stage)
+  return &not_stage_;
+}
+
+inline const NetStateRule* NetStateRule::internal_default_instance() {
+  return &NetStateRule_default_instance_.get();
+}
+// -------------------------------------------------------------------
+
+// ParamSpec
+
+// optional string name = 1;
+inline bool ParamSpec::has_name() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+inline void ParamSpec::set_has_name() {
+  _has_bits_[0] |= 0x00000001u;
+}
+inline void ParamSpec::clear_has_name() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+inline void ParamSpec::clear_name() {
+  name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  clear_has_name();
+}
+inline const ::std::string& ParamSpec::name() const {
+  // @@protoc_insertion_point(field_get:caffe.ParamSpec.name)
+  return name_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void ParamSpec::set_name(const ::std::string& value) {
+  set_has_name();
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:caffe.ParamSpec.name)
+}
+inline void ParamSpec::set_name(const char* value) {
+  set_has_name();
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:caffe.ParamSpec.name)
+}
+inline void ParamSpec::set_name(const char* value, size_t size) {
+  set_has_name();
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:caffe.ParamSpec.name)
+}
+inline ::std::string* ParamSpec::mutable_name() {
+  set_has_name();
+  // @@protoc_insertion_point(field_mutable:caffe.ParamSpec.name)
+  return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline ::std::string* ParamSpec::release_name() {
+  // @@protoc_insertion_point(field_release:caffe.ParamSpec.name)
+  clear_has_name();
+  return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void ParamSpec::set_allocated_name(::std::string* name) {
+  if (name != NULL) {
+    set_has_name();
+  } else {
+    clear_has_name();
+  }
+  name_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), name);
+  // @@protoc_insertion_point(field_set_allocated:caffe.ParamSpec.name)
+}
+
+// optional .caffe.ParamSpec.DimCheckMode share_mode = 2;
+inline bool ParamSpec::has_share_mode() const {
+  return (_has_bits_[0] & 0x00000002u) != 0;
+}
+inline void ParamSpec::set_has_share_mode() {
+  _has_bits_[0] |= 0x00000002u;
+}
+inline void ParamSpec::clear_has_share_mode() {
+  _has_bits_[0] &= ~0x00000002u;
+}
+inline void ParamSpec::clear_share_mode() {
+  share_mode_ = 0;
+  clear_has_share_mode();
+}
+inline ::caffe::ParamSpec_DimCheckMode ParamSpec::share_mode() const {
+  // @@protoc_insertion_point(field_get:caffe.ParamSpec.share_mode)
+  return static_cast< ::caffe::ParamSpec_DimCheckMode >(share_mode_);
+}
+inline void ParamSpec::set_share_mode(::caffe::ParamSpec_DimCheckMode value) {
+  assert(::caffe::ParamSpec_DimCheckMode_IsValid(value));
+  set_has_share_mode();
+  share_mode_ = value;
+  // @@protoc_insertion_point(field_set:caffe.ParamSpec.share_mode)
+}
+
+// optional float lr_mult = 3 [default = 1];
+inline bool ParamSpec::has_lr_mult() const {
+  return (_has_bits_[0] & 0x00000004u) != 0;
+}
+inline void ParamSpec::set_has_lr_mult() {
+  _has_bits_[0] |= 0x00000004u;
+}
+inline void ParamSpec::clear_has_lr_mult() {
+  _has_bits_[0] &= ~0x00000004u;
+}
+inline void ParamSpec::clear_lr_mult() {
+  lr_mult_ = 1;
+  clear_has_lr_mult();
+}
+inline float ParamSpec::lr_mult() const {
+  // @@protoc_insertion_point(field_get:caffe.ParamSpec.lr_mult)
+  return lr_mult_;
+}
+inline void ParamSpec::set_lr_mult(float value) {
+  set_has_lr_mult();
+  lr_mult_ = value;
+  // @@protoc_insertion_point(field_set:caffe.ParamSpec.lr_mult)
+}
+
+// optional float decay_mult = 4 [default = 1];
+inline bool ParamSpec::has_decay_mult() const {
+  return (_has_bits_[0] & 0x00000008u) != 0;
+}
+inline void ParamSpec::set_has_decay_mult() {
+  _has_bits_[0] |= 0x00000008u;
+}
+inline void ParamSpec::clear_has_decay_mult() {
+  _has_bits_[0] &= ~0x00000008u;
+}
+inline void ParamSpec::clear_decay_mult() {
+  decay_mult_ = 1;
+  clear_has_decay_mult();
+}
+inline float ParamSpec::decay_mult() const {
+  // @@protoc_insertion_point(field_get:caffe.ParamSpec.decay_mult)
+  return decay_mult_;
+}
+inline void ParamSpec::set_decay_mult(float value) {
+  set_has_decay_mult();
+  decay_mult_ = value;
+  // @@protoc_insertion_point(field_set:caffe.ParamSpec.decay_mult)
+}
+
+inline const ParamSpec* ParamSpec::internal_default_instance() {
+  return &ParamSpec_default_instance_.get();
+}
+// -------------------------------------------------------------------
+
+// LayerParameter
+
+// optional string name = 1;
+inline bool LayerParameter::has_name() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+inline void LayerParameter::set_has_name() {
+  _has_bits_[0] |= 0x00000001u;
+}
+inline void LayerParameter::clear_has_name() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+inline void LayerParameter::clear_name() {
+  name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  clear_has_name();
+}
+inline const ::std::string& LayerParameter::name() const {
+  // @@protoc_insertion_point(field_get:caffe.LayerParameter.name)
+  return name_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void LayerParameter::set_name(const ::std::string& value) {
+  set_has_name();
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:caffe.LayerParameter.name)
+}
+inline void LayerParameter::set_name(const char* value) {
+  set_has_name();
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:caffe.LayerParameter.name)
+}
+inline void LayerParameter::set_name(const char* value, size_t size) {
+  set_has_name();
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:caffe.LayerParameter.name)
+}
+inline ::std::string* LayerParameter::mutable_name() {
+  set_has_name();
+  // @@protoc_insertion_point(field_mutable:caffe.LayerParameter.name)
+  return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline ::std::string* LayerParameter::release_name() {
+  // @@protoc_insertion_point(field_release:caffe.LayerParameter.name)
+  clear_has_name();
+  return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void LayerParameter::set_allocated_name(::std::string* name) {
+  if (name != NULL) {
+    set_has_name();
+  } else {
+    clear_has_name();
+  }
+  name_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), name);
+  // @@protoc_insertion_point(field_set_allocated:caffe.LayerParameter.name)
+}
+
+// optional string type = 2;
+inline bool LayerParameter::has_type() const {
+  return (_has_bits_[0] & 0x00000002u) != 0;
+}
+inline void LayerParameter::set_has_type() {
+  _has_bits_[0] |= 0x00000002u;
+}
+inline void LayerParameter::clear_has_type() {
+  _has_bits_[0] &= ~0x00000002u;
+}
+inline void LayerParameter::clear_type() {
+  type_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  clear_has_type();
+}
+inline const ::std::string& LayerParameter::type() const {
+  // @@protoc_insertion_point(field_get:caffe.LayerParameter.type)
+  return type_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void LayerParameter::set_type(const ::std::string& value) {
+  set_has_type();
+  type_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:caffe.LayerParameter.type)
+}
+inline void LayerParameter::set_type(const char* value) {
+  set_has_type();
+  type_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:caffe.LayerParameter.type)
+}
+inline void LayerParameter::set_type(const char* value, size_t size) {
+  set_has_type();
+  type_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:caffe.LayerParameter.type)
+}
+inline ::std::string* LayerParameter::mutable_type() {
+  set_has_type();
+  // @@protoc_insertion_point(field_mutable:caffe.LayerParameter.type)
+  return type_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline ::std::string* LayerParameter::release_type() {
+  // @@protoc_insertion_point(field_release:caffe.LayerParameter.type)
+  clear_has_type();
+  return type_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void LayerParameter::set_allocated_type(::std::string* type) {
+  if (type != NULL) {
+    set_has_type();
+  } else {
+    clear_has_type();
+  }
+  type_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), type);
+  // @@protoc_insertion_point(field_set_allocated:caffe.LayerParameter.type)
+}
+
+// repeated string bottom = 3;
+inline int LayerParameter::bottom_size() const {
+  return bottom_.size();
+}
+inline void LayerParameter::clear_bottom() {
+  bottom_.Clear();
+}
+inline const ::std::string& LayerParameter::bottom(int index) const {
+  // @@protoc_insertion_point(field_get:caffe.LayerParameter.bottom)
+  return bottom_.Get(index);
+}
+inline ::std::string* LayerParameter::mutable_bottom(int index) {
+  // @@protoc_insertion_point(field_mutable:caffe.LayerParameter.bottom)
+  return bottom_.Mutable(index);
+}
+inline void LayerParameter::set_bottom(int index, const ::std::string& value) {
+  // @@protoc_insertion_point(field_set:caffe.LayerParameter.bottom)
+  bottom_.Mutable(index)->assign(value);
+}
+inline void LayerParameter::set_bottom(int index, const char* value) {
+  bottom_.Mutable(index)->assign(value);
+  // @@protoc_insertion_point(field_set_char:caffe.LayerParameter.bottom)
+}
+inline void LayerParameter::set_bottom(int index, const char* value, size_t size) {
+  bottom_.Mutable(index)->assign(
+    reinterpret_cast<const char*>(value), size);
+  // @@protoc_insertion_point(field_set_pointer:caffe.LayerParameter.bottom)
+}
+inline ::std::string* LayerParameter::add_bottom() {
+  // @@protoc_insertion_point(field_add_mutable:caffe.LayerParameter.bottom)
+  return bottom_.Add();
+}
+inline void LayerParameter::add_bottom(const ::std::string& value) {
+  bottom_.Add()->assign(value);
+  // @@protoc_insertion_point(field_add:caffe.LayerParameter.bottom)
+}
+inline void LayerParameter::add_bottom(const char* value) {
+  bottom_.Add()->assign(value);
+  // @@protoc_insertion_point(field_add_char:caffe.LayerParameter.bottom)
+}
+inline void LayerParameter::add_bottom(const char* value, size_t size) {
+  bottom_.Add()->assign(reinterpret_cast<const char*>(value), size);
+  // @@protoc_insertion_point(field_add_pointer:caffe.LayerParameter.bottom)
+}
+inline const ::google::protobuf::RepeatedPtrField< ::std::string>&
+LayerParameter::bottom() const {
+  // @@protoc_insertion_point(field_list:caffe.LayerParameter.bottom)
+  return bottom_;
+}
+inline ::google::protobuf::RepeatedPtrField< ::std::string>*
+LayerParameter::mutable_bottom() {
+  // @@protoc_insertion_point(field_mutable_list:caffe.LayerParameter.bottom)
+  return &bottom_;
+}
+
+// repeated string top = 4;
+inline int LayerParameter::top_size() const {
+  return top_.size();
+}
+inline void LayerParameter::clear_top() {
+  top_.Clear();
+}
+inline const ::std::string& LayerParameter::top(int index) const {
+  // @@protoc_insertion_point(field_get:caffe.LayerParameter.top)
+  return top_.Get(index);
+}
+inline ::std::string* LayerParameter::mutable_top(int index) {
+  // @@protoc_insertion_point(field_mutable:caffe.LayerParameter.top)
+  return top_.Mutable(index);
+}
+inline void LayerParameter::set_top(int index, const ::std::string& value) {
+  // @@protoc_insertion_point(field_set:caffe.LayerParameter.top)
+  top_.Mutable(index)->assign(value);
+}
+inline void LayerParameter::set_top(int index, const char* value) {
+  top_.Mutable(index)->assign(value);
+  // @@protoc_insertion_point(field_set_char:caffe.LayerParameter.top)
+}
+inline void LayerParameter::set_top(int index, const char* value, size_t size) {
+  top_.Mutable(index)->assign(
+    reinterpret_cast<const char*>(value), size);
+  // @@protoc_insertion_point(field_set_pointer:caffe.LayerParameter.top)
+}
+inline ::std::string* LayerParameter::add_top() {
+  // @@protoc_insertion_point(field_add_mutable:caffe.LayerParameter.top)
+  return top_.Add();
+}
+inline void LayerParameter::add_top(const ::std::string& value) {
+  top_.Add()->assign(value);
+  // @@protoc_insertion_point(field_add:caffe.LayerParameter.top)
+}
+inline void LayerParameter::add_top(const char* value) {
+  top_.Add()->assign(value);
+  // @@protoc_insertion_point(field_add_char:caffe.LayerParameter.top)
+}
+inline void LayerParameter::add_top(const char* value, size_t size) {
+  top_.Add()->assign(reinterpret_cast<const char*>(value), size);
+  // @@protoc_insertion_point(field_add_pointer:caffe.LayerParameter.top)
+}
+inline const ::google::protobuf::RepeatedPtrField< ::std::string>&
+LayerParameter::top() const {
+  // @@protoc_insertion_point(field_list:caffe.LayerParameter.top)
+  return top_;
+}
+inline ::google::protobuf::RepeatedPtrField< ::std::string>*
+LayerParameter::mutable_top() {
+  // @@protoc_insertion_point(field_mutable_list:caffe.LayerParameter.top)
+  return &top_;
+}
+
+// optional .caffe.Phase phase = 10;
+inline bool LayerParameter::has_phase() const {
+  return (_has_bits_[0] & 0x00000010u) != 0;
+}
+inline void LayerParameter::set_has_phase() {
+  _has_bits_[0] |= 0x00000010u;
+}
+inline void LayerParameter::clear_has_phase() {
+  _has_bits_[0] &= ~0x00000010u;
+}
+inline void LayerParameter::clear_phase() {
+  phase_ = 0;
+  clear_has_phase();
+}
+inline ::caffe::Phase LayerParameter::phase() const {
+  // @@protoc_insertion_point(field_get:caffe.LayerParameter.phase)
+  return static_cast< ::caffe::Phase >(phase_);
+}
+inline void LayerParameter::set_phase(::caffe::Phase value) {
+  assert(::caffe::Phase_IsValid(value));
+  set_has_phase();
+  phase_ = value;
+  // @@protoc_insertion_point(field_set:caffe.LayerParameter.phase)
+}
+
+// repeated float loss_weight = 5;
+inline int LayerParameter::loss_weight_size() const {
+  return loss_weight_.size();
+}
+inline void LayerParameter::clear_loss_weight() {
+  loss_weight_.Clear();
+}
+inline float LayerParameter::loss_weight(int index) const {
+  // @@protoc_insertion_point(field_get:caffe.LayerParameter.loss_weight)
+  return loss_weight_.Get(index);
+}
+inline void LayerParameter::set_loss_weight(int index, float value) {
+  loss_weight_.Set(index, value);
+  // @@protoc_insertion_point(field_set:caffe.LayerParameter.loss_weight)
+}
+inline void LayerParameter::add_loss_weight(float value) {
+  loss_weight_.Add(value);
+  // @@protoc_insertion_point(field_add:caffe.LayerParameter.loss_weight)
+}
+inline const ::google::protobuf::RepeatedField< float >&
+LayerParameter::loss_weight() const {
+  // @@protoc_insertion_point(field_list:caffe.LayerParameter.loss_weight)
+  return loss_weight_;
+}
+inline ::google::protobuf::RepeatedField< float >*
+LayerParameter::mutable_loss_weight() {
+  // @@protoc_insertion_point(field_mutable_list:caffe.LayerParameter.loss_weight)
+  return &loss_weight_;
+}
+
+// repeated .caffe.ParamSpec param = 6;
+inline int LayerParameter::param_size() const {
+  return param_.size();
+}
+inline void LayerParameter::clear_param() {
+  param_.Clear();
+}
+inline const ::caffe::ParamSpec& LayerParameter::param(int index) const {
+  // @@protoc_insertion_point(field_get:caffe.LayerParameter.param)
+  return param_.Get(index);
+}
+inline ::caffe::ParamSpec* LayerParameter::mutable_param(int index) {
+  // @@protoc_insertion_point(field_mutable:caffe.LayerParameter.param)
+  return param_.Mutable(index);
+}
+inline ::caffe::ParamSpec* LayerParameter::add_param() {
+  // @@protoc_insertion_point(field_add:caffe.LayerParameter.param)
+  return param_.Add();
+}
+inline ::google::protobuf::RepeatedPtrField< ::caffe::ParamSpec >*
+LayerParameter::mutable_param() {
+  // @@protoc_insertion_point(field_mutable_list:caffe.LayerParameter.param)
+  return &param_;
+}
+inline const ::google::protobuf::RepeatedPtrField< ::caffe::ParamSpec >&
+LayerParameter::param() const {
+  // @@protoc_insertion_point(field_list:caffe.LayerParameter.param)
+  return param_;
+}
+
+// repeated .caffe.BlobProto blobs = 7;
+inline int LayerParameter::blobs_size() const {
+  return blobs_.size();
+}
+inline void LayerParameter::clear_blobs() {
+  blobs_.Clear();
+}
+inline const ::caffe::BlobProto& LayerParameter::blobs(int index) const {
+  // @@protoc_insertion_point(field_get:caffe.LayerParameter.blobs)
+  return blobs_.Get(index);
+}
+inline ::caffe::BlobProto* LayerParameter::mutable_blobs(int index) {
+  // @@protoc_insertion_point(field_mutable:caffe.LayerParameter.blobs)
+  return blobs_.Mutable(index);
+}
+inline ::caffe::BlobProto* LayerParameter::add_blobs() {
+  // @@protoc_insertion_point(field_add:caffe.LayerParameter.blobs)
+  return blobs_.Add();
+}
+inline ::google::protobuf::RepeatedPtrField< ::caffe::BlobProto >*
+LayerParameter::mutable_blobs() {
+  // @@protoc_insertion_point(field_mutable_list:caffe.LayerParameter.blobs)
+  return &blobs_;
+}
+inline const ::google::protobuf::RepeatedPtrField< ::caffe::BlobProto >&
+LayerParameter::blobs() const {
+  // @@protoc_insertion_point(field_list:caffe.LayerParameter.blobs)
+  return blobs_;
+}
+
+// repeated bool propagate_down = 11;
+inline int LayerParameter::propagate_down_size() const {
+  return propagate_down_.size();
+}
+inline void LayerParameter::clear_propagate_down() {
+  propagate_down_.Clear();
+}
+inline bool LayerParameter::propagate_down(int index) const {
+  // @@protoc_insertion_point(field_get:caffe.LayerParameter.propagate_down)
+  return propagate_down_.Get(index);
+}
+inline void LayerParameter::set_propagate_down(int index, bool value) {
+  propagate_down_.Set(index, value);
+  // @@protoc_insertion_point(field_set:caffe.LayerParameter.propagate_down)
+}
+inline void LayerParameter::add_propagate_down(bool value) {
+  propagate_down_.Add(value);
+  // @@protoc_insertion_point(field_add:caffe.LayerParameter.propagate_down)
+}
+inline const ::google::protobuf::RepeatedField< bool >&
+LayerParameter::propagate_down() const {
+  // @@protoc_insertion_point(field_list:caffe.LayerParameter.propagate_down)
+  return propagate_down_;
+}
+inline ::google::protobuf::RepeatedField< bool >*
+LayerParameter::mutable_propagate_down() {
+  // @@protoc_insertion_point(field_mutable_list:caffe.LayerParameter.propagate_down)
+  return &propagate_down_;
+}
+
+// repeated .caffe.NetStateRule include = 8;
+inline int LayerParameter::include_size() const {
+  return include_.size();
+}
+inline void LayerParameter::clear_include() {
+  include_.Clear();
+}
+inline const ::caffe::NetStateRule& LayerParameter::include(int index) const {
+  // @@protoc_insertion_point(field_get:caffe.LayerParameter.include)
+  return include_.Get(index);
+}
+inline ::caffe::NetStateRule* LayerParameter::mutable_include(int index) {
+  // @@protoc_insertion_point(field_mutable:caffe.LayerParameter.include)
+  return include_.Mutable(index);
+}
+inline ::caffe::NetStateRule* LayerParameter::add_include() {
+  // @@protoc_insertion_point(field_add:caffe.LayerParameter.include)
+  return include_.Add();
+}
+inline ::google::protobuf::RepeatedPtrField< ::caffe::NetStateRule >*
+LayerParameter::mutable_include() {
+  // @@protoc_insertion_point(field_mutable_list:caffe.LayerParameter.include)
+  return &include_;
+}
+inline const ::google::protobuf::RepeatedPtrField< ::caffe::NetStateRule >&
+LayerParameter::include() const {
+  // @@protoc_insertion_point(field_list:caffe.LayerParameter.include)
+  return include_;
+}
+
+// repeated .caffe.NetStateRule exclude = 9;
+inline int LayerParameter::exclude_size() const {
+  return exclude_.size();
+}
+inline void LayerParameter::clear_exclude() {
+  exclude_.Clear();
+}
+inline const ::caffe::NetStateRule& LayerParameter::exclude(int index) const {
+  // @@protoc_insertion_point(field_get:caffe.LayerParameter.exclude)
+  return exclude_.Get(index);
+}
+inline ::caffe::NetStateRule* LayerParameter::mutable_exclude(int index) {
+  // @@protoc_insertion_point(field_mutable:caffe.LayerParameter.exclude)
+  return exclude_.Mutable(index);
+}
+inline ::caffe::NetStateRule* LayerParameter::add_exclude() {
+  // @@protoc_insertion_point(field_add:caffe.LayerParameter.exclude)
+  return exclude_.Add();
+}
+inline ::google::protobuf::RepeatedPtrField< ::caffe::NetStateRule >*
+LayerParameter::mutable_exclude() {
+  // @@protoc_insertion_point(field_mutable_list:caffe.LayerParameter.exclude)
+  return &exclude_;
+}
+inline const ::google::protobuf::RepeatedPtrField< ::caffe::NetStateRule >&
+LayerParameter::exclude() const {
+  // @@protoc_insertion_point(field_list:caffe.LayerParameter.exclude)
+  return exclude_;
+}
+
+// optional .caffe.TransformationParameter transform_param = 100;
+inline bool LayerParameter::has_transform_param() const {
+  return (_has_bits_[0] & 0x00000800u) != 0;
+}
+inline void LayerParameter::set_has_transform_param() {
+  _has_bits_[0] |= 0x00000800u;
+}
+inline void LayerParameter::clear_has_transform_param() {
+  _has_bits_[0] &= ~0x00000800u;
+}
+inline void LayerParameter::clear_transform_param() {
+  if (transform_param_ != NULL) transform_param_->::caffe::TransformationParameter::Clear();
+  clear_has_transform_param();
+}
+inline const ::caffe::TransformationParameter& LayerParameter::transform_param() const {
+  // @@protoc_insertion_point(field_get:caffe.LayerParameter.transform_param)
+  return transform_param_ != NULL ? *transform_param_
+                         : *::caffe::TransformationParameter::internal_default_instance();
+}
+inline ::caffe::TransformationParameter* LayerParameter::mutable_transform_param() {
+  set_has_transform_param();
+  if (transform_param_ == NULL) {
+    transform_param_ = new ::caffe::TransformationParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.LayerParameter.transform_param)
+  return transform_param_;
+}
+inline ::caffe::TransformationParameter* LayerParameter::release_transform_param() {
+  // @@protoc_insertion_point(field_release:caffe.LayerParameter.transform_param)
+  clear_has_transform_param();
+  ::caffe::TransformationParameter* temp = transform_param_;
+  transform_param_ = NULL;
+  return temp;
+}
+inline void LayerParameter::set_allocated_transform_param(::caffe::TransformationParameter* transform_param) {
+  delete transform_param_;
+  transform_param_ = transform_param;
+  if (transform_param) {
+    set_has_transform_param();
+  } else {
+    clear_has_transform_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.LayerParameter.transform_param)
+}
+
+// optional .caffe.LossParameter loss_param = 101;
+inline bool LayerParameter::has_loss_param() const {
+  return (_has_bits_[0] & 0x00001000u) != 0;
+}
+inline void LayerParameter::set_has_loss_param() {
+  _has_bits_[0] |= 0x00001000u;
+}
+inline void LayerParameter::clear_has_loss_param() {
+  _has_bits_[0] &= ~0x00001000u;
+}
+inline void LayerParameter::clear_loss_param() {
+  if (loss_param_ != NULL) loss_param_->::caffe::LossParameter::Clear();
+  clear_has_loss_param();
+}
+inline const ::caffe::LossParameter& LayerParameter::loss_param() const {
+  // @@protoc_insertion_point(field_get:caffe.LayerParameter.loss_param)
+  return loss_param_ != NULL ? *loss_param_
+                         : *::caffe::LossParameter::internal_default_instance();
+}
+inline ::caffe::LossParameter* LayerParameter::mutable_loss_param() {
+  set_has_loss_param();
+  if (loss_param_ == NULL) {
+    loss_param_ = new ::caffe::LossParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.LayerParameter.loss_param)
+  return loss_param_;
+}
+inline ::caffe::LossParameter* LayerParameter::release_loss_param() {
+  // @@protoc_insertion_point(field_release:caffe.LayerParameter.loss_param)
+  clear_has_loss_param();
+  ::caffe::LossParameter* temp = loss_param_;
+  loss_param_ = NULL;
+  return temp;
+}
+inline void LayerParameter::set_allocated_loss_param(::caffe::LossParameter* loss_param) {
+  delete loss_param_;
+  loss_param_ = loss_param;
+  if (loss_param) {
+    set_has_loss_param();
+  } else {
+    clear_has_loss_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.LayerParameter.loss_param)
+}
+
+// optional .caffe.AccuracyParameter accuracy_param = 102;
+inline bool LayerParameter::has_accuracy_param() const {
+  return (_has_bits_[0] & 0x00002000u) != 0;
+}
+inline void LayerParameter::set_has_accuracy_param() {
+  _has_bits_[0] |= 0x00002000u;
+}
+inline void LayerParameter::clear_has_accuracy_param() {
+  _has_bits_[0] &= ~0x00002000u;
+}
+inline void LayerParameter::clear_accuracy_param() {
+  if (accuracy_param_ != NULL) accuracy_param_->::caffe::AccuracyParameter::Clear();
+  clear_has_accuracy_param();
+}
+inline const ::caffe::AccuracyParameter& LayerParameter::accuracy_param() const {
+  // @@protoc_insertion_point(field_get:caffe.LayerParameter.accuracy_param)
+  return accuracy_param_ != NULL ? *accuracy_param_
+                         : *::caffe::AccuracyParameter::internal_default_instance();
+}
+inline ::caffe::AccuracyParameter* LayerParameter::mutable_accuracy_param() {
+  set_has_accuracy_param();
+  if (accuracy_param_ == NULL) {
+    accuracy_param_ = new ::caffe::AccuracyParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.LayerParameter.accuracy_param)
+  return accuracy_param_;
+}
+inline ::caffe::AccuracyParameter* LayerParameter::release_accuracy_param() {
+  // @@protoc_insertion_point(field_release:caffe.LayerParameter.accuracy_param)
+  clear_has_accuracy_param();
+  ::caffe::AccuracyParameter* temp = accuracy_param_;
+  accuracy_param_ = NULL;
+  return temp;
+}
+inline void LayerParameter::set_allocated_accuracy_param(::caffe::AccuracyParameter* accuracy_param) {
+  delete accuracy_param_;
+  accuracy_param_ = accuracy_param;
+  if (accuracy_param) {
+    set_has_accuracy_param();
+  } else {
+    clear_has_accuracy_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.LayerParameter.accuracy_param)
+}
+
+// optional .caffe.ArgMaxParameter argmax_param = 103;
+inline bool LayerParameter::has_argmax_param() const {
+  return (_has_bits_[0] & 0x00004000u) != 0;
+}
+inline void LayerParameter::set_has_argmax_param() {
+  _has_bits_[0] |= 0x00004000u;
+}
+inline void LayerParameter::clear_has_argmax_param() {
+  _has_bits_[0] &= ~0x00004000u;
+}
+inline void LayerParameter::clear_argmax_param() {
+  if (argmax_param_ != NULL) argmax_param_->::caffe::ArgMaxParameter::Clear();
+  clear_has_argmax_param();
+}
+inline const ::caffe::ArgMaxParameter& LayerParameter::argmax_param() const {
+  // @@protoc_insertion_point(field_get:caffe.LayerParameter.argmax_param)
+  return argmax_param_ != NULL ? *argmax_param_
+                         : *::caffe::ArgMaxParameter::internal_default_instance();
+}
+inline ::caffe::ArgMaxParameter* LayerParameter::mutable_argmax_param() {
+  set_has_argmax_param();
+  if (argmax_param_ == NULL) {
+    argmax_param_ = new ::caffe::ArgMaxParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.LayerParameter.argmax_param)
+  return argmax_param_;
+}
+inline ::caffe::ArgMaxParameter* LayerParameter::release_argmax_param() {
+  // @@protoc_insertion_point(field_release:caffe.LayerParameter.argmax_param)
+  clear_has_argmax_param();
+  ::caffe::ArgMaxParameter* temp = argmax_param_;
+  argmax_param_ = NULL;
+  return temp;
+}
+inline void LayerParameter::set_allocated_argmax_param(::caffe::ArgMaxParameter* argmax_param) {
+  delete argmax_param_;
+  argmax_param_ = argmax_param;
+  if (argmax_param) {
+    set_has_argmax_param();
+  } else {
+    clear_has_argmax_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.LayerParameter.argmax_param)
+}
+
+// optional .caffe.ConcatParameter concat_param = 104;
+inline bool LayerParameter::has_concat_param() const {
+  return (_has_bits_[0] & 0x00008000u) != 0;
+}
+inline void LayerParameter::set_has_concat_param() {
+  _has_bits_[0] |= 0x00008000u;
+}
+inline void LayerParameter::clear_has_concat_param() {
+  _has_bits_[0] &= ~0x00008000u;
+}
+inline void LayerParameter::clear_concat_param() {
+  if (concat_param_ != NULL) concat_param_->::caffe::ConcatParameter::Clear();
+  clear_has_concat_param();
+}
+inline const ::caffe::ConcatParameter& LayerParameter::concat_param() const {
+  // @@protoc_insertion_point(field_get:caffe.LayerParameter.concat_param)
+  return concat_param_ != NULL ? *concat_param_
+                         : *::caffe::ConcatParameter::internal_default_instance();
+}
+inline ::caffe::ConcatParameter* LayerParameter::mutable_concat_param() {
+  set_has_concat_param();
+  if (concat_param_ == NULL) {
+    concat_param_ = new ::caffe::ConcatParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.LayerParameter.concat_param)
+  return concat_param_;
+}
+inline ::caffe::ConcatParameter* LayerParameter::release_concat_param() {
+  // @@protoc_insertion_point(field_release:caffe.LayerParameter.concat_param)
+  clear_has_concat_param();
+  ::caffe::ConcatParameter* temp = concat_param_;
+  concat_param_ = NULL;
+  return temp;
+}
+inline void LayerParameter::set_allocated_concat_param(::caffe::ConcatParameter* concat_param) {
+  delete concat_param_;
+  concat_param_ = concat_param;
+  if (concat_param) {
+    set_has_concat_param();
+  } else {
+    clear_has_concat_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.LayerParameter.concat_param)
+}
+
+// optional .caffe.ContrastiveLossParameter contrastive_loss_param = 105;
+inline bool LayerParameter::has_contrastive_loss_param() const {
+  return (_has_bits_[0] & 0x00010000u) != 0;
+}
+inline void LayerParameter::set_has_contrastive_loss_param() {
+  _has_bits_[0] |= 0x00010000u;
+}
+inline void LayerParameter::clear_has_contrastive_loss_param() {
+  _has_bits_[0] &= ~0x00010000u;
+}
+inline void LayerParameter::clear_contrastive_loss_param() {
+  if (contrastive_loss_param_ != NULL) contrastive_loss_param_->::caffe::ContrastiveLossParameter::Clear();
+  clear_has_contrastive_loss_param();
+}
+inline const ::caffe::ContrastiveLossParameter& LayerParameter::contrastive_loss_param() const {
+  // @@protoc_insertion_point(field_get:caffe.LayerParameter.contrastive_loss_param)
+  return contrastive_loss_param_ != NULL ? *contrastive_loss_param_
+                         : *::caffe::ContrastiveLossParameter::internal_default_instance();
+}
+inline ::caffe::ContrastiveLossParameter* LayerParameter::mutable_contrastive_loss_param() {
+  set_has_contrastive_loss_param();
+  if (contrastive_loss_param_ == NULL) {
+    contrastive_loss_param_ = new ::caffe::ContrastiveLossParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.LayerParameter.contrastive_loss_param)
+  return contrastive_loss_param_;
+}
+inline ::caffe::ContrastiveLossParameter* LayerParameter::release_contrastive_loss_param() {
+  // @@protoc_insertion_point(field_release:caffe.LayerParameter.contrastive_loss_param)
+  clear_has_contrastive_loss_param();
+  ::caffe::ContrastiveLossParameter* temp = contrastive_loss_param_;
+  contrastive_loss_param_ = NULL;
+  return temp;
+}
+inline void LayerParameter::set_allocated_contrastive_loss_param(::caffe::ContrastiveLossParameter* contrastive_loss_param) {
+  delete contrastive_loss_param_;
+  contrastive_loss_param_ = contrastive_loss_param;
+  if (contrastive_loss_param) {
+    set_has_contrastive_loss_param();
+  } else {
+    clear_has_contrastive_loss_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.LayerParameter.contrastive_loss_param)
+}
+
+// optional .caffe.ConvolutionParameter convolution_param = 106;
+inline bool LayerParameter::has_convolution_param() const {
+  return (_has_bits_[0] & 0x00020000u) != 0;
+}
+inline void LayerParameter::set_has_convolution_param() {
+  _has_bits_[0] |= 0x00020000u;
+}
+inline void LayerParameter::clear_has_convolution_param() {
+  _has_bits_[0] &= ~0x00020000u;
+}
+inline void LayerParameter::clear_convolution_param() {
+  if (convolution_param_ != NULL) convolution_param_->::caffe::ConvolutionParameter::Clear();
+  clear_has_convolution_param();
+}
+inline const ::caffe::ConvolutionParameter& LayerParameter::convolution_param() const {
+  // @@protoc_insertion_point(field_get:caffe.LayerParameter.convolution_param)
+  return convolution_param_ != NULL ? *convolution_param_
+                         : *::caffe::ConvolutionParameter::internal_default_instance();
+}
+inline ::caffe::ConvolutionParameter* LayerParameter::mutable_convolution_param() {
+  set_has_convolution_param();
+  if (convolution_param_ == NULL) {
+    convolution_param_ = new ::caffe::ConvolutionParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.LayerParameter.convolution_param)
+  return convolution_param_;
+}
+inline ::caffe::ConvolutionParameter* LayerParameter::release_convolution_param() {
+  // @@protoc_insertion_point(field_release:caffe.LayerParameter.convolution_param)
+  clear_has_convolution_param();
+  ::caffe::ConvolutionParameter* temp = convolution_param_;
+  convolution_param_ = NULL;
+  return temp;
+}
+inline void LayerParameter::set_allocated_convolution_param(::caffe::ConvolutionParameter* convolution_param) {
+  delete convolution_param_;
+  convolution_param_ = convolution_param;
+  if (convolution_param) {
+    set_has_convolution_param();
+  } else {
+    clear_has_convolution_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.LayerParameter.convolution_param)
+}
+
+// optional .caffe.CropParameter crop_param = 137;
+inline bool LayerParameter::has_crop_param() const {
+  return (_has_bits_[0] & 0x00040000u) != 0;
+}
+inline void LayerParameter::set_has_crop_param() {
+  _has_bits_[0] |= 0x00040000u;
+}
+inline void LayerParameter::clear_has_crop_param() {
+  _has_bits_[0] &= ~0x00040000u;
+}
+inline void LayerParameter::clear_crop_param() {
+  if (crop_param_ != NULL) crop_param_->::caffe::CropParameter::Clear();
+  clear_has_crop_param();
+}
+inline const ::caffe::CropParameter& LayerParameter::crop_param() const {
+  // @@protoc_insertion_point(field_get:caffe.LayerParameter.crop_param)
+  return crop_param_ != NULL ? *crop_param_
+                         : *::caffe::CropParameter::internal_default_instance();
+}
+inline ::caffe::CropParameter* LayerParameter::mutable_crop_param() {
+  set_has_crop_param();
+  if (crop_param_ == NULL) {
+    crop_param_ = new ::caffe::CropParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.LayerParameter.crop_param)
+  return crop_param_;
+}
+inline ::caffe::CropParameter* LayerParameter::release_crop_param() {
+  // @@protoc_insertion_point(field_release:caffe.LayerParameter.crop_param)
+  clear_has_crop_param();
+  ::caffe::CropParameter* temp = crop_param_;
+  crop_param_ = NULL;
+  return temp;
+}
+inline void LayerParameter::set_allocated_crop_param(::caffe::CropParameter* crop_param) {
+  delete crop_param_;
+  crop_param_ = crop_param;
+  if (crop_param) {
+    set_has_crop_param();
+  } else {
+    clear_has_crop_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.LayerParameter.crop_param)
+}
+
+// optional .caffe.DataParameter data_param = 107;
+inline bool LayerParameter::has_data_param() const {
+  return (_has_bits_[0] & 0x00080000u) != 0;
+}
+inline void LayerParameter::set_has_data_param() {
+  _has_bits_[0] |= 0x00080000u;
+}
+inline void LayerParameter::clear_has_data_param() {
+  _has_bits_[0] &= ~0x00080000u;
+}
+inline void LayerParameter::clear_data_param() {
+  if (data_param_ != NULL) data_param_->::caffe::DataParameter::Clear();
+  clear_has_data_param();
+}
+inline const ::caffe::DataParameter& LayerParameter::data_param() const {
+  // @@protoc_insertion_point(field_get:caffe.LayerParameter.data_param)
+  return data_param_ != NULL ? *data_param_
+                         : *::caffe::DataParameter::internal_default_instance();
+}
+inline ::caffe::DataParameter* LayerParameter::mutable_data_param() {
+  set_has_data_param();
+  if (data_param_ == NULL) {
+    data_param_ = new ::caffe::DataParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.LayerParameter.data_param)
+  return data_param_;
+}
+inline ::caffe::DataParameter* LayerParameter::release_data_param() {
+  // @@protoc_insertion_point(field_release:caffe.LayerParameter.data_param)
+  clear_has_data_param();
+  ::caffe::DataParameter* temp = data_param_;
+  data_param_ = NULL;
+  return temp;
+}
+inline void LayerParameter::set_allocated_data_param(::caffe::DataParameter* data_param) {
+  delete data_param_;
+  data_param_ = data_param;
+  if (data_param) {
+    set_has_data_param();
+  } else {
+    clear_has_data_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.LayerParameter.data_param)
+}
+
+// optional .caffe.DetectionOutputParameter detection_output_param = 141;
+inline bool LayerParameter::has_detection_output_param() const {
+  return (_has_bits_[0] & 0x00100000u) != 0;
+}
+inline void LayerParameter::set_has_detection_output_param() {
+  _has_bits_[0] |= 0x00100000u;
+}
+inline void LayerParameter::clear_has_detection_output_param() {
+  _has_bits_[0] &= ~0x00100000u;
+}
+inline void LayerParameter::clear_detection_output_param() {
+  if (detection_output_param_ != NULL) detection_output_param_->::caffe::DetectionOutputParameter::Clear();
+  clear_has_detection_output_param();
+}
+inline const ::caffe::DetectionOutputParameter& LayerParameter::detection_output_param() const {
+  // @@protoc_insertion_point(field_get:caffe.LayerParameter.detection_output_param)
+  return detection_output_param_ != NULL ? *detection_output_param_
+                         : *::caffe::DetectionOutputParameter::internal_default_instance();
+}
+inline ::caffe::DetectionOutputParameter* LayerParameter::mutable_detection_output_param() {
+  set_has_detection_output_param();
+  if (detection_output_param_ == NULL) {
+    detection_output_param_ = new ::caffe::DetectionOutputParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.LayerParameter.detection_output_param)
+  return detection_output_param_;
+}
+inline ::caffe::DetectionOutputParameter* LayerParameter::release_detection_output_param() {
+  // @@protoc_insertion_point(field_release:caffe.LayerParameter.detection_output_param)
+  clear_has_detection_output_param();
+  ::caffe::DetectionOutputParameter* temp = detection_output_param_;
+  detection_output_param_ = NULL;
+  return temp;
+}
+inline void LayerParameter::set_allocated_detection_output_param(::caffe::DetectionOutputParameter* detection_output_param) {
+  delete detection_output_param_;
+  detection_output_param_ = detection_output_param;
+  if (detection_output_param) {
+    set_has_detection_output_param();
+  } else {
+    clear_has_detection_output_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.LayerParameter.detection_output_param)
+}
+
+// optional .caffe.DropoutParameter dropout_param = 108;
+inline bool LayerParameter::has_dropout_param() const {
+  return (_has_bits_[0] & 0x00200000u) != 0;
+}
+inline void LayerParameter::set_has_dropout_param() {
+  _has_bits_[0] |= 0x00200000u;
+}
+inline void LayerParameter::clear_has_dropout_param() {
+  _has_bits_[0] &= ~0x00200000u;
+}
+inline void LayerParameter::clear_dropout_param() {
+  if (dropout_param_ != NULL) dropout_param_->::caffe::DropoutParameter::Clear();
+  clear_has_dropout_param();
+}
+inline const ::caffe::DropoutParameter& LayerParameter::dropout_param() const {
+  // @@protoc_insertion_point(field_get:caffe.LayerParameter.dropout_param)
+  return dropout_param_ != NULL ? *dropout_param_
+                         : *::caffe::DropoutParameter::internal_default_instance();
+}
+inline ::caffe::DropoutParameter* LayerParameter::mutable_dropout_param() {
+  set_has_dropout_param();
+  if (dropout_param_ == NULL) {
+    dropout_param_ = new ::caffe::DropoutParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.LayerParameter.dropout_param)
+  return dropout_param_;
+}
+inline ::caffe::DropoutParameter* LayerParameter::release_dropout_param() {
+  // @@protoc_insertion_point(field_release:caffe.LayerParameter.dropout_param)
+  clear_has_dropout_param();
+  ::caffe::DropoutParameter* temp = dropout_param_;
+  dropout_param_ = NULL;
+  return temp;
+}
+inline void LayerParameter::set_allocated_dropout_param(::caffe::DropoutParameter* dropout_param) {
+  delete dropout_param_;
+  dropout_param_ = dropout_param;
+  if (dropout_param) {
+    set_has_dropout_param();
+  } else {
+    clear_has_dropout_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.LayerParameter.dropout_param)
+}
+
+// optional .caffe.DummyDataParameter dummy_data_param = 109;
+inline bool LayerParameter::has_dummy_data_param() const {
+  return (_has_bits_[0] & 0x00400000u) != 0;
+}
+inline void LayerParameter::set_has_dummy_data_param() {
+  _has_bits_[0] |= 0x00400000u;
+}
+inline void LayerParameter::clear_has_dummy_data_param() {
+  _has_bits_[0] &= ~0x00400000u;
+}
+inline void LayerParameter::clear_dummy_data_param() {
+  if (dummy_data_param_ != NULL) dummy_data_param_->::caffe::DummyDataParameter::Clear();
+  clear_has_dummy_data_param();
+}
+inline const ::caffe::DummyDataParameter& LayerParameter::dummy_data_param() const {
+  // @@protoc_insertion_point(field_get:caffe.LayerParameter.dummy_data_param)
+  return dummy_data_param_ != NULL ? *dummy_data_param_
+                         : *::caffe::DummyDataParameter::internal_default_instance();
+}
+inline ::caffe::DummyDataParameter* LayerParameter::mutable_dummy_data_param() {
+  set_has_dummy_data_param();
+  if (dummy_data_param_ == NULL) {
+    dummy_data_param_ = new ::caffe::DummyDataParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.LayerParameter.dummy_data_param)
+  return dummy_data_param_;
+}
+inline ::caffe::DummyDataParameter* LayerParameter::release_dummy_data_param() {
+  // @@protoc_insertion_point(field_release:caffe.LayerParameter.dummy_data_param)
+  clear_has_dummy_data_param();
+  ::caffe::DummyDataParameter* temp = dummy_data_param_;
+  dummy_data_param_ = NULL;
+  return temp;
+}
+inline void LayerParameter::set_allocated_dummy_data_param(::caffe::DummyDataParameter* dummy_data_param) {
+  delete dummy_data_param_;
+  dummy_data_param_ = dummy_data_param;
+  if (dummy_data_param) {
+    set_has_dummy_data_param();
+  } else {
+    clear_has_dummy_data_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.LayerParameter.dummy_data_param)
+}
+
+// optional .caffe.EltwiseParameter eltwise_param = 110;
+inline bool LayerParameter::has_eltwise_param() const {
+  return (_has_bits_[0] & 0x00800000u) != 0;
+}
+inline void LayerParameter::set_has_eltwise_param() {
+  _has_bits_[0] |= 0x00800000u;
+}
+inline void LayerParameter::clear_has_eltwise_param() {
+  _has_bits_[0] &= ~0x00800000u;
+}
+inline void LayerParameter::clear_eltwise_param() {
+  if (eltwise_param_ != NULL) eltwise_param_->::caffe::EltwiseParameter::Clear();
+  clear_has_eltwise_param();
+}
+inline const ::caffe::EltwiseParameter& LayerParameter::eltwise_param() const {
+  // @@protoc_insertion_point(field_get:caffe.LayerParameter.eltwise_param)
+  return eltwise_param_ != NULL ? *eltwise_param_
+                         : *::caffe::EltwiseParameter::internal_default_instance();
+}
+inline ::caffe::EltwiseParameter* LayerParameter::mutable_eltwise_param() {
+  set_has_eltwise_param();
+  if (eltwise_param_ == NULL) {
+    eltwise_param_ = new ::caffe::EltwiseParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.LayerParameter.eltwise_param)
+  return eltwise_param_;
+}
+inline ::caffe::EltwiseParameter* LayerParameter::release_eltwise_param() {
+  // @@protoc_insertion_point(field_release:caffe.LayerParameter.eltwise_param)
+  clear_has_eltwise_param();
+  ::caffe::EltwiseParameter* temp = eltwise_param_;
+  eltwise_param_ = NULL;
+  return temp;
+}
+inline void LayerParameter::set_allocated_eltwise_param(::caffe::EltwiseParameter* eltwise_param) {
+  delete eltwise_param_;
+  eltwise_param_ = eltwise_param;
+  if (eltwise_param) {
+    set_has_eltwise_param();
+  } else {
+    clear_has_eltwise_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.LayerParameter.eltwise_param)
+}
+
+// optional .caffe.ExpParameter exp_param = 111;
+inline bool LayerParameter::has_exp_param() const {
+  return (_has_bits_[0] & 0x01000000u) != 0;
+}
+inline void LayerParameter::set_has_exp_param() {
+  _has_bits_[0] |= 0x01000000u;
+}
+inline void LayerParameter::clear_has_exp_param() {
+  _has_bits_[0] &= ~0x01000000u;
+}
+inline void LayerParameter::clear_exp_param() {
+  if (exp_param_ != NULL) exp_param_->::caffe::ExpParameter::Clear();
+  clear_has_exp_param();
+}
+inline const ::caffe::ExpParameter& LayerParameter::exp_param() const {
+  // @@protoc_insertion_point(field_get:caffe.LayerParameter.exp_param)
+  return exp_param_ != NULL ? *exp_param_
+                         : *::caffe::ExpParameter::internal_default_instance();
+}
+inline ::caffe::ExpParameter* LayerParameter::mutable_exp_param() {
+  set_has_exp_param();
+  if (exp_param_ == NULL) {
+    exp_param_ = new ::caffe::ExpParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.LayerParameter.exp_param)
+  return exp_param_;
+}
+inline ::caffe::ExpParameter* LayerParameter::release_exp_param() {
+  // @@protoc_insertion_point(field_release:caffe.LayerParameter.exp_param)
+  clear_has_exp_param();
+  ::caffe::ExpParameter* temp = exp_param_;
+  exp_param_ = NULL;
+  return temp;
+}
+inline void LayerParameter::set_allocated_exp_param(::caffe::ExpParameter* exp_param) {
+  delete exp_param_;
+  exp_param_ = exp_param;
+  if (exp_param) {
+    set_has_exp_param();
+  } else {
+    clear_has_exp_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.LayerParameter.exp_param)
+}
+
+// optional .caffe.FlattenParameter flatten_param = 135;
+inline bool LayerParameter::has_flatten_param() const {
+  return (_has_bits_[0] & 0x02000000u) != 0;
+}
+inline void LayerParameter::set_has_flatten_param() {
+  _has_bits_[0] |= 0x02000000u;
+}
+inline void LayerParameter::clear_has_flatten_param() {
+  _has_bits_[0] &= ~0x02000000u;
+}
+inline void LayerParameter::clear_flatten_param() {
+  if (flatten_param_ != NULL) flatten_param_->::caffe::FlattenParameter::Clear();
+  clear_has_flatten_param();
+}
+inline const ::caffe::FlattenParameter& LayerParameter::flatten_param() const {
+  // @@protoc_insertion_point(field_get:caffe.LayerParameter.flatten_param)
+  return flatten_param_ != NULL ? *flatten_param_
+                         : *::caffe::FlattenParameter::internal_default_instance();
+}
+inline ::caffe::FlattenParameter* LayerParameter::mutable_flatten_param() {
+  set_has_flatten_param();
+  if (flatten_param_ == NULL) {
+    flatten_param_ = new ::caffe::FlattenParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.LayerParameter.flatten_param)
+  return flatten_param_;
+}
+inline ::caffe::FlattenParameter* LayerParameter::release_flatten_param() {
+  // @@protoc_insertion_point(field_release:caffe.LayerParameter.flatten_param)
+  clear_has_flatten_param();
+  ::caffe::FlattenParameter* temp = flatten_param_;
+  flatten_param_ = NULL;
+  return temp;
+}
+inline void LayerParameter::set_allocated_flatten_param(::caffe::FlattenParameter* flatten_param) {
+  delete flatten_param_;
+  flatten_param_ = flatten_param;
+  if (flatten_param) {
+    set_has_flatten_param();
+  } else {
+    clear_has_flatten_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.LayerParameter.flatten_param)
+}
+
+// optional .caffe.HDF5DataParameter hdf5_data_param = 112;
+inline bool LayerParameter::has_hdf5_data_param() const {
+  return (_has_bits_[0] & 0x04000000u) != 0;
+}
+inline void LayerParameter::set_has_hdf5_data_param() {
+  _has_bits_[0] |= 0x04000000u;
+}
+inline void LayerParameter::clear_has_hdf5_data_param() {
+  _has_bits_[0] &= ~0x04000000u;
+}
+inline void LayerParameter::clear_hdf5_data_param() {
+  if (hdf5_data_param_ != NULL) hdf5_data_param_->::caffe::HDF5DataParameter::Clear();
+  clear_has_hdf5_data_param();
+}
+inline const ::caffe::HDF5DataParameter& LayerParameter::hdf5_data_param() const {
+  // @@protoc_insertion_point(field_get:caffe.LayerParameter.hdf5_data_param)
+  return hdf5_data_param_ != NULL ? *hdf5_data_param_
+                         : *::caffe::HDF5DataParameter::internal_default_instance();
+}
+inline ::caffe::HDF5DataParameter* LayerParameter::mutable_hdf5_data_param() {
+  set_has_hdf5_data_param();
+  if (hdf5_data_param_ == NULL) {
+    hdf5_data_param_ = new ::caffe::HDF5DataParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.LayerParameter.hdf5_data_param)
+  return hdf5_data_param_;
+}
+inline ::caffe::HDF5DataParameter* LayerParameter::release_hdf5_data_param() {
+  // @@protoc_insertion_point(field_release:caffe.LayerParameter.hdf5_data_param)
+  clear_has_hdf5_data_param();
+  ::caffe::HDF5DataParameter* temp = hdf5_data_param_;
+  hdf5_data_param_ = NULL;
+  return temp;
+}
+inline void LayerParameter::set_allocated_hdf5_data_param(::caffe::HDF5DataParameter* hdf5_data_param) {
+  delete hdf5_data_param_;
+  hdf5_data_param_ = hdf5_data_param;
+  if (hdf5_data_param) {
+    set_has_hdf5_data_param();
+  } else {
+    clear_has_hdf5_data_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.LayerParameter.hdf5_data_param)
+}
+
+// optional .caffe.HDF5OutputParameter hdf5_output_param = 113;
+inline bool LayerParameter::has_hdf5_output_param() const {
+  return (_has_bits_[0] & 0x08000000u) != 0;
+}
+inline void LayerParameter::set_has_hdf5_output_param() {
+  _has_bits_[0] |= 0x08000000u;
+}
+inline void LayerParameter::clear_has_hdf5_output_param() {
+  _has_bits_[0] &= ~0x08000000u;
+}
+inline void LayerParameter::clear_hdf5_output_param() {
+  if (hdf5_output_param_ != NULL) hdf5_output_param_->::caffe::HDF5OutputParameter::Clear();
+  clear_has_hdf5_output_param();
+}
+inline const ::caffe::HDF5OutputParameter& LayerParameter::hdf5_output_param() const {
+  // @@protoc_insertion_point(field_get:caffe.LayerParameter.hdf5_output_param)
+  return hdf5_output_param_ != NULL ? *hdf5_output_param_
+                         : *::caffe::HDF5OutputParameter::internal_default_instance();
+}
+inline ::caffe::HDF5OutputParameter* LayerParameter::mutable_hdf5_output_param() {
+  set_has_hdf5_output_param();
+  if (hdf5_output_param_ == NULL) {
+    hdf5_output_param_ = new ::caffe::HDF5OutputParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.LayerParameter.hdf5_output_param)
+  return hdf5_output_param_;
+}
+inline ::caffe::HDF5OutputParameter* LayerParameter::release_hdf5_output_param() {
+  // @@protoc_insertion_point(field_release:caffe.LayerParameter.hdf5_output_param)
+  clear_has_hdf5_output_param();
+  ::caffe::HDF5OutputParameter* temp = hdf5_output_param_;
+  hdf5_output_param_ = NULL;
+  return temp;
+}
+inline void LayerParameter::set_allocated_hdf5_output_param(::caffe::HDF5OutputParameter* hdf5_output_param) {
+  delete hdf5_output_param_;
+  hdf5_output_param_ = hdf5_output_param;
+  if (hdf5_output_param) {
+    set_has_hdf5_output_param();
+  } else {
+    clear_has_hdf5_output_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.LayerParameter.hdf5_output_param)
+}
+
+// optional .caffe.HingeLossParameter hinge_loss_param = 114;
+inline bool LayerParameter::has_hinge_loss_param() const {
+  return (_has_bits_[0] & 0x10000000u) != 0;
+}
+inline void LayerParameter::set_has_hinge_loss_param() {
+  _has_bits_[0] |= 0x10000000u;
+}
+inline void LayerParameter::clear_has_hinge_loss_param() {
+  _has_bits_[0] &= ~0x10000000u;
+}
+inline void LayerParameter::clear_hinge_loss_param() {
+  if (hinge_loss_param_ != NULL) hinge_loss_param_->::caffe::HingeLossParameter::Clear();
+  clear_has_hinge_loss_param();
+}
+inline const ::caffe::HingeLossParameter& LayerParameter::hinge_loss_param() const {
+  // @@protoc_insertion_point(field_get:caffe.LayerParameter.hinge_loss_param)
+  return hinge_loss_param_ != NULL ? *hinge_loss_param_
+                         : *::caffe::HingeLossParameter::internal_default_instance();
+}
+inline ::caffe::HingeLossParameter* LayerParameter::mutable_hinge_loss_param() {
+  set_has_hinge_loss_param();
+  if (hinge_loss_param_ == NULL) {
+    hinge_loss_param_ = new ::caffe::HingeLossParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.LayerParameter.hinge_loss_param)
+  return hinge_loss_param_;
+}
+inline ::caffe::HingeLossParameter* LayerParameter::release_hinge_loss_param() {
+  // @@protoc_insertion_point(field_release:caffe.LayerParameter.hinge_loss_param)
+  clear_has_hinge_loss_param();
+  ::caffe::HingeLossParameter* temp = hinge_loss_param_;
+  hinge_loss_param_ = NULL;
+  return temp;
+}
+inline void LayerParameter::set_allocated_hinge_loss_param(::caffe::HingeLossParameter* hinge_loss_param) {
+  delete hinge_loss_param_;
+  hinge_loss_param_ = hinge_loss_param;
+  if (hinge_loss_param) {
+    set_has_hinge_loss_param();
+  } else {
+    clear_has_hinge_loss_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.LayerParameter.hinge_loss_param)
+}
+
+// optional .caffe.ImageDataParameter image_data_param = 115;
+inline bool LayerParameter::has_image_data_param() const {
+  return (_has_bits_[0] & 0x20000000u) != 0;
+}
+inline void LayerParameter::set_has_image_data_param() {
+  _has_bits_[0] |= 0x20000000u;
+}
+inline void LayerParameter::clear_has_image_data_param() {
+  _has_bits_[0] &= ~0x20000000u;
+}
+inline void LayerParameter::clear_image_data_param() {
+  if (image_data_param_ != NULL) image_data_param_->::caffe::ImageDataParameter::Clear();
+  clear_has_image_data_param();
+}
+inline const ::caffe::ImageDataParameter& LayerParameter::image_data_param() const {
+  // @@protoc_insertion_point(field_get:caffe.LayerParameter.image_data_param)
+  return image_data_param_ != NULL ? *image_data_param_
+                         : *::caffe::ImageDataParameter::internal_default_instance();
+}
+inline ::caffe::ImageDataParameter* LayerParameter::mutable_image_data_param() {
+  set_has_image_data_param();
+  if (image_data_param_ == NULL) {
+    image_data_param_ = new ::caffe::ImageDataParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.LayerParameter.image_data_param)
+  return image_data_param_;
+}
+inline ::caffe::ImageDataParameter* LayerParameter::release_image_data_param() {
+  // @@protoc_insertion_point(field_release:caffe.LayerParameter.image_data_param)
+  clear_has_image_data_param();
+  ::caffe::ImageDataParameter* temp = image_data_param_;
+  image_data_param_ = NULL;
+  return temp;
+}
+inline void LayerParameter::set_allocated_image_data_param(::caffe::ImageDataParameter* image_data_param) {
+  delete image_data_param_;
+  image_data_param_ = image_data_param;
+  if (image_data_param) {
+    set_has_image_data_param();
+  } else {
+    clear_has_image_data_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.LayerParameter.image_data_param)
+}
+
+// optional .caffe.InfogainLossParameter infogain_loss_param = 116;
+inline bool LayerParameter::has_infogain_loss_param() const {
+  return (_has_bits_[0] & 0x40000000u) != 0;
+}
+inline void LayerParameter::set_has_infogain_loss_param() {
+  _has_bits_[0] |= 0x40000000u;
+}
+inline void LayerParameter::clear_has_infogain_loss_param() {
+  _has_bits_[0] &= ~0x40000000u;
+}
+inline void LayerParameter::clear_infogain_loss_param() {
+  if (infogain_loss_param_ != NULL) infogain_loss_param_->::caffe::InfogainLossParameter::Clear();
+  clear_has_infogain_loss_param();
+}
+inline const ::caffe::InfogainLossParameter& LayerParameter::infogain_loss_param() const {
+  // @@protoc_insertion_point(field_get:caffe.LayerParameter.infogain_loss_param)
+  return infogain_loss_param_ != NULL ? *infogain_loss_param_
+                         : *::caffe::InfogainLossParameter::internal_default_instance();
+}
+inline ::caffe::InfogainLossParameter* LayerParameter::mutable_infogain_loss_param() {
+  set_has_infogain_loss_param();
+  if (infogain_loss_param_ == NULL) {
+    infogain_loss_param_ = new ::caffe::InfogainLossParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.LayerParameter.infogain_loss_param)
+  return infogain_loss_param_;
+}
+inline ::caffe::InfogainLossParameter* LayerParameter::release_infogain_loss_param() {
+  // @@protoc_insertion_point(field_release:caffe.LayerParameter.infogain_loss_param)
+  clear_has_infogain_loss_param();
+  ::caffe::InfogainLossParameter* temp = infogain_loss_param_;
+  infogain_loss_param_ = NULL;
+  return temp;
+}
+inline void LayerParameter::set_allocated_infogain_loss_param(::caffe::InfogainLossParameter* infogain_loss_param) {
+  delete infogain_loss_param_;
+  infogain_loss_param_ = infogain_loss_param;
+  if (infogain_loss_param) {
+    set_has_infogain_loss_param();
+  } else {
+    clear_has_infogain_loss_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.LayerParameter.infogain_loss_param)
+}
+
+// optional .caffe.InnerProductParameter inner_product_param = 117;
+inline bool LayerParameter::has_inner_product_param() const {
+  return (_has_bits_[0] & 0x80000000u) != 0;
+}
+inline void LayerParameter::set_has_inner_product_param() {
+  _has_bits_[0] |= 0x80000000u;
+}
+inline void LayerParameter::clear_has_inner_product_param() {
+  _has_bits_[0] &= ~0x80000000u;
+}
+inline void LayerParameter::clear_inner_product_param() {
+  if (inner_product_param_ != NULL) inner_product_param_->::caffe::InnerProductParameter::Clear();
+  clear_has_inner_product_param();
+}
+inline const ::caffe::InnerProductParameter& LayerParameter::inner_product_param() const {
+  // @@protoc_insertion_point(field_get:caffe.LayerParameter.inner_product_param)
+  return inner_product_param_ != NULL ? *inner_product_param_
+                         : *::caffe::InnerProductParameter::internal_default_instance();
+}
+inline ::caffe::InnerProductParameter* LayerParameter::mutable_inner_product_param() {
+  set_has_inner_product_param();
+  if (inner_product_param_ == NULL) {
+    inner_product_param_ = new ::caffe::InnerProductParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.LayerParameter.inner_product_param)
+  return inner_product_param_;
+}
+inline ::caffe::InnerProductParameter* LayerParameter::release_inner_product_param() {
+  // @@protoc_insertion_point(field_release:caffe.LayerParameter.inner_product_param)
+  clear_has_inner_product_param();
+  ::caffe::InnerProductParameter* temp = inner_product_param_;
+  inner_product_param_ = NULL;
+  return temp;
+}
+inline void LayerParameter::set_allocated_inner_product_param(::caffe::InnerProductParameter* inner_product_param) {
+  delete inner_product_param_;
+  inner_product_param_ = inner_product_param;
+  if (inner_product_param) {
+    set_has_inner_product_param();
+  } else {
+    clear_has_inner_product_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.LayerParameter.inner_product_param)
+}
+
+// optional .caffe.LogParameter log_param = 134;
+inline bool LayerParameter::has_log_param() const {
+  return (_has_bits_[1] & 0x00000001u) != 0;
+}
+inline void LayerParameter::set_has_log_param() {
+  _has_bits_[1] |= 0x00000001u;
+}
+inline void LayerParameter::clear_has_log_param() {
+  _has_bits_[1] &= ~0x00000001u;
+}
+inline void LayerParameter::clear_log_param() {
+  if (log_param_ != NULL) log_param_->::caffe::LogParameter::Clear();
+  clear_has_log_param();
+}
+inline const ::caffe::LogParameter& LayerParameter::log_param() const {
+  // @@protoc_insertion_point(field_get:caffe.LayerParameter.log_param)
+  return log_param_ != NULL ? *log_param_
+                         : *::caffe::LogParameter::internal_default_instance();
+}
+inline ::caffe::LogParameter* LayerParameter::mutable_log_param() {
+  set_has_log_param();
+  if (log_param_ == NULL) {
+    log_param_ = new ::caffe::LogParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.LayerParameter.log_param)
+  return log_param_;
+}
+inline ::caffe::LogParameter* LayerParameter::release_log_param() {
+  // @@protoc_insertion_point(field_release:caffe.LayerParameter.log_param)
+  clear_has_log_param();
+  ::caffe::LogParameter* temp = log_param_;
+  log_param_ = NULL;
+  return temp;
+}
+inline void LayerParameter::set_allocated_log_param(::caffe::LogParameter* log_param) {
+  delete log_param_;
+  log_param_ = log_param;
+  if (log_param) {
+    set_has_log_param();
+  } else {
+    clear_has_log_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.LayerParameter.log_param)
+}
+
+// optional .caffe.LRNParameter lrn_param = 118;
+inline bool LayerParameter::has_lrn_param() const {
+  return (_has_bits_[1] & 0x00000002u) != 0;
+}
+inline void LayerParameter::set_has_lrn_param() {
+  _has_bits_[1] |= 0x00000002u;
+}
+inline void LayerParameter::clear_has_lrn_param() {
+  _has_bits_[1] &= ~0x00000002u;
+}
+inline void LayerParameter::clear_lrn_param() {
+  if (lrn_param_ != NULL) lrn_param_->::caffe::LRNParameter::Clear();
+  clear_has_lrn_param();
+}
+inline const ::caffe::LRNParameter& LayerParameter::lrn_param() const {
+  // @@protoc_insertion_point(field_get:caffe.LayerParameter.lrn_param)
+  return lrn_param_ != NULL ? *lrn_param_
+                         : *::caffe::LRNParameter::internal_default_instance();
+}
+inline ::caffe::LRNParameter* LayerParameter::mutable_lrn_param() {
+  set_has_lrn_param();
+  if (lrn_param_ == NULL) {
+    lrn_param_ = new ::caffe::LRNParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.LayerParameter.lrn_param)
+  return lrn_param_;
+}
+inline ::caffe::LRNParameter* LayerParameter::release_lrn_param() {
+  // @@protoc_insertion_point(field_release:caffe.LayerParameter.lrn_param)
+  clear_has_lrn_param();
+  ::caffe::LRNParameter* temp = lrn_param_;
+  lrn_param_ = NULL;
+  return temp;
+}
+inline void LayerParameter::set_allocated_lrn_param(::caffe::LRNParameter* lrn_param) {
+  delete lrn_param_;
+  lrn_param_ = lrn_param;
+  if (lrn_param) {
+    set_has_lrn_param();
+  } else {
+    clear_has_lrn_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.LayerParameter.lrn_param)
+}
+
+// optional .caffe.MemoryDataParameter memory_data_param = 119;
+inline bool LayerParameter::has_memory_data_param() const {
+  return (_has_bits_[1] & 0x00000004u) != 0;
+}
+inline void LayerParameter::set_has_memory_data_param() {
+  _has_bits_[1] |= 0x00000004u;
+}
+inline void LayerParameter::clear_has_memory_data_param() {
+  _has_bits_[1] &= ~0x00000004u;
+}
+inline void LayerParameter::clear_memory_data_param() {
+  if (memory_data_param_ != NULL) memory_data_param_->::caffe::MemoryDataParameter::Clear();
+  clear_has_memory_data_param();
+}
+inline const ::caffe::MemoryDataParameter& LayerParameter::memory_data_param() const {
+  // @@protoc_insertion_point(field_get:caffe.LayerParameter.memory_data_param)
+  return memory_data_param_ != NULL ? *memory_data_param_
+                         : *::caffe::MemoryDataParameter::internal_default_instance();
+}
+inline ::caffe::MemoryDataParameter* LayerParameter::mutable_memory_data_param() {
+  set_has_memory_data_param();
+  if (memory_data_param_ == NULL) {
+    memory_data_param_ = new ::caffe::MemoryDataParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.LayerParameter.memory_data_param)
+  return memory_data_param_;
+}
+inline ::caffe::MemoryDataParameter* LayerParameter::release_memory_data_param() {
+  // @@protoc_insertion_point(field_release:caffe.LayerParameter.memory_data_param)
+  clear_has_memory_data_param();
+  ::caffe::MemoryDataParameter* temp = memory_data_param_;
+  memory_data_param_ = NULL;
+  return temp;
+}
+inline void LayerParameter::set_allocated_memory_data_param(::caffe::MemoryDataParameter* memory_data_param) {
+  delete memory_data_param_;
+  memory_data_param_ = memory_data_param;
+  if (memory_data_param) {
+    set_has_memory_data_param();
+  } else {
+    clear_has_memory_data_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.LayerParameter.memory_data_param)
+}
+
+// optional .caffe.MVNParameter mvn_param = 120;
+inline bool LayerParameter::has_mvn_param() const {
+  return (_has_bits_[1] & 0x00000008u) != 0;
+}
+inline void LayerParameter::set_has_mvn_param() {
+  _has_bits_[1] |= 0x00000008u;
+}
+inline void LayerParameter::clear_has_mvn_param() {
+  _has_bits_[1] &= ~0x00000008u;
+}
+inline void LayerParameter::clear_mvn_param() {
+  if (mvn_param_ != NULL) mvn_param_->::caffe::MVNParameter::Clear();
+  clear_has_mvn_param();
+}
+inline const ::caffe::MVNParameter& LayerParameter::mvn_param() const {
+  // @@protoc_insertion_point(field_get:caffe.LayerParameter.mvn_param)
+  return mvn_param_ != NULL ? *mvn_param_
+                         : *::caffe::MVNParameter::internal_default_instance();
+}
+inline ::caffe::MVNParameter* LayerParameter::mutable_mvn_param() {
+  set_has_mvn_param();
+  if (mvn_param_ == NULL) {
+    mvn_param_ = new ::caffe::MVNParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.LayerParameter.mvn_param)
+  return mvn_param_;
+}
+inline ::caffe::MVNParameter* LayerParameter::release_mvn_param() {
+  // @@protoc_insertion_point(field_release:caffe.LayerParameter.mvn_param)
+  clear_has_mvn_param();
+  ::caffe::MVNParameter* temp = mvn_param_;
+  mvn_param_ = NULL;
+  return temp;
+}
+inline void LayerParameter::set_allocated_mvn_param(::caffe::MVNParameter* mvn_param) {
+  delete mvn_param_;
+  mvn_param_ = mvn_param;
+  if (mvn_param) {
+    set_has_mvn_param();
+  } else {
+    clear_has_mvn_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.LayerParameter.mvn_param)
+}
+
+// optional .caffe.NormalizeBBoxParameter normalize_bbox_param = 139;
+inline bool LayerParameter::has_normalize_bbox_param() const {
+  return (_has_bits_[1] & 0x00000010u) != 0;
+}
+inline void LayerParameter::set_has_normalize_bbox_param() {
+  _has_bits_[1] |= 0x00000010u;
+}
+inline void LayerParameter::clear_has_normalize_bbox_param() {
+  _has_bits_[1] &= ~0x00000010u;
+}
+inline void LayerParameter::clear_normalize_bbox_param() {
+  if (normalize_bbox_param_ != NULL) normalize_bbox_param_->::caffe::NormalizeBBoxParameter::Clear();
+  clear_has_normalize_bbox_param();
+}
+inline const ::caffe::NormalizeBBoxParameter& LayerParameter::normalize_bbox_param() const {
+  // @@protoc_insertion_point(field_get:caffe.LayerParameter.normalize_bbox_param)
+  return normalize_bbox_param_ != NULL ? *normalize_bbox_param_
+                         : *::caffe::NormalizeBBoxParameter::internal_default_instance();
+}
+inline ::caffe::NormalizeBBoxParameter* LayerParameter::mutable_normalize_bbox_param() {
+  set_has_normalize_bbox_param();
+  if (normalize_bbox_param_ == NULL) {
+    normalize_bbox_param_ = new ::caffe::NormalizeBBoxParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.LayerParameter.normalize_bbox_param)
+  return normalize_bbox_param_;
+}
+inline ::caffe::NormalizeBBoxParameter* LayerParameter::release_normalize_bbox_param() {
+  // @@protoc_insertion_point(field_release:caffe.LayerParameter.normalize_bbox_param)
+  clear_has_normalize_bbox_param();
+  ::caffe::NormalizeBBoxParameter* temp = normalize_bbox_param_;
+  normalize_bbox_param_ = NULL;
+  return temp;
+}
+inline void LayerParameter::set_allocated_normalize_bbox_param(::caffe::NormalizeBBoxParameter* normalize_bbox_param) {
+  delete normalize_bbox_param_;
+  normalize_bbox_param_ = normalize_bbox_param;
+  if (normalize_bbox_param) {
+    set_has_normalize_bbox_param();
+  } else {
+    clear_has_normalize_bbox_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.LayerParameter.normalize_bbox_param)
+}
+
+// optional .caffe.PermuteParameter permute_param = 138;
+inline bool LayerParameter::has_permute_param() const {
+  return (_has_bits_[1] & 0x00000020u) != 0;
+}
+inline void LayerParameter::set_has_permute_param() {
+  _has_bits_[1] |= 0x00000020u;
+}
+inline void LayerParameter::clear_has_permute_param() {
+  _has_bits_[1] &= ~0x00000020u;
+}
+inline void LayerParameter::clear_permute_param() {
+  if (permute_param_ != NULL) permute_param_->::caffe::PermuteParameter::Clear();
+  clear_has_permute_param();
+}
+inline const ::caffe::PermuteParameter& LayerParameter::permute_param() const {
+  // @@protoc_insertion_point(field_get:caffe.LayerParameter.permute_param)
+  return permute_param_ != NULL ? *permute_param_
+                         : *::caffe::PermuteParameter::internal_default_instance();
+}
+inline ::caffe::PermuteParameter* LayerParameter::mutable_permute_param() {
+  set_has_permute_param();
+  if (permute_param_ == NULL) {
+    permute_param_ = new ::caffe::PermuteParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.LayerParameter.permute_param)
+  return permute_param_;
+}
+inline ::caffe::PermuteParameter* LayerParameter::release_permute_param() {
+  // @@protoc_insertion_point(field_release:caffe.LayerParameter.permute_param)
+  clear_has_permute_param();
+  ::caffe::PermuteParameter* temp = permute_param_;
+  permute_param_ = NULL;
+  return temp;
+}
+inline void LayerParameter::set_allocated_permute_param(::caffe::PermuteParameter* permute_param) {
+  delete permute_param_;
+  permute_param_ = permute_param;
+  if (permute_param) {
+    set_has_permute_param();
+  } else {
+    clear_has_permute_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.LayerParameter.permute_param)
+}
+
+// optional .caffe.PoolingParameter pooling_param = 121;
+inline bool LayerParameter::has_pooling_param() const {
+  return (_has_bits_[1] & 0x00000040u) != 0;
+}
+inline void LayerParameter::set_has_pooling_param() {
+  _has_bits_[1] |= 0x00000040u;
+}
+inline void LayerParameter::clear_has_pooling_param() {
+  _has_bits_[1] &= ~0x00000040u;
+}
+inline void LayerParameter::clear_pooling_param() {
+  if (pooling_param_ != NULL) pooling_param_->::caffe::PoolingParameter::Clear();
+  clear_has_pooling_param();
+}
+inline const ::caffe::PoolingParameter& LayerParameter::pooling_param() const {
+  // @@protoc_insertion_point(field_get:caffe.LayerParameter.pooling_param)
+  return pooling_param_ != NULL ? *pooling_param_
+                         : *::caffe::PoolingParameter::internal_default_instance();
+}
+inline ::caffe::PoolingParameter* LayerParameter::mutable_pooling_param() {
+  set_has_pooling_param();
+  if (pooling_param_ == NULL) {
+    pooling_param_ = new ::caffe::PoolingParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.LayerParameter.pooling_param)
+  return pooling_param_;
+}
+inline ::caffe::PoolingParameter* LayerParameter::release_pooling_param() {
+  // @@protoc_insertion_point(field_release:caffe.LayerParameter.pooling_param)
+  clear_has_pooling_param();
+  ::caffe::PoolingParameter* temp = pooling_param_;
+  pooling_param_ = NULL;
+  return temp;
+}
+inline void LayerParameter::set_allocated_pooling_param(::caffe::PoolingParameter* pooling_param) {
+  delete pooling_param_;
+  pooling_param_ = pooling_param;
+  if (pooling_param) {
+    set_has_pooling_param();
+  } else {
+    clear_has_pooling_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.LayerParameter.pooling_param)
+}
+
+// optional .caffe.PowerParameter power_param = 122;
+inline bool LayerParameter::has_power_param() const {
+  return (_has_bits_[1] & 0x00000080u) != 0;
+}
+inline void LayerParameter::set_has_power_param() {
+  _has_bits_[1] |= 0x00000080u;
+}
+inline void LayerParameter::clear_has_power_param() {
+  _has_bits_[1] &= ~0x00000080u;
+}
+inline void LayerParameter::clear_power_param() {
+  if (power_param_ != NULL) power_param_->::caffe::PowerParameter::Clear();
+  clear_has_power_param();
+}
+inline const ::caffe::PowerParameter& LayerParameter::power_param() const {
+  // @@protoc_insertion_point(field_get:caffe.LayerParameter.power_param)
+  return power_param_ != NULL ? *power_param_
+                         : *::caffe::PowerParameter::internal_default_instance();
+}
+inline ::caffe::PowerParameter* LayerParameter::mutable_power_param() {
+  set_has_power_param();
+  if (power_param_ == NULL) {
+    power_param_ = new ::caffe::PowerParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.LayerParameter.power_param)
+  return power_param_;
+}
+inline ::caffe::PowerParameter* LayerParameter::release_power_param() {
+  // @@protoc_insertion_point(field_release:caffe.LayerParameter.power_param)
+  clear_has_power_param();
+  ::caffe::PowerParameter* temp = power_param_;
+  power_param_ = NULL;
+  return temp;
+}
+inline void LayerParameter::set_allocated_power_param(::caffe::PowerParameter* power_param) {
+  delete power_param_;
+  power_param_ = power_param;
+  if (power_param) {
+    set_has_power_param();
+  } else {
+    clear_has_power_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.LayerParameter.power_param)
+}
+
+// optional .caffe.PReLUParameter prelu_param = 131;
+inline bool LayerParameter::has_prelu_param() const {
+  return (_has_bits_[1] & 0x00000100u) != 0;
+}
+inline void LayerParameter::set_has_prelu_param() {
+  _has_bits_[1] |= 0x00000100u;
+}
+inline void LayerParameter::clear_has_prelu_param() {
+  _has_bits_[1] &= ~0x00000100u;
+}
+inline void LayerParameter::clear_prelu_param() {
+  if (prelu_param_ != NULL) prelu_param_->::caffe::PReLUParameter::Clear();
+  clear_has_prelu_param();
+}
+inline const ::caffe::PReLUParameter& LayerParameter::prelu_param() const {
+  // @@protoc_insertion_point(field_get:caffe.LayerParameter.prelu_param)
+  return prelu_param_ != NULL ? *prelu_param_
+                         : *::caffe::PReLUParameter::internal_default_instance();
+}
+inline ::caffe::PReLUParameter* LayerParameter::mutable_prelu_param() {
+  set_has_prelu_param();
+  if (prelu_param_ == NULL) {
+    prelu_param_ = new ::caffe::PReLUParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.LayerParameter.prelu_param)
+  return prelu_param_;
+}
+inline ::caffe::PReLUParameter* LayerParameter::release_prelu_param() {
+  // @@protoc_insertion_point(field_release:caffe.LayerParameter.prelu_param)
+  clear_has_prelu_param();
+  ::caffe::PReLUParameter* temp = prelu_param_;
+  prelu_param_ = NULL;
+  return temp;
+}
+inline void LayerParameter::set_allocated_prelu_param(::caffe::PReLUParameter* prelu_param) {
+  delete prelu_param_;
+  prelu_param_ = prelu_param;
+  if (prelu_param) {
+    set_has_prelu_param();
+  } else {
+    clear_has_prelu_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.LayerParameter.prelu_param)
+}
+
+// optional .caffe.PriorBoxParameter prior_box_param = 140;
+inline bool LayerParameter::has_prior_box_param() const {
+  return (_has_bits_[1] & 0x00000200u) != 0;
+}
+inline void LayerParameter::set_has_prior_box_param() {
+  _has_bits_[1] |= 0x00000200u;
+}
+inline void LayerParameter::clear_has_prior_box_param() {
+  _has_bits_[1] &= ~0x00000200u;
+}
+inline void LayerParameter::clear_prior_box_param() {
+  if (prior_box_param_ != NULL) prior_box_param_->::caffe::PriorBoxParameter::Clear();
+  clear_has_prior_box_param();
+}
+inline const ::caffe::PriorBoxParameter& LayerParameter::prior_box_param() const {
+  // @@protoc_insertion_point(field_get:caffe.LayerParameter.prior_box_param)
+  return prior_box_param_ != NULL ? *prior_box_param_
+                         : *::caffe::PriorBoxParameter::internal_default_instance();
+}
+inline ::caffe::PriorBoxParameter* LayerParameter::mutable_prior_box_param() {
+  set_has_prior_box_param();
+  if (prior_box_param_ == NULL) {
+    prior_box_param_ = new ::caffe::PriorBoxParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.LayerParameter.prior_box_param)
+  return prior_box_param_;
+}
+inline ::caffe::PriorBoxParameter* LayerParameter::release_prior_box_param() {
+  // @@protoc_insertion_point(field_release:caffe.LayerParameter.prior_box_param)
+  clear_has_prior_box_param();
+  ::caffe::PriorBoxParameter* temp = prior_box_param_;
+  prior_box_param_ = NULL;
+  return temp;
+}
+inline void LayerParameter::set_allocated_prior_box_param(::caffe::PriorBoxParameter* prior_box_param) {
+  delete prior_box_param_;
+  prior_box_param_ = prior_box_param;
+  if (prior_box_param) {
+    set_has_prior_box_param();
+  } else {
+    clear_has_prior_box_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.LayerParameter.prior_box_param)
+}
+
+// optional .caffe.PythonParameter python_param = 130;
+inline bool LayerParameter::has_python_param() const {
+  return (_has_bits_[1] & 0x00000400u) != 0;
+}
+inline void LayerParameter::set_has_python_param() {
+  _has_bits_[1] |= 0x00000400u;
+}
+inline void LayerParameter::clear_has_python_param() {
+  _has_bits_[1] &= ~0x00000400u;
+}
+inline void LayerParameter::clear_python_param() {
+  if (python_param_ != NULL) python_param_->::caffe::PythonParameter::Clear();
+  clear_has_python_param();
+}
+inline const ::caffe::PythonParameter& LayerParameter::python_param() const {
+  // @@protoc_insertion_point(field_get:caffe.LayerParameter.python_param)
+  return python_param_ != NULL ? *python_param_
+                         : *::caffe::PythonParameter::internal_default_instance();
+}
+inline ::caffe::PythonParameter* LayerParameter::mutable_python_param() {
+  set_has_python_param();
+  if (python_param_ == NULL) {
+    python_param_ = new ::caffe::PythonParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.LayerParameter.python_param)
+  return python_param_;
+}
+inline ::caffe::PythonParameter* LayerParameter::release_python_param() {
+  // @@protoc_insertion_point(field_release:caffe.LayerParameter.python_param)
+  clear_has_python_param();
+  ::caffe::PythonParameter* temp = python_param_;
+  python_param_ = NULL;
+  return temp;
+}
+inline void LayerParameter::set_allocated_python_param(::caffe::PythonParameter* python_param) {
+  delete python_param_;
+  python_param_ = python_param;
+  if (python_param) {
+    set_has_python_param();
+  } else {
+    clear_has_python_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.LayerParameter.python_param)
+}
+
+// optional .caffe.ReductionParameter reduction_param = 136;
+inline bool LayerParameter::has_reduction_param() const {
+  return (_has_bits_[1] & 0x00000800u) != 0;
+}
+inline void LayerParameter::set_has_reduction_param() {
+  _has_bits_[1] |= 0x00000800u;
+}
+inline void LayerParameter::clear_has_reduction_param() {
+  _has_bits_[1] &= ~0x00000800u;
+}
+inline void LayerParameter::clear_reduction_param() {
+  if (reduction_param_ != NULL) reduction_param_->::caffe::ReductionParameter::Clear();
+  clear_has_reduction_param();
+}
+inline const ::caffe::ReductionParameter& LayerParameter::reduction_param() const {
+  // @@protoc_insertion_point(field_get:caffe.LayerParameter.reduction_param)
+  return reduction_param_ != NULL ? *reduction_param_
+                         : *::caffe::ReductionParameter::internal_default_instance();
+}
+inline ::caffe::ReductionParameter* LayerParameter::mutable_reduction_param() {
+  set_has_reduction_param();
+  if (reduction_param_ == NULL) {
+    reduction_param_ = new ::caffe::ReductionParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.LayerParameter.reduction_param)
+  return reduction_param_;
+}
+inline ::caffe::ReductionParameter* LayerParameter::release_reduction_param() {
+  // @@protoc_insertion_point(field_release:caffe.LayerParameter.reduction_param)
+  clear_has_reduction_param();
+  ::caffe::ReductionParameter* temp = reduction_param_;
+  reduction_param_ = NULL;
+  return temp;
+}
+inline void LayerParameter::set_allocated_reduction_param(::caffe::ReductionParameter* reduction_param) {
+  delete reduction_param_;
+  reduction_param_ = reduction_param;
+  if (reduction_param) {
+    set_has_reduction_param();
+  } else {
+    clear_has_reduction_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.LayerParameter.reduction_param)
+}
+
+// optional .caffe.ReLUParameter relu_param = 123;
+inline bool LayerParameter::has_relu_param() const {
+  return (_has_bits_[1] & 0x00001000u) != 0;
+}
+inline void LayerParameter::set_has_relu_param() {
+  _has_bits_[1] |= 0x00001000u;
+}
+inline void LayerParameter::clear_has_relu_param() {
+  _has_bits_[1] &= ~0x00001000u;
+}
+inline void LayerParameter::clear_relu_param() {
+  if (relu_param_ != NULL) relu_param_->::caffe::ReLUParameter::Clear();
+  clear_has_relu_param();
+}
+inline const ::caffe::ReLUParameter& LayerParameter::relu_param() const {
+  // @@protoc_insertion_point(field_get:caffe.LayerParameter.relu_param)
+  return relu_param_ != NULL ? *relu_param_
+                         : *::caffe::ReLUParameter::internal_default_instance();
+}
+inline ::caffe::ReLUParameter* LayerParameter::mutable_relu_param() {
+  set_has_relu_param();
+  if (relu_param_ == NULL) {
+    relu_param_ = new ::caffe::ReLUParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.LayerParameter.relu_param)
+  return relu_param_;
+}
+inline ::caffe::ReLUParameter* LayerParameter::release_relu_param() {
+  // @@protoc_insertion_point(field_release:caffe.LayerParameter.relu_param)
+  clear_has_relu_param();
+  ::caffe::ReLUParameter* temp = relu_param_;
+  relu_param_ = NULL;
+  return temp;
+}
+inline void LayerParameter::set_allocated_relu_param(::caffe::ReLUParameter* relu_param) {
+  delete relu_param_;
+  relu_param_ = relu_param;
+  if (relu_param) {
+    set_has_relu_param();
+  } else {
+    clear_has_relu_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.LayerParameter.relu_param)
+}
+
+// optional .caffe.ReshapeParameter reshape_param = 133;
+inline bool LayerParameter::has_reshape_param() const {
+  return (_has_bits_[1] & 0x00002000u) != 0;
+}
+inline void LayerParameter::set_has_reshape_param() {
+  _has_bits_[1] |= 0x00002000u;
+}
+inline void LayerParameter::clear_has_reshape_param() {
+  _has_bits_[1] &= ~0x00002000u;
+}
+inline void LayerParameter::clear_reshape_param() {
+  if (reshape_param_ != NULL) reshape_param_->::caffe::ReshapeParameter::Clear();
+  clear_has_reshape_param();
+}
+inline const ::caffe::ReshapeParameter& LayerParameter::reshape_param() const {
+  // @@protoc_insertion_point(field_get:caffe.LayerParameter.reshape_param)
+  return reshape_param_ != NULL ? *reshape_param_
+                         : *::caffe::ReshapeParameter::internal_default_instance();
+}
+inline ::caffe::ReshapeParameter* LayerParameter::mutable_reshape_param() {
+  set_has_reshape_param();
+  if (reshape_param_ == NULL) {
+    reshape_param_ = new ::caffe::ReshapeParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.LayerParameter.reshape_param)
+  return reshape_param_;
+}
+inline ::caffe::ReshapeParameter* LayerParameter::release_reshape_param() {
+  // @@protoc_insertion_point(field_release:caffe.LayerParameter.reshape_param)
+  clear_has_reshape_param();
+  ::caffe::ReshapeParameter* temp = reshape_param_;
+  reshape_param_ = NULL;
+  return temp;
+}
+inline void LayerParameter::set_allocated_reshape_param(::caffe::ReshapeParameter* reshape_param) {
+  delete reshape_param_;
+  reshape_param_ = reshape_param;
+  if (reshape_param) {
+    set_has_reshape_param();
+  } else {
+    clear_has_reshape_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.LayerParameter.reshape_param)
+}
+
+// optional .caffe.SigmoidParameter sigmoid_param = 124;
+inline bool LayerParameter::has_sigmoid_param() const {
+  return (_has_bits_[1] & 0x00004000u) != 0;
+}
+inline void LayerParameter::set_has_sigmoid_param() {
+  _has_bits_[1] |= 0x00004000u;
+}
+inline void LayerParameter::clear_has_sigmoid_param() {
+  _has_bits_[1] &= ~0x00004000u;
+}
+inline void LayerParameter::clear_sigmoid_param() {
+  if (sigmoid_param_ != NULL) sigmoid_param_->::caffe::SigmoidParameter::Clear();
+  clear_has_sigmoid_param();
+}
+inline const ::caffe::SigmoidParameter& LayerParameter::sigmoid_param() const {
+  // @@protoc_insertion_point(field_get:caffe.LayerParameter.sigmoid_param)
+  return sigmoid_param_ != NULL ? *sigmoid_param_
+                         : *::caffe::SigmoidParameter::internal_default_instance();
+}
+inline ::caffe::SigmoidParameter* LayerParameter::mutable_sigmoid_param() {
+  set_has_sigmoid_param();
+  if (sigmoid_param_ == NULL) {
+    sigmoid_param_ = new ::caffe::SigmoidParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.LayerParameter.sigmoid_param)
+  return sigmoid_param_;
+}
+inline ::caffe::SigmoidParameter* LayerParameter::release_sigmoid_param() {
+  // @@protoc_insertion_point(field_release:caffe.LayerParameter.sigmoid_param)
+  clear_has_sigmoid_param();
+  ::caffe::SigmoidParameter* temp = sigmoid_param_;
+  sigmoid_param_ = NULL;
+  return temp;
+}
+inline void LayerParameter::set_allocated_sigmoid_param(::caffe::SigmoidParameter* sigmoid_param) {
+  delete sigmoid_param_;
+  sigmoid_param_ = sigmoid_param;
+  if (sigmoid_param) {
+    set_has_sigmoid_param();
+  } else {
+    clear_has_sigmoid_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.LayerParameter.sigmoid_param)
+}
+
+// optional .caffe.SliceParameter slice_param = 126;
+inline bool LayerParameter::has_slice_param() const {
+  return (_has_bits_[1] & 0x00008000u) != 0;
+}
+inline void LayerParameter::set_has_slice_param() {
+  _has_bits_[1] |= 0x00008000u;
+}
+inline void LayerParameter::clear_has_slice_param() {
+  _has_bits_[1] &= ~0x00008000u;
+}
+inline void LayerParameter::clear_slice_param() {
+  if (slice_param_ != NULL) slice_param_->::caffe::SliceParameter::Clear();
+  clear_has_slice_param();
+}
+inline const ::caffe::SliceParameter& LayerParameter::slice_param() const {
+  // @@protoc_insertion_point(field_get:caffe.LayerParameter.slice_param)
+  return slice_param_ != NULL ? *slice_param_
+                         : *::caffe::SliceParameter::internal_default_instance();
+}
+inline ::caffe::SliceParameter* LayerParameter::mutable_slice_param() {
+  set_has_slice_param();
+  if (slice_param_ == NULL) {
+    slice_param_ = new ::caffe::SliceParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.LayerParameter.slice_param)
+  return slice_param_;
+}
+inline ::caffe::SliceParameter* LayerParameter::release_slice_param() {
+  // @@protoc_insertion_point(field_release:caffe.LayerParameter.slice_param)
+  clear_has_slice_param();
+  ::caffe::SliceParameter* temp = slice_param_;
+  slice_param_ = NULL;
+  return temp;
+}
+inline void LayerParameter::set_allocated_slice_param(::caffe::SliceParameter* slice_param) {
+  delete slice_param_;
+  slice_param_ = slice_param;
+  if (slice_param) {
+    set_has_slice_param();
+  } else {
+    clear_has_slice_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.LayerParameter.slice_param)
+}
+
+// optional .caffe.SoftmaxParameter softmax_param = 125;
+inline bool LayerParameter::has_softmax_param() const {
+  return (_has_bits_[1] & 0x00010000u) != 0;
+}
+inline void LayerParameter::set_has_softmax_param() {
+  _has_bits_[1] |= 0x00010000u;
+}
+inline void LayerParameter::clear_has_softmax_param() {
+  _has_bits_[1] &= ~0x00010000u;
+}
+inline void LayerParameter::clear_softmax_param() {
+  if (softmax_param_ != NULL) softmax_param_->::caffe::SoftmaxParameter::Clear();
+  clear_has_softmax_param();
+}
+inline const ::caffe::SoftmaxParameter& LayerParameter::softmax_param() const {
+  // @@protoc_insertion_point(field_get:caffe.LayerParameter.softmax_param)
+  return softmax_param_ != NULL ? *softmax_param_
+                         : *::caffe::SoftmaxParameter::internal_default_instance();
+}
+inline ::caffe::SoftmaxParameter* LayerParameter::mutable_softmax_param() {
+  set_has_softmax_param();
+  if (softmax_param_ == NULL) {
+    softmax_param_ = new ::caffe::SoftmaxParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.LayerParameter.softmax_param)
+  return softmax_param_;
+}
+inline ::caffe::SoftmaxParameter* LayerParameter::release_softmax_param() {
+  // @@protoc_insertion_point(field_release:caffe.LayerParameter.softmax_param)
+  clear_has_softmax_param();
+  ::caffe::SoftmaxParameter* temp = softmax_param_;
+  softmax_param_ = NULL;
+  return temp;
+}
+inline void LayerParameter::set_allocated_softmax_param(::caffe::SoftmaxParameter* softmax_param) {
+  delete softmax_param_;
+  softmax_param_ = softmax_param;
+  if (softmax_param) {
+    set_has_softmax_param();
+  } else {
+    clear_has_softmax_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.LayerParameter.softmax_param)
+}
+
+// optional .caffe.SPPParameter spp_param = 132;
+inline bool LayerParameter::has_spp_param() const {
+  return (_has_bits_[1] & 0x00020000u) != 0;
+}
+inline void LayerParameter::set_has_spp_param() {
+  _has_bits_[1] |= 0x00020000u;
+}
+inline void LayerParameter::clear_has_spp_param() {
+  _has_bits_[1] &= ~0x00020000u;
+}
+inline void LayerParameter::clear_spp_param() {
+  if (spp_param_ != NULL) spp_param_->::caffe::SPPParameter::Clear();
+  clear_has_spp_param();
+}
+inline const ::caffe::SPPParameter& LayerParameter::spp_param() const {
+  // @@protoc_insertion_point(field_get:caffe.LayerParameter.spp_param)
+  return spp_param_ != NULL ? *spp_param_
+                         : *::caffe::SPPParameter::internal_default_instance();
+}
+inline ::caffe::SPPParameter* LayerParameter::mutable_spp_param() {
+  set_has_spp_param();
+  if (spp_param_ == NULL) {
+    spp_param_ = new ::caffe::SPPParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.LayerParameter.spp_param)
+  return spp_param_;
+}
+inline ::caffe::SPPParameter* LayerParameter::release_spp_param() {
+  // @@protoc_insertion_point(field_release:caffe.LayerParameter.spp_param)
+  clear_has_spp_param();
+  ::caffe::SPPParameter* temp = spp_param_;
+  spp_param_ = NULL;
+  return temp;
+}
+inline void LayerParameter::set_allocated_spp_param(::caffe::SPPParameter* spp_param) {
+  delete spp_param_;
+  spp_param_ = spp_param;
+  if (spp_param) {
+    set_has_spp_param();
+  } else {
+    clear_has_spp_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.LayerParameter.spp_param)
+}
+
+// optional .caffe.TanHParameter tanh_param = 127;
+inline bool LayerParameter::has_tanh_param() const {
+  return (_has_bits_[1] & 0x00040000u) != 0;
+}
+inline void LayerParameter::set_has_tanh_param() {
+  _has_bits_[1] |= 0x00040000u;
+}
+inline void LayerParameter::clear_has_tanh_param() {
+  _has_bits_[1] &= ~0x00040000u;
+}
+inline void LayerParameter::clear_tanh_param() {
+  if (tanh_param_ != NULL) tanh_param_->::caffe::TanHParameter::Clear();
+  clear_has_tanh_param();
+}
+inline const ::caffe::TanHParameter& LayerParameter::tanh_param() const {
+  // @@protoc_insertion_point(field_get:caffe.LayerParameter.tanh_param)
+  return tanh_param_ != NULL ? *tanh_param_
+                         : *::caffe::TanHParameter::internal_default_instance();
+}
+inline ::caffe::TanHParameter* LayerParameter::mutable_tanh_param() {
+  set_has_tanh_param();
+  if (tanh_param_ == NULL) {
+    tanh_param_ = new ::caffe::TanHParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.LayerParameter.tanh_param)
+  return tanh_param_;
+}
+inline ::caffe::TanHParameter* LayerParameter::release_tanh_param() {
+  // @@protoc_insertion_point(field_release:caffe.LayerParameter.tanh_param)
+  clear_has_tanh_param();
+  ::caffe::TanHParameter* temp = tanh_param_;
+  tanh_param_ = NULL;
+  return temp;
+}
+inline void LayerParameter::set_allocated_tanh_param(::caffe::TanHParameter* tanh_param) {
+  delete tanh_param_;
+  tanh_param_ = tanh_param;
+  if (tanh_param) {
+    set_has_tanh_param();
+  } else {
+    clear_has_tanh_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.LayerParameter.tanh_param)
+}
+
+// optional .caffe.ThresholdParameter threshold_param = 128;
+inline bool LayerParameter::has_threshold_param() const {
+  return (_has_bits_[1] & 0x00080000u) != 0;
+}
+inline void LayerParameter::set_has_threshold_param() {
+  _has_bits_[1] |= 0x00080000u;
+}
+inline void LayerParameter::clear_has_threshold_param() {
+  _has_bits_[1] &= ~0x00080000u;
+}
+inline void LayerParameter::clear_threshold_param() {
+  if (threshold_param_ != NULL) threshold_param_->::caffe::ThresholdParameter::Clear();
+  clear_has_threshold_param();
+}
+inline const ::caffe::ThresholdParameter& LayerParameter::threshold_param() const {
+  // @@protoc_insertion_point(field_get:caffe.LayerParameter.threshold_param)
+  return threshold_param_ != NULL ? *threshold_param_
+                         : *::caffe::ThresholdParameter::internal_default_instance();
+}
+inline ::caffe::ThresholdParameter* LayerParameter::mutable_threshold_param() {
+  set_has_threshold_param();
+  if (threshold_param_ == NULL) {
+    threshold_param_ = new ::caffe::ThresholdParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.LayerParameter.threshold_param)
+  return threshold_param_;
+}
+inline ::caffe::ThresholdParameter* LayerParameter::release_threshold_param() {
+  // @@protoc_insertion_point(field_release:caffe.LayerParameter.threshold_param)
+  clear_has_threshold_param();
+  ::caffe::ThresholdParameter* temp = threshold_param_;
+  threshold_param_ = NULL;
+  return temp;
+}
+inline void LayerParameter::set_allocated_threshold_param(::caffe::ThresholdParameter* threshold_param) {
+  delete threshold_param_;
+  threshold_param_ = threshold_param;
+  if (threshold_param) {
+    set_has_threshold_param();
+  } else {
+    clear_has_threshold_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.LayerParameter.threshold_param)
+}
+
+// optional .caffe.WindowDataParameter window_data_param = 129;
+inline bool LayerParameter::has_window_data_param() const {
+  return (_has_bits_[1] & 0x00100000u) != 0;
+}
+inline void LayerParameter::set_has_window_data_param() {
+  _has_bits_[1] |= 0x00100000u;
+}
+inline void LayerParameter::clear_has_window_data_param() {
+  _has_bits_[1] &= ~0x00100000u;
+}
+inline void LayerParameter::clear_window_data_param() {
+  if (window_data_param_ != NULL) window_data_param_->::caffe::WindowDataParameter::Clear();
+  clear_has_window_data_param();
+}
+inline const ::caffe::WindowDataParameter& LayerParameter::window_data_param() const {
+  // @@protoc_insertion_point(field_get:caffe.LayerParameter.window_data_param)
+  return window_data_param_ != NULL ? *window_data_param_
+                         : *::caffe::WindowDataParameter::internal_default_instance();
+}
+inline ::caffe::WindowDataParameter* LayerParameter::mutable_window_data_param() {
+  set_has_window_data_param();
+  if (window_data_param_ == NULL) {
+    window_data_param_ = new ::caffe::WindowDataParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.LayerParameter.window_data_param)
+  return window_data_param_;
+}
+inline ::caffe::WindowDataParameter* LayerParameter::release_window_data_param() {
+  // @@protoc_insertion_point(field_release:caffe.LayerParameter.window_data_param)
+  clear_has_window_data_param();
+  ::caffe::WindowDataParameter* temp = window_data_param_;
+  window_data_param_ = NULL;
+  return temp;
+}
+inline void LayerParameter::set_allocated_window_data_param(::caffe::WindowDataParameter* window_data_param) {
+  delete window_data_param_;
+  window_data_param_ = window_data_param;
+  if (window_data_param) {
+    set_has_window_data_param();
+  } else {
+    clear_has_window_data_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.LayerParameter.window_data_param)
+}
+
+inline const LayerParameter* LayerParameter::internal_default_instance() {
+  return &LayerParameter_default_instance_.get();
+}
+// -------------------------------------------------------------------
+
+// TransformationParameter
+
+// optional float scale = 1 [default = 1];
+inline bool TransformationParameter::has_scale() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+inline void TransformationParameter::set_has_scale() {
+  _has_bits_[0] |= 0x00000001u;
+}
+inline void TransformationParameter::clear_has_scale() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+inline void TransformationParameter::clear_scale() {
+  scale_ = 1;
+  clear_has_scale();
+}
+inline float TransformationParameter::scale() const {
+  // @@protoc_insertion_point(field_get:caffe.TransformationParameter.scale)
+  return scale_;
+}
+inline void TransformationParameter::set_scale(float value) {
+  set_has_scale();
+  scale_ = value;
+  // @@protoc_insertion_point(field_set:caffe.TransformationParameter.scale)
+}
+
+// optional bool mirror = 2 [default = false];
+inline bool TransformationParameter::has_mirror() const {
+  return (_has_bits_[0] & 0x00000002u) != 0;
+}
+inline void TransformationParameter::set_has_mirror() {
+  _has_bits_[0] |= 0x00000002u;
+}
+inline void TransformationParameter::clear_has_mirror() {
+  _has_bits_[0] &= ~0x00000002u;
+}
+inline void TransformationParameter::clear_mirror() {
+  mirror_ = false;
+  clear_has_mirror();
+}
+inline bool TransformationParameter::mirror() const {
+  // @@protoc_insertion_point(field_get:caffe.TransformationParameter.mirror)
+  return mirror_;
+}
+inline void TransformationParameter::set_mirror(bool value) {
+  set_has_mirror();
+  mirror_ = value;
+  // @@protoc_insertion_point(field_set:caffe.TransformationParameter.mirror)
+}
+
+// optional uint32 crop_size = 3 [default = 0];
+inline bool TransformationParameter::has_crop_size() const {
+  return (_has_bits_[0] & 0x00000004u) != 0;
+}
+inline void TransformationParameter::set_has_crop_size() {
+  _has_bits_[0] |= 0x00000004u;
+}
+inline void TransformationParameter::clear_has_crop_size() {
+  _has_bits_[0] &= ~0x00000004u;
+}
+inline void TransformationParameter::clear_crop_size() {
+  crop_size_ = 0u;
+  clear_has_crop_size();
+}
+inline ::google::protobuf::uint32 TransformationParameter::crop_size() const {
+  // @@protoc_insertion_point(field_get:caffe.TransformationParameter.crop_size)
+  return crop_size_;
+}
+inline void TransformationParameter::set_crop_size(::google::protobuf::uint32 value) {
+  set_has_crop_size();
+  crop_size_ = value;
+  // @@protoc_insertion_point(field_set:caffe.TransformationParameter.crop_size)
+}
+
+// optional string mean_file = 4;
+inline bool TransformationParameter::has_mean_file() const {
+  return (_has_bits_[0] & 0x00000008u) != 0;
+}
+inline void TransformationParameter::set_has_mean_file() {
+  _has_bits_[0] |= 0x00000008u;
+}
+inline void TransformationParameter::clear_has_mean_file() {
+  _has_bits_[0] &= ~0x00000008u;
+}
+inline void TransformationParameter::clear_mean_file() {
+  mean_file_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  clear_has_mean_file();
+}
+inline const ::std::string& TransformationParameter::mean_file() const {
+  // @@protoc_insertion_point(field_get:caffe.TransformationParameter.mean_file)
+  return mean_file_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void TransformationParameter::set_mean_file(const ::std::string& value) {
+  set_has_mean_file();
+  mean_file_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:caffe.TransformationParameter.mean_file)
+}
+inline void TransformationParameter::set_mean_file(const char* value) {
+  set_has_mean_file();
+  mean_file_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:caffe.TransformationParameter.mean_file)
+}
+inline void TransformationParameter::set_mean_file(const char* value, size_t size) {
+  set_has_mean_file();
+  mean_file_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:caffe.TransformationParameter.mean_file)
+}
+inline ::std::string* TransformationParameter::mutable_mean_file() {
+  set_has_mean_file();
+  // @@protoc_insertion_point(field_mutable:caffe.TransformationParameter.mean_file)
+  return mean_file_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline ::std::string* TransformationParameter::release_mean_file() {
+  // @@protoc_insertion_point(field_release:caffe.TransformationParameter.mean_file)
+  clear_has_mean_file();
+  return mean_file_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void TransformationParameter::set_allocated_mean_file(::std::string* mean_file) {
+  if (mean_file != NULL) {
+    set_has_mean_file();
+  } else {
+    clear_has_mean_file();
+  }
+  mean_file_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), mean_file);
+  // @@protoc_insertion_point(field_set_allocated:caffe.TransformationParameter.mean_file)
+}
+
+// repeated float mean_value = 5;
+inline int TransformationParameter::mean_value_size() const {
+  return mean_value_.size();
+}
+inline void TransformationParameter::clear_mean_value() {
+  mean_value_.Clear();
+}
+inline float TransformationParameter::mean_value(int index) const {
+  // @@protoc_insertion_point(field_get:caffe.TransformationParameter.mean_value)
+  return mean_value_.Get(index);
+}
+inline void TransformationParameter::set_mean_value(int index, float value) {
+  mean_value_.Set(index, value);
+  // @@protoc_insertion_point(field_set:caffe.TransformationParameter.mean_value)
+}
+inline void TransformationParameter::add_mean_value(float value) {
+  mean_value_.Add(value);
+  // @@protoc_insertion_point(field_add:caffe.TransformationParameter.mean_value)
+}
+inline const ::google::protobuf::RepeatedField< float >&
+TransformationParameter::mean_value() const {
+  // @@protoc_insertion_point(field_list:caffe.TransformationParameter.mean_value)
+  return mean_value_;
+}
+inline ::google::protobuf::RepeatedField< float >*
+TransformationParameter::mutable_mean_value() {
+  // @@protoc_insertion_point(field_mutable_list:caffe.TransformationParameter.mean_value)
+  return &mean_value_;
+}
+
+// optional bool force_color = 6 [default = false];
+inline bool TransformationParameter::has_force_color() const {
+  return (_has_bits_[0] & 0x00000020u) != 0;
+}
+inline void TransformationParameter::set_has_force_color() {
+  _has_bits_[0] |= 0x00000020u;
+}
+inline void TransformationParameter::clear_has_force_color() {
+  _has_bits_[0] &= ~0x00000020u;
+}
+inline void TransformationParameter::clear_force_color() {
+  force_color_ = false;
+  clear_has_force_color();
+}
+inline bool TransformationParameter::force_color() const {
+  // @@protoc_insertion_point(field_get:caffe.TransformationParameter.force_color)
+  return force_color_;
+}
+inline void TransformationParameter::set_force_color(bool value) {
+  set_has_force_color();
+  force_color_ = value;
+  // @@protoc_insertion_point(field_set:caffe.TransformationParameter.force_color)
+}
+
+// optional bool force_gray = 7 [default = false];
+inline bool TransformationParameter::has_force_gray() const {
+  return (_has_bits_[0] & 0x00000040u) != 0;
+}
+inline void TransformationParameter::set_has_force_gray() {
+  _has_bits_[0] |= 0x00000040u;
+}
+inline void TransformationParameter::clear_has_force_gray() {
+  _has_bits_[0] &= ~0x00000040u;
+}
+inline void TransformationParameter::clear_force_gray() {
+  force_gray_ = false;
+  clear_has_force_gray();
+}
+inline bool TransformationParameter::force_gray() const {
+  // @@protoc_insertion_point(field_get:caffe.TransformationParameter.force_gray)
+  return force_gray_;
+}
+inline void TransformationParameter::set_force_gray(bool value) {
+  set_has_force_gray();
+  force_gray_ = value;
+  // @@protoc_insertion_point(field_set:caffe.TransformationParameter.force_gray)
+}
+
+inline const TransformationParameter* TransformationParameter::internal_default_instance() {
+  return &TransformationParameter_default_instance_.get();
+}
+// -------------------------------------------------------------------
+
+// LossParameter
+
+// optional int32 ignore_label = 1;
+inline bool LossParameter::has_ignore_label() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+inline void LossParameter::set_has_ignore_label() {
+  _has_bits_[0] |= 0x00000001u;
+}
+inline void LossParameter::clear_has_ignore_label() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+inline void LossParameter::clear_ignore_label() {
+  ignore_label_ = 0;
+  clear_has_ignore_label();
+}
+inline ::google::protobuf::int32 LossParameter::ignore_label() const {
+  // @@protoc_insertion_point(field_get:caffe.LossParameter.ignore_label)
+  return ignore_label_;
+}
+inline void LossParameter::set_ignore_label(::google::protobuf::int32 value) {
+  set_has_ignore_label();
+  ignore_label_ = value;
+  // @@protoc_insertion_point(field_set:caffe.LossParameter.ignore_label)
+}
+
+// optional bool normalize = 2 [default = true];
+inline bool LossParameter::has_normalize() const {
+  return (_has_bits_[0] & 0x00000002u) != 0;
+}
+inline void LossParameter::set_has_normalize() {
+  _has_bits_[0] |= 0x00000002u;
+}
+inline void LossParameter::clear_has_normalize() {
+  _has_bits_[0] &= ~0x00000002u;
+}
+inline void LossParameter::clear_normalize() {
+  normalize_ = true;
+  clear_has_normalize();
+}
+inline bool LossParameter::normalize() const {
+  // @@protoc_insertion_point(field_get:caffe.LossParameter.normalize)
+  return normalize_;
+}
+inline void LossParameter::set_normalize(bool value) {
+  set_has_normalize();
+  normalize_ = value;
+  // @@protoc_insertion_point(field_set:caffe.LossParameter.normalize)
+}
+
+inline const LossParameter* LossParameter::internal_default_instance() {
+  return &LossParameter_default_instance_.get();
+}
+// -------------------------------------------------------------------
+
+// AccuracyParameter
+
+// optional uint32 top_k = 1 [default = 1];
+inline bool AccuracyParameter::has_top_k() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+inline void AccuracyParameter::set_has_top_k() {
+  _has_bits_[0] |= 0x00000001u;
+}
+inline void AccuracyParameter::clear_has_top_k() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+inline void AccuracyParameter::clear_top_k() {
+  top_k_ = 1u;
+  clear_has_top_k();
+}
+inline ::google::protobuf::uint32 AccuracyParameter::top_k() const {
+  // @@protoc_insertion_point(field_get:caffe.AccuracyParameter.top_k)
+  return top_k_;
+}
+inline void AccuracyParameter::set_top_k(::google::protobuf::uint32 value) {
+  set_has_top_k();
+  top_k_ = value;
+  // @@protoc_insertion_point(field_set:caffe.AccuracyParameter.top_k)
+}
+
+// optional int32 axis = 2 [default = 1];
+inline bool AccuracyParameter::has_axis() const {
+  return (_has_bits_[0] & 0x00000002u) != 0;
+}
+inline void AccuracyParameter::set_has_axis() {
+  _has_bits_[0] |= 0x00000002u;
+}
+inline void AccuracyParameter::clear_has_axis() {
+  _has_bits_[0] &= ~0x00000002u;
+}
+inline void AccuracyParameter::clear_axis() {
+  axis_ = 1;
+  clear_has_axis();
+}
+inline ::google::protobuf::int32 AccuracyParameter::axis() const {
+  // @@protoc_insertion_point(field_get:caffe.AccuracyParameter.axis)
+  return axis_;
+}
+inline void AccuracyParameter::set_axis(::google::protobuf::int32 value) {
+  set_has_axis();
+  axis_ = value;
+  // @@protoc_insertion_point(field_set:caffe.AccuracyParameter.axis)
+}
+
+// optional int32 ignore_label = 3;
+inline bool AccuracyParameter::has_ignore_label() const {
+  return (_has_bits_[0] & 0x00000004u) != 0;
+}
+inline void AccuracyParameter::set_has_ignore_label() {
+  _has_bits_[0] |= 0x00000004u;
+}
+inline void AccuracyParameter::clear_has_ignore_label() {
+  _has_bits_[0] &= ~0x00000004u;
+}
+inline void AccuracyParameter::clear_ignore_label() {
+  ignore_label_ = 0;
+  clear_has_ignore_label();
+}
+inline ::google::protobuf::int32 AccuracyParameter::ignore_label() const {
+  // @@protoc_insertion_point(field_get:caffe.AccuracyParameter.ignore_label)
+  return ignore_label_;
+}
+inline void AccuracyParameter::set_ignore_label(::google::protobuf::int32 value) {
+  set_has_ignore_label();
+  ignore_label_ = value;
+  // @@protoc_insertion_point(field_set:caffe.AccuracyParameter.ignore_label)
+}
+
+inline const AccuracyParameter* AccuracyParameter::internal_default_instance() {
+  return &AccuracyParameter_default_instance_.get();
+}
+// -------------------------------------------------------------------
+
+// ArgMaxParameter
+
+// optional bool out_max_val = 1 [default = false];
+inline bool ArgMaxParameter::has_out_max_val() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+inline void ArgMaxParameter::set_has_out_max_val() {
+  _has_bits_[0] |= 0x00000001u;
+}
+inline void ArgMaxParameter::clear_has_out_max_val() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+inline void ArgMaxParameter::clear_out_max_val() {
+  out_max_val_ = false;
+  clear_has_out_max_val();
+}
+inline bool ArgMaxParameter::out_max_val() const {
+  // @@protoc_insertion_point(field_get:caffe.ArgMaxParameter.out_max_val)
+  return out_max_val_;
+}
+inline void ArgMaxParameter::set_out_max_val(bool value) {
+  set_has_out_max_val();
+  out_max_val_ = value;
+  // @@protoc_insertion_point(field_set:caffe.ArgMaxParameter.out_max_val)
+}
+
+// optional uint32 top_k = 2 [default = 1];
+inline bool ArgMaxParameter::has_top_k() const {
+  return (_has_bits_[0] & 0x00000002u) != 0;
+}
+inline void ArgMaxParameter::set_has_top_k() {
+  _has_bits_[0] |= 0x00000002u;
+}
+inline void ArgMaxParameter::clear_has_top_k() {
+  _has_bits_[0] &= ~0x00000002u;
+}
+inline void ArgMaxParameter::clear_top_k() {
+  top_k_ = 1u;
+  clear_has_top_k();
+}
+inline ::google::protobuf::uint32 ArgMaxParameter::top_k() const {
+  // @@protoc_insertion_point(field_get:caffe.ArgMaxParameter.top_k)
+  return top_k_;
+}
+inline void ArgMaxParameter::set_top_k(::google::protobuf::uint32 value) {
+  set_has_top_k();
+  top_k_ = value;
+  // @@protoc_insertion_point(field_set:caffe.ArgMaxParameter.top_k)
+}
+
+inline const ArgMaxParameter* ArgMaxParameter::internal_default_instance() {
+  return &ArgMaxParameter_default_instance_.get();
+}
+// -------------------------------------------------------------------
+
+// ConcatParameter
+
+// optional int32 axis = 2 [default = 1];
+inline bool ConcatParameter::has_axis() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+inline void ConcatParameter::set_has_axis() {
+  _has_bits_[0] |= 0x00000001u;
+}
+inline void ConcatParameter::clear_has_axis() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+inline void ConcatParameter::clear_axis() {
+  axis_ = 1;
+  clear_has_axis();
+}
+inline ::google::protobuf::int32 ConcatParameter::axis() const {
+  // @@protoc_insertion_point(field_get:caffe.ConcatParameter.axis)
+  return axis_;
+}
+inline void ConcatParameter::set_axis(::google::protobuf::int32 value) {
+  set_has_axis();
+  axis_ = value;
+  // @@protoc_insertion_point(field_set:caffe.ConcatParameter.axis)
+}
+
+// optional uint32 concat_dim = 1 [default = 1];
+inline bool ConcatParameter::has_concat_dim() const {
+  return (_has_bits_[0] & 0x00000002u) != 0;
+}
+inline void ConcatParameter::set_has_concat_dim() {
+  _has_bits_[0] |= 0x00000002u;
+}
+inline void ConcatParameter::clear_has_concat_dim() {
+  _has_bits_[0] &= ~0x00000002u;
+}
+inline void ConcatParameter::clear_concat_dim() {
+  concat_dim_ = 1u;
+  clear_has_concat_dim();
+}
+inline ::google::protobuf::uint32 ConcatParameter::concat_dim() const {
+  // @@protoc_insertion_point(field_get:caffe.ConcatParameter.concat_dim)
+  return concat_dim_;
+}
+inline void ConcatParameter::set_concat_dim(::google::protobuf::uint32 value) {
+  set_has_concat_dim();
+  concat_dim_ = value;
+  // @@protoc_insertion_point(field_set:caffe.ConcatParameter.concat_dim)
+}
+
+inline const ConcatParameter* ConcatParameter::internal_default_instance() {
+  return &ConcatParameter_default_instance_.get();
+}
+// -------------------------------------------------------------------
+
+// ContrastiveLossParameter
+
+// optional float margin = 1 [default = 1];
+inline bool ContrastiveLossParameter::has_margin() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+inline void ContrastiveLossParameter::set_has_margin() {
+  _has_bits_[0] |= 0x00000001u;
+}
+inline void ContrastiveLossParameter::clear_has_margin() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+inline void ContrastiveLossParameter::clear_margin() {
+  margin_ = 1;
+  clear_has_margin();
+}
+inline float ContrastiveLossParameter::margin() const {
+  // @@protoc_insertion_point(field_get:caffe.ContrastiveLossParameter.margin)
+  return margin_;
+}
+inline void ContrastiveLossParameter::set_margin(float value) {
+  set_has_margin();
+  margin_ = value;
+  // @@protoc_insertion_point(field_set:caffe.ContrastiveLossParameter.margin)
+}
+
+// optional bool legacy_version = 2 [default = false];
+inline bool ContrastiveLossParameter::has_legacy_version() const {
+  return (_has_bits_[0] & 0x00000002u) != 0;
+}
+inline void ContrastiveLossParameter::set_has_legacy_version() {
+  _has_bits_[0] |= 0x00000002u;
+}
+inline void ContrastiveLossParameter::clear_has_legacy_version() {
+  _has_bits_[0] &= ~0x00000002u;
+}
+inline void ContrastiveLossParameter::clear_legacy_version() {
+  legacy_version_ = false;
+  clear_has_legacy_version();
+}
+inline bool ContrastiveLossParameter::legacy_version() const {
+  // @@protoc_insertion_point(field_get:caffe.ContrastiveLossParameter.legacy_version)
+  return legacy_version_;
+}
+inline void ContrastiveLossParameter::set_legacy_version(bool value) {
+  set_has_legacy_version();
+  legacy_version_ = value;
+  // @@protoc_insertion_point(field_set:caffe.ContrastiveLossParameter.legacy_version)
+}
+
+inline const ContrastiveLossParameter* ContrastiveLossParameter::internal_default_instance() {
+  return &ContrastiveLossParameter_default_instance_.get();
+}
+// -------------------------------------------------------------------
+
+// ConvolutionParameter
+
+// optional uint32 num_output = 1;
+inline bool ConvolutionParameter::has_num_output() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+inline void ConvolutionParameter::set_has_num_output() {
+  _has_bits_[0] |= 0x00000001u;
+}
+inline void ConvolutionParameter::clear_has_num_output() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+inline void ConvolutionParameter::clear_num_output() {
+  num_output_ = 0u;
+  clear_has_num_output();
+}
+inline ::google::protobuf::uint32 ConvolutionParameter::num_output() const {
+  // @@protoc_insertion_point(field_get:caffe.ConvolutionParameter.num_output)
+  return num_output_;
+}
+inline void ConvolutionParameter::set_num_output(::google::protobuf::uint32 value) {
+  set_has_num_output();
+  num_output_ = value;
+  // @@protoc_insertion_point(field_set:caffe.ConvolutionParameter.num_output)
+}
+
+// optional bool bias_term = 2 [default = true];
+inline bool ConvolutionParameter::has_bias_term() const {
+  return (_has_bits_[0] & 0x00000002u) != 0;
+}
+inline void ConvolutionParameter::set_has_bias_term() {
+  _has_bits_[0] |= 0x00000002u;
+}
+inline void ConvolutionParameter::clear_has_bias_term() {
+  _has_bits_[0] &= ~0x00000002u;
+}
+inline void ConvolutionParameter::clear_bias_term() {
+  bias_term_ = true;
+  clear_has_bias_term();
+}
+inline bool ConvolutionParameter::bias_term() const {
+  // @@protoc_insertion_point(field_get:caffe.ConvolutionParameter.bias_term)
+  return bias_term_;
+}
+inline void ConvolutionParameter::set_bias_term(bool value) {
+  set_has_bias_term();
+  bias_term_ = value;
+  // @@protoc_insertion_point(field_set:caffe.ConvolutionParameter.bias_term)
+}
+
+// optional uint32 pad = 3 [default = 0];
+inline bool ConvolutionParameter::has_pad() const {
+  return (_has_bits_[0] & 0x00000004u) != 0;
+}
+inline void ConvolutionParameter::set_has_pad() {
+  _has_bits_[0] |= 0x00000004u;
+}
+inline void ConvolutionParameter::clear_has_pad() {
+  _has_bits_[0] &= ~0x00000004u;
+}
+inline void ConvolutionParameter::clear_pad() {
+  pad_ = 0u;
+  clear_has_pad();
+}
+inline ::google::protobuf::uint32 ConvolutionParameter::pad() const {
+  // @@protoc_insertion_point(field_get:caffe.ConvolutionParameter.pad)
+  return pad_;
+}
+inline void ConvolutionParameter::set_pad(::google::protobuf::uint32 value) {
+  set_has_pad();
+  pad_ = value;
+  // @@protoc_insertion_point(field_set:caffe.ConvolutionParameter.pad)
+}
+
+// optional uint32 pad_h = 9 [default = 0];
+inline bool ConvolutionParameter::has_pad_h() const {
+  return (_has_bits_[0] & 0x00000008u) != 0;
+}
+inline void ConvolutionParameter::set_has_pad_h() {
+  _has_bits_[0] |= 0x00000008u;
+}
+inline void ConvolutionParameter::clear_has_pad_h() {
+  _has_bits_[0] &= ~0x00000008u;
+}
+inline void ConvolutionParameter::clear_pad_h() {
+  pad_h_ = 0u;
+  clear_has_pad_h();
+}
+inline ::google::protobuf::uint32 ConvolutionParameter::pad_h() const {
+  // @@protoc_insertion_point(field_get:caffe.ConvolutionParameter.pad_h)
+  return pad_h_;
+}
+inline void ConvolutionParameter::set_pad_h(::google::protobuf::uint32 value) {
+  set_has_pad_h();
+  pad_h_ = value;
+  // @@protoc_insertion_point(field_set:caffe.ConvolutionParameter.pad_h)
+}
+
+// optional uint32 pad_w = 10 [default = 0];
+inline bool ConvolutionParameter::has_pad_w() const {
+  return (_has_bits_[0] & 0x00000010u) != 0;
+}
+inline void ConvolutionParameter::set_has_pad_w() {
+  _has_bits_[0] |= 0x00000010u;
+}
+inline void ConvolutionParameter::clear_has_pad_w() {
+  _has_bits_[0] &= ~0x00000010u;
+}
+inline void ConvolutionParameter::clear_pad_w() {
+  pad_w_ = 0u;
+  clear_has_pad_w();
+}
+inline ::google::protobuf::uint32 ConvolutionParameter::pad_w() const {
+  // @@protoc_insertion_point(field_get:caffe.ConvolutionParameter.pad_w)
+  return pad_w_;
+}
+inline void ConvolutionParameter::set_pad_w(::google::protobuf::uint32 value) {
+  set_has_pad_w();
+  pad_w_ = value;
+  // @@protoc_insertion_point(field_set:caffe.ConvolutionParameter.pad_w)
+}
+
+// optional uint32 kernel_size = 4;
+inline bool ConvolutionParameter::has_kernel_size() const {
+  return (_has_bits_[0] & 0x00000020u) != 0;
+}
+inline void ConvolutionParameter::set_has_kernel_size() {
+  _has_bits_[0] |= 0x00000020u;
+}
+inline void ConvolutionParameter::clear_has_kernel_size() {
+  _has_bits_[0] &= ~0x00000020u;
+}
+inline void ConvolutionParameter::clear_kernel_size() {
+  kernel_size_ = 0u;
+  clear_has_kernel_size();
+}
+inline ::google::protobuf::uint32 ConvolutionParameter::kernel_size() const {
+  // @@protoc_insertion_point(field_get:caffe.ConvolutionParameter.kernel_size)
+  return kernel_size_;
+}
+inline void ConvolutionParameter::set_kernel_size(::google::protobuf::uint32 value) {
+  set_has_kernel_size();
+  kernel_size_ = value;
+  // @@protoc_insertion_point(field_set:caffe.ConvolutionParameter.kernel_size)
+}
+
+// optional uint32 kernel_h = 11;
+inline bool ConvolutionParameter::has_kernel_h() const {
+  return (_has_bits_[0] & 0x00000040u) != 0;
+}
+inline void ConvolutionParameter::set_has_kernel_h() {
+  _has_bits_[0] |= 0x00000040u;
+}
+inline void ConvolutionParameter::clear_has_kernel_h() {
+  _has_bits_[0] &= ~0x00000040u;
+}
+inline void ConvolutionParameter::clear_kernel_h() {
+  kernel_h_ = 0u;
+  clear_has_kernel_h();
+}
+inline ::google::protobuf::uint32 ConvolutionParameter::kernel_h() const {
+  // @@protoc_insertion_point(field_get:caffe.ConvolutionParameter.kernel_h)
+  return kernel_h_;
+}
+inline void ConvolutionParameter::set_kernel_h(::google::protobuf::uint32 value) {
+  set_has_kernel_h();
+  kernel_h_ = value;
+  // @@protoc_insertion_point(field_set:caffe.ConvolutionParameter.kernel_h)
+}
+
+// optional uint32 kernel_w = 12;
+inline bool ConvolutionParameter::has_kernel_w() const {
+  return (_has_bits_[0] & 0x00000080u) != 0;
+}
+inline void ConvolutionParameter::set_has_kernel_w() {
+  _has_bits_[0] |= 0x00000080u;
+}
+inline void ConvolutionParameter::clear_has_kernel_w() {
+  _has_bits_[0] &= ~0x00000080u;
+}
+inline void ConvolutionParameter::clear_kernel_w() {
+  kernel_w_ = 0u;
+  clear_has_kernel_w();
+}
+inline ::google::protobuf::uint32 ConvolutionParameter::kernel_w() const {
+  // @@protoc_insertion_point(field_get:caffe.ConvolutionParameter.kernel_w)
+  return kernel_w_;
+}
+inline void ConvolutionParameter::set_kernel_w(::google::protobuf::uint32 value) {
+  set_has_kernel_w();
+  kernel_w_ = value;
+  // @@protoc_insertion_point(field_set:caffe.ConvolutionParameter.kernel_w)
+}
+
+// optional uint32 group = 5 [default = 1];
+inline bool ConvolutionParameter::has_group() const {
+  return (_has_bits_[0] & 0x00000100u) != 0;
+}
+inline void ConvolutionParameter::set_has_group() {
+  _has_bits_[0] |= 0x00000100u;
+}
+inline void ConvolutionParameter::clear_has_group() {
+  _has_bits_[0] &= ~0x00000100u;
+}
+inline void ConvolutionParameter::clear_group() {
+  group_ = 1u;
+  clear_has_group();
+}
+inline ::google::protobuf::uint32 ConvolutionParameter::group() const {
+  // @@protoc_insertion_point(field_get:caffe.ConvolutionParameter.group)
+  return group_;
+}
+inline void ConvolutionParameter::set_group(::google::protobuf::uint32 value) {
+  set_has_group();
+  group_ = value;
+  // @@protoc_insertion_point(field_set:caffe.ConvolutionParameter.group)
+}
+
+// optional uint32 stride = 6 [default = 1];
+inline bool ConvolutionParameter::has_stride() const {
+  return (_has_bits_[0] & 0x00000200u) != 0;
+}
+inline void ConvolutionParameter::set_has_stride() {
+  _has_bits_[0] |= 0x00000200u;
+}
+inline void ConvolutionParameter::clear_has_stride() {
+  _has_bits_[0] &= ~0x00000200u;
+}
+inline void ConvolutionParameter::clear_stride() {
+  stride_ = 1u;
+  clear_has_stride();
+}
+inline ::google::protobuf::uint32 ConvolutionParameter::stride() const {
+  // @@protoc_insertion_point(field_get:caffe.ConvolutionParameter.stride)
+  return stride_;
+}
+inline void ConvolutionParameter::set_stride(::google::protobuf::uint32 value) {
+  set_has_stride();
+  stride_ = value;
+  // @@protoc_insertion_point(field_set:caffe.ConvolutionParameter.stride)
+}
+
+// optional uint32 stride_h = 13;
+inline bool ConvolutionParameter::has_stride_h() const {
+  return (_has_bits_[0] & 0x00000400u) != 0;
+}
+inline void ConvolutionParameter::set_has_stride_h() {
+  _has_bits_[0] |= 0x00000400u;
+}
+inline void ConvolutionParameter::clear_has_stride_h() {
+  _has_bits_[0] &= ~0x00000400u;
+}
+inline void ConvolutionParameter::clear_stride_h() {
+  stride_h_ = 0u;
+  clear_has_stride_h();
+}
+inline ::google::protobuf::uint32 ConvolutionParameter::stride_h() const {
+  // @@protoc_insertion_point(field_get:caffe.ConvolutionParameter.stride_h)
+  return stride_h_;
+}
+inline void ConvolutionParameter::set_stride_h(::google::protobuf::uint32 value) {
+  set_has_stride_h();
+  stride_h_ = value;
+  // @@protoc_insertion_point(field_set:caffe.ConvolutionParameter.stride_h)
+}
+
+// optional uint32 stride_w = 14;
+inline bool ConvolutionParameter::has_stride_w() const {
+  return (_has_bits_[0] & 0x00000800u) != 0;
+}
+inline void ConvolutionParameter::set_has_stride_w() {
+  _has_bits_[0] |= 0x00000800u;
+}
+inline void ConvolutionParameter::clear_has_stride_w() {
+  _has_bits_[0] &= ~0x00000800u;
+}
+inline void ConvolutionParameter::clear_stride_w() {
+  stride_w_ = 0u;
+  clear_has_stride_w();
+}
+inline ::google::protobuf::uint32 ConvolutionParameter::stride_w() const {
+  // @@protoc_insertion_point(field_get:caffe.ConvolutionParameter.stride_w)
+  return stride_w_;
+}
+inline void ConvolutionParameter::set_stride_w(::google::protobuf::uint32 value) {
+  set_has_stride_w();
+  stride_w_ = value;
+  // @@protoc_insertion_point(field_set:caffe.ConvolutionParameter.stride_w)
+}
+
+// optional .caffe.FillerParameter weight_filler = 7;
+inline bool ConvolutionParameter::has_weight_filler() const {
+  return (_has_bits_[0] & 0x00001000u) != 0;
+}
+inline void ConvolutionParameter::set_has_weight_filler() {
+  _has_bits_[0] |= 0x00001000u;
+}
+inline void ConvolutionParameter::clear_has_weight_filler() {
+  _has_bits_[0] &= ~0x00001000u;
+}
+inline void ConvolutionParameter::clear_weight_filler() {
+  if (weight_filler_ != NULL) weight_filler_->::caffe::FillerParameter::Clear();
+  clear_has_weight_filler();
+}
+inline const ::caffe::FillerParameter& ConvolutionParameter::weight_filler() const {
+  // @@protoc_insertion_point(field_get:caffe.ConvolutionParameter.weight_filler)
+  return weight_filler_ != NULL ? *weight_filler_
+                         : *::caffe::FillerParameter::internal_default_instance();
+}
+inline ::caffe::FillerParameter* ConvolutionParameter::mutable_weight_filler() {
+  set_has_weight_filler();
+  if (weight_filler_ == NULL) {
+    weight_filler_ = new ::caffe::FillerParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.ConvolutionParameter.weight_filler)
+  return weight_filler_;
+}
+inline ::caffe::FillerParameter* ConvolutionParameter::release_weight_filler() {
+  // @@protoc_insertion_point(field_release:caffe.ConvolutionParameter.weight_filler)
+  clear_has_weight_filler();
+  ::caffe::FillerParameter* temp = weight_filler_;
+  weight_filler_ = NULL;
+  return temp;
+}
+inline void ConvolutionParameter::set_allocated_weight_filler(::caffe::FillerParameter* weight_filler) {
+  delete weight_filler_;
+  weight_filler_ = weight_filler;
+  if (weight_filler) {
+    set_has_weight_filler();
+  } else {
+    clear_has_weight_filler();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.ConvolutionParameter.weight_filler)
+}
+
+// optional .caffe.FillerParameter bias_filler = 8;
+inline bool ConvolutionParameter::has_bias_filler() const {
+  return (_has_bits_[0] & 0x00002000u) != 0;
+}
+inline void ConvolutionParameter::set_has_bias_filler() {
+  _has_bits_[0] |= 0x00002000u;
+}
+inline void ConvolutionParameter::clear_has_bias_filler() {
+  _has_bits_[0] &= ~0x00002000u;
+}
+inline void ConvolutionParameter::clear_bias_filler() {
+  if (bias_filler_ != NULL) bias_filler_->::caffe::FillerParameter::Clear();
+  clear_has_bias_filler();
+}
+inline const ::caffe::FillerParameter& ConvolutionParameter::bias_filler() const {
+  // @@protoc_insertion_point(field_get:caffe.ConvolutionParameter.bias_filler)
+  return bias_filler_ != NULL ? *bias_filler_
+                         : *::caffe::FillerParameter::internal_default_instance();
+}
+inline ::caffe::FillerParameter* ConvolutionParameter::mutable_bias_filler() {
+  set_has_bias_filler();
+  if (bias_filler_ == NULL) {
+    bias_filler_ = new ::caffe::FillerParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.ConvolutionParameter.bias_filler)
+  return bias_filler_;
+}
+inline ::caffe::FillerParameter* ConvolutionParameter::release_bias_filler() {
+  // @@protoc_insertion_point(field_release:caffe.ConvolutionParameter.bias_filler)
+  clear_has_bias_filler();
+  ::caffe::FillerParameter* temp = bias_filler_;
+  bias_filler_ = NULL;
+  return temp;
+}
+inline void ConvolutionParameter::set_allocated_bias_filler(::caffe::FillerParameter* bias_filler) {
+  delete bias_filler_;
+  bias_filler_ = bias_filler;
+  if (bias_filler) {
+    set_has_bias_filler();
+  } else {
+    clear_has_bias_filler();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.ConvolutionParameter.bias_filler)
+}
+
+// optional .caffe.ConvolutionParameter.Engine engine = 15 [default = DEFAULT];
+inline bool ConvolutionParameter::has_engine() const {
+  return (_has_bits_[0] & 0x00004000u) != 0;
+}
+inline void ConvolutionParameter::set_has_engine() {
+  _has_bits_[0] |= 0x00004000u;
+}
+inline void ConvolutionParameter::clear_has_engine() {
+  _has_bits_[0] &= ~0x00004000u;
+}
+inline void ConvolutionParameter::clear_engine() {
+  engine_ = 0;
+  clear_has_engine();
+}
+inline ::caffe::ConvolutionParameter_Engine ConvolutionParameter::engine() const {
+  // @@protoc_insertion_point(field_get:caffe.ConvolutionParameter.engine)
+  return static_cast< ::caffe::ConvolutionParameter_Engine >(engine_);
+}
+inline void ConvolutionParameter::set_engine(::caffe::ConvolutionParameter_Engine value) {
+  assert(::caffe::ConvolutionParameter_Engine_IsValid(value));
+  set_has_engine();
+  engine_ = value;
+  // @@protoc_insertion_point(field_set:caffe.ConvolutionParameter.engine)
+}
+
+// optional uint32 dilation_h = 18;
+inline bool ConvolutionParameter::has_dilation_h() const {
+  return (_has_bits_[0] & 0x00008000u) != 0;
+}
+inline void ConvolutionParameter::set_has_dilation_h() {
+  _has_bits_[0] |= 0x00008000u;
+}
+inline void ConvolutionParameter::clear_has_dilation_h() {
+  _has_bits_[0] &= ~0x00008000u;
+}
+inline void ConvolutionParameter::clear_dilation_h() {
+  dilation_h_ = 0u;
+  clear_has_dilation_h();
+}
+inline ::google::protobuf::uint32 ConvolutionParameter::dilation_h() const {
+  // @@protoc_insertion_point(field_get:caffe.ConvolutionParameter.dilation_h)
+  return dilation_h_;
+}
+inline void ConvolutionParameter::set_dilation_h(::google::protobuf::uint32 value) {
+  set_has_dilation_h();
+  dilation_h_ = value;
+  // @@protoc_insertion_point(field_set:caffe.ConvolutionParameter.dilation_h)
+}
+
+// optional uint32 dilation_w = 19;
+inline bool ConvolutionParameter::has_dilation_w() const {
+  return (_has_bits_[0] & 0x00010000u) != 0;
+}
+inline void ConvolutionParameter::set_has_dilation_w() {
+  _has_bits_[0] |= 0x00010000u;
+}
+inline void ConvolutionParameter::clear_has_dilation_w() {
+  _has_bits_[0] &= ~0x00010000u;
+}
+inline void ConvolutionParameter::clear_dilation_w() {
+  dilation_w_ = 0u;
+  clear_has_dilation_w();
+}
+inline ::google::protobuf::uint32 ConvolutionParameter::dilation_w() const {
+  // @@protoc_insertion_point(field_get:caffe.ConvolutionParameter.dilation_w)
+  return dilation_w_;
+}
+inline void ConvolutionParameter::set_dilation_w(::google::protobuf::uint32 value) {
+  set_has_dilation_w();
+  dilation_w_ = value;
+  // @@protoc_insertion_point(field_set:caffe.ConvolutionParameter.dilation_w)
+}
+
+// optional uint32 dilation = 20;
+inline bool ConvolutionParameter::has_dilation() const {
+  return (_has_bits_[0] & 0x00020000u) != 0;
+}
+inline void ConvolutionParameter::set_has_dilation() {
+  _has_bits_[0] |= 0x00020000u;
+}
+inline void ConvolutionParameter::clear_has_dilation() {
+  _has_bits_[0] &= ~0x00020000u;
+}
+inline void ConvolutionParameter::clear_dilation() {
+  dilation_ = 0u;
+  clear_has_dilation();
+}
+inline ::google::protobuf::uint32 ConvolutionParameter::dilation() const {
+  // @@protoc_insertion_point(field_get:caffe.ConvolutionParameter.dilation)
+  return dilation_;
+}
+inline void ConvolutionParameter::set_dilation(::google::protobuf::uint32 value) {
+  set_has_dilation();
+  dilation_ = value;
+  // @@protoc_insertion_point(field_set:caffe.ConvolutionParameter.dilation)
+}
+
+inline const ConvolutionParameter* ConvolutionParameter::internal_default_instance() {
+  return &ConvolutionParameter_default_instance_.get();
+}
+// -------------------------------------------------------------------
+
+// DataParameter
+
+// optional string source = 1;
+inline bool DataParameter::has_source() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+inline void DataParameter::set_has_source() {
+  _has_bits_[0] |= 0x00000001u;
+}
+inline void DataParameter::clear_has_source() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+inline void DataParameter::clear_source() {
+  source_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  clear_has_source();
+}
+inline const ::std::string& DataParameter::source() const {
+  // @@protoc_insertion_point(field_get:caffe.DataParameter.source)
+  return source_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void DataParameter::set_source(const ::std::string& value) {
+  set_has_source();
+  source_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:caffe.DataParameter.source)
+}
+inline void DataParameter::set_source(const char* value) {
+  set_has_source();
+  source_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:caffe.DataParameter.source)
+}
+inline void DataParameter::set_source(const char* value, size_t size) {
+  set_has_source();
+  source_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:caffe.DataParameter.source)
+}
+inline ::std::string* DataParameter::mutable_source() {
+  set_has_source();
+  // @@protoc_insertion_point(field_mutable:caffe.DataParameter.source)
+  return source_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline ::std::string* DataParameter::release_source() {
+  // @@protoc_insertion_point(field_release:caffe.DataParameter.source)
+  clear_has_source();
+  return source_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void DataParameter::set_allocated_source(::std::string* source) {
+  if (source != NULL) {
+    set_has_source();
+  } else {
+    clear_has_source();
+  }
+  source_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), source);
+  // @@protoc_insertion_point(field_set_allocated:caffe.DataParameter.source)
+}
+
+// optional uint32 batch_size = 4;
+inline bool DataParameter::has_batch_size() const {
+  return (_has_bits_[0] & 0x00000002u) != 0;
+}
+inline void DataParameter::set_has_batch_size() {
+  _has_bits_[0] |= 0x00000002u;
+}
+inline void DataParameter::clear_has_batch_size() {
+  _has_bits_[0] &= ~0x00000002u;
+}
+inline void DataParameter::clear_batch_size() {
+  batch_size_ = 0u;
+  clear_has_batch_size();
+}
+inline ::google::protobuf::uint32 DataParameter::batch_size() const {
+  // @@protoc_insertion_point(field_get:caffe.DataParameter.batch_size)
+  return batch_size_;
+}
+inline void DataParameter::set_batch_size(::google::protobuf::uint32 value) {
+  set_has_batch_size();
+  batch_size_ = value;
+  // @@protoc_insertion_point(field_set:caffe.DataParameter.batch_size)
+}
+
+// optional uint32 rand_skip = 7 [default = 0];
+inline bool DataParameter::has_rand_skip() const {
+  return (_has_bits_[0] & 0x00000004u) != 0;
+}
+inline void DataParameter::set_has_rand_skip() {
+  _has_bits_[0] |= 0x00000004u;
+}
+inline void DataParameter::clear_has_rand_skip() {
+  _has_bits_[0] &= ~0x00000004u;
+}
+inline void DataParameter::clear_rand_skip() {
+  rand_skip_ = 0u;
+  clear_has_rand_skip();
+}
+inline ::google::protobuf::uint32 DataParameter::rand_skip() const {
+  // @@protoc_insertion_point(field_get:caffe.DataParameter.rand_skip)
+  return rand_skip_;
+}
+inline void DataParameter::set_rand_skip(::google::protobuf::uint32 value) {
+  set_has_rand_skip();
+  rand_skip_ = value;
+  // @@protoc_insertion_point(field_set:caffe.DataParameter.rand_skip)
+}
+
+// optional .caffe.DataParameter.DB backend = 8 [default = LEVELDB];
+inline bool DataParameter::has_backend() const {
+  return (_has_bits_[0] & 0x00000008u) != 0;
+}
+inline void DataParameter::set_has_backend() {
+  _has_bits_[0] |= 0x00000008u;
+}
+inline void DataParameter::clear_has_backend() {
+  _has_bits_[0] &= ~0x00000008u;
+}
+inline void DataParameter::clear_backend() {
+  backend_ = 0;
+  clear_has_backend();
+}
+inline ::caffe::DataParameter_DB DataParameter::backend() const {
+  // @@protoc_insertion_point(field_get:caffe.DataParameter.backend)
+  return static_cast< ::caffe::DataParameter_DB >(backend_);
+}
+inline void DataParameter::set_backend(::caffe::DataParameter_DB value) {
+  assert(::caffe::DataParameter_DB_IsValid(value));
+  set_has_backend();
+  backend_ = value;
+  // @@protoc_insertion_point(field_set:caffe.DataParameter.backend)
+}
+
+// optional float scale = 2 [default = 1];
+inline bool DataParameter::has_scale() const {
+  return (_has_bits_[0] & 0x00000010u) != 0;
+}
+inline void DataParameter::set_has_scale() {
+  _has_bits_[0] |= 0x00000010u;
+}
+inline void DataParameter::clear_has_scale() {
+  _has_bits_[0] &= ~0x00000010u;
+}
+inline void DataParameter::clear_scale() {
+  scale_ = 1;
+  clear_has_scale();
+}
+inline float DataParameter::scale() const {
+  // @@protoc_insertion_point(field_get:caffe.DataParameter.scale)
+  return scale_;
+}
+inline void DataParameter::set_scale(float value) {
+  set_has_scale();
+  scale_ = value;
+  // @@protoc_insertion_point(field_set:caffe.DataParameter.scale)
+}
+
+// optional string mean_file = 3;
+inline bool DataParameter::has_mean_file() const {
+  return (_has_bits_[0] & 0x00000020u) != 0;
+}
+inline void DataParameter::set_has_mean_file() {
+  _has_bits_[0] |= 0x00000020u;
+}
+inline void DataParameter::clear_has_mean_file() {
+  _has_bits_[0] &= ~0x00000020u;
+}
+inline void DataParameter::clear_mean_file() {
+  mean_file_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  clear_has_mean_file();
+}
+inline const ::std::string& DataParameter::mean_file() const {
+  // @@protoc_insertion_point(field_get:caffe.DataParameter.mean_file)
+  return mean_file_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void DataParameter::set_mean_file(const ::std::string& value) {
+  set_has_mean_file();
+  mean_file_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:caffe.DataParameter.mean_file)
+}
+inline void DataParameter::set_mean_file(const char* value) {
+  set_has_mean_file();
+  mean_file_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:caffe.DataParameter.mean_file)
+}
+inline void DataParameter::set_mean_file(const char* value, size_t size) {
+  set_has_mean_file();
+  mean_file_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:caffe.DataParameter.mean_file)
+}
+inline ::std::string* DataParameter::mutable_mean_file() {
+  set_has_mean_file();
+  // @@protoc_insertion_point(field_mutable:caffe.DataParameter.mean_file)
+  return mean_file_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline ::std::string* DataParameter::release_mean_file() {
+  // @@protoc_insertion_point(field_release:caffe.DataParameter.mean_file)
+  clear_has_mean_file();
+  return mean_file_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void DataParameter::set_allocated_mean_file(::std::string* mean_file) {
+  if (mean_file != NULL) {
+    set_has_mean_file();
+  } else {
+    clear_has_mean_file();
+  }
+  mean_file_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), mean_file);
+  // @@protoc_insertion_point(field_set_allocated:caffe.DataParameter.mean_file)
+}
+
+// optional uint32 crop_size = 5 [default = 0];
+inline bool DataParameter::has_crop_size() const {
+  return (_has_bits_[0] & 0x00000040u) != 0;
+}
+inline void DataParameter::set_has_crop_size() {
+  _has_bits_[0] |= 0x00000040u;
+}
+inline void DataParameter::clear_has_crop_size() {
+  _has_bits_[0] &= ~0x00000040u;
+}
+inline void DataParameter::clear_crop_size() {
+  crop_size_ = 0u;
+  clear_has_crop_size();
+}
+inline ::google::protobuf::uint32 DataParameter::crop_size() const {
+  // @@protoc_insertion_point(field_get:caffe.DataParameter.crop_size)
+  return crop_size_;
+}
+inline void DataParameter::set_crop_size(::google::protobuf::uint32 value) {
+  set_has_crop_size();
+  crop_size_ = value;
+  // @@protoc_insertion_point(field_set:caffe.DataParameter.crop_size)
+}
+
+// optional bool mirror = 6 [default = false];
+inline bool DataParameter::has_mirror() const {
+  return (_has_bits_[0] & 0x00000080u) != 0;
+}
+inline void DataParameter::set_has_mirror() {
+  _has_bits_[0] |= 0x00000080u;
+}
+inline void DataParameter::clear_has_mirror() {
+  _has_bits_[0] &= ~0x00000080u;
+}
+inline void DataParameter::clear_mirror() {
+  mirror_ = false;
+  clear_has_mirror();
+}
+inline bool DataParameter::mirror() const {
+  // @@protoc_insertion_point(field_get:caffe.DataParameter.mirror)
+  return mirror_;
+}
+inline void DataParameter::set_mirror(bool value) {
+  set_has_mirror();
+  mirror_ = value;
+  // @@protoc_insertion_point(field_set:caffe.DataParameter.mirror)
+}
+
+// optional bool force_encoded_color = 9 [default = false];
+inline bool DataParameter::has_force_encoded_color() const {
+  return (_has_bits_[0] & 0x00000100u) != 0;
+}
+inline void DataParameter::set_has_force_encoded_color() {
+  _has_bits_[0] |= 0x00000100u;
+}
+inline void DataParameter::clear_has_force_encoded_color() {
+  _has_bits_[0] &= ~0x00000100u;
+}
+inline void DataParameter::clear_force_encoded_color() {
+  force_encoded_color_ = false;
+  clear_has_force_encoded_color();
+}
+inline bool DataParameter::force_encoded_color() const {
+  // @@protoc_insertion_point(field_get:caffe.DataParameter.force_encoded_color)
+  return force_encoded_color_;
+}
+inline void DataParameter::set_force_encoded_color(bool value) {
+  set_has_force_encoded_color();
+  force_encoded_color_ = value;
+  // @@protoc_insertion_point(field_set:caffe.DataParameter.force_encoded_color)
+}
+
+inline const DataParameter* DataParameter::internal_default_instance() {
+  return &DataParameter_default_instance_.get();
+}
+// -------------------------------------------------------------------
+
+// DropoutParameter
+
+// optional float dropout_ratio = 1 [default = 0.5];
+inline bool DropoutParameter::has_dropout_ratio() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+inline void DropoutParameter::set_has_dropout_ratio() {
+  _has_bits_[0] |= 0x00000001u;
+}
+inline void DropoutParameter::clear_has_dropout_ratio() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+inline void DropoutParameter::clear_dropout_ratio() {
+  dropout_ratio_ = 0.5f;
+  clear_has_dropout_ratio();
+}
+inline float DropoutParameter::dropout_ratio() const {
+  // @@protoc_insertion_point(field_get:caffe.DropoutParameter.dropout_ratio)
+  return dropout_ratio_;
+}
+inline void DropoutParameter::set_dropout_ratio(float value) {
+  set_has_dropout_ratio();
+  dropout_ratio_ = value;
+  // @@protoc_insertion_point(field_set:caffe.DropoutParameter.dropout_ratio)
+}
+
+inline const DropoutParameter* DropoutParameter::internal_default_instance() {
+  return &DropoutParameter_default_instance_.get();
+}
+// -------------------------------------------------------------------
+
+// DummyDataParameter
+
+// repeated .caffe.FillerParameter data_filler = 1;
+inline int DummyDataParameter::data_filler_size() const {
+  return data_filler_.size();
+}
+inline void DummyDataParameter::clear_data_filler() {
+  data_filler_.Clear();
+}
+inline const ::caffe::FillerParameter& DummyDataParameter::data_filler(int index) const {
+  // @@protoc_insertion_point(field_get:caffe.DummyDataParameter.data_filler)
+  return data_filler_.Get(index);
+}
+inline ::caffe::FillerParameter* DummyDataParameter::mutable_data_filler(int index) {
+  // @@protoc_insertion_point(field_mutable:caffe.DummyDataParameter.data_filler)
+  return data_filler_.Mutable(index);
+}
+inline ::caffe::FillerParameter* DummyDataParameter::add_data_filler() {
+  // @@protoc_insertion_point(field_add:caffe.DummyDataParameter.data_filler)
+  return data_filler_.Add();
+}
+inline ::google::protobuf::RepeatedPtrField< ::caffe::FillerParameter >*
+DummyDataParameter::mutable_data_filler() {
+  // @@protoc_insertion_point(field_mutable_list:caffe.DummyDataParameter.data_filler)
+  return &data_filler_;
+}
+inline const ::google::protobuf::RepeatedPtrField< ::caffe::FillerParameter >&
+DummyDataParameter::data_filler() const {
+  // @@protoc_insertion_point(field_list:caffe.DummyDataParameter.data_filler)
+  return data_filler_;
+}
+
+// repeated .caffe.BlobShape shape = 6;
+inline int DummyDataParameter::shape_size() const {
+  return shape_.size();
+}
+inline void DummyDataParameter::clear_shape() {
+  shape_.Clear();
+}
+inline const ::caffe::BlobShape& DummyDataParameter::shape(int index) const {
+  // @@protoc_insertion_point(field_get:caffe.DummyDataParameter.shape)
+  return shape_.Get(index);
+}
+inline ::caffe::BlobShape* DummyDataParameter::mutable_shape(int index) {
+  // @@protoc_insertion_point(field_mutable:caffe.DummyDataParameter.shape)
+  return shape_.Mutable(index);
+}
+inline ::caffe::BlobShape* DummyDataParameter::add_shape() {
+  // @@protoc_insertion_point(field_add:caffe.DummyDataParameter.shape)
+  return shape_.Add();
+}
+inline ::google::protobuf::RepeatedPtrField< ::caffe::BlobShape >*
+DummyDataParameter::mutable_shape() {
+  // @@protoc_insertion_point(field_mutable_list:caffe.DummyDataParameter.shape)
+  return &shape_;
+}
+inline const ::google::protobuf::RepeatedPtrField< ::caffe::BlobShape >&
+DummyDataParameter::shape() const {
+  // @@protoc_insertion_point(field_list:caffe.DummyDataParameter.shape)
+  return shape_;
+}
+
+// repeated uint32 num = 2;
+inline int DummyDataParameter::num_size() const {
+  return num_.size();
+}
+inline void DummyDataParameter::clear_num() {
+  num_.Clear();
+}
+inline ::google::protobuf::uint32 DummyDataParameter::num(int index) const {
+  // @@protoc_insertion_point(field_get:caffe.DummyDataParameter.num)
+  return num_.Get(index);
+}
+inline void DummyDataParameter::set_num(int index, ::google::protobuf::uint32 value) {
+  num_.Set(index, value);
+  // @@protoc_insertion_point(field_set:caffe.DummyDataParameter.num)
+}
+inline void DummyDataParameter::add_num(::google::protobuf::uint32 value) {
+  num_.Add(value);
+  // @@protoc_insertion_point(field_add:caffe.DummyDataParameter.num)
+}
+inline const ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >&
+DummyDataParameter::num() const {
+  // @@protoc_insertion_point(field_list:caffe.DummyDataParameter.num)
+  return num_;
+}
+inline ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >*
+DummyDataParameter::mutable_num() {
+  // @@protoc_insertion_point(field_mutable_list:caffe.DummyDataParameter.num)
+  return &num_;
+}
+
+// repeated uint32 channels = 3;
+inline int DummyDataParameter::channels_size() const {
+  return channels_.size();
+}
+inline void DummyDataParameter::clear_channels() {
+  channels_.Clear();
+}
+inline ::google::protobuf::uint32 DummyDataParameter::channels(int index) const {
+  // @@protoc_insertion_point(field_get:caffe.DummyDataParameter.channels)
+  return channels_.Get(index);
+}
+inline void DummyDataParameter::set_channels(int index, ::google::protobuf::uint32 value) {
+  channels_.Set(index, value);
+  // @@protoc_insertion_point(field_set:caffe.DummyDataParameter.channels)
+}
+inline void DummyDataParameter::add_channels(::google::protobuf::uint32 value) {
+  channels_.Add(value);
+  // @@protoc_insertion_point(field_add:caffe.DummyDataParameter.channels)
+}
+inline const ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >&
+DummyDataParameter::channels() const {
+  // @@protoc_insertion_point(field_list:caffe.DummyDataParameter.channels)
+  return channels_;
+}
+inline ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >*
+DummyDataParameter::mutable_channels() {
+  // @@protoc_insertion_point(field_mutable_list:caffe.DummyDataParameter.channels)
+  return &channels_;
+}
+
+// repeated uint32 height = 4;
+inline int DummyDataParameter::height_size() const {
+  return height_.size();
+}
+inline void DummyDataParameter::clear_height() {
+  height_.Clear();
+}
+inline ::google::protobuf::uint32 DummyDataParameter::height(int index) const {
+  // @@protoc_insertion_point(field_get:caffe.DummyDataParameter.height)
+  return height_.Get(index);
+}
+inline void DummyDataParameter::set_height(int index, ::google::protobuf::uint32 value) {
+  height_.Set(index, value);
+  // @@protoc_insertion_point(field_set:caffe.DummyDataParameter.height)
+}
+inline void DummyDataParameter::add_height(::google::protobuf::uint32 value) {
+  height_.Add(value);
+  // @@protoc_insertion_point(field_add:caffe.DummyDataParameter.height)
+}
+inline const ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >&
+DummyDataParameter::height() const {
+  // @@protoc_insertion_point(field_list:caffe.DummyDataParameter.height)
+  return height_;
+}
+inline ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >*
+DummyDataParameter::mutable_height() {
+  // @@protoc_insertion_point(field_mutable_list:caffe.DummyDataParameter.height)
+  return &height_;
+}
+
+// repeated uint32 width = 5;
+inline int DummyDataParameter::width_size() const {
+  return width_.size();
+}
+inline void DummyDataParameter::clear_width() {
+  width_.Clear();
+}
+inline ::google::protobuf::uint32 DummyDataParameter::width(int index) const {
+  // @@protoc_insertion_point(field_get:caffe.DummyDataParameter.width)
+  return width_.Get(index);
+}
+inline void DummyDataParameter::set_width(int index, ::google::protobuf::uint32 value) {
+  width_.Set(index, value);
+  // @@protoc_insertion_point(field_set:caffe.DummyDataParameter.width)
+}
+inline void DummyDataParameter::add_width(::google::protobuf::uint32 value) {
+  width_.Add(value);
+  // @@protoc_insertion_point(field_add:caffe.DummyDataParameter.width)
+}
+inline const ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >&
+DummyDataParameter::width() const {
+  // @@protoc_insertion_point(field_list:caffe.DummyDataParameter.width)
+  return width_;
+}
+inline ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >*
+DummyDataParameter::mutable_width() {
+  // @@protoc_insertion_point(field_mutable_list:caffe.DummyDataParameter.width)
+  return &width_;
+}
+
+inline const DummyDataParameter* DummyDataParameter::internal_default_instance() {
+  return &DummyDataParameter_default_instance_.get();
+}
+// -------------------------------------------------------------------
+
+// EltwiseParameter
+
+// optional .caffe.EltwiseParameter.EltwiseOp operation = 1 [default = SUM];
+inline bool EltwiseParameter::has_operation() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+inline void EltwiseParameter::set_has_operation() {
+  _has_bits_[0] |= 0x00000001u;
+}
+inline void EltwiseParameter::clear_has_operation() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+inline void EltwiseParameter::clear_operation() {
+  operation_ = 1;
+  clear_has_operation();
+}
+inline ::caffe::EltwiseParameter_EltwiseOp EltwiseParameter::operation() const {
+  // @@protoc_insertion_point(field_get:caffe.EltwiseParameter.operation)
+  return static_cast< ::caffe::EltwiseParameter_EltwiseOp >(operation_);
+}
+inline void EltwiseParameter::set_operation(::caffe::EltwiseParameter_EltwiseOp value) {
+  assert(::caffe::EltwiseParameter_EltwiseOp_IsValid(value));
+  set_has_operation();
+  operation_ = value;
+  // @@protoc_insertion_point(field_set:caffe.EltwiseParameter.operation)
+}
+
+// repeated float coeff = 2;
+inline int EltwiseParameter::coeff_size() const {
+  return coeff_.size();
+}
+inline void EltwiseParameter::clear_coeff() {
+  coeff_.Clear();
+}
+inline float EltwiseParameter::coeff(int index) const {
+  // @@protoc_insertion_point(field_get:caffe.EltwiseParameter.coeff)
+  return coeff_.Get(index);
+}
+inline void EltwiseParameter::set_coeff(int index, float value) {
+  coeff_.Set(index, value);
+  // @@protoc_insertion_point(field_set:caffe.EltwiseParameter.coeff)
+}
+inline void EltwiseParameter::add_coeff(float value) {
+  coeff_.Add(value);
+  // @@protoc_insertion_point(field_add:caffe.EltwiseParameter.coeff)
+}
+inline const ::google::protobuf::RepeatedField< float >&
+EltwiseParameter::coeff() const {
+  // @@protoc_insertion_point(field_list:caffe.EltwiseParameter.coeff)
+  return coeff_;
+}
+inline ::google::protobuf::RepeatedField< float >*
+EltwiseParameter::mutable_coeff() {
+  // @@protoc_insertion_point(field_mutable_list:caffe.EltwiseParameter.coeff)
+  return &coeff_;
+}
+
+// optional bool stable_prod_grad = 3 [default = true];
+inline bool EltwiseParameter::has_stable_prod_grad() const {
+  return (_has_bits_[0] & 0x00000004u) != 0;
+}
+inline void EltwiseParameter::set_has_stable_prod_grad() {
+  _has_bits_[0] |= 0x00000004u;
+}
+inline void EltwiseParameter::clear_has_stable_prod_grad() {
+  _has_bits_[0] &= ~0x00000004u;
+}
+inline void EltwiseParameter::clear_stable_prod_grad() {
+  stable_prod_grad_ = true;
+  clear_has_stable_prod_grad();
+}
+inline bool EltwiseParameter::stable_prod_grad() const {
+  // @@protoc_insertion_point(field_get:caffe.EltwiseParameter.stable_prod_grad)
+  return stable_prod_grad_;
+}
+inline void EltwiseParameter::set_stable_prod_grad(bool value) {
+  set_has_stable_prod_grad();
+  stable_prod_grad_ = value;
+  // @@protoc_insertion_point(field_set:caffe.EltwiseParameter.stable_prod_grad)
+}
+
+inline const EltwiseParameter* EltwiseParameter::internal_default_instance() {
+  return &EltwiseParameter_default_instance_.get();
+}
+// -------------------------------------------------------------------
+
+// ExpParameter
+
+// optional float base = 1 [default = -1];
+inline bool ExpParameter::has_base() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+inline void ExpParameter::set_has_base() {
+  _has_bits_[0] |= 0x00000001u;
+}
+inline void ExpParameter::clear_has_base() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+inline void ExpParameter::clear_base() {
+  base_ = -1;
+  clear_has_base();
+}
+inline float ExpParameter::base() const {
+  // @@protoc_insertion_point(field_get:caffe.ExpParameter.base)
+  return base_;
+}
+inline void ExpParameter::set_base(float value) {
+  set_has_base();
+  base_ = value;
+  // @@protoc_insertion_point(field_set:caffe.ExpParameter.base)
+}
+
+// optional float scale = 2 [default = 1];
+inline bool ExpParameter::has_scale() const {
+  return (_has_bits_[0] & 0x00000002u) != 0;
+}
+inline void ExpParameter::set_has_scale() {
+  _has_bits_[0] |= 0x00000002u;
+}
+inline void ExpParameter::clear_has_scale() {
+  _has_bits_[0] &= ~0x00000002u;
+}
+inline void ExpParameter::clear_scale() {
+  scale_ = 1;
+  clear_has_scale();
+}
+inline float ExpParameter::scale() const {
+  // @@protoc_insertion_point(field_get:caffe.ExpParameter.scale)
+  return scale_;
+}
+inline void ExpParameter::set_scale(float value) {
+  set_has_scale();
+  scale_ = value;
+  // @@protoc_insertion_point(field_set:caffe.ExpParameter.scale)
+}
+
+// optional float shift = 3 [default = 0];
+inline bool ExpParameter::has_shift() const {
+  return (_has_bits_[0] & 0x00000004u) != 0;
+}
+inline void ExpParameter::set_has_shift() {
+  _has_bits_[0] |= 0x00000004u;
+}
+inline void ExpParameter::clear_has_shift() {
+  _has_bits_[0] &= ~0x00000004u;
+}
+inline void ExpParameter::clear_shift() {
+  shift_ = 0;
+  clear_has_shift();
+}
+inline float ExpParameter::shift() const {
+  // @@protoc_insertion_point(field_get:caffe.ExpParameter.shift)
+  return shift_;
+}
+inline void ExpParameter::set_shift(float value) {
+  set_has_shift();
+  shift_ = value;
+  // @@protoc_insertion_point(field_set:caffe.ExpParameter.shift)
+}
+
+inline const ExpParameter* ExpParameter::internal_default_instance() {
+  return &ExpParameter_default_instance_.get();
+}
+// -------------------------------------------------------------------
+
+// FlattenParameter
+
+// optional int32 axis = 1 [default = 1];
+inline bool FlattenParameter::has_axis() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+inline void FlattenParameter::set_has_axis() {
+  _has_bits_[0] |= 0x00000001u;
+}
+inline void FlattenParameter::clear_has_axis() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+inline void FlattenParameter::clear_axis() {
+  axis_ = 1;
+  clear_has_axis();
+}
+inline ::google::protobuf::int32 FlattenParameter::axis() const {
+  // @@protoc_insertion_point(field_get:caffe.FlattenParameter.axis)
+  return axis_;
+}
+inline void FlattenParameter::set_axis(::google::protobuf::int32 value) {
+  set_has_axis();
+  axis_ = value;
+  // @@protoc_insertion_point(field_set:caffe.FlattenParameter.axis)
+}
+
+// optional int32 end_axis = 2 [default = -1];
+inline bool FlattenParameter::has_end_axis() const {
+  return (_has_bits_[0] & 0x00000002u) != 0;
+}
+inline void FlattenParameter::set_has_end_axis() {
+  _has_bits_[0] |= 0x00000002u;
+}
+inline void FlattenParameter::clear_has_end_axis() {
+  _has_bits_[0] &= ~0x00000002u;
+}
+inline void FlattenParameter::clear_end_axis() {
+  end_axis_ = -1;
+  clear_has_end_axis();
+}
+inline ::google::protobuf::int32 FlattenParameter::end_axis() const {
+  // @@protoc_insertion_point(field_get:caffe.FlattenParameter.end_axis)
+  return end_axis_;
+}
+inline void FlattenParameter::set_end_axis(::google::protobuf::int32 value) {
+  set_has_end_axis();
+  end_axis_ = value;
+  // @@protoc_insertion_point(field_set:caffe.FlattenParameter.end_axis)
+}
+
+inline const FlattenParameter* FlattenParameter::internal_default_instance() {
+  return &FlattenParameter_default_instance_.get();
+}
+// -------------------------------------------------------------------
+
+// HDF5DataParameter
+
+// optional string source = 1;
+inline bool HDF5DataParameter::has_source() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+inline void HDF5DataParameter::set_has_source() {
+  _has_bits_[0] |= 0x00000001u;
+}
+inline void HDF5DataParameter::clear_has_source() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+inline void HDF5DataParameter::clear_source() {
+  source_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  clear_has_source();
+}
+inline const ::std::string& HDF5DataParameter::source() const {
+  // @@protoc_insertion_point(field_get:caffe.HDF5DataParameter.source)
+  return source_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void HDF5DataParameter::set_source(const ::std::string& value) {
+  set_has_source();
+  source_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:caffe.HDF5DataParameter.source)
+}
+inline void HDF5DataParameter::set_source(const char* value) {
+  set_has_source();
+  source_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:caffe.HDF5DataParameter.source)
+}
+inline void HDF5DataParameter::set_source(const char* value, size_t size) {
+  set_has_source();
+  source_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:caffe.HDF5DataParameter.source)
+}
+inline ::std::string* HDF5DataParameter::mutable_source() {
+  set_has_source();
+  // @@protoc_insertion_point(field_mutable:caffe.HDF5DataParameter.source)
+  return source_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline ::std::string* HDF5DataParameter::release_source() {
+  // @@protoc_insertion_point(field_release:caffe.HDF5DataParameter.source)
+  clear_has_source();
+  return source_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void HDF5DataParameter::set_allocated_source(::std::string* source) {
+  if (source != NULL) {
+    set_has_source();
+  } else {
+    clear_has_source();
+  }
+  source_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), source);
+  // @@protoc_insertion_point(field_set_allocated:caffe.HDF5DataParameter.source)
+}
+
+// optional uint32 batch_size = 2;
+inline bool HDF5DataParameter::has_batch_size() const {
+  return (_has_bits_[0] & 0x00000002u) != 0;
+}
+inline void HDF5DataParameter::set_has_batch_size() {
+  _has_bits_[0] |= 0x00000002u;
+}
+inline void HDF5DataParameter::clear_has_batch_size() {
+  _has_bits_[0] &= ~0x00000002u;
+}
+inline void HDF5DataParameter::clear_batch_size() {
+  batch_size_ = 0u;
+  clear_has_batch_size();
+}
+inline ::google::protobuf::uint32 HDF5DataParameter::batch_size() const {
+  // @@protoc_insertion_point(field_get:caffe.HDF5DataParameter.batch_size)
+  return batch_size_;
+}
+inline void HDF5DataParameter::set_batch_size(::google::protobuf::uint32 value) {
+  set_has_batch_size();
+  batch_size_ = value;
+  // @@protoc_insertion_point(field_set:caffe.HDF5DataParameter.batch_size)
+}
+
+// optional bool shuffle = 3 [default = false];
+inline bool HDF5DataParameter::has_shuffle() const {
+  return (_has_bits_[0] & 0x00000004u) != 0;
+}
+inline void HDF5DataParameter::set_has_shuffle() {
+  _has_bits_[0] |= 0x00000004u;
+}
+inline void HDF5DataParameter::clear_has_shuffle() {
+  _has_bits_[0] &= ~0x00000004u;
+}
+inline void HDF5DataParameter::clear_shuffle() {
+  shuffle_ = false;
+  clear_has_shuffle();
+}
+inline bool HDF5DataParameter::shuffle() const {
+  // @@protoc_insertion_point(field_get:caffe.HDF5DataParameter.shuffle)
+  return shuffle_;
+}
+inline void HDF5DataParameter::set_shuffle(bool value) {
+  set_has_shuffle();
+  shuffle_ = value;
+  // @@protoc_insertion_point(field_set:caffe.HDF5DataParameter.shuffle)
+}
+
+inline const HDF5DataParameter* HDF5DataParameter::internal_default_instance() {
+  return &HDF5DataParameter_default_instance_.get();
+}
+// -------------------------------------------------------------------
+
+// HDF5OutputParameter
+
+// optional string file_name = 1;
+inline bool HDF5OutputParameter::has_file_name() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+inline void HDF5OutputParameter::set_has_file_name() {
+  _has_bits_[0] |= 0x00000001u;
+}
+inline void HDF5OutputParameter::clear_has_file_name() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+inline void HDF5OutputParameter::clear_file_name() {
+  file_name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  clear_has_file_name();
+}
+inline const ::std::string& HDF5OutputParameter::file_name() const {
+  // @@protoc_insertion_point(field_get:caffe.HDF5OutputParameter.file_name)
+  return file_name_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void HDF5OutputParameter::set_file_name(const ::std::string& value) {
+  set_has_file_name();
+  file_name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:caffe.HDF5OutputParameter.file_name)
+}
+inline void HDF5OutputParameter::set_file_name(const char* value) {
+  set_has_file_name();
+  file_name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:caffe.HDF5OutputParameter.file_name)
+}
+inline void HDF5OutputParameter::set_file_name(const char* value, size_t size) {
+  set_has_file_name();
+  file_name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:caffe.HDF5OutputParameter.file_name)
+}
+inline ::std::string* HDF5OutputParameter::mutable_file_name() {
+  set_has_file_name();
+  // @@protoc_insertion_point(field_mutable:caffe.HDF5OutputParameter.file_name)
+  return file_name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline ::std::string* HDF5OutputParameter::release_file_name() {
+  // @@protoc_insertion_point(field_release:caffe.HDF5OutputParameter.file_name)
+  clear_has_file_name();
+  return file_name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void HDF5OutputParameter::set_allocated_file_name(::std::string* file_name) {
+  if (file_name != NULL) {
+    set_has_file_name();
+  } else {
+    clear_has_file_name();
+  }
+  file_name_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), file_name);
+  // @@protoc_insertion_point(field_set_allocated:caffe.HDF5OutputParameter.file_name)
+}
+
+inline const HDF5OutputParameter* HDF5OutputParameter::internal_default_instance() {
+  return &HDF5OutputParameter_default_instance_.get();
+}
+// -------------------------------------------------------------------
+
+// HingeLossParameter
+
+// optional .caffe.HingeLossParameter.Norm norm = 1 [default = L1];
+inline bool HingeLossParameter::has_norm() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+inline void HingeLossParameter::set_has_norm() {
+  _has_bits_[0] |= 0x00000001u;
+}
+inline void HingeLossParameter::clear_has_norm() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+inline void HingeLossParameter::clear_norm() {
+  norm_ = 1;
+  clear_has_norm();
+}
+inline ::caffe::HingeLossParameter_Norm HingeLossParameter::norm() const {
+  // @@protoc_insertion_point(field_get:caffe.HingeLossParameter.norm)
+  return static_cast< ::caffe::HingeLossParameter_Norm >(norm_);
+}
+inline void HingeLossParameter::set_norm(::caffe::HingeLossParameter_Norm value) {
+  assert(::caffe::HingeLossParameter_Norm_IsValid(value));
+  set_has_norm();
+  norm_ = value;
+  // @@protoc_insertion_point(field_set:caffe.HingeLossParameter.norm)
+}
+
+inline const HingeLossParameter* HingeLossParameter::internal_default_instance() {
+  return &HingeLossParameter_default_instance_.get();
+}
+// -------------------------------------------------------------------
+
+// ImageDataParameter
+
+// optional string source = 1;
+inline bool ImageDataParameter::has_source() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+inline void ImageDataParameter::set_has_source() {
+  _has_bits_[0] |= 0x00000001u;
+}
+inline void ImageDataParameter::clear_has_source() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+inline void ImageDataParameter::clear_source() {
+  source_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  clear_has_source();
+}
+inline const ::std::string& ImageDataParameter::source() const {
+  // @@protoc_insertion_point(field_get:caffe.ImageDataParameter.source)
+  return source_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void ImageDataParameter::set_source(const ::std::string& value) {
+  set_has_source();
+  source_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:caffe.ImageDataParameter.source)
+}
+inline void ImageDataParameter::set_source(const char* value) {
+  set_has_source();
+  source_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:caffe.ImageDataParameter.source)
+}
+inline void ImageDataParameter::set_source(const char* value, size_t size) {
+  set_has_source();
+  source_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:caffe.ImageDataParameter.source)
+}
+inline ::std::string* ImageDataParameter::mutable_source() {
+  set_has_source();
+  // @@protoc_insertion_point(field_mutable:caffe.ImageDataParameter.source)
+  return source_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline ::std::string* ImageDataParameter::release_source() {
+  // @@protoc_insertion_point(field_release:caffe.ImageDataParameter.source)
+  clear_has_source();
+  return source_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void ImageDataParameter::set_allocated_source(::std::string* source) {
+  if (source != NULL) {
+    set_has_source();
+  } else {
+    clear_has_source();
+  }
+  source_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), source);
+  // @@protoc_insertion_point(field_set_allocated:caffe.ImageDataParameter.source)
+}
+
+// optional uint32 batch_size = 4;
+inline bool ImageDataParameter::has_batch_size() const {
+  return (_has_bits_[0] & 0x00000002u) != 0;
+}
+inline void ImageDataParameter::set_has_batch_size() {
+  _has_bits_[0] |= 0x00000002u;
+}
+inline void ImageDataParameter::clear_has_batch_size() {
+  _has_bits_[0] &= ~0x00000002u;
+}
+inline void ImageDataParameter::clear_batch_size() {
+  batch_size_ = 0u;
+  clear_has_batch_size();
+}
+inline ::google::protobuf::uint32 ImageDataParameter::batch_size() const {
+  // @@protoc_insertion_point(field_get:caffe.ImageDataParameter.batch_size)
+  return batch_size_;
+}
+inline void ImageDataParameter::set_batch_size(::google::protobuf::uint32 value) {
+  set_has_batch_size();
+  batch_size_ = value;
+  // @@protoc_insertion_point(field_set:caffe.ImageDataParameter.batch_size)
+}
+
+// optional uint32 rand_skip = 7 [default = 0];
+inline bool ImageDataParameter::has_rand_skip() const {
+  return (_has_bits_[0] & 0x00000004u) != 0;
+}
+inline void ImageDataParameter::set_has_rand_skip() {
+  _has_bits_[0] |= 0x00000004u;
+}
+inline void ImageDataParameter::clear_has_rand_skip() {
+  _has_bits_[0] &= ~0x00000004u;
+}
+inline void ImageDataParameter::clear_rand_skip() {
+  rand_skip_ = 0u;
+  clear_has_rand_skip();
+}
+inline ::google::protobuf::uint32 ImageDataParameter::rand_skip() const {
+  // @@protoc_insertion_point(field_get:caffe.ImageDataParameter.rand_skip)
+  return rand_skip_;
+}
+inline void ImageDataParameter::set_rand_skip(::google::protobuf::uint32 value) {
+  set_has_rand_skip();
+  rand_skip_ = value;
+  // @@protoc_insertion_point(field_set:caffe.ImageDataParameter.rand_skip)
+}
+
+// optional bool shuffle = 8 [default = false];
+inline bool ImageDataParameter::has_shuffle() const {
+  return (_has_bits_[0] & 0x00000008u) != 0;
+}
+inline void ImageDataParameter::set_has_shuffle() {
+  _has_bits_[0] |= 0x00000008u;
+}
+inline void ImageDataParameter::clear_has_shuffle() {
+  _has_bits_[0] &= ~0x00000008u;
+}
+inline void ImageDataParameter::clear_shuffle() {
+  shuffle_ = false;
+  clear_has_shuffle();
+}
+inline bool ImageDataParameter::shuffle() const {
+  // @@protoc_insertion_point(field_get:caffe.ImageDataParameter.shuffle)
+  return shuffle_;
+}
+inline void ImageDataParameter::set_shuffle(bool value) {
+  set_has_shuffle();
+  shuffle_ = value;
+  // @@protoc_insertion_point(field_set:caffe.ImageDataParameter.shuffle)
+}
+
+// optional uint32 new_height = 9 [default = 0];
+inline bool ImageDataParameter::has_new_height() const {
+  return (_has_bits_[0] & 0x00000010u) != 0;
+}
+inline void ImageDataParameter::set_has_new_height() {
+  _has_bits_[0] |= 0x00000010u;
+}
+inline void ImageDataParameter::clear_has_new_height() {
+  _has_bits_[0] &= ~0x00000010u;
+}
+inline void ImageDataParameter::clear_new_height() {
+  new_height_ = 0u;
+  clear_has_new_height();
+}
+inline ::google::protobuf::uint32 ImageDataParameter::new_height() const {
+  // @@protoc_insertion_point(field_get:caffe.ImageDataParameter.new_height)
+  return new_height_;
+}
+inline void ImageDataParameter::set_new_height(::google::protobuf::uint32 value) {
+  set_has_new_height();
+  new_height_ = value;
+  // @@protoc_insertion_point(field_set:caffe.ImageDataParameter.new_height)
+}
+
+// optional uint32 new_width = 10 [default = 0];
+inline bool ImageDataParameter::has_new_width() const {
+  return (_has_bits_[0] & 0x00000020u) != 0;
+}
+inline void ImageDataParameter::set_has_new_width() {
+  _has_bits_[0] |= 0x00000020u;
+}
+inline void ImageDataParameter::clear_has_new_width() {
+  _has_bits_[0] &= ~0x00000020u;
+}
+inline void ImageDataParameter::clear_new_width() {
+  new_width_ = 0u;
+  clear_has_new_width();
+}
+inline ::google::protobuf::uint32 ImageDataParameter::new_width() const {
+  // @@protoc_insertion_point(field_get:caffe.ImageDataParameter.new_width)
+  return new_width_;
+}
+inline void ImageDataParameter::set_new_width(::google::protobuf::uint32 value) {
+  set_has_new_width();
+  new_width_ = value;
+  // @@protoc_insertion_point(field_set:caffe.ImageDataParameter.new_width)
+}
+
+// optional bool is_color = 11 [default = true];
+inline bool ImageDataParameter::has_is_color() const {
+  return (_has_bits_[0] & 0x00000040u) != 0;
+}
+inline void ImageDataParameter::set_has_is_color() {
+  _has_bits_[0] |= 0x00000040u;
+}
+inline void ImageDataParameter::clear_has_is_color() {
+  _has_bits_[0] &= ~0x00000040u;
+}
+inline void ImageDataParameter::clear_is_color() {
+  is_color_ = true;
+  clear_has_is_color();
+}
+inline bool ImageDataParameter::is_color() const {
+  // @@protoc_insertion_point(field_get:caffe.ImageDataParameter.is_color)
+  return is_color_;
+}
+inline void ImageDataParameter::set_is_color(bool value) {
+  set_has_is_color();
+  is_color_ = value;
+  // @@protoc_insertion_point(field_set:caffe.ImageDataParameter.is_color)
+}
+
+// optional float scale = 2 [default = 1];
+inline bool ImageDataParameter::has_scale() const {
+  return (_has_bits_[0] & 0x00000080u) != 0;
+}
+inline void ImageDataParameter::set_has_scale() {
+  _has_bits_[0] |= 0x00000080u;
+}
+inline void ImageDataParameter::clear_has_scale() {
+  _has_bits_[0] &= ~0x00000080u;
+}
+inline void ImageDataParameter::clear_scale() {
+  scale_ = 1;
+  clear_has_scale();
+}
+inline float ImageDataParameter::scale() const {
+  // @@protoc_insertion_point(field_get:caffe.ImageDataParameter.scale)
+  return scale_;
+}
+inline void ImageDataParameter::set_scale(float value) {
+  set_has_scale();
+  scale_ = value;
+  // @@protoc_insertion_point(field_set:caffe.ImageDataParameter.scale)
+}
+
+// optional string mean_file = 3;
+inline bool ImageDataParameter::has_mean_file() const {
+  return (_has_bits_[0] & 0x00000100u) != 0;
+}
+inline void ImageDataParameter::set_has_mean_file() {
+  _has_bits_[0] |= 0x00000100u;
+}
+inline void ImageDataParameter::clear_has_mean_file() {
+  _has_bits_[0] &= ~0x00000100u;
+}
+inline void ImageDataParameter::clear_mean_file() {
+  mean_file_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  clear_has_mean_file();
+}
+inline const ::std::string& ImageDataParameter::mean_file() const {
+  // @@protoc_insertion_point(field_get:caffe.ImageDataParameter.mean_file)
+  return mean_file_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void ImageDataParameter::set_mean_file(const ::std::string& value) {
+  set_has_mean_file();
+  mean_file_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:caffe.ImageDataParameter.mean_file)
+}
+inline void ImageDataParameter::set_mean_file(const char* value) {
+  set_has_mean_file();
+  mean_file_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:caffe.ImageDataParameter.mean_file)
+}
+inline void ImageDataParameter::set_mean_file(const char* value, size_t size) {
+  set_has_mean_file();
+  mean_file_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:caffe.ImageDataParameter.mean_file)
+}
+inline ::std::string* ImageDataParameter::mutable_mean_file() {
+  set_has_mean_file();
+  // @@protoc_insertion_point(field_mutable:caffe.ImageDataParameter.mean_file)
+  return mean_file_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline ::std::string* ImageDataParameter::release_mean_file() {
+  // @@protoc_insertion_point(field_release:caffe.ImageDataParameter.mean_file)
+  clear_has_mean_file();
+  return mean_file_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void ImageDataParameter::set_allocated_mean_file(::std::string* mean_file) {
+  if (mean_file != NULL) {
+    set_has_mean_file();
+  } else {
+    clear_has_mean_file();
+  }
+  mean_file_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), mean_file);
+  // @@protoc_insertion_point(field_set_allocated:caffe.ImageDataParameter.mean_file)
+}
+
+// optional uint32 crop_size = 5 [default = 0];
+inline bool ImageDataParameter::has_crop_size() const {
+  return (_has_bits_[0] & 0x00000200u) != 0;
+}
+inline void ImageDataParameter::set_has_crop_size() {
+  _has_bits_[0] |= 0x00000200u;
+}
+inline void ImageDataParameter::clear_has_crop_size() {
+  _has_bits_[0] &= ~0x00000200u;
+}
+inline void ImageDataParameter::clear_crop_size() {
+  crop_size_ = 0u;
+  clear_has_crop_size();
+}
+inline ::google::protobuf::uint32 ImageDataParameter::crop_size() const {
+  // @@protoc_insertion_point(field_get:caffe.ImageDataParameter.crop_size)
+  return crop_size_;
+}
+inline void ImageDataParameter::set_crop_size(::google::protobuf::uint32 value) {
+  set_has_crop_size();
+  crop_size_ = value;
+  // @@protoc_insertion_point(field_set:caffe.ImageDataParameter.crop_size)
+}
+
+// optional bool mirror = 6 [default = false];
+inline bool ImageDataParameter::has_mirror() const {
+  return (_has_bits_[0] & 0x00000400u) != 0;
+}
+inline void ImageDataParameter::set_has_mirror() {
+  _has_bits_[0] |= 0x00000400u;
+}
+inline void ImageDataParameter::clear_has_mirror() {
+  _has_bits_[0] &= ~0x00000400u;
+}
+inline void ImageDataParameter::clear_mirror() {
+  mirror_ = false;
+  clear_has_mirror();
+}
+inline bool ImageDataParameter::mirror() const {
+  // @@protoc_insertion_point(field_get:caffe.ImageDataParameter.mirror)
+  return mirror_;
+}
+inline void ImageDataParameter::set_mirror(bool value) {
+  set_has_mirror();
+  mirror_ = value;
+  // @@protoc_insertion_point(field_set:caffe.ImageDataParameter.mirror)
+}
+
+// optional string root_folder = 12 [default = ""];
+inline bool ImageDataParameter::has_root_folder() const {
+  return (_has_bits_[0] & 0x00000800u) != 0;
+}
+inline void ImageDataParameter::set_has_root_folder() {
+  _has_bits_[0] |= 0x00000800u;
+}
+inline void ImageDataParameter::clear_has_root_folder() {
+  _has_bits_[0] &= ~0x00000800u;
+}
+inline void ImageDataParameter::clear_root_folder() {
+  root_folder_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  clear_has_root_folder();
+}
+inline const ::std::string& ImageDataParameter::root_folder() const {
+  // @@protoc_insertion_point(field_get:caffe.ImageDataParameter.root_folder)
+  return root_folder_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void ImageDataParameter::set_root_folder(const ::std::string& value) {
+  set_has_root_folder();
+  root_folder_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:caffe.ImageDataParameter.root_folder)
+}
+inline void ImageDataParameter::set_root_folder(const char* value) {
+  set_has_root_folder();
+  root_folder_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:caffe.ImageDataParameter.root_folder)
+}
+inline void ImageDataParameter::set_root_folder(const char* value, size_t size) {
+  set_has_root_folder();
+  root_folder_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:caffe.ImageDataParameter.root_folder)
+}
+inline ::std::string* ImageDataParameter::mutable_root_folder() {
+  set_has_root_folder();
+  // @@protoc_insertion_point(field_mutable:caffe.ImageDataParameter.root_folder)
+  return root_folder_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline ::std::string* ImageDataParameter::release_root_folder() {
+  // @@protoc_insertion_point(field_release:caffe.ImageDataParameter.root_folder)
+  clear_has_root_folder();
+  return root_folder_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void ImageDataParameter::set_allocated_root_folder(::std::string* root_folder) {
+  if (root_folder != NULL) {
+    set_has_root_folder();
+  } else {
+    clear_has_root_folder();
+  }
+  root_folder_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), root_folder);
+  // @@protoc_insertion_point(field_set_allocated:caffe.ImageDataParameter.root_folder)
+}
+
+inline const ImageDataParameter* ImageDataParameter::internal_default_instance() {
+  return &ImageDataParameter_default_instance_.get();
+}
+// -------------------------------------------------------------------
+
+// InfogainLossParameter
+
+// optional string source = 1;
+inline bool InfogainLossParameter::has_source() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+inline void InfogainLossParameter::set_has_source() {
+  _has_bits_[0] |= 0x00000001u;
+}
+inline void InfogainLossParameter::clear_has_source() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+inline void InfogainLossParameter::clear_source() {
+  source_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  clear_has_source();
+}
+inline const ::std::string& InfogainLossParameter::source() const {
+  // @@protoc_insertion_point(field_get:caffe.InfogainLossParameter.source)
+  return source_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void InfogainLossParameter::set_source(const ::std::string& value) {
+  set_has_source();
+  source_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:caffe.InfogainLossParameter.source)
+}
+inline void InfogainLossParameter::set_source(const char* value) {
+  set_has_source();
+  source_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:caffe.InfogainLossParameter.source)
+}
+inline void InfogainLossParameter::set_source(const char* value, size_t size) {
+  set_has_source();
+  source_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:caffe.InfogainLossParameter.source)
+}
+inline ::std::string* InfogainLossParameter::mutable_source() {
+  set_has_source();
+  // @@protoc_insertion_point(field_mutable:caffe.InfogainLossParameter.source)
+  return source_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline ::std::string* InfogainLossParameter::release_source() {
+  // @@protoc_insertion_point(field_release:caffe.InfogainLossParameter.source)
+  clear_has_source();
+  return source_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void InfogainLossParameter::set_allocated_source(::std::string* source) {
+  if (source != NULL) {
+    set_has_source();
+  } else {
+    clear_has_source();
+  }
+  source_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), source);
+  // @@protoc_insertion_point(field_set_allocated:caffe.InfogainLossParameter.source)
+}
+
+inline const InfogainLossParameter* InfogainLossParameter::internal_default_instance() {
+  return &InfogainLossParameter_default_instance_.get();
+}
+// -------------------------------------------------------------------
+
+// InnerProductParameter
+
+// optional uint32 num_output = 1;
+inline bool InnerProductParameter::has_num_output() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+inline void InnerProductParameter::set_has_num_output() {
+  _has_bits_[0] |= 0x00000001u;
+}
+inline void InnerProductParameter::clear_has_num_output() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+inline void InnerProductParameter::clear_num_output() {
+  num_output_ = 0u;
+  clear_has_num_output();
+}
+inline ::google::protobuf::uint32 InnerProductParameter::num_output() const {
+  // @@protoc_insertion_point(field_get:caffe.InnerProductParameter.num_output)
+  return num_output_;
+}
+inline void InnerProductParameter::set_num_output(::google::protobuf::uint32 value) {
+  set_has_num_output();
+  num_output_ = value;
+  // @@protoc_insertion_point(field_set:caffe.InnerProductParameter.num_output)
+}
+
+// optional bool bias_term = 2 [default = true];
+inline bool InnerProductParameter::has_bias_term() const {
+  return (_has_bits_[0] & 0x00000002u) != 0;
+}
+inline void InnerProductParameter::set_has_bias_term() {
+  _has_bits_[0] |= 0x00000002u;
+}
+inline void InnerProductParameter::clear_has_bias_term() {
+  _has_bits_[0] &= ~0x00000002u;
+}
+inline void InnerProductParameter::clear_bias_term() {
+  bias_term_ = true;
+  clear_has_bias_term();
+}
+inline bool InnerProductParameter::bias_term() const {
+  // @@protoc_insertion_point(field_get:caffe.InnerProductParameter.bias_term)
+  return bias_term_;
+}
+inline void InnerProductParameter::set_bias_term(bool value) {
+  set_has_bias_term();
+  bias_term_ = value;
+  // @@protoc_insertion_point(field_set:caffe.InnerProductParameter.bias_term)
+}
+
+// optional .caffe.FillerParameter weight_filler = 3;
+inline bool InnerProductParameter::has_weight_filler() const {
+  return (_has_bits_[0] & 0x00000004u) != 0;
+}
+inline void InnerProductParameter::set_has_weight_filler() {
+  _has_bits_[0] |= 0x00000004u;
+}
+inline void InnerProductParameter::clear_has_weight_filler() {
+  _has_bits_[0] &= ~0x00000004u;
+}
+inline void InnerProductParameter::clear_weight_filler() {
+  if (weight_filler_ != NULL) weight_filler_->::caffe::FillerParameter::Clear();
+  clear_has_weight_filler();
+}
+inline const ::caffe::FillerParameter& InnerProductParameter::weight_filler() const {
+  // @@protoc_insertion_point(field_get:caffe.InnerProductParameter.weight_filler)
+  return weight_filler_ != NULL ? *weight_filler_
+                         : *::caffe::FillerParameter::internal_default_instance();
+}
+inline ::caffe::FillerParameter* InnerProductParameter::mutable_weight_filler() {
+  set_has_weight_filler();
+  if (weight_filler_ == NULL) {
+    weight_filler_ = new ::caffe::FillerParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.InnerProductParameter.weight_filler)
+  return weight_filler_;
+}
+inline ::caffe::FillerParameter* InnerProductParameter::release_weight_filler() {
+  // @@protoc_insertion_point(field_release:caffe.InnerProductParameter.weight_filler)
+  clear_has_weight_filler();
+  ::caffe::FillerParameter* temp = weight_filler_;
+  weight_filler_ = NULL;
+  return temp;
+}
+inline void InnerProductParameter::set_allocated_weight_filler(::caffe::FillerParameter* weight_filler) {
+  delete weight_filler_;
+  weight_filler_ = weight_filler;
+  if (weight_filler) {
+    set_has_weight_filler();
+  } else {
+    clear_has_weight_filler();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.InnerProductParameter.weight_filler)
+}
+
+// optional .caffe.FillerParameter bias_filler = 4;
+inline bool InnerProductParameter::has_bias_filler() const {
+  return (_has_bits_[0] & 0x00000008u) != 0;
+}
+inline void InnerProductParameter::set_has_bias_filler() {
+  _has_bits_[0] |= 0x00000008u;
+}
+inline void InnerProductParameter::clear_has_bias_filler() {
+  _has_bits_[0] &= ~0x00000008u;
+}
+inline void InnerProductParameter::clear_bias_filler() {
+  if (bias_filler_ != NULL) bias_filler_->::caffe::FillerParameter::Clear();
+  clear_has_bias_filler();
+}
+inline const ::caffe::FillerParameter& InnerProductParameter::bias_filler() const {
+  // @@protoc_insertion_point(field_get:caffe.InnerProductParameter.bias_filler)
+  return bias_filler_ != NULL ? *bias_filler_
+                         : *::caffe::FillerParameter::internal_default_instance();
+}
+inline ::caffe::FillerParameter* InnerProductParameter::mutable_bias_filler() {
+  set_has_bias_filler();
+  if (bias_filler_ == NULL) {
+    bias_filler_ = new ::caffe::FillerParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.InnerProductParameter.bias_filler)
+  return bias_filler_;
+}
+inline ::caffe::FillerParameter* InnerProductParameter::release_bias_filler() {
+  // @@protoc_insertion_point(field_release:caffe.InnerProductParameter.bias_filler)
+  clear_has_bias_filler();
+  ::caffe::FillerParameter* temp = bias_filler_;
+  bias_filler_ = NULL;
+  return temp;
+}
+inline void InnerProductParameter::set_allocated_bias_filler(::caffe::FillerParameter* bias_filler) {
+  delete bias_filler_;
+  bias_filler_ = bias_filler;
+  if (bias_filler) {
+    set_has_bias_filler();
+  } else {
+    clear_has_bias_filler();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.InnerProductParameter.bias_filler)
+}
+
+// optional int32 axis = 5 [default = 1];
+inline bool InnerProductParameter::has_axis() const {
+  return (_has_bits_[0] & 0x00000010u) != 0;
+}
+inline void InnerProductParameter::set_has_axis() {
+  _has_bits_[0] |= 0x00000010u;
+}
+inline void InnerProductParameter::clear_has_axis() {
+  _has_bits_[0] &= ~0x00000010u;
+}
+inline void InnerProductParameter::clear_axis() {
+  axis_ = 1;
+  clear_has_axis();
+}
+inline ::google::protobuf::int32 InnerProductParameter::axis() const {
+  // @@protoc_insertion_point(field_get:caffe.InnerProductParameter.axis)
+  return axis_;
+}
+inline void InnerProductParameter::set_axis(::google::protobuf::int32 value) {
+  set_has_axis();
+  axis_ = value;
+  // @@protoc_insertion_point(field_set:caffe.InnerProductParameter.axis)
+}
+
+inline const InnerProductParameter* InnerProductParameter::internal_default_instance() {
+  return &InnerProductParameter_default_instance_.get();
+}
+// -------------------------------------------------------------------
+
+// LogParameter
+
+// optional float base = 1 [default = -1];
+inline bool LogParameter::has_base() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+inline void LogParameter::set_has_base() {
+  _has_bits_[0] |= 0x00000001u;
+}
+inline void LogParameter::clear_has_base() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+inline void LogParameter::clear_base() {
+  base_ = -1;
+  clear_has_base();
+}
+inline float LogParameter::base() const {
+  // @@protoc_insertion_point(field_get:caffe.LogParameter.base)
+  return base_;
+}
+inline void LogParameter::set_base(float value) {
+  set_has_base();
+  base_ = value;
+  // @@protoc_insertion_point(field_set:caffe.LogParameter.base)
+}
+
+// optional float scale = 2 [default = 1];
+inline bool LogParameter::has_scale() const {
+  return (_has_bits_[0] & 0x00000002u) != 0;
+}
+inline void LogParameter::set_has_scale() {
+  _has_bits_[0] |= 0x00000002u;
+}
+inline void LogParameter::clear_has_scale() {
+  _has_bits_[0] &= ~0x00000002u;
+}
+inline void LogParameter::clear_scale() {
+  scale_ = 1;
+  clear_has_scale();
+}
+inline float LogParameter::scale() const {
+  // @@protoc_insertion_point(field_get:caffe.LogParameter.scale)
+  return scale_;
+}
+inline void LogParameter::set_scale(float value) {
+  set_has_scale();
+  scale_ = value;
+  // @@protoc_insertion_point(field_set:caffe.LogParameter.scale)
+}
+
+// optional float shift = 3 [default = 0];
+inline bool LogParameter::has_shift() const {
+  return (_has_bits_[0] & 0x00000004u) != 0;
+}
+inline void LogParameter::set_has_shift() {
+  _has_bits_[0] |= 0x00000004u;
+}
+inline void LogParameter::clear_has_shift() {
+  _has_bits_[0] &= ~0x00000004u;
+}
+inline void LogParameter::clear_shift() {
+  shift_ = 0;
+  clear_has_shift();
+}
+inline float LogParameter::shift() const {
+  // @@protoc_insertion_point(field_get:caffe.LogParameter.shift)
+  return shift_;
+}
+inline void LogParameter::set_shift(float value) {
+  set_has_shift();
+  shift_ = value;
+  // @@protoc_insertion_point(field_set:caffe.LogParameter.shift)
+}
+
+inline const LogParameter* LogParameter::internal_default_instance() {
+  return &LogParameter_default_instance_.get();
+}
+// -------------------------------------------------------------------
+
+// LRNParameter
+
+// optional uint32 local_size = 1 [default = 5];
+inline bool LRNParameter::has_local_size() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+inline void LRNParameter::set_has_local_size() {
+  _has_bits_[0] |= 0x00000001u;
+}
+inline void LRNParameter::clear_has_local_size() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+inline void LRNParameter::clear_local_size() {
+  local_size_ = 5u;
+  clear_has_local_size();
+}
+inline ::google::protobuf::uint32 LRNParameter::local_size() const {
+  // @@protoc_insertion_point(field_get:caffe.LRNParameter.local_size)
+  return local_size_;
+}
+inline void LRNParameter::set_local_size(::google::protobuf::uint32 value) {
+  set_has_local_size();
+  local_size_ = value;
+  // @@protoc_insertion_point(field_set:caffe.LRNParameter.local_size)
+}
+
+// optional float alpha = 2 [default = 1];
+inline bool LRNParameter::has_alpha() const {
+  return (_has_bits_[0] & 0x00000002u) != 0;
+}
+inline void LRNParameter::set_has_alpha() {
+  _has_bits_[0] |= 0x00000002u;
+}
+inline void LRNParameter::clear_has_alpha() {
+  _has_bits_[0] &= ~0x00000002u;
+}
+inline void LRNParameter::clear_alpha() {
+  alpha_ = 1;
+  clear_has_alpha();
+}
+inline float LRNParameter::alpha() const {
+  // @@protoc_insertion_point(field_get:caffe.LRNParameter.alpha)
+  return alpha_;
+}
+inline void LRNParameter::set_alpha(float value) {
+  set_has_alpha();
+  alpha_ = value;
+  // @@protoc_insertion_point(field_set:caffe.LRNParameter.alpha)
+}
+
+// optional float beta = 3 [default = 0.75];
+inline bool LRNParameter::has_beta() const {
+  return (_has_bits_[0] & 0x00000004u) != 0;
+}
+inline void LRNParameter::set_has_beta() {
+  _has_bits_[0] |= 0x00000004u;
+}
+inline void LRNParameter::clear_has_beta() {
+  _has_bits_[0] &= ~0x00000004u;
+}
+inline void LRNParameter::clear_beta() {
+  beta_ = 0.75f;
+  clear_has_beta();
+}
+inline float LRNParameter::beta() const {
+  // @@protoc_insertion_point(field_get:caffe.LRNParameter.beta)
+  return beta_;
+}
+inline void LRNParameter::set_beta(float value) {
+  set_has_beta();
+  beta_ = value;
+  // @@protoc_insertion_point(field_set:caffe.LRNParameter.beta)
+}
+
+// optional .caffe.LRNParameter.NormRegion norm_region = 4 [default = ACROSS_CHANNELS];
+inline bool LRNParameter::has_norm_region() const {
+  return (_has_bits_[0] & 0x00000008u) != 0;
+}
+inline void LRNParameter::set_has_norm_region() {
+  _has_bits_[0] |= 0x00000008u;
+}
+inline void LRNParameter::clear_has_norm_region() {
+  _has_bits_[0] &= ~0x00000008u;
+}
+inline void LRNParameter::clear_norm_region() {
+  norm_region_ = 0;
+  clear_has_norm_region();
+}
+inline ::caffe::LRNParameter_NormRegion LRNParameter::norm_region() const {
+  // @@protoc_insertion_point(field_get:caffe.LRNParameter.norm_region)
+  return static_cast< ::caffe::LRNParameter_NormRegion >(norm_region_);
+}
+inline void LRNParameter::set_norm_region(::caffe::LRNParameter_NormRegion value) {
+  assert(::caffe::LRNParameter_NormRegion_IsValid(value));
+  set_has_norm_region();
+  norm_region_ = value;
+  // @@protoc_insertion_point(field_set:caffe.LRNParameter.norm_region)
+}
+
+// optional float k = 5 [default = 1];
+inline bool LRNParameter::has_k() const {
+  return (_has_bits_[0] & 0x00000010u) != 0;
+}
+inline void LRNParameter::set_has_k() {
+  _has_bits_[0] |= 0x00000010u;
+}
+inline void LRNParameter::clear_has_k() {
+  _has_bits_[0] &= ~0x00000010u;
+}
+inline void LRNParameter::clear_k() {
+  k_ = 1;
+  clear_has_k();
+}
+inline float LRNParameter::k() const {
+  // @@protoc_insertion_point(field_get:caffe.LRNParameter.k)
+  return k_;
+}
+inline void LRNParameter::set_k(float value) {
+  set_has_k();
+  k_ = value;
+  // @@protoc_insertion_point(field_set:caffe.LRNParameter.k)
+}
+
+inline const LRNParameter* LRNParameter::internal_default_instance() {
+  return &LRNParameter_default_instance_.get();
+}
+// -------------------------------------------------------------------
+
+// MemoryDataParameter
+
+// optional uint32 batch_size = 1;
+inline bool MemoryDataParameter::has_batch_size() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+inline void MemoryDataParameter::set_has_batch_size() {
+  _has_bits_[0] |= 0x00000001u;
+}
+inline void MemoryDataParameter::clear_has_batch_size() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+inline void MemoryDataParameter::clear_batch_size() {
+  batch_size_ = 0u;
+  clear_has_batch_size();
+}
+inline ::google::protobuf::uint32 MemoryDataParameter::batch_size() const {
+  // @@protoc_insertion_point(field_get:caffe.MemoryDataParameter.batch_size)
+  return batch_size_;
+}
+inline void MemoryDataParameter::set_batch_size(::google::protobuf::uint32 value) {
+  set_has_batch_size();
+  batch_size_ = value;
+  // @@protoc_insertion_point(field_set:caffe.MemoryDataParameter.batch_size)
+}
+
+// optional uint32 channels = 2;
+inline bool MemoryDataParameter::has_channels() const {
+  return (_has_bits_[0] & 0x00000002u) != 0;
+}
+inline void MemoryDataParameter::set_has_channels() {
+  _has_bits_[0] |= 0x00000002u;
+}
+inline void MemoryDataParameter::clear_has_channels() {
+  _has_bits_[0] &= ~0x00000002u;
+}
+inline void MemoryDataParameter::clear_channels() {
+  channels_ = 0u;
+  clear_has_channels();
+}
+inline ::google::protobuf::uint32 MemoryDataParameter::channels() const {
+  // @@protoc_insertion_point(field_get:caffe.MemoryDataParameter.channels)
+  return channels_;
+}
+inline void MemoryDataParameter::set_channels(::google::protobuf::uint32 value) {
+  set_has_channels();
+  channels_ = value;
+  // @@protoc_insertion_point(field_set:caffe.MemoryDataParameter.channels)
+}
+
+// optional uint32 height = 3;
+inline bool MemoryDataParameter::has_height() const {
+  return (_has_bits_[0] & 0x00000004u) != 0;
+}
+inline void MemoryDataParameter::set_has_height() {
+  _has_bits_[0] |= 0x00000004u;
+}
+inline void MemoryDataParameter::clear_has_height() {
+  _has_bits_[0] &= ~0x00000004u;
+}
+inline void MemoryDataParameter::clear_height() {
+  height_ = 0u;
+  clear_has_height();
+}
+inline ::google::protobuf::uint32 MemoryDataParameter::height() const {
+  // @@protoc_insertion_point(field_get:caffe.MemoryDataParameter.height)
+  return height_;
+}
+inline void MemoryDataParameter::set_height(::google::protobuf::uint32 value) {
+  set_has_height();
+  height_ = value;
+  // @@protoc_insertion_point(field_set:caffe.MemoryDataParameter.height)
+}
+
+// optional uint32 width = 4;
+inline bool MemoryDataParameter::has_width() const {
+  return (_has_bits_[0] & 0x00000008u) != 0;
+}
+inline void MemoryDataParameter::set_has_width() {
+  _has_bits_[0] |= 0x00000008u;
+}
+inline void MemoryDataParameter::clear_has_width() {
+  _has_bits_[0] &= ~0x00000008u;
+}
+inline void MemoryDataParameter::clear_width() {
+  width_ = 0u;
+  clear_has_width();
+}
+inline ::google::protobuf::uint32 MemoryDataParameter::width() const {
+  // @@protoc_insertion_point(field_get:caffe.MemoryDataParameter.width)
+  return width_;
+}
+inline void MemoryDataParameter::set_width(::google::protobuf::uint32 value) {
+  set_has_width();
+  width_ = value;
+  // @@protoc_insertion_point(field_set:caffe.MemoryDataParameter.width)
+}
+
+inline const MemoryDataParameter* MemoryDataParameter::internal_default_instance() {
+  return &MemoryDataParameter_default_instance_.get();
+}
+// -------------------------------------------------------------------
+
+// MVNParameter
+
+// optional bool normalize_variance = 1 [default = true];
+inline bool MVNParameter::has_normalize_variance() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+inline void MVNParameter::set_has_normalize_variance() {
+  _has_bits_[0] |= 0x00000001u;
+}
+inline void MVNParameter::clear_has_normalize_variance() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+inline void MVNParameter::clear_normalize_variance() {
+  normalize_variance_ = true;
+  clear_has_normalize_variance();
+}
+inline bool MVNParameter::normalize_variance() const {
+  // @@protoc_insertion_point(field_get:caffe.MVNParameter.normalize_variance)
+  return normalize_variance_;
+}
+inline void MVNParameter::set_normalize_variance(bool value) {
+  set_has_normalize_variance();
+  normalize_variance_ = value;
+  // @@protoc_insertion_point(field_set:caffe.MVNParameter.normalize_variance)
+}
+
+// optional bool across_channels = 2 [default = false];
+inline bool MVNParameter::has_across_channels() const {
+  return (_has_bits_[0] & 0x00000002u) != 0;
+}
+inline void MVNParameter::set_has_across_channels() {
+  _has_bits_[0] |= 0x00000002u;
+}
+inline void MVNParameter::clear_has_across_channels() {
+  _has_bits_[0] &= ~0x00000002u;
+}
+inline void MVNParameter::clear_across_channels() {
+  across_channels_ = false;
+  clear_has_across_channels();
+}
+inline bool MVNParameter::across_channels() const {
+  // @@protoc_insertion_point(field_get:caffe.MVNParameter.across_channels)
+  return across_channels_;
+}
+inline void MVNParameter::set_across_channels(bool value) {
+  set_has_across_channels();
+  across_channels_ = value;
+  // @@protoc_insertion_point(field_set:caffe.MVNParameter.across_channels)
+}
+
+// optional float eps = 3 [default = 1e-09];
+inline bool MVNParameter::has_eps() const {
+  return (_has_bits_[0] & 0x00000004u) != 0;
+}
+inline void MVNParameter::set_has_eps() {
+  _has_bits_[0] |= 0x00000004u;
+}
+inline void MVNParameter::clear_has_eps() {
+  _has_bits_[0] &= ~0x00000004u;
+}
+inline void MVNParameter::clear_eps() {
+  eps_ = 1e-09f;
+  clear_has_eps();
+}
+inline float MVNParameter::eps() const {
+  // @@protoc_insertion_point(field_get:caffe.MVNParameter.eps)
+  return eps_;
+}
+inline void MVNParameter::set_eps(float value) {
+  set_has_eps();
+  eps_ = value;
+  // @@protoc_insertion_point(field_set:caffe.MVNParameter.eps)
+}
+
+inline const MVNParameter* MVNParameter::internal_default_instance() {
+  return &MVNParameter_default_instance_.get();
+}
+// -------------------------------------------------------------------
+
+// PoolingParameter
+
+// optional .caffe.PoolingParameter.PoolMethod pool = 1 [default = MAX];
+inline bool PoolingParameter::has_pool() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+inline void PoolingParameter::set_has_pool() {
+  _has_bits_[0] |= 0x00000001u;
+}
+inline void PoolingParameter::clear_has_pool() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+inline void PoolingParameter::clear_pool() {
+  pool_ = 0;
+  clear_has_pool();
+}
+inline ::caffe::PoolingParameter_PoolMethod PoolingParameter::pool() const {
+  // @@protoc_insertion_point(field_get:caffe.PoolingParameter.pool)
+  return static_cast< ::caffe::PoolingParameter_PoolMethod >(pool_);
+}
+inline void PoolingParameter::set_pool(::caffe::PoolingParameter_PoolMethod value) {
+  assert(::caffe::PoolingParameter_PoolMethod_IsValid(value));
+  set_has_pool();
+  pool_ = value;
+  // @@protoc_insertion_point(field_set:caffe.PoolingParameter.pool)
+}
+
+// optional uint32 pad = 4 [default = 0];
+inline bool PoolingParameter::has_pad() const {
+  return (_has_bits_[0] & 0x00000002u) != 0;
+}
+inline void PoolingParameter::set_has_pad() {
+  _has_bits_[0] |= 0x00000002u;
+}
+inline void PoolingParameter::clear_has_pad() {
+  _has_bits_[0] &= ~0x00000002u;
+}
+inline void PoolingParameter::clear_pad() {
+  pad_ = 0u;
+  clear_has_pad();
+}
+inline ::google::protobuf::uint32 PoolingParameter::pad() const {
+  // @@protoc_insertion_point(field_get:caffe.PoolingParameter.pad)
+  return pad_;
+}
+inline void PoolingParameter::set_pad(::google::protobuf::uint32 value) {
+  set_has_pad();
+  pad_ = value;
+  // @@protoc_insertion_point(field_set:caffe.PoolingParameter.pad)
+}
+
+// optional uint32 pad_h = 9 [default = 0];
+inline bool PoolingParameter::has_pad_h() const {
+  return (_has_bits_[0] & 0x00000004u) != 0;
+}
+inline void PoolingParameter::set_has_pad_h() {
+  _has_bits_[0] |= 0x00000004u;
+}
+inline void PoolingParameter::clear_has_pad_h() {
+  _has_bits_[0] &= ~0x00000004u;
+}
+inline void PoolingParameter::clear_pad_h() {
+  pad_h_ = 0u;
+  clear_has_pad_h();
+}
+inline ::google::protobuf::uint32 PoolingParameter::pad_h() const {
+  // @@protoc_insertion_point(field_get:caffe.PoolingParameter.pad_h)
+  return pad_h_;
+}
+inline void PoolingParameter::set_pad_h(::google::protobuf::uint32 value) {
+  set_has_pad_h();
+  pad_h_ = value;
+  // @@protoc_insertion_point(field_set:caffe.PoolingParameter.pad_h)
+}
+
+// optional uint32 pad_w = 10 [default = 0];
+inline bool PoolingParameter::has_pad_w() const {
+  return (_has_bits_[0] & 0x00000008u) != 0;
+}
+inline void PoolingParameter::set_has_pad_w() {
+  _has_bits_[0] |= 0x00000008u;
+}
+inline void PoolingParameter::clear_has_pad_w() {
+  _has_bits_[0] &= ~0x00000008u;
+}
+inline void PoolingParameter::clear_pad_w() {
+  pad_w_ = 0u;
+  clear_has_pad_w();
+}
+inline ::google::protobuf::uint32 PoolingParameter::pad_w() const {
+  // @@protoc_insertion_point(field_get:caffe.PoolingParameter.pad_w)
+  return pad_w_;
+}
+inline void PoolingParameter::set_pad_w(::google::protobuf::uint32 value) {
+  set_has_pad_w();
+  pad_w_ = value;
+  // @@protoc_insertion_point(field_set:caffe.PoolingParameter.pad_w)
+}
+
+// optional uint32 kernel_size = 2;
+inline bool PoolingParameter::has_kernel_size() const {
+  return (_has_bits_[0] & 0x00000010u) != 0;
+}
+inline void PoolingParameter::set_has_kernel_size() {
+  _has_bits_[0] |= 0x00000010u;
+}
+inline void PoolingParameter::clear_has_kernel_size() {
+  _has_bits_[0] &= ~0x00000010u;
+}
+inline void PoolingParameter::clear_kernel_size() {
+  kernel_size_ = 0u;
+  clear_has_kernel_size();
+}
+inline ::google::protobuf::uint32 PoolingParameter::kernel_size() const {
+  // @@protoc_insertion_point(field_get:caffe.PoolingParameter.kernel_size)
+  return kernel_size_;
+}
+inline void PoolingParameter::set_kernel_size(::google::protobuf::uint32 value) {
+  set_has_kernel_size();
+  kernel_size_ = value;
+  // @@protoc_insertion_point(field_set:caffe.PoolingParameter.kernel_size)
+}
+
+// optional uint32 kernel_h = 5;
+inline bool PoolingParameter::has_kernel_h() const {
+  return (_has_bits_[0] & 0x00000020u) != 0;
+}
+inline void PoolingParameter::set_has_kernel_h() {
+  _has_bits_[0] |= 0x00000020u;
+}
+inline void PoolingParameter::clear_has_kernel_h() {
+  _has_bits_[0] &= ~0x00000020u;
+}
+inline void PoolingParameter::clear_kernel_h() {
+  kernel_h_ = 0u;
+  clear_has_kernel_h();
+}
+inline ::google::protobuf::uint32 PoolingParameter::kernel_h() const {
+  // @@protoc_insertion_point(field_get:caffe.PoolingParameter.kernel_h)
+  return kernel_h_;
+}
+inline void PoolingParameter::set_kernel_h(::google::protobuf::uint32 value) {
+  set_has_kernel_h();
+  kernel_h_ = value;
+  // @@protoc_insertion_point(field_set:caffe.PoolingParameter.kernel_h)
+}
+
+// optional uint32 kernel_w = 6;
+inline bool PoolingParameter::has_kernel_w() const {
+  return (_has_bits_[0] & 0x00000040u) != 0;
+}
+inline void PoolingParameter::set_has_kernel_w() {
+  _has_bits_[0] |= 0x00000040u;
+}
+inline void PoolingParameter::clear_has_kernel_w() {
+  _has_bits_[0] &= ~0x00000040u;
+}
+inline void PoolingParameter::clear_kernel_w() {
+  kernel_w_ = 0u;
+  clear_has_kernel_w();
+}
+inline ::google::protobuf::uint32 PoolingParameter::kernel_w() const {
+  // @@protoc_insertion_point(field_get:caffe.PoolingParameter.kernel_w)
+  return kernel_w_;
+}
+inline void PoolingParameter::set_kernel_w(::google::protobuf::uint32 value) {
+  set_has_kernel_w();
+  kernel_w_ = value;
+  // @@protoc_insertion_point(field_set:caffe.PoolingParameter.kernel_w)
+}
+
+// optional uint32 stride = 3 [default = 1];
+inline bool PoolingParameter::has_stride() const {
+  return (_has_bits_[0] & 0x00000080u) != 0;
+}
+inline void PoolingParameter::set_has_stride() {
+  _has_bits_[0] |= 0x00000080u;
+}
+inline void PoolingParameter::clear_has_stride() {
+  _has_bits_[0] &= ~0x00000080u;
+}
+inline void PoolingParameter::clear_stride() {
+  stride_ = 1u;
+  clear_has_stride();
+}
+inline ::google::protobuf::uint32 PoolingParameter::stride() const {
+  // @@protoc_insertion_point(field_get:caffe.PoolingParameter.stride)
+  return stride_;
+}
+inline void PoolingParameter::set_stride(::google::protobuf::uint32 value) {
+  set_has_stride();
+  stride_ = value;
+  // @@protoc_insertion_point(field_set:caffe.PoolingParameter.stride)
+}
+
+// optional uint32 stride_h = 7;
+inline bool PoolingParameter::has_stride_h() const {
+  return (_has_bits_[0] & 0x00000100u) != 0;
+}
+inline void PoolingParameter::set_has_stride_h() {
+  _has_bits_[0] |= 0x00000100u;
+}
+inline void PoolingParameter::clear_has_stride_h() {
+  _has_bits_[0] &= ~0x00000100u;
+}
+inline void PoolingParameter::clear_stride_h() {
+  stride_h_ = 0u;
+  clear_has_stride_h();
+}
+inline ::google::protobuf::uint32 PoolingParameter::stride_h() const {
+  // @@protoc_insertion_point(field_get:caffe.PoolingParameter.stride_h)
+  return stride_h_;
+}
+inline void PoolingParameter::set_stride_h(::google::protobuf::uint32 value) {
+  set_has_stride_h();
+  stride_h_ = value;
+  // @@protoc_insertion_point(field_set:caffe.PoolingParameter.stride_h)
+}
+
+// optional uint32 stride_w = 8;
+inline bool PoolingParameter::has_stride_w() const {
+  return (_has_bits_[0] & 0x00000200u) != 0;
+}
+inline void PoolingParameter::set_has_stride_w() {
+  _has_bits_[0] |= 0x00000200u;
+}
+inline void PoolingParameter::clear_has_stride_w() {
+  _has_bits_[0] &= ~0x00000200u;
+}
+inline void PoolingParameter::clear_stride_w() {
+  stride_w_ = 0u;
+  clear_has_stride_w();
+}
+inline ::google::protobuf::uint32 PoolingParameter::stride_w() const {
+  // @@protoc_insertion_point(field_get:caffe.PoolingParameter.stride_w)
+  return stride_w_;
+}
+inline void PoolingParameter::set_stride_w(::google::protobuf::uint32 value) {
+  set_has_stride_w();
+  stride_w_ = value;
+  // @@protoc_insertion_point(field_set:caffe.PoolingParameter.stride_w)
+}
+
+// optional .caffe.PoolingParameter.Engine engine = 11 [default = DEFAULT];
+inline bool PoolingParameter::has_engine() const {
+  return (_has_bits_[0] & 0x00000400u) != 0;
+}
+inline void PoolingParameter::set_has_engine() {
+  _has_bits_[0] |= 0x00000400u;
+}
+inline void PoolingParameter::clear_has_engine() {
+  _has_bits_[0] &= ~0x00000400u;
+}
+inline void PoolingParameter::clear_engine() {
+  engine_ = 0;
+  clear_has_engine();
+}
+inline ::caffe::PoolingParameter_Engine PoolingParameter::engine() const {
+  // @@protoc_insertion_point(field_get:caffe.PoolingParameter.engine)
+  return static_cast< ::caffe::PoolingParameter_Engine >(engine_);
+}
+inline void PoolingParameter::set_engine(::caffe::PoolingParameter_Engine value) {
+  assert(::caffe::PoolingParameter_Engine_IsValid(value));
+  set_has_engine();
+  engine_ = value;
+  // @@protoc_insertion_point(field_set:caffe.PoolingParameter.engine)
+}
+
+// optional bool global_pooling = 12 [default = false];
+inline bool PoolingParameter::has_global_pooling() const {
+  return (_has_bits_[0] & 0x00000800u) != 0;
+}
+inline void PoolingParameter::set_has_global_pooling() {
+  _has_bits_[0] |= 0x00000800u;
+}
+inline void PoolingParameter::clear_has_global_pooling() {
+  _has_bits_[0] &= ~0x00000800u;
+}
+inline void PoolingParameter::clear_global_pooling() {
+  global_pooling_ = false;
+  clear_has_global_pooling();
+}
+inline bool PoolingParameter::global_pooling() const {
+  // @@protoc_insertion_point(field_get:caffe.PoolingParameter.global_pooling)
+  return global_pooling_;
+}
+inline void PoolingParameter::set_global_pooling(bool value) {
+  set_has_global_pooling();
+  global_pooling_ = value;
+  // @@protoc_insertion_point(field_set:caffe.PoolingParameter.global_pooling)
+}
+
+inline const PoolingParameter* PoolingParameter::internal_default_instance() {
+  return &PoolingParameter_default_instance_.get();
+}
+// -------------------------------------------------------------------
+
+// PowerParameter
+
+// optional float power = 1 [default = 1];
+inline bool PowerParameter::has_power() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+inline void PowerParameter::set_has_power() {
+  _has_bits_[0] |= 0x00000001u;
+}
+inline void PowerParameter::clear_has_power() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+inline void PowerParameter::clear_power() {
+  power_ = 1;
+  clear_has_power();
+}
+inline float PowerParameter::power() const {
+  // @@protoc_insertion_point(field_get:caffe.PowerParameter.power)
+  return power_;
+}
+inline void PowerParameter::set_power(float value) {
+  set_has_power();
+  power_ = value;
+  // @@protoc_insertion_point(field_set:caffe.PowerParameter.power)
+}
+
+// optional float scale = 2 [default = 1];
+inline bool PowerParameter::has_scale() const {
+  return (_has_bits_[0] & 0x00000002u) != 0;
+}
+inline void PowerParameter::set_has_scale() {
+  _has_bits_[0] |= 0x00000002u;
+}
+inline void PowerParameter::clear_has_scale() {
+  _has_bits_[0] &= ~0x00000002u;
+}
+inline void PowerParameter::clear_scale() {
+  scale_ = 1;
+  clear_has_scale();
+}
+inline float PowerParameter::scale() const {
+  // @@protoc_insertion_point(field_get:caffe.PowerParameter.scale)
+  return scale_;
+}
+inline void PowerParameter::set_scale(float value) {
+  set_has_scale();
+  scale_ = value;
+  // @@protoc_insertion_point(field_set:caffe.PowerParameter.scale)
+}
+
+// optional float shift = 3 [default = 0];
+inline bool PowerParameter::has_shift() const {
+  return (_has_bits_[0] & 0x00000004u) != 0;
+}
+inline void PowerParameter::set_has_shift() {
+  _has_bits_[0] |= 0x00000004u;
+}
+inline void PowerParameter::clear_has_shift() {
+  _has_bits_[0] &= ~0x00000004u;
+}
+inline void PowerParameter::clear_shift() {
+  shift_ = 0;
+  clear_has_shift();
+}
+inline float PowerParameter::shift() const {
+  // @@protoc_insertion_point(field_get:caffe.PowerParameter.shift)
+  return shift_;
+}
+inline void PowerParameter::set_shift(float value) {
+  set_has_shift();
+  shift_ = value;
+  // @@protoc_insertion_point(field_set:caffe.PowerParameter.shift)
+}
+
+inline const PowerParameter* PowerParameter::internal_default_instance() {
+  return &PowerParameter_default_instance_.get();
+}
+// -------------------------------------------------------------------
+
+// PythonParameter
+
+// optional string module = 1;
+inline bool PythonParameter::has_module() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+inline void PythonParameter::set_has_module() {
+  _has_bits_[0] |= 0x00000001u;
+}
+inline void PythonParameter::clear_has_module() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+inline void PythonParameter::clear_module() {
+  module_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  clear_has_module();
+}
+inline const ::std::string& PythonParameter::module() const {
+  // @@protoc_insertion_point(field_get:caffe.PythonParameter.module)
+  return module_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void PythonParameter::set_module(const ::std::string& value) {
+  set_has_module();
+  module_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:caffe.PythonParameter.module)
+}
+inline void PythonParameter::set_module(const char* value) {
+  set_has_module();
+  module_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:caffe.PythonParameter.module)
+}
+inline void PythonParameter::set_module(const char* value, size_t size) {
+  set_has_module();
+  module_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:caffe.PythonParameter.module)
+}
+inline ::std::string* PythonParameter::mutable_module() {
+  set_has_module();
+  // @@protoc_insertion_point(field_mutable:caffe.PythonParameter.module)
+  return module_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline ::std::string* PythonParameter::release_module() {
+  // @@protoc_insertion_point(field_release:caffe.PythonParameter.module)
+  clear_has_module();
+  return module_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void PythonParameter::set_allocated_module(::std::string* module) {
+  if (module != NULL) {
+    set_has_module();
+  } else {
+    clear_has_module();
+  }
+  module_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), module);
+  // @@protoc_insertion_point(field_set_allocated:caffe.PythonParameter.module)
+}
+
+// optional string layer = 2;
+inline bool PythonParameter::has_layer() const {
+  return (_has_bits_[0] & 0x00000002u) != 0;
+}
+inline void PythonParameter::set_has_layer() {
+  _has_bits_[0] |= 0x00000002u;
+}
+inline void PythonParameter::clear_has_layer() {
+  _has_bits_[0] &= ~0x00000002u;
+}
+inline void PythonParameter::clear_layer() {
+  layer_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  clear_has_layer();
+}
+inline const ::std::string& PythonParameter::layer() const {
+  // @@protoc_insertion_point(field_get:caffe.PythonParameter.layer)
+  return layer_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void PythonParameter::set_layer(const ::std::string& value) {
+  set_has_layer();
+  layer_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:caffe.PythonParameter.layer)
+}
+inline void PythonParameter::set_layer(const char* value) {
+  set_has_layer();
+  layer_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:caffe.PythonParameter.layer)
+}
+inline void PythonParameter::set_layer(const char* value, size_t size) {
+  set_has_layer();
+  layer_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:caffe.PythonParameter.layer)
+}
+inline ::std::string* PythonParameter::mutable_layer() {
+  set_has_layer();
+  // @@protoc_insertion_point(field_mutable:caffe.PythonParameter.layer)
+  return layer_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline ::std::string* PythonParameter::release_layer() {
+  // @@protoc_insertion_point(field_release:caffe.PythonParameter.layer)
+  clear_has_layer();
+  return layer_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void PythonParameter::set_allocated_layer(::std::string* layer) {
+  if (layer != NULL) {
+    set_has_layer();
+  } else {
+    clear_has_layer();
+  }
+  layer_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), layer);
+  // @@protoc_insertion_point(field_set_allocated:caffe.PythonParameter.layer)
+}
+
+inline const PythonParameter* PythonParameter::internal_default_instance() {
+  return &PythonParameter_default_instance_.get();
+}
+// -------------------------------------------------------------------
+
+// ReductionParameter
+
+// optional .caffe.ReductionParameter.ReductionOp operation = 1 [default = SUM];
+inline bool ReductionParameter::has_operation() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+inline void ReductionParameter::set_has_operation() {
+  _has_bits_[0] |= 0x00000001u;
+}
+inline void ReductionParameter::clear_has_operation() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+inline void ReductionParameter::clear_operation() {
+  operation_ = 1;
+  clear_has_operation();
+}
+inline ::caffe::ReductionParameter_ReductionOp ReductionParameter::operation() const {
+  // @@protoc_insertion_point(field_get:caffe.ReductionParameter.operation)
+  return static_cast< ::caffe::ReductionParameter_ReductionOp >(operation_);
+}
+inline void ReductionParameter::set_operation(::caffe::ReductionParameter_ReductionOp value) {
+  assert(::caffe::ReductionParameter_ReductionOp_IsValid(value));
+  set_has_operation();
+  operation_ = value;
+  // @@protoc_insertion_point(field_set:caffe.ReductionParameter.operation)
+}
+
+// optional int32 axis = 2 [default = 0];
+inline bool ReductionParameter::has_axis() const {
+  return (_has_bits_[0] & 0x00000002u) != 0;
+}
+inline void ReductionParameter::set_has_axis() {
+  _has_bits_[0] |= 0x00000002u;
+}
+inline void ReductionParameter::clear_has_axis() {
+  _has_bits_[0] &= ~0x00000002u;
+}
+inline void ReductionParameter::clear_axis() {
+  axis_ = 0;
+  clear_has_axis();
+}
+inline ::google::protobuf::int32 ReductionParameter::axis() const {
+  // @@protoc_insertion_point(field_get:caffe.ReductionParameter.axis)
+  return axis_;
+}
+inline void ReductionParameter::set_axis(::google::protobuf::int32 value) {
+  set_has_axis();
+  axis_ = value;
+  // @@protoc_insertion_point(field_set:caffe.ReductionParameter.axis)
+}
+
+// optional float coeff = 3 [default = 1];
+inline bool ReductionParameter::has_coeff() const {
+  return (_has_bits_[0] & 0x00000004u) != 0;
+}
+inline void ReductionParameter::set_has_coeff() {
+  _has_bits_[0] |= 0x00000004u;
+}
+inline void ReductionParameter::clear_has_coeff() {
+  _has_bits_[0] &= ~0x00000004u;
+}
+inline void ReductionParameter::clear_coeff() {
+  coeff_ = 1;
+  clear_has_coeff();
+}
+inline float ReductionParameter::coeff() const {
+  // @@protoc_insertion_point(field_get:caffe.ReductionParameter.coeff)
+  return coeff_;
+}
+inline void ReductionParameter::set_coeff(float value) {
+  set_has_coeff();
+  coeff_ = value;
+  // @@protoc_insertion_point(field_set:caffe.ReductionParameter.coeff)
+}
+
+inline const ReductionParameter* ReductionParameter::internal_default_instance() {
+  return &ReductionParameter_default_instance_.get();
+}
+// -------------------------------------------------------------------
+
+// ReLUParameter
+
+// optional float negative_slope = 1 [default = 0];
+inline bool ReLUParameter::has_negative_slope() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+inline void ReLUParameter::set_has_negative_slope() {
+  _has_bits_[0] |= 0x00000001u;
+}
+inline void ReLUParameter::clear_has_negative_slope() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+inline void ReLUParameter::clear_negative_slope() {
+  negative_slope_ = 0;
+  clear_has_negative_slope();
+}
+inline float ReLUParameter::negative_slope() const {
+  // @@protoc_insertion_point(field_get:caffe.ReLUParameter.negative_slope)
+  return negative_slope_;
+}
+inline void ReLUParameter::set_negative_slope(float value) {
+  set_has_negative_slope();
+  negative_slope_ = value;
+  // @@protoc_insertion_point(field_set:caffe.ReLUParameter.negative_slope)
+}
+
+// optional .caffe.ReLUParameter.Engine engine = 2 [default = DEFAULT];
+inline bool ReLUParameter::has_engine() const {
+  return (_has_bits_[0] & 0x00000002u) != 0;
+}
+inline void ReLUParameter::set_has_engine() {
+  _has_bits_[0] |= 0x00000002u;
+}
+inline void ReLUParameter::clear_has_engine() {
+  _has_bits_[0] &= ~0x00000002u;
+}
+inline void ReLUParameter::clear_engine() {
+  engine_ = 0;
+  clear_has_engine();
+}
+inline ::caffe::ReLUParameter_Engine ReLUParameter::engine() const {
+  // @@protoc_insertion_point(field_get:caffe.ReLUParameter.engine)
+  return static_cast< ::caffe::ReLUParameter_Engine >(engine_);
+}
+inline void ReLUParameter::set_engine(::caffe::ReLUParameter_Engine value) {
+  assert(::caffe::ReLUParameter_Engine_IsValid(value));
+  set_has_engine();
+  engine_ = value;
+  // @@protoc_insertion_point(field_set:caffe.ReLUParameter.engine)
+}
+
+inline const ReLUParameter* ReLUParameter::internal_default_instance() {
+  return &ReLUParameter_default_instance_.get();
+}
+// -------------------------------------------------------------------
+
+// ReshapeParameter
+
+// optional .caffe.BlobShape shape = 1;
+inline bool ReshapeParameter::has_shape() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+inline void ReshapeParameter::set_has_shape() {
+  _has_bits_[0] |= 0x00000001u;
+}
+inline void ReshapeParameter::clear_has_shape() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+inline void ReshapeParameter::clear_shape() {
+  if (shape_ != NULL) shape_->::caffe::BlobShape::Clear();
+  clear_has_shape();
+}
+inline const ::caffe::BlobShape& ReshapeParameter::shape() const {
+  // @@protoc_insertion_point(field_get:caffe.ReshapeParameter.shape)
+  return shape_ != NULL ? *shape_
+                         : *::caffe::BlobShape::internal_default_instance();
+}
+inline ::caffe::BlobShape* ReshapeParameter::mutable_shape() {
+  set_has_shape();
+  if (shape_ == NULL) {
+    shape_ = new ::caffe::BlobShape;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.ReshapeParameter.shape)
+  return shape_;
+}
+inline ::caffe::BlobShape* ReshapeParameter::release_shape() {
+  // @@protoc_insertion_point(field_release:caffe.ReshapeParameter.shape)
+  clear_has_shape();
+  ::caffe::BlobShape* temp = shape_;
+  shape_ = NULL;
+  return temp;
+}
+inline void ReshapeParameter::set_allocated_shape(::caffe::BlobShape* shape) {
+  delete shape_;
+  shape_ = shape;
+  if (shape) {
+    set_has_shape();
+  } else {
+    clear_has_shape();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.ReshapeParameter.shape)
+}
+
+// optional int32 axis = 2 [default = 0];
+inline bool ReshapeParameter::has_axis() const {
+  return (_has_bits_[0] & 0x00000002u) != 0;
+}
+inline void ReshapeParameter::set_has_axis() {
+  _has_bits_[0] |= 0x00000002u;
+}
+inline void ReshapeParameter::clear_has_axis() {
+  _has_bits_[0] &= ~0x00000002u;
+}
+inline void ReshapeParameter::clear_axis() {
+  axis_ = 0;
+  clear_has_axis();
+}
+inline ::google::protobuf::int32 ReshapeParameter::axis() const {
+  // @@protoc_insertion_point(field_get:caffe.ReshapeParameter.axis)
+  return axis_;
+}
+inline void ReshapeParameter::set_axis(::google::protobuf::int32 value) {
+  set_has_axis();
+  axis_ = value;
+  // @@protoc_insertion_point(field_set:caffe.ReshapeParameter.axis)
+}
+
+// optional int32 num_axes = 3 [default = -1];
+inline bool ReshapeParameter::has_num_axes() const {
+  return (_has_bits_[0] & 0x00000004u) != 0;
+}
+inline void ReshapeParameter::set_has_num_axes() {
+  _has_bits_[0] |= 0x00000004u;
+}
+inline void ReshapeParameter::clear_has_num_axes() {
+  _has_bits_[0] &= ~0x00000004u;
+}
+inline void ReshapeParameter::clear_num_axes() {
+  num_axes_ = -1;
+  clear_has_num_axes();
+}
+inline ::google::protobuf::int32 ReshapeParameter::num_axes() const {
+  // @@protoc_insertion_point(field_get:caffe.ReshapeParameter.num_axes)
+  return num_axes_;
+}
+inline void ReshapeParameter::set_num_axes(::google::protobuf::int32 value) {
+  set_has_num_axes();
+  num_axes_ = value;
+  // @@protoc_insertion_point(field_set:caffe.ReshapeParameter.num_axes)
+}
+
+inline const ReshapeParameter* ReshapeParameter::internal_default_instance() {
+  return &ReshapeParameter_default_instance_.get();
+}
+// -------------------------------------------------------------------
+
+// SigmoidParameter
+
+// optional .caffe.SigmoidParameter.Engine engine = 1 [default = DEFAULT];
+inline bool SigmoidParameter::has_engine() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+inline void SigmoidParameter::set_has_engine() {
+  _has_bits_[0] |= 0x00000001u;
+}
+inline void SigmoidParameter::clear_has_engine() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+inline void SigmoidParameter::clear_engine() {
+  engine_ = 0;
+  clear_has_engine();
+}
+inline ::caffe::SigmoidParameter_Engine SigmoidParameter::engine() const {
+  // @@protoc_insertion_point(field_get:caffe.SigmoidParameter.engine)
+  return static_cast< ::caffe::SigmoidParameter_Engine >(engine_);
+}
+inline void SigmoidParameter::set_engine(::caffe::SigmoidParameter_Engine value) {
+  assert(::caffe::SigmoidParameter_Engine_IsValid(value));
+  set_has_engine();
+  engine_ = value;
+  // @@protoc_insertion_point(field_set:caffe.SigmoidParameter.engine)
+}
+
+inline const SigmoidParameter* SigmoidParameter::internal_default_instance() {
+  return &SigmoidParameter_default_instance_.get();
+}
+// -------------------------------------------------------------------
+
+// SliceParameter
+
+// optional int32 axis = 3 [default = 1];
+inline bool SliceParameter::has_axis() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+inline void SliceParameter::set_has_axis() {
+  _has_bits_[0] |= 0x00000001u;
+}
+inline void SliceParameter::clear_has_axis() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+inline void SliceParameter::clear_axis() {
+  axis_ = 1;
+  clear_has_axis();
+}
+inline ::google::protobuf::int32 SliceParameter::axis() const {
+  // @@protoc_insertion_point(field_get:caffe.SliceParameter.axis)
+  return axis_;
+}
+inline void SliceParameter::set_axis(::google::protobuf::int32 value) {
+  set_has_axis();
+  axis_ = value;
+  // @@protoc_insertion_point(field_set:caffe.SliceParameter.axis)
+}
+
+// repeated uint32 slice_point = 2;
+inline int SliceParameter::slice_point_size() const {
+  return slice_point_.size();
+}
+inline void SliceParameter::clear_slice_point() {
+  slice_point_.Clear();
+}
+inline ::google::protobuf::uint32 SliceParameter::slice_point(int index) const {
+  // @@protoc_insertion_point(field_get:caffe.SliceParameter.slice_point)
+  return slice_point_.Get(index);
+}
+inline void SliceParameter::set_slice_point(int index, ::google::protobuf::uint32 value) {
+  slice_point_.Set(index, value);
+  // @@protoc_insertion_point(field_set:caffe.SliceParameter.slice_point)
+}
+inline void SliceParameter::add_slice_point(::google::protobuf::uint32 value) {
+  slice_point_.Add(value);
+  // @@protoc_insertion_point(field_add:caffe.SliceParameter.slice_point)
+}
+inline const ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >&
+SliceParameter::slice_point() const {
+  // @@protoc_insertion_point(field_list:caffe.SliceParameter.slice_point)
+  return slice_point_;
+}
+inline ::google::protobuf::RepeatedField< ::google::protobuf::uint32 >*
+SliceParameter::mutable_slice_point() {
+  // @@protoc_insertion_point(field_mutable_list:caffe.SliceParameter.slice_point)
+  return &slice_point_;
+}
+
+// optional uint32 slice_dim = 1 [default = 1];
+inline bool SliceParameter::has_slice_dim() const {
+  return (_has_bits_[0] & 0x00000004u) != 0;
+}
+inline void SliceParameter::set_has_slice_dim() {
+  _has_bits_[0] |= 0x00000004u;
+}
+inline void SliceParameter::clear_has_slice_dim() {
+  _has_bits_[0] &= ~0x00000004u;
+}
+inline void SliceParameter::clear_slice_dim() {
+  slice_dim_ = 1u;
+  clear_has_slice_dim();
+}
+inline ::google::protobuf::uint32 SliceParameter::slice_dim() const {
+  // @@protoc_insertion_point(field_get:caffe.SliceParameter.slice_dim)
+  return slice_dim_;
+}
+inline void SliceParameter::set_slice_dim(::google::protobuf::uint32 value) {
+  set_has_slice_dim();
+  slice_dim_ = value;
+  // @@protoc_insertion_point(field_set:caffe.SliceParameter.slice_dim)
+}
+
+inline const SliceParameter* SliceParameter::internal_default_instance() {
+  return &SliceParameter_default_instance_.get();
+}
+// -------------------------------------------------------------------
+
+// SoftmaxParameter
+
+// optional .caffe.SoftmaxParameter.Engine engine = 1 [default = DEFAULT];
+inline bool SoftmaxParameter::has_engine() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+inline void SoftmaxParameter::set_has_engine() {
+  _has_bits_[0] |= 0x00000001u;
+}
+inline void SoftmaxParameter::clear_has_engine() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+inline void SoftmaxParameter::clear_engine() {
+  engine_ = 0;
+  clear_has_engine();
+}
+inline ::caffe::SoftmaxParameter_Engine SoftmaxParameter::engine() const {
+  // @@protoc_insertion_point(field_get:caffe.SoftmaxParameter.engine)
+  return static_cast< ::caffe::SoftmaxParameter_Engine >(engine_);
+}
+inline void SoftmaxParameter::set_engine(::caffe::SoftmaxParameter_Engine value) {
+  assert(::caffe::SoftmaxParameter_Engine_IsValid(value));
+  set_has_engine();
+  engine_ = value;
+  // @@protoc_insertion_point(field_set:caffe.SoftmaxParameter.engine)
+}
+
+// optional int32 axis = 2 [default = 1];
+inline bool SoftmaxParameter::has_axis() const {
+  return (_has_bits_[0] & 0x00000002u) != 0;
+}
+inline void SoftmaxParameter::set_has_axis() {
+  _has_bits_[0] |= 0x00000002u;
+}
+inline void SoftmaxParameter::clear_has_axis() {
+  _has_bits_[0] &= ~0x00000002u;
+}
+inline void SoftmaxParameter::clear_axis() {
+  axis_ = 1;
+  clear_has_axis();
+}
+inline ::google::protobuf::int32 SoftmaxParameter::axis() const {
+  // @@protoc_insertion_point(field_get:caffe.SoftmaxParameter.axis)
+  return axis_;
+}
+inline void SoftmaxParameter::set_axis(::google::protobuf::int32 value) {
+  set_has_axis();
+  axis_ = value;
+  // @@protoc_insertion_point(field_set:caffe.SoftmaxParameter.axis)
+}
+
+inline const SoftmaxParameter* SoftmaxParameter::internal_default_instance() {
+  return &SoftmaxParameter_default_instance_.get();
+}
+// -------------------------------------------------------------------
+
+// TanHParameter
+
+// optional .caffe.TanHParameter.Engine engine = 1 [default = DEFAULT];
+inline bool TanHParameter::has_engine() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+inline void TanHParameter::set_has_engine() {
+  _has_bits_[0] |= 0x00000001u;
+}
+inline void TanHParameter::clear_has_engine() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+inline void TanHParameter::clear_engine() {
+  engine_ = 0;
+  clear_has_engine();
+}
+inline ::caffe::TanHParameter_Engine TanHParameter::engine() const {
+  // @@protoc_insertion_point(field_get:caffe.TanHParameter.engine)
+  return static_cast< ::caffe::TanHParameter_Engine >(engine_);
+}
+inline void TanHParameter::set_engine(::caffe::TanHParameter_Engine value) {
+  assert(::caffe::TanHParameter_Engine_IsValid(value));
+  set_has_engine();
+  engine_ = value;
+  // @@protoc_insertion_point(field_set:caffe.TanHParameter.engine)
+}
+
+inline const TanHParameter* TanHParameter::internal_default_instance() {
+  return &TanHParameter_default_instance_.get();
+}
+// -------------------------------------------------------------------
+
+// ThresholdParameter
+
+// optional float threshold = 1 [default = 0];
+inline bool ThresholdParameter::has_threshold() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+inline void ThresholdParameter::set_has_threshold() {
+  _has_bits_[0] |= 0x00000001u;
+}
+inline void ThresholdParameter::clear_has_threshold() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+inline void ThresholdParameter::clear_threshold() {
+  threshold_ = 0;
+  clear_has_threshold();
+}
+inline float ThresholdParameter::threshold() const {
+  // @@protoc_insertion_point(field_get:caffe.ThresholdParameter.threshold)
+  return threshold_;
+}
+inline void ThresholdParameter::set_threshold(float value) {
+  set_has_threshold();
+  threshold_ = value;
+  // @@protoc_insertion_point(field_set:caffe.ThresholdParameter.threshold)
+}
+
+inline const ThresholdParameter* ThresholdParameter::internal_default_instance() {
+  return &ThresholdParameter_default_instance_.get();
+}
+// -------------------------------------------------------------------
+
+// WindowDataParameter
+
+// optional string source = 1;
+inline bool WindowDataParameter::has_source() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+inline void WindowDataParameter::set_has_source() {
+  _has_bits_[0] |= 0x00000001u;
+}
+inline void WindowDataParameter::clear_has_source() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+inline void WindowDataParameter::clear_source() {
+  source_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  clear_has_source();
+}
+inline const ::std::string& WindowDataParameter::source() const {
+  // @@protoc_insertion_point(field_get:caffe.WindowDataParameter.source)
+  return source_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void WindowDataParameter::set_source(const ::std::string& value) {
+  set_has_source();
+  source_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:caffe.WindowDataParameter.source)
+}
+inline void WindowDataParameter::set_source(const char* value) {
+  set_has_source();
+  source_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:caffe.WindowDataParameter.source)
+}
+inline void WindowDataParameter::set_source(const char* value, size_t size) {
+  set_has_source();
+  source_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:caffe.WindowDataParameter.source)
+}
+inline ::std::string* WindowDataParameter::mutable_source() {
+  set_has_source();
+  // @@protoc_insertion_point(field_mutable:caffe.WindowDataParameter.source)
+  return source_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline ::std::string* WindowDataParameter::release_source() {
+  // @@protoc_insertion_point(field_release:caffe.WindowDataParameter.source)
+  clear_has_source();
+  return source_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void WindowDataParameter::set_allocated_source(::std::string* source) {
+  if (source != NULL) {
+    set_has_source();
+  } else {
+    clear_has_source();
+  }
+  source_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), source);
+  // @@protoc_insertion_point(field_set_allocated:caffe.WindowDataParameter.source)
+}
+
+// optional float scale = 2 [default = 1];
+inline bool WindowDataParameter::has_scale() const {
+  return (_has_bits_[0] & 0x00000002u) != 0;
+}
+inline void WindowDataParameter::set_has_scale() {
+  _has_bits_[0] |= 0x00000002u;
+}
+inline void WindowDataParameter::clear_has_scale() {
+  _has_bits_[0] &= ~0x00000002u;
+}
+inline void WindowDataParameter::clear_scale() {
+  scale_ = 1;
+  clear_has_scale();
+}
+inline float WindowDataParameter::scale() const {
+  // @@protoc_insertion_point(field_get:caffe.WindowDataParameter.scale)
+  return scale_;
+}
+inline void WindowDataParameter::set_scale(float value) {
+  set_has_scale();
+  scale_ = value;
+  // @@protoc_insertion_point(field_set:caffe.WindowDataParameter.scale)
+}
+
+// optional string mean_file = 3;
+inline bool WindowDataParameter::has_mean_file() const {
+  return (_has_bits_[0] & 0x00000004u) != 0;
+}
+inline void WindowDataParameter::set_has_mean_file() {
+  _has_bits_[0] |= 0x00000004u;
+}
+inline void WindowDataParameter::clear_has_mean_file() {
+  _has_bits_[0] &= ~0x00000004u;
+}
+inline void WindowDataParameter::clear_mean_file() {
+  mean_file_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  clear_has_mean_file();
+}
+inline const ::std::string& WindowDataParameter::mean_file() const {
+  // @@protoc_insertion_point(field_get:caffe.WindowDataParameter.mean_file)
+  return mean_file_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void WindowDataParameter::set_mean_file(const ::std::string& value) {
+  set_has_mean_file();
+  mean_file_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:caffe.WindowDataParameter.mean_file)
+}
+inline void WindowDataParameter::set_mean_file(const char* value) {
+  set_has_mean_file();
+  mean_file_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:caffe.WindowDataParameter.mean_file)
+}
+inline void WindowDataParameter::set_mean_file(const char* value, size_t size) {
+  set_has_mean_file();
+  mean_file_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:caffe.WindowDataParameter.mean_file)
+}
+inline ::std::string* WindowDataParameter::mutable_mean_file() {
+  set_has_mean_file();
+  // @@protoc_insertion_point(field_mutable:caffe.WindowDataParameter.mean_file)
+  return mean_file_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline ::std::string* WindowDataParameter::release_mean_file() {
+  // @@protoc_insertion_point(field_release:caffe.WindowDataParameter.mean_file)
+  clear_has_mean_file();
+  return mean_file_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void WindowDataParameter::set_allocated_mean_file(::std::string* mean_file) {
+  if (mean_file != NULL) {
+    set_has_mean_file();
+  } else {
+    clear_has_mean_file();
+  }
+  mean_file_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), mean_file);
+  // @@protoc_insertion_point(field_set_allocated:caffe.WindowDataParameter.mean_file)
+}
+
+// optional uint32 batch_size = 4;
+inline bool WindowDataParameter::has_batch_size() const {
+  return (_has_bits_[0] & 0x00000008u) != 0;
+}
+inline void WindowDataParameter::set_has_batch_size() {
+  _has_bits_[0] |= 0x00000008u;
+}
+inline void WindowDataParameter::clear_has_batch_size() {
+  _has_bits_[0] &= ~0x00000008u;
+}
+inline void WindowDataParameter::clear_batch_size() {
+  batch_size_ = 0u;
+  clear_has_batch_size();
+}
+inline ::google::protobuf::uint32 WindowDataParameter::batch_size() const {
+  // @@protoc_insertion_point(field_get:caffe.WindowDataParameter.batch_size)
+  return batch_size_;
+}
+inline void WindowDataParameter::set_batch_size(::google::protobuf::uint32 value) {
+  set_has_batch_size();
+  batch_size_ = value;
+  // @@protoc_insertion_point(field_set:caffe.WindowDataParameter.batch_size)
+}
+
+// optional uint32 crop_size = 5 [default = 0];
+inline bool WindowDataParameter::has_crop_size() const {
+  return (_has_bits_[0] & 0x00000010u) != 0;
+}
+inline void WindowDataParameter::set_has_crop_size() {
+  _has_bits_[0] |= 0x00000010u;
+}
+inline void WindowDataParameter::clear_has_crop_size() {
+  _has_bits_[0] &= ~0x00000010u;
+}
+inline void WindowDataParameter::clear_crop_size() {
+  crop_size_ = 0u;
+  clear_has_crop_size();
+}
+inline ::google::protobuf::uint32 WindowDataParameter::crop_size() const {
+  // @@protoc_insertion_point(field_get:caffe.WindowDataParameter.crop_size)
+  return crop_size_;
+}
+inline void WindowDataParameter::set_crop_size(::google::protobuf::uint32 value) {
+  set_has_crop_size();
+  crop_size_ = value;
+  // @@protoc_insertion_point(field_set:caffe.WindowDataParameter.crop_size)
+}
+
+// optional bool mirror = 6 [default = false];
+inline bool WindowDataParameter::has_mirror() const {
+  return (_has_bits_[0] & 0x00000020u) != 0;
+}
+inline void WindowDataParameter::set_has_mirror() {
+  _has_bits_[0] |= 0x00000020u;
+}
+inline void WindowDataParameter::clear_has_mirror() {
+  _has_bits_[0] &= ~0x00000020u;
+}
+inline void WindowDataParameter::clear_mirror() {
+  mirror_ = false;
+  clear_has_mirror();
+}
+inline bool WindowDataParameter::mirror() const {
+  // @@protoc_insertion_point(field_get:caffe.WindowDataParameter.mirror)
+  return mirror_;
+}
+inline void WindowDataParameter::set_mirror(bool value) {
+  set_has_mirror();
+  mirror_ = value;
+  // @@protoc_insertion_point(field_set:caffe.WindowDataParameter.mirror)
+}
+
+// optional float fg_threshold = 7 [default = 0.5];
+inline bool WindowDataParameter::has_fg_threshold() const {
+  return (_has_bits_[0] & 0x00000040u) != 0;
+}
+inline void WindowDataParameter::set_has_fg_threshold() {
+  _has_bits_[0] |= 0x00000040u;
+}
+inline void WindowDataParameter::clear_has_fg_threshold() {
+  _has_bits_[0] &= ~0x00000040u;
+}
+inline void WindowDataParameter::clear_fg_threshold() {
+  fg_threshold_ = 0.5f;
+  clear_has_fg_threshold();
+}
+inline float WindowDataParameter::fg_threshold() const {
+  // @@protoc_insertion_point(field_get:caffe.WindowDataParameter.fg_threshold)
+  return fg_threshold_;
+}
+inline void WindowDataParameter::set_fg_threshold(float value) {
+  set_has_fg_threshold();
+  fg_threshold_ = value;
+  // @@protoc_insertion_point(field_set:caffe.WindowDataParameter.fg_threshold)
+}
+
+// optional float bg_threshold = 8 [default = 0.5];
+inline bool WindowDataParameter::has_bg_threshold() const {
+  return (_has_bits_[0] & 0x00000080u) != 0;
+}
+inline void WindowDataParameter::set_has_bg_threshold() {
+  _has_bits_[0] |= 0x00000080u;
+}
+inline void WindowDataParameter::clear_has_bg_threshold() {
+  _has_bits_[0] &= ~0x00000080u;
+}
+inline void WindowDataParameter::clear_bg_threshold() {
+  bg_threshold_ = 0.5f;
+  clear_has_bg_threshold();
+}
+inline float WindowDataParameter::bg_threshold() const {
+  // @@protoc_insertion_point(field_get:caffe.WindowDataParameter.bg_threshold)
+  return bg_threshold_;
+}
+inline void WindowDataParameter::set_bg_threshold(float value) {
+  set_has_bg_threshold();
+  bg_threshold_ = value;
+  // @@protoc_insertion_point(field_set:caffe.WindowDataParameter.bg_threshold)
+}
+
+// optional float fg_fraction = 9 [default = 0.25];
+inline bool WindowDataParameter::has_fg_fraction() const {
+  return (_has_bits_[0] & 0x00000100u) != 0;
+}
+inline void WindowDataParameter::set_has_fg_fraction() {
+  _has_bits_[0] |= 0x00000100u;
+}
+inline void WindowDataParameter::clear_has_fg_fraction() {
+  _has_bits_[0] &= ~0x00000100u;
+}
+inline void WindowDataParameter::clear_fg_fraction() {
+  fg_fraction_ = 0.25f;
+  clear_has_fg_fraction();
+}
+inline float WindowDataParameter::fg_fraction() const {
+  // @@protoc_insertion_point(field_get:caffe.WindowDataParameter.fg_fraction)
+  return fg_fraction_;
+}
+inline void WindowDataParameter::set_fg_fraction(float value) {
+  set_has_fg_fraction();
+  fg_fraction_ = value;
+  // @@protoc_insertion_point(field_set:caffe.WindowDataParameter.fg_fraction)
+}
+
+// optional uint32 context_pad = 10 [default = 0];
+inline bool WindowDataParameter::has_context_pad() const {
+  return (_has_bits_[0] & 0x00000200u) != 0;
+}
+inline void WindowDataParameter::set_has_context_pad() {
+  _has_bits_[0] |= 0x00000200u;
+}
+inline void WindowDataParameter::clear_has_context_pad() {
+  _has_bits_[0] &= ~0x00000200u;
+}
+inline void WindowDataParameter::clear_context_pad() {
+  context_pad_ = 0u;
+  clear_has_context_pad();
+}
+inline ::google::protobuf::uint32 WindowDataParameter::context_pad() const {
+  // @@protoc_insertion_point(field_get:caffe.WindowDataParameter.context_pad)
+  return context_pad_;
+}
+inline void WindowDataParameter::set_context_pad(::google::protobuf::uint32 value) {
+  set_has_context_pad();
+  context_pad_ = value;
+  // @@protoc_insertion_point(field_set:caffe.WindowDataParameter.context_pad)
+}
+
+// optional string crop_mode = 11 [default = "warp"];
+inline bool WindowDataParameter::has_crop_mode() const {
+  return (_has_bits_[0] & 0x00000400u) != 0;
+}
+inline void WindowDataParameter::set_has_crop_mode() {
+  _has_bits_[0] |= 0x00000400u;
+}
+inline void WindowDataParameter::clear_has_crop_mode() {
+  _has_bits_[0] &= ~0x00000400u;
+}
+inline void WindowDataParameter::clear_crop_mode() {
+  crop_mode_.ClearToDefaultNoArena(_default_crop_mode_);
+  clear_has_crop_mode();
+}
+inline const ::std::string& WindowDataParameter::crop_mode() const {
+  // @@protoc_insertion_point(field_get:caffe.WindowDataParameter.crop_mode)
+  return crop_mode_.GetNoArena(_default_crop_mode_);
+}
+inline void WindowDataParameter::set_crop_mode(const ::std::string& value) {
+  set_has_crop_mode();
+  crop_mode_.SetNoArena(_default_crop_mode_, value);
+  // @@protoc_insertion_point(field_set:caffe.WindowDataParameter.crop_mode)
+}
+inline void WindowDataParameter::set_crop_mode(const char* value) {
+  set_has_crop_mode();
+  crop_mode_.SetNoArena(_default_crop_mode_, ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:caffe.WindowDataParameter.crop_mode)
+}
+inline void WindowDataParameter::set_crop_mode(const char* value, size_t size) {
+  set_has_crop_mode();
+  crop_mode_.SetNoArena(_default_crop_mode_,
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:caffe.WindowDataParameter.crop_mode)
+}
+inline ::std::string* WindowDataParameter::mutable_crop_mode() {
+  set_has_crop_mode();
+  // @@protoc_insertion_point(field_mutable:caffe.WindowDataParameter.crop_mode)
+  return crop_mode_.MutableNoArena(_default_crop_mode_);
+}
+inline ::std::string* WindowDataParameter::release_crop_mode() {
+  // @@protoc_insertion_point(field_release:caffe.WindowDataParameter.crop_mode)
+  clear_has_crop_mode();
+  return crop_mode_.ReleaseNoArena(_default_crop_mode_);
+}
+inline void WindowDataParameter::set_allocated_crop_mode(::std::string* crop_mode) {
+  if (crop_mode != NULL) {
+    set_has_crop_mode();
+  } else {
+    clear_has_crop_mode();
+  }
+  crop_mode_.SetAllocatedNoArena(_default_crop_mode_, crop_mode);
+  // @@protoc_insertion_point(field_set_allocated:caffe.WindowDataParameter.crop_mode)
+}
+
+// optional bool cache_images = 12 [default = false];
+inline bool WindowDataParameter::has_cache_images() const {
+  return (_has_bits_[0] & 0x00000800u) != 0;
+}
+inline void WindowDataParameter::set_has_cache_images() {
+  _has_bits_[0] |= 0x00000800u;
+}
+inline void WindowDataParameter::clear_has_cache_images() {
+  _has_bits_[0] &= ~0x00000800u;
+}
+inline void WindowDataParameter::clear_cache_images() {
+  cache_images_ = false;
+  clear_has_cache_images();
+}
+inline bool WindowDataParameter::cache_images() const {
+  // @@protoc_insertion_point(field_get:caffe.WindowDataParameter.cache_images)
+  return cache_images_;
+}
+inline void WindowDataParameter::set_cache_images(bool value) {
+  set_has_cache_images();
+  cache_images_ = value;
+  // @@protoc_insertion_point(field_set:caffe.WindowDataParameter.cache_images)
+}
+
+// optional string root_folder = 13 [default = ""];
+inline bool WindowDataParameter::has_root_folder() const {
+  return (_has_bits_[0] & 0x00001000u) != 0;
+}
+inline void WindowDataParameter::set_has_root_folder() {
+  _has_bits_[0] |= 0x00001000u;
+}
+inline void WindowDataParameter::clear_has_root_folder() {
+  _has_bits_[0] &= ~0x00001000u;
+}
+inline void WindowDataParameter::clear_root_folder() {
+  root_folder_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  clear_has_root_folder();
+}
+inline const ::std::string& WindowDataParameter::root_folder() const {
+  // @@protoc_insertion_point(field_get:caffe.WindowDataParameter.root_folder)
+  return root_folder_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void WindowDataParameter::set_root_folder(const ::std::string& value) {
+  set_has_root_folder();
+  root_folder_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:caffe.WindowDataParameter.root_folder)
+}
+inline void WindowDataParameter::set_root_folder(const char* value) {
+  set_has_root_folder();
+  root_folder_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:caffe.WindowDataParameter.root_folder)
+}
+inline void WindowDataParameter::set_root_folder(const char* value, size_t size) {
+  set_has_root_folder();
+  root_folder_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:caffe.WindowDataParameter.root_folder)
+}
+inline ::std::string* WindowDataParameter::mutable_root_folder() {
+  set_has_root_folder();
+  // @@protoc_insertion_point(field_mutable:caffe.WindowDataParameter.root_folder)
+  return root_folder_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline ::std::string* WindowDataParameter::release_root_folder() {
+  // @@protoc_insertion_point(field_release:caffe.WindowDataParameter.root_folder)
+  clear_has_root_folder();
+  return root_folder_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void WindowDataParameter::set_allocated_root_folder(::std::string* root_folder) {
+  if (root_folder != NULL) {
+    set_has_root_folder();
+  } else {
+    clear_has_root_folder();
+  }
+  root_folder_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), root_folder);
+  // @@protoc_insertion_point(field_set_allocated:caffe.WindowDataParameter.root_folder)
+}
+
+inline const WindowDataParameter* WindowDataParameter::internal_default_instance() {
+  return &WindowDataParameter_default_instance_.get();
+}
+// -------------------------------------------------------------------
+
+// SPPParameter
+
+// optional uint32 pyramid_height = 1;
+inline bool SPPParameter::has_pyramid_height() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+inline void SPPParameter::set_has_pyramid_height() {
+  _has_bits_[0] |= 0x00000001u;
+}
+inline void SPPParameter::clear_has_pyramid_height() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+inline void SPPParameter::clear_pyramid_height() {
+  pyramid_height_ = 0u;
+  clear_has_pyramid_height();
+}
+inline ::google::protobuf::uint32 SPPParameter::pyramid_height() const {
+  // @@protoc_insertion_point(field_get:caffe.SPPParameter.pyramid_height)
+  return pyramid_height_;
+}
+inline void SPPParameter::set_pyramid_height(::google::protobuf::uint32 value) {
+  set_has_pyramid_height();
+  pyramid_height_ = value;
+  // @@protoc_insertion_point(field_set:caffe.SPPParameter.pyramid_height)
+}
+
+// optional .caffe.SPPParameter.PoolMethod pool = 2 [default = MAX];
+inline bool SPPParameter::has_pool() const {
+  return (_has_bits_[0] & 0x00000002u) != 0;
+}
+inline void SPPParameter::set_has_pool() {
+  _has_bits_[0] |= 0x00000002u;
+}
+inline void SPPParameter::clear_has_pool() {
+  _has_bits_[0] &= ~0x00000002u;
+}
+inline void SPPParameter::clear_pool() {
+  pool_ = 0;
+  clear_has_pool();
+}
+inline ::caffe::SPPParameter_PoolMethod SPPParameter::pool() const {
+  // @@protoc_insertion_point(field_get:caffe.SPPParameter.pool)
+  return static_cast< ::caffe::SPPParameter_PoolMethod >(pool_);
+}
+inline void SPPParameter::set_pool(::caffe::SPPParameter_PoolMethod value) {
+  assert(::caffe::SPPParameter_PoolMethod_IsValid(value));
+  set_has_pool();
+  pool_ = value;
+  // @@protoc_insertion_point(field_set:caffe.SPPParameter.pool)
+}
+
+// optional .caffe.SPPParameter.Engine engine = 6 [default = DEFAULT];
+inline bool SPPParameter::has_engine() const {
+  return (_has_bits_[0] & 0x00000004u) != 0;
+}
+inline void SPPParameter::set_has_engine() {
+  _has_bits_[0] |= 0x00000004u;
+}
+inline void SPPParameter::clear_has_engine() {
+  _has_bits_[0] &= ~0x00000004u;
+}
+inline void SPPParameter::clear_engine() {
+  engine_ = 0;
+  clear_has_engine();
+}
+inline ::caffe::SPPParameter_Engine SPPParameter::engine() const {
+  // @@protoc_insertion_point(field_get:caffe.SPPParameter.engine)
+  return static_cast< ::caffe::SPPParameter_Engine >(engine_);
+}
+inline void SPPParameter::set_engine(::caffe::SPPParameter_Engine value) {
+  assert(::caffe::SPPParameter_Engine_IsValid(value));
+  set_has_engine();
+  engine_ = value;
+  // @@protoc_insertion_point(field_set:caffe.SPPParameter.engine)
+}
+
+inline const SPPParameter* SPPParameter::internal_default_instance() {
+  return &SPPParameter_default_instance_.get();
+}
+// -------------------------------------------------------------------
+
+// V1LayerParameter
+
+// repeated string bottom = 2;
+inline int V1LayerParameter::bottom_size() const {
+  return bottom_.size();
+}
+inline void V1LayerParameter::clear_bottom() {
+  bottom_.Clear();
+}
+inline const ::std::string& V1LayerParameter::bottom(int index) const {
+  // @@protoc_insertion_point(field_get:caffe.V1LayerParameter.bottom)
+  return bottom_.Get(index);
+}
+inline ::std::string* V1LayerParameter::mutable_bottom(int index) {
+  // @@protoc_insertion_point(field_mutable:caffe.V1LayerParameter.bottom)
+  return bottom_.Mutable(index);
+}
+inline void V1LayerParameter::set_bottom(int index, const ::std::string& value) {
+  // @@protoc_insertion_point(field_set:caffe.V1LayerParameter.bottom)
+  bottom_.Mutable(index)->assign(value);
+}
+inline void V1LayerParameter::set_bottom(int index, const char* value) {
+  bottom_.Mutable(index)->assign(value);
+  // @@protoc_insertion_point(field_set_char:caffe.V1LayerParameter.bottom)
+}
+inline void V1LayerParameter::set_bottom(int index, const char* value, size_t size) {
+  bottom_.Mutable(index)->assign(
+    reinterpret_cast<const char*>(value), size);
+  // @@protoc_insertion_point(field_set_pointer:caffe.V1LayerParameter.bottom)
+}
+inline ::std::string* V1LayerParameter::add_bottom() {
+  // @@protoc_insertion_point(field_add_mutable:caffe.V1LayerParameter.bottom)
+  return bottom_.Add();
+}
+inline void V1LayerParameter::add_bottom(const ::std::string& value) {
+  bottom_.Add()->assign(value);
+  // @@protoc_insertion_point(field_add:caffe.V1LayerParameter.bottom)
+}
+inline void V1LayerParameter::add_bottom(const char* value) {
+  bottom_.Add()->assign(value);
+  // @@protoc_insertion_point(field_add_char:caffe.V1LayerParameter.bottom)
+}
+inline void V1LayerParameter::add_bottom(const char* value, size_t size) {
+  bottom_.Add()->assign(reinterpret_cast<const char*>(value), size);
+  // @@protoc_insertion_point(field_add_pointer:caffe.V1LayerParameter.bottom)
+}
+inline const ::google::protobuf::RepeatedPtrField< ::std::string>&
+V1LayerParameter::bottom() const {
+  // @@protoc_insertion_point(field_list:caffe.V1LayerParameter.bottom)
+  return bottom_;
+}
+inline ::google::protobuf::RepeatedPtrField< ::std::string>*
+V1LayerParameter::mutable_bottom() {
+  // @@protoc_insertion_point(field_mutable_list:caffe.V1LayerParameter.bottom)
+  return &bottom_;
+}
+
+// repeated string top = 3;
+inline int V1LayerParameter::top_size() const {
+  return top_.size();
+}
+inline void V1LayerParameter::clear_top() {
+  top_.Clear();
+}
+inline const ::std::string& V1LayerParameter::top(int index) const {
+  // @@protoc_insertion_point(field_get:caffe.V1LayerParameter.top)
+  return top_.Get(index);
+}
+inline ::std::string* V1LayerParameter::mutable_top(int index) {
+  // @@protoc_insertion_point(field_mutable:caffe.V1LayerParameter.top)
+  return top_.Mutable(index);
+}
+inline void V1LayerParameter::set_top(int index, const ::std::string& value) {
+  // @@protoc_insertion_point(field_set:caffe.V1LayerParameter.top)
+  top_.Mutable(index)->assign(value);
+}
+inline void V1LayerParameter::set_top(int index, const char* value) {
+  top_.Mutable(index)->assign(value);
+  // @@protoc_insertion_point(field_set_char:caffe.V1LayerParameter.top)
+}
+inline void V1LayerParameter::set_top(int index, const char* value, size_t size) {
+  top_.Mutable(index)->assign(
+    reinterpret_cast<const char*>(value), size);
+  // @@protoc_insertion_point(field_set_pointer:caffe.V1LayerParameter.top)
+}
+inline ::std::string* V1LayerParameter::add_top() {
+  // @@protoc_insertion_point(field_add_mutable:caffe.V1LayerParameter.top)
+  return top_.Add();
+}
+inline void V1LayerParameter::add_top(const ::std::string& value) {
+  top_.Add()->assign(value);
+  // @@protoc_insertion_point(field_add:caffe.V1LayerParameter.top)
+}
+inline void V1LayerParameter::add_top(const char* value) {
+  top_.Add()->assign(value);
+  // @@protoc_insertion_point(field_add_char:caffe.V1LayerParameter.top)
+}
+inline void V1LayerParameter::add_top(const char* value, size_t size) {
+  top_.Add()->assign(reinterpret_cast<const char*>(value), size);
+  // @@protoc_insertion_point(field_add_pointer:caffe.V1LayerParameter.top)
+}
+inline const ::google::protobuf::RepeatedPtrField< ::std::string>&
+V1LayerParameter::top() const {
+  // @@protoc_insertion_point(field_list:caffe.V1LayerParameter.top)
+  return top_;
+}
+inline ::google::protobuf::RepeatedPtrField< ::std::string>*
+V1LayerParameter::mutable_top() {
+  // @@protoc_insertion_point(field_mutable_list:caffe.V1LayerParameter.top)
+  return &top_;
+}
+
+// optional string name = 4;
+inline bool V1LayerParameter::has_name() const {
+  return (_has_bits_[0] & 0x00000004u) != 0;
+}
+inline void V1LayerParameter::set_has_name() {
+  _has_bits_[0] |= 0x00000004u;
+}
+inline void V1LayerParameter::clear_has_name() {
+  _has_bits_[0] &= ~0x00000004u;
+}
+inline void V1LayerParameter::clear_name() {
+  name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  clear_has_name();
+}
+inline const ::std::string& V1LayerParameter::name() const {
+  // @@protoc_insertion_point(field_get:caffe.V1LayerParameter.name)
+  return name_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void V1LayerParameter::set_name(const ::std::string& value) {
+  set_has_name();
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:caffe.V1LayerParameter.name)
+}
+inline void V1LayerParameter::set_name(const char* value) {
+  set_has_name();
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:caffe.V1LayerParameter.name)
+}
+inline void V1LayerParameter::set_name(const char* value, size_t size) {
+  set_has_name();
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:caffe.V1LayerParameter.name)
+}
+inline ::std::string* V1LayerParameter::mutable_name() {
+  set_has_name();
+  // @@protoc_insertion_point(field_mutable:caffe.V1LayerParameter.name)
+  return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline ::std::string* V1LayerParameter::release_name() {
+  // @@protoc_insertion_point(field_release:caffe.V1LayerParameter.name)
+  clear_has_name();
+  return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void V1LayerParameter::set_allocated_name(::std::string* name) {
+  if (name != NULL) {
+    set_has_name();
+  } else {
+    clear_has_name();
+  }
+  name_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), name);
+  // @@protoc_insertion_point(field_set_allocated:caffe.V1LayerParameter.name)
+}
+
+// repeated .caffe.NetStateRule include = 32;
+inline int V1LayerParameter::include_size() const {
+  return include_.size();
+}
+inline void V1LayerParameter::clear_include() {
+  include_.Clear();
+}
+inline const ::caffe::NetStateRule& V1LayerParameter::include(int index) const {
+  // @@protoc_insertion_point(field_get:caffe.V1LayerParameter.include)
+  return include_.Get(index);
+}
+inline ::caffe::NetStateRule* V1LayerParameter::mutable_include(int index) {
+  // @@protoc_insertion_point(field_mutable:caffe.V1LayerParameter.include)
+  return include_.Mutable(index);
+}
+inline ::caffe::NetStateRule* V1LayerParameter::add_include() {
+  // @@protoc_insertion_point(field_add:caffe.V1LayerParameter.include)
+  return include_.Add();
+}
+inline ::google::protobuf::RepeatedPtrField< ::caffe::NetStateRule >*
+V1LayerParameter::mutable_include() {
+  // @@protoc_insertion_point(field_mutable_list:caffe.V1LayerParameter.include)
+  return &include_;
+}
+inline const ::google::protobuf::RepeatedPtrField< ::caffe::NetStateRule >&
+V1LayerParameter::include() const {
+  // @@protoc_insertion_point(field_list:caffe.V1LayerParameter.include)
+  return include_;
+}
+
+// repeated .caffe.NetStateRule exclude = 33;
+inline int V1LayerParameter::exclude_size() const {
+  return exclude_.size();
+}
+inline void V1LayerParameter::clear_exclude() {
+  exclude_.Clear();
+}
+inline const ::caffe::NetStateRule& V1LayerParameter::exclude(int index) const {
+  // @@protoc_insertion_point(field_get:caffe.V1LayerParameter.exclude)
+  return exclude_.Get(index);
+}
+inline ::caffe::NetStateRule* V1LayerParameter::mutable_exclude(int index) {
+  // @@protoc_insertion_point(field_mutable:caffe.V1LayerParameter.exclude)
+  return exclude_.Mutable(index);
+}
+inline ::caffe::NetStateRule* V1LayerParameter::add_exclude() {
+  // @@protoc_insertion_point(field_add:caffe.V1LayerParameter.exclude)
+  return exclude_.Add();
+}
+inline ::google::protobuf::RepeatedPtrField< ::caffe::NetStateRule >*
+V1LayerParameter::mutable_exclude() {
+  // @@protoc_insertion_point(field_mutable_list:caffe.V1LayerParameter.exclude)
+  return &exclude_;
+}
+inline const ::google::protobuf::RepeatedPtrField< ::caffe::NetStateRule >&
+V1LayerParameter::exclude() const {
+  // @@protoc_insertion_point(field_list:caffe.V1LayerParameter.exclude)
+  return exclude_;
+}
+
+// optional .caffe.V1LayerParameter.LayerType type = 5;
+inline bool V1LayerParameter::has_type() const {
+  return (_has_bits_[0] & 0x00000020u) != 0;
+}
+inline void V1LayerParameter::set_has_type() {
+  _has_bits_[0] |= 0x00000020u;
+}
+inline void V1LayerParameter::clear_has_type() {
+  _has_bits_[0] &= ~0x00000020u;
+}
+inline void V1LayerParameter::clear_type() {
+  type_ = 0;
+  clear_has_type();
+}
+inline ::caffe::V1LayerParameter_LayerType V1LayerParameter::type() const {
+  // @@protoc_insertion_point(field_get:caffe.V1LayerParameter.type)
+  return static_cast< ::caffe::V1LayerParameter_LayerType >(type_);
+}
+inline void V1LayerParameter::set_type(::caffe::V1LayerParameter_LayerType value) {
+  assert(::caffe::V1LayerParameter_LayerType_IsValid(value));
+  set_has_type();
+  type_ = value;
+  // @@protoc_insertion_point(field_set:caffe.V1LayerParameter.type)
+}
+
+// repeated .caffe.BlobProto blobs = 6;
+inline int V1LayerParameter::blobs_size() const {
+  return blobs_.size();
+}
+inline void V1LayerParameter::clear_blobs() {
+  blobs_.Clear();
+}
+inline const ::caffe::BlobProto& V1LayerParameter::blobs(int index) const {
+  // @@protoc_insertion_point(field_get:caffe.V1LayerParameter.blobs)
+  return blobs_.Get(index);
+}
+inline ::caffe::BlobProto* V1LayerParameter::mutable_blobs(int index) {
+  // @@protoc_insertion_point(field_mutable:caffe.V1LayerParameter.blobs)
+  return blobs_.Mutable(index);
+}
+inline ::caffe::BlobProto* V1LayerParameter::add_blobs() {
+  // @@protoc_insertion_point(field_add:caffe.V1LayerParameter.blobs)
+  return blobs_.Add();
+}
+inline ::google::protobuf::RepeatedPtrField< ::caffe::BlobProto >*
+V1LayerParameter::mutable_blobs() {
+  // @@protoc_insertion_point(field_mutable_list:caffe.V1LayerParameter.blobs)
+  return &blobs_;
+}
+inline const ::google::protobuf::RepeatedPtrField< ::caffe::BlobProto >&
+V1LayerParameter::blobs() const {
+  // @@protoc_insertion_point(field_list:caffe.V1LayerParameter.blobs)
+  return blobs_;
+}
+
+// repeated string param = 1001;
+inline int V1LayerParameter::param_size() const {
+  return param_.size();
+}
+inline void V1LayerParameter::clear_param() {
+  param_.Clear();
+}
+inline const ::std::string& V1LayerParameter::param(int index) const {
+  // @@protoc_insertion_point(field_get:caffe.V1LayerParameter.param)
+  return param_.Get(index);
+}
+inline ::std::string* V1LayerParameter::mutable_param(int index) {
+  // @@protoc_insertion_point(field_mutable:caffe.V1LayerParameter.param)
+  return param_.Mutable(index);
+}
+inline void V1LayerParameter::set_param(int index, const ::std::string& value) {
+  // @@protoc_insertion_point(field_set:caffe.V1LayerParameter.param)
+  param_.Mutable(index)->assign(value);
+}
+inline void V1LayerParameter::set_param(int index, const char* value) {
+  param_.Mutable(index)->assign(value);
+  // @@protoc_insertion_point(field_set_char:caffe.V1LayerParameter.param)
+}
+inline void V1LayerParameter::set_param(int index, const char* value, size_t size) {
+  param_.Mutable(index)->assign(
+    reinterpret_cast<const char*>(value), size);
+  // @@protoc_insertion_point(field_set_pointer:caffe.V1LayerParameter.param)
+}
+inline ::std::string* V1LayerParameter::add_param() {
+  // @@protoc_insertion_point(field_add_mutable:caffe.V1LayerParameter.param)
+  return param_.Add();
+}
+inline void V1LayerParameter::add_param(const ::std::string& value) {
+  param_.Add()->assign(value);
+  // @@protoc_insertion_point(field_add:caffe.V1LayerParameter.param)
+}
+inline void V1LayerParameter::add_param(const char* value) {
+  param_.Add()->assign(value);
+  // @@protoc_insertion_point(field_add_char:caffe.V1LayerParameter.param)
+}
+inline void V1LayerParameter::add_param(const char* value, size_t size) {
+  param_.Add()->assign(reinterpret_cast<const char*>(value), size);
+  // @@protoc_insertion_point(field_add_pointer:caffe.V1LayerParameter.param)
+}
+inline const ::google::protobuf::RepeatedPtrField< ::std::string>&
+V1LayerParameter::param() const {
+  // @@protoc_insertion_point(field_list:caffe.V1LayerParameter.param)
+  return param_;
+}
+inline ::google::protobuf::RepeatedPtrField< ::std::string>*
+V1LayerParameter::mutable_param() {
+  // @@protoc_insertion_point(field_mutable_list:caffe.V1LayerParameter.param)
+  return &param_;
+}
+
+// repeated .caffe.V1LayerParameter.DimCheckMode blob_share_mode = 1002;
+inline int V1LayerParameter::blob_share_mode_size() const {
+  return blob_share_mode_.size();
+}
+inline void V1LayerParameter::clear_blob_share_mode() {
+  blob_share_mode_.Clear();
+}
+inline ::caffe::V1LayerParameter_DimCheckMode V1LayerParameter::blob_share_mode(int index) const {
+  // @@protoc_insertion_point(field_get:caffe.V1LayerParameter.blob_share_mode)
+  return static_cast< ::caffe::V1LayerParameter_DimCheckMode >(blob_share_mode_.Get(index));
+}
+inline void V1LayerParameter::set_blob_share_mode(int index, ::caffe::V1LayerParameter_DimCheckMode value) {
+  assert(::caffe::V1LayerParameter_DimCheckMode_IsValid(value));
+  blob_share_mode_.Set(index, value);
+  // @@protoc_insertion_point(field_set:caffe.V1LayerParameter.blob_share_mode)
+}
+inline void V1LayerParameter::add_blob_share_mode(::caffe::V1LayerParameter_DimCheckMode value) {
+  assert(::caffe::V1LayerParameter_DimCheckMode_IsValid(value));
+  blob_share_mode_.Add(value);
+  // @@protoc_insertion_point(field_add:caffe.V1LayerParameter.blob_share_mode)
+}
+inline const ::google::protobuf::RepeatedField<int>&
+V1LayerParameter::blob_share_mode() const {
+  // @@protoc_insertion_point(field_list:caffe.V1LayerParameter.blob_share_mode)
+  return blob_share_mode_;
+}
+inline ::google::protobuf::RepeatedField<int>*
+V1LayerParameter::mutable_blob_share_mode() {
+  // @@protoc_insertion_point(field_mutable_list:caffe.V1LayerParameter.blob_share_mode)
+  return &blob_share_mode_;
+}
+
+// repeated float blobs_lr = 7;
+inline int V1LayerParameter::blobs_lr_size() const {
+  return blobs_lr_.size();
+}
+inline void V1LayerParameter::clear_blobs_lr() {
+  blobs_lr_.Clear();
+}
+inline float V1LayerParameter::blobs_lr(int index) const {
+  // @@protoc_insertion_point(field_get:caffe.V1LayerParameter.blobs_lr)
+  return blobs_lr_.Get(index);
+}
+inline void V1LayerParameter::set_blobs_lr(int index, float value) {
+  blobs_lr_.Set(index, value);
+  // @@protoc_insertion_point(field_set:caffe.V1LayerParameter.blobs_lr)
+}
+inline void V1LayerParameter::add_blobs_lr(float value) {
+  blobs_lr_.Add(value);
+  // @@protoc_insertion_point(field_add:caffe.V1LayerParameter.blobs_lr)
+}
+inline const ::google::protobuf::RepeatedField< float >&
+V1LayerParameter::blobs_lr() const {
+  // @@protoc_insertion_point(field_list:caffe.V1LayerParameter.blobs_lr)
+  return blobs_lr_;
+}
+inline ::google::protobuf::RepeatedField< float >*
+V1LayerParameter::mutable_blobs_lr() {
+  // @@protoc_insertion_point(field_mutable_list:caffe.V1LayerParameter.blobs_lr)
+  return &blobs_lr_;
+}
+
+// repeated float weight_decay = 8;
+inline int V1LayerParameter::weight_decay_size() const {
+  return weight_decay_.size();
+}
+inline void V1LayerParameter::clear_weight_decay() {
+  weight_decay_.Clear();
+}
+inline float V1LayerParameter::weight_decay(int index) const {
+  // @@protoc_insertion_point(field_get:caffe.V1LayerParameter.weight_decay)
+  return weight_decay_.Get(index);
+}
+inline void V1LayerParameter::set_weight_decay(int index, float value) {
+  weight_decay_.Set(index, value);
+  // @@protoc_insertion_point(field_set:caffe.V1LayerParameter.weight_decay)
+}
+inline void V1LayerParameter::add_weight_decay(float value) {
+  weight_decay_.Add(value);
+  // @@protoc_insertion_point(field_add:caffe.V1LayerParameter.weight_decay)
+}
+inline const ::google::protobuf::RepeatedField< float >&
+V1LayerParameter::weight_decay() const {
+  // @@protoc_insertion_point(field_list:caffe.V1LayerParameter.weight_decay)
+  return weight_decay_;
+}
+inline ::google::protobuf::RepeatedField< float >*
+V1LayerParameter::mutable_weight_decay() {
+  // @@protoc_insertion_point(field_mutable_list:caffe.V1LayerParameter.weight_decay)
+  return &weight_decay_;
+}
+
+// repeated float loss_weight = 35;
+inline int V1LayerParameter::loss_weight_size() const {
+  return loss_weight_.size();
+}
+inline void V1LayerParameter::clear_loss_weight() {
+  loss_weight_.Clear();
+}
+inline float V1LayerParameter::loss_weight(int index) const {
+  // @@protoc_insertion_point(field_get:caffe.V1LayerParameter.loss_weight)
+  return loss_weight_.Get(index);
+}
+inline void V1LayerParameter::set_loss_weight(int index, float value) {
+  loss_weight_.Set(index, value);
+  // @@protoc_insertion_point(field_set:caffe.V1LayerParameter.loss_weight)
+}
+inline void V1LayerParameter::add_loss_weight(float value) {
+  loss_weight_.Add(value);
+  // @@protoc_insertion_point(field_add:caffe.V1LayerParameter.loss_weight)
+}
+inline const ::google::protobuf::RepeatedField< float >&
+V1LayerParameter::loss_weight() const {
+  // @@protoc_insertion_point(field_list:caffe.V1LayerParameter.loss_weight)
+  return loss_weight_;
+}
+inline ::google::protobuf::RepeatedField< float >*
+V1LayerParameter::mutable_loss_weight() {
+  // @@protoc_insertion_point(field_mutable_list:caffe.V1LayerParameter.loss_weight)
+  return &loss_weight_;
+}
+
+// optional .caffe.AccuracyParameter accuracy_param = 27;
+inline bool V1LayerParameter::has_accuracy_param() const {
+  return (_has_bits_[0] & 0x00001000u) != 0;
+}
+inline void V1LayerParameter::set_has_accuracy_param() {
+  _has_bits_[0] |= 0x00001000u;
+}
+inline void V1LayerParameter::clear_has_accuracy_param() {
+  _has_bits_[0] &= ~0x00001000u;
+}
+inline void V1LayerParameter::clear_accuracy_param() {
+  if (accuracy_param_ != NULL) accuracy_param_->::caffe::AccuracyParameter::Clear();
+  clear_has_accuracy_param();
+}
+inline const ::caffe::AccuracyParameter& V1LayerParameter::accuracy_param() const {
+  // @@protoc_insertion_point(field_get:caffe.V1LayerParameter.accuracy_param)
+  return accuracy_param_ != NULL ? *accuracy_param_
+                         : *::caffe::AccuracyParameter::internal_default_instance();
+}
+inline ::caffe::AccuracyParameter* V1LayerParameter::mutable_accuracy_param() {
+  set_has_accuracy_param();
+  if (accuracy_param_ == NULL) {
+    accuracy_param_ = new ::caffe::AccuracyParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.V1LayerParameter.accuracy_param)
+  return accuracy_param_;
+}
+inline ::caffe::AccuracyParameter* V1LayerParameter::release_accuracy_param() {
+  // @@protoc_insertion_point(field_release:caffe.V1LayerParameter.accuracy_param)
+  clear_has_accuracy_param();
+  ::caffe::AccuracyParameter* temp = accuracy_param_;
+  accuracy_param_ = NULL;
+  return temp;
+}
+inline void V1LayerParameter::set_allocated_accuracy_param(::caffe::AccuracyParameter* accuracy_param) {
+  delete accuracy_param_;
+  accuracy_param_ = accuracy_param;
+  if (accuracy_param) {
+    set_has_accuracy_param();
+  } else {
+    clear_has_accuracy_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.V1LayerParameter.accuracy_param)
+}
+
+// optional .caffe.ArgMaxParameter argmax_param = 23;
+inline bool V1LayerParameter::has_argmax_param() const {
+  return (_has_bits_[0] & 0x00002000u) != 0;
+}
+inline void V1LayerParameter::set_has_argmax_param() {
+  _has_bits_[0] |= 0x00002000u;
+}
+inline void V1LayerParameter::clear_has_argmax_param() {
+  _has_bits_[0] &= ~0x00002000u;
+}
+inline void V1LayerParameter::clear_argmax_param() {
+  if (argmax_param_ != NULL) argmax_param_->::caffe::ArgMaxParameter::Clear();
+  clear_has_argmax_param();
+}
+inline const ::caffe::ArgMaxParameter& V1LayerParameter::argmax_param() const {
+  // @@protoc_insertion_point(field_get:caffe.V1LayerParameter.argmax_param)
+  return argmax_param_ != NULL ? *argmax_param_
+                         : *::caffe::ArgMaxParameter::internal_default_instance();
+}
+inline ::caffe::ArgMaxParameter* V1LayerParameter::mutable_argmax_param() {
+  set_has_argmax_param();
+  if (argmax_param_ == NULL) {
+    argmax_param_ = new ::caffe::ArgMaxParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.V1LayerParameter.argmax_param)
+  return argmax_param_;
+}
+inline ::caffe::ArgMaxParameter* V1LayerParameter::release_argmax_param() {
+  // @@protoc_insertion_point(field_release:caffe.V1LayerParameter.argmax_param)
+  clear_has_argmax_param();
+  ::caffe::ArgMaxParameter* temp = argmax_param_;
+  argmax_param_ = NULL;
+  return temp;
+}
+inline void V1LayerParameter::set_allocated_argmax_param(::caffe::ArgMaxParameter* argmax_param) {
+  delete argmax_param_;
+  argmax_param_ = argmax_param;
+  if (argmax_param) {
+    set_has_argmax_param();
+  } else {
+    clear_has_argmax_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.V1LayerParameter.argmax_param)
+}
+
+// optional .caffe.ConcatParameter concat_param = 9;
+inline bool V1LayerParameter::has_concat_param() const {
+  return (_has_bits_[0] & 0x00004000u) != 0;
+}
+inline void V1LayerParameter::set_has_concat_param() {
+  _has_bits_[0] |= 0x00004000u;
+}
+inline void V1LayerParameter::clear_has_concat_param() {
+  _has_bits_[0] &= ~0x00004000u;
+}
+inline void V1LayerParameter::clear_concat_param() {
+  if (concat_param_ != NULL) concat_param_->::caffe::ConcatParameter::Clear();
+  clear_has_concat_param();
+}
+inline const ::caffe::ConcatParameter& V1LayerParameter::concat_param() const {
+  // @@protoc_insertion_point(field_get:caffe.V1LayerParameter.concat_param)
+  return concat_param_ != NULL ? *concat_param_
+                         : *::caffe::ConcatParameter::internal_default_instance();
+}
+inline ::caffe::ConcatParameter* V1LayerParameter::mutable_concat_param() {
+  set_has_concat_param();
+  if (concat_param_ == NULL) {
+    concat_param_ = new ::caffe::ConcatParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.V1LayerParameter.concat_param)
+  return concat_param_;
+}
+inline ::caffe::ConcatParameter* V1LayerParameter::release_concat_param() {
+  // @@protoc_insertion_point(field_release:caffe.V1LayerParameter.concat_param)
+  clear_has_concat_param();
+  ::caffe::ConcatParameter* temp = concat_param_;
+  concat_param_ = NULL;
+  return temp;
+}
+inline void V1LayerParameter::set_allocated_concat_param(::caffe::ConcatParameter* concat_param) {
+  delete concat_param_;
+  concat_param_ = concat_param;
+  if (concat_param) {
+    set_has_concat_param();
+  } else {
+    clear_has_concat_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.V1LayerParameter.concat_param)
+}
+
+// optional .caffe.ContrastiveLossParameter contrastive_loss_param = 40;
+inline bool V1LayerParameter::has_contrastive_loss_param() const {
+  return (_has_bits_[0] & 0x00008000u) != 0;
+}
+inline void V1LayerParameter::set_has_contrastive_loss_param() {
+  _has_bits_[0] |= 0x00008000u;
+}
+inline void V1LayerParameter::clear_has_contrastive_loss_param() {
+  _has_bits_[0] &= ~0x00008000u;
+}
+inline void V1LayerParameter::clear_contrastive_loss_param() {
+  if (contrastive_loss_param_ != NULL) contrastive_loss_param_->::caffe::ContrastiveLossParameter::Clear();
+  clear_has_contrastive_loss_param();
+}
+inline const ::caffe::ContrastiveLossParameter& V1LayerParameter::contrastive_loss_param() const {
+  // @@protoc_insertion_point(field_get:caffe.V1LayerParameter.contrastive_loss_param)
+  return contrastive_loss_param_ != NULL ? *contrastive_loss_param_
+                         : *::caffe::ContrastiveLossParameter::internal_default_instance();
+}
+inline ::caffe::ContrastiveLossParameter* V1LayerParameter::mutable_contrastive_loss_param() {
+  set_has_contrastive_loss_param();
+  if (contrastive_loss_param_ == NULL) {
+    contrastive_loss_param_ = new ::caffe::ContrastiveLossParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.V1LayerParameter.contrastive_loss_param)
+  return contrastive_loss_param_;
+}
+inline ::caffe::ContrastiveLossParameter* V1LayerParameter::release_contrastive_loss_param() {
+  // @@protoc_insertion_point(field_release:caffe.V1LayerParameter.contrastive_loss_param)
+  clear_has_contrastive_loss_param();
+  ::caffe::ContrastiveLossParameter* temp = contrastive_loss_param_;
+  contrastive_loss_param_ = NULL;
+  return temp;
+}
+inline void V1LayerParameter::set_allocated_contrastive_loss_param(::caffe::ContrastiveLossParameter* contrastive_loss_param) {
+  delete contrastive_loss_param_;
+  contrastive_loss_param_ = contrastive_loss_param;
+  if (contrastive_loss_param) {
+    set_has_contrastive_loss_param();
+  } else {
+    clear_has_contrastive_loss_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.V1LayerParameter.contrastive_loss_param)
+}
+
+// optional .caffe.ConvolutionParameter convolution_param = 10;
+inline bool V1LayerParameter::has_convolution_param() const {
+  return (_has_bits_[0] & 0x00010000u) != 0;
+}
+inline void V1LayerParameter::set_has_convolution_param() {
+  _has_bits_[0] |= 0x00010000u;
+}
+inline void V1LayerParameter::clear_has_convolution_param() {
+  _has_bits_[0] &= ~0x00010000u;
+}
+inline void V1LayerParameter::clear_convolution_param() {
+  if (convolution_param_ != NULL) convolution_param_->::caffe::ConvolutionParameter::Clear();
+  clear_has_convolution_param();
+}
+inline const ::caffe::ConvolutionParameter& V1LayerParameter::convolution_param() const {
+  // @@protoc_insertion_point(field_get:caffe.V1LayerParameter.convolution_param)
+  return convolution_param_ != NULL ? *convolution_param_
+                         : *::caffe::ConvolutionParameter::internal_default_instance();
+}
+inline ::caffe::ConvolutionParameter* V1LayerParameter::mutable_convolution_param() {
+  set_has_convolution_param();
+  if (convolution_param_ == NULL) {
+    convolution_param_ = new ::caffe::ConvolutionParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.V1LayerParameter.convolution_param)
+  return convolution_param_;
+}
+inline ::caffe::ConvolutionParameter* V1LayerParameter::release_convolution_param() {
+  // @@protoc_insertion_point(field_release:caffe.V1LayerParameter.convolution_param)
+  clear_has_convolution_param();
+  ::caffe::ConvolutionParameter* temp = convolution_param_;
+  convolution_param_ = NULL;
+  return temp;
+}
+inline void V1LayerParameter::set_allocated_convolution_param(::caffe::ConvolutionParameter* convolution_param) {
+  delete convolution_param_;
+  convolution_param_ = convolution_param;
+  if (convolution_param) {
+    set_has_convolution_param();
+  } else {
+    clear_has_convolution_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.V1LayerParameter.convolution_param)
+}
+
+// optional .caffe.DataParameter data_param = 11;
+inline bool V1LayerParameter::has_data_param() const {
+  return (_has_bits_[0] & 0x00020000u) != 0;
+}
+inline void V1LayerParameter::set_has_data_param() {
+  _has_bits_[0] |= 0x00020000u;
+}
+inline void V1LayerParameter::clear_has_data_param() {
+  _has_bits_[0] &= ~0x00020000u;
+}
+inline void V1LayerParameter::clear_data_param() {
+  if (data_param_ != NULL) data_param_->::caffe::DataParameter::Clear();
+  clear_has_data_param();
+}
+inline const ::caffe::DataParameter& V1LayerParameter::data_param() const {
+  // @@protoc_insertion_point(field_get:caffe.V1LayerParameter.data_param)
+  return data_param_ != NULL ? *data_param_
+                         : *::caffe::DataParameter::internal_default_instance();
+}
+inline ::caffe::DataParameter* V1LayerParameter::mutable_data_param() {
+  set_has_data_param();
+  if (data_param_ == NULL) {
+    data_param_ = new ::caffe::DataParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.V1LayerParameter.data_param)
+  return data_param_;
+}
+inline ::caffe::DataParameter* V1LayerParameter::release_data_param() {
+  // @@protoc_insertion_point(field_release:caffe.V1LayerParameter.data_param)
+  clear_has_data_param();
+  ::caffe::DataParameter* temp = data_param_;
+  data_param_ = NULL;
+  return temp;
+}
+inline void V1LayerParameter::set_allocated_data_param(::caffe::DataParameter* data_param) {
+  delete data_param_;
+  data_param_ = data_param;
+  if (data_param) {
+    set_has_data_param();
+  } else {
+    clear_has_data_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.V1LayerParameter.data_param)
+}
+
+// optional .caffe.DropoutParameter dropout_param = 12;
+inline bool V1LayerParameter::has_dropout_param() const {
+  return (_has_bits_[0] & 0x00040000u) != 0;
+}
+inline void V1LayerParameter::set_has_dropout_param() {
+  _has_bits_[0] |= 0x00040000u;
+}
+inline void V1LayerParameter::clear_has_dropout_param() {
+  _has_bits_[0] &= ~0x00040000u;
+}
+inline void V1LayerParameter::clear_dropout_param() {
+  if (dropout_param_ != NULL) dropout_param_->::caffe::DropoutParameter::Clear();
+  clear_has_dropout_param();
+}
+inline const ::caffe::DropoutParameter& V1LayerParameter::dropout_param() const {
+  // @@protoc_insertion_point(field_get:caffe.V1LayerParameter.dropout_param)
+  return dropout_param_ != NULL ? *dropout_param_
+                         : *::caffe::DropoutParameter::internal_default_instance();
+}
+inline ::caffe::DropoutParameter* V1LayerParameter::mutable_dropout_param() {
+  set_has_dropout_param();
+  if (dropout_param_ == NULL) {
+    dropout_param_ = new ::caffe::DropoutParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.V1LayerParameter.dropout_param)
+  return dropout_param_;
+}
+inline ::caffe::DropoutParameter* V1LayerParameter::release_dropout_param() {
+  // @@protoc_insertion_point(field_release:caffe.V1LayerParameter.dropout_param)
+  clear_has_dropout_param();
+  ::caffe::DropoutParameter* temp = dropout_param_;
+  dropout_param_ = NULL;
+  return temp;
+}
+inline void V1LayerParameter::set_allocated_dropout_param(::caffe::DropoutParameter* dropout_param) {
+  delete dropout_param_;
+  dropout_param_ = dropout_param;
+  if (dropout_param) {
+    set_has_dropout_param();
+  } else {
+    clear_has_dropout_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.V1LayerParameter.dropout_param)
+}
+
+// optional .caffe.DummyDataParameter dummy_data_param = 26;
+inline bool V1LayerParameter::has_dummy_data_param() const {
+  return (_has_bits_[0] & 0x00080000u) != 0;
+}
+inline void V1LayerParameter::set_has_dummy_data_param() {
+  _has_bits_[0] |= 0x00080000u;
+}
+inline void V1LayerParameter::clear_has_dummy_data_param() {
+  _has_bits_[0] &= ~0x00080000u;
+}
+inline void V1LayerParameter::clear_dummy_data_param() {
+  if (dummy_data_param_ != NULL) dummy_data_param_->::caffe::DummyDataParameter::Clear();
+  clear_has_dummy_data_param();
+}
+inline const ::caffe::DummyDataParameter& V1LayerParameter::dummy_data_param() const {
+  // @@protoc_insertion_point(field_get:caffe.V1LayerParameter.dummy_data_param)
+  return dummy_data_param_ != NULL ? *dummy_data_param_
+                         : *::caffe::DummyDataParameter::internal_default_instance();
+}
+inline ::caffe::DummyDataParameter* V1LayerParameter::mutable_dummy_data_param() {
+  set_has_dummy_data_param();
+  if (dummy_data_param_ == NULL) {
+    dummy_data_param_ = new ::caffe::DummyDataParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.V1LayerParameter.dummy_data_param)
+  return dummy_data_param_;
+}
+inline ::caffe::DummyDataParameter* V1LayerParameter::release_dummy_data_param() {
+  // @@protoc_insertion_point(field_release:caffe.V1LayerParameter.dummy_data_param)
+  clear_has_dummy_data_param();
+  ::caffe::DummyDataParameter* temp = dummy_data_param_;
+  dummy_data_param_ = NULL;
+  return temp;
+}
+inline void V1LayerParameter::set_allocated_dummy_data_param(::caffe::DummyDataParameter* dummy_data_param) {
+  delete dummy_data_param_;
+  dummy_data_param_ = dummy_data_param;
+  if (dummy_data_param) {
+    set_has_dummy_data_param();
+  } else {
+    clear_has_dummy_data_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.V1LayerParameter.dummy_data_param)
+}
+
+// optional .caffe.EltwiseParameter eltwise_param = 24;
+inline bool V1LayerParameter::has_eltwise_param() const {
+  return (_has_bits_[0] & 0x00100000u) != 0;
+}
+inline void V1LayerParameter::set_has_eltwise_param() {
+  _has_bits_[0] |= 0x00100000u;
+}
+inline void V1LayerParameter::clear_has_eltwise_param() {
+  _has_bits_[0] &= ~0x00100000u;
+}
+inline void V1LayerParameter::clear_eltwise_param() {
+  if (eltwise_param_ != NULL) eltwise_param_->::caffe::EltwiseParameter::Clear();
+  clear_has_eltwise_param();
+}
+inline const ::caffe::EltwiseParameter& V1LayerParameter::eltwise_param() const {
+  // @@protoc_insertion_point(field_get:caffe.V1LayerParameter.eltwise_param)
+  return eltwise_param_ != NULL ? *eltwise_param_
+                         : *::caffe::EltwiseParameter::internal_default_instance();
+}
+inline ::caffe::EltwiseParameter* V1LayerParameter::mutable_eltwise_param() {
+  set_has_eltwise_param();
+  if (eltwise_param_ == NULL) {
+    eltwise_param_ = new ::caffe::EltwiseParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.V1LayerParameter.eltwise_param)
+  return eltwise_param_;
+}
+inline ::caffe::EltwiseParameter* V1LayerParameter::release_eltwise_param() {
+  // @@protoc_insertion_point(field_release:caffe.V1LayerParameter.eltwise_param)
+  clear_has_eltwise_param();
+  ::caffe::EltwiseParameter* temp = eltwise_param_;
+  eltwise_param_ = NULL;
+  return temp;
+}
+inline void V1LayerParameter::set_allocated_eltwise_param(::caffe::EltwiseParameter* eltwise_param) {
+  delete eltwise_param_;
+  eltwise_param_ = eltwise_param;
+  if (eltwise_param) {
+    set_has_eltwise_param();
+  } else {
+    clear_has_eltwise_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.V1LayerParameter.eltwise_param)
+}
+
+// optional .caffe.ExpParameter exp_param = 41;
+inline bool V1LayerParameter::has_exp_param() const {
+  return (_has_bits_[0] & 0x00200000u) != 0;
+}
+inline void V1LayerParameter::set_has_exp_param() {
+  _has_bits_[0] |= 0x00200000u;
+}
+inline void V1LayerParameter::clear_has_exp_param() {
+  _has_bits_[0] &= ~0x00200000u;
+}
+inline void V1LayerParameter::clear_exp_param() {
+  if (exp_param_ != NULL) exp_param_->::caffe::ExpParameter::Clear();
+  clear_has_exp_param();
+}
+inline const ::caffe::ExpParameter& V1LayerParameter::exp_param() const {
+  // @@protoc_insertion_point(field_get:caffe.V1LayerParameter.exp_param)
+  return exp_param_ != NULL ? *exp_param_
+                         : *::caffe::ExpParameter::internal_default_instance();
+}
+inline ::caffe::ExpParameter* V1LayerParameter::mutable_exp_param() {
+  set_has_exp_param();
+  if (exp_param_ == NULL) {
+    exp_param_ = new ::caffe::ExpParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.V1LayerParameter.exp_param)
+  return exp_param_;
+}
+inline ::caffe::ExpParameter* V1LayerParameter::release_exp_param() {
+  // @@protoc_insertion_point(field_release:caffe.V1LayerParameter.exp_param)
+  clear_has_exp_param();
+  ::caffe::ExpParameter* temp = exp_param_;
+  exp_param_ = NULL;
+  return temp;
+}
+inline void V1LayerParameter::set_allocated_exp_param(::caffe::ExpParameter* exp_param) {
+  delete exp_param_;
+  exp_param_ = exp_param;
+  if (exp_param) {
+    set_has_exp_param();
+  } else {
+    clear_has_exp_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.V1LayerParameter.exp_param)
+}
+
+// optional .caffe.HDF5DataParameter hdf5_data_param = 13;
+inline bool V1LayerParameter::has_hdf5_data_param() const {
+  return (_has_bits_[0] & 0x00400000u) != 0;
+}
+inline void V1LayerParameter::set_has_hdf5_data_param() {
+  _has_bits_[0] |= 0x00400000u;
+}
+inline void V1LayerParameter::clear_has_hdf5_data_param() {
+  _has_bits_[0] &= ~0x00400000u;
+}
+inline void V1LayerParameter::clear_hdf5_data_param() {
+  if (hdf5_data_param_ != NULL) hdf5_data_param_->::caffe::HDF5DataParameter::Clear();
+  clear_has_hdf5_data_param();
+}
+inline const ::caffe::HDF5DataParameter& V1LayerParameter::hdf5_data_param() const {
+  // @@protoc_insertion_point(field_get:caffe.V1LayerParameter.hdf5_data_param)
+  return hdf5_data_param_ != NULL ? *hdf5_data_param_
+                         : *::caffe::HDF5DataParameter::internal_default_instance();
+}
+inline ::caffe::HDF5DataParameter* V1LayerParameter::mutable_hdf5_data_param() {
+  set_has_hdf5_data_param();
+  if (hdf5_data_param_ == NULL) {
+    hdf5_data_param_ = new ::caffe::HDF5DataParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.V1LayerParameter.hdf5_data_param)
+  return hdf5_data_param_;
+}
+inline ::caffe::HDF5DataParameter* V1LayerParameter::release_hdf5_data_param() {
+  // @@protoc_insertion_point(field_release:caffe.V1LayerParameter.hdf5_data_param)
+  clear_has_hdf5_data_param();
+  ::caffe::HDF5DataParameter* temp = hdf5_data_param_;
+  hdf5_data_param_ = NULL;
+  return temp;
+}
+inline void V1LayerParameter::set_allocated_hdf5_data_param(::caffe::HDF5DataParameter* hdf5_data_param) {
+  delete hdf5_data_param_;
+  hdf5_data_param_ = hdf5_data_param;
+  if (hdf5_data_param) {
+    set_has_hdf5_data_param();
+  } else {
+    clear_has_hdf5_data_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.V1LayerParameter.hdf5_data_param)
+}
+
+// optional .caffe.HDF5OutputParameter hdf5_output_param = 14;
+inline bool V1LayerParameter::has_hdf5_output_param() const {
+  return (_has_bits_[0] & 0x00800000u) != 0;
+}
+inline void V1LayerParameter::set_has_hdf5_output_param() {
+  _has_bits_[0] |= 0x00800000u;
+}
+inline void V1LayerParameter::clear_has_hdf5_output_param() {
+  _has_bits_[0] &= ~0x00800000u;
+}
+inline void V1LayerParameter::clear_hdf5_output_param() {
+  if (hdf5_output_param_ != NULL) hdf5_output_param_->::caffe::HDF5OutputParameter::Clear();
+  clear_has_hdf5_output_param();
+}
+inline const ::caffe::HDF5OutputParameter& V1LayerParameter::hdf5_output_param() const {
+  // @@protoc_insertion_point(field_get:caffe.V1LayerParameter.hdf5_output_param)
+  return hdf5_output_param_ != NULL ? *hdf5_output_param_
+                         : *::caffe::HDF5OutputParameter::internal_default_instance();
+}
+inline ::caffe::HDF5OutputParameter* V1LayerParameter::mutable_hdf5_output_param() {
+  set_has_hdf5_output_param();
+  if (hdf5_output_param_ == NULL) {
+    hdf5_output_param_ = new ::caffe::HDF5OutputParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.V1LayerParameter.hdf5_output_param)
+  return hdf5_output_param_;
+}
+inline ::caffe::HDF5OutputParameter* V1LayerParameter::release_hdf5_output_param() {
+  // @@protoc_insertion_point(field_release:caffe.V1LayerParameter.hdf5_output_param)
+  clear_has_hdf5_output_param();
+  ::caffe::HDF5OutputParameter* temp = hdf5_output_param_;
+  hdf5_output_param_ = NULL;
+  return temp;
+}
+inline void V1LayerParameter::set_allocated_hdf5_output_param(::caffe::HDF5OutputParameter* hdf5_output_param) {
+  delete hdf5_output_param_;
+  hdf5_output_param_ = hdf5_output_param;
+  if (hdf5_output_param) {
+    set_has_hdf5_output_param();
+  } else {
+    clear_has_hdf5_output_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.V1LayerParameter.hdf5_output_param)
+}
+
+// optional .caffe.HingeLossParameter hinge_loss_param = 29;
+inline bool V1LayerParameter::has_hinge_loss_param() const {
+  return (_has_bits_[0] & 0x01000000u) != 0;
+}
+inline void V1LayerParameter::set_has_hinge_loss_param() {
+  _has_bits_[0] |= 0x01000000u;
+}
+inline void V1LayerParameter::clear_has_hinge_loss_param() {
+  _has_bits_[0] &= ~0x01000000u;
+}
+inline void V1LayerParameter::clear_hinge_loss_param() {
+  if (hinge_loss_param_ != NULL) hinge_loss_param_->::caffe::HingeLossParameter::Clear();
+  clear_has_hinge_loss_param();
+}
+inline const ::caffe::HingeLossParameter& V1LayerParameter::hinge_loss_param() const {
+  // @@protoc_insertion_point(field_get:caffe.V1LayerParameter.hinge_loss_param)
+  return hinge_loss_param_ != NULL ? *hinge_loss_param_
+                         : *::caffe::HingeLossParameter::internal_default_instance();
+}
+inline ::caffe::HingeLossParameter* V1LayerParameter::mutable_hinge_loss_param() {
+  set_has_hinge_loss_param();
+  if (hinge_loss_param_ == NULL) {
+    hinge_loss_param_ = new ::caffe::HingeLossParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.V1LayerParameter.hinge_loss_param)
+  return hinge_loss_param_;
+}
+inline ::caffe::HingeLossParameter* V1LayerParameter::release_hinge_loss_param() {
+  // @@protoc_insertion_point(field_release:caffe.V1LayerParameter.hinge_loss_param)
+  clear_has_hinge_loss_param();
+  ::caffe::HingeLossParameter* temp = hinge_loss_param_;
+  hinge_loss_param_ = NULL;
+  return temp;
+}
+inline void V1LayerParameter::set_allocated_hinge_loss_param(::caffe::HingeLossParameter* hinge_loss_param) {
+  delete hinge_loss_param_;
+  hinge_loss_param_ = hinge_loss_param;
+  if (hinge_loss_param) {
+    set_has_hinge_loss_param();
+  } else {
+    clear_has_hinge_loss_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.V1LayerParameter.hinge_loss_param)
+}
+
+// optional .caffe.ImageDataParameter image_data_param = 15;
+inline bool V1LayerParameter::has_image_data_param() const {
+  return (_has_bits_[0] & 0x02000000u) != 0;
+}
+inline void V1LayerParameter::set_has_image_data_param() {
+  _has_bits_[0] |= 0x02000000u;
+}
+inline void V1LayerParameter::clear_has_image_data_param() {
+  _has_bits_[0] &= ~0x02000000u;
+}
+inline void V1LayerParameter::clear_image_data_param() {
+  if (image_data_param_ != NULL) image_data_param_->::caffe::ImageDataParameter::Clear();
+  clear_has_image_data_param();
+}
+inline const ::caffe::ImageDataParameter& V1LayerParameter::image_data_param() const {
+  // @@protoc_insertion_point(field_get:caffe.V1LayerParameter.image_data_param)
+  return image_data_param_ != NULL ? *image_data_param_
+                         : *::caffe::ImageDataParameter::internal_default_instance();
+}
+inline ::caffe::ImageDataParameter* V1LayerParameter::mutable_image_data_param() {
+  set_has_image_data_param();
+  if (image_data_param_ == NULL) {
+    image_data_param_ = new ::caffe::ImageDataParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.V1LayerParameter.image_data_param)
+  return image_data_param_;
+}
+inline ::caffe::ImageDataParameter* V1LayerParameter::release_image_data_param() {
+  // @@protoc_insertion_point(field_release:caffe.V1LayerParameter.image_data_param)
+  clear_has_image_data_param();
+  ::caffe::ImageDataParameter* temp = image_data_param_;
+  image_data_param_ = NULL;
+  return temp;
+}
+inline void V1LayerParameter::set_allocated_image_data_param(::caffe::ImageDataParameter* image_data_param) {
+  delete image_data_param_;
+  image_data_param_ = image_data_param;
+  if (image_data_param) {
+    set_has_image_data_param();
+  } else {
+    clear_has_image_data_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.V1LayerParameter.image_data_param)
+}
+
+// optional .caffe.InfogainLossParameter infogain_loss_param = 16;
+inline bool V1LayerParameter::has_infogain_loss_param() const {
+  return (_has_bits_[0] & 0x04000000u) != 0;
+}
+inline void V1LayerParameter::set_has_infogain_loss_param() {
+  _has_bits_[0] |= 0x04000000u;
+}
+inline void V1LayerParameter::clear_has_infogain_loss_param() {
+  _has_bits_[0] &= ~0x04000000u;
+}
+inline void V1LayerParameter::clear_infogain_loss_param() {
+  if (infogain_loss_param_ != NULL) infogain_loss_param_->::caffe::InfogainLossParameter::Clear();
+  clear_has_infogain_loss_param();
+}
+inline const ::caffe::InfogainLossParameter& V1LayerParameter::infogain_loss_param() const {
+  // @@protoc_insertion_point(field_get:caffe.V1LayerParameter.infogain_loss_param)
+  return infogain_loss_param_ != NULL ? *infogain_loss_param_
+                         : *::caffe::InfogainLossParameter::internal_default_instance();
+}
+inline ::caffe::InfogainLossParameter* V1LayerParameter::mutable_infogain_loss_param() {
+  set_has_infogain_loss_param();
+  if (infogain_loss_param_ == NULL) {
+    infogain_loss_param_ = new ::caffe::InfogainLossParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.V1LayerParameter.infogain_loss_param)
+  return infogain_loss_param_;
+}
+inline ::caffe::InfogainLossParameter* V1LayerParameter::release_infogain_loss_param() {
+  // @@protoc_insertion_point(field_release:caffe.V1LayerParameter.infogain_loss_param)
+  clear_has_infogain_loss_param();
+  ::caffe::InfogainLossParameter* temp = infogain_loss_param_;
+  infogain_loss_param_ = NULL;
+  return temp;
+}
+inline void V1LayerParameter::set_allocated_infogain_loss_param(::caffe::InfogainLossParameter* infogain_loss_param) {
+  delete infogain_loss_param_;
+  infogain_loss_param_ = infogain_loss_param;
+  if (infogain_loss_param) {
+    set_has_infogain_loss_param();
+  } else {
+    clear_has_infogain_loss_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.V1LayerParameter.infogain_loss_param)
+}
+
+// optional .caffe.InnerProductParameter inner_product_param = 17;
+inline bool V1LayerParameter::has_inner_product_param() const {
+  return (_has_bits_[0] & 0x08000000u) != 0;
+}
+inline void V1LayerParameter::set_has_inner_product_param() {
+  _has_bits_[0] |= 0x08000000u;
+}
+inline void V1LayerParameter::clear_has_inner_product_param() {
+  _has_bits_[0] &= ~0x08000000u;
+}
+inline void V1LayerParameter::clear_inner_product_param() {
+  if (inner_product_param_ != NULL) inner_product_param_->::caffe::InnerProductParameter::Clear();
+  clear_has_inner_product_param();
+}
+inline const ::caffe::InnerProductParameter& V1LayerParameter::inner_product_param() const {
+  // @@protoc_insertion_point(field_get:caffe.V1LayerParameter.inner_product_param)
+  return inner_product_param_ != NULL ? *inner_product_param_
+                         : *::caffe::InnerProductParameter::internal_default_instance();
+}
+inline ::caffe::InnerProductParameter* V1LayerParameter::mutable_inner_product_param() {
+  set_has_inner_product_param();
+  if (inner_product_param_ == NULL) {
+    inner_product_param_ = new ::caffe::InnerProductParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.V1LayerParameter.inner_product_param)
+  return inner_product_param_;
+}
+inline ::caffe::InnerProductParameter* V1LayerParameter::release_inner_product_param() {
+  // @@protoc_insertion_point(field_release:caffe.V1LayerParameter.inner_product_param)
+  clear_has_inner_product_param();
+  ::caffe::InnerProductParameter* temp = inner_product_param_;
+  inner_product_param_ = NULL;
+  return temp;
+}
+inline void V1LayerParameter::set_allocated_inner_product_param(::caffe::InnerProductParameter* inner_product_param) {
+  delete inner_product_param_;
+  inner_product_param_ = inner_product_param;
+  if (inner_product_param) {
+    set_has_inner_product_param();
+  } else {
+    clear_has_inner_product_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.V1LayerParameter.inner_product_param)
+}
+
+// optional .caffe.LRNParameter lrn_param = 18;
+inline bool V1LayerParameter::has_lrn_param() const {
+  return (_has_bits_[0] & 0x10000000u) != 0;
+}
+inline void V1LayerParameter::set_has_lrn_param() {
+  _has_bits_[0] |= 0x10000000u;
+}
+inline void V1LayerParameter::clear_has_lrn_param() {
+  _has_bits_[0] &= ~0x10000000u;
+}
+inline void V1LayerParameter::clear_lrn_param() {
+  if (lrn_param_ != NULL) lrn_param_->::caffe::LRNParameter::Clear();
+  clear_has_lrn_param();
+}
+inline const ::caffe::LRNParameter& V1LayerParameter::lrn_param() const {
+  // @@protoc_insertion_point(field_get:caffe.V1LayerParameter.lrn_param)
+  return lrn_param_ != NULL ? *lrn_param_
+                         : *::caffe::LRNParameter::internal_default_instance();
+}
+inline ::caffe::LRNParameter* V1LayerParameter::mutable_lrn_param() {
+  set_has_lrn_param();
+  if (lrn_param_ == NULL) {
+    lrn_param_ = new ::caffe::LRNParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.V1LayerParameter.lrn_param)
+  return lrn_param_;
+}
+inline ::caffe::LRNParameter* V1LayerParameter::release_lrn_param() {
+  // @@protoc_insertion_point(field_release:caffe.V1LayerParameter.lrn_param)
+  clear_has_lrn_param();
+  ::caffe::LRNParameter* temp = lrn_param_;
+  lrn_param_ = NULL;
+  return temp;
+}
+inline void V1LayerParameter::set_allocated_lrn_param(::caffe::LRNParameter* lrn_param) {
+  delete lrn_param_;
+  lrn_param_ = lrn_param;
+  if (lrn_param) {
+    set_has_lrn_param();
+  } else {
+    clear_has_lrn_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.V1LayerParameter.lrn_param)
+}
+
+// optional .caffe.MemoryDataParameter memory_data_param = 22;
+inline bool V1LayerParameter::has_memory_data_param() const {
+  return (_has_bits_[0] & 0x20000000u) != 0;
+}
+inline void V1LayerParameter::set_has_memory_data_param() {
+  _has_bits_[0] |= 0x20000000u;
+}
+inline void V1LayerParameter::clear_has_memory_data_param() {
+  _has_bits_[0] &= ~0x20000000u;
+}
+inline void V1LayerParameter::clear_memory_data_param() {
+  if (memory_data_param_ != NULL) memory_data_param_->::caffe::MemoryDataParameter::Clear();
+  clear_has_memory_data_param();
+}
+inline const ::caffe::MemoryDataParameter& V1LayerParameter::memory_data_param() const {
+  // @@protoc_insertion_point(field_get:caffe.V1LayerParameter.memory_data_param)
+  return memory_data_param_ != NULL ? *memory_data_param_
+                         : *::caffe::MemoryDataParameter::internal_default_instance();
+}
+inline ::caffe::MemoryDataParameter* V1LayerParameter::mutable_memory_data_param() {
+  set_has_memory_data_param();
+  if (memory_data_param_ == NULL) {
+    memory_data_param_ = new ::caffe::MemoryDataParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.V1LayerParameter.memory_data_param)
+  return memory_data_param_;
+}
+inline ::caffe::MemoryDataParameter* V1LayerParameter::release_memory_data_param() {
+  // @@protoc_insertion_point(field_release:caffe.V1LayerParameter.memory_data_param)
+  clear_has_memory_data_param();
+  ::caffe::MemoryDataParameter* temp = memory_data_param_;
+  memory_data_param_ = NULL;
+  return temp;
+}
+inline void V1LayerParameter::set_allocated_memory_data_param(::caffe::MemoryDataParameter* memory_data_param) {
+  delete memory_data_param_;
+  memory_data_param_ = memory_data_param;
+  if (memory_data_param) {
+    set_has_memory_data_param();
+  } else {
+    clear_has_memory_data_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.V1LayerParameter.memory_data_param)
+}
+
+// optional .caffe.MVNParameter mvn_param = 34;
+inline bool V1LayerParameter::has_mvn_param() const {
+  return (_has_bits_[0] & 0x40000000u) != 0;
+}
+inline void V1LayerParameter::set_has_mvn_param() {
+  _has_bits_[0] |= 0x40000000u;
+}
+inline void V1LayerParameter::clear_has_mvn_param() {
+  _has_bits_[0] &= ~0x40000000u;
+}
+inline void V1LayerParameter::clear_mvn_param() {
+  if (mvn_param_ != NULL) mvn_param_->::caffe::MVNParameter::Clear();
+  clear_has_mvn_param();
+}
+inline const ::caffe::MVNParameter& V1LayerParameter::mvn_param() const {
+  // @@protoc_insertion_point(field_get:caffe.V1LayerParameter.mvn_param)
+  return mvn_param_ != NULL ? *mvn_param_
+                         : *::caffe::MVNParameter::internal_default_instance();
+}
+inline ::caffe::MVNParameter* V1LayerParameter::mutable_mvn_param() {
+  set_has_mvn_param();
+  if (mvn_param_ == NULL) {
+    mvn_param_ = new ::caffe::MVNParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.V1LayerParameter.mvn_param)
+  return mvn_param_;
+}
+inline ::caffe::MVNParameter* V1LayerParameter::release_mvn_param() {
+  // @@protoc_insertion_point(field_release:caffe.V1LayerParameter.mvn_param)
+  clear_has_mvn_param();
+  ::caffe::MVNParameter* temp = mvn_param_;
+  mvn_param_ = NULL;
+  return temp;
+}
+inline void V1LayerParameter::set_allocated_mvn_param(::caffe::MVNParameter* mvn_param) {
+  delete mvn_param_;
+  mvn_param_ = mvn_param;
+  if (mvn_param) {
+    set_has_mvn_param();
+  } else {
+    clear_has_mvn_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.V1LayerParameter.mvn_param)
+}
+
+// optional .caffe.PoolingParameter pooling_param = 19;
+inline bool V1LayerParameter::has_pooling_param() const {
+  return (_has_bits_[0] & 0x80000000u) != 0;
+}
+inline void V1LayerParameter::set_has_pooling_param() {
+  _has_bits_[0] |= 0x80000000u;
+}
+inline void V1LayerParameter::clear_has_pooling_param() {
+  _has_bits_[0] &= ~0x80000000u;
+}
+inline void V1LayerParameter::clear_pooling_param() {
+  if (pooling_param_ != NULL) pooling_param_->::caffe::PoolingParameter::Clear();
+  clear_has_pooling_param();
+}
+inline const ::caffe::PoolingParameter& V1LayerParameter::pooling_param() const {
+  // @@protoc_insertion_point(field_get:caffe.V1LayerParameter.pooling_param)
+  return pooling_param_ != NULL ? *pooling_param_
+                         : *::caffe::PoolingParameter::internal_default_instance();
+}
+inline ::caffe::PoolingParameter* V1LayerParameter::mutable_pooling_param() {
+  set_has_pooling_param();
+  if (pooling_param_ == NULL) {
+    pooling_param_ = new ::caffe::PoolingParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.V1LayerParameter.pooling_param)
+  return pooling_param_;
+}
+inline ::caffe::PoolingParameter* V1LayerParameter::release_pooling_param() {
+  // @@protoc_insertion_point(field_release:caffe.V1LayerParameter.pooling_param)
+  clear_has_pooling_param();
+  ::caffe::PoolingParameter* temp = pooling_param_;
+  pooling_param_ = NULL;
+  return temp;
+}
+inline void V1LayerParameter::set_allocated_pooling_param(::caffe::PoolingParameter* pooling_param) {
+  delete pooling_param_;
+  pooling_param_ = pooling_param;
+  if (pooling_param) {
+    set_has_pooling_param();
+  } else {
+    clear_has_pooling_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.V1LayerParameter.pooling_param)
+}
+
+// optional .caffe.PowerParameter power_param = 21;
+inline bool V1LayerParameter::has_power_param() const {
+  return (_has_bits_[1] & 0x00000001u) != 0;
+}
+inline void V1LayerParameter::set_has_power_param() {
+  _has_bits_[1] |= 0x00000001u;
+}
+inline void V1LayerParameter::clear_has_power_param() {
+  _has_bits_[1] &= ~0x00000001u;
+}
+inline void V1LayerParameter::clear_power_param() {
+  if (power_param_ != NULL) power_param_->::caffe::PowerParameter::Clear();
+  clear_has_power_param();
+}
+inline const ::caffe::PowerParameter& V1LayerParameter::power_param() const {
+  // @@protoc_insertion_point(field_get:caffe.V1LayerParameter.power_param)
+  return power_param_ != NULL ? *power_param_
+                         : *::caffe::PowerParameter::internal_default_instance();
+}
+inline ::caffe::PowerParameter* V1LayerParameter::mutable_power_param() {
+  set_has_power_param();
+  if (power_param_ == NULL) {
+    power_param_ = new ::caffe::PowerParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.V1LayerParameter.power_param)
+  return power_param_;
+}
+inline ::caffe::PowerParameter* V1LayerParameter::release_power_param() {
+  // @@protoc_insertion_point(field_release:caffe.V1LayerParameter.power_param)
+  clear_has_power_param();
+  ::caffe::PowerParameter* temp = power_param_;
+  power_param_ = NULL;
+  return temp;
+}
+inline void V1LayerParameter::set_allocated_power_param(::caffe::PowerParameter* power_param) {
+  delete power_param_;
+  power_param_ = power_param;
+  if (power_param) {
+    set_has_power_param();
+  } else {
+    clear_has_power_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.V1LayerParameter.power_param)
+}
+
+// optional .caffe.ReLUParameter relu_param = 30;
+inline bool V1LayerParameter::has_relu_param() const {
+  return (_has_bits_[1] & 0x00000002u) != 0;
+}
+inline void V1LayerParameter::set_has_relu_param() {
+  _has_bits_[1] |= 0x00000002u;
+}
+inline void V1LayerParameter::clear_has_relu_param() {
+  _has_bits_[1] &= ~0x00000002u;
+}
+inline void V1LayerParameter::clear_relu_param() {
+  if (relu_param_ != NULL) relu_param_->::caffe::ReLUParameter::Clear();
+  clear_has_relu_param();
+}
+inline const ::caffe::ReLUParameter& V1LayerParameter::relu_param() const {
+  // @@protoc_insertion_point(field_get:caffe.V1LayerParameter.relu_param)
+  return relu_param_ != NULL ? *relu_param_
+                         : *::caffe::ReLUParameter::internal_default_instance();
+}
+inline ::caffe::ReLUParameter* V1LayerParameter::mutable_relu_param() {
+  set_has_relu_param();
+  if (relu_param_ == NULL) {
+    relu_param_ = new ::caffe::ReLUParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.V1LayerParameter.relu_param)
+  return relu_param_;
+}
+inline ::caffe::ReLUParameter* V1LayerParameter::release_relu_param() {
+  // @@protoc_insertion_point(field_release:caffe.V1LayerParameter.relu_param)
+  clear_has_relu_param();
+  ::caffe::ReLUParameter* temp = relu_param_;
+  relu_param_ = NULL;
+  return temp;
+}
+inline void V1LayerParameter::set_allocated_relu_param(::caffe::ReLUParameter* relu_param) {
+  delete relu_param_;
+  relu_param_ = relu_param;
+  if (relu_param) {
+    set_has_relu_param();
+  } else {
+    clear_has_relu_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.V1LayerParameter.relu_param)
+}
+
+// optional .caffe.SigmoidParameter sigmoid_param = 38;
+inline bool V1LayerParameter::has_sigmoid_param() const {
+  return (_has_bits_[1] & 0x00000004u) != 0;
+}
+inline void V1LayerParameter::set_has_sigmoid_param() {
+  _has_bits_[1] |= 0x00000004u;
+}
+inline void V1LayerParameter::clear_has_sigmoid_param() {
+  _has_bits_[1] &= ~0x00000004u;
+}
+inline void V1LayerParameter::clear_sigmoid_param() {
+  if (sigmoid_param_ != NULL) sigmoid_param_->::caffe::SigmoidParameter::Clear();
+  clear_has_sigmoid_param();
+}
+inline const ::caffe::SigmoidParameter& V1LayerParameter::sigmoid_param() const {
+  // @@protoc_insertion_point(field_get:caffe.V1LayerParameter.sigmoid_param)
+  return sigmoid_param_ != NULL ? *sigmoid_param_
+                         : *::caffe::SigmoidParameter::internal_default_instance();
+}
+inline ::caffe::SigmoidParameter* V1LayerParameter::mutable_sigmoid_param() {
+  set_has_sigmoid_param();
+  if (sigmoid_param_ == NULL) {
+    sigmoid_param_ = new ::caffe::SigmoidParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.V1LayerParameter.sigmoid_param)
+  return sigmoid_param_;
+}
+inline ::caffe::SigmoidParameter* V1LayerParameter::release_sigmoid_param() {
+  // @@protoc_insertion_point(field_release:caffe.V1LayerParameter.sigmoid_param)
+  clear_has_sigmoid_param();
+  ::caffe::SigmoidParameter* temp = sigmoid_param_;
+  sigmoid_param_ = NULL;
+  return temp;
+}
+inline void V1LayerParameter::set_allocated_sigmoid_param(::caffe::SigmoidParameter* sigmoid_param) {
+  delete sigmoid_param_;
+  sigmoid_param_ = sigmoid_param;
+  if (sigmoid_param) {
+    set_has_sigmoid_param();
+  } else {
+    clear_has_sigmoid_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.V1LayerParameter.sigmoid_param)
+}
+
+// optional .caffe.SoftmaxParameter softmax_param = 39;
+inline bool V1LayerParameter::has_softmax_param() const {
+  return (_has_bits_[1] & 0x00000008u) != 0;
+}
+inline void V1LayerParameter::set_has_softmax_param() {
+  _has_bits_[1] |= 0x00000008u;
+}
+inline void V1LayerParameter::clear_has_softmax_param() {
+  _has_bits_[1] &= ~0x00000008u;
+}
+inline void V1LayerParameter::clear_softmax_param() {
+  if (softmax_param_ != NULL) softmax_param_->::caffe::SoftmaxParameter::Clear();
+  clear_has_softmax_param();
+}
+inline const ::caffe::SoftmaxParameter& V1LayerParameter::softmax_param() const {
+  // @@protoc_insertion_point(field_get:caffe.V1LayerParameter.softmax_param)
+  return softmax_param_ != NULL ? *softmax_param_
+                         : *::caffe::SoftmaxParameter::internal_default_instance();
+}
+inline ::caffe::SoftmaxParameter* V1LayerParameter::mutable_softmax_param() {
+  set_has_softmax_param();
+  if (softmax_param_ == NULL) {
+    softmax_param_ = new ::caffe::SoftmaxParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.V1LayerParameter.softmax_param)
+  return softmax_param_;
+}
+inline ::caffe::SoftmaxParameter* V1LayerParameter::release_softmax_param() {
+  // @@protoc_insertion_point(field_release:caffe.V1LayerParameter.softmax_param)
+  clear_has_softmax_param();
+  ::caffe::SoftmaxParameter* temp = softmax_param_;
+  softmax_param_ = NULL;
+  return temp;
+}
+inline void V1LayerParameter::set_allocated_softmax_param(::caffe::SoftmaxParameter* softmax_param) {
+  delete softmax_param_;
+  softmax_param_ = softmax_param;
+  if (softmax_param) {
+    set_has_softmax_param();
+  } else {
+    clear_has_softmax_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.V1LayerParameter.softmax_param)
+}
+
+// optional .caffe.SliceParameter slice_param = 31;
+inline bool V1LayerParameter::has_slice_param() const {
+  return (_has_bits_[1] & 0x00000010u) != 0;
+}
+inline void V1LayerParameter::set_has_slice_param() {
+  _has_bits_[1] |= 0x00000010u;
+}
+inline void V1LayerParameter::clear_has_slice_param() {
+  _has_bits_[1] &= ~0x00000010u;
+}
+inline void V1LayerParameter::clear_slice_param() {
+  if (slice_param_ != NULL) slice_param_->::caffe::SliceParameter::Clear();
+  clear_has_slice_param();
+}
+inline const ::caffe::SliceParameter& V1LayerParameter::slice_param() const {
+  // @@protoc_insertion_point(field_get:caffe.V1LayerParameter.slice_param)
+  return slice_param_ != NULL ? *slice_param_
+                         : *::caffe::SliceParameter::internal_default_instance();
+}
+inline ::caffe::SliceParameter* V1LayerParameter::mutable_slice_param() {
+  set_has_slice_param();
+  if (slice_param_ == NULL) {
+    slice_param_ = new ::caffe::SliceParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.V1LayerParameter.slice_param)
+  return slice_param_;
+}
+inline ::caffe::SliceParameter* V1LayerParameter::release_slice_param() {
+  // @@protoc_insertion_point(field_release:caffe.V1LayerParameter.slice_param)
+  clear_has_slice_param();
+  ::caffe::SliceParameter* temp = slice_param_;
+  slice_param_ = NULL;
+  return temp;
+}
+inline void V1LayerParameter::set_allocated_slice_param(::caffe::SliceParameter* slice_param) {
+  delete slice_param_;
+  slice_param_ = slice_param;
+  if (slice_param) {
+    set_has_slice_param();
+  } else {
+    clear_has_slice_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.V1LayerParameter.slice_param)
+}
+
+// optional .caffe.TanHParameter tanh_param = 37;
+inline bool V1LayerParameter::has_tanh_param() const {
+  return (_has_bits_[1] & 0x00000020u) != 0;
+}
+inline void V1LayerParameter::set_has_tanh_param() {
+  _has_bits_[1] |= 0x00000020u;
+}
+inline void V1LayerParameter::clear_has_tanh_param() {
+  _has_bits_[1] &= ~0x00000020u;
+}
+inline void V1LayerParameter::clear_tanh_param() {
+  if (tanh_param_ != NULL) tanh_param_->::caffe::TanHParameter::Clear();
+  clear_has_tanh_param();
+}
+inline const ::caffe::TanHParameter& V1LayerParameter::tanh_param() const {
+  // @@protoc_insertion_point(field_get:caffe.V1LayerParameter.tanh_param)
+  return tanh_param_ != NULL ? *tanh_param_
+                         : *::caffe::TanHParameter::internal_default_instance();
+}
+inline ::caffe::TanHParameter* V1LayerParameter::mutable_tanh_param() {
+  set_has_tanh_param();
+  if (tanh_param_ == NULL) {
+    tanh_param_ = new ::caffe::TanHParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.V1LayerParameter.tanh_param)
+  return tanh_param_;
+}
+inline ::caffe::TanHParameter* V1LayerParameter::release_tanh_param() {
+  // @@protoc_insertion_point(field_release:caffe.V1LayerParameter.tanh_param)
+  clear_has_tanh_param();
+  ::caffe::TanHParameter* temp = tanh_param_;
+  tanh_param_ = NULL;
+  return temp;
+}
+inline void V1LayerParameter::set_allocated_tanh_param(::caffe::TanHParameter* tanh_param) {
+  delete tanh_param_;
+  tanh_param_ = tanh_param;
+  if (tanh_param) {
+    set_has_tanh_param();
+  } else {
+    clear_has_tanh_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.V1LayerParameter.tanh_param)
+}
+
+// optional .caffe.ThresholdParameter threshold_param = 25;
+inline bool V1LayerParameter::has_threshold_param() const {
+  return (_has_bits_[1] & 0x00000040u) != 0;
+}
+inline void V1LayerParameter::set_has_threshold_param() {
+  _has_bits_[1] |= 0x00000040u;
+}
+inline void V1LayerParameter::clear_has_threshold_param() {
+  _has_bits_[1] &= ~0x00000040u;
+}
+inline void V1LayerParameter::clear_threshold_param() {
+  if (threshold_param_ != NULL) threshold_param_->::caffe::ThresholdParameter::Clear();
+  clear_has_threshold_param();
+}
+inline const ::caffe::ThresholdParameter& V1LayerParameter::threshold_param() const {
+  // @@protoc_insertion_point(field_get:caffe.V1LayerParameter.threshold_param)
+  return threshold_param_ != NULL ? *threshold_param_
+                         : *::caffe::ThresholdParameter::internal_default_instance();
+}
+inline ::caffe::ThresholdParameter* V1LayerParameter::mutable_threshold_param() {
+  set_has_threshold_param();
+  if (threshold_param_ == NULL) {
+    threshold_param_ = new ::caffe::ThresholdParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.V1LayerParameter.threshold_param)
+  return threshold_param_;
+}
+inline ::caffe::ThresholdParameter* V1LayerParameter::release_threshold_param() {
+  // @@protoc_insertion_point(field_release:caffe.V1LayerParameter.threshold_param)
+  clear_has_threshold_param();
+  ::caffe::ThresholdParameter* temp = threshold_param_;
+  threshold_param_ = NULL;
+  return temp;
+}
+inline void V1LayerParameter::set_allocated_threshold_param(::caffe::ThresholdParameter* threshold_param) {
+  delete threshold_param_;
+  threshold_param_ = threshold_param;
+  if (threshold_param) {
+    set_has_threshold_param();
+  } else {
+    clear_has_threshold_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.V1LayerParameter.threshold_param)
+}
+
+// optional .caffe.WindowDataParameter window_data_param = 20;
+inline bool V1LayerParameter::has_window_data_param() const {
+  return (_has_bits_[1] & 0x00000080u) != 0;
+}
+inline void V1LayerParameter::set_has_window_data_param() {
+  _has_bits_[1] |= 0x00000080u;
+}
+inline void V1LayerParameter::clear_has_window_data_param() {
+  _has_bits_[1] &= ~0x00000080u;
+}
+inline void V1LayerParameter::clear_window_data_param() {
+  if (window_data_param_ != NULL) window_data_param_->::caffe::WindowDataParameter::Clear();
+  clear_has_window_data_param();
+}
+inline const ::caffe::WindowDataParameter& V1LayerParameter::window_data_param() const {
+  // @@protoc_insertion_point(field_get:caffe.V1LayerParameter.window_data_param)
+  return window_data_param_ != NULL ? *window_data_param_
+                         : *::caffe::WindowDataParameter::internal_default_instance();
+}
+inline ::caffe::WindowDataParameter* V1LayerParameter::mutable_window_data_param() {
+  set_has_window_data_param();
+  if (window_data_param_ == NULL) {
+    window_data_param_ = new ::caffe::WindowDataParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.V1LayerParameter.window_data_param)
+  return window_data_param_;
+}
+inline ::caffe::WindowDataParameter* V1LayerParameter::release_window_data_param() {
+  // @@protoc_insertion_point(field_release:caffe.V1LayerParameter.window_data_param)
+  clear_has_window_data_param();
+  ::caffe::WindowDataParameter* temp = window_data_param_;
+  window_data_param_ = NULL;
+  return temp;
+}
+inline void V1LayerParameter::set_allocated_window_data_param(::caffe::WindowDataParameter* window_data_param) {
+  delete window_data_param_;
+  window_data_param_ = window_data_param;
+  if (window_data_param) {
+    set_has_window_data_param();
+  } else {
+    clear_has_window_data_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.V1LayerParameter.window_data_param)
+}
+
+// optional .caffe.TransformationParameter transform_param = 36;
+inline bool V1LayerParameter::has_transform_param() const {
+  return (_has_bits_[1] & 0x00000100u) != 0;
+}
+inline void V1LayerParameter::set_has_transform_param() {
+  _has_bits_[1] |= 0x00000100u;
+}
+inline void V1LayerParameter::clear_has_transform_param() {
+  _has_bits_[1] &= ~0x00000100u;
+}
+inline void V1LayerParameter::clear_transform_param() {
+  if (transform_param_ != NULL) transform_param_->::caffe::TransformationParameter::Clear();
+  clear_has_transform_param();
+}
+inline const ::caffe::TransformationParameter& V1LayerParameter::transform_param() const {
+  // @@protoc_insertion_point(field_get:caffe.V1LayerParameter.transform_param)
+  return transform_param_ != NULL ? *transform_param_
+                         : *::caffe::TransformationParameter::internal_default_instance();
+}
+inline ::caffe::TransformationParameter* V1LayerParameter::mutable_transform_param() {
+  set_has_transform_param();
+  if (transform_param_ == NULL) {
+    transform_param_ = new ::caffe::TransformationParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.V1LayerParameter.transform_param)
+  return transform_param_;
+}
+inline ::caffe::TransformationParameter* V1LayerParameter::release_transform_param() {
+  // @@protoc_insertion_point(field_release:caffe.V1LayerParameter.transform_param)
+  clear_has_transform_param();
+  ::caffe::TransformationParameter* temp = transform_param_;
+  transform_param_ = NULL;
+  return temp;
+}
+inline void V1LayerParameter::set_allocated_transform_param(::caffe::TransformationParameter* transform_param) {
+  delete transform_param_;
+  transform_param_ = transform_param;
+  if (transform_param) {
+    set_has_transform_param();
+  } else {
+    clear_has_transform_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.V1LayerParameter.transform_param)
+}
+
+// optional .caffe.LossParameter loss_param = 42;
+inline bool V1LayerParameter::has_loss_param() const {
+  return (_has_bits_[1] & 0x00000200u) != 0;
+}
+inline void V1LayerParameter::set_has_loss_param() {
+  _has_bits_[1] |= 0x00000200u;
+}
+inline void V1LayerParameter::clear_has_loss_param() {
+  _has_bits_[1] &= ~0x00000200u;
+}
+inline void V1LayerParameter::clear_loss_param() {
+  if (loss_param_ != NULL) loss_param_->::caffe::LossParameter::Clear();
+  clear_has_loss_param();
+}
+inline const ::caffe::LossParameter& V1LayerParameter::loss_param() const {
+  // @@protoc_insertion_point(field_get:caffe.V1LayerParameter.loss_param)
+  return loss_param_ != NULL ? *loss_param_
+                         : *::caffe::LossParameter::internal_default_instance();
+}
+inline ::caffe::LossParameter* V1LayerParameter::mutable_loss_param() {
+  set_has_loss_param();
+  if (loss_param_ == NULL) {
+    loss_param_ = new ::caffe::LossParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.V1LayerParameter.loss_param)
+  return loss_param_;
+}
+inline ::caffe::LossParameter* V1LayerParameter::release_loss_param() {
+  // @@protoc_insertion_point(field_release:caffe.V1LayerParameter.loss_param)
+  clear_has_loss_param();
+  ::caffe::LossParameter* temp = loss_param_;
+  loss_param_ = NULL;
+  return temp;
+}
+inline void V1LayerParameter::set_allocated_loss_param(::caffe::LossParameter* loss_param) {
+  delete loss_param_;
+  loss_param_ = loss_param;
+  if (loss_param) {
+    set_has_loss_param();
+  } else {
+    clear_has_loss_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.V1LayerParameter.loss_param)
+}
+
+// optional .caffe.V0LayerParameter layer = 1;
+inline bool V1LayerParameter::has_layer() const {
+  return (_has_bits_[1] & 0x00000400u) != 0;
+}
+inline void V1LayerParameter::set_has_layer() {
+  _has_bits_[1] |= 0x00000400u;
+}
+inline void V1LayerParameter::clear_has_layer() {
+  _has_bits_[1] &= ~0x00000400u;
+}
+inline void V1LayerParameter::clear_layer() {
+  if (layer_ != NULL) layer_->::caffe::V0LayerParameter::Clear();
+  clear_has_layer();
+}
+inline const ::caffe::V0LayerParameter& V1LayerParameter::layer() const {
+  // @@protoc_insertion_point(field_get:caffe.V1LayerParameter.layer)
+  return layer_ != NULL ? *layer_
+                         : *::caffe::V0LayerParameter::internal_default_instance();
+}
+inline ::caffe::V0LayerParameter* V1LayerParameter::mutable_layer() {
+  set_has_layer();
+  if (layer_ == NULL) {
+    layer_ = new ::caffe::V0LayerParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.V1LayerParameter.layer)
+  return layer_;
+}
+inline ::caffe::V0LayerParameter* V1LayerParameter::release_layer() {
+  // @@protoc_insertion_point(field_release:caffe.V1LayerParameter.layer)
+  clear_has_layer();
+  ::caffe::V0LayerParameter* temp = layer_;
+  layer_ = NULL;
+  return temp;
+}
+inline void V1LayerParameter::set_allocated_layer(::caffe::V0LayerParameter* layer) {
+  delete layer_;
+  layer_ = layer;
+  if (layer) {
+    set_has_layer();
+  } else {
+    clear_has_layer();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.V1LayerParameter.layer)
+}
+
+inline const V1LayerParameter* V1LayerParameter::internal_default_instance() {
+  return &V1LayerParameter_default_instance_.get();
+}
+// -------------------------------------------------------------------
+
+// V0LayerParameter
+
+// optional string name = 1;
+inline bool V0LayerParameter::has_name() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+inline void V0LayerParameter::set_has_name() {
+  _has_bits_[0] |= 0x00000001u;
+}
+inline void V0LayerParameter::clear_has_name() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+inline void V0LayerParameter::clear_name() {
+  name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  clear_has_name();
+}
+inline const ::std::string& V0LayerParameter::name() const {
+  // @@protoc_insertion_point(field_get:caffe.V0LayerParameter.name)
+  return name_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void V0LayerParameter::set_name(const ::std::string& value) {
+  set_has_name();
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:caffe.V0LayerParameter.name)
+}
+inline void V0LayerParameter::set_name(const char* value) {
+  set_has_name();
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:caffe.V0LayerParameter.name)
+}
+inline void V0LayerParameter::set_name(const char* value, size_t size) {
+  set_has_name();
+  name_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:caffe.V0LayerParameter.name)
+}
+inline ::std::string* V0LayerParameter::mutable_name() {
+  set_has_name();
+  // @@protoc_insertion_point(field_mutable:caffe.V0LayerParameter.name)
+  return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline ::std::string* V0LayerParameter::release_name() {
+  // @@protoc_insertion_point(field_release:caffe.V0LayerParameter.name)
+  clear_has_name();
+  return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void V0LayerParameter::set_allocated_name(::std::string* name) {
+  if (name != NULL) {
+    set_has_name();
+  } else {
+    clear_has_name();
+  }
+  name_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), name);
+  // @@protoc_insertion_point(field_set_allocated:caffe.V0LayerParameter.name)
+}
+
+// optional string type = 2;
+inline bool V0LayerParameter::has_type() const {
+  return (_has_bits_[0] & 0x00000002u) != 0;
+}
+inline void V0LayerParameter::set_has_type() {
+  _has_bits_[0] |= 0x00000002u;
+}
+inline void V0LayerParameter::clear_has_type() {
+  _has_bits_[0] &= ~0x00000002u;
+}
+inline void V0LayerParameter::clear_type() {
+  type_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  clear_has_type();
+}
+inline const ::std::string& V0LayerParameter::type() const {
+  // @@protoc_insertion_point(field_get:caffe.V0LayerParameter.type)
+  return type_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void V0LayerParameter::set_type(const ::std::string& value) {
+  set_has_type();
+  type_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:caffe.V0LayerParameter.type)
+}
+inline void V0LayerParameter::set_type(const char* value) {
+  set_has_type();
+  type_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:caffe.V0LayerParameter.type)
+}
+inline void V0LayerParameter::set_type(const char* value, size_t size) {
+  set_has_type();
+  type_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:caffe.V0LayerParameter.type)
+}
+inline ::std::string* V0LayerParameter::mutable_type() {
+  set_has_type();
+  // @@protoc_insertion_point(field_mutable:caffe.V0LayerParameter.type)
+  return type_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline ::std::string* V0LayerParameter::release_type() {
+  // @@protoc_insertion_point(field_release:caffe.V0LayerParameter.type)
+  clear_has_type();
+  return type_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void V0LayerParameter::set_allocated_type(::std::string* type) {
+  if (type != NULL) {
+    set_has_type();
+  } else {
+    clear_has_type();
+  }
+  type_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), type);
+  // @@protoc_insertion_point(field_set_allocated:caffe.V0LayerParameter.type)
+}
+
+// optional uint32 num_output = 3;
+inline bool V0LayerParameter::has_num_output() const {
+  return (_has_bits_[0] & 0x00000004u) != 0;
+}
+inline void V0LayerParameter::set_has_num_output() {
+  _has_bits_[0] |= 0x00000004u;
+}
+inline void V0LayerParameter::clear_has_num_output() {
+  _has_bits_[0] &= ~0x00000004u;
+}
+inline void V0LayerParameter::clear_num_output() {
+  num_output_ = 0u;
+  clear_has_num_output();
+}
+inline ::google::protobuf::uint32 V0LayerParameter::num_output() const {
+  // @@protoc_insertion_point(field_get:caffe.V0LayerParameter.num_output)
+  return num_output_;
+}
+inline void V0LayerParameter::set_num_output(::google::protobuf::uint32 value) {
+  set_has_num_output();
+  num_output_ = value;
+  // @@protoc_insertion_point(field_set:caffe.V0LayerParameter.num_output)
+}
+
+// optional bool biasterm = 4 [default = true];
+inline bool V0LayerParameter::has_biasterm() const {
+  return (_has_bits_[0] & 0x00000008u) != 0;
+}
+inline void V0LayerParameter::set_has_biasterm() {
+  _has_bits_[0] |= 0x00000008u;
+}
+inline void V0LayerParameter::clear_has_biasterm() {
+  _has_bits_[0] &= ~0x00000008u;
+}
+inline void V0LayerParameter::clear_biasterm() {
+  biasterm_ = true;
+  clear_has_biasterm();
+}
+inline bool V0LayerParameter::biasterm() const {
+  // @@protoc_insertion_point(field_get:caffe.V0LayerParameter.biasterm)
+  return biasterm_;
+}
+inline void V0LayerParameter::set_biasterm(bool value) {
+  set_has_biasterm();
+  biasterm_ = value;
+  // @@protoc_insertion_point(field_set:caffe.V0LayerParameter.biasterm)
+}
+
+// optional .caffe.FillerParameter weight_filler = 5;
+inline bool V0LayerParameter::has_weight_filler() const {
+  return (_has_bits_[0] & 0x00000010u) != 0;
+}
+inline void V0LayerParameter::set_has_weight_filler() {
+  _has_bits_[0] |= 0x00000010u;
+}
+inline void V0LayerParameter::clear_has_weight_filler() {
+  _has_bits_[0] &= ~0x00000010u;
+}
+inline void V0LayerParameter::clear_weight_filler() {
+  if (weight_filler_ != NULL) weight_filler_->::caffe::FillerParameter::Clear();
+  clear_has_weight_filler();
+}
+inline const ::caffe::FillerParameter& V0LayerParameter::weight_filler() const {
+  // @@protoc_insertion_point(field_get:caffe.V0LayerParameter.weight_filler)
+  return weight_filler_ != NULL ? *weight_filler_
+                         : *::caffe::FillerParameter::internal_default_instance();
+}
+inline ::caffe::FillerParameter* V0LayerParameter::mutable_weight_filler() {
+  set_has_weight_filler();
+  if (weight_filler_ == NULL) {
+    weight_filler_ = new ::caffe::FillerParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.V0LayerParameter.weight_filler)
+  return weight_filler_;
+}
+inline ::caffe::FillerParameter* V0LayerParameter::release_weight_filler() {
+  // @@protoc_insertion_point(field_release:caffe.V0LayerParameter.weight_filler)
+  clear_has_weight_filler();
+  ::caffe::FillerParameter* temp = weight_filler_;
+  weight_filler_ = NULL;
+  return temp;
+}
+inline void V0LayerParameter::set_allocated_weight_filler(::caffe::FillerParameter* weight_filler) {
+  delete weight_filler_;
+  weight_filler_ = weight_filler;
+  if (weight_filler) {
+    set_has_weight_filler();
+  } else {
+    clear_has_weight_filler();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.V0LayerParameter.weight_filler)
+}
+
+// optional .caffe.FillerParameter bias_filler = 6;
+inline bool V0LayerParameter::has_bias_filler() const {
+  return (_has_bits_[0] & 0x00000020u) != 0;
+}
+inline void V0LayerParameter::set_has_bias_filler() {
+  _has_bits_[0] |= 0x00000020u;
+}
+inline void V0LayerParameter::clear_has_bias_filler() {
+  _has_bits_[0] &= ~0x00000020u;
+}
+inline void V0LayerParameter::clear_bias_filler() {
+  if (bias_filler_ != NULL) bias_filler_->::caffe::FillerParameter::Clear();
+  clear_has_bias_filler();
+}
+inline const ::caffe::FillerParameter& V0LayerParameter::bias_filler() const {
+  // @@protoc_insertion_point(field_get:caffe.V0LayerParameter.bias_filler)
+  return bias_filler_ != NULL ? *bias_filler_
+                         : *::caffe::FillerParameter::internal_default_instance();
+}
+inline ::caffe::FillerParameter* V0LayerParameter::mutable_bias_filler() {
+  set_has_bias_filler();
+  if (bias_filler_ == NULL) {
+    bias_filler_ = new ::caffe::FillerParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.V0LayerParameter.bias_filler)
+  return bias_filler_;
+}
+inline ::caffe::FillerParameter* V0LayerParameter::release_bias_filler() {
+  // @@protoc_insertion_point(field_release:caffe.V0LayerParameter.bias_filler)
+  clear_has_bias_filler();
+  ::caffe::FillerParameter* temp = bias_filler_;
+  bias_filler_ = NULL;
+  return temp;
+}
+inline void V0LayerParameter::set_allocated_bias_filler(::caffe::FillerParameter* bias_filler) {
+  delete bias_filler_;
+  bias_filler_ = bias_filler;
+  if (bias_filler) {
+    set_has_bias_filler();
+  } else {
+    clear_has_bias_filler();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.V0LayerParameter.bias_filler)
+}
+
+// optional uint32 pad = 7 [default = 0];
+inline bool V0LayerParameter::has_pad() const {
+  return (_has_bits_[0] & 0x00000040u) != 0;
+}
+inline void V0LayerParameter::set_has_pad() {
+  _has_bits_[0] |= 0x00000040u;
+}
+inline void V0LayerParameter::clear_has_pad() {
+  _has_bits_[0] &= ~0x00000040u;
+}
+inline void V0LayerParameter::clear_pad() {
+  pad_ = 0u;
+  clear_has_pad();
+}
+inline ::google::protobuf::uint32 V0LayerParameter::pad() const {
+  // @@protoc_insertion_point(field_get:caffe.V0LayerParameter.pad)
+  return pad_;
+}
+inline void V0LayerParameter::set_pad(::google::protobuf::uint32 value) {
+  set_has_pad();
+  pad_ = value;
+  // @@protoc_insertion_point(field_set:caffe.V0LayerParameter.pad)
+}
+
+// optional uint32 kernelsize = 8;
+inline bool V0LayerParameter::has_kernelsize() const {
+  return (_has_bits_[0] & 0x00000080u) != 0;
+}
+inline void V0LayerParameter::set_has_kernelsize() {
+  _has_bits_[0] |= 0x00000080u;
+}
+inline void V0LayerParameter::clear_has_kernelsize() {
+  _has_bits_[0] &= ~0x00000080u;
+}
+inline void V0LayerParameter::clear_kernelsize() {
+  kernelsize_ = 0u;
+  clear_has_kernelsize();
+}
+inline ::google::protobuf::uint32 V0LayerParameter::kernelsize() const {
+  // @@protoc_insertion_point(field_get:caffe.V0LayerParameter.kernelsize)
+  return kernelsize_;
+}
+inline void V0LayerParameter::set_kernelsize(::google::protobuf::uint32 value) {
+  set_has_kernelsize();
+  kernelsize_ = value;
+  // @@protoc_insertion_point(field_set:caffe.V0LayerParameter.kernelsize)
+}
+
+// optional uint32 group = 9 [default = 1];
+inline bool V0LayerParameter::has_group() const {
+  return (_has_bits_[0] & 0x00000100u) != 0;
+}
+inline void V0LayerParameter::set_has_group() {
+  _has_bits_[0] |= 0x00000100u;
+}
+inline void V0LayerParameter::clear_has_group() {
+  _has_bits_[0] &= ~0x00000100u;
+}
+inline void V0LayerParameter::clear_group() {
+  group_ = 1u;
+  clear_has_group();
+}
+inline ::google::protobuf::uint32 V0LayerParameter::group() const {
+  // @@protoc_insertion_point(field_get:caffe.V0LayerParameter.group)
+  return group_;
+}
+inline void V0LayerParameter::set_group(::google::protobuf::uint32 value) {
+  set_has_group();
+  group_ = value;
+  // @@protoc_insertion_point(field_set:caffe.V0LayerParameter.group)
+}
+
+// optional uint32 stride = 10 [default = 1];
+inline bool V0LayerParameter::has_stride() const {
+  return (_has_bits_[0] & 0x00000200u) != 0;
+}
+inline void V0LayerParameter::set_has_stride() {
+  _has_bits_[0] |= 0x00000200u;
+}
+inline void V0LayerParameter::clear_has_stride() {
+  _has_bits_[0] &= ~0x00000200u;
+}
+inline void V0LayerParameter::clear_stride() {
+  stride_ = 1u;
+  clear_has_stride();
+}
+inline ::google::protobuf::uint32 V0LayerParameter::stride() const {
+  // @@protoc_insertion_point(field_get:caffe.V0LayerParameter.stride)
+  return stride_;
+}
+inline void V0LayerParameter::set_stride(::google::protobuf::uint32 value) {
+  set_has_stride();
+  stride_ = value;
+  // @@protoc_insertion_point(field_set:caffe.V0LayerParameter.stride)
+}
+
+// optional .caffe.V0LayerParameter.PoolMethod pool = 11 [default = MAX];
+inline bool V0LayerParameter::has_pool() const {
+  return (_has_bits_[0] & 0x00000400u) != 0;
+}
+inline void V0LayerParameter::set_has_pool() {
+  _has_bits_[0] |= 0x00000400u;
+}
+inline void V0LayerParameter::clear_has_pool() {
+  _has_bits_[0] &= ~0x00000400u;
+}
+inline void V0LayerParameter::clear_pool() {
+  pool_ = 0;
+  clear_has_pool();
+}
+inline ::caffe::V0LayerParameter_PoolMethod V0LayerParameter::pool() const {
+  // @@protoc_insertion_point(field_get:caffe.V0LayerParameter.pool)
+  return static_cast< ::caffe::V0LayerParameter_PoolMethod >(pool_);
+}
+inline void V0LayerParameter::set_pool(::caffe::V0LayerParameter_PoolMethod value) {
+  assert(::caffe::V0LayerParameter_PoolMethod_IsValid(value));
+  set_has_pool();
+  pool_ = value;
+  // @@protoc_insertion_point(field_set:caffe.V0LayerParameter.pool)
+}
+
+// optional float dropout_ratio = 12 [default = 0.5];
+inline bool V0LayerParameter::has_dropout_ratio() const {
+  return (_has_bits_[0] & 0x00000800u) != 0;
+}
+inline void V0LayerParameter::set_has_dropout_ratio() {
+  _has_bits_[0] |= 0x00000800u;
+}
+inline void V0LayerParameter::clear_has_dropout_ratio() {
+  _has_bits_[0] &= ~0x00000800u;
+}
+inline void V0LayerParameter::clear_dropout_ratio() {
+  dropout_ratio_ = 0.5f;
+  clear_has_dropout_ratio();
+}
+inline float V0LayerParameter::dropout_ratio() const {
+  // @@protoc_insertion_point(field_get:caffe.V0LayerParameter.dropout_ratio)
+  return dropout_ratio_;
+}
+inline void V0LayerParameter::set_dropout_ratio(float value) {
+  set_has_dropout_ratio();
+  dropout_ratio_ = value;
+  // @@protoc_insertion_point(field_set:caffe.V0LayerParameter.dropout_ratio)
+}
+
+// optional uint32 local_size = 13 [default = 5];
+inline bool V0LayerParameter::has_local_size() const {
+  return (_has_bits_[0] & 0x00001000u) != 0;
+}
+inline void V0LayerParameter::set_has_local_size() {
+  _has_bits_[0] |= 0x00001000u;
+}
+inline void V0LayerParameter::clear_has_local_size() {
+  _has_bits_[0] &= ~0x00001000u;
+}
+inline void V0LayerParameter::clear_local_size() {
+  local_size_ = 5u;
+  clear_has_local_size();
+}
+inline ::google::protobuf::uint32 V0LayerParameter::local_size() const {
+  // @@protoc_insertion_point(field_get:caffe.V0LayerParameter.local_size)
+  return local_size_;
+}
+inline void V0LayerParameter::set_local_size(::google::protobuf::uint32 value) {
+  set_has_local_size();
+  local_size_ = value;
+  // @@protoc_insertion_point(field_set:caffe.V0LayerParameter.local_size)
+}
+
+// optional float alpha = 14 [default = 1];
+inline bool V0LayerParameter::has_alpha() const {
+  return (_has_bits_[0] & 0x00002000u) != 0;
+}
+inline void V0LayerParameter::set_has_alpha() {
+  _has_bits_[0] |= 0x00002000u;
+}
+inline void V0LayerParameter::clear_has_alpha() {
+  _has_bits_[0] &= ~0x00002000u;
+}
+inline void V0LayerParameter::clear_alpha() {
+  alpha_ = 1;
+  clear_has_alpha();
+}
+inline float V0LayerParameter::alpha() const {
+  // @@protoc_insertion_point(field_get:caffe.V0LayerParameter.alpha)
+  return alpha_;
+}
+inline void V0LayerParameter::set_alpha(float value) {
+  set_has_alpha();
+  alpha_ = value;
+  // @@protoc_insertion_point(field_set:caffe.V0LayerParameter.alpha)
+}
+
+// optional float beta = 15 [default = 0.75];
+inline bool V0LayerParameter::has_beta() const {
+  return (_has_bits_[0] & 0x00004000u) != 0;
+}
+inline void V0LayerParameter::set_has_beta() {
+  _has_bits_[0] |= 0x00004000u;
+}
+inline void V0LayerParameter::clear_has_beta() {
+  _has_bits_[0] &= ~0x00004000u;
+}
+inline void V0LayerParameter::clear_beta() {
+  beta_ = 0.75f;
+  clear_has_beta();
+}
+inline float V0LayerParameter::beta() const {
+  // @@protoc_insertion_point(field_get:caffe.V0LayerParameter.beta)
+  return beta_;
+}
+inline void V0LayerParameter::set_beta(float value) {
+  set_has_beta();
+  beta_ = value;
+  // @@protoc_insertion_point(field_set:caffe.V0LayerParameter.beta)
+}
+
+// optional float k = 22 [default = 1];
+inline bool V0LayerParameter::has_k() const {
+  return (_has_bits_[0] & 0x00008000u) != 0;
+}
+inline void V0LayerParameter::set_has_k() {
+  _has_bits_[0] |= 0x00008000u;
+}
+inline void V0LayerParameter::clear_has_k() {
+  _has_bits_[0] &= ~0x00008000u;
+}
+inline void V0LayerParameter::clear_k() {
+  k_ = 1;
+  clear_has_k();
+}
+inline float V0LayerParameter::k() const {
+  // @@protoc_insertion_point(field_get:caffe.V0LayerParameter.k)
+  return k_;
+}
+inline void V0LayerParameter::set_k(float value) {
+  set_has_k();
+  k_ = value;
+  // @@protoc_insertion_point(field_set:caffe.V0LayerParameter.k)
+}
+
+// optional string source = 16;
+inline bool V0LayerParameter::has_source() const {
+  return (_has_bits_[0] & 0x00010000u) != 0;
+}
+inline void V0LayerParameter::set_has_source() {
+  _has_bits_[0] |= 0x00010000u;
+}
+inline void V0LayerParameter::clear_has_source() {
+  _has_bits_[0] &= ~0x00010000u;
+}
+inline void V0LayerParameter::clear_source() {
+  source_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  clear_has_source();
+}
+inline const ::std::string& V0LayerParameter::source() const {
+  // @@protoc_insertion_point(field_get:caffe.V0LayerParameter.source)
+  return source_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void V0LayerParameter::set_source(const ::std::string& value) {
+  set_has_source();
+  source_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:caffe.V0LayerParameter.source)
+}
+inline void V0LayerParameter::set_source(const char* value) {
+  set_has_source();
+  source_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:caffe.V0LayerParameter.source)
+}
+inline void V0LayerParameter::set_source(const char* value, size_t size) {
+  set_has_source();
+  source_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:caffe.V0LayerParameter.source)
+}
+inline ::std::string* V0LayerParameter::mutable_source() {
+  set_has_source();
+  // @@protoc_insertion_point(field_mutable:caffe.V0LayerParameter.source)
+  return source_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline ::std::string* V0LayerParameter::release_source() {
+  // @@protoc_insertion_point(field_release:caffe.V0LayerParameter.source)
+  clear_has_source();
+  return source_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void V0LayerParameter::set_allocated_source(::std::string* source) {
+  if (source != NULL) {
+    set_has_source();
+  } else {
+    clear_has_source();
+  }
+  source_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), source);
+  // @@protoc_insertion_point(field_set_allocated:caffe.V0LayerParameter.source)
+}
+
+// optional float scale = 17 [default = 1];
+inline bool V0LayerParameter::has_scale() const {
+  return (_has_bits_[0] & 0x00020000u) != 0;
+}
+inline void V0LayerParameter::set_has_scale() {
+  _has_bits_[0] |= 0x00020000u;
+}
+inline void V0LayerParameter::clear_has_scale() {
+  _has_bits_[0] &= ~0x00020000u;
+}
+inline void V0LayerParameter::clear_scale() {
+  scale_ = 1;
+  clear_has_scale();
+}
+inline float V0LayerParameter::scale() const {
+  // @@protoc_insertion_point(field_get:caffe.V0LayerParameter.scale)
+  return scale_;
+}
+inline void V0LayerParameter::set_scale(float value) {
+  set_has_scale();
+  scale_ = value;
+  // @@protoc_insertion_point(field_set:caffe.V0LayerParameter.scale)
+}
+
+// optional string meanfile = 18;
+inline bool V0LayerParameter::has_meanfile() const {
+  return (_has_bits_[0] & 0x00040000u) != 0;
+}
+inline void V0LayerParameter::set_has_meanfile() {
+  _has_bits_[0] |= 0x00040000u;
+}
+inline void V0LayerParameter::clear_has_meanfile() {
+  _has_bits_[0] &= ~0x00040000u;
+}
+inline void V0LayerParameter::clear_meanfile() {
+  meanfile_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  clear_has_meanfile();
+}
+inline const ::std::string& V0LayerParameter::meanfile() const {
+  // @@protoc_insertion_point(field_get:caffe.V0LayerParameter.meanfile)
+  return meanfile_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void V0LayerParameter::set_meanfile(const ::std::string& value) {
+  set_has_meanfile();
+  meanfile_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value);
+  // @@protoc_insertion_point(field_set:caffe.V0LayerParameter.meanfile)
+}
+inline void V0LayerParameter::set_meanfile(const char* value) {
+  set_has_meanfile();
+  meanfile_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:caffe.V0LayerParameter.meanfile)
+}
+inline void V0LayerParameter::set_meanfile(const char* value, size_t size) {
+  set_has_meanfile();
+  meanfile_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:caffe.V0LayerParameter.meanfile)
+}
+inline ::std::string* V0LayerParameter::mutable_meanfile() {
+  set_has_meanfile();
+  // @@protoc_insertion_point(field_mutable:caffe.V0LayerParameter.meanfile)
+  return meanfile_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline ::std::string* V0LayerParameter::release_meanfile() {
+  // @@protoc_insertion_point(field_release:caffe.V0LayerParameter.meanfile)
+  clear_has_meanfile();
+  return meanfile_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void V0LayerParameter::set_allocated_meanfile(::std::string* meanfile) {
+  if (meanfile != NULL) {
+    set_has_meanfile();
+  } else {
+    clear_has_meanfile();
+  }
+  meanfile_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), meanfile);
+  // @@protoc_insertion_point(field_set_allocated:caffe.V0LayerParameter.meanfile)
+}
+
+// optional uint32 batchsize = 19;
+inline bool V0LayerParameter::has_batchsize() const {
+  return (_has_bits_[0] & 0x00080000u) != 0;
+}
+inline void V0LayerParameter::set_has_batchsize() {
+  _has_bits_[0] |= 0x00080000u;
+}
+inline void V0LayerParameter::clear_has_batchsize() {
+  _has_bits_[0] &= ~0x00080000u;
+}
+inline void V0LayerParameter::clear_batchsize() {
+  batchsize_ = 0u;
+  clear_has_batchsize();
+}
+inline ::google::protobuf::uint32 V0LayerParameter::batchsize() const {
+  // @@protoc_insertion_point(field_get:caffe.V0LayerParameter.batchsize)
+  return batchsize_;
+}
+inline void V0LayerParameter::set_batchsize(::google::protobuf::uint32 value) {
+  set_has_batchsize();
+  batchsize_ = value;
+  // @@protoc_insertion_point(field_set:caffe.V0LayerParameter.batchsize)
+}
+
+// optional uint32 cropsize = 20 [default = 0];
+inline bool V0LayerParameter::has_cropsize() const {
+  return (_has_bits_[0] & 0x00100000u) != 0;
+}
+inline void V0LayerParameter::set_has_cropsize() {
+  _has_bits_[0] |= 0x00100000u;
+}
+inline void V0LayerParameter::clear_has_cropsize() {
+  _has_bits_[0] &= ~0x00100000u;
+}
+inline void V0LayerParameter::clear_cropsize() {
+  cropsize_ = 0u;
+  clear_has_cropsize();
+}
+inline ::google::protobuf::uint32 V0LayerParameter::cropsize() const {
+  // @@protoc_insertion_point(field_get:caffe.V0LayerParameter.cropsize)
+  return cropsize_;
+}
+inline void V0LayerParameter::set_cropsize(::google::protobuf::uint32 value) {
+  set_has_cropsize();
+  cropsize_ = value;
+  // @@protoc_insertion_point(field_set:caffe.V0LayerParameter.cropsize)
+}
+
+// optional bool mirror = 21 [default = false];
+inline bool V0LayerParameter::has_mirror() const {
+  return (_has_bits_[0] & 0x00200000u) != 0;
+}
+inline void V0LayerParameter::set_has_mirror() {
+  _has_bits_[0] |= 0x00200000u;
+}
+inline void V0LayerParameter::clear_has_mirror() {
+  _has_bits_[0] &= ~0x00200000u;
+}
+inline void V0LayerParameter::clear_mirror() {
+  mirror_ = false;
+  clear_has_mirror();
+}
+inline bool V0LayerParameter::mirror() const {
+  // @@protoc_insertion_point(field_get:caffe.V0LayerParameter.mirror)
+  return mirror_;
+}
+inline void V0LayerParameter::set_mirror(bool value) {
+  set_has_mirror();
+  mirror_ = value;
+  // @@protoc_insertion_point(field_set:caffe.V0LayerParameter.mirror)
+}
+
+// repeated .caffe.BlobProto blobs = 50;
+inline int V0LayerParameter::blobs_size() const {
+  return blobs_.size();
+}
+inline void V0LayerParameter::clear_blobs() {
+  blobs_.Clear();
+}
+inline const ::caffe::BlobProto& V0LayerParameter::blobs(int index) const {
+  // @@protoc_insertion_point(field_get:caffe.V0LayerParameter.blobs)
+  return blobs_.Get(index);
+}
+inline ::caffe::BlobProto* V0LayerParameter::mutable_blobs(int index) {
+  // @@protoc_insertion_point(field_mutable:caffe.V0LayerParameter.blobs)
+  return blobs_.Mutable(index);
+}
+inline ::caffe::BlobProto* V0LayerParameter::add_blobs() {
+  // @@protoc_insertion_point(field_add:caffe.V0LayerParameter.blobs)
+  return blobs_.Add();
+}
+inline ::google::protobuf::RepeatedPtrField< ::caffe::BlobProto >*
+V0LayerParameter::mutable_blobs() {
+  // @@protoc_insertion_point(field_mutable_list:caffe.V0LayerParameter.blobs)
+  return &blobs_;
+}
+inline const ::google::protobuf::RepeatedPtrField< ::caffe::BlobProto >&
+V0LayerParameter::blobs() const {
+  // @@protoc_insertion_point(field_list:caffe.V0LayerParameter.blobs)
+  return blobs_;
+}
+
+// repeated float blobs_lr = 51;
+inline int V0LayerParameter::blobs_lr_size() const {
+  return blobs_lr_.size();
+}
+inline void V0LayerParameter::clear_blobs_lr() {
+  blobs_lr_.Clear();
+}
+inline float V0LayerParameter::blobs_lr(int index) const {
+  // @@protoc_insertion_point(field_get:caffe.V0LayerParameter.blobs_lr)
+  return blobs_lr_.Get(index);
+}
+inline void V0LayerParameter::set_blobs_lr(int index, float value) {
+  blobs_lr_.Set(index, value);
+  // @@protoc_insertion_point(field_set:caffe.V0LayerParameter.blobs_lr)
+}
+inline void V0LayerParameter::add_blobs_lr(float value) {
+  blobs_lr_.Add(value);
+  // @@protoc_insertion_point(field_add:caffe.V0LayerParameter.blobs_lr)
+}
+inline const ::google::protobuf::RepeatedField< float >&
+V0LayerParameter::blobs_lr() const {
+  // @@protoc_insertion_point(field_list:caffe.V0LayerParameter.blobs_lr)
+  return blobs_lr_;
+}
+inline ::google::protobuf::RepeatedField< float >*
+V0LayerParameter::mutable_blobs_lr() {
+  // @@protoc_insertion_point(field_mutable_list:caffe.V0LayerParameter.blobs_lr)
+  return &blobs_lr_;
+}
+
+// repeated float weight_decay = 52;
+inline int V0LayerParameter::weight_decay_size() const {
+  return weight_decay_.size();
+}
+inline void V0LayerParameter::clear_weight_decay() {
+  weight_decay_.Clear();
+}
+inline float V0LayerParameter::weight_decay(int index) const {
+  // @@protoc_insertion_point(field_get:caffe.V0LayerParameter.weight_decay)
+  return weight_decay_.Get(index);
+}
+inline void V0LayerParameter::set_weight_decay(int index, float value) {
+  weight_decay_.Set(index, value);
+  // @@protoc_insertion_point(field_set:caffe.V0LayerParameter.weight_decay)
+}
+inline void V0LayerParameter::add_weight_decay(float value) {
+  weight_decay_.Add(value);
+  // @@protoc_insertion_point(field_add:caffe.V0LayerParameter.weight_decay)
+}
+inline const ::google::protobuf::RepeatedField< float >&
+V0LayerParameter::weight_decay() const {
+  // @@protoc_insertion_point(field_list:caffe.V0LayerParameter.weight_decay)
+  return weight_decay_;
+}
+inline ::google::protobuf::RepeatedField< float >*
+V0LayerParameter::mutable_weight_decay() {
+  // @@protoc_insertion_point(field_mutable_list:caffe.V0LayerParameter.weight_decay)
+  return &weight_decay_;
+}
+
+// optional uint32 rand_skip = 53 [default = 0];
+inline bool V0LayerParameter::has_rand_skip() const {
+  return (_has_bits_[0] & 0x02000000u) != 0;
+}
+inline void V0LayerParameter::set_has_rand_skip() {
+  _has_bits_[0] |= 0x02000000u;
+}
+inline void V0LayerParameter::clear_has_rand_skip() {
+  _has_bits_[0] &= ~0x02000000u;
+}
+inline void V0LayerParameter::clear_rand_skip() {
+  rand_skip_ = 0u;
+  clear_has_rand_skip();
+}
+inline ::google::protobuf::uint32 V0LayerParameter::rand_skip() const {
+  // @@protoc_insertion_point(field_get:caffe.V0LayerParameter.rand_skip)
+  return rand_skip_;
+}
+inline void V0LayerParameter::set_rand_skip(::google::protobuf::uint32 value) {
+  set_has_rand_skip();
+  rand_skip_ = value;
+  // @@protoc_insertion_point(field_set:caffe.V0LayerParameter.rand_skip)
+}
+
+// optional float det_fg_threshold = 54 [default = 0.5];
+inline bool V0LayerParameter::has_det_fg_threshold() const {
+  return (_has_bits_[0] & 0x04000000u) != 0;
+}
+inline void V0LayerParameter::set_has_det_fg_threshold() {
+  _has_bits_[0] |= 0x04000000u;
+}
+inline void V0LayerParameter::clear_has_det_fg_threshold() {
+  _has_bits_[0] &= ~0x04000000u;
+}
+inline void V0LayerParameter::clear_det_fg_threshold() {
+  det_fg_threshold_ = 0.5f;
+  clear_has_det_fg_threshold();
+}
+inline float V0LayerParameter::det_fg_threshold() const {
+  // @@protoc_insertion_point(field_get:caffe.V0LayerParameter.det_fg_threshold)
+  return det_fg_threshold_;
+}
+inline void V0LayerParameter::set_det_fg_threshold(float value) {
+  set_has_det_fg_threshold();
+  det_fg_threshold_ = value;
+  // @@protoc_insertion_point(field_set:caffe.V0LayerParameter.det_fg_threshold)
+}
+
+// optional float det_bg_threshold = 55 [default = 0.5];
+inline bool V0LayerParameter::has_det_bg_threshold() const {
+  return (_has_bits_[0] & 0x08000000u) != 0;
+}
+inline void V0LayerParameter::set_has_det_bg_threshold() {
+  _has_bits_[0] |= 0x08000000u;
+}
+inline void V0LayerParameter::clear_has_det_bg_threshold() {
+  _has_bits_[0] &= ~0x08000000u;
+}
+inline void V0LayerParameter::clear_det_bg_threshold() {
+  det_bg_threshold_ = 0.5f;
+  clear_has_det_bg_threshold();
+}
+inline float V0LayerParameter::det_bg_threshold() const {
+  // @@protoc_insertion_point(field_get:caffe.V0LayerParameter.det_bg_threshold)
+  return det_bg_threshold_;
+}
+inline void V0LayerParameter::set_det_bg_threshold(float value) {
+  set_has_det_bg_threshold();
+  det_bg_threshold_ = value;
+  // @@protoc_insertion_point(field_set:caffe.V0LayerParameter.det_bg_threshold)
+}
+
+// optional float det_fg_fraction = 56 [default = 0.25];
+inline bool V0LayerParameter::has_det_fg_fraction() const {
+  return (_has_bits_[0] & 0x10000000u) != 0;
+}
+inline void V0LayerParameter::set_has_det_fg_fraction() {
+  _has_bits_[0] |= 0x10000000u;
+}
+inline void V0LayerParameter::clear_has_det_fg_fraction() {
+  _has_bits_[0] &= ~0x10000000u;
+}
+inline void V0LayerParameter::clear_det_fg_fraction() {
+  det_fg_fraction_ = 0.25f;
+  clear_has_det_fg_fraction();
+}
+inline float V0LayerParameter::det_fg_fraction() const {
+  // @@protoc_insertion_point(field_get:caffe.V0LayerParameter.det_fg_fraction)
+  return det_fg_fraction_;
+}
+inline void V0LayerParameter::set_det_fg_fraction(float value) {
+  set_has_det_fg_fraction();
+  det_fg_fraction_ = value;
+  // @@protoc_insertion_point(field_set:caffe.V0LayerParameter.det_fg_fraction)
+}
+
+// optional uint32 det_context_pad = 58 [default = 0];
+inline bool V0LayerParameter::has_det_context_pad() const {
+  return (_has_bits_[0] & 0x20000000u) != 0;
+}
+inline void V0LayerParameter::set_has_det_context_pad() {
+  _has_bits_[0] |= 0x20000000u;
+}
+inline void V0LayerParameter::clear_has_det_context_pad() {
+  _has_bits_[0] &= ~0x20000000u;
+}
+inline void V0LayerParameter::clear_det_context_pad() {
+  det_context_pad_ = 0u;
+  clear_has_det_context_pad();
+}
+inline ::google::protobuf::uint32 V0LayerParameter::det_context_pad() const {
+  // @@protoc_insertion_point(field_get:caffe.V0LayerParameter.det_context_pad)
+  return det_context_pad_;
+}
+inline void V0LayerParameter::set_det_context_pad(::google::protobuf::uint32 value) {
+  set_has_det_context_pad();
+  det_context_pad_ = value;
+  // @@protoc_insertion_point(field_set:caffe.V0LayerParameter.det_context_pad)
+}
+
+// optional string det_crop_mode = 59 [default = "warp"];
+inline bool V0LayerParameter::has_det_crop_mode() const {
+  return (_has_bits_[0] & 0x40000000u) != 0;
+}
+inline void V0LayerParameter::set_has_det_crop_mode() {
+  _has_bits_[0] |= 0x40000000u;
+}
+inline void V0LayerParameter::clear_has_det_crop_mode() {
+  _has_bits_[0] &= ~0x40000000u;
+}
+inline void V0LayerParameter::clear_det_crop_mode() {
+  det_crop_mode_.ClearToDefaultNoArena(_default_det_crop_mode_);
+  clear_has_det_crop_mode();
+}
+inline const ::std::string& V0LayerParameter::det_crop_mode() const {
+  // @@protoc_insertion_point(field_get:caffe.V0LayerParameter.det_crop_mode)
+  return det_crop_mode_.GetNoArena(_default_det_crop_mode_);
+}
+inline void V0LayerParameter::set_det_crop_mode(const ::std::string& value) {
+  set_has_det_crop_mode();
+  det_crop_mode_.SetNoArena(_default_det_crop_mode_, value);
+  // @@protoc_insertion_point(field_set:caffe.V0LayerParameter.det_crop_mode)
+}
+inline void V0LayerParameter::set_det_crop_mode(const char* value) {
+  set_has_det_crop_mode();
+  det_crop_mode_.SetNoArena(_default_det_crop_mode_, ::std::string(value));
+  // @@protoc_insertion_point(field_set_char:caffe.V0LayerParameter.det_crop_mode)
+}
+inline void V0LayerParameter::set_det_crop_mode(const char* value, size_t size) {
+  set_has_det_crop_mode();
+  det_crop_mode_.SetNoArena(_default_det_crop_mode_,
+      ::std::string(reinterpret_cast<const char*>(value), size));
+  // @@protoc_insertion_point(field_set_pointer:caffe.V0LayerParameter.det_crop_mode)
+}
+inline ::std::string* V0LayerParameter::mutable_det_crop_mode() {
+  set_has_det_crop_mode();
+  // @@protoc_insertion_point(field_mutable:caffe.V0LayerParameter.det_crop_mode)
+  return det_crop_mode_.MutableNoArena(_default_det_crop_mode_);
+}
+inline ::std::string* V0LayerParameter::release_det_crop_mode() {
+  // @@protoc_insertion_point(field_release:caffe.V0LayerParameter.det_crop_mode)
+  clear_has_det_crop_mode();
+  return det_crop_mode_.ReleaseNoArena(_default_det_crop_mode_);
+}
+inline void V0LayerParameter::set_allocated_det_crop_mode(::std::string* det_crop_mode) {
+  if (det_crop_mode != NULL) {
+    set_has_det_crop_mode();
+  } else {
+    clear_has_det_crop_mode();
+  }
+  det_crop_mode_.SetAllocatedNoArena(_default_det_crop_mode_, det_crop_mode);
+  // @@protoc_insertion_point(field_set_allocated:caffe.V0LayerParameter.det_crop_mode)
+}
+
+// optional int32 new_num = 60 [default = 0];
+inline bool V0LayerParameter::has_new_num() const {
+  return (_has_bits_[0] & 0x80000000u) != 0;
+}
+inline void V0LayerParameter::set_has_new_num() {
+  _has_bits_[0] |= 0x80000000u;
+}
+inline void V0LayerParameter::clear_has_new_num() {
+  _has_bits_[0] &= ~0x80000000u;
+}
+inline void V0LayerParameter::clear_new_num() {
+  new_num_ = 0;
+  clear_has_new_num();
+}
+inline ::google::protobuf::int32 V0LayerParameter::new_num() const {
+  // @@protoc_insertion_point(field_get:caffe.V0LayerParameter.new_num)
+  return new_num_;
+}
+inline void V0LayerParameter::set_new_num(::google::protobuf::int32 value) {
+  set_has_new_num();
+  new_num_ = value;
+  // @@protoc_insertion_point(field_set:caffe.V0LayerParameter.new_num)
+}
+
+// optional int32 new_channels = 61 [default = 0];
+inline bool V0LayerParameter::has_new_channels() const {
+  return (_has_bits_[1] & 0x00000001u) != 0;
+}
+inline void V0LayerParameter::set_has_new_channels() {
+  _has_bits_[1] |= 0x00000001u;
+}
+inline void V0LayerParameter::clear_has_new_channels() {
+  _has_bits_[1] &= ~0x00000001u;
+}
+inline void V0LayerParameter::clear_new_channels() {
+  new_channels_ = 0;
+  clear_has_new_channels();
+}
+inline ::google::protobuf::int32 V0LayerParameter::new_channels() const {
+  // @@protoc_insertion_point(field_get:caffe.V0LayerParameter.new_channels)
+  return new_channels_;
+}
+inline void V0LayerParameter::set_new_channels(::google::protobuf::int32 value) {
+  set_has_new_channels();
+  new_channels_ = value;
+  // @@protoc_insertion_point(field_set:caffe.V0LayerParameter.new_channels)
+}
+
+// optional int32 new_height = 62 [default = 0];
+inline bool V0LayerParameter::has_new_height() const {
+  return (_has_bits_[1] & 0x00000002u) != 0;
+}
+inline void V0LayerParameter::set_has_new_height() {
+  _has_bits_[1] |= 0x00000002u;
+}
+inline void V0LayerParameter::clear_has_new_height() {
+  _has_bits_[1] &= ~0x00000002u;
+}
+inline void V0LayerParameter::clear_new_height() {
+  new_height_ = 0;
+  clear_has_new_height();
+}
+inline ::google::protobuf::int32 V0LayerParameter::new_height() const {
+  // @@protoc_insertion_point(field_get:caffe.V0LayerParameter.new_height)
+  return new_height_;
+}
+inline void V0LayerParameter::set_new_height(::google::protobuf::int32 value) {
+  set_has_new_height();
+  new_height_ = value;
+  // @@protoc_insertion_point(field_set:caffe.V0LayerParameter.new_height)
+}
+
+// optional int32 new_width = 63 [default = 0];
+inline bool V0LayerParameter::has_new_width() const {
+  return (_has_bits_[1] & 0x00000004u) != 0;
+}
+inline void V0LayerParameter::set_has_new_width() {
+  _has_bits_[1] |= 0x00000004u;
+}
+inline void V0LayerParameter::clear_has_new_width() {
+  _has_bits_[1] &= ~0x00000004u;
+}
+inline void V0LayerParameter::clear_new_width() {
+  new_width_ = 0;
+  clear_has_new_width();
+}
+inline ::google::protobuf::int32 V0LayerParameter::new_width() const {
+  // @@protoc_insertion_point(field_get:caffe.V0LayerParameter.new_width)
+  return new_width_;
+}
+inline void V0LayerParameter::set_new_width(::google::protobuf::int32 value) {
+  set_has_new_width();
+  new_width_ = value;
+  // @@protoc_insertion_point(field_set:caffe.V0LayerParameter.new_width)
+}
+
+// optional bool shuffle_images = 64 [default = false];
+inline bool V0LayerParameter::has_shuffle_images() const {
+  return (_has_bits_[1] & 0x00000008u) != 0;
+}
+inline void V0LayerParameter::set_has_shuffle_images() {
+  _has_bits_[1] |= 0x00000008u;
+}
+inline void V0LayerParameter::clear_has_shuffle_images() {
+  _has_bits_[1] &= ~0x00000008u;
+}
+inline void V0LayerParameter::clear_shuffle_images() {
+  shuffle_images_ = false;
+  clear_has_shuffle_images();
+}
+inline bool V0LayerParameter::shuffle_images() const {
+  // @@protoc_insertion_point(field_get:caffe.V0LayerParameter.shuffle_images)
+  return shuffle_images_;
+}
+inline void V0LayerParameter::set_shuffle_images(bool value) {
+  set_has_shuffle_images();
+  shuffle_images_ = value;
+  // @@protoc_insertion_point(field_set:caffe.V0LayerParameter.shuffle_images)
+}
+
+// optional uint32 concat_dim = 65 [default = 1];
+inline bool V0LayerParameter::has_concat_dim() const {
+  return (_has_bits_[1] & 0x00000010u) != 0;
+}
+inline void V0LayerParameter::set_has_concat_dim() {
+  _has_bits_[1] |= 0x00000010u;
+}
+inline void V0LayerParameter::clear_has_concat_dim() {
+  _has_bits_[1] &= ~0x00000010u;
+}
+inline void V0LayerParameter::clear_concat_dim() {
+  concat_dim_ = 1u;
+  clear_has_concat_dim();
+}
+inline ::google::protobuf::uint32 V0LayerParameter::concat_dim() const {
+  // @@protoc_insertion_point(field_get:caffe.V0LayerParameter.concat_dim)
+  return concat_dim_;
+}
+inline void V0LayerParameter::set_concat_dim(::google::protobuf::uint32 value) {
+  set_has_concat_dim();
+  concat_dim_ = value;
+  // @@protoc_insertion_point(field_set:caffe.V0LayerParameter.concat_dim)
+}
+
+// optional .caffe.HDF5OutputParameter hdf5_output_param = 1001;
+inline bool V0LayerParameter::has_hdf5_output_param() const {
+  return (_has_bits_[1] & 0x00000020u) != 0;
+}
+inline void V0LayerParameter::set_has_hdf5_output_param() {
+  _has_bits_[1] |= 0x00000020u;
+}
+inline void V0LayerParameter::clear_has_hdf5_output_param() {
+  _has_bits_[1] &= ~0x00000020u;
+}
+inline void V0LayerParameter::clear_hdf5_output_param() {
+  if (hdf5_output_param_ != NULL) hdf5_output_param_->::caffe::HDF5OutputParameter::Clear();
+  clear_has_hdf5_output_param();
+}
+inline const ::caffe::HDF5OutputParameter& V0LayerParameter::hdf5_output_param() const {
+  // @@protoc_insertion_point(field_get:caffe.V0LayerParameter.hdf5_output_param)
+  return hdf5_output_param_ != NULL ? *hdf5_output_param_
+                         : *::caffe::HDF5OutputParameter::internal_default_instance();
+}
+inline ::caffe::HDF5OutputParameter* V0LayerParameter::mutable_hdf5_output_param() {
+  set_has_hdf5_output_param();
+  if (hdf5_output_param_ == NULL) {
+    hdf5_output_param_ = new ::caffe::HDF5OutputParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.V0LayerParameter.hdf5_output_param)
+  return hdf5_output_param_;
+}
+inline ::caffe::HDF5OutputParameter* V0LayerParameter::release_hdf5_output_param() {
+  // @@protoc_insertion_point(field_release:caffe.V0LayerParameter.hdf5_output_param)
+  clear_has_hdf5_output_param();
+  ::caffe::HDF5OutputParameter* temp = hdf5_output_param_;
+  hdf5_output_param_ = NULL;
+  return temp;
+}
+inline void V0LayerParameter::set_allocated_hdf5_output_param(::caffe::HDF5OutputParameter* hdf5_output_param) {
+  delete hdf5_output_param_;
+  hdf5_output_param_ = hdf5_output_param;
+  if (hdf5_output_param) {
+    set_has_hdf5_output_param();
+  } else {
+    clear_has_hdf5_output_param();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.V0LayerParameter.hdf5_output_param)
+}
+
+inline const V0LayerParameter* V0LayerParameter::internal_default_instance() {
+  return &V0LayerParameter_default_instance_.get();
+}
+// -------------------------------------------------------------------
+
+// PReLUParameter
+
+// optional .caffe.FillerParameter filler = 1;
+inline bool PReLUParameter::has_filler() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+inline void PReLUParameter::set_has_filler() {
+  _has_bits_[0] |= 0x00000001u;
+}
+inline void PReLUParameter::clear_has_filler() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+inline void PReLUParameter::clear_filler() {
+  if (filler_ != NULL) filler_->::caffe::FillerParameter::Clear();
+  clear_has_filler();
+}
+inline const ::caffe::FillerParameter& PReLUParameter::filler() const {
+  // @@protoc_insertion_point(field_get:caffe.PReLUParameter.filler)
+  return filler_ != NULL ? *filler_
+                         : *::caffe::FillerParameter::internal_default_instance();
+}
+inline ::caffe::FillerParameter* PReLUParameter::mutable_filler() {
+  set_has_filler();
+  if (filler_ == NULL) {
+    filler_ = new ::caffe::FillerParameter;
+  }
+  // @@protoc_insertion_point(field_mutable:caffe.PReLUParameter.filler)
+  return filler_;
+}
+inline ::caffe::FillerParameter* PReLUParameter::release_filler() {
+  // @@protoc_insertion_point(field_release:caffe.PReLUParameter.filler)
+  clear_has_filler();
+  ::caffe::FillerParameter* temp = filler_;
+  filler_ = NULL;
+  return temp;
+}
+inline void PReLUParameter::set_allocated_filler(::caffe::FillerParameter* filler) {
+  delete filler_;
+  filler_ = filler;
+  if (filler) {
+    set_has_filler();
+  } else {
+    clear_has_filler();
+  }
+  // @@protoc_insertion_point(field_set_allocated:caffe.PReLUParameter.filler)
+}
+
+// optional bool channel_shared = 2 [default = false];
+inline bool PReLUParameter::has_channel_shared() const {
+  return (_has_bits_[0] & 0x00000002u) != 0;
+}
+inline void PReLUParameter::set_has_channel_shared() {
+  _has_bits_[0] |= 0x00000002u;
+}
+inline void PReLUParameter::clear_has_channel_shared() {
+  _has_bits_[0] &= ~0x00000002u;
+}
+inline void PReLUParameter::clear_channel_shared() {
+  channel_shared_ = false;
+  clear_has_channel_shared();
+}
+inline bool PReLUParameter::channel_shared() const {
+  // @@protoc_insertion_point(field_get:caffe.PReLUParameter.channel_shared)
+  return channel_shared_;
+}
+inline void PReLUParameter::set_channel_shared(bool value) {
+  set_has_channel_shared();
+  channel_shared_ = value;
+  // @@protoc_insertion_point(field_set:caffe.PReLUParameter.channel_shared)
+}
+
+inline const PReLUParameter* PReLUParameter::internal_default_instance() {
+  return &PReLUParameter_default_instance_.get();
+}
+// -------------------------------------------------------------------
+
+// NormalizedBBox
+
+// optional float xmin = 1;
+inline bool NormalizedBBox::has_xmin() const {
+  return (_has_bits_[0] & 0x00000001u) != 0;
+}
+inline void NormalizedBBox::set_has_xmin() {
+  _has_bits_[0] |= 0x00000001u;
+}
+inline void NormalizedBBox::clear_has_xmin() {
+  _has_bits_[0] &= ~0x00000001u;
+}
+inline void NormalizedBBox::clear_xmin() {
+  xmin_ = 0;
+  clear_has_xmin();
+}
+inline float NormalizedBBox::xmin() const {
+  // @@protoc_insertion_point(field_get:caffe.NormalizedBBox.xmin)
+  return xmin_;
+}
+inline void NormalizedBBox::set_xmin(float value) {
+  set_has_xmin();
+  xmin_ = value;
+  // @@protoc_insertion_point(field_set:caffe.NormalizedBBox.xmin)
+}
+
+// optional float ymin = 2;
+inline bool NormalizedBBox::has_ymin() const {
+  return (_has_bits_[0] & 0x00000002u) != 0;
+}
+inline void NormalizedBBox::set_has_ymin() {
+  _has_bits_[0] |= 0x00000002u;
+}
+inline void NormalizedBBox::clear_has_ymin() {
+  _has_bits_[0] &= ~0x00000002u;
+}
+inline void NormalizedBBox::clear_ymin() {
+  ymin_ = 0;
+  clear_has_ymin();
+}
+inline float NormalizedBBox::ymin() const {
+  // @@protoc_insertion_point(field_get:caffe.NormalizedBBox.ymin)
+  return ymin_;
+}
+inline void NormalizedBBox::set_ymin(float value) {
+  set_has_ymin();
+  ymin_ = value;
+  // @@protoc_insertion_point(field_set:caffe.NormalizedBBox.ymin)
+}
+
+// optional float xmax = 3;
+inline bool NormalizedBBox::has_xmax() const {
+  return (_has_bits_[0] & 0x00000004u) != 0;
+}
+inline void NormalizedBBox::set_has_xmax() {
+  _has_bits_[0] |= 0x00000004u;
+}
+inline void NormalizedBBox::clear_has_xmax() {
+  _has_bits_[0] &= ~0x00000004u;
+}
+inline void NormalizedBBox::clear_xmax() {
+  xmax_ = 0;
+  clear_has_xmax();
+}
+inline float NormalizedBBox::xmax() const {
+  // @@protoc_insertion_point(field_get:caffe.NormalizedBBox.xmax)
+  return xmax_;
+}
+inline void NormalizedBBox::set_xmax(float value) {
+  set_has_xmax();
+  xmax_ = value;
+  // @@protoc_insertion_point(field_set:caffe.NormalizedBBox.xmax)
+}
+
+// optional float ymax = 4;
+inline bool NormalizedBBox::has_ymax() const {
+  return (_has_bits_[0] & 0x00000008u) != 0;
+}
+inline void NormalizedBBox::set_has_ymax() {
+  _has_bits_[0] |= 0x00000008u;
+}
+inline void NormalizedBBox::clear_has_ymax() {
+  _has_bits_[0] &= ~0x00000008u;
+}
+inline void NormalizedBBox::clear_ymax() {
+  ymax_ = 0;
+  clear_has_ymax();
+}
+inline float NormalizedBBox::ymax() const {
+  // @@protoc_insertion_point(field_get:caffe.NormalizedBBox.ymax)
+  return ymax_;
+}
+inline void NormalizedBBox::set_ymax(float value) {
+  set_has_ymax();
+  ymax_ = value;
+  // @@protoc_insertion_point(field_set:caffe.NormalizedBBox.ymax)
+}
+
+// optional int32 label = 5;
+inline bool NormalizedBBox::has_label() const {
+  return (_has_bits_[0] & 0x00000010u) != 0;
+}
+inline void NormalizedBBox::set_has_label() {
+  _has_bits_[0] |= 0x00000010u;
+}
+inline void NormalizedBBox::clear_has_label() {
+  _has_bits_[0] &= ~0x00000010u;
+}
+inline void NormalizedBBox::clear_label() {
+  label_ = 0;
+  clear_has_label();
+}
+inline ::google::protobuf::int32 NormalizedBBox::label() const {
+  // @@protoc_insertion_point(field_get:caffe.NormalizedBBox.label)
+  return label_;
+}
+inline void NormalizedBBox::set_label(::google::protobuf::int32 value) {
+  set_has_label();
+  label_ = value;
+  // @@protoc_insertion_point(field_set:caffe.NormalizedBBox.label)
+}
+
+// optional bool difficult = 6;
+inline bool NormalizedBBox::has_difficult() const {
+  return (_has_bits_[0] & 0x00000020u) != 0;
+}
+inline void NormalizedBBox::set_has_difficult() {
+  _has_bits_[0] |= 0x00000020u;
+}
+inline void NormalizedBBox::clear_has_difficult() {
+  _has_bits_[0] &= ~0x00000020u;
+}
+inline void NormalizedBBox::clear_difficult() {
+  difficult_ = false;
+  clear_has_difficult();
+}
+inline bool NormalizedBBox::difficult() const {
+  // @@protoc_insertion_point(field_get:caffe.NormalizedBBox.difficult)
+  return difficult_;
+}
+inline void NormalizedBBox::set_difficult(bool value) {
+  set_has_difficult();
+  difficult_ = value;
+  // @@protoc_insertion_point(field_set:caffe.NormalizedBBox.difficult)
+}
+
+// optional float score = 7;
+inline bool NormalizedBBox::has_score() const {
+  return (_has_bits_[0] & 0x00000040u) != 0;
+}
+inline void NormalizedBBox::set_has_score() {
+  _has_bits_[0] |= 0x00000040u;
+}
+inline void NormalizedBBox::clear_has_score() {
+  _has_bits_[0] &= ~0x00000040u;
+}
+inline void NormalizedBBox::clear_score() {
+  score_ = 0;
+  clear_has_score();
+}
+inline float NormalizedBBox::score() const {
+  // @@protoc_insertion_point(field_get:caffe.NormalizedBBox.score)
+  return score_;
+}
+inline void NormalizedBBox::set_score(float value) {
+  set_has_score();
+  score_ = value;
+  // @@protoc_insertion_point(field_set:caffe.NormalizedBBox.score)
+}
+
+// optional float size = 8;
+inline bool NormalizedBBox::has_size() const {
+  return (_has_bits_[0] & 0x00000080u) != 0;
+}
+inline void NormalizedBBox::set_has_size() {
+  _has_bits_[0] |= 0x00000080u;
+}
+inline void NormalizedBBox::clear_has_size() {
+  _has_bits_[0] &= ~0x00000080u;
+}
+inline void NormalizedBBox::clear_size() {
+  size_ = 0;
+  clear_has_size();
+}
+inline float NormalizedBBox::size() const {
+  // @@protoc_insertion_point(field_get:caffe.NormalizedBBox.size)
+  return size_;
+}
+inline void NormalizedBBox::set_size(float value) {
+  set_has_size();
+  size_ = value;
+  // @@protoc_insertion_point(field_set:caffe.NormalizedBBox.size)
+}
+
+inline const NormalizedBBox* NormalizedBBox::internal_default_instance() {
+  return &NormalizedBBox_default_instance_.get();
+}
+#endif  // !PROTOBUF_INLINE_NOT_IN_HEADERS
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+
+// @@protoc_insertion_point(namespace_scope)
+
+}  // namespace caffe
+
+#ifndef SWIG
+namespace google {
+namespace protobuf {
+
+template <> struct is_proto_enum< ::caffe::PriorBoxParameter_CodeType> : ::google::protobuf::internal::true_type {};
+template <>
+inline const EnumDescriptor* GetEnumDescriptor< ::caffe::PriorBoxParameter_CodeType>() {
+  return ::caffe::PriorBoxParameter_CodeType_descriptor();
+}
+template <> struct is_proto_enum< ::caffe::FillerParameter_VarianceNorm> : ::google::protobuf::internal::true_type {};
+template <>
+inline const EnumDescriptor* GetEnumDescriptor< ::caffe::FillerParameter_VarianceNorm>() {
+  return ::caffe::FillerParameter_VarianceNorm_descriptor();
+}
+template <> struct is_proto_enum< ::caffe::SolverParameter_SolverMode> : ::google::protobuf::internal::true_type {};
+template <>
+inline const EnumDescriptor* GetEnumDescriptor< ::caffe::SolverParameter_SolverMode>() {
+  return ::caffe::SolverParameter_SolverMode_descriptor();
+}
+template <> struct is_proto_enum< ::caffe::SolverParameter_SolverType> : ::google::protobuf::internal::true_type {};
+template <>
+inline const EnumDescriptor* GetEnumDescriptor< ::caffe::SolverParameter_SolverType>() {
+  return ::caffe::SolverParameter_SolverType_descriptor();
+}
+template <> struct is_proto_enum< ::caffe::ParamSpec_DimCheckMode> : ::google::protobuf::internal::true_type {};
+template <>
+inline const EnumDescriptor* GetEnumDescriptor< ::caffe::ParamSpec_DimCheckMode>() {
+  return ::caffe::ParamSpec_DimCheckMode_descriptor();
+}
+template <> struct is_proto_enum< ::caffe::ConvolutionParameter_Engine> : ::google::protobuf::internal::true_type {};
+template <>
+inline const EnumDescriptor* GetEnumDescriptor< ::caffe::ConvolutionParameter_Engine>() {
+  return ::caffe::ConvolutionParameter_Engine_descriptor();
+}
+template <> struct is_proto_enum< ::caffe::DataParameter_DB> : ::google::protobuf::internal::true_type {};
+template <>
+inline const EnumDescriptor* GetEnumDescriptor< ::caffe::DataParameter_DB>() {
+  return ::caffe::DataParameter_DB_descriptor();
+}
+template <> struct is_proto_enum< ::caffe::EltwiseParameter_EltwiseOp> : ::google::protobuf::internal::true_type {};
+template <>
+inline const EnumDescriptor* GetEnumDescriptor< ::caffe::EltwiseParameter_EltwiseOp>() {
+  return ::caffe::EltwiseParameter_EltwiseOp_descriptor();
+}
+template <> struct is_proto_enum< ::caffe::HingeLossParameter_Norm> : ::google::protobuf::internal::true_type {};
+template <>
+inline const EnumDescriptor* GetEnumDescriptor< ::caffe::HingeLossParameter_Norm>() {
+  return ::caffe::HingeLossParameter_Norm_descriptor();
+}
+template <> struct is_proto_enum< ::caffe::LRNParameter_NormRegion> : ::google::protobuf::internal::true_type {};
+template <>
+inline const EnumDescriptor* GetEnumDescriptor< ::caffe::LRNParameter_NormRegion>() {
+  return ::caffe::LRNParameter_NormRegion_descriptor();
+}
+template <> struct is_proto_enum< ::caffe::PoolingParameter_PoolMethod> : ::google::protobuf::internal::true_type {};
+template <>
+inline const EnumDescriptor* GetEnumDescriptor< ::caffe::PoolingParameter_PoolMethod>() {
+  return ::caffe::PoolingParameter_PoolMethod_descriptor();
+}
+template <> struct is_proto_enum< ::caffe::PoolingParameter_Engine> : ::google::protobuf::internal::true_type {};
+template <>
+inline const EnumDescriptor* GetEnumDescriptor< ::caffe::PoolingParameter_Engine>() {
+  return ::caffe::PoolingParameter_Engine_descriptor();
+}
+template <> struct is_proto_enum< ::caffe::ReductionParameter_ReductionOp> : ::google::protobuf::internal::true_type {};
+template <>
+inline const EnumDescriptor* GetEnumDescriptor< ::caffe::ReductionParameter_ReductionOp>() {
+  return ::caffe::ReductionParameter_ReductionOp_descriptor();
+}
+template <> struct is_proto_enum< ::caffe::ReLUParameter_Engine> : ::google::protobuf::internal::true_type {};
+template <>
+inline const EnumDescriptor* GetEnumDescriptor< ::caffe::ReLUParameter_Engine>() {
+  return ::caffe::ReLUParameter_Engine_descriptor();
+}
+template <> struct is_proto_enum< ::caffe::SigmoidParameter_Engine> : ::google::protobuf::internal::true_type {};
+template <>
+inline const EnumDescriptor* GetEnumDescriptor< ::caffe::SigmoidParameter_Engine>() {
+  return ::caffe::SigmoidParameter_Engine_descriptor();
+}
+template <> struct is_proto_enum< ::caffe::SoftmaxParameter_Engine> : ::google::protobuf::internal::true_type {};
+template <>
+inline const EnumDescriptor* GetEnumDescriptor< ::caffe::SoftmaxParameter_Engine>() {
+  return ::caffe::SoftmaxParameter_Engine_descriptor();
+}
+template <> struct is_proto_enum< ::caffe::TanHParameter_Engine> : ::google::protobuf::internal::true_type {};
+template <>
+inline const EnumDescriptor* GetEnumDescriptor< ::caffe::TanHParameter_Engine>() {
+  return ::caffe::TanHParameter_Engine_descriptor();
+}
+template <> struct is_proto_enum< ::caffe::SPPParameter_PoolMethod> : ::google::protobuf::internal::true_type {};
+template <>
+inline const EnumDescriptor* GetEnumDescriptor< ::caffe::SPPParameter_PoolMethod>() {
+  return ::caffe::SPPParameter_PoolMethod_descriptor();
+}
+template <> struct is_proto_enum< ::caffe::SPPParameter_Engine> : ::google::protobuf::internal::true_type {};
+template <>
+inline const EnumDescriptor* GetEnumDescriptor< ::caffe::SPPParameter_Engine>() {
+  return ::caffe::SPPParameter_Engine_descriptor();
+}
+template <> struct is_proto_enum< ::caffe::V1LayerParameter_LayerType> : ::google::protobuf::internal::true_type {};
+template <>
+inline const EnumDescriptor* GetEnumDescriptor< ::caffe::V1LayerParameter_LayerType>() {
+  return ::caffe::V1LayerParameter_LayerType_descriptor();
+}
+template <> struct is_proto_enum< ::caffe::V1LayerParameter_DimCheckMode> : ::google::protobuf::internal::true_type {};
+template <>
+inline const EnumDescriptor* GetEnumDescriptor< ::caffe::V1LayerParameter_DimCheckMode>() {
+  return ::caffe::V1LayerParameter_DimCheckMode_descriptor();
+}
+template <> struct is_proto_enum< ::caffe::V0LayerParameter_PoolMethod> : ::google::protobuf::internal::true_type {};
+template <>
+inline const EnumDescriptor* GetEnumDescriptor< ::caffe::V0LayerParameter_PoolMethod>() {
+  return ::caffe::V0LayerParameter_PoolMethod_descriptor();
+}
+template <> struct is_proto_enum< ::caffe::Phase> : ::google::protobuf::internal::true_type {};
+template <>
+inline const EnumDescriptor* GetEnumDescriptor< ::caffe::Phase>() {
+  return ::caffe::Phase_descriptor();
+}
+
+}  // namespace protobuf
+}  // namespace google
+#endif  // SWIG
+
+// @@protoc_insertion_point(global_scope)
+
+#endif  // PROTOBUF_caffe_2eproto__INCLUDED
diff --git a/contrib/modules/dnn/misc/python/pyopencv_dnn.hpp b/contrib/modules/dnn/misc/python/pyopencv_dnn.hpp
new file mode 100644
index 0000000..06661de
--- /dev/null
+++ b/contrib/modules/dnn/misc/python/pyopencv_dnn.hpp
@@ -0,0 +1,108 @@
+#ifdef HAVE_OPENCV_DNN
+typedef dnn::DictValue LayerId;
+typedef std::vector<cv::dnn::Blob> vector_Blob;
+
+template<>
+bool pyopencv_to(PyObject *o, dnn::Blob &blob, const char *name);
+
+template<> struct pyopencvVecConverter<dnn::Blob>
+{
+    static bool to(PyObject* obj, std::vector<dnn::Blob>& value, const ArgInfo info)
+    {
+        if (PyArray_Check(obj))
+        {
+            value.resize(1);
+            return pyopencv_to(obj, value[0], info.name);
+        }
+
+        return pyopencv_to_generic_vec(obj, value, info);
+    }
+
+    static PyObject* from(const std::vector<dnn::Blob>& value)
+    {
+        return pyopencv_from_generic_vec(value);
+    }
+};
+
+template<>
+bool pyopencv_to(PyObject *o, std::vector<dnn::Blob> &blobs, const char *name) //required for Layer::blobs RW
+{
+    return pyopencvVecConverter<dnn::Blob>::to(o, blobs, ArgInfo(name, false));
+}
+
+template<>
+bool pyopencv_to(PyObject *o, dnn::Blob &blob, const char *name)
+{
+    Mat &dst = blob.matRef();
+    if (!pyopencv_to(o, dst, name))
+        return false;
+
+    if (PyArray_Check(o)) //try fix channels
+    {
+        PyArrayObject* oarr = (PyArrayObject*) o;
+
+        if (PyArray_NDIM(oarr) == dst.dims)
+            return true;
+
+        int ndims = PyArray_NDIM(oarr);
+        std::vector<int> shape(ndims);
+        const npy_intp* _sizes = PyArray_DIMS(oarr);
+        for (int i = 0; i < ndims; i++)
+            shape[i] = (int)_sizes[i];
+
+        dst = dst.reshape(1, ndims, &shape[0]);
+    }
+
+    return true;
+}
+
+template<>
+PyObject *pyopencv_from(const dnn::Blob &blob)
+{
+    return pyopencv_from(blob.matRefConst());
+}
+
+template<>
+bool pyopencv_to(PyObject *o, dnn::DictValue &dv, const char *name)
+{
+    (void)name;
+    if (!o || o == Py_None)
+        return true; //Current state will be used
+    else if (PyLong_Check(o))
+    {
+        dv = dnn::DictValue((int64)PyLong_AsLongLong(o));
+        return true;
+    }
+    else if (PyFloat_Check(o))
+    {
+        dv = dnn::DictValue(PyFloat_AS_DOUBLE(o));
+        return true;
+    }
+    else if (PyString_Check(o))
+    {
+        dv = dnn::DictValue(String(PyString_AsString(o)));
+        return true;
+    }
+    else
+        return false;
+}
+
+template<>
+bool pyopencv_to(PyObject *o, dnn::BlobShape &shape, const char *name)
+{
+    std::vector<int> data;
+    if (!pyopencv_to_generic_vec(o, data, ArgInfo(name, false)))
+        return false;
+
+    shape = data.size() ? dnn::BlobShape((int)data.size(), &data[0]) : dnn::BlobShape::empty();
+    return true;
+}
+
+template<>
+PyObject *pyopencv_from(const dnn::BlobShape &shape)
+{
+    std::vector<int> data(shape.ptr(), shape.ptr() + shape.dims());
+    return pyopencv_from_generic_vec(data);
+}
+
+#endif
\ No newline at end of file
diff --git a/contrib/modules/dnn/misc/tensorflow/attr_value.pb.cc b/contrib/modules/dnn/misc/tensorflow/attr_value.pb.cc
new file mode 100644
index 0000000..deb3320
--- /dev/null
+++ b/contrib/modules/dnn/misc/tensorflow/attr_value.pb.cc
@@ -0,0 +1,3014 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: attr_value.proto
+
+#define INTERNAL_SUPPRESS_PROTOBUF_FIELD_DEPRECATION
+#include "attr_value.pb.h"
+
+#include <algorithm>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/port.h>
+#include <google/protobuf/stubs/once.h>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/wire_format_lite_inl.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/generated_message_reflection.h>
+#include <google/protobuf/reflection_ops.h>
+#include <google/protobuf/wire_format.h>
+// @@protoc_insertion_point(includes)
+
+namespace tensorflow {
+
+namespace {
+
+const ::google::protobuf::Descriptor* AttrValue_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+  AttrValue_reflection_ = NULL;
+struct AttrValueOneofInstance {
+  ::google::protobuf::internal::ArenaStringPtr s_;
+  ::google::protobuf::int64 i_;
+  float f_;
+  bool b_;
+  int type_;
+  const ::tensorflow::TensorShapeProto* shape_;
+  const ::tensorflow::TensorProto* tensor_;
+  const ::tensorflow::AttrValue_ListValue* list_;
+  const ::tensorflow::NameAttrList* func_;
+  ::google::protobuf::internal::ArenaStringPtr placeholder_;
+}* AttrValue_default_oneof_instance_ = NULL;
+const ::google::protobuf::Descriptor* AttrValue_ListValue_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+  AttrValue_ListValue_reflection_ = NULL;
+const ::google::protobuf::Descriptor* NameAttrList_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+  NameAttrList_reflection_ = NULL;
+const ::google::protobuf::Descriptor* NameAttrList_AttrEntry_descriptor_ = NULL;
+
+}  // namespace
+
+
+void protobuf_AssignDesc_attr_5fvalue_2eproto() GOOGLE_ATTRIBUTE_COLD;
+void protobuf_AssignDesc_attr_5fvalue_2eproto() {
+  protobuf_AddDesc_attr_5fvalue_2eproto();
+  const ::google::protobuf::FileDescriptor* file =
+    ::google::protobuf::DescriptorPool::generated_pool()->FindFileByName(
+      "attr_value.proto");
+  GOOGLE_CHECK(file != NULL);
+  AttrValue_descriptor_ = file->message_type(0);
+  static const int AttrValue_offsets_[11] = {
+    PROTO2_GENERATED_DEFAULT_ONEOF_FIELD_OFFSET(AttrValue_default_oneof_instance_, s_),
+    PROTO2_GENERATED_DEFAULT_ONEOF_FIELD_OFFSET(AttrValue_default_oneof_instance_, i_),
+    PROTO2_GENERATED_DEFAULT_ONEOF_FIELD_OFFSET(AttrValue_default_oneof_instance_, f_),
+    PROTO2_GENERATED_DEFAULT_ONEOF_FIELD_OFFSET(AttrValue_default_oneof_instance_, b_),
+    PROTO2_GENERATED_DEFAULT_ONEOF_FIELD_OFFSET(AttrValue_default_oneof_instance_, type_),
+    PROTO2_GENERATED_DEFAULT_ONEOF_FIELD_OFFSET(AttrValue_default_oneof_instance_, shape_),
+    PROTO2_GENERATED_DEFAULT_ONEOF_FIELD_OFFSET(AttrValue_default_oneof_instance_, tensor_),
+    PROTO2_GENERATED_DEFAULT_ONEOF_FIELD_OFFSET(AttrValue_default_oneof_instance_, list_),
+    PROTO2_GENERATED_DEFAULT_ONEOF_FIELD_OFFSET(AttrValue_default_oneof_instance_, func_),
+    PROTO2_GENERATED_DEFAULT_ONEOF_FIELD_OFFSET(AttrValue_default_oneof_instance_, placeholder_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(AttrValue, value_),
+  };
+  AttrValue_reflection_ =
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
+      AttrValue_descriptor_,
+      AttrValue::internal_default_instance(),
+      AttrValue_offsets_,
+      -1,
+      -1,
+      -1,
+      AttrValue_default_oneof_instance_,
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(AttrValue, _oneof_case_[0]),
+      sizeof(AttrValue),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(AttrValue, _internal_metadata_));
+  AttrValue_ListValue_descriptor_ = AttrValue_descriptor_->nested_type(0);
+  static const int AttrValue_ListValue_offsets_[7] = {
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(AttrValue_ListValue, s_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(AttrValue_ListValue, i_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(AttrValue_ListValue, f_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(AttrValue_ListValue, b_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(AttrValue_ListValue, type_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(AttrValue_ListValue, shape_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(AttrValue_ListValue, tensor_),
+  };
+  AttrValue_ListValue_reflection_ =
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
+      AttrValue_ListValue_descriptor_,
+      AttrValue_ListValue::internal_default_instance(),
+      AttrValue_ListValue_offsets_,
+      -1,
+      -1,
+      -1,
+      sizeof(AttrValue_ListValue),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(AttrValue_ListValue, _internal_metadata_));
+  NameAttrList_descriptor_ = file->message_type(1);
+  static const int NameAttrList_offsets_[2] = {
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(NameAttrList, name_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(NameAttrList, attr_),
+  };
+  NameAttrList_reflection_ =
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
+      NameAttrList_descriptor_,
+      NameAttrList::internal_default_instance(),
+      NameAttrList_offsets_,
+      -1,
+      -1,
+      -1,
+      sizeof(NameAttrList),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(NameAttrList, _internal_metadata_));
+  NameAttrList_AttrEntry_descriptor_ = NameAttrList_descriptor_->nested_type(0);
+}
+
+namespace {
+
+GOOGLE_PROTOBUF_DECLARE_ONCE(protobuf_AssignDescriptors_once_);
+void protobuf_AssignDescriptorsOnce() {
+  ::google::protobuf::GoogleOnceInit(&protobuf_AssignDescriptors_once_,
+                 &protobuf_AssignDesc_attr_5fvalue_2eproto);
+}
+
+void protobuf_RegisterTypes(const ::std::string&) GOOGLE_ATTRIBUTE_COLD;
+void protobuf_RegisterTypes(const ::std::string&) {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+      AttrValue_descriptor_, AttrValue::internal_default_instance());
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+      AttrValue_ListValue_descriptor_, AttrValue_ListValue::internal_default_instance());
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+      NameAttrList_descriptor_, NameAttrList::internal_default_instance());
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+        NameAttrList_AttrEntry_descriptor_,
+        ::google::protobuf::internal::MapEntry<
+            ::std::string,
+            ::tensorflow::AttrValue,
+            ::google::protobuf::internal::WireFormatLite::TYPE_STRING,
+            ::google::protobuf::internal::WireFormatLite::TYPE_MESSAGE,
+            0>::CreateDefaultInstance(
+                NameAttrList_AttrEntry_descriptor_));
+}
+
+}  // namespace
+
+void protobuf_ShutdownFile_attr_5fvalue_2eproto() {
+  AttrValue_default_instance_.Shutdown();
+  delete AttrValue_default_oneof_instance_;
+  delete AttrValue_reflection_;
+  AttrValue_ListValue_default_instance_.Shutdown();
+  delete AttrValue_ListValue_reflection_;
+  NameAttrList_default_instance_.Shutdown();
+  delete NameAttrList_reflection_;
+}
+
+void protobuf_InitDefaults_attr_5fvalue_2eproto_impl() {
+  GOOGLE_PROTOBUF_VERIFY_VERSION;
+
+  ::tensorflow::protobuf_InitDefaults_tensor_2eproto();
+  ::tensorflow::protobuf_InitDefaults_tensor_5fshape_2eproto();
+  ::tensorflow::protobuf_InitDefaults_types_2eproto();
+  ::google::protobuf::internal::GetEmptyString();
+  AttrValue_default_instance_.DefaultConstruct();
+  AttrValue_default_oneof_instance_ = new AttrValueOneofInstance();
+  ::google::protobuf::internal::GetEmptyString();
+  AttrValue_ListValue_default_instance_.DefaultConstruct();
+  ::google::protobuf::internal::GetEmptyString();
+  NameAttrList_default_instance_.DefaultConstruct();
+  AttrValue_default_instance_.get_mutable()->InitAsDefaultInstance();
+  AttrValue_ListValue_default_instance_.get_mutable()->InitAsDefaultInstance();
+  NameAttrList_default_instance_.get_mutable()->InitAsDefaultInstance();
+}
+
+GOOGLE_PROTOBUF_DECLARE_ONCE(protobuf_InitDefaults_attr_5fvalue_2eproto_once_);
+void protobuf_InitDefaults_attr_5fvalue_2eproto() {
+  ::google::protobuf::GoogleOnceInit(&protobuf_InitDefaults_attr_5fvalue_2eproto_once_,
+                 &protobuf_InitDefaults_attr_5fvalue_2eproto_impl);
+}
+void protobuf_AddDesc_attr_5fvalue_2eproto_impl() {
+  GOOGLE_PROTOBUF_VERIFY_VERSION;
+
+  protobuf_InitDefaults_attr_5fvalue_2eproto();
+  ::google::protobuf::DescriptorPool::InternalAddGeneratedFile(
+    "\n\020attr_value.proto\022\ntensorflow\032\014tensor.p"
+    "roto\032\022tensor_shape.proto\032\013types.proto\"\376\003"
+    "\n\tAttrValue\022\013\n\001s\030\002 \001(\014H\000\022\013\n\001i\030\003 \001(\003H\000\022\013\n"
+    "\001f\030\004 \001(\002H\000\022\013\n\001b\030\005 \001(\010H\000\022$\n\004type\030\006 \001(\0162\024."
+    "tensorflow.DataTypeH\000\022-\n\005shape\030\007 \001(\0132\034.t"
+    "ensorflow.TensorShapeProtoH\000\022)\n\006tensor\030\010"
+    " \001(\0132\027.tensorflow.TensorProtoH\000\022/\n\004list\030"
+    "\001 \001(\0132\037.tensorflow.AttrValue.ListValueH\000"
+    "\022(\n\004func\030\n \001(\0132\030.tensorflow.NameAttrList"
+    "H\000\022\025\n\013placeholder\030\t \001(\tH\000\032\301\001\n\tListValue\022"
+    "\t\n\001s\030\002 \003(\014\022\r\n\001i\030\003 \003(\003B\002\020\001\022\r\n\001f\030\004 \003(\002B\002\020\001"
+    "\022\r\n\001b\030\005 \003(\010B\002\020\001\022&\n\004type\030\006 \003(\0162\024.tensorfl"
+    "ow.DataTypeB\002\020\001\022+\n\005shape\030\007 \003(\0132\034.tensorf"
+    "low.TensorShapeProto\022\'\n\006tensor\030\010 \003(\0132\027.t"
+    "ensorflow.TensorProtoB\007\n\005value\"\222\001\n\014NameA"
+    "ttrList\022\014\n\004name\030\001 \001(\t\0220\n\004attr\030\002 \003(\0132\".te"
+    "nsorflow.NameAttrList.AttrEntry\032B\n\tAttrE"
+    "ntry\022\013\n\003key\030\001 \001(\t\022$\n\005value\030\002 \001(\0132\025.tenso"
+    "rflow.AttrValue:\0028\001B0\n\030org.tensorflow.fr"
+    "ameworkB\017AttrValueProtosP\001\370\001\001b\006proto3", 797);
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedFile(
+    "attr_value.proto", &protobuf_RegisterTypes);
+  ::tensorflow::protobuf_AddDesc_tensor_2eproto();
+  ::tensorflow::protobuf_AddDesc_tensor_5fshape_2eproto();
+  ::tensorflow::protobuf_AddDesc_types_2eproto();
+  ::google::protobuf::internal::OnShutdown(&protobuf_ShutdownFile_attr_5fvalue_2eproto);
+}
+
+GOOGLE_PROTOBUF_DECLARE_ONCE(protobuf_AddDesc_attr_5fvalue_2eproto_once_);
+void protobuf_AddDesc_attr_5fvalue_2eproto() {
+  ::google::protobuf::GoogleOnceInit(&protobuf_AddDesc_attr_5fvalue_2eproto_once_,
+                 &protobuf_AddDesc_attr_5fvalue_2eproto_impl);
+}
+// Force AddDescriptors() to be called at static initialization time.
+struct StaticDescriptorInitializer_attr_5fvalue_2eproto {
+  StaticDescriptorInitializer_attr_5fvalue_2eproto() {
+    protobuf_AddDesc_attr_5fvalue_2eproto();
+  }
+} static_descriptor_initializer_attr_5fvalue_2eproto_;
+
+namespace {
+
+static void MergeFromFail(int line) GOOGLE_ATTRIBUTE_COLD GOOGLE_ATTRIBUTE_NORETURN;
+static void MergeFromFail(int line) {
+  ::google::protobuf::internal::MergeFromFail(__FILE__, line);
+}
+
+}  // namespace
+
+
+// ===================================================================
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const int AttrValue_ListValue::kSFieldNumber;
+const int AttrValue_ListValue::kIFieldNumber;
+const int AttrValue_ListValue::kFFieldNumber;
+const int AttrValue_ListValue::kBFieldNumber;
+const int AttrValue_ListValue::kTypeFieldNumber;
+const int AttrValue_ListValue::kShapeFieldNumber;
+const int AttrValue_ListValue::kTensorFieldNumber;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+
+AttrValue_ListValue::AttrValue_ListValue()
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+  if (this != internal_default_instance()) protobuf_InitDefaults_attr_5fvalue_2eproto();
+  SharedCtor();
+  // @@protoc_insertion_point(constructor:tensorflow.AttrValue.ListValue)
+}
+AttrValue_ListValue::AttrValue_ListValue(::google::protobuf::Arena* arena)
+  : ::google::protobuf::Message(),
+  _internal_metadata_(arena),
+  s_(arena),
+  i_(arena),
+  f_(arena),
+  b_(arena),
+  type_(arena),
+  shape_(arena),
+  tensor_(arena) {
+#ifdef GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER
+  protobuf_InitDefaults_attr_5fvalue_2eproto();
+#endif  // GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER
+  SharedCtor();
+  RegisterArenaDtor(arena);
+  // @@protoc_insertion_point(arena_constructor:tensorflow.AttrValue.ListValue)
+}
+
+void AttrValue_ListValue::InitAsDefaultInstance() {
+}
+
+AttrValue_ListValue::AttrValue_ListValue(const AttrValue_ListValue& from)
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
+  SharedCtor();
+  UnsafeMergeFrom(from);
+  // @@protoc_insertion_point(copy_constructor:tensorflow.AttrValue.ListValue)
+}
+
+void AttrValue_ListValue::SharedCtor() {
+  _cached_size_ = 0;
+}
+
+AttrValue_ListValue::~AttrValue_ListValue() {
+  // @@protoc_insertion_point(destructor:tensorflow.AttrValue.ListValue)
+  SharedDtor();
+}
+
+void AttrValue_ListValue::SharedDtor() {
+  ::google::protobuf::Arena* arena = GetArenaNoVirtual();
+  if (arena != NULL) {
+    return;
+  }
+
+}
+
+void AttrValue_ListValue::ArenaDtor(void* object) {
+  AttrValue_ListValue* _this = reinterpret_cast< AttrValue_ListValue* >(object);
+  (void)_this;
+}
+void AttrValue_ListValue::RegisterArenaDtor(::google::protobuf::Arena* arena) {
+}
+void AttrValue_ListValue::SetCachedSize(int size) const {
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* AttrValue_ListValue::descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return AttrValue_ListValue_descriptor_;
+}
+
+const AttrValue_ListValue& AttrValue_ListValue::default_instance() {
+  protobuf_InitDefaults_attr_5fvalue_2eproto();
+  return *internal_default_instance();
+}
+
+::google::protobuf::internal::ExplicitlyConstructed<AttrValue_ListValue> AttrValue_ListValue_default_instance_;
+
+AttrValue_ListValue* AttrValue_ListValue::New(::google::protobuf::Arena* arena) const {
+  return ::google::protobuf::Arena::CreateMessage<AttrValue_ListValue>(arena);
+}
+
+void AttrValue_ListValue::Clear() {
+// @@protoc_insertion_point(message_clear_start:tensorflow.AttrValue.ListValue)
+  s_.Clear();
+  i_.Clear();
+  f_.Clear();
+  b_.Clear();
+  type_.Clear();
+  shape_.Clear();
+  tensor_.Clear();
+}
+
+bool AttrValue_ListValue::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
+  ::google::protobuf::uint32 tag;
+  // @@protoc_insertion_point(parse_start:tensorflow.AttrValue.ListValue)
+  for (;;) {
+    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+    tag = p.first;
+    if (!p.second) goto handle_unusual;
+    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+      // repeated bytes s = 2;
+      case 2: {
+        if (tag == 18) {
+         parse_s:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadBytes(
+                input, this->add_s()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(18)) goto parse_s;
+        if (input->ExpectTag(26)) goto parse_i;
+        break;
+      }
+
+      // repeated int64 i = 3 [packed = true];
+      case 3: {
+        if (tag == 26) {
+         parse_i:
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPackedPrimitive<
+                   ::google::protobuf::int64, ::google::protobuf::internal::WireFormatLite::TYPE_INT64>(
+                 input, this->mutable_i())));
+        } else if (tag == 24) {
+          DO_((::google::protobuf::internal::WireFormatLite::ReadRepeatedPrimitiveNoInline<
+                   ::google::protobuf::int64, ::google::protobuf::internal::WireFormatLite::TYPE_INT64>(
+                 1, 26, input, this->mutable_i())));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(34)) goto parse_f;
+        break;
+      }
+
+      // repeated float f = 4 [packed = true];
+      case 4: {
+        if (tag == 34) {
+         parse_f:
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPackedPrimitive<
+                   float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
+                 input, this->mutable_f())));
+        } else if (tag == 37) {
+          DO_((::google::protobuf::internal::WireFormatLite::ReadRepeatedPrimitiveNoInline<
+                   float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
+                 1, 34, input, this->mutable_f())));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(42)) goto parse_b;
+        break;
+      }
+
+      // repeated bool b = 5 [packed = true];
+      case 5: {
+        if (tag == 42) {
+         parse_b:
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPackedPrimitive<
+                   bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>(
+                 input, this->mutable_b())));
+        } else if (tag == 40) {
+          DO_((::google::protobuf::internal::WireFormatLite::ReadRepeatedPrimitiveNoInline<
+                   bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>(
+                 1, 42, input, this->mutable_b())));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(50)) goto parse_type;
+        break;
+      }
+
+      // repeated .tensorflow.DataType type = 6 [packed = true];
+      case 6: {
+        if (tag == 50) {
+         parse_type:
+          ::google::protobuf::uint32 length;
+          DO_(input->ReadVarint32(&length));
+          ::google::protobuf::io::CodedInputStream::Limit limit = input->PushLimit(length);
+          while (input->BytesUntilLimit() > 0) {
+            int value;
+            DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>(
+                 input, &value)));
+            add_type(static_cast< ::tensorflow::DataType >(value));
+          }
+          input->PopLimit(limit);
+        } else if (tag == 48) {
+          int value;
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>(
+                 input, &value)));
+          add_type(static_cast< ::tensorflow::DataType >(value));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(58)) goto parse_shape;
+        break;
+      }
+
+      // repeated .tensorflow.TensorShapeProto shape = 7;
+      case 7: {
+        if (tag == 58) {
+         parse_shape:
+          DO_(input->IncrementRecursionDepth());
+         parse_loop_shape:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth(
+                input, add_shape()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(58)) goto parse_loop_shape;
+        if (input->ExpectTag(66)) goto parse_loop_tensor;
+        input->UnsafeDecrementRecursionDepth();
+        break;
+      }
+
+      // repeated .tensorflow.TensorProto tensor = 8;
+      case 8: {
+        if (tag == 66) {
+          DO_(input->IncrementRecursionDepth());
+         parse_loop_tensor:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth(
+                input, add_tensor()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(66)) goto parse_loop_tensor;
+        input->UnsafeDecrementRecursionDepth();
+        if (input->ExpectAtEnd()) goto success;
+        break;
+      }
+
+      default: {
+      handle_unusual:
+        if (tag == 0 ||
+            ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+          goto success;
+        }
+        DO_(::google::protobuf::internal::WireFormatLite::SkipField(input, tag));
+        break;
+      }
+    }
+  }
+success:
+  // @@protoc_insertion_point(parse_success:tensorflow.AttrValue.ListValue)
+  return true;
+failure:
+  // @@protoc_insertion_point(parse_failure:tensorflow.AttrValue.ListValue)
+  return false;
+#undef DO_
+}
+
+void AttrValue_ListValue::SerializeWithCachedSizes(
+    ::google::protobuf::io::CodedOutputStream* output) const {
+  // @@protoc_insertion_point(serialize_start:tensorflow.AttrValue.ListValue)
+  // repeated bytes s = 2;
+  for (int i = 0; i < this->s_size(); i++) {
+    ::google::protobuf::internal::WireFormatLite::WriteBytes(
+      2, this->s(i), output);
+  }
+
+  // repeated int64 i = 3 [packed = true];
+  if (this->i_size() > 0) {
+    ::google::protobuf::internal::WireFormatLite::WriteTag(3, ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED, output);
+    output->WriteVarint32(_i_cached_byte_size_);
+  }
+  for (int i = 0; i < this->i_size(); i++) {
+    ::google::protobuf::internal::WireFormatLite::WriteInt64NoTag(
+      this->i(i), output);
+  }
+
+  // repeated float f = 4 [packed = true];
+  if (this->f_size() > 0) {
+    ::google::protobuf::internal::WireFormatLite::WriteTag(4, ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED, output);
+    output->WriteVarint32(_f_cached_byte_size_);
+  }
+  for (int i = 0; i < this->f_size(); i++) {
+    ::google::protobuf::internal::WireFormatLite::WriteFloatNoTag(
+      this->f(i), output);
+  }
+
+  // repeated bool b = 5 [packed = true];
+  if (this->b_size() > 0) {
+    ::google::protobuf::internal::WireFormatLite::WriteTag(5, ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED, output);
+    output->WriteVarint32(_b_cached_byte_size_);
+  }
+  for (int i = 0; i < this->b_size(); i++) {
+    ::google::protobuf::internal::WireFormatLite::WriteBoolNoTag(
+      this->b(i), output);
+  }
+
+  // repeated .tensorflow.DataType type = 6 [packed = true];
+  if (this->type_size() > 0) {
+    ::google::protobuf::internal::WireFormatLite::WriteTag(
+      6,
+      ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED,
+      output);
+    output->WriteVarint32(_type_cached_byte_size_);
+  }
+  for (int i = 0; i < this->type_size(); i++) {
+    ::google::protobuf::internal::WireFormatLite::WriteEnumNoTag(
+      this->type(i), output);
+  }
+
+  // repeated .tensorflow.TensorShapeProto shape = 7;
+  for (unsigned int i = 0, n = this->shape_size(); i < n; i++) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      7, this->shape(i), output);
+  }
+
+  // repeated .tensorflow.TensorProto tensor = 8;
+  for (unsigned int i = 0, n = this->tensor_size(); i < n; i++) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      8, this->tensor(i), output);
+  }
+
+  // @@protoc_insertion_point(serialize_end:tensorflow.AttrValue.ListValue)
+}
+
+::google::protobuf::uint8* AttrValue_ListValue::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
+  (void)deterministic; // Unused
+  // @@protoc_insertion_point(serialize_to_array_start:tensorflow.AttrValue.ListValue)
+  // repeated bytes s = 2;
+  for (int i = 0; i < this->s_size(); i++) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      WriteBytesToArray(2, this->s(i), target);
+  }
+
+  // repeated int64 i = 3 [packed = true];
+  if (this->i_size() > 0) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteTagToArray(
+      3,
+      ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED,
+      target);
+    target = ::google::protobuf::io::CodedOutputStream::WriteVarint32ToArray(
+      _i_cached_byte_size_, target);
+  }
+  for (int i = 0; i < this->i_size(); i++) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      WriteInt64NoTagToArray(this->i(i), target);
+  }
+
+  // repeated float f = 4 [packed = true];
+  if (this->f_size() > 0) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteTagToArray(
+      4,
+      ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED,
+      target);
+    target = ::google::protobuf::io::CodedOutputStream::WriteVarint32ToArray(
+      _f_cached_byte_size_, target);
+  }
+  for (int i = 0; i < this->f_size(); i++) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      WriteFloatNoTagToArray(this->f(i), target);
+  }
+
+  // repeated bool b = 5 [packed = true];
+  if (this->b_size() > 0) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteTagToArray(
+      5,
+      ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED,
+      target);
+    target = ::google::protobuf::io::CodedOutputStream::WriteVarint32ToArray(
+      _b_cached_byte_size_, target);
+  }
+  for (int i = 0; i < this->b_size(); i++) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      WriteBoolNoTagToArray(this->b(i), target);
+  }
+
+  // repeated .tensorflow.DataType type = 6 [packed = true];
+  if (this->type_size() > 0) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteTagToArray(
+      6,
+      ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED,
+      target);
+    target = ::google::protobuf::io::CodedOutputStream::WriteVarint32ToArray(    _type_cached_byte_size_, target);
+  }
+  for (int i = 0; i < this->type_size(); i++) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteEnumNoTagToArray(
+      this->type(i), target);
+  }
+
+  // repeated .tensorflow.TensorShapeProto shape = 7;
+  for (unsigned int i = 0, n = this->shape_size(); i < n; i++) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        7, this->shape(i), false, target);
+  }
+
+  // repeated .tensorflow.TensorProto tensor = 8;
+  for (unsigned int i = 0, n = this->tensor_size(); i < n; i++) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        8, this->tensor(i), false, target);
+  }
+
+  // @@protoc_insertion_point(serialize_to_array_end:tensorflow.AttrValue.ListValue)
+  return target;
+}
+
+size_t AttrValue_ListValue::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:tensorflow.AttrValue.ListValue)
+  size_t total_size = 0;
+
+  // repeated bytes s = 2;
+  total_size += 1 *
+      ::google::protobuf::internal::FromIntSize(this->s_size());
+  for (int i = 0; i < this->s_size(); i++) {
+    total_size += ::google::protobuf::internal::WireFormatLite::BytesSize(
+      this->s(i));
+  }
+
+  // repeated int64 i = 3 [packed = true];
+  {
+    size_t data_size = 0;
+    unsigned int count = this->i_size();
+    for (unsigned int i = 0; i < count; i++) {
+      data_size += ::google::protobuf::internal::WireFormatLite::
+        Int64Size(this->i(i));
+    }
+    if (data_size > 0) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::Int32Size(data_size);
+    }
+    int cached_size = ::google::protobuf::internal::ToCachedSize(data_size);
+    GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+    _i_cached_byte_size_ = cached_size;
+    GOOGLE_SAFE_CONCURRENT_WRITES_END();
+    total_size += data_size;
+  }
+
+  // repeated float f = 4 [packed = true];
+  {
+    size_t data_size = 0;
+    unsigned int count = this->f_size();
+    data_size = 4UL * count;
+    if (data_size > 0) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::Int32Size(data_size);
+    }
+    int cached_size = ::google::protobuf::internal::ToCachedSize(data_size);
+    GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+    _f_cached_byte_size_ = cached_size;
+    GOOGLE_SAFE_CONCURRENT_WRITES_END();
+    total_size += data_size;
+  }
+
+  // repeated bool b = 5 [packed = true];
+  {
+    size_t data_size = 0;
+    unsigned int count = this->b_size();
+    data_size = 1UL * count;
+    if (data_size > 0) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::Int32Size(data_size);
+    }
+    int cached_size = ::google::protobuf::internal::ToCachedSize(data_size);
+    GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+    _b_cached_byte_size_ = cached_size;
+    GOOGLE_SAFE_CONCURRENT_WRITES_END();
+    total_size += data_size;
+  }
+
+  // repeated .tensorflow.DataType type = 6 [packed = true];
+  {
+    size_t data_size = 0;
+    unsigned int count = this->type_size();for (unsigned int i = 0; i < count; i++) {
+      data_size += ::google::protobuf::internal::WireFormatLite::EnumSize(
+        this->type(i));
+    }
+    if (data_size > 0) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::Int32Size(data_size);
+    }
+    int cached_size = ::google::protobuf::internal::ToCachedSize(data_size);
+    GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+    _type_cached_byte_size_ = cached_size;
+    GOOGLE_SAFE_CONCURRENT_WRITES_END();
+    total_size += data_size;
+  }
+
+  // repeated .tensorflow.TensorShapeProto shape = 7;
+  {
+    unsigned int count = this->shape_size();
+    total_size += 1UL * count;
+    for (unsigned int i = 0; i < count; i++) {
+      total_size +=
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          this->shape(i));
+    }
+  }
+
+  // repeated .tensorflow.TensorProto tensor = 8;
+  {
+    unsigned int count = this->tensor_size();
+    total_size += 1UL * count;
+    for (unsigned int i = 0; i < count; i++) {
+      total_size +=
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          this->tensor(i));
+    }
+  }
+
+  int cached_size = ::google::protobuf::internal::ToCachedSize(total_size);
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = cached_size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+  return total_size;
+}
+
+void AttrValue_ListValue::MergeFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_merge_from_start:tensorflow.AttrValue.ListValue)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const AttrValue_ListValue* source =
+      ::google::protobuf::internal::DynamicCastToGenerated<const AttrValue_ListValue>(
+          &from);
+  if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:tensorflow.AttrValue.ListValue)
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:tensorflow.AttrValue.ListValue)
+    UnsafeMergeFrom(*source);
+  }
+}
+
+void AttrValue_ListValue::MergeFrom(const AttrValue_ListValue& from) {
+// @@protoc_insertion_point(class_specific_merge_from_start:tensorflow.AttrValue.ListValue)
+  if (GOOGLE_PREDICT_TRUE(&from != this)) {
+    UnsafeMergeFrom(from);
+  } else {
+    MergeFromFail(__LINE__);
+  }
+}
+
+void AttrValue_ListValue::UnsafeMergeFrom(const AttrValue_ListValue& from) {
+  GOOGLE_DCHECK(&from != this);
+  s_.UnsafeMergeFrom(from.s_);
+  i_.UnsafeMergeFrom(from.i_);
+  f_.UnsafeMergeFrom(from.f_);
+  b_.UnsafeMergeFrom(from.b_);
+  type_.UnsafeMergeFrom(from.type_);
+  shape_.MergeFrom(from.shape_);
+  tensor_.MergeFrom(from.tensor_);
+}
+
+void AttrValue_ListValue::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:tensorflow.AttrValue.ListValue)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void AttrValue_ListValue::CopyFrom(const AttrValue_ListValue& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:tensorflow.AttrValue.ListValue)
+  if (&from == this) return;
+  Clear();
+  UnsafeMergeFrom(from);
+}
+
+bool AttrValue_ListValue::IsInitialized() const {
+
+  return true;
+}
+
+void AttrValue_ListValue::Swap(AttrValue_ListValue* other) {
+  if (other == this) return;
+  if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) {
+    InternalSwap(other);
+  } else {
+    AttrValue_ListValue temp;
+    temp.UnsafeMergeFrom(*this);
+    CopyFrom(*other);
+    other->CopyFrom(temp);
+  }
+}
+void AttrValue_ListValue::UnsafeArenaSwap(AttrValue_ListValue* other) {
+  if (other == this) return;
+  GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual());
+  InternalSwap(other);
+}
+void AttrValue_ListValue::InternalSwap(AttrValue_ListValue* other) {
+  s_.UnsafeArenaSwap(&other->s_);
+  i_.UnsafeArenaSwap(&other->i_);
+  f_.UnsafeArenaSwap(&other->f_);
+  b_.UnsafeArenaSwap(&other->b_);
+  type_.UnsafeArenaSwap(&other->type_);
+  shape_.UnsafeArenaSwap(&other->shape_);
+  tensor_.UnsafeArenaSwap(&other->tensor_);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
+}
+
+::google::protobuf::Metadata AttrValue_ListValue::GetMetadata() const {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::Metadata metadata;
+  metadata.descriptor = AttrValue_ListValue_descriptor_;
+  metadata.reflection = AttrValue_ListValue_reflection_;
+  return metadata;
+}
+
+
+// -------------------------------------------------------------------
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const int AttrValue::kSFieldNumber;
+const int AttrValue::kIFieldNumber;
+const int AttrValue::kFFieldNumber;
+const int AttrValue::kBFieldNumber;
+const int AttrValue::kTypeFieldNumber;
+const int AttrValue::kShapeFieldNumber;
+const int AttrValue::kTensorFieldNumber;
+const int AttrValue::kListFieldNumber;
+const int AttrValue::kFuncFieldNumber;
+const int AttrValue::kPlaceholderFieldNumber;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+
+AttrValue::AttrValue()
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+  if (this != internal_default_instance()) protobuf_InitDefaults_attr_5fvalue_2eproto();
+  SharedCtor();
+  // @@protoc_insertion_point(constructor:tensorflow.AttrValue)
+}
+AttrValue::AttrValue(::google::protobuf::Arena* arena)
+  : ::google::protobuf::Message(),
+  _internal_metadata_(arena) {
+#ifdef GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER
+  protobuf_InitDefaults_attr_5fvalue_2eproto();
+#endif  // GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER
+  SharedCtor();
+  RegisterArenaDtor(arena);
+  // @@protoc_insertion_point(arena_constructor:tensorflow.AttrValue)
+}
+
+void AttrValue::InitAsDefaultInstance() {
+  AttrValue_default_oneof_instance_->s_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  AttrValue_default_oneof_instance_->i_ = GOOGLE_LONGLONG(0);
+  AttrValue_default_oneof_instance_->f_ = 0;
+  AttrValue_default_oneof_instance_->b_ = false;
+  AttrValue_default_oneof_instance_->type_ = 0;
+  AttrValue_default_oneof_instance_->shape_ = const_cast< ::tensorflow::TensorShapeProto*>(
+      ::tensorflow::TensorShapeProto::internal_default_instance());
+  AttrValue_default_oneof_instance_->tensor_ = const_cast< ::tensorflow::TensorProto*>(
+      ::tensorflow::TensorProto::internal_default_instance());
+  AttrValue_default_oneof_instance_->list_ = const_cast< ::tensorflow::AttrValue_ListValue*>(
+      ::tensorflow::AttrValue_ListValue::internal_default_instance());
+  AttrValue_default_oneof_instance_->func_ = const_cast< ::tensorflow::NameAttrList*>(
+      ::tensorflow::NameAttrList::internal_default_instance());
+  AttrValue_default_oneof_instance_->placeholder_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+
+AttrValue::AttrValue(const AttrValue& from)
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
+  SharedCtor();
+  UnsafeMergeFrom(from);
+  // @@protoc_insertion_point(copy_constructor:tensorflow.AttrValue)
+}
+
+void AttrValue::SharedCtor() {
+  clear_has_value();
+  _cached_size_ = 0;
+}
+
+AttrValue::~AttrValue() {
+  // @@protoc_insertion_point(destructor:tensorflow.AttrValue)
+  SharedDtor();
+}
+
+void AttrValue::SharedDtor() {
+  ::google::protobuf::Arena* arena = GetArenaNoVirtual();
+  if (arena != NULL) {
+    return;
+  }
+
+  if (has_value()) {
+    clear_value();
+  }
+}
+
+void AttrValue::ArenaDtor(void* object) {
+  AttrValue* _this = reinterpret_cast< AttrValue* >(object);
+  (void)_this;
+}
+void AttrValue::RegisterArenaDtor(::google::protobuf::Arena* arena) {
+}
+void AttrValue::SetCachedSize(int size) const {
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* AttrValue::descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return AttrValue_descriptor_;
+}
+
+const AttrValue& AttrValue::default_instance() {
+  protobuf_InitDefaults_attr_5fvalue_2eproto();
+  return *internal_default_instance();
+}
+
+::google::protobuf::internal::ExplicitlyConstructed<AttrValue> AttrValue_default_instance_;
+
+AttrValue* AttrValue::New(::google::protobuf::Arena* arena) const {
+  return ::google::protobuf::Arena::CreateMessage<AttrValue>(arena);
+}
+
+void AttrValue::clear_value() {
+// @@protoc_insertion_point(one_of_clear_start:tensorflow.AttrValue)
+  switch (value_case()) {
+    case kS: {
+      value_.s_.Destroy(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+          GetArenaNoVirtual());
+      break;
+    }
+    case kI: {
+      // No need to clear
+      break;
+    }
+    case kF: {
+      // No need to clear
+      break;
+    }
+    case kB: {
+      // No need to clear
+      break;
+    }
+    case kType: {
+      // No need to clear
+      break;
+    }
+    case kShape: {
+      if (GetArenaNoVirtual() == NULL) {
+        delete value_.shape_;
+      }
+      break;
+    }
+    case kTensor: {
+      if (GetArenaNoVirtual() == NULL) {
+        delete value_.tensor_;
+      }
+      break;
+    }
+    case kList: {
+      if (GetArenaNoVirtual() == NULL) {
+        delete value_.list_;
+      }
+      break;
+    }
+    case kFunc: {
+      if (GetArenaNoVirtual() == NULL) {
+        delete value_.func_;
+      }
+      break;
+    }
+    case kPlaceholder: {
+      value_.placeholder_.Destroy(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+          GetArenaNoVirtual());
+      break;
+    }
+    case VALUE_NOT_SET: {
+      break;
+    }
+  }
+  _oneof_case_[0] = VALUE_NOT_SET;
+}
+
+
+void AttrValue::Clear() {
+// @@protoc_insertion_point(message_clear_start:tensorflow.AttrValue)
+  clear_value();
+}
+
+bool AttrValue::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
+  ::google::protobuf::uint32 tag;
+  // @@protoc_insertion_point(parse_start:tensorflow.AttrValue)
+  for (;;) {
+    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+    tag = p.first;
+    if (!p.second) goto handle_unusual;
+    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+      // optional .tensorflow.AttrValue.ListValue list = 1;
+      case 1: {
+        if (tag == 10) {
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+               input, mutable_list()));
+        } else {
+          goto handle_unusual;
+        }
+        goto after_func;
+        break;
+      }
+
+      // optional bytes s = 2;
+      case 2: {
+        if (tag == 18) {
+          DO_(::google::protobuf::internal::WireFormatLite::ReadBytes(
+                input, this->mutable_s()));
+        } else {
+          goto handle_unusual;
+        }
+        goto after_func;
+        break;
+      }
+
+      // optional int64 i = 3;
+      case 3: {
+        if (tag == 24) {
+          clear_value();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::int64, ::google::protobuf::internal::WireFormatLite::TYPE_INT64>(
+                 input, &value_.i_)));
+          set_has_i();
+        } else {
+          goto handle_unusual;
+        }
+        goto after_func;
+        break;
+      }
+
+      // optional float f = 4;
+      case 4: {
+        if (tag == 37) {
+          clear_value();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
+                 input, &value_.f_)));
+          set_has_f();
+        } else {
+          goto handle_unusual;
+        }
+        goto after_func;
+        break;
+      }
+
+      // optional bool b = 5;
+      case 5: {
+        if (tag == 40) {
+          clear_value();
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>(
+                 input, &value_.b_)));
+          set_has_b();
+        } else {
+          goto handle_unusual;
+        }
+        goto after_func;
+        break;
+      }
+
+      // optional .tensorflow.DataType type = 6;
+      case 6: {
+        if (tag == 48) {
+          int value;
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>(
+                 input, &value)));
+          set_type(static_cast< ::tensorflow::DataType >(value));
+        } else {
+          goto handle_unusual;
+        }
+        goto after_func;
+        break;
+      }
+
+      // optional .tensorflow.TensorShapeProto shape = 7;
+      case 7: {
+        if (tag == 58) {
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+               input, mutable_shape()));
+        } else {
+          goto handle_unusual;
+        }
+        goto after_func;
+        break;
+      }
+
+      // optional .tensorflow.TensorProto tensor = 8;
+      case 8: {
+        if (tag == 66) {
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+               input, mutable_tensor()));
+        } else {
+          goto handle_unusual;
+        }
+        goto after_func;
+        break;
+      }
+
+      // optional string placeholder = 9;
+      case 9: {
+        if (tag == 74) {
+          DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+                input, this->mutable_placeholder()));
+          DO_(::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+            this->placeholder().data(), this->placeholder().length(),
+            ::google::protobuf::internal::WireFormatLite::PARSE,
+            "tensorflow.AttrValue.placeholder"));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(82)) goto parse_func;
+        break;
+      }
+
+      // optional .tensorflow.NameAttrList func = 10;
+      case 10: {
+        if (tag == 82) {
+         parse_func:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+               input, mutable_func()));
+        } else {
+          goto handle_unusual;
+        }
+       after_func:
+        if (input->ExpectAtEnd()) goto success;
+        break;
+      }
+
+      default: {
+      handle_unusual:
+        if (tag == 0 ||
+            ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+          goto success;
+        }
+        DO_(::google::protobuf::internal::WireFormatLite::SkipField(input, tag));
+        break;
+      }
+    }
+  }
+success:
+  // @@protoc_insertion_point(parse_success:tensorflow.AttrValue)
+  return true;
+failure:
+  // @@protoc_insertion_point(parse_failure:tensorflow.AttrValue)
+  return false;
+#undef DO_
+}
+
+void AttrValue::SerializeWithCachedSizes(
+    ::google::protobuf::io::CodedOutputStream* output) const {
+  // @@protoc_insertion_point(serialize_start:tensorflow.AttrValue)
+  // optional .tensorflow.AttrValue.ListValue list = 1;
+  if (has_list()) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      1, *value_.list_, output);
+  }
+
+  // optional bytes s = 2;
+  if (has_s()) {
+    ::google::protobuf::internal::WireFormatLite::WriteBytesMaybeAliased(
+      2, this->s(), output);
+  }
+
+  // optional int64 i = 3;
+  if (has_i()) {
+    ::google::protobuf::internal::WireFormatLite::WriteInt64(3, this->i(), output);
+  }
+
+  // optional float f = 4;
+  if (has_f()) {
+    ::google::protobuf::internal::WireFormatLite::WriteFloat(4, this->f(), output);
+  }
+
+  // optional bool b = 5;
+  if (has_b()) {
+    ::google::protobuf::internal::WireFormatLite::WriteBool(5, this->b(), output);
+  }
+
+  // optional .tensorflow.DataType type = 6;
+  if (has_type()) {
+    ::google::protobuf::internal::WireFormatLite::WriteEnum(
+      6, this->type(), output);
+  }
+
+  // optional .tensorflow.TensorShapeProto shape = 7;
+  if (has_shape()) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      7, *value_.shape_, output);
+  }
+
+  // optional .tensorflow.TensorProto tensor = 8;
+  if (has_tensor()) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      8, *value_.tensor_, output);
+  }
+
+  // optional string placeholder = 9;
+  if (has_placeholder()) {
+    ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+      this->placeholder().data(), this->placeholder().length(),
+      ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+      "tensorflow.AttrValue.placeholder");
+    ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
+      9, this->placeholder(), output);
+  }
+
+  // optional .tensorflow.NameAttrList func = 10;
+  if (has_func()) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      10, *value_.func_, output);
+  }
+
+  // @@protoc_insertion_point(serialize_end:tensorflow.AttrValue)
+}
+
+::google::protobuf::uint8* AttrValue::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
+  (void)deterministic; // Unused
+  // @@protoc_insertion_point(serialize_to_array_start:tensorflow.AttrValue)
+  // optional .tensorflow.AttrValue.ListValue list = 1;
+  if (has_list()) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        1, *value_.list_, false, target);
+  }
+
+  // optional bytes s = 2;
+  if (has_s()) {
+    target =
+      ::google::protobuf::internal::WireFormatLite::WriteBytesToArray(
+        2, this->s(), target);
+  }
+
+  // optional int64 i = 3;
+  if (has_i()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteInt64ToArray(3, this->i(), target);
+  }
+
+  // optional float f = 4;
+  if (has_f()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteFloatToArray(4, this->f(), target);
+  }
+
+  // optional bool b = 5;
+  if (has_b()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(5, this->b(), target);
+  }
+
+  // optional .tensorflow.DataType type = 6;
+  if (has_type()) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteEnumToArray(
+      6, this->type(), target);
+  }
+
+  // optional .tensorflow.TensorShapeProto shape = 7;
+  if (has_shape()) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        7, *value_.shape_, false, target);
+  }
+
+  // optional .tensorflow.TensorProto tensor = 8;
+  if (has_tensor()) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        8, *value_.tensor_, false, target);
+  }
+
+  // optional string placeholder = 9;
+  if (has_placeholder()) {
+    ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+      this->placeholder().data(), this->placeholder().length(),
+      ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+      "tensorflow.AttrValue.placeholder");
+    target =
+      ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
+        9, this->placeholder(), target);
+  }
+
+  // optional .tensorflow.NameAttrList func = 10;
+  if (has_func()) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        10, *value_.func_, false, target);
+  }
+
+  // @@protoc_insertion_point(serialize_to_array_end:tensorflow.AttrValue)
+  return target;
+}
+
+size_t AttrValue::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:tensorflow.AttrValue)
+  size_t total_size = 0;
+
+  switch (value_case()) {
+    // optional bytes s = 2;
+    case kS: {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::BytesSize(
+          this->s());
+      break;
+    }
+    // optional int64 i = 3;
+    case kI: {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::Int64Size(
+          this->i());
+      break;
+    }
+    // optional float f = 4;
+    case kF: {
+      total_size += 1 + 4;
+      break;
+    }
+    // optional bool b = 5;
+    case kB: {
+      total_size += 1 + 1;
+      break;
+    }
+    // optional .tensorflow.DataType type = 6;
+    case kType: {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::EnumSize(this->type());
+      break;
+    }
+    // optional .tensorflow.TensorShapeProto shape = 7;
+    case kShape: {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          *value_.shape_);
+      break;
+    }
+    // optional .tensorflow.TensorProto tensor = 8;
+    case kTensor: {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          *value_.tensor_);
+      break;
+    }
+    // optional .tensorflow.AttrValue.ListValue list = 1;
+    case kList: {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          *value_.list_);
+      break;
+    }
+    // optional .tensorflow.NameAttrList func = 10;
+    case kFunc: {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          *value_.func_);
+      break;
+    }
+    // optional string placeholder = 9;
+    case kPlaceholder: {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::StringSize(
+          this->placeholder());
+      break;
+    }
+    case VALUE_NOT_SET: {
+      break;
+    }
+  }
+  int cached_size = ::google::protobuf::internal::ToCachedSize(total_size);
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = cached_size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+  return total_size;
+}
+
+void AttrValue::MergeFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_merge_from_start:tensorflow.AttrValue)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const AttrValue* source =
+      ::google::protobuf::internal::DynamicCastToGenerated<const AttrValue>(
+          &from);
+  if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:tensorflow.AttrValue)
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:tensorflow.AttrValue)
+    UnsafeMergeFrom(*source);
+  }
+}
+
+void AttrValue::MergeFrom(const AttrValue& from) {
+// @@protoc_insertion_point(class_specific_merge_from_start:tensorflow.AttrValue)
+  if (GOOGLE_PREDICT_TRUE(&from != this)) {
+    UnsafeMergeFrom(from);
+  } else {
+    MergeFromFail(__LINE__);
+  }
+}
+
+void AttrValue::UnsafeMergeFrom(const AttrValue& from) {
+  GOOGLE_DCHECK(&from != this);
+  switch (from.value_case()) {
+    case kS: {
+      set_s(from.s());
+      break;
+    }
+    case kI: {
+      set_i(from.i());
+      break;
+    }
+    case kF: {
+      set_f(from.f());
+      break;
+    }
+    case kB: {
+      set_b(from.b());
+      break;
+    }
+    case kType: {
+      set_type(from.type());
+      break;
+    }
+    case kShape: {
+      mutable_shape()->::tensorflow::TensorShapeProto::MergeFrom(from.shape());
+      break;
+    }
+    case kTensor: {
+      mutable_tensor()->::tensorflow::TensorProto::MergeFrom(from.tensor());
+      break;
+    }
+    case kList: {
+      mutable_list()->::tensorflow::AttrValue_ListValue::MergeFrom(from.list());
+      break;
+    }
+    case kFunc: {
+      mutable_func()->::tensorflow::NameAttrList::MergeFrom(from.func());
+      break;
+    }
+    case kPlaceholder: {
+      set_placeholder(from.placeholder());
+      break;
+    }
+    case VALUE_NOT_SET: {
+      break;
+    }
+  }
+}
+
+void AttrValue::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:tensorflow.AttrValue)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void AttrValue::CopyFrom(const AttrValue& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:tensorflow.AttrValue)
+  if (&from == this) return;
+  Clear();
+  UnsafeMergeFrom(from);
+}
+
+bool AttrValue::IsInitialized() const {
+
+  return true;
+}
+
+void AttrValue::Swap(AttrValue* other) {
+  if (other == this) return;
+  if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) {
+    InternalSwap(other);
+  } else {
+    AttrValue temp;
+    temp.UnsafeMergeFrom(*this);
+    CopyFrom(*other);
+    other->CopyFrom(temp);
+  }
+}
+void AttrValue::UnsafeArenaSwap(AttrValue* other) {
+  if (other == this) return;
+  GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual());
+  InternalSwap(other);
+}
+void AttrValue::InternalSwap(AttrValue* other) {
+  std::swap(value_, other->value_);
+  std::swap(_oneof_case_[0], other->_oneof_case_[0]);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
+}
+
+::google::protobuf::Metadata AttrValue::GetMetadata() const {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::Metadata metadata;
+  metadata.descriptor = AttrValue_descriptor_;
+  metadata.reflection = AttrValue_reflection_;
+  return metadata;
+}
+
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// AttrValue_ListValue
+
+// repeated bytes s = 2;
+int AttrValue_ListValue::s_size() const {
+  return s_.size();
+}
+void AttrValue_ListValue::clear_s() {
+  s_.Clear();
+}
+const ::std::string& AttrValue_ListValue::s(int index) const {
+  // @@protoc_insertion_point(field_get:tensorflow.AttrValue.ListValue.s)
+  return s_.Get(index);
+}
+::std::string* AttrValue_ListValue::mutable_s(int index) {
+  // @@protoc_insertion_point(field_mutable:tensorflow.AttrValue.ListValue.s)
+  return s_.Mutable(index);
+}
+void AttrValue_ListValue::set_s(int index, const ::std::string& value) {
+  // @@protoc_insertion_point(field_set:tensorflow.AttrValue.ListValue.s)
+  s_.Mutable(index)->assign(value);
+}
+void AttrValue_ListValue::set_s(int index, const char* value) {
+  s_.Mutable(index)->assign(value);
+  // @@protoc_insertion_point(field_set_char:tensorflow.AttrValue.ListValue.s)
+}
+void AttrValue_ListValue::set_s(int index, const void* value, size_t size) {
+  s_.Mutable(index)->assign(
+    reinterpret_cast<const char*>(value), size);
+  // @@protoc_insertion_point(field_set_pointer:tensorflow.AttrValue.ListValue.s)
+}
+::std::string* AttrValue_ListValue::add_s() {
+  // @@protoc_insertion_point(field_add_mutable:tensorflow.AttrValue.ListValue.s)
+  return s_.Add();
+}
+void AttrValue_ListValue::add_s(const ::std::string& value) {
+  s_.Add()->assign(value);
+  // @@protoc_insertion_point(field_add:tensorflow.AttrValue.ListValue.s)
+}
+void AttrValue_ListValue::add_s(const char* value) {
+  s_.Add()->assign(value);
+  // @@protoc_insertion_point(field_add_char:tensorflow.AttrValue.ListValue.s)
+}
+void AttrValue_ListValue::add_s(const void* value, size_t size) {
+  s_.Add()->assign(reinterpret_cast<const char*>(value), size);
+  // @@protoc_insertion_point(field_add_pointer:tensorflow.AttrValue.ListValue.s)
+}
+const ::google::protobuf::RepeatedPtrField< ::std::string>&
+AttrValue_ListValue::s() const {
+  // @@protoc_insertion_point(field_list:tensorflow.AttrValue.ListValue.s)
+  return s_;
+}
+::google::protobuf::RepeatedPtrField< ::std::string>*
+AttrValue_ListValue::mutable_s() {
+  // @@protoc_insertion_point(field_mutable_list:tensorflow.AttrValue.ListValue.s)
+  return &s_;
+}
+
+// repeated int64 i = 3 [packed = true];
+int AttrValue_ListValue::i_size() const {
+  return i_.size();
+}
+void AttrValue_ListValue::clear_i() {
+  i_.Clear();
+}
+::google::protobuf::int64 AttrValue_ListValue::i(int index) const {
+  // @@protoc_insertion_point(field_get:tensorflow.AttrValue.ListValue.i)
+  return i_.Get(index);
+}
+void AttrValue_ListValue::set_i(int index, ::google::protobuf::int64 value) {
+  i_.Set(index, value);
+  // @@protoc_insertion_point(field_set:tensorflow.AttrValue.ListValue.i)
+}
+void AttrValue_ListValue::add_i(::google::protobuf::int64 value) {
+  i_.Add(value);
+  // @@protoc_insertion_point(field_add:tensorflow.AttrValue.ListValue.i)
+}
+const ::google::protobuf::RepeatedField< ::google::protobuf::int64 >&
+AttrValue_ListValue::i() const {
+  // @@protoc_insertion_point(field_list:tensorflow.AttrValue.ListValue.i)
+  return i_;
+}
+::google::protobuf::RepeatedField< ::google::protobuf::int64 >*
+AttrValue_ListValue::mutable_i() {
+  // @@protoc_insertion_point(field_mutable_list:tensorflow.AttrValue.ListValue.i)
+  return &i_;
+}
+
+// repeated float f = 4 [packed = true];
+int AttrValue_ListValue::f_size() const {
+  return f_.size();
+}
+void AttrValue_ListValue::clear_f() {
+  f_.Clear();
+}
+float AttrValue_ListValue::f(int index) const {
+  // @@protoc_insertion_point(field_get:tensorflow.AttrValue.ListValue.f)
+  return f_.Get(index);
+}
+void AttrValue_ListValue::set_f(int index, float value) {
+  f_.Set(index, value);
+  // @@protoc_insertion_point(field_set:tensorflow.AttrValue.ListValue.f)
+}
+void AttrValue_ListValue::add_f(float value) {
+  f_.Add(value);
+  // @@protoc_insertion_point(field_add:tensorflow.AttrValue.ListValue.f)
+}
+const ::google::protobuf::RepeatedField< float >&
+AttrValue_ListValue::f() const {
+  // @@protoc_insertion_point(field_list:tensorflow.AttrValue.ListValue.f)
+  return f_;
+}
+::google::protobuf::RepeatedField< float >*
+AttrValue_ListValue::mutable_f() {
+  // @@protoc_insertion_point(field_mutable_list:tensorflow.AttrValue.ListValue.f)
+  return &f_;
+}
+
+// repeated bool b = 5 [packed = true];
+int AttrValue_ListValue::b_size() const {
+  return b_.size();
+}
+void AttrValue_ListValue::clear_b() {
+  b_.Clear();
+}
+bool AttrValue_ListValue::b(int index) const {
+  // @@protoc_insertion_point(field_get:tensorflow.AttrValue.ListValue.b)
+  return b_.Get(index);
+}
+void AttrValue_ListValue::set_b(int index, bool value) {
+  b_.Set(index, value);
+  // @@protoc_insertion_point(field_set:tensorflow.AttrValue.ListValue.b)
+}
+void AttrValue_ListValue::add_b(bool value) {
+  b_.Add(value);
+  // @@protoc_insertion_point(field_add:tensorflow.AttrValue.ListValue.b)
+}
+const ::google::protobuf::RepeatedField< bool >&
+AttrValue_ListValue::b() const {
+  // @@protoc_insertion_point(field_list:tensorflow.AttrValue.ListValue.b)
+  return b_;
+}
+::google::protobuf::RepeatedField< bool >*
+AttrValue_ListValue::mutable_b() {
+  // @@protoc_insertion_point(field_mutable_list:tensorflow.AttrValue.ListValue.b)
+  return &b_;
+}
+
+// repeated .tensorflow.DataType type = 6 [packed = true];
+int AttrValue_ListValue::type_size() const {
+  return type_.size();
+}
+void AttrValue_ListValue::clear_type() {
+  type_.Clear();
+}
+::tensorflow::DataType AttrValue_ListValue::type(int index) const {
+  // @@protoc_insertion_point(field_get:tensorflow.AttrValue.ListValue.type)
+  return static_cast< ::tensorflow::DataType >(type_.Get(index));
+}
+void AttrValue_ListValue::set_type(int index, ::tensorflow::DataType value) {
+  type_.Set(index, value);
+  // @@protoc_insertion_point(field_set:tensorflow.AttrValue.ListValue.type)
+}
+void AttrValue_ListValue::add_type(::tensorflow::DataType value) {
+  type_.Add(value);
+  // @@protoc_insertion_point(field_add:tensorflow.AttrValue.ListValue.type)
+}
+const ::google::protobuf::RepeatedField<int>&
+AttrValue_ListValue::type() const {
+  // @@protoc_insertion_point(field_list:tensorflow.AttrValue.ListValue.type)
+  return type_;
+}
+::google::protobuf::RepeatedField<int>*
+AttrValue_ListValue::mutable_type() {
+  // @@protoc_insertion_point(field_mutable_list:tensorflow.AttrValue.ListValue.type)
+  return &type_;
+}
+
+// repeated .tensorflow.TensorShapeProto shape = 7;
+int AttrValue_ListValue::shape_size() const {
+  return shape_.size();
+}
+void AttrValue_ListValue::clear_shape() {
+  shape_.Clear();
+}
+const ::tensorflow::TensorShapeProto& AttrValue_ListValue::shape(int index) const {
+  // @@protoc_insertion_point(field_get:tensorflow.AttrValue.ListValue.shape)
+  return shape_.Get(index);
+}
+::tensorflow::TensorShapeProto* AttrValue_ListValue::mutable_shape(int index) {
+  // @@protoc_insertion_point(field_mutable:tensorflow.AttrValue.ListValue.shape)
+  return shape_.Mutable(index);
+}
+::tensorflow::TensorShapeProto* AttrValue_ListValue::add_shape() {
+  // @@protoc_insertion_point(field_add:tensorflow.AttrValue.ListValue.shape)
+  return shape_.Add();
+}
+::google::protobuf::RepeatedPtrField< ::tensorflow::TensorShapeProto >*
+AttrValue_ListValue::mutable_shape() {
+  // @@protoc_insertion_point(field_mutable_list:tensorflow.AttrValue.ListValue.shape)
+  return &shape_;
+}
+const ::google::protobuf::RepeatedPtrField< ::tensorflow::TensorShapeProto >&
+AttrValue_ListValue::shape() const {
+  // @@protoc_insertion_point(field_list:tensorflow.AttrValue.ListValue.shape)
+  return shape_;
+}
+
+// repeated .tensorflow.TensorProto tensor = 8;
+int AttrValue_ListValue::tensor_size() const {
+  return tensor_.size();
+}
+void AttrValue_ListValue::clear_tensor() {
+  tensor_.Clear();
+}
+const ::tensorflow::TensorProto& AttrValue_ListValue::tensor(int index) const {
+  // @@protoc_insertion_point(field_get:tensorflow.AttrValue.ListValue.tensor)
+  return tensor_.Get(index);
+}
+::tensorflow::TensorProto* AttrValue_ListValue::mutable_tensor(int index) {
+  // @@protoc_insertion_point(field_mutable:tensorflow.AttrValue.ListValue.tensor)
+  return tensor_.Mutable(index);
+}
+::tensorflow::TensorProto* AttrValue_ListValue::add_tensor() {
+  // @@protoc_insertion_point(field_add:tensorflow.AttrValue.ListValue.tensor)
+  return tensor_.Add();
+}
+::google::protobuf::RepeatedPtrField< ::tensorflow::TensorProto >*
+AttrValue_ListValue::mutable_tensor() {
+  // @@protoc_insertion_point(field_mutable_list:tensorflow.AttrValue.ListValue.tensor)
+  return &tensor_;
+}
+const ::google::protobuf::RepeatedPtrField< ::tensorflow::TensorProto >&
+AttrValue_ListValue::tensor() const {
+  // @@protoc_insertion_point(field_list:tensorflow.AttrValue.ListValue.tensor)
+  return tensor_;
+}
+
+inline const AttrValue_ListValue* AttrValue_ListValue::internal_default_instance() {
+  return &AttrValue_ListValue_default_instance_.get();
+}
+// -------------------------------------------------------------------
+
+// AttrValue
+
+// optional bytes s = 2;
+bool AttrValue::has_s() const {
+  return value_case() == kS;
+}
+void AttrValue::set_has_s() {
+  _oneof_case_[0] = kS;
+}
+void AttrValue::clear_s() {
+  if (has_s()) {
+    value_.s_.Destroy(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+        GetArenaNoVirtual());
+    clear_has_value();
+  }
+}
+const ::std::string& AttrValue::s() const {
+  // @@protoc_insertion_point(field_get:tensorflow.AttrValue.s)
+  if (has_s()) {
+    return value_.s_.Get(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  }
+  return *&::google::protobuf::internal::GetEmptyStringAlreadyInited();
+}
+void AttrValue::set_s(const ::std::string& value) {
+  if (!has_s()) {
+    clear_value();
+    set_has_s();
+    value_.s_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  }
+  value_.s_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value,
+      GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set:tensorflow.AttrValue.s)
+}
+void AttrValue::set_s(const char* value) {
+  if (!has_s()) {
+    clear_value();
+    set_has_s();
+    value_.s_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  }
+  value_.s_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(value), GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_char:tensorflow.AttrValue.s)
+}
+void AttrValue::set_s(const void* value,
+                             size_t size) {
+  if (!has_s()) {
+    clear_value();
+    set_has_s();
+    value_.s_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  }
+  value_.s_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(
+      reinterpret_cast<const char*>(value), size),
+      GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_pointer:tensorflow.AttrValue.s)
+}
+::std::string* AttrValue::mutable_s() {
+  if (!has_s()) {
+    clear_value();
+    set_has_s();
+    value_.s_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  }
+  return value_.s_.Mutable(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_mutable:tensorflow.AttrValue.s)
+}
+::std::string* AttrValue::release_s() {
+  // @@protoc_insertion_point(field_release:tensorflow.AttrValue.s)
+  if (has_s()) {
+    clear_has_value();
+    return value_.s_.Release(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+        GetArenaNoVirtual());
+  } else {
+    return NULL;
+  }
+}
+::std::string* AttrValue::unsafe_arena_release_s() {
+  // @@protoc_insertion_point(field_unsafe_arena_release:tensorflow.AttrValue.s)
+  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);
+  if (has_s()) {
+    clear_has_value();
+    return value_.s_.UnsafeArenaRelease(
+        &::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+  } else {
+    return NULL;
+  }
+}
+void AttrValue::set_allocated_s(::std::string* s) {
+  if (!has_s()) {
+    value_.s_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  }
+  clear_value();
+  if (s != NULL) {
+    set_has_s();
+    value_.s_.SetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), s,
+        GetArenaNoVirtual());
+  }
+  // @@protoc_insertion_point(field_set_allocated:tensorflow.AttrValue.s)
+}
+void AttrValue::unsafe_arena_set_allocated_s(::std::string* s) {
+  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);
+  if (!has_s()) {
+    value_.s_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  }
+  clear_value();
+  if (s) {
+    set_has_s();
+    value_.s_.UnsafeArenaSetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), s, GetArenaNoVirtual());
+  }
+  // @@protoc_insertion_point(field_unsafe_arena_set_allocated:tensorflow.AttrValue.s)
+}
+
+// optional int64 i = 3;
+bool AttrValue::has_i() const {
+  return value_case() == kI;
+}
+void AttrValue::set_has_i() {
+  _oneof_case_[0] = kI;
+}
+void AttrValue::clear_i() {
+  if (has_i()) {
+    value_.i_ = GOOGLE_LONGLONG(0);
+    clear_has_value();
+  }
+}
+::google::protobuf::int64 AttrValue::i() const {
+  // @@protoc_insertion_point(field_get:tensorflow.AttrValue.i)
+  if (has_i()) {
+    return value_.i_;
+  }
+  return GOOGLE_LONGLONG(0);
+}
+void AttrValue::set_i(::google::protobuf::int64 value) {
+  if (!has_i()) {
+    clear_value();
+    set_has_i();
+  }
+  value_.i_ = value;
+  // @@protoc_insertion_point(field_set:tensorflow.AttrValue.i)
+}
+
+// optional float f = 4;
+bool AttrValue::has_f() const {
+  return value_case() == kF;
+}
+void AttrValue::set_has_f() {
+  _oneof_case_[0] = kF;
+}
+void AttrValue::clear_f() {
+  if (has_f()) {
+    value_.f_ = 0;
+    clear_has_value();
+  }
+}
+float AttrValue::f() const {
+  // @@protoc_insertion_point(field_get:tensorflow.AttrValue.f)
+  if (has_f()) {
+    return value_.f_;
+  }
+  return 0;
+}
+void AttrValue::set_f(float value) {
+  if (!has_f()) {
+    clear_value();
+    set_has_f();
+  }
+  value_.f_ = value;
+  // @@protoc_insertion_point(field_set:tensorflow.AttrValue.f)
+}
+
+// optional bool b = 5;
+bool AttrValue::has_b() const {
+  return value_case() == kB;
+}
+void AttrValue::set_has_b() {
+  _oneof_case_[0] = kB;
+}
+void AttrValue::clear_b() {
+  if (has_b()) {
+    value_.b_ = false;
+    clear_has_value();
+  }
+}
+bool AttrValue::b() const {
+  // @@protoc_insertion_point(field_get:tensorflow.AttrValue.b)
+  if (has_b()) {
+    return value_.b_;
+  }
+  return false;
+}
+void AttrValue::set_b(bool value) {
+  if (!has_b()) {
+    clear_value();
+    set_has_b();
+  }
+  value_.b_ = value;
+  // @@protoc_insertion_point(field_set:tensorflow.AttrValue.b)
+}
+
+// optional .tensorflow.DataType type = 6;
+bool AttrValue::has_type() const {
+  return value_case() == kType;
+}
+void AttrValue::set_has_type() {
+  _oneof_case_[0] = kType;
+}
+void AttrValue::clear_type() {
+  if (has_type()) {
+    value_.type_ = 0;
+    clear_has_value();
+  }
+}
+::tensorflow::DataType AttrValue::type() const {
+  // @@protoc_insertion_point(field_get:tensorflow.AttrValue.type)
+  if (has_type()) {
+    return static_cast< ::tensorflow::DataType >(value_.type_);
+  }
+  return static_cast< ::tensorflow::DataType >(0);
+}
+void AttrValue::set_type(::tensorflow::DataType value) {
+  if (!has_type()) {
+    clear_value();
+    set_has_type();
+  }
+  value_.type_ = value;
+  // @@protoc_insertion_point(field_set:tensorflow.AttrValue.type)
+}
+
+// optional .tensorflow.TensorShapeProto shape = 7;
+bool AttrValue::has_shape() const {
+  return value_case() == kShape;
+}
+void AttrValue::set_has_shape() {
+  _oneof_case_[0] = kShape;
+}
+void AttrValue::clear_shape() {
+  if (has_shape()) {
+    if (GetArenaNoVirtual() == NULL) {
+      delete value_.shape_;
+    }
+    clear_has_value();
+  }
+}
+ const ::tensorflow::TensorShapeProto& AttrValue::shape() const {
+  // @@protoc_insertion_point(field_get:tensorflow.AttrValue.shape)
+  return has_shape()
+      ? *value_.shape_
+      : ::tensorflow::TensorShapeProto::default_instance();
+}
+::tensorflow::TensorShapeProto* AttrValue::mutable_shape() {
+  if (!has_shape()) {
+    clear_value();
+    set_has_shape();
+    value_.shape_ =
+      ::google::protobuf::Arena::CreateMessage< ::tensorflow::TensorShapeProto >(
+      GetArenaNoVirtual());
+  }
+  // @@protoc_insertion_point(field_mutable:tensorflow.AttrValue.shape)
+  return value_.shape_;
+}
+::tensorflow::TensorShapeProto* AttrValue::release_shape() {
+  // @@protoc_insertion_point(field_release:tensorflow.AttrValue.shape)
+  if (has_shape()) {
+    clear_has_value();
+    if (GetArenaNoVirtual() != NULL) {
+      ::tensorflow::TensorShapeProto* temp = new ::tensorflow::TensorShapeProto(*value_.shape_);
+      value_.shape_ = NULL;
+      return temp;
+    } else {
+      ::tensorflow::TensorShapeProto* temp = value_.shape_;
+      value_.shape_ = NULL;
+      return temp;
+    }
+  } else {
+    return NULL;
+  }
+}
+void AttrValue::set_allocated_shape(::tensorflow::TensorShapeProto* shape) {
+  clear_value();
+  if (shape) {
+    if (GetArenaNoVirtual() != NULL &&
+        ::google::protobuf::Arena::GetArena(shape) == NULL) {
+      GetArenaNoVirtual()->Own(shape);
+    } else if (GetArenaNoVirtual() !=
+               ::google::protobuf::Arena::GetArena(shape)) {
+      ::tensorflow::TensorShapeProto* new_shape =
+          ::google::protobuf::Arena::CreateMessage< ::tensorflow::TensorShapeProto >(
+          GetArenaNoVirtual());
+      new_shape->CopyFrom(*shape);
+      shape = new_shape;
+    }
+    set_has_shape();
+    value_.shape_ = shape;
+  }
+  // @@protoc_insertion_point(field_set_allocated:tensorflow.AttrValue.shape)
+}
+ ::tensorflow::TensorShapeProto* AttrValue::unsafe_arena_release_shape() {
+  // @@protoc_insertion_point(field_unsafe_arena_release:tensorflow.AttrValue.shape)
+  if (has_shape()) {
+    clear_has_value();
+    ::tensorflow::TensorShapeProto* temp = value_.shape_;
+    value_.shape_ = NULL;
+    return temp;
+  } else {
+    return NULL;
+  }
+}
+ void AttrValue::unsafe_arena_set_allocated_shape(::tensorflow::TensorShapeProto* shape) {
+  clear_value();
+  if (shape) {
+    set_has_shape();
+    value_.shape_ = shape;
+  }
+  // @@protoc_insertion_point(field_unsafe_arena_set_allocated:tensorflow.AttrValue.shape)
+}
+
+// optional .tensorflow.TensorProto tensor = 8;
+bool AttrValue::has_tensor() const {
+  return value_case() == kTensor;
+}
+void AttrValue::set_has_tensor() {
+  _oneof_case_[0] = kTensor;
+}
+void AttrValue::clear_tensor() {
+  if (has_tensor()) {
+    if (GetArenaNoVirtual() == NULL) {
+      delete value_.tensor_;
+    }
+    clear_has_value();
+  }
+}
+ const ::tensorflow::TensorProto& AttrValue::tensor() const {
+  // @@protoc_insertion_point(field_get:tensorflow.AttrValue.tensor)
+  return has_tensor()
+      ? *value_.tensor_
+      : ::tensorflow::TensorProto::default_instance();
+}
+::tensorflow::TensorProto* AttrValue::mutable_tensor() {
+  if (!has_tensor()) {
+    clear_value();
+    set_has_tensor();
+    value_.tensor_ =
+      ::google::protobuf::Arena::CreateMessage< ::tensorflow::TensorProto >(
+      GetArenaNoVirtual());
+  }
+  // @@protoc_insertion_point(field_mutable:tensorflow.AttrValue.tensor)
+  return value_.tensor_;
+}
+::tensorflow::TensorProto* AttrValue::release_tensor() {
+  // @@protoc_insertion_point(field_release:tensorflow.AttrValue.tensor)
+  if (has_tensor()) {
+    clear_has_value();
+    if (GetArenaNoVirtual() != NULL) {
+      ::tensorflow::TensorProto* temp = new ::tensorflow::TensorProto(*value_.tensor_);
+      value_.tensor_ = NULL;
+      return temp;
+    } else {
+      ::tensorflow::TensorProto* temp = value_.tensor_;
+      value_.tensor_ = NULL;
+      return temp;
+    }
+  } else {
+    return NULL;
+  }
+}
+void AttrValue::set_allocated_tensor(::tensorflow::TensorProto* tensor) {
+  clear_value();
+  if (tensor) {
+    if (GetArenaNoVirtual() != NULL &&
+        ::google::protobuf::Arena::GetArena(tensor) == NULL) {
+      GetArenaNoVirtual()->Own(tensor);
+    } else if (GetArenaNoVirtual() !=
+               ::google::protobuf::Arena::GetArena(tensor)) {
+      ::tensorflow::TensorProto* new_tensor =
+          ::google::protobuf::Arena::CreateMessage< ::tensorflow::TensorProto >(
+          GetArenaNoVirtual());
+      new_tensor->CopyFrom(*tensor);
+      tensor = new_tensor;
+    }
+    set_has_tensor();
+    value_.tensor_ = tensor;
+  }
+  // @@protoc_insertion_point(field_set_allocated:tensorflow.AttrValue.tensor)
+}
+ ::tensorflow::TensorProto* AttrValue::unsafe_arena_release_tensor() {
+  // @@protoc_insertion_point(field_unsafe_arena_release:tensorflow.AttrValue.tensor)
+  if (has_tensor()) {
+    clear_has_value();
+    ::tensorflow::TensorProto* temp = value_.tensor_;
+    value_.tensor_ = NULL;
+    return temp;
+  } else {
+    return NULL;
+  }
+}
+ void AttrValue::unsafe_arena_set_allocated_tensor(::tensorflow::TensorProto* tensor) {
+  clear_value();
+  if (tensor) {
+    set_has_tensor();
+    value_.tensor_ = tensor;
+  }
+  // @@protoc_insertion_point(field_unsafe_arena_set_allocated:tensorflow.AttrValue.tensor)
+}
+
+// optional .tensorflow.AttrValue.ListValue list = 1;
+bool AttrValue::has_list() const {
+  return value_case() == kList;
+}
+void AttrValue::set_has_list() {
+  _oneof_case_[0] = kList;
+}
+void AttrValue::clear_list() {
+  if (has_list()) {
+    if (GetArenaNoVirtual() == NULL) {
+      delete value_.list_;
+    }
+    clear_has_value();
+  }
+}
+ const ::tensorflow::AttrValue_ListValue& AttrValue::list() const {
+  // @@protoc_insertion_point(field_get:tensorflow.AttrValue.list)
+  return has_list()
+      ? *value_.list_
+      : ::tensorflow::AttrValue_ListValue::default_instance();
+}
+::tensorflow::AttrValue_ListValue* AttrValue::mutable_list() {
+  if (!has_list()) {
+    clear_value();
+    set_has_list();
+    value_.list_ =
+      ::google::protobuf::Arena::CreateMessage< ::tensorflow::AttrValue_ListValue >(
+      GetArenaNoVirtual());
+  }
+  // @@protoc_insertion_point(field_mutable:tensorflow.AttrValue.list)
+  return value_.list_;
+}
+::tensorflow::AttrValue_ListValue* AttrValue::release_list() {
+  // @@protoc_insertion_point(field_release:tensorflow.AttrValue.list)
+  if (has_list()) {
+    clear_has_value();
+    if (GetArenaNoVirtual() != NULL) {
+      ::tensorflow::AttrValue_ListValue* temp = new ::tensorflow::AttrValue_ListValue(*value_.list_);
+      value_.list_ = NULL;
+      return temp;
+    } else {
+      ::tensorflow::AttrValue_ListValue* temp = value_.list_;
+      value_.list_ = NULL;
+      return temp;
+    }
+  } else {
+    return NULL;
+  }
+}
+void AttrValue::set_allocated_list(::tensorflow::AttrValue_ListValue* list) {
+  clear_value();
+  if (list) {
+    if (GetArenaNoVirtual() != NULL &&
+        ::google::protobuf::Arena::GetArena(list) == NULL) {
+      GetArenaNoVirtual()->Own(list);
+    } else if (GetArenaNoVirtual() !=
+               ::google::protobuf::Arena::GetArena(list)) {
+      ::tensorflow::AttrValue_ListValue* new_list =
+          ::google::protobuf::Arena::CreateMessage< ::tensorflow::AttrValue_ListValue >(
+          GetArenaNoVirtual());
+      new_list->CopyFrom(*list);
+      list = new_list;
+    }
+    set_has_list();
+    value_.list_ = list;
+  }
+  // @@protoc_insertion_point(field_set_allocated:tensorflow.AttrValue.list)
+}
+ ::tensorflow::AttrValue_ListValue* AttrValue::unsafe_arena_release_list() {
+  // @@protoc_insertion_point(field_unsafe_arena_release:tensorflow.AttrValue.list)
+  if (has_list()) {
+    clear_has_value();
+    ::tensorflow::AttrValue_ListValue* temp = value_.list_;
+    value_.list_ = NULL;
+    return temp;
+  } else {
+    return NULL;
+  }
+}
+ void AttrValue::unsafe_arena_set_allocated_list(::tensorflow::AttrValue_ListValue* list) {
+  clear_value();
+  if (list) {
+    set_has_list();
+    value_.list_ = list;
+  }
+  // @@protoc_insertion_point(field_unsafe_arena_set_allocated:tensorflow.AttrValue.list)
+}
+
+// optional .tensorflow.NameAttrList func = 10;
+bool AttrValue::has_func() const {
+  return value_case() == kFunc;
+}
+void AttrValue::set_has_func() {
+  _oneof_case_[0] = kFunc;
+}
+void AttrValue::clear_func() {
+  if (has_func()) {
+    if (GetArenaNoVirtual() == NULL) {
+      delete value_.func_;
+    }
+    clear_has_value();
+  }
+}
+ const ::tensorflow::NameAttrList& AttrValue::func() const {
+  // @@protoc_insertion_point(field_get:tensorflow.AttrValue.func)
+  return has_func()
+      ? *value_.func_
+      : ::tensorflow::NameAttrList::default_instance();
+}
+::tensorflow::NameAttrList* AttrValue::mutable_func() {
+  if (!has_func()) {
+    clear_value();
+    set_has_func();
+    value_.func_ =
+      ::google::protobuf::Arena::CreateMessage< ::tensorflow::NameAttrList >(
+      GetArenaNoVirtual());
+  }
+  // @@protoc_insertion_point(field_mutable:tensorflow.AttrValue.func)
+  return value_.func_;
+}
+::tensorflow::NameAttrList* AttrValue::release_func() {
+  // @@protoc_insertion_point(field_release:tensorflow.AttrValue.func)
+  if (has_func()) {
+    clear_has_value();
+    if (GetArenaNoVirtual() != NULL) {
+      ::tensorflow::NameAttrList* temp = new ::tensorflow::NameAttrList(*value_.func_);
+      value_.func_ = NULL;
+      return temp;
+    } else {
+      ::tensorflow::NameAttrList* temp = value_.func_;
+      value_.func_ = NULL;
+      return temp;
+    }
+  } else {
+    return NULL;
+  }
+}
+void AttrValue::set_allocated_func(::tensorflow::NameAttrList* func) {
+  clear_value();
+  if (func) {
+    if (GetArenaNoVirtual() != NULL &&
+        ::google::protobuf::Arena::GetArena(func) == NULL) {
+      GetArenaNoVirtual()->Own(func);
+    } else if (GetArenaNoVirtual() !=
+               ::google::protobuf::Arena::GetArena(func)) {
+      ::tensorflow::NameAttrList* new_func =
+          ::google::protobuf::Arena::CreateMessage< ::tensorflow::NameAttrList >(
+          GetArenaNoVirtual());
+      new_func->CopyFrom(*func);
+      func = new_func;
+    }
+    set_has_func();
+    value_.func_ = func;
+  }
+  // @@protoc_insertion_point(field_set_allocated:tensorflow.AttrValue.func)
+}
+ ::tensorflow::NameAttrList* AttrValue::unsafe_arena_release_func() {
+  // @@protoc_insertion_point(field_unsafe_arena_release:tensorflow.AttrValue.func)
+  if (has_func()) {
+    clear_has_value();
+    ::tensorflow::NameAttrList* temp = value_.func_;
+    value_.func_ = NULL;
+    return temp;
+  } else {
+    return NULL;
+  }
+}
+ void AttrValue::unsafe_arena_set_allocated_func(::tensorflow::NameAttrList* func) {
+  clear_value();
+  if (func) {
+    set_has_func();
+    value_.func_ = func;
+  }
+  // @@protoc_insertion_point(field_unsafe_arena_set_allocated:tensorflow.AttrValue.func)
+}
+
+// optional string placeholder = 9;
+bool AttrValue::has_placeholder() const {
+  return value_case() == kPlaceholder;
+}
+void AttrValue::set_has_placeholder() {
+  _oneof_case_[0] = kPlaceholder;
+}
+void AttrValue::clear_placeholder() {
+  if (has_placeholder()) {
+    value_.placeholder_.Destroy(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+        GetArenaNoVirtual());
+    clear_has_value();
+  }
+}
+const ::std::string& AttrValue::placeholder() const {
+  // @@protoc_insertion_point(field_get:tensorflow.AttrValue.placeholder)
+  if (has_placeholder()) {
+    return value_.placeholder_.Get(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  }
+  return *&::google::protobuf::internal::GetEmptyStringAlreadyInited();
+}
+void AttrValue::set_placeholder(const ::std::string& value) {
+  if (!has_placeholder()) {
+    clear_value();
+    set_has_placeholder();
+    value_.placeholder_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  }
+  value_.placeholder_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value,
+      GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set:tensorflow.AttrValue.placeholder)
+}
+void AttrValue::set_placeholder(const char* value) {
+  if (!has_placeholder()) {
+    clear_value();
+    set_has_placeholder();
+    value_.placeholder_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  }
+  value_.placeholder_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(value), GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_char:tensorflow.AttrValue.placeholder)
+}
+void AttrValue::set_placeholder(const char* value,
+                             size_t size) {
+  if (!has_placeholder()) {
+    clear_value();
+    set_has_placeholder();
+    value_.placeholder_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  }
+  value_.placeholder_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(
+      reinterpret_cast<const char*>(value), size),
+      GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_pointer:tensorflow.AttrValue.placeholder)
+}
+::std::string* AttrValue::mutable_placeholder() {
+  if (!has_placeholder()) {
+    clear_value();
+    set_has_placeholder();
+    value_.placeholder_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  }
+  return value_.placeholder_.Mutable(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_mutable:tensorflow.AttrValue.placeholder)
+}
+::std::string* AttrValue::release_placeholder() {
+  // @@protoc_insertion_point(field_release:tensorflow.AttrValue.placeholder)
+  if (has_placeholder()) {
+    clear_has_value();
+    return value_.placeholder_.Release(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+        GetArenaNoVirtual());
+  } else {
+    return NULL;
+  }
+}
+::std::string* AttrValue::unsafe_arena_release_placeholder() {
+  // @@protoc_insertion_point(field_unsafe_arena_release:tensorflow.AttrValue.placeholder)
+  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);
+  if (has_placeholder()) {
+    clear_has_value();
+    return value_.placeholder_.UnsafeArenaRelease(
+        &::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+  } else {
+    return NULL;
+  }
+}
+void AttrValue::set_allocated_placeholder(::std::string* placeholder) {
+  if (!has_placeholder()) {
+    value_.placeholder_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  }
+  clear_value();
+  if (placeholder != NULL) {
+    set_has_placeholder();
+    value_.placeholder_.SetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), placeholder,
+        GetArenaNoVirtual());
+  }
+  // @@protoc_insertion_point(field_set_allocated:tensorflow.AttrValue.placeholder)
+}
+void AttrValue::unsafe_arena_set_allocated_placeholder(::std::string* placeholder) {
+  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);
+  if (!has_placeholder()) {
+    value_.placeholder_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  }
+  clear_value();
+  if (placeholder) {
+    set_has_placeholder();
+    value_.placeholder_.UnsafeArenaSetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), placeholder, GetArenaNoVirtual());
+  }
+  // @@protoc_insertion_point(field_unsafe_arena_set_allocated:tensorflow.AttrValue.placeholder)
+}
+
+bool AttrValue::has_value() const {
+  return value_case() != VALUE_NOT_SET;
+}
+void AttrValue::clear_has_value() {
+  _oneof_case_[0] = VALUE_NOT_SET;
+}
+AttrValue::ValueCase AttrValue::value_case() const {
+  return AttrValue::ValueCase(_oneof_case_[0]);
+}
+inline const AttrValue* AttrValue::internal_default_instance() {
+  return &AttrValue_default_instance_.get();
+}
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
+
+// ===================================================================
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const int NameAttrList::kNameFieldNumber;
+const int NameAttrList::kAttrFieldNumber;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+
+NameAttrList::NameAttrList()
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+  if (this != internal_default_instance()) protobuf_InitDefaults_attr_5fvalue_2eproto();
+  SharedCtor();
+  // @@protoc_insertion_point(constructor:tensorflow.NameAttrList)
+}
+NameAttrList::NameAttrList(::google::protobuf::Arena* arena)
+  : ::google::protobuf::Message(),
+  _internal_metadata_(arena),
+  attr_(arena) {
+#ifdef GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER
+  protobuf_InitDefaults_attr_5fvalue_2eproto();
+#endif  // GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER
+  SharedCtor();
+  RegisterArenaDtor(arena);
+  // @@protoc_insertion_point(arena_constructor:tensorflow.NameAttrList)
+}
+
+void NameAttrList::InitAsDefaultInstance() {
+}
+
+NameAttrList::NameAttrList(const NameAttrList& from)
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
+  SharedCtor();
+  UnsafeMergeFrom(from);
+  // @@protoc_insertion_point(copy_constructor:tensorflow.NameAttrList)
+}
+
+void NameAttrList::SharedCtor() {
+  attr_.SetAssignDescriptorCallback(
+      protobuf_AssignDescriptorsOnce);
+  attr_.SetEntryDescriptor(
+      &::tensorflow::NameAttrList_AttrEntry_descriptor_);
+  name_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  _cached_size_ = 0;
+}
+
+NameAttrList::~NameAttrList() {
+  // @@protoc_insertion_point(destructor:tensorflow.NameAttrList)
+  SharedDtor();
+}
+
+void NameAttrList::SharedDtor() {
+  ::google::protobuf::Arena* arena = GetArenaNoVirtual();
+  if (arena != NULL) {
+    return;
+  }
+
+  name_.Destroy(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), arena);
+}
+
+void NameAttrList::ArenaDtor(void* object) {
+  NameAttrList* _this = reinterpret_cast< NameAttrList* >(object);
+  (void)_this;
+}
+void NameAttrList::RegisterArenaDtor(::google::protobuf::Arena* arena) {
+}
+void NameAttrList::SetCachedSize(int size) const {
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* NameAttrList::descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return NameAttrList_descriptor_;
+}
+
+const NameAttrList& NameAttrList::default_instance() {
+  protobuf_InitDefaults_attr_5fvalue_2eproto();
+  return *internal_default_instance();
+}
+
+::google::protobuf::internal::ExplicitlyConstructed<NameAttrList> NameAttrList_default_instance_;
+
+NameAttrList* NameAttrList::New(::google::protobuf::Arena* arena) const {
+  return ::google::protobuf::Arena::CreateMessage<NameAttrList>(arena);
+}
+
+void NameAttrList::Clear() {
+// @@protoc_insertion_point(message_clear_start:tensorflow.NameAttrList)
+  name_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+  attr_.Clear();
+}
+
+bool NameAttrList::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
+  ::google::protobuf::uint32 tag;
+  // @@protoc_insertion_point(parse_start:tensorflow.NameAttrList)
+  for (;;) {
+    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+    tag = p.first;
+    if (!p.second) goto handle_unusual;
+    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+      // optional string name = 1;
+      case 1: {
+        if (tag == 10) {
+          DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+                input, this->mutable_name()));
+          DO_(::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+            this->name().data(), this->name().length(),
+            ::google::protobuf::internal::WireFormatLite::PARSE,
+            "tensorflow.NameAttrList.name"));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(18)) goto parse_attr;
+        break;
+      }
+
+      // map<string, .tensorflow.AttrValue> attr = 2;
+      case 2: {
+        if (tag == 18) {
+         parse_attr:
+          DO_(input->IncrementRecursionDepth());
+         parse_loop_attr:
+          NameAttrList_AttrEntry::Parser< ::google::protobuf::internal::MapField<
+              ::std::string, ::tensorflow::AttrValue,
+              ::google::protobuf::internal::WireFormatLite::TYPE_STRING,
+              ::google::protobuf::internal::WireFormatLite::TYPE_MESSAGE,
+              0 >,
+            ::google::protobuf::Map< ::std::string, ::tensorflow::AttrValue > > parser(&attr_);
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+              input, &parser));
+          DO_(::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+            parser.key().data(), parser.key().length(),
+            ::google::protobuf::internal::WireFormatLite::PARSE,
+            "tensorflow.NameAttrList.AttrEntry.key"));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(18)) goto parse_loop_attr;
+        input->UnsafeDecrementRecursionDepth();
+        if (input->ExpectAtEnd()) goto success;
+        break;
+      }
+
+      default: {
+      handle_unusual:
+        if (tag == 0 ||
+            ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+          goto success;
+        }
+        DO_(::google::protobuf::internal::WireFormatLite::SkipField(input, tag));
+        break;
+      }
+    }
+  }
+success:
+  // @@protoc_insertion_point(parse_success:tensorflow.NameAttrList)
+  return true;
+failure:
+  // @@protoc_insertion_point(parse_failure:tensorflow.NameAttrList)
+  return false;
+#undef DO_
+}
+
+void NameAttrList::SerializeWithCachedSizes(
+    ::google::protobuf::io::CodedOutputStream* output) const {
+  // @@protoc_insertion_point(serialize_start:tensorflow.NameAttrList)
+  // optional string name = 1;
+  if (this->name().size() > 0) {
+    ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+      this->name().data(), this->name().length(),
+      ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+      "tensorflow.NameAttrList.name");
+    ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
+      1, this->name(), output);
+  }
+
+  // map<string, .tensorflow.AttrValue> attr = 2;
+  if (!this->attr().empty()) {
+    typedef ::google::protobuf::Map< ::std::string, ::tensorflow::AttrValue >::const_pointer
+        ConstPtr;
+    typedef ConstPtr SortItem;
+    typedef ::google::protobuf::internal::CompareByDerefFirst<SortItem> Less;
+    struct Utf8Check {
+      static void Check(ConstPtr p) {
+        ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+          p->first.data(), p->first.length(),
+          ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+          "tensorflow.NameAttrList.AttrEntry.key");
+      }
+    };
+
+    if (output->IsSerializationDeterminstic() &&
+        this->attr().size() > 1) {
+      ::google::protobuf::scoped_array<SortItem> items(
+          new SortItem[this->attr().size()]);
+      typedef ::google::protobuf::Map< ::std::string, ::tensorflow::AttrValue >::size_type size_type;
+      size_type n = 0;
+      for (::google::protobuf::Map< ::std::string, ::tensorflow::AttrValue >::const_iterator
+          it = this->attr().begin();
+          it != this->attr().end(); ++it, ++n) {
+        items[n] = SortItem(&*it);
+      }
+      ::std::sort(&items[0], &items[n], Less());
+      ::google::protobuf::scoped_ptr<NameAttrList_AttrEntry> entry;
+      for (size_type i = 0; i < n; i++) {
+        entry.reset(attr_.NewEntryWrapper(
+            items[i]->first, items[i]->second));
+        ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+            2, *entry, output);
+        if (entry->GetArena() != NULL) {
+          entry.release();
+        }
+        Utf8Check::Check(items[i]);
+      }
+    } else {
+      ::google::protobuf::scoped_ptr<NameAttrList_AttrEntry> entry;
+      for (::google::protobuf::Map< ::std::string, ::tensorflow::AttrValue >::const_iterator
+          it = this->attr().begin();
+          it != this->attr().end(); ++it) {
+        entry.reset(attr_.NewEntryWrapper(
+            it->first, it->second));
+        ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+            2, *entry, output);
+        if (entry->GetArena() != NULL) {
+          entry.release();
+        }
+        Utf8Check::Check(&*it);
+      }
+    }
+  }
+
+  // @@protoc_insertion_point(serialize_end:tensorflow.NameAttrList)
+}
+
+::google::protobuf::uint8* NameAttrList::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
+  (void)deterministic; // Unused
+  // @@protoc_insertion_point(serialize_to_array_start:tensorflow.NameAttrList)
+  // optional string name = 1;
+  if (this->name().size() > 0) {
+    ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+      this->name().data(), this->name().length(),
+      ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+      "tensorflow.NameAttrList.name");
+    target =
+      ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
+        1, this->name(), target);
+  }
+
+  // map<string, .tensorflow.AttrValue> attr = 2;
+  if (!this->attr().empty()) {
+    typedef ::google::protobuf::Map< ::std::string, ::tensorflow::AttrValue >::const_pointer
+        ConstPtr;
+    typedef ConstPtr SortItem;
+    typedef ::google::protobuf::internal::CompareByDerefFirst<SortItem> Less;
+    struct Utf8Check {
+      static void Check(ConstPtr p) {
+        ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+          p->first.data(), p->first.length(),
+          ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+          "tensorflow.NameAttrList.AttrEntry.key");
+      }
+    };
+
+    if (deterministic &&
+        this->attr().size() > 1) {
+      ::google::protobuf::scoped_array<SortItem> items(
+          new SortItem[this->attr().size()]);
+      typedef ::google::protobuf::Map< ::std::string, ::tensorflow::AttrValue >::size_type size_type;
+      size_type n = 0;
+      for (::google::protobuf::Map< ::std::string, ::tensorflow::AttrValue >::const_iterator
+          it = this->attr().begin();
+          it != this->attr().end(); ++it, ++n) {
+        items[n] = SortItem(&*it);
+      }
+      ::std::sort(&items[0], &items[n], Less());
+      ::google::protobuf::scoped_ptr<NameAttrList_AttrEntry> entry;
+      for (size_type i = 0; i < n; i++) {
+        entry.reset(attr_.NewEntryWrapper(
+            items[i]->first, items[i]->second));
+        target = ::google::protobuf::internal::WireFormatLite::
+                   InternalWriteMessageNoVirtualToArray(
+                       2, *entry, deterministic, target);
+;
+        if (entry->GetArena() != NULL) {
+          entry.release();
+        }
+        Utf8Check::Check(items[i]);
+      }
+    } else {
+      ::google::protobuf::scoped_ptr<NameAttrList_AttrEntry> entry;
+      for (::google::protobuf::Map< ::std::string, ::tensorflow::AttrValue >::const_iterator
+          it = this->attr().begin();
+          it != this->attr().end(); ++it) {
+        entry.reset(attr_.NewEntryWrapper(
+            it->first, it->second));
+        target = ::google::protobuf::internal::WireFormatLite::
+                   InternalWriteMessageNoVirtualToArray(
+                       2, *entry, deterministic, target);
+;
+        if (entry->GetArena() != NULL) {
+          entry.release();
+        }
+        Utf8Check::Check(&*it);
+      }
+    }
+  }
+
+  // @@protoc_insertion_point(serialize_to_array_end:tensorflow.NameAttrList)
+  return target;
+}
+
+size_t NameAttrList::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:tensorflow.NameAttrList)
+  size_t total_size = 0;
+
+  // optional string name = 1;
+  if (this->name().size() > 0) {
+    total_size += 1 +
+      ::google::protobuf::internal::WireFormatLite::StringSize(
+        this->name());
+  }
+
+  // map<string, .tensorflow.AttrValue> attr = 2;
+  total_size += 1 *
+      ::google::protobuf::internal::FromIntSize(this->attr_size());
+  {
+    ::google::protobuf::scoped_ptr<NameAttrList_AttrEntry> entry;
+    for (::google::protobuf::Map< ::std::string, ::tensorflow::AttrValue >::const_iterator
+        it = this->attr().begin();
+        it != this->attr().end(); ++it) {
+      if (entry.get() != NULL && entry->GetArena() != NULL) {
+        entry.release();
+      }
+      entry.reset(attr_.NewEntryWrapper(it->first, it->second));
+      total_size += ::google::protobuf::internal::WireFormatLite::
+          MessageSizeNoVirtual(*entry);
+    }
+    if (entry.get() != NULL && entry->GetArena() != NULL) {
+      entry.release();
+    }
+  }
+
+  int cached_size = ::google::protobuf::internal::ToCachedSize(total_size);
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = cached_size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+  return total_size;
+}
+
+void NameAttrList::MergeFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_merge_from_start:tensorflow.NameAttrList)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const NameAttrList* source =
+      ::google::protobuf::internal::DynamicCastToGenerated<const NameAttrList>(
+          &from);
+  if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:tensorflow.NameAttrList)
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:tensorflow.NameAttrList)
+    UnsafeMergeFrom(*source);
+  }
+}
+
+void NameAttrList::MergeFrom(const NameAttrList& from) {
+// @@protoc_insertion_point(class_specific_merge_from_start:tensorflow.NameAttrList)
+  if (GOOGLE_PREDICT_TRUE(&from != this)) {
+    UnsafeMergeFrom(from);
+  } else {
+    MergeFromFail(__LINE__);
+  }
+}
+
+void NameAttrList::UnsafeMergeFrom(const NameAttrList& from) {
+  GOOGLE_DCHECK(&from != this);
+  attr_.MergeFrom(from.attr_);
+  if (from.name().size() > 0) {
+    set_name(from.name());
+  }
+}
+
+void NameAttrList::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:tensorflow.NameAttrList)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void NameAttrList::CopyFrom(const NameAttrList& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:tensorflow.NameAttrList)
+  if (&from == this) return;
+  Clear();
+  UnsafeMergeFrom(from);
+}
+
+bool NameAttrList::IsInitialized() const {
+
+  return true;
+}
+
+void NameAttrList::Swap(NameAttrList* other) {
+  if (other == this) return;
+  if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) {
+    InternalSwap(other);
+  } else {
+    NameAttrList temp;
+    temp.UnsafeMergeFrom(*this);
+    CopyFrom(*other);
+    other->CopyFrom(temp);
+  }
+}
+void NameAttrList::UnsafeArenaSwap(NameAttrList* other) {
+  if (other == this) return;
+  GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual());
+  InternalSwap(other);
+}
+void NameAttrList::InternalSwap(NameAttrList* other) {
+  name_.Swap(&other->name_);
+  attr_.Swap(&other->attr_);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
+}
+
+::google::protobuf::Metadata NameAttrList::GetMetadata() const {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::Metadata metadata;
+  metadata.descriptor = NameAttrList_descriptor_;
+  metadata.reflection = NameAttrList_reflection_;
+  return metadata;
+}
+
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// NameAttrList
+
+// optional string name = 1;
+void NameAttrList::clear_name() {
+  name_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+const ::std::string& NameAttrList::name() const {
+  // @@protoc_insertion_point(field_get:tensorflow.NameAttrList.name)
+  return name_.Get(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+void NameAttrList::set_name(const ::std::string& value) {
+
+  name_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value, GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set:tensorflow.NameAttrList.name)
+}
+void NameAttrList::set_name(const char* value) {
+
+  name_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value),
+              GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_char:tensorflow.NameAttrList.name)
+}
+void NameAttrList::set_name(const char* value,
+    size_t size) {
+
+  name_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(
+      reinterpret_cast<const char*>(value), size), GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_pointer:tensorflow.NameAttrList.name)
+}
+::std::string* NameAttrList::mutable_name() {
+
+  // @@protoc_insertion_point(field_mutable:tensorflow.NameAttrList.name)
+  return name_.Mutable(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+::std::string* NameAttrList::release_name() {
+  // @@protoc_insertion_point(field_release:tensorflow.NameAttrList.name)
+
+  return name_.Release(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+::std::string* NameAttrList::unsafe_arena_release_name() {
+  // @@protoc_insertion_point(field_unsafe_arena_release:tensorflow.NameAttrList.name)
+  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);
+
+  return name_.UnsafeArenaRelease(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      GetArenaNoVirtual());
+}
+void NameAttrList::set_allocated_name(::std::string* name) {
+  if (name != NULL) {
+
+  } else {
+
+  }
+  name_.SetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), name,
+      GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_allocated:tensorflow.NameAttrList.name)
+}
+void NameAttrList::unsafe_arena_set_allocated_name(
+    ::std::string* name) {
+  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);
+  if (name != NULL) {
+
+  } else {
+
+  }
+  name_.UnsafeArenaSetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      name, GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_unsafe_arena_set_allocated:tensorflow.NameAttrList.name)
+}
+
+// map<string, .tensorflow.AttrValue> attr = 2;
+int NameAttrList::attr_size() const {
+  return attr_.size();
+}
+void NameAttrList::clear_attr() {
+  attr_.Clear();
+}
+ const ::google::protobuf::Map< ::std::string, ::tensorflow::AttrValue >&
+NameAttrList::attr() const {
+  // @@protoc_insertion_point(field_map:tensorflow.NameAttrList.attr)
+  return attr_.GetMap();
+}
+ ::google::protobuf::Map< ::std::string, ::tensorflow::AttrValue >*
+NameAttrList::mutable_attr() {
+  // @@protoc_insertion_point(field_mutable_map:tensorflow.NameAttrList.attr)
+  return attr_.MutableMap();
+}
+
+inline const NameAttrList* NameAttrList::internal_default_instance() {
+  return &NameAttrList_default_instance_.get();
+}
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
+
+// @@protoc_insertion_point(namespace_scope)
+
+}  // namespace tensorflow
+
+// @@protoc_insertion_point(global_scope)
diff --git a/contrib/modules/dnn/misc/tensorflow/attr_value.pb.h b/contrib/modules/dnn/misc/tensorflow/attr_value.pb.h
new file mode 100644
index 0000000..d37a724
--- /dev/null
+++ b/contrib/modules/dnn/misc/tensorflow/attr_value.pb.h
@@ -0,0 +1,1697 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: attr_value.proto
+
+#ifndef PROTOBUF_attr_5fvalue_2eproto__INCLUDED
+#define PROTOBUF_attr_5fvalue_2eproto__INCLUDED
+
+#include <string>
+
+#include <google/protobuf/stubs/common.h>
+
+#if GOOGLE_PROTOBUF_VERSION < 3001000
+#error This file was generated by a newer version of protoc which is
+#error incompatible with your Protocol Buffer headers.  Please update
+#error your headers.
+#endif
+#if 3001000 < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION
+#error This file was generated by an older version of protoc which is
+#error incompatible with your Protocol Buffer headers.  Please
+#error regenerate this file with a newer version of protoc.
+#endif
+
+#include <google/protobuf/arena.h>
+#include <google/protobuf/arenastring.h>
+#include <google/protobuf/generated_message_util.h>
+#include <google/protobuf/metadata.h>
+#include <google/protobuf/message.h>
+#include <google/protobuf/repeated_field.h>
+#include <google/protobuf/extension_set.h>
+#include <google/protobuf/map.h>
+#include <google/protobuf/map_field_inl.h>
+#include <google/protobuf/unknown_field_set.h>
+#include "tensor.pb.h"
+#include "tensor_shape.pb.h"
+#include "types.pb.h"
+// @@protoc_insertion_point(includes)
+
+namespace tensorflow {
+
+// Internal implementation detail -- do not call these.
+void protobuf_AddDesc_attr_5fvalue_2eproto();
+void protobuf_InitDefaults_attr_5fvalue_2eproto();
+void protobuf_AssignDesc_attr_5fvalue_2eproto();
+void protobuf_ShutdownFile_attr_5fvalue_2eproto();
+
+class AttrValue;
+class AttrValue_ListValue;
+class NameAttrList;
+
+// ===================================================================
+
+class AttrValue_ListValue : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:tensorflow.AttrValue.ListValue) */ {
+ public:
+  AttrValue_ListValue();
+  virtual ~AttrValue_ListValue();
+
+  AttrValue_ListValue(const AttrValue_ListValue& from);
+
+  inline AttrValue_ListValue& operator=(const AttrValue_ListValue& from) {
+    CopyFrom(from);
+    return *this;
+  }
+
+  inline ::google::protobuf::Arena* GetArena() const { return GetArenaNoVirtual(); }
+  inline void* GetMaybeArenaPointer() const {
+    return MaybeArenaPtr();
+  }
+  static const ::google::protobuf::Descriptor* descriptor();
+  static const AttrValue_ListValue& default_instance();
+
+  static const AttrValue_ListValue* internal_default_instance();
+
+  void UnsafeArenaSwap(AttrValue_ListValue* other);
+  void Swap(AttrValue_ListValue* other);
+
+  // implements Message ----------------------------------------------
+
+  inline AttrValue_ListValue* New() const { return New(NULL); }
+
+  AttrValue_ListValue* New(::google::protobuf::Arena* arena) const;
+  void CopyFrom(const ::google::protobuf::Message& from);
+  void MergeFrom(const ::google::protobuf::Message& from);
+  void CopyFrom(const AttrValue_ListValue& from);
+  void MergeFrom(const AttrValue_ListValue& from);
+  void Clear();
+  bool IsInitialized() const;
+
+  size_t ByteSizeLong() const;
+  bool MergePartialFromCodedStream(
+      ::google::protobuf::io::CodedInputStream* input);
+  void SerializeWithCachedSizes(
+      ::google::protobuf::io::CodedOutputStream* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
+  int GetCachedSize() const { return _cached_size_; }
+  private:
+  void SharedCtor();
+  void SharedDtor();
+  void SetCachedSize(int size) const;
+  void InternalSwap(AttrValue_ListValue* other);
+  void UnsafeMergeFrom(const AttrValue_ListValue& from);
+  protected:
+  explicit AttrValue_ListValue(::google::protobuf::Arena* arena);
+  private:
+  static void ArenaDtor(void* object);
+  inline void RegisterArenaDtor(::google::protobuf::Arena* arena);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
+  public:
+
+  ::google::protobuf::Metadata GetMetadata() const;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  // repeated bytes s = 2;
+  int s_size() const;
+  void clear_s();
+  static const int kSFieldNumber = 2;
+  const ::std::string& s(int index) const;
+  ::std::string* mutable_s(int index);
+  void set_s(int index, const ::std::string& value);
+  void set_s(int index, const char* value);
+  void set_s(int index, const void* value, size_t size);
+  ::std::string* add_s();
+  void add_s(const ::std::string& value);
+  void add_s(const char* value);
+  void add_s(const void* value, size_t size);
+  const ::google::protobuf::RepeatedPtrField< ::std::string>& s() const;
+  ::google::protobuf::RepeatedPtrField< ::std::string>* mutable_s();
+
+  // repeated int64 i = 3 [packed = true];
+  int i_size() const;
+  void clear_i();
+  static const int kIFieldNumber = 3;
+  ::google::protobuf::int64 i(int index) const;
+  void set_i(int index, ::google::protobuf::int64 value);
+  void add_i(::google::protobuf::int64 value);
+  const ::google::protobuf::RepeatedField< ::google::protobuf::int64 >&
+      i() const;
+  ::google::protobuf::RepeatedField< ::google::protobuf::int64 >*
+      mutable_i();
+
+  // repeated float f = 4 [packed = true];
+  int f_size() const;
+  void clear_f();
+  static const int kFFieldNumber = 4;
+  float f(int index) const;
+  void set_f(int index, float value);
+  void add_f(float value);
+  const ::google::protobuf::RepeatedField< float >&
+      f() const;
+  ::google::protobuf::RepeatedField< float >*
+      mutable_f();
+
+  // repeated bool b = 5 [packed = true];
+  int b_size() const;
+  void clear_b();
+  static const int kBFieldNumber = 5;
+  bool b(int index) const;
+  void set_b(int index, bool value);
+  void add_b(bool value);
+  const ::google::protobuf::RepeatedField< bool >&
+      b() const;
+  ::google::protobuf::RepeatedField< bool >*
+      mutable_b();
+
+  // repeated .tensorflow.DataType type = 6 [packed = true];
+  int type_size() const;
+  void clear_type();
+  static const int kTypeFieldNumber = 6;
+  ::tensorflow::DataType type(int index) const;
+  void set_type(int index, ::tensorflow::DataType value);
+  void add_type(::tensorflow::DataType value);
+  const ::google::protobuf::RepeatedField<int>& type() const;
+  ::google::protobuf::RepeatedField<int>* mutable_type();
+
+  // repeated .tensorflow.TensorShapeProto shape = 7;
+  int shape_size() const;
+  void clear_shape();
+  static const int kShapeFieldNumber = 7;
+  const ::tensorflow::TensorShapeProto& shape(int index) const;
+  ::tensorflow::TensorShapeProto* mutable_shape(int index);
+  ::tensorflow::TensorShapeProto* add_shape();
+  ::google::protobuf::RepeatedPtrField< ::tensorflow::TensorShapeProto >*
+      mutable_shape();
+  const ::google::protobuf::RepeatedPtrField< ::tensorflow::TensorShapeProto >&
+      shape() const;
+
+  // repeated .tensorflow.TensorProto tensor = 8;
+  int tensor_size() const;
+  void clear_tensor();
+  static const int kTensorFieldNumber = 8;
+  const ::tensorflow::TensorProto& tensor(int index) const;
+  ::tensorflow::TensorProto* mutable_tensor(int index);
+  ::tensorflow::TensorProto* add_tensor();
+  ::google::protobuf::RepeatedPtrField< ::tensorflow::TensorProto >*
+      mutable_tensor();
+  const ::google::protobuf::RepeatedPtrField< ::tensorflow::TensorProto >&
+      tensor() const;
+
+  // @@protoc_insertion_point(class_scope:tensorflow.AttrValue.ListValue)
+ private:
+
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  friend class ::google::protobuf::Arena;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  ::google::protobuf::RepeatedPtrField< ::std::string> s_;
+  ::google::protobuf::RepeatedField< ::google::protobuf::int64 > i_;
+  mutable int _i_cached_byte_size_;
+  ::google::protobuf::RepeatedField< float > f_;
+  mutable int _f_cached_byte_size_;
+  ::google::protobuf::RepeatedField< bool > b_;
+  mutable int _b_cached_byte_size_;
+  ::google::protobuf::RepeatedField<int> type_;
+  mutable int _type_cached_byte_size_;
+  ::google::protobuf::RepeatedPtrField< ::tensorflow::TensorShapeProto > shape_;
+  ::google::protobuf::RepeatedPtrField< ::tensorflow::TensorProto > tensor_;
+  mutable int _cached_size_;
+  friend void  protobuf_InitDefaults_attr_5fvalue_2eproto_impl();
+  friend void  protobuf_AddDesc_attr_5fvalue_2eproto_impl();
+  friend void protobuf_AssignDesc_attr_5fvalue_2eproto();
+  friend void protobuf_ShutdownFile_attr_5fvalue_2eproto();
+
+  void InitAsDefaultInstance();
+};
+extern ::google::protobuf::internal::ExplicitlyConstructed<AttrValue_ListValue> AttrValue_ListValue_default_instance_;
+
+// -------------------------------------------------------------------
+
+class AttrValue : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:tensorflow.AttrValue) */ {
+ public:
+  AttrValue();
+  virtual ~AttrValue();
+
+  AttrValue(const AttrValue& from);
+
+  inline AttrValue& operator=(const AttrValue& from) {
+    CopyFrom(from);
+    return *this;
+  }
+
+  inline ::google::protobuf::Arena* GetArena() const { return GetArenaNoVirtual(); }
+  inline void* GetMaybeArenaPointer() const {
+    return MaybeArenaPtr();
+  }
+  static const ::google::protobuf::Descriptor* descriptor();
+  static const AttrValue& default_instance();
+
+  enum ValueCase {
+    kS = 2,
+    kI = 3,
+    kF = 4,
+    kB = 5,
+    kType = 6,
+    kShape = 7,
+    kTensor = 8,
+    kList = 1,
+    kFunc = 10,
+    kPlaceholder = 9,
+    VALUE_NOT_SET = 0,
+  };
+
+  static const AttrValue* internal_default_instance();
+
+  void UnsafeArenaSwap(AttrValue* other);
+  void Swap(AttrValue* other);
+
+  // implements Message ----------------------------------------------
+
+  inline AttrValue* New() const { return New(NULL); }
+
+  AttrValue* New(::google::protobuf::Arena* arena) const;
+  void CopyFrom(const ::google::protobuf::Message& from);
+  void MergeFrom(const ::google::protobuf::Message& from);
+  void CopyFrom(const AttrValue& from);
+  void MergeFrom(const AttrValue& from);
+  void Clear();
+  bool IsInitialized() const;
+
+  size_t ByteSizeLong() const;
+  bool MergePartialFromCodedStream(
+      ::google::protobuf::io::CodedInputStream* input);
+  void SerializeWithCachedSizes(
+      ::google::protobuf::io::CodedOutputStream* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
+  int GetCachedSize() const { return _cached_size_; }
+  private:
+  void SharedCtor();
+  void SharedDtor();
+  void SetCachedSize(int size) const;
+  void InternalSwap(AttrValue* other);
+  void UnsafeMergeFrom(const AttrValue& from);
+  protected:
+  explicit AttrValue(::google::protobuf::Arena* arena);
+  private:
+  static void ArenaDtor(void* object);
+  inline void RegisterArenaDtor(::google::protobuf::Arena* arena);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
+  public:
+
+  ::google::protobuf::Metadata GetMetadata() const;
+
+  // nested types ----------------------------------------------------
+
+  typedef AttrValue_ListValue ListValue;
+
+  // accessors -------------------------------------------------------
+
+  // optional bytes s = 2;
+  private:
+  bool has_s() const;
+  public:
+  void clear_s();
+  static const int kSFieldNumber = 2;
+  const ::std::string& s() const;
+  void set_s(const ::std::string& value);
+  void set_s(const char* value);
+  void set_s(const void* value, size_t size);
+  ::std::string* mutable_s();
+  ::std::string* release_s();
+  void set_allocated_s(::std::string* s);
+  ::std::string* unsafe_arena_release_s();
+  void unsafe_arena_set_allocated_s(
+      ::std::string* s);
+
+  // optional int64 i = 3;
+  private:
+  bool has_i() const;
+  public:
+  void clear_i();
+  static const int kIFieldNumber = 3;
+  ::google::protobuf::int64 i() const;
+  void set_i(::google::protobuf::int64 value);
+
+  // optional float f = 4;
+  private:
+  bool has_f() const;
+  public:
+  void clear_f();
+  static const int kFFieldNumber = 4;
+  float f() const;
+  void set_f(float value);
+
+  // optional bool b = 5;
+  private:
+  bool has_b() const;
+  public:
+  void clear_b();
+  static const int kBFieldNumber = 5;
+  bool b() const;
+  void set_b(bool value);
+
+  // optional .tensorflow.DataType type = 6;
+  private:
+  bool has_type() const;
+  public:
+  void clear_type();
+  static const int kTypeFieldNumber = 6;
+  ::tensorflow::DataType type() const;
+  void set_type(::tensorflow::DataType value);
+
+  // optional .tensorflow.TensorShapeProto shape = 7;
+  bool has_shape() const;
+  void clear_shape();
+  static const int kShapeFieldNumber = 7;
+  private:
+  void _slow_mutable_shape();
+  void _slow_set_allocated_shape(
+      ::google::protobuf::Arena* message_arena, ::tensorflow::TensorShapeProto** shape);
+  ::tensorflow::TensorShapeProto* _slow_release_shape();
+  public:
+  const ::tensorflow::TensorShapeProto& shape() const;
+  ::tensorflow::TensorShapeProto* mutable_shape();
+  ::tensorflow::TensorShapeProto* release_shape();
+  void set_allocated_shape(::tensorflow::TensorShapeProto* shape);
+  ::tensorflow::TensorShapeProto* unsafe_arena_release_shape();
+  void unsafe_arena_set_allocated_shape(
+      ::tensorflow::TensorShapeProto* shape);
+
+  // optional .tensorflow.TensorProto tensor = 8;
+  bool has_tensor() const;
+  void clear_tensor();
+  static const int kTensorFieldNumber = 8;
+  private:
+  void _slow_mutable_tensor();
+  void _slow_set_allocated_tensor(
+      ::google::protobuf::Arena* message_arena, ::tensorflow::TensorProto** tensor);
+  ::tensorflow::TensorProto* _slow_release_tensor();
+  public:
+  const ::tensorflow::TensorProto& tensor() const;
+  ::tensorflow::TensorProto* mutable_tensor();
+  ::tensorflow::TensorProto* release_tensor();
+  void set_allocated_tensor(::tensorflow::TensorProto* tensor);
+  ::tensorflow::TensorProto* unsafe_arena_release_tensor();
+  void unsafe_arena_set_allocated_tensor(
+      ::tensorflow::TensorProto* tensor);
+
+  // optional .tensorflow.AttrValue.ListValue list = 1;
+  bool has_list() const;
+  void clear_list();
+  static const int kListFieldNumber = 1;
+  private:
+  void _slow_mutable_list();
+  void _slow_set_allocated_list(
+      ::google::protobuf::Arena* message_arena, ::tensorflow::AttrValue_ListValue** list);
+  ::tensorflow::AttrValue_ListValue* _slow_release_list();
+  public:
+  const ::tensorflow::AttrValue_ListValue& list() const;
+  ::tensorflow::AttrValue_ListValue* mutable_list();
+  ::tensorflow::AttrValue_ListValue* release_list();
+  void set_allocated_list(::tensorflow::AttrValue_ListValue* list);
+  ::tensorflow::AttrValue_ListValue* unsafe_arena_release_list();
+  void unsafe_arena_set_allocated_list(
+      ::tensorflow::AttrValue_ListValue* list);
+
+  // optional .tensorflow.NameAttrList func = 10;
+  bool has_func() const;
+  void clear_func();
+  static const int kFuncFieldNumber = 10;
+  private:
+  void _slow_mutable_func();
+  void _slow_set_allocated_func(
+      ::google::protobuf::Arena* message_arena, ::tensorflow::NameAttrList** func);
+  ::tensorflow::NameAttrList* _slow_release_func();
+  public:
+  const ::tensorflow::NameAttrList& func() const;
+  ::tensorflow::NameAttrList* mutable_func();
+  ::tensorflow::NameAttrList* release_func();
+  void set_allocated_func(::tensorflow::NameAttrList* func);
+  ::tensorflow::NameAttrList* unsafe_arena_release_func();
+  void unsafe_arena_set_allocated_func(
+      ::tensorflow::NameAttrList* func);
+
+  // optional string placeholder = 9;
+  private:
+  bool has_placeholder() const;
+  public:
+  void clear_placeholder();
+  static const int kPlaceholderFieldNumber = 9;
+  const ::std::string& placeholder() const;
+  void set_placeholder(const ::std::string& value);
+  void set_placeholder(const char* value);
+  void set_placeholder(const char* value, size_t size);
+  ::std::string* mutable_placeholder();
+  ::std::string* release_placeholder();
+  void set_allocated_placeholder(::std::string* placeholder);
+  ::std::string* unsafe_arena_release_placeholder();
+  void unsafe_arena_set_allocated_placeholder(
+      ::std::string* placeholder);
+
+  ValueCase value_case() const;
+  // @@protoc_insertion_point(class_scope:tensorflow.AttrValue)
+ private:
+  inline void set_has_s();
+  inline void set_has_i();
+  inline void set_has_f();
+  inline void set_has_b();
+  inline void set_has_type();
+  inline void set_has_shape();
+  inline void set_has_tensor();
+  inline void set_has_list();
+  inline void set_has_func();
+  inline void set_has_placeholder();
+
+  inline bool has_value() const;
+  void clear_value();
+  inline void clear_has_value();
+
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  friend class ::google::protobuf::Arena;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  union ValueUnion {
+    ValueUnion() {}
+    ::google::protobuf::internal::ArenaStringPtr s_;
+    ::google::protobuf::int64 i_;
+    float f_;
+    bool b_;
+    int type_;
+    ::tensorflow::TensorShapeProto* shape_;
+    ::tensorflow::TensorProto* tensor_;
+    ::tensorflow::AttrValue_ListValue* list_;
+    ::tensorflow::NameAttrList* func_;
+    ::google::protobuf::internal::ArenaStringPtr placeholder_;
+  } value_;
+  mutable int _cached_size_;
+  ::google::protobuf::uint32 _oneof_case_[1];
+
+  friend void  protobuf_InitDefaults_attr_5fvalue_2eproto_impl();
+  friend void  protobuf_AddDesc_attr_5fvalue_2eproto_impl();
+  friend void protobuf_AssignDesc_attr_5fvalue_2eproto();
+  friend void protobuf_ShutdownFile_attr_5fvalue_2eproto();
+
+  void InitAsDefaultInstance();
+};
+extern ::google::protobuf::internal::ExplicitlyConstructed<AttrValue> AttrValue_default_instance_;
+
+// -------------------------------------------------------------------
+
+class NameAttrList : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:tensorflow.NameAttrList) */ {
+ public:
+  NameAttrList();
+  virtual ~NameAttrList();
+
+  NameAttrList(const NameAttrList& from);
+
+  inline NameAttrList& operator=(const NameAttrList& from) {
+    CopyFrom(from);
+    return *this;
+  }
+
+  inline ::google::protobuf::Arena* GetArena() const { return GetArenaNoVirtual(); }
+  inline void* GetMaybeArenaPointer() const {
+    return MaybeArenaPtr();
+  }
+  static const ::google::protobuf::Descriptor* descriptor();
+  static const NameAttrList& default_instance();
+
+  static const NameAttrList* internal_default_instance();
+
+  void UnsafeArenaSwap(NameAttrList* other);
+  void Swap(NameAttrList* other);
+
+  // implements Message ----------------------------------------------
+
+  inline NameAttrList* New() const { return New(NULL); }
+
+  NameAttrList* New(::google::protobuf::Arena* arena) const;
+  void CopyFrom(const ::google::protobuf::Message& from);
+  void MergeFrom(const ::google::protobuf::Message& from);
+  void CopyFrom(const NameAttrList& from);
+  void MergeFrom(const NameAttrList& from);
+  void Clear();
+  bool IsInitialized() const;
+
+  size_t ByteSizeLong() const;
+  bool MergePartialFromCodedStream(
+      ::google::protobuf::io::CodedInputStream* input);
+  void SerializeWithCachedSizes(
+      ::google::protobuf::io::CodedOutputStream* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
+  int GetCachedSize() const { return _cached_size_; }
+  private:
+  void SharedCtor();
+  void SharedDtor();
+  void SetCachedSize(int size) const;
+  void InternalSwap(NameAttrList* other);
+  void UnsafeMergeFrom(const NameAttrList& from);
+  protected:
+  explicit NameAttrList(::google::protobuf::Arena* arena);
+  private:
+  static void ArenaDtor(void* object);
+  inline void RegisterArenaDtor(::google::protobuf::Arena* arena);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
+  public:
+
+  ::google::protobuf::Metadata GetMetadata() const;
+
+  // nested types ----------------------------------------------------
+
+
+  // accessors -------------------------------------------------------
+
+  // optional string name = 1;
+  void clear_name();
+  static const int kNameFieldNumber = 1;
+  const ::std::string& name() const;
+  void set_name(const ::std::string& value);
+  void set_name(const char* value);
+  void set_name(const char* value, size_t size);
+  ::std::string* mutable_name();
+  ::std::string* release_name();
+  void set_allocated_name(::std::string* name);
+  ::std::string* unsafe_arena_release_name();
+  void unsafe_arena_set_allocated_name(
+      ::std::string* name);
+
+  // map<string, .tensorflow.AttrValue> attr = 2;
+  int attr_size() const;
+  void clear_attr();
+  static const int kAttrFieldNumber = 2;
+  const ::google::protobuf::Map< ::std::string, ::tensorflow::AttrValue >&
+      attr() const;
+  ::google::protobuf::Map< ::std::string, ::tensorflow::AttrValue >*
+      mutable_attr();
+
+  // @@protoc_insertion_point(class_scope:tensorflow.NameAttrList)
+ private:
+
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  friend class ::google::protobuf::Arena;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  typedef ::google::protobuf::internal::MapEntryLite<
+      ::std::string, ::tensorflow::AttrValue,
+      ::google::protobuf::internal::WireFormatLite::TYPE_STRING,
+      ::google::protobuf::internal::WireFormatLite::TYPE_MESSAGE,
+      0 >
+      NameAttrList_AttrEntry;
+  ::google::protobuf::internal::MapField<
+      ::std::string, ::tensorflow::AttrValue,
+      ::google::protobuf::internal::WireFormatLite::TYPE_STRING,
+      ::google::protobuf::internal::WireFormatLite::TYPE_MESSAGE,
+      0 > attr_;
+  ::google::protobuf::internal::ArenaStringPtr name_;
+  mutable int _cached_size_;
+  friend void  protobuf_InitDefaults_attr_5fvalue_2eproto_impl();
+  friend void  protobuf_AddDesc_attr_5fvalue_2eproto_impl();
+  friend void protobuf_AssignDesc_attr_5fvalue_2eproto();
+  friend void protobuf_ShutdownFile_attr_5fvalue_2eproto();
+
+  void InitAsDefaultInstance();
+};
+extern ::google::protobuf::internal::ExplicitlyConstructed<NameAttrList> NameAttrList_default_instance_;
+
+// ===================================================================
+
+
+// ===================================================================
+
+#if !PROTOBUF_INLINE_NOT_IN_HEADERS
+// AttrValue_ListValue
+
+// repeated bytes s = 2;
+inline int AttrValue_ListValue::s_size() const {
+  return s_.size();
+}
+inline void AttrValue_ListValue::clear_s() {
+  s_.Clear();
+}
+inline const ::std::string& AttrValue_ListValue::s(int index) const {
+  // @@protoc_insertion_point(field_get:tensorflow.AttrValue.ListValue.s)
+  return s_.Get(index);
+}
+inline ::std::string* AttrValue_ListValue::mutable_s(int index) {
+  // @@protoc_insertion_point(field_mutable:tensorflow.AttrValue.ListValue.s)
+  return s_.Mutable(index);
+}
+inline void AttrValue_ListValue::set_s(int index, const ::std::string& value) {
+  // @@protoc_insertion_point(field_set:tensorflow.AttrValue.ListValue.s)
+  s_.Mutable(index)->assign(value);
+}
+inline void AttrValue_ListValue::set_s(int index, const char* value) {
+  s_.Mutable(index)->assign(value);
+  // @@protoc_insertion_point(field_set_char:tensorflow.AttrValue.ListValue.s)
+}
+inline void AttrValue_ListValue::set_s(int index, const void* value, size_t size) {
+  s_.Mutable(index)->assign(
+    reinterpret_cast<const char*>(value), size);
+  // @@protoc_insertion_point(field_set_pointer:tensorflow.AttrValue.ListValue.s)
+}
+inline ::std::string* AttrValue_ListValue::add_s() {
+  // @@protoc_insertion_point(field_add_mutable:tensorflow.AttrValue.ListValue.s)
+  return s_.Add();
+}
+inline void AttrValue_ListValue::add_s(const ::std::string& value) {
+  s_.Add()->assign(value);
+  // @@protoc_insertion_point(field_add:tensorflow.AttrValue.ListValue.s)
+}
+inline void AttrValue_ListValue::add_s(const char* value) {
+  s_.Add()->assign(value);
+  // @@protoc_insertion_point(field_add_char:tensorflow.AttrValue.ListValue.s)
+}
+inline void AttrValue_ListValue::add_s(const void* value, size_t size) {
+  s_.Add()->assign(reinterpret_cast<const char*>(value), size);
+  // @@protoc_insertion_point(field_add_pointer:tensorflow.AttrValue.ListValue.s)
+}
+inline const ::google::protobuf::RepeatedPtrField< ::std::string>&
+AttrValue_ListValue::s() const {
+  // @@protoc_insertion_point(field_list:tensorflow.AttrValue.ListValue.s)
+  return s_;
+}
+inline ::google::protobuf::RepeatedPtrField< ::std::string>*
+AttrValue_ListValue::mutable_s() {
+  // @@protoc_insertion_point(field_mutable_list:tensorflow.AttrValue.ListValue.s)
+  return &s_;
+}
+
+// repeated int64 i = 3 [packed = true];
+inline int AttrValue_ListValue::i_size() const {
+  return i_.size();
+}
+inline void AttrValue_ListValue::clear_i() {
+  i_.Clear();
+}
+inline ::google::protobuf::int64 AttrValue_ListValue::i(int index) const {
+  // @@protoc_insertion_point(field_get:tensorflow.AttrValue.ListValue.i)
+  return i_.Get(index);
+}
+inline void AttrValue_ListValue::set_i(int index, ::google::protobuf::int64 value) {
+  i_.Set(index, value);
+  // @@protoc_insertion_point(field_set:tensorflow.AttrValue.ListValue.i)
+}
+inline void AttrValue_ListValue::add_i(::google::protobuf::int64 value) {
+  i_.Add(value);
+  // @@protoc_insertion_point(field_add:tensorflow.AttrValue.ListValue.i)
+}
+inline const ::google::protobuf::RepeatedField< ::google::protobuf::int64 >&
+AttrValue_ListValue::i() const {
+  // @@protoc_insertion_point(field_list:tensorflow.AttrValue.ListValue.i)
+  return i_;
+}
+inline ::google::protobuf::RepeatedField< ::google::protobuf::int64 >*
+AttrValue_ListValue::mutable_i() {
+  // @@protoc_insertion_point(field_mutable_list:tensorflow.AttrValue.ListValue.i)
+  return &i_;
+}
+
+// repeated float f = 4 [packed = true];
+inline int AttrValue_ListValue::f_size() const {
+  return f_.size();
+}
+inline void AttrValue_ListValue::clear_f() {
+  f_.Clear();
+}
+inline float AttrValue_ListValue::f(int index) const {
+  // @@protoc_insertion_point(field_get:tensorflow.AttrValue.ListValue.f)
+  return f_.Get(index);
+}
+inline void AttrValue_ListValue::set_f(int index, float value) {
+  f_.Set(index, value);
+  // @@protoc_insertion_point(field_set:tensorflow.AttrValue.ListValue.f)
+}
+inline void AttrValue_ListValue::add_f(float value) {
+  f_.Add(value);
+  // @@protoc_insertion_point(field_add:tensorflow.AttrValue.ListValue.f)
+}
+inline const ::google::protobuf::RepeatedField< float >&
+AttrValue_ListValue::f() const {
+  // @@protoc_insertion_point(field_list:tensorflow.AttrValue.ListValue.f)
+  return f_;
+}
+inline ::google::protobuf::RepeatedField< float >*
+AttrValue_ListValue::mutable_f() {
+  // @@protoc_insertion_point(field_mutable_list:tensorflow.AttrValue.ListValue.f)
+  return &f_;
+}
+
+// repeated bool b = 5 [packed = true];
+inline int AttrValue_ListValue::b_size() const {
+  return b_.size();
+}
+inline void AttrValue_ListValue::clear_b() {
+  b_.Clear();
+}
+inline bool AttrValue_ListValue::b(int index) const {
+  // @@protoc_insertion_point(field_get:tensorflow.AttrValue.ListValue.b)
+  return b_.Get(index);
+}
+inline void AttrValue_ListValue::set_b(int index, bool value) {
+  b_.Set(index, value);
+  // @@protoc_insertion_point(field_set:tensorflow.AttrValue.ListValue.b)
+}
+inline void AttrValue_ListValue::add_b(bool value) {
+  b_.Add(value);
+  // @@protoc_insertion_point(field_add:tensorflow.AttrValue.ListValue.b)
+}
+inline const ::google::protobuf::RepeatedField< bool >&
+AttrValue_ListValue::b() const {
+  // @@protoc_insertion_point(field_list:tensorflow.AttrValue.ListValue.b)
+  return b_;
+}
+inline ::google::protobuf::RepeatedField< bool >*
+AttrValue_ListValue::mutable_b() {
+  // @@protoc_insertion_point(field_mutable_list:tensorflow.AttrValue.ListValue.b)
+  return &b_;
+}
+
+// repeated .tensorflow.DataType type = 6 [packed = true];
+inline int AttrValue_ListValue::type_size() const {
+  return type_.size();
+}
+inline void AttrValue_ListValue::clear_type() {
+  type_.Clear();
+}
+inline ::tensorflow::DataType AttrValue_ListValue::type(int index) const {
+  // @@protoc_insertion_point(field_get:tensorflow.AttrValue.ListValue.type)
+  return static_cast< ::tensorflow::DataType >(type_.Get(index));
+}
+inline void AttrValue_ListValue::set_type(int index, ::tensorflow::DataType value) {
+  type_.Set(index, value);
+  // @@protoc_insertion_point(field_set:tensorflow.AttrValue.ListValue.type)
+}
+inline void AttrValue_ListValue::add_type(::tensorflow::DataType value) {
+  type_.Add(value);
+  // @@protoc_insertion_point(field_add:tensorflow.AttrValue.ListValue.type)
+}
+inline const ::google::protobuf::RepeatedField<int>&
+AttrValue_ListValue::type() const {
+  // @@protoc_insertion_point(field_list:tensorflow.AttrValue.ListValue.type)
+  return type_;
+}
+inline ::google::protobuf::RepeatedField<int>*
+AttrValue_ListValue::mutable_type() {
+  // @@protoc_insertion_point(field_mutable_list:tensorflow.AttrValue.ListValue.type)
+  return &type_;
+}
+
+// repeated .tensorflow.TensorShapeProto shape = 7;
+inline int AttrValue_ListValue::shape_size() const {
+  return shape_.size();
+}
+inline void AttrValue_ListValue::clear_shape() {
+  shape_.Clear();
+}
+inline const ::tensorflow::TensorShapeProto& AttrValue_ListValue::shape(int index) const {
+  // @@protoc_insertion_point(field_get:tensorflow.AttrValue.ListValue.shape)
+  return shape_.Get(index);
+}
+inline ::tensorflow::TensorShapeProto* AttrValue_ListValue::mutable_shape(int index) {
+  // @@protoc_insertion_point(field_mutable:tensorflow.AttrValue.ListValue.shape)
+  return shape_.Mutable(index);
+}
+inline ::tensorflow::TensorShapeProto* AttrValue_ListValue::add_shape() {
+  // @@protoc_insertion_point(field_add:tensorflow.AttrValue.ListValue.shape)
+  return shape_.Add();
+}
+inline ::google::protobuf::RepeatedPtrField< ::tensorflow::TensorShapeProto >*
+AttrValue_ListValue::mutable_shape() {
+  // @@protoc_insertion_point(field_mutable_list:tensorflow.AttrValue.ListValue.shape)
+  return &shape_;
+}
+inline const ::google::protobuf::RepeatedPtrField< ::tensorflow::TensorShapeProto >&
+AttrValue_ListValue::shape() const {
+  // @@protoc_insertion_point(field_list:tensorflow.AttrValue.ListValue.shape)
+  return shape_;
+}
+
+// repeated .tensorflow.TensorProto tensor = 8;
+inline int AttrValue_ListValue::tensor_size() const {
+  return tensor_.size();
+}
+inline void AttrValue_ListValue::clear_tensor() {
+  tensor_.Clear();
+}
+inline const ::tensorflow::TensorProto& AttrValue_ListValue::tensor(int index) const {
+  // @@protoc_insertion_point(field_get:tensorflow.AttrValue.ListValue.tensor)
+  return tensor_.Get(index);
+}
+inline ::tensorflow::TensorProto* AttrValue_ListValue::mutable_tensor(int index) {
+  // @@protoc_insertion_point(field_mutable:tensorflow.AttrValue.ListValue.tensor)
+  return tensor_.Mutable(index);
+}
+inline ::tensorflow::TensorProto* AttrValue_ListValue::add_tensor() {
+  // @@protoc_insertion_point(field_add:tensorflow.AttrValue.ListValue.tensor)
+  return tensor_.Add();
+}
+inline ::google::protobuf::RepeatedPtrField< ::tensorflow::TensorProto >*
+AttrValue_ListValue::mutable_tensor() {
+  // @@protoc_insertion_point(field_mutable_list:tensorflow.AttrValue.ListValue.tensor)
+  return &tensor_;
+}
+inline const ::google::protobuf::RepeatedPtrField< ::tensorflow::TensorProto >&
+AttrValue_ListValue::tensor() const {
+  // @@protoc_insertion_point(field_list:tensorflow.AttrValue.ListValue.tensor)
+  return tensor_;
+}
+
+inline const AttrValue_ListValue* AttrValue_ListValue::internal_default_instance() {
+  return &AttrValue_ListValue_default_instance_.get();
+}
+// -------------------------------------------------------------------
+
+// AttrValue
+
+// optional bytes s = 2;
+inline bool AttrValue::has_s() const {
+  return value_case() == kS;
+}
+inline void AttrValue::set_has_s() {
+  _oneof_case_[0] = kS;
+}
+inline void AttrValue::clear_s() {
+  if (has_s()) {
+    value_.s_.Destroy(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+        GetArenaNoVirtual());
+    clear_has_value();
+  }
+}
+inline const ::std::string& AttrValue::s() const {
+  // @@protoc_insertion_point(field_get:tensorflow.AttrValue.s)
+  if (has_s()) {
+    return value_.s_.Get(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  }
+  return *&::google::protobuf::internal::GetEmptyStringAlreadyInited();
+}
+inline void AttrValue::set_s(const ::std::string& value) {
+  if (!has_s()) {
+    clear_value();
+    set_has_s();
+    value_.s_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  }
+  value_.s_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value,
+      GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set:tensorflow.AttrValue.s)
+}
+inline void AttrValue::set_s(const char* value) {
+  if (!has_s()) {
+    clear_value();
+    set_has_s();
+    value_.s_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  }
+  value_.s_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(value), GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_char:tensorflow.AttrValue.s)
+}
+inline void AttrValue::set_s(const void* value,
+                             size_t size) {
+  if (!has_s()) {
+    clear_value();
+    set_has_s();
+    value_.s_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  }
+  value_.s_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(
+      reinterpret_cast<const char*>(value), size),
+      GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_pointer:tensorflow.AttrValue.s)
+}
+inline ::std::string* AttrValue::mutable_s() {
+  if (!has_s()) {
+    clear_value();
+    set_has_s();
+    value_.s_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  }
+  return value_.s_.Mutable(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_mutable:tensorflow.AttrValue.s)
+}
+inline ::std::string* AttrValue::release_s() {
+  // @@protoc_insertion_point(field_release:tensorflow.AttrValue.s)
+  if (has_s()) {
+    clear_has_value();
+    return value_.s_.Release(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+        GetArenaNoVirtual());
+  } else {
+    return NULL;
+  }
+}
+inline ::std::string* AttrValue::unsafe_arena_release_s() {
+  // @@protoc_insertion_point(field_unsafe_arena_release:tensorflow.AttrValue.s)
+  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);
+  if (has_s()) {
+    clear_has_value();
+    return value_.s_.UnsafeArenaRelease(
+        &::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+  } else {
+    return NULL;
+  }
+}
+inline void AttrValue::set_allocated_s(::std::string* s) {
+  if (!has_s()) {
+    value_.s_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  }
+  clear_value();
+  if (s != NULL) {
+    set_has_s();
+    value_.s_.SetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), s,
+        GetArenaNoVirtual());
+  }
+  // @@protoc_insertion_point(field_set_allocated:tensorflow.AttrValue.s)
+}
+inline void AttrValue::unsafe_arena_set_allocated_s(::std::string* s) {
+  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);
+  if (!has_s()) {
+    value_.s_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  }
+  clear_value();
+  if (s) {
+    set_has_s();
+    value_.s_.UnsafeArenaSetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), s, GetArenaNoVirtual());
+  }
+  // @@protoc_insertion_point(field_unsafe_arena_set_allocated:tensorflow.AttrValue.s)
+}
+
+// optional int64 i = 3;
+inline bool AttrValue::has_i() const {
+  return value_case() == kI;
+}
+inline void AttrValue::set_has_i() {
+  _oneof_case_[0] = kI;
+}
+inline void AttrValue::clear_i() {
+  if (has_i()) {
+    value_.i_ = GOOGLE_LONGLONG(0);
+    clear_has_value();
+  }
+}
+inline ::google::protobuf::int64 AttrValue::i() const {
+  // @@protoc_insertion_point(field_get:tensorflow.AttrValue.i)
+  if (has_i()) {
+    return value_.i_;
+  }
+  return GOOGLE_LONGLONG(0);
+}
+inline void AttrValue::set_i(::google::protobuf::int64 value) {
+  if (!has_i()) {
+    clear_value();
+    set_has_i();
+  }
+  value_.i_ = value;
+  // @@protoc_insertion_point(field_set:tensorflow.AttrValue.i)
+}
+
+// optional float f = 4;
+inline bool AttrValue::has_f() const {
+  return value_case() == kF;
+}
+inline void AttrValue::set_has_f() {
+  _oneof_case_[0] = kF;
+}
+inline void AttrValue::clear_f() {
+  if (has_f()) {
+    value_.f_ = 0;
+    clear_has_value();
+  }
+}
+inline float AttrValue::f() const {
+  // @@protoc_insertion_point(field_get:tensorflow.AttrValue.f)
+  if (has_f()) {
+    return value_.f_;
+  }
+  return 0;
+}
+inline void AttrValue::set_f(float value) {
+  if (!has_f()) {
+    clear_value();
+    set_has_f();
+  }
+  value_.f_ = value;
+  // @@protoc_insertion_point(field_set:tensorflow.AttrValue.f)
+}
+
+// optional bool b = 5;
+inline bool AttrValue::has_b() const {
+  return value_case() == kB;
+}
+inline void AttrValue::set_has_b() {
+  _oneof_case_[0] = kB;
+}
+inline void AttrValue::clear_b() {
+  if (has_b()) {
+    value_.b_ = false;
+    clear_has_value();
+  }
+}
+inline bool AttrValue::b() const {
+  // @@protoc_insertion_point(field_get:tensorflow.AttrValue.b)
+  if (has_b()) {
+    return value_.b_;
+  }
+  return false;
+}
+inline void AttrValue::set_b(bool value) {
+  if (!has_b()) {
+    clear_value();
+    set_has_b();
+  }
+  value_.b_ = value;
+  // @@protoc_insertion_point(field_set:tensorflow.AttrValue.b)
+}
+
+// optional .tensorflow.DataType type = 6;
+inline bool AttrValue::has_type() const {
+  return value_case() == kType;
+}
+inline void AttrValue::set_has_type() {
+  _oneof_case_[0] = kType;
+}
+inline void AttrValue::clear_type() {
+  if (has_type()) {
+    value_.type_ = 0;
+    clear_has_value();
+  }
+}
+inline ::tensorflow::DataType AttrValue::type() const {
+  // @@protoc_insertion_point(field_get:tensorflow.AttrValue.type)
+  if (has_type()) {
+    return static_cast< ::tensorflow::DataType >(value_.type_);
+  }
+  return static_cast< ::tensorflow::DataType >(0);
+}
+inline void AttrValue::set_type(::tensorflow::DataType value) {
+  if (!has_type()) {
+    clear_value();
+    set_has_type();
+  }
+  value_.type_ = value;
+  // @@protoc_insertion_point(field_set:tensorflow.AttrValue.type)
+}
+
+// optional .tensorflow.TensorShapeProto shape = 7;
+inline bool AttrValue::has_shape() const {
+  return value_case() == kShape;
+}
+inline void AttrValue::set_has_shape() {
+  _oneof_case_[0] = kShape;
+}
+inline void AttrValue::clear_shape() {
+  if (has_shape()) {
+    if (GetArenaNoVirtual() == NULL) {
+      delete value_.shape_;
+    }
+    clear_has_value();
+  }
+}
+inline  const ::tensorflow::TensorShapeProto& AttrValue::shape() const {
+  // @@protoc_insertion_point(field_get:tensorflow.AttrValue.shape)
+  return has_shape()
+      ? *value_.shape_
+      : ::tensorflow::TensorShapeProto::default_instance();
+}
+inline ::tensorflow::TensorShapeProto* AttrValue::mutable_shape() {
+  if (!has_shape()) {
+    clear_value();
+    set_has_shape();
+    value_.shape_ =
+      ::google::protobuf::Arena::CreateMessage< ::tensorflow::TensorShapeProto >(
+      GetArenaNoVirtual());
+  }
+  // @@protoc_insertion_point(field_mutable:tensorflow.AttrValue.shape)
+  return value_.shape_;
+}
+inline ::tensorflow::TensorShapeProto* AttrValue::release_shape() {
+  // @@protoc_insertion_point(field_release:tensorflow.AttrValue.shape)
+  if (has_shape()) {
+    clear_has_value();
+    if (GetArenaNoVirtual() != NULL) {
+      ::tensorflow::TensorShapeProto* temp = new ::tensorflow::TensorShapeProto(*value_.shape_);
+      value_.shape_ = NULL;
+      return temp;
+    } else {
+      ::tensorflow::TensorShapeProto* temp = value_.shape_;
+      value_.shape_ = NULL;
+      return temp;
+    }
+  } else {
+    return NULL;
+  }
+}
+inline void AttrValue::set_allocated_shape(::tensorflow::TensorShapeProto* shape) {
+  clear_value();
+  if (shape) {
+    if (GetArenaNoVirtual() != NULL &&
+        ::google::protobuf::Arena::GetArena(shape) == NULL) {
+      GetArenaNoVirtual()->Own(shape);
+    } else if (GetArenaNoVirtual() !=
+               ::google::protobuf::Arena::GetArena(shape)) {
+      ::tensorflow::TensorShapeProto* new_shape =
+          ::google::protobuf::Arena::CreateMessage< ::tensorflow::TensorShapeProto >(
+          GetArenaNoVirtual());
+      new_shape->CopyFrom(*shape);
+      shape = new_shape;
+    }
+    set_has_shape();
+    value_.shape_ = shape;
+  }
+  // @@protoc_insertion_point(field_set_allocated:tensorflow.AttrValue.shape)
+}
+inline  ::tensorflow::TensorShapeProto* AttrValue::unsafe_arena_release_shape() {
+  // @@protoc_insertion_point(field_unsafe_arena_release:tensorflow.AttrValue.shape)
+  if (has_shape()) {
+    clear_has_value();
+    ::tensorflow::TensorShapeProto* temp = value_.shape_;
+    value_.shape_ = NULL;
+    return temp;
+  } else {
+    return NULL;
+  }
+}
+inline  void AttrValue::unsafe_arena_set_allocated_shape(::tensorflow::TensorShapeProto* shape) {
+  clear_value();
+  if (shape) {
+    set_has_shape();
+    value_.shape_ = shape;
+  }
+  // @@protoc_insertion_point(field_unsafe_arena_set_allocated:tensorflow.AttrValue.shape)
+}
+
+// optional .tensorflow.TensorProto tensor = 8;
+inline bool AttrValue::has_tensor() const {
+  return value_case() == kTensor;
+}
+inline void AttrValue::set_has_tensor() {
+  _oneof_case_[0] = kTensor;
+}
+inline void AttrValue::clear_tensor() {
+  if (has_tensor()) {
+    if (GetArenaNoVirtual() == NULL) {
+      delete value_.tensor_;
+    }
+    clear_has_value();
+  }
+}
+inline  const ::tensorflow::TensorProto& AttrValue::tensor() const {
+  // @@protoc_insertion_point(field_get:tensorflow.AttrValue.tensor)
+  return has_tensor()
+      ? *value_.tensor_
+      : ::tensorflow::TensorProto::default_instance();
+}
+inline ::tensorflow::TensorProto* AttrValue::mutable_tensor() {
+  if (!has_tensor()) {
+    clear_value();
+    set_has_tensor();
+    value_.tensor_ =
+      ::google::protobuf::Arena::CreateMessage< ::tensorflow::TensorProto >(
+      GetArenaNoVirtual());
+  }
+  // @@protoc_insertion_point(field_mutable:tensorflow.AttrValue.tensor)
+  return value_.tensor_;
+}
+inline ::tensorflow::TensorProto* AttrValue::release_tensor() {
+  // @@protoc_insertion_point(field_release:tensorflow.AttrValue.tensor)
+  if (has_tensor()) {
+    clear_has_value();
+    if (GetArenaNoVirtual() != NULL) {
+      ::tensorflow::TensorProto* temp = new ::tensorflow::TensorProto(*value_.tensor_);
+      value_.tensor_ = NULL;
+      return temp;
+    } else {
+      ::tensorflow::TensorProto* temp = value_.tensor_;
+      value_.tensor_ = NULL;
+      return temp;
+    }
+  } else {
+    return NULL;
+  }
+}
+inline void AttrValue::set_allocated_tensor(::tensorflow::TensorProto* tensor) {
+  clear_value();
+  if (tensor) {
+    if (GetArenaNoVirtual() != NULL &&
+        ::google::protobuf::Arena::GetArena(tensor) == NULL) {
+      GetArenaNoVirtual()->Own(tensor);
+    } else if (GetArenaNoVirtual() !=
+               ::google::protobuf::Arena::GetArena(tensor)) {
+      ::tensorflow::TensorProto* new_tensor =
+          ::google::protobuf::Arena::CreateMessage< ::tensorflow::TensorProto >(
+          GetArenaNoVirtual());
+      new_tensor->CopyFrom(*tensor);
+      tensor = new_tensor;
+    }
+    set_has_tensor();
+    value_.tensor_ = tensor;
+  }
+  // @@protoc_insertion_point(field_set_allocated:tensorflow.AttrValue.tensor)
+}
+inline  ::tensorflow::TensorProto* AttrValue::unsafe_arena_release_tensor() {
+  // @@protoc_insertion_point(field_unsafe_arena_release:tensorflow.AttrValue.tensor)
+  if (has_tensor()) {
+    clear_has_value();
+    ::tensorflow::TensorProto* temp = value_.tensor_;
+    value_.tensor_ = NULL;
+    return temp;
+  } else {
+    return NULL;
+  }
+}
+inline  void AttrValue::unsafe_arena_set_allocated_tensor(::tensorflow::TensorProto* tensor) {
+  clear_value();
+  if (tensor) {
+    set_has_tensor();
+    value_.tensor_ = tensor;
+  }
+  // @@protoc_insertion_point(field_unsafe_arena_set_allocated:tensorflow.AttrValue.tensor)
+}
+
+// optional .tensorflow.AttrValue.ListValue list = 1;
+inline bool AttrValue::has_list() const {
+  return value_case() == kList;
+}
+inline void AttrValue::set_has_list() {
+  _oneof_case_[0] = kList;
+}
+inline void AttrValue::clear_list() {
+  if (has_list()) {
+    if (GetArenaNoVirtual() == NULL) {
+      delete value_.list_;
+    }
+    clear_has_value();
+  }
+}
+inline  const ::tensorflow::AttrValue_ListValue& AttrValue::list() const {
+  // @@protoc_insertion_point(field_get:tensorflow.AttrValue.list)
+  return has_list()
+      ? *value_.list_
+      : ::tensorflow::AttrValue_ListValue::default_instance();
+}
+inline ::tensorflow::AttrValue_ListValue* AttrValue::mutable_list() {
+  if (!has_list()) {
+    clear_value();
+    set_has_list();
+    value_.list_ =
+      ::google::protobuf::Arena::CreateMessage< ::tensorflow::AttrValue_ListValue >(
+      GetArenaNoVirtual());
+  }
+  // @@protoc_insertion_point(field_mutable:tensorflow.AttrValue.list)
+  return value_.list_;
+}
+inline ::tensorflow::AttrValue_ListValue* AttrValue::release_list() {
+  // @@protoc_insertion_point(field_release:tensorflow.AttrValue.list)
+  if (has_list()) {
+    clear_has_value();
+    if (GetArenaNoVirtual() != NULL) {
+      ::tensorflow::AttrValue_ListValue* temp = new ::tensorflow::AttrValue_ListValue(*value_.list_);
+      value_.list_ = NULL;
+      return temp;
+    } else {
+      ::tensorflow::AttrValue_ListValue* temp = value_.list_;
+      value_.list_ = NULL;
+      return temp;
+    }
+  } else {
+    return NULL;
+  }
+}
+inline void AttrValue::set_allocated_list(::tensorflow::AttrValue_ListValue* list) {
+  clear_value();
+  if (list) {
+    if (GetArenaNoVirtual() != NULL &&
+        ::google::protobuf::Arena::GetArena(list) == NULL) {
+      GetArenaNoVirtual()->Own(list);
+    } else if (GetArenaNoVirtual() !=
+               ::google::protobuf::Arena::GetArena(list)) {
+      ::tensorflow::AttrValue_ListValue* new_list =
+          ::google::protobuf::Arena::CreateMessage< ::tensorflow::AttrValue_ListValue >(
+          GetArenaNoVirtual());
+      new_list->CopyFrom(*list);
+      list = new_list;
+    }
+    set_has_list();
+    value_.list_ = list;
+  }
+  // @@protoc_insertion_point(field_set_allocated:tensorflow.AttrValue.list)
+}
+inline  ::tensorflow::AttrValue_ListValue* AttrValue::unsafe_arena_release_list() {
+  // @@protoc_insertion_point(field_unsafe_arena_release:tensorflow.AttrValue.list)
+  if (has_list()) {
+    clear_has_value();
+    ::tensorflow::AttrValue_ListValue* temp = value_.list_;
+    value_.list_ = NULL;
+    return temp;
+  } else {
+    return NULL;
+  }
+}
+inline  void AttrValue::unsafe_arena_set_allocated_list(::tensorflow::AttrValue_ListValue* list) {
+  clear_value();
+  if (list) {
+    set_has_list();
+    value_.list_ = list;
+  }
+  // @@protoc_insertion_point(field_unsafe_arena_set_allocated:tensorflow.AttrValue.list)
+}
+
+// optional .tensorflow.NameAttrList func = 10;
+inline bool AttrValue::has_func() const {
+  return value_case() == kFunc;
+}
+inline void AttrValue::set_has_func() {
+  _oneof_case_[0] = kFunc;
+}
+inline void AttrValue::clear_func() {
+  if (has_func()) {
+    if (GetArenaNoVirtual() == NULL) {
+      delete value_.func_;
+    }
+    clear_has_value();
+  }
+}
+inline  const ::tensorflow::NameAttrList& AttrValue::func() const {
+  // @@protoc_insertion_point(field_get:tensorflow.AttrValue.func)
+  return has_func()
+      ? *value_.func_
+      : ::tensorflow::NameAttrList::default_instance();
+}
+inline ::tensorflow::NameAttrList* AttrValue::mutable_func() {
+  if (!has_func()) {
+    clear_value();
+    set_has_func();
+    value_.func_ =
+      ::google::protobuf::Arena::CreateMessage< ::tensorflow::NameAttrList >(
+      GetArenaNoVirtual());
+  }
+  // @@protoc_insertion_point(field_mutable:tensorflow.AttrValue.func)
+  return value_.func_;
+}
+inline ::tensorflow::NameAttrList* AttrValue::release_func() {
+  // @@protoc_insertion_point(field_release:tensorflow.AttrValue.func)
+  if (has_func()) {
+    clear_has_value();
+    if (GetArenaNoVirtual() != NULL) {
+      ::tensorflow::NameAttrList* temp = new ::tensorflow::NameAttrList(*value_.func_);
+      value_.func_ = NULL;
+      return temp;
+    } else {
+      ::tensorflow::NameAttrList* temp = value_.func_;
+      value_.func_ = NULL;
+      return temp;
+    }
+  } else {
+    return NULL;
+  }
+}
+inline void AttrValue::set_allocated_func(::tensorflow::NameAttrList* func) {
+  clear_value();
+  if (func) {
+    if (GetArenaNoVirtual() != NULL &&
+        ::google::protobuf::Arena::GetArena(func) == NULL) {
+      GetArenaNoVirtual()->Own(func);
+    } else if (GetArenaNoVirtual() !=
+               ::google::protobuf::Arena::GetArena(func)) {
+      ::tensorflow::NameAttrList* new_func =
+          ::google::protobuf::Arena::CreateMessage< ::tensorflow::NameAttrList >(
+          GetArenaNoVirtual());
+      new_func->CopyFrom(*func);
+      func = new_func;
+    }
+    set_has_func();
+    value_.func_ = func;
+  }
+  // @@protoc_insertion_point(field_set_allocated:tensorflow.AttrValue.func)
+}
+inline  ::tensorflow::NameAttrList* AttrValue::unsafe_arena_release_func() {
+  // @@protoc_insertion_point(field_unsafe_arena_release:tensorflow.AttrValue.func)
+  if (has_func()) {
+    clear_has_value();
+    ::tensorflow::NameAttrList* temp = value_.func_;
+    value_.func_ = NULL;
+    return temp;
+  } else {
+    return NULL;
+  }
+}
+inline  void AttrValue::unsafe_arena_set_allocated_func(::tensorflow::NameAttrList* func) {
+  clear_value();
+  if (func) {
+    set_has_func();
+    value_.func_ = func;
+  }
+  // @@protoc_insertion_point(field_unsafe_arena_set_allocated:tensorflow.AttrValue.func)
+}
+
+// optional string placeholder = 9;
+inline bool AttrValue::has_placeholder() const {
+  return value_case() == kPlaceholder;
+}
+inline void AttrValue::set_has_placeholder() {
+  _oneof_case_[0] = kPlaceholder;
+}
+inline void AttrValue::clear_placeholder() {
+  if (has_placeholder()) {
+    value_.placeholder_.Destroy(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+        GetArenaNoVirtual());
+    clear_has_value();
+  }
+}
+inline const ::std::string& AttrValue::placeholder() const {
+  // @@protoc_insertion_point(field_get:tensorflow.AttrValue.placeholder)
+  if (has_placeholder()) {
+    return value_.placeholder_.Get(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  }
+  return *&::google::protobuf::internal::GetEmptyStringAlreadyInited();
+}
+inline void AttrValue::set_placeholder(const ::std::string& value) {
+  if (!has_placeholder()) {
+    clear_value();
+    set_has_placeholder();
+    value_.placeholder_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  }
+  value_.placeholder_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value,
+      GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set:tensorflow.AttrValue.placeholder)
+}
+inline void AttrValue::set_placeholder(const char* value) {
+  if (!has_placeholder()) {
+    clear_value();
+    set_has_placeholder();
+    value_.placeholder_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  }
+  value_.placeholder_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      ::std::string(value), GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_char:tensorflow.AttrValue.placeholder)
+}
+inline void AttrValue::set_placeholder(const char* value,
+                             size_t size) {
+  if (!has_placeholder()) {
+    clear_value();
+    set_has_placeholder();
+    value_.placeholder_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  }
+  value_.placeholder_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(
+      reinterpret_cast<const char*>(value), size),
+      GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_pointer:tensorflow.AttrValue.placeholder)
+}
+inline ::std::string* AttrValue::mutable_placeholder() {
+  if (!has_placeholder()) {
+    clear_value();
+    set_has_placeholder();
+    value_.placeholder_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  }
+  return value_.placeholder_.Mutable(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_mutable:tensorflow.AttrValue.placeholder)
+}
+inline ::std::string* AttrValue::release_placeholder() {
+  // @@protoc_insertion_point(field_release:tensorflow.AttrValue.placeholder)
+  if (has_placeholder()) {
+    clear_has_value();
+    return value_.placeholder_.Release(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+        GetArenaNoVirtual());
+  } else {
+    return NULL;
+  }
+}
+inline ::std::string* AttrValue::unsafe_arena_release_placeholder() {
+  // @@protoc_insertion_point(field_unsafe_arena_release:tensorflow.AttrValue.placeholder)
+  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);
+  if (has_placeholder()) {
+    clear_has_value();
+    return value_.placeholder_.UnsafeArenaRelease(
+        &::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+  } else {
+    return NULL;
+  }
+}
+inline void AttrValue::set_allocated_placeholder(::std::string* placeholder) {
+  if (!has_placeholder()) {
+    value_.placeholder_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  }
+  clear_value();
+  if (placeholder != NULL) {
+    set_has_placeholder();
+    value_.placeholder_.SetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), placeholder,
+        GetArenaNoVirtual());
+  }
+  // @@protoc_insertion_point(field_set_allocated:tensorflow.AttrValue.placeholder)
+}
+inline void AttrValue::unsafe_arena_set_allocated_placeholder(::std::string* placeholder) {
+  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);
+  if (!has_placeholder()) {
+    value_.placeholder_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  }
+  clear_value();
+  if (placeholder) {
+    set_has_placeholder();
+    value_.placeholder_.UnsafeArenaSetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), placeholder, GetArenaNoVirtual());
+  }
+  // @@protoc_insertion_point(field_unsafe_arena_set_allocated:tensorflow.AttrValue.placeholder)
+}
+
+inline bool AttrValue::has_value() const {
+  return value_case() != VALUE_NOT_SET;
+}
+inline void AttrValue::clear_has_value() {
+  _oneof_case_[0] = VALUE_NOT_SET;
+}
+inline AttrValue::ValueCase AttrValue::value_case() const {
+  return AttrValue::ValueCase(_oneof_case_[0]);
+}
+inline const AttrValue* AttrValue::internal_default_instance() {
+  return &AttrValue_default_instance_.get();
+}
+// -------------------------------------------------------------------
+
+// NameAttrList
+
+// optional string name = 1;
+inline void NameAttrList::clear_name() {
+  name_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+inline const ::std::string& NameAttrList::name() const {
+  // @@protoc_insertion_point(field_get:tensorflow.NameAttrList.name)
+  return name_.Get(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void NameAttrList::set_name(const ::std::string& value) {
+
+  name_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value, GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set:tensorflow.NameAttrList.name)
+}
+inline void NameAttrList::set_name(const char* value) {
+
+  name_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value),
+              GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_char:tensorflow.NameAttrList.name)
+}
+inline void NameAttrList::set_name(const char* value,
+    size_t size) {
+
+  name_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(
+      reinterpret_cast<const char*>(value), size), GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_pointer:tensorflow.NameAttrList.name)
+}
+inline ::std::string* NameAttrList::mutable_name() {
+
+  // @@protoc_insertion_point(field_mutable:tensorflow.NameAttrList.name)
+  return name_.Mutable(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+inline ::std::string* NameAttrList::release_name() {
+  // @@protoc_insertion_point(field_release:tensorflow.NameAttrList.name)
+
+  return name_.Release(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+inline ::std::string* NameAttrList::unsafe_arena_release_name() {
+  // @@protoc_insertion_point(field_unsafe_arena_release:tensorflow.NameAttrList.name)
+  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);
+
+  return name_.UnsafeArenaRelease(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      GetArenaNoVirtual());
+}
+inline void NameAttrList::set_allocated_name(::std::string* name) {
+  if (name != NULL) {
+
+  } else {
+
+  }
+  name_.SetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), name,
+      GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_allocated:tensorflow.NameAttrList.name)
+}
+inline void NameAttrList::unsafe_arena_set_allocated_name(
+    ::std::string* name) {
+  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);
+  if (name != NULL) {
+
+  } else {
+
+  }
+  name_.UnsafeArenaSetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      name, GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_unsafe_arena_set_allocated:tensorflow.NameAttrList.name)
+}
+
+// map<string, .tensorflow.AttrValue> attr = 2;
+inline int NameAttrList::attr_size() const {
+  return attr_.size();
+}
+inline void NameAttrList::clear_attr() {
+  attr_.Clear();
+}
+inline const ::google::protobuf::Map< ::std::string, ::tensorflow::AttrValue >&
+NameAttrList::attr() const {
+  // @@protoc_insertion_point(field_map:tensorflow.NameAttrList.attr)
+  return attr_.GetMap();
+}
+inline ::google::protobuf::Map< ::std::string, ::tensorflow::AttrValue >*
+NameAttrList::mutable_attr() {
+  // @@protoc_insertion_point(field_mutable_map:tensorflow.NameAttrList.attr)
+  return attr_.MutableMap();
+}
+
+inline const NameAttrList* NameAttrList::internal_default_instance() {
+  return &NameAttrList_default_instance_.get();
+}
+#endif  // !PROTOBUF_INLINE_NOT_IN_HEADERS
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+
+// @@protoc_insertion_point(namespace_scope)
+
+}  // namespace tensorflow
+
+// @@protoc_insertion_point(global_scope)
+
+#endif  // PROTOBUF_attr_5fvalue_2eproto__INCLUDED
diff --git a/contrib/modules/dnn/misc/tensorflow/function.pb.cc b/contrib/modules/dnn/misc/tensorflow/function.pb.cc
new file mode 100644
index 0000000..408a07e
--- /dev/null
+++ b/contrib/modules/dnn/misc/tensorflow/function.pb.cc
@@ -0,0 +1,2348 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: function.proto
+
+#define INTERNAL_SUPPRESS_PROTOBUF_FIELD_DEPRECATION
+#include "function.pb.h"
+
+#include <algorithm>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/port.h>
+#include <google/protobuf/stubs/once.h>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/wire_format_lite_inl.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/generated_message_reflection.h>
+#include <google/protobuf/reflection_ops.h>
+#include <google/protobuf/wire_format.h>
+// @@protoc_insertion_point(includes)
+
+namespace tensorflow {
+
+namespace {
+
+const ::google::protobuf::Descriptor* FunctionDefLibrary_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+  FunctionDefLibrary_reflection_ = NULL;
+const ::google::protobuf::Descriptor* FunctionDef_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+  FunctionDef_reflection_ = NULL;
+const ::google::protobuf::Descriptor* FunctionDef_Node_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+  FunctionDef_Node_reflection_ = NULL;
+const ::google::protobuf::Descriptor* FunctionDef_Node_AttrEntry_descriptor_ = NULL;
+const ::google::protobuf::Descriptor* GradientDef_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+  GradientDef_reflection_ = NULL;
+
+}  // namespace
+
+
+void protobuf_AssignDesc_function_2eproto() GOOGLE_ATTRIBUTE_COLD;
+void protobuf_AssignDesc_function_2eproto() {
+  protobuf_AddDesc_function_2eproto();
+  const ::google::protobuf::FileDescriptor* file =
+    ::google::protobuf::DescriptorPool::generated_pool()->FindFileByName(
+      "function.proto");
+  GOOGLE_CHECK(file != NULL);
+  FunctionDefLibrary_descriptor_ = file->message_type(0);
+  static const int FunctionDefLibrary_offsets_[2] = {
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FunctionDefLibrary, function_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FunctionDefLibrary, gradient_),
+  };
+  FunctionDefLibrary_reflection_ =
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
+      FunctionDefLibrary_descriptor_,
+      FunctionDefLibrary::internal_default_instance(),
+      FunctionDefLibrary_offsets_,
+      -1,
+      -1,
+      -1,
+      sizeof(FunctionDefLibrary),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FunctionDefLibrary, _internal_metadata_));
+  FunctionDef_descriptor_ = file->message_type(1);
+  static const int FunctionDef_offsets_[2] = {
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FunctionDef, signature_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FunctionDef, node_),
+  };
+  FunctionDef_reflection_ =
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
+      FunctionDef_descriptor_,
+      FunctionDef::internal_default_instance(),
+      FunctionDef_offsets_,
+      -1,
+      -1,
+      -1,
+      sizeof(FunctionDef),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FunctionDef, _internal_metadata_));
+  FunctionDef_Node_descriptor_ = FunctionDef_descriptor_->nested_type(0);
+  static const int FunctionDef_Node_offsets_[5] = {
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FunctionDef_Node, ret_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FunctionDef_Node, op_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FunctionDef_Node, arg_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FunctionDef_Node, dep_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FunctionDef_Node, attr_),
+  };
+  FunctionDef_Node_reflection_ =
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
+      FunctionDef_Node_descriptor_,
+      FunctionDef_Node::internal_default_instance(),
+      FunctionDef_Node_offsets_,
+      -1,
+      -1,
+      -1,
+      sizeof(FunctionDef_Node),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FunctionDef_Node, _internal_metadata_));
+  FunctionDef_Node_AttrEntry_descriptor_ = FunctionDef_Node_descriptor_->nested_type(0);
+  GradientDef_descriptor_ = file->message_type(2);
+  static const int GradientDef_offsets_[2] = {
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(GradientDef, function_name_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(GradientDef, gradient_func_),
+  };
+  GradientDef_reflection_ =
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
+      GradientDef_descriptor_,
+      GradientDef::internal_default_instance(),
+      GradientDef_offsets_,
+      -1,
+      -1,
+      -1,
+      sizeof(GradientDef),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(GradientDef, _internal_metadata_));
+}
+
+namespace {
+
+GOOGLE_PROTOBUF_DECLARE_ONCE(protobuf_AssignDescriptors_once_);
+void protobuf_AssignDescriptorsOnce() {
+  ::google::protobuf::GoogleOnceInit(&protobuf_AssignDescriptors_once_,
+                 &protobuf_AssignDesc_function_2eproto);
+}
+
+void protobuf_RegisterTypes(const ::std::string&) GOOGLE_ATTRIBUTE_COLD;
+void protobuf_RegisterTypes(const ::std::string&) {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+      FunctionDefLibrary_descriptor_, FunctionDefLibrary::internal_default_instance());
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+      FunctionDef_descriptor_, FunctionDef::internal_default_instance());
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+      FunctionDef_Node_descriptor_, FunctionDef_Node::internal_default_instance());
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+        FunctionDef_Node_AttrEntry_descriptor_,
+        ::google::protobuf::internal::MapEntry<
+            ::std::string,
+            ::tensorflow::AttrValue,
+            ::google::protobuf::internal::WireFormatLite::TYPE_STRING,
+            ::google::protobuf::internal::WireFormatLite::TYPE_MESSAGE,
+            0>::CreateDefaultInstance(
+                FunctionDef_Node_AttrEntry_descriptor_));
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+      GradientDef_descriptor_, GradientDef::internal_default_instance());
+}
+
+}  // namespace
+
+void protobuf_ShutdownFile_function_2eproto() {
+  FunctionDefLibrary_default_instance_.Shutdown();
+  delete FunctionDefLibrary_reflection_;
+  FunctionDef_default_instance_.Shutdown();
+  delete FunctionDef_reflection_;
+  FunctionDef_Node_default_instance_.Shutdown();
+  delete FunctionDef_Node_reflection_;
+  GradientDef_default_instance_.Shutdown();
+  delete GradientDef_reflection_;
+}
+
+void protobuf_InitDefaults_function_2eproto_impl() {
+  GOOGLE_PROTOBUF_VERIFY_VERSION;
+
+  ::tensorflow::protobuf_InitDefaults_attr_5fvalue_2eproto();
+  ::tensorflow::protobuf_InitDefaults_op_5fdef_2eproto();
+  FunctionDefLibrary_default_instance_.DefaultConstruct();
+  FunctionDef_default_instance_.DefaultConstruct();
+  ::google::protobuf::internal::GetEmptyString();
+  FunctionDef_Node_default_instance_.DefaultConstruct();
+  ::google::protobuf::internal::GetEmptyString();
+  GradientDef_default_instance_.DefaultConstruct();
+  FunctionDefLibrary_default_instance_.get_mutable()->InitAsDefaultInstance();
+  FunctionDef_default_instance_.get_mutable()->InitAsDefaultInstance();
+  FunctionDef_Node_default_instance_.get_mutable()->InitAsDefaultInstance();
+  GradientDef_default_instance_.get_mutable()->InitAsDefaultInstance();
+}
+
+GOOGLE_PROTOBUF_DECLARE_ONCE(protobuf_InitDefaults_function_2eproto_once_);
+void protobuf_InitDefaults_function_2eproto() {
+  ::google::protobuf::GoogleOnceInit(&protobuf_InitDefaults_function_2eproto_once_,
+                 &protobuf_InitDefaults_function_2eproto_impl);
+}
+void protobuf_AddDesc_function_2eproto_impl() {
+  GOOGLE_PROTOBUF_VERIFY_VERSION;
+
+  protobuf_InitDefaults_function_2eproto();
+  ::google::protobuf::DescriptorPool::InternalAddGeneratedFile(
+    "\n\016function.proto\022\ntensorflow\032\020attr_value"
+    ".proto\032\014op_def.proto\"j\n\022FunctionDefLibra"
+    "ry\022)\n\010function\030\001 \003(\0132\027.tensorflow.Functi"
+    "onDef\022)\n\010gradient\030\002 \003(\0132\027.tensorflow.Gra"
+    "dientDef\"\225\002\n\013FunctionDef\022$\n\tsignature\030\001 "
+    "\001(\0132\021.tensorflow.OpDef\022*\n\004node\030\002 \003(\0132\034.t"
+    "ensorflow.FunctionDef.Node\032\263\001\n\004Node\022\013\n\003r"
+    "et\030\001 \003(\t\022\n\n\002op\030\002 \001(\t\022\013\n\003arg\030\003 \003(\t\022\013\n\003dep"
+    "\030\004 \003(\t\0224\n\004attr\030\005 \003(\0132&.tensorflow.Functi"
+    "onDef.Node.AttrEntry\032B\n\tAttrEntry\022\013\n\003key"
+    "\030\001 \001(\t\022$\n\005value\030\002 \001(\0132\025.tensorflow.AttrV"
+    "alue:\0028\001\";\n\013GradientDef\022\025\n\rfunction_name"
+    "\030\001 \001(\t\022\025\n\rgradient_func\030\002 \001(\tB/\n\030org.ten"
+    "sorflow.frameworkB\016FunctionProtosP\001\370\001\001b\006"
+    "proto3", 566);
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedFile(
+    "function.proto", &protobuf_RegisterTypes);
+  ::tensorflow::protobuf_AddDesc_attr_5fvalue_2eproto();
+  ::tensorflow::protobuf_AddDesc_op_5fdef_2eproto();
+  ::google::protobuf::internal::OnShutdown(&protobuf_ShutdownFile_function_2eproto);
+}
+
+GOOGLE_PROTOBUF_DECLARE_ONCE(protobuf_AddDesc_function_2eproto_once_);
+void protobuf_AddDesc_function_2eproto() {
+  ::google::protobuf::GoogleOnceInit(&protobuf_AddDesc_function_2eproto_once_,
+                 &protobuf_AddDesc_function_2eproto_impl);
+}
+// Force AddDescriptors() to be called at static initialization time.
+struct StaticDescriptorInitializer_function_2eproto {
+  StaticDescriptorInitializer_function_2eproto() {
+    protobuf_AddDesc_function_2eproto();
+  }
+} static_descriptor_initializer_function_2eproto_;
+
+namespace {
+
+static void MergeFromFail(int line) GOOGLE_ATTRIBUTE_COLD GOOGLE_ATTRIBUTE_NORETURN;
+static void MergeFromFail(int line) {
+  ::google::protobuf::internal::MergeFromFail(__FILE__, line);
+}
+
+}  // namespace
+
+
+// ===================================================================
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const int FunctionDefLibrary::kFunctionFieldNumber;
+const int FunctionDefLibrary::kGradientFieldNumber;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+
+FunctionDefLibrary::FunctionDefLibrary()
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+  if (this != internal_default_instance()) protobuf_InitDefaults_function_2eproto();
+  SharedCtor();
+  // @@protoc_insertion_point(constructor:tensorflow.FunctionDefLibrary)
+}
+FunctionDefLibrary::FunctionDefLibrary(::google::protobuf::Arena* arena)
+  : ::google::protobuf::Message(),
+  _internal_metadata_(arena),
+  function_(arena),
+  gradient_(arena) {
+#ifdef GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER
+  protobuf_InitDefaults_function_2eproto();
+#endif  // GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER
+  SharedCtor();
+  RegisterArenaDtor(arena);
+  // @@protoc_insertion_point(arena_constructor:tensorflow.FunctionDefLibrary)
+}
+
+void FunctionDefLibrary::InitAsDefaultInstance() {
+}
+
+FunctionDefLibrary::FunctionDefLibrary(const FunctionDefLibrary& from)
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
+  SharedCtor();
+  UnsafeMergeFrom(from);
+  // @@protoc_insertion_point(copy_constructor:tensorflow.FunctionDefLibrary)
+}
+
+void FunctionDefLibrary::SharedCtor() {
+  _cached_size_ = 0;
+}
+
+FunctionDefLibrary::~FunctionDefLibrary() {
+  // @@protoc_insertion_point(destructor:tensorflow.FunctionDefLibrary)
+  SharedDtor();
+}
+
+void FunctionDefLibrary::SharedDtor() {
+  ::google::protobuf::Arena* arena = GetArenaNoVirtual();
+  if (arena != NULL) {
+    return;
+  }
+
+}
+
+void FunctionDefLibrary::ArenaDtor(void* object) {
+  FunctionDefLibrary* _this = reinterpret_cast< FunctionDefLibrary* >(object);
+  (void)_this;
+}
+void FunctionDefLibrary::RegisterArenaDtor(::google::protobuf::Arena* arena) {
+}
+void FunctionDefLibrary::SetCachedSize(int size) const {
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* FunctionDefLibrary::descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return FunctionDefLibrary_descriptor_;
+}
+
+const FunctionDefLibrary& FunctionDefLibrary::default_instance() {
+  protobuf_InitDefaults_function_2eproto();
+  return *internal_default_instance();
+}
+
+::google::protobuf::internal::ExplicitlyConstructed<FunctionDefLibrary> FunctionDefLibrary_default_instance_;
+
+FunctionDefLibrary* FunctionDefLibrary::New(::google::protobuf::Arena* arena) const {
+  return ::google::protobuf::Arena::CreateMessage<FunctionDefLibrary>(arena);
+}
+
+void FunctionDefLibrary::Clear() {
+// @@protoc_insertion_point(message_clear_start:tensorflow.FunctionDefLibrary)
+  function_.Clear();
+  gradient_.Clear();
+}
+
+bool FunctionDefLibrary::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
+  ::google::protobuf::uint32 tag;
+  // @@protoc_insertion_point(parse_start:tensorflow.FunctionDefLibrary)
+  for (;;) {
+    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+    tag = p.first;
+    if (!p.second) goto handle_unusual;
+    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+      // repeated .tensorflow.FunctionDef function = 1;
+      case 1: {
+        if (tag == 10) {
+          DO_(input->IncrementRecursionDepth());
+         parse_loop_function:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth(
+                input, add_function()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(10)) goto parse_loop_function;
+        if (input->ExpectTag(18)) goto parse_loop_gradient;
+        input->UnsafeDecrementRecursionDepth();
+        break;
+      }
+
+      // repeated .tensorflow.GradientDef gradient = 2;
+      case 2: {
+        if (tag == 18) {
+          DO_(input->IncrementRecursionDepth());
+         parse_loop_gradient:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth(
+                input, add_gradient()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(18)) goto parse_loop_gradient;
+        input->UnsafeDecrementRecursionDepth();
+        if (input->ExpectAtEnd()) goto success;
+        break;
+      }
+
+      default: {
+      handle_unusual:
+        if (tag == 0 ||
+            ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+          goto success;
+        }
+        DO_(::google::protobuf::internal::WireFormatLite::SkipField(input, tag));
+        break;
+      }
+    }
+  }
+success:
+  // @@protoc_insertion_point(parse_success:tensorflow.FunctionDefLibrary)
+  return true;
+failure:
+  // @@protoc_insertion_point(parse_failure:tensorflow.FunctionDefLibrary)
+  return false;
+#undef DO_
+}
+
+void FunctionDefLibrary::SerializeWithCachedSizes(
+    ::google::protobuf::io::CodedOutputStream* output) const {
+  // @@protoc_insertion_point(serialize_start:tensorflow.FunctionDefLibrary)
+  // repeated .tensorflow.FunctionDef function = 1;
+  for (unsigned int i = 0, n = this->function_size(); i < n; i++) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      1, this->function(i), output);
+  }
+
+  // repeated .tensorflow.GradientDef gradient = 2;
+  for (unsigned int i = 0, n = this->gradient_size(); i < n; i++) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      2, this->gradient(i), output);
+  }
+
+  // @@protoc_insertion_point(serialize_end:tensorflow.FunctionDefLibrary)
+}
+
+::google::protobuf::uint8* FunctionDefLibrary::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
+  (void)deterministic; // Unused
+  // @@protoc_insertion_point(serialize_to_array_start:tensorflow.FunctionDefLibrary)
+  // repeated .tensorflow.FunctionDef function = 1;
+  for (unsigned int i = 0, n = this->function_size(); i < n; i++) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        1, this->function(i), false, target);
+  }
+
+  // repeated .tensorflow.GradientDef gradient = 2;
+  for (unsigned int i = 0, n = this->gradient_size(); i < n; i++) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        2, this->gradient(i), false, target);
+  }
+
+  // @@protoc_insertion_point(serialize_to_array_end:tensorflow.FunctionDefLibrary)
+  return target;
+}
+
+size_t FunctionDefLibrary::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:tensorflow.FunctionDefLibrary)
+  size_t total_size = 0;
+
+  // repeated .tensorflow.FunctionDef function = 1;
+  {
+    unsigned int count = this->function_size();
+    total_size += 1UL * count;
+    for (unsigned int i = 0; i < count; i++) {
+      total_size +=
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          this->function(i));
+    }
+  }
+
+  // repeated .tensorflow.GradientDef gradient = 2;
+  {
+    unsigned int count = this->gradient_size();
+    total_size += 1UL * count;
+    for (unsigned int i = 0; i < count; i++) {
+      total_size +=
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          this->gradient(i));
+    }
+  }
+
+  int cached_size = ::google::protobuf::internal::ToCachedSize(total_size);
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = cached_size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+  return total_size;
+}
+
+void FunctionDefLibrary::MergeFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_merge_from_start:tensorflow.FunctionDefLibrary)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const FunctionDefLibrary* source =
+      ::google::protobuf::internal::DynamicCastToGenerated<const FunctionDefLibrary>(
+          &from);
+  if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:tensorflow.FunctionDefLibrary)
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:tensorflow.FunctionDefLibrary)
+    UnsafeMergeFrom(*source);
+  }
+}
+
+void FunctionDefLibrary::MergeFrom(const FunctionDefLibrary& from) {
+// @@protoc_insertion_point(class_specific_merge_from_start:tensorflow.FunctionDefLibrary)
+  if (GOOGLE_PREDICT_TRUE(&from != this)) {
+    UnsafeMergeFrom(from);
+  } else {
+    MergeFromFail(__LINE__);
+  }
+}
+
+void FunctionDefLibrary::UnsafeMergeFrom(const FunctionDefLibrary& from) {
+  GOOGLE_DCHECK(&from != this);
+  function_.MergeFrom(from.function_);
+  gradient_.MergeFrom(from.gradient_);
+}
+
+void FunctionDefLibrary::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:tensorflow.FunctionDefLibrary)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void FunctionDefLibrary::CopyFrom(const FunctionDefLibrary& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:tensorflow.FunctionDefLibrary)
+  if (&from == this) return;
+  Clear();
+  UnsafeMergeFrom(from);
+}
+
+bool FunctionDefLibrary::IsInitialized() const {
+
+  return true;
+}
+
+void FunctionDefLibrary::Swap(FunctionDefLibrary* other) {
+  if (other == this) return;
+  if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) {
+    InternalSwap(other);
+  } else {
+    FunctionDefLibrary temp;
+    temp.UnsafeMergeFrom(*this);
+    CopyFrom(*other);
+    other->CopyFrom(temp);
+  }
+}
+void FunctionDefLibrary::UnsafeArenaSwap(FunctionDefLibrary* other) {
+  if (other == this) return;
+  GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual());
+  InternalSwap(other);
+}
+void FunctionDefLibrary::InternalSwap(FunctionDefLibrary* other) {
+  function_.UnsafeArenaSwap(&other->function_);
+  gradient_.UnsafeArenaSwap(&other->gradient_);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
+}
+
+::google::protobuf::Metadata FunctionDefLibrary::GetMetadata() const {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::Metadata metadata;
+  metadata.descriptor = FunctionDefLibrary_descriptor_;
+  metadata.reflection = FunctionDefLibrary_reflection_;
+  return metadata;
+}
+
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// FunctionDefLibrary
+
+// repeated .tensorflow.FunctionDef function = 1;
+int FunctionDefLibrary::function_size() const {
+  return function_.size();
+}
+void FunctionDefLibrary::clear_function() {
+  function_.Clear();
+}
+const ::tensorflow::FunctionDef& FunctionDefLibrary::function(int index) const {
+  // @@protoc_insertion_point(field_get:tensorflow.FunctionDefLibrary.function)
+  return function_.Get(index);
+}
+::tensorflow::FunctionDef* FunctionDefLibrary::mutable_function(int index) {
+  // @@protoc_insertion_point(field_mutable:tensorflow.FunctionDefLibrary.function)
+  return function_.Mutable(index);
+}
+::tensorflow::FunctionDef* FunctionDefLibrary::add_function() {
+  // @@protoc_insertion_point(field_add:tensorflow.FunctionDefLibrary.function)
+  return function_.Add();
+}
+::google::protobuf::RepeatedPtrField< ::tensorflow::FunctionDef >*
+FunctionDefLibrary::mutable_function() {
+  // @@protoc_insertion_point(field_mutable_list:tensorflow.FunctionDefLibrary.function)
+  return &function_;
+}
+const ::google::protobuf::RepeatedPtrField< ::tensorflow::FunctionDef >&
+FunctionDefLibrary::function() const {
+  // @@protoc_insertion_point(field_list:tensorflow.FunctionDefLibrary.function)
+  return function_;
+}
+
+// repeated .tensorflow.GradientDef gradient = 2;
+int FunctionDefLibrary::gradient_size() const {
+  return gradient_.size();
+}
+void FunctionDefLibrary::clear_gradient() {
+  gradient_.Clear();
+}
+const ::tensorflow::GradientDef& FunctionDefLibrary::gradient(int index) const {
+  // @@protoc_insertion_point(field_get:tensorflow.FunctionDefLibrary.gradient)
+  return gradient_.Get(index);
+}
+::tensorflow::GradientDef* FunctionDefLibrary::mutable_gradient(int index) {
+  // @@protoc_insertion_point(field_mutable:tensorflow.FunctionDefLibrary.gradient)
+  return gradient_.Mutable(index);
+}
+::tensorflow::GradientDef* FunctionDefLibrary::add_gradient() {
+  // @@protoc_insertion_point(field_add:tensorflow.FunctionDefLibrary.gradient)
+  return gradient_.Add();
+}
+::google::protobuf::RepeatedPtrField< ::tensorflow::GradientDef >*
+FunctionDefLibrary::mutable_gradient() {
+  // @@protoc_insertion_point(field_mutable_list:tensorflow.FunctionDefLibrary.gradient)
+  return &gradient_;
+}
+const ::google::protobuf::RepeatedPtrField< ::tensorflow::GradientDef >&
+FunctionDefLibrary::gradient() const {
+  // @@protoc_insertion_point(field_list:tensorflow.FunctionDefLibrary.gradient)
+  return gradient_;
+}
+
+inline const FunctionDefLibrary* FunctionDefLibrary::internal_default_instance() {
+  return &FunctionDefLibrary_default_instance_.get();
+}
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
+
+// ===================================================================
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const int FunctionDef_Node::kRetFieldNumber;
+const int FunctionDef_Node::kOpFieldNumber;
+const int FunctionDef_Node::kArgFieldNumber;
+const int FunctionDef_Node::kDepFieldNumber;
+const int FunctionDef_Node::kAttrFieldNumber;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+
+FunctionDef_Node::FunctionDef_Node()
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+  if (this != internal_default_instance()) protobuf_InitDefaults_function_2eproto();
+  SharedCtor();
+  // @@protoc_insertion_point(constructor:tensorflow.FunctionDef.Node)
+}
+FunctionDef_Node::FunctionDef_Node(::google::protobuf::Arena* arena)
+  : ::google::protobuf::Message(),
+  _internal_metadata_(arena),
+  ret_(arena),
+  arg_(arena),
+  dep_(arena),
+  attr_(arena) {
+#ifdef GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER
+  protobuf_InitDefaults_function_2eproto();
+#endif  // GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER
+  SharedCtor();
+  RegisterArenaDtor(arena);
+  // @@protoc_insertion_point(arena_constructor:tensorflow.FunctionDef.Node)
+}
+
+void FunctionDef_Node::InitAsDefaultInstance() {
+}
+
+FunctionDef_Node::FunctionDef_Node(const FunctionDef_Node& from)
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
+  SharedCtor();
+  UnsafeMergeFrom(from);
+  // @@protoc_insertion_point(copy_constructor:tensorflow.FunctionDef.Node)
+}
+
+void FunctionDef_Node::SharedCtor() {
+  attr_.SetAssignDescriptorCallback(
+      protobuf_AssignDescriptorsOnce);
+  attr_.SetEntryDescriptor(
+      &::tensorflow::FunctionDef_Node_AttrEntry_descriptor_);
+  op_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  _cached_size_ = 0;
+}
+
+FunctionDef_Node::~FunctionDef_Node() {
+  // @@protoc_insertion_point(destructor:tensorflow.FunctionDef.Node)
+  SharedDtor();
+}
+
+void FunctionDef_Node::SharedDtor() {
+  ::google::protobuf::Arena* arena = GetArenaNoVirtual();
+  if (arena != NULL) {
+    return;
+  }
+
+  op_.Destroy(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), arena);
+}
+
+void FunctionDef_Node::ArenaDtor(void* object) {
+  FunctionDef_Node* _this = reinterpret_cast< FunctionDef_Node* >(object);
+  (void)_this;
+}
+void FunctionDef_Node::RegisterArenaDtor(::google::protobuf::Arena* arena) {
+}
+void FunctionDef_Node::SetCachedSize(int size) const {
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* FunctionDef_Node::descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return FunctionDef_Node_descriptor_;
+}
+
+const FunctionDef_Node& FunctionDef_Node::default_instance() {
+  protobuf_InitDefaults_function_2eproto();
+  return *internal_default_instance();
+}
+
+::google::protobuf::internal::ExplicitlyConstructed<FunctionDef_Node> FunctionDef_Node_default_instance_;
+
+FunctionDef_Node* FunctionDef_Node::New(::google::protobuf::Arena* arena) const {
+  return ::google::protobuf::Arena::CreateMessage<FunctionDef_Node>(arena);
+}
+
+void FunctionDef_Node::Clear() {
+// @@protoc_insertion_point(message_clear_start:tensorflow.FunctionDef.Node)
+  op_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+  ret_.Clear();
+  arg_.Clear();
+  dep_.Clear();
+  attr_.Clear();
+}
+
+bool FunctionDef_Node::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
+  ::google::protobuf::uint32 tag;
+  // @@protoc_insertion_point(parse_start:tensorflow.FunctionDef.Node)
+  for (;;) {
+    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+    tag = p.first;
+    if (!p.second) goto handle_unusual;
+    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+      // repeated string ret = 1;
+      case 1: {
+        if (tag == 10) {
+         parse_ret:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+                input, this->add_ret()));
+          DO_(::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+            this->ret(this->ret_size() - 1).data(),
+            this->ret(this->ret_size() - 1).length(),
+            ::google::protobuf::internal::WireFormatLite::PARSE,
+            "tensorflow.FunctionDef.Node.ret"));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(10)) goto parse_ret;
+        if (input->ExpectTag(18)) goto parse_op;
+        break;
+      }
+
+      // optional string op = 2;
+      case 2: {
+        if (tag == 18) {
+         parse_op:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+                input, this->mutable_op()));
+          DO_(::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+            this->op().data(), this->op().length(),
+            ::google::protobuf::internal::WireFormatLite::PARSE,
+            "tensorflow.FunctionDef.Node.op"));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(26)) goto parse_arg;
+        break;
+      }
+
+      // repeated string arg = 3;
+      case 3: {
+        if (tag == 26) {
+         parse_arg:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+                input, this->add_arg()));
+          DO_(::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+            this->arg(this->arg_size() - 1).data(),
+            this->arg(this->arg_size() - 1).length(),
+            ::google::protobuf::internal::WireFormatLite::PARSE,
+            "tensorflow.FunctionDef.Node.arg"));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(26)) goto parse_arg;
+        if (input->ExpectTag(34)) goto parse_dep;
+        break;
+      }
+
+      // repeated string dep = 4;
+      case 4: {
+        if (tag == 34) {
+         parse_dep:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+                input, this->add_dep()));
+          DO_(::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+            this->dep(this->dep_size() - 1).data(),
+            this->dep(this->dep_size() - 1).length(),
+            ::google::protobuf::internal::WireFormatLite::PARSE,
+            "tensorflow.FunctionDef.Node.dep"));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(34)) goto parse_dep;
+        if (input->ExpectTag(42)) goto parse_attr;
+        break;
+      }
+
+      // map<string, .tensorflow.AttrValue> attr = 5;
+      case 5: {
+        if (tag == 42) {
+         parse_attr:
+          DO_(input->IncrementRecursionDepth());
+         parse_loop_attr:
+          FunctionDef_Node_AttrEntry::Parser< ::google::protobuf::internal::MapField<
+              ::std::string, ::tensorflow::AttrValue,
+              ::google::protobuf::internal::WireFormatLite::TYPE_STRING,
+              ::google::protobuf::internal::WireFormatLite::TYPE_MESSAGE,
+              0 >,
+            ::google::protobuf::Map< ::std::string, ::tensorflow::AttrValue > > parser(&attr_);
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+              input, &parser));
+          DO_(::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+            parser.key().data(), parser.key().length(),
+            ::google::protobuf::internal::WireFormatLite::PARSE,
+            "tensorflow.FunctionDef.Node.AttrEntry.key"));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(42)) goto parse_loop_attr;
+        input->UnsafeDecrementRecursionDepth();
+        if (input->ExpectAtEnd()) goto success;
+        break;
+      }
+
+      default: {
+      handle_unusual:
+        if (tag == 0 ||
+            ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+          goto success;
+        }
+        DO_(::google::protobuf::internal::WireFormatLite::SkipField(input, tag));
+        break;
+      }
+    }
+  }
+success:
+  // @@protoc_insertion_point(parse_success:tensorflow.FunctionDef.Node)
+  return true;
+failure:
+  // @@protoc_insertion_point(parse_failure:tensorflow.FunctionDef.Node)
+  return false;
+#undef DO_
+}
+
+void FunctionDef_Node::SerializeWithCachedSizes(
+    ::google::protobuf::io::CodedOutputStream* output) const {
+  // @@protoc_insertion_point(serialize_start:tensorflow.FunctionDef.Node)
+  // repeated string ret = 1;
+  for (int i = 0; i < this->ret_size(); i++) {
+    ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+      this->ret(i).data(), this->ret(i).length(),
+      ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+      "tensorflow.FunctionDef.Node.ret");
+    ::google::protobuf::internal::WireFormatLite::WriteString(
+      1, this->ret(i), output);
+  }
+
+  // optional string op = 2;
+  if (this->op().size() > 0) {
+    ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+      this->op().data(), this->op().length(),
+      ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+      "tensorflow.FunctionDef.Node.op");
+    ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
+      2, this->op(), output);
+  }
+
+  // repeated string arg = 3;
+  for (int i = 0; i < this->arg_size(); i++) {
+    ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+      this->arg(i).data(), this->arg(i).length(),
+      ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+      "tensorflow.FunctionDef.Node.arg");
+    ::google::protobuf::internal::WireFormatLite::WriteString(
+      3, this->arg(i), output);
+  }
+
+  // repeated string dep = 4;
+  for (int i = 0; i < this->dep_size(); i++) {
+    ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+      this->dep(i).data(), this->dep(i).length(),
+      ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+      "tensorflow.FunctionDef.Node.dep");
+    ::google::protobuf::internal::WireFormatLite::WriteString(
+      4, this->dep(i), output);
+  }
+
+  // map<string, .tensorflow.AttrValue> attr = 5;
+  if (!this->attr().empty()) {
+    typedef ::google::protobuf::Map< ::std::string, ::tensorflow::AttrValue >::const_pointer
+        ConstPtr;
+    typedef ConstPtr SortItem;
+    typedef ::google::protobuf::internal::CompareByDerefFirst<SortItem> Less;
+    struct Utf8Check {
+      static void Check(ConstPtr p) {
+        ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+          p->first.data(), p->first.length(),
+          ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+          "tensorflow.FunctionDef.Node.AttrEntry.key");
+      }
+    };
+
+    if (output->IsSerializationDeterminstic() &&
+        this->attr().size() > 1) {
+      ::google::protobuf::scoped_array<SortItem> items(
+          new SortItem[this->attr().size()]);
+      typedef ::google::protobuf::Map< ::std::string, ::tensorflow::AttrValue >::size_type size_type;
+      size_type n = 0;
+      for (::google::protobuf::Map< ::std::string, ::tensorflow::AttrValue >::const_iterator
+          it = this->attr().begin();
+          it != this->attr().end(); ++it, ++n) {
+        items[n] = SortItem(&*it);
+      }
+      ::std::sort(&items[0], &items[n], Less());
+      ::google::protobuf::scoped_ptr<FunctionDef_Node_AttrEntry> entry;
+      for (size_type i = 0; i < n; i++) {
+        entry.reset(attr_.NewEntryWrapper(
+            items[i]->first, items[i]->second));
+        ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+            5, *entry, output);
+        if (entry->GetArena() != NULL) {
+          entry.release();
+        }
+        Utf8Check::Check(items[i]);
+      }
+    } else {
+      ::google::protobuf::scoped_ptr<FunctionDef_Node_AttrEntry> entry;
+      for (::google::protobuf::Map< ::std::string, ::tensorflow::AttrValue >::const_iterator
+          it = this->attr().begin();
+          it != this->attr().end(); ++it) {
+        entry.reset(attr_.NewEntryWrapper(
+            it->first, it->second));
+        ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+            5, *entry, output);
+        if (entry->GetArena() != NULL) {
+          entry.release();
+        }
+        Utf8Check::Check(&*it);
+      }
+    }
+  }
+
+  // @@protoc_insertion_point(serialize_end:tensorflow.FunctionDef.Node)
+}
+
+::google::protobuf::uint8* FunctionDef_Node::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
+  (void)deterministic; // Unused
+  // @@protoc_insertion_point(serialize_to_array_start:tensorflow.FunctionDef.Node)
+  // repeated string ret = 1;
+  for (int i = 0; i < this->ret_size(); i++) {
+    ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+      this->ret(i).data(), this->ret(i).length(),
+      ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+      "tensorflow.FunctionDef.Node.ret");
+    target = ::google::protobuf::internal::WireFormatLite::
+      WriteStringToArray(1, this->ret(i), target);
+  }
+
+  // optional string op = 2;
+  if (this->op().size() > 0) {
+    ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+      this->op().data(), this->op().length(),
+      ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+      "tensorflow.FunctionDef.Node.op");
+    target =
+      ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
+        2, this->op(), target);
+  }
+
+  // repeated string arg = 3;
+  for (int i = 0; i < this->arg_size(); i++) {
+    ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+      this->arg(i).data(), this->arg(i).length(),
+      ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+      "tensorflow.FunctionDef.Node.arg");
+    target = ::google::protobuf::internal::WireFormatLite::
+      WriteStringToArray(3, this->arg(i), target);
+  }
+
+  // repeated string dep = 4;
+  for (int i = 0; i < this->dep_size(); i++) {
+    ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+      this->dep(i).data(), this->dep(i).length(),
+      ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+      "tensorflow.FunctionDef.Node.dep");
+    target = ::google::protobuf::internal::WireFormatLite::
+      WriteStringToArray(4, this->dep(i), target);
+  }
+
+  // map<string, .tensorflow.AttrValue> attr = 5;
+  if (!this->attr().empty()) {
+    typedef ::google::protobuf::Map< ::std::string, ::tensorflow::AttrValue >::const_pointer
+        ConstPtr;
+    typedef ConstPtr SortItem;
+    typedef ::google::protobuf::internal::CompareByDerefFirst<SortItem> Less;
+    struct Utf8Check {
+      static void Check(ConstPtr p) {
+        ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+          p->first.data(), p->first.length(),
+          ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+          "tensorflow.FunctionDef.Node.AttrEntry.key");
+      }
+    };
+
+    if (deterministic &&
+        this->attr().size() > 1) {
+      ::google::protobuf::scoped_array<SortItem> items(
+          new SortItem[this->attr().size()]);
+      typedef ::google::protobuf::Map< ::std::string, ::tensorflow::AttrValue >::size_type size_type;
+      size_type n = 0;
+      for (::google::protobuf::Map< ::std::string, ::tensorflow::AttrValue >::const_iterator
+          it = this->attr().begin();
+          it != this->attr().end(); ++it, ++n) {
+        items[n] = SortItem(&*it);
+      }
+      ::std::sort(&items[0], &items[n], Less());
+      ::google::protobuf::scoped_ptr<FunctionDef_Node_AttrEntry> entry;
+      for (size_type i = 0; i < n; i++) {
+        entry.reset(attr_.NewEntryWrapper(
+            items[i]->first, items[i]->second));
+        target = ::google::protobuf::internal::WireFormatLite::
+                   InternalWriteMessageNoVirtualToArray(
+                       5, *entry, deterministic, target);
+;
+        if (entry->GetArena() != NULL) {
+          entry.release();
+        }
+        Utf8Check::Check(items[i]);
+      }
+    } else {
+      ::google::protobuf::scoped_ptr<FunctionDef_Node_AttrEntry> entry;
+      for (::google::protobuf::Map< ::std::string, ::tensorflow::AttrValue >::const_iterator
+          it = this->attr().begin();
+          it != this->attr().end(); ++it) {
+        entry.reset(attr_.NewEntryWrapper(
+            it->first, it->second));
+        target = ::google::protobuf::internal::WireFormatLite::
+                   InternalWriteMessageNoVirtualToArray(
+                       5, *entry, deterministic, target);
+;
+        if (entry->GetArena() != NULL) {
+          entry.release();
+        }
+        Utf8Check::Check(&*it);
+      }
+    }
+  }
+
+  // @@protoc_insertion_point(serialize_to_array_end:tensorflow.FunctionDef.Node)
+  return target;
+}
+
+size_t FunctionDef_Node::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:tensorflow.FunctionDef.Node)
+  size_t total_size = 0;
+
+  // optional string op = 2;
+  if (this->op().size() > 0) {
+    total_size += 1 +
+      ::google::protobuf::internal::WireFormatLite::StringSize(
+        this->op());
+  }
+
+  // repeated string ret = 1;
+  total_size += 1 *
+      ::google::protobuf::internal::FromIntSize(this->ret_size());
+  for (int i = 0; i < this->ret_size(); i++) {
+    total_size += ::google::protobuf::internal::WireFormatLite::StringSize(
+      this->ret(i));
+  }
+
+  // repeated string arg = 3;
+  total_size += 1 *
+      ::google::protobuf::internal::FromIntSize(this->arg_size());
+  for (int i = 0; i < this->arg_size(); i++) {
+    total_size += ::google::protobuf::internal::WireFormatLite::StringSize(
+      this->arg(i));
+  }
+
+  // repeated string dep = 4;
+  total_size += 1 *
+      ::google::protobuf::internal::FromIntSize(this->dep_size());
+  for (int i = 0; i < this->dep_size(); i++) {
+    total_size += ::google::protobuf::internal::WireFormatLite::StringSize(
+      this->dep(i));
+  }
+
+  // map<string, .tensorflow.AttrValue> attr = 5;
+  total_size += 1 *
+      ::google::protobuf::internal::FromIntSize(this->attr_size());
+  {
+    ::google::protobuf::scoped_ptr<FunctionDef_Node_AttrEntry> entry;
+    for (::google::protobuf::Map< ::std::string, ::tensorflow::AttrValue >::const_iterator
+        it = this->attr().begin();
+        it != this->attr().end(); ++it) {
+      if (entry.get() != NULL && entry->GetArena() != NULL) {
+        entry.release();
+      }
+      entry.reset(attr_.NewEntryWrapper(it->first, it->second));
+      total_size += ::google::protobuf::internal::WireFormatLite::
+          MessageSizeNoVirtual(*entry);
+    }
+    if (entry.get() != NULL && entry->GetArena() != NULL) {
+      entry.release();
+    }
+  }
+
+  int cached_size = ::google::protobuf::internal::ToCachedSize(total_size);
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = cached_size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+  return total_size;
+}
+
+void FunctionDef_Node::MergeFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_merge_from_start:tensorflow.FunctionDef.Node)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const FunctionDef_Node* source =
+      ::google::protobuf::internal::DynamicCastToGenerated<const FunctionDef_Node>(
+          &from);
+  if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:tensorflow.FunctionDef.Node)
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:tensorflow.FunctionDef.Node)
+    UnsafeMergeFrom(*source);
+  }
+}
+
+void FunctionDef_Node::MergeFrom(const FunctionDef_Node& from) {
+// @@protoc_insertion_point(class_specific_merge_from_start:tensorflow.FunctionDef.Node)
+  if (GOOGLE_PREDICT_TRUE(&from != this)) {
+    UnsafeMergeFrom(from);
+  } else {
+    MergeFromFail(__LINE__);
+  }
+}
+
+void FunctionDef_Node::UnsafeMergeFrom(const FunctionDef_Node& from) {
+  GOOGLE_DCHECK(&from != this);
+  ret_.UnsafeMergeFrom(from.ret_);
+  arg_.UnsafeMergeFrom(from.arg_);
+  dep_.UnsafeMergeFrom(from.dep_);
+  attr_.MergeFrom(from.attr_);
+  if (from.op().size() > 0) {
+    set_op(from.op());
+  }
+}
+
+void FunctionDef_Node::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:tensorflow.FunctionDef.Node)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void FunctionDef_Node::CopyFrom(const FunctionDef_Node& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:tensorflow.FunctionDef.Node)
+  if (&from == this) return;
+  Clear();
+  UnsafeMergeFrom(from);
+}
+
+bool FunctionDef_Node::IsInitialized() const {
+
+  return true;
+}
+
+void FunctionDef_Node::Swap(FunctionDef_Node* other) {
+  if (other == this) return;
+  if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) {
+    InternalSwap(other);
+  } else {
+    FunctionDef_Node temp;
+    temp.UnsafeMergeFrom(*this);
+    CopyFrom(*other);
+    other->CopyFrom(temp);
+  }
+}
+void FunctionDef_Node::UnsafeArenaSwap(FunctionDef_Node* other) {
+  if (other == this) return;
+  GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual());
+  InternalSwap(other);
+}
+void FunctionDef_Node::InternalSwap(FunctionDef_Node* other) {
+  ret_.UnsafeArenaSwap(&other->ret_);
+  op_.Swap(&other->op_);
+  arg_.UnsafeArenaSwap(&other->arg_);
+  dep_.UnsafeArenaSwap(&other->dep_);
+  attr_.Swap(&other->attr_);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
+}
+
+::google::protobuf::Metadata FunctionDef_Node::GetMetadata() const {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::Metadata metadata;
+  metadata.descriptor = FunctionDef_Node_descriptor_;
+  metadata.reflection = FunctionDef_Node_reflection_;
+  return metadata;
+}
+
+
+// -------------------------------------------------------------------
+
+void FunctionDef::_slow_mutable_signature() {
+  signature_ = ::google::protobuf::Arena::CreateMessage< ::tensorflow::OpDef >(
+      GetArenaNoVirtual());
+}
+::tensorflow::OpDef* FunctionDef::_slow_release_signature() {
+  if (signature_ == NULL) {
+    return NULL;
+  } else {
+    ::tensorflow::OpDef* temp = new ::tensorflow::OpDef(*signature_);
+    signature_ = NULL;
+    return temp;
+  }
+}
+::tensorflow::OpDef* FunctionDef::unsafe_arena_release_signature() {
+  // @@protoc_insertion_point(field_unsafe_arena_release:tensorflow.FunctionDef.signature)
+
+  ::tensorflow::OpDef* temp = signature_;
+  signature_ = NULL;
+  return temp;
+}
+void FunctionDef::_slow_set_allocated_signature(
+    ::google::protobuf::Arena* message_arena, ::tensorflow::OpDef** signature) {
+    if (message_arena != NULL &&
+        ::google::protobuf::Arena::GetArena(*signature) == NULL) {
+      message_arena->Own(*signature);
+    } else if (message_arena !=
+               ::google::protobuf::Arena::GetArena(*signature)) {
+      ::tensorflow::OpDef* new_signature =
+            ::google::protobuf::Arena::CreateMessage< ::tensorflow::OpDef >(
+            message_arena);
+      new_signature->CopyFrom(**signature);
+      *signature = new_signature;
+    }
+}
+void FunctionDef::unsafe_arena_set_allocated_signature(
+    ::tensorflow::OpDef* signature) {
+  if (GetArenaNoVirtual() == NULL) {
+    delete signature_;
+  }
+  signature_ = signature;
+  if (signature) {
+
+  } else {
+
+  }
+  // @@protoc_insertion_point(field_unsafe_arena_set_allocated:tensorflow.FunctionDef.signature)
+}
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const int FunctionDef::kSignatureFieldNumber;
+const int FunctionDef::kNodeFieldNumber;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+
+FunctionDef::FunctionDef()
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+  if (this != internal_default_instance()) protobuf_InitDefaults_function_2eproto();
+  SharedCtor();
+  // @@protoc_insertion_point(constructor:tensorflow.FunctionDef)
+}
+FunctionDef::FunctionDef(::google::protobuf::Arena* arena)
+  : ::google::protobuf::Message(),
+  _internal_metadata_(arena),
+  node_(arena) {
+#ifdef GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER
+  protobuf_InitDefaults_function_2eproto();
+#endif  // GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER
+  SharedCtor();
+  RegisterArenaDtor(arena);
+  // @@protoc_insertion_point(arena_constructor:tensorflow.FunctionDef)
+}
+
+void FunctionDef::InitAsDefaultInstance() {
+  signature_ = const_cast< ::tensorflow::OpDef*>(
+      ::tensorflow::OpDef::internal_default_instance());
+}
+
+FunctionDef::FunctionDef(const FunctionDef& from)
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
+  SharedCtor();
+  UnsafeMergeFrom(from);
+  // @@protoc_insertion_point(copy_constructor:tensorflow.FunctionDef)
+}
+
+void FunctionDef::SharedCtor() {
+  signature_ = NULL;
+  _cached_size_ = 0;
+}
+
+FunctionDef::~FunctionDef() {
+  // @@protoc_insertion_point(destructor:tensorflow.FunctionDef)
+  SharedDtor();
+}
+
+void FunctionDef::SharedDtor() {
+  ::google::protobuf::Arena* arena = GetArenaNoVirtual();
+  if (arena != NULL) {
+    return;
+  }
+
+  if (this != &FunctionDef_default_instance_.get()) {
+    delete signature_;
+  }
+}
+
+void FunctionDef::ArenaDtor(void* object) {
+  FunctionDef* _this = reinterpret_cast< FunctionDef* >(object);
+  (void)_this;
+}
+void FunctionDef::RegisterArenaDtor(::google::protobuf::Arena* arena) {
+}
+void FunctionDef::SetCachedSize(int size) const {
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* FunctionDef::descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return FunctionDef_descriptor_;
+}
+
+const FunctionDef& FunctionDef::default_instance() {
+  protobuf_InitDefaults_function_2eproto();
+  return *internal_default_instance();
+}
+
+::google::protobuf::internal::ExplicitlyConstructed<FunctionDef> FunctionDef_default_instance_;
+
+FunctionDef* FunctionDef::New(::google::protobuf::Arena* arena) const {
+  return ::google::protobuf::Arena::CreateMessage<FunctionDef>(arena);
+}
+
+void FunctionDef::Clear() {
+// @@protoc_insertion_point(message_clear_start:tensorflow.FunctionDef)
+  if (GetArenaNoVirtual() == NULL && signature_ != NULL) delete signature_;
+  signature_ = NULL;
+  node_.Clear();
+}
+
+bool FunctionDef::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
+  ::google::protobuf::uint32 tag;
+  // @@protoc_insertion_point(parse_start:tensorflow.FunctionDef)
+  for (;;) {
+    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+    tag = p.first;
+    if (!p.second) goto handle_unusual;
+    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+      // optional .tensorflow.OpDef signature = 1;
+      case 1: {
+        if (tag == 10) {
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+               input, mutable_signature()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(18)) goto parse_node;
+        break;
+      }
+
+      // repeated .tensorflow.FunctionDef.Node node = 2;
+      case 2: {
+        if (tag == 18) {
+         parse_node:
+          DO_(input->IncrementRecursionDepth());
+         parse_loop_node:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth(
+                input, add_node()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(18)) goto parse_loop_node;
+        input->UnsafeDecrementRecursionDepth();
+        if (input->ExpectAtEnd()) goto success;
+        break;
+      }
+
+      default: {
+      handle_unusual:
+        if (tag == 0 ||
+            ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+          goto success;
+        }
+        DO_(::google::protobuf::internal::WireFormatLite::SkipField(input, tag));
+        break;
+      }
+    }
+  }
+success:
+  // @@protoc_insertion_point(parse_success:tensorflow.FunctionDef)
+  return true;
+failure:
+  // @@protoc_insertion_point(parse_failure:tensorflow.FunctionDef)
+  return false;
+#undef DO_
+}
+
+void FunctionDef::SerializeWithCachedSizes(
+    ::google::protobuf::io::CodedOutputStream* output) const {
+  // @@protoc_insertion_point(serialize_start:tensorflow.FunctionDef)
+  // optional .tensorflow.OpDef signature = 1;
+  if (this->has_signature()) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      1, *this->signature_, output);
+  }
+
+  // repeated .tensorflow.FunctionDef.Node node = 2;
+  for (unsigned int i = 0, n = this->node_size(); i < n; i++) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      2, this->node(i), output);
+  }
+
+  // @@protoc_insertion_point(serialize_end:tensorflow.FunctionDef)
+}
+
+::google::protobuf::uint8* FunctionDef::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
+  (void)deterministic; // Unused
+  // @@protoc_insertion_point(serialize_to_array_start:tensorflow.FunctionDef)
+  // optional .tensorflow.OpDef signature = 1;
+  if (this->has_signature()) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        1, *this->signature_, false, target);
+  }
+
+  // repeated .tensorflow.FunctionDef.Node node = 2;
+  for (unsigned int i = 0, n = this->node_size(); i < n; i++) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        2, this->node(i), false, target);
+  }
+
+  // @@protoc_insertion_point(serialize_to_array_end:tensorflow.FunctionDef)
+  return target;
+}
+
+size_t FunctionDef::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:tensorflow.FunctionDef)
+  size_t total_size = 0;
+
+  // optional .tensorflow.OpDef signature = 1;
+  if (this->has_signature()) {
+    total_size += 1 +
+      ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+        *this->signature_);
+  }
+
+  // repeated .tensorflow.FunctionDef.Node node = 2;
+  {
+    unsigned int count = this->node_size();
+    total_size += 1UL * count;
+    for (unsigned int i = 0; i < count; i++) {
+      total_size +=
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          this->node(i));
+    }
+  }
+
+  int cached_size = ::google::protobuf::internal::ToCachedSize(total_size);
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = cached_size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+  return total_size;
+}
+
+void FunctionDef::MergeFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_merge_from_start:tensorflow.FunctionDef)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const FunctionDef* source =
+      ::google::protobuf::internal::DynamicCastToGenerated<const FunctionDef>(
+          &from);
+  if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:tensorflow.FunctionDef)
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:tensorflow.FunctionDef)
+    UnsafeMergeFrom(*source);
+  }
+}
+
+void FunctionDef::MergeFrom(const FunctionDef& from) {
+// @@protoc_insertion_point(class_specific_merge_from_start:tensorflow.FunctionDef)
+  if (GOOGLE_PREDICT_TRUE(&from != this)) {
+    UnsafeMergeFrom(from);
+  } else {
+    MergeFromFail(__LINE__);
+  }
+}
+
+void FunctionDef::UnsafeMergeFrom(const FunctionDef& from) {
+  GOOGLE_DCHECK(&from != this);
+  node_.MergeFrom(from.node_);
+  if (from.has_signature()) {
+    mutable_signature()->::tensorflow::OpDef::MergeFrom(from.signature());
+  }
+}
+
+void FunctionDef::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:tensorflow.FunctionDef)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void FunctionDef::CopyFrom(const FunctionDef& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:tensorflow.FunctionDef)
+  if (&from == this) return;
+  Clear();
+  UnsafeMergeFrom(from);
+}
+
+bool FunctionDef::IsInitialized() const {
+
+  return true;
+}
+
+void FunctionDef::Swap(FunctionDef* other) {
+  if (other == this) return;
+  if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) {
+    InternalSwap(other);
+  } else {
+    FunctionDef temp;
+    temp.UnsafeMergeFrom(*this);
+    CopyFrom(*other);
+    other->CopyFrom(temp);
+  }
+}
+void FunctionDef::UnsafeArenaSwap(FunctionDef* other) {
+  if (other == this) return;
+  GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual());
+  InternalSwap(other);
+}
+void FunctionDef::InternalSwap(FunctionDef* other) {
+  std::swap(signature_, other->signature_);
+  node_.UnsafeArenaSwap(&other->node_);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
+}
+
+::google::protobuf::Metadata FunctionDef::GetMetadata() const {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::Metadata metadata;
+  metadata.descriptor = FunctionDef_descriptor_;
+  metadata.reflection = FunctionDef_reflection_;
+  return metadata;
+}
+
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// FunctionDef_Node
+
+// repeated string ret = 1;
+int FunctionDef_Node::ret_size() const {
+  return ret_.size();
+}
+void FunctionDef_Node::clear_ret() {
+  ret_.Clear();
+}
+const ::std::string& FunctionDef_Node::ret(int index) const {
+  // @@protoc_insertion_point(field_get:tensorflow.FunctionDef.Node.ret)
+  return ret_.Get(index);
+}
+::std::string* FunctionDef_Node::mutable_ret(int index) {
+  // @@protoc_insertion_point(field_mutable:tensorflow.FunctionDef.Node.ret)
+  return ret_.Mutable(index);
+}
+void FunctionDef_Node::set_ret(int index, const ::std::string& value) {
+  // @@protoc_insertion_point(field_set:tensorflow.FunctionDef.Node.ret)
+  ret_.Mutable(index)->assign(value);
+}
+void FunctionDef_Node::set_ret(int index, const char* value) {
+  ret_.Mutable(index)->assign(value);
+  // @@protoc_insertion_point(field_set_char:tensorflow.FunctionDef.Node.ret)
+}
+void FunctionDef_Node::set_ret(int index, const char* value, size_t size) {
+  ret_.Mutable(index)->assign(
+    reinterpret_cast<const char*>(value), size);
+  // @@protoc_insertion_point(field_set_pointer:tensorflow.FunctionDef.Node.ret)
+}
+::std::string* FunctionDef_Node::add_ret() {
+  // @@protoc_insertion_point(field_add_mutable:tensorflow.FunctionDef.Node.ret)
+  return ret_.Add();
+}
+void FunctionDef_Node::add_ret(const ::std::string& value) {
+  ret_.Add()->assign(value);
+  // @@protoc_insertion_point(field_add:tensorflow.FunctionDef.Node.ret)
+}
+void FunctionDef_Node::add_ret(const char* value) {
+  ret_.Add()->assign(value);
+  // @@protoc_insertion_point(field_add_char:tensorflow.FunctionDef.Node.ret)
+}
+void FunctionDef_Node::add_ret(const char* value, size_t size) {
+  ret_.Add()->assign(reinterpret_cast<const char*>(value), size);
+  // @@protoc_insertion_point(field_add_pointer:tensorflow.FunctionDef.Node.ret)
+}
+const ::google::protobuf::RepeatedPtrField< ::std::string>&
+FunctionDef_Node::ret() const {
+  // @@protoc_insertion_point(field_list:tensorflow.FunctionDef.Node.ret)
+  return ret_;
+}
+::google::protobuf::RepeatedPtrField< ::std::string>*
+FunctionDef_Node::mutable_ret() {
+  // @@protoc_insertion_point(field_mutable_list:tensorflow.FunctionDef.Node.ret)
+  return &ret_;
+}
+
+// optional string op = 2;
+void FunctionDef_Node::clear_op() {
+  op_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+const ::std::string& FunctionDef_Node::op() const {
+  // @@protoc_insertion_point(field_get:tensorflow.FunctionDef.Node.op)
+  return op_.Get(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+void FunctionDef_Node::set_op(const ::std::string& value) {
+
+  op_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value, GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set:tensorflow.FunctionDef.Node.op)
+}
+void FunctionDef_Node::set_op(const char* value) {
+
+  op_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value),
+              GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_char:tensorflow.FunctionDef.Node.op)
+}
+void FunctionDef_Node::set_op(const char* value,
+    size_t size) {
+
+  op_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(
+      reinterpret_cast<const char*>(value), size), GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_pointer:tensorflow.FunctionDef.Node.op)
+}
+::std::string* FunctionDef_Node::mutable_op() {
+
+  // @@protoc_insertion_point(field_mutable:tensorflow.FunctionDef.Node.op)
+  return op_.Mutable(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+::std::string* FunctionDef_Node::release_op() {
+  // @@protoc_insertion_point(field_release:tensorflow.FunctionDef.Node.op)
+
+  return op_.Release(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+::std::string* FunctionDef_Node::unsafe_arena_release_op() {
+  // @@protoc_insertion_point(field_unsafe_arena_release:tensorflow.FunctionDef.Node.op)
+  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);
+
+  return op_.UnsafeArenaRelease(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      GetArenaNoVirtual());
+}
+void FunctionDef_Node::set_allocated_op(::std::string* op) {
+  if (op != NULL) {
+
+  } else {
+
+  }
+  op_.SetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), op,
+      GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_allocated:tensorflow.FunctionDef.Node.op)
+}
+void FunctionDef_Node::unsafe_arena_set_allocated_op(
+    ::std::string* op) {
+  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);
+  if (op != NULL) {
+
+  } else {
+
+  }
+  op_.UnsafeArenaSetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      op, GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_unsafe_arena_set_allocated:tensorflow.FunctionDef.Node.op)
+}
+
+// repeated string arg = 3;
+int FunctionDef_Node::arg_size() const {
+  return arg_.size();
+}
+void FunctionDef_Node::clear_arg() {
+  arg_.Clear();
+}
+const ::std::string& FunctionDef_Node::arg(int index) const {
+  // @@protoc_insertion_point(field_get:tensorflow.FunctionDef.Node.arg)
+  return arg_.Get(index);
+}
+::std::string* FunctionDef_Node::mutable_arg(int index) {
+  // @@protoc_insertion_point(field_mutable:tensorflow.FunctionDef.Node.arg)
+  return arg_.Mutable(index);
+}
+void FunctionDef_Node::set_arg(int index, const ::std::string& value) {
+  // @@protoc_insertion_point(field_set:tensorflow.FunctionDef.Node.arg)
+  arg_.Mutable(index)->assign(value);
+}
+void FunctionDef_Node::set_arg(int index, const char* value) {
+  arg_.Mutable(index)->assign(value);
+  // @@protoc_insertion_point(field_set_char:tensorflow.FunctionDef.Node.arg)
+}
+void FunctionDef_Node::set_arg(int index, const char* value, size_t size) {
+  arg_.Mutable(index)->assign(
+    reinterpret_cast<const char*>(value), size);
+  // @@protoc_insertion_point(field_set_pointer:tensorflow.FunctionDef.Node.arg)
+}
+::std::string* FunctionDef_Node::add_arg() {
+  // @@protoc_insertion_point(field_add_mutable:tensorflow.FunctionDef.Node.arg)
+  return arg_.Add();
+}
+void FunctionDef_Node::add_arg(const ::std::string& value) {
+  arg_.Add()->assign(value);
+  // @@protoc_insertion_point(field_add:tensorflow.FunctionDef.Node.arg)
+}
+void FunctionDef_Node::add_arg(const char* value) {
+  arg_.Add()->assign(value);
+  // @@protoc_insertion_point(field_add_char:tensorflow.FunctionDef.Node.arg)
+}
+void FunctionDef_Node::add_arg(const char* value, size_t size) {
+  arg_.Add()->assign(reinterpret_cast<const char*>(value), size);
+  // @@protoc_insertion_point(field_add_pointer:tensorflow.FunctionDef.Node.arg)
+}
+const ::google::protobuf::RepeatedPtrField< ::std::string>&
+FunctionDef_Node::arg() const {
+  // @@protoc_insertion_point(field_list:tensorflow.FunctionDef.Node.arg)
+  return arg_;
+}
+::google::protobuf::RepeatedPtrField< ::std::string>*
+FunctionDef_Node::mutable_arg() {
+  // @@protoc_insertion_point(field_mutable_list:tensorflow.FunctionDef.Node.arg)
+  return &arg_;
+}
+
+// repeated string dep = 4;
+int FunctionDef_Node::dep_size() const {
+  return dep_.size();
+}
+void FunctionDef_Node::clear_dep() {
+  dep_.Clear();
+}
+const ::std::string& FunctionDef_Node::dep(int index) const {
+  // @@protoc_insertion_point(field_get:tensorflow.FunctionDef.Node.dep)
+  return dep_.Get(index);
+}
+::std::string* FunctionDef_Node::mutable_dep(int index) {
+  // @@protoc_insertion_point(field_mutable:tensorflow.FunctionDef.Node.dep)
+  return dep_.Mutable(index);
+}
+void FunctionDef_Node::set_dep(int index, const ::std::string& value) {
+  // @@protoc_insertion_point(field_set:tensorflow.FunctionDef.Node.dep)
+  dep_.Mutable(index)->assign(value);
+}
+void FunctionDef_Node::set_dep(int index, const char* value) {
+  dep_.Mutable(index)->assign(value);
+  // @@protoc_insertion_point(field_set_char:tensorflow.FunctionDef.Node.dep)
+}
+void FunctionDef_Node::set_dep(int index, const char* value, size_t size) {
+  dep_.Mutable(index)->assign(
+    reinterpret_cast<const char*>(value), size);
+  // @@protoc_insertion_point(field_set_pointer:tensorflow.FunctionDef.Node.dep)
+}
+::std::string* FunctionDef_Node::add_dep() {
+  // @@protoc_insertion_point(field_add_mutable:tensorflow.FunctionDef.Node.dep)
+  return dep_.Add();
+}
+void FunctionDef_Node::add_dep(const ::std::string& value) {
+  dep_.Add()->assign(value);
+  // @@protoc_insertion_point(field_add:tensorflow.FunctionDef.Node.dep)
+}
+void FunctionDef_Node::add_dep(const char* value) {
+  dep_.Add()->assign(value);
+  // @@protoc_insertion_point(field_add_char:tensorflow.FunctionDef.Node.dep)
+}
+void FunctionDef_Node::add_dep(const char* value, size_t size) {
+  dep_.Add()->assign(reinterpret_cast<const char*>(value), size);
+  // @@protoc_insertion_point(field_add_pointer:tensorflow.FunctionDef.Node.dep)
+}
+const ::google::protobuf::RepeatedPtrField< ::std::string>&
+FunctionDef_Node::dep() const {
+  // @@protoc_insertion_point(field_list:tensorflow.FunctionDef.Node.dep)
+  return dep_;
+}
+::google::protobuf::RepeatedPtrField< ::std::string>*
+FunctionDef_Node::mutable_dep() {
+  // @@protoc_insertion_point(field_mutable_list:tensorflow.FunctionDef.Node.dep)
+  return &dep_;
+}
+
+// map<string, .tensorflow.AttrValue> attr = 5;
+int FunctionDef_Node::attr_size() const {
+  return attr_.size();
+}
+void FunctionDef_Node::clear_attr() {
+  attr_.Clear();
+}
+ const ::google::protobuf::Map< ::std::string, ::tensorflow::AttrValue >&
+FunctionDef_Node::attr() const {
+  // @@protoc_insertion_point(field_map:tensorflow.FunctionDef.Node.attr)
+  return attr_.GetMap();
+}
+ ::google::protobuf::Map< ::std::string, ::tensorflow::AttrValue >*
+FunctionDef_Node::mutable_attr() {
+  // @@protoc_insertion_point(field_mutable_map:tensorflow.FunctionDef.Node.attr)
+  return attr_.MutableMap();
+}
+
+inline const FunctionDef_Node* FunctionDef_Node::internal_default_instance() {
+  return &FunctionDef_Node_default_instance_.get();
+}
+// -------------------------------------------------------------------
+
+// FunctionDef
+
+// optional .tensorflow.OpDef signature = 1;
+bool FunctionDef::has_signature() const {
+  return this != internal_default_instance() && signature_ != NULL;
+}
+void FunctionDef::clear_signature() {
+  if (GetArenaNoVirtual() == NULL && signature_ != NULL) delete signature_;
+  signature_ = NULL;
+}
+const ::tensorflow::OpDef& FunctionDef::signature() const {
+  // @@protoc_insertion_point(field_get:tensorflow.FunctionDef.signature)
+  return signature_ != NULL ? *signature_
+                         : *::tensorflow::OpDef::internal_default_instance();
+}
+::tensorflow::OpDef* FunctionDef::mutable_signature() {
+
+  if (signature_ == NULL) {
+    _slow_mutable_signature();
+  }
+  // @@protoc_insertion_point(field_mutable:tensorflow.FunctionDef.signature)
+  return signature_;
+}
+::tensorflow::OpDef* FunctionDef::release_signature() {
+  // @@protoc_insertion_point(field_release:tensorflow.FunctionDef.signature)
+
+  if (GetArenaNoVirtual() != NULL) {
+    return _slow_release_signature();
+  } else {
+    ::tensorflow::OpDef* temp = signature_;
+    signature_ = NULL;
+    return temp;
+  }
+}
+ void FunctionDef::set_allocated_signature(::tensorflow::OpDef* signature) {
+  ::google::protobuf::Arena* message_arena = GetArenaNoVirtual();
+  if (message_arena == NULL) {
+    delete signature_;
+  }
+  if (signature != NULL) {
+    _slow_set_allocated_signature(message_arena, &signature);
+  }
+  signature_ = signature;
+  if (signature) {
+
+  } else {
+
+  }
+  // @@protoc_insertion_point(field_set_allocated:tensorflow.FunctionDef.signature)
+}
+
+// repeated .tensorflow.FunctionDef.Node node = 2;
+int FunctionDef::node_size() const {
+  return node_.size();
+}
+void FunctionDef::clear_node() {
+  node_.Clear();
+}
+const ::tensorflow::FunctionDef_Node& FunctionDef::node(int index) const {
+  // @@protoc_insertion_point(field_get:tensorflow.FunctionDef.node)
+  return node_.Get(index);
+}
+::tensorflow::FunctionDef_Node* FunctionDef::mutable_node(int index) {
+  // @@protoc_insertion_point(field_mutable:tensorflow.FunctionDef.node)
+  return node_.Mutable(index);
+}
+::tensorflow::FunctionDef_Node* FunctionDef::add_node() {
+  // @@protoc_insertion_point(field_add:tensorflow.FunctionDef.node)
+  return node_.Add();
+}
+::google::protobuf::RepeatedPtrField< ::tensorflow::FunctionDef_Node >*
+FunctionDef::mutable_node() {
+  // @@protoc_insertion_point(field_mutable_list:tensorflow.FunctionDef.node)
+  return &node_;
+}
+const ::google::protobuf::RepeatedPtrField< ::tensorflow::FunctionDef_Node >&
+FunctionDef::node() const {
+  // @@protoc_insertion_point(field_list:tensorflow.FunctionDef.node)
+  return node_;
+}
+
+inline const FunctionDef* FunctionDef::internal_default_instance() {
+  return &FunctionDef_default_instance_.get();
+}
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
+
+// ===================================================================
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const int GradientDef::kFunctionNameFieldNumber;
+const int GradientDef::kGradientFuncFieldNumber;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+
+GradientDef::GradientDef()
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+  if (this != internal_default_instance()) protobuf_InitDefaults_function_2eproto();
+  SharedCtor();
+  // @@protoc_insertion_point(constructor:tensorflow.GradientDef)
+}
+GradientDef::GradientDef(::google::protobuf::Arena* arena)
+  : ::google::protobuf::Message(),
+  _internal_metadata_(arena) {
+#ifdef GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER
+  protobuf_InitDefaults_function_2eproto();
+#endif  // GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER
+  SharedCtor();
+  RegisterArenaDtor(arena);
+  // @@protoc_insertion_point(arena_constructor:tensorflow.GradientDef)
+}
+
+void GradientDef::InitAsDefaultInstance() {
+}
+
+GradientDef::GradientDef(const GradientDef& from)
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
+  SharedCtor();
+  UnsafeMergeFrom(from);
+  // @@protoc_insertion_point(copy_constructor:tensorflow.GradientDef)
+}
+
+void GradientDef::SharedCtor() {
+  function_name_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  gradient_func_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  _cached_size_ = 0;
+}
+
+GradientDef::~GradientDef() {
+  // @@protoc_insertion_point(destructor:tensorflow.GradientDef)
+  SharedDtor();
+}
+
+void GradientDef::SharedDtor() {
+  ::google::protobuf::Arena* arena = GetArenaNoVirtual();
+  if (arena != NULL) {
+    return;
+  }
+
+  function_name_.Destroy(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), arena);
+  gradient_func_.Destroy(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), arena);
+}
+
+void GradientDef::ArenaDtor(void* object) {
+  GradientDef* _this = reinterpret_cast< GradientDef* >(object);
+  (void)_this;
+}
+void GradientDef::RegisterArenaDtor(::google::protobuf::Arena* arena) {
+}
+void GradientDef::SetCachedSize(int size) const {
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* GradientDef::descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return GradientDef_descriptor_;
+}
+
+const GradientDef& GradientDef::default_instance() {
+  protobuf_InitDefaults_function_2eproto();
+  return *internal_default_instance();
+}
+
+::google::protobuf::internal::ExplicitlyConstructed<GradientDef> GradientDef_default_instance_;
+
+GradientDef* GradientDef::New(::google::protobuf::Arena* arena) const {
+  return ::google::protobuf::Arena::CreateMessage<GradientDef>(arena);
+}
+
+void GradientDef::Clear() {
+// @@protoc_insertion_point(message_clear_start:tensorflow.GradientDef)
+  function_name_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+  gradient_func_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+
+bool GradientDef::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
+  ::google::protobuf::uint32 tag;
+  // @@protoc_insertion_point(parse_start:tensorflow.GradientDef)
+  for (;;) {
+    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+    tag = p.first;
+    if (!p.second) goto handle_unusual;
+    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+      // optional string function_name = 1;
+      case 1: {
+        if (tag == 10) {
+          DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+                input, this->mutable_function_name()));
+          DO_(::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+            this->function_name().data(), this->function_name().length(),
+            ::google::protobuf::internal::WireFormatLite::PARSE,
+            "tensorflow.GradientDef.function_name"));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(18)) goto parse_gradient_func;
+        break;
+      }
+
+      // optional string gradient_func = 2;
+      case 2: {
+        if (tag == 18) {
+         parse_gradient_func:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+                input, this->mutable_gradient_func()));
+          DO_(::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+            this->gradient_func().data(), this->gradient_func().length(),
+            ::google::protobuf::internal::WireFormatLite::PARSE,
+            "tensorflow.GradientDef.gradient_func"));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectAtEnd()) goto success;
+        break;
+      }
+
+      default: {
+      handle_unusual:
+        if (tag == 0 ||
+            ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+          goto success;
+        }
+        DO_(::google::protobuf::internal::WireFormatLite::SkipField(input, tag));
+        break;
+      }
+    }
+  }
+success:
+  // @@protoc_insertion_point(parse_success:tensorflow.GradientDef)
+  return true;
+failure:
+  // @@protoc_insertion_point(parse_failure:tensorflow.GradientDef)
+  return false;
+#undef DO_
+}
+
+void GradientDef::SerializeWithCachedSizes(
+    ::google::protobuf::io::CodedOutputStream* output) const {
+  // @@protoc_insertion_point(serialize_start:tensorflow.GradientDef)
+  // optional string function_name = 1;
+  if (this->function_name().size() > 0) {
+    ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+      this->function_name().data(), this->function_name().length(),
+      ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+      "tensorflow.GradientDef.function_name");
+    ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
+      1, this->function_name(), output);
+  }
+
+  // optional string gradient_func = 2;
+  if (this->gradient_func().size() > 0) {
+    ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+      this->gradient_func().data(), this->gradient_func().length(),
+      ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+      "tensorflow.GradientDef.gradient_func");
+    ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
+      2, this->gradient_func(), output);
+  }
+
+  // @@protoc_insertion_point(serialize_end:tensorflow.GradientDef)
+}
+
+::google::protobuf::uint8* GradientDef::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
+  (void)deterministic; // Unused
+  // @@protoc_insertion_point(serialize_to_array_start:tensorflow.GradientDef)
+  // optional string function_name = 1;
+  if (this->function_name().size() > 0) {
+    ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+      this->function_name().data(), this->function_name().length(),
+      ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+      "tensorflow.GradientDef.function_name");
+    target =
+      ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
+        1, this->function_name(), target);
+  }
+
+  // optional string gradient_func = 2;
+  if (this->gradient_func().size() > 0) {
+    ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+      this->gradient_func().data(), this->gradient_func().length(),
+      ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+      "tensorflow.GradientDef.gradient_func");
+    target =
+      ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
+        2, this->gradient_func(), target);
+  }
+
+  // @@protoc_insertion_point(serialize_to_array_end:tensorflow.GradientDef)
+  return target;
+}
+
+size_t GradientDef::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:tensorflow.GradientDef)
+  size_t total_size = 0;
+
+  // optional string function_name = 1;
+  if (this->function_name().size() > 0) {
+    total_size += 1 +
+      ::google::protobuf::internal::WireFormatLite::StringSize(
+        this->function_name());
+  }
+
+  // optional string gradient_func = 2;
+  if (this->gradient_func().size() > 0) {
+    total_size += 1 +
+      ::google::protobuf::internal::WireFormatLite::StringSize(
+        this->gradient_func());
+  }
+
+  int cached_size = ::google::protobuf::internal::ToCachedSize(total_size);
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = cached_size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+  return total_size;
+}
+
+void GradientDef::MergeFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_merge_from_start:tensorflow.GradientDef)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const GradientDef* source =
+      ::google::protobuf::internal::DynamicCastToGenerated<const GradientDef>(
+          &from);
+  if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:tensorflow.GradientDef)
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:tensorflow.GradientDef)
+    UnsafeMergeFrom(*source);
+  }
+}
+
+void GradientDef::MergeFrom(const GradientDef& from) {
+// @@protoc_insertion_point(class_specific_merge_from_start:tensorflow.GradientDef)
+  if (GOOGLE_PREDICT_TRUE(&from != this)) {
+    UnsafeMergeFrom(from);
+  } else {
+    MergeFromFail(__LINE__);
+  }
+}
+
+void GradientDef::UnsafeMergeFrom(const GradientDef& from) {
+  GOOGLE_DCHECK(&from != this);
+  if (from.function_name().size() > 0) {
+    set_function_name(from.function_name());
+  }
+  if (from.gradient_func().size() > 0) {
+    set_gradient_func(from.gradient_func());
+  }
+}
+
+void GradientDef::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:tensorflow.GradientDef)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void GradientDef::CopyFrom(const GradientDef& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:tensorflow.GradientDef)
+  if (&from == this) return;
+  Clear();
+  UnsafeMergeFrom(from);
+}
+
+bool GradientDef::IsInitialized() const {
+
+  return true;
+}
+
+void GradientDef::Swap(GradientDef* other) {
+  if (other == this) return;
+  if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) {
+    InternalSwap(other);
+  } else {
+    GradientDef temp;
+    temp.UnsafeMergeFrom(*this);
+    CopyFrom(*other);
+    other->CopyFrom(temp);
+  }
+}
+void GradientDef::UnsafeArenaSwap(GradientDef* other) {
+  if (other == this) return;
+  GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual());
+  InternalSwap(other);
+}
+void GradientDef::InternalSwap(GradientDef* other) {
+  function_name_.Swap(&other->function_name_);
+  gradient_func_.Swap(&other->gradient_func_);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
+}
+
+::google::protobuf::Metadata GradientDef::GetMetadata() const {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::Metadata metadata;
+  metadata.descriptor = GradientDef_descriptor_;
+  metadata.reflection = GradientDef_reflection_;
+  return metadata;
+}
+
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// GradientDef
+
+// optional string function_name = 1;
+void GradientDef::clear_function_name() {
+  function_name_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+const ::std::string& GradientDef::function_name() const {
+  // @@protoc_insertion_point(field_get:tensorflow.GradientDef.function_name)
+  return function_name_.Get(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+void GradientDef::set_function_name(const ::std::string& value) {
+
+  function_name_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value, GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set:tensorflow.GradientDef.function_name)
+}
+void GradientDef::set_function_name(const char* value) {
+
+  function_name_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value),
+              GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_char:tensorflow.GradientDef.function_name)
+}
+void GradientDef::set_function_name(const char* value,
+    size_t size) {
+
+  function_name_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(
+      reinterpret_cast<const char*>(value), size), GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_pointer:tensorflow.GradientDef.function_name)
+}
+::std::string* GradientDef::mutable_function_name() {
+
+  // @@protoc_insertion_point(field_mutable:tensorflow.GradientDef.function_name)
+  return function_name_.Mutable(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+::std::string* GradientDef::release_function_name() {
+  // @@protoc_insertion_point(field_release:tensorflow.GradientDef.function_name)
+
+  return function_name_.Release(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+::std::string* GradientDef::unsafe_arena_release_function_name() {
+  // @@protoc_insertion_point(field_unsafe_arena_release:tensorflow.GradientDef.function_name)
+  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);
+
+  return function_name_.UnsafeArenaRelease(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      GetArenaNoVirtual());
+}
+void GradientDef::set_allocated_function_name(::std::string* function_name) {
+  if (function_name != NULL) {
+
+  } else {
+
+  }
+  function_name_.SetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), function_name,
+      GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_allocated:tensorflow.GradientDef.function_name)
+}
+void GradientDef::unsafe_arena_set_allocated_function_name(
+    ::std::string* function_name) {
+  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);
+  if (function_name != NULL) {
+
+  } else {
+
+  }
+  function_name_.UnsafeArenaSetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      function_name, GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_unsafe_arena_set_allocated:tensorflow.GradientDef.function_name)
+}
+
+// optional string gradient_func = 2;
+void GradientDef::clear_gradient_func() {
+  gradient_func_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+const ::std::string& GradientDef::gradient_func() const {
+  // @@protoc_insertion_point(field_get:tensorflow.GradientDef.gradient_func)
+  return gradient_func_.Get(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+void GradientDef::set_gradient_func(const ::std::string& value) {
+
+  gradient_func_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value, GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set:tensorflow.GradientDef.gradient_func)
+}
+void GradientDef::set_gradient_func(const char* value) {
+
+  gradient_func_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value),
+              GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_char:tensorflow.GradientDef.gradient_func)
+}
+void GradientDef::set_gradient_func(const char* value,
+    size_t size) {
+
+  gradient_func_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(
+      reinterpret_cast<const char*>(value), size), GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_pointer:tensorflow.GradientDef.gradient_func)
+}
+::std::string* GradientDef::mutable_gradient_func() {
+
+  // @@protoc_insertion_point(field_mutable:tensorflow.GradientDef.gradient_func)
+  return gradient_func_.Mutable(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+::std::string* GradientDef::release_gradient_func() {
+  // @@protoc_insertion_point(field_release:tensorflow.GradientDef.gradient_func)
+
+  return gradient_func_.Release(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+::std::string* GradientDef::unsafe_arena_release_gradient_func() {
+  // @@protoc_insertion_point(field_unsafe_arena_release:tensorflow.GradientDef.gradient_func)
+  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);
+
+  return gradient_func_.UnsafeArenaRelease(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      GetArenaNoVirtual());
+}
+void GradientDef::set_allocated_gradient_func(::std::string* gradient_func) {
+  if (gradient_func != NULL) {
+
+  } else {
+
+  }
+  gradient_func_.SetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), gradient_func,
+      GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_allocated:tensorflow.GradientDef.gradient_func)
+}
+void GradientDef::unsafe_arena_set_allocated_gradient_func(
+    ::std::string* gradient_func) {
+  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);
+  if (gradient_func != NULL) {
+
+  } else {
+
+  }
+  gradient_func_.UnsafeArenaSetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      gradient_func, GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_unsafe_arena_set_allocated:tensorflow.GradientDef.gradient_func)
+}
+
+inline const GradientDef* GradientDef::internal_default_instance() {
+  return &GradientDef_default_instance_.get();
+}
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
+
+// @@protoc_insertion_point(namespace_scope)
+
+}  // namespace tensorflow
+
+// @@protoc_insertion_point(global_scope)
diff --git a/contrib/modules/dnn/misc/tensorflow/function.pb.h b/contrib/modules/dnn/misc/tensorflow/function.pb.h
new file mode 100644
index 0000000..3f89687
--- /dev/null
+++ b/contrib/modules/dnn/misc/tensorflow/function.pb.h
@@ -0,0 +1,1160 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: function.proto
+
+#ifndef PROTOBUF_function_2eproto__INCLUDED
+#define PROTOBUF_function_2eproto__INCLUDED
+
+#include <string>
+
+#include <google/protobuf/stubs/common.h>
+
+#if GOOGLE_PROTOBUF_VERSION < 3001000
+#error This file was generated by a newer version of protoc which is
+#error incompatible with your Protocol Buffer headers.  Please update
+#error your headers.
+#endif
+#if 3001000 < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION
+#error This file was generated by an older version of protoc which is
+#error incompatible with your Protocol Buffer headers.  Please
+#error regenerate this file with a newer version of protoc.
+#endif
+
+#include <google/protobuf/arena.h>
+#include <google/protobuf/arenastring.h>
+#include <google/protobuf/generated_message_util.h>
+#include <google/protobuf/metadata.h>
+#include <google/protobuf/message.h>
+#include <google/protobuf/repeated_field.h>
+#include <google/protobuf/extension_set.h>
+#include <google/protobuf/map.h>
+#include <google/protobuf/map_field_inl.h>
+#include <google/protobuf/unknown_field_set.h>
+#include "attr_value.pb.h"
+#include "op_def.pb.h"
+// @@protoc_insertion_point(includes)
+
+namespace tensorflow {
+
+// Internal implementation detail -- do not call these.
+void protobuf_AddDesc_function_2eproto();
+void protobuf_InitDefaults_function_2eproto();
+void protobuf_AssignDesc_function_2eproto();
+void protobuf_ShutdownFile_function_2eproto();
+
+class FunctionDef;
+class FunctionDefLibrary;
+class FunctionDef_Node;
+class GradientDef;
+
+// ===================================================================
+
+class FunctionDefLibrary : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:tensorflow.FunctionDefLibrary) */ {
+ public:
+  FunctionDefLibrary();
+  virtual ~FunctionDefLibrary();
+
+  FunctionDefLibrary(const FunctionDefLibrary& from);
+
+  inline FunctionDefLibrary& operator=(const FunctionDefLibrary& from) {
+    CopyFrom(from);
+    return *this;
+  }
+
+  inline ::google::protobuf::Arena* GetArena() const { return GetArenaNoVirtual(); }
+  inline void* GetMaybeArenaPointer() const {
+    return MaybeArenaPtr();
+  }
+  static const ::google::protobuf::Descriptor* descriptor();
+  static const FunctionDefLibrary& default_instance();
+
+  static const FunctionDefLibrary* internal_default_instance();
+
+  void UnsafeArenaSwap(FunctionDefLibrary* other);
+  void Swap(FunctionDefLibrary* other);
+
+  // implements Message ----------------------------------------------
+
+  inline FunctionDefLibrary* New() const { return New(NULL); }
+
+  FunctionDefLibrary* New(::google::protobuf::Arena* arena) const;
+  void CopyFrom(const ::google::protobuf::Message& from);
+  void MergeFrom(const ::google::protobuf::Message& from);
+  void CopyFrom(const FunctionDefLibrary& from);
+  void MergeFrom(const FunctionDefLibrary& from);
+  void Clear();
+  bool IsInitialized() const;
+
+  size_t ByteSizeLong() const;
+  bool MergePartialFromCodedStream(
+      ::google::protobuf::io::CodedInputStream* input);
+  void SerializeWithCachedSizes(
+      ::google::protobuf::io::CodedOutputStream* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
+  int GetCachedSize() const { return _cached_size_; }
+  private:
+  void SharedCtor();
+  void SharedDtor();
+  void SetCachedSize(int size) const;
+  void InternalSwap(FunctionDefLibrary* other);
+  void UnsafeMergeFrom(const FunctionDefLibrary& from);
+  protected:
+  explicit FunctionDefLibrary(::google::protobuf::Arena* arena);
+  private:
+  static void ArenaDtor(void* object);
+  inline void RegisterArenaDtor(::google::protobuf::Arena* arena);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
+  public:
+
+  ::google::protobuf::Metadata GetMetadata() const;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  // repeated .tensorflow.FunctionDef function = 1;
+  int function_size() const;
+  void clear_function();
+  static const int kFunctionFieldNumber = 1;
+  const ::tensorflow::FunctionDef& function(int index) const;
+  ::tensorflow::FunctionDef* mutable_function(int index);
+  ::tensorflow::FunctionDef* add_function();
+  ::google::protobuf::RepeatedPtrField< ::tensorflow::FunctionDef >*
+      mutable_function();
+  const ::google::protobuf::RepeatedPtrField< ::tensorflow::FunctionDef >&
+      function() const;
+
+  // repeated .tensorflow.GradientDef gradient = 2;
+  int gradient_size() const;
+  void clear_gradient();
+  static const int kGradientFieldNumber = 2;
+  const ::tensorflow::GradientDef& gradient(int index) const;
+  ::tensorflow::GradientDef* mutable_gradient(int index);
+  ::tensorflow::GradientDef* add_gradient();
+  ::google::protobuf::RepeatedPtrField< ::tensorflow::GradientDef >*
+      mutable_gradient();
+  const ::google::protobuf::RepeatedPtrField< ::tensorflow::GradientDef >&
+      gradient() const;
+
+  // @@protoc_insertion_point(class_scope:tensorflow.FunctionDefLibrary)
+ private:
+
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  friend class ::google::protobuf::Arena;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  ::google::protobuf::RepeatedPtrField< ::tensorflow::FunctionDef > function_;
+  ::google::protobuf::RepeatedPtrField< ::tensorflow::GradientDef > gradient_;
+  mutable int _cached_size_;
+  friend void  protobuf_InitDefaults_function_2eproto_impl();
+  friend void  protobuf_AddDesc_function_2eproto_impl();
+  friend void protobuf_AssignDesc_function_2eproto();
+  friend void protobuf_ShutdownFile_function_2eproto();
+
+  void InitAsDefaultInstance();
+};
+extern ::google::protobuf::internal::ExplicitlyConstructed<FunctionDefLibrary> FunctionDefLibrary_default_instance_;
+
+// -------------------------------------------------------------------
+
+class FunctionDef_Node : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:tensorflow.FunctionDef.Node) */ {
+ public:
+  FunctionDef_Node();
+  virtual ~FunctionDef_Node();
+
+  FunctionDef_Node(const FunctionDef_Node& from);
+
+  inline FunctionDef_Node& operator=(const FunctionDef_Node& from) {
+    CopyFrom(from);
+    return *this;
+  }
+
+  inline ::google::protobuf::Arena* GetArena() const { return GetArenaNoVirtual(); }
+  inline void* GetMaybeArenaPointer() const {
+    return MaybeArenaPtr();
+  }
+  static const ::google::protobuf::Descriptor* descriptor();
+  static const FunctionDef_Node& default_instance();
+
+  static const FunctionDef_Node* internal_default_instance();
+
+  void UnsafeArenaSwap(FunctionDef_Node* other);
+  void Swap(FunctionDef_Node* other);
+
+  // implements Message ----------------------------------------------
+
+  inline FunctionDef_Node* New() const { return New(NULL); }
+
+  FunctionDef_Node* New(::google::protobuf::Arena* arena) const;
+  void CopyFrom(const ::google::protobuf::Message& from);
+  void MergeFrom(const ::google::protobuf::Message& from);
+  void CopyFrom(const FunctionDef_Node& from);
+  void MergeFrom(const FunctionDef_Node& from);
+  void Clear();
+  bool IsInitialized() const;
+
+  size_t ByteSizeLong() const;
+  bool MergePartialFromCodedStream(
+      ::google::protobuf::io::CodedInputStream* input);
+  void SerializeWithCachedSizes(
+      ::google::protobuf::io::CodedOutputStream* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
+  int GetCachedSize() const { return _cached_size_; }
+  private:
+  void SharedCtor();
+  void SharedDtor();
+  void SetCachedSize(int size) const;
+  void InternalSwap(FunctionDef_Node* other);
+  void UnsafeMergeFrom(const FunctionDef_Node& from);
+  protected:
+  explicit FunctionDef_Node(::google::protobuf::Arena* arena);
+  private:
+  static void ArenaDtor(void* object);
+  inline void RegisterArenaDtor(::google::protobuf::Arena* arena);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
+  public:
+
+  ::google::protobuf::Metadata GetMetadata() const;
+
+  // nested types ----------------------------------------------------
+
+
+  // accessors -------------------------------------------------------
+
+  // repeated string ret = 1;
+  int ret_size() const;
+  void clear_ret();
+  static const int kRetFieldNumber = 1;
+  const ::std::string& ret(int index) const;
+  ::std::string* mutable_ret(int index);
+  void set_ret(int index, const ::std::string& value);
+  void set_ret(int index, const char* value);
+  void set_ret(int index, const char* value, size_t size);
+  ::std::string* add_ret();
+  void add_ret(const ::std::string& value);
+  void add_ret(const char* value);
+  void add_ret(const char* value, size_t size);
+  const ::google::protobuf::RepeatedPtrField< ::std::string>& ret() const;
+  ::google::protobuf::RepeatedPtrField< ::std::string>* mutable_ret();
+
+  // optional string op = 2;
+  void clear_op();
+  static const int kOpFieldNumber = 2;
+  const ::std::string& op() const;
+  void set_op(const ::std::string& value);
+  void set_op(const char* value);
+  void set_op(const char* value, size_t size);
+  ::std::string* mutable_op();
+  ::std::string* release_op();
+  void set_allocated_op(::std::string* op);
+  ::std::string* unsafe_arena_release_op();
+  void unsafe_arena_set_allocated_op(
+      ::std::string* op);
+
+  // repeated string arg = 3;
+  int arg_size() const;
+  void clear_arg();
+  static const int kArgFieldNumber = 3;
+  const ::std::string& arg(int index) const;
+  ::std::string* mutable_arg(int index);
+  void set_arg(int index, const ::std::string& value);
+  void set_arg(int index, const char* value);
+  void set_arg(int index, const char* value, size_t size);
+  ::std::string* add_arg();
+  void add_arg(const ::std::string& value);
+  void add_arg(const char* value);
+  void add_arg(const char* value, size_t size);
+  const ::google::protobuf::RepeatedPtrField< ::std::string>& arg() const;
+  ::google::protobuf::RepeatedPtrField< ::std::string>* mutable_arg();
+
+  // repeated string dep = 4;
+  int dep_size() const;
+  void clear_dep();
+  static const int kDepFieldNumber = 4;
+  const ::std::string& dep(int index) const;
+  ::std::string* mutable_dep(int index);
+  void set_dep(int index, const ::std::string& value);
+  void set_dep(int index, const char* value);
+  void set_dep(int index, const char* value, size_t size);
+  ::std::string* add_dep();
+  void add_dep(const ::std::string& value);
+  void add_dep(const char* value);
+  void add_dep(const char* value, size_t size);
+  const ::google::protobuf::RepeatedPtrField< ::std::string>& dep() const;
+  ::google::protobuf::RepeatedPtrField< ::std::string>* mutable_dep();
+
+  // map<string, .tensorflow.AttrValue> attr = 5;
+  int attr_size() const;
+  void clear_attr();
+  static const int kAttrFieldNumber = 5;
+  const ::google::protobuf::Map< ::std::string, ::tensorflow::AttrValue >&
+      attr() const;
+  ::google::protobuf::Map< ::std::string, ::tensorflow::AttrValue >*
+      mutable_attr();
+
+  // @@protoc_insertion_point(class_scope:tensorflow.FunctionDef.Node)
+ private:
+
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  friend class ::google::protobuf::Arena;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  ::google::protobuf::RepeatedPtrField< ::std::string> ret_;
+  ::google::protobuf::RepeatedPtrField< ::std::string> arg_;
+  ::google::protobuf::RepeatedPtrField< ::std::string> dep_;
+  typedef ::google::protobuf::internal::MapEntryLite<
+      ::std::string, ::tensorflow::AttrValue,
+      ::google::protobuf::internal::WireFormatLite::TYPE_STRING,
+      ::google::protobuf::internal::WireFormatLite::TYPE_MESSAGE,
+      0 >
+      FunctionDef_Node_AttrEntry;
+  ::google::protobuf::internal::MapField<
+      ::std::string, ::tensorflow::AttrValue,
+      ::google::protobuf::internal::WireFormatLite::TYPE_STRING,
+      ::google::protobuf::internal::WireFormatLite::TYPE_MESSAGE,
+      0 > attr_;
+  ::google::protobuf::internal::ArenaStringPtr op_;
+  mutable int _cached_size_;
+  friend void  protobuf_InitDefaults_function_2eproto_impl();
+  friend void  protobuf_AddDesc_function_2eproto_impl();
+  friend void protobuf_AssignDesc_function_2eproto();
+  friend void protobuf_ShutdownFile_function_2eproto();
+
+  void InitAsDefaultInstance();
+};
+extern ::google::protobuf::internal::ExplicitlyConstructed<FunctionDef_Node> FunctionDef_Node_default_instance_;
+
+// -------------------------------------------------------------------
+
+class FunctionDef : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:tensorflow.FunctionDef) */ {
+ public:
+  FunctionDef();
+  virtual ~FunctionDef();
+
+  FunctionDef(const FunctionDef& from);
+
+  inline FunctionDef& operator=(const FunctionDef& from) {
+    CopyFrom(from);
+    return *this;
+  }
+
+  inline ::google::protobuf::Arena* GetArena() const { return GetArenaNoVirtual(); }
+  inline void* GetMaybeArenaPointer() const {
+    return MaybeArenaPtr();
+  }
+  static const ::google::protobuf::Descriptor* descriptor();
+  static const FunctionDef& default_instance();
+
+  static const FunctionDef* internal_default_instance();
+
+  void UnsafeArenaSwap(FunctionDef* other);
+  void Swap(FunctionDef* other);
+
+  // implements Message ----------------------------------------------
+
+  inline FunctionDef* New() const { return New(NULL); }
+
+  FunctionDef* New(::google::protobuf::Arena* arena) const;
+  void CopyFrom(const ::google::protobuf::Message& from);
+  void MergeFrom(const ::google::protobuf::Message& from);
+  void CopyFrom(const FunctionDef& from);
+  void MergeFrom(const FunctionDef& from);
+  void Clear();
+  bool IsInitialized() const;
+
+  size_t ByteSizeLong() const;
+  bool MergePartialFromCodedStream(
+      ::google::protobuf::io::CodedInputStream* input);
+  void SerializeWithCachedSizes(
+      ::google::protobuf::io::CodedOutputStream* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
+  int GetCachedSize() const { return _cached_size_; }
+  private:
+  void SharedCtor();
+  void SharedDtor();
+  void SetCachedSize(int size) const;
+  void InternalSwap(FunctionDef* other);
+  void UnsafeMergeFrom(const FunctionDef& from);
+  protected:
+  explicit FunctionDef(::google::protobuf::Arena* arena);
+  private:
+  static void ArenaDtor(void* object);
+  inline void RegisterArenaDtor(::google::protobuf::Arena* arena);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
+  public:
+
+  ::google::protobuf::Metadata GetMetadata() const;
+
+  // nested types ----------------------------------------------------
+
+  typedef FunctionDef_Node Node;
+
+  // accessors -------------------------------------------------------
+
+  // optional .tensorflow.OpDef signature = 1;
+  bool has_signature() const;
+  void clear_signature();
+  static const int kSignatureFieldNumber = 1;
+  private:
+  void _slow_mutable_signature();
+  void _slow_set_allocated_signature(
+      ::google::protobuf::Arena* message_arena, ::tensorflow::OpDef** signature);
+  ::tensorflow::OpDef* _slow_release_signature();
+  public:
+  const ::tensorflow::OpDef& signature() const;
+  ::tensorflow::OpDef* mutable_signature();
+  ::tensorflow::OpDef* release_signature();
+  void set_allocated_signature(::tensorflow::OpDef* signature);
+  ::tensorflow::OpDef* unsafe_arena_release_signature();
+  void unsafe_arena_set_allocated_signature(
+      ::tensorflow::OpDef* signature);
+
+  // repeated .tensorflow.FunctionDef.Node node = 2;
+  int node_size() const;
+  void clear_node();
+  static const int kNodeFieldNumber = 2;
+  const ::tensorflow::FunctionDef_Node& node(int index) const;
+  ::tensorflow::FunctionDef_Node* mutable_node(int index);
+  ::tensorflow::FunctionDef_Node* add_node();
+  ::google::protobuf::RepeatedPtrField< ::tensorflow::FunctionDef_Node >*
+      mutable_node();
+  const ::google::protobuf::RepeatedPtrField< ::tensorflow::FunctionDef_Node >&
+      node() const;
+
+  // @@protoc_insertion_point(class_scope:tensorflow.FunctionDef)
+ private:
+
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  friend class ::google::protobuf::Arena;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  ::google::protobuf::RepeatedPtrField< ::tensorflow::FunctionDef_Node > node_;
+  ::tensorflow::OpDef* signature_;
+  mutable int _cached_size_;
+  friend void  protobuf_InitDefaults_function_2eproto_impl();
+  friend void  protobuf_AddDesc_function_2eproto_impl();
+  friend void protobuf_AssignDesc_function_2eproto();
+  friend void protobuf_ShutdownFile_function_2eproto();
+
+  void InitAsDefaultInstance();
+};
+extern ::google::protobuf::internal::ExplicitlyConstructed<FunctionDef> FunctionDef_default_instance_;
+
+// -------------------------------------------------------------------
+
+class GradientDef : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:tensorflow.GradientDef) */ {
+ public:
+  GradientDef();
+  virtual ~GradientDef();
+
+  GradientDef(const GradientDef& from);
+
+  inline GradientDef& operator=(const GradientDef& from) {
+    CopyFrom(from);
+    return *this;
+  }
+
+  inline ::google::protobuf::Arena* GetArena() const { return GetArenaNoVirtual(); }
+  inline void* GetMaybeArenaPointer() const {
+    return MaybeArenaPtr();
+  }
+  static const ::google::protobuf::Descriptor* descriptor();
+  static const GradientDef& default_instance();
+
+  static const GradientDef* internal_default_instance();
+
+  void UnsafeArenaSwap(GradientDef* other);
+  void Swap(GradientDef* other);
+
+  // implements Message ----------------------------------------------
+
+  inline GradientDef* New() const { return New(NULL); }
+
+  GradientDef* New(::google::protobuf::Arena* arena) const;
+  void CopyFrom(const ::google::protobuf::Message& from);
+  void MergeFrom(const ::google::protobuf::Message& from);
+  void CopyFrom(const GradientDef& from);
+  void MergeFrom(const GradientDef& from);
+  void Clear();
+  bool IsInitialized() const;
+
+  size_t ByteSizeLong() const;
+  bool MergePartialFromCodedStream(
+      ::google::protobuf::io::CodedInputStream* input);
+  void SerializeWithCachedSizes(
+      ::google::protobuf::io::CodedOutputStream* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
+  int GetCachedSize() const { return _cached_size_; }
+  private:
+  void SharedCtor();
+  void SharedDtor();
+  void SetCachedSize(int size) const;
+  void InternalSwap(GradientDef* other);
+  void UnsafeMergeFrom(const GradientDef& from);
+  protected:
+  explicit GradientDef(::google::protobuf::Arena* arena);
+  private:
+  static void ArenaDtor(void* object);
+  inline void RegisterArenaDtor(::google::protobuf::Arena* arena);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
+  public:
+
+  ::google::protobuf::Metadata GetMetadata() const;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  // optional string function_name = 1;
+  void clear_function_name();
+  static const int kFunctionNameFieldNumber = 1;
+  const ::std::string& function_name() const;
+  void set_function_name(const ::std::string& value);
+  void set_function_name(const char* value);
+  void set_function_name(const char* value, size_t size);
+  ::std::string* mutable_function_name();
+  ::std::string* release_function_name();
+  void set_allocated_function_name(::std::string* function_name);
+  ::std::string* unsafe_arena_release_function_name();
+  void unsafe_arena_set_allocated_function_name(
+      ::std::string* function_name);
+
+  // optional string gradient_func = 2;
+  void clear_gradient_func();
+  static const int kGradientFuncFieldNumber = 2;
+  const ::std::string& gradient_func() const;
+  void set_gradient_func(const ::std::string& value);
+  void set_gradient_func(const char* value);
+  void set_gradient_func(const char* value, size_t size);
+  ::std::string* mutable_gradient_func();
+  ::std::string* release_gradient_func();
+  void set_allocated_gradient_func(::std::string* gradient_func);
+  ::std::string* unsafe_arena_release_gradient_func();
+  void unsafe_arena_set_allocated_gradient_func(
+      ::std::string* gradient_func);
+
+  // @@protoc_insertion_point(class_scope:tensorflow.GradientDef)
+ private:
+
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  friend class ::google::protobuf::Arena;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  ::google::protobuf::internal::ArenaStringPtr function_name_;
+  ::google::protobuf::internal::ArenaStringPtr gradient_func_;
+  mutable int _cached_size_;
+  friend void  protobuf_InitDefaults_function_2eproto_impl();
+  friend void  protobuf_AddDesc_function_2eproto_impl();
+  friend void protobuf_AssignDesc_function_2eproto();
+  friend void protobuf_ShutdownFile_function_2eproto();
+
+  void InitAsDefaultInstance();
+};
+extern ::google::protobuf::internal::ExplicitlyConstructed<GradientDef> GradientDef_default_instance_;
+
+// ===================================================================
+
+
+// ===================================================================
+
+#if !PROTOBUF_INLINE_NOT_IN_HEADERS
+// FunctionDefLibrary
+
+// repeated .tensorflow.FunctionDef function = 1;
+inline int FunctionDefLibrary::function_size() const {
+  return function_.size();
+}
+inline void FunctionDefLibrary::clear_function() {
+  function_.Clear();
+}
+inline const ::tensorflow::FunctionDef& FunctionDefLibrary::function(int index) const {
+  // @@protoc_insertion_point(field_get:tensorflow.FunctionDefLibrary.function)
+  return function_.Get(index);
+}
+inline ::tensorflow::FunctionDef* FunctionDefLibrary::mutable_function(int index) {
+  // @@protoc_insertion_point(field_mutable:tensorflow.FunctionDefLibrary.function)
+  return function_.Mutable(index);
+}
+inline ::tensorflow::FunctionDef* FunctionDefLibrary::add_function() {
+  // @@protoc_insertion_point(field_add:tensorflow.FunctionDefLibrary.function)
+  return function_.Add();
+}
+inline ::google::protobuf::RepeatedPtrField< ::tensorflow::FunctionDef >*
+FunctionDefLibrary::mutable_function() {
+  // @@protoc_insertion_point(field_mutable_list:tensorflow.FunctionDefLibrary.function)
+  return &function_;
+}
+inline const ::google::protobuf::RepeatedPtrField< ::tensorflow::FunctionDef >&
+FunctionDefLibrary::function() const {
+  // @@protoc_insertion_point(field_list:tensorflow.FunctionDefLibrary.function)
+  return function_;
+}
+
+// repeated .tensorflow.GradientDef gradient = 2;
+inline int FunctionDefLibrary::gradient_size() const {
+  return gradient_.size();
+}
+inline void FunctionDefLibrary::clear_gradient() {
+  gradient_.Clear();
+}
+inline const ::tensorflow::GradientDef& FunctionDefLibrary::gradient(int index) const {
+  // @@protoc_insertion_point(field_get:tensorflow.FunctionDefLibrary.gradient)
+  return gradient_.Get(index);
+}
+inline ::tensorflow::GradientDef* FunctionDefLibrary::mutable_gradient(int index) {
+  // @@protoc_insertion_point(field_mutable:tensorflow.FunctionDefLibrary.gradient)
+  return gradient_.Mutable(index);
+}
+inline ::tensorflow::GradientDef* FunctionDefLibrary::add_gradient() {
+  // @@protoc_insertion_point(field_add:tensorflow.FunctionDefLibrary.gradient)
+  return gradient_.Add();
+}
+inline ::google::protobuf::RepeatedPtrField< ::tensorflow::GradientDef >*
+FunctionDefLibrary::mutable_gradient() {
+  // @@protoc_insertion_point(field_mutable_list:tensorflow.FunctionDefLibrary.gradient)
+  return &gradient_;
+}
+inline const ::google::protobuf::RepeatedPtrField< ::tensorflow::GradientDef >&
+FunctionDefLibrary::gradient() const {
+  // @@protoc_insertion_point(field_list:tensorflow.FunctionDefLibrary.gradient)
+  return gradient_;
+}
+
+inline const FunctionDefLibrary* FunctionDefLibrary::internal_default_instance() {
+  return &FunctionDefLibrary_default_instance_.get();
+}
+// -------------------------------------------------------------------
+
+// FunctionDef_Node
+
+// repeated string ret = 1;
+inline int FunctionDef_Node::ret_size() const {
+  return ret_.size();
+}
+inline void FunctionDef_Node::clear_ret() {
+  ret_.Clear();
+}
+inline const ::std::string& FunctionDef_Node::ret(int index) const {
+  // @@protoc_insertion_point(field_get:tensorflow.FunctionDef.Node.ret)
+  return ret_.Get(index);
+}
+inline ::std::string* FunctionDef_Node::mutable_ret(int index) {
+  // @@protoc_insertion_point(field_mutable:tensorflow.FunctionDef.Node.ret)
+  return ret_.Mutable(index);
+}
+inline void FunctionDef_Node::set_ret(int index, const ::std::string& value) {
+  // @@protoc_insertion_point(field_set:tensorflow.FunctionDef.Node.ret)
+  ret_.Mutable(index)->assign(value);
+}
+inline void FunctionDef_Node::set_ret(int index, const char* value) {
+  ret_.Mutable(index)->assign(value);
+  // @@protoc_insertion_point(field_set_char:tensorflow.FunctionDef.Node.ret)
+}
+inline void FunctionDef_Node::set_ret(int index, const char* value, size_t size) {
+  ret_.Mutable(index)->assign(
+    reinterpret_cast<const char*>(value), size);
+  // @@protoc_insertion_point(field_set_pointer:tensorflow.FunctionDef.Node.ret)
+}
+inline ::std::string* FunctionDef_Node::add_ret() {
+  // @@protoc_insertion_point(field_add_mutable:tensorflow.FunctionDef.Node.ret)
+  return ret_.Add();
+}
+inline void FunctionDef_Node::add_ret(const ::std::string& value) {
+  ret_.Add()->assign(value);
+  // @@protoc_insertion_point(field_add:tensorflow.FunctionDef.Node.ret)
+}
+inline void FunctionDef_Node::add_ret(const char* value) {
+  ret_.Add()->assign(value);
+  // @@protoc_insertion_point(field_add_char:tensorflow.FunctionDef.Node.ret)
+}
+inline void FunctionDef_Node::add_ret(const char* value, size_t size) {
+  ret_.Add()->assign(reinterpret_cast<const char*>(value), size);
+  // @@protoc_insertion_point(field_add_pointer:tensorflow.FunctionDef.Node.ret)
+}
+inline const ::google::protobuf::RepeatedPtrField< ::std::string>&
+FunctionDef_Node::ret() const {
+  // @@protoc_insertion_point(field_list:tensorflow.FunctionDef.Node.ret)
+  return ret_;
+}
+inline ::google::protobuf::RepeatedPtrField< ::std::string>*
+FunctionDef_Node::mutable_ret() {
+  // @@protoc_insertion_point(field_mutable_list:tensorflow.FunctionDef.Node.ret)
+  return &ret_;
+}
+
+// optional string op = 2;
+inline void FunctionDef_Node::clear_op() {
+  op_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+inline const ::std::string& FunctionDef_Node::op() const {
+  // @@protoc_insertion_point(field_get:tensorflow.FunctionDef.Node.op)
+  return op_.Get(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void FunctionDef_Node::set_op(const ::std::string& value) {
+
+  op_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value, GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set:tensorflow.FunctionDef.Node.op)
+}
+inline void FunctionDef_Node::set_op(const char* value) {
+
+  op_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value),
+              GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_char:tensorflow.FunctionDef.Node.op)
+}
+inline void FunctionDef_Node::set_op(const char* value,
+    size_t size) {
+
+  op_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(
+      reinterpret_cast<const char*>(value), size), GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_pointer:tensorflow.FunctionDef.Node.op)
+}
+inline ::std::string* FunctionDef_Node::mutable_op() {
+
+  // @@protoc_insertion_point(field_mutable:tensorflow.FunctionDef.Node.op)
+  return op_.Mutable(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+inline ::std::string* FunctionDef_Node::release_op() {
+  // @@protoc_insertion_point(field_release:tensorflow.FunctionDef.Node.op)
+
+  return op_.Release(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+inline ::std::string* FunctionDef_Node::unsafe_arena_release_op() {
+  // @@protoc_insertion_point(field_unsafe_arena_release:tensorflow.FunctionDef.Node.op)
+  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);
+
+  return op_.UnsafeArenaRelease(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      GetArenaNoVirtual());
+}
+inline void FunctionDef_Node::set_allocated_op(::std::string* op) {
+  if (op != NULL) {
+
+  } else {
+
+  }
+  op_.SetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), op,
+      GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_allocated:tensorflow.FunctionDef.Node.op)
+}
+inline void FunctionDef_Node::unsafe_arena_set_allocated_op(
+    ::std::string* op) {
+  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);
+  if (op != NULL) {
+
+  } else {
+
+  }
+  op_.UnsafeArenaSetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      op, GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_unsafe_arena_set_allocated:tensorflow.FunctionDef.Node.op)
+}
+
+// repeated string arg = 3;
+inline int FunctionDef_Node::arg_size() const {
+  return arg_.size();
+}
+inline void FunctionDef_Node::clear_arg() {
+  arg_.Clear();
+}
+inline const ::std::string& FunctionDef_Node::arg(int index) const {
+  // @@protoc_insertion_point(field_get:tensorflow.FunctionDef.Node.arg)
+  return arg_.Get(index);
+}
+inline ::std::string* FunctionDef_Node::mutable_arg(int index) {
+  // @@protoc_insertion_point(field_mutable:tensorflow.FunctionDef.Node.arg)
+  return arg_.Mutable(index);
+}
+inline void FunctionDef_Node::set_arg(int index, const ::std::string& value) {
+  // @@protoc_insertion_point(field_set:tensorflow.FunctionDef.Node.arg)
+  arg_.Mutable(index)->assign(value);
+}
+inline void FunctionDef_Node::set_arg(int index, const char* value) {
+  arg_.Mutable(index)->assign(value);
+  // @@protoc_insertion_point(field_set_char:tensorflow.FunctionDef.Node.arg)
+}
+inline void FunctionDef_Node::set_arg(int index, const char* value, size_t size) {
+  arg_.Mutable(index)->assign(
+    reinterpret_cast<const char*>(value), size);
+  // @@protoc_insertion_point(field_set_pointer:tensorflow.FunctionDef.Node.arg)
+}
+inline ::std::string* FunctionDef_Node::add_arg() {
+  // @@protoc_insertion_point(field_add_mutable:tensorflow.FunctionDef.Node.arg)
+  return arg_.Add();
+}
+inline void FunctionDef_Node::add_arg(const ::std::string& value) {
+  arg_.Add()->assign(value);
+  // @@protoc_insertion_point(field_add:tensorflow.FunctionDef.Node.arg)
+}
+inline void FunctionDef_Node::add_arg(const char* value) {
+  arg_.Add()->assign(value);
+  // @@protoc_insertion_point(field_add_char:tensorflow.FunctionDef.Node.arg)
+}
+inline void FunctionDef_Node::add_arg(const char* value, size_t size) {
+  arg_.Add()->assign(reinterpret_cast<const char*>(value), size);
+  // @@protoc_insertion_point(field_add_pointer:tensorflow.FunctionDef.Node.arg)
+}
+inline const ::google::protobuf::RepeatedPtrField< ::std::string>&
+FunctionDef_Node::arg() const {
+  // @@protoc_insertion_point(field_list:tensorflow.FunctionDef.Node.arg)
+  return arg_;
+}
+inline ::google::protobuf::RepeatedPtrField< ::std::string>*
+FunctionDef_Node::mutable_arg() {
+  // @@protoc_insertion_point(field_mutable_list:tensorflow.FunctionDef.Node.arg)
+  return &arg_;
+}
+
+// repeated string dep = 4;
+inline int FunctionDef_Node::dep_size() const {
+  return dep_.size();
+}
+inline void FunctionDef_Node::clear_dep() {
+  dep_.Clear();
+}
+inline const ::std::string& FunctionDef_Node::dep(int index) const {
+  // @@protoc_insertion_point(field_get:tensorflow.FunctionDef.Node.dep)
+  return dep_.Get(index);
+}
+inline ::std::string* FunctionDef_Node::mutable_dep(int index) {
+  // @@protoc_insertion_point(field_mutable:tensorflow.FunctionDef.Node.dep)
+  return dep_.Mutable(index);
+}
+inline void FunctionDef_Node::set_dep(int index, const ::std::string& value) {
+  // @@protoc_insertion_point(field_set:tensorflow.FunctionDef.Node.dep)
+  dep_.Mutable(index)->assign(value);
+}
+inline void FunctionDef_Node::set_dep(int index, const char* value) {
+  dep_.Mutable(index)->assign(value);
+  // @@protoc_insertion_point(field_set_char:tensorflow.FunctionDef.Node.dep)
+}
+inline void FunctionDef_Node::set_dep(int index, const char* value, size_t size) {
+  dep_.Mutable(index)->assign(
+    reinterpret_cast<const char*>(value), size);
+  // @@protoc_insertion_point(field_set_pointer:tensorflow.FunctionDef.Node.dep)
+}
+inline ::std::string* FunctionDef_Node::add_dep() {
+  // @@protoc_insertion_point(field_add_mutable:tensorflow.FunctionDef.Node.dep)
+  return dep_.Add();
+}
+inline void FunctionDef_Node::add_dep(const ::std::string& value) {
+  dep_.Add()->assign(value);
+  // @@protoc_insertion_point(field_add:tensorflow.FunctionDef.Node.dep)
+}
+inline void FunctionDef_Node::add_dep(const char* value) {
+  dep_.Add()->assign(value);
+  // @@protoc_insertion_point(field_add_char:tensorflow.FunctionDef.Node.dep)
+}
+inline void FunctionDef_Node::add_dep(const char* value, size_t size) {
+  dep_.Add()->assign(reinterpret_cast<const char*>(value), size);
+  // @@protoc_insertion_point(field_add_pointer:tensorflow.FunctionDef.Node.dep)
+}
+inline const ::google::protobuf::RepeatedPtrField< ::std::string>&
+FunctionDef_Node::dep() const {
+  // @@protoc_insertion_point(field_list:tensorflow.FunctionDef.Node.dep)
+  return dep_;
+}
+inline ::google::protobuf::RepeatedPtrField< ::std::string>*
+FunctionDef_Node::mutable_dep() {
+  // @@protoc_insertion_point(field_mutable_list:tensorflow.FunctionDef.Node.dep)
+  return &dep_;
+}
+
+// map<string, .tensorflow.AttrValue> attr = 5;
+inline int FunctionDef_Node::attr_size() const {
+  return attr_.size();
+}
+inline void FunctionDef_Node::clear_attr() {
+  attr_.Clear();
+}
+inline const ::google::protobuf::Map< ::std::string, ::tensorflow::AttrValue >&
+FunctionDef_Node::attr() const {
+  // @@protoc_insertion_point(field_map:tensorflow.FunctionDef.Node.attr)
+  return attr_.GetMap();
+}
+inline ::google::protobuf::Map< ::std::string, ::tensorflow::AttrValue >*
+FunctionDef_Node::mutable_attr() {
+  // @@protoc_insertion_point(field_mutable_map:tensorflow.FunctionDef.Node.attr)
+  return attr_.MutableMap();
+}
+
+inline const FunctionDef_Node* FunctionDef_Node::internal_default_instance() {
+  return &FunctionDef_Node_default_instance_.get();
+}
+// -------------------------------------------------------------------
+
+// FunctionDef
+
+// optional .tensorflow.OpDef signature = 1;
+inline bool FunctionDef::has_signature() const {
+  return this != internal_default_instance() && signature_ != NULL;
+}
+inline void FunctionDef::clear_signature() {
+  if (GetArenaNoVirtual() == NULL && signature_ != NULL) delete signature_;
+  signature_ = NULL;
+}
+inline const ::tensorflow::OpDef& FunctionDef::signature() const {
+  // @@protoc_insertion_point(field_get:tensorflow.FunctionDef.signature)
+  return signature_ != NULL ? *signature_
+                         : *::tensorflow::OpDef::internal_default_instance();
+}
+inline ::tensorflow::OpDef* FunctionDef::mutable_signature() {
+
+  if (signature_ == NULL) {
+    _slow_mutable_signature();
+  }
+  // @@protoc_insertion_point(field_mutable:tensorflow.FunctionDef.signature)
+  return signature_;
+}
+inline ::tensorflow::OpDef* FunctionDef::release_signature() {
+  // @@protoc_insertion_point(field_release:tensorflow.FunctionDef.signature)
+
+  if (GetArenaNoVirtual() != NULL) {
+    return _slow_release_signature();
+  } else {
+    ::tensorflow::OpDef* temp = signature_;
+    signature_ = NULL;
+    return temp;
+  }
+}
+inline  void FunctionDef::set_allocated_signature(::tensorflow::OpDef* signature) {
+  ::google::protobuf::Arena* message_arena = GetArenaNoVirtual();
+  if (message_arena == NULL) {
+    delete signature_;
+  }
+  if (signature != NULL) {
+    _slow_set_allocated_signature(message_arena, &signature);
+  }
+  signature_ = signature;
+  if (signature) {
+
+  } else {
+
+  }
+  // @@protoc_insertion_point(field_set_allocated:tensorflow.FunctionDef.signature)
+}
+
+// repeated .tensorflow.FunctionDef.Node node = 2;
+inline int FunctionDef::node_size() const {
+  return node_.size();
+}
+inline void FunctionDef::clear_node() {
+  node_.Clear();
+}
+inline const ::tensorflow::FunctionDef_Node& FunctionDef::node(int index) const {
+  // @@protoc_insertion_point(field_get:tensorflow.FunctionDef.node)
+  return node_.Get(index);
+}
+inline ::tensorflow::FunctionDef_Node* FunctionDef::mutable_node(int index) {
+  // @@protoc_insertion_point(field_mutable:tensorflow.FunctionDef.node)
+  return node_.Mutable(index);
+}
+inline ::tensorflow::FunctionDef_Node* FunctionDef::add_node() {
+  // @@protoc_insertion_point(field_add:tensorflow.FunctionDef.node)
+  return node_.Add();
+}
+inline ::google::protobuf::RepeatedPtrField< ::tensorflow::FunctionDef_Node >*
+FunctionDef::mutable_node() {
+  // @@protoc_insertion_point(field_mutable_list:tensorflow.FunctionDef.node)
+  return &node_;
+}
+inline const ::google::protobuf::RepeatedPtrField< ::tensorflow::FunctionDef_Node >&
+FunctionDef::node() const {
+  // @@protoc_insertion_point(field_list:tensorflow.FunctionDef.node)
+  return node_;
+}
+
+inline const FunctionDef* FunctionDef::internal_default_instance() {
+  return &FunctionDef_default_instance_.get();
+}
+// -------------------------------------------------------------------
+
+// GradientDef
+
+// optional string function_name = 1;
+inline void GradientDef::clear_function_name() {
+  function_name_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+inline const ::std::string& GradientDef::function_name() const {
+  // @@protoc_insertion_point(field_get:tensorflow.GradientDef.function_name)
+  return function_name_.Get(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void GradientDef::set_function_name(const ::std::string& value) {
+
+  function_name_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value, GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set:tensorflow.GradientDef.function_name)
+}
+inline void GradientDef::set_function_name(const char* value) {
+
+  function_name_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value),
+              GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_char:tensorflow.GradientDef.function_name)
+}
+inline void GradientDef::set_function_name(const char* value,
+    size_t size) {
+
+  function_name_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(
+      reinterpret_cast<const char*>(value), size), GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_pointer:tensorflow.GradientDef.function_name)
+}
+inline ::std::string* GradientDef::mutable_function_name() {
+
+  // @@protoc_insertion_point(field_mutable:tensorflow.GradientDef.function_name)
+  return function_name_.Mutable(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+inline ::std::string* GradientDef::release_function_name() {
+  // @@protoc_insertion_point(field_release:tensorflow.GradientDef.function_name)
+
+  return function_name_.Release(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+inline ::std::string* GradientDef::unsafe_arena_release_function_name() {
+  // @@protoc_insertion_point(field_unsafe_arena_release:tensorflow.GradientDef.function_name)
+  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);
+
+  return function_name_.UnsafeArenaRelease(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      GetArenaNoVirtual());
+}
+inline void GradientDef::set_allocated_function_name(::std::string* function_name) {
+  if (function_name != NULL) {
+
+  } else {
+
+  }
+  function_name_.SetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), function_name,
+      GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_allocated:tensorflow.GradientDef.function_name)
+}
+inline void GradientDef::unsafe_arena_set_allocated_function_name(
+    ::std::string* function_name) {
+  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);
+  if (function_name != NULL) {
+
+  } else {
+
+  }
+  function_name_.UnsafeArenaSetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      function_name, GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_unsafe_arena_set_allocated:tensorflow.GradientDef.function_name)
+}
+
+// optional string gradient_func = 2;
+inline void GradientDef::clear_gradient_func() {
+  gradient_func_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+inline const ::std::string& GradientDef::gradient_func() const {
+  // @@protoc_insertion_point(field_get:tensorflow.GradientDef.gradient_func)
+  return gradient_func_.Get(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void GradientDef::set_gradient_func(const ::std::string& value) {
+
+  gradient_func_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value, GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set:tensorflow.GradientDef.gradient_func)
+}
+inline void GradientDef::set_gradient_func(const char* value) {
+
+  gradient_func_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value),
+              GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_char:tensorflow.GradientDef.gradient_func)
+}
+inline void GradientDef::set_gradient_func(const char* value,
+    size_t size) {
+
+  gradient_func_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(
+      reinterpret_cast<const char*>(value), size), GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_pointer:tensorflow.GradientDef.gradient_func)
+}
+inline ::std::string* GradientDef::mutable_gradient_func() {
+
+  // @@protoc_insertion_point(field_mutable:tensorflow.GradientDef.gradient_func)
+  return gradient_func_.Mutable(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+inline ::std::string* GradientDef::release_gradient_func() {
+  // @@protoc_insertion_point(field_release:tensorflow.GradientDef.gradient_func)
+
+  return gradient_func_.Release(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+inline ::std::string* GradientDef::unsafe_arena_release_gradient_func() {
+  // @@protoc_insertion_point(field_unsafe_arena_release:tensorflow.GradientDef.gradient_func)
+  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);
+
+  return gradient_func_.UnsafeArenaRelease(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      GetArenaNoVirtual());
+}
+inline void GradientDef::set_allocated_gradient_func(::std::string* gradient_func) {
+  if (gradient_func != NULL) {
+
+  } else {
+
+  }
+  gradient_func_.SetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), gradient_func,
+      GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_allocated:tensorflow.GradientDef.gradient_func)
+}
+inline void GradientDef::unsafe_arena_set_allocated_gradient_func(
+    ::std::string* gradient_func) {
+  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);
+  if (gradient_func != NULL) {
+
+  } else {
+
+  }
+  gradient_func_.UnsafeArenaSetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      gradient_func, GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_unsafe_arena_set_allocated:tensorflow.GradientDef.gradient_func)
+}
+
+inline const GradientDef* GradientDef::internal_default_instance() {
+  return &GradientDef_default_instance_.get();
+}
+#endif  // !PROTOBUF_INLINE_NOT_IN_HEADERS
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+
+// @@protoc_insertion_point(namespace_scope)
+
+}  // namespace tensorflow
+
+// @@protoc_insertion_point(global_scope)
+
+#endif  // PROTOBUF_function_2eproto__INCLUDED
diff --git a/contrib/modules/dnn/misc/tensorflow/graph.pb.cc b/contrib/modules/dnn/misc/tensorflow/graph.pb.cc
new file mode 100644
index 0000000..21cec2e
--- /dev/null
+++ b/contrib/modules/dnn/misc/tensorflow/graph.pb.cc
@@ -0,0 +1,1687 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: graph.proto
+
+#define INTERNAL_SUPPRESS_PROTOBUF_FIELD_DEPRECATION
+#include "graph.pb.h"
+
+#include <algorithm>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/port.h>
+#include <google/protobuf/stubs/once.h>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/wire_format_lite_inl.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/generated_message_reflection.h>
+#include <google/protobuf/reflection_ops.h>
+#include <google/protobuf/wire_format.h>
+// @@protoc_insertion_point(includes)
+
+namespace tensorflow {
+
+namespace {
+
+const ::google::protobuf::Descriptor* GraphDef_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+  GraphDef_reflection_ = NULL;
+const ::google::protobuf::Descriptor* NodeDef_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+  NodeDef_reflection_ = NULL;
+const ::google::protobuf::Descriptor* NodeDef_AttrEntry_descriptor_ = NULL;
+
+}  // namespace
+
+
+void protobuf_AssignDesc_graph_2eproto() GOOGLE_ATTRIBUTE_COLD;
+void protobuf_AssignDesc_graph_2eproto() {
+  protobuf_AddDesc_graph_2eproto();
+  const ::google::protobuf::FileDescriptor* file =
+    ::google::protobuf::DescriptorPool::generated_pool()->FindFileByName(
+      "graph.proto");
+  GOOGLE_CHECK(file != NULL);
+  GraphDef_descriptor_ = file->message_type(0);
+  static const int GraphDef_offsets_[4] = {
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(GraphDef, node_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(GraphDef, versions_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(GraphDef, version_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(GraphDef, library_),
+  };
+  GraphDef_reflection_ =
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
+      GraphDef_descriptor_,
+      GraphDef::internal_default_instance(),
+      GraphDef_offsets_,
+      -1,
+      -1,
+      -1,
+      sizeof(GraphDef),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(GraphDef, _internal_metadata_));
+  NodeDef_descriptor_ = file->message_type(1);
+  static const int NodeDef_offsets_[5] = {
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(NodeDef, name_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(NodeDef, op_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(NodeDef, input_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(NodeDef, device_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(NodeDef, attr_),
+  };
+  NodeDef_reflection_ =
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
+      NodeDef_descriptor_,
+      NodeDef::internal_default_instance(),
+      NodeDef_offsets_,
+      -1,
+      -1,
+      -1,
+      sizeof(NodeDef),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(NodeDef, _internal_metadata_));
+  NodeDef_AttrEntry_descriptor_ = NodeDef_descriptor_->nested_type(0);
+}
+
+namespace {
+
+GOOGLE_PROTOBUF_DECLARE_ONCE(protobuf_AssignDescriptors_once_);
+void protobuf_AssignDescriptorsOnce() {
+  ::google::protobuf::GoogleOnceInit(&protobuf_AssignDescriptors_once_,
+                 &protobuf_AssignDesc_graph_2eproto);
+}
+
+void protobuf_RegisterTypes(const ::std::string&) GOOGLE_ATTRIBUTE_COLD;
+void protobuf_RegisterTypes(const ::std::string&) {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+      GraphDef_descriptor_, GraphDef::internal_default_instance());
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+      NodeDef_descriptor_, NodeDef::internal_default_instance());
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+        NodeDef_AttrEntry_descriptor_,
+        ::google::protobuf::internal::MapEntry<
+            ::std::string,
+            ::tensorflow::AttrValue,
+            ::google::protobuf::internal::WireFormatLite::TYPE_STRING,
+            ::google::protobuf::internal::WireFormatLite::TYPE_MESSAGE,
+            0>::CreateDefaultInstance(
+                NodeDef_AttrEntry_descriptor_));
+}
+
+}  // namespace
+
+void protobuf_ShutdownFile_graph_2eproto() {
+  GraphDef_default_instance_.Shutdown();
+  delete GraphDef_reflection_;
+  NodeDef_default_instance_.Shutdown();
+  delete NodeDef_reflection_;
+}
+
+void protobuf_InitDefaults_graph_2eproto_impl() {
+  GOOGLE_PROTOBUF_VERIFY_VERSION;
+
+  ::tensorflow::protobuf_InitDefaults_attr_5fvalue_2eproto();
+  ::tensorflow::protobuf_InitDefaults_function_2eproto();
+  ::tensorflow::protobuf_InitDefaults_versions_2eproto();
+  GraphDef_default_instance_.DefaultConstruct();
+  ::google::protobuf::internal::GetEmptyString();
+  NodeDef_default_instance_.DefaultConstruct();
+  GraphDef_default_instance_.get_mutable()->InitAsDefaultInstance();
+  NodeDef_default_instance_.get_mutable()->InitAsDefaultInstance();
+}
+
+GOOGLE_PROTOBUF_DECLARE_ONCE(protobuf_InitDefaults_graph_2eproto_once_);
+void protobuf_InitDefaults_graph_2eproto() {
+  ::google::protobuf::GoogleOnceInit(&protobuf_InitDefaults_graph_2eproto_once_,
+                 &protobuf_InitDefaults_graph_2eproto_impl);
+}
+void protobuf_AddDesc_graph_2eproto_impl() {
+  GOOGLE_PROTOBUF_VERIFY_VERSION;
+
+  protobuf_InitDefaults_graph_2eproto();
+  ::google::protobuf::DescriptorPool::InternalAddGeneratedFile(
+    "\n\013graph.proto\022\ntensorflow\032\020attr_value.pr"
+    "oto\032\016function.proto\032\016versions.proto\"\235\001\n\010"
+    "GraphDef\022!\n\004node\030\001 \003(\0132\023.tensorflow.Node"
+    "Def\022(\n\010versions\030\004 \001(\0132\026.tensorflow.Versi"
+    "onDef\022\023\n\007version\030\003 \001(\005B\002\030\001\022/\n\007library\030\002 "
+    "\001(\0132\036.tensorflow.FunctionDefLibrary\"\263\001\n\007"
+    "NodeDef\022\014\n\004name\030\001 \001(\t\022\n\n\002op\030\002 \001(\t\022\r\n\005inp"
+    "ut\030\003 \003(\t\022\016\n\006device\030\004 \001(\t\022+\n\004attr\030\005 \003(\0132\035"
+    ".tensorflow.NodeDef.AttrEntry\032B\n\tAttrEnt"
+    "ry\022\013\n\003key\030\001 \001(\t\022$\n\005value\030\002 \001(\0132\025.tensorf"
+    "low.AttrValue:\0028\001B,\n\030org.tensorflow.fram"
+    "eworkB\013GraphProtosP\001\370\001\001b\006proto3", 471);
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedFile(
+    "graph.proto", &protobuf_RegisterTypes);
+  ::tensorflow::protobuf_AddDesc_attr_5fvalue_2eproto();
+  ::tensorflow::protobuf_AddDesc_function_2eproto();
+  ::tensorflow::protobuf_AddDesc_versions_2eproto();
+  ::google::protobuf::internal::OnShutdown(&protobuf_ShutdownFile_graph_2eproto);
+}
+
+GOOGLE_PROTOBUF_DECLARE_ONCE(protobuf_AddDesc_graph_2eproto_once_);
+void protobuf_AddDesc_graph_2eproto() {
+  ::google::protobuf::GoogleOnceInit(&protobuf_AddDesc_graph_2eproto_once_,
+                 &protobuf_AddDesc_graph_2eproto_impl);
+}
+// Force AddDescriptors() to be called at static initialization time.
+struct StaticDescriptorInitializer_graph_2eproto {
+  StaticDescriptorInitializer_graph_2eproto() {
+    protobuf_AddDesc_graph_2eproto();
+  }
+} static_descriptor_initializer_graph_2eproto_;
+
+namespace {
+
+static void MergeFromFail(int line) GOOGLE_ATTRIBUTE_COLD GOOGLE_ATTRIBUTE_NORETURN;
+static void MergeFromFail(int line) {
+  ::google::protobuf::internal::MergeFromFail(__FILE__, line);
+}
+
+}  // namespace
+
+
+// ===================================================================
+
+void GraphDef::_slow_mutable_versions() {
+  versions_ = ::google::protobuf::Arena::CreateMessage< ::tensorflow::VersionDef >(
+      GetArenaNoVirtual());
+}
+::tensorflow::VersionDef* GraphDef::_slow_release_versions() {
+  if (versions_ == NULL) {
+    return NULL;
+  } else {
+    ::tensorflow::VersionDef* temp = new ::tensorflow::VersionDef(*versions_);
+    versions_ = NULL;
+    return temp;
+  }
+}
+::tensorflow::VersionDef* GraphDef::unsafe_arena_release_versions() {
+  // @@protoc_insertion_point(field_unsafe_arena_release:tensorflow.GraphDef.versions)
+
+  ::tensorflow::VersionDef* temp = versions_;
+  versions_ = NULL;
+  return temp;
+}
+void GraphDef::_slow_set_allocated_versions(
+    ::google::protobuf::Arena* message_arena, ::tensorflow::VersionDef** versions) {
+    if (message_arena != NULL &&
+        ::google::protobuf::Arena::GetArena(*versions) == NULL) {
+      message_arena->Own(*versions);
+    } else if (message_arena !=
+               ::google::protobuf::Arena::GetArena(*versions)) {
+      ::tensorflow::VersionDef* new_versions =
+            ::google::protobuf::Arena::CreateMessage< ::tensorflow::VersionDef >(
+            message_arena);
+      new_versions->CopyFrom(**versions);
+      *versions = new_versions;
+    }
+}
+void GraphDef::unsafe_arena_set_allocated_versions(
+    ::tensorflow::VersionDef* versions) {
+  if (GetArenaNoVirtual() == NULL) {
+    delete versions_;
+  }
+  versions_ = versions;
+  if (versions) {
+
+  } else {
+
+  }
+  // @@protoc_insertion_point(field_unsafe_arena_set_allocated:tensorflow.GraphDef.versions)
+}
+void GraphDef::_slow_mutable_library() {
+  library_ = ::google::protobuf::Arena::CreateMessage< ::tensorflow::FunctionDefLibrary >(
+      GetArenaNoVirtual());
+}
+::tensorflow::FunctionDefLibrary* GraphDef::_slow_release_library() {
+  if (library_ == NULL) {
+    return NULL;
+  } else {
+    ::tensorflow::FunctionDefLibrary* temp = new ::tensorflow::FunctionDefLibrary(*library_);
+    library_ = NULL;
+    return temp;
+  }
+}
+::tensorflow::FunctionDefLibrary* GraphDef::unsafe_arena_release_library() {
+  // @@protoc_insertion_point(field_unsafe_arena_release:tensorflow.GraphDef.library)
+
+  ::tensorflow::FunctionDefLibrary* temp = library_;
+  library_ = NULL;
+  return temp;
+}
+void GraphDef::_slow_set_allocated_library(
+    ::google::protobuf::Arena* message_arena, ::tensorflow::FunctionDefLibrary** library) {
+    if (message_arena != NULL &&
+        ::google::protobuf::Arena::GetArena(*library) == NULL) {
+      message_arena->Own(*library);
+    } else if (message_arena !=
+               ::google::protobuf::Arena::GetArena(*library)) {
+      ::tensorflow::FunctionDefLibrary* new_library =
+            ::google::protobuf::Arena::CreateMessage< ::tensorflow::FunctionDefLibrary >(
+            message_arena);
+      new_library->CopyFrom(**library);
+      *library = new_library;
+    }
+}
+void GraphDef::unsafe_arena_set_allocated_library(
+    ::tensorflow::FunctionDefLibrary* library) {
+  if (GetArenaNoVirtual() == NULL) {
+    delete library_;
+  }
+  library_ = library;
+  if (library) {
+
+  } else {
+
+  }
+  // @@protoc_insertion_point(field_unsafe_arena_set_allocated:tensorflow.GraphDef.library)
+}
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const int GraphDef::kNodeFieldNumber;
+const int GraphDef::kVersionsFieldNumber;
+const int GraphDef::kVersionFieldNumber;
+const int GraphDef::kLibraryFieldNumber;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+
+GraphDef::GraphDef()
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+  if (this != internal_default_instance()) protobuf_InitDefaults_graph_2eproto();
+  SharedCtor();
+  // @@protoc_insertion_point(constructor:tensorflow.GraphDef)
+}
+GraphDef::GraphDef(::google::protobuf::Arena* arena)
+  : ::google::protobuf::Message(),
+  _internal_metadata_(arena),
+  node_(arena) {
+#ifdef GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER
+  protobuf_InitDefaults_graph_2eproto();
+#endif  // GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER
+  SharedCtor();
+  RegisterArenaDtor(arena);
+  // @@protoc_insertion_point(arena_constructor:tensorflow.GraphDef)
+}
+
+void GraphDef::InitAsDefaultInstance() {
+  versions_ = const_cast< ::tensorflow::VersionDef*>(
+      ::tensorflow::VersionDef::internal_default_instance());
+  library_ = const_cast< ::tensorflow::FunctionDefLibrary*>(
+      ::tensorflow::FunctionDefLibrary::internal_default_instance());
+}
+
+GraphDef::GraphDef(const GraphDef& from)
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
+  SharedCtor();
+  UnsafeMergeFrom(from);
+  // @@protoc_insertion_point(copy_constructor:tensorflow.GraphDef)
+}
+
+void GraphDef::SharedCtor() {
+  versions_ = NULL;
+  library_ = NULL;
+  version_ = 0;
+  _cached_size_ = 0;
+}
+
+GraphDef::~GraphDef() {
+  // @@protoc_insertion_point(destructor:tensorflow.GraphDef)
+  SharedDtor();
+}
+
+void GraphDef::SharedDtor() {
+  ::google::protobuf::Arena* arena = GetArenaNoVirtual();
+  if (arena != NULL) {
+    return;
+  }
+
+  if (this != &GraphDef_default_instance_.get()) {
+    delete versions_;
+    delete library_;
+  }
+}
+
+void GraphDef::ArenaDtor(void* object) {
+  GraphDef* _this = reinterpret_cast< GraphDef* >(object);
+  (void)_this;
+}
+void GraphDef::RegisterArenaDtor(::google::protobuf::Arena* arena) {
+}
+void GraphDef::SetCachedSize(int size) const {
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* GraphDef::descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return GraphDef_descriptor_;
+}
+
+const GraphDef& GraphDef::default_instance() {
+  protobuf_InitDefaults_graph_2eproto();
+  return *internal_default_instance();
+}
+
+::google::protobuf::internal::ExplicitlyConstructed<GraphDef> GraphDef_default_instance_;
+
+GraphDef* GraphDef::New(::google::protobuf::Arena* arena) const {
+  return ::google::protobuf::Arena::CreateMessage<GraphDef>(arena);
+}
+
+void GraphDef::Clear() {
+// @@protoc_insertion_point(message_clear_start:tensorflow.GraphDef)
+  if (GetArenaNoVirtual() == NULL && versions_ != NULL) delete versions_;
+  versions_ = NULL;
+  version_ = 0;
+  if (GetArenaNoVirtual() == NULL && library_ != NULL) delete library_;
+  library_ = NULL;
+  node_.Clear();
+}
+
+bool GraphDef::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
+  ::google::protobuf::uint32 tag;
+  // @@protoc_insertion_point(parse_start:tensorflow.GraphDef)
+  for (;;) {
+    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+    tag = p.first;
+    if (!p.second) goto handle_unusual;
+    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+      // repeated .tensorflow.NodeDef node = 1;
+      case 1: {
+        if (tag == 10) {
+          DO_(input->IncrementRecursionDepth());
+         parse_loop_node:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth(
+                input, add_node()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(10)) goto parse_loop_node;
+        input->UnsafeDecrementRecursionDepth();
+        if (input->ExpectTag(18)) goto parse_library;
+        break;
+      }
+
+      // optional .tensorflow.FunctionDefLibrary library = 2;
+      case 2: {
+        if (tag == 18) {
+         parse_library:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+               input, mutable_library()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(24)) goto parse_version;
+        break;
+      }
+
+      // optional int32 version = 3 [deprecated = true];
+      case 3: {
+        if (tag == 24) {
+         parse_version:
+
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
+                 input, &version_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(34)) goto parse_versions;
+        break;
+      }
+
+      // optional .tensorflow.VersionDef versions = 4;
+      case 4: {
+        if (tag == 34) {
+         parse_versions:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+               input, mutable_versions()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectAtEnd()) goto success;
+        break;
+      }
+
+      default: {
+      handle_unusual:
+        if (tag == 0 ||
+            ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+          goto success;
+        }
+        DO_(::google::protobuf::internal::WireFormatLite::SkipField(input, tag));
+        break;
+      }
+    }
+  }
+success:
+  // @@protoc_insertion_point(parse_success:tensorflow.GraphDef)
+  return true;
+failure:
+  // @@protoc_insertion_point(parse_failure:tensorflow.GraphDef)
+  return false;
+#undef DO_
+}
+
+void GraphDef::SerializeWithCachedSizes(
+    ::google::protobuf::io::CodedOutputStream* output) const {
+  // @@protoc_insertion_point(serialize_start:tensorflow.GraphDef)
+  // repeated .tensorflow.NodeDef node = 1;
+  for (unsigned int i = 0, n = this->node_size(); i < n; i++) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      1, this->node(i), output);
+  }
+
+  // optional .tensorflow.FunctionDefLibrary library = 2;
+  if (this->has_library()) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      2, *this->library_, output);
+  }
+
+  // optional int32 version = 3 [deprecated = true];
+  if (this->version() != 0) {
+    ::google::protobuf::internal::WireFormatLite::WriteInt32(3, this->version(), output);
+  }
+
+  // optional .tensorflow.VersionDef versions = 4;
+  if (this->has_versions()) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      4, *this->versions_, output);
+  }
+
+  // @@protoc_insertion_point(serialize_end:tensorflow.GraphDef)
+}
+
+::google::protobuf::uint8* GraphDef::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
+  (void)deterministic; // Unused
+  // @@protoc_insertion_point(serialize_to_array_start:tensorflow.GraphDef)
+  // repeated .tensorflow.NodeDef node = 1;
+  for (unsigned int i = 0, n = this->node_size(); i < n; i++) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        1, this->node(i), false, target);
+  }
+
+  // optional .tensorflow.FunctionDefLibrary library = 2;
+  if (this->has_library()) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        2, *this->library_, false, target);
+  }
+
+  // optional int32 version = 3 [deprecated = true];
+  if (this->version() != 0) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteInt32ToArray(3, this->version(), target);
+  }
+
+  // optional .tensorflow.VersionDef versions = 4;
+  if (this->has_versions()) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        4, *this->versions_, false, target);
+  }
+
+  // @@protoc_insertion_point(serialize_to_array_end:tensorflow.GraphDef)
+  return target;
+}
+
+size_t GraphDef::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:tensorflow.GraphDef)
+  size_t total_size = 0;
+
+  // optional .tensorflow.VersionDef versions = 4;
+  if (this->has_versions()) {
+    total_size += 1 +
+      ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+        *this->versions_);
+  }
+
+  // optional int32 version = 3 [deprecated = true];
+  if (this->version() != 0) {
+    total_size += 1 +
+      ::google::protobuf::internal::WireFormatLite::Int32Size(
+        this->version());
+  }
+
+  // optional .tensorflow.FunctionDefLibrary library = 2;
+  if (this->has_library()) {
+    total_size += 1 +
+      ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+        *this->library_);
+  }
+
+  // repeated .tensorflow.NodeDef node = 1;
+  {
+    unsigned int count = this->node_size();
+    total_size += 1UL * count;
+    for (unsigned int i = 0; i < count; i++) {
+      total_size +=
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          this->node(i));
+    }
+  }
+
+  int cached_size = ::google::protobuf::internal::ToCachedSize(total_size);
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = cached_size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+  return total_size;
+}
+
+void GraphDef::MergeFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_merge_from_start:tensorflow.GraphDef)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const GraphDef* source =
+      ::google::protobuf::internal::DynamicCastToGenerated<const GraphDef>(
+          &from);
+  if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:tensorflow.GraphDef)
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:tensorflow.GraphDef)
+    UnsafeMergeFrom(*source);
+  }
+}
+
+void GraphDef::MergeFrom(const GraphDef& from) {
+// @@protoc_insertion_point(class_specific_merge_from_start:tensorflow.GraphDef)
+  if (GOOGLE_PREDICT_TRUE(&from != this)) {
+    UnsafeMergeFrom(from);
+  } else {
+    MergeFromFail(__LINE__);
+  }
+}
+
+void GraphDef::UnsafeMergeFrom(const GraphDef& from) {
+  GOOGLE_DCHECK(&from != this);
+  node_.MergeFrom(from.node_);
+  if (from.has_versions()) {
+    mutable_versions()->::tensorflow::VersionDef::MergeFrom(from.versions());
+  }
+  if (from.version() != 0) {
+    set_version(from.version());
+  }
+  if (from.has_library()) {
+    mutable_library()->::tensorflow::FunctionDefLibrary::MergeFrom(from.library());
+  }
+}
+
+void GraphDef::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:tensorflow.GraphDef)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void GraphDef::CopyFrom(const GraphDef& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:tensorflow.GraphDef)
+  if (&from == this) return;
+  Clear();
+  UnsafeMergeFrom(from);
+}
+
+bool GraphDef::IsInitialized() const {
+
+  return true;
+}
+
+void GraphDef::Swap(GraphDef* other) {
+  if (other == this) return;
+  if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) {
+    InternalSwap(other);
+  } else {
+    GraphDef temp;
+    temp.UnsafeMergeFrom(*this);
+    CopyFrom(*other);
+    other->CopyFrom(temp);
+  }
+}
+void GraphDef::UnsafeArenaSwap(GraphDef* other) {
+  if (other == this) return;
+  GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual());
+  InternalSwap(other);
+}
+void GraphDef::InternalSwap(GraphDef* other) {
+  node_.UnsafeArenaSwap(&other->node_);
+  std::swap(versions_, other->versions_);
+  std::swap(version_, other->version_);
+  std::swap(library_, other->library_);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
+}
+
+::google::protobuf::Metadata GraphDef::GetMetadata() const {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::Metadata metadata;
+  metadata.descriptor = GraphDef_descriptor_;
+  metadata.reflection = GraphDef_reflection_;
+  return metadata;
+}
+
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// GraphDef
+
+// repeated .tensorflow.NodeDef node = 1;
+int GraphDef::node_size() const {
+  return node_.size();
+}
+void GraphDef::clear_node() {
+  node_.Clear();
+}
+const ::tensorflow::NodeDef& GraphDef::node(int index) const {
+  // @@protoc_insertion_point(field_get:tensorflow.GraphDef.node)
+  return node_.Get(index);
+}
+::tensorflow::NodeDef* GraphDef::mutable_node(int index) {
+  // @@protoc_insertion_point(field_mutable:tensorflow.GraphDef.node)
+  return node_.Mutable(index);
+}
+::tensorflow::NodeDef* GraphDef::add_node() {
+  // @@protoc_insertion_point(field_add:tensorflow.GraphDef.node)
+  return node_.Add();
+}
+::google::protobuf::RepeatedPtrField< ::tensorflow::NodeDef >*
+GraphDef::mutable_node() {
+  // @@protoc_insertion_point(field_mutable_list:tensorflow.GraphDef.node)
+  return &node_;
+}
+const ::google::protobuf::RepeatedPtrField< ::tensorflow::NodeDef >&
+GraphDef::node() const {
+  // @@protoc_insertion_point(field_list:tensorflow.GraphDef.node)
+  return node_;
+}
+
+// optional .tensorflow.VersionDef versions = 4;
+bool GraphDef::has_versions() const {
+  return this != internal_default_instance() && versions_ != NULL;
+}
+void GraphDef::clear_versions() {
+  if (GetArenaNoVirtual() == NULL && versions_ != NULL) delete versions_;
+  versions_ = NULL;
+}
+const ::tensorflow::VersionDef& GraphDef::versions() const {
+  // @@protoc_insertion_point(field_get:tensorflow.GraphDef.versions)
+  return versions_ != NULL ? *versions_
+                         : *::tensorflow::VersionDef::internal_default_instance();
+}
+::tensorflow::VersionDef* GraphDef::mutable_versions() {
+
+  if (versions_ == NULL) {
+    _slow_mutable_versions();
+  }
+  // @@protoc_insertion_point(field_mutable:tensorflow.GraphDef.versions)
+  return versions_;
+}
+::tensorflow::VersionDef* GraphDef::release_versions() {
+  // @@protoc_insertion_point(field_release:tensorflow.GraphDef.versions)
+
+  if (GetArenaNoVirtual() != NULL) {
+    return _slow_release_versions();
+  } else {
+    ::tensorflow::VersionDef* temp = versions_;
+    versions_ = NULL;
+    return temp;
+  }
+}
+ void GraphDef::set_allocated_versions(::tensorflow::VersionDef* versions) {
+  ::google::protobuf::Arena* message_arena = GetArenaNoVirtual();
+  if (message_arena == NULL) {
+    delete versions_;
+  }
+  if (versions != NULL) {
+    _slow_set_allocated_versions(message_arena, &versions);
+  }
+  versions_ = versions;
+  if (versions) {
+
+  } else {
+
+  }
+  // @@protoc_insertion_point(field_set_allocated:tensorflow.GraphDef.versions)
+}
+
+// optional int32 version = 3 [deprecated = true];
+void GraphDef::clear_version() {
+  version_ = 0;
+}
+::google::protobuf::int32 GraphDef::version() const {
+  // @@protoc_insertion_point(field_get:tensorflow.GraphDef.version)
+  return version_;
+}
+void GraphDef::set_version(::google::protobuf::int32 value) {
+
+  version_ = value;
+  // @@protoc_insertion_point(field_set:tensorflow.GraphDef.version)
+}
+
+// optional .tensorflow.FunctionDefLibrary library = 2;
+bool GraphDef::has_library() const {
+  return this != internal_default_instance() && library_ != NULL;
+}
+void GraphDef::clear_library() {
+  if (GetArenaNoVirtual() == NULL && library_ != NULL) delete library_;
+  library_ = NULL;
+}
+const ::tensorflow::FunctionDefLibrary& GraphDef::library() const {
+  // @@protoc_insertion_point(field_get:tensorflow.GraphDef.library)
+  return library_ != NULL ? *library_
+                         : *::tensorflow::FunctionDefLibrary::internal_default_instance();
+}
+::tensorflow::FunctionDefLibrary* GraphDef::mutable_library() {
+
+  if (library_ == NULL) {
+    _slow_mutable_library();
+  }
+  // @@protoc_insertion_point(field_mutable:tensorflow.GraphDef.library)
+  return library_;
+}
+::tensorflow::FunctionDefLibrary* GraphDef::release_library() {
+  // @@protoc_insertion_point(field_release:tensorflow.GraphDef.library)
+
+  if (GetArenaNoVirtual() != NULL) {
+    return _slow_release_library();
+  } else {
+    ::tensorflow::FunctionDefLibrary* temp = library_;
+    library_ = NULL;
+    return temp;
+  }
+}
+ void GraphDef::set_allocated_library(::tensorflow::FunctionDefLibrary* library) {
+  ::google::protobuf::Arena* message_arena = GetArenaNoVirtual();
+  if (message_arena == NULL) {
+    delete library_;
+  }
+  if (library != NULL) {
+    _slow_set_allocated_library(message_arena, &library);
+  }
+  library_ = library;
+  if (library) {
+
+  } else {
+
+  }
+  // @@protoc_insertion_point(field_set_allocated:tensorflow.GraphDef.library)
+}
+
+inline const GraphDef* GraphDef::internal_default_instance() {
+  return &GraphDef_default_instance_.get();
+}
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
+
+// ===================================================================
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const int NodeDef::kNameFieldNumber;
+const int NodeDef::kOpFieldNumber;
+const int NodeDef::kInputFieldNumber;
+const int NodeDef::kDeviceFieldNumber;
+const int NodeDef::kAttrFieldNumber;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+
+NodeDef::NodeDef()
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+  if (this != internal_default_instance()) protobuf_InitDefaults_graph_2eproto();
+  SharedCtor();
+  // @@protoc_insertion_point(constructor:tensorflow.NodeDef)
+}
+NodeDef::NodeDef(::google::protobuf::Arena* arena)
+  : ::google::protobuf::Message(),
+  _internal_metadata_(arena),
+  input_(arena),
+  attr_(arena) {
+#ifdef GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER
+  protobuf_InitDefaults_graph_2eproto();
+#endif  // GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER
+  SharedCtor();
+  RegisterArenaDtor(arena);
+  // @@protoc_insertion_point(arena_constructor:tensorflow.NodeDef)
+}
+
+void NodeDef::InitAsDefaultInstance() {
+}
+
+NodeDef::NodeDef(const NodeDef& from)
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
+  SharedCtor();
+  UnsafeMergeFrom(from);
+  // @@protoc_insertion_point(copy_constructor:tensorflow.NodeDef)
+}
+
+void NodeDef::SharedCtor() {
+  attr_.SetAssignDescriptorCallback(
+      protobuf_AssignDescriptorsOnce);
+  attr_.SetEntryDescriptor(
+      &::tensorflow::NodeDef_AttrEntry_descriptor_);
+  name_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  op_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  device_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  _cached_size_ = 0;
+}
+
+NodeDef::~NodeDef() {
+  // @@protoc_insertion_point(destructor:tensorflow.NodeDef)
+  SharedDtor();
+}
+
+void NodeDef::SharedDtor() {
+  ::google::protobuf::Arena* arena = GetArenaNoVirtual();
+  if (arena != NULL) {
+    return;
+  }
+
+  name_.Destroy(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), arena);
+  op_.Destroy(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), arena);
+  device_.Destroy(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), arena);
+}
+
+void NodeDef::ArenaDtor(void* object) {
+  NodeDef* _this = reinterpret_cast< NodeDef* >(object);
+  (void)_this;
+}
+void NodeDef::RegisterArenaDtor(::google::protobuf::Arena* arena) {
+}
+void NodeDef::SetCachedSize(int size) const {
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* NodeDef::descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return NodeDef_descriptor_;
+}
+
+const NodeDef& NodeDef::default_instance() {
+  protobuf_InitDefaults_graph_2eproto();
+  return *internal_default_instance();
+}
+
+::google::protobuf::internal::ExplicitlyConstructed<NodeDef> NodeDef_default_instance_;
+
+NodeDef* NodeDef::New(::google::protobuf::Arena* arena) const {
+  return ::google::protobuf::Arena::CreateMessage<NodeDef>(arena);
+}
+
+void NodeDef::Clear() {
+// @@protoc_insertion_point(message_clear_start:tensorflow.NodeDef)
+  name_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+  op_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+  device_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+  input_.Clear();
+  attr_.Clear();
+}
+
+bool NodeDef::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
+  ::google::protobuf::uint32 tag;
+  // @@protoc_insertion_point(parse_start:tensorflow.NodeDef)
+  for (;;) {
+    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+    tag = p.first;
+    if (!p.second) goto handle_unusual;
+    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+      // optional string name = 1;
+      case 1: {
+        if (tag == 10) {
+          DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+                input, this->mutable_name()));
+          DO_(::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+            this->name().data(), this->name().length(),
+            ::google::protobuf::internal::WireFormatLite::PARSE,
+            "tensorflow.NodeDef.name"));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(18)) goto parse_op;
+        break;
+      }
+
+      // optional string op = 2;
+      case 2: {
+        if (tag == 18) {
+         parse_op:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+                input, this->mutable_op()));
+          DO_(::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+            this->op().data(), this->op().length(),
+            ::google::protobuf::internal::WireFormatLite::PARSE,
+            "tensorflow.NodeDef.op"));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(26)) goto parse_input;
+        break;
+      }
+
+      // repeated string input = 3;
+      case 3: {
+        if (tag == 26) {
+         parse_input:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+                input, this->add_input()));
+          DO_(::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+            this->input(this->input_size() - 1).data(),
+            this->input(this->input_size() - 1).length(),
+            ::google::protobuf::internal::WireFormatLite::PARSE,
+            "tensorflow.NodeDef.input"));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(26)) goto parse_input;
+        if (input->ExpectTag(34)) goto parse_device;
+        break;
+      }
+
+      // optional string device = 4;
+      case 4: {
+        if (tag == 34) {
+         parse_device:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+                input, this->mutable_device()));
+          DO_(::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+            this->device().data(), this->device().length(),
+            ::google::protobuf::internal::WireFormatLite::PARSE,
+            "tensorflow.NodeDef.device"));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(42)) goto parse_attr;
+        break;
+      }
+
+      // map<string, .tensorflow.AttrValue> attr = 5;
+      case 5: {
+        if (tag == 42) {
+         parse_attr:
+          DO_(input->IncrementRecursionDepth());
+         parse_loop_attr:
+          NodeDef_AttrEntry::Parser< ::google::protobuf::internal::MapField<
+              ::std::string, ::tensorflow::AttrValue,
+              ::google::protobuf::internal::WireFormatLite::TYPE_STRING,
+              ::google::protobuf::internal::WireFormatLite::TYPE_MESSAGE,
+              0 >,
+            ::google::protobuf::Map< ::std::string, ::tensorflow::AttrValue > > parser(&attr_);
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+              input, &parser));
+          DO_(::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+            parser.key().data(), parser.key().length(),
+            ::google::protobuf::internal::WireFormatLite::PARSE,
+            "tensorflow.NodeDef.AttrEntry.key"));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(42)) goto parse_loop_attr;
+        input->UnsafeDecrementRecursionDepth();
+        if (input->ExpectAtEnd()) goto success;
+        break;
+      }
+
+      default: {
+      handle_unusual:
+        if (tag == 0 ||
+            ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+          goto success;
+        }
+        DO_(::google::protobuf::internal::WireFormatLite::SkipField(input, tag));
+        break;
+      }
+    }
+  }
+success:
+  // @@protoc_insertion_point(parse_success:tensorflow.NodeDef)
+  return true;
+failure:
+  // @@protoc_insertion_point(parse_failure:tensorflow.NodeDef)
+  return false;
+#undef DO_
+}
+
+void NodeDef::SerializeWithCachedSizes(
+    ::google::protobuf::io::CodedOutputStream* output) const {
+  // @@protoc_insertion_point(serialize_start:tensorflow.NodeDef)
+  // optional string name = 1;
+  if (this->name().size() > 0) {
+    ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+      this->name().data(), this->name().length(),
+      ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+      "tensorflow.NodeDef.name");
+    ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
+      1, this->name(), output);
+  }
+
+  // optional string op = 2;
+  if (this->op().size() > 0) {
+    ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+      this->op().data(), this->op().length(),
+      ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+      "tensorflow.NodeDef.op");
+    ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
+      2, this->op(), output);
+  }
+
+  // repeated string input = 3;
+  for (int i = 0; i < this->input_size(); i++) {
+    ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+      this->input(i).data(), this->input(i).length(),
+      ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+      "tensorflow.NodeDef.input");
+    ::google::protobuf::internal::WireFormatLite::WriteString(
+      3, this->input(i), output);
+  }
+
+  // optional string device = 4;
+  if (this->device().size() > 0) {
+    ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+      this->device().data(), this->device().length(),
+      ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+      "tensorflow.NodeDef.device");
+    ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
+      4, this->device(), output);
+  }
+
+  // map<string, .tensorflow.AttrValue> attr = 5;
+  if (!this->attr().empty()) {
+    typedef ::google::protobuf::Map< ::std::string, ::tensorflow::AttrValue >::const_pointer
+        ConstPtr;
+    typedef ConstPtr SortItem;
+    typedef ::google::protobuf::internal::CompareByDerefFirst<SortItem> Less;
+    struct Utf8Check {
+      static void Check(ConstPtr p) {
+        ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+          p->first.data(), p->first.length(),
+          ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+          "tensorflow.NodeDef.AttrEntry.key");
+      }
+    };
+
+    if (output->IsSerializationDeterminstic() &&
+        this->attr().size() > 1) {
+      ::google::protobuf::scoped_array<SortItem> items(
+          new SortItem[this->attr().size()]);
+      typedef ::google::protobuf::Map< ::std::string, ::tensorflow::AttrValue >::size_type size_type;
+      size_type n = 0;
+      for (::google::protobuf::Map< ::std::string, ::tensorflow::AttrValue >::const_iterator
+          it = this->attr().begin();
+          it != this->attr().end(); ++it, ++n) {
+        items[n] = SortItem(&*it);
+      }
+      ::std::sort(&items[0], &items[n], Less());
+      ::google::protobuf::scoped_ptr<NodeDef_AttrEntry> entry;
+      for (size_type i = 0; i < n; i++) {
+        entry.reset(attr_.NewEntryWrapper(
+            items[i]->first, items[i]->second));
+        ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+            5, *entry, output);
+        if (entry->GetArena() != NULL) {
+          entry.release();
+        }
+        Utf8Check::Check(items[i]);
+      }
+    } else {
+      ::google::protobuf::scoped_ptr<NodeDef_AttrEntry> entry;
+      for (::google::protobuf::Map< ::std::string, ::tensorflow::AttrValue >::const_iterator
+          it = this->attr().begin();
+          it != this->attr().end(); ++it) {
+        entry.reset(attr_.NewEntryWrapper(
+            it->first, it->second));
+        ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+            5, *entry, output);
+        if (entry->GetArena() != NULL) {
+          entry.release();
+        }
+        Utf8Check::Check(&*it);
+      }
+    }
+  }
+
+  // @@protoc_insertion_point(serialize_end:tensorflow.NodeDef)
+}
+
+::google::protobuf::uint8* NodeDef::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
+  (void)deterministic; // Unused
+  // @@protoc_insertion_point(serialize_to_array_start:tensorflow.NodeDef)
+  // optional string name = 1;
+  if (this->name().size() > 0) {
+    ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+      this->name().data(), this->name().length(),
+      ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+      "tensorflow.NodeDef.name");
+    target =
+      ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
+        1, this->name(), target);
+  }
+
+  // optional string op = 2;
+  if (this->op().size() > 0) {
+    ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+      this->op().data(), this->op().length(),
+      ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+      "tensorflow.NodeDef.op");
+    target =
+      ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
+        2, this->op(), target);
+  }
+
+  // repeated string input = 3;
+  for (int i = 0; i < this->input_size(); i++) {
+    ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+      this->input(i).data(), this->input(i).length(),
+      ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+      "tensorflow.NodeDef.input");
+    target = ::google::protobuf::internal::WireFormatLite::
+      WriteStringToArray(3, this->input(i), target);
+  }
+
+  // optional string device = 4;
+  if (this->device().size() > 0) {
+    ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+      this->device().data(), this->device().length(),
+      ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+      "tensorflow.NodeDef.device");
+    target =
+      ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
+        4, this->device(), target);
+  }
+
+  // map<string, .tensorflow.AttrValue> attr = 5;
+  if (!this->attr().empty()) {
+    typedef ::google::protobuf::Map< ::std::string, ::tensorflow::AttrValue >::const_pointer
+        ConstPtr;
+    typedef ConstPtr SortItem;
+    typedef ::google::protobuf::internal::CompareByDerefFirst<SortItem> Less;
+    struct Utf8Check {
+      static void Check(ConstPtr p) {
+        ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+          p->first.data(), p->first.length(),
+          ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+          "tensorflow.NodeDef.AttrEntry.key");
+      }
+    };
+
+    if (deterministic &&
+        this->attr().size() > 1) {
+      ::google::protobuf::scoped_array<SortItem> items(
+          new SortItem[this->attr().size()]);
+      typedef ::google::protobuf::Map< ::std::string, ::tensorflow::AttrValue >::size_type size_type;
+      size_type n = 0;
+      for (::google::protobuf::Map< ::std::string, ::tensorflow::AttrValue >::const_iterator
+          it = this->attr().begin();
+          it != this->attr().end(); ++it, ++n) {
+        items[n] = SortItem(&*it);
+      }
+      ::std::sort(&items[0], &items[n], Less());
+      ::google::protobuf::scoped_ptr<NodeDef_AttrEntry> entry;
+      for (size_type i = 0; i < n; i++) {
+        entry.reset(attr_.NewEntryWrapper(
+            items[i]->first, items[i]->second));
+        target = ::google::protobuf::internal::WireFormatLite::
+                   InternalWriteMessageNoVirtualToArray(
+                       5, *entry, deterministic, target);
+;
+        if (entry->GetArena() != NULL) {
+          entry.release();
+        }
+        Utf8Check::Check(items[i]);
+      }
+    } else {
+      ::google::protobuf::scoped_ptr<NodeDef_AttrEntry> entry;
+      for (::google::protobuf::Map< ::std::string, ::tensorflow::AttrValue >::const_iterator
+          it = this->attr().begin();
+          it != this->attr().end(); ++it) {
+        entry.reset(attr_.NewEntryWrapper(
+            it->first, it->second));
+        target = ::google::protobuf::internal::WireFormatLite::
+                   InternalWriteMessageNoVirtualToArray(
+                       5, *entry, deterministic, target);
+;
+        if (entry->GetArena() != NULL) {
+          entry.release();
+        }
+        Utf8Check::Check(&*it);
+      }
+    }
+  }
+
+  // @@protoc_insertion_point(serialize_to_array_end:tensorflow.NodeDef)
+  return target;
+}
+
+size_t NodeDef::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:tensorflow.NodeDef)
+  size_t total_size = 0;
+
+  // optional string name = 1;
+  if (this->name().size() > 0) {
+    total_size += 1 +
+      ::google::protobuf::internal::WireFormatLite::StringSize(
+        this->name());
+  }
+
+  // optional string op = 2;
+  if (this->op().size() > 0) {
+    total_size += 1 +
+      ::google::protobuf::internal::WireFormatLite::StringSize(
+        this->op());
+  }
+
+  // optional string device = 4;
+  if (this->device().size() > 0) {
+    total_size += 1 +
+      ::google::protobuf::internal::WireFormatLite::StringSize(
+        this->device());
+  }
+
+  // repeated string input = 3;
+  total_size += 1 *
+      ::google::protobuf::internal::FromIntSize(this->input_size());
+  for (int i = 0; i < this->input_size(); i++) {
+    total_size += ::google::protobuf::internal::WireFormatLite::StringSize(
+      this->input(i));
+  }
+
+  // map<string, .tensorflow.AttrValue> attr = 5;
+  total_size += 1 *
+      ::google::protobuf::internal::FromIntSize(this->attr_size());
+  {
+    ::google::protobuf::scoped_ptr<NodeDef_AttrEntry> entry;
+    for (::google::protobuf::Map< ::std::string, ::tensorflow::AttrValue >::const_iterator
+        it = this->attr().begin();
+        it != this->attr().end(); ++it) {
+      if (entry.get() != NULL && entry->GetArena() != NULL) {
+        entry.release();
+      }
+      entry.reset(attr_.NewEntryWrapper(it->first, it->second));
+      total_size += ::google::protobuf::internal::WireFormatLite::
+          MessageSizeNoVirtual(*entry);
+    }
+    if (entry.get() != NULL && entry->GetArena() != NULL) {
+      entry.release();
+    }
+  }
+
+  int cached_size = ::google::protobuf::internal::ToCachedSize(total_size);
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = cached_size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+  return total_size;
+}
+
+void NodeDef::MergeFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_merge_from_start:tensorflow.NodeDef)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const NodeDef* source =
+      ::google::protobuf::internal::DynamicCastToGenerated<const NodeDef>(
+          &from);
+  if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:tensorflow.NodeDef)
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:tensorflow.NodeDef)
+    UnsafeMergeFrom(*source);
+  }
+}
+
+void NodeDef::MergeFrom(const NodeDef& from) {
+// @@protoc_insertion_point(class_specific_merge_from_start:tensorflow.NodeDef)
+  if (GOOGLE_PREDICT_TRUE(&from != this)) {
+    UnsafeMergeFrom(from);
+  } else {
+    MergeFromFail(__LINE__);
+  }
+}
+
+void NodeDef::UnsafeMergeFrom(const NodeDef& from) {
+  GOOGLE_DCHECK(&from != this);
+  input_.UnsafeMergeFrom(from.input_);
+  attr_.MergeFrom(from.attr_);
+  if (from.name().size() > 0) {
+    set_name(from.name());
+  }
+  if (from.op().size() > 0) {
+    set_op(from.op());
+  }
+  if (from.device().size() > 0) {
+    set_device(from.device());
+  }
+}
+
+void NodeDef::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:tensorflow.NodeDef)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void NodeDef::CopyFrom(const NodeDef& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:tensorflow.NodeDef)
+  if (&from == this) return;
+  Clear();
+  UnsafeMergeFrom(from);
+}
+
+bool NodeDef::IsInitialized() const {
+
+  return true;
+}
+
+void NodeDef::Swap(NodeDef* other) {
+  if (other == this) return;
+  if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) {
+    InternalSwap(other);
+  } else {
+    NodeDef temp;
+    temp.UnsafeMergeFrom(*this);
+    CopyFrom(*other);
+    other->CopyFrom(temp);
+  }
+}
+void NodeDef::UnsafeArenaSwap(NodeDef* other) {
+  if (other == this) return;
+  GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual());
+  InternalSwap(other);
+}
+void NodeDef::InternalSwap(NodeDef* other) {
+  name_.Swap(&other->name_);
+  op_.Swap(&other->op_);
+  input_.UnsafeArenaSwap(&other->input_);
+  device_.Swap(&other->device_);
+  attr_.Swap(&other->attr_);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
+}
+
+::google::protobuf::Metadata NodeDef::GetMetadata() const {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::Metadata metadata;
+  metadata.descriptor = NodeDef_descriptor_;
+  metadata.reflection = NodeDef_reflection_;
+  return metadata;
+}
+
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// NodeDef
+
+// optional string name = 1;
+void NodeDef::clear_name() {
+  name_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+const ::std::string& NodeDef::name() const {
+  // @@protoc_insertion_point(field_get:tensorflow.NodeDef.name)
+  return name_.Get(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+void NodeDef::set_name(const ::std::string& value) {
+
+  name_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value, GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set:tensorflow.NodeDef.name)
+}
+void NodeDef::set_name(const char* value) {
+
+  name_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value),
+              GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_char:tensorflow.NodeDef.name)
+}
+void NodeDef::set_name(const char* value,
+    size_t size) {
+
+  name_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(
+      reinterpret_cast<const char*>(value), size), GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_pointer:tensorflow.NodeDef.name)
+}
+::std::string* NodeDef::mutable_name() {
+
+  // @@protoc_insertion_point(field_mutable:tensorflow.NodeDef.name)
+  return name_.Mutable(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+::std::string* NodeDef::release_name() {
+  // @@protoc_insertion_point(field_release:tensorflow.NodeDef.name)
+
+  return name_.Release(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+::std::string* NodeDef::unsafe_arena_release_name() {
+  // @@protoc_insertion_point(field_unsafe_arena_release:tensorflow.NodeDef.name)
+  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);
+
+  return name_.UnsafeArenaRelease(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      GetArenaNoVirtual());
+}
+void NodeDef::set_allocated_name(::std::string* name) {
+  if (name != NULL) {
+
+  } else {
+
+  }
+  name_.SetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), name,
+      GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_allocated:tensorflow.NodeDef.name)
+}
+void NodeDef::unsafe_arena_set_allocated_name(
+    ::std::string* name) {
+  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);
+  if (name != NULL) {
+
+  } else {
+
+  }
+  name_.UnsafeArenaSetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      name, GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_unsafe_arena_set_allocated:tensorflow.NodeDef.name)
+}
+
+// optional string op = 2;
+void NodeDef::clear_op() {
+  op_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+const ::std::string& NodeDef::op() const {
+  // @@protoc_insertion_point(field_get:tensorflow.NodeDef.op)
+  return op_.Get(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+void NodeDef::set_op(const ::std::string& value) {
+
+  op_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value, GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set:tensorflow.NodeDef.op)
+}
+void NodeDef::set_op(const char* value) {
+
+  op_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value),
+              GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_char:tensorflow.NodeDef.op)
+}
+void NodeDef::set_op(const char* value,
+    size_t size) {
+
+  op_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(
+      reinterpret_cast<const char*>(value), size), GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_pointer:tensorflow.NodeDef.op)
+}
+::std::string* NodeDef::mutable_op() {
+
+  // @@protoc_insertion_point(field_mutable:tensorflow.NodeDef.op)
+  return op_.Mutable(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+::std::string* NodeDef::release_op() {
+  // @@protoc_insertion_point(field_release:tensorflow.NodeDef.op)
+
+  return op_.Release(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+::std::string* NodeDef::unsafe_arena_release_op() {
+  // @@protoc_insertion_point(field_unsafe_arena_release:tensorflow.NodeDef.op)
+  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);
+
+  return op_.UnsafeArenaRelease(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      GetArenaNoVirtual());
+}
+void NodeDef::set_allocated_op(::std::string* op) {
+  if (op != NULL) {
+
+  } else {
+
+  }
+  op_.SetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), op,
+      GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_allocated:tensorflow.NodeDef.op)
+}
+void NodeDef::unsafe_arena_set_allocated_op(
+    ::std::string* op) {
+  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);
+  if (op != NULL) {
+
+  } else {
+
+  }
+  op_.UnsafeArenaSetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      op, GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_unsafe_arena_set_allocated:tensorflow.NodeDef.op)
+}
+
+// repeated string input = 3;
+int NodeDef::input_size() const {
+  return input_.size();
+}
+void NodeDef::clear_input() {
+  input_.Clear();
+}
+const ::std::string& NodeDef::input(int index) const {
+  // @@protoc_insertion_point(field_get:tensorflow.NodeDef.input)
+  return input_.Get(index);
+}
+::std::string* NodeDef::mutable_input(int index) {
+  // @@protoc_insertion_point(field_mutable:tensorflow.NodeDef.input)
+  return input_.Mutable(index);
+}
+void NodeDef::set_input(int index, const ::std::string& value) {
+  // @@protoc_insertion_point(field_set:tensorflow.NodeDef.input)
+  input_.Mutable(index)->assign(value);
+}
+void NodeDef::set_input(int index, const char* value) {
+  input_.Mutable(index)->assign(value);
+  // @@protoc_insertion_point(field_set_char:tensorflow.NodeDef.input)
+}
+void NodeDef::set_input(int index, const char* value, size_t size) {
+  input_.Mutable(index)->assign(
+    reinterpret_cast<const char*>(value), size);
+  // @@protoc_insertion_point(field_set_pointer:tensorflow.NodeDef.input)
+}
+::std::string* NodeDef::add_input() {
+  // @@protoc_insertion_point(field_add_mutable:tensorflow.NodeDef.input)
+  return input_.Add();
+}
+void NodeDef::add_input(const ::std::string& value) {
+  input_.Add()->assign(value);
+  // @@protoc_insertion_point(field_add:tensorflow.NodeDef.input)
+}
+void NodeDef::add_input(const char* value) {
+  input_.Add()->assign(value);
+  // @@protoc_insertion_point(field_add_char:tensorflow.NodeDef.input)
+}
+void NodeDef::add_input(const char* value, size_t size) {
+  input_.Add()->assign(reinterpret_cast<const char*>(value), size);
+  // @@protoc_insertion_point(field_add_pointer:tensorflow.NodeDef.input)
+}
+const ::google::protobuf::RepeatedPtrField< ::std::string>&
+NodeDef::input() const {
+  // @@protoc_insertion_point(field_list:tensorflow.NodeDef.input)
+  return input_;
+}
+::google::protobuf::RepeatedPtrField< ::std::string>*
+NodeDef::mutable_input() {
+  // @@protoc_insertion_point(field_mutable_list:tensorflow.NodeDef.input)
+  return &input_;
+}
+
+// optional string device = 4;
+void NodeDef::clear_device() {
+  device_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+const ::std::string& NodeDef::device() const {
+  // @@protoc_insertion_point(field_get:tensorflow.NodeDef.device)
+  return device_.Get(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+void NodeDef::set_device(const ::std::string& value) {
+
+  device_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value, GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set:tensorflow.NodeDef.device)
+}
+void NodeDef::set_device(const char* value) {
+
+  device_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value),
+              GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_char:tensorflow.NodeDef.device)
+}
+void NodeDef::set_device(const char* value,
+    size_t size) {
+
+  device_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(
+      reinterpret_cast<const char*>(value), size), GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_pointer:tensorflow.NodeDef.device)
+}
+::std::string* NodeDef::mutable_device() {
+
+  // @@protoc_insertion_point(field_mutable:tensorflow.NodeDef.device)
+  return device_.Mutable(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+::std::string* NodeDef::release_device() {
+  // @@protoc_insertion_point(field_release:tensorflow.NodeDef.device)
+
+  return device_.Release(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+::std::string* NodeDef::unsafe_arena_release_device() {
+  // @@protoc_insertion_point(field_unsafe_arena_release:tensorflow.NodeDef.device)
+  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);
+
+  return device_.UnsafeArenaRelease(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      GetArenaNoVirtual());
+}
+void NodeDef::set_allocated_device(::std::string* device) {
+  if (device != NULL) {
+
+  } else {
+
+  }
+  device_.SetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), device,
+      GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_allocated:tensorflow.NodeDef.device)
+}
+void NodeDef::unsafe_arena_set_allocated_device(
+    ::std::string* device) {
+  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);
+  if (device != NULL) {
+
+  } else {
+
+  }
+  device_.UnsafeArenaSetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      device, GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_unsafe_arena_set_allocated:tensorflow.NodeDef.device)
+}
+
+// map<string, .tensorflow.AttrValue> attr = 5;
+int NodeDef::attr_size() const {
+  return attr_.size();
+}
+void NodeDef::clear_attr() {
+  attr_.Clear();
+}
+ const ::google::protobuf::Map< ::std::string, ::tensorflow::AttrValue >&
+NodeDef::attr() const {
+  // @@protoc_insertion_point(field_map:tensorflow.NodeDef.attr)
+  return attr_.GetMap();
+}
+ ::google::protobuf::Map< ::std::string, ::tensorflow::AttrValue >*
+NodeDef::mutable_attr() {
+  // @@protoc_insertion_point(field_mutable_map:tensorflow.NodeDef.attr)
+  return attr_.MutableMap();
+}
+
+inline const NodeDef* NodeDef::internal_default_instance() {
+  return &NodeDef_default_instance_.get();
+}
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
+
+// @@protoc_insertion_point(namespace_scope)
+
+}  // namespace tensorflow
+
+// @@protoc_insertion_point(global_scope)
diff --git a/contrib/modules/dnn/misc/tensorflow/graph.pb.h b/contrib/modules/dnn/misc/tensorflow/graph.pb.h
new file mode 100644
index 0000000..f4d54bc
--- /dev/null
+++ b/contrib/modules/dnn/misc/tensorflow/graph.pb.h
@@ -0,0 +1,814 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: graph.proto
+
+#ifndef PROTOBUF_graph_2eproto__INCLUDED
+#define PROTOBUF_graph_2eproto__INCLUDED
+
+#include <string>
+
+#include <google/protobuf/stubs/common.h>
+
+#if GOOGLE_PROTOBUF_VERSION < 3001000
+#error This file was generated by a newer version of protoc which is
+#error incompatible with your Protocol Buffer headers.  Please update
+#error your headers.
+#endif
+#if 3001000 < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION
+#error This file was generated by an older version of protoc which is
+#error incompatible with your Protocol Buffer headers.  Please
+#error regenerate this file with a newer version of protoc.
+#endif
+
+#include <google/protobuf/arena.h>
+#include <google/protobuf/arenastring.h>
+#include <google/protobuf/generated_message_util.h>
+#include <google/protobuf/metadata.h>
+#include <google/protobuf/message.h>
+#include <google/protobuf/repeated_field.h>
+#include <google/protobuf/extension_set.h>
+#include <google/protobuf/map.h>
+#include <google/protobuf/map_field_inl.h>
+#include <google/protobuf/unknown_field_set.h>
+#include "attr_value.pb.h"
+#include "function.pb.h"
+#include "versions.pb.h"
+// @@protoc_insertion_point(includes)
+
+namespace tensorflow {
+
+// Internal implementation detail -- do not call these.
+void protobuf_AddDesc_graph_2eproto();
+void protobuf_InitDefaults_graph_2eproto();
+void protobuf_AssignDesc_graph_2eproto();
+void protobuf_ShutdownFile_graph_2eproto();
+
+class GraphDef;
+class NodeDef;
+
+// ===================================================================
+
+class GraphDef : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:tensorflow.GraphDef) */ {
+ public:
+  GraphDef();
+  virtual ~GraphDef();
+
+  GraphDef(const GraphDef& from);
+
+  inline GraphDef& operator=(const GraphDef& from) {
+    CopyFrom(from);
+    return *this;
+  }
+
+  inline ::google::protobuf::Arena* GetArena() const { return GetArenaNoVirtual(); }
+  inline void* GetMaybeArenaPointer() const {
+    return MaybeArenaPtr();
+  }
+  static const ::google::protobuf::Descriptor* descriptor();
+  static const GraphDef& default_instance();
+
+  static const GraphDef* internal_default_instance();
+
+  void UnsafeArenaSwap(GraphDef* other);
+  void Swap(GraphDef* other);
+
+  // implements Message ----------------------------------------------
+
+  inline GraphDef* New() const { return New(NULL); }
+
+  GraphDef* New(::google::protobuf::Arena* arena) const;
+  void CopyFrom(const ::google::protobuf::Message& from);
+  void MergeFrom(const ::google::protobuf::Message& from);
+  void CopyFrom(const GraphDef& from);
+  void MergeFrom(const GraphDef& from);
+  void Clear();
+  bool IsInitialized() const;
+
+  size_t ByteSizeLong() const;
+  bool MergePartialFromCodedStream(
+      ::google::protobuf::io::CodedInputStream* input);
+  void SerializeWithCachedSizes(
+      ::google::protobuf::io::CodedOutputStream* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
+  int GetCachedSize() const { return _cached_size_; }
+  private:
+  void SharedCtor();
+  void SharedDtor();
+  void SetCachedSize(int size) const;
+  void InternalSwap(GraphDef* other);
+  void UnsafeMergeFrom(const GraphDef& from);
+  protected:
+  explicit GraphDef(::google::protobuf::Arena* arena);
+  private:
+  static void ArenaDtor(void* object);
+  inline void RegisterArenaDtor(::google::protobuf::Arena* arena);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
+  public:
+
+  ::google::protobuf::Metadata GetMetadata() const;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  // repeated .tensorflow.NodeDef node = 1;
+  int node_size() const;
+  void clear_node();
+  static const int kNodeFieldNumber = 1;
+  const ::tensorflow::NodeDef& node(int index) const;
+  ::tensorflow::NodeDef* mutable_node(int index);
+  ::tensorflow::NodeDef* add_node();
+  ::google::protobuf::RepeatedPtrField< ::tensorflow::NodeDef >*
+      mutable_node();
+  const ::google::protobuf::RepeatedPtrField< ::tensorflow::NodeDef >&
+      node() const;
+
+  // optional .tensorflow.VersionDef versions = 4;
+  bool has_versions() const;
+  void clear_versions();
+  static const int kVersionsFieldNumber = 4;
+  private:
+  void _slow_mutable_versions();
+  void _slow_set_allocated_versions(
+      ::google::protobuf::Arena* message_arena, ::tensorflow::VersionDef** versions);
+  ::tensorflow::VersionDef* _slow_release_versions();
+  public:
+  const ::tensorflow::VersionDef& versions() const;
+  ::tensorflow::VersionDef* mutable_versions();
+  ::tensorflow::VersionDef* release_versions();
+  void set_allocated_versions(::tensorflow::VersionDef* versions);
+  ::tensorflow::VersionDef* unsafe_arena_release_versions();
+  void unsafe_arena_set_allocated_versions(
+      ::tensorflow::VersionDef* versions);
+
+  // optional int32 version = 3 [deprecated = true];
+  GOOGLE_PROTOBUF_DEPRECATED_ATTR void clear_version();
+  GOOGLE_PROTOBUF_DEPRECATED_ATTR static const int kVersionFieldNumber = 3;
+  GOOGLE_PROTOBUF_DEPRECATED_ATTR ::google::protobuf::int32 version() const;
+  GOOGLE_PROTOBUF_DEPRECATED_ATTR void set_version(::google::protobuf::int32 value);
+
+  // optional .tensorflow.FunctionDefLibrary library = 2;
+  bool has_library() const;
+  void clear_library();
+  static const int kLibraryFieldNumber = 2;
+  private:
+  void _slow_mutable_library();
+  void _slow_set_allocated_library(
+      ::google::protobuf::Arena* message_arena, ::tensorflow::FunctionDefLibrary** library);
+  ::tensorflow::FunctionDefLibrary* _slow_release_library();
+  public:
+  const ::tensorflow::FunctionDefLibrary& library() const;
+  ::tensorflow::FunctionDefLibrary* mutable_library();
+  ::tensorflow::FunctionDefLibrary* release_library();
+  void set_allocated_library(::tensorflow::FunctionDefLibrary* library);
+  ::tensorflow::FunctionDefLibrary* unsafe_arena_release_library();
+  void unsafe_arena_set_allocated_library(
+      ::tensorflow::FunctionDefLibrary* library);
+
+  // @@protoc_insertion_point(class_scope:tensorflow.GraphDef)
+ private:
+
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  friend class ::google::protobuf::Arena;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  ::google::protobuf::RepeatedPtrField< ::tensorflow::NodeDef > node_;
+  ::tensorflow::VersionDef* versions_;
+  ::tensorflow::FunctionDefLibrary* library_;
+  ::google::protobuf::int32 version_;
+  mutable int _cached_size_;
+  friend void  protobuf_InitDefaults_graph_2eproto_impl();
+  friend void  protobuf_AddDesc_graph_2eproto_impl();
+  friend void protobuf_AssignDesc_graph_2eproto();
+  friend void protobuf_ShutdownFile_graph_2eproto();
+
+  void InitAsDefaultInstance();
+};
+extern ::google::protobuf::internal::ExplicitlyConstructed<GraphDef> GraphDef_default_instance_;
+
+// -------------------------------------------------------------------
+
+class NodeDef : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:tensorflow.NodeDef) */ {
+ public:
+  NodeDef();
+  virtual ~NodeDef();
+
+  NodeDef(const NodeDef& from);
+
+  inline NodeDef& operator=(const NodeDef& from) {
+    CopyFrom(from);
+    return *this;
+  }
+
+  inline ::google::protobuf::Arena* GetArena() const { return GetArenaNoVirtual(); }
+  inline void* GetMaybeArenaPointer() const {
+    return MaybeArenaPtr();
+  }
+  static const ::google::protobuf::Descriptor* descriptor();
+  static const NodeDef& default_instance();
+
+  static const NodeDef* internal_default_instance();
+
+  void UnsafeArenaSwap(NodeDef* other);
+  void Swap(NodeDef* other);
+
+  // implements Message ----------------------------------------------
+
+  inline NodeDef* New() const { return New(NULL); }
+
+  NodeDef* New(::google::protobuf::Arena* arena) const;
+  void CopyFrom(const ::google::protobuf::Message& from);
+  void MergeFrom(const ::google::protobuf::Message& from);
+  void CopyFrom(const NodeDef& from);
+  void MergeFrom(const NodeDef& from);
+  void Clear();
+  bool IsInitialized() const;
+
+  size_t ByteSizeLong() const;
+  bool MergePartialFromCodedStream(
+      ::google::protobuf::io::CodedInputStream* input);
+  void SerializeWithCachedSizes(
+      ::google::protobuf::io::CodedOutputStream* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
+  int GetCachedSize() const { return _cached_size_; }
+  private:
+  void SharedCtor();
+  void SharedDtor();
+  void SetCachedSize(int size) const;
+  void InternalSwap(NodeDef* other);
+  void UnsafeMergeFrom(const NodeDef& from);
+  protected:
+  explicit NodeDef(::google::protobuf::Arena* arena);
+  private:
+  static void ArenaDtor(void* object);
+  inline void RegisterArenaDtor(::google::protobuf::Arena* arena);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
+  public:
+
+  ::google::protobuf::Metadata GetMetadata() const;
+
+  // nested types ----------------------------------------------------
+
+
+  // accessors -------------------------------------------------------
+
+  // optional string name = 1;
+  void clear_name();
+  static const int kNameFieldNumber = 1;
+  const ::std::string& name() const;
+  void set_name(const ::std::string& value);
+  void set_name(const char* value);
+  void set_name(const char* value, size_t size);
+  ::std::string* mutable_name();
+  ::std::string* release_name();
+  void set_allocated_name(::std::string* name);
+  ::std::string* unsafe_arena_release_name();
+  void unsafe_arena_set_allocated_name(
+      ::std::string* name);
+
+  // optional string op = 2;
+  void clear_op();
+  static const int kOpFieldNumber = 2;
+  const ::std::string& op() const;
+  void set_op(const ::std::string& value);
+  void set_op(const char* value);
+  void set_op(const char* value, size_t size);
+  ::std::string* mutable_op();
+  ::std::string* release_op();
+  void set_allocated_op(::std::string* op);
+  ::std::string* unsafe_arena_release_op();
+  void unsafe_arena_set_allocated_op(
+      ::std::string* op);
+
+  // repeated string input = 3;
+  int input_size() const;
+  void clear_input();
+  static const int kInputFieldNumber = 3;
+  const ::std::string& input(int index) const;
+  ::std::string* mutable_input(int index);
+  void set_input(int index, const ::std::string& value);
+  void set_input(int index, const char* value);
+  void set_input(int index, const char* value, size_t size);
+  ::std::string* add_input();
+  void add_input(const ::std::string& value);
+  void add_input(const char* value);
+  void add_input(const char* value, size_t size);
+  const ::google::protobuf::RepeatedPtrField< ::std::string>& input() const;
+  ::google::protobuf::RepeatedPtrField< ::std::string>* mutable_input();
+
+  // optional string device = 4;
+  void clear_device();
+  static const int kDeviceFieldNumber = 4;
+  const ::std::string& device() const;
+  void set_device(const ::std::string& value);
+  void set_device(const char* value);
+  void set_device(const char* value, size_t size);
+  ::std::string* mutable_device();
+  ::std::string* release_device();
+  void set_allocated_device(::std::string* device);
+  ::std::string* unsafe_arena_release_device();
+  void unsafe_arena_set_allocated_device(
+      ::std::string* device);
+
+  // map<string, .tensorflow.AttrValue> attr = 5;
+  int attr_size() const;
+  void clear_attr();
+  static const int kAttrFieldNumber = 5;
+  const ::google::protobuf::Map< ::std::string, ::tensorflow::AttrValue >&
+      attr() const;
+  ::google::protobuf::Map< ::std::string, ::tensorflow::AttrValue >*
+      mutable_attr();
+
+  // @@protoc_insertion_point(class_scope:tensorflow.NodeDef)
+ private:
+
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  friend class ::google::protobuf::Arena;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  ::google::protobuf::RepeatedPtrField< ::std::string> input_;
+  typedef ::google::protobuf::internal::MapEntryLite<
+      ::std::string, ::tensorflow::AttrValue,
+      ::google::protobuf::internal::WireFormatLite::TYPE_STRING,
+      ::google::protobuf::internal::WireFormatLite::TYPE_MESSAGE,
+      0 >
+      NodeDef_AttrEntry;
+  ::google::protobuf::internal::MapField<
+      ::std::string, ::tensorflow::AttrValue,
+      ::google::protobuf::internal::WireFormatLite::TYPE_STRING,
+      ::google::protobuf::internal::WireFormatLite::TYPE_MESSAGE,
+      0 > attr_;
+  ::google::protobuf::internal::ArenaStringPtr name_;
+  ::google::protobuf::internal::ArenaStringPtr op_;
+  ::google::protobuf::internal::ArenaStringPtr device_;
+  mutable int _cached_size_;
+  friend void  protobuf_InitDefaults_graph_2eproto_impl();
+  friend void  protobuf_AddDesc_graph_2eproto_impl();
+  friend void protobuf_AssignDesc_graph_2eproto();
+  friend void protobuf_ShutdownFile_graph_2eproto();
+
+  void InitAsDefaultInstance();
+};
+extern ::google::protobuf::internal::ExplicitlyConstructed<NodeDef> NodeDef_default_instance_;
+
+// ===================================================================
+
+
+// ===================================================================
+
+#if !PROTOBUF_INLINE_NOT_IN_HEADERS
+// GraphDef
+
+// repeated .tensorflow.NodeDef node = 1;
+inline int GraphDef::node_size() const {
+  return node_.size();
+}
+inline void GraphDef::clear_node() {
+  node_.Clear();
+}
+inline const ::tensorflow::NodeDef& GraphDef::node(int index) const {
+  // @@protoc_insertion_point(field_get:tensorflow.GraphDef.node)
+  return node_.Get(index);
+}
+inline ::tensorflow::NodeDef* GraphDef::mutable_node(int index) {
+  // @@protoc_insertion_point(field_mutable:tensorflow.GraphDef.node)
+  return node_.Mutable(index);
+}
+inline ::tensorflow::NodeDef* GraphDef::add_node() {
+  // @@protoc_insertion_point(field_add:tensorflow.GraphDef.node)
+  return node_.Add();
+}
+inline ::google::protobuf::RepeatedPtrField< ::tensorflow::NodeDef >*
+GraphDef::mutable_node() {
+  // @@protoc_insertion_point(field_mutable_list:tensorflow.GraphDef.node)
+  return &node_;
+}
+inline const ::google::protobuf::RepeatedPtrField< ::tensorflow::NodeDef >&
+GraphDef::node() const {
+  // @@protoc_insertion_point(field_list:tensorflow.GraphDef.node)
+  return node_;
+}
+
+// optional .tensorflow.VersionDef versions = 4;
+inline bool GraphDef::has_versions() const {
+  return this != internal_default_instance() && versions_ != NULL;
+}
+inline void GraphDef::clear_versions() {
+  if (GetArenaNoVirtual() == NULL && versions_ != NULL) delete versions_;
+  versions_ = NULL;
+}
+inline const ::tensorflow::VersionDef& GraphDef::versions() const {
+  // @@protoc_insertion_point(field_get:tensorflow.GraphDef.versions)
+  return versions_ != NULL ? *versions_
+                         : *::tensorflow::VersionDef::internal_default_instance();
+}
+inline ::tensorflow::VersionDef* GraphDef::mutable_versions() {
+
+  if (versions_ == NULL) {
+    _slow_mutable_versions();
+  }
+  // @@protoc_insertion_point(field_mutable:tensorflow.GraphDef.versions)
+  return versions_;
+}
+inline ::tensorflow::VersionDef* GraphDef::release_versions() {
+  // @@protoc_insertion_point(field_release:tensorflow.GraphDef.versions)
+
+  if (GetArenaNoVirtual() != NULL) {
+    return _slow_release_versions();
+  } else {
+    ::tensorflow::VersionDef* temp = versions_;
+    versions_ = NULL;
+    return temp;
+  }
+}
+inline  void GraphDef::set_allocated_versions(::tensorflow::VersionDef* versions) {
+  ::google::protobuf::Arena* message_arena = GetArenaNoVirtual();
+  if (message_arena == NULL) {
+    delete versions_;
+  }
+  if (versions != NULL) {
+    _slow_set_allocated_versions(message_arena, &versions);
+  }
+  versions_ = versions;
+  if (versions) {
+
+  } else {
+
+  }
+  // @@protoc_insertion_point(field_set_allocated:tensorflow.GraphDef.versions)
+}
+
+// optional int32 version = 3 [deprecated = true];
+inline void GraphDef::clear_version() {
+  version_ = 0;
+}
+inline ::google::protobuf::int32 GraphDef::version() const {
+  // @@protoc_insertion_point(field_get:tensorflow.GraphDef.version)
+  return version_;
+}
+inline void GraphDef::set_version(::google::protobuf::int32 value) {
+
+  version_ = value;
+  // @@protoc_insertion_point(field_set:tensorflow.GraphDef.version)
+}
+
+// optional .tensorflow.FunctionDefLibrary library = 2;
+inline bool GraphDef::has_library() const {
+  return this != internal_default_instance() && library_ != NULL;
+}
+inline void GraphDef::clear_library() {
+  if (GetArenaNoVirtual() == NULL && library_ != NULL) delete library_;
+  library_ = NULL;
+}
+inline const ::tensorflow::FunctionDefLibrary& GraphDef::library() const {
+  // @@protoc_insertion_point(field_get:tensorflow.GraphDef.library)
+  return library_ != NULL ? *library_
+                         : *::tensorflow::FunctionDefLibrary::internal_default_instance();
+}
+inline ::tensorflow::FunctionDefLibrary* GraphDef::mutable_library() {
+
+  if (library_ == NULL) {
+    _slow_mutable_library();
+  }
+  // @@protoc_insertion_point(field_mutable:tensorflow.GraphDef.library)
+  return library_;
+}
+inline ::tensorflow::FunctionDefLibrary* GraphDef::release_library() {
+  // @@protoc_insertion_point(field_release:tensorflow.GraphDef.library)
+
+  if (GetArenaNoVirtual() != NULL) {
+    return _slow_release_library();
+  } else {
+    ::tensorflow::FunctionDefLibrary* temp = library_;
+    library_ = NULL;
+    return temp;
+  }
+}
+inline  void GraphDef::set_allocated_library(::tensorflow::FunctionDefLibrary* library) {
+  ::google::protobuf::Arena* message_arena = GetArenaNoVirtual();
+  if (message_arena == NULL) {
+    delete library_;
+  }
+  if (library != NULL) {
+    _slow_set_allocated_library(message_arena, &library);
+  }
+  library_ = library;
+  if (library) {
+
+  } else {
+
+  }
+  // @@protoc_insertion_point(field_set_allocated:tensorflow.GraphDef.library)
+}
+
+inline const GraphDef* GraphDef::internal_default_instance() {
+  return &GraphDef_default_instance_.get();
+}
+// -------------------------------------------------------------------
+
+// NodeDef
+
+// optional string name = 1;
+inline void NodeDef::clear_name() {
+  name_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+inline const ::std::string& NodeDef::name() const {
+  // @@protoc_insertion_point(field_get:tensorflow.NodeDef.name)
+  return name_.Get(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void NodeDef::set_name(const ::std::string& value) {
+
+  name_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value, GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set:tensorflow.NodeDef.name)
+}
+inline void NodeDef::set_name(const char* value) {
+
+  name_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value),
+              GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_char:tensorflow.NodeDef.name)
+}
+inline void NodeDef::set_name(const char* value,
+    size_t size) {
+
+  name_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(
+      reinterpret_cast<const char*>(value), size), GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_pointer:tensorflow.NodeDef.name)
+}
+inline ::std::string* NodeDef::mutable_name() {
+
+  // @@protoc_insertion_point(field_mutable:tensorflow.NodeDef.name)
+  return name_.Mutable(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+inline ::std::string* NodeDef::release_name() {
+  // @@protoc_insertion_point(field_release:tensorflow.NodeDef.name)
+
+  return name_.Release(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+inline ::std::string* NodeDef::unsafe_arena_release_name() {
+  // @@protoc_insertion_point(field_unsafe_arena_release:tensorflow.NodeDef.name)
+  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);
+
+  return name_.UnsafeArenaRelease(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      GetArenaNoVirtual());
+}
+inline void NodeDef::set_allocated_name(::std::string* name) {
+  if (name != NULL) {
+
+  } else {
+
+  }
+  name_.SetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), name,
+      GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_allocated:tensorflow.NodeDef.name)
+}
+inline void NodeDef::unsafe_arena_set_allocated_name(
+    ::std::string* name) {
+  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);
+  if (name != NULL) {
+
+  } else {
+
+  }
+  name_.UnsafeArenaSetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      name, GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_unsafe_arena_set_allocated:tensorflow.NodeDef.name)
+}
+
+// optional string op = 2;
+inline void NodeDef::clear_op() {
+  op_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+inline const ::std::string& NodeDef::op() const {
+  // @@protoc_insertion_point(field_get:tensorflow.NodeDef.op)
+  return op_.Get(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void NodeDef::set_op(const ::std::string& value) {
+
+  op_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value, GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set:tensorflow.NodeDef.op)
+}
+inline void NodeDef::set_op(const char* value) {
+
+  op_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value),
+              GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_char:tensorflow.NodeDef.op)
+}
+inline void NodeDef::set_op(const char* value,
+    size_t size) {
+
+  op_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(
+      reinterpret_cast<const char*>(value), size), GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_pointer:tensorflow.NodeDef.op)
+}
+inline ::std::string* NodeDef::mutable_op() {
+
+  // @@protoc_insertion_point(field_mutable:tensorflow.NodeDef.op)
+  return op_.Mutable(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+inline ::std::string* NodeDef::release_op() {
+  // @@protoc_insertion_point(field_release:tensorflow.NodeDef.op)
+
+  return op_.Release(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+inline ::std::string* NodeDef::unsafe_arena_release_op() {
+  // @@protoc_insertion_point(field_unsafe_arena_release:tensorflow.NodeDef.op)
+  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);
+
+  return op_.UnsafeArenaRelease(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      GetArenaNoVirtual());
+}
+inline void NodeDef::set_allocated_op(::std::string* op) {
+  if (op != NULL) {
+
+  } else {
+
+  }
+  op_.SetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), op,
+      GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_allocated:tensorflow.NodeDef.op)
+}
+inline void NodeDef::unsafe_arena_set_allocated_op(
+    ::std::string* op) {
+  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);
+  if (op != NULL) {
+
+  } else {
+
+  }
+  op_.UnsafeArenaSetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      op, GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_unsafe_arena_set_allocated:tensorflow.NodeDef.op)
+}
+
+// repeated string input = 3;
+inline int NodeDef::input_size() const {
+  return input_.size();
+}
+inline void NodeDef::clear_input() {
+  input_.Clear();
+}
+inline const ::std::string& NodeDef::input(int index) const {
+  // @@protoc_insertion_point(field_get:tensorflow.NodeDef.input)
+  return input_.Get(index);
+}
+inline ::std::string* NodeDef::mutable_input(int index) {
+  // @@protoc_insertion_point(field_mutable:tensorflow.NodeDef.input)
+  return input_.Mutable(index);
+}
+inline void NodeDef::set_input(int index, const ::std::string& value) {
+  // @@protoc_insertion_point(field_set:tensorflow.NodeDef.input)
+  input_.Mutable(index)->assign(value);
+}
+inline void NodeDef::set_input(int index, const char* value) {
+  input_.Mutable(index)->assign(value);
+  // @@protoc_insertion_point(field_set_char:tensorflow.NodeDef.input)
+}
+inline void NodeDef::set_input(int index, const char* value, size_t size) {
+  input_.Mutable(index)->assign(
+    reinterpret_cast<const char*>(value), size);
+  // @@protoc_insertion_point(field_set_pointer:tensorflow.NodeDef.input)
+}
+inline ::std::string* NodeDef::add_input() {
+  // @@protoc_insertion_point(field_add_mutable:tensorflow.NodeDef.input)
+  return input_.Add();
+}
+inline void NodeDef::add_input(const ::std::string& value) {
+  input_.Add()->assign(value);
+  // @@protoc_insertion_point(field_add:tensorflow.NodeDef.input)
+}
+inline void NodeDef::add_input(const char* value) {
+  input_.Add()->assign(value);
+  // @@protoc_insertion_point(field_add_char:tensorflow.NodeDef.input)
+}
+inline void NodeDef::add_input(const char* value, size_t size) {
+  input_.Add()->assign(reinterpret_cast<const char*>(value), size);
+  // @@protoc_insertion_point(field_add_pointer:tensorflow.NodeDef.input)
+}
+inline const ::google::protobuf::RepeatedPtrField< ::std::string>&
+NodeDef::input() const {
+  // @@protoc_insertion_point(field_list:tensorflow.NodeDef.input)
+  return input_;
+}
+inline ::google::protobuf::RepeatedPtrField< ::std::string>*
+NodeDef::mutable_input() {
+  // @@protoc_insertion_point(field_mutable_list:tensorflow.NodeDef.input)
+  return &input_;
+}
+
+// optional string device = 4;
+inline void NodeDef::clear_device() {
+  device_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+inline const ::std::string& NodeDef::device() const {
+  // @@protoc_insertion_point(field_get:tensorflow.NodeDef.device)
+  return device_.Get(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void NodeDef::set_device(const ::std::string& value) {
+
+  device_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value, GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set:tensorflow.NodeDef.device)
+}
+inline void NodeDef::set_device(const char* value) {
+
+  device_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value),
+              GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_char:tensorflow.NodeDef.device)
+}
+inline void NodeDef::set_device(const char* value,
+    size_t size) {
+
+  device_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(
+      reinterpret_cast<const char*>(value), size), GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_pointer:tensorflow.NodeDef.device)
+}
+inline ::std::string* NodeDef::mutable_device() {
+
+  // @@protoc_insertion_point(field_mutable:tensorflow.NodeDef.device)
+  return device_.Mutable(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+inline ::std::string* NodeDef::release_device() {
+  // @@protoc_insertion_point(field_release:tensorflow.NodeDef.device)
+
+  return device_.Release(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+inline ::std::string* NodeDef::unsafe_arena_release_device() {
+  // @@protoc_insertion_point(field_unsafe_arena_release:tensorflow.NodeDef.device)
+  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);
+
+  return device_.UnsafeArenaRelease(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      GetArenaNoVirtual());
+}
+inline void NodeDef::set_allocated_device(::std::string* device) {
+  if (device != NULL) {
+
+  } else {
+
+  }
+  device_.SetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), device,
+      GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_allocated:tensorflow.NodeDef.device)
+}
+inline void NodeDef::unsafe_arena_set_allocated_device(
+    ::std::string* device) {
+  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);
+  if (device != NULL) {
+
+  } else {
+
+  }
+  device_.UnsafeArenaSetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      device, GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_unsafe_arena_set_allocated:tensorflow.NodeDef.device)
+}
+
+// map<string, .tensorflow.AttrValue> attr = 5;
+inline int NodeDef::attr_size() const {
+  return attr_.size();
+}
+inline void NodeDef::clear_attr() {
+  attr_.Clear();
+}
+inline const ::google::protobuf::Map< ::std::string, ::tensorflow::AttrValue >&
+NodeDef::attr() const {
+  // @@protoc_insertion_point(field_map:tensorflow.NodeDef.attr)
+  return attr_.GetMap();
+}
+inline ::google::protobuf::Map< ::std::string, ::tensorflow::AttrValue >*
+NodeDef::mutable_attr() {
+  // @@protoc_insertion_point(field_mutable_map:tensorflow.NodeDef.attr)
+  return attr_.MutableMap();
+}
+
+inline const NodeDef* NodeDef::internal_default_instance() {
+  return &NodeDef_default_instance_.get();
+}
+#endif  // !PROTOBUF_INLINE_NOT_IN_HEADERS
+// -------------------------------------------------------------------
+
+
+// @@protoc_insertion_point(namespace_scope)
+
+}  // namespace tensorflow
+
+// @@protoc_insertion_point(global_scope)
+
+#endif  // PROTOBUF_graph_2eproto__INCLUDED
diff --git a/contrib/modules/dnn/misc/tensorflow/op_def.pb.cc b/contrib/modules/dnn/misc/tensorflow/op_def.pb.cc
new file mode 100644
index 0000000..1a9cae3
--- /dev/null
+++ b/contrib/modules/dnn/misc/tensorflow/op_def.pb.cc
@@ -0,0 +1,4045 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: op_def.proto
+
+#define INTERNAL_SUPPRESS_PROTOBUF_FIELD_DEPRECATION
+#include "op_def.pb.h"
+
+#include <algorithm>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/port.h>
+#include <google/protobuf/stubs/once.h>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/wire_format_lite_inl.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/generated_message_reflection.h>
+#include <google/protobuf/reflection_ops.h>
+#include <google/protobuf/wire_format.h>
+// @@protoc_insertion_point(includes)
+
+namespace tensorflow {
+
+namespace {
+
+const ::google::protobuf::Descriptor* OpDef_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+  OpDef_reflection_ = NULL;
+const ::google::protobuf::Descriptor* OpDef_ArgDef_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+  OpDef_ArgDef_reflection_ = NULL;
+const ::google::protobuf::Descriptor* OpDef_AttrDef_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+  OpDef_AttrDef_reflection_ = NULL;
+const ::google::protobuf::Descriptor* OpDeprecation_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+  OpDeprecation_reflection_ = NULL;
+const ::google::protobuf::Descriptor* OpList_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+  OpList_reflection_ = NULL;
+
+}  // namespace
+
+
+void protobuf_AssignDesc_op_5fdef_2eproto() GOOGLE_ATTRIBUTE_COLD;
+void protobuf_AssignDesc_op_5fdef_2eproto() {
+  protobuf_AddDesc_op_5fdef_2eproto();
+  const ::google::protobuf::FileDescriptor* file =
+    ::google::protobuf::DescriptorPool::generated_pool()->FindFileByName(
+      "op_def.proto");
+  GOOGLE_CHECK(file != NULL);
+  OpDef_descriptor_ = file->message_type(0);
+  static const int OpDef_offsets_[11] = {
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(OpDef, name_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(OpDef, input_arg_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(OpDef, output_arg_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(OpDef, attr_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(OpDef, deprecation_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(OpDef, summary_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(OpDef, description_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(OpDef, is_commutative_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(OpDef, is_aggregate_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(OpDef, is_stateful_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(OpDef, allows_uninitialized_input_),
+  };
+  OpDef_reflection_ =
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
+      OpDef_descriptor_,
+      OpDef::internal_default_instance(),
+      OpDef_offsets_,
+      -1,
+      -1,
+      -1,
+      sizeof(OpDef),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(OpDef, _internal_metadata_));
+  OpDef_ArgDef_descriptor_ = OpDef_descriptor_->nested_type(0);
+  static const int OpDef_ArgDef_offsets_[7] = {
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(OpDef_ArgDef, name_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(OpDef_ArgDef, description_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(OpDef_ArgDef, type_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(OpDef_ArgDef, type_attr_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(OpDef_ArgDef, number_attr_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(OpDef_ArgDef, type_list_attr_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(OpDef_ArgDef, is_ref_),
+  };
+  OpDef_ArgDef_reflection_ =
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
+      OpDef_ArgDef_descriptor_,
+      OpDef_ArgDef::internal_default_instance(),
+      OpDef_ArgDef_offsets_,
+      -1,
+      -1,
+      -1,
+      sizeof(OpDef_ArgDef),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(OpDef_ArgDef, _internal_metadata_));
+  OpDef_AttrDef_descriptor_ = OpDef_descriptor_->nested_type(1);
+  static const int OpDef_AttrDef_offsets_[7] = {
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(OpDef_AttrDef, name_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(OpDef_AttrDef, type_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(OpDef_AttrDef, default_value_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(OpDef_AttrDef, description_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(OpDef_AttrDef, has_minimum_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(OpDef_AttrDef, minimum_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(OpDef_AttrDef, allowed_values_),
+  };
+  OpDef_AttrDef_reflection_ =
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
+      OpDef_AttrDef_descriptor_,
+      OpDef_AttrDef::internal_default_instance(),
+      OpDef_AttrDef_offsets_,
+      -1,
+      -1,
+      -1,
+      sizeof(OpDef_AttrDef),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(OpDef_AttrDef, _internal_metadata_));
+  OpDeprecation_descriptor_ = file->message_type(1);
+  static const int OpDeprecation_offsets_[2] = {
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(OpDeprecation, version_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(OpDeprecation, explanation_),
+  };
+  OpDeprecation_reflection_ =
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
+      OpDeprecation_descriptor_,
+      OpDeprecation::internal_default_instance(),
+      OpDeprecation_offsets_,
+      -1,
+      -1,
+      -1,
+      sizeof(OpDeprecation),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(OpDeprecation, _internal_metadata_));
+  OpList_descriptor_ = file->message_type(2);
+  static const int OpList_offsets_[1] = {
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(OpList, op_),
+  };
+  OpList_reflection_ =
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
+      OpList_descriptor_,
+      OpList::internal_default_instance(),
+      OpList_offsets_,
+      -1,
+      -1,
+      -1,
+      sizeof(OpList),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(OpList, _internal_metadata_));
+}
+
+namespace {
+
+GOOGLE_PROTOBUF_DECLARE_ONCE(protobuf_AssignDescriptors_once_);
+void protobuf_AssignDescriptorsOnce() {
+  ::google::protobuf::GoogleOnceInit(&protobuf_AssignDescriptors_once_,
+                 &protobuf_AssignDesc_op_5fdef_2eproto);
+}
+
+void protobuf_RegisterTypes(const ::std::string&) GOOGLE_ATTRIBUTE_COLD;
+void protobuf_RegisterTypes(const ::std::string&) {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+      OpDef_descriptor_, OpDef::internal_default_instance());
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+      OpDef_ArgDef_descriptor_, OpDef_ArgDef::internal_default_instance());
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+      OpDef_AttrDef_descriptor_, OpDef_AttrDef::internal_default_instance());
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+      OpDeprecation_descriptor_, OpDeprecation::internal_default_instance());
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+      OpList_descriptor_, OpList::internal_default_instance());
+}
+
+}  // namespace
+
+void protobuf_ShutdownFile_op_5fdef_2eproto() {
+  OpDef_default_instance_.Shutdown();
+  delete OpDef_reflection_;
+  OpDef_ArgDef_default_instance_.Shutdown();
+  delete OpDef_ArgDef_reflection_;
+  OpDef_AttrDef_default_instance_.Shutdown();
+  delete OpDef_AttrDef_reflection_;
+  OpDeprecation_default_instance_.Shutdown();
+  delete OpDeprecation_reflection_;
+  OpList_default_instance_.Shutdown();
+  delete OpList_reflection_;
+}
+
+void protobuf_InitDefaults_op_5fdef_2eproto_impl() {
+  GOOGLE_PROTOBUF_VERIFY_VERSION;
+
+  ::tensorflow::protobuf_InitDefaults_attr_5fvalue_2eproto();
+  ::tensorflow::protobuf_InitDefaults_types_2eproto();
+  ::google::protobuf::internal::GetEmptyString();
+  OpDef_default_instance_.DefaultConstruct();
+  ::google::protobuf::internal::GetEmptyString();
+  OpDef_ArgDef_default_instance_.DefaultConstruct();
+  ::google::protobuf::internal::GetEmptyString();
+  OpDef_AttrDef_default_instance_.DefaultConstruct();
+  ::google::protobuf::internal::GetEmptyString();
+  OpDeprecation_default_instance_.DefaultConstruct();
+  OpList_default_instance_.DefaultConstruct();
+  OpDef_default_instance_.get_mutable()->InitAsDefaultInstance();
+  OpDef_ArgDef_default_instance_.get_mutable()->InitAsDefaultInstance();
+  OpDef_AttrDef_default_instance_.get_mutable()->InitAsDefaultInstance();
+  OpDeprecation_default_instance_.get_mutable()->InitAsDefaultInstance();
+  OpList_default_instance_.get_mutable()->InitAsDefaultInstance();
+}
+
+GOOGLE_PROTOBUF_DECLARE_ONCE(protobuf_InitDefaults_op_5fdef_2eproto_once_);
+void protobuf_InitDefaults_op_5fdef_2eproto() {
+  ::google::protobuf::GoogleOnceInit(&protobuf_InitDefaults_op_5fdef_2eproto_once_,
+                 &protobuf_InitDefaults_op_5fdef_2eproto_impl);
+}
+void protobuf_AddDesc_op_5fdef_2eproto_impl() {
+  GOOGLE_PROTOBUF_VERIFY_VERSION;
+
+  protobuf_InitDefaults_op_5fdef_2eproto();
+  ::google::protobuf::DescriptorPool::InternalAddGeneratedFile(
+    "\n\014op_def.proto\022\ntensorflow\032\020attr_value.p"
+    "roto\032\013types.proto\"\270\005\n\005OpDef\022\014\n\004name\030\001 \001("
+    "\t\022+\n\tinput_arg\030\002 \003(\0132\030.tensorflow.OpDef."
+    "ArgDef\022,\n\noutput_arg\030\003 \003(\0132\030.tensorflow."
+    "OpDef.ArgDef\022\'\n\004attr\030\004 \003(\0132\031.tensorflow."
+    "OpDef.AttrDef\022.\n\013deprecation\030\010 \001(\0132\031.ten"
+    "sorflow.OpDeprecation\022\017\n\007summary\030\005 \001(\t\022\023"
+    "\n\013description\030\006 \001(\t\022\026\n\016is_commutative\030\022 "
+    "\001(\010\022\024\n\014is_aggregate\030\020 \001(\010\022\023\n\013is_stateful"
+    "\030\021 \001(\010\022\"\n\032allows_uninitialized_input\030\023 \001"
+    "(\010\032\237\001\n\006ArgDef\022\014\n\004name\030\001 \001(\t\022\023\n\013descripti"
+    "on\030\002 \001(\t\022\"\n\004type\030\003 \001(\0162\024.tensorflow.Data"
+    "Type\022\021\n\ttype_attr\030\004 \001(\t\022\023\n\013number_attr\030\005"
+    " \001(\t\022\026\n\016type_list_attr\030\006 \001(\t\022\016\n\006is_ref\030\020"
+    " \001(\010\032\275\001\n\007AttrDef\022\014\n\004name\030\001 \001(\t\022\014\n\004type\030\002"
+    " \001(\t\022,\n\rdefault_value\030\003 \001(\0132\025.tensorflow"
+    ".AttrValue\022\023\n\013description\030\004 \001(\t\022\023\n\013has_m"
+    "inimum\030\005 \001(\010\022\017\n\007minimum\030\006 \001(\003\022-\n\016allowed"
+    "_values\030\007 \001(\0132\025.tensorflow.AttrValue\"5\n\r"
+    "OpDeprecation\022\017\n\007version\030\001 \001(\005\022\023\n\013explan"
+    "ation\030\002 \001(\t\"\'\n\006OpList\022\035\n\002op\030\001 \003(\0132\021.tens"
+    "orflow.OpDefB,\n\030org.tensorflow.framework"
+    "B\013OpDefProtosP\001\370\001\001b\006proto3", 906);
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedFile(
+    "op_def.proto", &protobuf_RegisterTypes);
+  ::tensorflow::protobuf_AddDesc_attr_5fvalue_2eproto();
+  ::tensorflow::protobuf_AddDesc_types_2eproto();
+  ::google::protobuf::internal::OnShutdown(&protobuf_ShutdownFile_op_5fdef_2eproto);
+}
+
+GOOGLE_PROTOBUF_DECLARE_ONCE(protobuf_AddDesc_op_5fdef_2eproto_once_);
+void protobuf_AddDesc_op_5fdef_2eproto() {
+  ::google::protobuf::GoogleOnceInit(&protobuf_AddDesc_op_5fdef_2eproto_once_,
+                 &protobuf_AddDesc_op_5fdef_2eproto_impl);
+}
+// Force AddDescriptors() to be called at static initialization time.
+struct StaticDescriptorInitializer_op_5fdef_2eproto {
+  StaticDescriptorInitializer_op_5fdef_2eproto() {
+    protobuf_AddDesc_op_5fdef_2eproto();
+  }
+} static_descriptor_initializer_op_5fdef_2eproto_;
+
+namespace {
+
+static void MergeFromFail(int line) GOOGLE_ATTRIBUTE_COLD GOOGLE_ATTRIBUTE_NORETURN;
+static void MergeFromFail(int line) {
+  ::google::protobuf::internal::MergeFromFail(__FILE__, line);
+}
+
+}  // namespace
+
+
+// ===================================================================
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const int OpDef_ArgDef::kNameFieldNumber;
+const int OpDef_ArgDef::kDescriptionFieldNumber;
+const int OpDef_ArgDef::kTypeFieldNumber;
+const int OpDef_ArgDef::kTypeAttrFieldNumber;
+const int OpDef_ArgDef::kNumberAttrFieldNumber;
+const int OpDef_ArgDef::kTypeListAttrFieldNumber;
+const int OpDef_ArgDef::kIsRefFieldNumber;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+
+OpDef_ArgDef::OpDef_ArgDef()
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+  if (this != internal_default_instance()) protobuf_InitDefaults_op_5fdef_2eproto();
+  SharedCtor();
+  // @@protoc_insertion_point(constructor:tensorflow.OpDef.ArgDef)
+}
+OpDef_ArgDef::OpDef_ArgDef(::google::protobuf::Arena* arena)
+  : ::google::protobuf::Message(),
+  _internal_metadata_(arena) {
+#ifdef GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER
+  protobuf_InitDefaults_op_5fdef_2eproto();
+#endif  // GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER
+  SharedCtor();
+  RegisterArenaDtor(arena);
+  // @@protoc_insertion_point(arena_constructor:tensorflow.OpDef.ArgDef)
+}
+
+void OpDef_ArgDef::InitAsDefaultInstance() {
+}
+
+OpDef_ArgDef::OpDef_ArgDef(const OpDef_ArgDef& from)
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
+  SharedCtor();
+  UnsafeMergeFrom(from);
+  // @@protoc_insertion_point(copy_constructor:tensorflow.OpDef.ArgDef)
+}
+
+void OpDef_ArgDef::SharedCtor() {
+  name_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  description_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  type_attr_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  number_attr_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  type_list_attr_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  ::memset(&type_, 0, reinterpret_cast<char*>(&is_ref_) -
+    reinterpret_cast<char*>(&type_) + sizeof(is_ref_));
+  _cached_size_ = 0;
+}
+
+OpDef_ArgDef::~OpDef_ArgDef() {
+  // @@protoc_insertion_point(destructor:tensorflow.OpDef.ArgDef)
+  SharedDtor();
+}
+
+void OpDef_ArgDef::SharedDtor() {
+  ::google::protobuf::Arena* arena = GetArenaNoVirtual();
+  if (arena != NULL) {
+    return;
+  }
+
+  name_.Destroy(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), arena);
+  description_.Destroy(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), arena);
+  type_attr_.Destroy(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), arena);
+  number_attr_.Destroy(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), arena);
+  type_list_attr_.Destroy(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), arena);
+}
+
+void OpDef_ArgDef::ArenaDtor(void* object) {
+  OpDef_ArgDef* _this = reinterpret_cast< OpDef_ArgDef* >(object);
+  (void)_this;
+}
+void OpDef_ArgDef::RegisterArenaDtor(::google::protobuf::Arena* arena) {
+}
+void OpDef_ArgDef::SetCachedSize(int size) const {
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* OpDef_ArgDef::descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return OpDef_ArgDef_descriptor_;
+}
+
+const OpDef_ArgDef& OpDef_ArgDef::default_instance() {
+  protobuf_InitDefaults_op_5fdef_2eproto();
+  return *internal_default_instance();
+}
+
+::google::protobuf::internal::ExplicitlyConstructed<OpDef_ArgDef> OpDef_ArgDef_default_instance_;
+
+OpDef_ArgDef* OpDef_ArgDef::New(::google::protobuf::Arena* arena) const {
+  return ::google::protobuf::Arena::CreateMessage<OpDef_ArgDef>(arena);
+}
+
+void OpDef_ArgDef::Clear() {
+// @@protoc_insertion_point(message_clear_start:tensorflow.OpDef.ArgDef)
+#if defined(__clang__)
+#define ZR_HELPER_(f) \
+  _Pragma("clang diagnostic push") \
+  _Pragma("clang diagnostic ignored \"-Winvalid-offsetof\"") \
+  __builtin_offsetof(OpDef_ArgDef, f) \
+  _Pragma("clang diagnostic pop")
+#else
+#define ZR_HELPER_(f) reinterpret_cast<char*>(\
+  &reinterpret_cast<OpDef_ArgDef*>(16)->f)
+#endif
+
+#define ZR_(first, last) do {\
+  ::memset(&(first), 0,\
+           ZR_HELPER_(last) - ZR_HELPER_(first) + sizeof(last));\
+} while (0)
+
+  ZR_(type_, is_ref_);
+  name_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+  description_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+  type_attr_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+  number_attr_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+  type_list_attr_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+
+#undef ZR_HELPER_
+#undef ZR_
+
+}
+
+bool OpDef_ArgDef::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
+  ::google::protobuf::uint32 tag;
+  // @@protoc_insertion_point(parse_start:tensorflow.OpDef.ArgDef)
+  for (;;) {
+    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(16383);
+    tag = p.first;
+    if (!p.second) goto handle_unusual;
+    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+      // optional string name = 1;
+      case 1: {
+        if (tag == 10) {
+          DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+                input, this->mutable_name()));
+          DO_(::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+            this->name().data(), this->name().length(),
+            ::google::protobuf::internal::WireFormatLite::PARSE,
+            "tensorflow.OpDef.ArgDef.name"));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(18)) goto parse_description;
+        break;
+      }
+
+      // optional string description = 2;
+      case 2: {
+        if (tag == 18) {
+         parse_description:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+                input, this->mutable_description()));
+          DO_(::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+            this->description().data(), this->description().length(),
+            ::google::protobuf::internal::WireFormatLite::PARSE,
+            "tensorflow.OpDef.ArgDef.description"));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(24)) goto parse_type;
+        break;
+      }
+
+      // optional .tensorflow.DataType type = 3;
+      case 3: {
+        if (tag == 24) {
+         parse_type:
+          int value;
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>(
+                 input, &value)));
+          set_type(static_cast< ::tensorflow::DataType >(value));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(34)) goto parse_type_attr;
+        break;
+      }
+
+      // optional string type_attr = 4;
+      case 4: {
+        if (tag == 34) {
+         parse_type_attr:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+                input, this->mutable_type_attr()));
+          DO_(::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+            this->type_attr().data(), this->type_attr().length(),
+            ::google::protobuf::internal::WireFormatLite::PARSE,
+            "tensorflow.OpDef.ArgDef.type_attr"));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(42)) goto parse_number_attr;
+        break;
+      }
+
+      // optional string number_attr = 5;
+      case 5: {
+        if (tag == 42) {
+         parse_number_attr:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+                input, this->mutable_number_attr()));
+          DO_(::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+            this->number_attr().data(), this->number_attr().length(),
+            ::google::protobuf::internal::WireFormatLite::PARSE,
+            "tensorflow.OpDef.ArgDef.number_attr"));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(50)) goto parse_type_list_attr;
+        break;
+      }
+
+      // optional string type_list_attr = 6;
+      case 6: {
+        if (tag == 50) {
+         parse_type_list_attr:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+                input, this->mutable_type_list_attr()));
+          DO_(::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+            this->type_list_attr().data(), this->type_list_attr().length(),
+            ::google::protobuf::internal::WireFormatLite::PARSE,
+            "tensorflow.OpDef.ArgDef.type_list_attr"));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(128)) goto parse_is_ref;
+        break;
+      }
+
+      // optional bool is_ref = 16;
+      case 16: {
+        if (tag == 128) {
+         parse_is_ref:
+
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>(
+                 input, &is_ref_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectAtEnd()) goto success;
+        break;
+      }
+
+      default: {
+      handle_unusual:
+        if (tag == 0 ||
+            ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+          goto success;
+        }
+        DO_(::google::protobuf::internal::WireFormatLite::SkipField(input, tag));
+        break;
+      }
+    }
+  }
+success:
+  // @@protoc_insertion_point(parse_success:tensorflow.OpDef.ArgDef)
+  return true;
+failure:
+  // @@protoc_insertion_point(parse_failure:tensorflow.OpDef.ArgDef)
+  return false;
+#undef DO_
+}
+
+void OpDef_ArgDef::SerializeWithCachedSizes(
+    ::google::protobuf::io::CodedOutputStream* output) const {
+  // @@protoc_insertion_point(serialize_start:tensorflow.OpDef.ArgDef)
+  // optional string name = 1;
+  if (this->name().size() > 0) {
+    ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+      this->name().data(), this->name().length(),
+      ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+      "tensorflow.OpDef.ArgDef.name");
+    ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
+      1, this->name(), output);
+  }
+
+  // optional string description = 2;
+  if (this->description().size() > 0) {
+    ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+      this->description().data(), this->description().length(),
+      ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+      "tensorflow.OpDef.ArgDef.description");
+    ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
+      2, this->description(), output);
+  }
+
+  // optional .tensorflow.DataType type = 3;
+  if (this->type() != 0) {
+    ::google::protobuf::internal::WireFormatLite::WriteEnum(
+      3, this->type(), output);
+  }
+
+  // optional string type_attr = 4;
+  if (this->type_attr().size() > 0) {
+    ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+      this->type_attr().data(), this->type_attr().length(),
+      ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+      "tensorflow.OpDef.ArgDef.type_attr");
+    ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
+      4, this->type_attr(), output);
+  }
+
+  // optional string number_attr = 5;
+  if (this->number_attr().size() > 0) {
+    ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+      this->number_attr().data(), this->number_attr().length(),
+      ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+      "tensorflow.OpDef.ArgDef.number_attr");
+    ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
+      5, this->number_attr(), output);
+  }
+
+  // optional string type_list_attr = 6;
+  if (this->type_list_attr().size() > 0) {
+    ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+      this->type_list_attr().data(), this->type_list_attr().length(),
+      ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+      "tensorflow.OpDef.ArgDef.type_list_attr");
+    ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
+      6, this->type_list_attr(), output);
+  }
+
+  // optional bool is_ref = 16;
+  if (this->is_ref() != 0) {
+    ::google::protobuf::internal::WireFormatLite::WriteBool(16, this->is_ref(), output);
+  }
+
+  // @@protoc_insertion_point(serialize_end:tensorflow.OpDef.ArgDef)
+}
+
+::google::protobuf::uint8* OpDef_ArgDef::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
+  (void)deterministic; // Unused
+  // @@protoc_insertion_point(serialize_to_array_start:tensorflow.OpDef.ArgDef)
+  // optional string name = 1;
+  if (this->name().size() > 0) {
+    ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+      this->name().data(), this->name().length(),
+      ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+      "tensorflow.OpDef.ArgDef.name");
+    target =
+      ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
+        1, this->name(), target);
+  }
+
+  // optional string description = 2;
+  if (this->description().size() > 0) {
+    ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+      this->description().data(), this->description().length(),
+      ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+      "tensorflow.OpDef.ArgDef.description");
+    target =
+      ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
+        2, this->description(), target);
+  }
+
+  // optional .tensorflow.DataType type = 3;
+  if (this->type() != 0) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteEnumToArray(
+      3, this->type(), target);
+  }
+
+  // optional string type_attr = 4;
+  if (this->type_attr().size() > 0) {
+    ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+      this->type_attr().data(), this->type_attr().length(),
+      ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+      "tensorflow.OpDef.ArgDef.type_attr");
+    target =
+      ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
+        4, this->type_attr(), target);
+  }
+
+  // optional string number_attr = 5;
+  if (this->number_attr().size() > 0) {
+    ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+      this->number_attr().data(), this->number_attr().length(),
+      ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+      "tensorflow.OpDef.ArgDef.number_attr");
+    target =
+      ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
+        5, this->number_attr(), target);
+  }
+
+  // optional string type_list_attr = 6;
+  if (this->type_list_attr().size() > 0) {
+    ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+      this->type_list_attr().data(), this->type_list_attr().length(),
+      ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+      "tensorflow.OpDef.ArgDef.type_list_attr");
+    target =
+      ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
+        6, this->type_list_attr(), target);
+  }
+
+  // optional bool is_ref = 16;
+  if (this->is_ref() != 0) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(16, this->is_ref(), target);
+  }
+
+  // @@protoc_insertion_point(serialize_to_array_end:tensorflow.OpDef.ArgDef)
+  return target;
+}
+
+size_t OpDef_ArgDef::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:tensorflow.OpDef.ArgDef)
+  size_t total_size = 0;
+
+  // optional string name = 1;
+  if (this->name().size() > 0) {
+    total_size += 1 +
+      ::google::protobuf::internal::WireFormatLite::StringSize(
+        this->name());
+  }
+
+  // optional string description = 2;
+  if (this->description().size() > 0) {
+    total_size += 1 +
+      ::google::protobuf::internal::WireFormatLite::StringSize(
+        this->description());
+  }
+
+  // optional .tensorflow.DataType type = 3;
+  if (this->type() != 0) {
+    total_size += 1 +
+      ::google::protobuf::internal::WireFormatLite::EnumSize(this->type());
+  }
+
+  // optional string type_attr = 4;
+  if (this->type_attr().size() > 0) {
+    total_size += 1 +
+      ::google::protobuf::internal::WireFormatLite::StringSize(
+        this->type_attr());
+  }
+
+  // optional string number_attr = 5;
+  if (this->number_attr().size() > 0) {
+    total_size += 1 +
+      ::google::protobuf::internal::WireFormatLite::StringSize(
+        this->number_attr());
+  }
+
+  // optional string type_list_attr = 6;
+  if (this->type_list_attr().size() > 0) {
+    total_size += 1 +
+      ::google::protobuf::internal::WireFormatLite::StringSize(
+        this->type_list_attr());
+  }
+
+  // optional bool is_ref = 16;
+  if (this->is_ref() != 0) {
+    total_size += 2 + 1;
+  }
+
+  int cached_size = ::google::protobuf::internal::ToCachedSize(total_size);
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = cached_size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+  return total_size;
+}
+
+void OpDef_ArgDef::MergeFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_merge_from_start:tensorflow.OpDef.ArgDef)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const OpDef_ArgDef* source =
+      ::google::protobuf::internal::DynamicCastToGenerated<const OpDef_ArgDef>(
+          &from);
+  if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:tensorflow.OpDef.ArgDef)
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:tensorflow.OpDef.ArgDef)
+    UnsafeMergeFrom(*source);
+  }
+}
+
+void OpDef_ArgDef::MergeFrom(const OpDef_ArgDef& from) {
+// @@protoc_insertion_point(class_specific_merge_from_start:tensorflow.OpDef.ArgDef)
+  if (GOOGLE_PREDICT_TRUE(&from != this)) {
+    UnsafeMergeFrom(from);
+  } else {
+    MergeFromFail(__LINE__);
+  }
+}
+
+void OpDef_ArgDef::UnsafeMergeFrom(const OpDef_ArgDef& from) {
+  GOOGLE_DCHECK(&from != this);
+  if (from.name().size() > 0) {
+    set_name(from.name());
+  }
+  if (from.description().size() > 0) {
+    set_description(from.description());
+  }
+  if (from.type() != 0) {
+    set_type(from.type());
+  }
+  if (from.type_attr().size() > 0) {
+    set_type_attr(from.type_attr());
+  }
+  if (from.number_attr().size() > 0) {
+    set_number_attr(from.number_attr());
+  }
+  if (from.type_list_attr().size() > 0) {
+    set_type_list_attr(from.type_list_attr());
+  }
+  if (from.is_ref() != 0) {
+    set_is_ref(from.is_ref());
+  }
+}
+
+void OpDef_ArgDef::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:tensorflow.OpDef.ArgDef)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void OpDef_ArgDef::CopyFrom(const OpDef_ArgDef& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:tensorflow.OpDef.ArgDef)
+  if (&from == this) return;
+  Clear();
+  UnsafeMergeFrom(from);
+}
+
+bool OpDef_ArgDef::IsInitialized() const {
+
+  return true;
+}
+
+void OpDef_ArgDef::Swap(OpDef_ArgDef* other) {
+  if (other == this) return;
+  if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) {
+    InternalSwap(other);
+  } else {
+    OpDef_ArgDef temp;
+    temp.UnsafeMergeFrom(*this);
+    CopyFrom(*other);
+    other->CopyFrom(temp);
+  }
+}
+void OpDef_ArgDef::UnsafeArenaSwap(OpDef_ArgDef* other) {
+  if (other == this) return;
+  GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual());
+  InternalSwap(other);
+}
+void OpDef_ArgDef::InternalSwap(OpDef_ArgDef* other) {
+  name_.Swap(&other->name_);
+  description_.Swap(&other->description_);
+  std::swap(type_, other->type_);
+  type_attr_.Swap(&other->type_attr_);
+  number_attr_.Swap(&other->number_attr_);
+  type_list_attr_.Swap(&other->type_list_attr_);
+  std::swap(is_ref_, other->is_ref_);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
+}
+
+::google::protobuf::Metadata OpDef_ArgDef::GetMetadata() const {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::Metadata metadata;
+  metadata.descriptor = OpDef_ArgDef_descriptor_;
+  metadata.reflection = OpDef_ArgDef_reflection_;
+  return metadata;
+}
+
+
+// -------------------------------------------------------------------
+
+void OpDef_AttrDef::_slow_mutable_default_value() {
+  default_value_ = ::google::protobuf::Arena::CreateMessage< ::tensorflow::AttrValue >(
+      GetArenaNoVirtual());
+}
+::tensorflow::AttrValue* OpDef_AttrDef::_slow_release_default_value() {
+  if (default_value_ == NULL) {
+    return NULL;
+  } else {
+    ::tensorflow::AttrValue* temp = new ::tensorflow::AttrValue(*default_value_);
+    default_value_ = NULL;
+    return temp;
+  }
+}
+::tensorflow::AttrValue* OpDef_AttrDef::unsafe_arena_release_default_value() {
+  // @@protoc_insertion_point(field_unsafe_arena_release:tensorflow.OpDef.AttrDef.default_value)
+
+  ::tensorflow::AttrValue* temp = default_value_;
+  default_value_ = NULL;
+  return temp;
+}
+void OpDef_AttrDef::_slow_set_allocated_default_value(
+    ::google::protobuf::Arena* message_arena, ::tensorflow::AttrValue** default_value) {
+    if (message_arena != NULL &&
+        ::google::protobuf::Arena::GetArena(*default_value) == NULL) {
+      message_arena->Own(*default_value);
+    } else if (message_arena !=
+               ::google::protobuf::Arena::GetArena(*default_value)) {
+      ::tensorflow::AttrValue* new_default_value =
+            ::google::protobuf::Arena::CreateMessage< ::tensorflow::AttrValue >(
+            message_arena);
+      new_default_value->CopyFrom(**default_value);
+      *default_value = new_default_value;
+    }
+}
+void OpDef_AttrDef::unsafe_arena_set_allocated_default_value(
+    ::tensorflow::AttrValue* default_value) {
+  if (GetArenaNoVirtual() == NULL) {
+    delete default_value_;
+  }
+  default_value_ = default_value;
+  if (default_value) {
+
+  } else {
+
+  }
+  // @@protoc_insertion_point(field_unsafe_arena_set_allocated:tensorflow.OpDef.AttrDef.default_value)
+}
+void OpDef_AttrDef::_slow_mutable_allowed_values() {
+  allowed_values_ = ::google::protobuf::Arena::CreateMessage< ::tensorflow::AttrValue >(
+      GetArenaNoVirtual());
+}
+::tensorflow::AttrValue* OpDef_AttrDef::_slow_release_allowed_values() {
+  if (allowed_values_ == NULL) {
+    return NULL;
+  } else {
+    ::tensorflow::AttrValue* temp = new ::tensorflow::AttrValue(*allowed_values_);
+    allowed_values_ = NULL;
+    return temp;
+  }
+}
+::tensorflow::AttrValue* OpDef_AttrDef::unsafe_arena_release_allowed_values() {
+  // @@protoc_insertion_point(field_unsafe_arena_release:tensorflow.OpDef.AttrDef.allowed_values)
+
+  ::tensorflow::AttrValue* temp = allowed_values_;
+  allowed_values_ = NULL;
+  return temp;
+}
+void OpDef_AttrDef::_slow_set_allocated_allowed_values(
+    ::google::protobuf::Arena* message_arena, ::tensorflow::AttrValue** allowed_values) {
+    if (message_arena != NULL &&
+        ::google::protobuf::Arena::GetArena(*allowed_values) == NULL) {
+      message_arena->Own(*allowed_values);
+    } else if (message_arena !=
+               ::google::protobuf::Arena::GetArena(*allowed_values)) {
+      ::tensorflow::AttrValue* new_allowed_values =
+            ::google::protobuf::Arena::CreateMessage< ::tensorflow::AttrValue >(
+            message_arena);
+      new_allowed_values->CopyFrom(**allowed_values);
+      *allowed_values = new_allowed_values;
+    }
+}
+void OpDef_AttrDef::unsafe_arena_set_allocated_allowed_values(
+    ::tensorflow::AttrValue* allowed_values) {
+  if (GetArenaNoVirtual() == NULL) {
+    delete allowed_values_;
+  }
+  allowed_values_ = allowed_values;
+  if (allowed_values) {
+
+  } else {
+
+  }
+  // @@protoc_insertion_point(field_unsafe_arena_set_allocated:tensorflow.OpDef.AttrDef.allowed_values)
+}
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const int OpDef_AttrDef::kNameFieldNumber;
+const int OpDef_AttrDef::kTypeFieldNumber;
+const int OpDef_AttrDef::kDefaultValueFieldNumber;
+const int OpDef_AttrDef::kDescriptionFieldNumber;
+const int OpDef_AttrDef::kHasMinimumFieldNumber;
+const int OpDef_AttrDef::kMinimumFieldNumber;
+const int OpDef_AttrDef::kAllowedValuesFieldNumber;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+
+OpDef_AttrDef::OpDef_AttrDef()
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+  if (this != internal_default_instance()) protobuf_InitDefaults_op_5fdef_2eproto();
+  SharedCtor();
+  // @@protoc_insertion_point(constructor:tensorflow.OpDef.AttrDef)
+}
+OpDef_AttrDef::OpDef_AttrDef(::google::protobuf::Arena* arena)
+  : ::google::protobuf::Message(),
+  _internal_metadata_(arena) {
+#ifdef GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER
+  protobuf_InitDefaults_op_5fdef_2eproto();
+#endif  // GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER
+  SharedCtor();
+  RegisterArenaDtor(arena);
+  // @@protoc_insertion_point(arena_constructor:tensorflow.OpDef.AttrDef)
+}
+
+void OpDef_AttrDef::InitAsDefaultInstance() {
+  default_value_ = const_cast< ::tensorflow::AttrValue*>(
+      ::tensorflow::AttrValue::internal_default_instance());
+  allowed_values_ = const_cast< ::tensorflow::AttrValue*>(
+      ::tensorflow::AttrValue::internal_default_instance());
+}
+
+OpDef_AttrDef::OpDef_AttrDef(const OpDef_AttrDef& from)
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
+  SharedCtor();
+  UnsafeMergeFrom(from);
+  // @@protoc_insertion_point(copy_constructor:tensorflow.OpDef.AttrDef)
+}
+
+void OpDef_AttrDef::SharedCtor() {
+  name_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  type_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  description_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  default_value_ = NULL;
+  allowed_values_ = NULL;
+  ::memset(&minimum_, 0, reinterpret_cast<char*>(&has_minimum_) -
+    reinterpret_cast<char*>(&minimum_) + sizeof(has_minimum_));
+  _cached_size_ = 0;
+}
+
+OpDef_AttrDef::~OpDef_AttrDef() {
+  // @@protoc_insertion_point(destructor:tensorflow.OpDef.AttrDef)
+  SharedDtor();
+}
+
+void OpDef_AttrDef::SharedDtor() {
+  ::google::protobuf::Arena* arena = GetArenaNoVirtual();
+  if (arena != NULL) {
+    return;
+  }
+
+  name_.Destroy(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), arena);
+  type_.Destroy(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), arena);
+  description_.Destroy(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), arena);
+  if (this != &OpDef_AttrDef_default_instance_.get()) {
+    delete default_value_;
+    delete allowed_values_;
+  }
+}
+
+void OpDef_AttrDef::ArenaDtor(void* object) {
+  OpDef_AttrDef* _this = reinterpret_cast< OpDef_AttrDef* >(object);
+  (void)_this;
+}
+void OpDef_AttrDef::RegisterArenaDtor(::google::protobuf::Arena* arena) {
+}
+void OpDef_AttrDef::SetCachedSize(int size) const {
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* OpDef_AttrDef::descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return OpDef_AttrDef_descriptor_;
+}
+
+const OpDef_AttrDef& OpDef_AttrDef::default_instance() {
+  protobuf_InitDefaults_op_5fdef_2eproto();
+  return *internal_default_instance();
+}
+
+::google::protobuf::internal::ExplicitlyConstructed<OpDef_AttrDef> OpDef_AttrDef_default_instance_;
+
+OpDef_AttrDef* OpDef_AttrDef::New(::google::protobuf::Arena* arena) const {
+  return ::google::protobuf::Arena::CreateMessage<OpDef_AttrDef>(arena);
+}
+
+void OpDef_AttrDef::Clear() {
+// @@protoc_insertion_point(message_clear_start:tensorflow.OpDef.AttrDef)
+#if defined(__clang__)
+#define ZR_HELPER_(f) \
+  _Pragma("clang diagnostic push") \
+  _Pragma("clang diagnostic ignored \"-Winvalid-offsetof\"") \
+  __builtin_offsetof(OpDef_AttrDef, f) \
+  _Pragma("clang diagnostic pop")
+#else
+#define ZR_HELPER_(f) reinterpret_cast<char*>(\
+  &reinterpret_cast<OpDef_AttrDef*>(16)->f)
+#endif
+
+#define ZR_(first, last) do {\
+  ::memset(&(first), 0,\
+           ZR_HELPER_(last) - ZR_HELPER_(first) + sizeof(last));\
+} while (0)
+
+  ZR_(minimum_, has_minimum_);
+  name_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+  type_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+  if (GetArenaNoVirtual() == NULL && default_value_ != NULL) delete default_value_;
+  default_value_ = NULL;
+  description_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+  if (GetArenaNoVirtual() == NULL && allowed_values_ != NULL) delete allowed_values_;
+  allowed_values_ = NULL;
+
+#undef ZR_HELPER_
+#undef ZR_
+
+}
+
+bool OpDef_AttrDef::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
+  ::google::protobuf::uint32 tag;
+  // @@protoc_insertion_point(parse_start:tensorflow.OpDef.AttrDef)
+  for (;;) {
+    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+    tag = p.first;
+    if (!p.second) goto handle_unusual;
+    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+      // optional string name = 1;
+      case 1: {
+        if (tag == 10) {
+          DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+                input, this->mutable_name()));
+          DO_(::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+            this->name().data(), this->name().length(),
+            ::google::protobuf::internal::WireFormatLite::PARSE,
+            "tensorflow.OpDef.AttrDef.name"));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(18)) goto parse_type;
+        break;
+      }
+
+      // optional string type = 2;
+      case 2: {
+        if (tag == 18) {
+         parse_type:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+                input, this->mutable_type()));
+          DO_(::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+            this->type().data(), this->type().length(),
+            ::google::protobuf::internal::WireFormatLite::PARSE,
+            "tensorflow.OpDef.AttrDef.type"));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(26)) goto parse_default_value;
+        break;
+      }
+
+      // optional .tensorflow.AttrValue default_value = 3;
+      case 3: {
+        if (tag == 26) {
+         parse_default_value:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+               input, mutable_default_value()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(34)) goto parse_description;
+        break;
+      }
+
+      // optional string description = 4;
+      case 4: {
+        if (tag == 34) {
+         parse_description:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+                input, this->mutable_description()));
+          DO_(::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+            this->description().data(), this->description().length(),
+            ::google::protobuf::internal::WireFormatLite::PARSE,
+            "tensorflow.OpDef.AttrDef.description"));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(40)) goto parse_has_minimum;
+        break;
+      }
+
+      // optional bool has_minimum = 5;
+      case 5: {
+        if (tag == 40) {
+         parse_has_minimum:
+
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>(
+                 input, &has_minimum_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(48)) goto parse_minimum;
+        break;
+      }
+
+      // optional int64 minimum = 6;
+      case 6: {
+        if (tag == 48) {
+         parse_minimum:
+
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::int64, ::google::protobuf::internal::WireFormatLite::TYPE_INT64>(
+                 input, &minimum_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(58)) goto parse_allowed_values;
+        break;
+      }
+
+      // optional .tensorflow.AttrValue allowed_values = 7;
+      case 7: {
+        if (tag == 58) {
+         parse_allowed_values:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+               input, mutable_allowed_values()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectAtEnd()) goto success;
+        break;
+      }
+
+      default: {
+      handle_unusual:
+        if (tag == 0 ||
+            ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+          goto success;
+        }
+        DO_(::google::protobuf::internal::WireFormatLite::SkipField(input, tag));
+        break;
+      }
+    }
+  }
+success:
+  // @@protoc_insertion_point(parse_success:tensorflow.OpDef.AttrDef)
+  return true;
+failure:
+  // @@protoc_insertion_point(parse_failure:tensorflow.OpDef.AttrDef)
+  return false;
+#undef DO_
+}
+
+void OpDef_AttrDef::SerializeWithCachedSizes(
+    ::google::protobuf::io::CodedOutputStream* output) const {
+  // @@protoc_insertion_point(serialize_start:tensorflow.OpDef.AttrDef)
+  // optional string name = 1;
+  if (this->name().size() > 0) {
+    ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+      this->name().data(), this->name().length(),
+      ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+      "tensorflow.OpDef.AttrDef.name");
+    ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
+      1, this->name(), output);
+  }
+
+  // optional string type = 2;
+  if (this->type().size() > 0) {
+    ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+      this->type().data(), this->type().length(),
+      ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+      "tensorflow.OpDef.AttrDef.type");
+    ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
+      2, this->type(), output);
+  }
+
+  // optional .tensorflow.AttrValue default_value = 3;
+  if (this->has_default_value()) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      3, *this->default_value_, output);
+  }
+
+  // optional string description = 4;
+  if (this->description().size() > 0) {
+    ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+      this->description().data(), this->description().length(),
+      ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+      "tensorflow.OpDef.AttrDef.description");
+    ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
+      4, this->description(), output);
+  }
+
+  // optional bool has_minimum = 5;
+  if (this->has_minimum() != 0) {
+    ::google::protobuf::internal::WireFormatLite::WriteBool(5, this->has_minimum(), output);
+  }
+
+  // optional int64 minimum = 6;
+  if (this->minimum() != 0) {
+    ::google::protobuf::internal::WireFormatLite::WriteInt64(6, this->minimum(), output);
+  }
+
+  // optional .tensorflow.AttrValue allowed_values = 7;
+  if (this->has_allowed_values()) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      7, *this->allowed_values_, output);
+  }
+
+  // @@protoc_insertion_point(serialize_end:tensorflow.OpDef.AttrDef)
+}
+
+::google::protobuf::uint8* OpDef_AttrDef::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
+  (void)deterministic; // Unused
+  // @@protoc_insertion_point(serialize_to_array_start:tensorflow.OpDef.AttrDef)
+  // optional string name = 1;
+  if (this->name().size() > 0) {
+    ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+      this->name().data(), this->name().length(),
+      ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+      "tensorflow.OpDef.AttrDef.name");
+    target =
+      ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
+        1, this->name(), target);
+  }
+
+  // optional string type = 2;
+  if (this->type().size() > 0) {
+    ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+      this->type().data(), this->type().length(),
+      ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+      "tensorflow.OpDef.AttrDef.type");
+    target =
+      ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
+        2, this->type(), target);
+  }
+
+  // optional .tensorflow.AttrValue default_value = 3;
+  if (this->has_default_value()) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        3, *this->default_value_, false, target);
+  }
+
+  // optional string description = 4;
+  if (this->description().size() > 0) {
+    ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+      this->description().data(), this->description().length(),
+      ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+      "tensorflow.OpDef.AttrDef.description");
+    target =
+      ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
+        4, this->description(), target);
+  }
+
+  // optional bool has_minimum = 5;
+  if (this->has_minimum() != 0) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(5, this->has_minimum(), target);
+  }
+
+  // optional int64 minimum = 6;
+  if (this->minimum() != 0) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteInt64ToArray(6, this->minimum(), target);
+  }
+
+  // optional .tensorflow.AttrValue allowed_values = 7;
+  if (this->has_allowed_values()) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        7, *this->allowed_values_, false, target);
+  }
+
+  // @@protoc_insertion_point(serialize_to_array_end:tensorflow.OpDef.AttrDef)
+  return target;
+}
+
+size_t OpDef_AttrDef::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:tensorflow.OpDef.AttrDef)
+  size_t total_size = 0;
+
+  // optional string name = 1;
+  if (this->name().size() > 0) {
+    total_size += 1 +
+      ::google::protobuf::internal::WireFormatLite::StringSize(
+        this->name());
+  }
+
+  // optional string type = 2;
+  if (this->type().size() > 0) {
+    total_size += 1 +
+      ::google::protobuf::internal::WireFormatLite::StringSize(
+        this->type());
+  }
+
+  // optional .tensorflow.AttrValue default_value = 3;
+  if (this->has_default_value()) {
+    total_size += 1 +
+      ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+        *this->default_value_);
+  }
+
+  // optional string description = 4;
+  if (this->description().size() > 0) {
+    total_size += 1 +
+      ::google::protobuf::internal::WireFormatLite::StringSize(
+        this->description());
+  }
+
+  // optional bool has_minimum = 5;
+  if (this->has_minimum() != 0) {
+    total_size += 1 + 1;
+  }
+
+  // optional int64 minimum = 6;
+  if (this->minimum() != 0) {
+    total_size += 1 +
+      ::google::protobuf::internal::WireFormatLite::Int64Size(
+        this->minimum());
+  }
+
+  // optional .tensorflow.AttrValue allowed_values = 7;
+  if (this->has_allowed_values()) {
+    total_size += 1 +
+      ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+        *this->allowed_values_);
+  }
+
+  int cached_size = ::google::protobuf::internal::ToCachedSize(total_size);
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = cached_size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+  return total_size;
+}
+
+void OpDef_AttrDef::MergeFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_merge_from_start:tensorflow.OpDef.AttrDef)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const OpDef_AttrDef* source =
+      ::google::protobuf::internal::DynamicCastToGenerated<const OpDef_AttrDef>(
+          &from);
+  if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:tensorflow.OpDef.AttrDef)
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:tensorflow.OpDef.AttrDef)
+    UnsafeMergeFrom(*source);
+  }
+}
+
+void OpDef_AttrDef::MergeFrom(const OpDef_AttrDef& from) {
+// @@protoc_insertion_point(class_specific_merge_from_start:tensorflow.OpDef.AttrDef)
+  if (GOOGLE_PREDICT_TRUE(&from != this)) {
+    UnsafeMergeFrom(from);
+  } else {
+    MergeFromFail(__LINE__);
+  }
+}
+
+void OpDef_AttrDef::UnsafeMergeFrom(const OpDef_AttrDef& from) {
+  GOOGLE_DCHECK(&from != this);
+  if (from.name().size() > 0) {
+    set_name(from.name());
+  }
+  if (from.type().size() > 0) {
+    set_type(from.type());
+  }
+  if (from.has_default_value()) {
+    mutable_default_value()->::tensorflow::AttrValue::MergeFrom(from.default_value());
+  }
+  if (from.description().size() > 0) {
+    set_description(from.description());
+  }
+  if (from.has_minimum() != 0) {
+    set_has_minimum(from.has_minimum());
+  }
+  if (from.minimum() != 0) {
+    set_minimum(from.minimum());
+  }
+  if (from.has_allowed_values()) {
+    mutable_allowed_values()->::tensorflow::AttrValue::MergeFrom(from.allowed_values());
+  }
+}
+
+void OpDef_AttrDef::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:tensorflow.OpDef.AttrDef)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void OpDef_AttrDef::CopyFrom(const OpDef_AttrDef& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:tensorflow.OpDef.AttrDef)
+  if (&from == this) return;
+  Clear();
+  UnsafeMergeFrom(from);
+}
+
+bool OpDef_AttrDef::IsInitialized() const {
+
+  return true;
+}
+
+void OpDef_AttrDef::Swap(OpDef_AttrDef* other) {
+  if (other == this) return;
+  if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) {
+    InternalSwap(other);
+  } else {
+    OpDef_AttrDef temp;
+    temp.UnsafeMergeFrom(*this);
+    CopyFrom(*other);
+    other->CopyFrom(temp);
+  }
+}
+void OpDef_AttrDef::UnsafeArenaSwap(OpDef_AttrDef* other) {
+  if (other == this) return;
+  GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual());
+  InternalSwap(other);
+}
+void OpDef_AttrDef::InternalSwap(OpDef_AttrDef* other) {
+  name_.Swap(&other->name_);
+  type_.Swap(&other->type_);
+  std::swap(default_value_, other->default_value_);
+  description_.Swap(&other->description_);
+  std::swap(has_minimum_, other->has_minimum_);
+  std::swap(minimum_, other->minimum_);
+  std::swap(allowed_values_, other->allowed_values_);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
+}
+
+::google::protobuf::Metadata OpDef_AttrDef::GetMetadata() const {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::Metadata metadata;
+  metadata.descriptor = OpDef_AttrDef_descriptor_;
+  metadata.reflection = OpDef_AttrDef_reflection_;
+  return metadata;
+}
+
+
+// -------------------------------------------------------------------
+
+void OpDef::_slow_mutable_deprecation() {
+  deprecation_ = ::google::protobuf::Arena::CreateMessage< ::tensorflow::OpDeprecation >(
+      GetArenaNoVirtual());
+}
+::tensorflow::OpDeprecation* OpDef::_slow_release_deprecation() {
+  if (deprecation_ == NULL) {
+    return NULL;
+  } else {
+    ::tensorflow::OpDeprecation* temp = new ::tensorflow::OpDeprecation(*deprecation_);
+    deprecation_ = NULL;
+    return temp;
+  }
+}
+::tensorflow::OpDeprecation* OpDef::unsafe_arena_release_deprecation() {
+  // @@protoc_insertion_point(field_unsafe_arena_release:tensorflow.OpDef.deprecation)
+
+  ::tensorflow::OpDeprecation* temp = deprecation_;
+  deprecation_ = NULL;
+  return temp;
+}
+void OpDef::_slow_set_allocated_deprecation(
+    ::google::protobuf::Arena* message_arena, ::tensorflow::OpDeprecation** deprecation) {
+    if (message_arena != NULL &&
+        ::google::protobuf::Arena::GetArena(*deprecation) == NULL) {
+      message_arena->Own(*deprecation);
+    } else if (message_arena !=
+               ::google::protobuf::Arena::GetArena(*deprecation)) {
+      ::tensorflow::OpDeprecation* new_deprecation =
+            ::google::protobuf::Arena::CreateMessage< ::tensorflow::OpDeprecation >(
+            message_arena);
+      new_deprecation->CopyFrom(**deprecation);
+      *deprecation = new_deprecation;
+    }
+}
+void OpDef::unsafe_arena_set_allocated_deprecation(
+    ::tensorflow::OpDeprecation* deprecation) {
+  if (GetArenaNoVirtual() == NULL) {
+    delete deprecation_;
+  }
+  deprecation_ = deprecation;
+  if (deprecation) {
+
+  } else {
+
+  }
+  // @@protoc_insertion_point(field_unsafe_arena_set_allocated:tensorflow.OpDef.deprecation)
+}
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const int OpDef::kNameFieldNumber;
+const int OpDef::kInputArgFieldNumber;
+const int OpDef::kOutputArgFieldNumber;
+const int OpDef::kAttrFieldNumber;
+const int OpDef::kDeprecationFieldNumber;
+const int OpDef::kSummaryFieldNumber;
+const int OpDef::kDescriptionFieldNumber;
+const int OpDef::kIsCommutativeFieldNumber;
+const int OpDef::kIsAggregateFieldNumber;
+const int OpDef::kIsStatefulFieldNumber;
+const int OpDef::kAllowsUninitializedInputFieldNumber;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+
+OpDef::OpDef()
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+  if (this != internal_default_instance()) protobuf_InitDefaults_op_5fdef_2eproto();
+  SharedCtor();
+  // @@protoc_insertion_point(constructor:tensorflow.OpDef)
+}
+OpDef::OpDef(::google::protobuf::Arena* arena)
+  : ::google::protobuf::Message(),
+  _internal_metadata_(arena),
+  input_arg_(arena),
+  output_arg_(arena),
+  attr_(arena) {
+#ifdef GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER
+  protobuf_InitDefaults_op_5fdef_2eproto();
+#endif  // GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER
+  SharedCtor();
+  RegisterArenaDtor(arena);
+  // @@protoc_insertion_point(arena_constructor:tensorflow.OpDef)
+}
+
+void OpDef::InitAsDefaultInstance() {
+  deprecation_ = const_cast< ::tensorflow::OpDeprecation*>(
+      ::tensorflow::OpDeprecation::internal_default_instance());
+}
+
+OpDef::OpDef(const OpDef& from)
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
+  SharedCtor();
+  UnsafeMergeFrom(from);
+  // @@protoc_insertion_point(copy_constructor:tensorflow.OpDef)
+}
+
+void OpDef::SharedCtor() {
+  name_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  summary_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  description_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  deprecation_ = NULL;
+  ::memset(&is_commutative_, 0, reinterpret_cast<char*>(&allows_uninitialized_input_) -
+    reinterpret_cast<char*>(&is_commutative_) + sizeof(allows_uninitialized_input_));
+  _cached_size_ = 0;
+}
+
+OpDef::~OpDef() {
+  // @@protoc_insertion_point(destructor:tensorflow.OpDef)
+  SharedDtor();
+}
+
+void OpDef::SharedDtor() {
+  ::google::protobuf::Arena* arena = GetArenaNoVirtual();
+  if (arena != NULL) {
+    return;
+  }
+
+  name_.Destroy(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), arena);
+  summary_.Destroy(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), arena);
+  description_.Destroy(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), arena);
+  if (this != &OpDef_default_instance_.get()) {
+    delete deprecation_;
+  }
+}
+
+void OpDef::ArenaDtor(void* object) {
+  OpDef* _this = reinterpret_cast< OpDef* >(object);
+  (void)_this;
+}
+void OpDef::RegisterArenaDtor(::google::protobuf::Arena* arena) {
+}
+void OpDef::SetCachedSize(int size) const {
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* OpDef::descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return OpDef_descriptor_;
+}
+
+const OpDef& OpDef::default_instance() {
+  protobuf_InitDefaults_op_5fdef_2eproto();
+  return *internal_default_instance();
+}
+
+::google::protobuf::internal::ExplicitlyConstructed<OpDef> OpDef_default_instance_;
+
+OpDef* OpDef::New(::google::protobuf::Arena* arena) const {
+  return ::google::protobuf::Arena::CreateMessage<OpDef>(arena);
+}
+
+void OpDef::Clear() {
+// @@protoc_insertion_point(message_clear_start:tensorflow.OpDef)
+#if defined(__clang__)
+#define ZR_HELPER_(f) \
+  _Pragma("clang diagnostic push") \
+  _Pragma("clang diagnostic ignored \"-Winvalid-offsetof\"") \
+  __builtin_offsetof(OpDef, f) \
+  _Pragma("clang diagnostic pop")
+#else
+#define ZR_HELPER_(f) reinterpret_cast<char*>(\
+  &reinterpret_cast<OpDef*>(16)->f)
+#endif
+
+#define ZR_(first, last) do {\
+  ::memset(&(first), 0,\
+           ZR_HELPER_(last) - ZR_HELPER_(first) + sizeof(last));\
+} while (0)
+
+  name_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+  if (GetArenaNoVirtual() == NULL && deprecation_ != NULL) delete deprecation_;
+  deprecation_ = NULL;
+  summary_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+  description_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+  is_commutative_ = false;
+  ZR_(is_aggregate_, allows_uninitialized_input_);
+
+#undef ZR_HELPER_
+#undef ZR_
+
+  input_arg_.Clear();
+  output_arg_.Clear();
+  attr_.Clear();
+}
+
+bool OpDef::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
+  ::google::protobuf::uint32 tag;
+  // @@protoc_insertion_point(parse_start:tensorflow.OpDef)
+  for (;;) {
+    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(16383);
+    tag = p.first;
+    if (!p.second) goto handle_unusual;
+    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+      // optional string name = 1;
+      case 1: {
+        if (tag == 10) {
+          DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+                input, this->mutable_name()));
+          DO_(::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+            this->name().data(), this->name().length(),
+            ::google::protobuf::internal::WireFormatLite::PARSE,
+            "tensorflow.OpDef.name"));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(18)) goto parse_input_arg;
+        break;
+      }
+
+      // repeated .tensorflow.OpDef.ArgDef input_arg = 2;
+      case 2: {
+        if (tag == 18) {
+         parse_input_arg:
+          DO_(input->IncrementRecursionDepth());
+         parse_loop_input_arg:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth(
+                input, add_input_arg()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(18)) goto parse_loop_input_arg;
+        if (input->ExpectTag(26)) goto parse_loop_output_arg;
+        input->UnsafeDecrementRecursionDepth();
+        break;
+      }
+
+      // repeated .tensorflow.OpDef.ArgDef output_arg = 3;
+      case 3: {
+        if (tag == 26) {
+          DO_(input->IncrementRecursionDepth());
+         parse_loop_output_arg:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth(
+                input, add_output_arg()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(26)) goto parse_loop_output_arg;
+        if (input->ExpectTag(34)) goto parse_loop_attr;
+        input->UnsafeDecrementRecursionDepth();
+        break;
+      }
+
+      // repeated .tensorflow.OpDef.AttrDef attr = 4;
+      case 4: {
+        if (tag == 34) {
+          DO_(input->IncrementRecursionDepth());
+         parse_loop_attr:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth(
+                input, add_attr()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(34)) goto parse_loop_attr;
+        input->UnsafeDecrementRecursionDepth();
+        if (input->ExpectTag(42)) goto parse_summary;
+        break;
+      }
+
+      // optional string summary = 5;
+      case 5: {
+        if (tag == 42) {
+         parse_summary:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+                input, this->mutable_summary()));
+          DO_(::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+            this->summary().data(), this->summary().length(),
+            ::google::protobuf::internal::WireFormatLite::PARSE,
+            "tensorflow.OpDef.summary"));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(50)) goto parse_description;
+        break;
+      }
+
+      // optional string description = 6;
+      case 6: {
+        if (tag == 50) {
+         parse_description:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+                input, this->mutable_description()));
+          DO_(::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+            this->description().data(), this->description().length(),
+            ::google::protobuf::internal::WireFormatLite::PARSE,
+            "tensorflow.OpDef.description"));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(66)) goto parse_deprecation;
+        break;
+      }
+
+      // optional .tensorflow.OpDeprecation deprecation = 8;
+      case 8: {
+        if (tag == 66) {
+         parse_deprecation:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+               input, mutable_deprecation()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(128)) goto parse_is_aggregate;
+        break;
+      }
+
+      // optional bool is_aggregate = 16;
+      case 16: {
+        if (tag == 128) {
+         parse_is_aggregate:
+
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>(
+                 input, &is_aggregate_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(136)) goto parse_is_stateful;
+        break;
+      }
+
+      // optional bool is_stateful = 17;
+      case 17: {
+        if (tag == 136) {
+         parse_is_stateful:
+
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>(
+                 input, &is_stateful_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(144)) goto parse_is_commutative;
+        break;
+      }
+
+      // optional bool is_commutative = 18;
+      case 18: {
+        if (tag == 144) {
+         parse_is_commutative:
+
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>(
+                 input, &is_commutative_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(152)) goto parse_allows_uninitialized_input;
+        break;
+      }
+
+      // optional bool allows_uninitialized_input = 19;
+      case 19: {
+        if (tag == 152) {
+         parse_allows_uninitialized_input:
+
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>(
+                 input, &allows_uninitialized_input_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectAtEnd()) goto success;
+        break;
+      }
+
+      default: {
+      handle_unusual:
+        if (tag == 0 ||
+            ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+          goto success;
+        }
+        DO_(::google::protobuf::internal::WireFormatLite::SkipField(input, tag));
+        break;
+      }
+    }
+  }
+success:
+  // @@protoc_insertion_point(parse_success:tensorflow.OpDef)
+  return true;
+failure:
+  // @@protoc_insertion_point(parse_failure:tensorflow.OpDef)
+  return false;
+#undef DO_
+}
+
+void OpDef::SerializeWithCachedSizes(
+    ::google::protobuf::io::CodedOutputStream* output) const {
+  // @@protoc_insertion_point(serialize_start:tensorflow.OpDef)
+  // optional string name = 1;
+  if (this->name().size() > 0) {
+    ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+      this->name().data(), this->name().length(),
+      ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+      "tensorflow.OpDef.name");
+    ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
+      1, this->name(), output);
+  }
+
+  // repeated .tensorflow.OpDef.ArgDef input_arg = 2;
+  for (unsigned int i = 0, n = this->input_arg_size(); i < n; i++) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      2, this->input_arg(i), output);
+  }
+
+  // repeated .tensorflow.OpDef.ArgDef output_arg = 3;
+  for (unsigned int i = 0, n = this->output_arg_size(); i < n; i++) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      3, this->output_arg(i), output);
+  }
+
+  // repeated .tensorflow.OpDef.AttrDef attr = 4;
+  for (unsigned int i = 0, n = this->attr_size(); i < n; i++) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      4, this->attr(i), output);
+  }
+
+  // optional string summary = 5;
+  if (this->summary().size() > 0) {
+    ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+      this->summary().data(), this->summary().length(),
+      ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+      "tensorflow.OpDef.summary");
+    ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
+      5, this->summary(), output);
+  }
+
+  // optional string description = 6;
+  if (this->description().size() > 0) {
+    ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+      this->description().data(), this->description().length(),
+      ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+      "tensorflow.OpDef.description");
+    ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
+      6, this->description(), output);
+  }
+
+  // optional .tensorflow.OpDeprecation deprecation = 8;
+  if (this->has_deprecation()) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      8, *this->deprecation_, output);
+  }
+
+  // optional bool is_aggregate = 16;
+  if (this->is_aggregate() != 0) {
+    ::google::protobuf::internal::WireFormatLite::WriteBool(16, this->is_aggregate(), output);
+  }
+
+  // optional bool is_stateful = 17;
+  if (this->is_stateful() != 0) {
+    ::google::protobuf::internal::WireFormatLite::WriteBool(17, this->is_stateful(), output);
+  }
+
+  // optional bool is_commutative = 18;
+  if (this->is_commutative() != 0) {
+    ::google::protobuf::internal::WireFormatLite::WriteBool(18, this->is_commutative(), output);
+  }
+
+  // optional bool allows_uninitialized_input = 19;
+  if (this->allows_uninitialized_input() != 0) {
+    ::google::protobuf::internal::WireFormatLite::WriteBool(19, this->allows_uninitialized_input(), output);
+  }
+
+  // @@protoc_insertion_point(serialize_end:tensorflow.OpDef)
+}
+
+::google::protobuf::uint8* OpDef::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
+  (void)deterministic; // Unused
+  // @@protoc_insertion_point(serialize_to_array_start:tensorflow.OpDef)
+  // optional string name = 1;
+  if (this->name().size() > 0) {
+    ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+      this->name().data(), this->name().length(),
+      ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+      "tensorflow.OpDef.name");
+    target =
+      ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
+        1, this->name(), target);
+  }
+
+  // repeated .tensorflow.OpDef.ArgDef input_arg = 2;
+  for (unsigned int i = 0, n = this->input_arg_size(); i < n; i++) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        2, this->input_arg(i), false, target);
+  }
+
+  // repeated .tensorflow.OpDef.ArgDef output_arg = 3;
+  for (unsigned int i = 0, n = this->output_arg_size(); i < n; i++) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        3, this->output_arg(i), false, target);
+  }
+
+  // repeated .tensorflow.OpDef.AttrDef attr = 4;
+  for (unsigned int i = 0, n = this->attr_size(); i < n; i++) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        4, this->attr(i), false, target);
+  }
+
+  // optional string summary = 5;
+  if (this->summary().size() > 0) {
+    ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+      this->summary().data(), this->summary().length(),
+      ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+      "tensorflow.OpDef.summary");
+    target =
+      ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
+        5, this->summary(), target);
+  }
+
+  // optional string description = 6;
+  if (this->description().size() > 0) {
+    ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+      this->description().data(), this->description().length(),
+      ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+      "tensorflow.OpDef.description");
+    target =
+      ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
+        6, this->description(), target);
+  }
+
+  // optional .tensorflow.OpDeprecation deprecation = 8;
+  if (this->has_deprecation()) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        8, *this->deprecation_, false, target);
+  }
+
+  // optional bool is_aggregate = 16;
+  if (this->is_aggregate() != 0) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(16, this->is_aggregate(), target);
+  }
+
+  // optional bool is_stateful = 17;
+  if (this->is_stateful() != 0) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(17, this->is_stateful(), target);
+  }
+
+  // optional bool is_commutative = 18;
+  if (this->is_commutative() != 0) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(18, this->is_commutative(), target);
+  }
+
+  // optional bool allows_uninitialized_input = 19;
+  if (this->allows_uninitialized_input() != 0) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(19, this->allows_uninitialized_input(), target);
+  }
+
+  // @@protoc_insertion_point(serialize_to_array_end:tensorflow.OpDef)
+  return target;
+}
+
+size_t OpDef::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:tensorflow.OpDef)
+  size_t total_size = 0;
+
+  // optional string name = 1;
+  if (this->name().size() > 0) {
+    total_size += 1 +
+      ::google::protobuf::internal::WireFormatLite::StringSize(
+        this->name());
+  }
+
+  // optional .tensorflow.OpDeprecation deprecation = 8;
+  if (this->has_deprecation()) {
+    total_size += 1 +
+      ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+        *this->deprecation_);
+  }
+
+  // optional string summary = 5;
+  if (this->summary().size() > 0) {
+    total_size += 1 +
+      ::google::protobuf::internal::WireFormatLite::StringSize(
+        this->summary());
+  }
+
+  // optional string description = 6;
+  if (this->description().size() > 0) {
+    total_size += 1 +
+      ::google::protobuf::internal::WireFormatLite::StringSize(
+        this->description());
+  }
+
+  // optional bool is_commutative = 18;
+  if (this->is_commutative() != 0) {
+    total_size += 2 + 1;
+  }
+
+  // optional bool is_aggregate = 16;
+  if (this->is_aggregate() != 0) {
+    total_size += 2 + 1;
+  }
+
+  // optional bool is_stateful = 17;
+  if (this->is_stateful() != 0) {
+    total_size += 2 + 1;
+  }
+
+  // optional bool allows_uninitialized_input = 19;
+  if (this->allows_uninitialized_input() != 0) {
+    total_size += 2 + 1;
+  }
+
+  // repeated .tensorflow.OpDef.ArgDef input_arg = 2;
+  {
+    unsigned int count = this->input_arg_size();
+    total_size += 1UL * count;
+    for (unsigned int i = 0; i < count; i++) {
+      total_size +=
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          this->input_arg(i));
+    }
+  }
+
+  // repeated .tensorflow.OpDef.ArgDef output_arg = 3;
+  {
+    unsigned int count = this->output_arg_size();
+    total_size += 1UL * count;
+    for (unsigned int i = 0; i < count; i++) {
+      total_size +=
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          this->output_arg(i));
+    }
+  }
+
+  // repeated .tensorflow.OpDef.AttrDef attr = 4;
+  {
+    unsigned int count = this->attr_size();
+    total_size += 1UL * count;
+    for (unsigned int i = 0; i < count; i++) {
+      total_size +=
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          this->attr(i));
+    }
+  }
+
+  int cached_size = ::google::protobuf::internal::ToCachedSize(total_size);
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = cached_size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+  return total_size;
+}
+
+void OpDef::MergeFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_merge_from_start:tensorflow.OpDef)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const OpDef* source =
+      ::google::protobuf::internal::DynamicCastToGenerated<const OpDef>(
+          &from);
+  if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:tensorflow.OpDef)
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:tensorflow.OpDef)
+    UnsafeMergeFrom(*source);
+  }
+}
+
+void OpDef::MergeFrom(const OpDef& from) {
+// @@protoc_insertion_point(class_specific_merge_from_start:tensorflow.OpDef)
+  if (GOOGLE_PREDICT_TRUE(&from != this)) {
+    UnsafeMergeFrom(from);
+  } else {
+    MergeFromFail(__LINE__);
+  }
+}
+
+void OpDef::UnsafeMergeFrom(const OpDef& from) {
+  GOOGLE_DCHECK(&from != this);
+  input_arg_.MergeFrom(from.input_arg_);
+  output_arg_.MergeFrom(from.output_arg_);
+  attr_.MergeFrom(from.attr_);
+  if (from.name().size() > 0) {
+    set_name(from.name());
+  }
+  if (from.has_deprecation()) {
+    mutable_deprecation()->::tensorflow::OpDeprecation::MergeFrom(from.deprecation());
+  }
+  if (from.summary().size() > 0) {
+    set_summary(from.summary());
+  }
+  if (from.description().size() > 0) {
+    set_description(from.description());
+  }
+  if (from.is_commutative() != 0) {
+    set_is_commutative(from.is_commutative());
+  }
+  if (from.is_aggregate() != 0) {
+    set_is_aggregate(from.is_aggregate());
+  }
+  if (from.is_stateful() != 0) {
+    set_is_stateful(from.is_stateful());
+  }
+  if (from.allows_uninitialized_input() != 0) {
+    set_allows_uninitialized_input(from.allows_uninitialized_input());
+  }
+}
+
+void OpDef::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:tensorflow.OpDef)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void OpDef::CopyFrom(const OpDef& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:tensorflow.OpDef)
+  if (&from == this) return;
+  Clear();
+  UnsafeMergeFrom(from);
+}
+
+bool OpDef::IsInitialized() const {
+
+  return true;
+}
+
+void OpDef::Swap(OpDef* other) {
+  if (other == this) return;
+  if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) {
+    InternalSwap(other);
+  } else {
+    OpDef temp;
+    temp.UnsafeMergeFrom(*this);
+    CopyFrom(*other);
+    other->CopyFrom(temp);
+  }
+}
+void OpDef::UnsafeArenaSwap(OpDef* other) {
+  if (other == this) return;
+  GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual());
+  InternalSwap(other);
+}
+void OpDef::InternalSwap(OpDef* other) {
+  name_.Swap(&other->name_);
+  input_arg_.UnsafeArenaSwap(&other->input_arg_);
+  output_arg_.UnsafeArenaSwap(&other->output_arg_);
+  attr_.UnsafeArenaSwap(&other->attr_);
+  std::swap(deprecation_, other->deprecation_);
+  summary_.Swap(&other->summary_);
+  description_.Swap(&other->description_);
+  std::swap(is_commutative_, other->is_commutative_);
+  std::swap(is_aggregate_, other->is_aggregate_);
+  std::swap(is_stateful_, other->is_stateful_);
+  std::swap(allows_uninitialized_input_, other->allows_uninitialized_input_);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
+}
+
+::google::protobuf::Metadata OpDef::GetMetadata() const {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::Metadata metadata;
+  metadata.descriptor = OpDef_descriptor_;
+  metadata.reflection = OpDef_reflection_;
+  return metadata;
+}
+
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// OpDef_ArgDef
+
+// optional string name = 1;
+void OpDef_ArgDef::clear_name() {
+  name_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+const ::std::string& OpDef_ArgDef::name() const {
+  // @@protoc_insertion_point(field_get:tensorflow.OpDef.ArgDef.name)
+  return name_.Get(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+void OpDef_ArgDef::set_name(const ::std::string& value) {
+
+  name_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value, GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set:tensorflow.OpDef.ArgDef.name)
+}
+void OpDef_ArgDef::set_name(const char* value) {
+
+  name_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value),
+              GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_char:tensorflow.OpDef.ArgDef.name)
+}
+void OpDef_ArgDef::set_name(const char* value,
+    size_t size) {
+
+  name_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(
+      reinterpret_cast<const char*>(value), size), GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_pointer:tensorflow.OpDef.ArgDef.name)
+}
+::std::string* OpDef_ArgDef::mutable_name() {
+
+  // @@protoc_insertion_point(field_mutable:tensorflow.OpDef.ArgDef.name)
+  return name_.Mutable(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+::std::string* OpDef_ArgDef::release_name() {
+  // @@protoc_insertion_point(field_release:tensorflow.OpDef.ArgDef.name)
+
+  return name_.Release(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+::std::string* OpDef_ArgDef::unsafe_arena_release_name() {
+  // @@protoc_insertion_point(field_unsafe_arena_release:tensorflow.OpDef.ArgDef.name)
+  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);
+
+  return name_.UnsafeArenaRelease(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      GetArenaNoVirtual());
+}
+void OpDef_ArgDef::set_allocated_name(::std::string* name) {
+  if (name != NULL) {
+
+  } else {
+
+  }
+  name_.SetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), name,
+      GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_allocated:tensorflow.OpDef.ArgDef.name)
+}
+void OpDef_ArgDef::unsafe_arena_set_allocated_name(
+    ::std::string* name) {
+  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);
+  if (name != NULL) {
+
+  } else {
+
+  }
+  name_.UnsafeArenaSetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      name, GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_unsafe_arena_set_allocated:tensorflow.OpDef.ArgDef.name)
+}
+
+// optional string description = 2;
+void OpDef_ArgDef::clear_description() {
+  description_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+const ::std::string& OpDef_ArgDef::description() const {
+  // @@protoc_insertion_point(field_get:tensorflow.OpDef.ArgDef.description)
+  return description_.Get(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+void OpDef_ArgDef::set_description(const ::std::string& value) {
+
+  description_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value, GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set:tensorflow.OpDef.ArgDef.description)
+}
+void OpDef_ArgDef::set_description(const char* value) {
+
+  description_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value),
+              GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_char:tensorflow.OpDef.ArgDef.description)
+}
+void OpDef_ArgDef::set_description(const char* value,
+    size_t size) {
+
+  description_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(
+      reinterpret_cast<const char*>(value), size), GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_pointer:tensorflow.OpDef.ArgDef.description)
+}
+::std::string* OpDef_ArgDef::mutable_description() {
+
+  // @@protoc_insertion_point(field_mutable:tensorflow.OpDef.ArgDef.description)
+  return description_.Mutable(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+::std::string* OpDef_ArgDef::release_description() {
+  // @@protoc_insertion_point(field_release:tensorflow.OpDef.ArgDef.description)
+
+  return description_.Release(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+::std::string* OpDef_ArgDef::unsafe_arena_release_description() {
+  // @@protoc_insertion_point(field_unsafe_arena_release:tensorflow.OpDef.ArgDef.description)
+  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);
+
+  return description_.UnsafeArenaRelease(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      GetArenaNoVirtual());
+}
+void OpDef_ArgDef::set_allocated_description(::std::string* description) {
+  if (description != NULL) {
+
+  } else {
+
+  }
+  description_.SetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), description,
+      GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_allocated:tensorflow.OpDef.ArgDef.description)
+}
+void OpDef_ArgDef::unsafe_arena_set_allocated_description(
+    ::std::string* description) {
+  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);
+  if (description != NULL) {
+
+  } else {
+
+  }
+  description_.UnsafeArenaSetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      description, GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_unsafe_arena_set_allocated:tensorflow.OpDef.ArgDef.description)
+}
+
+// optional .tensorflow.DataType type = 3;
+void OpDef_ArgDef::clear_type() {
+  type_ = 0;
+}
+::tensorflow::DataType OpDef_ArgDef::type() const {
+  // @@protoc_insertion_point(field_get:tensorflow.OpDef.ArgDef.type)
+  return static_cast< ::tensorflow::DataType >(type_);
+}
+void OpDef_ArgDef::set_type(::tensorflow::DataType value) {
+
+  type_ = value;
+  // @@protoc_insertion_point(field_set:tensorflow.OpDef.ArgDef.type)
+}
+
+// optional string type_attr = 4;
+void OpDef_ArgDef::clear_type_attr() {
+  type_attr_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+const ::std::string& OpDef_ArgDef::type_attr() const {
+  // @@protoc_insertion_point(field_get:tensorflow.OpDef.ArgDef.type_attr)
+  return type_attr_.Get(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+void OpDef_ArgDef::set_type_attr(const ::std::string& value) {
+
+  type_attr_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value, GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set:tensorflow.OpDef.ArgDef.type_attr)
+}
+void OpDef_ArgDef::set_type_attr(const char* value) {
+
+  type_attr_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value),
+              GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_char:tensorflow.OpDef.ArgDef.type_attr)
+}
+void OpDef_ArgDef::set_type_attr(const char* value,
+    size_t size) {
+
+  type_attr_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(
+      reinterpret_cast<const char*>(value), size), GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_pointer:tensorflow.OpDef.ArgDef.type_attr)
+}
+::std::string* OpDef_ArgDef::mutable_type_attr() {
+
+  // @@protoc_insertion_point(field_mutable:tensorflow.OpDef.ArgDef.type_attr)
+  return type_attr_.Mutable(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+::std::string* OpDef_ArgDef::release_type_attr() {
+  // @@protoc_insertion_point(field_release:tensorflow.OpDef.ArgDef.type_attr)
+
+  return type_attr_.Release(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+::std::string* OpDef_ArgDef::unsafe_arena_release_type_attr() {
+  // @@protoc_insertion_point(field_unsafe_arena_release:tensorflow.OpDef.ArgDef.type_attr)
+  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);
+
+  return type_attr_.UnsafeArenaRelease(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      GetArenaNoVirtual());
+}
+void OpDef_ArgDef::set_allocated_type_attr(::std::string* type_attr) {
+  if (type_attr != NULL) {
+
+  } else {
+
+  }
+  type_attr_.SetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), type_attr,
+      GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_allocated:tensorflow.OpDef.ArgDef.type_attr)
+}
+void OpDef_ArgDef::unsafe_arena_set_allocated_type_attr(
+    ::std::string* type_attr) {
+  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);
+  if (type_attr != NULL) {
+
+  } else {
+
+  }
+  type_attr_.UnsafeArenaSetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      type_attr, GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_unsafe_arena_set_allocated:tensorflow.OpDef.ArgDef.type_attr)
+}
+
+// optional string number_attr = 5;
+void OpDef_ArgDef::clear_number_attr() {
+  number_attr_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+const ::std::string& OpDef_ArgDef::number_attr() const {
+  // @@protoc_insertion_point(field_get:tensorflow.OpDef.ArgDef.number_attr)
+  return number_attr_.Get(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+void OpDef_ArgDef::set_number_attr(const ::std::string& value) {
+
+  number_attr_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value, GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set:tensorflow.OpDef.ArgDef.number_attr)
+}
+void OpDef_ArgDef::set_number_attr(const char* value) {
+
+  number_attr_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value),
+              GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_char:tensorflow.OpDef.ArgDef.number_attr)
+}
+void OpDef_ArgDef::set_number_attr(const char* value,
+    size_t size) {
+
+  number_attr_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(
+      reinterpret_cast<const char*>(value), size), GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_pointer:tensorflow.OpDef.ArgDef.number_attr)
+}
+::std::string* OpDef_ArgDef::mutable_number_attr() {
+
+  // @@protoc_insertion_point(field_mutable:tensorflow.OpDef.ArgDef.number_attr)
+  return number_attr_.Mutable(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+::std::string* OpDef_ArgDef::release_number_attr() {
+  // @@protoc_insertion_point(field_release:tensorflow.OpDef.ArgDef.number_attr)
+
+  return number_attr_.Release(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+::std::string* OpDef_ArgDef::unsafe_arena_release_number_attr() {
+  // @@protoc_insertion_point(field_unsafe_arena_release:tensorflow.OpDef.ArgDef.number_attr)
+  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);
+
+  return number_attr_.UnsafeArenaRelease(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      GetArenaNoVirtual());
+}
+void OpDef_ArgDef::set_allocated_number_attr(::std::string* number_attr) {
+  if (number_attr != NULL) {
+
+  } else {
+
+  }
+  number_attr_.SetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), number_attr,
+      GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_allocated:tensorflow.OpDef.ArgDef.number_attr)
+}
+void OpDef_ArgDef::unsafe_arena_set_allocated_number_attr(
+    ::std::string* number_attr) {
+  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);
+  if (number_attr != NULL) {
+
+  } else {
+
+  }
+  number_attr_.UnsafeArenaSetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      number_attr, GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_unsafe_arena_set_allocated:tensorflow.OpDef.ArgDef.number_attr)
+}
+
+// optional string type_list_attr = 6;
+void OpDef_ArgDef::clear_type_list_attr() {
+  type_list_attr_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+const ::std::string& OpDef_ArgDef::type_list_attr() const {
+  // @@protoc_insertion_point(field_get:tensorflow.OpDef.ArgDef.type_list_attr)
+  return type_list_attr_.Get(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+void OpDef_ArgDef::set_type_list_attr(const ::std::string& value) {
+
+  type_list_attr_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value, GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set:tensorflow.OpDef.ArgDef.type_list_attr)
+}
+void OpDef_ArgDef::set_type_list_attr(const char* value) {
+
+  type_list_attr_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value),
+              GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_char:tensorflow.OpDef.ArgDef.type_list_attr)
+}
+void OpDef_ArgDef::set_type_list_attr(const char* value,
+    size_t size) {
+
+  type_list_attr_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(
+      reinterpret_cast<const char*>(value), size), GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_pointer:tensorflow.OpDef.ArgDef.type_list_attr)
+}
+::std::string* OpDef_ArgDef::mutable_type_list_attr() {
+
+  // @@protoc_insertion_point(field_mutable:tensorflow.OpDef.ArgDef.type_list_attr)
+  return type_list_attr_.Mutable(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+::std::string* OpDef_ArgDef::release_type_list_attr() {
+  // @@protoc_insertion_point(field_release:tensorflow.OpDef.ArgDef.type_list_attr)
+
+  return type_list_attr_.Release(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+::std::string* OpDef_ArgDef::unsafe_arena_release_type_list_attr() {
+  // @@protoc_insertion_point(field_unsafe_arena_release:tensorflow.OpDef.ArgDef.type_list_attr)
+  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);
+
+  return type_list_attr_.UnsafeArenaRelease(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      GetArenaNoVirtual());
+}
+void OpDef_ArgDef::set_allocated_type_list_attr(::std::string* type_list_attr) {
+  if (type_list_attr != NULL) {
+
+  } else {
+
+  }
+  type_list_attr_.SetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), type_list_attr,
+      GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_allocated:tensorflow.OpDef.ArgDef.type_list_attr)
+}
+void OpDef_ArgDef::unsafe_arena_set_allocated_type_list_attr(
+    ::std::string* type_list_attr) {
+  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);
+  if (type_list_attr != NULL) {
+
+  } else {
+
+  }
+  type_list_attr_.UnsafeArenaSetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      type_list_attr, GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_unsafe_arena_set_allocated:tensorflow.OpDef.ArgDef.type_list_attr)
+}
+
+// optional bool is_ref = 16;
+void OpDef_ArgDef::clear_is_ref() {
+  is_ref_ = false;
+}
+bool OpDef_ArgDef::is_ref() const {
+  // @@protoc_insertion_point(field_get:tensorflow.OpDef.ArgDef.is_ref)
+  return is_ref_;
+}
+void OpDef_ArgDef::set_is_ref(bool value) {
+
+  is_ref_ = value;
+  // @@protoc_insertion_point(field_set:tensorflow.OpDef.ArgDef.is_ref)
+}
+
+inline const OpDef_ArgDef* OpDef_ArgDef::internal_default_instance() {
+  return &OpDef_ArgDef_default_instance_.get();
+}
+// -------------------------------------------------------------------
+
+// OpDef_AttrDef
+
+// optional string name = 1;
+void OpDef_AttrDef::clear_name() {
+  name_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+const ::std::string& OpDef_AttrDef::name() const {
+  // @@protoc_insertion_point(field_get:tensorflow.OpDef.AttrDef.name)
+  return name_.Get(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+void OpDef_AttrDef::set_name(const ::std::string& value) {
+
+  name_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value, GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set:tensorflow.OpDef.AttrDef.name)
+}
+void OpDef_AttrDef::set_name(const char* value) {
+
+  name_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value),
+              GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_char:tensorflow.OpDef.AttrDef.name)
+}
+void OpDef_AttrDef::set_name(const char* value,
+    size_t size) {
+
+  name_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(
+      reinterpret_cast<const char*>(value), size), GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_pointer:tensorflow.OpDef.AttrDef.name)
+}
+::std::string* OpDef_AttrDef::mutable_name() {
+
+  // @@protoc_insertion_point(field_mutable:tensorflow.OpDef.AttrDef.name)
+  return name_.Mutable(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+::std::string* OpDef_AttrDef::release_name() {
+  // @@protoc_insertion_point(field_release:tensorflow.OpDef.AttrDef.name)
+
+  return name_.Release(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+::std::string* OpDef_AttrDef::unsafe_arena_release_name() {
+  // @@protoc_insertion_point(field_unsafe_arena_release:tensorflow.OpDef.AttrDef.name)
+  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);
+
+  return name_.UnsafeArenaRelease(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      GetArenaNoVirtual());
+}
+void OpDef_AttrDef::set_allocated_name(::std::string* name) {
+  if (name != NULL) {
+
+  } else {
+
+  }
+  name_.SetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), name,
+      GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_allocated:tensorflow.OpDef.AttrDef.name)
+}
+void OpDef_AttrDef::unsafe_arena_set_allocated_name(
+    ::std::string* name) {
+  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);
+  if (name != NULL) {
+
+  } else {
+
+  }
+  name_.UnsafeArenaSetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      name, GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_unsafe_arena_set_allocated:tensorflow.OpDef.AttrDef.name)
+}
+
+// optional string type = 2;
+void OpDef_AttrDef::clear_type() {
+  type_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+const ::std::string& OpDef_AttrDef::type() const {
+  // @@protoc_insertion_point(field_get:tensorflow.OpDef.AttrDef.type)
+  return type_.Get(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+void OpDef_AttrDef::set_type(const ::std::string& value) {
+
+  type_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value, GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set:tensorflow.OpDef.AttrDef.type)
+}
+void OpDef_AttrDef::set_type(const char* value) {
+
+  type_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value),
+              GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_char:tensorflow.OpDef.AttrDef.type)
+}
+void OpDef_AttrDef::set_type(const char* value,
+    size_t size) {
+
+  type_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(
+      reinterpret_cast<const char*>(value), size), GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_pointer:tensorflow.OpDef.AttrDef.type)
+}
+::std::string* OpDef_AttrDef::mutable_type() {
+
+  // @@protoc_insertion_point(field_mutable:tensorflow.OpDef.AttrDef.type)
+  return type_.Mutable(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+::std::string* OpDef_AttrDef::release_type() {
+  // @@protoc_insertion_point(field_release:tensorflow.OpDef.AttrDef.type)
+
+  return type_.Release(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+::std::string* OpDef_AttrDef::unsafe_arena_release_type() {
+  // @@protoc_insertion_point(field_unsafe_arena_release:tensorflow.OpDef.AttrDef.type)
+  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);
+
+  return type_.UnsafeArenaRelease(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      GetArenaNoVirtual());
+}
+void OpDef_AttrDef::set_allocated_type(::std::string* type) {
+  if (type != NULL) {
+
+  } else {
+
+  }
+  type_.SetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), type,
+      GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_allocated:tensorflow.OpDef.AttrDef.type)
+}
+void OpDef_AttrDef::unsafe_arena_set_allocated_type(
+    ::std::string* type) {
+  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);
+  if (type != NULL) {
+
+  } else {
+
+  }
+  type_.UnsafeArenaSetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      type, GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_unsafe_arena_set_allocated:tensorflow.OpDef.AttrDef.type)
+}
+
+// optional .tensorflow.AttrValue default_value = 3;
+bool OpDef_AttrDef::has_default_value() const {
+  return this != internal_default_instance() && default_value_ != NULL;
+}
+void OpDef_AttrDef::clear_default_value() {
+  if (GetArenaNoVirtual() == NULL && default_value_ != NULL) delete default_value_;
+  default_value_ = NULL;
+}
+const ::tensorflow::AttrValue& OpDef_AttrDef::default_value() const {
+  // @@protoc_insertion_point(field_get:tensorflow.OpDef.AttrDef.default_value)
+  return default_value_ != NULL ? *default_value_
+                         : *::tensorflow::AttrValue::internal_default_instance();
+}
+::tensorflow::AttrValue* OpDef_AttrDef::mutable_default_value() {
+
+  if (default_value_ == NULL) {
+    _slow_mutable_default_value();
+  }
+  // @@protoc_insertion_point(field_mutable:tensorflow.OpDef.AttrDef.default_value)
+  return default_value_;
+}
+::tensorflow::AttrValue* OpDef_AttrDef::release_default_value() {
+  // @@protoc_insertion_point(field_release:tensorflow.OpDef.AttrDef.default_value)
+
+  if (GetArenaNoVirtual() != NULL) {
+    return _slow_release_default_value();
+  } else {
+    ::tensorflow::AttrValue* temp = default_value_;
+    default_value_ = NULL;
+    return temp;
+  }
+}
+ void OpDef_AttrDef::set_allocated_default_value(::tensorflow::AttrValue* default_value) {
+  ::google::protobuf::Arena* message_arena = GetArenaNoVirtual();
+  if (message_arena == NULL) {
+    delete default_value_;
+  }
+  if (default_value != NULL) {
+    _slow_set_allocated_default_value(message_arena, &default_value);
+  }
+  default_value_ = default_value;
+  if (default_value) {
+
+  } else {
+
+  }
+  // @@protoc_insertion_point(field_set_allocated:tensorflow.OpDef.AttrDef.default_value)
+}
+
+// optional string description = 4;
+void OpDef_AttrDef::clear_description() {
+  description_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+const ::std::string& OpDef_AttrDef::description() const {
+  // @@protoc_insertion_point(field_get:tensorflow.OpDef.AttrDef.description)
+  return description_.Get(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+void OpDef_AttrDef::set_description(const ::std::string& value) {
+
+  description_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value, GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set:tensorflow.OpDef.AttrDef.description)
+}
+void OpDef_AttrDef::set_description(const char* value) {
+
+  description_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value),
+              GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_char:tensorflow.OpDef.AttrDef.description)
+}
+void OpDef_AttrDef::set_description(const char* value,
+    size_t size) {
+
+  description_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(
+      reinterpret_cast<const char*>(value), size), GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_pointer:tensorflow.OpDef.AttrDef.description)
+}
+::std::string* OpDef_AttrDef::mutable_description() {
+
+  // @@protoc_insertion_point(field_mutable:tensorflow.OpDef.AttrDef.description)
+  return description_.Mutable(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+::std::string* OpDef_AttrDef::release_description() {
+  // @@protoc_insertion_point(field_release:tensorflow.OpDef.AttrDef.description)
+
+  return description_.Release(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+::std::string* OpDef_AttrDef::unsafe_arena_release_description() {
+  // @@protoc_insertion_point(field_unsafe_arena_release:tensorflow.OpDef.AttrDef.description)
+  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);
+
+  return description_.UnsafeArenaRelease(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      GetArenaNoVirtual());
+}
+void OpDef_AttrDef::set_allocated_description(::std::string* description) {
+  if (description != NULL) {
+
+  } else {
+
+  }
+  description_.SetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), description,
+      GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_allocated:tensorflow.OpDef.AttrDef.description)
+}
+void OpDef_AttrDef::unsafe_arena_set_allocated_description(
+    ::std::string* description) {
+  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);
+  if (description != NULL) {
+
+  } else {
+
+  }
+  description_.UnsafeArenaSetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      description, GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_unsafe_arena_set_allocated:tensorflow.OpDef.AttrDef.description)
+}
+
+// optional bool has_minimum = 5;
+void OpDef_AttrDef::clear_has_minimum() {
+  has_minimum_ = false;
+}
+bool OpDef_AttrDef::has_minimum() const {
+  // @@protoc_insertion_point(field_get:tensorflow.OpDef.AttrDef.has_minimum)
+  return has_minimum_;
+}
+void OpDef_AttrDef::set_has_minimum(bool value) {
+
+  has_minimum_ = value;
+  // @@protoc_insertion_point(field_set:tensorflow.OpDef.AttrDef.has_minimum)
+}
+
+// optional int64 minimum = 6;
+void OpDef_AttrDef::clear_minimum() {
+  minimum_ = GOOGLE_LONGLONG(0);
+}
+::google::protobuf::int64 OpDef_AttrDef::minimum() const {
+  // @@protoc_insertion_point(field_get:tensorflow.OpDef.AttrDef.minimum)
+  return minimum_;
+}
+void OpDef_AttrDef::set_minimum(::google::protobuf::int64 value) {
+
+  minimum_ = value;
+  // @@protoc_insertion_point(field_set:tensorflow.OpDef.AttrDef.minimum)
+}
+
+// optional .tensorflow.AttrValue allowed_values = 7;
+bool OpDef_AttrDef::has_allowed_values() const {
+  return this != internal_default_instance() && allowed_values_ != NULL;
+}
+void OpDef_AttrDef::clear_allowed_values() {
+  if (GetArenaNoVirtual() == NULL && allowed_values_ != NULL) delete allowed_values_;
+  allowed_values_ = NULL;
+}
+const ::tensorflow::AttrValue& OpDef_AttrDef::allowed_values() const {
+  // @@protoc_insertion_point(field_get:tensorflow.OpDef.AttrDef.allowed_values)
+  return allowed_values_ != NULL ? *allowed_values_
+                         : *::tensorflow::AttrValue::internal_default_instance();
+}
+::tensorflow::AttrValue* OpDef_AttrDef::mutable_allowed_values() {
+
+  if (allowed_values_ == NULL) {
+    _slow_mutable_allowed_values();
+  }
+  // @@protoc_insertion_point(field_mutable:tensorflow.OpDef.AttrDef.allowed_values)
+  return allowed_values_;
+}
+::tensorflow::AttrValue* OpDef_AttrDef::release_allowed_values() {
+  // @@protoc_insertion_point(field_release:tensorflow.OpDef.AttrDef.allowed_values)
+
+  if (GetArenaNoVirtual() != NULL) {
+    return _slow_release_allowed_values();
+  } else {
+    ::tensorflow::AttrValue* temp = allowed_values_;
+    allowed_values_ = NULL;
+    return temp;
+  }
+}
+ void OpDef_AttrDef::set_allocated_allowed_values(::tensorflow::AttrValue* allowed_values) {
+  ::google::protobuf::Arena* message_arena = GetArenaNoVirtual();
+  if (message_arena == NULL) {
+    delete allowed_values_;
+  }
+  if (allowed_values != NULL) {
+    _slow_set_allocated_allowed_values(message_arena, &allowed_values);
+  }
+  allowed_values_ = allowed_values;
+  if (allowed_values) {
+
+  } else {
+
+  }
+  // @@protoc_insertion_point(field_set_allocated:tensorflow.OpDef.AttrDef.allowed_values)
+}
+
+inline const OpDef_AttrDef* OpDef_AttrDef::internal_default_instance() {
+  return &OpDef_AttrDef_default_instance_.get();
+}
+// -------------------------------------------------------------------
+
+// OpDef
+
+// optional string name = 1;
+void OpDef::clear_name() {
+  name_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+const ::std::string& OpDef::name() const {
+  // @@protoc_insertion_point(field_get:tensorflow.OpDef.name)
+  return name_.Get(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+void OpDef::set_name(const ::std::string& value) {
+
+  name_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value, GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set:tensorflow.OpDef.name)
+}
+void OpDef::set_name(const char* value) {
+
+  name_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value),
+              GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_char:tensorflow.OpDef.name)
+}
+void OpDef::set_name(const char* value,
+    size_t size) {
+
+  name_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(
+      reinterpret_cast<const char*>(value), size), GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_pointer:tensorflow.OpDef.name)
+}
+::std::string* OpDef::mutable_name() {
+
+  // @@protoc_insertion_point(field_mutable:tensorflow.OpDef.name)
+  return name_.Mutable(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+::std::string* OpDef::release_name() {
+  // @@protoc_insertion_point(field_release:tensorflow.OpDef.name)
+
+  return name_.Release(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+::std::string* OpDef::unsafe_arena_release_name() {
+  // @@protoc_insertion_point(field_unsafe_arena_release:tensorflow.OpDef.name)
+  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);
+
+  return name_.UnsafeArenaRelease(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      GetArenaNoVirtual());
+}
+void OpDef::set_allocated_name(::std::string* name) {
+  if (name != NULL) {
+
+  } else {
+
+  }
+  name_.SetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), name,
+      GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_allocated:tensorflow.OpDef.name)
+}
+void OpDef::unsafe_arena_set_allocated_name(
+    ::std::string* name) {
+  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);
+  if (name != NULL) {
+
+  } else {
+
+  }
+  name_.UnsafeArenaSetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      name, GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_unsafe_arena_set_allocated:tensorflow.OpDef.name)
+}
+
+// repeated .tensorflow.OpDef.ArgDef input_arg = 2;
+int OpDef::input_arg_size() const {
+  return input_arg_.size();
+}
+void OpDef::clear_input_arg() {
+  input_arg_.Clear();
+}
+const ::tensorflow::OpDef_ArgDef& OpDef::input_arg(int index) const {
+  // @@protoc_insertion_point(field_get:tensorflow.OpDef.input_arg)
+  return input_arg_.Get(index);
+}
+::tensorflow::OpDef_ArgDef* OpDef::mutable_input_arg(int index) {
+  // @@protoc_insertion_point(field_mutable:tensorflow.OpDef.input_arg)
+  return input_arg_.Mutable(index);
+}
+::tensorflow::OpDef_ArgDef* OpDef::add_input_arg() {
+  // @@protoc_insertion_point(field_add:tensorflow.OpDef.input_arg)
+  return input_arg_.Add();
+}
+::google::protobuf::RepeatedPtrField< ::tensorflow::OpDef_ArgDef >*
+OpDef::mutable_input_arg() {
+  // @@protoc_insertion_point(field_mutable_list:tensorflow.OpDef.input_arg)
+  return &input_arg_;
+}
+const ::google::protobuf::RepeatedPtrField< ::tensorflow::OpDef_ArgDef >&
+OpDef::input_arg() const {
+  // @@protoc_insertion_point(field_list:tensorflow.OpDef.input_arg)
+  return input_arg_;
+}
+
+// repeated .tensorflow.OpDef.ArgDef output_arg = 3;
+int OpDef::output_arg_size() const {
+  return output_arg_.size();
+}
+void OpDef::clear_output_arg() {
+  output_arg_.Clear();
+}
+const ::tensorflow::OpDef_ArgDef& OpDef::output_arg(int index) const {
+  // @@protoc_insertion_point(field_get:tensorflow.OpDef.output_arg)
+  return output_arg_.Get(index);
+}
+::tensorflow::OpDef_ArgDef* OpDef::mutable_output_arg(int index) {
+  // @@protoc_insertion_point(field_mutable:tensorflow.OpDef.output_arg)
+  return output_arg_.Mutable(index);
+}
+::tensorflow::OpDef_ArgDef* OpDef::add_output_arg() {
+  // @@protoc_insertion_point(field_add:tensorflow.OpDef.output_arg)
+  return output_arg_.Add();
+}
+::google::protobuf::RepeatedPtrField< ::tensorflow::OpDef_ArgDef >*
+OpDef::mutable_output_arg() {
+  // @@protoc_insertion_point(field_mutable_list:tensorflow.OpDef.output_arg)
+  return &output_arg_;
+}
+const ::google::protobuf::RepeatedPtrField< ::tensorflow::OpDef_ArgDef >&
+OpDef::output_arg() const {
+  // @@protoc_insertion_point(field_list:tensorflow.OpDef.output_arg)
+  return output_arg_;
+}
+
+// repeated .tensorflow.OpDef.AttrDef attr = 4;
+int OpDef::attr_size() const {
+  return attr_.size();
+}
+void OpDef::clear_attr() {
+  attr_.Clear();
+}
+const ::tensorflow::OpDef_AttrDef& OpDef::attr(int index) const {
+  // @@protoc_insertion_point(field_get:tensorflow.OpDef.attr)
+  return attr_.Get(index);
+}
+::tensorflow::OpDef_AttrDef* OpDef::mutable_attr(int index) {
+  // @@protoc_insertion_point(field_mutable:tensorflow.OpDef.attr)
+  return attr_.Mutable(index);
+}
+::tensorflow::OpDef_AttrDef* OpDef::add_attr() {
+  // @@protoc_insertion_point(field_add:tensorflow.OpDef.attr)
+  return attr_.Add();
+}
+::google::protobuf::RepeatedPtrField< ::tensorflow::OpDef_AttrDef >*
+OpDef::mutable_attr() {
+  // @@protoc_insertion_point(field_mutable_list:tensorflow.OpDef.attr)
+  return &attr_;
+}
+const ::google::protobuf::RepeatedPtrField< ::tensorflow::OpDef_AttrDef >&
+OpDef::attr() const {
+  // @@protoc_insertion_point(field_list:tensorflow.OpDef.attr)
+  return attr_;
+}
+
+// optional .tensorflow.OpDeprecation deprecation = 8;
+bool OpDef::has_deprecation() const {
+  return this != internal_default_instance() && deprecation_ != NULL;
+}
+void OpDef::clear_deprecation() {
+  if (GetArenaNoVirtual() == NULL && deprecation_ != NULL) delete deprecation_;
+  deprecation_ = NULL;
+}
+const ::tensorflow::OpDeprecation& OpDef::deprecation() const {
+  // @@protoc_insertion_point(field_get:tensorflow.OpDef.deprecation)
+  return deprecation_ != NULL ? *deprecation_
+                         : *::tensorflow::OpDeprecation::internal_default_instance();
+}
+::tensorflow::OpDeprecation* OpDef::mutable_deprecation() {
+
+  if (deprecation_ == NULL) {
+    _slow_mutable_deprecation();
+  }
+  // @@protoc_insertion_point(field_mutable:tensorflow.OpDef.deprecation)
+  return deprecation_;
+}
+::tensorflow::OpDeprecation* OpDef::release_deprecation() {
+  // @@protoc_insertion_point(field_release:tensorflow.OpDef.deprecation)
+
+  if (GetArenaNoVirtual() != NULL) {
+    return _slow_release_deprecation();
+  } else {
+    ::tensorflow::OpDeprecation* temp = deprecation_;
+    deprecation_ = NULL;
+    return temp;
+  }
+}
+ void OpDef::set_allocated_deprecation(::tensorflow::OpDeprecation* deprecation) {
+  ::google::protobuf::Arena* message_arena = GetArenaNoVirtual();
+  if (message_arena == NULL) {
+    delete deprecation_;
+  }
+  if (deprecation != NULL) {
+    _slow_set_allocated_deprecation(message_arena, &deprecation);
+  }
+  deprecation_ = deprecation;
+  if (deprecation) {
+
+  } else {
+
+  }
+  // @@protoc_insertion_point(field_set_allocated:tensorflow.OpDef.deprecation)
+}
+
+// optional string summary = 5;
+void OpDef::clear_summary() {
+  summary_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+const ::std::string& OpDef::summary() const {
+  // @@protoc_insertion_point(field_get:tensorflow.OpDef.summary)
+  return summary_.Get(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+void OpDef::set_summary(const ::std::string& value) {
+
+  summary_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value, GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set:tensorflow.OpDef.summary)
+}
+void OpDef::set_summary(const char* value) {
+
+  summary_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value),
+              GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_char:tensorflow.OpDef.summary)
+}
+void OpDef::set_summary(const char* value,
+    size_t size) {
+
+  summary_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(
+      reinterpret_cast<const char*>(value), size), GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_pointer:tensorflow.OpDef.summary)
+}
+::std::string* OpDef::mutable_summary() {
+
+  // @@protoc_insertion_point(field_mutable:tensorflow.OpDef.summary)
+  return summary_.Mutable(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+::std::string* OpDef::release_summary() {
+  // @@protoc_insertion_point(field_release:tensorflow.OpDef.summary)
+
+  return summary_.Release(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+::std::string* OpDef::unsafe_arena_release_summary() {
+  // @@protoc_insertion_point(field_unsafe_arena_release:tensorflow.OpDef.summary)
+  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);
+
+  return summary_.UnsafeArenaRelease(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      GetArenaNoVirtual());
+}
+void OpDef::set_allocated_summary(::std::string* summary) {
+  if (summary != NULL) {
+
+  } else {
+
+  }
+  summary_.SetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), summary,
+      GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_allocated:tensorflow.OpDef.summary)
+}
+void OpDef::unsafe_arena_set_allocated_summary(
+    ::std::string* summary) {
+  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);
+  if (summary != NULL) {
+
+  } else {
+
+  }
+  summary_.UnsafeArenaSetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      summary, GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_unsafe_arena_set_allocated:tensorflow.OpDef.summary)
+}
+
+// optional string description = 6;
+void OpDef::clear_description() {
+  description_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+const ::std::string& OpDef::description() const {
+  // @@protoc_insertion_point(field_get:tensorflow.OpDef.description)
+  return description_.Get(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+void OpDef::set_description(const ::std::string& value) {
+
+  description_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value, GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set:tensorflow.OpDef.description)
+}
+void OpDef::set_description(const char* value) {
+
+  description_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value),
+              GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_char:tensorflow.OpDef.description)
+}
+void OpDef::set_description(const char* value,
+    size_t size) {
+
+  description_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(
+      reinterpret_cast<const char*>(value), size), GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_pointer:tensorflow.OpDef.description)
+}
+::std::string* OpDef::mutable_description() {
+
+  // @@protoc_insertion_point(field_mutable:tensorflow.OpDef.description)
+  return description_.Mutable(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+::std::string* OpDef::release_description() {
+  // @@protoc_insertion_point(field_release:tensorflow.OpDef.description)
+
+  return description_.Release(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+::std::string* OpDef::unsafe_arena_release_description() {
+  // @@protoc_insertion_point(field_unsafe_arena_release:tensorflow.OpDef.description)
+  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);
+
+  return description_.UnsafeArenaRelease(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      GetArenaNoVirtual());
+}
+void OpDef::set_allocated_description(::std::string* description) {
+  if (description != NULL) {
+
+  } else {
+
+  }
+  description_.SetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), description,
+      GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_allocated:tensorflow.OpDef.description)
+}
+void OpDef::unsafe_arena_set_allocated_description(
+    ::std::string* description) {
+  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);
+  if (description != NULL) {
+
+  } else {
+
+  }
+  description_.UnsafeArenaSetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      description, GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_unsafe_arena_set_allocated:tensorflow.OpDef.description)
+}
+
+// optional bool is_commutative = 18;
+void OpDef::clear_is_commutative() {
+  is_commutative_ = false;
+}
+bool OpDef::is_commutative() const {
+  // @@protoc_insertion_point(field_get:tensorflow.OpDef.is_commutative)
+  return is_commutative_;
+}
+void OpDef::set_is_commutative(bool value) {
+
+  is_commutative_ = value;
+  // @@protoc_insertion_point(field_set:tensorflow.OpDef.is_commutative)
+}
+
+// optional bool is_aggregate = 16;
+void OpDef::clear_is_aggregate() {
+  is_aggregate_ = false;
+}
+bool OpDef::is_aggregate() const {
+  // @@protoc_insertion_point(field_get:tensorflow.OpDef.is_aggregate)
+  return is_aggregate_;
+}
+void OpDef::set_is_aggregate(bool value) {
+
+  is_aggregate_ = value;
+  // @@protoc_insertion_point(field_set:tensorflow.OpDef.is_aggregate)
+}
+
+// optional bool is_stateful = 17;
+void OpDef::clear_is_stateful() {
+  is_stateful_ = false;
+}
+bool OpDef::is_stateful() const {
+  // @@protoc_insertion_point(field_get:tensorflow.OpDef.is_stateful)
+  return is_stateful_;
+}
+void OpDef::set_is_stateful(bool value) {
+
+  is_stateful_ = value;
+  // @@protoc_insertion_point(field_set:tensorflow.OpDef.is_stateful)
+}
+
+// optional bool allows_uninitialized_input = 19;
+void OpDef::clear_allows_uninitialized_input() {
+  allows_uninitialized_input_ = false;
+}
+bool OpDef::allows_uninitialized_input() const {
+  // @@protoc_insertion_point(field_get:tensorflow.OpDef.allows_uninitialized_input)
+  return allows_uninitialized_input_;
+}
+void OpDef::set_allows_uninitialized_input(bool value) {
+
+  allows_uninitialized_input_ = value;
+  // @@protoc_insertion_point(field_set:tensorflow.OpDef.allows_uninitialized_input)
+}
+
+inline const OpDef* OpDef::internal_default_instance() {
+  return &OpDef_default_instance_.get();
+}
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
+
+// ===================================================================
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const int OpDeprecation::kVersionFieldNumber;
+const int OpDeprecation::kExplanationFieldNumber;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+
+OpDeprecation::OpDeprecation()
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+  if (this != internal_default_instance()) protobuf_InitDefaults_op_5fdef_2eproto();
+  SharedCtor();
+  // @@protoc_insertion_point(constructor:tensorflow.OpDeprecation)
+}
+OpDeprecation::OpDeprecation(::google::protobuf::Arena* arena)
+  : ::google::protobuf::Message(),
+  _internal_metadata_(arena) {
+#ifdef GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER
+  protobuf_InitDefaults_op_5fdef_2eproto();
+#endif  // GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER
+  SharedCtor();
+  RegisterArenaDtor(arena);
+  // @@protoc_insertion_point(arena_constructor:tensorflow.OpDeprecation)
+}
+
+void OpDeprecation::InitAsDefaultInstance() {
+}
+
+OpDeprecation::OpDeprecation(const OpDeprecation& from)
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
+  SharedCtor();
+  UnsafeMergeFrom(from);
+  // @@protoc_insertion_point(copy_constructor:tensorflow.OpDeprecation)
+}
+
+void OpDeprecation::SharedCtor() {
+  explanation_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  version_ = 0;
+  _cached_size_ = 0;
+}
+
+OpDeprecation::~OpDeprecation() {
+  // @@protoc_insertion_point(destructor:tensorflow.OpDeprecation)
+  SharedDtor();
+}
+
+void OpDeprecation::SharedDtor() {
+  ::google::protobuf::Arena* arena = GetArenaNoVirtual();
+  if (arena != NULL) {
+    return;
+  }
+
+  explanation_.Destroy(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), arena);
+}
+
+void OpDeprecation::ArenaDtor(void* object) {
+  OpDeprecation* _this = reinterpret_cast< OpDeprecation* >(object);
+  (void)_this;
+}
+void OpDeprecation::RegisterArenaDtor(::google::protobuf::Arena* arena) {
+}
+void OpDeprecation::SetCachedSize(int size) const {
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* OpDeprecation::descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return OpDeprecation_descriptor_;
+}
+
+const OpDeprecation& OpDeprecation::default_instance() {
+  protobuf_InitDefaults_op_5fdef_2eproto();
+  return *internal_default_instance();
+}
+
+::google::protobuf::internal::ExplicitlyConstructed<OpDeprecation> OpDeprecation_default_instance_;
+
+OpDeprecation* OpDeprecation::New(::google::protobuf::Arena* arena) const {
+  return ::google::protobuf::Arena::CreateMessage<OpDeprecation>(arena);
+}
+
+void OpDeprecation::Clear() {
+// @@protoc_insertion_point(message_clear_start:tensorflow.OpDeprecation)
+  version_ = 0;
+  explanation_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+
+bool OpDeprecation::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
+  ::google::protobuf::uint32 tag;
+  // @@protoc_insertion_point(parse_start:tensorflow.OpDeprecation)
+  for (;;) {
+    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+    tag = p.first;
+    if (!p.second) goto handle_unusual;
+    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+      // optional int32 version = 1;
+      case 1: {
+        if (tag == 8) {
+
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
+                 input, &version_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(18)) goto parse_explanation;
+        break;
+      }
+
+      // optional string explanation = 2;
+      case 2: {
+        if (tag == 18) {
+         parse_explanation:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+                input, this->mutable_explanation()));
+          DO_(::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+            this->explanation().data(), this->explanation().length(),
+            ::google::protobuf::internal::WireFormatLite::PARSE,
+            "tensorflow.OpDeprecation.explanation"));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectAtEnd()) goto success;
+        break;
+      }
+
+      default: {
+      handle_unusual:
+        if (tag == 0 ||
+            ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+          goto success;
+        }
+        DO_(::google::protobuf::internal::WireFormatLite::SkipField(input, tag));
+        break;
+      }
+    }
+  }
+success:
+  // @@protoc_insertion_point(parse_success:tensorflow.OpDeprecation)
+  return true;
+failure:
+  // @@protoc_insertion_point(parse_failure:tensorflow.OpDeprecation)
+  return false;
+#undef DO_
+}
+
+void OpDeprecation::SerializeWithCachedSizes(
+    ::google::protobuf::io::CodedOutputStream* output) const {
+  // @@protoc_insertion_point(serialize_start:tensorflow.OpDeprecation)
+  // optional int32 version = 1;
+  if (this->version() != 0) {
+    ::google::protobuf::internal::WireFormatLite::WriteInt32(1, this->version(), output);
+  }
+
+  // optional string explanation = 2;
+  if (this->explanation().size() > 0) {
+    ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+      this->explanation().data(), this->explanation().length(),
+      ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+      "tensorflow.OpDeprecation.explanation");
+    ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
+      2, this->explanation(), output);
+  }
+
+  // @@protoc_insertion_point(serialize_end:tensorflow.OpDeprecation)
+}
+
+::google::protobuf::uint8* OpDeprecation::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
+  (void)deterministic; // Unused
+  // @@protoc_insertion_point(serialize_to_array_start:tensorflow.OpDeprecation)
+  // optional int32 version = 1;
+  if (this->version() != 0) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteInt32ToArray(1, this->version(), target);
+  }
+
+  // optional string explanation = 2;
+  if (this->explanation().size() > 0) {
+    ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+      this->explanation().data(), this->explanation().length(),
+      ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+      "tensorflow.OpDeprecation.explanation");
+    target =
+      ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
+        2, this->explanation(), target);
+  }
+
+  // @@protoc_insertion_point(serialize_to_array_end:tensorflow.OpDeprecation)
+  return target;
+}
+
+size_t OpDeprecation::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:tensorflow.OpDeprecation)
+  size_t total_size = 0;
+
+  // optional int32 version = 1;
+  if (this->version() != 0) {
+    total_size += 1 +
+      ::google::protobuf::internal::WireFormatLite::Int32Size(
+        this->version());
+  }
+
+  // optional string explanation = 2;
+  if (this->explanation().size() > 0) {
+    total_size += 1 +
+      ::google::protobuf::internal::WireFormatLite::StringSize(
+        this->explanation());
+  }
+
+  int cached_size = ::google::protobuf::internal::ToCachedSize(total_size);
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = cached_size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+  return total_size;
+}
+
+void OpDeprecation::MergeFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_merge_from_start:tensorflow.OpDeprecation)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const OpDeprecation* source =
+      ::google::protobuf::internal::DynamicCastToGenerated<const OpDeprecation>(
+          &from);
+  if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:tensorflow.OpDeprecation)
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:tensorflow.OpDeprecation)
+    UnsafeMergeFrom(*source);
+  }
+}
+
+void OpDeprecation::MergeFrom(const OpDeprecation& from) {
+// @@protoc_insertion_point(class_specific_merge_from_start:tensorflow.OpDeprecation)
+  if (GOOGLE_PREDICT_TRUE(&from != this)) {
+    UnsafeMergeFrom(from);
+  } else {
+    MergeFromFail(__LINE__);
+  }
+}
+
+void OpDeprecation::UnsafeMergeFrom(const OpDeprecation& from) {
+  GOOGLE_DCHECK(&from != this);
+  if (from.version() != 0) {
+    set_version(from.version());
+  }
+  if (from.explanation().size() > 0) {
+    set_explanation(from.explanation());
+  }
+}
+
+void OpDeprecation::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:tensorflow.OpDeprecation)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void OpDeprecation::CopyFrom(const OpDeprecation& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:tensorflow.OpDeprecation)
+  if (&from == this) return;
+  Clear();
+  UnsafeMergeFrom(from);
+}
+
+bool OpDeprecation::IsInitialized() const {
+
+  return true;
+}
+
+void OpDeprecation::Swap(OpDeprecation* other) {
+  if (other == this) return;
+  if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) {
+    InternalSwap(other);
+  } else {
+    OpDeprecation temp;
+    temp.UnsafeMergeFrom(*this);
+    CopyFrom(*other);
+    other->CopyFrom(temp);
+  }
+}
+void OpDeprecation::UnsafeArenaSwap(OpDeprecation* other) {
+  if (other == this) return;
+  GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual());
+  InternalSwap(other);
+}
+void OpDeprecation::InternalSwap(OpDeprecation* other) {
+  std::swap(version_, other->version_);
+  explanation_.Swap(&other->explanation_);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
+}
+
+::google::protobuf::Metadata OpDeprecation::GetMetadata() const {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::Metadata metadata;
+  metadata.descriptor = OpDeprecation_descriptor_;
+  metadata.reflection = OpDeprecation_reflection_;
+  return metadata;
+}
+
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// OpDeprecation
+
+// optional int32 version = 1;
+void OpDeprecation::clear_version() {
+  version_ = 0;
+}
+::google::protobuf::int32 OpDeprecation::version() const {
+  // @@protoc_insertion_point(field_get:tensorflow.OpDeprecation.version)
+  return version_;
+}
+void OpDeprecation::set_version(::google::protobuf::int32 value) {
+
+  version_ = value;
+  // @@protoc_insertion_point(field_set:tensorflow.OpDeprecation.version)
+}
+
+// optional string explanation = 2;
+void OpDeprecation::clear_explanation() {
+  explanation_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+const ::std::string& OpDeprecation::explanation() const {
+  // @@protoc_insertion_point(field_get:tensorflow.OpDeprecation.explanation)
+  return explanation_.Get(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+void OpDeprecation::set_explanation(const ::std::string& value) {
+
+  explanation_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value, GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set:tensorflow.OpDeprecation.explanation)
+}
+void OpDeprecation::set_explanation(const char* value) {
+
+  explanation_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value),
+              GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_char:tensorflow.OpDeprecation.explanation)
+}
+void OpDeprecation::set_explanation(const char* value,
+    size_t size) {
+
+  explanation_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(
+      reinterpret_cast<const char*>(value), size), GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_pointer:tensorflow.OpDeprecation.explanation)
+}
+::std::string* OpDeprecation::mutable_explanation() {
+
+  // @@protoc_insertion_point(field_mutable:tensorflow.OpDeprecation.explanation)
+  return explanation_.Mutable(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+::std::string* OpDeprecation::release_explanation() {
+  // @@protoc_insertion_point(field_release:tensorflow.OpDeprecation.explanation)
+
+  return explanation_.Release(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+::std::string* OpDeprecation::unsafe_arena_release_explanation() {
+  // @@protoc_insertion_point(field_unsafe_arena_release:tensorflow.OpDeprecation.explanation)
+  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);
+
+  return explanation_.UnsafeArenaRelease(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      GetArenaNoVirtual());
+}
+void OpDeprecation::set_allocated_explanation(::std::string* explanation) {
+  if (explanation != NULL) {
+
+  } else {
+
+  }
+  explanation_.SetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), explanation,
+      GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_allocated:tensorflow.OpDeprecation.explanation)
+}
+void OpDeprecation::unsafe_arena_set_allocated_explanation(
+    ::std::string* explanation) {
+  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);
+  if (explanation != NULL) {
+
+  } else {
+
+  }
+  explanation_.UnsafeArenaSetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      explanation, GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_unsafe_arena_set_allocated:tensorflow.OpDeprecation.explanation)
+}
+
+inline const OpDeprecation* OpDeprecation::internal_default_instance() {
+  return &OpDeprecation_default_instance_.get();
+}
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
+
+// ===================================================================
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const int OpList::kOpFieldNumber;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+
+OpList::OpList()
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+  if (this != internal_default_instance()) protobuf_InitDefaults_op_5fdef_2eproto();
+  SharedCtor();
+  // @@protoc_insertion_point(constructor:tensorflow.OpList)
+}
+OpList::OpList(::google::protobuf::Arena* arena)
+  : ::google::protobuf::Message(),
+  _internal_metadata_(arena),
+  op_(arena) {
+#ifdef GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER
+  protobuf_InitDefaults_op_5fdef_2eproto();
+#endif  // GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER
+  SharedCtor();
+  RegisterArenaDtor(arena);
+  // @@protoc_insertion_point(arena_constructor:tensorflow.OpList)
+}
+
+void OpList::InitAsDefaultInstance() {
+}
+
+OpList::OpList(const OpList& from)
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
+  SharedCtor();
+  UnsafeMergeFrom(from);
+  // @@protoc_insertion_point(copy_constructor:tensorflow.OpList)
+}
+
+void OpList::SharedCtor() {
+  _cached_size_ = 0;
+}
+
+OpList::~OpList() {
+  // @@protoc_insertion_point(destructor:tensorflow.OpList)
+  SharedDtor();
+}
+
+void OpList::SharedDtor() {
+  ::google::protobuf::Arena* arena = GetArenaNoVirtual();
+  if (arena != NULL) {
+    return;
+  }
+
+}
+
+void OpList::ArenaDtor(void* object) {
+  OpList* _this = reinterpret_cast< OpList* >(object);
+  (void)_this;
+}
+void OpList::RegisterArenaDtor(::google::protobuf::Arena* arena) {
+}
+void OpList::SetCachedSize(int size) const {
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* OpList::descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return OpList_descriptor_;
+}
+
+const OpList& OpList::default_instance() {
+  protobuf_InitDefaults_op_5fdef_2eproto();
+  return *internal_default_instance();
+}
+
+::google::protobuf::internal::ExplicitlyConstructed<OpList> OpList_default_instance_;
+
+OpList* OpList::New(::google::protobuf::Arena* arena) const {
+  return ::google::protobuf::Arena::CreateMessage<OpList>(arena);
+}
+
+void OpList::Clear() {
+// @@protoc_insertion_point(message_clear_start:tensorflow.OpList)
+  op_.Clear();
+}
+
+bool OpList::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
+  ::google::protobuf::uint32 tag;
+  // @@protoc_insertion_point(parse_start:tensorflow.OpList)
+  for (;;) {
+    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+    tag = p.first;
+    if (!p.second) goto handle_unusual;
+    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+      // repeated .tensorflow.OpDef op = 1;
+      case 1: {
+        if (tag == 10) {
+          DO_(input->IncrementRecursionDepth());
+         parse_loop_op:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth(
+                input, add_op()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(10)) goto parse_loop_op;
+        input->UnsafeDecrementRecursionDepth();
+        if (input->ExpectAtEnd()) goto success;
+        break;
+      }
+
+      default: {
+      handle_unusual:
+        if (tag == 0 ||
+            ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+          goto success;
+        }
+        DO_(::google::protobuf::internal::WireFormatLite::SkipField(input, tag));
+        break;
+      }
+    }
+  }
+success:
+  // @@protoc_insertion_point(parse_success:tensorflow.OpList)
+  return true;
+failure:
+  // @@protoc_insertion_point(parse_failure:tensorflow.OpList)
+  return false;
+#undef DO_
+}
+
+void OpList::SerializeWithCachedSizes(
+    ::google::protobuf::io::CodedOutputStream* output) const {
+  // @@protoc_insertion_point(serialize_start:tensorflow.OpList)
+  // repeated .tensorflow.OpDef op = 1;
+  for (unsigned int i = 0, n = this->op_size(); i < n; i++) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      1, this->op(i), output);
+  }
+
+  // @@protoc_insertion_point(serialize_end:tensorflow.OpList)
+}
+
+::google::protobuf::uint8* OpList::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
+  (void)deterministic; // Unused
+  // @@protoc_insertion_point(serialize_to_array_start:tensorflow.OpList)
+  // repeated .tensorflow.OpDef op = 1;
+  for (unsigned int i = 0, n = this->op_size(); i < n; i++) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        1, this->op(i), false, target);
+  }
+
+  // @@protoc_insertion_point(serialize_to_array_end:tensorflow.OpList)
+  return target;
+}
+
+size_t OpList::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:tensorflow.OpList)
+  size_t total_size = 0;
+
+  // repeated .tensorflow.OpDef op = 1;
+  {
+    unsigned int count = this->op_size();
+    total_size += 1UL * count;
+    for (unsigned int i = 0; i < count; i++) {
+      total_size +=
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          this->op(i));
+    }
+  }
+
+  int cached_size = ::google::protobuf::internal::ToCachedSize(total_size);
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = cached_size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+  return total_size;
+}
+
+void OpList::MergeFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_merge_from_start:tensorflow.OpList)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const OpList* source =
+      ::google::protobuf::internal::DynamicCastToGenerated<const OpList>(
+          &from);
+  if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:tensorflow.OpList)
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:tensorflow.OpList)
+    UnsafeMergeFrom(*source);
+  }
+}
+
+void OpList::MergeFrom(const OpList& from) {
+// @@protoc_insertion_point(class_specific_merge_from_start:tensorflow.OpList)
+  if (GOOGLE_PREDICT_TRUE(&from != this)) {
+    UnsafeMergeFrom(from);
+  } else {
+    MergeFromFail(__LINE__);
+  }
+}
+
+void OpList::UnsafeMergeFrom(const OpList& from) {
+  GOOGLE_DCHECK(&from != this);
+  op_.MergeFrom(from.op_);
+}
+
+void OpList::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:tensorflow.OpList)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void OpList::CopyFrom(const OpList& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:tensorflow.OpList)
+  if (&from == this) return;
+  Clear();
+  UnsafeMergeFrom(from);
+}
+
+bool OpList::IsInitialized() const {
+
+  return true;
+}
+
+void OpList::Swap(OpList* other) {
+  if (other == this) return;
+  if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) {
+    InternalSwap(other);
+  } else {
+    OpList temp;
+    temp.UnsafeMergeFrom(*this);
+    CopyFrom(*other);
+    other->CopyFrom(temp);
+  }
+}
+void OpList::UnsafeArenaSwap(OpList* other) {
+  if (other == this) return;
+  GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual());
+  InternalSwap(other);
+}
+void OpList::InternalSwap(OpList* other) {
+  op_.UnsafeArenaSwap(&other->op_);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
+}
+
+::google::protobuf::Metadata OpList::GetMetadata() const {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::Metadata metadata;
+  metadata.descriptor = OpList_descriptor_;
+  metadata.reflection = OpList_reflection_;
+  return metadata;
+}
+
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// OpList
+
+// repeated .tensorflow.OpDef op = 1;
+int OpList::op_size() const {
+  return op_.size();
+}
+void OpList::clear_op() {
+  op_.Clear();
+}
+const ::tensorflow::OpDef& OpList::op(int index) const {
+  // @@protoc_insertion_point(field_get:tensorflow.OpList.op)
+  return op_.Get(index);
+}
+::tensorflow::OpDef* OpList::mutable_op(int index) {
+  // @@protoc_insertion_point(field_mutable:tensorflow.OpList.op)
+  return op_.Mutable(index);
+}
+::tensorflow::OpDef* OpList::add_op() {
+  // @@protoc_insertion_point(field_add:tensorflow.OpList.op)
+  return op_.Add();
+}
+::google::protobuf::RepeatedPtrField< ::tensorflow::OpDef >*
+OpList::mutable_op() {
+  // @@protoc_insertion_point(field_mutable_list:tensorflow.OpList.op)
+  return &op_;
+}
+const ::google::protobuf::RepeatedPtrField< ::tensorflow::OpDef >&
+OpList::op() const {
+  // @@protoc_insertion_point(field_list:tensorflow.OpList.op)
+  return op_;
+}
+
+inline const OpList* OpList::internal_default_instance() {
+  return &OpList_default_instance_.get();
+}
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
+
+// @@protoc_insertion_point(namespace_scope)
+
+}  // namespace tensorflow
+
+// @@protoc_insertion_point(global_scope)
diff --git a/contrib/modules/dnn/misc/tensorflow/op_def.pb.h b/contrib/modules/dnn/misc/tensorflow/op_def.pb.h
new file mode 100644
index 0000000..71956e4
--- /dev/null
+++ b/contrib/modules/dnn/misc/tensorflow/op_def.pb.h
@@ -0,0 +1,2103 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: op_def.proto
+
+#ifndef PROTOBUF_op_5fdef_2eproto__INCLUDED
+#define PROTOBUF_op_5fdef_2eproto__INCLUDED
+
+#include <string>
+
+#include <google/protobuf/stubs/common.h>
+
+#if GOOGLE_PROTOBUF_VERSION < 3001000
+#error This file was generated by a newer version of protoc which is
+#error incompatible with your Protocol Buffer headers.  Please update
+#error your headers.
+#endif
+#if 3001000 < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION
+#error This file was generated by an older version of protoc which is
+#error incompatible with your Protocol Buffer headers.  Please
+#error regenerate this file with a newer version of protoc.
+#endif
+
+#include <google/protobuf/arena.h>
+#include <google/protobuf/arenastring.h>
+#include <google/protobuf/generated_message_util.h>
+#include <google/protobuf/metadata.h>
+#include <google/protobuf/message.h>
+#include <google/protobuf/repeated_field.h>
+#include <google/protobuf/extension_set.h>
+#include <google/protobuf/unknown_field_set.h>
+#include "attr_value.pb.h"
+#include "types.pb.h"
+// @@protoc_insertion_point(includes)
+
+namespace tensorflow {
+
+// Internal implementation detail -- do not call these.
+void protobuf_AddDesc_op_5fdef_2eproto();
+void protobuf_InitDefaults_op_5fdef_2eproto();
+void protobuf_AssignDesc_op_5fdef_2eproto();
+void protobuf_ShutdownFile_op_5fdef_2eproto();
+
+class OpDef;
+class OpDef_ArgDef;
+class OpDef_AttrDef;
+class OpDeprecation;
+class OpList;
+
+// ===================================================================
+
+class OpDef_ArgDef : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:tensorflow.OpDef.ArgDef) */ {
+ public:
+  OpDef_ArgDef();
+  virtual ~OpDef_ArgDef();
+
+  OpDef_ArgDef(const OpDef_ArgDef& from);
+
+  inline OpDef_ArgDef& operator=(const OpDef_ArgDef& from) {
+    CopyFrom(from);
+    return *this;
+  }
+
+  inline ::google::protobuf::Arena* GetArena() const { return GetArenaNoVirtual(); }
+  inline void* GetMaybeArenaPointer() const {
+    return MaybeArenaPtr();
+  }
+  static const ::google::protobuf::Descriptor* descriptor();
+  static const OpDef_ArgDef& default_instance();
+
+  static const OpDef_ArgDef* internal_default_instance();
+
+  void UnsafeArenaSwap(OpDef_ArgDef* other);
+  void Swap(OpDef_ArgDef* other);
+
+  // implements Message ----------------------------------------------
+
+  inline OpDef_ArgDef* New() const { return New(NULL); }
+
+  OpDef_ArgDef* New(::google::protobuf::Arena* arena) const;
+  void CopyFrom(const ::google::protobuf::Message& from);
+  void MergeFrom(const ::google::protobuf::Message& from);
+  void CopyFrom(const OpDef_ArgDef& from);
+  void MergeFrom(const OpDef_ArgDef& from);
+  void Clear();
+  bool IsInitialized() const;
+
+  size_t ByteSizeLong() const;
+  bool MergePartialFromCodedStream(
+      ::google::protobuf::io::CodedInputStream* input);
+  void SerializeWithCachedSizes(
+      ::google::protobuf::io::CodedOutputStream* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
+  int GetCachedSize() const { return _cached_size_; }
+  private:
+  void SharedCtor();
+  void SharedDtor();
+  void SetCachedSize(int size) const;
+  void InternalSwap(OpDef_ArgDef* other);
+  void UnsafeMergeFrom(const OpDef_ArgDef& from);
+  protected:
+  explicit OpDef_ArgDef(::google::protobuf::Arena* arena);
+  private:
+  static void ArenaDtor(void* object);
+  inline void RegisterArenaDtor(::google::protobuf::Arena* arena);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
+  public:
+
+  ::google::protobuf::Metadata GetMetadata() const;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  // optional string name = 1;
+  void clear_name();
+  static const int kNameFieldNumber = 1;
+  const ::std::string& name() const;
+  void set_name(const ::std::string& value);
+  void set_name(const char* value);
+  void set_name(const char* value, size_t size);
+  ::std::string* mutable_name();
+  ::std::string* release_name();
+  void set_allocated_name(::std::string* name);
+  ::std::string* unsafe_arena_release_name();
+  void unsafe_arena_set_allocated_name(
+      ::std::string* name);
+
+  // optional string description = 2;
+  void clear_description();
+  static const int kDescriptionFieldNumber = 2;
+  const ::std::string& description() const;
+  void set_description(const ::std::string& value);
+  void set_description(const char* value);
+  void set_description(const char* value, size_t size);
+  ::std::string* mutable_description();
+  ::std::string* release_description();
+  void set_allocated_description(::std::string* description);
+  ::std::string* unsafe_arena_release_description();
+  void unsafe_arena_set_allocated_description(
+      ::std::string* description);
+
+  // optional .tensorflow.DataType type = 3;
+  void clear_type();
+  static const int kTypeFieldNumber = 3;
+  ::tensorflow::DataType type() const;
+  void set_type(::tensorflow::DataType value);
+
+  // optional string type_attr = 4;
+  void clear_type_attr();
+  static const int kTypeAttrFieldNumber = 4;
+  const ::std::string& type_attr() const;
+  void set_type_attr(const ::std::string& value);
+  void set_type_attr(const char* value);
+  void set_type_attr(const char* value, size_t size);
+  ::std::string* mutable_type_attr();
+  ::std::string* release_type_attr();
+  void set_allocated_type_attr(::std::string* type_attr);
+  ::std::string* unsafe_arena_release_type_attr();
+  void unsafe_arena_set_allocated_type_attr(
+      ::std::string* type_attr);
+
+  // optional string number_attr = 5;
+  void clear_number_attr();
+  static const int kNumberAttrFieldNumber = 5;
+  const ::std::string& number_attr() const;
+  void set_number_attr(const ::std::string& value);
+  void set_number_attr(const char* value);
+  void set_number_attr(const char* value, size_t size);
+  ::std::string* mutable_number_attr();
+  ::std::string* release_number_attr();
+  void set_allocated_number_attr(::std::string* number_attr);
+  ::std::string* unsafe_arena_release_number_attr();
+  void unsafe_arena_set_allocated_number_attr(
+      ::std::string* number_attr);
+
+  // optional string type_list_attr = 6;
+  void clear_type_list_attr();
+  static const int kTypeListAttrFieldNumber = 6;
+  const ::std::string& type_list_attr() const;
+  void set_type_list_attr(const ::std::string& value);
+  void set_type_list_attr(const char* value);
+  void set_type_list_attr(const char* value, size_t size);
+  ::std::string* mutable_type_list_attr();
+  ::std::string* release_type_list_attr();
+  void set_allocated_type_list_attr(::std::string* type_list_attr);
+  ::std::string* unsafe_arena_release_type_list_attr();
+  void unsafe_arena_set_allocated_type_list_attr(
+      ::std::string* type_list_attr);
+
+  // optional bool is_ref = 16;
+  void clear_is_ref();
+  static const int kIsRefFieldNumber = 16;
+  bool is_ref() const;
+  void set_is_ref(bool value);
+
+  // @@protoc_insertion_point(class_scope:tensorflow.OpDef.ArgDef)
+ private:
+
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  friend class ::google::protobuf::Arena;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  ::google::protobuf::internal::ArenaStringPtr name_;
+  ::google::protobuf::internal::ArenaStringPtr description_;
+  ::google::protobuf::internal::ArenaStringPtr type_attr_;
+  ::google::protobuf::internal::ArenaStringPtr number_attr_;
+  ::google::protobuf::internal::ArenaStringPtr type_list_attr_;
+  int type_;
+  bool is_ref_;
+  mutable int _cached_size_;
+  friend void  protobuf_InitDefaults_op_5fdef_2eproto_impl();
+  friend void  protobuf_AddDesc_op_5fdef_2eproto_impl();
+  friend void protobuf_AssignDesc_op_5fdef_2eproto();
+  friend void protobuf_ShutdownFile_op_5fdef_2eproto();
+
+  void InitAsDefaultInstance();
+};
+extern ::google::protobuf::internal::ExplicitlyConstructed<OpDef_ArgDef> OpDef_ArgDef_default_instance_;
+
+// -------------------------------------------------------------------
+
+class OpDef_AttrDef : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:tensorflow.OpDef.AttrDef) */ {
+ public:
+  OpDef_AttrDef();
+  virtual ~OpDef_AttrDef();
+
+  OpDef_AttrDef(const OpDef_AttrDef& from);
+
+  inline OpDef_AttrDef& operator=(const OpDef_AttrDef& from) {
+    CopyFrom(from);
+    return *this;
+  }
+
+  inline ::google::protobuf::Arena* GetArena() const { return GetArenaNoVirtual(); }
+  inline void* GetMaybeArenaPointer() const {
+    return MaybeArenaPtr();
+  }
+  static const ::google::protobuf::Descriptor* descriptor();
+  static const OpDef_AttrDef& default_instance();
+
+  static const OpDef_AttrDef* internal_default_instance();
+
+  void UnsafeArenaSwap(OpDef_AttrDef* other);
+  void Swap(OpDef_AttrDef* other);
+
+  // implements Message ----------------------------------------------
+
+  inline OpDef_AttrDef* New() const { return New(NULL); }
+
+  OpDef_AttrDef* New(::google::protobuf::Arena* arena) const;
+  void CopyFrom(const ::google::protobuf::Message& from);
+  void MergeFrom(const ::google::protobuf::Message& from);
+  void CopyFrom(const OpDef_AttrDef& from);
+  void MergeFrom(const OpDef_AttrDef& from);
+  void Clear();
+  bool IsInitialized() const;
+
+  size_t ByteSizeLong() const;
+  bool MergePartialFromCodedStream(
+      ::google::protobuf::io::CodedInputStream* input);
+  void SerializeWithCachedSizes(
+      ::google::protobuf::io::CodedOutputStream* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
+  int GetCachedSize() const { return _cached_size_; }
+  private:
+  void SharedCtor();
+  void SharedDtor();
+  void SetCachedSize(int size) const;
+  void InternalSwap(OpDef_AttrDef* other);
+  void UnsafeMergeFrom(const OpDef_AttrDef& from);
+  protected:
+  explicit OpDef_AttrDef(::google::protobuf::Arena* arena);
+  private:
+  static void ArenaDtor(void* object);
+  inline void RegisterArenaDtor(::google::protobuf::Arena* arena);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
+  public:
+
+  ::google::protobuf::Metadata GetMetadata() const;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  // optional string name = 1;
+  void clear_name();
+  static const int kNameFieldNumber = 1;
+  const ::std::string& name() const;
+  void set_name(const ::std::string& value);
+  void set_name(const char* value);
+  void set_name(const char* value, size_t size);
+  ::std::string* mutable_name();
+  ::std::string* release_name();
+  void set_allocated_name(::std::string* name);
+  ::std::string* unsafe_arena_release_name();
+  void unsafe_arena_set_allocated_name(
+      ::std::string* name);
+
+  // optional string type = 2;
+  void clear_type();
+  static const int kTypeFieldNumber = 2;
+  const ::std::string& type() const;
+  void set_type(const ::std::string& value);
+  void set_type(const char* value);
+  void set_type(const char* value, size_t size);
+  ::std::string* mutable_type();
+  ::std::string* release_type();
+  void set_allocated_type(::std::string* type);
+  ::std::string* unsafe_arena_release_type();
+  void unsafe_arena_set_allocated_type(
+      ::std::string* type);
+
+  // optional .tensorflow.AttrValue default_value = 3;
+  bool has_default_value() const;
+  void clear_default_value();
+  static const int kDefaultValueFieldNumber = 3;
+  private:
+  void _slow_mutable_default_value();
+  void _slow_set_allocated_default_value(
+      ::google::protobuf::Arena* message_arena, ::tensorflow::AttrValue** default_value);
+  ::tensorflow::AttrValue* _slow_release_default_value();
+  public:
+  const ::tensorflow::AttrValue& default_value() const;
+  ::tensorflow::AttrValue* mutable_default_value();
+  ::tensorflow::AttrValue* release_default_value();
+  void set_allocated_default_value(::tensorflow::AttrValue* default_value);
+  ::tensorflow::AttrValue* unsafe_arena_release_default_value();
+  void unsafe_arena_set_allocated_default_value(
+      ::tensorflow::AttrValue* default_value);
+
+  // optional string description = 4;
+  void clear_description();
+  static const int kDescriptionFieldNumber = 4;
+  const ::std::string& description() const;
+  void set_description(const ::std::string& value);
+  void set_description(const char* value);
+  void set_description(const char* value, size_t size);
+  ::std::string* mutable_description();
+  ::std::string* release_description();
+  void set_allocated_description(::std::string* description);
+  ::std::string* unsafe_arena_release_description();
+  void unsafe_arena_set_allocated_description(
+      ::std::string* description);
+
+  // optional bool has_minimum = 5;
+  void clear_has_minimum();
+  static const int kHasMinimumFieldNumber = 5;
+  bool has_minimum() const;
+  void set_has_minimum(bool value);
+
+  // optional int64 minimum = 6;
+  void clear_minimum();
+  static const int kMinimumFieldNumber = 6;
+  ::google::protobuf::int64 minimum() const;
+  void set_minimum(::google::protobuf::int64 value);
+
+  // optional .tensorflow.AttrValue allowed_values = 7;
+  bool has_allowed_values() const;
+  void clear_allowed_values();
+  static const int kAllowedValuesFieldNumber = 7;
+  private:
+  void _slow_mutable_allowed_values();
+  void _slow_set_allocated_allowed_values(
+      ::google::protobuf::Arena* message_arena, ::tensorflow::AttrValue** allowed_values);
+  ::tensorflow::AttrValue* _slow_release_allowed_values();
+  public:
+  const ::tensorflow::AttrValue& allowed_values() const;
+  ::tensorflow::AttrValue* mutable_allowed_values();
+  ::tensorflow::AttrValue* release_allowed_values();
+  void set_allocated_allowed_values(::tensorflow::AttrValue* allowed_values);
+  ::tensorflow::AttrValue* unsafe_arena_release_allowed_values();
+  void unsafe_arena_set_allocated_allowed_values(
+      ::tensorflow::AttrValue* allowed_values);
+
+  // @@protoc_insertion_point(class_scope:tensorflow.OpDef.AttrDef)
+ private:
+
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  friend class ::google::protobuf::Arena;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  ::google::protobuf::internal::ArenaStringPtr name_;
+  ::google::protobuf::internal::ArenaStringPtr type_;
+  ::google::protobuf::internal::ArenaStringPtr description_;
+  ::tensorflow::AttrValue* default_value_;
+  ::tensorflow::AttrValue* allowed_values_;
+  ::google::protobuf::int64 minimum_;
+  bool has_minimum_;
+  mutable int _cached_size_;
+  friend void  protobuf_InitDefaults_op_5fdef_2eproto_impl();
+  friend void  protobuf_AddDesc_op_5fdef_2eproto_impl();
+  friend void protobuf_AssignDesc_op_5fdef_2eproto();
+  friend void protobuf_ShutdownFile_op_5fdef_2eproto();
+
+  void InitAsDefaultInstance();
+};
+extern ::google::protobuf::internal::ExplicitlyConstructed<OpDef_AttrDef> OpDef_AttrDef_default_instance_;
+
+// -------------------------------------------------------------------
+
+class OpDef : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:tensorflow.OpDef) */ {
+ public:
+  OpDef();
+  virtual ~OpDef();
+
+  OpDef(const OpDef& from);
+
+  inline OpDef& operator=(const OpDef& from) {
+    CopyFrom(from);
+    return *this;
+  }
+
+  inline ::google::protobuf::Arena* GetArena() const { return GetArenaNoVirtual(); }
+  inline void* GetMaybeArenaPointer() const {
+    return MaybeArenaPtr();
+  }
+  static const ::google::protobuf::Descriptor* descriptor();
+  static const OpDef& default_instance();
+
+  static const OpDef* internal_default_instance();
+
+  void UnsafeArenaSwap(OpDef* other);
+  void Swap(OpDef* other);
+
+  // implements Message ----------------------------------------------
+
+  inline OpDef* New() const { return New(NULL); }
+
+  OpDef* New(::google::protobuf::Arena* arena) const;
+  void CopyFrom(const ::google::protobuf::Message& from);
+  void MergeFrom(const ::google::protobuf::Message& from);
+  void CopyFrom(const OpDef& from);
+  void MergeFrom(const OpDef& from);
+  void Clear();
+  bool IsInitialized() const;
+
+  size_t ByteSizeLong() const;
+  bool MergePartialFromCodedStream(
+      ::google::protobuf::io::CodedInputStream* input);
+  void SerializeWithCachedSizes(
+      ::google::protobuf::io::CodedOutputStream* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
+  int GetCachedSize() const { return _cached_size_; }
+  private:
+  void SharedCtor();
+  void SharedDtor();
+  void SetCachedSize(int size) const;
+  void InternalSwap(OpDef* other);
+  void UnsafeMergeFrom(const OpDef& from);
+  protected:
+  explicit OpDef(::google::protobuf::Arena* arena);
+  private:
+  static void ArenaDtor(void* object);
+  inline void RegisterArenaDtor(::google::protobuf::Arena* arena);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
+  public:
+
+  ::google::protobuf::Metadata GetMetadata() const;
+
+  // nested types ----------------------------------------------------
+
+  typedef OpDef_ArgDef ArgDef;
+  typedef OpDef_AttrDef AttrDef;
+
+  // accessors -------------------------------------------------------
+
+  // optional string name = 1;
+  void clear_name();
+  static const int kNameFieldNumber = 1;
+  const ::std::string& name() const;
+  void set_name(const ::std::string& value);
+  void set_name(const char* value);
+  void set_name(const char* value, size_t size);
+  ::std::string* mutable_name();
+  ::std::string* release_name();
+  void set_allocated_name(::std::string* name);
+  ::std::string* unsafe_arena_release_name();
+  void unsafe_arena_set_allocated_name(
+      ::std::string* name);
+
+  // repeated .tensorflow.OpDef.ArgDef input_arg = 2;
+  int input_arg_size() const;
+  void clear_input_arg();
+  static const int kInputArgFieldNumber = 2;
+  const ::tensorflow::OpDef_ArgDef& input_arg(int index) const;
+  ::tensorflow::OpDef_ArgDef* mutable_input_arg(int index);
+  ::tensorflow::OpDef_ArgDef* add_input_arg();
+  ::google::protobuf::RepeatedPtrField< ::tensorflow::OpDef_ArgDef >*
+      mutable_input_arg();
+  const ::google::protobuf::RepeatedPtrField< ::tensorflow::OpDef_ArgDef >&
+      input_arg() const;
+
+  // repeated .tensorflow.OpDef.ArgDef output_arg = 3;
+  int output_arg_size() const;
+  void clear_output_arg();
+  static const int kOutputArgFieldNumber = 3;
+  const ::tensorflow::OpDef_ArgDef& output_arg(int index) const;
+  ::tensorflow::OpDef_ArgDef* mutable_output_arg(int index);
+  ::tensorflow::OpDef_ArgDef* add_output_arg();
+  ::google::protobuf::RepeatedPtrField< ::tensorflow::OpDef_ArgDef >*
+      mutable_output_arg();
+  const ::google::protobuf::RepeatedPtrField< ::tensorflow::OpDef_ArgDef >&
+      output_arg() const;
+
+  // repeated .tensorflow.OpDef.AttrDef attr = 4;
+  int attr_size() const;
+  void clear_attr();
+  static const int kAttrFieldNumber = 4;
+  const ::tensorflow::OpDef_AttrDef& attr(int index) const;
+  ::tensorflow::OpDef_AttrDef* mutable_attr(int index);
+  ::tensorflow::OpDef_AttrDef* add_attr();
+  ::google::protobuf::RepeatedPtrField< ::tensorflow::OpDef_AttrDef >*
+      mutable_attr();
+  const ::google::protobuf::RepeatedPtrField< ::tensorflow::OpDef_AttrDef >&
+      attr() const;
+
+  // optional .tensorflow.OpDeprecation deprecation = 8;
+  bool has_deprecation() const;
+  void clear_deprecation();
+  static const int kDeprecationFieldNumber = 8;
+  private:
+  void _slow_mutable_deprecation();
+  void _slow_set_allocated_deprecation(
+      ::google::protobuf::Arena* message_arena, ::tensorflow::OpDeprecation** deprecation);
+  ::tensorflow::OpDeprecation* _slow_release_deprecation();
+  public:
+  const ::tensorflow::OpDeprecation& deprecation() const;
+  ::tensorflow::OpDeprecation* mutable_deprecation();
+  ::tensorflow::OpDeprecation* release_deprecation();
+  void set_allocated_deprecation(::tensorflow::OpDeprecation* deprecation);
+  ::tensorflow::OpDeprecation* unsafe_arena_release_deprecation();
+  void unsafe_arena_set_allocated_deprecation(
+      ::tensorflow::OpDeprecation* deprecation);
+
+  // optional string summary = 5;
+  void clear_summary();
+  static const int kSummaryFieldNumber = 5;
+  const ::std::string& summary() const;
+  void set_summary(const ::std::string& value);
+  void set_summary(const char* value);
+  void set_summary(const char* value, size_t size);
+  ::std::string* mutable_summary();
+  ::std::string* release_summary();
+  void set_allocated_summary(::std::string* summary);
+  ::std::string* unsafe_arena_release_summary();
+  void unsafe_arena_set_allocated_summary(
+      ::std::string* summary);
+
+  // optional string description = 6;
+  void clear_description();
+  static const int kDescriptionFieldNumber = 6;
+  const ::std::string& description() const;
+  void set_description(const ::std::string& value);
+  void set_description(const char* value);
+  void set_description(const char* value, size_t size);
+  ::std::string* mutable_description();
+  ::std::string* release_description();
+  void set_allocated_description(::std::string* description);
+  ::std::string* unsafe_arena_release_description();
+  void unsafe_arena_set_allocated_description(
+      ::std::string* description);
+
+  // optional bool is_commutative = 18;
+  void clear_is_commutative();
+  static const int kIsCommutativeFieldNumber = 18;
+  bool is_commutative() const;
+  void set_is_commutative(bool value);
+
+  // optional bool is_aggregate = 16;
+  void clear_is_aggregate();
+  static const int kIsAggregateFieldNumber = 16;
+  bool is_aggregate() const;
+  void set_is_aggregate(bool value);
+
+  // optional bool is_stateful = 17;
+  void clear_is_stateful();
+  static const int kIsStatefulFieldNumber = 17;
+  bool is_stateful() const;
+  void set_is_stateful(bool value);
+
+  // optional bool allows_uninitialized_input = 19;
+  void clear_allows_uninitialized_input();
+  static const int kAllowsUninitializedInputFieldNumber = 19;
+  bool allows_uninitialized_input() const;
+  void set_allows_uninitialized_input(bool value);
+
+  // @@protoc_insertion_point(class_scope:tensorflow.OpDef)
+ private:
+
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  friend class ::google::protobuf::Arena;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  ::google::protobuf::RepeatedPtrField< ::tensorflow::OpDef_ArgDef > input_arg_;
+  ::google::protobuf::RepeatedPtrField< ::tensorflow::OpDef_ArgDef > output_arg_;
+  ::google::protobuf::RepeatedPtrField< ::tensorflow::OpDef_AttrDef > attr_;
+  ::google::protobuf::internal::ArenaStringPtr name_;
+  ::google::protobuf::internal::ArenaStringPtr summary_;
+  ::google::protobuf::internal::ArenaStringPtr description_;
+  ::tensorflow::OpDeprecation* deprecation_;
+  bool is_commutative_;
+  bool is_aggregate_;
+  bool is_stateful_;
+  bool allows_uninitialized_input_;
+  mutable int _cached_size_;
+  friend void  protobuf_InitDefaults_op_5fdef_2eproto_impl();
+  friend void  protobuf_AddDesc_op_5fdef_2eproto_impl();
+  friend void protobuf_AssignDesc_op_5fdef_2eproto();
+  friend void protobuf_ShutdownFile_op_5fdef_2eproto();
+
+  void InitAsDefaultInstance();
+};
+extern ::google::protobuf::internal::ExplicitlyConstructed<OpDef> OpDef_default_instance_;
+
+// -------------------------------------------------------------------
+
+class OpDeprecation : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:tensorflow.OpDeprecation) */ {
+ public:
+  OpDeprecation();
+  virtual ~OpDeprecation();
+
+  OpDeprecation(const OpDeprecation& from);
+
+  inline OpDeprecation& operator=(const OpDeprecation& from) {
+    CopyFrom(from);
+    return *this;
+  }
+
+  inline ::google::protobuf::Arena* GetArena() const { return GetArenaNoVirtual(); }
+  inline void* GetMaybeArenaPointer() const {
+    return MaybeArenaPtr();
+  }
+  static const ::google::protobuf::Descriptor* descriptor();
+  static const OpDeprecation& default_instance();
+
+  static const OpDeprecation* internal_default_instance();
+
+  void UnsafeArenaSwap(OpDeprecation* other);
+  void Swap(OpDeprecation* other);
+
+  // implements Message ----------------------------------------------
+
+  inline OpDeprecation* New() const { return New(NULL); }
+
+  OpDeprecation* New(::google::protobuf::Arena* arena) const;
+  void CopyFrom(const ::google::protobuf::Message& from);
+  void MergeFrom(const ::google::protobuf::Message& from);
+  void CopyFrom(const OpDeprecation& from);
+  void MergeFrom(const OpDeprecation& from);
+  void Clear();
+  bool IsInitialized() const;
+
+  size_t ByteSizeLong() const;
+  bool MergePartialFromCodedStream(
+      ::google::protobuf::io::CodedInputStream* input);
+  void SerializeWithCachedSizes(
+      ::google::protobuf::io::CodedOutputStream* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
+  int GetCachedSize() const { return _cached_size_; }
+  private:
+  void SharedCtor();
+  void SharedDtor();
+  void SetCachedSize(int size) const;
+  void InternalSwap(OpDeprecation* other);
+  void UnsafeMergeFrom(const OpDeprecation& from);
+  protected:
+  explicit OpDeprecation(::google::protobuf::Arena* arena);
+  private:
+  static void ArenaDtor(void* object);
+  inline void RegisterArenaDtor(::google::protobuf::Arena* arena);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
+  public:
+
+  ::google::protobuf::Metadata GetMetadata() const;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  // optional int32 version = 1;
+  void clear_version();
+  static const int kVersionFieldNumber = 1;
+  ::google::protobuf::int32 version() const;
+  void set_version(::google::protobuf::int32 value);
+
+  // optional string explanation = 2;
+  void clear_explanation();
+  static const int kExplanationFieldNumber = 2;
+  const ::std::string& explanation() const;
+  void set_explanation(const ::std::string& value);
+  void set_explanation(const char* value);
+  void set_explanation(const char* value, size_t size);
+  ::std::string* mutable_explanation();
+  ::std::string* release_explanation();
+  void set_allocated_explanation(::std::string* explanation);
+  ::std::string* unsafe_arena_release_explanation();
+  void unsafe_arena_set_allocated_explanation(
+      ::std::string* explanation);
+
+  // @@protoc_insertion_point(class_scope:tensorflow.OpDeprecation)
+ private:
+
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  friend class ::google::protobuf::Arena;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  ::google::protobuf::internal::ArenaStringPtr explanation_;
+  ::google::protobuf::int32 version_;
+  mutable int _cached_size_;
+  friend void  protobuf_InitDefaults_op_5fdef_2eproto_impl();
+  friend void  protobuf_AddDesc_op_5fdef_2eproto_impl();
+  friend void protobuf_AssignDesc_op_5fdef_2eproto();
+  friend void protobuf_ShutdownFile_op_5fdef_2eproto();
+
+  void InitAsDefaultInstance();
+};
+extern ::google::protobuf::internal::ExplicitlyConstructed<OpDeprecation> OpDeprecation_default_instance_;
+
+// -------------------------------------------------------------------
+
+class OpList : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:tensorflow.OpList) */ {
+ public:
+  OpList();
+  virtual ~OpList();
+
+  OpList(const OpList& from);
+
+  inline OpList& operator=(const OpList& from) {
+    CopyFrom(from);
+    return *this;
+  }
+
+  inline ::google::protobuf::Arena* GetArena() const { return GetArenaNoVirtual(); }
+  inline void* GetMaybeArenaPointer() const {
+    return MaybeArenaPtr();
+  }
+  static const ::google::protobuf::Descriptor* descriptor();
+  static const OpList& default_instance();
+
+  static const OpList* internal_default_instance();
+
+  void UnsafeArenaSwap(OpList* other);
+  void Swap(OpList* other);
+
+  // implements Message ----------------------------------------------
+
+  inline OpList* New() const { return New(NULL); }
+
+  OpList* New(::google::protobuf::Arena* arena) const;
+  void CopyFrom(const ::google::protobuf::Message& from);
+  void MergeFrom(const ::google::protobuf::Message& from);
+  void CopyFrom(const OpList& from);
+  void MergeFrom(const OpList& from);
+  void Clear();
+  bool IsInitialized() const;
+
+  size_t ByteSizeLong() const;
+  bool MergePartialFromCodedStream(
+      ::google::protobuf::io::CodedInputStream* input);
+  void SerializeWithCachedSizes(
+      ::google::protobuf::io::CodedOutputStream* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
+  int GetCachedSize() const { return _cached_size_; }
+  private:
+  void SharedCtor();
+  void SharedDtor();
+  void SetCachedSize(int size) const;
+  void InternalSwap(OpList* other);
+  void UnsafeMergeFrom(const OpList& from);
+  protected:
+  explicit OpList(::google::protobuf::Arena* arena);
+  private:
+  static void ArenaDtor(void* object);
+  inline void RegisterArenaDtor(::google::protobuf::Arena* arena);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
+  public:
+
+  ::google::protobuf::Metadata GetMetadata() const;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  // repeated .tensorflow.OpDef op = 1;
+  int op_size() const;
+  void clear_op();
+  static const int kOpFieldNumber = 1;
+  const ::tensorflow::OpDef& op(int index) const;
+  ::tensorflow::OpDef* mutable_op(int index);
+  ::tensorflow::OpDef* add_op();
+  ::google::protobuf::RepeatedPtrField< ::tensorflow::OpDef >*
+      mutable_op();
+  const ::google::protobuf::RepeatedPtrField< ::tensorflow::OpDef >&
+      op() const;
+
+  // @@protoc_insertion_point(class_scope:tensorflow.OpList)
+ private:
+
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  friend class ::google::protobuf::Arena;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  ::google::protobuf::RepeatedPtrField< ::tensorflow::OpDef > op_;
+  mutable int _cached_size_;
+  friend void  protobuf_InitDefaults_op_5fdef_2eproto_impl();
+  friend void  protobuf_AddDesc_op_5fdef_2eproto_impl();
+  friend void protobuf_AssignDesc_op_5fdef_2eproto();
+  friend void protobuf_ShutdownFile_op_5fdef_2eproto();
+
+  void InitAsDefaultInstance();
+};
+extern ::google::protobuf::internal::ExplicitlyConstructed<OpList> OpList_default_instance_;
+
+// ===================================================================
+
+
+// ===================================================================
+
+#if !PROTOBUF_INLINE_NOT_IN_HEADERS
+// OpDef_ArgDef
+
+// optional string name = 1;
+inline void OpDef_ArgDef::clear_name() {
+  name_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+inline const ::std::string& OpDef_ArgDef::name() const {
+  // @@protoc_insertion_point(field_get:tensorflow.OpDef.ArgDef.name)
+  return name_.Get(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void OpDef_ArgDef::set_name(const ::std::string& value) {
+
+  name_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value, GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set:tensorflow.OpDef.ArgDef.name)
+}
+inline void OpDef_ArgDef::set_name(const char* value) {
+
+  name_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value),
+              GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_char:tensorflow.OpDef.ArgDef.name)
+}
+inline void OpDef_ArgDef::set_name(const char* value,
+    size_t size) {
+
+  name_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(
+      reinterpret_cast<const char*>(value), size), GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_pointer:tensorflow.OpDef.ArgDef.name)
+}
+inline ::std::string* OpDef_ArgDef::mutable_name() {
+
+  // @@protoc_insertion_point(field_mutable:tensorflow.OpDef.ArgDef.name)
+  return name_.Mutable(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+inline ::std::string* OpDef_ArgDef::release_name() {
+  // @@protoc_insertion_point(field_release:tensorflow.OpDef.ArgDef.name)
+
+  return name_.Release(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+inline ::std::string* OpDef_ArgDef::unsafe_arena_release_name() {
+  // @@protoc_insertion_point(field_unsafe_arena_release:tensorflow.OpDef.ArgDef.name)
+  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);
+
+  return name_.UnsafeArenaRelease(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      GetArenaNoVirtual());
+}
+inline void OpDef_ArgDef::set_allocated_name(::std::string* name) {
+  if (name != NULL) {
+
+  } else {
+
+  }
+  name_.SetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), name,
+      GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_allocated:tensorflow.OpDef.ArgDef.name)
+}
+inline void OpDef_ArgDef::unsafe_arena_set_allocated_name(
+    ::std::string* name) {
+  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);
+  if (name != NULL) {
+
+  } else {
+
+  }
+  name_.UnsafeArenaSetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      name, GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_unsafe_arena_set_allocated:tensorflow.OpDef.ArgDef.name)
+}
+
+// optional string description = 2;
+inline void OpDef_ArgDef::clear_description() {
+  description_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+inline const ::std::string& OpDef_ArgDef::description() const {
+  // @@protoc_insertion_point(field_get:tensorflow.OpDef.ArgDef.description)
+  return description_.Get(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void OpDef_ArgDef::set_description(const ::std::string& value) {
+
+  description_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value, GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set:tensorflow.OpDef.ArgDef.description)
+}
+inline void OpDef_ArgDef::set_description(const char* value) {
+
+  description_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value),
+              GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_char:tensorflow.OpDef.ArgDef.description)
+}
+inline void OpDef_ArgDef::set_description(const char* value,
+    size_t size) {
+
+  description_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(
+      reinterpret_cast<const char*>(value), size), GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_pointer:tensorflow.OpDef.ArgDef.description)
+}
+inline ::std::string* OpDef_ArgDef::mutable_description() {
+
+  // @@protoc_insertion_point(field_mutable:tensorflow.OpDef.ArgDef.description)
+  return description_.Mutable(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+inline ::std::string* OpDef_ArgDef::release_description() {
+  // @@protoc_insertion_point(field_release:tensorflow.OpDef.ArgDef.description)
+
+  return description_.Release(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+inline ::std::string* OpDef_ArgDef::unsafe_arena_release_description() {
+  // @@protoc_insertion_point(field_unsafe_arena_release:tensorflow.OpDef.ArgDef.description)
+  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);
+
+  return description_.UnsafeArenaRelease(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      GetArenaNoVirtual());
+}
+inline void OpDef_ArgDef::set_allocated_description(::std::string* description) {
+  if (description != NULL) {
+
+  } else {
+
+  }
+  description_.SetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), description,
+      GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_allocated:tensorflow.OpDef.ArgDef.description)
+}
+inline void OpDef_ArgDef::unsafe_arena_set_allocated_description(
+    ::std::string* description) {
+  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);
+  if (description != NULL) {
+
+  } else {
+
+  }
+  description_.UnsafeArenaSetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      description, GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_unsafe_arena_set_allocated:tensorflow.OpDef.ArgDef.description)
+}
+
+// optional .tensorflow.DataType type = 3;
+inline void OpDef_ArgDef::clear_type() {
+  type_ = 0;
+}
+inline ::tensorflow::DataType OpDef_ArgDef::type() const {
+  // @@protoc_insertion_point(field_get:tensorflow.OpDef.ArgDef.type)
+  return static_cast< ::tensorflow::DataType >(type_);
+}
+inline void OpDef_ArgDef::set_type(::tensorflow::DataType value) {
+
+  type_ = value;
+  // @@protoc_insertion_point(field_set:tensorflow.OpDef.ArgDef.type)
+}
+
+// optional string type_attr = 4;
+inline void OpDef_ArgDef::clear_type_attr() {
+  type_attr_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+inline const ::std::string& OpDef_ArgDef::type_attr() const {
+  // @@protoc_insertion_point(field_get:tensorflow.OpDef.ArgDef.type_attr)
+  return type_attr_.Get(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void OpDef_ArgDef::set_type_attr(const ::std::string& value) {
+
+  type_attr_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value, GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set:tensorflow.OpDef.ArgDef.type_attr)
+}
+inline void OpDef_ArgDef::set_type_attr(const char* value) {
+
+  type_attr_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value),
+              GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_char:tensorflow.OpDef.ArgDef.type_attr)
+}
+inline void OpDef_ArgDef::set_type_attr(const char* value,
+    size_t size) {
+
+  type_attr_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(
+      reinterpret_cast<const char*>(value), size), GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_pointer:tensorflow.OpDef.ArgDef.type_attr)
+}
+inline ::std::string* OpDef_ArgDef::mutable_type_attr() {
+
+  // @@protoc_insertion_point(field_mutable:tensorflow.OpDef.ArgDef.type_attr)
+  return type_attr_.Mutable(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+inline ::std::string* OpDef_ArgDef::release_type_attr() {
+  // @@protoc_insertion_point(field_release:tensorflow.OpDef.ArgDef.type_attr)
+
+  return type_attr_.Release(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+inline ::std::string* OpDef_ArgDef::unsafe_arena_release_type_attr() {
+  // @@protoc_insertion_point(field_unsafe_arena_release:tensorflow.OpDef.ArgDef.type_attr)
+  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);
+
+  return type_attr_.UnsafeArenaRelease(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      GetArenaNoVirtual());
+}
+inline void OpDef_ArgDef::set_allocated_type_attr(::std::string* type_attr) {
+  if (type_attr != NULL) {
+
+  } else {
+
+  }
+  type_attr_.SetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), type_attr,
+      GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_allocated:tensorflow.OpDef.ArgDef.type_attr)
+}
+inline void OpDef_ArgDef::unsafe_arena_set_allocated_type_attr(
+    ::std::string* type_attr) {
+  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);
+  if (type_attr != NULL) {
+
+  } else {
+
+  }
+  type_attr_.UnsafeArenaSetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      type_attr, GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_unsafe_arena_set_allocated:tensorflow.OpDef.ArgDef.type_attr)
+}
+
+// optional string number_attr = 5;
+inline void OpDef_ArgDef::clear_number_attr() {
+  number_attr_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+inline const ::std::string& OpDef_ArgDef::number_attr() const {
+  // @@protoc_insertion_point(field_get:tensorflow.OpDef.ArgDef.number_attr)
+  return number_attr_.Get(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void OpDef_ArgDef::set_number_attr(const ::std::string& value) {
+
+  number_attr_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value, GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set:tensorflow.OpDef.ArgDef.number_attr)
+}
+inline void OpDef_ArgDef::set_number_attr(const char* value) {
+
+  number_attr_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value),
+              GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_char:tensorflow.OpDef.ArgDef.number_attr)
+}
+inline void OpDef_ArgDef::set_number_attr(const char* value,
+    size_t size) {
+
+  number_attr_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(
+      reinterpret_cast<const char*>(value), size), GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_pointer:tensorflow.OpDef.ArgDef.number_attr)
+}
+inline ::std::string* OpDef_ArgDef::mutable_number_attr() {
+
+  // @@protoc_insertion_point(field_mutable:tensorflow.OpDef.ArgDef.number_attr)
+  return number_attr_.Mutable(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+inline ::std::string* OpDef_ArgDef::release_number_attr() {
+  // @@protoc_insertion_point(field_release:tensorflow.OpDef.ArgDef.number_attr)
+
+  return number_attr_.Release(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+inline ::std::string* OpDef_ArgDef::unsafe_arena_release_number_attr() {
+  // @@protoc_insertion_point(field_unsafe_arena_release:tensorflow.OpDef.ArgDef.number_attr)
+  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);
+
+  return number_attr_.UnsafeArenaRelease(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      GetArenaNoVirtual());
+}
+inline void OpDef_ArgDef::set_allocated_number_attr(::std::string* number_attr) {
+  if (number_attr != NULL) {
+
+  } else {
+
+  }
+  number_attr_.SetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), number_attr,
+      GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_allocated:tensorflow.OpDef.ArgDef.number_attr)
+}
+inline void OpDef_ArgDef::unsafe_arena_set_allocated_number_attr(
+    ::std::string* number_attr) {
+  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);
+  if (number_attr != NULL) {
+
+  } else {
+
+  }
+  number_attr_.UnsafeArenaSetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      number_attr, GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_unsafe_arena_set_allocated:tensorflow.OpDef.ArgDef.number_attr)
+}
+
+// optional string type_list_attr = 6;
+inline void OpDef_ArgDef::clear_type_list_attr() {
+  type_list_attr_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+inline const ::std::string& OpDef_ArgDef::type_list_attr() const {
+  // @@protoc_insertion_point(field_get:tensorflow.OpDef.ArgDef.type_list_attr)
+  return type_list_attr_.Get(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void OpDef_ArgDef::set_type_list_attr(const ::std::string& value) {
+
+  type_list_attr_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value, GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set:tensorflow.OpDef.ArgDef.type_list_attr)
+}
+inline void OpDef_ArgDef::set_type_list_attr(const char* value) {
+
+  type_list_attr_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value),
+              GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_char:tensorflow.OpDef.ArgDef.type_list_attr)
+}
+inline void OpDef_ArgDef::set_type_list_attr(const char* value,
+    size_t size) {
+
+  type_list_attr_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(
+      reinterpret_cast<const char*>(value), size), GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_pointer:tensorflow.OpDef.ArgDef.type_list_attr)
+}
+inline ::std::string* OpDef_ArgDef::mutable_type_list_attr() {
+
+  // @@protoc_insertion_point(field_mutable:tensorflow.OpDef.ArgDef.type_list_attr)
+  return type_list_attr_.Mutable(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+inline ::std::string* OpDef_ArgDef::release_type_list_attr() {
+  // @@protoc_insertion_point(field_release:tensorflow.OpDef.ArgDef.type_list_attr)
+
+  return type_list_attr_.Release(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+inline ::std::string* OpDef_ArgDef::unsafe_arena_release_type_list_attr() {
+  // @@protoc_insertion_point(field_unsafe_arena_release:tensorflow.OpDef.ArgDef.type_list_attr)
+  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);
+
+  return type_list_attr_.UnsafeArenaRelease(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      GetArenaNoVirtual());
+}
+inline void OpDef_ArgDef::set_allocated_type_list_attr(::std::string* type_list_attr) {
+  if (type_list_attr != NULL) {
+
+  } else {
+
+  }
+  type_list_attr_.SetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), type_list_attr,
+      GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_allocated:tensorflow.OpDef.ArgDef.type_list_attr)
+}
+inline void OpDef_ArgDef::unsafe_arena_set_allocated_type_list_attr(
+    ::std::string* type_list_attr) {
+  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);
+  if (type_list_attr != NULL) {
+
+  } else {
+
+  }
+  type_list_attr_.UnsafeArenaSetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      type_list_attr, GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_unsafe_arena_set_allocated:tensorflow.OpDef.ArgDef.type_list_attr)
+}
+
+// optional bool is_ref = 16;
+inline void OpDef_ArgDef::clear_is_ref() {
+  is_ref_ = false;
+}
+inline bool OpDef_ArgDef::is_ref() const {
+  // @@protoc_insertion_point(field_get:tensorflow.OpDef.ArgDef.is_ref)
+  return is_ref_;
+}
+inline void OpDef_ArgDef::set_is_ref(bool value) {
+
+  is_ref_ = value;
+  // @@protoc_insertion_point(field_set:tensorflow.OpDef.ArgDef.is_ref)
+}
+
+inline const OpDef_ArgDef* OpDef_ArgDef::internal_default_instance() {
+  return &OpDef_ArgDef_default_instance_.get();
+}
+// -------------------------------------------------------------------
+
+// OpDef_AttrDef
+
+// optional string name = 1;
+inline void OpDef_AttrDef::clear_name() {
+  name_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+inline const ::std::string& OpDef_AttrDef::name() const {
+  // @@protoc_insertion_point(field_get:tensorflow.OpDef.AttrDef.name)
+  return name_.Get(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void OpDef_AttrDef::set_name(const ::std::string& value) {
+
+  name_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value, GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set:tensorflow.OpDef.AttrDef.name)
+}
+inline void OpDef_AttrDef::set_name(const char* value) {
+
+  name_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value),
+              GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_char:tensorflow.OpDef.AttrDef.name)
+}
+inline void OpDef_AttrDef::set_name(const char* value,
+    size_t size) {
+
+  name_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(
+      reinterpret_cast<const char*>(value), size), GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_pointer:tensorflow.OpDef.AttrDef.name)
+}
+inline ::std::string* OpDef_AttrDef::mutable_name() {
+
+  // @@protoc_insertion_point(field_mutable:tensorflow.OpDef.AttrDef.name)
+  return name_.Mutable(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+inline ::std::string* OpDef_AttrDef::release_name() {
+  // @@protoc_insertion_point(field_release:tensorflow.OpDef.AttrDef.name)
+
+  return name_.Release(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+inline ::std::string* OpDef_AttrDef::unsafe_arena_release_name() {
+  // @@protoc_insertion_point(field_unsafe_arena_release:tensorflow.OpDef.AttrDef.name)
+  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);
+
+  return name_.UnsafeArenaRelease(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      GetArenaNoVirtual());
+}
+inline void OpDef_AttrDef::set_allocated_name(::std::string* name) {
+  if (name != NULL) {
+
+  } else {
+
+  }
+  name_.SetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), name,
+      GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_allocated:tensorflow.OpDef.AttrDef.name)
+}
+inline void OpDef_AttrDef::unsafe_arena_set_allocated_name(
+    ::std::string* name) {
+  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);
+  if (name != NULL) {
+
+  } else {
+
+  }
+  name_.UnsafeArenaSetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      name, GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_unsafe_arena_set_allocated:tensorflow.OpDef.AttrDef.name)
+}
+
+// optional string type = 2;
+inline void OpDef_AttrDef::clear_type() {
+  type_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+inline const ::std::string& OpDef_AttrDef::type() const {
+  // @@protoc_insertion_point(field_get:tensorflow.OpDef.AttrDef.type)
+  return type_.Get(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void OpDef_AttrDef::set_type(const ::std::string& value) {
+
+  type_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value, GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set:tensorflow.OpDef.AttrDef.type)
+}
+inline void OpDef_AttrDef::set_type(const char* value) {
+
+  type_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value),
+              GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_char:tensorflow.OpDef.AttrDef.type)
+}
+inline void OpDef_AttrDef::set_type(const char* value,
+    size_t size) {
+
+  type_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(
+      reinterpret_cast<const char*>(value), size), GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_pointer:tensorflow.OpDef.AttrDef.type)
+}
+inline ::std::string* OpDef_AttrDef::mutable_type() {
+
+  // @@protoc_insertion_point(field_mutable:tensorflow.OpDef.AttrDef.type)
+  return type_.Mutable(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+inline ::std::string* OpDef_AttrDef::release_type() {
+  // @@protoc_insertion_point(field_release:tensorflow.OpDef.AttrDef.type)
+
+  return type_.Release(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+inline ::std::string* OpDef_AttrDef::unsafe_arena_release_type() {
+  // @@protoc_insertion_point(field_unsafe_arena_release:tensorflow.OpDef.AttrDef.type)
+  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);
+
+  return type_.UnsafeArenaRelease(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      GetArenaNoVirtual());
+}
+inline void OpDef_AttrDef::set_allocated_type(::std::string* type) {
+  if (type != NULL) {
+
+  } else {
+
+  }
+  type_.SetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), type,
+      GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_allocated:tensorflow.OpDef.AttrDef.type)
+}
+inline void OpDef_AttrDef::unsafe_arena_set_allocated_type(
+    ::std::string* type) {
+  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);
+  if (type != NULL) {
+
+  } else {
+
+  }
+  type_.UnsafeArenaSetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      type, GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_unsafe_arena_set_allocated:tensorflow.OpDef.AttrDef.type)
+}
+
+// optional .tensorflow.AttrValue default_value = 3;
+inline bool OpDef_AttrDef::has_default_value() const {
+  return this != internal_default_instance() && default_value_ != NULL;
+}
+inline void OpDef_AttrDef::clear_default_value() {
+  if (GetArenaNoVirtual() == NULL && default_value_ != NULL) delete default_value_;
+  default_value_ = NULL;
+}
+inline const ::tensorflow::AttrValue& OpDef_AttrDef::default_value() const {
+  // @@protoc_insertion_point(field_get:tensorflow.OpDef.AttrDef.default_value)
+  return default_value_ != NULL ? *default_value_
+                         : *::tensorflow::AttrValue::internal_default_instance();
+}
+inline ::tensorflow::AttrValue* OpDef_AttrDef::mutable_default_value() {
+
+  if (default_value_ == NULL) {
+    _slow_mutable_default_value();
+  }
+  // @@protoc_insertion_point(field_mutable:tensorflow.OpDef.AttrDef.default_value)
+  return default_value_;
+}
+inline ::tensorflow::AttrValue* OpDef_AttrDef::release_default_value() {
+  // @@protoc_insertion_point(field_release:tensorflow.OpDef.AttrDef.default_value)
+
+  if (GetArenaNoVirtual() != NULL) {
+    return _slow_release_default_value();
+  } else {
+    ::tensorflow::AttrValue* temp = default_value_;
+    default_value_ = NULL;
+    return temp;
+  }
+}
+inline  void OpDef_AttrDef::set_allocated_default_value(::tensorflow::AttrValue* default_value) {
+  ::google::protobuf::Arena* message_arena = GetArenaNoVirtual();
+  if (message_arena == NULL) {
+    delete default_value_;
+  }
+  if (default_value != NULL) {
+    _slow_set_allocated_default_value(message_arena, &default_value);
+  }
+  default_value_ = default_value;
+  if (default_value) {
+
+  } else {
+
+  }
+  // @@protoc_insertion_point(field_set_allocated:tensorflow.OpDef.AttrDef.default_value)
+}
+
+// optional string description = 4;
+inline void OpDef_AttrDef::clear_description() {
+  description_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+inline const ::std::string& OpDef_AttrDef::description() const {
+  // @@protoc_insertion_point(field_get:tensorflow.OpDef.AttrDef.description)
+  return description_.Get(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void OpDef_AttrDef::set_description(const ::std::string& value) {
+
+  description_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value, GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set:tensorflow.OpDef.AttrDef.description)
+}
+inline void OpDef_AttrDef::set_description(const char* value) {
+
+  description_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value),
+              GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_char:tensorflow.OpDef.AttrDef.description)
+}
+inline void OpDef_AttrDef::set_description(const char* value,
+    size_t size) {
+
+  description_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(
+      reinterpret_cast<const char*>(value), size), GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_pointer:tensorflow.OpDef.AttrDef.description)
+}
+inline ::std::string* OpDef_AttrDef::mutable_description() {
+
+  // @@protoc_insertion_point(field_mutable:tensorflow.OpDef.AttrDef.description)
+  return description_.Mutable(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+inline ::std::string* OpDef_AttrDef::release_description() {
+  // @@protoc_insertion_point(field_release:tensorflow.OpDef.AttrDef.description)
+
+  return description_.Release(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+inline ::std::string* OpDef_AttrDef::unsafe_arena_release_description() {
+  // @@protoc_insertion_point(field_unsafe_arena_release:tensorflow.OpDef.AttrDef.description)
+  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);
+
+  return description_.UnsafeArenaRelease(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      GetArenaNoVirtual());
+}
+inline void OpDef_AttrDef::set_allocated_description(::std::string* description) {
+  if (description != NULL) {
+
+  } else {
+
+  }
+  description_.SetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), description,
+      GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_allocated:tensorflow.OpDef.AttrDef.description)
+}
+inline void OpDef_AttrDef::unsafe_arena_set_allocated_description(
+    ::std::string* description) {
+  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);
+  if (description != NULL) {
+
+  } else {
+
+  }
+  description_.UnsafeArenaSetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      description, GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_unsafe_arena_set_allocated:tensorflow.OpDef.AttrDef.description)
+}
+
+// optional bool has_minimum = 5;
+inline void OpDef_AttrDef::clear_has_minimum() {
+  has_minimum_ = false;
+}
+inline bool OpDef_AttrDef::has_minimum() const {
+  // @@protoc_insertion_point(field_get:tensorflow.OpDef.AttrDef.has_minimum)
+  return has_minimum_;
+}
+inline void OpDef_AttrDef::set_has_minimum(bool value) {
+
+  has_minimum_ = value;
+  // @@protoc_insertion_point(field_set:tensorflow.OpDef.AttrDef.has_minimum)
+}
+
+// optional int64 minimum = 6;
+inline void OpDef_AttrDef::clear_minimum() {
+  minimum_ = GOOGLE_LONGLONG(0);
+}
+inline ::google::protobuf::int64 OpDef_AttrDef::minimum() const {
+  // @@protoc_insertion_point(field_get:tensorflow.OpDef.AttrDef.minimum)
+  return minimum_;
+}
+inline void OpDef_AttrDef::set_minimum(::google::protobuf::int64 value) {
+
+  minimum_ = value;
+  // @@protoc_insertion_point(field_set:tensorflow.OpDef.AttrDef.minimum)
+}
+
+// optional .tensorflow.AttrValue allowed_values = 7;
+inline bool OpDef_AttrDef::has_allowed_values() const {
+  return this != internal_default_instance() && allowed_values_ != NULL;
+}
+inline void OpDef_AttrDef::clear_allowed_values() {
+  if (GetArenaNoVirtual() == NULL && allowed_values_ != NULL) delete allowed_values_;
+  allowed_values_ = NULL;
+}
+inline const ::tensorflow::AttrValue& OpDef_AttrDef::allowed_values() const {
+  // @@protoc_insertion_point(field_get:tensorflow.OpDef.AttrDef.allowed_values)
+  return allowed_values_ != NULL ? *allowed_values_
+                         : *::tensorflow::AttrValue::internal_default_instance();
+}
+inline ::tensorflow::AttrValue* OpDef_AttrDef::mutable_allowed_values() {
+
+  if (allowed_values_ == NULL) {
+    _slow_mutable_allowed_values();
+  }
+  // @@protoc_insertion_point(field_mutable:tensorflow.OpDef.AttrDef.allowed_values)
+  return allowed_values_;
+}
+inline ::tensorflow::AttrValue* OpDef_AttrDef::release_allowed_values() {
+  // @@protoc_insertion_point(field_release:tensorflow.OpDef.AttrDef.allowed_values)
+
+  if (GetArenaNoVirtual() != NULL) {
+    return _slow_release_allowed_values();
+  } else {
+    ::tensorflow::AttrValue* temp = allowed_values_;
+    allowed_values_ = NULL;
+    return temp;
+  }
+}
+inline  void OpDef_AttrDef::set_allocated_allowed_values(::tensorflow::AttrValue* allowed_values) {
+  ::google::protobuf::Arena* message_arena = GetArenaNoVirtual();
+  if (message_arena == NULL) {
+    delete allowed_values_;
+  }
+  if (allowed_values != NULL) {
+    _slow_set_allocated_allowed_values(message_arena, &allowed_values);
+  }
+  allowed_values_ = allowed_values;
+  if (allowed_values) {
+
+  } else {
+
+  }
+  // @@protoc_insertion_point(field_set_allocated:tensorflow.OpDef.AttrDef.allowed_values)
+}
+
+inline const OpDef_AttrDef* OpDef_AttrDef::internal_default_instance() {
+  return &OpDef_AttrDef_default_instance_.get();
+}
+// -------------------------------------------------------------------
+
+// OpDef
+
+// optional string name = 1;
+inline void OpDef::clear_name() {
+  name_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+inline const ::std::string& OpDef::name() const {
+  // @@protoc_insertion_point(field_get:tensorflow.OpDef.name)
+  return name_.Get(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void OpDef::set_name(const ::std::string& value) {
+
+  name_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value, GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set:tensorflow.OpDef.name)
+}
+inline void OpDef::set_name(const char* value) {
+
+  name_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value),
+              GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_char:tensorflow.OpDef.name)
+}
+inline void OpDef::set_name(const char* value,
+    size_t size) {
+
+  name_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(
+      reinterpret_cast<const char*>(value), size), GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_pointer:tensorflow.OpDef.name)
+}
+inline ::std::string* OpDef::mutable_name() {
+
+  // @@protoc_insertion_point(field_mutable:tensorflow.OpDef.name)
+  return name_.Mutable(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+inline ::std::string* OpDef::release_name() {
+  // @@protoc_insertion_point(field_release:tensorflow.OpDef.name)
+
+  return name_.Release(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+inline ::std::string* OpDef::unsafe_arena_release_name() {
+  // @@protoc_insertion_point(field_unsafe_arena_release:tensorflow.OpDef.name)
+  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);
+
+  return name_.UnsafeArenaRelease(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      GetArenaNoVirtual());
+}
+inline void OpDef::set_allocated_name(::std::string* name) {
+  if (name != NULL) {
+
+  } else {
+
+  }
+  name_.SetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), name,
+      GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_allocated:tensorflow.OpDef.name)
+}
+inline void OpDef::unsafe_arena_set_allocated_name(
+    ::std::string* name) {
+  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);
+  if (name != NULL) {
+
+  } else {
+
+  }
+  name_.UnsafeArenaSetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      name, GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_unsafe_arena_set_allocated:tensorflow.OpDef.name)
+}
+
+// repeated .tensorflow.OpDef.ArgDef input_arg = 2;
+inline int OpDef::input_arg_size() const {
+  return input_arg_.size();
+}
+inline void OpDef::clear_input_arg() {
+  input_arg_.Clear();
+}
+inline const ::tensorflow::OpDef_ArgDef& OpDef::input_arg(int index) const {
+  // @@protoc_insertion_point(field_get:tensorflow.OpDef.input_arg)
+  return input_arg_.Get(index);
+}
+inline ::tensorflow::OpDef_ArgDef* OpDef::mutable_input_arg(int index) {
+  // @@protoc_insertion_point(field_mutable:tensorflow.OpDef.input_arg)
+  return input_arg_.Mutable(index);
+}
+inline ::tensorflow::OpDef_ArgDef* OpDef::add_input_arg() {
+  // @@protoc_insertion_point(field_add:tensorflow.OpDef.input_arg)
+  return input_arg_.Add();
+}
+inline ::google::protobuf::RepeatedPtrField< ::tensorflow::OpDef_ArgDef >*
+OpDef::mutable_input_arg() {
+  // @@protoc_insertion_point(field_mutable_list:tensorflow.OpDef.input_arg)
+  return &input_arg_;
+}
+inline const ::google::protobuf::RepeatedPtrField< ::tensorflow::OpDef_ArgDef >&
+OpDef::input_arg() const {
+  // @@protoc_insertion_point(field_list:tensorflow.OpDef.input_arg)
+  return input_arg_;
+}
+
+// repeated .tensorflow.OpDef.ArgDef output_arg = 3;
+inline int OpDef::output_arg_size() const {
+  return output_arg_.size();
+}
+inline void OpDef::clear_output_arg() {
+  output_arg_.Clear();
+}
+inline const ::tensorflow::OpDef_ArgDef& OpDef::output_arg(int index) const {
+  // @@protoc_insertion_point(field_get:tensorflow.OpDef.output_arg)
+  return output_arg_.Get(index);
+}
+inline ::tensorflow::OpDef_ArgDef* OpDef::mutable_output_arg(int index) {
+  // @@protoc_insertion_point(field_mutable:tensorflow.OpDef.output_arg)
+  return output_arg_.Mutable(index);
+}
+inline ::tensorflow::OpDef_ArgDef* OpDef::add_output_arg() {
+  // @@protoc_insertion_point(field_add:tensorflow.OpDef.output_arg)
+  return output_arg_.Add();
+}
+inline ::google::protobuf::RepeatedPtrField< ::tensorflow::OpDef_ArgDef >*
+OpDef::mutable_output_arg() {
+  // @@protoc_insertion_point(field_mutable_list:tensorflow.OpDef.output_arg)
+  return &output_arg_;
+}
+inline const ::google::protobuf::RepeatedPtrField< ::tensorflow::OpDef_ArgDef >&
+OpDef::output_arg() const {
+  // @@protoc_insertion_point(field_list:tensorflow.OpDef.output_arg)
+  return output_arg_;
+}
+
+// repeated .tensorflow.OpDef.AttrDef attr = 4;
+inline int OpDef::attr_size() const {
+  return attr_.size();
+}
+inline void OpDef::clear_attr() {
+  attr_.Clear();
+}
+inline const ::tensorflow::OpDef_AttrDef& OpDef::attr(int index) const {
+  // @@protoc_insertion_point(field_get:tensorflow.OpDef.attr)
+  return attr_.Get(index);
+}
+inline ::tensorflow::OpDef_AttrDef* OpDef::mutable_attr(int index) {
+  // @@protoc_insertion_point(field_mutable:tensorflow.OpDef.attr)
+  return attr_.Mutable(index);
+}
+inline ::tensorflow::OpDef_AttrDef* OpDef::add_attr() {
+  // @@protoc_insertion_point(field_add:tensorflow.OpDef.attr)
+  return attr_.Add();
+}
+inline ::google::protobuf::RepeatedPtrField< ::tensorflow::OpDef_AttrDef >*
+OpDef::mutable_attr() {
+  // @@protoc_insertion_point(field_mutable_list:tensorflow.OpDef.attr)
+  return &attr_;
+}
+inline const ::google::protobuf::RepeatedPtrField< ::tensorflow::OpDef_AttrDef >&
+OpDef::attr() const {
+  // @@protoc_insertion_point(field_list:tensorflow.OpDef.attr)
+  return attr_;
+}
+
+// optional .tensorflow.OpDeprecation deprecation = 8;
+inline bool OpDef::has_deprecation() const {
+  return this != internal_default_instance() && deprecation_ != NULL;
+}
+inline void OpDef::clear_deprecation() {
+  if (GetArenaNoVirtual() == NULL && deprecation_ != NULL) delete deprecation_;
+  deprecation_ = NULL;
+}
+inline const ::tensorflow::OpDeprecation& OpDef::deprecation() const {
+  // @@protoc_insertion_point(field_get:tensorflow.OpDef.deprecation)
+  return deprecation_ != NULL ? *deprecation_
+                         : *::tensorflow::OpDeprecation::internal_default_instance();
+}
+inline ::tensorflow::OpDeprecation* OpDef::mutable_deprecation() {
+
+  if (deprecation_ == NULL) {
+    _slow_mutable_deprecation();
+  }
+  // @@protoc_insertion_point(field_mutable:tensorflow.OpDef.deprecation)
+  return deprecation_;
+}
+inline ::tensorflow::OpDeprecation* OpDef::release_deprecation() {
+  // @@protoc_insertion_point(field_release:tensorflow.OpDef.deprecation)
+
+  if (GetArenaNoVirtual() != NULL) {
+    return _slow_release_deprecation();
+  } else {
+    ::tensorflow::OpDeprecation* temp = deprecation_;
+    deprecation_ = NULL;
+    return temp;
+  }
+}
+inline  void OpDef::set_allocated_deprecation(::tensorflow::OpDeprecation* deprecation) {
+  ::google::protobuf::Arena* message_arena = GetArenaNoVirtual();
+  if (message_arena == NULL) {
+    delete deprecation_;
+  }
+  if (deprecation != NULL) {
+    _slow_set_allocated_deprecation(message_arena, &deprecation);
+  }
+  deprecation_ = deprecation;
+  if (deprecation) {
+
+  } else {
+
+  }
+  // @@protoc_insertion_point(field_set_allocated:tensorflow.OpDef.deprecation)
+}
+
+// optional string summary = 5;
+inline void OpDef::clear_summary() {
+  summary_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+inline const ::std::string& OpDef::summary() const {
+  // @@protoc_insertion_point(field_get:tensorflow.OpDef.summary)
+  return summary_.Get(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void OpDef::set_summary(const ::std::string& value) {
+
+  summary_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value, GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set:tensorflow.OpDef.summary)
+}
+inline void OpDef::set_summary(const char* value) {
+
+  summary_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value),
+              GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_char:tensorflow.OpDef.summary)
+}
+inline void OpDef::set_summary(const char* value,
+    size_t size) {
+
+  summary_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(
+      reinterpret_cast<const char*>(value), size), GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_pointer:tensorflow.OpDef.summary)
+}
+inline ::std::string* OpDef::mutable_summary() {
+
+  // @@protoc_insertion_point(field_mutable:tensorflow.OpDef.summary)
+  return summary_.Mutable(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+inline ::std::string* OpDef::release_summary() {
+  // @@protoc_insertion_point(field_release:tensorflow.OpDef.summary)
+
+  return summary_.Release(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+inline ::std::string* OpDef::unsafe_arena_release_summary() {
+  // @@protoc_insertion_point(field_unsafe_arena_release:tensorflow.OpDef.summary)
+  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);
+
+  return summary_.UnsafeArenaRelease(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      GetArenaNoVirtual());
+}
+inline void OpDef::set_allocated_summary(::std::string* summary) {
+  if (summary != NULL) {
+
+  } else {
+
+  }
+  summary_.SetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), summary,
+      GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_allocated:tensorflow.OpDef.summary)
+}
+inline void OpDef::unsafe_arena_set_allocated_summary(
+    ::std::string* summary) {
+  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);
+  if (summary != NULL) {
+
+  } else {
+
+  }
+  summary_.UnsafeArenaSetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      summary, GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_unsafe_arena_set_allocated:tensorflow.OpDef.summary)
+}
+
+// optional string description = 6;
+inline void OpDef::clear_description() {
+  description_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+inline const ::std::string& OpDef::description() const {
+  // @@protoc_insertion_point(field_get:tensorflow.OpDef.description)
+  return description_.Get(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void OpDef::set_description(const ::std::string& value) {
+
+  description_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value, GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set:tensorflow.OpDef.description)
+}
+inline void OpDef::set_description(const char* value) {
+
+  description_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value),
+              GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_char:tensorflow.OpDef.description)
+}
+inline void OpDef::set_description(const char* value,
+    size_t size) {
+
+  description_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(
+      reinterpret_cast<const char*>(value), size), GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_pointer:tensorflow.OpDef.description)
+}
+inline ::std::string* OpDef::mutable_description() {
+
+  // @@protoc_insertion_point(field_mutable:tensorflow.OpDef.description)
+  return description_.Mutable(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+inline ::std::string* OpDef::release_description() {
+  // @@protoc_insertion_point(field_release:tensorflow.OpDef.description)
+
+  return description_.Release(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+inline ::std::string* OpDef::unsafe_arena_release_description() {
+  // @@protoc_insertion_point(field_unsafe_arena_release:tensorflow.OpDef.description)
+  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);
+
+  return description_.UnsafeArenaRelease(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      GetArenaNoVirtual());
+}
+inline void OpDef::set_allocated_description(::std::string* description) {
+  if (description != NULL) {
+
+  } else {
+
+  }
+  description_.SetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), description,
+      GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_allocated:tensorflow.OpDef.description)
+}
+inline void OpDef::unsafe_arena_set_allocated_description(
+    ::std::string* description) {
+  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);
+  if (description != NULL) {
+
+  } else {
+
+  }
+  description_.UnsafeArenaSetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      description, GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_unsafe_arena_set_allocated:tensorflow.OpDef.description)
+}
+
+// optional bool is_commutative = 18;
+inline void OpDef::clear_is_commutative() {
+  is_commutative_ = false;
+}
+inline bool OpDef::is_commutative() const {
+  // @@protoc_insertion_point(field_get:tensorflow.OpDef.is_commutative)
+  return is_commutative_;
+}
+inline void OpDef::set_is_commutative(bool value) {
+
+  is_commutative_ = value;
+  // @@protoc_insertion_point(field_set:tensorflow.OpDef.is_commutative)
+}
+
+// optional bool is_aggregate = 16;
+inline void OpDef::clear_is_aggregate() {
+  is_aggregate_ = false;
+}
+inline bool OpDef::is_aggregate() const {
+  // @@protoc_insertion_point(field_get:tensorflow.OpDef.is_aggregate)
+  return is_aggregate_;
+}
+inline void OpDef::set_is_aggregate(bool value) {
+
+  is_aggregate_ = value;
+  // @@protoc_insertion_point(field_set:tensorflow.OpDef.is_aggregate)
+}
+
+// optional bool is_stateful = 17;
+inline void OpDef::clear_is_stateful() {
+  is_stateful_ = false;
+}
+inline bool OpDef::is_stateful() const {
+  // @@protoc_insertion_point(field_get:tensorflow.OpDef.is_stateful)
+  return is_stateful_;
+}
+inline void OpDef::set_is_stateful(bool value) {
+
+  is_stateful_ = value;
+  // @@protoc_insertion_point(field_set:tensorflow.OpDef.is_stateful)
+}
+
+// optional bool allows_uninitialized_input = 19;
+inline void OpDef::clear_allows_uninitialized_input() {
+  allows_uninitialized_input_ = false;
+}
+inline bool OpDef::allows_uninitialized_input() const {
+  // @@protoc_insertion_point(field_get:tensorflow.OpDef.allows_uninitialized_input)
+  return allows_uninitialized_input_;
+}
+inline void OpDef::set_allows_uninitialized_input(bool value) {
+
+  allows_uninitialized_input_ = value;
+  // @@protoc_insertion_point(field_set:tensorflow.OpDef.allows_uninitialized_input)
+}
+
+inline const OpDef* OpDef::internal_default_instance() {
+  return &OpDef_default_instance_.get();
+}
+// -------------------------------------------------------------------
+
+// OpDeprecation
+
+// optional int32 version = 1;
+inline void OpDeprecation::clear_version() {
+  version_ = 0;
+}
+inline ::google::protobuf::int32 OpDeprecation::version() const {
+  // @@protoc_insertion_point(field_get:tensorflow.OpDeprecation.version)
+  return version_;
+}
+inline void OpDeprecation::set_version(::google::protobuf::int32 value) {
+
+  version_ = value;
+  // @@protoc_insertion_point(field_set:tensorflow.OpDeprecation.version)
+}
+
+// optional string explanation = 2;
+inline void OpDeprecation::clear_explanation() {
+  explanation_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+inline const ::std::string& OpDeprecation::explanation() const {
+  // @@protoc_insertion_point(field_get:tensorflow.OpDeprecation.explanation)
+  return explanation_.Get(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void OpDeprecation::set_explanation(const ::std::string& value) {
+
+  explanation_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value, GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set:tensorflow.OpDeprecation.explanation)
+}
+inline void OpDeprecation::set_explanation(const char* value) {
+
+  explanation_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value),
+              GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_char:tensorflow.OpDeprecation.explanation)
+}
+inline void OpDeprecation::set_explanation(const char* value,
+    size_t size) {
+
+  explanation_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(
+      reinterpret_cast<const char*>(value), size), GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_pointer:tensorflow.OpDeprecation.explanation)
+}
+inline ::std::string* OpDeprecation::mutable_explanation() {
+
+  // @@protoc_insertion_point(field_mutable:tensorflow.OpDeprecation.explanation)
+  return explanation_.Mutable(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+inline ::std::string* OpDeprecation::release_explanation() {
+  // @@protoc_insertion_point(field_release:tensorflow.OpDeprecation.explanation)
+
+  return explanation_.Release(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+inline ::std::string* OpDeprecation::unsafe_arena_release_explanation() {
+  // @@protoc_insertion_point(field_unsafe_arena_release:tensorflow.OpDeprecation.explanation)
+  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);
+
+  return explanation_.UnsafeArenaRelease(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      GetArenaNoVirtual());
+}
+inline void OpDeprecation::set_allocated_explanation(::std::string* explanation) {
+  if (explanation != NULL) {
+
+  } else {
+
+  }
+  explanation_.SetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), explanation,
+      GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_allocated:tensorflow.OpDeprecation.explanation)
+}
+inline void OpDeprecation::unsafe_arena_set_allocated_explanation(
+    ::std::string* explanation) {
+  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);
+  if (explanation != NULL) {
+
+  } else {
+
+  }
+  explanation_.UnsafeArenaSetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      explanation, GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_unsafe_arena_set_allocated:tensorflow.OpDeprecation.explanation)
+}
+
+inline const OpDeprecation* OpDeprecation::internal_default_instance() {
+  return &OpDeprecation_default_instance_.get();
+}
+// -------------------------------------------------------------------
+
+// OpList
+
+// repeated .tensorflow.OpDef op = 1;
+inline int OpList::op_size() const {
+  return op_.size();
+}
+inline void OpList::clear_op() {
+  op_.Clear();
+}
+inline const ::tensorflow::OpDef& OpList::op(int index) const {
+  // @@protoc_insertion_point(field_get:tensorflow.OpList.op)
+  return op_.Get(index);
+}
+inline ::tensorflow::OpDef* OpList::mutable_op(int index) {
+  // @@protoc_insertion_point(field_mutable:tensorflow.OpList.op)
+  return op_.Mutable(index);
+}
+inline ::tensorflow::OpDef* OpList::add_op() {
+  // @@protoc_insertion_point(field_add:tensorflow.OpList.op)
+  return op_.Add();
+}
+inline ::google::protobuf::RepeatedPtrField< ::tensorflow::OpDef >*
+OpList::mutable_op() {
+  // @@protoc_insertion_point(field_mutable_list:tensorflow.OpList.op)
+  return &op_;
+}
+inline const ::google::protobuf::RepeatedPtrField< ::tensorflow::OpDef >&
+OpList::op() const {
+  // @@protoc_insertion_point(field_list:tensorflow.OpList.op)
+  return op_;
+}
+
+inline const OpList* OpList::internal_default_instance() {
+  return &OpList_default_instance_.get();
+}
+#endif  // !PROTOBUF_INLINE_NOT_IN_HEADERS
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+// -------------------------------------------------------------------
+
+
+// @@protoc_insertion_point(namespace_scope)
+
+}  // namespace tensorflow
+
+// @@protoc_insertion_point(global_scope)
+
+#endif  // PROTOBUF_op_5fdef_2eproto__INCLUDED
diff --git a/contrib/modules/dnn/misc/tensorflow/tensor.pb.cc b/contrib/modules/dnn/misc/tensorflow/tensor.pb.cc
new file mode 100644
index 0000000..e985109
--- /dev/null
+++ b/contrib/modules/dnn/misc/tensorflow/tensor.pb.cc
@@ -0,0 +1,1596 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: tensor.proto
+
+#define INTERNAL_SUPPRESS_PROTOBUF_FIELD_DEPRECATION
+#include "tensor.pb.h"
+
+#include <algorithm>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/port.h>
+#include <google/protobuf/stubs/once.h>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/wire_format_lite_inl.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/generated_message_reflection.h>
+#include <google/protobuf/reflection_ops.h>
+#include <google/protobuf/wire_format.h>
+// @@protoc_insertion_point(includes)
+
+namespace tensorflow {
+
+namespace {
+
+const ::google::protobuf::Descriptor* TensorProto_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+  TensorProto_reflection_ = NULL;
+
+}  // namespace
+
+
+void protobuf_AssignDesc_tensor_2eproto() GOOGLE_ATTRIBUTE_COLD;
+void protobuf_AssignDesc_tensor_2eproto() {
+  protobuf_AddDesc_tensor_2eproto();
+  const ::google::protobuf::FileDescriptor* file =
+    ::google::protobuf::DescriptorPool::generated_pool()->FindFileByName(
+      "tensor.proto");
+  GOOGLE_CHECK(file != NULL);
+  TensorProto_descriptor_ = file->message_type(0);
+  static const int TensorProto_offsets_[13] = {
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(TensorProto, dtype_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(TensorProto, tensor_shape_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(TensorProto, version_number_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(TensorProto, tensor_content_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(TensorProto, half_val_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(TensorProto, float_val_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(TensorProto, double_val_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(TensorProto, int_val_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(TensorProto, string_val_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(TensorProto, scomplex_val_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(TensorProto, int64_val_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(TensorProto, bool_val_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(TensorProto, dcomplex_val_),
+  };
+  TensorProto_reflection_ =
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
+      TensorProto_descriptor_,
+      TensorProto::internal_default_instance(),
+      TensorProto_offsets_,
+      -1,
+      -1,
+      -1,
+      sizeof(TensorProto),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(TensorProto, _internal_metadata_));
+}
+
+namespace {
+
+GOOGLE_PROTOBUF_DECLARE_ONCE(protobuf_AssignDescriptors_once_);
+void protobuf_AssignDescriptorsOnce() {
+  ::google::protobuf::GoogleOnceInit(&protobuf_AssignDescriptors_once_,
+                 &protobuf_AssignDesc_tensor_2eproto);
+}
+
+void protobuf_RegisterTypes(const ::std::string&) GOOGLE_ATTRIBUTE_COLD;
+void protobuf_RegisterTypes(const ::std::string&) {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+      TensorProto_descriptor_, TensorProto::internal_default_instance());
+}
+
+}  // namespace
+
+void protobuf_ShutdownFile_tensor_2eproto() {
+  TensorProto_default_instance_.Shutdown();
+  delete TensorProto_reflection_;
+}
+
+void protobuf_InitDefaults_tensor_2eproto_impl() {
+  GOOGLE_PROTOBUF_VERIFY_VERSION;
+
+  ::tensorflow::protobuf_InitDefaults_tensor_5fshape_2eproto();
+  ::tensorflow::protobuf_InitDefaults_types_2eproto();
+  ::google::protobuf::internal::GetEmptyString();
+  TensorProto_default_instance_.DefaultConstruct();
+  TensorProto_default_instance_.get_mutable()->InitAsDefaultInstance();
+}
+
+GOOGLE_PROTOBUF_DECLARE_ONCE(protobuf_InitDefaults_tensor_2eproto_once_);
+void protobuf_InitDefaults_tensor_2eproto() {
+  ::google::protobuf::GoogleOnceInit(&protobuf_InitDefaults_tensor_2eproto_once_,
+                 &protobuf_InitDefaults_tensor_2eproto_impl);
+}
+void protobuf_AddDesc_tensor_2eproto_impl() {
+  GOOGLE_PROTOBUF_VERIFY_VERSION;
+
+  protobuf_InitDefaults_tensor_2eproto();
+  ::google::protobuf::DescriptorPool::InternalAddGeneratedFile(
+    "\n\014tensor.proto\022\ntensorflow\032\022tensor_shape"
+    ".proto\032\013types.proto\"\345\002\n\013TensorProto\022#\n\005d"
+    "type\030\001 \001(\0162\024.tensorflow.DataType\0222\n\014tens"
+    "or_shape\030\002 \001(\0132\034.tensorflow.TensorShapeP"
+    "roto\022\026\n\016version_number\030\003 \001(\005\022\026\n\016tensor_c"
+    "ontent\030\004 \001(\014\022\024\n\010half_val\030\r \003(\005B\002\020\001\022\025\n\tfl"
+    "oat_val\030\005 \003(\002B\002\020\001\022\026\n\ndouble_val\030\006 \003(\001B\002\020"
+    "\001\022\023\n\007int_val\030\007 \003(\005B\002\020\001\022\022\n\nstring_val\030\010 \003"
+    "(\014\022\030\n\014scomplex_val\030\t \003(\002B\002\020\001\022\025\n\tint64_va"
+    "l\030\n \003(\003B\002\020\001\022\024\n\010bool_val\030\013 \003(\010B\002\020\001\022\030\n\014dco"
+    "mplex_val\030\014 \003(\001B\002\020\001B-\n\030org.tensorflow.fr"
+    "ameworkB\014TensorProtosP\001\370\001\001b\006proto3", 474);
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedFile(
+    "tensor.proto", &protobuf_RegisterTypes);
+  ::tensorflow::protobuf_AddDesc_tensor_5fshape_2eproto();
+  ::tensorflow::protobuf_AddDesc_types_2eproto();
+  ::google::protobuf::internal::OnShutdown(&protobuf_ShutdownFile_tensor_2eproto);
+}
+
+GOOGLE_PROTOBUF_DECLARE_ONCE(protobuf_AddDesc_tensor_2eproto_once_);
+void protobuf_AddDesc_tensor_2eproto() {
+  ::google::protobuf::GoogleOnceInit(&protobuf_AddDesc_tensor_2eproto_once_,
+                 &protobuf_AddDesc_tensor_2eproto_impl);
+}
+// Force AddDescriptors() to be called at static initialization time.
+struct StaticDescriptorInitializer_tensor_2eproto {
+  StaticDescriptorInitializer_tensor_2eproto() {
+    protobuf_AddDesc_tensor_2eproto();
+  }
+} static_descriptor_initializer_tensor_2eproto_;
+
+namespace {
+
+static void MergeFromFail(int line) GOOGLE_ATTRIBUTE_COLD GOOGLE_ATTRIBUTE_NORETURN;
+static void MergeFromFail(int line) {
+  ::google::protobuf::internal::MergeFromFail(__FILE__, line);
+}
+
+}  // namespace
+
+
+// ===================================================================
+
+void TensorProto::_slow_mutable_tensor_shape() {
+  tensor_shape_ = ::google::protobuf::Arena::CreateMessage< ::tensorflow::TensorShapeProto >(
+      GetArenaNoVirtual());
+}
+::tensorflow::TensorShapeProto* TensorProto::_slow_release_tensor_shape() {
+  if (tensor_shape_ == NULL) {
+    return NULL;
+  } else {
+    ::tensorflow::TensorShapeProto* temp = new ::tensorflow::TensorShapeProto(*tensor_shape_);
+    tensor_shape_ = NULL;
+    return temp;
+  }
+}
+::tensorflow::TensorShapeProto* TensorProto::unsafe_arena_release_tensor_shape() {
+  // @@protoc_insertion_point(field_unsafe_arena_release:tensorflow.TensorProto.tensor_shape)
+
+  ::tensorflow::TensorShapeProto* temp = tensor_shape_;
+  tensor_shape_ = NULL;
+  return temp;
+}
+void TensorProto::_slow_set_allocated_tensor_shape(
+    ::google::protobuf::Arena* message_arena, ::tensorflow::TensorShapeProto** tensor_shape) {
+    if (message_arena != NULL &&
+        ::google::protobuf::Arena::GetArena(*tensor_shape) == NULL) {
+      message_arena->Own(*tensor_shape);
+    } else if (message_arena !=
+               ::google::protobuf::Arena::GetArena(*tensor_shape)) {
+      ::tensorflow::TensorShapeProto* new_tensor_shape =
+            ::google::protobuf::Arena::CreateMessage< ::tensorflow::TensorShapeProto >(
+            message_arena);
+      new_tensor_shape->CopyFrom(**tensor_shape);
+      *tensor_shape = new_tensor_shape;
+    }
+}
+void TensorProto::unsafe_arena_set_allocated_tensor_shape(
+    ::tensorflow::TensorShapeProto* tensor_shape) {
+  if (GetArenaNoVirtual() == NULL) {
+    delete tensor_shape_;
+  }
+  tensor_shape_ = tensor_shape;
+  if (tensor_shape) {
+
+  } else {
+
+  }
+  // @@protoc_insertion_point(field_unsafe_arena_set_allocated:tensorflow.TensorProto.tensor_shape)
+}
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const int TensorProto::kDtypeFieldNumber;
+const int TensorProto::kTensorShapeFieldNumber;
+const int TensorProto::kVersionNumberFieldNumber;
+const int TensorProto::kTensorContentFieldNumber;
+const int TensorProto::kHalfValFieldNumber;
+const int TensorProto::kFloatValFieldNumber;
+const int TensorProto::kDoubleValFieldNumber;
+const int TensorProto::kIntValFieldNumber;
+const int TensorProto::kStringValFieldNumber;
+const int TensorProto::kScomplexValFieldNumber;
+const int TensorProto::kInt64ValFieldNumber;
+const int TensorProto::kBoolValFieldNumber;
+const int TensorProto::kDcomplexValFieldNumber;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+
+TensorProto::TensorProto()
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+  if (this != internal_default_instance()) protobuf_InitDefaults_tensor_2eproto();
+  SharedCtor();
+  // @@protoc_insertion_point(constructor:tensorflow.TensorProto)
+}
+TensorProto::TensorProto(::google::protobuf::Arena* arena)
+  : ::google::protobuf::Message(),
+  _internal_metadata_(arena),
+  half_val_(arena),
+  float_val_(arena),
+  double_val_(arena),
+  int_val_(arena),
+  string_val_(arena),
+  scomplex_val_(arena),
+  int64_val_(arena),
+  bool_val_(arena),
+  dcomplex_val_(arena) {
+#ifdef GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER
+  protobuf_InitDefaults_tensor_2eproto();
+#endif  // GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER
+  SharedCtor();
+  RegisterArenaDtor(arena);
+  // @@protoc_insertion_point(arena_constructor:tensorflow.TensorProto)
+}
+
+void TensorProto::InitAsDefaultInstance() {
+  tensor_shape_ = const_cast< ::tensorflow::TensorShapeProto*>(
+      ::tensorflow::TensorShapeProto::internal_default_instance());
+}
+
+TensorProto::TensorProto(const TensorProto& from)
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
+  SharedCtor();
+  UnsafeMergeFrom(from);
+  // @@protoc_insertion_point(copy_constructor:tensorflow.TensorProto)
+}
+
+void TensorProto::SharedCtor() {
+  tensor_content_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  tensor_shape_ = NULL;
+  ::memset(&dtype_, 0, reinterpret_cast<char*>(&version_number_) -
+    reinterpret_cast<char*>(&dtype_) + sizeof(version_number_));
+  _cached_size_ = 0;
+}
+
+TensorProto::~TensorProto() {
+  // @@protoc_insertion_point(destructor:tensorflow.TensorProto)
+  SharedDtor();
+}
+
+void TensorProto::SharedDtor() {
+  ::google::protobuf::Arena* arena = GetArenaNoVirtual();
+  if (arena != NULL) {
+    return;
+  }
+
+  tensor_content_.Destroy(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), arena);
+  if (this != &TensorProto_default_instance_.get()) {
+    delete tensor_shape_;
+  }
+}
+
+void TensorProto::ArenaDtor(void* object) {
+  TensorProto* _this = reinterpret_cast< TensorProto* >(object);
+  (void)_this;
+}
+void TensorProto::RegisterArenaDtor(::google::protobuf::Arena* arena) {
+}
+void TensorProto::SetCachedSize(int size) const {
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* TensorProto::descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return TensorProto_descriptor_;
+}
+
+const TensorProto& TensorProto::default_instance() {
+  protobuf_InitDefaults_tensor_2eproto();
+  return *internal_default_instance();
+}
+
+::google::protobuf::internal::ExplicitlyConstructed<TensorProto> TensorProto_default_instance_;
+
+TensorProto* TensorProto::New(::google::protobuf::Arena* arena) const {
+  return ::google::protobuf::Arena::CreateMessage<TensorProto>(arena);
+}
+
+void TensorProto::Clear() {
+// @@protoc_insertion_point(message_clear_start:tensorflow.TensorProto)
+#if defined(__clang__)
+#define ZR_HELPER_(f) \
+  _Pragma("clang diagnostic push") \
+  _Pragma("clang diagnostic ignored \"-Winvalid-offsetof\"") \
+  __builtin_offsetof(TensorProto, f) \
+  _Pragma("clang diagnostic pop")
+#else
+#define ZR_HELPER_(f) reinterpret_cast<char*>(\
+  &reinterpret_cast<TensorProto*>(16)->f)
+#endif
+
+#define ZR_(first, last) do {\
+  ::memset(&(first), 0,\
+           ZR_HELPER_(last) - ZR_HELPER_(first) + sizeof(last));\
+} while (0)
+
+  ZR_(dtype_, version_number_);
+  if (GetArenaNoVirtual() == NULL && tensor_shape_ != NULL) delete tensor_shape_;
+  tensor_shape_ = NULL;
+  tensor_content_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+
+#undef ZR_HELPER_
+#undef ZR_
+
+  half_val_.Clear();
+  float_val_.Clear();
+  double_val_.Clear();
+  int_val_.Clear();
+  string_val_.Clear();
+  scomplex_val_.Clear();
+  int64_val_.Clear();
+  bool_val_.Clear();
+  dcomplex_val_.Clear();
+}
+
+bool TensorProto::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
+  ::google::protobuf::uint32 tag;
+  // @@protoc_insertion_point(parse_start:tensorflow.TensorProto)
+  for (;;) {
+    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+    tag = p.first;
+    if (!p.second) goto handle_unusual;
+    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+      // optional .tensorflow.DataType dtype = 1;
+      case 1: {
+        if (tag == 8) {
+          int value;
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>(
+                 input, &value)));
+          set_dtype(static_cast< ::tensorflow::DataType >(value));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(18)) goto parse_tensor_shape;
+        break;
+      }
+
+      // optional .tensorflow.TensorShapeProto tensor_shape = 2;
+      case 2: {
+        if (tag == 18) {
+         parse_tensor_shape:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+               input, mutable_tensor_shape()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(24)) goto parse_version_number;
+        break;
+      }
+
+      // optional int32 version_number = 3;
+      case 3: {
+        if (tag == 24) {
+         parse_version_number:
+
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
+                 input, &version_number_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(34)) goto parse_tensor_content;
+        break;
+      }
+
+      // optional bytes tensor_content = 4;
+      case 4: {
+        if (tag == 34) {
+         parse_tensor_content:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadBytes(
+                input, this->mutable_tensor_content()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(42)) goto parse_float_val;
+        break;
+      }
+
+      // repeated float float_val = 5 [packed = true];
+      case 5: {
+        if (tag == 42) {
+         parse_float_val:
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPackedPrimitive<
+                   float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
+                 input, this->mutable_float_val())));
+        } else if (tag == 45) {
+          DO_((::google::protobuf::internal::WireFormatLite::ReadRepeatedPrimitiveNoInline<
+                   float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
+                 1, 42, input, this->mutable_float_val())));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(50)) goto parse_double_val;
+        break;
+      }
+
+      // repeated double double_val = 6 [packed = true];
+      case 6: {
+        if (tag == 50) {
+         parse_double_val:
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPackedPrimitive<
+                   double, ::google::protobuf::internal::WireFormatLite::TYPE_DOUBLE>(
+                 input, this->mutable_double_val())));
+        } else if (tag == 49) {
+          DO_((::google::protobuf::internal::WireFormatLite::ReadRepeatedPrimitiveNoInline<
+                   double, ::google::protobuf::internal::WireFormatLite::TYPE_DOUBLE>(
+                 1, 50, input, this->mutable_double_val())));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(58)) goto parse_int_val;
+        break;
+      }
+
+      // repeated int32 int_val = 7 [packed = true];
+      case 7: {
+        if (tag == 58) {
+         parse_int_val:
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPackedPrimitive<
+                   ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
+                 input, this->mutable_int_val())));
+        } else if (tag == 56) {
+          DO_((::google::protobuf::internal::WireFormatLite::ReadRepeatedPrimitiveNoInline<
+                   ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
+                 1, 58, input, this->mutable_int_val())));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(66)) goto parse_string_val;
+        break;
+      }
+
+      // repeated bytes string_val = 8;
+      case 8: {
+        if (tag == 66) {
+         parse_string_val:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadBytes(
+                input, this->add_string_val()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(66)) goto parse_string_val;
+        if (input->ExpectTag(74)) goto parse_scomplex_val;
+        break;
+      }
+
+      // repeated float scomplex_val = 9 [packed = true];
+      case 9: {
+        if (tag == 74) {
+         parse_scomplex_val:
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPackedPrimitive<
+                   float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
+                 input, this->mutable_scomplex_val())));
+        } else if (tag == 77) {
+          DO_((::google::protobuf::internal::WireFormatLite::ReadRepeatedPrimitiveNoInline<
+                   float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
+                 1, 74, input, this->mutable_scomplex_val())));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(82)) goto parse_int64_val;
+        break;
+      }
+
+      // repeated int64 int64_val = 10 [packed = true];
+      case 10: {
+        if (tag == 82) {
+         parse_int64_val:
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPackedPrimitive<
+                   ::google::protobuf::int64, ::google::protobuf::internal::WireFormatLite::TYPE_INT64>(
+                 input, this->mutable_int64_val())));
+        } else if (tag == 80) {
+          DO_((::google::protobuf::internal::WireFormatLite::ReadRepeatedPrimitiveNoInline<
+                   ::google::protobuf::int64, ::google::protobuf::internal::WireFormatLite::TYPE_INT64>(
+                 1, 82, input, this->mutable_int64_val())));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(90)) goto parse_bool_val;
+        break;
+      }
+
+      // repeated bool bool_val = 11 [packed = true];
+      case 11: {
+        if (tag == 90) {
+         parse_bool_val:
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPackedPrimitive<
+                   bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>(
+                 input, this->mutable_bool_val())));
+        } else if (tag == 88) {
+          DO_((::google::protobuf::internal::WireFormatLite::ReadRepeatedPrimitiveNoInline<
+                   bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>(
+                 1, 90, input, this->mutable_bool_val())));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(98)) goto parse_dcomplex_val;
+        break;
+      }
+
+      // repeated double dcomplex_val = 12 [packed = true];
+      case 12: {
+        if (tag == 98) {
+         parse_dcomplex_val:
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPackedPrimitive<
+                   double, ::google::protobuf::internal::WireFormatLite::TYPE_DOUBLE>(
+                 input, this->mutable_dcomplex_val())));
+        } else if (tag == 97) {
+          DO_((::google::protobuf::internal::WireFormatLite::ReadRepeatedPrimitiveNoInline<
+                   double, ::google::protobuf::internal::WireFormatLite::TYPE_DOUBLE>(
+                 1, 98, input, this->mutable_dcomplex_val())));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(106)) goto parse_half_val;
+        break;
+      }
+
+      // repeated int32 half_val = 13 [packed = true];
+      case 13: {
+        if (tag == 106) {
+         parse_half_val:
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPackedPrimitive<
+                   ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
+                 input, this->mutable_half_val())));
+        } else if (tag == 104) {
+          DO_((::google::protobuf::internal::WireFormatLite::ReadRepeatedPrimitiveNoInline<
+                   ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
+                 1, 106, input, this->mutable_half_val())));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectAtEnd()) goto success;
+        break;
+      }
+
+      default: {
+      handle_unusual:
+        if (tag == 0 ||
+            ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+          goto success;
+        }
+        DO_(::google::protobuf::internal::WireFormatLite::SkipField(input, tag));
+        break;
+      }
+    }
+  }
+success:
+  // @@protoc_insertion_point(parse_success:tensorflow.TensorProto)
+  return true;
+failure:
+  // @@protoc_insertion_point(parse_failure:tensorflow.TensorProto)
+  return false;
+#undef DO_
+}
+
+void TensorProto::SerializeWithCachedSizes(
+    ::google::protobuf::io::CodedOutputStream* output) const {
+  // @@protoc_insertion_point(serialize_start:tensorflow.TensorProto)
+  // optional .tensorflow.DataType dtype = 1;
+  if (this->dtype() != 0) {
+    ::google::protobuf::internal::WireFormatLite::WriteEnum(
+      1, this->dtype(), output);
+  }
+
+  // optional .tensorflow.TensorShapeProto tensor_shape = 2;
+  if (this->has_tensor_shape()) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      2, *this->tensor_shape_, output);
+  }
+
+  // optional int32 version_number = 3;
+  if (this->version_number() != 0) {
+    ::google::protobuf::internal::WireFormatLite::WriteInt32(3, this->version_number(), output);
+  }
+
+  // optional bytes tensor_content = 4;
+  if (this->tensor_content().size() > 0) {
+    ::google::protobuf::internal::WireFormatLite::WriteBytesMaybeAliased(
+      4, this->tensor_content(), output);
+  }
+
+  // repeated float float_val = 5 [packed = true];
+  if (this->float_val_size() > 0) {
+    ::google::protobuf::internal::WireFormatLite::WriteTag(5, ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED, output);
+    output->WriteVarint32(_float_val_cached_byte_size_);
+  }
+  for (int i = 0; i < this->float_val_size(); i++) {
+    ::google::protobuf::internal::WireFormatLite::WriteFloatNoTag(
+      this->float_val(i), output);
+  }
+
+  // repeated double double_val = 6 [packed = true];
+  if (this->double_val_size() > 0) {
+    ::google::protobuf::internal::WireFormatLite::WriteTag(6, ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED, output);
+    output->WriteVarint32(_double_val_cached_byte_size_);
+  }
+  for (int i = 0; i < this->double_val_size(); i++) {
+    ::google::protobuf::internal::WireFormatLite::WriteDoubleNoTag(
+      this->double_val(i), output);
+  }
+
+  // repeated int32 int_val = 7 [packed = true];
+  if (this->int_val_size() > 0) {
+    ::google::protobuf::internal::WireFormatLite::WriteTag(7, ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED, output);
+    output->WriteVarint32(_int_val_cached_byte_size_);
+  }
+  for (int i = 0; i < this->int_val_size(); i++) {
+    ::google::protobuf::internal::WireFormatLite::WriteInt32NoTag(
+      this->int_val(i), output);
+  }
+
+  // repeated bytes string_val = 8;
+  for (int i = 0; i < this->string_val_size(); i++) {
+    ::google::protobuf::internal::WireFormatLite::WriteBytes(
+      8, this->string_val(i), output);
+  }
+
+  // repeated float scomplex_val = 9 [packed = true];
+  if (this->scomplex_val_size() > 0) {
+    ::google::protobuf::internal::WireFormatLite::WriteTag(9, ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED, output);
+    output->WriteVarint32(_scomplex_val_cached_byte_size_);
+  }
+  for (int i = 0; i < this->scomplex_val_size(); i++) {
+    ::google::protobuf::internal::WireFormatLite::WriteFloatNoTag(
+      this->scomplex_val(i), output);
+  }
+
+  // repeated int64 int64_val = 10 [packed = true];
+  if (this->int64_val_size() > 0) {
+    ::google::protobuf::internal::WireFormatLite::WriteTag(10, ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED, output);
+    output->WriteVarint32(_int64_val_cached_byte_size_);
+  }
+  for (int i = 0; i < this->int64_val_size(); i++) {
+    ::google::protobuf::internal::WireFormatLite::WriteInt64NoTag(
+      this->int64_val(i), output);
+  }
+
+  // repeated bool bool_val = 11 [packed = true];
+  if (this->bool_val_size() > 0) {
+    ::google::protobuf::internal::WireFormatLite::WriteTag(11, ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED, output);
+    output->WriteVarint32(_bool_val_cached_byte_size_);
+  }
+  for (int i = 0; i < this->bool_val_size(); i++) {
+    ::google::protobuf::internal::WireFormatLite::WriteBoolNoTag(
+      this->bool_val(i), output);
+  }
+
+  // repeated double dcomplex_val = 12 [packed = true];
+  if (this->dcomplex_val_size() > 0) {
+    ::google::protobuf::internal::WireFormatLite::WriteTag(12, ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED, output);
+    output->WriteVarint32(_dcomplex_val_cached_byte_size_);
+  }
+  for (int i = 0; i < this->dcomplex_val_size(); i++) {
+    ::google::protobuf::internal::WireFormatLite::WriteDoubleNoTag(
+      this->dcomplex_val(i), output);
+  }
+
+  // repeated int32 half_val = 13 [packed = true];
+  if (this->half_val_size() > 0) {
+    ::google::protobuf::internal::WireFormatLite::WriteTag(13, ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED, output);
+    output->WriteVarint32(_half_val_cached_byte_size_);
+  }
+  for (int i = 0; i < this->half_val_size(); i++) {
+    ::google::protobuf::internal::WireFormatLite::WriteInt32NoTag(
+      this->half_val(i), output);
+  }
+
+  // @@protoc_insertion_point(serialize_end:tensorflow.TensorProto)
+}
+
+::google::protobuf::uint8* TensorProto::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
+  (void)deterministic; // Unused
+  // @@protoc_insertion_point(serialize_to_array_start:tensorflow.TensorProto)
+  // optional .tensorflow.DataType dtype = 1;
+  if (this->dtype() != 0) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteEnumToArray(
+      1, this->dtype(), target);
+  }
+
+  // optional .tensorflow.TensorShapeProto tensor_shape = 2;
+  if (this->has_tensor_shape()) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        2, *this->tensor_shape_, false, target);
+  }
+
+  // optional int32 version_number = 3;
+  if (this->version_number() != 0) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteInt32ToArray(3, this->version_number(), target);
+  }
+
+  // optional bytes tensor_content = 4;
+  if (this->tensor_content().size() > 0) {
+    target =
+      ::google::protobuf::internal::WireFormatLite::WriteBytesToArray(
+        4, this->tensor_content(), target);
+  }
+
+  // repeated float float_val = 5 [packed = true];
+  if (this->float_val_size() > 0) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteTagToArray(
+      5,
+      ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED,
+      target);
+    target = ::google::protobuf::io::CodedOutputStream::WriteVarint32ToArray(
+      _float_val_cached_byte_size_, target);
+  }
+  for (int i = 0; i < this->float_val_size(); i++) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      WriteFloatNoTagToArray(this->float_val(i), target);
+  }
+
+  // repeated double double_val = 6 [packed = true];
+  if (this->double_val_size() > 0) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteTagToArray(
+      6,
+      ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED,
+      target);
+    target = ::google::protobuf::io::CodedOutputStream::WriteVarint32ToArray(
+      _double_val_cached_byte_size_, target);
+  }
+  for (int i = 0; i < this->double_val_size(); i++) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      WriteDoubleNoTagToArray(this->double_val(i), target);
+  }
+
+  // repeated int32 int_val = 7 [packed = true];
+  if (this->int_val_size() > 0) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteTagToArray(
+      7,
+      ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED,
+      target);
+    target = ::google::protobuf::io::CodedOutputStream::WriteVarint32ToArray(
+      _int_val_cached_byte_size_, target);
+  }
+  for (int i = 0; i < this->int_val_size(); i++) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      WriteInt32NoTagToArray(this->int_val(i), target);
+  }
+
+  // repeated bytes string_val = 8;
+  for (int i = 0; i < this->string_val_size(); i++) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      WriteBytesToArray(8, this->string_val(i), target);
+  }
+
+  // repeated float scomplex_val = 9 [packed = true];
+  if (this->scomplex_val_size() > 0) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteTagToArray(
+      9,
+      ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED,
+      target);
+    target = ::google::protobuf::io::CodedOutputStream::WriteVarint32ToArray(
+      _scomplex_val_cached_byte_size_, target);
+  }
+  for (int i = 0; i < this->scomplex_val_size(); i++) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      WriteFloatNoTagToArray(this->scomplex_val(i), target);
+  }
+
+  // repeated int64 int64_val = 10 [packed = true];
+  if (this->int64_val_size() > 0) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteTagToArray(
+      10,
+      ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED,
+      target);
+    target = ::google::protobuf::io::CodedOutputStream::WriteVarint32ToArray(
+      _int64_val_cached_byte_size_, target);
+  }
+  for (int i = 0; i < this->int64_val_size(); i++) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      WriteInt64NoTagToArray(this->int64_val(i), target);
+  }
+
+  // repeated bool bool_val = 11 [packed = true];
+  if (this->bool_val_size() > 0) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteTagToArray(
+      11,
+      ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED,
+      target);
+    target = ::google::protobuf::io::CodedOutputStream::WriteVarint32ToArray(
+      _bool_val_cached_byte_size_, target);
+  }
+  for (int i = 0; i < this->bool_val_size(); i++) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      WriteBoolNoTagToArray(this->bool_val(i), target);
+  }
+
+  // repeated double dcomplex_val = 12 [packed = true];
+  if (this->dcomplex_val_size() > 0) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteTagToArray(
+      12,
+      ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED,
+      target);
+    target = ::google::protobuf::io::CodedOutputStream::WriteVarint32ToArray(
+      _dcomplex_val_cached_byte_size_, target);
+  }
+  for (int i = 0; i < this->dcomplex_val_size(); i++) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      WriteDoubleNoTagToArray(this->dcomplex_val(i), target);
+  }
+
+  // repeated int32 half_val = 13 [packed = true];
+  if (this->half_val_size() > 0) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteTagToArray(
+      13,
+      ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED,
+      target);
+    target = ::google::protobuf::io::CodedOutputStream::WriteVarint32ToArray(
+      _half_val_cached_byte_size_, target);
+  }
+  for (int i = 0; i < this->half_val_size(); i++) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      WriteInt32NoTagToArray(this->half_val(i), target);
+  }
+
+  // @@protoc_insertion_point(serialize_to_array_end:tensorflow.TensorProto)
+  return target;
+}
+
+size_t TensorProto::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:tensorflow.TensorProto)
+  size_t total_size = 0;
+
+  // optional .tensorflow.DataType dtype = 1;
+  if (this->dtype() != 0) {
+    total_size += 1 +
+      ::google::protobuf::internal::WireFormatLite::EnumSize(this->dtype());
+  }
+
+  // optional .tensorflow.TensorShapeProto tensor_shape = 2;
+  if (this->has_tensor_shape()) {
+    total_size += 1 +
+      ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+        *this->tensor_shape_);
+  }
+
+  // optional int32 version_number = 3;
+  if (this->version_number() != 0) {
+    total_size += 1 +
+      ::google::protobuf::internal::WireFormatLite::Int32Size(
+        this->version_number());
+  }
+
+  // optional bytes tensor_content = 4;
+  if (this->tensor_content().size() > 0) {
+    total_size += 1 +
+      ::google::protobuf::internal::WireFormatLite::BytesSize(
+        this->tensor_content());
+  }
+
+  // repeated int32 half_val = 13 [packed = true];
+  {
+    size_t data_size = 0;
+    unsigned int count = this->half_val_size();
+    for (unsigned int i = 0; i < count; i++) {
+      data_size += ::google::protobuf::internal::WireFormatLite::
+        Int32Size(this->half_val(i));
+    }
+    if (data_size > 0) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::Int32Size(data_size);
+    }
+    int cached_size = ::google::protobuf::internal::ToCachedSize(data_size);
+    GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+    _half_val_cached_byte_size_ = cached_size;
+    GOOGLE_SAFE_CONCURRENT_WRITES_END();
+    total_size += data_size;
+  }
+
+  // repeated float float_val = 5 [packed = true];
+  {
+    size_t data_size = 0;
+    unsigned int count = this->float_val_size();
+    data_size = 4UL * count;
+    if (data_size > 0) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::Int32Size(data_size);
+    }
+    int cached_size = ::google::protobuf::internal::ToCachedSize(data_size);
+    GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+    _float_val_cached_byte_size_ = cached_size;
+    GOOGLE_SAFE_CONCURRENT_WRITES_END();
+    total_size += data_size;
+  }
+
+  // repeated double double_val = 6 [packed = true];
+  {
+    size_t data_size = 0;
+    unsigned int count = this->double_val_size();
+    data_size = 8UL * count;
+    if (data_size > 0) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::Int32Size(data_size);
+    }
+    int cached_size = ::google::protobuf::internal::ToCachedSize(data_size);
+    GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+    _double_val_cached_byte_size_ = cached_size;
+    GOOGLE_SAFE_CONCURRENT_WRITES_END();
+    total_size += data_size;
+  }
+
+  // repeated int32 int_val = 7 [packed = true];
+  {
+    size_t data_size = 0;
+    unsigned int count = this->int_val_size();
+    for (unsigned int i = 0; i < count; i++) {
+      data_size += ::google::protobuf::internal::WireFormatLite::
+        Int32Size(this->int_val(i));
+    }
+    if (data_size > 0) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::Int32Size(data_size);
+    }
+    int cached_size = ::google::protobuf::internal::ToCachedSize(data_size);
+    GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+    _int_val_cached_byte_size_ = cached_size;
+    GOOGLE_SAFE_CONCURRENT_WRITES_END();
+    total_size += data_size;
+  }
+
+  // repeated bytes string_val = 8;
+  total_size += 1 *
+      ::google::protobuf::internal::FromIntSize(this->string_val_size());
+  for (int i = 0; i < this->string_val_size(); i++) {
+    total_size += ::google::protobuf::internal::WireFormatLite::BytesSize(
+      this->string_val(i));
+  }
+
+  // repeated float scomplex_val = 9 [packed = true];
+  {
+    size_t data_size = 0;
+    unsigned int count = this->scomplex_val_size();
+    data_size = 4UL * count;
+    if (data_size > 0) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::Int32Size(data_size);
+    }
+    int cached_size = ::google::protobuf::internal::ToCachedSize(data_size);
+    GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+    _scomplex_val_cached_byte_size_ = cached_size;
+    GOOGLE_SAFE_CONCURRENT_WRITES_END();
+    total_size += data_size;
+  }
+
+  // repeated int64 int64_val = 10 [packed = true];
+  {
+    size_t data_size = 0;
+    unsigned int count = this->int64_val_size();
+    for (unsigned int i = 0; i < count; i++) {
+      data_size += ::google::protobuf::internal::WireFormatLite::
+        Int64Size(this->int64_val(i));
+    }
+    if (data_size > 0) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::Int32Size(data_size);
+    }
+    int cached_size = ::google::protobuf::internal::ToCachedSize(data_size);
+    GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+    _int64_val_cached_byte_size_ = cached_size;
+    GOOGLE_SAFE_CONCURRENT_WRITES_END();
+    total_size += data_size;
+  }
+
+  // repeated bool bool_val = 11 [packed = true];
+  {
+    size_t data_size = 0;
+    unsigned int count = this->bool_val_size();
+    data_size = 1UL * count;
+    if (data_size > 0) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::Int32Size(data_size);
+    }
+    int cached_size = ::google::protobuf::internal::ToCachedSize(data_size);
+    GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+    _bool_val_cached_byte_size_ = cached_size;
+    GOOGLE_SAFE_CONCURRENT_WRITES_END();
+    total_size += data_size;
+  }
+
+  // repeated double dcomplex_val = 12 [packed = true];
+  {
+    size_t data_size = 0;
+    unsigned int count = this->dcomplex_val_size();
+    data_size = 8UL * count;
+    if (data_size > 0) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::Int32Size(data_size);
+    }
+    int cached_size = ::google::protobuf::internal::ToCachedSize(data_size);
+    GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+    _dcomplex_val_cached_byte_size_ = cached_size;
+    GOOGLE_SAFE_CONCURRENT_WRITES_END();
+    total_size += data_size;
+  }
+
+  int cached_size = ::google::protobuf::internal::ToCachedSize(total_size);
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = cached_size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+  return total_size;
+}
+
+void TensorProto::MergeFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_merge_from_start:tensorflow.TensorProto)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const TensorProto* source =
+      ::google::protobuf::internal::DynamicCastToGenerated<const TensorProto>(
+          &from);
+  if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:tensorflow.TensorProto)
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:tensorflow.TensorProto)
+    UnsafeMergeFrom(*source);
+  }
+}
+
+void TensorProto::MergeFrom(const TensorProto& from) {
+// @@protoc_insertion_point(class_specific_merge_from_start:tensorflow.TensorProto)
+  if (GOOGLE_PREDICT_TRUE(&from != this)) {
+    UnsafeMergeFrom(from);
+  } else {
+    MergeFromFail(__LINE__);
+  }
+}
+
+void TensorProto::UnsafeMergeFrom(const TensorProto& from) {
+  GOOGLE_DCHECK(&from != this);
+  half_val_.UnsafeMergeFrom(from.half_val_);
+  float_val_.UnsafeMergeFrom(from.float_val_);
+  double_val_.UnsafeMergeFrom(from.double_val_);
+  int_val_.UnsafeMergeFrom(from.int_val_);
+  string_val_.UnsafeMergeFrom(from.string_val_);
+  scomplex_val_.UnsafeMergeFrom(from.scomplex_val_);
+  int64_val_.UnsafeMergeFrom(from.int64_val_);
+  bool_val_.UnsafeMergeFrom(from.bool_val_);
+  dcomplex_val_.UnsafeMergeFrom(from.dcomplex_val_);
+  if (from.dtype() != 0) {
+    set_dtype(from.dtype());
+  }
+  if (from.has_tensor_shape()) {
+    mutable_tensor_shape()->::tensorflow::TensorShapeProto::MergeFrom(from.tensor_shape());
+  }
+  if (from.version_number() != 0) {
+    set_version_number(from.version_number());
+  }
+  if (from.tensor_content().size() > 0) {
+    set_tensor_content(from.tensor_content());
+  }
+}
+
+void TensorProto::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:tensorflow.TensorProto)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void TensorProto::CopyFrom(const TensorProto& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:tensorflow.TensorProto)
+  if (&from == this) return;
+  Clear();
+  UnsafeMergeFrom(from);
+}
+
+bool TensorProto::IsInitialized() const {
+
+  return true;
+}
+
+void TensorProto::Swap(TensorProto* other) {
+  if (other == this) return;
+  if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) {
+    InternalSwap(other);
+  } else {
+    TensorProto temp;
+    temp.UnsafeMergeFrom(*this);
+    CopyFrom(*other);
+    other->CopyFrom(temp);
+  }
+}
+void TensorProto::UnsafeArenaSwap(TensorProto* other) {
+  if (other == this) return;
+  GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual());
+  InternalSwap(other);
+}
+void TensorProto::InternalSwap(TensorProto* other) {
+  std::swap(dtype_, other->dtype_);
+  std::swap(tensor_shape_, other->tensor_shape_);
+  std::swap(version_number_, other->version_number_);
+  tensor_content_.Swap(&other->tensor_content_);
+  half_val_.UnsafeArenaSwap(&other->half_val_);
+  float_val_.UnsafeArenaSwap(&other->float_val_);
+  double_val_.UnsafeArenaSwap(&other->double_val_);
+  int_val_.UnsafeArenaSwap(&other->int_val_);
+  string_val_.UnsafeArenaSwap(&other->string_val_);
+  scomplex_val_.UnsafeArenaSwap(&other->scomplex_val_);
+  int64_val_.UnsafeArenaSwap(&other->int64_val_);
+  bool_val_.UnsafeArenaSwap(&other->bool_val_);
+  dcomplex_val_.UnsafeArenaSwap(&other->dcomplex_val_);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
+}
+
+::google::protobuf::Metadata TensorProto::GetMetadata() const {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::Metadata metadata;
+  metadata.descriptor = TensorProto_descriptor_;
+  metadata.reflection = TensorProto_reflection_;
+  return metadata;
+}
+
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// TensorProto
+
+// optional .tensorflow.DataType dtype = 1;
+void TensorProto::clear_dtype() {
+  dtype_ = 0;
+}
+::tensorflow::DataType TensorProto::dtype() const {
+  // @@protoc_insertion_point(field_get:tensorflow.TensorProto.dtype)
+  return static_cast< ::tensorflow::DataType >(dtype_);
+}
+void TensorProto::set_dtype(::tensorflow::DataType value) {
+
+  dtype_ = value;
+  // @@protoc_insertion_point(field_set:tensorflow.TensorProto.dtype)
+}
+
+// optional .tensorflow.TensorShapeProto tensor_shape = 2;
+bool TensorProto::has_tensor_shape() const {
+  return this != internal_default_instance() && tensor_shape_ != NULL;
+}
+void TensorProto::clear_tensor_shape() {
+  if (GetArenaNoVirtual() == NULL && tensor_shape_ != NULL) delete tensor_shape_;
+  tensor_shape_ = NULL;
+}
+const ::tensorflow::TensorShapeProto& TensorProto::tensor_shape() const {
+  // @@protoc_insertion_point(field_get:tensorflow.TensorProto.tensor_shape)
+  return tensor_shape_ != NULL ? *tensor_shape_
+                         : *::tensorflow::TensorShapeProto::internal_default_instance();
+}
+::tensorflow::TensorShapeProto* TensorProto::mutable_tensor_shape() {
+
+  if (tensor_shape_ == NULL) {
+    _slow_mutable_tensor_shape();
+  }
+  // @@protoc_insertion_point(field_mutable:tensorflow.TensorProto.tensor_shape)
+  return tensor_shape_;
+}
+::tensorflow::TensorShapeProto* TensorProto::release_tensor_shape() {
+  // @@protoc_insertion_point(field_release:tensorflow.TensorProto.tensor_shape)
+
+  if (GetArenaNoVirtual() != NULL) {
+    return _slow_release_tensor_shape();
+  } else {
+    ::tensorflow::TensorShapeProto* temp = tensor_shape_;
+    tensor_shape_ = NULL;
+    return temp;
+  }
+}
+ void TensorProto::set_allocated_tensor_shape(::tensorflow::TensorShapeProto* tensor_shape) {
+  ::google::protobuf::Arena* message_arena = GetArenaNoVirtual();
+  if (message_arena == NULL) {
+    delete tensor_shape_;
+  }
+  if (tensor_shape != NULL) {
+    _slow_set_allocated_tensor_shape(message_arena, &tensor_shape);
+  }
+  tensor_shape_ = tensor_shape;
+  if (tensor_shape) {
+
+  } else {
+
+  }
+  // @@protoc_insertion_point(field_set_allocated:tensorflow.TensorProto.tensor_shape)
+}
+
+// optional int32 version_number = 3;
+void TensorProto::clear_version_number() {
+  version_number_ = 0;
+}
+::google::protobuf::int32 TensorProto::version_number() const {
+  // @@protoc_insertion_point(field_get:tensorflow.TensorProto.version_number)
+  return version_number_;
+}
+void TensorProto::set_version_number(::google::protobuf::int32 value) {
+
+  version_number_ = value;
+  // @@protoc_insertion_point(field_set:tensorflow.TensorProto.version_number)
+}
+
+// optional bytes tensor_content = 4;
+void TensorProto::clear_tensor_content() {
+  tensor_content_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+const ::std::string& TensorProto::tensor_content() const {
+  // @@protoc_insertion_point(field_get:tensorflow.TensorProto.tensor_content)
+  return tensor_content_.Get(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+void TensorProto::set_tensor_content(const ::std::string& value) {
+
+  tensor_content_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value, GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set:tensorflow.TensorProto.tensor_content)
+}
+void TensorProto::set_tensor_content(const char* value) {
+
+  tensor_content_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value),
+              GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_char:tensorflow.TensorProto.tensor_content)
+}
+void TensorProto::set_tensor_content(const void* value,
+    size_t size) {
+
+  tensor_content_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(
+      reinterpret_cast<const char*>(value), size), GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_pointer:tensorflow.TensorProto.tensor_content)
+}
+::std::string* TensorProto::mutable_tensor_content() {
+
+  // @@protoc_insertion_point(field_mutable:tensorflow.TensorProto.tensor_content)
+  return tensor_content_.Mutable(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+::std::string* TensorProto::release_tensor_content() {
+  // @@protoc_insertion_point(field_release:tensorflow.TensorProto.tensor_content)
+
+  return tensor_content_.Release(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+::std::string* TensorProto::unsafe_arena_release_tensor_content() {
+  // @@protoc_insertion_point(field_unsafe_arena_release:tensorflow.TensorProto.tensor_content)
+  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);
+
+  return tensor_content_.UnsafeArenaRelease(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      GetArenaNoVirtual());
+}
+void TensorProto::set_allocated_tensor_content(::std::string* tensor_content) {
+  if (tensor_content != NULL) {
+
+  } else {
+
+  }
+  tensor_content_.SetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), tensor_content,
+      GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_allocated:tensorflow.TensorProto.tensor_content)
+}
+void TensorProto::unsafe_arena_set_allocated_tensor_content(
+    ::std::string* tensor_content) {
+  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);
+  if (tensor_content != NULL) {
+
+  } else {
+
+  }
+  tensor_content_.UnsafeArenaSetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      tensor_content, GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_unsafe_arena_set_allocated:tensorflow.TensorProto.tensor_content)
+}
+
+// repeated int32 half_val = 13 [packed = true];
+int TensorProto::half_val_size() const {
+  return half_val_.size();
+}
+void TensorProto::clear_half_val() {
+  half_val_.Clear();
+}
+::google::protobuf::int32 TensorProto::half_val(int index) const {
+  // @@protoc_insertion_point(field_get:tensorflow.TensorProto.half_val)
+  return half_val_.Get(index);
+}
+void TensorProto::set_half_val(int index, ::google::protobuf::int32 value) {
+  half_val_.Set(index, value);
+  // @@protoc_insertion_point(field_set:tensorflow.TensorProto.half_val)
+}
+void TensorProto::add_half_val(::google::protobuf::int32 value) {
+  half_val_.Add(value);
+  // @@protoc_insertion_point(field_add:tensorflow.TensorProto.half_val)
+}
+const ::google::protobuf::RepeatedField< ::google::protobuf::int32 >&
+TensorProto::half_val() const {
+  // @@protoc_insertion_point(field_list:tensorflow.TensorProto.half_val)
+  return half_val_;
+}
+::google::protobuf::RepeatedField< ::google::protobuf::int32 >*
+TensorProto::mutable_half_val() {
+  // @@protoc_insertion_point(field_mutable_list:tensorflow.TensorProto.half_val)
+  return &half_val_;
+}
+
+// repeated float float_val = 5 [packed = true];
+int TensorProto::float_val_size() const {
+  return float_val_.size();
+}
+void TensorProto::clear_float_val() {
+  float_val_.Clear();
+}
+float TensorProto::float_val(int index) const {
+  // @@protoc_insertion_point(field_get:tensorflow.TensorProto.float_val)
+  return float_val_.Get(index);
+}
+void TensorProto::set_float_val(int index, float value) {
+  float_val_.Set(index, value);
+  // @@protoc_insertion_point(field_set:tensorflow.TensorProto.float_val)
+}
+void TensorProto::add_float_val(float value) {
+  float_val_.Add(value);
+  // @@protoc_insertion_point(field_add:tensorflow.TensorProto.float_val)
+}
+const ::google::protobuf::RepeatedField< float >&
+TensorProto::float_val() const {
+  // @@protoc_insertion_point(field_list:tensorflow.TensorProto.float_val)
+  return float_val_;
+}
+::google::protobuf::RepeatedField< float >*
+TensorProto::mutable_float_val() {
+  // @@protoc_insertion_point(field_mutable_list:tensorflow.TensorProto.float_val)
+  return &float_val_;
+}
+
+// repeated double double_val = 6 [packed = true];
+int TensorProto::double_val_size() const {
+  return double_val_.size();
+}
+void TensorProto::clear_double_val() {
+  double_val_.Clear();
+}
+double TensorProto::double_val(int index) const {
+  // @@protoc_insertion_point(field_get:tensorflow.TensorProto.double_val)
+  return double_val_.Get(index);
+}
+void TensorProto::set_double_val(int index, double value) {
+  double_val_.Set(index, value);
+  // @@protoc_insertion_point(field_set:tensorflow.TensorProto.double_val)
+}
+void TensorProto::add_double_val(double value) {
+  double_val_.Add(value);
+  // @@protoc_insertion_point(field_add:tensorflow.TensorProto.double_val)
+}
+const ::google::protobuf::RepeatedField< double >&
+TensorProto::double_val() const {
+  // @@protoc_insertion_point(field_list:tensorflow.TensorProto.double_val)
+  return double_val_;
+}
+::google::protobuf::RepeatedField< double >*
+TensorProto::mutable_double_val() {
+  // @@protoc_insertion_point(field_mutable_list:tensorflow.TensorProto.double_val)
+  return &double_val_;
+}
+
+// repeated int32 int_val = 7 [packed = true];
+int TensorProto::int_val_size() const {
+  return int_val_.size();
+}
+void TensorProto::clear_int_val() {
+  int_val_.Clear();
+}
+::google::protobuf::int32 TensorProto::int_val(int index) const {
+  // @@protoc_insertion_point(field_get:tensorflow.TensorProto.int_val)
+  return int_val_.Get(index);
+}
+void TensorProto::set_int_val(int index, ::google::protobuf::int32 value) {
+  int_val_.Set(index, value);
+  // @@protoc_insertion_point(field_set:tensorflow.TensorProto.int_val)
+}
+void TensorProto::add_int_val(::google::protobuf::int32 value) {
+  int_val_.Add(value);
+  // @@protoc_insertion_point(field_add:tensorflow.TensorProto.int_val)
+}
+const ::google::protobuf::RepeatedField< ::google::protobuf::int32 >&
+TensorProto::int_val() const {
+  // @@protoc_insertion_point(field_list:tensorflow.TensorProto.int_val)
+  return int_val_;
+}
+::google::protobuf::RepeatedField< ::google::protobuf::int32 >*
+TensorProto::mutable_int_val() {
+  // @@protoc_insertion_point(field_mutable_list:tensorflow.TensorProto.int_val)
+  return &int_val_;
+}
+
+// repeated bytes string_val = 8;
+int TensorProto::string_val_size() const {
+  return string_val_.size();
+}
+void TensorProto::clear_string_val() {
+  string_val_.Clear();
+}
+const ::std::string& TensorProto::string_val(int index) const {
+  // @@protoc_insertion_point(field_get:tensorflow.TensorProto.string_val)
+  return string_val_.Get(index);
+}
+::std::string* TensorProto::mutable_string_val(int index) {
+  // @@protoc_insertion_point(field_mutable:tensorflow.TensorProto.string_val)
+  return string_val_.Mutable(index);
+}
+void TensorProto::set_string_val(int index, const ::std::string& value) {
+  // @@protoc_insertion_point(field_set:tensorflow.TensorProto.string_val)
+  string_val_.Mutable(index)->assign(value);
+}
+void TensorProto::set_string_val(int index, const char* value) {
+  string_val_.Mutable(index)->assign(value);
+  // @@protoc_insertion_point(field_set_char:tensorflow.TensorProto.string_val)
+}
+void TensorProto::set_string_val(int index, const void* value, size_t size) {
+  string_val_.Mutable(index)->assign(
+    reinterpret_cast<const char*>(value), size);
+  // @@protoc_insertion_point(field_set_pointer:tensorflow.TensorProto.string_val)
+}
+::std::string* TensorProto::add_string_val() {
+  // @@protoc_insertion_point(field_add_mutable:tensorflow.TensorProto.string_val)
+  return string_val_.Add();
+}
+void TensorProto::add_string_val(const ::std::string& value) {
+  string_val_.Add()->assign(value);
+  // @@protoc_insertion_point(field_add:tensorflow.TensorProto.string_val)
+}
+void TensorProto::add_string_val(const char* value) {
+  string_val_.Add()->assign(value);
+  // @@protoc_insertion_point(field_add_char:tensorflow.TensorProto.string_val)
+}
+void TensorProto::add_string_val(const void* value, size_t size) {
+  string_val_.Add()->assign(reinterpret_cast<const char*>(value), size);
+  // @@protoc_insertion_point(field_add_pointer:tensorflow.TensorProto.string_val)
+}
+const ::google::protobuf::RepeatedPtrField< ::std::string>&
+TensorProto::string_val() const {
+  // @@protoc_insertion_point(field_list:tensorflow.TensorProto.string_val)
+  return string_val_;
+}
+::google::protobuf::RepeatedPtrField< ::std::string>*
+TensorProto::mutable_string_val() {
+  // @@protoc_insertion_point(field_mutable_list:tensorflow.TensorProto.string_val)
+  return &string_val_;
+}
+
+// repeated float scomplex_val = 9 [packed = true];
+int TensorProto::scomplex_val_size() const {
+  return scomplex_val_.size();
+}
+void TensorProto::clear_scomplex_val() {
+  scomplex_val_.Clear();
+}
+float TensorProto::scomplex_val(int index) const {
+  // @@protoc_insertion_point(field_get:tensorflow.TensorProto.scomplex_val)
+  return scomplex_val_.Get(index);
+}
+void TensorProto::set_scomplex_val(int index, float value) {
+  scomplex_val_.Set(index, value);
+  // @@protoc_insertion_point(field_set:tensorflow.TensorProto.scomplex_val)
+}
+void TensorProto::add_scomplex_val(float value) {
+  scomplex_val_.Add(value);
+  // @@protoc_insertion_point(field_add:tensorflow.TensorProto.scomplex_val)
+}
+const ::google::protobuf::RepeatedField< float >&
+TensorProto::scomplex_val() const {
+  // @@protoc_insertion_point(field_list:tensorflow.TensorProto.scomplex_val)
+  return scomplex_val_;
+}
+::google::protobuf::RepeatedField< float >*
+TensorProto::mutable_scomplex_val() {
+  // @@protoc_insertion_point(field_mutable_list:tensorflow.TensorProto.scomplex_val)
+  return &scomplex_val_;
+}
+
+// repeated int64 int64_val = 10 [packed = true];
+int TensorProto::int64_val_size() const {
+  return int64_val_.size();
+}
+void TensorProto::clear_int64_val() {
+  int64_val_.Clear();
+}
+::google::protobuf::int64 TensorProto::int64_val(int index) const {
+  // @@protoc_insertion_point(field_get:tensorflow.TensorProto.int64_val)
+  return int64_val_.Get(index);
+}
+void TensorProto::set_int64_val(int index, ::google::protobuf::int64 value) {
+  int64_val_.Set(index, value);
+  // @@protoc_insertion_point(field_set:tensorflow.TensorProto.int64_val)
+}
+void TensorProto::add_int64_val(::google::protobuf::int64 value) {
+  int64_val_.Add(value);
+  // @@protoc_insertion_point(field_add:tensorflow.TensorProto.int64_val)
+}
+const ::google::protobuf::RepeatedField< ::google::protobuf::int64 >&
+TensorProto::int64_val() const {
+  // @@protoc_insertion_point(field_list:tensorflow.TensorProto.int64_val)
+  return int64_val_;
+}
+::google::protobuf::RepeatedField< ::google::protobuf::int64 >*
+TensorProto::mutable_int64_val() {
+  // @@protoc_insertion_point(field_mutable_list:tensorflow.TensorProto.int64_val)
+  return &int64_val_;
+}
+
+// repeated bool bool_val = 11 [packed = true];
+int TensorProto::bool_val_size() const {
+  return bool_val_.size();
+}
+void TensorProto::clear_bool_val() {
+  bool_val_.Clear();
+}
+bool TensorProto::bool_val(int index) const {
+  // @@protoc_insertion_point(field_get:tensorflow.TensorProto.bool_val)
+  return bool_val_.Get(index);
+}
+void TensorProto::set_bool_val(int index, bool value) {
+  bool_val_.Set(index, value);
+  // @@protoc_insertion_point(field_set:tensorflow.TensorProto.bool_val)
+}
+void TensorProto::add_bool_val(bool value) {
+  bool_val_.Add(value);
+  // @@protoc_insertion_point(field_add:tensorflow.TensorProto.bool_val)
+}
+const ::google::protobuf::RepeatedField< bool >&
+TensorProto::bool_val() const {
+  // @@protoc_insertion_point(field_list:tensorflow.TensorProto.bool_val)
+  return bool_val_;
+}
+::google::protobuf::RepeatedField< bool >*
+TensorProto::mutable_bool_val() {
+  // @@protoc_insertion_point(field_mutable_list:tensorflow.TensorProto.bool_val)
+  return &bool_val_;
+}
+
+// repeated double dcomplex_val = 12 [packed = true];
+int TensorProto::dcomplex_val_size() const {
+  return dcomplex_val_.size();
+}
+void TensorProto::clear_dcomplex_val() {
+  dcomplex_val_.Clear();
+}
+double TensorProto::dcomplex_val(int index) const {
+  // @@protoc_insertion_point(field_get:tensorflow.TensorProto.dcomplex_val)
+  return dcomplex_val_.Get(index);
+}
+void TensorProto::set_dcomplex_val(int index, double value) {
+  dcomplex_val_.Set(index, value);
+  // @@protoc_insertion_point(field_set:tensorflow.TensorProto.dcomplex_val)
+}
+void TensorProto::add_dcomplex_val(double value) {
+  dcomplex_val_.Add(value);
+  // @@protoc_insertion_point(field_add:tensorflow.TensorProto.dcomplex_val)
+}
+const ::google::protobuf::RepeatedField< double >&
+TensorProto::dcomplex_val() const {
+  // @@protoc_insertion_point(field_list:tensorflow.TensorProto.dcomplex_val)
+  return dcomplex_val_;
+}
+::google::protobuf::RepeatedField< double >*
+TensorProto::mutable_dcomplex_val() {
+  // @@protoc_insertion_point(field_mutable_list:tensorflow.TensorProto.dcomplex_val)
+  return &dcomplex_val_;
+}
+
+inline const TensorProto* TensorProto::internal_default_instance() {
+  return &TensorProto_default_instance_.get();
+}
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
+
+// @@protoc_insertion_point(namespace_scope)
+
+}  // namespace tensorflow
+
+// @@protoc_insertion_point(global_scope)
diff --git a/contrib/modules/dnn/misc/tensorflow/tensor.pb.h b/contrib/modules/dnn/misc/tensorflow/tensor.pb.h
new file mode 100644
index 0000000..362821f
--- /dev/null
+++ b/contrib/modules/dnn/misc/tensorflow/tensor.pb.h
@@ -0,0 +1,770 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: tensor.proto
+
+#ifndef PROTOBUF_tensor_2eproto__INCLUDED
+#define PROTOBUF_tensor_2eproto__INCLUDED
+
+#include <string>
+
+#include <google/protobuf/stubs/common.h>
+
+#if GOOGLE_PROTOBUF_VERSION < 3001000
+#error This file was generated by a newer version of protoc which is
+#error incompatible with your Protocol Buffer headers.  Please update
+#error your headers.
+#endif
+#if 3001000 < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION
+#error This file was generated by an older version of protoc which is
+#error incompatible with your Protocol Buffer headers.  Please
+#error regenerate this file with a newer version of protoc.
+#endif
+
+#include <google/protobuf/arena.h>
+#include <google/protobuf/arenastring.h>
+#include <google/protobuf/generated_message_util.h>
+#include <google/protobuf/metadata.h>
+#include <google/protobuf/message.h>
+#include <google/protobuf/repeated_field.h>
+#include <google/protobuf/extension_set.h>
+#include <google/protobuf/unknown_field_set.h>
+#include "tensor_shape.pb.h"
+#include "types.pb.h"
+// @@protoc_insertion_point(includes)
+
+namespace tensorflow {
+
+// Internal implementation detail -- do not call these.
+void protobuf_AddDesc_tensor_2eproto();
+void protobuf_InitDefaults_tensor_2eproto();
+void protobuf_AssignDesc_tensor_2eproto();
+void protobuf_ShutdownFile_tensor_2eproto();
+
+class TensorProto;
+
+// ===================================================================
+
+class TensorProto : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:tensorflow.TensorProto) */ {
+ public:
+  TensorProto();
+  virtual ~TensorProto();
+
+  TensorProto(const TensorProto& from);
+
+  inline TensorProto& operator=(const TensorProto& from) {
+    CopyFrom(from);
+    return *this;
+  }
+
+  inline ::google::protobuf::Arena* GetArena() const { return GetArenaNoVirtual(); }
+  inline void* GetMaybeArenaPointer() const {
+    return MaybeArenaPtr();
+  }
+  static const ::google::protobuf::Descriptor* descriptor();
+  static const TensorProto& default_instance();
+
+  static const TensorProto* internal_default_instance();
+
+  void UnsafeArenaSwap(TensorProto* other);
+  void Swap(TensorProto* other);
+
+  // implements Message ----------------------------------------------
+
+  inline TensorProto* New() const { return New(NULL); }
+
+  TensorProto* New(::google::protobuf::Arena* arena) const;
+  void CopyFrom(const ::google::protobuf::Message& from);
+  void MergeFrom(const ::google::protobuf::Message& from);
+  void CopyFrom(const TensorProto& from);
+  void MergeFrom(const TensorProto& from);
+  void Clear();
+  bool IsInitialized() const;
+
+  size_t ByteSizeLong() const;
+  bool MergePartialFromCodedStream(
+      ::google::protobuf::io::CodedInputStream* input);
+  void SerializeWithCachedSizes(
+      ::google::protobuf::io::CodedOutputStream* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
+  int GetCachedSize() const { return _cached_size_; }
+  private:
+  void SharedCtor();
+  void SharedDtor();
+  void SetCachedSize(int size) const;
+  void InternalSwap(TensorProto* other);
+  void UnsafeMergeFrom(const TensorProto& from);
+  protected:
+  explicit TensorProto(::google::protobuf::Arena* arena);
+  private:
+  static void ArenaDtor(void* object);
+  inline void RegisterArenaDtor(::google::protobuf::Arena* arena);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
+  public:
+
+  ::google::protobuf::Metadata GetMetadata() const;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  // optional .tensorflow.DataType dtype = 1;
+  void clear_dtype();
+  static const int kDtypeFieldNumber = 1;
+  ::tensorflow::DataType dtype() const;
+  void set_dtype(::tensorflow::DataType value);
+
+  // optional .tensorflow.TensorShapeProto tensor_shape = 2;
+  bool has_tensor_shape() const;
+  void clear_tensor_shape();
+  static const int kTensorShapeFieldNumber = 2;
+  private:
+  void _slow_mutable_tensor_shape();
+  void _slow_set_allocated_tensor_shape(
+      ::google::protobuf::Arena* message_arena, ::tensorflow::TensorShapeProto** tensor_shape);
+  ::tensorflow::TensorShapeProto* _slow_release_tensor_shape();
+  public:
+  const ::tensorflow::TensorShapeProto& tensor_shape() const;
+  ::tensorflow::TensorShapeProto* mutable_tensor_shape();
+  ::tensorflow::TensorShapeProto* release_tensor_shape();
+  void set_allocated_tensor_shape(::tensorflow::TensorShapeProto* tensor_shape);
+  ::tensorflow::TensorShapeProto* unsafe_arena_release_tensor_shape();
+  void unsafe_arena_set_allocated_tensor_shape(
+      ::tensorflow::TensorShapeProto* tensor_shape);
+
+  // optional int32 version_number = 3;
+  void clear_version_number();
+  static const int kVersionNumberFieldNumber = 3;
+  ::google::protobuf::int32 version_number() const;
+  void set_version_number(::google::protobuf::int32 value);
+
+  // optional bytes tensor_content = 4;
+  void clear_tensor_content();
+  static const int kTensorContentFieldNumber = 4;
+  const ::std::string& tensor_content() const;
+  void set_tensor_content(const ::std::string& value);
+  void set_tensor_content(const char* value);
+  void set_tensor_content(const void* value, size_t size);
+  ::std::string* mutable_tensor_content();
+  ::std::string* release_tensor_content();
+  void set_allocated_tensor_content(::std::string* tensor_content);
+  ::std::string* unsafe_arena_release_tensor_content();
+  void unsafe_arena_set_allocated_tensor_content(
+      ::std::string* tensor_content);
+
+  // repeated int32 half_val = 13 [packed = true];
+  int half_val_size() const;
+  void clear_half_val();
+  static const int kHalfValFieldNumber = 13;
+  ::google::protobuf::int32 half_val(int index) const;
+  void set_half_val(int index, ::google::protobuf::int32 value);
+  void add_half_val(::google::protobuf::int32 value);
+  const ::google::protobuf::RepeatedField< ::google::protobuf::int32 >&
+      half_val() const;
+  ::google::protobuf::RepeatedField< ::google::protobuf::int32 >*
+      mutable_half_val();
+
+  // repeated float float_val = 5 [packed = true];
+  int float_val_size() const;
+  void clear_float_val();
+  static const int kFloatValFieldNumber = 5;
+  float float_val(int index) const;
+  void set_float_val(int index, float value);
+  void add_float_val(float value);
+  const ::google::protobuf::RepeatedField< float >&
+      float_val() const;
+  ::google::protobuf::RepeatedField< float >*
+      mutable_float_val();
+
+  // repeated double double_val = 6 [packed = true];
+  int double_val_size() const;
+  void clear_double_val();
+  static const int kDoubleValFieldNumber = 6;
+  double double_val(int index) const;
+  void set_double_val(int index, double value);
+  void add_double_val(double value);
+  const ::google::protobuf::RepeatedField< double >&
+      double_val() const;
+  ::google::protobuf::RepeatedField< double >*
+      mutable_double_val();
+
+  // repeated int32 int_val = 7 [packed = true];
+  int int_val_size() const;
+  void clear_int_val();
+  static const int kIntValFieldNumber = 7;
+  ::google::protobuf::int32 int_val(int index) const;
+  void set_int_val(int index, ::google::protobuf::int32 value);
+  void add_int_val(::google::protobuf::int32 value);
+  const ::google::protobuf::RepeatedField< ::google::protobuf::int32 >&
+      int_val() const;
+  ::google::protobuf::RepeatedField< ::google::protobuf::int32 >*
+      mutable_int_val();
+
+  // repeated bytes string_val = 8;
+  int string_val_size() const;
+  void clear_string_val();
+  static const int kStringValFieldNumber = 8;
+  const ::std::string& string_val(int index) const;
+  ::std::string* mutable_string_val(int index);
+  void set_string_val(int index, const ::std::string& value);
+  void set_string_val(int index, const char* value);
+  void set_string_val(int index, const void* value, size_t size);
+  ::std::string* add_string_val();
+  void add_string_val(const ::std::string& value);
+  void add_string_val(const char* value);
+  void add_string_val(const void* value, size_t size);
+  const ::google::protobuf::RepeatedPtrField< ::std::string>& string_val() const;
+  ::google::protobuf::RepeatedPtrField< ::std::string>* mutable_string_val();
+
+  // repeated float scomplex_val = 9 [packed = true];
+  int scomplex_val_size() const;
+  void clear_scomplex_val();
+  static const int kScomplexValFieldNumber = 9;
+  float scomplex_val(int index) const;
+  void set_scomplex_val(int index, float value);
+  void add_scomplex_val(float value);
+  const ::google::protobuf::RepeatedField< float >&
+      scomplex_val() const;
+  ::google::protobuf::RepeatedField< float >*
+      mutable_scomplex_val();
+
+  // repeated int64 int64_val = 10 [packed = true];
+  int int64_val_size() const;
+  void clear_int64_val();
+  static const int kInt64ValFieldNumber = 10;
+  ::google::protobuf::int64 int64_val(int index) const;
+  void set_int64_val(int index, ::google::protobuf::int64 value);
+  void add_int64_val(::google::protobuf::int64 value);
+  const ::google::protobuf::RepeatedField< ::google::protobuf::int64 >&
+      int64_val() const;
+  ::google::protobuf::RepeatedField< ::google::protobuf::int64 >*
+      mutable_int64_val();
+
+  // repeated bool bool_val = 11 [packed = true];
+  int bool_val_size() const;
+  void clear_bool_val();
+  static const int kBoolValFieldNumber = 11;
+  bool bool_val(int index) const;
+  void set_bool_val(int index, bool value);
+  void add_bool_val(bool value);
+  const ::google::protobuf::RepeatedField< bool >&
+      bool_val() const;
+  ::google::protobuf::RepeatedField< bool >*
+      mutable_bool_val();
+
+  // repeated double dcomplex_val = 12 [packed = true];
+  int dcomplex_val_size() const;
+  void clear_dcomplex_val();
+  static const int kDcomplexValFieldNumber = 12;
+  double dcomplex_val(int index) const;
+  void set_dcomplex_val(int index, double value);
+  void add_dcomplex_val(double value);
+  const ::google::protobuf::RepeatedField< double >&
+      dcomplex_val() const;
+  ::google::protobuf::RepeatedField< double >*
+      mutable_dcomplex_val();
+
+  // @@protoc_insertion_point(class_scope:tensorflow.TensorProto)
+ private:
+
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  friend class ::google::protobuf::Arena;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  ::google::protobuf::RepeatedField< ::google::protobuf::int32 > half_val_;
+  mutable int _half_val_cached_byte_size_;
+  ::google::protobuf::RepeatedField< float > float_val_;
+  mutable int _float_val_cached_byte_size_;
+  ::google::protobuf::RepeatedField< double > double_val_;
+  mutable int _double_val_cached_byte_size_;
+  ::google::protobuf::RepeatedField< ::google::protobuf::int32 > int_val_;
+  mutable int _int_val_cached_byte_size_;
+  ::google::protobuf::RepeatedPtrField< ::std::string> string_val_;
+  ::google::protobuf::RepeatedField< float > scomplex_val_;
+  mutable int _scomplex_val_cached_byte_size_;
+  ::google::protobuf::RepeatedField< ::google::protobuf::int64 > int64_val_;
+  mutable int _int64_val_cached_byte_size_;
+  ::google::protobuf::RepeatedField< bool > bool_val_;
+  mutable int _bool_val_cached_byte_size_;
+  ::google::protobuf::RepeatedField< double > dcomplex_val_;
+  mutable int _dcomplex_val_cached_byte_size_;
+  ::google::protobuf::internal::ArenaStringPtr tensor_content_;
+  ::tensorflow::TensorShapeProto* tensor_shape_;
+  int dtype_;
+  ::google::protobuf::int32 version_number_;
+  mutable int _cached_size_;
+  friend void  protobuf_InitDefaults_tensor_2eproto_impl();
+  friend void  protobuf_AddDesc_tensor_2eproto_impl();
+  friend void protobuf_AssignDesc_tensor_2eproto();
+  friend void protobuf_ShutdownFile_tensor_2eproto();
+
+  void InitAsDefaultInstance();
+};
+extern ::google::protobuf::internal::ExplicitlyConstructed<TensorProto> TensorProto_default_instance_;
+
+// ===================================================================
+
+
+// ===================================================================
+
+#if !PROTOBUF_INLINE_NOT_IN_HEADERS
+// TensorProto
+
+// optional .tensorflow.DataType dtype = 1;
+inline void TensorProto::clear_dtype() {
+  dtype_ = 0;
+}
+inline ::tensorflow::DataType TensorProto::dtype() const {
+  // @@protoc_insertion_point(field_get:tensorflow.TensorProto.dtype)
+  return static_cast< ::tensorflow::DataType >(dtype_);
+}
+inline void TensorProto::set_dtype(::tensorflow::DataType value) {
+
+  dtype_ = value;
+  // @@protoc_insertion_point(field_set:tensorflow.TensorProto.dtype)
+}
+
+// optional .tensorflow.TensorShapeProto tensor_shape = 2;
+inline bool TensorProto::has_tensor_shape() const {
+  return this != internal_default_instance() && tensor_shape_ != NULL;
+}
+inline void TensorProto::clear_tensor_shape() {
+  if (GetArenaNoVirtual() == NULL && tensor_shape_ != NULL) delete tensor_shape_;
+  tensor_shape_ = NULL;
+}
+inline const ::tensorflow::TensorShapeProto& TensorProto::tensor_shape() const {
+  // @@protoc_insertion_point(field_get:tensorflow.TensorProto.tensor_shape)
+  return tensor_shape_ != NULL ? *tensor_shape_
+                         : *::tensorflow::TensorShapeProto::internal_default_instance();
+}
+inline ::tensorflow::TensorShapeProto* TensorProto::mutable_tensor_shape() {
+
+  if (tensor_shape_ == NULL) {
+    _slow_mutable_tensor_shape();
+  }
+  // @@protoc_insertion_point(field_mutable:tensorflow.TensorProto.tensor_shape)
+  return tensor_shape_;
+}
+inline ::tensorflow::TensorShapeProto* TensorProto::release_tensor_shape() {
+  // @@protoc_insertion_point(field_release:tensorflow.TensorProto.tensor_shape)
+
+  if (GetArenaNoVirtual() != NULL) {
+    return _slow_release_tensor_shape();
+  } else {
+    ::tensorflow::TensorShapeProto* temp = tensor_shape_;
+    tensor_shape_ = NULL;
+    return temp;
+  }
+}
+inline  void TensorProto::set_allocated_tensor_shape(::tensorflow::TensorShapeProto* tensor_shape) {
+  ::google::protobuf::Arena* message_arena = GetArenaNoVirtual();
+  if (message_arena == NULL) {
+    delete tensor_shape_;
+  }
+  if (tensor_shape != NULL) {
+    _slow_set_allocated_tensor_shape(message_arena, &tensor_shape);
+  }
+  tensor_shape_ = tensor_shape;
+  if (tensor_shape) {
+
+  } else {
+
+  }
+  // @@protoc_insertion_point(field_set_allocated:tensorflow.TensorProto.tensor_shape)
+}
+
+// optional int32 version_number = 3;
+inline void TensorProto::clear_version_number() {
+  version_number_ = 0;
+}
+inline ::google::protobuf::int32 TensorProto::version_number() const {
+  // @@protoc_insertion_point(field_get:tensorflow.TensorProto.version_number)
+  return version_number_;
+}
+inline void TensorProto::set_version_number(::google::protobuf::int32 value) {
+
+  version_number_ = value;
+  // @@protoc_insertion_point(field_set:tensorflow.TensorProto.version_number)
+}
+
+// optional bytes tensor_content = 4;
+inline void TensorProto::clear_tensor_content() {
+  tensor_content_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+inline const ::std::string& TensorProto::tensor_content() const {
+  // @@protoc_insertion_point(field_get:tensorflow.TensorProto.tensor_content)
+  return tensor_content_.Get(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void TensorProto::set_tensor_content(const ::std::string& value) {
+
+  tensor_content_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value, GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set:tensorflow.TensorProto.tensor_content)
+}
+inline void TensorProto::set_tensor_content(const char* value) {
+
+  tensor_content_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value),
+              GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_char:tensorflow.TensorProto.tensor_content)
+}
+inline void TensorProto::set_tensor_content(const void* value,
+    size_t size) {
+
+  tensor_content_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(
+      reinterpret_cast<const char*>(value), size), GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_pointer:tensorflow.TensorProto.tensor_content)
+}
+inline ::std::string* TensorProto::mutable_tensor_content() {
+
+  // @@protoc_insertion_point(field_mutable:tensorflow.TensorProto.tensor_content)
+  return tensor_content_.Mutable(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+inline ::std::string* TensorProto::release_tensor_content() {
+  // @@protoc_insertion_point(field_release:tensorflow.TensorProto.tensor_content)
+
+  return tensor_content_.Release(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+inline ::std::string* TensorProto::unsafe_arena_release_tensor_content() {
+  // @@protoc_insertion_point(field_unsafe_arena_release:tensorflow.TensorProto.tensor_content)
+  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);
+
+  return tensor_content_.UnsafeArenaRelease(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      GetArenaNoVirtual());
+}
+inline void TensorProto::set_allocated_tensor_content(::std::string* tensor_content) {
+  if (tensor_content != NULL) {
+
+  } else {
+
+  }
+  tensor_content_.SetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), tensor_content,
+      GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_allocated:tensorflow.TensorProto.tensor_content)
+}
+inline void TensorProto::unsafe_arena_set_allocated_tensor_content(
+    ::std::string* tensor_content) {
+  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);
+  if (tensor_content != NULL) {
+
+  } else {
+
+  }
+  tensor_content_.UnsafeArenaSetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      tensor_content, GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_unsafe_arena_set_allocated:tensorflow.TensorProto.tensor_content)
+}
+
+// repeated int32 half_val = 13 [packed = true];
+inline int TensorProto::half_val_size() const {
+  return half_val_.size();
+}
+inline void TensorProto::clear_half_val() {
+  half_val_.Clear();
+}
+inline ::google::protobuf::int32 TensorProto::half_val(int index) const {
+  // @@protoc_insertion_point(field_get:tensorflow.TensorProto.half_val)
+  return half_val_.Get(index);
+}
+inline void TensorProto::set_half_val(int index, ::google::protobuf::int32 value) {
+  half_val_.Set(index, value);
+  // @@protoc_insertion_point(field_set:tensorflow.TensorProto.half_val)
+}
+inline void TensorProto::add_half_val(::google::protobuf::int32 value) {
+  half_val_.Add(value);
+  // @@protoc_insertion_point(field_add:tensorflow.TensorProto.half_val)
+}
+inline const ::google::protobuf::RepeatedField< ::google::protobuf::int32 >&
+TensorProto::half_val() const {
+  // @@protoc_insertion_point(field_list:tensorflow.TensorProto.half_val)
+  return half_val_;
+}
+inline ::google::protobuf::RepeatedField< ::google::protobuf::int32 >*
+TensorProto::mutable_half_val() {
+  // @@protoc_insertion_point(field_mutable_list:tensorflow.TensorProto.half_val)
+  return &half_val_;
+}
+
+// repeated float float_val = 5 [packed = true];
+inline int TensorProto::float_val_size() const {
+  return float_val_.size();
+}
+inline void TensorProto::clear_float_val() {
+  float_val_.Clear();
+}
+inline float TensorProto::float_val(int index) const {
+  // @@protoc_insertion_point(field_get:tensorflow.TensorProto.float_val)
+  return float_val_.Get(index);
+}
+inline void TensorProto::set_float_val(int index, float value) {
+  float_val_.Set(index, value);
+  // @@protoc_insertion_point(field_set:tensorflow.TensorProto.float_val)
+}
+inline void TensorProto::add_float_val(float value) {
+  float_val_.Add(value);
+  // @@protoc_insertion_point(field_add:tensorflow.TensorProto.float_val)
+}
+inline const ::google::protobuf::RepeatedField< float >&
+TensorProto::float_val() const {
+  // @@protoc_insertion_point(field_list:tensorflow.TensorProto.float_val)
+  return float_val_;
+}
+inline ::google::protobuf::RepeatedField< float >*
+TensorProto::mutable_float_val() {
+  // @@protoc_insertion_point(field_mutable_list:tensorflow.TensorProto.float_val)
+  return &float_val_;
+}
+
+// repeated double double_val = 6 [packed = true];
+inline int TensorProto::double_val_size() const {
+  return double_val_.size();
+}
+inline void TensorProto::clear_double_val() {
+  double_val_.Clear();
+}
+inline double TensorProto::double_val(int index) const {
+  // @@protoc_insertion_point(field_get:tensorflow.TensorProto.double_val)
+  return double_val_.Get(index);
+}
+inline void TensorProto::set_double_val(int index, double value) {
+  double_val_.Set(index, value);
+  // @@protoc_insertion_point(field_set:tensorflow.TensorProto.double_val)
+}
+inline void TensorProto::add_double_val(double value) {
+  double_val_.Add(value);
+  // @@protoc_insertion_point(field_add:tensorflow.TensorProto.double_val)
+}
+inline const ::google::protobuf::RepeatedField< double >&
+TensorProto::double_val() const {
+  // @@protoc_insertion_point(field_list:tensorflow.TensorProto.double_val)
+  return double_val_;
+}
+inline ::google::protobuf::RepeatedField< double >*
+TensorProto::mutable_double_val() {
+  // @@protoc_insertion_point(field_mutable_list:tensorflow.TensorProto.double_val)
+  return &double_val_;
+}
+
+// repeated int32 int_val = 7 [packed = true];
+inline int TensorProto::int_val_size() const {
+  return int_val_.size();
+}
+inline void TensorProto::clear_int_val() {
+  int_val_.Clear();
+}
+inline ::google::protobuf::int32 TensorProto::int_val(int index) const {
+  // @@protoc_insertion_point(field_get:tensorflow.TensorProto.int_val)
+  return int_val_.Get(index);
+}
+inline void TensorProto::set_int_val(int index, ::google::protobuf::int32 value) {
+  int_val_.Set(index, value);
+  // @@protoc_insertion_point(field_set:tensorflow.TensorProto.int_val)
+}
+inline void TensorProto::add_int_val(::google::protobuf::int32 value) {
+  int_val_.Add(value);
+  // @@protoc_insertion_point(field_add:tensorflow.TensorProto.int_val)
+}
+inline const ::google::protobuf::RepeatedField< ::google::protobuf::int32 >&
+TensorProto::int_val() const {
+  // @@protoc_insertion_point(field_list:tensorflow.TensorProto.int_val)
+  return int_val_;
+}
+inline ::google::protobuf::RepeatedField< ::google::protobuf::int32 >*
+TensorProto::mutable_int_val() {
+  // @@protoc_insertion_point(field_mutable_list:tensorflow.TensorProto.int_val)
+  return &int_val_;
+}
+
+// repeated bytes string_val = 8;
+inline int TensorProto::string_val_size() const {
+  return string_val_.size();
+}
+inline void TensorProto::clear_string_val() {
+  string_val_.Clear();
+}
+inline const ::std::string& TensorProto::string_val(int index) const {
+  // @@protoc_insertion_point(field_get:tensorflow.TensorProto.string_val)
+  return string_val_.Get(index);
+}
+inline ::std::string* TensorProto::mutable_string_val(int index) {
+  // @@protoc_insertion_point(field_mutable:tensorflow.TensorProto.string_val)
+  return string_val_.Mutable(index);
+}
+inline void TensorProto::set_string_val(int index, const ::std::string& value) {
+  // @@protoc_insertion_point(field_set:tensorflow.TensorProto.string_val)
+  string_val_.Mutable(index)->assign(value);
+}
+inline void TensorProto::set_string_val(int index, const char* value) {
+  string_val_.Mutable(index)->assign(value);
+  // @@protoc_insertion_point(field_set_char:tensorflow.TensorProto.string_val)
+}
+inline void TensorProto::set_string_val(int index, const void* value, size_t size) {
+  string_val_.Mutable(index)->assign(
+    reinterpret_cast<const char*>(value), size);
+  // @@protoc_insertion_point(field_set_pointer:tensorflow.TensorProto.string_val)
+}
+inline ::std::string* TensorProto::add_string_val() {
+  // @@protoc_insertion_point(field_add_mutable:tensorflow.TensorProto.string_val)
+  return string_val_.Add();
+}
+inline void TensorProto::add_string_val(const ::std::string& value) {
+  string_val_.Add()->assign(value);
+  // @@protoc_insertion_point(field_add:tensorflow.TensorProto.string_val)
+}
+inline void TensorProto::add_string_val(const char* value) {
+  string_val_.Add()->assign(value);
+  // @@protoc_insertion_point(field_add_char:tensorflow.TensorProto.string_val)
+}
+inline void TensorProto::add_string_val(const void* value, size_t size) {
+  string_val_.Add()->assign(reinterpret_cast<const char*>(value), size);
+  // @@protoc_insertion_point(field_add_pointer:tensorflow.TensorProto.string_val)
+}
+inline const ::google::protobuf::RepeatedPtrField< ::std::string>&
+TensorProto::string_val() const {
+  // @@protoc_insertion_point(field_list:tensorflow.TensorProto.string_val)
+  return string_val_;
+}
+inline ::google::protobuf::RepeatedPtrField< ::std::string>*
+TensorProto::mutable_string_val() {
+  // @@protoc_insertion_point(field_mutable_list:tensorflow.TensorProto.string_val)
+  return &string_val_;
+}
+
+// repeated float scomplex_val = 9 [packed = true];
+inline int TensorProto::scomplex_val_size() const {
+  return scomplex_val_.size();
+}
+inline void TensorProto::clear_scomplex_val() {
+  scomplex_val_.Clear();
+}
+inline float TensorProto::scomplex_val(int index) const {
+  // @@protoc_insertion_point(field_get:tensorflow.TensorProto.scomplex_val)
+  return scomplex_val_.Get(index);
+}
+inline void TensorProto::set_scomplex_val(int index, float value) {
+  scomplex_val_.Set(index, value);
+  // @@protoc_insertion_point(field_set:tensorflow.TensorProto.scomplex_val)
+}
+inline void TensorProto::add_scomplex_val(float value) {
+  scomplex_val_.Add(value);
+  // @@protoc_insertion_point(field_add:tensorflow.TensorProto.scomplex_val)
+}
+inline const ::google::protobuf::RepeatedField< float >&
+TensorProto::scomplex_val() const {
+  // @@protoc_insertion_point(field_list:tensorflow.TensorProto.scomplex_val)
+  return scomplex_val_;
+}
+inline ::google::protobuf::RepeatedField< float >*
+TensorProto::mutable_scomplex_val() {
+  // @@protoc_insertion_point(field_mutable_list:tensorflow.TensorProto.scomplex_val)
+  return &scomplex_val_;
+}
+
+// repeated int64 int64_val = 10 [packed = true];
+inline int TensorProto::int64_val_size() const {
+  return int64_val_.size();
+}
+inline void TensorProto::clear_int64_val() {
+  int64_val_.Clear();
+}
+inline ::google::protobuf::int64 TensorProto::int64_val(int index) const {
+  // @@protoc_insertion_point(field_get:tensorflow.TensorProto.int64_val)
+  return int64_val_.Get(index);
+}
+inline void TensorProto::set_int64_val(int index, ::google::protobuf::int64 value) {
+  int64_val_.Set(index, value);
+  // @@protoc_insertion_point(field_set:tensorflow.TensorProto.int64_val)
+}
+inline void TensorProto::add_int64_val(::google::protobuf::int64 value) {
+  int64_val_.Add(value);
+  // @@protoc_insertion_point(field_add:tensorflow.TensorProto.int64_val)
+}
+inline const ::google::protobuf::RepeatedField< ::google::protobuf::int64 >&
+TensorProto::int64_val() const {
+  // @@protoc_insertion_point(field_list:tensorflow.TensorProto.int64_val)
+  return int64_val_;
+}
+inline ::google::protobuf::RepeatedField< ::google::protobuf::int64 >*
+TensorProto::mutable_int64_val() {
+  // @@protoc_insertion_point(field_mutable_list:tensorflow.TensorProto.int64_val)
+  return &int64_val_;
+}
+
+// repeated bool bool_val = 11 [packed = true];
+inline int TensorProto::bool_val_size() const {
+  return bool_val_.size();
+}
+inline void TensorProto::clear_bool_val() {
+  bool_val_.Clear();
+}
+inline bool TensorProto::bool_val(int index) const {
+  // @@protoc_insertion_point(field_get:tensorflow.TensorProto.bool_val)
+  return bool_val_.Get(index);
+}
+inline void TensorProto::set_bool_val(int index, bool value) {
+  bool_val_.Set(index, value);
+  // @@protoc_insertion_point(field_set:tensorflow.TensorProto.bool_val)
+}
+inline void TensorProto::add_bool_val(bool value) {
+  bool_val_.Add(value);
+  // @@protoc_insertion_point(field_add:tensorflow.TensorProto.bool_val)
+}
+inline const ::google::protobuf::RepeatedField< bool >&
+TensorProto::bool_val() const {
+  // @@protoc_insertion_point(field_list:tensorflow.TensorProto.bool_val)
+  return bool_val_;
+}
+inline ::google::protobuf::RepeatedField< bool >*
+TensorProto::mutable_bool_val() {
+  // @@protoc_insertion_point(field_mutable_list:tensorflow.TensorProto.bool_val)
+  return &bool_val_;
+}
+
+// repeated double dcomplex_val = 12 [packed = true];
+inline int TensorProto::dcomplex_val_size() const {
+  return dcomplex_val_.size();
+}
+inline void TensorProto::clear_dcomplex_val() {
+  dcomplex_val_.Clear();
+}
+inline double TensorProto::dcomplex_val(int index) const {
+  // @@protoc_insertion_point(field_get:tensorflow.TensorProto.dcomplex_val)
+  return dcomplex_val_.Get(index);
+}
+inline void TensorProto::set_dcomplex_val(int index, double value) {
+  dcomplex_val_.Set(index, value);
+  // @@protoc_insertion_point(field_set:tensorflow.TensorProto.dcomplex_val)
+}
+inline void TensorProto::add_dcomplex_val(double value) {
+  dcomplex_val_.Add(value);
+  // @@protoc_insertion_point(field_add:tensorflow.TensorProto.dcomplex_val)
+}
+inline const ::google::protobuf::RepeatedField< double >&
+TensorProto::dcomplex_val() const {
+  // @@protoc_insertion_point(field_list:tensorflow.TensorProto.dcomplex_val)
+  return dcomplex_val_;
+}
+inline ::google::protobuf::RepeatedField< double >*
+TensorProto::mutable_dcomplex_val() {
+  // @@protoc_insertion_point(field_mutable_list:tensorflow.TensorProto.dcomplex_val)
+  return &dcomplex_val_;
+}
+
+inline const TensorProto* TensorProto::internal_default_instance() {
+  return &TensorProto_default_instance_.get();
+}
+#endif  // !PROTOBUF_INLINE_NOT_IN_HEADERS
+
+// @@protoc_insertion_point(namespace_scope)
+
+}  // namespace tensorflow
+
+// @@protoc_insertion_point(global_scope)
+
+#endif  // PROTOBUF_tensor_2eproto__INCLUDED
diff --git a/contrib/modules/dnn/misc/tensorflow/tensor_shape.pb.cc b/contrib/modules/dnn/misc/tensorflow/tensor_shape.pb.cc
new file mode 100644
index 0000000..1e92ff8
--- /dev/null
+++ b/contrib/modules/dnn/misc/tensorflow/tensor_shape.pb.cc
@@ -0,0 +1,895 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: tensor_shape.proto
+
+#define INTERNAL_SUPPRESS_PROTOBUF_FIELD_DEPRECATION
+#include "tensor_shape.pb.h"
+
+#include <algorithm>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/port.h>
+#include <google/protobuf/stubs/once.h>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/wire_format_lite_inl.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/generated_message_reflection.h>
+#include <google/protobuf/reflection_ops.h>
+#include <google/protobuf/wire_format.h>
+// @@protoc_insertion_point(includes)
+
+namespace tensorflow {
+
+namespace {
+
+const ::google::protobuf::Descriptor* TensorShapeProto_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+  TensorShapeProto_reflection_ = NULL;
+const ::google::protobuf::Descriptor* TensorShapeProto_Dim_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+  TensorShapeProto_Dim_reflection_ = NULL;
+
+}  // namespace
+
+
+void protobuf_AssignDesc_tensor_5fshape_2eproto() GOOGLE_ATTRIBUTE_COLD;
+void protobuf_AssignDesc_tensor_5fshape_2eproto() {
+  protobuf_AddDesc_tensor_5fshape_2eproto();
+  const ::google::protobuf::FileDescriptor* file =
+    ::google::protobuf::DescriptorPool::generated_pool()->FindFileByName(
+      "tensor_shape.proto");
+  GOOGLE_CHECK(file != NULL);
+  TensorShapeProto_descriptor_ = file->message_type(0);
+  static const int TensorShapeProto_offsets_[2] = {
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(TensorShapeProto, dim_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(TensorShapeProto, unknown_rank_),
+  };
+  TensorShapeProto_reflection_ =
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
+      TensorShapeProto_descriptor_,
+      TensorShapeProto::internal_default_instance(),
+      TensorShapeProto_offsets_,
+      -1,
+      -1,
+      -1,
+      sizeof(TensorShapeProto),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(TensorShapeProto, _internal_metadata_));
+  TensorShapeProto_Dim_descriptor_ = TensorShapeProto_descriptor_->nested_type(0);
+  static const int TensorShapeProto_Dim_offsets_[2] = {
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(TensorShapeProto_Dim, size_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(TensorShapeProto_Dim, name_),
+  };
+  TensorShapeProto_Dim_reflection_ =
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
+      TensorShapeProto_Dim_descriptor_,
+      TensorShapeProto_Dim::internal_default_instance(),
+      TensorShapeProto_Dim_offsets_,
+      -1,
+      -1,
+      -1,
+      sizeof(TensorShapeProto_Dim),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(TensorShapeProto_Dim, _internal_metadata_));
+}
+
+namespace {
+
+GOOGLE_PROTOBUF_DECLARE_ONCE(protobuf_AssignDescriptors_once_);
+void protobuf_AssignDescriptorsOnce() {
+  ::google::protobuf::GoogleOnceInit(&protobuf_AssignDescriptors_once_,
+                 &protobuf_AssignDesc_tensor_5fshape_2eproto);
+}
+
+void protobuf_RegisterTypes(const ::std::string&) GOOGLE_ATTRIBUTE_COLD;
+void protobuf_RegisterTypes(const ::std::string&) {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+      TensorShapeProto_descriptor_, TensorShapeProto::internal_default_instance());
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+      TensorShapeProto_Dim_descriptor_, TensorShapeProto_Dim::internal_default_instance());
+}
+
+}  // namespace
+
+void protobuf_ShutdownFile_tensor_5fshape_2eproto() {
+  TensorShapeProto_default_instance_.Shutdown();
+  delete TensorShapeProto_reflection_;
+  TensorShapeProto_Dim_default_instance_.Shutdown();
+  delete TensorShapeProto_Dim_reflection_;
+}
+
+void protobuf_InitDefaults_tensor_5fshape_2eproto_impl() {
+  GOOGLE_PROTOBUF_VERIFY_VERSION;
+
+  TensorShapeProto_default_instance_.DefaultConstruct();
+  ::google::protobuf::internal::GetEmptyString();
+  TensorShapeProto_Dim_default_instance_.DefaultConstruct();
+  TensorShapeProto_default_instance_.get_mutable()->InitAsDefaultInstance();
+  TensorShapeProto_Dim_default_instance_.get_mutable()->InitAsDefaultInstance();
+}
+
+GOOGLE_PROTOBUF_DECLARE_ONCE(protobuf_InitDefaults_tensor_5fshape_2eproto_once_);
+void protobuf_InitDefaults_tensor_5fshape_2eproto() {
+  ::google::protobuf::GoogleOnceInit(&protobuf_InitDefaults_tensor_5fshape_2eproto_once_,
+                 &protobuf_InitDefaults_tensor_5fshape_2eproto_impl);
+}
+void protobuf_AddDesc_tensor_5fshape_2eproto_impl() {
+  GOOGLE_PROTOBUF_VERIFY_VERSION;
+
+  protobuf_InitDefaults_tensor_5fshape_2eproto();
+  ::google::protobuf::DescriptorPool::InternalAddGeneratedFile(
+    "\n\022tensor_shape.proto\022\ntensorflow\"z\n\020Tens"
+    "orShapeProto\022-\n\003dim\030\002 \003(\0132 .tensorflow.T"
+    "ensorShapeProto.Dim\022\024\n\014unknown_rank\030\003 \001("
+    "\010\032!\n\003Dim\022\014\n\004size\030\001 \001(\003\022\014\n\004name\030\002 \001(\tB2\n\030"
+    "org.tensorflow.frameworkB\021TensorShapePro"
+    "tosP\001\370\001\001b\006proto3", 216);
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedFile(
+    "tensor_shape.proto", &protobuf_RegisterTypes);
+  ::google::protobuf::internal::OnShutdown(&protobuf_ShutdownFile_tensor_5fshape_2eproto);
+}
+
+GOOGLE_PROTOBUF_DECLARE_ONCE(protobuf_AddDesc_tensor_5fshape_2eproto_once_);
+void protobuf_AddDesc_tensor_5fshape_2eproto() {
+  ::google::protobuf::GoogleOnceInit(&protobuf_AddDesc_tensor_5fshape_2eproto_once_,
+                 &protobuf_AddDesc_tensor_5fshape_2eproto_impl);
+}
+// Force AddDescriptors() to be called at static initialization time.
+struct StaticDescriptorInitializer_tensor_5fshape_2eproto {
+  StaticDescriptorInitializer_tensor_5fshape_2eproto() {
+    protobuf_AddDesc_tensor_5fshape_2eproto();
+  }
+} static_descriptor_initializer_tensor_5fshape_2eproto_;
+
+namespace {
+
+static void MergeFromFail(int line) GOOGLE_ATTRIBUTE_COLD GOOGLE_ATTRIBUTE_NORETURN;
+static void MergeFromFail(int line) {
+  ::google::protobuf::internal::MergeFromFail(__FILE__, line);
+}
+
+}  // namespace
+
+
+// ===================================================================
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const int TensorShapeProto_Dim::kSizeFieldNumber;
+const int TensorShapeProto_Dim::kNameFieldNumber;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+
+TensorShapeProto_Dim::TensorShapeProto_Dim()
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+  if (this != internal_default_instance()) protobuf_InitDefaults_tensor_5fshape_2eproto();
+  SharedCtor();
+  // @@protoc_insertion_point(constructor:tensorflow.TensorShapeProto.Dim)
+}
+TensorShapeProto_Dim::TensorShapeProto_Dim(::google::protobuf::Arena* arena)
+  : ::google::protobuf::Message(),
+  _internal_metadata_(arena) {
+#ifdef GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER
+  protobuf_InitDefaults_tensor_5fshape_2eproto();
+#endif  // GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER
+  SharedCtor();
+  RegisterArenaDtor(arena);
+  // @@protoc_insertion_point(arena_constructor:tensorflow.TensorShapeProto.Dim)
+}
+
+void TensorShapeProto_Dim::InitAsDefaultInstance() {
+}
+
+TensorShapeProto_Dim::TensorShapeProto_Dim(const TensorShapeProto_Dim& from)
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
+  SharedCtor();
+  UnsafeMergeFrom(from);
+  // @@protoc_insertion_point(copy_constructor:tensorflow.TensorShapeProto.Dim)
+}
+
+void TensorShapeProto_Dim::SharedCtor() {
+  name_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  size_ = GOOGLE_LONGLONG(0);
+  _cached_size_ = 0;
+}
+
+TensorShapeProto_Dim::~TensorShapeProto_Dim() {
+  // @@protoc_insertion_point(destructor:tensorflow.TensorShapeProto.Dim)
+  SharedDtor();
+}
+
+void TensorShapeProto_Dim::SharedDtor() {
+  ::google::protobuf::Arena* arena = GetArenaNoVirtual();
+  if (arena != NULL) {
+    return;
+  }
+
+  name_.Destroy(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), arena);
+}
+
+void TensorShapeProto_Dim::ArenaDtor(void* object) {
+  TensorShapeProto_Dim* _this = reinterpret_cast< TensorShapeProto_Dim* >(object);
+  (void)_this;
+}
+void TensorShapeProto_Dim::RegisterArenaDtor(::google::protobuf::Arena* arena) {
+}
+void TensorShapeProto_Dim::SetCachedSize(int size) const {
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* TensorShapeProto_Dim::descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return TensorShapeProto_Dim_descriptor_;
+}
+
+const TensorShapeProto_Dim& TensorShapeProto_Dim::default_instance() {
+  protobuf_InitDefaults_tensor_5fshape_2eproto();
+  return *internal_default_instance();
+}
+
+::google::protobuf::internal::ExplicitlyConstructed<TensorShapeProto_Dim> TensorShapeProto_Dim_default_instance_;
+
+TensorShapeProto_Dim* TensorShapeProto_Dim::New(::google::protobuf::Arena* arena) const {
+  return ::google::protobuf::Arena::CreateMessage<TensorShapeProto_Dim>(arena);
+}
+
+void TensorShapeProto_Dim::Clear() {
+// @@protoc_insertion_point(message_clear_start:tensorflow.TensorShapeProto.Dim)
+  size_ = GOOGLE_LONGLONG(0);
+  name_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+
+bool TensorShapeProto_Dim::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
+  ::google::protobuf::uint32 tag;
+  // @@protoc_insertion_point(parse_start:tensorflow.TensorShapeProto.Dim)
+  for (;;) {
+    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+    tag = p.first;
+    if (!p.second) goto handle_unusual;
+    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+      // optional int64 size = 1;
+      case 1: {
+        if (tag == 8) {
+
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::int64, ::google::protobuf::internal::WireFormatLite::TYPE_INT64>(
+                 input, &size_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(18)) goto parse_name;
+        break;
+      }
+
+      // optional string name = 2;
+      case 2: {
+        if (tag == 18) {
+         parse_name:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadString(
+                input, this->mutable_name()));
+          DO_(::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+            this->name().data(), this->name().length(),
+            ::google::protobuf::internal::WireFormatLite::PARSE,
+            "tensorflow.TensorShapeProto.Dim.name"));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectAtEnd()) goto success;
+        break;
+      }
+
+      default: {
+      handle_unusual:
+        if (tag == 0 ||
+            ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+          goto success;
+        }
+        DO_(::google::protobuf::internal::WireFormatLite::SkipField(input, tag));
+        break;
+      }
+    }
+  }
+success:
+  // @@protoc_insertion_point(parse_success:tensorflow.TensorShapeProto.Dim)
+  return true;
+failure:
+  // @@protoc_insertion_point(parse_failure:tensorflow.TensorShapeProto.Dim)
+  return false;
+#undef DO_
+}
+
+void TensorShapeProto_Dim::SerializeWithCachedSizes(
+    ::google::protobuf::io::CodedOutputStream* output) const {
+  // @@protoc_insertion_point(serialize_start:tensorflow.TensorShapeProto.Dim)
+  // optional int64 size = 1;
+  if (this->size() != 0) {
+    ::google::protobuf::internal::WireFormatLite::WriteInt64(1, this->size(), output);
+  }
+
+  // optional string name = 2;
+  if (this->name().size() > 0) {
+    ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+      this->name().data(), this->name().length(),
+      ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+      "tensorflow.TensorShapeProto.Dim.name");
+    ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased(
+      2, this->name(), output);
+  }
+
+  // @@protoc_insertion_point(serialize_end:tensorflow.TensorShapeProto.Dim)
+}
+
+::google::protobuf::uint8* TensorShapeProto_Dim::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
+  (void)deterministic; // Unused
+  // @@protoc_insertion_point(serialize_to_array_start:tensorflow.TensorShapeProto.Dim)
+  // optional int64 size = 1;
+  if (this->size() != 0) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteInt64ToArray(1, this->size(), target);
+  }
+
+  // optional string name = 2;
+  if (this->name().size() > 0) {
+    ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
+      this->name().data(), this->name().length(),
+      ::google::protobuf::internal::WireFormatLite::SERIALIZE,
+      "tensorflow.TensorShapeProto.Dim.name");
+    target =
+      ::google::protobuf::internal::WireFormatLite::WriteStringToArray(
+        2, this->name(), target);
+  }
+
+  // @@protoc_insertion_point(serialize_to_array_end:tensorflow.TensorShapeProto.Dim)
+  return target;
+}
+
+size_t TensorShapeProto_Dim::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:tensorflow.TensorShapeProto.Dim)
+  size_t total_size = 0;
+
+  // optional int64 size = 1;
+  if (this->size() != 0) {
+    total_size += 1 +
+      ::google::protobuf::internal::WireFormatLite::Int64Size(
+        this->size());
+  }
+
+  // optional string name = 2;
+  if (this->name().size() > 0) {
+    total_size += 1 +
+      ::google::protobuf::internal::WireFormatLite::StringSize(
+        this->name());
+  }
+
+  int cached_size = ::google::protobuf::internal::ToCachedSize(total_size);
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = cached_size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+  return total_size;
+}
+
+void TensorShapeProto_Dim::MergeFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_merge_from_start:tensorflow.TensorShapeProto.Dim)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const TensorShapeProto_Dim* source =
+      ::google::protobuf::internal::DynamicCastToGenerated<const TensorShapeProto_Dim>(
+          &from);
+  if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:tensorflow.TensorShapeProto.Dim)
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:tensorflow.TensorShapeProto.Dim)
+    UnsafeMergeFrom(*source);
+  }
+}
+
+void TensorShapeProto_Dim::MergeFrom(const TensorShapeProto_Dim& from) {
+// @@protoc_insertion_point(class_specific_merge_from_start:tensorflow.TensorShapeProto.Dim)
+  if (GOOGLE_PREDICT_TRUE(&from != this)) {
+    UnsafeMergeFrom(from);
+  } else {
+    MergeFromFail(__LINE__);
+  }
+}
+
+void TensorShapeProto_Dim::UnsafeMergeFrom(const TensorShapeProto_Dim& from) {
+  GOOGLE_DCHECK(&from != this);
+  if (from.size() != 0) {
+    set_size(from.size());
+  }
+  if (from.name().size() > 0) {
+    set_name(from.name());
+  }
+}
+
+void TensorShapeProto_Dim::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:tensorflow.TensorShapeProto.Dim)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void TensorShapeProto_Dim::CopyFrom(const TensorShapeProto_Dim& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:tensorflow.TensorShapeProto.Dim)
+  if (&from == this) return;
+  Clear();
+  UnsafeMergeFrom(from);
+}
+
+bool TensorShapeProto_Dim::IsInitialized() const {
+
+  return true;
+}
+
+void TensorShapeProto_Dim::Swap(TensorShapeProto_Dim* other) {
+  if (other == this) return;
+  if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) {
+    InternalSwap(other);
+  } else {
+    TensorShapeProto_Dim temp;
+    temp.UnsafeMergeFrom(*this);
+    CopyFrom(*other);
+    other->CopyFrom(temp);
+  }
+}
+void TensorShapeProto_Dim::UnsafeArenaSwap(TensorShapeProto_Dim* other) {
+  if (other == this) return;
+  GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual());
+  InternalSwap(other);
+}
+void TensorShapeProto_Dim::InternalSwap(TensorShapeProto_Dim* other) {
+  std::swap(size_, other->size_);
+  name_.Swap(&other->name_);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
+}
+
+::google::protobuf::Metadata TensorShapeProto_Dim::GetMetadata() const {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::Metadata metadata;
+  metadata.descriptor = TensorShapeProto_Dim_descriptor_;
+  metadata.reflection = TensorShapeProto_Dim_reflection_;
+  return metadata;
+}
+
+
+// -------------------------------------------------------------------
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const int TensorShapeProto::kDimFieldNumber;
+const int TensorShapeProto::kUnknownRankFieldNumber;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+
+TensorShapeProto::TensorShapeProto()
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+  if (this != internal_default_instance()) protobuf_InitDefaults_tensor_5fshape_2eproto();
+  SharedCtor();
+  // @@protoc_insertion_point(constructor:tensorflow.TensorShapeProto)
+}
+TensorShapeProto::TensorShapeProto(::google::protobuf::Arena* arena)
+  : ::google::protobuf::Message(),
+  _internal_metadata_(arena),
+  dim_(arena) {
+#ifdef GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER
+  protobuf_InitDefaults_tensor_5fshape_2eproto();
+#endif  // GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER
+  SharedCtor();
+  RegisterArenaDtor(arena);
+  // @@protoc_insertion_point(arena_constructor:tensorflow.TensorShapeProto)
+}
+
+void TensorShapeProto::InitAsDefaultInstance() {
+}
+
+TensorShapeProto::TensorShapeProto(const TensorShapeProto& from)
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
+  SharedCtor();
+  UnsafeMergeFrom(from);
+  // @@protoc_insertion_point(copy_constructor:tensorflow.TensorShapeProto)
+}
+
+void TensorShapeProto::SharedCtor() {
+  unknown_rank_ = false;
+  _cached_size_ = 0;
+}
+
+TensorShapeProto::~TensorShapeProto() {
+  // @@protoc_insertion_point(destructor:tensorflow.TensorShapeProto)
+  SharedDtor();
+}
+
+void TensorShapeProto::SharedDtor() {
+  ::google::protobuf::Arena* arena = GetArenaNoVirtual();
+  if (arena != NULL) {
+    return;
+  }
+
+}
+
+void TensorShapeProto::ArenaDtor(void* object) {
+  TensorShapeProto* _this = reinterpret_cast< TensorShapeProto* >(object);
+  (void)_this;
+}
+void TensorShapeProto::RegisterArenaDtor(::google::protobuf::Arena* arena) {
+}
+void TensorShapeProto::SetCachedSize(int size) const {
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* TensorShapeProto::descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return TensorShapeProto_descriptor_;
+}
+
+const TensorShapeProto& TensorShapeProto::default_instance() {
+  protobuf_InitDefaults_tensor_5fshape_2eproto();
+  return *internal_default_instance();
+}
+
+::google::protobuf::internal::ExplicitlyConstructed<TensorShapeProto> TensorShapeProto_default_instance_;
+
+TensorShapeProto* TensorShapeProto::New(::google::protobuf::Arena* arena) const {
+  return ::google::protobuf::Arena::CreateMessage<TensorShapeProto>(arena);
+}
+
+void TensorShapeProto::Clear() {
+// @@protoc_insertion_point(message_clear_start:tensorflow.TensorShapeProto)
+  unknown_rank_ = false;
+  dim_.Clear();
+}
+
+bool TensorShapeProto::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
+  ::google::protobuf::uint32 tag;
+  // @@protoc_insertion_point(parse_start:tensorflow.TensorShapeProto)
+  for (;;) {
+    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+    tag = p.first;
+    if (!p.second) goto handle_unusual;
+    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+      // repeated .tensorflow.TensorShapeProto.Dim dim = 2;
+      case 2: {
+        if (tag == 18) {
+          DO_(input->IncrementRecursionDepth());
+         parse_loop_dim:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth(
+                input, add_dim()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(18)) goto parse_loop_dim;
+        input->UnsafeDecrementRecursionDepth();
+        if (input->ExpectTag(24)) goto parse_unknown_rank;
+        break;
+      }
+
+      // optional bool unknown_rank = 3;
+      case 3: {
+        if (tag == 24) {
+         parse_unknown_rank:
+
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>(
+                 input, &unknown_rank_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectAtEnd()) goto success;
+        break;
+      }
+
+      default: {
+      handle_unusual:
+        if (tag == 0 ||
+            ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+          goto success;
+        }
+        DO_(::google::protobuf::internal::WireFormatLite::SkipField(input, tag));
+        break;
+      }
+    }
+  }
+success:
+  // @@protoc_insertion_point(parse_success:tensorflow.TensorShapeProto)
+  return true;
+failure:
+  // @@protoc_insertion_point(parse_failure:tensorflow.TensorShapeProto)
+  return false;
+#undef DO_
+}
+
+void TensorShapeProto::SerializeWithCachedSizes(
+    ::google::protobuf::io::CodedOutputStream* output) const {
+  // @@protoc_insertion_point(serialize_start:tensorflow.TensorShapeProto)
+  // repeated .tensorflow.TensorShapeProto.Dim dim = 2;
+  for (unsigned int i = 0, n = this->dim_size(); i < n; i++) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      2, this->dim(i), output);
+  }
+
+  // optional bool unknown_rank = 3;
+  if (this->unknown_rank() != 0) {
+    ::google::protobuf::internal::WireFormatLite::WriteBool(3, this->unknown_rank(), output);
+  }
+
+  // @@protoc_insertion_point(serialize_end:tensorflow.TensorShapeProto)
+}
+
+::google::protobuf::uint8* TensorShapeProto::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
+  (void)deterministic; // Unused
+  // @@protoc_insertion_point(serialize_to_array_start:tensorflow.TensorShapeProto)
+  // repeated .tensorflow.TensorShapeProto.Dim dim = 2;
+  for (unsigned int i = 0, n = this->dim_size(); i < n; i++) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        2, this->dim(i), false, target);
+  }
+
+  // optional bool unknown_rank = 3;
+  if (this->unknown_rank() != 0) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(3, this->unknown_rank(), target);
+  }
+
+  // @@protoc_insertion_point(serialize_to_array_end:tensorflow.TensorShapeProto)
+  return target;
+}
+
+size_t TensorShapeProto::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:tensorflow.TensorShapeProto)
+  size_t total_size = 0;
+
+  // optional bool unknown_rank = 3;
+  if (this->unknown_rank() != 0) {
+    total_size += 1 + 1;
+  }
+
+  // repeated .tensorflow.TensorShapeProto.Dim dim = 2;
+  {
+    unsigned int count = this->dim_size();
+    total_size += 1UL * count;
+    for (unsigned int i = 0; i < count; i++) {
+      total_size +=
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          this->dim(i));
+    }
+  }
+
+  int cached_size = ::google::protobuf::internal::ToCachedSize(total_size);
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = cached_size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+  return total_size;
+}
+
+void TensorShapeProto::MergeFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_merge_from_start:tensorflow.TensorShapeProto)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const TensorShapeProto* source =
+      ::google::protobuf::internal::DynamicCastToGenerated<const TensorShapeProto>(
+          &from);
+  if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:tensorflow.TensorShapeProto)
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:tensorflow.TensorShapeProto)
+    UnsafeMergeFrom(*source);
+  }
+}
+
+void TensorShapeProto::MergeFrom(const TensorShapeProto& from) {
+// @@protoc_insertion_point(class_specific_merge_from_start:tensorflow.TensorShapeProto)
+  if (GOOGLE_PREDICT_TRUE(&from != this)) {
+    UnsafeMergeFrom(from);
+  } else {
+    MergeFromFail(__LINE__);
+  }
+}
+
+void TensorShapeProto::UnsafeMergeFrom(const TensorShapeProto& from) {
+  GOOGLE_DCHECK(&from != this);
+  dim_.MergeFrom(from.dim_);
+  if (from.unknown_rank() != 0) {
+    set_unknown_rank(from.unknown_rank());
+  }
+}
+
+void TensorShapeProto::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:tensorflow.TensorShapeProto)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void TensorShapeProto::CopyFrom(const TensorShapeProto& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:tensorflow.TensorShapeProto)
+  if (&from == this) return;
+  Clear();
+  UnsafeMergeFrom(from);
+}
+
+bool TensorShapeProto::IsInitialized() const {
+
+  return true;
+}
+
+void TensorShapeProto::Swap(TensorShapeProto* other) {
+  if (other == this) return;
+  if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) {
+    InternalSwap(other);
+  } else {
+    TensorShapeProto temp;
+    temp.UnsafeMergeFrom(*this);
+    CopyFrom(*other);
+    other->CopyFrom(temp);
+  }
+}
+void TensorShapeProto::UnsafeArenaSwap(TensorShapeProto* other) {
+  if (other == this) return;
+  GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual());
+  InternalSwap(other);
+}
+void TensorShapeProto::InternalSwap(TensorShapeProto* other) {
+  dim_.UnsafeArenaSwap(&other->dim_);
+  std::swap(unknown_rank_, other->unknown_rank_);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
+}
+
+::google::protobuf::Metadata TensorShapeProto::GetMetadata() const {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::Metadata metadata;
+  metadata.descriptor = TensorShapeProto_descriptor_;
+  metadata.reflection = TensorShapeProto_reflection_;
+  return metadata;
+}
+
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// TensorShapeProto_Dim
+
+// optional int64 size = 1;
+void TensorShapeProto_Dim::clear_size() {
+  size_ = GOOGLE_LONGLONG(0);
+}
+::google::protobuf::int64 TensorShapeProto_Dim::size() const {
+  // @@protoc_insertion_point(field_get:tensorflow.TensorShapeProto.Dim.size)
+  return size_;
+}
+void TensorShapeProto_Dim::set_size(::google::protobuf::int64 value) {
+
+  size_ = value;
+  // @@protoc_insertion_point(field_set:tensorflow.TensorShapeProto.Dim.size)
+}
+
+// optional string name = 2;
+void TensorShapeProto_Dim::clear_name() {
+  name_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+const ::std::string& TensorShapeProto_Dim::name() const {
+  // @@protoc_insertion_point(field_get:tensorflow.TensorShapeProto.Dim.name)
+  return name_.Get(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+void TensorShapeProto_Dim::set_name(const ::std::string& value) {
+
+  name_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value, GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set:tensorflow.TensorShapeProto.Dim.name)
+}
+void TensorShapeProto_Dim::set_name(const char* value) {
+
+  name_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value),
+              GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_char:tensorflow.TensorShapeProto.Dim.name)
+}
+void TensorShapeProto_Dim::set_name(const char* value,
+    size_t size) {
+
+  name_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(
+      reinterpret_cast<const char*>(value), size), GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_pointer:tensorflow.TensorShapeProto.Dim.name)
+}
+::std::string* TensorShapeProto_Dim::mutable_name() {
+
+  // @@protoc_insertion_point(field_mutable:tensorflow.TensorShapeProto.Dim.name)
+  return name_.Mutable(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+::std::string* TensorShapeProto_Dim::release_name() {
+  // @@protoc_insertion_point(field_release:tensorflow.TensorShapeProto.Dim.name)
+
+  return name_.Release(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+::std::string* TensorShapeProto_Dim::unsafe_arena_release_name() {
+  // @@protoc_insertion_point(field_unsafe_arena_release:tensorflow.TensorShapeProto.Dim.name)
+  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);
+
+  return name_.UnsafeArenaRelease(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      GetArenaNoVirtual());
+}
+void TensorShapeProto_Dim::set_allocated_name(::std::string* name) {
+  if (name != NULL) {
+
+  } else {
+
+  }
+  name_.SetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), name,
+      GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_allocated:tensorflow.TensorShapeProto.Dim.name)
+}
+void TensorShapeProto_Dim::unsafe_arena_set_allocated_name(
+    ::std::string* name) {
+  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);
+  if (name != NULL) {
+
+  } else {
+
+  }
+  name_.UnsafeArenaSetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      name, GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_unsafe_arena_set_allocated:tensorflow.TensorShapeProto.Dim.name)
+}
+
+inline const TensorShapeProto_Dim* TensorShapeProto_Dim::internal_default_instance() {
+  return &TensorShapeProto_Dim_default_instance_.get();
+}
+// -------------------------------------------------------------------
+
+// TensorShapeProto
+
+// repeated .tensorflow.TensorShapeProto.Dim dim = 2;
+int TensorShapeProto::dim_size() const {
+  return dim_.size();
+}
+void TensorShapeProto::clear_dim() {
+  dim_.Clear();
+}
+const ::tensorflow::TensorShapeProto_Dim& TensorShapeProto::dim(int index) const {
+  // @@protoc_insertion_point(field_get:tensorflow.TensorShapeProto.dim)
+  return dim_.Get(index);
+}
+::tensorflow::TensorShapeProto_Dim* TensorShapeProto::mutable_dim(int index) {
+  // @@protoc_insertion_point(field_mutable:tensorflow.TensorShapeProto.dim)
+  return dim_.Mutable(index);
+}
+::tensorflow::TensorShapeProto_Dim* TensorShapeProto::add_dim() {
+  // @@protoc_insertion_point(field_add:tensorflow.TensorShapeProto.dim)
+  return dim_.Add();
+}
+::google::protobuf::RepeatedPtrField< ::tensorflow::TensorShapeProto_Dim >*
+TensorShapeProto::mutable_dim() {
+  // @@protoc_insertion_point(field_mutable_list:tensorflow.TensorShapeProto.dim)
+  return &dim_;
+}
+const ::google::protobuf::RepeatedPtrField< ::tensorflow::TensorShapeProto_Dim >&
+TensorShapeProto::dim() const {
+  // @@protoc_insertion_point(field_list:tensorflow.TensorShapeProto.dim)
+  return dim_;
+}
+
+// optional bool unknown_rank = 3;
+void TensorShapeProto::clear_unknown_rank() {
+  unknown_rank_ = false;
+}
+bool TensorShapeProto::unknown_rank() const {
+  // @@protoc_insertion_point(field_get:tensorflow.TensorShapeProto.unknown_rank)
+  return unknown_rank_;
+}
+void TensorShapeProto::set_unknown_rank(bool value) {
+
+  unknown_rank_ = value;
+  // @@protoc_insertion_point(field_set:tensorflow.TensorShapeProto.unknown_rank)
+}
+
+inline const TensorShapeProto* TensorShapeProto::internal_default_instance() {
+  return &TensorShapeProto_default_instance_.get();
+}
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
+
+// @@protoc_insertion_point(namespace_scope)
+
+}  // namespace tensorflow
+
+// @@protoc_insertion_point(global_scope)
diff --git a/contrib/modules/dnn/misc/tensorflow/tensor_shape.pb.h b/contrib/modules/dnn/misc/tensorflow/tensor_shape.pb.h
new file mode 100644
index 0000000..df66bfc
--- /dev/null
+++ b/contrib/modules/dnn/misc/tensorflow/tensor_shape.pb.h
@@ -0,0 +1,423 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: tensor_shape.proto
+
+#ifndef PROTOBUF_tensor_5fshape_2eproto__INCLUDED
+#define PROTOBUF_tensor_5fshape_2eproto__INCLUDED
+
+#include <string>
+
+#include <google/protobuf/stubs/common.h>
+
+#if GOOGLE_PROTOBUF_VERSION < 3001000
+#error This file was generated by a newer version of protoc which is
+#error incompatible with your Protocol Buffer headers.  Please update
+#error your headers.
+#endif
+#if 3001000 < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION
+#error This file was generated by an older version of protoc which is
+#error incompatible with your Protocol Buffer headers.  Please
+#error regenerate this file with a newer version of protoc.
+#endif
+
+#include <google/protobuf/arena.h>
+#include <google/protobuf/arenastring.h>
+#include <google/protobuf/generated_message_util.h>
+#include <google/protobuf/metadata.h>
+#include <google/protobuf/message.h>
+#include <google/protobuf/repeated_field.h>
+#include <google/protobuf/extension_set.h>
+#include <google/protobuf/unknown_field_set.h>
+// @@protoc_insertion_point(includes)
+
+namespace tensorflow {
+
+// Internal implementation detail -- do not call these.
+void protobuf_AddDesc_tensor_5fshape_2eproto();
+void protobuf_InitDefaults_tensor_5fshape_2eproto();
+void protobuf_AssignDesc_tensor_5fshape_2eproto();
+void protobuf_ShutdownFile_tensor_5fshape_2eproto();
+
+class TensorShapeProto;
+class TensorShapeProto_Dim;
+
+// ===================================================================
+
+class TensorShapeProto_Dim : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:tensorflow.TensorShapeProto.Dim) */ {
+ public:
+  TensorShapeProto_Dim();
+  virtual ~TensorShapeProto_Dim();
+
+  TensorShapeProto_Dim(const TensorShapeProto_Dim& from);
+
+  inline TensorShapeProto_Dim& operator=(const TensorShapeProto_Dim& from) {
+    CopyFrom(from);
+    return *this;
+  }
+
+  inline ::google::protobuf::Arena* GetArena() const { return GetArenaNoVirtual(); }
+  inline void* GetMaybeArenaPointer() const {
+    return MaybeArenaPtr();
+  }
+  static const ::google::protobuf::Descriptor* descriptor();
+  static const TensorShapeProto_Dim& default_instance();
+
+  static const TensorShapeProto_Dim* internal_default_instance();
+
+  void UnsafeArenaSwap(TensorShapeProto_Dim* other);
+  void Swap(TensorShapeProto_Dim* other);
+
+  // implements Message ----------------------------------------------
+
+  inline TensorShapeProto_Dim* New() const { return New(NULL); }
+
+  TensorShapeProto_Dim* New(::google::protobuf::Arena* arena) const;
+  void CopyFrom(const ::google::protobuf::Message& from);
+  void MergeFrom(const ::google::protobuf::Message& from);
+  void CopyFrom(const TensorShapeProto_Dim& from);
+  void MergeFrom(const TensorShapeProto_Dim& from);
+  void Clear();
+  bool IsInitialized() const;
+
+  size_t ByteSizeLong() const;
+  bool MergePartialFromCodedStream(
+      ::google::protobuf::io::CodedInputStream* input);
+  void SerializeWithCachedSizes(
+      ::google::protobuf::io::CodedOutputStream* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
+  int GetCachedSize() const { return _cached_size_; }
+  private:
+  void SharedCtor();
+  void SharedDtor();
+  void SetCachedSize(int size) const;
+  void InternalSwap(TensorShapeProto_Dim* other);
+  void UnsafeMergeFrom(const TensorShapeProto_Dim& from);
+  protected:
+  explicit TensorShapeProto_Dim(::google::protobuf::Arena* arena);
+  private:
+  static void ArenaDtor(void* object);
+  inline void RegisterArenaDtor(::google::protobuf::Arena* arena);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
+  public:
+
+  ::google::protobuf::Metadata GetMetadata() const;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  // optional int64 size = 1;
+  void clear_size();
+  static const int kSizeFieldNumber = 1;
+  ::google::protobuf::int64 size() const;
+  void set_size(::google::protobuf::int64 value);
+
+  // optional string name = 2;
+  void clear_name();
+  static const int kNameFieldNumber = 2;
+  const ::std::string& name() const;
+  void set_name(const ::std::string& value);
+  void set_name(const char* value);
+  void set_name(const char* value, size_t size);
+  ::std::string* mutable_name();
+  ::std::string* release_name();
+  void set_allocated_name(::std::string* name);
+  ::std::string* unsafe_arena_release_name();
+  void unsafe_arena_set_allocated_name(
+      ::std::string* name);
+
+  // @@protoc_insertion_point(class_scope:tensorflow.TensorShapeProto.Dim)
+ private:
+
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  friend class ::google::protobuf::Arena;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  ::google::protobuf::internal::ArenaStringPtr name_;
+  ::google::protobuf::int64 size_;
+  mutable int _cached_size_;
+  friend void  protobuf_InitDefaults_tensor_5fshape_2eproto_impl();
+  friend void  protobuf_AddDesc_tensor_5fshape_2eproto_impl();
+  friend void protobuf_AssignDesc_tensor_5fshape_2eproto();
+  friend void protobuf_ShutdownFile_tensor_5fshape_2eproto();
+
+  void InitAsDefaultInstance();
+};
+extern ::google::protobuf::internal::ExplicitlyConstructed<TensorShapeProto_Dim> TensorShapeProto_Dim_default_instance_;
+
+// -------------------------------------------------------------------
+
+class TensorShapeProto : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:tensorflow.TensorShapeProto) */ {
+ public:
+  TensorShapeProto();
+  virtual ~TensorShapeProto();
+
+  TensorShapeProto(const TensorShapeProto& from);
+
+  inline TensorShapeProto& operator=(const TensorShapeProto& from) {
+    CopyFrom(from);
+    return *this;
+  }
+
+  inline ::google::protobuf::Arena* GetArena() const { return GetArenaNoVirtual(); }
+  inline void* GetMaybeArenaPointer() const {
+    return MaybeArenaPtr();
+  }
+  static const ::google::protobuf::Descriptor* descriptor();
+  static const TensorShapeProto& default_instance();
+
+  static const TensorShapeProto* internal_default_instance();
+
+  void UnsafeArenaSwap(TensorShapeProto* other);
+  void Swap(TensorShapeProto* other);
+
+  // implements Message ----------------------------------------------
+
+  inline TensorShapeProto* New() const { return New(NULL); }
+
+  TensorShapeProto* New(::google::protobuf::Arena* arena) const;
+  void CopyFrom(const ::google::protobuf::Message& from);
+  void MergeFrom(const ::google::protobuf::Message& from);
+  void CopyFrom(const TensorShapeProto& from);
+  void MergeFrom(const TensorShapeProto& from);
+  void Clear();
+  bool IsInitialized() const;
+
+  size_t ByteSizeLong() const;
+  bool MergePartialFromCodedStream(
+      ::google::protobuf::io::CodedInputStream* input);
+  void SerializeWithCachedSizes(
+      ::google::protobuf::io::CodedOutputStream* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
+  int GetCachedSize() const { return _cached_size_; }
+  private:
+  void SharedCtor();
+  void SharedDtor();
+  void SetCachedSize(int size) const;
+  void InternalSwap(TensorShapeProto* other);
+  void UnsafeMergeFrom(const TensorShapeProto& from);
+  protected:
+  explicit TensorShapeProto(::google::protobuf::Arena* arena);
+  private:
+  static void ArenaDtor(void* object);
+  inline void RegisterArenaDtor(::google::protobuf::Arena* arena);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
+  public:
+
+  ::google::protobuf::Metadata GetMetadata() const;
+
+  // nested types ----------------------------------------------------
+
+  typedef TensorShapeProto_Dim Dim;
+
+  // accessors -------------------------------------------------------
+
+  // repeated .tensorflow.TensorShapeProto.Dim dim = 2;
+  int dim_size() const;
+  void clear_dim();
+  static const int kDimFieldNumber = 2;
+  const ::tensorflow::TensorShapeProto_Dim& dim(int index) const;
+  ::tensorflow::TensorShapeProto_Dim* mutable_dim(int index);
+  ::tensorflow::TensorShapeProto_Dim* add_dim();
+  ::google::protobuf::RepeatedPtrField< ::tensorflow::TensorShapeProto_Dim >*
+      mutable_dim();
+  const ::google::protobuf::RepeatedPtrField< ::tensorflow::TensorShapeProto_Dim >&
+      dim() const;
+
+  // optional bool unknown_rank = 3;
+  void clear_unknown_rank();
+  static const int kUnknownRankFieldNumber = 3;
+  bool unknown_rank() const;
+  void set_unknown_rank(bool value);
+
+  // @@protoc_insertion_point(class_scope:tensorflow.TensorShapeProto)
+ private:
+
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  friend class ::google::protobuf::Arena;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  ::google::protobuf::RepeatedPtrField< ::tensorflow::TensorShapeProto_Dim > dim_;
+  bool unknown_rank_;
+  mutable int _cached_size_;
+  friend void  protobuf_InitDefaults_tensor_5fshape_2eproto_impl();
+  friend void  protobuf_AddDesc_tensor_5fshape_2eproto_impl();
+  friend void protobuf_AssignDesc_tensor_5fshape_2eproto();
+  friend void protobuf_ShutdownFile_tensor_5fshape_2eproto();
+
+  void InitAsDefaultInstance();
+};
+extern ::google::protobuf::internal::ExplicitlyConstructed<TensorShapeProto> TensorShapeProto_default_instance_;
+
+// ===================================================================
+
+
+// ===================================================================
+
+#if !PROTOBUF_INLINE_NOT_IN_HEADERS
+// TensorShapeProto_Dim
+
+// optional int64 size = 1;
+inline void TensorShapeProto_Dim::clear_size() {
+  size_ = GOOGLE_LONGLONG(0);
+}
+inline ::google::protobuf::int64 TensorShapeProto_Dim::size() const {
+  // @@protoc_insertion_point(field_get:tensorflow.TensorShapeProto.Dim.size)
+  return size_;
+}
+inline void TensorShapeProto_Dim::set_size(::google::protobuf::int64 value) {
+
+  size_ = value;
+  // @@protoc_insertion_point(field_set:tensorflow.TensorShapeProto.Dim.size)
+}
+
+// optional string name = 2;
+inline void TensorShapeProto_Dim::clear_name() {
+  name_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+inline const ::std::string& TensorShapeProto_Dim::name() const {
+  // @@protoc_insertion_point(field_get:tensorflow.TensorShapeProto.Dim.name)
+  return name_.Get(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+}
+inline void TensorShapeProto_Dim::set_name(const ::std::string& value) {
+
+  name_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value, GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set:tensorflow.TensorShapeProto.Dim.name)
+}
+inline void TensorShapeProto_Dim::set_name(const char* value) {
+
+  name_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value),
+              GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_char:tensorflow.TensorShapeProto.Dim.name)
+}
+inline void TensorShapeProto_Dim::set_name(const char* value,
+    size_t size) {
+
+  name_.Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(
+      reinterpret_cast<const char*>(value), size), GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_pointer:tensorflow.TensorShapeProto.Dim.name)
+}
+inline ::std::string* TensorShapeProto_Dim::mutable_name() {
+
+  // @@protoc_insertion_point(field_mutable:tensorflow.TensorShapeProto.Dim.name)
+  return name_.Mutable(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+inline ::std::string* TensorShapeProto_Dim::release_name() {
+  // @@protoc_insertion_point(field_release:tensorflow.TensorShapeProto.Dim.name)
+
+  return name_.Release(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual());
+}
+inline ::std::string* TensorShapeProto_Dim::unsafe_arena_release_name() {
+  // @@protoc_insertion_point(field_unsafe_arena_release:tensorflow.TensorShapeProto.Dim.name)
+  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);
+
+  return name_.UnsafeArenaRelease(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      GetArenaNoVirtual());
+}
+inline void TensorShapeProto_Dim::set_allocated_name(::std::string* name) {
+  if (name != NULL) {
+
+  } else {
+
+  }
+  name_.SetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), name,
+      GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_set_allocated:tensorflow.TensorShapeProto.Dim.name)
+}
+inline void TensorShapeProto_Dim::unsafe_arena_set_allocated_name(
+    ::std::string* name) {
+  GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);
+  if (name != NULL) {
+
+  } else {
+
+  }
+  name_.UnsafeArenaSetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),
+      name, GetArenaNoVirtual());
+  // @@protoc_insertion_point(field_unsafe_arena_set_allocated:tensorflow.TensorShapeProto.Dim.name)
+}
+
+inline const TensorShapeProto_Dim* TensorShapeProto_Dim::internal_default_instance() {
+  return &TensorShapeProto_Dim_default_instance_.get();
+}
+// -------------------------------------------------------------------
+
+// TensorShapeProto
+
+// repeated .tensorflow.TensorShapeProto.Dim dim = 2;
+inline int TensorShapeProto::dim_size() const {
+  return dim_.size();
+}
+inline void TensorShapeProto::clear_dim() {
+  dim_.Clear();
+}
+inline const ::tensorflow::TensorShapeProto_Dim& TensorShapeProto::dim(int index) const {
+  // @@protoc_insertion_point(field_get:tensorflow.TensorShapeProto.dim)
+  return dim_.Get(index);
+}
+inline ::tensorflow::TensorShapeProto_Dim* TensorShapeProto::mutable_dim(int index) {
+  // @@protoc_insertion_point(field_mutable:tensorflow.TensorShapeProto.dim)
+  return dim_.Mutable(index);
+}
+inline ::tensorflow::TensorShapeProto_Dim* TensorShapeProto::add_dim() {
+  // @@protoc_insertion_point(field_add:tensorflow.TensorShapeProto.dim)
+  return dim_.Add();
+}
+inline ::google::protobuf::RepeatedPtrField< ::tensorflow::TensorShapeProto_Dim >*
+TensorShapeProto::mutable_dim() {
+  // @@protoc_insertion_point(field_mutable_list:tensorflow.TensorShapeProto.dim)
+  return &dim_;
+}
+inline const ::google::protobuf::RepeatedPtrField< ::tensorflow::TensorShapeProto_Dim >&
+TensorShapeProto::dim() const {
+  // @@protoc_insertion_point(field_list:tensorflow.TensorShapeProto.dim)
+  return dim_;
+}
+
+// optional bool unknown_rank = 3;
+inline void TensorShapeProto::clear_unknown_rank() {
+  unknown_rank_ = false;
+}
+inline bool TensorShapeProto::unknown_rank() const {
+  // @@protoc_insertion_point(field_get:tensorflow.TensorShapeProto.unknown_rank)
+  return unknown_rank_;
+}
+inline void TensorShapeProto::set_unknown_rank(bool value) {
+
+  unknown_rank_ = value;
+  // @@protoc_insertion_point(field_set:tensorflow.TensorShapeProto.unknown_rank)
+}
+
+inline const TensorShapeProto* TensorShapeProto::internal_default_instance() {
+  return &TensorShapeProto_default_instance_.get();
+}
+#endif  // !PROTOBUF_INLINE_NOT_IN_HEADERS
+// -------------------------------------------------------------------
+
+
+// @@protoc_insertion_point(namespace_scope)
+
+}  // namespace tensorflow
+
+// @@protoc_insertion_point(global_scope)
+
+#endif  // PROTOBUF_tensor_5fshape_2eproto__INCLUDED
diff --git a/contrib/modules/dnn/misc/tensorflow/types.pb.cc b/contrib/modules/dnn/misc/tensorflow/types.pb.cc
new file mode 100644
index 0000000..0e509cc
--- /dev/null
+++ b/contrib/modules/dnn/misc/tensorflow/types.pb.cc
@@ -0,0 +1,163 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: types.proto
+
+#define INTERNAL_SUPPRESS_PROTOBUF_FIELD_DEPRECATION
+#include "types.pb.h"
+
+#include <algorithm>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/port.h>
+#include <google/protobuf/stubs/once.h>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/wire_format_lite_inl.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/generated_message_reflection.h>
+#include <google/protobuf/reflection_ops.h>
+#include <google/protobuf/wire_format.h>
+// @@protoc_insertion_point(includes)
+
+namespace tensorflow {
+
+namespace {
+
+const ::google::protobuf::EnumDescriptor* DataType_descriptor_ = NULL;
+
+}  // namespace
+
+
+void protobuf_AssignDesc_types_2eproto() GOOGLE_ATTRIBUTE_COLD;
+void protobuf_AssignDesc_types_2eproto() {
+  protobuf_AddDesc_types_2eproto();
+  const ::google::protobuf::FileDescriptor* file =
+    ::google::protobuf::DescriptorPool::generated_pool()->FindFileByName(
+      "types.proto");
+  GOOGLE_CHECK(file != NULL);
+  DataType_descriptor_ = file->enum_type(0);
+}
+
+namespace {
+
+GOOGLE_PROTOBUF_DECLARE_ONCE(protobuf_AssignDescriptors_once_);
+void protobuf_AssignDescriptorsOnce() {
+  ::google::protobuf::GoogleOnceInit(&protobuf_AssignDescriptors_once_,
+                 &protobuf_AssignDesc_types_2eproto);
+}
+
+void protobuf_RegisterTypes(const ::std::string&) GOOGLE_ATTRIBUTE_COLD;
+void protobuf_RegisterTypes(const ::std::string&) {
+  protobuf_AssignDescriptorsOnce();
+}
+
+}  // namespace
+
+void protobuf_ShutdownFile_types_2eproto() {
+}
+
+void protobuf_InitDefaults_types_2eproto_impl() {
+  GOOGLE_PROTOBUF_VERIFY_VERSION;
+
+}
+
+GOOGLE_PROTOBUF_DECLARE_ONCE(protobuf_InitDefaults_types_2eproto_once_);
+void protobuf_InitDefaults_types_2eproto() {
+  ::google::protobuf::GoogleOnceInit(&protobuf_InitDefaults_types_2eproto_once_,
+                 &protobuf_InitDefaults_types_2eproto_impl);
+}
+void protobuf_AddDesc_types_2eproto_impl() {
+  GOOGLE_PROTOBUF_VERIFY_VERSION;
+
+  protobuf_InitDefaults_types_2eproto();
+  ::google::protobuf::DescriptorPool::InternalAddGeneratedFile(
+    "\n\013types.proto\022\ntensorflow*\234\005\n\010DataType\022\016"
+    "\n\nDT_INVALID\020\000\022\014\n\010DT_FLOAT\020\001\022\r\n\tDT_DOUBL"
+    "E\020\002\022\014\n\010DT_INT32\020\003\022\014\n\010DT_UINT8\020\004\022\014\n\010DT_IN"
+    "T16\020\005\022\013\n\007DT_INT8\020\006\022\r\n\tDT_STRING\020\007\022\020\n\014DT_"
+    "COMPLEX64\020\010\022\014\n\010DT_INT64\020\t\022\013\n\007DT_BOOL\020\n\022\014"
+    "\n\010DT_QINT8\020\013\022\r\n\tDT_QUINT8\020\014\022\r\n\tDT_QINT32"
+    "\020\r\022\017\n\013DT_BFLOAT16\020\016\022\r\n\tDT_QINT16\020\017\022\016\n\nDT"
+    "_QUINT16\020\020\022\r\n\tDT_UINT16\020\021\022\021\n\rDT_COMPLEX1"
+    "28\020\022\022\013\n\007DT_HALF\020\023\022\020\n\014DT_FLOAT_REF\020e\022\021\n\rD"
+    "T_DOUBLE_REF\020f\022\020\n\014DT_INT32_REF\020g\022\020\n\014DT_U"
+    "INT8_REF\020h\022\020\n\014DT_INT16_REF\020i\022\017\n\013DT_INT8_"
+    "REF\020j\022\021\n\rDT_STRING_REF\020k\022\024\n\020DT_COMPLEX64"
+    "_REF\020l\022\020\n\014DT_INT64_REF\020m\022\017\n\013DT_BOOL_REF\020"
+    "n\022\020\n\014DT_QINT8_REF\020o\022\021\n\rDT_QUINT8_REF\020p\022\021"
+    "\n\rDT_QINT32_REF\020q\022\023\n\017DT_BFLOAT16_REF\020r\022\021"
+    "\n\rDT_QINT16_REF\020s\022\022\n\016DT_QUINT16_REF\020t\022\021\n"
+    "\rDT_UINT16_REF\020u\022\025\n\021DT_COMPLEX128_REF\020v\022"
+    "\017\n\013DT_HALF_REF\020wB,\n\030org.tensorflow.frame"
+    "workB\013TypesProtosP\001\370\001\001b\006proto3", 750);
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedFile(
+    "types.proto", &protobuf_RegisterTypes);
+  ::google::protobuf::internal::OnShutdown(&protobuf_ShutdownFile_types_2eproto);
+}
+
+GOOGLE_PROTOBUF_DECLARE_ONCE(protobuf_AddDesc_types_2eproto_once_);
+void protobuf_AddDesc_types_2eproto() {
+  ::google::protobuf::GoogleOnceInit(&protobuf_AddDesc_types_2eproto_once_,
+                 &protobuf_AddDesc_types_2eproto_impl);
+}
+// Force AddDescriptors() to be called at static initialization time.
+struct StaticDescriptorInitializer_types_2eproto {
+  StaticDescriptorInitializer_types_2eproto() {
+    protobuf_AddDesc_types_2eproto();
+  }
+} static_descriptor_initializer_types_2eproto_;
+const ::google::protobuf::EnumDescriptor* DataType_descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return DataType_descriptor_;
+}
+bool DataType_IsValid(int value) {
+  switch (value) {
+    case 0:
+    case 1:
+    case 2:
+    case 3:
+    case 4:
+    case 5:
+    case 6:
+    case 7:
+    case 8:
+    case 9:
+    case 10:
+    case 11:
+    case 12:
+    case 13:
+    case 14:
+    case 15:
+    case 16:
+    case 17:
+    case 18:
+    case 19:
+    case 101:
+    case 102:
+    case 103:
+    case 104:
+    case 105:
+    case 106:
+    case 107:
+    case 108:
+    case 109:
+    case 110:
+    case 111:
+    case 112:
+    case 113:
+    case 114:
+    case 115:
+    case 116:
+    case 117:
+    case 118:
+    case 119:
+      return true;
+    default:
+      return false;
+  }
+}
+
+
+// @@protoc_insertion_point(namespace_scope)
+
+}  // namespace tensorflow
+
+// @@protoc_insertion_point(global_scope)
diff --git a/contrib/modules/dnn/misc/tensorflow/types.pb.h b/contrib/modules/dnn/misc/tensorflow/types.pb.h
new file mode 100644
index 0000000..40ed7b8
--- /dev/null
+++ b/contrib/modules/dnn/misc/tensorflow/types.pb.h
@@ -0,0 +1,129 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: types.proto
+
+#ifndef PROTOBUF_types_2eproto__INCLUDED
+#define PROTOBUF_types_2eproto__INCLUDED
+
+#include <string>
+
+#include <google/protobuf/stubs/common.h>
+
+#if GOOGLE_PROTOBUF_VERSION < 3001000
+#error This file was generated by a newer version of protoc which is
+#error incompatible with your Protocol Buffer headers.  Please update
+#error your headers.
+#endif
+#if 3001000 < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION
+#error This file was generated by an older version of protoc which is
+#error incompatible with your Protocol Buffer headers.  Please
+#error regenerate this file with a newer version of protoc.
+#endif
+
+#include <google/protobuf/arena.h>
+#include <google/protobuf/arenastring.h>
+#include <google/protobuf/generated_message_util.h>
+#include <google/protobuf/metadata.h>
+#include <google/protobuf/repeated_field.h>
+#include <google/protobuf/extension_set.h>
+#include <google/protobuf/generated_enum_reflection.h>
+// @@protoc_insertion_point(includes)
+
+namespace tensorflow {
+
+// Internal implementation detail -- do not call these.
+void protobuf_AddDesc_types_2eproto();
+void protobuf_InitDefaults_types_2eproto();
+void protobuf_AssignDesc_types_2eproto();
+void protobuf_ShutdownFile_types_2eproto();
+
+
+enum DataType {
+  DT_INVALID = 0,
+  DT_FLOAT = 1,
+  DT_DOUBLE = 2,
+  DT_INT32 = 3,
+  DT_UINT8 = 4,
+  DT_INT16 = 5,
+  DT_INT8 = 6,
+  DT_STRING = 7,
+  DT_COMPLEX64 = 8,
+  DT_INT64 = 9,
+  DT_BOOL = 10,
+  DT_QINT8 = 11,
+  DT_QUINT8 = 12,
+  DT_QINT32 = 13,
+  DT_BFLOAT16 = 14,
+  DT_QINT16 = 15,
+  DT_QUINT16 = 16,
+  DT_UINT16 = 17,
+  DT_COMPLEX128 = 18,
+  DT_HALF = 19,
+  DT_FLOAT_REF = 101,
+  DT_DOUBLE_REF = 102,
+  DT_INT32_REF = 103,
+  DT_UINT8_REF = 104,
+  DT_INT16_REF = 105,
+  DT_INT8_REF = 106,
+  DT_STRING_REF = 107,
+  DT_COMPLEX64_REF = 108,
+  DT_INT64_REF = 109,
+  DT_BOOL_REF = 110,
+  DT_QINT8_REF = 111,
+  DT_QUINT8_REF = 112,
+  DT_QINT32_REF = 113,
+  DT_BFLOAT16_REF = 114,
+  DT_QINT16_REF = 115,
+  DT_QUINT16_REF = 116,
+  DT_UINT16_REF = 117,
+  DT_COMPLEX128_REF = 118,
+  DT_HALF_REF = 119,
+  DataType_INT_MIN_SENTINEL_DO_NOT_USE_ = ::google::protobuf::kint32min,
+  DataType_INT_MAX_SENTINEL_DO_NOT_USE_ = ::google::protobuf::kint32max
+};
+bool DataType_IsValid(int value);
+const DataType DataType_MIN = DT_INVALID;
+const DataType DataType_MAX = DT_HALF_REF;
+const int DataType_ARRAYSIZE = DataType_MAX + 1;
+
+const ::google::protobuf::EnumDescriptor* DataType_descriptor();
+inline const ::std::string& DataType_Name(DataType value) {
+  return ::google::protobuf::internal::NameOfEnum(
+    DataType_descriptor(), value);
+}
+inline bool DataType_Parse(
+    const ::std::string& name, DataType* value) {
+  return ::google::protobuf::internal::ParseNamedEnum<DataType>(
+    DataType_descriptor(), name, value);
+}
+// ===================================================================
+
+
+// ===================================================================
+
+
+// ===================================================================
+
+#if !PROTOBUF_INLINE_NOT_IN_HEADERS
+#endif  // !PROTOBUF_INLINE_NOT_IN_HEADERS
+
+// @@protoc_insertion_point(namespace_scope)
+
+}  // namespace tensorflow
+
+#ifndef SWIG
+namespace google {
+namespace protobuf {
+
+template <> struct is_proto_enum< ::tensorflow::DataType> : ::google::protobuf::internal::true_type {};
+template <>
+inline const EnumDescriptor* GetEnumDescriptor< ::tensorflow::DataType>() {
+  return ::tensorflow::DataType_descriptor();
+}
+
+}  // namespace protobuf
+}  // namespace google
+#endif  // SWIG
+
+// @@protoc_insertion_point(global_scope)
+
+#endif  // PROTOBUF_types_2eproto__INCLUDED
diff --git a/contrib/modules/dnn/misc/tensorflow/versions.pb.cc b/contrib/modules/dnn/misc/tensorflow/versions.pb.cc
new file mode 100644
index 0000000..a4556a0
--- /dev/null
+++ b/contrib/modules/dnn/misc/tensorflow/versions.pb.cc
@@ -0,0 +1,572 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: versions.proto
+
+#define INTERNAL_SUPPRESS_PROTOBUF_FIELD_DEPRECATION
+#include "versions.pb.h"
+
+#include <algorithm>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/port.h>
+#include <google/protobuf/stubs/once.h>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/wire_format_lite_inl.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/generated_message_reflection.h>
+#include <google/protobuf/reflection_ops.h>
+#include <google/protobuf/wire_format.h>
+// @@protoc_insertion_point(includes)
+
+namespace tensorflow {
+
+namespace {
+
+const ::google::protobuf::Descriptor* VersionDef_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+  VersionDef_reflection_ = NULL;
+
+}  // namespace
+
+
+void protobuf_AssignDesc_versions_2eproto() GOOGLE_ATTRIBUTE_COLD;
+void protobuf_AssignDesc_versions_2eproto() {
+  protobuf_AddDesc_versions_2eproto();
+  const ::google::protobuf::FileDescriptor* file =
+    ::google::protobuf::DescriptorPool::generated_pool()->FindFileByName(
+      "versions.proto");
+  GOOGLE_CHECK(file != NULL);
+  VersionDef_descriptor_ = file->message_type(0);
+  static const int VersionDef_offsets_[3] = {
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(VersionDef, producer_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(VersionDef, min_consumer_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(VersionDef, bad_consumers_),
+  };
+  VersionDef_reflection_ =
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
+      VersionDef_descriptor_,
+      VersionDef::internal_default_instance(),
+      VersionDef_offsets_,
+      -1,
+      -1,
+      -1,
+      sizeof(VersionDef),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(VersionDef, _internal_metadata_));
+}
+
+namespace {
+
+GOOGLE_PROTOBUF_DECLARE_ONCE(protobuf_AssignDescriptors_once_);
+void protobuf_AssignDescriptorsOnce() {
+  ::google::protobuf::GoogleOnceInit(&protobuf_AssignDescriptors_once_,
+                 &protobuf_AssignDesc_versions_2eproto);
+}
+
+void protobuf_RegisterTypes(const ::std::string&) GOOGLE_ATTRIBUTE_COLD;
+void protobuf_RegisterTypes(const ::std::string&) {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+      VersionDef_descriptor_, VersionDef::internal_default_instance());
+}
+
+}  // namespace
+
+void protobuf_ShutdownFile_versions_2eproto() {
+  VersionDef_default_instance_.Shutdown();
+  delete VersionDef_reflection_;
+}
+
+void protobuf_InitDefaults_versions_2eproto_impl() {
+  GOOGLE_PROTOBUF_VERIFY_VERSION;
+
+  VersionDef_default_instance_.DefaultConstruct();
+  VersionDef_default_instance_.get_mutable()->InitAsDefaultInstance();
+}
+
+GOOGLE_PROTOBUF_DECLARE_ONCE(protobuf_InitDefaults_versions_2eproto_once_);
+void protobuf_InitDefaults_versions_2eproto() {
+  ::google::protobuf::GoogleOnceInit(&protobuf_InitDefaults_versions_2eproto_once_,
+                 &protobuf_InitDefaults_versions_2eproto_impl);
+}
+void protobuf_AddDesc_versions_2eproto_impl() {
+  GOOGLE_PROTOBUF_VERIFY_VERSION;
+
+  protobuf_InitDefaults_versions_2eproto();
+  ::google::protobuf::DescriptorPool::InternalAddGeneratedFile(
+    "\n\016versions.proto\022\ntensorflow\"K\n\nVersionD"
+    "ef\022\020\n\010producer\030\001 \001(\005\022\024\n\014min_consumer\030\002 \001"
+    "(\005\022\025\n\rbad_consumers\030\003 \003(\005B/\n\030org.tensorf"
+    "low.frameworkB\016VersionsProtosP\001\370\001\001b\006prot"
+    "o3", 162);
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedFile(
+    "versions.proto", &protobuf_RegisterTypes);
+  ::google::protobuf::internal::OnShutdown(&protobuf_ShutdownFile_versions_2eproto);
+}
+
+GOOGLE_PROTOBUF_DECLARE_ONCE(protobuf_AddDesc_versions_2eproto_once_);
+void protobuf_AddDesc_versions_2eproto() {
+  ::google::protobuf::GoogleOnceInit(&protobuf_AddDesc_versions_2eproto_once_,
+                 &protobuf_AddDesc_versions_2eproto_impl);
+}
+// Force AddDescriptors() to be called at static initialization time.
+struct StaticDescriptorInitializer_versions_2eproto {
+  StaticDescriptorInitializer_versions_2eproto() {
+    protobuf_AddDesc_versions_2eproto();
+  }
+} static_descriptor_initializer_versions_2eproto_;
+
+namespace {
+
+static void MergeFromFail(int line) GOOGLE_ATTRIBUTE_COLD GOOGLE_ATTRIBUTE_NORETURN;
+static void MergeFromFail(int line) {
+  ::google::protobuf::internal::MergeFromFail(__FILE__, line);
+}
+
+}  // namespace
+
+
+// ===================================================================
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const int VersionDef::kProducerFieldNumber;
+const int VersionDef::kMinConsumerFieldNumber;
+const int VersionDef::kBadConsumersFieldNumber;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+
+VersionDef::VersionDef()
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+  if (this != internal_default_instance()) protobuf_InitDefaults_versions_2eproto();
+  SharedCtor();
+  // @@protoc_insertion_point(constructor:tensorflow.VersionDef)
+}
+VersionDef::VersionDef(::google::protobuf::Arena* arena)
+  : ::google::protobuf::Message(),
+  _internal_metadata_(arena),
+  bad_consumers_(arena) {
+#ifdef GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER
+  protobuf_InitDefaults_versions_2eproto();
+#endif  // GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER
+  SharedCtor();
+  RegisterArenaDtor(arena);
+  // @@protoc_insertion_point(arena_constructor:tensorflow.VersionDef)
+}
+
+void VersionDef::InitAsDefaultInstance() {
+}
+
+VersionDef::VersionDef(const VersionDef& from)
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
+  SharedCtor();
+  UnsafeMergeFrom(from);
+  // @@protoc_insertion_point(copy_constructor:tensorflow.VersionDef)
+}
+
+void VersionDef::SharedCtor() {
+  ::memset(&producer_, 0, reinterpret_cast<char*>(&min_consumer_) -
+    reinterpret_cast<char*>(&producer_) + sizeof(min_consumer_));
+  _cached_size_ = 0;
+}
+
+VersionDef::~VersionDef() {
+  // @@protoc_insertion_point(destructor:tensorflow.VersionDef)
+  SharedDtor();
+}
+
+void VersionDef::SharedDtor() {
+  ::google::protobuf::Arena* arena = GetArenaNoVirtual();
+  if (arena != NULL) {
+    return;
+  }
+
+}
+
+void VersionDef::ArenaDtor(void* object) {
+  VersionDef* _this = reinterpret_cast< VersionDef* >(object);
+  (void)_this;
+}
+void VersionDef::RegisterArenaDtor(::google::protobuf::Arena* arena) {
+}
+void VersionDef::SetCachedSize(int size) const {
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* VersionDef::descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return VersionDef_descriptor_;
+}
+
+const VersionDef& VersionDef::default_instance() {
+  protobuf_InitDefaults_versions_2eproto();
+  return *internal_default_instance();
+}
+
+::google::protobuf::internal::ExplicitlyConstructed<VersionDef> VersionDef_default_instance_;
+
+VersionDef* VersionDef::New(::google::protobuf::Arena* arena) const {
+  return ::google::protobuf::Arena::CreateMessage<VersionDef>(arena);
+}
+
+void VersionDef::Clear() {
+// @@protoc_insertion_point(message_clear_start:tensorflow.VersionDef)
+#if defined(__clang__)
+#define ZR_HELPER_(f) \
+  _Pragma("clang diagnostic push") \
+  _Pragma("clang diagnostic ignored \"-Winvalid-offsetof\"") \
+  __builtin_offsetof(VersionDef, f) \
+  _Pragma("clang diagnostic pop")
+#else
+#define ZR_HELPER_(f) reinterpret_cast<char*>(\
+  &reinterpret_cast<VersionDef*>(16)->f)
+#endif
+
+#define ZR_(first, last) do {\
+  ::memset(&(first), 0,\
+           ZR_HELPER_(last) - ZR_HELPER_(first) + sizeof(last));\
+} while (0)
+
+  ZR_(producer_, min_consumer_);
+
+#undef ZR_HELPER_
+#undef ZR_
+
+  bad_consumers_.Clear();
+}
+
+bool VersionDef::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
+  ::google::protobuf::uint32 tag;
+  // @@protoc_insertion_point(parse_start:tensorflow.VersionDef)
+  for (;;) {
+    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127);
+    tag = p.first;
+    if (!p.second) goto handle_unusual;
+    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+      // optional int32 producer = 1;
+      case 1: {
+        if (tag == 8) {
+
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
+                 input, &producer_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(16)) goto parse_min_consumer;
+        break;
+      }
+
+      // optional int32 min_consumer = 2;
+      case 2: {
+        if (tag == 16) {
+         parse_min_consumer:
+
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
+                 input, &min_consumer_)));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(26)) goto parse_bad_consumers;
+        break;
+      }
+
+      // repeated int32 bad_consumers = 3;
+      case 3: {
+        if (tag == 26) {
+         parse_bad_consumers:
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPackedPrimitive<
+                   ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
+                 input, this->mutable_bad_consumers())));
+        } else if (tag == 24) {
+          DO_((::google::protobuf::internal::WireFormatLite::ReadRepeatedPrimitiveNoInline<
+                   ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
+                 1, 26, input, this->mutable_bad_consumers())));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectAtEnd()) goto success;
+        break;
+      }
+
+      default: {
+      handle_unusual:
+        if (tag == 0 ||
+            ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+          goto success;
+        }
+        DO_(::google::protobuf::internal::WireFormatLite::SkipField(input, tag));
+        break;
+      }
+    }
+  }
+success:
+  // @@protoc_insertion_point(parse_success:tensorflow.VersionDef)
+  return true;
+failure:
+  // @@protoc_insertion_point(parse_failure:tensorflow.VersionDef)
+  return false;
+#undef DO_
+}
+
+void VersionDef::SerializeWithCachedSizes(
+    ::google::protobuf::io::CodedOutputStream* output) const {
+  // @@protoc_insertion_point(serialize_start:tensorflow.VersionDef)
+  // optional int32 producer = 1;
+  if (this->producer() != 0) {
+    ::google::protobuf::internal::WireFormatLite::WriteInt32(1, this->producer(), output);
+  }
+
+  // optional int32 min_consumer = 2;
+  if (this->min_consumer() != 0) {
+    ::google::protobuf::internal::WireFormatLite::WriteInt32(2, this->min_consumer(), output);
+  }
+
+  // repeated int32 bad_consumers = 3;
+  if (this->bad_consumers_size() > 0) {
+    ::google::protobuf::internal::WireFormatLite::WriteTag(3, ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED, output);
+    output->WriteVarint32(_bad_consumers_cached_byte_size_);
+  }
+  for (int i = 0; i < this->bad_consumers_size(); i++) {
+    ::google::protobuf::internal::WireFormatLite::WriteInt32NoTag(
+      this->bad_consumers(i), output);
+  }
+
+  // @@protoc_insertion_point(serialize_end:tensorflow.VersionDef)
+}
+
+::google::protobuf::uint8* VersionDef::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
+  (void)deterministic; // Unused
+  // @@protoc_insertion_point(serialize_to_array_start:tensorflow.VersionDef)
+  // optional int32 producer = 1;
+  if (this->producer() != 0) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteInt32ToArray(1, this->producer(), target);
+  }
+
+  // optional int32 min_consumer = 2;
+  if (this->min_consumer() != 0) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteInt32ToArray(2, this->min_consumer(), target);
+  }
+
+  // repeated int32 bad_consumers = 3;
+  if (this->bad_consumers_size() > 0) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteTagToArray(
+      3,
+      ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED,
+      target);
+    target = ::google::protobuf::io::CodedOutputStream::WriteVarint32ToArray(
+      _bad_consumers_cached_byte_size_, target);
+  }
+  for (int i = 0; i < this->bad_consumers_size(); i++) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      WriteInt32NoTagToArray(this->bad_consumers(i), target);
+  }
+
+  // @@protoc_insertion_point(serialize_to_array_end:tensorflow.VersionDef)
+  return target;
+}
+
+size_t VersionDef::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:tensorflow.VersionDef)
+  size_t total_size = 0;
+
+  // optional int32 producer = 1;
+  if (this->producer() != 0) {
+    total_size += 1 +
+      ::google::protobuf::internal::WireFormatLite::Int32Size(
+        this->producer());
+  }
+
+  // optional int32 min_consumer = 2;
+  if (this->min_consumer() != 0) {
+    total_size += 1 +
+      ::google::protobuf::internal::WireFormatLite::Int32Size(
+        this->min_consumer());
+  }
+
+  // repeated int32 bad_consumers = 3;
+  {
+    size_t data_size = 0;
+    unsigned int count = this->bad_consumers_size();
+    for (unsigned int i = 0; i < count; i++) {
+      data_size += ::google::protobuf::internal::WireFormatLite::
+        Int32Size(this->bad_consumers(i));
+    }
+    if (data_size > 0) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::Int32Size(data_size);
+    }
+    int cached_size = ::google::protobuf::internal::ToCachedSize(data_size);
+    GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+    _bad_consumers_cached_byte_size_ = cached_size;
+    GOOGLE_SAFE_CONCURRENT_WRITES_END();
+    total_size += data_size;
+  }
+
+  int cached_size = ::google::protobuf::internal::ToCachedSize(total_size);
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = cached_size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+  return total_size;
+}
+
+void VersionDef::MergeFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_merge_from_start:tensorflow.VersionDef)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const VersionDef* source =
+      ::google::protobuf::internal::DynamicCastToGenerated<const VersionDef>(
+          &from);
+  if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:tensorflow.VersionDef)
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:tensorflow.VersionDef)
+    UnsafeMergeFrom(*source);
+  }
+}
+
+void VersionDef::MergeFrom(const VersionDef& from) {
+// @@protoc_insertion_point(class_specific_merge_from_start:tensorflow.VersionDef)
+  if (GOOGLE_PREDICT_TRUE(&from != this)) {
+    UnsafeMergeFrom(from);
+  } else {
+    MergeFromFail(__LINE__);
+  }
+}
+
+void VersionDef::UnsafeMergeFrom(const VersionDef& from) {
+  GOOGLE_DCHECK(&from != this);
+  bad_consumers_.UnsafeMergeFrom(from.bad_consumers_);
+  if (from.producer() != 0) {
+    set_producer(from.producer());
+  }
+  if (from.min_consumer() != 0) {
+    set_min_consumer(from.min_consumer());
+  }
+}
+
+void VersionDef::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:tensorflow.VersionDef)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void VersionDef::CopyFrom(const VersionDef& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:tensorflow.VersionDef)
+  if (&from == this) return;
+  Clear();
+  UnsafeMergeFrom(from);
+}
+
+bool VersionDef::IsInitialized() const {
+
+  return true;
+}
+
+void VersionDef::Swap(VersionDef* other) {
+  if (other == this) return;
+  if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) {
+    InternalSwap(other);
+  } else {
+    VersionDef temp;
+    temp.UnsafeMergeFrom(*this);
+    CopyFrom(*other);
+    other->CopyFrom(temp);
+  }
+}
+void VersionDef::UnsafeArenaSwap(VersionDef* other) {
+  if (other == this) return;
+  GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual());
+  InternalSwap(other);
+}
+void VersionDef::InternalSwap(VersionDef* other) {
+  std::swap(producer_, other->producer_);
+  std::swap(min_consumer_, other->min_consumer_);
+  bad_consumers_.UnsafeArenaSwap(&other->bad_consumers_);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
+}
+
+::google::protobuf::Metadata VersionDef::GetMetadata() const {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::Metadata metadata;
+  metadata.descriptor = VersionDef_descriptor_;
+  metadata.reflection = VersionDef_reflection_;
+  return metadata;
+}
+
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// VersionDef
+
+// optional int32 producer = 1;
+void VersionDef::clear_producer() {
+  producer_ = 0;
+}
+::google::protobuf::int32 VersionDef::producer() const {
+  // @@protoc_insertion_point(field_get:tensorflow.VersionDef.producer)
+  return producer_;
+}
+void VersionDef::set_producer(::google::protobuf::int32 value) {
+
+  producer_ = value;
+  // @@protoc_insertion_point(field_set:tensorflow.VersionDef.producer)
+}
+
+// optional int32 min_consumer = 2;
+void VersionDef::clear_min_consumer() {
+  min_consumer_ = 0;
+}
+::google::protobuf::int32 VersionDef::min_consumer() const {
+  // @@protoc_insertion_point(field_get:tensorflow.VersionDef.min_consumer)
+  return min_consumer_;
+}
+void VersionDef::set_min_consumer(::google::protobuf::int32 value) {
+
+  min_consumer_ = value;
+  // @@protoc_insertion_point(field_set:tensorflow.VersionDef.min_consumer)
+}
+
+// repeated int32 bad_consumers = 3;
+int VersionDef::bad_consumers_size() const {
+  return bad_consumers_.size();
+}
+void VersionDef::clear_bad_consumers() {
+  bad_consumers_.Clear();
+}
+::google::protobuf::int32 VersionDef::bad_consumers(int index) const {
+  // @@protoc_insertion_point(field_get:tensorflow.VersionDef.bad_consumers)
+  return bad_consumers_.Get(index);
+}
+void VersionDef::set_bad_consumers(int index, ::google::protobuf::int32 value) {
+  bad_consumers_.Set(index, value);
+  // @@protoc_insertion_point(field_set:tensorflow.VersionDef.bad_consumers)
+}
+void VersionDef::add_bad_consumers(::google::protobuf::int32 value) {
+  bad_consumers_.Add(value);
+  // @@protoc_insertion_point(field_add:tensorflow.VersionDef.bad_consumers)
+}
+const ::google::protobuf::RepeatedField< ::google::protobuf::int32 >&
+VersionDef::bad_consumers() const {
+  // @@protoc_insertion_point(field_list:tensorflow.VersionDef.bad_consumers)
+  return bad_consumers_;
+}
+::google::protobuf::RepeatedField< ::google::protobuf::int32 >*
+VersionDef::mutable_bad_consumers() {
+  // @@protoc_insertion_point(field_mutable_list:tensorflow.VersionDef.bad_consumers)
+  return &bad_consumers_;
+}
+
+inline const VersionDef* VersionDef::internal_default_instance() {
+  return &VersionDef_default_instance_.get();
+}
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
+
+// @@protoc_insertion_point(namespace_scope)
+
+}  // namespace tensorflow
+
+// @@protoc_insertion_point(global_scope)
diff --git a/contrib/modules/dnn/misc/tensorflow/versions.pb.h b/contrib/modules/dnn/misc/tensorflow/versions.pb.h
new file mode 100644
index 0000000..ce099cb
--- /dev/null
+++ b/contrib/modules/dnn/misc/tensorflow/versions.pb.h
@@ -0,0 +1,239 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: versions.proto
+
+#ifndef PROTOBUF_versions_2eproto__INCLUDED
+#define PROTOBUF_versions_2eproto__INCLUDED
+
+#include <string>
+
+#include <google/protobuf/stubs/common.h>
+
+#if GOOGLE_PROTOBUF_VERSION < 3001000
+#error This file was generated by a newer version of protoc which is
+#error incompatible with your Protocol Buffer headers.  Please update
+#error your headers.
+#endif
+#if 3001000 < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION
+#error This file was generated by an older version of protoc which is
+#error incompatible with your Protocol Buffer headers.  Please
+#error regenerate this file with a newer version of protoc.
+#endif
+
+#include <google/protobuf/arena.h>
+#include <google/protobuf/arenastring.h>
+#include <google/protobuf/generated_message_util.h>
+#include <google/protobuf/metadata.h>
+#include <google/protobuf/message.h>
+#include <google/protobuf/repeated_field.h>
+#include <google/protobuf/extension_set.h>
+#include <google/protobuf/unknown_field_set.h>
+// @@protoc_insertion_point(includes)
+
+namespace tensorflow {
+
+// Internal implementation detail -- do not call these.
+void protobuf_AddDesc_versions_2eproto();
+void protobuf_InitDefaults_versions_2eproto();
+void protobuf_AssignDesc_versions_2eproto();
+void protobuf_ShutdownFile_versions_2eproto();
+
+class VersionDef;
+
+// ===================================================================
+
+class VersionDef : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:tensorflow.VersionDef) */ {
+ public:
+  VersionDef();
+  virtual ~VersionDef();
+
+  VersionDef(const VersionDef& from);
+
+  inline VersionDef& operator=(const VersionDef& from) {
+    CopyFrom(from);
+    return *this;
+  }
+
+  inline ::google::protobuf::Arena* GetArena() const { return GetArenaNoVirtual(); }
+  inline void* GetMaybeArenaPointer() const {
+    return MaybeArenaPtr();
+  }
+  static const ::google::protobuf::Descriptor* descriptor();
+  static const VersionDef& default_instance();
+
+  static const VersionDef* internal_default_instance();
+
+  void UnsafeArenaSwap(VersionDef* other);
+  void Swap(VersionDef* other);
+
+  // implements Message ----------------------------------------------
+
+  inline VersionDef* New() const { return New(NULL); }
+
+  VersionDef* New(::google::protobuf::Arena* arena) const;
+  void CopyFrom(const ::google::protobuf::Message& from);
+  void MergeFrom(const ::google::protobuf::Message& from);
+  void CopyFrom(const VersionDef& from);
+  void MergeFrom(const VersionDef& from);
+  void Clear();
+  bool IsInitialized() const;
+
+  size_t ByteSizeLong() const;
+  bool MergePartialFromCodedStream(
+      ::google::protobuf::io::CodedInputStream* input);
+  void SerializeWithCachedSizes(
+      ::google::protobuf::io::CodedOutputStream* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
+  int GetCachedSize() const { return _cached_size_; }
+  private:
+  void SharedCtor();
+  void SharedDtor();
+  void SetCachedSize(int size) const;
+  void InternalSwap(VersionDef* other);
+  void UnsafeMergeFrom(const VersionDef& from);
+  protected:
+  explicit VersionDef(::google::protobuf::Arena* arena);
+  private:
+  static void ArenaDtor(void* object);
+  inline void RegisterArenaDtor(::google::protobuf::Arena* arena);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
+  public:
+
+  ::google::protobuf::Metadata GetMetadata() const;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  // optional int32 producer = 1;
+  void clear_producer();
+  static const int kProducerFieldNumber = 1;
+  ::google::protobuf::int32 producer() const;
+  void set_producer(::google::protobuf::int32 value);
+
+  // optional int32 min_consumer = 2;
+  void clear_min_consumer();
+  static const int kMinConsumerFieldNumber = 2;
+  ::google::protobuf::int32 min_consumer() const;
+  void set_min_consumer(::google::protobuf::int32 value);
+
+  // repeated int32 bad_consumers = 3;
+  int bad_consumers_size() const;
+  void clear_bad_consumers();
+  static const int kBadConsumersFieldNumber = 3;
+  ::google::protobuf::int32 bad_consumers(int index) const;
+  void set_bad_consumers(int index, ::google::protobuf::int32 value);
+  void add_bad_consumers(::google::protobuf::int32 value);
+  const ::google::protobuf::RepeatedField< ::google::protobuf::int32 >&
+      bad_consumers() const;
+  ::google::protobuf::RepeatedField< ::google::protobuf::int32 >*
+      mutable_bad_consumers();
+
+  // @@protoc_insertion_point(class_scope:tensorflow.VersionDef)
+ private:
+
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  friend class ::google::protobuf::Arena;
+  typedef void InternalArenaConstructable_;
+  typedef void DestructorSkippable_;
+  ::google::protobuf::RepeatedField< ::google::protobuf::int32 > bad_consumers_;
+  mutable int _bad_consumers_cached_byte_size_;
+  ::google::protobuf::int32 producer_;
+  ::google::protobuf::int32 min_consumer_;
+  mutable int _cached_size_;
+  friend void  protobuf_InitDefaults_versions_2eproto_impl();
+  friend void  protobuf_AddDesc_versions_2eproto_impl();
+  friend void protobuf_AssignDesc_versions_2eproto();
+  friend void protobuf_ShutdownFile_versions_2eproto();
+
+  void InitAsDefaultInstance();
+};
+extern ::google::protobuf::internal::ExplicitlyConstructed<VersionDef> VersionDef_default_instance_;
+
+// ===================================================================
+
+
+// ===================================================================
+
+#if !PROTOBUF_INLINE_NOT_IN_HEADERS
+// VersionDef
+
+// optional int32 producer = 1;
+inline void VersionDef::clear_producer() {
+  producer_ = 0;
+}
+inline ::google::protobuf::int32 VersionDef::producer() const {
+  // @@protoc_insertion_point(field_get:tensorflow.VersionDef.producer)
+  return producer_;
+}
+inline void VersionDef::set_producer(::google::protobuf::int32 value) {
+
+  producer_ = value;
+  // @@protoc_insertion_point(field_set:tensorflow.VersionDef.producer)
+}
+
+// optional int32 min_consumer = 2;
+inline void VersionDef::clear_min_consumer() {
+  min_consumer_ = 0;
+}
+inline ::google::protobuf::int32 VersionDef::min_consumer() const {
+  // @@protoc_insertion_point(field_get:tensorflow.VersionDef.min_consumer)
+  return min_consumer_;
+}
+inline void VersionDef::set_min_consumer(::google::protobuf::int32 value) {
+
+  min_consumer_ = value;
+  // @@protoc_insertion_point(field_set:tensorflow.VersionDef.min_consumer)
+}
+
+// repeated int32 bad_consumers = 3;
+inline int VersionDef::bad_consumers_size() const {
+  return bad_consumers_.size();
+}
+inline void VersionDef::clear_bad_consumers() {
+  bad_consumers_.Clear();
+}
+inline ::google::protobuf::int32 VersionDef::bad_consumers(int index) const {
+  // @@protoc_insertion_point(field_get:tensorflow.VersionDef.bad_consumers)
+  return bad_consumers_.Get(index);
+}
+inline void VersionDef::set_bad_consumers(int index, ::google::protobuf::int32 value) {
+  bad_consumers_.Set(index, value);
+  // @@protoc_insertion_point(field_set:tensorflow.VersionDef.bad_consumers)
+}
+inline void VersionDef::add_bad_consumers(::google::protobuf::int32 value) {
+  bad_consumers_.Add(value);
+  // @@protoc_insertion_point(field_add:tensorflow.VersionDef.bad_consumers)
+}
+inline const ::google::protobuf::RepeatedField< ::google::protobuf::int32 >&
+VersionDef::bad_consumers() const {
+  // @@protoc_insertion_point(field_list:tensorflow.VersionDef.bad_consumers)
+  return bad_consumers_;
+}
+inline ::google::protobuf::RepeatedField< ::google::protobuf::int32 >*
+VersionDef::mutable_bad_consumers() {
+  // @@protoc_insertion_point(field_mutable_list:tensorflow.VersionDef.bad_consumers)
+  return &bad_consumers_;
+}
+
+inline const VersionDef* VersionDef::internal_default_instance() {
+  return &VersionDef_default_instance_.get();
+}
+#endif  // !PROTOBUF_INLINE_NOT_IN_HEADERS
+
+// @@protoc_insertion_point(namespace_scope)
+
+}  // namespace tensorflow
+
+// @@protoc_insertion_point(global_scope)
+
+#endif  // PROTOBUF_versions_2eproto__INCLUDED
diff --git a/contrib/modules/dnn/perf/perf_convolution.cpp b/contrib/modules/dnn/perf/perf_convolution.cpp
new file mode 100644
index 0000000..17fda01
--- /dev/null
+++ b/contrib/modules/dnn/perf/perf_convolution.cpp
@@ -0,0 +1,80 @@
+#include "perf_precomp.hpp"
+
+namespace cvtest
+{
+
+using std::tr1::tuple;
+using std::tr1::get;
+using std::tr1::make_tuple;
+using std::make_pair;
+using namespace perf;
+using namespace testing;
+using namespace cv;
+using namespace cv::dnn;
+
+enum {STRIDE_OFF = 1, STRIDE_ON = 2};
+CV_ENUM(StrideSize, STRIDE_OFF, STRIDE_ON);
+
+enum {GROUP_OFF = 1, GROUP_2 = 2};
+CV_ENUM(GroupSize, GROUP_OFF, GROUP_2);
+
+//Squared Size
+#define SSZ(n) cv::Size(n, n)
+
+typedef std::pair<BlobShape, int> InpShapeNumOut;
+typedef tuple<Size, InpShapeNumOut, GroupSize, StrideSize> ConvParam; //kernel_size, inp shape, groups, stride
+typedef TestBaseWithParam<ConvParam> ConvolutionPerfTest;
+
+PERF_TEST_P( ConvolutionPerfTest, perf, Combine(
+    Values(Size(1, 1), Size(3, 3), Size(5, 5), Size(11, 11)),
+    Values(make_pair(BlobShape(1,   4, 224, 224),  64),
+           make_pair(BlobShape(1,  64, 112, 122), 128),
+           make_pair(BlobShape(1, 256,  28,  28), 512)),
+    GroupSize::all(),
+    StrideSize::all())
+)
+{
+    RNG rng(0);
+
+    ConvParam params = GetParam();
+    int ksz     = get<0>(params).width;
+    BlobShape inpShape = get<1>(params).first;
+    int outCn   = get<1>(params).second;
+    int groups  = get<2>(params);
+    int stride  = (ksz >= 11) ? 4 : (int)get<3>(params);
+
+    int inpCn = inpShape[1];
+    Blob wgtBlob(BlobShape(outCn, inpCn/groups, ksz, ksz)), biasBlob(BlobShape(outCn, 1, 1, 1));
+    Blob inpBlob(inpShape);
+    rng.fill(biasBlob.matRef(), RNG::UNIFORM, -1, +1);
+    rng.fill(wgtBlob.matRef(), RNG::UNIFORM, -1, +1);
+    rng.fill(inpBlob.matRef(), RNG::UNIFORM, -1, +1);
+
+    LayerParams lp;
+    lp.set("num_output", outCn);
+    lp.set("group", groups);
+    lp.set("stride", stride);
+    lp.set("kernel_size", ksz);
+    lp.blobs.reserve(2);
+    lp.blobs.push_back(wgtBlob);
+    lp.blobs.push_back(biasBlob);
+
+    std::vector<Blob*> inpBlobs(1, &inpBlob);
+    std::vector<Blob> outBlobs;
+
+    cv::setNumThreads(cv::getNumberOfCPUs());
+
+    Ptr<Layer> layer = cv::dnn::LayerFactory::createLayerInstance("Convolution", lp);
+    layer->allocate(inpBlobs, outBlobs);
+
+    declare.in(inpBlob.matRef(), wgtBlob.matRef(), WARMUP_RNG).out(outBlobs[0].matRef()).tbb_threads(cv::getNumThreads());
+
+    TEST_CYCLE_N(10)
+    {
+        layer->forward(inpBlobs, outBlobs);
+    }
+
+    SANITY_CHECK_NOTHING();
+}
+
+}
\ No newline at end of file
diff --git a/contrib/modules/dnn/perf/perf_main.cpp b/contrib/modules/dnn/perf/perf_main.cpp
new file mode 100644
index 0000000..1798020
--- /dev/null
+++ b/contrib/modules/dnn/perf/perf_main.cpp
@@ -0,0 +1,3 @@
+#include "perf_precomp.hpp"
+
+CV_PERF_TEST_MAIN(dnn)
diff --git a/contrib/modules/dnn/perf/perf_precomp.hpp b/contrib/modules/dnn/perf/perf_precomp.hpp
new file mode 100644
index 0000000..5cdbc6d
--- /dev/null
+++ b/contrib/modules/dnn/perf/perf_precomp.hpp
@@ -0,0 +1,17 @@
+#ifdef __GNUC__
+#  pragma GCC diagnostic ignored "-Wmissing-declarations"
+#  if defined __clang__ || defined __APPLE__
+#    pragma GCC diagnostic ignored "-Wmissing-prototypes"
+#    pragma GCC diagnostic ignored "-Wextra"
+#  endif
+#endif
+
+#ifndef __OPENCV_PERF_PRECOMP_HPP__
+#define __OPENCV_PERF_PRECOMP_HPP__
+
+#include <opencv2/ts.hpp>
+#include <opencv2/imgproc.hpp>
+#include <opencv2/highgui.hpp>
+#include <opencv2/dnn.hpp>
+
+#endif
diff --git a/contrib/modules/dnn/samples/.gitignore b/contrib/modules/dnn/samples/.gitignore
new file mode 100644
index 0000000..be71866
--- /dev/null
+++ b/contrib/modules/dnn/samples/.gitignore
@@ -0,0 +1 @@
+*.caffemodel
diff --git a/contrib/modules/dnn/samples/VGG_VOC0712_SSD_300x300_iter_60000.prototxt b/contrib/modules/dnn/samples/VGG_VOC0712_SSD_300x300_iter_60000.prototxt
new file mode 100644
index 0000000..19156c7
--- /dev/null
+++ b/contrib/modules/dnn/samples/VGG_VOC0712_SSD_300x300_iter_60000.prototxt
@@ -0,0 +1,1547 @@
+name: "VGG_VOC0712_SSD_300x300_deploy"
+input: "data"
+input_dim: 1
+input_dim: 3
+input_dim: 300
+input_dim: 300
+layer {
+  name: "conv1_1"
+  type: "Convolution"
+  bottom: "data"
+  top: "conv1_1"
+  param {
+    lr_mult: 0
+    decay_mult: 0
+  }
+  param {
+    lr_mult: 0
+    decay_mult: 0
+  }
+  convolution_param {
+    num_output: 64
+    pad: 1
+    kernel_size: 3
+    weight_filler {
+      type: "xavier"
+    }
+    bias_filler {
+      type: "constant"
+      value: 0
+    }
+  }
+}
+layer {
+  name: "relu1_1"
+  type: "ReLU"
+  bottom: "conv1_1"
+  top: "conv1_1"
+}
+layer {
+  name: "conv1_2"
+  type: "Convolution"
+  bottom: "conv1_1"
+  top: "conv1_2"
+  param {
+    lr_mult: 0
+    decay_mult: 0
+  }
+  param {
+    lr_mult: 0
+    decay_mult: 0
+  }
+  convolution_param {
+    num_output: 64
+    pad: 1
+    kernel_size: 3
+    weight_filler {
+      type: "xavier"
+    }
+    bias_filler {
+      type: "constant"
+      value: 0
+    }
+  }
+}
+layer {
+  name: "relu1_2"
+  type: "ReLU"
+  bottom: "conv1_2"
+  top: "conv1_2"
+}
+layer {
+  name: "pool1"
+  type: "Pooling"
+  bottom: "conv1_2"
+  top: "pool1"
+  pooling_param {
+    pool: MAX
+    kernel_size: 2
+    stride: 2
+  }
+}
+layer {
+  name: "conv2_1"
+  type: "Convolution"
+  bottom: "pool1"
+  top: "conv2_1"
+  param {
+    lr_mult: 0
+    decay_mult: 0
+  }
+  param {
+    lr_mult: 0
+    decay_mult: 0
+  }
+  convolution_param {
+    num_output: 128
+    pad: 1
+    kernel_size: 3
+    weight_filler {
+      type: "xavier"
+    }
+    bias_filler {
+      type: "constant"
+      value: 0
+    }
+  }
+}
+layer {
+  name: "relu2_1"
+  type: "ReLU"
+  bottom: "conv2_1"
+  top: "conv2_1"
+}
+layer {
+  name: "conv2_2"
+  type: "Convolution"
+  bottom: "conv2_1"
+  top: "conv2_2"
+  param {
+    lr_mult: 0
+    decay_mult: 0
+  }
+  param {
+    lr_mult: 0
+    decay_mult: 0
+  }
+  convolution_param {
+    num_output: 128
+    pad: 1
+    kernel_size: 3
+    weight_filler {
+      type: "xavier"
+    }
+    bias_filler {
+      type: "constant"
+      value: 0
+    }
+  }
+}
+layer {
+  name: "relu2_2"
+  type: "ReLU"
+  bottom: "conv2_2"
+  top: "conv2_2"
+}
+layer {
+  name: "pool2"
+  type: "Pooling"
+  bottom: "conv2_2"
+  top: "pool2"
+  pooling_param {
+    pool: MAX
+    kernel_size: 2
+    stride: 2
+  }
+}
+layer {
+  name: "conv3_1"
+  type: "Convolution"
+  bottom: "pool2"
+  top: "conv3_1"
+  param {
+    lr_mult: 1
+    decay_mult: 1
+  }
+  param {
+    lr_mult: 2
+    decay_mult: 0
+  }
+  convolution_param {
+    num_output: 256
+    pad: 1
+    kernel_size: 3
+    weight_filler {
+      type: "xavier"
+    }
+    bias_filler {
+      type: "constant"
+      value: 0
+    }
+  }
+}
+layer {
+  name: "relu3_1"
+  type: "ReLU"
+  bottom: "conv3_1"
+  top: "conv3_1"
+}
+layer {
+  name: "conv3_2"
+  type: "Convolution"
+  bottom: "conv3_1"
+  top: "conv3_2"
+  param {
+    lr_mult: 1
+    decay_mult: 1
+  }
+  param {
+    lr_mult: 2
+    decay_mult: 0
+  }
+  convolution_param {
+    num_output: 256
+    pad: 1
+    kernel_size: 3
+    weight_filler {
+      type: "xavier"
+    }
+    bias_filler {
+      type: "constant"
+      value: 0
+    }
+  }
+}
+layer {
+  name: "relu3_2"
+  type: "ReLU"
+  bottom: "conv3_2"
+  top: "conv3_2"
+}
+layer {
+  name: "conv3_3"
+  type: "Convolution"
+  bottom: "conv3_2"
+  top: "conv3_3"
+  param {
+    lr_mult: 1
+    decay_mult: 1
+  }
+  param {
+    lr_mult: 2
+    decay_mult: 0
+  }
+  convolution_param {
+    num_output: 256
+    pad: 1
+    kernel_size: 3
+    weight_filler {
+      type: "xavier"
+    }
+    bias_filler {
+      type: "constant"
+      value: 0
+    }
+  }
+}
+layer {
+  name: "relu3_3"
+  type: "ReLU"
+  bottom: "conv3_3"
+  top: "conv3_3"
+}
+layer {
+  name: "pool3"
+  type: "Pooling"
+  bottom: "conv3_3"
+  top: "pool3"
+  pooling_param {
+    pool: MAX
+    kernel_size: 2
+    stride: 2
+  }
+}
+layer {
+  name: "conv4_1"
+  type: "Convolution"
+  bottom: "pool3"
+  top: "conv4_1"
+  param {
+    lr_mult: 1
+    decay_mult: 1
+  }
+  param {
+    lr_mult: 2
+    decay_mult: 0
+  }
+  convolution_param {
+    num_output: 512
+    pad: 1
+    kernel_size: 3
+    weight_filler {
+      type: "xavier"
+    }
+    bias_filler {
+      type: "constant"
+      value: 0
+    }
+  }
+}
+layer {
+  name: "relu4_1"
+  type: "ReLU"
+  bottom: "conv4_1"
+  top: "conv4_1"
+}
+layer {
+  name: "conv4_2"
+  type: "Convolution"
+  bottom: "conv4_1"
+  top: "conv4_2"
+  param {
+    lr_mult: 1
+    decay_mult: 1
+  }
+  param {
+    lr_mult: 2
+    decay_mult: 0
+  }
+  convolution_param {
+    num_output: 512
+    pad: 1
+    kernel_size: 3
+    weight_filler {
+      type: "xavier"
+    }
+    bias_filler {
+      type: "constant"
+      value: 0
+    }
+  }
+}
+layer {
+  name: "relu4_2"
+  type: "ReLU"
+  bottom: "conv4_2"
+  top: "conv4_2"
+}
+layer {
+  name: "conv4_3"
+  type: "Convolution"
+  bottom: "conv4_2"
+  top: "conv4_3"
+  param {
+    lr_mult: 1
+    decay_mult: 1
+  }
+  param {
+    lr_mult: 2
+    decay_mult: 0
+  }
+  convolution_param {
+    num_output: 512
+    pad: 1
+    kernel_size: 3
+    weight_filler {
+      type: "xavier"
+    }
+    bias_filler {
+      type: "constant"
+      value: 0
+    }
+  }
+}
+layer {
+  name: "relu4_3"
+  type: "ReLU"
+  bottom: "conv4_3"
+  top: "conv4_3"
+}
+layer {
+  name: "pool4"
+  type: "Pooling"
+  bottom: "conv4_3"
+  top: "pool4"
+  pooling_param {
+    pool: MAX
+    kernel_size: 2
+    stride: 2
+  }
+}
+layer {
+  name: "conv5_1"
+  type: "Convolution"
+  bottom: "pool4"
+  top: "conv5_1"
+  param {
+    lr_mult: 1
+    decay_mult: 1
+  }
+  param {
+    lr_mult: 2
+    decay_mult: 0
+  }
+  convolution_param {
+    num_output: 512
+    pad: 1
+    kernel_size: 3
+    weight_filler {
+      type: "xavier"
+    }
+    bias_filler {
+      type: "constant"
+      value: 0
+    }
+  }
+}
+layer {
+  name: "relu5_1"
+  type: "ReLU"
+  bottom: "conv5_1"
+  top: "conv5_1"
+}
+layer {
+  name: "conv5_2"
+  type: "Convolution"
+  bottom: "conv5_1"
+  top: "conv5_2"
+  param {
+    lr_mult: 1
+    decay_mult: 1
+  }
+  param {
+    lr_mult: 2
+    decay_mult: 0
+  }
+  convolution_param {
+    num_output: 512
+    pad: 1
+    kernel_size: 3
+    weight_filler {
+      type: "xavier"
+    }
+    bias_filler {
+      type: "constant"
+      value: 0
+    }
+  }
+}
+layer {
+  name: "relu5_2"
+  type: "ReLU"
+  bottom: "conv5_2"
+  top: "conv5_2"
+}
+layer {
+  name: "conv5_3"
+  type: "Convolution"
+  bottom: "conv5_2"
+  top: "conv5_3"
+  param {
+    lr_mult: 1
+    decay_mult: 1
+  }
+  param {
+    lr_mult: 2
+    decay_mult: 0
+  }
+  convolution_param {
+    num_output: 512
+    pad: 1
+    kernel_size: 3
+    weight_filler {
+      type: "xavier"
+    }
+    bias_filler {
+      type: "constant"
+      value: 0
+    }
+  }
+}
+layer {
+  name: "relu5_3"
+  type: "ReLU"
+  bottom: "conv5_3"
+  top: "conv5_3"
+}
+layer {
+  name: "pool5"
+  type: "Pooling"
+  bottom: "conv5_3"
+  top: "pool5"
+  pooling_param {
+    pool: MAX
+    kernel_size: 3
+    stride: 1
+    pad: 1
+  }
+}
+layer {
+  name: "fc6"
+  type: "Convolution"
+  bottom: "pool5"
+  top: "fc6"
+  param {
+    lr_mult: 1
+    decay_mult: 1
+  }
+  param {
+    lr_mult: 2
+    decay_mult: 0
+  }
+  convolution_param {
+    num_output: 1024
+    pad: 6
+    kernel_size: 3
+    weight_filler {
+      type: "xavier"
+    }
+    bias_filler {
+      type: "constant"
+      value: 0
+    }
+    dilation: 6
+  }
+}
+layer {
+  name: "relu6"
+  type: "ReLU"
+  bottom: "fc6"
+  top: "fc6"
+}
+layer {
+  name: "fc7"
+  type: "Convolution"
+  bottom: "fc6"
+  top: "fc7"
+  param {
+    lr_mult: 1
+    decay_mult: 1
+  }
+  param {
+    lr_mult: 2
+    decay_mult: 0
+  }
+  convolution_param {
+    num_output: 1024
+    kernel_size: 1
+    weight_filler {
+      type: "xavier"
+    }
+    bias_filler {
+      type: "constant"
+      value: 0
+    }
+  }
+}
+layer {
+  name: "relu7"
+  type: "ReLU"
+  bottom: "fc7"
+  top: "fc7"
+}
+layer {
+  name: "conv6_1"
+  type: "Convolution"
+  bottom: "fc7"
+  top: "conv6_1"
+  param {
+    lr_mult: 1
+    decay_mult: 1
+  }
+  param {
+    lr_mult: 2
+    decay_mult: 0
+  }
+  convolution_param {
+    num_output: 256
+    pad: 0
+    kernel_size: 1
+    stride: 1
+    weight_filler {
+      type: "xavier"
+    }
+    bias_filler {
+      type: "constant"
+      value: 0
+    }
+  }
+}
+layer {
+  name: "conv6_1_relu"
+  type: "ReLU"
+  bottom: "conv6_1"
+  top: "conv6_1"
+}
+layer {
+  name: "conv6_2"
+  type: "Convolution"
+  bottom: "conv6_1"
+  top: "conv6_2"
+  param {
+    lr_mult: 1
+    decay_mult: 1
+  }
+  param {
+    lr_mult: 2
+    decay_mult: 0
+  }
+  convolution_param {
+    num_output: 512
+    pad: 1
+    kernel_size: 3
+    stride: 2
+    weight_filler {
+      type: "xavier"
+    }
+    bias_filler {
+      type: "constant"
+      value: 0
+    }
+  }
+}
+layer {
+  name: "conv6_2_relu"
+  type: "ReLU"
+  bottom: "conv6_2"
+  top: "conv6_2"
+}
+layer {
+  name: "conv7_1"
+  type: "Convolution"
+  bottom: "conv6_2"
+  top: "conv7_1"
+  param {
+    lr_mult: 1
+    decay_mult: 1
+  }
+  param {
+    lr_mult: 2
+    decay_mult: 0
+  }
+  convolution_param {
+    num_output: 128
+    pad: 0
+    kernel_size: 1
+    stride: 1
+    weight_filler {
+      type: "xavier"
+    }
+    bias_filler {
+      type: "constant"
+      value: 0
+    }
+  }
+}
+layer {
+  name: "conv7_1_relu"
+  type: "ReLU"
+  bottom: "conv7_1"
+  top: "conv7_1"
+}
+layer {
+  name: "conv7_2"
+  type: "Convolution"
+  bottom: "conv7_1"
+  top: "conv7_2"
+  param {
+    lr_mult: 1
+    decay_mult: 1
+  }
+  param {
+    lr_mult: 2
+    decay_mult: 0
+  }
+  convolution_param {
+    num_output: 256
+    pad: 1
+    kernel_size: 3
+    stride: 2
+    weight_filler {
+      type: "xavier"
+    }
+    bias_filler {
+      type: "constant"
+      value: 0
+    }
+  }
+}
+layer {
+  name: "conv7_2_relu"
+  type: "ReLU"
+  bottom: "conv7_2"
+  top: "conv7_2"
+}
+layer {
+  name: "conv8_1"
+  type: "Convolution"
+  bottom: "conv7_2"
+  top: "conv8_1"
+  param {
+    lr_mult: 1
+    decay_mult: 1
+  }
+  param {
+    lr_mult: 2
+    decay_mult: 0
+  }
+  convolution_param {
+    num_output: 128
+    pad: 0
+    kernel_size: 1
+    stride: 1
+    weight_filler {
+      type: "xavier"
+    }
+    bias_filler {
+      type: "constant"
+      value: 0
+    }
+  }
+}
+layer {
+  name: "conv8_1_relu"
+  type: "ReLU"
+  bottom: "conv8_1"
+  top: "conv8_1"
+}
+layer {
+  name: "conv8_2"
+  type: "Convolution"
+  bottom: "conv8_1"
+  top: "conv8_2"
+  param {
+    lr_mult: 1
+    decay_mult: 1
+  }
+  param {
+    lr_mult: 2
+    decay_mult: 0
+  }
+  convolution_param {
+    num_output: 256
+    pad: 1
+    kernel_size: 3
+    stride: 2
+    weight_filler {
+      type: "xavier"
+    }
+    bias_filler {
+      type: "constant"
+      value: 0
+    }
+  }
+}
+layer {
+  name: "conv8_2_relu"
+  type: "ReLU"
+  bottom: "conv8_2"
+  top: "conv8_2"
+}
+layer {
+  name: "pool6"
+  type: "Pooling"
+  bottom: "conv8_2"
+  top: "pool6"
+  pooling_param {
+    pool: AVE
+    global_pooling: true
+  }
+}
+layer {
+  name: "conv4_3_norm"
+  type: "NormalizeBBox"
+  bottom: "conv4_3"
+  top: "conv4_3_norm"
+  normalize_bbox_param {
+    across_spatial: false
+    scale_filler {
+      type: "constant"
+      value: 20
+    }
+    channel_shared: false
+  }
+}
+layer {
+  name: "conv4_3_norm_mbox_loc"
+  type: "Convolution"
+  bottom: "conv4_3_norm"
+  top: "conv4_3_norm_mbox_loc"
+  param {
+    lr_mult: 1
+    decay_mult: 1
+  }
+  param {
+    lr_mult: 2
+    decay_mult: 0
+  }
+  convolution_param {
+    num_output: 12
+    pad: 1
+    kernel_size: 3
+    stride: 1
+    weight_filler {
+      type: "xavier"
+    }
+    bias_filler {
+      type: "constant"
+      value: 0
+    }
+  }
+}
+layer {
+  name: "conv4_3_norm_mbox_loc_perm"
+  type: "Permute"
+  bottom: "conv4_3_norm_mbox_loc"
+  top: "conv4_3_norm_mbox_loc_perm"
+  permute_param {
+    order: 0
+    order: 2
+    order: 3
+    order: 1
+  }
+}
+layer {
+  name: "conv4_3_norm_mbox_loc_flat"
+  type: "Flatten"
+  bottom: "conv4_3_norm_mbox_loc_perm"
+  top: "conv4_3_norm_mbox_loc_flat"
+  flatten_param {
+    axis: 1
+  }
+}
+layer {
+  name: "conv4_3_norm_mbox_conf"
+  type: "Convolution"
+  bottom: "conv4_3_norm"
+  top: "conv4_3_norm_mbox_conf"
+  param {
+    lr_mult: 1
+    decay_mult: 1
+  }
+  param {
+    lr_mult: 2
+    decay_mult: 0
+  }
+  convolution_param {
+    num_output: 63
+    pad: 1
+    kernel_size: 3
+    stride: 1
+    weight_filler {
+      type: "xavier"
+    }
+    bias_filler {
+      type: "constant"
+      value: 0
+    }
+  }
+}
+layer {
+  name: "conv4_3_norm_mbox_conf_perm"
+  type: "Permute"
+  bottom: "conv4_3_norm_mbox_conf"
+  top: "conv4_3_norm_mbox_conf_perm"
+  permute_param {
+    order: 0
+    order: 2
+    order: 3
+    order: 1
+  }
+}
+layer {
+  name: "conv4_3_norm_mbox_conf_flat"
+  type: "Flatten"
+  bottom: "conv4_3_norm_mbox_conf_perm"
+  top: "conv4_3_norm_mbox_conf_flat"
+  flatten_param {
+    axis: 1
+  }
+}
+layer {
+  name: "conv4_3_norm_mbox_priorbox"
+  type: "PriorBox"
+  bottom: "conv4_3_norm"
+  bottom: "data"
+  top: "conv4_3_norm_mbox_priorbox"
+  prior_box_param {
+    min_size: 30.0
+    aspect_ratio: 2
+    flip: true
+    clip: true
+    variance: 0.1
+    variance: 0.1
+    variance: 0.2
+    variance: 0.2
+  }
+}
+layer {
+  name: "fc7_mbox_loc"
+  type: "Convolution"
+  bottom: "fc7"
+  top: "fc7_mbox_loc"
+  param {
+    lr_mult: 1
+    decay_mult: 1
+  }
+  param {
+    lr_mult: 2
+    decay_mult: 0
+  }
+  convolution_param {
+    num_output: 24
+    pad: 1
+    kernel_size: 3
+    stride: 1
+    weight_filler {
+      type: "xavier"
+    }
+    bias_filler {
+      type: "constant"
+      value: 0
+    }
+  }
+}
+layer {
+  name: "fc7_mbox_loc_perm"
+  type: "Permute"
+  bottom: "fc7_mbox_loc"
+  top: "fc7_mbox_loc_perm"
+  permute_param {
+    order: 0
+    order: 2
+    order: 3
+    order: 1
+  }
+}
+layer {
+  name: "fc7_mbox_loc_flat"
+  type: "Flatten"
+  bottom: "fc7_mbox_loc_perm"
+  top: "fc7_mbox_loc_flat"
+  flatten_param {
+    axis: 1
+  }
+}
+layer {
+  name: "fc7_mbox_conf"
+  type: "Convolution"
+  bottom: "fc7"
+  top: "fc7_mbox_conf"
+  param {
+    lr_mult: 1
+    decay_mult: 1
+  }
+  param {
+    lr_mult: 2
+    decay_mult: 0
+  }
+  convolution_param {
+    num_output: 126
+    pad: 1
+    kernel_size: 3
+    stride: 1
+    weight_filler {
+      type: "xavier"
+    }
+    bias_filler {
+      type: "constant"
+      value: 0
+    }
+  }
+}
+layer {
+  name: "fc7_mbox_conf_perm"
+  type: "Permute"
+  bottom: "fc7_mbox_conf"
+  top: "fc7_mbox_conf_perm"
+  permute_param {
+    order: 0
+    order: 2
+    order: 3
+    order: 1
+  }
+}
+layer {
+  name: "fc7_mbox_conf_flat"
+  type: "Flatten"
+  bottom: "fc7_mbox_conf_perm"
+  top: "fc7_mbox_conf_flat"
+  flatten_param {
+    axis: 1
+  }
+}
+layer {
+  name: "fc7_mbox_priorbox"
+  type: "PriorBox"
+  bottom: "fc7"
+  bottom: "data"
+  top: "fc7_mbox_priorbox"
+  prior_box_param {
+    min_size: 60.0
+    max_size: 114.0
+    aspect_ratio: 2
+    aspect_ratio: 3
+    flip: true
+    clip: true
+    variance: 0.1
+    variance: 0.1
+    variance: 0.2
+    variance: 0.2
+  }
+}
+layer {
+  name: "conv6_2_mbox_loc"
+  type: "Convolution"
+  bottom: "conv6_2"
+  top: "conv6_2_mbox_loc"
+  param {
+    lr_mult: 1
+    decay_mult: 1
+  }
+  param {
+    lr_mult: 2
+    decay_mult: 0
+  }
+  convolution_param {
+    num_output: 24
+    pad: 1
+    kernel_size: 3
+    stride: 1
+    weight_filler {
+      type: "xavier"
+    }
+    bias_filler {
+      type: "constant"
+      value: 0
+    }
+  }
+}
+layer {
+  name: "conv6_2_mbox_loc_perm"
+  type: "Permute"
+  bottom: "conv6_2_mbox_loc"
+  top: "conv6_2_mbox_loc_perm"
+  permute_param {
+    order: 0
+    order: 2
+    order: 3
+    order: 1
+  }
+}
+layer {
+  name: "conv6_2_mbox_loc_flat"
+  type: "Flatten"
+  bottom: "conv6_2_mbox_loc_perm"
+  top: "conv6_2_mbox_loc_flat"
+  flatten_param {
+    axis: 1
+  }
+}
+layer {
+  name: "conv6_2_mbox_conf"
+  type: "Convolution"
+  bottom: "conv6_2"
+  top: "conv6_2_mbox_conf"
+  param {
+    lr_mult: 1
+    decay_mult: 1
+  }
+  param {
+    lr_mult: 2
+    decay_mult: 0
+  }
+  convolution_param {
+    num_output: 126
+    pad: 1
+    kernel_size: 3
+    stride: 1
+    weight_filler {
+      type: "xavier"
+    }
+    bias_filler {
+      type: "constant"
+      value: 0
+    }
+  }
+}
+layer {
+  name: "conv6_2_mbox_conf_perm"
+  type: "Permute"
+  bottom: "conv6_2_mbox_conf"
+  top: "conv6_2_mbox_conf_perm"
+  permute_param {
+    order: 0
+    order: 2
+    order: 3
+    order: 1
+  }
+}
+layer {
+  name: "conv6_2_mbox_conf_flat"
+  type: "Flatten"
+  bottom: "conv6_2_mbox_conf_perm"
+  top: "conv6_2_mbox_conf_flat"
+  flatten_param {
+    axis: 1
+  }
+}
+layer {
+  name: "conv6_2_mbox_priorbox"
+  type: "PriorBox"
+  bottom: "conv6_2"
+  bottom: "data"
+  top: "conv6_2_mbox_priorbox"
+  prior_box_param {
+    min_size: 114.0
+    max_size: 168.0
+    aspect_ratio: 2
+    aspect_ratio: 3
+    flip: true
+    clip: true
+    variance: 0.1
+    variance: 0.1
+    variance: 0.2
+    variance: 0.2
+  }
+}
+layer {
+  name: "conv7_2_mbox_loc"
+  type: "Convolution"
+  bottom: "conv7_2"
+  top: "conv7_2_mbox_loc"
+  param {
+    lr_mult: 1
+    decay_mult: 1
+  }
+  param {
+    lr_mult: 2
+    decay_mult: 0
+  }
+  convolution_param {
+    num_output: 24
+    pad: 1
+    kernel_size: 3
+    stride: 1
+    weight_filler {
+      type: "xavier"
+    }
+    bias_filler {
+      type: "constant"
+      value: 0
+    }
+  }
+}
+layer {
+  name: "conv7_2_mbox_loc_perm"
+  type: "Permute"
+  bottom: "conv7_2_mbox_loc"
+  top: "conv7_2_mbox_loc_perm"
+  permute_param {
+    order: 0
+    order: 2
+    order: 3
+    order: 1
+  }
+}
+layer {
+  name: "conv7_2_mbox_loc_flat"
+  type: "Flatten"
+  bottom: "conv7_2_mbox_loc_perm"
+  top: "conv7_2_mbox_loc_flat"
+  flatten_param {
+    axis: 1
+  }
+}
+layer {
+  name: "conv7_2_mbox_conf"
+  type: "Convolution"
+  bottom: "conv7_2"
+  top: "conv7_2_mbox_conf"
+  param {
+    lr_mult: 1
+    decay_mult: 1
+  }
+  param {
+    lr_mult: 2
+    decay_mult: 0
+  }
+  convolution_param {
+    num_output: 126
+    pad: 1
+    kernel_size: 3
+    stride: 1
+    weight_filler {
+      type: "xavier"
+    }
+    bias_filler {
+      type: "constant"
+      value: 0
+    }
+  }
+}
+layer {
+  name: "conv7_2_mbox_conf_perm"
+  type: "Permute"
+  bottom: "conv7_2_mbox_conf"
+  top: "conv7_2_mbox_conf_perm"
+  permute_param {
+    order: 0
+    order: 2
+    order: 3
+    order: 1
+  }
+}
+layer {
+  name: "conv7_2_mbox_conf_flat"
+  type: "Flatten"
+  bottom: "conv7_2_mbox_conf_perm"
+  top: "conv7_2_mbox_conf_flat"
+  flatten_param {
+    axis: 1
+  }
+}
+layer {
+  name: "conv7_2_mbox_priorbox"
+  type: "PriorBox"
+  bottom: "conv7_2"
+  bottom: "data"
+  top: "conv7_2_mbox_priorbox"
+  prior_box_param {
+    min_size: 168.0
+    max_size: 222.0
+    aspect_ratio: 2
+    aspect_ratio: 3
+    flip: true
+    clip: true
+    variance: 0.1
+    variance: 0.1
+    variance: 0.2
+    variance: 0.2
+  }
+}
+layer {
+  name: "conv8_2_mbox_loc"
+  type: "Convolution"
+  bottom: "conv8_2"
+  top: "conv8_2_mbox_loc"
+  param {
+    lr_mult: 1
+    decay_mult: 1
+  }
+  param {
+    lr_mult: 2
+    decay_mult: 0
+  }
+  convolution_param {
+    num_output: 24
+    pad: 1
+    kernel_size: 3
+    stride: 1
+    weight_filler {
+      type: "xavier"
+    }
+    bias_filler {
+      type: "constant"
+      value: 0
+    }
+  }
+}
+layer {
+  name: "conv8_2_mbox_loc_perm"
+  type: "Permute"
+  bottom: "conv8_2_mbox_loc"
+  top: "conv8_2_mbox_loc_perm"
+  permute_param {
+    order: 0
+    order: 2
+    order: 3
+    order: 1
+  }
+}
+layer {
+  name: "conv8_2_mbox_loc_flat"
+  type: "Flatten"
+  bottom: "conv8_2_mbox_loc_perm"
+  top: "conv8_2_mbox_loc_flat"
+  flatten_param {
+    axis: 1
+  }
+}
+layer {
+  name: "conv8_2_mbox_conf"
+  type: "Convolution"
+  bottom: "conv8_2"
+  top: "conv8_2_mbox_conf"
+  param {
+    lr_mult: 1
+    decay_mult: 1
+  }
+  param {
+    lr_mult: 2
+    decay_mult: 0
+  }
+  convolution_param {
+    num_output: 126
+    pad: 1
+    kernel_size: 3
+    stride: 1
+    weight_filler {
+      type: "xavier"
+    }
+    bias_filler {
+      type: "constant"
+      value: 0
+    }
+  }
+}
+layer {
+  name: "conv8_2_mbox_conf_perm"
+  type: "Permute"
+  bottom: "conv8_2_mbox_conf"
+  top: "conv8_2_mbox_conf_perm"
+  permute_param {
+    order: 0
+    order: 2
+    order: 3
+    order: 1
+  }
+}
+layer {
+  name: "conv8_2_mbox_conf_flat"
+  type: "Flatten"
+  bottom: "conv8_2_mbox_conf_perm"
+  top: "conv8_2_mbox_conf_flat"
+  flatten_param {
+    axis: 1
+  }
+}
+layer {
+  name: "conv8_2_mbox_priorbox"
+  type: "PriorBox"
+  bottom: "conv8_2"
+  bottom: "data"
+  top: "conv8_2_mbox_priorbox"
+  prior_box_param {
+    min_size: 222.0
+    max_size: 276.0
+    aspect_ratio: 2
+    aspect_ratio: 3
+    flip: true
+    clip: true
+    variance: 0.1
+    variance: 0.1
+    variance: 0.2
+    variance: 0.2
+  }
+}
+layer {
+  name: "pool6_mbox_loc"
+  type: "Convolution"
+  bottom: "pool6"
+  top: "pool6_mbox_loc"
+  param {
+    lr_mult: 1
+    decay_mult: 1
+  }
+  param {
+    lr_mult: 2
+    decay_mult: 0
+  }
+  convolution_param {
+    num_output: 24
+    pad: 1
+    kernel_size: 3
+    stride: 1
+    weight_filler {
+      type: "xavier"
+    }
+    bias_filler {
+      type: "constant"
+      value: 0
+    }
+  }
+}
+layer {
+  name: "pool6_mbox_loc_perm"
+  type: "Permute"
+  bottom: "pool6_mbox_loc"
+  top: "pool6_mbox_loc_perm"
+  permute_param {
+    order: 0
+    order: 2
+    order: 3
+    order: 1
+  }
+}
+layer {
+  name: "pool6_mbox_loc_flat"
+  type: "Flatten"
+  bottom: "pool6_mbox_loc_perm"
+  top: "pool6_mbox_loc_flat"
+  flatten_param {
+    axis: 1
+  }
+}
+layer {
+  name: "pool6_mbox_conf"
+  type: "Convolution"
+  bottom: "pool6"
+  top: "pool6_mbox_conf"
+  param {
+    lr_mult: 1
+    decay_mult: 1
+  }
+  param {
+    lr_mult: 2
+    decay_mult: 0
+  }
+  convolution_param {
+    num_output: 126
+    pad: 1
+    kernel_size: 3
+    stride: 1
+    weight_filler {
+      type: "xavier"
+    }
+    bias_filler {
+      type: "constant"
+      value: 0
+    }
+  }
+}
+layer {
+  name: "pool6_mbox_conf_perm"
+  type: "Permute"
+  bottom: "pool6_mbox_conf"
+  top: "pool6_mbox_conf_perm"
+  permute_param {
+    order: 0
+    order: 2
+    order: 3
+    order: 1
+  }
+}
+layer {
+  name: "pool6_mbox_conf_flat"
+  type: "Flatten"
+  bottom: "pool6_mbox_conf_perm"
+  top: "pool6_mbox_conf_flat"
+  flatten_param {
+    axis: 1
+  }
+}
+layer {
+  name: "pool6_mbox_priorbox"
+  type: "PriorBox"
+  bottom: "pool6"
+  bottom: "data"
+  top: "pool6_mbox_priorbox"
+  prior_box_param {
+    min_size: 276.0
+    max_size: 330.0
+    aspect_ratio: 2
+    aspect_ratio: 3
+    flip: true
+    clip: true
+    variance: 0.1
+    variance: 0.1
+    variance: 0.2
+    variance: 0.2
+  }
+}
+layer {
+  name: "mbox_loc"
+  type: "Concat"
+  bottom: "conv4_3_norm_mbox_loc_flat"
+  bottom: "fc7_mbox_loc_flat"
+  bottom: "conv6_2_mbox_loc_flat"
+  bottom: "conv7_2_mbox_loc_flat"
+  bottom: "conv8_2_mbox_loc_flat"
+  bottom: "pool6_mbox_loc_flat"
+  top: "mbox_loc"
+  concat_param {
+    axis: 1
+  }
+}
+layer {
+  name: "mbox_conf"
+  type: "Concat"
+  bottom: "conv4_3_norm_mbox_conf_flat"
+  bottom: "fc7_mbox_conf_flat"
+  bottom: "conv6_2_mbox_conf_flat"
+  bottom: "conv7_2_mbox_conf_flat"
+  bottom: "conv8_2_mbox_conf_flat"
+  bottom: "pool6_mbox_conf_flat"
+  top: "mbox_conf"
+  concat_param {
+    axis: 1
+  }
+}
+layer {
+  name: "mbox_priorbox"
+  type: "Concat"
+  bottom: "conv4_3_norm_mbox_priorbox"
+  bottom: "fc7_mbox_priorbox"
+  bottom: "conv6_2_mbox_priorbox"
+  bottom: "conv7_2_mbox_priorbox"
+  bottom: "conv8_2_mbox_priorbox"
+  bottom: "pool6_mbox_priorbox"
+  top: "mbox_priorbox"
+  concat_param {
+    axis: 2
+  }
+}
+layer {
+  name: "mbox_conf_reshape"
+  type: "Reshape"
+  bottom: "mbox_conf"
+  top: "mbox_conf_reshape"
+  reshape_param {
+    shape {
+      dim: 0
+      dim: -1
+      dim: 21
+    }
+  }
+}
+layer {
+  name: "mbox_conf_softmax"
+  type: "Softmax"
+  bottom: "mbox_conf_reshape"
+  top: "mbox_conf_softmax"
+  softmax_param {
+    axis: 2
+  }
+}
+layer {
+  name: "mbox_conf_flatten"
+  type: "Flatten"
+  bottom: "mbox_conf_softmax"
+  top: "mbox_conf_flatten"
+  flatten_param {
+    axis: 1
+  }
+}
+layer {
+  name: "detection_out"
+  type: "DetectionOutput"
+  bottom: "mbox_loc"
+  bottom: "mbox_conf_flatten"
+  bottom: "mbox_priorbox"
+  top: "detection_out"
+  include {
+    phase: TEST
+  }
+  detection_output_param {
+    num_classes: 21
+    share_location: true
+    background_label_id: 0
+    nms_threshold: 0.45
+    top_k: 400
+    code_type: CENTER_SIZE
+    keep_top_k: 200
+    confidence_threshold: 0.01
+  }
+}
+
diff --git a/contrib/modules/dnn/samples/caffe_googlenet.cpp b/contrib/modules/dnn/samples/caffe_googlenet.cpp
index 0901cb5..ddd5d8b 100644
--- a/contrib/modules/dnn/samples/caffe_googlenet.cpp
+++ b/contrib/modules/dnn/samples/caffe_googlenet.cpp
@@ -84,23 +84,18 @@ std::vector<String> readClassNames(const char *filename = "synset_words.txt")
 
 int main(int argc, char **argv)
 {
+    cv::dnn::initModule();  //Required if OpenCV is built as static libs
+
     String modelTxt = "bvlc_googlenet.prototxt";
     String modelBin = "bvlc_googlenet.caffemodel";
     String imageFile = (argc > 1) ? argv[1] : "space_shuttle.jpg";
 
-    //! [Create the importer of Caffe model]
-    Ptr<dnn::Importer> importer;
-    try                                     //Try to import Caffe GoogleNet model
-    {
-        importer = dnn::createCaffeImporter(modelTxt, modelBin);
-    }
-    catch (const cv::Exception &err)        //Importer can throw errors, we will catch them
-    {
-        std::cerr << err.msg << std::endl;
-    }
-    //! [Create the importer of Caffe model]
+    //! [Read and initialize network]
+    Net net = dnn::readNetFromCaffe(modelTxt, modelBin);
+    //! [Read and initialize network]
 
-    if (!importer)
+    //! [Check that network was read successfully]
+    if (net.empty())
     {
         std::cerr << "Can't load network by using the following files: " << std::endl;
         std::cerr << "prototxt:   " << modelTxt << std::endl;
@@ -109,12 +104,7 @@ int main(int argc, char **argv)
         std::cerr << "http://dl.caffe.berkeleyvision.org/bvlc_googlenet.caffemodel" << std::endl;
         exit(-1);
     }
-
-    //! [Initialize network]
-    dnn::Net net;
-    importer->populateNet(net);
-    importer.release();                     //We don't need importer anymore
-    //! [Initialize network]
+    //! [Check that network was read successfully]
 
     //! [Prepare blob]
     Mat img = imread(imageFile);
@@ -124,8 +114,8 @@ int main(int argc, char **argv)
         exit(-1);
     }
 
-    resize(img, img, Size(224, 224));       //GoogLeNet accepts only 224x224 RGB-images
-    dnn::Blob inputBlob = dnn::Blob(img);   //Convert Mat to dnn::Blob image batch
+    resize(img, img, Size(224, 224));                   //GoogLeNet accepts only 224x224 RGB-images
+    dnn::Blob inputBlob = dnn::Blob::fromImages(img);   //Convert Mat to dnn::Blob batch of images
     //! [Prepare blob]
 
     //! [Set input blob]
diff --git a/contrib/modules/dnn/samples/fcn32s-heavy-pascal.prototxt b/contrib/modules/dnn/samples/fcn32s-heavy-pascal.prototxt
new file mode 100755
index 0000000..7b5a0c5
--- /dev/null
+++ b/contrib/modules/dnn/samples/fcn32s-heavy-pascal.prototxt
@@ -0,0 +1,502 @@
+#
+# This prototxt is based on voc-fcn32s/val.prototxt file from
+# https://github.com/shelhamer/fcn.berkeleyvision.org, which is distributed under
+# Caffe (BSD) license:
+# http://caffe.berkeleyvision.org/model_zoo.html#bvlc-model-license
+#
+name: "voc-fcn32s"
+input: "data"
+input_dim: 1
+input_dim: 3
+input_dim: 500
+input_dim: 500
+layer {
+  name: "conv1_1"
+  type: "Convolution"
+  bottom: "data"
+  top: "conv1_1"
+  param {
+    lr_mult: 1
+    decay_mult: 1
+  }
+  param {
+    lr_mult: 2
+    decay_mult: 0
+  }
+  convolution_param {
+    num_output: 64
+    pad: 100
+    kernel_size: 3
+    stride: 1
+  }
+}
+layer {
+  name: "relu1_1"
+  type: "ReLU"
+  bottom: "conv1_1"
+  top: "conv1_1"
+}
+layer {
+  name: "conv1_2"
+  type: "Convolution"
+  bottom: "conv1_1"
+  top: "conv1_2"
+  param {
+    lr_mult: 1
+    decay_mult: 1
+  }
+  param {
+    lr_mult: 2
+    decay_mult: 0
+  }
+  convolution_param {
+    num_output: 64
+    pad: 1
+    kernel_size: 3
+    stride: 1
+  }
+}
+layer {
+  name: "relu1_2"
+  type: "ReLU"
+  bottom: "conv1_2"
+  top: "conv1_2"
+}
+layer {
+  name: "pool1"
+  type: "Pooling"
+  bottom: "conv1_2"
+  top: "pool1"
+  pooling_param {
+    pool: MAX
+    kernel_size: 2
+    stride: 2
+  }
+}
+layer {
+  name: "conv2_1"
+  type: "Convolution"
+  bottom: "pool1"
+  top: "conv2_1"
+  param {
+    lr_mult: 1
+    decay_mult: 1
+  }
+  param {
+    lr_mult: 2
+    decay_mult: 0
+  }
+  convolution_param {
+    num_output: 128
+    pad: 1
+    kernel_size: 3
+    stride: 1
+  }
+}
+layer {
+  name: "relu2_1"
+  type: "ReLU"
+  bottom: "conv2_1"
+  top: "conv2_1"
+}
+layer {
+  name: "conv2_2"
+  type: "Convolution"
+  bottom: "conv2_1"
+  top: "conv2_2"
+  param {
+    lr_mult: 1
+    decay_mult: 1
+  }
+  param {
+    lr_mult: 2
+    decay_mult: 0
+  }
+  convolution_param {
+    num_output: 128
+    pad: 1
+    kernel_size: 3
+    stride: 1
+  }
+}
+layer {
+  name: "relu2_2"
+  type: "ReLU"
+  bottom: "conv2_2"
+  top: "conv2_2"
+}
+layer {
+  name: "pool2"
+  type: "Pooling"
+  bottom: "conv2_2"
+  top: "pool2"
+  pooling_param {
+    pool: MAX
+    kernel_size: 2
+    stride: 2
+  }
+}
+layer {
+  name: "conv3_1"
+  type: "Convolution"
+  bottom: "pool2"
+  top: "conv3_1"
+  param {
+    lr_mult: 1
+    decay_mult: 1
+  }
+  param {
+    lr_mult: 2
+    decay_mult: 0
+  }
+  convolution_param {
+    num_output: 256
+    pad: 1
+    kernel_size: 3
+    stride: 1
+  }
+}
+layer {
+  name: "relu3_1"
+  type: "ReLU"
+  bottom: "conv3_1"
+  top: "conv3_1"
+}
+layer {
+  name: "conv3_2"
+  type: "Convolution"
+  bottom: "conv3_1"
+  top: "conv3_2"
+  param {
+    lr_mult: 1
+    decay_mult: 1
+  }
+  param {
+    lr_mult: 2
+    decay_mult: 0
+  }
+  convolution_param {
+    num_output: 256
+    pad: 1
+    kernel_size: 3
+    stride: 1
+  }
+}
+layer {
+  name: "relu3_2"
+  type: "ReLU"
+  bottom: "conv3_2"
+  top: "conv3_2"
+}
+layer {
+  name: "conv3_3"
+  type: "Convolution"
+  bottom: "conv3_2"
+  top: "conv3_3"
+  param {
+    lr_mult: 1
+    decay_mult: 1
+  }
+  param {
+    lr_mult: 2
+    decay_mult: 0
+  }
+  convolution_param {
+    num_output: 256
+    pad: 1
+    kernel_size: 3
+    stride: 1
+  }
+}
+layer {
+  name: "relu3_3"
+  type: "ReLU"
+  bottom: "conv3_3"
+  top: "conv3_3"
+}
+layer {
+  name: "pool3"
+  type: "Pooling"
+  bottom: "conv3_3"
+  top: "pool3"
+  pooling_param {
+    pool: MAX
+    kernel_size: 2
+    stride: 2
+  }
+}
+layer {
+  name: "conv4_1"
+  type: "Convolution"
+  bottom: "pool3"
+  top: "conv4_1"
+  param {
+    lr_mult: 1
+    decay_mult: 1
+  }
+  param {
+    lr_mult: 2
+    decay_mult: 0
+  }
+  convolution_param {
+    num_output: 512
+    pad: 1
+    kernel_size: 3
+    stride: 1
+  }
+}
+layer {
+  name: "relu4_1"
+  type: "ReLU"
+  bottom: "conv4_1"
+  top: "conv4_1"
+}
+layer {
+  name: "conv4_2"
+  type: "Convolution"
+  bottom: "conv4_1"
+  top: "conv4_2"
+  param {
+    lr_mult: 1
+    decay_mult: 1
+  }
+  param {
+    lr_mult: 2
+    decay_mult: 0
+  }
+  convolution_param {
+    num_output: 512
+    pad: 1
+    kernel_size: 3
+    stride: 1
+  }
+}
+layer {
+  name: "relu4_2"
+  type: "ReLU"
+  bottom: "conv4_2"
+  top: "conv4_2"
+}
+layer {
+  name: "conv4_3"
+  type: "Convolution"
+  bottom: "conv4_2"
+  top: "conv4_3"
+  param {
+    lr_mult: 1
+    decay_mult: 1
+  }
+  param {
+    lr_mult: 2
+    decay_mult: 0
+  }
+  convolution_param {
+    num_output: 512
+    pad: 1
+    kernel_size: 3
+    stride: 1
+  }
+}
+layer {
+  name: "relu4_3"
+  type: "ReLU"
+  bottom: "conv4_3"
+  top: "conv4_3"
+}
+layer {
+  name: "pool4"
+  type: "Pooling"
+  bottom: "conv4_3"
+  top: "pool4"
+  pooling_param {
+    pool: MAX
+    kernel_size: 2
+    stride: 2
+  }
+}
+layer {
+  name: "conv5_1"
+  type: "Convolution"
+  bottom: "pool4"
+  top: "conv5_1"
+  param {
+    lr_mult: 1
+    decay_mult: 1
+  }
+  param {
+    lr_mult: 2
+    decay_mult: 0
+  }
+  convolution_param {
+    num_output: 512
+    pad: 1
+    kernel_size: 3
+    stride: 1
+  }
+}
+layer {
+  name: "relu5_1"
+  type: "ReLU"
+  bottom: "conv5_1"
+  top: "conv5_1"
+}
+layer {
+  name: "conv5_2"
+  type: "Convolution"
+  bottom: "conv5_1"
+  top: "conv5_2"
+  param {
+    lr_mult: 1
+    decay_mult: 1
+  }
+  param {
+    lr_mult: 2
+    decay_mult: 0
+  }
+  convolution_param {
+    num_output: 512
+    pad: 1
+    kernel_size: 3
+    stride: 1
+  }
+}
+layer {
+  name: "relu5_2"
+  type: "ReLU"
+  bottom: "conv5_2"
+  top: "conv5_2"
+}
+layer {
+  name: "conv5_3"
+  type: "Convolution"
+  bottom: "conv5_2"
+  top: "conv5_3"
+  param {
+    lr_mult: 1
+    decay_mult: 1
+  }
+  param {
+    lr_mult: 2
+    decay_mult: 0
+  }
+  convolution_param {
+    num_output: 512
+    pad: 1
+    kernel_size: 3
+    stride: 1
+  }
+}
+layer {
+  name: "relu5_3"
+  type: "ReLU"
+  bottom: "conv5_3"
+  top: "conv5_3"
+}
+layer {
+  name: "pool5"
+  type: "Pooling"
+  bottom: "conv5_3"
+  top: "pool5"
+  pooling_param {
+    pool: MAX
+    kernel_size: 2
+    stride: 2
+  }
+}
+layer {
+  name: "fc6"
+  type: "Convolution"
+  bottom: "pool5"
+  top: "fc6"
+  param {
+    lr_mult: 1
+    decay_mult: 1
+  }
+  param {
+    lr_mult: 2
+    decay_mult: 0
+  }
+  convolution_param {
+    num_output: 4096
+    pad: 0
+    kernel_size: 7
+    stride: 1
+  }
+}
+layer {
+  name: "relu6"
+  type: "ReLU"
+  bottom: "fc6"
+  top: "fc6"
+}
+layer {
+  name: "fc7"
+  type: "Convolution"
+  bottom: "fc6"
+  top: "fc7"
+  param {
+    lr_mult: 1
+    decay_mult: 1
+  }
+  param {
+    lr_mult: 2
+    decay_mult: 0
+  }
+  convolution_param {
+    num_output: 4096
+    pad: 0
+    kernel_size: 1
+    stride: 1
+  }
+}
+layer {
+  name: "relu7"
+  type: "ReLU"
+  bottom: "fc7"
+  top: "fc7"
+}
+layer {
+  name: "score_fr"
+  type: "Convolution"
+  bottom: "fc7"
+  top: "score_fr"
+  param {
+    lr_mult: 1
+    decay_mult: 1
+  }
+  param {
+    lr_mult: 2
+    decay_mult: 0
+  }
+  convolution_param {
+    num_output: 21
+    pad: 0
+    kernel_size: 1
+  }
+}
+layer {
+  name: "upscore"
+  type: "Deconvolution"
+  bottom: "score_fr"
+  top: "upscore"
+  param {
+    lr_mult: 0
+  }
+  convolution_param {
+    num_output: 21
+    bias_term: false
+    kernel_size: 64
+    stride: 32
+  }
+}
+layer {
+  name: "score"
+  type: "Crop"
+  bottom: "upscore"
+  bottom: "data"
+  top: "score"
+  crop_param {
+    axis: 2
+    offset: 19
+  }
+}
diff --git a/contrib/modules/dnn/samples/fcn8s-heavy-pascal.prototxt b/contrib/modules/dnn/samples/fcn8s-heavy-pascal.prototxt
new file mode 100755
index 0000000..426b40f
--- /dev/null
+++ b/contrib/modules/dnn/samples/fcn8s-heavy-pascal.prototxt
@@ -0,0 +1,612 @@
+#
+# This prototxt is based on voc-fcn8s/val.prototxt file from
+# https://github.com/shelhamer/fcn.berkeleyvision.org, which is distributed under
+# Caffe (BSD) license:
+# http://caffe.berkeleyvision.org/model_zoo.html#bvlc-model-license
+#
+name: "voc-fcn8s"
+input: "data"
+input_dim: 1
+input_dim: 3
+input_dim: 500
+input_dim: 500
+layer {
+  name: "conv1_1"
+  type: "Convolution"
+  bottom: "data"
+  top: "conv1_1"
+  param {
+    lr_mult: 1
+    decay_mult: 1
+  }
+  param {
+    lr_mult: 2
+    decay_mult: 0
+  }
+  convolution_param {
+    num_output: 64
+    pad: 100
+    kernel_size: 3
+    stride: 1
+  }
+}
+layer {
+  name: "relu1_1"
+  type: "ReLU"
+  bottom: "conv1_1"
+  top: "conv1_1"
+}
+layer {
+  name: "conv1_2"
+  type: "Convolution"
+  bottom: "conv1_1"
+  top: "conv1_2"
+  param {
+    lr_mult: 1
+    decay_mult: 1
+  }
+  param {
+    lr_mult: 2
+    decay_mult: 0
+  }
+  convolution_param {
+    num_output: 64
+    pad: 1
+    kernel_size: 3
+    stride: 1
+  }
+}
+layer {
+  name: "relu1_2"
+  type: "ReLU"
+  bottom: "conv1_2"
+  top: "conv1_2"
+}
+layer {
+  name: "pool1"
+  type: "Pooling"
+  bottom: "conv1_2"
+  top: "pool1"
+  pooling_param {
+    pool: MAX
+    kernel_size: 2
+    stride: 2
+  }
+}
+layer {
+  name: "conv2_1"
+  type: "Convolution"
+  bottom: "pool1"
+  top: "conv2_1"
+  param {
+    lr_mult: 1
+    decay_mult: 1
+  }
+  param {
+    lr_mult: 2
+    decay_mult: 0
+  }
+  convolution_param {
+    num_output: 128
+    pad: 1
+    kernel_size: 3
+    stride: 1
+  }
+}
+layer {
+  name: "relu2_1"
+  type: "ReLU"
+  bottom: "conv2_1"
+  top: "conv2_1"
+}
+layer {
+  name: "conv2_2"
+  type: "Convolution"
+  bottom: "conv2_1"
+  top: "conv2_2"
+  param {
+    lr_mult: 1
+    decay_mult: 1
+  }
+  param {
+    lr_mult: 2
+    decay_mult: 0
+  }
+  convolution_param {
+    num_output: 128
+    pad: 1
+    kernel_size: 3
+    stride: 1
+  }
+}
+layer {
+  name: "relu2_2"
+  type: "ReLU"
+  bottom: "conv2_2"
+  top: "conv2_2"
+}
+layer {
+  name: "pool2"
+  type: "Pooling"
+  bottom: "conv2_2"
+  top: "pool2"
+  pooling_param {
+    pool: MAX
+    kernel_size: 2
+    stride: 2
+  }
+}
+layer {
+  name: "conv3_1"
+  type: "Convolution"
+  bottom: "pool2"
+  top: "conv3_1"
+  param {
+    lr_mult: 1
+    decay_mult: 1
+  }
+  param {
+    lr_mult: 2
+    decay_mult: 0
+  }
+  convolution_param {
+    num_output: 256
+    pad: 1
+    kernel_size: 3
+    stride: 1
+  }
+}
+layer {
+  name: "relu3_1"
+  type: "ReLU"
+  bottom: "conv3_1"
+  top: "conv3_1"
+}
+layer {
+  name: "conv3_2"
+  type: "Convolution"
+  bottom: "conv3_1"
+  top: "conv3_2"
+  param {
+    lr_mult: 1
+    decay_mult: 1
+  }
+  param {
+    lr_mult: 2
+    decay_mult: 0
+  }
+  convolution_param {
+    num_output: 256
+    pad: 1
+    kernel_size: 3
+    stride: 1
+  }
+}
+layer {
+  name: "relu3_2"
+  type: "ReLU"
+  bottom: "conv3_2"
+  top: "conv3_2"
+}
+layer {
+  name: "conv3_3"
+  type: "Convolution"
+  bottom: "conv3_2"
+  top: "conv3_3"
+  param {
+    lr_mult: 1
+    decay_mult: 1
+  }
+  param {
+    lr_mult: 2
+    decay_mult: 0
+  }
+  convolution_param {
+    num_output: 256
+    pad: 1
+    kernel_size: 3
+    stride: 1
+  }
+}
+layer {
+  name: "relu3_3"
+  type: "ReLU"
+  bottom: "conv3_3"
+  top: "conv3_3"
+}
+layer {
+  name: "pool3"
+  type: "Pooling"
+  bottom: "conv3_3"
+  top: "pool3"
+  pooling_param {
+    pool: MAX
+    kernel_size: 2
+    stride: 2
+  }
+}
+layer {
+  name: "conv4_1"
+  type: "Convolution"
+  bottom: "pool3"
+  top: "conv4_1"
+  param {
+    lr_mult: 1
+    decay_mult: 1
+  }
+  param {
+    lr_mult: 2
+    decay_mult: 0
+  }
+  convolution_param {
+    num_output: 512
+    pad: 1
+    kernel_size: 3
+    stride: 1
+  }
+}
+layer {
+  name: "relu4_1"
+  type: "ReLU"
+  bottom: "conv4_1"
+  top: "conv4_1"
+}
+layer {
+  name: "conv4_2"
+  type: "Convolution"
+  bottom: "conv4_1"
+  top: "conv4_2"
+  param {
+    lr_mult: 1
+    decay_mult: 1
+  }
+  param {
+    lr_mult: 2
+    decay_mult: 0
+  }
+  convolution_param {
+    num_output: 512
+    pad: 1
+    kernel_size: 3
+    stride: 1
+  }
+}
+layer {
+  name: "relu4_2"
+  type: "ReLU"
+  bottom: "conv4_2"
+  top: "conv4_2"
+}
+layer {
+  name: "conv4_3"
+  type: "Convolution"
+  bottom: "conv4_2"
+  top: "conv4_3"
+  param {
+    lr_mult: 1
+    decay_mult: 1
+  }
+  param {
+    lr_mult: 2
+    decay_mult: 0
+  }
+  convolution_param {
+    num_output: 512
+    pad: 1
+    kernel_size: 3
+    stride: 1
+  }
+}
+layer {
+  name: "relu4_3"
+  type: "ReLU"
+  bottom: "conv4_3"
+  top: "conv4_3"
+}
+layer {
+  name: "pool4"
+  type: "Pooling"
+  bottom: "conv4_3"
+  top: "pool4"
+  pooling_param {
+    pool: MAX
+    kernel_size: 2
+    stride: 2
+  }
+}
+layer {
+  name: "conv5_1"
+  type: "Convolution"
+  bottom: "pool4"
+  top: "conv5_1"
+  param {
+    lr_mult: 1
+    decay_mult: 1
+  }
+  param {
+    lr_mult: 2
+    decay_mult: 0
+  }
+  convolution_param {
+    num_output: 512
+    pad: 1
+    kernel_size: 3
+    stride: 1
+  }
+}
+layer {
+  name: "relu5_1"
+  type: "ReLU"
+  bottom: "conv5_1"
+  top: "conv5_1"
+}
+layer {
+  name: "conv5_2"
+  type: "Convolution"
+  bottom: "conv5_1"
+  top: "conv5_2"
+  param {
+    lr_mult: 1
+    decay_mult: 1
+  }
+  param {
+    lr_mult: 2
+    decay_mult: 0
+  }
+  convolution_param {
+    num_output: 512
+    pad: 1
+    kernel_size: 3
+    stride: 1
+  }
+}
+layer {
+  name: "relu5_2"
+  type: "ReLU"
+  bottom: "conv5_2"
+  top: "conv5_2"
+}
+layer {
+  name: "conv5_3"
+  type: "Convolution"
+  bottom: "conv5_2"
+  top: "conv5_3"
+  param {
+    lr_mult: 1
+    decay_mult: 1
+  }
+  param {
+    lr_mult: 2
+    decay_mult: 0
+  }
+  convolution_param {
+    num_output: 512
+    pad: 1
+    kernel_size: 3
+    stride: 1
+  }
+}
+layer {
+  name: "relu5_3"
+  type: "ReLU"
+  bottom: "conv5_3"
+  top: "conv5_3"
+}
+layer {
+  name: "pool5"
+  type: "Pooling"
+  bottom: "conv5_3"
+  top: "pool5"
+  pooling_param {
+    pool: MAX
+    kernel_size: 2
+    stride: 2
+  }
+}
+layer {
+  name: "fc6"
+  type: "Convolution"
+  bottom: "pool5"
+  top: "fc6"
+  param {
+    lr_mult: 1
+    decay_mult: 1
+  }
+  param {
+    lr_mult: 2
+    decay_mult: 0
+  }
+  convolution_param {
+    num_output: 4096
+    pad: 0
+    kernel_size: 7
+    stride: 1
+  }
+}
+layer {
+  name: "relu6"
+  type: "ReLU"
+  bottom: "fc6"
+  top: "fc6"
+}
+layer {
+  name: "fc7"
+  type: "Convolution"
+  bottom: "fc6"
+  top: "fc7"
+  param {
+    lr_mult: 1
+    decay_mult: 1
+  }
+  param {
+    lr_mult: 2
+    decay_mult: 0
+  }
+  convolution_param {
+    num_output: 4096
+    pad: 0
+    kernel_size: 1
+    stride: 1
+  }
+}
+layer {
+  name: "relu7"
+  type: "ReLU"
+  bottom: "fc7"
+  top: "fc7"
+}
+layer {
+  name: "score_fr"
+  type: "Convolution"
+  bottom: "fc7"
+  top: "score_fr"
+  param {
+    lr_mult: 1
+    decay_mult: 1
+  }
+  param {
+    lr_mult: 2
+    decay_mult: 0
+  }
+  convolution_param {
+    num_output: 21
+    pad: 0
+    kernel_size: 1
+  }
+}
+layer {
+  name: "upscore2"
+  type: "Deconvolution"
+  bottom: "score_fr"
+  top: "upscore2"
+  param {
+    lr_mult: 0
+  }
+  convolution_param {
+    num_output: 21
+    bias_term: false
+    kernel_size: 4
+    stride: 2
+  }
+}
+layer {
+  name: "score_pool4"
+  type: "Convolution"
+  bottom: "pool4"
+  top: "score_pool4"
+  param {
+    lr_mult: 1
+    decay_mult: 1
+  }
+  param {
+    lr_mult: 2
+    decay_mult: 0
+  }
+  convolution_param {
+    num_output: 21
+    pad: 0
+    kernel_size: 1
+  }
+}
+layer {
+  name: "score_pool4c"
+  type: "Crop"
+  bottom: "score_pool4"
+  bottom: "upscore2"
+  top: "score_pool4c"
+  crop_param {
+    axis: 2
+    offset: 5
+  }
+}
+layer {
+  name: "fuse_pool4"
+  type: "Eltwise"
+  bottom: "upscore2"
+  bottom: "score_pool4c"
+  top: "fuse_pool4"
+  eltwise_param {
+    operation: SUM
+  }
+}
+layer {
+  name: "upscore_pool4"
+  type: "Deconvolution"
+  bottom: "fuse_pool4"
+  top: "upscore_pool4"
+  param {
+    lr_mult: 0
+  }
+  convolution_param {
+    num_output: 21
+    bias_term: false
+    kernel_size: 4
+    stride: 2
+  }
+}
+layer {
+  name: "score_pool3"
+  type: "Convolution"
+  bottom: "pool3"
+  top: "score_pool3"
+  param {
+    lr_mult: 1
+    decay_mult: 1
+  }
+  param {
+    lr_mult: 2
+    decay_mult: 0
+  }
+  convolution_param {
+    num_output: 21
+    pad: 0
+    kernel_size: 1
+  }
+}
+layer {
+  name: "score_pool3c"
+  type: "Crop"
+  bottom: "score_pool3"
+  bottom: "upscore_pool4"
+  top: "score_pool3c"
+  crop_param {
+    axis: 2
+    offset: 9
+  }
+}
+layer {
+  name: "fuse_pool3"
+  type: "Eltwise"
+  bottom: "upscore_pool4"
+  bottom: "score_pool3c"
+  top: "fuse_pool3"
+  eltwise_param {
+    operation: SUM
+  }
+}
+layer {
+  name: "upscore8"
+  type: "Deconvolution"
+  bottom: "fuse_pool3"
+  top: "upscore8"
+  param {
+    lr_mult: 0
+  }
+  convolution_param {
+    num_output: 21
+    bias_term: false
+    kernel_size: 16
+    stride: 8
+  }
+}
+layer {
+  name: "score"
+  type: "Crop"
+  bottom: "upscore8"
+  bottom: "data"
+  top: "score"
+  crop_param {
+    axis: 2
+    offset: 31
+  }
+}
diff --git a/contrib/modules/dnn/samples/fcn_semsegm.cpp b/contrib/modules/dnn/samples/fcn_semsegm.cpp
new file mode 100755
index 0000000..bdeb75c
--- /dev/null
+++ b/contrib/modules/dnn/samples/fcn_semsegm.cpp
@@ -0,0 +1,159 @@
+#include <opencv2/dnn.hpp>
+#include <opencv2/imgproc.hpp>
+#include <opencv2/highgui.hpp>
+#include <opencv2/core/ocl.hpp>
+using namespace cv;
+using namespace cv::dnn;
+
+#include <fstream>
+#include <iostream>
+#include <cstdlib>
+using namespace std;
+
+static const string fcnType = "fcn8s";
+
+static vector<cv::Vec3b> readColors(const string &filename = "pascal-classes.txt")
+{
+    vector<cv::Vec3b> colors;
+
+    ifstream fp(filename.c_str());
+    if (!fp.is_open())
+    {
+        cerr << "File with colors not found: " << filename << endl;
+        exit(-1);
+    }
+
+    string line;
+    while (!fp.eof())
+    {
+        getline(fp, line);
+        if (line.length())
+        {
+            stringstream ss(line);
+
+            string name; ss >> name;
+            int temp;
+            cv::Vec3b color;
+            ss >> temp; color[0] = temp;
+            ss >> temp; color[1] = temp;
+            ss >> temp; color[2] = temp;
+            colors.push_back(color);
+        }
+    }
+
+    fp.close();
+    return colors;
+}
+
+static void colorizeSegmentation(dnn::Blob &score, const vector<cv::Vec3b> &colors, cv::Mat &segm)
+{
+    const int rows = score.rows();
+    const int cols = score.cols();
+    const int chns = score.channels();
+
+    cv::Mat maxCl(rows, cols, CV_8UC1);
+    cv::Mat maxVal(rows, cols, CV_32FC1);
+    for (int ch = 0; ch < chns; ch++)
+    {
+        for (int row = 0; row < rows; row++)
+        {
+            const float *ptrScore = score.ptrf(0, ch, row);
+            uchar *ptrMaxCl = maxCl.ptr<uchar>(row);
+            float *ptrMaxVal = maxVal.ptr<float>(row);
+            for (int col = 0; col < cols; col++)
+            {
+                if (ptrScore[col] > ptrMaxVal[col])
+                {
+                    ptrMaxVal[col] = ptrScore[col];
+                    ptrMaxCl[col] = ch;
+                }
+            }
+        }
+    }
+
+    segm.create(rows, cols, CV_8UC3);
+    for (int row = 0; row < rows; row++)
+    {
+        const uchar *ptrMaxCl = maxCl.ptr<uchar>(row);
+        cv::Vec3b *ptrSegm = segm.ptr<cv::Vec3b>(row);
+        for (int col = 0; col < cols; col++)
+        {
+            ptrSegm[col] = colors[ptrMaxCl[col]];
+        }
+    }
+
+}
+
+int main(int argc, char **argv)
+{
+    cv::dnn::initModule();          //Required if OpenCV is built as static libs
+    cv::ocl::setUseOpenCL(false);   //OpenCL switcher
+
+    String modelTxt = fcnType + "-heavy-pascal.prototxt";
+    String modelBin = fcnType + "-heavy-pascal.caffemodel";
+    String imageFile = (argc > 1) ? argv[1] : "rgb.jpg";
+
+    vector<cv::Vec3b> colors = readColors();
+
+    //! [Create the importer of Caffe model]
+    Ptr<dnn::Importer> importer;
+    try                                     //Try to import Caffe GoogleNet model
+    {
+        importer = dnn::createCaffeImporter(modelTxt, modelBin);
+    }
+    catch (const cv::Exception &err)        //Importer can throw errors, we will catch them
+    {
+        cerr << err.msg << endl;
+    }
+    //! [Create the importer of Caffe model]
+
+    if (!importer)
+    {
+        cerr << "Can't load network by using the following files: " << endl;
+        cerr << "prototxt:   " << modelTxt << endl;
+        cerr << "caffemodel: " << modelBin << endl;
+        cerr << fcnType << "-heavy-pascal.caffemodel can be downloaded here:" << endl;
+        cerr << "http://dl.caffe.berkeleyvision.org/" << fcnType << "-heavy-pascal.caffemodel" << endl;
+        exit(-1);
+    }
+
+    //! [Initialize network]
+    dnn::Net net;
+    importer->populateNet(net);
+    importer.release();                     //We don't need importer anymore
+    //! [Initialize network]
+
+    //! [Prepare blob]
+    Mat img = imread(imageFile);
+    if (img.empty())
+    {
+        cerr << "Can't read image from the file: " << imageFile << endl;
+        exit(-1);
+    }
+
+    resize(img, img, Size(500, 500));       //FCN accepts 500x500 RGB-images
+    dnn::Blob inputBlob = dnn::Blob::fromImages(img);   //Convert Mat to dnn::Blob batch of images
+    //! [Prepare blob]
+
+    //! [Set input blob]
+    net.setBlob(".data", inputBlob);        //set the network input
+    //! [Set input blob]
+
+    //! [Make forward pass]
+    double t = (double)cv::getTickCount();
+    net.forward();                          //compute output
+    t = (double)cv::getTickCount() - t;
+    printf("processing time: %.1fms\n", t*1000./getTickFrequency());
+    //! [Make forward pass]
+
+    //! [Gather output]
+    dnn::Blob score = net.getBlob("score");
+
+    cv::Mat colorize;
+    colorizeSegmentation(score, colors, colorize);
+    cv::Mat show;
+    cv::addWeighted(img, 0.4, colorize, 0.6, 0.0, show);
+    cv::imshow("show", show);
+    cv::waitKey(0);
+    return 0;
+} //main
diff --git a/contrib/modules/dnn/samples/googlenet_python.py b/contrib/modules/dnn/samples/googlenet_python.py
new file mode 100644
index 0000000..53ccdc5
--- /dev/null
+++ b/contrib/modules/dnn/samples/googlenet_python.py
@@ -0,0 +1,34 @@
+from __future__ import print_function
+import numpy as np
+import cv2
+from cv2 import dnn
+import timeit
+
+def prepare_image(img):
+    img = cv2.resize(img, (224, 224))
+    #convert interleaved image (RGBRGB) to planar(RRGGBB)
+    blob = np.moveaxis(img, 2, 0)
+    blob = np.reshape(blob.astype(np.float32), (-1, 3, 224, 224))
+    return blob
+
+def timeit_forward(net):
+    print("OpenCL:", cv2.ocl.useOpenCL())
+    print("Runtime:", timeit.timeit(lambda: net.forward(), number=10))
+
+def get_class_list():
+    with open('synset_words.txt', 'rt') as f:
+        return [ x[x.find(" ") + 1 :] for x in f ]
+
+blob = prepare_image(cv2.imread('space_shuttle.jpg'))
+print("Input:", blob.shape, blob.dtype)
+
+cv2.ocl.setUseOpenCL(True)  #Disable OCL if you want
+net = dnn.readNetFromCaffe('bvlc_googlenet.prototxt', 'bvlc_googlenet.caffemodel')
+net.setBlob(".data", blob)
+net.forward()
+#timeit_forward(net)        #Uncomment to check performance
+
+prob = net.getBlob("prob")
+print("Output:", prob.shape, prob.dtype)
+classes = get_class_list()
+print("Best match", classes[prob.argmax()])
\ No newline at end of file
diff --git a/contrib/modules/dnn/samples/pascal-classes.txt b/contrib/modules/dnn/samples/pascal-classes.txt
new file mode 100755
index 0000000..a3a62c1
--- /dev/null
+++ b/contrib/modules/dnn/samples/pascal-classes.txt
@@ -0,0 +1,21 @@
+background 0 0 0
+aeroplane 128 0 0
+bicycle 0 128 0
+bird 128 128 0
+boat 0 0 128
+bottle 128 0 128
+bus 0 128 128
+car 128 128 128
+cat 64 0 0
+chair 192 0 0
+cow 64 128 0
+diningtable 192 128 0
+dog 64 0 128
+horse 192 0 128
+motorbike 64 128 128
+person 192 128 128
+pottedplant 0 64 0
+sheep 128 64 0
+sofa 0 192 0
+train 128 192 0
+tvmonitor 0 64 128
diff --git a/contrib/modules/dnn/samples/rgb.jpg b/contrib/modules/dnn/samples/rgb.jpg
new file mode 100755
index 0000000..f78e6e4
Binary files /dev/null and b/contrib/modules/dnn/samples/rgb.jpg differ
diff --git a/contrib/modules/dnn/samples/ssd_object_detection.cpp b/contrib/modules/dnn/samples/ssd_object_detection.cpp
new file mode 100644
index 0000000..ec01d8f
--- /dev/null
+++ b/contrib/modules/dnn/samples/ssd_object_detection.cpp
@@ -0,0 +1,153 @@
+#include <opencv2/dnn.hpp>
+#include <opencv2/imgproc.hpp>
+#include <opencv2/highgui.hpp>
+using namespace cv;
+using namespace cv::dnn;
+
+#include <fstream>
+#include <iostream>
+#include <cstdlib>
+using namespace std;
+
+const size_t width = 300;
+const size_t height = 300;
+
+Mat getMean(const size_t& imageHeight, const size_t& imageWidth)
+{
+    Mat mean;
+
+    const int meanValues[3] = {104, 117, 123};
+    vector<Mat> meanChannels;
+    for(size_t i = 0; i < 3; i++)
+    {
+        Mat channel(imageHeight, imageWidth, CV_32F, Scalar(meanValues[i]));
+        meanChannels.push_back(channel);
+    }
+    cv::merge(meanChannels, mean);
+    return mean;
+}
+
+Mat preprocess(const Mat& frame)
+{
+    Mat preprocessed;
+    frame.convertTo(preprocessed, CV_32FC3);
+    resize(preprocessed, preprocessed, Size(width, height)); //SSD accepts 300x300 RGB-images
+
+    Mat mean = getMean(width, height);
+    cv::subtract(preprocessed, mean, preprocessed);
+
+    return preprocessed;
+}
+
+const char* about = "This sample uses Single-Shot Detector "
+                    "(https://arxiv.org/abs/1512.02325)"
+                    "to detect objects on image\n"; // TODO: link
+
+const char* params
+    = "{ help           | false | print usage         }"
+      "{ proto          |       | model configuration }"
+      "{ model          |       | model weights       }"
+      "{ image          |       | image for detection }"
+      "{ min_confidence | 0.5   | min confidence      }";
+
+int main(int argc, char** argv)
+{
+    cv::CommandLineParser parser(argc, argv, params);
+
+    if (parser.get<bool>("help"))
+    {
+        std::cout << about << std::endl;
+        parser.printMessage();
+        return 0;
+    }
+
+    cv::dnn::initModule();          //Required if OpenCV is built as static libs
+
+    String modelConfiguration = parser.get<string>("proto");
+    String modelBinary = parser.get<string>("model");
+
+    //! [Create the importer of Caffe model]
+    Ptr<dnn::Importer> importer;
+
+    // Import Caffe SSD model
+    try
+    {
+        importer = dnn::createCaffeImporter(modelConfiguration, modelBinary);
+    }
+    catch (const cv::Exception &err) //Importer can throw errors, we will catch them
+    {
+        cerr << err.msg << endl;
+    }
+    //! [Create the importer of Caffe model]
+
+    if (!importer)
+    {
+        cerr << "Can't load network by using the following files: " << endl;
+        cerr << "prototxt:   " << modelConfiguration << endl;
+        cerr << "caffemodel: " << modelBinary << endl;
+        cerr << "Models can be downloaded here:" << endl;
+        cerr << "https://github.com/weiliu89/caffe/tree/ssd#models" << endl;
+        exit(-1);
+    }
+
+    //! [Initialize network]
+    dnn::Net net;
+    importer->populateNet(net);
+    importer.release();          //We don't need importer anymore
+    //! [Initialize network]
+
+    cv::Mat frame = cv::imread(parser.get<string>("image"), -1);
+
+    //! [Prepare blob]
+    Mat preprocessedFrame = preprocess(frame);
+
+    dnn::Blob inputBlob = dnn::Blob::fromImages(preprocessedFrame); //Convert Mat to dnn::Blob image
+    //! [Prepare blob]
+
+    //! [Set input blob]
+    net.setBlob(".data", inputBlob);                //set the network input
+    //! [Set input blob]
+
+    //! [Make forward pass]
+    net.forward();                                  //compute output
+    //! [Make forward pass]
+
+    //! [Gather output]
+    dnn::Blob detection = net.getBlob("detection_out");
+    Mat detectionMat(detection.rows(), detection.cols(), CV_32F, detection.ptrf());
+
+    float confidenceThreshold = parser.get<float>("min_confidence");
+    for(int i = 0; i < detectionMat.rows; i++)
+    {
+        float confidence = detectionMat.at<float>(i, 2);
+
+        if(confidence > confidenceThreshold)
+        {
+            size_t objectClass = detectionMat.at<float>(i, 1);
+
+            float xLeftBottom = detectionMat.at<float>(i, 3) * frame.cols;
+            float yLeftBottom = detectionMat.at<float>(i, 4) * frame.rows;
+            float xRightTop = detectionMat.at<float>(i, 5) * frame.cols;
+            float yRightTop = detectionMat.at<float>(i, 6) * frame.rows;
+
+            std::cout << "Class: " << objectClass << std::endl;
+            std::cout << "Confidence: " << confidence << std::endl;
+
+            std::cout << " " << xLeftBottom
+                      << " " << yLeftBottom
+                      << " " << xRightTop
+                      << " " << yRightTop << std::endl;
+
+            Rect object(xLeftBottom, yLeftBottom,
+                        xRightTop - xLeftBottom,
+                        yRightTop - yLeftBottom);
+
+            rectangle(frame, object, Scalar(0, 255, 0));
+        }
+    }
+
+    imshow("detections", frame);
+    waitKey();
+
+    return 0;
+} // main
diff --git a/contrib/modules/dnn/samples/tf_inception.cpp b/contrib/modules/dnn/samples/tf_inception.cpp
new file mode 100644
index 0000000..e3b6e9c
--- /dev/null
+++ b/contrib/modules/dnn/samples/tf_inception.cpp
@@ -0,0 +1,182 @@
+// This file is part of OpenCV project.
+// It is subject to the license terms in the LICENSE file found in the top-level directory
+// of this distribution and at http://opencv.org/license.html.
+
+// Copyright (C) 2016, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+
+/*
+Sample of using OpenCV dnn module with Tensorflow Inception model.
+*/
+
+#include <opencv2/dnn.hpp>
+#include <opencv2/imgproc.hpp>
+#include <opencv2/highgui.hpp>
+using namespace cv;
+using namespace cv::dnn;
+
+#include <fstream>
+#include <iostream>
+#include <cstdlib>
+using namespace std;
+
+const String keys =
+        "{help h    || Sample app for loading Inception TensorFlow model. "
+                       "The model and class names list can be downloaded here: "
+                       "https://storage.googleapis.com/download.tensorflow.org/models/inception5h.zip }"
+        "{model m   |tensorflow_inception_graph.pb| path to TensorFlow .pb model file }"
+        "{image i   || path to image file }"
+        "{i_blob    | .input | input blob name) }"
+        "{o_blob    | softmax2 | output blob name) }"
+        "{c_names c | imagenet_comp_graph_label_strings.txt | path to file with classnames for class id }"
+        "{result r  || path to save output blob (optional, binary format, NCHW order) }"
+        ;
+
+void getMaxClass(dnn::Blob &probBlob, int *classId, double *classProb);
+std::vector<String> readClassNames(const char *filename);
+
+int main(int argc, char **argv)
+{
+    cv::CommandLineParser parser(argc, argv, keys);
+
+    if (parser.has("help"))
+    {
+        parser.printMessage();
+        return 0;
+    }
+
+    String modelFile = parser.get<String>("model");
+    String imageFile = parser.get<String>("image");
+    String inBlobName = parser.get<String>("i_blob");
+    String outBlobName = parser.get<String>("o_blob");
+
+    if (!parser.check())
+    {
+        parser.printErrors();
+        return 0;
+    }
+
+    String classNamesFile = parser.get<String>("c_names");
+    String resultFile = parser.get<String>("result");
+
+    //! [Create the importer of TensorFlow model]
+    Ptr<dnn::Importer> importer;
+    try                                     //Try to import TensorFlow AlexNet model
+    {
+        importer = dnn::createTensorflowImporter(modelFile);
+    }
+    catch (const cv::Exception &err)        //Importer can throw errors, we will catch them
+    {
+        std::cerr << err.msg << std::endl;
+    }
+    //! [Create the importer of Caffe model]
+
+    if (!importer)
+    {
+        std::cerr << "Can't load network by using the mode file: " << std::endl;
+        std::cerr << modelFile << std::endl;
+        exit(-1);
+    }
+
+    //! [Initialize network]
+    dnn::Net net;
+    importer->populateNet(net);
+    importer.release();                     //We don't need importer anymore
+    //! [Initialize network]
+
+    //! [Prepare blob]
+    Mat img = imread(imageFile);
+    if (img.empty())
+    {
+        std::cerr << "Can't read image from the file: " << imageFile << std::endl;
+        exit(-1);
+    }
+
+    cv::Size inputImgSize = cv::Size(224, 224);
+
+    if (inputImgSize != img.size())
+        resize(img, img, inputImgSize);       //Resize image to input size
+
+    cv::cvtColor(img, img, cv::COLOR_BGR2RGB);
+
+    dnn::Blob inputBlob = dnn::Blob::fromImages(img);   //Convert Mat to dnn::Blob image batch
+    //! [Prepare blob]
+
+    //! [Set input blob]
+    net.setBlob(inBlobName, inputBlob);        //set the network input
+    //! [Set input blob]
+
+    cv::TickMeter tm;
+    tm.start();
+
+    //! [Make forward pass]
+    net.forward();                          //compute output
+    //! [Make forward pass]
+
+    tm.stop();
+
+    //! [Gather output]
+    dnn::Blob prob = net.getBlob(outBlobName);   //gather output of "prob" layer
+
+    Mat& result = prob.matRef();
+
+    BlobShape shape = prob.shape();
+
+    if (!resultFile.empty()) {
+        CV_Assert(result.isContinuous());
+
+        ofstream fout(resultFile.c_str(), ios::out | ios::binary);
+        fout.write((char*)result.data, result.total() * sizeof(float));
+        fout.close();
+    }
+
+    std::cout << "Output blob shape " << shape  << std::endl;
+    std::cout << "Inference time, ms: " << tm.getTimeMilli()  << std::endl;
+
+    if (!classNamesFile.empty()) {
+        std::vector<String> classNames = readClassNames(classNamesFile.c_str());
+
+        int classId;
+        double classProb;
+        getMaxClass(prob, &classId, &classProb);//find the best class
+
+        //! [Print results]
+        std::cout << "Best class: #" << classId << " '" << classNames.at(classId) << "'" << std::endl;
+        std::cout << "Probability: " << classProb * 100 << "%" << std::endl;
+    }
+    return 0;
+} //main
+
+
+/* Find best class for the blob (i. e. class with maximal probability) */
+void getMaxClass(dnn::Blob &probBlob, int *classId, double *classProb)
+{
+    Mat probMat = probBlob.matRefConst().reshape(1, 1); //reshape the blob to 1x1000 matrix
+    Point classNumber;
+
+    minMaxLoc(probMat, NULL, classProb, NULL, &classNumber);
+    *classId = classNumber.x;
+}
+
+std::vector<String> readClassNames(const char *filename)
+{
+    std::vector<String> classNames;
+
+    std::ifstream fp(filename);
+    if (!fp.is_open())
+    {
+        std::cerr << "File with classes labels not found: " << filename << std::endl;
+        exit(-1);
+    }
+
+    std::string name;
+    while (!fp.eof())
+    {
+        std::getline(fp, name);
+        if (name.length())
+            classNames.push_back( name );
+    }
+
+    fp.close();
+    return classNames;
+}
diff --git a/contrib/modules/dnn/scripts/download_model.py b/contrib/modules/dnn/scripts/download_model.py
deleted file mode 100644
index d2951f5..0000000
--- a/contrib/modules/dnn/scripts/download_model.py
+++ /dev/null
@@ -1,79 +0,0 @@
-#!/usr/bin/env python
-import os
-import sys
-import time
-import urllib
-import hashlib
-import argparse
-import json
-
-
-def reporthook(count, block_size, total_size):
-    """
-    From http://blog.moleculea.com/2012/10/04/urlretrieve-progres-indicator/
-    """
-    global start_time
-    global prev_duration
-    if count == 0:
-        start_time = time.time()
-        prev_duration = -1
-        return
-    duration = max(1, time.time() - start_time)
-    if int(duration) == int(prev_duration):
-        return
-
-    progress_size = int(count * block_size)
-    speed = int(progress_size / (1024 * duration))
-    percent = int(count * block_size * 100 / total_size)
-    sys.stdout.write("\r...%d%%, %d MB, %d KB/s, %d seconds passed" %
-                     (percent, progress_size / (1024 * 1024), speed, duration))
-    sys.stdout.flush()
-    prev_duration = duration
-
-
-# Function for checking SHA1.
-def model_checks_out(filename, sha1):
-    with open(filename, 'r') as f:
-        return hashlib.sha1(f.read()).hexdigest() == sha1
-
-def model_download(filename, url, sha1):
-    # Check if model exists.
-    if os.path.exists(filename) and model_checks_out(filename, sha1):
-        print("Model {} already exists.".format(filename))
-        return
-
-    # Download and verify model.
-    urllib.urlretrieve(url, filename, reporthook)
-    print model_checks_out(filename, sha1)
-    if not model_checks_out(filename, sha1):
-        print("ERROR: model {} did not download correctly!".format(url))
-        sys.exit(1)
-
-if __name__ == '__main__':
-    parser = argparse.ArgumentParser(description="Downloading trained model binaries.")
-    parser.add_argument("download_list")
-    args = parser.parse_args()
-
-    test_dir = os.environ.get("OPENCV_TEST_DATA_PATH")
-    if not test_dir:
-        print "ERROR: OPENCV_TEST_DATA_PATH environment not specified"
-        sys.exit(1)
-
-    try:
-        with open(args.download_list, 'r') as f:
-            models_to_download = json.load(f)
-    except:
-        print "ERROR: Can't pasrse {}".format(args.download_list)
-        sys.exit(1)
-
-    for model_name in models_to_download:
-        model = models_to_download[model_name]
-
-        dst_dir = os.path.join(test_dir, os.path.dirname(model['file']))
-        dst_file = os.path.join(test_dir, model['file'])
-        if not os.path.exists(dst_dir):
-            print "ERROR: Can't find module testdata path '{}'".format(dst_dir)
-            sys.exit(1)
-
-        print "Downloading model '{}' to {} from {} ...".format(model_name, dst_file, model['url'])
-        model_download(dst_file, model['url'], model['sha1'])
\ No newline at end of file
diff --git a/contrib/modules/dnn/scripts/test_models.json b/contrib/modules/dnn/scripts/test_models.json
deleted file mode 100644
index 47b1315..0000000
--- a/contrib/modules/dnn/scripts/test_models.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
-  "googlenet": {
-    "file": "dnn/bvlc_googlenet.caffemodel",
-    "url": "http://dl.caffe.berkeleyvision.org/bvlc_googlenet.caffemodel",
-    "sha1": "405fc5acd08a3bb12de8ee5e23a96bec22f08204"
-  }
-}
\ No newline at end of file
diff --git a/contrib/modules/dnn/src/blob.cpp b/contrib/modules/dnn/src/blob.cpp
index 1ef47e0..9dc0d97 100644
--- a/contrib/modules/dnn/src/blob.cpp
+++ b/contrib/modules/dnn/src/blob.cpp
@@ -40,179 +40,382 @@
 //M*/
 
 #include "precomp.hpp"
+#include <opencv2/dnn/shape_utils.hpp>
 
 namespace cv
 {
 namespace dnn
 {
 
-    Blob::Blob()
-    {
-        int zeros[4] = { 0, 0, 0, 0 };
-        m = Mat(4, zeros, CV_32F, NULL);
-    }
+Blob::Blob()
+{
+    CV_DNN_UMAT_ONLY(state = UNINITIALIZED);
+}
 
-    static inline int getMatChannels(const Mat &mat)
+Blob::Blob(const BlobShape &shape, int type, int allocFlags)
+{
+    CV_DNN_UMAT_ONLY(state = UNINITIALIZED);
+    this->create(shape, type, allocFlags);
+}
+
+Blob::Blob(InputArray data)
+{
+#ifndef CV_DNN_UMAT
+    m = data.getMat();
+#else
+    if (data.isUMat())
     {
-       return (mat.dims <= 2) ? mat.channels() : mat.size[0];
+        um = data.getUMat();
+        state = HEAD_AT_UMAT;
     }
-
-    static BlobShape getBlobShpae(std::vector<Mat> &vmat, int requestedCn = -1)
+    else
     {
-        BlobShape shape(4);
-        int cnSum = 0, matCn;
+        m = data.getMat();
+        state = HEAD_AT_MAT;
+    }
+#endif
+}
 
-        CV_Assert(vmat.size() > 0);
+void Blob::create(const BlobShape &shape, int type, int allocFlags)
+{
+#ifndef CV_DNN_UMAT
+    CV_Assert(allocFlags & ALLOC_MAT);
+    m.create(shape.dims(), shape.ptr(), type);
+#else
+    CV_Assert(allocFlags & ALLOC_MAT || allocFlags & ALLOC_UMAT);
 
-        for (size_t i = 0; i < vmat.size(); i++)
-        {
-            Mat &mat = vmat[i];
-            CV_Assert(!mat.empty());
-            CV_Assert((mat.dims == 3 && mat.channels() == 1) || mat.dims <= 2);
+    if (allocFlags & ALLOC_MAT)
+        m.create(shape.dims(), shape.ptr(), type);
+    if (allocFlags & ALLOC_UMAT)
+        um.create(shape.dims(), shape.ptr(), type);
 
-            matCn = getMatChannels(mat);
-            cnSum += getMatChannels(mat);
+    if (state == UNINITIALIZED)
+    {
+        if (allocFlags & ALLOC_MAT && allocFlags & ALLOC_UMAT)
+            state = SYNCED;
+        else if (allocFlags & ALLOC_MAT)
+            state = HEAD_AT_MAT;
+        else
+            state = HEAD_AT_UMAT;
+    }
+#endif
+}
 
-            if (i == 0)
-            {
-                shape[-1] = mat.cols;
-                shape[-2] = mat.rows;
-                shape[-3] = (requestedCn <= 0) ? matCn : requestedCn;
-            }
-            else
-            {
-                if (mat.cols != shape[-1] || mat.rows != shape[-2])
-                    CV_Error(Error::StsError, "Each Mat.size() must be equal");
+void Blob::fill(InputArray in)
+{
+#ifdef CV_DNN_UMAT
+    CV_Assert(in.isMat() || in.isUMat());
+    if (in.isMat())
+    {
+        m = in.getMat();
+        state = HEAD_AT_MAT;
+    }
+    else
+    {
+        um = in.getUMat();
+        state = HEAD_AT_UMAT;
+    }
+#else
+    CV_Assert(in.isMat());
+    m = in.getMat();
+#endif
+}
 
-                if (requestedCn <= 0 && matCn != shape[-3])
-                    CV_Error(Error::StsError, "Each Mat.chnannels() (or number of planes) must be equal");
-            }
-        }
+static inline int getMatChannels(const Mat &mat)
+{
+    return (mat.dims <= 2) ? mat.channels() : mat.size[0];
+}
 
-        if (cnSum % shape[-3] != 0)
-            CV_Error(Error::StsError, "Total number of channels in vector is not a multiple of requsted channel number");
+static BlobShape getBlobShape(std::vector<Mat> &vmat, int requestedCn = -1)
+{
+    BlobShape shape(BlobShape::all(4));
+    int cnSum = 0, matCn;
 
-        shape[0] = cnSum / shape[-3];
-        return shape;
-    }
+    CV_Assert(vmat.size() > 0);
 
-    static std::vector<Mat> extractMatVector(InputArray in)
+    for (size_t i = 0; i < vmat.size(); i++)
     {
-        if (in.isMat() || in.isUMat())
-        {
-            return std::vector<Mat>(1, in.getMat());
-        }
-        else if (in.isMatVector())
-        {
-            return *static_cast<const std::vector<Mat>*>(in.getObj());
-        }
-        else if (in.isUMatVector())
+        Mat &mat = vmat[i];
+        CV_Assert(!mat.empty());
+        CV_Assert((mat.dims == 3 && mat.channels() == 1) || mat.dims <= 2);
+
+        matCn = getMatChannels(mat);
+        cnSum += getMatChannels(mat);
+
+        if (i == 0)
         {
-            std::vector<Mat> vmat;
-            in.getMatVector(vmat);
-            return vmat;
+            shape[-1] = mat.cols;
+            shape[-2] = mat.rows;
+            shape[-3] = (requestedCn <= 0) ? matCn : requestedCn;
         }
         else
         {
-            CV_Assert(in.isMat() || in.isMatVector() || in.isUMat() || in.isUMatVector());
-            return std::vector<Mat>();
+            if (mat.cols != shape[-1] || mat.rows != shape[-2])
+                CV_Error(Error::StsError, "Each Mat.size() must be equal");
+
+            if (requestedCn <= 0 && matCn != shape[-3])
+                CV_Error(Error::StsError, "Each Mat.chnannels() (or number of planes) must be equal");
         }
     }
 
-    Blob::Blob(InputArray image, int dstCn)
+    if (cnSum % shape[-3] != 0)
+        CV_Error(Error::StsError, "Total number of channels in vector is not a multiple of requsted channel number");
+
+    shape[0] = cnSum / shape[-3];
+    return shape;
+}
+
+static std::vector<Mat> extractMatVector(InputArray in)
+{
+    if (in.isMat() || in.isUMat())
+    {
+        return std::vector<Mat>(1, in.getMat());
+    }
+    else if (in.isMatVector())
+    {
+        return *static_cast<const std::vector<Mat>*>(in.getObj());
+    }
+    else if (in.isUMatVector())
     {
-        CV_Assert(dstCn == -1 || dstCn > 0);
-        std::vector<Mat> inMats = extractMatVector(image);
-        BlobShape dstShape = getBlobShpae(inMats, dstCn);
+        std::vector<Mat> vmat;
+        in.getMatVector(vmat);
+        return vmat;
+    }
+    else
+    {
+        CV_Assert(in.isMat() || in.isMatVector() || in.isUMat() || in.isUMatVector());
+        return std::vector<Mat>();
+    }
+}
 
-        m.create(dstShape.dims(), dstShape.ptr(), CV_32F);
+void Blob::batchFromImages(InputArray image, int dstCn)
+{
+    CV_Assert(dstCn == -1 || dstCn > 0);
+    std::vector<Mat> inMats = extractMatVector(image);
+    BlobShape dstShape = getBlobShape(inMats, dstCn);
 
-        std::vector<Mat> wrapBuf(dstShape[-3]);
-        int elemSize = (int)m.elemSize();
-        uchar *ptr = this->ptr();
-        for (size_t i = 0; i < inMats.size(); i++)
-        {
-            Mat inMat = inMats[i];
+    int dtype = CV_32F;
+    this->create(dstShape, dtype, ALLOC_MAT);
+    uchar *dstPtr = this->matRef().ptr();
+    int elemSize = CV_ELEM_SIZE(dtype);
 
-            if (inMat.dims <= 2)
-            {
-                inMat.convertTo(inMat, m.type());
+    std::vector<Mat> wrapBuf(dstShape[-3]);
+    for (size_t i = 0; i < inMats.size(); i++)
+    {
+        Mat inMat = inMats[i];
 
-                wrapBuf.resize(0);
-                for (int cn = 0; cn < inMat.channels(); cn++)
-                {
-                    wrapBuf.push_back(Mat(inMat.rows, inMat.cols, m.type(), ptr));
-                    ptr += elemSize * inMat.total();
-                }
+        if (inMat.dims <= 2)
+        {
+            inMat.convertTo(inMat, dtype);
 
-                cv::split(inMat, wrapBuf);
-            }
-            else
+            wrapBuf.resize(0);
+            for (int cn = 0; cn < inMat.channels(); cn++)
             {
-                inMat.convertTo(Mat(inMat.dims, inMat.size, m.type(), ptr), m.type());
-                ptr += elemSize * inMat.total();
+                wrapBuf.push_back(Mat(inMat.rows, inMat.cols, dtype, dstPtr));
+                dstPtr += elemSize * inMat.total();
             }
+
+            cv::split(inMat, wrapBuf);
+        }
+        else
+        {
+            inMat.convertTo(Mat(inMat.dims, inMat.size, dtype, dstPtr), dtype);
+            dstPtr += elemSize * inMat.total();
         }
     }
+}
+
+Blob Blob::fromImages(InputArray image, int dstCn)
+{
+    Blob res;
+    res.batchFromImages(image, dstCn);
+    return res;
+}
 
-    Blob::Blob(const BlobShape &shape, int type)
+void Blob::fill(const BlobShape &shape, int type, void *data, bool deepCopy)
+{
+    if (deepCopy)
     {
-        this->create(shape, type);
+        create(shape, type);
+        memcpy(ptr(), data, this->total() * CV_ELEM_SIZE(type));
     }
-
-    void Blob::fill(const BlobShape &shape, int type, void *data, bool deepCopy)
+    else
     {
-        CV_Assert(type == CV_32F || type == CV_64F);
+        m = Mat(shape.dims(), shape.ptr(), type, data);
+    }
+    CV_DNN_UMAT_ONLY(state = HEAD_AT_MAT);
+}
 
-        if (deepCopy)
-        {
-            m.create(shape.dims(), shape.ptr(), type);
-            memcpy(m.data, data, m.total() * m.elemSize());
-        }
-        else
+void Blob::setTo(InputArray value, int allocFlags)
+{
+#ifdef CV_DNN_UMAT
+    if (allocFlags == -1)
+    {
+        if (state == HEAD_AT_UMAT)
+            um.setTo(value);
+        else if (state == HEAD_AT_MAT)
+            m.setTo(value);
+        else //SYNCED or UNINITIALIZED
         {
-            m = Mat(shape.dims(), shape.ptr(), type, data);
+            um.setTo(value);
+            m.setTo(value);
+
+            if (state == UNINITIALIZED)
+                state = SYNCED;
         }
     }
+    else if (allocFlags == ALLOC_BOTH)
+    {
+        m.setTo(value);
+        um.setTo(value);
+        state = SYNCED;
+    }
+    else if (allocFlags == ALLOC_MAT)
+    {
+        matRef().setTo(value);
+    }
+    else if (allocFlags == ALLOC_UMAT)
+    {
+        umatRef().setTo(value);
+    }
+    else
+    {
+        CV_Error(Error::StsBadArg, "allocFlags sholud be -1 or one of Blob::AllocFlag values");
+    }
+#else
+    m.setTo(value);
+#endif
+}
 
-    void Blob::create(const BlobShape &shape, int type)
+void Blob::updateMat(bool syncData) const
+{
+#ifdef CV_DNN_UMAT
+    if (state == UNINITIALIZED || state == SYNCED || state == HEAD_AT_MAT)
     {
-        CV_Assert(type == CV_32F || type == CV_64F);
-        m.create(shape.dims(), shape.ptr(), type);
+        return;
+    }
+    else if (state == HEAD_AT_UMAT)
+    {
+        if (syncData)
+            um.copyTo(m);
+        else
+            m.create(dims(), sizes(), type());
+        state = SYNCED;
+    }
+    else
+    {
+        CV_Error(Error::StsInternal, "");
     }
+#else
+    (void)syncData;
+#endif
+}
 
-    inline void squeezeShape(const int srcDims, const int *srcSizes, const int dstDims, int *dstSizes)
+void Blob::updateUMat(bool syncData) const
+{
+#ifdef CV_DNN_UMAT
+    if (state == UNINITIALIZED || state == SYNCED || state == HEAD_AT_UMAT)
+    {
+        return;
+    }
+    else if (state == HEAD_AT_MAT)
     {
-        const int m = std::min(dstDims, srcDims);
+        if (syncData)
+            m.copyTo(um);
+        else
+            um.create(dims(), sizes(), type());
+    }
+    else
+    {
+        CV_Error(Error::StsInternal, "");
+    }
+#else
+    (void)syncData;
+#endif
+}
+
+void Blob::sync() const
+{
+    updateMat();
+    updateUMat();
+}
 
-        //copy common(last) dimensions
-        for (int i = 0; i < m; i++)
-            dstSizes[dstDims - 1 - i] = srcSizes[srcDims - 1 - i];
+Vec4i Blob::shape4() const
+{
+    return Vec4i(num(), channels(), rows(), cols());
+}
 
-        //either flatten extra dimensions
-        for (int i = m; i < srcDims; i++)
-            dstSizes[0] *= srcSizes[srcDims - 1 - i];
+//BlobShape
 
-        //either fill gaps
-        for (int i = m; i < dstDims; i++)
-            dstSizes[dstDims - 1 - i] = 1;
-    }
+std::ostream &operator<< (std::ostream &stream, const BlobShape &shape)
+{
+    stream << "[";
 
-    Vec4i Blob::shape4() const
+    for (int i = 0; i < shape.dims() - 1; i++)
+        stream << shape[i] << ", ";
+    if (shape.dims() > 0)
+        stream << shape[-1];
+
+    return stream << "]";
+}
+
+BlobShape computeShapeByReshapeMask(const BlobShape &srcShape, const BlobShape &maskShape, Range srcRange /*= Range::all()*/)
+{
+    if (srcRange == Range::all())
+        srcRange = Range(0, srcShape.dims());
+    else
     {
-        return Vec4i(num(), channels(), rows(), cols());
+        int sz = srcRange.size();
+        srcRange.start = srcShape.canonicalAxis(srcRange.start);
+        srcRange.end =  (srcRange.end == INT_MAX) ? srcShape.dims() : srcRange.start + sz;
     }
 
-    std::ostream &operator<< (std::ostream &stream, const BlobShape &shape)
+    CV_Assert(0 <= srcRange.start && srcRange.start <= srcRange.end && srcRange.end <= srcShape.dims());
+    BlobShape dstShape(srcShape.dims() - srcRange.size() + maskShape.dims(), (const int*)NULL);
+
+    std::copy(srcShape.ptr(), srcShape.ptr() + srcRange.start, dstShape.ptr());
+    std::copy(srcShape.ptr() + srcRange.end, srcShape.ptr() + srcShape.dims(), dstShape.ptr() + srcRange.start + maskShape.dims());
+
+    int inferDim = -1;
+    for (int i = 0; i < maskShape.dims(); i++)
     {
-        stream << "[";
+        if (maskShape[i] > 0)
+        {
+            dstShape[srcRange.start + i] = maskShape[i];
+        }
+        else if (maskShape[i] == 0)
+        {
+            if (srcRange.start + i >= srcShape.dims())
+                CV_Error(Error::StsBadArg, format("Copy dim[%d] (which has zero size) is out of the source shape bounds", srcRange.start + i));
+            dstShape[srcRange.start + i] = srcShape[srcRange.start + i];
+        }
+        else if (maskShape[i] == -1)
+        {
+            if (inferDim != -1)
+                CV_Error(Error::StsAssert, "Duplicate of inferred dim (which is denoted by -1)");
+            inferDim = srcRange.start + i;
+            dstShape[inferDim] = 1;
+        }
+        else
+            CV_Error(Error::StsBadArg, "maskShape[i] >= -1");
+    }
 
-        for (int i = 0; i < shape.dims() - 1; i++)
-            stream << shape[i] << ", ";
-        if (shape.dims() > 0)
-            stream << shape[-1];
+    if (inferDim != -1)
+    {
+        ptrdiff_t srcTotal = srcShape.total();
+        ptrdiff_t dstTotal = dstShape.total();
+        if (srcTotal % dstTotal != 0)
+            CV_Error(Error::StsBackTrace, "Can't infer a dim denoted by -1");
 
-        return stream << "]";
+        dstShape[inferDim] = (int)(srcTotal / dstTotal);
+    }
+    else
+    {
+        CV_Assert(srcShape.total() == dstShape.total());
     }
+
+    return dstShape;
+}
+
 }
 }
diff --git a/contrib/modules/dnn/src/caffe/caffe.proto b/contrib/modules/dnn/src/caffe/caffe.proto
index 8109821..f769fd0 100644
--- a/contrib/modules/dnn/src/caffe/caffe.proto
+++ b/contrib/modules/dnn/src/caffe/caffe.proto
@@ -73,6 +73,93 @@ message BlobProtoVector {
   repeated BlobProto blobs = 1;
 }
 
+message CropParameter {
+  // To crop, elements of the first bottom are selected to fit the dimensions
+  // of the second, reference bottom. The crop is configured by
+  // - the crop `axis` to pick the dimensions for cropping
+  // - the crop `offset` to set the shift for all/each dimension
+  // to align the cropped bottom with the reference bottom.
+  // All dimensions up to but excluding `axis` are preserved, while
+  // the dimensions including and trailing `axis` are cropped.
+  // If only one `offset` is set, then all dimensions are offset by this amount.
+  // Otherwise, the number of offsets must equal the number of cropped axes to
+  // shift the crop in each dimension accordingly.
+  // Note: standard dimensions are N,C,H,W so the default is a spatial crop,
+  // and `axis` may be negative to index from the end (e.g., -1 for the last
+  // axis).
+  optional int32 axis = 1 [default = 2];
+  repeated uint32 offset = 2;
+}
+
+message PermuteParameter {
+  // The new orders of the axes of data. Notice it should be with
+  // in the same range as the input data, and it starts from 0.
+  // Do not provide repeated order.
+  repeated uint32 order = 1;
+}
+
+// Message that stores parameters used by NormalizeBBoxLayer
+message NormalizeBBoxParameter {
+  optional bool across_spatial = 1 [default = true];
+  // Initial value of scale. Default is 1.0 for all
+  optional FillerParameter scale_filler = 2;
+  // Whether or not scale parameters are shared across channels.
+  optional bool channel_shared = 3 [default = true];
+  // Epsilon for not dividing by zero while normalizing variance
+  optional float eps = 4 [default = 1e-10];
+}
+
+// Message that store parameters used by PriorBoxLayer
+message PriorBoxParameter {
+  // Encode/decode type.
+  enum CodeType {
+    CORNER = 1;
+    CENTER_SIZE = 2;
+  }
+  // Minimum box size (in pixels). Required!
+  optional float min_size = 1;
+  // Maximum box size (in pixels). Required!
+  optional float max_size = 2;
+  // Various of aspect ratios. Duplicate ratios will be ignored.
+  // If none is provided, we use default ratio 1.
+  repeated float aspect_ratio = 3;
+  // If true, will flip each aspect ratio.
+  // For example, if there is aspect ratio "r",
+  // we will generate aspect ratio "1.0/r" as well.
+  optional bool flip = 4 [default = true];
+  // If true, will clip the prior so that it is within [0, 1]
+  optional bool clip = 5 [default = true];
+  // Variance for adjusting the prior bboxes.
+  repeated float variance = 6;
+}
+
+// Message that store parameters used by DetectionOutputLayer
+message DetectionOutputParameter {
+  // Number of classes to be predicted. Required!
+  optional uint32 num_classes = 1;
+  // If true, bounding box are shared among different classes.
+  optional bool share_location = 2 [default = true];
+  // Background label id. If there is no background class,
+  // set it as -1.
+  optional int32 background_label_id = 3 [default = 0];
+  // Type of coding method for bbox.
+  optional PriorBoxParameter.CodeType code_type = 6 [default = CORNER];
+  // If true, variance is encoded in target; otherwise we need to adjust the
+  // predicted offset accordingly.
+  optional bool variance_encoded_in_target = 8 [default = false];
+  // Number of total bboxes to be kept per image after nms step.
+  // -1 means keeping all bboxes after nms step.
+  optional int32 keep_top_k = 7 [default = -1];
+  // Only consider detections whose confidences are larger than a threshold.
+  // If not provided, consider all boxes.
+  optional float confidence_threshold = 9;
+  // Parameters used for non maximum suppression.
+  // Threshold to be used in nms.
+  optional float nms_threshold = 10 [default = 0.3];
+  // Maximum number of results to be kept.
+  optional int32 top_k = 11;
+}
+
 message Datum {
   optional int32 channels = 1;
   optional int32 height = 2;
@@ -317,7 +404,7 @@ message ParamSpec {
 // NOTE
 // Update the next available ID when you add a new LayerParameter field.
 //
-// LayerParameter next available layer-specific ID: 137 (last added: reduction_param)
+// LayerParameter next available layer-specific ID: 142 (last added: detection_output_param)
 message LayerParameter {
   optional string name = 1; // the layer name
   optional string type = 2; // the layer type
@@ -369,7 +456,9 @@ message LayerParameter {
   optional ConcatParameter concat_param = 104;
   optional ContrastiveLossParameter contrastive_loss_param = 105;
   optional ConvolutionParameter convolution_param = 106;
+  optional CropParameter crop_param = 137;
   optional DataParameter data_param = 107;
+  optional DetectionOutputParameter detection_output_param = 141;
   optional DropoutParameter dropout_param = 108;
   optional DummyDataParameter dummy_data_param = 109;
   optional EltwiseParameter eltwise_param = 110;
@@ -385,17 +474,20 @@ message LayerParameter {
   optional LRNParameter lrn_param = 118;
   optional MemoryDataParameter memory_data_param = 119;
   optional MVNParameter mvn_param = 120;
+  optional NormalizeBBoxParameter normalize_bbox_param = 139;
+  optional PermuteParameter permute_param = 138;
   optional PoolingParameter pooling_param = 121;
   optional PowerParameter power_param = 122;
   optional PReLUParameter prelu_param = 131;
+  optional PriorBoxParameter prior_box_param = 140;
   optional PythonParameter python_param = 130;
   optional ReductionParameter reduction_param = 136;
   optional ReLUParameter relu_param = 123;
   optional ReshapeParameter reshape_param = 133;
   optional SigmoidParameter sigmoid_param = 124;
+  optional SliceParameter slice_param = 126;
   optional SoftmaxParameter softmax_param = 125;
   optional SPPParameter spp_param = 132;
-  optional SliceParameter slice_param = 126;
   optional TanHParameter tanh_param = 127;
   optional ThresholdParameter threshold_param = 128;
   optional WindowDataParameter window_data_param = 129;
@@ -505,6 +597,12 @@ message ConvolutionParameter {
     CUDNN = 2;
   }
   optional Engine engine = 15 [default = DEFAULT];
+  // Factor used to dilate the kernel, (implicitly) zero-filling the resulting
+  // holes. (Kernel dilation is sometimes referred to by its use in the
+  // algorithme a trous from Holschneider et al. 1987.)
+  optional uint32 dilation_h = 18; // The dilation height
+  optional uint32 dilation_w = 19; // The dilation width
+  optional uint32 dilation = 20; // The dilation; defaults to 1
 }
 
 message DataParameter {
@@ -1155,3 +1253,15 @@ message PReLUParameter {
   // Whether or not slope paramters are shared across channels.
   optional bool channel_shared = 2 [default = false];
 }
+
+// The normalized bounding box [0, 1] w.r.t. the input image size.
+message NormalizedBBox {
+  optional float xmin = 1;
+  optional float ymin = 2;
+  optional float xmax = 3;
+  optional float ymax = 4;
+  optional int32 label = 5;
+  optional bool difficult = 6;
+  optional float score = 7;
+  optional float size = 8;
+}
diff --git a/contrib/modules/dnn/src/caffe/caffe_importer.cpp b/contrib/modules/dnn/src/caffe/caffe_importer.cpp
index 59a656f..5f66393 100644
--- a/contrib/modules/dnn/src/caffe/caffe_importer.cpp
+++ b/contrib/modules/dnn/src/caffe/caffe_importer.cpp
@@ -48,6 +48,7 @@ using namespace cv::dnn;
 
 #include <iostream>
 #include <fstream>
+#include <sstream>
 #include <algorithm>
 #include <google/protobuf/message.h>
 #include <google/protobuf/text_format.h>
@@ -63,279 +64,297 @@ using ::google::protobuf::Reflection;
 
 namespace
 {
-    class CaffeImporter : public Importer
-    {
-        caffe::NetParameter net;
-        caffe::NetParameter netBinary;
 
-    public:
+template<typename T>
+static cv::String toString(const T &v)
+{
+    std::ostringstream ss;
+    ss << v;
+    return ss.str();
+}
 
-        CaffeImporter(const char *pototxt, const char *caffeModel)
-        {
-            ReadNetParamsFromTextFileOrDie(pototxt, &net);
+class CaffeImporter : public Importer
+{
+    caffe::NetParameter net;
+    caffe::NetParameter netBinary;
 
-            if (caffeModel && caffeModel[0])
-                ReadNetParamsFromBinaryFileOrDie(caffeModel, &netBinary);
-        }
+public:
 
-        void addParam(const Message &msg, const FieldDescriptor *field, cv::dnn::LayerParams &params)
-        {
-            const Reflection *refl = msg.GetReflection();
-            int type = field->cpp_type();
-            bool isRepeated = field->is_repeated();
-            const std::string &name = field->name();
-
-            #define SET_UP_FILED(getter, arrayConstr, gtype)                                    \
-                if (isRepeated) {                                                               \
-                    const RepeatedField<gtype> &v = refl->GetRepeatedField<gtype>(msg, field);  \
-                    params.set(name, DictValue::arrayConstr(v.begin(), (int)v.size()));                  \
-                }                                                                               \
-                else {                                                                          \
-                    params.set(name, refl->getter(msg, field));                               \
-                }
-
-            switch (type)
-            {
-            case FieldDescriptor::CPPTYPE_INT32:
-                SET_UP_FILED(GetInt32, arrayInt, ::google::protobuf::int32);
-                break;
-            case FieldDescriptor::CPPTYPE_UINT32:
-                SET_UP_FILED(GetUInt32, arrayInt, ::google::protobuf::uint32);
-                break;
-            case FieldDescriptor::CPPTYPE_INT64:
-                SET_UP_FILED(GetInt32, arrayInt, ::google::protobuf::int64);
-                break;
-            case FieldDescriptor::CPPTYPE_UINT64:
-                SET_UP_FILED(GetUInt32, arrayInt, ::google::protobuf::uint64);
-                break;
-            case FieldDescriptor::CPPTYPE_BOOL:
-                SET_UP_FILED(GetBool, arrayInt, bool);
-                break;
-            case FieldDescriptor::CPPTYPE_DOUBLE:
-                SET_UP_FILED(GetDouble, arrayReal, double);
-                break;
-            case FieldDescriptor::CPPTYPE_FLOAT:
-                SET_UP_FILED(GetFloat, arrayReal, float);
-                break;
-            case FieldDescriptor::CPPTYPE_STRING:
-                if (isRepeated) {
-                    const RepeatedPtrField<std::string> &v = refl->GetRepeatedPtrField<std::string>(msg, field);
-                    params.set(name, DictValue::arrayString(v.begin(), (int)v.size()));
-                }
-                else {
-                    params.set(name, refl->GetString(msg, field));
-                }
-                break;
-            case FieldDescriptor::CPPTYPE_ENUM:
-                if (isRepeated) {
-                    int size = refl->FieldSize(msg, field);
-                    std::vector<cv::String> buf(size);
-                    for (int i = 0; i < size; i++)
-                        buf[i] = refl->GetRepeatedEnum(msg, field, i)->name();
-                    params.set(name, DictValue::arrayString(buf.begin(), size));
-                }
-                else {
-                    params.set(name, refl->GetEnum(msg, field)->name());
-                }
-                break;
-            default:
-                CV_Error(Error::StsError, "Unknown type \"" + String(field->type_name()) + "\" in prototxt");
-                break;
+    CaffeImporter(const char *pototxt, const char *caffeModel)
+    {
+        ReadNetParamsFromTextFileOrDie(pototxt, &net);
+
+        if (caffeModel && caffeModel[0])
+            ReadNetParamsFromBinaryFileOrDie(caffeModel, &netBinary);
+    }
+
+    void addParam(const Message &msg, const FieldDescriptor *field, cv::dnn::LayerParams &params)
+    {
+        const Reflection *refl = msg.GetReflection();
+        int type = field->cpp_type();
+        bool isRepeated = field->is_repeated();
+        const std::string &name = field->name();
+
+        #define SET_UP_FILED(getter, arrayConstr, gtype)                                    \
+            if (isRepeated) {                                                               \
+                const RepeatedField<gtype> &v = refl->GetRepeatedField<gtype>(msg, field);  \
+                params.set(name, DictValue::arrayConstr(v.begin(), (int)v.size()));                  \
+            }                                                                               \
+            else {                                                                          \
+                params.set(name, refl->getter(msg, field));                               \
             }
-        }
 
-        inline static bool ends_with_param(const std::string &str)
+        switch (type)
         {
-            static const std::string _param("_param");
-            return (str.size() >= _param.size()) && str.compare(str.size() - _param.size(), _param.size(), _param) == 0;
+        case FieldDescriptor::CPPTYPE_INT32:
+            SET_UP_FILED(GetInt32, arrayInt, ::google::protobuf::int32);
+            break;
+        case FieldDescriptor::CPPTYPE_UINT32:
+            SET_UP_FILED(GetUInt32, arrayInt, ::google::protobuf::uint32);
+            break;
+        case FieldDescriptor::CPPTYPE_INT64:
+            SET_UP_FILED(GetInt32, arrayInt, ::google::protobuf::int64);
+            break;
+        case FieldDescriptor::CPPTYPE_UINT64:
+            SET_UP_FILED(GetUInt32, arrayInt, ::google::protobuf::uint64);
+            break;
+        case FieldDescriptor::CPPTYPE_BOOL:
+            SET_UP_FILED(GetBool, arrayInt, bool);
+            break;
+        case FieldDescriptor::CPPTYPE_DOUBLE:
+            SET_UP_FILED(GetDouble, arrayReal, double);
+            break;
+        case FieldDescriptor::CPPTYPE_FLOAT:
+            SET_UP_FILED(GetFloat, arrayReal, float);
+            break;
+        case FieldDescriptor::CPPTYPE_STRING:
+            if (isRepeated) {
+                const RepeatedPtrField<std::string> &v = refl->GetRepeatedPtrField<std::string>(msg, field);
+                params.set(name, DictValue::arrayString(v.begin(), (int)v.size()));
+            }
+            else {
+                params.set(name, refl->GetString(msg, field));
+            }
+            break;
+        case FieldDescriptor::CPPTYPE_ENUM:
+            if (isRepeated) {
+                int size = refl->FieldSize(msg, field);
+                std::vector<cv::String> buf(size);
+                for (int i = 0; i < size; i++)
+                    buf[i] = refl->GetRepeatedEnum(msg, field, i)->name();
+                params.set(name, DictValue::arrayString(buf.begin(), size));
+            }
+            else {
+                params.set(name, refl->GetEnum(msg, field)->name());
+            }
+            break;
+        default:
+            CV_Error(Error::StsError, "Unknown type \"" + String(field->type_name()) + "\" in prototxt");
+            break;
         }
+    }
 
-        void extractLayerParams(const Message &msg, cv::dnn::LayerParams &params, bool isInternal = false)
-        {
-            const Descriptor *msgDesc = msg.GetDescriptor();
-            const Reflection *msgRefl = msg.GetReflection();
+    inline static bool ends_with_param(const std::string &str)
+    {
+        static const std::string _param("_param");
+        return (str.size() >= _param.size()) && str.compare(str.size() - _param.size(), _param.size(), _param) == 0;
+    }
 
-            for (int fieldId = 0; fieldId < msgDesc->field_count(); fieldId++)
-            {
-                const FieldDescriptor *fd = msgDesc->field(fieldId);
-
-                if (!isInternal && !ends_with_param(fd->name()))
-                    continue;
-
-                bool hasData =  fd->is_required() ||
-                               (fd->is_optional() && msgRefl->HasField(msg, fd)) ||
-                               (fd->is_repeated() && msgRefl->FieldSize(msg, fd) > 0);
-                if (!hasData)
-                    continue;
-
-                if (fd->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE)
-                {
-                    if (fd->is_repeated()) //Extract only first item!
-                        extractLayerParams(msgRefl->GetRepeatedMessage(msg, fd, 0), params, true);
-                    else
-                        extractLayerParams(msgRefl->GetMessage(msg, fd), params, true);
-                }
-                else
-                {
-                    addParam(msg, fd, params);
-                }
-            }
-        }
+    void extractLayerParams(const Message &msg, cv::dnn::LayerParams &params, bool isInternal = false)
+    {
+        const Descriptor *msgDesc = msg.GetDescriptor();
+        const Reflection *msgRefl = msg.GetReflection();
 
-        BlobShape blobShapeFromProto(const caffe::BlobProto &pbBlob)
+        for (int fieldId = 0; fieldId < msgDesc->field_count(); fieldId++)
         {
-            if (pbBlob.has_num() || pbBlob.has_channels() || pbBlob.has_height() || pbBlob.has_width())
-            {
-                return BlobShape(pbBlob.num(), pbBlob.channels(), pbBlob.height(), pbBlob.width());
-            }
-            else if (pbBlob.has_shape())
-            {
-                const caffe::BlobShape &_shape = pbBlob.shape();
-                BlobShape shape(_shape.dim_size());
+            const FieldDescriptor *fd = msgDesc->field(fieldId);
 
-                for (int i = 0; i < _shape.dim_size(); i++)
-                    shape[i] = (int)_shape.dim(i);
+            if (!isInternal && !ends_with_param(fd->name()))
+                continue;
 
-                return shape;
+            bool hasData =  fd->is_required() ||
+                            (fd->is_optional() && msgRefl->HasField(msg, fd)) ||
+                            (fd->is_repeated() && msgRefl->FieldSize(msg, fd) > 0);
+            if (!hasData)
+                continue;
+
+            if (fd->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE)
+            {
+                if (fd->is_repeated()) //Extract only first item!
+                    extractLayerParams(msgRefl->GetRepeatedMessage(msg, fd, 0), params, true);
+                else
+                    extractLayerParams(msgRefl->GetMessage(msg, fd), params, true);
             }
             else
             {
-                CV_Error(Error::StsError, "Unknown shape of input blob");
-                return BlobShape(-1);
+                addParam(msg, fd, params);
             }
         }
+    }
 
-        void blobFromProto(const caffe::BlobProto &pbBlob, cv::dnn::Blob &dstBlob)
+    BlobShape blobShapeFromProto(const caffe::BlobProto &pbBlob)
+    {
+        if (pbBlob.has_num() || pbBlob.has_channels() || pbBlob.has_height() || pbBlob.has_width())
         {
-            BlobShape shape = blobShapeFromProto(pbBlob);
-
-            dstBlob.create(shape, CV_32F);
-            CV_Assert(pbBlob.data_size() == (int)dstBlob.matRefConst().total());
+            return BlobShape(pbBlob.num(), pbBlob.channels(), pbBlob.height(), pbBlob.width());
+        }
+        else if (pbBlob.has_shape())
+        {
+            const caffe::BlobShape &_shape = pbBlob.shape();
+            BlobShape shape = BlobShape::all(_shape.dim_size());
 
-            CV_DbgAssert(pbBlob.GetDescriptor()->FindFieldByLowercaseName("data")->cpp_type() == FieldDescriptor::CPPTYPE_FLOAT);
-            float *dstData = dstBlob.matRef().ptr<float>();
+            for (int i = 0; i < _shape.dim_size(); i++)
+                shape[i] = (int)_shape.dim(i);
 
-            for (int i = 0; i < pbBlob.data_size(); i++)
-                dstData[i] = pbBlob.data(i);
+            return shape;
         }
-
-        void extractBinaryLayerParms(const caffe::LayerParameter& layer, LayerParams& layerParams)
+        else
         {
-            const std::string &name = layer.name();
+            CV_Error(Error::StsError, "Unknown shape of input blob");
+            return BlobShape();
+        }
+    }
 
-            int li;
-            for (li = 0; li != netBinary.layer_size(); li++)
-            {
-                if (netBinary.layer(li).name() == name)
-                    break;
-            }
+    void blobFromProto(const caffe::BlobProto &pbBlob, cv::dnn::Blob &dstBlob)
+    {
+        BlobShape shape = blobShapeFromProto(pbBlob);
 
-            if (li == netBinary.layer_size() || netBinary.layer(li).blobs_size() == 0)
-                return;
+        dstBlob.create(shape, CV_32F);
+        CV_Assert(pbBlob.data_size() == (int)dstBlob.matRefConst().total());
 
-            const caffe::LayerParameter &binLayer = netBinary.layer(li);
-            layerParams.blobs.resize(binLayer.blobs_size());
-            for (int bi = 0; bi < binLayer.blobs_size(); bi++)
-            {
-                blobFromProto(binLayer.blobs(bi), layerParams.blobs[bi]);
-            }
-        }
+        CV_DbgAssert(pbBlob.GetDescriptor()->FindFieldByLowercaseName("data")->cpp_type() == FieldDescriptor::CPPTYPE_FLOAT);
+        float *dstData = dstBlob.matRef().ptr<float>();
 
-        struct BlobNote
-        {
-            BlobNote(const std::string &_name, int _layerId, int _outNum) :
-                name(_name.c_str()), layerId(_layerId), outNum(_outNum) {}
+        for (int i = 0; i < pbBlob.data_size(); i++)
+            dstData[i] = pbBlob.data(i);
+    }
 
-            const char *name;
-            int layerId, outNum;
-        };
+    void extractBinaryLayerParms(const caffe::LayerParameter& layer, LayerParams& layerParams)
+    {
+        const std::string &name = layer.name();
 
-        void populateNet(Net dstNet)
+        int li;
+        for (li = 0; li != netBinary.layer_size(); li++)
         {
-            int layersSize = net.layer_size();
-            std::vector<BlobNote> addedBlobs;
-            addedBlobs.reserve(layersSize + 1);
+            if (netBinary.layer(li).name() == name)
+                break;
+        }
 
-            //setup input layer names
-            {
-                std::vector<String> netInputs(net.input_size());
-                for (int inNum = 0; inNum < net.input_size(); inNum++)
-                {
-                    addedBlobs.push_back(BlobNote(net.input(inNum), 0, inNum));
-                    netInputs[inNum] = net.input(inNum);
-                }
-                dstNet.setNetInputs(netInputs);
-            }
+        if (li == netBinary.layer_size() || netBinary.layer(li).blobs_size() == 0)
+            return;
 
-            for (int li = 0; li < layersSize; li++)
-            {
-                const caffe::LayerParameter &layer = net.layer(li);
-                String name = layer.name();
-                String type = layer.type();
-                LayerParams layerParams;
+        const caffe::LayerParameter &binLayer = netBinary.layer(li);
+        layerParams.blobs.resize(binLayer.blobs_size());
+        for (int bi = 0; bi < binLayer.blobs_size(); bi++)
+        {
+            blobFromProto(binLayer.blobs(bi), layerParams.blobs[bi]);
+        }
+    }
 
-                extractLayerParams(layer, layerParams);
-                extractBinaryLayerParms(layer, layerParams);
+    struct BlobNote
+    {
+        BlobNote(const std::string &_name, int _layerId, int _outNum) :
+            name(_name.c_str()), layerId(_layerId), outNum(_outNum) {}
+
+        const char *name;
+        int layerId, outNum;
+    };
 
-                int id = dstNet.addLayer(name, type, layerParams);
+    std::vector<BlobNote> addedBlobs;
+    std::map<String, int> layerCounter;
 
-                for (int inNum = 0; inNum < layer.bottom_size(); inNum++)
-                    addInput(layer.bottom(inNum), id, inNum, dstNet, addedBlobs);
+    void populateNet(Net dstNet)
+    {
+        int layersSize = net.layer_size();
+        layerCounter.clear();
+        addedBlobs.clear();
+        addedBlobs.reserve(layersSize + 1);
 
-                for (int outNum = 0; outNum < layer.top_size(); outNum++)
-                    addOutput(layer, id, outNum, addedBlobs);
+        //setup input layer names
+        {
+            std::vector<String> netInputs(net.input_size());
+            for (int inNum = 0; inNum < net.input_size(); inNum++)
+            {
+                addedBlobs.push_back(BlobNote(net.input(inNum), 0, inNum));
+                netInputs[inNum] = net.input(inNum);
             }
+            dstNet.setNetInputs(netInputs);
         }
 
-        void addOutput(const caffe::LayerParameter &layer, int layerId, int outNum, std::vector<BlobNote> &addedBlobs)
+        for (int li = 0; li < layersSize; li++)
         {
-            const std::string &name = layer.top(outNum);
+            const caffe::LayerParameter &layer = net.layer(li);
+            String name = layer.name();
+            String type = layer.type();
+            LayerParams layerParams;
 
-            bool haveDups = false;
-            for (int idx = (int)addedBlobs.size() - 1; idx >= 0; idx--)
-            {
-                if (addedBlobs[idx].name == name)
-                {
-                    haveDups = true;
-                    break;
-                }
-            }
+            extractLayerParams(layer, layerParams);
+            extractBinaryLayerParms(layer, layerParams);
 
-            if (haveDups)
-            {
-                bool isInplace = layer.bottom_size() > outNum && layer.bottom(outNum) == name;
-                if (!isInplace)
-                    CV_Error(Error::StsBadArg, "Duplicate blobs produced by multiple sources");
-            }
+            int repetitions = layerCounter[name]++;
+            if (repetitions)
+                name += String("_") + toString(repetitions);
+
+            int id = dstNet.addLayer(name, type, layerParams);
+
+            for (int inNum = 0; inNum < layer.bottom_size(); inNum++)
+                addInput(layer.bottom(inNum), id, inNum, dstNet);
 
-            addedBlobs.push_back(BlobNote(name, layerId, outNum));
+            for (int outNum = 0; outNum < layer.top_size(); outNum++)
+                addOutput(layer, id, outNum);
         }
 
-        void addInput(const std::string &name, int layerId, int inNum, Net &dstNet, std::vector<BlobNote> &addedBlobs)
-        {
-            int idx;
-            for (idx = (int)addedBlobs.size() - 1; idx >= 0; idx--)
-            {
-                if (addedBlobs[idx].name == name)
-                    break;
-            }
+        addedBlobs.clear();
+    }
 
-            if (idx < 0)
+    void addOutput(const caffe::LayerParameter &layer, int layerId, int outNum)
+    {
+        const std::string &name = layer.top(outNum);
+
+        bool haveDups = false;
+        for (int idx = (int)addedBlobs.size() - 1; idx >= 0; idx--)
+        {
+            if (addedBlobs[idx].name == name)
             {
-                CV_Error(Error::StsObjectNotFound, "Can't found output blob \"" + name + "\"");
-                return;
+                haveDups = true;
+                break;
             }
+        }
 
-            dstNet.connect(addedBlobs[idx].layerId, addedBlobs[idx].outNum, layerId, inNum);
+        if (haveDups)
+        {
+            bool isInplace = layer.bottom_size() > outNum && layer.bottom(outNum) == name;
+            if (!isInplace)
+                CV_Error(Error::StsBadArg, "Duplicate blobs produced by multiple sources");
         }
 
-        ~CaffeImporter()
+        addedBlobs.push_back(BlobNote(name, layerId, outNum));
+    }
+
+    void addInput(const std::string &name, int layerId, int inNum, Net &dstNet)
+    {
+        int idx;
+        for (idx = (int)addedBlobs.size() - 1; idx >= 0; idx--)
         {
+            if (addedBlobs[idx].name == name)
+                break;
+        }
 
+        if (idx < 0)
+        {
+            CV_Error(Error::StsObjectNotFound, "Can't find output blob \"" + name + "\"");
+            return;
         }
 
+        dstNet.connect(addedBlobs[idx].layerId, addedBlobs[idx].outNum, layerId, inNum);
+    }
 
-    };
+    ~CaffeImporter()
+    {
+
+    }
+
+};
 
 }
 
@@ -353,3 +372,20 @@ Ptr<Importer> cv::dnn::createCaffeImporter(const String&, const String&)
 }
 
 #endif //HAVE_PROTOBUF
+
+Net cv::dnn::readNetFromCaffe(const String &prototxt, const String &caffeModel /*= String()*/)
+{
+    Ptr<Importer> caffeImporter;
+    try
+    {
+        caffeImporter = createCaffeImporter(prototxt, caffeModel);
+    }
+    catch(...)
+    {
+    }
+
+    Net net;
+    if (caffeImporter)
+        caffeImporter->populateNet(net);
+    return net;
+}
diff --git a/contrib/modules/dnn/src/caffe/compiled/caffe.tar.gz b/contrib/modules/dnn/src/caffe/compiled/caffe.tar.gz
deleted file mode 100644
index c66784d..0000000
Binary files a/contrib/modules/dnn/src/caffe/compiled/caffe.tar.gz and /dev/null differ
diff --git a/contrib/modules/dnn/src/caffe/glog_emulator.hpp b/contrib/modules/dnn/src/caffe/glog_emulator.hpp
index 39d1615..5f674e4 100644
--- a/contrib/modules/dnn/src/caffe/glog_emulator.hpp
+++ b/contrib/modules/dnn/src/caffe/glog_emulator.hpp
@@ -46,52 +46,59 @@
 #include <sstream>
 #include <opencv2/core.hpp>
 
-#define CHECK(cond)     cv::GLogWrapper(__FILE__, CV_Func, __LINE__, "CHECK", #cond, cond)
-#define CHECK_EQ(a, b)  cv::GLogWrapper(__FILE__, CV_Func, __LINE__, "CHECK", #a"="#b, ((a) == (b)))
-#define LOG(TYPE)       cv::GLogWrapper(__FILE__, CV_Func, __LINE__, #TYPE)
+#define CHECK(cond)     for(cv::dnn::GLogWrapper _logger(__FILE__, CV_Func, __LINE__, "CHECK", #cond, cond); _logger.exit(); _logger.check()) _logger.stream()
+#define CHECK_EQ(a, b)  for(cv::dnn::GLogWrapper _logger(__FILE__, CV_Func, __LINE__, "CHECK", #a"="#b, ((a) == (b))); _logger.exit(); _logger.check()) _logger.stream()
+#define LOG(TYPE)       for(cv::dnn::GLogWrapper _logger(__FILE__, CV_Func, __LINE__, #TYPE); _logger.exit(); _logger.check()) _logger.stream()
 
 namespace cv
 {
+namespace dnn
+{
 
 class GLogWrapper
 {
-    std::stringstream stream;
     const char *file, *func, *type, *cond_str;
     int line;
-    bool cond_staus;
+    bool cond_staus, exit_loop;
+    std::stringstream sstream;
 
 public:
 
     GLogWrapper(const char *_file, const char *_func, int _line,
-                const char *_type,
-                const char *_cond_str = NULL, bool _cond_status = true
-               ) :
-               file(_file), func(_func), type(_type), cond_str(_cond_str),
-               line(_line), cond_staus(_cond_status) {}
+          const char *_type,
+          const char *_cond_str = NULL, bool _cond_status = true
+    ) :
+        file(_file), func(_func), type(_type), cond_str(_cond_str),
+        line(_line), cond_staus(_cond_status), exit_loop(true) {}
+
+    std::iostream &stream()
+    {
+        return sstream;
+    }
 
-    template<typename T>
-    GLogWrapper &operator<<(const T &v)
+    bool exit()
     {
-        if (!cond_str || cond_str && !cond_staus)
-            stream << v;
-        return *this;
+        return exit_loop;
     }
 
-    ~GLogWrapper()
+    void check()
     {
+        exit_loop = false;
+
         if (cond_str && !cond_staus)
         {
-            cv::error(cv::Error::StsError, "FAILED: " + String(cond_str) + "." + stream.str(), func, file, line);
+            cv::error(cv::Error::StsError, "FAILED: " + String(cond_str) + ". " + sstream.str(), func, file, line);
         }
         else if (!cond_str && strcmp(type, "CHECK"))
         {
             if (!std::strcmp(type, "INFO"))
-                std::cout << stream.str() << std::endl;
+                std::cout << sstream.str() << std::endl;
             else
-                std::cerr << stream.str() << std::endl;
+                std::cerr << sstream.str() << std::endl;
         }
     }
 };
 
 }
+}
 #endif
diff --git a/contrib/modules/dnn/src/caffe/layer_loaders.cpp b/contrib/modules/dnn/src/caffe/layer_loaders.cpp
new file mode 100644
index 0000000..40a7e56
--- /dev/null
+++ b/contrib/modules/dnn/src/caffe/layer_loaders.cpp
@@ -0,0 +1,304 @@
+#include "../precomp.hpp"
+#include "layer_loaders.hpp"
+#include <opencv2/dnn/shape_utils.hpp>
+#include <climits>
+#include "layers/layers_common.hpp"
+
+namespace cv
+{
+namespace dnn
+{
+
+//Layers
+
+//Convolution and Deconvolution
+static void initConvDeconvLayerFromCaffe(Ptr<BaseConvolutionLayer> l, LayerParams &params)
+{
+    l->setParamsFrom(params);
+    getConvolutionKernelParams(params, l->kernel.height, l->kernel.width, l->pad.height,
+                               l->pad.width, l->stride.height, l->stride.width, l->dilation.height,
+                               l->dilation.width, l->padMode);
+
+    bool bias = params.get<bool>("bias_term", true);
+    int numOutput = params.get<int>("num_output");
+    int group = params.get<int>("group", 1);
+
+    CV_Assert(numOutput % group == 0);
+    CV_Assert((bias && l->blobs.size() == 2) || (!bias && l->blobs.size() == 1));
+}
+
+template<>
+Ptr<Layer> createLayerFromCaffe<ConvolutionLayer>(LayerParams &params)
+{
+    Ptr<BaseConvolutionLayer> l = ConvolutionLayer::create();
+    initConvDeconvLayerFromCaffe(l, params);
+    return Ptr<Layer>(l);
+}
+
+template<>
+Ptr<Layer> createLayerFromCaffe<DeconvolutionLayer>(LayerParams &params)
+{
+    Ptr<BaseConvolutionLayer> l = DeconvolutionLayer::create();
+    initConvDeconvLayerFromCaffe(l, params);
+    return Ptr<Layer>(l);
+}
+
+template<>
+Ptr<Layer> createLayerFromCaffe<PoolingLayer>(LayerParams &params)
+{
+    int type = PoolingLayer::MAX;
+    Size kernel, stride, pad;
+    bool globalPooling;
+    cv::String padMode;
+
+    if (params.has("pool"))
+    {
+        String pool = params.get<String>("pool").toLowerCase();
+        if (pool == "max")
+            type = PoolingLayer::MAX;
+        else if (pool == "ave")
+            type = PoolingLayer::AVE;
+        else if (pool == "stochastic")
+            type = PoolingLayer::STOCHASTIC;
+        else
+            CV_Error(Error::StsBadArg, "Unknown pooling type \"" + pool + "\"");
+    }
+
+    getPoolingKernelParams(params, kernel.height, kernel.width, globalPooling,
+                           pad.height, pad.width, stride.height, stride.width, padMode);
+    //getCaffeConvParams(params, kernel, pad, stride);
+
+    if (!globalPooling)
+        return Ptr<Layer>(PoolingLayer::create(type, kernel, stride, pad, padMode));
+    else
+        return Ptr<Layer>(PoolingLayer::createGlobal(type));
+}
+
+template<>
+Ptr<Layer> createLayerFromCaffe<SoftmaxLayer>(LayerParams &params)
+{
+    int axis = params.get<int>("axis", 1);
+    return Ptr<Layer>(SoftmaxLayer::create(axis));
+}
+
+template<> //InnerProduct specialization
+Ptr<Layer> createLayerFromCaffe<InnerProductLayer>(LayerParams &params)
+{
+    const std::vector<Blob> &blobs = params.blobs;
+    CV_Assert(1 <= blobs.size() && blobs.size() <= 2);
+
+    int numOutputs = params.get<int>("num_output");
+    int innerSize = (int)blobs[0].total() / numOutputs;
+    bool bias = params.get<bool>("bias_term", true);
+    int axis = params.get<int>("axis", 1);
+
+    CV_Assert(blobs[0].dims() >= 2 && (size_t)(innerSize * numOutputs) == blobs[0].total());
+    CV_Assert(!bias || (blobs.size() == 2 && (size_t)numOutputs == blobs[1].total()));
+
+    Ptr<InnerProductLayer> l = InnerProductLayer::create(axis);
+    l->setParamsFrom(params);
+    l->blobs[0].reshape(Shape(numOutputs, innerSize));
+    if (bias)
+        l->blobs[1].reshape(Shape(1, numOutputs));
+
+    return Ptr<Layer>(l);
+}
+
+template<> //LRNLayer specialization
+Ptr<Layer> createLayerFromCaffe<LRNLayer>(LayerParams& params)
+{
+    int type = -1;
+    String nrmType = params.get<String>("norm_region", "ACROSS_CHANNELS");
+    if (nrmType == "ACROSS_CHANNELS")
+        type = LRNLayer::CHANNEL_NRM;
+    else if (nrmType == "WITHIN_CHANNEL")
+        type = LRNLayer::SPATIAL_NRM;
+    else
+        CV_Error(Error::StsBadArg, "Unknown region type \"" + nrmType + "\"");
+
+    int size = params.get<int>("local_size", 5);
+    if (size % 2 != 1 || size <= 0)
+        CV_Error(Error::StsBadArg, "LRN layer supports only positive odd values for local_size");
+
+    double alpha = params.get<double>("alpha", 1);
+    double beta = params.get<double>("beta", 0.75);
+    double bias = params.get<double>("bias", 1);
+    bool normBySize = params.get<bool>("norm_by_size", true);
+
+    return Ptr<Layer>(LRNLayer::create(type, size, alpha, beta, bias, normBySize));
+}
+
+template<>
+Ptr<Layer> createLayerFromCaffe<MVNLayer>(LayerParams &params)
+{
+    return Ptr<Layer>(MVNLayer::create(
+        params.get<bool>("normalize_variance", true),
+        params.get<bool>("across_channels", false),
+        params.get<double>("eps", 1e-9)
+    ));
+}
+
+/* Reshape layers */
+
+template<>
+Ptr<Layer> createLayerFromCaffe<ReshapeLayer>(LayerParams &params)
+{
+    int axis = params.get<int>("axis", 0);
+    int numAxes = params.get<int>("num_axes", -1);
+    bool enableReordering = params.get<bool>("reorder_dims", false);
+    CV_Assert(numAxes >= -1);
+    Range applyingRange = (numAxes == -1) ? Range(axis, INT_MAX) : Range(axis, axis + numAxes);
+
+    Shape newShape;
+    if (params.has("dim"))
+    {
+        const DictValue &paramShape = params.get("dim");
+        newShape = Shape::all(paramShape.size());
+        for (int i = 0; i < paramShape.size(); i++)
+            newShape[i] = paramShape.get<int>(i);
+    }
+    else
+        newShape = Shape::all(0);
+
+    return Ptr<Layer>(ReshapeLayer::create(newShape, applyingRange, enableReordering));
+}
+
+template<>
+Ptr<Layer> createLayerFromCaffe<ConcatLayer>(LayerParams& params)
+{
+    return Ptr<Layer>(ConcatLayer::create(params.get<int>("axis", 1)));
+}
+
+template<>
+Ptr<Layer> createLayerFromCaffe<SplitLayer>(LayerParams &params)
+{
+    int outputsCount;
+
+    //TODO: maybe "top_count" param is useless because it can be determined by output connections number
+    if (params.has("top_count"))
+    {
+        outputsCount = params.get<int>("top_count");
+        CV_Assert(outputsCount >= 0);
+    }
+    else
+    {
+        outputsCount = -1;
+    }
+
+    return Ptr<Layer>(SplitLayer::create(outputsCount));
+}
+
+template<>
+Ptr<Layer> createLayerFromCaffe<SliceLayer>(LayerParams& params)
+{
+    int axis = params.get<int>("axis", 1);
+
+    if (!params.has("slice_point"))
+    {
+        return Ptr<Layer>(SliceLayer::create(axis));
+    }
+    else
+    {
+        const DictValue &indicesValue = params.get("slice_point");
+        std::vector<int> sliceIndices(indicesValue.size());
+        for (int i = 0; i < indicesValue.size(); i++)
+            sliceIndices[i] = indicesValue.get<int>(i);
+
+        return Ptr<Layer>(SliceLayer::create(axis, sliceIndices));
+    }
+}
+
+/* Activation layers */
+
+template <typename ActivationLayer> //Intended for parameters-free activations
+Ptr<Layer> createLayerFromCaffe(LayerParams&)
+{
+    return Ptr<Layer>(ActivationLayer::create());
+}
+
+template<> //ReLU specialization
+Ptr<Layer> createLayerFromCaffe<ReLULayer>(LayerParams& params)
+{
+    float negative_slope = params.get<float>("negative_slope", 0.f);
+    return Ptr<Layer>(ReLULayer::create(negative_slope));
+}
+
+template<> //Power specialization
+Ptr<Layer> createLayerFromCaffe<PowerLayer>(LayerParams& params)
+{
+    float power = params.get<float>("power", 1.0f);
+    float scale = params.get<float>("scale", 1.0f);
+    float shift = params.get<float>("shift", 0.0f);
+    return Ptr<Layer>(PowerLayer::create(power, scale, shift));
+}
+
+template<> //CropLayer specialization
+Ptr<Layer> createLayerFromCaffe<CropLayer>(LayerParams& params)
+{
+    int start_axis = params.get<int>("axis", 2);
+    DictValue *paramOffset = params.ptr("offset");
+
+    std::vector<int> offset;
+    if (paramOffset)
+    {
+        for (int i = 0; i < paramOffset->size(); i++)
+            offset.push_back(paramOffset->get<int>(i));
+    }
+
+    return Ptr<Layer>(CropLayer::create(start_axis, offset));
+}
+
+template<> //Power specialization
+Ptr<Layer> createLayerFromCaffe<EltwiseLayer>(LayerParams& params)
+{
+    EltwiseLayer::EltwiseOp op = EltwiseLayer::SUM;
+    if (params.has("operation"))
+    {
+        String operation = params.get<String>("operation").toLowerCase();
+        if (operation == "prod")
+            op = EltwiseLayer::PROD;
+        else if (operation == "sum")
+            op = EltwiseLayer::SUM;
+        else if (operation == "max")
+            op = EltwiseLayer::MAX;
+        else
+            CV_Error(cv::Error::StsBadArg, "Unknown operaticon type \"" + operation + "\"");
+    }
+
+    std::vector<int> coeffs;
+    if (params.has("coeff"))
+    {
+        DictValue paramCoeff = params.get("coeff");
+        coeffs.resize(paramCoeff.size(), 1);
+        for (int i = 0; i < paramCoeff.size(); i++)
+        {
+            coeffs[i] = paramCoeff.get<int>(i);
+        }
+    }
+    return Ptr<Layer>(EltwiseLayer::create(op, coeffs));
+}
+
+//Explicit instantiation
+template Ptr<Layer> createLayerFromCaffe<ConvolutionLayer>(LayerParams&);
+template Ptr<Layer> createLayerFromCaffe<DeconvolutionLayer>(LayerParams&);
+template Ptr<Layer> createLayerFromCaffe<SoftmaxLayer>(LayerParams&);
+template Ptr<Layer> createLayerFromCaffe<InnerProductLayer>(LayerParams&);
+template Ptr<Layer> createLayerFromCaffe<LRNLayer>(LayerParams&);
+template Ptr<Layer> createLayerFromCaffe<MVNLayer>(LayerParams&);
+
+template Ptr<Layer> createLayerFromCaffe<ConcatLayer>(LayerParams&);
+template Ptr<Layer> createLayerFromCaffe<SliceLayer>(LayerParams&);
+template Ptr<Layer> createLayerFromCaffe<SplitLayer>(LayerParams&);
+
+template Ptr<Layer> createLayerFromCaffe<ReLULayer>(LayerParams&);
+template Ptr<Layer> createLayerFromCaffe<SigmoidLayer>(LayerParams&);
+template Ptr<Layer> createLayerFromCaffe<TanHLayer>(LayerParams&);
+template Ptr<Layer> createLayerFromCaffe<AbsLayer>(LayerParams&);
+template Ptr<Layer> createLayerFromCaffe<BNLLLayer>(LayerParams&);
+template Ptr<Layer> createLayerFromCaffe<PowerLayer>(LayerParams&);
+
+template Ptr<Layer> createLayerFromCaffe<CropLayer>(LayerParams&);
+template Ptr<Layer> createLayerFromCaffe<EltwiseLayer>(LayerParams&);
+
+}
+}
diff --git a/contrib/modules/dnn/src/caffe/layer_loaders.hpp b/contrib/modules/dnn/src/caffe/layer_loaders.hpp
new file mode 100644
index 0000000..617691c
--- /dev/null
+++ b/contrib/modules/dnn/src/caffe/layer_loaders.hpp
@@ -0,0 +1,60 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+//  By downloading, copying, installing or using the software you agree to this license.
+//  If you do not agree to this license, do not download, install,
+//  copy or use the software.
+//
+//
+//                           License Agreement
+//                For Open Source Computer Vision Library
+//
+// Copyright (C) 2013, OpenCV Foundation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+//   * Redistribution's of source code must retain the above copyright notice,
+//     this list of conditions and the following disclaimer.
+//
+//   * Redistribution's in binary form must reproduce the above copyright notice,
+//     this list of conditions and the following disclaimer in the documentation
+//     and/or other materials provided with the distribution.
+//
+//   * The name of the copyright holders may not be used to endorse or promote products
+//     derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#ifndef __OPENCV_DNN_CAFFE_LAYER_LOADERS_HPP__
+#define __OPENCV_DNN_CAFFE_LAYER_LOADERS_HPP__
+
+#include <opencv2/dnn/all_layers.hpp>
+
+namespace cv
+{
+namespace dnn
+{
+
+//Common template for Caffe layer loaders
+template <typename PublicLayer>
+Ptr<Layer> createLayerFromCaffe(LayerParams&);
+
+Ptr<Layer> createFlattenLayerFromCaffe(LayerParams&);
+
+}
+}
+#endif
\ No newline at end of file
diff --git a/contrib/modules/dnn/src/dnn.cpp b/contrib/modules/dnn/src/dnn.cpp
index 7616aa8..5c00927 100644
--- a/contrib/modules/dnn/src/dnn.cpp
+++ b/contrib/modules/dnn/src/dnn.cpp
@@ -44,6 +44,7 @@
 #include <algorithm>
 #include <iostream>
 #include <sstream>
+#include <iterator>
 
 using namespace cv;
 using namespace cv::dnn;
@@ -59,7 +60,7 @@ namespace dnn
 {
 
 template<typename T>
-String toString(const T &v)
+static String toString(const T &v)
 {
     std::ostringstream ss;
     ss << v;
@@ -127,7 +128,7 @@ struct LayerData
 };
 
 //fake layer containing network input blobs
-struct NetInputLayer : public Layer
+struct DataLayer : public Layer
 {
     void allocate(const std::vector<Blob*>&, std::vector<Blob>&) {}
     void forward(std::vector<Blob*>&, std::vector<Blob>&) {}
@@ -152,18 +153,19 @@ struct Net::Impl
     Impl()
     {
         //allocate fake net input layer
-        netInputLayer = Ptr<NetInputLayer>(new NetInputLayer());
+        netInputLayer = Ptr<DataLayer>(new DataLayer());
         LayerData &inpl = layers.insert( make_pair(0, LayerData()) ).first->second;
         inpl.id = 0;
         inpl.name = "_input";
         inpl.type = "__NetInputLayer__";
         inpl.layerInstance = netInputLayer;
+        layerNameToId.insert(std::make_pair(inpl.name, inpl.id));
 
         lastLayerId = 1;
         netWasAllocated = false;
     }
 
-    Ptr<NetInputLayer> netInputLayer;
+    Ptr<DataLayer> netInputLayer;
     std::vector<int> netOutputs;
 
     typedef std::map<int, LayerData> MapIdToLayerData;
@@ -328,11 +330,16 @@ struct Net::Impl
                 netOutputs.push_back(lid);
         }
 
+        #ifndef NDEBUG
         std::cout << "\nNet Outputs(" << netOutputs.size() << "):\n";
         for (size_t i = 0; i < netOutputs.size(); i++)
-            std::cout << layers[netOutputs[i]].name << std::endl;
+            std::cout << layers[netOutputs[i]].name << "\n";
+        #endif
     }
 
+    #define CV_RETHROW_ERROR(err, newmsg)\
+        cv::error(err.code, newmsg, err.func.c_str(), err.file.c_str(), err.line)
+
     void allocateLayer(int lid)
     {
         LayerData &ld = layers[lid];
@@ -361,7 +368,15 @@ struct Net::Impl
 
         //allocate layer
         ld.outputBlobs.resize(std::max((size_t)1, ld.requiredOutputs.size())); //layer produce at least one output blob
-        ld.getLayerInstance()->allocate(ld.inputBlobs, ld.outputBlobs);
+        try
+        {
+            Ptr<Layer> layerPtr = ld.getLayerInstance();
+            layerPtr->allocate(ld.inputBlobs, ld.outputBlobs);
+        }
+        catch (const cv::Exception &err)
+        {
+            CV_RETHROW_ERROR(err, format("The following error occured while making allocate() for layer \"%s\": %s", ld.name.c_str(), err.err.c_str()));
+        }
 
         ld.flag = 1;
     }
@@ -399,7 +414,14 @@ struct Net::Impl
         }
 
         //forward itself
-        ld.layerInstance->forward(ld.inputBlobs, ld.outputBlobs);
+        try
+        {
+            ld.layerInstance->forward(ld.inputBlobs, ld.outputBlobs);
+        }
+        catch (const cv::Exception &err)
+        {
+            CV_RETHROW_ERROR(err, format("The following error occured while making forward() for layer \"%s\": %s", ld.name.c_str(), err.err.c_str()));
+        }
 
         ld.flag = 1;
     }
@@ -417,12 +439,10 @@ struct Net::Impl
 
 Net::Net() : impl(new Net::Impl)
 {
-
 }
 
 Net::~Net()
 {
-
 }
 
 int Net::addLayer(const String &name, const String &type, LayerParams &params)
@@ -469,16 +489,19 @@ void Net::connect(String _outPin, String _inPin)
     impl->connect(outPin.lid, outPin.oid, inpPin.lid, inpPin.oid);
 }
 
-void Net::forward()
+void Net::allocate()
 {
     impl->setUpNet();
-    impl->forwardAll();
 }
 
 void Net::forward(LayerId toLayer)
 {
     impl->setUpNet();
-    impl->forwardLayer(impl->getLayerData(toLayer));
+
+    if (toLayer.isString() && toLayer.get<String>().empty())
+        impl->forwardAll();
+    else
+        impl->forwardLayer(impl->getLayerData(toLayer));
 }
 
 void Net::setNetInputs(const std::vector<String> &inputBlobNames)
@@ -521,6 +544,16 @@ Blob Net::getParam(LayerId layer, int numParam)
     return layerBlobs[numParam];
 }
 
+void Net::setParam(LayerId layer, int numParam, const Blob &blob)
+{
+    LayerData &ld = impl->getLayerData(layer);
+
+    std::vector<Blob> &layerBlobs = ld.layerInstance->blobs;
+    CV_Assert(numParam < (int)layerBlobs.size());
+    //we don't make strong checks, use this function carefully
+    layerBlobs[numParam] = blob;
+}
+
 int Net::getLayerId(const String &layer)
 {
     return impl->getLayerId(layer);
@@ -531,6 +564,34 @@ void Net::deleteLayer(LayerId)
     CV_Error(Error::StsNotImplemented, "");
 }
 
+Ptr<Layer> Net::getLayer(LayerId layerId)
+{
+    LayerData &ld = impl->getLayerData(layerId);
+    if (!ld.layerInstance)
+        CV_Error(Error::StsNullPtr, format("Requseted layer \"%s\" was not initialized", ld.name.c_str()));
+    return ld.layerInstance;
+}
+
+std::vector<String> Net::getLayerNames() const
+{
+    std::vector<String> res;
+    res.reserve(impl->layers.size());
+
+    Impl::MapIdToLayerData::iterator it;
+    for (it = impl->layers.begin(); it != impl->layers.end(); it++)
+    {
+        if (it->second.id) //skip Data layer
+            res.push_back(it->second.name);
+    }
+
+    return res;
+}
+
+bool Net::empty() const
+{
+    return impl->layers.size() <= 1; //first layer is default Data layer
+}
+
 //////////////////////////////////////////////////////////////////////////
 
 Importer::~Importer() {}
@@ -543,6 +604,13 @@ Layer::Layer(const LayerParams &params)
 
 }
 
+void Layer::setParamsFrom(const LayerParams &params)
+{
+    blobs = params.blobs;
+    name = params.name;
+    type = params.type;
+}
+
 int Layer::inputNameToIndex(String)
 {
     return -1;
@@ -553,6 +621,43 @@ int Layer::outputNameToIndex(String)
     return -1;
 }
 
+template <typename T>
+static void vecToPVec(const std::vector<T> &v, std::vector<T*> &pv)
+{
+    pv.resize(v.size());
+    for (size_t i = 0; i < v.size(); i++)
+        pv[i] = const_cast<T*>(&v[i]);
+}
+
+void Layer::allocate(const std::vector<Blob> &inputs, std::vector<Blob> &outputs)
+{
+    std::vector<Blob*> inputsp;
+    vecToPVec(inputs, inputsp);
+    this->allocate(inputsp, outputs);
+}
+
+std::vector<Blob> Layer::allocate(const std::vector<Blob> &inputs)
+{
+    std::vector<Blob> outputs;
+    this->allocate(inputs, outputs);
+    return outputs;
+}
+
+void Layer::forward(const std::vector<Blob> &inputs, std::vector<Blob> &outputs)
+{
+    std::vector<Blob*> inputsp;
+    vecToPVec(inputs, inputsp);
+    this->forward(inputsp, outputs);
+}
+
+void Layer::run(const std::vector<Blob> &inputs, std::vector<Blob> &outputs)
+{
+    std::vector<Blob*> inputsp;
+    vecToPVec(inputs, inputsp);
+    this->allocate(inputsp, outputs);
+    this->forward(inputsp, outputs);
+}
+
 Layer::~Layer() {}
 
 //////////////////////////////////////////////////////////////////////////
diff --git a/contrib/modules/dnn/src/init.cpp b/contrib/modules/dnn/src/init.cpp
index 3d951e1..5b675bd 100644
--- a/contrib/modules/dnn/src/init.cpp
+++ b/contrib/modules/dnn/src/init.cpp
@@ -40,19 +40,17 @@
 //M*/
 
 #include "precomp.hpp"
-
-#include "layers/concat_layer.hpp"
-#include "layers/convolution_layer.hpp"
+#include "caffe/layer_loaders.hpp"
 #include "layers/blank_layer.hpp"
-#include "layers/elementwise_layers.hpp"
-#include "layers/fully_connected_layer.hpp"
-#include "layers/lrn_layer.hpp"
-#include "layers/mvn_layer.hpp"
-#include "layers/pooling_layer.hpp"
-#include "layers/reshape_layer.hpp"
-#include "layers/slice_layer.hpp"
-#include "layers/softmax_layer.hpp"
-#include "layers/split_layer.hpp"
+
+#include "layers/crop_layer.hpp"
+#include "layers/eltwise_layer.hpp"
+#include "layers/flatten_layer.hpp"
+#include "layers/permute_layer.hpp"
+#include "layers/prior_box_layer.hpp"
+#include "layers/detection_output_layer.hpp"
+#include "layers/normalize_bbox_layer.hpp"
+#include "layers/shift_layer.hpp"
 
 namespace cv
 {
@@ -76,27 +74,36 @@ void initModule()
     if (init.status)
         return;
 
-    REG_RUNTIME_LAYER_CLASS(Slice, SliceLayer)
-    REG_RUNTIME_LAYER_CLASS(Softmax, SoftMaxLayer)
-    REG_RUNTIME_LAYER_CLASS(Split, SplitLayer)
-    REG_RUNTIME_LAYER_CLASS(Reshape, ReshapeLayer)
-    REG_STATIC_LAYER_FUNC(Flatten, createFlattenLayer)
-    REG_RUNTIME_LAYER_CLASS(Pooling, PoolingLayer)
-    REG_RUNTIME_LAYER_CLASS(MVN, MVNLayer)
-    REG_RUNTIME_LAYER_CLASS(LRN, LRNLayer)
-    REG_RUNTIME_LAYER_CLASS(InnerProduct, FullyConnectedLayer)
+    REG_RUNTIME_LAYER_FUNC(Slice,           createLayerFromCaffe<SliceLayer>);
+    REG_RUNTIME_LAYER_FUNC(Split,           createLayerFromCaffe<SplitLayer>);
+    REG_RUNTIME_LAYER_FUNC(Concat,          createLayerFromCaffe<ConcatLayer>);
+    REG_RUNTIME_LAYER_FUNC(Reshape,         createLayerFromCaffe<ReshapeLayer>);
+    REG_RUNTIME_LAYER_CLASS(Flatten,        FlattenLayer);
+
+    REG_RUNTIME_LAYER_FUNC(Convolution,     createLayerFromCaffe<ConvolutionLayer>);
+    REG_RUNTIME_LAYER_FUNC(Deconvolution,   createLayerFromCaffe<DeconvolutionLayer>);
+    REG_RUNTIME_LAYER_FUNC(Pooling,         createLayerFromCaffe<PoolingLayer>);
+    REG_RUNTIME_LAYER_FUNC(LRN,             createLayerFromCaffe<LRNLayer>);
+    REG_RUNTIME_LAYER_FUNC(InnerProduct,    createLayerFromCaffe<InnerProductLayer>);
+    REG_RUNTIME_LAYER_FUNC(Softmax,         createLayerFromCaffe<SoftmaxLayer>);
+    REG_RUNTIME_LAYER_FUNC(MVN,             createLayerFromCaffe<MVNLayer>);
 
-    REG_RUNTIME_LAYER_CLASS(ReLU, ElementWiseLayer<ReLUFunctor>)
-    REG_RUNTIME_LAYER_CLASS(TanH, ElementWiseLayer<TanHFunctor>)
-    REG_RUNTIME_LAYER_CLASS(BNLL, ElementWiseLayer<BNLLFunctor>)
-    REG_RUNTIME_LAYER_CLASS(Power, ElementWiseLayer<PowerFunctor>)
-    REG_RUNTIME_LAYER_CLASS(AbsVal, ElementWiseLayer<AbsValFunctor>)
-    REG_RUNTIME_LAYER_CLASS(Sigmoid, ElementWiseLayer<SigmoidFunctor>)
-    REG_RUNTIME_LAYER_CLASS(Dropout, BlankLayer)
+    REG_RUNTIME_LAYER_FUNC(ReLU,            createLayerFromCaffe<ReLULayer>);
+    REG_RUNTIME_LAYER_FUNC(Sigmoid,         createLayerFromCaffe<SigmoidLayer>);
+    REG_RUNTIME_LAYER_FUNC(TanH,            createLayerFromCaffe<TanHLayer>);
+    REG_RUNTIME_LAYER_FUNC(BNLL,            createLayerFromCaffe<BNLLLayer>);
+    REG_RUNTIME_LAYER_FUNC(AbsVal,          createLayerFromCaffe<AbsLayer>);
+    REG_RUNTIME_LAYER_FUNC(Power,           createLayerFromCaffe<PowerLayer>);
+    REG_RUNTIME_LAYER_CLASS(Dropout,        BlankLayer);
+    REG_RUNTIME_LAYER_CLASS(Identity,       BlankLayer);
 
-    REG_RUNTIME_LAYER_CLASS(Convolution, ConvolutionLayer)
-    REG_RUNTIME_LAYER_CLASS(Deconvolution, DeConvolutionLayer)
-    REG_RUNTIME_LAYER_CLASS(Concat, ConcatLayer)
+    REG_RUNTIME_LAYER_FUNC(Crop,            createLayerFromCaffe<CropLayer>);
+    REG_RUNTIME_LAYER_FUNC(Eltwise,         createLayerFromCaffe<EltwiseLayer>);
+    REG_RUNTIME_LAYER_CLASS(Permute,        PermuteLayer);
+    REG_RUNTIME_LAYER_CLASS(PriorBox,       PriorBoxLayer);
+    REG_RUNTIME_LAYER_CLASS(DetectionOutput, DetectionOutputLayer);
+    REG_RUNTIME_LAYER_CLASS(NormalizeBBox,  NormalizeBBoxLayer);
+    REG_RUNTIME_LAYER_CLASS(Shift,          ShiftLayer);
 
     init.status = true;
 }
diff --git a/contrib/modules/dnn/src/layers/concat_layer.cpp b/contrib/modules/dnn/src/layers/concat_layer.cpp
index 24ef4fd..61341fe 100644
--- a/contrib/modules/dnn/src/layers/concat_layer.cpp
+++ b/contrib/modules/dnn/src/layers/concat_layer.cpp
@@ -42,60 +42,80 @@
 #include "../precomp.hpp"
 #include "layers_common.hpp"
 #include "concat_layer.hpp"
+#include <opencv2/core/ocl.hpp>
 
 namespace cv
 {
 namespace dnn
 {
-    ConcatLayer::ConcatLayer(LayerParams &params) : Layer(params)
-    {
-        axis = params.get<int>("axis", 1);
-        CV_Assert(axis >= 0);
-    }
 
-    void ConcatLayer::allocate(const std::vector<Blob *> &inputs, std::vector<Blob> &outputs)
-    {
-        CV_Assert(inputs.size() > 0);
+ConcatLayerImpl::ConcatLayerImpl(int axis_ /*= 1*/)
+{
+    axis = axis_;
+}
 
-        int refType = inputs[0]->type();
-        BlobShape refShape = inputs[0]->shape();
-        CV_Assert(axis < refShape.dims());
+void ConcatLayerImpl::allocate(const std::vector<Blob *> &inputs, std::vector<Blob> &outputs)
+{
+    CV_Assert(inputs.size() > 0);
 
-        int axisSum = 0;
-        for (size_t i = 0; i < inputs.size(); i++)
-        {
-            BlobShape curShape = inputs[i]->shape();
+    BlobShape refShape = inputs[0]->shape();
+    axisIdx = inputs[0]->canonicalAxis(axis);
 
-            CV_Assert(curShape.dims() == refShape.dims() && inputs[i]->type() == refType);
-            for (int axisId = 0; axisId < refShape.dims(); axisId++)
-            {
-                if (axisId != axis && refShape[axisId] != curShape[axisId])
-                    CV_Error(Error::StsBadSize, "Inconsitent shape for ConcatLayer");
-            }
+    int axisSum = 0;
+    useOpenCL = false;
+    for (size_t i = 0; i < inputs.size(); i++)
+    {
+        BlobShape curShape = inputs[i]->shape();
 
-            axisSum += curShape[axis];
+        CV_Assert(curShape.dims() == refShape.dims() && inputs[i]->type() == inputs[0]->type());
+        for (int curAxis = 0; curAxis < refShape.dims(); curAxis++)
+        {
+            if (curAxis != axisIdx && refShape[curAxis] != curShape[curAxis])
+                CV_Error(Error::StsBadSize, "Inconsitent shape for ConcatLayer");
         }
 
-        refShape[axis] = axisSum;
-        outputs.resize(1);
-        outputs[0].create(refShape);
+        axisSum += curShape[axisIdx];
+        useOpenCL |= inputs[i]->getState() == Blob::HEAD_AT_MAT;
     }
 
-    void ConcatLayer::forward(std::vector<Blob *> &inputs, std::vector<Blob> &outputs)
-    {
-        const Mat& outMat = outputs[0].matRef();
-        std::vector<Range> ranges(outputs[0].dims(), Range::all());
-        int sizeStart = 0;
-        for (size_t i = 0; i < inputs.size(); i++)
-        {
-            int sizeEnd = sizeStart + inputs[i]->size(axis);
-            ranges[axis] = Range(sizeStart, sizeEnd);
+    refShape[axisIdx] = axisSum;
+    useOpenCL &= ocl::useOpenCL();
+    int allocFlags = (useOpenCL) ? Blob::ALLOC_UMAT : Blob::ALLOC_MAT;
 
-            Mat outSubMat = outMat(&ranges[0]);
-            inputs[i]->matRef().copyTo(outSubMat);
+    outputs.resize(1);
+    outputs[0].create(refShape, inputs[0]->type(), allocFlags);
+}
 
-            sizeStart = sizeEnd;
-        }
+
+void ConcatLayerImpl::forward(std::vector<Blob *> &inputs, std::vector<Blob> &outputs)
+{
+    #ifdef HAVE_OPENCL
+    if (useOpenCL)
+        forward_<UMat>(inputs, outputs);
+    else
+    #endif
+        forward_<Mat>(inputs, outputs);
+}
+
+template<typename XMat>
+void ConcatLayerImpl::forward_(std::vector<Blob*> &inputs, std::vector<Blob> &outputs)
+{
+    XMat& outMat = outputs[0].getRef<XMat>();
+    std::vector<Range> ranges(outputs[0].dims(), Range::all());
+
+    ranges[axisIdx].start = 0;
+    for (size_t i = 0; i < inputs.size(); i++)
+    {
+        ranges[axisIdx].end = ranges[axisIdx].start + inputs[i]->size(axisIdx);
+        inputs[i]->getRefConst<XMat>().copyTo(outMat(&ranges[0]));
+        ranges[axisIdx].start = ranges[axisIdx].end;
     }
 }
+
+Ptr<ConcatLayer> ConcatLayer::create(int axis)
+{
+    return Ptr<ConcatLayer>(new ConcatLayerImpl(axis));
+}
+
+}
 }
diff --git a/contrib/modules/dnn/src/layers/concat_layer.hpp b/contrib/modules/dnn/src/layers/concat_layer.hpp
index fbc491c..86f2083 100644
--- a/contrib/modules/dnn/src/layers/concat_layer.hpp
+++ b/contrib/modules/dnn/src/layers/concat_layer.hpp
@@ -42,20 +42,29 @@
 #ifndef __OPENCV_DNN_LAYERS_CONCAT_LAYER_HPP__
 #define __OPENCV_DNN_LAYERS_CONCAT_LAYER_HPP__
 #include "../precomp.hpp"
+#include <opencv2/dnn/all_layers.hpp>
 
 namespace cv
 {
 namespace dnn
 {
-    class ConcatLayer : public Layer
-    {
-        int axis;
-
-    public:
-        ConcatLayer(LayerParams& params);
-        void allocate(const std::vector<Blob*> &inputs, std::vector<Blob> &outputs);
-        void forward(std::vector<Blob*> &inputs, std::vector<Blob> &outputs);
-    };
+
+class ConcatLayerImpl : public ConcatLayer
+{
+    bool useOpenCL;
+    int axisIdx;
+
+    template<typename XMat>
+    void forward_(std::vector<Blob*> &inputs, std::vector<Blob> &outputs);
+
+public:
+    ConcatLayerImpl(int axis_ = 1);
+
+    void allocate(const std::vector<Blob*> &inputs, std::vector<Blob> &outputs);
+
+    void forward(std::vector<Blob*> &inputs, std::vector<Blob> &outputs);
+};
+
 }
 }
 #endif
diff --git a/contrib/modules/dnn/src/layers/convolution_layer.cpp b/contrib/modules/dnn/src/layers/convolution_layer.cpp
index 13bc191..d10df01 100644
--- a/contrib/modules/dnn/src/layers/convolution_layer.cpp
+++ b/contrib/modules/dnn/src/layers/convolution_layer.cpp
@@ -43,209 +43,310 @@
 #include <opencv2/core/ocl.hpp>
 #include "layers_common.hpp"
 #include "convolution_layer.hpp"
-#include "im2col.hpp"
+#include "op_im2col.hpp"
+#include "op_blas.hpp"
+#include <opencv2/dnn/shape_utils.hpp>
 #include <iostream>
 
 namespace cv
 {
 namespace dnn
 {
-    ConvolutionLayer::ConvolutionLayer(LayerParams &params) : Layer(params)
-    {
-        getKernelParams(params, kerH, kerW, padH, padW, strideH, strideW);
-
-        numOutput = params.get<int>("num_output");
-        bias = params.get<bool>("bias_term", true);
-        group = params.get<int>("group", 1);
-        CV_Assert(numOutput % group == 0);
-
-        CV_Assert(!bias || blobs.size() == 2);
-        CV_Assert( bias || blobs.size() == 1);
 
-        const Blob &wgtBlob = blobs[0];
-        CV_Assert(wgtBlob.dims() == 4 && wgtBlob.cols() == kerW && wgtBlob.rows() == kerH);
+ConvolutionLayerImpl::ConvolutionLayerImpl()
+{
+    tryUseOpenCL = false; //true;
+    numOutput = -1;
+    group = -1;
 
-        if (bias)
+    #if HAVE_CBLAS
+        if (getBlasThreads() != cv::getThreadNum())
         {
-            Blob &biasBlob = blobs[1];
-            CV_Assert(biasBlob.total() == (size_t)numOutput);
+            setBlasThreads(cv::getThreadNum());
         }
+    #endif
+}
 
-        //TBD
-        useOpenCL = params.has("use_opencl");
-    }
+void ConvolutionLayerImpl::init()
+{
+    CV_Assert(1 <= blobs.size() && blobs.size() <= 2);
 
-    void ConvolutionLayer::allocate(const std::vector<Blob*> &inputs, std::vector<Blob> &outputs)
-    {
-        CV_Assert(inputs.size() > 0);
+    bias = (blobs.size() >= 2);
+    numOutput = blobs[0].num();
 
-        const Blob &inpBlob = *inputs[0];
-        CV_Assert(inpBlob.dims() == 4 && inpBlob.type() == CV_32F);
-        computeInpOutShape(inpBlob);
+    CV_Assert(blobs[0].dims() == 4 && blobs[0].cols() == kernel.width && blobs[0].rows() == kernel.height);
+    CV_Assert(!bias || blobs[1].total() == (size_t)blobs[0].num());
 
-        CV_Assert(inpCn % group == 0 && outCn % group == 0);
-        CV_Assert(blobs[0].num() == outCn && blobs[0].channels() == inpCn / group);
+    //TODO: dilation in OCL mode
+    useOpenCL = ocl::useOpenCL() && tryUseOpenCL && dilation == Size(1, 1);
+}
 
-        outGroupCn = outCn / group;
-        inpGroupCn = inpCn / group;
-        ksize = inpGroupCn * kerH * kerW;
+void ConvolutionLayerImpl::allocate(const std::vector<Blob*> &inputs, std::vector<Blob> &outputs)
+{
+    init();
 
-        outputs.resize(inputs.size());
-        for (size_t i = 0; i < inputs.size(); i++)
-        {
-            CV_Assert(inputs[i]->type() == inpBlob.type());
-            CV_Assert(inputs[i]->dims() == 4 && inputs[i]->channels() == inpBlob.channels());
-            CV_Assert(inputs[i]->rows() == inpBlob.rows() && inputs[i]->cols() == inpBlob.cols());
+    CV_Assert(inputs.size() > 0);
+    const Blob &input = *inputs[0];
+    CV_Assert(input.dims() == 4 && (input.type() == CV_32F || input.type() == CV_64F));
+    computeInpOutShape(input);
 
-            outputs[i].create(BlobShape(inputs[i]->num(), topCn, topH, topW));
-        }
+    group = inpCn / blobs[0].channels();
+    CV_Assert(inpCn % group == 0 && outCn % group == 0);
+    CV_Assert(blobs[0].num() == outCn && blobs[0].channels() == inpCn / group);
 
-        if (!is1x1())
-            colMat.create(ksize, outH * outW, inpBlob.type());
+    outGroupCn = outCn / group;
+    inpGroupCn = inpCn / group;
+    ksize = inpGroupCn * kernel.height * kernel.width;
 
-        if (bias)
-            biasOnesMat = Mat::ones(1, topH * topW, inpBlob.type());
+    for (size_t i = 0; i < inputs.size(); i++)
+    {
+        CV_Assert(inputs[i]->type() == input.type());
+        CV_Assert(inputs[i]->dims() == 4 && inputs[i]->channels() == input.channels());
+        CV_Assert(inputs[i]->rows() == input.rows() && inputs[i]->cols() == input.cols());
     }
 
-    inline bool ConvolutionLayer::is1x1() const
+    int allocFlags = useOpenCL ? Blob::ALLOC_UMAT : Blob::ALLOC_MAT;
+
+    if (!is1x1())
     {
-        return (kerH == 1 && kerW == 1);
+        colBlob.create(Shape(ksize, outH * outW), input.type(), allocFlags);
     }
 
-    void ConvolutionLayer::forward(std::vector<Blob*> &inputs, std::vector<Blob> &outputs)
+    if (bias)
     {
-        Blob &wgtBlob = blobs[0];
+        biasOnesBlob.create(Shape(1, topH * topW), input.type(), allocFlags);
+        biasOnesBlob.setTo(1);
+    }
 
-        for (size_t ii = 0; ii < outputs.size(); ii++)
-        {
-            Blob &inpBlob = *inputs[ii];
-            Blob &outBlob = outputs[ii];
+    outputs.resize(inputs.size());
+    for (size_t i = 0; i < inputs.size(); i++)
+    {
+        outputs[i].create(Shape(inputs[i]->num(), topCn, topH, topW), input.type(), allocFlags);
+    }
+}
+
+bool ConvolutionLayerImpl::is1x1() const
+{
+    return (kernel.height == 1 && kernel.width == 1) &&
+           (stride.height == 1 && stride.width == 1) &&
+           (dilation.height == 1 && dilation.width == 1);
+}
 
-            for (int n = 0; n < inpBlob.num(); n++)
+template<typename XMat>
+void ConvolutionLayerImpl::forward_(std::vector<Blob*> &inputs, std::vector<Blob> &outputs)
+{
+    XMat weightsMat = reshaped(blobs[0].getRefConst<XMat>(), Shape(outCn, ksize));
+    XMat biasesMat  = (bias) ? reshaped(blobs[1].getRefConst<XMat>(), Shape(outCn, 1)) : XMat();
+
+    for (size_t ii = 0; ii < outputs.size(); ii++)
+    {
+        int numImg = inputs[ii]->size(0);
+        XMat inpMat = inputs[ii]->getRefConst<XMat>();
+        XMat outMat = reshaped(outputs[ii].getRef<XMat>(), Shape(numImg*group*outGroupCn, outH*outW));
+
+        for (int n = 0; n < numImg; n++)
+        {
+            for (int g = 0; g < group; g++)
             {
-                for (int g = 0; g < group; g++)
-                {
-                    im2col(inpBlob, n, g);
+                XMat colMat, curInp = slice(inpMat, n, _Range(g * inpGroupCn, inpGroupCn));
+                im2col(curInp, colMat);
 
-                    Mat kerMat(outGroupCn, ksize, wgtBlob.type(), wgtBlob.ptr(g*outGroupCn));
-                    Mat dstMat(outGroupCn, outH*outW, outBlob.type(), outBlob.ptr(n, g*outGroupCn));
+                _Range kerRange(g * outGroupCn, outGroupCn);
+                XMat kerMat = weightsMat.rowRange(kerRange);
 
-                    cv::gemm(kerMat, colMat, 1, noArray(), 0, dstMat);
+                _Range outRange((g + n * group) * outGroupCn, outGroupCn);
+                XMat dstMat = outMat.rowRange(outRange);
 
-                    if (bias)
-                    {
-                        float *biasPtr = blobs[1].ptrf() + g*outGroupCn;
-                        Mat biasMat(outGroupCn, 1, CV_32F, biasPtr);
-                        cv::gemm(biasMat, biasOnesMat, 1, dstMat, 1, dstMat);
-                    }
+                dnn::gemm(kerMat, colMat, 1, dstMat, 0);
+
+                if (bias)
+                {
+                    dnn::gemm(biasesMat.rowRange(kerRange), biasOnesBlob.getRefConst<XMat>(), 1, dstMat, 1);
                 }
             }
         }
     }
+}
 
-    void ConvolutionLayer::im2col(Blob &inpBlob, int imNum, int cnGroup)
-    {
-        uchar *srcPtr = inpBlob.ptr(imNum, cnGroup*inpGroupCn);
-
-        if (is1x1())
-        {
-            colMat = Mat(ksize, inpBlob.rows()*inpBlob.cols(), inpBlob.type(), srcPtr);
-            return;
-        }
+void ConvolutionLayerImpl::forward(std::vector<Blob*> &inputs, std::vector<Blob> &outputs)
+{
+    if (!useOpenCL)
+        forward_<Mat>(inputs, outputs);
+    else
+        forward_<UMat>(inputs, outputs);
+}
 
+void ConvolutionLayerImpl::im2col(const UMat &srcImg, UMat &dstCol)
+{
+    if (is1x1())
+    {
+        dstCol = reshaped(srcImg, Shape(ksize, outH*outW));
+        return;
+    }
 #ifdef HAVE_OPENCL
-        if (useOpenCL && ocl::useOpenCL() && inpBlob.type() == CV_32F && !is1x1())
-        {
-            std::vector<Range> ranges(4, Range::all());
-            ranges[0] = Range(imNum, imNum+1);
-            ranges[1] = Range(cnGroup*inpGroupCn, (cnGroup + 1)*inpGroupCn);
-
-            UMat src = inpBlob.matRef()(&ranges[0]).getUMat(ACCESS_READ);
-            UMat dst(colMat.size(), colMat.type());
-            im2col_ocl(src, inpGroupCn, inpH, inpW, kerH, kerW, padH, padW, strideH, strideW, dst);
-            dst.copyTo(colMat);
-            return;
-        }
-#endif // HAVE_OPENCL
+    CV_Assert(im2col_ocl(srcImg, inpGroupCn, inpH, inpW, kernel.height, kernel.width, pad.height, pad.width, stride.height, stride.width, dilation.height, dilation.width, this->colBlob.umatRef()));
+    dstCol = this->colBlob.umatRefConst();
+#else
+    CV_Error(Error::StsInternal, "");
+    dstCol = srcImg; //supress warning
+#endif
+}
 
-        if (inpBlob.type() == CV_32F)
-            im2col_cpu((float *)srcPtr, inpGroupCn, inpH, inpW, kerH, kerW, padH, padW, strideH, strideW, (float *)colMat.ptr());
-        if (inpBlob.type() == CV_64F)
-            im2col_cpu((double*)srcPtr, inpGroupCn, inpH, inpW, kerH, kerW, padH, padW, strideH, strideW, (double*)colMat.ptr());
+void ConvolutionLayerImpl::im2col(const Mat &srcImg, Mat &dstCol)
+{
+    if (is1x1())
+    {
+        dstCol = reshaped(srcImg, Shape(ksize, outH*outW));
+        return;
     }
 
-    void ConvolutionLayer::computeInpOutShape(const Blob &inpBlob)
-    {
-        inpH = inpBlob.rows();
-        inpW = inpBlob.cols();
-        inpCn = inpBlob.channels();
+    Mat &colMat = colBlob.matRef();
+    if (srcImg.type() == CV_32F)
+        im2col_CpuPBody<float>::run(srcImg.ptr<float>(), inpGroupCn, inpH, inpW, kernel.height,
+                                    kernel.width, pad.height, pad.width, stride.height, stride.width,
+                                    dilation.height, dilation.width, outH, outW, colMat.ptr<float>());
+    if (srcImg.type() == CV_64F)
+        im2col_CpuPBody<double>::run(srcImg.ptr<double>(), inpGroupCn, inpH, inpW, kernel.height,
+                                     kernel.width, pad.height, pad.width, stride.height, stride.width,
+                                     dilation.height, dilation.width, outH, outW, colMat.ptr<double>());
+
+    dstCol = colMat;
+}
 
-        outH = (inpH + 2 * padH - kerH) / strideH + 1;
-        outW = (inpW + 2 * padW - kerW) / strideW + 1;
-        outCn = numOutput;
+void ConvolutionLayerImpl::computeInpOutShape(const Blob &input)
+{
+    inpH = input.rows();
+    inpW = input.cols();
+    inpCn = input.channels();
+    outCn = numOutput;
 
-        topH = outH; topW = outW; topCn = outCn;
+    if (padMode.empty())
+    {
+        outH = (inpH + 2 * pad.height - (dilation.height * (kernel.height - 1) + 1)) / stride.height + 1;
+        outW = (inpW + 2 * pad.width - (dilation.width * (kernel.width - 1) + 1)) / stride.width + 1;
+    }
+    else
+    {
+        getConvPoolOutParams(inpH, inpW, kernel, stride, pad, padMode, outH, outW);
     }
 
-    DeConvolutionLayer::DeConvolutionLayer(LayerParams &params)
-        : ConvolutionLayer(params) {}
+    topH = outH; topW = outW; topCn = outCn;
+}
 
-    void DeConvolutionLayer::computeInpOutShape(const Blob &inpBlob)
-    {
-        outH = inpBlob.rows();
-        outW = inpBlob.cols();
-        outCn = inpBlob.channels();
+//Deconvolution
 
-        inpH = strideH * (outH - 1) + kerH - 2 * padH;
-        inpW = strideW * (outW - 1) + kerW - 2 * padW;
-        inpCn = numOutput;
+DeConvolutionLayerImpl::DeConvolutionLayerImpl()
+{
 
-        topH = inpH; topW = inpW; topCn = inpCn;
-    }
+}
+
+void DeConvolutionLayerImpl::computeInpOutShape(const Blob &inpBlob)
+{
+    outH = inpBlob.rows();
+    outW = inpBlob.cols();
+    outCn = inpBlob.channels();
+
+    inpH = stride.height * (outH - 1) + kernel.height - 2 * pad.height;
+    inpW = stride.width * (outW - 1) + kernel.width - 2 * pad.width;
+    inpCn = numOutput;
+
+    topH = inpH; topW = inpW; topCn = inpCn;
+}
+
+void DeConvolutionLayerImpl::forward(std::vector<Blob*> &inputs, std::vector<Blob> &outputs)
+{
+    if (!useOpenCL)
+        forward_<Mat>(inputs, outputs);
+    else
+        forward_<UMat>(inputs, outputs);
+}
 
-    void DeConvolutionLayer::forward(std::vector<Blob*> &inputs, std::vector<Blob> &outputs)
+template<typename XMat>
+void DeConvolutionLayerImpl::forward_(std::vector<Blob *> &inputs, std::vector<Blob> &outputs)
+{
+    XMat weightsMat = reshaped(blobs[0].getRefConst<XMat>(), Shape(outCn, ksize));
+    XMat biasesMat  = (bias) ? reshaped(blobs[1].getRefConst<XMat>(), Shape(outCn, 1)) : XMat();
+
+    for (size_t ii = 0; ii < outputs.size(); ii++)
     {
-        Blob &wghtBlob = blobs[0];
+        int numImg = inputs[ii]->size(0);
+        XMat convBlob = reshaped(inputs[ii]->getRefConst<XMat>(), Shape(numImg*outCn, outH*outW));
+        XMat decnBlob = reshaped(outputs[ii].getRef<XMat>(), Shape(numImg*inpCn, inpH*inpW));
 
-        for (size_t ii = 0; ii < outputs.size(); ii++)
+        for (int n = 0; n < numImg; n++)
         {
-            Blob &convBlob = *inputs[ii];
-            Blob &decnBlob = outputs[ii];
-
-            for (int n = 0; n < convBlob.num(); n++)
+            for (int g = 0; g < group; g++)
             {
-                for (int g = 0; g < group; g++)
-                {
-                    Mat dstMat(inpGroupCn, inpH*inpW, decnBlob.type(), decnBlob.ptr(n, g*inpGroupCn));
+                XMat dstMat = decnBlob.rowRange(_Range((g + n * group) * inpGroupCn, inpGroupCn));
+                XMat &colMat = (is1x1()) ? dstMat : colBlob.getRef<XMat>();
 
-                    if (is1x1())
-                        colMat = dstMat;
+                XMat convMat = convBlob.rowRange(_Range((g + n * group) * outGroupCn, outGroupCn));
+                XMat wghtMat = weightsMat.rowRange(_Range(g * outGroupCn, outGroupCn));
 
-                    Mat convMat(outGroupCn, outH*outW, convBlob.type(), convBlob.ptr(n, g*outGroupCn));
-                    Mat wghtMat(outGroupCn, ksize, wghtBlob.type(), wghtBlob.ptr(g*outGroupCn));
-                    cv::gemm(wghtMat, convMat, 1, noArray(), 0, colMat, GEMM_1_T);
+                dnn::gemm(wghtMat, convMat, 1, colMat, 0, GEMM_1_T);
 
-                    col2im(dstMat);
+                if (!is1x1())
+                    col2im(colMat, dstMat);
 
-                    if (bias)
-                    {
-                        float *biasPtr = blobs[1].ptrf() + g*inpGroupCn;
-                        Mat biasMat(inpGroupCn, 1, CV_32F, biasPtr);
-                        cv::gemm(biasMat, biasOnesMat, 1, dstMat, 1, dstMat);
-                    }
+                if (bias)
+                {
+                    XMat curBiasMat = biasesMat.rowRange(_Range(g * outGroupCn, outGroupCn));
+                    dnn::gemm(curBiasMat, biasOnesBlob.getRefConst<XMat>(), 1, dstMat, 1);
                 }
             }
         }
     }
+}
 
-    void DeConvolutionLayer::col2im(Mat &dstMat)
+void DeConvolutionLayerImpl::col2im(const Mat &colMat, Mat &dstImg)
+{
+    if (is1x1())
     {
-        if (is1x1()) return;
+        dstImg = colMat;
+        return;
+    }
+    if (dstImg.type() == CV_32F)
+        col2im_CpuPBody<float>::run(colMat.ptr<float>(), inpGroupCn, inpH, inpW, kernel.height, kernel.width, pad.height, pad.width, stride.height, stride.width, dstImg.ptr<float>());
+    if (dstImg.type() == CV_64F)
+        col2im_CpuPBody<double>::run(colMat.ptr<double>(), inpGroupCn, inpH, inpW, kernel.height, kernel.width, pad.height, pad.width, stride.height, stride.width, dstImg.ptr<double>());
+}
 
-        if (dstMat.type() == CV_32F)
-            col2im_cpu((float*)colMat.ptr(), inpGroupCn, inpH, inpW, kerH, kerW, padH, padW, strideH, strideW, (float*)dstMat.ptr());
-        if (dstMat.type() == CV_64F)
-            col2im_cpu((double*)colMat.ptr(), inpGroupCn, inpH, inpW, kerH, kerW, padH, padW, strideH, strideW, (double*)dstMat.ptr());
+void DeConvolutionLayerImpl::col2im(const UMat &colMat, UMat &dstImg)
+{
+    if (is1x1())
+    {
+        dstImg = colMat;
+        return;
     }
+#ifdef HAVE_OPENCL
+    CV_Assert(col2im_ocl(colMat, inpGroupCn, inpH, inpW, kernel.height, kernel.width, pad.height, pad.width, stride.height, stride.width, dstImg));
+#else
+    CV_Error(Error::StsInternal, "");
+    dstImg = colMat;
+#endif
+}
+
+//Initializers
+
+Ptr<BaseConvolutionLayer> ConvolutionLayer::create(Size kernel, Size stride, Size pad, Size dilation)
+{
+    ConvolutionLayerImpl *l = new ConvolutionLayerImpl();
+    l->kernel = kernel;
+    l->pad = pad;
+    l->stride = stride;
+    l->dilation = dilation;
+    return Ptr<BaseConvolutionLayer>(l);
+}
+
+Ptr<BaseConvolutionLayer> DeconvolutionLayer::create(Size kernel, Size stride, Size pad, Size dilation)
+{
+    DeConvolutionLayerImpl *l = new DeConvolutionLayerImpl();
+    l->kernel = kernel;
+    l->pad = pad;
+    l->stride = stride;
+    l->dilation = dilation;
+    return Ptr<BaseConvolutionLayer>(l);
+}
+
 }
 }
diff --git a/contrib/modules/dnn/src/layers/convolution_layer.hpp b/contrib/modules/dnn/src/layers/convolution_layer.hpp
index 0598217..3b59bb6 100644
--- a/contrib/modules/dnn/src/layers/convolution_layer.hpp
+++ b/contrib/modules/dnn/src/layers/convolution_layer.hpp
@@ -42,51 +42,66 @@
 #ifndef __OPENCV_DNN_LAYERS_CONVOLUTION_LAYER_HPP__
 #define __OPENCV_DNN_LAYERS_CONVOLUTION_LAYER_HPP__
 #include "../precomp.hpp"
+#include <opencv2/dnn/all_layers.hpp>
 
 namespace cv
 {
 namespace dnn
 {
-    //TODO: simultaneously convolution and bias addition for cache optimization
-    class ConvolutionLayer : public Layer
-    {
-    protected:
-        bool bias;
-        int numOutput, group;
-        int padH, padW;
-        int kerH, kerW;
-        int strideH, strideW;
-
-        int inpH, inpW, inpCn;
-        int outH, outW, outCn;
-        int topH, topW, topCn; //switched between inp/out on deconv/conv
-        int inpGroupCn, outGroupCn;
-        int ksize;
-
-        bool useOpenCL;
-        Mat colMat, biasOnesMat;
-
-        inline bool is1x1() const;
-        virtual void computeInpOutShape(const Blob &inpBlob);
-        void im2col(Blob &inpBlob, int imNum, int cnGroup);
-
-    public:
-        ConvolutionLayer() {}
-        ConvolutionLayer(LayerParams &params);
-        void allocate(const std::vector<Blob*> &inputs, std::vector<Blob> &outputs);
-        void forward(std::vector<Blob*> &inputs, std::vector<Blob> &outputs);
-    };
-
-    class DeConvolutionLayer : public ConvolutionLayer
-    {
-    protected:
-        void computeInpOutShape(const Blob &inpBlob);
-        void col2im(Mat &dstMat);
-
-    public:
-        DeConvolutionLayer(LayerParams &params);
-        void forward(std::vector<Blob*> &inputs, std::vector<Blob> &outputs);
-    };
+
+//TODO: simultaneously convolution and bias addition for cache optimization
+class ConvolutionLayerImpl : public ConvolutionLayer
+{
+public:
+
+    ConvolutionLayerImpl();
+    virtual void allocate(const std::vector<Blob*> &inputs, std::vector<Blob> &outputs);
+    virtual void forward(std::vector<Blob*> &inputs, std::vector<Blob> &outputs);
+    virtual void init();
+
+protected:
+    int numOutput, group;
+    int inpH, inpW, inpCn;
+    int outH, outW, outCn;
+    int topH, topW, topCn; //switched between inp/out on deconv/conv
+    int inpGroupCn, outGroupCn;
+    int ksize;
+
+    bool bias;
+    bool tryUseOpenCL, useOpenCL;
+
+    Blob colBlob, biasOnesBlob;
+
+    bool is1x1() const;
+    virtual void computeInpOutShape(const Blob &inpBlob);
+
+    template<typename XMat>
+    void forward_(std::vector<Blob*> &inputs, std::vector<Blob> &outputs);
+    void im2col(const  Mat &srcImg,  Mat &dstCol);
+    void im2col(const UMat &srcImg, UMat &dstCol);
+};
+
+class DeConvolutionLayerImpl : public ConvolutionLayerImpl
+{
+public:
+    DeConvolutionLayerImpl();
+    virtual void forward(std::vector<Blob*> &inputs, std::vector<Blob> &outputs);
+
+protected:
+
+    virtual void computeInpOutShape(const Blob &inpBlob);
+
+    template<typename XMat>
+    void forward_(std::vector<Blob*> &inputs, std::vector<Blob> &outputs);
+    void col2im(const  Mat &colMat, Mat  &dstImg);
+    void col2im(const UMat &colMat, UMat &dstImg);
+};
+
+//Importers
+Ptr<Layer> createConvolutionLayerFromCaffe(LayerParams &params);
+Ptr<Layer> createDeconvolutionLayerFromCaffe(LayerParams &params);
+
 }
 }
+
 #endif
diff --git a/contrib/modules/dnn/src/layers/crop_layer.cpp b/contrib/modules/dnn/src/layers/crop_layer.cpp
new file mode 100755
index 0000000..06f6f75
--- /dev/null
+++ b/contrib/modules/dnn/src/layers/crop_layer.cpp
@@ -0,0 +1,128 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+//  By downloading, copying, installing or using the software you agree to this license.
+//  If you do not agree to this license, do not download, install,
+//  copy or use the software.
+//
+//
+//                           License Agreement
+//                For Open Source Computer Vision Library
+//
+// Copyright (C) 2013, OpenCV Foundation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+//   * Redistribution's of source code must retain the above copyright notice,
+//     this list of conditions and the following disclaimer.
+//
+//   * Redistribution's in binary form must reproduce the above copyright notice,
+//     this list of conditions and the following disclaimer in the documentation
+//     and/or other materials provided with the distribution.
+//
+//   * The name of the copyright holders may not be used to endorse or promote products
+//     derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "../precomp.hpp"
+#include "layers_common.hpp"
+#include "crop_layer.hpp"
+
+namespace cv
+{
+namespace dnn
+{
+
+CropLayerImpl::CropLayerImpl(int start_axis_, const std::vector<int> &offset_)
+{
+    startAxis = start_axis_;
+    offset = offset_;
+}
+
+void CropLayerImpl::allocate(const std::vector<Blob *> &inputs, std::vector<Blob> &outputs)
+{
+    CV_Assert(2 == inputs.size());
+
+    const Blob &inpBlob = *inputs[0];
+    const Blob &inpSzBlob = *inputs[1];
+
+    int start_axis = inpBlob.canonicalAxis(startAxis);
+    int dims = inpBlob.dims();
+
+    std::vector<int> offset_final(dims, 0);
+    if (offset.size() == 1)
+    {
+        for (int i = start_axis; i < dims; i++)
+            offset_final[i] = offset[0];
+    }
+    else if (offset.size() > 1)
+    {
+        if ((int)offset.size() != dims - start_axis)
+            CV_Error(Error::StsBadArg, "number of offset values specified must be equal to the number of dimensions following axis.");
+
+        for (int i = start_axis; i < dims; i++)
+            offset_final[i] = offset[i - start_axis];
+    }
+
+    BlobShape dstShape = inpBlob.shape();
+    crop_ranges.resize(dims, Range::all());
+    for (int i = start_axis; i < dims; i++)
+    {
+        dstShape[i] = inpSzBlob.size(i);
+
+        if (!offset.empty()) //normal case
+        {
+            if (offset_final[i] < 0 || offset_final[i] + inpSzBlob.size(i) > inpBlob.size(i))
+                CV_Error(Error::StsBadArg, "invalid crop parameters");
+
+            crop_ranges[i] = Range(offset_final[i], offset_final[i] + inpSzBlob.size(i));
+        }
+        else //detect offset automatically so that cropped image is center of original one
+        {
+            if (inpSzBlob.size(i) > inpBlob.size(i))
+                CV_Error(Error::StsBadArg, "invalid output blob size");
+
+            int cur_crop = (inpBlob.size(i) - inpSzBlob.size(i)) / 2;
+            crop_ranges[i] = Range(cur_crop, cur_crop + inpSzBlob.size(i));
+        }
+    }
+
+    outputs.resize(1);
+    outputs[0].create(dstShape);
+}
+
+void CropLayerImpl::forward(std::vector<Blob *> &inputs, std::vector<Blob> &outputs)
+{
+    Blob &input = *inputs[0];
+    Blob &output = outputs[0];
+
+    #ifdef HAVE_OPENCL
+    if (input.getState() == Blob::HEAD_AT_UMAT)
+        input.umatRefConst()(&crop_ranges[0]).copyTo(output.umatRef());
+    else
+    #endif
+        input.matRefConst()(&crop_ranges[0]).copyTo(output.matRef());
+}
+
+Ptr<CropLayer> CropLayer::create(int start_axis, const std::vector<int> &offset)
+{
+    return Ptr<CropLayer>(new CropLayerImpl(start_axis, offset));
+}
+
+}
+}
diff --git a/contrib/modules/dnn/src/layers/crop_layer.hpp b/contrib/modules/dnn/src/layers/crop_layer.hpp
new file mode 100755
index 0000000..bc8789b
--- /dev/null
+++ b/contrib/modules/dnn/src/layers/crop_layer.hpp
@@ -0,0 +1,62 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+//  By downloading, copying, installing or using the software you agree to this license.
+//  If you do not agree to this license, do not download, install,
+//  copy or use the software.
+//
+//
+//                           License Agreement
+//                For Open Source Computer Vision Library
+//
+// Copyright (C) 2013, OpenCV Foundation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+//   * Redistribution's of source code must retain the above copyright notice,
+//     this list of conditions and the following disclaimer.
+//
+//   * Redistribution's in binary form must reproduce the above copyright notice,
+//     this list of conditions and the following disclaimer in the documentation
+//     and/or other materials provided with the distribution.
+//
+//   * The name of the copyright holders may not be used to endorse or promote products
+//     derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#ifndef __OPENCV_DNN_LAYERS_CROP_LAYER_HPP__
+#define __OPENCV_DNN_LAYERS_CROP_LAYER_HPP__
+#include "../precomp.hpp"
+#include <opencv2/dnn/all_layers.hpp>
+
+namespace cv
+{
+namespace dnn
+{
+    class CropLayerImpl : public CropLayer
+    {
+        std::vector<Range> crop_ranges;
+
+    public:
+        CropLayerImpl(int start_axis, const std::vector<int> &offset);
+        void allocate(const std::vector<Blob*> &inputs, std::vector<Blob> &outputs);
+        void forward(std::vector<Blob*> &inputs, std::vector<Blob> &outputs);
+    };
+}
+}
+#endif
diff --git a/contrib/modules/dnn/src/layers/detection_output_layer.cpp b/contrib/modules/dnn/src/layers/detection_output_layer.cpp
new file mode 100644
index 0000000..00002db
--- /dev/null
+++ b/contrib/modules/dnn/src/layers/detection_output_layer.cpp
@@ -0,0 +1,750 @@
+/*M ///////////////////////////////////////////////////////////////////////////////////////
+//
+//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+//  By downloading, copying, installing or using the software you agree to this license.
+//  If you do not agree to this license, do not download, install,
+//  copy or use the software.
+//
+//
+//                           License Agreement
+//                For Open Source Computer Vision Library
+//
+// Copyright (C) 2013, OpenCV Foundation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+//   * Redistribution's of source code must retain the above copyright notice,
+//     this list of conditions and the following disclaimer.
+//
+//   * Redistribution's in binary form must reproduce the above copyright notice,
+//     this list of conditions and the following disclaimer in the documentation
+//     and/or other materials provided with the distribution.
+//
+//   * The name of the copyright holders may not be used to endorse or promote products
+//     derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "../precomp.hpp"
+#include "layers_common.hpp"
+#include "detection_output_layer.hpp"
+#include <float.h>
+#include <string>
+
+namespace cv
+{
+namespace dnn
+{
+
+namespace util
+{
+template <typename T>
+std::string to_string(T value)
+{
+    std::ostringstream stream;
+    stream << value;
+    return stream.str();
+}
+
+template <typename T>
+void make_error(const std::string& message1, const T& message2)
+{
+    std::string error(message1);
+    error += std::string(util::to_string<int>(message2));
+    CV_Error(Error::StsBadArg, error.c_str());
+}
+
+template <typename T>
+bool SortScorePairDescend(const std::pair<float, T>& pair1,
+                          const std::pair<float, T>& pair2)
+{
+    return pair1.first > pair2.first;
+}
+}
+
+const std::string DetectionOutputLayer::_layerName = std::string("DetectionOutput");
+
+bool DetectionOutputLayer::getParameterDict(const LayerParams &params,
+                                    const std::string &parameterName,
+                                    DictValue& result)
+{
+    if (!params.has(parameterName))
+    {
+        return false;
+    }
+
+    result = params.get(parameterName);
+    return true;
+}
+
+template<typename T>
+T DetectionOutputLayer::getParameter(const LayerParams &params,
+                             const std::string &parameterName,
+                             const size_t &idx,
+                             const bool required,
+                             const T& defaultValue)
+{
+    DictValue dictValue;
+    bool success = getParameterDict(params, parameterName, dictValue);
+    if(!success)
+    {
+        if(required)
+        {
+            std::string message = _layerName;
+            message += " layer parameter does not contain ";
+            message += parameterName;
+            message += " parameter.";
+            CV_Error(Error::StsBadArg, message);
+        }
+        else
+        {
+            return defaultValue;
+        }
+    }
+    return dictValue.get<T>(idx);
+}
+
+void DetectionOutputLayer::getCodeType(LayerParams &params)
+{
+    String codeTypeString = params.get<String>("code_type").toLowerCase();
+    if (codeTypeString == "corner")
+        _codeType = caffe::PriorBoxParameter_CodeType_CORNER;
+    else if (codeTypeString == "center_size")
+        _codeType = caffe::PriorBoxParameter_CodeType_CENTER_SIZE;
+    else
+        _codeType = caffe::PriorBoxParameter_CodeType_CORNER;
+}
+
+DetectionOutputLayer::DetectionOutputLayer(LayerParams &params) : Layer(params)
+{
+    _numClasses = getParameter<unsigned>(params, "num_classes");
+    _shareLocation = getParameter<bool>(params, "share_location");
+    _numLocClasses = _shareLocation ? 1 : _numClasses;
+    _backgroundLabelId = getParameter<int>(params, "background_label_id");
+    _varianceEncodedInTarget = getParameter<bool>(params, "variance_encoded_in_target", 0, false, false);
+    _keepTopK = getParameter<int>(params, "keep_top_k");
+    _confidenceThreshold = getParameter<float>(params, "confidence_threshold", 0, false, -FLT_MAX);
+    _topK = getParameter<int>(params, "top_k", 0, false, -1);
+
+    getCodeType(params);
+
+    // Parameters used in nms.
+    _nmsThreshold = getParameter<float>(params, "nms_threshold");
+    CV_Assert(_nmsThreshold > 0.);
+}
+
+void DetectionOutputLayer::checkInputs(const std::vector<Blob*> &inputs)
+{
+    for (size_t i = 1; i < inputs.size(); i++)
+    {
+        for (size_t j = 0; j < _numAxes; j++)
+        {
+            CV_Assert(inputs[i]->shape()[j] == inputs[0]->shape()[j]);
+        }
+    }
+}
+
+void DetectionOutputLayer::allocate(const std::vector<Blob*> &inputs,
+                                    std::vector<Blob> &outputs)
+{
+    CV_Assert(inputs.size() > 0);
+    CV_Assert(inputs[0]->num() == inputs[1]->num());
+    _num = inputs[0]->num();
+
+    _numPriors = inputs[2]->rows() / 4;
+    CV_Assert((_numPriors * _numLocClasses * 4) == inputs[0]->channels());
+    CV_Assert(int(_numPriors * _numClasses) == inputs[1]->channels());
+
+    // num() and channels() are 1.
+    // Since the number of bboxes to be kept is unknown before nms, we manually
+    // set it to (fake) 1.
+    // Each row is a 7 dimension std::vector, which stores
+    // [image_id, label, confidence, xmin, ymin, xmax, ymax]
+    BlobShape outputShape = BlobShape(1, 1, 1, 7);
+    outputs[0].create(BlobShape(outputShape));
+}
+
+void DetectionOutputLayer::forward(std::vector<Blob*> &inputs,
+                                   std::vector<Blob> &outputs)
+{
+    const float* locationData = inputs[0]->ptrf();
+    const float* confidenceData = inputs[1]->ptrf();
+    const float* priorData = inputs[2]->ptrf();
+
+    // Retrieve all location predictions.
+    std::vector<LabelBBox> allLocationPredictions;
+    GetLocPredictions(locationData, _num, _numPriors, _numLocClasses,
+                      _shareLocation, &allLocationPredictions);
+
+    // Retrieve all confidences.
+    std::vector<std::map<int, std::vector<float> > > allConfidenceScores;
+    GetConfidenceScores(confidenceData, _num, _numPriors, _numClasses,
+                        &allConfidenceScores);
+
+    // Retrieve all prior bboxes. It is same within a batch since we assume all
+    // images in a batch are of same dimension.
+    std::vector<caffe::NormalizedBBox> priorBBoxes;
+    std::vector<std::vector<float> > priorVariances;
+    GetPriorBBoxes(priorData, _numPriors, &priorBBoxes, &priorVariances);
+
+    // Decode all loc predictions to bboxes.
+    std::vector<LabelBBox> allDecodedBBoxes;
+    DecodeBBoxesAll(allLocationPredictions, priorBBoxes, priorVariances, _num,
+                    _shareLocation, _numLocClasses, _backgroundLabelId,
+                    _codeType, _varianceEncodedInTarget, &allDecodedBBoxes);
+
+    int numKept = 0;
+    std::vector<std::map<int, std::vector<int> > > allIndices;
+    for (int i = 0; i < _num; ++i)
+    {
+        const LabelBBox& decodeBBoxes = allDecodedBBoxes[i];
+        const std::map<int, std::vector<float> >& confidenceScores =
+            allConfidenceScores[i];
+        std::map<int, std::vector<int> > indices;
+        int numDetections = 0;
+        for (int c = 0; c < (int)_numClasses; ++c)
+        {
+            if (c == _backgroundLabelId)
+            {
+                // Ignore background class.
+                continue;
+            }
+            if (confidenceScores.find(c) == confidenceScores.end())
+            {
+                // Something bad happened if there are no predictions for current label.
+                util::make_error<int>("Could not find confidence predictions for label ", c);
+            }
+
+            const std::vector<float>& scores = confidenceScores.find(c)->second;
+            int label = _shareLocation ? -1 : c;
+            if (decodeBBoxes.find(label) == decodeBBoxes.end())
+            {
+                // Something bad happened if there are no predictions for current label.
+                util::make_error<int>("Could not find location predictions for label ", label);
+                continue;
+            }
+            const std::vector<caffe::NormalizedBBox>& bboxes =
+                decodeBBoxes.find(label)->second;
+            ApplyNMSFast(bboxes, scores, _confidenceThreshold, _nmsThreshold,
+                         _topK, &(indices[c]));
+            numDetections += indices[c].size();
+        }
+        if (_keepTopK > -1 && numDetections > _keepTopK)
+        {
+            std::vector<std::pair<float, std::pair<int, int> > > scoreIndexPairs;
+            for (std::map<int, std::vector<int> >::iterator it = indices.begin();
+                 it != indices.end(); ++it)
+            {
+                int label = it->first;
+                const std::vector<int>& labelIndices = it->second;
+                if (confidenceScores.find(label) == confidenceScores.end())
+                {
+                    // Something bad happened for current label.
+                    util::make_error<int>("Could not find location predictions for label ", label);
+                    continue;
+                }
+                const std::vector<float>& scores = confidenceScores.find(label)->second;
+                for (size_t j = 0; j < labelIndices.size(); ++j)
+                {
+                    size_t idx = labelIndices[j];
+                    CV_Assert(idx < scores.size());
+                    scoreIndexPairs.push_back(
+                        std::make_pair(scores[idx], std::make_pair(label, idx)));
+                }
+            }
+            // Keep outputs k results per image.
+            std::sort(scoreIndexPairs.begin(), scoreIndexPairs.end(),
+                      util::SortScorePairDescend<std::pair<int, int> >);
+            scoreIndexPairs.resize(_keepTopK);
+            // Store the new indices.
+            std::map<int, std::vector<int> > newIndices;
+            for (size_t j = 0; j < scoreIndexPairs.size(); ++j)
+            {
+                int label = scoreIndexPairs[j].second.first;
+                int idx = scoreIndexPairs[j].second.second;
+                newIndices[label].push_back(idx);
+            }
+            allIndices.push_back(newIndices);
+            numKept += _keepTopK;
+        }
+        else
+        {
+            allIndices.push_back(indices);
+            numKept += numDetections;
+        }
+    }
+
+    if (numKept == 0)
+    {
+        CV_ErrorNoReturn(Error::StsError, "Couldn't find any detections");
+        return;
+    }
+    std::vector<int> outputsShape(2, 1);
+    outputsShape.push_back(numKept);
+    outputsShape.push_back(7);
+    outputs[0].create(outputsShape);
+    float* outputsData = outputs[0].ptrf();
+
+    int count = 0;
+    for (int i = 0; i < _num; ++i)
+    {
+        const std::map<int, std::vector<float> >& confidenceScores =
+            allConfidenceScores[i];
+        const LabelBBox& decodeBBoxes = allDecodedBBoxes[i];
+        for (std::map<int, std::vector<int> >::iterator it = allIndices[i].begin();
+             it != allIndices[i].end(); ++it)
+        {
+            int label = it->first;
+            if (confidenceScores.find(label) == confidenceScores.end())
+            {
+                // Something bad happened if there are no predictions for current label.
+                util::make_error<int>("Could not find confidence predictions for label ", label);
+                continue;
+            }
+            const std::vector<float>& scores = confidenceScores.find(label)->second;
+            int locLabel = _shareLocation ? -1 : label;
+            if (decodeBBoxes.find(locLabel) == decodeBBoxes.end())
+            {
+                // Something bad happened if there are no predictions for current label.
+                util::make_error<int>("Could not find location predictions for label ", locLabel);
+                continue;
+            }
+            const std::vector<caffe::NormalizedBBox>& bboxes =
+                decodeBBoxes.find(locLabel)->second;
+            std::vector<int>& indices = it->second;
+
+            for (size_t j = 0; j < indices.size(); ++j)
+            {
+                int idx = indices[j];
+                outputsData[count * 7] = i;
+                outputsData[count * 7 + 1] = label;
+                outputsData[count * 7 + 2] = scores[idx];
+                caffe::NormalizedBBox clipBBox;
+                ClipBBox(bboxes[idx], &clipBBox);
+                outputsData[count * 7 + 3] = clipBBox.xmin();
+                outputsData[count * 7 + 4] = clipBBox.ymin();
+                outputsData[count * 7 + 5] = clipBBox.xmax();
+                outputsData[count * 7 + 6] = clipBBox.ymax();
+
+                ++count;
+            }
+        }
+    }
+}
+
+float DetectionOutputLayer::BBoxSize(const caffe::NormalizedBBox& bbox,
+                                     const bool normalized)
+{
+    if (bbox.xmax() < bbox.xmin() || bbox.ymax() < bbox.ymin())
+    {
+        // If bbox is invalid (e.g. xmax < xmin or ymax < ymin), return 0.
+        return 0;
+    }
+    else
+    {
+        if (bbox.has_size())
+        {
+            return bbox.size();
+        }
+        else
+        {
+            float width = bbox.xmax() - bbox.xmin();
+            float height = bbox.ymax() - bbox.ymin();
+            if (normalized)
+            {
+                return width * height;
+            }
+            else
+            {
+                // If bbox is not within range [0, 1].
+                return (width + 1) * (height + 1);
+            }
+        }
+    }
+}
+
+void DetectionOutputLayer::ClipBBox(const caffe::NormalizedBBox& bbox,
+                                    caffe::NormalizedBBox* clipBBox)
+{
+    clipBBox->set_xmin(std::max(std::min(bbox.xmin(), 1.f), 0.f));
+    clipBBox->set_ymin(std::max(std::min(bbox.ymin(), 1.f), 0.f));
+    clipBBox->set_xmax(std::max(std::min(bbox.xmax(), 1.f), 0.f));
+    clipBBox->set_ymax(std::max(std::min(bbox.ymax(), 1.f), 0.f));
+    clipBBox->clear_size();
+    clipBBox->set_size(BBoxSize(*clipBBox));
+    clipBBox->set_difficult(bbox.difficult());
+}
+
+void DetectionOutputLayer::DecodeBBox(
+    const caffe::NormalizedBBox& priorBBox, const std::vector<float>& priorVariance,
+    const CodeType codeType, const bool varianceEncodedInTarget,
+    const caffe::NormalizedBBox& bbox, caffe::NormalizedBBox* decodeBBox)
+{
+    if (codeType == caffe::PriorBoxParameter_CodeType_CORNER)
+    {
+        if (varianceEncodedInTarget)
+        {
+            // variance is encoded in target, we simply need to add the offset
+            // predictions.
+            decodeBBox->set_xmin(priorBBox.xmin() + bbox.xmin());
+            decodeBBox->set_ymin(priorBBox.ymin() + bbox.ymin());
+            decodeBBox->set_xmax(priorBBox.xmax() + bbox.xmax());
+            decodeBBox->set_ymax(priorBBox.ymax() + bbox.ymax());
+        }
+        else
+        {
+            // variance is encoded in bbox, we need to scale the offset accordingly.
+            decodeBBox->set_xmin(
+                priorBBox.xmin() + priorVariance[0] * bbox.xmin());
+            decodeBBox->set_ymin(
+                priorBBox.ymin() + priorVariance[1] * bbox.ymin());
+            decodeBBox->set_xmax(
+                priorBBox.xmax() + priorVariance[2] * bbox.xmax());
+            decodeBBox->set_ymax(
+                priorBBox.ymax() + priorVariance[3] * bbox.ymax());
+        }
+    }
+    else
+    if (codeType == caffe::PriorBoxParameter_CodeType_CENTER_SIZE)
+    {
+        float priorWidth = priorBBox.xmax() - priorBBox.xmin();
+        CV_Assert(priorWidth > 0);
+
+        float priorHeight = priorBBox.ymax() - priorBBox.ymin();
+        CV_Assert(priorHeight > 0);
+
+        float priorCenterX = (priorBBox.xmin() + priorBBox.xmax()) / 2.;
+        float priorCenterY = (priorBBox.ymin() + priorBBox.ymax()) / 2.;
+
+        float decodeBBoxCenterX, decodeBBoxCenterY;
+        float decodeBBoxWidth, decodeBBoxHeight;
+        if (varianceEncodedInTarget)
+        {
+            // variance is encoded in target, we simply need to retore the offset
+            // predictions.
+            decodeBBoxCenterX = bbox.xmin() * priorWidth + priorCenterX;
+            decodeBBoxCenterY = bbox.ymin() * priorHeight + priorCenterY;
+            decodeBBoxWidth = exp(bbox.xmax()) * priorWidth;
+            decodeBBoxHeight = exp(bbox.ymax()) * priorHeight;
+        }
+        else
+        {
+            // variance is encoded in bbox, we need to scale the offset accordingly.
+            decodeBBoxCenterX =
+                priorVariance[0] * bbox.xmin() * priorWidth + priorCenterX;
+            decodeBBoxCenterY =
+                priorVariance[1] * bbox.ymin() * priorHeight + priorCenterY;
+            decodeBBoxWidth =
+                exp(priorVariance[2] * bbox.xmax()) * priorWidth;
+            decodeBBoxHeight =
+                exp(priorVariance[3] * bbox.ymax()) * priorHeight;
+        }
+
+        decodeBBox->set_xmin(decodeBBoxCenterX - decodeBBoxWidth / 2.);
+        decodeBBox->set_ymin(decodeBBoxCenterY - decodeBBoxHeight / 2.);
+        decodeBBox->set_xmax(decodeBBoxCenterX + decodeBBoxWidth / 2.);
+        decodeBBox->set_ymax(decodeBBoxCenterY + decodeBBoxHeight / 2.);
+    }
+    else
+    {
+        CV_Error(Error::StsBadArg, "Unknown LocLossType.");
+    }
+    float bboxSize = BBoxSize(*decodeBBox);
+    decodeBBox->set_size(bboxSize);
+}
+
+void DetectionOutputLayer::DecodeBBoxes(
+    const std::vector<caffe::NormalizedBBox>& priorBBoxes,
+    const std::vector<std::vector<float> >& priorVariances,
+    const CodeType codeType, const bool varianceEncodedInTarget,
+    const std::vector<caffe::NormalizedBBox>& bboxes,
+    std::vector<caffe::NormalizedBBox>* decodeBBoxes)
+{
+    CV_Assert(priorBBoxes.size() == priorVariances.size());
+    CV_Assert(priorBBoxes.size() == bboxes.size());
+    int numBBoxes = priorBBoxes.size();
+    if (numBBoxes >= 1)
+    {
+        CV_Assert(priorVariances[0].size() == 4);
+    }
+    decodeBBoxes->clear();
+    for (int i = 0; i < numBBoxes; ++i)
+    {
+        caffe::NormalizedBBox decodeBBox;
+        DecodeBBox(priorBBoxes[i], priorVariances[i], codeType,
+                   varianceEncodedInTarget, bboxes[i], &decodeBBox);
+        decodeBBoxes->push_back(decodeBBox);
+    }
+}
+
+void DetectionOutputLayer::DecodeBBoxesAll(
+    const std::vector<LabelBBox>& allLocPreds,
+    const std::vector<caffe::NormalizedBBox>& priorBBoxes,
+    const std::vector<std::vector<float> >& priorVariances,
+    const size_t num, const bool shareLocation,
+    const int numLocClasses, const int backgroundLabelId,
+    const CodeType codeType, const bool varianceEncodedInTarget,
+    std::vector<LabelBBox>* allDecodeBBoxes)
+{
+    CV_Assert(allLocPreds.size() == num);
+    allDecodeBBoxes->clear();
+    allDecodeBBoxes->resize(num);
+    for (size_t i = 0; i < num; ++i)
+    {
+        // Decode predictions into bboxes.
+        LabelBBox& decodeBBoxes = (*allDecodeBBoxes)[i];
+        for (int c = 0; c < numLocClasses; ++c)
+        {
+            int label = shareLocation ? -1 : c;
+            if (label == backgroundLabelId)
+            {
+                // Ignore background class.
+                continue;
+            }
+            if (allLocPreds[i].find(label) == allLocPreds[i].end())
+            {
+                // Something bad happened if there are no predictions for current label.
+                util::make_error<int>("Could not find location predictions for label ", label);
+            }
+            const std::vector<caffe::NormalizedBBox>& labelLocPreds =
+                allLocPreds[i].find(label)->second;
+            DecodeBBoxes(priorBBoxes, priorVariances,
+                         codeType, varianceEncodedInTarget,
+                         labelLocPreds, &(decodeBBoxes[label]));
+        }
+    }
+}
+
+void DetectionOutputLayer::GetPriorBBoxes(const float* priorData, const int& numPriors,
+                                          std::vector<caffe::NormalizedBBox>* priorBBoxes,
+                                          std::vector<std::vector<float> >* priorVariances)
+{
+    priorBBoxes->clear();
+    priorVariances->clear();
+    for (int i = 0; i < numPriors; ++i)
+    {
+        int startIdx = i * 4;
+        caffe::NormalizedBBox bbox;
+        bbox.set_xmin(priorData[startIdx]);
+        bbox.set_ymin(priorData[startIdx + 1]);
+        bbox.set_xmax(priorData[startIdx + 2]);
+        bbox.set_ymax(priorData[startIdx + 3]);
+        float bboxSize = BBoxSize(bbox);
+        bbox.set_size(bboxSize);
+        priorBBoxes->push_back(bbox);
+    }
+
+    for (int i = 0; i < numPriors; ++i)
+    {
+        int startIdx = (numPriors + i) * 4;
+        std::vector<float> var;
+        for (int j = 0; j < 4; ++j)
+        {
+            var.push_back(priorData[startIdx + j]);
+        }
+        priorVariances->push_back(var);
+    }
+}
+
+void DetectionOutputLayer::ScaleBBox(const caffe::NormalizedBBox& bbox,
+                                     const int height, const int width,
+                                     caffe::NormalizedBBox* scaleBBox)
+{
+    scaleBBox->set_xmin(bbox.xmin() * width);
+    scaleBBox->set_ymin(bbox.ymin() * height);
+    scaleBBox->set_xmax(bbox.xmax() * width);
+    scaleBBox->set_ymax(bbox.ymax() * height);
+    scaleBBox->clear_size();
+    bool normalized = !(width > 1 || height > 1);
+    scaleBBox->set_size(BBoxSize(*scaleBBox, normalized));
+    scaleBBox->set_difficult(bbox.difficult());
+}
+
+
+void DetectionOutputLayer::GetLocPredictions(
+    const float* locData, const int num,
+    const int numPredsPerClass, const int numLocClasses,
+    const bool shareLocation, std::vector<LabelBBox>* locPreds)
+{
+    locPreds->clear();
+    if (shareLocation)
+    {
+        CV_Assert(numLocClasses == 1);
+    }
+    locPreds->resize(num);
+    for (int i = 0; i < num; ++i)
+    {
+        LabelBBox& labelBBox = (*locPreds)[i];
+        for (int p = 0; p < numPredsPerClass; ++p)
+        {
+            int startIdx = p * numLocClasses * 4;
+            for (int c = 0; c < numLocClasses; ++c)
+            {
+                int label = shareLocation ? -1 : c;
+                if (labelBBox.find(label) == labelBBox.end())
+                {
+                    labelBBox[label].resize(numPredsPerClass);
+                }
+                labelBBox[label][p].set_xmin(locData[startIdx + c * 4]);
+                labelBBox[label][p].set_ymin(locData[startIdx + c * 4 + 1]);
+                labelBBox[label][p].set_xmax(locData[startIdx + c * 4 + 2]);
+                labelBBox[label][p].set_ymax(locData[startIdx + c * 4 + 3]);
+            }
+        }
+        locData += numPredsPerClass * numLocClasses * 4;
+    }
+}
+
+void DetectionOutputLayer::GetConfidenceScores(
+    const float* confData, const int num,
+    const int numPredsPerClass, const int numClasses,
+    std::vector<std::map<int, std::vector<float> > >* confPreds)
+{
+    confPreds->clear();
+    confPreds->resize(num);
+    for (int i = 0; i < num; ++i)
+    {
+        std::map<int, std::vector<float> >& labelScores = (*confPreds)[i];
+        for (int p = 0; p < numPredsPerClass; ++p)
+        {
+            int startIdx = p * numClasses;
+            for (int c = 0; c < numClasses; ++c)
+            {
+                labelScores[c].push_back(confData[startIdx + c]);
+            }
+        }
+        confData += numPredsPerClass * numClasses;
+    }
+}
+
+void DetectionOutputLayer::ApplyNMSFast(const std::vector<caffe::NormalizedBBox>& bboxes,
+                                        const std::vector<float>& scores,
+                                        const float score_threshold,
+                                        const float nms_threshold, const int top_k,
+                                        std::vector<int>* indices)
+{
+    // Sanity check.
+    CV_Assert(bboxes.size() == scores.size());
+
+    // Get top_k scores (with corresponding indices).
+    std::vector<std::pair<float, int> > score_index_vec;
+    GetMaxScoreIndex(scores, score_threshold, top_k, &score_index_vec);
+
+    // Do nms.
+    indices->clear();
+    while (score_index_vec.size() != 0)
+    {
+        const int idx = score_index_vec.front().second;
+        bool keep = true;
+        for (size_t k = 0; k < indices->size(); ++k)
+        {
+            if (keep)
+            {
+                const int kept_idx = (*indices)[k];
+                float overlap = JaccardOverlap(bboxes[idx], bboxes[kept_idx]);
+                keep = overlap <= nms_threshold;
+            }
+            else
+            {
+                break;
+            }
+        }
+        if (keep)
+        {
+            indices->push_back(idx);
+        }
+        score_index_vec.erase(score_index_vec.begin());
+    }
+}
+
+
+void DetectionOutputLayer::GetMaxScoreIndex(
+    const std::vector<float>& scores, const float threshold,const int top_k,
+    std::vector<std::pair<float, int> >* score_index_vec)
+{
+    // Generate index score pairs.
+    for (size_t i = 0; i < scores.size(); ++i)
+    {
+        if (scores[i] > threshold)
+        {
+            score_index_vec->push_back(std::make_pair(scores[i], i));
+        }
+    }
+
+    // Sort the score pair according to the scores in descending order
+    std::stable_sort(score_index_vec->begin(), score_index_vec->end(),
+                     util::SortScorePairDescend<int>);
+
+    // Keep top_k scores if needed.
+    if (top_k > -1 && top_k < (int)score_index_vec->size())
+    {
+        score_index_vec->resize(top_k);
+    }
+}
+
+void DetectionOutputLayer::IntersectBBox(const caffe::NormalizedBBox& bbox1,
+                                         const caffe::NormalizedBBox& bbox2,
+                                         caffe::NormalizedBBox* intersect_bbox) {
+    if (bbox2.xmin() > bbox1.xmax() || bbox2.xmax() < bbox1.xmin() ||
+        bbox2.ymin() > bbox1.ymax() || bbox2.ymax() < bbox1.ymin())
+    {
+        // Return [0, 0, 0, 0] if there is no intersection.
+        intersect_bbox->set_xmin(0);
+        intersect_bbox->set_ymin(0);
+        intersect_bbox->set_xmax(0);
+        intersect_bbox->set_ymax(0);
+    }
+    else
+    {
+        intersect_bbox->set_xmin(std::max(bbox1.xmin(), bbox2.xmin()));
+        intersect_bbox->set_ymin(std::max(bbox1.ymin(), bbox2.ymin()));
+        intersect_bbox->set_xmax(std::min(bbox1.xmax(), bbox2.xmax()));
+        intersect_bbox->set_ymax(std::min(bbox1.ymax(), bbox2.ymax()));
+    }
+}
+
+float DetectionOutputLayer::JaccardOverlap(const caffe::NormalizedBBox& bbox1,
+                                           const caffe::NormalizedBBox& bbox2,
+                                           const bool normalized) {
+    caffe::NormalizedBBox intersect_bbox;
+    IntersectBBox(bbox1, bbox2, &intersect_bbox);
+    float intersect_width, intersect_height;
+    if (normalized)
+    {
+        intersect_width = intersect_bbox.xmax() - intersect_bbox.xmin();
+        intersect_height = intersect_bbox.ymax() - intersect_bbox.ymin();
+    }
+    else
+    {
+        intersect_width = intersect_bbox.xmax() - intersect_bbox.xmin() + 1;
+        intersect_height = intersect_bbox.ymax() - intersect_bbox.ymin() + 1;
+    }
+    if (intersect_width > 0 && intersect_height > 0)
+    {
+        float intersect_size = intersect_width * intersect_height;
+        float bbox1_size = BBoxSize(bbox1);
+        float bbox2_size = BBoxSize(bbox2);
+        return intersect_size / (bbox1_size + bbox2_size - intersect_size);
+    }
+    else
+    {
+        return 0.;
+    }
+}
+
+}
+}
diff --git a/contrib/modules/dnn/src/layers/detection_output_layer.hpp b/contrib/modules/dnn/src/layers/detection_output_layer.hpp
new file mode 100644
index 0000000..0b28d69
--- /dev/null
+++ b/contrib/modules/dnn/src/layers/detection_output_layer.hpp
@@ -0,0 +1,226 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+//  By downloading, copying, installing or using the software you agree to this license.
+//  If you do not agree to this license, do not download, install,
+//  copy or use the software.
+//
+//
+//                           License Agreement
+//                For Open Source Computer Vision Library
+//
+// Copyright (C) 2013, OpenCV Foundation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+//   * Redistribution's of source code must retain the above copyright notice,
+//     this list of conditions and the following disclaimer.
+//
+//   * Redistribution's in binary form must reproduce the above copyright notice,
+//     this list of conditions and the following disclaimer in the documentation
+//     and/or other materials provided with the distribution.
+//
+//   * The name of the copyright holders may not be used to endorse or promote products
+//     derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#ifndef __OPENCV_DNN_LAYERS_DETECTION_OUTPUT_LAYER_HPP__
+#define __OPENCV_DNN_LAYERS_DETECTION_OUTPUT_LAYER_HPP__
+
+#include "../precomp.hpp"
+#include "caffe.pb.h"
+
+namespace cv
+{
+namespace dnn
+{
+class DetectionOutputLayer : public Layer
+{
+    unsigned _numClasses;
+    bool _shareLocation;
+    int _numLocClasses;
+
+    int _backgroundLabelId;
+
+    typedef caffe::PriorBoxParameter_CodeType CodeType;
+    CodeType _codeType;
+
+    bool _varianceEncodedInTarget;
+    int _keepTopK;
+    float _confidenceThreshold;
+
+    int _num;
+    int _numPriors;
+
+    float _nmsThreshold;
+    int _topK;
+
+    static const size_t _numAxes = 4;
+    static const std::string _layerName;
+
+public:
+    DetectionOutputLayer(LayerParams &params);
+    void allocate(const std::vector<Blob*> &inputs, std::vector<Blob> &outputs);
+    void forward(std::vector<Blob*> &inputs, std::vector<Blob> &outputs);
+
+    void checkInputs(const std::vector<Blob*> &inputs);
+    void getCodeType(LayerParams &params);
+
+    template<typename T>
+    T getParameter(const LayerParams &params,
+                   const std::string &parameterName,
+                   const size_t &idx = 0,
+                   const bool required = true,
+                   const T& defaultValue = T());
+
+    bool getParameterDict(const LayerParams &params,
+                          const std::string &parameterName,
+                          DictValue& result);
+
+    typedef std::map<int, std::vector<caffe::NormalizedBBox> > LabelBBox;
+
+    // Clip the caffe::NormalizedBBox such that the range for each corner is [0, 1].
+    void ClipBBox(const caffe::NormalizedBBox& bbox, caffe::NormalizedBBox* clip_bbox);
+
+    // Decode a bbox according to a prior bbox.
+    void DecodeBBox(const caffe::NormalizedBBox& prior_bbox,
+                    const std::vector<float>& prior_variance, const CodeType code_type,
+                    const bool variance_encoded_in_target, const caffe::NormalizedBBox& bbox,
+                    caffe::NormalizedBBox* decode_bbox);
+
+    // Decode a set of bboxes according to a set of prior bboxes.
+    void DecodeBBoxes(const std::vector<caffe::NormalizedBBox>& prior_bboxes,
+                      const std::vector<std::vector<float> >& prior_variances,
+                      const CodeType code_type, const bool variance_encoded_in_target,
+                      const std::vector<caffe::NormalizedBBox>& bboxes,
+                      std::vector<caffe::NormalizedBBox>* decode_bboxes);
+
+    // Decode all bboxes in a batch.
+    void DecodeBBoxesAll(const std::vector<LabelBBox>& all_loc_pred,
+                         const std::vector<caffe::NormalizedBBox>& prior_bboxes,
+                         const std::vector<std::vector<float> >& prior_variances,
+                         const size_t num, const bool share_location,
+                         const int num_loc_classes, const int background_label_id,
+                         const CodeType code_type, const bool variance_encoded_in_target,
+                         std::vector<LabelBBox>* all_decode_bboxes);
+
+    // Get prior bounding boxes from prior_data.
+    //    prior_data: 1 x 2 x num_priors * 4 x 1 blob.
+    //    num_priors: number of priors.
+    //    prior_bboxes: stores all the prior bboxes in the format of caffe::NormalizedBBox.
+    //    prior_variances: stores all the variances needed by prior bboxes.
+    void GetPriorBBoxes(const float* priorData, const int& numPriors,
+                        std::vector<caffe::NormalizedBBox>* priorBBoxes,
+                        std::vector<std::vector<float> >* priorVariances);
+
+    // Scale the caffe::NormalizedBBox w.r.t. height and width.
+    void ScaleBBox(const caffe::NormalizedBBox& bbox, const int height, const int width,
+                   caffe::NormalizedBBox* scale_bbox);
+
+    // Do non maximum suppression given bboxes and scores.
+    // Inspired by Piotr Dollar's NMS implementation in EdgeBox.
+    // https://goo.gl/jV3JYS
+    //    bboxes: a set of bounding boxes.
+    //    scores: a set of corresponding confidences.
+    //    score_threshold: a threshold used to filter detection results.
+    //    nms_threshold: a threshold used in non maximum suppression.
+    //    top_k: if not -1, keep at most top_k picked indices.
+    //    indices: the kept indices of bboxes after nms.
+    void ApplyNMSFast(const std::vector<caffe::NormalizedBBox>& bboxes,
+                      const std::vector<float>& scores, const float score_threshold,
+                      const float nms_threshold, const int top_k, std::vector<int>* indices);
+
+
+    // Do non maximum suppression given bboxes and scores.
+    //    bboxes: a set of bounding boxes.
+    //    scores: a set of corresponding confidences.
+    //    threshold: the threshold used in non maximu suppression.
+    //    top_k: if not -1, keep at most top_k picked indices.
+    //    reuse_overlaps: if true, use and update overlaps; otherwise, always
+    //      compute overlap.
+    //    overlaps: a temp place to optionally store the overlaps between pairs of
+    //      bboxes if reuse_overlaps is true.
+    //    indices: the kept indices of bboxes after nms.
+    void ApplyNMS(const std::vector<caffe::NormalizedBBox>& bboxes,
+                  const std::vector<float>& scores,
+                  const float threshold, const int top_k, const bool reuse_overlaps,
+                  std::map<int, std::map<int, float> >* overlaps, std::vector<int>* indices);
+
+    void ApplyNMS(const bool* overlapped, const int num, std::vector<int>* indices);
+
+    // Get confidence predictions from conf_data.
+    //    conf_data: num x num_preds_per_class * num_classes blob.
+    //    num: the number of images.
+    //    num_preds_per_class: number of predictions per class.
+    //    num_classes: number of classes.
+    //    conf_preds: stores the confidence prediction, where each item contains
+    //      confidence prediction for an image.
+    void GetConfidenceScores(const float* conf_data, const int num,
+                             const int num_preds_per_class, const int num_classes,
+                             std::vector<std::map<int, std::vector<float> > >* conf_scores);
+
+    // Get confidence predictions from conf_data.
+    //    conf_data: num x num_preds_per_class * num_classes blob.
+    //    num: the number of images.
+    //    num_preds_per_class: number of predictions per class.
+    //    num_classes: number of classes.
+    //    class_major: if true, data layout is
+    //      num x num_classes x num_preds_per_class; otherwise, data layerout is
+    //      num x num_preds_per_class * num_classes.
+    //    conf_preds: stores the confidence prediction, where each item contains
+    //      confidence prediction for an image.
+    void GetConfidenceScores(const float* conf_data, const int num,
+                             const int num_preds_per_class, const int num_classes,
+                             const bool class_major,
+                             std::vector<std::map<int, std::vector<float> > >* conf_scores);
+
+    // Get location predictions from loc_data.
+    //    loc_data: num x num_preds_per_class * num_loc_classes * 4 blob.
+    //    num: the number of images.
+    //    num_preds_per_class: number of predictions per class.
+    //    num_loc_classes: number of location classes. It is 1 if share_location is
+    //      true; and is equal to number of classes needed to predict otherwise.
+    //    share_location: if true, all classes share the same location prediction.
+    //    loc_preds: stores the location prediction, where each item contains
+    //      location prediction for an image.
+    void GetLocPredictions(const float* loc_data, const int num,
+                           const int num_preds_per_class, const int num_loc_classes,
+                           const bool share_location, std::vector<LabelBBox>* loc_preds);
+
+    // Get max scores with corresponding indices.
+    //    scores: a set of scores.
+    //    threshold: only consider scores higher than the threshold.
+    //    top_k: if -1, keep all; otherwise, keep at most top_k.
+    //    score_index_vec: store the sorted (score, index) pair.
+    void GetMaxScoreIndex(const std::vector<float>& scores, const float threshold,
+                          const int top_k, std::vector<std::pair<float, int> >* score_index_vec);
+
+    // Compute the jaccard (intersection over union IoU) overlap between two bboxes.
+    float JaccardOverlap(const caffe::NormalizedBBox& bbox1, const caffe::NormalizedBBox& bbox2,
+                         const bool normalized = true);
+
+    // Compute the intersection between two bboxes.
+    void IntersectBBox(const caffe::NormalizedBBox& bbox1, const caffe::NormalizedBBox& bbox2,
+                       caffe::NormalizedBBox* intersect_bbox);
+
+    // Compute bbox size.
+    float BBoxSize(const caffe::NormalizedBBox& bbox, const bool normalized = true);
+};
+}
+}
+#endif
diff --git a/contrib/modules/dnn/src/layers/elementwise_layers.cpp b/contrib/modules/dnn/src/layers/elementwise_layers.cpp
new file mode 100644
index 0000000..6ed7558
--- /dev/null
+++ b/contrib/modules/dnn/src/layers/elementwise_layers.cpp
@@ -0,0 +1,46 @@
+#include "../precomp.hpp"
+#include "elementwise_layers.hpp"
+
+namespace cv
+{
+namespace dnn
+{
+
+#define ACTIVATION_CREATOR_FOR(_Layer, _Functor, ...) \
+Ptr<_Layer> _Layer::create() { \
+    return return Ptr<_Layer>( new ElementWiseLayer<_Functor>(_Functor()) ); }
+
+
+Ptr<ReLULayer> ReLULayer::create(double negativeSlope)
+{
+    return Ptr<ReLULayer>(new ElementWiseLayer<ReLUFunctor>(ReLUFunctor(negativeSlope)));
+}
+
+Ptr<TanHLayer> TanHLayer::create()
+{
+    return Ptr<TanHLayer>(new ElementWiseLayer<TanHFunctor>());
+}
+
+Ptr<SigmoidLayer> SigmoidLayer::create()
+{
+    return Ptr<SigmoidLayer>(new ElementWiseLayer<SigmoidFunctor>());
+}
+
+Ptr<AbsLayer> AbsLayer::create()
+{
+    return Ptr<AbsLayer>(new ElementWiseLayer<AbsValFunctor>());
+}
+
+Ptr<BNLLLayer> BNLLLayer::create()
+{
+    return Ptr<BNLLLayer>(new ElementWiseLayer<BNLLFunctor>());
+}
+
+Ptr<PowerLayer> PowerLayer::create(double power /*= 1*/, double scale /*= 1*/, double shift /*= 0*/)
+{
+    const PowerFunctor f(power, scale, shift);
+    return Ptr<PowerLayer>(new ElementWiseLayer<PowerFunctor>(f));
+}
+
+}
+}
\ No newline at end of file
diff --git a/contrib/modules/dnn/src/layers/elementwise_layers.hpp b/contrib/modules/dnn/src/layers/elementwise_layers.hpp
index e660661..2f67f0a 100644
--- a/contrib/modules/dnn/src/layers/elementwise_layers.hpp
+++ b/contrib/modules/dnn/src/layers/elementwise_layers.hpp
@@ -44,6 +44,11 @@
 #include "../precomp.hpp"
 #include "layers_common.hpp"
 #include <cmath>
+#include <opencv2/dnn/all_layers.hpp>
+#include <opencv2/core/ocl.hpp>
+#ifdef HAVE_OPENCL
+#include "modules/dnn/opencl_kernels_dnn.hpp"
+#endif
 
 namespace cv
 {
@@ -55,130 +60,259 @@ using std::exp;
 using std::tanh;
 using std::pow;
 
-    template<typename Func>
-    class ElementWiseLayer : public Layer
+template<typename Func>
+class ElementWiseLayer : public Func::Layer
+{
+    bool useOpenCL;
+    Func func;
+
+    template<typename Dtype>
+    class PBody : public cv::ParallelLoopBody
     {
-        Func func;
+        Func &func;
+        Dtype *data;
     public:
 
-        ElementWiseLayer(LayerParams &_params) : func(_params) {}
-
-        void allocate(const std::vector<Blob*> &inputs, std::vector<Blob> &outputs)
-        {
-            outputs.resize(inputs.size());
-            for (size_t i = 0; i < inputs.size(); i++)
-                outputs[i].shareFrom(*inputs[i]); //no data copy
-        }
+        PBody(Mat &mat, Func &func_) :
+            func(func_), data(mat.ptr<Dtype>())
+        {}
 
-        void forward(std::vector<Blob*> &inputs, std::vector<Blob> &outputs)
+        void operator()(const Range &r) const
         {
-            for (size_t i = 0; i < inputs.size(); i++)
-            {
-                CV_Assert(inputs[i]->ptr() == outputs[i].ptr() && inputs[i]->type() == outputs[i].type());
-
-                size_t size = outputs[i].total();
-
-                if (outputs[i].type() == CV_32F)
-                {
-                    float *data = outputs[i].ptrf();
-                    for (size_t j = 0; j < size; j++)
-                        data[j] = func(data[j]);
-                }
-                else if (outputs[i].type() == CV_64F)
-                {
-                    double *data = outputs[i].ptr<double>();
-                    for (size_t j = 0; j < size; j++)
-                        data[j] = func(data[j]);
-                }
-                else
-                {
-                    CV_Error(Error::StsNotImplemented, "Only CV_32F and CV_64F blobs are supported");
-                }
-            }
+            for (int i = r.start; i < r.end; i++)
+                data[i] = func(data[i]);
         }
     };
 
+public:
 
-    struct ReLUFunctor
+    ElementWiseLayer() {}
+    ElementWiseLayer(const Func &f) : func(f) {}
+
+    void allocate(const std::vector<Blob*> &inputs, std::vector<Blob> &outputs)
     {
-        float negative_slope;
+        useOpenCL = ocl::useOpenCL();
 
-        ReLUFunctor(LayerParams &params)
+        outputs.resize(inputs.size());
+        for (size_t i = 0; i < inputs.size(); i++)
         {
-            if (params.has("negative_slope"))
-                negative_slope = params.get<float>("negative_slope");
+            outputs[i].shareFrom(*inputs[i]); //no data copy
+
+            //hotfix: shareFrom doesn't provide properly Mat/UMat switching
+            if (useOpenCL)
+                outputs[i].umatRef() = inputs[i]->umatRefConst();
             else
-                negative_slope = 0.f;
+                outputs[i].matRef() = inputs[i]->matRefConst();
         }
+    }
 
-        template<typename TFloat>
-        inline TFloat operator()(TFloat x)
-        {
-            return (x >= (TFloat)0) ? x : negative_slope * x;
-        }
-    };
+    void forward(std::vector<Blob*> &inputs, std::vector<Blob> &outputs)
+    {
+        #ifdef HAVE_OPENCL
+        if (useOpenCL)
+            forwardOCL(inputs, outputs);
+        else
+        #endif
+            forwardCPU(inputs, outputs);
+    }
 
-    struct TanHFunctor
+    #ifdef HAVE_OPENCL
+    void forwardOCL(std::vector<Blob*> &inputs, std::vector<Blob> &outputs)
     {
-        TanHFunctor(LayerParams&) {}
+        size_t wgSize = ocl::Device::getDefault().maxWorkGroupSize();
 
-        template<typename TFloat>
-        inline TFloat operator()(TFloat x)
+        for (size_t i = 0; i < inputs.size(); i++)
         {
-            return tanh(x);
+            const UMat &src = inputs[i]->umatRefConst();
+            UMat &dst = outputs[i].umatRef();
+            CV_Assert(src.isContinuous() && dst.isContinuous() && !src.offset && !dst.offset);
+
+            ocl::Kernel ker;
+            CV_Assert(func.initKernel(ker, src));
+            ker.set(0, (int)src.total());
+            ker.set(1, ocl::KernelArg::PtrReadOnly(src));
+            ker.set(2, ocl::KernelArg::PtrWriteOnly(dst));
+
+            size_t gSize = src.total();
+            CV_Assert(ker.run(1, &gSize, &wgSize, true));
         }
-    };
+    }
+    #endif
 
-    struct SigmoidFunctor
+    void forwardCPU(std::vector<Blob*> &inputs, std::vector<Blob> &outputs)
     {
-        SigmoidFunctor(LayerParams&) {}
-
-        template<typename TFloat>
-        inline TFloat operator()(TFloat x)
+        for (size_t i = 0; i < inputs.size(); i++)
         {
-            return (TFloat)1 / ((TFloat)1 + exp(-x));
+            const Mat &src = inputs[i]->matRefConst();
+            Mat &dst = outputs[i].matRef();
+            CV_Assert(src.ptr() == dst.ptr() && src.isContinuous());
+
+            Range sizeRange = Range(0, dst.total());
+            if (dst.type() == CV_32F)
+            {
+                cv::parallel_for_(sizeRange, PBody<float>(dst, func));
+            }
+            else if (dst.type() == CV_64F)
+            {
+                cv::parallel_for_(sizeRange, PBody<double>(dst, func));
+            }
+            else
+            {
+                CV_Error(Error::StsNotImplemented, "Only CV_32F and CV_64F blobs are supported");
+            }
         }
-    };
+    }
+};
 
-    struct AbsValFunctor
+#ifdef HAVE_OPENCL
+static String oclGetTMacro(const UMat &m)
+{
+    return String("-DT=") + ocl::typeToStr(m.type()) + String(" ");
+}
+#endif
+
+struct ReLUFunctor
+{
+    typedef ReLULayer Layer;
+
+    double slope;
+
+    ReLUFunctor(double slope_)
+        : slope(slope_) {}
+
+    template<typename TFloat>
+    inline TFloat operator()(TFloat x) const
     {
-        AbsValFunctor(LayerParams&) {}
+        return (x >= (TFloat)0) ? x : (TFloat)slope * x;
+    }
 
-        template<typename TFloat>
-        inline TFloat operator()(TFloat x)
-        {
-            return abs(x);
-        }
-    };
+    #ifdef HAVE_OPENCL
+    bool initKernel(ocl::Kernel &ker, const UMat &src) const
+    {
+        const char *buildoptSlope = (slope == 0) ? "-DRELU_NO_SLOPE" : "";
+        String buildopt = oclGetTMacro(src) + buildoptSlope;
 
-    struct PowerFunctor
+        if (!ker.create("ReLUForward", ocl::dnn::activations_oclsrc, buildopt))
+            return false;
+
+        if (slope != 0)
+            ker.set(3, (float)slope);
+
+        return true;
+    }
+    #endif
+};
+
+struct TanHFunctor
+{
+    typedef TanHLayer Layer;
+
+    template<typename TFloat>
+    inline TFloat operator()(TFloat x) const
     {
-        float power, scale, shift;
+        return tanh(x);
+    }
 
-        PowerFunctor(LayerParams &params)
-        {
-            power = params.get<float>("power", 1.0f);
-            scale = params.get<float>("scale", 1.0f);
-            shift = params.get<float>("shift", 0.0f);
-        }
+    #ifdef HAVE_OPENCL
+    bool initKernel(ocl::Kernel &ker, const UMat &src) const
+    {
+        if (!ker.create("TanHForward", ocl::dnn::activations_oclsrc, oclGetTMacro(src)))
+            return false;
+        return true;
+    }
+    #endif
+};
 
-        template<typename TFloat>
-        inline TFloat operator()(TFloat x)
-        {
-            return pow((TFloat)shift + (TFloat)scale * x, (TFloat)power);
-        }
-    };
+struct SigmoidFunctor
+{
+    typedef SigmoidLayer Layer;
 
-    struct BNLLFunctor
+    template<typename TFloat>
+    inline TFloat operator()(TFloat x) const
     {
-        BNLLFunctor(LayerParams&) {}
+        return (TFloat)1 / ((TFloat)1 + exp(-x));
+    }
+
+    #ifdef HAVE_OPENCL
+    bool initKernel(ocl::Kernel &ker, const UMat &src) const
+    {
+        if (!ker.create("SigmoidForward", ocl::dnn::activations_oclsrc, oclGetTMacro(src)))
+            return false;
+        return true;
+    }
+    #endif
+};
+
+struct AbsValFunctor
+{
+    typedef AbsLayer Layer;
+
+    template<typename TFloat>
+    inline TFloat operator()(TFloat x) const
+    {
+        return abs(x);
+    }
+
+    #ifdef HAVE_OPENCL
+    bool initKernel(ocl::Kernel &ker, const UMat &src) const
+    {
+        if (!ker.create("AbsValForward", ocl::dnn::activations_oclsrc, oclGetTMacro(src)))
+            return false;
+        return true;
+    }
+    #endif
+};
+
+struct BNLLFunctor
+{
+    typedef BNLLLayer Layer;
+
+    template<typename TFloat>
+    inline TFloat operator()(TFloat x) const
+    {
+        return log((TFloat)1 + exp(-abs(x)));
+    }
+
+    #ifdef HAVE_OPENCL
+    bool initKernel(ocl::Kernel &ker, const UMat &src) const
+    {
+        if (!ker.create("BNLLForward", ocl::dnn::activations_oclsrc, oclGetTMacro(src)))
+            return false;
+        return true;
+    }
+    #endif
+};
+
+struct PowerFunctor
+{
+    typedef PowerLayer Layer;
+
+    double power, scale, shift;
+
+    PowerFunctor(double power_, double scale_ = 1, double shift_ = 0)
+        : power(power_), scale(scale_), shift(shift_) {}
+
+    template<typename TFloat>
+    inline TFloat operator()(TFloat x) const
+    {
+        return pow((TFloat)shift + (TFloat)scale * x, (TFloat)power);
+    }
+
+    #ifdef HAVE_OPENCL
+    bool initKernel(ocl::Kernel &ker, const UMat &src) const
+    {
+        if (!ker.create("PowForward", ocl::dnn::activations_oclsrc, oclGetTMacro(src)))
+            return false;
+
+        ker.set(3, (float)power);
+        ker.set(4, (float)scale);
+        ker.set(5, (float)shift);
+
+        return true;
+    }
+    #endif
+};
 
-        template<typename TFloat>
-        inline TFloat operator()(TFloat x)
-        {
-            return log((TFloat)1 + exp(-abs(x)));
-        }
-    };
 }
 }
 #endif
diff --git a/contrib/modules/dnn/src/layers/eltwise_layer.cpp b/contrib/modules/dnn/src/layers/eltwise_layer.cpp
new file mode 100755
index 0000000..ecd09e7
--- /dev/null
+++ b/contrib/modules/dnn/src/layers/eltwise_layer.cpp
@@ -0,0 +1,127 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+//  By downloading, copying, installing or using the software you agree to this license.
+//  If you do not agree to this license, do not download, install,
+//  copy or use the software.
+//
+//
+//                           License Agreement
+//                For Open Source Computer Vision Library
+//
+// Copyright (C) 2013, OpenCV Foundation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+//   * Redistribution's of source code must retain the above copyright notice,
+//     this list of conditions and the following disclaimer.
+//
+//   * Redistribution's in binary form must reproduce the above copyright notice,
+//     this list of conditions and the following disclaimer in the documentation
+//     and/or other materials provided with the distribution.
+//
+//   * The name of the copyright holders may not be used to endorse or promote products
+//     derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "../precomp.hpp"
+#include "layers_common.hpp"
+#include "eltwise_layer.hpp"
+
+namespace cv
+{
+namespace dnn
+{
+    EltwiseLayerImpl::EltwiseLayerImpl(EltwiseOp op_, const std::vector<int> &coeffs_)
+    {
+        op = op_;
+        coeffs = coeffs_;
+    }
+
+    void EltwiseLayerImpl::allocate(const std::vector<Blob *> &inputs, std::vector<Blob> &outputs)
+    {
+        CV_Assert(2 <= inputs.size());
+        CV_Assert(coeffs.size() == 0 || coeffs.size() == inputs.size());
+        CV_Assert(op == SUM || coeffs.size() == 0);
+
+        const BlobShape &shape0 = inputs[0]->shape();
+        for (size_t i = 1; i < inputs.size(); ++i)
+        {
+            CV_Assert(shape0 == inputs[i]->shape());
+        }
+        outputs.resize(1);
+        outputs[0].create(shape0);
+    }
+
+    void EltwiseLayerImpl::forward(std::vector<Blob *> &inputs, std::vector<Blob> &outputs)
+    {
+        switch (op)
+        {
+        case SUM:
+            {
+                CV_Assert(coeffs.size() == 0 || coeffs.size() == inputs.size());
+                Mat& output = outputs[0].matRef();
+                output.setTo(0.);
+                if (0 < coeffs.size())
+                {
+                    for (size_t i = 0; i < inputs.size(); i++)
+                    {
+                        output += inputs[i]->matRefConst() * coeffs[i];
+                    }
+                }
+                else
+                {
+                    for (size_t i = 0; i < inputs.size(); i++)
+                    {
+                        output += inputs[i]->matRefConst();
+                    }
+                }
+            }
+            break;
+        case PROD:
+            {
+                Mat& output = outputs[0].matRef();
+                output.setTo(1.);
+                for (size_t i = 0; i < inputs.size(); i++)
+                {
+                    output = output.mul(inputs[i]->matRefConst());
+                }
+            }
+            break;
+        case MAX:
+            {
+                Mat& output = outputs[0].matRef();
+                cv::max(inputs[0]->matRefConst(), inputs[1]->matRefConst(), output);
+                for (size_t i = 2; i < inputs.size(); i++)
+                {
+                    cv::max(output, inputs[i]->matRefConst(), output);
+                }
+            }
+            break;
+        default:
+            CV_Assert(0);
+            break;
+        };
+    }
+
+    Ptr<EltwiseLayer> EltwiseLayer::create(EltwiseOp op, const std::vector<int> &coeffs)
+    {
+        return Ptr<EltwiseLayer>(new EltwiseLayerImpl(op, coeffs));
+    }
+}
+}
diff --git a/contrib/modules/dnn/src/layers/eltwise_layer.hpp b/contrib/modules/dnn/src/layers/eltwise_layer.hpp
new file mode 100755
index 0000000..c67575c
--- /dev/null
+++ b/contrib/modules/dnn/src/layers/eltwise_layer.hpp
@@ -0,0 +1,62 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+//  By downloading, copying, installing or using the software you agree to this license.
+//  If you do not agree to this license, do not download, install,
+//  copy or use the software.
+//
+//
+//                           License Agreement
+//                For Open Source Computer Vision Library
+//
+// Copyright (C) 2013, OpenCV Foundation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+//   * Redistribution's of source code must retain the above copyright notice,
+//     this list of conditions and the following disclaimer.
+//
+//   * Redistribution's in binary form must reproduce the above copyright notice,
+//     this list of conditions and the following disclaimer in the documentation
+//     and/or other materials provided with the distribution.
+//
+//   * The name of the copyright holders may not be used to endorse or promote products
+//     derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#ifndef __OPENCV_DNN_LAYERS_ELTWISE_LAYER_HPP__
+#define __OPENCV_DNN_LAYERS_ELTWISE_LAYER_HPP__
+#include "../precomp.hpp"
+#include <opencv2/dnn/all_layers.hpp>
+
+namespace cv
+{
+namespace dnn
+{
+    class EltwiseLayerImpl : public EltwiseLayer
+    {
+        EltwiseOp op;
+        std::vector<int> coeffs;
+    public:
+        EltwiseLayerImpl(EltwiseOp op, const std::vector<int> &coeffs);
+        void allocate(const std::vector<Blob*> &inputs, std::vector<Blob> &outputs);
+        void forward(std::vector<Blob*> &inputs, std::vector<Blob> &outputs);
+    };
+}
+}
+#endif
diff --git a/contrib/modules/dnn/src/layers/flatten_layer.cpp b/contrib/modules/dnn/src/layers/flatten_layer.cpp
new file mode 100644
index 0000000..dc80703
--- /dev/null
+++ b/contrib/modules/dnn/src/layers/flatten_layer.cpp
@@ -0,0 +1,117 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+//  By downloading, copying, installing or using the software you agree to this license.
+//  If you do not agree to this license, do not download, install,
+//  copy or use the software.
+//
+//
+//                           License Agreement
+//                For Open Source Computer Vision Library
+//
+// Copyright (C) 2013, OpenCV Foundation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+//   * Redistribution's of source code must retain the above copyright notice,
+//     this list of conditions and the following disclaimer.
+//
+//   * Redistribution's in binary form must reproduce the above copyright notice,
+//     this list of conditions and the following disclaimer in the documentation
+//     and/or other materials provided with the distribution.
+//
+//   * The name of the copyright holders may not be used to endorse or promote products
+//     derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "../precomp.hpp"
+#include "layers_common.hpp"
+#include "flatten_layer.hpp"
+#include <float.h>
+#include <algorithm>
+
+namespace cv
+{
+namespace dnn
+{
+
+FlattenLayer::FlattenLayer(LayerParams &params) : Layer(params)
+{
+    _startAxis = params.get<int>("axis", 1);
+    _endAxis = params.get<int>("end_axis", -1);
+}
+
+void FlattenLayer::checkInputs(const std::vector<Blob*> &inputs)
+{
+    CV_Assert(inputs.size() > 0);
+    for (size_t i = 1; i < inputs.size(); i++)
+    {
+        for (size_t j = 0; j < _numAxes; j++)
+        {
+            CV_Assert(inputs[i]->shape()[j] == inputs[0]->shape()[j]);
+        }
+    }
+}
+
+void FlattenLayer::allocate(const std::vector<Blob*> &inputs, std::vector<Blob> &outputs)
+{
+    checkInputs(inputs);
+
+    _numAxes = inputs[0]->dims();
+    _endAxis = inputs[0]->canonicalAxis(_endAxis);
+    CV_Assert(_startAxis >= 0);
+    CV_Assert(_endAxis >= _startAxis && _endAxis < (int)_numAxes);
+
+    size_t flattenedDimensionSize = 1;
+    for (int i = _startAxis; i <= _endAxis; i++)
+    {
+        flattenedDimensionSize *= inputs[0]->size(i);
+    }
+
+    std::vector<int> outputShapeVec;
+    for (int i = 0; i < _startAxis; i++)
+    {
+        outputShapeVec.push_back(inputs[0]->size(i));
+    }
+    outputShapeVec.push_back(flattenedDimensionSize);
+    for (size_t i = _endAxis + 1; i < _numAxes; i++)
+    {
+        outputShapeVec.push_back(inputs[0]->size(i));
+    }
+    CV_Assert(outputShapeVec.size() <= 4);
+
+    resultShape = BlobShape(outputShapeVec);
+
+    for (size_t i = 0; i < inputs.size(); i++)
+    {
+        //in-place
+        outputs[i].shareFrom(*inputs[i]);
+        outputs[i].reshape(resultShape);
+    }
+}
+
+void FlattenLayer::forward(std::vector<Blob*> &inputs, std::vector<Blob> &outputs)
+{
+    for (size_t j = 0; j < inputs.size(); j++)
+    {
+        outputs[j].shareFrom(*inputs[j]);
+        outputs[j].reshape(resultShape);
+    }
+}
+}
+}
diff --git a/contrib/modules/dnn/src/layers/flatten_layer.hpp b/contrib/modules/dnn/src/layers/flatten_layer.hpp
new file mode 100644
index 0000000..1aab0eb
--- /dev/null
+++ b/contrib/modules/dnn/src/layers/flatten_layer.hpp
@@ -0,0 +1,67 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+//  By downloading, copying, installing or using the software you agree to this license.
+//  If you do not agree to this license, do not download, install,
+//  copy or use the software.
+//
+//
+//                           License Agreement
+//                For Open Source Computer Vision Library
+//
+// Copyright (C) 2013, OpenCV Foundation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+//   * Redistribution's of source code must retain the above copyright notice,
+//     this list of conditions and the following disclaimer.
+//
+//   * Redistribution's in binary form must reproduce the above copyright notice,
+//     this list of conditions and the following disclaimer in the documentation
+//     and/or other materials provided with the distribution.
+//
+//   * The name of the copyright holders may not be used to endorse or promote products
+//     derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#ifndef __OPENCV_DNN_LAYERS_FLATTEN_LAYER_HPP__
+#define __OPENCV_DNN_LAYERS_FLATTEN_LAYER_HPP__
+#include "../precomp.hpp"
+
+namespace cv
+{
+namespace dnn
+{
+class FlattenLayer : public Layer
+{
+    int _startAxis;
+    int _endAxis;
+    size_t _numAxes;
+
+    BlobShape resultShape;
+
+public:
+    FlattenLayer(LayerParams &params);
+    void allocate(const std::vector<Blob*> &inputs, std::vector<Blob> &outputs);
+    void forward(std::vector<Blob*> &inputs, std::vector<Blob> &outputs);
+
+    void checkInputs(const std::vector<Blob*> &inputs);
+};
+}
+}
+#endif
diff --git a/contrib/modules/dnn/src/layers/fully_connected_layer.cpp b/contrib/modules/dnn/src/layers/fully_connected_layer.cpp
index 848080b..bb58027 100644
--- a/contrib/modules/dnn/src/layers/fully_connected_layer.cpp
+++ b/contrib/modules/dnn/src/layers/fully_connected_layer.cpp
@@ -42,73 +42,88 @@
 #include "../precomp.hpp"
 #include "layers_common.hpp"
 #include "fully_connected_layer.hpp"
+#include "op_blas.hpp"
+#include <opencv2/dnn/shape_utils.hpp>
+#include <opencv2/core/ocl.hpp>
 
 namespace cv
 {
 namespace dnn
 {
-    FullyConnectedLayer::FullyConnectedLayer(LayerParams &params) : Layer(params)
-    {
-        numOutputs = params.get<int>("num_output");
-        bias = params.get<bool>("bias_term", true);
-        axis_ = params.get<int>("axis", 1);
 
-        CV_Assert(blobs.size() == (bias ? 2U : 1U));
-        CV_Assert(blobs[0].dims() >= 2 && blobs[0].total() >= (size_t)numOutputs);
-        CV_Assert(!bias || blobs[1].total() == (size_t)numOutputs);
-    }
+FullyConnectedLayerImpl::FullyConnectedLayerImpl(int axis_)
+{
+    axis = axis_;
+}
 
-    void FullyConnectedLayer::allocate(const std::vector<Blob*> &input, std::vector<Blob> &output)
-    {
-        CV_Assert(input.size() > 0);
+void FullyConnectedLayerImpl::allocate(const std::vector<Blob*> &input, std::vector<Blob> &output)
+{
+    CV_Assert(input.size() > 0);
+    CV_Assert(1 <= blobs.size() && blobs.size() <= 2);
+    CV_Assert(blobs[0].dims() == 2);
 
-        axis = input[0]->canonicalAxis(axis_);
-        innerSize = (int)input[0]->total(axis);
+    bias = (blobs.size() >= 1);
+    axisCan = input[0]->canonicalAxis(axis);
+    dtype = input[0]->type();
+    numOutput = blobs[0].size(0);
+    innerSize = blobs[0].size(1);
+    outerSize = input[0]->total(0, axisCan);
 
-        CV_Assert((size_t)innerSize * (size_t)numOutputs == blobs[0].total());
-        CV_Assert(blobs[0].size(-2) == numOutputs && blobs[0].size(-1) == innerSize);
+    CV_Assert((size_t)innerSize == input[0]->total(axisCan));
+    CV_Assert(!bias || (size_t)numOutput == blobs[1].total());
 
-        output.resize(input.size());
-        for (size_t i = 0; i < input.size(); i++)
-        {
-            if (i != 0)
-                CV_Assert(input[i]->equalShape(*input[0]));
+    useOpenCL = ocl::useOpenCL();
+    int allocFlags = useOpenCL ? Blob::ALLOC_UMAT : Blob::ALLOC_UMAT;
 
-            this->reshape(*input[i], output[i]);
-        }
-    }
+    biasOnesBlob.create(Shape(outerSize, 1), dtype, allocFlags);
+    biasOnesBlob.setTo(1);
 
-    void FullyConnectedLayer::reshape(const Blob &inp, Blob &out)
+    output.resize(input.size());
+    for (size_t i = 0; i < input.size(); i++)
     {
-        BlobShape inpShape = inp.shape();
-        BlobShape outShape(axis+1, inpShape.ptr());
-        outShape[axis] = numOutputs;
+        CV_Assert(i == 0 || (input[i]->equalShape(*input[0]) && input[i]->type() == dtype));
+        Shape outShape = Shape(outerSize, numOutput);
+        output[i].create(outShape, dtype, allocFlags);
+    }
+}
 
-        out.create(outShape, inp.type());
+void FullyConnectedLayerImpl::forward(std::vector<Blob*> &input, std::vector<Blob> &output)
+{
+    #ifdef HAVE_OPENCL
+    if (useOpenCL)
+        forward_<UMat>(input, output);
+    else
+    #endif
+        forward_<Mat>(input, output);
+}
+
+template<typename XMat>
+void FullyConnectedLayerImpl::forward_(std::vector<Blob *> &input, std::vector<Blob> &output)
+{
+    const XMat &weight = blobs[0].getRefConst<XMat>();
+    const XMat *biasMat = NULL, *biasOnesMat = NULL;
+    if (bias)
+    {
+        biasOnesMat = &biasOnesBlob.getRefConst<XMat>();
+        biasMat = &blobs[1].getRefConst<XMat>();
     }
 
-    void FullyConnectedLayer::forward(std::vector<Blob*> &input, std::vector<Blob> &output)
+    for (size_t i = 0; i < input.size(); i++)
     {
-        for (size_t i = 0; i < input.size(); i++)
-        {
-            int M = (int)input[i]->total(0, axis);
-            int N = numOutputs;
-            int K = innerSize;
-
-            Mat srcMat(M, K, input[i]->type(), input[i]->ptrf());
-            Mat weight(N, K, blobs[0].type(), blobs[0].ptrf());
-            Mat dstMat(M, N, output[i].type(), output[i].ptrf());
-
-            //important: Caffe stores weights as transposed array
-            cv::gemm(srcMat, weight, 1, noArray(), 0, dstMat, GEMM_2_T);
-
-            if (bias)
-            {
-                Mat biasOnesMat = Mat::ones(M, 1, CV_32F);
-                Mat biasMat(1, N, CV_32F, blobs[1].ptrf());
-                cv::gemm(biasOnesMat, biasMat, 1, dstMat, 1, dstMat);
-            }
-        }
+        const XMat srcMat = reshaped(input[i]->getRefConst<XMat>(), Shape(outerSize, innerSize));
+        XMat dstMat = reshaped(output[i].getRef<XMat>(), Shape(outerSize, numOutput));
+        dnn::gemm(srcMat, weight, 1, dstMat, 0, GEMM_2_T);
+
+        if (bias)
+            dnn::gemm(*biasOnesMat, *biasMat, 1, dstMat, 1);
     }
 }
+
+
+Ptr<InnerProductLayer> InnerProductLayer::create(int axis)
+{
+    return Ptr<InnerProductLayer>(new FullyConnectedLayerImpl(axis));
+}
+
+}
 }
diff --git a/contrib/modules/dnn/src/layers/fully_connected_layer.hpp b/contrib/modules/dnn/src/layers/fully_connected_layer.hpp
index 5213b98..0cf5940 100644
--- a/contrib/modules/dnn/src/layers/fully_connected_layer.hpp
+++ b/contrib/modules/dnn/src/layers/fully_connected_layer.hpp
@@ -42,26 +42,30 @@
 #ifndef __OPENCV_DNN_LAYERS_FULLY_CONNECTED_LAYER_HPP__
 #define __OPENCV_DNN_LAYERS_FULLY_CONNECTED_LAYER_HPP__
 #include "../precomp.hpp"
+#include <opencv2/dnn/all_layers.hpp>
 
 namespace cv
 {
 namespace dnn
 {
-    class FullyConnectedLayer : public Layer
-    {
-        bool bias;
-        int numOutputs;
-        int axis_, axis;
 
-        int innerSize;
+class FullyConnectedLayerImpl : public InnerProductLayer
+{
+    int axisCan, dtype;
+    int numOutput, innerSize, outerSize;
+    bool bias, useOpenCL;
+    Blob biasOnesBlob;
+
+    template<typename XMat>
+    void forward_(std::vector<Blob*> &input, std::vector<Blob> &output);
+
+public:
 
-        void reshape(const Blob &inp, Blob &out);
+    FullyConnectedLayerImpl(int axisCan = 1);
+    void allocate(const std::vector<Blob*> &input, std::vector<Blob> &output);
+    void forward(std::vector<Blob*> &inputs, std::vector<Blob> &outputs);
+};
 
-    public:
-        FullyConnectedLayer(LayerParams &params);
-        void allocate(const std::vector<Blob*> &input, std::vector<Blob> &output);
-        void forward(std::vector<Blob*> &inputs, std::vector<Blob> &outputs);
-    };
 }
 }
 #endif
diff --git a/contrib/modules/dnn/src/layers/im2col.cpp b/contrib/modules/dnn/src/layers/im2col.cpp
deleted file mode 100644
index a4f9e76..0000000
--- a/contrib/modules/dnn/src/layers/im2col.cpp
+++ /dev/null
@@ -1,85 +0,0 @@
-/*M///////////////////////////////////////////////////////////////////////////////////////
-//
-//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
-//
-//  By downloading, copying, installing or using the software you agree to this license.
-//  If you do not agree to this license, do not download, install,
-//  copy or use the software.
-//
-//
-//                           License Agreement
-//                For Open Source Computer Vision Library
-//
-// Copyright (C) 2013, OpenCV Foundation, all rights reserved.
-// Third party copyrights are property of their respective owners.
-//
-// Redistribution and use in source and binary forms, with or without modification,
-// are permitted provided that the following conditions are met:
-//
-//   * Redistribution's of source code must retain the above copyright notice,
-//     this list of conditions and the following disclaimer.
-//
-//   * Redistribution's in binary form must reproduce the above copyright notice,
-//     this list of conditions and the following disclaimer in the documentation
-//     and/or other materials provided with the distribution.
-//
-//   * The name of the copyright holders may not be used to endorse or promote products
-//     derived from this software without specific prior written permission.
-//
-// This software is provided by the copyright holders and contributors "as is" and
-// any express or implied warranties, including, but not limited to, the implied
-// warranties of merchantability and fitness for a particular purpose are disclaimed.
-// In no event shall the Intel Corporation or contributors be liable for any direct,
-// indirect, incidental, special, exemplary, or consequential damages
-// (including, but not limited to, procurement of substitute goods or services;
-// loss of use, data, or profits; or business interruption) however caused
-// and on any theory of liability, whether in contract, strict liability,
-// or tort (including negligence or otherwise) arising in any way out of
-// the use of this software, even if advised of the possibility of such damage.
-//
-//M*/
-
-#include "../precomp.hpp"
-#include <opencv2/core/ocl.hpp>
-#include "im2col.hpp"
-#include "opencl_kernels_dnn.hpp"
-
-namespace cv
-{
-namespace dnn
-{
-
-#ifdef HAVE_OPENCL
-void im2col_ocl(UMat &img,
-                int channels, int height, int width,
-                int kernel_h, int kernel_w,
-                int pad_h, int pad_w,
-                int stride_h, int stride_w,
-                UMat &col)
-{
-    int h_out = (height + 2 * pad_h - kernel_h) / stride_h + 1;
-    int w_out = (width + 2 * pad_w - kernel_w) / stride_w + 1;
-
-    CV_Assert(img.isContinuous() && col.isContinuous());
-    CV_Assert(img.total() == (size_t)channels * height * width);
-    CV_Assert(col.total() == (size_t)channels * kernel_h * kernel_w * h_out * w_out);
-
-    ocl::Kernel im2col_ker("im2col", ocl::dnn::im2col_oclsrc);
-    CV_Assert(!im2col_ker.empty());
-
-    im2col_ker.args(ocl::KernelArg::PtrReadOnly(img), (int)img.offset,
-             channels, height, width,
-             kernel_h, kernel_w, pad_h, pad_w, stride_h, stride_w,
-             h_out, w_out,
-             ocl::KernelArg::PtrWriteOnly(col), (int)col.offset
-        );
-
-    size_t localSize = ocl::Device::getDefault().maxWorkGroupSize();
-    size_t globalSize = (size_t)channels * h_out * w_out;
-
-    CV_Assert(im2col_ker.run(1, &globalSize, &localSize, true));
-}
-#endif // HAVE_OPENCL
-
-}
-}
diff --git a/contrib/modules/dnn/src/layers/im2col.hpp b/contrib/modules/dnn/src/layers/im2col.hpp
deleted file mode 100644
index d3353e3..0000000
--- a/contrib/modules/dnn/src/layers/im2col.hpp
+++ /dev/null
@@ -1,126 +0,0 @@
-/*M///////////////////////////////////////////////////////////////////////////////////////
-//
-//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
-//
-//  By downloading, copying, installing or using the software you agree to this license.
-//  If you do not agree to this license, do not download, install,
-//  copy or use the software.
-//
-//
-//                           License Agreement
-//                For Open Source Computer Vision Library
-//
-// Copyright (C) 2013, OpenCV Foundation, all rights reserved.
-// Third party copyrights are property of their respective owners.
-//
-// Redistribution and use in source and binary forms, with or without modification,
-// are permitted provided that the following conditions are met:
-//
-//   * Redistribution's of source code must retain the above copyright notice,
-//     this list of conditions and the following disclaimer.
-//
-//   * Redistribution's in binary form must reproduce the above copyright notice,
-//     this list of conditions and the following disclaimer in the documentation
-//     and/or other materials provided with the distribution.
-//
-//   * The name of the copyright holders may not be used to endorse or promote products
-//     derived from this software without specific prior written permission.
-//
-// This software is provided by the copyright holders and contributors "as is" and
-// any express or implied warranties, including, but not limited to, the implied
-// warranties of merchantability and fitness for a particular purpose are disclaimed.
-// In no event shall the Intel Corporation or contributors be liable for any direct,
-// indirect, incidental, special, exemplary, or consequential damages
-// (including, but not limited to, procurement of substitute goods or services;
-// loss of use, data, or profits; or business interruption) however caused
-// and on any theory of liability, whether in contract, strict liability,
-// or tort (including negligence or otherwise) arising in any way out of
-// the use of this software, even if advised of the possibility of such damage.
-//
-//M*/
-
-#ifndef __OPENCV_DNN_LAYERS_IM2COL_HPP__
-#define __OPENCV_DNN_LAYERS_IM2COL_HPP__
-
-namespace cv
-{
-namespace dnn
-{
-
-template <typename Dtype>
-void im2col_cpu(const Dtype* data_im,
-                int channels, int height, int width,
-                int kernel_h, int kernel_w,
-                int pad_h, int pad_w,
-                int stride_h, int stride_w,
-                Dtype* data_col)
-{
-    int height_col = (height + 2 * pad_h - kernel_h) / stride_h + 1;
-    int width_col = (width + 2 * pad_w - kernel_w) / stride_w + 1;
-    int channels_col = channels * kernel_h * kernel_w;
-    for (int c = 0; c < channels_col; ++c) {
-        int w_offset = c % kernel_w;
-        int h_offset = (c / kernel_w) % kernel_h;
-        int c_im = c / kernel_h / kernel_w;
-        for (int h = 0; h < height_col; ++h) {
-            for (int w = 0; w < width_col; ++w) {
-                int h_pad = h * stride_h - pad_h + h_offset;
-                int w_pad = w * stride_w - pad_w + w_offset;
-                if (h_pad >= 0 && h_pad < height && w_pad >= 0 && w_pad < width)
-                    data_col[(c * height_col + h) * width_col + w] =
-                    data_im[(c_im * height + h_pad) * width + w_pad];
-                else
-                    data_col[(c * height_col + h) * width_col + w] = 0;
-            }
-        }
-    }
-}
-
-template <typename Dtype>
-void col2im_cpu(const Dtype* data_col,
-                int channels, int height, int width,
-                int patch_h, int patch_w,
-                int pad_h, int pad_w,
-                int stride_h, int stride_w,
-                Dtype* data_im)
-{
-    memset(data_im, 0, height * width * channels * sizeof(Dtype));
-
-    int height_col = (height + 2 * pad_h - patch_h) / stride_h + 1;
-    int width_col = (width + 2 * pad_w - patch_w) / stride_w + 1;
-    int channels_col = channels * patch_h * patch_w;
-
-    for (int c = 0; c < channels_col; ++c)
-    {
-        int w_offset = c % patch_w;
-        int h_offset = (c / patch_w) % patch_h;
-        int c_im = c / patch_h / patch_w;
-
-        for (int h = 0; h < height_col; ++h)
-        {
-            for (int w = 0; w < width_col; ++w)
-            {
-                int h_pad = h * stride_h - pad_h + h_offset;
-                int w_pad = w * stride_w - pad_w + w_offset;
-
-                if (h_pad >= 0 && h_pad < height && w_pad >= 0 && w_pad < width)
-                    data_im[(c_im * height + h_pad) * width + w_pad] +=
-                    data_col[(c * height_col + h) * width_col + w];
-            }
-        }
-    }
-}
-
-#ifdef HAVE_OPENCL
-void im2col_ocl(UMat &img,
-                int channels, int height, int width,
-                int kernel_h, int kernel_w,
-                int pad_h, int pad_w,
-                int stride_h, int stride_w,
-                UMat &col);
-#endif
-
-}
-}
-
-#endif
diff --git a/contrib/modules/dnn/src/layers/layers_common.cpp b/contrib/modules/dnn/src/layers/layers_common.cpp
index e3fedd9..c1f586a 100644
--- a/contrib/modules/dnn/src/layers/layers_common.cpp
+++ b/contrib/modules/dnn/src/layers/layers_common.cpp
@@ -46,43 +46,146 @@ namespace cv
 namespace dnn
 {
 
-void getKernelParams(LayerParams &params, int &kernelH, int &kernelW, int &padH, int &padW, int &strideH, int &strideW)
+namespace util
 {
-    if (params.has("kernel_h") && params.has("kernel_w"))
+
+std::string makeName(const std::string& str1, const std::string& str2)
+{
+    return str1 + str2;
+}
+
+bool getParameter(LayerParams &params, const std::string& nameBase, const std::string& nameAll, int &parameterH, int &parameterW, bool hasDefault = false, const int& defaultValue = 0)
+{
+    std::string nameH = makeName(nameBase, std::string("_h"));
+    std::string nameW = makeName(nameBase, std::string("_w"));
+    std::string nameAll_ = nameAll;
+    if(nameAll_ == "")
     {
-        kernelH = params.get<int>("kernel_h");
-        kernelW = params.get<int>("kernel_w");
+        nameAll_ = nameBase;
     }
-    else if (params.has("kernel_size"))
+
+    if (params.has(nameH) && params.has(nameW))
     {
-        kernelH = kernelW = params.get<int>("kernel_size");
+        parameterH = params.get<int>(nameH);
+        parameterW = params.get<int>(nameW);
+        return true;
     }
     else
     {
+        if (params.has(nameAll_))
+        {
+            parameterH = parameterW = params.get<int>(nameAll_);
+            return true;
+        }
+        else
+        {
+            if(hasDefault)
+            {
+                parameterH = parameterW = defaultValue;
+                return true;
+            }
+            else
+            {
+                return false;
+            }
+        }
+    }
+}
+
+void getKernelSize(LayerParams &params, int &kernelH, int &kernelW)
+{
+    if(!util::getParameter(params, "kernel", "kernel_size", kernelH, kernelW))
+    {
         CV_Error(cv::Error::StsBadArg, "kernel_size (or kernel_h and kernel_w) not specified");
     }
 
-    if (params.has("pad_h") && params.has("pad_w"))
+    CV_Assert(kernelH > 0 && kernelW > 0);
+}
+
+void getStrideAndPadding(LayerParams &params, int &padH, int &padW, int &strideH, int &strideW, cv::String& padMode)
+{
+    util::getParameter(params, "pad", "pad", padH, padW, true, 0);
+    util::getParameter(params, "stride", "stride", strideH, strideW, true, 1);
+
+    padMode = "";
+    if (params.has("pad_mode"))
     {
-        padH = params.get<int>("pad_h");
-        padW = params.get<int>("pad_w");
+        padMode = params.get<String>("pad_mode");
+    }
+
+    CV_Assert(padH >= 0 && padW >= 0 && strideH > 0 && strideW > 0);
+}
+}
+
+
+void getPoolingKernelParams(LayerParams &params, int &kernelH, int &kernelW, bool &globalPooling,
+                            int &padH, int &padW, int &strideH, int &strideW, cv::String &padMode)
+{
+    util::getStrideAndPadding(params, padH, padW, strideH, strideW, padMode);
+
+    globalPooling = params.has("global_pooling");
+
+    if (globalPooling)
+    {
+        if(params.has("kernel_h") || params.has("kernel_w") || params.has("kernel_size"))
+        {
+            CV_Error(cv::Error::StsBadArg, "In global_pooling mode, kernel_size (or kernel_h and kernel_w) cannot be specified");
+        }
+        if(padH != 0 || padW != 0 || strideH != 1 || strideW != 1)
+        {
+            CV_Error(cv::Error::StsBadArg, "In global_pooling mode, pad_h and pad_w must be = 0, and stride_h and stride_w must be = 1");
+        }
     }
     else
     {
-        padH = padW = params.get<int>("pad", 0);
+        util::getKernelSize(params, kernelH, kernelW);
     }
+}
 
-    if (params.has("stride_h") && params.has("stride_w"))
+void getConvolutionKernelParams(LayerParams &params, int &kernelH, int &kernelW, int &padH, int &padW,
+                                int &strideH, int &strideW, int &dilationH, int &dilationW, cv::String &padMode)
+{
+    util::getKernelSize(params, kernelH, kernelW);
+    util::getStrideAndPadding(params, padH, padW, strideH, strideW, padMode);
+
+    util::getParameter(params, "dilation", "dilation", dilationH, dilationW, true, 1);
+
+    CV_Assert(dilationH > 0 && dilationW > 0);
+}
+
+// From TensorFlow code:
+// Total padding on rows and cols is
+// Pr = (R' - 1) * S + Kr - R
+// Pc = (C' - 1) * S + Kc - C
+// where (R', C') are output dimensions, (R, C) are input dimensions, S
+// is stride, (Kr, Kc) are filter dimensions.
+// We pad Pr/2 on the left and Pr - Pr/2 on the right, Pc/2 on the top
+// and Pc - Pc/2 on the bottom.  When Pr or Pc is odd, this means
+// we pad more on the right and bottom than on the top and left.
+void getConvPoolOutParams(const int inputH, const int inputW, const cv::Size &kernel,
+                          const cv::Size &stride, cv::Size& pad, const cv::String &padMode,
+                          int &outH, int &outW)
+{
+    if (padMode == "VALID")
+    {
+        outH = (inputH - kernel.height + stride.height) / stride.height;
+        outW = (inputW - kernel.width + stride.width) / stride.width;
+        pad = cv::Size(0,0);
+    }
+    else if (padMode == "SAME")
     {
-        strideH = params.get<int>("stride_h");
-        strideW = params.get<int>("stride_w");
+        outH = (inputH - 1 + stride.height) / stride.height;
+        outW = (inputW - 1 + stride.width) / stride.width;
+        int Ph = std::max(0, (outH - 1) * stride.height + kernel.height - inputH);
+        int Pw = std::max(0, (outW - 1) * stride.width + kernel.width - inputW);
+        // For odd values of total padding, add more padding at the 'right'
+        // side of the given dimension.
+        pad = cv::Size(Pw / 2, Ph / 2);
     }
     else
     {
-        strideH = strideW = params.get<int>("stride", 1);
+        CV_Error(Error::StsError, "Unsupported padding mode");
     }
-
-    CV_Assert(kernelH > 0 && kernelW > 0 && padH >= 0 && padW >= 0 && strideH > 0 && strideW > 0);
 }
 
 }
diff --git a/contrib/modules/dnn/src/layers/layers_common.hpp b/contrib/modules/dnn/src/layers/layers_common.hpp
index 1637bd8..b27afaf 100644
--- a/contrib/modules/dnn/src/layers/layers_common.hpp
+++ b/contrib/modules/dnn/src/layers/layers_common.hpp
@@ -42,14 +42,23 @@
 #ifndef __OPENCV_DNN_LAYERS_LAYERS_COMMON_HPP__
 #define __OPENCV_DNN_LAYERS_LAYERS_COMMON_HPP__
 #include <opencv2/dnn.hpp>
+#include "op_blas.hpp"
+#include "op_im2col.hpp"
 
 namespace cv
 {
 namespace dnn
 {
 
-void getKernelParams(LayerParams &params, int &kernelH, int &kernelW, int &padH, int &padW, int &strideH, int &strideW);
+void getConvolutionKernelParams(LayerParams &params, int &kernelH, int &kernelW, int &padH, int &padW,
+                                int &strideH, int &strideW, int &dilationH, int &dilationW, cv::String& padMode);
 
+void getPoolingKernelParams(LayerParams &params, int &kernelH, int &kernelW, bool &globalPooling,
+                            int &padH, int &padW, int &strideH, int &strideW, cv::String& padMode);
+
+void getConvPoolOutParams(const int inputH, const int inputW, const cv::Size& kernel,
+                          const cv::Size& stride, cv::Size &pad, const cv::String& padMode,
+                          int &outH, int &outW);
 }
 }
 
diff --git a/contrib/modules/dnn/src/layers/lrn_layer.cpp b/contrib/modules/dnn/src/layers/lrn_layer.cpp
index a55d8fe..e2c0ec7 100644
--- a/contrib/modules/dnn/src/layers/lrn_layer.cpp
+++ b/contrib/modules/dnn/src/layers/lrn_layer.cpp
@@ -42,123 +42,219 @@
 #include "../precomp.hpp"
 #include "layers_common.hpp"
 #include "lrn_layer.hpp"
+#include "modules/dnn/opencl_kernels_dnn.hpp"
 #include <opencv2/imgproc.hpp>
+#include <opencv2/core/ocl.hpp>
+#include <opencv2/dnn/shape_utils.hpp>
 #include <algorithm>
 
 namespace cv
 {
 namespace dnn
 {
-    LRNLayer::LRNLayer(LayerParams &params) : Layer(params)
-    {
-        String nrmType = params.get<String>("norm_region", "ACROSS_CHANNELS");
-        if (nrmType == "ACROSS_CHANNELS")
-            type = CHANNEL_NRM;
-        else if (nrmType == "WITHIN_CHANNEL")
-            type = SPATIAL_NRM;
-        else
-            CV_Error(Error::StsBadArg, "Unknown region type \"" + nrmType + "\"");
-
-        size = params.get<int>("local_size", 5);
-        if (size % 2 != 1 || size <= 0)
-            CV_Error(Error::StsBadArg, "LRN layer supports only positive odd values for local_size");
-
-        alpha = params.get<double>("alpha", 1);
-        beta = params.get<double>("beta", 0.75);
-    }
 
-    void LRNLayer::allocate(const std::vector<Blob*> &inputs, std::vector<Blob> &outputs)
-    {
-        CV_Assert(inputs.size() == 1);
-        outputs.resize(1);
+LRNLayerImpl::LRNLayerImpl(int type_, int size_, double alpha_, double beta_, double bias_, bool normBySize_)
+{
+    type = type_;
+    size = size_;
+    alpha = alpha_;
+    beta = beta_;
+    bias = bias_;
+    normBySize = normBySize_;
+}
+
+void LRNLayerImpl::allocate(const std::vector<Blob*> &inputs, std::vector<Blob> &outputs)
+{
+    CV_Assert(inputs.size() == 1 && inputs[0]->dims() == 4);
+    CV_Assert(type == CHANNEL_NRM || type == SPATIAL_NRM);
+    useOpenCL = cv::ocl::useOpenCL();
 
-        Vec4i shape = inputs[0]->shape4();
-        outputs[0].create(shape);
+    if (type == SPATIAL_NRM && !useOpenCL)
+        buf.create(inputs[0]->shape().slice(2), inputs[0]->type(), Blob::ALLOC_MAT);
+    if (type == CHANNEL_NRM && useOpenCL)
+        buf.create(inputs[0]->shape().slice(2), inputs[0]->type(), Blob::ALLOC_UMAT);
 
-        shape[0] = 1; //maybe make shape[0] = 1 too
-        bufBlob.create(shape);
-    }
+    outputs.resize(1);
+    outputs[0].create(inputs[0]->shape(), inputs[0]->type());
+}
+
+void LRNLayerImpl::forward(std::vector<Blob*> &inputs, std::vector<Blob> &outputs)
+{
+    Blob &src = *inputs[0];
+    Blob &dst = outputs[0];
 
-    void LRNLayer::forward(std::vector<Blob*> &inputs, std::vector<Blob> &outputs)
+    switch (type)
     {
-        Blob &src = *inputs[0];
-        Blob &dst = outputs[0];
+    case CHANNEL_NRM:
+        channelNoramlization(src, dst);
+        break;
+    case SPATIAL_NRM:
+        spatialNormalization(src, dst);
+        break;
+    default:
+        CV_Error(Error::StsNotImplemented, "Unimplemented mode of LRN layer");
+        break;
+    }
+}
 
-        switch (type)
-        {
-        case CHANNEL_NRM:
-            channelNoramlization(src, dst);
-            break;
-        case SPATIAL_NRM:
-            spatialNormalization(src, dst);
-            break;
-        default:
-            CV_Error(cv::Error::StsNotImplemented, "Unimplemented mode of LRN layer");
-            break;
-        }
+template<typename XMat>
+static XMat getPlane(XMat &m, int n, int cn)
+{
+    return reshaped(slice(m, n, cn), BlobShape::like(m).slice(2));
+}
+
+void LRNLayerImpl::channelNoramlization(Blob &src, Blob &dst)
+{
+    if (!useOpenCL)
+        channelNoramlization_<Mat>(src, dst);
+    else
+    {
+        //channelNoramlization_ocl(src.getRefConst<UMat>(), dst.getRef<UMat>()); //consumes a lot of memory
+        channelNoramlization_<UMat>(src, dst);
     }
+}
+
+template<typename XMat>
+void LRNLayerImpl::channelNoramlization_(Blob &srcBlob, Blob &dstBlob)
+{
+    int num = srcBlob.num();
+    int channels = srcBlob.channels();
+    int ksize = (size - 1) / 2;
+    int sizeNormFactor = normBySize ? size : 1;
+
+    XMat srcMat = srcBlob.getRefConst<XMat>();
+    XMat dstMat = dstBlob.getRef<XMat>();
 
-    void LRNLayer::channelNoramlization(Blob &srcBlob, Blob &dstBlob)
+    for (int n = 0; n < num; n++)
     {
-        CV_DbgAssert(srcBlob.ptr() != dstBlob.ptr());
+        XMat accum = getPlane(dstMat, n, channels-1); //trick for memory saving
+        accum.setTo(0);
 
-        int num = srcBlob.num();
-        int channels = srcBlob.channels();
-        int ksize = (size - 1) / 2;
+        for (int cn = 0; cn < std::min(ksize, channels); cn++)
+            cv::accumulateSquare(getPlane(srcMat, n, cn), accum);
 
-        for (int n = 0; n < num; n++)
+        for (int cn = 0; cn < channels; cn++)
         {
-            Mat accum = dstBlob.getPlane(n, channels-1); //trick for memory saving
-            accum.setTo(0);
-
-            for (int cn = 0; cn < std::min(ksize, channels); cn++)
-                cv::accumulateSquare(srcBlob.getPlane(n, cn), accum);
+            if (cn + ksize < channels)
+            {
+                cv::accumulateSquare(getPlane(srcMat, n, cn + ksize), accum);
+            }
 
-            for (int cn = 0; cn < channels; cn++)
+            if (cn - ksize - 1 >= 0)
             {
-                if (cn + ksize < channels)
-                {
-                    cv::accumulateSquare(srcBlob.getPlane(n, cn + ksize), accum);
-                }
-
-                if (cn - ksize - 1 >= 0)
-                {
-                    Mat left = srcBlob.getPlane(n, cn - ksize - 1);
-                    cv::subtract(accum, left.mul(left), accum); //subtractSquare
-                }
-
-                Mat dst = dstBlob.getPlane(n, cn);
-                accum.convertTo(dst, dst.type(), alpha/size, 1);
-                cv::pow(dst, beta, dst);
-                cv::divide(srcBlob.getPlane(n, cn), dst, dst);
+                //subtractSquare
+                XMat left = getPlane(srcMat, n, cn - ksize - 1);
+                cv::pow(left, 2, left);
+                cv::subtract(accum, left, accum);
             }
+
+            XMat dst = getPlane(dstMat, n, cn);
+            accum.convertTo(dst, dst.type(), alpha/sizeNormFactor, bias);
+            cv::pow(dst, beta, dst);
+            cv::divide(getPlane(srcMat, n, cn), dst, dst);
         }
     }
+}
 
-    void LRNLayer::spatialNormalization(Blob &srcBlob, Blob &dstBlob)
-    {
-        int num = srcBlob.num();
-        int channels = srcBlob.channels();
+bool LRNLayerImpl::channelNoramlization_ocl(const UMat &src, UMat &dst)
+{
+#ifdef HAVE_OPENCL
+    if (src.offset != 0 || dst.offset != 0) //TODO: add offset
+        return false;
 
-        for (int n = 0; n < num; n++)
+    String buildOpts = String("-DT=") + ocl::typeToStr(src.type());
+
+    ocl::Kernel kerScale("LRNFillScale", ocl::dnn::lrn_oclsrc, buildOpts);
+    if (kerScale.empty())
+        return false;
+
+    ocl::Kernel kerOutput("LRNComputeOutput", ocl::dnn::lrn_oclsrc, buildOpts);
+    if (kerOutput.empty())
+        return false;
+
+    Shape shape = Shape::like(src);
+    int ksize = (size - 1) / 2;
+    int sizeNormFactor = normBySize ? size : 1;
+    // TODO: add bias
+    size_t wgSize = ocl::Device::getDefault().maxWorkGroupSize();
+    UMat &scaleBuf = buf.umatRef();
+
+    size_t nthreads = (size_t)(shape.total() / shape[1]);
+    kerScale.args((int)nthreads,
+                  ocl::KernelArg::PtrReadOnly(src), shape[0], shape[1], shape[2], shape[3],
+                  size, (float)(alpha/sizeNormFactor), (float)ksize, ocl::KernelArg::PtrWriteOnly(scaleBuf));
+    if (!kerScale.run(1, &nthreads, &wgSize, true))
+        return false;
+
+    nthreads = (size_t)shape.total();
+    kerOutput.args((int)nthreads,
+                   ocl::KernelArg::PtrReadOnly(src), ocl::KernelArg::PtrReadOnly(scaleBuf),
+                   -beta, ocl::KernelArg::PtrWriteOnly(dst) );
+    if (!kerOutput.run(1, &nthreads, &wgSize, true))
+        return false;
+
+    return true;
+#else
+    (void)src;
+    (void)dst;
+    return false;
+#endif
+}
+
+void LRNLayerImpl::spatialNormalization(Blob &src, Blob &dst)
+{
+    if (!useOpenCL)
+        spatialNormalization_<Mat>(src, dst);
+    else
+        spatialNormalization_<UMat>(src, dst);
+}
+
+//TODO: fix cv::boxFilter with BORDER_ISOLATED flag in CPU mode
+template<>
+void LRNLayerImpl::sqrBoxFilter_<Mat>(const Mat &src, Mat &dst)
+{
+    Mat srcRawWrapper(src.rows, src.cols, src.type(), src.data, src.step[0]);
+    cv::sqrBoxFilter(srcRawWrapper, dst, dst.depth(), Size(size, size), Point(-1, -1), false, BORDER_CONSTANT);
+}
+
+template<>
+void LRNLayerImpl::sqrBoxFilter_<UMat>(const UMat &src, UMat &dst)
+{
+    cv::sqrBoxFilter(src, dst, dst.depth(), Size(size, size), Point(-1, -1), false, BORDER_CONSTANT | BORDER_ISOLATED);
+}
+
+template<typename XMat>
+void LRNLayerImpl::spatialNormalization_(Blob &srcBlob, Blob &dstBlob)
+{
+    int num = srcBlob.num();
+    int channels = srcBlob.channels();
+    int sizeNormFactor = normBySize ? size*size : 1;
+
+    XMat srcMat = srcBlob.getRefConst<XMat>();
+    XMat dstMat = dstBlob.getRef<XMat>();
+
+    for (int n = 0; n < num; n++)
+    {
+        for (int cn = 0; cn < channels; cn++)
         {
-            for (int cn = 0; cn < channels; cn++)
-            {
-                Mat src = srcBlob.getPlane(n, cn);
-                Mat dst = dstBlob.getPlane(n, cn);
-                uchar *dataDst0 = dst.data;
-
-                cv::pow(srcBlob.getPlane(n, cn), 2, dst);
-                //TODO: check border type
-                cv::boxFilter(dst, dst, dst.depth(), cv::Size(size, size), cv::Point(-1, -1), false, cv::BORDER_CONSTANT);
-                dst.convertTo(dst, dst.type(), alpha/(size*size), 1);
-                cv::pow(dst, beta, dst);
-                cv::divide(src, dst, dst);
-
-                CV_Assert(dataDst0 == dst.data); //debug
-            }
+            XMat src = getPlane(srcMat, n, cn);
+            XMat dst = getPlane(dstMat, n, cn);
+
+            sqrBoxFilter_(src, dst);
+
+            dst.convertTo(dst, dst.type(), alpha/sizeNormFactor, bias);
+            cv::pow(dst, beta, dst);
+            cv::divide(src, dst, dst);
         }
     }
+}
+
+
+Ptr<LRNLayer> LRNLayer::create(int type, int size, double alpha, double beta, double bias,
+                               bool normBySize)
+{
+    return Ptr<LRNLayer>(new LRNLayerImpl(type, size, alpha, beta, bias, normBySize));
+}
 
 }
 }
diff --git a/contrib/modules/dnn/src/layers/lrn_layer.hpp b/contrib/modules/dnn/src/layers/lrn_layer.hpp
index c207e63..c9017b0 100644
--- a/contrib/modules/dnn/src/layers/lrn_layer.hpp
+++ b/contrib/modules/dnn/src/layers/lrn_layer.hpp
@@ -42,34 +42,38 @@
 #ifndef __OPENCV_DNN_LAYERS_LRN_LAYER_HPP__
 #define __OPENCV_DNN_LAYERS_LRN_LAYER_HPP__
 #include "../precomp.hpp"
+#include <opencv2/dnn/all_layers.hpp>
 
 namespace cv
 {
 namespace dnn
 {
-    class LRNLayer : public Layer
-    {
-        enum
-        {
-            CHANNEL_NRM,
-            SPATIAL_NRM,
-            SPATIAL_CONTRAST_NRM //cuda-convnet feature
-        } type;
 
-        int size;
-        double alpha, beta;
+class LRNLayerImpl : public LRNLayer
+{
+    bool useOpenCL;
+    Blob buf;
+
+    void channelNoramlization(Blob &src, Blob &dst);
+    template<typename XMat>
+    void channelNoramlization_(Blob &src, Blob &dst);
+    bool channelNoramlization_ocl(const UMat &src, UMat &dst);
 
-        Blob bufBlob;
+    void spatialNormalization(Blob &src, Blob &dst);
+    template<typename XMat>
+    void spatialNormalization_(Blob &src, Blob &dst);
+    template<typename XMat>
+    void sqrBoxFilter_(const XMat &src, XMat &dst);
 
-        void channelNoramlization(Blob &src, Blob &dst);
-        void spatialNormalization(Blob &src, Blob &dst);
+public:
 
-    public:
+    LRNLayerImpl(int type = CHANNEL_NRM, int size = 5, double alpha = 1, double beta = 0.75, double bias = 1,
+                 bool normBySize = true);
+    void allocate(const std::vector<Blob*> &inputs, std::vector<Blob> &outputs);
+    void forward(std::vector<Blob*> &inputs, std::vector<Blob> &outputs);
+};
 
-        LRNLayer(LayerParams &params);
-        void allocate(const std::vector<Blob*> &inputs, std::vector<Blob> &outputs);
-        void forward(std::vector<Blob*> &inputs, std::vector<Blob> &outputs);
-    };
 }
 }
+
 #endif
diff --git a/contrib/modules/dnn/src/layers/mvn_layer.cpp b/contrib/modules/dnn/src/layers/mvn_layer.cpp
index eb9a7b5..36c48c4 100644
--- a/contrib/modules/dnn/src/layers/mvn_layer.cpp
+++ b/contrib/modules/dnn/src/layers/mvn_layer.cpp
@@ -42,20 +42,21 @@
 #include "../precomp.hpp"
 #include "layers_common.hpp"
 #include "mvn_layer.hpp"
+#include <opencv2/dnn/shape_utils.hpp>
 
 namespace cv
 {
 namespace dnn
 {
 
-MVNLayer::MVNLayer(LayerParams &params) : Layer(params)
+MVNLayerImpl::MVNLayerImpl(bool normVariance_, bool acrossChannels_, double eps_)
 {
-    eps = params.get<double>("eps", 1e-9);
-    acrossChannels = params.get<bool>("across_channels", false);
-    normalizeVariance = params.get<bool>("normalize_variance", true);
+    normVariance = normVariance_;
+    acrossChannels = acrossChannels_;
+    eps = eps_;
 }
 
-void MVNLayer::allocate(const std::vector<Blob *> &inputs, std::vector<Blob> &outputs)
+void MVNLayerImpl::allocate(const std::vector<Blob *> &inputs, std::vector<Blob> &outputs)
 {
     outputs.resize(inputs.size());
     for (size_t i = 0; i < inputs.size(); i++)
@@ -65,20 +66,17 @@ void MVNLayer::allocate(const std::vector<Blob *> &inputs, std::vector<Blob> &ou
     }
 }
 
-void MVNLayer::forward(std::vector<Blob *> &inputs, std::vector<Blob> &outputs)
+void MVNLayerImpl::forward(std::vector<Blob *> &inputs, std::vector<Blob> &outputs)
 {
     for (size_t inpIdx = 0; inpIdx < inputs.size(); inpIdx++)
     {
         Blob &inpBlob = *inputs[inpIdx];
         Blob &outBlob = outputs[inpIdx];
 
-        int workSize[2];
         int splitDim = (acrossChannels) ? 1 : 2;
-        workSize[0] = (int)inpBlob.total(0, splitDim);
-        workSize[1] = (int)inpBlob.total(splitDim);
-
-        Mat inpMat = inpBlob.matRef().reshape(1, 2, workSize);
-        Mat outMat = outBlob.matRef().reshape(1, 2, workSize);
+        Shape workSize((int)inpBlob.total(0, splitDim), (int)inpBlob.total(splitDim));
+        Mat inpMat = reshaped(inpBlob.matRefConst(), workSize);
+        Mat outMat = reshaped(outBlob.matRef(), workSize);
 
         Scalar mean, dev;
         for (int i = 0; i < workSize[0]; i++)
@@ -86,12 +84,18 @@ void MVNLayer::forward(std::vector<Blob *> &inputs, std::vector<Blob> &outputs)
             Mat inpRow = inpMat.row(i);
             Mat outRow = outMat.row(i);
 
-            cv::meanStdDev(inpRow, mean, (normalizeVariance) ? dev : noArray());
-            double alpha = (normalizeVariance) ? 1/(eps + dev[0]) : 1;
+            cv::meanStdDev(inpRow, mean, (normVariance) ? dev : noArray());
+            double alpha = (normVariance) ? 1/(eps + dev[0]) : 1;
             inpRow.convertTo(outRow, outRow.type(), alpha, -mean[0] * alpha);
         }
     }
 }
 
+
+Ptr<MVNLayer> MVNLayer::create(bool normVariance, bool acrossChannels, double eps)
+{
+    return Ptr<MVNLayer>(new MVNLayerImpl(normVariance, acrossChannels, eps));
+}
+
 }
 }
diff --git a/contrib/modules/dnn/src/layers/mvn_layer.hpp b/contrib/modules/dnn/src/layers/mvn_layer.hpp
index 431db7c..80b8954 100644
--- a/contrib/modules/dnn/src/layers/mvn_layer.hpp
+++ b/contrib/modules/dnn/src/layers/mvn_layer.hpp
@@ -42,20 +42,18 @@
 #ifndef __OPENCV_DNN_LAYERS_MVN_LAYER_HPP__
 #define __OPENCV_DNN_LAYERS_MVN_LAYER_HPP__
 #include "../precomp.hpp"
+#include <opencv2/dnn/all_layers.hpp>
 
 namespace cv
 {
 namespace dnn
 {
 
-class MVNLayer : public Layer
+class MVNLayerImpl : public MVNLayer
 {
-    double eps;
-    bool acrossChannels, normalizeVariance;
-
 public:
 
-    MVNLayer(LayerParams &params);
+    MVNLayerImpl(bool normVariance_ = true, bool acrossChannels_ = false, double eps_ = 1e-9);
     void allocate(const std::vector<Blob*> &inputs, std::vector<Blob> &outputs);
     void forward(std::vector<Blob*> &inputs, std::vector<Blob> &outputs);
 };
diff --git a/contrib/modules/dnn/src/layers/normalize_bbox_layer.cpp b/contrib/modules/dnn/src/layers/normalize_bbox_layer.cpp
new file mode 100644
index 0000000..926465b
--- /dev/null
+++ b/contrib/modules/dnn/src/layers/normalize_bbox_layer.cpp
@@ -0,0 +1,201 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+//  By downloading, copying, installing or using the software you agree to this license.
+//  If you do not agree to this license, do not download, install,
+//  copy or use the software.
+//
+//
+//                           License Agreement
+//                For Open Source Computer Vision Library
+//
+// Copyright (C) 2013, OpenCV Foundation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+//   * Redistribution's of source code must retain the above copyright notice,
+//     this list of conditions and the following disclaimer.
+//
+//   * Redistribution's in binary form must reproduce the above copyright notice,
+//     this list of conditions and the following disclaimer in the documentation
+//     and/or other materials provided with the distribution.
+//
+//   * The name of the copyright holders may not be used to endorse or promote products
+//     derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "../precomp.hpp"
+#include "layers_common.hpp"
+#include "normalize_bbox_layer.hpp"
+#include "op_blas.hpp"
+
+#include <float.h>
+#include <algorithm>
+
+namespace cv
+{
+namespace dnn
+{
+
+const std::string NormalizeBBoxLayer::_layerName = std::string("NormalizeBBox");
+
+bool NormalizeBBoxLayer::getParameterDict(const LayerParams &params,
+                                          const std::string &parameterName,
+                                          DictValue& result)
+{
+    if (!params.has(parameterName))
+    {
+        return false;
+    }
+
+    result = params.get(parameterName);
+    return true;
+}
+
+template<typename T>
+T NormalizeBBoxLayer::getParameter(const LayerParams &params,
+                                   const std::string &parameterName,
+                                   const size_t &idx,
+                                   const bool required,
+                                   const T& defaultValue)
+{
+    DictValue dictValue;
+    bool success = getParameterDict(params, parameterName, dictValue);
+    if(!success)
+    {
+        if(required)
+        {
+            std::string message = _layerName;
+            message += " layer parameter does not contain ";
+            message += parameterName;
+            message += " parameter.";
+            CV_Error(Error::StsBadArg, message);
+        }
+        else
+        {
+            return defaultValue;
+        }
+    }
+    return dictValue.get<T>(idx);
+}
+
+NormalizeBBoxLayer::NormalizeBBoxLayer(LayerParams &params) : Layer(params)
+{
+    _eps = getParameter<float>(params, "eps", 0, false, 1e-10f);
+    _across_spatial = getParameter<bool>(params, "across_spatial");
+    _channel_shared = getParameter<bool>(params, "channel_shared");
+}
+
+void NormalizeBBoxLayer::checkInputs(const std::vector<Blob*> &inputs)
+{
+    CV_Assert(inputs.size() > 0);
+    for (size_t i = 1; i < inputs.size(); i++)
+    {
+        for (size_t j = 0; j < _numAxes; j++)
+        {
+            CV_Assert(inputs[i]->shape()[j] == inputs[0]->shape()[j]);
+        }
+    }
+    CV_Assert(inputs[0]->dims() > 2);
+}
+
+void NormalizeBBoxLayer::allocate(const std::vector<Blob*> &inputs, std::vector<Blob> &outputs)
+{
+    checkInputs(inputs);
+
+    _num = inputs[0]->num();
+    _channels = inputs[0]->shape()[1];
+    _rows = inputs[0]->shape()[2];
+    _cols = inputs[0]->shape()[3];
+
+    _channelSize = _rows * _cols;
+    _imageSize = _channelSize * _channels;
+
+    _buffer = Mat(_channels, _channelSize, CV_32F);
+
+    _sumChannelMultiplier = Mat(_channels, 1, CV_32F, Scalar(1.0));
+    _sumSpatialMultiplier = Mat(1, _channelSize, CV_32F, Scalar(1.0));
+
+    _scale = blobs[0];
+
+    for(size_t i = 0; i < inputs.size(); i++)
+    {
+        outputs[i].create(BlobShape(inputs[0]->shape()));
+    }
+}
+
+void NormalizeBBoxLayer::forward(std::vector<Blob*> &inputs, std::vector<Blob> &outputs)
+{
+    Mat zeroBuffer(_channels, _channelSize, CV_32F, Scalar(0));
+    Mat absDiff;
+
+    for (size_t j = 0; j < inputs.size(); j++)
+    {
+        for (size_t n = 0; n < _num; ++n)
+        {
+            Mat src = Mat(_channels, _channelSize, CV_32F, inputs[j]->ptrf(n));
+            Mat dst = Mat(_channels, _channelSize, CV_32F, outputs[j].ptrf(n));
+
+            _buffer = src.mul(src);
+
+            if (_across_spatial)
+            {
+                absdiff(_buffer, zeroBuffer, absDiff);
+
+                // add eps to avoid overflow
+                double absSum = sum(absDiff)[0] + _eps;
+
+                float norm = sqrt(absSum);
+                dst = src / norm;
+            }
+            else
+            {
+                Mat norm(_channelSize, 1, _buffer.type()); // 1 x _channelSize
+
+                // (_channels x_channelSize)T * _channels x 1 -> _channelSize x 1
+                gemmCPU(_buffer, _sumChannelMultiplier, 1, norm, 0, GEMM_1_T);
+
+                // compute norm
+                pow(norm, 0.5f, norm);
+
+                // scale the layer
+                // _channels x 1 * (_channelSize x 1)T -> _channels x _channelSize
+                gemmCPU(_sumChannelMultiplier, norm, 1, _buffer, 0, GEMM_2_T);
+
+                dst = src / _buffer;
+            }
+
+            // scale the output
+            if (_channel_shared)
+            {
+                // _scale: 1 x 1
+                dst *= _scale.matRefConst().at<float>(0, 0);
+            }
+            else
+            {
+                // _scale: _channels x 1
+                // _channels x 1 * 1 x _channelSize -> _channels x _channelSize
+                gemmCPU(_scale.matRefConst(), _sumSpatialMultiplier, 1, _buffer, 0);
+
+                dst = dst.mul(_buffer);
+           }
+        }
+    }
+}
+}
+}
diff --git a/contrib/modules/dnn/src/layers/normalize_bbox_layer.hpp b/contrib/modules/dnn/src/layers/normalize_bbox_layer.hpp
new file mode 100644
index 0000000..825a0f8
--- /dev/null
+++ b/contrib/modules/dnn/src/layers/normalize_bbox_layer.hpp
@@ -0,0 +1,94 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+//  By downloading, copying, installing or using the software you agree to this license.
+//  If you do not agree to this license, do not download, install,
+//  copy or use the software.
+//
+//
+//                           License Agreement
+//                For Open Source Computer Vision Library
+//
+// Copyright (C) 2013, OpenCV Foundation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+//   * Redistribution's of source code must retain the above copyright notice,
+//     this list of conditions and the following disclaimer.
+//
+//   * Redistribution's in binary form must reproduce the above copyright notice,
+//     this list of conditions and the following disclaimer in the documentation
+//     and/or other materials provided with the distribution.
+//
+//   * The name of the copyright holders may not be used to endorse or promote products
+//     derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#ifndef __OPENCV_DNN_LAYERS_NORMALIZEBBOX_LAYER_HPP__
+#define __OPENCV_DNN_LAYERS_NORMALIZEBBOX_LAYER_HPP__
+#include "../precomp.hpp"
+
+namespace cv
+{
+namespace dnn
+{
+class NormalizeBBoxLayer : public Layer
+{
+    Mat _buffer;
+
+    Mat _sumChannelMultiplier;
+    Mat _sumSpatialMultiplier;
+
+    Blob _scale;
+
+    float _eps;
+    bool _across_spatial;
+    bool _channel_shared;
+
+    size_t _num;
+    size_t _channels;
+    size_t _rows;
+    size_t _cols;
+
+    size_t _channelSize;
+    size_t _imageSize;
+
+    static const size_t _numAxes = 4;
+    static const std::string _layerName;
+
+public:
+    NormalizeBBoxLayer(LayerParams &params);
+    void allocate(const std::vector<Blob*> &inputs, std::vector<Blob> &outputs);
+    void forward(std::vector<Blob*> &inputs, std::vector<Blob> &outputs);
+
+    void checkInputs(const std::vector<Blob*> &inputs);
+
+    template<typename T>
+    T getParameter(const LayerParams &params,
+                   const std::string &parameterName,
+                   const size_t &idx = 0,
+                   const bool required = true,
+                   const T& defaultValue = T());
+
+    bool getParameterDict(const LayerParams &params,
+                          const std::string &parameterName,
+                          DictValue& result);
+};
+}
+}
+#endif
diff --git a/contrib/modules/dnn/src/layers/op_blas.cpp b/contrib/modules/dnn/src/layers/op_blas.cpp
new file mode 100644
index 0000000..5f7f446
--- /dev/null
+++ b/contrib/modules/dnn/src/layers/op_blas.cpp
@@ -0,0 +1,171 @@
+#include "op_blas.hpp"
+
+#ifdef HAVE_LAPACK
+#include "opencv_lapack.h"
+#endif
+
+#include <iostream>
+
+namespace cv
+{
+namespace dnn
+{
+
+void gemm(InputArray A, InputArray B, double alpha, InputOutputArray C, double beta, int flags)
+{
+    if (C.isMat())
+        gemmCPU(A.getMat(), B.getMat(), alpha, C.getMatRef(), beta, flags);
+    else
+    {
+        cv::gemm(A, B, alpha, (beta == 0) ? noArray() : C, beta, C, flags);
+    }
+}
+
+inline void SwapRowCols(const Mat &A, int &rows, int &cols, bool isTrans)
+{
+    CV_DbgAssert(A.dims == 2);
+    rows = (isTrans) ? A.cols : A.rows;
+    cols = (isTrans) ? A.rows : A.cols;
+}
+
+
+class GEMMInvoker : public ParallelLoopBody
+{
+public:
+    GEMMInvoker(const Mat* _a, const Mat* _b, double _alpha, Mat* _c, double _beta)
+    {
+        a = _a;
+        b = _b;
+        c = _c;
+        alpha = _alpha;
+        beta = _beta;
+    }
+
+    void operator()(const Range& range) const
+    {
+        int mmax = a->rows;
+        int nmax = range.end - range.start;
+        int kmax = a->cols;
+        int m, n, k;
+        AutoBuffer<float> buf(nmax);
+        float* ptr = buf;
+        if( mmax %2 != 0 )
+            memset(ptr, 0, nmax*sizeof(ptr[0]));
+
+        for( m = 0; m < mmax; m += 2 )
+        {
+            float* dst0 = c->ptr<float>(m) + range.start;
+            float* dst1 = m+1 < mmax ? c->ptr<float>(m+1) + range.start : ptr;
+            const float* aptr0 = a->ptr<float>(m);
+            const float* aptr1 = m+1 < mmax ? a->ptr<float>(m+1) : aptr0;
+
+            if( beta != 1 )
+            {
+                if( beta == 0 )
+                    for( n = 0; n < nmax; n++ )
+                    {
+                        dst0[n] = 0.f;
+                        dst1[n] = 0.f;
+                    }
+                else
+                    for( n = 0; n < nmax; n++ )
+                    {
+                        dst0[n] *= (float)beta;
+                        dst1[n] *= (float)beta;
+                    }
+            }
+
+            for( k = 0; k < kmax; k++ )
+            {
+                float alpha0 = (float)(alpha*aptr0[k]);
+                float alpha1 = (float)(alpha*aptr1[k]);
+                const float* bptr = b->ptr<float>(k) + range.start;
+
+                for( n = 0; n < nmax; n++ )
+                {
+                    float d0 = dst0[n] + alpha0*bptr[n];
+                    float d1 = dst1[n] + alpha1*bptr[n];
+                    dst0[n] = d0;
+                    dst1[n] = d1;
+                }
+            }
+        }
+    }
+
+    const Mat *a, *b;
+    Mat* c;
+    double alpha, beta;
+};
+
+void gemmCPU(const Mat &A, const Mat &B, double alpha, Mat &C, double beta, int flags /*= 0*/)
+{
+    #ifdef HAVE_LAPACK
+    bool transA = static_cast<bool>(flags & GEMM_1_T);
+    bool transB = static_cast<bool>(flags & GEMM_2_T);
+    bool transC = static_cast<bool>(flags & GEMM_3_T);
+
+    int Arows, Acols, Brows, Bcols, Crows, Ccols;
+    SwapRowCols(A, Arows, Acols, transA);
+    SwapRowCols(B, Brows, Bcols, transB);
+    SwapRowCols(C, Crows, Ccols, transC);
+
+    CV_Assert(!(flags & GEMM_3_T));
+    CV_Assert(Acols == Brows && Arows == Crows && Bcols == Ccols);
+    CV_Assert(A.isContinuous() && B.isContinuous() && C.isContinuous());
+    CV_Assert(A.type() == B.type() && B.type() == C.type());
+    CV_Assert(A.data != C.data && B.data != C.data);
+
+    if (C.type() == CV_32F)
+    {
+        cblas_sgemm(CblasRowMajor, transA ? CblasTrans : CblasNoTrans, transB ? CblasTrans : CblasNoTrans,
+                    Arows, Bcols, Acols,
+                    (float)alpha, A.ptr<float>(), A.cols,
+                    B.ptr<float>(), B.cols,
+                    (float)beta, C.ptr<float>(), C.cols);
+    }
+    else if (C.type() == CV_64F)
+    {
+        //TODO: Should be tested
+        cblas_dgemm(CblasRowMajor, transA ? CblasTrans : CblasNoTrans, transB ? CblasTrans : CblasNoTrans,
+                    Arows, Bcols, Acols,
+                    alpha, A.ptr<double>(), A.cols,
+                    B.ptr<double>(), B.cols,
+                    beta, C.ptr<double>(), C.cols);
+    }
+    else
+    {
+        CV_Error(Error::BadDepth, "Only floating point types are supported");
+    }
+    #else
+    if( C.type() == CV_32F && flags == 0 )
+    {
+        GEMMInvoker invoker(&A, &B, alpha, &C, beta);
+        double granularity = 10000000./((double)A.rows*A.cols);
+        parallel_for_(Range(0, B.cols), invoker, granularity);
+    }
+    else
+        cv::gemm(A, B, alpha, C, beta, C, flags);
+    #endif
+}
+
+int getBlasThreads()
+{
+    #ifdef OPENBLAS_VERSION
+    return openblas_get_num_threads();
+    #else
+    return 1;
+    #endif
+}
+
+void setBlasThreads(int numThreads)
+{
+    #ifdef OPENBLAS_VERSION
+    openblas_set_num_threads(numThreads);
+    goto_set_num_threads(numThreads);
+    #else
+    (void)numThreads;   //suppress compilers' warning
+    #endif
+}
+
+}
+}
diff --git a/contrib/modules/dnn/src/layers/op_blas.hpp b/contrib/modules/dnn/src/layers/op_blas.hpp
new file mode 100644
index 0000000..55c70d8
--- /dev/null
+++ b/contrib/modules/dnn/src/layers/op_blas.hpp
@@ -0,0 +1,59 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+//  By downloading, copying, installing or using the software you agree to this license.
+//  If you do not agree to this license, do not download, install,
+//  copy or use the software.
+//
+//
+//                           License Agreement
+//                For Open Source Computer Vision Library
+//
+// Copyright (C) 2013, OpenCV Foundation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+//   * Redistribution's of source code must retain the above copyright notice,
+//     this list of conditions and the following disclaimer.
+//
+//   * Redistribution's in binary form must reproduce the above copyright notice,
+//     this list of conditions and the following disclaimer in the documentation
+//     and/or other materials provided with the distribution.
+//
+//   * The name of the copyright holders may not be used to endorse or promote products
+//     derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#ifndef __OPENCV_DNN_LAYERS_OP_BLAS_HPP__
+#define __OPENCV_DNN_LAYERS_OP_BLAS_HPP__
+#include "../precomp.hpp"
+
+namespace cv
+{
+namespace dnn
+{
+    int getBlasThreads();
+
+    void setBlasThreads(int numThreads);
+
+    void gemm(InputArray A, InputArray B, double alpha, InputOutputArray C, double beta, int flags = 0);
+
+    void gemmCPU(const Mat &A, const Mat &B, double alpha, Mat &C, double beta, int flags = 0);
+}
+}
+#endif
\ No newline at end of file
diff --git a/contrib/modules/dnn/src/layers/op_im2col.cpp b/contrib/modules/dnn/src/layers/op_im2col.cpp
new file mode 100644
index 0000000..4adeec7
--- /dev/null
+++ b/contrib/modules/dnn/src/layers/op_im2col.cpp
@@ -0,0 +1,168 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+//  By downloading, copying, installing or using the software you agree to this license.
+//  If you do not agree to this license, do not download, install,
+//  copy or use the software.
+//
+//
+//                           License Agreement
+//                For Open Source Computer Vision Library
+//
+// Copyright (C) 2013, OpenCV Foundation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+//   * Redistribution's of source code must retain the above copyright notice,
+//     this list of conditions and the following disclaimer.
+//
+//   * Redistribution's in binary form must reproduce the above copyright notice,
+//     this list of conditions and the following disclaimer in the documentation
+//     and/or other materials provided with the distribution.
+//
+//   * The name of the copyright holders may not be used to endorse or promote products
+//     derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "../precomp.hpp"
+#include <opencv2/core/ocl.hpp>
+#include "opencl_kernels_dnn.hpp"
+#include "op_im2col.hpp"
+#include "opencl_kernels_dnn.hpp"
+
+namespace cv
+{
+namespace dnn
+{
+
+#ifdef HAVE_OPENCL
+
+bool im2col_ocl(const UMat &img,
+                 int channels, int height, int width,
+                 int kernel_h, int kernel_w,
+                 int pad_h, int pad_w,
+                 int stride_h, int stride_w,
+                 int dilation_h, int dilation_w,
+                 UMat &col)
+{
+    //TODO
+    CV_Assert(dilation_h == 1 && dilation_w == 1);
+
+    int height_col = (height + 2 * pad_h - kernel_h) / stride_h + 1;
+    int width_col = (width + 2 * pad_w - kernel_w) / stride_w + 1;
+    int channels_col = channels * kernel_h * kernel_w;
+    int esz = img.elemSize();
+
+    CV_Assert(img.isContinuous() && col.isContinuous());
+    CV_Assert(img.total() == (size_t)channels * height * width);
+    CV_Assert(col.total() == (size_t)channels_col * height_col * width_col);
+
+    ocl::Kernel ker("im2col", ocl::dnn::im2col_oclsrc, String("-DT=") + ocl::typeToStr(img.type()));
+    if (ker.empty())
+        return false;
+
+    ker.args(ocl::KernelArg::PtrReadOnly(img), (int)img.offset/esz,
+             channels, height, width,
+             kernel_h, kernel_w, pad_h, pad_w, stride_h, stride_w,
+             height_col, width_col,
+             ocl::KernelArg::PtrWriteOnly(col), (int)col.offset/esz
+             );
+
+    size_t localSize = ocl::Device::getDefault().maxWorkGroupSize();
+    size_t globalSize = (size_t)channels * height_col * width_col;
+    return ker.run(1, &globalSize, &localSize, true);
+}
+
+bool col2im_ocl(const UMat &col,
+                int channels, int height, int width,
+                int kernel_h, int kernel_w,
+                int pad_h, int pad_w,
+                int stride_h, int stride_w,
+                UMat &img)
+{
+    int height_col = (height + 2 * pad_h - kernel_h) / stride_h + 1;
+    int width_col = (width + 2 * pad_w - kernel_w) / stride_w + 1;
+    int channels_col = channels * kernel_h * kernel_w;
+    int esz = img.elemSize();
+
+    CV_Assert(img.isContinuous() && col.isContinuous());
+    CV_Assert(img.total() == (size_t)channels * height * width);
+    CV_Assert(col.total() == (size_t)channels_col * height_col * width_col);
+
+    ocl::Kernel ker("col2im", ocl::dnn::col2im_oclsrc, String("-DT=") + ocl::typeToStr(col.type()));
+    if (ker.empty())
+        return false;
+
+    ker.args((int)img.total(),
+             ocl::KernelArg::PtrReadOnly(col), (int)col.offset/esz,
+             height, width, channels,
+             kernel_h, kernel_w,
+             pad_h, pad_w,
+             stride_h, stride_w,
+             height_col, width_col,
+             ocl::KernelArg::PtrWriteOnly(img), (int)img.offset/esz);
+
+    size_t localSize = ocl::Device::getDefault().maxWorkGroupSize();
+    size_t globalSize = img.total();
+    return ker.run(1, &globalSize, &localSize, true);
+}
+
+#endif
+}
+}
+
+namespace cv
+{
+namespace dnn
+{
+
+#ifdef HAVE_OPENCL
+void im2col_ocl(UMat &img,
+                int channels, int height, int width,
+                int kernel_h, int kernel_w,
+                int pad_h, int pad_w,
+                int stride_h, int stride_w,
+                int height_out, int width_out,
+                UMat &col)
+{
+    int h_out = height_out;
+    int w_out = width_out;
+
+    CV_Assert(img.isContinuous() && col.isContinuous());
+    CV_Assert(img.total() == (size_t)channels * height * width);
+    CV_Assert(col.total() == (size_t)channels * kernel_h * kernel_w * h_out * w_out);
+
+    ocl::Kernel im2col_ker("im2col", ocl::dnn::im2col_oclsrc);
+    CV_Assert(!im2col_ker.empty());
+
+    im2col_ker.args(ocl::KernelArg::PtrReadOnly(img), (int)img.offset,
+             channels, height, width,
+             kernel_h, kernel_w, pad_h, pad_w, stride_h, stride_w,
+             h_out, w_out,
+             ocl::KernelArg::PtrWriteOnly(col), (int)col.offset
+        );
+
+    size_t localSize = ocl::Device::getDefault().maxWorkGroupSize();
+    size_t globalSize = (size_t)channels * h_out * w_out;
+
+    CV_Assert(im2col_ker.run(1, &globalSize, &localSize, true));
+}
+#endif // HAVE_OPENCL
+
+}
+}
diff --git a/contrib/modules/dnn/src/layers/op_im2col.hpp b/contrib/modules/dnn/src/layers/op_im2col.hpp
new file mode 100644
index 0000000..b41c684
--- /dev/null
+++ b/contrib/modules/dnn/src/layers/op_im2col.hpp
@@ -0,0 +1,242 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+//  By downloading, copying, installing or using the software you agree to this license.
+//  If you do not agree to this license, do not download, install,
+//  copy or use the software.
+//
+//
+//                           License Agreement
+//                For Open Source Computer Vision Library
+//
+// Copyright (C) 2013, OpenCV Foundation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+//   * Redistribution's of source code must retain the above copyright notice,
+//     this list of conditions and the following disclaimer.
+//
+//   * Redistribution's in binary form must reproduce the above copyright notice,
+//     this list of conditions and the following disclaimer in the documentation
+//     and/or other materials provided with the distribution.
+//
+//   * The name of the copyright holders may not be used to endorse or promote products
+//     derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#ifndef __OPENCV_DNN_LAYERS_IM2COL_HPP__
+#define __OPENCV_DNN_LAYERS_IM2COL_HPP__
+#include <opencv2/core.hpp>
+#include <cstdlib>
+
+namespace cv
+{
+namespace dnn
+{
+
+template <typename Dtype>
+class im2col_CpuPBody : public cv::ParallelLoopBody
+{
+    const Dtype* data_im;
+    int channels, height, width;
+    int kernel_h, kernel_w;
+    int pad_h, pad_w;
+    int stride_h, stride_w;
+    int dilation_h, dilation_w;
+    Dtype* data_col;
+    int height_col, width_col, channels_col;
+
+    im2col_CpuPBody() {}
+public:
+
+    static void run(const Dtype* data_im,
+                    int channels, int height, int width,
+                    int kernel_h, int kernel_w,
+                    int pad_h, int pad_w,
+                    int stride_h, int stride_w,
+                    int dilation_h, int dilation_w,
+                    int height_col, int width_col,
+                    Dtype* data_col)
+    {
+        im2col_CpuPBody<Dtype> t;
+
+        t.data_im = data_im;
+        t.data_col = data_col;
+        t.channels = channels; t.height = height; t.width = width;
+        t.kernel_h = kernel_h; t.kernel_w = kernel_w;
+        t.pad_h = pad_h; t.pad_w = pad_w;
+        t.stride_h = stride_h; t.stride_w = stride_w;
+        t.dilation_h = dilation_h; t.dilation_w = dilation_w;
+
+        t.height_col = height_col;
+        t.width_col = width_col;
+        t.channels_col = channels * kernel_h * kernel_w;
+
+        cv::parallel_for_(Range(0, t.channels_col), t);
+    }
+
+    virtual void operator ()(const Range &r) const
+    {
+        for (int c = r.start; c < r.end; ++c)
+        {
+            int w_offset = c % kernel_w;
+            int h_offset = (c / kernel_w) % kernel_h;
+            int c_im = c / kernel_h / kernel_w;
+            for (int h = 0; h < height_col; ++h)
+            {
+                for (int w = 0; w < width_col; ++w)
+                {
+                    int h_pad = h * stride_h - pad_h + h_offset * dilation_h;
+                    int w_pad = w * stride_w - pad_w + w_offset * dilation_w;
+                    if (h_pad >= 0 && h_pad < height && w_pad >= 0 && w_pad < width)
+                        data_col[(c * height_col + h) * width_col + w] =
+                            data_im[(c_im * height + h_pad) * width + w_pad];
+                    else
+                        data_col[(c * height_col + h) * width_col + w] = 0;
+                }
+            }
+        }
+    }
+};
+
+template <typename Dtype>
+class col2im_CpuPBody : public cv::ParallelLoopBody
+{
+    const Dtype* data_col;
+    int channels, height, width;
+    int kernel_h, kernel_w;
+    int pad_h, pad_w;
+    int stride_h, stride_w;
+    Dtype* data_im;
+    int height_col, width_col;
+
+    col2im_CpuPBody() {}
+
+public:
+
+    static void run(const Dtype* data_col,
+                    int channels, int height, int width,
+                    int kernel_h, int kernel_w,
+                    int pad_h, int pad_w,
+                    int stride_h, int stride_w,
+                    Dtype* data_im)
+    {
+        //TODO: single-threaded version switch
+
+        col2im_CpuPBody t;
+        t.data_col = data_col;
+        t.data_im = data_im;
+        t.channels = channels; t.height = height; t.width = width;
+        t.kernel_h = kernel_h; t.kernel_w = kernel_w;
+        t.pad_h = pad_h; t.pad_w = pad_w;
+        t.stride_h = stride_h; t.stride_w = stride_w;
+        t.height_col = (height + 2 * pad_h - kernel_h) / stride_h + 1;
+        t.width_col = (width + 2 * pad_w - kernel_w) / stride_w + 1;
+        int img_total = channels * height * width;
+
+        cv::parallel_for_(Range(0, img_total), t);
+    }
+
+    virtual void operator ()(const Range &r) const
+    {
+        for (int index = r.start; index < r.end; index++)
+        {
+            Dtype val = 0;
+            int w = index % width + pad_w;
+            int h = (index / width) % height + pad_h;
+            int c = index / (width * height);
+
+            // compute the start and end of the output
+            int w_col_start = (w < kernel_w) ? 0 : (w - kernel_w) / stride_w + 1;
+            int w_col_end = std::min(w / stride_w + 1, width_col);
+            int h_col_start = (h < kernel_h) ? 0 : (h - kernel_h) / stride_h + 1;
+            int h_col_end = std::min(h / stride_h + 1, height_col);
+
+            // equivalent implementation
+            int offset =
+            (c * kernel_h * kernel_w + h * kernel_w + w) * height_col * width_col;
+            int coeff_h_col = (1 - stride_h * kernel_w * height_col) * width_col;
+            int coeff_w_col = (1 - stride_w * height_col * width_col);
+            for (int h_col = h_col_start; h_col < h_col_end; ++h_col) {
+              for (int w_col = w_col_start; w_col < w_col_end; ++w_col) {
+                val += data_col[offset + h_col * coeff_h_col + w_col * coeff_w_col];
+              }
+            }
+            data_im[index] = val;
+        }
+    }
+};
+
+//single-threaded version
+template <typename Dtype>
+void col2im_cpu(const Dtype* data_col,
+                int channels, int height, int width,
+                int kernel_h, int kernel_w,
+                int pad_h, int pad_w,
+                int stride_h, int stride_w,
+                int dilation_h, int dilation_w,
+                Dtype* data_im)
+{
+    int height_col = (height + 2 * pad_h - (dilation_h * (kernel_h - 1) + 1)) / stride_h + 1;
+    int width_col = (width + 2 * pad_w - (dilation_w * (kernel_w - 1) + 1)) / stride_w + 1;
+    int channels_col = channels * kernel_h * kernel_w;
+
+    std::memset(data_im, 0, height * width * channels * sizeof(Dtype));
+
+    for (int c = 0; c < channels_col; ++c)
+    {
+        int w_offset = c % kernel_w;
+        int h_offset = (c / kernel_w) % kernel_h;
+        int c_im = c / kernel_h / kernel_w;
+
+        for (int h = 0; h < height_col; ++h)
+        {
+            for (int w = 0; w < width_col; ++w)
+            {
+                int h_pad = h * stride_h - pad_h + h_offset * dilation_h;
+                int w_pad = w * stride_w - pad_w + w_offset * dilation_w;
+
+                if (h_pad >= 0 && h_pad < height && w_pad >= 0 && w_pad < width)
+                    data_im[(c_im * height + h_pad) * width + w_pad] +=
+                        data_col[(c * height_col + h) * width_col + w];
+            }
+        }
+    }
+}
+
+#ifdef HAVE_OPENCL
+bool im2col_ocl(const UMat &img,
+                int channels, int height, int width,
+                int kernel_h, int kernel_w,
+                int pad_h, int pad_w,
+                int stride_h, int stride_w,
+                int dilation_h, int dilation_w,
+                UMat &col);
+
+bool col2im_ocl(const UMat &col,
+                int channels, int height, int width,
+                int kernel_h, int kernel_w,
+                int pad_h, int pad_w,
+                int stride_h, int stride_w,
+                UMat &img);
+#endif
+
+}
+}
+
+#endif
diff --git a/contrib/modules/dnn/src/layers/permute_layer.cpp b/contrib/modules/dnn/src/layers/permute_layer.cpp
new file mode 100644
index 0000000..41c8399
--- /dev/null
+++ b/contrib/modules/dnn/src/layers/permute_layer.cpp
@@ -0,0 +1,185 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+//  By downloading, copying, installing or using the software you agree to this license.
+//  If you do not agree to this license, do not download, install,
+//  copy or use the software.
+//
+//
+//                           License Agreement
+//                For Open Source Computer Vision Library
+//
+// Copyright (C) 2013, OpenCV Foundation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+//   * Redistribution's of source code must retain the above copyright notice,
+//     this list of conditions and the following disclaimer.
+//
+//   * Redistribution's in binary form must reproduce the above copyright notice,
+//     this list of conditions and the following disclaimer in the documentation
+//     and/or other materials provided with the distribution.
+//
+//   * The name of the copyright holders may not be used to endorse or promote products
+//     derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "../precomp.hpp"
+#include "layers_common.hpp"
+#include "permute_layer.hpp"
+#include <float.h>
+#include <algorithm>
+
+namespace cv
+{
+namespace dnn
+{
+void PermuteLayer::checkCurrentOrder(int currentOrder)
+{
+    if(currentOrder < 0 || currentOrder > 3)
+    {
+        CV_Error(
+            Error::StsBadArg,
+            "Orders of dimensions in Permute layer parameter"
+            "must be in [0...3] interval");
+    }
+
+    if(std::find(_order.begin(), _order.end(), currentOrder) != _order.end())
+    {
+        CV_Error(Error::StsBadArg,
+                 "Permute layer parameter contains duplicated orders.");
+    }
+}
+
+void PermuteLayer::checkNeedForPermutation()
+{
+    _needsPermute = false;
+    for (size_t i = 0; i < _numAxes; ++i)
+    {
+        if (_order[i] != i)
+        {
+            _needsPermute = true;
+            break;
+        }
+    }
+}
+
+PermuteLayer::PermuteLayer(LayerParams &params) : Layer(params)
+{
+    if (!params.has("order"))
+    {
+        _needsPermute = false;
+        return;
+    }
+
+    DictValue paramOrder = params.get("order");
+    if(paramOrder.size() > 4)
+    {
+        CV_Error(
+            Error::StsBadArg,
+            "Too many (> 4) orders of dimensions in Permute layer");
+    }
+
+    _numAxes = paramOrder.size();
+
+    for (size_t i = 0; i < _numAxes; i++)
+    {
+        int currentOrder = paramOrder.get<int>(i);
+        checkCurrentOrder(currentOrder);
+        _order.push_back(currentOrder);
+    }
+
+    checkNeedForPermutation();
+}
+
+void PermuteLayer::computeStrides()
+{
+    _oldStride.resize(_numAxes);
+    _newStride.resize(_numAxes);
+
+    _oldStride[_numAxes - 1] = 1;
+    _newStride[_numAxes - 1] = 1;
+
+    for(int i = _numAxes - 2; i >= 0; i--)
+    {
+        _oldStride[i] = _oldStride[i + 1] * _oldDimensionSize[i + 1];
+        _newStride[i] = _newStride[i + 1] * _newDimensionSize[i + 1];
+    }
+
+    _count = _oldStride[0] * _oldDimensionSize[0];
+}
+
+void PermuteLayer::allocate(const std::vector<Blob*> &inputs, std::vector<Blob> &outputs)
+{
+    if(!_needsPermute)
+    {
+        return;
+    }
+
+    CV_Assert(inputs.size() > 0);
+    CV_Assert((int)_numAxes == inputs[0]->shape().dims());
+
+    outputs.resize(inputs.size());
+
+    _oldDimensionSize = inputs[0]->shape();
+    for (size_t i = 0; i < _numAxes; i++)
+    {
+        _newDimensionSize[i] = _oldDimensionSize[_order[i]];
+    }
+
+    for (size_t i = 0; i < inputs.size(); i++)
+    {
+        CV_Assert(inputs[i]->rows() == _oldDimensionSize[2] && inputs[i]->cols() == _oldDimensionSize[3]);
+        outputs[i].create(BlobShape(_newDimensionSize));
+    }
+
+    computeStrides();
+}
+
+void PermuteLayer::forward(std::vector<Blob*> &inputs, std::vector<Blob> &outputs)
+{
+    if(!_needsPermute)
+    {
+        for (size_t j = 0; j < inputs.size(); j++)
+        {
+            outputs[j].matRef() = inputs[j]->matRef();
+        }
+        return;
+    }
+
+    for (size_t k = 0; k < inputs.size(); k++)
+    {
+        float *srcData = inputs[k]->ptrf();
+        float *dstData = outputs[k].ptrf();
+
+        for (size_t i = 0; i < _count; ++i)
+        {
+            int oldPosition = 0;
+            int newPosition = i;
+
+            for (size_t j = 0; j < _numAxes; ++j)
+            {
+                oldPosition += (newPosition / _newStride[j]) * _oldStride[_order[j]];
+                newPosition %= _newStride[j];
+            }
+            dstData[i] = srcData[oldPosition];
+        }
+    }
+}
+}
+}
diff --git a/contrib/modules/dnn/src/layers/permute_layer.hpp b/contrib/modules/dnn/src/layers/permute_layer.hpp
new file mode 100644
index 0000000..cc51c60
--- /dev/null
+++ b/contrib/modules/dnn/src/layers/permute_layer.hpp
@@ -0,0 +1,75 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+//  By downloading, copying, installing or using the software you agree to this license.
+//  If you do not agree to this license, do not download, install,
+//  copy or use the software.
+//
+//
+//                           License Agreement
+//                For Open Source Computer Vision Library
+//
+// Copyright (C) 2013, OpenCV Foundation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+//   * Redistribution's of source code must retain the above copyright notice,
+//     this list of conditions and the following disclaimer.
+//
+//   * Redistribution's in binary form must reproduce the above copyright notice,
+//     this list of conditions and the following disclaimer in the documentation
+//     and/or other materials provided with the distribution.
+//
+//   * The name of the copyright holders may not be used to endorse or promote products
+//     derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#ifndef __OPENCV_DNN_LAYERS_PERMUTE_LAYER_HPP__
+#define __OPENCV_DNN_LAYERS_PERMUTE_LAYER_HPP__
+#include "../precomp.hpp"
+
+namespace cv
+{
+namespace dnn
+{
+class PermuteLayer : public Layer
+{
+    size_t _count;
+    std::vector<size_t> _order;
+
+    BlobShape _oldDimensionSize;
+    BlobShape _newDimensionSize;
+
+    std::vector<size_t> _oldStride;
+    std::vector<size_t> _newStride;
+    bool _needsPermute;
+
+    size_t _numAxes;
+
+    void checkCurrentOrder(int currentOrder);
+    void checkNeedForPermutation();
+    void computeStrides();
+
+public:
+    PermuteLayer(LayerParams &params);
+    void allocate(const std::vector<Blob*> &inputs, std::vector<Blob> &outputs);
+    void forward(std::vector<Blob*> &inputs, std::vector<Blob> &outputs);
+};
+}
+}
+#endif
diff --git a/contrib/modules/dnn/src/layers/pooling_layer.cpp b/contrib/modules/dnn/src/layers/pooling_layer.cpp
index 840b85f..2e18450 100644
--- a/contrib/modules/dnn/src/layers/pooling_layer.cpp
+++ b/contrib/modules/dnn/src/layers/pooling_layer.cpp
@@ -42,8 +42,10 @@
 #include "../precomp.hpp"
 #include "layers_common.hpp"
 #include "pooling_layer.hpp"
+#include "opencl_kernels_dnn.hpp"
 #include <float.h>
 #include <algorithm>
+#include <opencv2/core/ocl.hpp>
 using std::max;
 using std::min;
 
@@ -53,155 +55,241 @@ namespace dnn
 {
 //TODO: add ceil_mode param
 
-    PoolingLayer::PoolingLayer(LayerParams &params) : Layer(params)
-    {
-        if (params.has("pool"))
-        {
-            String pool = params.get<String>("pool").toLowerCase();
-            if (pool == "max")
-                type = MAX;
-            else if (pool == "ave")
-                type = AVE;
-            else if (pool == "stochastic")
-                type = STOCHASTIC;
-            else
-                CV_Error(cv::Error::StsBadArg, "Unknown pooling type \"" + pool + "\"");
-        }
-        else
-        {
-            type = MAX;
-        }
+PoolingLayerImpl::PoolingLayerImpl()
+{
+    globalPooling = false;
+}
 
-        getKernelParams(params, kernelH, kernelW, padH, padW, strideH, strideW);
-    }
+PoolingLayerImpl::PoolingLayerImpl(int type_, Size kernel_, Size stride_, Size pad_, const String &padMode_)
+{
+    globalPooling = false;
+    type = type_;
+    kernel = kernel_;
+    pad = pad_;
+    stride = stride_;
+    padMode = padMode_;
+}
 
-    void PoolingLayer::allocate(const std::vector<Blob*> &inputs, std::vector<Blob> &outputs)
+void PoolingLayerImpl::allocate(const std::vector<Blob*> &inputs, std::vector<Blob> &outputs)
+{
+    CV_Assert(inputs.size() > 0);
+
+    inp = inputs[0]->size2();
+
+    if(globalPooling)
     {
-        CV_Assert(inputs.size() > 0);
+        kernel = inp;
+    }
 
-        inpW = inputs[0]->cols();
-        inpH = inputs[0]->rows();
-        computeOutputShape(inpH, inpW);
+    computeOutputShape(inp);
 
-        outputs.resize(inputs.size());
-        for (size_t i = 0; i < inputs.size(); i++)
-        {
-            CV_Assert(inputs[i]->rows() == inpH && inputs[i]->cols() == inpW);
-            outputs[i].create(BlobShape(inputs[i]->num(), inputs[i]->channels(), outH, outW));
-        }
+    useOpenCL = ocl::useOpenCL();
+
+    outputs.resize(inputs.size());
+    for (size_t i = 0; i < inputs.size(); i++)
+    {
+        CV_Assert(inputs[i]->rows() == inp.height && inputs[i]->cols() == inp.width);
+        outputs[i].create(BlobShape(inputs[i]->num(), inputs[i]->channels(), out.height, out.width));
     }
+}
 
-    void PoolingLayer::forward(std::vector<Blob*> &inputs, std::vector<Blob> &outputs)
+void PoolingLayerImpl::forward(std::vector<Blob*> &inputs, std::vector<Blob> &outputs)
+{
+    for (size_t ii = 0; ii < inputs.size(); ii++)
     {
-        for (size_t ii = 0; ii < inputs.size(); ii++)
+        switch (type)
         {
-            switch (type)
-            {
-            case MAX:
-                maxPooling(*inputs[ii], outputs[ii]);
-                break;
-            case AVE:
-                avePooling(*inputs[ii], outputs[ii]);
-                break;
-            default:
-                CV_Error(cv::Error::StsNotImplemented, "Not implemented");
-                break;
-            }
+        case MAX:
+            maxPooling(*inputs[ii], outputs[ii]);
+            break;
+        case AVE:
+            avePooling(*inputs[ii], outputs[ii]);
+            break;
+        default:
+            CV_Error(Error::StsNotImplemented, "Not implemented");
+            break;
         }
     }
+}
 
-    void PoolingLayer::maxPooling(Blob &input, Blob &output)
+void PoolingLayerImpl::maxPooling(Blob &src, Blob &dst)
+{
+    if (!useOpenCL)
+        maxPooling_cpu(src, dst);
+    else
     {
-        CV_DbgAssert(output.rows() == outH && output.cols() == outW);
+        CV_Assert(maxPooling_ocl(src, dst));
+    }
+}
+
+bool PoolingLayerImpl::maxPooling_ocl(Blob &src, Blob &dst)
+{
+    return pooling_ocl("MaxPoolForward", src, dst);
+}
 
-        for (int n = 0; n < input.num(); ++n)
+void PoolingLayerImpl::avePooling(Blob &src, Blob &dst)
+{
+    if (!useOpenCL)
+        avePooling_cpu(src, dst);
+    else
+    {
+        CV_Assert(avePooling_ocl(src, dst));
+    }
+}
+
+bool PoolingLayerImpl::avePooling_ocl(Blob &src, Blob &dst)
+{
+    return pooling_ocl("AvePoolForward", src, dst);
+}
+
+void PoolingLayerImpl::maxPooling_cpu(Blob &src, Blob &dst)
+{
+    CV_DbgAssert(dst.rows() == out.height && dst.cols() == out.width);
+
+    for (int n = 0; n < src.num(); ++n)
+    {
+        for (int c = 0; c < src.channels(); ++c)
         {
-            for (int c = 0; c < input.channels(); ++c)
-            {
-                float *srcData = input.ptrf(n, c);
-                float *dstData = output.ptrf(n, c);
+            const float *srcData = src.ptrf(n, c);
+            float *dstData = dst.ptrf(n, c);
 
-                for (int ph = 0; ph < outH; ++ph)
+            for (int ph = 0; ph < out.height; ++ph)
+            {
+                for (int pw = 0; pw < out.width; ++pw)
                 {
-                    for (int pw = 0; pw < outW; ++pw)
-                    {
-                        int hstart = ph * strideH - padH;
-                        int wstart = pw * strideW - padW;
-                        int hend = min(hstart + kernelH, inpH);
-                        int wend = min(wstart + kernelW, inpW);
-                        hstart = max(hstart, 0);
-                        wstart = max(wstart, 0);
-                        const int poolIndex = ph * outW + pw;
-                        float max_val = -FLT_MAX;
-
-                        for (int h = hstart; h < hend; ++h)
-                            for (int w = wstart; w < wend; ++w)
-                            {
-                                const int index = h * inpW + w;
-                                if (srcData[index] > max_val)
-                                    max_val = srcData[index];
-                            }
-
-                        dstData[poolIndex] = max_val;
-                    }
+                    int hstart = ph * stride.height - pad.height;
+                    int wstart = pw * stride.width - pad.width;
+                    int hend = min(hstart + kernel.height, inp.height);
+                    int wend = min(wstart + kernel.width, inp.width);
+                    hstart = max(hstart, 0);
+                    wstart = max(wstart, 0);
+                    const int poolIndex = ph * out.width + pw;
+                    float max_val = -FLT_MAX;
+
+                    for (int h = hstart; h < hend; ++h)
+                        for (int w = wstart; w < wend; ++w)
+                        {
+                            const int index = h * inp.width + w;
+                            if (srcData[index] > max_val)
+                                max_val = srcData[index];
+                        }
+
+                    dstData[poolIndex] = max_val;
                 }
             }
         }
     }
+}
+
+
+#ifdef HAVE_OPENCL
+bool PoolingLayerImpl::pooling_ocl(const char *kname, const Blob &src, Blob &dst, Blob *mask)
+{
+    const UMat &srcMat = src.umatRefConst();
+    UMat &dstMat = dst.umatRef();
+    CV_Assert(mask == NULL && srcMat.offset == 0 && dstMat.offset == 0);
 
-    void PoolingLayer::avePooling(Blob &input, Blob &output)
+    ocl::Kernel ker(kname, ocl::dnn::pooling_oclsrc, String("-DT=") + ocl::typeToStr(src.type()));
+    if (ker.empty())
+        return false;
+
+    BlobShape s = src.shape();
+    size_t nthreads = dst.total();
+    ker.args((int)nthreads,
+             ocl::KernelArg::PtrReadOnly(srcMat), s[0], s[1], s[2], s[3],
+             out.height, out.width, kernel.height, kernel.width,
+             stride.height, stride.width, pad.height, pad.width,
+             ocl::KernelArg::PtrWriteOnly(dstMat));
+
+    size_t wgSize = ocl::Device::getDefault().maxWorkGroupSize();
+    if (!ker.run(1, &nthreads, &wgSize, true))
+        return false;
+
+    return true;
+}
+#else
+bool PoolingLayerImpl::pooling_ocl(const char*, const Blob&, Blob&, Blob*)
+{
+    return false;
+}
+#endif
+
+void PoolingLayerImpl::avePooling_cpu(Blob &src, Blob &dst)
+{
+    for (int n = 0; n < src.num(); ++n)
     {
-        for (int n = 0; n < input.num(); ++n)
+        for (int c = 0; c < src.channels(); ++c)
         {
-            for (int c = 0; c < input.channels(); ++c)
-            {
-                float *srcData = input.ptrf(n, c);
-                float *dstData = output.ptrf(n, c);
+            const float *srcData = src.ptrf(n, c);
+            float *dstData = dst.ptrf(n, c);
 
-                for (int ph = 0; ph < outH; ++ph)
+            for (int ph = 0; ph < out.height; ++ph)
+            {
+                for (int pw = 0; pw < out.width; ++pw)
                 {
-                    for (int pw = 0; pw < outW; ++pw)
-                    {
-                        int hstart = ph * strideH - padH;
-                        int wstart = pw * strideW - padW;
-                        int hend = min(hstart + kernelH, inpH + padH);
-                        int wend = min(wstart + kernelW, inpW + padW);
-                        int poolSize = (hend - hstart) * (wend - wstart);
-                        hstart = max(hstart, 0);
-                        wstart = max(wstart, 0);
-                        hend = min(hend, inpH);
-                        wend = min(wend, inpW);
-
-                        dstData[ph * outW + pw] = 0.f;
-
-                        for (int h = hstart; h < hend; ++h)
-                            for (int w = wstart; w < wend; ++w)
-                                dstData[ph * outW + pw] += srcData[h * inpW + w];
-
-                        dstData[ph * outW + pw] /= poolSize;
-                    }
+                    int hstart = ph * stride.height - pad.height;
+                    int wstart = pw * stride.width - pad.width;
+                    int hend = min(hstart + kernel.height, inp.height + pad.height);
+                    int wend = min(wstart + kernel.width, inp.width + pad.width);
+                    int poolSize = (hend - hstart) * (wend - wstart);
+                    hstart = max(hstart, 0);
+                    wstart = max(wstart, 0);
+                    hend = min(hend, inp.height);
+                    wend = min(wend, inp.width);
+
+                    dstData[ph * out.width + pw] = 0.f;
+
+                    for (int h = hstart; h < hend; ++h)
+                        for (int w = wstart; w < wend; ++w)
+                            dstData[ph * out.width + pw] += srcData[h * inp.width + w];
+
+                    dstData[ph * out.width + pw] /= poolSize;
                 }
-          }
+            }
         }
     }
+}
 
-    void PoolingLayer::computeOutputShape(int inH, int inW)
-    {
+void PoolingLayerImpl::computeOutputShape(Size inpSz)
+{
+    if (padMode.empty()) {
         //Yeah, something strange Caffe scheme-)
-        outH = static_cast<int>(ceil(static_cast<float>(inH + 2 * padH - kernelH) / strideH)) + 1;
-        outW = static_cast<int>(ceil(static_cast<float>(inW + 2 * padW - kernelW) / strideW)) + 1;
+        out.height = static_cast<int>(ceil(static_cast<float>(inpSz.height + 2 * pad.height -
+                                                              kernel.height) / stride.height)) + 1;
+        out.width = static_cast<int>(ceil(static_cast<float>(inpSz.width + 2 * pad.width -
+                                                             kernel.width) / stride.width)) + 1;
 
-        if (padH || padW)
+        if (pad.height || pad.width)
         {
             // If we have padding, ensure that the last pooling starts strictly
             // inside the image (instead of at the padding); otherwise clip the last.
-            if ((outH - 1) * strideH >= inH + padH)
-                --outH;
-            if ((outW - 1) * strideW >= inW + padW)
-                --outW;
-            CV_Assert((outH - 1) * strideH < inH + padH);
-            CV_Assert((outW - 1) * strideW < inW + padW);
+            if ((out.height - 1) * stride.height >= inpSz.height + pad.height)
+                --out.height;
+            if ((out.width - 1) * stride.width >= inpSz.width + pad.width)
+                --out.width;
+            CV_Assert((out.height - 1) * stride.height < inpSz.height + pad.height);
+            CV_Assert((out.width - 1) * stride.width < inpSz.width + pad.width);
         }
     }
+    else
+    {
+        getConvPoolOutParams(inpSz.height, inpSz.width, kernel, stride, pad,
+                             padMode, out.height, out.width);
+    }
+}
+
+Ptr<PoolingLayer> PoolingLayer::create(int type, Size kernel, Size stride, Size pad,
+                                       const String& padMode)
+{
+    return Ptr<PoolingLayer>(new PoolingLayerImpl(type, kernel, stride, pad, padMode));
+}
+
+Ptr<PoolingLayer> PoolingLayer::createGlobal(int type)
+{
+    Ptr<PoolingLayer> l = PoolingLayer::create(type);
+    l->globalPooling = true;
+    return l;
+}
+
 }
 }
diff --git a/contrib/modules/dnn/src/layers/pooling_layer.hpp b/contrib/modules/dnn/src/layers/pooling_layer.hpp
index 1f1a221..c5723cd 100644
--- a/contrib/modules/dnn/src/layers/pooling_layer.hpp
+++ b/contrib/modules/dnn/src/layers/pooling_layer.hpp
@@ -42,37 +42,40 @@
 #ifndef __OPENCV_DNN_LAYERS_POOLING_LAYER_HPP__
 #define __OPENCV_DNN_LAYERS_POOLING_LAYER_HPP__
 #include "../precomp.hpp"
+#include <opencv2/dnn/all_layers.hpp>
 
 namespace cv
 {
 namespace dnn
 {
-    class PoolingLayer : public Layer
-    {
-        enum
-        {
-            MAX,
-            AVE,
-            STOCHASTIC
-        };
 
-        int type;
-        int padH, padW;
-        int strideH, strideW;
-        int kernelH, kernelW;
+class PoolingLayerImpl : public PoolingLayer
+{
+    bool useOpenCL;
+    Size inp, out;
+
+    void computeOutputShape(Size inpSz);
+
+    bool pooling_ocl(const char *kname, const Blob &src, Blob &dst, Blob *mask = NULL);
+
+    void maxPooling(Blob &src, Blob &dst);
+    void maxPooling_cpu(Blob &src, Blob &dst);
+    bool maxPooling_ocl(Blob &src, Blob &dst);
 
-        int inpH, inpW;
-        int outH, outW;
+    void avePooling(Blob &src, Blob &dst);
+    void avePooling_cpu(Blob &src, Blob &dst);
+    bool avePooling_ocl(Blob &src, Blob &dst);
 
-        void computeOutputShape(int inpH, int inpW);
-        void maxPooling(Blob &input, Blob &output);
-        void avePooling(Blob &input, Blob &output);
+public:
+
+    PoolingLayerImpl();
+    PoolingLayerImpl(int type, Size kernel, Size stride, Size pad, const String& padMode);
+
+    void allocate(const std::vector<Blob*> &inputs, std::vector<Blob> &outputs);
+    void forward(std::vector<Blob*> &inputs, std::vector<Blob> &outputs);
+};
 
-    public:
-        PoolingLayer(LayerParams &params);
-        void allocate(const std::vector<Blob*> &inputs, std::vector<Blob> &outputs);
-        void forward(std::vector<Blob*> &inputs, std::vector<Blob> &outputs);
-    };
 }
 }
+
 #endif
diff --git a/contrib/modules/dnn/src/layers/prior_box_layer.cpp b/contrib/modules/dnn/src/layers/prior_box_layer.cpp
new file mode 100644
index 0000000..a5343a4
--- /dev/null
+++ b/contrib/modules/dnn/src/layers/prior_box_layer.cpp
@@ -0,0 +1,307 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+//  By downloading, copying, installing or using the software you agree to this license.
+//  If you do not agree to this license, do not download, install,
+//  copy or use the software.
+//
+//
+//                           License Agreement
+//                For Open Source Computer Vision Library
+//
+// Copyright (C) 2013, OpenCV Foundation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+//   * Redistribution's of source code must retain the above copyright notice,
+//     this list of conditions and the following disclaimer.
+//
+//   * Redistribution's in binary form must reproduce the above copyright notice,
+//     this list of conditions and the following disclaimer in the documentation
+//     and/or other materials provided with the distribution.
+//
+//   * The name of the copyright holders may not be used to endorse or promote products
+//     derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "../precomp.hpp"
+#include "layers_common.hpp"
+#include "prior_box_layer.hpp"
+#include <float.h>
+#include <algorithm>
+#include <cmath>
+
+namespace cv
+{
+namespace dnn
+{
+
+const std::string PriorBoxLayer::_layerName = std::string("PriorBox");
+
+bool PriorBoxLayer::getParameterDict(const LayerParams &params,
+                                     const std::string &parameterName,
+                                     DictValue& result)
+{
+    if (!params.has(parameterName))
+    {
+        return false;
+    }
+
+    result = params.get(parameterName);
+    return true;
+}
+
+template<typename T>
+T PriorBoxLayer::getParameter(const LayerParams &params,
+                              const std::string &parameterName,
+                              const size_t &idx,
+                              const bool required,
+                              const T& defaultValue)
+{
+    DictValue dictValue;
+    bool success = getParameterDict(params, parameterName, dictValue);
+    if(!success)
+    {
+        if(required)
+        {
+            std::string message = _layerName;
+            message += " layer parameter does not contain ";
+            message += parameterName;
+            message += " parameter.";
+            CV_Error(Error::StsBadArg, message);
+        }
+        else
+        {
+            return defaultValue;
+        }
+    }
+    return dictValue.get<T>(idx);
+}
+
+void PriorBoxLayer::getAspectRatios(const LayerParams &params)
+{
+    DictValue aspectRatioParameter;
+    bool aspectRatioRetieved = getParameterDict(params, "aspect_ratio", aspectRatioParameter);
+    CV_Assert(aspectRatioRetieved);
+
+    for (int i = 0; i < aspectRatioParameter.size(); ++i)
+    {
+        float aspectRatio = aspectRatioParameter.get<float>(i);
+        bool alreadyExists = false;
+
+        for (size_t j = 0; j < _aspectRatios.size(); ++j)
+        {
+            if (fabs(aspectRatio - _aspectRatios[j]) < 1e-6)
+            {
+                alreadyExists = true;
+                break;
+            }
+        }
+        if (!alreadyExists)
+        {
+            _aspectRatios.push_back(aspectRatio);
+            if (_flip)
+            {
+                _aspectRatios.push_back(1./aspectRatio);
+            }
+        }
+    }
+}
+
+void PriorBoxLayer::getVariance(const LayerParams &params)
+{
+    DictValue varianceParameter;
+    bool varianceParameterRetrieved = getParameterDict(params, "variance", varianceParameter);
+    CV_Assert(varianceParameterRetrieved);
+
+    int varianceSize = varianceParameter.size();
+    if (varianceSize > 1)
+    {
+        // Must and only provide 4 variance.
+        CV_Assert(varianceSize == 4);
+
+        for (int i = 0; i < varianceSize; ++i)
+        {
+            float variance = varianceParameter.get<float>(i);
+            CV_Assert(variance > 0);
+            _variance.push_back(variance);
+        }
+    }
+    else
+    {
+        if (varianceSize == 1)
+        {
+            float variance = varianceParameter.get<float>(0);
+            CV_Assert(variance > 0);
+            _variance.push_back(variance);
+        }
+        else
+        {
+            // Set default to 0.1.
+            _variance.push_back(0.1f);
+        }
+    }
+}
+
+PriorBoxLayer::PriorBoxLayer(LayerParams &params) : Layer(params)
+{
+    _minSize = getParameter<unsigned>(params, "min_size");
+    CV_Assert(_minSize > 0);
+
+    _flip = getParameter<bool>(params, "flip");
+    _clip = getParameter<bool>(params, "clip");
+
+    _aspectRatios.clear();
+    _aspectRatios.push_back(1.);
+
+    getAspectRatios(params);
+    getVariance(params);
+
+    _numPriors = _aspectRatios.size();
+
+    _maxSize = -1;
+    if (params.has("max_size"))
+    {
+        _maxSize = params.get("max_size").get<float>(0);
+        CV_Assert(_maxSize > _minSize);
+
+        _numPriors += 1;
+    }
+}
+
+void PriorBoxLayer::allocate(const std::vector<Blob*> &inputs, std::vector<Blob> &outputs)
+{
+    CV_Assert(inputs.size() == 2);
+
+    _layerWidth = inputs[0]->cols();
+    _layerHeight = inputs[0]->rows();
+
+    _imageWidth = inputs[1]->cols();
+    _imageHeight = inputs[1]->rows();
+
+    _stepX = static_cast<float>(_imageWidth) / _layerWidth;
+    _stepY = static_cast<float>(_imageHeight) / _layerHeight;
+
+    // Since all images in a batch has same height and width, we only need to
+    // generate one set of priors which can be shared across all images.
+    size_t outNum = 1;
+    // 2 channels. First channel stores the mean of each prior coordinate.
+    // Second channel stores the variance of each prior coordinate.
+    size_t outChannels = 2;
+    _outChannelSize = _layerHeight * _layerWidth * _numPriors * 4;
+
+    outputs[0].create(BlobShape(outNum, outChannels, _outChannelSize));
+    outputs[0].matRef() = 0;
+}
+
+void PriorBoxLayer::forward(std::vector<Blob*> &inputs, std::vector<Blob> &outputs)
+{
+    (void)inputs; // to suppress unused parameter warning
+
+    float* outputPtr = outputs[0].ptrf();
+
+    // first prior: aspect_ratio = 1, size = min_size
+    int idx = 0;
+    for (size_t h = 0; h < _layerHeight; ++h)
+    {
+        for (size_t w = 0; w < _layerWidth; ++w)
+        {
+            _boxWidth = _boxHeight = _minSize;
+
+            float center_x = (w + 0.5) * _stepX;
+            float center_y = (h + 0.5) * _stepY;
+            // xmin
+            outputPtr[idx++] = (center_x - _boxWidth / 2.) / _imageWidth;
+            // ymin
+            outputPtr[idx++] = (center_y - _boxHeight / 2.) / _imageHeight;
+            // xmax
+            outputPtr[idx++] = (center_x + _boxWidth / 2.) / _imageWidth;
+            // ymax
+            outputPtr[idx++] = (center_y + _boxHeight / 2.) / _imageHeight;
+
+            if (_maxSize > 0)
+            {
+                // second prior: aspect_ratio = 1, size = sqrt(min_size * max_size)
+                _boxWidth = _boxHeight = sqrt(_minSize * _maxSize);
+                // xmin
+                outputPtr[idx++] = (center_x - _boxWidth / 2.) / _imageWidth;
+                // ymin
+                outputPtr[idx++] = (center_y - _boxHeight / 2.) / _imageHeight;
+                // xmax
+                outputPtr[idx++] = (center_x + _boxWidth / 2.) / _imageWidth;
+                // ymax
+                outputPtr[idx++] = (center_y + _boxHeight / 2.) / _imageHeight;
+            }
+
+            // rest of priors
+            for (size_t r = 0; r < _aspectRatios.size(); ++r)
+            {
+                float ar = _aspectRatios[r];
+                if (fabs(ar - 1.) < 1e-6)
+                {
+                    continue;
+                }
+                _boxWidth = _minSize * sqrt(ar);
+                _boxHeight = _minSize / sqrt(ar);
+                // xmin
+                outputPtr[idx++] = (center_x - _boxWidth / 2.) / _imageWidth;
+                // ymin
+                outputPtr[idx++] = (center_y - _boxHeight / 2.) / _imageHeight;
+                // xmax
+                outputPtr[idx++] = (center_x + _boxWidth / 2.) / _imageWidth;
+                // ymax
+                outputPtr[idx++] = (center_y + _boxHeight / 2.) / _imageHeight;
+            }
+        }
+    }
+    // clip the prior's coordidate such that it is within [0, 1]
+    if (_clip)
+    {
+        for (size_t d = 0; d < _outChannelSize; ++d)
+        {
+            outputPtr[d] = std::min<float>(std::max<float>(outputPtr[d], 0.), 1.);
+        }
+    }
+    // set the variance.
+    outputPtr = outputs[0].ptrf(0, 1);
+    if(_variance.size() == 1)
+    {
+        Mat secondChannel(outputs[0].rows(), outputs[0].cols(), CV_32F, outputPtr);
+        secondChannel.setTo(Scalar(_variance[0]));
+    }
+    else
+    {
+        int count = 0;
+        for (size_t h = 0; h < _layerHeight; ++h)
+        {
+            for (size_t w = 0; w < _layerWidth; ++w)
+            {
+                for (size_t i = 0; i < _numPriors; ++i)
+                {
+                    for (int j = 0; j < 4; ++j)
+                    {
+                        outputPtr[count] = _variance[j];
+                        ++count;
+                    }
+                }
+            }
+        }
+    }
+}
+}
+}
diff --git a/contrib/modules/dnn/src/layers/prior_box_layer.hpp b/contrib/modules/dnn/src/layers/prior_box_layer.hpp
new file mode 100644
index 0000000..e398aa1
--- /dev/null
+++ b/contrib/modules/dnn/src/layers/prior_box_layer.hpp
@@ -0,0 +1,101 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+//  By downloading, copying, installing or using the software you agree to this license.
+//  If you do not agree to this license, do not download, install,
+//  copy or use the software.
+//
+//
+//                           License Agreement
+//                For Open Source Computer Vision Library
+//
+// Copyright (C) 2013, OpenCV Foundation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+//   * Redistribution's of source code must retain the above copyright notice,
+//     this list of conditions and the following disclaimer.
+//
+//   * Redistribution's in binary form must reproduce the above copyright notice,
+//     this list of conditions and the following disclaimer in the documentation
+//     and/or other materials provided with the distribution.
+//
+//   * The name of the copyright holders may not be used to endorse or promote products
+//     derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#ifndef __OPENCV_DNN_LAYERS_PRIOR_BOX_LAYER_HPP__
+#define __OPENCV_DNN_LAYERS_PRIOR_BOX_LAYER_HPP__
+#include "../precomp.hpp"
+
+namespace cv
+{
+namespace dnn
+{
+class PriorBoxLayer : public Layer
+{
+    size_t _layerWidth;
+    size_t _layerHeight;
+
+    size_t _imageWidth;
+    size_t _imageHeight;
+
+    size_t _outChannelSize;
+
+    float _stepX;
+    float _stepY;
+
+    float _minSize;
+    float _maxSize;
+
+    float _boxWidth;
+    float _boxHeight;
+
+    std::vector<float> _aspectRatios;
+    std::vector<float> _variance;
+
+    bool _flip;
+    bool _clip;
+
+    size_t _numPriors;
+
+    static const size_t _numAxes = 4;
+    static const std::string _layerName;
+
+public:
+    PriorBoxLayer(LayerParams &params);
+    void allocate(const std::vector<Blob*> &inputs, std::vector<Blob> &outputs);
+    void forward(std::vector<Blob*> &inputs, std::vector<Blob> &outputs);
+
+    template<typename T>
+    T getParameter(const LayerParams &params,
+                   const std::string &parameterName,
+                   const size_t &idx = 0,
+                   const bool required = true,
+                   const T& defaultValue = T());
+
+    bool getParameterDict(const LayerParams &params,
+                          const std::string &parameterName,
+                          DictValue& result);
+
+    void getAspectRatios(const LayerParams &params);
+    void getVariance(const LayerParams &params);
+};
+}
+}
+#endif
diff --git a/contrib/modules/dnn/src/layers/recurrent_layers.cpp b/contrib/modules/dnn/src/layers/recurrent_layers.cpp
new file mode 100644
index 0000000..65545fe
--- /dev/null
+++ b/contrib/modules/dnn/src/layers/recurrent_layers.cpp
@@ -0,0 +1,442 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+//  By downloading, copying, installing or using the software you agree to this license.
+//  If you do not agree to this license, do not download, install,
+//  copy or use the software.
+//
+//
+//                           License Agreement
+//                For Open Source Computer Vision Library
+//
+// Copyright (C) 2013, OpenCV Foundation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+//   * Redistribution's of source code must retain the above copyright notice,
+//     this list of conditions and the following disclaimer.
+//
+//   * Redistribution's in binary form must reproduce the above copyright notice,
+//     this list of conditions and the following disclaimer in the documentation
+//     and/or other materials provided with the distribution.
+//
+//   * The name of the copyright holders may not be used to endorse or promote products
+//     derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "../precomp.hpp"
+#include "recurrent_layers.hpp"
+#include "op_blas.hpp"
+#include <iostream>
+#include <cmath>
+#include <opencv2/dnn/shape_utils.hpp>
+
+namespace cv
+{
+namespace dnn
+{
+
+template<typename Dtype>
+static void tanh(const Mat &src, Mat &dst)
+{
+    MatConstIterator_<Dtype> itSrc = src.begin<Dtype>();
+    MatIterator_<Dtype> itDst = dst.begin<Dtype>();
+
+    for (; itSrc != src.end<Dtype>(); itSrc++, itDst++)
+        *itDst = std::tanh(*itSrc);
+}
+
+//TODO: make utils method
+static void tanh(const Mat &src, Mat &dst)
+{
+    dst.create(src.dims, (const int*)src.size, src.type());
+
+    if (src.type() == CV_32F)
+        tanh<float>(src, dst);
+    else if (src.type() == CV_64F)
+        tanh<double>(src, dst);
+    else
+        CV_Error(Error::StsUnsupportedFormat, "Function supports only floating point types");
+}
+
+static void sigmoid(const Mat &src, Mat &dst)
+{
+    cv::exp(-src, dst);
+    cv::pow(1 + dst, -1, dst);
+}
+
+class LSTMLayerImpl : public LSTMLayer
+{
+    int numOut, numTimeStamps, numSamples, numInp;
+    Mat hInternal, cInternal;
+    Mat gates, dummyOnes;
+    int dtype;
+    bool allocated;
+
+    Shape outTailShape;                 //shape of single output sample
+    Shape outTsMatShape, outTsShape;    //shape of N output samples
+    Shape outResShape;                  //shape of T timestamps and N output samples
+
+    bool useTimestampDim;
+    bool produceCellOutput;
+
+public:
+
+    LSTMLayerImpl()
+    {
+        type = "LSTM";
+        useTimestampDim = true;
+        produceCellOutput = false;
+        allocated = false;
+        outTailShape = Shape::empty();
+    }
+
+    void setUseTimstampsDim(bool use)
+    {
+        CV_Assert(!allocated);
+        useTimestampDim = use;
+    }
+
+    void setProduceCellOutput(bool produce)
+    {
+        CV_Assert(!allocated);
+        produceCellOutput = produce;
+    }
+
+    void setC(const Blob &C)
+    {
+        CV_Assert(cInternal.empty() || C.total() == cInternal.total());
+        if (!cInternal.empty())
+            C.reshaped(Shape::like(cInternal)).matRefConst().copyTo(cInternal);
+        else
+            C.matRefConst().copyTo(cInternal);
+    }
+
+    void setH(const Blob &H)
+    {
+        CV_Assert(hInternal.empty() || H.total() == hInternal.total());
+        if (!hInternal.empty())
+            H.reshaped(Shape::like(hInternal)).matRefConst().copyTo(hInternal);
+        else
+            H.matRefConst().copyTo(hInternal);
+    }
+
+    Blob getC() const
+    {
+        CV_Assert(!cInternal.empty());
+
+        //TODO: add convinient Mat -> Blob constructor
+        Blob res(outTsShape, cInternal.type());
+        res.fill(res.shape(), res.type(), cInternal.data);
+        return res;
+    }
+
+    Blob getH() const
+    {
+        CV_Assert(!hInternal.empty());
+
+        Blob res(outTsShape, hInternal.type());
+        res.fill(res.shape(), res.type(), hInternal.data);
+        return res;
+    }
+
+    void setOutShape(const Shape &outTailShape_)
+    {
+        CV_Assert(!allocated || outTailShape_.total() == outTailShape.total());
+        outTailShape = outTailShape_;
+    }
+
+    void setWeights(const Blob &Wh, const Blob &Wx, const Blob &bias)
+    {
+        CV_Assert(Wh.dims() == 2 && Wx.dims() == 2);
+        CV_Assert(Wh.size(0) == Wx.size(0));
+        CV_Assert(Wh.size(0) == 4*Wh.size(1));
+        CV_Assert(Wh.size(0) == (int)bias.total());
+        CV_Assert(Wh.type() == Wx.type() && Wx.type() == bias.type());
+
+        blobs.resize(3);
+        blobs[0] = Wh;
+        blobs[1] = Wx;
+        blobs[2] = bias;
+        blobs[2].reshape(Shape(1, (int)bias.total()));
+    }
+
+    void allocate(const std::vector<Blob*> &input, std::vector<Blob> &output)
+    {
+        CV_Assert(blobs.size() == 3);
+        CV_Assert(input.size() == 1);
+
+        Blob &Wh = blobs[0], &Wx = blobs[1];
+        numOut = Wh.size(1);
+        numInp = Wx.size(1);
+
+        if (!outTailShape.isEmpty())
+            CV_Assert(outTailShape.total() == numOut);
+        else
+            outTailShape = Shape(numOut);
+
+        if (useTimestampDim)
+        {
+            CV_Assert(input[0]->dims() >= 2 && (int)input[0]->total(2) == numInp);
+            numTimeStamps = input[0]->size(0);
+            numSamples = input[0]->size(1);
+            outResShape = Shape(numTimeStamps, numSamples) + outTailShape;
+        }
+        else
+        {
+            CV_Assert(input[0]->dims() >= 1 && (int)input[0]->total(1) == numInp);
+            numTimeStamps = 1;
+            numSamples = input[0]->size(0);
+            outResShape = Shape(numSamples) + outTailShape;
+        }
+        outTsMatShape = Shape(numSamples, numOut);
+        outTsShape = Shape(numSamples) + outTailShape;
+
+        dtype = input[0]->type();
+        CV_Assert(dtype == CV_32F || dtype == CV_64F);
+        CV_Assert(Wh.type() == dtype);
+
+        output.resize( (produceCellOutput) ? 2 : 1 );
+        output[0].create(outResShape, dtype);
+        if (produceCellOutput)
+            output[1].create(outResShape, dtype);
+
+        if (hInternal.empty())
+        {
+            hInternal.create(outTsMatShape.dims(), outTsMatShape.ptr(), dtype);
+            hInternal.setTo(0);
+        }
+        else
+        {
+            CV_Assert((int)hInternal.total() == numSamples*numOut);
+            hInternal = hInternal.reshape(1, outTsMatShape.dims(), outTsMatShape.ptr());
+        }
+
+        if (cInternal.empty())
+        {
+            cInternal.create(outTsMatShape.dims(), outTsMatShape.ptr(), dtype);
+            cInternal.setTo(0);
+        }
+        else
+        {
+            CV_Assert((int)cInternal.total() == numSamples*numOut);
+            cInternal = cInternal.reshape(1, outTsMatShape.dims(), outTsMatShape.ptr());
+        }
+
+        gates.create(numSamples, 4*numOut, dtype);
+
+        dummyOnes.create(numSamples, 1, dtype);
+        dummyOnes.setTo(1);
+
+        allocated = true;
+    }
+
+    void forward(std::vector<Blob*> &input, std::vector<Blob> &output)
+    {
+        const Mat &Wh = blobs[0].getRefConst<Mat>();
+        const Mat &Wx = blobs[1].getRefConst<Mat>();
+        const Mat &bias = blobs[2].getRefConst<Mat>();
+
+        int numSamplesTotal = numTimeStamps*numSamples;
+        Mat xTs = reshaped(input[0]->getRefConst<Mat>(), Shape(numSamplesTotal, numInp));
+
+        Shape outMatShape(numSamplesTotal, numOut);
+        Mat hOutTs = reshaped(output[0].getRef<Mat>(), outMatShape);
+        Mat cOutTs = (produceCellOutput) ? reshaped(output[1].getRef<Mat>(), outMatShape) : Mat();
+
+        for (int ts = 0; ts < numTimeStamps; ts++)
+        {
+            Range curRowRange(ts*numSamples, (ts + 1)*numSamples);
+            Mat xCurr = xTs.rowRange(curRowRange);
+
+            dnn::gemm(xCurr, Wx, 1, gates, 0, GEMM_2_T);      // Wx * x_t
+            dnn::gemm(hInternal, Wh, 1, gates, 1, GEMM_2_T);  //+Wh * h_{t-1}
+            dnn::gemm(dummyOnes, bias, 1, gates, 1);          //+b
+
+            Mat getesIFO = gates.colRange(0, 3*numOut);
+            Mat gateI = gates.colRange(0*numOut, 1*numOut);
+            Mat gateF = gates.colRange(1*numOut, 2*numOut);
+            Mat gateO = gates.colRange(2*numOut, 3*numOut);
+            Mat gateG = gates.colRange(3*numOut, 4*numOut);
+
+            sigmoid(getesIFO, getesIFO);
+            tanh(gateG, gateG);
+
+            //compute c_t
+            cv::multiply(gateF, cInternal, gateF);  // f_t (*) c_{t-1}
+            cv::multiply(gateI, gateG, gateI);      // i_t (*) g_t
+            cv::add(gateF, gateI, cInternal);       // c_t = f_t (*) c_{t-1} + i_t (*) g_t
+
+            //compute h_t
+            tanh(cInternal, hInternal);
+            cv::multiply(gateO, hInternal, hInternal);
+
+            //save results in output blobs
+            hInternal.copyTo(hOutTs.rowRange(curRowRange));
+            if (produceCellOutput)
+                cInternal.copyTo(cOutTs.rowRange(curRowRange));
+        }
+    }
+};
+
+Ptr<LSTMLayer> LSTMLayer::create()
+{
+    return Ptr<LSTMLayer>(new LSTMLayerImpl());
+}
+
+void LSTMLayer::forward(std::vector<Blob*>&, std::vector<Blob>&)
+{
+    CV_Error(Error::StsInternal, "This function should be unreached");
+}
+
+int LSTMLayer::inputNameToIndex(String inputName)
+{
+    if (inputName.toLowerCase() == "x")
+        return 0;
+    return -1;
+}
+
+int LSTMLayer::outputNameToIndex(String outputName)
+{
+    if (outputName.toLowerCase() == "h")
+        return 0;
+    else if (outputName.toLowerCase() == "c")
+        return 1;
+    return -1;
+}
+
+
+class RNNLayerImpl : public RNNLayer
+{
+    int numX, numH, numO;
+    int numSamples, numTimestamps, numSamplesTotal;
+    int dtype;
+    Mat Whh, Wxh, bh;
+    Mat Who, bo;
+    Mat hCurr, hPrev, dummyBiasOnes;
+    bool produceH;
+
+public:
+
+    RNNLayerImpl()
+    {
+        type = "RNN";
+        produceH = false;
+    }
+
+    void setProduceHiddenOutput(bool produce = false)
+    {
+        produceH = produce;
+    }
+
+    void setWeights(const Blob &W_xh, const Blob &b_h, const Blob &W_hh, const Blob &W_ho, const Blob &b_o)
+    {
+        CV_Assert(W_hh.dims() == 2 && W_xh.dims() == 2);
+        CV_Assert(W_hh.size(0) == W_xh.size(0) && W_hh.size(0) == W_hh.size(1) && (int)b_h.total() == W_xh.size(0));
+        CV_Assert(W_ho.size(0) == (int)b_o.total());
+        CV_Assert(W_ho.size(1) == W_hh.size(1));
+
+        blobs.resize(5);
+        blobs[0] = W_xh;
+        blobs[1] = b_h;
+        blobs[2] = W_hh;
+        blobs[3] = W_ho;
+        blobs[4] = b_o;
+    }
+
+    void allocate(const std::vector<Blob*> &input, std::vector<Blob> &output)
+    {
+        CV_Assert(input.size() >= 1 && input.size() <= 2);
+
+        Wxh = blobs[0].matRefConst();
+        bh  = blobs[1].matRefConst();
+        Whh = blobs[2].matRefConst();
+        Who = blobs[3].matRefConst();
+        bo  = blobs[4].matRefConst();
+
+        numH = Wxh.rows;
+        numX = Wxh.cols;
+        numO = Who.rows;
+
+        CV_Assert(input[0]->dims() >= 2);
+        CV_Assert((int)input[0]->total(2) == numX);
+        CV_Assert(input[0]->type() == CV_32F || input[0]->type() == CV_64F);
+        dtype = input[0]->type();
+        numTimestamps = input[0]->size(0);
+        numSamples = input[0]->size(1);
+        numSamplesTotal = numTimestamps * numSamples;
+
+        hCurr.create(numSamples, numH, dtype);
+        hPrev.create(numSamples, numH, dtype);
+        hPrev.setTo(0);
+
+        dummyBiasOnes.create(numSamples, 1, dtype);
+        dummyBiasOnes.setTo(1);
+        bh = bh.reshape(1, 1); //is 1 x numH Mat
+        bo = bo.reshape(1, 1); //is 1 x numO Mat
+
+        reshapeOutput(output);
+    }
+
+    void reshapeOutput(std::vector<Blob> &output)
+    {
+        output.resize((produceH) ? 2 : 1);
+        output[0].create(Shape(numTimestamps, numSamples, numO), dtype);
+        if (produceH)
+            output[1].create(Shape(numTimestamps, numSamples, numH), dtype);
+    }
+
+    void forward(std::vector<Blob*> &input, std::vector<Blob> &output)
+    {
+        Mat xTs = reshaped(input[0]->getRefConst<Mat>(), Shape(numSamplesTotal, numX));
+        Mat oTs = reshaped(output[0].getRef<Mat>(), Shape(numSamplesTotal, numO));
+        Mat hTs = (produceH) ? reshaped(output[1].getRef<Mat>(), Shape(numSamplesTotal, numH)) : Mat();
+
+        for (int ts = 0; ts < numTimestamps; ts++)
+        {
+            Range curRowRange = Range(ts * numSamples, (ts + 1) * numSamples);
+            Mat xCurr = xTs.rowRange(curRowRange);
+
+            dnn::gemm(hPrev, Whh, 1, hCurr, 0, GEMM_2_T); // W_{hh} * h_{prev}
+            dnn::gemm(xCurr, Wxh, 1, hCurr, 1, GEMM_2_T); //+W_{xh} * x_{curr}
+            dnn::gemm(dummyBiasOnes, bh, 1, hCurr, 1);    //+bh
+            tanh(hCurr, hPrev);
+
+            Mat oCurr = oTs.rowRange(curRowRange);
+            dnn::gemm(hPrev, Who, 1, oCurr, 0, GEMM_2_T); // W_{ho} * h_{prev}
+            dnn::gemm(dummyBiasOnes, bo, 1, oCurr, 1);    //+b_o
+            tanh(oCurr, oCurr);
+
+            if (produceH)
+                hPrev.copyTo(hTs.rowRange(curRowRange));
+        }
+    }
+};
+
+void RNNLayer::forward(std::vector<Blob*>&, std::vector<Blob>&)
+{
+    CV_Error(Error::StsInternal, "This function should be unreached");
+}
+
+CV_EXPORTS_W Ptr<RNNLayer> RNNLayer::create()
+{
+    return Ptr<RNNLayer>(new RNNLayerImpl());
+}
+
+}
+}
diff --git a/contrib/modules/dnn/src/layers/recurrent_layers.hpp b/contrib/modules/dnn/src/layers/recurrent_layers.hpp
new file mode 100644
index 0000000..5445121
--- /dev/null
+++ b/contrib/modules/dnn/src/layers/recurrent_layers.hpp
@@ -0,0 +1,54 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+//  By downloading, copying, installing or using the software you agree to this license.
+//  If you do not agree to this license, do not download, install,
+//  copy or use the software.
+//
+//
+//                           License Agreement
+//                For Open Source Computer Vision Library
+//
+// Copyright (C) 2013, OpenCV Foundation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+//   * Redistribution's of source code must retain the above copyright notice,
+//     this list of conditions and the following disclaimer.
+//
+//   * Redistribution's in binary form must reproduce the above copyright notice,
+//     this list of conditions and the following disclaimer in the documentation
+//     and/or other materials provided with the distribution.
+//
+//   * The name of the copyright holders may not be used to endorse or promote products
+//     derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#ifndef __OPENCV_DNN_LAYERS_RECURRENT_LAYERS_HPP__
+#define __OPENCV_DNN_LAYERS_RECURRENT_LAYERS_HPP__
+#include "../precomp.hpp"
+#include <opencv2/dnn/all_layers.hpp>
+
+namespace cv
+{
+namespace dnn
+{
+
+}
+}
+#endif
\ No newline at end of file
diff --git a/contrib/modules/dnn/src/layers/reshape_layer.cpp b/contrib/modules/dnn/src/layers/reshape_layer.cpp
index f5d4b1c..6bc9ebc 100644
--- a/contrib/modules/dnn/src/layers/reshape_layer.cpp
+++ b/contrib/modules/dnn/src/layers/reshape_layer.cpp
@@ -42,125 +42,82 @@
 #include "../precomp.hpp"
 #include "layers_common.hpp"
 #include "reshape_layer.hpp"
+#include <opencv2/dnn/shape_utils.hpp>
 
 namespace cv
 {
 namespace dnn
 {
 
-ReshapeLayer::ReshapeLayer(LayerParams &params) : Layer(params)
+ReshapeLayerImpl::ReshapeLayerImpl(const BlobShape &newShape_, Range applyingRange_, bool enableReordering_) :
+    enableReordering(enableReordering_)
 {
-    inAxis = params.get<int>("axis", 0);
-    inNumAxes = params.get<int>("num_axes", -1);
-    CV_Assert(inNumAxes >= -1);
-
-    autoAxisIdx = -1;
-
-    if (!params.has("dim"))
-    {
-        shapeDesc = BlobShape(0);
-        return;
-    }
-
-    DictValue paramShape = params.get("dim");
-    shapeDesc = BlobShape(paramShape.size());
-
-    for (int i = 0; i < paramShape.size(); i++)
-    {
-        int dim = paramShape.get<int>(i);
-        CV_Assert(dim >= -1);
-
-        if (dim == -1)
-        {
-            if (autoAxisIdx != -1)
-                CV_Error(Error::StsBadArg, "New shape contains multiple -1 dims");
-            autoAxisIdx = i;
-        }
-
-        shapeDesc[i] = dim;
-    }
+    newShapeDesc = newShape_;
+    newShapeRange = applyingRange_;
 }
 
-void ReshapeLayer::allocate(const std::vector<Blob*> &inputs, std::vector<Blob> &outputs)
+void ReshapeLayerImpl::allocate(const std::vector<Blob*> &inputs, std::vector<Blob> &outputs)
 {
     outputs.resize(inputs.size());
+    outShapes.resize(inputs.size());
 
     for (size_t i = 0; i < inputs.size(); i++)
     {
-        Blob &inpBlob = *inputs[i];
-        Blob &outBlob = outputs[i];
-        BlobShape inpShape = inpBlob.shape();
-
-        int startAxis = (inAxis >= 0) ? inAxis : inpShape.dims() + 1 + inAxis;
-        int endAxis = (inNumAxes == -1) ? inpShape.dims() : startAxis + inNumAxes;
-        CV_Assert(0 <= startAxis && startAxis <= inpShape.dims());
-        CV_Assert(0 <= endAxis && endAxis <= inpShape.dims());
-
-        int newDims = inpShape.dims() - (endAxis - startAxis) + shapeDesc.dims();
-        BlobShape outShape(newDims);
-
-        computeOutputShape(startAxis, endAxis, inpShape, outShape);
-
-        outBlob.shareFrom(inpBlob);
-        outBlob.reshape(outShape);
+        outShapes[i] = computeShapeByReshapeMask(inputs[i]->shape(), newShapeDesc, newShapeRange);
+        outputs[i].shareFrom(*inputs[i]);
+        outputs[i].reshape(outShapes[i]);
     }
 }
 
-void ReshapeLayer::computeOutputShape(int startAxis, int endAxis, BlobShape &inpShape, BlobShape &outShape)
+void ReshapeLayerImpl::forward(std::vector<Blob*> &inputs, std::vector<Blob> &outputs)
 {
-    int idx = 0;
-    for (int i = 0; i < startAxis; i++)
-        outShape[idx++] = inpShape[i];
-
-    for (int i = 0; i < shapeDesc.dims(); i++)
+    for (size_t i = 0; i < outputs.size(); i++)
     {
-        if (shapeDesc[i] == 0)
-        {
-            int inpAxisIdx = startAxis + i;
-            if (inpAxisIdx < 0 || inpShape.dims() <= inpAxisIdx)
-                CV_Error(Error::StsOutOfRange, "copy dimension (which has zero size) is not presented into reshaped blob");
-            outShape[idx++] = inpShape[startAxis + i];
-        }
-        else
-        {
-            outShape[idx++] = (shapeDesc[i] > 0) ? shapeDesc[i] : 1;
-        }
-    }
+        Blob& srcBlob = *inputs[i];
+        BlobShape inputShape = inputs[i]->shape();
+        bool channelsReduced = inputShape.dims() > outShapes[i].dims() ||
+                (inputShape.dims() == 4 && inputShape[1] > outShapes[i][1]);
+        bool performReordering = enableReordering && inputShape.dims() == 4 && channelsReduced;
 
-    for (int i = endAxis; i < inpShape.dims(); i++)
-        outShape[idx++] = inpShape[i];
-
-    if (autoAxisIdx >= 0)
-    {
-        size_t total = inpShape.total();
-        size_t curTotal = 1;
-        for (int i = 0; i < outShape.dims(); i++)
+        if (performReordering)
         {
-            if (i != startAxis + autoAxisIdx)
-                curTotal *= outShape[i];
+            Blob reordered_blob(inputShape, inputs[i]->type());
+
+            float *dstData = reordered_blob.matRef().ptr<float>();
+            const float *srcData = srcBlob.matRefConst().ptr<float>();
+
+            int num = inputShape[0], channels = inputShape[1], height = inputShape[2], width = inputShape[3];
+            int total = num*channels*height*width;
+            for(int i_n = 0; i_n < num; i_n++) {
+                for(int i_c = 0; i_c < channels; i_c++) {
+                    for(int i_h = 0; i_h < height; i_h++) {
+                        for(int i_w = 0; i_w < width; i_w++) {
+                           int src_i = channels*height*width*i_n + height*width*i_c + width*i_h + i_w;
+                           int dst_i = channels*height*width*i_n + i_c + channels*width*i_h + channels*i_w;
+
+                           CV_Assert(dst_i < total);
+                           CV_Assert(src_i < total);
+
+                           dstData[dst_i] = srcData[src_i];
+                        }
+                    }
+                }
+            }
+
+            srcBlob = reordered_blob;
         }
 
-        CV_DbgAssert(curTotal <= total && total % curTotal == 0);
-
-        outShape[startAxis + autoAxisIdx] = (int)(total / curTotal);
-    }
-
-    if (inpShape.total() != outShape.total())
-    {
-        CV_Error(Error::StsUnmatchedSizes, "Mismatch between input and output blob elements count");
+        outputs[i].shareFrom(srcBlob);
+        outputs[i].reshape(outShapes[i]);
     }
 }
 
-
-Ptr<Layer> createFlattenLayer(LayerParams&)
+Ptr<ReshapeLayer> ReshapeLayer::create(const BlobShape &newShape, Range applyingRange /*= Range::all()*/,
+                                       bool enableReordering /*= false*/)
 {
-    LayerParams params;
-
-    int shapeDesc[] = {0, -1};
-    params.set("dim", DictValue::arrayInt(shapeDesc, 2));
-
-    return Ptr<Layer>(new ReshapeLayer(params));
+    return Ptr<ReshapeLayer>(new ReshapeLayerImpl(newShape, applyingRange, enableReordering));
 }
 
+
 }
 }
diff --git a/contrib/modules/dnn/src/layers/reshape_layer.hpp b/contrib/modules/dnn/src/layers/reshape_layer.hpp
index 0c3881c..10718b8 100644
--- a/contrib/modules/dnn/src/layers/reshape_layer.hpp
+++ b/contrib/modules/dnn/src/layers/reshape_layer.hpp
@@ -42,30 +42,29 @@
 #ifndef __OPENCV_DNN_LAYERS_RESHAPE_LAYER_HPP__
 #define __OPENCV_DNN_LAYERS_RESHAPE_LAYER_HPP__
 #include "../precomp.hpp"
+#include <opencv2/dnn/all_layers.hpp>
 
 namespace cv
 {
 namespace dnn
 {
 
-class ReshapeLayer : public Layer
+class ReshapeLayerImpl : public ReshapeLayer
 {
+    std::vector<BlobShape> outShapes;
+    bool enableReordering;
+
 public:
-    ReshapeLayer(LayerParams &params);
+    ReshapeLayerImpl(const BlobShape &newShape_, Range applyingRange_, bool enableReordering_);
 
     void allocate(const std::vector<Blob*> &inputs, std::vector<Blob> &outputs);
 
-    void forward(std::vector<Blob*>&, std::vector<Blob>&) {}
-
-protected:
-    BlobShape shapeDesc;
-    int inAxis, inNumAxes, autoAxisIdx;
-
-    void computeOutputShape(int startAxis, int endAxis, BlobShape &inpShape, BlobShape &outShape);
+    void forward(std::vector<Blob*> &inputs, std::vector<Blob> &outputs);
 };
 
 Ptr<Layer> createFlattenLayer(LayerParams&);
 
 }
 }
+
 #endif
diff --git a/contrib/modules/dnn/src/layers/shift_layer.cpp b/contrib/modules/dnn/src/layers/shift_layer.cpp
new file mode 100644
index 0000000..98bfdfc
--- /dev/null
+++ b/contrib/modules/dnn/src/layers/shift_layer.cpp
@@ -0,0 +1,157 @@
+// This file is part of OpenCV project.
+// It is subject to the license terms in the LICENSE file found in the top-level directory
+// of this distribution and at http://opencv.org/license.html.
+
+// Copyright (C) 2016, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+
+/*
+Implementation of shift layer, which adds up const values to blob.
+*/
+
+#include "../precomp.hpp"
+#include "shift_layer.hpp"
+#include "op_blas.hpp"
+
+namespace cv
+{
+namespace dnn
+{
+
+class ShiftLayerImpl {
+public:
+    static Ptr<ShiftLayerImpl> create(const std::vector<Blob*> &inputs, std::vector<Blob> &outputs,
+                                          const std::vector<Blob>& blobs);
+
+    virtual ~ShiftLayerImpl() {}
+
+    virtual void forward(std::vector<Blob*> &inputs, std::vector<Blob> &outputs, const std::vector<Blob>& blobs) = 0;
+
+protected:
+    ShiftLayerImpl() {}
+    virtual void allocate(const std::vector<Blob*> &inputs, std::vector<Blob> &outputs, const std::vector<Blob>& blobs) = 0;
+};
+
+namespace {
+
+class ShiftChannelsLayerImpl : public ShiftLayerImpl {
+public:
+    virtual void forward(std::vector<Blob*> &inputs, std::vector<Blob> &outputs, const std::vector<Blob>& blobs) {
+        for (size_t ii = 0; ii < outputs.size(); ii++)
+        {
+          Blob &inpBlob = *inputs[ii];
+          Blob &outBlob = outputs[ii];
+
+          inpBlob.matRef().copyTo(outBlob.matRef());
+
+          for (int n = 0; n < inpBlob.num(); n++)
+          {
+            Mat dstMat(inpBlob.channels(), inpBlob.rows() * inpBlob.cols(),
+                       outBlob.type(), outBlob.ptr(n));
+           dnn::gemm(blobs[0].matRefConst(), biasOnesMat, 1, dstMat, 1); //TODO: gemv
+          }
+        }
+    }
+
+protected:
+    virtual void allocate(const std::vector<Blob*> &inputs, std::vector<Blob> &outputs, const std::vector<Blob>& blobs) {
+        CV_Assert(inputs.size() > 0);
+
+        const Blob &inpBlob = *inputs[0];
+        CV_Assert(inpBlob.dims() == 4 && inpBlob.type() == CV_32F);
+        const Blob &biasBlob = blobs[0];
+        CV_Assert(biasBlob.total() == (size_t)inpBlob.channels());
+
+        outputs.resize(inputs.size());
+        for (size_t i = 0; i < inputs.size(); i++)
+        {
+            CV_Assert(inputs[i]->type() == inpBlob.type());
+            CV_Assert(inputs[i]->dims() == 4 && inputs[i]->channels() == inpBlob.channels());
+
+            outputs[i].shareFrom(*inputs[i]);
+        }
+
+        biasOnesMat = Mat::ones(1, inpBlob.rows() * inpBlob.cols(), inpBlob.type());
+    }
+
+private:
+    Mat biasOnesMat;
+};
+
+
+class ShiftElementsLayerImpl : public ShiftLayerImpl {
+public:
+    virtual void forward(std::vector<Blob*> &inputs, std::vector<Blob> &outputs, const std::vector<Blob>& blobs) {
+        for (size_t ii = 0; ii < outputs.size(); ii++)
+        {
+          Blob &inpBlob = *inputs[ii];
+          Blob &outBlob = outputs[ii];
+
+          outBlob.matRef() = inpBlob.matRef() + blobs[0].matRefConst();
+        }
+    }
+
+protected:
+    virtual void allocate(const std::vector<Blob*> &inputs, std::vector<Blob> &outputs, const std::vector<Blob>& blobs) {
+        CV_Assert(inputs.size() > 0);
+
+        const Blob &inpBlob = *inputs[0];
+        CV_Assert(inpBlob.type() == CV_32F);
+        const Blob &biasBlob = blobs[0];
+        CV_Assert(biasBlob.dims() == inpBlob.dims());
+
+        outputs.resize(inputs.size());
+        for (size_t i = 0; i < inputs.size(); i++)
+        {
+            CV_Assert(inputs[i]->type() == inpBlob.type());
+            CV_Assert(inputs[i]->dims() == inpBlob.dims());
+
+            outputs[i].shareFrom(*inputs[i]);
+        }
+    }
+};
+
+}
+
+Ptr<ShiftLayerImpl> ShiftLayerImpl::create(const std::vector<Blob*> &inputs, std::vector<Blob> &outputs,
+                                      const std::vector<Blob>& blobs) {
+    Ptr<ShiftLayerImpl> impl;
+
+    CV_Assert(inputs.size() > 0);
+    CV_Assert(blobs.size() > 0);
+
+    if(inputs[0]->dims() == blobs[0].dims())
+        impl = Ptr<ShiftLayerImpl>(new ShiftElementsLayerImpl);
+    else
+        impl = Ptr<ShiftLayerImpl>(new ShiftChannelsLayerImpl);
+
+    impl->allocate(inputs, outputs, blobs);
+    return impl;
+}
+
+ShiftLayer::ShiftLayer(LayerParams &params) : Layer(params)
+{
+    CV_Assert(blobs.size() == 1);
+
+    #ifdef HAVE_LAPACK
+    {
+        if (getBlasThreads() != cv::getThreadNum())
+        {
+            setBlasThreads(cv::getThreadNum());
+        }
+    }
+    #endif
+}
+
+void ShiftLayer::allocate(const std::vector<Blob*> &inputs, std::vector<Blob> &outputs)
+{
+    impl = ShiftLayerImpl::create(inputs, outputs, blobs);
+}
+
+void ShiftLayer::forward(std::vector<Blob*> &inputs, std::vector<Blob> &outputs)
+{
+    impl->forward(inputs, outputs, blobs);
+}
+
+}
+}
diff --git a/contrib/modules/dnn/src/layers/shift_layer.hpp b/contrib/modules/dnn/src/layers/shift_layer.hpp
new file mode 100644
index 0000000..1d1c70a
--- /dev/null
+++ b/contrib/modules/dnn/src/layers/shift_layer.hpp
@@ -0,0 +1,36 @@
+// This file is part of OpenCV project.
+// It is subject to the license terms in the LICENSE file found in the top-level directory
+// of this distribution and at http://opencv.org/license.html.
+
+// Copyright (C) 2016, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+
+/*
+Declaration of shift layer, which adds up const values to blob.
+*/
+
+#ifndef __OPENCV_DNN_LAYERS_SHIFT_LAYER_HPP__
+#define __OPENCV_DNN_LAYERS_SHIFT_LAYER_HPP__
+#include "../precomp.hpp"
+
+namespace cv
+{
+namespace dnn
+{
+
+class ShiftLayerImpl;
+
+class ShiftLayer : public Layer
+{
+    cv::Ptr<ShiftLayerImpl> impl;
+
+public:
+    ShiftLayer() {}
+    ShiftLayer(LayerParams &params);
+    void allocate(const std::vector<Blob*> &inputs, std::vector<Blob> &outputs);
+    void forward(std::vector<Blob*> &inputs, std::vector<Blob> &outputs);
+};
+
+}
+}
+#endif
diff --git a/contrib/modules/dnn/src/layers/slice_layer.cpp b/contrib/modules/dnn/src/layers/slice_layer.cpp
index 68051e8..01dc27f 100644
--- a/contrib/modules/dnn/src/layers/slice_layer.cpp
+++ b/contrib/modules/dnn/src/layers/slice_layer.cpp
@@ -42,55 +42,57 @@
 #include "../precomp.hpp"
 #include "layers_common.hpp"
 #include "slice_layer.hpp"
+#include <opencv2/core/ocl.hpp>
+#include <opencv2/dnn/shape_utils.hpp>
 
 namespace cv
 {
 namespace dnn
 {
 
-SliceLayer::SliceLayer(LayerParams &params) : Layer(params)
+SliceLayerImpl::SliceLayerImpl(int axis_ /*= 1*/)
 {
-    inAxis = params.get<int>("axis", 1);
-
-    if (!params.has("slice_point"))
-        return;
+    axis = axis_;
+}
 
-    const DictValue &_slicePoints = params.get("slice_point");
-    slicePoints.resize(_slicePoints.size());
-    for (int i = 0; i < _slicePoints.size(); i++)
-    {
-        slicePoints[i] = _slicePoints.get<int>(i);
-        CV_Assert(slicePoints[i] > 0 && (i == 0 || slicePoints[i-1] < slicePoints[i]));
-    }
+SliceLayerImpl::SliceLayerImpl(int axis_, const std::vector<int> &sliceIndices_)
+{
+    axis = axis_;
+    sliceIndices = sliceIndices_;
 }
 
-void SliceLayer::allocate(const std::vector<Blob*> &inputs, std::vector<Blob> &outputs)
+void SliceLayerImpl::allocate(const std::vector<Blob*> &inputs, std::vector<Blob> &outputs)
 {
     CV_Assert(inputs.size() == 1);
 
-    const Blob inpBlob = *inputs[0];
-    int axis = inpBlob.canonicalAxis(inAxis);
-    int axisSize = inpBlob.size(axis);
+    const Blob &inpBlob = *inputs[0];
+    useOpenCL = ocl::useOpenCL() && inpBlob.getState() == Blob::HEAD_AT_UMAT;
+
+    axisIdx = inpBlob.canonicalAxis(axis);
+    int axisSize = inpBlob.size(axisIdx);
     BlobShape inpShape = inpBlob.shape();
+    int allocFlags = useOpenCL ? Blob::ALLOC_UMAT : Blob::ALLOC_MAT;
 
-    if (slicePoints.size()) //divide blob with respect to passed parameters
+    if (sliceIndices.size()) //divide blob with respect to passed parameters
     {
         std::vector<int> outAxisSize;
         int prevSlice = 0;
 
-        for (size_t i = 0; i < slicePoints.size(); i++)
+        for (size_t i = 0; i < sliceIndices.size(); i++)
         {
-            CV_Assert(prevSlice < slicePoints[i] && slicePoints[i] < axisSize);
-            outAxisSize.push_back(slicePoints[i] - prevSlice);
-            prevSlice = slicePoints[i];
+            if (!(prevSlice < sliceIndices[i] && sliceIndices[i] < axisSize))
+                CV_Error(Error::StsBadArg, "Slice indices should be positive, increased and don't exceed size of sliced dimension");
+
+            outAxisSize.push_back(sliceIndices[i] - prevSlice);
+            prevSlice = sliceIndices[i];
         }
         outAxisSize.push_back(axisSize - prevSlice);
 
         outputs.resize(outAxisSize.size());
         for (size_t i = 0; i < outAxisSize.size(); i++)
         {
-            inpShape[axis] = outAxisSize[i];
-            outputs[i].create(inpShape, inpBlob.type());
+            inpShape[axisIdx] = outAxisSize[i];
+            outputs[i].create(inpShape, inpBlob.type(), allocFlags);
         }
     }
     else //divide blob with respect to count of output blobs
@@ -100,30 +102,45 @@ void SliceLayer::allocate(const std::vector<Blob*> &inputs, std::vector<Blob> &o
 
         for (size_t i = 0; i < outputs.size(); i++)
         {
-            inpShape[axis] = outAxisSize;
-            outputs[i].create(inpShape, inpBlob.type());
+            inpShape[axisIdx] = outAxisSize;
+            outputs[i].create(inpShape, inpBlob.type(), allocFlags);
         }
     }
 }
 
-void SliceLayer::forward(std::vector<Blob*> &inputs, std::vector<Blob> &outputs)
+void SliceLayerImpl::forward(std::vector<Blob*> &inputs, std::vector<Blob> &outputs)
+{
+    #ifdef HAVE_OPENCL
+    if (useOpenCL)
+        forward_<UMat>(inputs, outputs);
+    else
+    #endif
+        forward_<Mat>(inputs, outputs);
+}
+
+template<typename XMat>
+void SliceLayerImpl::forward_(std::vector<Blob*> &inputs, std::vector<Blob> &outputs)
 {
-    Blob &inpBlob = *inputs[0];
-    const int axis = inpBlob.canonicalAxis(inAxis);
-    const Mat& inpMat = inpBlob.matRef();
+    const XMat& inpMat = inputs[0]->getRefConst<XMat>();
+    std::vector<Range> ranges(inputs[0]->dims(), Range::all());
 
-    std::vector<Range> ranges(inpBlob.dims(), Range::all());
-    int sizeStart = 0;
+    ranges[axisIdx].start = 0;
     for (size_t i = 0; i < outputs.size(); i++)
     {
-        int sizeEnd = sizeStart + outputs[i].size(axis);
-        ranges[axis] = Range(sizeStart, sizeEnd);
+        ranges[axisIdx].end = ranges[axisIdx].start + outputs[i].size(axisIdx);
+        inpMat(&ranges[0]).copyTo(outputs[i].getRef<XMat>());
+        ranges[axisIdx].start = ranges[axisIdx].end;
+    }
+}
 
-        Mat inpSubMat = inpMat(&ranges[0]);
-        inpSubMat.copyTo(outputs[i].matRef());
+Ptr<SliceLayer> SliceLayer::create(int axis)
+{
+    return Ptr<SliceLayer>(new SliceLayerImpl(axis));
+}
 
-        sizeStart = sizeEnd;
-    }
+Ptr<SliceLayer> SliceLayer::create(int axis, const std::vector<int> &sliceIndices)
+{
+    return Ptr<SliceLayer>(new SliceLayerImpl(axis, sliceIndices));
 }
 
 }
diff --git a/contrib/modules/dnn/src/layers/slice_layer.hpp b/contrib/modules/dnn/src/layers/slice_layer.hpp
index 9f15840..4f7cbb3 100644
--- a/contrib/modules/dnn/src/layers/slice_layer.hpp
+++ b/contrib/modules/dnn/src/layers/slice_layer.hpp
@@ -42,24 +42,28 @@
 #ifndef __OPENCV_DNN_LAYERS_SLICE_LAYER_HPP__
 #define __OPENCV_DNN_LAYERS_SLICE_LAYER_HPP__
 #include "../precomp.hpp"
+#include <opencv2/dnn/all_layers.hpp>
 
 namespace cv
 {
 namespace dnn
 {
 
-class SliceLayer : public Layer
+class SliceLayerImpl : public SliceLayer
 {
+    bool useOpenCL;
+    int axisIdx;
+
+    template<typename XMat>
+    void forward_(std::vector<Blob*> &inputs, std::vector<Blob> &outputs);
+
 public:
-    SliceLayer(LayerParams &params);
+    SliceLayerImpl(int axis_ = 1);
+    SliceLayerImpl(int axis_, const std::vector<int> &sliceIndices_);
 
     void allocate(const std::vector<Blob*> &inputs, std::vector<Blob> &outputs);
 
     void forward(std::vector<Blob*> &inputs, std::vector<Blob> &outputs);
-
-private:
-    int inAxis;
-    std::vector<int> slicePoints;
 };
 
 }
diff --git a/contrib/modules/dnn/src/layers/softmax_layer.cpp b/contrib/modules/dnn/src/layers/softmax_layer.cpp
index e90a590..576ed4d 100644
--- a/contrib/modules/dnn/src/layers/softmax_layer.cpp
+++ b/contrib/modules/dnn/src/layers/softmax_layer.cpp
@@ -42,6 +42,8 @@
 #include "../precomp.hpp"
 #include "layers_common.hpp"
 #include "softmax_layer.hpp"
+#include <opencv2/core/ocl.hpp>
+#include "modules/dnn/opencl_kernels_dnn.hpp"
 #include <algorithm>
 #include <stdlib.h>
 using std::max;
@@ -50,95 +52,173 @@ namespace cv
 {
 namespace dnn
 {
-    //TODO: set default axis number to 1, and add custom shape length in FullyConnected
-    SoftMaxLayer::SoftMaxLayer(LayerParams &params) : Layer(params)
+
+SoftMaxLayerImpl::SoftMaxLayerImpl(int axis)
+{
+    axisRaw = axis;
+}
+
+void SoftMaxLayerImpl::allocate(const std::vector<Blob*> &inputs, std::vector<Blob> &outputs)
+{
+    CV_Assert(inputs.size() == 1);
+    axis = inputs[0]->canonicalAxis(axisRaw);
+
+    useOpenCL = ocl::useOpenCL();
+
+    BlobShape shape = inputs[0]->shape();
+    outerSize = shape.total(0, axis);
+    channels = shape[axis];
+    innerSize = shape.total(axis + 1);
+
+    int allocFlag = (useOpenCL) ? Blob::ALLOC_UMAT : Blob::ALLOC_MAT;
+    shape[axis] = 1;
+    buf.create(shape, inputs[0]->type(), allocFlag);
+
+    outputs.resize(1);
+    outputs[0].create(inputs[0]->shape(), inputs[0]->type(), allocFlag);
+}
+
+void SoftMaxLayerImpl::forward(std::vector<Blob*> &inputs, std::vector<Blob> &outputs)
+{
+    Blob &src = *inputs[0];
+    Blob &dst = outputs[0];
+
+    if (!useOpenCL)
+        forward_cpu(src, dst);
+    else
     {
-        //hotfix!!!
-        axis_ = params.get<int>("axis", 1);
+        CV_Assert(forward_ocl(src, dst));
     }
+}
 
-    void SoftMaxLayer::allocate(const std::vector<Blob*> &inputs, std::vector<Blob> &outputs)
-    {
-        CV_Assert(inputs.size() == 1);
-        axis = inputs[0]->canonicalAxis(axis_);
+#ifdef HAVE_OPENCL
+bool SoftMaxLayerImpl::forward_ocl(Blob &src, Blob &dst)
+{
+    const UMat &srcMat = src.umatRefConst();
+    UMat &dstMat = dst.umatRef();
+    srcMat.copyTo(dstMat);
+    UMat &bufMat = buf.umatRef();
+    CV_Assert(dstMat.offset == 0);
 
-        BlobShape shape = inputs[0]->shape();
-        outputs.resize(1);
-        outputs[0].create(shape);
+    String buildOpts = String("-DT=") + ocl::typeToStr(src.type());
+    ocl::Kernel kmax, ksub, ksum, kdiv;
 
-        shape[axis] = 1;
-        maxAggregator.create(shape);
-    }
+    if (!kmax.create("kernel_channel_max", ocl::dnn::softmax_oclsrc, buildOpts))
+        return false;
 
-    void SoftMaxLayer::forward(std::vector<Blob*> &inputs, std::vector<Blob> &outputs)
-    {
-        Blob &src = *inputs[0];
-        Blob &dst = outputs[0];
+    if (!ksub.create("kernel_channel_subtract", ocl::dnn::softmax_oclsrc, buildOpts))
+        return false;
 
-        float *srcPtr = src.ptrf();
-        float *dstPtr = dst.ptrf();
-        float *bufPtr = maxAggregator.ptrf();
+    if (!ksum.create("kernel_channel_sum", ocl::dnn::softmax_oclsrc, buildOpts))
+        return false;
 
-        size_t outerSize = src.total(0, axis);
-        size_t channels = src.size(axis);
-        size_t innerSize = src.total(axis + 1);
+    if (!kdiv.create("kernel_channel_div", ocl::dnn::softmax_oclsrc, buildOpts))
+        return false;
 
-        size_t outerStep = src.total(axis);
-        size_t cnStep = src.total(axis + 1);
+    size_t wgSize = ocl::Device::getDefault().maxWorkGroupSize();
+    size_t bufSize = buf.total();
+    size_t totalSize = src.total();
 
-        //compute max along axis
-        for (size_t outerDim = 0; outerDim < outerSize; outerDim++)
-        {
-            size_t srcOffset = outerDim * outerStep;
-            size_t bufOffset = outerDim * cnStep;
+    kmax.args((int)outerSize, (int)channels, (int)innerSize,
+              ocl::KernelArg::PtrReadOnly(dstMat), ocl::KernelArg::PtrReadWrite(bufMat));
+    if (!kmax.run(1, &bufSize, &wgSize, true))
+        return false;
+
+    ksub.args((int)totalSize, (int)outerSize, (int)channels, (int)innerSize,
+              ocl::KernelArg::PtrReadOnly(bufMat), ocl::KernelArg::PtrReadWrite(dstMat));
+    if (!ksub.run(1, &totalSize, &wgSize, true))
+        return false;
+
+    cv::exp(dstMat, dstMat);
+
+    ksum.args((int)outerSize, (int)channels, (int)innerSize,
+              ocl::KernelArg::PtrReadOnly(dstMat), ocl::KernelArg::PtrReadWrite(bufMat));
+    if (!ksum.run(1, &bufSize, &wgSize, true))
+        return false;
+
+    kdiv.args((int)totalSize, (int)outerSize, (int)channels, (int)innerSize,
+              ocl::KernelArg::PtrReadOnly(bufMat), ocl::KernelArg::PtrReadWrite(dstMat));
+    if (!kdiv.run(1, &totalSize, &wgSize, true))
+        return false;
+
+    return true;
+}
+#else
+bool SoftMaxLayerImpl::forward_ocl(Blob&, Blob&)
+{
+    return false;
+}
+#endif
+
+void SoftMaxLayerImpl::forward_cpu(Blob &src, Blob &dst)
+{
+    CV_Assert(src.type() == CV_32F);
 
-            memcpy(bufPtr + bufOffset, srcPtr + srcOffset, innerSize * sizeof(float));
+    float *srcPtr = src.ptrf();
+    float *dstPtr = dst.ptrf();
+    float *bufPtr = buf.ptrf();
+
+    size_t outerStep = src.total(axis);
+    size_t cnStep = src.total(axis + 1);
+
+    //compute max along axis
+    for (size_t outerDim = 0; outerDim < outerSize; outerDim++)
+    {
+        size_t srcOffset = outerDim * outerStep;
+        size_t bufOffset = outerDim * cnStep;
 
-            for (size_t cnDim = 1; cnDim < channels; cnDim++)
-            {
-                for (size_t i = 0; i < innerSize; i++)
-                    bufPtr[bufOffset + i] = std::max(bufPtr[bufOffset + i], srcPtr[srcOffset + cnDim * cnStep + i]);
-            }
+        memcpy(bufPtr + bufOffset, srcPtr + srcOffset, innerSize * sizeof(float));
+
+        for (size_t cnDim = 1; cnDim < channels; cnDim++)
+        {
+            for (size_t i = 0; i < innerSize; i++)
+                bufPtr[bufOffset + i] = std::max(bufPtr[bufOffset + i], srcPtr[srcOffset + cnDim * cnStep + i]);
         }
+    }
+
+    //subtract max
+    for (size_t outerDim = 0; outerDim < outerSize; outerDim++)
+    {
+        size_t srcOffset = outerDim * outerStep;
+        size_t bufOffset = outerDim * cnStep;
 
-        //subtract max
-        for (size_t outerDim = 0; outerDim < outerSize; outerDim++)
+        for (size_t cnDim = 0; cnDim < channels; cnDim++)
         {
-            size_t srcOffset = outerDim * outerStep;
-            size_t bufOffset = outerDim * cnStep;
-
-            for (size_t cnDim = 0; cnDim < channels; cnDim++)
-            {
-                for (size_t i = 0; i < innerSize; i++)
-                    dstPtr[srcOffset + cnDim * cnStep + i] = srcPtr[srcOffset + cnDim * cnStep + i] - bufPtr[bufOffset + i];
-            }
+            for (size_t i = 0; i < innerSize; i++)
+                dstPtr[srcOffset + cnDim * cnStep + i] = srcPtr[srcOffset + cnDim * cnStep + i] - bufPtr[bufOffset + i];
         }
+    }
+
+    cv::exp(dst.matRef(), dst.matRef());
 
-        cv::exp(dst.matRef(), dst.matRef());
+    for (size_t outerDim = 0; outerDim < outerSize; outerDim++)
+    {
+        size_t srcOffset = outerDim * outerStep;
+        size_t bufOffset = outerDim * cnStep;
+
+        //sum exp along axis
+        for (size_t i = 0; i < innerSize; i++)
+            bufPtr[bufOffset + i] = 0.f;
 
-        for (size_t outerDim = 0; outerDim < outerSize; outerDim++)
+        for (size_t cnDim = 0; cnDim < channels; cnDim++)
         {
-            size_t srcOffset = outerDim * outerStep;
-            size_t bufOffset = outerDim * cnStep;
+            for (size_t i = 0; i < innerSize; i++)
+                bufPtr[bufOffset + i] += dstPtr[srcOffset + cnDim * cnStep + i];
+        }
 
-            //sum exp along axis
+        //divide by computed sum
+        for (size_t cnDim = 0; cnDim < channels; cnDim++)
+        {
             for (size_t i = 0; i < innerSize; i++)
-                bufPtr[bufOffset + i] = 0.f;
-
-            for (size_t cnDim = 0; cnDim < channels; cnDim++)
-            {
-                for (size_t i = 0; i < innerSize; i++)
-                    bufPtr[bufOffset + i] += dstPtr[srcOffset + cnDim * cnStep + i];
-            }
-
-            //divide by computed sum
-            for (size_t cnDim = 0; cnDim < channels; cnDim++)
-            {
-                for (size_t i = 0; i < innerSize; i++)
-                    dstPtr[srcOffset + cnDim * cnStep + i] /= bufPtr[bufOffset + i];
-            }
+                dstPtr[srcOffset + cnDim * cnStep + i] /= bufPtr[bufOffset + i];
         }
     }
+}
+
+Ptr<SoftmaxLayer> SoftmaxLayer::create(int axis)
+{
+    return Ptr<SoftmaxLayer>(new SoftMaxLayerImpl(axis));
+}
 
 }
 }
diff --git a/contrib/modules/dnn/src/layers/softmax_layer.hpp b/contrib/modules/dnn/src/layers/softmax_layer.hpp
index 5b55794..fad97dd 100644
--- a/contrib/modules/dnn/src/layers/softmax_layer.hpp
+++ b/contrib/modules/dnn/src/layers/softmax_layer.hpp
@@ -42,21 +42,31 @@
 #ifndef __OPENCV_DNN_LAYERS_SOFTMAX_LAYER_HPP__
 #define __OPENCV_DNN_LAYERS_SOFTMAX_LAYER_HPP__
 #include "../precomp.hpp"
+#include <opencv2/dnn/all_layers.hpp>
 
 namespace cv
 {
 namespace dnn
 {
-    class SoftMaxLayer : public Layer
-    {
-        int axis_, axis;
-        Blob maxAggregator;
-
-    public:
-        SoftMaxLayer(LayerParams &params);
-        void allocate(const std::vector<Blob*> &inputs, std::vector<Blob> &outputs);
-        void forward(std::vector<Blob*> &inputs, std::vector<Blob> &outputs);
-    };
+
+class SoftMaxLayerImpl : public SoftmaxLayer
+{
+    int axis, axisRaw;
+    Blob buf;
+    bool useOpenCL;
+    size_t outerSize, channels, innerSize;
+
+
+    bool forward_ocl(Blob &src, Blob &dst);
+    void forward_cpu(Blob &src, Blob &dst);
+
+public:
+
+    SoftMaxLayerImpl(int axis = 1);
+    void allocate(const std::vector<Blob*> &inputs, std::vector<Blob> &outputs);
+    void forward(std::vector<Blob*> &inputs, std::vector<Blob> &outputs);
+};
+
 }
 }
 #endif
diff --git a/contrib/modules/dnn/src/layers/split_layer.cpp b/contrib/modules/dnn/src/layers/split_layer.cpp
index b29c427..cd3a507 100644
--- a/contrib/modules/dnn/src/layers/split_layer.cpp
+++ b/contrib/modules/dnn/src/layers/split_layer.cpp
@@ -42,41 +42,46 @@
 #include "../precomp.hpp"
 #include "layers_common.hpp"
 #include "split_layer.hpp"
+#include <opencv2/core/ocl.hpp>
 
 namespace cv
 {
 namespace dnn
 {
 
-//TODO: maybe "top_count" param is useless because it can be determined by output connections number?
-SplitLayer::SplitLayer(LayerParams &params) : Layer(params)
+SplitLayerImpl::SplitLayerImpl(int outputsCount_ /*= -1*/)
 {
-    if (params.has("top_count"))
-    {
-        outputsNum = params.get<int>("top_count");
-        CV_Assert(outputsNum >= 0);
-    }
-    else
-    {
-        outputsNum = -1;
-    }
+    outputsCount = outputsCount_;
 }
 
-void SplitLayer::allocate(const std::vector<Blob*> &inputs, std::vector<Blob> &outputs)
+void SplitLayerImpl::allocate(const std::vector<Blob*> &inputs, std::vector<Blob> &outputs)
 {
     CV_Assert(inputs.size() == 1);
+    useOpenCL = ocl::useOpenCL() && inputs[0]->getState() == Blob::HEAD_AT_UMAT;
+    int allocFlags = useOpenCL ? Blob::ALLOC_UMAT : Blob::ALLOC_MAT;
 
-    if (outputsNum >= 0)
-        outputs.resize(outputsNum);
+    if (outputsCount >= 0)
+        outputs.resize(outputsCount);
 
     for (size_t i = 0; i < outputs.size(); i++)
-        outputs[i].create(inputs[0]->shape(), inputs[0]->type());
+        outputs[i].create(inputs[0]->shape(), inputs[0]->type(), allocFlags);
 }
 
-void SplitLayer::forward(std::vector<Blob*> &inputs, std::vector<Blob> &outputs)
+void SplitLayerImpl::forward(std::vector<Blob*> &inputs, std::vector<Blob> &outputs)
 {
     for (size_t i = 0; i < outputs.size(); i++)
-        inputs[0]->matRefConst().copyTo(outputs[i].matRef());
+    {
+        if (useOpenCL)
+            inputs[0]->umatRefConst().copyTo(outputs[i].umatRef());
+        else
+            inputs[0]->matRefConst().copyTo(outputs[i].matRef());
+    }
+}
+
+
+Ptr<SplitLayer> SplitLayer::create(int outputsCount)
+{
+    return Ptr<SplitLayer>(new SplitLayerImpl(outputsCount));
 }
 
 }
diff --git a/contrib/modules/dnn/src/layers/split_layer.hpp b/contrib/modules/dnn/src/layers/split_layer.hpp
index 1793dbf..124cb12 100644
--- a/contrib/modules/dnn/src/layers/split_layer.hpp
+++ b/contrib/modules/dnn/src/layers/split_layer.hpp
@@ -42,23 +42,23 @@
 #ifndef __OPENCV_DNN_LAYERS_SPLIT_LAYER_HPP__
 #define __OPENCV_DNN_LAYERS_SPLIT_LAYER_HPP__
 #include "../precomp.hpp"
+#include <opencv2/dnn/all_layers.hpp>
 
 namespace cv
 {
 namespace dnn
 {
 
-class SplitLayer : public Layer
+class SplitLayerImpl : public SplitLayer
 {
+    bool useOpenCL;
+
 public:
-    SplitLayer(LayerParams &params);
+    SplitLayerImpl(int outputsCount_ = -1);
 
     void allocate(const std::vector<Blob*> &inputs, std::vector<Blob> &outputs);
 
     void forward(std::vector<Blob*> &inputs, std::vector<Blob> &outputs);
-
-private:
-    int outputsNum;
 };
 
 }
diff --git a/contrib/modules/dnn/src/opencl/activations.cl b/contrib/modules/dnn/src/opencl/activations.cl
new file mode 100644
index 0000000..58da4db
--- /dev/null
+++ b/contrib/modules/dnn/src/opencl/activations.cl
@@ -0,0 +1,44 @@
+__kernel void ReLUForward(const int count, __global const T* in, __global T* out
+#ifndef RELU_NO_SLOPE
+, T negative_slope
+#endif
+) {
+  int index = get_global_id(0);
+  if(index < count)
+#ifndef RELU_NO_SLOPE
+  out[index] = in[index] > 0 ? in[index] : in[index] * negative_slope;
+#else
+  out[index] = in[index] > 0 ? in[index] : 0;
+#endif
+}
+
+__kernel void TanHForward(const int count, __global T* in, __global T* out) {
+  int index = get_global_id(0);
+  if(index < count)
+  out[index] = tanh(in[index]);
+}
+
+__kernel void SigmoidForward(const int count, __global const T* in, __global T* out) {
+  int index = get_global_id(0);
+  if(index < count)
+  out[index] = 1. / (1. + exp(-in[index]));
+}
+
+__kernel void BNLLForward(const int n, __global const T* in, __global T* out) {
+  int index = get_global_id(0);
+  if (index < n) {
+    out[index] = in[index] > 0 ? in[index] + log(1. + exp(-in[index])) : log(1. + exp(in[index]));
+  }
+}
+
+__kernel void AbsValForward(const int n, __global const T* in, __global T* out) {
+  int index = get_global_id(0);
+  if (index < n)
+    out[index] = fabs(in[index]);
+}
+
+__kernel void PowForward(const int n, __global const T* in, __global T* out, const T power, const T scale, const T shift) {
+  int index = get_global_id(0);
+  if (index < n)
+    out[index] = pow(shift + scale * in[index], power);
+}
\ No newline at end of file
diff --git a/contrib/modules/dnn/src/opencl/col2im.cl b/contrib/modules/dnn/src/opencl/col2im.cl
new file mode 100644
index 0000000..30d4664
--- /dev/null
+++ b/contrib/modules/dnn/src/opencl/col2im.cl
@@ -0,0 +1,62 @@
+/*************************************************************************************
+ * Copyright (c) 2015, Advanced Micro Devices, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ *  other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+ * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ **************************************************************************************/
+
+__kernel void col2im(const int n, __global const T* data_col, const int col_offset,
+    const int height, const int width, const int channels,
+    const int patch_h, const int patch_w,
+    const int pad_h, const int pad_w,
+    const int stride_h, const int stride_w,
+    const int height_col, const int width_col,
+    __global T* data_im, const int img_offset)
+{
+  data_col = data_col + col_offset;
+  data_im = data_im + img_offset;
+  int index = get_global_id(0);
+  if(index < n) {
+    T val = 0;
+    int w = index % width + pad_w;
+    int h = (index / width) % height + pad_h;
+    int c = index / (width * height);
+
+    // compute the start and end of the output
+    int w_col_start = (w < patch_w) ? 0 : (w - patch_w) / stride_w + 1;
+    int w_col_end = min(w / stride_w + 1, width_col);
+    int h_col_start = (h < patch_h) ? 0 : (h - patch_h) / stride_h + 1;
+    int h_col_end = min(h / stride_h + 1, height_col);
+
+    // equivalent implementation
+    int offset =
+    (c * patch_h * patch_w + h * patch_w + w) * height_col * width_col;
+    int coeff_h_col = (1 - stride_h * patch_w * height_col) * width_col;
+    int coeff_w_col = (1 - stride_w * height_col * width_col);
+    for (int h_col = h_col_start; h_col < h_col_end; ++h_col) {
+      for (int w_col = w_col_start; w_col < w_col_end; ++w_col) {
+        val += data_col[offset + h_col * coeff_h_col + w_col * coeff_w_col];
+      }
+    }
+    data_im[index] = val;
+  }
+}
diff --git a/contrib/modules/dnn/src/opencl/im2col.cl b/contrib/modules/dnn/src/opencl/im2col.cl
index 7900645..f3f18b5 100644
--- a/contrib/modules/dnn/src/opencl/im2col.cl
+++ b/contrib/modules/dnn/src/opencl/im2col.cl
@@ -39,11 +39,11 @@
 //
 //M*/
 
-__kernel void im2col(__global const float *im_src, int im_src_offset,
+__kernel void im2col(__global const T *im_src, int im_src_offset,
                      int channels, int height_inp, int width_inp,
                      int kernel_h, int kernel_w, int pad_h, int pad_w, int stride_h, int stride_w,
                      int height_out, int width_out,
-                     __global float *im_col, int im_col_offset
+                     __global T *im_col, int im_col_offset
                     )
 {
     int index = get_global_id(0);
@@ -52,13 +52,13 @@ __kernel void im2col(__global const float *im_src, int im_src_offset,
     int j_out = index % width_out;
     int i_out = (index / width_out) % height_out;
     int c_inp = (index / width_out) / height_out;
-    
+
     int c_out = c_inp * kernel_h * kernel_w;
     int i_inp = i_out * stride_h - pad_h;
     int j_inp = j_out * stride_w - pad_w;
 
-    im_src += (c_inp * height_inp + i_inp) * width_inp + j_inp + im_src_offset / sizeof(float);
-    im_col += (c_out * height_out + i_out) * width_out + j_out + im_col_offset / sizeof(float);
+    im_src += (c_inp * height_inp + i_inp) * width_inp + j_inp + im_src_offset;
+    im_col += (c_out * height_out + i_out) * width_out + j_out + im_col_offset;
 
     for (int ki = 0; ki < kernel_h; ++ki)
         for (int kj = 0; kj < kernel_w; ++kj) {
diff --git a/contrib/modules/dnn/src/opencl/lrn.cl b/contrib/modules/dnn/src/opencl/lrn.cl
new file mode 100644
index 0000000..2ff03f0
--- /dev/null
+++ b/contrib/modules/dnn/src/opencl/lrn.cl
@@ -0,0 +1,76 @@
+/*************************************************************************************
+ * Copyright (c) 2015, Advanced Micro Devices, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ *  other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+ * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ **************************************************************************************/
+
+__kernel void LRNComputeOutput(const int nthreads, __global T* in, __global T* scale, const T negative_beta, __global T* out) {
+  int index = get_global_id(0);
+  int tmp = get_global_size(0);
+  for(index; index < nthreads; index += tmp)
+  out[index] = in[index] * pow(scale[index], negative_beta);
+}
+
+__kernel void LRNFillScale(const int nthreads, __global T* in, const int num, const int channels, const int height, const int width, const int size, const T alpha_over_size, const T k, __global T* scale) {
+  int index = get_global_id(0);
+  int tmp = get_global_size(0);
+  for(index; index < nthreads; index += tmp) {
+    // find out the local offset
+    const int w = index % width;
+    const int h = (index / width) % height;
+    const int n = index / width / height;
+    const int offset = (n * channels * height + h) * width + w;
+    const int step = height * width;
+    in = in + offset;
+    scale = scale + offset;
+    int head = 0;
+    const int pre_pad = (size - 1) / 2;
+    const int post_pad = size - pre_pad - 1;
+    T accum_scale = 0;
+    // fill the scale at [n, :, h, w]
+    // accumulate values
+    while (head < post_pad && head < channels) {
+      accum_scale += in[head * step] * in[head * step];
+      ++head;
+    }
+    // both add and subtract
+    while (head < channels) {
+      accum_scale += in[head * step] * in[head * step];
+      if (head - size >= 0) {
+        accum_scale -= in[(head - size) * step]
+        * in[(head - size) * step];
+      }
+      scale[(head - post_pad) * step] = k + accum_scale * alpha_over_size;
+      ++head;
+    }
+    // subtract only
+    while (head < channels + post_pad) {
+      if (head - size >= 0) {
+        accum_scale -= in[(head - size) * step]
+        * in[(head - size) * step];
+      }
+      scale[(head - post_pad) * step] = k + accum_scale * alpha_over_size;
+      ++head;
+    }
+  }
+}
\ No newline at end of file
diff --git a/contrib/modules/dnn/src/opencl/pooling.cl b/contrib/modules/dnn/src/opencl/pooling.cl
new file mode 100644
index 0000000..aeb70bc
--- /dev/null
+++ b/contrib/modules/dnn/src/opencl/pooling.cl
@@ -0,0 +1,94 @@
+/*************************************************************************************
+ * Copyright (c) 2015, Advanced Micro Devices, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ *  other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+ * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ **************************************************************************************/
+
+__kernel void MaxPoolForward(const int nthreads, __global T* bottom_data, const int num, const int channels, const int height, const int width, const int pooled_height, const int pooled_width, const int kernel_h, const int kernel_w, const int stride_h, const int stride_w, const int pad_h, const int pad_w, __global T* top_data
+#ifdef MASK
+  , __global int* mask, __global T* top_mask
+#endif
+) {
+  int index = get_global_id(0);
+  int tmp = get_global_size(0);
+  for(index; index < nthreads; index += tmp) {
+    int pw = index % pooled_width;
+    int ph = (index / pooled_width) % pooled_height;
+    int c = (index / pooled_width / pooled_height) % channels;
+    int n = index / pooled_width / pooled_height / channels;
+    int hstart = ph * stride_h - pad_h;
+    int wstart = pw * stride_w - pad_w;
+    const int hend = min(hstart + kernel_h, height);
+    const int wend = min(wstart + kernel_w, width);
+    hstart = max(hstart, 0);
+    wstart = max(wstart, 0);
+    T maxval = -FLT_MAX;
+    int maxidx = -1;
+    bottom_data =
+    bottom_data + (n * channels + c) * height * width;
+    for (int h = hstart; h < hend; ++h) {
+      for (int w = wstart; w < wend; ++w) {
+        if (bottom_data[h * width + w] > maxval) {
+          maxidx = h * width + w;
+          maxval = bottom_data[maxidx];
+        }
+      }
+    }
+    top_data[index] = maxval;
+#ifdef MASK
+    if (mask) {
+      mask[index] = maxidx;
+    } else {
+      top_mask[index] = maxidx;
+    }
+#endif
+  }
+}
+
+__kernel void AvePoolForward(const int nthreads, __global T* bottom_data, const int num, const int channels, const int height, const int width, const int pooled_height, const int pooled_width, const int kernel_h, const int kernel_w, const int stride_h, const int stride_w, const int pad_h, const int pad_w,__global T* top_data) {
+  int index = get_global_id(0);
+  int tmp = get_global_size(0);
+  for(index; index < nthreads; index+=tmp) {
+    int pw = index % pooled_width;
+    int ph = (index / pooled_width) % pooled_height;
+    int c = (index / pooled_width / pooled_height) % channels;
+    int n = index / pooled_width / pooled_height / channels; int hstart = ph * stride_h - pad_h; int wstart = pw * stride_w - pad_w;
+    int hend = min(hstart + kernel_h, height + pad_h);
+    int wend = min(wstart + kernel_w, width + pad_w);
+    const int pool_size = (hend - hstart) * (wend - wstart);
+    hstart = max(hstart, 0);
+    wstart = max(wstart, 0);
+    hend = min(hend, height);
+    wend = min(wend, width);
+    T aveval = 0;
+    bottom_data =
+    bottom_data + (n * channels + c) * height * width;
+    for (int h = hstart; h < hend; ++h) {
+      for (int w = wstart; w < wend; ++w) {
+        aveval += bottom_data[h * width + w];
+      }
+    }
+    top_data[index] = aveval / pool_size;
+  }
+
+}
diff --git a/contrib/modules/dnn/src/opencl/softmax.cl b/contrib/modules/dnn/src/opencl/softmax.cl
new file mode 100644
index 0000000..e9fcadc
--- /dev/null
+++ b/contrib/modules/dnn/src/opencl/softmax.cl
@@ -0,0 +1,75 @@
+/*************************************************************************************
+ * Copyright (c) 2015, Advanced Micro Devices, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ *  other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+ * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ **************************************************************************************/
+
+__kernel void kernel_channel_max(const int num, const int channels,
+    const int spatial_dim, __global const T* data, __global T* out) {
+  int index = get_global_id(0);
+  if(index < num * spatial_dim) {
+    int n = index / spatial_dim;
+    int s = index % spatial_dim;
+    T maxval = -FLT_MAX;
+    for (int c = 0; c < channels; ++c) {
+      maxval = max(data[(n * channels + c) * spatial_dim + s], maxval);
+    }
+    out[index] = maxval;
+  }
+}
+
+__kernel void kernel_channel_subtract(const int count,
+    const int num, const int channels,
+    const int spatial_dim, __global const T* channel_max, __global T* data) {
+  int index = get_global_id(0);
+  if(index < count) {
+    int n = index / channels / spatial_dim;
+    int s = index % spatial_dim;
+    data[index] -= channel_max[n * spatial_dim + s];
+  }
+}
+
+__kernel void kernel_channel_sum(const int num, const int channels,
+    const int spatial_dim, __global const T* data, __global T* channel_sum) {
+  int index = get_global_id(0);
+  if(index < num * spatial_dim) {
+    int n = index / spatial_dim;
+    int s = index % spatial_dim;
+    T sum = 0;
+    for (int c = 0; c < channels; ++c) {
+      sum += data[(n * channels + c) * spatial_dim + s];
+    }
+    channel_sum[index] = sum;
+  }
+}
+
+__kernel void kernel_channel_div(const int count,
+    const int num, const int channels,
+    const int spatial_dim, __global const T* channel_sum, __global T* data) {
+  int index = get_global_id(0);
+  if(index < count) {
+    int n = index / channels / spatial_dim;
+    int s = index % spatial_dim;
+    data[index] /= channel_sum[n * spatial_dim + s];
+  }
+}
\ No newline at end of file
diff --git a/contrib/modules/dnn/src/precomp.hpp b/contrib/modules/dnn/src/precomp.hpp
index 8639e45..6932bc8 100644
--- a/contrib/modules/dnn/src/precomp.hpp
+++ b/contrib/modules/dnn/src/precomp.hpp
@@ -40,4 +40,5 @@
 //M*/
 
 #include <opencv2/core.hpp>
+#include "cvconfig.h"
 #include <opencv2/dnn.hpp>
diff --git a/contrib/modules/dnn/src/tensorflow/attr_value.proto b/contrib/modules/dnn/src/tensorflow/attr_value.proto
new file mode 100644
index 0000000..26e42bc
--- /dev/null
+++ b/contrib/modules/dnn/src/tensorflow/attr_value.proto
@@ -0,0 +1,60 @@
+syntax = "proto3";
+
+package tensorflow;
+option cc_enable_arenas = true;
+option java_outer_classname = "AttrValueProtos";
+option java_multiple_files = true;
+option java_package = "org.tensorflow.framework";
+
+import "tensor.proto";
+import "tensor_shape.proto";
+import "types.proto";
+
+// Protocol buffer representing the value for an attr used to configure an Op.
+// Comment indicates the corresponding attr type.  Only the field matching the
+// attr type may be filled.
+message AttrValue {
+  message ListValue {
+    repeated bytes s = 2;                        // "list(string)"
+    repeated int64 i = 3 [packed = true];        // "list(int)"
+    repeated float f = 4 [packed = true];        // "list(float)"
+    repeated bool b = 5 [packed = true];         // "list(bool)"
+    repeated DataType type = 6 [packed = true];  // "list(type)"
+    repeated TensorShapeProto shape = 7;         // "list(shape)"
+    repeated TensorProto tensor = 8;             // "list(tensor)"
+    // TODO(zhifengc/josh11b): implements list(func) if needed.
+  }
+
+  oneof value {
+    bytes s = 2;                 // "string"
+    int64 i = 3;                 // "int"
+    float f = 4;                 // "float"
+    bool b = 5;                  // "bool"
+    DataType type = 6;           // "type"
+    TensorShapeProto shape = 7;  // "shape"
+    TensorProto tensor = 8;      // "tensor"
+    ListValue list = 1;          // any "list(...)"
+
+    // "func" represents a function. func.name is a function's name or
+    // a primitive op's name. func.attr.first is the name of an attr
+    // defined for that function. func.attr.second is the value for
+    // that attr in the instantiation.
+    NameAttrList func = 10;
+
+    // This is a placeholder only used in nodes defined inside a
+    // function.  It indicates the attr value will be supplied when
+    // the function is instantiated.  For example, let us suppose a
+    // node "N" in function "FN". "N" has an attr "A" with value
+    // placeholder = "foo". When FN is instantiated with attr "foo"
+    // set to "bar", the instantiated node N's attr A will have been
+    // given the value "bar".
+    string placeholder = 9;
+  }
+}
+
+// A list of attr names and their values. The whole list is attached
+// with a string name.  E.g., MatMul[T=float].
+message NameAttrList {
+  string name = 1;
+  map<string, AttrValue> attr = 2;
+}
diff --git a/contrib/modules/dnn/src/tensorflow/function.proto b/contrib/modules/dnn/src/tensorflow/function.proto
new file mode 100644
index 0000000..144c75b
--- /dev/null
+++ b/contrib/modules/dnn/src/tensorflow/function.proto
@@ -0,0 +1,95 @@
+syntax = "proto3";
+
+package tensorflow;
+option cc_enable_arenas = true;
+option java_outer_classname = "FunctionProtos";
+option java_multiple_files = true;
+option java_package = "org.tensorflow.framework";
+
+import "attr_value.proto";
+import "op_def.proto";
+
+// A library is a set of named functions.
+message FunctionDefLibrary {
+  repeated FunctionDef function = 1;
+  repeated GradientDef gradient = 2;
+}
+
+// A function can be instantiated when the runtime can bind every attr
+// with a value. When a GraphDef has a call to a function, it must
+// have binding for every attr defined in the signature.
+//
+// TODO(zhifengc):
+//   * device spec, etc.
+message FunctionDef {
+  // The definition of the function's name, arguments, return values,
+  // attrs etc.
+  OpDef signature = 1;
+
+  // The body of the function.
+  repeated Node node = 2;  // function.node.ret[*] are unique.
+
+  // A node is a multi-value assignment:
+  //   (ret[0], ret[1], ...) = func(arg[0], arg[1], ...)
+  //
+  // By convention, "func" is resolved by consulting with a user-defined
+  // library first. If not resolved, "func" is assumed to be a builtin op.
+  message Node {
+    // This node produces multiple outputs. They are named ret[0],
+    // ret[1], ..., etc.
+    //
+    // REQUIRES: function.node.ret[*] are unique across all nodes.
+    // REQUIRES: ret.size == func/op def's number of output args.
+    repeated string ret = 1;
+
+    // The op/function name.
+    string op = 2;
+
+    // Arguments passed to this func/op.
+    //
+    // arg[i] must be either one of
+    // function.signature.input_args[*].name or one of
+    // function.node[*].ret[*].
+    //
+    // REQUIRES: arg.size == func/op def's number of input args.
+    repeated string arg = 3;
+
+    // Control dependencies.
+    //
+    // dep[i] must be one of function.node[*].ret[*] or one of
+    // function.signature.input_args[*].name.
+    repeated string dep = 4;
+
+    // Attrs.
+    //
+    // 'attr' maps names defined by 'func's attr defs to attr values.
+    // attr values may have placeholders which are substituted
+    // recursively by concrete values when this node is instantiated.
+    // These placeholders must name an attr listed in the FunctionDef's
+    // signature.
+    map<string, AttrValue> attr = 5;
+  }
+}
+
+// GradientDef defines the gradient function of a function defined in
+// a function library.
+//
+// A gradient function g (specified by gradient_func) for a function f
+// (specified by function_name) must follow the following:
+//
+// The function 'f' must be a numerical function which takes N inputs
+// and produces M outputs. Its gradient function 'g', which is a
+// function taking N + M inputs and produces N outputs.
+//
+// I.e. if we have
+//    (y1, y2, ..., y_M) = f(x1, x2, ..., x_N),
+// then, g is
+//    (dL/dx1, dL/dx2, ..., dL/dx_N) = g(x1, x2, ..., x_N,
+//                                      dL/dy1, dL/dy2, ..., dL/dy_M),
+// where L is a scalar-value function of (x1, x2, ..., xN) (e.g., the
+// loss function). dL/dx_i is the partial derivative of L with respect
+// to x_i.
+message GradientDef {
+  string function_name = 1;  // The function name.
+  string gradient_func = 2;  // The gradient function's name.
+}
diff --git a/contrib/modules/dnn/src/tensorflow/graph.proto b/contrib/modules/dnn/src/tensorflow/graph.proto
new file mode 100644
index 0000000..f945201
--- /dev/null
+++ b/contrib/modules/dnn/src/tensorflow/graph.proto
@@ -0,0 +1,112 @@
+syntax = "proto3";
+
+package tensorflow;
+option cc_enable_arenas = true;
+option java_outer_classname = "GraphProtos";
+option java_multiple_files = true;
+option java_package = "org.tensorflow.framework";
+
+import "attr_value.proto";
+import "function.proto";
+import "versions.proto";
+
+// Represents the graph of operations
+message GraphDef {
+  repeated NodeDef node = 1;
+
+  // Compatibility versions of the graph.  See core/public/version.h for version
+  // history.  The GraphDef version is distinct from the TensorFlow version, and
+  // each release of TensorFlow will support a range of GraphDef versions.
+  VersionDef versions = 4;
+
+  // Deprecated single version field; use versions above instead.  Since all
+  // GraphDef changes before "versions" was introduced were forward
+  // compatible, this field is entirely ignored.
+  int32 version = 3 [deprecated = true];
+
+  // EXPERIMENTAL. DO NOT USE OR DEPEND ON THIS YET.
+  //
+  // "library" provides user-defined functions.
+  //
+  // Naming:
+  //   * library.function.name are in a flat namespace.
+  //     NOTE: We may need to change it to be hierarchical to support
+  //     different orgs. E.g.,
+  //     { "/google/nn", { ... }},
+  //     { "/google/vision", { ... }}
+  //     { "/org_foo/module_bar", {...}}
+  //     map<string, FunctionDefLib> named_lib;
+  //   * If node[i].op is the name of one function in "library",
+  //     node[i] is deemed as a function call. Otherwise, node[i].op
+  //     must be a primitive operation supported by the runtime.
+  //
+  //
+  // Function call semantics:
+  //
+  //   * The callee may start execution as soon as some of its inputs
+  //     are ready. The caller may want to use Tuple() mechanism to
+  //     ensure all inputs are ready in the same time.
+  //
+  //   * The consumer of return values may start executing as soon as
+  //     the return values the consumer depends on are ready.  The
+  //     consumer may want to use Tuple() mechanism to ensure the
+  //     consumer does not start until all return values of the callee
+  //     function are ready.
+  FunctionDefLibrary library = 2;
+};
+
+message NodeDef {
+  // The name given to this operator. Used for naming inputs,
+  // logging, visualization, etc.  Unique within a single GraphDef.
+  // Must match the regexp "[A-Za-z0-9.][A-Za-z0-9_./]*".
+  string name = 1;
+
+  // The operation name.  There may be custom parameters in attrs.
+  // Op names starting with an underscore are reserved for internal use.
+  string op = 2;
+
+  // Each input is "node:src_output" with "node" being a string name and
+  // "src_output" indicating which output tensor to use from "node". If
+  // "src_output" is 0 the ":0" suffix can be omitted.  Regular inputs
+  // may optionally be followed by control inputs that have the format
+  // "^node".
+  repeated string input = 3;
+
+  // A (possibly partial) specification for the device on which this
+  // node should be placed.
+  // The expected syntax for this string is as follows:
+  //
+  // DEVICE_SPEC ::= COLOCATED_NODE | PARTIAL_SPEC
+  //
+  // COLOCATED_NODE ::= "@" NODE_NAME  // See NodeDef.name above.
+  // PARTIAL_SPEC ::= ("/" CONSTRAINT) *
+  // CONSTRAINT ::= ("job:" JOB_NAME)
+  //              | ("replica:" [1-9][0-9]*)
+  //              | ("task:" [1-9][0-9]*)
+  //              | ( ("gpu" | "cpu") ":" ([1-9][0-9]* | "*") )
+  //
+  // Valid values for this string include:
+  // * "@other/node"                         (colocate with "other/node")
+  // * "/job:worker/replica:0/task:1/gpu:3"  (full specification)
+  // * "/job:worker/gpu:3"                   (partial specification)
+  // * ""                                    (no specification)
+  //
+  // If the constraints do not resolve to a single device (or if this
+  // field is empty or not present), the runtime will attempt to
+  // choose a device automatically.
+  string device = 4;
+
+  // Operation-specific graph-construction-time configuration.
+  // Note that this should include all attrs defined in the
+  // corresponding OpDef, including those with a value matching
+  // the default -- this allows the default to change and makes
+  // NodeDefs easier to interpret on their own.  However, if
+  // an attr with a default is not specified in this list, the
+  // default will be used.
+  // The "names" (keys) must match the regexp "[a-z][a-z0-9_]+" (and
+  // one of the names from the corresponding OpDef's attr field).
+  // The values must have a type matching the corresponding OpDef
+  // attr's type field.
+  // TODO(josh11b): Add some examples here showing best practices.
+  map<string, AttrValue> attr = 5;
+};
diff --git a/contrib/modules/dnn/src/tensorflow/op_def.proto b/contrib/modules/dnn/src/tensorflow/op_def.proto
new file mode 100644
index 0000000..baf68ea
--- /dev/null
+++ b/contrib/modules/dnn/src/tensorflow/op_def.proto
@@ -0,0 +1,157 @@
+syntax = "proto3";
+
+package tensorflow;
+option cc_enable_arenas = true;
+option java_outer_classname = "OpDefProtos";
+option java_multiple_files = true;
+option java_package = "org.tensorflow.framework";
+
+import "attr_value.proto";
+import "types.proto";
+
+// Defines an operation. A NodeDef in a GraphDef specifies an Op by
+// using the "op" field which should match the name of a OpDef.
+message OpDef {
+  // Op names starting with an underscore are reserved for internal use.
+  // Names should be CamelCase and match the regexp "[A-Z][a-zA-Z0-9_]*".
+  string name = 1;
+
+  // For describing inputs and outputs.
+  message ArgDef {
+    // Name for the input/output.  Should match the regexp "[a-z][a-z0-9_]*".
+    string name = 1;
+
+    // Human readable description.
+    string description = 2;
+
+    // Describes the type of one or more tensors that are accepted/produced
+    // by this input/output arg.  The only legal combinations are:
+    // * For a single tensor: either the "type" field is set or the
+    //   "type_attr" field is set to the name of an attr with type "type".
+    // * For a sequence of tensors with the same type: the "number_attr"
+    //   field will be set to the name of an attr with type "int", and
+    //   either the "type" or "type_attr" field will be set as for
+    //   single tensors.
+    // * For a sequence of tensors, the "type_list_attr" field will be set
+    //   to the name of an attr with type "list(type)".
+    DataType type = 3;
+    string type_attr = 4;    // if specified, attr must have type "type"
+    string number_attr = 5;  // if specified, attr must have type "int"
+    // If specified, attr must have type "list(type)", and none of
+    // type, type_attr, and number_attr may be specified.
+    string type_list_attr = 6;
+
+    // For inputs: if true, the inputs are required to be refs.
+    //   By default, inputs can be either refs or non-refs.
+    // For outputs: if true, outputs are refs, otherwise they are not.
+    bool is_ref = 16;
+  };
+
+  // Description of the input(s).
+  repeated ArgDef input_arg = 2;
+
+  // Description of the output(s).
+  repeated ArgDef output_arg = 3;
+
+  // Description of the graph-construction-time configuration of this
+  // Op.  That is to say, this describes the attr fields that will
+  // be specified in the NodeDef.
+  message AttrDef {
+    // A descriptive name for the argument.  May be used, e.g. by the
+    // Python client, as a keyword argument name, and so should match
+    // the regexp "[a-z][a-z0-9_]+".
+    string name = 1;
+
+    // One of the type names from attr_value.proto ("string", "list(string)",
+    // "int", etc.).
+    string type = 2;
+
+    // A reasonable default for this attribute if the user does not supply
+    // a value.  If not specified, the user must supply a value.
+    AttrValue default_value = 3;
+
+    // Human-readable description.
+    string description = 4;
+
+    // TODO(josh11b): bool is_optional?
+
+    // --- Constraints ---
+    // These constraints are only in effect if specified.  Default is no
+    // constraints.
+
+    // For type == "int", this is a minimum value.  For "list(___)"
+    // types, this is the minimum length.
+    bool has_minimum = 5;
+    int64 minimum = 6;
+
+    // The set of allowed values.  Has type that is the "list" version
+    // of the "type" field above (uses the "list" field of AttrValue).
+    // If type == "type" or "list(type)" above, then the "type" field
+    // of "allowed_values.list" has the set of allowed DataTypes.
+    // If type == "string" or "list(string)", then the "s" field of
+    // "allowed_values.list" has the set of allowed strings.
+    AttrValue allowed_values = 7;
+  }
+  repeated AttrDef attr = 4;
+
+  // Optional deprecation based on GraphDef versions.
+  OpDeprecation deprecation = 8;
+
+  // One-line human-readable description of what the Op does.
+  string summary = 5;
+
+  // Additional, longer human-readable description of what the Op does.
+  string description = 6;
+
+  // -------------------------------------------------------------------------
+  // Which optimizations this operation can participate in.
+
+  // True if the operation is commutative ("op(a,b) == op(b,a)" for all inputs)
+  bool is_commutative = 18;
+
+  // If is_aggregate is true, then this operation accepts N >= 2
+  // inputs and produces 1 output all of the same type.  Should be
+  // associative and commutative, and produce output with the same
+  // shape as the input.  The optimizer may replace an aggregate op
+  // taking input from multiple devices with a tree of aggregate ops
+  // that aggregate locally within each device (and possibly within
+  // groups of nearby devices) before communicating.
+  // TODO(josh11b): Implement that optimization.
+  bool is_aggregate = 16;  // for things like add
+
+  // Other optimizations go here, like
+  //   can_alias_input, rewrite_when_output_unused, partitioning_strategy, etc.
+
+  // -------------------------------------------------------------------------
+  // Optimization constraints.
+
+  // By default Ops may be moved between devices.  Stateful ops should
+  // either not be moved, or should only be moved if that state can also
+  // be moved (e.g. via some sort of save / restore).
+  // Stateful ops are guaranteed to never be optimized away by Common
+  // Subexpression Elimination (CSE).
+  bool is_stateful = 17;  // for things like variables, queue
+
+  // -------------------------------------------------------------------------
+  // Non-standard options.
+
+  // By default, all inputs to an Op must be initialized Tensors.  Ops
+  // that may initialize tensors for the first time should set this
+  // field to true, to allow the Op to take an uninitialized Tensor as
+  // input.
+  bool allows_uninitialized_input = 19;  // for Assign, etc.
+};
+
+// Information about version-dependent deprecation of an op
+message OpDeprecation {
+  // First GraphDef version at which the op is disallowed.
+  int32 version = 1;
+
+  // Explanation of why it was deprecated and what to use instead.
+  string explanation = 2;
+};
+
+// A collection of OpDefs
+message OpList {
+  repeated OpDef op = 1;
+};
diff --git a/contrib/modules/dnn/src/tensorflow/tensor.proto b/contrib/modules/dnn/src/tensorflow/tensor.proto
new file mode 100644
index 0000000..0804218
--- /dev/null
+++ b/contrib/modules/dnn/src/tensorflow/tensor.proto
@@ -0,0 +1,68 @@
+syntax = "proto3";
+
+package tensorflow;
+option cc_enable_arenas = true;
+option java_outer_classname = "TensorProtos";
+option java_multiple_files = true;
+option java_package = "org.tensorflow.framework";
+
+import "tensor_shape.proto";
+import "types.proto";
+
+// Protocol buffer representing a tensor.
+message TensorProto {
+  DataType dtype = 1;
+
+  // Shape of the tensor.  TODO(touts): sort out the 0-rank issues.
+  TensorShapeProto tensor_shape = 2;
+
+  // Only one of the representations below is set, one of "tensor_contents" and
+  // the "xxx_val" attributes.  We are not using oneof because as oneofs cannot
+  // contain repeated fields it would require another extra set of messages.
+
+  // Version number.
+  //
+  // In version 0, if the "repeated xxx" representations contain only one
+  // element, that element is repeated to fill the shape.  This makes it easy
+  // to represent a constant Tensor with a single value.
+  int32 version_number = 3;
+
+  // Serialized content from Tensor::AsProtoTensorContent(). This representation
+  // can be used for all tensor types.
+  bytes tensor_content = 4;
+
+  // Type specific representations that make it easy to create tensor protos in
+  // all languages.  Only the representation corresponding to "dtype" can
+  // be set.  The values hold the flattened representation of the tensor in
+  // row major order.
+
+  // DT_HALF. Note that since protobuf has no int16 type, we'll have some
+  // pointless zero padding for each value here.
+  repeated int32 half_val = 13 [packed = true];
+
+  // DT_FLOAT.
+  repeated float float_val = 5 [packed = true];
+
+  // DT_DOUBLE.
+  repeated double double_val = 6 [packed = true];
+
+  // DT_INT32, DT_INT16, DT_INT8, DT_UINT8.
+  repeated int32 int_val = 7 [packed = true];
+
+  // DT_STRING
+  repeated bytes string_val = 8;
+
+  // DT_COMPLEX64. scomplex_val(2*i) and scomplex_val(2*i+1) are real
+  // and imaginary parts of i-th single precision complex.
+  repeated float scomplex_val = 9 [packed = true];
+
+  // DT_INT64
+  repeated int64 int64_val = 10 [packed = true];
+
+  // DT_BOOL
+  repeated bool bool_val = 11 [packed = true];
+
+  // DT_COMPLEX128. dcomplex_val(2*i) and dcomplex_val(2*i+1) are real
+  // and imaginary parts of i-th double precision complex.
+  repeated double dcomplex_val = 12 [packed = true];
+};
diff --git a/contrib/modules/dnn/src/tensorflow/tensor_shape.proto b/contrib/modules/dnn/src/tensorflow/tensor_shape.proto
new file mode 100644
index 0000000..1ec3c53
--- /dev/null
+++ b/contrib/modules/dnn/src/tensorflow/tensor_shape.proto
@@ -0,0 +1,45 @@
+// Protocol buffer representing the shape of tensors.
+
+syntax = "proto3";
+option cc_enable_arenas = true;
+option java_outer_classname = "TensorShapeProtos";
+option java_multiple_files = true;
+option java_package = "org.tensorflow.framework";
+
+package tensorflow;
+
+// Dimensions of a tensor.
+message TensorShapeProto {
+  // One dimension of the tensor.
+  message Dim {
+    // Size of the tensor in that dimension.
+    // This value must be >= -1, but values of -1 are reserved for "unknown"
+    // shapes (values of -1 mean "unknown" dimension).  Certain wrappers
+    // that work with TensorShapeProto may fail at runtime when deserializing
+    // a TensorShapeProto containing a dim value of -1.
+    int64 size = 1;
+
+    // Optional name of the tensor dimension.
+    string name = 2;
+  };
+
+  // Dimensions of the tensor, such as {"input", 30}, {"output", 40}
+  // for a 30 x 40 2D tensor.  If an entry has size -1, this
+  // corresponds to a dimension of unknown size. The names are
+  // optional.
+  //
+  // The order of entries in "dim" matters: It indicates the layout of the
+  // values in the tensor in-memory representation.
+  //
+  // The first entry in "dim" is the outermost dimension used to layout the
+  // values, the last entry is the innermost dimension.  This matches the
+  // in-memory layout of RowMajor Eigen tensors.
+  //
+  // If "dim.size()" > 0, "unknown_rank" must be false.
+  repeated Dim dim = 2;
+
+  // If true, the number of dimensions in the shape is unknown.
+  //
+  // If true, "dim.size()" must be 0.
+  bool unknown_rank = 3;
+};
diff --git a/contrib/modules/dnn/src/tensorflow/tf_importer.cpp b/contrib/modules/dnn/src/tensorflow/tf_importer.cpp
new file mode 100644
index 0000000..6caccef
--- /dev/null
+++ b/contrib/modules/dnn/src/tensorflow/tf_importer.cpp
@@ -0,0 +1,749 @@
+// This file is part of OpenCV project.
+// It is subject to the license terms in the LICENSE file found in the top-level directory
+// of this distribution and at http://opencv.org/license.html.
+
+// Copyright (C) 2016, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+
+/*
+Implementation of Tensorflow models parser
+*/
+
+#include "precomp.hpp"
+using namespace cv;
+using namespace cv::dnn;
+
+#if HAVE_PROTOBUF
+#include "graph.pb.h"
+
+#include <iostream>
+#include <fstream>
+#include <algorithm>
+#include <string>
+#include <google/protobuf/message.h>
+#include <google/protobuf/text_format.h>
+#include <google/protobuf/io/zero_copy_stream_impl.h>
+#include "tf_io.hpp"
+
+using ::google::protobuf::RepeatedField;
+using ::google::protobuf::RepeatedPtrField;
+using ::google::protobuf::Message;
+using ::google::protobuf::Descriptor;
+using ::google::protobuf::FieldDescriptor;
+using ::google::protobuf::Reflection;
+
+namespace
+{
+
+static int toNCHW[] = {0, 2, 3, 1};
+
+typedef std::vector<std::pair<String, int> > StrIntVector;
+
+struct Pin
+{
+    Pin(const std::string &_name, int _blobIndex = 0) :
+        name(_name), blobIndex(_blobIndex) {}
+
+    Pin() :
+        name(""), blobIndex(-1) {}
+
+    std::string name;
+    int blobIndex;
+};
+
+BlobShape blobShapeFromTensor(const tensorflow::TensorProto &tensor)
+{
+    if (tensor.has_tensor_shape())
+    {
+        const tensorflow::TensorShapeProto &_shape = tensor.tensor_shape();
+        BlobShape shape = BlobShape::all(_shape.dim_size());
+
+        for (int i = 0; i < _shape.dim_size(); i++)
+            shape[i] = (int)_shape.dim(i).size();
+
+        return shape;
+    }
+    else
+    {
+        CV_Error(Error::StsError, "Unknown shape of input tensor");
+        return BlobShape();
+    }
+}
+
+template <typename T>
+void parseTensor(const tensorflow::TensorProto &tensor, Blob &dstBlob)
+{
+    BlobShape shape = blobShapeFromTensor(tensor);
+
+    if (shape.dims() == 4)
+    {
+        // REORDER blob NHWC to NCHW
+        swap(shape[2], shape[3]); // NHCW
+        swap(shape[1], shape[2]); // NCHW
+    }
+
+    dstBlob.create(shape, CV_32F);
+
+    int size = tensor.tensor_content().size() / sizeof(T);
+    CV_Assert(size == (int)dstBlob.matRefConst().total());
+
+    float *dstData = dstBlob.matRef().ptr<float>();
+    const T *data = reinterpret_cast<const T*>(tensor.tensor_content().c_str());
+
+    if (shape.dims() == 4)
+    {
+        int num = shape[0], channels = shape[1], height = shape[2], width = shape[3];
+        int total = num*channels*height*width;
+        for(int i_n = 0; i_n < shape[0]; i_n++) {
+            for(int i_c = 0; i_c < shape[1]; i_c++) {
+                for(int i_h = 0; i_h < shape[2]; i_h++) {
+                    for(int i_w = 0; i_w < shape[3]; i_w++) {
+                       int dst_i = channels*height*width*i_n + height*width*i_c + width*i_h + i_w;
+                       int src_i = channels*height*width*i_n + i_c + channels*width*i_h + channels*i_w;
+
+                       CV_Assert(dst_i < total);
+                       CV_Assert(src_i < total);
+
+                       dstData[dst_i] = data[src_i];
+                    }
+                }
+            }
+        }
+    } else {
+        for (int i = 0; i < size; i++)
+            dstData[i] = data[i];
+    }
+}
+
+void blobFromTensor(const tensorflow::TensorProto &tensor, Blob &dstBlob)
+{
+    switch (tensor.dtype()) {
+        case tensorflow::DT_FLOAT:
+            parseTensor<float>(tensor, dstBlob);
+            break;
+        case tensorflow::DT_DOUBLE:
+            parseTensor<double>(tensor, dstBlob);
+            break;
+        default:
+            CV_Error(Error::StsError, "Tensor's data type is not supported");
+            break;
+    }
+}
+
+void printList(const tensorflow::AttrValue::ListValue &val)
+{
+    std::cout << "(";
+    for (int i = 0; i < val.i_size(); i++)
+        std::cout << " " << val.i(i);
+    std::cout << " )";
+}
+
+void printTensorShape(const tensorflow::TensorShapeProto &shape)
+{
+    std::cout << "[ ";
+    for (int d = 0; d < shape.dim_size(); d++)
+        std::cout << shape.dim(d).name() <<
+                     ":" << shape.dim(d).size() << " ";
+    std::cout << "]";
+}
+
+void printTensor(const tensorflow::TensorProto &tensor)
+{
+    printTensorShape(tensor.tensor_shape());
+
+    if (tensor.tensor_content().empty())
+        return;
+
+    switch (tensor.dtype())
+    {
+    case 1:  // float
+        {
+            const float *data = reinterpret_cast<const float*>(tensor.tensor_content().c_str());
+            int size = tensor.tensor_content().size() / sizeof(float);
+            for (int i = 0; i < std::min(10, size); i++)
+                std::cout << " " << data[i];
+            if (size > 10)
+                std::cout << " ... " << size - 10 << " more";
+            break;
+        }
+    case 3:  // int32
+        {
+            const int *data = reinterpret_cast<const int*>(tensor.tensor_content().c_str());
+            int size = tensor.tensor_content().size() / sizeof(int);
+            for (int i = 0; i < std::min(10, size); i++)
+                std::cout << " " << data[i];
+            if (size > 10)
+                std::cout << " ... " << size - 10 << " more";
+            break;
+        }
+    default:
+        CV_Error(Error::StsError, "Tensor type is not supported");
+        break;
+    }
+}
+
+void printLayerAttr(const tensorflow::NodeDef &layer)
+{
+    std::cout << std::endl << layer.name() << ":" << layer.op();
+    for (int ii = 0; ii < layer.input_size(); ii++)
+        std::cout << "(" << layer.input(ii) << ")";
+    std::cout << std::endl;
+    google::protobuf::Map<std::string, tensorflow::AttrValue> attr
+            = layer.attr();
+    for (google::protobuf::Map<std::string, tensorflow::AttrValue>::const_iterator ai = attr.begin();
+         ai != attr.end(); ++ai)
+    {
+        std::cout << ai->first << ":";
+        if (ai->first == "dtype" || ai->first == "T")
+            std::cout << ai->second.i();
+        else if (ai->first == "padding")
+            std::cout << ai->second.s();
+        else if (ai->first == "transpose_a" || ai->first == "transpose_b")
+            std::cout << ai->second.b();
+        //            else if (ai->first == "shape")
+        //              printTensorShape(ai->second.shape());
+        else if (ai->first == "strides" || ai->first == "ksize")
+            printList(ai->second.list());
+        else
+            printTensor(ai->second.tensor());
+        std::cout << std::endl;
+    }
+}
+
+bool hasLayerAttr(const tensorflow::NodeDef &layer, const std::string &name)
+{
+    google::protobuf::Map<std::string, tensorflow::AttrValue> attr = layer.attr();
+    return attr.find(name) != attr.end();
+}
+
+const tensorflow::AttrValue& getLayerAttr(const tensorflow::NodeDef &layer, const std::string &name)
+{
+    return layer.attr().at(name);
+}
+
+void setStrides(LayerParams &layerParams, const tensorflow::NodeDef &layer)
+{
+    if (hasLayerAttr(layer, "strides"))
+    {
+        const tensorflow::AttrValue& val = getLayerAttr(layer, "strides");
+        if (val.list().i_size() != 4 ||
+            val.list().i(0) != 1 || val.list().i(3) != 1)
+            CV_Error(Error::StsError, "Unsupported strides");
+        layerParams.set("stride_h", static_cast<int>(val.list().i(1)));
+        layerParams.set("stride_w", static_cast<int>(val.list().i(2)));
+    }
+}
+
+DictValue parseDims(const tensorflow::TensorProto &tensor) {
+    BlobShape shape = blobShapeFromTensor(tensor);
+
+    CV_Assert(tensor.dtype() == tensorflow::DT_INT32);
+    CV_Assert(shape.dims() == 1);
+
+    int size = tensor.tensor_content().size() / sizeof(int);
+    const int *data = reinterpret_cast<const int*>(tensor.tensor_content().c_str());
+    // TODO: add reordering shape if dims == 4
+    return DictValue::arrayInt(data, size);
+}
+
+void setKSize(LayerParams &layerParams, const tensorflow::NodeDef &layer)
+{
+    if (hasLayerAttr(layer, "ksize"))
+    {
+        const tensorflow::AttrValue& val = getLayerAttr(layer, "ksize");
+        if (val.list().i_size() != 4 ||
+            val.list().i(0) != 1 || val.list().i(3) != 1)
+            CV_Error(Error::StsError, "Unsupported ksize");
+        layerParams.set("kernel_h", static_cast<int>(val.list().i(1)));
+        layerParams.set("kernel_w", static_cast<int>(val.list().i(2)));
+    }
+    else
+    {
+        layerParams.set("kernel_h", 1);
+        layerParams.set("kernel_w", 1);
+    }
+}
+
+void setPadding(LayerParams &layerParams, const tensorflow::NodeDef &layer)
+{
+    if (hasLayerAttr(layer, "padding"))
+        layerParams.set("pad_mode", getLayerAttr(layer, "padding").s());
+}
+
+void RemoveIdentityOps(tensorflow::GraphDef& net) {
+    typedef std::map<String, String>  IdentityOpsMap;
+    IdentityOpsMap identity_ops;
+
+    std::vector<int> identity_ops_idx;
+
+    int layersCount = net.node_size();
+    for (int li = 0; li < layersCount; li++)
+    {
+        const tensorflow::NodeDef &layer = net.node(li);
+        String type = layer.op();
+
+        if (type == "Identity") {
+            identity_ops_idx.push_back(li);
+            identity_ops[layer.name()] = layer.input(0);
+        }
+    }
+
+    for (int li = 0; li < layersCount; li++)
+    {
+        tensorflow::NodeDef* layer = net.mutable_node(li);
+        for (int input_id = 0; input_id < layer->input_size(); input_id++) {
+            String input_op_name = layer->input(input_id);
+            IdentityOpsMap::iterator it = identity_ops.find(input_op_name);
+
+            if (it != identity_ops.end()) {
+                layer->set_input(input_id, it->second);
+            }
+        }
+    }
+
+    std::sort(identity_ops_idx.begin(), identity_ops_idx.end());
+
+    int removed_nodes = 0;
+    for(size_t i = 0; i < identity_ops_idx.size(); i++) {
+        int start_id = identity_ops_idx[i] - removed_nodes;
+        net.mutable_node()->DeleteSubrange(start_id, 1);
+        removed_nodes++;
+    }
+}
+
+Pin parsePin(const std::string &name)
+{
+    Pin pin(name);
+
+    size_t delimiter_pos = name.find_first_of(":");
+    if (delimiter_pos != std::string::npos)
+    {
+        pin.name = name.substr(0, delimiter_pos);
+        std::istringstream(name.substr(delimiter_pos + 1)) >> pin.blobIndex;
+    }
+
+    return pin;
+}
+
+StrIntVector getNextLayers(const tensorflow::GraphDef& net, const String& layer_name, const String& type = "")
+{
+   StrIntVector layers;
+
+   for (int li = 0; li < net.node_size(); li++)
+   {
+       const tensorflow::NodeDef& layer = net.node(li);
+       for (int input_id = 0; input_id < layer.input_size(); input_id++) {
+           String input_op_name = parsePin(layer.input(input_id)).name;
+           bool type_ok = type.empty() ? true : type == layer.op();
+           if (input_op_name == layer_name && type_ok)
+               layers.push_back(std::make_pair(layer.name(), li));
+       }
+   }
+
+   return layers;
+}
+
+void ExcludeLayer(tensorflow::GraphDef& net, const int layer_index, const int input_blob_index, bool remove_from_net = true) {
+    String layer_name = net.node(layer_index).name();
+    StrIntVector layers = getNextLayers(net, layer_name);
+
+    String removed_layer_input = net.node(layer_index).input(input_blob_index);
+
+    for (size_t i = 0; i < layers.size(); i++)
+    {
+        tensorflow::NodeDef* layer = net.mutable_node(layers[i].second);
+        for (int input_id = 0; input_id < layer->input_size(); input_id++) {
+                String input_op_name = layer->input(input_id);
+
+                if (input_op_name == layer_name) {
+                    layer->set_input(input_id, removed_layer_input);
+                }
+        }
+    }
+
+    if (remove_from_net)
+        net.mutable_node()->DeleteSubrange(layer_index, 1);
+}
+
+class TFImporter : public Importer {
+public:
+    TFImporter(const char *model);
+    void populateNet(Net dstNet);
+    ~TFImporter() {}
+
+private:
+    void kernelFromTensor(const tensorflow::TensorProto &tensor, Blob &dstBlob);
+
+    void connect(const std::map<String, int>& layers_name_id_map, Net& network, const Pin& outPin,
+                 const int input_layer_id, const int input_blob_id);
+    void connectToAllBlobs(const std::map<String, int>& layer_id, Net& network, const Pin& outPin,
+                           const int input_layer_id, const int input_blobs_count);
+    const tensorflow::TensorProto& getConstBlob(const tensorflow::NodeDef &layer, std::map<String, int> const_layers,
+                                                int input_blob_index = -1, int* actual_inp_blob_idx = 0);
+
+
+    tensorflow::GraphDef net;
+};
+
+TFImporter::TFImporter(const char *model)
+{
+    if (model && model[0])
+        ReadTFNetParamsFromBinaryFileOrDie(model, &net);
+}
+
+void TFImporter::kernelFromTensor(const tensorflow::TensorProto &tensor, Blob &dstBlob)
+{
+    BlobShape shape = blobShapeFromTensor(tensor);
+
+    // TODO: other blob types
+    CV_Assert(tensor.dtype() == tensorflow::DT_FLOAT);
+    CV_Assert(shape.dims() == 4);
+
+    // REORDER kernel HWIO to OIHW
+    swap(shape[0], shape[2]); // IWHO
+    swap(shape[1], shape[3]); // IOHW
+    swap(shape[0], shape[1]); // OIHW
+
+    dstBlob.create(shape, CV_32F);
+
+    int size = tensor.tensor_content().size() / sizeof(float);
+    CV_Assert(size == (int)dstBlob.matRefConst().total());
+
+    float *dstData = dstBlob.matRef().ptr<float>();
+    const float *data = reinterpret_cast<const float*>(tensor.tensor_content().c_str());
+
+    int out_c = shape[0], input_c = shape[1], height = shape[2], width = shape[3];
+    int total = out_c*input_c*height*width;
+    for(int i_oc = 0; i_oc < out_c; i_oc++) {
+        for(int i_ic = 0; i_ic < input_c; i_ic++) {
+            for(int i_h = 0; i_h < height; i_h++) {
+                for(int i_w = 0; i_w < width; i_w++) {
+                    int dst_i = input_c*height*width*i_oc + height*width*i_ic + width*i_h + i_w;
+                    int src_i = out_c*input_c*width*i_h + out_c*input_c*i_w + out_c*i_ic + i_oc;
+                    CV_Assert(dst_i < total);
+                    CV_Assert(src_i < total);
+                   dstData[dst_i] = data[src_i];
+                }
+            }
+        }
+    }
+}
+
+void TFImporter::connect(const std::map<String, int>& layers_name_id_map, Net& network, const Pin& outPin,
+             const int input_layer_id, const int input_blob_id)
+{
+    std::map<String, int>::const_iterator it = layers_name_id_map.find(outPin.name);
+    if (it == layers_name_id_map.end())
+        CV_Error(Error::StsError, "Input layer not found: " + outPin.name);
+    network.connect(it->second, outPin.blobIndex, input_layer_id, input_blob_id);
+}
+
+void TFImporter::connectToAllBlobs(const std::map<String, int>& layer_id, Net& network, const Pin& outPin,
+                     const int input_layer_id, const int input_blobs_count)
+{
+    for (int input_blob_id = 0; input_blob_id < input_blobs_count; input_blob_id++)
+        connect(layer_id, network, outPin, input_layer_id, input_blob_id);
+}
+
+const tensorflow::TensorProto& TFImporter::getConstBlob(const tensorflow::NodeDef &layer, std::map<String, int> const_layers,
+                                              int input_blob_index, int* actual_inp_blob_idx) {
+    if (input_blob_index == -1) {
+        for(int i = 0; i < layer.input_size(); i++) {
+            Pin input = parsePin(layer.input(i));
+            if (const_layers.find(input.name) != const_layers.end()) {
+                if (input_blob_index != -1)
+                    CV_Error(Error::StsError, "More than one input is Const op");
+
+                input_blob_index = i;
+            }
+        }
+    }
+
+    if (input_blob_index == -1)
+        CV_Error(Error::StsError, "Const input blob for weights not found");
+
+    Pin kernel_inp = parsePin(layer.input(input_blob_index));
+    if (const_layers.find(kernel_inp.name) == const_layers.end())
+        CV_Error(Error::StsError, "Const kernel input not found");
+    if (kernel_inp.blobIndex != 0)
+        CV_Error(Error::StsError, "Unsupported kernel input");
+
+    if(actual_inp_blob_idx) {
+        *actual_inp_blob_idx = input_blob_index;
+    }
+
+    return net.node(const_layers.at(kernel_inp.name)).attr().at("value").tensor();
+}
+
+
+void TFImporter::populateNet(Net dstNet)
+{
+    RemoveIdentityOps(net);
+
+    std::map<int, String> layers_to_ignore;
+
+    int layersSize = net.node_size();
+
+    // find all Const layers for params
+    std::map<String, int> value_id;
+    for (int li = 0; li < layersSize; li++)
+    {
+        const tensorflow::NodeDef &layer = net.node(li);
+        String name = layer.name();
+        String type = layer.op();
+
+        if (type != "Const")
+            continue;  // only Const parameters are supported
+
+        if (layer.attr().find("value") != layer.attr().end())
+        {
+            value_id.insert(std::make_pair(name, li));
+        }
+
+        layers_to_ignore[li] = name;
+    }
+
+    std::map<String, int> layer_id;
+
+    for (int li = 0; li < layersSize; li++)
+    {
+        const tensorflow::NodeDef &layer = net.node(li);
+        String name = layer.name();
+        String type = layer.op();
+        LayerParams layerParams;
+
+        if(layers_to_ignore.find(li) != layers_to_ignore.end())
+            continue;
+
+        if (type == "Conv2D")
+        {
+            layerParams.set("bias_term", false);
+            layerParams.blobs.resize(1);
+
+            StrIntVector next_layers = getNextLayers(net, name, "BiasAdd");
+            if (next_layers.size() == 1) {
+                layerParams.set("bias_term", true);
+                layerParams.blobs.resize(2);
+
+                int weights_layer_index = next_layers[0].second;
+
+                blobFromTensor(getConstBlob(net.node(weights_layer_index), value_id), layerParams.blobs[1]);
+                ExcludeLayer(net, weights_layer_index, 0, false);
+                layers_to_ignore[weights_layer_index] = next_layers[0].first;
+            }
+
+            kernelFromTensor(getConstBlob(layer, value_id), layerParams.blobs[0]);
+            BlobShape kshape = layerParams.blobs[0].shape();
+            layerParams.set("kernel_h", kshape[2]);
+            layerParams.set("kernel_w", kshape[3]);
+            layerParams.set("num_output", kshape[0]);
+
+            setStrides(layerParams, layer);
+            setPadding(layerParams, layer);
+
+            int id = dstNet.addLayer(name, "Convolution", layerParams);
+            layer_id[name] = id;
+
+            // one input only
+            connect(layer_id, dstNet, parsePin(layer.input(0)), id, 0);
+        }
+        else if (type == "BiasAdd" || type == "Add")
+        {
+            layerParams.blobs.resize(1);
+            blobFromTensor(getConstBlob(layer, value_id), layerParams.blobs[0]);
+
+            int id = dstNet.addLayer(name, "Shift", layerParams);
+            layer_id[name] = id;
+
+            // one input only
+            connect(layer_id, dstNet, parsePin(layer.input(0)), id, 0);
+        }
+        else if (type == "Identity")
+        {
+            int id = dstNet.addLayer(name, "Identity", layerParams);
+            layer_id[name] = id;
+
+            connectToAllBlobs(layer_id, dstNet, parsePin(layer.input(0)), id, layer.input_size());
+        }
+        else if (type == "MatMul")
+        {
+            CV_Assert(layer.input_size() == 2);
+
+            layerParams.set("axis", 0);
+            layerParams.set("bias_term", false);
+            layerParams.blobs.resize(1);
+
+            StrIntVector next_layers = getNextLayers(net, name, "BiasAdd");
+            if (next_layers.size() == 1) {
+                layerParams.set("bias_term", true);
+                layerParams.blobs.resize(2);
+
+                int weights_layer_index = next_layers[0].second;
+                blobFromTensor(getConstBlob(net.node(weights_layer_index), value_id), layerParams.blobs[1]);
+                ExcludeLayer(net, weights_layer_index, 0, false);
+                layers_to_ignore[weights_layer_index] = next_layers[0].first;
+            }
+
+            int kernel_blob_index = -1;
+            blobFromTensor(getConstBlob(layer, value_id, -1, &kernel_blob_index), layerParams.blobs[0]);
+
+            if (kernel_blob_index == 1) { // In this case output is computed by x*W formula - W should be transposed
+                Mat data = layerParams.blobs[0].matRef().t();
+                BlobShape shape(data.rows, data.cols);
+                layerParams.blobs[0].fill(shape, layerParams.blobs[0].type(), data.data);
+            }
+
+            BlobShape kshape = layerParams.blobs[0].shape();
+            layerParams.set("num_output", kshape[0]);
+
+            int id = dstNet.addLayer(name, "InnerProduct", layerParams);
+            layer_id[name] = id;
+
+            // one input only
+            int input_blob_index = kernel_blob_index == 0 ? 1 : 0;
+            connect(layer_id, dstNet, parsePin(layer.input(input_blob_index)), id, 0);
+        }
+        else if (type == "Reshape")
+        {
+            layerParams.set("dim", parseDims(getConstBlob(layer, value_id, 1)));
+            layerParams.set("reorder_dims", true);
+
+            int id = dstNet.addLayer(name, "Reshape", layerParams);
+            layer_id[name] = id;
+
+            // one input only
+            connect(layer_id, dstNet, parsePin(layer.input(0)), id, 0);
+        }
+        else if (type == "Const")
+        {
+        }
+        else if (type == "Softmax")
+        {
+            layerParams.set("axis", -1);
+            int id = dstNet.addLayer(name, "Softmax", layerParams);
+            layer_id[name] = id;
+
+            connectToAllBlobs(layer_id, dstNet, parsePin(layer.input(0)), id, layer.input_size());
+        }
+        else if (type == "LRN")
+        {
+            if(hasLayerAttr(layer, "alpha")) {
+                layerParams.set("alpha", getLayerAttr(layer, "alpha").f());
+            }
+            if(hasLayerAttr(layer, "beta")) {
+                layerParams.set("beta", getLayerAttr(layer, "beta").f());
+            }
+            if(hasLayerAttr(layer, "depth_radius")) {
+                int radius = (int)getLayerAttr(layer, "depth_radius").i();
+                layerParams.set("local_size", 2*radius + 1);
+            }
+            if(hasLayerAttr(layer, "bias")) {
+                layerParams.set("bias", getLayerAttr(layer, "bias").f());
+            }
+            layerParams.set("norm_sz", false);
+
+            int id = dstNet.addLayer(name, "LRN", layerParams);
+            layer_id[name] = id;
+
+            connectToAllBlobs(layer_id, dstNet, parsePin(layer.input(0)), id, layer.input_size());
+        }
+        else if (type == "Concat")
+        {
+            int axis = getConstBlob(layer, value_id, 0).int_val().Get(0);
+            layerParams.set("axis", toNCHW[axis]);
+
+            int id = dstNet.addLayer(name, "Concat", layerParams);
+            layer_id[name] = id;
+
+            // input(0) is concat_dim
+            for (int ii = 1; ii < layer.input_size(); ii++)
+            {
+                Pin inp = parsePin(layer.input(ii));
+                if (layer_id.find(inp.name) == layer_id.end())
+                    CV_Error(Error::StsError, "Input layer not found: " + inp.name);
+                dstNet.connect(layer_id.at(inp.name), inp.blobIndex, id, ii - 1);
+            }
+        }
+        else if (type == "Relu")
+        {
+            int id = dstNet.addLayer(name, "ReLU", layerParams);
+            layer_id[name] = id;
+
+            connectToAllBlobs(layer_id, dstNet, parsePin(layer.input(0)), id, layer.input_size());
+        }
+        else if (type == "MaxPool")
+        {
+            layerParams.set("pool", "max");
+
+            setKSize(layerParams, layer);
+            setStrides(layerParams, layer);
+            setPadding(layerParams, layer);
+
+            int id = dstNet.addLayer(name, "Pooling", layerParams);
+            layer_id[name] = id;
+
+            connectToAllBlobs(layer_id, dstNet, parsePin(layer.input(0)), id, layer.input_size());
+        }
+        else if (type == "AvgPool")
+        {
+            layerParams.set("pool", "ave");
+
+            setKSize(layerParams, layer);
+            setStrides(layerParams, layer);
+            setPadding(layerParams, layer);
+
+            int id = dstNet.addLayer(name, "Pooling", layerParams);
+            layer_id[name] = id;
+
+            connectToAllBlobs(layer_id, dstNet, parsePin(layer.input(0)), id, layer.input_size());
+        }
+        else if (type == "Placeholder")
+        {
+            std::vector<String> netInputs(1);
+            netInputs[0] = name;
+            layer_id[name] = 0;
+            dstNet.setNetInputs(netInputs);
+        }
+        else if (type == "Split") {
+            // TODO: determing axis index remapping by input dimensions order of input blob
+            // TODO: slicing input may be Const op
+            // TODO: slicing kernels for convolutions - in current implenmentation it is impossible
+            // TODO: add parsing num of slices parameter
+            CV_Assert(layer.input_size() == 2);
+            // num_split
+            // 1st blob is dims tensor
+            layerParams.set("slice_point", DictValue::arrayReal((double*)0, 0));
+
+            int axis = getConstBlob(layer, value_id, 0).int_val().Get(0);
+            layerParams.set("axis", toNCHW[axis]);
+
+            int id = dstNet.addLayer(name, "Slice", layerParams);
+            layer_id[name] = id;
+
+            // one input only
+            connect(layer_id, dstNet, parsePin(layer.input(1)), id, 0);
+        }
+        else
+        {
+            printLayerAttr(layer);
+            CV_Error_(Error::StsError, ("Unknown layer type %s in op %s", type.c_str(), name.c_str()));
+        }
+    }
+}
+
+} // namespace
+
+Ptr<Importer> cv::dnn::createTensorflowImporter(const String &model)
+{
+    return Ptr<Importer>(new TFImporter(model.c_str()));
+}
+
+#else //HAVE_PROTOBUF
+
+Ptr<Importer> cv::dnn::createTensorflowImporter(const String&)
+{
+    CV_Error(cv::Error::StsNotImplemented, "libprotobuf required to import data from TensorFlow models");
+    return Ptr<Importer>();
+}
+
+#endif //HAVE_PROTOBUF
diff --git a/contrib/modules/dnn/src/tensorflow/tf_io.cpp b/contrib/modules/dnn/src/tensorflow/tf_io.cpp
new file mode 100644
index 0000000..fafe3cf
--- /dev/null
+++ b/contrib/modules/dnn/src/tensorflow/tf_io.cpp
@@ -0,0 +1,63 @@
+// This file is part of OpenCV project.
+// It is subject to the license terms in the LICENSE file found in the top-level directory
+// of this distribution and at http://opencv.org/license.html.
+
+// Copyright (C) 2016, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+
+/*
+Implementation of various functions which are related to Tensorflow models reading.
+*/
+
+#if HAVE_PROTOBUF
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/io/zero_copy_stream_impl.h>
+#include <google/protobuf/text_format.h>
+
+#include <opencv2/core.hpp>
+
+#include <map>
+#include <string>
+#include <fstream>
+#include <vector>
+
+#include "graph.pb.h"
+#include "tf_io.hpp"
+#include "../caffe/glog_emulator.hpp"
+
+namespace cv {
+namespace dnn {
+
+using std::string;
+using std::map;
+using namespace tensorflow;
+using namespace ::google::protobuf;
+using namespace ::google::protobuf::io;
+
+const int kProtoReadBytesLimit = INT_MAX;  // Max size of 2 GB minus 1 byte.
+
+// TODO: remove Caffe duplicate
+bool ReadProtoFromBinaryFileTF(const char* filename, Message* proto) {
+    std::ifstream fs(filename, std::ifstream::in | std::ifstream::binary);
+    CHECK(fs.is_open()) << "Can't open \"" << filename << "\"";
+    ZeroCopyInputStream* raw_input = new IstreamInputStream(&fs);
+    CodedInputStream* coded_input = new CodedInputStream(raw_input);
+    coded_input->SetTotalBytesLimit(kProtoReadBytesLimit, 536870912);
+
+    bool success = proto->ParseFromCodedStream(coded_input);
+
+    delete coded_input;
+    delete raw_input;
+    fs.close();
+    return success;
+}
+
+void ReadTFNetParamsFromBinaryFileOrDie(const char* param_file,
+                                      tensorflow::GraphDef* param) {
+  CHECK(ReadProtoFromBinaryFileTF(param_file, param))
+      << "Failed to parse GraphDef file: " << param_file;
+}
+
+}
+}
+#endif
diff --git a/contrib/modules/dnn/src/tensorflow/tf_io.hpp b/contrib/modules/dnn/src/tensorflow/tf_io.hpp
new file mode 100644
index 0000000..db9612f
--- /dev/null
+++ b/contrib/modules/dnn/src/tensorflow/tf_io.hpp
@@ -0,0 +1,29 @@
+// This file is part of OpenCV project.
+// It is subject to the license terms in the LICENSE file found in the top-level directory
+// of this distribution and at http://opencv.org/license.html.
+
+// Copyright (C) 2016, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+
+/*
+Declaration of various functions which are related to Tensorflow models reading.
+*/
+
+#ifndef __OPENCV_DNN_TF_IO_HPP__
+#define __OPENCV_DNN_TF_IO_HPP__
+#if HAVE_PROTOBUF
+
+#include "graph.pb.h"
+
+namespace cv {
+namespace dnn {
+
+// Read parameters from a file into a GraphDef proto message.
+void ReadTFNetParamsFromBinaryFileOrDie(const char* param_file,
+                                      tensorflow::GraphDef* param);
+
+}
+}
+
+#endif
+#endif
diff --git a/contrib/modules/dnn/src/tensorflow/types.proto b/contrib/modules/dnn/src/tensorflow/types.proto
new file mode 100644
index 0000000..051361b
--- /dev/null
+++ b/contrib/modules/dnn/src/tensorflow/types.proto
@@ -0,0 +1,60 @@
+syntax = "proto3";
+
+package tensorflow;
+option cc_enable_arenas = true;
+option java_outer_classname = "TypesProtos";
+option java_multiple_files = true;
+option java_package = "org.tensorflow.framework";
+
+enum DataType {
+  // Not a legal value for DataType.  Used to indicate a DataType field
+  // has not been set.
+  DT_INVALID = 0;
+
+  // Data types that all computation devices are expected to be
+  // capable to support.
+  DT_FLOAT = 1;
+  DT_DOUBLE = 2;
+  DT_INT32 = 3;
+  DT_UINT8 = 4;
+  DT_INT16 = 5;
+  DT_INT8 = 6;
+  DT_STRING = 7;
+  DT_COMPLEX64 = 8;  // Single-precision complex
+  DT_INT64 = 9;
+  DT_BOOL = 10;
+  DT_QINT8 = 11;     // Quantized int8
+  DT_QUINT8 = 12;    // Quantized uint8
+  DT_QINT32 = 13;    // Quantized int32
+  DT_BFLOAT16 = 14;  // Float32 truncated to 16 bits.  Only for cast ops.
+  DT_QINT16 = 15;    // Quantized int16
+  DT_QUINT16 = 16;   // Quantized uint16
+  DT_UINT16 = 17;
+  DT_COMPLEX128 = 18;  // Double-precision complex
+  DT_HALF = 19;
+
+  // TODO(josh11b): DT_GENERIC_PROTO = ??;
+  // TODO(jeff,josh11b): DT_UINT64?  DT_UINT32?
+
+  // Do not use!  These are only for parameters.  Every enum above
+  // should have a corresponding value below (verified by types_test).
+  DT_FLOAT_REF = 101;
+  DT_DOUBLE_REF = 102;
+  DT_INT32_REF = 103;
+  DT_UINT8_REF = 104;
+  DT_INT16_REF = 105;
+  DT_INT8_REF = 106;
+  DT_STRING_REF = 107;
+  DT_COMPLEX64_REF = 108;
+  DT_INT64_REF = 109;
+  DT_BOOL_REF = 110;
+  DT_QINT8_REF = 111;
+  DT_QUINT8_REF = 112;
+  DT_QINT32_REF = 113;
+  DT_BFLOAT16_REF = 114;
+  DT_QINT16_REF = 115;
+  DT_QUINT16_REF = 116;
+  DT_UINT16_REF = 117;
+  DT_COMPLEX128_REF = 118;
+  DT_HALF_REF = 119;
+}
diff --git a/contrib/modules/dnn/src/tensorflow/versions.proto b/contrib/modules/dnn/src/tensorflow/versions.proto
new file mode 100644
index 0000000..7d5e58a
--- /dev/null
+++ b/contrib/modules/dnn/src/tensorflow/versions.proto
@@ -0,0 +1,31 @@
+syntax = "proto3";
+
+package tensorflow;
+option cc_enable_arenas = true;
+option java_outer_classname = "VersionsProtos";
+option java_multiple_files = true;
+option java_package = "org.tensorflow.framework";
+
+// Version information for a piece of serialized data
+//
+// There are different types of versions for each type of data
+// (GraphDef, etc.), but they all have the same common shape
+// described here.
+//
+// Each consumer has "consumer" and "min_producer" versions (specified
+// elsewhere).  A consumer is allowed to consume this data if
+//
+//   producer >= min_producer
+//   consumer >= min_consumer
+//   consumer not in bad_consumers
+//
+message VersionDef {
+  // The version of the code that produced this data.
+  int32 producer = 1;
+
+  // Any consumer below this version is not allowed to consume this data.
+  int32 min_consumer = 2;
+
+  // Specific consumer versions which are disallowed (e.g. due to bugs).
+  repeated int32 bad_consumers = 3;
+};
diff --git a/contrib/modules/dnn/src/torch/torch_importer.cpp b/contrib/modules/dnn/src/torch/torch_importer.cpp
index 8a4071d..f11028f 100644
--- a/contrib/modules/dnn/src/torch/torch_importer.cpp
+++ b/contrib/modules/dnn/src/torch/torch_importer.cpp
@@ -52,6 +52,12 @@ namespace dnn {
 #if defined(ENABLE_TORCH_IMPORTER) && ENABLE_TORCH_IMPORTER
 #include "THDiskFile.h"
 
+#ifdef NDEBUG
+static bool dbgPrint = false;
+#else
+static bool dbgPrint = true;
+#endif
+
 enum LuaType
 {
     TYPE_NIL      = 0,
@@ -290,7 +296,8 @@ struct TorchImporter : public ::cv::dnn::Importer
             }
 
             String key = readString();
-            std::cout << i << "th key: " << key << "\n";
+            if (dbgPrint)
+                std::cout << i << "th key: " << key << "\n";
 
             fpos = THFile_position(file);
             int vtype = readInt();
@@ -334,13 +341,16 @@ struct TorchImporter : public ::cv::dnn::Importer
         }
 
         //Debug output
-        std::cout << "scalarParams:\n";
-        std::cout << scalarParams;
+        if (dbgPrint)
+        {
+            std::cout << "scalarParams:\n";
+            std::cout << scalarParams;
 
-        std::cout << "#" << tensorParams.size() << " tensorParams:\n";
-        std::map<String,Blob>::const_iterator it;
-        for (it = tensorParams.begin(); it != tensorParams.end(); it++)
-            std::cout << it->first << ": Tensor " << it->second.shape() << "\n";
+            std::cout << "#" << tensorParams.size() << " tensorParams:\n";
+            std::map<String,Blob>::const_iterator it;
+            for (it = tensorParams.begin(); it != tensorParams.end(); it++)
+                std::cout << it->first << ": Tensor " << it->second.shape() << "\n";
+        }
     }
 
     void readTorchTensor(int indexTensor, int typeTensor)
@@ -435,7 +445,9 @@ struct TorchImporter : public ::cv::dnn::Importer
 
         String className = readTorchClassName();
         String nnName;
-        std::cout << "Class: " << className << std::endl;
+
+        if (dbgPrint)
+            std::cout << "Class: " << className << std::endl;
 
         int type;
         if ( (type = parseTensorType(className)) >= 0 ) //is Tensor
@@ -680,13 +692,13 @@ struct TorchImporter : public ::cv::dnn::Importer
     }
 };
 
-CV_EXPORTS Ptr<Importer> createTorchImporter(const String &filename, bool isBinary)
+Ptr<Importer> createTorchImporter(const String &filename, bool isBinary)
 {
     return Ptr<Importer>(new TorchImporter(filename, isBinary));
 }
 
 
-CV_EXPORTS Blob readTorchBlob(const String &filename, bool isBinary)
+Blob readTorchBlob(const String &filename, bool isBinary)
 {
     Ptr<TorchImporter> importer(new TorchImporter(filename, isBinary));
     importer->readObject();
@@ -697,13 +709,13 @@ CV_EXPORTS Blob readTorchBlob(const String &filename, bool isBinary)
 
 #else //ENABLE_TORCH_IMPORTER
 
-CV_EXPORTS Ptr<Importer> createTorchImporter(const String&, bool)
+Ptr<Importer> createTorchImporter(const String&, bool)
 {
     CV_Error(Error::StsNotImplemented, "Module was build without Torch importer");
     return Ptr<Importer>();
 }
 
-CV_EXPORTS Blob readTorchMat(const String&, bool)
+Blob readTorchBlob(const String&, bool)
 {
     CV_Error(Error::StsNotImplemented, "Module was build without Torch importer");
     return Blob();
diff --git a/contrib/modules/dnn/test/cnpy.h b/contrib/modules/dnn/test/cnpy.h
index 4e98ce8..37732b0 100644
--- a/contrib/modules/dnn/test/cnpy.h
+++ b/contrib/modules/dnn/test/cnpy.h
@@ -95,7 +95,7 @@ namespace cnpy {
 
     template<typename T> std::vector<char>& operator+=(std::vector<char>& lhs, const T rhs) {
         //write in little endian
-        for(char byte = 0; byte < sizeof(T); byte++) {
+        for(char byte = 0; (size_t)byte < sizeof(T); byte++) {
             char val = *((char*)&rhs+byte);
             lhs.push_back(val);
         }
diff --git a/contrib/modules/dnn/test/test_googlenet.cpp b/contrib/modules/dnn/test/test_googlenet.cpp
index 74be053..6adf321 100644
--- a/contrib/modules/dnn/test/test_googlenet.cpp
+++ b/contrib/modules/dnn/test/test_googlenet.cpp
@@ -42,6 +42,8 @@
 #if defined(ENABLE_CAFFE_MODEL_TESTS)
 #include "test_precomp.hpp"
 #include "npy_blob.hpp"
+#include <opencv2/core/ocl.hpp>
+#include <opencv2/ts/ocl_test.hpp>
 
 namespace cvtest
 {
@@ -55,7 +57,7 @@ static std::string _tf(TString filename)
     return (getOpenCVExtraDir() + "/dnn/") + filename;
 }
 
-TEST(Reproducibility_GoogLeNet, Accuracy)
+static void launchGoogleNetTest()
 {
     Net net;
     {
@@ -69,7 +71,7 @@ TEST(Reproducibility_GoogLeNet, Accuracy)
     inpMats.push_back( imread(_tf("googlenet_1.jpg")) );
     ASSERT_TRUE(!inpMats[0].empty() && !inpMats[1].empty());
 
-    net.setBlob(".data", Blob(inpMats));
+    net.setBlob(".data", Blob::fromImages(inpMats));
     net.forward();
 
     Blob out = net.getBlob("prob");
@@ -77,5 +79,16 @@ TEST(Reproducibility_GoogLeNet, Accuracy)
     normAssert(out, ref);
 }
 
+TEST(Reproducibility_GoogLeNet, Accuracy)
+{
+    OCL_OFF(launchGoogleNetTest());
+}
+
+OCL_TEST(Reproducibility_GoogLeNet, Accuracy)
+{
+    OCL_ON(launchGoogleNetTest());
+    OCL_OFF();
+}
+
 }
 #endif
diff --git a/contrib/modules/dnn/test/test_layers.cpp b/contrib/modules/dnn/test/test_layers.cpp
index 35c678b..6680de3 100644
--- a/contrib/modules/dnn/test/test_layers.cpp
+++ b/contrib/modules/dnn/test/test_layers.cpp
@@ -43,6 +43,8 @@
 #include <opencv2/core/ocl.hpp>
 #include <iostream>
 #include "npy_blob.hpp"
+#include <opencv2/dnn/all_layers.hpp>
+#include <opencv2/ts/ocl_test.hpp>
 
 namespace cvtest
 {
@@ -56,7 +58,32 @@ static String _tf(TString filename)
     return (getOpenCVExtraDir() + "/dnn/layers/") + filename;
 }
 
-static void testLayer(String basename, bool useCaffeModel = false, bool useCommonInputBlob = true)
+
+enum RunLayerMode
+{
+    ALLOC_ONLY = 1,
+    FORWARD_ONLY = 2,
+    ALLOC_AND_FORWARD = ALLOC_ONLY | FORWARD_ONLY
+};
+
+typedef Ptr<std::vector<Blob*> > PtrToVecPtrBlob;
+
+PtrToVecPtrBlob
+runLayer(Ptr<Layer> layer, std::vector<Blob> &inpBlobs, std::vector<Blob> &outBlobs, int mode = ALLOC_AND_FORWARD)
+{
+    PtrToVecPtrBlob inpPtrs(new std::vector<Blob*>());
+    inpPtrs->reserve(inpBlobs.size());
+    for (size_t i = 0; i < inpBlobs.size(); i++)
+        inpPtrs->push_back(&inpBlobs[i]);
+
+    if (mode & ALLOC_ONLY) layer->allocate(*inpPtrs, outBlobs);
+    if (mode & FORWARD_ONLY) layer->forward(*inpPtrs, outBlobs);
+
+    return inpPtrs;
+}
+
+
+void testLayerUsingCaffeModels(String basename, bool useCaffeModel = false, bool useCommonInputBlob = true)
 {
     String prototxt = _tf(basename + ".prototxt");
     String caffemodel = _tf(basename + ".caffemodel");
@@ -64,6 +91,8 @@ static void testLayer(String basename, bool useCaffeModel = false, bool useCommo
     String inpfile = (useCommonInputBlob) ? _tf("blob.npy") : _tf(basename + ".input.npy");
     String outfile = _tf(basename + ".npy");
 
+    cv::setNumThreads(cv::getNumberOfCPUs());
+
     Net net;
     {
         Ptr<Importer> importer = createCaffeImporter(prototxt, (useCaffeModel) ? caffemodel : String());
@@ -83,58 +112,89 @@ static void testLayer(String basename, bool useCaffeModel = false, bool useCommo
 
 TEST(Layer_Test_Softmax, Accuracy)
 {
-     testLayer("layer_softmax");
+     OCL_OFF(testLayerUsingCaffeModels("layer_softmax"));
+}
+OCL_TEST(Layer_Test_Softmax, Accuracy)
+{
+     OCL_ON(testLayerUsingCaffeModels("layer_softmax"));
+     OCL_OFF();
 }
 
 TEST(Layer_Test_LRN_spatial, Accuracy)
 {
-     testLayer("layer_lrn_spatial");
+     OCL_OFF(testLayerUsingCaffeModels("layer_lrn_spatial"));
+}
+OCL_TEST(Layer_Test_LRN_spatial, Accuracy)
+{
+     OCL_ON(testLayerUsingCaffeModels("layer_lrn_spatial"));
+     OCL_OFF();
 }
 
 TEST(Layer_Test_LRN_channels, Accuracy)
 {
-     testLayer("layer_lrn_channels");
+     OCL_OFF(testLayerUsingCaffeModels("layer_lrn_channels"));
+}
+OCL_TEST(Layer_Test_LRN_channels, Accuracy)
+{
+    OCL_ON(testLayerUsingCaffeModels("layer_lrn_channels"));
+    OCL_OFF();
 }
 
 TEST(Layer_Test_Convolution, Accuracy)
 {
-     testLayer("layer_convolution", true);
+     OCL_OFF(testLayerUsingCaffeModels("layer_convolution", true));
+}
+OCL_TEST(Layer_Test_Convolution, Accuracy)
+{
+     OCL_ON(testLayerUsingCaffeModels("layer_convolution", true));
+     OCL_OFF();
 }
 
-//TODO: move this test into separate file
-TEST(Layer_Test_Convolution, AccuracyOCL)
+TEST(Layer_Test_DeConvolution, Accuracy)
 {
-    if (cv::ocl::haveOpenCL())
-    {
-        cv::ocl::setUseOpenCL(true);
-        testLayer("layer_convolution", true);
-        cv::ocl::setUseOpenCL(false);
-    }
+     OCL_OFF(testLayerUsingCaffeModels("layer_deconvolution", true, false));
+}
+OCL_TEST(Layer_Test_DeConvolution, Accuracy)
+{
+     OCL_ON(testLayerUsingCaffeModels("layer_deconvolution", true, false););
+     OCL_OFF();
 }
 
 TEST(Layer_Test_InnerProduct, Accuracy)
 {
-     testLayer("layer_inner_product", true);
+     OCL_OFF(testLayerUsingCaffeModels("layer_inner_product", true));
+}
+OCL_TEST(Layer_Test_InnerProduct, Accuracy)
+{
+    OCL_ON(testLayerUsingCaffeModels("layer_inner_product", true));
+    OCL_OFF();
 }
 
 TEST(Layer_Test_Pooling_max, Accuracy)
 {
-     testLayer("layer_pooling_max");
+     OCL_OFF(testLayerUsingCaffeModels("layer_pooling_max"));
+     OCL_ON();
+}
+OCL_TEST(Layer_Test_Pooling_max, Accuracy)
+{
+     OCL_ON(testLayerUsingCaffeModels("layer_pooling_max"));
+     OCL_OFF();
 }
 
 TEST(Layer_Test_Pooling_ave, Accuracy)
 {
-     testLayer("layer_pooling_ave");
+     OCL_OFF(testLayerUsingCaffeModels("layer_pooling_ave"));
+     OCL_ON();
 }
-
-TEST(Layer_Test_DeConvolution, Accuracy)
+OCL_TEST(Layer_Test_Pooling_ave, Accuracy)
 {
-     testLayer("layer_deconvolution", true, false);
+     OCL_ON(testLayerUsingCaffeModels("layer_pooling_ave"));
+     OCL_OFF();
 }
 
 TEST(Layer_Test_MVN, Accuracy)
 {
-     testLayer("layer_mvn");
+     OCL_OFF(testLayerUsingCaffeModels("layer_mvn"));
 }
 
 TEST(Layer_Test_Reshape, squeeze)
@@ -151,10 +211,31 @@ TEST(Layer_Test_Reshape, squeeze)
     rl->allocate(inpVec, outVec);
     rl->forward(inpVec, outVec);
 
-    EXPECT_EQ(outVec[0].shape(), BlobShape(Vec3i(4, 3, 2)));
+    EXPECT_EQ(outVec[0].shape(), BlobShape(4, 3, 2));
 }
 
-TEST(Layer_Test_Reshape_Split_Slice, Accuracy)
+//template<typename XMat>
+//static void test_Layer_Concat()
+//{
+//    Matx21f a(1.f, 1.f), b(2.f, 2.f), c(3.f, 3.f);
+//    std::vector<Blob> res(1), src = { Blob(XMat(a)), Blob(XMat(b)), Blob(XMat(c)) };
+//    Blob ref(XMat(Matx23f(1.f, 2.f, 3.f, 1.f, 2.f, 3.f)));
+//
+//    runLayer(ConcatLayer::create(1), src, res);
+//    normAssert(ref, res[0]);
+//}
+//TEST(Layer_Concat, Accuracy)
+//{
+//    OCL_OFF(test_Layer_Concat<Mat>());
+//}
+//OCL_TEST(Layer_Concat, Accuracy)
+//{
+//    OCL_ON(test_Layer_Concat<Mat>());
+//    OCL_OFF();
+//}
+
+template<typename XMat>
+void test_Reshape_Split_Slice_layers()
 {
     Net net;
     {
@@ -163,9 +244,9 @@ TEST(Layer_Test_Reshape_Split_Slice, Accuracy)
         importer->populateNet(net);
     }
 
-    Blob input(BlobShape(Vec2i(6, 12)));
+    Blob input(BlobShape(6, 12));
     RNG rng(0);
-    rng.fill(input.matRef(), RNG::UNIFORM, -1, 1);
+    rng.fill(input.getRef<XMat>(), RNG::UNIFORM, -1, 1);
 
     net.setBlob(".input", input);
     net.forward();
@@ -173,5 +254,143 @@ TEST(Layer_Test_Reshape_Split_Slice, Accuracy)
 
     normAssert(input, output);
 }
+TEST(Layer_Test_Reshape_Split_Slice, Accuracy)
+{
+    OCL_OFF(test_Reshape_Split_Slice_layers<Mat>());
+}
+OCL_TEST(Layer_Test_Reshape_Split_Slice, Accuracy)
+{
+    OCL_ON(test_Reshape_Split_Slice_layers<UMat>());
+    OCL_OFF();
+}
+
+class Layer_LSTM_Test : public ::testing::Test
+{
+public:
+    int numInp, numOut;
+    Blob Wh, Wx, b;
+    Ptr<LSTMLayer> layer;
+    std::vector<Blob> inputs, outputs;
+
+    Layer_LSTM_Test() {}
+
+    void init(const BlobShape &inpShape_, const BlobShape &outShape_)
+    {
+        numInp = inpShape_.total();
+        numOut = outShape_.total();
+
+        Wh = Blob(BlobShape(4 * numOut, numOut));
+        Wx = Blob(BlobShape(4 * numOut, numInp));
+        b  = Blob(BlobShape(4 * numOut, 1));
+
+        layer = LSTMLayer::create();
+        layer->setWeights(Wh, Wx, b);
+        layer->setOutShape(outShape_);
+    }
+};
+
+TEST_F(Layer_LSTM_Test, get_set_test)
+{
+    BlobShape TN(4);
+    BlobShape inpShape(5, 3, 2), inpResShape = TN + inpShape;
+    BlobShape outShape(3, 1, 2), outResShape = TN + outShape;
+
+    init(inpShape, outShape);
+    layer->setProduceCellOutput(true);
+    layer->setUseTimstampsDim(false);
+    layer->setOutShape(outShape);
+
+    layer->setC(Blob(outResShape));
+    layer->setH(Blob(outResShape));
+
+    inputs.push_back(Blob(inpResShape));
+    runLayer(layer, inputs, outputs);
+
+    EXPECT_EQ(2u, outputs.size());
+    EXPECT_EQ(outResShape, outputs[0].shape());
+    EXPECT_EQ(outResShape, outputs[1].shape());
+
+    EXPECT_EQ(outResShape, layer->getC().shape());
+    EXPECT_EQ(outResShape, layer->getH().shape());
+
+    EXPECT_EQ(0, layer->inputNameToIndex("x"));
+    EXPECT_EQ(0, layer->outputNameToIndex("h"));
+    EXPECT_EQ(1, layer->outputNameToIndex("c"));
+}
+
+TEST(Layer_LSTM_Test_Accuracy_with_, CaffeRecurrent)
+{
+    Ptr<LSTMLayer> layer = LSTMLayer::create();
+
+    Blob Wx = blobFromNPY(_tf("lstm.prototxt.w_0.npy"));
+    Blob Wh = blobFromNPY(_tf("lstm.prototxt.w_2.npy"));
+    Blob b  = blobFromNPY(_tf("lstm.prototxt.w_1.npy"));
+    layer->setWeights(Wh, Wx, b);
+
+    Blob inp = blobFromNPY(_tf("recurrent.input.npy"));
+    std::vector<Blob> inputs(1, inp), outputs;
+    runLayer(layer, inputs, outputs);
+
+    Blob h_t_reference = blobFromNPY(_tf("lstm.prototxt.h_1.npy"));
+    normAssert(h_t_reference, outputs[0]);
+}
+
+TEST(Layer_RNN_Test_Accuracy_with_, CaffeRecurrent)
+{
+    Ptr<RNNLayer> layer = RNNLayer::create();
+
+    layer->setWeights(
+                blobFromNPY(_tf("rnn.prototxt.w_0.npy")),
+                blobFromNPY(_tf("rnn.prototxt.w_1.npy")),
+                blobFromNPY(_tf("rnn.prototxt.w_2.npy")),
+                blobFromNPY(_tf("rnn.prototxt.w_3.npy")),
+                blobFromNPY(_tf("rnn.prototxt.w_4.npy")) );
+
+    std::vector<Blob> output, input(1, blobFromNPY(_tf("recurrent.input.npy")));
+    runLayer(layer, input, output);
+
+    Blob h_ref = blobFromNPY(_tf("rnn.prototxt.h_1.npy"));
+    normAssert(h_ref, output[0]);
+}
+
+
+class Layer_RNN_Test : public ::testing::Test
+{
+public:
+    int nX, nH, nO, nT, nS;
+    Blob Whh, Wxh, bh, Who, bo;
+    Ptr<RNNLayer> layer;
+
+    std::vector<Blob> inputs, outputs;
+
+    Layer_RNN_Test()
+    {
+        nT = 3;
+        nS = 5;
+        nX = 31;
+        nH = 64;
+        nO = 100;
+
+        Whh = Blob(BlobShape(nH, nH));
+        Wxh = Blob(BlobShape(nH, nX));
+        bh  = Blob(BlobShape(nH, 1));
+        Who = Blob(BlobShape(nO, nH));
+        bo  = Blob(BlobShape(nO, 1));
+
+        layer = RNNLayer::create();
+        layer->setProduceHiddenOutput(true);
+        layer->setWeights(Wxh, bh, Whh, Who, bo);
+    }
+};
+
+TEST_F(Layer_RNN_Test, get_set_test)
+{
+    inputs.push_back(Blob(BlobShape(nT, nS, 1, nX)));
+    runLayer(layer, inputs, outputs);
+
+    EXPECT_EQ(outputs.size(), 2u);
+    EXPECT_EQ(outputs[0].shape(), BlobShape(nT, nS, nO));
+    EXPECT_EQ(outputs[1].shape(), BlobShape(nT, nS, nH));
+}
 
 }
diff --git a/contrib/modules/dnn/test/test_main.cpp b/contrib/modules/dnn/test/test_main.cpp
index 6f9ac2e..42917f2 100644
--- a/contrib/modules/dnn/test/test_main.cpp
+++ b/contrib/modules/dnn/test/test_main.cpp
@@ -1,3 +1,31 @@
 #include "test_precomp.hpp"
 
 CV_TEST_MAIN("")
+
+namespace cvtest
+{
+
+using namespace cv;
+using namespace cv::dnn;
+
+TEST(BlobShape_SimpleConstr, Regression)
+{
+    BlobShape sd;
+
+    BlobShape s1(0);
+    EXPECT_EQ(s1.dims(), 1);
+    EXPECT_EQ(s1[0], 0);
+
+    BlobShape s2(0, 0);
+    EXPECT_EQ(s2.dims(), 2);
+    EXPECT_EQ(s2[0], 0);
+    EXPECT_EQ(s2[1], 0);
+}
+
+TEST(BlobShape_EmptyFill, Regression)
+{
+    BlobShape s(10, (int*)NULL);
+    EXPECT_EQ(s.dims(), 10);
+}
+
+}
diff --git a/contrib/modules/dnn/test/test_tf_importer.cpp b/contrib/modules/dnn/test/test_tf_importer.cpp
new file mode 100644
index 0000000..9f5d086
--- /dev/null
+++ b/contrib/modules/dnn/test/test_tf_importer.cpp
@@ -0,0 +1,51 @@
+// This file is part of OpenCV project.
+// It is subject to the license terms in the LICENSE file found in the top-level directory
+// of this distribution and at http://opencv.org/license.html.
+
+// Copyright (C) 2016, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+
+/*
+Test for Tensorflow models loading
+*/
+
+#include "test_precomp.hpp"
+
+namespace cvtest
+{
+
+using namespace cv;
+using namespace cv::dnn;
+
+template<typename TString>
+static std::string _tf(TString filename)
+{
+    return (getOpenCVExtraDir() + "/dnn/") + filename;
+}
+
+TEST(Test_TensorFlow, read_inception)
+{
+    Net net;
+    {
+        Ptr<Importer> importer = createTensorflowImporter(_tf("tensorflow_inception_graph.pb"));
+        ASSERT_TRUE(importer != NULL);
+        importer->populateNet(net);
+    }
+
+    Mat sample = imread(_tf("grace_hopper.jpg"));
+    ASSERT_TRUE(!sample.empty());
+    Mat input;
+    resize(sample, input, Size(224, 224));
+    input -= 128; // mean sub
+
+    std::vector<Mat> inpMats;
+    inpMats.push_back(input);
+
+    net.setBlob("_input.input", Blob(inpMats));
+    net.forward();
+
+    Blob out = net.getBlob("output");
+    std::cout << out.dims() << std::endl;
+}
+
+}
diff --git a/contrib/modules/dnn/testdata/dnn/.gitignore b/contrib/modules/dnn/testdata/dnn/.gitignore
new file mode 100644
index 0000000..be71866
--- /dev/null
+++ b/contrib/modules/dnn/testdata/dnn/.gitignore
@@ -0,0 +1 @@
+*.caffemodel
diff --git a/contrib/modules/dnn/tutorials/tutorial_dnn_build.markdown b/contrib/modules/dnn/tutorials/tutorial_dnn_build.markdown
index d5fbc7f..36f0fec 100644
--- a/contrib/modules/dnn/tutorials/tutorial_dnn_build.markdown
+++ b/contrib/modules/dnn/tutorials/tutorial_dnn_build.markdown
@@ -3,7 +3,7 @@ Build opencv_contrib with dnn module {#tutorial_dnn_build}
 
 Introduction
 ------------
-opencv_dnn module is placed in the secondary [opencv_contrib](https://github.com/Itseez/opencv_contrib) repository,
+opencv_dnn module is placed in the secondary [opencv_contrib](https://github.com/opencv/opencv_contrib) repository,
 which isn't distributed in binary form, therefore you need to build it manually.
 
 To do this you need to have installed: [CMake](http://www.cmake.org/download), git, and build system (*gcc* with *make* for Linux or *MS Visual Studio* for Windows)
@@ -12,12 +12,12 @@ Steps
 -----
 -# Make any directory, for example **opencv_root**
 
--# Clone [opencv](https://github.com/Itseez/opencv) and [opencv_contrib](https://github.com/Itseez/opencv_contrib) repos to the **opencv_root**.
+-# Clone [opencv](https://github.com/opencv/opencv) and [opencv_contrib](https://github.com/opencv/opencv_contrib) repos to the **opencv_root**.
    You can do it in terminal like here:
 @code
 cd opencv_root
-git clone https://github.com/Itseez/opencv
-git clone https://github.com/Itseez/opencv_contrib
+git clone https://github.com/opencv/opencv
+git clone https://github.com/opencv/opencv_contrib
 @endcode
 
 -# Run [CMake-gui] and set source and build directories:
diff --git a/contrib/modules/dnn/tutorials/tutorial_dnn_googlenet.markdown b/contrib/modules/dnn/tutorials/tutorial_dnn_googlenet.markdown
index 87b60ac..1eaaf25 100644
--- a/contrib/modules/dnn/tutorials/tutorial_dnn_googlenet.markdown
+++ b/contrib/modules/dnn/tutorials/tutorial_dnn_googlenet.markdown
@@ -29,11 +29,11 @@ Explanation
 
    Put these files into working dir of this program example.
 
--# Create the importer of Caffe models
-   @snippet dnn/samples/caffe_googlenet.cpp Create the importer of Caffe model
+-# Read and initialize network using path to .prototxt and .caffemodel files
+   @snippet dnn/samples/caffe_googlenet.cpp Read and initialize network
 
--# Create the network and initialize its by using the created importer
-   @snippet dnn/samples/caffe_googlenet.cpp Initialize network
+-# Check that network was read successfully
+   @snippet dnn/samples/caffe_googlenet.cpp Check that network was read successfully
 
 -# Read input image and convert to the blob, acceptable by GoogleNet
    @snippet dnn/samples/caffe_googlenet.cpp Prepare blob
@@ -41,7 +41,7 @@ Explanation
 
    Now image is actually a 3-dimensional array with 224x224x3 shape.
 
-   Next, we convert the image to 4-dimensional blob (so-called batch) with 1x2x224x224 shape by using special @ref cv::dnn::Blob constructor.
+   Next, we convert the image to 4-dimensional blob (so-called batch) with 1x3x224x224 shape by using special cv::dnn::Blob::fromImages constructor.
 
 -# Pass the blob to the network
    @snippet dnn/samples/caffe_googlenet.cpp Set input blob
diff --git a/contrib/modules/dnns_easily_fooled/.gitignore b/contrib/modules/dnns_easily_fooled/.gitignore
new file mode 100644
index 0000000..d7ca9af
--- /dev/null
+++ b/contrib/modules/dnns_easily_fooled/.gitignore
@@ -0,0 +1,29 @@
+# Compiled Object files
+*.slo
+*.lo
+*.o
+*.obj
+
+# Precompiled Headers
+*.gch
+*.pch
+
+# Compiled Dynamic libraries
+*.so
+*.dylib
+*.dll
+*.pyc
+
+# Fortran module files
+*.mod
+
+# Compiled Static libraries
+*.lai
+*.la
+*.a
+*.lib
+
+# Executables
+*.exe
+*.out
+*.app
diff --git a/contrib/modules/dpm/src/dpm_convolution.cpp b/contrib/modules/dpm/src/dpm_convolution.cpp
index f988e09..8d435ba 100644
--- a/contrib/modules/dpm/src/dpm_convolution.cpp
+++ b/contrib/modules/dpm/src/dpm_convolution.cpp
@@ -49,11 +49,15 @@ double ConvolutionEngine::convolve(const Mat &feat, const Mat &filter,
         int dimHOG, int x, int y)
 {
     double val = 0;
-    for (int xp = 0; xp < filter.cols; xp++)
+    for (int yp = 0; yp < filter.rows; yp++)
     {
-        for (int yp = 0; yp < filter.rows; yp++)
-            val += filter.at<double>(yp, xp)
-                * feat.at<double>(y + yp, x * dimHOG + xp);
+        const double *pfeat = (double*)feat.ptr(y + yp) + x * dimHOG;
+        const double *pfilter = (double*)filter.ptr(yp);
+
+        for (int xp = 0; xp < filter.cols; xp++)
+        {
+            val += pfeat[xp] * pfilter[xp];
+        }
     }
 
     return val;
@@ -62,20 +66,26 @@ double ConvolutionEngine::convolve(const Mat &feat, const Mat &filter,
 void ConvolutionEngine::convolve(const Mat &feat, const Mat &filter,
         int dimHOG, Mat &result)
 {
-    for (int x = 0; x < result.cols; x++)
+    for (int y = 0; y < result.rows; y++)
     {
-        for (int y = 0; y < result.rows; y++)
+        double *presult = (double*)result.ptr(y);
+        for (int x = 0; x < result.cols; x++)
         {
             double val = 0;
-            for (int xp = 0; xp < filter.cols; xp++)
+            for (int yp = 0; yp < filter.rows; yp++)
             {
-                for (int yp = 0; yp < filter.rows; yp++)
-                    val += feat.at<double>(y + yp, x*dimHOG + xp)
-                        * filter.at<double>(yp, xp);
-            } // xp
-            result.at<double>(y, x) = val;
-        } // y
-    } // x
+                const double *pfeat = (double*)feat.ptr(y + yp) + x * dimHOG;
+                const double *pfilter = (double*)filter.ptr(yp);
+
+                for (int xp = 0; xp < filter.cols; xp++)
+                {
+                    val += pfeat[xp] * pfilter[xp];
+                }
+            } // yp
+
+            presult[x] = val;
+        } // x
+    } // y
 }
 } // namespace cv
 } // namespace dpm
diff --git a/contrib/modules/dpm/src/dpm_nms.cpp b/contrib/modules/dpm/src/dpm_nms.cpp
index e1feb8d..bdf9d36 100644
--- a/contrib/modules/dpm/src/dpm_nms.cpp
+++ b/contrib/modules/dpm/src/dpm_nms.cpp
@@ -40,6 +40,7 @@
 //M*/
 
 #include "dpm_nms.hpp"
+#include <algorithm>
 
 using namespace std;
 
diff --git a/contrib/modules/face/README.md b/contrib/modules/face/README.md
index f8abffc..9b8904c 100644
--- a/contrib/modules/face/README.md
+++ b/contrib/modules/face/README.md
@@ -1,2 +1,8 @@
-Recently added face recognition software
-========================================
\ No newline at end of file
+Face recognition techniques
+===========================
+
+Collection of face recognition techniques:
+
+1. Eigen Faces
+2. Fisher Faces
+3. Local Binary Pattern Histograms
diff --git a/contrib/modules/face/data/cascades/haarcascade_mcs_eyepair_big.xml b/contrib/modules/face/data/cascades/haarcascade_mcs_eyepair_big.xml
index c3ac7a1..56598de 100644
--- a/contrib/modules/face/data/cascades/haarcascade_mcs_eyepair_big.xml
+++ b/contrib/modules/face/data/cascades/haarcascade_mcs_eyepair_big.xml
@@ -122,8 +122,8 @@ Section 8 – Interpretation.
 <opencv_storage>
 <cascade type_id="opencv-cascade-classifier"><stageType>BOOST</stageType>
   <featureType>HAAR</featureType>
-  <height>45</height>
-  <width>11</width>
+  <height>11</height>
+  <width>45</width>
   <stageParams>
     <maxWeakCount>85</maxWeakCount></stageParams>
   <featureParams>
diff --git a/contrib/modules/face/data/cascades/haarcascade_mcs_eyepair_small.xml b/contrib/modules/face/data/cascades/haarcascade_mcs_eyepair_small.xml
index 6e22b44..9828a87 100644
--- a/contrib/modules/face/data/cascades/haarcascade_mcs_eyepair_small.xml
+++ b/contrib/modules/face/data/cascades/haarcascade_mcs_eyepair_small.xml
@@ -121,8 +121,8 @@ Section 8 – Interpretation.
 <opencv_storage>
 <cascade type_id="opencv-cascade-classifier"><stageType>BOOST</stageType>
   <featureType>HAAR</featureType>
-  <height>22</height>
-  <width>5</width>
+  <height>5</height>
+  <width>22</width>
   <stageParams>
     <maxWeakCount>133</maxWeakCount></stageParams>
   <featureParams>
diff --git a/contrib/modules/face/data/cascades/haarcascade_mcs_leftear.xml b/contrib/modules/face/data/cascades/haarcascade_mcs_leftear.xml
index 3598515..f684976 100644
--- a/contrib/modules/face/data/cascades/haarcascade_mcs_leftear.xml
+++ b/contrib/modules/face/data/cascades/haarcascade_mcs_leftear.xml
@@ -120,8 +120,8 @@ Section 8 – Interpretation.
 <opencv_storage>
 <cascade type_id="opencv-cascade-classifier"><stageType>BOOST</stageType>
   <featureType>HAAR</featureType>
-  <height>12</height>
-  <width>20</width>
+  <height>20</height>
+  <width>12</width>
   <stageParams>
     <maxWeakCount>65</maxWeakCount></stageParams>
   <featureParams>
diff --git a/contrib/modules/face/data/cascades/haarcascade_mcs_lefteye.xml b/contrib/modules/face/data/cascades/haarcascade_mcs_lefteye.xml
index d745e05..525c600 100644
--- a/contrib/modules/face/data/cascades/haarcascade_mcs_lefteye.xml
+++ b/contrib/modules/face/data/cascades/haarcascade_mcs_lefteye.xml
@@ -121,8 +121,8 @@ Section 8 – Interpretation.
 <opencv_storage>
 <cascade type_id="opencv-cascade-classifier"><stageType>BOOST</stageType>
   <featureType>HAAR</featureType>
-  <height>18</height>
-  <width>12</width>
+  <height>12</height>
+  <width>18</width>
   <stageParams>
     <maxWeakCount>279</maxWeakCount></stageParams>
   <featureParams>
diff --git a/contrib/modules/face/data/cascades/haarcascade_mcs_mouth.xml b/contrib/modules/face/data/cascades/haarcascade_mcs_mouth.xml
index 277a2eb..d4dc053 100644
--- a/contrib/modules/face/data/cascades/haarcascade_mcs_mouth.xml
+++ b/contrib/modules/face/data/cascades/haarcascade_mcs_mouth.xml
@@ -122,8 +122,8 @@ Section 8 – Interpretation.
 <opencv_storage>
 <cascade type_id="opencv-cascade-classifier"><stageType>BOOST</stageType>
   <featureType>HAAR</featureType>
-  <height>25</height>
-  <width>15</width>
+  <height>15</height>
+  <width>25</width>
   <stageParams>
     <maxWeakCount>218</maxWeakCount></stageParams>
   <featureParams>
diff --git a/contrib/modules/face/data/cascades/haarcascade_mcs_nose.xml b/contrib/modules/face/data/cascades/haarcascade_mcs_nose.xml
index d196df1..49e0b87 100644
--- a/contrib/modules/face/data/cascades/haarcascade_mcs_nose.xml
+++ b/contrib/modules/face/data/cascades/haarcascade_mcs_nose.xml
@@ -121,8 +121,8 @@ Section 8 – Interpretation.
 <opencv_storage>
 <cascade type_id="opencv-cascade-classifier"><stageType>BOOST</stageType>
   <featureType>HAAR</featureType>
-  <height>18</height>
-  <width>15</width>
+  <height>15</height>
+  <width>18</width>
   <stageParams>
     <maxWeakCount>377</maxWeakCount></stageParams>
   <featureParams>
diff --git a/contrib/modules/face/data/cascades/haarcascade_mcs_rightear.xml b/contrib/modules/face/data/cascades/haarcascade_mcs_rightear.xml
index 61adf16..8c028c2 100644
--- a/contrib/modules/face/data/cascades/haarcascade_mcs_rightear.xml
+++ b/contrib/modules/face/data/cascades/haarcascade_mcs_rightear.xml
@@ -121,8 +121,8 @@ Section 8 – Interpretation.
 <opencv_storage>
 <cascade type_id="opencv-cascade-classifier"><stageType>BOOST</stageType>
   <featureType>HAAR</featureType>
-  <height>12</height>
-  <width>20</width>
+  <height>20</height>
+  <width>12</width>
   <stageParams>
     <maxWeakCount>61</maxWeakCount></stageParams>
   <featureParams>
diff --git a/contrib/modules/face/data/cascades/haarcascade_mcs_righteye.xml b/contrib/modules/face/data/cascades/haarcascade_mcs_righteye.xml
index 8db288d..12bbc79 100644
--- a/contrib/modules/face/data/cascades/haarcascade_mcs_righteye.xml
+++ b/contrib/modules/face/data/cascades/haarcascade_mcs_righteye.xml
@@ -121,8 +121,8 @@ Section 8 – Interpretation.
 <opencv_storage>
 <cascade type_id="opencv-cascade-classifier"><stageType>BOOST</stageType>
   <featureType>HAAR</featureType>
-  <height>18</height>
-  <width>12</width>
+  <height>12</height>
+  <width>18</width>
   <stageParams>
     <maxWeakCount>415</maxWeakCount></stageParams>
   <featureParams>
diff --git a/contrib/modules/face/data/cascades/haarcascade_mcs_upperbody.xml b/contrib/modules/face/data/cascades/haarcascade_mcs_upperbody.xml
index 76ba9ce..ba66ca9 100644
--- a/contrib/modules/face/data/cascades/haarcascade_mcs_upperbody.xml
+++ b/contrib/modules/face/data/cascades/haarcascade_mcs_upperbody.xml
@@ -119,8 +119,8 @@ Section 8 – Interpretation.
 <opencv_storage>
 <cascade type_id="opencv-cascade-classifier"><stageType>BOOST</stageType>
   <featureType>HAAR</featureType>
-  <height>22</height>
-  <width>20</width>
+  <height>20</height>
+  <width>22</width>
   <stageParams>
     <maxWeakCount>334</maxWeakCount></stageParams>
   <featureParams>
diff --git a/contrib/modules/face/include/opencv2/face.hpp b/contrib/modules/face/include/opencv2/face.hpp
index d7237bc..a90a1da 100644
--- a/contrib/modules/face/include/opencv2/face.hpp
+++ b/contrib/modules/face/include/opencv2/face.hpp
@@ -256,7 +256,7 @@ public:
     CV_WRAP virtual void update(InputArrayOfArrays src, InputArray labels);
 
     /** @overload */
-    CV_WRAP int predict(InputArray src) const;
+    CV_WRAP_AS(predict_label) int predict(InputArray src) const;
 
 
     /** @brief Predicts a label and associated confidence (e.g. distance) for a given input image.
@@ -300,12 +300,11 @@ public:
     /** @brief - if implemented - send all result of prediction to collector that can be used for somehow custom result handling
     @param src Sample image to get a prediction from.
     @param collector User-defined collector object that accepts all results
-    @param state - optional user-defined state token that should be passed back from FaceRecognizer implementation
 
     To implement this method u just have to do same internal cycle as in predict(InputArray src, CV_OUT int &label, CV_OUT double &confidence) but
     not try to get "best@ result, just resend it to caller side with given collector
     */
-    CV_WRAP virtual void predict(InputArray src, Ptr<PredictCollector> collector, const int state = 0) const = 0;
+    CV_WRAP_AS(predict_collect) virtual void predict(InputArray src, Ptr<PredictCollector> collector) const = 0;
 
     /** @brief Saves a FaceRecognizer and its model state.
 
@@ -358,8 +357,10 @@ public:
     info.
      */
     CV_WRAP virtual std::vector<int> getLabelsByString(const String& str) const;
-    /** @brief threshhold parameter accessor - required for default BestMinDist collector */
+    /** @brief threshold parameter accessor - required for default BestMinDist collector */
     virtual double getThreshold() const = 0;
+    /** @brief Sets threshold of model */
+    virtual void setThreshold(double val) = 0;
 protected:
     // Stored pairs "label id - string info"
     std::map<int, String> _labelsInfo;
diff --git a/contrib/modules/face/include/opencv2/face/bif.hpp b/contrib/modules/face/include/opencv2/face/bif.hpp
new file mode 100644
index 0000000..c22c28c
--- /dev/null
+++ b/contrib/modules/face/include/opencv2/face/bif.hpp
@@ -0,0 +1,83 @@
+/*
+By downloading, copying, installing or using the software you agree to this license.
+If you do not agree to this license, do not download, install,
+copy or use the software.
+
+
+                          License Agreement
+               For Open Source Computer Vision Library
+                       (3-clause BSD License)
+
+Copyright (C) 2000-2015, Intel Corporation, all rights reserved.
+Copyright (C) 2009-2011, Willow Garage Inc., all rights reserved.
+Copyright (C) 2009-2015, NVIDIA Corporation, all rights reserved.
+Copyright (C) 2010-2013, Advanced Micro Devices, Inc., all rights reserved.
+Copyright (C) 2015, OpenCV Foundation, all rights reserved.
+Copyright (C) 2015, Itseez Inc., all rights reserved.
+Third party copyrights are property of their respective owners.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+  * Redistributions of source code must retain the above copyright notice,
+    this list of conditions and the following disclaimer.
+
+  * Redistributions in binary form must reproduce the above copyright notice,
+    this list of conditions and the following disclaimer in the documentation
+    and/or other materials provided with the distribution.
+
+  * Neither the names of the copyright holders nor the names of the contributors
+    may be used to endorse or promote products derived from this software
+    without specific prior written permission.
+
+This software is provided by the copyright holders and contributors "as is" and
+any express or implied warranties, including, but not limited to, the implied
+warranties of merchantability and fitness for a particular purpose are disclaimed.
+In no event shall copyright holders or contributors be liable for any direct,
+indirect, incidental, special, exemplary, or consequential damages
+(including, but not limited to, procurement of substitute goods or services;
+loss of use, data, or profits; or business interruption) however caused
+and on any theory of liability, whether in contract, strict liability,
+or tort (including negligence or otherwise) arising in any way out of
+the use of this software, even if advised of the possibility of such damage.
+*/
+
+#ifndef __OPENCV_BIF_HPP__
+#define __OPENCV_BIF_HPP__
+
+#include "opencv2/core.hpp"
+
+namespace cv {
+namespace face {
+
+/** Implementation of bio-inspired features (BIF) from the paper:
+ *  Guo, Guodong, et al. "Human age estimation using bio-inspired features."
+ *  Computer Vision and Pattern Recognition, 2009. CVPR 2009.
+ */
+class CV_EXPORTS_W BIF : public Algorithm {
+public:
+    /** @returns The number of filter bands used for computing BIF. */
+    CV_WRAP virtual int getNumBands() const = 0;
+
+    /** @returns The number of image rotations. */
+    CV_WRAP virtual int getNumRotations() const = 0;
+
+    /** Computes features sby input image.
+     *  @param image Input image (CV_32FC1).
+     *  @param features Feature vector (CV_32FC1).
+     */
+    CV_WRAP virtual void compute(InputArray image,
+                                 OutputArray features) const = 0;
+};
+
+/**
+ * @param num_bands The number of filter bands (<=8) used for computing BIF.
+ * @param num_rotations The number of image rotations for computing BIF.
+ * @returns Object for computing BIF.
+ */
+CV_EXPORTS_W cv::Ptr<BIF> createBIF(int num_bands = 8, int num_rotations = 12);
+
+}  // namespace cv
+}  // namespace face
+
+#endif  // #ifndef __OPENCV_FACEREC_HPP__
diff --git a/contrib/modules/face/include/opencv2/face/predict_collector.hpp b/contrib/modules/face/include/opencv2/face/predict_collector.hpp
index e659d3e..a9f907d 100644
--- a/contrib/modules/face/include/opencv2/face/predict_collector.hpp
+++ b/contrib/modules/face/include/opencv2/face/predict_collector.hpp
@@ -44,59 +44,84 @@ the use of this software, even if advised of the possibility of such damage.
 
 #ifndef __OPENCV_PREDICT_COLLECTOR_HPP__
 #define __OPENCV_PREDICT_COLLECTOR_HPP__
+
+#include <vector>
+#include <map>
+#include <utility>
 #include <cfloat>
-#include "opencv2/core/cvdef.h"
+
 #include "opencv2/core/cvstd.hpp"
+
 namespace cv {
 namespace face {
 //! @addtogroup face
 //! @{
 /** @brief Abstract base class for all strategies of prediction result handling
 */
-class CV_EXPORTS_W PredictCollector {
-protected:
-    double _threshhold;
-    int _size;
-    int _state;
+class CV_EXPORTS_W PredictCollector
+{
 public:
-    /** @brief creates new predict collector with given threshhold */
-    PredictCollector(double threshhold = DBL_MAX) :_threshhold(threshhold) {};
-    CV_WRAP virtual ~PredictCollector() {}
-    /** @brief called once at start of recognition
+    virtual ~PredictCollector() {}
+
+    /** @brief Interface method called by face recognizer before results processing
     @param size total size of prediction evaluation that recognizer could perform
-    @param state user defined send-to-back optional value to allow multi-thread, multi-session or aggregation scenarios
     */
-    CV_WRAP virtual void init(const int size, const int state = 0);
-    /** @brief called with every recognition result
+    virtual void init(size_t size) { (void)size; }
+
+    /** @brief Interface method called by face recognizer for each result
     @param label current prediction label
     @param dist current prediction distance (confidence)
-    @param state user defined send-to-back optional value to allow multi-thread, multi-session or aggregation scenarios
-    @return true if recognizer should proceed prediction , false - if recognizer should terminate prediction
     */
-    CV_WRAP virtual bool emit(const int label, const double dist, const int state = 0); //not abstract while Python generation require non-abstract class
+    virtual bool collect(int label, double dist) = 0;
 };
 
-/** @brief default predict collector that trace minimal distance with treshhold checking (that is default behavior for most predict logic)
+/** @brief Default predict collector
+
+Trace minimal distance with treshhold checking (that is default behavior for most predict logic)
 */
-class CV_EXPORTS_W MinDistancePredictCollector : public PredictCollector {
-private:
-    int _label;
-    double _dist;
+class CV_EXPORTS_W StandardCollector : public PredictCollector
+{
 public:
-    /** @brief creates new MinDistancePredictCollector with given threshhold */
-    CV_WRAP MinDistancePredictCollector(double threshhold = DBL_MAX) : PredictCollector(threshhold) {
-        _label = 0;
-        _dist = DBL_MAX;
+    struct PredictResult
+    {
+        int label;
+        double distance;
+        PredictResult(int label_ = -1, double distance_ = DBL_MAX) : label(label_), distance(distance_) {}
     };
-    CV_WRAP bool emit(const int label, const double dist, const int state = 0);
-    /** @brief result label, 0 if not found */
-    CV_WRAP int getLabel() const;
-    /** @brief result distance (confidence) DBL_MAX if not found */
-    CV_WRAP double getDist() const;
-    /** @brief factory method to create cv-pointers to MinDistancePredictCollector */
-    CV_WRAP static Ptr<MinDistancePredictCollector> create(double threshold = DBL_MAX);
+protected:
+    double threshold;
+    PredictResult minRes;
+    std::vector<PredictResult> data;
+public:
+    /** @brief Constructor
+    @param threshold_ set threshold
+    */
+    StandardCollector(double threshold_ = DBL_MAX);
+    /** @brief overloaded interface method */
+    void init(size_t size);
+    /** @brief overloaded interface method */
+    bool collect(int label, double dist);
+    /** @brief Returns label with minimal distance */
+    CV_WRAP int getMinLabel() const;
+    /** @brief Returns minimal distance value */
+    CV_WRAP double getMinDist() const;
+    /** @brief Return results as vector
+    @param sorted If set, results will be sorted by distance
+    Each values is a pair of label and distance.
+    */
+    CV_WRAP std::vector< std::pair<int, double> > getResults(bool sorted = false) const;
+    /** @brief Return results as map
+    Labels are keys, values are minimal distances
+    */
+    std::map<int, double> getResultsMap() const;
+    /** @brief Static constructor
+    @param threshold set threshold
+    */
+    CV_WRAP static Ptr<StandardCollector> create(double threshold = DBL_MAX);
 };
+
 //! @}
 }
 }
-#endif
\ No newline at end of file
+
+#endif
diff --git a/contrib/modules/face/src/bif.cpp b/contrib/modules/face/src/bif.cpp
new file mode 100644
index 0000000..090ceae
--- /dev/null
+++ b/contrib/modules/face/src/bif.cpp
@@ -0,0 +1,221 @@
+/*
+By downloading, copying, installing or using the software you agree to this license.
+If you do not agree to this license, do not download, install,
+copy or use the software.
+
+
+                          License Agreement
+               For Open Source Computer Vision Library
+                       (3-clause BSD License)
+
+Copyright (C) 2000-2015, Intel Corporation, all rights reserved.
+Copyright (C) 2009-2011, Willow Garage Inc., all rights reserved.
+Copyright (C) 2009-2015, NVIDIA Corporation, all rights reserved.
+Copyright (C) 2010-2013, Advanced Micro Devices, Inc., all rights reserved.
+Copyright (C) 2015, OpenCV Foundation, all rights reserved.
+Copyright (C) 2015, Itseez Inc., all rights reserved.
+Third party copyrights are property of their respective owners.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+  * Redistributions of source code must retain the above copyright notice,
+    this list of conditions and the following disclaimer.
+
+  * Redistributions in binary form must reproduce the above copyright notice,
+    this list of conditions and the following disclaimer in the documentation
+    and/or other materials provided with the distribution.
+
+  * Neither the names of the copyright holders nor the names of the contributors
+    may be used to endorse or promote products derived from this software
+    without specific prior written permission.
+
+This software is provided by the copyright holders and contributors "as is" and
+any express or implied warranties, including, but not limited to, the implied
+warranties of merchantability and fitness for a particular purpose are disclaimed.
+In no event shall copyright holders or contributors be liable for any direct,
+indirect, incidental, special, exemplary, or consequential damages
+(including, but not limited to, procurement of substitute goods or services;
+loss of use, data, or profits; or business interruption) however caused
+and on any theory of liability, whether in contract, strict liability,
+or tort (including negligence or otherwise) arising in any way out of
+the use of this software, even if advised of the possibility of such damage.
+*/
+
+
+/*
+This file contains implementation of the bio-inspired features (BIF) approach
+for computing image descriptors, applicable for human age estimation. For more
+details we refer to [1,2].
+
+REFERENCES
+  [1] Guo, Guodong, et al. "Human age estimation using bio-inspired features."
+      Computer Vision and Pattern Recognition, 2009. CVPR 2009.
+  [2] Spizhevoi, A. S., and A. V. Bovyrin. "Estimating human age using
+      bio-inspired features and the ranking method." Pattern Recognition and
+      Image Analysis 25.3 (2015): 547-552.
+*/
+
+#include "precomp.hpp"
+#include "opencv2/face/bif.hpp"
+#include <iostream>
+#include <vector>
+
+namespace {
+
+// The constants below are taken from paper [1].
+
+const int kNumBandsMax = 8;
+
+const cv::Size kCellSizes[kNumBandsMax] = {
+    cv::Size(6,6), cv::Size(8,8), cv::Size(10,10), cv::Size(12,12),
+    cv::Size(14,14), cv::Size(16,16), cv::Size(18,18), cv::Size(20,20)
+};
+
+const cv::Size kGaborSize[kNumBandsMax][2] = {
+    {cv::Size(5,5), cv::Size(7,7)}, {cv::Size(9,9), cv::Size(11,11)},
+    {cv::Size(13,13), cv::Size(15,15)}, {cv::Size(17,17), cv::Size(19,19)},
+    {cv::Size(21,21), cv::Size(23,23)}, {cv::Size(25,25), cv::Size(27,27)},
+    {cv::Size(29,29), cv::Size(31,31)}, {cv::Size(33,33), cv::Size(35,35)}
+};
+
+const double kGaborGamma = 0.3;
+
+const double kGaborSigmas[kNumBandsMax][2] = {
+    {2.0, 2.8}, {3.6, 4.5}, {5.4, 6.3}, {7.3, 8.2},
+    {9.2, 10.2}, {11.3, 12.3}, {13.4, 14.6}, {15.8, 17.0}
+};
+
+const double kGaborWavelens[kNumBandsMax][2] = {
+    {2.5, 3.5}, {4.6, 5.6}, {6.8, 7.9}, {9.1, 10.3},
+    {11.5, 12.7}, {14.1, 15.4}, {16.8, 18.2}, {19.7, 21.2}
+};
+
+class BIFImpl : public cv::face::BIF {
+public:
+    BIFImpl(int num_bands, int num_rotations) {
+        initUnits(num_bands, num_rotations);
+    }
+
+    virtual int getNumBands() const { return num_bands_; }
+
+    virtual int getNumRotations() const { return num_rotations_; }
+
+    virtual void compute(cv::InputArray image,
+                         cv::OutputArray features) const;
+
+private:
+    struct UnitParams {
+        cv::Size cell_size;
+        cv::Mat filter1, filter2;
+    };
+
+    void initUnits(int num_bands, int num_rotations);
+    void computeUnit(int unit_idx, const cv::Mat &img, cv::Mat &dst) const;
+
+    int num_bands_;
+    int num_rotations_;
+    std::vector<UnitParams> units_;
+};
+
+void BIFImpl::compute(cv::InputArray _image,
+                      cv::OutputArray _features) const {
+    cv::Mat image = _image.getMat();
+    CV_Assert(image.type() == CV_32F);
+
+    std::vector<cv::Mat> fea_units(units_.size());
+    int fea_dim = 0;
+
+    for (size_t i = 0; i < units_.size(); ++i) {
+        computeUnit(static_cast<int>(i), image, fea_units[i]);
+        fea_dim += fea_units[i].rows;
+    }
+
+    _features.create(fea_dim, 1, CV_32F);
+    cv::Mat fea = _features.getMat();
+
+    int offset = 0;
+    for (size_t i = 0; i < fea_units.size(); ++i) {
+        cv::Mat roi = fea.rowRange(offset, offset + fea_units[i].rows);
+        fea_units[i].copyTo(roi);
+        offset += fea_units[i].rows;
+    }
+    CV_Assert(offset == fea_dim);
+}
+
+void BIFImpl::initUnits(int num_bands, int num_rotations) {
+    CV_Assert(num_bands > 0 && num_bands <= kNumBandsMax);
+    CV_Assert(num_rotations > 0);
+
+    num_bands_ = num_bands;
+    num_rotations_ = num_rotations;
+
+    for (int ri = 0; ri < num_rotations; ++ri) {
+        double angle = CV_PI / num_rotations * ri;
+
+        for (int bi = 0; bi < num_bands; ++bi) {
+            cv::Mat kernel[2];
+            for (int i = 0; i < 2; ++i) {
+                kernel[i] = cv::getGaborKernel(
+                    kGaborSize[bi][i], kGaborSigmas[bi][i], angle,
+                    kGaborWavelens[bi][i], kGaborGamma, 0, CV_32F);
+
+                // Make variance for the Gaussian part of the Gabor filter
+                // the same across all filters.
+                kernel[i] /= 2 * kGaborSigmas[bi][i] * kGaborSigmas[bi][i]
+                             / kGaborGamma;
+            }
+
+            UnitParams unit;
+            unit.cell_size = kCellSizes[bi];
+            unit.filter1 = kernel[0];
+            unit.filter2 = kernel[1];
+            units_.push_back(unit);
+        }
+    }
+}
+
+void BIFImpl::computeUnit(int unit_idx, const cv::Mat &img,
+                          cv::Mat &dst) const {
+    cv::Mat resp1, resp2;
+    cv::filter2D(img, resp1, CV_32F, units_[unit_idx].filter1);
+    cv::filter2D(img, resp2, CV_32F, units_[unit_idx].filter2);
+
+    cv::Mat resp, sum, sumsq;
+    cv::max(resp1, resp2, resp);
+    cv::integral(resp, sum, sumsq);
+
+    int Hhalf = units_[unit_idx].cell_size.height / 2;
+    int Whalf = units_[unit_idx].cell_size.width / 2;
+
+    int nrows = (resp.rows + Hhalf - 1) / Hhalf;
+    int ncols = (resp.cols + Whalf - 1) / Whalf;
+    dst.create(nrows*ncols, 1, CV_32F);
+
+    for (int pos = 0, yc = 0; yc < resp.rows; yc += Hhalf) {
+        int y0 = std::max(0, yc - Hhalf);
+        int y1 = std::min(resp.rows, yc + Hhalf);
+
+        for (int xc = 0; xc < resp.cols; xc += Whalf, ++pos) {
+            int x0 = std::max(0, xc - Whalf);
+            int x1 = std::min(resp.cols, xc + Whalf);
+            int area = (y1-y0) * (x1-x0);
+
+            double mean = sum.at<double>(y1,x1) - sum.at<double>(y1,x0)
+                         - sum.at<double>(y0,x1) + sum.at<double>(y0,x0);
+            mean /= area;
+
+            double sd = sumsq.at<double>(y1,x1) - sumsq.at<double>(y1,x0)
+                        - sumsq.at<double>(y0,x1) + sumsq.at<double>(y0,x0);
+            sd = sqrt(std::max(0.0, sd / area - mean * mean));
+
+            dst.at<float>(pos) = static_cast<float>(sd);
+        }
+    }
+}
+
+}  // namespace
+
+cv::Ptr<cv::face::BIF> cv::face::createBIF(int num_bands, int num_rotations) {
+    return cv::Ptr<cv::face::BIF>(new BIFImpl(num_bands, num_rotations));
+}
diff --git a/contrib/modules/face/src/eigen_faces.cpp b/contrib/modules/face/src/eigen_faces.cpp
index 2e5d58c..9ea5d82 100644
--- a/contrib/modules/face/src/eigen_faces.cpp
+++ b/contrib/modules/face/src/eigen_faces.cpp
@@ -42,7 +42,7 @@ public:
     void train(InputArrayOfArrays src, InputArray labels);
 
     // Send all predict results to caller side for custom result handling
-    void predict(InputArray src, Ptr<PredictCollector> collector, const int state) const;
+    void predict(InputArray src, Ptr<PredictCollector> collector) const;
 };
 
 //------------------------------------------------------------------------------
@@ -99,7 +99,7 @@ void Eigenfaces::train(InputArrayOfArrays _src, InputArray _local_labels) {
     }
 }
 
-void Eigenfaces::predict(InputArray _src, Ptr<PredictCollector> collector, const int state) const {
+void Eigenfaces::predict(InputArray _src, Ptr<PredictCollector> collector) const {
     // get data
     Mat src = _src.getMat();
     // make sure the user is passing correct data
@@ -114,11 +114,11 @@ void Eigenfaces::predict(InputArray _src, Ptr<PredictCollector> collector, const
     }
     // project into PCA subspace
     Mat q = LDA::subspaceProject(_eigenvectors, _mean, src.reshape(1, 1));
-    collector->init((int)_projections.size(), state);
+    collector->init(_projections.size());
     for (size_t sampleIdx = 0; sampleIdx < _projections.size(); sampleIdx++) {
         double dist = norm(_projections[sampleIdx], q, NORM_L2);
         int label = _labels.at<int>((int)sampleIdx);
-        if (!collector->emit(label, dist, state))return;
+        if (!collector->collect(label, dist))return;
     }
 }
 
diff --git a/contrib/modules/face/src/facerec.cpp b/contrib/modules/face/src/facerec.cpp
index 0ea2a04..1b1d639 100644
--- a/contrib/modules/face/src/facerec.cpp
+++ b/contrib/modules/face/src/facerec.cpp
@@ -58,7 +58,7 @@ void FaceRecognizer::load(const String &filename)
 {
     FileStorage fs(filename, FileStorage::READ);
     if (!fs.isOpened())
-        CV_Error(Error::StsError, "File can't be opened for writing!");
+        CV_Error(Error::StsError, "File can't be opened for reading!");
     this->load(fs);
     fs.release();
 }
@@ -80,10 +80,10 @@ int FaceRecognizer::predict(InputArray src) const {
 }
 
 void FaceRecognizer::predict(InputArray src, CV_OUT int &label, CV_OUT double &confidence) const {
-    Ptr<MinDistancePredictCollector> collector = MinDistancePredictCollector::create(getThreshold());
-    predict(src, collector, 0);
-    label = collector->getLabel();
-    confidence = collector->getDist();
+    Ptr<StandardCollector> collector = StandardCollector::create(getThreshold());
+    predict(src, collector);
+    label = collector->getMinLabel();
+    confidence = collector->getMinDist();
 }
 
 }
diff --git a/contrib/modules/face/src/fisher_faces.cpp b/contrib/modules/face/src/fisher_faces.cpp
index 160d724..a43fa43 100644
--- a/contrib/modules/face/src/fisher_faces.cpp
+++ b/contrib/modules/face/src/fisher_faces.cpp
@@ -37,7 +37,7 @@ public:
     void train(InputArrayOfArrays src, InputArray labels);
 
     // Send all predict results to caller side for custom result handling
-    void predict(InputArray src, Ptr<PredictCollector> collector, const int state) const;
+    void predict(InputArray src, Ptr<PredictCollector> collector) const;
 };
 
 // Removes duplicate elements in a given vector.
@@ -120,7 +120,7 @@ void Fisherfaces::train(InputArrayOfArrays src, InputArray _lbls) {
     }
 }
 
-void Fisherfaces::predict(InputArray _src, Ptr<PredictCollector> collector, const int state) const {
+void Fisherfaces::predict(InputArray _src, Ptr<PredictCollector> collector) const {
     Mat src = _src.getMat();
     // check data alignment just for clearer exception messages
     if(_projections.empty()) {
@@ -134,11 +134,11 @@ void Fisherfaces::predict(InputArray _src, Ptr<PredictCollector> collector, cons
     // project into LDA subspace
     Mat q = LDA::subspaceProject(_eigenvectors, _mean, src.reshape(1,1));
     // find 1-nearest neighbor
-    collector->init((int)_projections.size(), state);
+    collector->init((int)_projections.size());
     for (size_t sampleIdx = 0; sampleIdx < _projections.size(); sampleIdx++) {
         double dist = norm(_projections[sampleIdx], q, NORM_L2);
         int label = _labels.at<int>((int)sampleIdx);
-        if (!collector->emit(label, dist, state))return;
+        if (!collector->collect(label, dist))return;
     }
 }
 
diff --git a/contrib/modules/face/src/lbph_faces.cpp b/contrib/modules/face/src/lbph_faces.cpp
index 8d8d40b..f73f060 100644
--- a/contrib/modules/face/src/lbph_faces.cpp
+++ b/contrib/modules/face/src/lbph_faces.cpp
@@ -92,7 +92,7 @@ public:
     void update(InputArrayOfArrays src, InputArray labels);
 
     // Send all predict results to caller side for custom result handling
-    void predict(InputArray src, Ptr<PredictCollector> collector, const int state = 0) const;
+    void predict(InputArray src, Ptr<PredictCollector> collector) const;
 
     // See FaceRecognizer::load.
     void load(const FileStorage& fs);
@@ -383,7 +383,7 @@ void LBPH::train(InputArrayOfArrays _in_src, InputArray _in_labels, bool preserv
     }
 }
 
-void LBPH::predict(InputArray _src, Ptr<PredictCollector> collector, const int state) const {
+void LBPH::predict(InputArray _src, Ptr<PredictCollector> collector) const {
     if(_histograms.empty()) {
         // throw error if no data (or simply return -1?)
         String error_message = "This LBPH model is not computed yet. Did you call the train method?";
@@ -399,11 +399,11 @@ void LBPH::predict(InputArray _src, Ptr<PredictCollector> collector, const int s
             _grid_y, /* grid size y */
             true /* normed histograms */);
     // find 1-nearest neighbor
-    collector->init((int)_histograms.size(), state);
+    collector->init((int)_histograms.size());
     for (size_t sampleIdx = 0; sampleIdx < _histograms.size(); sampleIdx++) {
         double dist = compareHist(_histograms[sampleIdx], query, HISTCMP_CHISQR_ALT);
         int label = _labels.at<int>((int)sampleIdx);
-        if (!collector->emit(label, dist, state))return;
+        if (!collector->collect(label, dist))return;
     }
 }
 
diff --git a/contrib/modules/face/src/predict_collector.cpp b/contrib/modules/face/src/predict_collector.cpp
index 732a068..67fdb6e 100644
--- a/contrib/modules/face/src/predict_collector.cpp
+++ b/contrib/modules/face/src/predict_collector.cpp
@@ -42,45 +42,73 @@ or tort (including negligence or otherwise) arising in any way out of
 the use of this software, even if advised of the possibility of such damage.
 */
 #include "opencv2/face/predict_collector.hpp"
-#include "opencv2/core/cvstd.hpp"
-namespace cv {
-namespace face {
-
-void PredictCollector::init(const int size, const int state) {
-    //reserve for some-how usage in descendants
-    _size = size;
-    _state = state;
+
+namespace cv {namespace face {
+
+static std::pair<int, double> toPair(const StandardCollector::PredictResult & val) {
+    return std::make_pair(val.label, val.distance);
 }
 
-bool PredictCollector::emit(const int, const double, const int state) {
-    if (_state == state) {
-        return false; // if it's own session - terminate it while default PredictCollector does nothing
-    }
-    return true;
+static bool pairLess(const std::pair<int, double> & lhs, const std::pair<int, double> & rhs) {
+    return lhs.second < rhs.second;
 }
 
-bool MinDistancePredictCollector::emit(const int label, const double dist, const int state) {
-    if (_state != state) {
-        return true; // it works only in one (same) session doesn't accept values for other states
-    }
-    if (dist < _threshhold && dist < _dist) {
-        _label = label;
-        _dist = dist;
+//===================================
+
+StandardCollector::StandardCollector(double threshold_) : threshold(threshold_) {
+    init(0);
+}
+
+void StandardCollector::init(size_t size) {
+    minRes = PredictResult();
+    data.clear();
+    data.reserve(size);
+}
+
+bool StandardCollector::collect(int label, double dist) {
+    if (dist < threshold)
+    {
+        PredictResult res(label, dist);
+        if (res.distance < minRes.distance)
+            minRes = res;
+        data.push_back(res);
     }
     return true;
 }
 
-int MinDistancePredictCollector::getLabel() const {
-    return _label;
+int StandardCollector::getMinLabel() const {
+    return minRes.label;
 }
 
-double MinDistancePredictCollector::getDist() const {
-    return _dist;
+double StandardCollector::getMinDist() const {
+    return minRes.distance;
 }
 
-Ptr<MinDistancePredictCollector> MinDistancePredictCollector::create(double threshold) {
-    return Ptr<MinDistancePredictCollector>(new MinDistancePredictCollector(threshold));
+std::vector< std::pair<int, double> > StandardCollector::getResults(bool sorted) const {
+    std::vector< std::pair<int, double> > res(data.size());
+    std::transform(data.begin(), data.end(), res.begin(), &toPair);
+    if (sorted)
+    {
+        std::sort(res.begin(), res.end(), &pairLess);
+    }
+    return res;
 }
 
+std::map<int, double> StandardCollector::getResultsMap() const {
+    std::map<int, double> res;
+    for (std::vector<PredictResult>::const_iterator i = data.begin(); i != data.end(); ++i) {
+        std::map<int, double>::iterator j = res.find(i->label);
+        if (j == res.end()) {
+            res.insert(toPair(*i));
+        } else if (i->distance < j->second) {
+            j->second = i->distance;
+        }
+    }
+    return res;
 }
-}
\ No newline at end of file
+
+Ptr<StandardCollector> StandardCollector::create(double threshold) {
+    return makePtr<StandardCollector>(threshold);
+}
+
+}} // cv::face::
diff --git a/contrib/modules/face/test/test_bif.cpp b/contrib/modules/face/test/test_bif.cpp
new file mode 100644
index 0000000..521d2ce
--- /dev/null
+++ b/contrib/modules/face/test/test_bif.cpp
@@ -0,0 +1,67 @@
+/*
+By downloading, copying, installing or using the software you agree to this
+license. If you do not agree to this license, do not download, install,
+copy or use the software.
+
+                          License Agreement
+               For Open Source Computer Vision Library
+                       (3-clause BSD License)
+
+Copyright (C) 2013, OpenCV Foundation, all rights reserved.
+Third party copyrights are property of their respective owners.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+  * Redistributions of source code must retain the above copyright notice,
+    this list of conditions and the following disclaimer.
+
+  * Redistributions in binary form must reproduce the above copyright notice,
+    this list of conditions and the following disclaimer in the documentation
+    and/or other materials provided with the distribution.
+
+  * Neither the names of the copyright holders nor the names of the contributors
+    may be used to endorse or promote products derived from this software
+    without specific prior written permission.
+
+This software is provided by the copyright holders and contributors "as is" and
+any express or implied warranties, including, but not limited to, the implied
+warranties of merchantability and fitness for a particular purpose are
+disclaimed. In no event shall copyright holders or contributors be liable for
+any direct, indirect, incidental, special, exemplary, or consequential damages
+(including, but not limited to, procurement of substitute goods or services;
+loss of use, data, or profits; or business interruption) however caused
+and on any theory of liability, whether in contract, strict liability,
+or tort (including negligence or otherwise) arising in any way out of
+the use of this software, even if advised of the possibility of such damage.
+*/
+
+#include "test_precomp.hpp"
+
+TEST(CV_Face_BIF, can_create_default) {
+    cv::Ptr<cv::face::BIF> bif;
+    EXPECT_NO_THROW(bif = cv::face::createBIF());
+    EXPECT_FALSE(bif.empty());
+}
+
+TEST(CV_Face_BIF, fails_when_zero_bands) {
+    EXPECT_ANY_THROW(cv::face::createBIF(0));
+}
+
+TEST(CV_Face_BIF, fails_when_too_many_bands) {
+    EXPECT_ANY_THROW(cv::face::createBIF(9));
+}
+
+TEST(CV_Face_BIF, fails_when_zero_rotations) {
+    EXPECT_ANY_THROW(cv::face::createBIF(8, 0));
+}
+
+TEST(CV_Face_BIF, can_compute) {
+    cv::Mat image(60, 60, CV_32F);
+    cv::theRNG().fill(image, cv::RNG::UNIFORM, -1, 1);
+
+    cv::Ptr<cv::face::BIF> bif = cv::face::createBIF();
+    cv::Mat fea;
+    EXPECT_NO_THROW(bif->compute(image, fea));
+    EXPECT_EQ(cv::Size(1, 13188), fea.size());
+}
diff --git a/contrib/modules/face/test/test_main.cpp b/contrib/modules/face/test/test_main.cpp
new file mode 100644
index 0000000..2f16b0c
--- /dev/null
+++ b/contrib/modules/face/test/test_main.cpp
@@ -0,0 +1,41 @@
+/*
+By downloading, copying, installing or using the software you agree to this
+license. If you do not agree to this license, do not download, install,
+copy or use the software.
+
+                          License Agreement
+               For Open Source Computer Vision Library
+                       (3-clause BSD License)
+
+Copyright (C) 2013, OpenCV Foundation, all rights reserved.
+Third party copyrights are property of their respective owners.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+  * Redistributions of source code must retain the above copyright notice,
+    this list of conditions and the following disclaimer.
+
+  * Redistributions in binary form must reproduce the above copyright notice,
+    this list of conditions and the following disclaimer in the documentation
+    and/or other materials provided with the distribution.
+
+  * Neither the names of the copyright holders nor the names of the contributors
+    may be used to endorse or promote products derived from this software
+    without specific prior written permission.
+
+This software is provided by the copyright holders and contributors "as is" and
+any express or implied warranties, including, but not limited to, the implied
+warranties of merchantability and fitness for a particular purpose are
+disclaimed. In no event shall copyright holders or contributors be liable for
+any direct, indirect, incidental, special, exemplary, or consequential damages
+(including, but not limited to, procurement of substitute goods or services;
+loss of use, data, or profits; or business interruption) however caused
+and on any theory of liability, whether in contract, strict liability,
+or tort (including negligence or otherwise) arising in any way out of
+the use of this software, even if advised of the possibility of such damage.
+*/
+
+#include "test_precomp.hpp"
+
+CV_TEST_MAIN("cv")
diff --git a/contrib/modules/face/test/test_precomp.hpp b/contrib/modules/face/test/test_precomp.hpp
new file mode 100644
index 0000000..7fba99d
--- /dev/null
+++ b/contrib/modules/face/test/test_precomp.hpp
@@ -0,0 +1,56 @@
+/*
+By downloading, copying, installing or using the software you agree to this
+license. If you do not agree to this license, do not download, install,
+copy or use the software.
+
+                          License Agreement
+               For Open Source Computer Vision Library
+                       (3-clause BSD License)
+
+Copyright (C) 2013, OpenCV Foundation, all rights reserved.
+Third party copyrights are property of their respective owners.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+  * Redistributions of source code must retain the above copyright notice,
+    this list of conditions and the following disclaimer.
+
+  * Redistributions in binary form must reproduce the above copyright notice,
+    this list of conditions and the following disclaimer in the documentation
+    and/or other materials provided with the distribution.
+
+  * Neither the names of the copyright holders nor the names of the contributors
+    may be used to endorse or promote products derived from this software
+    without specific prior written permission.
+
+This software is provided by the copyright holders and contributors "as is" and
+any express or implied warranties, including, but not limited to, the implied
+warranties of merchantability and fitness for a particular purpose are
+disclaimed. In no event shall copyright holders or contributors be liable for
+any direct, indirect, incidental, special, exemplary, or consequential damages
+(including, but not limited to, procurement of substitute goods or services;
+loss of use, data, or profits; or business interruption) however caused
+and on any theory of liability, whether in contract, strict liability,
+or tort (including negligence or otherwise) arising in any way out of
+the use of this software, even if advised of the possibility of such damage.
+*/
+
+#ifdef __GNUC__
+#  pragma GCC diagnostic ignored "-Wmissing-declarations"
+#  if defined __clang__ || defined __APPLE__
+#    pragma GCC diagnostic ignored "-Wmissing-prototypes"
+#    pragma GCC diagnostic ignored "-Wextra"
+#  endif
+#endif
+
+#ifndef __OPENCV_TEST_PRECOMP_HPP__
+#define __OPENCV_TEST_PRECOMP_HPP__
+
+#include <iostream>
+#include "opencv2/ts.hpp"
+#include "opencv2/imgproc.hpp"
+#include "opencv2/face.hpp"
+#include "opencv2/face/bif.hpp"
+
+#endif
diff --git a/contrib/modules/face/tutorials/face_tutorial.markdown b/contrib/modules/face/tutorials/face_tutorial.markdown
index 0de519c..0cae7ab 100644
--- a/contrib/modules/face/tutorials/face_tutorial.markdown
+++ b/contrib/modules/face/tutorials/face_tutorial.markdown
@@ -632,11 +632,11 @@ philipp at mango:~/facerec/data/at$ tree
 |   |-- 10.pgm
 @endcode
 
-Then simply call `create_csv.py` with the path to the folder, just like this and you could save the
+Then simply call `create_csv.py at` , here 'at' being the basepath to the folder, just like this and you could save the
 output:
 
 @code{.sh}
-philipp at mango:~/facerec/data$ python create_csv.py
+philipp at mango:~/facerec/data$ python create_csv.py at
 at/s13/2.pgm;0
 at/s13/7.pgm;0
 at/s13/6.pgm;0
diff --git a/contrib/modules/freetype/CMakeLists.txt b/contrib/modules/freetype/CMakeLists.txt
new file mode 100644
index 0000000..47e2f01
--- /dev/null
+++ b/contrib/modules/freetype/CMakeLists.txt
@@ -0,0 +1,26 @@
+set(the_description "FreeType module. It enables to draw strings with outlines and mono-bitmaps/gray-bitmaps.")
+
+if(PKG_CONFIG_FOUND)
+  pkg_search_module(FREETYPE freetype2)
+  pkg_search_module(HARFBUZZ harfbuzz)
+endif()
+
+if(NOT FREETYPE_FOUND)
+  message(STATUS "freetype2:   NO")
+else()
+  message(STATUS "freetype2:   YES")
+endif()
+
+if(NOT HARFBUZZ_FOUND)
+  message(STATUS "harfbuzz:    NO")
+else()
+  message(STATUS "harfbuzz:    YES")
+endif()
+
+
+if( FREETYPE_FOUND AND HARFBUZZ_FOUND )
+  ocv_define_module(freetype opencv_core opencv_imgproc PRIVATE_REQUIRED ${freetype2_LIBRARIES} ${harfbuzz_LIBRARIES} WRAP python)
+  ocv_include_directories( ${FREETYPE_INCLUDE_DIRS} ${HARFBUZZ_INCLUDE_DIRS} )
+else()
+  ocv_module_disable(freetype)
+endif()
diff --git a/contrib/modules/freetype/README.md b/contrib/modules/freetype/README.md
new file mode 100644
index 0000000..44ecb16
--- /dev/null
+++ b/contrib/modules/freetype/README.md
@@ -0,0 +1,34 @@
+FreeType Module
+===========
+
+This FreeType module allows you to draw strings with outlines and bitmaps.
+
+Installation
+-----------
+harfbuzz is requested to convert UTF8 to gid(GlyphID).
+freetype library is requested to rasterize given gid.
+
+harfbuzz https://www.freedesktop.org/wiki/Software/HarfBuzz/
+freetype https://www.freetype.org/
+
+Usage
+-----------
+cv::freetype::FreeType2 ft2;
+ft2.loadFontData("your-font.ttf", 0);
+ft2.setSplitNumber( 4 ); // Bezier-line is splited by 4 segment.
+ft2.putText(src, .... )
+
+Option
+------------
+- 2nd argument of loadFontData is used if font file has many font data.
+- 3 drawing mode is available.
+-- outline mode is used if lineWidth is larger than 0. (like original putText)
+-- bitmap  mode is used if lineWidth is less than 0.
+--- 1bit bitmap mode is used if lineStyle is 4 or 8.
+--- gray bitmap mode is used if lineStyle is 16.
+
+Future work
+------------
+- test
+-- CJK and ...
+- RTL,LTR,TTB,BTT...
diff --git a/contrib/modules/freetype/include/opencv2/freetype.hpp b/contrib/modules/freetype/include/opencv2/freetype.hpp
new file mode 100644
index 0000000..c0920e4
--- /dev/null
+++ b/contrib/modules/freetype/include/opencv2/freetype.hpp
@@ -0,0 +1,130 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+//  By downloading, copying, installing or using the software you agree to this license.
+//  If you do not agree to this license, do not download, install,
+//  copy or use the software.
+//
+//
+//                           License Agreement
+//                For Open Source Computer Vision Library
+//
+// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
+// Copyright (C) 2009-2012, Willow Garage Inc., all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+//   * Redistribution's of source code must retain the above copyright notice,
+//     this list of conditions and the following disclaimer.
+//
+//   * Redistribution's in binary form must reproduce the above copyright notice,
+//     this list of conditions and the following disclaimer in the documentation
+//     and/or other materials provided with the distribution.
+//
+//   * The name of the copyright holders may not be used to endorse or promote products
+//     derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+//################################################################################
+//
+//                    Created by Kumataro
+//
+//################################################################################
+
+#ifndef _OPENCV_FREETYPE_H_
+#define _OPENCV_FREETYPE_H_
+#ifdef __cplusplus
+
+#include <opencv2/core.hpp>
+
+/**
+ at defgroup freetype Drawing UTF-8 strings with freetype/harfbuzz
+
+This modules is to draw UTF-8 strings with freetype/harfbuzz.
+
+1. Install freetype2 and harfbuzz in your system.
+2. Create FreeType2 instance with createFreeType2() function.
+3. Load font file with loadFontData() function.
+4. Draw text with putText() function.
+
+- If thickness parameter is negative, drawing glyph is filled.
+- If thickness parameter is positive, drawing glyph is outlined with thickness.
+- If line_type parameter is 16(or CV_AA), drawing glyph is smooth.
+
+*/
+
+namespace cv {
+namespace freetype {
+//! @addtogroup freetype
+//! @{
+class CV_EXPORTS_W FreeType2 : public Algorithm
+{
+public:
+/** @brief Load font data.
+
+The function loadFontData loads font data.
+
+ at param fontFileName FontFile Name
+ at param id face_index to select a font faces in a single file.
+*/
+
+    CV_WRAP virtual void loadFontData(String fontFileName, int id) = 0;
+
+/** @brief Set Split Number from Bezier-curve to line
+
+The function setSplitNumber set the number of split points from bezier-curve to line.
+If you want to draw large glyph, large is better.
+If you want to draw small glyph, small is better.
+
+ at param num number of split points from bezier-curve to line
+*/
+
+    CV_WRAP virtual void setSplitNumber( int num ) = 0;
+
+/** @brief Draws a text string.
+
+The function putText renders the specified text string in the image. Symbols that cannot be rendered using the specified font are replaced by "Tofu" or non-drawn.
+
+ at param img Image.
+ at param text Text string to be drawn.
+ at param org Bottom-left/Top-left corner of the text string in the image.
+ at param fontHeight Drawing font size by pixel unit.
+ at param color Text color.
+ at param thickness Thickness of the lines used to draw a text when negative, the glyph is filled. Otherwise, the glyph is drawn with this thickness.
+ at param line_type Line type. See the line for details.
+ at param bottomLeftOrigin When true, the image data origin is at the bottom-left corner. Otherwise, it is at the top-left corner.
+*/
+
+    CV_WRAP virtual void putText(
+        InputOutputArray img, const String& text, Point org,
+        int fontHeight, Scalar color,
+        int thickness, int line_type, bool bottomLeftOrigin
+    ) = 0;
+
+};
+/** @brief Create FreeType2 Instance
+
+The function createFreeType2 create instance to draw UTF-8 strings.
+
+*/
+    CV_EXPORTS_W Ptr<FreeType2> createFreeType2();
+
+//! @]
+} } // namespace freetype
+
+#endif
+#endif
diff --git a/contrib/modules/freetype/src/freetype.cpp b/contrib/modules/freetype/src/freetype.cpp
new file mode 100644
index 0000000..6444d6f
--- /dev/null
+++ b/contrib/modules/freetype/src/freetype.cpp
@@ -0,0 +1,502 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+//  By downloading, copying, installing or using the software you agree to this license.
+//  If you do not agree to this license, do not download, install,
+//  copy or use the software.
+//
+//
+//                           License Agreement
+//                For Open Source Computer Vision Library
+//
+// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
+// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+//   * Redistribution's of source code must retain the above copyright notice,
+//     this list of conditions and the following disclaimer.
+//
+//   * Redistribution's in binary form must reproduce the above copyright notice,
+//     this list of conditions and the following disclaimer in the documentation
+//     and/or other materials provided with the distribution.
+//
+//   * The name of the copyright holders may not be used to endorse or promote products
+//     derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+//################################################################################
+//
+//                    Created by Kumataro
+//
+//################################################################################
+
+#include "precomp.hpp"
+
+#include <ft2build.h>
+#include FT_FREETYPE_H
+#include FT_OUTLINE_H
+
+#include <hb.h>
+#include <hb-ft.h>
+
+namespace cv {
+namespace freetype {
+
+using namespace std;
+
+class CV_EXPORTS_W FreeType2Impl : public FreeType2
+{
+public:
+    FreeType2Impl();
+    ~FreeType2Impl();
+    void loadFontData(String fontFileName, int id) ;
+    void setSplitNumber( int num );
+    void putText(
+        InputOutputArray img, const String& text, Point org,
+        int fontHeight, Scalar color,
+        int thickness, int line_type, bool bottomLeftOrigin
+    );
+
+private:
+    FT_Library       mLibrary;
+    FT_Face          mFace;
+    FT_Outline_Funcs mFn;
+
+    Point            mOrg;
+    int              mLine_type;
+    int              mThickness;
+    int              mHeight;
+    Scalar           mColor;
+    bool             mIsFaceAvailable;
+    String           mText;
+    int              mCtoL;
+    hb_font_t        *mHb_font;
+
+    void putTextBitmapMono ( InputOutputArray _img);
+    void putTextBitmapBlend( InputOutputArray _img);
+    void putTextOutline    ( InputOutputArray _img);
+
+    static int mvFn( const FT_Vector *to, void * user);
+    static int lnFn( const FT_Vector *to, void * user);
+    static int coFn( const FT_Vector *cnt,
+                     const FT_Vector *to,
+                     void * user);
+    static int cuFn( const FT_Vector *cnt1,
+                     const FT_Vector *cnt2,
+                     const FT_Vector *to,
+                     void * user);
+
+    // Offset value to handle the position less than 0.
+    static const unsigned int cOutlineOffset = 0x80000000;
+
+    /**
+     * Convert from 26.6 real to signed integer
+     */
+    static int ftd(unsigned int fixedInt){
+        unsigned int ret = ( ( fixedInt + (1 << 5)  ) >> 6 );
+        return (int)ret - ( cOutlineOffset >> 6 );
+    }
+
+    class PathUserData{
+    private:
+    public:
+        PathUserData( InputOutputArray _img) : mImg(_img) {};
+
+        InputOutputArray mImg;
+        Scalar mColor;
+        int    mThickness;
+        int    mLine_type;
+        FT_Vector        mOldP;
+        int              mCtoL;
+        std::vector < Point > mPts;
+    };
+};
+
+FreeType2Impl::FreeType2Impl()
+{
+    FT_Init_FreeType(&(this->mLibrary) );
+
+    mCtoL        = 16;
+    mFn.shift    = 0;
+    mFn.delta    = 0;
+    mFn.move_to  = FreeType2Impl::mvFn;
+    mFn.line_to  = FreeType2Impl::lnFn;
+    mFn.cubic_to = FreeType2Impl::cuFn;
+    mFn.conic_to = FreeType2Impl::coFn;
+
+    mIsFaceAvailable = false;
+}
+
+FreeType2Impl::~FreeType2Impl()
+{
+    if( mIsFaceAvailable  == true ){
+        hb_font_destroy (mHb_font);
+        CV_Assert(!FT_Done_Face(mFace));
+        mIsFaceAvailable = false;
+    }
+    CV_Assert(!FT_Done_FreeType(mLibrary));
+}
+
+void FreeType2Impl::loadFontData(String fontFileName, int idx)
+{
+    if( mIsFaceAvailable  == true ){
+        hb_font_destroy (mHb_font);
+        CV_Assert(!FT_Done_Face(mFace));
+    }
+    CV_Assert(!FT_New_Face( mLibrary, fontFileName.c_str(), idx, &(mFace) ) );
+    mHb_font = hb_ft_font_create (mFace, NULL);
+    CV_Assert( mHb_font != NULL );
+    mIsFaceAvailable = true;
+}
+
+void FreeType2Impl::setSplitNumber(int num ){
+    CV_Assert( num > 0 );
+    mCtoL        = num;
+}
+
+void FreeType2Impl::putText(
+    InputOutputArray _img, const String& _text, Point _org,
+    int _fontHeight, Scalar _color,
+    int _thickness, int _line_type, bool bottomLeftOrigin
+)
+{
+    CV_Assert( mIsFaceAvailable == true );
+    CV_Assert( ( _img.empty()    == false ) &&
+               ( _img.isMat()    == true  ) &&
+               ( _img.depth()    == CV_8U ) &&
+               ( _img.dims()     == 2     ) &&
+               ( _img.channels() == 3     ) );
+    CV_Assert( ( _line_type == CV_AA) ||
+               ( _line_type == 4 ) ||
+               ( _line_type == 8 ) );
+
+    if ( _text.empty() )
+    {
+         return;
+    }
+
+    if( _line_type == CV_AA && _img.depth() != CV_8U ){
+        _line_type = 8;
+    }
+
+    CV_Assert(!FT_Set_Pixel_Sizes( mFace, _fontHeight, _fontHeight ));
+
+    mThickness = _thickness;
+    mLine_type = _line_type;
+    mColor     = _color;
+    mHeight    = _fontHeight;
+    mText      = _text;
+    mOrg       = _org;
+
+    if( !bottomLeftOrigin ) {
+        mOrg.y += mHeight;
+    }
+
+    if( mThickness < 0 ) // CV_FILLED
+    {
+        if ( mLine_type == CV_AA ) {
+            putTextBitmapBlend(_img);
+        }else{
+            putTextBitmapMono (_img);
+        }
+    }else{
+        putTextOutline(_img);
+    }
+}
+
+void FreeType2Impl::putTextOutline(InputOutputArray _img)
+{
+    hb_buffer_t *hb_buffer = hb_buffer_create ();
+    CV_Assert( hb_buffer != NULL );
+
+    unsigned int textLen;
+    hb_buffer_guess_segment_properties (hb_buffer);
+    hb_buffer_add_utf8 (hb_buffer, mText.c_str(), -1, 0, -1);
+    hb_glyph_info_t *info =
+        hb_buffer_get_glyph_infos(hb_buffer,&textLen );
+    CV_Assert( info != NULL );
+    hb_shape (mHb_font, hb_buffer, NULL, 0);
+
+    mOrg.y -= mHeight;
+    PathUserData *userData = new PathUserData( _img );
+    userData->mColor     = mColor;
+    userData->mCtoL      = mCtoL;
+    userData->mThickness = mThickness;
+    userData->mLine_type = mLine_type;
+
+    for( unsigned int i = 0 ; i < textLen ; i ++ ){
+        CV_Assert(!FT_Load_Glyph(mFace, info[i].codepoint, 0 ));
+
+        FT_GlyphSlot slot  = mFace->glyph;
+        FT_Outline outline = slot->outline;
+
+        // Flip
+        FT_Matrix mtx = { 1 << 16 , 0 , 0 , -(1 << 16) };
+        FT_Outline_Transform(&outline, &mtx);
+
+        // Move
+        FT_Outline_Translate(&outline,
+                             cOutlineOffset,
+                             cOutlineOffset );
+        // Move
+        FT_Outline_Translate(&outline,
+                             (FT_Pos)(mOrg.x << 6),
+                             (FT_Pos)((mOrg.y + mHeight)  << 6) );
+
+        // Draw
+        CV_Assert( !FT_Outline_Decompose(&outline, &mFn, (void*)userData) );
+
+        // Draw (Last Path)
+        mvFn( NULL, (void*)userData );
+
+        mOrg.x += ( mFace->glyph->advance.x ) >> 6;
+        mOrg.y += ( mFace->glyph->advance.y ) >> 6;
+   }
+   delete userData;
+   hb_buffer_destroy (hb_buffer);
+}
+
+void FreeType2Impl::putTextBitmapMono(InputOutputArray _img)
+{
+    Mat dst = _img.getMat();
+    hb_buffer_t *hb_buffer = hb_buffer_create ();
+    CV_Assert( hb_buffer != NULL );
+
+    unsigned int textLen;
+    hb_buffer_guess_segment_properties (hb_buffer);
+    hb_buffer_add_utf8 (hb_buffer, mText.c_str(), -1, 0, -1);
+    hb_glyph_info_t *info =
+        hb_buffer_get_glyph_infos(hb_buffer,&textLen );
+    CV_Assert( info != NULL );
+    hb_shape (mHb_font, hb_buffer, NULL, 0);
+
+    for( unsigned int i = 0 ; i < textLen ; i ++ ){
+        CV_Assert( !FT_Load_Glyph(mFace, info[i].codepoint, 0 ) );
+        CV_Assert( !FT_Render_Glyph( mFace->glyph, FT_RENDER_MODE_MONO ) );
+        FT_Bitmap    *bmp = &(mFace->glyph->bitmap);
+
+        Point gPos = mOrg;
+        gPos.y -= ( mFace->glyph->metrics.horiBearingY >> 6) ;
+        gPos.x += ( mFace->glyph->metrics.horiBearingX >> 6) ;
+
+        for (int row = 0; row < (int)bmp->rows; row ++) {
+            if( gPos.y + row < 0 ) {
+                continue;
+            }
+            if( gPos.y + row >= dst.rows ) {
+                break;
+            }
+
+            for (int col = 0; col < bmp->pitch; col ++) {
+                int cl = bmp->buffer[ row * bmp->pitch + col ];
+                if ( cl == 0 ) {
+                    continue;
+                }
+                for(int bit = 7; bit >= 0; bit -- ){
+                    if( gPos.x + col * 8 + (7 - bit) < 0 )
+                    {
+                        continue;
+                    }
+                    if( gPos.x + col * 8 + (7 - bit) >= dst.cols )
+                    {
+                        break;
+                    }
+
+                    if ( ( (cl >> bit) & 0x01 ) == 1 ) {
+                        cv::Vec3b* ptr = dst.ptr<cv::Vec3b>( gPos.y + row,  gPos.x + col * 8 + (7 - bit) );
+                        (*ptr)[0] = mColor[0];
+                        (*ptr)[1] = mColor[1];
+                        (*ptr)[2] = mColor[2];
+                    }
+                }
+            }
+        }
+
+        mOrg.x += ( mFace->glyph->advance.x ) >> 6;
+        mOrg.y += ( mFace->glyph->advance.y ) >> 6;
+    }
+    hb_buffer_destroy (hb_buffer);
+}
+
+void FreeType2Impl::putTextBitmapBlend(InputOutputArray _img)
+{
+    Mat dst = _img.getMat();
+    hb_buffer_t *hb_buffer = hb_buffer_create ();
+    CV_Assert( hb_buffer != NULL );
+
+    unsigned int textLen;
+    hb_buffer_guess_segment_properties (hb_buffer);
+    hb_buffer_add_utf8 (hb_buffer, mText.c_str(), -1, 0, -1);
+    hb_glyph_info_t *info =
+        hb_buffer_get_glyph_infos(hb_buffer,&textLen );
+    CV_Assert( info != NULL );
+
+    hb_shape (mHb_font, hb_buffer, NULL, 0);
+
+    for( unsigned int i = 0 ; i < textLen ; i ++ ){
+        CV_Assert( !FT_Load_Glyph(mFace, info[i].codepoint, 0 ) );
+        CV_Assert( !FT_Render_Glyph( mFace->glyph, FT_RENDER_MODE_NORMAL ) );
+        FT_Bitmap    *bmp = &(mFace->glyph->bitmap);
+
+        Point gPos = mOrg;
+        gPos.y -= ( mFace->glyph->metrics.horiBearingY >> 6) ;
+        gPos.x += ( mFace->glyph->metrics.horiBearingX >> 6) ;
+
+        for (int row = 0; row < (int)bmp->rows; row ++) {
+            if( gPos.y + row < 0 ) {
+                continue;
+            }
+            if( gPos.y + row >= dst.rows ) {
+                break;
+            }
+
+            for (int col = 0; col < bmp->pitch; col ++) {
+                int cl = bmp->buffer[ row * bmp->pitch + col ];
+                if ( cl == 0 ) {
+                    continue;
+                }
+                if( gPos.x + col < 0 )
+                {
+                    continue;
+                }
+                if( gPos.x + col >= dst.cols )
+                {
+                    break;
+                }
+
+                cv::Vec3b* ptr = dst.ptr<cv::Vec3b>( gPos.y + row , gPos.x + col);
+                double blendAlpha = (double ) cl / 255.0;
+
+                (*ptr)[0] = (double) mColor[0] * blendAlpha + (*ptr)[0] * (1.0 - blendAlpha );
+                (*ptr)[1] = (double) mColor[1] * blendAlpha + (*ptr)[1] * (1.0 - blendAlpha );
+                (*ptr)[2] = (double) mColor[2] * blendAlpha + (*ptr)[2] * (1.0 - blendAlpha );
+            }
+        }
+        mOrg.x += ( mFace->glyph->advance.x ) >> 6;
+        mOrg.y += ( mFace->glyph->advance.y ) >> 6;
+    }
+    hb_buffer_destroy (hb_buffer);
+}
+
+int FreeType2Impl::mvFn( const FT_Vector *to, void * user)
+{
+    if(user == NULL ) { return 1; }
+    PathUserData *p = (PathUserData*)user;
+
+    if( p->mPts.size() > 0 ){
+        Mat dst = p->mImg.getMat();
+        const Point *ptsList[] = { &(p->mPts[0]) };
+        int npt[1]; npt[0] = p->mPts.size();
+        polylines(
+            dst,
+            ptsList,
+            npt,
+            1,
+            false,
+            p->mColor,
+            p->mThickness,
+            p->mLine_type,
+            0
+        );
+    }
+
+    p->mPts.clear();
+
+    if( to == NULL ) { return 1; }
+
+    p->mPts.push_back( Point ( ftd(to->x), ftd(to->y) ) );
+    p->mOldP = *to;
+    return 0;
+}
+
+int FreeType2Impl::lnFn( const FT_Vector *to, void * user)
+{
+    if(to   == NULL ) { return 1; }
+    if(user == NULL ) { return 1; }
+
+    PathUserData *p = (PathUserData *)user;
+    p->mPts.push_back( Point ( ftd(to->x), ftd(to->y) ) );
+    p->mOldP = *to;
+    return 0;
+}
+
+int FreeType2Impl::coFn( const FT_Vector *cnt,
+                     const FT_Vector *to,
+                     void * user)
+{
+    if(cnt  == NULL ) { return 1; }
+    if(to   == NULL ) { return 1; }
+    if(user == NULL ) { return 1; }
+
+    PathUserData *p = (PathUserData *)user;
+
+    // Bezier to Line
+    for(int i = 0;i <= p->mCtoL; i++){
+        double u = (double)i * 1.0 / (p->mCtoL) ;
+        double nu = 1.0 - u;
+        double p0 =                  nu * nu;
+        double p1 = 2.0 * u *        nu;
+        double p2 =       u * u;
+
+        double X = (p->mOldP.x) * p0 + cnt->x * p1 + to->x * p2;
+        double Y = (p->mOldP.y) * p0 + cnt->y * p1 + to->y * p2;
+        p->mPts.push_back( Point ( ftd(X), ftd(Y) ) );
+    }
+    p->mOldP = *to;
+    return 0;
+}
+
+int FreeType2Impl::cuFn( const FT_Vector *cnt1,
+                     const FT_Vector *cnt2,
+                     const FT_Vector *to,
+                     void * user)
+{
+    if(cnt1 == NULL ) { return 1; }
+    if(cnt2 == NULL ) { return 1; }
+    if(to   == NULL ) { return 1; }
+    if(user == NULL ) { return 1; }
+
+    PathUserData *p = (PathUserData *)user;
+
+    // Bezier to Line
+    for(int i = 0; i <= p->mCtoL ;i++){
+        double u = (double)i * 1.0 / (p->mCtoL) ;
+        double nu = 1.0 - u;
+        double p0 =                  nu * nu * nu;
+        double p1 = 3.0 * u *        nu * nu;
+        double p2 = 3.0 * u * u *    nu;
+        double p3 =       u * u * u;
+
+        double X = (p->mOldP.x) * p0 + (cnt1->x)    * p1 +
+                   (cnt2->x   ) * p2 + (to->x  )    * p3;
+        double Y = (p->mOldP.y) * p0 + (cnt1->y)    * p1 +
+                   (cnt2->y   ) * p2 + (to->y  )    * p3;
+
+        p->mPts.push_back( Point ( ftd(X), ftd(Y) ) );
+    }
+    p->mOldP = *to;
+    return 0;
+}
+
+CV_EXPORTS_W Ptr<FreeType2> createFreeType2()
+{
+    return Ptr<FreeType2Impl> (new FreeType2Impl () );
+}
+
+
+}} // namespace freetype2
diff --git a/contrib/modules/freetype/src/precomp.hpp b/contrib/modules/freetype/src/precomp.hpp
new file mode 100644
index 0000000..dd12d57
--- /dev/null
+++ b/contrib/modules/freetype/src/precomp.hpp
@@ -0,0 +1,60 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+//  By downloading, copying, installing or using the software you agree to this license.
+//  If you do not agree to this license, do not download, install,
+//  copy or use the software.
+//
+//
+//                          License Agreement
+//                For Open Source Computer Vision Library
+//
+// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
+// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+//   * Redistribution's of source code must retain the above copyright notice,
+//     this list of conditions and the following disclaimer.
+//
+//   * Redistribution's in binary form must reproduce the above copyright notice,
+//     this list of conditions and the following disclaimer in the documentation
+//     and/or other materials provided with the distribution.
+//
+//   * The name of the copyright holders may not be used to endorse or promote products
+//     derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+//################################################################################
+//
+//                    Created by Kumataro
+//
+//################################################################################
+
+#ifndef __OPENCV_PRECOMP_H__
+#define __OPENCV_PRECOMP_H__
+
+#include <opencv2/core.hpp>
+#include <opencv2/imgproc.hpp>
+#include <opencv2/imgproc/imgproc_c.h> // for CV_AA
+#include <opencv2/freetype.hpp>
+#include "opencv2/opencv_modules.hpp"
+
+#include <iostream>
+#include <cstdio>
+#include <vector>
+#endif
diff --git a/contrib/modules/fuzzy/CMakeLists.txt b/contrib/modules/fuzzy/CMakeLists.txt
index cc04e15..e4e9ca6 100644
--- a/contrib/modules/fuzzy/CMakeLists.txt
+++ b/contrib/modules/fuzzy/CMakeLists.txt
@@ -1,3 +1,3 @@
 set(the_description "Fuzzy mathematical image processing")
 
-ocv_define_module(fuzzy opencv_imgproc opencv_core)
+ocv_define_module(fuzzy opencv_imgproc opencv_core WRAP python)
diff --git a/contrib/modules/fuzzy/include/opencv2/fuzzy/fuzzy_F0_math.hpp b/contrib/modules/fuzzy/include/opencv2/fuzzy/fuzzy_F0_math.hpp
index e0a2c48..5b24157 100644
--- a/contrib/modules/fuzzy/include/opencv2/fuzzy/fuzzy_F0_math.hpp
+++ b/contrib/modules/fuzzy/include/opencv2/fuzzy/fuzzy_F0_math.hpp
@@ -54,7 +54,7 @@ namespace ft
     //! @{
 
     /** @brief Computes components of the array using direct F0-transform.
-    @param matrix Input 1-channel array.
+    @param matrix Input array.
     @param kernel Kernel used for processing. Function **createKernel** can be used.
     @param components Output 32-bit array for the components.
     @param mask Mask can be used for unwanted area marking.
@@ -64,10 +64,10 @@ namespace ft
     @note
         F-transform technique is described in paper @cite Perf:FT.
      */
-    CV_EXPORTS void FT02D_components(InputArray matrix, InputArray kernel, OutputArray components, InputArray mask);
+    CV_EXPORTS_AS(FT02D_components1) void FT02D_components(InputArray matrix, InputArray kernel, OutputArray components, InputArray mask);
 
     /** @brief Computes components of the array using direct F0-transform.
-    @param matrix Input 1-channel array.
+    @param matrix Input array.
     @param kernel Kernel used for processing. Function **createKernel** can be used.
     @param components Output 32-bit array for the components.
 
@@ -76,10 +76,10 @@ namespace ft
     @note
         F-transform technique is described in paper @cite Perf:FT.
      */
-    CV_EXPORTS void FT02D_components(InputArray matrix, InputArray kernel, OutputArray components);
+    CV_EXPORTS_W void FT02D_components(InputArray matrix, InputArray kernel, OutputArray components);
 
     /** @brief Computes inverse F0-transfrom.
-    @param components Input 32-bit array for the components.
+    @param components Input 32-bit single channel array for the components.
     @param kernel Kernel used for processing. Function **createKernel** can be used.
     @param output Output 32-bit array.
     @param width Width of the output array.
@@ -88,29 +88,38 @@ namespace ft
     @note
         F-transform technique is described in paper @cite Perf:FT.
      */
-    CV_EXPORTS void FT02D_inverseFT(InputArray components, InputArray kernel, OutputArray output, int width, int height);
+    CV_EXPORTS_W void FT02D_inverseFT(InputArray components, InputArray kernel, OutputArray output, int width, int height);
 
     /** @brief Computes F0-transfrom and inverse F0-transfrom at once.
-    @param image Input image.
+    @param matrix Input matrix.
     @param kernel Kernel used for processing. Function **createKernel** can be used.
     @param output Output 32-bit array.
     @param mask Mask used for unwanted area marking.
 
     This function computes F-transfrom and inverse F-transfotm in one step. It is fully sufficient and optimized for **Mat**.
     */
-    CV_EXPORTS void FT02D_process(const Mat &image, const Mat &kernel, Mat &output, const Mat &mask);
+    CV_EXPORTS_AS(FT02D_process1) void FT02D_process(InputArray matrix, InputArray kernel, OutputArray output, InputArray mask);
+
+    /** @brief Computes F0-transfrom and inverse F0-transfrom at once.
+    @param matrix Input matrix.
+    @param kernel Kernel used for processing. Function **createKernel** can be used.
+    @param output Output 32-bit array.
+
+    This function computes F-transfrom and inverse F-transfotm in one step. It is fully sufficient and optimized for **Mat**.
+    */
+    CV_EXPORTS_W void FT02D_process(InputArray matrix, InputArray kernel, OutputArray output);
 
     /** @brief Computes F0-transfrom and inverse F0-transfrom at once and return state.
-    @param image Input image.
+    @param matrix Input matrix.
     @param kernel Kernel used for processing. Function **createKernel** can be used.
-    @param imageOutput Output 32-bit array.
+    @param output Output 32-bit array.
     @param mask Mask used for unwanted area marking.
     @param maskOutput Mask after one iteration.
     @param firstStop If **true** function returns -1 when first problem appears. In case of **false**, the process is completed and summation of all problems returned.
 
     This function computes iteration of F-transfrom and inverse F-transfotm and handle image and mask change. The function is used in *inpaint* function.
     */
-    CV_EXPORTS int FT02D_iteration(const Mat &image, const Mat &kernel, Mat &imageOutput, const Mat &mask, Mat &maskOutput, bool firstStop = true);
+    CV_EXPORTS_W int FT02D_iteration(InputArray matrix, InputArray kernel, OutputArray output, InputArray mask, OutputArray maskOutput, bool firstStop);
 
     //! @}
 }
diff --git a/contrib/modules/fuzzy/include/opencv2/fuzzy/fuzzy_image.hpp b/contrib/modules/fuzzy/include/opencv2/fuzzy/fuzzy_image.hpp
index 00a8efa..e5287a9 100644
--- a/contrib/modules/fuzzy/include/opencv2/fuzzy/fuzzy_image.hpp
+++ b/contrib/modules/fuzzy/include/opencv2/fuzzy/fuzzy_image.hpp
@@ -61,7 +61,7 @@ namespace ft
 
     The function creates kernel usable for latter fuzzy image processing.
     */
-    CV_EXPORTS void createKernel(cv::InputArray A, cv::InputArray B, cv::OutputArray kernel, const int chn = 1);
+    CV_EXPORTS_AS(createKernel1) void createKernel(InputArray A, InputArray B, OutputArray kernel, const int chn);
 
     /** @brief Creates kernel from general functions.
     @param function Function type could be one of the following:
@@ -72,7 +72,7 @@ namespace ft
 
     The function creates kernel from predefined functions.
     */
-    CV_EXPORTS void createKernel(int function, int radius, cv::OutputArray kernel, const int chn = 1);
+    CV_EXPORTS_W void createKernel(int function, int radius, OutputArray kernel, const int chn);
 
     /** @brief Image inpainting
     @param image Input image.
@@ -91,16 +91,16 @@ namespace ft
     @note
         The algorithms are described in paper @cite Perf:rec.
     */
-    CV_EXPORTS void inpaint(const cv::Mat &image, const cv::Mat &mask, cv::Mat &output, int radius = 2, int function = ft::LINEAR, int algorithm = ft::ONE_STEP);
+    CV_EXPORTS_W void inpaint(InputArray image, InputArray mask, OutputArray output, int radius, int function, int algorithm);
 
     /** @brief Image filtering
     @param image Input image.
-    @param kernel Final 32-b kernel.
+    @param kernel Final 32-bit kernel.
     @param output Output 32-bit image.
 
     Filtering of the input image by means of F-transform.
     */
-    CV_EXPORTS void filter(const cv::Mat &image, const cv::Mat &kernel, cv::Mat &output);
+    CV_EXPORTS_W void filter(InputArray image, InputArray kernel, OutputArray output);
 
     //! @}
 }
diff --git a/contrib/modules/fuzzy/src/fuzzy_F0_math.cpp b/contrib/modules/fuzzy/src/fuzzy_F0_math.cpp
index 730f408..892bcbe 100644
--- a/contrib/modules/fuzzy/src/fuzzy_F0_math.cpp
+++ b/contrib/modules/fuzzy/src/fuzzy_F0_math.cpp
@@ -45,24 +45,21 @@ using namespace cv;
 
 void ft::FT02D_components(InputArray matrix, InputArray kernel, OutputArray components, InputArray mask)
 {
-    Mat matrixMat = matrix.getMat();
-    Mat kernelMat = kernel.getMat();
-    Mat maskMat = mask.getMat();
+    CV_Assert(matrix.channels() == kernel.channels() && mask.channels() == 1);
 
-    CV_Assert(matrixMat.channels() == 1 && kernelMat.channels() == 1 && maskMat.channels() == 1);
-
-    int radiusX = (kernelMat.cols - 1) / 2;
-    int radiusY = (kernelMat.rows - 1) / 2;
-    int An = matrixMat.cols / radiusX + 1;
-    int Bn = matrixMat.rows / radiusY + 1;
+    int radiusX = (kernel.cols() - 1) / 2;
+    int radiusY = (kernel.rows() - 1) / 2;
+    int An = matrix.cols() / radiusX + 1;
+    int Bn = matrix.rows() / radiusY + 1;
 
     Mat matrixPadded;
     Mat maskPadded;
 
-    copyMakeBorder(matrixMat, matrixPadded, radiusY, kernelMat.rows, radiusX, kernelMat.cols, BORDER_CONSTANT, Scalar(0));
-    copyMakeBorder(maskMat, maskPadded, radiusY, kernelMat.rows, radiusX, kernelMat.cols, BORDER_CONSTANT, Scalar(0));
+    copyMakeBorder(matrix, matrixPadded, radiusY, kernel.rows(), radiusX, kernel.cols(), BORDER_CONSTANT, Scalar(0));
+    copyMakeBorder(mask, maskPadded, radiusY, kernel.rows(), radiusX, kernel.cols(), BORDER_CONSTANT, Scalar(0));
+
+    components.create(Bn, An, CV_MAKETYPE(CV_32F, matrix.channels()));
 
-    components.create(Bn, An, CV_32F);
     Mat componentsMat = components.getMat();
 
     for (int i = 0; i < An; i++)
@@ -71,18 +68,21 @@ void ft::FT02D_components(InputArray matrix, InputArray kernel, OutputArray comp
         {
             int centerX = (i * radiusX) + radiusX;
             int centerY = (o * radiusY) + radiusY;
-            Rect area(centerX - radiusX, centerY - radiusY, kernelMat.cols, kernelMat.rows);
+            Rect area(centerX - radiusX, centerY - radiusY, kernel.cols(), kernel.rows());
 
             Mat roiImage(matrixPadded, area);
             Mat roiMask(maskPadded, area);
             Mat kernelMasked;
 
-            kernelMat.copyTo(kernelMasked, roiMask);
+            kernel.copyTo(kernelMasked, roiMask);
 
             Mat numerator;
             multiply(roiImage, kernelMasked, numerator, 1, CV_32F);
 
-            componentsMat.row(o).col(i) = sum(numerator) / sum(kernelMasked);
+            Scalar value;
+            divide(sum(numerator), sum(kernelMasked), value, 1, CV_32F);
+
+            componentsMat.row(o).col(i).setTo(value);
         }
     }
 }
@@ -96,19 +96,18 @@ void ft::FT02D_components(InputArray matrix, InputArray kernel, OutputArray comp
 
 void ft::FT02D_inverseFT(InputArray components, InputArray kernel, OutputArray output, int width, int height)
 {
-    Mat componentsMat = components.getMat();
-    Mat kernelMat = kernel.getMat();
+    CV_Assert(components.channels() == 1 && kernel.channels() == 1);
 
-    CV_Assert(componentsMat.channels() == 1 && kernelMat.channels() == 1);
+    Mat componentsMat = components.getMat();
 
-    int radiusX = (kernelMat.cols - 1) / 2;
-    int radiusY = (kernelMat.rows - 1) / 2;
-    int paddedOutputWidth = radiusX + width + kernelMat.cols;
-    int paddedOutputHeight = radiusY + height + kernelMat.rows;
+    int radiusX = (kernel.cols() - 1) / 2;
+    int radiusY = (kernel.rows() - 1) / 2;
+    int outputWidthPadded = radiusX + width + kernel.cols();
+    int outputHeightPadded = radiusY + height + kernel.rows();
 
     output.create(height, width, CV_32F);
 
-    Mat outputZeroes(paddedOutputHeight, paddedOutputWidth, CV_32F, Scalar(0));
+    Mat outputZeroes(outputHeightPadded, outputWidthPadded, CV_32F, Scalar(0));
 
     for (int i = 0; i < componentsMat.cols; i++)
     {
@@ -116,34 +115,48 @@ void ft::FT02D_inverseFT(InputArray components, InputArray kernel, OutputArray o
         {
             int centerX = (i * radiusX) + radiusX;
             int centerY = (o * radiusY) + radiusY;
-            Rect area(centerX - radiusX, centerY - radiusY, kernelMat.cols, kernelMat.rows);
+            Rect area(centerX - radiusX, centerY - radiusY, kernel.cols(), kernel.rows());
+
+            float component = componentsMat.at<float>(o, i);
+
+            Mat inverse;
+            multiply(kernel, component, inverse, 1, CV_32F);
 
             Mat roiOutput(outputZeroes, area);
-            roiOutput += kernelMat.mul(componentsMat.at<float>(o,i));
+            add(roiOutput, inverse, roiOutput);
         }
     }
 
     outputZeroes(Rect(radiusX, radiusY, width, height)).copyTo(output);
 }
 
-void ft::FT02D_process(const cv::Mat &image, const cv::Mat &kernel, cv::Mat &output, const cv::Mat &mask)
+void ft::FT02D_process(InputArray matrix, InputArray kernel, OutputArray output)
+{
+    Mat mask = Mat::ones(matrix.size(), CV_8U);
+
+    ft::FT02D_process(matrix, kernel, output, mask);
+}
+
+void ft::FT02D_process(InputArray matrix, InputArray kernel, OutputArray output, InputArray mask)
 {
-    CV_Assert(image.channels() == kernel.channels());
+    CV_Assert(matrix.channels() == kernel.channels() && mask.channels() == 1);
 
-    int radiusX = (kernel.cols - 1) / 2;
-    int radiusY = (kernel.rows - 1) / 2;
-    int An = image.cols / radiusX + 1;
-    int Bn = image.rows / radiusY + 1;
-    int outputWidthPadded = radiusX + image.cols + kernel.cols;
-    int outputHeightPadded = radiusY + image.rows + kernel.rows;
+    int radiusX = (kernel.cols() - 1) / 2;
+    int radiusY = (kernel.rows() - 1) / 2;
+    int An = matrix.cols() / radiusX + 1;
+    int Bn = matrix.rows() / radiusY + 1;
+    int outputWidthPadded = radiusX + matrix.cols() + kernel.cols();
+    int outputHeightPadded = radiusY + matrix.rows() + kernel.rows();
 
-    Mat imagePadded;
+    Mat matrixPadded;
     Mat maskPadded;
 
-    output = Mat::zeros(outputHeightPadded, outputWidthPadded, CV_MAKETYPE(CV_32F, image.channels()));
+    output.create(matrix.size(), CV_MAKETYPE(CV_32F, matrix.channels()));
+
+    Mat outputZeroes(outputHeightPadded, outputWidthPadded, output.type(), Scalar(0));
 
-    copyMakeBorder(image, imagePadded, radiusY, kernel.rows, radiusX, kernel.cols, BORDER_CONSTANT, Scalar(0));
-    copyMakeBorder(mask, maskPadded, radiusY, kernel.rows, radiusX, kernel.cols, BORDER_CONSTANT, Scalar(0));
+    copyMakeBorder(matrix, matrixPadded, radiusY, kernel.rows(), radiusX, kernel.cols(), BORDER_CONSTANT, Scalar(0));
+    copyMakeBorder(mask, maskPadded, radiusY, kernel.rows(), radiusX, kernel.cols(), BORDER_CONSTANT, Scalar(0));
 
     for (int i = 0; i < An; i++)
     {
@@ -151,16 +164,16 @@ void ft::FT02D_process(const cv::Mat &image, const cv::Mat &kernel, cv::Mat &out
         {
             int centerX = (i * radiusX) + radiusX;
             int centerY = (o * radiusY) + radiusY;
-            Rect area(centerX - radiusX, centerY - radiusY, kernel.cols, kernel.rows);
+            Rect area(centerX - radiusX, centerY - radiusY, kernel.cols(), kernel.rows());
 
-            Mat roiImage(imagePadded, area);
+            Mat roiMatrix(matrixPadded, area);
             Mat roiMask(maskPadded, area);
             Mat kernelMasked;
 
             kernel.copyTo(kernelMasked, roiMask);
 
             Mat numerator;
-            multiply(roiImage, kernelMasked, numerator, 1, CV_32F);
+            multiply(roiMatrix, kernelMasked, numerator, 1, CV_32F);
 
             Scalar component;
             divide(sum(numerator), sum(kernelMasked), component, 1, CV_32F);
@@ -168,34 +181,43 @@ void ft::FT02D_process(const cv::Mat &image, const cv::Mat &kernel, cv::Mat &out
             Mat inverse;
             multiply(kernel, component, inverse, 1, CV_32F);
 
-            Mat roiOutput(output, area);
+            Mat roiOutput(outputZeroes, area);
             add(roiOutput, inverse, roiOutput);
         }
     }
 
-    output = output(Rect(radiusX, radiusY, image.cols, image.rows));
+    outputZeroes(Rect(radiusX, radiusY, matrix.cols(), matrix.rows())).copyTo(output);
 }
 
-int ft::FT02D_iteration(const Mat &image, const Mat &kernel, Mat &imageOutput, const Mat &mask, Mat &maskOutput, bool firstStop)
+int ft::FT02D_iteration(InputArray matrix, InputArray kernel, OutputArray output, InputArray mask, OutputArray maskOutput, bool firstStop)
 {
-    CV_Assert(image.channels() == kernel.channels() && mask.channels() == 1);
-
-    int radiusX = (kernel.cols - 1) / 2;
-    int radiusY = (kernel.rows - 1) / 2;
-    int An = image.cols / radiusX + 1;
-    int Bn = image.rows / radiusY + 1;
-    int outputWidthPadded = radiusX + image.cols + kernel.cols;
-    int outputHeightPadded = radiusY + image.rows + kernel.rows;
+    CV_Assert(matrix.channels() == kernel.channels() && mask.channels() == 1);
+
+    int radiusX = (kernel.cols() - 1) / 2;
+    int radiusY = (kernel.rows() - 1) / 2;
+    int An = matrix.cols() / radiusX + 1;
+    int Bn = matrix.rows() / radiusY + 1;
+    int outputWidthPadded = radiusX + matrix.cols() + kernel.cols();
+    int outputHeightPadded = radiusY + matrix.rows() + kernel.rows();
     int undefinedComponents = 0;
 
-    Mat imagePadded;
-    Mat maskPadded;
+    output.create(matrix.size(), CV_MAKETYPE(CV_32F, matrix.channels()));
+    output.setTo(0);
 
-    imageOutput = Mat::zeros(outputHeightPadded, outputWidthPadded, CV_MAKETYPE(CV_32F, image.channels()));
-    maskOutput = Mat::ones(outputHeightPadded, outputWidthPadded, CV_8UC1);
+    if (maskOutput.needed())
+    {
+        maskOutput.create(mask.rows(), mask.cols(), CV_8UC1);
+        maskOutput.setTo(1);
+    }
 
-    copyMakeBorder(image, imagePadded, radiusY, kernel.rows, radiusX, kernel.cols, BORDER_CONSTANT, Scalar(0));
-    copyMakeBorder(mask, maskPadded, radiusY, kernel.rows, radiusX, kernel.cols, BORDER_CONSTANT, Scalar(0));
+    Mat matrixOutputMat = Mat::zeros(outputHeightPadded, outputWidthPadded, CV_MAKETYPE(CV_32F, matrix.channels()));
+    Mat maskOutputMat = Mat::ones(outputHeightPadded, outputWidthPadded, CV_8UC1);
+
+    Mat matrixPadded;
+    Mat maskPadded;
+
+    copyMakeBorder(matrix, matrixPadded, radiusY, kernel.rows(), radiusX, kernel.cols(), BORDER_CONSTANT, Scalar(0));
+    copyMakeBorder(mask, maskPadded, radiusY, kernel.rows(), radiusX, kernel.cols(), BORDER_CONSTANT, Scalar(0));
 
     for (int i = 0; i < An; i++)
     {
@@ -203,16 +225,16 @@ int ft::FT02D_iteration(const Mat &image, const Mat &kernel, Mat &imageOutput, c
         {
             int centerX = (i * radiusX) + radiusX;
             int centerY = (o * radiusY) + radiusY;
-            Rect area(centerX - radiusX, centerY - radiusY, kernel.cols, kernel.rows);
+            Rect area(centerX - radiusX, centerY - radiusY, kernel.cols(), kernel.rows());
 
-            Mat roiImage(imagePadded, area);
+            Mat roiMatrix(matrixPadded, area);
             Mat roiMask(maskPadded, area);
             Mat kernelMasked;
 
             kernel.copyTo(kernelMasked, roiMask);
 
             Mat numerator;
-            multiply(roiImage, kernelMasked, numerator, 1, CV_32F);
+            multiply(roiMatrix, kernelMasked, numerator, 1, CV_32F);
 
             Scalar denominator = sum(kernelMasked);
 
@@ -220,8 +242,8 @@ int ft::FT02D_iteration(const Mat &image, const Mat &kernel, Mat &imageOutput, c
             {
                 if (firstStop)
                 {
-                    imageOutput = imageOutput(Rect(radiusX, radiusY, image.cols, image.rows));
-                    maskOutput = maskPadded(Rect(radiusX, radiusY, image.cols, image.rows));
+                    matrixOutputMat = matrixPadded(Rect(radiusX, radiusY, matrix.cols(), matrix.rows()));
+                    maskOutputMat = maskPadded(Rect(radiusX, radiusY, matrix.cols(), matrix.rows()));
 
                     return -1;
                 }
@@ -229,8 +251,8 @@ int ft::FT02D_iteration(const Mat &image, const Mat &kernel, Mat &imageOutput, c
                 {
                     undefinedComponents++;
 
-                    Mat roiMaskOutput(maskOutput, Rect(centerX - radiusX + 1, centerY - radiusY + 1, kernel.cols - 2, kernel.rows - 2));
-                    roiMaskOutput = 0;
+                    Mat roiMaskOutput(maskOutputMat, Rect(centerX - radiusX + 1, centerY - radiusY + 1, kernel.cols() - 2, kernel.rows() - 2));
+                    roiMaskOutput.setTo(0);
 
                     continue;
                 }
@@ -242,13 +264,17 @@ int ft::FT02D_iteration(const Mat &image, const Mat &kernel, Mat &imageOutput, c
             Mat inverse;
             multiply(kernel, component, inverse, 1, CV_32F);
 
-            Mat roiImageOutput(imageOutput, area);
-            add(roiImageOutput, inverse, roiImageOutput);
+            Mat roiMatrixOutput(matrixOutputMat, area);
+            add(roiMatrixOutput, inverse, roiMatrixOutput);
         }
     }
 
-    imageOutput = imageOutput(Rect(radiusX, radiusY, image.cols, image.rows));
-    maskOutput = maskOutput(Rect(radiusX, radiusY, image.cols, image.rows));
+    matrixOutputMat(Rect(radiusX, radiusY, matrix.cols(), matrix.rows())).copyTo(output);
+
+    if (maskOutput.needed())
+    {
+        maskOutputMat(Rect(radiusX, radiusY, matrix.cols(), matrix.rows())).copyTo(maskOutput);
+    }
 
     return undefinedComponents;
 }
diff --git a/contrib/modules/fuzzy/src/fuzzy_image.cpp b/contrib/modules/fuzzy/src/fuzzy_image.cpp
index 3147383..c443a70 100644
--- a/contrib/modules/fuzzy/src/fuzzy_image.cpp
+++ b/contrib/modules/fuzzy/src/fuzzy_image.cpp
@@ -58,7 +58,7 @@ void ft::createKernel(InputArray A, InputArray B, OutputArray kernel, const int
     merge(channels, kernel);
 }
 
-void ft::createKernel(int function, int radius, cv::OutputArray kernel, const int chn)
+void ft::createKernel(int function, int radius, OutputArray kernel, const int chn)
 {
     int basicFunctionWidth = 2 * radius + 1;
     Mat kernelOneChannel;
@@ -91,7 +91,7 @@ void ft::createKernel(int function, int radius, cv::OutputArray kernel, const in
     merge(channels, kernel);
 }
 
-void ft::inpaint(const cv::Mat &image, const cv::Mat &mask, cv::Mat &output, int radius, int function, int algorithm)
+void ft::inpaint(InputArray image, InputArray mask, OutputArray output, int radius, int function, int algorithm)
 {
     if (algorithm == ft::ONE_STEP)
     {
@@ -99,42 +99,32 @@ void ft::inpaint(const cv::Mat &image, const cv::Mat &mask, cv::Mat &output, int
         ft::createKernel(function, radius, kernel, image.channels());
 
         Mat processingInput;
-        image.convertTo(processingInput, CV_32F);
+        image.getMat().convertTo(processingInput, CV_32F);
 
-        Mat processingOutput;
-        ft::FT02D_process(processingInput, kernel, processingOutput, mask);
-
-        processingInput.copyTo(processingOutput, mask);
+        ft::FT02D_process(image, kernel, output, mask);
 
-        output = processingOutput;
+        processingInput.copyTo(output, mask);
     }
     else if (algorithm == ft::MULTI_STEP)
     {
         Mat kernel;
-        Mat processingOutput;
-        Mat outpuMask;
         int state = 0;
         int currentRadius = radius;
 
         Mat processingInput;
-        image.convertTo(processingInput, CV_32F);
-
-        Mat processingMask;
-        cvtColor(mask, processingMask, COLOR_BGR2GRAY);
+        image.getMat().convertTo(processingInput, CV_32F);
 
         do
         {
             ft::createKernel(function, currentRadius, kernel, image.channels());
 
-            state = ft::FT02D_iteration(processingInput, kernel, processingOutput, processingMask, outpuMask, true);
+            state = ft::FT02D_iteration(image, kernel, output, mask, noArray(), true);
 
             currentRadius++;
         }
         while(state != 0);
 
-        processingInput.copyTo(processingOutput, mask);
-
-        output = processingOutput;
+        processingInput.copyTo(output, mask);
     }
     else if (algorithm == ft::ITERATIVE)
     {
@@ -144,14 +134,11 @@ void ft::inpaint(const cv::Mat &image, const cv::Mat &mask, cv::Mat &output, int
         int state = 0;
         int currentRadius = radius;
 
-        Mat originalImage;
-        image.convertTo(originalImage, CV_32F);
-
         Mat processingInput;
-        image.convertTo(processingInput, CV_32F);
+        image.getMat().convertTo(processingInput, CV_32F);
 
         Mat processingMask;
-        cvtColor(mask, processingMask, COLOR_BGR2GRAY);
+        mask.copyTo(processingMask);
 
         do
         {
@@ -168,11 +155,11 @@ void ft::inpaint(const cv::Mat &image, const cv::Mat &mask, cv::Mat &output, int
         }
         while(state != 0);
 
-        output = processingInput;
+        processingInput.copyTo(output);
     }
 }
 
-void ft::filter(const cv::Mat &image, const cv::Mat &kernel, cv::Mat &output)
+void ft::filter(InputArray image, InputArray kernel, OutputArray output)
 {
     Mat mask = Mat::ones(image.size(), CV_8U);
 
diff --git a/contrib/modules/fuzzy/test/test_f0.cpp b/contrib/modules/fuzzy/test/test_f0.cpp
new file mode 100644
index 0000000..e9ff61b
--- /dev/null
+++ b/contrib/modules/fuzzy/test/test_f0.cpp
@@ -0,0 +1,164 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+//  By downloading, copying, installing or using the software you agree to this license.
+//  If you do not agree to this license, do not download, install,
+//  copy or use the software.
+//
+//
+//                           License Agreement
+//                For Open Source Computer Vision Library
+//
+// Copyright (C) 2015, University of Ostrava, Institute for Research and Applications of Fuzzy Modeling,
+// Pavel Vlasanek, all rights reserved. Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+//   * Redistribution's of source code must retain the above copyright notice,
+//     this list of conditions and the following disclaimer.
+//
+//   * Redistribution's in binary form must reproduce the above copyright notice,
+//     this list of conditions and the following disclaimer in the documentation
+//     and/or other materials provided with the distribution.
+//
+//   * The name of the copyright holders may not be used to endorse or promote products
+//     derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "test_precomp.hpp"
+
+#include <string>
+
+using namespace std;
+using namespace cv;
+
+TEST(fuzzy_f0, components)
+{
+    float arI[16][16] =
+    {
+        { 0, 0, 0, 10, 34, 57, 80, 104, 127, 150, 174, 197, 221, 244, 255, 255 },
+        { 0, 0, 0, 10, 34, 57, 80, 104, 127, 150, 174, 197, 221, 244, 255, 255 },
+        { 0, 0, 0, 10, 34, 57, 80, 104, 127, 150, 174, 197, 221, 244, 255, 255 },
+        { 0, 0, 0, 10, 34, 57, 80, 104, 127, 150, 174, 197, 221, 244, 255, 255 },
+        { 0, 0, 0, 10, 34, 57, 80, 104, 127, 150, 174, 197, 221, 244, 255, 255 },
+        { 0, 0, 0, 10, 34, 57, 80, 104, 127, 150, 174, 197, 221, 244, 255, 255 },
+        { 0, 0, 0, 10, 34, 57, 80, 104, 127, 150, 174, 197, 221, 244, 255, 255 },
+        { 0, 0, 0, 10, 34, 57, 80, 104, 127, 150, 174, 197, 221, 244, 255, 255 },
+        { 0, 0, 0, 10, 34, 57, 80, 104, 127, 150, 174, 197, 221, 244, 255, 255 },
+        { 0, 0, 0, 10, 34, 57, 80, 104, 127, 150, 174, 197, 221, 244, 255, 255 },
+        { 0, 0, 0, 10, 34, 57, 80, 104, 127, 150, 174, 197, 221, 244, 255, 255 },
+        { 0, 0, 0, 10, 34, 57, 80, 104, 127, 150, 174, 197, 221, 244, 255, 255 },
+        { 0, 0, 0, 10, 34, 57, 80, 104, 127, 150, 174, 197, 221, 244, 255, 255 },
+        { 0, 0, 0, 10, 34, 57, 80, 104, 127, 150, 174, 197, 221, 244, 255, 255 },
+        { 0, 0, 0, 10, 34, 57, 80, 104, 127, 150, 174, 197, 221, 244, 255, 255 },
+        { 0, 0, 0, 10, 34, 57, 80, 104, 127, 150, 174, 197, 221, 244, 255, 255 }
+    };
+    Mat I = Mat(16, 16, CV_32F, arI);
+
+    float arDemandedComp[9][9] =
+    {
+        { 0, 2.5, 33.75, 80.25, 127, 173.75, 220.75, 252.25, 255 },
+        { 0, 2.5, 33.75, 80.25, 127, 173.75, 220.75, 252.25, 255 },
+        { 0, 2.5, 33.75, 80.25, 127, 173.75, 220.75, 252.25, 255 },
+        { 0, 2.5, 33.75, 80.25, 127, 173.75, 220.75, 252.25, 255 },
+        { 0, 2.5, 33.75, 80.25, 127, 173.75, 220.75, 252.25, 255 },
+        { 0, 2.5, 33.75, 80.25, 127, 173.75, 220.75, 252.25, 255 },
+        { 0, 2.5, 33.75, 80.25, 127, 173.75, 220.75, 252.25, 255 },
+        { 0, 2.5, 33.75, 80.25, 127, 173.75, 220.75, 252.25, 255 },
+        { 0, 2.5, 33.75, 80.25, 127, 173.75, 220.75, 252.25, 255 }
+    };
+    Mat demandedComp = Mat(9, 9, CV_32F, arDemandedComp);
+
+    Mat kernel;
+    ft::createKernel(ft::LINEAR, 2, kernel, 1);
+
+    Mat f0comp;
+    ft::FT02D_components(I, kernel, f0comp);
+
+    double n1 = cvtest::norm(demandedComp, f0comp, NORM_INF);
+
+    EXPECT_DOUBLE_EQ(n1, 0);
+}
+
+TEST(fuzzy_f0, inversion)
+{
+    float arI[16][16] =
+    {
+        { 0, 0, 0, 10, 34, 57, 80, 104, 127, 150, 174, 197, 221, 244, 255, 255 },
+        { 0, 0, 0, 10, 34, 57, 80, 104, 127, 150, 174, 197, 221, 244, 255, 255 },
+        { 0, 0, 0, 10, 34, 57, 80, 104, 127, 150, 174, 197, 221, 244, 255, 255 },
+        { 0, 0, 0, 10, 34, 57, 80, 104, 127, 150, 174, 197, 221, 244, 255, 255 },
+        { 0, 0, 0, 10, 34, 57, 80, 104, 127, 150, 174, 197, 221, 244, 255, 255 },
+        { 0, 0, 0, 10, 34, 57, 80, 104, 127, 150, 174, 197, 221, 244, 255, 255 },
+        { 0, 0, 0, 10, 34, 57, 80, 104, 127, 150, 174, 197, 221, 244, 255, 255 },
+        { 0, 0, 0, 10, 34, 57, 80, 104, 127, 150, 174, 197, 221, 244, 255, 255 },
+        { 0, 0, 0, 10, 34, 57, 80, 104, 127, 150, 174, 197, 221, 244, 255, 255 },
+        { 0, 0, 0, 10, 34, 57, 80, 104, 127, 150, 174, 197, 221, 244, 255, 255 },
+        { 0, 0, 0, 10, 34, 57, 80, 104, 127, 150, 174, 197, 221, 244, 255, 255 },
+        { 0, 0, 0, 10, 34, 57, 80, 104, 127, 150, 174, 197, 221, 244, 255, 255 },
+        { 0, 0, 0, 10, 34, 57, 80, 104, 127, 150, 174, 197, 221, 244, 255, 255 },
+        { 0, 0, 0, 10, 34, 57, 80, 104, 127, 150, 174, 197, 221, 244, 255, 255 },
+        { 0, 0, 0, 10, 34, 57, 80, 104, 127, 150, 174, 197, 221, 244, 255, 255 },
+        { 0, 0, 0, 10, 34, 57, 80, 104, 127, 150, 174, 197, 221, 244, 255, 255 }
+    };
+    Mat I = Mat(16, 16, CV_32F, arI);
+
+    float arDemandedO[16][16] =
+    {
+        { 0, 1.25, 2.5, 18.125, 33.75, 57, 80.25, 103.625, 127, 150.375, 173.75, 197.25, 220.75, 236.5, 252.25, 253.625 },
+        { 0, 1.25, 2.5, 18.125, 33.75, 57, 80.25, 103.625, 127, 150.375, 173.75, 197.25, 220.75, 236.5, 252.25, 253.625 },
+        { 0, 1.25, 2.5, 18.125, 33.75, 57, 80.25, 103.625, 127, 150.375, 173.75, 197.25, 220.75, 236.5, 252.25, 253.625 },
+        { 0, 1.25, 2.5, 18.125, 33.75, 57, 80.25, 103.625, 127, 150.375, 173.75, 197.25, 220.75, 236.5, 252.25, 253.625 },
+        { 0, 1.25, 2.5, 18.125, 33.75, 57, 80.25, 103.625, 127, 150.375, 173.75, 197.25, 220.75, 236.5, 252.25, 253.625 },
+        { 0, 1.25, 2.5, 18.125, 33.75, 57, 80.25, 103.625, 127, 150.375, 173.75, 197.25, 220.75, 236.5, 252.25, 253.625 },
+        { 0, 1.25, 2.5, 18.125, 33.75, 57, 80.25, 103.625, 127, 150.375, 173.75, 197.25, 220.75, 236.5, 252.25, 253.625 },
+        { 0, 1.25, 2.5, 18.125, 33.75, 57, 80.25, 103.625, 127, 150.375, 173.75, 197.25, 220.75, 236.5, 252.25, 253.625 },
+        { 0, 1.25, 2.5, 18.125, 33.75, 57, 80.25, 103.625, 127, 150.375, 173.75, 197.25, 220.75, 236.5, 252.25, 253.625 },
+        { 0, 1.25, 2.5, 18.125, 33.75, 57, 80.25, 103.625, 127, 150.375, 173.75, 197.25, 220.75, 236.5, 252.25, 253.625 },
+        { 0, 1.25, 2.5, 18.125, 33.75, 57, 80.25, 103.625, 127, 150.375, 173.75, 197.25, 220.75, 236.5, 252.25, 253.625 },
+        { 0, 1.25, 2.5, 18.125, 33.75, 57, 80.25, 103.625, 127, 150.375, 173.75, 197.25, 220.75, 236.5, 252.25, 253.625 },
+        { 0, 1.25, 2.5, 18.125, 33.75, 57, 80.25, 103.625, 127, 150.375, 173.75, 197.25, 220.75, 236.5, 252.25, 253.625 },
+        { 0, 1.25, 2.5, 18.125, 33.75, 57, 80.25, 103.625, 127, 150.375, 173.75, 197.25, 220.75, 236.5, 252.25, 253.625 },
+        { 0, 1.25, 2.5, 18.125, 33.75, 57, 80.25, 103.625, 127, 150.375, 173.75, 197.25, 220.75, 236.5, 252.25, 253.625 },
+        { 0, 1.25, 2.5, 18.125, 33.75, 57, 80.25, 103.625, 127, 150.375, 173.75, 197.25, 220.75, 236.5, 252.25, 253.625 }
+    };
+    Mat demandedO = Mat(16, 16, CV_32F, arDemandedO);
+
+    float arComp[9][9] =
+    {
+        { 0, 2.5, 33.75, 80.25, 127, 173.75, 220.75, 252.25, 255 },
+        { 0, 2.5, 33.75, 80.25, 127, 173.75, 220.75, 252.25, 255 },
+        { 0, 2.5, 33.75, 80.25, 127, 173.75, 220.75, 252.25, 255 },
+        { 0, 2.5, 33.75, 80.25, 127, 173.75, 220.75, 252.25, 255 },
+        { 0, 2.5, 33.75, 80.25, 127, 173.75, 220.75, 252.25, 255 },
+        { 0, 2.5, 33.75, 80.25, 127, 173.75, 220.75, 252.25, 255 },
+        { 0, 2.5, 33.75, 80.25, 127, 173.75, 220.75, 252.25, 255 },
+        { 0, 2.5, 33.75, 80.25, 127, 173.75, 220.75, 252.25, 255 },
+        { 0, 2.5, 33.75, 80.25, 127, 173.75, 220.75, 252.25, 255 }
+    };
+    Mat comp = Mat(9, 9, CV_32F, arComp);
+
+    Mat kernel;
+    ft::createKernel(ft::LINEAR, 2, kernel, 1);
+
+    Mat O;
+    ft::FT02D_inverseFT(comp, kernel, O, 16, 16);
+
+    double n1 = cvtest::norm(demandedO, O, NORM_INF);
+
+    EXPECT_DOUBLE_EQ(n1, 0);
+}
\ No newline at end of file
diff --git a/contrib/modules/fuzzy/test/test_image.cpp b/contrib/modules/fuzzy/test/test_image.cpp
index 7924d2d..fd22e47 100644
--- a/contrib/modules/fuzzy/test/test_image.cpp
+++ b/contrib/modules/fuzzy/test/test_image.cpp
@@ -40,84 +40,75 @@
 //M*/
 
 #include "test_precomp.hpp"
+
 #include <string>
 
 using namespace std;
 using namespace cv;
 
-class CV_FuzzyImageTest : public cvtest::BaseTest
-{
-public:
-    CV_FuzzyImageTest();
-    ~CV_FuzzyImageTest();
-protected:
-    void run(int);
-};
-
-CV_FuzzyImageTest::CV_FuzzyImageTest()
-{
-}
-CV_FuzzyImageTest::~CV_FuzzyImageTest() {}
-
-void CV_FuzzyImageTest::run( int )
+TEST(fuzzy_image, inpainting)
 {
-    string folder = string(ts->get_data_path()) + "fuzzy/";
+    string folder = string(cvtest::TS::ptr()->get_data_path()) + "fuzzy/";
     Mat orig = imread(folder + "orig.png");
     Mat exp1 = imread(folder + "exp1.png");
     Mat exp2 = imread(folder + "exp2.png");
     Mat exp3 = imread(folder + "exp3.png");
-    Mat mask1 = imread(folder + "mask1.png");
-    Mat mask2 = imread(folder + "mask2.png");
-
-    if (orig.empty() || exp1.empty() || exp2.empty() || mask1.empty() || mask2.empty())
-    {
-        ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_TEST_DATA );
-        return;
-    }
+    Mat mask1 = imread(folder + "mask1.png", IMREAD_GRAYSCALE);
+    Mat mask2 = imread(folder + "mask2.png", IMREAD_GRAYSCALE);
 
-    // Conversion because of comparison.
+    EXPECT_TRUE(!orig.empty() && !exp1.empty() && !exp2.empty() && !exp3.empty() && !mask1.empty() && !mask2.empty());
 
-    orig.convertTo(orig, CV_32F);
-    exp1.convertTo(exp1, CV_32F);
-    exp2.convertTo(exp2, CV_32F);
-    exp3.convertTo(exp3, CV_32F);
-
-    Mat res1, res2,res3;
+    Mat res1, res2, res3;
     ft::inpaint(orig, mask1, res1, 2, ft::LINEAR, ft::ONE_STEP);
     ft::inpaint(orig, mask2, res2, 2, ft::LINEAR, ft::MULTI_STEP);
     ft::inpaint(orig, mask2, res3, 2, ft::LINEAR, ft::ITERATIVE);
 
-    Mat diff1, diff2, diff3;
-    absdiff(orig, res1, diff1);
-    absdiff(orig, res2, diff2);
-    absdiff(orig, res3, diff3);
-
-    double n1 = cvtest::norm(diff1.reshape(1), NORM_INF, mask1.reshape(1));
-    double n2 = cvtest::norm(diff2.reshape(1), NORM_INF, mask2.reshape(1));
-    double n3 = cvtest::norm(diff3.reshape(1), NORM_INF, mask2.reshape(1));
-
-    if (n1 != 0 || n2 != 0 || n3 != 0)
-    {
-        ts->set_failed_test_info( cvtest::TS::FAIL_MISMATCH );
-        return;
-    }
-
-    absdiff(exp1, res1, diff1);
-    absdiff(exp2, res2, diff2);
-    absdiff(exp3, res3, diff3);
-
-    n1 = cvtest::norm(diff1.reshape(1), NORM_INF, mask1.reshape(1));
-    n2 = cvtest::norm(diff2.reshape(1), NORM_INF, mask2.reshape(1));
-    n3 = cvtest::norm(diff3.reshape(1), NORM_INF, mask2.reshape(1));
-
-    const int jpeg_thres = 3;
-    if (n1 > jpeg_thres || n2 > jpeg_thres || n3 > jpeg_thres)
-    {
-        ts->set_failed_test_info( cvtest::TS::FAIL_BAD_ACCURACY );
-        return;
-    }
-
-    ts->set_failed_test_info(cvtest::TS::OK);
+    res1.convertTo(res1, CV_8UC3);
+    res2.convertTo(res2, CV_8UC3);
+    res3.convertTo(res3, CV_8UC3);
+
+    double n1 = cvtest::norm(exp1, res1, NORM_INF);
+    double n2 = cvtest::norm(exp2, res2, NORM_INF);
+    double n3 = cvtest::norm(exp3, res3, NORM_INF);
+
+    EXPECT_LE(n1, 1);
+    EXPECT_LE(n2, 1);
+    EXPECT_LE(n3, 1);
+}
+
+TEST(fuzzy_image, filtering)
+{
+    string folder = string(cvtest::TS::ptr()->get_data_path()) + "fuzzy/";
+    Mat orig = imread(folder + "orig.png");
+    Mat exp4 = imread(folder + "exp4.png");
+
+    EXPECT_TRUE(!orig.empty() && !exp4.empty());
+
+    Mat kernel;
+    ft::createKernel(ft::LINEAR, 20, kernel, 3);
+
+    Mat res4;
+    ft::filter(orig, kernel, res4);
+
+    res4.convertTo(res4, CV_8UC3);
+
+    double n1 = cvtest::norm(exp4, res4, NORM_INF);
+
+    EXPECT_LE(n1, 1);
 }
 
-TEST(Fuzzy_image, regression) { CV_FuzzyImageTest test; test.safe_run(); }
+TEST(fuzzy_image, kernel)
+{
+    Mat kernel1;
+    ft::createKernel(ft::LINEAR, 2, kernel1, 1);
+
+    Mat vector1 = (Mat_<float>(5, 1) << 0, 0.5, 1, 0.5, 0);
+    Mat vector2 = (Mat_<float>(1, 5) << 0, 0.5, 1, 0.5, 0);
+
+    Mat kernel2;
+    ft::createKernel(vector1, vector2, kernel2, 1);
+
+    double diff = cvtest::norm(kernel1, kernel2, NORM_INF);
+
+    EXPECT_DOUBLE_EQ(diff, 0);
+}
\ No newline at end of file
diff --git a/contrib/modules/hdf/CMakeLists.txt b/contrib/modules/hdf/CMakeLists.txt
index 9bba8b4..b6bfa49 100644
--- a/contrib/modules/hdf/CMakeLists.txt
+++ b/contrib/modules/hdf/CMakeLists.txt
@@ -1,21 +1,36 @@
 set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR})
 
-find_package(HDF5)
-if(HDF5_FOUND)
-    set(HAVE_HDF5 1)
-    message(STATUS "HDF5:   YES")
+if(WIN32)
+  # windows cmake internal lookups are broken for now
+  # will lookup for headers and shared libs given HDF_DIR env
+  find_path(HDF5_INCLUDE_DIRS hdf5.h HINTS "$ENV{HDF5_DIR}\\..\\include")
+  find_library(HDF5_C_LIBRARY NAMES hdf5 HINTS "$ENV{HDF5_DIR}\\..\\lib")
+  if(HDF5_INCLUDE_DIRS AND HDF5_C_LIBRARY)
+    set(HDF5_FOUND "YES")
+    set(HDF5_LIBRARIES ${HDF5_C_LIBRARY})
+    mark_as_advanced(HDF5_LIBRARIES)
+    mark_as_advanced(HDF5_C_LIBRARY)
+    mark_as_advanced(HDF5_INCLUDE_DIRS)
+    add_definitions(-DH5_BUILT_AS_DYNAMIC_LIB -D_HDF5USEDLL_)
+  else()
+     set(HDF5_FOUND "NO")
+  endif()
 else()
-    ocv_module_disable(hdf)
-    message(STATUS "HDF5:   NO")
+  if(NOT CMAKE_CROSSCOMPILING) # iOS build should not reuse OSX package
+    find_package(HDF5)
+  endif()
 endif()
 
-if(${HDF5_FOUND})
-  include_directories(${HDF5_INCLUDE_DIRS})
+if(NOT HDF5_FOUND)
+    ocv_module_disable(hdf) # no return
 endif()
 
+set(HAVE_HDF5 1)
+
+ocv_warnings_disable(CMAKE_CXX_FLAGS -Winvalid-offsetof)
+
 set(the_description "Hierarchical Data Format I/O")
 ocv_define_module(hdf opencv_core WRAP python)
 
-if(${HDF5_FOUND})
-  target_link_libraries(opencv_hdf ${HDF5_LIBRARIES})
-endif()
+include_directories(${HDF5_INCLUDE_DIRS})
+target_link_libraries(opencv_hdf ${HDF5_LIBRARIES})
diff --git a/contrib/modules/hdf/README.md b/contrib/modules/hdf/README.md
index 92c1a84..8bc1ac3 100644
--- a/contrib/modules/hdf/README.md
+++ b/contrib/modules/hdf/README.md
@@ -1,4 +1,4 @@
-HDF I/O
-============================================================
+Hierarchical Data Format (hdf) I/O
+==================================
 
-The module contains I/O routines for Hierarchical Data Formats.
+The module contains I/O routines for Hierarchical Data Format: https://en.m.wikipedia.org/wiki/Hierarchical_Data_Format meant to store large amounts of data. This module does not implement the specs from scratch, it's a wrapper on top of libhdf5, which should be pre-installed by the user.
diff --git a/contrib/modules/hdf/include/opencv2/hdf/hdf5.hpp b/contrib/modules/hdf/include/opencv2/hdf/hdf5.hpp
index 504cca1..2c6deaa 100644
--- a/contrib/modules/hdf/include/opencv2/hdf/hdf5.hpp
+++ b/contrib/modules/hdf/include/opencv2/hdf/hdf5.hpp
@@ -37,16 +37,12 @@
 
 #include <vector>
 
-#include <hdf5.h>
-
-
-
-using namespace std;
 
 namespace cv
 {
 namespace hdf
 {
+using namespace std;
 
 //! @addtogroup hdf5
 //! @{
@@ -63,7 +59,7 @@ public:
 
     CV_WRAP enum
     {
-      H5_UNLIMITED = -1, H5_NONE = -1, H5_GETDIMS = 100, H5_GETMAXDIMS = 101,
+      H5_UNLIMITED = -1, H5_NONE = -1, H5_GETDIMS = 100, H5_GETMAXDIMS = 101, H5_GETCHUNKDIMS = 102,
     };
 
     virtual ~HDF5() {}
@@ -115,14 +111,19 @@ public:
 
     /* @overload */
     CV_WRAP virtual void dscreate( const int rows, const int cols, const int type,
-                 String dslabel, const int compresslevel = HDF5::H5_NONE,
-                 const vector<int>& dims_chunks = vector<int>() ) const = 0;
+                 String dslabel ) const = 0;
+    /* @overload */
+    CV_WRAP virtual void dscreate( const int rows, const int cols, const int type,
+                 String dslabel, const int compresslevel ) const = 0;
+    /* @overload */
+    CV_WRAP virtual void dscreate( const int rows, const int cols, const int type,
+                 String dslabel, const int compresslevel, const vector<int>& dims_chunks ) const = 0;
     /** @brief Create and allocate storage for two dimensional single or multi channel dataset.
     @param rows declare amount of rows
     @param cols declare amount of cols
     @param type type to be used
     @param dslabel specify the hdf5 dataset label, any existing dataset with the same label will be overwritten.
-    @param compresslevel specify the compression level 0-9 to be used, by default H5_NONE means none at all.
+    @param compresslevel specify the compression level 0-9 to be used, H5_NONE is default and means no compression.
     @param dims_chunks each array member specify chunking sizes to be used for block i/o,
            by default NULL means none at all.
 
@@ -181,17 +182,24 @@ public:
     Multiple datasets inside single hdf5 file is allowed.
      */
     CV_WRAP virtual void dscreate( const int rows, const int cols, const int type,
-                 String dslabel, const int compresslevel = HDF5::H5_NONE, const int* dims_chunks = NULL ) const = 0;
+                 String dslabel, const int compresslevel, const int* dims_chunks ) const = 0;
 
     /* @overload */
-    CV_WRAP virtual void dscreate( const vector<int>& sizes, const int type, String dslabel,
-                 const int compresslevel = HDF5::H5_NONE, const vector<int>& dims_chunks = vector<int>() ) const = 0;
+    CV_WRAP virtual void dscreate( const int n_dims, const int* sizes, const int type,
+                 String dslabel ) const = 0;
+    /* @overload */
+    CV_WRAP virtual void dscreate( const int n_dims, const int* sizes, const int type,
+                 String dslabel, const int compresslevel ) const = 0;
+    /* @overload */
+    CV_WRAP virtual void dscreate( const vector<int>& sizes, const int type,
+                 String dslabel, const int compresslevel = HDF5::H5_NONE,
+                 const vector<int>& dims_chunks = vector<int>() ) const = 0;
     /** @brief Create and allocate storage for n-dimensional dataset, single or mutichannel type.
     @param n_dims declare number of dimensions
     @param sizes array containing sizes for each dimensions
     @param type type to be used
     @param dslabel specify the hdf5 dataset label, any existing dataset with the same label will be overwritten.
-    @param compresslevel specify the compression level 0-9 to be used, by default H5_NONE means none at all.
+    @param compresslevel specify the compression level 0-9 to be used, H5_NONE is default and means no compression.
     @param dims_chunks each array member specify chunking sizes to be used for block i/o,
            by default NULL means none at all.
     @note If the dataset already exists an exception will be thrown. Existence of the dataset can be checked
@@ -254,7 +262,7 @@ public:
     @endcode
      */
     CV_WRAP virtual void dscreate( const int n_dims, const int* sizes, const int type,
-                 String dslabel, const int compresslevel = HDF5::H5_NONE, const int* dims_chunks = NULL ) const = 0;
+                 String dslabel, const int compresslevel, const int* dims_chunks ) const = 0;
 
     /** @brief Fetch dataset sizes
     @param dslabel specify the hdf5 dataset label to be measured.
@@ -266,7 +274,9 @@ public:
     actual dataset dimensions. Using H5_GETMAXDIM flag will get maximum allowed dimension which normally match
     actual dataset dimension but can hold H5_UNLIMITED value if dataset was prepared in **unlimited** mode on
     some of its dimension. It can be useful to check existing dataset dimensions before overwrite it as whole or subset.
-    Trying to write with oversized source data into dataset target will thrown exception.
+    Trying to write with oversized source data into dataset target will thrown exception. The H5_GETCHUNKDIMS will
+    return the dimension of chunk if dataset was created with chunking options otherwise returned vector size
+    will be zero.
      */
     CV_WRAP virtual vector<int> dsgetsize( String dslabel, int dims_flag = HDF5::H5_GETDIMS ) const = 0;
 
@@ -282,8 +292,13 @@ public:
     CV_WRAP virtual int dsgettype( String dslabel ) const = 0;
 
     /* @overload */
+    CV_WRAP virtual void dswrite( InputArray Array, String dslabel ) const = 0;
+    /* @overload */
+    CV_WRAP virtual void dswrite( InputArray Array, String dslabel,
+                 const int* dims_offset ) const = 0;
+    /* @overload */
     CV_WRAP virtual void dswrite( InputArray Array, String dslabel,
-                 const vector<int>& dims_offset = vector<int>(),
+                 const vector<int>& dims_offset,
                  const vector<int>& dims_counts = vector<int>() ) const = 0;
     /** @brief Write or overwrite a Mat object into specified dataset of hdf5 file.
     @param Array specify Mat data array to be written.
@@ -348,11 +363,16 @@ public:
     @endcode
      */
     CV_WRAP virtual void dswrite( InputArray Array, String dslabel,
-                 const int* dims_offset = NULL, const int* dims_counts = NULL ) const = 0;
+                 const int* dims_offset, const int* dims_counts ) const = 0;
 
     /* @overload */
-    CV_WRAP virtual void dsinsert( InputArray Array, String dslabel,
-                 const vector<int>& dims_offset = vector<int>(),
+    CV_WRAP virtual void dsinsert( InputArray Array, String dslabel ) const = 0;
+    /* @overload */
+    CV_WRAP virtual void dsinsert( InputArray Array,
+                 String dslabel, const int* dims_offset ) const = 0;
+    /* @overload */
+    CV_WRAP virtual void dsinsert( InputArray Array,
+                 String dslabel, const vector<int>& dims_offset,
                  const vector<int>& dims_counts = vector<int>() ) const = 0;
     /** @brief Insert or overwrite a Mat object into specified dataset and autoexpand dataset size if **unlimited** property allows.
     @param Array specify Mat data array to be written.
@@ -402,12 +422,17 @@ public:
     @endcode
      */
     CV_WRAP virtual void dsinsert( InputArray Array, String dslabel,
-                 const int* dims_offset = NULL, const int* dims_counts = NULL ) const = 0;
+                 const int* dims_offset, const int* dims_counts ) const = 0;
 
 
     /* @overload */
+    CV_WRAP virtual void dsread( OutputArray Array, String dslabel ) const = 0;
+    /* @overload */
+    CV_WRAP virtual void dsread( OutputArray Array,
+                 String dslabel, const int* dims_offset ) const = 0;
+    /* @overload */
     CV_WRAP virtual void dsread( OutputArray Array, String dslabel,
-                 const vector<int>& dims_offset = vector<int>(),
+                 const vector<int>& dims_offset,
                  const vector<int>& dims_counts = vector<int>() ) const = 0;
     /** @brief Read specific dataset from hdf5 file into Mat object.
     @param Array Mat container where data reads will be returned.
@@ -449,7 +474,7 @@ public:
     @endcode
      */
     CV_WRAP virtual void dsread( OutputArray Array, String dslabel,
-                 const int* dims_offset = NULL, const int* dims_counts = NULL ) const = 0;
+                 const int* dims_offset, const int* dims_counts ) const = 0;
 
     /** @brief Fetch keypoint dataset size
     @param kplabel specify the hdf5 dataset label to be measured.
@@ -461,16 +486,17 @@ public:
     Using H5_GETMAXDIM flag will get maximum allowed dimension which normally match actual dataset dimension but can hold
     H5_UNLIMITED value if dataset was prepared in **unlimited** mode. It can be useful to check existing dataset dimension
     before overwrite it as whole or subset. Trying to write with oversized source data into dataset target will thrown
-    exception.
+    exception. The H5_GETCHUNKDIMS will return the dimension of chunk if dataset was created with chunking options otherwise
+    returned vector size will be zero.
      */
     CV_WRAP virtual int kpgetsize( String kplabel, int dims_flag = HDF5::H5_GETDIMS ) const = 0;
 
     /** @brief Create and allocate special storage for cv::KeyPoint dataset.
     @param size declare fixed number of KeyPoints
     @param kplabel specify the hdf5 dataset label, any existing dataset with the same label will be overwritten.
-    @param compresslevel specify the compression level 0-9 to be used, by default H5_NONE means none at all.
+    @param compresslevel specify the compression level 0-9 to be used, H5_NONE is default and means no compression.
     @param chunks each array member specify chunking sizes to be used for block i/o,
-           by default H5_NONE means none at all.
+           H5_NONE is default and means no compression.
     @note If the dataset already exists an exception will be thrown. Existence of the dataset can be checked
     using hlexists().
 
diff --git a/contrib/modules/hdf/src/hdf5.cpp b/contrib/modules/hdf/src/hdf5.cpp
index 6e0fb52..1886574 100644
--- a/contrib/modules/hdf/src/hdf5.cpp
+++ b/contrib/modules/hdf/src/hdf5.cpp
@@ -34,7 +34,7 @@
 
 #include "precomp.hpp"
 
-
+#include <hdf5.h>
 
 using namespace std;
 
@@ -75,52 +75,81 @@ public:
     // get sizes of dataset
     virtual vector<int> dsgetsize( String dslabel, int dims_flag = H5_GETDIMS ) const;
 
-    // get data type of dataset
+    /* get data type of dataset */
     virtual int dsgettype( String dslabel ) const;
 
-    // overload dscreate()
-    virtual void dscreate( const int rows, const int cols, const int type,
-             String dslabel, const int compresslevel = H5_NONE,
-             const vector<int>& dims_chunks = vector<int>() ) const;
+    // overload dscreate() #1
+    virtual void dscreate( const int rows, const int cols, const int type, String dslabel ) const;
+
+    // overload dscreate() #2
+    virtual void dscreate( const int rows, const int cols, const int type, String dslabel,
+             const int compresslevel ) const;
+
+    // overload dscreate() #3
+    virtual void dscreate( const int rows, const int cols, const int type, String dslabel,
+             const int compresslevel, const vector<int>& dims_chunks ) const;
+
+    /* create two dimensional single or mutichannel dataset */
+    virtual void dscreate( const int rows, const int cols, const int type, String dslabel,
+             const int compresslevel, const int* dims_chunks ) const;
+
+    // overload dscreate() #1
+    virtual void dscreate( const int n_dims, const int* sizes, const int type,
+             String dslabel ) const;
 
-    // create two dimensional single or mutichannel dataset
-    virtual void dscreate( const int rows, const int cols, const int type,
-             String dslabel, const int compresslevel = H5_NONE, const int* dims_chunks = NULL ) const;
+    // overload dscreate() #2
+    virtual void dscreate( const int n_dims, const int* sizes, const int type,
+             String dslabel, const int compresslevel ) const;
 
-    // overload dscreate()
+    // overload dscreate() #3
     virtual void dscreate( const vector<int>& sizes, const int type, String dslabel,
              const int compresslevel = H5_NONE, const vector<int>& dims_chunks = vector<int>() ) const;
 
-    // create n-dimensional single or mutichannel dataset
+    /* create n-dimensional single or mutichannel dataset */
     virtual void dscreate( const int n_dims, const int* sizes, const int type,
-             String dslabel, const int compresslevel = H5_NONE, const int* dims_chunks = NULL ) const;
+             String dslabel, const int compresslevel, const int* dims_chunks ) const;
 
-    // overload dswrite()
-    virtual void dswrite( InputArray Array, String dslabel,
-             const vector<int>& dims_offset = vector<int>(),
+    // overload dswrite() #1
+    virtual void dswrite( InputArray Array, String dslabel ) const;
+
+    // overload dswrite() #2
+    virtual void dswrite( InputArray Array, String dslabel, const int* dims_offset ) const;
+
+    // overload dswrite() #3
+    virtual void dswrite( InputArray Array, String dslabel, const vector<int>& dims_offset,
              const vector<int>& dims_counts = vector<int>() ) const;
 
-    // write into dataset
+    /* write into dataset */
     virtual void dswrite( InputArray Array, String dslabel,
-             const int* dims_offset = NULL, const int* dims_counts = NULL ) const;
+             const int* dims_offset, const int* dims_counts ) const;
 
-    // overload dsinsert()
+    // overload dsinsert() #1
+    virtual void dsinsert( InputArray Array, String dslabel ) const;
+
+    // overload dsinsert() #2
+    virtual void dsinsert( InputArray Array, String dslabel, const int* dims_offset ) const;
+
+    // overload dsinsert() #3
     virtual void dsinsert( InputArray Array, String dslabel,
-             const vector<int>& dims_offset = vector<int>(),
-             const vector<int>& dims_counts = vector<int>() ) const;
+             const vector<int>& dims_offset, const vector<int>& dims_counts = vector<int>() ) const;
 
-    // append / merge into dataset
+    /* append / merge into dataset */
     virtual void dsinsert( InputArray Array, String dslabel,
              const int* dims_offset = NULL, const int* dims_counts = NULL ) const;
 
-    // overload dsread()
+    // overload dsread() #1
+    virtual void dsread( OutputArray Array, String dslabel ) const;
+
+    // overload dsread() #2
+    virtual void dsread( OutputArray Array, String dslabel, const int* dims_offset ) const;
+
+    // overload dsread() #3
     virtual void dsread( OutputArray Array, String dslabel,
-             const vector<int>& dims_offset = vector<int>(),
-             const vector<int>& dims_counts = vector<int>() ) const;
+             const vector<int>& dims_offset, const vector<int>& dims_counts = vector<int>() ) const;
 
     // read from dataset
     virtual void dsread( OutputArray Array, String dslabel,
-             const int* dims_offset = NULL, const int* dims_counts = NULL ) const;
+             const int* dims_offset, const int* dims_counts ) const;
 
     /*
      *  std::vector<cv::KeyPoint>
@@ -237,14 +266,16 @@ HDF5Impl::HDF5Impl( String _hdf5_filename )
     // restore previous error handler
     H5Eset_auto( stackid, errfunc, errdata );
 
-    if ( check == 1 )
+    if ( check == 1 || check == 0 )
       // open the HDF5 file
       m_h5_file_id = H5Fopen( m_hdf5_filename.c_str(),
                             H5F_ACC_RDWR, H5P_DEFAULT );
-    else
-      // create the HDF5 file
+    else if ( check == -1 )
+      // file does not exist
       m_h5_file_id = H5Fcreate( m_hdf5_filename.c_str(),
                      H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT );
+    else
+      CV_Error( Error::StsInternal, "Unknown file state." );
 }
 
 void HDF5Impl::close()
@@ -253,8 +284,6 @@ void HDF5Impl::close()
       H5Fclose( m_h5_file_id );
     // mark closed
     m_h5_file_id = -1;
-
-    H5close( );
 }
 
 /*
@@ -299,21 +328,47 @@ vector<int> HDF5Impl::dsgetsize( String dslabel, int dims_flag ) const
     // fetch rank
     int n_dims = H5Sget_simple_extent_ndims( fspace );
 
+    // dims storage
+    hsize_t *dims = new hsize_t[n_dims];
+
+    // output storage
+    vector<int> SizeVect(0);
+
     // fetch dims
-    hsize_t dsdims[n_dims];
-    if ( dims_flag == H5_GETDIMS )
-      H5Sget_simple_extent_dims( fspace, dsdims, NULL );
+    if ( dims_flag == H5_GETDIMS ||
+         dims_flag == H5_GETMAXDIMS )
+    {
+      if ( dims_flag == H5_GETDIMS )
+        H5Sget_simple_extent_dims( fspace, dims, NULL );
+      else
+        H5Sget_simple_extent_dims( fspace, NULL, dims );
+      SizeVect.resize( n_dims );
+    }
+    else if ( dims_flag == H5_GETCHUNKDIMS )
+    {
+      // rank size
+      int rank_chunk = -1;
+      // fetch chunk size
+      hid_t cparms = H5Dget_create_plist( dsdata );
+      if ( H5D_CHUNKED == H5Pget_layout ( cparms ) )
+      {
+         rank_chunk = H5Pget_chunk ( cparms, n_dims, dims );
+      }
+      if ( rank_chunk > 0 )
+        SizeVect.resize( n_dims );
+    }
     else
-      H5Sget_simple_extent_dims( fspace, NULL, dsdims );
+      CV_Error( Error::StsInternal, "Unknown dimension flag." );
 
     // fill with size data
-    vector<int> SizeVect( n_dims );
-    for ( int d = 0; d < n_dims; d++ )
-      SizeVect[d] = (int) dsdims[d];
+    for ( size_t d = 0; d < SizeVect.size(); d++ )
+      SizeVect[d] = (int) dims[d];
 
     H5Dclose( dsdata );
     H5Sclose( fspace );
 
+    delete [] dims;
+
     return SizeVect;
 }
 
@@ -333,7 +388,7 @@ int HDF5Impl::dsgettype( String dslabel ) const
       // fetch channs
       hsize_t ardims[1];
       H5Tget_array_dims( dstype, ardims );
-      channs = ardims[0];
+      channs = (int)ardims[0];
       // fetch depth
       hid_t tsuper = H5Tget_super( dstype );
       h5type = H5Tget_native_type( tsuper, H5T_DIR_ASCEND );
@@ -353,11 +408,33 @@ int HDF5Impl::dsgettype( String dslabel ) const
 
 // overload
 void HDF5Impl::dscreate( const int rows, const int cols, const int type,
+                         String dslabel ) const
+{
+    // dataset dims
+    int dsizes[2] = { rows, cols };
+
+    // create the two dim array
+    dscreate( 2, dsizes, type, dslabel, HDF5::H5_NONE, NULL );
+}
+
+// overload
+void HDF5Impl::dscreate( const int rows, const int cols, const int type,
+                         String dslabel, const int compresslevel ) const
+{
+    // dataset dims
+    int dsizes[2] = { rows, cols };
+
+    // create the two dim array
+    dscreate( 2, dsizes, type, dslabel, compresslevel, NULL );
+}
+
+// overload
+void HDF5Impl::dscreate( const int rows, const int cols, const int type,
                  String dslabel, const int compresslevel,
                  const vector<int>& dims_chunks ) const
 {
-    CV_Assert( &dims_chunks[0] == NULL || dims_chunks.size() == 2 );
-    dscreate( rows, cols, type, dslabel, compresslevel, &dims_chunks[0] );
+    CV_Assert( dims_chunks.empty() || dims_chunks.size() == 2 );
+    dscreate( rows, cols, type, dslabel, compresslevel, dims_chunks.empty() ? NULL : &(dims_chunks[0]) );
 }
 
 void HDF5Impl::dscreate( const int rows, const int cols, const int type,
@@ -371,14 +448,28 @@ void HDF5Impl::dscreate( const int rows, const int cols, const int type,
 }
 
 // overload
+void HDF5Impl::dscreate( const int n_dims, const int* sizes, const int type,
+                 String dslabel ) const
+{
+    dscreate( n_dims, sizes, type, dslabel, H5_NONE, NULL );
+}
+
+// overload
+void HDF5Impl::dscreate( const int n_dims, const int* sizes, const int type,
+                 String dslabel, const int compresslevel ) const
+{
+    dscreate( n_dims, sizes, type, dslabel, compresslevel, NULL );
+}
+
+// overload
 void HDF5Impl::dscreate( const vector<int>& sizes, const int type,
                  String dslabel, const int compresslevel,
                  const vector<int>& dims_chunks ) const
 {
-    CV_Assert( &dims_chunks[0] == NULL || dims_chunks.size() == sizes.size() );
+    CV_Assert( dims_chunks.empty() || dims_chunks.size() == sizes.size() );
 
     const int n_dims = (int) sizes.size();
-    dscreate( n_dims, &sizes[0], type, dslabel, compresslevel, &dims_chunks[0] );
+    dscreate( n_dims, &sizes[0], type, dslabel, compresslevel, dims_chunks.empty() ? NULL : &(dims_chunks[0]) );
 }
 
 void HDF5Impl::dscreate( const int n_dims, const int* sizes, const int type,
@@ -392,9 +483,9 @@ void HDF5Impl::dscreate( const int n_dims, const int* sizes, const int type,
 
     int channs = CV_MAT_CN( type );
 
-    hsize_t chunks[n_dims];
-    hsize_t dsdims[n_dims];
-    hsize_t maxdim[n_dims];
+    hsize_t *chunks = new hsize_t[n_dims];
+    hsize_t *dsdims = new hsize_t[n_dims];
+    hsize_t *maxdim = new hsize_t[n_dims];
 
     // dimension space
     for ( int d = 0; d < n_dims; d++ )
@@ -440,19 +531,37 @@ void HDF5Impl::dscreate( const int n_dims, const int* sizes, const int type,
     // expand channs
     if ( channs > 1 )
     {
-      hsize_t adims[1] = { channs };
+      hsize_t adims[1] = { (hsize_t)channs };
       dstype = H5Tarray_create( dstype, 1, adims );
     }
 
     // create data
-    H5Dcreate( m_h5_file_id, dslabel.c_str(), dstype,
+    hid_t dsdata = H5Dcreate( m_h5_file_id, dslabel.c_str(), dstype,
                dspace, H5P_DEFAULT, dsdcpl, H5P_DEFAULT );
 
     if ( channs > 1 )
       H5Tclose( dstype );
 
+    delete [] chunks;
+    delete [] dsdims;
+    delete [] maxdim;
+
     H5Pclose( dsdcpl );
     H5Sclose( dspace );
+    H5Dclose( dsdata );
+}
+
+// overload
+void HDF5Impl::dsread( OutputArray Array, String dslabel ) const
+{
+    dsread( Array, dslabel, NULL, NULL );
+}
+
+// overload
+void HDF5Impl::dsread( OutputArray Array, String dslabel,
+             const int* dims_offset ) const
+{
+    dsread( Array, dslabel, dims_offset, NULL );
 }
 
 // overload
@@ -483,7 +592,7 @@ void HDF5Impl::dsread( OutputArray Array, String dslabel,
       // fetch channs
       hsize_t ardims[1];
       H5Tget_array_dims( dstype, ardims );
-      channs = ardims[0];
+      channs = (int) ardims[0];
       // fetch depth
       hid_t tsuper = H5Tget_super( dstype );
       h5type = H5Tget_native_type( tsuper, H5T_DIR_ASCEND );
@@ -500,7 +609,7 @@ void HDF5Impl::dsread( OutputArray Array, String dslabel,
     int n_dims = H5Sget_simple_extent_ndims( fspace );
 
     // fetch dims
-    hsize_t dsdims[n_dims];
+    hsize_t *dsdims = new hsize_t[n_dims];
     H5Sget_simple_extent_dims( fspace, dsdims, NULL );
 
     // set amount by custom offset
@@ -518,8 +627,8 @@ void HDF5Impl::dsread( OutputArray Array, String dslabel,
     }
 
     // get memory write window
-    int mxdims[n_dims];
-    hsize_t foffset[n_dims];
+    int *mxdims = new int[n_dims];
+    hsize_t *foffset = new hsize_t[n_dims];
     for ( int d = 0; d < n_dims; d++ )
     {
       foffset[d] = 0;
@@ -551,6 +660,11 @@ void HDF5Impl::dsread( OutputArray Array, String dslabel,
     Mat matrix = Array.getMat();
     H5Dread( dsdata, dstype, dspace, fspace, H5P_DEFAULT, matrix.data );
 
+    delete [] dsdims;
+    delete [] mxdims;
+    delete [] foffset;
+
+    H5Tclose (h5type );
     H5Tclose( dstype );
     H5Sclose( dspace );
     H5Sclose( fspace );
@@ -558,6 +672,17 @@ void HDF5Impl::dsread( OutputArray Array, String dslabel,
 }
 
 // overload
+void HDF5Impl::dswrite( InputArray Array, String dslabel ) const
+{
+    dswrite( Array, dslabel, NULL, NULL );
+}
+// overload
+void HDF5Impl::dswrite( InputArray Array, String dslabel,
+             const int* dims_offset ) const
+{
+    dswrite( Array, dslabel, dims_offset, NULL );
+}
+// overload
 void HDF5Impl::dswrite( InputArray Array, String dslabel,
              const vector<int>& dims_offset,
              const vector<int>& dims_counts ) const
@@ -579,9 +704,9 @@ void HDF5Impl::dswrite( InputArray Array, String dslabel,
     int n_dims = matrix.dims;
     int channs = matrix.channels();
 
-    int dsizes[n_dims];
-    hsize_t dsdims[n_dims];
-    hsize_t offset[n_dims];
+    int *dsizes = new int[n_dims];
+    hsize_t *dsdims = new hsize_t[n_dims];
+    hsize_t *offset = new hsize_t[n_dims];
     // replicate Mat dimensions
     for ( int d = 0; d < n_dims; d++ )
     {
@@ -625,7 +750,7 @@ void HDF5Impl::dswrite( InputArray Array, String dslabel,
     // expand channs
     if ( matrix.channels() > 1 )
     {
-      hsize_t adims[1] = { channs };
+      hsize_t adims[1] = { (hsize_t)channs };
       dstype = H5Tarray_create( dstype, 1, adims );
     }
 
@@ -636,12 +761,29 @@ void HDF5Impl::dswrite( InputArray Array, String dslabel,
     if ( matrix.channels() > 1 )
       H5Tclose( dstype );
 
+    delete [] dsizes;
+    delete [] dsdims;
+    delete [] offset;
+
     H5Sclose( dspace );
     H5Sclose( fspace );
     H5Dclose( dsdata );
 }
 
 // overload
+void HDF5Impl::dsinsert( InputArray Array, String dslabel ) const
+{
+    dsinsert( Array, dslabel, NULL, NULL );
+}
+
+// overload
+void HDF5Impl::dsinsert( InputArray Array, String dslabel,
+             const int* dims_offset ) const
+{
+    dsinsert( Array, dslabel, dims_offset, NULL );
+}
+
+// overload
 void HDF5Impl::dsinsert( InputArray Array, String dslabel,
              const vector<int>& dims_offset,
              const vector<int>& dims_counts ) const
@@ -667,8 +809,8 @@ void HDF5Impl::dsinsert( InputArray Array, String dslabel,
     int n_dims = matrix.dims;
     int channs = matrix.channels();
 
-    hsize_t dsdims[n_dims];
-    hsize_t offset[n_dims];
+    hsize_t *dsdims = new hsize_t[n_dims];
+    hsize_t *offset = new hsize_t[n_dims];
     // replicate Mat dimensions
     for ( int d = 0; d < n_dims; d++ )
     {
@@ -702,14 +844,14 @@ void HDF5Impl::dsinsert( InputArray Array, String dslabel,
     // get actual file space and dims
     hid_t fspace = H5Dget_space( dsdata );
     int f_dims = H5Sget_simple_extent_ndims( fspace );
-    hsize_t fsdims[f_dims];
+    hsize_t *fsdims = new hsize_t[f_dims];
     H5Sget_simple_extent_dims( fspace, fsdims, NULL );
     H5Sclose( fspace );
 
     CV_Assert( f_dims == n_dims );
 
     // compute new extents
-    hsize_t nwdims[n_dims];
+    hsize_t *nwdims = new hsize_t[n_dims];
     for ( int d = 0; d < n_dims; d++ )
     {
       // init
@@ -743,7 +885,7 @@ void HDF5Impl::dsinsert( InputArray Array, String dslabel,
     // expand channs
     if ( matrix.channels() > 1 )
     {
-      hsize_t adims[1] = { channs };
+      hsize_t adims[1] = { (hsize_t)channs };
       dstype = H5Tarray_create( dstype, 1, adims );
     }
 
@@ -754,6 +896,11 @@ void HDF5Impl::dsinsert( InputArray Array, String dslabel,
     if ( matrix.channels() > 1 )
       H5Tclose( dstype );
 
+    delete [] dsdims;
+    delete [] offset;
+    delete [] fsdims;
+    delete [] nwdims;
+
     H5Sclose( dspace );
     H5Sclose( fspace );
     H5Dclose( dsdata );
@@ -850,16 +997,18 @@ void HDF5Impl::kpwrite( const vector<KeyPoint> keypoints, String kplabel,
 {
     CV_Assert( keypoints.size() > 0 );
 
+    int dskdims[1];
     hsize_t dsddims[1];
     hsize_t doffset[1];
 
     // replicate vector dimension
     doffset[0] = 0;
     dsddims[0] = keypoints.size();
+    dskdims[0] = (int)keypoints.size();
 
     // pre-create dataset if needed
     if ( hlexists( kplabel ) == false )
-      kpcreate( dsddims[0], kplabel );
+      kpcreate( dskdims[0], kplabel );
 
     // set custom amount of data
     if ( counts != H5_NONE )
@@ -932,7 +1081,7 @@ void HDF5Impl::kpinsert( const vector<KeyPoint> keypoints, String kplabel,
     // get actual file space and dims
     hid_t fspace = H5Dget_space( dsdata );
     int f_dims = H5Sget_simple_extent_ndims( fspace );
-    hsize_t fsdims[f_dims];
+    hsize_t *fsdims = new hsize_t[f_dims];
     H5Sget_simple_extent_dims( fspace, fsdims, NULL );
     H5Sclose( fspace );
 
@@ -975,6 +1124,8 @@ void HDF5Impl::kpinsert( const vector<KeyPoint> keypoints, String kplabel,
     // write into dataset
     H5Dwrite( dsdata, mmtype, dspace, fspace, H5P_DEFAULT, &keypoints[0] );
 
+    delete [] fsdims;
+
     H5Tclose( mmtype );
     H5Sclose( dspace );
     H5Sclose( fspace );
diff --git a/contrib/modules/line_descriptor/README.md b/contrib/modules/line_descriptor/README.md
index 6028de0..2ef30b0 100644
--- a/contrib/modules/line_descriptor/README.md
+++ b/contrib/modules/line_descriptor/README.md
@@ -1,2 +1,4 @@
-Binary descriptors for lines extracted from an image
-====================================================
\ No newline at end of file
+Binary Descriptors for Line Segments
+====================================
+
+This module shows how to extract line segments from an image by 2 different methods: First segmenting lines with Line Segment Detector LSDDetector and then (or just) using the Binary Descriptor to get the lines and give them a descriptor -- BinaryDescriptor. Finally, we can then match line segments using the BinaryDescriptorMatcher class.
diff --git a/contrib/modules/line_descriptor/include/opencv2/line_descriptor/descriptor.hpp b/contrib/modules/line_descriptor/include/opencv2/line_descriptor/descriptor.hpp
index 65c4395..9f2c639 100644
--- a/contrib/modules/line_descriptor/include/opencv2/line_descriptor/descriptor.hpp
+++ b/contrib/modules/line_descriptor/include/opencv2/line_descriptor/descriptor.hpp
@@ -1095,7 +1095,7 @@ class BucketGroup
 
 public:
 /** constructor */
-BucketGroup();
+BucketGroup(bool needAllocateGroup = true);
 
 /** destructor */
 ~BucketGroup();
@@ -1126,7 +1126,7 @@ private:
 static const int MAX_B;
 
 /** Bins (each bin is an Array object for duplicates of the same key) */
-BucketGroup *table;
+std::vector<BucketGroup> table;
 
 public:
 
@@ -1172,12 +1172,15 @@ length = 0;
 /** constructor setting sequence's length */
 bitarray( UINT64 _bits )
 {
+arr = NULL;
 init( _bits );
 }
 
 /** initializer of private fields */
 void init( UINT64 _bits )
 {
+if( arr )
+delete[] arr;
 length = (UINT32) ceil( _bits / 32.00 );
 arr = new UINT32[length];
 erase();
@@ -1248,13 +1251,13 @@ UINT64 N;
 cv::Mat codes;
 
 /** Counter for eliminating duplicate results (it is not thread safe) */
-bitarray *counter;
+Ptr<bitarray> counter;
 
 /** Array of m hashtables */
-SparseHashtable *H;
+std::vector<SparseHashtable> H;
 
 /** Volume of a b-bit Hamming ball with radius s (for s = 0 to d) */
-UINT32 *xornum;
+std::vector<UINT32> xornum;
 
 /** Used within generation of binary codes at a certain Hamming distance */
 int power[100];
@@ -1293,7 +1296,7 @@ Mat descriptorsMat;
 std::map<int, int> indexesMap;
 
 /** internal MiHaser representing dataset */
-Mihasher* dataset;
+Ptr<Mihasher> dataset;
 
 /** index from which next added descriptors' bunch must begin */
 int nextAddedIndex;
diff --git a/contrib/modules/line_descriptor/perf/perf_matching.cpp b/contrib/modules/line_descriptor/perf/perf_matching.cpp
index 139e3d4..1f5a7c0 100644
--- a/contrib/modules/line_descriptor/perf/perf_matching.cpp
+++ b/contrib/modules/line_descriptor/perf/perf_matching.cpp
@@ -101,7 +101,7 @@ uchar invertSingleBits( uchar dividend_char, int numBits )
   /* reconvert to decimal */
   uchar result = 0;
   for ( int i = (int) bin_vector.size() - 1; i >= 0; i-- )
-    result += (uchar) ( bin_vector[i] * pow( 2, i ) );
+    result += (uchar) ( bin_vector[i] * ( 1 << i ) );
 
   return result;
 }
diff --git a/contrib/modules/line_descriptor/samples/knn_matching.cpp b/contrib/modules/line_descriptor/samples/knn_matching.cpp
index 3618133..a59b6ca 100644
--- a/contrib/modules/line_descriptor/samples/knn_matching.cpp
+++ b/contrib/modules/line_descriptor/samples/knn_matching.cpp
@@ -111,7 +111,7 @@ uchar invertSingleBits( uchar dividend_char, int numBits )
   /* reconvert to decimal */
   uchar result = 0;
   for ( int i = (int) bin_vector.size() - 1; i >= 0; i-- )
-    result += (uchar) ( bin_vector[i] * pow( 2, i ) );
+    result += (uchar) ( bin_vector[i] * (1 << i) );
 
   return result;
 }
diff --git a/contrib/modules/line_descriptor/src/LSDDetector.cpp b/contrib/modules/line_descriptor/src/LSDDetector.cpp
index de4e784..c511ef6 100644
--- a/contrib/modules/line_descriptor/src/LSDDetector.cpp
+++ b/contrib/modules/line_descriptor/src/LSDDetector.cpp
@@ -104,7 +104,7 @@ inline void checkLineExtremes( cv::Vec4f& extremes, cv::Size imageSize )
 void LSDDetector::detect( const Mat& image, CV_OUT std::vector<KeyLine>& keylines, int scale, int numOctaves, const Mat& mask )
 {
   if( mask.data != NULL && ( mask.size() != image.size() || mask.type() != CV_8UC1 ) )
-    throw std::runtime_error( "Mask error while detecting lines: please check its dimensions and that data type is CV_8UC1" );
+    CV_Error( Error::StsBadArg, "Mask error while detecting lines: please check its dimensions and that data type is CV_8UC1" );
 
   else
     detectImpl( image, keylines, numOctaves, scale, mask );
@@ -118,7 +118,7 @@ void LSDDetector::detect( const std::vector<Mat>& images, std::vector<std::vecto
   for ( size_t counter = 0; counter < images.size(); counter++ )
   {
     if( masks[counter].data != NULL && ( masks[counter].size() != images[counter].size() || masks[counter].type() != CV_8UC1 ) )
-      throw std::runtime_error( "Masks error while detecting lines: please check their dimensions and that data types are CV_8UC1" );
+      CV_Error( Error::StsBadArg, "Masks error while detecting lines: please check their dimensions and that data types are CV_8UC1" );
 
     else
       detectImpl( images[counter], keylines[counter], numOctaves, scale, masks[counter] );
@@ -136,7 +136,7 @@ void LSDDetector::detectImpl( const Mat& imageSrc, std::vector<KeyLine>& keyline
 
   /*check whether image depth is different from 0 */
   if( image.depth() != 0 )
-    throw std::runtime_error( "Error, depth image!= 0" );
+    CV_Error( Error::BadDepth, "Error, depth image!= 0" );
 
   /* create a pointer to self */
   LSDDetector *lsd = const_cast<LSDDetector*>( this );
diff --git a/contrib/modules/line_descriptor/src/binary_descriptor.cpp b/contrib/modules/line_descriptor/src/binary_descriptor.cpp
index 16f1249..a7364da 100644
--- a/contrib/modules/line_descriptor/src/binary_descriptor.cpp
+++ b/contrib/modules/line_descriptor/src/binary_descriptor.cpp
@@ -338,11 +338,11 @@ int BinaryDescriptor::descriptorSize() const
 static inline int get2Pow( int i )
 {
   if( i >= 0 && i <= 7 )
-    return (int) pow( 2, (double) i );
-
+    return 1 << i;
   else
   {
-    throw std::runtime_error( "Invalid power argument" );
+    CV_Error( Error::StsBadArg, "Invalid power argument" );
+    return -1;
   }
 }
 
@@ -421,7 +421,7 @@ void BinaryDescriptor::detect( const Mat& image, CV_OUT std::vector<KeyLine>& ke
   }
 
   if( mask.data != NULL && ( mask.size() != image.size() || mask.type() != CV_8UC1 ) )
-  throw std::runtime_error( "Mask error while detecting lines: please check its dimensions and that data type is CV_8UC1" );
+    CV_Error( Error::StsBadArg, "Mask error while detecting lines: please check its dimensions and that data type is CV_8UC1" );
 
   else
   detectImpl( image, keylines, mask );
@@ -441,7 +441,7 @@ void BinaryDescriptor::detect( const std::vector<Mat>& images, std::vector<std::
   for ( size_t counter = 0; counter < images.size(); counter++ )
   {
     if( masks[counter].data != NULL && ( masks[counter].size() != images[counter].size() || masks[counter].type() != CV_8UC1 ) )
-      throw std::runtime_error( "Masks error while detecting lines: please check their dimensions and that data types are CV_8UC1" );
+      CV_Error( Error::StsBadArg, "Mask error while detecting lines: please check its dimensions and that data type is CV_8UC1" );
 
     else
       detectImpl( images[counter], keylines[counter], masks[counter] );
@@ -461,7 +461,7 @@ void BinaryDescriptor::detectImpl( const Mat& imageSrc, std::vector<KeyLine>& ke
 
   /*check whether image depth is different from 0 */
   if( image.depth() != 0 )
-    throw std::runtime_error( "Warning, depth image!= 0" );
+    CV_Error( Error::BadDepth, "Warning, depth image!= 0" );
 
   /* create a pointer to self */
   BinaryDescriptor *bn = const_cast<BinaryDescriptor*>( this );
@@ -511,7 +511,15 @@ void BinaryDescriptor::detectImpl( const Mat& imageSrc, std::vector<KeyLine>& ke
   {
     for ( size_t keyCounter = 0; keyCounter < keylines.size(); keyCounter++ )
     {
-      KeyLine kl = keylines[keyCounter];
+      KeyLine& kl = keylines[keyCounter];
+
+      //due to imprecise floating point scaling in the pyramid a little overflow can occur in line coordinates,
+      //especially on big images. It will be fixed here
+      kl.startPointX = (float)std::min((int)kl.startPointX, mask.cols - 1);
+      kl.startPointY = (float)std::min((int)kl.startPointY, mask.rows - 1);
+      kl.endPointX = (float)std::min((int)kl.endPointX, mask.cols - 1);
+      kl.endPointY = (float)std::min((int)kl.endPointY, mask.rows - 1);
+
       if( mask.at < uchar > ( (int) kl.startPointY, (int) kl.startPointX ) == 0 && mask.at < uchar > ( (int) kl.endPointY, (int) kl.endPointX ) == 0 )
         keylines.erase( keylines.begin() + keyCounter );
     }
@@ -547,7 +555,7 @@ void BinaryDescriptor::computeImpl( const Mat& imageSrc, std::vector<KeyLine>& k
 
   /*check whether image's depth is different from 0 */
   if( image.depth() != 0 )
-    throw std::runtime_error( "Error, depth of image != 0" );
+    CV_Error( Error::BadDepth, "Error, depth of image != 0" );
 
   /* keypoints list can't be empty */
   if( keylines.size() == 0 )
@@ -2196,6 +2204,11 @@ int BinaryDescriptor::EDLineDetector::EdgeDrawing( cv::Mat &image, EdgeChains &e
         "numofedgePixel1 = " << offsetPFirst << ",  numofedgePixel2 = " << offsetPSecond << ", MaxNumOfEdgePixel=" << edgePixelArraySize << std::endl;
     return -1;
   }
+  if( !(offsetPFirst && offsetPSecond) )
+  {
+      std::cout << "Edge drawing Error: lines not found" << std::endl;
+      return -1;
+  }
 
   /*now all the edge information are stored in pFirstPartEdgeX_, pFirstPartEdgeY_,
    *pFirstPartEdgeS_,  pSecondPartEdgeX_, pSecondPartEdgeY_, pSecondPartEdgeS_;
diff --git a/contrib/modules/line_descriptor/src/binary_descriptor_matcher.cpp b/contrib/modules/line_descriptor/src/binary_descriptor_matcher.cpp
index 437a6e2..eb4d283 100644
--- a/contrib/modules/line_descriptor/src/binary_descriptor_matcher.cpp
+++ b/contrib/modules/line_descriptor/src/binary_descriptor_matcher.cpp
@@ -54,7 +54,7 @@ namespace line_descriptor
 /* constructor */
 BinaryDescriptorMatcher::BinaryDescriptorMatcher()
 {
-  dataset = new Mihasher( 256, 32 );
+  dataset = Ptr<Mihasher>(new Mihasher( 256, 32 ));
   nextAddedIndex = 0;
   numImages = 0;
   descrInDS = 0;
@@ -83,7 +83,7 @@ void BinaryDescriptorMatcher::add( const std::vector<Mat>& descriptors )
 void BinaryDescriptorMatcher::train()
 {
   if( !dataset )
-    dataset = new Mihasher( 256, 32 );
+    dataset = Ptr<Mihasher>(new Mihasher( 256, 32 ));
 
   if( descriptorsMat.rows > 0 )
     dataset->populate( descriptorsMat, descriptorsMat.rows, descriptorsMat.cols );
@@ -97,7 +97,7 @@ void BinaryDescriptorMatcher::clear()
 {
   descriptorsMat.release();
   indexesMap.clear();
-  dataset = 0;
+  dataset.release();
   nextAddedIndex = 0;
   numImages = 0;
   descrInDS = 0;
@@ -596,7 +596,7 @@ void BinaryDescriptorMatcher::radiusMatch( const Mat& queryDescriptors, std::vec
 void BinaryDescriptorMatcher::Mihasher::batchquery( UINT32 * results, UINT32 *numres, const cv::Mat & queries, UINT32 numq, int dim1queries )
 {
   /* create and initialize a bitarray */
-  counter = new bitarray;
+  counter = makePtr<bitarray>();
   counter->init( N );
 
   UINT32 *res = new UINT32[K * ( D + 1 )];
@@ -627,8 +627,6 @@ void BinaryDescriptorMatcher::Mihasher::batchquery( UINT32 * results, UINT32 *nu
 
   delete[] res;
   delete[] chunks;
-
-  delete counter;
 }
 
 /* execute a single query */
@@ -769,12 +767,12 @@ BinaryDescriptorMatcher::Mihasher::Mihasher( int B_val, int _m )
    (m-mplus) is the number of chunks with (b-1) bits */
   mplus = B - m * ( b - 1 );
 
-  xornum = new UINT32[d + 2];
+  xornum.resize(d + 2);
   xornum[0] = 0;
   for ( int i = 0; i <= d; i++ )
     xornum[i + 1] = xornum[i] + (UINT32) choose( b, i );
 
-  H = new SparseHashtable[m];
+  H.resize(m);
 
   /* H[i].init might fail */
   for ( int i = 0; i < mplus; i++ )
@@ -792,8 +790,6 @@ void BinaryDescriptorMatcher::Mihasher::setK( int K_val )
 /* desctructor */
 BinaryDescriptorMatcher::Mihasher::~Mihasher()
 {
-  delete[] xornum;
-  delete[] H;
 }
 
 /* populate tables */
@@ -821,7 +817,6 @@ void BinaryDescriptorMatcher::Mihasher::populate( cv::Mat & _codes, UINT32 N_val
 /* constructor */
 BinaryDescriptorMatcher::SparseHashtable::SparseHashtable()
 {
-  table = NULL;
   size = 0;
   b = 0;
 }
@@ -835,7 +830,7 @@ int BinaryDescriptorMatcher::SparseHashtable::init( int _b )
     return 1;
 
   size = UINT64_1 << ( b - 5 );  // size = 2 ^ b
-  table = (BucketGroup*) calloc( (size_t)size, sizeof(BucketGroup) );
+  table = std::vector<BucketGroup>((size_t)size, BucketGroup(false));
 
   return 0;
 
@@ -844,26 +839,28 @@ int BinaryDescriptorMatcher::SparseHashtable::init( int _b )
 /* destructor */
 BinaryDescriptorMatcher::SparseHashtable::~SparseHashtable()
 {
-  free (table);
 }
 
 /* insert data */
 void BinaryDescriptorMatcher::SparseHashtable::insert( UINT64 index, UINT32 data )
 {
-  table[index >> 5].insert( (int) ( index % 32 ), data );
+  table[(size_t)(index >> 5)].insert( (int) ( index & 31 ), data );
 }
 
 /* query data */
 UINT32* BinaryDescriptorMatcher::SparseHashtable::query( UINT64 index, int *Size )
 {
-  return table[index >> 5].query( (int) ( index % 32 ), Size );
+  return table[(size_t)(index >> 5)].query( (int) ( index & 31 ), Size );
 }
 
 /* constructor */
-BinaryDescriptorMatcher::BucketGroup::BucketGroup()
+BinaryDescriptorMatcher::BucketGroup::BucketGroup(bool needAllocateGroup)
 {
   empty = 0;
-  group = std::vector < uint32_t > ( 2, 0 );
+  if (needAllocateGroup)
+    group = std::vector < uint32_t > ( 2, 0 );
+  else
+    group = std::vector < uint32_t > ( 0, 0 );
 }
 
 /* destructor */
diff --git a/contrib/modules/line_descriptor/src/bitops.hpp b/contrib/modules/line_descriptor/src/bitops.hpp
index 2b5d624..f2e2a1a 100644
--- a/contrib/modules/line_descriptor/src/bitops.hpp
+++ b/contrib/modules/line_descriptor/src/bitops.hpp
@@ -143,8 +143,8 @@ inline void print_code( UINT64 tmp, int b )
 {
   for ( long long int j = ( b - 1 ); j >= 0; j-- )
   {
-    printf( "%llu", (long long int) tmp / (UINT64) ( 1 << j ) );
-    tmp = tmp - ( tmp / (UINT64) ( 1 << j ) ) * (UINT64) ( 1 << j );
+    printf( "%llu", (long long int) tmp / (UINT64) ( (UINT64)1 << j ) );
+    tmp = tmp - ( tmp / (UINT64) ( (UINT64)1 << j ) ) * (UINT64) ( (UINT64)1 << j );
   }
 
   printf( "\n" );
diff --git a/contrib/modules/line_descriptor/test/test_descriptors_regression.cpp b/contrib/modules/line_descriptor/test/test_descriptors_regression.cpp
index a25ca51..1fd3787 100644
--- a/contrib/modules/line_descriptor/test/test_descriptors_regression.cpp
+++ b/contrib/modules/line_descriptor/test/test_descriptors_regression.cpp
@@ -372,3 +372,18 @@ TEST( BinaryDescriptor_Descriptors, regression )
   CV_BD_DescriptorsTest<Hamming> test( std::string( "lbd_descriptors_cameraman" ), 1 );
   test.safe_run();
 }
+
+/****************************************************************************************\
+*                                Other tests                                             *
+ \****************************************************************************************/
+
+TEST( BinaryDescriptor, no_lines_found )
+{
+  Mat Image = Mat::zeros(100, 100, CV_8U);
+  Ptr<line_descriptor::BinaryDescriptor> binDescriptor =
+    line_descriptor::BinaryDescriptor::createBinaryDescriptor();
+
+  std::vector<cv::line_descriptor::KeyLine> keyLines;
+  binDescriptor->detect(Image, keyLines);
+  ASSERT_EQ(keyLines.size(), 0u);
+}
diff --git a/contrib/modules/line_descriptor/test/test_matcher_regression.cpp b/contrib/modules/line_descriptor/test/test_matcher_regression.cpp
index df649c0..75ea0d8 100644
--- a/contrib/modules/line_descriptor/test/test_matcher_regression.cpp
+++ b/contrib/modules/line_descriptor/test/test_matcher_regression.cpp
@@ -123,7 +123,7 @@ uchar CV_BinaryDescriptorMatcherTest::invertSingleBits( uchar dividend_char, int
   /* reconvert to decimal */
   uchar result = 0;
   for ( int i = (int) bin_vector.size() - 1; i >= 0; i-- )
-    result += (uchar) ( bin_vector[i] * pow( 2, i ) );
+    result += (uchar) ( bin_vector[i] * ( 1 << i ) );
 
   return result;
 }
diff --git a/contrib/modules/matlab/CMakeLists.txt b/contrib/modules/matlab/CMakeLists.txt
index 32c8bc0..30e7ddb 100644
--- a/contrib/modules/matlab/CMakeLists.txt
+++ b/contrib/modules/matlab/CMakeLists.txt
@@ -23,6 +23,20 @@
 #  them with mex.
 # ----------------------------------------------------------------------------
 
+# ----------------------------------------------------------------------------
+#  Architecture checks
+# ----------------------------------------------------------------------------
+# make sure we're on a supported architecture with Matlab and python installed
+if(APPLE_FRAMEWORK OR ANDROID OR NOT MATLAB_FOUND)
+    ocv_module_disable(matlab)
+    return()
+elseif (NOT PYTHON_DEFAULT_AVAILABLE)
+    message(WARNING "A required dependency of the matlab module (Python) was not found. Disabling Matlab bindings...")
+    ocv_module_disable(matlab)
+    return()
+endif()
+
+
 # PREPEND
 # Given a list of strings IN and a TOKEN, prepend the token to each string
 # and append to OUT. This is used for passing command line "-I", "-L" and "-l"
@@ -44,19 +58,6 @@ macro(WARN_MIXED_PRECISION COMPILER_BITNESS MATLAB_BITNESS)
     message(WARNING ${MSG})
 endmacro()
 
-# ----------------------------------------------------------------------------
-#  Architecture checks
-# ----------------------------------------------------------------------------
-# make sure we're on a supported architecture with Matlab and python installed
-if (IOS OR ANDROID OR NOT MATLAB_FOUND)
-    ocv_module_disable(matlab)
-    return()
-elseif (NOT PYTHON_DEFAULT_AVAILABLE)
-    message(WARNING "A required dependency of the matlab module (PythonLibs) was not found. Disabling Matlab bindings...")
-    ocv_module_disable(matlab)
-    return()
-endif()
-
 
 # If the user built OpenCV as X-bit, but they have a Y-bit version of Matlab,
 # attempting to link to OpenCV during binding generation will fail, since
diff --git a/contrib/modules/matlab/generator/filters.pyc b/contrib/modules/matlab/generator/filters.pyc
deleted file mode 100644
index e7a8290..0000000
Binary files a/contrib/modules/matlab/generator/filters.pyc and /dev/null differ
diff --git a/contrib/modules/matlab/generator/parse_tree.pyc b/contrib/modules/matlab/generator/parse_tree.pyc
deleted file mode 100644
index d7f652e..0000000
Binary files a/contrib/modules/matlab/generator/parse_tree.pyc and /dev/null differ
diff --git a/contrib/modules/matlab/include/opencv2/matlab/bridge.hpp b/contrib/modules/matlab/include/opencv2/matlab/bridge.hpp
index 34faeae..e622fe9 100644
--- a/contrib/modules/matlab/include/opencv2/matlab/bridge.hpp
+++ b/contrib/modules/matlab/include/opencv2/matlab/bridge.hpp
@@ -293,6 +293,10 @@ public:
   int toInt() { return ptr_.scalar<int>(); }
   operator int() { return toInt(); }
 
+  // --------------------------- size_t -----------------------------------------
+  Bridge& operator=(const size_t&) { return *this; }
+  size_t toSizeT() { return ptr_.scalar<size_t>(); }
+  operator size_t() { return toSizeT(); }
 
 
 
diff --git a/contrib/modules/optflow/README.md b/contrib/modules/optflow/README.md
index e0a0437..614b5a1 100644
--- a/contrib/modules/optflow/README.md
+++ b/contrib/modules/optflow/README.md
@@ -1,2 +1,4 @@
-Optical Flow Algorithms for tracking points
-===========================================
\ No newline at end of file
+Optical Flow Algorithms
+=======================
+
+Algorithms for running and evaluating deepflow, simpleflow, sparsetodenseflow and motion templates (silhouette flow).
diff --git a/contrib/modules/optflow/doc/optflow.bib b/contrib/modules/optflow/doc/optflow.bib
index e9ef098..5cfcab7 100644
--- a/contrib/modules/optflow/doc/optflow.bib
+++ b/contrib/modules/optflow/doc/optflow.bib
@@ -37,3 +37,34 @@
   year={2013},
   organization={IEEE}
 }
+
+ at inproceedings{Kroeger2016,
+  author={Till Kroeger and Radu Timofte and Dengxin Dai and Luc Van Gool},
+  title={Fast Optical Flow using Dense Inverse Search},
+  booktitle={Proceedings of the European Conference on Computer Vision ({ECCV})},
+  year = {2016}
+}
+
+ at inproceedings{Brox2004,
+  title={High accuracy optical flow estimation based on a theory for warping},
+  author={Brox, Thomas and Bruhn, Andr{\'e}s and Papenberg, Nils and Weickert, Joachim},
+  booktitle={European Conference on Computer Vision (ECCV)},
+  pages={25--36},
+  year={2004}
+}
+
+ at inproceedings{Wulff:CVPR:2015,
+  title = {Efficient Sparse-to-Dense Optical Flow Estimation using a Learned Basis and Layers},
+  author = {Wulff, Jonas and Black, Michael J.},
+  booktitle = { IEEE Conf. on Computer Vision and Pattern Recognition (CVPR) 2015},
+  month = {June},
+  year = {2015}
+}
+
+ at inproceedings{Wang_2016_CVPR,
+  author = {Wang, Shenlong and Ryan Fanello, Sean and Rhemann, Christoph and Izadi, Shahram and Kohli, Pushmeet},
+  title = {The Global Patch Collider},
+  booktitle = {The IEEE Conference on Computer Vision and Pattern Recognition (CVPR)},
+  month = {June},
+  year = {2016}
+}
diff --git a/contrib/modules/optflow/include/opencv2/optflow.hpp b/contrib/modules/optflow/include/opencv2/optflow.hpp
index 667adcb..e68d5b7 100644
--- a/contrib/modules/optflow/include/opencv2/optflow.hpp
+++ b/contrib/modules/optflow/include/opencv2/optflow.hpp
@@ -66,6 +66,9 @@ Functions reading and writing .flo files in "Middlebury" format, see: <http://vi
 
  */
 
+#include "opencv2/optflow/pcaflow.hpp"
+#include "opencv2/optflow/sparse_matching_gpc.hpp"
+
 namespace cv
 {
 namespace optflow
@@ -154,6 +157,64 @@ to the flow in the horizontal direction (u), second - vertical (v).
  */
 CV_EXPORTS_W bool writeOpticalFlow( const String& path, InputArray flow );
 
+/** @brief Variational optical flow refinement
+
+This class implements variational refinement of the input flow field, i.e.
+it uses input flow to initialize the minimization of the following functional:
+\f$E(U) = \int_{\Omega} \delta \Psi(E_I) + \gamma \Psi(E_G) + \alpha \Psi(E_S) \f$,
+where \f$E_I,E_G,E_S\f$ are color constancy, gradient constancy and smoothness terms
+respectively. \f$\Psi(s^2)=\sqrt{s^2+\epsilon^2}\f$ is a robust penalizer to limit the
+influence of outliers. A complete formulation and a description of the minimization
+procedure can be found in @cite Brox2004
+*/
+class CV_EXPORTS_W VariationalRefinement : public DenseOpticalFlow
+{
+public:
+    /** @brief @ref calc function overload to handle separate horizontal (u) and vertical (v) flow components
+    (to avoid extra splits/merges) */
+    CV_WRAP virtual void calcUV(InputArray I0, InputArray I1, InputOutputArray flow_u, InputOutputArray flow_v) = 0;
+
+    /** @brief Number of outer (fixed-point) iterations in the minimization procedure.
+    @see setFixedPointIterations */
+    CV_WRAP virtual int getFixedPointIterations() const = 0;
+    /** @copybrief getFixedPointIterations @see getFixedPointIterations */
+    CV_WRAP virtual void setFixedPointIterations(int val) = 0;
+
+    /** @brief Number of inner successive over-relaxation (SOR) iterations
+        in the minimization procedure to solve the respective linear system.
+    @see setSorIterations */
+    CV_WRAP virtual int getSorIterations() const = 0;
+    /** @copybrief getSorIterations @see getSorIterations */
+    CV_WRAP virtual void setSorIterations(int val) = 0;
+
+    /** @brief Relaxation factor in SOR
+    @see setOmega */
+    CV_WRAP virtual float getOmega() const = 0;
+    /** @copybrief getOmega @see getOmega */
+    CV_WRAP virtual void setOmega(float val) = 0;
+
+    /** @brief Weight of the smoothness term
+    @see setAlpha */
+    CV_WRAP virtual float getAlpha() const = 0;
+    /** @copybrief getAlpha @see getAlpha */
+    CV_WRAP virtual void setAlpha(float val) = 0;
+
+    /** @brief Weight of the color constancy term
+    @see setDelta */
+    CV_WRAP virtual float getDelta() const = 0;
+    /** @copybrief getDelta @see getDelta */
+    CV_WRAP virtual void setDelta(float val) = 0;
+
+    /** @brief Weight of the gradient constancy term
+    @see setGamma */
+    CV_WRAP virtual float getGamma() const = 0;
+    /** @copybrief getGamma @see getGamma */
+    CV_WRAP virtual void setGamma(float val) = 0;
+};
+
+/** @brief Creates an instance of VariationalRefinement
+*/
+CV_EXPORTS_W Ptr<VariationalRefinement> createVariationalFlowRefinement();
 
 /** @brief DeepFlow optical flow algorithm implementation.
 
@@ -191,6 +252,108 @@ CV_EXPORTS_W Ptr<DenseOpticalFlow> createOptFlow_Farneback();
 //! Additional interface to the SparseToDenseFlow algorithm - calcOpticalFlowSparseToDense()
 CV_EXPORTS_W Ptr<DenseOpticalFlow> createOptFlow_SparseToDense();
 
+/** @brief DIS optical flow algorithm.
+
+This class implements the Dense Inverse Search (DIS) optical flow algorithm. More
+details about the algorithm can be found at @cite Kroeger2016 . Includes three presets with preselected
+parameters to provide reasonable trade-off between speed and quality. However, even the slowest preset is
+still relatively fast, use DeepFlow if you need better quality and don't care about speed.
+
+This implementation includes several additional features compared to the algorithm described in the paper,
+including spatial propagation of flow vectors (@ref getUseSpatialPropagation), as well as an option to
+utilize an initial flow approximation passed to @ref calc (which is, essentially, temporal propagation,
+if the previous frame's flow field is passed).
+*/
+class CV_EXPORTS_W DISOpticalFlow : public DenseOpticalFlow
+{
+public:
+    enum
+    {
+        PRESET_ULTRAFAST = 0,
+        PRESET_FAST = 1,
+        PRESET_MEDIUM = 2
+    };
+
+    /** @brief Finest level of the Gaussian pyramid on which the flow is computed (zero level
+        corresponds to the original image resolution). The final flow is obtained by bilinear upscaling.
+        @see setFinestScale */
+    CV_WRAP virtual int getFinestScale() const = 0;
+    /** @copybrief getFinestScale @see getFinestScale */
+    CV_WRAP virtual void setFinestScale(int val) = 0;
+
+    /** @brief Size of an image patch for matching (in pixels). Normally, default 8x8 patches work well
+        enough in most cases.
+        @see setPatchSize */
+    CV_WRAP virtual int getPatchSize() const = 0;
+    /** @copybrief getPatchSize @see getPatchSize */
+    CV_WRAP virtual void setPatchSize(int val) = 0;
+
+    /** @brief Stride between neighbor patches. Must be less than patch size. Lower values correspond
+        to higher flow quality.
+        @see setPatchStride */
+    CV_WRAP virtual int getPatchStride() const = 0;
+    /** @copybrief getPatchStride @see getPatchStride */
+    CV_WRAP virtual void setPatchStride(int val) = 0;
+
+    /** @brief Maximum number of gradient descent iterations in the patch inverse search stage. Higher values
+        may improve quality in some cases.
+        @see setGradientDescentIterations */
+    CV_WRAP virtual int getGradientDescentIterations() const = 0;
+    /** @copybrief getGradientDescentIterations @see getGradientDescentIterations */
+    CV_WRAP virtual void setGradientDescentIterations(int val) = 0;
+
+    /** @brief Number of fixed point iterations of variational refinement per scale. Set to zero to
+        disable variational refinement completely. Higher values will typically result in more smooth and
+        high-quality flow.
+    @see setGradientDescentIterations */
+    CV_WRAP virtual int getVariationalRefinementIterations() const = 0;
+    /** @copybrief getGradientDescentIterations @see getGradientDescentIterations */
+    CV_WRAP virtual void setVariationalRefinementIterations(int val) = 0;
+
+    /** @brief Weight of the smoothness term
+    @see setVariationalRefinementAlpha */
+    CV_WRAP virtual float getVariationalRefinementAlpha() const = 0;
+    /** @copybrief getVariationalRefinementAlpha @see getVariationalRefinementAlpha */
+    CV_WRAP virtual void setVariationalRefinementAlpha(float val) = 0;
+
+    /** @brief Weight of the color constancy term
+    @see setVariationalRefinementDelta */
+    CV_WRAP virtual float getVariationalRefinementDelta() const = 0;
+    /** @copybrief getVariationalRefinementDelta @see getVariationalRefinementDelta */
+    CV_WRAP virtual void setVariationalRefinementDelta(float val) = 0;
+
+    /** @brief Weight of the gradient constancy term
+    @see setVariationalRefinementGamma */
+    CV_WRAP virtual float getVariationalRefinementGamma() const = 0;
+    /** @copybrief getVariationalRefinementGamma @see getVariationalRefinementGamma */
+    CV_WRAP virtual void setVariationalRefinementGamma(float val) = 0;
+
+
+    /** @brief Whether to use mean-normalization of patches when computing patch distance. It is turned on
+        by default as it typically provides a noticeable quality boost because of increased robustness to
+        illumination variations. Turn it off if you are certain that your sequence doesn't contain any changes
+        in illumination.
+    @see setUseMeanNormalization */
+    CV_WRAP virtual bool getUseMeanNormalization() const = 0;
+    /** @copybrief getUseMeanNormalization @see getUseMeanNormalization */
+    CV_WRAP virtual void setUseMeanNormalization(bool val) = 0;
+
+    /** @brief Whether to use spatial propagation of good optical flow vectors. This option is turned on by
+        default, as it tends to work better on average and can sometimes help recover from major errors
+        introduced by the coarse-to-fine scheme employed by the DIS optical flow algorithm. Turning this
+        option off can make the output flow field a bit smoother, however.
+    @see setUseSpatialPropagation */
+    CV_WRAP virtual bool getUseSpatialPropagation() const = 0;
+    /** @copybrief getUseSpatialPropagation @see getUseSpatialPropagation */
+    CV_WRAP virtual void setUseSpatialPropagation(bool val) = 0;
+};
+
+/** @brief Creates an instance of DISOpticalFlow
+
+ at param preset one of PRESET_ULTRAFAST, PRESET_FAST and PRESET_MEDIUM
+*/
+CV_EXPORTS_W Ptr<DISOpticalFlow> createOptFlow_DIS(int preset = DISOpticalFlow::PRESET_FAST);
+
 //! @}
 
 } //optflow
diff --git a/contrib/modules/optflow/include/opencv2/optflow/pcaflow.hpp b/contrib/modules/optflow/include/opencv2/optflow/pcaflow.hpp
new file mode 100644
index 0000000..6645363
--- /dev/null
+++ b/contrib/modules/optflow/include/opencv2/optflow/pcaflow.hpp
@@ -0,0 +1,149 @@
+/*
+By downloading, copying, installing or using the software you agree to this
+license. If you do not agree to this license, do not download, install,
+copy or use the software.
+
+
+                          License Agreement
+               For Open Source Computer Vision Library
+                       (3-clause BSD License)
+
+Copyright (C) 2016, OpenCV Foundation, all rights reserved.
+Third party copyrights are property of their respective owners.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+  * Redistributions of source code must retain the above copyright notice,
+    this list of conditions and the following disclaimer.
+
+  * Redistributions in binary form must reproduce the above copyright notice,
+    this list of conditions and the following disclaimer in the documentation
+    and/or other materials provided with the distribution.
+
+  * Neither the names of the copyright holders nor the names of the contributors
+    may be used to endorse or promote products derived from this software
+    without specific prior written permission.
+
+This software is provided by the copyright holders and contributors "as is" and
+any express or implied warranties, including, but not limited to, the implied
+warranties of merchantability and fitness for a particular purpose are
+disclaimed. In no event shall copyright holders or contributors be liable for
+any direct, indirect, incidental, special, exemplary, or consequential damages
+(including, but not limited to, procurement of substitute goods or services;
+loss of use, data, or profits; or business interruption) however caused
+and on any theory of liability, whether in contract, strict liability,
+or tort (including negligence or otherwise) arising in any way out of
+the use of this software, even if advised of the possibility of such damage.
+*/
+
+/**
+ * @file   pcaflow.hpp
+ * @author Vladislav Samsonov <vvladxx at gmail.com>
+ * @brief  Implementation of the PCAFlow algorithm from the following paper:
+ * http://files.is.tue.mpg.de/black/papers/cvpr2015_pcaflow.pdf
+ *
+ * @cite Wulff:CVPR:2015
+ *
+ * There are some key differences which distinguish this algorithm from the original PCAFlow (see paper):
+ * - Discrete Cosine Transform basis is used instead of basis extracted with PCA.
+ *   Reasoning: DCT basis has comparable performance and it doesn't require additional storage space.
+ *   Also, this decision helps to avoid overloading the algorithm with a lot of external input.
+ * - Usage of built-in OpenCV feature tracking instead of libviso.
+*/
+
+#ifndef __OPENCV_OPTFLOW_PCAFLOW_HPP__
+#define __OPENCV_OPTFLOW_PCAFLOW_HPP__
+
+#include "opencv2/core.hpp"
+#include "opencv2/video.hpp"
+
+namespace cv
+{
+namespace optflow
+{
+
+//! @addtogroup optflow
+//! @{
+
+/** @brief
+ * This class can be used for imposing a learned prior on the resulting optical flow.
+ * Solution will be regularized according to this prior.
+ * You need to generate appropriate prior file with "learn_prior.py" script beforehand.
+ */
+class CV_EXPORTS_W PCAPrior
+{
+private:
+  Mat L1;
+  Mat L2;
+  Mat c1;
+  Mat c2;
+
+public:
+  PCAPrior( const char *pathToPrior );
+
+  int getPadding() const { return L1.size().height; }
+
+  int getBasisSize() const { return L1.size().width; }
+
+  void fillConstraints( float *A1, float *A2, float *b1, float *b2 ) const;
+};
+
+/** @brief PCAFlow algorithm.
+ */
+class CV_EXPORTS_W OpticalFlowPCAFlow : public DenseOpticalFlow
+{
+protected:
+  const Ptr<const PCAPrior> prior;
+  const Size basisSize;
+  const float sparseRate;              // (0 .. 0.1)
+  const float retainedCornersFraction; // [0 .. 1]
+  const float occlusionsThreshold;
+  const float dampingFactor;
+  const float claheClip;
+  bool useOpenCL;
+
+public:
+  /** @brief Creates an instance of PCAFlow algorithm.
+   * @param _prior Learned prior or no prior (default). @see cv::optflow::PCAPrior
+   * @param _basisSize Number of basis vectors.
+   * @param _sparseRate Controls density of sparse matches.
+   * @param _retainedCornersFraction Retained corners fraction.
+   * @param _occlusionsThreshold Occlusion threshold.
+   * @param _dampingFactor Regularization term for solving least-squares. It is not related to the prior regularization.
+   * @param _claheClip Clip parameter for CLAHE.
+   */
+  OpticalFlowPCAFlow( Ptr<const PCAPrior> _prior = Ptr<const PCAPrior>(), const Size _basisSize = Size( 18, 14 ),
+                      float _sparseRate = 0.024, float _retainedCornersFraction = 0.2,
+                      float _occlusionsThreshold = 0.0003, float _dampingFactor = 0.00002, float _claheClip = 14 );
+
+  void calc( InputArray I0, InputArray I1, InputOutputArray flow );
+  void collectGarbage();
+
+private:
+  void findSparseFeatures( UMat &from, UMat &to, std::vector<Point2f> &features,
+                           std::vector<Point2f> &predictedFeatures ) const;
+
+  void removeOcclusions( UMat &from, UMat &to, std::vector<Point2f> &features,
+                         std::vector<Point2f> &predictedFeatures ) const;
+
+  void getSystem( OutputArray AOut, OutputArray b1Out, OutputArray b2Out, const std::vector<Point2f> &features,
+                  const std::vector<Point2f> &predictedFeatures, const Size size );
+
+  void getSystem( OutputArray A1Out, OutputArray A2Out, OutputArray b1Out, OutputArray b2Out,
+                  const std::vector<Point2f> &features, const std::vector<Point2f> &predictedFeatures,
+                  const Size size );
+
+  OpticalFlowPCAFlow& operator=( const OpticalFlowPCAFlow& ); // make it non-assignable
+};
+
+/** @brief Creates an instance of PCAFlow
+*/
+CV_EXPORTS_W Ptr<DenseOpticalFlow> createOptFlow_PCAFlow();
+
+//! @}
+
+}
+}
+
+#endif
diff --git a/contrib/modules/optflow/include/opencv2/optflow/sparse_matching_gpc.hpp b/contrib/modules/optflow/include/opencv2/optflow/sparse_matching_gpc.hpp
new file mode 100644
index 0000000..3127710
--- /dev/null
+++ b/contrib/modules/optflow/include/opencv2/optflow/sparse_matching_gpc.hpp
@@ -0,0 +1,380 @@
+/*
+By downloading, copying, installing or using the software you agree to this
+license. If you do not agree to this license, do not download, install,
+copy or use the software.
+
+
+                          License Agreement
+               For Open Source Computer Vision Library
+                       (3-clause BSD License)
+
+Copyright (C) 2016, OpenCV Foundation, all rights reserved.
+Third party copyrights are property of their respective owners.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+  * Redistributions of source code must retain the above copyright notice,
+    this list of conditions and the following disclaimer.
+
+  * Redistributions in binary form must reproduce the above copyright notice,
+    this list of conditions and the following disclaimer in the documentation
+    and/or other materials provided with the distribution.
+
+  * Neither the names of the copyright holders nor the names of the contributors
+    may be used to endorse or promote products derived from this software
+    without specific prior written permission.
+
+This software is provided by the copyright holders and contributors "as is" and
+any express or implied warranties, including, but not limited to, the implied
+warranties of merchantability and fitness for a particular purpose are
+disclaimed. In no event shall copyright holders or contributors be liable for
+any direct, indirect, incidental, special, exemplary, or consequential damages
+(including, but not limited to, procurement of substitute goods or services;
+loss of use, data, or profits; or business interruption) however caused
+and on any theory of liability, whether in contract, strict liability,
+or tort (including negligence or otherwise) arising in any way out of
+the use of this software, even if advised of the possibility of such damage.
+*/
+
+/**
+ * @file   sparse_matching_gpc.hpp
+ * @author Vladislav Samsonov <vvladxx at gmail.com>
+ * @brief  Implementation of the Global Patch Collider.
+ *
+ * Implementation of the Global Patch Collider algorithm from the following paper:
+ * http://research.microsoft.com/en-us/um/people/pkohli/papers/wfrik_cvpr2016.pdf
+ *
+ * @cite Wang_2016_CVPR
+ */
+
+#ifndef __OPENCV_OPTFLOW_SPARSE_MATCHING_GPC_HPP__
+#define __OPENCV_OPTFLOW_SPARSE_MATCHING_GPC_HPP__
+
+#include "opencv2/core.hpp"
+#include "opencv2/core/hal/intrin.hpp"
+#include "opencv2/imgproc.hpp"
+
+namespace cv
+{
+namespace optflow
+{
+
+//! @addtogroup optflow
+//! @{
+
+struct CV_EXPORTS_W GPCPatchDescriptor
+{
+  static const unsigned nFeatures = 18; //!< number of features in a patch descriptor
+  Vec< double, nFeatures > feature;
+
+  double dot( const Vec< double, nFeatures > &coef ) const;
+
+  void markAsSeparated() { feature[0] = std::numeric_limits< double >::quiet_NaN(); }
+
+  bool isSeparated() const { return cvIsNaN( feature[0] ) != 0; }
+};
+
+struct CV_EXPORTS_W GPCPatchSample
+{
+  GPCPatchDescriptor ref;
+  GPCPatchDescriptor pos;
+  GPCPatchDescriptor neg;
+
+  void getDirections( bool &refdir, bool &posdir, bool &negdir, const Vec< double, GPCPatchDescriptor::nFeatures > &coef, double rhs ) const;
+};
+
+typedef std::vector< GPCPatchSample > GPCSamplesVector;
+
+/** @brief Descriptor types for the Global Patch Collider.
+ */
+enum GPCDescType
+{
+  GPC_DESCRIPTOR_DCT = 0, //!< Better quality but slow
+  GPC_DESCRIPTOR_WHT      //!< Worse quality but much faster
+};
+
+/** @brief Class encapsulating training samples.
+ */
+class CV_EXPORTS_W GPCTrainingSamples
+{
+private:
+  GPCSamplesVector samples;
+  int descriptorType;
+
+public:
+  /** @brief This function can be used to extract samples from a pair of images and a ground truth flow.
+   * Sizes of all the provided vectors must be equal.
+   */
+  static Ptr< GPCTrainingSamples > create( const std::vector< String > &imagesFrom, const std::vector< String > &imagesTo,
+                                           const std::vector< String > &gt, int descriptorType );
+
+  static Ptr< GPCTrainingSamples > create( InputArrayOfArrays imagesFrom, InputArrayOfArrays imagesTo, InputArrayOfArrays gt,
+                                           int descriptorType );
+
+  size_t size() const { return samples.size(); }
+
+  int type() const { return descriptorType; }
+
+  operator GPCSamplesVector &() { return samples; }
+};
+
+/** @brief Class encapsulating training parameters.
+ */
+struct GPCTrainingParams
+{
+  unsigned maxTreeDepth;  //!< Maximum tree depth to stop partitioning.
+  int minNumberOfSamples; //!< Minimum number of samples in the node to stop partitioning.
+  int descriptorType;     //!< Type of descriptors to use.
+  bool printProgress;     //!< Print progress to stdout.
+
+  GPCTrainingParams( unsigned _maxTreeDepth = 20, int _minNumberOfSamples = 3, GPCDescType _descriptorType = GPC_DESCRIPTOR_DCT,
+                     bool _printProgress = true )
+      : maxTreeDepth( _maxTreeDepth ), minNumberOfSamples( _minNumberOfSamples ), descriptorType( _descriptorType ),
+        printProgress( _printProgress )
+  {
+    CV_Assert( check() );
+  }
+
+  GPCTrainingParams( const GPCTrainingParams &params )
+      : maxTreeDepth( params.maxTreeDepth ), minNumberOfSamples( params.minNumberOfSamples ), descriptorType( params.descriptorType ),
+        printProgress( params.printProgress )
+  {
+    CV_Assert( check() );
+  }
+
+  bool check() const { return maxTreeDepth > 1 && minNumberOfSamples > 1; }
+};
+
+/** @brief Class encapsulating matching parameters.
+ */
+struct GPCMatchingParams
+{
+  bool useOpenCL; //!< Whether to use OpenCL to speed up the matching.
+
+  GPCMatchingParams( bool _useOpenCL = false ) : useOpenCL( _useOpenCL ) {}
+
+  GPCMatchingParams( const GPCMatchingParams &params ) : useOpenCL( params.useOpenCL ) {}
+};
+
+/** @brief Class for individual tree.
+ */
+class CV_EXPORTS_W GPCTree : public Algorithm
+{
+public:
+  struct Node
+  {
+    Vec< double, GPCPatchDescriptor::nFeatures > coef; //!< Hyperplane coefficients
+    double rhs;                                        //!< Bias term of the hyperplane
+    unsigned left;
+    unsigned right;
+
+    bool operator==( const Node &n ) const { return coef == n.coef && rhs == n.rhs && left == n.left && right == n.right; }
+  };
+
+private:
+  typedef GPCSamplesVector::iterator SIter;
+
+  std::vector< Node > nodes;
+  GPCTrainingParams params;
+
+  bool trainNode( size_t nodeId, SIter begin, SIter end, unsigned depth );
+
+public:
+  void train( GPCTrainingSamples &samples, const GPCTrainingParams params = GPCTrainingParams() );
+
+  void write( FileStorage &fs ) const;
+
+  void read( const FileNode &fn );
+
+  unsigned findLeafForPatch( const GPCPatchDescriptor &descr ) const;
+
+  static Ptr< GPCTree > create() { return makePtr< GPCTree >(); }
+
+  bool operator==( const GPCTree &t ) const { return nodes == t.nodes; }
+
+  int getDescriptorType() const { return params.descriptorType; }
+};
+
+template < int T > class CV_EXPORTS_W GPCForest : public Algorithm
+{
+private:
+  struct Trail
+  {
+    unsigned leaf[T]; //!< Inside which leaf of the tree 0..T the patch fell?
+    Point2i coord;    //!< Patch coordinates.
+
+    bool operator==( const Trail &trail ) const { return memcmp( leaf, trail.leaf, sizeof( leaf ) ) == 0; }
+
+    bool operator<( const Trail &trail ) const
+    {
+      for ( int i = 0; i < T - 1; ++i )
+        if ( leaf[i] != trail.leaf[i] )
+          return leaf[i] < trail.leaf[i];
+      return leaf[T - 1] < trail.leaf[T - 1];
+    }
+  };
+
+  class ParallelTrailsFilling : public ParallelLoopBody
+  {
+  private:
+    const GPCForest *forest;
+    const std::vector< GPCPatchDescriptor > *descr;
+    std::vector< Trail > *trails;
+
+    ParallelTrailsFilling &operator=( const ParallelTrailsFilling & );
+
+  public:
+    ParallelTrailsFilling( const GPCForest *_forest, const std::vector< GPCPatchDescriptor > *_descr, std::vector< Trail > *_trails )
+        : forest( _forest ), descr( _descr ), trails( _trails ){};
+
+    void operator()( const Range &range ) const
+    {
+      for ( int t = range.start; t < range.end; ++t )
+        for ( size_t i = 0; i < descr->size(); ++i )
+          trails->at( i ).leaf[t] = forest->tree[t].findLeafForPatch( descr->at( i ) );
+    }
+  };
+
+  GPCTree tree[T];
+
+public:
+  /** @brief Train the forest using one sample set for every tree.
+   * Please, consider using the next method instead of this one for better quality.
+   */
+  void train( GPCTrainingSamples &samples, const GPCTrainingParams params = GPCTrainingParams() )
+  {
+    for ( int i = 0; i < T; ++i )
+      tree[i].train( samples, params );
+  }
+
+  /** @brief Train the forest using individual samples for each tree.
+   * It is generally better to use this instead of the first method.
+   */
+  void train( const std::vector< String > &imagesFrom, const std::vector< String > &imagesTo, const std::vector< String > &gt,
+              const GPCTrainingParams params = GPCTrainingParams() )
+  {
+    for ( int i = 0; i < T; ++i )
+    {
+      Ptr< GPCTrainingSamples > samples =
+        GPCTrainingSamples::create( imagesFrom, imagesTo, gt, params.descriptorType ); // Create training set for the tree
+      tree[i].train( *samples, params );
+    }
+  }
+
+  void train( InputArrayOfArrays imagesFrom, InputArrayOfArrays imagesTo, InputArrayOfArrays gt,
+              const GPCTrainingParams params = GPCTrainingParams() )
+  {
+    for ( int i = 0; i < T; ++i )
+    {
+      Ptr< GPCTrainingSamples > samples =
+        GPCTrainingSamples::create( imagesFrom, imagesTo, gt, params.descriptorType ); // Create training set for the tree
+      tree[i].train( *samples, params );
+    }
+  }
+
+  void write( FileStorage &fs ) const
+  {
+    fs << "ntrees" << T << "trees"
+       << "[";
+    for ( int i = 0; i < T; ++i )
+    {
+      fs << "{";
+      tree[i].write( fs );
+      fs << "}";
+    }
+    fs << "]";
+  }
+
+  void read( const FileNode &fn )
+  {
+    CV_Assert( T <= (int)fn["ntrees"] );
+    FileNodeIterator it = fn["trees"].begin();
+    for ( int i = 0; i < T; ++i, ++it )
+      tree[i].read( *it );
+  }
+
+  /** @brief Find correspondences between two images.
+   * @param[in] imgFrom First image in a sequence.
+   * @param[in] imgTo Second image in a sequence.
+   * @param[out] corr Output vector with pairs of corresponding points.
+   * @param[in] params Additional matching parameters for fine-tuning.
+   */
+  void findCorrespondences( InputArray imgFrom, InputArray imgTo, std::vector< std::pair< Point2i, Point2i > > &corr,
+                            const GPCMatchingParams params = GPCMatchingParams() ) const;
+
+  static Ptr< GPCForest > create() { return makePtr< GPCForest >(); }
+};
+
+class CV_EXPORTS_W GPCDetails
+{
+public:
+  static void dropOutliers( std::vector< std::pair< Point2i, Point2i > > &corr );
+
+  static void getAllDescriptorsForImage( const Mat *imgCh, std::vector< GPCPatchDescriptor > &descr, const GPCMatchingParams &mp,
+                                         int type );
+
+  static void getCoordinatesFromIndex( size_t index, Size sz, int &x, int &y );
+};
+
+template < int T >
+void GPCForest< T >::findCorrespondences( InputArray imgFrom, InputArray imgTo, std::vector< std::pair< Point2i, Point2i > > &corr,
+                                          const GPCMatchingParams params ) const
+{
+  CV_Assert( imgFrom.channels() == 3 );
+  CV_Assert( imgTo.channels() == 3 );
+
+  Mat from, to;
+  imgFrom.getMat().convertTo( from, CV_32FC3 );
+  imgTo.getMat().convertTo( to, CV_32FC3 );
+  cvtColor( from, from, COLOR_BGR2YCrCb );
+  cvtColor( to, to, COLOR_BGR2YCrCb );
+
+  Mat fromCh[3], toCh[3];
+  split( from, fromCh );
+  split( to, toCh );
+
+  std::vector< GPCPatchDescriptor > descr;
+  GPCDetails::getAllDescriptorsForImage( fromCh, descr, params, tree[0].getDescriptorType() );
+  std::vector< Trail > trailsFrom( descr.size() ), trailsTo( descr.size() );
+
+  for ( size_t i = 0; i < descr.size(); ++i )
+    GPCDetails::getCoordinatesFromIndex( i, from.size(), trailsFrom[i].coord.x, trailsFrom[i].coord.y );
+  parallel_for_( Range( 0, T ), ParallelTrailsFilling( this, &descr, &trailsFrom ) );
+
+  descr.clear();
+  GPCDetails::getAllDescriptorsForImage( toCh, descr, params, tree[0].getDescriptorType() );
+
+  for ( size_t i = 0; i < descr.size(); ++i )
+    GPCDetails::getCoordinatesFromIndex( i, to.size(), trailsTo[i].coord.x, trailsTo[i].coord.y );
+  parallel_for_( Range( 0, T ), ParallelTrailsFilling( this, &descr, &trailsTo ) );
+
+  std::sort( trailsFrom.begin(), trailsFrom.end() );
+  std::sort( trailsTo.begin(), trailsTo.end() );
+
+  for ( size_t i = 0; i < trailsFrom.size(); ++i )
+  {
+    bool uniq = true;
+    while ( i + 1 < trailsFrom.size() && trailsFrom[i] == trailsFrom[i + 1] )
+      ++i, uniq = false;
+    if ( uniq )
+    {
+      typename std::vector< Trail >::const_iterator lb = std::lower_bound( trailsTo.begin(), trailsTo.end(), trailsFrom[i] );
+      if ( lb != trailsTo.end() && *lb == trailsFrom[i] && ( ( lb + 1 ) == trailsTo.end() || !( *lb == *( lb + 1 ) ) ) )
+        corr.push_back( std::make_pair( trailsFrom[i].coord, lb->coord ) );
+    }
+  }
+
+  GPCDetails::dropOutliers( corr );
+}
+
+//! @}
+
+} // namespace optflow
+
+CV_EXPORTS void write( FileStorage &fs, const String &name, const optflow::GPCTree::Node &node );
+
+CV_EXPORTS void read( const FileNode &fn, optflow::GPCTree::Node &node, optflow::GPCTree::Node );
+} // namespace cv
+
+#endif
diff --git a/contrib/modules/optflow/perf/perf_deepflow.cpp b/contrib/modules/optflow/perf/perf_deepflow.cpp
new file mode 100644
index 0000000..e52dcd7
--- /dev/null
+++ b/contrib/modules/optflow/perf/perf_deepflow.cpp
@@ -0,0 +1,69 @@
+/*
+ *  By downloading, copying, installing or using the software you agree to this license.
+ *  If you do not agree to this license, do not download, install,
+ *  copy or use the software.
+ *
+ *
+ *  License Agreement
+ *  For Open Source Computer Vision Library
+ *  (3 - clause BSD License)
+ *
+ *  Redistribution and use in source and binary forms, with or without modification,
+ *  are permitted provided that the following conditions are met :
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *  this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *  this list of conditions and the following disclaimer in the documentation
+ *  and / or other materials provided with the distribution.
+ *
+ *  * Neither the names of the copyright holders nor the names of the contributors
+ *  may be used to endorse or promote products derived from this software
+ *  without specific prior written permission.
+ *
+ *  This software is provided by the copyright holders and contributors "as is" and
+ *  any express or implied warranties, including, but not limited to, the implied
+ *  warranties of merchantability and fitness for a particular purpose are disclaimed.
+ *  In no event shall copyright holders or contributors be liable for any direct,
+ *  indirect, incidental, special, exemplary, or consequential damages
+ *  (including, but not limited to, procurement of substitute goods or services;
+ *  loss of use, data, or profits; or business interruption) however caused
+ *  and on any theory of liability, whether in contract, strict liability,
+ *  or tort(including negligence or otherwise) arising in any way out of
+ *  the use of this software, even if advised of the possibility of such damage.
+ */
+
+#include "perf_precomp.hpp"
+
+using std::tr1::tuple;
+using std::tr1::get;
+using namespace perf;
+using namespace testing;
+using namespace cv;
+using namespace cv::optflow;
+
+typedef tuple<Size> DFParams;
+typedef TestBaseWithParam<DFParams> DenseOpticalFlow_DeepFlow;
+
+PERF_TEST_P(DenseOpticalFlow_DeepFlow, perf, Values(szVGA, sz720p))
+{
+    DFParams params = GetParam();
+    Size sz = get<0>(params);
+
+    Mat frame1(sz, CV_8U);
+    Mat frame2(sz, CV_8U);
+    Mat flow;
+
+    randu(frame1, 0, 255);
+    randu(frame2, 0, 255);
+
+    cv::setNumThreads(cv::getNumberOfCPUs());
+    TEST_CYCLE_N(1)
+    {
+        Ptr<DenseOpticalFlow> algo = createOptFlow_DeepFlow();
+        algo->calc(frame1, frame2, flow);
+    }
+
+    SANITY_CHECK_NOTHING();
+}
diff --git a/contrib/modules/optflow/perf/perf_disflow.cpp b/contrib/modules/optflow/perf/perf_disflow.cpp
new file mode 100644
index 0000000..12a6203
--- /dev/null
+++ b/contrib/modules/optflow/perf/perf_disflow.cpp
@@ -0,0 +1,103 @@
+/*
+ *  By downloading, copying, installing or using the software you agree to this license.
+ *  If you do not agree to this license, do not download, install,
+ *  copy or use the software.
+ *
+ *
+ *  License Agreement
+ *  For Open Source Computer Vision Library
+ *  (3 - clause BSD License)
+ *
+ *  Redistribution and use in source and binary forms, with or without modification,
+ *  are permitted provided that the following conditions are met :
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *  this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *  this list of conditions and the following disclaimer in the documentation
+ *  and / or other materials provided with the distribution.
+ *
+ *  * Neither the names of the copyright holders nor the names of the contributors
+ *  may be used to endorse or promote products derived from this software
+ *  without specific prior written permission.
+ *
+ *  This software is provided by the copyright holders and contributors "as is" and
+ *  any express or implied warranties, including, but not limited to, the implied
+ *  warranties of merchantability and fitness for a particular purpose are disclaimed.
+ *  In no event shall copyright holders or contributors be liable for any direct,
+ *  indirect, incidental, special, exemplary, or consequential damages
+ *  (including, but not limited to, procurement of substitute goods or services;
+ *  loss of use, data, or profits; or business interruption) however caused
+ *  and on any theory of liability, whether in contract, strict liability,
+ *  or tort(including negligence or otherwise) arising in any way out of
+ *  the use of this software, even if advised of the possibility of such damage.
+ */
+
+#include "perf_precomp.hpp"
+
+using std::tr1::tuple;
+using std::tr1::get;
+using namespace perf;
+using namespace testing;
+using namespace cv;
+using namespace cv::optflow;
+
+void MakeArtificialExample(Mat &dst_frame1, Mat &dst_frame2);
+
+typedef tuple<String, Size> DISParams;
+typedef TestBaseWithParam<DISParams> DenseOpticalFlow_DIS;
+
+PERF_TEST_P(DenseOpticalFlow_DIS, perf,
+            Combine(Values("PRESET_ULTRAFAST", "PRESET_FAST", "PRESET_MEDIUM"), Values(szVGA, sz720p, sz1080p)))
+{
+    DISParams params = GetParam();
+
+    // use strings to print preset names in the perf test results:
+    String preset_string = get<0>(params);
+    int preset = DISOpticalFlow::PRESET_FAST;
+    if (preset_string == "PRESET_ULTRAFAST")
+        preset = DISOpticalFlow::PRESET_ULTRAFAST;
+    else if (preset_string == "PRESET_FAST")
+        preset = DISOpticalFlow::PRESET_FAST;
+    else if (preset_string == "PRESET_MEDIUM")
+        preset = DISOpticalFlow::PRESET_MEDIUM;
+    Size sz = get<1>(params);
+
+    Mat frame1(sz, CV_8U);
+    Mat frame2(sz, CV_8U);
+    Mat flow;
+
+    MakeArtificialExample(frame1, frame2);
+
+    cv::setNumThreads(cv::getNumberOfCPUs());
+    TEST_CYCLE_N(10)
+    {
+        Ptr<DenseOpticalFlow> algo = createOptFlow_DIS(preset);
+        algo->calc(frame1, frame2, flow);
+    }
+
+    SANITY_CHECK_NOTHING();
+}
+
+void MakeArtificialExample(Mat &dst_frame1, Mat &dst_frame2)
+{
+    int src_scale = 2;
+    int OF_scale = 6;
+    double sigma = dst_frame1.cols / 300;
+
+    Mat tmp(Size(dst_frame1.cols / (int)pow(2, src_scale), dst_frame1.rows / (int)pow(2, src_scale)), CV_8U);
+    randu(tmp, 0, 255);
+    resize(tmp, dst_frame1, dst_frame1.size(), 0.0, 0.0, INTER_LINEAR);
+    resize(tmp, dst_frame2, dst_frame2.size(), 0.0, 0.0, INTER_LINEAR);
+
+    Mat displacement_field(Size(dst_frame1.cols / (int)pow(2, OF_scale), dst_frame1.rows / (int)pow(2, OF_scale)),
+                           CV_32FC2);
+    randn(displacement_field, 0.0, sigma);
+    resize(displacement_field, displacement_field, dst_frame2.size(), 0.0, 0.0, INTER_CUBIC);
+    for (int i = 0; i < displacement_field.rows; i++)
+        for (int j = 0; j < displacement_field.cols; j++)
+            displacement_field.at<Vec2f>(i, j) += Vec2f((float)j, (float)i);
+
+    remap(dst_frame2, dst_frame2, displacement_field, Mat(), INTER_LINEAR, BORDER_REPLICATE);
+}
diff --git a/contrib/modules/optflow/perf/perf_main.cpp b/contrib/modules/optflow/perf/perf_main.cpp
new file mode 100644
index 0000000..0fbf990
--- /dev/null
+++ b/contrib/modules/optflow/perf/perf_main.cpp
@@ -0,0 +1,3 @@
+#include "perf_precomp.hpp"
+
+CV_PERF_TEST_MAIN(optflow)
diff --git a/contrib/modules/optflow/perf/perf_precomp.hpp b/contrib/modules/optflow/perf/perf_precomp.hpp
new file mode 100644
index 0000000..79e2f05
--- /dev/null
+++ b/contrib/modules/optflow/perf/perf_precomp.hpp
@@ -0,0 +1,17 @@
+#ifdef __GNUC__
+#  pragma GCC diagnostic ignored "-Wmissing-declarations"
+#  if defined __clang__ || defined __APPLE__
+#    pragma GCC diagnostic ignored "-Wmissing-prototypes"
+#    pragma GCC diagnostic ignored "-Wextra"
+#  endif
+#endif
+
+#ifndef __OPENCV_PERF_PRECOMP_HPP__
+#define __OPENCV_PERF_PRECOMP_HPP__
+
+#include "opencv2/ts.hpp"
+#include "opencv2/imgproc.hpp"
+#include "opencv2/optflow.hpp"
+#include "opencv2/highgui.hpp"
+
+#endif
diff --git a/contrib/modules/optflow/perf/perf_variational_refinement.cpp b/contrib/modules/optflow/perf/perf_variational_refinement.cpp
new file mode 100644
index 0000000..613d698
--- /dev/null
+++ b/contrib/modules/optflow/perf/perf_variational_refinement.cpp
@@ -0,0 +1,77 @@
+/*
+*  By downloading, copying, installing or using the software you agree to this license.
+*  If you do not agree to this license, do not download, install,
+*  copy or use the software.
+*
+*
+*  License Agreement
+*  For Open Source Computer Vision Library
+*  (3 - clause BSD License)
+*
+*  Redistribution and use in source and binary forms, with or without modification,
+*  are permitted provided that the following conditions are met :
+*
+*  * Redistributions of source code must retain the above copyright notice,
+*  this list of conditions and the following disclaimer.
+*
+*  * Redistributions in binary form must reproduce the above copyright notice,
+*  this list of conditions and the following disclaimer in the documentation
+*  and / or other materials provided with the distribution.
+*
+*  * Neither the names of the copyright holders nor the names of the contributors
+*  may be used to endorse or promote products derived from this software
+*  without specific prior written permission.
+*
+*  This software is provided by the copyright holders and contributors "as is" and
+*  any express or implied warranties, including, but not limited to, the implied
+*  warranties of merchantability and fitness for a particular purpose are disclaimed.
+*  In no event shall copyright holders or contributors be liable for any direct,
+*  indirect, incidental, special, exemplary, or consequential damages
+*  (including, but not limited to, procurement of substitute goods or services;
+*  loss of use, data, or profits; or business interruption) however caused
+*  and on any theory of liability, whether in contract, strict liability,
+*  or tort(including negligence or otherwise) arising in any way out of
+*  the use of this software, even if advised of the possibility of such damage.
+*/
+
+#include "perf_precomp.hpp"
+
+using std::tr1::tuple;
+using std::tr1::get;
+using namespace perf;
+using namespace testing;
+using namespace cv;
+using namespace cv::optflow;
+
+typedef tuple<Size, int, int> VarRefParams;
+typedef TestBaseWithParam<VarRefParams> DenseOpticalFlow_VariationalRefinement;
+
+PERF_TEST_P(DenseOpticalFlow_VariationalRefinement, perf, Combine(Values(szQVGA, szVGA), Values(5, 10), Values(5, 10)))
+{
+    VarRefParams params = GetParam();
+    Size sz = get<0>(params);
+    int sorIter = get<1>(params);
+    int fixedPointIter = get<2>(params);
+
+    Mat frame1(sz, CV_8U);
+    Mat frame2(sz, CV_8U);
+    Mat flow(sz, CV_32FC2);
+
+    randu(frame1, 0, 255);
+    randu(frame2, 0, 255);
+    flow.setTo(0.0f);
+
+    cv::setNumThreads(cv::getNumberOfCPUs());
+    TEST_CYCLE_N(10)
+    {
+        Ptr<VariationalRefinement> var = createVariationalFlowRefinement();
+        var->setAlpha(20.0f);
+        var->setGamma(10.0f);
+        var->setDelta(5.0f);
+        var->setSorIterations(sorIter);
+        var->setFixedPointIterations(fixedPointIter);
+        var->calc(frame1, frame2, flow);
+    }
+
+    SANITY_CHECK_NOTHING();
+}
diff --git a/contrib/modules/optflow/samples/gpc_evaluate.cpp b/contrib/modules/optflow/samples/gpc_evaluate.cpp
new file mode 100644
index 0000000..7a53e8f
--- /dev/null
+++ b/contrib/modules/optflow/samples/gpc_evaluate.cpp
@@ -0,0 +1,164 @@
+#include "opencv2/core/ocl.hpp"
+#include "opencv2/highgui.hpp"
+#include "opencv2/imgcodecs.hpp"
+#include "opencv2/optflow.hpp"
+#include <fstream>
+#include <iostream>
+#include <stdio.h>
+
+/* This tool finds correspondences between two images using Global Patch Collider
+ * and calculates error using provided ground truth flow.
+ *
+ * It will look for the file named "forest.yml.gz" with a learned forest.
+ * You can obtain the "forest.yml.gz" either by manually training it using another tool with *_train suffix
+ * or by downloading one of the files trained on some publicly available dataset from here:
+ *
+ * https://drive.google.com/open?id=0B7Hb8cfuzrIIZDFscXVYd0NBNFU
+ */
+
+using namespace cv;
+
+const String keys = "{help h ?     |             | print this message}"
+                    "{@image1      |<none>       | image1}"
+                    "{@image2      |<none>       | image2}"
+                    "{@groundtruth |<none>       | path to the .flo file}"
+                    "{@output      |             | output to a file instead of displaying, output image path}"
+                    "{g gpu        |             | use OpenCL}"
+                    "{f forest     |forest.yml.gz| path to the forest.yml.gz}";
+
+const int nTrees = 5;
+
+static double normL2( const Point2f &v ) { return sqrt( v.x * v.x + v.y * v.y ); }
+
+static Vec3d getFlowColor( const Point2f &f, const bool logScale = true, const double scaleDown = 5 )
+{
+  if ( f.x == 0 && f.y == 0 )
+    return Vec3d( 0, 0, 1 );
+
+  double radius = normL2( f );
+  if ( logScale )
+    radius = log( radius + 1 );
+  radius /= scaleDown;
+  radius = std::min( 1.0, radius );
+
+  double angle = ( atan2( -f.y, -f.x ) + CV_PI ) * 180 / CV_PI;
+  return Vec3d( angle, radius, 1 );
+}
+
+static void displayFlow( InputArray _flow, OutputArray _img )
+{
+  const Size sz = _flow.size();
+  Mat flow = _flow.getMat();
+  _img.create( sz, CV_32FC3 );
+  Mat img = _img.getMat();
+
+  for ( int i = 0; i < sz.height; ++i )
+    for ( int j = 0; j < sz.width; ++j )
+      img.at< Vec3f >( i, j ) = getFlowColor( flow.at< Point2f >( i, j ) );
+
+  cvtColor( img, img, COLOR_HSV2BGR );
+}
+
+static bool fileProbe( const char *name ) { return std::ifstream( name ).good(); }
+
+int main( int argc, const char **argv )
+{
+  CommandLineParser parser( argc, argv, keys );
+  parser.about( "Global Patch Collider evaluation tool" );
+
+  if ( parser.has( "help" ) )
+  {
+    parser.printMessage();
+    return 0;
+  }
+
+  String fromPath = parser.get< String >( 0 );
+  String toPath = parser.get< String >( 1 );
+  String gtPath = parser.get< String >( 2 );
+  String outPath = parser.get< String >( 3 );
+  const bool useOpenCL = parser.has( "gpu" );
+  String forestDumpPath = parser.get< String >( "forest" );
+
+  if ( !parser.check() )
+  {
+    parser.printErrors();
+    return 1;
+  }
+
+  if ( !fileProbe( forestDumpPath.c_str() ) )
+  {
+    std::cerr << "Can't open the file with a trained model: `" << forestDumpPath
+              << "`.\nYou can obtain this file either by manually training the model using another tool with *_train suffix or by "
+                 "downloading one of the files trained on some publicly available dataset from "
+                 "here:\nhttps://drive.google.com/open?id=0B7Hb8cfuzrIIZDFscXVYd0NBNFU"
+              << std::endl;
+    return 1;
+  }
+
+  ocl::setUseOpenCL( useOpenCL );
+
+  Ptr< optflow::GPCForest< nTrees > > forest = Algorithm::load< optflow::GPCForest< nTrees > >( forestDumpPath );
+
+  Mat from = imread( fromPath );
+  Mat to = imread( toPath );
+  Mat gt = optflow::readOpticalFlow( gtPath );
+  std::vector< std::pair< Point2i, Point2i > > corr;
+
+  TickMeter meter;
+  meter.start();
+
+  forest->findCorrespondences( from, to, corr, optflow::GPCMatchingParams( useOpenCL ) );
+
+  meter.stop();
+
+  std::cout << "Found " << corr.size() << " matches." << std::endl;
+  std::cout << "Time:  " << meter.getTimeSec() << " sec." << std::endl;
+  double error = 0;
+  Mat dispErr = Mat::zeros( from.size(), CV_32FC3 );
+  dispErr = Scalar( 0, 0, 1 );
+  Mat disp = Mat::zeros( from.size(), CV_32FC3 );
+  disp = Scalar( 0, 0, 1 );
+
+  for ( size_t i = 0; i < corr.size(); ++i )
+  {
+    const Point2f a = corr[i].first;
+    const Point2f b = corr[i].second;
+    const Point2f c = a + gt.at< Point2f >( corr[i].first.y, corr[i].first.x );
+    error += normL2( b - c );
+    circle( disp, a, 3, getFlowColor( b - a ), -1 );
+    circle( dispErr, a, 3, getFlowColor( b - c, false, 32 ), -1 );
+  }
+
+  error /= corr.size();
+
+  std::cout << "Average endpoint error: " << error << " px." << std::endl;
+
+  cvtColor( disp, disp, COLOR_HSV2BGR );
+  cvtColor( dispErr, dispErr, COLOR_HSV2BGR );
+
+  Mat dispGroundTruth;
+  displayFlow( gt, dispGroundTruth );
+
+  if ( outPath.length() )
+  {
+    putText( disp, "Sparse matching: Global Patch Collider", Point2i( 24, 40 ), FONT_HERSHEY_DUPLEX, 1, Vec3b( 1, 0, 0 ), 2, LINE_AA );
+    char buf[256];
+    sprintf( buf, "Average EPE: %.2f", error );
+    putText( disp, buf, Point2i( 24, 80 ), FONT_HERSHEY_DUPLEX, 1, Vec3b( 1, 0, 0 ), 2, LINE_AA );
+    sprintf( buf, "Number of matches: %u", (unsigned)corr.size() );
+    putText( disp, buf, Point2i( 24, 120 ), FONT_HERSHEY_DUPLEX, 1, Vec3b( 1, 0, 0 ), 2, LINE_AA );
+    disp *= 255;
+    imwrite( outPath, disp );
+    return 0;
+  }
+
+  namedWindow( "Correspondences", WINDOW_AUTOSIZE );
+  imshow( "Correspondences", disp );
+  namedWindow( "Error", WINDOW_AUTOSIZE );
+  imshow( "Error", dispErr );
+  namedWindow( "Ground truth", WINDOW_AUTOSIZE );
+  imshow( "Ground truth", dispGroundTruth );
+  waitKey( 0 );
+
+  return 0;
+}
diff --git a/contrib/modules/optflow/samples/gpc_train.cpp b/contrib/modules/optflow/samples/gpc_train.cpp
new file mode 100644
index 0000000..6557eb5
--- /dev/null
+++ b/contrib/modules/optflow/samples/gpc_train.cpp
@@ -0,0 +1,66 @@
+#include "opencv2/optflow.hpp"
+#include <iostream>
+
+/* This tool trains the forest for the Global Patch Collider and stores output to the "forest.yml.gz".
+ */
+
+using namespace cv;
+
+const String keys = "{help h ?       |             | print this message}"
+                    "{max-tree-depth |             | Maximum tree depth to stop partitioning}"
+                    "{min-samples    |             | Minimum number of samples in the node to stop partitioning}"
+                    "{descriptor-type|0            | Descriptor type. Set to 0 for quality, 1 for speed.}"
+                    "{print-progress |             | Set to 0 to enable quiet mode, set to 1 to print progress}"
+                    "{f forest       |forest.yml.gz| Path where to store resulting forest. It is recommended to use .yml.gz extension.}";
+
+const int nTrees = 5;
+
+static void fillInputImagesFromCommandLine( std::vector< String > &img1, std::vector< String > &img2, std::vector< String > &gt, int argc,
+                                            const char **argv )
+{
+  for ( int i = 1, j = 0; i < argc; ++i )
+  {
+    if ( argv[i][0] == '-' )
+      continue;
+    if ( j % 3 == 0 )
+      img1.push_back( argv[i] );
+    if ( j % 3 == 1 )
+      img2.push_back( argv[i] );
+    if ( j % 3 == 2 )
+      gt.push_back( argv[i] );
+    ++j;
+  }
+}
+
+int main( int argc, const char **argv )
+{
+  CommandLineParser parser( argc, argv, keys );
+  parser.about( "Global Patch Collider training tool" );
+
+  std::vector< String > img1, img2, gt;
+  optflow::GPCTrainingParams params;
+
+  if ( parser.has( "max-tree-depth" ) )
+    params.maxTreeDepth = parser.get< unsigned >( "max-tree-depth" );
+  if ( parser.has( "min-samples" ) )
+    params.minNumberOfSamples = parser.get< unsigned >( "min-samples" );
+  if ( parser.has( "descriptor-type" ) )
+    params.descriptorType = parser.get< int >( "descriptor-type" );
+  if ( parser.has( "print-progress" ) )
+    params.printProgress = parser.get< unsigned >( "print-progress" ) != 0;
+
+  fillInputImagesFromCommandLine( img1, img2, gt, argc, argv );
+
+  if ( parser.has( "help" ) || img1.size() != img2.size() || img1.size() != gt.size() || img1.size() == 0 )
+  {
+    std::cerr << "\nUsage: " << argv[0] << " [params] ImageFrom1 ImageTo1 GroundTruth1 ... ImageFromN ImageToN GroundTruthN\n" << std::endl;
+    parser.printMessage();
+    return 1;
+  }
+
+  Ptr< optflow::GPCForest< nTrees > > forest = optflow::GPCForest< nTrees >::create();
+  forest->train( img1, img2, gt, params );
+  forest->save( parser.get< String >( "forest" ) );
+
+  return 0;
+}
diff --git a/contrib/modules/optflow/samples/gpc_train_middlebury.py b/contrib/modules/optflow/samples/gpc_train_middlebury.py
new file mode 100644
index 0000000..e923258
--- /dev/null
+++ b/contrib/modules/optflow/samples/gpc_train_middlebury.py
@@ -0,0 +1,58 @@
+import argparse
+import glob
+import os
+import subprocess
+
+
+def execute(cmd):
+    popen = subprocess.Popen(cmd,
+                             stdout=subprocess.PIPE,
+                             stderr=subprocess.PIPE)
+    for stdout_line in iter(popen.stdout.readline, ''):
+        print(stdout_line.rstrip())
+    for stderr_line in iter(popen.stderr.readline, ''):
+        print(stderr_line.rstrip())
+    popen.stdout.close()
+    popen.stderr.close()
+    return_code = popen.wait()
+    if return_code != 0:
+        raise subprocess.CalledProcessError(return_code, cmd)
+
+
+def main():
+    parser = argparse.ArgumentParser(
+        description='Train Global Patch Collider using Middlebury dataset')
+    parser.add_argument(
+        '--bin_path',
+        help='Path to the training executable (example_optflow_gpc_train)',
+        required=True)
+    parser.add_argument('--dataset_path',
+                        help='Path to the directory with frames',
+                        required=True)
+    parser.add_argument('--gt_path',
+                        help='Path to the directory with ground truth flow',
+                        required=True)
+    parser.add_argument('--descriptor_type',
+                        help='Descriptor type',
+                        type=int,
+                        default=0)
+    args = parser.parse_args()
+    seq = glob.glob(os.path.join(args.dataset_path, '*'))
+    seq.sort()
+    input_files = []
+    for s in seq:
+        if os.path.isdir(s):
+            seq_name = os.path.basename(s)
+            frames = glob.glob(os.path.join(s, 'frame*.png'))
+            frames.sort()
+            assert (len(frames) == 2)
+            assert (os.path.basename(frames[0]) == 'frame10.png')
+            assert (os.path.basename(frames[1]) == 'frame11.png')
+            gt_flow = os.path.join(args.gt_path, seq_name, 'flow10.flo')
+            if os.path.isfile(gt_flow):
+                input_files += [frames[0], frames[1], gt_flow]
+    execute([args.bin_path, '--descriptor-type=%d' % args.descriptor_type] + input_files)
+
+
+if __name__ == '__main__':
+    main()
diff --git a/contrib/modules/optflow/samples/gpc_train_sintel.py b/contrib/modules/optflow/samples/gpc_train_sintel.py
new file mode 100644
index 0000000..1f1c5d8
--- /dev/null
+++ b/contrib/modules/optflow/samples/gpc_train_sintel.py
@@ -0,0 +1,60 @@
+import argparse
+import glob
+import os
+import subprocess
+
+FRAME_DIST = 2
+
+assert (FRAME_DIST >= 1)
+
+
+def execute(cmd):
+    popen = subprocess.Popen(cmd,
+                             stdout=subprocess.PIPE,
+                             stderr=subprocess.PIPE)
+    for stdout_line in iter(popen.stdout.readline, ''):
+        print(stdout_line.rstrip())
+    for stderr_line in iter(popen.stderr.readline, ''):
+        print(stderr_line.rstrip())
+    popen.stdout.close()
+    popen.stderr.close()
+    return_code = popen.wait()
+    if return_code != 0:
+        raise subprocess.CalledProcessError(return_code, cmd)
+
+
+def main():
+    parser = argparse.ArgumentParser(
+        description='Train Global Patch Collider using MPI Sintel dataset')
+    parser.add_argument(
+        '--bin_path',
+        help='Path to the training executable (example_optflow_gpc_train)',
+        required=True)
+    parser.add_argument('--dataset_path',
+                        help='Path to the directory with frames',
+                        required=True)
+    parser.add_argument('--gt_path',
+                        help='Path to the directory with ground truth flow',
+                        required=True)
+    parser.add_argument('--descriptor_type',
+                        help='Descriptor type',
+                        type=int,
+                        default=0)
+    args = parser.parse_args()
+    seq = glob.glob(os.path.join(args.dataset_path, '*'))
+    seq.sort()
+    input_files = []
+    for s in seq:
+        seq_name = os.path.basename(s)
+        frames = glob.glob(os.path.join(s, 'frame*.png'))
+        frames.sort()
+        for i in range(0, len(frames) - 1, FRAME_DIST):
+            gt_flow = os.path.join(args.gt_path, seq_name,
+                                   os.path.basename(frames[i])[0:-4] + '.flo')
+            assert (os.path.isfile(gt_flow))
+            input_files += [frames[i], frames[i + 1], gt_flow]
+    execute([args.bin_path, '--descriptor-type=%d' % args.descriptor_type] + input_files)
+
+
+if __name__ == '__main__':
+    main()
diff --git a/contrib/modules/optflow/samples/motempl.py b/contrib/modules/optflow/samples/motempl.py
index ce9b666..88fedf4 100755
--- a/contrib/modules/optflow/samples/motempl.py
+++ b/contrib/modules/optflow/samples/motempl.py
@@ -1,15 +1,16 @@
 #!/usr/bin/env python
-
 import numpy as np
 import cv2
-import video
-from common import nothing, clock, draw_str
 
 MHI_DURATION = 0.5
 DEFAULT_THRESHOLD = 32
 MAX_TIME_DELTA = 0.25
 MIN_TIME_DELTA = 0.05
 
+# (empty) trackbar callback
+def nothing(dummy):
+    pass
+
 def draw_motion_comp(vis, (x, y, w, h), angle, color):
     cv2.rectangle(vis, (x, y), (x+w, y+h), (0, 255, 0))
     r = min(w/2, h/2)
@@ -30,8 +31,13 @@ if __name__ == '__main__':
     cv2.createTrackbar('visual', 'motempl', 2, len(visuals)-1, nothing)
     cv2.createTrackbar('threshold', 'motempl', DEFAULT_THRESHOLD, 255, nothing)
 
-    cam = video.create_capture(video_src, fallback='synth:class=chess:bg=../cpp/lena.jpg:noise=0.01')
+    cam = cv2.VideoCapture(video_src)
+    if not cam.isOpened():
+        print("could not open video_src " + str(video_src) + " !\n")
+        sys.exit(1)
     ret, frame = cam.read()
+    if ret == False:
+        break
     h, w = frame.shape[:2]
     prev_frame = frame.copy()
     motion_history = np.zeros((h, w), np.float32)
@@ -43,10 +49,10 @@ if __name__ == '__main__':
         gray_diff = cv2.cvtColor(frame_diff, cv2.COLOR_BGR2GRAY)
         thrs = cv2.getTrackbarPos('threshold', 'motempl')
         ret, motion_mask = cv2.threshold(gray_diff, thrs, 1, cv2.THRESH_BINARY)
-        timestamp = clock()
-        cv2.updateMotionHistory(motion_mask, motion_history, timestamp, MHI_DURATION)
-        mg_mask, mg_orient = cv2.calcMotionGradient( motion_history, MAX_TIME_DELTA, MIN_TIME_DELTA, apertureSize=5 )
-        seg_mask, seg_bounds = cv2.segmentMotion(motion_history, timestamp, MAX_TIME_DELTA)
+        timestamp = cv2.getTickCount() / cv2.getTickFrequency()
+        cv2.motempl.updateMotionHistory(motion_mask, motion_history, timestamp, MHI_DURATION)
+        mg_mask, mg_orient = cv2.motempl.calcMotionGradient( motion_history, MAX_TIME_DELTA, MIN_TIME_DELTA, apertureSize=5 )
+        seg_mask, seg_bounds = cv2.motempl.segmentMotion(motion_history, timestamp, MAX_TIME_DELTA)
 
         visual_name = visuals[cv2.getTrackbarPos('visual', 'motempl')]
         if visual_name == 'input':
@@ -72,11 +78,11 @@ if __name__ == '__main__':
             mhi_roi    = motion_history[y:y+rh,x:x+rw]
             if cv2.norm(silh_roi, cv2.NORM_L1) < area*0.05:
                 continue
-            angle = cv2.calcGlobalOrientation(orient_roi, mask_roi, mhi_roi, timestamp, MHI_DURATION)
+            angle = cv2.motempl.calcGlobalOrientation(orient_roi, mask_roi, mhi_roi, timestamp, MHI_DURATION)
             color = ((255, 0, 0), (0, 0, 255))[i == 0]
             draw_motion_comp(vis, rect, angle, color)
 
-        draw_str(vis, (20, 20), visual_name)
+        cv2.putText(vis, visual_name, (20, 20), cv2.FONT_HERSHEY_PLAIN, 1.0, (200,0,0))
         cv2.imshow('motempl', vis)
 
         prev_frame = frame.copy()
diff --git a/contrib/modules/optflow/samples/optical_flow_benchmark.py b/contrib/modules/optflow/samples/optical_flow_benchmark.py
new file mode 100644
index 0000000..a463642
--- /dev/null
+++ b/contrib/modules/optflow/samples/optical_flow_benchmark.py
@@ -0,0 +1,268 @@
+#!/usr/bin/env python
+from __future__ import print_function
+import os, sys, shutil
+import argparse
+import json, re
+from subprocess import check_output
+import datetime
+import matplotlib.pyplot as plt
+
+
+def load_json(path):
+    f = open(path, "r")
+    data = json.load(f)
+    return data
+
+
+def save_json(obj, path):
+    tmp_file = path + ".bak"
+    f = open(tmp_file, "w")
+    json.dump(obj, f, indent=2)
+    f.flush()
+    os.fsync(f.fileno())
+    f.close()
+    try:
+        os.rename(tmp_file, path)
+    except:
+        os.remove(path)
+        os.rename(tmp_file, path)
+
+
+def parse_evaluation_result(input_str, i):
+    res = {}
+    res['frame_number'] = i + 1
+    res['error'] = {}
+    regex = "([A-Za-z. \\[\\].0-9]+):[ ]*([0-9]*\.[0-9]+|[0-9]+)"
+    for elem in re.findall(regex,input_str):
+        if "Time" in elem[0]:
+            res['time'] = float(elem[1])
+        elif "Average" in elem[0]:
+            res['error']['average'] = float(elem[1])
+        elif "deviation" in elem[0]:
+            res['error']['std'] = float(elem[1])
+        else:
+            res['error'][elem[0]] = float(elem[1])
+    return res
+
+
+def evaluate_sequence(sequence, algorithm, dataset, executable, img_files, gt_files,
+                      state, state_path):
+    if "eval_results" not in state[dataset][algorithm][-1].keys():
+        state[dataset][algorithm][-1]["eval_results"] = {}
+    elif sequence in state[dataset][algorithm][-1]["eval_results"].keys():
+        return
+
+    res = []
+    for i in range(len(img_files) - 1):
+        sys.stdout.write("Algorithm: %-20s Sequence: %-10s Done: [%3d/%3d]\r" %
+                         (algorithm, sequence, i, len(img_files) - 1)),
+        sys.stdout.flush()
+
+        res_string = check_output([executable, img_files[i], img_files[i + 1],
+                                   algorithm, gt_files[i]])
+        res.append(parse_evaluation_result(res_string, i))
+    state[dataset][algorithm][-1]["eval_results"][sequence] = res
+    save_json(state, state_path)
+
+#############################DATSET DEFINITIONS################################
+
+def evaluate_mpi_sintel(source_dir, algorithm, evaluation_executable, state, state_path):
+    evaluation_result = {}
+    img_dir = os.path.join(source_dir, 'mpi_sintel', 'training', 'final')
+    gt_dir = os.path.join(source_dir, 'mpi_sintel', 'training', 'flow')
+    sequences = [f for f in os.listdir(img_dir)
+                 if os.path.isdir(os.path.join(img_dir, f))]
+    for seq in sequences:
+        img_files = sorted([os.path.join(img_dir, seq, f)
+                            for f in os.listdir(os.path.join(img_dir, seq))
+                            if f.endswith(".png")])
+        gt_files = sorted([os.path.join(gt_dir, seq, f)
+                           for f in os.listdir(os.path.join(gt_dir, seq))
+                           if f.endswith(".flo")])
+        evaluation_result[seq] = evaluate_sequence(seq, algorithm, 'mpi_sintel',
+            evaluation_executable, img_files, gt_files, state, state_path)
+    return evaluation_result
+
+
+def evaluate_middlebury(source_dir, algorithm, evaluation_executable, state, state_path):
+    evaluation_result = {}
+    img_dir = os.path.join(source_dir, 'middlebury', 'other-data')
+    gt_dir = os.path.join(source_dir, 'middlebury', 'other-gt-flow')
+    sequences = [f for f in os.listdir(gt_dir)
+                 if os.path.isdir(os.path.join(gt_dir, f))]
+    for seq in sequences:
+        img_files = sorted([os.path.join(img_dir, seq, f)
+                            for f in os.listdir(os.path.join(img_dir, seq))
+                            if f.endswith(".png")])
+        gt_files = sorted([os.path.join(gt_dir, seq, f)
+                           for f in os.listdir(os.path.join(gt_dir, seq))
+                           if f.endswith(".flo")])
+        evaluation_result[seq] = evaluate_sequence(seq, algorithm, 'middlebury',
+            evaluation_executable, img_files, gt_files, state, state_path)
+    return evaluation_result
+
+
+dataset_eval_functions = {
+    "mpi_sintel": evaluate_mpi_sintel,
+    "middlebury": evaluate_middlebury
+}
+
+###############################################################################
+
+def create_dir(dir):
+    if not os.path.exists(dir):
+        os.makedirs(dir)
+
+
+def parse_sequence(input_str):
+    if len(input_str) == 0:
+        return []
+    else:
+        return [o.strip() for o in input_str.split(",") if o]
+
+
+def build_chart(dst_folder, state, dataset):
+    fig = plt.figure(figsize=(16, 10))
+    markers = ["o", "s", "h", "^", "D"]
+    marker_idx = 0
+    colors = ["b", "g", "r"]
+    color_idx = 0
+    for algo in state[dataset].keys():
+        for eval_instance in state[dataset][algo]:
+            name = algo + "--" + eval_instance["timestamp"]
+            average_time = 0.0
+            average_error = 0.0
+            num_elem = 0
+            for seq in eval_instance["eval_results"].keys():
+                for frame in eval_instance["eval_results"][seq]:
+                    average_time += frame["time"]
+                    average_error += frame["error"]["average"]
+                    num_elem += 1
+            average_time /= num_elem
+            average_error /= num_elem
+
+            marker_style = colors[color_idx] + markers[marker_idx]
+            color_idx += 1
+            if color_idx >= len(colors):
+                color_idx = 0
+            marker_idx += 1
+            if marker_idx >= len(markers):
+                marker_idx = 0
+            plt.gca().plot([average_time], [average_error],
+                           marker_style,
+                           markersize=14,
+                           label=name)
+
+    plt.gca().set_ylabel('Average Endpoint Error (EPE)', fontsize=20)
+    plt.gca().set_xlabel('Average Runtime (seconds per frame)', fontsize=20)
+    plt.gca().set_xscale("log")
+    plt.gca().set_title('Evaluation on ' + dataset, fontsize=20)
+
+    plt.gca().legend()
+    fig.savefig(os.path.join(dst_folder, "evaluation_results_" + dataset + ".png"),
+                bbox_inches='tight')
+    plt.close()
+
+
+if __name__ == '__main__':
+    parser = argparse.ArgumentParser(
+        description='Optical flow benchmarking script',
+        formatter_class=argparse.RawDescriptionHelpFormatter)
+    parser.add_argument(
+        "bin_path",
+        default="./optflow-example-optical_flow_evaluation",
+        help="Path to the optical flow evaluation executable")
+    parser.add_argument(
+        "-a",
+        "--algorithms",
+        metavar="ALGORITHMS",
+        default="",
+        help=("Comma-separated list of optical-flow algorithms to evaluate "
+              "(example: -a farneback,tvl1,deepflow). Note that previously "
+              "evaluated algorithms are also included in the output charts"))
+    parser.add_argument(
+        "-d",
+        "--datasets",
+        metavar="DATASETS",
+        default="mpi_sintel",
+        help=("Comma-separated list of datasets for evaluation (currently only "
+              "'mpi_sintel' and 'middlebury' are supported)"))
+    parser.add_argument(
+        "-f",
+        "--dataset_folder",
+        metavar="DATASET_FOLDER",
+        default="./OF_datasets",
+        help=("Path to a folder containing datasets. To enable evaluation on "
+              "MPI Sintel dataset, please download it using the following links: "
+              "http://files.is.tue.mpg.de/sintel/MPI-Sintel-training_images.zip and "
+              "http://files.is.tue.mpg.de/sintel/MPI-Sintel-training_extras.zip and "
+              "unzip these archives into the 'mpi_sintel' folder. To enable evaluation "
+              "on the Middlebury dataset use the following links: "
+              "http://vision.middlebury.edu/flow/data/comp/zip/other-color-twoframes.zip, "
+              "http://vision.middlebury.edu/flow/data/comp/zip/other-gt-flow.zip. "
+              "These should be unzipped into 'middlebury' folder"))
+    parser.add_argument(
+        "-o",
+        "--out",
+        metavar="OUT_DIR",
+        default="./OF_evaluation_results",
+        help="Output directory where to store benchmark results")
+    parser.add_argument(
+        "-s",
+        "--state",
+        metavar="STATE_JSON",
+        default="./OF_evaluation_state.json",
+        help=("Path to a json file that stores the current evaluation state and "
+              "previous evaluation results"))
+    args, other_args = parser.parse_known_args()
+
+    if not os.path.isfile(args.bin_path):
+        print("Error: " + args.bin_path + " does not exist")
+        sys.exit(1)
+
+    if not os.path.exists(args.dataset_folder):
+        print("Error: " + args.dataset_folder + (" does not exist. Please, correctly "
+                                                 "specify the -f parameter"))
+        sys.exit(1)
+
+    state = {}
+    if os.path.isfile(args.state):
+        state = load_json(args.state)
+
+    algorithm_list = parse_sequence(args.algorithms)
+    dataset_list = parse_sequence(args.datasets)
+    for dataset in dataset_list:
+        if dataset not in dataset_eval_functions.keys():
+            print("Error: unsupported dataset " + dataset)
+            sys.exit(1)
+        if dataset not in os.listdir(args.dataset_folder):
+            print("Error: " + os.path.join(args.dataset_folder, dataset) + (" does not exist. "
+                              "Please, download the dataset and follow the naming conventions "
+                              "(use -h for more information)"))
+            sys.exit(1)
+
+    for dataset in dataset_list:
+        if dataset not in state.keys():
+            state[dataset] = {}
+        for algorithm in algorithm_list:
+            if algorithm in state[dataset].keys():
+                last_eval_instance = state[dataset][algorithm][-1]
+                if "finished" not in last_eval_instance.keys():
+                    print(("Continuing an unfinished evaluation of " +
+                          algorithm + " started at " + last_eval_instance["timestamp"]))
+                else:
+                    state[dataset][algorithm].append({"timestamp":
+                        datetime.datetime.now().strftime("%Y-%m-%d--%H-%M")})
+            else:
+                state[dataset][algorithm] = [{"timestamp":
+                    datetime.datetime.now().strftime("%Y-%m-%d--%H-%M")}]
+            save_json(state, args.state)
+            dataset_eval_functions[dataset](args.dataset_folder, algorithm, args.bin_path,
+                                            state, args.state)
+            state[dataset][algorithm][-1]["finished"] = True
+            save_json(state, args.state)
+    save_json(state, args.state)
+
+    create_dir(args.out)
+    for dataset in dataset_list:
+        build_chart(args.out, state, dataset)
diff --git a/contrib/modules/optflow/samples/optical_flow_evaluation.cpp b/contrib/modules/optflow/samples/optical_flow_evaluation.cpp
index 4ecc798..cdd641f 100644
--- a/contrib/modules/optflow/samples/optical_flow_evaluation.cpp
+++ b/contrib/modules/optflow/samples/optical_flow_evaluation.cpp
@@ -1,7 +1,9 @@
 #include "opencv2/highgui.hpp"
 #include "opencv2/video.hpp"
 #include "opencv2/optflow.hpp"
+#include "opencv2/core/ocl.hpp"
 #include <fstream>
+#include <limits>
 
 using namespace std;
 using namespace cv;
@@ -10,11 +12,13 @@ using namespace optflow;
 const String keys = "{help h usage ? |      | print this message   }"
         "{@image1        |      | image1               }"
         "{@image2        |      | image2               }"
-        "{@algorithm     |      | [farneback, simpleflow, tvl1, deepflow or sparsetodenseflow] }"
+        "{@algorithm     |      | [farneback, simpleflow, tvl1, deepflow, sparsetodenseflow, pcaflow, DISflow_ultrafast, DISflow_fast, DISflow_medium] }"
         "{@groundtruth   |      | path to the .flo file  (optional), Middlebury format }"
         "{m measure      |endpoint| error measure - [endpoint or angular] }"
         "{r region       |all   | region to compute stats about [all, discontinuities, untextured] }"
-        "{d display      |      | display additional info images (pauses program execution) }";
+        "{d display      |      | display additional info images (pauses program execution) }"
+        "{g gpu          |      | use OpenCL}"
+        "{prior          |      | path to a prior file for PCAFlow}";
 
 inline bool isFlowCorrect( const Point2f u )
 {
@@ -40,7 +44,7 @@ static Mat endpointError( const Mat_<Point2f>& flow1, const Mat_<Point2f>& flow2
                 const Point2f diff = u1 - u2;
                 result.at<float>(i, j) = sqrt((float)diff.ddot(diff)); //distance
             } else
-                result.at<float>(i, j) = NAN;
+                result.at<float>(i, j) = std::numeric_limits<float>::quiet_NaN();
         }
     }
     return result;
@@ -61,7 +65,7 @@ static Mat angularError( const Mat_<Point2f>& flow1, const Mat_<Point2f>& flow2
             if ( isFlowCorrect(u1) && isFlowCorrect(u2) )
                 result.at<float>(i, j) = acos((float)(u1.ddot(u2) / norm(u1) * norm(u2)));
             else
-                result.at<float>(i, j) = NAN;
+                result.at<float>(i, j) = std::numeric_limits<float>::quiet_NaN();
         }
     }
     return result;
@@ -199,6 +203,7 @@ int main( int argc, char** argv )
     String error_measure = parser.get<String>("measure");
     String region = parser.get<String>("region");
     bool display_images = parser.has("display");
+    const bool useGpu = parser.has("gpu");
 
     if ( !parser.check() )
     {
@@ -206,6 +211,9 @@ int main( int argc, char** argv )
         return 0;
     }
 
+    cv::ocl::setUseOpenCL(useGpu);
+    printf("OpenCL Enabled: %u\n", useGpu && cv::ocl::haveOpenCL());
+
     Mat i1, i2;
     Mat_<Point2f> flow, ground_truth;
     Mat computed_errors;
@@ -228,7 +236,7 @@ int main( int argc, char** argv )
     if ( i2.depth() != CV_8U )
         i2.convertTo(i2, CV_8U);
 
-    if ( (method == "farneback" || method == "tvl1" || method == "deepflow") && i1.channels() == 3 )
+    if ( (method == "farneback" || method == "tvl1" || method == "deepflow" || method == "DISflow_ultrafast" || method == "DISflow_fast" || method == "DISflow_medium") && i1.channels() == 3 )
     {   // 1-channel images are expected
         cvtColor(i1, i1, COLOR_BGR2GRAY);
         cvtColor(i2, i2, COLOR_BGR2GRAY);
@@ -251,6 +259,21 @@ int main( int argc, char** argv )
         algorithm = createOptFlow_DeepFlow();
     else if ( method == "sparsetodenseflow" )
         algorithm = createOptFlow_SparseToDense();
+    else if ( method == "pcaflow" ) {
+        if ( parser.has("prior") ) {
+            String prior = parser.get<String>("prior");
+            printf("Using prior file: %s\n", prior.c_str());
+            algorithm = makePtr<OpticalFlowPCAFlow>(makePtr<PCAPrior>(prior.c_str()));
+        }
+        else
+            algorithm = createOptFlow_PCAFlow();
+    }
+    else if ( method == "DISflow_ultrafast" )
+        algorithm = createOptFlow_DIS(DISOpticalFlow::PRESET_ULTRAFAST);
+    else if (method == "DISflow_fast")
+        algorithm = createOptFlow_DIS(DISOpticalFlow::PRESET_FAST);
+    else if (method == "DISflow_medium")
+        algorithm = createOptFlow_DIS(DISOpticalFlow::PRESET_MEDIUM);
     else
     {
         printf("Wrong method!\n");
@@ -260,7 +283,12 @@ int main( int argc, char** argv )
 
     double startTick, time;
     startTick = (double) getTickCount(); // measure time
-    algorithm->calc(i1, i2, flow);
+
+    if (useGpu)
+        algorithm->calc(i1, i2, flow.getUMat(ACCESS_RW));
+    else
+        algorithm->calc(i1, i2, flow);
+
     time = ((double) getTickCount() - startTick) / getTickFrequency();
     printf("\nTime [s]: %.3f\n", time);
     if(display_images)
diff --git a/contrib/modules/optflow/samples/pcaflow_demo.cpp b/contrib/modules/optflow/samples/pcaflow_demo.cpp
new file mode 100644
index 0000000..ea9a607
--- /dev/null
+++ b/contrib/modules/optflow/samples/pcaflow_demo.cpp
@@ -0,0 +1,172 @@
+#include "opencv2/core/ocl.hpp"
+#include "opencv2/highgui.hpp"
+#include "opencv2/imgcodecs.hpp"
+#include "opencv2/optflow.hpp"
+#include <fstream>
+#include <iostream>
+#include <stdio.h>
+
+using namespace cv;
+using optflow::OpticalFlowPCAFlow;
+using optflow::PCAPrior;
+
+const String keys = "{help h ?     |      | print this message}"
+                    "{@image1      |<none>| image1}"
+                    "{@image2      |<none>| image2}"
+                    "{@groundtruth |<none>| path to the .flo file}"
+                    "{@prior       |<none>| path to a prior file for PCAFlow}"
+                    "{@output      |<none>| output image path}"
+                    "{g gpu        |      | use OpenCL}";
+
+static double normL2( const Point2f &v ) { return sqrt( v.x * v.x + v.y * v.y ); }
+
+static bool fileProbe( const char *name ) { return std::ifstream( name ).good(); }
+
+static Vec3d getFlowColor( const Point2f &f, const bool logScale = true, const double scaleDown = 5 )
+{
+  if ( f.x == 0 && f.y == 0 )
+    return Vec3d( 0, 0, 1 );
+
+  double radius = normL2( f );
+  if ( logScale )
+    radius = log( radius + 1 );
+  radius /= scaleDown;
+  radius = std::min( 1.0, radius );
+
+  double angle = ( atan2( -f.y, -f.x ) + CV_PI ) * 180 / CV_PI;
+  return Vec3d( angle, radius, 1 );
+}
+
+static void displayFlow( InputArray _flow, OutputArray _img )
+{
+  const Size sz = _flow.size();
+  Mat flow = _flow.getMat();
+  _img.create( sz, CV_32FC3 );
+  Mat img = _img.getMat();
+
+  for ( int i = 0; i < sz.height; ++i )
+    for ( int j = 0; j < sz.width; ++j )
+      img.at< Vec3f >( i, j ) = getFlowColor( flow.at< Point2f >( i, j ) );
+
+  cvtColor( img, img, COLOR_HSV2BGR );
+}
+
+static bool isFlowCorrect( const Point2f &u )
+{
+  return !cvIsNaN( u.x ) && !cvIsNaN( u.y ) && ( fabs( u.x ) < 1e9 ) && ( fabs( u.y ) < 1e9 );
+}
+
+static double calcEPE( const Mat &f1, const Mat &f2 )
+{
+  double sum = 0;
+  Size sz = f1.size();
+  size_t cnt = 0;
+  for ( int i = 0; i < sz.height; ++i )
+    for ( int j = 0; j < sz.width; ++j )
+      if ( isFlowCorrect( f1.at< Point2f >( i, j ) ) && isFlowCorrect( f2.at< Point2f >( i, j ) ) )
+      {
+        sum += normL2( f1.at< Point2f >( i, j ) - f2.at< Point2f >( i, j ) );
+        ++cnt;
+      }
+  return sum / cnt;
+}
+
+static void displayResult( Mat &i1, Mat &i2, Mat &gt, Ptr< DenseOpticalFlow > &algo, OutputArray _img, const char *descr,
+                           const bool useGpu = false )
+{
+  Mat flow( i1.size[0], i1.size[1], CV_32FC2 );
+  TickMeter meter;
+  meter.start();
+
+  if ( useGpu )
+    algo->calc( i1, i2, flow.getUMat( ACCESS_RW ) );
+  else
+    algo->calc( i1, i2, flow );
+
+  meter.stop();
+  displayFlow( flow, _img );
+  Mat img = _img.getMat();
+  putText( img, descr, Point2i( 24, 40 ), FONT_HERSHEY_DUPLEX, 1, Vec3b( 1, 0, 0 ), 2, LINE_AA );
+  char buf[256];
+  sprintf( buf, "Average EPE: %.2f", calcEPE( flow, gt ) );
+  putText( img, buf, Point2i( 24, 80 ), FONT_HERSHEY_DUPLEX, 1, Vec3b( 1, 0, 0 ), 2, LINE_AA );
+  sprintf( buf, "Time: %.2fs", meter.getTimeSec() );
+  putText( img, buf, Point2i( 24, 120 ), FONT_HERSHEY_DUPLEX, 1, Vec3b( 1, 0, 0 ), 2, LINE_AA );
+}
+
+static void displayGT( InputArray _flow, OutputArray _img, const char *descr )
+{
+  displayFlow( _flow, _img );
+  Mat img = _img.getMat();
+  putText( img, descr, Point2i( 24, 40 ), FONT_HERSHEY_DUPLEX, 1, Vec3b( 1, 0, 0 ), 2, LINE_AA );
+}
+
+int main( int argc, const char **argv )
+{
+  CommandLineParser parser( argc, argv, keys );
+  parser.about( "PCAFlow demonstration" );
+
+  if ( parser.has( "help" ) )
+  {
+    parser.printMessage();
+    return 0;
+  }
+
+  String img1 = parser.get< String >( 0 );
+  String img2 = parser.get< String >( 1 );
+  String groundtruth = parser.get< String >( 2 );
+  String prior = parser.get< String >( 3 );
+  String outimg = parser.get< String >( 4 );
+  const bool useGpu = parser.has( "gpu" );
+
+  if ( !parser.check() )
+  {
+    parser.printErrors();
+    return 1;
+  }
+
+  if ( !fileProbe( prior.c_str() ) )
+  {
+    std::cerr << "Can't open the file with prior! Check the provided path: " << prior << std::endl;
+    return 1;
+  }
+
+  cv::ocl::setUseOpenCL( useGpu );
+
+  Mat i1 = imread( img1 );
+  Mat i2 = imread( img2 );
+  Mat gt = optflow::readOpticalFlow( groundtruth );
+
+  Mat i1g, i2g;
+  cvtColor( i1, i1g, COLOR_BGR2GRAY );
+  cvtColor( i2, i2g, COLOR_BGR2GRAY );
+
+  Mat pcaflowDisp, pcaflowpriDisp, farnebackDisp, gtDisp;
+
+  {
+    Ptr< DenseOpticalFlow > pcaflow = makePtr< OpticalFlowPCAFlow >( makePtr< PCAPrior >( prior.c_str() ) );
+    displayResult( i1, i2, gt, pcaflow, pcaflowpriDisp, "PCAFlow with prior", useGpu );
+  }
+
+  {
+    Ptr< DenseOpticalFlow > pcaflow = makePtr< OpticalFlowPCAFlow >();
+    displayResult( i1, i2, gt, pcaflow, pcaflowDisp, "PCAFlow without prior", useGpu );
+  }
+
+  {
+    Ptr< DenseOpticalFlow > farneback = optflow::createOptFlow_Farneback();
+    displayResult( i1g, i2g, gt, farneback, farnebackDisp, "Farneback", useGpu );
+  }
+
+  displayGT( gt, gtDisp, "Ground truth" );
+
+  Mat disp1, disp2;
+  vconcat( pcaflowpriDisp, farnebackDisp, disp1 );
+  vconcat( pcaflowDisp, gtDisp, disp2 );
+  hconcat( disp1, disp2, disp1 );
+  disp1 *= 255;
+
+  imwrite( outimg, disp1 );
+
+  return 0;
+}
diff --git a/contrib/modules/optflow/samples/video.py b/contrib/modules/optflow/samples/video.py
deleted file mode 100755
index 187bb6d..0000000
--- a/contrib/modules/optflow/samples/video.py
+++ /dev/null
@@ -1,199 +0,0 @@
-#!/usr/bin/env python
-
-'''
-Video capture sample.
-
-Sample shows how VideoCapture class can be used to acquire video
-frames from a camera of a movie file. Also the sample provides
-an example of procedural video generation by an object, mimicking
-the VideoCapture interface (see Chess class).
-
-'create_capture' is a convinience function for capture creation,
-falling back to procedural video in case of error.
-
-Usage:
-    video.py [--shotdir <shot path>] [source0] [source1] ...'
-
-    sourceN is an
-     - integer number for camera capture
-     - name of video file
-     - synth:<params> for procedural video
-
-Synth examples:
-    synth:bg=../cpp/lena.jpg:noise=0.1
-    synth:class=chess:bg=../cpp/lena.jpg:noise=0.1:size=640x480
-
-Keys:
-    ESC    - exit
-    SPACE  - save current frame to <shot path> directory
-
-'''
-
-import numpy as np
-from numpy import pi, sin, cos
-
-import cv2
-
-# built-in modules
-from time import clock
-
-# local modules
-import common
-
-class VideoSynthBase(object):
-    def __init__(self, size=None, noise=0.0, bg = None, **params):
-        self.bg = None
-        self.frame_size = (640, 480)
-        if bg is not None:
-            self.bg = cv2.imread(bg, 1)
-            h, w = self.bg.shape[:2]
-            self.frame_size = (w, h)
-
-        if size is not None:
-            w, h = map(int, size.split('x'))
-            self.frame_size = (w, h)
-            self.bg = cv2.resize(self.bg, self.frame_size)
-
-        self.noise = float(noise)
-
-    def render(self, dst):
-        pass
-
-    def read(self, dst=None):
-        w, h = self.frame_size
-
-        if self.bg is None:
-            buf = np.zeros((h, w, 3), np.uint8)
-        else:
-            buf = self.bg.copy()
-
-        self.render(buf)
-
-        if self.noise > 0.0:
-            noise = np.zeros((h, w, 3), np.int8)
-            cv2.randn(noise, np.zeros(3), np.ones(3)*255*self.noise)
-            buf = cv2.add(buf, noise, dtype=cv2.CV_8UC3)
-        return True, buf
-
-    def isOpened(self):
-        return True
-
-class Chess(VideoSynthBase):
-    def __init__(self, **kw):
-        super(Chess, self).__init__(**kw)
-
-        w, h = self.frame_size
-
-        self.grid_size = sx, sy = 10, 7
-        white_quads = []
-        black_quads = []
-        for i, j in np.ndindex(sy, sx):
-            q = [[j, i, 0], [j+1, i, 0], [j+1, i+1, 0], [j, i+1, 0]]
-            [white_quads, black_quads][(i + j) % 2].append(q)
-        self.white_quads = np.float32(white_quads)
-        self.black_quads = np.float32(black_quads)
-
-        fx = 0.9
-        self.K = np.float64([[fx*w, 0, 0.5*(w-1)],
-                        [0, fx*w, 0.5*(h-1)],
-                        [0.0,0.0,      1.0]])
-
-        self.dist_coef = np.float64([-0.2, 0.1, 0, 0])
-        self.t = 0
-
-    def draw_quads(self, img, quads, color = (0, 255, 0)):
-        img_quads = cv2.projectPoints(quads.reshape(-1, 3), self.rvec, self.tvec, self.K, self.dist_coef) [0]
-        img_quads.shape = quads.shape[:2] + (2,)
-        for q in img_quads:
-            cv2.fillConvexPoly(img, np.int32(q*4), color, cv2.LINE_AA, shift=2)
-
-    def render(self, dst):
-        t = self.t
-        self.t += 1.0/30.0
-
-        sx, sy = self.grid_size
-        center = np.array([0.5*sx, 0.5*sy, 0.0])
-        phi = pi/3 + sin(t*3)*pi/8
-        c, s = cos(phi), sin(phi)
-        ofs = np.array([sin(1.2*t), cos(1.8*t), 0]) * sx * 0.2
-        eye_pos = center + np.array([cos(t)*c, sin(t)*c, s]) * 15.0 + ofs
-        target_pos = center + ofs
-
-        R, self.tvec = common.lookat(eye_pos, target_pos)
-        self.rvec = common.mtx2rvec(R)
-
-        self.draw_quads(dst, self.white_quads, (245, 245, 245))
-        self.draw_quads(dst, self.black_quads, (10, 10, 10))
-
-
-classes = dict(chess=Chess)
-
-presets = dict(
-    empty = 'synth:',
-    lena = 'synth:bg=../cpp/lena.jpg:noise=0.1',
-    chess = 'synth:class=chess:bg=../cpp/lena.jpg:noise=0.1:size=640x480'
-)
-
-
-def create_capture(source = 0, fallback = presets['chess']):
-    '''source: <int> or '<int>|<filename>|synth [:<param_name>=<value> [:...]]'
-    '''
-    source = str(source).strip()
-    chunks = source.split(':')
-    # handle drive letter ('c:', ...)
-    if len(chunks) > 1 and len(chunks[0]) == 1 and chunks[0].isalpha():
-        chunks[1] = chunks[0] + ':' + chunks[1]
-        del chunks[0]
-
-    source = chunks[0]
-    try: source = int(source)
-    except ValueError: pass
-    params = dict( s.split('=') for s in chunks[1:] )
-
-    cap = None
-    if source == 'synth':
-        Class = classes.get(params.get('class', None), VideoSynthBase)
-        try: cap = Class(**params)
-        except: pass
-    else:
-        cap = cv2.VideoCapture(source)
-        if 'size' in params:
-            w, h = map(int, params['size'].split('x'))
-            cap.set(cv2.CAP_PROP_FRAME_WIDTH, w)
-            cap.set(cv2.CAP_PROP_FRAME_HEIGHT, h)
-    if cap is None or not cap.isOpened():
-        print 'Warning: unable to open video source: ', source
-        if fallback is not None:
-            return create_capture(fallback, None)
-    return cap
-
-if __name__ == '__main__':
-    import sys
-    import getopt
-
-    print __doc__
-
-    args, sources = getopt.getopt(sys.argv[1:], '', 'shotdir=')
-    args = dict(args)
-    shotdir = args.get('--shotdir', '.')
-    if len(sources) == 0:
-        sources = [ 0 ]
-
-    caps = map(create_capture, sources)
-    shot_idx = 0
-    while True:
-        imgs = []
-        for i, cap in enumerate(caps):
-            ret, img = cap.read()
-            imgs.append(img)
-            cv2.imshow('capture %d' % i, img)
-        ch = 0xFF & cv2.waitKey(1)
-        if ch == 27:
-            break
-        if ch == ord(' '):
-            for i, img in enumerate(imgs):
-                fn = '%s/shot_%d_%03d.bmp' % (shotdir, i, shot_idx)
-                cv2.imwrite(fn, img)
-                print fn, 'saved'
-            shot_idx += 1
-    cv2.destroyAllWindows()
diff --git a/contrib/modules/optflow/src/deepflow.cpp b/contrib/modules/optflow/src/deepflow.cpp
index 284061a..a813e5a 100644
--- a/contrib/modules/optflow/src/deepflow.cpp
+++ b/contrib/modules/optflow/src/deepflow.cpp
@@ -67,26 +67,12 @@ protected:
     float gamma; // gradient constancy weight
     float omega; // relaxation factor in SOR
 
-    float zeta; // added to the denomimnator of theta_0 (normaliation of the data term)
-    float epsilon; // robust penalizer const
     int maxLayers; // max amount of layers in the pyramid
+    int interpolationType;
 
 private:
-    void calcOneLevel( const Mat I0, const Mat I1, Mat W );
-    Mat warpImage( const Mat input, const Mat flow );
-    void dataTerm( const Mat W, const Mat dW, const Mat Ix, const Mat Iy, const Mat Iz,
-            const Mat Ixx, const Mat Ixy, const Mat Iyy, const Mat Ixz, const Mat Iyz,
-            Mat a11, Mat a12, Mat a22, Mat b1, Mat b2 );
-    void smoothnessWeights( const Mat W, Mat weightsX, Mat weightsY );
-    void smoothnessTerm( const Mat W, const Mat weightsX, const Mat weightsY, Mat b1, Mat b2 );
-    void sorSolve( const Mat a11, const Mat a12, const Mat a22, const Mat b1, const Mat b2,
-            const Mat smoothX, const Mat smoothY, Mat dW );
-    void sorUnfolded( const Mat a11, const Mat a12, const Mat a22, const Mat b1, const Mat b2,
-            const Mat smoothX, const Mat smoothY, Mat dW );
     std::vector<Mat> buildPyramid( const Mat& src );
 
-    int interpolationType;
-
 };
 
 OpticalFlowDeepFlow::OpticalFlowDeepFlow()
@@ -104,8 +90,6 @@ OpticalFlowDeepFlow::OpticalFlowDeepFlow()
 
     //consts
     interpolationType = INTER_LINEAR;
-    zeta = 0.1f;
-    epsilon = 0.001f;
     maxLayers = 200;
 }
 
@@ -130,31 +114,7 @@ std::vector<Mat> OpticalFlowDeepFlow::buildPyramid( const Mat& src )
     }
     return pyramid;
 }
-Mat OpticalFlowDeepFlow::warpImage( const Mat input, const Mat flow )
-{
-    // warps the image "backwards"
-    // if flow = computeFlow( I0, I1 ), then
-    // I0 = warpImage( I1, flow ) - approx.
 
-    Mat output;
-    Mat mapX = Mat(flow.size(), CV_32FC1);
-    Mat mapY = Mat(flow.size(), CV_32FC1);
-    const float *pFlow;
-    float *pMapX, *pMapY;
-    for ( int j = 0; j < flow.rows; ++j )
-    {
-        pFlow = flow.ptr<float>(j);
-        pMapX = mapX.ptr<float>(j);
-        pMapY = mapY.ptr<float>(j);
-        for ( int i = 0; i < flow.cols; ++i )
-        {
-            pMapX[i] = i + pFlow[2 * i];
-            pMapY[i] = j + pFlow[2 * i + 1];
-        }
-    }
-    remap(input, output, mapX, mapY, interpolationType);
-    return output;
-}
 void OpticalFlowDeepFlow::calc( InputArray _I0, InputArray _I1, InputOutputArray _flow )
 {
     Mat I0temp = _I0.getMat();
@@ -189,7 +149,16 @@ void OpticalFlowDeepFlow::calc( InputArray _I0, InputArray _I1, InputOutputArray
 
     for ( int level = levelCount - 1; level >= 0; --level )
     { //iterate through  all levels, beginning with the most coarse
-        calcOneLevel(pyramid_I0[level], pyramid_I1[level], W);
+        Ptr<VariationalRefinement> var = createVariationalFlowRefinement();
+
+        var->setAlpha(4 * alpha);
+        var->setDelta(delta / 3);
+        var->setGamma(gamma / 3);
+        var->setFixedPointIterations(fixedPointIterations);
+        var->setSorIterations(sorIterations);
+        var->setOmega(omega);
+
+        var->calc(pyramid_I0[level], pyramid_I1[level], W);
         if ( level > 0 ) //not the last level
         {
             Mat temp;
@@ -201,666 +170,9 @@ void OpticalFlowDeepFlow::calc( InputArray _I0, InputArray _I1, InputOutputArray
     W.copyTo(_flow);
 }
 
-void OpticalFlowDeepFlow::calcOneLevel( const Mat I0, const Mat I1, Mat W )
-{
-    CV_DbgAssert( I0.size() == I1.size() );CV_DbgAssert( I0.type() == I1.type() );CV_DbgAssert( W.size() == I0.size() );
-
-    // linear equation systems
-    Size s = I0.size();
-    int t = CV_32F; // data type
-    Mat a11, a12, a22, b1, b2;
-    a11.create(s, t);
-    a12.create(s, t);
-    a22.create(s, t);
-    b1.create(s, t);
-    b2.create(s, t);
-    // diffusivity coeffs
-    Mat weightsX, weightsY;
-    weightsX.create(s, t);
-    weightsY.create(s, t);
-
-    Mat warpedI1 = warpImage(I1, W); // warped second image
-    Mat averageFrame = 0.5 * (I0 + warpedI1); // mean value of 2 frames - to compute derivatives on
-
-    //computing derivatives, notation as in Brox's paper
-    Mat Ix, Iy, Iz, Ixx, Ixy, Iyy, Ixz, Iyz;
-    int ddepth = -1; //as source image
-    int kernel_size = 1;
-
-    Sobel(averageFrame, Ix, ddepth, 1, 0, kernel_size, 1, 0.00, BORDER_REPLICATE);
-    Sobel(averageFrame, Iy, ddepth, 0, 1, kernel_size, 1, 0.00, BORDER_REPLICATE);
-    Iz.create(I1.size(), I1.type());
-    Iz = warpedI1 - I0;
-    Sobel(Ix, Ixx, ddepth, 1, 0, kernel_size, 1, 0.00, BORDER_REPLICATE);
-    Sobel(Ix, Ixy, ddepth, 0, 1, kernel_size, 1, 0.00, BORDER_REPLICATE);
-    Sobel(Iy, Iyy, ddepth, 0, 1, kernel_size, 1, 0.00, BORDER_REPLICATE);
-    Sobel(Iz, Ixz, ddepth, 1, 0, kernel_size, 1, 0.00, BORDER_REPLICATE);
-    Sobel(Iz, Iyz, ddepth, 0, 1, kernel_size, 1, 0.00, BORDER_REPLICATE);
-
-    Mat tempW = W.clone(); // flow version to be modified in each iteration
-    Mat dW = Mat::zeros(W.size(), W.type()); // flow increment
-
-    //fixed-point iterations
-    for ( int i = 0; i < fixedPointIterations; ++i )
-    {
-        dataTerm(W, dW, Ix, Iy, Iz, Ixx, Ixy, Iyy, Ixz, Iyz, a11, a12, a22, b1, b2);
-        smoothnessWeights(tempW, weightsX, weightsY);
-        smoothnessTerm(W, weightsX, weightsY, b1, b2);
-        sorSolve(a11, a12, a22, b1, b2, weightsX, weightsY, dW);
-        tempW = W + dW;
-    }
-    tempW.copyTo(W);
-}
-void OpticalFlowDeepFlow::dataTerm( const Mat W, const Mat dW, const Mat Ix, const Mat Iy,
-        const Mat Iz, const Mat Ixx, const Mat Ixy, const Mat Iyy, const Mat Ixz,
-        const Mat Iyz, Mat a11, Mat a12, Mat a22, Mat b1, Mat b2 )
-{
-    const float zeta_squared = zeta * zeta; // added in normalization factor to be non-zero
-    const float epsilon_squared = epsilon * epsilon;
-
-    const float *pIx, *pIy, *pIz;
-    const float *pIxx, *pIxy, *pIyy, *pIxz, *pIyz;
-    const float *pdU, *pdV; // accessing 2 layers of dW. Succesive columns interleave u and v
-    float *pa11, *pa12, *pa22, *pb1, *pb2; // linear equation sys. coeffs for each pixel
-
-    float derivNorm; //denominator of the spatial-derivative normalizing factor (theta_0)
-    float derivNorm2;
-    float Ik1z, Ik1zx, Ik1zy; // approximations of I^(k+1) values by Taylor expansions
-    float temp;
-    for ( int j = 0; j < W.rows; j++ ) //for each row
-    {
-        pIx = Ix.ptr<float>(j);
-        pIy = Iy.ptr<float>(j);
-        pIz = Iz.ptr<float>(j);
-        pIxx = Ixx.ptr<float>(j);
-        pIxy = Ixy.ptr<float>(j);
-        pIyy = Iyy.ptr<float>(j);
-        pIxz = Ixz.ptr<float>(j);
-        pIyz = Iyz.ptr<float>(j);
-
-        pa11 = a11.ptr<float>(j);
-        pa12 = a12.ptr<float>(j);
-        pa22 = a22.ptr<float>(j);
-        pb1 = b1.ptr<float>(j);
-        pb2 = b2.ptr<float>(j);
-
-        pdU = dW.ptr<float>(j);
-        pdV = pdU + 1;
-        for ( int i = 0; i < W.cols; i++ ) //for each pixel in the row
-        { // TODO: implement masking of points warped out of the image
-          //color constancy component
-            derivNorm = (*pIx) * (*pIx) + (*pIy) * (*pIy) + zeta_squared;
-            Ik1z = *pIz + (*pIx * *pdU) + (*pIy * *pdV);
-            temp = (0.5f*delta/3) / sqrt(Ik1z * Ik1z / derivNorm + epsilon_squared);
-            *pa11 = *pIx * *pIx * temp / derivNorm;
-            *pa12 = *pIx * *pIy * temp / derivNorm;
-            *pa22 = *pIy * *pIy * temp / derivNorm;
-            *pb1 = -*pIz * *pIx * temp / derivNorm;
-            *pb2 = -*pIz * *pIy * temp / derivNorm;
-
-            // gradient constancy component
-
-            derivNorm = *pIxx * *pIxx + *pIxy * *pIxy + zeta_squared;
-            derivNorm2 = *pIyy * *pIyy + *pIxy * *pIxy + zeta_squared;
-            Ik1zx = *pIxz + *pIxx * *pdU + *pIxy * *pdV;
-            Ik1zy = *pIyz + *pIxy * *pdU + *pIyy * *pdV;
-
-            temp = (0.5f*gamma/3)
-                    / sqrt(
-                            Ik1zx * Ik1zx / derivNorm + Ik1zy * Ik1zy / derivNorm2
-                                    + epsilon_squared);
-            *pa11 += temp * (*pIxx * *pIxx / derivNorm + *pIxy * *pIxy / derivNorm2);
-            *pa12 += temp * (*pIxx * *pIxy / derivNorm + *pIxy * *pIyy / derivNorm2);
-            *pa22 += temp * (*pIxy * *pIxy / derivNorm + *pIyy * *pIyy / derivNorm2);
-            *pb1 += -temp * (*pIxx * *pIxz / derivNorm + *pIxy * *pIyz / derivNorm2);
-            *pb2 += -temp * (*pIxy * *pIxz / derivNorm + *pIyy * *pIyz / derivNorm2);
-
-            ++pIx;
-            ++pIy;
-            ++pIz;
-            ++pIxx;
-            ++pIxy;
-            ++pIyy;
-            ++pIxz;
-            ++pIyz;
-            pdU += 2;
-            pdV += 2;
-            ++pa11;
-            ++pa12;
-            ++pa22;
-            ++pb1;
-            ++pb2;
-
-        }
-    }
-
-
-
-}
-void OpticalFlowDeepFlow::smoothnessWeights( const Mat W, Mat weightsX, Mat weightsY )
-{
-    float k[] = { -0.5, 0, 0.5 };
-    const float epsilon_squared = epsilon * epsilon;
-    Mat kernel_h = Mat(1, 3, CV_32FC1, k);
-    Mat kernel_v = Mat(3, 1, CV_32FC1, k);
-    Mat Wx, Wy; // partial derivatives of the flow
-    Mat S = Mat(W.size(), CV_32FC1); // sum of squared derivatives
-    weightsX = Mat::zeros(W.size(), CV_32FC1); //output - weights of smoothness terms in x and y directions
-    weightsY = Mat::zeros(W.size(), CV_32FC1);
-
-    filter2D(W, Wx, CV_32FC2, kernel_h);
-    filter2D(W, Wy, CV_32FC2, kernel_v);
-
-    const float * ux, *uy, *vx, *vy;
-    float * pS, *pWeight, *temp;
-
-    for ( int j = 0; j < S.rows; ++j )
-    {
-        ux = Wx.ptr<float>(j);
-        vx = ux + 1;
-        uy = Wy.ptr<float>(j);
-        vy = uy + 1;
-        pS = S.ptr<float>(j);
-        for ( int i = 0; i < S.cols; ++i )
-        {
-            *pS = alpha / sqrt(*ux * *ux + *vx * *vx + *uy * *uy + *vy * *vy + epsilon_squared);
-            ux += 2;
-            vx += 2;
-            uy += 2;
-            vy += 2;
-            ++pS;
-        }
-    }
-    // horizontal weights
-    for ( int j = 0; j < S.rows; ++j )
-    {
-        pWeight = weightsX.ptr<float>(j);
-        pS = S.ptr<float>(j);
-        for ( int i = 0; i < S.cols - 1; ++i )
-        {
-            *pWeight = *pS + *(pS + 1);
-            ++pS;
-            ++pWeight;
-        }
-    }
-    //vertical weights
-    for ( int j = 0; j < S.rows - 1; ++j )
-    {
-        pWeight = weightsY.ptr<float>(j);
-        pS = S.ptr<float>(j);
-        temp = S.ptr<float>(j + 1); // next row pointer for easy access
-        for ( int i = 0; i < S.cols; ++i )
-        {
-            *pWeight = *(pS++) + *(temp++);
-            ++pWeight;
-        }
-    }
-}
-void OpticalFlowDeepFlow::smoothnessTerm( const Mat W, const Mat weightsX, const Mat weightsY,
-        Mat b1, Mat b2 )
-{
-    float *pB1, *pB2;
-    const float *pU, *pV, *pWeight;
-    float iB1, iB2; // increments of b1 and b2
-    //horizontal direction - both U and V (b1 and b2)
-    for ( int j = 0; j < W.rows; j++ )
-    {
-        pB1 = b1.ptr<float>(j);
-        pB2 = b2.ptr<float>(j);
-        pU = W.ptr<float>(j);
-        pV = pU + 1;
-        pWeight = weightsX.ptr<float>(j);
-        for ( int i = 0; i < W.cols - 1; i++ )
-        {
-            iB1 = (*(pU + 2) - *pU) * *pWeight;
-            iB2 = (*(pV + 2) - *pV) * *pWeight;
-            *pB1 += iB1;
-            *(pB1 + 1) -= iB1;
-            *pB2 += iB2;
-            *(pB2 + 1) -= iB2;
-
-            pB1++;
-            pB2++;
-            pU += 2;
-            pV += 2;
-            pWeight++;
-        }
-    }
-    const float *pUnext, *pVnext; // temp pointers for next row
-    float *pB1next, *pB2next;
-    //vertical direction - both U and V
-    for ( int j = 0; j < W.rows - 1; j++ )
-    {
-        pB1 = b1.ptr<float>(j);
-        pB2 = b2.ptr<float>(j);
-        pU = W.ptr<float>(j);
-        pV = pU + 1;
-        pUnext = W.ptr<float>(j + 1);
-        pVnext = pUnext + 1;
-        pB1next = b1.ptr<float>(j + 1);
-        pB2next = b2.ptr<float>(j + 1);
-        pWeight = weightsY.ptr<float>(j);
-        for ( int i = 0; i < W.cols; i++ )
-        {
-            iB1 = (*pUnext - *pU) * *pWeight;
-            iB2 = (*pVnext - *pV) * *pWeight;
-            *pB1 += iB1;
-            *pB1next -= iB1;
-            *pB2 += iB2;
-            *pB2next -= iB2;
-
-            pB1++;
-            pB2++;
-            pU += 2;
-            pV += 2;
-            pWeight++;
-            pUnext += 2;
-            pVnext += 2;
-            pB1next++;
-            pB2next++;
-        }
-    }
-}
-
-void OpticalFlowDeepFlow::sorSolve( const Mat a11, const Mat a12, const Mat a22, const Mat b1,
-        const Mat b2, const Mat smoothX, const Mat smoothY, Mat dW )
-{
-    CV_Assert(a11.isContinuous());
-    CV_Assert(a12.isContinuous());
-    CV_Assert(a22.isContinuous());
-    CV_Assert(b1.isContinuous());
-    CV_Assert(b2.isContinuous());
-    CV_Assert(smoothX.isContinuous());
-    CV_Assert(smoothY.isContinuous());
-
-    if(dW.cols > 2 && dW.rows > 2)
-    {
-        sorUnfolded(a11, a12, a22, b1, b2, smoothX, smoothY, dW );
-        //more efficient version - this one is mostly for future reference and readability
-        return;
-    }
-    std::vector<Mat> dWChannels(2);
-    split(dW, dWChannels);
-
-    Mat *du = &(dWChannels[0]);
-    Mat *dv = &(dWChannels[1]);
-
-    CV_Assert(du->isContinuous());
-    CV_Assert(dv->isContinuous());
-
-    const float *pa11, *pa12, *pa22, *pb1, *pb2, *psmoothX, *psmoothY;
-    float *pdu, *pdv;
-    psmoothX = smoothX.ptr<float>(0);
-    psmoothY = smoothY.ptr<float>(0);
-    pdu = du->ptr<float>(0);
-    pdv = dv->ptr<float>(0);
-
-    float sigmaU, sigmaV, dPsi, A11, A22, A12, B1, B2, det;
-
-    int cols = dW.cols;
-    int rows = dW.rows;
-
-    int s = dW.cols; // step between rows
-
-    for ( int iter = 0; iter < sorIterations; ++iter )
-    {
-        pa11 = a11.ptr<float>(0);
-        pa12 = a12.ptr<float>(0);
-        pa22 = a22.ptr<float>(0);
-        pb1 = b1.ptr<float>(0);
-        pb2 = b2.ptr<float>(0);
-        for ( int j = 0; j < rows; ++j )
-        {
-            for ( int i = 0; i < cols; ++i )
-            {
-                int o = j * s + i;
-                if ( i == 0 && j == 0 )
-                {
-                    dPsi = psmoothX[o] + psmoothY[o];
-                    sigmaU = psmoothX[o] * pdu[o + 1] + psmoothY[o] * pdu[o + s];
-                    sigmaV = psmoothX[o] * pdv[o + 1] + psmoothY[o] * pdv[o + s];
-                } else if ( i == cols - 1 && j == 0 )
-                {
-                    dPsi = psmoothX[o - 1] + psmoothY[o];
-                    sigmaU = psmoothX[o - 1] * pdu[o - 1]
-                            + psmoothY[o] * pdu[o + s];
-                    sigmaV = psmoothX[o - 1] * pdv[o - 1]
-                            + psmoothY[o] * pdv[o + s];
-                } else if ( j == 0 )
-                {
-                    dPsi = psmoothX[o - 1] + psmoothX[o] + psmoothY[o];
-                    sigmaU = psmoothX[o - 1] * pdu[o - 1]
-                            + psmoothX[o] * pdu[o + 1] + psmoothY[o] * pdu[o + s];
-                    sigmaV = psmoothX[o - 1] * pdv[o - 1]
-                            + psmoothX[o] * pdv[o + 1] + psmoothY[o] * pdv[o + s];
-                } else if ( i == 0 && j == rows - 1 )
-                {
-                    dPsi = psmoothX[o] + psmoothY[o - s];
-                    sigmaU = psmoothX[o] * pdu[o + 1]
-                            + psmoothY[o - s] * pdu[o - s];
-                    sigmaV = psmoothX[o] * pdv[o + 1]
-                            + psmoothY[o - s] * pdv[o - s];
-                } else if ( i == cols - 1 && j == rows - 1 )
-                {
-                    dPsi = psmoothX[o - 1] + psmoothY[o - s];
-                    sigmaU = psmoothX[o - 1] * pdu[o - 1]
-                            + psmoothY[o - s] * pdu[o - s];
-                    sigmaV = psmoothX[o - 1] * pdv[o - 1]
-                            + psmoothY[o - s] * pdv[o - s];
-                } else if ( j == rows - 1 )
-                {
-                    dPsi = psmoothX[o - 1] + psmoothX[o] + psmoothY[o - s];
-                    sigmaU = psmoothX[o - 1] * pdu[o - 1]
-                            + psmoothX[o] * pdu[o + 1]
-                            + psmoothY[o - s] * pdu[o - s];
-                    sigmaV = psmoothX[o - 1] * pdv[o - 1]
-                            + psmoothX[o] * pdv[o + 1]
-                            + psmoothY[o - s] * pdv[o - s];
-                } else if ( i == 0 )
-                {
-                    dPsi = psmoothX[o] + psmoothY[o - s] + psmoothY[o];
-                    sigmaU = psmoothX[o] * pdu[o + 1]
-                            + psmoothY[o - s] * pdu[o - s]
-                            + psmoothY[o] * pdu[o + s];
-                    sigmaV = psmoothX[o] * pdv[o + 1]
-                            + psmoothY[o - s] * pdv[o - s]
-                            + psmoothY[o] * pdv[o + s];
-                } else if ( i == cols - 1 )
-                {
-                    dPsi = psmoothX[o - 1] + psmoothY[o - s] + psmoothY[o];
-                    sigmaU = psmoothX[o - 1] * pdu[o - 1]
-                            + psmoothY[o - s] * pdu[o - s]
-                            + psmoothY[o] * pdu[o + s];
-                    sigmaV = psmoothX[o - 1] * pdv[o - 1]
-                            + psmoothY[o - s] * pdv[o - s]
-                            + psmoothY[o] * pdv[o + s];
-                } else
-                {
-                    dPsi = psmoothX[o - 1] + psmoothX[o] + psmoothY[o - s]
-                            + psmoothY[o];
-                    sigmaU = psmoothX[o - 1] * pdu[o - 1]
-                            + psmoothX[o] * pdu[o + 1]
-                            + psmoothY[o - s] * pdu[o - s]
-                            + psmoothY[o] * pdu[o + s];
-                    sigmaV = psmoothX[o - 1] * pdv[o - 1]
-                            + psmoothX[o] * pdv[o + 1]
-                            + psmoothY[o - s] * pdv[o - s]
-                            + psmoothY[o] * pdv[o + s];
-                }
-                A11 = *pa22 + dPsi;
-                A12 = -*pa12;
-                A22 = *pa11 + dPsi;
-                det = A11 * A22 - A12 * A12;
-                A11 /= det;
-                A12 /= det;
-                A22 /= det;
-                B1 = *pb1 + sigmaU;
-                B2 = *pb2 + sigmaV;
-                pdu[o] += omega * (A11 * B1 + A12 * B2 - pdu[o]);
-                pdv[o] += omega * (A12 * B1 + A22 * B2 - pdv[o]);
-                ++pa11; ++pa12; ++pa22; ++pb1; ++pb2;
-            }
-        }
-    }
-    merge(dWChannels, dW);
-}
-
-
-void OpticalFlowDeepFlow::sorUnfolded( const Mat a11, const Mat a12, const Mat a22, const Mat b1, const Mat b2,
-        const Mat smoothX, const Mat smoothY, Mat dW )
-{
-    // the same effect as sorSolve(), but written more efficiently
-    std::vector<Mat> dWChannels(2);
-    split(dW, dWChannels);
-
-    Mat *du = &(dWChannels[0]);
-    Mat *dv = &(dWChannels[1]);
-
-    CV_Assert(du->isContinuous());
-    CV_Assert(dv->isContinuous());
-
-    const float *pa11, *pa12, *pa22, *pb1, *pb2, *psmoothX, *psmoothY;
-    float *pdu, *pdv;
-
-
-    float sigmaU, sigmaV, dPsi, A11, A22, A12, B1, B2, det;
-
-    int cols = dW.cols;
-    int rows = dW.rows;
-
-    int s = dW.cols; // step between rows
-    int j, i, o; //row, column, offset
-
-    for ( int iter = 0; iter < sorIterations; ++iter )
-    {
-        pa11 = a11.ptr<float>(0);
-        pa12 = a12.ptr<float>(0);
-        pa22 = a22.ptr<float>(0);
-        pb1 = b1.ptr<float>(0);
-        pb2 = b2.ptr<float>(0);
-        psmoothX = smoothX.ptr<float>(0);
-        psmoothY = smoothY.ptr<float>(0);
-        pdu = du->ptr<float>(0);
-        pdv = dv->ptr<float>(0);
-
-        // first row
-        // first column
-        o=0;
-        dPsi = psmoothX[o] + psmoothY[o];
-        sigmaU = psmoothX[o] * pdu[o + 1] + psmoothY[o] * pdu[o + s];
-        sigmaV = psmoothX[o] * pdv[o + 1] + psmoothY[o] * pdv[o + s];
-        A11 = *pa22 + dPsi;
-        A12 = -*pa12;
-        A22 = *pa11 + dPsi;
-        det = A11 * A22 - A12 * A12;
-        A11 /= det;
-        A12 /= det;
-        A22 /= det;
-        B1 = *pb1 + sigmaU;
-        B2 = *pb2 + sigmaV;
-        pdu[o] += omega * (A11 * B1 + A12 * B2 - pdu[o]);
-        pdv[o] += omega * (A12 * B1 + A22 * B2 - pdv[o]);
-        ++pa11; ++pa12; ++pa22; ++pb1; ++pb2;
-        // middle rows
-        for ( o = 1; o < cols-1; ++o )
-        {
-            dPsi = psmoothX[o - 1] + psmoothX[o] + psmoothY[o];
-            sigmaU = psmoothX[o - 1] * pdu[o - 1]
-                    + psmoothX[o] * pdu[o + 1] + psmoothY[o] * pdu[o + s];
-            sigmaV = psmoothX[o - 1] * pdv[o - 1]
-                    + psmoothX[o] * pdv[o + 1] + psmoothY[o] * pdv[o + s];
-            A11 = *pa22 + dPsi;
-            A12 = -*pa12;
-            A22 = *pa11 + dPsi;
-            det = A11 * A22 - A12 * A12;
-            A11 /= det;
-            A12 /= det;
-            A22 /= det;
-            B1 = *pb1 + sigmaU;
-            B2 = *pb2 + sigmaV;
-            pdu[o] += omega * (A11 * B1 + A12 * B2 - pdu[o]);
-            pdv[o] += omega * (A12 * B1 + A22 * B2 - pdv[o]);
-            ++pa11; ++pa12; ++pa22; ++pb1; ++pb2;
-        }
-        // last column
-        dPsi = psmoothX[o - 1] + psmoothY[o];
-        sigmaU = psmoothX[o - 1] * pdu[o - 1]
-                + psmoothY[o] * pdu[o + s];
-        sigmaV = psmoothX[o - 1] * pdv[o - 1]
-                + psmoothY[o] * pdv[o + s];
-        A11 = *pa22 + dPsi;
-        A12 = -*pa12;
-        A22 = *pa11 + dPsi;
-        det = A11 * A22 - A12 * A12;
-        A11 /= det;
-        A12 /= det;
-        A22 /= det;
-        B1 = *pb1 + sigmaU;
-        B2 = *pb2 + sigmaV;
-        pdu[o] += omega * (A11 * B1 + A12 * B2 - pdu[o]);
-        pdv[o] += omega * (A12 * B1 + A22 * B2 - pdv[o]);
-        ++pa11; ++pa12; ++pa22; ++pb1; ++pb2;
-        ++o;
-        //middle rows
-        for ( j = 1; j < rows - 1; ++j)
-        {
-            // first column
-            dPsi = psmoothX[o] + psmoothY[o - s] + psmoothY[o];
-            sigmaU = psmoothX[o] * pdu[o + 1]
-                    + psmoothY[o - s] * pdu[o - s]
-                    + psmoothY[o] * pdu[o + s];
-            sigmaV = psmoothX[o] * pdv[o + 1]
-                    + psmoothY[o - s] * pdv[o - s]
-                    + psmoothY[o] * pdv[o + s];
-            A11 = *pa22 + dPsi;
-            A12 = -*pa12;
-            A22 = *pa11 + dPsi;
-            det = A11 * A22 - A12 * A12;
-            A11 /= det;
-            A12 /= det;
-            A22 /= det;
-            B1 = *pb1 + sigmaU;
-            B2 = *pb2 + sigmaV;
-            pdu[o] += omega * (A11 * B1 + A12 * B2 - pdu[o]);
-            pdv[o] += omega * (A12 * B1 + A22 * B2 - pdv[o]);
-            ++pa11; ++pa12; ++pa22; ++pb1; ++pb2;
-            ++o;
-            // middle columns
-            for ( i = 1; i < cols - 1; ++i)
-            {
-                dPsi = psmoothX[o - 1] + psmoothX[o] + psmoothY[o - s]
-                        + psmoothY[o];
-                sigmaU = psmoothX[o - 1] * pdu[o - 1]
-                        + psmoothX[o] * pdu[o + 1]
-                        + psmoothY[o - s] * pdu[o - s]
-                        + psmoothY[o] * pdu[o + s];
-                sigmaV = psmoothX[o - 1] * pdv[o - 1]
-                        + psmoothX[o] * pdv[o + 1]
-                        + psmoothY[o - s] * pdv[o - s]
-                        + psmoothY[o] * pdv[o + s];
-                A11 = *pa22 + dPsi;
-                A12 = -*pa12;
-                A22 = *pa11 + dPsi;
-                det = A11 * A22 - A12 * A12;
-                A11 /= det;
-                A12 /= det;
-                A22 /= det;
-                B1 = *pb1 + sigmaU;
-                B2 = *pb2 + sigmaV;
-                pdu[o] += omega * (A11 * B1 + A12 * B2 - pdu[o]);
-                pdv[o] += omega * (A12 * B1 + A22 * B2 - pdv[o]);
-                ++pa11; ++pa12; ++pa22; ++pb1; ++pb2;
-                ++o;
-            }
-            //last column
-            dPsi = psmoothX[o - 1] + psmoothY[o - s] + psmoothY[o];
-            sigmaU = psmoothX[o - 1] * pdu[o - 1]
-                    + psmoothY[o - s] * pdu[o - s]
-                    + psmoothY[o] * pdu[o + s];
-            sigmaV = psmoothX[o - 1] * pdv[o - 1]
-                    + psmoothY[o - s] * pdv[o - s]
-                    + psmoothY[o] * pdv[o + s];
-            A11 = *pa22 + dPsi;
-            A12 = -*pa12;
-            A22 = *pa11 + dPsi;
-            det = A11 * A22 - A12 * A12;
-            A11 /= det;
-            A12 /= det;
-            A22 /= det;
-            B1 = *pb1 + sigmaU;
-            B2 = *pb2 + sigmaV;
-            pdu[o] += omega * (A11 * B1 + A12 * B2 - pdu[o]);
-            pdv[o] += omega * (A12 * B1 + A22 * B2 - pdv[o]);
-            ++pa11; ++pa12; ++pa22; ++pb1; ++pb2;
-            ++o;
-        }
-        //last row
-        //first column
-        dPsi = psmoothX[o] + psmoothY[o - s];
-        sigmaU = psmoothX[o] * pdu[o + 1]
-                + psmoothY[o - s] * pdu[o - s];
-        sigmaV = psmoothX[o] * pdv[o + 1]
-                + psmoothY[o - s] * pdv[o - s];
-        A11 = *pa22 + dPsi;
-        A12 = -*pa12;
-        A22 = *pa11 + dPsi;
-        det = A11 * A22 - A12 * A12;
-        A11 /= det;
-        A12 /= det;
-        A22 /= det;
-        B1 = *pb1 + sigmaU;
-        B2 = *pb2 + sigmaV;
-        pdu[o] += omega * (A11 * B1 + A12 * B2 - pdu[o]);
-        pdv[o] += omega * (A12 * B1 + A22 * B2 - pdv[o]);
-        ++pa11; ++pa12; ++pa22; ++pb1; ++pb2;
-        ++o;
-        //middle columns
-        for ( i = 1; i < cols - 1; ++i)
-        {
-            dPsi = psmoothX[o - 1] + psmoothX[o] + psmoothY[o - s];
-            sigmaU = psmoothX[o - 1] * pdu[o - 1]
-                    + psmoothX[o] * pdu[o + 1]
-                    + psmoothY[o - s] * pdu[o - s];
-            sigmaV = psmoothX[o - 1] * pdv[o - 1]
-                    + psmoothX[o] * pdv[o + 1]
-                    + psmoothY[o - s] * pdv[o - s];
-            A11 = *pa22 + dPsi;
-            A12 = -*pa12;
-            A22 = *pa11 + dPsi;
-            det = A11 * A22 - A12 * A12;
-            A11 /= det;
-            A12 /= det;
-            A22 /= det;
-            B1 = *pb1 + sigmaU;
-            B2 = *pb2 + sigmaV;
-            pdu[o] += omega * (A11 * B1 + A12 * B2 - pdu[o]);
-            pdv[o] += omega * (A12 * B1 + A22 * B2 - pdv[o]);
-            ++pa11; ++pa12; ++pa22; ++pb1; ++pb2;
-            ++o;
-        }
-        //last column
-        dPsi = psmoothX[o - 1] + psmoothY[o - s];
-        sigmaU = psmoothX[o - 1] * pdu[o - 1]
-                + psmoothY[o - s] * pdu[o - s];
-        sigmaV = psmoothX[o - 1] * pdv[o - 1]
-                + psmoothY[o - s] * pdv[o - s];
-        A11 = *pa22 + dPsi;
-        A12 = -*pa12;
-        A22 = *pa11 + dPsi;
-        det = A11 * A22 - A12 * A12;
-        A11 /= det;
-        A12 /= det;
-        A22 /= det;
-        B1 = *pb1 + sigmaU;
-        B2 = *pb2 + sigmaV;
-        pdu[o] += omega * (A11 * B1 + A12 * B2 - pdu[o]);
-        pdv[o] += omega * (A12 * B1 + A22 * B2 - pdv[o]);
-        ++pa11; ++pa12; ++pa22; ++pb1; ++pb2;
-    }
-    merge(dWChannels, dW);
-
-}
-void OpticalFlowDeepFlow::collectGarbage()
-{
-
-}
-//
-//CV_INIT_ALGORITHM(OpticalFlowDeepFlow, "DenseOpticalFlow.DeepFlow",
-//        obj.info()->addParam(obj, "sigma", obj.sigma, false, 0, 0, "Gaussian blur parameter");
-//        obj.info()->addParam(obj, "alpha", obj.alpha, false, 0, 0, "Smoothness assumption weight");
-//        obj.info()->addParam(obj, "delta", obj.delta, false, 0, 0, "Color constancy weight");
-//        obj.info()->addParam(obj, "gamma", obj.gamma, false, 0, 0, "Gradient constancy weight");
-//        obj.info()->addParam(obj, "omega", obj.omega, false, 0, 0, "Relaxation factor in SOR");
-//        obj.info()->addParam(obj, "minSize", obj.minSize, false, 0, 0, "Min. image size in the pyramid");
-//        obj.info()->addParam(obj, "fixedPointIterations", obj.fixedPointIterations, false, 0, 0, "Fixed point iterations");
-//        obj.info()->addParam(obj, "sorIterations", obj.sorIterations, false, 0, 0, "SOR iterations");
-//        obj.info()->addParam(obj, "downscaleFactor", obj.downscaleFactor, false, 0, 0,"Downscale factor"))
+void OpticalFlowDeepFlow::collectGarbage() {}
 
-
-Ptr<DenseOpticalFlow> createOptFlow_DeepFlow()
-{
-    return makePtr<OpticalFlowDeepFlow>();
-}
+Ptr<DenseOpticalFlow> createOptFlow_DeepFlow() { return makePtr<OpticalFlowDeepFlow>(); }
 
 }//optflow
 }//cv
diff --git a/contrib/modules/optflow/src/dis_flow.cpp b/contrib/modules/optflow/src/dis_flow.cpp
new file mode 100644
index 0000000..3980a46
--- /dev/null
+++ b/contrib/modules/optflow/src/dis_flow.cpp
@@ -0,0 +1,1125 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+//  By downloading, copying, installing or using the software you agree to this license.
+//  If you do not agree to this license, do not download, install,
+//  copy or use the software.
+//
+//
+//                           License Agreement
+//                For Open Source Computer Vision Library
+//
+// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
+// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+//   * Redistribution's of source code must retain the above copyright notice,
+//     this list of conditions and the following disclaimer.
+//
+//   * Redistribution's in binary form must reproduce the above copyright notice,
+//     this list of conditions and the following disclaimer in the documentation
+//     and/or other materials provided with the distribution.
+//
+//   * The name of the copyright holders may not be used to endorse or promote products
+//     derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "opencv2/core/hal/intrin.hpp"
+#include "precomp.hpp"
+using namespace std;
+#define EPS 0.001F
+#define INF 1E+10F
+
+namespace cv
+{
+namespace optflow
+{
+
+class DISOpticalFlowImpl : public DISOpticalFlow
+{
+  public:
+    DISOpticalFlowImpl();
+
+    void calc(InputArray I0, InputArray I1, InputOutputArray flow);
+    void collectGarbage();
+
+  protected: //!< algorithm parameters
+    int finest_scale, coarsest_scale;
+    int patch_size;
+    int patch_stride;
+    int grad_descent_iter;
+    int variational_refinement_iter;
+    float variational_refinement_alpha;
+    float variational_refinement_gamma;
+    float variational_refinement_delta;
+    bool use_mean_normalization;
+    bool use_spatial_propagation;
+
+  protected: //!< some auxiliary variables
+    int border_size;
+    int w, h;   //!< flow buffer width and height on the current scale
+    int ws, hs; //!< sparse flow buffer width and height on the current scale
+
+  public:
+    int getFinestScale() const { return finest_scale; }
+    void setFinestScale(int val) { finest_scale = val; }
+    int getPatchSize() const { return patch_size; }
+    void setPatchSize(int val) { patch_size = val; }
+    int getPatchStride() const { return patch_stride; }
+    void setPatchStride(int val) { patch_stride = val; }
+    int getGradientDescentIterations() const { return grad_descent_iter; }
+    void setGradientDescentIterations(int val) { grad_descent_iter = val; }
+    int getVariationalRefinementIterations() const { return variational_refinement_iter; }
+    void setVariationalRefinementIterations(int val) { variational_refinement_iter = val; }
+    float getVariationalRefinementAlpha() const { return variational_refinement_alpha; }
+    void setVariationalRefinementAlpha(float val) { variational_refinement_alpha = val; }
+    float getVariationalRefinementDelta() const { return variational_refinement_delta; }
+    void setVariationalRefinementDelta(float val) { variational_refinement_delta = val; }
+    float getVariationalRefinementGamma() const { return variational_refinement_gamma; }
+    void setVariationalRefinementGamma(float val) { variational_refinement_gamma = val; }
+
+    bool getUseMeanNormalization() const { return use_mean_normalization; }
+    void setUseMeanNormalization(bool val) { use_mean_normalization = val; }
+    bool getUseSpatialPropagation() const { return use_spatial_propagation; }
+    void setUseSpatialPropagation(bool val) { use_spatial_propagation = val; }
+
+  protected:                      //!< internal buffers
+    vector<Mat_<uchar> > I0s;     //!< Gaussian pyramid for the current frame
+    vector<Mat_<uchar> > I1s;     //!< Gaussian pyramid for the next frame
+    vector<Mat_<uchar> > I1s_ext; //!< I1s with borders
+
+    vector<Mat_<short> > I0xs; //!< Gaussian pyramid for the x gradient of the current frame
+    vector<Mat_<short> > I0ys; //!< Gaussian pyramid for the y gradient of the current frame
+
+    vector<Mat_<float> > Ux; //!< x component of the flow vectors
+    vector<Mat_<float> > Uy; //!< y component of the flow vectors
+
+    vector<Mat_<float> > initial_Ux; //!< x component of the initial flow field, if one was passed as an input
+    vector<Mat_<float> > initial_Uy; //!< y component of the initial flow field, if one was passed as an input
+
+    Mat_<Vec2f> U; //!< a buffer for the merged flow
+
+    Mat_<float> Sx; //!< intermediate sparse flow representation (x component)
+    Mat_<float> Sy; //!< intermediate sparse flow representation (y component)
+
+    /* Structure tensor components: */
+    Mat_<float> I0xx_buf; //!< sum of squares of x gradient values
+    Mat_<float> I0yy_buf; //!< sum of squares of y gradient values
+    Mat_<float> I0xy_buf; //!< sum of x and y gradient products
+
+    /* Extra buffers that are useful if patch mean-normalization is used: */
+    Mat_<float> I0x_buf; //!< sum of x gradient values
+    Mat_<float> I0y_buf; //!< sum of y gradient values
+
+    /* Auxiliary buffers used in structure tensor computation: */
+    Mat_<float> I0xx_buf_aux;
+    Mat_<float> I0yy_buf_aux;
+    Mat_<float> I0xy_buf_aux;
+    Mat_<float> I0x_buf_aux;
+    Mat_<float> I0y_buf_aux;
+
+    vector<Ptr<VariationalRefinement> > variational_refinement_processors;
+
+  private: //!< private methods and parallel sections
+    void prepareBuffers(Mat &I0, Mat &I1, Mat &flow, bool use_flow);
+    void precomputeStructureTensor(Mat &dst_I0xx, Mat &dst_I0yy, Mat &dst_I0xy, Mat &dst_I0x, Mat &dst_I0y, Mat &I0x,
+                                   Mat &I0y);
+
+    struct PatchInverseSearch_ParBody : public ParallelLoopBody
+    {
+        DISOpticalFlowImpl *dis;
+        int nstripes, stripe_sz;
+        int hs;
+        Mat *Sx, *Sy, *Ux, *Uy, *I0, *I1, *I0x, *I0y;
+        int num_iter, pyr_level;
+
+        PatchInverseSearch_ParBody(DISOpticalFlowImpl &_dis, int _nstripes, int _hs, Mat &dst_Sx, Mat &dst_Sy,
+                                   Mat &src_Ux, Mat &src_Uy, Mat &_I0, Mat &_I1, Mat &_I0x, Mat &_I0y, int _num_iter,
+                                   int _pyr_level);
+        void operator()(const Range &range) const;
+    };
+
+    struct Densification_ParBody : public ParallelLoopBody
+    {
+        DISOpticalFlowImpl *dis;
+        int nstripes, stripe_sz;
+        int h;
+        Mat *Ux, *Uy, *Sx, *Sy, *I0, *I1;
+
+        Densification_ParBody(DISOpticalFlowImpl &_dis, int _nstripes, int _h, Mat &dst_Ux, Mat &dst_Uy, Mat &src_Sx,
+                              Mat &src_Sy, Mat &_I0, Mat &_I1);
+        void operator()(const Range &range) const;
+    };
+};
+
+DISOpticalFlowImpl::DISOpticalFlowImpl()
+{
+    finest_scale = 2;
+    patch_size = 8;
+    patch_stride = 4;
+    grad_descent_iter = 16;
+    variational_refinement_iter = 5;
+    variational_refinement_alpha = 20.f;
+    variational_refinement_gamma = 10.f;
+    variational_refinement_delta = 5.f;
+
+    border_size = 16;
+    use_mean_normalization = true;
+    use_spatial_propagation = true;
+
+    /* Use separate variational refinement instances for different scales to avoid repeated memory allocation: */
+    int max_possible_scales = 10;
+    for (int i = 0; i < max_possible_scales; i++)
+        variational_refinement_processors.push_back(createVariationalFlowRefinement());
+}
+
+void DISOpticalFlowImpl::prepareBuffers(Mat &I0, Mat &I1, Mat &flow, bool use_flow)
+{
+    I0s.resize(coarsest_scale + 1);
+    I1s.resize(coarsest_scale + 1);
+    I1s_ext.resize(coarsest_scale + 1);
+    I0xs.resize(coarsest_scale + 1);
+    I0ys.resize(coarsest_scale + 1);
+    Ux.resize(coarsest_scale + 1);
+    Uy.resize(coarsest_scale + 1);
+
+    Mat flow_uv[2];
+    if (use_flow)
+    {
+        split(flow, flow_uv);
+        initial_Ux.resize(coarsest_scale + 1);
+        initial_Uy.resize(coarsest_scale + 1);
+    }
+
+    int fraction = 1;
+    int cur_rows = 0, cur_cols = 0;
+
+    for (int i = 0; i <= coarsest_scale; i++)
+    {
+        /* Avoid initializing the pyramid levels above the finest scale, as they won't be used anyway */
+        if (i == finest_scale)
+        {
+            cur_rows = I0.rows / fraction;
+            cur_cols = I0.cols / fraction;
+            I0s[i].create(cur_rows, cur_cols);
+            resize(I0, I0s[i], I0s[i].size(), 0.0, 0.0, INTER_AREA);
+            I1s[i].create(cur_rows, cur_cols);
+            resize(I1, I1s[i], I1s[i].size(), 0.0, 0.0, INTER_AREA);
+
+            /* These buffers are reused in each scale so we initialize them once on the finest scale: */
+            Sx.create(cur_rows / patch_stride, cur_cols / patch_stride);
+            Sy.create(cur_rows / patch_stride, cur_cols / patch_stride);
+            I0xx_buf.create(cur_rows / patch_stride, cur_cols / patch_stride);
+            I0yy_buf.create(cur_rows / patch_stride, cur_cols / patch_stride);
+            I0xy_buf.create(cur_rows / patch_stride, cur_cols / patch_stride);
+            I0x_buf.create(cur_rows / patch_stride, cur_cols / patch_stride);
+            I0y_buf.create(cur_rows / patch_stride, cur_cols / patch_stride);
+
+            I0xx_buf_aux.create(cur_rows, cur_cols / patch_stride);
+            I0yy_buf_aux.create(cur_rows, cur_cols / patch_stride);
+            I0xy_buf_aux.create(cur_rows, cur_cols / patch_stride);
+            I0x_buf_aux.create(cur_rows, cur_cols / patch_stride);
+            I0y_buf_aux.create(cur_rows, cur_cols / patch_stride);
+
+            U.create(cur_rows, cur_cols);
+        }
+        else if (i > finest_scale)
+        {
+            cur_rows = I0s[i - 1].rows / 2;
+            cur_cols = I0s[i - 1].cols / 2;
+            I0s[i].create(cur_rows, cur_cols);
+            resize(I0s[i - 1], I0s[i], I0s[i].size(), 0.0, 0.0, INTER_AREA);
+            I1s[i].create(cur_rows, cur_cols);
+            resize(I1s[i - 1], I1s[i], I1s[i].size(), 0.0, 0.0, INTER_AREA);
+        }
+
+        if (i >= finest_scale)
+        {
+            I1s_ext[i].create(cur_rows + 2 * border_size, cur_cols + 2 * border_size);
+            copyMakeBorder(I1s[i], I1s_ext[i], border_size, border_size, border_size, border_size, BORDER_REPLICATE);
+            I0xs[i].create(cur_rows, cur_cols);
+            I0ys[i].create(cur_rows, cur_cols);
+            spatialGradient(I0s[i], I0xs[i], I0ys[i]);
+            Ux[i].create(cur_rows, cur_cols);
+            Uy[i].create(cur_rows, cur_cols);
+            variational_refinement_processors[i]->setAlpha(variational_refinement_alpha);
+            variational_refinement_processors[i]->setDelta(variational_refinement_delta);
+            variational_refinement_processors[i]->setGamma(variational_refinement_gamma);
+            variational_refinement_processors[i]->setSorIterations(5);
+            variational_refinement_processors[i]->setFixedPointIterations(variational_refinement_iter);
+
+            if (use_flow)
+            {
+                resize(flow_uv[0], initial_Ux[i], Size(cur_cols, cur_rows));
+                initial_Ux[i] /= fraction;
+                resize(flow_uv[1], initial_Uy[i], Size(cur_cols, cur_rows));
+                initial_Uy[i] /= fraction;
+            }
+        }
+
+        fraction *= 2;
+    }
+}
+
+/* This function computes the structure tensor elements (local sums of I0x^2, I0x*I0y and I0y^2).
+ * A simple box filter is not used instead because we need to compute these sums on a sparse grid
+ * and store them densely in the output buffers.
+ */
+void DISOpticalFlowImpl::precomputeStructureTensor(Mat &dst_I0xx, Mat &dst_I0yy, Mat &dst_I0xy, Mat &dst_I0x,
+                                                   Mat &dst_I0y, Mat &I0x, Mat &I0y)
+{
+    float *I0xx_ptr = dst_I0xx.ptr<float>();
+    float *I0yy_ptr = dst_I0yy.ptr<float>();
+    float *I0xy_ptr = dst_I0xy.ptr<float>();
+    float *I0x_ptr = dst_I0x.ptr<float>();
+    float *I0y_ptr = dst_I0y.ptr<float>();
+
+    float *I0xx_aux_ptr = I0xx_buf_aux.ptr<float>();
+    float *I0yy_aux_ptr = I0yy_buf_aux.ptr<float>();
+    float *I0xy_aux_ptr = I0xy_buf_aux.ptr<float>();
+    float *I0x_aux_ptr = I0x_buf_aux.ptr<float>();
+    float *I0y_aux_ptr = I0y_buf_aux.ptr<float>();
+
+    /* Separable box filter: horizontal pass */
+    for (int i = 0; i < h; i++)
+    {
+        float sum_xx = 0.0f, sum_yy = 0.0f, sum_xy = 0.0f, sum_x = 0.0f, sum_y = 0.0f;
+        short *x_row = I0x.ptr<short>(i);
+        short *y_row = I0y.ptr<short>(i);
+        for (int j = 0; j < patch_size; j++)
+        {
+            sum_xx += x_row[j] * x_row[j];
+            sum_yy += y_row[j] * y_row[j];
+            sum_xy += x_row[j] * y_row[j];
+            sum_x += x_row[j];
+            sum_y += y_row[j];
+        }
+        I0xx_aux_ptr[i * ws] = sum_xx;
+        I0yy_aux_ptr[i * ws] = sum_yy;
+        I0xy_aux_ptr[i * ws] = sum_xy;
+        I0x_aux_ptr[i * ws] = sum_x;
+        I0y_aux_ptr[i * ws] = sum_y;
+        int js = 1;
+        for (int j = patch_size; j < w; j++)
+        {
+            sum_xx += (x_row[j] * x_row[j] - x_row[j - patch_size] * x_row[j - patch_size]);
+            sum_yy += (y_row[j] * y_row[j] - y_row[j - patch_size] * y_row[j - patch_size]);
+            sum_xy += (x_row[j] * y_row[j] - x_row[j - patch_size] * y_row[j - patch_size]);
+            sum_x += (x_row[j] - x_row[j - patch_size]);
+            sum_y += (y_row[j] - y_row[j - patch_size]);
+            if ((j - patch_size + 1) % patch_stride == 0)
+            {
+                I0xx_aux_ptr[i * ws + js] = sum_xx;
+                I0yy_aux_ptr[i * ws + js] = sum_yy;
+                I0xy_aux_ptr[i * ws + js] = sum_xy;
+                I0x_aux_ptr[i * ws + js] = sum_x;
+                I0y_aux_ptr[i * ws + js] = sum_y;
+                js++;
+            }
+        }
+    }
+
+    AutoBuffer<float> sum_xx_buf(ws), sum_yy_buf(ws), sum_xy_buf(ws), sum_x_buf(ws), sum_y_buf(ws);
+    float *sum_xx = (float *)sum_xx_buf;
+    float *sum_yy = (float *)sum_yy_buf;
+    float *sum_xy = (float *)sum_xy_buf;
+    float *sum_x = (float *)sum_x_buf;
+    float *sum_y = (float *)sum_y_buf;
+    for (int j = 0; j < ws; j++)
+    {
+        sum_xx[j] = 0.0f;
+        sum_yy[j] = 0.0f;
+        sum_xy[j] = 0.0f;
+        sum_x[j] = 0.0f;
+        sum_y[j] = 0.0f;
+    }
+
+    /* Separable box filter: vertical pass */
+    for (int i = 0; i < patch_size; i++)
+        for (int j = 0; j < ws; j++)
+        {
+            sum_xx[j] += I0xx_aux_ptr[i * ws + j];
+            sum_yy[j] += I0yy_aux_ptr[i * ws + j];
+            sum_xy[j] += I0xy_aux_ptr[i * ws + j];
+            sum_x[j] += I0x_aux_ptr[i * ws + j];
+            sum_y[j] += I0y_aux_ptr[i * ws + j];
+        }
+    for (int j = 0; j < ws; j++)
+    {
+        I0xx_ptr[j] = sum_xx[j];
+        I0yy_ptr[j] = sum_yy[j];
+        I0xy_ptr[j] = sum_xy[j];
+        I0x_ptr[j] = sum_x[j];
+        I0y_ptr[j] = sum_y[j];
+    }
+    int is = 1;
+    for (int i = patch_size; i < h; i++)
+    {
+        for (int j = 0; j < ws; j++)
+        {
+            sum_xx[j] += (I0xx_aux_ptr[i * ws + j] - I0xx_aux_ptr[(i - patch_size) * ws + j]);
+            sum_yy[j] += (I0yy_aux_ptr[i * ws + j] - I0yy_aux_ptr[(i - patch_size) * ws + j]);
+            sum_xy[j] += (I0xy_aux_ptr[i * ws + j] - I0xy_aux_ptr[(i - patch_size) * ws + j]);
+            sum_x[j] += (I0x_aux_ptr[i * ws + j] - I0x_aux_ptr[(i - patch_size) * ws + j]);
+            sum_y[j] += (I0y_aux_ptr[i * ws + j] - I0y_aux_ptr[(i - patch_size) * ws + j]);
+        }
+        if ((i - patch_size + 1) % patch_stride == 0)
+        {
+            for (int j = 0; j < ws; j++)
+            {
+                I0xx_ptr[is * ws + j] = sum_xx[j];
+                I0yy_ptr[is * ws + j] = sum_yy[j];
+                I0xy_ptr[is * ws + j] = sum_xy[j];
+                I0x_ptr[is * ws + j] = sum_x[j];
+                I0y_ptr[is * ws + j] = sum_y[j];
+            }
+            is++;
+        }
+    }
+}
+
+DISOpticalFlowImpl::PatchInverseSearch_ParBody::PatchInverseSearch_ParBody(DISOpticalFlowImpl &_dis, int _nstripes,
+                                                                           int _hs, Mat &dst_Sx, Mat &dst_Sy,
+                                                                           Mat &src_Ux, Mat &src_Uy, Mat &_I0, Mat &_I1,
+                                                                           Mat &_I0x, Mat &_I0y, int _num_iter,
+                                                                           int _pyr_level)
+    : dis(&_dis), nstripes(_nstripes), hs(_hs), Sx(&dst_Sx), Sy(&dst_Sy), Ux(&src_Ux), Uy(&src_Uy), I0(&_I0), I1(&_I1),
+      I0x(&_I0x), I0y(&_I0y), num_iter(_num_iter), pyr_level(_pyr_level)
+{
+    stripe_sz = (int)ceil(hs / (double)nstripes);
+}
+
+/////////////////////////////////////////////* Patch processing functions */////////////////////////////////////////////
+
+/* Some auxiliary macros */
+#define HAL_INIT_BILINEAR_8x8_PATCH_EXTRACTION                                                                         \
+    v_float32x4 w00v = v_setall_f32(w00);                                                                              \
+    v_float32x4 w01v = v_setall_f32(w01);                                                                              \
+    v_float32x4 w10v = v_setall_f32(w10);                                                                              \
+    v_float32x4 w11v = v_setall_f32(w11);                                                                              \
+                                                                                                                       \
+    v_uint8x16 I0_row_16, I1_row_16, I1_row_shifted_16, I1_row_next_16, I1_row_next_shifted_16;                        \
+    v_uint16x8 I0_row_8, I1_row_8, I1_row_shifted_8, I1_row_next_8, I1_row_next_shifted_8, tmp;                        \
+    v_uint32x4 I0_row_4_left, I1_row_4_left, I1_row_shifted_4_left, I1_row_next_4_left, I1_row_next_shifted_4_left;    \
+    v_uint32x4 I0_row_4_right, I1_row_4_right, I1_row_shifted_4_right, I1_row_next_4_right,                            \
+      I1_row_next_shifted_4_right;                                                                                     \
+    v_float32x4 I_diff_left, I_diff_right;                                                                             \
+                                                                                                                       \
+    /* Preload and expand the first row of I1: */                                                                      \
+    I1_row_16 = v_load(I1_ptr);                                                                                        \
+    I1_row_shifted_16 = v_extract<1>(I1_row_16, I1_row_16);                                                            \
+    v_expand(I1_row_16, I1_row_8, tmp);                                                                                \
+    v_expand(I1_row_shifted_16, I1_row_shifted_8, tmp);                                                                \
+    v_expand(I1_row_8, I1_row_4_left, I1_row_4_right);                                                                 \
+    v_expand(I1_row_shifted_8, I1_row_shifted_4_left, I1_row_shifted_4_right);                                         \
+    I1_ptr += I1_stride;
+
+#define HAL_PROCESS_BILINEAR_8x8_PATCH_EXTRACTION                                                                      \
+    /* Load the next row of I1: */                                                                                     \
+    I1_row_next_16 = v_load(I1_ptr);                                                                                   \
+    /* Circular shift left by 1 element: */                                                                            \
+    I1_row_next_shifted_16 = v_extract<1>(I1_row_next_16, I1_row_next_16);                                             \
+    /* Expand to 8 ushorts (we only need the first 8 values): */                                                       \
+    v_expand(I1_row_next_16, I1_row_next_8, tmp);                                                                      \
+    v_expand(I1_row_next_shifted_16, I1_row_next_shifted_8, tmp);                                                      \
+    /* Separate the left and right halves: */                                                                          \
+    v_expand(I1_row_next_8, I1_row_next_4_left, I1_row_next_4_right);                                                  \
+    v_expand(I1_row_next_shifted_8, I1_row_next_shifted_4_left, I1_row_next_shifted_4_right);                          \
+                                                                                                                       \
+    /* Load current row of I0: */                                                                                      \
+    I0_row_16 = v_load(I0_ptr);                                                                                        \
+    v_expand(I0_row_16, I0_row_8, tmp);                                                                                \
+    v_expand(I0_row_8, I0_row_4_left, I0_row_4_right);                                                                 \
+                                                                                                                       \
+    /* Compute diffs between I0 and bilinearly interpolated I1: */                                                     \
+    I_diff_left = w00v * v_cvt_f32(v_reinterpret_as_s32(I1_row_4_left)) +                                              \
+                  w01v * v_cvt_f32(v_reinterpret_as_s32(I1_row_shifted_4_left)) +                                      \
+                  w10v * v_cvt_f32(v_reinterpret_as_s32(I1_row_next_4_left)) +                                         \
+                  w11v * v_cvt_f32(v_reinterpret_as_s32(I1_row_next_shifted_4_left)) -                                 \
+                  v_cvt_f32(v_reinterpret_as_s32(I0_row_4_left));                                                      \
+    I_diff_right = w00v * v_cvt_f32(v_reinterpret_as_s32(I1_row_4_right)) +                                            \
+                   w01v * v_cvt_f32(v_reinterpret_as_s32(I1_row_shifted_4_right)) +                                    \
+                   w10v * v_cvt_f32(v_reinterpret_as_s32(I1_row_next_4_right)) +                                       \
+                   w11v * v_cvt_f32(v_reinterpret_as_s32(I1_row_next_shifted_4_right)) -                               \
+                   v_cvt_f32(v_reinterpret_as_s32(I0_row_4_right));
+
+#define HAL_BILINEAR_8x8_PATCH_EXTRACTION_NEXT_ROW                                                                     \
+    I0_ptr += I0_stride;                                                                                               \
+    I1_ptr += I1_stride;                                                                                               \
+                                                                                                                       \
+    I1_row_4_left = I1_row_next_4_left;                                                                                \
+    I1_row_4_right = I1_row_next_4_right;                                                                              \
+    I1_row_shifted_4_left = I1_row_next_shifted_4_left;                                                                \
+    I1_row_shifted_4_right = I1_row_next_shifted_4_right;
+
+/* This function essentially performs one iteration of gradient descent when finding the most similar patch in I1 for a
+ * given one in I0. It assumes that I0_ptr and I1_ptr already point to the corresponding patches and w00, w01, w10, w11
+ * are precomputed bilinear interpolation weights. It returns the SSD (sum of squared differences) between these patches
+ * and computes the values (dst_dUx, dst_dUy) that are used in the flow vector update. HAL acceleration is implemented
+ * only for the default patch size (8x8). Everything is processed in floats as using fixed-point approximations harms
+ * the quality significantly.
+ */
+inline float processPatch(float &dst_dUx, float &dst_dUy, uchar *I0_ptr, uchar *I1_ptr, short *I0x_ptr, short *I0y_ptr,
+                          int I0_stride, int I1_stride, float w00, float w01, float w10, float w11, int patch_sz)
+{
+    float SSD = 0.0f;
+#ifdef CV_SIMD128
+    if (patch_sz == 8)
+    {
+        /* Variables to accumulate the sums */
+        v_float32x4 Ux_vec = v_setall_f32(0);
+        v_float32x4 Uy_vec = v_setall_f32(0);
+        v_float32x4 SSD_vec = v_setall_f32(0);
+
+        v_int16x8 I0x_row, I0y_row;
+        v_int32x4 I0x_row_4_left, I0x_row_4_right, I0y_row_4_left, I0y_row_4_right;
+
+        HAL_INIT_BILINEAR_8x8_PATCH_EXTRACTION;
+        for (int row = 0; row < 8; row++)
+        {
+            HAL_PROCESS_BILINEAR_8x8_PATCH_EXTRACTION;
+            I0x_row = v_load(I0x_ptr);
+            v_expand(I0x_row, I0x_row_4_left, I0x_row_4_right);
+            I0y_row = v_load(I0y_ptr);
+            v_expand(I0y_row, I0y_row_4_left, I0y_row_4_right);
+
+            /* Update the sums: */
+            Ux_vec += I_diff_left * v_cvt_f32(I0x_row_4_left) + I_diff_right * v_cvt_f32(I0x_row_4_right);
+            Uy_vec += I_diff_left * v_cvt_f32(I0y_row_4_left) + I_diff_right * v_cvt_f32(I0y_row_4_right);
+            SSD_vec += I_diff_left * I_diff_left + I_diff_right * I_diff_right;
+
+            I0x_ptr += I0_stride;
+            I0y_ptr += I0_stride;
+            HAL_BILINEAR_8x8_PATCH_EXTRACTION_NEXT_ROW;
+        }
+
+        /* Final reduce operations: */
+        dst_dUx = v_reduce_sum(Ux_vec);
+        dst_dUy = v_reduce_sum(Uy_vec);
+        SSD = v_reduce_sum(SSD_vec);
+    }
+    else
+    {
+#endif
+        dst_dUx = 0.0f;
+        dst_dUy = 0.0f;
+        float diff;
+        for (int i = 0; i < patch_sz; i++)
+            for (int j = 0; j < patch_sz; j++)
+            {
+                diff = w00 * I1_ptr[i * I1_stride + j] + w01 * I1_ptr[i * I1_stride + j + 1] +
+                       w10 * I1_ptr[(i + 1) * I1_stride + j] + w11 * I1_ptr[(i + 1) * I1_stride + j + 1] -
+                       I0_ptr[i * I0_stride + j];
+
+                SSD += diff * diff;
+                dst_dUx += diff * I0x_ptr[i * I0_stride + j];
+                dst_dUy += diff * I0y_ptr[i * I0_stride + j];
+            }
+#ifdef CV_SIMD128
+    }
+#endif
+    return SSD;
+}
+
+/* Same as processPatch, but with patch mean normalization, which improves robustness under changing
+ * lighting conditions
+ */
+inline float processPatchMeanNorm(float &dst_dUx, float &dst_dUy, uchar *I0_ptr, uchar *I1_ptr, short *I0x_ptr,
+                                  short *I0y_ptr, int I0_stride, int I1_stride, float w00, float w01, float w10,
+                                  float w11, int patch_sz, float x_grad_sum, float y_grad_sum)
+{
+    float sum_diff = 0.0, sum_diff_sq = 0.0;
+    float sum_I0x_mul = 0.0, sum_I0y_mul = 0.0;
+    float n = (float)patch_sz * patch_sz;
+
+#ifdef CV_SIMD128
+    if (patch_sz == 8)
+    {
+        /* Variables to accumulate the sums */
+        v_float32x4 sum_I0x_mul_vec = v_setall_f32(0);
+        v_float32x4 sum_I0y_mul_vec = v_setall_f32(0);
+        v_float32x4 sum_diff_vec = v_setall_f32(0);
+        v_float32x4 sum_diff_sq_vec = v_setall_f32(0);
+
+        v_int16x8 I0x_row, I0y_row;
+        v_int32x4 I0x_row_4_left, I0x_row_4_right, I0y_row_4_left, I0y_row_4_right;
+
+        HAL_INIT_BILINEAR_8x8_PATCH_EXTRACTION;
+        for (int row = 0; row < 8; row++)
+        {
+            HAL_PROCESS_BILINEAR_8x8_PATCH_EXTRACTION;
+            I0x_row = v_load(I0x_ptr);
+            v_expand(I0x_row, I0x_row_4_left, I0x_row_4_right);
+            I0y_row = v_load(I0y_ptr);
+            v_expand(I0y_row, I0y_row_4_left, I0y_row_4_right);
+
+            /* Update the sums: */
+            sum_I0x_mul_vec += I_diff_left * v_cvt_f32(I0x_row_4_left) + I_diff_right * v_cvt_f32(I0x_row_4_right);
+            sum_I0y_mul_vec += I_diff_left * v_cvt_f32(I0y_row_4_left) + I_diff_right * v_cvt_f32(I0y_row_4_right);
+            sum_diff_sq_vec += I_diff_left * I_diff_left + I_diff_right * I_diff_right;
+            sum_diff_vec += I_diff_left + I_diff_right;
+
+            I0x_ptr += I0_stride;
+            I0y_ptr += I0_stride;
+            HAL_BILINEAR_8x8_PATCH_EXTRACTION_NEXT_ROW;
+        }
+
+        /* Final reduce operations: */
+        sum_I0x_mul = v_reduce_sum(sum_I0x_mul_vec);
+        sum_I0y_mul = v_reduce_sum(sum_I0y_mul_vec);
+        sum_diff = v_reduce_sum(sum_diff_vec);
+        sum_diff_sq = v_reduce_sum(sum_diff_sq_vec);
+    }
+    else
+    {
+#endif
+        float diff;
+        for (int i = 0; i < patch_sz; i++)
+            for (int j = 0; j < patch_sz; j++)
+            {
+                diff = w00 * I1_ptr[i * I1_stride + j] + w01 * I1_ptr[i * I1_stride + j + 1] +
+                       w10 * I1_ptr[(i + 1) * I1_stride + j] + w11 * I1_ptr[(i + 1) * I1_stride + j + 1] -
+                       I0_ptr[i * I0_stride + j];
+
+                sum_diff += diff;
+                sum_diff_sq += diff * diff;
+
+                sum_I0x_mul += diff * I0x_ptr[i * I0_stride + j];
+                sum_I0y_mul += diff * I0y_ptr[i * I0_stride + j];
+            }
+#ifdef CV_SIMD128
+    }
+#endif
+    dst_dUx = sum_I0x_mul - sum_diff * x_grad_sum / n;
+    dst_dUy = sum_I0y_mul - sum_diff * y_grad_sum / n;
+    return sum_diff_sq - sum_diff * sum_diff / n;
+}
+
+/* Similar to processPatch, but compute only the sum of squared differences (SSD) between the patches */
+inline float computeSSD(uchar *I0_ptr, uchar *I1_ptr, int I0_stride, int I1_stride, float w00, float w01, float w10,
+                        float w11, int patch_sz)
+{
+    float SSD = 0.0f;
+#ifdef CV_SIMD128
+    if (patch_sz == 8)
+    {
+        v_float32x4 SSD_vec = v_setall_f32(0);
+        HAL_INIT_BILINEAR_8x8_PATCH_EXTRACTION;
+        for (int row = 0; row < 8; row++)
+        {
+            HAL_PROCESS_BILINEAR_8x8_PATCH_EXTRACTION;
+            SSD_vec += I_diff_left * I_diff_left + I_diff_right * I_diff_right;
+            HAL_BILINEAR_8x8_PATCH_EXTRACTION_NEXT_ROW;
+        }
+        SSD = v_reduce_sum(SSD_vec);
+    }
+    else
+    {
+#endif
+        float diff;
+        for (int i = 0; i < patch_sz; i++)
+            for (int j = 0; j < patch_sz; j++)
+            {
+                diff = w00 * I1_ptr[i * I1_stride + j] + w01 * I1_ptr[i * I1_stride + j + 1] +
+                       w10 * I1_ptr[(i + 1) * I1_stride + j] + w11 * I1_ptr[(i + 1) * I1_stride + j + 1] -
+                       I0_ptr[i * I0_stride + j];
+                SSD += diff * diff;
+            }
+#ifdef CV_SIMD128
+    }
+#endif
+    return SSD;
+}
+
+/* Same as computeSSD, but with patch mean normalization */
+inline float computeSSDMeanNorm(uchar *I0_ptr, uchar *I1_ptr, int I0_stride, int I1_stride, float w00, float w01,
+                                float w10, float w11, int patch_sz)
+{
+    float sum_diff = 0.0f, sum_diff_sq = 0.0f;
+    float n = (float)patch_sz * patch_sz;
+#ifdef CV_SIMD128
+    if (patch_sz == 8)
+    {
+        v_float32x4 sum_diff_vec = v_setall_f32(0);
+        v_float32x4 sum_diff_sq_vec = v_setall_f32(0);
+        HAL_INIT_BILINEAR_8x8_PATCH_EXTRACTION;
+        for (int row = 0; row < 8; row++)
+        {
+            HAL_PROCESS_BILINEAR_8x8_PATCH_EXTRACTION;
+            sum_diff_sq_vec += I_diff_left * I_diff_left + I_diff_right * I_diff_right;
+            sum_diff_vec += I_diff_left + I_diff_right;
+            HAL_BILINEAR_8x8_PATCH_EXTRACTION_NEXT_ROW;
+        }
+        sum_diff = v_reduce_sum(sum_diff_vec);
+        sum_diff_sq = v_reduce_sum(sum_diff_sq_vec);
+    }
+    else
+    {
+#endif
+        float diff;
+        for (int i = 0; i < patch_sz; i++)
+            for (int j = 0; j < patch_sz; j++)
+            {
+                diff = w00 * I1_ptr[i * I1_stride + j] + w01 * I1_ptr[i * I1_stride + j + 1] +
+                       w10 * I1_ptr[(i + 1) * I1_stride + j] + w11 * I1_ptr[(i + 1) * I1_stride + j + 1] -
+                       I0_ptr[i * I0_stride + j];
+
+                sum_diff += diff;
+                sum_diff_sq += diff * diff;
+            }
+#ifdef CV_SIMD128
+    }
+#endif
+    return sum_diff_sq - sum_diff * sum_diff / n;
+}
+
+#undef HAL_INIT_BILINEAR_8x8_PATCH_EXTRACTION
+#undef HAL_PROCESS_BILINEAR_8x8_PATCH_EXTRACTION
+#undef HAL_BILINEAR_8x8_PATCH_EXTRACTION_NEXT_ROW
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+void DISOpticalFlowImpl::PatchInverseSearch_ParBody::operator()(const Range &range) const
+{
+    // force separate processing of stripes if we are using spatial propagation:
+    if (dis->use_spatial_propagation && range.end > range.start + 1)
+    {
+        for (int n = range.start; n < range.end; n++)
+            (*this)(Range(n, n + 1));
+        return;
+    }
+    int psz = dis->patch_size;
+    int psz2 = psz / 2;
+    int w_ext = dis->w + 2 * dis->border_size; //!< width of I1_ext
+    int bsz = dis->border_size;
+
+    /* Input dense flow */
+    float *Ux_ptr = Ux->ptr<float>();
+    float *Uy_ptr = Uy->ptr<float>();
+
+    /* Output sparse flow */
+    float *Sx_ptr = Sx->ptr<float>();
+    float *Sy_ptr = Sy->ptr<float>();
+
+    uchar *I0_ptr = I0->ptr<uchar>();
+    uchar *I1_ptr = I1->ptr<uchar>();
+    short *I0x_ptr = I0x->ptr<short>();
+    short *I0y_ptr = I0y->ptr<short>();
+
+    /* Precomputed structure tensor */
+    float *xx_ptr = dis->I0xx_buf.ptr<float>();
+    float *yy_ptr = dis->I0yy_buf.ptr<float>();
+    float *xy_ptr = dis->I0xy_buf.ptr<float>();
+    /* And extra buffers for mean-normalization: */
+    float *x_ptr = dis->I0x_buf.ptr<float>();
+    float *y_ptr = dis->I0y_buf.ptr<float>();
+
+    bool use_temporal_candidates = false;
+    float *initial_Ux_ptr = NULL, *initial_Uy_ptr = NULL;
+    if (!dis->initial_Ux.empty())
+    {
+        initial_Ux_ptr = dis->initial_Ux[pyr_level].ptr<float>();
+        initial_Uy_ptr = dis->initial_Uy[pyr_level].ptr<float>();
+        use_temporal_candidates = true;
+    }
+
+    int i, j, dir;
+    int start_is, end_is, start_js, end_js;
+    int start_i, start_j;
+    float i_lower_limit = bsz - psz + 1.0f;
+    float i_upper_limit = bsz + dis->h - 1.0f;
+    float j_lower_limit = bsz - psz + 1.0f;
+    float j_upper_limit = bsz + dis->w - 1.0f;
+    float dUx, dUy, i_I1, j_I1, w00, w01, w10, w11, dx, dy;
+
+#define INIT_BILINEAR_WEIGHTS(Ux, Uy)                                                                                  \
+    i_I1 = min(max(i + Uy + bsz, i_lower_limit), i_upper_limit);                                                       \
+    j_I1 = min(max(j + Ux + bsz, j_lower_limit), j_upper_limit);                                                       \
+                                                                                                                       \
+    w11 = (i_I1 - floor(i_I1)) * (j_I1 - floor(j_I1));                                                                 \
+    w10 = (i_I1 - floor(i_I1)) * (floor(j_I1) + 1 - j_I1);                                                             \
+    w01 = (floor(i_I1) + 1 - i_I1) * (j_I1 - floor(j_I1));                                                             \
+    w00 = (floor(i_I1) + 1 - i_I1) * (floor(j_I1) + 1 - j_I1);
+
+#define COMPUTE_SSD(dst, Ux, Uy)                                                                                       \
+    INIT_BILINEAR_WEIGHTS(Ux, Uy);                                                                                     \
+    if (dis->use_mean_normalization)                                                                                   \
+        dst = computeSSDMeanNorm(I0_ptr + i * dis->w + j, I1_ptr + (int)i_I1 * w_ext + (int)j_I1, dis->w, w_ext, w00,  \
+                                 w01, w10, w11, psz);                                                                  \
+    else                                                                                                               \
+        dst = computeSSD(I0_ptr + i * dis->w + j, I1_ptr + (int)i_I1 * w_ext + (int)j_I1, dis->w, w_ext, w00, w01,     \
+                         w10, w11, psz);
+
+    int num_inner_iter = (int)floor(dis->grad_descent_iter / (float)num_iter);
+    for (int iter = 0; iter < num_iter; iter++)
+    {
+        if (iter % 2 == 0)
+        {
+            dir = 1;
+            start_is = min(range.start * stripe_sz, hs);
+            end_is = min(range.end * stripe_sz, hs);
+            start_js = 0;
+            end_js = dis->ws;
+            start_i = start_is * dis->patch_stride;
+            start_j = 0;
+        }
+        else
+        {
+            dir = -1;
+            start_is = min(range.end * stripe_sz, hs) - 1;
+            end_is = min(range.start * stripe_sz, hs) - 1;
+            start_js = dis->ws - 1;
+            end_js = -1;
+            start_i = start_is * dis->patch_stride;
+            start_j = (dis->ws - 1) * dis->patch_stride;
+        }
+
+        i = start_i;
+        for (int is = start_is; dir * is < dir * end_is; is += dir)
+        {
+            j = start_j;
+            for (int js = start_js; dir * js < dir * end_js; js += dir)
+            {
+                if (iter == 0)
+                {
+                    /* Using result form the previous pyramid level as the very first approximation: */
+                    Sx_ptr[is * dis->ws + js] = Ux_ptr[(i + psz2) * dis->w + j + psz2];
+                    Sy_ptr[is * dis->ws + js] = Uy_ptr[(i + psz2) * dis->w + j + psz2];
+                }
+
+                float min_SSD = INF, cur_SSD;
+                if (use_temporal_candidates || dis->use_spatial_propagation)
+                {
+                    COMPUTE_SSD(min_SSD, Sx_ptr[is * dis->ws + js], Sy_ptr[is * dis->ws + js]);
+                }
+
+                if (use_temporal_candidates)
+                {
+                    /* Try temporal candidates (vectors from the initial flow field that was passed to the function) */
+                    COMPUTE_SSD(cur_SSD, initial_Ux_ptr[(i + psz2) * dis->w + j + psz2],
+                                initial_Uy_ptr[(i + psz2) * dis->w + j + psz2]);
+                    if (cur_SSD < min_SSD)
+                    {
+                        min_SSD = cur_SSD;
+                        Sx_ptr[is * dis->ws + js] = initial_Ux_ptr[(i + psz2) * dis->w + j + psz2];
+                        Sy_ptr[is * dis->ws + js] = initial_Uy_ptr[(i + psz2) * dis->w + j + psz2];
+                    }
+                }
+
+                if (dis->use_spatial_propagation)
+                {
+                    /* Try spatial candidates: */
+                    if (dir * js > dir * start_js)
+                    {
+                        COMPUTE_SSD(cur_SSD, Sx_ptr[is * dis->ws + js - dir], Sy_ptr[is * dis->ws + js - dir]);
+                        if (cur_SSD < min_SSD)
+                        {
+                            min_SSD = cur_SSD;
+                            Sx_ptr[is * dis->ws + js] = Sx_ptr[is * dis->ws + js - dir];
+                            Sy_ptr[is * dis->ws + js] = Sy_ptr[is * dis->ws + js - dir];
+                        }
+                    }
+                    /* Flow vectors won't actually propagate across different stripes, which is the reason for keeping
+                     * the number of stripes constant. It works well enough in practice and doesn't introduce any
+                     * visible seams.
+                     */
+                    if (dir * is > dir * start_is)
+                    {
+                        COMPUTE_SSD(cur_SSD, Sx_ptr[(is - dir) * dis->ws + js], Sy_ptr[(is - dir) * dis->ws + js]);
+                        if (cur_SSD < min_SSD)
+                        {
+                            min_SSD = cur_SSD;
+                            Sx_ptr[is * dis->ws + js] = Sx_ptr[(is - dir) * dis->ws + js];
+                            Sy_ptr[is * dis->ws + js] = Sy_ptr[(is - dir) * dis->ws + js];
+                        }
+                    }
+                }
+
+                /* Use the best candidate as a starting point for the gradient descent: */
+                float cur_Ux = Sx_ptr[is * dis->ws + js];
+                float cur_Uy = Sy_ptr[is * dis->ws + js];
+
+                /* Computing the inverse of the structure tensor: */
+                float detH = xx_ptr[is * dis->ws + js] * yy_ptr[is * dis->ws + js] -
+                             xy_ptr[is * dis->ws + js] * xy_ptr[is * dis->ws + js];
+                if (abs(detH) < EPS)
+                    detH = EPS;
+                float invH11 = yy_ptr[is * dis->ws + js] / detH;
+                float invH12 = -xy_ptr[is * dis->ws + js] / detH;
+                float invH22 = xx_ptr[is * dis->ws + js] / detH;
+                float prev_SSD = INF, SSD;
+                float x_grad_sum = x_ptr[is * dis->ws + js];
+                float y_grad_sum = y_ptr[is * dis->ws + js];
+
+                for (int t = 0; t < num_inner_iter; t++)
+                {
+                    INIT_BILINEAR_WEIGHTS(cur_Ux, cur_Uy);
+                    if (dis->use_mean_normalization)
+                        SSD = processPatchMeanNorm(dUx, dUy, I0_ptr + i * dis->w + j,
+                                                   I1_ptr + (int)i_I1 * w_ext + (int)j_I1, I0x_ptr + i * dis->w + j,
+                                                   I0y_ptr + i * dis->w + j, dis->w, w_ext, w00, w01, w10, w11, psz,
+                                                   x_grad_sum, y_grad_sum);
+                    else
+                        SSD = processPatch(dUx, dUy, I0_ptr + i * dis->w + j, I1_ptr + (int)i_I1 * w_ext + (int)j_I1,
+                                           I0x_ptr + i * dis->w + j, I0y_ptr + i * dis->w + j, dis->w, w_ext, w00, w01,
+                                           w10, w11, psz);
+
+                    dx = invH11 * dUx + invH12 * dUy;
+                    dy = invH12 * dUx + invH22 * dUy;
+                    cur_Ux -= dx;
+                    cur_Uy -= dy;
+
+                    /* Break when patch distance stops decreasing */
+                    if (SSD >= prev_SSD)
+                        break;
+                    prev_SSD = SSD;
+                }
+
+                /* If gradient descent converged to a flow vector that is very far from the initial approximation
+                 * (more than patch size) then we don't use it. Noticeably improves the robustness.
+                 */
+                if (norm(Vec2f(cur_Ux - Sx_ptr[is * dis->ws + js], cur_Uy - Sy_ptr[is * dis->ws + js])) <= psz)
+                {
+                    Sx_ptr[is * dis->ws + js] = cur_Ux;
+                    Sy_ptr[is * dis->ws + js] = cur_Uy;
+                }
+                j += dir * dis->patch_stride;
+            }
+            i += dir * dis->patch_stride;
+        }
+    }
+#undef INIT_BILINEAR_WEIGHTS
+#undef COMPUTE_SSD
+}
+
+DISOpticalFlowImpl::Densification_ParBody::Densification_ParBody(DISOpticalFlowImpl &_dis, int _nstripes, int _h,
+                                                                 Mat &dst_Ux, Mat &dst_Uy, Mat &src_Sx, Mat &src_Sy,
+                                                                 Mat &_I0, Mat &_I1)
+    : dis(&_dis), nstripes(_nstripes), h(_h), Ux(&dst_Ux), Uy(&dst_Uy), Sx(&src_Sx), Sy(&src_Sy), I0(&_I0), I1(&_I1)
+{
+    stripe_sz = (int)ceil(h / (double)nstripes);
+}
+
+/* This function transforms a sparse optical flow field obtained by PatchInverseSearch (which computes flow values
+ * on a sparse grid defined by patch_stride) into a dense optical flow field by weighted averaging of values from the
+ * overlapping patches.
+ */
+void DISOpticalFlowImpl::Densification_ParBody::operator()(const Range &range) const
+{
+    int start_i = min(range.start * stripe_sz, h);
+    int end_i = min(range.end * stripe_sz, h);
+
+    /* Input sparse flow */
+    float *Sx_ptr = Sx->ptr<float>();
+    float *Sy_ptr = Sy->ptr<float>();
+
+    /* Output dense flow */
+    float *Ux_ptr = Ux->ptr<float>();
+    float *Uy_ptr = Uy->ptr<float>();
+
+    uchar *I0_ptr = I0->ptr<uchar>();
+    uchar *I1_ptr = I1->ptr<uchar>();
+
+    int psz = dis->patch_size;
+    int pstr = dis->patch_stride;
+    int i_l, i_u;
+    int j_l, j_u;
+    float i_m, j_m, diff;
+
+    /* These values define the set of sparse grid locations that contain patches overlapping with the current dense flow
+     * location */
+    int start_is, end_is;
+    int start_js, end_js;
+
+/* Some helper macros for updating this set of sparse grid locations */
+#define UPDATE_SPARSE_I_COORDINATES                                                                                    \
+    if (i % pstr == 0 && i + psz <= h)                                                                                 \
+        end_is++;                                                                                                      \
+    if (i - psz >= 0 && (i - psz) % pstr == 0 && start_is < end_is)                                                    \
+        start_is++;
+
+#define UPDATE_SPARSE_J_COORDINATES                                                                                    \
+    if (j % pstr == 0 && j + psz <= dis->w)                                                                            \
+        end_js++;                                                                                                      \
+    if (j - psz >= 0 && (j - psz) % pstr == 0 && start_js < end_js)                                                    \
+        start_js++;
+
+    start_is = 0;
+    end_is = -1;
+    for (int i = 0; i < start_i; i++)
+    {
+        UPDATE_SPARSE_I_COORDINATES;
+    }
+    for (int i = start_i; i < end_i; i++)
+    {
+        UPDATE_SPARSE_I_COORDINATES;
+        start_js = 0;
+        end_js = -1;
+        for (int j = 0; j < dis->w; j++)
+        {
+            UPDATE_SPARSE_J_COORDINATES;
+            float coef, sum_coef = 0.0f;
+            float sum_Ux = 0.0f;
+            float sum_Uy = 0.0f;
+
+            /* Iterate through all the patches that overlap the current location (i,j) */
+            for (int is = start_is; is <= end_is; is++)
+                for (int js = start_js; js <= end_js; js++)
+                {
+                    j_m = min(max(j + Sx_ptr[is * dis->ws + js], 0.0f), dis->w - 1.0f - EPS);
+                    i_m = min(max(i + Sy_ptr[is * dis->ws + js], 0.0f), dis->h - 1.0f - EPS);
+                    j_l = (int)j_m;
+                    j_u = j_l + 1;
+                    i_l = (int)i_m;
+                    i_u = i_l + 1;
+                    diff = (j_m - j_l) * (i_m - i_l) * I1_ptr[i_u * dis->w + j_u] +
+                           (j_u - j_m) * (i_m - i_l) * I1_ptr[i_u * dis->w + j_l] +
+                           (j_m - j_l) * (i_u - i_m) * I1_ptr[i_l * dis->w + j_u] +
+                           (j_u - j_m) * (i_u - i_m) * I1_ptr[i_l * dis->w + j_l] - I0_ptr[i * dis->w + j];
+                    coef = 1 / max(1.0f, abs(diff));
+                    sum_Ux += coef * Sx_ptr[is * dis->ws + js];
+                    sum_Uy += coef * Sy_ptr[is * dis->ws + js];
+                    sum_coef += coef;
+                }
+            Ux_ptr[i * dis->w + j] = sum_Ux / sum_coef;
+            Uy_ptr[i * dis->w + j] = sum_Uy / sum_coef;
+        }
+    }
+#undef UPDATE_SPARSE_I_COORDINATES
+#undef UPDATE_SPARSE_J_COORDINATES
+}
+
+void DISOpticalFlowImpl::calc(InputArray I0, InputArray I1, InputOutputArray flow)
+{
+    CV_Assert(!I0.empty() && I0.depth() == CV_8U && I0.channels() == 1);
+    CV_Assert(!I1.empty() && I1.depth() == CV_8U && I1.channels() == 1);
+    CV_Assert(I0.sameSize(I1));
+    CV_Assert(I0.isContinuous());
+    CV_Assert(I1.isContinuous());
+
+    Mat I0Mat = I0.getMat();
+    Mat I1Mat = I1.getMat();
+    bool use_input_flow = false;
+    if (flow.sameSize(I0) && flow.depth() == CV_32F && flow.channels() == 2)
+        use_input_flow = true;
+    else
+        flow.create(I1Mat.size(), CV_32FC2);
+    Mat &flowMat = flow.getMatRef();
+    coarsest_scale = (int)(log((2 * I0Mat.cols) / (4.0 * patch_size)) / log(2.0) + 0.5) - 1;
+    int num_stripes = getNumThreads();
+
+    prepareBuffers(I0Mat, I1Mat, flowMat, use_input_flow);
+    Ux[coarsest_scale].setTo(0.0f);
+    Uy[coarsest_scale].setTo(0.0f);
+
+    for (int i = coarsest_scale; i >= finest_scale; i--)
+    {
+        w = I0s[i].cols;
+        h = I0s[i].rows;
+        ws = 1 + (w - patch_size) / patch_stride;
+        hs = 1 + (h - patch_size) / patch_stride;
+
+        precomputeStructureTensor(I0xx_buf, I0yy_buf, I0xy_buf, I0x_buf, I0y_buf, I0xs[i], I0ys[i]);
+        if (use_spatial_propagation)
+        {
+            /* Use a fixed number of stripes regardless the number of threads to make inverse search
+             * with spatial propagation reproducible
+             */
+            parallel_for_(Range(0, 8), PatchInverseSearch_ParBody(*this, 8, hs, Sx, Sy, Ux[i], Uy[i], I0s[i],
+                                                                  I1s_ext[i], I0xs[i], I0ys[i], 2, i));
+        }
+        else
+        {
+            parallel_for_(Range(0, num_stripes),
+                          PatchInverseSearch_ParBody(*this, num_stripes, hs, Sx, Sy, Ux[i], Uy[i], I0s[i], I1s_ext[i],
+                                                     I0xs[i], I0ys[i], 1, i));
+        }
+
+        parallel_for_(Range(0, num_stripes),
+                      Densification_ParBody(*this, num_stripes, I0s[i].rows, Ux[i], Uy[i], Sx, Sy, I0s[i], I1s[i]));
+        if (variational_refinement_iter > 0)
+            variational_refinement_processors[i]->calcUV(I0s[i], I1s[i], Ux[i], Uy[i]);
+
+        if (i > finest_scale)
+        {
+            resize(Ux[i], Ux[i - 1], Ux[i - 1].size());
+            resize(Uy[i], Uy[i - 1], Uy[i - 1].size());
+            Ux[i - 1] *= 2;
+            Uy[i - 1] *= 2;
+        }
+    }
+    Mat uxy[] = {Ux[finest_scale], Uy[finest_scale]};
+    merge(uxy, 2, U);
+    resize(U, flowMat, flowMat.size());
+    flowMat *= 1 << finest_scale;
+}
+
+void DISOpticalFlowImpl::collectGarbage()
+{
+    I0s.clear();
+    I1s.clear();
+    I1s_ext.clear();
+    I0xs.clear();
+    I0ys.clear();
+    Ux.clear();
+    Uy.clear();
+    U.release();
+    Sx.release();
+    Sy.release();
+    I0xx_buf.release();
+    I0yy_buf.release();
+    I0xy_buf.release();
+    I0xx_buf_aux.release();
+    I0yy_buf_aux.release();
+    I0xy_buf_aux.release();
+
+    for (int i = finest_scale; i <= coarsest_scale; i++)
+        variational_refinement_processors[i]->collectGarbage();
+    variational_refinement_processors.clear();
+}
+
+Ptr<DISOpticalFlow> createOptFlow_DIS(int preset)
+{
+    Ptr<DISOpticalFlow> dis = makePtr<DISOpticalFlowImpl>();
+    dis->setPatchSize(8);
+    if (preset == DISOpticalFlow::PRESET_ULTRAFAST)
+    {
+        dis->setFinestScale(2);
+        dis->setPatchStride(4);
+        dis->setGradientDescentIterations(12);
+        dis->setVariationalRefinementIterations(0);
+    }
+    else if (preset == DISOpticalFlow::PRESET_FAST)
+    {
+        dis->setFinestScale(2);
+        dis->setPatchStride(4);
+        dis->setGradientDescentIterations(16);
+        dis->setVariationalRefinementIterations(5);
+    }
+    else if (preset == DISOpticalFlow::PRESET_MEDIUM)
+    {
+        dis->setFinestScale(1);
+        dis->setPatchStride(3);
+        dis->setGradientDescentIterations(25);
+        dis->setVariationalRefinementIterations(5);
+    }
+
+    return dis;
+}
+}
+}
diff --git a/contrib/modules/optflow/src/learn_prior.py b/contrib/modules/optflow/src/learn_prior.py
new file mode 100644
index 0000000..8148b23
--- /dev/null
+++ b/contrib/modules/optflow/src/learn_prior.py
@@ -0,0 +1,166 @@
+#!/usr/bin/env python
+
+import os
+import sys
+import numpy as np
+import cv2
+import struct
+import argparse
+from math import sqrt
+
+argparser = argparse.ArgumentParser(
+    description='''Use this script to generate prior for using with PCAFlow.
+Basis size here must match corresponding parameter in the PCAFlow.
+Gamma should be selected experimentally.''')
+
+argparser.add_argument('-f',
+                       '--files',
+                       nargs='+',
+                       help='List of optical flow .flo files for learning. You can pass a directory here and it will be scanned recursively for .flo files.',
+                       required=True)
+argparser.add_argument('-o',
+                       '--output',
+                       help='Output file for prior',
+                       required=True)
+argparser.add_argument('--width',
+                       type=int,
+                       help='Size of the basis first dimension',
+                       required=True,
+                       default=18)
+argparser.add_argument('--height',
+                       type=int,
+                       help='Size of the basis second dimension',
+                       required=True,
+                       default=14)
+argparser.add_argument(
+    '-g',
+    '--gamma',
+    type=float,
+    help='Amount of regularization. The greater this parameter, the bigger will be an impact of the regularization.',
+    required=True)
+args = argparser.parse_args()
+
+basis_size = (args.height, args.width)
+gamma = args.gamma
+
+
+def find_flo(pp):
+    f = []
+    for p in pp:
+        if os.path.isfile(p):
+            f.append(p)
+        else:
+            for root, subdirs, files in os.walk(p):
+                f += map(lambda x: os.path.join(root, x),
+                         filter(lambda x: x.split('.')[-1] == 'flo', files))
+    return list(set(f))
+
+
+def load_flo(flo):
+    with open(flo, 'rb') as f:
+        magic = np.fromfile(f, np.float32, count=1)[0]
+        if 202021.25 != magic:
+            print('Magic number incorrect. Invalid .flo file')
+        else:
+            w = np.fromfile(f, np.int32, count=1)[0]
+            h = np.fromfile(f, np.int32, count=1)[0]
+            print('Reading %dx%d flo file %s' % (w, h, flo))
+            data = np.fromfile(f, np.float32, count=2 * w * h)
+            # Reshape data into 3D array (columns, rows, bands)
+            flow = np.reshape(data, (h, w, 2))
+            return flow[:, :, 0], flow[:, :, 1]
+
+
+def get_w(m):
+    s = m.shape
+    w = cv2.dct(m)
+    w *= 2.0 / sqrt(s[0] * s[1])
+    #w[0,0] *= 0.5
+    w[:, 0] *= sqrt(0.5)
+    w[0, :] *= sqrt(0.5)
+    w = w[0:basis_size[0], 0:basis_size[1]].transpose().flatten()
+    return w
+
+
+w1 = []
+w2 = []
+
+for flo in find_flo(args.files):
+    x, y = load_flo(flo)
+    w1.append(get_w(x))
+    w2.append(get_w(y))
+
+w1mean = sum(w1) / len(w1)
+w2mean = sum(w2) / len(w2)
+
+for i in xrange(len(w1)):
+    w1[i] -= w1mean
+for i in xrange(len(w2)):
+    w2[i] -= w2mean
+
+Q1 = sum([w1[i].reshape(-1, 1).dot(w1[i].reshape(1, -1))
+          for i in xrange(len(w1))]) / len(w1)
+Q2 = sum([w2[i].reshape(-1, 1).dot(w2[i].reshape(1, -1))
+          for i in xrange(len(w2))]) / len(w2)
+Q1 = np.matrix(Q1)
+Q2 = np.matrix(Q2)
+
+if len(w1) > 1:
+    while True:
+        try:
+            L1 = np.linalg.cholesky(Q1)
+            break
+        except np.linalg.linalg.LinAlgError:
+            mev = min(np.linalg.eig(Q1)[0]).real
+            assert (mev < 0)
+            print('Q1', mev)
+            if -mev < 1e-6:
+                mev = -1e-6
+            Q1 += (-mev * 1.000001) * np.identity(Q1.shape[0])
+
+    while True:
+        try:
+            L2 = np.linalg.cholesky(Q2)
+            break
+        except np.linalg.linalg.LinAlgError:
+            mev = min(np.linalg.eig(Q2)[0]).real
+            assert (mev < 0)
+            print('Q2', mev)
+            if -mev < 1e-6:
+                mev = -1e-6
+            Q2 += (-mev * 1.000001) * np.identity(Q2.shape[0])
+else:
+    L1 = np.identity(Q1.shape[0])
+    L2 = np.identity(Q2.shape[0])
+
+L1 = np.linalg.inv(L1) * gamma
+L2 = np.linalg.inv(L2) * gamma
+
+assert (L1.shape == L2.shape)
+assert (L1.shape[0] == L1.shape[1])
+
+f = open(args.output, 'wb')
+
+f.write(struct.pack('I', L1.shape[0]))
+f.write(struct.pack('I', L1.shape[1]))
+
+for i in xrange(L1.shape[0]):
+    for j in xrange(L1.shape[1]):
+        f.write(struct.pack('f', L1[i, j]))
+
+for i in xrange(L2.shape[0]):
+    for j in xrange(L2.shape[1]):
+        f.write(struct.pack('f', L2[i, j]))
+
+b1 = L1.dot(w1mean.reshape(-1, 1))
+b2 = L2.dot(w2mean.reshape(-1, 1))
+
+assert (L1.shape[0] == b1.shape[0])
+
+for i in xrange(b1.shape[0]):
+    f.write(struct.pack('f', b1[i, 0]))
+
+for i in xrange(b2.shape[0]):
+    f.write(struct.pack('f', b2[i, 0]))
+
+f.close()
diff --git a/contrib/modules/optflow/src/motempl.cpp b/contrib/modules/optflow/src/motempl.cpp
index 452ad63..83ff017 100644
--- a/contrib/modules/optflow/src/motempl.cpp
+++ b/contrib/modules/optflow/src/motempl.cpp
@@ -42,6 +42,7 @@
 #include "precomp.hpp"
 #include "opencv2/core/utility.hpp"
 #include "opencv2/core/hal/hal.hpp"
+#include "opencv2/core/private.hpp"
 #include "opencl_kernels_optflow.hpp"
 
 namespace  cv {
@@ -54,7 +55,7 @@ using std::vector;
 static bool ocl_updateMotionHistory( InputArray _silhouette, InputOutputArray _mhi,
                                      float timestamp, float delbound )
 {
-    ocl::Kernel k("updateMotionHistory", ocl::video::updatemotionhistory_oclsrc);
+    ocl::Kernel k("updateMotionHistory", ocl::optflow::updatemotionhistory_oclsrc);
     if (k.empty())
         return false;
 
diff --git a/contrib/modules/optflow/src/opencl/sparse_matching_gpc.cl b/contrib/modules/optflow/src/opencl/sparse_matching_gpc.cl
new file mode 100644
index 0000000..ba19d7b
--- /dev/null
+++ b/contrib/modules/optflow/src/opencl/sparse_matching_gpc.cl
@@ -0,0 +1,69 @@
+// This file is part of OpenCV project.
+// It is subject to the license terms in the LICENSE file found in the top-level directory
+// of this distribution and at http://opencv.org/license.html.
+
+// Copyright (C) 2016, Itseez, Inc., all rights reserved.
+// Third party copyrights are property of their respective owners.
+
+// @Authors
+//    Vladislav Samsonov, vvladxx at gmail.com
+
+__kernel void getPatchDescriptor(
+  __global const uchar* imgCh0, int ic0step, int ic0off,
+  __global const uchar* imgCh1, int ic1step, int ic1off,
+  __global const uchar* imgCh2, int ic2step, int ic2off,
+  __global uchar* out, int outstep, int outoff,
+  const int gh, const int gw, const int PR  )
+{
+  const int i = get_global_id(0);
+  const int j = get_global_id(1);
+
+  if (i >= gh || j >= gw)
+    return;
+
+  __global double* desc = (__global double*)(out + (outstep * (i * gw + j) + outoff));
+  const int patchRadius = PR * 2;
+  float patch[PATCH_RADIUS_DOUBLED][PATCH_RADIUS_DOUBLED];
+
+  for (int i0 = 0; i0 < patchRadius; ++i0) {
+    __global const float* ch0Row = (__global const float*)(imgCh0 + (ic0step * (i + i0) + ic0off + j * sizeof(float)));
+    for (int j0 = 0; j0 < patchRadius; ++j0)
+      patch[i0][j0] = ch0Row[j0];
+  }
+
+  #pragma unroll
+  for (int n0 = 0; n0 < 4; ++n0) {
+    #pragma unroll
+    for (int n1 = 0; n1 < 4; ++n1) {
+      double sum = 0;
+      for (int i0 = 0; i0 < patchRadius; ++i0)
+        for (int j0 = 0; j0 < patchRadius; ++j0)
+          sum += patch[i0][j0] * cos(CV_PI * (i0 + 0.5) * n0 / patchRadius) * cos(CV_PI * (j0 + 0.5) * n1 / patchRadius);
+      desc[n0 * 4 + n1] = sum / PR;
+    }
+  }
+
+  for (int k = 0; k < 4; ++k) {
+    desc[k] *= SQRT2_INV;
+    desc[k * 4] *= SQRT2_INV;
+  }
+
+  double sum = 0;
+
+  for (int i0 = 0; i0 < patchRadius; ++i0) {
+    __global const float* ch1Row = (__global const float*)(imgCh1 + (ic1step * (i + i0) + ic1off + j * sizeof(float)));
+    for (int j0 = 0; j0 < patchRadius; ++j0)
+      sum += ch1Row[j0];
+  }
+
+  desc[16] = sum / patchRadius;
+  sum = 0;
+
+  for (int i0 = 0; i0 < patchRadius; ++i0) {
+    __global const float* ch2Row = (__global const float*)(imgCh2 + (ic2step * (i + i0) + ic2off + j * sizeof(float)));
+    for (int j0 = 0; j0 < patchRadius; ++j0)
+      sum += ch2Row[j0];
+  }
+
+  desc[17] = sum / patchRadius;
+}
diff --git a/contrib/modules/optflow/src/pcaflow.cpp b/contrib/modules/optflow/src/pcaflow.cpp
new file mode 100644
index 0000000..9eaeb5e
--- /dev/null
+++ b/contrib/modules/optflow/src/pcaflow.cpp
@@ -0,0 +1,526 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+ //
+ //  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+ //
+ //  By downloading, copying, installing or using the software you agree to this license.
+ //  If you do not agree to this license, do not download, install,
+ //  copy or use the software.
+ //
+ //
+ //                           License Agreement
+ //                For Open Source Computer Vision Library
+ //
+ // Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
+ // Copyright (C) 2009, Willow Garage Inc., all rights reserved.
+ // Third party copyrights are property of their respective owners.
+ //
+ // Redistribution and use in source and binary forms, with or without modification,
+ // are permitted provided that the following conditions are met:
+ //
+ //   * Redistribution's of source code must retain the above copyright notice,
+ //     this list of conditions and the following disclaimer.
+ //
+ //   * Redistribution's in binary form must reproduce the above copyright notice,
+ //     this list of conditions and the following disclaimer in the documentation
+ //     and/or other materials provided with the distribution.
+ //
+ //   * The name of the copyright holders may not be used to endorse or promote products
+ //     derived from this software without specific prior written permission.
+ //
+ // This software is provided by the copyright holders and contributors "as is" and
+ // any express or implied warranties, including, but not limited to, the implied
+ // warranties of merchantability and fitness for a particular purpose are disclaimed.
+ // In no event shall the Intel Corporation or contributors be liable for any direct,
+ // indirect, incidental, special, exemplary, or consequential damages
+ // (including, but not limited to, procurement of substitute goods or services;
+ // loss of use, data, or profits; or business interruption) however caused
+ // and on any theory of liability, whether in contract, strict liability,
+ // or tort (including negligence or otherwise) arising in any way out of
+ // the use of this software, even if advised of the possibility of such damage.
+ //
+ //M*/
+
+#include "opencv2/ximgproc/edge_filter.hpp"
+#include "precomp.hpp"
+
+/* Disable "from double to float" and "from size_t to int" warnings.
+ * Fixing these would make the code look ugly by introducing explicit cast all around.
+ * Here these warning are pointless anyway.
+ */
+#ifdef _MSC_VER
+#pragma warning( disable : 4305 4244 4267 4838 )
+#endif
+#ifdef __clang__
+#pragma clang diagnostic ignored "-Wshorten-64-to-32"
+#endif
+
+namespace cv
+{
+namespace optflow
+{
+namespace
+{
+
+#ifndef M_SQRT2
+const float M_SQRT2 = 1.41421356237309504880;
+#endif
+
+template <typename T> inline int mathSign( T val ) { return ( T( 0 ) < val ) - ( val < T( 0 ) ); }
+
+/* Stable symmetric Householder reflection that gives c and s such that
+ *   [ c  s ][a] = [d],
+ *   [ s -c ][b]   [0]
+ *
+ * Output:
+ *   c -- cosine(theta), where theta is the implicit angle of rotation
+ *        (counter-clockwise) in a plane-rotation
+ *   s -- sine(theta)
+ *   r -- two-norm of [a; b]
+ */
+inline void symOrtho( double a, double b, double &c, double &s, double &r )
+{
+  if ( b == 0 )
+  {
+    c = mathSign( a );
+    s = 0;
+    r = std::abs( a );
+  }
+  else if ( a == 0 )
+  {
+    c = 0;
+    s = mathSign( b );
+    r = std::abs( b );
+  }
+  else if ( std::abs( b ) > std::abs( a ) )
+  {
+    const double tau = a / b;
+    s = mathSign( b ) / std::sqrt( 1 + tau * tau );
+    c = s * tau;
+    r = b / s;
+  }
+  else
+  {
+    const double tau = b / a;
+    c = mathSign( a ) / std::sqrt( 1 + tau * tau );
+    s = c * tau;
+    r = a / c;
+  }
+}
+
+/* Iterative LSQR algorithm for solving least squares problems.
+ *
+ * [1] Paige, C. C. and M. A. Saunders,
+ * LSQR: An Algorithm for Sparse Linear Equations And Sparse Least Squares
+ * ACM Trans. Math. Soft., Vol.8, 1982, pp. 43-71.
+ *
+ * Solves the following problem:
+ *   argmin_x ||Ax - b|| + damp||x||
+ *
+ * Output:
+ *   x -- approximate solution
+ */
+void solveLSQR( const Mat &A, const Mat &b, OutputArray xOut, const double damp = 0.0, const unsigned iter_lim = 10 )
+{
+  const int n = A.size().width;
+  CV_Assert( A.size().height == b.size().height );
+  CV_Assert( A.type() == CV_32F );
+  CV_Assert( b.type() == CV_32F );
+  xOut.create( n, 1, CV_32F );
+
+  Mat v( n, 1, CV_32F, 0.0f );
+  Mat u = b;
+  Mat x = xOut.getMat();
+  x = Mat::zeros( x.size(), x.type() );
+  double alfa = 0;
+  double beta = cv::norm( u, NORM_L2 );
+  Mat w( n, 1, CV_32F, 0.0f );
+  const Mat AT = A.t();
+
+  if ( beta > 0 )
+  {
+    u *= 1 / beta;
+    v = AT * u;
+    alfa = cv::norm( v, NORM_L2 );
+  }
+
+  if ( alfa > 0 )
+  {
+    v *= 1 / alfa;
+    w = v.clone();
+  }
+
+  double rhobar = alfa;
+  double phibar = beta;
+  if ( alfa * beta == 0 )
+    return;
+
+  for ( unsigned itn = 0; itn < iter_lim; ++itn )
+  {
+    u *= -alfa;
+    u += A * v;
+    beta = cv::norm( u, NORM_L2 );
+
+    if ( beta > 0 )
+    {
+      u *= 1 / beta;
+      v *= -beta;
+      v += AT * u;
+      alfa = cv::norm( v, NORM_L2 );
+      if ( alfa > 0 )
+        v *= 1 / alfa;
+    }
+
+    double rhobar1 = sqrt( rhobar * rhobar + damp * damp );
+    double cs1 = rhobar / rhobar1;
+    phibar = cs1 * phibar;
+
+    double cs, sn, rho;
+    symOrtho( rhobar1, beta, cs, sn, rho );
+
+    double theta = sn * alfa;
+    rhobar = -cs * alfa;
+    double phi = cs * phibar;
+    phibar = sn * phibar;
+
+    double t1 = phi / rho;
+    double t2 = -theta / rho;
+
+    x += t1 * w;
+    w *= t2;
+    w += v;
+  }
+}
+
+inline void _cpu_fillDCTSampledPoints( float *row, const Point2f &p, const Size &basisSize, const Size &size )
+{
+  for ( int n1 = 0; n1 < basisSize.width; ++n1 )
+    for ( int n2 = 0; n2 < basisSize.height; ++n2 )
+      row[n1 * basisSize.height + n2] =
+        cosf( ( n1 * CV_PI / size.width ) * ( p.x + 0.5 ) ) * cosf( ( n2 * CV_PI / size.height ) * ( p.y + 0.5 ) );
+}
+
+ocl::ProgramSource _ocl_fillDCTSampledPointsSource(
+  "__kernel void fillDCTSampledPoints(__global const uchar* features, int fstep, int foff, __global "
+  "uchar* A, int Astep, int Aoff, int fs, int bsw, int bsh, int sw, int sh) {"
+  "const int i = get_global_id(0);"
+  "const int n1 = get_global_id(1);"
+  "const int n2 = get_global_id(2);"
+  "if (i >= fs || n1 >= bsw || n2 >= bsh) return;"
+  "__global const float2* f = (__global const float2*)(features + (fstep * i + foff));"
+  "__global float* a = (__global float*)(A + (Astep * i + Aoff + (n1 * bsh + n2) * sizeof(float)));"
+  "const float2 p = f[0];"
+  "const float pi = 3.14159265358979323846;"
+  "a[0] = cos((n1 * pi / sw) * (p.x + 0.5)) * cos((n2 * pi / sh) * (p.y + 0.5));"
+  "}" );
+
+void applyCLAHE( UMat &img, float claheClip )
+{
+  Ptr<CLAHE> clahe = createCLAHE();
+  clahe->setClipLimit( claheClip );
+  clahe->apply( img, img );
+}
+
+void reduceToFlow( const Mat &w1, const Mat &w2, Mat &flow, const Size &basisSize )
+{
+  const Size size = flow.size();
+  Mat flowX( size, CV_32F, 0.0f );
+  Mat flowY( size, CV_32F, 0.0f );
+
+  const float mult = sqrt( static_cast<float>(size.area()) ) * 0.5;
+
+  for ( int i = 0; i < basisSize.width; ++i )
+    for ( int j = 0; j < basisSize.height; ++j )
+    {
+      flowX.at<float>( j, i ) = w1.at<float>( i * basisSize.height + j ) * mult;
+      flowY.at<float>( j, i ) = w2.at<float>( i * basisSize.height + j ) * mult;
+    }
+  for ( int i = 0; i < basisSize.height; ++i )
+  {
+    flowX.at<float>( i, 0 ) *= M_SQRT2;
+    flowY.at<float>( i, 0 ) *= M_SQRT2;
+  }
+  for ( int i = 0; i < basisSize.width; ++i )
+  {
+    flowX.at<float>( 0, i ) *= M_SQRT2;
+    flowY.at<float>( 0, i ) *= M_SQRT2;
+  }
+
+  dct( flowX, flowX, DCT_INVERSE );
+  dct( flowY, flowY, DCT_INVERSE );
+  for ( int i = 0; i < size.height; ++i )
+    for ( int j = 0; j < size.width; ++j )
+      flow.at<Point2f>( i, j ) = Point2f( flowX.at<float>( i, j ), flowY.at<float>( i, j ) );
+}
+}
+
+void OpticalFlowPCAFlow::findSparseFeatures( UMat &from, UMat &to, std::vector<Point2f> &features,
+                                             std::vector<Point2f> &predictedFeatures ) const
+{
+  Size size = from.size();
+  const unsigned maxFeatures = size.area() * sparseRate;
+  goodFeaturesToTrack( from, features, maxFeatures * retainedCornersFraction, 0.005, 3 );
+
+  // Add points along the grid if not enough features
+  if ( maxFeatures > features.size() )
+  {
+    const unsigned missingPoints = maxFeatures - features.size();
+    const unsigned blockSize = sqrt( (float)size.area() / missingPoints );
+    for ( int x = blockSize / 2; x < size.width; x += blockSize )
+      for ( int y = blockSize / 2; y < size.height; y += blockSize )
+        features.push_back( Point2f( x, y ) );
+  }
+  std::vector<uchar> predictedStatus;
+  std::vector<float> predictedError;
+  calcOpticalFlowPyrLK( from, to, features, predictedFeatures, predictedStatus, predictedError );
+
+  size_t j = 0;
+  for ( size_t i = 0; i < features.size(); ++i )
+  {
+    if ( predictedStatus[i] )
+    {
+      features[j] = features[i];
+      predictedFeatures[j] = predictedFeatures[i];
+      ++j;
+    }
+  }
+  features.resize( j );
+  predictedFeatures.resize( j );
+}
+
+void OpticalFlowPCAFlow::removeOcclusions( UMat &from, UMat &to, std::vector<Point2f> &features,
+                                           std::vector<Point2f> &predictedFeatures ) const
+{
+  std::vector<uchar> predictedStatus;
+  std::vector<float> predictedError;
+  std::vector<Point2f> backwardFeatures;
+  calcOpticalFlowPyrLK( to, from, predictedFeatures, backwardFeatures, predictedStatus, predictedError );
+
+  size_t j = 0;
+  const float threshold = occlusionsThreshold * sqrt( static_cast<float>(from.size().area()) );
+  for ( size_t i = 0; i < predictedFeatures.size(); ++i )
+  {
+    if ( predictedStatus[i] )
+    {
+      Point2f flowDiff = features[i] - backwardFeatures[i];
+      if ( flowDiff.dot( flowDiff ) <= threshold )
+      {
+        features[j] = features[i];
+        predictedFeatures[j] = predictedFeatures[i];
+        ++j;
+      }
+    }
+  }
+  features.resize( j );
+  predictedFeatures.resize( j );
+}
+
+void OpticalFlowPCAFlow::getSystem( OutputArray AOut, OutputArray b1Out, OutputArray b2Out,
+                                    const std::vector<Point2f> &features, const std::vector<Point2f> &predictedFeatures,
+                                    const Size size )
+{
+  AOut.create( features.size(), basisSize.area(), CV_32F );
+  b1Out.create( features.size(), 1, CV_32F );
+  b2Out.create( features.size(), 1, CV_32F );
+  if ( useOpenCL )
+  {
+    UMat A = AOut.getUMat();
+    Mat b1 = b1Out.getMat();
+    Mat b2 = b2Out.getMat();
+
+    ocl::Kernel kernel( "fillDCTSampledPoints", _ocl_fillDCTSampledPointsSource );
+    size_t globSize[] = {features.size(), basisSize.width, basisSize.height};
+    kernel
+      .args( cv::ocl::KernelArg::ReadOnlyNoSize( Mat( features ).getUMat( ACCESS_READ ) ),
+             cv::ocl::KernelArg::WriteOnlyNoSize( A ), (int)features.size(), (int)basisSize.width,
+             (int)basisSize.height, (int)size.width, (int)size.height )
+      .run( 3, globSize, 0, true );
+
+    for ( size_t i = 0; i < features.size(); ++i )
+    {
+      const Point2f flow = predictedFeatures[i] - features[i];
+      b1.at<float>( i ) = flow.x;
+      b2.at<float>( i ) = flow.y;
+    }
+  }
+  else
+  {
+    Mat A = AOut.getMat();
+    Mat b1 = b1Out.getMat();
+    Mat b2 = b2Out.getMat();
+
+    for ( size_t i = 0; i < features.size(); ++i )
+    {
+      _cpu_fillDCTSampledPoints( A.ptr<float>( i ), features[i], basisSize, size );
+      const Point2f flow = predictedFeatures[i] - features[i];
+      b1.at<float>( i ) = flow.x;
+      b2.at<float>( i ) = flow.y;
+    }
+  }
+}
+
+void OpticalFlowPCAFlow::getSystem( OutputArray A1Out, OutputArray A2Out, OutputArray b1Out, OutputArray b2Out,
+                                    const std::vector<Point2f> &features, const std::vector<Point2f> &predictedFeatures,
+                                    const Size size )
+{
+  CV_Assert( prior->getBasisSize() == basisSize.area() );
+
+  A1Out.create( features.size() + prior->getPadding(), basisSize.area(), CV_32F );
+  A2Out.create( features.size() + prior->getPadding(), basisSize.area(), CV_32F );
+  b1Out.create( features.size() + prior->getPadding(), 1, CV_32F );
+  b2Out.create( features.size() + prior->getPadding(), 1, CV_32F );
+
+  if ( useOpenCL )
+  {
+    UMat A = A1Out.getUMat();
+    Mat b1 = b1Out.getMat();
+    Mat b2 = b2Out.getMat();
+
+    ocl::Kernel kernel( "fillDCTSampledPoints", _ocl_fillDCTSampledPointsSource );
+    size_t globSize[] = {features.size(), basisSize.width, basisSize.height};
+    kernel
+      .args( cv::ocl::KernelArg::ReadOnlyNoSize( Mat( features ).getUMat( ACCESS_READ ) ),
+             cv::ocl::KernelArg::WriteOnlyNoSize( A ), (int)features.size(), (int)basisSize.width,
+             (int)basisSize.height, (int)size.width, (int)size.height )
+      .run( 3, globSize, 0, true );
+
+    for ( size_t i = 0; i < features.size(); ++i )
+    {
+      const Point2f flow = predictedFeatures[i] - features[i];
+      b1.at<float>( i ) = flow.x;
+      b2.at<float>( i ) = flow.y;
+    }
+  }
+  else
+  {
+    Mat A1 = A1Out.getMat();
+    Mat b1 = b1Out.getMat();
+    Mat b2 = b2Out.getMat();
+
+    for ( size_t i = 0; i < features.size(); ++i )
+    {
+      _cpu_fillDCTSampledPoints( A1.ptr<float>( i ), features[i], basisSize, size );
+      const Point2f flow = predictedFeatures[i] - features[i];
+      b1.at<float>( i ) = flow.x;
+      b2.at<float>( i ) = flow.y;
+    }
+  }
+
+  Mat A1 = A1Out.getMat();
+  Mat A2 = A2Out.getMat();
+  Mat b1 = b1Out.getMat();
+  Mat b2 = b2Out.getMat();
+
+  memcpy( A2.ptr<float>(), A1.ptr<float>(), features.size() * basisSize.area() * sizeof( float ) );
+  prior->fillConstraints( A1.ptr<float>( features.size(), 0 ), A2.ptr<float>( features.size(), 0 ),
+                          b1.ptr<float>( features.size(), 0 ), b2.ptr<float>( features.size(), 0 ) );
+}
+
+void OpticalFlowPCAFlow::calc( InputArray I0, InputArray I1, InputOutputArray flowOut )
+{
+  const Size size = I0.size();
+  CV_Assert( size == I1.size() );
+
+  UMat from, to;
+  if ( I0.channels() == 3 )
+  {
+    cvtColor( I0, from, COLOR_BGR2GRAY );
+    from.convertTo( from, CV_8U );
+  }
+  else
+  {
+    I0.getMat().convertTo( from, CV_8U );
+  }
+  if ( I1.channels() == 3 )
+  {
+    cvtColor( I1, to, COLOR_BGR2GRAY );
+    to.convertTo( to, CV_8U );
+  }
+  else
+  {
+    I1.getMat().convertTo( to, CV_8U );
+  }
+
+  CV_Assert( from.channels() == 1 );
+  CV_Assert( to.channels() == 1 );
+
+  const Mat fromOrig = from.getMat( ACCESS_READ ).clone();
+  useOpenCL = flowOut.isUMat() && ocl::useOpenCL();
+
+  applyCLAHE( from, claheClip );
+  applyCLAHE( to, claheClip );
+
+  std::vector<Point2f> features, predictedFeatures;
+  findSparseFeatures( from, to, features, predictedFeatures );
+  removeOcclusions( from, to, features, predictedFeatures );
+
+  flowOut.create( size, CV_32FC2 );
+  Mat flow = flowOut.getMat();
+
+  Mat w1, w2;
+  if ( prior.get() )
+  {
+    Mat A1, A2, b1, b2;
+    getSystem( A1, A2, b1, b2, features, predictedFeatures, size );
+    solveLSQR( A1, b1, w1, dampingFactor * size.area() );
+    solveLSQR( A2, b2, w2, dampingFactor * size.area() );
+  }
+  else
+  {
+    Mat A, b1, b2;
+    getSystem( A, b1, b2, features, predictedFeatures, size );
+    solveLSQR( A, b1, w1, dampingFactor * size.area() );
+    solveLSQR( A, b2, w2, dampingFactor * size.area() );
+  }
+  Mat flowSmall( ( size / 8 ) * 2, CV_32FC2 );
+  reduceToFlow( w1, w2, flowSmall, basisSize );
+  resize( flowSmall, flow, size, 0, 0, INTER_LINEAR );
+  ximgproc::fastGlobalSmootherFilter( fromOrig, flow, flow, 500, 2 );
+}
+
+OpticalFlowPCAFlow::OpticalFlowPCAFlow( Ptr<const PCAPrior> _prior, const Size _basisSize, float _sparseRate,
+                                        float _retainedCornersFraction, float _occlusionsThreshold,
+                                        float _dampingFactor, float _claheClip )
+    : prior( _prior ), basisSize( _basisSize ), sparseRate( _sparseRate ),
+      retainedCornersFraction( _retainedCornersFraction ), occlusionsThreshold( _occlusionsThreshold ),
+      dampingFactor( _dampingFactor ), claheClip( _claheClip ), useOpenCL( false )
+{
+  CV_Assert( sparseRate > 0 && sparseRate <= 0.1 );
+  CV_Assert( retainedCornersFraction >= 0 && retainedCornersFraction <= 1.0 );
+  CV_Assert( occlusionsThreshold > 0 );
+}
+
+void OpticalFlowPCAFlow::collectGarbage() {}
+
+Ptr<DenseOpticalFlow> createOptFlow_PCAFlow() { return makePtr<OpticalFlowPCAFlow>(); }
+
+PCAPrior::PCAPrior( const char *pathToPrior )
+{
+  FILE *f = fopen( pathToPrior, "rb" );
+  CV_Assert( f );
+
+  unsigned n = 0, m = 0;
+  CV_Assert( fread( &n, sizeof( n ), 1, f ) == 1 );
+  CV_Assert( fread( &m, sizeof( m ), 1, f ) == 1 );
+
+  L1.create( n, m, CV_32F );
+  L2.create( n, m, CV_32F );
+  c1.create( n, 1, CV_32F );
+  c2.create( n, 1, CV_32F );
+
+  CV_Assert( fread( L1.ptr<float>(), n * m * sizeof( float ), 1, f ) == 1 );
+  CV_Assert( fread( L2.ptr<float>(), n * m * sizeof( float ), 1, f ) == 1 );
+  CV_Assert( fread( c1.ptr<float>(), n * sizeof( float ), 1, f ) == 1 );
+  CV_Assert( fread( c2.ptr<float>(), n * sizeof( float ), 1, f ) == 1 );
+
+  fclose( f );
+}
+
+void PCAPrior::fillConstraints( float *A1, float *A2, float *b1, float *b2 ) const
+{
+  memcpy( A1, L1.ptr<float>(), L1.size().area() * sizeof( float ) );
+  memcpy( A2, L2.ptr<float>(), L2.size().area() * sizeof( float ) );
+  memcpy( b1, c1.ptr<float>(), c1.size().area() * sizeof( float ) );
+  memcpy( b2, c2.ptr<float>(), c2.size().area() * sizeof( float ) );
+}
+}
+}
diff --git a/contrib/modules/optflow/src/sparse_matching_gpc.cpp b/contrib/modules/optflow/src/sparse_matching_gpc.cpp
new file mode 100644
index 0000000..649308a
--- /dev/null
+++ b/contrib/modules/optflow/src/sparse_matching_gpc.cpp
@@ -0,0 +1,774 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+ //
+ //  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+ //
+ //  By downloading, copying, installing or using the software you agree to this license.
+ //  If you do not agree to this license, do not download, install,
+ //  copy or use the software.
+ //
+ //
+ //                           License Agreement
+ //                For Open Source Computer Vision Library
+ //
+ // Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
+ // Copyright (C) 2009, Willow Garage Inc., all rights reserved.
+ // Third party copyrights are property of their respective owners.
+ //
+ // Redistribution and use in source and binary forms, with or without modification,
+ // are permitted provided that the following conditions are met:
+ //
+ //   * Redistribution's of source code must retain the above copyright notice,
+ //     this list of conditions and the following disclaimer.
+ //
+ //   * Redistribution's in binary form must reproduce the above copyright notice,
+ //     this list of conditions and the following disclaimer in the documentation
+ //     and/or other materials provided with the distribution.
+ //
+ //   * The name of the copyright holders may not be used to endorse or promote products
+ //     derived from this software without specific prior written permission.
+ //
+ // This software is provided by the copyright holders and contributors "as is" and
+ // any express or implied warranties, including, but not limited to, the implied
+ // warranties of merchantability and fitness for a particular purpose are disclaimed.
+ // In no event shall the Intel Corporation or contributors be liable for any direct,
+ // indirect, incidental, special, exemplary, or consequential damages
+ // (including, but not limited to, procurement of substitute goods or services;
+ // loss of use, data, or profits; or business interruption) however caused
+ // and on any theory of liability, whether in contract, strict liability,
+ // or tort (including negligence or otherwise) arising in any way out of
+ // the use of this software, even if advised of the possibility of such damage.
+ //
+ //M*/
+
+#include "opencv2/core/core_c.h"
+#include "opencv2/core/private.hpp"
+#include "opencv2/flann/miniflann.hpp"
+#include "opencv2/highgui.hpp"
+#include "precomp.hpp"
+#include "opencl_kernels_optflow.hpp"
+
+/* Disable "from double to float" and "from size_t to int" warnings.
+ * Fixing these would make the code look ugly by introducing explicit cast all around.
+ * Here these warning are pointless anyway.
+ */
+#ifdef _MSC_VER
+#pragma warning( disable : 4244 4267 4838 )
+#endif
+#ifdef __clang__
+#pragma clang diagnostic ignored "-Wshorten-64-to-32"
+#endif
+
+namespace cv
+{
+namespace optflow
+{
+namespace
+{
+
+#define PATCH_RADIUS 10
+#define PATCH_RADIUS_DOUBLED 20
+#define SQRT2_INV 0.7071067811865475
+
+const int patchRadius = PATCH_RADIUS;
+const int globalIters = 3;
+const int localIters = 500;
+const double thresholdOutliers = 0.98;
+const double thresholdMagnitudeFrac = 0.8;
+const double epsTolerance = 1e-12;
+const unsigned scoreGainPos = 5;
+const unsigned scoreGainNeg = 1;
+const unsigned negSearchKNN = 5;
+const double simulatedAnnealingTemperatureCoef = 200.0;
+const double sigmaGrowthRate = 0.2;
+
+RNG rng;
+
+struct Magnitude
+{
+  float val;
+  int i;
+  int j;
+
+  Magnitude( float _val, int _i, int _j ) : val( _val ), i( _i ), j( _j ) {}
+  Magnitude() {}
+
+  bool operator<( const Magnitude &m ) const { return val > m.val; }
+};
+
+struct PartitionPredicate1
+{
+  Vec< double, GPCPatchDescriptor::nFeatures > coef;
+  double rhs;
+
+  PartitionPredicate1( const Vec< double, GPCPatchDescriptor::nFeatures > &_coef, double _rhs ) : coef( _coef ), rhs( _rhs ) {}
+
+  bool operator()( const GPCPatchSample &sample ) const
+  {
+    bool refdir, posdir, negdir;
+    sample.getDirections( refdir, posdir, negdir, coef, rhs );
+    return refdir == false && ( posdir == false || negdir == true );
+  }
+};
+
+struct PartitionPredicate2
+{
+  Vec< double, GPCPatchDescriptor::nFeatures > coef;
+  double rhs;
+
+  PartitionPredicate2( const Vec< double, GPCPatchDescriptor::nFeatures > &_coef, double _rhs ) : coef( _coef ), rhs( _rhs ) {}
+
+  bool operator()( const GPCPatchSample &sample ) const
+  {
+    bool refdir, posdir, negdir;
+    sample.getDirections( refdir, posdir, negdir, coef, rhs );
+    return refdir != posdir && refdir == negdir;
+  }
+};
+
+struct CompareWithTolerance
+{
+  double val;
+
+  CompareWithTolerance( double _val ) : val( _val ) {};
+
+  bool operator()( const double &elem ) const
+  {
+    const double diff = ( val + elem == 0 ) ? std::abs( val - elem ) : std::abs( ( val - elem ) / ( val + elem ) );
+    return diff <= epsTolerance;
+  }
+};
+
+float normL2Sqr( const Vec2f &v ) { return v[0] * v[0] + v[1] * v[1]; }
+
+int normL2Sqr( const Point2i &v ) { return v.x * v.x + v.y * v.y; }
+
+bool checkBounds( int i, int j, Size sz )
+{
+  return i >= patchRadius && j >= patchRadius && i + patchRadius < sz.height && j + patchRadius < sz.width;
+}
+
+void getDCTPatchDescriptor( GPCPatchDescriptor &patchDescr, const Mat *imgCh, int i, int j )
+{
+  Rect roi( j - patchRadius, i - patchRadius, 2 * patchRadius, 2 * patchRadius );
+  Mat freqDomain;
+  dct( imgCh[0]( roi ), freqDomain );
+
+  double *feature = patchDescr.feature.val;
+  feature[0] = freqDomain.at< float >( 0, 0 );
+  feature[1] = freqDomain.at< float >( 0, 1 );
+  feature[2] = freqDomain.at< float >( 0, 2 );
+  feature[3] = freqDomain.at< float >( 0, 3 );
+
+  feature[4] = freqDomain.at< float >( 1, 0 );
+  feature[5] = freqDomain.at< float >( 1, 1 );
+  feature[6] = freqDomain.at< float >( 1, 2 );
+  feature[7] = freqDomain.at< float >( 1, 3 );
+
+  feature[8] = freqDomain.at< float >( 2, 0 );
+  feature[9] = freqDomain.at< float >( 2, 1 );
+  feature[10] = freqDomain.at< float >( 2, 2 );
+  feature[11] = freqDomain.at< float >( 2, 3 );
+
+  feature[12] = freqDomain.at< float >( 3, 0 );
+  feature[13] = freqDomain.at< float >( 3, 1 );
+  feature[14] = freqDomain.at< float >( 3, 2 );
+  feature[15] = freqDomain.at< float >( 3, 3 );
+
+  feature[16] = cv::sum( imgCh[1]( roi ) )[0] / ( 2 * patchRadius );
+  feature[17] = cv::sum( imgCh[2]( roi ) )[0] / ( 2 * patchRadius );
+}
+
+double sumInt( const Mat &integ, int i, int j, int h, int w )
+{
+  return integ.at< double >( i + h, j + w ) - integ.at< double >( i + h, j ) - integ.at< double >( i, j + w ) + integ.at< double >( i, j );
+}
+
+void getWHTPatchDescriptor( GPCPatchDescriptor &patchDescr, const Mat *imgCh, int i, int j )
+{
+  i -= patchRadius;
+  j -= patchRadius;
+  const int k = 2 * patchRadius;
+  const double s = sumInt( imgCh[0], i, j, k, k );
+  double *feature = patchDescr.feature.val;
+
+  feature[0] = s;
+  feature[1] = s - 2 * sumInt( imgCh[0], i, j + k / 2, k, k / 2 );
+  feature[2] = s - 2 * sumInt( imgCh[0], i, j + k / 4, k, k / 2 );
+  feature[3] = s - 2 * sumInt( imgCh[0], i, j + k / 4, k, k / 4 ) - 2 * sumInt( imgCh[0], i, j + 3 * k / 4, k, k / 4 );
+
+  feature[4] = s - 2 * sumInt( imgCh[0], i + k / 2, j, k / 2, k );
+  feature[5] = s - 2 * sumInt( imgCh[0], i, j + k / 2, k / 2, k / 2 ) - 2 * sumInt( imgCh[0], i + k / 2, j, k / 2, k / 2 );
+  feature[6] = s - 2 * sumInt( imgCh[0], i, j + k / 4, k / 2, k / 2 ) - 2 * sumInt( imgCh[0], i + k / 2, j, k / 2, k / 4 ) -
+               2 * sumInt( imgCh[0], i + k / 2, j + 3 * k / 4, k / 2, k / 4 );
+  feature[7] = s - 2 * sumInt( imgCh[0], i, j + k / 4, k / 2, k / 4 ) - 2 * sumInt( imgCh[0], i, j + 3 * k / 4, k / 2, k / 4 ) -
+               2 * sumInt( imgCh[0], i + k / 2, j, k / 2, k / 4 ) - 2 * sumInt( imgCh[0], i + k / 2, j + k / 2, k / 2, k / 4 );
+
+  feature[8] = s - 2 * sumInt( imgCh[0], i + k / 4, j, k / 2, k );
+  feature[9] = s - 2 * sumInt( imgCh[0], i + k / 4, j, k / 2, k / 2 ) - 2 * sumInt( imgCh[0], i, j + k / 2, k / 4, k / 2 ) -
+               2 * sumInt( imgCh[0], i + 3 * k / 4, j + k / 2, k / 4, k / 2 );
+  feature[10] = s - 2 * sumInt( imgCh[0], i + k / 4, j, k / 2, k / 4 ) - 2 * sumInt( imgCh[0], i + k / 4, j + 3 * k / 4, k / 2, k / 4 ) -
+                2 * sumInt( imgCh[0], i, j + k / 4, k / 4, k / 2 ) - 2 * sumInt( imgCh[0], i + 3 * k / 4, j + k / 4, k / 4, k / 2 );
+  feature[11] = s - 2 * sumInt( imgCh[0], i, j + k / 4, k / 4, k / 4 ) - 2 * sumInt( imgCh[0], i, j + 3 * k / 4, k / 4, k / 4 ) -
+                2 * sumInt( imgCh[0], i + k / 4, j, k / 2, k / 4 ) - 2 * sumInt( imgCh[0], i + k / 4, j + k / 2, k / 2, k / 4 ) -
+                2 * sumInt( imgCh[0], i + 3 * k / 4, j + k / 4, k / 4, k / 4 ) -
+                2 * sumInt( imgCh[0], i + 3 * k / 4, j + 3 * k / 4, k / 4, k / 4 );
+
+  feature[12] = s - 2 * sumInt( imgCh[0], i + k / 4, j, k / 4, k ) - 2 * sumInt( imgCh[0], i + 3 * k / 4, j, k / 4, k );
+  feature[13] = s - 2 * sumInt( imgCh[0], i + k / 4, j, k / 4, k / 2 ) - 2 * sumInt( imgCh[0], i + 3 * k / 4, j, k / 4, k / 2 ) -
+                2 * sumInt( imgCh[0], i, j + k / 2, k / 4, k / 2 ) - 2 * sumInt( imgCh[0], i + k / 2, j + k / 2, k / 4, k / 2 );
+  feature[14] = s - 2 * sumInt( imgCh[0], i + k / 4, j, k / 4, k / 4 ) - 2 * sumInt( imgCh[0], i + 3 * k / 4, j, k / 4, k / 4 ) -
+                2 * sumInt( imgCh[0], i, j + k / 4, k / 4, k / 2 ) - 2 * sumInt( imgCh[0], i + k / 2, j + k / 4, k / 4, k / 2 ) -
+                2 * sumInt( imgCh[0], i + k / 4, j + 3 * k / 4, k / 4, k / 4 ) -
+                2 * sumInt( imgCh[0], i + 3 * k / 4, j + 3 * k / 4, k / 4, k / 4 );
+  feature[15] = s - 2 * sumInt( imgCh[0], i, j + k / 4, k / 4, k / 4 ) - 2 * sumInt( imgCh[0], i, j + 3 * k / 4, k / 4, k / 4 ) -
+                2 * sumInt( imgCh[0], i + k / 4, j, k / 4, k / 4 ) - 2 * sumInt( imgCh[0], i + k / 4, j + k / 2, k / 4, k / 4 ) -
+                2 * sumInt( imgCh[0], i + k / 2, j + k / 4, k / 4, k / 4 ) -
+                2 * sumInt( imgCh[0], i + k / 2, j + 3 * k / 4, k / 4, k / 4 ) - 2 * sumInt( imgCh[0], i + 3 * k / 4, j, k / 4, k / 4 ) -
+                2 * sumInt( imgCh[0], i + 3 * k / 4, j + k / 2, k / 4, k / 4 );
+
+  feature[16] = sumInt( imgCh[1], i, j, k, k );
+  feature[17] = sumInt( imgCh[2], i, j, k, k );
+
+  patchDescr.feature /= patchRadius;
+}
+
+class ParallelDCTFiller : public ParallelLoopBody
+{
+private:
+  const Size sz;
+  const Mat *imgCh;
+  std::vector< GPCPatchDescriptor > *descr;
+
+  ParallelDCTFiller &operator=( const ParallelDCTFiller & );
+
+public:
+  ParallelDCTFiller( const Size &_sz, const Mat *_imgCh, std::vector< GPCPatchDescriptor > *_descr )
+      : sz( _sz ), imgCh( _imgCh ), descr( _descr ){};
+
+  void operator()( const Range &range ) const
+  {
+    for ( int i = range.start; i < range.end; ++i )
+    {
+      int x, y;
+      GPCDetails::getCoordinatesFromIndex( i, sz, x, y );
+      getDCTPatchDescriptor( descr->at( i ), imgCh, y, x );
+    }
+  }
+};
+
+#ifdef HAVE_OPENCL
+
+bool ocl_getAllDCTDescriptorsForImage( const Mat *imgCh, std::vector< GPCPatchDescriptor > &descr )
+{
+  const Size sz = imgCh[0].size();
+  ocl::Kernel kernel( "getPatchDescriptor", ocl::optflow::sparse_matching_gpc_oclsrc,
+                      format( "-DPATCH_RADIUS_DOUBLED=%d -DCV_PI=%f -DSQRT2_INV=%f", PATCH_RADIUS_DOUBLED, CV_PI, SQRT2_INV ) );
+  size_t globSize[] = {sz.height - 2 * patchRadius, sz.width - 2 * patchRadius};
+  UMat out( globSize[0] * globSize[1], GPCPatchDescriptor::nFeatures, CV_64F );
+  if (
+    kernel
+    .args( cv::ocl::KernelArg::ReadOnlyNoSize( imgCh[0].getUMat( ACCESS_READ ) ),
+           cv::ocl::KernelArg::ReadOnlyNoSize( imgCh[1].getUMat( ACCESS_READ ) ),
+           cv::ocl::KernelArg::ReadOnlyNoSize( imgCh[2].getUMat( ACCESS_READ ) ),
+           cv::ocl::KernelArg::WriteOnlyNoSize( out ),
+           (int)globSize[0], (int)globSize[1], (int)patchRadius )
+    .run( 2, globSize, 0, true ) == false )
+    return false;
+  Mat cpuOut = out.getMat( 0 );
+  for ( int i = 0; i + 2 * patchRadius < sz.height; ++i )
+    for ( int j = 0; j + 2 * patchRadius < sz.width; ++j )
+      descr.push_back( *cpuOut.ptr< GPCPatchDescriptor >( i * globSize[1] + j ) );
+  return true;
+}
+
+#endif
+
+void getAllDCTDescriptorsForImage( const Mat *imgCh, std::vector< GPCPatchDescriptor > &descr, const GPCMatchingParams &mp )
+{
+  const Size sz = imgCh[0].size();
+  descr.reserve( ( sz.height - 2 * patchRadius ) * ( sz.width - 2 * patchRadius ) );
+
+  (void)mp; // Fix unused parameter warning in case OpenCL is not available
+  CV_OCL_RUN( mp.useOpenCL, ocl_getAllDCTDescriptorsForImage( imgCh, descr ) )
+
+  descr.resize( ( sz.height - 2 * patchRadius ) * ( sz.width - 2 * patchRadius ) );
+  parallel_for_( Range( 0, descr.size() ), ParallelDCTFiller( sz, imgCh, &descr ) );
+}
+
+class ParallelWHTFiller : public ParallelLoopBody
+{
+private:
+  const Size sz;
+  const Mat *imgChInt;
+  std::vector< GPCPatchDescriptor > *descr;
+
+  ParallelWHTFiller &operator=( const ParallelWHTFiller & );
+
+public:
+  ParallelWHTFiller( const Size &_sz, const Mat *_imgChInt, std::vector< GPCPatchDescriptor > *_descr )
+      : sz( _sz ), imgChInt( _imgChInt ), descr( _descr ){};
+
+  void operator()( const Range &range ) const
+  {
+    for ( int i = range.start; i < range.end; ++i )
+    {
+      int x, y;
+      GPCDetails::getCoordinatesFromIndex( i, sz, x, y );
+      getWHTPatchDescriptor( descr->at( i ), imgChInt, y, x );
+    }
+  }
+};
+
+void getAllWHTDescriptorsForImage( const Mat *imgCh, std::vector< GPCPatchDescriptor > &descr, const GPCMatchingParams & )
+{
+  const Size sz = imgCh[0].size();
+  descr.resize( ( sz.height - 2 * patchRadius ) * ( sz.width - 2 * patchRadius ) );
+
+  Mat imgChInt[3];
+  integral( imgCh[0], imgChInt[0], CV_64F );
+  integral( imgCh[1], imgChInt[1], CV_64F );
+  integral( imgCh[2], imgChInt[2], CV_64F );
+
+  parallel_for_( Range( 0, descr.size() ), ParallelWHTFiller( sz, imgChInt, &descr ) );
+}
+
+void buildIndex( OutputArray featuresOut, flann::Index &index, const Mat *imgCh,
+                 void ( *getAllDescrFn )( const Mat *, std::vector< GPCPatchDescriptor > &, const GPCMatchingParams & ) )
+{
+  std::vector< GPCPatchDescriptor > descriptors;
+  getAllDescrFn( imgCh, descriptors, GPCMatchingParams() );
+
+  featuresOut.create( descriptors.size(), GPCPatchDescriptor::nFeatures, CV_32F );
+  Mat features = featuresOut.getMat();
+
+  for ( size_t i = 0; i < descriptors.size(); ++i )
+    *features.ptr< Vec< float, GPCPatchDescriptor::nFeatures > >( i ) = descriptors[i].feature;
+
+  cv::flann::KDTreeIndexParams indexParams;
+  index.build( features, indexParams, cvflann::FLANN_DIST_L2 );
+}
+
+void getTriplet( const Magnitude &mag, const Mat &gt, const Mat *fromCh, const Mat *toCh, GPCSamplesVector &samples, flann::Index &index,
+                 void ( *getDescFn )( GPCPatchDescriptor &, const Mat *, int, int ) )
+{
+  const Size sz = gt.size();
+  const int i0 = mag.i;
+  const int j0 = mag.j;
+  const int i1 = i0 + cvRound( gt.at< Vec2f >( i0, j0 )[1] );
+  const int j1 = j0 + cvRound( gt.at< Vec2f >( i0, j0 )[0] );
+  if ( checkBounds( i1, j1, sz ) )
+  {
+    GPCPatchSample ps;
+    getDescFn( ps.ref, fromCh, i0, j0 );
+    getDescFn( ps.pos, toCh, i1, j1 );
+    ps.neg.markAsSeparated();
+
+    Matx< float, 1, GPCPatchDescriptor::nFeatures > ref32;
+    Matx< int, 1, negSearchKNN > indices;
+    int maxDist = 0;
+
+    for ( unsigned i = 0; i < GPCPatchDescriptor::nFeatures; ++i )
+      ref32( 0, i ) = ps.ref.feature[i];
+
+    index.knnSearch( ref32, indices, noArray(), negSearchKNN );
+
+    for ( unsigned i = 0; i < negSearchKNN; ++i )
+    {
+      int i2, j2;
+      GPCDetails::getCoordinatesFromIndex( indices( 0, i ), sz, j2, i2 );
+      const int dist = ( i2 - i1 ) * ( i2 - i1 ) + ( j2 - j1 ) * ( j2 - j1 );
+      if ( maxDist < dist )
+      {
+        maxDist = dist;
+        getDescFn( ps.neg, toCh, i2, j2 );
+      }
+    }
+
+    samples.push_back( ps );
+  }
+}
+
+void getTrainingSamples( const Mat &from, const Mat &to, const Mat &gt, GPCSamplesVector &samples, const int type )
+{
+  const Size sz = gt.size();
+  std::vector< Magnitude > mag;
+
+  for ( int i = patchRadius; i + patchRadius < sz.height; ++i )
+    for ( int j = patchRadius; j + patchRadius < sz.width; ++j )
+      mag.push_back( Magnitude( normL2Sqr( gt.at< Vec2f >( i, j ) ), i, j ) );
+
+  size_t n = size_t( mag.size() * thresholdMagnitudeFrac ); // As suggested in the paper, we discard part of the training samples
+                                                            // with a small displacement and train to better distinguish hard pairs.
+  std::nth_element( mag.begin(), mag.begin() + n, mag.end() );
+  mag.resize( n );
+  std::random_shuffle( mag.begin(), mag.end() );
+  n /= patchRadius;
+  mag.resize( n );
+
+  if ( type == GPC_DESCRIPTOR_DCT )
+  {
+    Mat fromCh[3], toCh[3];
+    split( from, fromCh );
+    split( to, toCh );
+
+    Mat allDescriptors;
+    flann::Index index;
+    buildIndex( allDescriptors, index, toCh, getAllDCTDescriptorsForImage );
+
+    for ( size_t k = 0; k < n; ++k )
+      getTriplet( mag[k], gt, fromCh, toCh, samples, index, getDCTPatchDescriptor );
+  }
+  else if ( type == GPC_DESCRIPTOR_WHT )
+  {
+    Mat fromCh[3], toCh[3], fromChInt[3], toChInt[3];
+    split( from, fromCh );
+    split( to, toCh );
+    integral( fromCh[0], fromChInt[0], CV_64F );
+    integral( fromCh[1], fromChInt[1], CV_64F );
+    integral( fromCh[2], fromChInt[2], CV_64F );
+    integral( toCh[0], toChInt[0], CV_64F );
+    integral( toCh[1], toChInt[1], CV_64F );
+    integral( toCh[2], toChInt[2], CV_64F );
+
+    Mat allDescriptors;
+    flann::Index index;
+    buildIndex( allDescriptors, index, toCh, getAllWHTDescriptorsForImage );
+
+    for ( size_t k = 0; k < n; ++k )
+      getTriplet( mag[k], gt, fromChInt, toChInt, samples, index, getWHTPatchDescriptor );
+  }
+  else
+    CV_Error( CV_StsBadArg, "Unknown descriptor type" );
+}
+
+/* Sample random number from Cauchy distribution. */
+double getRandomCauchyScalar()
+{
+  return tan( rng.uniform( -1.54, 1.54 ) ); // I intentionally used the value slightly less than PI/2 to enforce strictly
+                                            // zero probability for large numbers. Resulting PDF for Cauchy has
+                                            // truncated "tails".
+}
+
+/* Sample random vector from Cauchy distribution (pointwise, i.e. vector whose components are independent random
+ * variables from Cauchy distribution) */
+void getRandomCauchyVector( Vec< double, GPCPatchDescriptor::nFeatures > &v )
+{
+  for ( unsigned i = 0; i < GPCPatchDescriptor::nFeatures; ++i )
+    v[i] = getRandomCauchyScalar();
+}
+
+double getRobustMedian( double m ) { return m < 0 ? m * ( 1.0 + epsTolerance ) : m * ( 1.0 - epsTolerance ); }
+}
+
+double GPCPatchDescriptor::dot( const Vec< double, nFeatures > &coef ) const
+{
+#if CV_SIMD128_64F
+  v_float64x2 sum = v_setzero_f64();
+  for ( unsigned i = 0; i < nFeatures; i += 2 )
+  {
+    v_float64x2 x = v_load( &feature.val[i] );
+    v_float64x2 y = v_load( &coef.val[i] );
+    sum = v_muladd( x, y, sum );
+  }
+#if CV_SSE2
+  __m128d sumrev = _mm_shuffle_pd( sum.val, sum.val, _MM_SHUFFLE2( 0, 1 ) );
+  return _mm_cvtsd_f64( _mm_add_pd( sum.val, sumrev ) );
+#else
+  double CV_DECL_ALIGNED( 16 ) buf[2];
+  v_store_aligned( buf, sum );
+  return OPENCV_HAL_ADD( buf[0], buf[1] );
+#endif
+
+#else
+  return feature.dot( coef );
+#endif
+}
+
+void GPCPatchSample::getDirections( bool &refdir, bool &posdir, bool &negdir, const Vec< double, GPCPatchDescriptor::nFeatures > &coef, double rhs ) const
+{
+  refdir = ( ref.dot( coef ) < rhs );
+  posdir = pos.isSeparated() ? ( !refdir ) : ( pos.dot( coef ) < rhs );
+  negdir = neg.isSeparated() ? ( !refdir ) : ( neg.dot( coef ) < rhs );
+}
+
+void GPCDetails::getAllDescriptorsForImage( const Mat *imgCh, std::vector< GPCPatchDescriptor > &descr, const GPCMatchingParams &mp,
+                                            int type )
+{
+  if ( type == GPC_DESCRIPTOR_DCT )
+    getAllDCTDescriptorsForImage( imgCh, descr, mp );
+  else if ( type == GPC_DESCRIPTOR_WHT )
+    getAllWHTDescriptorsForImage( imgCh, descr, mp );
+  else
+    CV_Error( CV_StsBadArg, "Unknown descriptor type" );
+}
+
+void GPCDetails::getCoordinatesFromIndex( size_t index, Size sz, int &x, int &y )
+{
+  const size_t stride = sz.width - patchRadius * 2;
+  y = int( index / stride );
+  x = int( index - y * stride + patchRadius );
+  y += patchRadius;
+}
+
+bool GPCTree::trainNode( size_t nodeId, SIter begin, SIter end, unsigned depth )
+{
+  const int nSamples = (int)std::distance( begin, end );
+
+  if ( nSamples < params.minNumberOfSamples || depth >= params.maxTreeDepth )
+    return false;
+
+  if ( nodeId >= nodes.size() )
+    nodes.resize( nodeId + 1 );
+
+  Node &node = nodes[nodeId];
+
+  // Select the best hyperplane
+  unsigned globalBestScore = 0;
+  std::vector< double > values;
+  values.reserve( nSamples * 2 );
+
+  for ( int j = 0; j < globalIters; ++j )
+  { // Global search step
+    Vec< double, GPCPatchDescriptor::nFeatures > coef;
+    unsigned localBestScore = 0;
+    getRandomCauchyVector( coef );
+
+    for ( int i = 0; i < localIters; ++i )
+    { // Local search step
+      double randomModification = getRandomCauchyScalar() * ( 1.0 + sigmaGrowthRate * int( i / GPCPatchDescriptor::nFeatures ) );
+      const int pos = i % GPCPatchDescriptor::nFeatures;
+      std::swap( coef[pos], randomModification );
+      values.clear();
+
+      for ( SIter iter = begin; iter != end; ++iter )
+        values.push_back( iter->ref.dot( coef ) );
+
+      std::nth_element( values.begin(), values.begin() + nSamples / 2, values.end() );
+      double median = values[nSamples / 2];
+
+      // Skip obviously malformed division. This may happen in case there are a large number of equal samples.
+      // Most likely this won't happen with samples collected from a good dataset.
+      // Happens in case dataset contains plain (or close to plain) images.
+      if ( std::count_if( values.begin(), values.end(), CompareWithTolerance( median ) ) > std::max( 1, nSamples / 4 ) )
+        continue;
+
+      median = getRobustMedian( median );
+
+      unsigned score = 0;
+      for ( SIter iter = begin; iter != end; ++iter )
+      {
+        bool refdir, posdir, negdir;
+        iter->getDirections( refdir, posdir, negdir, coef, median );
+        if ( refdir == posdir )
+          score += scoreGainPos;
+        if ( refdir != negdir )
+          score += scoreGainNeg;
+      }
+
+      if ( score > localBestScore )
+        localBestScore = score;
+      else
+      {
+        const double beta = simulatedAnnealingTemperatureCoef * std::sqrt( i ) / ( nSamples * ( scoreGainPos + scoreGainNeg ) );
+        if ( rng.uniform( 0.0, 1.0 ) > std::exp( -beta * ( localBestScore - score) ) )
+          coef[pos] = randomModification;
+      }
+
+      if ( score > globalBestScore )
+      {
+        globalBestScore = score;
+        node.coef = coef;
+        node.rhs = median;
+      }
+    }
+  }
+
+  if ( globalBestScore == 0 )
+    return false;
+
+  if ( params.printProgress )
+  {
+    const int maxScore = nSamples * ( scoreGainPos + scoreGainNeg );
+    const double correctRatio = double( globalBestScore ) / maxScore;
+    printf( "[%u] Correct %.2f (%u/%d)\nWeights:", depth, correctRatio, globalBestScore, maxScore );
+    for ( unsigned k = 0; k < GPCPatchDescriptor::nFeatures; ++k )
+      printf( " %.3f", node.coef[k] );
+    printf( "\n" );
+  }
+
+  for ( SIter iter = begin; iter != end; ++iter )
+  {
+    bool refdir, posdir, negdir;
+    iter->getDirections( refdir, posdir, negdir, node.coef, node.rhs );
+    // We shouldn't account for positive sample in the scoring in case it was separated before. So mark it as separated.
+    // After all, we can't bring back samples which were separated from reference on early levels.
+    if ( refdir != posdir )
+      iter->pos.markAsSeparated();
+    // The same for negative sample.
+    if ( refdir != negdir )
+      iter->neg.markAsSeparated();
+    // If both positive and negative were separated before then such triplet doesn't make sense on deeper levels. We discard it.
+  }
+
+  // Partition vector with samples according to the hyperplane in QuickSort-like manner.
+  // Unlike QuickSort, we need to partition it into 3 parts (left subtree samples; undefined samples; right subtree
+  // samples), so we call it two times.
+  SIter leftEnd = std::partition( begin, end, PartitionPredicate1( node.coef, node.rhs ) ); // Separate left subtree samples from others.
+  SIter rightBegin =
+    std::partition( leftEnd, end, PartitionPredicate2( node.coef, node.rhs ) ); // Separate undefined samples from right subtree samples.
+
+  node.left = ( trainNode( nodeId * 2 + 1, begin, leftEnd, depth + 1 ) ) ? unsigned( nodeId * 2 + 1 ) : 0;
+  node.right = ( trainNode( nodeId * 2 + 2, rightBegin, end, depth + 1 ) ) ? unsigned( nodeId * 2 + 2 ) : 0;
+
+  return true;
+}
+
+void GPCTree::train( GPCTrainingSamples &samples, const GPCTrainingParams _params )
+{
+  if ( _params.descriptorType != samples.type() )
+    CV_Error( CV_StsBadArg, "Descriptor type mismatch! Check that samples are collected with the same descriptor type." );
+  nodes.clear();
+  nodes.reserve( samples.size() * 2 - 1 ); // set upper bound for the possible number of nodes so all subsequent resize() will be no-op
+  params = _params;
+  GPCSamplesVector &sv = samples;
+  trainNode( 0, sv.begin(), sv.end(), 0 );
+}
+
+void GPCTree::write( FileStorage &fs ) const
+{
+  if ( nodes.empty() )
+    CV_Error( CV_StsBadArg, "Tree have not been trained" );
+  fs << "nodes" << nodes;
+  fs << "dtype" << (int)params.descriptorType;
+}
+
+void GPCTree::read( const FileNode &fn )
+{
+  fn["nodes"] >> nodes;
+  fn["dtype"] >> (int &)params.descriptorType;
+}
+
+unsigned GPCTree::findLeafForPatch( const GPCPatchDescriptor &descr ) const
+{
+  unsigned id = 0, prevId;
+  do
+  {
+    prevId = id;
+    if ( descr.dot( nodes[id].coef ) < nodes[id].rhs )
+      id = nodes[id].right;
+    else
+      id = nodes[id].left;
+  } while ( id );
+  return prevId;
+}
+
+Ptr< GPCTrainingSamples > GPCTrainingSamples::create( const std::vector< String > &imagesFrom, const std::vector< String > &imagesTo,
+                                                      const std::vector< String > &gt, int _descriptorType )
+{
+  CV_Assert( imagesFrom.size() == imagesTo.size() );
+  CV_Assert( imagesFrom.size() == gt.size() );
+
+  Ptr< GPCTrainingSamples > ts = makePtr< GPCTrainingSamples >();
+
+  ts->descriptorType = _descriptorType;
+
+  for ( size_t i = 0; i < imagesFrom.size(); ++i )
+  {
+    Mat from = imread( imagesFrom[i] );
+    Mat to = imread( imagesTo[i] );
+    Mat gtFlow = readOpticalFlow( gt[i] );
+
+    CV_Assert( from.size == to.size );
+    CV_Assert( from.size == gtFlow.size );
+    CV_Assert( from.channels() == 3 );
+    CV_Assert( to.channels() == 3 );
+
+    from.convertTo( from, CV_32FC3 );
+    to.convertTo( to, CV_32FC3 );
+    cvtColor( from, from, COLOR_BGR2YCrCb );
+    cvtColor( to, to, COLOR_BGR2YCrCb );
+
+    getTrainingSamples( from, to, gtFlow, ts->samples, ts->descriptorType );
+  }
+
+  return ts;
+}
+
+Ptr< GPCTrainingSamples > GPCTrainingSamples::create( InputArrayOfArrays imagesFrom, InputArrayOfArrays imagesTo,
+                                                      InputArrayOfArrays gt, int _descriptorType )
+{
+  CV_Assert( imagesFrom.total() == imagesTo.total() );
+  CV_Assert( imagesFrom.total() == gt.total() );
+
+  Ptr< GPCTrainingSamples > ts = makePtr< GPCTrainingSamples >();
+
+  ts->descriptorType = _descriptorType;
+
+  for ( size_t i = 0; i < imagesFrom.total(); ++i )
+  {
+    Mat from = imagesFrom.getMat( static_cast<int>( i ) );
+    Mat to = imagesTo.getMat( static_cast<int>( i ) );
+    Mat gtFlow = gt.getMat( static_cast<int>( i ) );
+
+    CV_Assert( from.size == to.size );
+    CV_Assert( from.size == gtFlow.size );
+    CV_Assert( from.channels() == 3 );
+    CV_Assert( to.channels() == 3 );
+
+    from.convertTo( from, CV_32FC3 );
+    to.convertTo( to, CV_32FC3 );
+    cvtColor( from, from, COLOR_BGR2YCrCb );
+    cvtColor( to, to, COLOR_BGR2YCrCb );
+
+    getTrainingSamples( from, to, gtFlow, ts->samples, ts->descriptorType );
+  }
+
+  return ts;
+}
+
+void GPCDetails::dropOutliers( std::vector< std::pair< Point2i, Point2i > > &corr )
+{
+  std::vector< float > mag( corr.size() );
+
+  for ( size_t i = 0; i < corr.size(); ++i )
+    mag[i] = normL2Sqr( corr[i].first - corr[i].second );
+
+  const size_t threshold = size_t( mag.size() * thresholdOutliers );
+  std::nth_element( mag.begin(), mag.begin() + threshold, mag.end() );
+  const float percentile = mag[threshold];
+  size_t i = 0, j = 0;
+
+  while ( i < corr.size() )
+  {
+    if ( normL2Sqr( corr[i].first - corr[i].second ) <= percentile )
+    {
+      corr[j] = corr[i];
+      ++j;
+    }
+    ++i;
+  }
+
+  corr.resize( j );
+}
+
+} // namespace optflow
+
+void write( FileStorage &fs, const String &name, const optflow::GPCTree::Node &node )
+{
+  cv::internal::WriteStructContext ws( fs, name, CV_NODE_SEQ + CV_NODE_FLOW );
+  for ( unsigned i = 0; i < optflow::GPCPatchDescriptor::nFeatures; ++i )
+    write( fs, node.coef[i] );
+  write( fs, node.rhs );
+  write( fs, (int)node.left );
+  write( fs, (int)node.right );
+}
+
+void read( const FileNode &fn, optflow::GPCTree::Node &node, optflow::GPCTree::Node )
+{
+  FileNodeIterator it = fn.begin();
+  for ( unsigned i = 0; i < optflow::GPCPatchDescriptor::nFeatures; ++i )
+    it >> node.coef[i];
+  it >> node.rhs >> (int &)node.left >> (int &)node.right;
+}
+
+} // namespace cv
diff --git a/contrib/modules/optflow/src/variational_refinement.cpp b/contrib/modules/optflow/src/variational_refinement.cpp
new file mode 100644
index 0000000..6353c09
--- /dev/null
+++ b/contrib/modules/optflow/src/variational_refinement.cpp
@@ -0,0 +1,1191 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+//  By downloading, copying, installing or using the software you agree to this license.
+//  If you do not agree to this license, do not download, install,
+//  copy or use the software.
+//
+//
+//                           License Agreement
+//                For Open Source Computer Vision Library
+//
+// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
+// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+//   * Redistribution's of source code must retain the above copyright notice,
+//     this list of conditions and the following disclaimer.
+//
+//   * Redistribution's in binary form must reproduce the above copyright notice,
+//     this list of conditions and the following disclaimer in the documentation
+//     and/or other materials provided with the distribution.
+//
+//   * The name of the copyright holders may not be used to endorse or promote products
+//     derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "opencv2/core/hal/intrin.hpp"
+#include "precomp.hpp"
+using namespace std;
+
+namespace cv
+{
+namespace optflow
+{
+
+class VariationalRefinementImpl : public VariationalRefinement
+{
+  public:
+    VariationalRefinementImpl();
+
+    void calc(InputArray I0, InputArray I1, InputOutputArray flow);
+    void calcUV(InputArray I0, InputArray I1, InputOutputArray flow_u, InputOutputArray flow_v);
+    void collectGarbage();
+
+  protected: //!< algorithm parameters
+    int fixedPointIterations, sorIterations;
+    float omega;
+    float alpha, delta, gamma;
+    float zeta, epsilon;
+
+  public:
+    int getFixedPointIterations() const { return fixedPointIterations; }
+    void setFixedPointIterations(int val) { fixedPointIterations = val; }
+    int getSorIterations() const { return sorIterations; }
+    void setSorIterations(int val) { sorIterations = val; }
+    float getOmega() const { return omega; }
+    void setOmega(float val) { omega = val; }
+    float getAlpha() const { return alpha; }
+    void setAlpha(float val) { alpha = val; }
+    float getDelta() const { return delta; }
+    void setDelta(float val) { delta = val; }
+    float getGamma() const { return gamma; }
+    void setGamma(float val) { gamma = val; }
+
+  protected: //!< internal buffers
+    /* This struct defines a special data layout for Mat_<float>. Original buffer is split into two: one for "red"
+     * elements (sum of indices is even) and one for "black" (sum of indices is odd) in a checkerboard pattern. It
+     * allows for more efficient processing in SOR iterations, more natural SIMD vectorization and parallelization
+     * (Red-Black SOR). Additionally, it simplifies border handling by adding repeated borders to both red and
+     * black buffers.
+     */
+    struct RedBlackBuffer
+    {
+        Mat_<float> red;   //!< (i+j)%2==0
+        Mat_<float> black; //!< (i+j)%2==1
+
+        /* Width of even and odd rows may be different */
+        int red_even_len, red_odd_len;
+        int black_even_len, black_odd_len;
+
+        void create(Size s);
+        void release();
+    };
+
+    Mat_<float> Ix, Iy, Iz, Ixx, Ixy, Iyy, Ixz, Iyz;                            //!< image derivative buffers
+    RedBlackBuffer Ix_rb, Iy_rb, Iz_rb, Ixx_rb, Ixy_rb, Iyy_rb, Ixz_rb, Iyz_rb; //!< corresponding red-black buffers
+
+    RedBlackBuffer A11, A12, A22, b1, b2; //!< main linear system coefficients
+    RedBlackBuffer weights;               //!< smoothness term weights in the current fixed point iteration
+
+    Mat_<float> mapX, mapY; //!< auxiliary buffers for remapping
+
+    RedBlackBuffer tempW_u, tempW_v; //!< flow buffers that are modified in each fixed point iteration
+    RedBlackBuffer dW_u, dW_v;       //!< optical flow increment
+    RedBlackBuffer W_u_rb, W_v_rb;   //!< red-black-buffer version of the input flow
+
+  private: //!< private methods and parallel sections
+    void splitCheckerboard(RedBlackBuffer &dst, Mat &src);
+    void mergeCheckerboard(Mat &dst, RedBlackBuffer &src);
+    void updateRepeatedBorders(RedBlackBuffer &dst);
+    void warpImage(Mat &dst, Mat &src, Mat &flow_u, Mat &flow_v);
+    void prepareBuffers(Mat &I0, Mat &I1, Mat &W_u, Mat &W_v);
+
+    /* Parallelizing arbitrary operations with 3 input/output arguments */
+    typedef void (VariationalRefinementImpl::*Op)(void *op1, void *op2, void *op3);
+    struct ParallelOp_ParBody : public ParallelLoopBody
+    {
+        VariationalRefinementImpl *var;
+        vector<Op> ops;
+        vector<void *> op1s;
+        vector<void *> op2s;
+        vector<void *> op3s;
+
+        ParallelOp_ParBody(VariationalRefinementImpl &_var, vector<Op> _ops, vector<void *> &_op1s,
+                           vector<void *> &_op2s, vector<void *> &_op3s);
+        void operator()(const Range &range) const;
+    };
+    void gradHorizAndSplitOp(void *src, void *dst, void *dst_split)
+    {
+        Sobel(*(Mat *)src, *(Mat *)dst, -1, 1, 0, 1, 1, 0.00, BORDER_REPLICATE);
+        splitCheckerboard(*(RedBlackBuffer *)dst_split, *(Mat *)dst);
+    }
+    void gradVertAndSplitOp(void *src, void *dst, void *dst_split)
+    {
+        Sobel(*(Mat *)src, *(Mat *)dst, -1, 0, 1, 1, 1, 0.00, BORDER_REPLICATE);
+        splitCheckerboard(*(RedBlackBuffer *)dst_split, *(Mat *)dst);
+    }
+    void averageOp(void *src1, void *src2, void *dst)
+    {
+        addWeighted(*(Mat *)src1, 0.5, *(Mat *)src2, 0.5, 0.0, *(Mat *)dst, CV_32F);
+    }
+    void subtractOp(void *src1, void *src2, void *dst)
+    {
+        subtract(*(Mat *)src1, *(Mat *)src2, *(Mat *)dst, noArray(), CV_32F);
+    }
+
+    struct ComputeDataTerm_ParBody : public ParallelLoopBody
+    {
+        VariationalRefinementImpl *var;
+        int nstripes, stripe_sz;
+        int h;
+        RedBlackBuffer *dW_u, *dW_v;
+        bool red_pass;
+
+        ComputeDataTerm_ParBody(VariationalRefinementImpl &_var, int _nstripes, int _h, RedBlackBuffer &_dW_u,
+                                RedBlackBuffer &_dW_v, bool _red_pass);
+        void operator()(const Range &range) const;
+    };
+
+    struct ComputeSmoothnessTermHorPass_ParBody : public ParallelLoopBody
+    {
+        VariationalRefinementImpl *var;
+        int nstripes, stripe_sz;
+        int h;
+        RedBlackBuffer *W_u, *W_v, *curW_u, *curW_v;
+        bool red_pass;
+
+        ComputeSmoothnessTermHorPass_ParBody(VariationalRefinementImpl &_var, int _nstripes, int _h,
+                                             RedBlackBuffer &_W_u, RedBlackBuffer &_W_v, RedBlackBuffer &_tempW_u,
+                                             RedBlackBuffer &_tempW_v, bool _red_pass);
+        void operator()(const Range &range) const;
+    };
+
+    struct ComputeSmoothnessTermVertPass_ParBody : public ParallelLoopBody
+    {
+        VariationalRefinementImpl *var;
+        int nstripes, stripe_sz;
+        int h;
+        RedBlackBuffer *W_u, *W_v;
+        bool red_pass;
+
+        ComputeSmoothnessTermVertPass_ParBody(VariationalRefinementImpl &_var, int _nstripes, int _h,
+                                              RedBlackBuffer &W_u, RedBlackBuffer &_W_v, bool _red_pass);
+        void operator()(const Range &range) const;
+    };
+
+    struct RedBlackSOR_ParBody : public ParallelLoopBody
+    {
+        VariationalRefinementImpl *var;
+        int nstripes, stripe_sz;
+        int h;
+        RedBlackBuffer *dW_u, *dW_v;
+        bool red_pass;
+
+        RedBlackSOR_ParBody(VariationalRefinementImpl &_var, int _nstripes, int _h, RedBlackBuffer &_dW_u,
+                            RedBlackBuffer &_dW_v, bool _red_pass);
+        void operator()(const Range &range) const;
+    };
+};
+
+VariationalRefinementImpl::VariationalRefinementImpl()
+{
+    fixedPointIterations = 5;
+    sorIterations = 5;
+    alpha = 20.0f;
+    delta = 5.0f;
+    gamma = 10.0f;
+    omega = 1.6f;
+    zeta = 0.1f;
+    epsilon = 0.001f;
+}
+
+/* This function converts an input Mat into the RedBlackBuffer format, which involves
+ * splitting the input buffer into two and adding repeated borders. Assumes that enough
+ * memory in dst is already allocated.
+ */
+void VariationalRefinementImpl::splitCheckerboard(RedBlackBuffer &dst, Mat &src)
+{
+    int buf_j, j;
+    int buf_w = (int)ceil(src.cols / 2.0) + 2; //!< max width of red/black buffers with borders
+
+    /* Rows of red and black buffers can have different actual width, some extra repeated values are
+     * added for padding in such cases.
+     */
+    for (int i = 0; i < src.rows; i++)
+    {
+        float *src_buf = src.ptr<float>(i);
+        float *r_buf = dst.red.ptr<float>(i + 1);
+        float *b_buf = dst.black.ptr<float>(i + 1);
+        r_buf[0] = b_buf[0] = src_buf[0];
+        buf_j = 1;
+        if (i % 2 == 0)
+        {
+            for (j = 0; j < src.cols - 1; j += 2)
+            {
+                r_buf[buf_j] = src_buf[j];
+                b_buf[buf_j] = src_buf[j + 1];
+                buf_j++;
+            }
+            if (j < src.cols)
+                r_buf[buf_j] = b_buf[buf_j] = src_buf[j];
+            else
+                j--;
+        }
+        else
+        {
+            for (j = 0; j < src.cols - 1; j += 2)
+            {
+                b_buf[buf_j] = src_buf[j];
+                r_buf[buf_j] = src_buf[j + 1];
+                buf_j++;
+            }
+            if (j < src.cols)
+                r_buf[buf_j] = b_buf[buf_j] = src_buf[j];
+            else
+                j--;
+        }
+        r_buf[buf_w - 1] = b_buf[buf_w - 1] = src_buf[j];
+    }
+
+    /* Fill top and bottom borders: */
+    {
+        float *r_buf_border = dst.red.ptr<float>(dst.red.rows - 1);
+        float *b_buf_border = dst.black.ptr<float>(dst.black.rows - 1);
+        float *r_buf = dst.red.ptr<float>(dst.red.rows - 2);
+        float *b_buf = dst.black.ptr<float>(dst.black.rows - 2);
+        memcpy(r_buf_border, b_buf, buf_w * sizeof(float));
+        memcpy(b_buf_border, r_buf, buf_w * sizeof(float));
+    }
+    {
+        float *r_buf_border = dst.red.ptr<float>(0);
+        float *b_buf_border = dst.black.ptr<float>(0);
+        float *r_buf = dst.red.ptr<float>(1);
+        float *b_buf = dst.black.ptr<float>(1);
+        memcpy(r_buf_border, b_buf, buf_w * sizeof(float));
+        memcpy(b_buf_border, r_buf, buf_w * sizeof(float));
+    }
+}
+
+/* The inverse of splitCheckerboard, i.e. converting the RedBlackBuffer back into Mat.
+ * Assumes that enough memory in dst is already allocated.
+ */
+void VariationalRefinementImpl::mergeCheckerboard(Mat &dst, RedBlackBuffer &src)
+{
+    int buf_j, j;
+    for (int i = 0; i < dst.rows; i++)
+    {
+        float *src_r_buf = src.red.ptr<float>(i + 1);
+        float *src_b_buf = src.black.ptr<float>(i + 1);
+        float *dst_buf = dst.ptr<float>(i);
+        buf_j = 1;
+
+        if (i % 2 == 0)
+        {
+            for (j = 0; j < dst.cols - 1; j += 2)
+            {
+                dst_buf[j] = src_r_buf[buf_j];
+                dst_buf[j + 1] = src_b_buf[buf_j];
+                buf_j++;
+            }
+            if (j < dst.cols)
+                dst_buf[j] = src_r_buf[buf_j];
+        }
+        else
+        {
+            for (j = 0; j < dst.cols - 1; j += 2)
+            {
+                dst_buf[j] = src_b_buf[buf_j];
+                dst_buf[j + 1] = src_r_buf[buf_j];
+                buf_j++;
+            }
+            if (j < dst.cols)
+                dst_buf[j] = src_b_buf[buf_j];
+        }
+    }
+}
+
+/* An auxiliary function that updates the borders. Used to enforce that border values repeat
+ * the ones adjacent to the border.
+ */
+void VariationalRefinementImpl::updateRepeatedBorders(RedBlackBuffer &dst)
+{
+    int buf_w = dst.red.cols;
+    for (int i = 0; i < dst.red.rows - 2; i++)
+    {
+        float *r_buf = dst.red.ptr<float>(i + 1);
+        float *b_buf = dst.black.ptr<float>(i + 1);
+
+        if (i % 2 == 0)
+        {
+            b_buf[0] = r_buf[1];
+            if (dst.red_even_len > dst.black_even_len)
+                b_buf[dst.black_even_len + 1] = r_buf[dst.red_even_len];
+            else
+                r_buf[dst.red_even_len + 1] = b_buf[dst.black_even_len];
+        }
+        else
+        {
+            r_buf[0] = b_buf[1];
+            if (dst.red_odd_len < dst.black_odd_len)
+                r_buf[dst.red_odd_len + 1] = b_buf[dst.black_odd_len];
+            else
+                b_buf[dst.black_odd_len + 1] = r_buf[dst.red_odd_len];
+        }
+    }
+    {
+        float *r_buf_border = dst.red.ptr<float>(dst.red.rows - 1);
+        float *b_buf_border = dst.black.ptr<float>(dst.black.rows - 1);
+        float *r_buf = dst.red.ptr<float>(dst.red.rows - 2);
+        float *b_buf = dst.black.ptr<float>(dst.black.rows - 2);
+        memcpy(r_buf_border, b_buf, buf_w * sizeof(float));
+        memcpy(b_buf_border, r_buf, buf_w * sizeof(float));
+    }
+    {
+        float *r_buf_border = dst.red.ptr<float>(0);
+        float *b_buf_border = dst.black.ptr<float>(0);
+        float *r_buf = dst.red.ptr<float>(1);
+        float *b_buf = dst.black.ptr<float>(1);
+        memcpy(r_buf_border, b_buf, buf_w * sizeof(float));
+        memcpy(b_buf_border, r_buf, buf_w * sizeof(float));
+    }
+}
+
+void VariationalRefinementImpl::RedBlackBuffer::create(Size s)
+{
+    /* Allocate enough memory to include borders */
+    int w = (int)ceil(s.width / 2.0) + 2;
+    red.create(s.height + 2, w);
+    black.create(s.height + 2, w);
+
+    if (s.width % 2 == 0)
+        red_even_len = red_odd_len = black_even_len = black_odd_len = w - 2;
+    else
+    {
+        red_even_len = black_odd_len = w - 2;
+        red_odd_len = black_even_len = w - 3;
+    }
+}
+
+void VariationalRefinementImpl::RedBlackBuffer::release()
+{
+    red.release();
+    black.release();
+}
+
+VariationalRefinementImpl::ParallelOp_ParBody::ParallelOp_ParBody(VariationalRefinementImpl &_var, vector<Op> _ops,
+                                                                  vector<void *> &_op1s, vector<void *> &_op2s,
+                                                                  vector<void *> &_op3s)
+    : var(&_var), ops(_ops), op1s(_op1s), op2s(_op2s), op3s(_op3s)
+{
+}
+
+void VariationalRefinementImpl::ParallelOp_ParBody::operator()(const Range &range) const
+{
+    for (int i = range.start; i < range.end; i++)
+        (var->*ops[i])(op1s[i], op2s[i], op3s[i]);
+}
+
+void VariationalRefinementImpl::warpImage(Mat &dst, Mat &src, Mat &flow_u, Mat &flow_v)
+{
+    for (int i = 0; i < flow_u.rows; i++)
+    {
+        float *pFlowU = flow_u.ptr<float>(i);
+        float *pFlowV = flow_v.ptr<float>(i);
+        float *pMapX = mapX.ptr<float>(i);
+        float *pMapY = mapY.ptr<float>(i);
+        for (int j = 0; j < flow_u.cols; j++)
+        {
+            pMapX[j] = j + pFlowU[j];
+            pMapY[j] = i + pFlowV[j];
+        }
+    }
+    remap(src, dst, mapX, mapY, INTER_LINEAR, BORDER_REPLICATE);
+}
+
+void VariationalRefinementImpl::prepareBuffers(Mat &I0, Mat &I1, Mat &W_u, Mat &W_v)
+{
+    Size s = I0.size();
+    A11.create(s);
+    A12.create(s);
+    A22.create(s);
+    b1.create(s);
+    b2.create(s);
+    weights.create(s);
+    weights.red.setTo(0.0f);
+    weights.black.setTo(0.0f);
+    tempW_u.create(s);
+    tempW_v.create(s);
+    dW_u.create(s);
+    dW_v.create(s);
+    W_u_rb.create(s);
+    W_v_rb.create(s);
+
+    Ix.create(s);
+    Iy.create(s);
+    Iz.create(s);
+    Ixx.create(s);
+    Ixy.create(s);
+    Iyy.create(s);
+    Ixz.create(s);
+    Iyz.create(s);
+
+    Ix_rb.create(s);
+    Iy_rb.create(s);
+    Iz_rb.create(s);
+    Ixx_rb.create(s);
+    Ixy_rb.create(s);
+    Iyy_rb.create(s);
+    Ixz_rb.create(s);
+    Iyz_rb.create(s);
+
+    mapX.create(s);
+    mapY.create(s);
+
+    /* Floating point warps work significantly better than fixed-point */
+    Mat I1flt, warpedI;
+    I1.convertTo(I1flt, CV_32F);
+    warpImage(warpedI, I1flt, W_u, W_v);
+
+    /* Computing an average of the current and warped next frames (to compute the derivatives on) and
+     * temporal derivative Iz
+     */
+    Mat averagedI;
+    {
+        vector<void *> op1s;
+        op1s.push_back((void *)&I0);
+        op1s.push_back((void *)&warpedI);
+        vector<void *> op2s;
+        op2s.push_back((void *)&warpedI);
+        op2s.push_back((void *)&I0);
+        vector<void *> op3s;
+        op3s.push_back((void *)&averagedI);
+        op3s.push_back((void *)&Iz);
+        vector<Op> ops;
+        ops.push_back(&VariationalRefinementImpl::averageOp);
+        ops.push_back(&VariationalRefinementImpl::subtractOp);
+        parallel_for_(Range(0, 2), ParallelOp_ParBody(*this, ops, op1s, op2s, op3s));
+    }
+    splitCheckerboard(Iz_rb, Iz);
+
+    /* Computing first-order derivatives */
+    {
+        vector<void *> op1s;
+        op1s.push_back((void *)&averagedI);
+        op1s.push_back((void *)&averagedI);
+        op1s.push_back((void *)&Iz);
+        op1s.push_back((void *)&Iz);
+        vector<void *> op2s;
+        op2s.push_back((void *)&Ix);
+        op2s.push_back((void *)&Iy);
+        op2s.push_back((void *)&Ixz);
+        op2s.push_back((void *)&Iyz);
+        vector<void *> op3s;
+        op3s.push_back((void *)&Ix_rb);
+        op3s.push_back((void *)&Iy_rb);
+        op3s.push_back((void *)&Ixz_rb);
+        op3s.push_back((void *)&Iyz_rb);
+        vector<Op> ops;
+        ops.push_back(&VariationalRefinementImpl::gradHorizAndSplitOp);
+        ops.push_back(&VariationalRefinementImpl::gradVertAndSplitOp);
+        ops.push_back(&VariationalRefinementImpl::gradHorizAndSplitOp);
+        ops.push_back(&VariationalRefinementImpl::gradVertAndSplitOp);
+        parallel_for_(Range(0, 4), ParallelOp_ParBody(*this, ops, op1s, op2s, op3s));
+    }
+
+    /* Computing second-order derivatives */
+    {
+        vector<void *> op1s;
+        op1s.push_back((void *)&Ix);
+        op1s.push_back((void *)&Ix);
+        op1s.push_back((void *)&Iy);
+        vector<void *> op2s;
+        op2s.push_back((void *)&Ixx);
+        op2s.push_back((void *)&Ixy);
+        op2s.push_back((void *)&Iyy);
+        vector<void *> op3s;
+        op3s.push_back((void *)&Ixx_rb);
+        op3s.push_back((void *)&Ixy_rb);
+        op3s.push_back((void *)&Iyy_rb);
+        vector<Op> ops;
+        ops.push_back(&VariationalRefinementImpl::gradHorizAndSplitOp);
+        ops.push_back(&VariationalRefinementImpl::gradVertAndSplitOp);
+        ops.push_back(&VariationalRefinementImpl::gradVertAndSplitOp);
+        parallel_for_(Range(0, 3), ParallelOp_ParBody(*this, ops, op1s, op2s, op3s));
+    }
+}
+
+VariationalRefinementImpl::ComputeDataTerm_ParBody::ComputeDataTerm_ParBody(VariationalRefinementImpl &_var,
+                                                                            int _nstripes, int _h,
+                                                                            RedBlackBuffer &_dW_u,
+                                                                            RedBlackBuffer &_dW_v, bool _red_pass)
+    : var(&_var), nstripes(_nstripes), h(_h), dW_u(&_dW_u), dW_v(&_dW_v), red_pass(_red_pass)
+{
+    stripe_sz = (int)ceil(h / (double)nstripes);
+}
+
+/* This function computes parts of the main linear system coefficients A11,A12,A22,b1,b1
+ * that correspond to the data term, which includes color and gradient constancy assumptions.
+ */
+void VariationalRefinementImpl::ComputeDataTerm_ParBody::operator()(const Range &range) const
+{
+    int start_i = min(range.start * stripe_sz, h);
+    int end_i = min(range.end * stripe_sz, h);
+
+    float zeta_squared = var->zeta * var->zeta;
+    float epsilon_squared = var->epsilon * var->epsilon;
+    float gamma2 = var->gamma / 2;
+    float delta2 = var->delta / 2;
+
+    float *pIx, *pIy, *pIz;
+    float *pIxx, *pIxy, *pIyy, *pIxz, *pIyz;
+    float *pdU, *pdV;
+    float *pa11, *pa12, *pa22, *pb1, *pb2;
+
+    float derivNorm, derivNorm2;
+    float Ik1z, Ik1zx, Ik1zy;
+    float weight;
+    int len;
+    for (int i = start_i; i < end_i; i++)
+    {
+#define INIT_ROW_POINTERS(color)                                                                                       \
+    pIx = var->Ix_rb.color.ptr<float>(i + 1) + 1;                                                                      \
+    pIy = var->Iy_rb.color.ptr<float>(i + 1) + 1;                                                                      \
+    pIz = var->Iz_rb.color.ptr<float>(i + 1) + 1;                                                                      \
+    pIxx = var->Ixx_rb.color.ptr<float>(i + 1) + 1;                                                                    \
+    pIxy = var->Ixy_rb.color.ptr<float>(i + 1) + 1;                                                                    \
+    pIyy = var->Iyy_rb.color.ptr<float>(i + 1) + 1;                                                                    \
+    pIxz = var->Ixz_rb.color.ptr<float>(i + 1) + 1;                                                                    \
+    pIyz = var->Iyz_rb.color.ptr<float>(i + 1) + 1;                                                                    \
+    pa11 = var->A11.color.ptr<float>(i + 1) + 1;                                                                       \
+    pa12 = var->A12.color.ptr<float>(i + 1) + 1;                                                                       \
+    pa22 = var->A22.color.ptr<float>(i + 1) + 1;                                                                       \
+    pb1 = var->b1.color.ptr<float>(i + 1) + 1;                                                                         \
+    pb2 = var->b2.color.ptr<float>(i + 1) + 1;                                                                         \
+    pdU = dW_u->color.ptr<float>(i + 1) + 1;                                                                           \
+    pdV = dW_v->color.ptr<float>(i + 1) + 1;                                                                           \
+    if (i % 2 == 0)                                                                                                    \
+        len = var->Ix_rb.color##_even_len;                                                                             \
+    else                                                                                                               \
+        len = var->Ix_rb.color##_odd_len;
+
+        if (red_pass)
+        {
+            INIT_ROW_POINTERS(red);
+        }
+        else
+        {
+            INIT_ROW_POINTERS(black);
+        }
+#undef INIT_ROW_POINTERS
+
+        int j = 0;
+#ifdef CV_SIMD128
+        v_float32x4 zeta_vec = v_setall_f32(zeta_squared);
+        v_float32x4 eps_vec = v_setall_f32(epsilon_squared);
+        v_float32x4 delta_vec = v_setall_f32(delta2);
+        v_float32x4 gamma_vec = v_setall_f32(gamma2);
+        v_float32x4 zero_vec = v_setall_f32(0.0f);
+        v_float32x4 pIx_vec, pIy_vec, pIz_vec, pdU_vec, pdV_vec;
+        v_float32x4 pIxx_vec, pIxy_vec, pIyy_vec, pIxz_vec, pIyz_vec;
+        v_float32x4 derivNorm_vec, derivNorm2_vec, weight_vec;
+        v_float32x4 Ik1z_vec, Ik1zx_vec, Ik1zy_vec;
+        v_float32x4 pa11_vec, pa12_vec, pa22_vec, pb1_vec, pb2_vec;
+
+        for (; j < len - 3; j += 4)
+        {
+            pIx_vec = v_load(pIx + j);
+            pIy_vec = v_load(pIy + j);
+            pIz_vec = v_load(pIz + j);
+            pdU_vec = v_load(pdU + j);
+            pdV_vec = v_load(pdV + j);
+
+            derivNorm_vec = pIx_vec * pIx_vec + pIy_vec * pIy_vec + zeta_vec;
+            Ik1z_vec = pIz_vec + pIx_vec * pdU_vec + pIy_vec * pdV_vec;
+            weight_vec = (delta_vec / v_sqrt(Ik1z_vec * Ik1z_vec / derivNorm_vec + eps_vec)) / derivNorm_vec;
+
+            pa11_vec = weight_vec * (pIx_vec * pIx_vec) + zeta_vec;
+            pa12_vec = weight_vec * (pIx_vec * pIy_vec);
+            pa22_vec = weight_vec * (pIy_vec * pIy_vec) + zeta_vec;
+            pb1_vec = zero_vec - weight_vec * (pIz_vec * pIx_vec);
+            pb2_vec = zero_vec - weight_vec * (pIz_vec * pIy_vec);
+
+            pIxx_vec = v_load(pIxx + j);
+            pIxy_vec = v_load(pIxy + j);
+            pIyy_vec = v_load(pIyy + j);
+            pIxz_vec = v_load(pIxz + j);
+            pIyz_vec = v_load(pIyz + j);
+
+            derivNorm_vec = pIxx_vec * pIxx_vec + pIxy_vec * pIxy_vec + zeta_vec;
+            derivNorm2_vec = pIyy_vec * pIyy_vec + pIxy_vec * pIxy_vec + zeta_vec;
+            Ik1zx_vec = pIxz_vec + pIxx_vec * pdU_vec + pIxy_vec * pdV_vec;
+            Ik1zy_vec = pIyz_vec + pIxy_vec * pdU_vec + pIyy_vec * pdV_vec;
+            weight_vec = gamma_vec / v_sqrt(Ik1zx_vec * Ik1zx_vec / derivNorm_vec +
+                                            Ik1zy_vec * Ik1zy_vec / derivNorm2_vec + eps_vec);
+
+            pa11_vec += weight_vec * (pIxx_vec * pIxx_vec / derivNorm_vec + pIxy_vec * pIxy_vec / derivNorm2_vec);
+            pa12_vec += weight_vec * (pIxx_vec * pIxy_vec / derivNorm_vec + pIxy_vec * pIyy_vec / derivNorm2_vec);
+            pa22_vec += weight_vec * (pIxy_vec * pIxy_vec / derivNorm_vec + pIyy_vec * pIyy_vec / derivNorm2_vec);
+            pb1_vec -= weight_vec * (pIxx_vec * pIxz_vec / derivNorm_vec + pIxy_vec * pIyz_vec / derivNorm2_vec);
+            pb2_vec -= weight_vec * (pIxy_vec * pIxz_vec / derivNorm_vec + pIyy_vec * pIyz_vec / derivNorm2_vec);
+
+            v_store(pa11 + j, pa11_vec);
+            v_store(pa12 + j, pa12_vec);
+            v_store(pa22 + j, pa22_vec);
+            v_store(pb1 + j, pb1_vec);
+            v_store(pb2 + j, pb2_vec);
+        }
+#endif
+        for (; j < len; j++)
+        {
+            /* Step 1: Compute color constancy terms */
+            /* Normalization factor:*/
+            derivNorm = pIx[j] * pIx[j] + pIy[j] * pIy[j] + zeta_squared;
+            /* Color constancy penalty (computed by Taylor expansion):*/
+            Ik1z = pIz[j] + pIx[j] * pdU[j] + pIy[j] * pdV[j];
+            /* Weight of the color constancy term in the current fixed-point iteration divided by derivNorm: */
+            weight = (delta2 / sqrt(Ik1z * Ik1z / derivNorm + epsilon_squared)) / derivNorm;
+            /* Add respective color constancy terms to the linear system coefficients: */
+            pa11[j] = weight * (pIx[j] * pIx[j]) + zeta_squared;
+            pa12[j] = weight * (pIx[j] * pIy[j]);
+            pa22[j] = weight * (pIy[j] * pIy[j]) + zeta_squared;
+            pb1[j] = -weight * (pIz[j] * pIx[j]);
+            pb2[j] = -weight * (pIz[j] * pIy[j]);
+
+            /* Step 2: Compute gradient constancy terms */
+            /* Normalization factor for x gradient: */
+            derivNorm = pIxx[j] * pIxx[j] + pIxy[j] * pIxy[j] + zeta_squared;
+            /* Normalization factor for y gradient: */
+            derivNorm2 = pIyy[j] * pIyy[j] + pIxy[j] * pIxy[j] + zeta_squared;
+            /* Gradient constancy penalties (computed by Taylor expansion): */
+            Ik1zx = pIxz[j] + pIxx[j] * pdU[j] + pIxy[j] * pdV[j];
+            Ik1zy = pIyz[j] + pIxy[j] * pdU[j] + pIyy[j] * pdV[j];
+            /* Weight of the gradient constancy term in the current fixed-point iteration: */
+            weight = gamma2 / sqrt(Ik1zx * Ik1zx / derivNorm + Ik1zy * Ik1zy / derivNorm2 + epsilon_squared);
+            /* Add respective gradient constancy components to the linear system coefficients: */
+            pa11[j] += weight * (pIxx[j] * pIxx[j] / derivNorm + pIxy[j] * pIxy[j] / derivNorm2);
+            pa12[j] += weight * (pIxx[j] * pIxy[j] / derivNorm + pIxy[j] * pIyy[j] / derivNorm2);
+            pa22[j] += weight * (pIxy[j] * pIxy[j] / derivNorm + pIyy[j] * pIyy[j] / derivNorm2);
+            pb1[j] += -weight * (pIxx[j] * pIxz[j] / derivNorm + pIxy[j] * pIyz[j] / derivNorm2);
+            pb2[j] += -weight * (pIxy[j] * pIxz[j] / derivNorm + pIyy[j] * pIyz[j] / derivNorm2);
+        }
+    }
+}
+
+VariationalRefinementImpl::ComputeSmoothnessTermHorPass_ParBody::ComputeSmoothnessTermHorPass_ParBody(
+  VariationalRefinementImpl &_var, int _nstripes, int _h, RedBlackBuffer &_W_u, RedBlackBuffer &_W_v,
+  RedBlackBuffer &_tempW_u, RedBlackBuffer &_tempW_v, bool _red_pass)
+    : var(&_var), nstripes(_nstripes), h(_h), W_u(&_W_u), W_v(&_W_v), curW_u(&_tempW_u), curW_v(&_tempW_v),
+      red_pass(_red_pass)
+{
+    stripe_sz = (int)ceil(h / (double)nstripes);
+}
+
+/* This function updates the linear system coefficients A11,A22,b1,b1 according to the
+ * flow smoothness term and computes corresponding weights for the current fixed point iteration.
+ * A11,A22,b1,b1 are updated only partially (horizontal pass). Doing both horizontal and vertical
+ * passes in one loop complicates parallelization (different threads write to the same elements).
+ */
+void VariationalRefinementImpl::ComputeSmoothnessTermHorPass_ParBody::operator()(const Range &range) const
+{
+    int start_i = min(range.start * stripe_sz, h);
+    int end_i = min(range.end * stripe_sz, h);
+
+    float epsilon_squared = var->epsilon * var->epsilon;
+    float alpha2 = var->alpha / 2;
+    float *pWeight;
+    float *pA_u, *pA_u_next, *pA_v, *pA_v_next;
+    float *pB_u, *pB_u_next, *pB_v, *pB_v_next;
+    float *cW_u, *cW_u_next, *cW_u_next_row;
+    float *cW_v, *cW_v_next, *cW_v_next_row;
+    float *pW_u, *pW_u_next;
+    float *pW_v, *pW_v_next;
+    float ux, uy, vx, vy;
+    int len;
+    bool touches_right_border = true;
+
+#define INIT_ROW_POINTERS(cur_color, next_color, next_offs_even, next_offs_odd, bool_default)                          \
+    pWeight = var->weights.cur_color.ptr<float>(i + 1) + 1;                                                            \
+    pA_u = var->A11.cur_color.ptr<float>(i + 1) + 1;                                                                   \
+    pB_u = var->b1.cur_color.ptr<float>(i + 1) + 1;                                                                    \
+    cW_u = curW_u->cur_color.ptr<float>(i + 1) + 1;                                                                    \
+    pW_u = W_u->cur_color.ptr<float>(i + 1) + 1;                                                                       \
+    pA_v = var->A22.cur_color.ptr<float>(i + 1) + 1;                                                                   \
+    pB_v = var->b2.cur_color.ptr<float>(i + 1) + 1;                                                                    \
+    cW_v = curW_v->cur_color.ptr<float>(i + 1) + 1;                                                                    \
+    pW_v = W_v->cur_color.ptr<float>(i + 1) + 1;                                                                       \
+                                                                                                                       \
+    cW_u_next_row = curW_u->next_color.ptr<float>(i + 2) + 1;                                                          \
+    cW_v_next_row = curW_v->next_color.ptr<float>(i + 2) + 1;                                                          \
+                                                                                                                       \
+    if (i % 2 == 0)                                                                                                    \
+    {                                                                                                                  \
+        pA_u_next = var->A11.next_color.ptr<float>(i + 1) + next_offs_even;                                            \
+        pB_u_next = var->b1.next_color.ptr<float>(i + 1) + next_offs_even;                                             \
+        cW_u_next = curW_u->next_color.ptr<float>(i + 1) + next_offs_even;                                             \
+        pW_u_next = W_u->next_color.ptr<float>(i + 1) + next_offs_even;                                                \
+        pA_v_next = var->A22.next_color.ptr<float>(i + 1) + next_offs_even;                                            \
+        pB_v_next = var->b2.next_color.ptr<float>(i + 1) + next_offs_even;                                             \
+        cW_v_next = curW_v->next_color.ptr<float>(i + 1) + next_offs_even;                                             \
+        pW_v_next = W_v->next_color.ptr<float>(i + 1) + next_offs_even;                                                \
+        len = var->A11.cur_color##_even_len;                                                                           \
+        if (var->A11.cur_color##_even_len != var->A11.cur_color##_odd_len)                                             \
+            touches_right_border = bool_default;                                                                       \
+        else                                                                                                           \
+            touches_right_border = !bool_default;                                                                      \
+    }                                                                                                                  \
+    else                                                                                                               \
+    {                                                                                                                  \
+        pA_u_next = var->A11.next_color.ptr<float>(i + 1) + next_offs_odd;                                             \
+        pB_u_next = var->b1.next_color.ptr<float>(i + 1) + next_offs_odd;                                              \
+        cW_u_next = curW_u->next_color.ptr<float>(i + 1) + next_offs_odd;                                              \
+        pW_u_next = W_u->next_color.ptr<float>(i + 1) + next_offs_odd;                                                 \
+        pA_v_next = var->A22.next_color.ptr<float>(i + 1) + next_offs_odd;                                             \
+        pB_v_next = var->b2.next_color.ptr<float>(i + 1) + next_offs_odd;                                              \
+        cW_v_next = curW_v->next_color.ptr<float>(i + 1) + next_offs_odd;                                              \
+        pW_v_next = W_v->next_color.ptr<float>(i + 1) + next_offs_odd;                                                 \
+        len = var->A11.cur_color##_odd_len;                                                                            \
+        if (var->A11.cur_color##_even_len != var->A11.cur_color##_odd_len)                                             \
+            touches_right_border = !bool_default;                                                                      \
+        else                                                                                                           \
+            touches_right_border = bool_default;                                                                       \
+    }
+
+    for (int i = start_i; i < end_i; i++)
+    {
+        if (red_pass)
+        {
+            INIT_ROW_POINTERS(red, black, 1, 2, true);
+        }
+        else
+        {
+            INIT_ROW_POINTERS(black, red, 2, 1, false);
+        }
+#undef INIT_ROW_POINTERS
+
+#define COMPUTE                                                                                                        \
+    /* Gradients for the flow on the current fixed-point iteration: */                                                 \
+    ux = cW_u_next[j] - cW_u[j];                                                                                       \
+    vx = cW_v_next[j] - cW_v[j];                                                                                       \
+    uy = cW_u_next_row[j] - cW_u[j];                                                                                   \
+    vy = cW_v_next_row[j] - cW_v[j];                                                                                   \
+    /* Weight of the smoothness term in the current fixed-point iteration: */                                          \
+    pWeight[j] = alpha2 / sqrt(ux * ux + vx * vx + uy * uy + vy * vy + epsilon_squared);                               \
+    /* Gradients for initial raw flow multiplied by weight:*/                                                          \
+    ux = pWeight[j] * (pW_u_next[j] - pW_u[j]);                                                                        \
+    vx = pWeight[j] * (pW_v_next[j] - pW_v[j]);
+
+#define UPDATE                                                                                                         \
+    pB_u[j] += ux;                                                                                                     \
+    pA_u[j] += pWeight[j];                                                                                             \
+    pB_v[j] += vx;                                                                                                     \
+    pA_v[j] += pWeight[j];                                                                                             \
+    pB_u_next[j] -= ux;                                                                                                \
+    pA_u_next[j] += pWeight[j];                                                                                        \
+    pB_v_next[j] -= vx;                                                                                                \
+    pA_v_next[j] += pWeight[j];
+
+        int j = 0;
+#ifdef CV_SIMD128
+        v_float32x4 alpha2_vec = v_setall_f32(alpha2);
+        v_float32x4 eps_vec = v_setall_f32(epsilon_squared);
+        v_float32x4 cW_u_vec, cW_v_vec;
+        v_float32x4 pWeight_vec, ux_vec, vx_vec, uy_vec, vy_vec;
+
+        for (; j < len - 4; j += 4)
+        {
+            cW_u_vec = v_load(cW_u + j);
+            cW_v_vec = v_load(cW_v + j);
+
+            ux_vec = v_load(cW_u_next + j) - cW_u_vec;
+            vx_vec = v_load(cW_v_next + j) - cW_v_vec;
+            uy_vec = v_load(cW_u_next_row + j) - cW_u_vec;
+            vy_vec = v_load(cW_v_next_row + j) - cW_v_vec;
+            pWeight_vec =
+              alpha2_vec / v_sqrt(ux_vec * ux_vec + vx_vec * vx_vec + uy_vec * uy_vec + vy_vec * vy_vec + eps_vec);
+            v_store(pWeight + j, pWeight_vec);
+
+            ux_vec = pWeight_vec * (v_load(pW_u_next + j) - v_load(pW_u + j));
+            vx_vec = pWeight_vec * (v_load(pW_v_next + j) - v_load(pW_v + j));
+
+            v_store(pA_u + j, v_load(pA_u + j) + pWeight_vec);
+            v_store(pA_v + j, v_load(pA_v + j) + pWeight_vec);
+            v_store(pB_u + j, v_load(pB_u + j) + ux_vec);
+            v_store(pB_v + j, v_load(pB_v + j) + vx_vec);
+
+            v_store(pA_u_next + j, v_load(pA_u_next + j) + pWeight_vec);
+            v_store(pA_v_next + j, v_load(pA_v_next + j) + pWeight_vec);
+            v_store(pB_u_next + j, v_load(pB_u_next + j) - ux_vec);
+            v_store(pB_v_next + j, v_load(pB_v_next + j) - vx_vec);
+        }
+#endif
+        for (; j < len - 1; j++)
+        {
+            COMPUTE;
+            UPDATE;
+        }
+
+        /* Omit the update on the rightmost elements */
+        if (touches_right_border)
+        {
+            COMPUTE;
+        }
+        else
+        {
+            COMPUTE;
+            UPDATE;
+        }
+    }
+#undef COMPUTE
+#undef UPDATE
+}
+
+VariationalRefinementImpl::ComputeSmoothnessTermVertPass_ParBody::ComputeSmoothnessTermVertPass_ParBody(
+  VariationalRefinementImpl &_var, int _nstripes, int _h, RedBlackBuffer &_W_u, RedBlackBuffer &_W_v, bool _red_pass)
+    : var(&_var), nstripes(_nstripes), W_u(&_W_u), W_v(&_W_v), red_pass(_red_pass)
+{
+    /* Omit the last row in the vertical pass */
+    h = _h - 1;
+    stripe_sz = (int)ceil(h / (double)nstripes);
+}
+
+/* This function adds the last remaining terms to the linear system coefficients A11,A22,b1,b1. */
+void VariationalRefinementImpl::ComputeSmoothnessTermVertPass_ParBody::operator()(const Range &range) const
+{
+    int start_i = min(range.start * stripe_sz, h);
+    int end_i = min(range.end * stripe_sz, h);
+
+    float *pWeight;
+    float *pA_u, *pA_u_next_row, *pA_v, *pA_v_next_row;
+    float *pB_u, *pB_u_next_row, *pB_v, *pB_v_next_row;
+    float *pW_u, *pW_u_next_row, *pW_v, *pW_v_next_row;
+    float vy, uy;
+    int len;
+
+    for (int i = start_i; i < end_i; i++)
+    {
+#define INIT_ROW_POINTERS(cur_color, next_color)                                                                       \
+    pWeight = var->weights.cur_color.ptr<float>(i + 1) + 1;                                                            \
+    pA_u = var->A11.cur_color.ptr<float>(i + 1) + 1;                                                                   \
+    pB_u = var->b1.cur_color.ptr<float>(i + 1) + 1;                                                                    \
+    pW_u = W_u->cur_color.ptr<float>(i + 1) + 1;                                                                       \
+    pA_v = var->A22.cur_color.ptr<float>(i + 1) + 1;                                                                   \
+    pB_v = var->b2.cur_color.ptr<float>(i + 1) + 1;                                                                    \
+    pW_v = W_v->cur_color.ptr<float>(i + 1) + 1;                                                                       \
+                                                                                                                       \
+    pA_u_next_row = var->A11.next_color.ptr<float>(i + 2) + 1;                                                         \
+    pB_u_next_row = var->b1.next_color.ptr<float>(i + 2) + 1;                                                          \
+    pW_u_next_row = W_u->next_color.ptr<float>(i + 2) + 1;                                                             \
+    pA_v_next_row = var->A22.next_color.ptr<float>(i + 2) + 1;                                                         \
+    pB_v_next_row = var->b2.next_color.ptr<float>(i + 2) + 1;                                                          \
+    pW_v_next_row = W_v->next_color.ptr<float>(i + 2) + 1;                                                             \
+                                                                                                                       \
+    if (i % 2 == 0)                                                                                                    \
+        len = var->A11.cur_color##_even_len;                                                                           \
+    else                                                                                                               \
+        len = var->A11.cur_color##_odd_len;
+
+        if (red_pass)
+        {
+            INIT_ROW_POINTERS(red, black);
+        }
+        else
+        {
+            INIT_ROW_POINTERS(black, red);
+        }
+#undef INIT_ROW_POINTERS
+
+        int j = 0;
+#ifdef CV_SIMD128
+        v_float32x4 pWeight_vec, uy_vec, vy_vec;
+        for (; j < len - 3; j += 4)
+        {
+            pWeight_vec = v_load(pWeight + j);
+            uy_vec = pWeight_vec * (v_load(pW_u_next_row + j) - v_load(pW_u + j));
+            vy_vec = pWeight_vec * (v_load(pW_v_next_row + j) - v_load(pW_v + j));
+
+            v_store(pA_u + j, v_load(pA_u + j) + pWeight_vec);
+            v_store(pA_v + j, v_load(pA_v + j) + pWeight_vec);
+            v_store(pB_u + j, v_load(pB_u + j) + uy_vec);
+            v_store(pB_v + j, v_load(pB_v + j) + vy_vec);
+
+            v_store(pA_u_next_row + j, v_load(pA_u_next_row + j) + pWeight_vec);
+            v_store(pA_v_next_row + j, v_load(pA_v_next_row + j) + pWeight_vec);
+            v_store(pB_u_next_row + j, v_load(pB_u_next_row + j) - uy_vec);
+            v_store(pB_v_next_row + j, v_load(pB_v_next_row + j) - vy_vec);
+        }
+#endif
+        for (; j < len; j++)
+        {
+            uy = pWeight[j] * (pW_u_next_row[j] - pW_u[j]);
+            vy = pWeight[j] * (pW_v_next_row[j] - pW_v[j]);
+            pB_u[j] += uy;
+            pA_u[j] += pWeight[j];
+            pB_v[j] += vy;
+            pA_v[j] += pWeight[j];
+            pB_u_next_row[j] -= uy;
+            pA_u_next_row[j] += pWeight[j];
+            pB_v_next_row[j] -= vy;
+            pA_v_next_row[j] += pWeight[j];
+        }
+    }
+}
+
+VariationalRefinementImpl::RedBlackSOR_ParBody::RedBlackSOR_ParBody(VariationalRefinementImpl &_var, int _nstripes,
+                                                                    int _h, RedBlackBuffer &_dW_u,
+                                                                    RedBlackBuffer &_dW_v, bool _red_pass)
+    : var(&_var), nstripes(_nstripes), h(_h), dW_u(&_dW_u), dW_v(&_dW_v), red_pass(_red_pass)
+{
+    stripe_sz = (int)ceil(h / (double)nstripes);
+}
+
+/* This function implements the Red-Black SOR (successive-over relaxation) method for solving the main
+ * linear system in the current fixed-point iteration.
+ */
+void VariationalRefinementImpl::RedBlackSOR_ParBody::operator()(const Range &range) const
+{
+    int start = min(range.start * stripe_sz, h);
+    int end = min(range.end * stripe_sz, h);
+
+    float *pa11, *pa12, *pa22, *pb1, *pb2, *pW, *pdu, *pdv;
+    float *pW_next, *pdu_next, *pdv_next;
+    float *pW_prev_row, *pdu_prev_row, *pdv_prev_row;
+    float *pdu_next_row, *pdv_next_row;
+
+    float sigmaU, sigmaV;
+    int j, len;
+    for (int i = start; i < end; i++)
+    {
+#define INIT_ROW_POINTERS(cur_color, next_color, next_offs_even, next_offs_odd)                                        \
+    pW = var->weights.cur_color.ptr<float>(i + 1) + 1;                                                                 \
+    pa11 = var->A11.cur_color.ptr<float>(i + 1) + 1;                                                                   \
+    pa12 = var->A12.cur_color.ptr<float>(i + 1) + 1;                                                                   \
+    pa22 = var->A22.cur_color.ptr<float>(i + 1) + 1;                                                                   \
+    pb1 = var->b1.cur_color.ptr<float>(i + 1) + 1;                                                                     \
+    pb2 = var->b2.cur_color.ptr<float>(i + 1) + 1;                                                                     \
+    pdu = dW_u->cur_color.ptr<float>(i + 1) + 1;                                                                       \
+    pdv = dW_v->cur_color.ptr<float>(i + 1) + 1;                                                                       \
+                                                                                                                       \
+    pdu_next_row = dW_u->next_color.ptr<float>(i + 2) + 1;                                                             \
+    pdv_next_row = dW_v->next_color.ptr<float>(i + 2) + 1;                                                             \
+                                                                                                                       \
+    pW_prev_row = var->weights.next_color.ptr<float>(i) + 1;                                                           \
+    pdu_prev_row = dW_u->next_color.ptr<float>(i) + 1;                                                                 \
+    pdv_prev_row = dW_v->next_color.ptr<float>(i) + 1;                                                                 \
+                                                                                                                       \
+    if (i % 2 == 0)                                                                                                    \
+    {                                                                                                                  \
+        pW_next = var->weights.next_color.ptr<float>(i + 1) + next_offs_even;                                          \
+        pdu_next = dW_u->next_color.ptr<float>(i + 1) + next_offs_even;                                                \
+        pdv_next = dW_v->next_color.ptr<float>(i + 1) + next_offs_even;                                                \
+        len = var->A11.cur_color##_even_len;                                                                           \
+    }                                                                                                                  \
+    else                                                                                                               \
+    {                                                                                                                  \
+        pW_next = var->weights.next_color.ptr<float>(i + 1) + next_offs_odd;                                           \
+        pdu_next = dW_u->next_color.ptr<float>(i + 1) + next_offs_odd;                                                 \
+        pdv_next = dW_v->next_color.ptr<float>(i + 1) + next_offs_odd;                                                 \
+        len = var->A11.cur_color##_odd_len;                                                                            \
+    }
+        if (red_pass)
+        {
+            INIT_ROW_POINTERS(red, black, 1, 2);
+        }
+        else
+        {
+            INIT_ROW_POINTERS(black, red, 2, 1);
+        }
+#undef INIT_ROW_POINTERS
+
+        j = 0;
+#ifdef CV_SIMD128
+        v_float32x4 pW_prev_vec = v_setall_f32(pW_next[-1]);
+        v_float32x4 pdu_prev_vec = v_setall_f32(pdu_next[-1]);
+        v_float32x4 pdv_prev_vec = v_setall_f32(pdv_next[-1]);
+        v_float32x4 omega_vec = v_setall_f32(var->omega);
+        v_float32x4 pW_vec, pW_next_vec, pW_prev_row_vec;
+        v_float32x4 pdu_next_vec, pdu_prev_row_vec, pdu_next_row_vec;
+        v_float32x4 pdv_next_vec, pdv_prev_row_vec, pdv_next_row_vec;
+        v_float32x4 pW_shifted_vec, pdu_shifted_vec, pdv_shifted_vec;
+        v_float32x4 pa12_vec, sigmaU_vec, sigmaV_vec, pdu_vec, pdv_vec;
+        for (; j < len - 3; j += 4)
+        {
+            pW_vec = v_load(pW + j);
+            pW_next_vec = v_load(pW_next + j);
+            pW_prev_row_vec = v_load(pW_prev_row + j);
+            pdu_next_vec = v_load(pdu_next + j);
+            pdu_prev_row_vec = v_load(pdu_prev_row + j);
+            pdu_next_row_vec = v_load(pdu_next_row + j);
+            pdv_next_vec = v_load(pdv_next + j);
+            pdv_prev_row_vec = v_load(pdv_prev_row + j);
+            pdv_next_row_vec = v_load(pdv_next_row + j);
+            pa12_vec = v_load(pa12 + j);
+            pW_shifted_vec = v_reinterpret_as_f32(
+              v_extract<3>(v_reinterpret_as_s32(pW_prev_vec), v_reinterpret_as_s32(pW_next_vec)));
+            pdu_shifted_vec = v_reinterpret_as_f32(
+              v_extract<3>(v_reinterpret_as_s32(pdu_prev_vec), v_reinterpret_as_s32(pdu_next_vec)));
+            pdv_shifted_vec = v_reinterpret_as_f32(
+              v_extract<3>(v_reinterpret_as_s32(pdv_prev_vec), v_reinterpret_as_s32(pdv_next_vec)));
+
+            sigmaU_vec = pW_shifted_vec * pdu_shifted_vec + pW_vec * pdu_next_vec + pW_prev_row_vec * pdu_prev_row_vec +
+                         pW_vec * pdu_next_row_vec;
+            sigmaV_vec = pW_shifted_vec * pdv_shifted_vec + pW_vec * pdv_next_vec + pW_prev_row_vec * pdv_prev_row_vec +
+                         pW_vec * pdv_next_row_vec;
+
+            pdu_vec = v_load(pdu + j);
+            pdv_vec = v_load(pdv + j);
+            pdu_vec += omega_vec * ((sigmaU_vec + v_load(pb1 + j) - pdv_vec * pa12_vec) / v_load(pa11 + j) - pdu_vec);
+            pdv_vec += omega_vec * ((sigmaV_vec + v_load(pb2 + j) - pdu_vec * pa12_vec) / v_load(pa22 + j) - pdv_vec);
+            v_store(pdu + j, pdu_vec);
+            v_store(pdv + j, pdv_vec);
+
+            pW_prev_vec = pW_next_vec;
+            pdu_prev_vec = pdu_next_vec;
+            pdv_prev_vec = pdv_next_vec;
+        }
+#endif
+        for (; j < len; j++)
+        {
+            sigmaU = pW_next[j - 1] * pdu_next[j - 1] + pW[j] * pdu_next[j] + pW_prev_row[j] * pdu_prev_row[j] +
+                     pW[j] * pdu_next_row[j];
+            sigmaV = pW_next[j - 1] * pdv_next[j - 1] + pW[j] * pdv_next[j] + pW_prev_row[j] * pdv_prev_row[j] +
+                     pW[j] * pdv_next_row[j];
+            pdu[j] += var->omega * ((sigmaU + pb1[j] - pdv[j] * pa12[j]) / pa11[j] - pdu[j]);
+            pdv[j] += var->omega * ((sigmaV + pb2[j] - pdu[j] * pa12[j]) / pa22[j] - pdv[j]);
+        }
+    }
+}
+
+void VariationalRefinementImpl::calc(InputArray I0, InputArray I1, InputOutputArray flow)
+{
+    CV_Assert(!I0.empty() && I0.channels() == 1);
+    CV_Assert(!I1.empty() && I1.channels() == 1);
+    CV_Assert(I0.sameSize(I1));
+    CV_Assert((I0.depth() == CV_8U && I1.depth() == CV_8U) || (I0.depth() == CV_32F && I1.depth() == CV_32F));
+    CV_Assert(!flow.empty() && flow.depth() == CV_32F && flow.channels() == 2);
+    CV_Assert(I0.sameSize(flow));
+
+    Mat uv[2];
+    Mat &flowMat = flow.getMatRef();
+    split(flowMat, uv);
+    calcUV(I0, I1, uv[0], uv[1]);
+    merge(uv, 2, flowMat);
+}
+
+void VariationalRefinementImpl::calcUV(InputArray I0, InputArray I1, InputOutputArray flow_u, InputOutputArray flow_v)
+{
+    CV_Assert(!I0.empty() && I0.channels() == 1);
+    CV_Assert(!I1.empty() && I1.channels() == 1);
+    CV_Assert(I0.sameSize(I1));
+    CV_Assert((I0.depth() == CV_8U && I1.depth() == CV_8U) || (I0.depth() == CV_32F && I1.depth() == CV_32F));
+    CV_Assert(!flow_u.empty() && flow_u.depth() == CV_32F && flow_u.channels() == 1);
+    CV_Assert(!flow_v.empty() && flow_v.depth() == CV_32F && flow_v.channels() == 1);
+    CV_Assert(I0.sameSize(flow_u));
+    CV_Assert(flow_u.sameSize(flow_v));
+
+    int num_stripes = getNumThreads();
+    Mat I0Mat = I0.getMat();
+    Mat I1Mat = I1.getMat();
+    Mat &W_u = flow_u.getMatRef();
+    Mat &W_v = flow_v.getMatRef();
+    prepareBuffers(I0Mat, I1Mat, W_u, W_v);
+
+    splitCheckerboard(W_u_rb, W_u);
+    splitCheckerboard(W_v_rb, W_v);
+    W_u_rb.red.copyTo(tempW_u.red);
+    W_u_rb.black.copyTo(tempW_u.black);
+    W_v_rb.red.copyTo(tempW_v.red);
+    W_v_rb.black.copyTo(tempW_v.black);
+    dW_u.red.setTo(0.0f);
+    dW_u.black.setTo(0.0f);
+    dW_v.red.setTo(0.0f);
+    dW_v.black.setTo(0.0f);
+
+    for (int i = 0; i < fixedPointIterations; i++)
+    {
+        parallel_for_(Range(0, num_stripes), ComputeDataTerm_ParBody(*this, num_stripes, I0Mat.rows, dW_u, dW_v, true));
+        parallel_for_(Range(0, num_stripes), ComputeDataTerm_ParBody(*this, num_stripes, I0Mat.rows, dW_u, dW_v, false));
+
+        parallel_for_(Range(0, num_stripes), ComputeSmoothnessTermHorPass_ParBody(
+                                               *this, num_stripes, I0Mat.rows, W_u_rb, W_v_rb, tempW_u, tempW_v, true));
+        parallel_for_(Range(0, num_stripes), ComputeSmoothnessTermHorPass_ParBody(
+                                               *this, num_stripes, I0Mat.rows, W_u_rb, W_v_rb, tempW_u, tempW_v, false));
+
+        parallel_for_(Range(0, num_stripes),
+                      ComputeSmoothnessTermVertPass_ParBody(*this, num_stripes, I0Mat.rows, W_u_rb, W_v_rb, true));
+        parallel_for_(Range(0, num_stripes),
+                      ComputeSmoothnessTermVertPass_ParBody(*this, num_stripes, I0Mat.rows, W_u_rb, W_v_rb, false));
+
+        for (int j = 0; j < sorIterations; j++)
+        {
+            parallel_for_(Range(0, num_stripes), RedBlackSOR_ParBody(*this, num_stripes, I0Mat.rows, dW_u, dW_v, true));
+            parallel_for_(Range(0, num_stripes), RedBlackSOR_ParBody(*this, num_stripes, I0Mat.rows, dW_u, dW_v, false));
+        }
+
+        tempW_u.red = W_u_rb.red + dW_u.red;
+        tempW_u.black = W_u_rb.black + dW_u.black;
+        updateRepeatedBorders(tempW_u);
+        tempW_v.red = W_v_rb.red + dW_v.red;
+        tempW_v.black = W_v_rb.black + dW_v.black;
+        updateRepeatedBorders(tempW_v);
+    }
+    mergeCheckerboard(W_u, tempW_u);
+    mergeCheckerboard(W_v, tempW_v);
+}
+void VariationalRefinementImpl::collectGarbage()
+{
+    Ix.release();
+    Iy.release();
+    Iz.release();
+    Ixx.release();
+    Ixy.release();
+    Iyy.release();
+    Ixz.release();
+    Iyz.release();
+
+    Ix_rb.release();
+    Iy_rb.release();
+    Iz_rb.release();
+    Ixx_rb.release();
+    Ixy_rb.release();
+    Iyy_rb.release();
+    Ixz_rb.release();
+    Iyz_rb.release();
+
+    A11.release();
+    A12.release();
+    A22.release();
+    b1.release();
+    b2.release();
+    weights.release();
+
+    mapX.release();
+    mapY.release();
+
+    tempW_u.release();
+    tempW_v.release();
+    dW_u.release();
+    dW_v.release();
+    W_u_rb.release();
+    W_v_rb.release();
+}
+
+Ptr<VariationalRefinement> createVariationalFlowRefinement() { return makePtr<VariationalRefinementImpl>(); }
+}
+}
diff --git a/contrib/modules/optflow/test/test_OF_accuracy.cpp b/contrib/modules/optflow/test/test_OF_accuracy.cpp
new file mode 100644
index 0000000..c47ff90
--- /dev/null
+++ b/contrib/modules/optflow/test/test_OF_accuracy.cpp
@@ -0,0 +1,285 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+//  By downloading, copying, installing or using the software you agree to this license.
+//  If you do not agree to this license, do not download, install,
+//  copy or use the software.
+//
+//
+//                        Intel License Agreement
+//                For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+//   * Redistribution's of source code must retain the above copyright notice,
+//     this list of conditions and the following disclaimer.
+//
+//   * Redistribution's in binary form must reproduce the above copyright notice,
+//     this list of conditions and the following disclaimer in the documentation
+//     and/or other materials provided with the distribution.
+//
+//   * The name of Intel Corporation may not be used to endorse or promote products
+//     derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "test_precomp.hpp"
+#include <fstream>
+
+using namespace std;
+using namespace cv;
+using namespace cvtest;
+using namespace optflow;
+
+static string getDataDir() { return TS::ptr()->get_data_path(); }
+
+static string getRubberWhaleFrame1() { return getDataDir() + "optflow/RubberWhale1.png"; }
+
+static string getRubberWhaleFrame2() { return getDataDir() + "optflow/RubberWhale2.png"; }
+
+static string getRubberWhaleGroundTruth() { return getDataDir() + "optflow/RubberWhale.flo"; }
+
+static bool isFlowCorrect(float u) { return !cvIsNaN(u) && (fabs(u) < 1e9); }
+
+static bool isFlowCorrect(double u) { return !cvIsNaN(u) && (fabs(u) < 1e9); }
+
+static float calcRMSE(Mat flow1, Mat flow2)
+{
+    float sum = 0;
+    int counter = 0;
+    const int rows = flow1.rows;
+    const int cols = flow1.cols;
+
+    for (int y = 0; y < rows; ++y)
+    {
+        for (int x = 0; x < cols; ++x)
+        {
+            Vec2f flow1_at_point = flow1.at<Vec2f>(y, x);
+            Vec2f flow2_at_point = flow2.at<Vec2f>(y, x);
+
+            float u1 = flow1_at_point[0];
+            float v1 = flow1_at_point[1];
+            float u2 = flow2_at_point[0];
+            float v2 = flow2_at_point[1];
+
+            if (isFlowCorrect(u1) && isFlowCorrect(u2) && isFlowCorrect(v1) && isFlowCorrect(v2))
+            {
+                sum += (u1 - u2) * (u1 - u2) + (v1 - v2) * (v1 - v2);
+                counter++;
+            }
+        }
+    }
+    return (float)sqrt(sum / (1e-9 + counter));
+}
+
+static float calcAvgEPE(vector< pair<Point2i, Point2i> > corr, Mat flow)
+{
+    double sum = 0;
+    int counter = 0;
+
+    for (size_t i = 0; i < corr.size(); ++i)
+    {
+        Vec2f flow1_at_point = Point2f(corr[i].second - corr[i].first);
+        Vec2f flow2_at_point = flow.at<Vec2f>(corr[i].first.y, corr[i].first.x);
+
+        double u1 = (double)flow1_at_point[0];
+        double v1 = (double)flow1_at_point[1];
+        double u2 = (double)flow2_at_point[0];
+        double v2 = (double)flow2_at_point[1];
+
+        if (isFlowCorrect(u1) && isFlowCorrect(u2) && isFlowCorrect(v1) && isFlowCorrect(v2))
+        {
+            sum += sqrt((u1 - u2) * (u1 - u2) + (v1 - v2) * (v1 - v2));
+            counter++;
+        }
+    }
+
+    return (float)(sum / counter);
+}
+
+bool readRubberWhale(Mat &dst_frame_1, Mat &dst_frame_2, Mat &dst_GT)
+{
+    const string frame1_path = getRubberWhaleFrame1();
+    const string frame2_path = getRubberWhaleFrame2();
+    const string gt_flow_path = getRubberWhaleGroundTruth();
+
+    dst_frame_1 = imread(frame1_path);
+    dst_frame_2 = imread(frame2_path);
+    dst_GT = readOpticalFlow(gt_flow_path);
+
+    if (dst_frame_1.empty() || dst_frame_2.empty() || dst_GT.empty())
+        return false;
+    else
+        return true;
+}
+
+TEST(DenseOpticalFlow_SimpleFlow, ReferenceAccuracy)
+{
+    Mat frame1, frame2, GT;
+    ASSERT_TRUE(readRubberWhale(frame1, frame2, GT));
+    float target_RMSE = 0.37f;
+
+    Mat flow;
+    Ptr<DenseOpticalFlow> algo;
+    algo = createOptFlow_SimpleFlow();
+    algo->calc(frame1, frame2, flow);
+    ASSERT_EQ(GT.rows, flow.rows);
+    ASSERT_EQ(GT.cols, flow.cols);
+    EXPECT_LE(calcRMSE(GT, flow), target_RMSE);
+}
+
+TEST(DenseOpticalFlow_DeepFlow, ReferenceAccuracy)
+{
+    Mat frame1, frame2, GT;
+    ASSERT_TRUE(readRubberWhale(frame1, frame2, GT));
+    float target_RMSE = 0.35f;
+    cvtColor(frame1, frame1, COLOR_BGR2GRAY);
+    cvtColor(frame2, frame2, COLOR_BGR2GRAY);
+
+    Mat flow;
+    Ptr<DenseOpticalFlow> algo;
+    algo = createOptFlow_DeepFlow();
+    algo->calc(frame1, frame2, flow);
+    ASSERT_EQ(GT.rows, flow.rows);
+    ASSERT_EQ(GT.cols, flow.cols);
+    EXPECT_LE(calcRMSE(GT, flow), target_RMSE);
+}
+
+TEST(DenseOpticalFlow_SparseToDenseFlow, ReferenceAccuracy)
+{
+    Mat frame1, frame2, GT;
+    ASSERT_TRUE(readRubberWhale(frame1, frame2, GT));
+    float target_RMSE = 0.52f;
+
+    Mat flow;
+    Ptr<DenseOpticalFlow> algo;
+    algo = createOptFlow_SparseToDense();
+    algo->calc(frame1, frame2, flow);
+    ASSERT_EQ(GT.rows, flow.rows);
+    ASSERT_EQ(GT.cols, flow.cols);
+    EXPECT_LE(calcRMSE(GT, flow), target_RMSE);
+}
+
+TEST(DenseOpticalFlow_DIS, ReferenceAccuracy)
+{
+    Mat frame1, frame2, GT;
+    ASSERT_TRUE(readRubberWhale(frame1, frame2, GT));
+    int presets[] = {DISOpticalFlow::PRESET_ULTRAFAST, DISOpticalFlow::PRESET_FAST, DISOpticalFlow::PRESET_MEDIUM};
+    float target_RMSE[] = {0.86f, 0.74f, 0.49f};
+    cvtColor(frame1, frame1, COLOR_BGR2GRAY);
+    cvtColor(frame2, frame2, COLOR_BGR2GRAY);
+
+    Ptr<DenseOpticalFlow> algo;
+
+    // iterate over presets:
+    for (int i = 0; i < 3; i++)
+    {
+        Mat flow;
+        algo = createOptFlow_DIS(presets[i]);
+        algo->calc(frame1, frame2, flow);
+        ASSERT_EQ(GT.rows, flow.rows);
+        ASSERT_EQ(GT.cols, flow.cols);
+        EXPECT_LE(calcRMSE(GT, flow), target_RMSE[i]);
+    }
+}
+
+TEST(DenseOpticalFlow_VariationalRefinement, ReferenceAccuracy)
+{
+    Mat frame1, frame2, GT;
+    ASSERT_TRUE(readRubberWhale(frame1, frame2, GT));
+    float target_RMSE = 0.86f;
+    cvtColor(frame1, frame1, COLOR_BGR2GRAY);
+    cvtColor(frame2, frame2, COLOR_BGR2GRAY);
+
+    Ptr<VariationalRefinement> var_ref;
+    var_ref = createVariationalFlowRefinement();
+    var_ref->setAlpha(20.0f);
+    var_ref->setDelta(5.0f);
+    var_ref->setGamma(10.0f);
+    var_ref->setSorIterations(25);
+    var_ref->setFixedPointIterations(25);
+    Mat flow(frame1.size(), CV_32FC2);
+    flow.setTo(0.0f);
+    var_ref->calc(frame1, frame2, flow);
+    ASSERT_EQ(GT.rows, flow.rows);
+    ASSERT_EQ(GT.cols, flow.cols);
+    EXPECT_LE(calcRMSE(GT, flow), target_RMSE);
+}
+
+TEST(DenseOpticalFlow_PCAFlow, ReferenceAccuracy)
+{
+    Mat frame1, frame2, GT;
+    ASSERT_TRUE(readRubberWhale(frame1, frame2, GT));
+    const float target_RMSE = 0.55f;
+
+    Mat flow;
+    Ptr<DenseOpticalFlow> algo = createOptFlow_PCAFlow();
+    algo->calc(frame1, frame2, flow);
+    ASSERT_EQ(GT.rows, flow.rows);
+    ASSERT_EQ(GT.cols, flow.cols);
+    EXPECT_LE(calcRMSE(GT, flow), target_RMSE);
+}
+
+TEST(DenseOpticalFlow_GlobalPatchColliderDCT, ReferenceAccuracy)
+{
+    Mat frame1, frame2, GT;
+    ASSERT_TRUE(readRubberWhale(frame1, frame2, GT));
+
+    const Size sz = frame1.size() / 2;
+    frame1 = frame1(Rect(0, 0, sz.width, sz.height));
+    frame2 = frame2(Rect(0, 0, sz.width, sz.height));
+    GT = GT(Rect(0, 0, sz.width, sz.height));
+
+    vector<Mat> img1, img2, gt;
+    vector< pair<Point2i, Point2i> > corr;
+    img1.push_back(frame1);
+    img2.push_back(frame2);
+    gt.push_back(GT);
+
+    Ptr< GPCForest<5> > forest = GPCForest<5>::create();
+    forest->train(img1, img2, gt, GPCTrainingParams(8, 3, GPC_DESCRIPTOR_DCT, false));
+    forest->findCorrespondences(frame1, frame2, corr);
+
+    ASSERT_LE(7500U, corr.size());
+    ASSERT_LE(calcAvgEPE(corr, GT), 0.5f);
+}
+
+TEST(DenseOpticalFlow_GlobalPatchColliderWHT, ReferenceAccuracy)
+{
+    Mat frame1, frame2, GT;
+    ASSERT_TRUE(readRubberWhale(frame1, frame2, GT));
+
+    const Size sz = frame1.size() / 2;
+    frame1 = frame1(Rect(0, 0, sz.width, sz.height));
+    frame2 = frame2(Rect(0, 0, sz.width, sz.height));
+    GT = GT(Rect(0, 0, sz.width, sz.height));
+
+    vector<Mat> img1, img2, gt;
+    vector< pair<Point2i, Point2i> > corr;
+    img1.push_back(frame1);
+    img2.push_back(frame2);
+    gt.push_back(GT);
+
+    Ptr< GPCForest<5> > forest = GPCForest<5>::create();
+    forest->train(img1, img2, gt, GPCTrainingParams(8, 3, GPC_DESCRIPTOR_WHT, false));
+    forest->findCorrespondences(frame1, frame2, corr);
+
+    ASSERT_LE(7000U, corr.size());
+    ASSERT_LE(calcAvgEPE(corr, GT), 0.5f);
+}
diff --git a/contrib/modules/optflow/test/test_OF_reproducibility.cpp b/contrib/modules/optflow/test/test_OF_reproducibility.cpp
new file mode 100644
index 0000000..0cdbd50
--- /dev/null
+++ b/contrib/modules/optflow/test/test_OF_reproducibility.cpp
@@ -0,0 +1,159 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+//  By downloading, copying, installing or using the software you agree to this license.
+//  If you do not agree to this license, do not download, install,
+//  copy or use the software.
+//
+//
+//                        Intel License Agreement
+//                For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+//   * Redistribution's of source code must retain the above copyright notice,
+//     this list of conditions and the following disclaimer.
+//
+//   * Redistribution's in binary form must reproduce the above copyright notice,
+//     this list of conditions and the following disclaimer in the documentation
+//     and/or other materials provided with the distribution.
+//
+//   * The name of Intel Corporation may not be used to endorse or promote products
+//     derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "test_precomp.hpp"
+#include <fstream>
+
+using namespace std;
+using namespace std::tr1;
+using namespace cv;
+using namespace cvtest;
+using namespace perf;
+using namespace testing;
+using namespace optflow;
+
+typedef tuple<Size> OFParams;
+typedef TestWithParam<OFParams> DenseOpticalFlow_DIS;
+typedef TestWithParam<OFParams> DenseOpticalFlow_VariationalRefinement;
+
+TEST_P(DenseOpticalFlow_DIS, MultithreadReproducibility)
+{
+    double MAX_DIF = 0.01;
+    double MAX_MEAN_DIF = 0.001;
+    int loopsCount = 2;
+    RNG rng(0);
+
+    OFParams params = GetParam();
+    Size size = get<0>(params);
+
+    for (int iter = 0; iter <= loopsCount; iter++)
+    {
+        Mat frame1(size, CV_8U);
+        randu(frame1, 0, 255);
+        Mat frame2(size, CV_8U);
+        randu(frame2, 0, 255);
+
+        Ptr<DISOpticalFlow> algo = createOptFlow_DIS();
+        int psz = rng.uniform(4, 16);
+        int pstr = rng.uniform(1, psz - 1);
+        int grad_iter = rng.uniform(1, 64);
+        int var_iter = rng.uniform(0, 10);
+        bool use_mean_normalization = !!rng.uniform(0, 2);
+        bool use_spatial_propagation = !!rng.uniform(0, 2);
+        algo->setFinestScale(0);
+        algo->setPatchSize(psz);
+        algo->setPatchStride(pstr);
+        algo->setGradientDescentIterations(grad_iter);
+        algo->setVariationalRefinementIterations(var_iter);
+        algo->setUseMeanNormalization(use_mean_normalization);
+        algo->setUseSpatialPropagation(use_spatial_propagation);
+
+        cv::setNumThreads(cv::getNumberOfCPUs());
+        Mat resMultiThread;
+        algo->calc(frame1, frame2, resMultiThread);
+
+        cv::setNumThreads(1);
+        Mat resSingleThread;
+        algo->calc(frame1, frame2, resSingleThread);
+
+        EXPECT_LE(cv::norm(resSingleThread, resMultiThread, NORM_INF), MAX_DIF);
+        EXPECT_LE(cv::norm(resSingleThread, resMultiThread, NORM_L1), MAX_MEAN_DIF * frame1.total());
+
+        // resulting flow should be within the frame bounds:
+        double min_val, max_val;
+        minMaxLoc(resMultiThread, &min_val, &max_val);
+        EXPECT_LE(abs(min_val), sqrt(size.height * size.height + size.width * size.width));
+        EXPECT_LE(abs(max_val), sqrt(size.height * size.height + size.width * size.width));
+    }
+}
+
+INSTANTIATE_TEST_CASE_P(FullSet, DenseOpticalFlow_DIS, Values(szODD, szQVGA));
+
+TEST_P(DenseOpticalFlow_VariationalRefinement, MultithreadReproducibility)
+{
+    double MAX_DIF = 0.01;
+    double MAX_MEAN_DIF = 0.001;
+    float input_flow_rad = 5.0;
+    int loopsCount = 2;
+    RNG rng(0);
+
+    OFParams params = GetParam();
+    Size size = get<0>(params);
+
+    for (int iter = 0; iter <= loopsCount; iter++)
+    {
+        Mat frame1(size, CV_8U);
+        randu(frame1, 0, 255);
+        Mat frame2(size, CV_8U);
+        randu(frame2, 0, 255);
+        Mat flow(size, CV_32FC2);
+        randu(flow, -input_flow_rad, input_flow_rad);
+
+        Ptr<VariationalRefinement> var = createVariationalFlowRefinement();
+        var->setAlpha(rng.uniform(1.0f, 100.0f));
+        var->setGamma(rng.uniform(0.1f, 10.0f));
+        var->setDelta(rng.uniform(0.1f, 10.0f));
+        var->setSorIterations(rng.uniform(1, 20));
+        var->setFixedPointIterations(rng.uniform(1, 20));
+        var->setOmega(rng.uniform(1.01f, 1.99f));
+
+        cv::setNumThreads(cv::getNumberOfCPUs());
+        Mat resMultiThread;
+        flow.copyTo(resMultiThread);
+        var->calc(frame1, frame2, resMultiThread);
+
+        cv::setNumThreads(1);
+        Mat resSingleThread;
+        flow.copyTo(resSingleThread);
+        var->calc(frame1, frame2, resSingleThread);
+
+        EXPECT_LE(cv::norm(resSingleThread, resMultiThread, NORM_INF), MAX_DIF);
+        EXPECT_LE(cv::norm(resSingleThread, resMultiThread, NORM_L1), MAX_MEAN_DIF * frame1.total());
+
+        // resulting flow should be within the frame bounds:
+        double min_val, max_val;
+        minMaxLoc(resMultiThread, &min_val, &max_val);
+        EXPECT_LE(abs(min_val), sqrt(size.height * size.height + size.width * size.width));
+        EXPECT_LE(abs(max_val), sqrt(size.height * size.height + size.width * size.width));
+    }
+}
+
+INSTANTIATE_TEST_CASE_P(FullSet, DenseOpticalFlow_VariationalRefinement, Values(szODD, szQVGA));
diff --git a/contrib/modules/optflow/test/test_simpleflow.cpp b/contrib/modules/optflow/test/test_simpleflow.cpp
deleted file mode 100644
index b04cae2..0000000
--- a/contrib/modules/optflow/test/test_simpleflow.cpp
+++ /dev/null
@@ -1,190 +0,0 @@
-/*M///////////////////////////////////////////////////////////////////////////////////////
-//
-//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
-//
-//  By downloading, copying, installing or using the software you agree to this license.
-//  If you do not agree to this license, do not download, install,
-//  copy or use the software.
-//
-//
-//                        Intel License Agreement
-//                For Open Source Computer Vision Library
-//
-// Copyright (C) 2000, Intel Corporation, all rights reserved.
-// Third party copyrights are property of their respective owners.
-//
-// Redistribution and use in source and binary forms, with or without modification,
-// are permitted provided that the following conditions are met:
-//
-//   * Redistribution's of source code must retain the above copyright notice,
-//     this list of conditions and the following disclaimer.
-//
-//   * Redistribution's in binary form must reproduce the above copyright notice,
-//     this list of conditions and the following disclaimer in the documentation
-//     and/or other materials provided with the distribution.
-//
-//   * The name of Intel Corporation may not be used to endorse or promote products
-//     derived from this software without specific prior written permission.
-//
-// This software is provided by the copyright holders and contributors "as is" and
-// any express or implied warranties, including, but not limited to, the implied
-// warranties of merchantability and fitness for a particular purpose are disclaimed.
-// In no event shall the Intel Corporation or contributors be liable for any direct,
-// indirect, incidental, special, exemplary, or consequential damages
-// (including, but not limited to, procurement of substitute goods or services;
-// loss of use, data, or profits; or business interruption) however caused
-// and on any theory of liability, whether in contract, strict liability,
-// or tort (including negligence or otherwise) arising in any way out of
-// the use of this software, even if advised of the possibility of such damage.
-//
-//M*/
-
-#include "test_precomp.hpp"
-
-#include <string>
-
-using namespace std;
-
-/* ///////////////////// simpleflow_test ///////////////////////// */
-
-class CV_SimpleFlowTest : public cvtest::BaseTest
-{
-public:
-    CV_SimpleFlowTest();
-protected:
-    void run(int);
-};
-
-
-CV_SimpleFlowTest::CV_SimpleFlowTest() {}
-
-static bool readOpticalFlowFromFile(FILE* file, cv::Mat& flow) {
-  char header[5];
-  if (fread(header, 1, 4, file) < 4 && (string)header != "PIEH") {
-    return false;
-  }
-
-  int cols, rows;
-  if (fread(&cols, sizeof(int), 1, file) != 1||
-      fread(&rows, sizeof(int), 1, file) != 1) {
-    return false;
-  }
-
-  flow = cv::Mat::zeros(rows, cols, CV_32FC2);
-
-  for (int i = 0; i < rows; ++i) {
-    for (int j = 0; j < cols; ++j) {
-      cv::Vec2f flow_at_point;
-      if (fread(&(flow_at_point[0]), sizeof(float), 1, file) != 1 ||
-          fread(&(flow_at_point[1]), sizeof(float), 1, file) != 1) {
-        return false;
-      }
-      flow.at<cv::Vec2f>(i, j) = flow_at_point;
-    }
-  }
-
-  return true;
-}
-
-static bool isFlowCorrect(float u) {
-  return !cvIsNaN(u) && (fabs(u) < 1e9);
-}
-
-static float calc_rmse(cv::Mat flow1, cv::Mat flow2) {
-  float sum = 0;
-  int counter = 0;
-  const int rows = flow1.rows;
-  const int cols = flow1.cols;
-
-  for (int y = 0; y < rows; ++y) {
-    for (int x = 0; x < cols; ++x) {
-      cv::Vec2f flow1_at_point = flow1.at<cv::Vec2f>(y, x);
-      cv::Vec2f flow2_at_point = flow2.at<cv::Vec2f>(y, x);
-
-      float u1 = flow1_at_point[0];
-      float v1 = flow1_at_point[1];
-      float u2 = flow2_at_point[0];
-      float v2 = flow2_at_point[1];
-
-      if (isFlowCorrect(u1) && isFlowCorrect(u2) && isFlowCorrect(v1) && isFlowCorrect(v2)) {
-        sum += (u1-u2)*(u1-u2) + (v1-v2)*(v1-v2);
-        counter++;
-      }
-    }
-  }
-  return (float)sqrt(sum / (1e-9 + counter));
-}
-
-void CV_SimpleFlowTest::run(int) {
-    const float MAX_RMSE = 0.6f;
-    const string frame1_path = ts->get_data_path() + "optflow/RubberWhale1.png";
-    const string frame2_path = ts->get_data_path() + "optflow/RubberWhale2.png";
-    const string gt_flow_path = ts->get_data_path() + "optflow/RubberWhale.flo";
-
-    cv::Mat frame1 = cv::imread(frame1_path);
-    cv::Mat frame2 = cv::imread(frame2_path);
-
-    if (frame1.empty()) {
-      ts->printf(cvtest::TS::LOG, "could not read image %s\n", frame2_path.c_str());
-      ts->set_failed_test_info(cvtest::TS::FAIL_MISSING_TEST_DATA);
-      return;
-    }
-
-    if (frame2.empty()) {
-      ts->printf(cvtest::TS::LOG, "could not read image %s\n", frame2_path.c_str());
-      ts->set_failed_test_info(cvtest::TS::FAIL_MISSING_TEST_DATA);
-      return;
-    }
-
-    if (frame1.rows != frame2.rows && frame1.cols != frame2.cols) {
-      ts->printf(cvtest::TS::LOG, "images should be of equal sizes (%s and %s)",
-                 frame1_path.c_str(), frame2_path.c_str());
-      ts->set_failed_test_info(cvtest::TS::FAIL_MISSING_TEST_DATA);
-      return;
-    }
-
-    if (frame1.type() != 16 || frame2.type() != 16) {
-      ts->printf(cvtest::TS::LOG, "images should be of equal type CV_8UC3 (%s and %s)",
-                 frame1_path.c_str(), frame2_path.c_str());
-      ts->set_failed_test_info(cvtest::TS::FAIL_MISSING_TEST_DATA);
-      return;
-    }
-
-    cv::Mat flow_gt;
-
-    FILE* gt_flow_file = fopen(gt_flow_path.c_str(), "rb");
-    if (gt_flow_file == NULL) {
-      ts->printf(cvtest::TS::LOG, "could not read ground-thuth flow from file %s",
-                 gt_flow_path.c_str());
-      ts->set_failed_test_info(cvtest::TS::FAIL_MISSING_TEST_DATA);
-      return;
-    }
-
-    if (!readOpticalFlowFromFile(gt_flow_file, flow_gt)) {
-      ts->printf(cvtest::TS::LOG, "error while reading flow data from file %s",
-                 gt_flow_path.c_str());
-      ts->set_failed_test_info(cvtest::TS::FAIL_MISSING_TEST_DATA);
-      return;
-    }
-    fclose(gt_flow_file);
-
-    cv::Mat flow;
-    cv::optflow::calcOpticalFlowSF(frame1, frame2, flow, 3, 2, 4);
-
-    float rmse = calc_rmse(flow_gt, flow);
-
-    ts->printf(cvtest::TS::LOG, "Optical flow estimation RMSE for SimpleFlow algorithm : %lf\n",
-               rmse);
-
-    if (rmse > MAX_RMSE) {
-      ts->printf( cvtest::TS::LOG,
-                 "Too big rmse error : %lf ( >= %lf )\n", rmse, MAX_RMSE);
-      ts->set_failed_test_info(cvtest::TS::FAIL_BAD_ACCURACY);
-      return;
-    }
-}
-
-
-TEST(Video_OpticalFlowSimpleFlow, accuracy) { CV_SimpleFlowTest test; test.safe_run(); }
-
-/* End of file. */
diff --git a/contrib/modules/optflow/test/test_sparsetodenseflow.cpp b/contrib/modules/optflow/test/test_sparsetodenseflow.cpp
deleted file mode 100644
index a8d645d..0000000
--- a/contrib/modules/optflow/test/test_sparsetodenseflow.cpp
+++ /dev/null
@@ -1,146 +0,0 @@
-/*M///////////////////////////////////////////////////////////////////////////////////////
-//
-//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
-//
-//  By downloading, copying, installing or using the software you agree to this license.
-//  If you do not agree to this license, do not download, install,
-//  copy or use the software.
-//
-//
-//                        Intel License Agreement
-//                For Open Source Computer Vision Library
-//
-// Copyright (C) 2000, Intel Corporation, all rights reserved.
-// Third party copyrights are property of their respective owners.
-//
-// Redistribution and use in source and binary forms, with or without modification,
-// are permitted provided that the following conditions are met:
-//
-//   * Redistribution's of source code must retain the above copyright notice,
-//     this list of conditions and the following disclaimer.
-//
-//   * Redistribution's in binary form must reproduce the above copyright notice,
-//     this list of conditions and the following disclaimer in the documentation
-//     and/or other materials provided with the distribution.
-//
-//   * The name of Intel Corporation may not be used to endorse or promote products
-//     derived from this software without specific prior written permission.
-//
-// This software is provided by the copyright holders and contributors "as is" and
-// any express or implied warranties, including, but not limited to, the implied
-// warranties of merchantability and fitness for a particular purpose are disclaimed.
-// In no event shall the Intel Corporation or contributors be liable for any direct,
-// indirect, incidental, special, exemplary, or consequential damages
-// (including, but not limited to, procurement of substitute goods or services;
-// loss of use, data, or profits; or business interruption) however caused
-// and on any theory of liability, whether in contract, strict liability,
-// or tort (including negligence or otherwise) arising in any way out of
-// the use of this software, even if advised of the possibility of such damage.
-//
-//M*/
-
-#include "test_precomp.hpp"
-
-#include <string>
-
-using namespace std;
-using namespace cv;
-
-/* ///////////////////// sparsetodenseflow_test ///////////////////////// */
-
-class CV_SparseToDenseFlowTest : public cvtest::BaseTest
-{
-protected:
-    void run(int);
-};
-
-static bool isFlowCorrect(float u) {
-  return !cvIsNaN(u) && (fabs(u) < 1e9);
-}
-
-static float calc_rmse(Mat flow1, Mat flow2) {
-  float sum = 0;
-  int counter = 0;
-  const int rows = flow1.rows;
-  const int cols = flow1.cols;
-
-  for (int y = 0; y < rows; ++y) {
-    for (int x = 0; x < cols; ++x) {
-      Vec2f flow1_at_point = flow1.at<Vec2f>(y, x);
-      Vec2f flow2_at_point = flow2.at<Vec2f>(y, x);
-
-      float u1 = flow1_at_point[0];
-      float v1 = flow1_at_point[1];
-      float u2 = flow2_at_point[0];
-      float v2 = flow2_at_point[1];
-
-      if (isFlowCorrect(u1) && isFlowCorrect(u2) && isFlowCorrect(v1) && isFlowCorrect(v2)) {
-        sum += (u1-u2)*(u1-u2) + (v1-v2)*(v1-v2);
-        counter++;
-      }
-    }
-  }
-  return (float)sqrt(sum / (1e-9 + counter));
-}
-
-void CV_SparseToDenseFlowTest::run(int) {
-    const float MAX_RMSE = 0.6f;
-    const string frame1_path = ts->get_data_path() + "optflow/RubberWhale1.png";
-    const string frame2_path = ts->get_data_path() + "optflow/RubberWhale2.png";
-    const string gt_flow_path = ts->get_data_path() + "optflow/RubberWhale.flo";
-
-    Mat frame1 = imread(frame1_path);
-    Mat frame2 = imread(frame2_path);
-
-    if (frame1.empty()) {
-      ts->printf(cvtest::TS::LOG, "could not read image %s\n", frame2_path.c_str());
-      ts->set_failed_test_info(cvtest::TS::FAIL_MISSING_TEST_DATA);
-      return;
-    }
-
-    if (frame2.empty()) {
-      ts->printf(cvtest::TS::LOG, "could not read image %s\n", frame2_path.c_str());
-      ts->set_failed_test_info(cvtest::TS::FAIL_MISSING_TEST_DATA);
-      return;
-    }
-
-    if (frame1.rows != frame2.rows && frame1.cols != frame2.cols) {
-      ts->printf(cvtest::TS::LOG, "images should be of equal sizes (%s and %s)",
-                 frame1_path.c_str(), frame2_path.c_str());
-      ts->set_failed_test_info(cvtest::TS::FAIL_MISSING_TEST_DATA);
-      return;
-    }
-
-    if (frame1.type() != 16 || frame2.type() != 16) {
-      ts->printf(cvtest::TS::LOG, "images should be of equal type CV_8UC3 (%s and %s)",
-                 frame1_path.c_str(), frame2_path.c_str());
-      ts->set_failed_test_info(cvtest::TS::FAIL_MISSING_TEST_DATA);
-      return;
-    }
-
-    Mat flow_gt = optflow::readOpticalFlow(gt_flow_path);
-    if(flow_gt.empty()) {
-      ts->printf(cvtest::TS::LOG, "error while reading flow data from file %s",
-                 gt_flow_path.c_str());
-      ts->set_failed_test_info(cvtest::TS::FAIL_MISSING_TEST_DATA);
-      return;
-    }
-
-    Mat flow;
-    optflow::calcOpticalFlowSparseToDense(frame1, frame2, flow);
-
-    float rmse = calc_rmse(flow_gt, flow);
-
-    ts->printf(cvtest::TS::LOG, "Optical flow estimation RMSE for SparseToDenseFlow algorithm : %lf\n",
-               rmse);
-
-    if (rmse > MAX_RMSE) {
-      ts->printf( cvtest::TS::LOG,
-                 "Too big rmse error : %lf ( >= %lf )\n", rmse, MAX_RMSE);
-      ts->set_failed_test_info(cvtest::TS::FAIL_BAD_ACCURACY);
-      return;
-    }
-}
-
-
-TEST(Video_OpticalFlowSparseToDenseFlow, accuracy) { CV_SparseToDenseFlowTest test; test.safe_run(); }
diff --git a/contrib/modules/phase_unwrapping/CMakeLists.txt b/contrib/modules/phase_unwrapping/CMakeLists.txt
new file mode 100644
index 0000000..6ba8923
--- /dev/null
+++ b/contrib/modules/phase_unwrapping/CMakeLists.txt
@@ -0,0 +1,2 @@
+set(the_description "Phase Unwrapping API")
+ocv_define_module(phase_unwrapping opencv_core opencv_calib3d opencv_imgproc opencv_highgui opencv_features2d opencv_rgbd WRAP python java)
diff --git a/contrib/modules/phase_unwrapping/README.md b/contrib/modules/phase_unwrapping/README.md
new file mode 100644
index 0000000..7a82e59
--- /dev/null
+++ b/contrib/modules/phase_unwrapping/README.md
@@ -0,0 +1,4 @@
+Phase Unwrapping
+================
+
+OpenCV module that can be used to unwrap two-dimensional phase map.
diff --git a/contrib/modules/phase_unwrapping/doc/phase_unwrapping.bib b/contrib/modules/phase_unwrapping/doc/phase_unwrapping.bib
new file mode 100644
index 0000000..b957ca8
--- /dev/null
+++ b/contrib/modules/phase_unwrapping/doc/phase_unwrapping.bib
@@ -0,0 +1,9 @@
+ at article{histogramUnwrapping,
+  title={A novel algorithm based on histogram processing of reliability for two-dimensional phase unwrapping},
+  author={Lei, Hai and Chang, Xin-yu and Wang, Fei and Hu, Xiao-Tang and Hu, Xiao-Dong},
+  journal={Optik-International Journal for Light and Electron Optics},
+  volume={126},
+  number={18},
+  pages={1640--1644},
+  year={2015},
+}
diff --git a/contrib/modules/phase_unwrapping/include/opencv2/phase_unwrapping.hpp b/contrib/modules/phase_unwrapping/include/opencv2/phase_unwrapping.hpp
new file mode 100644
index 0000000..0e15e71
--- /dev/null
+++ b/contrib/modules/phase_unwrapping/include/opencv2/phase_unwrapping.hpp
@@ -0,0 +1,61 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+ //
+ //  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+ //
+ //  By downloading, copying, installing or using the software you agree to this license.
+ //  If you do not agree to this license, do not download, install,
+ //  copy or use the software.
+ //
+ //
+ //                           License Agreement
+ //                For Open Source Computer Vision Library
+ //
+ // Copyright (C) 2015, OpenCV Foundation, all rights reserved.
+ // Third party copyrights are property of their respective owners.
+ //
+ // Redistribution and use in source and binary forms, with or without modification,
+ // are permitted provided that the following conditions are met:
+ //
+ //   * Redistribution's of source code must retain the above copyright notice,
+ //     this list of conditions and the following disclaimer.
+ //
+ //   * Redistribution's in binary form must reproduce the above copyright notice,
+ //     this list of conditions and the following disclaimer in the documentation
+ //     and/or other materials provided with the distribution.
+ //
+ //   * The name of the copyright holders may not be used to endorse or promote products
+ //     derived from this software without specific prior written permission.
+ //
+ // This software is provided by the copyright holders and contributors "as is" and
+ // any express or implied warranties, including, but not limited to, the implied
+ // warranties of merchantability and fitness for a particular purpose are disclaimed.
+ // In no event shall the Intel Corporation or contributors be liable for any direct,
+ // indirect, incidental, special, exemplary, or consequential damages
+ // (including, but not limited to, procurement of substitute goods or services;
+ // loss of use, data, or profits; or business interruption) however caused
+ // and on any theory of liability, whether in contract, strict liability,
+ // or tort (including negligence or otherwise) arising in any way out of
+ // the use of this software, even if advised of the possibility of such damage.
+ //
+ //M*/
+
+#include "opencv2/phase_unwrapping/phase_unwrapping.hpp"
+#include "opencv2/phase_unwrapping/histogramphaseunwrapping.hpp"
+
+/** @defgroup phase_unwrapping Phase Unwrapping API
+
+Two-dimensional phase unwrapping is found in different applications like terrain elevation estimation
+in synthetic aperture radar (SAR), field mapping in magnetic resonance imaging or as a way of finding
+corresponding pixels in structured light reconstruction with sinusoidal patterns.
+
+Given a phase map, wrapped between [-pi; pi], phase unwrapping aims at finding the "true" phase map
+by adding the right number of 2*pi to each pixel.
+
+The problem is straightforward for perfect wrapped phase map, but real data are usually not noise-free.
+Among the different algorithms that were developed, quality-guided phase unwrapping methods are fast
+and efficient. They follow a path that unwraps high quality pixels first,
+avoiding error propagation from the start.
+
+In this module, a quality-guided phase unwrapping is implemented following the approach described in @cite histogramUnwrapping .
+
+*/
\ No newline at end of file
diff --git a/contrib/modules/phase_unwrapping/include/opencv2/phase_unwrapping/histogramphaseunwrapping.hpp b/contrib/modules/phase_unwrapping/include/opencv2/phase_unwrapping/histogramphaseunwrapping.hpp
new file mode 100644
index 0000000..e75d889
--- /dev/null
+++ b/contrib/modules/phase_unwrapping/include/opencv2/phase_unwrapping/histogramphaseunwrapping.hpp
@@ -0,0 +1,107 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+ //
+ //  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+ //
+ //  By downloading, copying, installing or using the software you agree to this license.
+ //  If you do not agree to this license, do not download, install,
+ //  copy or use the software.
+ //
+ //
+ //                           License Agreement
+ //                For Open Source Computer Vision Library
+ //
+ // Copyright (C) 2015, OpenCV Foundation, all rights reserved.
+ // Third party copyrights are property of their respective owners.
+ //
+ // Redistribution and use in source and binary forms, with or without modification,
+ // are permitted provided that the following conditions are met:
+ //
+ //   * Redistribution's of source code must retain the above copyright notice,
+ //     this list of conditions and the following disclaimer.
+ //
+ //   * Redistribution's in binary form must reproduce the above copyright notice,
+ //     this list of conditions and the following disclaimer in the documentation
+ //     and/or other materials provided with the distribution.
+ //
+ //   * The name of the copyright holders may not be used to endorse or promote products
+ //     derived from this software without specific prior written permission.
+ //
+ // This software is provided by the copyright holders and contributors "as is" and
+ // any express or implied warranties, including, but not limited to, the implied
+ // warranties of merchantability and fitness for a particular purpose are disclaimed.
+ // In no event shall the Intel Corporation or contributors be liable for any direct,
+ // indirect, incidental, special, exemplary, or consequential damages
+ // (including, but not limited to, procurement of substitute goods or services;
+ // loss of use, data, or profits; or business interruption) however caused
+ // and on any theory of liability, whether in contract, strict liability,
+ // or tort (including negligence or otherwise) arising in any way out of
+ // the use of this software, even if advised of the possibility of such damage.
+ //
+ //M*/
+
+#ifndef __OPENCV_HISTOGRAM_PHASE_UNWRAPPING_HPP__
+#define __OPENCV_HISTOGRAM_PHASE_UNWRAPPING_HPP__
+
+#include "opencv2/core.hpp"
+#include <opencv2/imgproc.hpp>
+#include "opencv2/phase_unwrapping/phase_unwrapping.hpp"
+
+namespace cv {
+namespace phase_unwrapping {
+//! @addtogroup phase_unwrapping
+//! @{
+
+    /** @brief Class implementing two-dimensional phase unwrapping based on @cite histogramUnwrapping
+     * This algorithm belongs to the quality-guided phase unwrapping methods.
+     * First, it computes a reliability map from second differences between a pixel and its eight neighbours.
+     * Reliability values lie between 0 and 16*pi*pi. Then, this reliability map is used to compute
+     * the reliabilities of "edges". An edge is an entity defined by two pixels that are connected
+     * horizontally or vertically. Its reliability is found by adding the the reliabilities of the
+     * two pixels connected through it. Edges are sorted in a histogram based on their reliability values.
+     * This histogram is then used to unwrap pixels, starting from the highest quality pixel.
+
+     * The wrapped phase map and the unwrapped result are stored in CV_32FC1 Mat.
+     */
+class CV_EXPORTS_W HistogramPhaseUnwrapping : public PhaseUnwrapping
+{
+
+public:
+    /**
+     * @brief Parameters of phaseUnwrapping constructor.
+
+     * @param width Phase map width.
+     * @param height Phase map height.
+     * @param histThresh Bins in the histogram are not of equal size. Default value is 3*pi*pi. The one before "histThresh" value are smaller.
+     * @param nbrOfSmallBins Number of bins between 0 and "histThresh". Default value is 10.
+     * @param nbrOfLargeBins Number of bins between "histThresh" and 32*pi*pi (highest edge reliability value). Default value is 5.
+     */
+    struct CV_EXPORTS Params
+    {
+        Params();
+        int width;
+        int height;
+        float histThresh;
+        int nbrOfSmallBins;
+        int nbrOfLargeBins;
+    };
+    /**
+     * @brief Constructor
+
+     * @param parameters HistogramPhaseUnwrapping parameters HistogramPhaseUnwrapping::Params: width,height of the phase map and histogram characteristics.
+     */
+    static Ptr<HistogramPhaseUnwrapping> create( const HistogramPhaseUnwrapping::Params &parameters =
+                                                 HistogramPhaseUnwrapping::Params() );
+
+    /**
+     * @brief Get the reliability map computed from the wrapped phase map.
+
+     * @param reliabilityMap Image where the reliability map is stored.
+     */
+    CV_WRAP
+    virtual void getInverseReliabilityMap( OutputArray reliabilityMap ) = 0;
+};
+
+//! @}
+}
+}
+#endif
\ No newline at end of file
diff --git a/contrib/modules/phase_unwrapping/include/opencv2/phase_unwrapping/phase_unwrapping.hpp b/contrib/modules/phase_unwrapping/include/opencv2/phase_unwrapping/phase_unwrapping.hpp
new file mode 100644
index 0000000..5b5cb51
--- /dev/null
+++ b/contrib/modules/phase_unwrapping/include/opencv2/phase_unwrapping/phase_unwrapping.hpp
@@ -0,0 +1,74 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+ //
+ //  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+ //
+ //  By downloading, copying, installing or using the software you agree to this license.
+ //  If you do not agree to this license, do not download, install,
+ //  copy or use the software.
+ //
+ //
+ //                           License Agreement
+ //                For Open Source Computer Vision Library
+ //
+ // Copyright (C) 2015, OpenCV Foundation, all rights reserved.
+ // Third party copyrights are property of their respective owners.
+ //
+ // Redistribution and use in source and binary forms, with or without modification,
+ // are permitted provided that the following conditions are met:
+ //
+ //   * Redistribution's of source code must retain the above copyright notice,
+ //     this list of conditions and the following disclaimer.
+ //
+ //   * Redistribution's in binary form must reproduce the above copyright notice,
+ //     this list of conditions and the following disclaimer in the documentation
+ //     and/or other materials provided with the distribution.
+ //
+ //   * The name of the copyright holders may not be used to endorse or promote products
+ //     derived from this software without specific prior written permission.
+ //
+ // This software is provided by the copyright holders and contributors "as is" and
+ // any express or implied warranties, including, but not limited to, the implied
+ // warranties of merchantability and fitness for a particular purpose are disclaimed.
+ // In no event shall the Intel Corporation or contributors be liable for any direct,
+ // indirect, incidental, special, exemplary, or consequential damages
+ // (including, but not limited to, procurement of substitute goods or services;
+ // loss of use, data, or profits; or business interruption) however caused
+ // and on any theory of liability, whether in contract, strict liability,
+ // or tort (including negligence or otherwise) arising in any way out of
+ // the use of this software, even if advised of the possibility of such damage.
+ //
+ //M*/
+
+#ifndef __OPENCV_PHASE_UNWRAPPING_HPP__
+#define __OPENCV_PHASE_UNWRAPPING_HPP__
+
+#include "opencv2/core.hpp"
+
+namespace cv {
+namespace phase_unwrapping {
+//! @addtogroup phase_unwrapping
+//! @{
+
+    /**
+     @brief Abstract base class for phase unwrapping.
+    */
+class CV_EXPORTS_W PhaseUnwrapping : public virtual Algorithm
+{
+public:
+    /**
+     * @brief Unwraps a 2D phase map.
+
+     * @param wrappedPhaseMap The wrapped phase map that needs to be unwrapped.
+     * @param unwrappedPhaseMap The unwrapped phase map.
+     * @param shadowMask Optional parameter used when some pixels do not hold any phase information in the wrapped phase map.
+     */
+    CV_WRAP
+    virtual void unwrapPhaseMap( InputArray wrappedPhaseMap, OutputArray unwrappedPhaseMap,
+                                 InputArray shadowMask = noArray() ) = 0;
+
+};
+
+//! @}
+}
+}
+#endif
\ No newline at end of file
diff --git a/contrib/modules/phase_unwrapping/samples/unwrap.cpp b/contrib/modules/phase_unwrapping/samples/unwrap.cpp
new file mode 100644
index 0000000..ad9f9e4
--- /dev/null
+++ b/contrib/modules/phase_unwrapping/samples/unwrap.cpp
@@ -0,0 +1,125 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+ //
+ //  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+ //
+ //  By downloading, copying, installing or using the software you agree to this license.
+ //  If you do not agree to this license, do not download, install,
+ //  copy or use the software.
+ //
+ //
+ //                           License Agreement
+ //                For Open Source Computer Vision Library
+ //
+ // Copyright (C) 2015, OpenCV Foundation, all rights reserved.
+ // Third party copyrights are property of their respective owners.
+ //
+ // Redistribution and use in source and binary forms, with or without modification,
+ // are permitted provided that the following conditions are met:
+ //
+ //   * Redistribution's of source code must retain the above copyright notice,
+ //     this list of conditions and the following disclaimer.
+ //
+ //   * Redistribution's in binary form must reproduce the above copyright notice,
+ //     this list of conditions and the following disclaimer in the documentation
+ //     and/or other materials provided with the distribution.
+ //
+ //   * The name of the copyright holders may not be used to endorse or promote products
+ //     derived from this software without specific prior written permission.
+ //
+ // This software is provided by the copyright holders and contributors "as is" and
+ // any express or implied warranties, including, but not limited to, the implied
+ // warranties of merchantability and fitness for a particular purpose are disclaimed.
+ // In no event shall the Intel Corporation or contributors be liable for any direct,
+ // indirect, incidental, special, exemplary, or consequential damages
+ // (including, but not limited to, procurement of substitute goods or services;
+ // loss of use, data, or profits; or business interruption) however caused
+ // and on any theory of liability, whether in contract, strict liability,
+ // or tort (including negligence or otherwise) arising in any way out of
+ // the use of this software, even if advised of the possibility of such damage.
+
+ *  //
+ //M*/
+
+#include <opencv2/imgproc.hpp>
+#include <opencv2/highgui.hpp>
+#include <opencv2/phase_unwrapping.hpp>
+#include <iostream>
+#include <fstream>
+#include <stdio.h>
+
+
+
+using namespace cv;
+using namespace std;
+
+static const char* keys =
+{
+    "{@inputPath | | Path of the wrapped phase map saved in a yaml file }"
+    "{@outputUnwrappedName | | Path of the unwrapped phase map to be saved in a yaml file and as an 8 bit png}"
+};
+
+static void help()
+{
+    cout << "\nThis example shows how to use the \"Phase unwrapping module\" to unwrap a phase map"
+            " saved in a yaml file (see extra_data\\phase_unwrapping\\data\\wrappedpeaks.yml)."
+            " The mat name in the file should be \"phaseValue\". The result is saved in a yaml file"
+            " too. Two images (wrapped.png and output_name.png) are also created"
+            " for visualization purpose."
+            "\nTo call: ./example_phase_unwrapping_unwrap <input_path> <output_unwrapped_name> \n"
+         << endl;
+}
+int main(int argc, char **argv)
+{
+    phase_unwrapping::HistogramPhaseUnwrapping::Params params;
+
+    CommandLineParser parser(argc, argv, keys);
+    String inputPath = parser.get<String>(0);
+    String outputUnwrappedName = parser.get<String>(1);
+
+    if( inputPath.empty() || outputUnwrappedName.empty() )
+    {
+        help();
+        return -1;
+    }
+    FileStorage fsInput(inputPath, FileStorage::READ);
+    FileStorage fsOutput(outputUnwrappedName + ".yml", FileStorage::WRITE);
+
+    Mat wPhaseMap;
+    Mat uPhaseMap;
+    Mat reliabilities;
+    fsInput["phaseValues"] >> wPhaseMap;
+    fsInput.release();
+    params.width = wPhaseMap.cols;
+    params.height = wPhaseMap.rows;
+
+    Ptr<phase_unwrapping::HistogramPhaseUnwrapping> phaseUnwrapping = phase_unwrapping::HistogramPhaseUnwrapping::create(params);
+
+    phaseUnwrapping->unwrapPhaseMap(wPhaseMap, uPhaseMap);
+    fsOutput << "phaseValues" << uPhaseMap;
+    fsOutput.release();
+
+    phaseUnwrapping->getInverseReliabilityMap(reliabilities);
+
+    Mat uPhaseMap8, wPhaseMap8, reliabilities8;
+    wPhaseMap.convertTo(wPhaseMap8, CV_8U, 255, 128);
+    uPhaseMap.convertTo(uPhaseMap8, CV_8U, 1, 128);
+    reliabilities.convertTo(reliabilities8, CV_8U, 255,128);
+
+    imshow("reliabilities", reliabilities);
+    imshow("wrapped phase map", wPhaseMap8);
+    imshow("unwrapped phase map", uPhaseMap8);
+
+    imwrite(outputUnwrappedName + ".png", uPhaseMap8);
+    imwrite("reliabilities.png", reliabilities8);
+
+    bool loop = true;
+    while( loop )
+    {
+        char key = (char)waitKey(0);
+        if( key == 27 )
+        {
+            loop = false;
+        }
+    }
+    return 0;
+}
\ No newline at end of file
diff --git a/contrib/modules/phase_unwrapping/src/histogramphaseunwrapping.cpp b/contrib/modules/phase_unwrapping/src/histogramphaseunwrapping.cpp
new file mode 100644
index 0000000..6551285
--- /dev/null
+++ b/contrib/modules/phase_unwrapping/src/histogramphaseunwrapping.cpp
@@ -0,0 +1,783 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+ //
+ //  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+ //
+ //  By downloading, copying, installing or using the software you agree to this license.
+ //  If you do not agree to this license, do not download, install,
+ //  copy or use the software.
+ //
+ //
+ //                           License Agreement
+ //                For Open Source Computer Vision Library
+ //
+ // Copyright (C) 2015, OpenCV Foundation, all rights reserved.
+ // Third party copyrights are property of their respective owners.
+ //
+ // Redistribution and use in source and binary forms, with or without modification,
+ // are permitted provided that the following conditions are met:
+ //
+ //   * Redistribution's of source code must retain the above copyright notice,
+ //     this list of conditions and the following disclaimer.
+ //
+ //   * Redistribution's in binary form must reproduce the above copyright notice,
+ //     this list of conditions and the following disclaimer in the documentation
+ //     and/or other materials provided with the distribution.
+ //
+ //   * The name of the copyright holders may not be used to endorse or promote products
+ //     derived from this software without specific prior written permission.
+ //
+ // This software is provided by the copyright holders and contributors "as is" and
+ // any express or implied warranties, including, but not limited to, the implied
+ // warranties of merchantability and fitness for a particular purpose are disclaimed.
+ // In no event shall the Intel Corporation or contributors be liable for any direct,
+ // indirect, incidental, special, exemplary, or consequential damages
+ // (including, but not limited to, procurement of substitute goods or services;
+ // loss of use, data, or profits; or business interruption) however caused
+ // and on any theory of liability, whether in contract, strict liability,
+ // or tort (including negligence or otherwise) arising in any way out of
+ // the use of this software, even if advised of the possibility of such damage.
+ //
+ //M*/
+
+
+#include "precomp.hpp"
+
+namespace cv {
+namespace phase_unwrapping {
+class CV_EXPORTS_W HistogramPhaseUnwrapping_Impl : public HistogramPhaseUnwrapping
+{
+public:
+    // Constructor
+    explicit HistogramPhaseUnwrapping_Impl( const HistogramPhaseUnwrapping::Params &parameters =
+                                            HistogramPhaseUnwrapping::Params() );
+    // Destructor
+    virtual ~HistogramPhaseUnwrapping_Impl(){};
+
+    // Unwrap phase map
+    void unwrapPhaseMap( InputArray wrappedPhaseMap, OutputArray unwrappedPhaseMap,
+                         InputArray shadowMask = noArray() );
+    // Get reliability map computed from the wrapped phase map
+    void getInverseReliabilityMap( OutputArray reliabilityMap );
+
+private:
+    // Class describing a pixel
+    class Pixel
+    {
+    private:
+        // Value from the wrapped phase map
+        float phaseValue;
+        // Id of a pixel. Computed from its position in the Mat
+        int idx;
+        // Pixel is valid if it's not in a shadow region
+        bool valid;
+        // "Quality" parameter. See reference paper
+        float inverseReliability;
+        // Number of 2pi  that needs to be added to the pixel to unwrap the phase map
+        int increment;
+        // Number of pixels that are in the same group as the current pixel
+        int nbrOfPixelsInGroup;
+        // Group id. At first, group id is the same value as idx
+        int groupId;
+        // Pixel is alone in its group
+        bool singlePixelGroup;
+    public:
+        Pixel();
+        Pixel( float pV, int id, bool v, float iR, int inc );
+        float getPhaseValue();
+        int getIndex();
+        bool getValidity();
+        float getInverseReliability();
+        int getIncrement();
+        int getNbrOfPixelsInGroup();
+        int getGroupId();
+        bool getSinglePixelGroup();
+        void setIncrement( int inc );
+        // When a pixel which is not in a single group is added to a new group, we need to keep the previous increment and add "inc" to it.
+        void changeIncrement( int inc );
+        void setNbrOfPixelsInGroup( int nbr );
+        void setGroupId( int gId );
+        void setSinglePixelGroup( bool s );
+    };
+    // Class describing an Edge as presented in the reference paper
+    class Edge
+    {
+    private:
+        // Id of the first pixel that forms the edge
+        int pixOneId;
+        // Id of the second pixel that forms the edge
+        int pixTwoId;
+        // Number of 2pi that needs to be added to the second pixel to remove discontinuities
+        int increment;
+    public:
+        Edge();
+        Edge( int p1, int p2, int inc );
+        int getPixOneId();
+        int getPixTwoId();
+        int getIncrement();
+    };
+    // Class describing a bin from the histogram
+    class HistogramBin
+    {
+    private:
+        float start;
+        float end;
+        std::vector<Edge> edges;
+    public:
+        HistogramBin();
+        HistogramBin( float s, float e );
+        void addEdge( Edge e );
+        std::vector<Edge> getEdges();
+    };
+    // Class describing the histogram. Bins before "thresh" are smaller than the one after "thresh" value
+    class Histogram
+    {
+    private:
+        std::vector<HistogramBin> bins;
+        float thresh;
+        float smallWidth;
+        float largeWidth;
+        int nbrOfSmallBins;
+        int nbrOfLargeBins;
+        int nbrOfBins;
+    public:
+        Histogram();
+        void createBins( float t, int nbrOfBinsBeforeThresh, int nbrOfBinsAfterThresh );
+        void addBin( HistogramBin b );
+        void addEdgeInBin( Edge e, int binIndex);
+        float getThresh();
+        float getSmallWidth();
+        float getLargeWidth();
+        int getNbrOfBins();
+        std::vector<Edge> getEdgesFromBin( int binIndex );
+    };
+    // Params for phase unwrapping
+    Params params;
+    // Pixels from the wrapped phase map
+    std::vector<Pixel> pixels;
+    // Histogram used to unwrap
+    Histogram histogram;
+    // Compute pixel reliability.
+    void computePixelsReliability( InputArray wrappedPhaseMap, InputArray shadowMask = noArray() );
+    // Compute edges reliability and sort them in the histogram
+    void computeEdgesReliabilityAndCreateHistogram();
+    // Methods that is used in the previous one
+    void createAndSortEdge( int idx1, int idx2 );
+    // Unwrap the phase map thanks to the histogram
+    void unwrapHistogram();
+    // add right number of 2*pi to the pixels
+    void addIncrement( OutputArray unwrappedPhaseMap );
+    // Gamma function from the paper
+    float wrap( float a, float b );
+    // Similar to the previous one but returns the number of 2pi that needs to be added
+    int findInc( float a, float b );
+};
+// Default parameters
+HistogramPhaseUnwrapping::Params::Params(){
+    width = 800;
+    height = 600;
+    histThresh = static_cast<float>(3 * CV_PI * CV_PI);
+    nbrOfSmallBins = 10;
+    nbrOfLargeBins = 5;
+}
+HistogramPhaseUnwrapping_Impl::HistogramPhaseUnwrapping_Impl(
+                            const HistogramPhaseUnwrapping::Params &parameters ) : params(parameters)
+{
+
+}
+
+HistogramPhaseUnwrapping_Impl::Pixel::Pixel()
+{
+
+}
+// Constructor
+HistogramPhaseUnwrapping_Impl::Pixel::Pixel( float pV, int id, bool v, float iR, int inc )
+{
+    phaseValue = pV;
+    idx = id;
+    valid = v;
+    inverseReliability = iR;
+    increment = inc;
+    nbrOfPixelsInGroup = 1;
+    groupId = id;
+    singlePixelGroup = true;
+}
+
+float HistogramPhaseUnwrapping_Impl::Pixel::getPhaseValue()
+{
+    return phaseValue;
+}
+
+int HistogramPhaseUnwrapping_Impl::Pixel::getIndex()
+{
+    return idx;
+}
+
+bool HistogramPhaseUnwrapping_Impl::Pixel::getValidity()
+{
+    return valid;
+}
+
+float HistogramPhaseUnwrapping_Impl::Pixel::getInverseReliability()
+{
+    return inverseReliability;
+}
+
+int HistogramPhaseUnwrapping_Impl::Pixel::getIncrement()
+{
+    return increment;
+}
+
+int HistogramPhaseUnwrapping_Impl::Pixel::getNbrOfPixelsInGroup()
+{
+    return nbrOfPixelsInGroup;
+}
+
+int HistogramPhaseUnwrapping_Impl::Pixel::getGroupId()
+{
+    return groupId;
+}
+
+bool HistogramPhaseUnwrapping_Impl::Pixel::getSinglePixelGroup()
+{
+    return singlePixelGroup;
+}
+
+void HistogramPhaseUnwrapping_Impl::Pixel::setIncrement( int inc )
+{
+    increment = inc;
+}
+/* When a pixel of a non-single group is added to an other non-single group, we need to add a new
+increment to the one that was there previously and that was already removing some wraps.
+*/
+void HistogramPhaseUnwrapping_Impl::Pixel::changeIncrement( int inc )
+{
+    increment += inc;
+}
+
+void HistogramPhaseUnwrapping_Impl::Pixel::setNbrOfPixelsInGroup( int nbr )
+{
+    nbrOfPixelsInGroup = nbr;
+}
+void HistogramPhaseUnwrapping_Impl::Pixel::setGroupId( int gId )
+{
+    groupId = gId;
+}
+
+void HistogramPhaseUnwrapping_Impl::Pixel::setSinglePixelGroup( bool s )
+{
+    singlePixelGroup = s;
+}
+
+HistogramPhaseUnwrapping_Impl::Edge::Edge()
+{
+
+}
+// Constructor
+HistogramPhaseUnwrapping_Impl::Edge::Edge( int p1, int p2, int inc )
+{
+    pixOneId = p1;
+    pixTwoId = p2;
+    increment = inc;
+}
+
+int HistogramPhaseUnwrapping_Impl::Edge::getPixOneId()
+{
+    return pixOneId;
+}
+
+int HistogramPhaseUnwrapping_Impl::Edge::getPixTwoId()
+{
+    return pixTwoId;
+}
+
+int HistogramPhaseUnwrapping_Impl::Edge::getIncrement()
+{
+    return increment;
+}
+
+HistogramPhaseUnwrapping_Impl::HistogramBin::HistogramBin()
+{
+
+}
+
+HistogramPhaseUnwrapping_Impl::HistogramBin::HistogramBin( float s, float e )
+{
+    start = s;
+    end = e;
+}
+
+void HistogramPhaseUnwrapping_Impl::HistogramBin::addEdge( Edge e )
+{
+    edges.push_back(e);
+}
+std::vector<HistogramPhaseUnwrapping_Impl::Edge> HistogramPhaseUnwrapping_Impl::HistogramBin::getEdges()
+{
+    return edges;
+}
+HistogramPhaseUnwrapping_Impl::Histogram::Histogram()
+{
+
+}
+/*
+ * create histogram bins. Bins size is not uniform, as in the reference paper
+ *
+ */
+void HistogramPhaseUnwrapping_Impl::Histogram::createBins( float t, int nbrOfBinsBeforeThresh,
+                                                           int nbrOfBinsAfterThresh )
+{
+    thresh = t;
+
+    nbrOfSmallBins = nbrOfBinsBeforeThresh;
+    nbrOfLargeBins = nbrOfBinsAfterThresh;
+    nbrOfBins = nbrOfBinsBeforeThresh + nbrOfBinsAfterThresh;
+
+    smallWidth = thresh / nbrOfSmallBins;
+    largeWidth = static_cast<float>(32 * CV_PI * CV_PI - thresh) / static_cast<float>(nbrOfLargeBins);
+
+    for( int i = 0; i < nbrOfSmallBins; ++i )
+    {
+        addBin(HistogramBin(i * smallWidth, ( i + 1 ) * smallWidth));
+    }
+    for( int i = 0; i < nbrOfLargeBins; ++i )
+    {
+        addBin(HistogramBin(thresh + i * largeWidth, thresh + ( i + 1 ) * largeWidth));
+    }
+}
+// Add a bin b to the histogram
+void HistogramPhaseUnwrapping_Impl::Histogram::addBin( HistogramBin b )
+{
+    bins.push_back(b);
+}
+// Add edge E in bin binIndex
+void HistogramPhaseUnwrapping_Impl::Histogram::addEdgeInBin( Edge e, int binIndex )
+{
+    bins[binIndex].addEdge(e);
+}
+float HistogramPhaseUnwrapping_Impl::Histogram::getThresh()
+{
+    return thresh;
+}
+
+float HistogramPhaseUnwrapping_Impl::Histogram::getSmallWidth()
+{
+    return smallWidth;
+}
+
+float HistogramPhaseUnwrapping_Impl::Histogram::getLargeWidth()
+{
+    return largeWidth;
+}
+
+int HistogramPhaseUnwrapping_Impl::Histogram::getNbrOfBins()
+{
+    return nbrOfBins;
+}
+
+std::vector<HistogramPhaseUnwrapping_Impl::Edge> HistogramPhaseUnwrapping_Impl::
+                                                 Histogram::getEdgesFromBin( int binIndex )
+{
+    std::vector<HistogramPhaseUnwrapping_Impl::Edge> temp;
+    temp = bins[binIndex].getEdges();
+    return temp;
+}
+/* Method in which reliabilities are computed and edges are sorted in the histogram.
+Increments are computed for each pixels.
+ */
+void HistogramPhaseUnwrapping_Impl::unwrapPhaseMap( InputArray wrappedPhaseMap,
+                                                    OutputArray unwrappedPhaseMap,
+                                                    InputArray shadowMask )
+{
+    Mat &wPhaseMap = *(Mat*) wrappedPhaseMap.getObj();
+    Mat mask;
+    int rows = params.height;
+    int cols = params.width;
+    if( shadowMask.empty() )
+    {
+        mask.create(rows, cols, CV_8UC1);
+        mask = Scalar::all(255);
+    }
+    else
+    {
+        Mat &temp = *(Mat*) shadowMask.getObj();
+        temp.copyTo(mask);
+    }
+
+    computePixelsReliability(wPhaseMap, mask);
+    computeEdgesReliabilityAndCreateHistogram();
+
+    unwrapHistogram();
+    addIncrement(unwrappedPhaseMap);
+}
+
+//compute pixels reliabilities according to "A novel algorithm based on histogram processing of reliability for two-dimensional phase unwrapping"
+
+void HistogramPhaseUnwrapping_Impl::computePixelsReliability( InputArray wrappedPhaseMap,
+                                                              InputArray shadowMask )
+{
+    int rows = params.height;
+    int cols = params.width;
+
+    Mat &wPhaseMap = *(Mat*) wrappedPhaseMap.getObj();
+    Mat &mask = *(Mat*) shadowMask.getObj();
+
+    int idx; //idx is used to store pixel position (idx = i*cols + j)
+    bool valid;//tells if a pixel is in the valid mask region
+
+    // H, V, D1, D2 are from the paper
+    float H, V, D1, D2, D;
+    /* used to store neighbours coordinates
+     * ul = upper left, um = upper middle, ur = upper right
+     * ml = middle left, mr = middle right
+     * ll = lower left, lm = lower middle, lr = lower right
+     */
+    Point ul, um, ur, ml, mr, ll, lm, lr;
+
+    for( int i = 0; i < rows; ++i )
+    {
+        for( int j = 0; j < cols; ++j )
+        {
+            if( mask.at<uchar>( i, j ) != 0 ) //if pixel is in a valid region
+            {
+                if( i == 0 || i == rows - 1 || j == 0 || j == cols - 1 )
+                {
+                    idx = i * cols + j;
+                    valid = true;
+                    Pixel p(wPhaseMap.at<float>(i, j), idx, valid,
+                            static_cast<float>(16 * CV_PI * CV_PI), 0);
+                    pixels.push_back(p);
+                }
+                else
+                {
+                    ul = Point(j-1, i-1);
+                    um = Point(j, i-1);
+                    ur = Point(j+1, i-1);
+                    ml = Point(j-1, i);
+                    mr = Point(j+1, i);
+                    ll = Point(j-1, i+1);
+                    lm = Point(j, i+1);
+                    lr = Point(j+1, i+1);
+
+                    Mat neighbourhood = mask( Rect( j-1, i-1, 3, 3 ) );
+                    Scalar meanValue = mean(neighbourhood);
+
+                    /* if mean value is different from 255, it means that one of the neighbouring
+                     * pixel is not valid -> pixel (i,j) is considered as being on the border.
+                     */
+                    if( meanValue[0] != 255 )
+                    {
+                        idx = i * cols + j;
+                        valid = true;
+                        Pixel p(wPhaseMap.at<float>(i, j), idx, valid,
+                                static_cast<float>(16 * CV_PI * CV_PI), 0);
+                        pixels.push_back(p);
+                    }
+                    else
+                    {
+                        H = wrap(wPhaseMap.at<float>(ml.y, ml.x), wPhaseMap.at<float>(i, j))
+                            - wrap(wPhaseMap.at<float>(i, j), wPhaseMap.at<float>(mr.y, mr.x));
+                        V = wrap(wPhaseMap.at<float>(um.y, um.x), wPhaseMap.at<float>(i, j))
+                            - wrap(wPhaseMap.at<float>(i, j), wPhaseMap.at<float>(lm.y, lm.x));
+                        D1 = wrap(wPhaseMap.at<float>(ul.y, ul.x), wPhaseMap.at<float>(i, j))
+                            - wrap(wPhaseMap.at<float>(i, j), wPhaseMap.at<float>(lr.y, lr.x));
+                        D2 = wrap(wPhaseMap.at<float>(ur.y, ur.x), wPhaseMap.at<float>(i, j))
+                            - wrap(wPhaseMap.at<float>(i, j), wPhaseMap.at<float>(ll.y, ll.x));
+                        D = H * H + V * V + D1 * D1 + D2 * D2;
+
+                        idx = i * cols + j;
+                        valid = true;
+                        Pixel p(wPhaseMap.at<float>(i, j), idx, valid, D, 0);
+                        pixels.push_back(p);
+                    }
+                }
+            }
+            else // pixel is not in a valid region. It's inverse reliability is set to the maximum
+            {
+                idx = i * cols + j;
+                valid = false;
+                Pixel p(wPhaseMap.at<float>(i, j), idx, valid,
+                        static_cast<float>(16 * CV_PI * CV_PI), 0);
+                pixels.push_back(p);
+            }
+        }
+    }
+}
+/* Edges are created from the vector of pixels. We loop on the vector and create the edges
+ * that link the current pixel to his right neighbour (first edge) and the one that is under it (second edge)
+ */
+void HistogramPhaseUnwrapping_Impl::computeEdgesReliabilityAndCreateHistogram()
+{
+    int row;
+    int col;
+    histogram.createBins(params.histThresh, params.nbrOfSmallBins, params.nbrOfLargeBins);
+    int nbrOfPixels = static_cast<int>(pixels.size());
+    /* Edges are built by considering a pixel and it's right-neighbour and lower-neighbour.
+     We discard non-valid pixels here.
+     */
+    for( int i = 0; i < nbrOfPixels; ++i )
+    {
+        if( pixels[i].getValidity() )
+        {
+            row = pixels[i].getIndex() / params.width;
+            col = pixels[i].getIndex() % params.width;
+
+            if( row != params.height - 1 && col != params.width -1 )
+            {
+                int idxRight, idxDown;
+                idxRight = row * params.width + col + 1; // Pixel to the right
+                idxDown = ( row + 1 ) * params.width + col; // Pixel under pixel i.
+                createAndSortEdge(i, idxRight);
+                createAndSortEdge(i, idxDown);
+            }
+            else if( row != params.height - 1 && col == params.width - 1 )
+            {
+                int idxDown = ( row + 1 ) * params.width + col;
+                createAndSortEdge(i, idxDown);
+            }
+            else if( row == params.height - 1 && col != params.width - 1 )
+            {
+                int idxRight = row * params.width + col + 1;
+                createAndSortEdge(i, idxRight);
+            }
+        }
+    }
+}
+/*used along the previous method to sort edges in the histogram*/
+void HistogramPhaseUnwrapping_Impl::createAndSortEdge( int idx1, int idx2 )
+{
+    if( pixels[idx2].getValidity() )
+    {
+        float edgeReliability = pixels[idx1].getInverseReliability() +
+                                pixels[idx2].getInverseReliability();
+        int inc = findInc(pixels[idx2].getPhaseValue(), pixels[idx1].getPhaseValue());
+        Edge e(idx1, idx2, inc);
+
+        if( edgeReliability < histogram.getThresh() )
+        {
+            int binIndex = static_cast<int> (ceil(edgeReliability / histogram.getSmallWidth()) - 1);
+            if( binIndex == -1 )
+            {
+                binIndex = 0;
+            }
+            histogram.addEdgeInBin(e, binIndex);
+        }
+        else
+        {
+            int binIndex = params.nbrOfSmallBins +
+                           static_cast<int> (ceil((edgeReliability - histogram.getThresh()) /
+                                 histogram.getLargeWidth()) - 1);
+            histogram.addEdgeInBin(e, binIndex);
+        }
+    }
+}
+
+void HistogramPhaseUnwrapping_Impl::unwrapHistogram()
+{
+    int nbrOfPixels = static_cast<int>(pixels.size());
+    int nbrOfBins = histogram.getNbrOfBins();
+    /* This vector is used to keep track of the number of pixels in each group and avoid useless group.
+       For example, if lastPixelAddedToGroup[10] is equal to 5, it means that pixel "5" was the last one
+       to be added to group 10. So, pixel "5" is the only one that has the correct value for parameter
+       "numberOfPixelsInGroup" in order to avoid a loop on all the pixels to update this number*/
+    std::vector<int> lastPixelAddedToGroup(nbrOfPixels, 0);
+    for( int i = 0; i < nbrOfBins; ++i )
+    {
+        std::vector<Edge> currentEdges = histogram.getEdgesFromBin(i);
+        int nbrOfEdgesInBin = static_cast<int>(currentEdges.size());
+
+        for( int j = 0; j < nbrOfEdgesInBin; ++j )
+        {
+
+            int pOneId = currentEdges[j].getPixOneId();
+            int pTwoId = currentEdges[j].getPixTwoId();
+            // Both pixels are in a single group.
+            if( pixels[pOneId].getSinglePixelGroup() && pixels[pTwoId].getSinglePixelGroup() )
+            {
+                float invRel1 = pixels[pOneId].getInverseReliability();
+                float invRel2 = pixels[pTwoId].getInverseReliability();
+                // Quality of pixel 2 is better than that of pixel 1 -> pixel 1 is added to group 2
+                if( invRel1 > invRel2 )
+                {
+                    int newGroupId = pixels[pTwoId].getGroupId();
+                    int newInc = pixels[pTwoId].getIncrement() + currentEdges[j].getIncrement();
+                    pixels[pOneId].setGroupId(newGroupId);
+                    pixels[pOneId].setIncrement(newInc);
+                    lastPixelAddedToGroup[newGroupId] = pOneId; // Pixel 1 is the last one to be added to group 2
+                }
+                else
+                {
+                    int newGroupId = pixels[pOneId].getGroupId();
+                    int newInc = pixels[pOneId].getIncrement() - currentEdges[j].getIncrement();
+                    pixels[pTwoId].setGroupId(newGroupId);
+                    pixels[pTwoId].setIncrement(newInc);
+                    lastPixelAddedToGroup[newGroupId] = pTwoId;
+                }
+                pixels[pOneId].setNbrOfPixelsInGroup(2);
+                pixels[pTwoId].setNbrOfPixelsInGroup(2);
+                pixels[pOneId].setSinglePixelGroup(false);
+                pixels[pTwoId].setSinglePixelGroup(false);
+            }
+            //p1 is in a single group, p2 is not -> p1 added to p2
+            else if( pixels[pOneId].getSinglePixelGroup() && !pixels[pTwoId].getSinglePixelGroup() )
+            {
+                int newGroupId = pixels[pTwoId].getGroupId();
+                int lastPix = lastPixelAddedToGroup[newGroupId];
+                int newNbrOfPixelsInGroup = pixels[lastPix].getNbrOfPixelsInGroup() + 1;
+                int newInc = pixels[pTwoId].getIncrement() + currentEdges[j].getIncrement();
+
+                pixels[pOneId].setGroupId(newGroupId);
+                pixels[pOneId].setNbrOfPixelsInGroup(newNbrOfPixelsInGroup);
+                pixels[pTwoId].setNbrOfPixelsInGroup(newNbrOfPixelsInGroup);
+                pixels[pOneId].setIncrement(newInc);
+                pixels[pOneId].setSinglePixelGroup(false);
+
+                lastPixelAddedToGroup[newGroupId] = pOneId;
+            }
+            //p2 is in a single group, p1 is not -> p2 added to p1
+            else if( !pixels[pOneId].getSinglePixelGroup() && pixels[pTwoId].getSinglePixelGroup() )
+            {
+                int newGroupId = pixels[pOneId].getGroupId();
+                int lastPix = lastPixelAddedToGroup[newGroupId];
+                int newNbrOfPixelsInGroup = pixels[lastPix].getNbrOfPixelsInGroup() + 1;
+                int newInc = pixels[pOneId].getIncrement() - currentEdges[j].getIncrement();
+
+                pixels[pTwoId].setGroupId(newGroupId);
+                pixels[pTwoId].setNbrOfPixelsInGroup(newNbrOfPixelsInGroup);
+                pixels[pOneId].setNbrOfPixelsInGroup(newNbrOfPixelsInGroup);
+                pixels[pTwoId].setIncrement(newInc);
+                pixels[pTwoId].setSinglePixelGroup(false);
+
+                lastPixelAddedToGroup[newGroupId] = pTwoId;
+            }
+            //p1 and p2 are in two different groups
+            else if( pixels[pOneId].getGroupId() != pixels[pTwoId].getGroupId() )
+            {
+                int pOneGroupId = pixels[pOneId].getGroupId();
+                int pTwoGroupId = pixels[pTwoId].getGroupId();
+
+                float invRel1 = pixels[pOneId].getInverseReliability();
+                float invRel2 = pixels[pTwoId].getInverseReliability();
+
+                int lastAddedToGroupOne = lastPixelAddedToGroup[pOneGroupId];
+                int lastAddedToGroupTwo = lastPixelAddedToGroup[pTwoGroupId];
+
+                int nbrOfPixelsInGroupOne = pixels[lastAddedToGroupOne].getNbrOfPixelsInGroup();
+                int nbrOfPixelsInGroupTwo = pixels[lastAddedToGroupTwo].getNbrOfPixelsInGroup();
+
+                int totalNbrOfPixels = nbrOfPixelsInGroupOne + nbrOfPixelsInGroupTwo;
+
+                if( nbrOfPixelsInGroupOne < nbrOfPixelsInGroupTwo ||
+                   (nbrOfPixelsInGroupOne == nbrOfPixelsInGroupTwo && invRel1 >= invRel2) ) //group p1 added to group p2
+                {
+                    pixels[pTwoId].setNbrOfPixelsInGroup(totalNbrOfPixels);
+                    pixels[pOneId].setNbrOfPixelsInGroup(totalNbrOfPixels);
+                    int inc = pixels[pTwoId].getIncrement() + currentEdges[j].getIncrement() -
+                                 pixels[pOneId].getIncrement();
+                    lastPixelAddedToGroup[pTwoGroupId] = pOneId;
+
+                    for( int k = 0; k < nbrOfPixels; ++k )
+                    {
+                        if( pixels[k].getGroupId() == pOneGroupId )
+                        {
+                            pixels[k].setGroupId(pTwoGroupId);
+                            pixels[k].changeIncrement(inc);
+                        }
+                    }
+                }
+                else if( nbrOfPixelsInGroupOne > nbrOfPixelsInGroupTwo ||
+                        (nbrOfPixelsInGroupOne == nbrOfPixelsInGroupTwo && invRel2 > invRel1) ) //group p2 added to group p1
+                {
+                    int oldGroupId = pTwoGroupId;
+                    pixels[pOneId].setNbrOfPixelsInGroup(totalNbrOfPixels);
+                    pixels[pTwoId].setNbrOfPixelsInGroup(totalNbrOfPixels);
+                    int inc = pixels[pOneId].getIncrement() - currentEdges[j].getIncrement() -
+                              pixels[pTwoId].getIncrement();
+                    lastPixelAddedToGroup[pOneGroupId] = pTwoId;
+
+                    for( int k = 0; k < nbrOfPixels; ++k )
+                    {
+                        if( pixels[k].getGroupId() == oldGroupId )
+                        {
+                            pixels[k].setGroupId(pOneGroupId);
+                            pixels[k].changeIncrement(inc);
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
+void HistogramPhaseUnwrapping_Impl::addIncrement( OutputArray unwrappedPhaseMap )
+{
+    Mat &uPhaseMap = *(Mat*) unwrappedPhaseMap.getObj();
+    int rows = params.height;
+    int cols = params.width;
+    if( uPhaseMap.empty() )
+        uPhaseMap.create(rows, cols, CV_32FC1);
+    int nbrOfPixels = static_cast<int>(pixels.size());
+    for( int i = 0; i < nbrOfPixels; ++i )
+    {
+        int row = pixels[i].getIndex() / params.width;
+        int col = pixels[i].getIndex() % params.width;
+
+        if( pixels[i].getValidity() )
+        {
+            uPhaseMap.at<float>(row, col) = pixels[i].getPhaseValue() +
+                                            static_cast<float>(2 * CV_PI * pixels[i].getIncrement());
+        }
+    }
+}
+float HistogramPhaseUnwrapping_Impl::wrap( float a, float b )
+{
+    float result;
+    float difference = a - b;
+    float pi = static_cast<float>(CV_PI);
+    if( difference > pi )
+        result = ( difference - 2 * pi );
+    else if( difference < -pi )
+        result = ( difference + 2 * pi );
+    else
+        result = difference;
+    return result;
+}
+
+int HistogramPhaseUnwrapping_Impl::findInc( float a, float b )
+{
+    float difference;
+    int wrapValue;
+    difference = b - a;
+    float pi = static_cast<float>(CV_PI);
+    if( difference > pi )
+        wrapValue = -1;
+    else if( difference < -pi )
+        wrapValue = 1;
+    else
+        wrapValue = 0;
+    return wrapValue;
+}
+
+//create a Mat that shows pixel inverse reliabilities
+void HistogramPhaseUnwrapping_Impl::getInverseReliabilityMap( OutputArray inverseReliabilityMap )
+{
+    int rows = params.height;
+    int cols = params.width;
+    Mat &reliabilityMap_ = *(Mat*) inverseReliabilityMap.getObj();
+    if( reliabilityMap_.empty() )
+        reliabilityMap_.create(rows, cols, CV_32FC1);
+    for( int i = 0; i < rows; ++i )
+    {
+        for( int j = 0; j < cols; ++j )
+        {
+            int idx = i * cols + j;
+            reliabilityMap_.at<float>(i, j) = pixels[idx].getInverseReliability();
+        }
+    }
+}
+
+Ptr<HistogramPhaseUnwrapping> HistogramPhaseUnwrapping::create( const HistogramPhaseUnwrapping::Params
+                                                                &params )
+{
+    return makePtr<HistogramPhaseUnwrapping_Impl>(params);
+}
+
+}
+}
\ No newline at end of file
diff --git a/contrib/modules/phase_unwrapping/src/precomp.hpp b/contrib/modules/phase_unwrapping/src/precomp.hpp
new file mode 100644
index 0000000..662e4bf
--- /dev/null
+++ b/contrib/modules/phase_unwrapping/src/precomp.hpp
@@ -0,0 +1,49 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+ //
+ //  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+ //
+ //  By downloading, copying, installing or using the software you agree to this license.
+ //  If you do not agree to this license, do not download, install,
+ //  copy or use the software.
+ //
+ //
+ //                           License Agreement
+ //                For Open Source Computer Vision Library
+ //
+ // Copyright (C) 2015, OpenCV Foundation, all rights reserved.
+ // Third party copyrights are property of their respective owners.
+ //
+ // Redistribution and use in source and binary forms, with or without modification,
+ // are permitted provided that the following conditions are met:
+ //
+ //   * Redistribution's of source code must retain the above copyright notice,
+ //     this list of conditions and the following disclaimer.
+ //
+ //   * Redistribution's in binary form must reproduce the above copyright notice,
+ //     this list of conditions and the following disclaimer in the documentation
+ //     and/or other materials provided with the distribution.
+ //
+ //   * The name of the copyright holders may not be used to endorse or promote products
+ //     derived from this software without specific prior written permission.
+ //
+ // This software is provided by the copyright holders and contributors "as is" and
+ // any express or implied warranties, including, but not limited to, the implied
+ // warranties of merchantability and fitness for a particular purpose are disclaimed.
+ // In no event shall the Intel Corporation or contributors be liable for any direct,
+ // indirect, incidental, special, exemplary, or consequential damages
+ // (including, but not limited to, procurement of substitute goods or services;
+ // loss of use, data, or profits; or business interruption) however caused
+ // and on any theory of liability, whether in contract, strict liability,
+ // or tort (including negligence or otherwise) arising in any way out of
+ // the use of this software, even if advised of the possibility of such damage.
+ //
+ //M*/
+
+#ifndef __OPENCV_PRECOMP_H__
+#define __OPENCV_PRECOMP_H__
+
+#include "opencv2/phase_unwrapping.hpp"
+#include "opencv2/core/utility.hpp"
+#include "opencv2/core/private.hpp"
+
+#endif
\ No newline at end of file
diff --git a/contrib/modules/phase_unwrapping/test/test_main.cpp b/contrib/modules/phase_unwrapping/test/test_main.cpp
new file mode 100644
index 0000000..74b896b
--- /dev/null
+++ b/contrib/modules/phase_unwrapping/test/test_main.cpp
@@ -0,0 +1,3 @@
+#include "test_precomp.hpp"
+
+CV_TEST_MAIN("cv")
\ No newline at end of file
diff --git a/contrib/modules/phase_unwrapping/test/test_precomp.hpp b/contrib/modules/phase_unwrapping/test/test_precomp.hpp
new file mode 100644
index 0000000..6819def
--- /dev/null
+++ b/contrib/modules/phase_unwrapping/test/test_precomp.hpp
@@ -0,0 +1,17 @@
+#ifdef __GNUC__
+#  pragma GCC diagnostic ignored "-Wmissing-declarations"
+#  if defined __clang__ || defined __APPLE__
+#    pragma GCC diagnostic ignored "-Wmissing-prototypes"
+#    pragma GCC diagnostic ignored "-Wextra"
+#  endif
+#endif
+
+#ifndef __OPENCV_TEST_PRECOMP_HPP__
+#define __OPENCV_TEST_PRECOMP_HPP__
+
+#include "opencv2/ts.hpp"
+#include "opencv2/phase_unwrapping.hpp"
+#include <opencv2/rgbd.hpp>
+#include <iostream>
+
+#endif
diff --git a/contrib/modules/phase_unwrapping/test/test_unwrapping.cpp b/contrib/modules/phase_unwrapping/test/test_unwrapping.cpp
new file mode 100644
index 0000000..a18a26f
--- /dev/null
+++ b/contrib/modules/phase_unwrapping/test/test_unwrapping.cpp
@@ -0,0 +1,103 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+ //
+ //  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+ //
+ //  By downloading, copying, installing or using the software you agree to this license.
+ //  If you do not agree to this license, do not download, install,
+ //  copy or use the software.
+ //
+ //
+ //                           License Agreement
+ //                For Open Source Computer Vision Library
+ //
+ // Copyright (C) 2015, OpenCV Foundation, all rights reserved.
+ // Third party copyrights are property of their respective owners.
+ //
+ // Redistribution and use in source and binary forms, with or without modification,
+ // are permitted provided that the following conditions are met:
+ //
+ //   * Redistribution's of source code must retain the above copyright notice,
+ //     this list of conditions and the following disclaimer.
+ //
+ //   * Redistribution's in binary form must reproduce the above copyright notice,
+ //     this list of conditions and the following disclaimer in the documentation
+ //     and/or other materials provided with the distribution.
+ //
+ //   * The name of the copyright holders may not be used to endorse or promote products
+ //     derived from this software without specific prior written permission.
+ //
+ // This software is provided by the copyright holders and contributors "as is" and
+ // any express or implied warranties, including, but not limited to, the implied
+ // warranties of merchantability and fitness for a particular purpose are disclaimed.
+ // In no event shall the Intel Corporation or contributors be liable for any direct,
+ // indirect, incidental, special, exemplary, or consequential damages
+ // (including, but not limited to, procurement of substitute goods or services;
+ // loss of use, data, or profits; or business interruption) however caused
+ // and on any theory of liability, whether in contract, strict liability,
+ // or tort (including negligence or otherwise) arising in any way out of
+ // the use of this software, even if advised of the possibility of such damage.
+ //
+ //M*/
+
+#include "test_precomp.hpp"
+
+using namespace std;
+using namespace cv;
+
+class CV_Unwrapping : public cvtest::BaseTest
+{
+public:
+    CV_Unwrapping();
+    ~CV_Unwrapping();
+protected:
+    void run(int);
+};
+
+CV_Unwrapping::CV_Unwrapping(){}
+
+CV_Unwrapping::~CV_Unwrapping(){}
+
+void CV_Unwrapping::run( int )
+{
+    int rows = 600;
+    int cols = 800;
+    int max = 50;
+
+    Mat ramp(rows, cols, CV_32FC1);
+    Mat wrappedRamp(rows, cols, CV_32FC1);
+    Mat unwrappedRamp;
+    Mat rowValues(1, cols, CV_32FC1);
+    Mat wrappedRowValues(1, cols, CV_32FC1);
+
+    for( int i = 0; i < cols; ++i )
+    {
+        float v = (float)i*(float)max/(float)cols;
+        rowValues.at<float>(0, i) = v;
+        wrappedRowValues.at<float>(0, i) = atan2(sin(v), cos(v));
+    }
+    for( int i = 0; i < rows; ++i )
+    {
+        rowValues.row(0).copyTo(ramp.row(i));
+        wrappedRowValues.row(0).copyTo(wrappedRamp.row(i));
+    }
+
+    phase_unwrapping::HistogramPhaseUnwrapping::Params params;
+    params.width = cols;
+    params.height = rows;
+    Ptr<phase_unwrapping::HistogramPhaseUnwrapping> phaseUnwrapping = phase_unwrapping::HistogramPhaseUnwrapping::create(params);
+    phaseUnwrapping->unwrapPhaseMap(wrappedRamp, unwrappedRamp);
+
+    for(int i = 0; i < rows; ++i )
+    {
+        for( int j = 0; j < cols; ++ j )
+        {
+            EXPECT_NEAR(ramp.at<float>(i, j), unwrappedRamp.at<float>(i, j), 0.001);
+        }
+    }
+}
+
+TEST( HistogramPhaseUnwrapping, unwrapPhaseMap )
+{
+    CV_Unwrapping test;
+    test.safe_run();
+}
\ No newline at end of file
diff --git a/contrib/modules/phase_unwrapping/tutorials/phase_unwrapping.markdown b/contrib/modules/phase_unwrapping/tutorials/phase_unwrapping.markdown
new file mode 100644
index 0000000..9aaf8d9
--- /dev/null
+++ b/contrib/modules/phase_unwrapping/tutorials/phase_unwrapping.markdown
@@ -0,0 +1,10 @@
+Phase Unwrapping tutorial {#tutorial_unwrap_phase_map}
+=======================================================
+
+-	@subpage tutorial_unwrap
+
+	_Compatibility:_ \> OpenCV 3.0.0
+
+	_Author:_ Ambroise Moreau
+
+	You will learn how to use the phase unwrapping module.
diff --git a/contrib/modules/phase_unwrapping/tutorials/unwrap/unwrap.markdown b/contrib/modules/phase_unwrapping/tutorials/unwrap/unwrap.markdown
new file mode 100644
index 0000000..934b0b8
--- /dev/null
+++ b/contrib/modules/phase_unwrapping/tutorials/unwrap/unwrap.markdown
@@ -0,0 +1,68 @@
+Unwrap two-dimensional phase maps {#tutorial_unwrap}
+==============
+
+Goal
+----
+
+In this tutorial, you will learn how to use the phase unwrapping module to unwrap two-dimensional phase maps. The implementation is based on @cite histogramUnwrapping.
+
+Code
+----
+ at include phase_unwrapping/samples/unwrap.cpp
+
+Explanation
+-----------
+
+To use this example, wrapped phase map values should be stored in a yml file as CV_32FC1 Mat, under the name "phaseValues". Path to the data and a name to save the unwrapped phase map must be set in the command line. The results are saved with floating point precision in a yml file and as an 8-bit image for visualization purpose.
+
+Some parameters can be chosen by the user:
+- histThresh is a parameter used to divide the histogram in two parts. Bins before histThresh are smaller than the ones after histThresh. (Default value is 3*pi*pi).
+- nbrOfSmallBins is the number of bins between 0 and histThresh. (Default value is 10).
+- nbrOfLargeBins is the number of bins between histThresh and 32*pi*pi. (Default value is 5).
+
+ at code{.cpp}
+phase_unwrapping::HistogramPhaseUnwrapping::Params params;
+
+    CommandLineParser parser(argc, argv, keys);
+    String inputPath = parser.get<String>(0);
+    String outputUnwrappedName = parser.get<String>(1);
+    String outputWrappedName = parser.get<String>(2);
+
+    if( inputPath.empty() || outputUnwrappedName.empty() )
+    {
+        help();
+        return -1;
+    }
+    FileStorage fsInput(inputPath, FileStorage::READ);
+    FileStorage fsOutput(outputUnwrappedName + ".yml", FileStorage::WRITE);
+
+    Mat wPhaseMap;
+    Mat uPhaseMap;
+    Mat reliabilities;
+    fsInput["phaseValues"] >> wPhaseMap;
+    fsInput.release();
+    params.width = wPhaseMap.cols;
+    params.height = wPhaseMap.rows;
+	Ptr<phase_unwrapping::HistogramPhaseUnwrapping> phaseUnwrapping = phase_unwrapping::HistogramPhaseUnwrapping::create(params);
+ at endcode
+The wrapped phase map is unwrapped and the result is saved in a yml file. We can also get the reliabilities map for visualization purpose. The unwrapped phase map and the reliabilities map are converted to 8-bit images in order to be saved as png files.
+
+ at code{.cpp}
+phaseUnwrapping->unwrapPhaseMap(wPhaseMap, uPhaseMap);
+    fsOutput << "phaseValues" << uPhaseMap;
+    fsOutput.release();
+
+    phaseUnwrapping->getInverseReliabilityMap(reliabilities);
+
+    Mat uPhaseMap8, wPhaseMap8, reliabilities8;
+    wPhaseMap.convertTo(wPhaseMap8, CV_8U, 255, 128);
+    uPhaseMap.convertTo(uPhaseMap8, CV_8U, 1, 128);
+    reliabilities.convertTo(reliabilities8, CV_8U, 255,128);
+
+    imshow("reliabilities", reliabilities);
+    imshow("wrapped phase map", wPhaseMap8);
+    imshow("unwrapped phase map", uPhaseMap8);
+
+    imwrite(outputUnwrappedName + ".png", uPhaseMap8);
+    imwrite("reliabilities.png", reliabilities8);
+ at endcode
diff --git a/contrib/modules/plot/CMakeLists.txt b/contrib/modules/plot/CMakeLists.txt
index 8edf06b..1c879fe 100644
--- a/contrib/modules/plot/CMakeLists.txt
+++ b/contrib/modules/plot/CMakeLists.txt
@@ -1,2 +1,2 @@
 set(the_description "Plot function for Mat data.")
-ocv_define_module(plot opencv_core opencv_highgui)
+ocv_define_module(plot opencv_core opencv_highgui WRAP python)
diff --git a/contrib/modules/plot/include/opencv2/plot.hpp b/contrib/modules/plot/include/opencv2/plot.hpp
index 8243985..6673bd1 100644
--- a/contrib/modules/plot/include/opencv2/plot.hpp
+++ b/contrib/modules/plot/include/opencv2/plot.hpp
@@ -59,6 +59,9 @@ namespace cv
 {
     namespace plot
     {
+    //! @addtogroup plot
+    //! @{
+
         class CV_EXPORTS_W Plot2d : public Algorithm
         {
             public:
@@ -68,17 +71,37 @@ namespace cv
             CV_WRAP virtual void setMaxX(double _plotMaxX) = 0;
             CV_WRAP virtual void setMaxY(double _plotMaxY) = 0;
             CV_WRAP virtual void setPlotLineWidth(int _plotLineWidth) = 0;
+            /**
+             * @brief Switches data visualization mode
+             *
+             * @param _needPlotLine if true then neighbour plot points will be connected by lines.
+             * In other case data will be plotted as a set of standalone points.
+             */
+            CV_WRAP virtual void setNeedPlotLine(bool _needPlotLine) = 0;
             CV_WRAP virtual void setPlotLineColor(Scalar _plotLineColor) = 0;
             CV_WRAP virtual void setPlotBackgroundColor(Scalar _plotBackgroundColor) = 0;
             CV_WRAP virtual void setPlotAxisColor(Scalar _plotAxisColor) = 0;
             CV_WRAP virtual void setPlotGridColor(Scalar _plotGridColor) = 0;
             CV_WRAP virtual void setPlotTextColor(Scalar _plotTextColor) = 0;
             CV_WRAP virtual void setPlotSize(int _plotSizeWidth, int _plotSizeHeight) = 0;
-            CV_WRAP virtual void render(Mat &_plotResult) = 0;
+            CV_WRAP virtual void render(OutputArray _plotResult) = 0;
         };
 
-        CV_EXPORTS_W Ptr<Plot2d> createPlot2d(Mat data);
-        CV_EXPORTS_W Ptr<Plot2d> createPlot2d(Mat dataX, Mat dataY);
+        /**
+         * @brief Creates Plot2d object
+         *
+         * @param data \f$1xN\f$ or \f$Nx1\f$ matrix containing \f$Y\f$ values of points to plot. \f$X\f$ values
+         * will be equal to indexes of correspondind elements in data matrix.
+         */
+        CV_EXPORTS_W Ptr<Plot2d> createPlot2d(InputArray data);
+        /**
+         * @brief Creates Plot2d object
+         *
+         * @param dataX \f$1xN\f$ or \f$Nx1\f$ matrix \f$X\f$ values of points to plot.
+         * @param dataY \f$1xN\f$ or \f$Nx1\f$ matrix containing \f$Y\f$ values of points to plot.
+         */
+        CV_EXPORTS_W Ptr<Plot2d> createPlot2d(InputArray dataX, InputArray dataY);
+    //! @}
     }
 }
 
diff --git a/contrib/modules/plot/src/plot.cpp b/contrib/modules/plot/src/plot.cpp
index 08fc679..60e8549 100644
--- a/contrib/modules/plot/src/plot.cpp
+++ b/contrib/modules/plot/src/plot.cpp
@@ -57,8 +57,9 @@ namespace cv
         {
             public:
 
-            Plot2dImpl(Mat _plotData)
+            Plot2dImpl(InputArray plotData)
             {
+                Mat _plotData = plotData.getMat();
                 //if the matrix is not Nx1 or 1xN
                 if(_plotData.cols > 1 && _plotData.rows > 1)
                 {
@@ -91,8 +92,10 @@ namespace cv
 
             }
 
-            Plot2dImpl(Mat _plotDataX, Mat _plotDataY)
+            Plot2dImpl(InputArray plotDataX_, InputArray plotDataY_)
             {
+                Mat _plotDataX = plotDataX_.getMat();
+                Mat _plotDataY = plotDataY_.getMat();
                 //f the matrix is not Nx1 or 1xN
                 if((_plotDataX.cols > 1 && _plotDataX.rows > 1) || (_plotDataY.cols > 1 && _plotDataY.rows > 1))
                 {
@@ -143,7 +146,11 @@ namespace cv
             }
             void setPlotLineWidth(int _plotLineWidth)
             {
-                plotLineWidth=_plotLineWidth;
+                plotLineWidth = _plotLineWidth;
+            }
+            void setNeedPlotLine(bool _needPlotLine)
+            {
+                needPlotLine = _needPlotLine;
             }
             void setPlotLineColor(Scalar _plotLineColor)
             {
@@ -179,10 +186,12 @@ namespace cv
             }
 
             //render the plotResult to a Mat
-            void render(Mat &_plotResult)
+            void render(OutputArray _plotResult)
             {
                 //create the plot result
-                plotResult = Mat::zeros(plotSizeHeight, plotSizeWidth, CV_8UC3);
+                _plotResult.create(plotSizeHeight, plotSizeWidth, CV_8UC3);
+                plotResult = _plotResult.getMat();
+                plotResult.setTo(plotBackgroundColor);
 
                 int NumVecElements = plotDataX.rows;
 
@@ -199,26 +208,37 @@ namespace cv
                 double CurrentX = plotDataX.at<double>(NumVecElements-1,0);
                 double CurrentY = plotDataY.at<double>(NumVecElements-1,0);
 
-                //Draw the plot by connecting lines between the points
-                Point p1;
-                p1.x = (int)InterpXdata.at<double>(0,0);
-                p1.y = (int)InterpYdata.at<double>(0,0);
-
                 drawAxis(ImageXzero,ImageYzero, CurrentX, CurrentY, plotAxisColor, plotGridColor);
 
-                for (int r=1; r<InterpXdata.rows; r++){
-
-                    Point p2;
-                    p2.x = (int)InterpXdata.at<double>(r,0);
-                    p2.y = (int)InterpYdata.at<double>(r,0);
+                if(needPlotLine)
+                {
+                    //Draw the plot by connecting lines between the points
+                    Point p1;
+                    p1.x = (int)InterpXdata.at<double>(0,0);
+                    p1.y = (int)InterpYdata.at<double>(0,0);
 
-                    line(plotResult, p1, p2, plotLineColor, plotLineWidth, 8, 0);
+                    for (int r=1; r<InterpXdata.rows; r++)
+                    {
+                        Point p2;
+                        p2.x = (int)InterpXdata.at<double>(r,0);
+                        p2.y = (int)InterpYdata.at<double>(r,0);
 
-                    p1 = p2;
+                        line(plotResult, p1, p2, plotLineColor, plotLineWidth, 8, 0);
 
+                        p1 = p2;
+                    }
                 }
+                else
+                {
+                    for (int r=0; r<InterpXdata.rows; r++)
+                    {
+                        Point p;
+                        p.x = (int)InterpXdata.at<double>(r,0);
+                        p.y = (int)InterpYdata.at<double>(r,0);
 
-                _plotResult = plotResult.clone();
+                        circle(plotResult, p, 1, plotLineColor, plotLineWidth, 8, 0);
+                    }
+                }
             }
 
             protected:
@@ -252,6 +272,9 @@ namespace cv
             //the final plot result
             Mat plotResult;
 
+            //flag which enables/disables connection of plotted points by lines
+            bool needPlotLine;
+
             void plotHelper(Mat _plotDataX, Mat _plotDataY)
             {
                 plotDataX=_plotDataX;
@@ -276,6 +299,8 @@ namespace cv
                 double MinY_plusZero;
                 double MaxY_plusZero;
 
+                needPlotLine = true;
+
                 //Obtain the minimum and maximum values of Xdata
                 minMaxLoc(plotDataX,&MinX,&MaxX);
 
@@ -411,13 +436,13 @@ namespace cv
 
         };
 
-        Ptr<Plot2d> createPlot2d(Mat _plotData)
+        Ptr<Plot2d> createPlot2d(InputArray _plotData)
         {
             return Ptr<Plot2dImpl> (new Plot2dImpl (_plotData));
 
         }
 
-        Ptr<Plot2d> createPlot2d(Mat _plotDataX, Mat _plotDataY)
+        Ptr<Plot2d> createPlot2d(InputArray _plotDataX, InputArray _plotDataY)
         {
             return Ptr<Plot2dImpl> (new Plot2dImpl (_plotDataX, _plotDataY));
         }
diff --git a/contrib/modules/rgbd/README.md b/contrib/modules/rgbd/README.md
index 6c2440a..a8e9e7a 100644
--- a/contrib/modules/rgbd/README.md
+++ b/contrib/modules/rgbd/README.md
@@ -1,2 +1,4 @@
  RGB-Depth Processing module
-============================
\ No newline at end of file
+============================
+
+RGB-Depth Processing module -- Linemod 3D object recognition; Fast surface normals and 3D plane finding. 3D visual odometry
diff --git a/contrib/modules/saliency/CMakeLists.txt b/contrib/modules/saliency/CMakeLists.txt
index 31f09f9..1d0d40e 100644
--- a/contrib/modules/saliency/CMakeLists.txt
+++ b/contrib/modules/saliency/CMakeLists.txt
@@ -1,3 +1,10 @@
+if(CV_ICC AND NOT MSVC)
+  ocv_module_disable(saliency)
+endif()
+
 set(the_description "Saliency API")
 set(OPENCV_MODULE_IS_PART_OF_WORLD OFF)
+
 ocv_define_module(saliency opencv_imgproc opencv_highgui opencv_features2d WRAP python)
+
+ocv_warnings_disable(CMAKE_CXX_FLAGS -Woverloaded-virtual)
diff --git a/contrib/modules/saliency/README.md b/contrib/modules/saliency/README.md
index ff8749e..64549ad 100644
--- a/contrib/modules/saliency/README.md
+++ b/contrib/modules/saliency/README.md
@@ -1,5 +1,5 @@
-Saliency API, understanding where humans focus given a scene
-============================================================
+Saliency API, Where to Focus in a Scene
+=======================================
 
-The purpose of this module is to create, group and make available to the users, different saliency algorithms, belonging to different categories.
+The purpose of this module is to create, group and make available to the users, different saliency algorithms, belonging to different categories. Saliency API -- Where humans would look in a scene. Has routines for static, motion and "objectness" saliency.
 
diff --git a/contrib/modules/saliency/doc/saliency.bib b/contrib/modules/saliency/doc/saliency.bib
index 6fd82ea..0aa094b 100644
--- a/contrib/modules/saliency/doc/saliency.bib
+++ b/contrib/modules/saliency/doc/saliency.bib
@@ -22,3 +22,12 @@
   year={2007},
   organization={IEEE}
 }
+
+ at inproceedings{FGS,
+  title={Human Detection Using a Mobile Platform and Novel Features Derived from a Visual Saliency Mechanism},
+  author={Montabone, Sebastian and Soto, Alvaro},
+  booktitle={Image and Vision Computing, Vol. 28 Issue 3},
+  pages={391--402},
+  year={2010},
+  organization={Elsevier}
+}
diff --git a/contrib/modules/saliency/include/opencv2/saliency/saliencyBaseClasses.hpp b/contrib/modules/saliency/include/opencv2/saliency/saliencyBaseClasses.hpp
index 84b4d8f..65f9d07 100644
--- a/contrib/modules/saliency/include/opencv2/saliency/saliencyBaseClasses.hpp
+++ b/contrib/modules/saliency/include/opencv2/saliency/saliencyBaseClasses.hpp
@@ -59,7 +59,7 @@ namespace saliency
 
 /************************************ Saliency Base Class ************************************/
 
-class CV_EXPORTS Saliency : public virtual Algorithm
+class CV_EXPORTS_W Saliency : public virtual Algorithm
 {
  public:
   /**
@@ -78,13 +78,13 @@ class CV_EXPORTS Saliency : public virtual Algorithm
    * \param saliencyMap      The computed saliency map.
    * \return true if the saliency map is computed, false otherwise
    */
-  bool computeSaliency( InputArray image, OutputArray saliencyMap );
+  CV_WRAP bool computeSaliency( InputArray image, OutputArray saliencyMap );
 
   /**
    * \brief Get the name of the specific saliency type
    * \return The name of the tracker initializer
    */
-  String getClassName() const;
+  CV_WRAP String getClassName() const;
 
  protected:
 
@@ -93,7 +93,7 @@ class CV_EXPORTS Saliency : public virtual Algorithm
 };
 
 /************************************ Static Saliency Base Class ************************************/
-class CV_EXPORTS StaticSaliency : public virtual Saliency
+class CV_EXPORTS_W StaticSaliency : public virtual Saliency
 {
  public:
 
@@ -109,17 +109,17 @@ class CV_EXPORTS StaticSaliency : public virtual Saliency
     algorithm calculates the optimal threshold separating those two classes, so that their
     intra-class variance is minimal.
 
-    @param saliencyMap the saliency map obtained through one of the specialized algorithms
-    @param binaryMap the binary map
+    @param _saliencyMap the saliency map obtained through one of the specialized algorithms
+    @param _binaryMap the binary map
      */
-  bool computeBinaryMap( const Mat& saliencyMap, Mat& binaryMap );
+  CV_WRAP bool computeBinaryMap( InputArray _saliencyMap, OutputArray _binaryMap );
  protected:
   virtual bool computeSaliencyImpl( InputArray image, OutputArray saliencyMap )=0;
 
 };
 
 /************************************ Motion Saliency Base Class ************************************/
-class CV_EXPORTS MotionSaliency : public virtual Saliency
+class CV_EXPORTS_W MotionSaliency : public virtual Saliency
 {
 
  protected:
@@ -128,7 +128,7 @@ class CV_EXPORTS MotionSaliency : public virtual Saliency
 };
 
 /************************************ Objectness Base Class ************************************/
-class CV_EXPORTS Objectness : public virtual Saliency
+class CV_EXPORTS_W Objectness : public virtual Saliency
 {
 
  protected:
diff --git a/contrib/modules/saliency/include/opencv2/saliency/saliencySpecializedClasses.hpp b/contrib/modules/saliency/include/opencv2/saliency/saliencySpecializedClasses.hpp
index 6a5f7a3..2088035 100644
--- a/contrib/modules/saliency/include/opencv2/saliency/saliencySpecializedClasses.hpp
+++ b/contrib/modules/saliency/include/opencv2/saliency/saliencySpecializedClasses.hpp
@@ -42,11 +42,11 @@
 #ifndef __OPENCV_SALIENCY_SPECIALIZED_CLASSES_HPP__
 #define __OPENCV_SALIENCY_SPECIALIZED_CLASSES_HPP__
 
-//#include "opencv2/saliency/kyheader.hpp"
 #include <cstdio>
 #include <string>
 #include <iostream>
 #include <stdint.h>
+#include "saliencyBaseClasses.hpp"
 #include "opencv2/core.hpp"
 
 namespace cv
@@ -66,40 +66,95 @@ pre-attentive visual search. The algorithm analyze the log spectrum of each imag
 spectral residual. Then transform the spectral residual to spatial domain to obtain the saliency
 map, which suggests the positions of proto-objects.
  */
-class CV_EXPORTS StaticSaliencySpectralResidual : public StaticSaliency
+class CV_EXPORTS_W StaticSaliencySpectralResidual : public StaticSaliency
 {
 public:
 
   StaticSaliencySpectralResidual();
   virtual ~StaticSaliencySpectralResidual();
 
-  void read( const FileNode& fn );
+  CV_WRAP static Ptr<StaticSaliencySpectralResidual> create()
+  {
+    return makePtr<StaticSaliencySpectralResidual>();
+  }
+
+  CV_WRAP bool computeSaliency( InputArray image, OutputArray saliencyMap )
+  {
+    if( image.empty() )
+      return false;
+
+    return computeSaliencyImpl( image, saliencyMap );
+  }
+
+  CV_WRAP void read( const FileNode& fn );
   void write( FileStorage& fs ) const;
 
-  int getImageWidth() const
+  CV_WRAP int getImageWidth() const
   {
     return resImWidth;
   }
-  inline void setImageWidth(int val)
+  CV_WRAP inline void setImageWidth(int val)
   {
     resImWidth = val;
   }
-  int getImageHeight() const
+  CV_WRAP int getImageHeight() const
   {
     return resImHeight;
   }
-  void setImageHeight(int val)
+  CV_WRAP void setImageHeight(int val)
   {
     resImHeight = val;
   }
 
 protected:
   bool computeSaliencyImpl( InputArray image, OutputArray saliencyMap );
-  int resImWidth;
-  int resImHeight;
+  CV_PROP_RW int resImWidth;
+  CV_PROP_RW int resImHeight;
+
+};
+
+
+/** @brief the Fine Grained Saliency approach from @cite FGS
+
+This method calculates saliency based on center-surround differences.
+High resolution saliency maps are generated in real time by using integral images.
+ */
+class CV_EXPORTS_W StaticSaliencyFineGrained : public StaticSaliency
+{
+public:
+
+  StaticSaliencyFineGrained();
+
+  CV_WRAP static Ptr<StaticSaliencyFineGrained> create()
+  {
+    return makePtr<StaticSaliencyFineGrained>();
+  }
+
+  CV_WRAP bool computeSaliency( InputArray image, OutputArray saliencyMap )
+  {
+    if( image.empty() )
+      return false;
+
+    return computeSaliencyImpl( image, saliencyMap );
+  }
+  virtual ~StaticSaliencyFineGrained();
+
+protected:
+  bool computeSaliencyImpl( InputArray image, OutputArray saliencyMap );
 
+private:
+  void calcIntensityChannel(Mat src, Mat dst);
+  void copyImage(Mat src, Mat dst);
+  void getIntensityScaled(Mat integralImage, Mat gray, Mat saliencyOn, Mat saliencyOff, int neighborhood);
+  float getMean(Mat srcArg, Point2i PixArg, int neighbourhood, int centerVal);
+  void mixScales(Mat *saliencyOn, Mat intensityOn, Mat *saliencyOff, Mat intensityOff, const int numScales);
+  void mixOnOff(Mat intensityOn, Mat intensityOff, Mat intensity);
+  void getIntensity(Mat srcArg, Mat dstArg,  Mat dstOnArg,  Mat dstOffArg, bool generateOnOff);
 };
 
+
+
+
 /************************************ Specific Motion Saliency Specialized Classes ************************************/
 
 /*!
@@ -111,36 +166,49 @@ protected:
  */
 /** @brief the Fast Self-tuning Background Subtraction Algorithm from @cite BinWangApr2014
  */
-class CV_EXPORTS MotionSaliencyBinWangApr2014 : public MotionSaliency
+class CV_EXPORTS_W MotionSaliencyBinWangApr2014 : public MotionSaliency
 {
 public:
   MotionSaliencyBinWangApr2014();
   virtual ~MotionSaliencyBinWangApr2014();
 
+  CV_WRAP static Ptr<MotionSaliencyBinWangApr2014> create()
+  {
+    return makePtr<MotionSaliencyBinWangApr2014>();
+  }
+
+  CV_WRAP bool computeSaliency( InputArray image, OutputArray saliencyMap )
+  {
+    if( image.empty() )
+      return false;
+
+    return computeSaliencyImpl( image, saliencyMap );
+  }
+
   /** @brief This is a utility function that allows to set the correct size (taken from the input image) in the
     corresponding variables that will be used to size the data structures of the algorithm.
     @param W width of input image
     @param H height of input image
   */
-  void setImagesize( int W, int H );
+  CV_WRAP void setImagesize( int W, int H );
   /** @brief This function allows the correct initialization of all data structures that will be used by the
     algorithm.
   */
-  bool init();
+  CV_WRAP bool init();
 
-  int getImageWidth() const
+  CV_WRAP int getImageWidth() const
   {
     return imageWidth;
   }
-  inline void setImageWidth(int val)
+  CV_WRAP inline void setImageWidth(int val)
   {
     imageWidth = val;
   }
-  int getImageHeight() const
+  CV_WRAP int getImageHeight() const
   {
     return imageHeight;
   }
-  void setImageHeight(int val)
+  CV_WRAP void setImageHeight(int val)
   {
     imageHeight = val;
   }
@@ -177,8 +245,8 @@ private:
   //fixed parameter
   bool neighborhoodCheck;
   int N_DS;// Number of template to be downsampled and used in lowResolutionDetection function
-  int imageWidth;// Width of input image
-  int imageHeight;//Height of input image
+  CV_PROP_RW int imageWidth;// Width of input image
+  CV_PROP_RW int imageHeight;//Height of input image
   int K;// Number of background model template
   int N;// NxN is the size of the block for downsampling in the lowlowResolutionDetection
   float alpha;// Learning rate
@@ -200,15 +268,28 @@ private:
 
 /** @brief the Binarized normed gradients algorithm from @cite BING
  */
-class CV_EXPORTS ObjectnessBING : public Objectness
+class CV_EXPORTS_W ObjectnessBING : public Objectness
 {
 public:
 
   ObjectnessBING();
   virtual ~ObjectnessBING();
 
-  void read();
-  void write() const;
+  CV_WRAP static Ptr<ObjectnessBING> create()
+  {
+    return makePtr<ObjectnessBING>();
+  }
+
+  CV_WRAP bool computeSaliency( InputArray image, OutputArray saliencyMap )
+  {
+    if( image.empty() )
+      return false;
+
+    return computeSaliencyImpl( image, saliencyMap );
+  }
+
+  CV_WRAP void read();
+  CV_WRAP void write() const;
 
   /** @brief Return the list of the rectangles' objectness value,
 
@@ -222,7 +303,7 @@ public:
     the trained model.
     @param trainingPath trained model path
      */
-  void setTrainingPath( std::string trainingPath );
+  CV_WRAP void setTrainingPath( const String& trainingPath );
 
   /** @brief This is a utility function that allows to set an arbitrary path in which the algorithm will save the
     optional results
@@ -231,29 +312,29 @@ public:
     each row).
     @param resultsDir results' folder path
      */
-  void setBBResDir( std::string resultsDir );
+  CV_WRAP void setBBResDir( const String& resultsDir );
 
-  double getBase() const
+  CV_WRAP double getBase() const
   {
     return _base;
   }
-  inline void setBase(double val)
+  CV_WRAP inline void setBase(double val)
   {
     _base = val;
   }
-  int getNSS() const
+  CV_WRAP int getNSS() const
   {
     return _NSS;
   }
-  void setNSS(int val)
+  CV_WRAP void setNSS(int val)
   {
     _NSS = val;
   }
-  int getW() const
+  CV_WRAP int getW() const
   {
     return _W;
   }
-  void setW(int val)
+  CV_WRAP void setW(int val)
   {
     _W = val;
   }
diff --git a/contrib/modules/saliency/samples/computeSaliency.cpp b/contrib/modules/saliency/samples/computeSaliency.cpp
index 38b0d9a..58bc9c5 100644
--- a/contrib/modules/saliency/samples/computeSaliency.cpp
+++ b/contrib/modules/saliency/samples/computeSaliency.cpp
@@ -128,6 +128,17 @@ int main( int argc, char** argv )
     }
 
   }
+  else if( saliency_algorithm.find( "FINE_GRAINED" ) == 0 )
+  {
+    Mat saliencyMap;
+    if( saliencyAlgorithm->computeSaliency( image, saliencyMap ) )
+    {
+      imshow( "Saliency Map", saliencyMap );
+      imshow( "Original Image", image );
+      waitKey( 0 );
+    }
+
+  }
   else if( saliency_algorithm.find( "BING" ) == 0 )
   {
     if( training_path.empty() )
diff --git a/contrib/modules/saliency/src/BING/objectnessBING.cpp b/contrib/modules/saliency/src/BING/objectnessBING.cpp
index d6643ba..cd3019b 100644
--- a/contrib/modules/saliency/src/BING/objectnessBING.cpp
+++ b/contrib/modules/saliency/src/BING/objectnessBING.cpp
@@ -85,12 +85,12 @@ void ObjectnessBING::setColorSpace( int clr )
   _bbResDir = _resultsDir + "/" + std::string( format( "BBoxesB%gW%d%s/", _base, _W, _clrName[_Clr] ).c_str() );
 }
 
-void ObjectnessBING::setTrainingPath( std::string trainingPath )
+void ObjectnessBING::setTrainingPath( const String& trainingPath )
 {
   _trainingPath = trainingPath;
 }
 
-void ObjectnessBING::setBBResDir( std::string resultsDir )
+void ObjectnessBING::setBBResDir(const String &resultsDir )
 {
   _resultsDir = resultsDir;
 }
@@ -475,7 +475,7 @@ bool ObjectnessBING::computeSaliencyImpl( InputArray image, OutputArray objectne
   unsigned long int valIdxesSize = (unsigned long int) finalBoxes.getvalIdxes().size();
   objectnessValues.resize( valIdxesSize );
   for ( uint i = 0; i < valIdxesSize; i++ )
-    objectnessValues[i] = finalBoxes.getvalIdxes()[i].first;
+    objectnessValues[finalBoxes.getvalIdxes()[i].second] = finalBoxes.getvalIdxes()[i].first;
 
   return true;
 }
diff --git a/contrib/modules/saliency/src/saliency.cpp b/contrib/modules/saliency/src/saliency.cpp
index 1c74f2c..ca89b06 100644
--- a/contrib/modules/saliency/src/saliency.cpp
+++ b/contrib/modules/saliency/src/saliency.cpp
@@ -55,6 +55,8 @@ Ptr<Saliency> Saliency::create( const String& saliencyType )
 {
     if (saliencyType == "SPECTRAL_RESIDUAL")
         return makePtr<StaticSaliencySpectralResidual>();
+    else if (saliencyType == "FINE_GRAINED")
+        return makePtr<StaticSaliencyFineGrained>();
     else if (saliencyType == "BING")
         return makePtr<ObjectnessBING>();
     else if (saliencyType == "BinWangApr2014")
diff --git a/contrib/modules/saliency/src/staticSaliency.cpp b/contrib/modules/saliency/src/staticSaliency.cpp
index e57c7b9..62c9062 100644
--- a/contrib/modules/saliency/src/staticSaliency.cpp
+++ b/contrib/modules/saliency/src/staticSaliency.cpp
@@ -50,9 +50,9 @@ namespace saliency
  * StaticSaliency
  */
 
-bool StaticSaliency::computeBinaryMap( const Mat& saliencyMap, Mat& BinaryMap )
+bool StaticSaliency::computeBinaryMap( InputArray _saliencyMap, OutputArray _binaryMap )
 {
-
+  Mat saliencyMap = _saliencyMap.getMat();
   Mat labels = Mat::zeros( saliencyMap.rows * saliencyMap.cols, 1, 1 );
   Mat samples = Mat_<float>( saliencyMap.rows * saliencyMap.cols, 1 );
   Mat centers;
@@ -90,6 +90,8 @@ bool StaticSaliency::computeBinaryMap( const Mat& saliencyMap, Mat& BinaryMap )
   outputMat.convertTo( outputMat, CV_8U );
 
   // adaptative thresholding using Otsu's method, to make saliency map binary
+  _binaryMap.createSameSize(outputMat, outputMat.type());
+  Mat BinaryMap = _binaryMap.getMat();
   threshold( outputMat, BinaryMap, 0, 255, THRESH_BINARY | THRESH_OTSU );
 
   return true;
diff --git a/contrib/modules/saliency/src/staticSaliencyFineGrained.cpp b/contrib/modules/saliency/src/staticSaliencyFineGrained.cpp
new file mode 100644
index 0000000..9d8d68e
--- /dev/null
+++ b/contrib/modules/saliency/src/staticSaliencyFineGrained.cpp
@@ -0,0 +1,310 @@
+ /*M///////////////////////////////////////////////////////////////////////////////////////
+ //
+ //  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+ //
+ //  By downloading, copying, installing or using the software you agree to this license.
+ //  If you do not agree to this license, do not download, install,
+ //  copy or use the software.
+ //
+ //
+ //                           License Agreement
+ //                For Open Source Computer Vision Library
+ //
+ // Copyright (C) 2014, OpenCV Foundation, all rights reserved.
+ // Third party copyrights are property of their respective owners.
+ //
+ // Redistribution and use in source and binary forms, with or without modification,
+ // are permitted provided that the following conditions are met:
+ //
+ //   * Redistribution's of source code must retain the above copyright notice,
+ //     this list of conditions and the following disclaimer.
+ //
+ //   * Redistribution's in binary form must reproduce the above copyright notice,
+ //     this list of conditions and the following disclaimer in the documentation
+ //     and/or other materials provided with the distribution.
+ //
+ //   * The name of the copyright holders may not be used to endorse or promote products
+ //     derived from this software without specific prior written permission.
+ //
+ // This software is provided by the copyright holders and contributors "as is" and
+ // any express or implied warranties, including, but not limited to, the implied
+ // warranties of merchantability and fitness for a particular purpose are disclaimed.
+ // In no event shall the Intel Corporation or contributors be liable for any direct,
+ // indirect, incidental, special, exemplary, or consequential damages
+ // (including, but not limited to, procurement of substitute goods or services;
+ // loss of use, data, or profits; or business interruption) however caused
+ // and on any theory of liability, whether in contract, strict liability,
+ // or tort (including negligence or otherwise) arising in any way out of
+ // the use of this software, even if advised of the possibility of such damage.
+ //
+ //M*/
+
+#include "precomp.hpp"
+
+namespace cv
+{
+namespace saliency
+{
+
+/**
+ * Fine Grained Saliency
+ */
+
+
+StaticSaliencyFineGrained::StaticSaliencyFineGrained()
+{
+    className = "FINE_GRAINED";
+}
+
+StaticSaliencyFineGrained::~StaticSaliencyFineGrained()
+{
+
+}
+
+
+bool StaticSaliencyFineGrained::computeSaliencyImpl(InputArray image, OutputArray saliencyMap )
+{
+    Mat dst(Size(image.getMat().cols, image.getMat().rows), CV_8UC1);
+    calcIntensityChannel(image.getMat(), dst);
+    dst.copyTo(saliencyMap);
+
+    #ifdef SALIENCY_DEBUG
+    // visualize saliency map
+    imshow( "Saliency Map Interna", saliencyMap );
+    #endif
+
+    return true;
+}
+
+void StaticSaliencyFineGrained::copyImage(Mat srcArg, Mat dstArg)
+{
+    srcArg.copyTo(dstArg);
+}
+
+void StaticSaliencyFineGrained::calcIntensityChannel(Mat srcArg, Mat dstArg)
+{
+    if(dstArg.channels() > 1)
+    {
+        //("Error: Destiny image must have only one channel.\n");
+        return;
+    }
+    const int numScales = 6;
+    Mat intensityScaledOn[numScales];
+    Mat intensityScaledOff[numScales];
+    Mat gray = Mat::zeros(Size(srcArg.cols, srcArg.rows), CV_8UC1);
+    Mat integralImage(Size(srcArg.cols + 1, srcArg.rows + 1), CV_32FC1);
+    Mat intensity(Size(srcArg.cols, srcArg.rows), CV_8UC1);
+    Mat intensityOn(Size(srcArg.cols, srcArg.rows), CV_8UC1);
+    Mat intensityOff(Size(srcArg.cols, srcArg.rows), CV_8UC1);
+
+    int i;
+    int neighborhood;
+    int neighborhoods[] = {3*4, 3*4*2, 3*4*2*2, 7*4, 7*4*2, 7*4*2*2};
+
+    for(i=0; i<numScales; i++)
+    {
+        intensityScaledOn[i] = Mat(Size(srcArg.cols, srcArg.rows), CV_8UC1);
+        intensityScaledOff[i] = Mat(Size(srcArg.cols, srcArg.rows), CV_8UC1);
+    }
+
+    // Prepare the input image: put it into a grayscale image.
+    if(srcArg.channels()==3)
+    {
+        cvtColor(srcArg, gray, COLOR_BGR2GRAY);
+    }
+    else
+    {
+        srcArg.copyTo(gray);
+    }
+
+    // smooth pixels at least twice, as done by Frintrop and Itti
+    GaussianBlur( gray, gray, Size( 3, 3 ), 0, 0 );
+    GaussianBlur( gray, gray, Size( 3, 3 ), 0, 0 );
+
+
+    // Calculate integral image, only once.
+    integral(gray, integralImage, CV_32F);
+
+
+    for(i=0; i< numScales; i++)
+    {
+        neighborhood = neighborhoods[i] ;
+        getIntensityScaled(integralImage, gray, intensityScaledOn[i], intensityScaledOff[i], neighborhood);
+    }
+
+    mixScales(intensityScaledOn, intensityOn, intensityScaledOff, intensityOff, numScales);
+
+    mixOnOff(intensityOn, intensityOff, intensity);
+
+    intensity.copyTo(dstArg);
+}
+
+void StaticSaliencyFineGrained::getIntensityScaled(Mat integralImage, Mat gray, Mat intensityScaledOn, Mat intensityScaledOff, int neighborhood)
+{
+    float value, meanOn, meanOff;
+    Point2i point;
+    int x,y;
+    intensityScaledOn.setTo(Scalar::all(0));
+    intensityScaledOff.setTo(Scalar::all(0));
+
+
+    for(y = 0; y < gray.rows; y++)
+    {
+        for(x = 0; x < gray.cols; x++)
+        {
+            point.x = x;
+            point.y = y;
+            value = getMean(integralImage, point, neighborhood, gray.at<uchar>(y, x));
+
+            meanOn = gray.at<uchar>(y, x) - value;
+            meanOff = value - gray.at<uchar>(y, x);
+
+            if(meanOn > 0)
+                intensityScaledOn.at<uchar>(y, x) = (uchar)meanOn;
+            else
+                intensityScaledOn.at<uchar>(y, x) = 0;
+
+            if(meanOff > 0)
+                intensityScaledOff.at<uchar>(y, x) = (uchar)meanOff;
+            else
+                intensityScaledOff.at<uchar>(y, x) = 0;
+        }
+    }
+}
+
+float StaticSaliencyFineGrained::getMean(Mat srcArg, Point2i PixArg, int neighbourhood, int centerVal)
+{
+    Point2i P1, P2;
+    float value;
+
+    P1.x = PixArg.x - neighbourhood + 1;
+    P1.y = PixArg.y - neighbourhood + 1;
+    P2.x = PixArg.x + neighbourhood + 1;
+    P2.y = PixArg.y + neighbourhood + 1;
+
+    if(P1.x < 0)
+        P1.x = 0;
+    else if(P1.x > srcArg.cols - 1)
+        P1.x = srcArg.cols - 1;
+    if(P2.x < 0)
+        P2.x = 0;
+    else if(P2.x > srcArg.cols - 1)
+        P2.x = srcArg.cols - 1;
+    if(P1.y < 0)
+        P1.y = 0;
+    else if(P1.y > srcArg.rows - 1)
+        P1.y = srcArg.rows - 1;
+    if(P2.y < 0)
+        P2.y = 0;
+    else if(P2.y > srcArg.rows - 1)
+        P2.y = srcArg.rows - 1;
+
+    // we use the integral image to compute fast features
+    value = (float) (
+            (srcArg.at<float>(P2.y, P2.x)) +
+            (srcArg.at<float>(P1.y, P1.x)) -
+            (srcArg.at<float>(P2.y, P1.x)) -
+            (srcArg.at<float>(P1.y, P2.x))
+    );
+    value = (value - centerVal)/  (( (P2.x - P1.x) * (P2.y - P1.y))-1)  ;
+    return value;
+}
+
+void StaticSaliencyFineGrained::mixScales(Mat *intensityScaledOn, Mat intensityOn, Mat *intensityScaledOff, Mat intensityOff, const int numScales)
+{
+    int i=0, x, y;
+    int width = intensityScaledOn[0].cols;
+    int height = intensityScaledOn[0].rows;
+    short int maxValOn = 0, currValOn=0;
+    short int maxValOff = 0, currValOff=0;
+    int maxValSumOff = 0, maxValSumOn=0;
+    Mat mixedValuesOn(Size(width, height), CV_16UC1);
+    Mat mixedValuesOff(Size(width, height), CV_16UC1);
+
+    mixedValuesOn.setTo(Scalar::all(0));
+    mixedValuesOff.setTo(Scalar::all(0));
+
+    for(i=0;i<numScales;i++)
+    {
+        for(y=0;y<height;y++)
+            for(x=0;x<width;x++)
+            {
+                      currValOn = intensityScaledOn[i].at<uchar>(y, x);
+                      if(currValOn > maxValOn)
+                          maxValOn = currValOn;
+
+                      currValOff = intensityScaledOff[i].at<uchar>(y, x);
+                      if(currValOff > maxValOff)
+                          maxValOff = currValOff;
+
+                      mixedValuesOn.at<unsigned short>(y, x) += currValOn;
+                      mixedValuesOff.at<unsigned short>(y, x) += currValOff;
+            }
+    }
+
+    for(y=0;y<height;y++)
+        for(x=0;x<width;x++)
+        {
+            currValOn = mixedValuesOn.at<unsigned short>(y, x);
+            currValOff = mixedValuesOff.at<unsigned short>(y, x);
+                  if(currValOff > maxValSumOff)
+                      maxValSumOff = currValOff;
+                  if(currValOn > maxValSumOn)
+                      maxValSumOn = currValOn;
+        }
+
+
+    for(y=0;y<height;y++)
+        for(x=0;x<width;x++)
+        {
+            intensityOn.at<uchar>(y, x) = (uchar)(255.*((float)(mixedValuesOn.at<unsigned short>(y, x) / (float)maxValSumOn)));
+            intensityOff.at<uchar>(y, x) = (uchar)(255.*((float)(mixedValuesOff.at<unsigned short>(y, x) / (float)maxValSumOff)));
+        }
+
+}
+
+void StaticSaliencyFineGrained::mixOnOff(Mat intensityOn, Mat intensityOff, Mat intensityArg)
+{
+    int x,y;
+    int width = intensityOn.cols;
+    int height= intensityOn.rows;
+    int maxVal=0;
+
+    int currValOn, currValOff, maxValSumOff, maxValSumOn;
+
+    Mat intensity(Size(width, height), CV_8UC1);
+
+
+    maxValSumOff = 0;
+    maxValSumOn = 0;
+
+    for(y=0;y<height;y++)
+    for(x=0;x<width;x++)
+    {
+        currValOn = intensityOn.at<uchar>(y, x);
+        currValOff = intensityOff.at<uchar>(y, x);
+              if(currValOff > maxValSumOff)
+                  maxValSumOff = currValOff;
+              if(currValOn > maxValSumOn)
+                  maxValSumOn = currValOn;
+    }
+
+    if(maxValSumOn > maxValSumOff)
+        maxVal = maxValSumOn;
+    else
+        maxVal = maxValSumOff;
+
+
+
+    for(y=0;y<height;y++)
+        for(x=0;x<width;x++)
+        {
+            intensity.at<uchar>(y, x) = (uchar) (255. * (float) (intensityOn.at<uchar>(y, x) + intensityOff.at<uchar>(y, x)) / (float)maxVal);
+        }
+
+    intensity.copyTo(intensityArg);
+}
+
+
+} /* namespace saliency */
+}/* namespace cv */
diff --git a/contrib/modules/sfm/CMakeLists.txt b/contrib/modules/sfm/CMakeLists.txt
index d466af6..83f0e4d 100644
--- a/contrib/modules/sfm/CMakeLists.txt
+++ b/contrib/modules/sfm/CMakeLists.txt
@@ -3,27 +3,24 @@ set(the_description "SFM algorithms")
 
 ### LIBMV LIGHT EXTERNAL DEPENDENCIES ###
 
+find_package(Gflags QUIET)
 find_package(Ceres QUIET)
-
-if(NOT DEFINED GFLAGS_LIBRARIES)
-  set(GFLAGS_LIBRARIES "gflags")
-endif()
-
-if(NOT DEFINED GLOG_LIBRARIES)
-  set(GLOG_LIBRARIES "glog")
+if(NOT Ceres_FOUND)  # Looks like Ceres find glog on the own, so separate search isn't necessary
+  find_package(Glog QUIET)
 endif()
 
-if(NOT DEFINED SFM_DEPS_OK)
-
+if((gflags_FOUND OR GFLAGS_FOUND) AND (glog_FOUND OR GLOG_FOUND))
   set(_fname "${CMAKE_CURRENT_BINARY_DIR}/test_sfm_deps.cpp")
   file(WRITE "${_fname}" "#include <glog/logging.h>\n#include <gflags/gflags.h>\nint main() { (void)(0); return 0; }\n")
-  try_compile(SFM_DEPS_OK "${CMAKE_CURRENT_BINARY_DIR}" "${_fname}"
+  try_compile(SFM_DEPS_OK "${CMAKE_BINARY_DIR}" "${_fname}"
       CMAKE_FLAGS "-DINCLUDE_DIRECTORIES:STRING=${GLOG_INCLUDE_DIRS};${GFLAGS_INCLUDE_DIRS}"
       LINK_LIBRARIES ${GLOG_LIBRARIES} ${GFLAGS_LIBRARIES}
       OUTPUT_VARIABLE OUTPUT
   )
   file(REMOVE "${_fname}")
   message(STATUS "Checking SFM deps... ${SFM_DEPS_OK}")
+else()
+  set(SFM_DEPS_OK FALSE)
 endif()
 
 if(NOT HAVE_EIGEN OR NOT SFM_DEPS_OK)
@@ -59,6 +56,7 @@ set(LIBMV_LIGHT_LIBS
 if(Ceres_FOUND)
   add_definitions("-DCERES_FOUND=1")
   list(APPEND LIBMV_LIGHT_LIBS simple_pipeline)
+  list(APPEND LIBMV_LIGHT_INCLUDES "${CERES_INCLUDE_DIR}")
 else()
   add_definitions("-DCERES_FOUND=0")
   message(STATUS "CERES support is disabled. Ceres Solver for reconstruction API is required.")
diff --git a/contrib/modules/sfm/README.md b/contrib/modules/sfm/README.md
index 57f34ff..83a860b 100644
--- a/contrib/modules/sfm/README.md
+++ b/contrib/modules/sfm/README.md
@@ -7,7 +7,7 @@ This module contains algorithms to perform 3d reconstruction from 2d images. The
 Dependencies
 ------------
 
-Before compiling, take a look at the following details in order to give a proper use of the Struncture from Motion module. **Advice:** The module is only available for Linux/GNU systems.
+Before compiling, take a look at the following details in order to give a proper use of the Structure from Motion module. **Advice:** The module is only available for Linux/GNU systems.
 
 In addition, it depends on some open source libraries:
 
diff --git a/contrib/modules/sfm/cmake/FindGflags.cmake b/contrib/modules/sfm/cmake/FindGflags.cmake
new file mode 100644
index 0000000..aaaf43f
--- /dev/null
+++ b/contrib/modules/sfm/cmake/FindGflags.cmake
@@ -0,0 +1,582 @@
+# Ceres Solver - A fast non-linear least squares minimizer
+# Copyright 2015 Google Inc. All rights reserved.
+# http://ceres-solver.org/
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice,
+#   this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice,
+#   this list of conditions and the following disclaimer in the documentation
+#   and/or other materials provided with the distribution.
+# * Neither the name of Google Inc. nor the names of its contributors may be
+#   used to endorse or promote products derived from this software without
+#   specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+# Author: alexs.mac at gmail.com (Alex Stewart)
+#
+
+# FindGflags.cmake - Find Google gflags logging library.
+#
+# This module will attempt to find gflags, either via an exported CMake
+# configuration (generated by gflags >= 2.1 which are built with CMake), or
+# by performing a standard search for all gflags components.  The order of
+# precedence for these two methods of finding gflags is controlled by:
+# GFLAGS_PREFER_EXPORTED_GFLAGS_CMAKE_CONFIGURATION.
+#
+# This module defines the following variables:
+#
+# GFLAGS_FOUND: TRUE iff gflags is found.
+# GFLAGS_INCLUDE_DIRS: Include directories for gflags.
+# GFLAGS_LIBRARIES: Libraries required to link gflags.
+# GFLAGS_NAMESPACE: The namespace in which gflags is defined.  In versions of
+#                   gflags < 2.1, this was google, for versions >= 2.1 it is
+#                   by default gflags, although can be configured when building
+#                   gflags to be something else (i.e. google for legacy
+#                   compatibility).
+#
+# The following variables control the behaviour of this module when an exported
+# gflags CMake configuration is not found.
+#
+# GFLAGS_PREFER_EXPORTED_GFLAGS_CMAKE_CONFIGURATION: TRUE/FALSE, iff TRUE then
+#                           then prefer using an exported CMake configuration
+#                           generated by gflags >= 2.1 over searching for the
+#                           gflags components manually.  Otherwise (FALSE)
+#                           ignore any exported gflags CMake configurations and
+#                           always perform a manual search for the components.
+#                           Default: TRUE iff user does not define this variable
+#                           before we are called, and does NOT specify either
+#                           GFLAGS_INCLUDE_DIR_HINTS or GFLAGS_LIBRARY_DIR_HINTS
+#                           otherwise FALSE.
+# GFLAGS_INCLUDE_DIR_HINTS: List of additional directories in which to
+#                           search for gflags includes, e.g: /timbuktu/include.
+# GFLAGS_LIBRARY_DIR_HINTS: List of additional directories in which to
+#                           search for gflags libraries, e.g: /timbuktu/lib.
+#
+# The following variables are also defined by this module, but in line with
+# CMake recommended FindPackage() module style should NOT be referenced directly
+# by callers (use the plural variables detailed above instead).  These variables
+# do however affect the behaviour of the module via FIND_[PATH/LIBRARY]() which
+# are NOT re-called (i.e. search for library is not repeated) if these variables
+# are set with valid values _in the CMake cache_. This means that if these
+# variables are set directly in the cache, either by the user in the CMake GUI,
+# or by the user passing -DVAR=VALUE directives to CMake when called (which
+# explicitly defines a cache variable), then they will be used verbatim,
+# bypassing the HINTS variables and other hard-coded search locations.
+#
+# GFLAGS_INCLUDE_DIR: Include directory for gflags, not including the
+#                     include directory of any dependencies.
+# GFLAGS_LIBRARY: gflags library, not including the libraries of any
+#                 dependencies.
+
+# Reset CALLERS_CMAKE_FIND_LIBRARY_PREFIXES to its value when FindGflags was
+# invoked, necessary for MSVC.
+macro(GFLAGS_RESET_FIND_LIBRARY_PREFIX)
+  if (MSVC)
+    set(CMAKE_FIND_LIBRARY_PREFIXES "${CALLERS_CMAKE_FIND_LIBRARY_PREFIXES}")
+  endif (MSVC)
+endmacro(GFLAGS_RESET_FIND_LIBRARY_PREFIX)
+
+# Called if we failed to find gflags or any of it's required dependencies,
+# unsets all public (designed to be used externally) variables and reports
+# error message at priority depending upon [REQUIRED/QUIET/<NONE>] argument.
+macro(GFLAGS_REPORT_NOT_FOUND REASON_MSG)
+  unset(GFLAGS_FOUND)
+  unset(GFLAGS_INCLUDE_DIRS)
+  unset(GFLAGS_LIBRARIES)
+  # Do not use unset, as we want to keep GFLAGS_NAMESPACE in the cache,
+  # but simply clear its value.
+  set(GFLAGS_NAMESPACE "" CACHE STRING
+    "gflags namespace (google or gflags)" FORCE)
+
+  # Make results of search visible in the CMake GUI if gflags has not
+  # been found so that user does not have to toggle to advanced view.
+  mark_as_advanced(CLEAR GFLAGS_INCLUDE_DIR
+                         GFLAGS_LIBRARY
+                         GFLAGS_NAMESPACE)
+
+  gflags_reset_find_library_prefix()
+
+  # Note <package>_FIND_[REQUIRED/QUIETLY] variables defined by FindPackage()
+  # use the camelcase library name, not uppercase.
+  if (Gflags_FIND_QUIETLY)
+    message(STATUS "Failed to find gflags - " ${REASON_MSG} ${ARGN})
+  elseif (Gflags_FIND_REQUIRED)
+    message(FATAL_ERROR "Failed to find gflags - " ${REASON_MSG} ${ARGN})
+  else()
+    # Neither QUIETLY nor REQUIRED, use no priority which emits a message
+    # but continues configuration and allows generation.
+    message("-- Failed to find gflags - " ${REASON_MSG} ${ARGN})
+  endif ()
+  return()
+endmacro(GFLAGS_REPORT_NOT_FOUND)
+
+# Verify that all variable names passed as arguments are defined (can be empty
+# but must be defined) or raise a fatal error.
+macro(GFLAGS_CHECK_VARS_DEFINED)
+  foreach(CHECK_VAR ${ARGN})
+    if (NOT DEFINED ${CHECK_VAR})
+      message(FATAL_ERROR "Ceres Bug: ${CHECK_VAR} is not defined.")
+    endif()
+  endforeach()
+endmacro(GFLAGS_CHECK_VARS_DEFINED)
+
+# Use check_cxx_source_compiles() to compile trivial test programs to determine
+# the gflags namespace.  This works on all OSs except Windows.  If using Visual
+# Studio, it fails because msbuild forces check_cxx_source_compiles() to use
+# CMAKE_BUILD_TYPE=Debug for the test project, which usually breaks detection
+# because MSVC requires that the test project use the same build type as gflags,
+# which would normally be built in Release.
+#
+# Defines: GFLAGS_NAMESPACE in the caller's scope with the detected namespace,
+#          which is blank (empty string, will test FALSE is CMake conditionals)
+#          if detection failed.
+function(GFLAGS_CHECK_GFLAGS_NAMESPACE_USING_TRY_COMPILE)
+  # Verify that all required variables are defined.
+  gflags_check_vars_defined(
+    GFLAGS_INCLUDE_DIR GFLAGS_LIBRARY)
+  # Ensure that GFLAGS_NAMESPACE is always unset on completion unless
+  # we explicitly set if after having the correct namespace.
+  set(GFLAGS_NAMESPACE "" PARENT_SCOPE)
+
+  include(CheckCXXSourceCompiles)
+  # Setup include path & link library for gflags for CHECK_CXX_SOURCE_COMPILES.
+  set(CMAKE_REQUIRED_INCLUDES ${GFLAGS_INCLUDE_DIR})
+  set(CMAKE_REQUIRED_LIBRARIES ${GFLAGS_LIBRARY} ${GFLAGS_LINK_LIBRARIES})
+  # First try the (older) google namespace.  Note that the output variable
+  # MUST be unique to the build type as otherwise the test is not repeated as
+  # it is assumed to have already been performed.
+  check_cxx_source_compiles(
+    "#include <gflags/gflags.h>
+     int main(int argc, char * argv[]) {
+       google::ParseCommandLineFlags(&argc, &argv, true);
+       return 0;
+     }"
+     GFLAGS_IN_GOOGLE_NAMESPACE)
+  if (GFLAGS_IN_GOOGLE_NAMESPACE)
+    set(GFLAGS_NAMESPACE google PARENT_SCOPE)
+    return()
+  endif()
+
+  # Try (newer) gflags namespace instead.  Note that the output variable
+  # MUST be unique to the build type as otherwise the test is not repeated as
+  # it is assumed to have already been performed.
+  set(CMAKE_REQUIRED_INCLUDES ${GFLAGS_INCLUDE_DIR})
+  set(CMAKE_REQUIRED_LIBRARIES ${GFLAGS_LIBRARY} ${GFLAGS_LINK_LIBRARIES})
+  check_cxx_source_compiles(
+    "#include <gflags/gflags.h>
+     int main(int argc, char * argv[]) {
+        gflags::ParseCommandLineFlags(&argc, &argv, true);
+        return 0;
+     }"
+     GFLAGS_IN_GFLAGS_NAMESPACE)
+  if (GFLAGS_IN_GFLAGS_NAMESPACE)
+    set(GFLAGS_NAMESPACE gflags PARENT_SCOPE)
+    return()
+  endif (GFLAGS_IN_GFLAGS_NAMESPACE)
+endfunction(GFLAGS_CHECK_GFLAGS_NAMESPACE_USING_TRY_COMPILE)
+
+# Use regex on the gflags headers to attempt to determine the gflags namespace.
+# Checks both gflags.h (contained namespace on versions < 2.1.2) and
+# gflags_declare.h, which contains the namespace on versions >= 2.1.2.
+# In general, this method should only be used when
+# GFLAGS_CHECK_GFLAGS_NAMESPACE_USING_TRY_COMPILE() cannot be used, or has
+# failed.
+#
+# Defines: GFLAGS_NAMESPACE in the caller's scope with the detected namespace,
+#          which is blank (empty string, will test FALSE is CMake conditionals)
+#          if detection failed.
+function(GFLAGS_CHECK_GFLAGS_NAMESPACE_USING_REGEX)
+  # Verify that all required variables are defined.
+  gflags_check_vars_defined(GFLAGS_INCLUDE_DIR)
+  # Ensure that GFLAGS_NAMESPACE is always undefined on completion unless
+  # we explicitly set if after having the correct namespace.
+  set(GFLAGS_NAMESPACE "" PARENT_SCOPE)
+
+  # Scan gflags.h to identify what namespace gflags was built with.  On
+  # versions of gflags < 2.1.2, gflags.h was configured with the namespace
+  # directly, on >= 2.1.2, gflags.h uses the GFLAGS_NAMESPACE #define which
+  # is defined in gflags_declare.h, we try each location in turn.
+  set(GFLAGS_HEADER_FILE ${GFLAGS_INCLUDE_DIR}/gflags/gflags.h)
+  if (NOT EXISTS ${GFLAGS_HEADER_FILE})
+    gflags_report_not_found(
+      "Could not find file: ${GFLAGS_HEADER_FILE} "
+      "containing namespace information in gflags install located at: "
+      "${GFLAGS_INCLUDE_DIR}.")
+  endif()
+  file(READ ${GFLAGS_HEADER_FILE} GFLAGS_HEADER_FILE_CONTENTS)
+
+  string(REGEX MATCH "namespace [A-Za-z]+"
+    GFLAGS_NAMESPACE "${GFLAGS_HEADER_FILE_CONTENTS}")
+  string(REGEX REPLACE "namespace ([A-Za-z]+)" "\\1"
+    GFLAGS_NAMESPACE "${GFLAGS_NAMESPACE}")
+
+  if (NOT GFLAGS_NAMESPACE)
+    gflags_report_not_found(
+      "Failed to extract gflags namespace from header file: "
+      "${GFLAGS_HEADER_FILE}.")
+  endif (NOT GFLAGS_NAMESPACE)
+
+  if (GFLAGS_NAMESPACE STREQUAL "google" OR
+      GFLAGS_NAMESPACE STREQUAL "gflags")
+    # Found valid gflags namespace from gflags.h.
+    set(GFLAGS_NAMESPACE "${GFLAGS_NAMESPACE}" PARENT_SCOPE)
+    return()
+  endif()
+
+  # Failed to find gflags namespace from gflags.h, gflags is likely a new
+  # version, check gflags_declare.h, which in newer versions (>= 2.1.2) contains
+  # the GFLAGS_NAMESPACE #define, which is then referenced in gflags.h.
+  set(GFLAGS_DECLARE_FILE ${GFLAGS_INCLUDE_DIR}/gflags/gflags_declare.h)
+  if (NOT EXISTS ${GFLAGS_DECLARE_FILE})
+    gflags_report_not_found(
+      "Could not find file: ${GFLAGS_DECLARE_FILE} "
+      "containing namespace information in gflags install located at: "
+      "${GFLAGS_INCLUDE_DIR}.")
+  endif()
+  file(READ ${GFLAGS_DECLARE_FILE} GFLAGS_DECLARE_FILE_CONTENTS)
+
+  string(REGEX MATCH "#define GFLAGS_NAMESPACE [A-Za-z]+"
+    GFLAGS_NAMESPACE "${GFLAGS_DECLARE_FILE_CONTENTS}")
+  string(REGEX REPLACE "#define GFLAGS_NAMESPACE ([A-Za-z]+)" "\\1"
+    GFLAGS_NAMESPACE "${GFLAGS_NAMESPACE}")
+
+  if (NOT GFLAGS_NAMESPACE)
+    gflags_report_not_found(
+      "Failed to extract gflags namespace from declare file: "
+      "${GFLAGS_DECLARE_FILE}.")
+  endif (NOT GFLAGS_NAMESPACE)
+
+  if (GFLAGS_NAMESPACE STREQUAL "google" OR
+      GFLAGS_NAMESPACE STREQUAL "gflags")
+    # Found valid gflags namespace from gflags.h.
+    set(GFLAGS_NAMESPACE "${GFLAGS_NAMESPACE}" PARENT_SCOPE)
+    return()
+  endif()
+endfunction(GFLAGS_CHECK_GFLAGS_NAMESPACE_USING_REGEX)
+
+# -----------------------------------------------------------------
+# By default, if the user has expressed no preference for using an exported
+# gflags CMake configuration over performing a search for the installed
+# components, and has not specified any hints for the search locations, then
+# prefer a gflags exported configuration if available.
+if (NOT DEFINED GFLAGS_PREFER_EXPORTED_GFLAGS_CMAKE_CONFIGURATION
+    AND NOT GFLAGS_INCLUDE_DIR_HINTS
+    AND NOT GFLAGS_LIBRARY_DIR_HINTS)
+  message(STATUS "No preference for use of exported gflags CMake configuration "
+    "set, and no hints for include/library directories provided. "
+    "Defaulting to preferring an installed/exported gflags CMake configuration "
+    "if available.")
+  set(GFLAGS_PREFER_EXPORTED_GFLAGS_CMAKE_CONFIGURATION TRUE)
+endif()
+
+if (GFLAGS_PREFER_EXPORTED_GFLAGS_CMAKE_CONFIGURATION)
+  # Try to find an exported CMake configuration for gflags, as generated by
+  # gflags versions >= 2.1.
+  #
+  # We search twice, s/t we can invert the ordering of precedence used by
+  # find_package() for exported package build directories, and installed
+  # packages (found via CMAKE_SYSTEM_PREFIX_PATH), listed as items 6) and 7)
+  # respectively in [1].
+  #
+  # By default, exported build directories are (in theory) detected first, and
+  # this is usually the case on Windows.  However, on OS X & Linux, the install
+  # path (/usr/local) is typically present in the PATH environment variable
+  # which is checked in item 4) in [1] (i.e. before both of the above, unless
+  # NO_SYSTEM_ENVIRONMENT_PATH is passed).  As such on those OSs installed
+  # packages are usually detected in preference to exported package build
+  # directories.
+  #
+  # To ensure a more consistent response across all OSs, and as users usually
+  # want to prefer an installed version of a package over a locally built one
+  # where both exist (esp. as the exported build directory might be removed
+  # after installation), we first search with NO_CMAKE_PACKAGE_REGISTRY which
+  # means any build directories exported by the user are ignored, and thus
+  # installed directories are preferred.  If this fails to find the package
+  # we then research again, but without NO_CMAKE_PACKAGE_REGISTRY, so any
+  # exported build directories will now be detected.
+  #
+  # To prevent confusion on Windows, we also pass NO_CMAKE_BUILDS_PATH (which
+  # is item 5) in [1]), to not preferentially use projects that were built
+  # recently with the CMake GUI to ensure that we always prefer an installed
+  # version if available.
+  #
+  # [1] http://www.cmake.org/cmake/help/v2.8.11/cmake.html#command:find_package
+  find_package(gflags QUIET
+                      NO_MODULE
+                      NO_CMAKE_PACKAGE_REGISTRY
+                      NO_CMAKE_BUILDS_PATH)
+  if (gflags_FOUND)
+    message(STATUS "Found installed version of gflags: ${gflags_DIR}")
+  else(gflags_FOUND)
+    # Failed to find an installed version of gflags, repeat search allowing
+    # exported build directories.
+    message(STATUS "Failed to find installed gflags CMake configuration, "
+      "searching for gflags build directories exported with CMake.")
+    # Again pass NO_CMAKE_BUILDS_PATH, as we know that gflags is exported and
+    # do not want to treat projects built with the CMake GUI preferentially.
+    find_package(gflags QUIET
+                        NO_MODULE
+                        NO_CMAKE_BUILDS_PATH)
+    if (gflags_FOUND)
+      message(STATUS "Found exported gflags build directory: ${gflags_DIR}")
+    endif(gflags_FOUND)
+  endif(gflags_FOUND)
+
+  set(FOUND_INSTALLED_GFLAGS_CMAKE_CONFIGURATION ${gflags_FOUND})
+
+  # gflags v2.1 - 2.1.2 shipped with a bug in their gflags-config.cmake [1]
+  # whereby gflags_LIBRARIES = "gflags", but there was no imported target
+  # called "gflags", they were called: gflags[_nothreads]-[static/shared].
+  # As this causes linker errors when gflags is not installed in a location
+  # on the current library paths, detect if this problem is present and
+  # fix it.
+  #
+  # [1] https://github.com/gflags/gflags/issues/110
+  if (gflags_FOUND)
+    # NOTE: This is not written as additional conditions in the outer
+    #       if (gflags_FOUND) as the NOT TARGET "${gflags_LIBRARIES}"
+    #       condition causes problems if gflags is not found.
+    if (${gflags_VERSION} VERSION_LESS 2.1.3 AND
+        NOT TARGET "${gflags_LIBRARIES}")
+      message(STATUS "Detected broken gflags install in: ${gflags_DIR}, "
+        "version: ${gflags_VERSION} <= 2.1.2 which defines gflags_LIBRARIES = "
+        "${gflags_LIBRARIES} which is not an imported CMake target, see: "
+        "https://github.com/gflags/gflags/issues/110.  Attempting to fix by "
+        "detecting correct gflags target.")
+      # Ordering here expresses preference for detection, specifically we do not
+      # want to use the _nothreads variants if the full library is available.
+      list(APPEND CHECK_GFLAGS_IMPORTED_TARGET_NAMES
+        gflags-shared gflags-static
+        gflags_nothreads-shared gflags_nothreads-static)
+      foreach(CHECK_GFLAGS_TARGET ${CHECK_GFLAGS_IMPORTED_TARGET_NAMES})
+        if (TARGET ${CHECK_GFLAGS_TARGET})
+          message(STATUS "Found valid gflags target: ${CHECK_GFLAGS_TARGET}, "
+            "updating gflags_LIBRARIES.")
+          set(gflags_LIBRARIES ${CHECK_GFLAGS_TARGET})
+          break()
+        endif()
+      endforeach()
+      if (NOT TARGET ${gflags_LIBRARIES})
+        message(STATUS "Failed to fix detected broken gflags install in: "
+          "${gflags_DIR}, version: ${gflags_VERSION} <= 2.1.2, none of the "
+          "imported targets for gflags: ${CHECK_GFLAGS_IMPORTED_TARGET_NAMES} "
+          "are defined.  Will continue with a manual search for gflags "
+          "components.  We recommend you build/install a version of gflags > "
+          "2.1.2 (or master).")
+        set(FOUND_INSTALLED_GFLAGS_CMAKE_CONFIGURATION FALSE)
+      endif()
+    endif()
+  endif()
+
+  if (FOUND_INSTALLED_GFLAGS_CMAKE_CONFIGURATION)
+    message(STATUS "Detected gflags version: ${gflags_VERSION}")
+    #set(GFLAGS_FOUND ${gflags_FOUND})
+    #set(GFLAGS_INCLUDE_DIR ${gflags_INCLUDE_DIR})
+    #set(GFLAGS_LIBRARY ${gflags_LIBRARIES})
+
+    # gflags does not export the namespace in their CMake configuration, so
+    # use our function to determine what it should be, as it can be either
+    # gflags or google dependent upon version & configuration.
+    #
+    # NOTE: We use the regex method to determine the namespace here, as
+    #       check_cxx_source_compiles() will not use imported targets, which
+    #       is what gflags will be in this case.
+    gflags_check_gflags_namespace_using_regex()
+
+    if (NOT GFLAGS_NAMESPACE)
+      gflags_report_not_found(
+        "Failed to determine gflags namespace using regex for gflags "
+        "version: ${gflags_VERSION} exported here: ${gflags_DIR} using CMake.")
+    endif (NOT GFLAGS_NAMESPACE)
+  else (FOUND_INSTALLED_GFLAGS_CMAKE_CONFIGURATION)
+    message(STATUS "Failed to find an installed/exported CMake configuration "
+      "for gflags, will perform search for installed gflags components.")
+  endif (FOUND_INSTALLED_GFLAGS_CMAKE_CONFIGURATION)
+endif(GFLAGS_PREFER_EXPORTED_GFLAGS_CMAKE_CONFIGURATION)
+
+if (NOT GFLAGS_FOUND)
+  # Either failed to find an exported gflags CMake configuration, or user
+  # told us not to use one.  Perform a manual search for all gflags components.
+
+  # Handle possible presence of lib prefix for libraries on MSVC, see
+  # also GFLAGS_RESET_FIND_LIBRARY_PREFIX().
+  if (MSVC)
+    # Preserve the caller's original values for CMAKE_FIND_LIBRARY_PREFIXES
+    # s/t we can set it back before returning.
+    set(CALLERS_CMAKE_FIND_LIBRARY_PREFIXES "${CMAKE_FIND_LIBRARY_PREFIXES}")
+    # The empty string in this list is important, it represents the case when
+    # the libraries have no prefix (shared libraries / DLLs).
+    set(CMAKE_FIND_LIBRARY_PREFIXES "lib" "" "${CMAKE_FIND_LIBRARY_PREFIXES}")
+  endif (MSVC)
+
+  # Search user-installed locations first, so that we prefer user installs
+  # to system installs where both exist.
+  list(APPEND GFLAGS_CHECK_INCLUDE_DIRS
+    /usr/local/include
+    /usr/local/homebrew/include # Mac OS X
+    /opt/local/var/macports/software # Mac OS X.
+    /opt/local/include
+    /usr/include)
+  list(APPEND GFLAGS_CHECK_PATH_SUFFIXES
+    gflags/include # Windows (for C:/Program Files prefix).
+    gflags/Include ) # Windows (for C:/Program Files prefix).
+
+  list(APPEND GFLAGS_CHECK_LIBRARY_DIRS
+    /usr/local/lib
+    /usr/local/homebrew/lib # Mac OS X.
+    /opt/local/lib
+    /usr/lib)
+  list(APPEND GFLAGS_CHECK_LIBRARY_SUFFIXES
+    gflags/lib # Windows (for C:/Program Files prefix).
+    gflags/Lib ) # Windows (for C:/Program Files prefix).
+
+  # Search supplied hint directories first if supplied.
+  find_path(GFLAGS_INCLUDE_DIR
+    NAMES gflags/gflags.h
+    PATHS ${GFLAGS_INCLUDE_DIR_HINTS}
+    ${GFLAGS_CHECK_INCLUDE_DIRS}
+    PATH_SUFFIXES ${GFLAGS_CHECK_PATH_SUFFIXES})
+  if (NOT GFLAGS_INCLUDE_DIR OR
+      NOT EXISTS ${GFLAGS_INCLUDE_DIR})
+    gflags_report_not_found(
+      "Could not find gflags include directory, set GFLAGS_INCLUDE_DIR "
+      "to directory containing gflags/gflags.h")
+  endif (NOT GFLAGS_INCLUDE_DIR OR
+    NOT EXISTS ${GFLAGS_INCLUDE_DIR})
+
+  find_library(GFLAGS_LIBRARY NAMES gflags
+    PATHS ${GFLAGS_LIBRARY_DIR_HINTS}
+    ${GFLAGS_CHECK_LIBRARY_DIRS}
+    PATH_SUFFIXES ${GFLAGS_CHECK_LIBRARY_SUFFIXES})
+  if (NOT GFLAGS_LIBRARY OR
+      NOT EXISTS ${GFLAGS_LIBRARY})
+    gflags_report_not_found(
+      "Could not find gflags library, set GFLAGS_LIBRARY "
+      "to full path to libgflags.")
+  endif (NOT GFLAGS_LIBRARY OR
+    NOT EXISTS ${GFLAGS_LIBRARY})
+
+  # gflags typically requires a threading library (which is OS dependent), note
+  # that this defines the CMAKE_THREAD_LIBS_INIT variable.  If we are able to
+  # detect threads, we assume that gflags requires it.
+  find_package(Threads QUIET)
+  set(GFLAGS_LINK_LIBRARIES ${CMAKE_THREAD_LIBS_INIT})
+  # On Windows (including MinGW), the Shlwapi library is used by gflags if
+  # available.
+  if (WIN32)
+    include(CheckIncludeFileCXX)
+    check_include_file_cxx("shlwapi.h" HAVE_SHLWAPI)
+    if (HAVE_SHLWAPI)
+      list(APPEND GFLAGS_LINK_LIBRARIES shlwapi.lib)
+    endif(HAVE_SHLWAPI)
+  endif (WIN32)
+
+  # Mark internally as found, then verify. GFLAGS_REPORT_NOT_FOUND() unsets
+  # if called.
+  set(GFLAGS_FOUND TRUE)
+
+  # Identify what namespace gflags was built with.
+  if (GFLAGS_INCLUDE_DIR AND NOT GFLAGS_NAMESPACE)
+    # To handle Windows peculiarities / CMake bugs on MSVC we try two approaches
+    # to detect the gflags namespace:
+    #
+    # 1) Try to use check_cxx_source_compiles() to compile a trivial program
+    #    with the two choices for the gflags namespace.
+    #
+    # 2) [In the event 1) fails] Use regex on the gflags headers to try to
+    #    determine the gflags namespace.  Whilst this is less robust than 1),
+    #    it does avoid any interaction with msbuild.
+    gflags_check_gflags_namespace_using_try_compile()
+
+    if (NOT GFLAGS_NAMESPACE)
+      # Failed to determine gflags namespace using check_cxx_source_compiles()
+      # method, try and obtain it using regex on the gflags headers instead.
+      message(STATUS "Failed to find gflags namespace using using "
+        "check_cxx_source_compiles(), trying namespace regex instead, "
+        "this is expected on Windows.")
+      gflags_check_gflags_namespace_using_regex()
+
+      if (NOT GFLAGS_NAMESPACE)
+        gflags_report_not_found(
+          "Failed to determine gflags namespace either by "
+          "check_cxx_source_compiles(), or namespace regex.")
+      endif (NOT GFLAGS_NAMESPACE)
+    endif (NOT GFLAGS_NAMESPACE)
+  endif (GFLAGS_INCLUDE_DIR AND NOT GFLAGS_NAMESPACE)
+
+  # Make the GFLAGS_NAMESPACE a cache variable s/t the user can view it, and could
+  # overwrite it in the CMake GUI.
+  set(GFLAGS_NAMESPACE "${GFLAGS_NAMESPACE}" CACHE STRING
+    "gflags namespace (google or gflags)" FORCE)
+
+  # gflags does not seem to provide any record of the version in its
+  # source tree, thus cannot extract version.
+
+  # Catch case when caller has set GFLAGS_NAMESPACE in the cache / GUI
+  # with an invalid value.
+  if (GFLAGS_NAMESPACE AND
+      NOT GFLAGS_NAMESPACE STREQUAL "google" AND
+      NOT GFLAGS_NAMESPACE STREQUAL "gflags")
+    gflags_report_not_found(
+      "Caller defined GFLAGS_NAMESPACE:"
+      " ${GFLAGS_NAMESPACE} is not valid, not google or gflags.")
+  endif ()
+  # Catch case when caller has set GFLAGS_INCLUDE_DIR in the cache / GUI and
+  # thus FIND_[PATH/LIBRARY] are not called, but specified locations are
+  # invalid, otherwise we would report the library as found.
+  if (GFLAGS_INCLUDE_DIR AND
+      NOT EXISTS ${GFLAGS_INCLUDE_DIR}/gflags/gflags.h)
+    gflags_report_not_found(
+      "Caller defined GFLAGS_INCLUDE_DIR:"
+      " ${GFLAGS_INCLUDE_DIR} does not contain gflags/gflags.h header.")
+  endif (GFLAGS_INCLUDE_DIR AND
+    NOT EXISTS ${GFLAGS_INCLUDE_DIR}/gflags/gflags.h)
+  # TODO: This regex for gflags library is pretty primitive, we use lowercase
+  #       for comparison to handle Windows using CamelCase library names, could
+  #       this check be better?
+  string(TOLOWER "${GFLAGS_LIBRARY}" LOWERCASE_GFLAGS_LIBRARY)
+  if (GFLAGS_LIBRARY AND
+      NOT "${LOWERCASE_GFLAGS_LIBRARY}" MATCHES ".*gflags[^/]*")
+    gflags_report_not_found(
+      "Caller defined GFLAGS_LIBRARY: "
+      "${GFLAGS_LIBRARY} does not match gflags.")
+  endif (GFLAGS_LIBRARY AND
+    NOT "${LOWERCASE_GFLAGS_LIBRARY}" MATCHES ".*gflags[^/]*")
+
+  gflags_reset_find_library_prefix()
+
+endif(NOT GFLAGS_FOUND)
+
+# Set standard CMake FindPackage variables if found.
+if (GFLAGS_FOUND)
+  set(GFLAGS_INCLUDE_DIRS ${GFLAGS_INCLUDE_DIR})
+  set(GFLAGS_LIBRARIES ${GFLAGS_LIBRARY} ${GFLAGS_LINK_LIBRARIES})
+endif (GFLAGS_FOUND)
+
+# Handle REQUIRED / QUIET optional arguments.
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(Gflags DEFAULT_MSG
+  GFLAGS_INCLUDE_DIRS GFLAGS_LIBRARIES GFLAGS_NAMESPACE)
+
+# Only mark internal variables as advanced if we found gflags, otherwise
+# leave them visible in the standard GUI for the user to set manually.
+if (GFLAGS_FOUND)
+  mark_as_advanced(FORCE GFLAGS_INCLUDE_DIR
+    GFLAGS_LIBRARY
+    GFLAGS_NAMESPACE
+    gflags_DIR) # Autogenerated by find_package(gflags)
+endif (GFLAGS_FOUND)
diff --git a/contrib/modules/sfm/cmake/FindGlog.cmake b/contrib/modules/sfm/cmake/FindGlog.cmake
new file mode 100644
index 0000000..3057b31
--- /dev/null
+++ b/contrib/modules/sfm/cmake/FindGlog.cmake
@@ -0,0 +1,210 @@
+# Ceres Solver - A fast non-linear least squares minimizer
+# Copyright 2015 Google Inc. All rights reserved.
+# http://ceres-solver.org/
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice,
+#   this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice,
+#   this list of conditions and the following disclaimer in the documentation
+#   and/or other materials provided with the distribution.
+# * Neither the name of Google Inc. nor the names of its contributors may be
+#   used to endorse or promote products derived from this software without
+#   specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+# Author: alexs.mac at gmail.com (Alex Stewart)
+#
+
+# FindGlog.cmake - Find Google glog logging library.
+#
+# This module defines the following variables:
+#
+# GLOG_FOUND: TRUE iff glog is found.
+# GLOG_INCLUDE_DIRS: Include directories for glog.
+# GLOG_LIBRARIES: Libraries required to link glog.
+#
+# The following variables control the behaviour of this module:
+#
+# GLOG_INCLUDE_DIR_HINTS: List of additional directories in which to
+#                         search for glog includes, e.g: /timbuktu/include.
+# GLOG_LIBRARY_DIR_HINTS: List of additional directories in which to
+#                         search for glog libraries, e.g: /timbuktu/lib.
+#
+# The following variables are also defined by this module, but in line with
+# CMake recommended FindPackage() module style should NOT be referenced directly
+# by callers (use the plural variables detailed above instead).  These variables
+# do however affect the behaviour of the module via FIND_[PATH/LIBRARY]() which
+# are NOT re-called (i.e. search for library is not repeated) if these variables
+# are set with valid values _in the CMake cache_. This means that if these
+# variables are set directly in the cache, either by the user in the CMake GUI,
+# or by the user passing -DVAR=VALUE directives to CMake when called (which
+# explicitly defines a cache variable), then they will be used verbatim,
+# bypassing the HINTS variables and other hard-coded search locations.
+#
+# GLOG_INCLUDE_DIR: Include directory for glog, not including the
+#                   include directory of any dependencies.
+# GLOG_LIBRARY: glog library, not including the libraries of any
+#               dependencies.
+
+# Reset CALLERS_CMAKE_FIND_LIBRARY_PREFIXES to its value when
+# FindGlog was invoked.
+macro(GLOG_RESET_FIND_LIBRARY_PREFIX)
+  if (MSVC)
+    set(CMAKE_FIND_LIBRARY_PREFIXES "${CALLERS_CMAKE_FIND_LIBRARY_PREFIXES}")
+  endif (MSVC)
+endmacro(GLOG_RESET_FIND_LIBRARY_PREFIX)
+
+# Called if we failed to find glog or any of it's required dependencies,
+# unsets all public (designed to be used externally) variables and reports
+# error message at priority depending upon [REQUIRED/QUIET/<NONE>] argument.
+macro(GLOG_REPORT_NOT_FOUND REASON_MSG)
+  unset(GLOG_FOUND)
+  unset(GLOG_INCLUDE_DIRS)
+  unset(GLOG_LIBRARIES)
+  # Make results of search visible in the CMake GUI if glog has not
+  # been found so that user does not have to toggle to advanced view.
+  mark_as_advanced(CLEAR GLOG_INCLUDE_DIR
+                         GLOG_LIBRARY)
+
+  glog_reset_find_library_prefix()
+
+  # Note <package>_FIND_[REQUIRED/QUIETLY] variables defined by FindPackage()
+  # use the camelcase library name, not uppercase.
+  if (Glog_FIND_QUIETLY)
+    message(STATUS "Failed to find glog - " ${REASON_MSG} ${ARGN})
+  elseif (Glog_FIND_REQUIRED)
+    message(FATAL_ERROR "Failed to find glog - " ${REASON_MSG} ${ARGN})
+  else()
+    # Neither QUIETLY nor REQUIRED, use no priority which emits a message
+    # but continues configuration and allows generation.
+    message("-- Failed to find glog - " ${REASON_MSG} ${ARGN})
+  endif ()
+  return()
+endmacro(GLOG_REPORT_NOT_FOUND)
+
+# Handle possible presence of lib prefix for libraries on MSVC, see
+# also GLOG_RESET_FIND_LIBRARY_PREFIX().
+if (MSVC)
+  # Preserve the caller's original values for CMAKE_FIND_LIBRARY_PREFIXES
+  # s/t we can set it back before returning.
+  set(CALLERS_CMAKE_FIND_LIBRARY_PREFIXES "${CMAKE_FIND_LIBRARY_PREFIXES}")
+  # The empty string in this list is important, it represents the case when
+  # the libraries have no prefix (shared libraries / DLLs).
+  set(CMAKE_FIND_LIBRARY_PREFIXES "lib" "" "${CMAKE_FIND_LIBRARY_PREFIXES}")
+endif (MSVC)
+
+# Search user-installed locations first, so that we prefer user installs
+# to system installs where both exist.
+list(APPEND GLOG_CHECK_INCLUDE_DIRS
+  /usr/local/include
+  /usr/local/homebrew/include # Mac OS X
+  /opt/local/var/macports/software # Mac OS X.
+  /opt/local/include
+  /usr/include)
+# Windows (for C:/Program Files prefix).
+list(APPEND GLOG_CHECK_PATH_SUFFIXES
+  glog/include
+  glog/Include
+  Glog/include
+  Glog/Include)
+
+list(APPEND GLOG_CHECK_LIBRARY_DIRS
+  /usr/local/lib
+  /usr/local/homebrew/lib # Mac OS X.
+  /opt/local/lib
+  /usr/lib)
+# Windows (for C:/Program Files prefix).
+list(APPEND GLOG_CHECK_LIBRARY_SUFFIXES
+  glog/lib
+  glog/Lib
+  Glog/lib
+  Glog/Lib)
+
+# Search supplied hint directories first if supplied.
+find_path(GLOG_INCLUDE_DIR
+  NAMES glog/logging.h
+  PATHS ${GLOG_INCLUDE_DIR_HINTS}
+  ${GLOG_CHECK_INCLUDE_DIRS}
+  PATH_SUFFIXES ${GLOG_CHECK_PATH_SUFFIXES})
+if (NOT GLOG_INCLUDE_DIR OR
+    NOT EXISTS ${GLOG_INCLUDE_DIR})
+  glog_report_not_found(
+    "Could not find glog include directory, set GLOG_INCLUDE_DIR "
+    "to directory containing glog/logging.h")
+endif (NOT GLOG_INCLUDE_DIR OR
+       NOT EXISTS ${GLOG_INCLUDE_DIR})
+
+find_library(GLOG_LIBRARY NAMES glog
+  PATHS ${GLOG_LIBRARY_DIR_HINTS}
+  ${GLOG_CHECK_LIBRARY_DIRS}
+  PATH_SUFFIXES ${GLOG_CHECK_LIBRARY_SUFFIXES})
+if (NOT GLOG_LIBRARY OR
+    NOT EXISTS ${GLOG_LIBRARY})
+  glog_report_not_found(
+    "Could not find glog library, set GLOG_LIBRARY "
+    "to full path to libglog.")
+endif (NOT GLOG_LIBRARY OR
+       NOT EXISTS ${GLOG_LIBRARY})
+
+# Mark internally as found, then verify. GLOG_REPORT_NOT_FOUND() unsets
+# if called.
+set(GLOG_FOUND TRUE)
+
+# Glog does not seem to provide any record of the version in its
+# source tree, thus cannot extract version.
+
+# Catch case when caller has set GLOG_INCLUDE_DIR in the cache / GUI and
+# thus FIND_[PATH/LIBRARY] are not called, but specified locations are
+# invalid, otherwise we would report the library as found.
+if (GLOG_INCLUDE_DIR AND
+    NOT EXISTS ${GLOG_INCLUDE_DIR}/glog/logging.h)
+  glog_report_not_found(
+    "Caller defined GLOG_INCLUDE_DIR:"
+    " ${GLOG_INCLUDE_DIR} does not contain glog/logging.h header.")
+endif (GLOG_INCLUDE_DIR AND
+       NOT EXISTS ${GLOG_INCLUDE_DIR}/glog/logging.h)
+# TODO: This regex for glog library is pretty primitive, we use lowercase
+#       for comparison to handle Windows using CamelCase library names, could
+#       this check be better?
+string(TOLOWER "${GLOG_LIBRARY}" LOWERCASE_GLOG_LIBRARY)
+if (GLOG_LIBRARY AND
+    NOT "${LOWERCASE_GLOG_LIBRARY}" MATCHES ".*glog[^/]*")
+  glog_report_not_found(
+    "Caller defined GLOG_LIBRARY: "
+    "${GLOG_LIBRARY} does not match glog.")
+endif (GLOG_LIBRARY AND
+       NOT "${LOWERCASE_GLOG_LIBRARY}" MATCHES ".*glog[^/]*")
+
+# Set standard CMake FindPackage variables if found.
+if (GLOG_FOUND)
+  set(GLOG_INCLUDE_DIRS ${GLOG_INCLUDE_DIR})
+  set(GLOG_LIBRARIES ${GLOG_LIBRARY})
+endif (GLOG_FOUND)
+
+glog_reset_find_library_prefix()
+
+# Handle REQUIRED / QUIET optional arguments.
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(Glog DEFAULT_MSG
+  GLOG_INCLUDE_DIRS GLOG_LIBRARIES)
+
+# Only mark internal variables as advanced if we found glog, otherwise
+# leave them visible in the standard GUI for the user to set manually.
+if (GLOG_FOUND)
+  mark_as_advanced(FORCE GLOG_INCLUDE_DIR
+                         GLOG_LIBRARY)
+endif (GLOG_FOUND)
diff --git a/contrib/modules/sfm/doc/pics/import_sagrada_familia.png b/contrib/modules/sfm/doc/pics/import_sagrada_familia.png
new file mode 100644
index 0000000..0566119
Binary files /dev/null and b/contrib/modules/sfm/doc/pics/import_sagrada_familia.png differ
diff --git a/contrib/modules/sfm/include/opencv2/sfm.hpp b/contrib/modules/sfm/include/opencv2/sfm.hpp
index f6e24cd..25a3b10 100644
--- a/contrib/modules/sfm/include/opencv2/sfm.hpp
+++ b/contrib/modules/sfm/include/opencv2/sfm.hpp
@@ -38,6 +38,7 @@
 
 #include <opencv2/sfm/conditioning.hpp>
 #include <opencv2/sfm/fundamental.hpp>
+#include <opencv2/sfm/io.hpp>
 #include <opencv2/sfm/numeric.hpp>
 #include <opencv2/sfm/projection.hpp>
 #include <opencv2/sfm/triangulation.hpp>
@@ -77,6 +78,7 @@ This module has been originally developed as a project for Google Summer of Code
   @{
     @defgroup conditioning Conditioning
     @defgroup fundamental Fundamental
+    @defgroup io Input/Output
     @defgroup numeric Numeric
     @defgroup projection Projection
     @defgroup robust Robust Estimation
diff --git a/contrib/modules/sfm/include/opencv2/sfm/io.hpp b/contrib/modules/sfm/include/opencv2/sfm/io.hpp
new file mode 100644
index 0000000..dc01a25
--- /dev/null
+++ b/contrib/modules/sfm/include/opencv2/sfm/io.hpp
@@ -0,0 +1,88 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+ //
+ //  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+ //
+ //  By downloading, copying, installing or using the software you agree to this license.
+ //  If you do not agree to this license, do not download, install,
+ //  copy or use the software.
+ //
+ //
+ //                           License Agreement
+ //                For Open Source Computer Vision Library
+ //
+ // Copyright (C) 2015, OpenCV Foundation, all rights reserved.
+ // Third party copyrights are property of their respective owners.
+ //
+ // Redistribution and use in source and binary forms, with or without modification,
+ // are permitted provided that the following conditions are met:
+ //
+ //   * Redistribution's of source code must retain the above copyright notice,
+ //     this list of conditions and the following disclaimer.
+ //
+ //   * Redistribution's in binary form must reproduce the above copyright notice,
+ //     this list of conditions and the following disclaimer in the documentation
+ //     and/or other materials provided with the distribution.
+ //
+ //   * The name of the copyright holders may not be used to endorse or promote products
+ //     derived from this software without specific prior written permission.
+ //
+ // This software is provided by the copyright holders and contributors "as is" and
+ // any express or implied warranties, including, but not limited to, the implied
+ // warranties of merchantability and fitness for a particular purpose are disclaimed.
+ // In no event shall the Intel Corporation or contributors be liable for any direct,
+ // indirect, incidental, special, exemplary, or consequential damages
+ // (including, but not limited to, procurement of substitute goods or services;
+ // loss of use, data, or profits; or business interruption) however caused
+ // and on any theory of liability, whether in contract, strict liability,
+ // or tort (including negligence or otherwise) arising in any way out of
+ // the use of this software, even if advised of the possibility of such damage.
+ //
+ //M*/
+
+#ifndef __OPENCV_SFM_IO_HPP__
+#define __OPENCV_SFM_IO_HPP__
+
+#include <opencv2/core.hpp>
+
+namespace cv
+{
+namespace sfm
+{
+
+//! @addtogroup io
+//! @{
+
+/** @brief Different supported file formats.
+ */
+enum {
+  SFM_IO_BUNDLER = 0,
+  SFM_IO_VISUALSFM = 1,
+  SFM_IO_OPENSFM = 2,
+  SFM_IO_OPENMVG = 3,
+  SFM_IO_THEIASFM = 4
+};
+
+/** @brief Import a reconstruction file.
+  @param file The path to the file.
+  @param Rs Output vector of 3x3 rotations of the camera
+  @param Ts Output vector of 3x1 translations of the camera.
+  @param Ks Output vector of 3x3 instrinsics of the camera.
+  @param points3d Output array with 3d points. Is 3 x N.
+  @param file_format The format of the file to import.
+
+  The function supports reconstructions from Bundler.
+*/
+CV_EXPORTS_W
+void
+importReconstruction(const cv::String &file, OutputArrayOfArrays Rs,
+                     OutputArrayOfArrays Ts, OutputArrayOfArrays Ks,
+                     OutputArray points3d, int file_format = SFM_IO_BUNDLER);
+
+//! @} sfm
+
+} /* namespace sfm */
+} /* namespace cv */
+
+#endif
+
+/* End of file. */
diff --git a/contrib/modules/sfm/samples/import_reconstruction.cpp b/contrib/modules/sfm/samples/import_reconstruction.cpp
new file mode 100644
index 0000000..4c31e4e
--- /dev/null
+++ b/contrib/modules/sfm/samples/import_reconstruction.cpp
@@ -0,0 +1,80 @@
+#include <opencv2/sfm.hpp>
+#include <opencv2/viz.hpp>
+
+#include <iostream>
+
+using namespace std;
+using namespace cv;
+using namespace cv::sfm;
+
+static void help() {
+  cout
+      << "\n---------------------------------------------------------------------------\n"
+      << " This program shows how to import a reconstructed scene in the \n"
+      << " OpenCV Structure From Motion (SFM) module.\n"
+      << " Usage:\n"
+      << "        example_sfm_import_reconstruction <path_to_file>\n"
+      << " where: file_path is the absolute path file into your system which contains\n"
+      << "        the reconstructed scene. \n"
+      << "---------------------------------------------------------------------------\n\n"
+      << endl;
+}
+
+
+int main(int argc, char* argv[])
+{
+  /// Read input parameters
+
+  if ( argc != 2 ) {
+    help();
+    exit(0);
+  }
+
+  /// Immport a reconstructed scene
+
+  vector<Mat> Rs, Ts, Ks, points3d;
+  importReconstruction(argv[1], Rs, Ts, Ks, points3d, SFM_IO_BUNDLER);
+
+
+  /// Create 3D windows
+
+  viz::Viz3d window("Coordinate Frame");
+             window.setWindowSize(Size(500,500));
+             window.setWindowPosition(Point(150,150));
+             window.setBackgroundColor(); // black by default
+
+
+  /// Create the pointcloud
+
+  vector<Vec3d> point_cloud;
+  for (int i = 0; i < points3d.size(); ++i){
+    point_cloud.push_back(Vec3f(points3d[i]));
+  }
+
+
+  /// Recovering cameras
+
+  vector<Affine3d> path;
+  for (size_t i = 0; i < Rs.size(); ++i)
+    path.push_back(Affine3d(Rs[i], Ts[i]));
+
+
+  /// Create and show widgets
+
+  viz::WCloud cloud_widget(point_cloud, viz::Color::green());
+  viz::WTrajectory trajectory(path, viz::WTrajectory::FRAMES, 0.5);
+  viz::WTrajectoryFrustums frustums(path, Vec2f(0.889484, 0.523599), 0.5,
+                                    viz::Color::yellow());
+
+  window.showWidget("point_cloud", cloud_widget);
+  window.showWidget("cameras", trajectory);
+  window.showWidget("frustums", frustums);
+
+
+  /// Wait for key 'q' to close the window
+  cout << endl << "Press 'q' to close each windows ... " << endl;
+
+  window.spin();
+
+  return 0;
+}
\ No newline at end of file
diff --git a/contrib/modules/sfm/src/io.cpp b/contrib/modules/sfm/src/io.cpp
new file mode 100644
index 0000000..8e4255b
--- /dev/null
+++ b/contrib/modules/sfm/src/io.cpp
@@ -0,0 +1,92 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+ //
+ //  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+ //
+ //  By downloading, copying, installing or using the software you agree to this license.
+ //  If you do not agree to this license, do not download, install,
+ //  copy or use the software.
+ //
+ //
+ //                           License Agreement
+ //                For Open Source Computer Vision Library
+ //
+ // Copyright (C) 2015, OpenCV Foundation, all rights reserved.
+ // Third party copyrights are property of their respective owners.
+ //
+ // Redistribution and use in source and binary forms, with or without modification,
+ // are permitted provided that the following conditions are met:
+ //
+ //   * Redistribution's of source code must retain the above copyright notice,
+ //     this list of conditions and the following disclaimer.
+ //
+ //   * Redistribution's in binary form must reproduce the above copyright notice,
+ //     this list of conditions and the following disclaimer in the documentation
+ //     and/or other materials provided with the distribution.
+ //
+ //   * The name of the copyright holders may not be used to endorse or promote products
+ //     derived from this software without specific prior written permission.
+ //
+ // This software is provided by the copyright holders and contributors "as is" and
+ // any express or implied warranties, including, but not limited to, the implied
+ // warranties of merchantability and fitness for a particular purpose are disclaimed.
+ // In no event shall the Intel Corporation or contributors be liable for any direct,
+ // indirect, incidental, special, exemplary, or consequential damages
+ // (including, but not limited to, procurement of substitute goods or services;
+ // loss of use, data, or profits; or business interruption) however caused
+ // and on any theory of liability, whether in contract, strict liability,
+ // or tort (including negligence or otherwise) arising in any way out of
+ // the use of this software, even if advised of the possibility of such damage.
+ //
+ //M*/
+
+#include <opencv2/sfm/io.hpp>
+#include "io/io_bundler.h"
+
+namespace cv
+{
+namespace sfm
+{
+
+void
+importReconstruction(const cv::String &file, OutputArrayOfArrays _Rs,
+                     OutputArrayOfArrays _Ts, OutputArrayOfArrays _Ks,
+                     OutputArray _points3d, int file_format) {
+
+    std::vector<Matx33d> Rs, Ks;
+    std::vector<Vec3d> Ts, points3d;
+
+    if (file_format == SFM_IO_BUNDLER) {
+        readBundlerFile(file, Rs, Ts, Ks, points3d);
+    } else if (file_format == SFM_IO_VISUALSFM) {
+        CV_Error(Error::StsNotImplemented, "The requested function/feature is not implemented");
+    } else if (file_format == SFM_IO_OPENSFM) {
+        CV_Error(Error::StsNotImplemented, "The requested function/feature is not implemented");
+    } else if (file_format == SFM_IO_OPENMVG) {
+        CV_Error(Error::StsNotImplemented, "The requested function/feature is not implemented");
+    } else if (file_format == SFM_IO_THEIASFM) {
+        CV_Error(Error::StsNotImplemented, "The requested function/feature is not implemented");
+    } else {
+        CV_Error(Error::StsBadArg, "The file format one of SFM_IO_BUNDLER, SFM_IO_VISUALSFM, SFM_IO_OPENSFM, SFM_IO_OPENMVG or SFM_IO_THEIASFM");
+    }
+
+    const size_t num_cameras = Rs.size();
+    const size_t num_points = points3d.size();
+
+    _Rs.create(num_cameras, 1, CV_64F);
+    _Ts.create(num_cameras, 1, CV_64F);
+    _Ks.create(num_cameras, 1, CV_64F);
+    _points3d.create(num_points, 1, CV_64F);
+
+    for (size_t i = 0; i < num_cameras; ++i) {
+        Mat(Rs[i]).copyTo(_Rs.getMatRef(i));
+        Mat(Ts[i]).copyTo(_Ts.getMatRef(i));
+        Mat(Ks[i]).copyTo(_Ks.getMatRef(i));
+    }
+
+    for (size_t i = 0; i < num_points; ++i)
+        Mat(points3d[i]).copyTo(_points3d.getMatRef(i));
+}
+
+
+} /* namespace sfm */
+} /* namespace cv */
\ No newline at end of file
diff --git a/contrib/modules/sfm/src/io/io_bundler.h b/contrib/modules/sfm/src/io/io_bundler.h
new file mode 100644
index 0000000..0bce9be
--- /dev/null
+++ b/contrib/modules/sfm/src/io/io_bundler.h
@@ -0,0 +1,189 @@
+/*
+ Based on TheiaSfM library.
+ https://github.com/sweeneychris/TheiaSfM/blob/master/src/theia/io/read_bundler_files.cc
+
+ Adapted by Edgar Riba <edgar.riba at gmail.com>
+
+*/
+
+#include <iostream>
+#include <fstream>
+#include <opencv2/core.hpp>
+
+// The bundle files contain the estimated scene and camera geometry have the
+// following format:
+//     # Bundle file v0.3
+//     <num_cameras> <num_points>   [two integers]
+//     <camera1>
+//     <camera2>
+//        ...
+//     <cameraN>
+//     <point1>
+//     <point2>
+//        ...
+//     <pointM>
+// Each camera entry <cameraI> contains the estimated camera intrinsics and
+// extrinsics, and has the form:
+//     <f> <k1> <k2>   [the focal length, followed by two radial distortion
+//                      coeffs]
+//     <R>             [a 3x3 matrix representing the camera rotation]
+//     <t>             [a 3-vector describing the camera translation]
+// The cameras are specified in the order they appear in the list of images.
+//
+// Each point entry has the form:
+//     <position>      [a 3-vector describing the 3D position of the point]
+//     <color>         [a 3-vector describing the RGB color of the point]
+//     <view list>     [a list of views the point is visible in]
+//
+// The view list begins with the length of the list (i.e., the number of cameras
+// the point is visible in). The list is then given as a list of quadruplets
+// <camera> <key> <x> <y>, where <camera> is a camera index, <key> the index of
+// the SIFT keypoint where the point was detected in that camera, and <x> and
+// <y> are the detected positions of that keypoint. Both indices are 0-based
+// (e.g., if camera 0 appears in the list, this corresponds to the first camera
+// in the scene file and the first image in "list.txt"). The pixel positions are
+// floating point numbers in a coordinate system where the origin is the center
+// of the image, the x-axis increases to the right, and the y-axis increases
+// towards the top of the image. Thus, (-w/2, -h/2) is the lower-left corner of
+// the image, and (w/2, h/2) is the top-right corner (where w and h are the
+// width and height of the image).
+bool readBundlerFile(const std::string &file,
+                     std::vector<cv::Matx33d> &Rs,
+                     std::vector<cv::Vec3d> &Ts,
+                     std::vector<cv::Matx33d> &Ks,
+                     std::vector<cv::Vec3d> &points3d) {
+
+  // Read in num cameras, num points.
+  std::ifstream ifs(file.c_str(), std::ios::in);
+  if (!ifs.is_open()) {
+    std::cout << "Cannot read the file from " << file << std::endl;
+    return false;
+  }
+
+  const cv::Matx33d bundler_to_opencv(1, 0, 0, 0, -1, 0, 0, 0, -1);
+
+  std::string header_string;
+  std::getline(ifs, header_string);
+
+  // If the first line starts with '#' then it is a comment, so skip it!
+  if (header_string[0] == '#') {
+    std::getline(ifs, header_string);
+  }
+  const char* p = header_string.c_str();
+  char* p2;
+  const int num_cameras = strtol(p, &p2, 10);
+
+  p = p2;
+  const int num_points = strtol(p, &p2, 10);
+
+  // Read in the camera params.
+  for (int i = 0; i < num_cameras; i++) {
+    // Read in focal length, radial distortion.
+    std::string internal_params;
+    std::getline(ifs, internal_params);
+    p = internal_params.c_str();
+    const double focal_length = strtod(p, &p2);
+    p = p2;
+    //const double k1 = strtod(p, &p2);
+    p = p2;
+    //const double k2 = strtod(p, &p2);
+    p = p2;
+
+    cv::Matx33d intrinsics;
+    intrinsics(0,0) = intrinsics(1,1) = focal_length;
+    Ks.push_back(intrinsics);
+
+    // Read in rotation (row-major).
+    cv::Matx33d rotation;
+    for (int r = 0; r < 3; r++) {
+      std::string rotation_row;
+      std::getline(ifs, rotation_row);
+      p = rotation_row.c_str();
+
+      for (int c = 0; c < 3; c++) {
+        rotation(r, c) = strtod(p, &p2);
+        p = p2;
+      }
+    }
+
+    std::string translation_string;
+    std::getline(ifs, translation_string);
+    p = translation_string.c_str();
+    cv::Vec3d translation;
+    for (int j = 0; j < 3; j++) {
+      translation(j) = strtod(p, &p2);
+      p = p2;
+    }
+
+    rotation = bundler_to_opencv * rotation;
+    translation =  bundler_to_opencv * translation;
+
+    cv::Matx33d rotation_t = rotation.t();
+    translation = -1.0 * rotation_t * translation;
+
+    Rs.push_back(rotation);
+    Ts.push_back(translation);
+
+    if ((i + 1) % 100 == 0 || i == num_cameras - 1) {
+      std::cout << "\r Loading parameters for camera " << i + 1 << " / "
+                << num_cameras << std::flush;
+    }
+  }
+  std::cout << std::endl;
+
+  // Read in each 3D point and correspondences.
+  for (int i = 0; i < num_points; i++) {
+    // Read position.
+    std::string position_str;
+    std::getline(ifs, position_str);
+    p = position_str.c_str();
+    cv::Vec3d position;
+    for (int j = 0; j < 3; j++) {
+      position(j) = strtod(p, &p2);
+      p = p2;
+    }
+    points3d.push_back(position);
+
+    // Read color.
+    std::string color_str;
+    std::getline(ifs, color_str);
+    p = color_str.c_str();
+    cv::Vec3d color;
+    for (int j = 0; j < 3; j++) {
+      color(j) = static_cast<double>(strtol(p, &p2, 10)) / 255.0;
+      p = p2;
+    }
+
+    // Read viewlist.
+    std::string view_list_string;
+    std::getline(ifs, view_list_string);
+    p = view_list_string.c_str();
+    const int num_views = strtol(p, &p2, 10);
+    p = p2;
+
+    // Reserve the view list for this 3D point.
+    for (int j = 0; j < num_views; j++) {
+      // Camera key x y
+      //const int camera_index = strtol(p, &p2, 10);
+      p = p2;
+      // Returns the index of the sift descriptor in the camera for this track.
+      strtol(p, &p2, 10);
+      p = p2;
+      //const float x_pos = strtof(p, &p2);
+      p = p2;
+      //const float y_pos = strtof(p, &p2);
+      p = p2;
+
+    }
+
+    if ((i + 1) % 100 == 0 || i == num_points - 1) {
+      std::cout << "\r Loading 3D points " << i + 1 << " / " << num_points
+                << std::flush;
+    }
+  }
+
+  std::cout << std::endl;
+  ifs.close();
+
+  return true;
+}
\ No newline at end of file
diff --git a/contrib/modules/sfm/src/libmv_capi.h b/contrib/modules/sfm/src/libmv_capi.h
index 606bed1..e48c6b8 100644
--- a/contrib/modules/sfm/src/libmv_capi.h
+++ b/contrib/modules/sfm/src/libmv_capi.h
@@ -56,11 +56,16 @@
 #include "libmv/simple_pipeline/pipeline.h"
 #include "libmv/simple_pipeline/reconstruction_scale.h"
 #include "libmv/simple_pipeline/tracks.h"
+#include "gflags/gflags.h"
 
 using namespace cv;
 using namespace cv::sfm;
 using namespace libmv;
 
+using namespace google;
+
+namespace gflags {}
+using namespace gflags;
 
 ////////////////////////////////////////
 // Based on 'libmv_capi' (blender API)
@@ -84,26 +89,26 @@ void libmv_initLogging(const char* argv0) {
   // Make it so FATAL messages are always print into console.
   char severity_fatal[32];
   snprintf(severity_fatal, sizeof(severity_fatal), "%d",
-           google::GLOG_FATAL);
+           GLOG_FATAL);
 
-  google::InitGoogleLogging(argv0);
-  google::SetCommandLineOption("logtostderr", "1");
-  google::SetCommandLineOption("v", "0");
-  google::SetCommandLineOption("stderrthreshold", severity_fatal);
-  google::SetCommandLineOption("minloglevel", severity_fatal);
+  InitGoogleLogging(argv0);
+  SetCommandLineOption("logtostderr", "1");
+  SetCommandLineOption("v", "0");
+  SetCommandLineOption("stderrthreshold", severity_fatal);
+  SetCommandLineOption("minloglevel", severity_fatal);
 }
 
 void libmv_startDebugLogging(void) {
-  google::SetCommandLineOption("logtostderr", "1");
-  google::SetCommandLineOption("v", "2");
-  google::SetCommandLineOption("stderrthreshold", "1");
-  google::SetCommandLineOption("minloglevel", "0");
+  SetCommandLineOption("logtostderr", "1");
+  SetCommandLineOption("v", "2");
+  SetCommandLineOption("stderrthreshold", "1");
+  SetCommandLineOption("minloglevel", "0");
 }
 
 void libmv_setLoggingVerbosity(int verbosity) {
   char val[10];
   snprintf(val, sizeof(val), "%d", verbosity);
-  google::SetCommandLineOption("v", val);
+  SetCommandLineOption("v", val);
 }
 
 
@@ -432,4 +437,4 @@ libmv_Reconstruction *libmv_solveReconstruction(
   return (libmv_Reconstruction *) libmv_reconstruction;
 }
 
-#endif
\ No newline at end of file
+#endif
diff --git a/contrib/modules/sfm/src/libmv_light/libmv/multiview/CMakeLists.txt b/contrib/modules/sfm/src/libmv_light/libmv/multiview/CMakeLists.txt
index 3fc7e4b..b99ffbe 100644
--- a/contrib/modules/sfm/src/libmv_light/libmv/multiview/CMakeLists.txt
+++ b/contrib/modules/sfm/src/libmv_light/libmv/multiview/CMakeLists.txt
@@ -17,6 +17,6 @@ SET(MULTIVIEW_SRC conditioning.cc
 FILE(GLOB MULTIVIEW_HDRS *.h)
 
 ADD_LIBRARY(multiview STATIC ${MULTIVIEW_SRC} ${MULTIVIEW_HDRS})
-TARGET_LINK_LIBRARIES(multiview glog numeric)
+TARGET_LINK_LIBRARIES(multiview ${GLOG_LIBRARY} numeric)
 
 LIBMV_INSTALL_LIB(multiview)
diff --git a/contrib/modules/sfm/tutorials/sfm_import_reconstruction/sfm_import_reconstruction.markdown b/contrib/modules/sfm/tutorials/sfm_import_reconstruction/sfm_import_reconstruction.markdown
new file mode 100644
index 0000000..2c56809
--- /dev/null
+++ b/contrib/modules/sfm/tutorials/sfm_import_reconstruction/sfm_import_reconstruction.markdown
@@ -0,0 +1,28 @@
+Import Reconstruction {#tutorial_sfm_import_reconstruction}
+=====================
+
+Goal
+----
+
+In this tutorial you will learn how to import a reconstruction from a given file obtained with Bundler [1]:
+
+-   Load a file containing a set of cameras and 3D points.
+-   Show obtained results using Viz.
+
+
+Code
+----
+
+ at include sfm/samples/import_reconstruction.cpp
+
+Results
+-------
+
+The following picture shows a reconstruction from la *Sagrada Familia* (BCN) using dataset [2].
+
+![](pics/import_sagrada_familia.png)
+
+[1] [http://www.cs.cornell.edu/~snavely/bundler](http://www.cs.cornell.edu/~snavely/bundler)
+
+[2] Penate Sanchez, A. and Moreno-Noguer, F. and Andrade Cetto, J. and Fleuret, F. (2014). LETHA: Learning from High Quality Inputs for 3D Pose Estimation in Low Quality Images. Proceedings of the International Conference on 3D vision (3DV).
+[URL](http://www.iri.upc.edu/research/webprojects/pau/datasets/sagfam)
diff --git a/contrib/modules/sfm/tutorials/sfm_trajectory_estimation/sfm_trajectory_estimation.markdown b/contrib/modules/sfm/tutorials/sfm_trajectory_estimation/sfm_trajectory_estimation.markdown
index f39bba2..e013734 100644
--- a/contrib/modules/sfm/tutorials/sfm_trajectory_estimation/sfm_trajectory_estimation.markdown
+++ b/contrib/modules/sfm/tutorials/sfm_trajectory_estimation/sfm_trajectory_estimation.markdown
@@ -6,7 +6,7 @@ Goal
 
 In this tutorial you will learn how to use the reconstruction api for camera motion estimation:
 
--   Load and file with the tracked 2d points and build the container over all the frames.
+-   Load a file with the tracked 2d points and build the container over all the frames.
 -   Run libmv reconstruction pipeline.
 -   Show obtained results using Viz.
 
diff --git a/contrib/modules/sfm/tutorials/table_of_content_sfm.markdown b/contrib/modules/sfm/tutorials/table_of_content_sfm.markdown
index 7d9423e..3239949 100644
--- a/contrib/modules/sfm/tutorials/table_of_content_sfm.markdown
+++ b/contrib/modules/sfm/tutorials/table_of_content_sfm.markdown
@@ -23,4 +23,12 @@ Structure From Motion {#tutorial_table_of_content_sfm}
 
     *Author:* Edgar Riba
 
-    Sparse scene reconstruction from a given set of images.
\ No newline at end of file
+    Sparse scene reconstruction from a given set of images.
+
+-   @subpage tutorial_sfm_import_reconstruction
+
+    *Compatibility:* \> OpenCV 3.0
+
+    *Author:* Edgar Riba
+
+    Import a scene reconstruction.
\ No newline at end of file
diff --git a/contrib/modules/stereo/README.md b/contrib/modules/stereo/README.md
index c5f9c5b..745064d 100644
--- a/contrib/modules/stereo/README.md
+++ b/contrib/modules/stereo/README.md
@@ -1,2 +1,4 @@
 Stereo Correspondence with different descriptors
 ================================================
+
+Stereo matching done with different descriptors: Census / CS-Census / MCT / BRIEF / MV.
diff --git a/contrib/modules/stereo/include/opencv2/stereo/matching.hpp b/contrib/modules/stereo/include/opencv2/stereo/matching.hpp
index 8c787bb..2238961 100644
--- a/contrib/modules/stereo/include/opencv2/stereo/matching.hpp
+++ b/contrib/modules/stereo/include/opencv2/stereo/matching.hpp
@@ -170,11 +170,16 @@ namespace cv
                             {
                                 j2 = (0 > j - d) ? (0) : (j - d);
                                 xorul = left[(iwj)] ^ right[(iw + j2)];
-#if CV_SSE4_1
-                                c[(iwj)* (v + 1) + d] = (short)_mm_popcnt_u32(xorul);
-#else
-                                c[(iwj)* (v + 1) + d] = (short)(hammLut[xorul & MASK] + hammLut[(xorul >> 16) & MASK]);
+#if CV_POPCNT
+                                if (checkHardwareSupport(CV_CPU_POPCNT))
+                                {
+                                    c[(iwj)* (v + 1) + d] = (short)_mm_popcnt_u32(xorul);
+                                }
+                                else
 #endif
+                                {
+                                    c[(iwj)* (v + 1) + d] = (short)(hammLut[xorul & MASK] + hammLut[(xorul >> 16) & MASK]);
+                                }
                             }
                         }
                     }
diff --git a/contrib/modules/structured_light/CMakeLists.txt b/contrib/modules/structured_light/CMakeLists.txt
index 66bcc27..556a29d 100644
--- a/contrib/modules/structured_light/CMakeLists.txt
+++ b/contrib/modules/structured_light/CMakeLists.txt
@@ -1,2 +1,2 @@
 set(the_description "Structured Light API")
-ocv_define_module(structured_light opencv_core opencv_calib3d opencv_imgproc opencv_highgui opencv_features2d opencv_rgbd OPTIONAL opencv_viz)
+ocv_define_module(structured_light opencv_core opencv_calib3d opencv_imgproc opencv_highgui opencv_features2d opencv_rgbd opencv_phase_unwrapping OPTIONAL opencv_viz WRAP python java)
diff --git a/contrib/modules/structured_light/README.md b/contrib/modules/structured_light/README.md
index f3dec88..9d82753 100644
--- a/contrib/modules/structured_light/README.md
+++ b/contrib/modules/structured_light/README.md
@@ -1,2 +1,4 @@
-Structured Light module
-============================================================
\ No newline at end of file
+Structured Light Use
+====================
+
+How to generate and project gray code patterns and use them to find dense depth in a scene.
diff --git a/contrib/modules/structured_light/doc/structured_light.bib b/contrib/modules/structured_light/doc/structured_light.bib
index 8d11b8d..c737bce 100644
--- a/contrib/modules/structured_light/doc/structured_light.bib
+++ b/contrib/modules/structured_light/doc/structured_light.bib
@@ -14,3 +14,13 @@
    pages = {827-849},
    year = {April 2004},
 }
+
+ at article{faps,
+  title={Accurate dynamic 3D sensing with Fourier-assisted phase shifting},
+  author={Cong, Pengyu and Xiong, Zhiwei and Zhang, Yueyi and Zhao, Shenghui and Wu, Feng},
+  journal={IEEE Journal of Selected Topics in Signal Processing},
+  volume={9},
+  number={3},
+  pages={396--408},
+  year={2015},
+}
diff --git a/contrib/modules/structured_light/include/opencv2/structured_light.hpp b/contrib/modules/structured_light/include/opencv2/structured_light.hpp
index b06cdfb..4508d89 100644
--- a/contrib/modules/structured_light/include/opencv2/structured_light.hpp
+++ b/contrib/modules/structured_light/include/opencv2/structured_light.hpp
@@ -45,6 +45,7 @@
 
 #include "opencv2/structured_light/structured_light.hpp"
 #include "opencv2/structured_light/graycodepattern.hpp"
+#include "opencv2/structured_light/sinusoidalpattern.hpp"
 
 /** @defgroup structured_light Structured Light API
 
diff --git a/contrib/modules/structured_light/include/opencv2/structured_light/graycodepattern.hpp b/contrib/modules/structured_light/include/opencv2/structured_light/graycodepattern.hpp
index cf01f70..55b39af 100644
--- a/contrib/modules/structured_light/include/opencv2/structured_light/graycodepattern.hpp
+++ b/contrib/modules/structured_light/include/opencv2/structured_light/graycodepattern.hpp
@@ -43,6 +43,7 @@
 #define __OPENCV_GRAY_CODE_PATTERN_HPP__
 
 #include "opencv2/core.hpp"
+#include "opencv2/structured_light/structured_light.hpp"
 
 namespace cv {
 namespace structured_light {
@@ -72,22 +73,22 @@ class CV_EXPORTS_W GrayCodePattern : public StructuredLightPattern
    *  @param width Projector's width. Default value is 1024.
    *  @param height Projector's height. Default value is 768.
    */
-  struct CV_EXPORTS_W_SIMPLE Params
+  struct CV_EXPORTS Params
   {
-    CV_WRAP
     Params();
-    CV_PROP_RW
     int width;
-    CV_PROP_RW
     int height;
   };
 
   /** @brief Constructor
    @param parameters GrayCodePattern parameters GrayCodePattern::Params: the width and the height of the projector.
    */
-  CV_WRAP
   static Ptr<GrayCodePattern> create( const GrayCodePattern::Params &parameters = GrayCodePattern::Params() );
 
+  // alias for scripting
+  CV_WRAP
+  static Ptr<GrayCodePattern> create( int width, int height );
+
   /** @brief Get the number of pattern images needed for the graycode pattern.
    *
    * @return The number of pattern images needed for the graycode pattern.
diff --git a/contrib/modules/structured_light/include/opencv2/structured_light/sinusoidalpattern.hpp b/contrib/modules/structured_light/include/opencv2/structured_light/sinusoidalpattern.hpp
new file mode 100644
index 0000000..c4549f5
--- /dev/null
+++ b/contrib/modules/structured_light/include/opencv2/structured_light/sinusoidalpattern.hpp
@@ -0,0 +1,151 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+//  By downloading, copying, installing or using the software you agree to this license.
+//  If you do not agree to this license, do not download, install,
+//  copy or use the software.
+//
+//
+//                           License Agreement
+//                For Open Source Computer Vision Library
+//
+// Copyright (C) 2015, OpenCV Foundation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+//   * Redistribution's of source code must retain the above copyright notice,
+//     this list of conditions and the following disclaimer.
+//
+//   * Redistribution's in binary form must reproduce the above copyright notice,
+//     this list of conditions and the following disclaimer in the documentation
+//     and/or other materials provided with the distribution.
+//
+//   * The name of the copyright holders may not be used to endorse or promote products
+//     derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#ifndef __OPENCV_SINUSOIDAL_PATTERN_HPP__
+#define __OPENCV_SINUSOIDAL_PATTERN_HPP__
+
+#include "opencv2/core.hpp"
+#include "opencv2/imgproc.hpp"
+#include "opencv2/structured_light/structured_light.hpp"
+#include <opencv2/phase_unwrapping.hpp>
+#include <opencv2/calib3d.hpp>
+
+namespace cv {
+namespace structured_light {
+//! @addtogroup structured_light
+//! @{
+
+ //! Type of sinusoidal pattern profilometry methods.
+enum{
+  FTP = 0,
+  PSP = 1,
+  FAPS = 2
+ };
+/**
+ * @brief Class implementing Fourier transform profilometry (FTP) , phase-shifting profilometry (PSP)
+ * and Fourier-assisted phase-shifting profilometry (FAPS) based on @cite faps.
+
+ * This class generates sinusoidal patterns that can be used with FTP, PSP and FAPS.
+*/
+class CV_EXPORTS_W SinusoidalPattern : public StructuredLightPattern
+{
+public:
+    /**
+     * @brief Parameters of SinusoidalPattern constructor
+     * @param width Projector's width.
+     * @param height Projector's height.
+     * @param nbrOfPeriods Number of period along the patterns direction.
+     * @param shiftValue Phase shift between two consecutive patterns.
+     * @param methodId Allow to choose between FTP, PSP and FAPS.
+     * @param nbrOfPixelsBetweenMarkers Number of pixels between two consecutive markers on the same row.
+     * @param setMarkers Allow to set markers on the patterns.
+     * @param markersLocation vector used to store markers location on the patterns.
+     */
+    struct CV_EXPORTS Params
+    {
+        Params();
+        int width;
+        int height;
+        int nbrOfPeriods;
+        float shiftValue;
+        int methodId;
+        int nbrOfPixelsBetweenMarkers;
+        bool horizontal;
+        bool setMarkers;
+        std::vector<Point2f> markersLocation;
+    };
+    /**
+     * @brief Constructor.
+     * @param parameters SinusoidalPattern parameters SinusoidalPattern::Params: width, height of the projector and patterns parameters.
+     *
+     */
+    static Ptr<SinusoidalPattern> create( const SinusoidalPattern::Params &parameters =
+                                          SinusoidalPattern::Params() );
+    /**
+     * @brief Compute a wrapped phase map from sinusoidal patterns.
+     * @param patternImages Input data to compute the wrapped phase map.
+     * @param wrappedPhaseMap Wrapped phase map obtained through one of the three methods.
+     * @param shadowMask Mask used to discard shadow regions.
+     * @param fundamental Fundamental matrix used to compute epipolar lines and ease the matching step.
+     */
+    CV_WRAP
+    virtual void computePhaseMap( InputArrayOfArrays patternImages,
+                                  OutputArray wrappedPhaseMap,
+                                  OutputArray shadowMask = noArray(),
+                                  InputArray fundamental = noArray()) = 0;
+    /**
+     * @brief Unwrap the wrapped phase map to remove phase ambiguities.
+     * @param wrappedPhaseMap The wrapped phase map computed from the pattern.
+     * @param unwrappedPhaseMap The unwrapped phase map used to find correspondences between the two devices.
+     * @param camSize Resolution of the camera.
+     * @param shadowMask Mask used to discard shadow regions.
+     */
+    CV_WRAP
+    virtual void unwrapPhaseMap( InputArrayOfArrays wrappedPhaseMap,
+                                 OutputArray unwrappedPhaseMap,
+                                 cv::Size camSize,
+                                 InputArray shadowMask = noArray() ) = 0;
+    /**
+     * @brief Find correspondences between the two devices thanks to unwrapped phase maps.
+     * @param projUnwrappedPhaseMap Projector's unwrapped phase map.
+     * @param camUnwrappedPhaseMap Camera's unwrapped phase map.
+     * @param matches Images used to display correspondences map.
+     */
+    CV_WRAP
+    virtual void findProCamMatches( InputArray projUnwrappedPhaseMap, InputArray camUnwrappedPhaseMap,
+                                    OutputArrayOfArrays matches ) = 0;
+
+    /**
+     * @brief compute the data modulation term.
+     * @param patternImages captured images with projected patterns.
+     * @param dataModulationTerm Mat where the data modulation term is saved.
+     * @param shadowMask Mask used to discard shadow regions.
+     */
+    CV_WRAP
+    virtual void computeDataModulationTerm( InputArrayOfArrays patternImages,
+                                            OutputArray dataModulationTerm,
+                                            InputArray shadowMask ) = 0;
+
+};
+//! @}
+}
+}
+#endif
\ No newline at end of file
diff --git a/contrib/modules/structured_light/include/opencv2/structured_light/structured_light.hpp b/contrib/modules/structured_light/include/opencv2/structured_light/structured_light.hpp
index aa7e014..a970c41 100644
--- a/contrib/modules/structured_light/include/opencv2/structured_light/structured_light.hpp
+++ b/contrib/modules/structured_light/include/opencv2/structured_light/structured_light.hpp
@@ -78,9 +78,10 @@ class CV_EXPORTS_W StructuredLightPattern : public virtual Algorithm
    @note All the images must be at the same resolution.
    */
   CV_WRAP
-  virtual bool decode( InputArrayOfArrays patternImages, OutputArray disparityMap, InputArrayOfArrays blackImages =
-                          noArray(),
-                      InputArrayOfArrays whiteImages = noArray(), int flags = DECODE_3D_UNDERWORLD ) const = 0;
+  virtual bool decode( InputArrayOfArrays patternImages, OutputArray disparityMap,
+                       InputArrayOfArrays blackImages = noArray(),
+                       InputArrayOfArrays whiteImages = noArray(),
+                       int flags = DECODE_3D_UNDERWORLD ) const = 0;
 };
 
 //! @}
diff --git a/contrib/modules/structured_light/samples/capsinpattern.cpp b/contrib/modules/structured_light/samples/capsinpattern.cpp
new file mode 100644
index 0000000..b16061e
--- /dev/null
+++ b/contrib/modules/structured_light/samples/capsinpattern.cpp
@@ -0,0 +1,335 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+ //
+ //  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+ //
+ //  By downloading, copying, installing or using the software you agree to this license.
+ //  If you do not agree to this license, do not download, install,
+ //  copy or use the software.
+ //
+ //
+ //                           License Agreement
+ //                For Open Source Computer Vision Library
+ //
+ // Copyright (C) 2015, OpenCV Foundation, all rights reserved.
+ // Third party copyrights are property of their respective owners.
+ //
+ // Redistribution and use in source and binary forms, with or without modification,
+ // are permitted provided that the following conditions are met:
+ //
+ //   * Redistribution's of source code must retain the above copyright notice,
+ //     this list of conditions and the following disclaimer.
+ //
+ //   * Redistribution's in binary form must reproduce the above copyright notice,
+ //     this list of conditions and the following disclaimer in the documentation
+ //     and/or other materials provided with the distribution.
+ //
+ //   * The name of the copyright holders may not be used to endorse or promote products
+ //     derived from this software without specific prior written permission.
+ //
+ // This software is provided by the copyright holders and contributors "as is" and
+ // any express or implied warranties, including, but not limited to, the implied
+ // warranties of merchantability and fitness for a particular purpose are disclaimed.
+ // In no event shall the Intel Corporation or contributors be liable for any direct,
+ // indirect, incidental, special, exemplary, or consequential damages
+ // (including, but not limited to, procurement of substitute goods or services;
+ // loss of use, data, or profits; or business interruption) however caused
+ // and on any theory of liability, whether in contract, strict liability,
+ // or tort (including negligence or otherwise) arising in any way out of
+ // the use of this software, even if advised of the possibility of such damage.
+ //
+ //M*/
+
+#include <opencv2/highgui.hpp>
+#include <vector>
+#include <iostream>
+#include <fstream>
+#include <opencv2/core.hpp>
+#include <opencv2/core/utility.hpp>
+#include <opencv2/imgproc.hpp>
+#include <opencv2/calib3d.hpp>
+#include <opencv2/structured_light.hpp>
+#include <opencv2/phase_unwrapping.hpp>
+
+using namespace cv;
+using namespace std;
+
+static const char* keys =
+{
+    "{@width | | Projector width}"
+    "{@height | | Projector height}"
+    "{@periods | | Number of periods}"
+    "{@setMarkers | | Patterns with or without markers}"
+    "{@horizontal | | Patterns are horizontal}"
+    "{@methodId | | Method to be used}"
+    "{@outputPatternPath | | Path to save patterns}"
+    "{@outputWrappedPhasePath | | Path to save wrapped phase map}"
+    "{@outputUnwrappedPhasePath | | Path to save unwrapped phase map}"
+    "{@outputCapturePath | | Path to save the captures}"
+    "{@reliabilitiesPath | | Path to save reliabilities}"
+};
+static void help()
+{
+    cout << "\nThis example generates sinusoidal patterns" << endl;
+    cout << "To call: ./example_structured_light_createsinuspattern <width> <height>"
+            " <number_of_period> <set_marker>(bool) <horizontal_patterns>(bool) <method_id>"
+            " <output_captures_path> <output_pattern_path>(optional) <output_wrapped_phase_path> (optional)"
+            " <output_unwrapped_phase_path>" << endl;
+}
+
+int main(int argc, char **argv)
+{
+    if( argc < 2 )
+    {
+        help();
+        return -1;
+    }
+    structured_light::SinusoidalPattern::Params params;
+    phase_unwrapping::HistogramPhaseUnwrapping::Params paramsUnwrapping;
+
+    // Retrieve parameters written in the command line
+    CommandLineParser parser(argc, argv, keys);
+    params.width = parser.get<int>(0);
+    params.height = parser.get<int>(1);
+    params.nbrOfPeriods = parser.get<int>(2);
+    params.setMarkers = parser.get<bool>(3);
+    params.horizontal = parser.get<bool>(4);
+    params.methodId = parser.get<int>(5);
+    String outputCapturePath = parser.get<String>(6);
+
+    params.shiftValue = static_cast<float>(2 * CV_PI / 3);
+    params.nbrOfPixelsBetweenMarkers = 70;
+    String outputPatternPath = parser.get<String>(7);
+    String outputWrappedPhasePath = parser.get<String>(8);
+    String outputUnwrappedPhasePath = parser.get<String>(9);
+    String reliabilitiesPath = parser.get<String>(10);
+
+    Ptr<structured_light::SinusoidalPattern> sinus = structured_light::SinusoidalPattern::create(params);
+    Ptr<phase_unwrapping::HistogramPhaseUnwrapping> phaseUnwrapping;
+
+    vector<Mat> patterns;
+    Mat shadowMask;
+    Mat unwrappedPhaseMap, unwrappedPhaseMap8;
+    Mat wrappedPhaseMap, wrappedPhaseMap8;
+    //Generate sinusoidal patterns
+    sinus->generate(patterns);
+
+
+    VideoCapture cap(CAP_PVAPI);
+    if( !cap.isOpened() )
+    {
+        cout << "Camera could not be opened" << endl;
+        return -1;
+    }
+    cap.set(CAP_PROP_PVAPI_PIXELFORMAT, CAP_PVAPI_PIXELFORMAT_MONO8);
+
+    namedWindow("pattern", WINDOW_NORMAL);
+    setWindowProperty("pattern", WND_PROP_FULLSCREEN, WINDOW_FULLSCREEN);
+    imshow("pattern", patterns[0]);
+    cout << "Press any key when ready" << endl;
+    waitKey(0);
+
+    int nbrOfImages = 30;
+    int count = 0;
+
+    vector<Mat> img(nbrOfImages);
+    Size camSize(-1, -1);
+
+    while( count < nbrOfImages )
+    {
+        for(int i = 0; i < (int)patterns.size(); ++i )
+        {
+            imshow("pattern", patterns[i]);
+            waitKey(300);
+            cap >> img[count];
+            count += 1;
+        }
+    }
+
+    cout << "press enter when ready" << endl;
+    bool loop = true;
+    while ( loop )
+    {
+        char c = (char) waitKey(0);
+        if( c == 10 )
+        {
+            loop = false;
+        }
+    }
+
+    switch(params.methodId)
+    {
+        case structured_light::FTP:
+            for( int i = 0; i < nbrOfImages; ++i )
+            {
+                /*We need three images to compute the shadow mask, as described in the reference paper
+                 * even if the phase map is computed from one pattern only
+                */
+                vector<Mat> captures;
+                if( i == nbrOfImages - 2 )
+                {
+                    captures.push_back(img[i]);
+                    captures.push_back(img[i-1]);
+                    captures.push_back(img[i+1]);
+                }
+                else if( i == nbrOfImages - 1 )
+                {
+                    captures.push_back(img[i]);
+                    captures.push_back(img[i-1]);
+                    captures.push_back(img[i-2]);
+                }
+                else
+                {
+                    captures.push_back(img[i]);
+                    captures.push_back(img[i+1]);
+                    captures.push_back(img[i+2]);
+                }
+                sinus->computePhaseMap(captures, wrappedPhaseMap, shadowMask);
+                if( camSize.height == -1 )
+                {
+                    camSize.height = img[i].rows;
+                    camSize.width = img[i].cols;
+                    paramsUnwrapping.height = camSize.height;
+                    paramsUnwrapping.width = camSize.width;
+                    phaseUnwrapping =
+                    phase_unwrapping::HistogramPhaseUnwrapping::create(paramsUnwrapping);
+                }
+                sinus->unwrapPhaseMap(wrappedPhaseMap, unwrappedPhaseMap, camSize, shadowMask);
+
+                phaseUnwrapping->unwrapPhaseMap(wrappedPhaseMap, unwrappedPhaseMap, shadowMask);
+                Mat reliabilities, reliabilities8;
+                phaseUnwrapping->getInverseReliabilityMap(reliabilities);
+                reliabilities.convertTo(reliabilities8, CV_8U, 255,128);
+
+                ostringstream tt;
+                tt << i;
+                imwrite(reliabilitiesPath + tt.str() + ".png", reliabilities8);
+
+                unwrappedPhaseMap.convertTo(unwrappedPhaseMap8, CV_8U, 1, 128);
+                wrappedPhaseMap.convertTo(wrappedPhaseMap8, CV_8U, 255, 128);
+
+                if( !outputUnwrappedPhasePath.empty() )
+                {
+                    ostringstream name;
+                    name << i;
+                    imwrite(outputUnwrappedPhasePath + "_FTP_" + name.str() + ".png", unwrappedPhaseMap8);
+                }
+
+                if( !outputWrappedPhasePath.empty() )
+                {
+                    ostringstream name;
+                    name << i;
+                    imwrite(outputWrappedPhasePath + "_FTP_" + name.str() + ".png", wrappedPhaseMap8);
+                }
+            }
+            break;
+        case structured_light::PSP:
+        case structured_light::FAPS:
+            for( int i = 0; i < nbrOfImages - 2; ++i )
+            {
+                vector<Mat> captures;
+                captures.push_back(img[i]);
+                captures.push_back(img[i+1]);
+                captures.push_back(img[i+2]);
+
+                sinus->computePhaseMap(captures, wrappedPhaseMap, shadowMask);
+
+                if( camSize.height == -1 )
+                {
+                    camSize.height = img[i].rows;
+                    camSize.width = img[i].cols;
+                    paramsUnwrapping.height = camSize.height;
+                    paramsUnwrapping.width = camSize.width;
+                    phaseUnwrapping =
+                    phase_unwrapping::HistogramPhaseUnwrapping::create(paramsUnwrapping);
+                }
+                sinus->unwrapPhaseMap(wrappedPhaseMap, unwrappedPhaseMap, camSize, shadowMask);
+                unwrappedPhaseMap.convertTo(unwrappedPhaseMap8, CV_8U, 1, 128);
+                wrappedPhaseMap.convertTo(wrappedPhaseMap8, CV_8U, 255, 128);
+
+                phaseUnwrapping->unwrapPhaseMap(wrappedPhaseMap, unwrappedPhaseMap, shadowMask);
+                Mat reliabilities, reliabilities8;
+                phaseUnwrapping->getInverseReliabilityMap(reliabilities);
+                reliabilities.convertTo(reliabilities8, CV_8U, 255,128);
+
+                ostringstream tt;
+                tt << i;
+                imwrite(reliabilitiesPath + tt.str() + ".png", reliabilities8);
+
+                if( !outputUnwrappedPhasePath.empty() )
+                {
+                    ostringstream name;
+                    name << i;
+                    if( params.methodId == structured_light::PSP )
+                        imwrite(outputUnwrappedPhasePath + "_PSP_" + name.str() + ".png", unwrappedPhaseMap8);
+                    else
+                        imwrite(outputUnwrappedPhasePath + "_FAPS_" + name.str() + ".png", unwrappedPhaseMap8);
+                }
+
+                if( !outputWrappedPhasePath.empty() )
+                {
+                    ostringstream name;
+                    name << i;
+                    if( params.methodId == structured_light::PSP )
+                        imwrite(outputWrappedPhasePath + "_PSP_" + name.str() + ".png", wrappedPhaseMap8);
+                    else
+                        imwrite(outputWrappedPhasePath + "_FAPS_" + name.str() + ".png", wrappedPhaseMap8);
+                }
+
+                if( !outputCapturePath.empty() )
+                {
+                    ostringstream name;
+                    name << i;
+                    if( params.methodId == structured_light::PSP )
+                        imwrite(outputCapturePath + "_PSP_" + name.str() + ".png", img[i]);
+                    else
+                        imwrite(outputCapturePath + "_FAPS_" + name.str() + ".png", img[i]);
+                    if( i == nbrOfImages - 3 )
+                    {
+                        if( params.methodId == structured_light::PSP )
+                        {
+                            ostringstream nameBis;
+                            nameBis << i+1;
+                            ostringstream nameTer;
+                            nameTer << i+2;
+                            imwrite(outputCapturePath + "_PSP_" + nameBis.str() + ".png", img[i+1]);
+                            imwrite(outputCapturePath + "_PSP_" + nameTer.str() + ".png", img[i+2]);
+                        }
+                        else
+                        {
+                            ostringstream nameBis;
+                            nameBis << i+1;
+                            ostringstream nameTer;
+                            nameTer << i+2;
+                            imwrite(outputCapturePath + "_FAPS_" + nameBis.str() + ".png", img[i+1]);
+                            imwrite(outputCapturePath + "_FAPS_" + nameTer.str() + ".png", img[i+2]);
+                        }
+                    }
+                }
+            }
+            break;
+        default:
+            cout << "error" << endl;
+    }
+    cout << "done" << endl;
+
+    if( !outputPatternPath.empty() )
+    {
+        for( int i = 0; i < 3; ++ i )
+        {
+            ostringstream name;
+            name << i + 1;
+            imwrite(outputPatternPath + name.str() + ".png", patterns[i]);
+        }
+    }
+
+    loop = true;
+    while( loop )
+    {
+        char key = (char) waitKey(0);
+        if( key == 27 )
+        {
+            loop = false;
+        }
+    }
+    return 0;
+}
\ No newline at end of file
diff --git a/contrib/modules/structured_light/samples/projectorcalibration.cpp b/contrib/modules/structured_light/samples/projectorcalibration.cpp
new file mode 100644
index 0000000..d5bfb55
--- /dev/null
+++ b/contrib/modules/structured_light/samples/projectorcalibration.cpp
@@ -0,0 +1,517 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+ //
+ //  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+ //
+ //  By downloading, copying, installing or using the software you agree to this license.
+ //  If you do not agree to this license, do not download, install,
+ //  copy or use the software.
+ //
+ //
+ //                           License Agreement
+ //                For Open Source Computer Vision Library
+ //
+ // Copyright (C) 2015, OpenCV Foundation, all rights reserved.
+ // Third party copyrights are property of their respective owners.
+ //
+ // Redistribution and use in source and binary forms, with or without modification,
+ // are permitted provided that the following conditions are met:
+ //
+ //   * Redistribution's of source code must retain the above copyright notice,
+ //     this list of conditions and the following disclaimer.
+ //
+ //   * Redistribution's in binary form must reproduce the above copyright notice,
+ //     this list of conditions and the following disclaimer in the documentation
+ //     and/or other materials provided with the distribution.
+ //
+ //   * The name of the copyright holders may not be used to endorse or promote products
+ //     derived from this software without specific prior written permission.
+ //
+ // This software is provided by the copyright holders and contributors "as is" and
+ // any express or implied warranties, including, but not limited to, the implied
+ // warranties of merchantability and fitness for a particular purpose are disclaimed.
+ // In no event shall the Intel Corporation or contributors be liable for any direct,
+ // indirect, incidental, special, exemplary, or consequential damages
+ // (including, but not limited to, procurement of substitute goods or services;
+ // loss of use, data, or profits; or business interruption) however caused
+ // and on any theory of liability, whether in contract, strict liability,
+ // or tort (including negligence or otherwise) arising in any way out of
+ // the use of this software, even if advised of the possibility of such damage.
+ //
+ //M*/
+
+#include <opencv2/highgui.hpp>
+#include <vector>
+#include <iostream>
+#include <fstream>
+
+#include <opencv2/core.hpp>
+#include <opencv2/core/utility.hpp>
+#include <opencv2/imgproc.hpp>
+#include <opencv2/calib3d.hpp>
+
+using namespace std;
+using namespace cv;
+
+static const char* keys =
+{
+    "{@camSettingsPath | | Path of camera calibration file}"
+    "{@projSettingsPath | | Path of projector settings}"
+    "{@patternPath | | Path to checkerboard pattern}"
+    "{@outputName | | Base name for the calibration data}"
+};
+
+static void help()
+{
+    cout << "\nThis example calibrates a camera and a projector" << endl;
+    cout << "To call: ./example_structured_light_projectorcalibration <cam_settings_path> "
+            " <proj_settings_path> <chessboard_path> <calibration_basename>"
+            " cam settings are parameters about the chessboard that needs to be detected to"
+            " calibrate the camera and proj setting are the same kind of parameters about the chessboard"
+            " that needs to be detected to calibrate the projector" << endl;
+}
+enum calibrationPattern{ CHESSBOARD, CIRCLES_GRID, ASYMETRIC_CIRCLES_GRID };
+
+struct Settings
+{
+    Settings();
+    int patternType;
+    Size patternSize;
+    Size subpixelSize;
+    Size imageSize;
+    float squareSize;
+    int nbrOfFrames;
+};
+
+void loadSettings( String path, Settings &sttngs );
+
+void createObjectPoints( vector<Point3f> &patternCorners, Size patternSize, float squareSize,
+                        int patternType );
+
+void createProjectorObjectPoints( vector<Point2f> &patternCorners, Size patternSize, float squareSize,
+                        int patternType );
+
+double calibrate( vector< vector<Point3f> > objPoints, vector< vector<Point2f> > imgPoints,
+               Mat &cameraMatrix, Mat &distCoeffs, vector<Mat> &r, vector<Mat> &t, Size imgSize );
+
+void fromCamToWorld( Mat cameraMatrix, vector<Mat> rV, vector<Mat> tV,
+                    vector< vector<Point2f> > imgPoints, vector< vector<Point3f> > &worldPoints );
+
+void saveCalibrationResults( String path, Mat camK, Mat camDistCoeffs, Mat projK, Mat projDistCoeffs,
+                      Mat fundamental );
+
+void saveCalibrationData( String path, vector<Mat> T1, vector<Mat> T2, vector<Mat> ptsProjCam, vector<Mat> ptsProjProj, vector<Mat> ptsProjCamN, vector<Mat> ptsProjProjN);
+
+void normalize(const Mat &pts, const int& dim, Mat& normpts, Mat &T);
+
+void fromVectorToMat( vector<Point2f> v, Mat &pts);
+
+void fromMatToVector( Mat pts, vector<Point2f> &v );
+
+int main( int argc, char **argv )
+{
+    VideoCapture cap(CAP_PVAPI);
+    Mat frame;
+
+    int nbrOfValidFrames = 0;
+
+    vector< vector<Point2f> > imagePointsCam, imagePointsProj, PointsInProj, imagePointsProjN, pointsInProjN;
+    vector< vector<Point3f> > objectPointsCam, worldPointsProj;
+    vector<Point3f> tempCam;
+    vector<Point2f> tempProj;
+    vector<Mat> T1, T2;
+    vector<Mat> projInProj, projInCam;
+    vector<Mat> projInProjN, projInCamN;
+
+    vector<Mat> rVecs, tVecs, projectorRVecs, projectorTVecs;
+    Mat cameraMatrix, distCoeffs, projectorMatrix, projectorDistCoeffs;
+    Mat pattern;
+    vector<Mat> images;
+
+    Settings camSettings, projSettings;
+
+    CommandLineParser parser(argc, argv, keys);
+
+    String camSettingsPath = parser.get<String>(0);
+    String projSettingsPath = parser.get<String>(1);
+    String patternPath = parser.get<String>(2);
+    String outputName = parser.get<String>(3);
+
+    if( camSettingsPath.empty() || projSettingsPath.empty() || patternPath.empty() || outputName.empty() ){
+        help();
+        return -1;
+    }
+
+    pattern = imread(patternPath);
+
+    loadSettings(camSettingsPath, camSettings);
+    loadSettings(projSettingsPath, projSettings);
+
+    projSettings.imageSize = Size(pattern.rows, pattern.cols);
+
+    createObjectPoints(tempCam, camSettings.patternSize,
+                       camSettings.squareSize, camSettings.patternType);
+    createProjectorObjectPoints(tempProj, projSettings.patternSize,
+                                projSettings.squareSize, projSettings.patternType);
+
+    if(!cap.isOpened())
+    {
+        cout << "Camera could not be opened" << endl;
+        return -1;
+    }
+    cap.set(CAP_PROP_PVAPI_PIXELFORMAT, CAP_PVAPI_PIXELFORMAT_BAYER8);
+
+    namedWindow("pattern", WINDOW_NORMAL);
+    setWindowProperty("pattern", WND_PROP_FULLSCREEN, WINDOW_FULLSCREEN);
+
+    namedWindow("camera view", WINDOW_NORMAL);
+
+    imshow("pattern", pattern);
+    cout << "Press any key when ready" << endl;
+    waitKey(0);
+
+    while( nbrOfValidFrames < camSettings.nbrOfFrames )
+    {
+        cap >> frame;
+        if( frame.data )
+        {
+            Mat color;
+            cvtColor(frame, color, COLOR_BayerBG2BGR);
+            if( camSettings.imageSize.height == 0 || camSettings.imageSize.width == 0 )
+            {
+                camSettings.imageSize = Size(frame.rows, frame.cols);
+            }
+
+            bool foundProj, foundCam;
+
+            vector<Point2f> projPointBuf;
+            vector<Point2f> camPointBuf;
+
+            imshow("camera view", color);
+            if( camSettings.patternType == CHESSBOARD && projSettings.patternType == CHESSBOARD )
+            {
+                int calibFlags = CALIB_CB_ADAPTIVE_THRESH;
+
+                foundCam = findChessboardCorners(color, camSettings.patternSize,
+                                                 camPointBuf, calibFlags);
+
+                foundProj = findChessboardCorners(color, projSettings.patternSize,
+                                                  projPointBuf, calibFlags);
+
+                if( foundCam && foundProj )
+                {
+                    Mat gray;
+                    cvtColor(color, gray, COLOR_BGR2GRAY);
+                    cout << "found pattern" << endl;
+                    Mat projCorners, camCorners;
+                    cornerSubPix(gray, camPointBuf, camSettings.subpixelSize, Size(-1, -1),
+                            TermCriteria(TermCriteria::COUNT + TermCriteria::EPS, 30, 0.1));
+
+                    cornerSubPix(gray, projPointBuf, projSettings.subpixelSize, Size(-1, -1),
+                            TermCriteria(TermCriteria::COUNT + TermCriteria::EPS, 30, 0.1));
+
+                    drawChessboardCorners(gray, camSettings.patternSize, camPointBuf, foundCam);
+                    drawChessboardCorners(gray, projSettings.patternSize, projPointBuf, foundProj);
+
+                    imshow("camera view", gray);
+                    char c = (char)waitKey(0);
+                    if( c == 10 )
+                    {
+                        cout << "saving pattern #" << nbrOfValidFrames << " for calibration" << endl;
+                        ostringstream name;
+                        name << nbrOfValidFrames;
+                        nbrOfValidFrames += 1;
+
+                        imagePointsCam.push_back(camPointBuf);
+                        imagePointsProj.push_back(projPointBuf);
+                        objectPointsCam.push_back(tempCam);
+                        PointsInProj.push_back(tempProj);
+                        images.push_back(frame);
+
+                        Mat ptsProjProj, ptsProjCam;
+                        Mat ptsProjProjN, ptsProjCamN;
+                        Mat TProjProj, TProjCam;
+                        vector<Point2f> ptsProjProjVec;
+                        vector<Point2f> ptsProjCamVec;
+
+                        fromVectorToMat(tempProj, ptsProjProj);
+                        normalize(ptsProjProj, 2, ptsProjProjN, TProjProj);
+                        fromMatToVector(ptsProjProjN, ptsProjProjVec);
+                        pointsInProjN.push_back(ptsProjProjVec);
+                        T2.push_back(TProjProj);
+                        projInProj.push_back(ptsProjProj);
+                        projInProjN.push_back(ptsProjProjN);
+
+                        fromVectorToMat(projPointBuf, ptsProjCam);
+                        normalize(ptsProjCam, 2, ptsProjCamN, TProjCam);
+                        fromMatToVector(ptsProjCamN, ptsProjCamVec);
+                        imagePointsProjN.push_back(ptsProjCamVec);
+                        T1.push_back(TProjCam);
+                        projInCam.push_back(ptsProjCam);
+                        projInCamN.push_back(ptsProjCamN);
+
+                    }
+                    else if( c == 32 )
+                    {
+                       cout << "capture discarded" << endl;
+                    }
+                    else if( c == 27 )
+                    {
+                        cout << "closing program" << endl;
+                        return -1;
+                    }
+                }
+                else
+                {
+                    cout << "no pattern found, move board and press any key" << endl;
+                    imshow("camera view", frame);
+                    waitKey(0);
+                }
+            }
+        }
+    }
+
+    saveCalibrationData(outputName + "_points.yml", T1, T2, projInCam, projInProj, projInCamN, projInProjN);
+
+    double rms = calibrate(objectPointsCam, imagePointsCam, cameraMatrix, distCoeffs,
+                          rVecs, tVecs, camSettings.imageSize);
+    cout << "rms = " << rms << endl;
+    cout << "camera matrix = \n" << cameraMatrix << endl;
+    cout << "dist coeffs = \n" << distCoeffs << endl;
+
+    fromCamToWorld(cameraMatrix, rVecs, tVecs, imagePointsProj, worldPointsProj);
+
+    rms = calibrate(worldPointsProj, PointsInProj, projectorMatrix, projectorDistCoeffs,
+                    projectorRVecs, projectorTVecs, projSettings.imageSize);
+
+    cout << "rms = " << rms << endl;
+    cout << "projector matrix = \n" << projectorMatrix << endl;
+    cout << "projector dist coeffs = \n" << distCoeffs << endl;
+
+    Mat stereoR, stereoT, essential, fundamental;
+    Mat RCam, RProj, PCam, PProj, Q;
+    rms = stereoCalibrate(worldPointsProj, imagePointsProj, PointsInProj, cameraMatrix, distCoeffs,
+                projectorMatrix, projectorDistCoeffs, camSettings.imageSize, stereoR, stereoT,
+                essential, fundamental);
+
+    cout << "stereo calibrate: \n" << fundamental << endl;
+
+    saveCalibrationResults(outputName, cameraMatrix, distCoeffs, projectorMatrix, projectorDistCoeffs, fundamental );
+    return 0;
+}
+
+Settings::Settings(){
+    patternType = CHESSBOARD;
+    patternSize = Size(13, 9);
+    subpixelSize = Size(11, 11);
+    squareSize = 50;
+    nbrOfFrames = 25;
+}
+
+void loadSettings( String path, Settings &sttngs )
+{
+    FileStorage fsInput(path, FileStorage::READ);
+
+    fsInput["PatternWidth"] >> sttngs.patternSize.width;
+    fsInput["PatternHeight"] >> sttngs.patternSize.height;
+    fsInput["SubPixelWidth"] >> sttngs.subpixelSize.width;
+    fsInput["SubPixelHeight"] >> sttngs.subpixelSize.height;
+    fsInput["SquareSize"] >> sttngs.squareSize;
+    fsInput["NbrOfFrames"] >> sttngs.nbrOfFrames;
+    fsInput["PatternType"] >> sttngs.patternType;
+    fsInput.release();
+}
+
+double calibrate( vector< vector<Point3f> > objPoints, vector< vector<Point2f> > imgPoints,
+               Mat &cameraMatrix, Mat &distCoeffs, vector<Mat> &r, vector<Mat> &t, Size imgSize )
+{
+    int calibFlags = 0;
+
+    double rms = calibrateCamera(objPoints, imgPoints, imgSize, cameraMatrix,
+                                distCoeffs, r, t, calibFlags);
+
+    return rms;
+}
+
+void createObjectPoints( vector<Point3f> &patternCorners, Size patternSize, float squareSize,
+                         int patternType )
+{
+    switch( patternType )
+    {
+        case CHESSBOARD:
+        case CIRCLES_GRID:
+            for( int i = 0; i < patternSize.height; ++i )
+            {
+                for( int j = 0; j < patternSize.width; ++j )
+                {
+                    patternCorners.push_back(Point3f(float(i*squareSize), float(j*squareSize), 0));
+                }
+            }
+            break;
+        case ASYMETRIC_CIRCLES_GRID:
+            break;
+    }
+}
+
+void createProjectorObjectPoints( vector<Point2f> &patternCorners, Size patternSize, float squareSize,
+                        int patternType )
+{
+    switch( patternType )
+    {
+        case CHESSBOARD:
+        case CIRCLES_GRID:
+            for( int i = 1; i <= patternSize.height; ++i )
+            {
+                for( int j = 1; j <= patternSize.width; ++j )
+                {
+                    patternCorners.push_back(Point2f(float(j*squareSize), float(i*squareSize)));
+                }
+            }
+            break;
+        case ASYMETRIC_CIRCLES_GRID:
+            break;
+    }
+}
+
+void fromCamToWorld( Mat cameraMatrix, vector<Mat> rV, vector<Mat> tV,
+                    vector< vector<Point2f> > imgPoints, vector< vector<Point3f> > &worldPoints )
+{
+    int s = (int) rV.size();
+    Mat invK64, invK;
+    invK64 = cameraMatrix.inv();
+    invK64.convertTo(invK, CV_32F);
+
+    for(int i = 0; i < s; ++i)
+    {
+        Mat r, t, rMat;
+        rV[i].convertTo(r, CV_32F);
+        tV[i].convertTo(t, CV_32F);
+
+        Rodrigues(r, rMat);
+        Mat transPlaneToCam = rMat.inv()*t;
+
+        vector<Point3f> wpTemp;
+        int s2 = (int) imgPoints[i].size();
+        for(int j = 0; j < s2; ++j){
+            Mat coords(3, 1, CV_32F);
+            coords.at<float>(0, 0) = imgPoints[i][j].x;
+            coords.at<float>(1, 0) = imgPoints[i][j].y;
+            coords.at<float>(2, 0) = 1.0f;
+
+            Mat worldPtCam = invK*coords;
+            Mat worldPtPlane = rMat.inv()*worldPtCam;
+
+            float scale = transPlaneToCam.at<float>(2)/worldPtPlane.at<float>(2);
+            Mat worldPtPlaneReproject = scale*worldPtPlane - transPlaneToCam;
+
+            Point3f pt;
+            pt.x = worldPtPlaneReproject.at<float>(0);
+            pt.y = worldPtPlaneReproject.at<float>(1);
+            pt.z = 0;
+            wpTemp.push_back(pt);
+        }
+        worldPoints.push_back(wpTemp);
+    }
+}
+
+void saveCalibrationResults( String path, Mat camK, Mat camDistCoeffs, Mat projK, Mat projDistCoeffs,
+                      Mat fundamental )
+{
+    FileStorage fs(path + ".yml", FileStorage::WRITE);
+    fs << "camIntrinsics" << camK;
+    fs << "camDistCoeffs" << camDistCoeffs;
+    fs << "projIntrinsics" << projK;
+    fs << "projDistCoeffs" << projDistCoeffs;
+    fs << "fundamental" << fundamental;
+    fs.release();
+}
+
+void saveCalibrationData( String path, vector<Mat> T1, vector<Mat> T2, vector<Mat> ptsProjCam, vector<Mat> ptsProjProj, vector<Mat> ptsProjCamN, vector<Mat> ptsProjProjN )
+{
+    FileStorage fs(path + ".yml", FileStorage::WRITE);
+
+    int size = (int) T1.size();
+    fs << "size" << size;
+    for( int i = 0; i < (int)T1.size(); ++i )
+    {
+        ostringstream nbr;
+        nbr << i;
+        fs << "TprojCam" + nbr.str() << T1[i];
+        fs << "TProjProj" + nbr.str() << T2[i];
+        fs << "ptsProjCam" + nbr.str() << ptsProjCam[i];
+        fs << "ptsProjProj" + nbr.str() << ptsProjProj[i];
+        fs << "ptsProjCamN" + nbr.str() << ptsProjCamN[i];
+        fs << "ptsProjProjN" + nbr.str() << ptsProjProjN[i];
+    }
+    fs.release();
+
+}
+
+void normalize( const Mat &pts, const int& dim, Mat& normpts, Mat &T )
+{
+    float averagedist = 0;
+    float scale = 0;
+
+    //centroid
+
+    Mat centroid(dim,1,CV_32F);
+    Scalar tmp;
+
+    if( normpts.empty() )
+    {
+        normpts= Mat(pts.rows,pts.cols,CV_32F);
+    }
+
+    for( int i = 0 ; i < dim ; ++i )
+    {
+        tmp = mean(pts.row(i));
+        centroid.at<float>(i,0) = (float)tmp[0];
+        subtract(pts.row(i), centroid.at<float>(i, 0), normpts.row(i));
+    }
+
+    //average distance
+
+    Mat ptstmp;
+    for( int i = 0 ; i < normpts.cols; ++i )
+    {
+        ptstmp = normpts.col(i);
+        averagedist = averagedist+(float)norm(ptstmp);
+    }
+    averagedist = averagedist / normpts.cols;
+    scale = (float)(sqrt(dim) / averagedist);
+
+    normpts = normpts * scale;
+
+    T=cv::Mat::eye(dim+1,dim+1,CV_32F);
+    for( int i = 0; i < dim; ++i )
+    {
+        T.at<float>(i, i) = scale;
+        T.at<float>(i, dim) = -scale*centroid.at<float>(i, 0);
+    }
+}
+
+void fromVectorToMat( vector<Point2f> v, Mat &pts )
+{
+    int nbrOfPoints = (int) v.size();
+
+    if( pts.empty() )
+        pts.create(2, nbrOfPoints, CV_32F);
+
+    for( int i = 0; i < nbrOfPoints; ++i )
+    {
+        pts.at<float>(0, i) = v[i].x;
+        pts.at<float>(1, i) = v[i].y;
+    }
+}
+
+void fromMatToVector( Mat pts, vector<Point2f> &v )
+{
+    int nbrOfPoints = pts.cols;
+
+    for( int i = 0; i < nbrOfPoints; ++i )
+    {
+        Point2f temp;
+        temp.x = pts.at<float>(0, i);
+        temp.y = pts.at<float>(1, i);
+        v.push_back(temp);
+    }
+}
\ No newline at end of file
diff --git a/contrib/modules/structured_light/src/graycodepattern.cpp b/contrib/modules/structured_light/src/graycodepattern.cpp
index d3df7aa..ff56a02 100644
--- a/contrib/modules/structured_light/src/graycodepattern.cpp
+++ b/contrib/modules/structured_light/src/graycodepattern.cpp
@@ -471,5 +471,15 @@ Ptr<GrayCodePattern> GrayCodePattern::create( const GrayCodePattern::Params& par
   return makePtr<GrayCodePattern_Impl>( params );
 }
 
+// Creates the GrayCodePattern instance
+// alias for scripting
+Ptr<GrayCodePattern> GrayCodePattern::create( int width, int height )
+{
+  Params params;
+  params.width = width;
+  params.height = height;
+  return makePtr<GrayCodePattern_Impl>( params );
+}
+
 }
 }
diff --git a/contrib/modules/structured_light/src/sinusoidalpattern.cpp b/contrib/modules/structured_light/src/sinusoidalpattern.cpp
new file mode 100644
index 0000000..bc26b20
--- /dev/null
+++ b/contrib/modules/structured_light/src/sinusoidalpattern.cpp
@@ -0,0 +1,919 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+ //
+ //  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+ //
+ //  By downloading, copying, installing or using the software you agree to this license.
+ //  If you do not agree to this license, do not download, install,
+ //  copy or use the software.
+ //
+ //
+ //                           License Agreement
+ //                For Open Source Computer Vision Library
+ //
+ // Copyright (C) 2015, OpenCV Foundation, all rights reserved.
+ // Third party copyrights are property of their respective owners.
+ //
+ // Redistribution and use in source and binary forms, with or without modification,
+ // are permitted provided that the following conditions are met:
+ //
+ //   * Redistribution's of source code must retain the above copyright notice,
+ //     this list of conditions and the following disclaimer.
+ //
+ //   * Redistribution's in binary form must reproduce the above copyright notice,
+ //     this list of conditions and the following disclaimer in the documentation
+ //     and/or other materials provided with the distribution.
+ //
+ //   * The name of the copyright holders may not be used to endorse or promote products
+ //     derived from this software without specific prior written permission.
+ //
+ // This software is provided by the copyright holders and contributors "as is" and
+ // any express or implied warranties, including, but not limited to, the implied
+ // warranties of merchantability and fitness for a particular purpose are disclaimed.
+ // In no event shall the Intel Corporation or contributors be liable for any direct,
+ // indirect, incidental, special, exemplary, or consequential damages
+ // (including, but not limited to, procurement of substitute goods or services;
+ // loss of use, data, or profits; or business interruption) however caused
+ // and on any theory of liability, whether in contract, strict liability,
+ // or tort (including negligence or otherwise) arising in any way out of
+ // the use of this software, even if advised of the possibility of such damage.
+ //
+ //M*/
+
+
+#include "precomp.hpp"
+
+namespace cv {
+namespace structured_light {
+class CV_EXPORTS_W SinusoidalPatternProfilometry_Impl : public SinusoidalPattern
+{
+public:
+    // Constructor
+    explicit SinusoidalPatternProfilometry_Impl( const SinusoidalPattern::Params &parameters =
+                                                 SinusoidalPattern::Params() );
+    // Destructor
+    virtual ~SinusoidalPatternProfilometry_Impl(){};
+
+    // Generate sinusoidal patterns
+    bool generate( OutputArrayOfArrays patternImages );
+
+    bool decode( InputArrayOfArrays patternImages, OutputArray disparityMap,
+                InputArrayOfArrays blackImages = noArray(), InputArrayOfArrays whiteImages =
+                noArray(), int flags = 0 ) const;
+
+    // Compute a wrapped phase map from the sinusoidal patterns
+    void computePhaseMap( InputArrayOfArrays patternImages, OutputArray wrappedPhaseMap,
+                         OutputArray shadowMask = noArray(), InputArray fundamental = noArray());
+    // Unwrap the wrapped phase map to retrieve correspondences
+    void unwrapPhaseMap( InputArray wrappedPhaseMap,
+                         OutputArray unwrappedPhaseMap,
+                         cv::Size camSize,
+                         InputArray shadowMask = noArray() );
+    // Find correspondences between the devices
+    void findProCamMatches( InputArray projUnwrappedPhaseMap, InputArray camUnwrappedPhaseMap,
+                            OutputArrayOfArrays matches );
+
+    void computeDataModulationTerm( InputArrayOfArrays patternImages,
+                                    OutputArray dataModulationTerm,
+                                    InputArray shadowMask );
+
+private:
+    // Compute The Fourier transform of a pattern. Output is complex. Taken from the DFT example in OpenCV
+    void computeDft( InputArray patternImage, OutputArray FourierTransform );
+    // Compute the inverse Fourier transform. Output can be complex or real
+    void computeInverseDft( InputArray FourierTransform, OutputArray inverseFourierTransform,
+                            bool realOutput );
+    // Compute the DFT magnitude which is used to find maxima in the spectrum
+    void computeDftMagnitude( InputArray FourierTransform, OutputArray FourierTransformMagnitude );
+    // Compute phase map from the complex signal given by non-symmetrical filtering of DFT
+    void computeFtPhaseMap( InputArray inverseFourierTransform,
+                            InputArray shadowMask,
+                            OutputArray wrappedPhaseMap );
+    // Swap DFT quadrants. Come from opencv example
+    void swapQuadrants( InputOutputArray image, int centerX, int centerY );
+    // Filter (non)-symmetrically the DFT.
+    void frequencyFiltering( InputOutputArray FourierTransform, int centerX1, int centerY1,
+                             int halfRegionWidth, int halfRegionHeight, bool keepInsideRegion,
+                             int centerX2 = -1, int centerY2 = -1 );
+    // Find maxima in the spectrum so that we know how it should be filtered
+    bool findMaxInHalvesTransform( InputArray FourierTransformMag, Point &maxPosition1,
+                                  Point &maxPosition2 );
+    // Compute phase map from the three sinusoidal patterns
+    void computePsPhaseMap( InputArrayOfArrays patternImages,
+                            InputArray shadowMask,
+                            OutputArray wrappedPhaseMap );
+
+    void computeFapsPhaseMap( InputArray a, InputArray b, InputArray theta1, InputArray theta2,
+                              InputArray shadowMask, OutputArray wrappedPhaseMap );
+    // Compute a shadow mask to discard shadow regions
+    void computeShadowMask( InputArrayOfArrays patternImages, OutputArray shadowMask );
+    // Data modulation term is used to isolate cross markers
+
+    void extractMarkersLocation( InputArray dataModulationTerm,
+                                 std::vector<Point> &markersLocation );
+
+    void convertToAbsolutePhaseMap( InputArrayOfArrays camPatterns,
+                                    InputArray unwrappedProjPhaseMap,
+                                    InputArray unwrappedCamPhaseMap,
+                                    InputArray shadowMask,
+                                    InputArray fundamentalMatrix );
+
+    Params params;
+    phase_unwrapping::HistogramPhaseUnwrapping::Params unwrappingParams;
+    // Class describing markers that are added to the patterns
+    class Marker{
+    private:
+        Point center, up, right, left, down;
+    public:
+        Marker();
+        Marker( Point c );
+        void drawMarker( OutputArray pattern );
+    };
+};
+// Default parameters value
+SinusoidalPattern::Params::Params()
+{
+    width = 800;
+    height = 600;
+    nbrOfPeriods = 20;
+    shiftValue = (float)(2 * CV_PI / 3);
+    methodId = FAPS;
+    nbrOfPixelsBetweenMarkers = 56;
+    horizontal = false;
+    setMarkers = false;
+}
+SinusoidalPatternProfilometry_Impl::Marker::Marker(){};
+
+SinusoidalPatternProfilometry_Impl::Marker::Marker( Point c )
+{
+    center = c;
+    up.x = c.x;
+    up.y = c.y - 1;
+    left.x = c.x - 1;
+    left.y = c.y;
+
+    down.x = c.x;
+    down.y = c.y + 1;
+    right.x = c.x + 1;
+    right.y = c.y;
+}
+// Draw marker on a pattern
+void SinusoidalPatternProfilometry_Impl::Marker::drawMarker( OutputArray pattern )
+{
+    Mat &pattern_ = *(Mat*) pattern.getObj();
+
+    pattern_.at<uchar>(center.x, center.y) = 255;
+    pattern_.at<uchar>(up.x, up.y) = 255;
+    pattern_.at<uchar>(right.x, right.y) = 255;
+    pattern_.at<uchar>(left.x, left.y) = 255;
+    pattern_.at<uchar>(down.x, down.y) = 255;
+}
+
+SinusoidalPatternProfilometry_Impl::SinusoidalPatternProfilometry_Impl(
+        const SinusoidalPattern::Params &parameters ) : params(parameters)
+{
+
+}
+// Generate sinusoidal patterns. Markers are optional
+bool SinusoidalPatternProfilometry_Impl::generate( OutputArrayOfArrays pattern )
+{
+    // Three patterns are used in the reference paper.
+    int nbrOfPatterns = 3;
+    float meanAmpl = 127.5;
+    float sinAmpl = 127.5;
+    // Period in number of pixels
+    int period;
+    float frequency;
+    // m and n are parameters described in the reference paper
+    int m = params.nbrOfPixelsBetweenMarkers;
+    int n;
+    // Offset for the first marker of the first row.
+    int firstMarkerOffset = 10;
+    int mnRatio;
+    int nbrOfMarkersOnOneRow;
+    std::vector<Mat> &pattern_ = *(std::vector<Mat>*) pattern.getObj();
+
+    n = params.nbrOfPeriods / nbrOfPatterns;
+    mnRatio = m / n;
+
+    pattern_.resize(nbrOfPatterns);
+
+    if( params.horizontal )
+    {
+        period = params.height / params.nbrOfPeriods;
+        nbrOfMarkersOnOneRow = (int)floor((params.width - firstMarkerOffset) / m);
+    }
+    else
+    {
+        period = params.width / params.nbrOfPeriods;
+        nbrOfMarkersOnOneRow = (int)floor((params.height - firstMarkerOffset) / m);
+    }
+    frequency = (float) 1 / period;
+
+    for( int i = 0; i < nbrOfPatterns; ++i )
+    {
+        pattern_[i] = Mat(params.height, params.width, CV_8UC1);
+
+        if( params.horizontal )
+        pattern_[i] = pattern_[i].t();
+    }
+    // Patterns vary along one direction only so, a row Mat can be created and copied to the pattern's rows
+    for( int i = 0; i < nbrOfPatterns; ++i )
+    {
+        Mat rowValues(1, pattern_[i].cols, CV_8UC1);
+
+        for( int j = 0; j < pattern_[i].cols; ++j )
+        {
+            rowValues.at<uchar>(0, j) = saturate_cast<uchar>(
+                    meanAmpl + sinAmpl * sin(2 * CV_PI * frequency * j + i * params.shiftValue));
+        }
+
+        for( int j = 0; j < pattern_[i].rows; ++j )
+        {
+            rowValues.row(0).copyTo(pattern_[i].row(j));
+        }
+    }
+    // Add cross markers to the patterns.
+    if( params.setMarkers )
+    {
+        for( int i = 0; i < nbrOfPatterns; ++i )
+        {
+            for( int j = 0; j < n; ++j )
+            {
+                for( int k = 0; k < nbrOfMarkersOnOneRow; ++k )
+                {
+                    Marker mark(Point(firstMarkerOffset + k * m + j * mnRatio,
+                            3 * period / 4 + j * period + i * period * n  - i * period / 3));
+                    mark.drawMarker(pattern_[i]);
+                    params.markersLocation.push_back(Point2f((float)(firstMarkerOffset + k * m + j * mnRatio),
+                            (float) (3 * period / 4 + j * period + i * period * n  - i * period / 3)));
+                }
+            }
+        }
+    }
+    if( params.horizontal )
+        for( int i = 0; i < nbrOfPatterns; ++i )
+        {
+            pattern_[i] = pattern_[i].t();
+        }
+    return true;
+}
+
+bool SinusoidalPatternProfilometry_Impl::decode( InputArrayOfArrays patternImages,
+                                                OutputArray disparityMap,
+                                                InputArrayOfArrays blackImages,
+                                                InputArrayOfArrays whiteImages, int flags ) const
+{
+    (void) patternImages;
+    (void) disparityMap;
+    (void) blackImages;
+    (void) whiteImages;
+    (void) flags;
+    return true;
+}
+// Most of the steps described in the paper to get the wrapped phase map take place here
+void SinusoidalPatternProfilometry_Impl::computePhaseMap( InputArrayOfArrays patternImages,
+                                                          OutputArray wrappedPhaseMap,
+                                                          OutputArray shadowMask,
+                                                          InputArray fundamental  )
+{
+    std::vector<Mat> &pattern_ = *(std::vector<Mat>*) patternImages.getObj();
+    Mat &wrappedPhaseMap_ = *(Mat*) wrappedPhaseMap.getObj();
+    int rows = pattern_[0].rows;
+    int cols = pattern_[0].cols;
+    int dcWidth = 5;
+    int dcHeight = 5;
+    int bpWidth = 21;
+    int bpHeight = 21;
+    // Compute wrapped phase map for FTP
+    if( params.methodId == FTP )
+    {
+        Mat &shadowMask_ = *(Mat*) shadowMask.getObj();
+        Mat dftImage, complexInverseDft;
+        Mat dftMag;
+        int halfWidth = cols/2;
+        int halfHeight = rows/2;
+        Point m1, m2;
+        computeShadowMask(pattern_, shadowMask_);
+
+        computeDft(pattern_[0], dftImage); //compute the complex pattern DFT
+        swapQuadrants(dftImage, halfWidth, halfHeight); //swap quadrants to get 0 frequency in (halfWidth, halfHeight)
+        frequencyFiltering(dftImage, halfHeight, halfWidth, dcHeight, dcWidth, false); //get rid of 0 frequency
+        computeDftMagnitude(dftImage, dftMag); //compute magnitude to find maxima
+        findMaxInHalvesTransform(dftMag, m1, m2); //look for maxima in the magnitude. Useful information is located around maxima
+        frequencyFiltering(dftImage, m2.y, m2.x, bpHeight, bpWidth, true); //keep useful information only
+        swapQuadrants(dftImage,halfWidth, halfHeight); //swap quadrants again to compute inverse dft
+        computeInverseDft(dftImage, complexInverseDft, false); //compute inverse dft. Result is complex since we only keep half of the spectrum
+        computeFtPhaseMap(complexInverseDft, shadowMask_, wrappedPhaseMap_); //compute phaseMap from the complex image.
+    }
+    // Compute wrapped pahse map for PSP
+    else if( params.methodId == PSP )
+    {
+        Mat &shadowMask_ = *(Mat*) shadowMask.getObj();
+        //Mat &fundamental_ = *(Mat*) fundamental.getObj();
+        (void) fundamental;
+        Mat dmt;
+        int nbrOfPatterns = static_cast<int>(pattern_.size());
+        std::vector<Mat> filteredPatterns(nbrOfPatterns);
+        std::vector<Mat> dftImages(nbrOfPatterns);
+        std::vector<Mat> dftMags(nbrOfPatterns);
+        int halfWidth = cols/2;
+        int halfHeight = rows/2;
+        Point m1, m2;
+
+        computeShadowMask(pattern_, shadowMask_);
+
+        //this loop symmetrically filters pattern to remove cross markers.
+        for( int i = 0; i < nbrOfPatterns; ++i )
+        {
+            computeDft(pattern_[i], dftImages[i]);
+            swapQuadrants(dftImages[i], halfWidth, halfHeight);
+            frequencyFiltering(dftImages[i], halfHeight, halfWidth, dcHeight, dcWidth, false);
+            computeDftMagnitude(dftImages[i], dftMags[i]);
+            findMaxInHalvesTransform(dftMags[i], m1, m2);
+            frequencyFiltering(dftImages[i], m1.y, m1.x, bpHeight, bpWidth, true, m2.y, m2.x);//symmetrical filtering
+            swapQuadrants(dftImages[i], halfWidth, halfHeight);
+            computeInverseDft(dftImages[i], filteredPatterns[i], true);
+
+        }
+        computePsPhaseMap(filteredPatterns, shadowMask_, wrappedPhaseMap_);
+    }
+    else if( params.methodId == FAPS )
+    {
+        Mat &shadowMask_ = *(Mat*) shadowMask.getObj();
+        int nbrOfPatterns = static_cast<int>(pattern_.size());
+        std::vector<Mat> unwrappedFTPhaseMaps;
+        std::vector<Mat> filteredPatterns(nbrOfPatterns);
+        Mat dmt;
+        Mat theta1, theta2, a, b;
+        std::vector<Point> markersLoc;
+        cv::Size camSize;
+        camSize.height = pattern_[0].rows;
+        camSize.width = pattern_[0].cols;
+        computeShadowMask(pattern_, shadowMask_);
+
+        for( int i = 0; i < nbrOfPatterns; ++i )
+        {
+            Mat dftImage, complexInverseDft;
+            Mat dftMag;
+            Mat tempWrappedPhaseMap;
+            Mat tempUnwrappedPhaseMap;
+            int halfWidth = cols/2;
+            int halfHeight = rows/2;
+            Point m1, m2;
+
+            computeDft(pattern_[i], dftImage); //compute the complex pattern DFT
+            swapQuadrants(dftImage, halfWidth, halfHeight); //swap quadrants to get 0 frequency in (halfWidth, halfHeight)
+            frequencyFiltering(dftImage, halfHeight, halfWidth, dcHeight, dcWidth, false); //get rid of 0 frequency
+            computeDftMagnitude(dftImage, dftMag); //compute magnitude to find maxima
+            findMaxInHalvesTransform(dftMag, m1, m2); //look for maxima in the magnitude. Useful information is located around maxima
+            frequencyFiltering(dftImage, m2.y, m2.x, bpHeight, bpWidth, true); //keep useful information only
+            swapQuadrants(dftImage,halfWidth, halfHeight); //swap quadrants again to compute inverse dft
+            computeInverseDft(dftImage, complexInverseDft, false); //compute inverse dft. Result is complex since we only keep half of the spectrum
+            computeFtPhaseMap(complexInverseDft, shadowMask_, tempWrappedPhaseMap); //compute phaseMap from the complex image.
+            unwrapPhaseMap(tempWrappedPhaseMap, tempUnwrappedPhaseMap, camSize, shadowMask);
+            unwrappedFTPhaseMaps.push_back(tempUnwrappedPhaseMap);
+            computeInverseDft(dftImage, filteredPatterns[i], true);
+        }
+
+        theta1.create(camSize.height, camSize.width, unwrappedFTPhaseMaps[0].type());
+        theta2.create(camSize.height, camSize.width, unwrappedFTPhaseMaps[0].type());
+        a.create(camSize.height, camSize.width, CV_32FC1);
+        b.create(camSize.height, camSize.width, CV_32FC1);
+
+        a = filteredPatterns[0] - filteredPatterns[1];
+        b = filteredPatterns[1] - filteredPatterns[2];
+
+        theta1 = unwrappedFTPhaseMaps[1] - unwrappedFTPhaseMaps[0];
+        theta2 = unwrappedFTPhaseMaps[2] - unwrappedFTPhaseMaps[1];
+
+        computeFapsPhaseMap(a, b, theta1, theta2, shadowMask_, wrappedPhaseMap_);
+    }
+}
+
+void SinusoidalPatternProfilometry_Impl::unwrapPhaseMap( InputArray wrappedPhaseMap,
+                                                         OutputArray unwrappedPhaseMap,
+                                                         cv::Size camSize,
+                                                         InputArray shadowMask )
+{
+    int rows = params.height;
+    int cols = params.width;
+    unwrappingParams.width = camSize.width;
+    unwrappingParams.height = camSize.height;
+
+    Mat &wPhaseMap = *(Mat*) wrappedPhaseMap.getObj();
+    Mat &uPhaseMap = *(Mat*) unwrappedPhaseMap.getObj();
+    Mat mask;
+
+    if( shadowMask.empty() )
+    {
+        mask.create(rows, cols, CV_8UC1);
+        mask = Scalar::all(255);
+    }
+    else
+    {
+        Mat &temp = *(Mat*) shadowMask.getObj();
+        temp.copyTo(mask);
+    }
+
+    Ptr<phase_unwrapping::HistogramPhaseUnwrapping> phaseUnwrapping =
+            phase_unwrapping::HistogramPhaseUnwrapping::create(unwrappingParams);
+
+    phaseUnwrapping->unwrapPhaseMap(wPhaseMap, uPhaseMap, mask);
+}
+
+void SinusoidalPatternProfilometry_Impl::findProCamMatches( InputArray projUnwrappedPhaseMap,
+                                                            InputArray camUnwrappedPhaseMap,
+                                                            OutputArrayOfArrays matches )
+{
+    (void) projUnwrappedPhaseMap;
+    (void) camUnwrappedPhaseMap;
+    (void) matches;
+}
+
+void SinusoidalPatternProfilometry_Impl::computeDft( InputArray patternImage,
+                                                     OutputArray FourierTransform )
+{
+    Mat &pattern_ = *(Mat*) patternImage.getObj();
+    Mat &FourierTransform_ = *(Mat*) FourierTransform.getObj();
+    Mat padded;
+    int m = getOptimalDFTSize(pattern_.rows);
+    int n = getOptimalDFTSize(pattern_.cols);
+    copyMakeBorder(pattern_, padded, 0, m - pattern_.rows, 0, n - pattern_.cols, BORDER_CONSTANT,
+                   Scalar::all(0));
+    Mat planes[] = {Mat_<float>(padded), Mat::zeros(padded.size(), CV_32F)};
+    merge(planes, 2, FourierTransform_);
+    dft(FourierTransform_, FourierTransform_);
+}
+
+void SinusoidalPatternProfilometry_Impl::computeInverseDft( InputArray FourierTransform,
+                                                           OutputArray inverseFourierTransform,
+                                                           bool realOutput )
+{
+    Mat &FourierTransform_ = *(Mat*) FourierTransform.getObj();
+    Mat &inverseFourierTransform_ = *(Mat*) inverseFourierTransform.getObj();
+    if( realOutput )
+        idft(FourierTransform_, inverseFourierTransform_, DFT_SCALE | DFT_REAL_OUTPUT);
+    else
+        idft(FourierTransform_, inverseFourierTransform_, DFT_SCALE);
+}
+
+void SinusoidalPatternProfilometry_Impl::computeDftMagnitude( InputArray FourierTransform,
+                                                              OutputArray FourierTransformMagnitude )
+{
+    Mat &FourierTransform_ = *(Mat*) FourierTransform.getObj();
+    Mat &FourierTransformMagnitude_ = *(Mat*) FourierTransformMagnitude.getObj();
+    Mat planes[2];
+    split(FourierTransform_, planes);
+    magnitude(planes[0], planes[1], planes[0]);
+    FourierTransformMagnitude_ = planes[0];
+    FourierTransformMagnitude_ += Scalar::all(1);
+    log(FourierTransformMagnitude_, FourierTransformMagnitude_);
+    FourierTransformMagnitude_ = FourierTransformMagnitude_(
+            Rect(0, 0, FourierTransformMagnitude_.cols & -2, FourierTransformMagnitude_.rows & - 2));
+    normalize(FourierTransformMagnitude_, FourierTransformMagnitude_, 0, 1, NORM_MINMAX);
+}
+
+void SinusoidalPatternProfilometry_Impl::computeFtPhaseMap( InputArray inverseFourierTransform,
+                                                            InputArray shadowMask,
+                                                            OutputArray wrappedPhaseMap )
+{
+
+    Mat &inverseFourierTransform_ = *(Mat*) inverseFourierTransform.getObj();
+    Mat &wrappedPhaseMap_ = *(Mat*) wrappedPhaseMap.getObj();
+    Mat &shadowMask_ = *(Mat*) shadowMask.getObj();
+    Mat planes[2];
+
+    int rows = inverseFourierTransform_.rows;
+    int cols = inverseFourierTransform_.cols;
+
+    if( wrappedPhaseMap_.empty () )
+        wrappedPhaseMap_.create(rows, cols, CV_32FC1);
+
+    split(inverseFourierTransform_, planes);
+
+    for( int i = 0; i < rows; ++i )
+    {
+        for( int j = 0; j < cols; ++j )
+        {
+            if( shadowMask_.at<uchar>(i, j) != 0 )
+            {
+                float im = planes[1].at<float>(i, j);
+                float re = planes[0].at<float>(i, j);
+                wrappedPhaseMap_.at<float>(i, j) = atan2(re, im);
+            }
+            else
+            {
+                wrappedPhaseMap_.at<float>(i, j) = 0;
+            }
+        }
+    }
+}
+void SinusoidalPatternProfilometry_Impl::swapQuadrants( InputOutputArray image,
+                                                       int centerX, int centerY )
+{
+    Mat &image_ = *(Mat*) image.getObj();
+    Mat q0(image_, Rect(0, 0, centerX, centerY));
+    Mat q1(image_, Rect(centerX, 0, centerX, centerY));
+    Mat q2(image_, Rect(0, centerY, centerX, centerY));
+    Mat q3(image_, Rect(centerX, centerY, centerX, centerY));
+    Mat tmp;
+
+    q0.copyTo(tmp);
+    q3.copyTo(q0);
+    tmp.copyTo(q3);
+
+    q1.copyTo(tmp);
+    q2.copyTo(q1);
+    tmp.copyTo(q2);
+}
+
+void SinusoidalPatternProfilometry_Impl::frequencyFiltering( InputOutputArray FourierTransform,
+                                                             int centerX1, int centerY1,
+                                                             int halfRegionWidth, int halfRegionHeight,
+                                                             bool keepInsideRegion, int centerX2,
+                                                             int centerY2 )
+{
+    Mat &FourierTransform_ = *(Mat*) FourierTransform.getObj();
+    int rows = FourierTransform_.rows;
+    int cols = FourierTransform_.cols;
+    int type = FourierTransform_.type();
+    if( keepInsideRegion )
+    {
+        Mat maskedTransform(rows, cols, type);
+        maskedTransform = Scalar::all(0);
+        Mat roi1 = FourierTransform_(
+                Rect(centerY1 - halfRegionHeight, centerX1 - halfRegionWidth,
+                    2 * halfRegionHeight, 2 * halfRegionWidth));
+        Mat dstRoi1 = maskedTransform(
+                Rect(centerY1 - halfRegionHeight, centerX1 - halfRegionWidth,
+                    2 * halfRegionHeight, 2 * halfRegionWidth));
+        roi1.copyTo(dstRoi1);
+
+        if( centerY2 != -1 || centerX2 != -1 )
+        {
+            Mat roi2 = FourierTransform_(
+                    Rect(centerY2 - halfRegionHeight, centerX2 - halfRegionWidth,
+                        2 * halfRegionHeight, 2 * halfRegionWidth));
+            Mat dstRoi2 = maskedTransform(
+                    Rect(centerY2 - halfRegionHeight, centerX2 - halfRegionWidth,
+                        2 * halfRegionHeight, 2 * halfRegionWidth));
+            roi2.copyTo(dstRoi2);
+        }
+        FourierTransform_ = maskedTransform;
+    }
+    else
+    {
+        Mat roi(2 * halfRegionHeight, 2 * halfRegionWidth, type);
+        roi = Scalar::all(0);
+
+        Mat dstRoi1 = FourierTransform_(
+                Rect(centerY1 - halfRegionHeight, centerX1 - halfRegionWidth,
+                    2 * halfRegionHeight, 2 * halfRegionWidth));
+        roi.copyTo(dstRoi1);
+
+        if( centerY2 != -1 || centerX2 != -1 )
+        {
+            Mat dstRoi2 = FourierTransform_(
+                    Rect(centerY2 - halfRegionHeight, centerX2 - halfRegionWidth,
+                        2 * halfRegionHeight, 2 * halfRegionWidth));
+            roi.copyTo(dstRoi2);
+        }
+    }
+}
+bool SinusoidalPatternProfilometry_Impl::findMaxInHalvesTransform( InputArray FourierTransformMag,
+                                                                   Point &maxPosition1,
+                                                                   Point &maxPosition2 )
+{
+    Mat &FourierTransformMag_ = *(Mat*) FourierTransformMag.getObj();
+
+    int centerX = FourierTransformMag_.cols / 2;
+    int centerY = FourierTransformMag_.rows / 2;
+    Mat h0, h1;
+    double maxV1 = -1;
+    double maxV2 = -1;
+    int margin = 5;
+
+    if( params.horizontal )
+    {
+        h0 = FourierTransformMag_(Rect(0, 0, FourierTransformMag_.cols, centerY - margin));
+        h1 = FourierTransformMag_(
+                Rect(0, centerY + margin, FourierTransformMag_.cols, centerY - margin));
+    }
+    else
+    {
+        h0 = FourierTransformMag_(Rect(0, 0, centerX - margin, FourierTransformMag_.rows));
+        h1 = FourierTransformMag_(
+                Rect(centerX + margin, 0, centerX - margin, FourierTransformMag_.rows));
+    }
+
+    minMaxLoc(h0, NULL, &maxV1, NULL, &maxPosition1);
+    minMaxLoc(h1, NULL, &maxV2, NULL, &maxPosition2);
+
+    if( params.horizontal )
+    {
+        maxPosition2.y = maxPosition2.y + centerY + margin;
+    }
+    else
+    {
+        maxPosition2.x = maxPosition2.x + centerX + margin;
+    }
+
+    if( maxV1 == -1 || maxV2 == -1 )
+    {
+        return false;
+    }
+
+    return true;
+}
+
+void SinusoidalPatternProfilometry_Impl::computePsPhaseMap( InputArrayOfArrays patternImages,
+                                                            InputArray shadowMask,
+                                                            OutputArray wrappedPhaseMap )
+{
+    std::vector<Mat> &pattern_ = *(std::vector<Mat>*) patternImages.getObj();
+    Mat &wrappedPhaseMap_ = *(Mat*) wrappedPhaseMap.getObj();
+    Mat &shadowMask_ = *(Mat*) shadowMask.getObj();
+
+    int rows = pattern_[0].rows;
+    int cols = pattern_[0].cols;
+
+    float i1 = 0;
+    float i2 = 0;
+    float i3 = 0;
+
+    if( wrappedPhaseMap_.empty() )
+        wrappedPhaseMap_.create(rows, cols, CV_32FC1);
+
+    for( int i = 0; i < rows; ++i )
+    {
+        for( int j = 0; j < cols; ++j )
+        {
+            if( shadowMask_.at<uchar>(i, j) != 0 )
+            {
+                if( pattern_[0].type() == CV_8UC1 )
+                {
+                    i1 = pattern_[0].at<uchar>(i, j);
+                    i2 = pattern_[1].at<uchar>(i, j);
+                    i3 = pattern_[2].at<uchar>(i, j);
+                }
+                else if( pattern_[0].type() == CV_32FC1 )
+                {
+                    i1 = pattern_[0].at<float>(i, j);
+                    i2 = pattern_[1].at<float>(i, j);
+                    i3 = pattern_[2].at<float>(i, j);
+                }
+                float num = (1- cos(params.shiftValue)) * (i3 - i2);
+                float den = sin(params.shiftValue) * (2 * i1 - i2 - i3);
+                wrappedPhaseMap_.at<float>(i,j) = atan2(num, den);
+            }
+            else
+            {
+                wrappedPhaseMap_.at<float>(i,j) = 0;
+            }
+        }
+    }
+}
+
+void SinusoidalPatternProfilometry_Impl::computeFapsPhaseMap( InputArray a,
+                                                              InputArray b,
+                                                              InputArray theta1,
+                                                              InputArray theta2,
+                                                              InputArray shadowMask,
+                                                              OutputArray wrappedPhaseMap )
+{
+    Mat &a_ = *(Mat*) a.getObj();
+    Mat &b_ = *(Mat*) b.getObj();
+    Mat &theta1_ = *(Mat*) theta1.getObj();
+    Mat &theta2_ = *(Mat*) theta2.getObj();
+    Mat &wrappedPhaseMap_ = *(Mat*) wrappedPhaseMap.getObj();
+    Mat &shadowMask_ = *(Mat*) shadowMask.getObj();
+
+    int rows = a_.rows;
+    int cols = a_.cols;
+
+    if( wrappedPhaseMap_.empty() )
+        wrappedPhaseMap_.create(rows, cols, CV_32FC1);
+
+    for( int i = 0; i < rows; ++i )
+    {
+        for( int j = 0; j < cols; ++j )
+        {
+            if( shadowMask_.at<uchar>(i, j ) != 0 )
+            {
+                float num = (1 - cos(theta2_.at<float>(i, j))) * a_.at<float>(i, j) +
+                            (1 - cos(theta1_.at<float>(i, j))) * b_.at<float>(i, j);
+
+                float den = sin(theta1_.at<float>(i, j)) * b_.at<float>(i, j) -
+                            sin(theta2_.at<float>(i, j)) * a_.at<float>(i, j);
+
+                wrappedPhaseMap_.at<float>(i, j) = atan2(num, den);
+            }
+            else
+            {
+                wrappedPhaseMap_.at<float>(i, j) = 0;
+            }
+        }
+    }
+}
+
+//compute shadow mask from three patterns. Valid pixels are lit at least by one pattern
+void SinusoidalPatternProfilometry_Impl::computeShadowMask( InputArrayOfArrays patternImages,
+                                                            OutputArray shadowMask )
+{
+    std::vector<Mat> &patternImages_ = *(std::vector<Mat>*) patternImages.getObj();
+    Mat &shadowMask_ = *(Mat*) shadowMask.getObj();
+    Mat mean;
+    int rows = patternImages_[0].rows;
+    int cols = patternImages_[0].cols;
+    float i1, i2, i3;
+
+    mean.create(rows, cols, CV_32FC1);
+
+    for( int i = 0; i < rows; ++i )
+    {
+        for( int j = 0; j < cols; ++j )
+        {
+            i1 = (float) patternImages_[0].at<uchar>(i, j);
+            i2 = (float) patternImages_[1].at<uchar>(i, j);
+            i3 = (float) patternImages_[2].at<uchar>(i, j);
+            mean.at<float>(i, j) = (i1 + i2 + i3) / 3;
+        }
+    }
+    mean.convertTo(mean, CV_8UC1);
+    threshold(mean, shadowMask_, 10, 255, 0);
+
+}
+// Compute the data modulation term according to the formula given in the reference paper
+void SinusoidalPatternProfilometry_Impl::computeDataModulationTerm( InputArrayOfArrays patternImages,
+                                                                    OutputArray dataModulationTerm,
+                                                                    InputArray shadowMask )
+{
+    std::vector<Mat> &patternImages_ = *(std::vector<Mat>*) patternImages.getObj();
+    Mat &dataModulationTerm_ = *(Mat*) dataModulationTerm.getObj();
+    Mat &shadowMask_ = *(Mat*) shadowMask.getObj();
+    int rows = patternImages_[0].rows;
+    int cols = patternImages_[0].cols;
+    float num = 0;
+    float den = 0;
+    float i1 = 0;
+    float i2 = 0;
+    float i3 = 0;
+
+    int iOffset, jOffset;
+    Mat dmt(rows, cols, CV_32FC1);
+    Mat threshedDmt;
+
+    if( dataModulationTerm_.empty() )
+    {
+            dataModulationTerm_.create(rows, cols, CV_8UC1);
+    }
+    if( shadowMask_.empty() )
+    {
+        shadowMask_.create(rows, cols, CV_8U);
+        shadowMask_ = Scalar::all(255);
+    }
+    for( int i = 0; i < rows; ++i )
+    {
+        for( int j = 0; j < cols; ++j )
+        {
+            if( shadowMask_.at<uchar>(i, j) != 0 ){
+                if( i - 2 == - 2 )
+                {
+                    iOffset = 0;
+                }
+                else if( i - 2 == - 1 )
+                {
+                    iOffset = -1;
+                }
+                else if( i - 2 + 4 == rows + 1 )
+                {
+                    iOffset = -3;
+                }
+                else
+                {
+                    iOffset = -2;
+                }
+                if( j - 2 == -2 )
+                {
+                    jOffset = 0;
+                }
+                else if( j - 2 == -1 )
+                {
+                    jOffset = -1;
+                }
+                else if( j - 2 + 4 == cols + 1 )
+                {
+                    jOffset = -3;
+                }
+                else
+                {
+                    jOffset = -2;
+                }
+                Mat roi = shadowMask_(Rect(j + jOffset, i + iOffset, 4, 4));
+                Scalar nbrOfValidPixels = sum(roi);
+                if( nbrOfValidPixels[0] < 14*255 )
+                {
+                    dmt.at<float>(i, j) = 0;
+                }
+                else
+                {
+                    i1 = patternImages_[0].at<uchar>(i, j);
+                    i2 = patternImages_[1].at<uchar>(i, j);
+                    i3 = patternImages_[2].at<uchar>(i, j);
+
+                    num = sqrt(3 * ( i1 - i3 ) * ( i1 - i3 ) + ( 2 * i2 - i1 - i3 ) * ( 2 * i2 - i1 - i3 ));
+                    den = i1 + i2 + i3;
+                    dmt.at<float>(i, j) = 1 - num / den;
+                }
+            }
+            else
+            {
+                dmt.at<float>(i, j) = 0;
+            }
+        }
+    }
+    Mat kernel(3, 3, CV_32F);
+    kernel.at<float>(0, 0) = 1.f/16.f;
+    kernel.at<float>(1, 0) = 2.f/16.f;
+    kernel.at<float>(2, 0) = 1.f/16.f;
+
+    kernel.at<float>(0, 1) = 2.f/16.f;
+    kernel.at<float>(1, 1) = 4.f/16.f;
+    kernel.at<float>(2, 1) = 2.f/16.f;
+
+    kernel.at<float>(0, 2) = 1.f/16.f;
+    kernel.at<float>(1, 2) = 2.f/16.f;
+    kernel.at<float>(2, 2) = 1.f/16.f;
+
+    Point anchor = Point(-1, -1);
+    double delta = 0;
+    int ddepth = -1;
+
+    filter2D(dmt, dmt, ddepth, kernel, anchor, delta, BORDER_DEFAULT);
+
+    threshold(dmt, threshedDmt, 0.4, 1, THRESH_BINARY);
+    threshedDmt.convertTo(dataModulationTerm_, CV_8UC1, 255, 0);
+}
+
+//Extract marker location on the DMT. Duplicates are removed
+void SinusoidalPatternProfilometry_Impl::extractMarkersLocation( InputArray dataModulationTerm,
+                                                                 std::vector<Point> &markersLocation )
+{
+    Mat &dmt = *(Mat*) dataModulationTerm.getObj();
+    int rows = dmt.rows;
+    int cols = dmt.cols;
+    int halfRegionSize = 6;
+
+    for( int i = 0; i < rows; ++i )
+    {
+        for( int j = 0; j < cols; ++j )
+        {
+            if( dmt.at<uchar>(i,j) != 0 )
+            {
+                bool addToVector = true;
+                for(int k = 0; k < (int)markersLocation.size(); ++k)
+                {
+                    if( markersLocation[k].x - halfRegionSize < i &&
+                        markersLocation[k].x + halfRegionSize > i &&
+                        markersLocation[k].y - halfRegionSize < j &&
+                        markersLocation[k].y + halfRegionSize > j ){
+                        addToVector = false;
+                    }
+                }
+                if(addToVector)
+                {
+                    Point temp(i,j);
+                    markersLocation.push_back(temp);
+                }
+            }
+        }
+    }
+}
+void SinusoidalPatternProfilometry_Impl::convertToAbsolutePhaseMap( InputArrayOfArrays camPatterns,
+                                                                    InputArray unwrappedProjPhaseMap,
+                                                                    InputArray unwrappedCamPhaseMap,
+                                                                    InputArray shadowMask,
+                                                                    InputArray fundamentalMatrix )
+{
+    std::vector<Mat> &camPatterns_ = *(std::vector<Mat>*) camPatterns.getObj();
+    (void) unwrappedCamPhaseMap;
+    (void) unwrappedProjPhaseMap;
+
+    Mat &fundamental = *(Mat*) fundamentalMatrix.getObj();
+
+    Mat camDmt;
+
+    std::vector<Point> markersLocation;
+
+    computeDataModulationTerm(camPatterns_, camDmt, shadowMask);
+
+    std::vector<Vec3f> epilines;
+    computeCorrespondEpilines(params.markersLocation, 2, fundamental, epilines);
+
+}
+Ptr<SinusoidalPattern> SinusoidalPattern::create( const SinusoidalPattern::Params &params )
+{
+    return makePtr<SinusoidalPatternProfilometry_Impl>(params);
+}
+}
+}
\ No newline at end of file
diff --git a/contrib/modules/structured_light/test/test_faps.cpp b/contrib/modules/structured_light/test/test_faps.cpp
new file mode 100644
index 0000000..56ed093
--- /dev/null
+++ b/contrib/modules/structured_light/test/test_faps.cpp
@@ -0,0 +1,146 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+ //
+ //  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+ //
+ //  By downloading, copying, installing or using the software you agree to this license.
+ //  If you do not agree to this license, do not download, install,
+ //  copy or use the software.
+ //
+ //
+ //                           License Agreement
+ //                For Open Source Computer Vision Library
+ //
+ // Copyright (C) 2015, OpenCV Foundation, all rights reserved.
+ // Third party copyrights are property of their respective owners.
+ //
+ // Redistribution and use in source and binary forms, with or without modification,
+ // are permitted provided that the following conditions are met:
+ //
+ //   * Redistribution's of source code must retain the above copyright notice,
+ //     this list of conditions and the following disclaimer.
+ //
+ //   * Redistribution's in binary form must reproduce the above copyright notice,
+ //     this list of conditions and the following disclaimer in the documentation
+ //     and/or other materials provided with the distribution.
+ //
+ //   * The name of the copyright holders may not be used to endorse or promote products
+ //     derived from this software without specific prior written permission.
+ //
+ // This software is provided by the copyright holders and contributors "as is" and
+ // any express or implied warranties, including, but not limited to, the implied
+ // warranties of merchantability and fitness for a particular purpose are disclaimed.
+ // In no event shall the Intel Corporation or contributors be liable for any direct,
+ // indirect, incidental, special, exemplary, or consequential damages
+ // (including, but not limited to, procurement of substitute goods or services;
+ // loss of use, data, or profits; or business interruption) however caused
+ // and on any theory of liability, whether in contract, strict liability,
+ // or tort (including negligence or otherwise) arising in any way out of
+ // the use of this software, even if advised of the possibility of such damage.
+ //
+ //M*/
+
+#include <opencv2/structured_light/graycodepattern.hpp>
+#include <opencv2/structured_light/sinusoidalpattern.hpp>
+#include <opencv2/imgcodecs.hpp>
+#include "test_precomp.hpp"
+
+using namespace std;
+using namespace cv;
+
+const string STRUCTURED_LIGHT_DIR = "structured_light";
+const string FOLDER_DATA = "data";
+
+TEST( SinusoidalPattern, unwrapPhaseMap )
+{
+    string folder = cvtest::TS::ptr()->get_data_path() + "/" + STRUCTURED_LIGHT_DIR + "/" + FOLDER_DATA + "/";
+
+    structured_light::SinusoidalPattern::Params paramsPsp, paramsFtp, paramsFaps;
+    paramsFtp.methodId = 0;
+    paramsPsp.methodId = 1;
+    paramsFaps.methodId = 2;
+
+    Ptr<structured_light::SinusoidalPattern> sinusPsp = structured_light::SinusoidalPattern::create(paramsPsp);
+    Ptr<structured_light::SinusoidalPattern> sinusFtp = structured_light::SinusoidalPattern::create(paramsFtp);
+    Ptr<structured_light::SinusoidalPattern> sinusFaps = structured_light::SinusoidalPattern::create(paramsFaps);
+
+    vector<Mat> captures(3);
+    Mat unwrappedPhaseMapPspRef, unwrappedPhaseMapFtpRef, unwrappedPhaseMapFapsRef;
+    Mat shadowMask;
+    Mat wrappedPhaseMap, unwrappedPhaseMap, unwrappedPhaseMap8;
+    captures[0] = imread(folder + "capture_sin_0.jpg", IMREAD_GRAYSCALE);
+    captures[1] = imread(folder + "capture_sin_1.jpg", IMREAD_GRAYSCALE);
+    captures[2] = imread(folder + "capture_sin_2.jpg", IMREAD_GRAYSCALE);
+
+    unwrappedPhaseMapPspRef = imread(folder + "unwrappedPspTest.jpg", IMREAD_GRAYSCALE);
+    unwrappedPhaseMapFtpRef = imread(folder + "unwrappedFtpTest.jpg", IMREAD_GRAYSCALE);
+    unwrappedPhaseMapFapsRef = imread(folder + "unwrappedFapsTest.jpg", IMREAD_GRAYSCALE);
+
+    if( !captures[0].data || !captures[1].data || !captures[2].data || !unwrappedPhaseMapFapsRef.data
+        || !unwrappedPhaseMapFtpRef.data || !unwrappedPhaseMapPspRef.data )
+    {
+        cerr << "invalid test data" << endl;
+    }
+
+    sinusPsp->computePhaseMap(captures, wrappedPhaseMap, shadowMask);
+    sinusPsp->unwrapPhaseMap(wrappedPhaseMap, unwrappedPhaseMap, Size(captures[0].cols, captures[1].rows), shadowMask);
+    unwrappedPhaseMap.convertTo(unwrappedPhaseMap8, CV_8U, 1, 128);
+
+    int sumOfDiff = 0;
+    int count = 0;
+    float ratio = 0;
+    for( int i = 0; i < unwrappedPhaseMap8.rows; ++i )
+    {
+        for( int j = 0; j < unwrappedPhaseMap8.cols; ++j )
+        {
+            int ref = unwrappedPhaseMapPspRef.at<uchar>(i, j);
+            int comp = unwrappedPhaseMap8.at<uchar>(i, j);
+            sumOfDiff += (ref - comp);
+            count ++;
+        }
+    }
+    ratio = (float)(sumOfDiff / count);
+
+    EXPECT_LE( ratio, 0.003 );
+
+    sinusFtp->computePhaseMap(captures, wrappedPhaseMap, shadowMask);
+    sinusFtp->unwrapPhaseMap(wrappedPhaseMap, unwrappedPhaseMap, Size(captures[0].cols, captures[1].rows), shadowMask);
+    unwrappedPhaseMap.convertTo(unwrappedPhaseMap8, CV_8U, 1, 128);
+
+    sumOfDiff = 0;
+    count = 0;
+    ratio = 0;
+    for( int i = 0; i < unwrappedPhaseMap8.rows; ++i )
+    {
+        for( int j = 0; j < unwrappedPhaseMap8.cols; ++j )
+        {
+            int ref = unwrappedPhaseMapFtpRef.at<uchar>(i, j);
+            int comp = unwrappedPhaseMap8.at<uchar>(i, j);
+            sumOfDiff += (ref - comp);
+            count ++;
+        }
+    }
+    ratio = (float)(sumOfDiff / count);
+
+    EXPECT_LE( ratio, 0.003 );
+
+    sinusFaps->computePhaseMap(captures, wrappedPhaseMap, shadowMask);
+    sinusFaps->unwrapPhaseMap(wrappedPhaseMap, unwrappedPhaseMap, Size(captures[0].cols, captures[1].rows), shadowMask);
+    unwrappedPhaseMap.convertTo(unwrappedPhaseMap8, CV_8U, 1, 128);
+
+    sumOfDiff = 0;
+    count = 0;
+    ratio = 0;
+    for( int i = 0; i < unwrappedPhaseMap8.rows; ++i )
+    {
+        for( int j = 0; j < unwrappedPhaseMap8.cols; ++j )
+        {
+            int ref = unwrappedPhaseMapFapsRef.at<uchar>(i, j);
+            int comp = unwrappedPhaseMap8.at<uchar>(i, j);
+            sumOfDiff += (ref - comp);
+            count ++;
+        }
+    }
+    ratio = (float)(sumOfDiff / count);
+
+    EXPECT_LE( ratio, 0.003 );
+}
diff --git a/contrib/modules/structured_light/tutorials/capturesinpattern/capturesinpattern.markdown b/contrib/modules/structured_light/tutorials/capturesinpattern/capturesinpattern.markdown
new file mode 100644
index 0000000..cfffac9
--- /dev/null
+++ b/contrib/modules/structured_light/tutorials/capturesinpattern/capturesinpattern.markdown
@@ -0,0 +1,207 @@
+Capture Sinusoidal pattern tutorial {#tutorial_capture_sinusoidal_pattern}
+=============
+
+Goal
+----
+
+In this tutorial, you will learn how to use the sinusoidal pattern class to:
+
+- Generate sinusoidal patterns.
+- Project the generated patterns.
+- Capture the projected patterns.
+- Compute a wrapped phase map from these patterns using three different algorithms (Fourier Transform Profilometry, Phase Shifting Profilometry, Fourier-assisted Phase Shifting Profilometry)
+- Unwrap the previous phase map.
+
+Code
+----
+ at include structured_light/samples/capsinpattern.cpp
+
+Expalantion
+-----------
+First, the sinusoidal patterns must be generated. *SinusoidalPattern* class parameters have to be set by the user:
+
+- projector width and height
+- number of periods in the patterns
+- set cross markers in the patterns (used to convert relative phase map to absolute phase map)
+- patterns direction (horizontal or vertical)
+- phase shift value (usually set to 2pi/3 to enable a cyclical system)
+- number of pixels between two consecutive markers on the same row/column
+- id of the method used to compute the phase map (FTP = 0, PSP = 1, FAPS = 2)
+
+The user can also choose to save the patterns and the phase map.
+
+ at code{.cpp}
+	structured_light::SinusoidalPattern::Params params;
+    params.width = parser.get<int>(0);
+    params.height = parser.get<int>(1);
+    params.nbrOfPeriods = parser.get<int>(2);
+    params.setMarkers = parser.get<bool>(3);
+    params.horizontal = parser.get<bool>(4);
+    params.methodId = parser.get<int>(5);
+    params.shiftValue = static_cast<float>(2 * CV_PI / 3);
+    params.nbrOfPixelsBetweenMarkers = 70;
+    String outputPatternPath = parser.get<String>(6);
+    String outputWrappedPhasePath = parser.get<String>(7);
+    String outputUnwrappedPhasePath = parser.get<String>(8);
+
+    Ptr<structured_light::SinusoidalPattern> sinus = structured_light::SinusoidalPattern::create(params);
+	// Storage for patterns
+    vector<Mat> patterns;
+    //Generate sinusoidal patterns
+    sinus->generate(patterns);
+ at endcode
+The number of patterns is always equal to three, no matter the method used to compute the phase map. Those three patterns are projected in a loop which is fine since the system is cyclical.
+
+Once the patterns have been generated, the camera is opened and the patterns are projected, using fullscreen resolution. In this tutorial, a prosilica camera is used to capture gray images. When the first pattern is displayed by the projector, the user can press any key to start the projection sequence.
+
+ at code{.cpp}
+VideoCapture cap(CAP_PVAPI);
+    if( !cap.isOpened() )
+    {
+        cout << "Camera could not be opened" << endl;
+        return -1;
+    }
+    cap.set(CAP_PROP_PVAPI_PIXELFORMAT, CAP_PVAPI_PIXELFORMAT_MONO8);
+
+    namedWindow("pattern", WINDOW_NORMAL);
+    setWindowProperty("pattern", WND_PROP_FULLSCREEN, WINDOW_FULLSCREEN);
+    imshow("pattern", patterns[0]);
+    cout << "Press any key when ready" << endl;
+    waitKey(0);
+ at endcode
+
+In this tutorial, 30 images are projected so, each of the three patterns is projected ten times.
+The "while" loop takes care of the projection process. The captured images are stored in a vector of Mat. There is a 30 ms delay between two successive captures.
+When the projection is done, the user has to press "Enter" to start computing the phase maps.
+
+ at code{.cpp}
+    int nbrOfImages = 30;
+    int count = 0;
+
+    vector<Mat> img(nbrOfImages);
+    Size camSize(-1, -1);
+
+    while( count < nbrOfImages )
+    {
+        for(int i = 0; i < (int)patterns.size(); ++i )
+        {
+            imshow("pattern", patterns[i]);
+            waitKey(30);
+            cap >> img[count];
+            count += 1;
+        }
+    }
+
+    cout << "press enter when ready" << endl;
+    bool loop = true;
+    while ( loop )
+    {
+        char c = waitKey(0);
+        if( c == 10 )
+        {
+            loop = false;
+        }
+    }
+ at endcode
+The phase maps are ready to be computed according to the selected method.
+For FTP, a phase map is computed for each projected pattern, but we need to compute the shadow mask from three successive patterns, as explained in @cite faps. Therefore, three patterns are set in a vector called captures. Care is taken to fill this vector with three patterns, especially when we reach the last captures. The unwrapping algorithm needs to know the size of the captured images so, we make sure to give it to the "unwrapPhaseMap" method.
+The phase maps are converted to 8-bit images in order to save them as png.
+
+ at code{.cpp}
+switch(params.methodId)
+    {
+        case structured_light::FTP:
+            for( int i = 0; i < nbrOfImages; ++i )
+            {
+                /*We need three images to compute the shadow mask, as described in the reference paper
+                 * even if the phase map is computed from one pattern only
+                */
+                vector<Mat> captures;
+                if( i == nbrOfImages - 2 )
+                {
+                    captures.push_back(img[i]);
+                    captures.push_back(img[i-1]);
+                    captures.push_back(img[i+1]);
+                }
+                else if( i == nbrOfImages - 1 )
+                {
+                    captures.push_back(img[i]);
+                    captures.push_back(img[i-1]);
+                    captures.push_back(img[i-2]);
+                }
+                else
+                {
+                    captures.push_back(img[i]);
+                    captures.push_back(img[i+1]);
+                    captures.push_back(img[i+2]);
+                }
+                sinus->computePhaseMap(captures, wrappedPhaseMap, shadowMask);
+                if( camSize.height == -1 )
+                {
+                    camSize.height = img[i].rows;
+                    camSize.width = img[i].cols;
+                }
+                sinus->unwrapPhaseMap(wrappedPhaseMap, unwrappedPhaseMap, camSize, shadowMask);
+                unwrappedPhaseMap.convertTo(unwrappedPhaseMap8, CV_8U, 1, 128);
+                wrappedPhaseMap.convertTo(wrappedPhaseMap8, CV_8U, 255, 128);
+
+                if( !outputUnwrappedPhasePath.empty() )
+                {
+                    ostringstream name;
+                    name << i;
+                    imwrite(outputUnwrappedPhasePath + "_FTP_" + name.str() + ".png", unwrappedPhaseMap8);
+                }
+
+                if( !outputWrappedPhasePath.empty() )
+                {
+                    ostringstream name;
+                    name << i;
+                    imwrite(outputWrappedPhasePath + "_FTP_" + name.str() + ".png", wrappedPhaseMap8);
+                }
+            }
+            break;
+ at endcode
+
+For PSP and FAPS, three projected images are used to compute a single phase map. These three images are set in "captures", a vector working as a FIFO.Here again, phase maps are converted to 8-bit images in order to save them as png.
+ at code{.cpp}
+case structured_light::PSP:
+        case structured_light::FAPS:
+            for( int i = 0; i < nbrOfImages - 2; ++i )
+            {
+                vector<Mat> captures;
+                captures.push_back(img[i]);
+                captures.push_back(img[i+1]);
+                captures.push_back(img[i+2]);
+
+                sinus->computePhaseMap(captures, wrappedPhaseMap, shadowMask);
+                if( camSize.height == -1 )
+                {
+                    camSize.height = img[i].rows;
+                    camSize.width = img[i].cols;
+                }
+                sinus->unwrapPhaseMap(wrappedPhaseMap, unwrappedPhaseMap, camSize, shadowMask);
+                unwrappedPhaseMap.convertTo(unwrappedPhaseMap8, CV_8U, 1, 128);
+                wrappedPhaseMap.convertTo(wrappedPhaseMap8, CV_8U, 255, 128);
+
+                if( !outputUnwrappedPhasePath.empty() )
+                {
+                    ostringstream name;
+                    name << i;
+                    if( params.methodId == structured_light::PSP )
+                        imwrite(outputUnwrappedPhasePath + "_PSP_" + name.str() + ".png", unwrappedPhaseMap8);
+                    else
+                        imwrite(outputUnwrappedPhasePath + "_FAPS_" + name.str() + ".png", unwrappedPhaseMap8);
+                }
+
+                if( !outputWrappedPhasePath.empty() )
+                {
+                    ostringstream name;
+                    name << i;
+                    if( params.methodId == structured_light::PSP )
+                        imwrite(outputWrappedPhasePath + "_PSP_" + name.str() + ".png", wrappedPhaseMap8);
+                    else
+                        imwrite(outputWrappedPhasePath + "_FAPS_" + name.str() + ".png", wrappedPhaseMap8);
+                }
+            }
+            break;
+ at endcode
diff --git a/contrib/modules/structured_light/tutorials/structured_light.markdown b/contrib/modules/structured_light/tutorials/structured_light.markdown
index 4059693..79cc143 100644
--- a/contrib/modules/structured_light/tutorials/structured_light.markdown
+++ b/contrib/modules/structured_light/tutorials/structured_light.markdown
@@ -15,4 +15,12 @@ Structured Light tutorials {#tutorial_structured_light}
 
     _Author:_ Roberta Ravanelli
 
-    You will learn how to decode a previously acquired Gray code pattern, generating a pointcloud.
\ No newline at end of file
+    You will learn how to decode a previously acquired Gray code pattern, generating a pointcloud.
+
+-	@subpage tutorial_capture_sinusoidal_pattern
+
+	_Compatibility:_ \> OpenCV 3.0.0
+
+	_Author:_ Ambroise Moreau
+
+	You will learn how to compute phase maps using *SinusoidalPattern* class.
diff --git a/contrib/modules/surface_matching/README.md b/contrib/modules/surface_matching/README.md
index 6584d22..72d64de 100644
--- a/contrib/modules/surface_matching/README.md
+++ b/contrib/modules/surface_matching/README.md
@@ -1,2 +1,5 @@
-Surface Matching Algorithm Through 3D Features
-==============================================
+Point Pair Features for 3D Surface Matching
+===========================================
+
+Implements 3d object detection and localization using multimodal point pair features.
+http://docs.opencv.org/3.0-beta/modules/surface_matching/doc/surface_matching.html
diff --git a/contrib/modules/text/CMakeLists.txt b/contrib/modules/text/CMakeLists.txt
index 1e0a8e5..7ec4d24 100644
--- a/contrib/modules/text/CMakeLists.txt
+++ b/contrib/modules/text/CMakeLists.txt
@@ -1,25 +1,24 @@
-set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR})
+set(the_description "Text Detection and Recognition")
+ocv_define_module(text opencv_ml opencv_imgproc opencv_core opencv_features2d OPTIONAL opencv_highgui WRAP python)
 
-find_package(Tesseract)
-if(Tesseract_FOUND)
+if(NOT CMAKE_CROSSCOMPILING OR OPENCV_FIND_TESSERACT)
+  set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
+  find_package(Tesseract QUIET)
+  if(Tesseract_FOUND)
     message(STATUS "Tesseract:   YES")
     set(HAVE_TESSERACT 1)
-else()
+    ocv_include_directories(${Tesseract_INCLUDE_DIR})
+    ocv_target_link_libraries(${the_module} ${Tesseract_LIBRARIES})
+  else()
     message(STATUS "Tesseract:   NO")
+  endif()
 endif()
 
 configure_file(${CMAKE_CURRENT_SOURCE_DIR}/text_config.hpp.in
                ${CMAKE_BINARY_DIR}/text_config.hpp @ONLY)
 
-include_directories(${CMAKE_CURRENT_BINARY_DIR})
-
-if(${Tesseract_FOUND})
-include_directories(${Tesseract_INCLUDE_DIR})
-endif()
-
-set(the_description "Text Detection and Recognition")
-ocv_define_module(text opencv_ml opencv_highgui opencv_imgproc opencv_core opencv_features2d WRAP python)
+ocv_include_directories(${CMAKE_CURRENT_BINARY_DIR})
 
-if(${Tesseract_FOUND})
-  target_link_libraries(opencv_text ${Tesseract_LIBS})
-endif()
+ocv_add_testdata(samples/ contrib/text
+    FILES_MATCHING PATTERN "*.xml" PATTERN "*.xml.gz" REGEX "scenetext[0-9]+.jpg"
+)
diff --git a/contrib/modules/text/FindTesseract.cmake b/contrib/modules/text/FindTesseract.cmake
deleted file mode 100644
index 54c4a49..0000000
--- a/contrib/modules/text/FindTesseract.cmake
+++ /dev/null
@@ -1,24 +0,0 @@
-# Tesseract OCR
-unset(Tesseract_FOUND)
-
-find_path(Tesseract_INCLUDE_DIR tesseract/baseapi.h
-  HINTS
-  /usr/include
-  /usr/local/include)
-
-find_library(Tesseract_LIBRARY NAMES tesseract
-  HINTS
-  /usr/lib
-  /usr/local/lib)
-
-find_library(Lept_LIBRARY NAMES lept
-  HINTS
-  /usr/lib
-  /usr/local/lib)
-
-set(Tesseract_LIBS ${Tesseract_LIBRARY} ${Lept_LIBRARY})
-if(Tesseract_LIBS AND Tesseract_INCLUDE_DIR)
-    set(Tesseract_FOUND 1)
-endif()
-
-        
diff --git a/contrib/modules/text/cmake/FindTesseract.cmake b/contrib/modules/text/cmake/FindTesseract.cmake
new file mode 100644
index 0000000..2a5d868
--- /dev/null
+++ b/contrib/modules/text/cmake/FindTesseract.cmake
@@ -0,0 +1,23 @@
+# Tesseract OCR
+if(COMMAND pkg_check_modules)
+  pkg_check_modules(Tesseract tesseract lept)
+endif()
+if(NOT Tesseract_FOUND)
+  find_path(Tesseract_INCLUDE_DIR tesseract/baseapi.h
+    HINTS
+    /usr/local/include)
+
+  find_library(Tesseract_LIBRARY NAMES tesseract
+    HINTS
+    /usr/local/lib)
+
+  find_library(Lept_LIBRARY NAMES lept
+    HINTS
+    /usr/local/lib)
+
+  if(Tesseract_INCLUDE_DIR AND Tesseract_LIBRARY AND Lept_LIBRARY)
+    set(Tesseract_INCLUDE_DIRS ${Tesseract_INCLUDE_DIR})
+    set(Tesseract_LIBRARIES ${Tesseract_LIBRARY} ${Lept_LIBRARY})
+    set(Tesseract_FOUND 1)
+  endif()
+endif()
diff --git a/contrib/modules/text/include/opencv2/text.hpp b/contrib/modules/text/include/opencv2/text.hpp
index 591424c..945194a 100644
--- a/contrib/modules/text/include/opencv2/text.hpp
+++ b/contrib/modules/text/include/opencv2/text.hpp
@@ -92,7 +92,7 @@ grouping horizontally aligned text, and the method proposed by Lluis Gomez and D
 in [Gomez13][Gomez14] for grouping arbitrary oriented text (see erGrouping).
 
 To see the text detector at work, have a look at the textdetection demo:
-<https://github.com/Itseez/opencv_contrib/blob/master/modules/text/samples/textdetection.cpp>
+<https://github.com/opencv/opencv_contrib/blob/master/modules/text/samples/textdetection.cpp>
 
     @defgroup text_recognize Scene Text Recognition
   @}
diff --git a/contrib/modules/text/include/opencv2/text/erfilter.hpp b/contrib/modules/text/include/opencv2/text/erfilter.hpp
index 7b4f4c1..af983c6 100644
--- a/contrib/modules/text/include/opencv2/text/erfilter.hpp
+++ b/contrib/modules/text/include/opencv2/text/erfilter.hpp
@@ -82,7 +82,7 @@ public:
     Rect rect;
     double raw_moments[2];     //!< order 1 raw moments to derive the centroid
     double central_moments[3]; //!< order 2 central moments to construct the covariance matrix
-    std::deque<int> *crossings;//!< horizontal crossings
+    Ptr<std::deque<int> > crossings;//!< horizontal crossings
     float med_crossings;       //!< median of the crossings at three different height levels
 
     //! 2nd stage features
@@ -115,7 +115,7 @@ public:
 
 Extracts the component tree (if needed) and filter the extremal regions (ER's) by using a given classifier.
  */
-class CV_EXPORTS ERFilter : public Algorithm
+class CV_EXPORTS_W ERFilter : public Algorithm
 {
 public:
 
@@ -124,7 +124,7 @@ public:
     By doing it we hide SVM, Boost etc. Developers can provide their own classifiers to the
     ERFilter algorithm.
      */
-    class CV_EXPORTS Callback
+    class CV_EXPORTS_W Callback
     {
     public:
         virtual ~Callback() { }
@@ -207,11 +207,11 @@ the probability P(er|character) are selected (if the local maximum of the probab
 global limit pmin and the difference between local maximum and local minimum is greater than
 minProbabilityDiff).
  */
-CV_EXPORTS Ptr<ERFilter> createERFilterNM1(const Ptr<ERFilter::Callback>& cb,
-                                                  int thresholdDelta = 1, float minArea = 0.00025,
-                                                  float maxArea = 0.13, float minProbability = 0.4,
+CV_EXPORTS_W Ptr<ERFilter> createERFilterNM1(const Ptr<ERFilter::Callback>& cb,
+                                                  int thresholdDelta = 1, float minArea = (float)0.00025,
+                                                  float maxArea = (float)0.13, float minProbability = (float)0.4,
                                                   bool nonMaxSuppression = true,
-                                                  float minProbabilityDiff = 0.1);
+                                                  float minProbabilityDiff = (float)0.1);
 
 /** @brief Create an Extremal Region Filter for the 2nd stage classifier of N&M algorithm [Neumann12].
 
@@ -224,8 +224,8 @@ non-character classes using more informative but also more computationally expen
 classifier uses all the features calculated in the first stage and the following additional
 features: hole area ratio, convex hull ratio, and number of outer inflexion points.
  */
-CV_EXPORTS Ptr<ERFilter> createERFilterNM2(const Ptr<ERFilter::Callback>& cb,
-                                                  float minProbability = 0.3);
+CV_EXPORTS_W Ptr<ERFilter> createERFilterNM2(const Ptr<ERFilter::Callback>& cb,
+                                                  float minProbability = (float)0.3);
 
 
 /** @brief Allow to implicitly load the default classifier when creating an ERFilter object.
@@ -234,7 +234,7 @@ CV_EXPORTS Ptr<ERFilter> createERFilterNM2(const Ptr<ERFilter::Callback>& cb,
 
 returns a pointer to ERFilter::Callback.
  */
-CV_EXPORTS Ptr<ERFilter::Callback> loadClassifierNM1(const std::string& filename);
+CV_EXPORTS_W Ptr<ERFilter::Callback> loadClassifierNM1(const String& filename);
 
 /** @brief Allow to implicitly load the default classifier when creating an ERFilter object.
 
@@ -242,7 +242,7 @@ CV_EXPORTS Ptr<ERFilter::Callback> loadClassifierNM1(const std::string& filename
 
 returns a pointer to ERFilter::Callback.
  */
-CV_EXPORTS Ptr<ERFilter::Callback> loadClassifierNM2(const std::string& filename);
+CV_EXPORTS_W Ptr<ERFilter::Callback> loadClassifierNM2(const String& filename);
 
 
 //! computeNMChannels operation modes
@@ -264,7 +264,7 @@ channels (Grad) are used in order to obtain high localization recall. This imple
 provides an alternative combination of red (R), green (G), blue (B), lightness (L), and gradient
 magnitude (Grad).
  */
-CV_EXPORTS void computeNMChannels(InputArray _src, OutputArrayOfArrays _channels, int _mode = ERFILTER_NM_RGBLGrad);
+CV_EXPORTS_W void computeNMChannels(InputArray _src, CV_OUT OutputArrayOfArrays _channels, int _mode = ERFILTER_NM_RGBLGrad);
 
 
 
@@ -324,6 +324,13 @@ CV_EXPORTS void erGrouping(InputArray img, InputArrayOfArrays channels,
                                            const std::string& filename = std::string(),
                                            float minProbablity = 0.5);
 
+CV_EXPORTS_W void erGrouping(InputArray image, InputArray channel,
+                                           std::vector<std::vector<Point> > regions,
+                                           CV_OUT std::vector<Rect> &groups_rects,
+                                           int method = ERGROUPING_ORIENTATION_HORIZ,
+                                           const String& filename = String(),
+                                           float minProbablity = (float)0.5);
+
 /** @brief Converts MSER contours (vector\<Point\>) to ERStat regions.
 
 @param image Source image CV_8UC1 from which the MSERs where extracted.
@@ -338,11 +345,14 @@ single vector\<Point\>, the function separates them in two different vectors (th
 ERStats where extracted from two different channels).
 
 An example of MSERsToERStats in use can be found in the text detection webcam_demo:
-<https://github.com/Itseez/opencv_contrib/blob/master/modules/text/samples/webcam_demo.cpp>
+<https://github.com/opencv/opencv_contrib/blob/master/modules/text/samples/webcam_demo.cpp>
  */
 CV_EXPORTS void MSERsToERStats(InputArray image, std::vector<std::vector<Point> > &contours,
                                std::vector<std::vector<ERStat> > &regions);
 
+// Utility funtion for scripting
+CV_EXPORTS_W void detectRegions(InputArray image, const Ptr<ERFilter>& er_filter1, const Ptr<ERFilter>& er_filter2, CV_OUT std::vector< std::vector<Point> >& regions);
+
 //! @}
 
 }
diff --git a/contrib/modules/text/include/opencv2/text/ocr.hpp b/contrib/modules/text/include/opencv2/text/ocr.hpp
index 651934b..1261046 100644
--- a/contrib/modules/text/include/opencv2/text/ocr.hpp
+++ b/contrib/modules/text/include/opencv2/text/ocr.hpp
@@ -81,10 +81,10 @@ Notice that it is compiled only when tesseract-ocr is correctly installed.
 @note
    -   (C++) An example of OCRTesseract recognition combined with scene text detection can be found
         at the end_to_end_recognition demo:
-        <https://github.com/Itseez/opencv_contrib/blob/master/modules/text/samples/end_to_end_recognition.cpp>
+        <https://github.com/opencv/opencv_contrib/blob/master/modules/text/samples/end_to_end_recognition.cpp>
     -   (C++) Another example of OCRTesseract recognition combined with scene text detection can be
         found at the webcam_demo:
-        <https://github.com/Itseez/opencv_contrib/blob/master/modules/text/samples/webcam_demo.cpp>
+        <https://github.com/opencv/opencv_contrib/blob/master/modules/text/samples/webcam_demo.cpp>
  */
 class CV_EXPORTS_W OCRTesseract : public BaseOCR
 {
@@ -152,7 +152,7 @@ enum decoder_mode
 @note
    -   (C++) An example on using OCRHMMDecoder recognition combined with scene text detection can
         be found at the webcam_demo sample:
-        <https://github.com/Itseez/opencv_contrib/blob/master/modules/text/samples/webcam_demo.cpp>
+        <https://github.com/opencv/opencv_contrib/blob/master/modules/text/samples/webcam_demo.cpp>
  */
 class CV_EXPORTS_W OCRHMMDecoder : public BaseOCR
 {
@@ -165,7 +165,7 @@ public:
 
     The default character classifier and feature extractor can be loaded using the utility funtion
     loadOCRHMMClassifierNM and KNN model provided in
-    <https://github.com/Itseez/opencv_contrib/blob/master/modules/text/samples/OCRHMM_knn_model_data.xml.gz>.
+    <https://github.com/opencv/opencv_contrib/blob/master/modules/text/samples/OCRHMM_knn_model_data.xml.gz>.
      */
     class CV_EXPORTS_W ClassifierCallback
     {
@@ -321,7 +321,7 @@ CV_EXPORTS_W Ptr<OCRHMMDecoder::ClassifierCallback> loadOCRHMMClassifierCNN(cons
  * The function calculate frequency statistics of character pairs from the given lexicon and fills the output transition_probabilities_table with them. The transition_probabilities_table can be used as input in the OCRHMMDecoder::create() and OCRBeamSearchDecoder::create() methods.
  * @note
  *    -   (C++) An alternative would be to load the default generic language transition table provided in the text module samples folder (created from ispell 42869 english words list) :
- *            <https://github.com/Itseez/opencv_contrib/blob/master/modules/text/samples/OCRHMM_transitions_table.xml>
+ *            <https://github.com/opencv/opencv_contrib/blob/master/modules/text/samples/OCRHMM_transitions_table.xml>
  **/
 CV_EXPORTS void createOCRHMMTransitionsTable(std::string& vocabulary, std::vector<std::string>& lexicon, OutputArray transition_probabilities_table);
 
@@ -335,7 +335,7 @@ CV_EXPORTS_W Mat createOCRHMMTransitionsTable(const String& vocabulary, std::vec
 @note
    -   (C++) An example on using OCRBeamSearchDecoder recognition combined with scene text detection can
         be found at the demo sample:
-        <https://github.com/Itseez/opencv_contrib/blob/master/modules/text/samples/word_recognition.cpp>
+        <https://github.com/opencv/opencv_contrib/blob/master/modules/text/samples/word_recognition.cpp>
  */
 class CV_EXPORTS_W OCRBeamSearchDecoder : public BaseOCR
 {
@@ -348,7 +348,7 @@ public:
 
     The default character classifier and feature extractor can be loaded using the utility funtion
     loadOCRBeamSearchClassifierCNN with all its parameters provided in
-    <https://github.com/Itseez/opencv_contrib/blob/master/modules/text/samples/OCRBeamSearch_CNN_model_data.xml.gz>.
+    <https://github.com/opencv/opencv_contrib/blob/master/modules/text/samples/OCRBeamSearch_CNN_model_data.xml.gz>.
      */
     class CV_EXPORTS_W ClassifierCallback
     {
diff --git a/contrib/modules/text/samples/detect_er_chars.py b/contrib/modules/text/samples/detect_er_chars.py
new file mode 100644
index 0000000..e0433e7
--- /dev/null
+++ b/contrib/modules/text/samples/detect_er_chars.py
@@ -0,0 +1,38 @@
+#!/usr/bin/python
+
+import sys
+import os
+
+import cv2
+import numpy as np
+
+print('\ndetect_er_chars.py')
+print('       A simple demo script using the Extremal Region Filter algorithm described in:')
+print('       Neumann L., Matas J.: Real-Time Scene Text Localization and Recognition, CVPR 2012\n')
+
+
+if (len(sys.argv) < 2):
+  print(' (ERROR) You must call this script with an argument (path_to_image_to_be_processed)\n')
+  quit()
+
+pathname = os.path.dirname(sys.argv[0])
+
+img  = cv2.imread(str(sys.argv[1]))
+gray = cv2.imread(str(sys.argv[1]),0)
+
+erc1 = cv2.text.loadClassifierNM1(pathname+'/trained_classifierNM1.xml')
+er1 = cv2.text.createERFilterNM1(erc1)
+
+erc2 = cv2.text.loadClassifierNM2(pathname+'/trained_classifierNM2.xml')
+er2 = cv2.text.createERFilterNM2(erc2)
+
+regions = cv2.text.detectRegions(gray,er1,er2)
+
+#Visualization
+rects = [cv2.boundingRect(p.reshape(-1, 1, 2)) for p in regions]
+for rect in rects:
+  cv2.rectangle(img, rect[0:2], (rect[0]+rect[2],rect[1]+rect[3]), (0, 0, 0), 2)
+for rect in rects:
+  cv2.rectangle(img, rect[0:2], (rect[0]+rect[2],rect[1]+rect[3]), (255, 255, 255), 1)
+cv2.imshow("Text detection result", img)
+cv2.waitKey(0)
diff --git a/contrib/modules/text/samples/textdetection.cpp b/contrib/modules/text/samples/textdetection.cpp
index 2cf67b0..6d167b4 100644
--- a/contrib/modules/text/samples/textdetection.cpp
+++ b/contrib/modules/text/samples/textdetection.cpp
@@ -32,7 +32,6 @@ int main(int argc, const char * argv[])
 
     if (argc < 2) show_help_and_exit(argv[0]);
 
-    namedWindow("grouping",WINDOW_NORMAL);
     Mat src = imread(argv[1]);
 
     // Extract channels to be processed individually
@@ -70,8 +69,8 @@ int main(int argc, const char * argv[])
     imshow("grouping",src);
 
     cout << "Done!" << endl << endl;
-    cout << "Press 'e' to show the extracted Extremal Regions, any other key to exit." << endl << endl;
-    if( waitKey (-1) == 101)
+    cout << "Press 'space' to show the extracted Extremal Regions, any other key to exit." << endl << endl;
+    if ((waitKey()&0xff) == ' ')
         er_show(channels,regions);
 
     // memory clean-up
diff --git a/contrib/modules/text/samples/textdetection.py b/contrib/modules/text/samples/textdetection.py
new file mode 100644
index 0000000..1da2833
--- /dev/null
+++ b/contrib/modules/text/samples/textdetection.py
@@ -0,0 +1,58 @@
+#!/usr/bin/python
+
+import sys
+import os
+
+import cv2
+import numpy as np
+
+print('\ntextdetection.py')
+print('       A demo script of the Extremal Region Filter algorithm described in:')
+print('       Neumann L., Matas J.: Real-Time Scene Text Localization and Recognition, CVPR 2012\n')
+
+
+if (len(sys.argv) < 2):
+  print(' (ERROR) You must call this script with an argument (path_to_image_to_be_processed)\n')
+  quit()
+
+pathname = os.path.dirname(sys.argv[0])
+
+
+img      = cv2.imread(str(sys.argv[1]))
+# for visualization
+vis      = img.copy()
+
+
+# Extract channels to be processed individually
+channels = cv2.text.computeNMChannels(img)
+# Append negative channels to detect ER- (bright regions over dark background)
+cn = len(channels)-1
+for c in range(0,cn):
+  channels.append((255-channels[c]))
+
+# Apply the default cascade classifier to each independent channel (could be done in parallel)
+print("Extracting Class Specific Extremal Regions from "+str(len(channels))+" channels ...")
+print("    (...) this may take a while (...)")
+for channel in channels:
+
+  erc1 = cv2.text.loadClassifierNM1(pathname+'/trained_classifierNM1.xml')
+  er1 = cv2.text.createERFilterNM1(erc1,16,0.00015,0.13,0.2,True,0.1)
+
+  erc2 = cv2.text.loadClassifierNM2(pathname+'/trained_classifierNM2.xml')
+  er2 = cv2.text.createERFilterNM2(erc2,0.5)
+
+  regions = cv2.text.detectRegions(channel,er1,er2)
+
+  rects = cv2.text.erGrouping(img,channel,[r.tolist() for r in regions])
+  #rects = cv2.text.erGrouping(img,gray,[x.tolist() for x in regions], cv2.text.ERGROUPING_ORIENTATION_ANY,'../../GSoC2014/opencv_contrib/modules/text/samples/trained_classifier_erGrouping.xml',0.5)
+
+  #Visualization
+  for r in range(0,np.shape(rects)[0]):
+    rect = rects[r]
+    cv2.rectangle(vis, (rect[0],rect[1]), (rect[0]+rect[2],rect[1]+rect[3]), (0, 0, 0), 2)
+    cv2.rectangle(vis, (rect[0],rect[1]), (rect[0]+rect[2],rect[1]+rect[3]), (255, 255, 255), 1)
+
+
+#Visualization
+cv2.imshow("Text detection result", vis)
+cv2.waitKey(0)
diff --git a/contrib/modules/text/src/erfilter.cpp b/contrib/modules/text/src/erfilter.cpp
index b5f58b7..f438c75 100644
--- a/contrib/modules/text/src/erfilter.cpp
+++ b/contrib/modules/text/src/erfilter.cpp
@@ -97,7 +97,7 @@ ERStat::ERStat(int init_level, int init_pixel, int init_x, int init_y) : pixel(i
     central_moments[0] = 0.0;
     central_moments[1] = 0.0;
     central_moments[2] = 0.0;
-    crossings = new deque<int>();
+    crossings = makePtr<deque<int> >();
     crossings->push_back(0);
 }
 
@@ -275,24 +275,18 @@ void ERFilterNM::er_tree_extract( InputArray image )
     // the component stack
     vector<ERStat*> er_stack;
 
-    //the quads for euler number calculation
-    unsigned char quads[3][4];
-    quads[0][0] = 1 << 3;
-    quads[0][1] = 1 << 2;
-    quads[0][2] = 1 << 1;
-    quads[0][3] = 1;
-    quads[1][0] = (1<<2)|(1<<1)|(1);
-    quads[1][1] = (1<<3)|(1<<1)|(1);
-    quads[1][2] = (1<<3)|(1<<2)|(1);
-    quads[1][3] = (1<<3)|(1<<2)|(1<<1);
-    quads[2][0] = (1<<2)|(1<<1);
-    quads[2][1] = (1<<3)|(1);
-    // quads[2][2] and quads[2][3] are never used so no need to initialize them.
+    // the quads for euler number calculation
+    // quads[2][2] and quads[2][3] are never used.
     // The four lowest bits in each quads[i][j] correspond to the 2x2 binary patterns 
     // Q_1, Q_2, Q_3 in the Neumann and Matas CVPR 2012 paper 
     // (see in page 4 at the end of first column). 
     // Q_1 and Q_2 have four patterns, while Q_3 has only two.
-
+    const int quads[3][4] =
+    {
+        { 1<<3                 ,          1<<2          ,                 1<<1   ,                       1<<0 },
+        {     (1<<2)|(1<<1)|(1),   (1<<3)|    (1<<1)|(1),   (1<<3)|(1<<2)|    (1),   (1<<3)|(1<<2)|(1<<1)     },
+        {     (1<<2)|(1<<1)    ,   (1<<3)|           (1),            /*unused*/-1,               /*unused*/-1 }
+    };
 
     // masks to know if a pixel is accessible and if it has been already added to some region
     vector<bool> accessible_pixel_mask(width * height);
@@ -392,8 +386,8 @@ void ERFilterNM::er_tree_extract( InputArray image )
         int non_boundary_neighbours = 0;
         int non_boundary_neighbours_horiz = 0;
 
-        unsigned char quad_before[4] = {0,0,0,0};
-        unsigned char quad_after[4] = {0,0,0,0};
+        int quad_before[4] = {0,0,0,0};
+        int quad_after[4] = {0,0,0,0};
         quad_after[0] = 1<<1;
         quad_after[1] = 1<<3;
         quad_after[2] = 1<<2;
@@ -526,9 +520,7 @@ void ERFilterNM::er_tree_extract( InputArray image )
                 ERStat *stat = er_stack.at(r);
                 if (stat->crossings)
                 {
-                    stat->crossings->clear();
-                    delete(stat->crossings);
-                    stat->crossings = NULL;
+                    stat->crossings.release();
                 }
                 deleteERStatTree(stat);
             }
@@ -544,9 +536,9 @@ void ERFilterNM::er_tree_extract( InputArray image )
         current_edge  = boundary_edges[threshold_level].back();
         boundary_edges[threshold_level].erase(boundary_edges[threshold_level].end()-1);
 
-        while (boundary_pixes[threshold_level].empty() && (threshold_level < (255/thresholdDelta)+1))
-            threshold_level++;
-
+        for (; threshold_level < (255/thresholdDelta)+1; threshold_level++)
+            if (!boundary_pixes[threshold_level].empty())
+                break;
 
         int new_level = image_data[current_pixel];
 
@@ -665,9 +657,7 @@ void ERFilterNM::er_merge(ERStat *parent, ERStat *child)
     child->med_crossings = (float)m_crossings.at(1);
 
     // free unnecessary mem
-    child->crossings->clear();
-    delete(child->crossings);
-    child->crossings = NULL;
+    child->crossings.release();
 
     // recover the original grey-level
     child->level = child->level*thresholdDelta;
@@ -714,9 +704,7 @@ void ERFilterNM::er_merge(ERStat *parent, ERStat *child)
         // free mem
         if(child->crossings)
         {
-            child->crossings->clear();
-            delete(child->crossings);
-            child->crossings = NULL;
+            child->crossings.release();
         }
         delete(child);
     }
@@ -790,23 +778,22 @@ ERStat* ERFilterNM::er_save( ERStat *er, ERStat *parent, ERStat *prev )
 // recursively walk the tree and filter (remove) regions using the callback classifier
 ERStat* ERFilterNM::er_tree_filter ( InputArray image, ERStat * stat, ERStat *parent, ERStat *prev )
 {
-    Mat src = image.getMat();
     // assert correct image type
-    CV_Assert( src.type() == CV_8UC1 );
+    CV_Assert( image.type() == CV_8UC1 );
+
+    Mat src = image.getMat();
 
     //Fill the region and calculate 2nd stage features
-    Mat region = region_mask(Rect(Point(stat->rect.x,stat->rect.y),Point(stat->rect.br().x+2,stat->rect.br().y+2)));
+    Mat region = region_mask(Rect(stat->rect.tl(), stat->rect.br() + Point(2,2)));
     region = Scalar(0);
     int newMaskVal = 255;
     int flags = 4 + (newMaskVal << 8) + FLOODFILL_FIXED_RANGE + FLOODFILL_MASK_ONLY;
     Rect rect;
 
-    floodFill( src(Rect(Point(stat->rect.x,stat->rect.y),Point(stat->rect.br().x,stat->rect.br().y))),
-               region, Point(stat->pixel%src.cols - stat->rect.x, stat->pixel/src.cols - stat->rect.y),
+    floodFill( src(stat->rect),
+               region, Point(stat->pixel%src.cols, stat->pixel/src.cols) - stat->rect.tl(),
                Scalar(255), &rect, Scalar(stat->level), Scalar(0), flags );
-    rect.width += 2;
-    rect.height += 2;
-    region = region(rect);
+    region = region(Rect(1, 1, rect.width, rect.height));
 
     vector<vector<Point> > contours;
     vector<Point> contour_poly;
@@ -1161,7 +1148,7 @@ Ptr<ERFilter> createERFilterNM2(const Ptr<ERFilter::Callback>& cb, float minProb
     The function takes as parameter the XML or YAML file with the classifier model
     (e.g. trained_classifierNM1.xml) returns a pointer to ERFilter::Callback.
 */
-Ptr<ERFilter::Callback> loadClassifierNM1(const string& filename)
+Ptr<ERFilter::Callback> loadClassifierNM1(const String& filename)
 
 {
     return makePtr<ERClassifierNM1>(filename);
@@ -1172,7 +1159,7 @@ Ptr<ERFilter::Callback> loadClassifierNM1(const string& filename)
     The function takes as parameter the XML or YAML file with the classifier model
     (e.g. trained_classifierNM2.xml) returns a pointer to ERFilter::Callback.
 */
-Ptr<ERFilter::Callback> loadClassifierNM2(const string& filename)
+Ptr<ERFilter::Callback> loadClassifierNM2(const String& filename)
 {
     return makePtr<ERClassifierNM2>(filename);
 }
@@ -1236,7 +1223,7 @@ void get_gradient_magnitude(Mat& _grey_img, Mat& _gradient_magnitude)
                            ERFILTER_NM_RGBLGrad and ERFILTER_NM_IHSGrad.
 
 */
-void computeNMChannels(InputArray _src, OutputArrayOfArrays _channels, int _mode)
+void computeNMChannels(InputArray _src, CV_OUT OutputArrayOfArrays _channels, int _mode)
 {
 
     CV_Assert( ( _mode == ERFILTER_NM_RGBLGrad ) || ( _mode == ERFILTER_NM_IHSGrad ) );
@@ -2820,12 +2807,12 @@ bool guo_hall_thinning(const Mat1b & img, Mat& skeleton)
             p8 = (skeleton.data[row     * skeleton.cols + col-1]) > 0;
             p9 = (skeleton.data[(row-1) * skeleton.cols + col-1]) > 0;
 
-            int C  = (!p2 & (p3 | p4)) + (!p4 & (p5 | p6)) +
-                    (!p6 & (p7 | p8)) + (!p8 & (p9 | p2));
-            int N1 = (p9 | p2) + (p3 | p4) + (p5 | p6) + (p7 | p8);
-            int N2 = (p2 | p3) + (p4 | p5) + (p6 | p7) + (p8 | p9);
+            int C  = (!p2 && (p3 || p4)) + (!p4 && (p5 || p6)) +
+                    (!p6 && (p7 || p8)) + (!p8 && (p9 || p2));
+            int N1 = (p9 || p2) + (p3 || p4) + (p5 || p6) + (p7 || p8);
+            int N2 = (p2 || p3) + (p4 || p5) + (p6 || p7) + (p8 || p9);
             int N  = N1 < N2 ? N1 : N2;
-            int m  = iter == 0 ? ((p6 | p7 | !p9) & p8) : ((p2 | p3 | !p5) & p4);
+            int m  = iter == 0 ? ((p6 || p7 || !p9) && p8) : ((p2 || p3 || !p5) && p4);
 
             if ((C == 1) && (N >= 2) && (N <= 3) && (m == 0))
             {
@@ -2865,9 +2852,7 @@ bool guo_hall_thinning(const Mat1b & img, Mat& skeleton)
 }
 
 
-float extract_features(Mat &grey, Mat& channel, vector<ERStat> &regions, vector<ERFeatures> &features);
-
-float extract_features(Mat &grey, Mat& channel, vector<ERStat> &regions, vector<ERFeatures> &features)
+static float extract_features(Mat &grey, Mat& channel, vector<ERStat> &regions, vector<ERFeatures> &features)
 {
     // assert correct image type
     CV_Assert(( channel.type() == CV_8UC1 ) && ( grey.type() == CV_8UC1 ));
@@ -2896,18 +2881,15 @@ float extract_features(Mat &grey, Mat& channel, vector<ERStat> &regions, vector<
         {
 
             //Fill the region and calculate features
-            Mat region = region_mask(Rect(Point(stat->rect.x,stat->rect.y),
-                                          Point(stat->rect.br().x+2,stat->rect.br().y+2)));
+            Mat region = region_mask(Rect(stat->rect.tl(),
+                                          stat->rect.br() + Point(2,2)));
             region = Scalar(0);
             int newMaskVal = 255;
             int flags = 4 + (newMaskVal << 8) + FLOODFILL_FIXED_RANGE + FLOODFILL_MASK_ONLY;
-            Rect rect;
 
-            floodFill( channel(Rect(Point(stat->rect.x,stat->rect.y),Point(stat->rect.br().x,stat->rect.br().y))),
+            floodFill( channel(stat->rect),
                        region, Point(stat->pixel%channel.cols - stat->rect.x, stat->pixel/channel.cols - stat->rect.y),
-                       Scalar(255), &rect, Scalar(stat->level), Scalar(0), flags );
-            rect.width += 2;
-            rect.height += 2;
+                       Scalar(255), NULL, Scalar(stat->level), Scalar(0), flags );
             Mat rect_mask = region_mask(Rect(stat->rect.x+1,stat->rect.y+1,stat->rect.width,stat->rect.height));
 
 
@@ -2917,7 +2899,7 @@ float extract_features(Mat &grey, Mat& channel, vector<ERStat> &regions, vector<
             f.intensity_std  = (float)std[0];
 
             Mat tmp,bw;
-            region_mask(Rect(stat->rect.x+1,stat->rect.y+1,stat->rect.width,stat->rect.height)).copyTo(bw);
+            rect_mask.copyTo(bw);
             distanceTransform(bw, tmp, DIST_L1,3); //L1 gives distance in round integers while L2 floats
 
             // Add border because if region span all the image size skeleton will crash
@@ -3519,19 +3501,16 @@ bool isValidPair(Mat &grey, Mat &lab, Mat &mask, vector<Mat> &channels, vector<
     i = &regions[idx1[0]][idx1[1]];
     j = &regions[idx2[0]][idx2[1]];
 
-    Mat region = mask(Rect(Point(i->rect.x,i->rect.y),
-                           Point(i->rect.br().x+2,i->rect.br().y+2)));
+    Mat region = mask(Rect(i->rect.tl(),
+                           i->rect.br()+ Point(2,2)));
     region = Scalar(0);
 
     int newMaskVal = 255;
     int flags = 4 + (newMaskVal << 8) + FLOODFILL_FIXED_RANGE + FLOODFILL_MASK_ONLY;
-    Rect rect;
 
-    floodFill( channels[idx1[0]](Rect(Point(i->rect.x,i->rect.y),Point(i->rect.br().x,i->rect.br().y))),
-               region, Point(i->pixel%grey.cols - i->rect.x, i->pixel/grey.cols - i->rect.y),
-               Scalar(255), &rect, Scalar(i->level), Scalar(0), flags);
-    rect.width += 2;
-    rect.height += 2;
+    floodFill( channels[idx1[0]](i->rect),
+               region, Point(i->pixel%grey.cols, i->pixel/grey.cols) - i->rect.tl(),
+               Scalar(255), NULL, Scalar(i->level), Scalar(0), flags);
     Mat rect_mask = mask(Rect(i->rect.x+1,i->rect.y+1,i->rect.width,i->rect.height));
 
     Scalar mean,std;
@@ -3541,15 +3520,12 @@ bool isValidPair(Mat &grey, Mat &lab, Mat &mask, vector<Mat> &channels, vector<
     float a_mean1 = (float)mean[1];
     float b_mean1 = (float)mean[2];
 
-    region = mask(Rect(Point(j->rect.x,j->rect.y),
-                           Point(j->rect.br().x+2,j->rect.br().y+2)));
+    region = mask(Rect(j->rect.tl(), j->rect.br()+ Point(2,2)));
     region = Scalar(0);
 
-    floodFill( channels[idx2[0]](Rect(Point(j->rect.x,j->rect.y),Point(j->rect.br().x,j->rect.br().y))),
-               region, Point(j->pixel%grey.cols - j->rect.x, j->pixel/grey.cols - j->rect.y),
-               Scalar(255), &rect, Scalar(j->level), Scalar(0), flags);
-    rect.width += 2;
-    rect.height += 2;
+    floodFill( channels[idx2[0]](j->rect),
+               region, Point(j->pixel%grey.cols, j->pixel/grey.cols) - j->rect.tl(),
+               Scalar(255), NULL, Scalar(j->level), Scalar(0), flags);
     rect_mask = mask(Rect(j->rect.x+1,j->rect.y+1,j->rect.width,j->rect.height));
 
     meanStdDev(grey(j->rect),mean,std,rect_mask);
@@ -4094,6 +4070,22 @@ void erGrouping(InputArray image, InputArrayOfArrays channels, vector<vector<ERS
 
 }
 
+void erGrouping(InputArray image, InputArray channel, vector<vector<Point> > contours, CV_OUT std::vector<Rect> &groups_rects, int method, const String& filename, float minProbability)
+{
+    CV_Assert( image.getMat().type() == CV_8UC3 );
+    CV_Assert( channel.getMat().type() == CV_8UC1 );
+    CV_Assert( !((method == ERGROUPING_ORIENTATION_ANY) && (filename.empty())) );
+
+    vector<Mat> channels;
+    channels.push_back(channel.getMat());
+    vector<vector<ERStat> > regions;
+    MSERsToERStats(channel, contours, regions);
+    regions.pop_back();
+    std::vector<std::vector<Vec2i> > groups;
+
+    erGrouping(image, channels, regions,  groups,  groups_rects, method, filename, minProbability);
+}
+
 /*!
  * MSERsToERStats function converts MSER contours (vector<Point>) to ERStat regions.
  * It takes as input the contours provided by the OpenCV MSER feature detector and returns as output two vectors
@@ -4167,5 +4159,52 @@ void MSERsToERStats(InputArray image, vector<vector<Point> > &contours, vector<v
   }
 }
 
+// Utility funtion for scripting
+void detectRegions(InputArray image, const Ptr<ERFilter>& er_filter1, const Ptr<ERFilter>& er_filter2, CV_OUT vector< vector<Point> >& regions)
+{
+    // assert correct image type
+    CV_Assert( image.type() == CV_8UC1 );
+    // at least one ERFilter must be passed
+    CV_Assert( !er_filter1.empty() );
+
+    vector<ERStat> ers;
+
+    er_filter1->run(image, ers);
+
+    if (!er_filter2.empty())
+    {
+      er_filter2->run(image, ers);
+    }
+
+    //Convert each ER to vector<Point> and push it to output regions
+    const Mat src = image.getMat();
+    for (size_t i=1; i < ers.size(); i++) //start from 1 to deprecate root region
+    {
+      ERStat* stat = &ers[i];
+
+      //Fill the region and calculate 2nd stage features
+      Mat region_mask(Size(stat->rect.width + 2, stat->rect.height + 2), CV_8UC1, Scalar(0));
+      Mat region = region_mask(Rect(1, 1, stat->rect.width, stat->rect.height));
+
+      int newMaskVal = 255;
+      int flags = 4 + (newMaskVal << 8) + FLOODFILL_FIXED_RANGE + FLOODFILL_MASK_ONLY;
+
+      const Point seed_pt(stat->pixel%src.cols, stat->pixel/src.cols);
+      uchar seed_v = src.at<uchar>(seed_pt);
+      CV_Assert((int)seed_v <= stat->level);
+
+      floodFill( src(stat->rect),
+                 region_mask,
+                 seed_pt - stat->rect.tl(),
+                 Scalar(255), NULL, Scalar(/*stat->level*/255), Scalar(0), flags );
+
+      vector<vector<Point> > contours;
+      vector<Vec4i> hierarchy;
+      findContours( region, contours, hierarchy, RETR_TREE, CHAIN_APPROX_NONE, stat->rect.tl() );
+
+      regions.push_back(contours[0]);
+    }
+}
+
 }
 }
diff --git a/contrib/modules/text/src/ocr_beamsearch_decoder.cpp b/contrib/modules/text/src/ocr_beamsearch_decoder.cpp
index 3ab24d2..41be856 100644
--- a/contrib/modules/text/src/ocr_beamsearch_decoder.cpp
+++ b/contrib/modules/text/src/ocr_beamsearch_decoder.cpp
@@ -566,7 +566,7 @@ OCRBeamSearchClassifierCNN::OCRBeamSearchClassifierCNN (const string& filename)
 
     nr_feature = weights.rows;
     nr_class   = weights.cols;
-    patch_size  = (int)sqrt(kernels.cols);
+    patch_size  = (int)sqrt((float)kernels.cols);
     window_size = 4*patch_size;
     step_size   = 4;
     quad_size   = 12;
diff --git a/contrib/modules/text/src/ocr_hmm_decoder.cpp b/contrib/modules/text/src/ocr_hmm_decoder.cpp
index 002dc86..e436749 100644
--- a/contrib/modules/text/src/ocr_hmm_decoder.cpp
+++ b/contrib/modules/text/src/ocr_hmm_decoder.cpp
@@ -935,7 +935,7 @@ public:
 
 protected:
     void normalizeAndZCA(Mat& patches);
-    double eval_feature(Mat& feature, double* prob_estimates);
+    double eval_feature(Mat& feature, vector<double>& prob_estimates);
 
 private:
     int nr_class;		 // number of classes
@@ -982,7 +982,7 @@ OCRHMMClassifierCNN::OCRHMMClassifierCNN (const string& filename)
 
     nr_feature  = weights.rows;
     nr_class    = weights.cols;
-    patch_size  = (int)sqrt(kernels.cols);
+    patch_size  = (int)sqrt((float)kernels.cols);
     // algorithm internal parameters
     window_size = 32;
     num_quads   = 25;
@@ -1089,7 +1089,7 @@ void OCRHMMClassifierCNN::eval( InputArray _src, vector<int>& out_class, vector<
                 (feature_max.at<double>(0,k)-feature_min.at<double>(0,k));
     }
 
-    double *p = new double[nr_class];
+    vector<double> p(nr_class, 0);
     double predict_label = eval_feature(feature,p);
     //cout << " Prediction: " << vocabulary[predict_label] << " with probability " << p[0] << endl;
     if (predict_label < 0)
@@ -1107,7 +1107,6 @@ void OCRHMMClassifierCNN::eval( InputArray _src, vector<int>& out_class, vector<
       }
     }
 
-
 }
 
 // normalize for contrast and apply ZCA whitening to a set of image patches
@@ -1157,11 +1156,8 @@ void OCRHMMClassifierCNN::normalizeAndZCA(Mat& patches)
 
 }
 
-double OCRHMMClassifierCNN::eval_feature(Mat& feature, double* prob_estimates)
+double OCRHMMClassifierCNN::eval_feature(Mat& feature, vector<double>& prob_estimates)
 {
-    for(int i=0;i<nr_class;i++)
-        prob_estimates[i] = 0;
-
     for(int idx=0; idx<nr_feature; idx++)
         for(int i=0;i<nr_class;i++)
             prob_estimates[i] += weights.at<float>(idx,i)*feature.at<double>(0,idx); //TODO use vectorized dot product
@@ -1206,7 +1202,7 @@ the output transition_probabilities_table with them.
 The transition_probabilities_table can be used as input in the OCRHMMDecoder::create() and OCRBeamSearchDecoder::create() methods.
 @note
    -   (C++) An alternative would be to load the default generic language transition table provided in the text module samples folder (created from ispell 42869 english words list) :
-        <https://github.com/Itseez/opencv_contrib/blob/master/modules/text/samples/OCRHMM_transitions_table.xml>
+        <https://github.com/opencv/opencv_contrib/blob/master/modules/text/samples/OCRHMM_transitions_table.xml>
  */
 void createOCRHMMTransitionsTable(string& vocabulary, vector<string>& lexicon, OutputArray _transitions)
 {
diff --git a/contrib/modules/text/test/test_detection.cpp b/contrib/modules/text/test/test_detection.cpp
new file mode 100644
index 0000000..bd0a30c
--- /dev/null
+++ b/contrib/modules/text/test/test_detection.cpp
@@ -0,0 +1,91 @@
+// This file is part of OpenCV project.
+// It is subject to the license terms in the LICENSE file found in the top-level directory
+// of this distribution and at http://opencv.org/license.html.
+
+#include "test_precomp.hpp"
+#include "opencv2/imgcodecs.hpp"
+
+using namespace cv;
+using namespace cv::text;
+using namespace cvtest;
+
+namespace {
+
+// Just skip test in case of missed testdata
+static cv::String findDataFile(const String& path)
+{
+    return cvtest::findDataFile(path, false);
+}
+
+
+PARAM_TEST_CASE(Detection, std::string, bool)
+{
+    Ptr<ERFilter> er_filter1;
+    Ptr<ERFilter> er_filter2;
+
+    // SetUp doesn't handle SkipTestException
+    void InitERFilter()
+    {
+        String nm1_file = findDataFile("trained_classifierNM1.xml");
+        String nm2_file = findDataFile("trained_classifierNM2.xml");
+
+        // Create ERFilter objects with the 1st and 2nd stage default classifiers
+        er_filter1 = createERFilterNM1(loadClassifierNM1(nm1_file),16,0.00015f,0.13f,0.2f,true,0.1f);
+        er_filter2 = createERFilterNM2(loadClassifierNM2(nm2_file),0.5);
+    }
+};
+
+TEST_P(Detection, sample)
+{
+    InitERFilter();
+
+    std::string imageName = GET_PARAM(0);
+    bool anyDirection = GET_PARAM(1);
+    std::cout << "Image: " << imageName << std::endl;
+    std::cout << "Orientation: " << (anyDirection ? "any" : "horiz") << std::endl;
+    Mat src = cv::imread(findDataFile(imageName));
+    ASSERT_FALSE(src.empty());
+
+    // Extract channels to be processed individually
+    std::vector<Mat> channels;
+    computeNMChannels(src, channels);
+
+    // Append negative channels to detect ER- (bright regions over dark background)
+    for (size_t c = channels.size(); c > 0; c--)
+        channels.push_back(255 - channels[c - 1]);
+
+    std::vector<std::vector<ERStat> > regions(channels.size());
+    // Apply the default cascade classifier to each independent channel (could be done in parallel)
+    for (size_t c = 0; c < channels.size(); c++)
+    {
+        er_filter1->run(channels[c], regions[c]);
+        er_filter2->run(channels[c], regions[c]);
+    }
+
+    // Detect character groups
+    std::vector< std::vector<Vec2i> > region_groups;
+    std::vector<Rect> groups_boxes;
+    if (!anyDirection)
+        erGrouping(src, channels, regions, region_groups, groups_boxes, ERGROUPING_ORIENTATION_HORIZ);
+    else
+        erGrouping(src, channels, regions, region_groups, groups_boxes, ERGROUPING_ORIENTATION_ANY,
+                   findDataFile("trained_classifier_erGrouping.xml"), 0.5);
+
+    std::cout << "Found groups: " << groups_boxes.size() << std::endl;
+
+    EXPECT_GT(groups_boxes.size(), 3u);
+}
+
+INSTANTIATE_TEST_CASE_P(Text, Detection,
+    testing::Combine(
+        testing::Values(
+            "text/scenetext01.jpg",
+            "text/scenetext02.jpg",
+            "text/scenetext03.jpg",
+            "text/scenetext04.jpg",
+            "text/scenetext05.jpg",
+            "text/scenetext06.jpg"
+        ),
+        testing::Bool()
+    ));
+}
diff --git a/contrib/modules/text/test/test_main.cpp b/contrib/modules/text/test/test_main.cpp
new file mode 100644
index 0000000..6a1bfde
--- /dev/null
+++ b/contrib/modules/text/test/test_main.cpp
@@ -0,0 +1,6 @@
+#include "test_precomp.hpp"
+
+CV_TEST_MAIN("",
+    cvtest::addDataSearchSubDirectory("contrib"),
+    cvtest::addDataSearchSubDirectory("contrib/text")
+)
diff --git a/contrib/modules/text/test/test_precomp.hpp b/contrib/modules/text/test/test_precomp.hpp
new file mode 100644
index 0000000..a51ea32
--- /dev/null
+++ b/contrib/modules/text/test/test_precomp.hpp
@@ -0,0 +1,8 @@
+#ifndef __OPENCV_TEST_TEXT_PRECOMP_HPP__
+#define __OPENCV_TEST_TEXT_PRECOMP_HPP__
+
+#include "opencv2/core.hpp"
+#include "opencv2/ts.hpp"
+#include "opencv2/text.hpp"
+
+#endif
diff --git a/contrib/modules/tracking/CMakeLists.txt b/contrib/modules/tracking/CMakeLists.txt
index 9a87174..a8b3183 100644
--- a/contrib/modules/tracking/CMakeLists.txt
+++ b/contrib/modules/tracking/CMakeLists.txt
@@ -1,2 +1,2 @@
 set(the_description "Tracking API")
-ocv_define_module(tracking opencv_imgproc opencv_core opencv_video opencv_highgui opencv_datasets WRAP python)
+ocv_define_module(tracking opencv_imgproc opencv_core opencv_video opencv_highgui opencv_dnn opencv_plot OPTIONAL opencv_datasets WRAP python)
\ No newline at end of file
diff --git a/contrib/modules/tracking/README.md b/contrib/modules/tracking/README.md
index fd80468..01cf79d 100644
--- a/contrib/modules/tracking/README.md
+++ b/contrib/modules/tracking/README.md
@@ -1,3 +1,4 @@
-Long-term optical tracking API
-==============================
+Object tracking API
+===================
 
+Use and/or evaluate one of 5 different visual object tracking techniques.
diff --git a/contrib/modules/tracking/doc/diagrams.markdown b/contrib/modules/tracking/doc/diagrams.markdown
deleted file mode 100644
index 32abd2e..0000000
--- a/contrib/modules/tracking/doc/diagrams.markdown
+++ /dev/null
@@ -1,256 +0,0 @@
-Tracking diagrams {#tracking_diagrams}
-=================
-
-General diagram
-===============
-
- at startuml{tracking_uml_general.png}
-  package "Tracker"
-  package "TrackerFeature"
-  package "TrackerSampler"
-  package "TrackerModel"
-
-  Tracker -> TrackerModel: create
-  Tracker -> TrackerSampler: create
-  Tracker -> TrackerFeature: create
- at enduml
-
-Tracker diagram
-===============
-
- at startuml{tracking_uml_tracking.png}
-  package "Tracker package" #DDDDDD {
-
-
-  class Algorithm
-
-  class Tracker{
-    Ptr<TrackerFeatureSet> featureSet;
-    Ptr<TrackerSampler> sampler;
-    Ptr<TrackerModel> model;
-    ---
-    +static Ptr<Tracker> create(const string& trackerType);
-    +bool init(const Mat& image, const Rect& boundingBox);
-    +bool update(const Mat& image, Rect& boundingBox);
-  }
-  class Tracker
-  note right: Tracker is the general interface for each specialized trackers
-  class TrackerMIL{
-    +static Ptr<TrackerMIL> createTracker(const TrackerMIL::Params &parameters);
-      +virtual ~TrackerMIL();
-  }
-  class TrackerBoosting{
-    +static Ptr<TrackerBoosting> createTracker(const TrackerBoosting::Params &parameters);
-      +virtual ~TrackerBoosting();
-  }
-  Algorithm <|-- Tracker : virtual inheritance
-  Tracker <|-- TrackerMIL
-  Tracker <|-- TrackerBoosting
-
-  note "Single instance of the Tracker" as N1
-  TrackerBoosting .. N1
-  TrackerMIL .. N1
-  }
-
- at enduml
-
-TrackerFeatureSet diagram
-=========================
-
- at startuml{tracking_uml_feature.png}
-  package "TrackerFeature package" #DDDDDD {
-
-  class TrackerFeatureSet{
-    -vector<pair<string, Ptr<TrackerFeature> > > features
-    -vector<Mat> responses
-    ...
-    TrackerFeatureSet();
-    ~TrackerFeatureSet();
-    --
-    +extraction(const std::vector<Mat>& images);
-    +selection();
-    +removeOutliers();
-    +vector<Mat> response getResponses();
-    +vector<pair<string TrackerFeatureType, Ptr<TrackerFeature> > > getTrackerFeatures();
-    +bool addTrackerFeature(string trackerFeatureType);
-    +bool addTrackerFeature(Ptr<TrackerFeature>& feature);
-    -clearResponses();
-  }
-
-  class TrackerFeature <<virtual>>{
-    static Ptr<TrackerFeature> = create(const string& trackerFeatureType);
-    compute(const std::vector<Mat>& images, Mat& response);
-    selection(Mat& response, int npoints);
-  }
-  note bottom: Can be specialized as in table II\nA tracker can use more types of features
-
-  class TrackerFeatureFeature2D{
-    -vector<Keypoints> keypoints
-    ---
-    TrackerFeatureFeature2D(string detectorType, string descriptorType);
-    ~TrackerFeatureFeature2D();
-    ---
-    compute(const std::vector<Mat>& images, Mat& response);
-    selection( Mat& response, int npoints);
-  }
-  class TrackerFeatureHOG{
-    TrackerFeatureHOG();
-    ~TrackerFeatureHOG();
-    ---
-    compute(const std::vector<Mat>& images, Mat& response);
-    selection(Mat& response, int npoints);
-  }
-
-  TrackerFeatureSet *-- TrackerFeature
-  TrackerFeature <|-- TrackerFeatureHOG
-  TrackerFeature <|-- TrackerFeatureFeature2D
-
-
-  note "Per readability and simplicity in this diagram\n there are only two TrackerFeature but you\n can considering the implementation of the other TrackerFeature" as N1
-  TrackerFeatureHOG .. N1
-  TrackerFeatureFeature2D .. N1
-  }
-
- at enduml
-
-
-TrackerModel diagram
-====================
-
- at startuml{tracking_uml_model.png}
-  package "TrackerModel package" #DDDDDD {
-
-  class Typedef << (T,#FF7700) >>{
-    ConfidenceMap
-    Trajectory
-  }
-
-  class TrackerModel{
-    -vector<ConfidenceMap> confidenceMaps;
-    -Trajectory trajectory;
-    -Ptr<TrackerStateEstimator> stateEstimator;
-    ...
-    TrackerModel();
-    ~TrackerModel();
-
-    +bool setTrackerStateEstimator(Ptr<TrackerStateEstimator> trackerStateEstimator);
-    +Ptr<TrackerStateEstimator> getTrackerStateEstimator();
-
-    +void modelEstimation(const vector<Mat>& responses);
-    +void modelUpdate();
-    +void setLastTargetState(const Ptr<TrackerTargetState> lastTargetState);
-    +void runStateEstimator();
-
-    +const vector<ConfidenceMap>& getConfidenceMaps();
-    +const ConfidenceMap& getLastConfidenceMap();
-  }
-  class TrackerTargetState <<virtual>>{
-    Point2f targetPosition;
-    ---
-    Point2f getTargetPosition();
-    void setTargetPosition(Point2f position);
-  }
-  class TrackerTargetState
-  note bottom: Each tracker can create own state
-
-  class TrackerStateEstimator <<virtual>>{
-    ~TrackerStateEstimator();
-    static Ptr<TrackerStateEstimator> create(const String& trackeStateEstimatorType);
-    Ptr<TrackerTargetState> estimate(const vector<ConfidenceMap>& confidenceMaps)
-    void update(vector<ConfidenceMap>& confidenceMaps)
-  }
-
-  class TrackerStateEstimatorSVM{
-    TrackerStateEstimatorSVM()
-    ~TrackerStateEstimatorSVM()
-    Ptr<TrackerTargetState> estimate(const vector<ConfidenceMap>& confidenceMaps)
-    void update(vector<ConfidenceMap>& confidenceMaps)
-  }
-  class TrackerStateEstimatorMILBoosting{
-    TrackerStateEstimatorMILBoosting()
-    ~TrackerStateEstimatorMILBoosting()
-    Ptr<TrackerTargetState> estimate(const vector<ConfidenceMap>& confidenceMaps)
-    void update(vector<ConfidenceMap>& confidenceMaps)
-  }
-
-  TrackerModel -> TrackerStateEstimator: create
-  TrackerModel *-- TrackerTargetState
-  TrackerStateEstimator <|-- TrackerStateEstimatorMILBoosting
-  TrackerStateEstimator <|-- TrackerStateEstimatorSVM
-  }
- at enduml
-
-TrackerSampler diagram
-======================
-
- at startuml{tracking_uml_sampler.png}
-  package "TrackerSampler package" #DDDDDD {
-
-  class TrackerSampler{
-    -vector<pair<String, Ptr<TrackerSamplerAlgorithm> > > samplers
-    -vector<Mat> samples;
-    ...
-    TrackerSampler();
-    ~TrackerSampler();
-    +sampling(const Mat& image, Rect boundingBox);
-    +const vector<pair<String, Ptr<TrackerSamplerAlgorithm> > >& getSamplers();
-    +const vector<Mat>& getSamples();
-    +bool addTrackerSamplerAlgorithm(String trackerSamplerAlgorithmType);
-    +bool addTrackerSamplerAlgorithm(Ptr<TrackerSamplerAlgorithm>& sampler);
-    ---
-    -void clearSamples();
-  }
-
-  class TrackerSamplerAlgorithm{
-    ~TrackerSamplerAlgorithm();
-    +static Ptr<TrackerSamplerAlgorithm> create(const String& trackerSamplerType);
-    +bool sampling(const Mat& image, Rect boundingBox, vector<Mat>& sample);
-  }
-  note bottom: A tracker could sample the target\nor it could sample the target and the background
-
-
-  class TrackerSamplerCS{
-    TrackerSamplerCS();
-    ~TrackerSamplerCS();
-    +bool sampling(const Mat& image, Rect boundingBox, vector<Mat>& sample);
-  }
-  class TrackerSamplerCSC{
-    TrackerSamplerCSC();
-    ~TrackerSamplerCSC();
-    +bool sampling(const Mat& image, Rect boundingBox, vector<Mat>& sample);
-  }
-
-
-  }
- at enduml
-
-MultiTracker diagram
-======================
-
- at startuml{tracking_uml_multiple.png}
-  package "MultiTracker"
-  package "Tracker"
-
-  MultiTracker -> Tracker: create
-
-  note top of Tracker: Several classes can be generated.
- at enduml
-
- at startuml{multi_tracker_uml.png}
-
-  class MultiTracker{
-    MultiTracker(const String& trackerType = "" );
-    ~MultiTracker();
-    +bool add( const Mat& image, const Rect2d& boundingBox );
-    +bool add( const String& trackerType, const Mat& image, const Rect2d& boundingBox );
-    +bool add(const String& trackerType, const Mat& image, std::vector<Rect2d> boundingBox);
-    +bool add(const Mat& image, std::vector<Rect2d> boundingBox);
-    +bool update( const Mat& image, std::vector<Rect2d> & boundingBox );
-    +std::vector<Rect2d> objects;
-    ---
-    #std::vector< Ptr<Tracker> > trackerList;
-    #String defaultAlgorithm;
-  }
-
-
- at enduml
diff --git a/contrib/modules/tracking/doc/tracking.bib b/contrib/modules/tracking/doc/tracking.bib
index 6b8b462..8ab4fd2 100644
--- a/contrib/modules/tracking/doc/tracking.bib
+++ b/contrib/modules/tracking/doc/tracking.bib
@@ -93,3 +93,10 @@
   keywords={computer vision;feature extraction;image colour analysis;image representation;image sequences;adaptive color attributes;benchmark color sequences;color features;color representations;computer vision;image description;real-time visual tracking;tracking-by-detection framework;Color;Computational modeling;Covariance matrices;Image color analysis;Kernel;Target tracking;Visualization;Adaptive Dimensionality Reduction;Appearance Model;Color Features;Visual Tracking},
   doi={10.1109/CVPR.2014.143},
 }
+
+ at inproceedings{GOTURN,
+title={Learning to Track at 100 FPS with Deep Regression Networks},
+author={Held, David and Thrun, Sebastian and Savarese, Silvio},
+booktitle = {European Conference Computer Vision (ECCV)},
+year      = {2016}
+}
diff --git a/contrib/modules/tracking/include/opencv2/tracking.hpp b/contrib/modules/tracking/include/opencv2/tracking.hpp
index 488c2db..6efabc6 100644
--- a/contrib/modules/tracking/include/opencv2/tracking.hpp
+++ b/contrib/modules/tracking/include/opencv2/tracking.hpp
@@ -69,14 +69,9 @@ the TrackerModel is the statistical model.
 
 A recent benchmark between these algorithms can be found in @cite OOT
 
-UML design: see @ref tracking_diagrams
-
 To see how API works, try tracker demo:
 <https://github.com/lenlen/opencv/blob/tracking_api/samples/cpp/tracker.cpp>
 
- at note This Tracking API has been designed with PlantUML. If you modify this API please change UML
-in <em>modules/tracking/doc/tracking_diagrams.markdown</em>. The following reference was used in the API
-
 Creating Own Tracker
 --------------------
 
diff --git a/contrib/modules/tracking/include/opencv2/tracking/kalman_filters.hpp b/contrib/modules/tracking/include/opencv2/tracking/kalman_filters.hpp
index e733b22..7a89c87 100644
--- a/contrib/modules/tracking/include/opencv2/tracking/kalman_filters.hpp
+++ b/contrib/modules/tracking/include/opencv2/tracking/kalman_filters.hpp
@@ -62,13 +62,13 @@ public:
     * @param control - the current control vector,
     * @return the predicted estimate of the state.
     */
-    virtual Mat predict( const Mat& control = Mat() ) = 0;
+    virtual Mat predict( InputArray control = noArray() ) = 0;
 
     /** The function performs correction step of the algorithm
     * @param measurement - the current measurement vector,
     * @return the corrected estimate of the state.
     */
-    virtual Mat correct( const Mat& measurement ) = 0;
+    virtual Mat correct( InputArray measurement ) = 0;
 
     /**
     * @return the process noise cross-covariance matrix.
diff --git a/contrib/modules/tracking/include/opencv2/tracking/onlineMIL.hpp b/contrib/modules/tracking/include/opencv2/tracking/onlineMIL.hpp
index b6fc25b..78e1372 100644
--- a/contrib/modules/tracking/include/opencv2/tracking/onlineMIL.hpp
+++ b/contrib/modules/tracking/include/opencv2/tracking/onlineMIL.hpp
@@ -54,8 +54,6 @@ namespace cv
 //TODO based on the original implementation
 //http://vision.ucsd.edu/~bbabenko/project_miltrack.shtml
 
-#define  sign(s)  ((s > 0 ) ? 1 : ((s<0) ? -1 : 0))
-
 class ClfOnlineStump;
 
 class CV_EXPORTS ClfMilBoost
diff --git a/contrib/modules/tracking/include/opencv2/tracking/tracker.hpp b/contrib/modules/tracking/include/opencv2/tracking/tracker.hpp
index 5fabfec..3b32033 100644
--- a/contrib/modules/tracking/include/opencv2/tracking/tracker.hpp
+++ b/contrib/modules/tracking/include/opencv2/tracking/tracker.hpp
@@ -57,7 +57,7 @@
 /*
  * Partially based on:
  * ====================================================================================================================
- * 	- [AAM] S. Salti, A. Cavallaro, L. Di Stefano, Adaptive Appearance Modeling for Video Tracking: Survey and Evaluation
+ *   - [AAM] S. Salti, A. Cavallaro, L. Di Stefano, Adaptive Appearance Modeling for Video Tracking: Survey and Evaluation
  *  - [AMVOT] X. Li, W. Hu, C. Shen, Z. Zhang, A. Dick, A. van den Hengel, A Survey of Appearance Models in Visual Object Tracking
  *
  * This Tracking API has been designed with PlantUML. If you modify this API please change UML files under modules/tracking/doc/uml
@@ -200,7 +200,7 @@ class CV_EXPORTS TrackerFeatureSet
   bool blockAddTrackerFeature;
 
   std::vector<std::pair<String, Ptr<TrackerFeature> > > features;  //list of features
-  std::vector<Mat> responses;				//list of response after compute
+  std::vector<Mat> responses;        //list of response after compute
 
 };
 
@@ -567,7 +567,7 @@ class CV_EXPORTS_W Tracker : public virtual Algorithm
 
   Ptr<TrackerModel> getModel()
   {
-	  return model;
+    return model;
   }
 
  protected:
@@ -806,7 +806,7 @@ class CV_EXPORTS TrackerSamplerCSC : public TrackerSamplerAlgorithm
     Params();
     float initInRad;        //!< radius for gathering positive instances during init
     float trackInPosRad;    //!< radius for gathering positive instances during tracking
-    float searchWinSize;	//!< size of search window
+    float searchWinSize;  //!< size of search window
     int initMaxNegNum;      //!< # negative samples to use during init
     int trackMaxPosNum;     //!< # positive samples to use during training
     int trackMaxNegNum;     //!< # negative samples to use during training
@@ -1090,12 +1090,12 @@ class CV_EXPORTS TrackerMIL : public Tracker
   {
     Params();
     //parameters for sampler
-    float samplerInitInRadius;	//!< radius for gathering positive instances during init
+    float samplerInitInRadius;  //!< radius for gathering positive instances during init
     int samplerInitMaxNegNum;  //!< # negative samples to use during init
     float samplerSearchWinSize;  //!< size of search window
     float samplerTrackInRadius;  //!< radius for gathering positive instances during tracking
-    int samplerTrackMaxPosNum;	//!< # positive samples to use during tracking
-    int samplerTrackMaxNegNum;	//!< # negative samples to use during tracking
+    int samplerTrackMaxPosNum;  //!< # positive samples to use during tracking
+    int samplerTrackMaxNegNum;  //!< # negative samples to use during tracking
     int featureSetNumFeatures;  //!< # features
 
     void read( const FileNode& fn );
@@ -1205,56 +1205,85 @@ class CV_EXPORTS TrackerTLD : public Tracker
 class CV_EXPORTS TrackerKCF : public Tracker
 {
 public:
-	/**
-	* \brief Feature type to be used in the tracking grayscale, colornames, compressed color-names
-	* The modes available now:
-	-   "GRAY" -- Use grayscale values as the feature
-	-   "CN" -- Color-names feature
-	*/
-	enum MODE {
-		GRAY = (1u << 0),
-		CN = (1u << 1),
-		CUSTOM = (1u << 2)
-	};
-
-	struct CV_EXPORTS Params
-	{
-		/**
-		* \brief Constructor
-		*/
-		Params();
-
-		/**
-		* \brief Read parameters from file, currently unused
-		*/
-		void read(const FileNode& /*fn*/);
-
-		/**
-		* \brief Read parameters from file, currently unused
-		*/
-		void write(FileStorage& /*fs*/) const;
-
-		double sigma;                 //!<  gaussian kernel bandwidth
-		double lambda;                //!<  regularization
-		double interp_factor;         //!<  linear interpolation factor for adaptation
-		double output_sigma_factor;   //!<  spatial bandwidth (proportional to target)
-		double pca_learning_rate;     //!<  compression learning rate
-		bool resize;                  //!<  activate the resize feature to improve the processing speed
-		bool split_coeff;             //!<  split the training coefficients into two matrices
-		bool wrap_kernel;             //!<  wrap around the kernel values
-		bool compress_feature;        //!<  activate the pca method to compress the features
-		int max_patch_size;           //!<  threshold for the ROI size
-		int compressed_size;          //!<  feature size after compression
-		unsigned int desc_pca;        //!<  compressed descriptors of TrackerKCF::MODE
-		unsigned int desc_npca;       //!<  non-compressed descriptors of TrackerKCF::MODE
-	};
-
-	virtual void setFeatureExtractor(void(*)(const Mat, const Rect, Mat&), bool pca_func = false);
-
-	/** @brief Constructor
-	@param parameters KCF parameters TrackerKCF::Params
-	*/
-	BOILERPLATE_CODE("KCF", TrackerKCF);
+  /**
+  * \brief Feature type to be used in the tracking grayscale, colornames, compressed color-names
+  * The modes available now:
+  -   "GRAY" -- Use grayscale values as the feature
+  -   "CN" -- Color-names feature
+  */
+  enum MODE {
+    GRAY = (1u << 0),
+    CN = (1u << 1),
+    CUSTOM = (1u << 2)
+  };
+
+  struct CV_EXPORTS Params
+  {
+    /**
+    * \brief Constructor
+    */
+    Params();
+
+    /**
+    * \brief Read parameters from file, currently unused
+    */
+    void read(const FileNode& /*fn*/);
+
+    /**
+    * \brief Read parameters from file, currently unused
+    */
+    void write(FileStorage& /*fs*/) const;
+
+    double sigma;                 //!<  gaussian kernel bandwidth
+    double lambda;                //!<  regularization
+    double interp_factor;         //!<  linear interpolation factor for adaptation
+    double output_sigma_factor;   //!<  spatial bandwidth (proportional to target)
+    double pca_learning_rate;     //!<  compression learning rate
+    bool resize;                  //!<  activate the resize feature to improve the processing speed
+    bool split_coeff;             //!<  split the training coefficients into two matrices
+    bool wrap_kernel;             //!<  wrap around the kernel values
+    bool compress_feature;        //!<  activate the pca method to compress the features
+    int max_patch_size;           //!<  threshold for the ROI size
+    int compressed_size;          //!<  feature size after compression
+    unsigned int desc_pca;        //!<  compressed descriptors of TrackerKCF::MODE
+    unsigned int desc_npca;       //!<  non-compressed descriptors of TrackerKCF::MODE
+  };
+
+  virtual void setFeatureExtractor(void(*)(const Mat, const Rect, Mat&), bool pca_func = false);
+
+  /** @brief Constructor
+  @param parameters KCF parameters TrackerKCF::Params
+  */
+  BOILERPLATE_CODE("KCF", TrackerKCF);
+};
+
+/** @brief GOTURN (@cite GOTURN) is kind of trackers based on Convolutional Neural Networks (CNN). While taking all advantages of CNN trackers,
+ *  GOTURN is much faster due to offline training without online fine-tuning nature.
+ *  GOTURN tracker addresses the problem of single target tracking: given a bounding box label of an object in the first frame of the video,
+ *  we track that object through the rest of the video. NOTE: Current method of GOTURN does not handle occlusions; however, it is fairly
+ *  robust to viewpoint changes, lighting changes, and deformations.
+ *  Inputs of GOTURN are two RGB patches representing Target and Search patches resized to 227x227.
+ *  Outputs of GOTURN are predicted bounding box coordinates, relative to Search patch coordinate system, in format X1,Y1,X2,Y2.
+ *  Original paper is here: <http://davheld.github.io/GOTURN/GOTURN.pdf>
+ *  As long as original authors implementation: <https://github.com/davheld/GOTURN#train-the-tracker>
+ *  Implementation of training algorithm is placed in separately here due to 3d-party dependencies:
+ *  <https://github.com/Auron-X/GOTURN_Training_Toolkit>
+ *  GOTURN architecture goturn.prototxt and trained model goturn.caffemodel are accessible on opencv_extra GitHub repository.
+*/
+class CV_EXPORTS TrackerGOTURN : public Tracker
+{
+public:
+  struct CV_EXPORTS Params
+  {
+    Params();
+    void read(const FileNode& /*fn*/);
+    void write(FileStorage& /*fs*/) const;
+  };
+
+  /** @brief Constructor
+  @param parameters GOTURN parameters TrackerGOTURN::Params
+  */
+  BOILERPLATE_CODE("GOTURN", TrackerGOTURN);
 };
 
 /************************************ MultiTracker Class ---By Laksono Kurnianggoro---) ************************************/
@@ -1266,103 +1295,103 @@ class CV_EXPORTS_W MultiTracker
 {
 public:
 
-	/**
-	* \brief Constructor.
-	* In the case of trackerType is given, it will be set as the default algorithm for all trackers.
-	* @param trackerType the name of the tracker algorithm to be used
-	*/
-	CV_WRAP MultiTracker(const String& trackerType = "");
-
-	/**
-	* \brief Destructor
-	*/
-	~MultiTracker();
-
-	/**
-	* \brief Add a new object to be tracked.
-	* The defaultAlgorithm will be used the newly added tracker.
-	* @param image input image
-	* @param boundingBox a rectangle represents ROI of the tracked object
-	*/
-	CV_WRAP bool add(const Mat& image, const Rect2d& boundingBox);
-
-	/**
-	* \brief Add a new object to be tracked.
-	* @param trackerType the name of the tracker algorithm to be used
-	* @param image input image
-	* @param boundingBox a rectangle represents ROI of the tracked object
-	*/
-	CV_WRAP bool add(const String& trackerType, const Mat& image, const Rect2d& boundingBox);
-
-	/**
-	* \brief Add a set of objects to be tracked.
-	* @param trackerType the name of the tracker algorithm to be used
-	* @param image input image
-	* @param boundingBox list of the tracked objects
-	*/
-	CV_WRAP bool add(const String& trackerType, const Mat& image, std::vector<Rect2d> boundingBox);
-
-	/**
-	* \brief Add a set of objects to be tracked using the defaultAlgorithm tracker.
-	* @param image input image
-	* @param boundingBox list of the tracked objects
-	*/
-	CV_WRAP bool add(const Mat& image, std::vector<Rect2d> boundingBox);
-
-	/**
-	* \brief Update the current tracking status.
-	* The result will be saved in the internal storage.
-	* @param image input image
-	*/
-	bool update(const Mat& image);
-
-	//!<  storage for the tracked objects, each object corresponds to one tracker algorithm.
-	std::vector<Rect2d> objects;
-
-	/**
-	* \brief Update the current tracking status.
-	* @param image input image
-	* @param boundingBox the tracking result, represent a list of ROIs of the tracked objects.
-	*/
-	CV_WRAP bool update(const Mat& image, CV_OUT std::vector<Rect2d> & boundingBox);
+  /**
+  * \brief Constructor.
+  * In the case of trackerType is given, it will be set as the default algorithm for all trackers.
+  * @param trackerType the name of the tracker algorithm to be used
+  */
+  CV_WRAP MultiTracker(const String& trackerType = "");
+
+  /**
+  * \brief Destructor
+  */
+  ~MultiTracker();
+
+  /**
+  * \brief Add a new object to be tracked.
+  * The defaultAlgorithm will be used the newly added tracker.
+  * @param image input image
+  * @param boundingBox a rectangle represents ROI of the tracked object
+  */
+  CV_WRAP bool add(const Mat& image, const Rect2d& boundingBox);
+
+  /**
+  * \brief Add a new object to be tracked.
+  * @param trackerType the name of the tracker algorithm to be used
+  * @param image input image
+  * @param boundingBox a rectangle represents ROI of the tracked object
+  */
+  CV_WRAP bool add(const String& trackerType, const Mat& image, const Rect2d& boundingBox);
+
+  /**
+  * \brief Add a set of objects to be tracked.
+  * @param trackerType the name of the tracker algorithm to be used
+  * @param image input image
+  * @param boundingBox list of the tracked objects
+  */
+  CV_WRAP bool add(const String& trackerType, const Mat& image, std::vector<Rect2d> boundingBox);
+
+  /**
+  * \brief Add a set of objects to be tracked using the defaultAlgorithm tracker.
+  * @param image input image
+  * @param boundingBox list of the tracked objects
+  */
+  CV_WRAP bool add(const Mat& image, std::vector<Rect2d> boundingBox);
+
+  /**
+  * \brief Update the current tracking status.
+  * The result will be saved in the internal storage.
+  * @param image input image
+  */
+  bool update(const Mat& image);
+
+  //!<  storage for the tracked objects, each object corresponds to one tracker algorithm.
+  std::vector<Rect2d> objects;
+
+  /**
+  * \brief Update the current tracking status.
+  * @param image input image
+  * @param boundingBox the tracking result, represent a list of ROIs of the tracked objects.
+  */
+  CV_WRAP bool update(const Mat& image, CV_OUT std::vector<Rect2d> & boundingBox);
 
 protected:
-	//!<  storage for the tracker algorithms.
-	std::vector< Ptr<Tracker> > trackerList;
+  //!<  storage for the tracker algorithms.
+  std::vector< Ptr<Tracker> > trackerList;
 
-	//!<  default algorithm for the tracking method.
-	String defaultAlgorithm;
+  //!<  default algorithm for the tracking method.
+  String defaultAlgorithm;
 };
 
 class ROISelector {
 public:
-	Rect2d select(Mat img, bool fromCenter = true);
-	Rect2d select(const cv::String& windowName, Mat img, bool showCrossair = true, bool fromCenter = true);
-	void select(const cv::String& windowName, Mat img, std::vector<Rect2d> & boundingBox, bool fromCenter = true);
+  Rect2d select(Mat img, bool fromCenter = true);
+  Rect2d select(const cv::String& windowName, Mat img, bool showCrossair = true, bool fromCenter = true);
+  void select(const cv::String& windowName, Mat img, std::vector<Rect2d> & boundingBox, bool fromCenter = true);
 
-	struct handlerT{
-		// basic parameters
-		bool isDrawing;
-		Rect2d box;
-		Mat image;
+  struct handlerT{
+    // basic parameters
+    bool isDrawing;
+    Rect2d box;
+    Mat image;
 
-		// parameters for drawing from the center
-		bool drawFromCenter;
-		Point2f center;
+    // parameters for drawing from the center
+    bool drawFromCenter;
+    Point2f center;
 
-		// initializer list
-		handlerT() : isDrawing(false), drawFromCenter(true) {};
-	}selectorParams;
+    // initializer list
+    handlerT() : isDrawing(false), drawFromCenter(true) {};
+  }selectorParams;
 
-	// to store the tracked objects
-	std::vector<handlerT> objects;
+  // to store the tracked objects
+  std::vector<handlerT> objects;
 
 private:
-	static void mouseHandler(int event, int x, int y, int flags, void *param);
-	void opencv_mouse_callback(int event, int x, int y, int, void *param);
+  static void mouseHandler(int event, int x, int y, int flags, void *param);
+  void opencv_mouse_callback(int event, int x, int y, int, void *param);
 
-	// save the keypressed characted
-	int key;
+  // save the keypressed characted
+  int key;
 };
 
 Rect2d CV_EXPORTS_W selectROI(Mat img, bool fromCenter = true);
@@ -1379,45 +1408,45 @@ void CV_EXPORTS_W selectROI(const cv::String& windowName, Mat img, std::vector<R
 class CV_EXPORTS MultiTracker_Alt
 {
 public:
-	/** @brief Constructor for Multitracker
-	*/
-	MultiTracker_Alt()
-	{
-		targetNum = 0;
-	}
-
-	/** @brief Add a new target to a tracking-list and initialize the tracker with a know bounding box that surrounding the target
-	@param image The initial frame
-	@param boundingBox The initial boundig box of target
-	@param tracker_algorithm_name Multi-tracker algorithm name
-
-	@return True if new target initialization went succesfully, false otherwise
-	*/
-	bool addTarget(const Mat& image, const Rect2d& boundingBox, String tracker_algorithm_name);
-
-	/** @brief Update all trackers from the tracking-list, find a new most likely bounding boxes for the targets
-	@param image The current frame
-
-	@return True means that all targets were located and false means that tracker couldn't locate one of the targets in
-	current frame. Note, that latter *does not* imply that tracker has failed, maybe target is indeed
-	missing from the frame (say, out of sight)
-	*/
-	bool update(const Mat& image);
-
-	/** @brief Current number of targets in tracking-list
-	*/
-	int targetNum;
-
-	/** @brief Trackers list for Multi-Object-Tracker
-	*/
-	std::vector <Ptr<Tracker> > trackers;
-
-	/** @brief Bounding Boxes list for Multi-Object-Tracker
-	*/
-	std::vector <Rect2d> boundingBoxes;
-	/** @brief List of randomly generated colors for bounding boxes display
-	*/
-	std::vector<Scalar> colors;
+  /** @brief Constructor for Multitracker
+  */
+  MultiTracker_Alt()
+  {
+    targetNum = 0;
+  }
+
+  /** @brief Add a new target to a tracking-list and initialize the tracker with a know bounding box that surrounding the target
+  @param image The initial frame
+  @param boundingBox The initial boundig box of target
+  @param tracker_algorithm_name Multi-tracker algorithm name
+
+  @return True if new target initialization went succesfully, false otherwise
+  */
+  bool addTarget(const Mat& image, const Rect2d& boundingBox, String tracker_algorithm_name);
+
+  /** @brief Update all trackers from the tracking-list, find a new most likely bounding boxes for the targets
+  @param image The current frame
+
+  @return True means that all targets were located and false means that tracker couldn't locate one of the targets in
+  current frame. Note, that latter *does not* imply that tracker has failed, maybe target is indeed
+  missing from the frame (say, out of sight)
+  */
+  bool update(const Mat& image);
+
+  /** @brief Current number of targets in tracking-list
+  */
+  int targetNum;
+
+  /** @brief Trackers list for Multi-Object-Tracker
+  */
+  std::vector <Ptr<Tracker> > trackers;
+
+  /** @brief Bounding Boxes list for Multi-Object-Tracker
+  */
+  std::vector <Rect2d> boundingBoxes;
+  /** @brief List of randomly generated colors for bounding boxes display
+  */
+  std::vector<Scalar> colors;
 };
 
 /** @brief Multi Object Tracker for TLD. TLD is a novel tracking framework that explicitly decomposes
@@ -1436,17 +1465,17 @@ occlusions, object absence etc.
 class CV_EXPORTS MultiTrackerTLD : public MultiTracker_Alt
 {
 public:
-	/** @brief Update all trackers from the tracking-list, find a new most likely bounding boxes for the targets by
-	optimized update method using some techniques to speedup calculations specifically for MO TLD. The only limitation
-	is that	all target bounding boxes should have approximately same aspect ratios. Speed boost is around 20%
+  /** @brief Update all trackers from the tracking-list, find a new most likely bounding boxes for the targets by
+  optimized update method using some techniques to speedup calculations specifically for MO TLD. The only limitation
+  is that all target bounding boxes should have approximately same aspect ratios. Speed boost is around 20%
 
-	@param image The current frame.
+  @param image The current frame.
 
-	@return True means that all targets were located and false means that tracker couldn't locate one of the targets in
-	current frame. Note, that latter *does not* imply that tracker has failed, maybe target is indeed
-	missing from the frame (say, out of sight)
-	*/
-	bool update_opt(const Mat& image);
+  @return True means that all targets were located and false means that tracker couldn't locate one of the targets in
+  current frame. Note, that latter *does not* imply that tracker has failed, maybe target is indeed
+  missing from the frame (say, out of sight)
+  */
+  bool update_opt(const Mat& image);
 };
 
 //! @}
diff --git a/contrib/modules/tracking/perf/perf_Tracker.cpp b/contrib/modules/tracking/perf/perf_Tracker.cpp
index cc5311d..0a3d96f 100644
--- a/contrib/modules/tracking/perf/perf_Tracker.cpp
+++ b/contrib/modules/tracking/perf/perf_Tracker.cpp
@@ -343,3 +343,73 @@ PERF_TEST_P(tracking, tld, testing::Combine(TESTSET_NAMES, SEGMENTS))
   SANITY_CHECK( bbs_mat, 15, ERROR_RELATIVE );
 
 }
+
+PERF_TEST_P(tracking, GOTURN, testing::Combine(TESTSET_NAMES, SEGMENTS))
+{
+  string video = get<0>(GetParam());
+  int segmentId = get<1>(GetParam());
+
+  int startFrame;
+  string prefix;
+  string suffix;
+  string datasetMeta = getDataPath(TRACKING_DIR + "/" + video + "/" + video + ".yml");
+  checkData(datasetMeta, startFrame, prefix, suffix);
+  int gtStartFrame = startFrame;
+
+  vector<Rect> gtBBs;
+  string gtFile = getDataPath(TRACKING_DIR + "/" + video + "/gt.txt");
+  if (!getGroundTruth(gtFile, gtBBs))
+    FAIL() << "Ground truth file " << gtFile << " can not be read" << endl;
+  int bbCounter = (int)gtBBs.size();
+
+  Mat frame;
+  bool initialized = false;
+  vector<Rect> bbs;
+
+  Ptr<Tracker> tracker = Tracker::create("GOTURN");
+  string folder = TRACKING_DIR + "/" + video + "/" + FOLDER_IMG;
+  int numSegments = (sizeof(SEGMENTS) / sizeof(int));
+  int endFrame = 0;
+  getSegment(segmentId, numSegments, bbCounter, startFrame, endFrame);
+
+  Rect currentBBi = gtBBs[startFrame - gtStartFrame];
+  Rect2d currentBB(currentBBi);
+
+  TEST_CYCLE_N(1)
+  {
+    VideoCapture c;
+    c.open(getDataPath(TRACKING_DIR + "/" + video + "/" + FOLDER_IMG + "/" + video + ".webm"));
+    c.set(CAP_PROP_POS_FRAMES, startFrame);
+    for (int frameCounter = startFrame; frameCounter < endFrame; frameCounter++)
+    {
+      c >> frame;
+
+      if (frame.empty())
+      {
+        break;
+      }
+
+      if (!initialized)
+      {
+        if (!tracker->init(frame, currentBB))
+        {
+          FAIL() << "Could not initialize tracker" << endl;
+          return;
+        }
+        initialized = true;
+      }
+      else if (initialized)
+      {
+        tracker->update(frame, currentBB);
+      }
+      bbs.push_back(currentBB);
+
+    }
+  }
+  //save the bounding boxes in a Mat
+  Mat bbs_mat((int)bbs.size(), 4, CV_32F);
+  getMatOfRects(bbs, bbs_mat);
+
+  SANITY_CHECK(bbs_mat, 15, ERROR_RELATIVE);
+
+}
diff --git a/contrib/modules/tracking/samples/benchmark.cpp b/contrib/modules/tracking/samples/benchmark.cpp
index 3fb8c99..16e4956 100644
--- a/contrib/modules/tracking/samples/benchmark.cpp
+++ b/contrib/modules/tracking/samples/benchmark.cpp
@@ -1,415 +1,355 @@
-#include <opencv2/core/utility.hpp>
-#include <opencv2/tracking.hpp>
-#include <opencv2/videoio.hpp>
-#include <opencv2/highgui.hpp>
+#include "opencv2/core/utility.hpp"
+#include "opencv2/highgui.hpp"
+#include "opencv2/tracking.hpp"
+#include "opencv2/videoio.hpp"
+#include "opencv2/plot.hpp"
+#include <fstream>
+#include <iomanip>
 #include <iostream>
-#include <time.h>
-#include <cstring>
-#include <climits>
-
-const int CMDLINEMAX = 30;
-      int ASSESS_TILL = INT_MAX;
-const int LINEMAX = 40;
 
 using namespace std;
 using namespace cv;
 
-/* TODO:  
-            do normalization ala Kalal's assessment protocol for TLD
- */
-
-static Mat image;
-static bool paused;
-static bool saveImageKey;
-static vector<Scalar> palette;
-
-void print_table(char* videos[],int videoNum,char* algorithms[],int algNum,const vector<vector<char*> >& results,char* tableName);
-
-static int lineToRect(char* line,Rect2d& res){
-  char * ptr=line,*pos=ptr;
-  if(line==NULL || line[0]=='\0'){
-      return -1;
-  }
-  if(strcmp(line,"NaN,NaN,NaN,NaN\n")==0){
-      res.height=res.width=-1.0;
-      return 0;
-  }
-
-  double nums[4]={0};
-  for(int i=0; i<4 && (ptr=strpbrk(ptr,"0123456789-"))!= NULL;i++,ptr=pos){
-    nums[i]=strtod(ptr,&pos);
-    if(pos==ptr){
-      printf("lineToRect had problems with decoding line %s\n",line);
-      return -1;
-    }
-  }
-  res.x=cv::min(nums[0],nums[2]);
-  res.y=cv::min(nums[1],nums[3]);
-  res.width=cv::abs(nums[0]-nums[2]);
-  res.height=cv::abs(nums[1]-nums[3]);
-  return 0;
-}
-static inline double overlap(Rect2d r1,Rect2d r2){
-    if(r1.width<0 || r2.width<0 || r1.height<0 || r1.width<0)return -1.0;
-    double a1=r1.area(), a2=r2.area(), a0=(r1&r2).area();
-    return a0/(a1+a2-a0);
-}
-static void help(){
-  cout << "\nThis example shows the functionality of \"Long-term optical tracking API\""
-       "-- pause video [p] and draw a bounding box around the target to start the tracker\n"
-       "Example of <video_name> is in opencv_extra/testdata/cv/tracking/\n"
-       "Call:\n"
-       "./tracker [<keys and args>] <video_name> <ground_truth> <algorithm1> <init_box1> <algorithm2> <init_box2> ...\n"
-       << endl;
-
-  cout << "\n\nConsole keys: \n"
-       "\t-s - save images\n"
-       "\t-l=100 - assess only, say, first 100 frames\n";
-
-  cout << "\n\nHot keys: \n"
-       "\tq - quit the program\n"
-       "\tp - pause video\n";
-  exit(EXIT_SUCCESS);
+// TODO: do normalization ala Kalal's assessment protocol for TLD
+
+static const Scalar gtColor = Scalar(0, 255, 0);
+
+static Scalar getNextColor()
+{
+    const int num = 6;
+    static Scalar colors[num] = {Scalar(160, 0, 0),   Scalar(0, 0, 160),   Scalar(0, 160, 160),
+                                 Scalar(160, 160, 0), Scalar(160, 0, 160), Scalar(20, 50, 160)};
+    static int id = 0;
+    return colors[id < num ? id++ : num - 1];
 }
-static void parseCommandLineArgs(int argc, char** argv,char* videos[],char* gts[],
-        int* vc,char* algorithms[],char* initBoxes[][CMDLINEMAX],int* ac,char keys[CMDLINEMAX][LINEMAX]){
-
-    *ac=*vc=0;
-    for(int i=1;i<argc;i++){
-        if(argv[i][0]=='-'){
-            for(int j=0;j<CMDLINEMAX;j++){
-                char* ptr = strchr(argv[i], '=');
-                if( !strncmp(argv[i], keys[j], (ptr == NULL) ? strlen(argv[i]) : (ptr-argv[i]) ) )
+
+inline vector<Rect2d> readGT(const string &filename, const string &omitname)
+{
+    vector<Rect2d> res;
+    {
+        ifstream input(filename.c_str());
+        if (!input.is_open())
+            CV_Error(Error::StsError, "Failed to open file");
+        while (input)
+        {
+            Rect2d one;
+            input >> one.x;
+            input.ignore(numeric_limits<std::streamsize>::max(), ',');
+            input >> one.y;
+            input.ignore(numeric_limits<std::streamsize>::max(), ',');
+            input >> one.width;
+            input.ignore(numeric_limits<std::streamsize>::max(), ',');
+            input >> one.height;
+            input.ignore(numeric_limits<std::streamsize>::max(), '\n');
+            if (input.good())
+                res.push_back(one);
+        }
+    }
+    if (!omitname.empty())
+    {
+        ifstream input(omitname.c_str());
+        if (!input.is_open())
+            CV_Error(Error::StsError, "Failed to open file");
+        while (input)
+        {
+            unsigned int a = 0, b = 0;
+            input >> a >> b;
+            input.ignore(numeric_limits<std::streamsize>::max(), '\n');
+            if (a > 0 && b > 0 && a < res.size() && b < res.size())
+            {
+                if (a > b)
+                    swap(a, b);
+                for (vector<Rect2d>::iterator i = res.begin() + a; i != res.begin() + b; ++i)
                 {
-                    if( ptr == NULL )
-                        keys[j][0]='\0';
-                    else
-                        strcpy(keys[j], ptr+1);
+                    *i = Rect2d();
                 }
             }
-            continue;
-        }
-        bool isVideo=false;
-        for(int j=0,len=(int)strlen(argv[i]);j<len;j++){
-            if(!('A'<=argv[i][j] && argv[i][j]<='Z') && argv[i][j]!='.'){
-                isVideo=true;
-                break;
-            }
         }
+    }
+    return res;
+}
 
-        if(isVideo){
-            videos[*vc]=argv[i];
-            i++;
-            gts[*vc]=(i<argc)?argv[i]:NULL;
-            (*vc)++;
-        }else{
-            algorithms[*ac]=argv[i];
-            i++;
-            for(int j=0;j<*vc;j++,i++){
-                initBoxes[*ac][j]=(i<argc)?argv[i]:NULL;
-            }
-            i--;(*ac)++;
+inline bool isGoodBox(const Rect2d &box) { return box.width > 0. && box.height > 0.; }
+const int LTRC_COUNT = 100;
+
+struct AlgoWrap
+{
+    AlgoWrap(const string &name_)
+        : tracker(Tracker::create(name_)), lastState(NotFound), name(name_), color(getNextColor()),
+          numTotal(0), numResponse(0), numPresent(0), numCorrect_0(0), numCorrect_0_5(0),
+          timeTotal(0), auc(LTRC_COUNT + 1, 0)
+    {
+    }
+
+    enum State
+    {
+        NotFound,
+        Overlap_None,
+        Overlap_0,
+        Overlap_0_5,
+    };
+
+    Ptr<Tracker> tracker;
+    bool lastRes;
+    Rect2d lastBox;
+    State lastState;
+
+    // visual
+    string name;
+    Scalar color;
+
+    // results
+    int numTotal;       // frames passed to tracker
+    int numResponse;    // frames where tracker had response
+    int numPresent;     // frames where ground truth result present
+    int numCorrect_0;   // frames where overlap with GT > 0
+    int numCorrect_0_5; // frames where overlap with GT > 0.5
+    int64 timeTotal;    // ticks
+    vector<int> auc;   // number of frames for each overlap percent
+
+    void eval(const Mat &frame, const Rect2d &gtBox, bool isVerbose)
+    {
+        // RUN
+        lastBox = Rect2d();
+        int64 frameTime = getTickCount();
+        lastRes = tracker->update(frame, lastBox);
+        frameTime = getTickCount() - frameTime;
+
+        // RESULTS
+        double intersectArea = (gtBox & lastBox).area();
+        double unionArea = (gtBox | lastBox).area();
+        numTotal++;
+        numResponse += (lastRes && isGoodBox(lastBox)) ? 1 : 0;
+        numPresent += isGoodBox(gtBox) ? 1 : 0;
+        double overlap = unionArea > 0. ? intersectArea / unionArea : 0.;
+        numCorrect_0 += overlap > 0. ? 1 : 0;
+        numCorrect_0_5 += overlap > 0.5 ? 1 : 0;
+        auc[std::min(std::max((size_t)(overlap * LTRC_COUNT), (size_t)0), (size_t)LTRC_COUNT)]++;
+        timeTotal += frameTime;
+
+        if (isVerbose)
+            cout << name << " - " << overlap << endl;
+
+        if (isGoodBox(gtBox) != isGoodBox(lastBox)) lastState = NotFound;
+        else if (overlap > 0.5) lastState = Overlap_0_5;
+        else if (overlap > 0.0001) lastState = Overlap_0;
+        else lastState = Overlap_None;
+    }
+
+    void draw(Mat &image, const Point &textPoint) const
+    {
+        if (lastRes)
+            rectangle(image, lastBox, color, 2, LINE_8);
+        string suf;
+        switch (lastState)
+        {
+        case AlgoWrap::NotFound: suf = " X"; break;
+        case AlgoWrap::Overlap_None: suf = " ~"; break;
+        case AlgoWrap::Overlap_0: suf = " +"; break;
+        case AlgoWrap::Overlap_0_5: suf = " ++"; break;
         }
+        putText(image, name + suf, textPoint, FONT_HERSHEY_PLAIN, 1, color, 1, LINE_AA);
     }
-}
-void print_table(char* videos[],int videoNum,char* algorithms[],int algNum,const vector<vector<char*> >& results,char* tableName){
-    printf("\n%s",tableName);
-    vector<int> grid(1+algNum,0);
-    char spaces[100];memset(spaces,' ',100);
-    for(int i=0;i<videoNum;i++){
-        grid[0]=std::max(grid[0],(int)strlen(videos[i]));
+
+    // calculates "lost track ratio" curve - row of values growing from 0 to 1
+    // number of elements is LTRC_COUNT + 2
+    Mat getLTRC() const
+    {
+        Mat t, res;
+        Mat(auc).convertTo(t, CV_64F); // integral does not support CV_32S input
+        integral(t.t(), res, CV_64F); // t is a column of values
+        return res.row(1) / (double)numTotal;
     }
-    for(int i=0;i<algNum;i++){
-        grid[i+1]=(int)strlen(algorithms[i]);
-        for(int j=0;j<videoNum;j++)
-            grid[i+1]=std::max(grid[i+1],(int)strlen(results[j][i]));
+
+    void plotLTRC(Mat &img) const
+    {
+        Ptr<plot::Plot2d> p_ = plot::createPlot2d(getLTRC());
+        p_->render(img);
     }
-    printf("%.*s ",(int)grid[0],spaces);
-    for(int i=0;i<algNum;i++)
-        printf("%s%.*s",algorithms[i],(int)(grid[i+1]+1-strlen(algorithms[i])),spaces);
-    printf("\n");
-    for(int i=0;i<videoNum;i++){
-        printf("%s%.*s",videos[i],(int)(grid[0]+1-strlen(videos[i])),spaces);
-        for(int j=0;j<algNum;j++)
-            printf("%s%.*s",results[i][j],(int)(grid[j+1]+1-strlen(results[i][j])),spaces);
-        printf("\n");
+
+    double calcAUC() const
+    {
+        return cv::sum(getLTRC())[0] / (double)LTRC_COUNT;
     }
-    printf("*************************************************************\n");
-}
 
-struct AssessmentRes{
-    class Assessment{
-    public:
-        virtual int printf(char* buf)=0;
-        virtual int printName(char* buf)=0;
-        virtual void assess(const Rect2d& ethalon,const Rect2d& res)=0;
-        virtual ~Assessment(){}
-    };
-    AssessmentRes(int algnum);
-    int len;
-    char* videoName;
-    vector<vector<Ptr<Assessment> > >results;
-};
-class CorrectFrames : public AssessmentRes::Assessment{
-public:
-    CorrectFrames(double tol):tol_(tol),len_(1),correctFrames_(1){}
-    int printf(char* buf){return sprintf(buf,"%d/%d",correctFrames_,len_);}
-    int printName(char* buf){return sprintf(buf,(char*)"Num of correct frames (overlap>%g)\n",tol_);}
-    void assess(const Rect2d& ethalon,const Rect2d& res){len_++;if(overlap(ethalon,res)>tol_)correctFrames_++;}
-private:
-    double tol_;
-    int len_;
-    int correctFrames_;
-};
-class AvgTime : public AssessmentRes::Assessment{
-public:
-    AvgTime(double res):res_(res){}
-    int printf(char* buf){return sprintf(buf,"%gms",res_);}
-    int printName(char* buf){return sprintf(buf,(char*)"Average frame tracking time\n");}
-    void assess(const Rect2d& /*ethalon*/,const Rect2d&/* res*/){};
-private:
-    double res_;
-};
-class PRF : public AssessmentRes::Assessment{
-public:
-    PRF():occurences_(0),responses_(0),true_responses_(0){};
-    int printName(char* buf){return sprintf(buf,(char*)"PRF\n");}
-    int printf(char* buf){return sprintf(buf,"%g/%g/%g",(1.0*true_responses_)/responses_,(1.0*true_responses_)/occurences_,
-            (2.0*true_responses_)/(responses_+occurences_));}
-    void assess(const Rect2d& ethalon,const Rect2d& res){
-        if(res.height>=0)responses_++;
-        if(ethalon.height>=0)occurences_++;
-        if(ethalon.height>=0 && res.height>=0)true_responses_++;
+    void stat(ostream &out) const
+    {
+        out << name << endl;
+        out << setw(20) << "Overlap > 0  " << setw(20) << (double)numCorrect_0 / numTotal * 100
+            << "%" << setw(20) << numCorrect_0 << endl;
+        out << setw(20) << "Overlap > 0.5" << setw(20) << (double)numCorrect_0_5 / numTotal * 100
+            << "%" << setw(20) << numCorrect_0_5 << endl;
+
+        double p = (double)numCorrect_0_5 / numResponse;
+        double r = (double)numCorrect_0_5 / numPresent;
+        double f = 2 * p * r / (p + r);
+        out << setw(20) << "Precision" << setw(20) << p * 100 << "%" << endl;
+        out << setw(20) << "Recall   " << setw(20) << r * 100 << "%" << endl;
+        out << setw(20) << "f-measure" << setw(20) << f * 100 << "%" << endl;
+        out << setw(20) << "AUC" << setw(20) << calcAUC() << endl;
+
+        double s = (timeTotal / getTickFrequency()) / numTotal;
+        out << setw(20) << "Performance" << setw(20) << s * 1000 << " ms/frame" << setw(20) << 1 / s
+            << " fps" << endl;
     }
-private:
-    int occurences_,responses_,true_responses_;
 };
-AssessmentRes::AssessmentRes(int algnum):len(0),results(algnum){
-    for(int i=0;i<(int)results.size();i++){
-        results[i].push_back(Ptr<Assessment>(new CorrectFrames(0.0)));
-        results[i].push_back(Ptr<Assessment>(new CorrectFrames(0.5)));
-        results[i].push_back(Ptr<Assessment>(new PRF()));
+
+inline ostream &operator<<(ostream &out, const AlgoWrap &w) { w.stat(out); return out; }
+
+inline vector<AlgoWrap> initAlgorithms(const string &algList)
+{
+    vector<AlgoWrap> res;
+    istringstream input(algList);
+    for (;;)
+    {
+        char one[30];
+        input.getline(one, 30, ',');
+        if (!input)
+            break;
+        cout << "  " << one << " - ";
+        AlgoWrap a(one);
+        if (a.tracker)
+        {
+            res.push_back(a);
+            cout << "OK";
+        }
+        else
+        {
+            cout << "FAILED";
+        }
+        cout << endl;
     }
+    return res;
 }
 
-static AssessmentRes assessment(char* video,char* gt_str, char* algorithms[],char* initBoxes_str[],int algnum){
-  char buf[200];
-  int start_frame=0;
-  int linecount=0;
-  Rect2d boundingBox;
-  vector<double> averageMillisPerFrame(algnum,0.0);
-  static int videoNum=0;
-  videoNum++;
-
-  FILE* gt=fopen(gt_str,"r");
-  if(gt==NULL){
-      printf("cannot open the ground truth file %s\n",gt_str);
-      exit(EXIT_FAILURE);
-  }
-  for(linecount=0;fgets(buf,sizeof(buf),gt)!=NULL;linecount++);
-  if(linecount==0){
-      printf("ground truth file %s has no lines\n",gt_str);
-      exit(EXIT_FAILURE);
-  }
-  fseek(gt,0,SEEK_SET);
-  if(fgets(buf,sizeof(buf),gt)==NULL){
-      printf("ground truth file %s has no lines\n",gt_str);
-      exit(EXIT_FAILURE);
-  }
-
-  std::vector<Rect2d> initBoxes(algnum);
-  for(int i=0;i<algnum;i++){
-      printf("%s %s\n",algorithms[i],initBoxes_str[CMDLINEMAX*i]);
-      if(lineToRect(initBoxes_str[CMDLINEMAX*i],boundingBox)<0){
-          printf("please, specify bounding box for video %s, algorithm %s\n",video,algorithms[i]);
-          printf("FYI, initial bounding box in ground truth is %s\n",buf);
-          if(gt!=NULL){
-              fclose(gt);
-          }
-          exit(EXIT_FAILURE);
-      }else{
-          initBoxes[i].x=boundingBox.x;
-          initBoxes[i].y=boundingBox.y;
-          initBoxes[i].width=boundingBox.width;
-          initBoxes[i].height=boundingBox.height;
-      }
-  }
-
-  VideoCapture cap;
-  cap.open( String(video) );
-  cap.set( CAP_PROP_POS_FRAMES, start_frame );
-
-  if( !cap.isOpened() ){
-    printf("cannot open video %s\n",video);
-    help();
-  }
-
-  Mat frame;
-  namedWindow( "Tracking API", 1 );
-
-  std::vector<Ptr<Tracker> >trackers(algnum);
-  for(int i=0;i<algnum;i++){
-      trackers[i] = Tracker::create( algorithms[i] );
-      if( trackers[i] == NULL ){
-        printf("error in the instantiation of the tracker %s\n",algorithms[i]);
-        if(gt!=NULL){
-            fclose(gt);
+static const string &window = "Tracking API";
+
+int main(int argc, char **argv)
+{
+    const string keys =
+        "{help h||show help}"
+        "{video||video file to process}"
+        "{gt||ground truth file (each line describes rectangle in format: '<x>,<y>,<w>,<h>')}"
+        "{start|0|starting frame}"
+        "{num|0|frame number (0 for all)}"
+        "{omit||file with omit ranges (each line describes occluded frames: '<start> <end>')}"
+        "{plot|false|plot LTR curves at the end}"
+        "{v|false|print each frame info}"
+        "{@algos||comma-separated algorithm names}";
+    CommandLineParser p(argc, argv, keys);
+    if (p.has("help"))
+    {
+        p.printMessage();
+        return 0;
+    }
+    int startFrame = p.get<int>("start");
+    int frameCount = p.get<int>("num");
+    string videoFile = p.get<string>("video");
+    string gtFile = p.get<string>("gt");
+    string omitFile = p.get<string>("omit");
+    string algList = p.get<string>("@algos");
+    bool doPlot = p.get<bool>("plot");
+    bool isVerbose = p.get<bool>("v");
+    if (!p.check())
+    {
+        p.printErrors();
+        return 0;
+    }
+
+    cout << "Reading GT from " << gtFile << " ... ";
+    vector<Rect2d> gt = readGT(gtFile, omitFile);
+    if (gt.empty())
+        CV_Error(Error::StsError, "Failed to read GT file");
+    cout << gt.size() << " boxes" << endl;
+
+    cout << "Opening video " << videoFile << " ... ";
+    VideoCapture cap;
+    cap.open(videoFile);
+    if (!cap.isOpened())
+        CV_Error(Error::StsError, "Failed to open video file");
+    cap.set(CAP_PROP_POS_FRAMES, startFrame);
+    cout << "at frame " << startFrame << endl;
+
+    // INIT
+    vector<AlgoWrap> algos = initAlgorithms(algList);
+    Mat frame, image;
+    cap >> frame;
+    for (vector<AlgoWrap>::iterator i = algos.begin(); i != algos.end(); ++i)
+        i->tracker->init(frame, gt[0]);
+
+    // DRAW
+    {
+        namedWindow(window, WINDOW_AUTOSIZE);
+        frame.copyTo(image);
+        rectangle(image, gt[0], gtColor, 2, LINE_8);
+        imshow(window, image);
+    }
+
+    bool paused = false;
+    int frameId = 0;
+    cout << "Hot keys:" << endl << "  q - exit" << endl << "  p - pause" << endl;
+    for (;;)
+    {
+        if (!paused)
+        {
+            cap >> frame;
+            if (frame.empty())
+            {
+                cout << "Done - video end" << endl;
+                break;
+            }
+            frameId++;
+            if (isVerbose)
+                cout << endl << "Frame " << frameId << endl;
+            // EVAL
+            for (vector<AlgoWrap>::iterator i = algos.begin(); i != algos.end(); ++i)
+                i->eval(frame, gt[frameId], isVerbose);
+            // DRAW
+            {
+                Point textPoint(1, 16);
+                frame.copyTo(image);
+                rectangle(image, gt[frameId], gtColor, 2, LINE_8);
+                putText(image, "GROUND TRUTH", textPoint, FONT_HERSHEY_PLAIN, 1, gtColor, 1, LINE_AA);
+                for (vector<AlgoWrap>::iterator i = algos.begin(); i != algos.end(); ++i)
+                {
+                    textPoint.y += 14;
+                    i->draw(image, textPoint);
+                }
+                imshow(window, image);
+            }
         }
-        exit(EXIT_FAILURE);
-      }
-  }
-
-  cap >> frame;
-  frame.copyTo( image );
-  if(lineToRect(buf,boundingBox)<0){
-      if(gt!=NULL){
-          fclose(gt);
-      }
-      exit(EXIT_FAILURE);
-  }
-  rectangle( image, boundingBox,palette[0], 2, 1 );
-  for(int i=0;i<(int)trackers.size();i++){
-      rectangle(image,initBoxes[i],palette[i+1], 2, 1 );
-      if( !trackers[i]->init( frame, initBoxes[i] ) ){
-        printf("could not initialize tracker %s with box %s at video %s\n",algorithms[i],initBoxes_str[i],video);
-        if(gt!=NULL){
-            fclose(gt);
+
+        char c = (char)waitKey(1);
+        if (c == 'q')
+        {
+            cout << "Done - manual exit" << endl;
+            break;
         }
-        exit(EXIT_FAILURE);
-      }
-  }
-  imshow( "Tracking API", image );
-
-  int frameCounter = 0;
-  AssessmentRes res((int)trackers.size());
-
-  for ( ;; ){
-    if( !paused ){
-      cap >> frame;
-      if(frame.empty()){
-        break;
-      }
-      frame.copyTo( image );
-
-      if(fgets(buf,sizeof(buf),gt)==NULL){
-          printf("ground truth is over\n");
-          break;
-      }
-      if(lineToRect(buf,boundingBox)<0){
-          if(gt!=NULL){
-              fclose(gt);
-          }
-          exit(EXIT_FAILURE);
-      }
-      rectangle( image, boundingBox,palette[0], 2, 1 );
-      putText(image, "GROUND TRUTH", Point(1,16 + 0*14), FONT_HERSHEY_SIMPLEX, 0.5, palette[0],2);
-      
-      frameCounter++;
-      for(int i=0;i<(int)trackers.size();i++){
-          bool trackerRes=true;
-          clock_t start;start=clock();
-          trackerRes=trackers[i]->update( frame, initBoxes[i] );
-          start=clock()-start;
-          averageMillisPerFrame[i]+=1000.0*start/CLOCKS_PER_SEC;
-          if( trackerRes == false )
-          {
-              initBoxes[i].height=initBoxes[i].width=-1.0;
-          }
-          else
-          {
-              rectangle( image, initBoxes[i], palette[i+1], 2, 1 );
-              putText(image, algorithms[i], Point(1,16 + (i+1)*14), FONT_HERSHEY_SIMPLEX, 0.5, palette[i+1],2);
-          }
-          for(int j=0;j<(int)res.results[i].size();j++)
-              res.results[i][j]->assess(boundingBox,initBoxes[i]);
-      }
-      imshow( "Tracking API", image );
-      if(saveImageKey){
-          char inbuf[LINEMAX];
-          sprintf(inbuf,"image%d_%d.jpg",videoNum,frameCounter);
-          imwrite(inbuf,image);
-      }
-
-      if((frameCounter+1)>=ASSESS_TILL){
-          break;
-      }
-
-      char c = (char) waitKey( 2 );
-      if( c == 'q' )
-        break;
-      if( c == 'p' )
-        paused = !paused;
-      }
-  }
-  if(gt!=NULL){
-      fclose(gt);
-  }
-  destroyWindow( "Tracking API");
-
-  res.len=linecount;
-  res.videoName=video;
-  for(int i=0;i<(int)res.results.size();i++)
-      res.results[i].push_back(Ptr<AssessmentRes::Assessment>(new AvgTime(averageMillisPerFrame[i]/res.len)));
-  return res;
-}
+        else if (c == 'p')
+        {
+            paused = !paused;
+        }
+        if (frameCount && frameId >= frameCount)
+        {
+            cout << "Done - max frame count" << endl;
+            break;
+        }
+    }
+
+    // STAT
+    for (vector<AlgoWrap>::iterator i = algos.begin(); i != algos.end(); ++i)
+        cout << "==========" << endl << *i << endl;
+
+    if (doPlot)
+    {
+        Mat img(300, 300, CV_8UC3);
+        for (vector<AlgoWrap>::iterator i = algos.begin(); i != algos.end(); ++i)
+        {
+            i->plotLTRC(img);
+            imshow("LTR curve for " + i->name, img);
+        }
+        waitKey(0);
+    }
 
-int main( int argc, char** argv ){
-  palette.push_back(Scalar(255,0,0));//BGR, blue
-  palette.push_back(Scalar(0,0,255));//red
-  palette.push_back(Scalar(0,255,255));//yellow
-  palette.push_back(Scalar(255,255,0));//orange
-  int vcount=0,acount=0;
-  char* videos[CMDLINEMAX],*gts[CMDLINEMAX],*algorithms[CMDLINEMAX],*initBoxes[CMDLINEMAX][CMDLINEMAX];
-  char keys[CMDLINEMAX][LINEMAX];
-  strcpy(keys[0],"-s");
-  strcpy(keys[1],"-a");
-
-  parseCommandLineArgs(argc,argv,videos,gts,&vcount,algorithms,initBoxes,&acount,keys);
-
-  saveImageKey=(keys[0][0]=='\0');
-  if( strcmp(keys[1],"-a") != 0 )
-      ASSESS_TILL = atoi(keys[1]);
-  else
-      ASSESS_TILL = INT_MAX;
-
-  CV_Assert(acount<CMDLINEMAX && vcount<CMDLINEMAX);
-  printf("videos and gts\n");
-  for(int i=0;i<vcount;i++){
-      printf("%s %s\n",videos[i],gts[i]);
-  }
-  printf("algorithms and boxes (%d)\n",acount);
-  for(int i=0;i<acount;i++){
-      printf("%s ",algorithms[i]);
-      for(int j=0;j<vcount;j++){
-        printf("%s ",initBoxes[i][j]);
-      }
-      printf("\n");
-  }
-
-  std::vector<AssessmentRes> results;
-  for(int i=0;i<vcount;i++)
-      results.push_back(assessment(videos[i],gts[i],algorithms,((char**)initBoxes)+i,acount));
-  CV_Assert( (int)results[0].results[0].size() < CMDLINEMAX );
-  printf("\n\n");
-
-  char buf[CMDLINEMAX*CMDLINEMAX*LINEMAX], buf2[CMDLINEMAX*40];
-  vector<vector<char*> > resultStrings(vcount);
-  vector<char*> nameStrings;
-  for(int i=0;i<vcount;i++){
-      for(int j=0;j<acount;j++){
-          resultStrings[i].push_back(buf+i*CMDLINEMAX*LINEMAX + j*40);
-      }
-  }
-  for(int i=0;i<(int)results[0].results[0].size();i++)
-      nameStrings.push_back(buf2+LINEMAX*i);
-  for(int tableCount=0;tableCount<(int)results[0].results[0].size();tableCount++)
-  {
-      CV_Assert(results[0].results[0][tableCount]->printName(nameStrings[tableCount])<LINEMAX);
-      for(int videoCount=0;videoCount<(int)results.size();videoCount++)
-          for(int algoCount=0;algoCount<(int)results[0].results.size();algoCount++){
-              (results[videoCount].results[algoCount][tableCount])->printf(resultStrings[videoCount][algoCount]);
-          }
-      print_table(videos,vcount,algorithms,acount,resultStrings,nameStrings[tableCount]);
-  }
-  return 0;
+    return 0;
 }
diff --git a/contrib/modules/tracking/samples/goturnTracker.cpp b/contrib/modules/tracking/samples/goturnTracker.cpp
new file mode 100644
index 0000000..389771e
--- /dev/null
+++ b/contrib/modules/tracking/samples/goturnTracker.cpp
@@ -0,0 +1,217 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+//  By downloading, copying, installing or using the software you agree to this license.
+//  If you do not agree to this license, do not download, install,
+//  copy or use the software.
+//
+//
+//                           License Agreement
+//                For Open Source Computer Vision Library
+//
+// Copyright (C) 2013, OpenCV Foundation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+//   * Redistribution's of source code must retain the above copyright notice,
+//     this list of conditions and the following disclaimer.
+//
+//   * Redistribution's in binary form must reproduce the above copyright notice,
+//     this list of conditions and the following disclaimer in the documentation
+//     and/or other materials provided with the distribution.
+//
+//   * The name of the copyright holders may not be used to endorse or promote products
+//     derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+//Demo of GOTURN tracker
+//In order to use GOTURN tracker, GOTURN architecture goturn.prototxt and goturn.caffemodel are required to exist in root folder.
+//There are 2 ways to get caffemodel:
+//1 - Train you own GOTURN model using <https://github.com/Auron-X/GOTURN_Training_Toolkit>
+//2 - Download pretrained caffemodel from <https://github.com/opencv/opencv_extra>
+
+#include "opencv2/datasets/track_alov.hpp"
+#include <opencv2/core/utility.hpp>
+#include <opencv2/tracking.hpp>
+#include <opencv2/videoio.hpp>
+#include <opencv2/highgui.hpp>
+#include <iostream>
+
+using namespace std;
+using namespace cv;
+using namespace cv::datasets;
+
+#define NUM_TEST_FRAMES 1000
+
+static Mat image;
+static bool paused;
+static bool selectObjects = false;
+static bool startSelection = false;
+Rect2d boundingBox;
+
+static const char* keys =
+{ "{@dataset_path     |true| Dataset path     }"
+"{@dataset_id     |1| Dataset ID     }"
+};
+
+static void onMouse(int event, int x, int y, int, void*)
+{
+    if (!selectObjects)
+    {
+        switch (event)
+        {
+        case EVENT_LBUTTONDOWN:
+            //set origin of the bounding box
+            startSelection = true;
+            boundingBox.x = x;
+            boundingBox.y = y;
+            boundingBox.width = boundingBox.height = 0;
+            break;
+        case EVENT_LBUTTONUP:
+            //sei with and height of the bounding box
+            boundingBox.width = std::abs(x - boundingBox.x);
+            boundingBox.height = std::abs(y - boundingBox.y);
+            paused = false;
+            selectObjects = true;
+            startSelection = false;
+            break;
+        case EVENT_MOUSEMOVE:
+
+            if (startSelection && !selectObjects)
+            {
+                //draw the bounding box
+                Mat currentFrame;
+                image.copyTo(currentFrame);
+                rectangle(currentFrame, Point((int)boundingBox.x, (int)boundingBox.y), Point(x, y), Scalar(255, 0, 0), 2, 1);
+                imshow("GOTURN Tracking", currentFrame);
+            }
+            break;
+        }
+    }
+}
+
+static void help()
+{
+    cout << "\nThis example is a simple demo of GOTURN tracking on ALOV300++ dataset"
+        "ALOV dataset contains videos with ID range: 1~314\n"
+        "-- pause video [p] and draw a bounding boxes around the targets to start the tracker\n"
+        "Example:\n"
+        "./goturnTracker <dataset_path> <dataset_id>\n"
+        << endl;
+
+    cout << "\n\nHot keys: \n"
+        "\tq - quit the program\n"
+        "\tp - pause video\n";
+}
+
+int main(int argc, char *argv[])
+{
+    CommandLineParser parser(argc, argv, keys);
+    string datasetRootPath = parser.get<string>(0);
+    int datasetID = parser.get<int>(1);
+
+    if (datasetRootPath.empty())
+    {
+        help();
+        return -1;
+    }
+
+    Mat frame;
+    paused = false;
+    namedWindow("GOTURN Tracking", 0);
+    setMouseCallback("GOTURN Tracking", onMouse, 0);
+
+    //Create GOTURN tracker
+    Ptr<Tracker> tracker = Tracker::create("GOTURN");
+
+    //Load and init full ALOV300++ dataset with a given datasetID, as alternative you can use loadAnnotatedOnly(..)
+    //to load only frames with labled ground truth ~ every 5-th frame
+    Ptr<cv::datasets::TRACK_alov> dataset = TRACK_alov::create();
+    dataset->load(datasetRootPath);
+    dataset->initDataset(datasetID);
+
+    //Read first frame
+    dataset->getNextFrame(frame);
+    frame.copyTo(image);
+    rectangle(image, boundingBox, Scalar(255, 0, 0), 2, 1);
+    imshow("GOTURN Tracking", image);
+
+    bool initialized = false;
+    paused = true;
+    int frameCounter = 0;
+
+    //Time measurment
+    int64 e3 = getTickCount();
+
+    for (;;)
+    {
+        if (!paused)
+        {
+            //Time measurment
+            int64 e1 = getTickCount();
+            if (initialized){
+                if (!dataset->getNextFrame(frame))
+                    break;
+                frame.copyTo(image);
+            }
+
+            if (!initialized && selectObjects)
+            {
+                //Initialize the tracker and add targets
+                if (!tracker->init(frame, boundingBox))
+                {
+                    cout << "Tracker Init Error!!!";
+                    return 0;
+                }
+                rectangle(frame, boundingBox, Scalar(0, 0, 255), 2, 1);
+                initialized = true;
+            }
+            else if (initialized)
+            {
+                //Update all targets
+                if (tracker->update(frame, boundingBox))
+                {
+                    rectangle(frame, boundingBox, Scalar(0, 0, 255), 2, 1);
+                }
+            }
+            imshow("GOTURN Tracking", frame);
+            frameCounter++;
+            //Time measurment
+            int64 e2 = getTickCount();
+            double t1 = (e2 - e1) / getTickFrequency();
+            cout << frameCounter << "\tframe :  " << t1 * 1000.0 << "ms" << endl;
+        }
+
+        char c = (char)waitKey(2);
+        if (c == 'q')
+            break;
+        if (c == 'p')
+            paused = !paused;
+    }
+
+    //Time measurment
+    int64 e4 = getTickCount();
+    double t2 = (e4 - e3) / getTickFrequency();
+    cout << "Average Time for Frame:  " << t2 * 1000.0 / frameCounter << "ms" << endl;
+    cout << "Average FPS:  " << 1.0 / t2*frameCounter << endl;
+
+
+    waitKey(0);
+
+    return 0;
+}
diff --git a/contrib/modules/tracking/samples/multiTracker_dataset.cpp b/contrib/modules/tracking/samples/multiTracker_dataset.cpp
index ce4c705..2826b19 100644
--- a/contrib/modules/tracking/samples/multiTracker_dataset.cpp
+++ b/contrib/modules/tracking/samples/multiTracker_dataset.cpp
@@ -39,6 +39,10 @@
 //
 //M*/
 
+#include "opencv2/opencv_modules.hpp"
+#include "opencv2/core.hpp"
+#ifdef HAVE_OPENCV_DATASETS
+
 #include "opencv2/datasets/track_vot.hpp"
 #include <opencv2/core/utility.hpp>
 #include <opencv2/tracking.hpp>
@@ -227,4 +231,11 @@ int main(int argc, char *argv[])
 	waitKey(0);
 
 	return 0;
-}
\ No newline at end of file
+}
+
+#else // ! HAVE_OPENCV_DATASETS
+int main() {
+	CV_Error(cv::Error::StsNotImplemented , "this sample needs to be built with opencv_datasets !");
+	return -1;
+}
+#endif // HAVE_OPENCV_DATASETS
diff --git a/contrib/modules/tracking/samples/tracker_dataset.cpp b/contrib/modules/tracking/samples/tracker_dataset.cpp
index 489469f..8b7832a 100644
--- a/contrib/modules/tracking/samples/tracker_dataset.cpp
+++ b/contrib/modules/tracking/samples/tracker_dataset.cpp
@@ -39,6 +39,14 @@
 //
 //M*/
 
+
+//
+//  !!! this sample requires the opencv_datasets module !!!
+//
+
+#include "opencv2/opencv_modules.hpp"
+#ifdef HAVE_OPENCV_DATASETS
+
 #include "opencv2/datasets/track_vot.hpp"
 #include <opencv2/core/utility.hpp>
 #include <opencv2/tracking.hpp>
@@ -221,4 +229,13 @@ int main(int argc, char *argv[])
 	waitKey(0);
 
 	return 0;
-}
\ No newline at end of file
+}
+
+
+
+#else // ! HAVE_OPENCV_DATASETS
+int main() {
+	CV_Error(cv::Error::StsNotImplemented , "this sample needs to be built with opencv_datasets !");
+	return -1;
+}
+#endif // HAVE_OPENCV_DATASETS
diff --git a/contrib/modules/tracking/src/augmented_unscented_kalman.cpp b/contrib/modules/tracking/src/augmented_unscented_kalman.cpp
index 953e422..0ba8b03 100644
--- a/contrib/modules/tracking/src/augmented_unscented_kalman.cpp
+++ b/contrib/modules/tracking/src/augmented_unscented_kalman.cpp
@@ -47,50 +47,6 @@ namespace cv
 namespace tracking
 {
 
-/* Cholesky decomposition
- The function performs Cholesky decomposition <https://en.wikipedia.org/wiki/Cholesky_decomposition>.
- A - the Hermitian, positive-definite matrix,
- astep - size of row in A,
- asize - number of cols and rows in A,
- L - the lower triangular matrix, A = L*Lt.
-*/
-template<typename _Tp> bool
-inline choleskyDecomposition( const _Tp* A, size_t astep, const int asize, _Tp* L )
-{
-    int i, j, k;
-    double s;
-    astep /= sizeof(A[0]);
-    for( i = 0; i < asize; i++ )
-
-    {
-        for( j = 0; j < i; j++ )
-        {
-            s = A[i*astep + j];
-            for( k = 0; k < j; k++ )
-                s -= L[i*astep + k]*L[j*astep + k];
-            L[i*astep + j] = (_Tp)(s/L[j*astep + j]);
-        }
-        s = A[i*astep + i];
-        for( k = 0; k < i; k++ )
-        {
-            double t = L[i*astep + k];
-            s -= t*t;
-        }
-        if( s < std::numeric_limits<_Tp>::epsilon() )
-            return false;
-        L[i*astep + i] = (_Tp)(std::sqrt(s));
-    }
-
-   for( i = 0; i < asize; i++ )
-       for( j = i+1; j < asize; j++ )
-       {
-           L[i*astep + j] = 0.0;
-       }
-
-    return true;
-}
-
-
 void AugmentedUnscentedKalmanFilterParams::
     init( int dp, int mp, int cp, double processNoiseCovDiag, double measurementNoiseCovDiag,
                                 Ptr<UkfSystemModel> dynamicalSystem, int type )
@@ -179,10 +135,6 @@ class AugmentedUnscentedKalmanFilterImpl: public UnscentedKalmanFilter
     Mat r;                                      // zero vector of process noise for getting transitionSPFuncVals,
     Mat q;                                      // zero vector of measurement noise for getting measurementSPFuncVals
 
-
-    template <typename T>
-    Mat getSigmaPoints(const Mat& mean, const Mat& covMatrix, double coef);
-
     Mat getSigmaPoints(const Mat& mean, const Mat& covMatrix, double coef);
 
 public:
@@ -190,8 +142,8 @@ public:
     AugmentedUnscentedKalmanFilterImpl(const AugmentedUnscentedKalmanFilterParams& params);
     ~AugmentedUnscentedKalmanFilterImpl();
 
-    Mat predict(const Mat& control);
-    Mat correct(const Mat& measurement);
+    Mat predict(InputArray control);
+    Mat correct(InputArray measurement);
 
     Mat getProcessNoiseCov() const;
     Mat getMeasurementNoiseCov() const;
@@ -303,7 +255,6 @@ AugmentedUnscentedKalmanFilterImpl::~AugmentedUnscentedKalmanFilterImpl()
 
 }
 
-template <typename T>
 Mat AugmentedUnscentedKalmanFilterImpl::getSigmaPoints(const Mat &mean, const Mat &covMatrix, double coef)
 {
 // x_0 = mean
@@ -313,11 +264,18 @@ Mat AugmentedUnscentedKalmanFilterImpl::getSigmaPoints(const Mat &mean, const Ma
     int n = mean.rows;
     Mat points = repeat(mean, 1, 2*n+1);
 
-// covMatrixL = cholesky( covMatrix )
     Mat covMatrixL = covMatrix.clone();
-    covMatrixL.setTo(0);
 
-    choleskyDecomposition<T>( covMatrix.ptr<T>(), covMatrix.step, covMatrix.rows, covMatrixL.ptr<T>() );
+// covMatrixL = cholesky( covMatrix )
+    if ( dataType == CV_64F )
+        choleskyDecomposition<double>(
+                    covMatrix.ptr<double>(), covMatrix.step, covMatrix.rows,
+                    covMatrixL.ptr<double>(), covMatrixL.step );
+    else if ( dataType == CV_32F )
+        choleskyDecomposition<float>(
+                    covMatrix.ptr<float>(), covMatrix.step, covMatrix.rows,
+                    covMatrixL.ptr<float>(), covMatrixL.step );
+
     covMatrixL = coef * covMatrixL;
 
     Mat p_plus = points( Rect( 1, 0, n, n ) );
@@ -329,16 +287,9 @@ Mat AugmentedUnscentedKalmanFilterImpl::getSigmaPoints(const Mat &mean, const Ma
     return points;
 }
 
-Mat AugmentedUnscentedKalmanFilterImpl::getSigmaPoints(const Mat& mean, const Mat& covMatrix, double coef)
-{
-    if ( dataType == CV_64F ) return getSigmaPoints<double>(mean, covMatrix, coef);
-    if ( dataType == CV_32F ) return getSigmaPoints<float>(mean, covMatrix, coef);
-
-    return Mat();
-}
-
-Mat AugmentedUnscentedKalmanFilterImpl::predict(const Mat& control)
+Mat AugmentedUnscentedKalmanFilterImpl::predict(InputArray _control)
 {
+    Mat control = _control.getMat();
 // get sigma points from xa* and Pa
     sigmaPoints = getSigmaPoints( stateAug, errorCovAug, sqrt( tmpLambda ) );
 
@@ -368,8 +319,9 @@ Mat AugmentedUnscentedKalmanFilterImpl::predict(const Mat& control)
     return state.clone();
 }
 
-Mat AugmentedUnscentedKalmanFilterImpl::correct(const Mat& measurement)
+Mat AugmentedUnscentedKalmanFilterImpl::correct(InputArray _measurement)
 {
+    Mat measurement = _measurement.getMat();
 // get sigma points from xa* and Pa
     sigmaPoints = getSigmaPoints( stateAug, errorCovAug, sqrt( tmpLambda ) );
 
diff --git a/contrib/modules/tracking/src/gtrTracker.cpp b/contrib/modules/tracking/src/gtrTracker.cpp
new file mode 100644
index 0000000..58debfd
--- /dev/null
+++ b/contrib/modules/tracking/src/gtrTracker.cpp
@@ -0,0 +1,191 @@
+/*///////////////////////////////////////////////////////////////////////////////////////
+//
+//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+//  By downloading, copying, installing or using the software you agree to this license.
+//  If you do not agree to this license, do not download, install,
+//  copy or use the software.
+//
+//
+//                           License Agreement
+//                For Open Source Computer Vision Library
+//
+// Copyright (C) 2013, OpenCV Foundation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+//   * Redistribution's of source code must retain the above copyright notice,
+//     this list of conditions and the following disclaimer.
+//
+//   * Redistribution's in binary form must reproduce the above copyright notice,
+//     this list of conditions and the following disclaimer in the documentation
+//     and/or other materials provided with the distribution.
+//
+//   * The name of the copyright holders may not be used to endorse or promote products
+//     derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "gtrTracker.hpp"
+
+
+namespace cv
+{
+
+TrackerGOTURN::Params::Params(){}
+
+void TrackerGOTURN::Params::read(const cv::FileNode& /*fn*/){}
+
+void TrackerGOTURN::Params::write(cv::FileStorage& /*fs*/) const {}
+
+
+Ptr<TrackerGOTURN> TrackerGOTURN::createTracker(const TrackerGOTURN::Params &parameters)
+{
+    return Ptr<gtr::TrackerGOTURNImpl>(new gtr::TrackerGOTURNImpl(parameters));
+}
+
+namespace gtr
+{
+
+class TrackerGOTURNModel : public TrackerModel{
+public:
+    TrackerGOTURNModel(TrackerGOTURN::Params){}
+    Rect2d getBoundingBox(){ return boundingBox_; }
+    void setBoudingBox(Rect2d boundingBox){ boundingBox_ = boundingBox; }
+    Mat getImage(){ return image_; }
+    void setImage(const Mat& image){ image.copyTo(image_); }
+protected:
+    Rect2d boundingBox_;
+    Mat image_;
+    void modelEstimationImpl(const std::vector<Mat>&){}
+    void modelUpdateImpl(){}
+};
+
+TrackerGOTURNImpl::TrackerGOTURNImpl(const TrackerGOTURN::Params &parameters) :
+    params(parameters){
+    isInit = false;
+};
+
+void TrackerGOTURNImpl::read(const cv::FileNode& fn)
+{
+    params.read(fn);
+}
+
+void TrackerGOTURNImpl::write(cv::FileStorage& fs) const
+{
+    params.write(fs);
+}
+
+bool TrackerGOTURNImpl::initImpl(const Mat& image, const Rect2d& boundingBox)
+{
+    //Make a simple model from frame and bounding box
+    model = Ptr<TrackerGOTURNModel>(new TrackerGOTURNModel(params));
+    ((TrackerGOTURNModel*)static_cast<TrackerModel*>(model))->setImage(image);
+    ((TrackerGOTURNModel*)static_cast<TrackerModel*>(model))->setBoudingBox(boundingBox);
+
+    //Load GOTURN architecture from *.prototxt and pretrained weights from *.caffemodel
+    String modelTxt = "goturn.prototxt";
+    String modelBin = "goturn.caffemodel";
+    Ptr<dnn::Importer> importer;
+    try                                     //Import GOTURN model
+    {
+        importer = dnn::createCaffeImporter(modelTxt, modelBin);
+    }
+    catch (const cv::Exception &err)        //Importer can throw errors, we will catch them
+    {
+        std::cerr << err.msg << std::endl;
+    }
+    if (!importer)
+    {
+        cvError(CV_StsError, "cv::gtr::InitImpl", "GOTURN network loading error...", "gtrTracker.cpp", 117);
+    }
+
+    importer->populateNet(net);
+    importer.release();                     //We don't need importer anymore
+
+    return true;
+}
+
+bool TrackerGOTURNImpl::updateImpl(const Mat& image, Rect2d& boundingBox)
+{
+    int INPUT_SIZE = 227;
+    //Using prevFrame & prevBB from model and curFrame GOTURN calculating curBB
+    Mat curFrame = image.clone();
+    Mat prevFrame = ((TrackerGOTURNModel*)static_cast<TrackerModel*>(model))->getImage();
+    Rect2d prevBB = ((TrackerGOTURNModel*)static_cast<TrackerModel*>(model))->getBoundingBox();
+    Rect2d curBB;
+
+    float padTargetPatch = 2.0;
+    Rect2f searchPatchRect, targetPatchRect;
+    Point2f currCenter, prevCenter;
+    Mat prevFramePadded, curFramePadded;
+    Mat searchPatch, targetPatch;
+
+    prevCenter.x = (float)(prevBB.x + prevBB.width / 2);
+    prevCenter.y = (float)(prevBB.y + prevBB.height / 2);
+
+    targetPatchRect.width = (float)(prevBB.width*padTargetPatch);
+    targetPatchRect.height = (float)(prevBB.height*padTargetPatch);
+    targetPatchRect.x = (float)(prevCenter.x - prevBB.width*padTargetPatch / 2.0 + targetPatchRect.width);
+    targetPatchRect.y = (float)(prevCenter.y - prevBB.height*padTargetPatch / 2.0 + targetPatchRect.height);
+
+    copyMakeBorder(prevFrame, prevFramePadded, (int)targetPatchRect.height, (int)targetPatchRect.height, (int)targetPatchRect.width, (int)targetPatchRect.width, BORDER_REPLICATE);
+    targetPatch = prevFramePadded(targetPatchRect).clone();
+
+    copyMakeBorder(curFrame, curFramePadded, (int)targetPatchRect.height, (int)targetPatchRect.height, (int)targetPatchRect.width, (int)targetPatchRect.width, BORDER_REPLICATE);
+    searchPatch = curFramePadded(targetPatchRect).clone();
+
+    //Preprocess
+    //Resize
+    resize(targetPatch, targetPatch, Size(INPUT_SIZE, INPUT_SIZE));
+    resize(searchPatch, searchPatch, Size(INPUT_SIZE, INPUT_SIZE));
+
+    //Mean Subtract
+    targetPatch = targetPatch - 128;
+    searchPatch = searchPatch - 128;
+
+    //Convert to Float type
+    targetPatch.convertTo(targetPatch, CV_32F);
+    searchPatch.convertTo(searchPatch, CV_32F);
+
+    dnn::Blob targetBlob = dnn::Blob(targetPatch);
+    dnn::Blob searchBlob = dnn::Blob(searchPatch);
+
+    net.setBlob(".data1", targetBlob);
+    net.setBlob(".data2", searchBlob);
+
+    net.forward();
+    dnn::Blob res = net.getBlob("scale");
+
+    Mat resMat = res.matRefConst().reshape(1, 1);
+
+    curBB.x = targetPatchRect.x + (resMat.at<float>(0) * targetPatchRect.width / INPUT_SIZE) - targetPatchRect.width;
+    curBB.y = targetPatchRect.y + (resMat.at<float>(1) * targetPatchRect.height / INPUT_SIZE) - targetPatchRect.height;
+    curBB.width = (resMat.at<float>(2) - resMat.at<float>(0)) * targetPatchRect.width / INPUT_SIZE;
+    curBB.height = (resMat.at<float>(3) - resMat.at<float>(1)) * targetPatchRect.height / INPUT_SIZE;
+
+    //Predicted BB
+    boundingBox = curBB;
+
+    //Set new model image and BB from current frame
+    ((TrackerGOTURNModel*)static_cast<TrackerModel*>(model))->setImage(curFrame);
+    ((TrackerGOTURNModel*)static_cast<TrackerModel*>(model))->setBoudingBox(curBB);
+    return true;
+}
+
+}
+
+}
diff --git a/contrib/modules/tracking/src/gtrTracker.hpp b/contrib/modules/tracking/src/gtrTracker.hpp
new file mode 100644
index 0000000..34f2c48
--- /dev/null
+++ b/contrib/modules/tracking/src/gtrTracker.hpp
@@ -0,0 +1,76 @@
+
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+//  By downloading, copying, installing or using the software you agree to this license.
+//  If you do not agree to this license, do not download, install,
+//  copy or use the software.
+//
+//
+//                           License Agreement
+//                For Open Source Computer Vision Library
+//
+// Copyright (C) 2013, OpenCV Foundation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+//   * Redistribution's of source code must retain the above copyright notice,
+//     this list of conditions and the following disclaimer.
+//
+//   * Redistribution's in binary form must reproduce the above copyright notice,
+//     this list of conditions and the following disclaimer in the documentation
+//     and/or other materials provided with the distribution.
+//
+//   * The name of the copyright holders may not be used to endorse or promote products
+//     derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#ifndef OPENCV_GOTURN_TRACKER
+#define OPENCV_GOTURN_TRACKER
+
+#include "precomp.hpp"
+#include "opencv2/video/tracking.hpp"
+#include "opencv2/dnn.hpp"
+#include "gtrUtils.hpp"
+#include "opencv2/imgproc.hpp"
+#include<algorithm>
+#include<limits.h>
+
+namespace cv
+{
+namespace gtr
+{
+
+class TrackerGOTURNImpl : public TrackerGOTURN
+{
+public:
+    TrackerGOTURNImpl(const TrackerGOTURN::Params &parameters = TrackerGOTURN::Params());
+    void read(const FileNode& fn);
+    void write(FileStorage& fs) const;
+    bool initImpl(const Mat& image, const Rect2d& boundingBox);
+    bool updateImpl(const Mat& image, Rect2d& boundingBox);
+
+    TrackerGOTURN::Params params;
+
+    dnn::Net net;
+};
+
+}
+}
+
+#endif
diff --git a/contrib/modules/tracking/src/gtrUtils.cpp b/contrib/modules/tracking/src/gtrUtils.cpp
new file mode 100644
index 0000000..0df1197
--- /dev/null
+++ b/contrib/modules/tracking/src/gtrUtils.cpp
@@ -0,0 +1,146 @@
+/*///////////////////////////////////////////////////////////////////////////////////////
+ //
+ //  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+ //
+ //  By downloading, copying, installing or using the software you agree to this license.
+ //  If you do not agree to this license, do not download, install,
+ //  copy or use the software.
+ //
+ //
+ //                           License Agreement
+ //                For Open Source Computer Vision Library
+ //
+ // Copyright (C) 2013, OpenCV Foundation, all rights reserved.
+ // Third party copyrights are property of their respective owners.
+ //
+ // Redistribution and use in source and binary forms, with or without modification,
+ // are permitted provided that the following conditions are met:
+ //
+ //   * Redistribution's of source code must retain the above copyright notice,
+ //     this list of conditions and the following disclaimer.
+ //
+ //   * Redistribution's in binary form must reproduce the above copyright notice,
+ //     this list of conditions and the following disclaimer in the documentation
+ //     and/or other materials provided with the distribution.
+ //
+ //   * The name of the copyright holders may not be used to endorse or promote products
+ //     derived from this software without specific prior written permission.
+ //
+ // This software is provided by the copyright holders and contributors "as is" and
+ // any express or implied warranties, including, but not limited to, the implied
+ // warranties of merchantability and fitness for a particular purpose are disclaimed.
+ // In no event shall the Intel Corporation or contributors be liable for any direct,
+ // indirect, incidental, special, exemplary, or consequential damages
+ // (including, but not limited to, procurement of substitute goods or services;
+ // loss of use, data, or profits; or business interruption) however caused
+ // and on any theory of liability, whether in contract, strict liability,
+ // or tort (including negligence or otherwise) arising in any way out of
+ // the use of this software, even if advised of the possibility of such damage.
+ //
+ //M*/
+
+#include "gtrUtils.hpp"
+
+
+namespace cv
+{
+namespace gtr
+{
+
+double generateRandomLaplacian(double b, double m)
+{
+    double t = (double)rand() / (RAND_MAX);
+    double n = (double)rand() / (RAND_MAX);
+
+    if (t > 0.5)
+        return m + b*log(n);
+    else
+        return m - b*log(n);
+}
+
+Rect2f anno2rect(vector<Point2f> annoBB)
+{
+    Rect2f rectBB;
+    rectBB.x = min(annoBB[0].x, annoBB[1].x);
+    rectBB.y = min(annoBB[0].y, annoBB[2].y);
+    rectBB.width = fabs(annoBB[0].x - annoBB[1].x);
+    rectBB.height = fabs(annoBB[0].y - annoBB[2].y);
+
+    return rectBB;
+}
+
+vector <TrainingSample> gatherFrameSamples(Mat prevFrame, Mat currFrame, Rect2f prevBB, Rect2f currBB)
+{
+    vector <TrainingSample> trainingSamples;
+    Point2f currCenter, prevCenter;
+    Rect2f targetPatchRect, searchPatchRect;
+    Mat targetPatch, searchPatch;
+    Mat prevFramePadded, currFramePadded;
+
+    //Crop Target Patch
+
+    //Padding
+
+    //Previous frame GTBBs center
+    prevCenter.x = prevBB.x + prevBB.width / 2;
+    prevCenter.y = prevBB.y + prevBB.height / 2;
+
+    targetPatchRect.width = (float)(prevBB.width*padTarget);
+    targetPatchRect.height = (float)(prevBB.height*padTarget);
+    targetPatchRect.x = (float)(prevCenter.x - prevBB.width*padTarget / 2.0 + targetPatchRect.width);
+    targetPatchRect.y = (float)(prevCenter.y - prevBB.height*padTarget / 2.0 + targetPatchRect.height);
+
+    copyMakeBorder(prevFrame, prevFramePadded, (int)targetPatchRect.height, (int)targetPatchRect.height, (int)targetPatchRect.width, (int)targetPatchRect.width, BORDER_REPLICATE);
+
+    targetPatch = prevFramePadded(targetPatchRect);
+
+
+    for (int i = 0; i < samplesInFrame; i++)
+    {
+        TrainingSample sample;
+
+        //Current frame GTBBs center
+        currCenter.x = (float)(currBB.x + currBB.width / 2.0);
+        currCenter.y = (float)(currBB.y + currBB.height / 2.0);
+
+        //Generate and add random Laplacian distribution (Scaling from target size)
+        double dx, dy, ds;
+        dx = generateRandomLaplacian(bX, 0)*prevBB.width;
+        dy = generateRandomLaplacian(bY, 0)*prevBB.height;
+        ds = generateRandomLaplacian(bS, 1);
+
+        //Limit coefficients
+        dx = min(dx, (double)prevBB.width);
+        dx = max(dx, (double)-prevBB.width);
+        dy = min(dy, (double)prevBB.height);
+        dy = max(dy, (double)-prevBB.height);
+        ds = min(ds, Ymax);
+        ds = max(ds, Ymin);
+
+        searchPatchRect.width = (float)(prevBB.width*padSearch*ds);
+        searchPatchRect.height =(float)(prevBB.height*padSearch*ds);
+        searchPatchRect.x = (float)(currCenter.x + dx - searchPatchRect.width / 2.0 + searchPatchRect.width);
+        searchPatchRect.y = (float)(currCenter.y + dy - searchPatchRect.height / 2.0 + searchPatchRect.height);
+        copyMakeBorder(currFrame, currFramePadded, (int)searchPatchRect.height, (int)searchPatchRect.height, (int)searchPatchRect.width, (int)searchPatchRect.width, BORDER_REPLICATE);
+        searchPatch = currFramePadded(searchPatchRect);
+
+        //Calculate Relative GTBB in search patch
+        Rect2f relGTBB;
+        relGTBB.width = currBB.width;
+        relGTBB.height = currBB.height;
+        relGTBB.x = currBB.x - searchPatchRect.x + searchPatchRect.width;
+        relGTBB.y = currBB.y - searchPatchRect.y + searchPatchRect.height;
+
+        //Link to the sample struct
+        sample.targetPatch = targetPatch.clone();
+        sample.searchPatch = searchPatch.clone();
+        sample.targetBB = relGTBB;
+
+        trainingSamples.push_back(sample);
+    }
+
+    return trainingSamples;
+}
+
+}
+}
diff --git a/contrib/modules/tracking/src/gtrUtils.hpp b/contrib/modules/tracking/src/gtrUtils.hpp
new file mode 100644
index 0000000..8f388be
--- /dev/null
+++ b/contrib/modules/tracking/src/gtrUtils.hpp
@@ -0,0 +1,61 @@
+#ifndef OPENCV_GTR_UTILS
+#define OPENCV_GTR_UTILS
+
+#include "precomp.hpp"
+#include <vector>
+#include "opencv2/highgui.hpp"
+#include <opencv2/datasets/track_alov.hpp>
+
+namespace cv
+{
+namespace gtr
+{
+
+//Number of samples in batch
+const int samplesInBatch = 50;
+
+//Number of samples to mine from video frame
+const int samplesInFrame = 10;
+
+//Number of samples to mine from still image
+const int samplesInImage = 10;
+
+//Padding coefficients for Target/Search Region
+const double padTarget = 2.0;
+const double padSearch = 2.0;
+
+//Scale parameters for Laplace distribution for Translation/Scale
+const double bX = 1.0/10;
+const double bY = 1.0/10;
+const double bS = 1.0/15;
+
+//Limits of scale changes
+const double Ymax = 1.4;
+const double Ymin = 0.6;
+
+//Lower boundary constraints for random samples (sample should include X% of target BB)
+const double minX = 0.5;
+const double minY = 0.5;
+
+//Structure of sample for training
+struct TrainingSample
+{
+    Mat targetPatch;
+    Mat searchPatch;
+    //Output bounding box on search patch
+    Rect2f targetBB;
+};
+
+//Laplacian distribution
+double generateRandomLaplacian(double b, double m);
+
+//Convert ALOV300++ anno coordinates to Rectangle BB
+Rect2f anno2rect(vector<Point2f> annoBB);
+
+//Gather samples from random video frame
+vector <TrainingSample> gatherFrameSamples(Mat prevFrame, Mat currFrame, Rect2f prevBB, Rect2f currBB);
+
+}
+}
+
+#endif
diff --git a/contrib/modules/tracking/src/onlineMIL.cpp b/contrib/modules/tracking/src/onlineMIL.cpp
index 4fcfb54..29fa9fe 100644
--- a/contrib/modules/tracking/src/onlineMIL.cpp
+++ b/contrib/modules/tracking/src/onlineMIL.cpp
@@ -42,6 +42,8 @@
 #include "precomp.hpp"
 #include "opencv2/tracking/onlineMIL.hpp"
 
+#define  sign(s)  ((s > 0 ) ? 1 : ((s<0) ? -1 : 0))
+
 template<class T> class SortableElementRev
 {
  public:
diff --git a/contrib/modules/tracking/src/precomp.hpp b/contrib/modules/tracking/src/precomp.hpp
index 0d67de8..660cdfc 100644
--- a/contrib/modules/tracking/src/precomp.hpp
+++ b/contrib/modules/tracking/src/precomp.hpp
@@ -45,10 +45,63 @@
 #include "opencv2/tracking.hpp"
 #include "opencv2/core/utility.hpp"
 #include "opencv2/core/ocl.hpp"
+#include <typeinfo>
+#include "opencv2/core/hal/hal.hpp"
 
 namespace cv
 {
 	extern const double ColorNames[][10];
-}
+
+    namespace tracking {
+
+    /* Cholesky decomposition
+     The function performs Cholesky decomposition <https://en.wikipedia.org/wiki/Cholesky_decomposition>.
+     A - the Hermitian, positive-definite matrix,
+     astep - size of row in A,
+     asize - number of cols and rows in A,
+     L - the lower triangular matrix, A = L*Lt.
+    */
+
+    template<typename _Tp> bool
+    inline callHalCholesky( _Tp* L, size_t lstep, int lsize );
+
+    template<> bool
+    inline callHalCholesky<float>( float* L, size_t lstep, int lsize )
+    {
+        return hal::Cholesky32f(L, lstep, lsize, NULL, 0, 0);
+    }
+
+    template<> bool
+    inline callHalCholesky<double>( double* L, size_t lstep, int lsize)
+    {
+        return hal::Cholesky64f(L, lstep, lsize, NULL, 0, 0);
+    }
+
+    template<typename _Tp> bool
+    inline choleskyDecomposition( const _Tp* A, size_t astep, int asize, _Tp* L, size_t lstep )
+    {
+        bool success = false;
+
+        astep /= sizeof(_Tp);
+        lstep /= sizeof(_Tp);
+
+        for(int i = 0; i < asize; i++)
+            for(int j = 0; j <= i; j++)
+                L[i*lstep + j] = A[i*astep + j];
+
+       success = callHalCholesky(L, lstep*sizeof(_Tp), asize);
+
+       if(success)
+       {
+           for(int i = 0; i < asize; i++ )
+               for(int j = i + 1; j < asize; j++ )
+                   L[i*lstep + j] = 0.0;
+       }
+
+        return success;
+    }
+
+    } // tracking
+} // cv
 
 #endif
diff --git a/contrib/modules/tracking/src/roiSelector.cpp b/contrib/modules/tracking/src/roiSelector.cpp
index 051129f..a1a7e6e 100644
--- a/contrib/modules/tracking/src/roiSelector.cpp
+++ b/contrib/modules/tracking/src/roiSelector.cpp
@@ -107,7 +107,7 @@ namespace cv {
     // select the object
     setMouseCallback( windowName, mouseHandler, (void *)&selectorParams );
 
-    // end selection process on SPACE (32) BACKSPACE (27) or ENTER (13)
+    // end selection process on SPACE (32) ESC (27) or ENTER (13)
     while(!(key==32 || key==27 || key==13)){
       // draw the selected object
       rectangle(
@@ -141,8 +141,8 @@ namespace cv {
       // reset the image
       selectorParams.image=img.clone();
 
-      //get keyboard event
-      key=waitKey(1);
+      //get keyboard event, extract lower 8 bits for scancode comparison
+      key=waitKey(1) & 0xFF;
     }
 
 
@@ -156,11 +156,12 @@ namespace cv {
 
     // show notice to user
     printf("Select an object to track and then press SPACE or ENTER button!\n" );
-    printf("Finish the selection process by pressing BACKSPACE button!\n" );
+    printf("Finish the selection process by pressing ESC button!\n" );
 
-    // while key is not Backspace
-    while(key!=27){
+    // while key is not ESC (27)
+    for(;;) {
       temp=select(windowName, img, true, fromCenter);
+      if(key==27) break;
       if(temp.width>0 && temp.height>0)
         box.push_back(temp);
     }
diff --git a/contrib/modules/tracking/src/tldDetector.cpp b/contrib/modules/tracking/src/tldDetector.cpp
index 7136e70..633a60b 100644
--- a/contrib/modules/tracking/src/tldDetector.cpp
+++ b/contrib/modules/tracking/src/tldDetector.cpp
@@ -41,6 +41,8 @@
 
 #include "tldDetector.hpp"
 
+#include <opencv2/core/utility.hpp>
+
 namespace cv
 {
 	namespace tld
@@ -63,7 +65,7 @@ namespace cv
 		}
 
 		// Calculate Relative similarity of the patch (NN-Model)
-		double TLDDetector::Sr(const Mat_<uchar>& patch)
+		double TLDDetector::Sr(const Mat_<uchar>& patch) const
 		{
 			double splus = 0.0, sminus = 0.0;
 			Mat_<uchar> modelSample(STANDARD_PATCH_SIZE, STANDARD_PATCH_SIZE);
@@ -189,7 +191,7 @@ namespace cv
 #endif
 
 		// Calculate Conservative similarity of the patch (NN-Model)
-		double TLDDetector::Sc(const Mat_<uchar>& patch)
+		double TLDDetector::Sc(const Mat_<uchar>& patch) const
 		{
 			double splus = 0.0, sminus = 0.0;
 			Mat_<uchar> modelSample(STANDARD_PATCH_SIZE, STANDARD_PATCH_SIZE);
@@ -298,10 +300,38 @@ namespace cv
 
 		//Detection - returns most probable new target location (Max Sc)
 
+		class CalcScSrParallelLoopBody: public cv::ParallelLoopBody
+		{
+		public:
+			explicit CalcScSrParallelLoopBody (TLDDetector * detector, Size initSize):
+				detectorF (detector),
+				initSizeF (initSize)
+			{
+			}
+
+			virtual void operator () (const cv::Range & r) const
+			{
+				for (int ind = r.start; ind < r.end; ++ind)
+				{
+					resample(detectorF->resized_imgs[detectorF->ensScaleIDs[ind]],
+						Rect2d(detectorF->ensBuffer[ind], initSizeF),
+						detectorF->standardPatches[ind]);
+
+					detectorF->scValues[ind] = detectorF->Sc (detectorF->standardPatches[ind]);
+					detectorF->srValues[ind] = detectorF->Sr (detectorF->standardPatches[ind]);
+				}
+			}
+
+			TLDDetector * detectorF;
+			const Size initSizeF;
+		private:
+			CalcScSrParallelLoopBody (const CalcScSrParallelLoopBody&);
+			CalcScSrParallelLoopBody& operator= (const CalcScSrParallelLoopBody&);
+		};
+
 		bool TLDDetector::detect(const Mat& img, const Mat& imgBlurred, Rect2d& res, std::vector<LabeledPatch>& patches, Size initSize)
 		{
 			patches.clear();
-			Mat_<uchar> standardPatch(STANDARD_PATCH_SIZE, STANDARD_PATCH_SIZE);
 			Mat tmp;
 			int dx = initSize.width / 10, dy = initSize.height / 10;
 			Size2d size = img.size();
@@ -310,9 +340,13 @@ namespace cv
 			double maxSc = -5.0;
 			Rect2d maxScRect;
 			int scaleID;
-			std::vector <Mat> resized_imgs, blurred_imgs;
-			std::vector <Point> varBuffer, ensBuffer;
-			std::vector <int> varScaleIDs, ensScaleIDs;
+
+			resized_imgs.clear ();
+			blurred_imgs.clear ();
+			varBuffer.clear ();
+			ensBuffer.clear ();
+			varScaleIDs.clear ();
+			ensScaleIDs.clear ();
 
 			//Detection part
 			//Generate windows and filter by variance
@@ -353,16 +387,34 @@ namespace cv
 				ensScaleIDs.push_back(varScaleIDs[i]);
 			}
 
+			//Batch preparation
+			srValues.resize (ensBuffer.size());
+			scValues.resize (ensBuffer.size());
+
+			//Carefully resize standard patches with reference-counted Mat members
+			const int oldPatchesSize = (int)standardPatches.size();
+			standardPatches.resize (ensBuffer.size());
+			if ((int)ensBuffer.size() > oldPatchesSize)
+			{
+				Mat_<uchar> standardPatch(STANDARD_PATCH_SIZE, STANDARD_PATCH_SIZE);
+				for (int i = oldPatchesSize; i < (int)ensBuffer.size(); ++i)
+				{
+					standardPatches[i] = standardPatch.clone();
+				}
+			}
+
+			//Batch calculation
+			cv::parallel_for_ (cv::Range (0, (int)ensBuffer.size ()), CalcScSrParallelLoopBody (this, initSize));
+
 			//NN classification
 			for (int i = 0; i < (int)ensBuffer.size(); i++)
 			{
 				LabeledPatch labPatch;
 				double curScale = pow(SCALE_STEP, ensScaleIDs[i]);
 				labPatch.rect = Rect2d(ensBuffer[i].x*curScale, ensBuffer[i].y*curScale, initSize.width * curScale, initSize.height * curScale);
-				resample(resized_imgs[ensScaleIDs[i]], Rect2d(ensBuffer[i], initSize), standardPatch);
 
-				double srValue, scValue;
-				srValue = Sr(standardPatch);
+				const double srValue = srValues[i];
+				const double scValue = scValues[i];
 
 				////To fix: Check the paper, probably this cause wrong learning
 				//
@@ -380,7 +432,7 @@ namespace cv
 				{
 					npos++;
 				}
-				scValue = Sc(standardPatch);
+
 				if (scValue > maxSc)
 				{
 					maxSc = scValue;
@@ -540,4 +592,4 @@ namespace cv
 		}
 
 	}
-}
\ No newline at end of file
+}
diff --git a/contrib/modules/tracking/src/tldDetector.hpp b/contrib/modules/tracking/src/tldDetector.hpp
index 7421256..4fbc4df 100644
--- a/contrib/modules/tracking/src/tldDetector.hpp
+++ b/contrib/modules/tracking/src/tldDetector.hpp
@@ -75,8 +75,8 @@ namespace cv
 			~TLDDetector(){}
 			double ensembleClassifierNum(const uchar* data);
 			void prepareClassifiers(int rowstep);
-			double Sr(const Mat_<uchar>& patch);
-			double Sc(const Mat_<uchar>& patch);
+			double Sr(const Mat_<uchar>& patch) const;
+			double Sc(const Mat_<uchar>& patch) const;
 #ifdef HAVE_OPENCL
 			double ocl_Sr(const Mat_<uchar>& patch);
 			double ocl_Sc(const Mat_<uchar>& patch);
@@ -89,6 +89,12 @@ namespace cv
 			std::vector<Mat_<uchar> > *positiveExamples, *negativeExamples;
 			std::vector<int> *timeStampsPositive, *timeStampsNegative;
 			double *originalVariancePtr;
+			std::vector<double> scValues, srValues;
+			std::vector<Mat_<uchar> > standardPatches;
+
+			std::vector <Mat> resized_imgs, blurred_imgs;
+			std::vector <Point> varBuffer, ensBuffer;
+			std::vector <int> varScaleIDs, ensScaleIDs;
 
 			static void generateScanGrid(int rows, int cols, Size initBox, std::vector<Rect2d>& res, bool withScaling = false);
 			struct LabeledPatch
@@ -108,4 +114,4 @@ namespace cv
 	}
 }
 
-#endif
\ No newline at end of file
+#endif
diff --git a/contrib/modules/tracking/src/tldModel.cpp b/contrib/modules/tracking/src/tldModel.cpp
index 03d922e..5598ca5 100644
--- a/contrib/modules/tracking/src/tldModel.cpp
+++ b/contrib/modules/tracking/src/tldModel.cpp
@@ -41,6 +41,8 @@
 
 #include "tldModel.hpp"
 
+#include <opencv2/core/utility.hpp>
+
 namespace cv
 {
 	namespace tld
@@ -182,14 +184,41 @@ namespace cv
 
 		}
 
+		class CalcSrParallelLoopBody: public cv::ParallelLoopBody
+		{
+		public:
+			explicit CalcSrParallelLoopBody (TrackerTLDModel * model, const std::vector<Mat_<uchar> >& eForModel):
+				modelF (model),
+				eForModelF (eForModel)
+			{
+			}
+
+			virtual void operator () (const cv::Range & r) const
+			{
+				for (int ind = r.start; ind < r.end; ++ind)
+				{
+					modelF->srValues[ind] = modelF->detector->Sr (eForModelF[ind]);
+				}
+			}
+
+			TrackerTLDModel * modelF;
+			const std::vector<Mat_<uchar> >& eForModelF;
+		private:
+			CalcSrParallelLoopBody (const CalcSrParallelLoopBody&);
+			CalcSrParallelLoopBody& operator= (const CalcSrParallelLoopBody&);
+		};
+
 		void TrackerTLDModel::integrateAdditional(const std::vector<Mat_<uchar> >& eForModel, const std::vector<Mat_<uchar> >& eForEnsemble, bool isPositive)
 		{
 			int positiveIntoModel = 0, negativeIntoModel = 0, positiveIntoEnsemble = 0, negativeIntoEnsemble = 0;
 			if ((int)eForModel.size() == 0) return;
 
+			srValues.resize (eForModel.size ());
+			cv::parallel_for_ (cv::Range (0, (int)eForModel.size ()), CalcSrParallelLoopBody (this, eForModel));
+
 			for (int k = 0; k < (int)eForModel.size(); k++)
 			{
-				double sr = detector->Sr(eForModel[k]);
+				const double sr = srValues[k];
 				if ((sr > THETA_NN) != isPositive)
 				{
 					if (isPositive)
@@ -331,4 +360,4 @@ namespace cv
 			dfprintf((port, "\tnegativeExamples.size() = %d\n", (int)negativeExamples.size()));
 		}
 	}
-}
\ No newline at end of file
+}
diff --git a/contrib/modules/tracking/src/tldModel.hpp b/contrib/modules/tracking/src/tldModel.hpp
index ba7c926..a46aa1d 100644
--- a/contrib/modules/tracking/src/tldModel.hpp
+++ b/contrib/modules/tracking/src/tldModel.hpp
@@ -71,6 +71,7 @@ namespace cv
 			std::vector<int> timeStampsPositive, timeStampsNegative;
 			int timeStampPositiveNext, timeStampNegativeNext;
 			double originalVariance_;
+			std::vector<double> srValues;
 
 			double getOriginalVariance(){ return originalVariance_; }
 
@@ -87,4 +88,4 @@ namespace cv
 	}
 }
 
-#endif
\ No newline at end of file
+#endif
diff --git a/contrib/modules/tracking/src/tldTracker.cpp b/contrib/modules/tracking/src/tldTracker.cpp
index 51d994e..05585e1 100644
--- a/contrib/modules/tracking/src/tldTracker.cpp
+++ b/contrib/modules/tracking/src/tldTracker.cpp
@@ -82,7 +82,15 @@ bool TrackerTLDImpl::initImpl(const Mat& image, const Rect2d& boundingBox)
 {
     Mat image_gray;
     trackerProxy->init(image, boundingBox);
-    cvtColor( image, image_gray, COLOR_BGR2GRAY );
+    if(image.channels() > 1)
+    {
+        cvtColor( image, image_gray, COLOR_BGR2GRAY );
+    }
+    else
+    {
+        image_gray = image.clone();
+    }
+
     data = Ptr<Data>(new Data(boundingBox));
     double scale = data->getScale();
     Rect2d myBoundingBox = boundingBox;
diff --git a/contrib/modules/tracking/src/tracker.cpp b/contrib/modules/tracking/src/tracker.cpp
index cad2ffd..8127f2a 100644
--- a/contrib/modules/tracking/src/tracker.cpp
+++ b/contrib/modules/tracking/src/tracker.cpp
@@ -111,6 +111,7 @@ Ptr<Tracker> Tracker::create( const String& trackerType )
   BOILERPLATE_CODE("MEDIANFLOW",TrackerMedianFlow);
   BOILERPLATE_CODE("TLD",TrackerTLD);
   BOILERPLATE_CODE("KCF",TrackerKCF);
+  BOILERPLATE_CODE("GOTURN", TrackerGOTURN);
   return Ptr<Tracker>();
 }
 
diff --git a/contrib/modules/tracking/src/trackerKCF.cpp b/contrib/modules/tracking/src/trackerKCF.cpp
index 4fab280..5ccc3f4 100644
--- a/contrib/modules/tracking/src/trackerKCF.cpp
+++ b/contrib/modules/tracking/src/trackerKCF.cpp
@@ -336,12 +336,14 @@ namespace cv{
       minMaxLoc( response, &minVal, &maxVal, &minLoc, &maxLoc );
       roi.x+=(maxLoc.x-roi.width/2+1);
       roi.y+=(maxLoc.y-roi.height/2+1);
-
-      // update the bounding box
-      boundingBox.x=(resizeImage?roi.x*2:roi.x)+boundingBox.width/2;
-      boundingBox.y=(resizeImage?roi.y*2:roi.y)+boundingBox.height/2;
     }
 
+    // update the bounding box
+    boundingBox.x=(resizeImage?roi.x*2:roi.x)+(resizeImage?roi.width*2:roi.width)/4;
+    boundingBox.y=(resizeImage?roi.y*2:roi.y)+(resizeImage?roi.height*2:roi.height)/4;
+    boundingBox.width = (resizeImage?roi.width*2:roi.width)/2;
+    boundingBox.height = (resizeImage?roi.height*2:roi.height)/2;
+
     // extract the patch for learning purpose
     // get non compressed descriptors
     for(unsigned i=0;i<descriptors_npca.size()-extractor_npca.size();i++){
@@ -666,7 +668,7 @@ namespace cv{
     for(int i=0;i<patch_data.rows;i++){
       for(int j=0;j<patch_data.cols;j++){
         pixel=patch_data.at<Vec3b>(i,j);
-        index=(unsigned)(floor(pixel[2]/8)+32*floor(pixel[1]/8)+32*32*floor(pixel[0]/8));
+        index=(unsigned)(floor((float)pixel[2]/8)+32*floor((float)pixel[1]/8)+32*32*floor((float)pixel[0]/8));
 
         //copy the values
         for(int _k=0;_k<10;_k++){
diff --git a/contrib/modules/tracking/src/trackerMedianFlow.cpp b/contrib/modules/tracking/src/trackerMedianFlow.cpp
index 7dcf4c0..f24fc3b 100644
--- a/contrib/modules/tracking/src/trackerMedianFlow.cpp
+++ b/contrib/modules/tracking/src/trackerMedianFlow.cpp
@@ -190,8 +190,15 @@ bool TrackerMedianFlowImpl::medianFlowImpl(Mat oldImage,Mat newImage,Rect2d& old
     std::vector<Point2f> pointsToTrackOld,pointsToTrackNew;
 
     Mat oldImage_gray,newImage_gray;
-    cvtColor( oldImage, oldImage_gray, COLOR_BGR2GRAY );
-    cvtColor( newImage, newImage_gray, COLOR_BGR2GRAY );
+    if (oldImage.channels() != 1)
+        cvtColor( oldImage, oldImage_gray, COLOR_BGR2GRAY );
+    else
+        oldImage.copyTo(oldImage_gray);
+
+    if (newImage.channels() != 1)
+        cvtColor( newImage, newImage_gray, COLOR_BGR2GRAY );
+    else
+        newImage.copyTo(newImage_gray);
 
     //"open ended" grid
     for(int i=0;i<params.pointsInGrid;i++){
diff --git a/contrib/modules/tracking/src/trackerModel.cpp b/contrib/modules/tracking/src/trackerModel.cpp
index 79499d5..38e4ab2 100644
--- a/contrib/modules/tracking/src/trackerModel.cpp
+++ b/contrib/modules/tracking/src/trackerModel.cpp
@@ -51,7 +51,7 @@ namespace cv
 TrackerModel::TrackerModel()
 {
   stateEstimator = Ptr<TrackerStateEstimator>();
-  maxCMLength = 1;
+  maxCMLength = 10;
 }
 
 TrackerModel::~TrackerModel()
diff --git a/contrib/modules/tracking/src/unscented_kalman.cpp b/contrib/modules/tracking/src/unscented_kalman.cpp
index 8cfa9d3..c29d7dc 100644
--- a/contrib/modules/tracking/src/unscented_kalman.cpp
+++ b/contrib/modules/tracking/src/unscented_kalman.cpp
@@ -47,49 +47,6 @@ namespace cv
 namespace tracking
 {
 
-/* Cholesky decomposition
- The function performs Cholesky decomposition <https://en.wikipedia.org/wiki/Cholesky_decomposition>.
- A - the Hermitian, positive-definite matrix,
- astep - size of row in A,
- asize - number of cols and rows in A,
- L - the lower triangular matrix, A = L*Lt.
-*/
-template<typename _Tp> bool
-inline choleskyDecomposition( const _Tp* A, size_t astep, const int asize, _Tp* L )
-{
-    int i, j, k;
-    double s;
-    astep /= sizeof(A[0]);
-    for( i = 0; i < asize; i++ )
-
-    {
-        for( j = 0; j < i; j++ )
-        {
-            s = A[i*astep + j];
-            for( k = 0; k < j; k++ )
-                s -= L[i*astep + k]*L[j*astep + k];
-            L[i*astep + j] = (_Tp)(s/L[j*astep + j]);
-        }
-        s = A[i*astep + i];
-        for( k = 0; k < i; k++ )
-        {
-            double t = L[i*astep + k];
-            s -= t*t;
-        }
-        if( s < std::numeric_limits<_Tp>::epsilon() )
-            return false;
-        L[i*astep + i] = (_Tp)(std::sqrt(s));
-    }
-
-   for( i = 0; i < asize; i++ )
-       for( j = i+1; j < asize; j++ )
-       {
-           L[i*astep + j] = 0.0;
-       }
-
-    return true;
-}
-
 void UnscentedKalmanFilterParams::
     init( int dp, int mp, int cp, double processNoiseCovDiag, double measurementNoiseCovDiag,
                                 Ptr<UkfSystemModel> dynamicalSystem, int type )
@@ -166,11 +123,6 @@ class UnscentedKalmanFilterImpl: public UnscentedKalmanFilter
     Mat r;                                      // zero vector of process noise for getting transitionSPFuncVals,
     Mat q;                                      // zero vector of measurement noise for getting measurementSPFuncVals
 
-
-//get sigma points
-    template <typename T>
-    Mat getSigmaPoints( const Mat& mean, const Mat& covMatrix, double coef );
-
     Mat getSigmaPoints( const Mat& mean, const Mat& covMatrix, double coef );
 
 public:
@@ -180,11 +132,11 @@ public:
 
 // perform prediction step
 // control - the optional control vector, CP x 1
-    Mat predict( const Mat& control = Mat() );
+    Mat predict( InputArray control = noArray() );
 
 // perform correction step
 // measurement - current measurement vector, MP x 1
-    Mat correct( const Mat& measurement );
+    Mat correct( InputArray measurement );
 
 //  Get system parameters
     Mat getProcessNoiseCov() const;
@@ -282,7 +234,6 @@ UnscentedKalmanFilterImpl::~UnscentedKalmanFilterImpl()
     q.release();
 }
 
-template <typename T>
 Mat UnscentedKalmanFilterImpl::getSigmaPoints(const Mat &mean, const Mat &covMatrix, double coef)
 {
 // x_0 = mean
@@ -293,10 +244,17 @@ Mat UnscentedKalmanFilterImpl::getSigmaPoints(const Mat &mean, const Mat &covMat
     Mat points = repeat(mean, 1, 2*n+1);
 
     Mat covMatrixL = covMatrix.clone();
-    covMatrixL.setTo(0);
 
 // covMatrixL = cholesky( covMatrix )
-    choleskyDecomposition<T>( covMatrix.ptr<T>(), covMatrix.step, covMatrix.rows, covMatrixL.ptr<T>() );
+    if ( dataType == CV_64F )
+        choleskyDecomposition<double>(
+                    covMatrix.ptr<double>(), covMatrix.step, covMatrix.rows,
+                    covMatrixL.ptr<double>(), covMatrixL.step );
+    else if ( dataType == CV_32F )
+        choleskyDecomposition<float>(
+                    covMatrix.ptr<float>(), covMatrix.step, covMatrix.rows,
+                    covMatrixL.ptr<float>(), covMatrixL.step );
+
     covMatrixL = coef * covMatrixL;
 
     Mat p_plus = points( Rect( 1, 0, n, n ) );
@@ -308,16 +266,9 @@ Mat UnscentedKalmanFilterImpl::getSigmaPoints(const Mat &mean, const Mat &covMat
     return points;
 }
 
-Mat UnscentedKalmanFilterImpl::getSigmaPoints(const Mat &mean, const Mat &covMatrix, double coef)
-{
-    if ( dataType == CV_64F ) return getSigmaPoints<double>(mean, covMatrix, coef);
-    if ( dataType == CV_32F ) return getSigmaPoints<float>(mean, covMatrix, coef);
-
-    return Mat();
-}
-
-Mat UnscentedKalmanFilterImpl::predict(const Mat& control)
+Mat UnscentedKalmanFilterImpl::predict(InputArray _control)
 {
+    Mat control = _control.getMat();
 // get sigma points from x* and P
     sigmaPoints = getSigmaPoints( state, errorCov, sqrt( tmpLambda ) );
 
@@ -345,8 +296,9 @@ Mat UnscentedKalmanFilterImpl::predict(const Mat& control)
     return state.clone();
 }
 
-Mat UnscentedKalmanFilterImpl::correct(const Mat& measurement)
+Mat UnscentedKalmanFilterImpl::correct(InputArray _measurement)
 {
+    Mat measurement = _measurement.getMat();
 // get sigma points from x* and P
     sigmaPoints = getSigmaPoints( state, errorCov, sqrt( tmpLambda ) );
 
diff --git a/contrib/modules/tracking/test/test_trackerOPE.cpp b/contrib/modules/tracking/test/test_trackerOPE.cpp
index db8bdc1..09be4f8 100644
--- a/contrib/modules/tracking/test/test_trackerOPE.cpp
+++ b/contrib/modules/tracking/test/test_trackerOPE.cpp
@@ -422,6 +422,20 @@ TEST_P(OPE_Overlap, TLD)
   RecordProperty( "ratioSuccess", test.getRatioSucc() );
 }
 
+TEST_P(OPE_Distance, GOTURN)
+{
+  TrackerOPETest test(Tracker::create("GOTURN"), TrackerOPETest::DISTANCE, dataset, threshold);
+  test.run();
+  RecordProperty("ratioSuccess", test.getRatioSucc());
+}
+
+TEST_P(OPE_Overlap, GOTURN)
+{
+  TrackerOPETest test(Tracker::create("GOTURN"), TrackerOPETest::OVERLAP, dataset, threshold);
+  test.run();
+  RecordProperty("ratioSuccess", test.getRatioSucc());
+}
+
 INSTANTIATE_TEST_CASE_P( Tracking, OPE_Distance, testing::Combine( TESTSET_NAMES, LOCATION_ERROR_THRESHOLD ) );
 
 INSTANTIATE_TEST_CASE_P( Tracking, OPE_Overlap, testing::Combine( TESTSET_NAMES, OVERLAP_THRESHOLD ) );
diff --git a/contrib/modules/tracking/test/test_trackerSRE.cpp b/contrib/modules/tracking/test/test_trackerSRE.cpp
index a688517..c50437b 100644
--- a/contrib/modules/tracking/test/test_trackerSRE.cpp
+++ b/contrib/modules/tracking/test/test_trackerSRE.cpp
@@ -529,6 +529,20 @@ TEST_P(SRE_Overlap, TLD)
   RecordProperty( "ratioSuccess", test.getRatioSucc() );
 }
 
+TEST_P(SRE_Distance, GOTURN)
+{
+  TrackerSRETest test(Tracker::create("GOTURN"), TrackerSRETest::DISTANCE, dataset, shift, threshold);
+  test.run();
+  RecordProperty("ratioSuccess", test.getRatioSucc());
+}
+
+TEST_P(SRE_Overlap, GOTURN)
+{
+  TrackerSRETest test(Tracker::create("GOTURN"), TrackerSRETest::OVERLAP, dataset, shift, threshold);
+  test.run();
+  RecordProperty("ratioSuccess", test.getRatioSucc());
+}
+
 INSTANTIATE_TEST_CASE_P( Tracking, SRE_Distance, testing::Combine( TESTSET_NAMES, SPATIAL_SHIFTS, LOCATION_ERROR_THRESHOLD ) );
 
 INSTANTIATE_TEST_CASE_P( Tracking, SRE_Overlap, testing::Combine( TESTSET_NAMES, SPATIAL_SHIFTS, OVERLAP_THRESHOLD ) );
diff --git a/contrib/modules/tracking/test/test_trackerTRE.cpp b/contrib/modules/tracking/test/test_trackerTRE.cpp
index e83b3da..d771ff1 100644
--- a/contrib/modules/tracking/test/test_trackerTRE.cpp
+++ b/contrib/modules/tracking/test/test_trackerTRE.cpp
@@ -389,7 +389,7 @@ void TrackerTRETest::checkDataTest()
   gt2.close();
 
   if( segmentIdx == ( sizeof ( SEGMENTS)/sizeof(int) ) )
-	endFrame = (int)bbs.size();
+  endFrame = (int)bbs.size();
 }
 
 void TrackerTRETest::run()
@@ -499,6 +499,20 @@ TEST_P(TRE_Overlap, TLD)
   RecordProperty( "ratioSuccess", test.getRatioSucc() );
 }
 
+TEST_P(TRE_Distance, GOTURN)
+{
+  TrackerTRETest test(Tracker::create("GOTURN"), TrackerTRETest::DISTANCE, dataset, threshold, segment);
+  test.run();
+  RecordProperty("ratioSuccess", test.getRatioSucc());
+}
+
+TEST_P(TRE_Overlap, GOTURN)
+{
+  TrackerTRETest test(Tracker::create("GOTURN"), TrackerTRETest::OVERLAP, dataset, threshold, segment);
+  test.run();
+  RecordProperty("ratioSuccess", test.getRatioSucc());
+}
+
 INSTANTIATE_TEST_CASE_P( Tracking, TRE_Distance, testing::Combine( TESTSET_NAMES, SEGMENTS, LOCATION_ERROR_THRESHOLD ) );
 
 INSTANTIATE_TEST_CASE_P( Tracking, TRE_Overlap, testing::Combine( TESTSET_NAMES, SEGMENTS, OVERLAP_THRESHOLD ) );
diff --git a/contrib/modules/tracking/tutorials/tutorial_introduction_to_tracker.markdown b/contrib/modules/tracking/tutorials/tutorial_introduction_to_tracker.markdown
index 500df0c..9e2b6eb 100644
--- a/contrib/modules/tracking/tutorials/tutorial_introduction_to_tracker.markdown
+++ b/contrib/modules/tracking/tutorials/tutorial_introduction_to_tracker.markdown
@@ -28,8 +28,8 @@ Explanation
     as shown in help. In the help, it means that the image files are numbered with 4 digits
     (e.g. the file naming will be 0001.jpg, 0002.jpg, and so on).
 
-    You can find video samples in Itseez/opencv_extra/testdata/cv/tracking
-    <https://github.com/Itseez/opencv_extra/tree/master/testdata/cv/tracking>
+    You can find video samples in opencv_extra/testdata/cv/tracking
+    <https://github.com/opencv/opencv_extra/tree/master/testdata/cv/tracking>
 
 -#  **Declares the required variables**
 
diff --git a/contrib/modules/ximgproc/README.md b/contrib/modules/ximgproc/README.md
index 70c24d3..3cf3e1b 100644
--- a/contrib/modules/ximgproc/README.md
+++ b/contrib/modules/ximgproc/README.md
@@ -1,10 +1,14 @@
 Extended Image Processing
 =========================
 
-1. Structured Forests 
-2. Domain Transform Filter
-3. Guided Filter
-4. Adaptive Manifold Filter
-5. Joint Bilateral Filter
-6. Superpixels
-7. Graph segmentation
+- Structured Forests
+- Domain Transform Filter
+- Guided Filter
+- Adaptive Manifold Filter
+- Joint Bilateral Filter
+- Superpixels
+- Graph segmentation
+- Selective search from segmentation
+- Paillou Filter
+- Fast Line Detector
+- Deriche Filter
diff --git a/contrib/modules/ximgproc/doc/pics/corridor_fld.jpg b/contrib/modules/ximgproc/doc/pics/corridor_fld.jpg
new file mode 100644
index 0000000..baff041
Binary files /dev/null and b/contrib/modules/ximgproc/doc/pics/corridor_fld.jpg differ
diff --git a/contrib/modules/ximgproc/doc/pics/slic-slico-kermit.png b/contrib/modules/ximgproc/doc/pics/superpixels_slic.png
similarity index 100%
rename from contrib/modules/ximgproc/doc/pics/slic-slico-kermit.png
rename to contrib/modules/ximgproc/doc/pics/superpixels_slic.png
diff --git a/contrib/modules/ximgproc/doc/ximgproc.bib b/contrib/modules/ximgproc/doc/ximgproc.bib
index a03cb47..08bcbc4 100644
--- a/contrib/modules/ximgproc/doc/ximgproc.bib
+++ b/contrib/modules/ximgproc/doc/ximgproc.bib
@@ -47,6 +47,15 @@
   publisher={Springer}
 }
 
+ at inproceedings{Lee14,
+  title={Outdoor place recognition in urban environments using straight lines},
+  author={Lee, Jin Han and Lee, Sehyung and Zhang, Guoxuan and Lim, Jongwoo and Chung, Wan Kyun and Suh, Il Hong},
+  booktitle={2014 IEEE International Conference on Robotics and Automation (ICRA)},
+  pages={5550--5557},
+  year={2014},
+  organization={IEEE}
+}
+
 @inproceedings{Lim2013,
   title={Sketch tokens: A learned mid-level representation for contour and object detection},
   author={Lim, Joseph J and Zitnick, C Lawrence and Doll{\'a}r, Piotr},
@@ -67,6 +76,28 @@
   publisher={Springer}
 }
 
+ at article{deriche1987using,
+  title={Using Canny's criteria to derive a recursively implemented optimal edge detector},
+  author={Deriche, Rachid},
+  journal={International journal of computer vision},
+  volume={1},
+  number={2},
+  pages={167--187},
+  year={1987},
+  publisher={Springer}
+}
+
+ at article{uijlings2013selective,
+  title={Selective search for object recognition},
+  author={Uijlings, Jasper RR and van de Sande, Koen EA and Gevers, Theo and Smeulders, Arnold WM},
+  journal={International journal of computer vision},
+  volume={104},
+  number={2},
+  pages={154--171},
+  year={2013},
+  publisher={Springer}
+}
+
 @article{Min2014,
   title={Fast global image smoothing based on weighted least squares},
   author={Min, Dongbo and Choi, Sunghwan and Lu, Jiangbo and Ham, Bumsub and Sohn, Kwanghoon and Do, Minh N},
@@ -136,3 +167,42 @@
   month = {June},
   year = {2015}
 }
+
+ at article{Cho2014,
+  title = {Bilateral Texture Filtering},
+  author = {Hojin Cho and Hyunjoon Lee and Henry Kang and Seungyong Lee},
+  journal = {ACM Transactions on Graphics},
+  year = {2014},
+  volume = {33},
+  number = {4},
+  month = {July},
+  pages = {128:1--128:8}
+}
+
+ at incollection{zhang2014rolling,
+  title={Rolling guidance filter},
+  author={Zhang, Qi and Shen, Xiaoyong and Xu, Li and Jia, Jiaya},
+  booktitle={Computer Vision--ECCV 2014},
+  pages={815--830},
+  year={2014},
+  publisher={Springer}
+}
+
+ at inproceedings{zhang2014100+,
+  title={100+ times faster weighted median filter (WMF)},
+  author={Zhang, Qi and Xu, Li and Jia, Jiaya},
+  booktitle={Computer Vision and Pattern Recognition (CVPR), 2014 IEEE Conference on},
+  pages={2830--2837},
+  year={2014},
+  organization={IEEE}
+}
+
+ at article{paillou1997detecting,
+  title={Detecting step edges in noisy SAR images: a new linear operator},
+  author={Paillou, Philippe},
+  journal={IEEE transactions on geoscience and remote sensing},
+  volume={35},
+  number={1},
+  pages={191--196},
+  year={1997}
+}
diff --git a/contrib/modules/ximgproc/include/opencv2/ximgproc.hpp b/contrib/modules/ximgproc/include/opencv2/ximgproc.hpp
index c96a257..7616a40 100644
--- a/contrib/modules/ximgproc/include/opencv2/ximgproc.hpp
+++ b/contrib/modules/ximgproc/include/opencv2/ximgproc.hpp
@@ -2,26 +2,26 @@
  *  By downloading, copying, installing or using the software you agree to this license.
  *  If you do not agree to this license, do not download, install,
  *  copy or use the software.
- *  
- *  
+ *
+ *
  *  License Agreement
  *  For Open Source Computer Vision Library
  *  (3 - clause BSD License)
- *  
+ *
  *  Redistribution and use in source and binary forms, with or without modification,
  *  are permitted provided that the following conditions are met :
- *  
- *  *Redistributions of source code must retain the above copyright notice,
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
  *  this list of conditions and the following disclaimer.
- *  
+ *
  *  * Redistributions in binary form must reproduce the above copyright notice,
  *  this list of conditions and the following disclaimer in the documentation
  *  and / or other materials provided with the distribution.
- *  
+ *
  *  * Neither the names of the copyright holders nor the names of the contributors
  *  may be used to endorse or promote products derived from this software
  *  without specific prior written permission.
- *  
+ *
  *  This software is provided by the copyright holders and contributors "as is" and
  *  any express or implied warranties, including, but not limited to, the implied
  *  warranties of merchantability and fitness for a particular purpose are disclaimed.
@@ -45,31 +45,87 @@
 #include "ximgproc/segmentation.hpp"
 #include "ximgproc/fast_hough_transform.hpp"
 #include "ximgproc/estimated_covariance.hpp"
+#include "ximgproc/weighted_median_filter.hpp"
 #include "ximgproc/slic.hpp"
 #include "ximgproc/lsc.hpp"
+#include "ximgproc/paillou_filter.hpp"
+#include "ximgproc/fast_line_detector.hpp"
+#include "ximgproc/deriche_filter.hpp"
 
 /** @defgroup ximgproc Extended Image Processing
   @{
     @defgroup ximgproc_edge Structured forests for fast edge detection
 
-This module contains implementations of modern structured edge detection algorithms, i.e. algorithms
-which somehow takes into account pixel affinities in natural images.
+This module contains implementations of modern structured edge detection algorithms,
+i.e. algorithms which somehow takes into account pixel affinities in natural images.
 
     @defgroup ximgproc_filters Filters
 
     @defgroup ximgproc_superpixel Superpixels
 
     @defgroup ximgproc_segmentation Image segmentation
+
+    @defgroup ximgproc_fast_line_detector Fast line detector
   @}
 */
 
-namespace cv {
-namespace ximgproc {
-    CV_EXPORTS_W
-    void niBlackThreshold( InputArray _src, OutputArray _dst, double maxValue,
-            int type, int blockSize, double delta );
+namespace cv
+{
+namespace ximgproc
+{
+
+enum ThinningTypes{
+    THINNING_ZHANGSUEN    = 0, // Thinning technique of Zhang-Suen
+    THINNING_GUOHALL      = 1  // Thinning technique of Guo-Hall
+};
+
+//! @addtogroup ximgproc
+//! @{
+
+/** @brief Applies Niblack thresholding to input image.
+
+The function transforms a grayscale image to a binary image according to the formulae:
+-   **THRESH_BINARY**
+    \f[dst(x,y) =  \fork{\texttt{maxValue}}{if \(src(x,y) > T(x,y)\)}{0}{otherwise}\f]
+-   **THRESH_BINARY_INV**
+    \f[dst(x,y) =  \fork{0}{if \(src(x,y) > T(x,y)\)}{\texttt{maxValue}}{otherwise}\f]
+where \f$T(x,y)\f$ is a threshold calculated individually for each pixel.
+
+The threshold value \f$T(x, y)\f$ is the mean minus \f$ delta \f$ times standard deviation
+of \f$\texttt{blockSize} \times\texttt{blockSize}\f$ neighborhood of \f$(x, y)\f$.
+
+The function can't process the image in-place.
+
+ at param _src Source 8-bit single-channel image.
+ at param _dst Destination image of the same size and the same type as src.
+ at param maxValue Non-zero value assigned to the pixels for which the condition is satisfied,
+used with the THRESH_BINARY and THRESH_BINARY_INV thresholding types.
+ at param type Thresholding type, see cv::ThresholdTypes.
+ at param blockSize Size of a pixel neighborhood that is used to calculate a threshold value
+for the pixel: 3, 5, 7, and so on.
+ at param delta Constant multiplied with the standard deviation and subtracted from the mean.
+Normally, it is taken to be a real number between 0 and 1.
+
+ at sa  threshold, adaptiveThreshold
+ */
+CV_EXPORTS_W void niBlackThreshold( InputArray _src, OutputArray _dst,
+                                    double maxValue, int type,
+                                    int blockSize, double delta );
+
+/** @brief Applies a binary blob thinning operation, to achieve a skeletization of the input image.
+
+The function transforms a binary blob image into a skeletized form using the technique of Zhang-Suen.
+
+ at param src Source 8-bit single-channel image, containing binary blobs, with blobs having 255 pixel values.
+ at param dst Destination image of the same size and the same type as src. The function can work in-place.
+ at param thinningType Value that defines which thinning algorithm should be used. See cv::ThinningTypes
+ */
+CV_EXPORTS_W void thinning( InputArray src, OutputArray dst, int thinningType = THINNING_ZHANGSUEN);
+
+
+//! @}
 
-} // namespace ximgproc
-} //namespace cv
+}
+}
 
-#endif
+#endif // __OPENCV_XIMGPROC_HPP__
diff --git a/contrib/modules/ximgproc/include/opencv2/ximgproc/deriche_filter.hpp b/contrib/modules/ximgproc/include/opencv2/ximgproc/deriche_filter.hpp
new file mode 100644
index 0000000..2371feb
--- /dev/null
+++ b/contrib/modules/ximgproc/include/opencv2/ximgproc/deriche_filter.hpp
@@ -0,0 +1,77 @@
+/*
+ *  By downloading, copying, installing or using the software you agree to this license.
+ *  If you do not agree to this license, do not download, install,
+ *  copy or use the software.
+ *
+ *
+ *  License Agreement
+ *  For Open Source Computer Vision Library
+ *  (3 - clause BSD License)
+ *
+ *  Redistribution and use in source and binary forms, with or without modification,
+ *  are permitted provided that the following conditions are met :
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *  this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *  this list of conditions and the following disclaimer in the documentation
+ *  and / or other materials provided with the distribution.
+ *
+ *  * Neither the names of the copyright holders nor the names of the contributors
+ *  may be used to endorse or promote products derived from this software
+ *  without specific prior written permission.
+ *
+ *  This software is provided by the copyright holders and contributors "as is" and
+ *  any express or implied warranties, including, but not limited to, the implied
+ *  warranties of merchantability and fitness for a particular purpose are disclaimed.
+ *  In no event shall copyright holders or contributors be liable for any direct,
+ *  indirect, incidental, special, exemplary, or consequential damages
+ *  (including, but not limited to, procurement of substitute goods or services;
+ *  loss of use, data, or profits; or business interruption) however caused
+ *  and on any theory of liability, whether in contract, strict liability,
+ *  or tort(including negligence or otherwise) arising in any way out of
+ *  the use of this software, even if advised of the possibility of such damage.
+ */
+
+#ifndef __OPENCV_DERICHEFILTER_HPP__
+#define __OPENCV_DERICHEFILTER_HPP__
+#ifdef __cplusplus
+
+#include <opencv2/core.hpp>
+
+namespace cv {
+namespace ximgproc {
+
+//! @addtogroup ximgproc_filters
+//! @{
+
+/**
+* @brief   Applies Y Deriche filter to an image.
+*
+* For more details about this implementation, please see http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.476.5736&rep=rep1&type=pdf
+*
+* @param   _op         Source 8-bit or 16bit image, 1-channel or 3-channel image.
+* @param   _dst        result CV_32FC image with same number of channel than _op.
+* @param   alphaDerive double see paper
+* @param   alphaMean   double see paper
+*
+*/
+CV_EXPORTS void GradientDericheY(InputArray _op, OutputArray _dst, double alphaDerive,double alphaMean);
+/**
+* @brief   Applies X Deriche filter to an image.
+*
+* For more details about this implementation, please see http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.476.5736&rep=rep1&type=pdf
+*
+* @param   _op         Source 8-bit or 16bit image, 1-channel or 3-channel image.
+* @param   _dst        result CV_32FC image with same number of channel than _op.
+* @param   alphaDerive double see paper
+* @param   alphaMean   double see paper
+*
+*/
+CV_EXPORTS void GradientDericheX(InputArray _op, OutputArray _dst, double alphaDerive,double alphaMean);
+
+}
+}
+#endif
+#endif
diff --git a/contrib/modules/ximgproc/include/opencv2/ximgproc/disparity_filter.hpp b/contrib/modules/ximgproc/include/opencv2/ximgproc/disparity_filter.hpp
index 07bcf6d..b738436 100644
--- a/contrib/modules/ximgproc/include/opencv2/ximgproc/disparity_filter.hpp
+++ b/contrib/modules/ximgproc/include/opencv2/ximgproc/disparity_filter.hpp
@@ -11,7 +11,7 @@
  *  Redistribution and use in source and binary forms, with or without modification,
  *  are permitted provided that the following conditions are met :
  *
- *  *Redistributions of source code must retain the above copyright notice,
+ *  * Redistributions of source code must retain the above copyright notice,
  *  this list of conditions and the following disclaimer.
  *
  *  * Redistributions in binary form must reproduce the above copyright notice,
diff --git a/contrib/modules/ximgproc/include/opencv2/ximgproc/edge_filter.hpp b/contrib/modules/ximgproc/include/opencv2/ximgproc/edge_filter.hpp
index f87138a..65cff9e 100644
--- a/contrib/modules/ximgproc/include/opencv2/ximgproc/edge_filter.hpp
+++ b/contrib/modules/ximgproc/include/opencv2/ximgproc/edge_filter.hpp
@@ -11,7 +11,7 @@
  *  Redistribution and use in source and binary forms, with or without modification,
  *  are permitted provided that the following conditions are met :
  *
- *  *Redistributions of source code must retain the above copyright notice,
+ *  * Redistributions of source code must retain the above copyright notice,
  *  this list of conditions and the following disclaimer.
  *
  *  * Redistributions in binary form must reproduce the above copyright notice,
@@ -316,11 +316,35 @@ proportional to sigmaSpace .
 CV_EXPORTS_W
 void jointBilateralFilter(InputArray joint, InputArray src, OutputArray dst, int d, double sigmaColor, double sigmaSpace, int borderType = BORDER_DEFAULT);
 
+/** @brief Applies the bilateral texture filter to an image. It performs structure-preserving texture filter.
+For more details about this filter see @cite Cho2014.
+
+ at param src Source image whose depth is 8-bit UINT or 32-bit FLOAT
+
+ at param dst Destination image of the same size and type as src.
+
+ at param fr Radius of kernel to be used for filtering. It should be positive integer
+
+ at param numIter Number of iterations of algorithm, It should be positive integer
+
+ at param sigmaAlpha Controls the sharpness of the weight transition from edges to smooth/texture regions, where
+a bigger value means sharper transition. When the value is negative, it is automatically calculated.
+
+ at param sigmaAvg Range blur parameter for texture blurring. Larger value makes result to be more blurred. When the
+value is negative, it is automatically calculated as described in the paper.
+
+ at sa rollingGuidanceFilter, bilateralFilter
+*/
+CV_EXPORTS_W
+void bilateralTextureFilter(InputArray src, OutputArray dst, int fr = 3, int numIter = 1, double sigmaAlpha = -1., double sigmaAvg = -1.);
+
 //////////////////////////////////////////////////////////////////////////
 //////////////////////////////////////////////////////////////////////////
 
 /** @brief Applies the rolling guidance filter to an image.
 
+For more details, please see @cite zhang2014rolling
+
 @param src Source 8-bit or floating-point, 1-channel or 3-channel image.
 
 @param dst Destination image of the same size and type as src.
diff --git a/contrib/modules/ximgproc/include/opencv2/ximgproc/fast_line_detector.hpp b/contrib/modules/ximgproc/include/opencv2/ximgproc/fast_line_detector.hpp
new file mode 100644
index 0000000..1df5558
--- /dev/null
+++ b/contrib/modules/ximgproc/include/opencv2/ximgproc/fast_line_detector.hpp
@@ -0,0 +1,81 @@
+// This file is part of OpenCV project.
+// It is subject to the license terms in the LICENSE file found in the top-level directory
+// of this distribution and at http://opencv.org/license.html.
+
+#ifndef __OPENCV_FAST_LINE_DETECTOR_HPP__
+#define __OPENCV_FAST_LINE_DETECTOR_HPP__
+
+#include <opencv2/core.hpp>
+
+namespace cv
+{
+namespace ximgproc
+{
+
+//! @addtogroup ximgproc_fast_line_detector
+//! @{
+
+/** @brief Class implementing the FLD (Fast Line Detector) algorithm described
+in @cite Lee14 .
+*/
+
+//! @include samples/fld_lines.cpp
+
+class CV_EXPORTS_W FastLineDetector : public Algorithm
+{
+public:
+    /** @example fld_lines.cpp
+      An example using the FastLineDetector
+      */
+    /** @brief Finds lines in the input image.
+      This is the output of the default parameters of the algorithm on the above
+      shown image.
+
+      ![image](pics/corridor_fld.jpg)
+
+      @param _image A grayscale (CV_8UC1) input image. If only a roi needs to be
+      selected, use: `fld_ptr-\>detect(image(roi), lines, ...);
+      lines += Scalar(roi.x, roi.y, roi.x, roi.y);`
+      @param _lines A vector of Vec4f elements specifying the beginning
+      and ending point of a line.  Where Vec4f is (x1, y1, x2, y2), point
+      1 is the start, point 2 - end. Returned lines are directed so that the
+      brighter side is on their left.
+      */
+    CV_WRAP virtual void detect(InputArray _image, OutputArray _lines) = 0;
+
+    /** @brief Draws the line segments on a given image.
+      @param _image The image, where the lines will be drawn. Should be bigger
+      or equal to the image, where the lines were found.
+      @param lines A vector of the lines that needed to be drawn.
+      @param draw_arrow If true, arrow heads will be drawn.
+    */
+    CV_WRAP virtual void drawSegments(InputOutputArray _image, InputArray lines,
+            bool draw_arrow = false) = 0;
+
+    virtual ~FastLineDetector() { }
+};
+
+/** @brief Creates a smart pointer to a FastLineDetector object and initializes it
+
+ at param _length_threshold    10         - Segment shorter than this will be discarded
+ at param _distance_threshold  1.41421356 - A point placed from a hypothesis line
+                                         segment farther than this will be
+                                         regarded as an outlier
+ at param _canny_th1           50         - First threshold for
+                                         hysteresis procedure in Canny()
+ at param _canny_th2           50         - Second threshold for
+                                         hysteresis procedure in Canny()
+ at param _canny_aperture_size 3          - Aperturesize for the sobel
+                                         operator in Canny()
+ at param _do_merge            false      - If true, incremental merging of segments
+                                         will be perfomred
+*/
+CV_EXPORTS_W Ptr<FastLineDetector> createFastLineDetector(
+        int _length_threshold = 10, float _distance_threshold = 1.414213562f,
+        double _canny_th1 = 50.0, double _canny_th2 = 50.0, int _canny_aperture_size = 3,
+        bool _do_merge = false);
+
+//! @} ximgproc_fast_line_detector
+}
+}
+#endif
diff --git a/contrib/modules/ximgproc/include/opencv2/ximgproc/paillou_filter.hpp b/contrib/modules/ximgproc/include/opencv2/ximgproc/paillou_filter.hpp
new file mode 100644
index 0000000..f7feee3
--- /dev/null
+++ b/contrib/modules/ximgproc/include/opencv2/ximgproc/paillou_filter.hpp
@@ -0,0 +1,67 @@
+/*
+ *  By downloading, copying, installing or using the software you agree to this license.
+ *  If you do not agree to this license, do not download, install,
+ *  copy or use the software.
+ *
+ *
+ *  License Agreement
+ *  For Open Source Computer Vision Library
+ *  (3 - clause BSD License)
+ *
+ *  Redistribution and use in source and binary forms, with or without modification,
+ *  are permitted provided that the following conditions are met :
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *  this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *  this list of conditions and the following disclaimer in the documentation
+ *  and / or other materials provided with the distribution.
+ *
+ *  * Neither the names of the copyright holders nor the names of the contributors
+ *  may be used to endorse or promote products derived from this software
+ *  without specific prior written permission.
+ *
+ *  This software is provided by the copyright holders and contributors "as is" and
+ *  any express or implied warranties, including, but not limited to, the implied
+ *  warranties of merchantability and fitness for a particular purpose are disclaimed.
+ *  In no event shall copyright holders or contributors be liable for any direct,
+ *  indirect, incidental, special, exemplary, or consequential damages
+ *  (including, but not limited to, procurement of substitute goods or services;
+ *  loss of use, data, or profits; or business interruption) however caused
+ *  and on any theory of liability, whether in contract, strict liability,
+ *  or tort(including negligence or otherwise) arising in any way out of
+ *  the use of this software, even if advised of the possibility of such damage.
+ */
+
+#ifndef __OPENCV_PAILLOUFILTER_HPP__
+#define __OPENCV_PAILLOUFILTER_HPP__
+#ifdef __cplusplus
+
+#include <opencv2/core.hpp>
+
+namespace cv {
+namespace ximgproc {
+
+//! @addtogroup ximgproc_filters
+//! @{
+
+/**
+* @brief   Applies Paillou filter to an image.
+*
+* For more details about this implementation, please see @cite paillou1997detecting
+*
+* @param   op          Source 8-bit or 16bit image, 1-channel or 3-channel image.
+* @param   _dst        result CV_32F image with same numeber of channel than op.
+* @param   omega double see paper
+* @param   alpha double see paper
+*
+* @sa GradientPaillouX, GradientPaillouY
+*/
+CV_EXPORTS void GradientPaillouY(InputArray op, OutputArray _dst, double alpha, double omega);
+CV_EXPORTS void GradientPaillouX(InputArray op, OutputArray _dst, double alpha, double omega);
+
+}
+}
+#endif
+#endif
diff --git a/contrib/modules/ximgproc/include/opencv2/ximgproc/segmentation.hpp b/contrib/modules/ximgproc/include/opencv2/ximgproc/segmentation.hpp
index 990fc64..02d28bf 100644
--- a/contrib/modules/ximgproc/include/opencv2/ximgproc/segmentation.hpp
+++ b/contrib/modules/ximgproc/include/opencv2/ximgproc/segmentation.hpp
@@ -67,55 +67,183 @@ namespace cv {
                         @param min_size The minimum size of segments
                      */
                     CV_EXPORTS_W Ptr<GraphSegmentation> createGraphSegmentation(double sigma=0.5, float k=300, int min_size=100);
-            //! @}
 
-            // Represent an edge between two pixels
-            class Edge {
-                public:
-                    int from;
-                    int to;
-                    float weight;
+                    /** @brief Strategie for the selective search segmentation algorithm
+                        The class implements a generic stragery for the algorithm described in @cite uijlings2013selective.
+                     */
+                    class CV_EXPORTS_W SelectiveSearchSegmentationStrategy : public Algorithm {
+                        public:
+                            /** @brief Set a initial image, with a segementation.
+                                @param img The input image. Any number of channel can be provided
+                                @param regions A segementation of the image. The parameter must be the same size of img.
+                                @param sizes The sizes of different regions
+                                @param image_id If not set to -1, try to cache pre-computations. If the same set og (img, regions, size) is used, the image_id need to be the same.
+                            */
+                            CV_WRAP virtual void setImage(InputArray img, InputArray regions, InputArray sizes, int image_id = -1) = 0;
 
-                    bool operator <(const Edge& e) const {
-                        return weight < e.weight;
-                    }
-            };
+                            /** @brief Return the score between two regions (between 0 and 1)
+                                @param r1 The first region
+                                @param r2 The second region
+                            */
+                            CV_WRAP virtual float get(int r1, int r2) = 0;
 
-            // A point in the sets of points
-            class PointSetElement {
-                public:
-                    int p;
-                    int size;
+                            /** @brief Inform the strategy that two regions will be merged
+                                @param r1 The first region
+                                @param r2 The second region
+                            */
+                            CV_WRAP virtual void merge(int r1, int r2) = 0;
+                    };
+
+                    /** @brief Color-based strategy for the selective search segmentation algorithm
+                        The class is implemented from the algorithm described in @cite uijlings2013selective.
+                     */
+                    class CV_EXPORTS_W SelectiveSearchSegmentationStrategyColor : public SelectiveSearchSegmentationStrategy {
+                    };
+
+                    /** @brief Create a new color-based strategy */
+                    CV_EXPORTS_W Ptr<SelectiveSearchSegmentationStrategyColor> createSelectiveSearchSegmentationStrategyColor();
+
+                    /** @brief Size-based strategy for the selective search segmentation algorithm
+                        The class is implemented from the algorithm described in @cite uijlings2013selective.
+                     */
+                    class CV_EXPORTS_W SelectiveSearchSegmentationStrategySize : public SelectiveSearchSegmentationStrategy {
+                    };
 
-                    PointSetElement() { }
+                    /** @brief Create a new size-based strategy */
+                    CV_EXPORTS_W Ptr<SelectiveSearchSegmentationStrategySize> createSelectiveSearchSegmentationStrategySize();
 
-                    PointSetElement(int p_) {
-                        p = p_;
-                        size = 1;
-                    }
-            };
+                    /** @brief Texture-based strategy for the selective search segmentation algorithm
+                        The class is implemented from the algorithm described in @cite uijlings2013selective.
+                     */
+                    class CV_EXPORTS_W SelectiveSearchSegmentationStrategyTexture : public SelectiveSearchSegmentationStrategy {
+                    };
 
-            // An object to manage set of points, who can be fusionned
-            class PointSet {
-                public:
-                    PointSet(int nb_elements_);
-                    ~PointSet();
+                    /** @brief Create a new size-based strategy */
+                    CV_EXPORTS_W Ptr<SelectiveSearchSegmentationStrategyTexture> createSelectiveSearchSegmentationStrategyTexture();
 
-                    int nb_elements;
+                    /** @brief Fill-based strategy for the selective search segmentation algorithm
+                        The class is implemented from the algorithm described in @cite uijlings2013selective.
+                     */
+                    class CV_EXPORTS_W SelectiveSearchSegmentationStrategyFill : public SelectiveSearchSegmentationStrategy {
+                    };
 
-                    // Return the main point of the point's set
-                    int getBasePoint(int p);
+                    /** @brief Create a new fill-based strategy */
+                    CV_EXPORTS_W Ptr<SelectiveSearchSegmentationStrategyFill> createSelectiveSearchSegmentationStrategyFill();
 
-                    // Join two sets of points, based on their main point
-                    void joinPoints(int p_a, int p_b);
+                    /** @brief Regroup multiple strategies for the selective search segmentation algorithm
+                     */
+                    class CV_EXPORTS_W SelectiveSearchSegmentationStrategyMultiple : public SelectiveSearchSegmentationStrategy {
+                        public:
 
-                    // Return the set size of a set (based on the main point)
-                    int size(unsigned int p) { return mapping[p].size; }
+                            /** @brief Add a new sub-strategy
+                                @param g The strategy
+                                @param weight The weight of the strategy
+                            */
+                            CV_WRAP virtual void addStrategy(Ptr<SelectiveSearchSegmentationStrategy> g, float weight) = 0;
+                            /** @brief Remove all sub-strategies
+                            */
+                            CV_WRAP virtual void clearStrategies() = 0;
+                    };
 
-                private:
-                    PointSetElement* mapping;
+                    /** @brief Create a new multiple strategy */
+                    CV_EXPORTS_W Ptr<SelectiveSearchSegmentationStrategyMultiple> createSelectiveSearchSegmentationStrategyMultiple();
+
+                    /** @brief Create a new multiple strategy and set one subtrategy
+                        @param s1 The first strategy
+                    */
+                    CV_EXPORTS_W Ptr<SelectiveSearchSegmentationStrategyMultiple> createSelectiveSearchSegmentationStrategyMultiple(Ptr<SelectiveSearchSegmentationStrategy> s1);
+
+                    /** @brief Create a new multiple strategy and set two subtrategies, with equal weights
+                        @param s1 The first strategy
+                        @param s2 The second strategy
+                    */
+                    CV_EXPORTS_W Ptr<SelectiveSearchSegmentationStrategyMultiple> createSelectiveSearchSegmentationStrategyMultiple(Ptr<SelectiveSearchSegmentationStrategy> s1, Ptr<SelectiveSearchSegmentationStrategy> s2);
+
+
+                    /** @brief Create a new multiple strategy and set three subtrategies, with equal weights
+                        @param s1 The first strategy
+                        @param s2 The second strategy
+                        @param s3 The third strategy
+                    */
+                    CV_EXPORTS_W Ptr<SelectiveSearchSegmentationStrategyMultiple> createSelectiveSearchSegmentationStrategyMultiple(Ptr<SelectiveSearchSegmentationStrategy> s1, Ptr<SelectiveSearchSegmentationStrategy> s2, Ptr<SelectiveSearchSegmentationStrategy> s3);
+
+                    /** @brief Create a new multiple strategy and set four subtrategies, with equal weights
+                        @param s1 The first strategy
+                        @param s2 The second strategy
+                        @param s3 The third strategy
+                        @param s4 The forth strategy
+                    */
+                    CV_EXPORTS_W Ptr<SelectiveSearchSegmentationStrategyMultiple> createSelectiveSearchSegmentationStrategyMultiple(Ptr<SelectiveSearchSegmentationStrategy> s1, Ptr<SelectiveSearchSegmentationStrategy> s2, Ptr<SelectiveSearchSegmentationStrategy> s3, Ptr<SelectiveSearchSegmentationStrategy> s4);
+
+                    /** @brief Selective search segmentation algorithm
+                        The class implements the algorithm described in @cite uijlings2013selective.
+                     */
+                    class CV_EXPORTS_W SelectiveSearchSegmentation : public Algorithm {
+                        public:
 
-            };
+                            /** @brief Set a image used by switch* functions to initialize the class
+                                @param img The image
+                            */
+                            CV_WRAP virtual void setBaseImage(InputArray img) = 0;
+
+                            /** @brief Initialize the class with the 'Single stragegy' parameters describled in @cite uijlings2013selective.
+                                @param k The k parameter for the graph segmentation
+                                @param sigma The sigma parameter for the graph segmentation
+                            */
+                            CV_WRAP virtual void switchToSingleStrategy(int k = 200, float sigma = 0.8f) = 0;
+
+                            /** @brief Initialize the class with the 'Selective search fast' parameters describled in @cite uijlings2013selective.
+                                @param base_k The k parameter for the first graph segmentation
+                                @param inc_k The increment of the k parameter for all graph segmentations
+                                @param sigma The sigma parameter for the graph segmentation
+                            */
+                            CV_WRAP virtual void switchToSelectiveSearchFast(int base_k = 150, int inc_k = 150, float sigma = 0.8f) = 0;
+
+                            /** @brief Initialize the class with the 'Selective search fast' parameters describled in @cite uijlings2013selective.
+                                @param base_k The k parameter for the first graph segmentation
+                                @param inc_k The increment of the k parameter for all graph segmentations
+                                @param sigma The sigma parameter for the graph segmentation
+                            */
+                            CV_WRAP virtual void switchToSelectiveSearchQuality(int base_k = 150, int inc_k = 150, float sigma = 0.8f) = 0;
+
+                            /** @brief Add a new image in the list of images to process.
+                                @param img The image
+                            */
+                            CV_WRAP virtual void addImage(InputArray img) = 0;
+
+                            /** @brief Clear the list of images to process
+                            */
+                            CV_WRAP virtual void clearImages() = 0;
+
+                            /** @brief Add a new graph segmentation in the list of graph segementations to process.
+                                @param g The graph segmentation
+                            */
+                            CV_WRAP virtual void addGraphSegmentation(Ptr<GraphSegmentation> g) = 0;
+
+                            /** @brief Clear the list of graph segmentations to process;
+                            */
+                            CV_WRAP virtual void clearGraphSegmentations() = 0;
+
+                            /** @brief Add a new strategy in the list of strategy to process.
+                                @param s The strategy
+                            */
+                            CV_WRAP virtual void addStrategy(Ptr<SelectiveSearchSegmentationStrategy> s) = 0;
+
+                            /** @brief Clear the list of strategy to process;
+                            */
+                            CV_WRAP virtual void clearStrategies() = 0;
+
+                            /** @brief Based on all images, graph segmentations and stragies, computes all possible rects and return them
+                                @param rects The list of rects. The first ones are more relevents than the lasts ones.
+                            */
+                            CV_WRAP virtual void process(std::vector<Rect>& rects) = 0;
+                    };
+
+                    /** @brief Create a new SelectiveSearchSegmentation class.
+                     */
+                    CV_EXPORTS_W Ptr<SelectiveSearchSegmentation> createSelectiveSearchSegmentation();
+
+            //! @}
 
         }
     }
diff --git a/contrib/modules/ximgproc/include/opencv2/ximgproc/slic.hpp b/contrib/modules/ximgproc/include/opencv2/ximgproc/slic.hpp
index 4d9eb9a..64fc45c 100644
--- a/contrib/modules/ximgproc/include/opencv2/ximgproc/slic.hpp
+++ b/contrib/modules/ximgproc/include/opencv2/ximgproc/slic.hpp
@@ -148,7 +148,7 @@ superpixel algorithm, which are: region_size and ruler. It preallocate some buff
 computing iterations over the given image. An example of SLIC versus SLICO is ilustrated in the
 following picture.
 
-![image](pics/slic_slico_kermit.png)
+![image](pics/superpixels_slic.png)
 
  */
 
diff --git a/contrib/modules/ximgproc/include/opencv2/ximgproc/sparse_match_interpolator.hpp b/contrib/modules/ximgproc/include/opencv2/ximgproc/sparse_match_interpolator.hpp
index 4821aba..fffcfd6 100644
--- a/contrib/modules/ximgproc/include/opencv2/ximgproc/sparse_match_interpolator.hpp
+++ b/contrib/modules/ximgproc/include/opencv2/ximgproc/sparse_match_interpolator.hpp
@@ -11,7 +11,7 @@
  *  Redistribution and use in source and binary forms, with or without modification,
  *  are permitted provided that the following conditions are met :
  *
- *  *Redistributions of source code must retain the above copyright notice,
+ *  * Redistributions of source code must retain the above copyright notice,
  *  this list of conditions and the following disclaimer.
  *
  *  * Redistributions in binary form must reproduce the above copyright notice,
diff --git a/contrib/modules/ximgproc/include/opencv2/ximgproc/weighted_median_filter.hpp b/contrib/modules/ximgproc/include/opencv2/ximgproc/weighted_median_filter.hpp
new file mode 100644
index 0000000..30a169c
--- /dev/null
+++ b/contrib/modules/ximgproc/include/opencv2/ximgproc/weighted_median_filter.hpp
@@ -0,0 +1,95 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+//  By downloading, copying, installing or using the software you agree to this license.
+//  If you do not agree to this license, do not download, install,
+//  copy or use the software.
+//
+//
+//                           License Agreement
+//                For Open Source Computer Vision Library
+//
+// Copyright (C) 2015, The Chinese University of Hong Kong, all rights reserved.
+//
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+//   * Redistribution's of source code must retain the above copyright notice,
+//     this list of conditions and the following disclaimer.
+//
+//   * Redistribution's in binary form must reproduce the above copyright notice,
+//     this list of conditions and the following disclaimer in the documentation
+//     and/or other materials provided with the distribution.
+//
+//   * The name of the copyright holders may not be used to endorse or promote products
+//     derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#ifndef  __OPENCV_WEIGHTED_MEDIAN_FILTER_HPP__
+#define  __OPENCV_WEIGHTED_MEDIAN_FILTER_HPP__
+#ifdef __cplusplus
+
+/**
+* @file
+* @date Sept 9, 2015
+* @author Zhou Chao
+*/
+
+#include <opencv2/core.hpp>
+#include <string>
+
+namespace cv
+{
+namespace ximgproc
+{
+
+/**
+* @brief Specifies weight types of weighted median filter.
+*/
+enum WMFWeightType
+{
+    WMF_EXP, //!< \f$exp(-|I1-I2|^2/(2*sigma^2))\f$
+    WMF_IV1, //!< \f$(|I1-I2|+sigma)^-1\f$
+    WMF_IV2, //!< \f$(|I1-I2|^2+sigma^2)^-1\f$
+    WMF_COS, //!< \f$dot(I1,I2)/(|I1|*|I2|)\f$
+    WMF_JAC, //!< \f$(min(r1,r2)+min(g1,g2)+min(b1,b2))/(max(r1,r2)+max(g1,g2)+max(b1,b2))\f$
+    WMF_OFF //!< unweighted
+};
+
+/**
+* @brief   Applies weighted median filter to an image.
+*
+* For more details about this implementation, please see @cite zhang2014100+
+*
+* @param   joint       Joint 8-bit, 1-channel or 3-channel image.
+* @param   src         Source 8-bit or floating-point, 1-channel or 3-channel image.
+* @param   dst         Destination image.
+* @param   r           Radius of filtering kernel, should be a positive integer.
+* @param   sigma       Filter range standard deviation for the joint image.
+* @param   weightType  weightType The type of weight definition, see WMFWeightType
+* @param   mask        A 0-1 mask that has the same size with I. This mask is used to ignore the effect of some pixels. If the pixel value on mask is 0,
+*                           the pixel will be ignored when maintaining the joint-histogram. This is useful for applications like optical flow occlusion handling.
+*
+* @sa medianBlur, jointBilateralFilter
+*/
+CV_EXPORTS void weightedMedianFilter(InputArray joint, InputArray src, OutputArray dst, int r, double sigma=25.5, WMFWeightType weightType=WMF_EXP, Mat mask=Mat());
+}
+}
+
+#endif
+#endif
diff --git a/contrib/modules/ximgproc/perf/perf_adaptive_manifold.cpp b/contrib/modules/ximgproc/perf/perf_adaptive_manifold.cpp
index a0a5df1..5702fab 100644
--- a/contrib/modules/ximgproc/perf/perf_adaptive_manifold.cpp
+++ b/contrib/modules/ximgproc/perf/perf_adaptive_manifold.cpp
@@ -11,7 +11,7 @@
  *  Redistribution and use in source and binary forms, with or without modification,
  *  are permitted provided that the following conditions are met :
  *
- *  *Redistributions of source code must retain the above copyright notice,
+ *  * Redistributions of source code must retain the above copyright notice,
  *  this list of conditions and the following disclaimer.
  *
  *  * Redistributions in binary form must reproduce the above copyright notice,
diff --git a/contrib/modules/ximgproc/perf/perf_bilateral_texture_filter.cpp b/contrib/modules/ximgproc/perf/perf_bilateral_texture_filter.cpp
new file mode 100644
index 0000000..f49e4e5
--- /dev/null
+++ b/contrib/modules/ximgproc/perf/perf_bilateral_texture_filter.cpp
@@ -0,0 +1,83 @@
+/*
+ *  By downloading, copying, installing or using the software you agree to this license.
+ *  If you do not agree to this license, do not download, install,
+ *  copy or use the software.
+ *
+ *
+ *  License Agreement
+ *  For Open Source Computer Vision Library
+ *  (3 - clause BSD License)
+ *
+ *  Redistribution and use in source and binary forms, with or without modification,
+ *  are permitted provided that the following conditions are met :
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *  this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *  this list of conditions and the following disclaimer in the documentation
+ *  and / or other materials provided with the distribution.
+ *
+ *  * Neither the names of the copyright holders nor the names of the contributors
+ *  may be used to endorse or promote products derived from this software
+ *  without specific prior written permission.
+ *
+ *  This software is provided by the copyright holders and contributors "as is" and
+ *  any express or implied warranties, including, but not limited to, the implied
+ *  warranties of merchantability and fitness for a particular purpose are disclaimed.
+ *  In no event shall copyright holders or contributors be liable for any direct,
+ *  indirect, incidental, special, exemplary, or consequential damages
+ *  (including, but not limited to, procurement of substitute goods or services;
+ *  loss of use, data, or profits; or business interruption) however caused
+ *  and on any theory of liability, whether in contract, strict liability,
+ *  or tort(including negligence or otherwise) arising in any way out of
+ *  the use of this software, even if advised of the possibility of such damage.
+ */
+
+#include "perf_precomp.hpp"
+
+namespace cvtest
+{
+
+using std::tr1::tuple;
+using std::tr1::get;
+using namespace perf;
+using namespace testing;
+using namespace cv;
+using namespace cv::ximgproc;
+
+typedef tuple<int, double, double, Size, MatType, int> BTFTestParam;
+typedef TestBaseWithParam<BTFTestParam> BilateralTextureFilterTest;
+
+PERF_TEST_P(BilateralTextureFilterTest, perf,
+    Combine(
+    Values(2),
+    Values(0.5),
+    Values(0.5),
+    SZ_TYPICAL,
+    Values(CV_8U, CV_32F),
+    Values(1, 3))
+)
+{
+    BTFTestParam params = GetParam();
+    int fr            = get<0>(params);
+    double sigmaAlpha = get<1>(params);
+    double sigmaAvg   = get<2>(params);
+    Size sz           = get<3>(params);
+    int depth         = get<4>(params);
+    int srcCn         = get<5>(params);
+
+    Mat src(sz, CV_MAKE_TYPE(depth,srcCn));
+    Mat dst(sz, src.type());
+
+    cv::setNumThreads(cv::getNumberOfCPUs());
+    declare.in(src, WARMUP_RNG).out(dst).tbb_threads(cv::getNumberOfCPUs());
+
+    TEST_CYCLE_N(1)
+    {
+        bilateralTextureFilter(src, dst, fr, 1, sigmaAlpha, sigmaAvg);
+    }
+
+    SANITY_CHECK_NOTHING();
+}
+}
diff --git a/contrib/modules/ximgproc/perf/perf_disparity_wls_filter.cpp b/contrib/modules/ximgproc/perf/perf_disparity_wls_filter.cpp
index bd7c8c2..89b9e77 100644
--- a/contrib/modules/ximgproc/perf/perf_disparity_wls_filter.cpp
+++ b/contrib/modules/ximgproc/perf/perf_disparity_wls_filter.cpp
@@ -11,7 +11,7 @@
  *  Redistribution and use in source and binary forms, with or without modification,
  *  are permitted provided that the following conditions are met :
  *
- *  *Redistributions of source code must retain the above copyright notice,
+ *  * Redistributions of source code must retain the above copyright notice,
  *  this list of conditions and the following disclaimer.
  *
  *  * Redistributions in binary form must reproduce the above copyright notice,
diff --git a/contrib/modules/ximgproc/perf/perf_domain_transform.cpp b/contrib/modules/ximgproc/perf/perf_domain_transform.cpp
index 9e522df..2d99c79 100644
--- a/contrib/modules/ximgproc/perf/perf_domain_transform.cpp
+++ b/contrib/modules/ximgproc/perf/perf_domain_transform.cpp
@@ -11,7 +11,7 @@
  *  Redistribution and use in source and binary forms, with or without modification,
  *  are permitted provided that the following conditions are met :
  *
- *  *Redistributions of source code must retain the above copyright notice,
+ *  * Redistributions of source code must retain the above copyright notice,
  *  this list of conditions and the following disclaimer.
  *
  *  * Redistributions in binary form must reproduce the above copyright notice,
diff --git a/contrib/modules/ximgproc/perf/perf_fgs_filter.cpp b/contrib/modules/ximgproc/perf/perf_fgs_filter.cpp
index b37188f..465193b 100644
--- a/contrib/modules/ximgproc/perf/perf_fgs_filter.cpp
+++ b/contrib/modules/ximgproc/perf/perf_fgs_filter.cpp
@@ -11,7 +11,7 @@
  *  Redistribution and use in source and binary forms, with or without modification,
  *  are permitted provided that the following conditions are met :
  *
- *  *Redistributions of source code must retain the above copyright notice,
+ *  * Redistributions of source code must retain the above copyright notice,
  *  this list of conditions and the following disclaimer.
  *
  *  * Redistributions in binary form must reproduce the above copyright notice,
diff --git a/contrib/modules/ximgproc/perf/perf_guided_filter.cpp b/contrib/modules/ximgproc/perf/perf_guided_filter.cpp
index 8dd785d..4f2d74e 100644
--- a/contrib/modules/ximgproc/perf/perf_guided_filter.cpp
+++ b/contrib/modules/ximgproc/perf/perf_guided_filter.cpp
@@ -11,7 +11,7 @@
  *  Redistribution and use in source and binary forms, with or without modification,
  *  are permitted provided that the following conditions are met :
  *
- *  *Redistributions of source code must retain the above copyright notice,
+ *  * Redistributions of source code must retain the above copyright notice,
  *  this list of conditions and the following disclaimer.
  *
  *  * Redistributions in binary form must reproduce the above copyright notice,
diff --git a/contrib/modules/ximgproc/perf/perf_l0_smooth.cpp b/contrib/modules/ximgproc/perf/perf_l0_smooth.cpp
index 4ae7820..325c703 100644
--- a/contrib/modules/ximgproc/perf/perf_l0_smooth.cpp
+++ b/contrib/modules/ximgproc/perf/perf_l0_smooth.cpp
@@ -11,7 +11,7 @@
  *  Redistribution and use in source and binary forms, with or without modification,
  *  are permitted provided that the following conditions are met :
  *
- *  *Redistributions of source code must retain the above copyright notice,
+ *  * Redistributions of source code must retain the above copyright notice,
  *  this list of conditions and the following disclaimer.
  *
  *  * Redistributions in binary form must reproduce the above copyright notice,
diff --git a/contrib/modules/ximgproc/perf/perf_rolling_guidance_filter.cpp b/contrib/modules/ximgproc/perf/perf_rolling_guidance_filter.cpp
index a0bc3d4..89548c1 100644
--- a/contrib/modules/ximgproc/perf/perf_rolling_guidance_filter.cpp
+++ b/contrib/modules/ximgproc/perf/perf_rolling_guidance_filter.cpp
@@ -11,7 +11,7 @@
  *  Redistribution and use in source and binary forms, with or without modification,
  *  are permitted provided that the following conditions are met :
  *
- *  *Redistributions of source code must retain the above copyright notice,
+ *  * Redistributions of source code must retain the above copyright notice,
  *  this list of conditions and the following disclaimer.
  *
  *  * Redistributions in binary form must reproduce the above copyright notice,
diff --git a/contrib/modules/ximgproc/perf/perf_weighted_median_filter.cpp b/contrib/modules/ximgproc/perf/perf_weighted_median_filter.cpp
new file mode 100644
index 0000000..7ab4e70
--- /dev/null
+++ b/contrib/modules/ximgproc/perf/perf_weighted_median_filter.cpp
@@ -0,0 +1,88 @@
+/*
+ *  By downloading, copying, installing or using the software you agree to this license.
+ *  If you do not agree to this license, do not download, install,
+ *  copy or use the software.
+ *
+ *
+ *  License Agreement
+ *  For Open Source Computer Vision Library
+ *  (3 - clause BSD License)
+ *
+ *  Redistribution and use in source and binary forms, with or without modification,
+ *  are permitted provided that the following conditions are met :
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *  this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *  this list of conditions and the following disclaimer in the documentation
+ *  and / or other materials provided with the distribution.
+ *
+ *  * Neither the names of the copyright holders nor the names of the contributors
+ *  may be used to endorse or promote products derived from this software
+ *  without specific prior written permission.
+ *
+ *  This software is provided by the copyright holders and contributors "as is" and
+ *  any express or implied warranties, including, but not limited to, the implied
+ *  warranties of merchantability and fitness for a particular purpose are disclaimed.
+ *  In no event shall copyright holders or contributors be liable for any direct,
+ *  indirect, incidental, special, exemplary, or consequential damages
+ *  (including, but not limited to, procurement of substitute goods or services;
+ *  loss of use, data, or profits; or business interruption) however caused
+ *  and on any theory of liability, whether in contract, strict liability,
+ *  or tort(including negligence or otherwise) arising in any way out of
+ *  the use of this software, even if advised of the possibility of such damage.
+ */
+
+ #include "perf_precomp.hpp"
+
+ namespace cvtest
+ {
+
+ using std::tr1::tuple;
+ using std::tr1::get;
+ using namespace perf;
+ using namespace testing;
+ using namespace cv;
+ using namespace cv::ximgproc;
+
+ typedef tuple<Size, MatType, int, int, int, WMFWeightType> WMFTestParam;
+ typedef TestBaseWithParam<WMFTestParam> WeightedMedianFilterTest;
+
+ PERF_TEST_P(WeightedMedianFilterTest, perf,
+     Combine(
+     Values(szODD, szQVGA),
+     Values(CV_8U, CV_32F),
+     Values(1, 3),
+     Values(1, 3),
+     Values(3, 5),
+     Values(WMF_EXP, WMF_COS))
+ )
+ {
+     RNG rnd(1);
+
+     WMFTestParam params = GetParam();
+
+     double sigma   = rnd.uniform(20.0, 30.0);
+     Size sz         = get<0>(params);
+     int srcDepth       = get<1>(params);
+     int jCn         = get<2>(params);
+     int srcCn       = get<3>(params);
+     int r = get<4>(params);
+     WMFWeightType weightType = get<5>(params);
+
+     Mat joint(sz, CV_MAKE_TYPE(CV_8U, jCn));
+     Mat src(sz, CV_MAKE_TYPE(srcDepth, srcCn));
+     Mat dst(sz, src.type());
+
+     cv::setNumThreads(cv::getNumberOfCPUs());
+     declare.in(joint, src, WARMUP_RNG).out(dst).tbb_threads(cv::getNumberOfCPUs());
+
+     TEST_CYCLE_N(1)
+     {
+         weightedMedianFilter(joint, src, dst, r, sigma, weightType);
+     }
+
+     SANITY_CHECK_NOTHING();
+ }
+ }
diff --git a/contrib/modules/ximgproc/perf/pref_joint_bilateral_filter.cpp b/contrib/modules/ximgproc/perf/pref_joint_bilateral_filter.cpp
index 59ce046..0873082 100644
--- a/contrib/modules/ximgproc/perf/pref_joint_bilateral_filter.cpp
+++ b/contrib/modules/ximgproc/perf/pref_joint_bilateral_filter.cpp
@@ -11,7 +11,7 @@
  *  Redistribution and use in source and binary forms, with or without modification,
  *  are permitted provided that the following conditions are met :
  *
- *  *Redistributions of source code must retain the above copyright notice,
+ *  * Redistributions of source code must retain the above copyright notice,
  *  this list of conditions and the following disclaimer.
  *
  *  * Redistributions in binary form must reproduce the above copyright notice,
diff --git a/contrib/modules/ximgproc/samples/cpp/graphsegmentation_demo.cpp b/contrib/modules/ximgproc/samples/cpp/graphsegmentation_demo.cpp
deleted file mode 100644
index 10e5e6d..0000000
--- a/contrib/modules/ximgproc/samples/cpp/graphsegmentation_demo.cpp
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
-By downloading, copying, installing or using the software you agree to this
-license. If you do not agree to this license, do not download, install,
-copy or use the software.
-                          License Agreement
-               For Open Source Computer Vision Library
-                       (3-clause BSD License)
-Copyright (C) 2013, OpenCV Foundation, all rights reserved.
-Third party copyrights are property of their respective owners.
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-  * Redistributions of source code must retain the above copyright notice,
-    this list of conditions and the following disclaimer.
-  * Redistributions in binary form must reproduce the above copyright notice,
-    this list of conditions and the following disclaimer in the documentation
-    and/or other materials provided with the distribution.
-  * Neither the names of the copyright holders nor the names of the contributors
-    may be used to endorse or promote products derived from this software
-    without specific prior written permission.
-This software is provided by the copyright holders and contributors "as is" and
-any express or implied warranties, including, but not limited to, the implied
-warranties of merchantability and fitness for a particular purpose are
-disclaimed. In no event shall copyright holders or contributors be liable for
-any direct, indirect, incidental, special, exemplary, or consequential damages
-(including, but not limited to, procurement of substitute goods or services;
-loss of use, data, or profits; or business interruption) however caused
-and on any theory of liability, whether in contract, strict liability,
-or tort (including negligence or otherwise) arising in any way out of
-the use of this software, even if advised of the possibility of such damage.
-*/
-
-
-#include "opencv2/ximgproc/segmentation.hpp"
-#include "opencv2/highgui.hpp"
-#include <opencv2/core/utility.hpp>
-#include <opencv2/opencv.hpp>
-#include <iostream>
-
-using namespace cv;
-using namespace cv::ximgproc::segmentation;
-
-static void help() {
-    std::cout << std::endl <<
-    "A program demonstrating the use and capabilities of a particular graph based image" << std::endl <<
-    "segmentation algorithm described in P. Felzenszwalb, D. Huttenlocher," << std::endl <<
-    "             \"Efficient Graph-Based Image Segmentation\"" << std::endl <<
-    "International Journal of Computer Vision, Vol. 59, No. 2, September 2004" << std::endl << std::endl <<
-    "Usage:" << std::endl <<
-    "./graphsegmentation_demo input_image output_image [simga=0.5] [k=300] [min_size=100]" << std::endl;
-}
-
-Scalar hsv_to_rgb(Scalar c) {
-    Mat in(1, 1, CV_32FC3);
-    Mat out(1, 1, CV_32FC3);
-
-    float * p = in.ptr<float>(0);
-
-    p[0] = c[0] * 360;
-    p[1] = c[1];
-    p[2] = c[2];
-
-    cvtColor(in, out, COLOR_HSV2RGB);
-
-    Scalar t;
-
-    Vec3f p2 = out.at<Vec3f>(0, 0);
-
-    t[0] = (int)(p2[0] * 255);
-    t[1] = (int)(p2[1] * 255);
-    t[2] = (int)(p2[2] * 255);
-
-    return t;
-
-}
-
-Scalar color_mapping(int segment_id) {
-
-    double base = (double)(segment_id) * 0.618033988749895 + 0.24443434;
-
-    return hsv_to_rgb(Scalar(fmod(base, 1.2), 0.95, 0.80));
-
-}
-
-int main(int argc, char** argv) {
-
-    if (argc < 2 || argc > 6) {
-        help();
-        return -1;
-    }
-
-    setUseOptimized(true);
-    setNumThreads(8);
-
-    Ptr<GraphSegmentation> gs = createGraphSegmentation();
-
-    if (argc > 3)
-        gs->setSigma(atof(argv[3]));
-
-    if (argc > 4)
-        gs->setK(atoi(argv[4]));
-
-    if (argc > 5)
-        gs->setMinSize(atoi(argv[5]));
-
-    if (!gs) {
-        std::cerr << "Failed to create GraphSegmentation Algorithm." << std::endl;
-        return -2;
-    }
-
-    Mat input, output, output_image;
-
-    input = imread(argv[1]);
-
-    if (!input.data) {
-        std::cerr << "Failed to load input image" << std::endl;
-        return -3;
-    }
-
-    gs->processImage(input, output);
-
-    double min, max;
-    minMaxLoc(output, &min, &max);
-
-    int nb_segs = (int)max + 1;
-
-    std::cout << nb_segs << " segments" << std::endl;
-
-    output_image = Mat::zeros(output.rows, output.cols, CV_8UC3);
-
-    uint* p;
-    uchar* p2;
-
-    for (int i = 0; i < output.rows; i++) {
-
-        p = output.ptr<uint>(i);
-        p2 = output_image.ptr<uchar>(i);
-
-        for (int j = 0; j < output.cols; j++) {
-            Scalar color = color_mapping(p[j]);
-            p2[j*3] = color[0];
-            p2[j*3 + 1] = color[1];
-            p2[j*3 + 2] = color[2];
-        }
-    }
-
-    imwrite(argv[2], output_image);
-
-    std::cout << "Image written to " << argv[2] << std::endl;
-
-    return 0;
-}
diff --git a/contrib/modules/ximgproc/samples/deriche_demo.cpp b/contrib/modules/ximgproc/samples/deriche_demo.cpp
new file mode 100644
index 0000000..403b855
--- /dev/null
+++ b/contrib/modules/ximgproc/samples/deriche_demo.cpp
@@ -0,0 +1,120 @@
+/*
+ *  By downloading, copying, installing or using the software you agree to this license.
+ *  If you do not agree to this license, do not download, install,
+ *  copy or use the software.
+ *
+ *
+ *  License Agreement
+ *  For Open Source Computer Vision Library
+ *  (3 - clause BSD License)
+ *
+ *  Redistribution and use in source and binary forms, with or without modification,
+ *  are permitted provided that the following conditions are met :
+ *
+ *  *Redistributions of source code must retain the above copyright notice,
+ *  this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *  this list of conditions and the following disclaimer in the documentation
+ *  and / or other materials provided with the distribution.
+ *
+ *  * Neither the names of the copyright holders nor the names of the contributors
+ *  may be used to endorse or promote products derived from this software
+ *  without specific prior written permission.
+ *
+ *  This software is provided by the copyright holders and contributors "as is" and
+ *  any express or implied warranties, including, but not limited to, the implied
+ *  warranties of merchantability and fitness for a particular purpose are disclaimed.
+ *  In no event shall copyright holders or contributors be liable for any direct,
+ *  indirect, incidental, special, exemplary, or consequential damages
+ *  (including, but not limited to, procurement of substitute goods or services;
+ *  loss of use, data, or profits; or business interruption) however caused
+ *  and on any theory of liability, whether in contract, strict liability,
+ *  or tort(including negligence or otherwise) arising in any way out of
+ *  the use of this software, even if advised of the possibility of such damage.
+ */
+#include <opencv2/core.hpp>
+#include <opencv2/core/utility.hpp>
+#include <opencv2/highgui.hpp>
+#include <opencv2/ximgproc.hpp>
+#include "opencv2/ximgproc/deriche_filter.hpp"
+
+using namespace cv;
+using namespace cv::ximgproc;
+
+#include <iostream>
+using namespace std;
+
+int alDerive=100;
+int alMean=100;
+Ptr<Mat> img;
+const string & winName = "Gradient Modulus";
+
+static void DisplayImage(Mat x,string s)
+{
+	vector<Mat> sx;
+	split(x, sx);
+	vector<double> minVal(3), maxVal(3);
+	for (size_t i = 0; i < sx.size(); i++)
+	{
+		minMaxLoc(sx[i], &minVal[i], &maxVal[i]);
+	}
+	maxVal[0] = *max_element(maxVal.begin(), maxVal.end());
+	minVal[0] = *min_element(minVal.begin(), minVal.end());
+	Mat uc;
+	x.convertTo(uc, CV_8U,255/(maxVal[0]-minVal[0]),-255*minVal[0]/(maxVal[0]-minVal[0]));
+	imshow(s, uc);
+}
+
+
+/**
+ * @function DericheFilter
+ * @brief Trackbar callback
+ */
+static void DericheFilter(int, void*)
+{
+    Mat dst;
+    double d=alDerive/100.0,m=alMean/100.0;
+    Mat rx,ry;
+    GradientDericheX(*img.get(),rx,d,m);
+    GradientDericheY(*img.get(),ry,d,m);
+    DisplayImage(rx, "Gx");
+    DisplayImage(ry, "Gy");
+    add(rx.mul(rx),ry.mul(ry),dst);
+    sqrt(dst,dst);
+    DisplayImage(dst, winName );
+}
+
+int main(int argc, char* argv[])
+{
+    Mat *m=new Mat;
+    cv::CommandLineParser parser(argc, argv, "{help h | | show help message}{@input | | input image}");
+    if (parser.has("help"))
+    {
+        parser.printMessage();
+        return -1;
+    }
+    string input_image = parser.get<string>("@input");
+    if (input_image.empty())
+    {
+        parser.printMessage();
+        parser.printErrors();
+        return -2;
+    }
+    if (argc==2)
+        *m = imread(input_image);
+    if (m->empty())
+    {
+        cout << "File not found or empty image\n";
+        return -3;
+    }
+    imshow("Original", *m);
+    img =Ptr<Mat>(m);
+    namedWindow( winName, WINDOW_AUTOSIZE );
+    /// Create a Trackbar for user to enter threshold
+    createTrackbar( "Derive:",winName, &alDerive, 400, DericheFilter );
+    createTrackbar( "Mean:", winName, &alMean, 400, DericheFilter );
+    DericheFilter(0,NULL);
+    waitKey();
+    return 0;
+}
\ No newline at end of file
diff --git a/contrib/modules/ximgproc/samples/fld_lines.cpp b/contrib/modules/ximgproc/samples/fld_lines.cpp
new file mode 100644
index 0000000..1bcfaf7
--- /dev/null
+++ b/contrib/modules/ximgproc/samples/fld_lines.cpp
@@ -0,0 +1,91 @@
+#include <iostream>
+
+#include "opencv2/imgproc.hpp"
+#include "opencv2/ximgproc.hpp"
+#include "opencv2/imgcodecs.hpp"
+#include "opencv2/highgui.hpp"
+
+using namespace std;
+using namespace cv;
+using namespace cv::ximgproc;
+
+int main(int argc, char** argv)
+{
+    std::string in;
+    cv::CommandLineParser parser(argc, argv, "{@input|../samples/data/corridor.jpg|input image}{help h||show help message}");
+    if (parser.has("help"))
+    {
+        parser.printMessage();
+        return 0;
+    }
+    in = parser.get<string>("@input");
+
+    Mat image = imread(in, IMREAD_GRAYSCALE);
+
+    if( image.empty() )
+    {
+        return -1;
+    }
+
+    // Create LSD detector
+    Ptr<LineSegmentDetector> lsd = createLineSegmentDetector();
+    vector<Vec4f> lines_lsd;
+
+    // Create FLD detector
+    // Param               Default value   Description
+    // length_threshold    10            - Segments shorter than this will be discarded
+    // distance_threshold  1.41421356    - A point placed from a hypothesis line
+    //                                     segment farther than this will be
+    //                                     regarded as an outlier
+    // canny_th1           50            - First threshold for
+    //                                     hysteresis procedure in Canny()
+    // canny_th2           50            - Second threshold for
+    //                                     hysteresis procedure in Canny()
+    // canny_aperture_size 3             - Aperturesize for the sobel
+    //                                     operator in Canny()
+    // do_merge            false         - If true, incremental merging of segments
+    //                                     will be perfomred
+    int length_threshold = 10;
+    float distance_threshold = 1.41421356f;
+    double canny_th1 = 50.0;
+    double canny_th2 = 50.0;
+    int canny_aperture_size = 3;
+    bool do_merge = false;
+    Ptr<FastLineDetector> fld = createFastLineDetector(length_threshold,
+            distance_threshold, canny_th1, canny_th2, canny_aperture_size,
+            do_merge);
+    vector<Vec4f> lines_fld;
+
+    // Because of some CPU's power strategy, it seems that the first running of
+    // an algorithm takes much longer. So here we run both of the algorithmes 10
+    // times to see each algorithm's processing time with sufficiently warmed-up
+    // CPU performance.
+    for(int run_count = 0; run_count < 10; run_count++) {
+        lines_lsd.clear();
+        int64 start_lsd = getTickCount();
+        lsd->detect(image, lines_lsd);
+        // Detect the lines with LSD
+        double freq = getTickFrequency();
+        double duration_ms_lsd = double(getTickCount() - start_lsd) * 1000 / freq;
+        std::cout << "Elapsed time for LSD: " << duration_ms_lsd << " ms." << std::endl;
+
+        lines_fld.clear();
+        int64 start = getTickCount();
+        // Detect the lines with FLD
+        fld->detect(image, lines_fld);
+        double duration_ms = double(getTickCount() - start) * 1000 / freq;
+        std::cout << "Ealpsed time for FLD " << duration_ms << " ms." << std::endl;
+    }
+    // Show found lines with LSD
+    Mat line_image_lsd(image);
+    lsd->drawSegments(line_image_lsd, lines_lsd);
+    imshow("LSD result", line_image_lsd);
+
+    // Show found lines with FLD
+    Mat line_image_fld(image);
+    fld->drawSegments(line_image_fld, lines_fld);
+    imshow("FLD result", line_image_fld);
+
+    waitKey();
+    return 0;
+}
diff --git a/contrib/modules/ximgproc/samples/graphsegmentation_demo.cpp b/contrib/modules/ximgproc/samples/graphsegmentation_demo.cpp
new file mode 100644
index 0000000..d38ffa8
--- /dev/null
+++ b/contrib/modules/ximgproc/samples/graphsegmentation_demo.cpp
@@ -0,0 +1,154 @@
+/*
+By downloading, copying, installing or using the software you agree to this
+license. If you do not agree to this license, do not download, install,
+copy or use the software.
+                          License Agreement
+               For Open Source Computer Vision Library
+                       (3-clause BSD License)
+Copyright (C) 2013, OpenCV Foundation, all rights reserved.
+Third party copyrights are property of their respective owners.
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+  * Redistributions of source code must retain the above copyright notice,
+    this list of conditions and the following disclaimer.
+  * Redistributions in binary form must reproduce the above copyright notice,
+    this list of conditions and the following disclaimer in the documentation
+    and/or other materials provided with the distribution.
+  * Neither the names of the copyright holders nor the names of the contributors
+    may be used to endorse or promote products derived from this software
+    without specific prior written permission.
+This software is provided by the copyright holders and contributors "as is" and
+any express or implied warranties, including, but not limited to, the implied
+warranties of merchantability and fitness for a particular purpose are
+disclaimed. In no event shall copyright holders or contributors be liable for
+any direct, indirect, incidental, special, exemplary, or consequential damages
+(including, but not limited to, procurement of substitute goods or services;
+loss of use, data, or profits; or business interruption) however caused
+and on any theory of liability, whether in contract, strict liability,
+or tort (including negligence or otherwise) arising in any way out of
+the use of this software, even if advised of the possibility of such damage.
+*/
+
+
+#include "opencv2/ximgproc/segmentation.hpp"
+#include "opencv2/highgui.hpp"
+#include "opencv2/core.hpp"
+#include "opencv2/imgproc.hpp"
+#include <iostream>
+
+using namespace cv;
+using namespace cv::ximgproc::segmentation;
+
+Scalar hsv_to_rgb(Scalar);
+Scalar color_mapping(int);
+
+static void help() {
+    std::cout << std::endl <<
+    "A program demonstrating the use and capabilities of a particular graph based image" << std::endl <<
+    "segmentation algorithm described in P. Felzenszwalb, D. Huttenlocher," << std::endl <<
+    "             \"Efficient Graph-Based Image Segmentation\"" << std::endl <<
+    "International Journal of Computer Vision, Vol. 59, No. 2, September 2004" << std::endl << std::endl <<
+    "Usage:" << std::endl <<
+    "./graphsegmentation_demo input_image output_image [simga=0.5] [k=300] [min_size=100]" << std::endl;
+}
+
+Scalar hsv_to_rgb(Scalar c) {
+    Mat in(1, 1, CV_32FC3);
+    Mat out(1, 1, CV_32FC3);
+
+    float * p = in.ptr<float>(0);
+
+    p[0] = (float)c[0] * 360.0f;
+    p[1] = (float)c[1];
+    p[2] = (float)c[2];
+
+    cvtColor(in, out, COLOR_HSV2RGB);
+
+    Scalar t;
+
+    Vec3f p2 = out.at<Vec3f>(0, 0);
+
+    t[0] = (int)(p2[0] * 255);
+    t[1] = (int)(p2[1] * 255);
+    t[2] = (int)(p2[2] * 255);
+
+    return t;
+
+}
+
+Scalar color_mapping(int segment_id) {
+
+    double base = (double)(segment_id) * 0.618033988749895 + 0.24443434;
+
+    return hsv_to_rgb(Scalar(fmod(base, 1.2), 0.95, 0.80));
+
+}
+
+int main(int argc, char** argv) {
+
+    if (argc < 2 || argc > 6) {
+        help();
+        return -1;
+    }
+
+    setUseOptimized(true);
+    setNumThreads(8);
+
+    Ptr<GraphSegmentation> gs = createGraphSegmentation();
+
+    if (argc > 3)
+        gs->setSigma(atof(argv[3]));
+
+    if (argc > 4)
+        gs->setK((float)atoi(argv[4]));
+
+    if (argc > 5)
+        gs->setMinSize(atoi(argv[5]));
+
+    if (!gs) {
+        std::cerr << "Failed to create GraphSegmentation Algorithm." << std::endl;
+        return -2;
+    }
+
+    Mat input, output, output_image;
+
+    input = imread(argv[1]);
+
+    if (!input.data) {
+        std::cerr << "Failed to load input image" << std::endl;
+        return -3;
+    }
+
+    gs->processImage(input, output);
+
+    double min, max;
+    minMaxLoc(output, &min, &max);
+
+    int nb_segs = (int)max + 1;
+
+    std::cout << nb_segs << " segments" << std::endl;
+
+    output_image = Mat::zeros(output.rows, output.cols, CV_8UC3);
+
+    uint* p;
+    uchar* p2;
+
+    for (int i = 0; i < output.rows; i++) {
+
+        p = output.ptr<uint>(i);
+        p2 = output_image.ptr<uchar>(i);
+
+        for (int j = 0; j < output.cols; j++) {
+            Scalar color = color_mapping(p[j]);
+            p2[j*3] = (uchar)color[0];
+            p2[j*3 + 1] = (uchar)color[1];
+            p2[j*3 + 2] = (uchar)color[2];
+        }
+    }
+
+    imwrite(argv[2], output_image);
+
+    std::cout << "Image written to " << argv[2] << std::endl;
+
+    return 0;
+}
diff --git a/contrib/modules/ximgproc/samples/live_demo.cpp b/contrib/modules/ximgproc/samples/live_demo.cpp
index 8e16de3..a5a09e2 100644
--- a/contrib/modules/ximgproc/samples/live_demo.cpp
+++ b/contrib/modules/ximgproc/samples/live_demo.cpp
@@ -11,7 +11,7 @@
  *  Redistribution and use in source and binary forms, with or without modification,
  *  are permitted provided that the following conditions are met :
  *  
- *  *Redistributions of source code must retain the above copyright notice,
+ *  * Redistributions of source code must retain the above copyright notice,
  *  this list of conditions and the following disclaimer.
  *  
  *  * Redistributions in binary form must reproduce the above copyright notice,
diff --git a/contrib/modules/ximgproc/samples/niblack_thresholding.cpp b/contrib/modules/ximgproc/samples/niblack_thresholding.cpp
index fed7ca4..495cfff 100644
--- a/contrib/modules/ximgproc/samples/niblack_thresholding.cpp
+++ b/contrib/modules/ximgproc/samples/niblack_thresholding.cpp
@@ -1,49 +1,41 @@
 /*
- * Sample C++ to demonstrate Niblack thresholding.
- *
+ * C++ sample to demonstrate Niblack thresholding.
  */
 
 #include <iostream>
-#include <cstdio>
-
-#include "opencv2/highgui.hpp"
 #include "opencv2/core.hpp"
+#include "opencv2/highgui.hpp"
 #include "opencv2/imgproc.hpp"
-
 #include "opencv2/ximgproc.hpp"
 
 using namespace std;
 using namespace cv;
 using namespace cv::ximgproc;
 
-Mat_<uchar> src, dst;
-
-const int k_max_value = 10;
-int k_from_slider = 0;
-double k_actual = 0.0;
+Mat_<uchar> src;
+int k_ = 8;
+int blockSize_ = 11;
+int type_ = THRESH_BINARY;
 
 void on_trackbar(int, void*);
 
 int main(int argc, char** argv)
 {
-    /*
-     * Read filename from the command-line and load
-     * corresponding gray-scale image.
-     */
+    // read gray-scale image
     if(argc != 2)
     {
         cout << "Usage: ./niblack_thresholding [IMAGE]\n";
         return 1;
     }
     const char* filename = argv[1];
-    src = imread(filename, 1);
-
-    namedWindow("k-slider", 1);
-    string trackbar_name = "k";
-    createTrackbar(trackbar_name, "k-slider", &k_from_slider, k_max_value, on_trackbar);
-    on_trackbar(k_from_slider, 0);
-
+    src = imread(filename, IMREAD_GRAYSCALE);
     imshow("Source", src);
+
+    namedWindow("Niblack", WINDOW_AUTOSIZE);
+    createTrackbar("k", "Niblack", &k_, 20, on_trackbar);
+    createTrackbar("blockSize", "Niblack", &blockSize_, 30, on_trackbar);
+    createTrackbar("threshType", "Niblack", &type_, 4, on_trackbar);
+    on_trackbar(0, 0);
     waitKey(0);
 
     return 0;
@@ -51,8 +43,11 @@ int main(int argc, char** argv)
 
 void on_trackbar(int, void*)
 {
-    k_actual = (double)k_from_slider/k_max_value;
-    niBlackThreshold(src, dst, 255, THRESH_BINARY, 3, k_actual);
-
-    imshow("Destination", dst);
+    double k = static_cast<double>(k_-10)/10;                 // [-1.0, 1.0]
+    int blockSize = 2*(blockSize_ >= 1 ? blockSize_ : 1) + 1; // 3,5,7,...,61
+    int type = type_;  // THRESH_BINARY, THRESH_BINARY_INV,
+                       // THRESH_TRUNC, THRESH_TOZERO, THRESH_TOZERO_INV
+    Mat dst;
+    niBlackThreshold(src, dst, 255, type, blockSize, k);
+    imshow("Niblack", dst);
 }
diff --git a/contrib/modules/ximgproc/samples/paillou_demo.cpp b/contrib/modules/ximgproc/samples/paillou_demo.cpp
new file mode 100644
index 0000000..bcbb9ee
--- /dev/null
+++ b/contrib/modules/ximgproc/samples/paillou_demo.cpp
@@ -0,0 +1,107 @@
+/*
+ *  By downloading, copying, installing or using the software you agree to this license.
+ *  If you do not agree to this license, do not download, install,
+ *  copy or use the software.
+ *
+ *
+ *  License Agreement
+ *  For Open Source Computer Vision Library
+ *  (3 - clause BSD License)
+ *
+ *  Redistribution and use in source and binary forms, with or without modification,
+ *  are permitted provided that the following conditions are met :
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *  this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *  this list of conditions and the following disclaimer in the documentation
+ *  and / or other materials provided with the distribution.
+ *
+ *  * Neither the names of the copyright holders nor the names of the contributors
+ *  may be used to endorse or promote products derived from this software
+ *  without specific prior written permission.
+ *
+ *  This software is provided by the copyright holders and contributors "as is" and
+ *  any express or implied warranties, including, but not limited to, the implied
+ *  warranties of merchantability and fitness for a particular purpose are disclaimed.
+ *  In no event shall copyright holders or contributors be liable for any direct,
+ *  indirect, incidental, special, exemplary, or consequential damages
+ *  (including, but not limited to, procurement of substitute goods or services;
+ *  loss of use, data, or profits; or business interruption) however caused
+ *  and on any theory of liability, whether in contract, strict liability,
+ *  or tort(including negligence or otherwise) arising in any way out of
+ *  the use of this software, even if advised of the possibility of such damage.
+ */
+
+#include <opencv2/core.hpp>
+#include <opencv2/core/utility.hpp>
+#include <opencv2/highgui.hpp>
+#include <opencv2/ximgproc.hpp>
+#include "opencv2/ximgproc/paillou_filter.hpp"
+
+using namespace cv;
+using namespace cv::ximgproc;
+
+#include <iostream>
+using namespace std;
+
+int aa = 100, ww = 10;
+Mat dx, dy;
+UMat img;
+const char* window_name = "Gradient Modulus";
+
+static void DisplayImage(Mat x,string s)
+{
+	vector<Mat> sx;
+	split(x, sx);
+	vector<double> minVal(3), maxVal(3);
+	for (int i = 0; i < static_cast<int>(sx.size()); i++)
+	{
+		minMaxLoc(sx[i], &minVal[i], &maxVal[i]);
+	}
+	maxVal[0] = *max_element(maxVal.begin(), maxVal.end());
+	minVal[0] = *min_element(minVal.begin(), minVal.end());
+	Mat uc;
+	x.convertTo(uc, CV_8U,255/(maxVal[0]-minVal[0]),-255*minVal[0]/(maxVal[0]-minVal[0]));
+	imshow(s, uc);
+}
+
+
+/**
+ * @function paillouFilter
+ * @brief Trackbar callback
+ */
+static void PaillouFilter(int, void*)
+{
+    Mat dst;
+    double a=aa/100.0,w=ww/100.0;
+    Mat rx,ry;
+    GradientPaillouX(img,rx,a,w);
+    GradientPaillouY(img,ry,a,w);
+    DisplayImage(rx, "Gx");
+    DisplayImage(ry, "Gy");
+    add(rx.mul(rx),ry.mul(ry),dst);
+    sqrt(dst,dst);
+    DisplayImage(dst, window_name );
+}
+
+
+int main(int argc, char* argv[])
+{
+    if (argc==2)
+        imread(argv[1]).copyTo(img);
+    if (img.empty())
+    {
+        cout << "File not found or empty image\n";
+    }
+    imshow("Original",img);
+    namedWindow( window_name, WINDOW_AUTOSIZE );
+
+    /// Create a Trackbar for user to enter threshold
+    createTrackbar( "a:",window_name, &aa, 400, PaillouFilter );
+    createTrackbar( "w:", window_name, &ww, 400, PaillouFilter );
+    PaillouFilter(0,NULL);
+    waitKey();
+    return 0;
+}
\ No newline at end of file
diff --git a/contrib/modules/ximgproc/samples/selectivesearchsegmentation_demo.cpp b/contrib/modules/ximgproc/samples/selectivesearchsegmentation_demo.cpp
new file mode 100644
index 0000000..6d65c01
--- /dev/null
+++ b/contrib/modules/ximgproc/samples/selectivesearchsegmentation_demo.cpp
@@ -0,0 +1,115 @@
+/*
+By downloading, copying, installing or using the software you agree to this
+license. If you do not agree to this license, do not download, install,
+copy or use the software.
+                          License Agreement
+               For Open Source Computer Vision Library
+                       (3-clause BSD License)
+Copyright (C) 2013, OpenCV Foundation, all rights reserved.
+Third party copyrights are property of their respective owners.
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+  * Redistributions of source code must retain the above copyright notice,
+    this list of conditions and the following disclaimer.
+  * Redistributions in binary form must reproduce the above copyright notice,
+    this list of conditions and the following disclaimer in the documentation
+    and/or other materials provided with the distribution.
+  * Neither the names of the copyright holders nor the names of the contributors
+    may be used to endorse or promote products derived from this software
+    without specific prior written permission.
+This software is provided by the copyright holders and contributors "as is" and
+any express or implied warranties, including, but not limited to, the implied
+warranties of merchantability and fitness for a particular purpose are
+disclaimed. In no event shall copyright holders or contributors be liable for
+any direct, indirect, incidental, special, exemplary, or consequential damages
+(including, but not limited to, procurement of substitute goods or services;
+loss of use, data, or profits; or business interruption) however caused
+and on any theory of liability, whether in contract, strict liability,
+or tort (including negligence or otherwise) arising in any way out of
+the use of this software, even if advised of the possibility of such damage.
+*/
+
+
+#include "opencv2/ximgproc/segmentation.hpp"
+#include "opencv2/highgui.hpp"
+#include "opencv2/core.hpp"
+#include "opencv2/imgproc.hpp"
+#include <iostream>
+#include <ctime>
+
+using namespace cv;
+using namespace cv::ximgproc::segmentation;
+
+static void help() {
+    std::cout << std::endl <<
+    "A program demonstrating the use and capabilities of a particular image segmentation algorithm described" << std::endl <<
+    " in Jasper R. R. Uijlings, Koen E. A. van de Sande, Theo Gevers, Arnold W. M. Smeulders: " << std::endl <<
+    "                       \"Selective Search for Object Recognition\"" << std::endl <<
+    "International Journal of Computer Vision, Volume 104 (2), page 154-171, 2013" << std::endl << std::endl <<
+    "Usage:" << std::endl <<
+    "./selectivesearchsegmentation_demo input_image (single|fast|quality)" << std::endl <<
+    "Use a to display less rects, d to display more rects, q to quit" << std::endl;
+}
+
+
+int main(int argc, char** argv) {
+
+    if (argc < 3) {
+        help();
+        return -1;
+    }
+
+    setUseOptimized(true);
+    setNumThreads(8);
+
+    std::srand((int)std::time(0));
+
+    Mat img = imread(argv[1]);
+
+    Ptr<SelectiveSearchSegmentation> gs = createSelectiveSearchSegmentation();
+    gs->setBaseImage(img);
+
+    if (argv[2][0] == 's') {
+        gs->switchToSingleStrategy();
+    } else if (argv[2][0] == 'f') {
+        gs->switchToSelectiveSearchFast();
+    } else if (argv[2][0] == 'q') {
+        gs->switchToSelectiveSearchQuality();
+    } else {
+        help();
+        return -2;
+    }
+
+    std::vector<Rect> rects;
+    gs->process(rects);
+
+    int nb_rects = 10;
+
+    char c = (char)waitKey();
+
+    while(c != 'q') {
+
+        Mat wimg = img.clone();
+
+        int i = 0;
+
+        for(std::vector<Rect>::iterator it = rects.begin(); it != rects.end(); ++it) {
+            if (i++ < nb_rects) {
+                rectangle(wimg, *it, Scalar(0, 0, 255));
+            }
+        }
+
+        imshow("Output", wimg);
+        c = (char)waitKey();
+
+        if (c == 'd') {
+            nb_rects += 10;
+        }
+
+        if (c == 'a' && nb_rects > 10) {
+            nb_rects -= 10;
+        }
+    }
+
+    return 0;
+}
diff --git a/contrib/modules/ximgproc/samples/slic.cpp b/contrib/modules/ximgproc/samples/slic.cpp
new file mode 100644
index 0000000..637cbf2
--- /dev/null
+++ b/contrib/modules/ximgproc/samples/slic.cpp
@@ -0,0 +1,138 @@
+#include <opencv2/imgproc.hpp>
+#include <opencv2/highgui.hpp>
+#include <opencv2/imgcodecs.hpp>
+#include <opencv2/core/utility.hpp>
+
+#include <opencv2/ximgproc.hpp>
+
+#include <ctype.h>
+#include <stdio.h>
+#include <iostream>
+
+using namespace cv;
+using namespace cv::ximgproc;
+using namespace std;
+
+static const char* window_name = "SLIC Superpixels";
+
+static const char* keys =
+    "{h help      | | help menu}"
+    "{c camera    |0| camera id}"
+    "{i image     | | image file}"
+    "{a algorithm |1| SLIC(0),SLICO(1)}"
+    ;
+
+int main(int argc, char** argv)
+{
+    CommandLineParser cmd(argc,argv,keys);
+    if (cmd.has("help")) {
+        cmd.about("This program demonstrates SLIC superpixels using OpenCV class SuperpixelSLIC.\n"
+            "If no image file is supplied, try to open a webcam.\n"
+            "Use [space] to toggle output mode, ['q' or 'Q' or 'esc'] to exit.\n");
+        cmd.printMessage();
+        return 0;
+    }
+    int capture = cmd.get<int>("camera");
+    String img_file = cmd.get<String>("image");
+    int algorithm = cmd.get<int>("algorithm");
+    int region_size = 50;
+    int ruler = 30;
+    int min_element_size = 50;
+    int num_iterations = 3;
+    bool use_video_capture = img_file.empty();
+
+    VideoCapture cap;
+    Mat input_image;
+
+    if( use_video_capture )
+    {
+        if( !cap.open(capture) )
+        {
+            cout << "Could not initialize capturing..."<<capture<<"\n";
+            return -1;
+        }
+    }
+    else
+    {
+        input_image = imread(img_file);
+        if( input_image.empty() )
+        {
+            cout << "Could not open image..."<<img_file<<"\n";
+            return -1;
+        }
+    }
+
+    namedWindow(window_name, 0);
+    createTrackbar("Algorithm", window_name, &algorithm, 1, 0);
+    createTrackbar("Region size", window_name, &region_size, 200, 0);
+    createTrackbar("Ruler", window_name, &ruler, 100, 0);
+    createTrackbar("Connectivity", window_name, &min_element_size, 100, 0);
+    createTrackbar("Iterations", window_name, &num_iterations, 12, 0);
+
+    Mat result, mask;
+    int display_mode = 0;
+
+    for (;;)
+    {
+        Mat frame;
+        if( use_video_capture )
+            cap >> frame;
+        else
+            input_image.copyTo(frame);
+
+        if( frame.empty() )
+            break;
+
+        result = frame;
+        Mat converted;
+        cvtColor(frame, converted, COLOR_BGR2HSV);
+
+        double t = (double) getTickCount();
+
+        Ptr<SuperpixelSLIC> slic = createSuperpixelSLIC(converted,algorithm+SLIC,region_size,float(ruler));
+        slic->iterate(num_iterations);
+        if (min_element_size>0)
+            slic->enforceLabelConnectivity(min_element_size);
+
+        t = ((double) getTickCount() - t) / getTickFrequency();
+        cout << "SLIC" << (algorithm?'O':' ')
+             << " segmentation took " << (int) (t * 1000)
+             << " ms with " << slic->getNumberOfSuperpixels() << " superpixels" << endl;
+
+        // get the contours for displaying
+        slic->getLabelContourMask(mask, true);
+        result.setTo(Scalar(0, 0, 255), mask);
+
+        // display output
+        switch (display_mode)
+        {
+        case 0: //superpixel contours
+            imshow(window_name, result);
+            break;
+        case 1: //mask
+            imshow(window_name, mask);
+            break;
+        case 2: //labels array
+        {
+            // use the last x bit to determine the color. Note that this does not
+            // guarantee that 2 neighboring superpixels have different colors.
+            // retrieve the segmentation result
+            Mat labels;
+            slic->getLabels(labels);
+            const int num_label_bits = 2;
+            labels &= (1 << num_label_bits) - 1;
+            labels *= 1 << (16 - num_label_bits);
+            imshow(window_name, labels);
+            break;
+        }
+        }
+
+        int c = waitKey(1) & 0xff;
+        if( c == 'q' || c == 'Q' || c == 27 )
+            break;
+        else if( c == ' ' )
+            display_mode = (display_mode + 1) % 3;
+    }
+
+    return 0;
+}
diff --git a/contrib/modules/ximgproc/samples/structured_edge_detection.cpp b/contrib/modules/ximgproc/samples/structured_edge_detection.cpp
index fed8da4..98eeefc 100644
--- a/contrib/modules/ximgproc/samples/structured_edge_detection.cpp
+++ b/contrib/modules/ximgproc/samples/structured_edge_detection.cpp
@@ -1,6 +1,13 @@
+/**************************************************************************************
+The structered edge demo requires you to provide a model.
+This model can be found at the opencv_extra repository on Github on the following link:
+https://github.com/opencv/opencv_extra/blob/master/testdata/cv/ximgproc/model.yml.gz
+***************************************************************************************/
+
 #include <opencv2/ximgproc.hpp>
 #include "opencv2/highgui.hpp"
 #include "opencv2/core/utility.hpp"
+#include <iostream>
 
 using namespace cv;
 using namespace cv::ximgproc;
@@ -15,52 +22,51 @@ const char* keys =
 int main( int argc, const char** argv )
 {
     bool printHelp = ( argc == 1 );
-    printHelp = printHelp || ( argc == 2 && std::string(argv[1]) == "--help" );
-    printHelp = printHelp || ( argc == 2 && std::string(argv[1]) == "-h" );
+    printHelp = printHelp || ( argc == 2 && String(argv[1]) == "--help" );
+    printHelp = printHelp || ( argc == 2 && String(argv[1]) == "-h" );
 
     if ( printHelp )
     {
-        printf("\nThis sample demonstrates structured forests for fast edge detection\n"
+        std::cout << "\nThis sample demonstrates structured forests for fast edge detection\n"
                "Call:\n"
-               "    structured_edge_detection -i=in_image_name -m=model_name [-o=out_image_name]\n\n");
+               "    structured_edge_detection -i=in_image_name -m=model_name [-o=out_image_name]\n\n";
         return 0;
     }
 
-    cv::CommandLineParser parser(argc, argv, keys);
+    CommandLineParser parser(argc, argv, keys);
     if ( !parser.check() )
     {
         parser.printErrors();
         return -1;
     }
 
-    std::string modelFilename = parser.get<std::string>("m");
-    std::string inFilename = parser.get<std::string>("i");
-    std::string outFilename = parser.get<std::string>("o");
+    String modelFilename = parser.get<String>("m");
+    String inFilename = parser.get<String>("i");
+    String outFilename = parser.get<String>("o");
 
-    cv::Mat image = cv::imread(inFilename, 1);
+    Mat image = imread(inFilename, 1);
     if ( image.empty() )
-    {
-        printf("Cannot read image file: %s\n", inFilename.c_str());
-        return -1;
-    }
+        CV_Error(Error::StsError, String("Cannot read image file: ") + inFilename);
+
+    if ( modelFilename.size() == 0)
+        CV_Error(Error::StsError, String("Empty model name"));
 
-    image.convertTo(image, cv::DataType<float>::type, 1/255.0);
+    image.convertTo(image, DataType<float>::type, 1/255.0);
 
-    cv::Mat edges(image.size(), image.type());
+    Mat edges(image.size(), image.type());
 
-    cv::Ptr<StructuredEdgeDetection> pDollar =
+    Ptr<StructuredEdgeDetection> pDollar =
         createStructuredEdgeDetection(modelFilename);
     pDollar->detectEdges(image, edges);
 
-    if ( outFilename == "" )
+    if ( outFilename.size() == 0 )
     {
-        cv::namedWindow("edges", 1);
-        cv::imshow("edges", edges);
-
-        cv::waitKey(0);
+        namedWindow("edges", 1);
+        imshow("edges", edges);
+        waitKey(0);
     }
     else
-        cv::imwrite(outFilename, 255*edges);
+        imwrite(outFilename, 255*edges);
 
     return 0;
 }
diff --git a/contrib/modules/ximgproc/samples/thinning.cpp b/contrib/modules/ximgproc/samples/thinning.cpp
new file mode 100644
index 0000000..7adabb7
--- /dev/null
+++ b/contrib/modules/ximgproc/samples/thinning.cpp
@@ -0,0 +1,44 @@
+#include <iostream>
+
+#include "opencv2/imgproc.hpp"
+#include "opencv2/highgui.hpp"
+
+#include "opencv2/ximgproc.hpp"
+
+using namespace std;
+using namespace cv;
+
+int main()
+{
+    Mat img = imread("opencv-logo.png", IMREAD_COLOR);
+
+    /// Threshold the input image
+    Mat img_grayscale, img_binary;
+    cvtColor(img, img_grayscale,COLOR_BGR2GRAY);
+    threshold(img_grayscale, img_binary, 0, 255, THRESH_OTSU | THRESH_BINARY_INV);
+
+    /// Apply thinning to get a skeleton
+    Mat img_thinning_ZS, img_thinning_GH;
+    //ximgproc::thinning(img_binary, img_thinning_ZS, THINNING_ZHANGSUEN);
+    //ximgproc::thinning(img_binary, img_thinning_GH, THINNING_GUOHALL);
+
+    /// Make 3 channel images from thinning result
+    Mat result_ZS(img.rows, img.cols, CV_8UC3), result_GH(img.rows, img.cols, CV_8UC3);
+
+    Mat in[] = { img_thinning_ZS, img_thinning_ZS, img_thinning_ZS };
+    Mat in2[] = { img_thinning_GH, img_thinning_GH, img_thinning_GH };
+    int from_to[] = { 0,0, 1,1, 2,2 };
+    mixChannels( in, 3, &result_ZS, 1, from_to, 3 );
+    mixChannels( in2, 3, &result_GH, 1, from_to, 3 );
+
+    /// Combine everything into a canvas
+    Mat canvas(img.rows, img.cols * 3, CV_8UC3);
+    img.copyTo( canvas( Rect(0, 0, img.cols, img.rows) ) );
+    result_ZS.copyTo( canvas( Rect(img.cols, 0, img.cols, img.rows) ) );
+    result_GH.copyTo( canvas( Rect(img.cols*2, 0, img.cols, img.rows) ) );
+
+    /// Visualize result
+    imshow("Skeleton", canvas); waitKey(0);
+
+    return 0;
+}
diff --git a/contrib/modules/ximgproc/src/adaptive_manifold_filter_n.cpp b/contrib/modules/ximgproc/src/adaptive_manifold_filter_n.cpp
index 3d400a4..89a5325 100644
--- a/contrib/modules/ximgproc/src/adaptive_manifold_filter_n.cpp
+++ b/contrib/modules/ximgproc/src/adaptive_manifold_filter_n.cpp
@@ -11,7 +11,7 @@
  *  Redistribution and use in source and binary forms, with or without modification,
  *  are permitted provided that the following conditions are met :
  *  
- *  *Redistributions of source code must retain the above copyright notice,
+ *  * Redistributions of source code must retain the above copyright notice,
  *  this list of conditions and the following disclaimer.
  *  
  *  * Redistributions in binary form must reproduce the above copyright notice,
diff --git a/contrib/modules/ximgproc/src/bilateral_texture_filter.cpp b/contrib/modules/ximgproc/src/bilateral_texture_filter.cpp
new file mode 100644
index 0000000..5be6c0a
--- /dev/null
+++ b/contrib/modules/ximgproc/src/bilateral_texture_filter.cpp
@@ -0,0 +1,357 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+//  By downloading, copying, installing or using the software you agree to this license.
+//  If you do not agree to this license, do not download, install,
+//  copy or use the software.
+//
+//
+//                           License Agreement
+//                For Open Source Computer Vision Library
+//
+// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
+// Copyright (C) 2009-2011, Willow Garage Inc., all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+//   * Redistribution's of source code must retain the above copyright notice,
+//     this list of conditions and the following disclaimer.
+//
+//   * Redistribution's in binary form must reproduce the above copyright notice,
+//     this list of conditions and the following disclaimer in the documentation
+//     and/or other materials provided with the distribution.
+//
+//   * The name of Intel Corporation may not be used to endorse or promote products
+//     derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "precomp.hpp"
+#include <opencv2/ximgproc.hpp>
+#include <vector>
+
+namespace cv
+{
+namespace ximgproc
+{
+  void compute_mRTV(const Mat& L, Mat& mRTV, int fr);
+  void compute_G(const Mat& B, const Mat& mRTV, Mat& G, Mat& alpha, int fr);
+  void joint_bilateral_filter(const Mat& img, const Mat& G, Mat& r_img, int fr2, double sigma_avg);
+  void joint_bilateral_filter3(const Mat& img, const Mat& G, Mat& r_img, int fr2, double sigma_avg);
+
+  void bilateralTextureFilter(InputArray src_, OutputArray dst_, int fr,
+                              int numIter, double sigmaAlpha, double sigmaAvg)
+  {
+    CV_Assert(!src_.empty());
+
+    Mat src = src_.getMat();
+    CV_Assert(src.depth() == CV_8U || src.depth() == CV_32F);
+
+    CV_Assert(fr > 0 && numIter > 0);
+
+    if (sigmaAlpha < 0)
+      sigmaAlpha = 5. * fr;
+    if (sigmaAvg < 0)
+      sigmaAvg = 0.05 * sqrt(src.channels());
+
+    Mat I;
+    src.copyTo(I);
+    if (src.type() == CV_8UC1) {
+      I.convertTo(I, CV_32FC1, 1.0 / 255.0);
+    }
+    else if (src.type() == CV_8UC3) {
+      I.convertTo(I, CV_32FC3, 1.0 / 255.0);
+    }
+
+    for (int iter = 0; iter < numIter; iter++)
+    {
+      Mat B;
+      blur(I, B, Size(2 * fr + 1, 2 * fr + 1), Point(-1, -1), BORDER_REFLECT);
+
+      Mat mRTV;
+      compute_mRTV(I, mRTV, fr);
+
+      Mat G, minmRTV;
+      compute_G(B, mRTV, G, minmRTV, fr);
+
+      // alpha blending
+      Mat Gtilde;
+      Mat diff = mRTV - minmRTV;
+      Mat alpha = -diff.mul(sigmaAlpha);
+      exp(alpha, alpha);
+      alpha = alpha + 1.;
+      pow(alpha, -1, alpha);
+      alpha = (alpha - 0.5) * 2;
+      Mat alphainv = -(alpha - 1);
+
+      std::vector<Mat> Gi, Bi;
+      Gi.resize(I.channels());
+      Bi.resize(I.channels());
+      if (I.channels() == 3) {
+        split(G, &Gi[0]);
+        split(B, &Bi[0]);
+      }
+      else {
+        G.copyTo(Gi[0]);
+        B.copyTo(Bi[0]);
+      }
+
+      std::vector<Mat> Gtildei;
+      Gtildei.resize(I.channels());
+      for (int i = 0; i < B.channels(); i++)
+        Gtildei[i] = Gi[i].mul(alpha) + Bi[i].mul(alphainv);
+      merge(&Gtildei[0], B.channels(), Gtilde);
+
+      // joint bilateral filter
+      cv::Mat J;
+      if (I.channels() == 1)
+        joint_bilateral_filter(I, Gtilde, J, fr * 2, sigmaAvg);
+      else if (I.channels() == 3)
+        joint_bilateral_filter3(I, Gtilde, J, fr * 2, sigmaAvg);
+      I = J;
+    }
+    if (src.type() == CV_8UC1) {
+      I.convertTo(I, CV_8UC1, 255.0);
+    }
+    else if (src.type() == CV_8UC3) {
+      I.convertTo(I, CV_8UC3, 255.0);
+    }
+
+    I.copyTo(dst_);
+  }
+
+  void compute_mRTV(const Mat& L, Mat& mRTV, int fr)
+  {
+    mRTV = Mat::zeros(L.size(), CV_32FC1);
+
+    const float eps = 0.00001f;
+
+    // Calculate image derivative(gradient)
+    Mat G;
+    Mat Gx, Gy, kernelx, kernely;
+    kernelx = Mat::zeros(1, 3, CV_32F);
+    kernelx.at<float>(0, 1) = -1.0;
+    kernelx.at<float>(0, 2) = 1.0;
+    filter2D(L, Gx, -1, kernelx, Point(-1, -1), 0, BORDER_REFLECT);
+    kernely = Mat::zeros(3, 1, CV_32F);
+    kernely.at<float>(1, 0) = -1.0;
+    kernely.at<float>(2, 0) = 1.0;
+    filter2D(L, Gy, -1, kernely, Point(-1, -1), 0, BORDER_REFLECT);
+
+    Gx = Gx.mul(Gx);
+    Gy = Gy.mul(Gy);
+    sqrt(Gx + Gy, G);
+
+    // Pad image L and G
+    Mat padL;
+    Mat padG;
+    copyMakeBorder(L, padL, fr, fr, fr, fr, BORDER_REFLECT);
+    copyMakeBorder(G, padG, fr, fr, fr, fr, BORDER_REFLECT);
+
+    // Calculate maxL, minL, maxG, sumG
+    int pu = fr;
+    int pb = pu + L.rows;
+    int pl = fr;
+    int pr = pl + L.cols;
+
+    std::vector<Mat> Li, Gi;
+    Li.resize(L.channels());
+    Gi.resize(L.channels());
+    if (L.channels() == 3) {
+      split(padL, &Li[0]);
+      split(padG, &Gi[0]);
+    }
+    else {
+      padL.copyTo(Li[0]);
+      padG.copyTo(Gi[0]);
+    }
+
+    for (int i = 0; i < L.channels(); i++)
+    {
+      Mat maxL = Mat::zeros(L.size(), CV_32FC1);
+      Mat minL = Mat::ones(L.size(), CV_32FC1);
+      Mat maxG = Mat::zeros(L.size(), CV_32FC1);
+      Mat sumG = Mat::zeros(L.size(), CV_32FC1);
+      for (int y = -fr; y <= fr; y++)
+      {
+        for (int x = -fr; x <= fr; x++)
+        {
+          Mat temp = Li[i](
+            Range(pu + y, pb + y),
+            Range(pl + x, pr + x)
+          );
+          maxL = max(maxL, temp);
+          minL = min(minL, temp);
+
+          temp = Gi[i](
+            Range(pu + y, pb + y),
+            Range(pl + x, pr + x)
+          );
+          maxG = max(maxG, temp);
+          sumG = sumG + temp;
+        }
+      }
+      Mat deltai = maxL - minL;
+      sumG = max(sumG, eps);
+      Mat mRTVi = maxG / sumG * (2 * fr + 1);
+      mRTV = mRTV + mRTVi.mul(deltai);
+    }
+    if (L.channels() == 3)
+      mRTV = mRTV / 3;
+  }
+
+  void compute_G(const Mat& B, const Mat& mRTV, Mat& G, Mat& alpha, int fr)
+  {
+    B.copyTo(G);
+    alpha = Mat::ones(B.size(), CV_32FC1);
+    for (int y = -fr; y <= fr; y++)
+    {
+      for (int x = -fr; x <= fr; x++)
+      {
+        Point pb;
+        Point pt;
+        for (pb.y = 0; pb.y < B.rows; pb.y++)
+        {
+          for (pb.x = 0; pb.x < B.cols; pb.x++)
+          {
+            pt.x = min(max(pb.x + x, 0), B.cols - 1);
+            pt.y = min(max(pb.y + y, 0), B.rows - 1);
+            if (alpha.at<float>(pb) > mRTV.at<float>(pt))
+            {
+              alpha.at<float>(pb) = mRTV.at<float>(pt);
+              if (B.channels() == 3)
+                G.at<Vec3f>(pb) = B.at<Vec3f>(pt);
+              else if (B.channels() == 1)
+                G.at<float>(pb) = B.at<float>(pt);
+            }
+          }
+        }
+      }
+    }
+  }
+
+  void joint_bilateral_filter(const Mat& img, const Mat& G, Mat& r_img, int fr2, double sigma_avg)
+  {
+    Mat p_G;
+    copyMakeBorder(G, p_G, fr2, fr2, fr2, fr2, BORDER_REFLECT);
+
+    Mat p_img;
+    copyMakeBorder(img, p_img, fr2, fr2, fr2, fr2, BORDER_REFLECT);
+
+    Mat SW;
+    if (SW.empty()) {
+      SW = Mat(2*fr2+1, 2*fr2+1, CV_32FC1);
+      int r, c;
+      float y, x;
+      for (r = 0, y = (float)-fr2; r < SW.rows; r++, y += 1.0) {
+        for(c = 0, x = (float)-fr2; c < SW.cols; c++, x += 1.0) {
+          SW.at<float>(r,c) = exp(-(x*x + y*y) / (2*fr2*fr2));
+        }
+      }
+    }
+
+    r_img = Mat::zeros(img.size(), CV_32FC1);
+    {
+      Mat sum_d_W = Mat::zeros(img.size(), CV_32FC1);
+      Mat d_W = Mat::zeros(G.size(), CV_32FC1);
+
+      for (int x = -fr2; x <= fr2; x++) {
+        for (int y = -fr2; y <= fr2; y++) {
+          d_W = p_G(Rect(fr2+x, fr2+y, img.cols, img.rows)) - G;
+          multiply(d_W, d_W, d_W);
+          exp(-0.5 * d_W / (sigma_avg*sigma_avg), d_W);
+
+          d_W = d_W * SW.at<float>(fr2+y, fr2+x); //Gaussian weight
+
+          sum_d_W = sum_d_W + d_W;
+          multiply(d_W, p_img(Rect(fr2+x, fr2+y, img.cols, img.rows)), d_W);
+          r_img = r_img + d_W;
+        }
+      }
+      max(1e-5f, sum_d_W, sum_d_W);
+      divide(r_img, sum_d_W, r_img);
+    }
+  }
+
+  void joint_bilateral_filter3(const Mat& img, const Mat& G, Mat& r_img, int fr2, double sigma_avg)
+  {
+    Mat p_G;
+    copyMakeBorder(G, p_G, fr2, fr2, fr2, fr2, BORDER_REFLECT);
+
+    Mat p_img;
+    copyMakeBorder(img, p_img, fr2, fr2, fr2, fr2, BORDER_REFLECT);
+
+    Mat SW;
+    if (SW.empty()) {
+      SW = Mat(2*fr2+1, 2*fr2+1, CV_32FC1);
+      int r, c;
+      float y, x;
+      for (r = 0, y = (float)-fr2; r < SW.rows; r++, y += 1.0) {
+        for(c = 0, x = (float)-fr2; c < SW.cols; c++, x += 1.0) {
+          SW.at<float>(r,c) = exp(-(x*x + y*y) / (2*fr2*fr2));
+        }
+      }
+    }
+
+    std::vector<Mat> G_channels(3);
+    split(G, G_channels);
+    std::vector<Mat> p_G_channels(3);
+    split(p_G, p_G_channels);
+    std::vector<Mat> p_img_channels(3);
+    split(p_img, p_img_channels);
+
+    Mat sum_d_W = Mat::zeros(img.size(), CV_32FC1);
+    std::vector<Mat> d_W_channels(3);
+    for (int ch = 0; ch < 3; ch++) {
+      d_W_channels[ch] = Mat::zeros(G.size(), CV_32FC1);
+    }
+    Mat d_W = Mat::zeros(G.size(), CV_32FC1);
+
+    std::vector<Mat> r_img_channels(3);
+    for (int ch = 0; ch < 3; ch++) {
+      r_img_channels[ch] = Mat::zeros(G.size(), CV_32FC1);
+    }
+
+    for (int x = -fr2; x <= fr2; x++) {
+      for (int y = -fr2; y <= fr2; y++) {
+        d_W.setTo(0);
+        for (int ch = 0; ch < 3; ch++) {
+          subtract(p_G_channels[ch](Rect(fr2+x, fr2+y, img.cols, img.rows)), G_channels[ch], d_W_channels[ch]);
+          multiply(d_W_channels[ch], d_W_channels[ch], d_W_channels[ch]);
+        }
+        for (int ch = 0; ch < 3; ch++) {
+          add(d_W, d_W_channels[ch], d_W);
+        }
+        exp(-0.5 * d_W / (sigma_avg*sigma_avg), d_W);
+
+        d_W = d_W * SW.at<float>(fr2+y, fr2+x); //Gaussian weight
+
+        add(sum_d_W, d_W, sum_d_W);
+
+        for (int ch = 0; ch < 3; ch++) {
+          Mat n_p_img = p_img_channels[ch](Rect(fr2+x, fr2+y, img.cols, img.rows));
+          accumulateProduct(d_W, n_p_img, r_img_channels[ch]);
+        }
+      }
+    }
+
+    max(1e-5f, sum_d_W, sum_d_W);
+    for (int ch = 0; ch < 3; ch++) {
+      divide(r_img_channels[ch], sum_d_W, r_img_channels[ch]);
+    }
+    merge(r_img_channels, r_img);
+  }
+
+}
+}
diff --git a/contrib/modules/ximgproc/src/deriche_filter.cpp b/contrib/modules/ximgproc/src/deriche_filter.cpp
new file mode 100644
index 0000000..a2495e6
--- /dev/null
+++ b/contrib/modules/ximgproc/src/deriche_filter.cpp
@@ -0,0 +1,430 @@
+/*
+ *  By downloading, copying, installing or using the software you agree to this license.
+ *  If you do not agree to this license, do not download, install,
+ *  copy or use the software.
+ *
+ *
+ *  License Agreement
+ *  For Open Source Computer Vision Library
+ *  (3 - clause BSD License)
+ *
+ *  Redistribution and use in source and binary forms, with or without modification,
+ *  are permitted provided that the following conditions are met :
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *  this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *  this list of conditions and the following disclaimer in the documentation
+ *  and / or other materials provided with the distribution.
+ *
+ *  * Neither the names of the copyright holders nor the names of the contributors
+ *  may be used to endorse or promote products derived from this software
+ *  without specific prior written permission.
+ *
+ *  This software is provided by the copyright holders and contributors "as is" and
+ *  any express or implied warranties, including, but not limited to, the implied
+ *  warranties of merchantability and fitness for a particular purpose are disclaimed.
+ *  In no event shall copyright holders or contributors be liable for any direct,
+ *  indirect, incidental, special, exemplary, or consequential damages
+ *  (including, but not limited to, procurement of substitute goods or services;
+ *  loss of use, data, or profits; or business interruption) however caused
+ *  and on any theory of liability, whether in contract, strict liability,
+ *  or tort(including negligence or otherwise) arising in any way out of
+ *  the use of this software, even if advised of the possibility of such damage.
+ */
+#include "precomp.hpp"
+#include "opencv2/highgui.hpp"
+#include <math.h>
+#include <vector>
+#include <iostream>
+
+/*
+If you use this code please cite this @cite deriche1987using
+Using Canny's criteria to derive a recursively implemented optimal edge detector  International journal of computer vision  (Volume:1 ,  Issue: 2 )  1987
+*/
+
+namespace cv {
+namespace ximgproc {
+template<typename T> static void
+VerticalIIRFilter(Mat &img,Mat &dst,const Range &r,double alphaDerive)
+{
+    float                *f2;
+    int tailleSequence = (img.rows>img.cols) ? img.rows : img.cols;
+    Mat matG1(1, tailleSequence, CV_64FC1), matG2(1, tailleSequence, CV_64FC1);
+    double *g1 = matG1.ptr<double>(0), *g2 = (double*)matG2.ptr<double>(0);
+    double    kp = pow(1 - exp(-alphaDerive), 2.0) / exp(-alphaDerive);
+    double a1, a2, a3, a4;
+    double b1, b2;
+    int rows = img.rows, cols = img.cols;
+
+    kp = pow(1 - exp(-alphaDerive), 2.0) / exp(-alphaDerive);
+    a1 = 0;
+    a2 = kp*exp(-alphaDerive), a3 = -kp*exp(-alphaDerive);
+    a4 = 0;
+    b1 = 2 * exp(-alphaDerive);
+    b2 = -exp(-2 * alphaDerive);
+    for (int j = r.start; j<r.end; j++)
+    {
+        // Causal vertical  IIR filter
+        T *c1 = img.ptr<T>(0);
+        f2 = dst.ptr<float>(0);
+        f2 += j;
+        c1 += j;
+        int i = 0;
+        g1[i] = (a1 + a2)* *c1;
+        i++;
+        c1 += cols;
+        g1[i] = a1 * *c1 + a2 * c1[-cols] + (b1)* g1[i - 1];
+        i++;
+        c1 += cols;
+        for (i = 2; i<rows; i++, c1 += cols)
+            g1[i] = a1 * *c1 + a2 * c1[-cols] + b1*g1[i - 1] + b2 *g1[i - 2];
+        // Anticausal vertical IIR filter
+        c1 = img.ptr<T>(0);
+        c1 += (rows - 1)*cols + j;
+        i = rows - 1;
+        g2[i] = (a3 + a4)* *c1;
+        i--;
+        c1 -= cols;
+        g2[i] = a3* c1[cols] + a4 * c1[cols] + (b1)*g2[i + 1];
+        i--;
+        c1 -= cols;
+        for (i = rows - 3; i >= 0; i--, c1 -= cols)
+            g2[i] = a3*c1[cols] + a4* c1[2 * cols] +
+            b1*g2[i + 1] + b2*g2[i + 2];
+        for (i = 0; i<rows; i++, f2 += cols)
+            *f2 = (float)(g1[i] + g2[i]);
+    }
+}
+
+template<typename T> static void
+HorizontalIIRFilter(Mat &img, Mat &dst, const Range &r, double alphaDerive)
+{
+    float *f1;
+    int rows = img.rows, cols = img.cols;
+    int tailleSequence = (rows>cols) ? rows : cols;
+    Mat matG1(1, tailleSequence, CV_64FC1), matG2(1, tailleSequence, CV_64FC1);
+    double *g1 = (double*)matG1.ptr(0), *g2 = (double*)matG2.ptr(0);
+    double kp;;
+    double a1, a2, a3, a4;
+    double b1, b2;
+
+    kp = pow(1 - exp(-alphaDerive), 2.0) / exp(-alphaDerive);
+    a1 = 0;
+    a2 = kp*exp(-alphaDerive);
+    a3 = -kp*exp(-alphaDerive);
+    a4 = 0;
+    b1 = 2 * exp(-alphaDerive);
+    b2 = -exp(-2 * alphaDerive);
+
+    for (int i = r.start; i<r.end; i++)
+    {
+        f1 = dst.ptr<float>(i);
+        T *c1 = img.ptr<T>(i);
+        int j = 0;
+        g1[j] = (a1 + a2)* *c1;
+        j++;
+        c1++;
+        g1[j] = a1 * c1[0] + a2*c1[j - 1] + (b1)* g1[j - 1];
+        j++;
+        c1++;
+        for (j = 2; j<cols; j++, c1++)
+            g1[j] = a1 * c1[0] + a2 * c1[-1] + b1*g1[j - 1] + b2*g1[j - 2];
+        c1 = img.ptr<T>(0);
+        c1 += i*cols + cols - 1;
+        j = cols - 1;
+        g2[j] = (a3 + a4)* *c1;
+        j--;
+        g2[j] = (a3 + a4) * c1[1] + b1 * g2[j + 1];
+        j--;
+        c1--;
+        for (j = cols - 3; j >= 0; j--, c1--)
+            g2[j] = a3*c1[1] + a4*c1[2] + b1*g2[j + 1] + b2*g2[j + 2];
+        for (j = 0; j<cols; j++, f1++)
+            *f1 = (float)(g1[j] + g2[j]);
+    }
+}
+
+class ParallelGradientDericheYCols : public ParallelLoopBody
+{
+private:
+    Mat &img;
+    Mat &dst;
+    double alphaDerive;
+    bool verbose;
+
+
+public:
+    ParallelGradientDericheYCols(Mat &imgSrc, Mat &d, double ald) :
+        img(imgSrc),
+        dst(d),
+        alphaDerive(ald),
+        verbose(false)
+    {}
+    void Verbose(bool b) { verbose = b; }
+    virtual void operator()(const Range& range) const
+    {
+        CV_Assert(img.depth()==CV_8UC1  || img.depth()==CV_8SC1  || img.depth()==CV_16SC1 || img.depth()==CV_16UC1);
+        CV_Assert(dst.depth()==CV_32FC1);
+        if (verbose)
+            std::cout << getThreadNum() << "# :Start from row " << range.start << " to " << range.end - 1 << " (" << range.end - range.start << " loops)" << std::endl;
+
+
+        switch (img.depth()) {
+        case CV_8U:
+            VerticalIIRFilter<uchar>(img,dst,range, alphaDerive);
+        break;
+        case CV_8S:
+            VerticalIIRFilter<char>(img, dst, range, alphaDerive);
+        break;
+        case CV_16U:
+            VerticalIIRFilter<ushort>(img, dst, range, alphaDerive);
+            break;
+        case CV_16S:
+            VerticalIIRFilter<short>(img, dst, range, alphaDerive);
+            break;
+        default:
+            return;
+        }
+    };
+    ParallelGradientDericheYCols& operator=(const ParallelGradientDericheYCols &) {
+        return *this;
+    };
+};
+
+
+class ParallelGradientDericheYRows : public ParallelLoopBody
+{
+private:
+    Mat &img;
+    Mat &dst;
+    double alphaMoyenne;
+    bool verbose;
+
+public:
+    ParallelGradientDericheYRows(Mat& imgSrc, Mat &d, double alm) :
+        img(imgSrc),
+        dst(d),
+        alphaMoyenne(alm),
+        verbose(false)
+    {}
+    void Verbose(bool b) { verbose = b; }
+    virtual void operator()(const Range& range) const
+    {
+        CV_Assert(img.depth()==CV_32FC1);
+        CV_Assert(dst.depth()==CV_32FC1);
+        if (verbose)
+            std::cout << getThreadNum() << "# :Start from row " << range.start << " to " << range.end - 1 << " (" << range.end - range.start << " loops)" << std::endl;
+        float *f1, *f2;
+        int tailleSequence = (img.rows>img.cols) ? img.rows : img.cols;
+        Mat matG1(1,tailleSequence,CV_64FC1), matG2(1,tailleSequence,CV_64FC1);
+        double *g1 = matG1.ptr<double>(0), *g2 = matG2.ptr<double>(0);
+        double k, a5, a6, a7, a8;
+        double b3, b4;
+        int cols = img.cols;
+
+        k = pow(1 - exp(-alphaMoyenne), 2.0) / (1 + 2 * alphaMoyenne*exp(-alphaMoyenne) - exp(-2 * alphaMoyenne));
+        a5 = k;
+        a6 = k*exp(-alphaMoyenne)*(alphaMoyenne - 1);
+        a7 = k*exp(-alphaMoyenne)*(alphaMoyenne + 1);
+        a8 = -k*exp(-2 * alphaMoyenne);
+        b3 = 2 * exp(-alphaMoyenne);
+        b4 = -exp(-2 * alphaMoyenne);
+
+        for (int i = range.start; i<range.end; i++)
+        {
+            f2 = dst.ptr<float>(i);
+            f1 = img.ptr<float>(i);
+            int j = 0;
+            g1[j] = (a5 + a6)* *f1;
+            j++;
+            f1++;
+            g1[j] = a5 * f1[0] + a6*f1[j - 1] + (b3)* g1[j - 1];
+            j++;
+            f1++;
+            for (j = 2; j<cols; j++, f1++)
+                g1[j] = a5 * f1[0] + a6 * f1[-1] + b3*g1[j - 1] + b4*g1[j - 2];
+            f1 = ((float*)img.ptr(0));
+            f1 += i*cols + cols - 1;
+            j = cols - 1;
+            g2[j] = (a7 + a8)* *f1;
+            j--;
+            f1--;
+            g2[j] = (a7 + a8) * f1[1] + (b3)* g2[j + 1];
+            j--;
+            f1--;
+            for (j = cols - 3; j >= 0; j--, f1--)
+                g2[j] = a7*f1[1] + a8*f1[2] + b3*g2[j + 1] + b4*g2[j + 2];
+            for (j = 0; j<cols; j++, f2++)
+                *f2 = (float)(g1[j] + g2[j]);
+        }
+
+    };
+    ParallelGradientDericheYRows& operator=(const ParallelGradientDericheYRows &) {
+        return *this;
+    };
+};
+
+
+class ParallelGradientDericheXCols : public ParallelLoopBody
+{
+private:
+    Mat &img;
+    Mat &dst;
+    double alphaMoyenne;
+    bool verbose;
+
+public:
+    ParallelGradientDericheXCols(Mat& imgSrc, Mat &d, double alm) :
+        img(imgSrc),
+        dst(d),
+        alphaMoyenne(alm),
+        verbose(false)
+    {}
+    void Verbose(bool b) { verbose = b; }
+    virtual void operator()(const Range& range) const
+    {
+        CV_Assert(img.depth()==CV_32FC1);
+        CV_Assert(dst.depth()==CV_32FC1);
+        if (verbose)
+            std::cout << getThreadNum() << "# :Start from row " << range.start << " to " << range.end - 1 << " (" << range.end - range.start << " loops)" << std::endl;
+        float                *f1, *f2;
+        int rows = img.rows, cols = img.cols;
+
+        int tailleSequence = (rows>cols) ? rows : cols;
+        Mat matG1(1,tailleSequence,CV_64FC1), matG2(1,tailleSequence,CV_64FC1);
+        double *g1 = (double*)matG1.ptr(0), *g2 = (double*)matG2.ptr(0);
+        double k, a5, a6, a7, a8 = 0;
+        double b3, b4;
+
+        k = pow(1 - exp(-alphaMoyenne), 2.0) / (1 + 2 * alphaMoyenne*exp(-alphaMoyenne) - exp(-2 * alphaMoyenne));
+        a5 = k, a6 = k*exp(-alphaMoyenne)*(alphaMoyenne - 1);
+        a7 = k*exp(-alphaMoyenne)*(alphaMoyenne + 1), a8 = -k*exp(-2 * alphaMoyenne);
+        b3 = 2 * exp(-alphaMoyenne);
+        b4 = -exp(-2 * alphaMoyenne);
+
+        for (int j = range.start; j<range.end; j++)
+        {
+            f1 = img.ptr<float>(0);
+            f1 += j;
+            int i = 0;
+            g1[i] = (a5 + a6)* *f1;
+            i++;
+            f1 += cols;
+            g1[i] = a5 * *f1 + a6 * f1[-cols] + (b3)* g1[i - 1];
+            i++;
+            f1 += cols;
+            for (i = 2; i<rows; i++, f1 += cols)
+                g1[i] = a5 * *f1 + a6 * f1[-cols] + b3*g1[i - 1] + b4 *g1[i - 2];
+            f1 = img.ptr<float>(0);
+            f1 += (rows - 1)*cols + j;
+            i = rows - 1;
+            g2[i] = (a7 + a8)* *f1;
+            i--;
+            f1 -= cols;
+            g2[i] = (a7 + a8)* f1[cols] + (b3)*g2[i + 1];
+            i--;
+            f1 -= cols;
+            for (i = rows - 3; i >= 0; i--, f1 -= cols)
+                g2[i] = a7*f1[cols] + a8* f1[2 * cols] +
+                b3*g2[i + 1] + b4*g2[i + 2];
+            for (i = 0; i<rows; i++, f2 += cols)
+            {
+                f2 = (dst.ptr<float>(i)) + (j*img.channels());
+                *f2 = (float)(g1[i] + g2[i]);
+            }
+        }
+    };
+    ParallelGradientDericheXCols& operator=(const ParallelGradientDericheXCols &) {
+        return *this;
+    };
+};
+
+
+class ParallelGradientDericheXRows : public ParallelLoopBody
+{
+private:
+    Mat &img;
+    Mat &dst;
+    double alphaDerive;
+    bool verbose;
+
+public:
+    ParallelGradientDericheXRows(Mat& imgSrc, Mat &d, double ald) :
+        img(imgSrc),
+        dst(d),
+        alphaDerive(ald),
+        verbose(false)
+    {}
+    void Verbose(bool b) { verbose = b; }
+    virtual void operator()(const Range& range) const
+    {
+        CV_Assert(img.depth()==CV_8UC1 || img.depth()==CV_8SC1 || img.depth()==CV_16SC1 || img.depth()==CV_16UC1);
+        CV_Assert(dst.depth()==CV_32FC1);
+        if (verbose)
+            std::cout << getThreadNum() << "# :Start from row " << range.start << " to " << range.end - 1 << " (" << range.end - range.start << " loops)" << std::endl;
+
+        switch (img.depth()) {
+        case CV_8U:
+            HorizontalIIRFilter<uchar>(img,dst,range,alphaDerive);
+            break;
+        case CV_8S:
+            HorizontalIIRFilter<char>(img, dst, range, alphaDerive);
+            break;
+        case CV_16U:
+            HorizontalIIRFilter<ushort>(img, dst, range, alphaDerive);
+            break;
+        case CV_16S:
+            HorizontalIIRFilter<short>(img, dst, range, alphaDerive);
+            break;
+        default:
+            return;
+        }
+    };
+    ParallelGradientDericheXRows& operator=(const ParallelGradientDericheXRows &) {
+        return *this;
+    };
+};
+
+void GradientDericheY(InputArray _op, OutputArray _dst,double alphaDerive, double alphaMean)
+{
+    std::vector<Mat> planSrc;
+    split(_op, planSrc);
+    std::vector<Mat> planTmp;
+    std::vector<Mat> planDst;
+    for (size_t i = 0; i < planSrc.size(); i++)
+    {
+        planTmp.push_back(Mat(_op.size(), CV_32FC1));
+        planDst.push_back(Mat(_op.size(), CV_32FC1));
+        CV_Assert(planSrc[i].isContinuous() && planTmp[i].isContinuous() && planDst[i].isContinuous());
+        ParallelGradientDericheYCols x(planSrc[i], planTmp[i], alphaDerive);
+        parallel_for_(Range(0, planSrc[i].cols), x, getNumThreads());
+        ParallelGradientDericheYRows xr(planTmp[i], planDst[i], alphaMean);
+        parallel_for_(Range(0, planTmp[i].rows), xr, getNumThreads());
+    }
+    merge(planDst, _dst);
+}
+
+void GradientDericheX(InputArray _op, OutputArray _dst, double alphaDerive, double alphaMean)
+{
+    std::vector<Mat> planSrc;
+    split(_op, planSrc);
+    std::vector<Mat> planTmp;
+    std::vector<Mat> planDst;
+    for (size_t i = 0; i < planSrc.size(); i++)
+    {
+        planTmp.push_back(Mat(_op.size(), CV_32FC1));
+        planDst.push_back(Mat(_op.size(), CV_32FC1));
+        CV_Assert(planSrc[i].isContinuous() && planTmp[i].isContinuous() && planDst[i].isContinuous());
+
+        ParallelGradientDericheXRows x(planSrc[i], planTmp[i], alphaDerive);
+        parallel_for_(Range(0, planSrc[i].rows), x, getNumThreads());
+        ParallelGradientDericheXCols xr(planTmp[i], planDst[i], alphaMean);
+        parallel_for_(Range(0, planTmp[i].cols), xr, getNumThreads());
+    }
+    merge(planDst, _dst);
+}
+
+} //end of cv::ximgproc
+} //end of cv
diff --git a/contrib/modules/ximgproc/src/disparity_filters.cpp b/contrib/modules/ximgproc/src/disparity_filters.cpp
index 63db083..77eb6ac 100644
--- a/contrib/modules/ximgproc/src/disparity_filters.cpp
+++ b/contrib/modules/ximgproc/src/disparity_filters.cpp
@@ -11,7 +11,7 @@
  *  Redistribution and use in source and binary forms, with or without modification,
  *  are permitted provided that the following conditions are met :
  *  
- *  *Redistributions of source code must retain the above copyright notice,
+ *  * Redistributions of source code must retain the above copyright notice,
  *  this list of conditions and the following disclaimer.
  *  
  *  * Redistributions in binary form must reproduce the above copyright notice,
diff --git a/contrib/modules/ximgproc/src/domain_transform.cpp b/contrib/modules/ximgproc/src/domain_transform.cpp
index 9689cbe..9569fec 100644
--- a/contrib/modules/ximgproc/src/domain_transform.cpp
+++ b/contrib/modules/ximgproc/src/domain_transform.cpp
@@ -11,7 +11,7 @@
  *  Redistribution and use in source and binary forms, with or without modification,
  *  are permitted provided that the following conditions are met :
  *  
- *  *Redistributions of source code must retain the above copyright notice,
+ *  * Redistributions of source code must retain the above copyright notice,
  *  this list of conditions and the following disclaimer.
  *  
  *  * Redistributions in binary form must reproduce the above copyright notice,
diff --git a/contrib/modules/ximgproc/src/dtfilter_cpu.cpp b/contrib/modules/ximgproc/src/dtfilter_cpu.cpp
index a908f4a..79bad42 100644
--- a/contrib/modules/ximgproc/src/dtfilter_cpu.cpp
+++ b/contrib/modules/ximgproc/src/dtfilter_cpu.cpp
@@ -11,7 +11,7 @@
  *  Redistribution and use in source and binary forms, with or without modification,
  *  are permitted provided that the following conditions are met :
  *  
- *  *Redistributions of source code must retain the above copyright notice,
+ *  * Redistributions of source code must retain the above copyright notice,
  *  this list of conditions and the following disclaimer.
  *  
  *  * Redistributions in binary form must reproduce the above copyright notice,
diff --git a/contrib/modules/ximgproc/src/dtfilter_cpu.hpp b/contrib/modules/ximgproc/src/dtfilter_cpu.hpp
index 7e92b00..89881f9 100644
--- a/contrib/modules/ximgproc/src/dtfilter_cpu.hpp
+++ b/contrib/modules/ximgproc/src/dtfilter_cpu.hpp
@@ -11,7 +11,7 @@
  *  Redistribution and use in source and binary forms, with or without modification,
  *  are permitted provided that the following conditions are met :
  *  
- *  *Redistributions of source code must retain the above copyright notice,
+ *  * Redistributions of source code must retain the above copyright notice,
  *  this list of conditions and the following disclaimer.
  *  
  *  * Redistributions in binary form must reproduce the above copyright notice,
diff --git a/contrib/modules/ximgproc/src/dtfilter_cpu.inl.hpp b/contrib/modules/ximgproc/src/dtfilter_cpu.inl.hpp
index b8d012b..73e903a 100644
--- a/contrib/modules/ximgproc/src/dtfilter_cpu.inl.hpp
+++ b/contrib/modules/ximgproc/src/dtfilter_cpu.inl.hpp
@@ -11,7 +11,7 @@
  *  Redistribution and use in source and binary forms, with or without modification,
  *  are permitted provided that the following conditions are met :
  *  
- *  *Redistributions of source code must retain the above copyright notice,
+ *  * Redistributions of source code must retain the above copyright notice,
  *  this list of conditions and the following disclaimer.
  *  
  *  * Redistributions in binary form must reproduce the above copyright notice,
diff --git a/contrib/modules/ximgproc/src/edgeaware_filters_common.cpp b/contrib/modules/ximgproc/src/edgeaware_filters_common.cpp
index 223a244..2328914 100644
--- a/contrib/modules/ximgproc/src/edgeaware_filters_common.cpp
+++ b/contrib/modules/ximgproc/src/edgeaware_filters_common.cpp
@@ -11,7 +11,7 @@
  *  Redistribution and use in source and binary forms, with or without modification,
  *  are permitted provided that the following conditions are met :
  *  
- *  *Redistributions of source code must retain the above copyright notice,
+ *  * Redistributions of source code must retain the above copyright notice,
  *  this list of conditions and the following disclaimer.
  *  
  *  * Redistributions in binary form must reproduce the above copyright notice,
diff --git a/contrib/modules/ximgproc/src/edgeaware_filters_common.hpp b/contrib/modules/ximgproc/src/edgeaware_filters_common.hpp
index 7ed217b..e45d397 100644
--- a/contrib/modules/ximgproc/src/edgeaware_filters_common.hpp
+++ b/contrib/modules/ximgproc/src/edgeaware_filters_common.hpp
@@ -11,7 +11,7 @@
  *  Redistribution and use in source and binary forms, with or without modification,
  *  are permitted provided that the following conditions are met :
  *  
- *  *Redistributions of source code must retain the above copyright notice,
+ *  * Redistributions of source code must retain the above copyright notice,
  *  this list of conditions and the following disclaimer.
  *  
  *  * Redistributions in binary form must reproduce the above copyright notice,
diff --git a/contrib/modules/ximgproc/src/fast_line_detector.cpp b/contrib/modules/ximgproc/src/fast_line_detector.cpp
new file mode 100644
index 0000000..625e14e
--- /dev/null
+++ b/contrib/modules/ximgproc/src/fast_line_detector.cpp
@@ -0,0 +1,730 @@
+// This file is part of OpenCV project.
+// It is subject to the license terms in the LICENSE file found in the top-level directory
+// of this distribution and at http://opencv.org/license.html.
+
+#include "precomp.hpp"
+#include <vector>
+#include <iostream>
+
+struct SEGMENT
+{
+    float x1, y1, x2, y2, angle;
+};
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+namespace cv{
+namespace ximgproc{
+
+class FastLineDetectorImpl : public FastLineDetector
+{
+    public:
+        /**
+         * @param _length_threshold    10         - Segment shorter than this will be discarded
+         * @param _distance_threshold  1.41421356 - A point placed from a hypothesis line segment
+         *                                          farther than this will be regarded as an outlier
+         * @param _canny_th1           50         - First threshold for
+         *        _                                 hysteresis procedure in Canny()
+         * @param _canny_th2           50         - Second threshold for
+         *        _                                 hysteresis procedure in Canny()
+         * @param _canny_aperture_size 3          - Aperturesize for the sobel
+         *        _                                 operator in Canny()
+         * @param _do_merge            false      - If true, incremental merging of segments
+                                                   will be perfomred
+         */
+        FastLineDetectorImpl(int _length_threshold = 10, float _distance_threshold = 1.414213562f,
+                double _canny_th1 = 50.0, double _canny_th2 = 50.0, int _canny_aperture_size = 3,
+                bool _do_merge = false);
+
+        /**
+         * Detect lines in the input image.
+         *
+         * @param _image    A grayscale(CV_8UC1) input image.
+         *                  If only a roi needs to be selected, use
+         *                  lsd_ptr->detect(image(roi), ..., lines);
+         *                  lines += Scalar(roi.x, roi.y, roi.x, roi.y);
+         * @param _lines    Return: A vector of Vec4f elements specifying the beginning and ending point of
+         *                  a line. Where Vec4f is (x1, y1, x2, y2), point 1 is the start, point 2 is the end.
+         *                  Returned lines are directed so that the brighter side is placed on left.
+         */
+        void detect(InputArray _image, OutputArray _lines);
+
+        /**
+         * Draw lines on the given canvas.
+         *
+         * @param image          The image, where lines will be drawn
+         *                       Should have the size of the image, where the lines were found
+         * @param lines          The lines that need to be drawn
+         * @param draw_arrow     If true, arrow heads will be drawn
+         */
+        void drawSegments(InputOutputArray _image, InputArray lines, bool draw_arrow = false);
+
+    private:
+        int imagewidth, imageheight, threshold_length;
+        float threshold_dist;
+        double canny_th1, canny_th2;
+        int canny_aperture_size;
+        bool do_merge;
+
+        FastLineDetectorImpl& operator= (const FastLineDetectorImpl&); // to quiet MSVC
+        template<class T>
+            void incidentPoint(const Mat& l, T& pt);
+
+        void mergeLines(const SEGMENT& seg1, const SEGMENT& seg2, SEGMENT& seg_merged);
+
+        bool mergeSegments(const SEGMENT& seg1, const SEGMENT& seg2, SEGMENT& seg_merged);
+
+        bool getPointChain(const Mat& img, Point pt, Point& chained_pt, float& direction, int step);
+
+        double distPointLine(const Mat& p, Mat& l);
+
+        void extractSegments(const std::vector<Point2i>& points, std::vector<SEGMENT>& segments );
+
+        void lineDetection(const Mat& src, std::vector<SEGMENT>& segments_all);
+
+        void pointInboardTest(const Mat& src, Point2i& pt);
+
+        inline void getAngle(SEGMENT& seg);
+
+        void additionalOperationsOnSegment(const Mat& src, SEGMENT& seg);
+
+        void drawSegment(Mat& mat, const SEGMENT& seg, Scalar bgr = Scalar(0,255,0),
+                int thickness = 1, bool directed = true);
+};
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+CV_EXPORTS Ptr<FastLineDetector> createFastLineDetector(
+        int _length_threshold, float _distance_threshold,
+        double _canny_th1, double _canny_th2, int _canny_aperture_size, bool _do_merge)
+{
+    return makePtr<FastLineDetectorImpl>(
+            _length_threshold, _distance_threshold,
+            _canny_th1, _canny_th2, _canny_aperture_size, _do_merge);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+FastLineDetectorImpl::FastLineDetectorImpl(int _length_threshold, float _distance_threshold,
+        double _canny_th1, double _canny_th2, int _canny_aperture_size, bool _do_merge)
+    :threshold_length(_length_threshold), threshold_dist(_distance_threshold),
+    canny_th1(_canny_th1), canny_th2(_canny_th2), canny_aperture_size(_canny_aperture_size), do_merge(_do_merge)
+{
+    CV_Assert(_length_threshold > 0 && _distance_threshold > 0 &&
+            _canny_th1 > 0 && _canny_th2 > 0 && _canny_aperture_size > 0);
+}
+
+void FastLineDetectorImpl::detect(InputArray _image, OutputArray _lines)
+{
+    CV_INSTRUMENT_REGION();
+
+    Mat image = _image.getMat();
+    CV_Assert(!image.empty() && image.type() == CV_8UC1);
+
+    std::vector<Vec4f> lines;
+    std::vector<SEGMENT> segments;
+    lineDetection(image, segments);
+    for(size_t i = 0; i < segments.size(); ++i)
+    {
+        const SEGMENT seg = segments[i];
+        Vec4f line(seg.x1, seg.y1, seg.x2, seg.y2);
+        lines.push_back(line);
+    }
+    Mat(lines).copyTo(_lines);
+}
+
+void FastLineDetectorImpl::drawSegments(InputOutputArray _image, InputArray lines, bool draw_arrow)
+{
+    CV_INSTRUMENT_REGION();
+
+    CV_Assert(!_image.empty() && (_image.channels() == 1 || _image.channels() == 3));
+
+    Mat gray;
+    if (_image.channels() == 1)
+    {
+        gray = _image.getMatRef();
+    }
+    else if (_image.channels() == 3)
+    {
+        cvtColor(_image, gray, COLOR_BGR2GRAY);
+    }
+
+    // Create a 3 channel image in order to draw colored lines
+    std::vector<Mat> planes;
+    planes.push_back(gray);
+    planes.push_back(gray);
+    planes.push_back(gray);
+
+    merge(planes, _image);
+
+    double gap = 10.0;
+    double arrow_angle = 30.0;
+
+    Mat _lines;
+    _lines = lines.getMat();
+    int N = _lines.checkVector(4);
+    // Draw segments
+    for(int i = 0; i < N; ++i)
+    {
+        const Vec4f& v = _lines.at<Vec4f>(i);
+        Point2f b(v[0], v[1]);
+        Point2f e(v[2], v[3]);
+        line(_image.getMatRef(), b, e, Scalar(0, 0, 255), 1);
+        if(draw_arrow)
+        {
+            SEGMENT seg;
+            seg.x1 = b.x;
+            seg.y1 = b.y;
+            seg.x2 = e.x;
+            seg.y2 = e.y;
+            getAngle(seg);
+            double ang = (double)seg.angle;
+            Point2i p1;
+            p1.x = (int)round(seg.x2 - gap*cos(arrow_angle * CV_PI / 180.0 + ang));
+            p1.y = (int)round(seg.y2 - gap*sin(arrow_angle * CV_PI / 180.0 + ang));
+            pointInboardTest(_image.getMatRef(), p1);
+            line(_image.getMatRef(), Point((int)round(seg.x2), (int)round(seg.y2)), p1, Scalar(0,0,255), 1);
+        }
+    }
+}
+
+void FastLineDetectorImpl::mergeLines(const SEGMENT& seg1, const SEGMENT& seg2, SEGMENT& seg_merged)
+{
+    double xg = 0.0, yg = 0.0;
+    double delta1x = 0.0, delta1y = 0.0, delta2x = 0.0, delta2y = 0.0;
+    float ax = 0, bx = 0, cx = 0, dx = 0;
+    float ay = 0, by = 0, cy = 0, dy = 0;
+    double li = 0.0, lj = 0.0;
+    double thi = 0.0, thj = 0.0, thr = 0.0;
+    double axg = 0.0, bxg = 0.0, cxg = 0.0, dxg = 0.0, delta1xg = 0.0, delta2xg = 0.0;
+
+    ax = seg1.x1;
+    ay = seg1.y1;
+
+    bx = seg1.x2;
+    by = seg1.y2;
+    cx = seg2.x1;
+    cy = seg2.y1;
+
+    dx = seg2.x2;
+    dy = seg2.y2;
+
+    float dlix = (bx - ax);
+    float dliy = (by - ay);
+    float dljx = (dx - cx);
+    float dljy = (dy - cy);
+
+    li = sqrt((double) (dlix * dlix) + (double) (dliy * dliy));
+    lj = sqrt((double) (dljx * dljx) + (double) (dljy * dljy));
+
+    xg = (li * (double) (ax + bx) + lj * (double) (cx + dx))
+        / (double) (2.0 * (li + lj));
+    yg = (li * (double) (ay + by) + lj * (double) (cy + dy))
+        / (double) (2.0 * (li + lj));
+
+    if(dlix == 0.0f) thi = CV_PI / 2.0;
+    else thi = atan(dliy / dlix);
+
+    if(dljx == 0.0f) thj = CV_PI / 2.0;
+    else thj = atan(dljy / dljx);
+
+    if (fabs(thi - thj) <= CV_PI / 2.0)
+    {
+        thr = (li * thi + lj * thj) / (li + lj);
+    }
+    else
+    {
+        double tmp = thj - CV_PI * (thj / fabs(thj));
+        thr = li * thi + lj * tmp;
+        thr /= (li + lj);
+    }
+
+    axg = ((double) ay - yg) * sin(thr) + ((double) ax - xg) * cos(thr);
+    bxg = ((double) by - yg) * sin(thr) + ((double) bx - xg) * cos(thr);
+    cxg = ((double) cy - yg) * sin(thr) + ((double) cx - xg) * cos(thr);
+    dxg = ((double) dy - yg) * sin(thr) + ((double) dx - xg) * cos(thr);
+
+    delta1xg = min(axg,min(bxg,min(cxg,dxg)));
+    delta2xg = max(axg,max(bxg,max(cxg,dxg)));
+
+    delta1x = delta1xg * cos(thr) + xg;
+    delta1y = delta1xg * sin(thr) + yg;
+    delta2x = delta2xg * cos(thr) + xg;
+    delta2y = delta2xg * sin(thr) + yg;
+
+    seg_merged.x1 = (float)delta1x;
+    seg_merged.y1 = (float)delta1y;
+    seg_merged.x2 = (float)delta2x;
+    seg_merged.y2 = (float)delta2y;
+}
+
+double FastLineDetectorImpl::distPointLine(const Mat& p, Mat& l)
+{
+    double x = l.at<double>(0,0);
+    double y = l.at<double>(1,0);
+    double w = sqrt(x*x+y*y);
+
+    l.at<double>(0,0) = x / w;
+    l.at<double>(1,0) = y / w;
+    l.at<double>(2,0) = l.at<double>(2,0) / w;
+
+    return l.dot(p);
+}
+
+bool FastLineDetectorImpl::mergeSegments(const SEGMENT& seg1, const SEGMENT& seg2, SEGMENT& seg_merged)
+{
+    double o[] = { 0.0, 0.0, 1.0 };
+    double a[] = { 0.0, 0.0, 1.0 };
+    double b[] = { 0.0, 0.0, 1.0 };
+    double c[3];
+
+    o[0] = ( seg2.x1 + seg2.x2 ) / 2.0;
+    o[1] = ( seg2.y1 + seg2.y2 ) / 2.0;
+
+    a[0] = seg1.x1;
+    a[1] = seg1.y1;
+    b[0] = seg1.x2;
+    b[1] = seg1.y2;
+
+    Mat ori = Mat(3, 1, CV_64FC1, o).clone();
+    Mat p1 = Mat(3, 1, CV_64FC1, a).clone();
+    Mat p2 = Mat(3, 1, CV_64FC1, b).clone();
+    Mat l1 = Mat(3, 1, CV_64FC1, c).clone();
+
+    l1 = p1.cross(p2);
+
+    Point2f seg1mid, seg2mid;
+    seg1mid.x = (seg1.x1 + seg1.x2) /2.0f;
+    seg1mid.y = (seg1.y1 + seg1.y2) /2.0f;
+    seg2mid.x = (seg2.x1 + seg2.x2) /2.0f;
+    seg2mid.y = (seg2.y1 + seg2.y2) /2.0f;
+
+    float seg1len = sqrt((seg1.x1 - seg1.x2)*(seg1.x1 - seg1.x2)+(seg1.y1 - seg1.y2)*(seg1.y1 - seg1.y2));
+    float seg2len = sqrt((seg2.x1 - seg2.x2)*(seg2.x1 - seg2.x2)+(seg2.y1 - seg2.y2)*(seg2.y1 - seg2.y2));
+    float middist = sqrt((seg1mid.x - seg2mid.x)*(seg1mid.x - seg2mid.x) + (seg1mid.y - seg2mid.y)*(seg1mid.y - seg2mid.y));
+    float angdiff = fabs(seg1.angle - seg2.angle);
+
+    float dist = (float)distPointLine(ori, l1);
+
+    if ( fabs( dist ) <= threshold_dist * 2.0f && middist <= seg1len / 2.0f + seg2len / 2.0f + 20.0f
+            && angdiff <= CV_PI / 180.0f * 5.0f)
+    {
+        mergeLines(seg1, seg2, seg_merged);
+        return true;
+    }
+    else
+    {
+        return false;
+    }
+}
+
+template<class T>
+    void FastLineDetectorImpl::incidentPoint(const Mat& l, T& pt)
+    {
+        double a[] = { (double)pt.x, (double)pt.y, 1.0 };
+        double b[] = { l.at<double>(0,0), l.at<double>(1,0), 0.0 };
+        double c[3];
+
+        Mat xk = Mat(3, 1, CV_64FC1, a).clone();
+        Mat lh = Mat(3, 1, CV_64FC1, b).clone();
+        Mat lk = Mat(3, 1, CV_64FC1, c).clone();
+
+        lk = xk.cross(lh);
+        xk = lk.cross(l);
+
+        xk.convertTo(xk, -1, 1.0 / xk.at<double>(2,0));
+
+        Point2f pt_tmp;
+        pt_tmp.x = (float)xk.at<double>(0,0) < 0.0f ? 0.0f : (float)xk.at<double>(0,0)
+            >= (imagewidth - 1.0f) ? (imagewidth - 1.0f) : (float)xk.at<double>(0,0);
+        pt_tmp.y = (float)xk.at<double>(1,0) < 0.0f ? 0.0f : (float)xk.at<double>(1,0)
+            >= (imageheight - 1.0f) ? (imageheight - 1.0f) : (float)xk.at<double>(1,0);
+        pt = T(pt_tmp);
+    }
+
+void FastLineDetectorImpl::extractSegments(const std::vector<Point2i>& points, std::vector<SEGMENT>& segments )
+{
+    bool is_line;
+
+    int i, j;
+    SEGMENT seg;
+    Point2i ps, pe, pt;
+
+    std::vector<Point2i> l_points;
+
+    int total = (int)points.size();
+
+    for ( i = 0; i + threshold_length < total; i++ )
+    {
+        ps = points[i];
+        pe = points[i + threshold_length];
+
+        double a[] = { (double)ps.x, (double)ps.y, 1 };
+        double b[] = { (double)pe.x, (double)pe.y, 1 };
+        double c[3], d[3];
+
+        Mat p1 = Mat(3, 1, CV_64FC1, a).clone();
+        Mat p2 = Mat(3, 1, CV_64FC1, b).clone();
+        Mat p = Mat(3, 1, CV_64FC1, c).clone();
+        Mat l = Mat(3, 1, CV_64FC1, d).clone();
+        l = p1.cross(p2);
+
+        is_line = true;
+
+        l_points.clear();
+        l_points.push_back(ps);
+
+        for ( j = 1; j < threshold_length; j++ )
+        {
+            pt.x = points[i+j].x;
+            pt.y = points[i+j].y;
+
+            p.at<double>(0,0) = (double)pt.x;
+            p.at<double>(1,0) = (double)pt.y;
+            p.at<double>(2,0) = 1.0;
+
+            double dist = distPointLine(p, l);
+
+            if ( fabs( dist ) > threshold_dist )
+            {
+                is_line = false;
+                break;
+            }
+            l_points.push_back(pt);
+        }
+
+        // Line check fail, test next point
+        if ( is_line == false )
+            continue;
+
+        l_points.push_back(pe);
+
+        Vec4f line;
+        fitLine( Mat(l_points), line, DIST_L2, 0, 0.01, 0.01);
+        a[0] = line[2];
+        a[1] = line[3];
+        b[0] = line[2] + line[0];
+        b[1] = line[3] + line[1];
+
+        p1 = Mat(3, 1, CV_64FC1, a).clone();
+        p2 = Mat(3, 1, CV_64FC1, b).clone();
+
+        l = p1.cross(p2);
+
+        incidentPoint(l, ps);
+
+        // Extending line
+        for ( j = threshold_length + 1; i + j < total; j++ )
+        {
+            pt.x = points[i+j].x;
+            pt.y = points[i+j].y;
+
+            p.at<double>(0,0) = (double)pt.x;
+            p.at<double>(1,0) = (double)pt.y;
+            p.at<double>(2,0) = 1.0;
+
+            double dist = distPointLine(p, l);
+            if ( fabs( dist ) > threshold_dist )
+            {
+                fitLine( Mat(l_points), line, DIST_L2, 0, 0.01, 0.01);
+                a[0] = line[2];
+                a[1] = line[3];
+                b[0] = line[2] + line[0];
+                b[1] = line[3] + line[1];
+
+                p1 = Mat(3, 1, CV_64FC1, a).clone();
+                p2 = Mat(3, 1, CV_64FC1, b).clone();
+
+                l = p1.cross(p2);
+                dist = distPointLine(p, l);
+                if ( fabs( dist ) > threshold_dist ) {
+                    j--;
+                    break;
+                }
+            }
+            pe = pt;
+            l_points.push_back(pt);
+        }
+        fitLine( Mat(l_points), line, DIST_L2, 0, 0.01, 0.01);
+        a[0] = line[2];
+        a[1] = line[3];
+        b[0] = line[2] + line[0];
+        b[1] = line[3] + line[1];
+
+        p1 = Mat(3, 1, CV_64FC1, a).clone();
+        p2 = Mat(3, 1, CV_64FC1, b).clone();
+
+        l = p1.cross(p2);
+
+        Point2f e1, e2;
+        e1.x = (float)ps.x;
+        e1.y = (float)ps.y;
+        e2.x = (float)pe.x;
+        e2.y = (float)pe.y;
+
+        incidentPoint(l, e1);
+        incidentPoint(l, e2);
+        seg.x1 = e1.x;
+        seg.y1 = e1.y;
+        seg.x2 = e2.x;
+        seg.y2 = e2.y;
+
+        segments.push_back(seg);
+        i = i + j;
+    }
+}
+
+void FastLineDetectorImpl::pointInboardTest(const Mat& src, Point2i& pt)
+{
+    pt.x = pt.x <= 5 ? 5 : pt.x >= src.cols - 5 ? src.cols - 5 : pt.x;
+    pt.y = pt.y <= 5 ? 5 : pt.y >= src.rows - 5 ? src.rows - 5 : pt.y;
+}
+
+bool FastLineDetectorImpl::getPointChain(const Mat& img, Point pt,
+        Point& chained_pt, float& direction, int step)
+{
+    int ri, ci;
+    int indices[8][2] = { {1,1}, {1,0}, {1,-1}, {0,-1},
+        {-1,-1},{-1,0}, {-1,1}, {0,1} };
+
+    float min_dir_diff = 7.0f;
+    Point consistent_pt;
+    int consistent_direction = 0;
+    for ( int i = 0; i < 8; i++ )
+    {
+        ci = pt.x + indices[i][1];
+        ri = pt.y + indices[i][0];
+
+        if ( ri < 0 || ri == img.rows || ci < 0 || ci == img.cols )
+            continue;
+
+        if ( img.at<unsigned char>(ri, ci) == 0 )
+            continue;
+
+        if(step == 0)
+        {
+            chained_pt.x = ci;
+            chained_pt.y = ri;
+            // direction = (float)i;
+            direction = i > 4 ? (float)(i - 8) : (float)i;
+            return true;
+        }
+        else
+        {
+            float curr_dir = i > 4 ? (float)(i - 8) : (float)i;
+            float dir_diff = abs(curr_dir - direction);
+            dir_diff = dir_diff > 4.0f ? 8.0f - dir_diff : dir_diff;
+            if(dir_diff <= min_dir_diff)
+            {
+                min_dir_diff = dir_diff;
+                consistent_pt.x = ci;
+                consistent_pt.y = ri;
+                consistent_direction = i > 4 ? i - 8 : i;
+            }
+        }
+    }
+    if(min_dir_diff < 2.0f)
+    {
+        chained_pt.x = consistent_pt.x;
+        chained_pt.y = consistent_pt.y;
+        direction = (direction * (float)step + (float)consistent_direction)
+            / (float)(step + 1);
+        return true;
+    }
+    return false;
+}
+
+void FastLineDetectorImpl::lineDetection(const Mat& src, std::vector<SEGMENT>& segments_all)
+{
+    int r, c;
+    imageheight=src.rows; imagewidth=src.cols;
+
+    std::vector<Point2i> points;
+    std::vector<SEGMENT> segments, segments_tmp;
+    Mat canny;
+    Canny(src, canny, canny_th1, canny_th2, canny_aperture_size);
+
+    canny.colRange(0,6).rowRange(0,6) = 0;
+    canny.colRange(src.cols-5,src.cols).rowRange(src.rows-5,src.rows) = 0;
+
+    SEGMENT seg, seg1, seg2;
+
+    for ( r = 0; r < imageheight; r++ )
+    {
+        for ( c = 0; c < imagewidth; c++ )
+        {
+            // Find seeds - skip for non-seeds
+            if ( canny.at<unsigned char>(r,c) == 0 )
+                continue;
+
+            // Found seeds
+            Point2i pt = Point2i(c,r);
+
+            points.push_back(pt);
+            canny.at<unsigned char>(pt.y, pt.x) = 0;
+
+            float direction = 0.0f;
+            int step = 0;
+            while(getPointChain(canny, pt, pt, direction, step))
+            {
+                points.push_back(pt);
+                step++;
+                canny.at<unsigned char>(pt.y, pt.x) = 0;
+            }
+
+            if ( points.size() < (unsigned int)threshold_length + 1 )
+            {
+                points.clear();
+                continue;
+            }
+
+            extractSegments(points, segments);
+
+            if ( segments.size() == 0 )
+            {
+                points.clear();
+                continue;
+            }
+            for ( int i = 0; i < (int)segments.size(); i++ )
+            {
+                seg = segments[i];
+                float length = sqrt((seg.x1 - seg.x2)*(seg.x1 - seg.x2) +
+                        (seg.y1 - seg.y2)*(seg.y1 - seg.y2));
+                if(length < threshold_length)
+                    continue;
+                if( (seg.x1 <= 5.0f && seg.x2 <= 5.0f) ||
+                    (seg.y1 <= 5.0f && seg.y2 <= 5.0f) ||
+                    (seg.x1 >= imagewidth - 5.0f && seg.x2 >= imagewidth - 5.0f) ||
+                    (seg.y1 >= imageheight - 5.0f && seg.y2 >= imageheight - 5.0f) )
+                    continue;
+                additionalOperationsOnSegment(src, seg);
+                if(!do_merge)
+                    segments_all.push_back(seg);
+                segments_tmp.push_back(seg);
+            }
+            points.clear();
+            segments.clear();
+        }
+    }
+    if(!do_merge)
+        return;
+
+    bool is_merged = false;
+    int ith = (int)segments_tmp.size() - 1;
+    int jth = ith - 1;
+    while(ith > 1 || jth > 0)
+    {
+        seg1 = segments_tmp[ith];
+        seg2 = segments_tmp[jth];
+        SEGMENT seg_merged;
+        is_merged = mergeSegments(seg1, seg2, seg_merged);
+        if(is_merged == true)
+        {
+            seg2 = seg_merged;
+            additionalOperationsOnSegment(src, seg2);
+            std::vector<SEGMENT>::iterator it = segments_tmp.begin() + ith;
+            *it = seg2;
+            segments_tmp.erase(segments_tmp.begin()+jth);
+            ith--;
+            jth = ith - 1;
+        }
+        else
+        {
+            jth--;
+        }
+        if(jth < 0) {
+            ith--;
+            jth = ith - 1;
+        }
+    }
+    segments_all = segments_tmp;
+}
+
+inline void FastLineDetectorImpl::getAngle(SEGMENT& seg)
+{
+    seg.angle = (float)(fastAtan2(seg.y2 - seg.y1, seg.x2 - seg.x1) / 180.0f * CV_PI);
+}
+
+void FastLineDetectorImpl::additionalOperationsOnSegment(const Mat& src, SEGMENT& seg)
+{
+    if(seg.x1 == 0.0f && seg.x2 == 0.0f && seg.y1 == 0.0f && seg.y2 == 0.0f)
+        return;
+
+    getAngle(seg);
+    double ang = (double)seg.angle;
+
+    Point2f start = Point2f(seg.x1, seg.y1);
+    Point2f end = Point2f(seg.x2, seg.y2);
+
+    double dx = 0.0, dy = 0.0;
+    dx = (double) end.x - (double) start.x;
+    dy = (double) end.y - (double) start.y;
+
+    int num_points = 10;
+    Point2f *points = new Point2f[num_points];
+
+    points[0] = start;
+    points[num_points - 1] = end;
+    for (int i = 0; i < num_points; i++)
+    {
+        if (i == 0 || i == num_points - 1)
+            continue;
+        points[i].x = points[0].x + ((float)dx / float(num_points - 1) * (float) i);
+        points[i].y = points[0].y + ((float)dy / float(num_points - 1) * (float) i);
+    }
+
+    Point2i *points_right = new Point2i[num_points];
+    Point2i *points_left = new Point2i[num_points];
+    double gap = 1.0;
+
+    for(int i = 0; i < num_points; i++)
+    {
+        points_right[i].x = cvRound(points[i].x + gap*cos(90.0 * CV_PI / 180.0 + ang));
+        points_right[i].y = cvRound(points[i].y + gap*sin(90.0 * CV_PI / 180.0 + ang));
+        points_left[i].x = cvRound(points[i].x - gap*cos(90.0 * CV_PI / 180.0 + ang));
+        points_left[i].y = cvRound(points[i].y - gap*sin(90.0 * CV_PI / 180.0 + ang));
+        pointInboardTest(src, points_right[i]);
+        pointInboardTest(src, points_left[i]);
+    }
+
+    int iR = 0, iL = 0;
+    for(int i = 0; i < num_points; i++)
+    {
+        iR += src.at<unsigned char>(points_right[i].y, points_right[i].x);
+        iL += src.at<unsigned char>(points_left[i].y, points_left[i].x);
+    }
+
+    if(iR > iL)
+    {
+        std::swap(seg.x1, seg.x2);
+        std::swap(seg.y1, seg.y2);
+        getAngle(seg);
+    }
+
+    delete[] points;
+    delete[] points_right;
+    delete[] points_left;
+
+    return;
+}
+
+void FastLineDetectorImpl::drawSegment(Mat& mat, const SEGMENT& seg, Scalar bgr, int thickness, bool directed)
+{
+    double gap = 10.0;
+    double ang = (double)seg.angle;
+    double arrow_angle = 30.0;
+
+    Point2i p1;
+    p1.x = (int)round(seg.x2 - gap*cos(arrow_angle * CV_PI / 180.0 + ang));
+    p1.y = (int)round(seg.y2 - gap*sin(arrow_angle * CV_PI / 180.0 + ang));
+    pointInboardTest(mat, p1);
+
+    line(mat, Point((int)round(seg.x1), (int)round(seg.y1)),
+            Point((int)round(seg.x2), (int)round(seg.y2)), bgr, thickness, 1);
+    if(directed)
+        line(mat, Point((int)round(seg.x2), (int)round(seg.y2)), p1, bgr, thickness, 1);
+}
+} // namespace cv
+} // namespace ximgproc
diff --git a/contrib/modules/ximgproc/src/fgs_filter.cpp b/contrib/modules/ximgproc/src/fgs_filter.cpp
index 39307e5..f9f17ed 100644
--- a/contrib/modules/ximgproc/src/fgs_filter.cpp
+++ b/contrib/modules/ximgproc/src/fgs_filter.cpp
@@ -11,7 +11,7 @@
  *  Redistribution and use in source and binary forms, with or without modification,
  *  are permitted provided that the following conditions are met :
  *
- *  *Redistributions of source code must retain the above copyright notice,
+ *  * Redistributions of source code must retain the above copyright notice,
  *  this list of conditions and the following disclaimer.
  *
  *  * Redistributions in binary form must reproduce the above copyright notice,
diff --git a/contrib/modules/ximgproc/src/graphsegmentation.cpp b/contrib/modules/ximgproc/src/graphsegmentation.cpp
index 7e03446..f81eb67 100644
--- a/contrib/modules/ximgproc/src/graphsegmentation.cpp
+++ b/contrib/modules/ximgproc/src/graphsegmentation.cpp
@@ -47,6 +47,56 @@ namespace cv {
     namespace ximgproc {
         namespace segmentation {
 
+            // Helpers
+
+            // Represent an edge between two pixels
+            class Edge {
+                public:
+                    int from;
+                    int to;
+                    float weight;
+
+                    bool operator <(const Edge& e) const {
+                        return weight < e.weight;
+                    }
+            };
+
+            // A point in the sets of points
+            class PointSetElement {
+                public:
+                    int p;
+                    int size;
+
+                    PointSetElement() { }
+
+                    PointSetElement(int p_) {
+                        p = p_;
+                        size = 1;
+                    }
+            };
+
+            // An object to manage set of points, who can be fusionned
+            class PointSet {
+                public:
+                    PointSet(int nb_elements_);
+                    ~PointSet();
+
+                    int nb_elements;
+
+                    // Return the main point of the point's set
+                    int getBasePoint(int p);
+
+                    // Join two sets of points, based on their main point
+                    void joinPoints(int p_a, int p_b);
+
+                    // Return the set size of a set (based on the main point)
+                    int size(unsigned int p) { return mapping[p].size; }
+
+                private:
+                    PointSetElement* mapping;
+
+            };
+
             class GraphSegmentationImpl : public GraphSegmentation {
                 public:
                     GraphSegmentationImpl() {
@@ -193,6 +243,8 @@ namespace cv {
                         }
                     }
                 }
+
+                delete [] thresholds;
             }
 
             void GraphSegmentationImpl::filterSmallAreas(Edge *edges, const int &nb_edges, PointSet *es) {
@@ -247,6 +299,8 @@ namespace cv {
                         p[j] = mapped_id[point];
                     }
                 }
+
+                delete [] mapped_id;
             }
 
             void GraphSegmentationImpl::processImage(InputArray src, OutputArray dst) {
@@ -278,6 +332,9 @@ namespace cv {
                 // Map to final output
                 finalMapping(es, output);
 
+                delete [] edges;
+                delete es;
+
             }
 
             Ptr<GraphSegmentation> createGraphSegmentation(double sigma, float k, int min_size) {
@@ -301,6 +358,10 @@ namespace cv {
                 }
             }
 
+            PointSet::~PointSet() {
+                delete [] mapping;
+            }
+
             int PointSet::getBasePoint( int p) {
 
                  int base_p = p;
@@ -326,6 +387,7 @@ namespace cv {
 
                 nb_elements--;
             }
+
         }
     }
 }
diff --git a/contrib/modules/ximgproc/src/guided_filter.cpp b/contrib/modules/ximgproc/src/guided_filter.cpp
index 502679e..1a5f793 100644
--- a/contrib/modules/ximgproc/src/guided_filter.cpp
+++ b/contrib/modules/ximgproc/src/guided_filter.cpp
@@ -11,7 +11,7 @@
  *  Redistribution and use in source and binary forms, with or without modification,
  *  are permitted provided that the following conditions are met :
  *  
- *  *Redistributions of source code must retain the above copyright notice,
+ *  * Redistributions of source code must retain the above copyright notice,
  *  this list of conditions and the following disclaimer.
  *  
  *  * Redistributions in binary form must reproduce the above copyright notice,
@@ -424,6 +424,13 @@ void GuidedFilterImpl::ComputeCovGuideInv_ParBody::operator()(const Range& range
                     add_mul(det, a, ac, gf.w);
             }
 
+            if (gf.eps < 1e-2)
+            {
+                for (int j = 0; j < gf.w; j++)
+                    if (abs(det[j]) < 1e-6f)
+                        det[j] = 1.f;
+            }
+
             for (int k = 0; k < gf.covarsInv.total(); k += 1)
             {
                 div_1x(gf.covarsInv(k).ptr<float>(i), det, gf.w);
@@ -788,4 +795,4 @@ void guidedFilter(InputArray guide, InputArray src, OutputArray dst, int radius,
 }
 
 }
-}
\ No newline at end of file
+}
diff --git a/contrib/modules/ximgproc/src/joint_bilateral_filter.cpp b/contrib/modules/ximgproc/src/joint_bilateral_filter.cpp
index 5bc7dc6..433e21a 100644
--- a/contrib/modules/ximgproc/src/joint_bilateral_filter.cpp
+++ b/contrib/modules/ximgproc/src/joint_bilateral_filter.cpp
@@ -11,7 +11,7 @@
  *  Redistribution and use in source and binary forms, with or without modification,
  *  are permitted provided that the following conditions are met :
  *  
- *  *Redistributions of source code must retain the above copyright notice,
+ *  * Redistributions of source code must retain the above copyright notice,
  *  this list of conditions and the following disclaimer.
  *  
  *  * Redistributions in binary form must reproduce the above copyright notice,
diff --git a/contrib/modules/ximgproc/src/l0_smooth.cpp b/contrib/modules/ximgproc/src/l0_smooth.cpp
index bbc487e..65b1b7e 100644
--- a/contrib/modules/ximgproc/src/l0_smooth.cpp
+++ b/contrib/modules/ximgproc/src/l0_smooth.cpp
@@ -11,7 +11,7 @@
  *  Redistribution and use in source and binary forms, with or without modification,
  *  are permitted provided that the following conditions are met :
  *
- *  *Redistributions of source code must retain the above copyright notice,
+ *  * Redistributions of source code must retain the above copyright notice,
  *  this list of conditions and the following disclaimer.
  *
  *  * Redistributions in binary form must reproduce the above copyright notice,
@@ -212,14 +212,6 @@ namespace
         D.copyTo(dst);
     }
 
-    void addComplex(InputArray aSrc, int bSrc, OutputArray dst)
-    {
-        Mat panels[2];
-        split(aSrc.getMat(), panels);
-        panels[0] = panels[0] + bSrc;
-        merge(panels, 2, dst);
-    }
-
     void divComplexByRealMultiChannel(vector<Mat> &numer,
         vector<Mat> &denom, vector<Mat> &dst)
     {
diff --git a/contrib/modules/ximgproc/src/lsc.cpp b/contrib/modules/ximgproc/src/lsc.cpp
index 25247e0..1575406 100644
--- a/contrib/modules/ximgproc/src/lsc.cpp
+++ b/contrib/modules/ximgproc/src/lsc.cpp
@@ -274,10 +274,10 @@ void SuperpixelLSCImpl::getLabelContourMask(OutputArray _mask, bool _thick_line)
 
     if ( !_thick_line ) line_width = 1;
 
-    _mask.create( m_height, m_width, CV_8SC1 );
+    _mask.create( m_height, m_width, CV_8UC1 );
     Mat mask = _mask.getMat();
 
-    mask.setTo(1);
+    mask.setTo(0);
 
     const int dx8[8] = { -1, -1,  0,  1, 1, 1, 0, -1 };
     const int dy8[8] = {  0, -1, -1, -1, 0, 1, 1,  1 };
@@ -309,7 +309,7 @@ void SuperpixelLSCImpl::getLabelContourMask(OutputArray _mask, bool _thick_line)
         }
         if( np > line_width )
         {
-           mask.at<char>(j,k) = -1;
+           mask.at<char>(j,k) = (uchar)255;
            istaken[mainindex] = true;
         }
         mainindex++;
diff --git a/contrib/modules/ximgproc/src/niblack_thresholding.cpp b/contrib/modules/ximgproc/src/niblack_thresholding.cpp
index 7167e6d..f2ee962 100644
--- a/contrib/modules/ximgproc/src/niblack_thresholding.cpp
+++ b/contrib/modules/ximgproc/src/niblack_thresholding.cpp
@@ -49,52 +49,59 @@ namespace ximgproc {
 void niBlackThreshold( InputArray _src, OutputArray _dst, double maxValue,
         int type, int blockSize, double delta )
 {
+    // Input grayscale image
     Mat src = _src.getMat();
-    CV_Assert( src.type() == CV_8UC1 );
-    CV_Assert( blockSize % 2 == 1 && blockSize > 1 );
-    Size size = src.size();
+    CV_Assert(src.channels() == 1);
+    CV_Assert(blockSize % 2 == 1 && blockSize > 1);
+    type &= THRESH_MASK;
 
-    _dst.create( size, src.type() );
-    Mat dst = _dst.getMat();
-
-    if( maxValue < 0 )
+    // Compute local threshold (T = mean + k * stddev)
+    // using mean and standard deviation in the neighborhood of each pixel
+    // (intermediate calculations are done with floating-point precision)
+    Mat thresh;
     {
-        dst = Scalar(0);
-        return;
+        // note that: Var[X] = E[X^2] - E[X]^2
+        Mat mean, sqmean, stddev;
+        boxFilter(src, mean, CV_32F, Size(blockSize, blockSize),
+                Point(-1,-1), true, BORDER_REPLICATE);
+        sqrBoxFilter(src, sqmean, CV_32F, Size(blockSize, blockSize),
+                Point(-1,-1), true, BORDER_REPLICATE);
+        sqrt(sqmean - mean.mul(mean), stddev);
+        thresh = mean + stddev * static_cast<float>(delta);
+        thresh.convertTo(thresh, src.depth());
     }
 
-    // Calculate and store the mean and mean of squares in the neighborhood
-    // of each pixel and store them in Mat mean and sqmean.
-    Mat_<float> mean(size), sqmean(size);
-
-    if( src.data != dst.data )
-        mean = dst;
-
-    boxFilter( src, mean, CV_64F, Size(blockSize, blockSize),
-            Point(-1,-1), true, BORDER_REPLICATE );
-    sqrBoxFilter( src, sqmean, CV_64F, Size(blockSize, blockSize),
-            Point(-1,-1), true, BORDER_REPLICATE );
+    // Prepare output image
+    _dst.create(src.size(), src.type());
+    Mat dst = _dst.getMat();
+    CV_Assert(src.data != dst.data);  // no inplace processing
 
-    // Compute (k * standard deviation) in the neighborhood of each pixel
-    // and store in Mat stddev. Also threshold the values in the src matrix to compute dst matrix.
-    Mat_<float> stddev(size);
-    int i, j, threshold;
-    uchar imaxval = saturate_cast<uchar>(maxValue);
-    for(i = 0; i < size.height; ++i)
+    // Apply thresholding: ( pixel > threshold ) ? foreground : background
+    Mat mask;
+    switch (type)
     {
-        for(j = 0; j < size.width; ++j)
-        {
-            stddev.at<float>(i, j) = saturate_cast<float>(delta) * cvRound( sqrt(sqmean.at<float>(i, j) -
-                        mean.at<float>(i, j)*mean.at<float>(i, j)) );
-            threshold = cvRound(mean.at<float>(i, j) + stddev.at<float>(i, j));
-            if(src.at<uchar>(i, j) > threshold)
-                dst.at<uchar>(i, j) = (type == THRESH_BINARY) ? imaxval : 0;
-            else
-                dst.at<uchar>(i, j) = (type == THRESH_BINARY) ? 0 : imaxval;
-        }
+    case THRESH_BINARY:      // dst = (src > thresh) ? maxval : 0
+    case THRESH_BINARY_INV:  // dst = (src > thresh) ? 0 : maxval
+        compare(src, thresh, mask, (type == THRESH_BINARY ? CMP_GT : CMP_LE));
+        dst.setTo(0);
+        dst.setTo(maxValue, mask);
+        break;
+    case THRESH_TRUNC:       // dst = (src > thresh) ? thresh : src
+        compare(src, thresh, mask, CMP_GT);
+        src.copyTo(dst);
+        thresh.copyTo(dst, mask);
+        break;
+    case THRESH_TOZERO:      // dst = (src > thresh) ? src : 0
+    case THRESH_TOZERO_INV:  // dst = (src > thresh) ? 0 : src
+        compare(src, thresh, mask, (type == THRESH_TOZERO ? CMP_GT : CMP_LE));
+        dst.setTo(0);
+        src.copyTo(dst, mask);
+        break;
+    default:
+        CV_Error( CV_StsBadArg, "Unknown threshold type" );
+        break;
     }
-
 }
 
 } // namespace ximgproc
-} //namespace cv
+} // namespace cv
diff --git a/contrib/modules/ximgproc/src/paillou_filter.cpp b/contrib/modules/ximgproc/src/paillou_filter.cpp
new file mode 100644
index 0000000..a821580
--- /dev/null
+++ b/contrib/modules/ximgproc/src/paillou_filter.cpp
@@ -0,0 +1,486 @@
+#include "precomp.hpp"
+#include "opencv2/highgui.hpp"
+#include <math.h>
+#include <vector>
+#include <iostream>
+
+namespace cv {
+namespace ximgproc {
+
+/*
+If you use this code please cite this @cite paillou1997detecting
+Detecting step edges in noisy SAR images: a new linear operator  IEEE Transactions on Geoscience and Remote Sensing  (Volume:35 ,  Issue: 1 )  1997
+*/
+
+
+class ParallelGradientPaillouYCols: public ParallelLoopBody
+{
+private:
+    Mat &img;
+    Mat &dst;
+    double a;
+    double w;
+    bool verbose;
+public:
+    ParallelGradientPaillouYCols(Mat& imgSrc, Mat &d,double aa,double ww):
+        img(imgSrc),
+        dst(d),
+        a(aa),
+        w(ww),
+        verbose(false)
+    {}
+    void Verbose(bool b){verbose=b;}
+    virtual void operator()(const Range& range) const
+    {
+        CV_Assert(img.depth()==CV_8UC1 || img.depth()==CV_16SC1 || img.depth()==CV_16UC1);
+        CV_Assert(dst.depth()==CV_32FC1);
+        if (verbose)
+            std::cout << getThreadNum()<<"# :Start from row " << range.start << " to "  << range.end-1<<" ("<<range.end-range.start<<" loops)" << std::endl;
+        float                *f2;
+        int tailleSequence=(img.rows>img.cols)?img.rows:img.cols;
+        Mat matYp(1,tailleSequence,CV_64FC1),  matYm(1,tailleSequence,CV_64FC1);
+        double *yp=matYp.ptr<double>(0), *ym=matYm.ptr<double>(0);
+        int rows=img.rows,cols=img.cols;
+
+        // Equation 12 p193
+        double                b1=-2*exp(-a)*cosh(w);
+        double                a1=2*exp(-a)*cosh(w)-exp(-2*a)-1;
+        double                b2=exp(-2*a);
+
+        switch(img.depth()){
+        case CV_8U :
+            for (int j=range.start;j<range.end;j++)
+            {
+                // Equation 26 p194
+                uchar *c1 = img.ptr(0)+j;
+                f2 = dst.ptr<float>(0)+j;
+                double border=*c1;
+                yp[0] = *c1 ;
+                c1+=cols;
+                yp[1] = *c1 - b1*yp[0]-b2*border;
+                c1+=cols;
+                for (int i=2;i<rows;i++,c1+=cols)
+                    yp[i] = *c1-b1*yp[i-1]-b2*yp[i-2];
+                // Equation 27 p194
+                c1 = img.ptr(rows-1)+j;
+                border=*c1;
+                ym[rows - 1] = *c1;
+                c1 -= cols;
+                ym[rows-2] =*c1 - b1*ym[rows-1];
+                c1 -= cols;
+                for (int i=rows-3;i>=0;i--,c1-=cols)
+                    ym[i]=*c1-b1*ym[i+1]-b2*ym[i+2];
+                // Equation 25 p193
+                for (int i=0;i<rows;i++,f2+=cols)
+                    *f2 = (float)(a1*(ym[i]-yp[i]));
+            }
+            break;
+        case CV_16S :
+            for (int j = range.start; j<range.end; j++)
+            {
+                // Equation 26 p194
+                short *c1 = img.ptr<short>(0) + j;
+                f2 = dst.ptr<float>(0) + j;
+                double border = *c1;
+                yp[0] = *c1;
+                c1 += cols;
+                yp[1] = *c1 - b1*yp[0] - b2*border;
+                c1 += cols;
+                for (int i = 2; i<rows; i++, c1 += cols)
+                    yp[i] = *c1 - b1*yp[i - 1] - b2*yp[i - 2];
+                // Equation 27 p194
+                c1 = img.ptr<short>(rows - 1) + j;
+                border = *c1;
+                ym[rows - 1] = *c1;
+                c1 -= cols;
+                ym[rows - 2] = *c1 - b1*ym[rows - 1];
+                c1 -= cols;
+                for (int i = rows - 3; i >= 0; i--, c1 -= cols)
+                    ym[i] = *c1 - b1*ym[i + 1] - b2*ym[i + 2];
+                // Equation 25 p193
+                for (int i = 0; i<rows; i++, f2 += cols)
+                    *f2 = (float)(a1*(ym[i] - yp[i]));
+            }
+        break;
+        case CV_16U :
+            for (int j = range.start; j<range.end; j++)
+            {
+                // Equation 26 p194
+                ushort *c1 = img.ptr<ushort>(0) + j;
+                f2 = dst.ptr<float>(0) + j;
+                double border = *c1;
+                yp[0] = *c1;
+                c1 += cols;
+                yp[1] = *c1 - b1*yp[0] - b2*border;
+                c1 += cols;
+                for (int i = 2; i<rows; i++, c1 += cols)
+                    yp[i] = *c1 - b1*yp[i - 1] - b2*yp[i - 2];
+                // Equation 27 p194
+                c1 = img.ptr<ushort>(rows - 1) + j;
+                border = *c1;
+                ym[rows - 1] = *c1;
+                c1 -= cols;
+                ym[rows - 2] = *c1 - b1*ym[rows - 1];
+                c1 -= cols;
+                for (int i = rows - 3; i >= 0; i--, c1 -= cols)
+                    ym[i] = *c1 - b1*ym[i + 1] - b2*ym[i + 2];
+                // Equation 25 p193
+                for (int i = 0; i<rows; i++, f2 += cols)
+                    *f2 = (float)(a1*(ym[i] - yp[i]));
+            }
+            break;
+        default :
+            return ;
+            }
+    };
+    ParallelGradientPaillouYCols& operator=(const ParallelGradientPaillouYCols &) {
+         return *this;
+    };
+};
+
+
+class ParallelGradientPaillouYRows: public ParallelLoopBody
+{
+private:
+    Mat &img;
+    Mat &dst;
+    double a;
+    double w;
+    bool verbose;
+
+public:
+    ParallelGradientPaillouYRows(Mat& imgSrc, Mat &d,double aa,double ww):
+        img(imgSrc),
+        dst(d),
+        a(aa),
+        w(ww),
+        verbose(false)
+    {}
+    void Verbose(bool b){verbose=b;}
+    virtual void operator()(const Range& range) const
+    {
+        CV_Assert(img.depth()==CV_32FC1);
+        if (verbose)
+            std::cout << getThreadNum()<<"# :Start from row " << range.start << " to "  << range.end-1<<" ("<<range.end-range.start<<" loops)" << std::endl;
+        float *iy,*iy0;
+        int tailleSequence=(img.rows>img.cols)?img.rows:img.cols;
+        Mat matIym(1,tailleSequence,CV_64FC1),  matIyp(1,tailleSequence,CV_64FC1);
+        double *iym=matIym.ptr<double>(0), *iyp=matIyp.ptr<double>(0);
+        int cols=img.cols;
+
+        // Equation 13 p193
+        double                d=(1-2*exp(-a)*cosh(w)+exp(-2*a))/(2*a*exp(-a)*sinh(w)+w*(1-exp(-2*a)));
+        double                c1=a*d;
+        double                c2=w*d;
+        // Equation 12 p193
+        double                b1=-2*exp(-a)*cosh(w);
+        double                b2=exp(-2*a);
+        // Equation 14 p193
+        double                a0p=c2;
+        double                a1p=(c1*sinh(w)-c2*cosh(w))*exp(-a);
+        double                a1m=a1p-c2*b1;
+        double                a2m=-c2*b2;
+
+        for (int i=range.start;i<range.end;i++)
+            {
+            iy0 = img.ptr<float>(i);
+            int j=0;
+            iyp[0] = a0p*iy0[0] ;
+            iyp[1] = a0p*iy0[1] + a1p*iy0[0] - b1*iyp[0];
+            iy0 += 2;
+            for (j=2;j<cols;j++,iy0++)
+                iyp[j] = a0p*iy0[0] + a1p*iy0[-1] - b1*iyp[j-1] - b2*iyp[j-2];
+            iy0 = img.ptr<float>(i)+cols-1;
+            iym[cols-1] = 0;
+            iy0--;
+            iym[cols-2] = a1m*iy0[1]  - b1*iym[cols-1];
+            iy0--;
+            for (j=cols-3;j>=0;j--,iy0--)
+                iym[j] = a1m*iy0[1] + a2m*iy0[2] - b1*iym[j+1] - b2*iym[j+2];
+            iy = dst.ptr<float>(i);
+            for (j=0;j<cols;j++,iy++)
+                *iy = (float)(iym[j]+iyp[j]);
+            }
+
+    };
+    ParallelGradientPaillouYRows& operator=(const ParallelGradientPaillouYRows &) {
+         return *this;
+    };
+};
+
+
+class ParallelGradientPaillouXCols: public ParallelLoopBody
+{
+private:
+    Mat &img;
+    Mat &dst;
+    double a;
+    double w;
+    bool verbose;
+
+public:
+    ParallelGradientPaillouXCols(Mat& imgSrc, Mat &d,double aa,double ww):
+        img(imgSrc),
+        dst(d),
+        a(aa),
+        w(ww),
+        verbose(false)
+    {}
+    void Verbose(bool b){verbose=b;}
+    virtual void operator()(const Range& range) const
+    {
+        CV_Assert(img.depth()==CV_32FC1);
+        if (verbose)
+            std::cout << getThreadNum() << "# :Start from row " << range.start << " to " << range.end - 1 << " (" << range.end - range.start << " loops)" << std::endl;
+        float *iy, *iy0;
+        int tailleSequence = (img.rows>img.cols) ? img.rows : img.cols;
+        Mat matIym(1,tailleSequence,CV_64FC1),  matIyp(1,tailleSequence,CV_64FC1);
+        double *iym=matIym.ptr<double>(0), *iyp=matIyp.ptr<double>(0);
+        int rows = img.rows,cols=img.cols;
+
+        // Equation 13 p193
+        double                d = (1 - 2 * exp(-a)*cosh(w) + exp(-2 * a)) / (2 * a*exp(-a)*sinh(w) + w*(1 - exp(-2 * a)));
+        double                c1 = a*d;
+        double                c2 = w*d;
+        // Equation 12 p193
+        double                b1 = -2 * exp(-a)*cosh(w);
+        double                b2 = exp(-2 * a);
+        // Equation 14 p193
+        double                a0p = c2;
+        double                a1p = (c1*sinh(w) - c2*cosh(w))*exp(-a);
+        double                a1m = a1p - c2*b1;
+        double                a2m = -c2*b2;
+
+        for (int j = range.start; j<range.end; j++)
+        {
+            iy0 = img.ptr<float>(0)+j;
+            iyp[0] = a0p*iy0[0];
+            iy0 +=cols;
+            iyp[1] = a0p*iy0[0] + a1p*iy0[-cols] - b1*iyp[0];
+            iy0 +=cols;
+            for (int i = 2; i<rows; i++, iy0+=cols)
+                iyp[i] = a0p*iy0[0] + a1p*iy0[-cols] - b1*iyp[i - 1] - b2*iyp[i - 2];
+            iy0 = img.ptr<float>(rows-1) + j;
+            iym[rows - 1] = 0;
+            iy0 -=cols;
+            iym[rows - 2] = a1m*iy0[cols] - b1*iym[rows-1];
+            iy0-=cols;
+            for (int i = rows - 3; i >= 0; i--, iy0-=cols)
+                iym[i] = a1m*iy0[cols] + a2m*iy0[2*cols] - b1*iym[i + 1] - b2*iym[i + 2];
+            iy = dst.ptr<float>(0)+j;
+            for (int i = 0; i<rows; i++, iy+=cols)
+                *iy = (float)(iym[i] + iyp[i]);
+        }
+
+    };
+    ParallelGradientPaillouXCols& operator=(const ParallelGradientPaillouXCols &) {
+         return *this;
+    };
+};
+
+
+class ParallelGradientPaillouXRows: public ParallelLoopBody
+{
+private:
+    Mat &img;
+    Mat &im1;
+    double a;
+    double w;
+    bool verbose;
+
+public:
+    ParallelGradientPaillouXRows(Mat& imgSrc, Mat &d,double aa,double ww):
+        img(imgSrc),
+        im1(d),
+        a(aa),
+        w(ww),
+        verbose(false)
+    {}
+    void Verbose(bool b){verbose=b;}
+    virtual void operator()(const Range& range) const
+    {
+        if (verbose)
+            std::cout << getThreadNum()<<"# :Start from row " << range.start << " to "  << range.end-1<<" ("<<range.end-range.start<<" loops)" << std::endl;
+        float                *f2;
+        int tailleSequence = (img.rows>img.cols) ? img.rows : img.cols;
+        Mat matYp(1,tailleSequence,CV_64FC1),  matYm(1,tailleSequence,CV_64FC1);
+        double *yp=matYp.ptr<double>(0), *ym=matYm.ptr<double>(0);
+        int cols = img.cols;
+
+        // Equation 12 p193
+        double                b1 = -2 * exp(-a)*cosh(w);
+        double                a1 = 2 * exp(-a)*cosh(w) - exp(-2 * a) - 1;
+        double                b2 = exp(-2 * a);
+
+        switch(img.depth()){
+        case CV_8U :
+            for (int i = range.start; i<range.end; i++)
+            {
+                // Equation 26 p194
+                uchar *c1 = img.ptr(i);
+                double border = *c1;
+                yp[0] = *c1;
+                c1++;
+                yp[1] = *c1 - b1*yp[0] - b2*border;
+                c1++;
+                for (int j = 2; j<cols; j++, c1++)
+                    yp[j] = *c1 - b1*yp[j - 1] - b2*yp[j - 2];
+                // Equation 27 p194
+                c1 = img.ptr(i)+cols-1;
+                border = *c1;
+                ym[cols - 1] = *c1;
+                c1--;
+                ym[cols - 2] = *c1 - b1*ym[cols - 1];
+                c1--;
+                for (int j = cols - 3; j >= 0; j--, c1--)
+                    ym[j] = *c1 - b1*ym[j + 1] - b2*ym[j + 2];
+                // Equation 25 p193
+                f2 = im1.ptr<float>(i);
+                for (int j = 0; j<cols; j++, f2 ++)
+                    *f2 = (float)(a1*(ym[j] - yp[j]));
+            }
+            break;
+        case CV_8S :
+            for (int i = range.start; i<range.end; i++)
+            {
+                // Equation 26 p194
+                char *c1 = img.ptr<char>(i);
+                double border = *c1;
+                yp[0] = *c1;
+                c1++;
+                yp[1] = *c1 - b1*yp[0] - b2*border;
+                c1++;
+                for (int j = 2; j<cols; j++, c1++)
+                    yp[j] = *c1 - b1*yp[j - 1] - b2*yp[j - 2];
+                // Equation 27 p194
+                c1 = img.ptr<char>(i)+cols-1;
+                border = *c1;
+                ym[cols - 1] = *c1;
+                c1--;
+                ym[cols - 2] = *c1 - b1*ym[cols - 1];
+                c1--;
+                for (int j = cols - 3; j >= 0; j--, c1--)
+                    ym[j] = *c1 - b1*ym[j + 1] - b2*ym[j + 2];
+                // Equation 25 p193
+                f2 = im1.ptr<float>(i);
+                for (int j = 0; j<cols; j++, f2 ++)
+                    *f2 = (float)(a1*(ym[j] - yp[j]));
+            }
+            break;
+        case CV_16S :
+            for (int i = range.start; i<range.end; i++)
+            {
+                // Equation 26 p194
+                short *c1 = img.ptr<short>(i);
+                f2 = im1.ptr<float>(i);
+                double border = *c1;
+                yp[0] = *c1;
+                c1++;
+                yp[1] = *c1 - b1*yp[0] - b2*border;
+                c1++;
+                for (int j = 2; j<cols; j++, c1++)
+                    yp[j] = *c1 - b1*yp[j - 1] - b2*yp[j - 2];
+                // Equation 27 p194
+                c1 = img.ptr<short>(i) + cols - 1;
+                border = *c1;
+                ym[cols - 1] = *c1;
+                c1--;
+                ym[cols - 2] = *c1 - b1*ym[cols - 1];
+                c1--;
+                for (int j = cols - 3; j >= 0; j--, c1--)
+                    ym[j] = *c1 - b1*ym[j + 1] - b2*ym[j + 2];
+                // Equation 25 p193
+                for (int j = 0; j<cols; j++, f2++)
+                    *f2 = (float)(a1*(ym[i] - yp[i]));
+            }
+            break;
+        case CV_16U :
+            for (int i = range.start; i<range.end; i++)
+            {
+                // Equation 26 p194
+                ushort *c1 = img.ptr<ushort>(i);
+                f2 = im1.ptr<float>(i);
+                double border = *c1;
+                yp[0] = *c1;
+                c1++;
+                yp[1] = *c1 - b1*yp[0] - b2*border;
+                c1++;
+                for (int j = 2; j<cols; j++, c1++)
+                    yp[j] = *c1 - b1*yp[j - 1] - b2*yp[j - 2];
+                // Equation 27 p194
+                c1 = img.ptr<ushort>(i) + cols - 1;
+                border = *c1;
+                ym[cols - 1] = *c1;
+                c1--;
+                ym[cols - 2] = *c1 - b1*ym[cols - 1];
+                c1--;
+                for (int j = cols - 3; j >= 0; j--, c1--)
+                    ym[j] = *c1 - b1*ym[j + 1] - b2*ym[j + 2];
+                // Equation 25 p193
+                for (int j = 0; j<cols; j++, f2++)
+                    *f2 = (float)(a1*(ym[i] - yp[i]));
+            }
+            break;
+        default :
+            return ;
+            }
+    };
+    ParallelGradientPaillouXRows& operator=(const ParallelGradientPaillouXRows &) {
+         return *this;
+    };
+};
+
+void GradientPaillouY(InputArray _op, OutputArray _dst, double alpha, double omega)
+{
+    Mat tmp(_op.size(),CV_32FC(_op.channels()));
+    _dst.create( _op.size(),CV_32FC(tmp.channels()) );
+    cv::Mat opSrc = _op.getMat();
+    std::vector<Mat> planSrc;
+    split(opSrc,planSrc);
+    std::vector<Mat> planTmp;
+    split(tmp,planTmp);
+    std::vector<Mat> planDst;
+    split(_dst,planDst);
+    for (int i = 0; i < static_cast<int>(planSrc.size()); i++)
+    {
+        if (planSrc[i].isContinuous() && planTmp[i].isContinuous() && planDst[i].isContinuous())
+        {
+            ParallelGradientPaillouYCols x(planSrc[i],planTmp[i],alpha,omega);
+            parallel_for_(Range(0,opSrc.cols), x,getNumThreads());
+            ParallelGradientPaillouYRows xr(planTmp[i],planDst[i],alpha,omega);
+            parallel_for_(Range(0,opSrc.rows), xr,getNumThreads());
+
+        }
+        else
+            std::cout << "PB";
+    }
+    merge(planDst,_dst);
+}
+
+void GradientPaillouX(InputArray _op, OutputArray _dst, double alpha, double omega)
+{
+    Mat tmp(_op.size(),CV_32FC(_op.channels()));
+    _dst.create( _op.size(),CV_32FC(tmp.channels()) );
+    Mat opSrc = _op.getMat();
+    std::vector<Mat> planSrc;
+    split(opSrc,planSrc);
+    std::vector<Mat> planTmp;
+    split(tmp,planTmp);
+    std::vector<Mat> planDst;
+    split(_dst,planDst);
+    for (int i = 0; i < static_cast<int>(planSrc.size()); i++)
+    {
+        if (planSrc[i].isContinuous() && planTmp[i].isContinuous() && planDst[i].isContinuous())
+        {
+            ParallelGradientPaillouXRows x(planSrc[i],planTmp[i],alpha,omega);
+            parallel_for_(Range(0,opSrc.rows), x,getNumThreads());
+            ParallelGradientPaillouXCols xr(planTmp[i],planDst[i],alpha,omega);
+            parallel_for_(Range(0,opSrc.cols), xr,getNumThreads());
+        }
+        else
+            std::cout << "PB";
+    }
+    merge(planDst,_dst);
+}
+}
+}
diff --git a/contrib/modules/ximgproc/src/precomp.hpp b/contrib/modules/ximgproc/src/precomp.hpp
index 74d2c38..29af094 100644
--- a/contrib/modules/ximgproc/src/precomp.hpp
+++ b/contrib/modules/ximgproc/src/precomp.hpp
@@ -11,7 +11,7 @@
  *  Redistribution and use in source and binary forms, with or without modification,
  *  are permitted provided that the following conditions are met :
  *
- *  *Redistributions of source code must retain the above copyright notice,
+ *  * Redistributions of source code must retain the above copyright notice,
  *  this list of conditions and the following disclaimer.
  *
  *  * Redistributions in binary form must reproduce the above copyright notice,
diff --git a/contrib/modules/ximgproc/src/rolling_guidance_filter.cpp b/contrib/modules/ximgproc/src/rolling_guidance_filter.cpp
index 679b296..0786ea0 100644
--- a/contrib/modules/ximgproc/src/rolling_guidance_filter.cpp
+++ b/contrib/modules/ximgproc/src/rolling_guidance_filter.cpp
@@ -11,7 +11,7 @@
  *  Redistribution and use in source and binary forms, with or without modification,
  *  are permitted provided that the following conditions are met :
  *
- *  *Redistributions of source code must retain the above copyright notice,
+ *  * Redistributions of source code must retain the above copyright notice,
  *  this list of conditions and the following disclaimer.
  *
  *  * Redistributions in binary form must reproduce the above copyright notice,
diff --git a/contrib/modules/ximgproc/src/seeds.cpp b/contrib/modules/ximgproc/src/seeds.cpp
index 90273ad..7fecca3 100644
--- a/contrib/modules/ximgproc/src/seeds.cpp
+++ b/contrib/modules/ximgproc/src/seeds.cpp
@@ -375,7 +375,31 @@ void SuperpixelSEEDSImpl::initImageBins<float>(const Mat& img, int)
 
 void SuperpixelSEEDSImpl::initImage(InputArray img)
 {
-    Mat src = img.getMat();
+    Mat src;
+
+    if ( img.isMat() )
+    {
+      // get Mat
+      src = img.getMat();
+
+      // image should be valid
+      CV_Assert( !src.empty() );
+    }
+    else if ( img.isMatVector() )
+    {
+      vector<Mat> vec;
+      // get vector Mat
+      img.getMatVector( vec );
+
+      // array should be valid
+      CV_Assert( !vec.empty() );
+
+      // merge into Mat
+      merge( vec, src );
+    }
+    else
+      CV_Error( Error::StsInternal, "Invalid InputArray." );
+
     int depth = src.depth();
     seeds_current_level = seeds_nr_levels - 2;
     forwardbackward = true;
@@ -1214,7 +1238,7 @@ void SuperpixelSEEDSImpl::getLabelContourMask(OutputArray image, bool thick_line
                 }
             }
             if( neighbors > 1 )
-                *dst.ptr<uchar>(j, k) = (uchar)-1;
+                *dst.ptr<uchar>(j, k) = (uchar)255;
         }
     }
 }
diff --git a/contrib/modules/ximgproc/src/selectivesearchsegmentation.cpp b/contrib/modules/ximgproc/src/selectivesearchsegmentation.cpp
new file mode 100644
index 0000000..cfcc7c0
--- /dev/null
+++ b/contrib/modules/ximgproc/src/selectivesearchsegmentation.cpp
@@ -0,0 +1,1108 @@
+/*
+By downloading, copying, installing or using the software you agree to this
+license. If you do not agree to this license, do not download, install,
+copy or use the software.
+                          License Agreement
+               For Open Source Computer Vision Library
+                       (3-clause BSD License)
+Copyright (C) 2013, OpenCV Foundation, all rights reserved.
+Third party copyrights are property of their respective owners.
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+  * Redistributions of source code must retain the above copyright notice,
+    this list of conditions and the following disclaimer.
+  * Redistributions in binary form must reproduce the above copyright notice,
+    this list of conditions and the following disclaimer in the documentation
+    and/or other materials provided with the distribution.
+  * Neither the names of the copyright holders nor the names of the contributors
+    may be used to endorse or promote products derived from this software
+    without specific prior written permission.
+This software is provided by the copyright holders and contributors "as is" and
+any express or implied warranties, including, but not limited to, the implied
+warranties of merchantability and fitness for a particular purpose are
+disclaimed. In no event shall copyright holders or contributors be liable for
+any direct, indirect, incidental, special, exemplary, or consequential damages
+(including, but not limited to, procurement of substitute goods or services;
+loss of use, data, or profits; or business interruption) however caused
+and on any theory of liability, whether in contract, strict liability,
+or tort (including negligence or otherwise) arising in any way out of
+the use of this software, even if advised of the possibility of such damage.
+*/
+
+/*******************************************************************************\
+*                   Selective search segmentation                              *
+* This code implements the segmentation method described in:                   *
+* Jasper R. R. Uijlings, Koen E. A. van de Sande, Theo Gevers,                 *
+* Arnold W. M. Smeulders: "Selective Search for Object Recognition "           *
+* International Journal of Computer Vision, Volume 104 (2), page 154-171, 2013 *
+* Author: Maximilien Cuony / LTS2 / EPFL / 2016                                *
+********************************************************************************/
+
+#include "precomp.hpp"
+#include "opencv2/highgui.hpp"
+#include "opencv2/ximgproc/segmentation.hpp"
+
+#include <iostream>
+
+namespace cv {
+    namespace ximgproc {
+        namespace segmentation {
+
+            // Helpers
+
+            // Represent a regsion
+            class Region {
+                public:
+                    int id;
+                    int level;
+                    int merged_to;
+                    double rank;
+                    Rect bounding_box;
+
+                    friend std::ostream& operator<<(std::ostream& os, const Region& n);
+
+                    bool operator <(const Region& n) const {
+                        return rank < n.rank;
+                    }
+            };
+
+            // Comparator to sort cv::rect (used for a std::map).
+            struct rectComparator {
+                bool operator()(const cv::Rect_<int>& a, const cv::Rect_<int>& b) const {
+                    if (a.x < b.x) {
+                        return true;
+                    }
+                    if (a.x > b.x) {
+                        return false;
+                    }
+                    if (a.y < b.y) {
+                        return true;
+                    }
+                    if (a.y > b.y) {
+                        return false;
+                    }
+                    if (a.width < b.width) {
+                        return true;
+                    }
+                    if (a.width > b.width) {
+                        return false;
+                    }
+                    if (a.height < b.height) {
+                        return true;
+                    }
+                    if (a.height > b.height) {
+                        return false;
+                    }
+                    return false;
+                }
+            };
+
+            // Represent a neighboor
+            class Neighbour {
+                public:
+                    int from;
+                    int to;
+                    float similarity;
+                    friend std::ostream& operator<<(std::ostream& os, const Neighbour& n);
+
+                    bool operator <(const Neighbour& n) const {
+                        return similarity < n.similarity;
+                    }
+            };
+
+            /****************************************
+             * Stragegy / Color
+             ***************************************/
+
+            class SelectiveSearchSegmentationStrategyColorImpl : public SelectiveSearchSegmentationStrategyColor {
+                public:
+                    SelectiveSearchSegmentationStrategyColorImpl() {
+                        name_ = "SelectiveSearchSegmentationStrategyColor";
+                        last_image_id = -1;
+                    }
+
+                    virtual void setImage(InputArray img, InputArray regions, InputArray sizes, int image_id = -1);
+                    virtual float get(int r1, int r2);
+                    virtual void merge(int r1, int r2);
+
+                private:
+                    String name_;
+
+                    Mat histograms; // [Region X Histogram]
+                    Mat sizes;
+                    int histogram_size;
+
+                    int last_image_id; // If the image_id is not equal to -1 and the same as the previous call for setImage, computations are used again
+                    Mat last_histograms;
+            };
+
+
+            void SelectiveSearchSegmentationStrategyColorImpl::setImage(InputArray img_, InputArray regions_, InputArray sizes_, int image_id) {
+
+                Mat img = img_.getMat();
+                Mat regions = regions_.getMat();
+                sizes = sizes_.getMat();
+
+                if (image_id != -1 && last_image_id != image_id) {
+
+                    std::vector<Mat> img_planes;
+                    split(img, img_planes);
+
+                    int histogram_bins_size = 25;
+
+                    float range[] = {0, 256};
+                    const float* histogram_ranges = {range};
+
+                    double min, max;
+                    minMaxLoc(regions, &min, &max);
+                    int nb_segs = (int)max + 1;
+
+                    histogram_size = histogram_bins_size * img.channels();
+
+                    histograms = Mat_<float>(nb_segs, histogram_size);
+
+                    for (int r = 0; r < nb_segs; r++) {
+
+                        // Generate mask
+                        Mat mask = Mat(img.rows, img.cols, CV_8UC1);
+
+                        int* regions_data = (int*)regions.data;
+                        char* mask_data = (char*)mask.data;
+
+                        for (unsigned int x = 0; x < regions.total(); x++) {
+                            mask_data[x] = regions_data[x] == r ? 255 : 0;
+                        }
+
+                        // Compute histogram for each channels
+                        float tt = 0;
+
+                        Mat tmp_hists = Mat(histogram_size, 1, CV_32F);
+                        float *tmp_histogram = tmp_hists.ptr<float>(0);
+                        int h_pos = 0;
+                        Mat tmp_hist;
+
+                        for (int p = 0; p < img.channels(); p++) {
+
+                            calcHist(&img_planes[p], 1, 0, mask, tmp_hist, 1, &histogram_bins_size, &histogram_ranges);
+
+                            float *tmp_hist_ = tmp_hist.ptr<float>(0);
+
+                            // Copy local histogram to global histogram
+                            for (int pos = 0; pos < histogram_bins_size; pos++) {
+                                tmp_histogram[pos + h_pos] = tmp_hist_[pos];
+                                tt += tmp_histogram[pos + h_pos];
+                            }
+                            h_pos += histogram_bins_size;
+                        }
+
+                        // Normalize historgrams
+                        float* histogram = histograms.ptr<float>(r);
+
+                        for (int h_pos2 = 0; h_pos2 < histogram_size; h_pos2++) {
+                            histogram[h_pos2] = tmp_histogram[h_pos2] / tt;
+                        }
+                    }
+
+                    // Save cache if we have an image id
+                    if (image_id != -1) {
+                        last_histograms = histograms.clone();
+                        last_image_id = image_id;
+                    }
+                } else { // last_image_id == image_id
+                    // Use cache
+                    histograms = last_histograms.clone();
+                }
+            }
+
+            float SelectiveSearchSegmentationStrategyColorImpl::get(int r1, int r2) {
+
+                float r = 0;
+                float* h1 = histograms.ptr<float>(r1);
+                float* h2 = histograms.ptr<float>(r2);
+
+                for (int i = 0; i < histogram_size; i++) {
+                    r += min(h1[i], h2[i]);
+                }
+
+                return r;
+            }
+
+            void SelectiveSearchSegmentationStrategyColorImpl::merge(int r1, int r2) {
+                int size_r1 = sizes.at<int>(r1);
+                int size_r2 = sizes.at<int>(r2);
+
+                float* h1 = histograms.ptr<float>(r1);
+                float* h2 = histograms.ptr<float>(r2);
+
+                for (int i = 0; i < histogram_size; i++) {
+                    h1[i] = (h1[i] * size_r1 + h2[i] * size_r2) / (size_r1 + size_r2);
+                    h2[i] = h1[i];
+                }
+            }
+
+
+            Ptr<SelectiveSearchSegmentationStrategyColor> createSelectiveSearchSegmentationStrategyColor() {
+                Ptr<SelectiveSearchSegmentationStrategyColor> s = makePtr<SelectiveSearchSegmentationStrategyColorImpl>();
+                return s;
+            }
+
+            /****************************************
+             * Stragegy / Multiple
+             ***************************************/
+
+            class SelectiveSearchSegmentationStrategyMultipleImpl : public SelectiveSearchSegmentationStrategyMultiple {
+                public:
+                    SelectiveSearchSegmentationStrategyMultipleImpl() {
+                        name_ = "SelectiveSearchSegmentationStrategyMultiple";
+                        weights_total = 0;
+                    }
+
+                    virtual void setImage(InputArray img, InputArray regions, InputArray sizes, int image_id = -1);
+                    virtual float get(int r1, int r2);
+                    virtual void merge(int r1, int r2);
+
+                    virtual void addStrategy(Ptr<SelectiveSearchSegmentationStrategy> g, float weight);
+                    virtual void clearStrategies();
+
+                private:
+                    String name_;
+                    std::vector<Ptr<SelectiveSearchSegmentationStrategy> > strategies;
+                    std::vector<float> weights;
+                    float weights_total;
+            };
+
+            void SelectiveSearchSegmentationStrategyMultipleImpl::addStrategy(Ptr<SelectiveSearchSegmentationStrategy> g, float weight) {
+                strategies.push_back(g);
+                weights.push_back(weight);
+                weights_total += weight;
+            }
+
+            void SelectiveSearchSegmentationStrategyMultipleImpl::clearStrategies() {
+                strategies.clear();
+                weights.clear();
+                weights_total = 0;
+            }
+
+            void SelectiveSearchSegmentationStrategyMultipleImpl::setImage(InputArray img_, InputArray regions_, InputArray sizes_, int image_id) {
+                for (unsigned int i = 0; i < strategies.size(); i++) {
+                    strategies[i]->setImage(img_, regions_, sizes_, image_id);
+                }
+            }
+
+            float SelectiveSearchSegmentationStrategyMultipleImpl::get(int r1, int r2) {
+                float tt = 0;
+
+                for (unsigned int i = 0; i < strategies.size(); i++) {
+                    tt += weights[i] * strategies[i]->get(r1, r2);
+                }
+
+                return tt / weights_total;
+            }
+
+            void SelectiveSearchSegmentationStrategyMultipleImpl::merge(int r1, int r2) {
+                for (unsigned int i = 0; i < strategies.size(); i++) {
+                    strategies[i]->merge(r1, r2);
+                }
+            }
+
+            Ptr<SelectiveSearchSegmentationStrategyMultiple> createSelectiveSearchSegmentationStrategyMultiple() {
+                Ptr<SelectiveSearchSegmentationStrategyMultiple> s = makePtr<SelectiveSearchSegmentationStrategyMultipleImpl>();
+                return s;
+            }
+
+            // Helpers to quickly create a multiple stragegy with 1 to 4 equal strageries
+            Ptr<SelectiveSearchSegmentationStrategyMultiple> createSelectiveSearchSegmentationStrategyMultiple(Ptr<SelectiveSearchSegmentationStrategy> s1) {
+                Ptr<SelectiveSearchSegmentationStrategyMultiple> s = makePtr<SelectiveSearchSegmentationStrategyMultipleImpl>();
+
+                s->addStrategy(s1, 1.0f);
+
+                return s;
+            }
+
+            Ptr<SelectiveSearchSegmentationStrategyMultiple> createSelectiveSearchSegmentationStrategyMultiple(Ptr<SelectiveSearchSegmentationStrategy> s1, Ptr<SelectiveSearchSegmentationStrategy> s2) {
+                Ptr<SelectiveSearchSegmentationStrategyMultiple> s = makePtr<SelectiveSearchSegmentationStrategyMultipleImpl>();
+
+                s->addStrategy(s1, 0.5f);
+                s->addStrategy(s2, 0.5f);
+
+                return s;
+            }
+
+            Ptr<SelectiveSearchSegmentationStrategyMultiple> createSelectiveSearchSegmentationStrategyMultiple(Ptr<SelectiveSearchSegmentationStrategy> s1, Ptr<SelectiveSearchSegmentationStrategy> s2, Ptr<SelectiveSearchSegmentationStrategy> s3) {
+                Ptr<SelectiveSearchSegmentationStrategyMultiple> s = makePtr<SelectiveSearchSegmentationStrategyMultipleImpl>();
+
+                s->addStrategy(s1, 0.3333f);
+                s->addStrategy(s2, 0.3333f);
+                s->addStrategy(s3, 0.3333f);
+
+                return s;
+            }
+
+            Ptr<SelectiveSearchSegmentationStrategyMultiple> createSelectiveSearchSegmentationStrategyMultiple(Ptr<SelectiveSearchSegmentationStrategy> s1, Ptr<SelectiveSearchSegmentationStrategy> s2, Ptr<SelectiveSearchSegmentationStrategy> s3, Ptr<SelectiveSearchSegmentationStrategy> s4) {
+                Ptr<SelectiveSearchSegmentationStrategyMultiple> s = makePtr<SelectiveSearchSegmentationStrategyMultipleImpl>();
+
+                s->addStrategy(s1, 0.25f);
+                s->addStrategy(s2, 0.25f);
+                s->addStrategy(s3, 0.25f);
+                s->addStrategy(s4, 0.25f);
+
+                return s;
+            }
+
+
+            /****************************************
+             * Stragegy / Size
+             ***************************************/
+
+            class SelectiveSearchSegmentationStrategySizeImpl : public SelectiveSearchSegmentationStrategySize {
+                public:
+                    SelectiveSearchSegmentationStrategySizeImpl() {
+                        name_ = "SelectiveSearchSegmentationStrategySize";
+                    }
+
+                    virtual void setImage(InputArray img, InputArray regions, InputArray sizes, int image_id = -1);
+                    virtual float get(int r1, int r2);
+                    virtual void merge(int r1, int r2);
+
+                private:
+                    String name_;
+
+                    Mat sizes;
+                    int size_image;
+            };
+
+
+            void SelectiveSearchSegmentationStrategySizeImpl::setImage(InputArray img_, InputArray, InputArray sizes_, int /* image_id */) {
+                Mat img = img_.getMat();
+                size_image = img.rows * img.cols;
+                sizes = sizes_.getMat();
+            }
+
+            float SelectiveSearchSegmentationStrategySizeImpl::get(int r1, int r2) {
+
+                int size_r1 = sizes.at<int>(r1);
+                int size_r2 = sizes.at<int>(r2);
+
+                return max(min(1.0f - (float)(size_r1 + size_r2) / (float)(size_image), 1.0f), 0.0f);
+            }
+
+            void SelectiveSearchSegmentationStrategySizeImpl::merge(int /* r1 */, int /* r2 */) {
+                // Nothing to do (sizes are merged at parent level)
+            }
+
+
+            Ptr<SelectiveSearchSegmentationStrategySize> createSelectiveSearchSegmentationStrategySize() {
+                Ptr<SelectiveSearchSegmentationStrategySize> s = makePtr<SelectiveSearchSegmentationStrategySizeImpl>();
+                return s;
+            }
+
+
+            /****************************************
+             * Stragegy / Fill
+             ***************************************/
+
+            class SelectiveSearchSegmentationStrategyFillImpl : public SelectiveSearchSegmentationStrategyFill {
+                public:
+                    SelectiveSearchSegmentationStrategyFillImpl() {
+                        name_ = "SelectiveSearchSegmentationStrategyFill";
+                    }
+
+                    virtual void setImage(InputArray img, InputArray regions, InputArray sizes, int image_id = -1);
+                    virtual float get(int r1, int r2);
+                    virtual void merge(int r1, int r2);
+
+                private:
+                    String name_;
+
+                    Mat sizes;
+                    int size_image;
+                    std::vector<Rect> bounding_rects;
+            };
+
+
+            void SelectiveSearchSegmentationStrategyFillImpl::setImage(InputArray img_, InputArray regions_, InputArray sizes_, int /* image_id */) {
+                Mat img = img_.getMat();
+                sizes = sizes_.getMat();
+                Mat regions = regions_.getMat();
+
+                size_image = img.rows * img.cols;
+
+                // Build initial bouding rects
+                double min, max;
+                minMaxLoc(regions, &min, &max);
+
+                int nb_segs = (int)max + 1;
+
+                // Build a list of points for each regions
+                std::vector<std::vector<cv::Point> > points;
+
+                points.resize(nb_segs);
+
+                for (int i = 0; i < (int)regions.rows; i++) {
+                    const int* p = regions.ptr<int>(i);
+
+                    for (int j = 0; j < (int)regions.cols; j++) {
+                        points[p[j]].push_back(cv::Point(j, i));
+                    }
+                }
+
+                // Compute bounding rects for each regions
+                bounding_rects.resize(nb_segs);
+
+                for(int seg = 0; seg < nb_segs; seg++) {
+                    bounding_rects[seg] = cv::boundingRect(points[seg]);
+                }
+            }
+
+            float SelectiveSearchSegmentationStrategyFillImpl::get(int r1, int r2) {
+
+                int size_r1 = sizes.at<int>(r1);
+                int size_r2 = sizes.at<int>(r2);
+                int bounding_rect_size = (bounding_rects[r1] | bounding_rects[r2]).area();
+
+                return max(min(1.0f - (float)(bounding_rect_size - size_r1 - size_r2) / (float)(size_image), 1.0f), 0.0f);
+            }
+
+            void SelectiveSearchSegmentationStrategyFillImpl::merge(int r1, int r2) {
+                bounding_rects[r1] = bounding_rects[r1] | bounding_rects[r2];
+                bounding_rects[r2] = bounding_rects[r1];
+            }
+
+
+            Ptr<SelectiveSearchSegmentationStrategyFill> createSelectiveSearchSegmentationStrategyFill() {
+                Ptr<SelectiveSearchSegmentationStrategyFill> s = makePtr<SelectiveSearchSegmentationStrategyFillImpl>();
+                return s;
+            }
+
+
+            /****************************************
+             * Stragegy / Texture
+             ***************************************/
+
+            class SelectiveSearchSegmentationStrategyTextureImpl : public SelectiveSearchSegmentationStrategyTexture {
+                public:
+                    SelectiveSearchSegmentationStrategyTextureImpl() {
+                        name_ = "SelectiveSearchSegmentationStrategyTexture";
+                        last_image_id = -1;
+                    }
+
+                    virtual void setImage(InputArray img, InputArray regions, InputArray sizes, int image_id = -1);
+                    virtual float get(int r1, int r2);
+                    virtual void merge(int r1, int r2);
+
+                private:
+                    String name_;
+
+                    Mat histograms; //[Region X Histogram]
+                    Mat sizes;
+                    int histogram_size;
+
+                    int last_image_id; // If the image_id is not equal to -1 and the same as the previous call for setImage, computations are used again
+                    Mat last_histograms;
+            };
+
+
+            void SelectiveSearchSegmentationStrategyTextureImpl::setImage(InputArray img_, InputArray regions_, InputArray sizes_, int image_id) {
+
+                Mat img = img_.getMat();
+                Mat regions = regions_.getMat();
+                sizes = sizes_.getMat();
+
+                if (image_id != -1 && last_image_id != image_id) {
+
+                    std::vector<Mat> img_planes;
+                    split(img, img_planes);
+
+                    int histogram_bins_size = 10;
+
+                    float range[] = {0.0, 256.0};
+
+                    double min, max;
+                    minMaxLoc(regions, &min, &max);
+                    int nb_segs = (int)max + 1;
+
+                    histogram_size = histogram_bins_size * img.channels() * 8;
+
+                    histograms = Mat_<float>(nb_segs, histogram_size);
+
+                    // Compute, for each channels, the 8 gaussians
+                    std::vector<Mat> img_gaussians;
+
+                    for (int p = 0; p < img.channels(); p++) {
+
+                        Mat tmp_gradiant;
+                        Mat tmp_gradiant_pos, tmp_gradiant_neg;
+                        Mat img_plane_rotated;
+                        Mat tmp_rot;
+
+                        // X, no rot
+                        Scharr(img_planes[p], tmp_gradiant, CV_32F, 1, 0);
+                        threshold(tmp_gradiant, tmp_gradiant_pos, 0, 0, THRESH_TOZERO);
+                        threshold(tmp_gradiant, tmp_gradiant_neg, 0, 0, THRESH_TOZERO_INV);
+
+                        img_gaussians.push_back(tmp_gradiant_pos.clone());
+                        img_gaussians.push_back(tmp_gradiant_neg.clone());
+
+                        // Y, no rot
+                        Scharr(img_planes[p], tmp_gradiant, CV_32F, 0, 1);
+                        threshold(tmp_gradiant, tmp_gradiant_pos, 0, 0, THRESH_TOZERO);
+                        threshold(tmp_gradiant, tmp_gradiant_neg, 0, 0, THRESH_TOZERO_INV);
+
+                        img_gaussians.push_back(tmp_gradiant_pos.clone());
+                        img_gaussians.push_back(tmp_gradiant_neg.clone());
+
+                        Point2f center(img.cols / 2.0f, img.rows / 2.0f);
+                        Mat rot = cv::getRotationMatrix2D(center, 45.0, 1.0);
+                        Rect bbox = cv::RotatedRect(center, img.size(), 45.0).boundingRect();
+                        rot.at<double>(0,2) += bbox.width/2.0 - center.x;
+                        rot.at<double>(1,2) += bbox.height/2.0 - center.y;
+
+                        warpAffine(img_planes[p], img_plane_rotated, rot, bbox.size());
+
+                        // X, rot
+                        Scharr(img_plane_rotated, tmp_gradiant, CV_32F, 1, 0);
+
+                        center = Point((int)(img_plane_rotated.cols / 2.0), (int)(img_plane_rotated.rows / 2.0));
+                        rot = cv::getRotationMatrix2D(center, -45.0, 1.0);
+                        warpAffine(tmp_gradiant, tmp_rot, rot, bbox.size());
+
+                        tmp_gradiant = tmp_rot(Rect((bbox.width - img.cols) / 2, (bbox.height - img.rows) / 2, img.cols, img.rows));
+
+                        threshold(tmp_gradiant, tmp_gradiant_pos, 0, 0, THRESH_TOZERO);
+                        threshold(tmp_gradiant, tmp_gradiant_neg, 0, 0, THRESH_TOZERO_INV);
+
+                        img_gaussians.push_back(tmp_gradiant_pos.clone());
+                        img_gaussians.push_back(tmp_gradiant_neg.clone());
+
+                        // Y, rot
+                        Scharr(img_plane_rotated, tmp_gradiant, CV_32F, 0, 1);
+
+                        center = Point((int)(img_plane_rotated.cols / 2.0), (int)(img_plane_rotated.rows / 2.0));
+                        rot = cv::getRotationMatrix2D(center, -45.0, 1.0);
+                        warpAffine(tmp_gradiant, tmp_rot, rot, bbox.size());
+
+                        tmp_gradiant = tmp_rot(Rect((bbox.width - img.cols) / 2, (bbox.height - img.rows) / 2, img.cols, img.rows));
+
+                        threshold(tmp_gradiant, tmp_gradiant_pos, 0, 0, THRESH_TOZERO);
+                        threshold(tmp_gradiant, tmp_gradiant_neg, 0, 0, THRESH_TOZERO_INV);
+
+                        img_gaussians.push_back(tmp_gradiant_pos.clone());
+                        img_gaussians.push_back(tmp_gradiant_neg.clone());
+
+                    }
+
+                    // Normalisze gaussiaans in 0-255 range (for faster computation of histograms)
+                    for (int i = 0; i < img.channels() * 8; i++) {
+
+                        double hmin, hmax;
+                        minMaxLoc(img_gaussians[i], &hmin, &hmax);
+
+                        Mat tmp;
+                        img_gaussians[i].convertTo(tmp, CV_8U, (range[1] - 1) / (hmax - hmin), -(range[1] - 1) * hmin / (hmax - hmin));
+                        img_gaussians[i] = tmp;
+
+                    }
+
+                    // We compute histograms manualy, directly addings bins based on the region instead of computing multiple histograms
+                    // This speedup significantly computations
+
+                    std::vector<int> totals;
+                    totals.resize(nb_segs);
+
+                    // Bins for histograms
+                    Mat_<int> tmp_histograms = Mat_<int>::zeros(nb_segs, histogram_size);
+
+                    int* regions_data = (int*)regions.data;
+
+                    for (unsigned int x = 0; x < regions.total(); x++) {
+                        int region = regions_data[x];
+
+                        int* histogram = tmp_histograms.ptr<int>(region);
+
+                        for (int p = 0; p < img.channels(); p++) {
+                            for (unsigned int i = 0; i < 8; i++) {
+
+                                int val = (int)((unsigned char*)img_gaussians[p * 8 + i].data)[x];
+
+                                int bin = (int)((float)val / (range[1] / histogram_bins_size));
+
+                                histogram[(p * 8 + i) * histogram_bins_size + bin]++;
+                                totals[region]++;
+                            }
+                        }
+                    }
+
+                    // Normalisation per segments
+                    for (int r = 0; r < nb_segs; r++) {
+
+                        float* histogram = histograms.ptr<float>(r);
+                        int* tmp_histogram = tmp_histograms.ptr<int>(r);
+
+                        for (int h_pos2 = 0; h_pos2 < histogram_size; h_pos2++) {
+                            histogram[h_pos2] = (float)tmp_histogram[h_pos2] / (float)totals[r];
+                        }
+                    }
+
+                    if (image_id != -1) { // Save cache if it's apply
+                        last_histograms = histograms.clone();
+                        last_image_id = image_id;
+                    }
+                } else { // image_id == last_image_id
+                    histograms = last_histograms.clone(); // Use cache
+                }
+            }
+
+            float SelectiveSearchSegmentationStrategyTextureImpl::get(int r1, int r2) {
+
+                float r = 0;
+                float* h1 = histograms.ptr<float>(r1);
+                float* h2 = histograms.ptr<float>(r2);
+
+                for (int i = 0; i < histogram_size; i++) {
+                    r += min(h1[i], h2[i]);
+                }
+
+                return r;
+            }
+
+            void SelectiveSearchSegmentationStrategyTextureImpl::merge(int r1, int r2) {
+                int size_r1 = sizes.at<int>(r1);
+                int size_r2 = sizes.at<int>(r2);
+
+                float* h1 = histograms.ptr<float>(r1);
+                float* h2 = histograms.ptr<float>(r2);
+
+                for (int i = 0; i < histogram_size; i++) {
+                    h1[i] = (h1[i] * size_r1 + h2[i] * size_r2) / (size_r1 + size_r2);
+                    h2[i] = h1[i];
+                }
+            }
+
+
+            Ptr<SelectiveSearchSegmentationStrategyTexture> createSelectiveSearchSegmentationStrategyTexture() {
+                Ptr<SelectiveSearchSegmentationStrategyTexture> s = makePtr<SelectiveSearchSegmentationStrategyTextureImpl>();
+                return s;
+            }
+
+            // Core
+
+            class SelectiveSearchSegmentationImpl : public SelectiveSearchSegmentation {
+                public:
+                    SelectiveSearchSegmentationImpl() {
+                        name_ = "SelectiveSearchSegmentation";
+                    }
+
+                    ~SelectiveSearchSegmentationImpl() {
+                    };
+
+                    virtual void write(FileStorage& fs) const {
+                        fs << "name" << name_;
+                    }
+
+                    virtual void read(const FileNode& fn) {
+                        CV_Assert( (String)fn["name"] == name_);
+                    }
+
+                    virtual void setBaseImage(InputArray img);
+
+                    virtual void switchToSingleStrategy(int k = 200, float sigma = 0.8);
+                    virtual void switchToSelectiveSearchFast(int base_k = 150, int inc_k = 150, float sigma = 0.8);
+                    virtual void switchToSelectiveSearchQuality(int base_k = 150, int inc_k = 150, float sigma = 0.8);
+
+                    virtual void addImage(InputArray img);
+                    virtual void clearImages();
+
+                    virtual void addGraphSegmentation(Ptr<GraphSegmentation> g);
+                    virtual void clearGraphSegmentations();
+
+                    virtual void addStrategy(Ptr<SelectiveSearchSegmentationStrategy> s);
+                    virtual void clearStrategies();
+
+                    virtual void process(std::vector<Rect>& rects);
+
+
+                private:
+                    String name_;
+
+                    Mat base_image;
+                    std::vector<Mat> images;
+                    std::vector<Ptr<GraphSegmentation> > segmentations;
+                    std::vector<Ptr<SelectiveSearchSegmentationStrategy> > strategies;
+
+                    void hierarchicalGrouping(const Mat& img, Ptr<SelectiveSearchSegmentationStrategy>& s, const Mat& img_regions, const Mat_<char>& is_neighbour, const Mat_<int>& sizes, int& nb_segs, const std::vector<Rect>& bounding_rects, std::vector<Region>& regions, int region_id);
+            };
+
+            void SelectiveSearchSegmentationImpl::setBaseImage(InputArray img) {
+                base_image = img.getMat();
+            }
+
+            void SelectiveSearchSegmentationImpl::addImage(InputArray img) {
+                images.push_back(img.getMat());
+            }
+
+            void SelectiveSearchSegmentationImpl::clearImages() {
+                images.clear();
+            }
+
+            void SelectiveSearchSegmentationImpl::addGraphSegmentation(Ptr<GraphSegmentation> g) {
+                segmentations.push_back(g);
+            }
+
+            void SelectiveSearchSegmentationImpl::clearGraphSegmentations() {
+                segmentations.clear();
+            }
+
+            void SelectiveSearchSegmentationImpl::addStrategy(Ptr<SelectiveSearchSegmentationStrategy> s) {
+                strategies.push_back(s);
+            }
+
+            void SelectiveSearchSegmentationImpl::clearStrategies() {
+                strategies.clear();
+            }
+
+            void SelectiveSearchSegmentationImpl::switchToSingleStrategy(int k, float sigma) {
+                clearImages();
+                clearGraphSegmentations();
+                clearStrategies();
+
+                Mat hsv;
+                cvtColor(base_image, hsv, COLOR_BGR2HSV);
+                addImage(hsv);
+
+                Ptr<GraphSegmentation> gs = createGraphSegmentation();
+                gs->setK((float)k);
+                gs->setSigma(sigma);
+                addGraphSegmentation(gs);
+
+                Ptr<SelectiveSearchSegmentationStrategyColor> color = createSelectiveSearchSegmentationStrategyColor();
+                Ptr<SelectiveSearchSegmentationStrategyFill> fill = createSelectiveSearchSegmentationStrategyFill();
+                Ptr<SelectiveSearchSegmentationStrategyTexture> texture = createSelectiveSearchSegmentationStrategyTexture();
+                Ptr<SelectiveSearchSegmentationStrategySize> size = createSelectiveSearchSegmentationStrategySize();
+
+                Ptr<SelectiveSearchSegmentationStrategyMultiple> m = createSelectiveSearchSegmentationStrategyMultiple(color, fill, texture, size);
+
+                addStrategy(m);
+
+            }
+
+            void SelectiveSearchSegmentationImpl::switchToSelectiveSearchFast(int base_k, int inc_k, float sigma) {
+                clearImages();
+                clearGraphSegmentations();
+                clearStrategies();
+
+                Mat hsv;
+                cvtColor(base_image, hsv, COLOR_BGR2HSV);
+                addImage(hsv);
+                Mat lab;
+                cvtColor(base_image, lab, COLOR_BGR2Lab);
+                addImage(lab);
+
+                for (int k = base_k; k <= base_k + inc_k * 2; k+= inc_k) {
+                    Ptr<GraphSegmentation> gs = createGraphSegmentation();
+                    gs->setK((float)k);
+                    gs->setSigma(sigma);
+                    addGraphSegmentation(gs);
+                }
+
+                Ptr<SelectiveSearchSegmentationStrategyColor> color = createSelectiveSearchSegmentationStrategyColor();
+                Ptr<SelectiveSearchSegmentationStrategyFill> fill = createSelectiveSearchSegmentationStrategyFill();
+                Ptr<SelectiveSearchSegmentationStrategyTexture> texture = createSelectiveSearchSegmentationStrategyTexture();
+                Ptr<SelectiveSearchSegmentationStrategySize> size = createSelectiveSearchSegmentationStrategySize();
+
+                Ptr<SelectiveSearchSegmentationStrategyMultiple> m = createSelectiveSearchSegmentationStrategyMultiple(color, fill, texture, size);
+
+                addStrategy(m);
+
+                Ptr<SelectiveSearchSegmentationStrategyFill> fill2 = createSelectiveSearchSegmentationStrategyFill();
+                Ptr<SelectiveSearchSegmentationStrategyTexture> texture2 = createSelectiveSearchSegmentationStrategyTexture();
+                Ptr<SelectiveSearchSegmentationStrategySize> size2 = createSelectiveSearchSegmentationStrategySize();
+
+                Ptr<SelectiveSearchSegmentationStrategyMultiple> m2 = createSelectiveSearchSegmentationStrategyMultiple(fill, texture, size);
+
+                addStrategy(m2);
+
+            }
+
+            void SelectiveSearchSegmentationImpl::switchToSelectiveSearchQuality(int base_k, int inc_k, float sigma) {
+                clearImages();
+                clearGraphSegmentations();
+                clearStrategies();
+
+
+                Mat hsv;
+                cvtColor(base_image, hsv, COLOR_BGR2HSV);
+                addImage(hsv);
+                Mat lab;
+                cvtColor(base_image, lab, COLOR_BGR2Lab);
+                addImage(lab);
+
+                Mat I;
+                cvtColor(base_image, I, COLOR_BGR2GRAY);
+                addImage(I);
+
+                Mat channel[3];
+                split(hsv, channel);
+                addImage(channel[0]);
+
+                split(base_image, channel);
+                std::vector<Mat> channel2;
+                channel2.push_back(channel[2]);
+                channel2.push_back(channel[1]);
+                channel2.push_back(I);
+
+                Mat rgI;
+                merge(channel2, rgI);
+                addImage(rgI);
+
+                for (int k = base_k; k <= base_k + inc_k * 4; k+= inc_k) {
+                    Ptr<GraphSegmentation> gs = createGraphSegmentation();
+                    gs->setK((float)k);
+                    gs->setSigma(sigma);
+                    addGraphSegmentation(gs);
+                }
+
+                Ptr<SelectiveSearchSegmentationStrategyColor> color = createSelectiveSearchSegmentationStrategyColor();
+                Ptr<SelectiveSearchSegmentationStrategyFill> fill = createSelectiveSearchSegmentationStrategyFill();
+                Ptr<SelectiveSearchSegmentationStrategyTexture> texture = createSelectiveSearchSegmentationStrategyTexture();
+                Ptr<SelectiveSearchSegmentationStrategySize> size = createSelectiveSearchSegmentationStrategySize();
+
+                Ptr<SelectiveSearchSegmentationStrategyMultiple> m = createSelectiveSearchSegmentationStrategyMultiple(color, fill, texture, size);
+
+                addStrategy(m);
+
+                Ptr<SelectiveSearchSegmentationStrategyFill> fill2 = createSelectiveSearchSegmentationStrategyFill();
+                Ptr<SelectiveSearchSegmentationStrategyTexture> texture2 = createSelectiveSearchSegmentationStrategyTexture();
+                Ptr<SelectiveSearchSegmentationStrategySize> size2 = createSelectiveSearchSegmentationStrategySize();
+
+                Ptr<SelectiveSearchSegmentationStrategyMultiple> m2 = createSelectiveSearchSegmentationStrategyMultiple(fill, texture, size);
+
+                addStrategy(m2);
+
+                Ptr<SelectiveSearchSegmentationStrategyFill> fill3 = createSelectiveSearchSegmentationStrategyFill();
+                addStrategy(fill3);
+
+                Ptr<SelectiveSearchSegmentationStrategySize> size3 = createSelectiveSearchSegmentationStrategySize();
+                addStrategy(size3);
+            }
+
+            void SelectiveSearchSegmentationImpl::process(std::vector<Rect>& rects) {
+
+                std::vector<Region> all_regions;
+
+                int image_id = 0;
+
+                for(std::vector<Mat>::iterator image = images.begin(); image != images.end(); ++image) {
+                    for(std::vector<Ptr<GraphSegmentation> >::iterator gs = segmentations.begin(); gs != segmentations.end(); ++gs) {
+
+                        Mat img_regions;
+                        Mat_<char> is_neighbour;
+                        Mat_<int> sizes;
+
+                        // Compute initial segmentation
+                        (*gs)->processImage(*image, img_regions);
+
+                        // Get number of regions
+                        double min, max;
+                        minMaxLoc(img_regions, &min, &max);
+                        int nb_segs = (int)max + 1;
+
+                        // Compute bouding rects and neighbours
+                        std::vector<Rect> bounding_rects;
+                        bounding_rects.resize(nb_segs);
+
+                        std::vector<std::vector<cv::Point> > points;
+
+                        points.resize(nb_segs);
+
+                        is_neighbour = Mat::zeros(nb_segs, nb_segs, CV_8UC1);
+                        sizes = Mat::zeros(nb_segs, 1, CV_32SC1);
+
+                        const int* previous_p = NULL;
+
+                        for (int i = 0; i < (int)img_regions.rows; i++) {
+                            const int* p = img_regions.ptr<int>(i);
+
+                            for (int j = 0; j < (int)img_regions.cols; j++) {
+
+                                points[p[j]].push_back(cv::Point(j, i));
+                                sizes.at<int>(p[j], 0) = sizes.at<int>(p[j], 0) + 1;
+
+                                if (i > 0 && j > 0) {
+
+                                    is_neighbour.at<char>(p[j], p[j - 1]) = 1;
+                                    is_neighbour.at<char>(p[j], previous_p[j]) = 1;
+                                    is_neighbour.at<char>(p[j], previous_p[j - 1]) = 1;
+
+                                    is_neighbour.at<char>(p[j - 1], p[j]) = 1;
+                                    is_neighbour.at<char>(previous_p[j], p[j]) = 1;
+                                    is_neighbour.at<char>(previous_p[j - 1], p[j]) = 1;
+                                }
+                            }
+                            previous_p = p;
+                        }
+
+                        for(int seg = 0; seg < nb_segs; seg++) {
+                            bounding_rects[seg] = cv::boundingRect(points[seg]);
+                        }
+
+                        for(std::vector<Ptr<SelectiveSearchSegmentationStrategy> >::iterator strategy = strategies.begin(); strategy != strategies.end(); ++strategy) {
+                            std::vector<Region> regions;
+                            hierarchicalGrouping(*image, *strategy, img_regions, is_neighbour, sizes, nb_segs, bounding_rects, regions, image_id);
+
+                            for(std::vector<Region>::iterator region = regions.begin(); region != regions.end(); ++region) {
+                                all_regions.push_back(*region);
+                            }
+                        }
+
+                        image_id++;
+                    }
+                }
+
+                std::sort(all_regions.begin(), all_regions.end());
+
+                std::map<Rect, char, rectComparator> processed_rect;
+
+                rects.clear();
+
+                // Remove duplicate in rect list
+                for(std::vector<Region>::iterator region = all_regions.begin(); region != all_regions.end(); ++region) {
+                    if (processed_rect.find((*region).bounding_box) == processed_rect.end()) {
+                        processed_rect[(*region).bounding_box] = true;
+                        rects.push_back((*region).bounding_box);
+                    }
+                }
+
+            }
+
+            void SelectiveSearchSegmentationImpl::hierarchicalGrouping(const Mat& img, Ptr<SelectiveSearchSegmentationStrategy>& s, const Mat& img_regions, const Mat_<char>& is_neighbour, const Mat_<int>& sizes_, int& nb_segs, const std::vector<Rect>& bounding_rects, std::vector<Region>& regions, int image_id) {
+
+                Mat sizes = sizes_.clone();
+
+                std::vector<Neighbour> similarities;
+                regions.clear();
+
+                /////////////////////////////////////////
+
+                s->setImage(img, img_regions, sizes, image_id);
+
+                // Compute initial similarities
+                for (int i = 0; i < nb_segs; i++) {
+                    Region r;
+
+                    r.id = i;
+                    r.level = 1;
+                    r.merged_to = -1;
+                    r.bounding_box = bounding_rects[i];
+
+                    regions.push_back(r);
+
+                    for (int j = i + 1; j < nb_segs; j++) {
+                        if (is_neighbour.at<char>(i, j)) {
+                            Neighbour n;
+                            n.from = i;
+                            n.to = j;
+                            n.similarity = s->get(i, j);
+
+                            similarities.push_back(n);
+                        }
+                    }
+                }
+
+                while(similarities.size() > 0) {
+
+                    std::sort(similarities.begin(), similarities.end());
+
+                    // for(std::vector<Neighbour>::iterator similarity = similarities.begin(); similarity != similarities.end(); ++similarity) {
+                    //     std::cout << *similarity << std::endl;
+                    // }
+
+                    Neighbour p = similarities.back();
+                    similarities.pop_back();
+
+                    Region region_from = regions[p.from];
+                    Region region_to = regions[p.to];
+
+                    Region new_r;
+                    new_r.id = std::min(region_from.id, region_to.id); // Should be the smalest, working ID
+                    new_r.level = std::max(region_from.level, region_to.level) + 1;
+                    new_r.merged_to = -1;
+                    new_r.bounding_box = region_from.bounding_box | region_to.bounding_box;
+
+                    regions.push_back(new_r);
+
+                    regions[p.from].merged_to = (int)regions.size() - 1;
+                    regions[p.to].merged_to = (int)regions.size() - 1;
+
+                    // Merge
+                    s->merge(region_from.id, region_to.id);
+
+                    // Update size
+                    sizes.at<int>(region_from.id, 0) += sizes.at<int>(region_to.id, 0);
+                    sizes.at<int>(region_to.id, 0) = sizes.at<int>(region_from.id, 0);
+
+                    std::vector<int> local_neighbours;
+
+                    for(std::vector<Neighbour>::iterator similarity = similarities.begin(); similarity != similarities.end();) {
+                        if ((*similarity).from == p.from || (*similarity).to == p.from || (*similarity).from == p.to || (*similarity).to == p.to) {
+                            int from = 0;
+
+                            if ((*similarity).from == p.from || (*similarity).from == p.to) {
+                                from = (*similarity).to;
+                            } else {
+                                from = (*similarity).from;
+                            }
+
+                            bool already_neighboor = false;
+
+                            for(std::vector<int>::iterator local_neighbour = local_neighbours.begin(); local_neighbour != local_neighbours.end(); local_neighbour++) {
+                                if (*local_neighbour == from) {
+                                    already_neighboor = true;
+                                }
+                            }
+
+                            if (!already_neighboor) {
+                                local_neighbours.push_back(from);
+                            }
+
+                            similarity = similarities.erase(similarity);
+                        } else {
+                            similarity++;
+                        }
+                    }
+
+                    for(std::vector<int>::iterator local_neighbour = local_neighbours.begin(); local_neighbour != local_neighbours.end(); local_neighbour++) {
+
+                        Neighbour n;
+                        n.from = (int)regions.size() - 1;
+                        n.to = *local_neighbour;
+                        n.similarity = s->get(regions[n.from].id, regions[n.to].id);
+
+                        similarities.push_back(n);
+                    }
+                }
+
+                // Compute regions' rank
+                for(std::vector<Region>::iterator region = regions.begin(); region != regions.end(); ++region) {
+                    // Note: this is inverted from the paper, but we keep the lover region first so it's works
+                    (*region).rank = ((double) rand() / (RAND_MAX)) * ((*region).level);
+                }
+
+            }
+
+            Ptr<SelectiveSearchSegmentation> createSelectiveSearchSegmentation() {
+                Ptr<SelectiveSearchSegmentation> s = makePtr<SelectiveSearchSegmentationImpl>();
+                return s;
+            }
+
+            std::ostream& operator<<(std::ostream& os, const Neighbour& n) {
+                os << "Neighbour[" << n.from << "->" << n.to << "," << n.similarity << "]";
+                return os;
+            }
+
+            std::ostream& operator<<(std::ostream& os, const Region& r) {
+                os << "Region[WID" << r.id << ", L" << r.level << ", merged to " << r.merged_to << ", R:" << r.rank << ", " << r.bounding_box << "]";
+                return os;
+            }
+        }
+    }
+}
diff --git a/contrib/modules/ximgproc/src/slic.cpp b/contrib/modules/ximgproc/src/slic.cpp
index d0ef004..4f955fd 100644
--- a/contrib/modules/ximgproc/src/slic.cpp
+++ b/contrib/modules/ximgproc/src/slic.cpp
@@ -226,11 +226,12 @@ void SuperpixelSLICImpl::initialize()
     else
       CV_Error( Error::StsInternal, "No such algorithm" );
 
+    // update amount of labels now
+    m_numlabels = (int)m_kseeds[0].size();
+
     // perturb seeds given edges
     if ( perturbseeds ) PerturbSeeds( edgemag );
 
-    // update amount of labels now
-    m_numlabels = (int)m_kseeds[0].size();
 }
 
 void SuperpixelSLICImpl::iterate( int num_iterations )
@@ -258,10 +259,10 @@ void SuperpixelSLICImpl::getLabelContourMask(OutputArray _mask, bool _thick_line
 
     if ( !_thick_line ) line_width = 1;
 
-    _mask.create( m_height, m_width, CV_8SC1 );
+    _mask.create( m_height, m_width, CV_8UC1 );
     Mat mask = _mask.getMat();
 
-    mask.setTo(1);
+    mask.setTo(0);
 
     const int dx8[8] = { -1, -1,  0,  1, 1, 1, 0, -1 };
     const int dy8[8] = {  0, -1, -1, -1, 0, 1, 1,  1 };
@@ -293,7 +294,7 @@ void SuperpixelSLICImpl::getLabelContourMask(OutputArray _mask, bool _thick_line
         }
         if( np > line_width )
         {
-           mask.at<char>(j,k) = -1;
+           mask.at<char>(j,k) = (uchar)255;
            istaken[mainindex] = true;
         }
         mainindex++;
diff --git a/contrib/modules/ximgproc/src/sparse_match_interpolators.cpp b/contrib/modules/ximgproc/src/sparse_match_interpolators.cpp
index 2ed790e..5be3c46 100644
--- a/contrib/modules/ximgproc/src/sparse_match_interpolators.cpp
+++ b/contrib/modules/ximgproc/src/sparse_match_interpolators.cpp
@@ -11,7 +11,7 @@
  *  Redistribution and use in source and binary forms, with or without modification,
  *  are permitted provided that the following conditions are met :
  *
- *  *Redistributions of source code must retain the above copyright notice,
+ *  * Redistributions of source code must retain the above copyright notice,
  *  this list of conditions and the following disclaimer.
  *
  *  * Redistributions in binary form must reproduce the above copyright notice,
diff --git a/contrib/modules/ximgproc/src/structured_edge_detection.cpp b/contrib/modules/ximgproc/src/structured_edge_detection.cpp
index 69edf4e..ef8acff 100644
--- a/contrib/modules/ximgproc/src/structured_edge_detection.cpp
+++ b/contrib/modules/ximgproc/src/structured_edge_detection.cpp
@@ -235,6 +235,7 @@ static void gradientHist(const cv::Mat &src, cv::Mat &magnitude, cv::Mat &histog
     magnitude /= imsmooth( magnitude, gnrmRad )
         + 0.01*cv::Mat::ones( magnitude.size(), magnitude.type() );
 
+    int pHistSize = histogram.cols*histogram.channels() - 1;
     for (int i = 0; i < phase.rows; ++i)
     {
         const float *pPhase = phase.ptr<float>(i);
@@ -243,7 +244,11 @@ static void gradientHist(const cv::Mat &src, cv::Mat &magnitude, cv::Mat &histog
         float *pHist = histogram.ptr<float>(i/pSize);
 
         for (int j = 0; j < phase.cols; ++j)
-            pHist[cvRound((j/pSize + pPhase[j])*nBins)] += pMagn[j] / CV_SQR(pSize);
+        {
+            int index  = cvRound((j/pSize + pPhase[j])*nBins);
+            index = std::max(0, std::min(index, pHistSize));
+            pHist[index] += pMagn[j] / CV_SQR(pSize);
+        }
     }
 }
 
diff --git a/contrib/modules/ximgproc/src/thinning.cpp b/contrib/modules/ximgproc/src/thinning.cpp
new file mode 100644
index 0000000..c62c13e
--- /dev/null
+++ b/contrib/modules/ximgproc/src/thinning.cpp
@@ -0,0 +1,92 @@
+#include "precomp.hpp"
+
+using namespace std;
+
+namespace cv {
+namespace ximgproc {
+
+// Applies a thinning iteration to a binary image
+static void thinningIteration(Mat img, int iter, int thinningType){
+    Mat marker = Mat::zeros(img.size(), CV_8UC1);
+
+    if(thinningType == THINNING_ZHANGSUEN){
+        for (int i = 1; i < img.rows-1; i++)
+        {
+            for (int j = 1; j < img.cols-1; j++)
+            {
+                uchar p2 = img.at<uchar>(i-1, j);
+                uchar p3 = img.at<uchar>(i-1, j+1);
+                uchar p4 = img.at<uchar>(i, j+1);
+                uchar p5 = img.at<uchar>(i+1, j+1);
+                uchar p6 = img.at<uchar>(i+1, j);
+                uchar p7 = img.at<uchar>(i+1, j-1);
+                uchar p8 = img.at<uchar>(i, j-1);
+                uchar p9 = img.at<uchar>(i-1, j-1);
+
+                int A  = (p2 == 0 && p3 == 1) + (p3 == 0 && p4 == 1) +
+                         (p4 == 0 && p5 == 1) + (p5 == 0 && p6 == 1) +
+                         (p6 == 0 && p7 == 1) + (p7 == 0 && p8 == 1) +
+                         (p8 == 0 && p9 == 1) + (p9 == 0 && p2 == 1);
+                int B  = p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9;
+                int m1 = iter == 0 ? (p2 * p4 * p6) : (p2 * p4 * p8);
+                int m2 = iter == 0 ? (p4 * p6 * p8) : (p2 * p6 * p8);
+
+                if (A == 1 && (B >= 2 && B <= 6) && m1 == 0 && m2 == 0)
+                    marker.at<uchar>(i,j) = 1;
+            }
+        }
+    }
+    if(thinningType == THINNING_GUOHALL){
+        for (int i = 1; i < img.rows-1; i++)
+        {
+            for (int j = 1; j < img.cols-1; j++)
+            {
+                uchar p2 = img.at<uchar>(i-1, j);
+                uchar p3 = img.at<uchar>(i-1, j+1);
+                uchar p4 = img.at<uchar>(i, j+1);
+                uchar p5 = img.at<uchar>(i+1, j+1);
+                uchar p6 = img.at<uchar>(i+1, j);
+                uchar p7 = img.at<uchar>(i+1, j-1);
+                uchar p8 = img.at<uchar>(i, j-1);
+                uchar p9 = img.at<uchar>(i-1, j-1);
+
+                int C  = ((!p2) & (p3 | p4)) + ((!p4) & (p5 | p6)) +
+                         ((!p6) & (p7 | p8)) + ((!p8) & (p9 | p2));
+                int N1 = (p9 | p2) + (p3 | p4) + (p5 | p6) + (p7 | p8);
+                int N2 = (p2 | p3) + (p4 | p5) + (p6 | p7) + (p8 | p9);
+                int N  = N1 < N2 ? N1 : N2;
+                int m  = iter == 0 ? ((p6 | p7 | (!p9)) & p8) : ((p2 | p3 | (!p5)) & p4);
+
+                if ((C == 1) && ((N >= 2) && ((N <= 3)) & (m == 0)))
+                    marker.at<uchar>(i,j) = 1;
+            }
+        }
+    }
+
+    img &= ~marker;
+}
+
+// Apply the thinning procedure to a given image
+void thinning(InputArray input, OutputArray output, int thinningType){
+    Mat processed = input.getMat().clone();
+    // Enforce the range of the input image to be in between 0 - 255
+    processed /= 255;
+
+    Mat prev = Mat::zeros(processed.size(), CV_8UC1);
+    Mat diff;
+
+    do {
+        thinningIteration(processed, 0, thinningType);
+        thinningIteration(processed, 1, thinningType);
+        absdiff(processed, prev, diff);
+        processed.copyTo(prev);
+    }
+    while (countNonZero(diff) > 0);
+
+    processed *= 255;
+
+    output.assign(processed);
+}
+
+} //namespace ximgproc
+} //namespace cv
diff --git a/contrib/modules/ximgproc/src/weighted_median_filter.cpp b/contrib/modules/ximgproc/src/weighted_median_filter.cpp
new file mode 100644
index 0000000..358959c
--- /dev/null
+++ b/contrib/modules/ximgproc/src/weighted_median_filter.cpp
@@ -0,0 +1,723 @@
+/*
+ *  By downloading, copying, installing or using the software you agree to this license.
+ *  If you do not agree to this license, do not download, install,
+ *  copy or use the software.
+ *
+ *
+ *  License Agreement
+ *  For Open Source Computer Vision Library
+ *  (3 - clause BSD License)
+ *
+ *  Redistribution and use in source and binary forms, with or without modification,
+ *  are permitted provided that the following conditions are met :
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *  this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *  this list of conditions and the following disclaimer in the documentation
+ *  and / or other materials provided with the distribution.
+ *
+ *  * Neither the names of the copyright holders nor the names of the contributors
+ *  may be used to endorse or promote products derived from this software
+ *  without specific prior written permission.
+ *
+ *  This software is provided by the copyright holders and contributors "as is" and
+ *  any express or implied warranties, including, but not limited to, the implied
+ *  warranties of merchantability and fitness for a particular purpose are disclaimed.
+ *  In no event shall copyright holders or contributors be liable for any direct,
+ *  indirect, incidental, special, exemplary, or consequential damages
+ *  (including, but not limited to, procurement of substitute goods or services;
+ *  loss of use, data, or profits; or business interruption) however caused
+ *  and on any theory of liability, whether in contract, strict liability,
+ *  or tort(including negligence or otherwise) arising in any way out of
+ *  the use of this software, even if advised of the possibility of such damage.
+ */
+
+#include "precomp.hpp"
+#include <opencv2/imgproc.hpp>
+
+using namespace std;
+using namespace cv;
+
+namespace{
+
+using namespace cv::ximgproc;
+
+/***************************************************************/
+/* Function: from32FTo32S
+ * Description: adaptive quantization for changing a floating-point 1D image to integer image.
+ *                The adaptive quantization strategy is based on binary search, which searches an
+ *                upper bound of quantization error.
+ *                The function also return a mapping between quantized value (32F) and quantized index (32S).
+ *                The mapping is used to convert integer image back to floating-point image after filtering.
+ ***************************************************************/
+void from32FTo32S(Mat &img, Mat &outImg, int nI, float *mapping)
+{
+    int rows = img.rows, cols = img.cols;
+    int alls = rows * cols;
+
+    float *imgPtr = img.ptr<float>();
+    typedef pair<float,int> pairFI;
+    pairFI *data = (pairFI *)malloc(alls*sizeof(pairFI));
+
+    // Sort all pixels of the image by ascending order of pixel value
+    for(int i=0;i<alls;i++){
+        data[i].second = i;
+        data[i].first = imgPtr[i];
+    }
+    sort(data,data+alls);
+
+    // Find lower bound and upper bound of the pixel values
+    double maxVal,minVal;
+    minMaxLoc(img,&minVal,&maxVal);
+    float maxRange = (float)(maxVal - minVal);
+    float th = 1e-5f;
+
+    float l = 0, r = maxRange*2.0f/nI;
+    // Perform binary search on error bound
+    while(r-l > th)
+    {
+        float m = (r+l)*0.5f;
+        bool suc = true;
+        float base = (float)minVal;
+        int cnt=0;
+        for(int i=0;i<alls;i++)
+        {
+            if(data[i].first>base+m)
+            {
+                cnt++;
+                base = data[i].first;
+                if(cnt==nI)
+                {
+                    suc = false;
+                    break;
+                }
+            }
+        }
+        if(suc)r=m;
+        else l=m;
+    }
+
+    Mat retImg(img.size(),CV_32SC1);
+    int *retImgPtr = retImg.ptr<int>();
+
+    // In the sorted list, divide pixel values into clusters according to the minimum error bound
+    // Quantize each value to the median of its cluster
+    // Also record the mapping of quantized value and quantized index.
+    float base = (float)minVal;
+    int baseI = 0;
+    int cnt = 0;
+    for(int i=0;i<=alls;i++)
+    {
+        if(i==alls || data[i].first>base+r)
+        {
+            mapping[cnt] = data[(baseI+i-1)>>1].first; //median
+            if(i==alls)break;
+            cnt++;
+            base = data[i].first;
+            baseI = i;
+        }
+        retImgPtr[data[i].second] = cnt;
+    }
+
+    free(data);
+
+    //end of the function
+    outImg = retImg;
+}
+
+/***************************************************************/
+/* Function: from32STo32F
+ * Description: convert the quantization index image back to the floating-point image accroding to the mapping
+***************************************************************/
+void from32STo32F(Mat &img, Mat &outImg, float *mapping)
+{
+    Mat retImg(img.size(),CV_32F);
+    int rows = img.rows, cols = img.cols, alls = rows*cols;
+    float *retImgPtr = retImg.ptr<float>();
+    int *imgPtr = img.ptr<int>();
+
+    // convert 32S index to 32F real value
+    for(int i=0;i<alls;i++)
+    {
+        retImgPtr[i] = mapping[imgPtr[i]];
+    }
+
+    // end of the function
+    outImg = retImg;
+}
+
+
+/***************************************************************
+ * Function: float2D
+ * Description: allocate a 2D float array with dimension "dim1 x dim2"
+ ***************************************************************/
+float** float2D(int dim1, int dim2)
+{
+    float **ret = new float*[dim1];
+    ret[0] = new float[dim1*dim2];
+    for(int i=1;i<dim1;i++)ret[i] = ret[i-1]+dim2;
+
+    return ret;
+}
+
+/***************************************************************
+ * Function: float2D_release
+ * Description: deallocate the 2D array created by float2D()
+ ***************************************************************/
+void float2D_release(float **p)
+{
+    delete []p[0];
+    delete []p;
+}
+
+/***************************************************************
+ * Function: int2D
+ * Description: allocate a 2D integer array with dimension "dim1 x dim2"
+ ***************************************************************/
+int** int2D(int dim1, int dim2)
+{
+    int **ret = new int*[dim1];
+    ret[0] = new int[dim1*dim2];
+    for(int i=1;i<dim1;i++)ret[i] = ret[i-1]+dim2;
+
+    return ret;
+}
+
+/***************************************************************
+ * Function: int2D_release
+ * Description: deallocate the 2D array created by int2D()
+ ***************************************************************/
+void int2D_release(int **p)
+{
+    delete []p[0];
+    delete []p;
+}
+
+/***************************************************************
+ * Function: updateBCB
+ * Description: maintain the necklace table of BCB
+ ***************************************************************/
+inline void updateBCB(int &num,int *f,int *b,int i,int v)
+{
+    static int p1,p2;
+
+    if(i)
+    {
+        if(!num)
+        { // cell is becoming non-empty
+            p2=f[0];
+            f[0]=i;
+            f[i]=p2;
+            b[p2]=i;
+            b[i]=0;
+        }
+        else if(!(num+v))
+        {// cell is becoming empty
+            p1=b[i],p2=f[i];
+            f[p1]=p2;
+            b[p2]=p1;
+        }
+    }
+
+    // update the cell count
+    num += v;
+}
+
+/***************************************************************
+ * Function: featureIndexing
+ * Description: convert uchar feature image "F" to CV_32SC1 type.
+ *                If F is 3-channel, perform k-means clustering
+ *                If F is 1-channel, only perform type-casting
+ ***************************************************************/
+void featureIndexing(Mat &F, float **&wMap, int &nF, float sigmaI, WMFWeightType weightType){
+    // Configuration and Declaration
+    Mat FNew;
+    int cols = F.cols, rows = F.rows;
+    int alls = cols * rows;
+    int KmeansAttempts=1;
+
+    /* For 1 channel feature image (uchar)*/
+    if(F.channels() == 1)
+    {
+        nF = 256;
+
+        // Type-casting
+        F.convertTo(FNew, CV_32S);
+
+        // Compute weight map (weight between each pair of feature index)
+        wMap = float2D(nF,nF);
+        float nSigmaI = sigmaI;
+        float divider = (1.0f/(2*nSigmaI*nSigmaI));
+
+        for(int i=0;i<nF;i++)
+        {
+            for(int j=i;j<nF;j++)
+            {
+                float diff = fabs((float)(i-j));
+                float val;
+
+                switch(weightType)
+                {
+                    case WMF_EXP: val = exp(-(diff*diff)*divider); break;
+                    case WMF_IV1: val = 1.0f/(diff+nSigmaI); break;
+                    case WMF_IV2: val = 1.0f / (diff*diff+nSigmaI*nSigmaI); break;
+                    case WMF_COS: val = 1.0f; break;
+                    case WMF_JAC: val = (float)(min(i,j)*1.0/max(i,j)); break;
+                    case WMF_OFF: val = 1.0f; break;
+                    default: val = exp(-(diff*diff)*divider);
+                }
+
+                wMap[i][j] = wMap[j][i] = val;
+            }
+        }
+    }
+
+    /* For 3 channel feature image (uchar)*/
+    else if(F.channels() == 3)
+    {
+        const int shift = 2; // 256(8-bit)->64(6-bit)
+        const int LOW_NUM = 256>>shift;
+        static int hash[LOW_NUM][LOW_NUM][LOW_NUM]={{{0}}};
+
+        memset(hash,0,sizeof(hash));
+
+        // throw pixels into a 2D histogram
+        int candCnt = 0;
+        {
+            int lowR,lowG,lowB;
+            uchar *FPtr = F.ptr<uchar>();
+            for(int i=0,i3=0;i<alls;i++,i3+=3)
+            {
+                lowB = FPtr[i3]>>shift;
+                lowG = FPtr[i3+1]>>shift;
+                lowR = FPtr[i3+2]>>shift;
+
+                if(hash[lowB][lowG][lowR]==0)
+                {
+                    candCnt++;
+                    hash[lowB][lowG][lowR]=1;
+                }
+            }
+        }
+
+        nF = min(nF, candCnt);
+        Mat samples(candCnt,3,CV_32F);
+
+        //prepare for K-means
+        int top=0;
+        for(int i=0;i<LOW_NUM;i++)for(int j=0;j<LOW_NUM;j++)for(int k=0;k<LOW_NUM;k++){
+            if(hash[i][j][k]){
+                samples.ptr<float>(top)[0] = (float)i;
+                samples.ptr<float>(top)[1] = (float)j;
+                samples.ptr<float>(top)[2] = (float)k;
+                top++;
+            }
+        }
+
+        //do K-means
+        Mat labels;
+        Mat centers;
+        kmeans(samples, nF, labels, TermCriteria(CV_TERMCRIT_ITER|CV_TERMCRIT_EPS, 0, 10000), KmeansAttempts, KMEANS_PP_CENTERS, centers );
+
+        //make connection (i,j,k) <-> index
+        top = 0;
+        for(int i=0;i<LOW_NUM;i++)for(int j=0;j<LOW_NUM;j++)for(int k=0;k<LOW_NUM;k++)
+        {
+            if(hash[i][j][k])
+            {
+                hash[i][j][k] = labels.ptr<int>(top)[0];
+                top++;
+            }
+        }
+
+        // generate index map
+        FNew = Mat(F.size(),CV_32SC1);
+
+        int lowR,lowG,lowB;
+        uchar *FPtr = F.ptr<uchar>();
+        for(int i=0,i3=0;i<alls;i++,i3+=3)
+        {
+            lowB = FPtr[i3]>>shift;
+            lowG = FPtr[i3+1]>>shift;
+            lowR = FPtr[i3+2]>>shift;
+
+            FNew.ptr<int>()[i] = hash[lowB][lowG][lowR];
+        }
+
+        // Compute weight map (weight between each pair of feature index)
+        wMap = float2D(nF,nF);
+        float nSigmaI = sigmaI/256.0f*LOW_NUM;
+        float divider = (1.0f/(2*nSigmaI*nSigmaI));
+
+        float *length = new float[nF];
+        for(int i=0;i<nF;i++)
+        {
+            float a0 = centers.ptr<float>(i)[0];
+            float a1 = centers.ptr<float>(i)[1];
+            float a2 = centers.ptr<float>(i)[2];
+            length[i] = sqrt(a0*a0+a1*a1+a2*a2);
+        }
+
+        for(int i=0;i<nF;i++)
+        {
+            for(int j=i;j<nF;j++)
+            {
+                float a0 = centers.ptr<float>(i)[0], b0 = centers.ptr<float>(j)[0];
+                float a1 = centers.ptr<float>(i)[1], b1 = centers.ptr<float>(j)[1];
+                float a2 = centers.ptr<float>(i)[2], b2 = centers.ptr<float>(j)[2];
+                float diff0 = a0-b0;
+                float diff1 = a1-b1;
+                float diff2 = a2-b2;
+
+                float val;
+
+                switch(weightType)
+                {
+                    case WMF_EXP: val = exp(-(diff0*diff0+diff1*diff1+diff2*diff2)*divider); break;
+                    case WMF_IV1: val = 1.0f/(fabs(diff0)+fabs(diff1)+fabs(diff2)+nSigmaI); break;
+                    case WMF_IV2: val = 1.0f / (diff0*diff0+diff1*diff1+diff2*diff2+nSigmaI*nSigmaI); break;
+                    case WMF_COS: val = (a0*b0+a1*b1+a2*b2)/(length[i]*length[j]); break;
+                    case WMF_JAC: val = (min(a0,b0)+min(a1,b1)+min(a2,b2))/(max(a0,b0)+max(a1,b1)+max(a2,b2)); break;
+                    case WMF_OFF: val = 1.0f; break;
+                    default: val = exp(-(diff0*diff0+diff1*diff1+diff2*diff2)*divider);
+                }
+
+                wMap[i][j] = wMap[j][i] = val;
+            }
+        }
+
+        delete []length;
+    }
+    //end of the function
+    F = FNew;
+}
+
+Mat filterCore(Mat &I, Mat &F, float **wMap, int r=20, int nF=256, int nI=256, Mat mask=Mat())
+{
+    // Check validation
+    assert(I.depth() == CV_32S && I.channels()==1);//input image: 32SC1
+    assert(F.depth() == CV_32S && F.channels()==1);//feature image: 32SC1
+
+    // Configuration and declaration
+    int rows = I.rows, cols = I.cols;
+    Mat outImg = I.clone();
+
+    // Handle Mask
+    if(mask.empty())
+    {
+        mask = Mat(I.size(),CV_8U);
+        mask = Scalar(1);
+    }
+
+    // Allocate memory for joint-histogram and BCB
+    int **H = int2D(nI,nF);
+    int *BCB = new int[nF];
+
+    // Allocate links for necklace table
+    int **Hf = int2D(nI,nF);//forward link
+    int **Hb = int2D(nI,nF);//backward link
+    int *BCBf = new int[nF];//forward link
+    int *BCBb = new int[nF];//backward link
+
+    // Column Scanning
+    for(int x=0;x<cols;x++)
+    {
+        // Reset histogram and BCB for each column
+        memset(BCB, 0, sizeof(int)*nF);
+        memset(H[0], 0, sizeof(int)*nF*nI);
+        for(int i=0;i<nI;i++)Hf[i][0]=Hb[i][0]=0;
+        BCBf[0]=BCBb[0]=0;
+
+        // Reset cut-point
+        int medianVal = -1;
+
+        // Precompute "x" range and checks boundary
+        int downX = max(0,x-r);
+        int upX = min(cols-1,x+r);
+
+        // Initialize joint-histogram and BCB for the first window
+        int upY = min(rows-1,r);
+        for(int i=0;i<=upY;i++)
+        {
+            int *IPtr = I.ptr<int>(i);
+            int *FPtr = F.ptr<int>(i);
+            uchar *maskPtr = mask.ptr<uchar>(i);
+
+            for(int j=downX;j<=upX;j++)
+            {
+                if(!maskPtr[j])continue;
+
+                int fval = IPtr[j];
+                int *curHist = H[fval];
+                int gval = FPtr[j];
+
+                // Maintain necklace table of joint-histogram
+                if(!curHist[gval] && gval)
+                {
+                    int *curHf = Hf[fval];
+                    int *curHb = Hb[fval];
+
+                    int p1=0,p2=curHf[0];
+                    curHf[p1]=gval;
+                    curHf[gval]=p2;
+                    curHb[p2]=gval;
+                    curHb[gval]=p1;
+                }
+
+                curHist[gval]++;
+                // Maintain necklace table of BCB
+                updateBCB(BCB[gval],BCBf,BCBb,gval,-1);
+            }
+        }
+
+        for(int y=0;y<rows;y++)
+        {
+            // Find weighted median with help of BCB and joint-histogram
+            float balanceWeight = 0;
+            int curIndex = F.ptr<int>(y,x)[0];
+            float *fPtr = wMap[curIndex];
+            int &curMedianVal = medianVal;
+
+            // Compute current balance
+            {
+                int i=0;
+                do
+                {
+                    balanceWeight += BCB[i]*fPtr[i];
+                    i=BCBf[i];
+                }while(i);
+            }
+
+            // Move cut-point to the left
+            if(balanceWeight >= 0)
+            {
+                for(;balanceWeight >= 0 && curMedianVal; curMedianVal--)
+                {
+                    float curWeight = 0;
+                    int *nextHist = H[curMedianVal];
+                    int *nextHf = Hf[curMedianVal];
+
+                    // Compute weight change by shift cut-point
+                    int i=0;
+                    do
+                    {
+                        curWeight += (nextHist[i]<<1)*fPtr[i];
+
+                        // Update BCB and maintain the necklace table of BCB
+                        updateBCB(BCB[i],BCBf,BCBb,i,-(nextHist[i]<<1));
+
+                        i=nextHf[i];
+                    }while(i);
+
+                    balanceWeight -= curWeight;
+                }
+            }
+            // Move cut-point to the right
+            else if(balanceWeight < 0)
+            {
+                for(;balanceWeight < 0 && curMedianVal != nI-1; curMedianVal++)
+                {
+                    float curWeight = 0;
+                    int *nextHist = H[curMedianVal+1];
+                    int *nextHf = Hf[curMedianVal+1];
+
+                    // Compute weight change by shift cut-point
+                    int i=0;
+                    do
+                    {
+                        curWeight += (nextHist[i]<<1)*fPtr[i];
+
+                        // Update BCB and maintain the necklace table of BCB
+                        updateBCB(BCB[i],BCBf,BCBb,i,nextHist[i]<<1);
+
+                        i=nextHf[i];
+                    }while(i);
+                    balanceWeight += curWeight;
+                }
+            }
+
+            // Weighted median is found and written to the output image
+            if(balanceWeight<0)outImg.ptr<int>(y,x)[0] = curMedianVal+1;
+            else outImg.ptr<int>(y,x)[0] = curMedianVal;
+
+            // Update joint-histogram and BCB when local window is shifted.
+            int fval,gval,*curHist;
+
+            // Add entering pixels into joint-histogram and BCB
+            int rownum = y + r + 1;
+            if(rownum < rows)
+            {
+                    int *inputImgPtr = I.ptr<int>(rownum);
+                    int *guideImgPtr = F.ptr<int>(rownum);
+                    uchar *maskPtr = mask.ptr<uchar>(rownum);
+
+                    for(int j=downX;j<=upX;j++)
+                    {
+                        if(!maskPtr[j])continue;
+
+                        fval = inputImgPtr[j];
+                        curHist = H[fval];
+                        gval = guideImgPtr[j];
+
+                        // Maintain necklace table of joint-histogram
+                        if(!curHist[gval] && gval)
+                        {
+                            int *curHf = Hf[fval];
+                            int *curHb = Hb[fval];
+
+                            int p1=0,p2=curHf[0];
+                            curHf[gval]=p2;
+                            curHb[gval]=p1;
+                            curHf[p1]=curHb[p2]=gval;
+                        }
+
+                        curHist[gval]++;
+
+                        // Maintain necklace table of BCB
+                        updateBCB(BCB[gval],BCBf,BCBb,gval,((fval <= medianVal)<<1)-1);
+                    }
+                }
+
+
+                // Delete leaving pixels into joint-histogram and BCB
+                rownum = y - r;
+                if(rownum >= 0)
+                {
+                    int *inputImgPtr = I.ptr<int>(rownum);
+                    int *guideImgPtr = F.ptr<int>(rownum);
+                    uchar *maskPtr = mask.ptr<uchar>(rownum);
+
+                    for(int j=downX;j<=upX;j++)
+                    {
+                        if(!maskPtr[j])continue;
+
+                        fval = inputImgPtr[j];
+                        curHist = H[fval];
+                        gval = guideImgPtr[j];
+
+                        curHist[gval]--;
+
+                        // Maintain necklace table of joint-histogram
+                        if(!curHist[gval] && gval)
+                        {
+                            int *curHf = Hf[fval];
+                            int *curHb = Hb[fval];
+
+                            int p1=curHb[gval],p2=curHf[gval];
+                            curHf[p1]=p2;
+                            curHb[p2]=p1;
+                        }
+
+                        // Maintain necklace table of BCB
+                        updateBCB(BCB[gval],BCBf,BCBb,gval,-((fval <= medianVal)<<1)+1);
+                    }
+                }
+        }
+    }
+
+    // Deallocate the memory
+    {
+        delete []BCB;
+        delete []BCBf;
+        delete []BCBb;
+        int2D_release(H);
+        int2D_release(Hf);
+        int2D_release(Hb);
+    }
+
+    // end of the function
+    return outImg;
+}
+}
+
+namespace cv
+{
+namespace ximgproc
+{
+void weightedMedianFilter(InputArray joint, InputArray src, OutputArray dst, int r, double sigma, WMFWeightType weightType, Mat mask)
+{
+    CV_Assert(!src.empty());
+    CV_Assert(r > 0 && sigma > 0);
+
+    int nI = 256;
+    int nF = 256;
+
+    Mat I = src.getMat();
+    Mat F = joint.getMat();
+    if(joint.empty())
+    {
+        medianBlur(src, dst, r);
+        return;
+    }
+
+    CV_Assert(I.depth() == CV_32F || I.depth() == CV_8U);
+    CV_Assert(F.depth() == CV_8U && (F.channels() == 1 || F.channels() == 3));
+
+    dst.create(src.size(), src.type());
+    Mat D = dst.getMat();
+
+    if(D.data == F.data)
+        F = F.clone();
+    if(D.data == I.data)
+        I = I.clone();
+
+    //Preprocess I
+    //OUTPUT OF THIS STEP: Is, iMap
+    //If I is floating point image, "adaptive quantization" is done in from32FTo32S.
+    //The mapping of floating value to integer value is stored in iMap (for each channel).
+    //"Is" stores each channel of "I". The channels are converted to CV_32S type after this step.
+    vector<float *> iMap(I.channels());
+    vector<Mat> Is;
+    split(I,Is);
+    for(int i=0;i<(int)Is.size();i++)
+    {
+        if(I.depth() == CV_32F)
+        {
+            iMap[i] = new float[nI];
+            from32FTo32S(Is[i],Is[i],nI,iMap[i]);
+        }
+        else if(I.depth() == CV_8U)
+        {
+            Is[i].convertTo(Is[i],CV_32S);
+        }
+    }
+
+    //Preprocess F
+    //OUTPUT OF THIS STEP: F(new), wMap
+    //If "F" is 3-channel image, "clustering feature image" is done in featureIndexing.
+    //If "F" is 1-channel image, featureIndexing only does a type-casting on "F".
+    //The output "F" is CV_32S type, containing indexes of feature values.
+    //"wMap" is a 2D array that defines the distance between each pair of feature indexes.
+    // wMap[i][j] is the weight between feature index "i" and "j".
+    float **wMap = NULL;
+    featureIndexing(F, wMap, nF, float(sigma), weightType);
+
+    //Filtering - Joint-Histogram Framework
+    for(int i=0; i<(int)Is.size(); i++)
+    {
+        Is[i] = filterCore(Is[i], F, wMap, r, nF,nI,mask);
+    }
+    float2D_release(wMap);
+
+    //Postprocess F
+    //Convert input image back to the original type.
+    for(int i = 0; i < (int)Is.size(); i++)
+    {
+        if(I.depth()==CV_32F)
+        {
+            from32STo32F(Is[i],Is[i],iMap[i]);
+            delete []iMap[i];
+        }
+        else if(I.depth()==CV_8U)
+        {
+            Is[i].convertTo(Is[i],CV_8U);
+        }
+    }
+
+    //merge the channels
+    merge(Is, D);
+}
+}
+}
diff --git a/contrib/modules/ximgproc/test/test_adaptive_manifold.cpp b/contrib/modules/ximgproc/test/test_adaptive_manifold.cpp
index 6eca621..5e175b6 100644
--- a/contrib/modules/ximgproc/test/test_adaptive_manifold.cpp
+++ b/contrib/modules/ximgproc/test/test_adaptive_manifold.cpp
@@ -11,7 +11,7 @@
  *  Redistribution and use in source and binary forms, with or without modification,
  *  are permitted provided that the following conditions are met :
  *
- *  *Redistributions of source code must retain the above copyright notice,
+ *  * Redistributions of source code must retain the above copyright notice,
  *  this list of conditions and the following disclaimer.
  *
  *  * Redistributions in binary form must reproduce the above copyright notice,
diff --git a/contrib/modules/ximgproc/test/test_adaptive_manifold_ref_impl.cpp b/contrib/modules/ximgproc/test/test_adaptive_manifold_ref_impl.cpp
index 70d329e..273daed 100644
--- a/contrib/modules/ximgproc/test/test_adaptive_manifold_ref_impl.cpp
+++ b/contrib/modules/ximgproc/test/test_adaptive_manifold_ref_impl.cpp
@@ -11,7 +11,7 @@
  *  Redistribution and use in source and binary forms, with or without modification,
  *  are permitted provided that the following conditions are met :
  *  
- *  *Redistributions of source code must retain the above copyright notice,
+ *  * Redistributions of source code must retain the above copyright notice,
  *  this list of conditions and the following disclaimer.
  *  
  *  * Redistributions in binary form must reproduce the above copyright notice,
@@ -253,7 +253,7 @@ namespace
         const double Lr = 1.0 - sigma_r;
         return max(2, static_cast<int>(ceil(Hs * Lr)));
     }
-
+/*
     void ensureSizeIsEnough(int rows, int cols, int type, Mat& m)
     {
         if (m.empty() || m.type() != type || m.data != m.datastart)
@@ -283,7 +283,7 @@ namespace
     {
         ensureSizeIsEnough(size.height, size.width, type, m);
     }
-
+*/
     template <typename T>
     inline void ensureSizeIsEnough(int rows, int cols, Mat_<T>& m)
     {
diff --git a/contrib/modules/ximgproc/test/test_bilateral_texture_filter.cpp b/contrib/modules/ximgproc/test/test_bilateral_texture_filter.cpp
new file mode 100644
index 0000000..61fa972
--- /dev/null
+++ b/contrib/modules/ximgproc/test/test_bilateral_texture_filter.cpp
@@ -0,0 +1,141 @@
+/*
+ *  By downloading, copying, installing or using the software you agree to this license.
+ *  If you do not agree to this license, do not download, install,
+ *  copy or use the software.
+ *
+ *
+ *  License Agreement
+ *  For Open Source Computer Vision Library
+ *  (3 - clause BSD License)
+ *
+ *  Redistribution and use in source and binary forms, with or without modification,
+ *  are permitted provided that the following conditions are met :
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *  this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *  this list of conditions and the following disclaimer in the documentation
+ *  and / or other materials provided with the distribution.
+ *
+ *  * Neither the names of the copyright holders nor the names of the contributors
+ *  may be used to endorse or promote products derived from this software
+ *  without specific prior written permission.
+ *
+ *  This software is provided by the copyright holders and contributors "as is" and
+ *  any express or implied warranties, including, but not limited to, the implied
+ *  warranties of merchantability and fitness for a particular purpose are disclaimed.
+ *  In no event shall copyright holders or contributors be liable for any direct,
+ *  indirect, incidental, special, exemplary, or consequential damages
+ *  (including, but not limited to, procurement of substitute goods or services;
+ *  loss of use, data, or profits; or business interruption) however caused
+ *  and on any theory of liability, whether in contract, strict liability,
+ *  or tort(including negligence or otherwise) arising in any way out of
+ *  the use of this software, even if advised of the possibility of such damage.
+ */
+
+#include "test_precomp.hpp"
+
+namespace cvtest
+{
+
+using namespace std;
+using namespace std::tr1;
+using namespace testing;
+using namespace perf;
+using namespace cv;
+using namespace cv::ximgproc;
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+
+typedef tuple<int, double, double, MatType, int> BTFParams;
+typedef TestWithParam<BTFParams> BilateralTextureFilterTest;
+
+TEST_P(BilateralTextureFilterTest, SplatSurfaceAccuracy)
+{
+  BTFParams params = GetParam();
+  int fr            = get<0>(params);
+  double sigmaAlpha = get<1>(params);
+  double sigmaAvg   = get<2>(params);
+  int depth         = get<3>(params);
+  int srcCn         = get<4>(params);
+
+  RNG rnd(0);
+
+  Size sz(rnd.uniform(256,512), rnd.uniform(256,512));
+
+  for (int i = 0; i < 5; i++)
+  {
+    Scalar surfaceValue;
+    if(depth == CV_8U)
+        rnd.fill(surfaceValue, RNG::UNIFORM, 0, 255);
+    else
+        rnd.fill(surfaceValue, RNG::UNIFORM, 0.0f, 1.0f);
+
+    Mat src(sz, CV_MAKE_TYPE(depth, srcCn), surfaceValue);
+
+    Mat res;
+    bilateralTextureFilter(src, res, fr, 1, sigmaAlpha, sigmaAvg);
+
+    double normL1 = cvtest::norm(src, res, NORM_L1)/src.total()/src.channels();
+    EXPECT_LE(normL1, 1.0/64.0);
+  }
+}
+
+TEST_P(BilateralTextureFilterTest, MultiThreadReproducibility)
+{
+    if (cv::getNumberOfCPUs() == 1)
+      return;
+
+    BTFParams params = GetParam();
+    int fr            = get<0>(params);
+    double sigmaAlpha = get<1>(params);
+    double sigmaAvg   = get<2>(params);
+    int depth         = get<3>(params);
+    int srcCn         = get<4>(params);
+
+    double MAX_DIF = 1.0;
+    double MAX_MEAN_DIF = 1.0 / 64.0;
+    int loopsCount = 2;
+    RNG rnd(1);
+
+    Size sz(rnd.uniform(256,512), rnd.uniform(256,512));
+
+    Mat src(sz,CV_MAKE_TYPE(depth, srcCn));
+    if(src.depth()==CV_8U)
+        randu(src, 0, 255);
+    else if(src.depth()==CV_16S)
+        randu(src, -32767, 32767);
+    else
+        randu(src, 0.0f, 1.0f);
+
+    for (int iter = 0; iter <= loopsCount; iter++)
+    {
+        cv::setNumThreads(cv::getNumberOfCPUs());
+        Mat resMultiThread;
+        bilateralTextureFilter(src, resMultiThread, fr, 1, sigmaAlpha, sigmaAvg);
+
+        cv::setNumThreads(1);
+        Mat resSingleThread;
+        bilateralTextureFilter(src, resSingleThread, fr, 1, sigmaAlpha, sigmaAvg);
+
+        EXPECT_LE(cv::norm(resSingleThread, resMultiThread, NORM_INF), MAX_DIF);
+        EXPECT_LE(
+          cv::norm(resSingleThread, resMultiThread, NORM_L1),
+          MAX_MEAN_DIF * src.total() * src.channels());
+    }
+}
+
+INSTANTIATE_TEST_CASE_P(
+  TypicalSet1,
+  BilateralTextureFilterTest,
+  Combine(
+    Values(2),
+    Values(0.5),
+    Values(0.5),
+    Values(CV_8U, CV_32F),
+    Values(1, 3)
+    )
+);
+}
diff --git a/contrib/modules/ximgproc/test/test_disparity_wls_filter.cpp b/contrib/modules/ximgproc/test/test_disparity_wls_filter.cpp
index a3e0ce6..93323b5 100644
--- a/contrib/modules/ximgproc/test/test_disparity_wls_filter.cpp
+++ b/contrib/modules/ximgproc/test/test_disparity_wls_filter.cpp
@@ -11,7 +11,7 @@
  *  Redistribution and use in source and binary forms, with or without modification,
  *  are permitted provided that the following conditions are met :
  *
- *  *Redistributions of source code must retain the above copyright notice,
+ *  * Redistributions of source code must retain the above copyright notice,
  *  this list of conditions and the following disclaimer.
  *
  *  * Redistributions in binary form must reproduce the above copyright notice,
diff --git a/contrib/modules/ximgproc/test/test_domain_transform.cpp b/contrib/modules/ximgproc/test/test_domain_transform.cpp
index 53bf010..8695117 100644
--- a/contrib/modules/ximgproc/test/test_domain_transform.cpp
+++ b/contrib/modules/ximgproc/test/test_domain_transform.cpp
@@ -11,7 +11,7 @@
  *  Redistribution and use in source and binary forms, with or without modification,
  *  are permitted provided that the following conditions are met :
  *
- *  *Redistributions of source code must retain the above copyright notice,
+ *  * Redistributions of source code must retain the above copyright notice,
  *  this list of conditions and the following disclaimer.
  *
  *  * Redistributions in binary form must reproduce the above copyright notice,
diff --git a/contrib/modules/ximgproc/test/test_fgs_filter.cpp b/contrib/modules/ximgproc/test/test_fgs_filter.cpp
index 3f35082..94b4e7d 100644
--- a/contrib/modules/ximgproc/test/test_fgs_filter.cpp
+++ b/contrib/modules/ximgproc/test/test_fgs_filter.cpp
@@ -11,7 +11,7 @@
  *  Redistribution and use in source and binary forms, with or without modification,
  *  are permitted provided that the following conditions are met :
  *
- *  *Redistributions of source code must retain the above copyright notice,
+ *  * Redistributions of source code must retain the above copyright notice,
  *  this list of conditions and the following disclaimer.
  *
  *  * Redistributions in binary form must reproduce the above copyright notice,
diff --git a/contrib/modules/ximgproc/test/test_fld.cpp b/contrib/modules/ximgproc/test/test_fld.cpp
new file mode 100644
index 0000000..7e8e682
--- /dev/null
+++ b/contrib/modules/ximgproc/test/test_fld.cpp
@@ -0,0 +1,173 @@
+#include "test_precomp.hpp"
+
+#include <vector>
+
+using namespace cv;
+using namespace cv::ximgproc;
+using namespace std;
+
+const Size img_size(640, 480);
+const int FLD_TEST_SEED = 0x134679;
+const int EPOCHS = 20;
+
+class FLDBase : public testing::Test
+{
+    public:
+        FLDBase() { }
+
+    protected:
+        Mat test_image;
+        vector<Vec4f> lines;
+        RNG rng;
+        int passedtests;
+
+        void GenerateWhiteNoise(Mat& image);
+        void GenerateConstColor(Mat& image);
+        void GenerateLines(Mat& image, const unsigned int numLines);
+        void GenerateBrokenLines(Mat& image, const unsigned int numLines);
+        void GenerateRotatedRect(Mat& image);
+        virtual void SetUp();
+};
+
+class ximgproc_FLD: public FLDBase
+{
+    public:
+        ximgproc_FLD() { }
+    protected:
+
+};
+
+void FLDBase::GenerateWhiteNoise(Mat& image)
+{
+    image = Mat(img_size, CV_8UC1);
+    rng.fill(image, RNG::UNIFORM, 0, 256);
+}
+
+void FLDBase::GenerateConstColor(Mat& image)
+{
+    image = Mat(img_size, CV_8UC1, Scalar::all(rng.uniform(0, 256)));
+}
+
+void FLDBase::GenerateLines(Mat& image, const unsigned int numLines)
+{
+    image = Mat(img_size, CV_8UC1, Scalar::all(rng.uniform(0, 128)));
+
+    for(unsigned int i = 0; i < numLines; ++i)
+    {
+        int y = rng.uniform(10, img_size.width - 10);
+        Point p1(y, 10);
+        Point p2(y, img_size.height - 10);
+        line(image, p1, p2, Scalar(255), 2);
+    }
+}
+
+void FLDBase::GenerateBrokenLines(Mat& image, const unsigned int numLines)
+{
+    image = Mat(img_size, CV_8UC1, Scalar::all(rng.uniform(0, 128)));
+
+    for(unsigned int i = 0; i < numLines; ++i)
+    {
+        int y = rng.uniform(10, img_size.width - 10);
+        Point p1(y, 10);
+        Point p2(y, img_size.height/2);
+        line(image, p1, p2, Scalar(255), 2);
+        p1 = Point2i(y, img_size.height/2 + 3);
+        p2 = Point2i(y, img_size.height - 10);
+        line(image, p1, p2, Scalar(255), 2);
+    }
+}
+
+void FLDBase::GenerateRotatedRect(Mat& image)
+{
+    image = Mat::zeros(img_size, CV_8UC1);
+
+    Point center(rng.uniform(img_size.width/4, img_size.width*3/4),
+            rng.uniform(img_size.height/4, img_size.height*3/4));
+    Size rect_size(rng.uniform(img_size.width/8, img_size.width/6),
+            rng.uniform(img_size.height/8, img_size.height/6));
+    float angle = rng.uniform(0.f, 360.f);
+
+    Point2f vertices[4];
+
+    RotatedRect rRect = RotatedRect(center, rect_size, angle);
+
+    rRect.points(vertices);
+    for (int i = 0; i < 4; i++)
+    {
+        line(image, vertices[i], vertices[(i + 1) % 4], Scalar(255), 3);
+    }
+}
+
+void FLDBase::SetUp()
+{
+    lines.clear();
+    test_image = Mat();
+    rng = RNG(FLD_TEST_SEED);
+    passedtests = 0;
+}
+
+
+TEST_F(ximgproc_FLD, whiteNoise)
+{
+    for (int i = 0; i < EPOCHS; ++i)
+    {
+        GenerateWhiteNoise(test_image);
+        Ptr<FastLineDetector> detector = createFastLineDetector(20);
+        detector->detect(test_image, lines);
+
+        if(40u >= lines.size()) ++passedtests;
+    }
+    ASSERT_EQ(EPOCHS, passedtests);
+}
+
+TEST_F(ximgproc_FLD, constColor)
+{
+    for (int i = 0; i < EPOCHS; ++i)
+    {
+        GenerateConstColor(test_image);
+        Ptr<FastLineDetector> detector = createFastLineDetector();
+        detector->detect(test_image, lines);
+
+        if(0u == lines.size()) ++passedtests;
+    }
+    ASSERT_EQ(EPOCHS, passedtests);
+}
+
+TEST_F(ximgproc_FLD, lines)
+{
+    for (int i = 0; i < EPOCHS; ++i)
+    {
+        const unsigned int numOfLines = 1;
+        GenerateLines(test_image, numOfLines);
+        Ptr<FastLineDetector> detector = createFastLineDetector();
+        detector->detect(test_image, lines);
+        if(numOfLines * 2 == lines.size()) ++passedtests;  // * 2 because of Gibbs effect
+    }
+    ASSERT_EQ(EPOCHS, passedtests);
+}
+
+TEST_F(ximgproc_FLD, mergeLines)
+{
+    for (int i = 0; i < EPOCHS; ++i)
+    {
+        const unsigned int numOfLines = 1;
+        GenerateBrokenLines(test_image, numOfLines);
+        Ptr<FastLineDetector> detector = createFastLineDetector(10, 1.414213562f, true);
+        detector->detect(test_image, lines);
+        if(numOfLines * 2 == lines.size()) ++passedtests;  // * 2 because of Gibbs effect
+    }
+    ASSERT_EQ(EPOCHS, passedtests);
+}
+
+TEST_F(ximgproc_FLD, rotatedRect)
+{
+    for (int i = 0; i < EPOCHS; ++i)
+    {
+        GenerateRotatedRect(test_image);
+        Ptr<FastLineDetector> detector = createFastLineDetector();
+        detector->detect(test_image, lines);
+
+        if(2u <= lines.size())  ++passedtests;
+    }
+    ASSERT_EQ(EPOCHS, passedtests);
+}
diff --git a/contrib/modules/ximgproc/test/test_guided_filter.cpp b/contrib/modules/ximgproc/test/test_guided_filter.cpp
index 42a11a7..04b185f 100644
--- a/contrib/modules/ximgproc/test/test_guided_filter.cpp
+++ b/contrib/modules/ximgproc/test/test_guided_filter.cpp
@@ -11,7 +11,7 @@
  *  Redistribution and use in source and binary forms, with or without modification,
  *  are permitted provided that the following conditions are met :
  *
- *  *Redistributions of source code must retain the above copyright notice,
+ *  * Redistributions of source code must retain the above copyright notice,
  *  this list of conditions and the following disclaimer.
  *
  *  * Redistributions in binary form must reproduce the above copyright notice,
@@ -387,6 +387,47 @@ TEST_P(GuidedFilterTest, accuracy)
     }
 }
 
+TEST_P(GuidedFilterTest, smallParamsIssue)
+{
+    GFParams params = GetParam();
+    string guideFileName = get<1>(params);
+    string srcFileName = get<2>(params);
+    int guideCnNum = 3;
+    int srcCnNum = get<0>(params);
+
+    Mat guide = imread(getOpenCVExtraDir() + guideFileName);
+    Mat src = imread(getOpenCVExtraDir() + srcFileName);
+    ASSERT_TRUE(!guide.empty() && !src.empty());
+
+    Size dstSize(guide.cols, guide.rows);
+    guide = convertTypeAndSize(guide, CV_MAKE_TYPE(guide.depth(), guideCnNum), dstSize);
+    src = convertTypeAndSize(src, CV_MAKE_TYPE(src.depth(), srcCnNum), dstSize);
+    Mat output;
+
+    ximgproc::guidedFilter(guide, src, output, 3, 1e-6);
+
+    size_t whitePixels = 0;
+    for(int i = 0; i < output.cols; i++)
+    {
+        for(int j = 0; j < output.rows; j++)
+        {
+            if(output.channels() == 1)
+            {
+                if(output.ptr<uchar>(i)[j] == 255)
+                    whitePixels++;
+            }
+            else if(output.channels() == 3)
+            {
+                Vec3b currentPixel = output.ptr<Vec3b>(i)[j];
+                if(currentPixel == Vec3b(255, 255, 255))
+                    whitePixels++;
+            }
+        }
+    }
+    double whiteRate = whitePixels / (double) output.total();
+    EXPECT_LE(whiteRate, 0.1);
+}
+
 INSTANTIATE_TEST_CASE_P(TypicalSet, GuidedFilterTest,
     Combine(
     Values(1, 3),
diff --git a/contrib/modules/ximgproc/test/test_joint_bilateral_filter.cpp b/contrib/modules/ximgproc/test/test_joint_bilateral_filter.cpp
index ccd41de..9c4de77 100644
--- a/contrib/modules/ximgproc/test/test_joint_bilateral_filter.cpp
+++ b/contrib/modules/ximgproc/test/test_joint_bilateral_filter.cpp
@@ -11,7 +11,7 @@
  *  Redistribution and use in source and binary forms, with or without modification,
  *  are permitted provided that the following conditions are met :
  *
- *  *Redistributions of source code must retain the above copyright notice,
+ *  * Redistributions of source code must retain the above copyright notice,
  *  this list of conditions and the following disclaimer.
  *
  *  * Redistributions in binary form must reproduce the above copyright notice,
diff --git a/contrib/modules/ximgproc/test/test_l0_smooth.cpp b/contrib/modules/ximgproc/test/test_l0_smooth.cpp
index dae1b43..9f006a5 100644
--- a/contrib/modules/ximgproc/test/test_l0_smooth.cpp
+++ b/contrib/modules/ximgproc/test/test_l0_smooth.cpp
@@ -11,7 +11,7 @@
  *  Redistribution and use in source and binary forms, with or without modification,
  *  are permitted provided that the following conditions are met :
  *
- *  *Redistributions of source code must retain the above copyright notice,
+ *  * Redistributions of source code must retain the above copyright notice,
  *  this list of conditions and the following disclaimer.
  *
  *  * Redistributions in binary form must reproduce the above copyright notice,
diff --git a/contrib/modules/ximgproc/test/test_rolling_guidance_filter.cpp b/contrib/modules/ximgproc/test/test_rolling_guidance_filter.cpp
index 604f851..a29f9c4 100644
--- a/contrib/modules/ximgproc/test/test_rolling_guidance_filter.cpp
+++ b/contrib/modules/ximgproc/test/test_rolling_guidance_filter.cpp
@@ -11,7 +11,7 @@
  *  Redistribution and use in source and binary forms, with or without modification,
  *  are permitted provided that the following conditions are met :
  *
- *  *Redistributions of source code must retain the above copyright notice,
+ *  * Redistributions of source code must retain the above copyright notice,
  *  this list of conditions and the following disclaimer.
  *
  *  * Redistributions in binary form must reproduce the above copyright notice,
diff --git a/contrib/modules/ximgproc/test/test_sparse_match_interpolator.cpp b/contrib/modules/ximgproc/test/test_sparse_match_interpolator.cpp
index bb9eb61..fece6db 100644
--- a/contrib/modules/ximgproc/test/test_sparse_match_interpolator.cpp
+++ b/contrib/modules/ximgproc/test/test_sparse_match_interpolator.cpp
@@ -11,7 +11,7 @@
  *  Redistribution and use in source and binary forms, with or without modification,
  *  are permitted provided that the following conditions are met :
  *
- *  *Redistributions of source code must retain the above copyright notice,
+ *  * Redistributions of source code must retain the above copyright notice,
  *  this list of conditions and the following disclaimer.
  *
  *  * Redistributions in binary form must reproduce the above copyright notice,
diff --git a/contrib/modules/ximgproc/test/test_thinning.cpp b/contrib/modules/ximgproc/test/test_thinning.cpp
new file mode 100644
index 0000000..b5a9fe2
--- /dev/null
+++ b/contrib/modules/ximgproc/test/test_thinning.cpp
@@ -0,0 +1,54 @@
+// This file is part of OpenCV project.
+// It is subject to the license terms in the LICENSE file found in the top-level directory
+// of this distribution and at http://opencv.org/license.html.
+
+#include "test_precomp.hpp"
+
+using namespace cv;
+using namespace cv::ximgproc;
+
+namespace {
+
+static int createTestImage(Mat& src)
+{
+    src = Mat::zeros(Size(256, 256), CV_8UC1);
+    for (int x = 50; x < src.cols - 50; x += 50)
+    {
+        cv::circle(src, Point(x, x/2), 30 + x/2, Scalar(255), 5);
+    }
+    int src_pixels = countNonZero(src);
+    EXPECT_GT(src_pixels, 0);
+    return src_pixels;
+}
+
+TEST(ximpgroc_Thinning, simple_ZHANGSUEN)
+{
+    Mat src;
+    int src_pixels = createTestImage(src);
+
+    Mat dst;
+    thinning(src, dst, THINNING_ZHANGSUEN);
+    int dst_pixels = countNonZero(dst);
+    EXPECT_LE(dst_pixels, src_pixels);
+
+#if 0
+    imshow("src", src); imshow("dst", dst); waitKey();
+#endif
+}
+
+TEST(ximpgroc_Thinning, simple_GUOHALL)
+{
+    Mat src;
+    int src_pixels = createTestImage(src);
+
+    Mat dst;
+    thinning(src, dst, THINNING_GUOHALL);
+    int dst_pixels = countNonZero(dst);
+    EXPECT_LE(dst_pixels, src_pixels);
+
+#if 0
+    imshow("src", src); imshow("dst", dst); waitKey();
+#endif
+}
+
+}
diff --git a/contrib/modules/ximgproc/test/test_weighted_median_filter.cpp b/contrib/modules/ximgproc/test/test_weighted_median_filter.cpp
new file mode 100644
index 0000000..9dea51f
--- /dev/null
+++ b/contrib/modules/ximgproc/test/test_weighted_median_filter.cpp
@@ -0,0 +1,107 @@
+/*
+ *  By downloading, copying, installing or using the software you agree to this license.
+ *  If you do not agree to this license, do not download, install,
+ *  copy or use the software.
+ *
+ *
+ *  License Agreement
+ *  For Open Source Computer Vision Library
+ *  (3 - clause BSD License)
+ *
+ *  Redistribution and use in source and binary forms, with or without modification,
+ *  are permitted provided that the following conditions are met :
+ *
+ *  * Redistributions of source code must retain the above copyright notice,
+ *  this list of conditions and the following disclaimer.
+ *
+ *  * Redistributions in binary form must reproduce the above copyright notice,
+ *  this list of conditions and the following disclaimer in the documentation
+ *  and / or other materials provided with the distribution.
+ *
+ *  * Neither the names of the copyright holders nor the names of the contributors
+ *  may be used to endorse or promote products derived from this software
+ *  without specific prior written permission.
+ *
+ *  This software is provided by the copyright holders and contributors "as is" and
+ *  any express or implied warranties, including, but not limited to, the implied
+ *  warranties of merchantability and fitness for a particular purpose are disclaimed.
+ *  In no event shall copyright holders or contributors be liable for any direct,
+ *  indirect, incidental, special, exemplary, or consequential damages
+ *  (including, but not limited to, procurement of substitute goods or services;
+ *  loss of use, data, or profits; or business interruption) however caused
+ *  and on any theory of liability, whether in contract, strict liability,
+ *  or tort(including negligence or otherwise) arising in any way out of
+ *  the use of this software, even if advised of the possibility of such damage.
+ */
+
+#include "test_precomp.hpp"
+
+namespace cvtest
+{
+
+using namespace std;
+using namespace std::tr1;
+using namespace testing;
+using namespace perf;
+using namespace cv;
+using namespace cv::ximgproc;
+
+static string getDataDir()
+{
+    return cvtest::TS::ptr()->get_data_path();
+}
+
+typedef tuple<Size, WMFWeightType> WMFParams;
+typedef TestWithParam<WMFParams> WeightedMedianFilterTest;
+
+TEST_P(WeightedMedianFilterTest, SplatSurfaceAccuracy)
+{
+
+    WMFParams params = GetParam();
+    Size size = get<0>(params);
+    WMFWeightType weightType = get<1>(params);
+
+    RNG rnd(0);
+
+    int guideCn = rnd.uniform(1, 2);
+    if(guideCn==2) guideCn++; //1 or 3 channels
+    Mat guide(size, CV_MAKE_TYPE(CV_8U, guideCn));
+    randu(guide, 0, 255);
+
+    Scalar surfaceValue;
+    int srcCn = rnd.uniform(1, 4);
+    rnd.fill(surfaceValue, RNG::UNIFORM, 0, 255);
+    Mat src(size, CV_MAKE_TYPE(CV_8U, srcCn), surfaceValue);
+
+    int r = int(rnd.uniform(3, 11));
+    double sigma  = rnd.uniform(9.0, 100.0);
+
+    Mat res;
+    weightedMedianFilter(guide, src, res, r, sigma, weightType);
+
+    double normL1 = cvtest::norm(src, res, NORM_L1)/src.total()/src.channels();
+    EXPECT_LE(normL1, 1.0/64);
+}
+
+TEST(WeightedMedianFilterTest, ReferenceAccuracy)
+{
+    string dir = getDataDir() + "cv/edgefilter";
+
+    Mat src = imread(dir + "/kodim23.png");
+    Mat ref = imread(dir + "/fgs/kodim23_lambda=1000_sigma=10.png");
+
+    ASSERT_FALSE(src.empty());
+    ASSERT_FALSE(ref.empty());
+
+    cv::setNumThreads(cv::getNumberOfCPUs());
+    Mat res;
+    weightedMedianFilter(src, src, res, 7);
+
+    double totalMaxError = 1.0/32.0*src.total()*src.channels();
+
+    EXPECT_LE(cvtest::norm(res, ref, NORM_L2), totalMaxError);
+}
+
+INSTANTIATE_TEST_CASE_P(TypicalSET, WeightedMedianFilterTest, Combine(Values(szODD, szQVGA),  Values(WMF_EXP, WMF_IV2, WMF_OFF)));
+
+}
diff --git a/contrib/modules/ximgproc/tutorials/disparity_filtering.markdown b/contrib/modules/ximgproc/tutorials/disparity_filtering.markdown
index 4ca559f..0248c6d 100644
--- a/contrib/modules/ximgproc/tutorials/disparity_filtering.markdown
+++ b/contrib/modules/ximgproc/tutorials/disparity_filtering.markdown
@@ -27,7 +27,7 @@ Source Stereoscopic Image
 Source Code
 -----------
 
-We will be using snippets from the example application, that can be downloaded [here ](https://github.com/Itseez/opencv_contrib/blob/master/modules/ximgproc/samples/disparity_filtering.cpp).
+We will be using snippets from the example application, that can be downloaded [here ](https://github.com/opencv/opencv_contrib/blob/master/modules/ximgproc/samples/disparity_filtering.cpp).
 
 Explanation
 -----------
diff --git a/contrib/modules/xobjdetect/CMakeLists.txt b/contrib/modules/xobjdetect/CMakeLists.txt
index 6adbd4b..567909b 100644
--- a/contrib/modules/xobjdetect/CMakeLists.txt
+++ b/contrib/modules/xobjdetect/CMakeLists.txt
@@ -1,5 +1,5 @@
 set(the_description "Object detection algorithms")
 ocv_define_module(xobjdetect opencv_core opencv_imgproc opencv_highgui opencv_objdetect WRAP python)
-if (NOT IOS)
+if (NOT APPLE_FRAMEWORK)
     add_subdirectory(tools)
 endif()
diff --git a/contrib/modules/xobjdetect/README.md b/contrib/modules/xobjdetect/README.md
index 20b0fc6..1b428e7 100644
--- a/contrib/modules/xobjdetect/README.md
+++ b/contrib/modules/xobjdetect/README.md
@@ -1,3 +1,4 @@
-Integral Channel Features Detector Framework
-============================================
+Object Detection using Boosted Features
+=======================================
 
+Uses a Waldboost cascade and local binary patterns computed as integral features for 2D object detection.
diff --git a/contrib/modules/xobjdetect/src/precomp.hpp b/contrib/modules/xobjdetect/src/precomp.hpp
index a83f787..daf8f61 100644
--- a/contrib/modules/xobjdetect/src/precomp.hpp
+++ b/contrib/modules/xobjdetect/src/precomp.hpp
@@ -76,6 +76,5 @@ the use of this software, even if advised of the possibility of such damage.
 #include "lbpfeatures.h"
 #include "waldboost.hpp"
 #include "wbdetector.hpp"
-#include <opencv2/xobjdetect.hpp>
 
 #endif /* __OPENCV_XOBJDETECT_PRECOMP_HPP__ */
diff --git a/contrib/modules/xobjdetect/tools/waldboost_detector/CMakeLists.txt b/contrib/modules/xobjdetect/tools/waldboost_detector/CMakeLists.txt
index 7d2272a..8ed7eb6 100644
--- a/contrib/modules/xobjdetect/tools/waldboost_detector/CMakeLists.txt
+++ b/contrib/modules/xobjdetect/tools/waldboost_detector/CMakeLists.txt
@@ -19,13 +19,12 @@ file(GLOB ${the_target}_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp)
 
 add_executable(${the_target} ${${the_target}_SOURCES})
 
-target_link_libraries(${the_target} ${OPENCV_${the_target}_DEPS})
+ocv_target_link_libraries(${the_target} ${OPENCV_${the_target}_DEPS})
 
 set_target_properties(${the_target} PROPERTIES
                       DEBUG_POSTFIX "${OPENCV_DEBUG_POSTFIX}"
                       ARCHIVE_OUTPUT_DIRECTORY ${LIBRARY_OUTPUT_PATH}
                       RUNTIME_OUTPUT_DIRECTORY ${EXECUTABLE_OUTPUT_PATH}
-                      INSTALL_NAME_DIR lib
                       OUTPUT_NAME ${the_target})
 
 if(ENABLE_SOLUTION_FOLDERS)
diff --git a/contrib/modules/xphoto/doc/xphoto.bib b/contrib/modules/xphoto/doc/xphoto.bib
index b3db180..b57471c 100644
--- a/contrib/modules/xphoto/doc/xphoto.bib
+++ b/contrib/modules/xphoto/doc/xphoto.bib
@@ -6,3 +6,11 @@
   year={2012},
   publisher={Springer}
 }
+
+ at inproceedings{Cheng2015,
+  title={Effective learning-based illuminant estimation using simple features},
+  author={Cheng, Dongliang and Price, Brian and Cohen, Scott and Brown, Michael S},
+  booktitle={Proceedings of the IEEE Conference on Computer Vision and Pattern Recognition},
+  pages={1000--1008},
+  year={2015}
+}
diff --git a/contrib/modules/xphoto/include/opencv2/xphoto.hpp b/contrib/modules/xphoto/include/opencv2/xphoto.hpp
index 844ef41..73b1e0b 100644
--- a/contrib/modules/xphoto/include/opencv2/xphoto.hpp
+++ b/contrib/modules/xphoto/include/opencv2/xphoto.hpp
@@ -49,4 +49,5 @@
 #include "xphoto/inpainting.hpp"
 #include "xphoto/white_balance.hpp"
 #include "xphoto/dct_image_denoising.hpp"
+#include "xphoto/bm3d_image_denoising.hpp"
 #endif
diff --git a/contrib/modules/xphoto/include/opencv2/xphoto/bm3d_image_denoising.hpp b/contrib/modules/xphoto/include/opencv2/xphoto/bm3d_image_denoising.hpp
new file mode 100644
index 0000000..5873f4c
--- /dev/null
+++ b/contrib/modules/xphoto/include/opencv2/xphoto/bm3d_image_denoising.hpp
@@ -0,0 +1,186 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+//  By downloading, copying, installing or using the software you agree to this license.
+//  If you do not agree to this license, do not download, install,
+//  copy or use the software.
+//
+//
+//                           License Agreement
+//                For Open Source Computer Vision Library
+//
+// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
+// Copyright (C) 2009-2011, Willow Garage Inc., all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+//   * Redistribution's of source code must retain the above copyright notice,
+//     this list of conditions and the following disclaimer.
+//
+//   * Redistribution's in binary form must reproduce the above copyright notice,
+//     this list of conditions and the following disclaimer in the documentation
+//     and/or other materials provided with the distribution.
+//
+//   * The name of the copyright holders may not be used to endorse or promote products
+//     derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#ifndef __OPENCV_BM3D_IMAGE_DENOISING_HPP__
+#define __OPENCV_BM3D_IMAGE_DENOISING_HPP__
+
+/** @file
+ at date Jul 19, 2016
+ at author Bartek Pawlik
+*/
+
+#include <opencv2/core.hpp>
+
+namespace cv
+{
+    namespace xphoto
+    {
+        //! @addtogroup xphoto
+        //! @{
+
+        //! BM3D transform types
+        enum TransformTypes
+        {
+            /** Un-normalized Haar transform */
+            HAAR = 0
+        };
+
+        //! BM3D algorithm steps
+        enum Bm3dSteps
+        {
+            /** Execute all steps of the algorithm */
+            BM3D_STEPALL = 0,
+            /** Execute only first step of the algorithm */
+            BM3D_STEP1 = 1,
+            /** Execute only second step of the algorithm */
+            BM3D_STEP2 = 2
+        };
+
+        /** @brief Performs image denoising using the Block-Matching and 3D-filtering algorithm
+        <http://www.cs.tut.fi/~foi/GCF-BM3D/BM3D_TIP_2007.pdf> with several computational
+        optimizations. Noise expected to be a gaussian white noise.
+
+        @param src Input 8-bit or 16-bit 1-channel image.
+        @param dstStep1 Output image of the first step of BM3D with the same size and type as src.
+        @param dstStep2 Output image of the second step of BM3D with the same size and type as src.
+        @param h Parameter regulating filter strength. Big h value perfectly removes noise but also
+        removes image details, smaller h value preserves details but also preserves some noise.
+        @param templateWindowSize Size in pixels of the template patch that is used for block-matching.
+        Should be power of 2.
+        @param searchWindowSize Size in pixels of the window that is used to perform block-matching.
+        Affect performance linearly: greater searchWindowsSize - greater denoising time.
+        Must be larger than templateWindowSize.
+        @param blockMatchingStep1 Block matching threshold for the first step of BM3D (hard thresholding),
+        i.e. maximum distance for which two blocks are considered similar.
+        Value expressed in euclidean distance.
+        @param blockMatchingStep2 Block matching threshold for the second step of BM3D (Wiener filtering),
+        i.e. maximum distance for which two blocks are considered similar.
+        Value expressed in euclidean distance.
+        @param groupSize Maximum size of the 3D group for collaborative filtering.
+        @param slidingStep Sliding step to process every next reference block.
+        @param beta Kaiser window parameter that affects the sidelobe attenuation of the transform of the
+        window. Kaiser window is used in order to reduce border effects. To prevent usage of the window,
+        set beta to zero.
+        @param normType Norm used to calculate distance between blocks. L2 is slower than L1
+        but yields more accurate results.
+        @param step Step of BM3D to be executed. Possible variants are: step 1, step 2, both steps.
+        @param transformType Type of the orthogonal transform used in collaborative filtering step.
+        Currently only Haar transform is supported.
+
+        This function expected to be applied to grayscale images. Advanced usage of this function
+        can be manual denoising of colored image in different colorspaces.
+
+        @sa
+        fastNlMeansDenoising
+        */
+        CV_EXPORTS_W void bm3dDenoising(
+            InputArray src,
+            InputOutputArray dstStep1,
+            OutputArray dstStep2,
+            float h = 1,
+            int templateWindowSize = 4,
+            int searchWindowSize = 16,
+            int blockMatchingStep1 = 2500,
+            int blockMatchingStep2 = 400,
+            int groupSize = 8,
+            int slidingStep = 1,
+            float beta = 2.0f,
+            int normType = cv::NORM_L2,
+            int step = cv::xphoto::BM3D_STEPALL,
+            int transformType = cv::xphoto::HAAR);
+
+        /** @brief Performs image denoising using the Block-Matching and 3D-filtering algorithm
+        <http://www.cs.tut.fi/~foi/GCF-BM3D/BM3D_TIP_2007.pdf> with several computational
+        optimizations. Noise expected to be a gaussian white noise.
+
+        @param src Input 8-bit or 16-bit 1-channel image.
+        @param dst Output image with the same size and type as src.
+        @param h Parameter regulating filter strength. Big h value perfectly removes noise but also
+        removes image details, smaller h value preserves details but also preserves some noise.
+        @param templateWindowSize Size in pixels of the template patch that is used for block-matching.
+        Should be power of 2.
+        @param searchWindowSize Size in pixels of the window that is used to perform block-matching.
+        Affect performance linearly: greater searchWindowsSize - greater denoising time.
+        Must be larger than templateWindowSize.
+        @param blockMatchingStep1 Block matching threshold for the first step of BM3D (hard thresholding),
+        i.e. maximum distance for which two blocks are considered similar.
+        Value expressed in euclidean distance.
+        @param blockMatchingStep2 Block matching threshold for the second step of BM3D (Wiener filtering),
+        i.e. maximum distance for which two blocks are considered similar.
+        Value expressed in euclidean distance.
+        @param groupSize Maximum size of the 3D group for collaborative filtering.
+        @param slidingStep Sliding step to process every next reference block.
+        @param beta Kaiser window parameter that affects the sidelobe attenuation of the transform of the
+        window. Kaiser window is used in order to reduce border effects. To prevent usage of the window,
+        set beta to zero.
+        @param normType Norm used to calculate distance between blocks. L2 is slower than L1
+        but yields more accurate results.
+        @param step Step of BM3D to be executed. Allowed are only BM3D_STEP1 and BM3D_STEPALL.
+        BM3D_STEP2 is not allowed as it requires basic estimate to be present.
+        @param transformType Type of the orthogonal transform used in collaborative filtering step.
+        Currently only Haar transform is supported.
+
+        This function expected to be applied to grayscale images. Advanced usage of this function
+        can be manual denoising of colored image in different colorspaces.
+
+        @sa
+        fastNlMeansDenoising
+        */
+        CV_EXPORTS_W void bm3dDenoising(
+            InputArray src,
+            OutputArray dst,
+            float h = 1,
+            int templateWindowSize = 4,
+            int searchWindowSize = 16,
+            int blockMatchingStep1 = 2500,
+            int blockMatchingStep2 = 400,
+            int groupSize = 8,
+            int slidingStep = 1,
+            float beta = 2.0f,
+            int normType = cv::NORM_L2,
+            int step = cv::xphoto::BM3D_STEPALL,
+            int transformType = cv::xphoto::HAAR);
+        //! @}
+    }
+}
+
+#endif // __OPENCV_BM3D_IMAGE_DENOISING_HPP__
diff --git a/contrib/modules/xphoto/include/opencv2/xphoto/white_balance.hpp b/contrib/modules/xphoto/include/opencv2/xphoto/white_balance.hpp
index d4d68ea..1767f1f 100644
--- a/contrib/modules/xphoto/include/opencv2/xphoto/white_balance.hpp
+++ b/contrib/modules/xphoto/include/opencv2/xphoto/white_balance.hpp
@@ -58,67 +58,172 @@ namespace xphoto
 //! @addtogroup xphoto
 //! @{
 
-    //! various white balance algorithms
-    enum WhitebalanceTypes
-    {
-        /** perform smart histogram adjustments (ignoring 4% pixels with minimal and maximal
-        values) for each channel */
-        WHITE_BALANCE_SIMPLE = 0,
-        WHITE_BALANCE_GRAYWORLD = 1
-    };
-
-    /** @brief The function implements different algorithm of automatic white balance,
-
-    i.e. it tries to map image's white color to perceptual white (this can be violated due to
-    specific illumination or camera settings).
-
-    @param src
-    @param dst
-    @param algorithmType see xphoto::WhitebalanceTypes
-    @param inputMin minimum value in the input image
-    @param inputMax maximum value in the input image
-    @param outputMin minimum value in the output image
-    @param outputMax maximum value in the output image
-    @sa cvtColor, equalizeHist
-     */
-    CV_EXPORTS_W void balanceWhite(const Mat &src, Mat &dst, const int algorithmType,
-        const float inputMin  = 0.0f, const float inputMax  = 255.0f,
-        const float outputMin = 0.0f, const float outputMax = 255.0f);
-
-    /** @brief Implements a simple grayworld white balance algorithm.
-
-    The function autowbGrayworld scales the values of pixels based on a
-    gray-world assumption which states that the average of all channels
-    should result in a gray image.
-
-    This function adds a modification which thresholds pixels based on their
-    saturation value and only uses pixels below the provided threshold in
-    finding average pixel values.
-
-    Saturation is calculated using the following for a 3-channel RGB image per
-    pixel I and is in the range [0, 1]:
-
-    \f[ \texttt{Saturation} [I] = \frac{\textrm{max}(R,G,B) - \textrm{min}(R,G,B)
-    }{\textrm{max}(R,G,B)} \f]
-
-    A threshold of 1 means that all pixels are used to white-balance, while a
-    threshold of 0 means no pixels are used. Lower thresholds are useful in
-    white-balancing saturated images.
-
-    Currently only works on images of type @ref CV_8UC3.
-
-    @param src Input array.
-    @param dst Output array of the same size and type as src.
-    @param thresh Maximum saturation for a pixel to be included in the
-        gray-world assumption.
-
-    @sa balanceWhite
-     */
-    CV_EXPORTS_W void autowbGrayworld(InputArray src, OutputArray dst,
-        float thresh = 0.5f);
+/** @brief The base class for auto white balance algorithms.
+ */
+class CV_EXPORTS_W WhiteBalancer : public Algorithm
+{
+  public:
+    /** @brief Applies white balancing to the input image
 
+    @param src Input image
+    @param dst White balancing result
+    @sa cvtColor, equalizeHist
+    */
+    CV_WRAP virtual void balanceWhite(InputArray src, OutputArray dst) = 0;
+};
+
+/** @brief A simple white balance algorithm that works by independently stretching
+    each of the input image channels to the specified range. For increased robustness
+    it ignores the top and bottom \f$p\%\f$ of pixel values.
+ */
+class CV_EXPORTS_W SimpleWB : public WhiteBalancer
+{
+  public:
+    /** @brief Input image range minimum value
+    @see setInputMin */
+    CV_WRAP virtual float getInputMin() const = 0;
+    /** @copybrief getInputMin @see getInputMin */
+    CV_WRAP virtual void setInputMin(float val) = 0;
+
+    /** @brief Input image range maximum value
+    @see setInputMax */
+    CV_WRAP virtual float getInputMax() const = 0;
+    /** @copybrief getInputMax @see getInputMax */
+    CV_WRAP virtual void setInputMax(float val) = 0;
+
+    /** @brief Output image range minimum value
+    @see setOutputMin */
+    CV_WRAP virtual float getOutputMin() const = 0;
+    /** @copybrief getOutputMin @see getOutputMin */
+    CV_WRAP virtual void setOutputMin(float val) = 0;
+
+    /** @brief Output image range maximum value
+    @see setOutputMax */
+    CV_WRAP virtual float getOutputMax() const = 0;
+    /** @copybrief getOutputMax @see getOutputMax */
+    CV_WRAP virtual void setOutputMax(float val) = 0;
+
+    /** @brief Percent of top/bottom values to ignore
+    @see setP */
+    CV_WRAP virtual float getP() const = 0;
+    /** @copybrief getP @see getP */
+    CV_WRAP virtual void setP(float val) = 0;
+};
+
+/** @brief Creates an instance of SimpleWB
+ */
+CV_EXPORTS_W Ptr<SimpleWB> createSimpleWB();
+
+/** @brief Gray-world white balance algorithm
+
+This algorithm scales the values of pixels based on a
+gray-world assumption which states that the average of all channels
+should result in a gray image.
+
+It adds a modification which thresholds pixels based on their
+saturation value and only uses pixels below the provided threshold in
+finding average pixel values.
+
+Saturation is calculated using the following for a 3-channel RGB image per
+pixel I and is in the range [0, 1]:
+
+\f[ \texttt{Saturation} [I] = \frac{\textrm{max}(R,G,B) - \textrm{min}(R,G,B)
+}{\textrm{max}(R,G,B)} \f]
+
+A threshold of 1 means that all pixels are used to white-balance, while a
+threshold of 0 means no pixels are used. Lower thresholds are useful in
+white-balancing saturated images.
+
+Currently supports images of type @ref CV_8UC3 and @ref CV_16UC3.
+ */
+class CV_EXPORTS_W GrayworldWB : public WhiteBalancer
+{
+  public:
+    /** @brief Maximum saturation for a pixel to be included in the
+        gray-world assumption
+    @see setSaturationThreshold */
+    CV_WRAP virtual float getSaturationThreshold() const = 0;
+    /** @copybrief getSaturationThreshold @see getSaturationThreshold */
+    CV_WRAP virtual void setSaturationThreshold(float val) = 0;
+};
+
+/** @brief Creates an instance of GrayworldWB
+ */
+CV_EXPORTS_W Ptr<GrayworldWB> createGrayworldWB();
+
+/** @brief More sophisticated learning-based automatic white balance algorithm.
+
+As @ref GrayworldWB, this algorithm works by applying different gains to the input
+image channels, but their computation is a bit more involved compared to the
+simple gray-world assumption. More details about the algorithm can be found in
+ at cite Cheng2015 .
+
+To mask out saturated pixels this function uses only pixels that satisfy the
+following condition:
+
+\f[ \frac{\textrm{max}(R,G,B)}{\texttt{range_max_val}} < \texttt{saturation_thresh} \f]
+
+Currently supports images of type @ref CV_8UC3 and @ref CV_16UC3.
+ */
+class CV_EXPORTS_W LearningBasedWB : public WhiteBalancer
+{
+  public:
+    /** @brief Implements the feature extraction part of the algorithm.
+
+    In accordance with @cite Cheng2015 , computes the following features for the input image:
+    1. Chromaticity of an average (R,G,B) tuple
+    2. Chromaticity of the brightest (R,G,B) tuple (while ignoring saturated pixels)
+    3. Chromaticity of the dominant (R,G,B) tuple (the one that has the highest value in the RGB histogram)
+    4. Mode of the chromaticity palette, that is constructed by taking 300 most common colors according to
+       the RGB histogram and projecting them on the chromaticity plane. Mode is the most high-density point
+       of the palette, which is computed by a straightforward fixed-bandwidth kernel density estimator with
+       a Epanechnikov kernel function.
+
+    @param src Input three-channel image (BGR color space is assumed).
+    @param dst An array of four (r,g) chromaticity tuples corresponding to the features listed above.
+    */
+    CV_WRAP virtual void extractSimpleFeatures(InputArray src, OutputArray dst) = 0;
+
+    /** @brief Maximum possible value of the input image (e.g. 255 for 8 bit images,
+               4095 for 12 bit images)
+    @see setRangeMaxVal */
+    CV_WRAP virtual int getRangeMaxVal() const = 0;
+    /** @copybrief getRangeMaxVal @see getRangeMaxVal */
+    CV_WRAP virtual void setRangeMaxVal(int val) = 0;
+
+    /** @brief Threshold that is used to determine saturated pixels, i.e. pixels where at least one of the
+        channels exceeds \f$\texttt{saturation_threshold}\times\texttt{range_max_val}\f$ are ignored.
+    @see setSaturationThreshold */
+    CV_WRAP virtual float getSaturationThreshold() const = 0;
+    /** @copybrief getSaturationThreshold @see getSaturationThreshold */
+    CV_WRAP virtual void setSaturationThreshold(float val) = 0;
+
+    /** @brief Defines the size of one dimension of a three-dimensional RGB histogram that is used internally
+        by the algorithm. It often makes sense to increase the number of bins for images with higher bit depth
+        (e.g. 256 bins for a 12 bit image).
+    @see setHistBinNum */
+    CV_WRAP virtual int getHistBinNum() const = 0;
+    /** @copybrief getHistBinNum @see getHistBinNum */
+    CV_WRAP virtual void setHistBinNum(int val) = 0;
+};
+
+/** @brief Creates an instance of LearningBasedWB
+
+ at param path_to_model Path to a .yml file with the model. If not specified, the default model is used
+ */
+CV_EXPORTS_W Ptr<LearningBasedWB> createLearningBasedWB(const String& path_to_model = String());
+
+/** @brief Implements an efficient fixed-point approximation for applying channel gains, which is
+    the last step of multiple white balance algorithms.
+
+ at param src Input three-channel image in the BGR color space (either CV_8UC3 or CV_16UC3)
+ at param dst Output image of the same size and type as src.
+ at param gainB gain for the B channel
+ at param gainG gain for the G channel
+ at param gainR gain for the R channel
+*/
+CV_EXPORTS_W void applyChannelGains(InputArray src, OutputArray dst, float gainB, float gainG, float gainR);
 //! @}
-
 }
 }
 
diff --git a/contrib/modules/xphoto/perf/perf_grayworld.cpp b/contrib/modules/xphoto/perf/perf_grayworld.cpp
index 80c034c..32eea8f 100644
--- a/contrib/modules/xphoto/perf/perf_grayworld.cpp
+++ b/contrib/modules/xphoto/perf/perf_grayworld.cpp
@@ -21,8 +21,10 @@ PERF_TEST_P( Size_WBThresh, autowbGrayworld,
     Mat dst(size, CV_8UC3);
 
     declare.in(src, WARMUP_RNG).out(dst);
+    Ptr<xphoto::GrayworldWB> wb = xphoto::createGrayworldWB();
+    wb->setSaturationThreshold(wb_thresh);
 
-    TEST_CYCLE() xphoto::autowbGrayworld(src, dst, wb_thresh);
+    TEST_CYCLE() wb->balanceWhite(src, dst);
 
     SANITY_CHECK(dst);
 }
diff --git a/contrib/modules/xphoto/perf/perf_learning_based_color_balance.cpp b/contrib/modules/xphoto/perf/perf_learning_based_color_balance.cpp
new file mode 100644
index 0000000..6c66d4e
--- /dev/null
+++ b/contrib/modules/xphoto/perf/perf_learning_based_color_balance.cpp
@@ -0,0 +1,76 @@
+/*
+*  By downloading, copying, installing or using the software you agree to this license.
+*  If you do not agree to this license, do not download, install,
+*  copy or use the software.
+*
+*
+*  License Agreement
+*  For Open Source Computer Vision Library
+*  (3 - clause BSD License)
+*
+*  Redistribution and use in source and binary forms, with or without modification,
+*  are permitted provided that the following conditions are met :
+*
+*  * Redistributions of source code must retain the above copyright notice,
+*  this list of conditions and the following disclaimer.
+*
+*  * Redistributions in binary form must reproduce the above copyright notice,
+*  this list of conditions and the following disclaimer in the documentation
+*  and / or other materials provided with the distribution.
+*
+*  * Neither the names of the copyright holders nor the names of the contributors
+*  may be used to endorse or promote products derived from this software
+*  without specific prior written permission.
+*
+*  This software is provided by the copyright holders and contributors "as is" and
+*  any express or implied warranties, including, but not limited to, the implied
+*  warranties of merchantability and fitness for a particular purpose are disclaimed.
+*  In no event shall copyright holders or contributors be liable for any direct,
+*  indirect, incidental, special, exemplary, or consequential damages
+*  (including, but not limited to, procurement of substitute goods or services;
+*  loss of use, data, or profits; or business interruption) however caused
+*  and on any theory of liability, whether in contract, strict liability,
+*  or tort(including negligence or otherwise) arising in any way out of
+*  the use of this software, even if advised of the possibility of such damage.
+*/
+
+#include "perf_precomp.hpp"
+#include "opencv2/imgproc.hpp"
+
+using std::tr1::tuple;
+using std::tr1::get;
+using namespace std;
+using namespace cv;
+using namespace perf;
+using namespace testing;
+
+typedef tuple<Size, MatType> learningBasedWBParams;
+typedef TestBaseWithParam<learningBasedWBParams> learningBasedWBPerfTest;
+
+PERF_TEST_P(learningBasedWBPerfTest, perf, Combine(SZ_ALL_HD, Values(CV_8UC3, CV_16UC3)))
+{
+    Size size = get<0>(GetParam());
+    MatType t = get<1>(GetParam());
+    Mat src(size, t);
+    Mat dst(size, t);
+
+    int range_max_val = 255, hist_bin_num = 64;
+    if (t == CV_16UC3)
+    {
+        range_max_val = 65535;
+        hist_bin_num = 256;
+    }
+
+    Mat src_dscl(Size(size.width / 16, size.height / 16), t);
+    RNG rng(1234);
+    rng.fill(src_dscl, RNG::UNIFORM, 0, range_max_val);
+    resize(src_dscl, src, src.size());
+    Ptr<xphoto::LearningBasedWB> wb = xphoto::createLearningBasedWB();
+    wb->setRangeMaxVal(range_max_val);
+    wb->setSaturationThreshold(0.98f);
+    wb->setHistBinNum(hist_bin_num);
+
+    TEST_CYCLE() wb->balanceWhite(src, dst);
+
+    SANITY_CHECK_NOTHING();
+}
diff --git a/contrib/modules/xphoto/samples/bm3d_image_denoising.cpp b/contrib/modules/xphoto/samples/bm3d_image_denoising.cpp
new file mode 100644
index 0000000..cc872d6
--- /dev/null
+++ b/contrib/modules/xphoto/samples/bm3d_image_denoising.cpp
@@ -0,0 +1,73 @@
+#include "opencv2/xphoto.hpp"
+#include "opencv2/highgui.hpp"
+
+const char* keys =
+{
+    "{i || input image name}"
+    "{o || output image name}"
+    "{sigma || expected noise standard deviation}"
+    "{tw |4| template window size}"
+    "{sw |16| search window size}"
+};
+
+int main(int argc, const char** argv)
+{
+    bool printHelp = (argc == 1);
+    printHelp = printHelp || (argc == 2 && std::string(argv[1]) == "--help");
+    printHelp = printHelp || (argc == 2 && std::string(argv[1]) == "-h");
+
+    if (printHelp)
+    {
+        printf("\nThis sample demonstrates BM3D image denoising\n"
+            "Call:\n"
+            "    bm3d_image_denoising -i=<string> -sigma=<double> -tw=<int> -sw=<int> [-o=<string>]\n\n");
+        return 0;
+    }
+
+    cv::CommandLineParser parser(argc, argv, keys);
+    if (!parser.check())
+    {
+        parser.printErrors();
+        return -1;
+    }
+
+    std::string inFilename = parser.get<std::string>("i");
+    std::string outFilename = parser.get<std::string>("o");
+
+    cv::Mat src = cv::imread(inFilename, cv::IMREAD_GRAYSCALE);
+    if (src.empty())
+    {
+        printf("Cannot read image file: %s\n", inFilename.c_str());
+        return -1;
+    }
+
+    float sigma = parser.get<float>("sigma");
+    if (sigma == 0.0)
+        sigma = 15.0;
+
+    int templateWindowSize = parser.get<int>("tw");
+    if (templateWindowSize == 0)
+        templateWindowSize = 4;
+
+    int searchWindowSize = parser.get<int>("sw");
+    if (searchWindowSize == 0)
+        searchWindowSize = 16;
+
+    cv::Mat res(src.size(), src.type());
+    cv::xphoto::bm3dDenoising(src, res, sigma, templateWindowSize, searchWindowSize);
+
+    if (outFilename.empty())
+    {
+        cv::namedWindow("input image", cv::WINDOW_NORMAL);
+        cv::imshow("input image", src);
+        cv::namedWindow("denoising result", cv::WINDOW_NORMAL);
+        cv::imshow("denoising result", res);
+        cv::waitKey(0);
+    }
+    else
+    {
+        cv::imwrite(outFilename, res);
+    }
+
+    return 0;
+}
diff --git a/contrib/modules/xphoto/samples/color_balance.cpp b/contrib/modules/xphoto/samples/color_balance.cpp
new file mode 100644
index 0000000..b33fe9d
--- /dev/null
+++ b/contrib/modules/xphoto/samples/color_balance.cpp
@@ -0,0 +1,68 @@
+#include "opencv2/xphoto.hpp"
+#include "opencv2/highgui.hpp"
+
+using namespace cv;
+using namespace std;
+
+const char *keys = { "{help h usage ? |         | print this message}"
+                     "{i              |         | input image name  }"
+                     "{o              |         | output image name }"
+                     "{a              |grayworld| color balance algorithm (simple, grayworld or learning_based)}"
+                     "{m              |         | path to the model for the learning-based algorithm (optional) }" };
+
+int main(int argc, const char **argv)
+{
+    CommandLineParser parser(argc, argv, keys);
+    parser.about("OpenCV color balance demonstration sample");
+    if (parser.has("help") || argc < 2)
+    {
+        parser.printMessage();
+        return 0;
+    }
+
+    string inFilename = parser.get<string>("i");
+    string outFilename = parser.get<string>("o");
+    string algorithm = parser.get<string>("a");
+    string modelFilename = parser.get<string>("m");
+
+    if (!parser.check())
+    {
+        parser.printErrors();
+        return -1;
+    }
+
+    Mat src = imread(inFilename, 1);
+    if (src.empty())
+    {
+        printf("Cannot read image file: %s\n", inFilename.c_str());
+        return -1;
+    }
+
+    Mat res;
+    Ptr<xphoto::WhiteBalancer> wb;
+    if (algorithm == "simple")
+        wb = xphoto::createSimpleWB();
+    else if (algorithm == "grayworld")
+        wb = xphoto::createGrayworldWB();
+    else if (algorithm == "learning_based")
+        wb = xphoto::createLearningBasedWB(modelFilename);
+    else
+    {
+        printf("Unsupported algorithm: %s\n", algorithm.c_str());
+        return -1;
+    }
+
+    wb->balanceWhite(src, res);
+
+    if (outFilename == "")
+    {
+        namedWindow("after white balance", 1);
+        imshow("after white balance", res);
+
+        waitKey(0);
+    }
+    else
+        imwrite(outFilename, res);
+
+    return 0;
+}
diff --git a/contrib/modules/xphoto/samples/color_balance_benchmark.py b/contrib/modules/xphoto/samples/color_balance_benchmark.py
new file mode 100644
index 0000000..405b8f9
--- /dev/null
+++ b/contrib/modules/xphoto/samples/color_balance_benchmark.py
@@ -0,0 +1,268 @@
+#!/usr/bin/env python
+from __future__ import print_function
+import os, sys, argparse, json
+import numpy as np
+import scipy.io
+import cv2
+import timeit
+from learn_color_balance import load_ground_truth
+
+
+def load_json(path):
+    f = open(path, "r")
+    data = json.load(f)
+    return data
+
+
+def save_json(obj, path):
+    tmp_file = path + ".bak"
+    f = open(tmp_file, "w")
+    json.dump(obj, f, indent=2)
+    f.flush()
+    os.fsync(f.fileno())
+    f.close()
+    try:
+        os.rename(tmp_file, path)
+    except:
+        os.remove(path)
+        os.rename(tmp_file, path)
+
+
+def parse_sequence(input_str):
+    if len(input_str) == 0:
+        return []
+    else:
+        return [o.strip() for o in input_str.split(",") if o]
+
+
+def stretch_to_8bit(arr, clip_percentile = 2.5):
+    arr = np.clip(arr * (255.0 / np.percentile(arr, 100 - clip_percentile)), 0, 255)
+    return arr.astype(np.uint8)
+
+
+def evaluate(im, algo, gt_illuminant, i, range_thresh, bin_num, dst_folder, model_folder):
+    new_im = None
+    start_time = timeit.default_timer()
+    if algo=="grayworld":
+        inst = cv2.xphoto.createGrayworldWB()
+        inst.setSaturationThreshold(0.95)
+        new_im = inst.balanceWhite(im)
+    elif algo=="nothing":
+        new_im = im
+    elif algo.split(":")[0]=="learning_based":
+        model_path = ""
+        if len(algo.split(":"))>1:
+            model_path = os.path.join(model_folder, algo.split(":")[1])
+        inst = cv2.xphoto.createLearningBasedWB(model_path)
+        inst.setRangeMaxVal(range_thresh)
+        inst.setSaturationThreshold(0.98)
+        inst.setHistBinNum(bin_num)
+        new_im = inst.balanceWhite(im)
+    elif algo=="GT":
+        gains = gt_illuminant / min(gt_illuminant)
+        g1 = float(1.0 / gains[2])
+        g2 = float(1.0 / gains[1])
+        g3 = float(1.0 / gains[0])
+        new_im = cv2.xphoto.applyChannelGains(im, g1, g2, g3)
+    time = 1000*(timeit.default_timer() - start_time) #time in ms
+
+    if len(dst_folder)>0:
+        if not os.path.exists(dst_folder):
+            os.makedirs(dst_folder)
+        im_name = ("%04d_" % i) + algo.replace(":","_") + ".jpg"
+        cv2.imwrite(os.path.join(dst_folder, im_name), stretch_to_8bit(new_im))
+
+    #recover the illuminant from the color balancing result, assuming the standard model:
+    estimated_illuminant = [0, 0, 0]
+    eps = 0.01
+    estimated_illuminant[2] = np.percentile((im[:,:,0] + eps) / (new_im[:,:,0] + eps), 50)
+    estimated_illuminant[1] = np.percentile((im[:,:,1] + eps) / (new_im[:,:,1] + eps), 50)
+    estimated_illuminant[0] = np.percentile((im[:,:,2] + eps) / (new_im[:,:,2] + eps), 50)
+
+    res = np.arccos(np.dot(gt_illuminant,estimated_illuminant)/
+                   (np.linalg.norm(gt_illuminant) * np.linalg.norm(estimated_illuminant)))
+    return (time, (res / np.pi) * 180)
+
+
+def build_html_table(out, state, stat_list, img_range):
+    stat_dict = {'mean': ('Mean error', lambda arr: np.mean(arr)),
+                 'median': ('Median error',lambda arr: np.percentile(arr, 50)),
+                 'p05': ('5<sup>th</sup> percentile',lambda arr: np.percentile(arr, 5)),
+                 'p20': ('20<sup>th</sup> percentile',lambda arr: np.percentile(arr, 20)),
+                 'p80': ('80<sup>th</sup> percentile',lambda arr: np.percentile(arr, 80)),
+                 'p95': ('95<sup>th</sup> percentile',lambda arr: np.percentile(arr, 95))
+                }
+    html_out = ['<style type="text/css">\n',
+                '  html, body {font-family: Lucida Console, Courier New, Courier;font-size: 16px;color:#3e4758;}\n',
+                '  .tbl{background:none repeat scroll 0 0 #FFFFFF;border-collapse:collapse;font-family:"Lucida Sans Unicode","Lucida Grande",Sans-Serif;font-size:14px;margin:20px;text-align:left;width:480px;margin-left: auto;margin-right: auto;white-space:nowrap;}\n',
+                '  .tbl span{display:block;white-space:nowrap;}\n',
+                '  .tbl thead tr:last-child th {padding-bottom:5px;}\n',
+                '  .tbl tbody tr:first-child td {border-top:3px solid #6678B1;}\n',
+                '  .tbl th{border:none;color:#003399;font-size:16px;font-weight:normal;white-space:nowrap;padding:3px 10px;}\n',
+                '  .tbl td{border:none;border-bottom:1px solid #CCCCCC;color:#666699;padding:6px 8px;white-space:nowrap;}\n',
+                '  .tbl tbody tr:hover td{color:#000099;}\n',
+                '  .tbl caption{font:italic 16px "Trebuchet MS",Verdana,Arial,Helvetica,sans-serif;padding:0 0 5px;text-align:right;white-space:normal;}\n',
+                '  .firstingroup {border-top:2px solid #6678B1;}\n',
+                '</style>\n\n']
+
+    html_out += ['<table class="tbl">\n',
+                 '  <thead>\n',
+                 '    <tr>\n',
+                 '      <th align="center" valign="top"> Algorithm Name </th>\n',
+                 '      <th align="center" valign="top"> Average Time </th>\n']
+    for stat in stat_list:
+        if stat not in stat_dict.keys():
+            print("Error: unsupported statistic " + stat)
+            sys.exit(1)
+        html_out += ['      <th align="center" valign="top"> ' +
+                             stat_dict[stat][0] +
+                          ' </th>\n']
+    html_out += ['    </tr>\n',
+                 '  </thead>\n',
+                 '  <tbody>\n']
+
+    for algorithm in state.keys():
+        arr = [state[algorithm][file]["angular_error"] for file in state[algorithm].keys() if file>=img_range[0] and file<=img_range[1]]
+        average_time = "%.2f ms" % np.mean([state[algorithm][file]["time"] for file in state[algorithm].keys()
+                                                                           if file>=img_range[0] and file<=img_range[1]])
+        html_out += ['    <tr>\n',
+                     '      <td>' + algorithm + '</td>\n',
+                     '      <td>' + average_time + '</td>\n']
+        for stat in stat_list:
+            html_out += ['      <td> ' +
+                                 "%.2f&deg" % stat_dict[stat][1](arr) +
+                             ' </td>\n']
+        html_out += ['    </tr>\n']
+    html_out += ['  </tbody>\n',
+                 '</table>\n']
+    f = open(out, 'w')
+    f.writelines(html_out)
+    f.close()
+
+
+if __name__ == '__main__':
+    parser = argparse.ArgumentParser(
+        description=("A benchmarking script for color balance algorithms"),
+        formatter_class=argparse.RawDescriptionHelpFormatter)
+    parser.add_argument(
+        "-a",
+        "--algorithms",
+        metavar="ALGORITHMS",
+        default="",
+        help=("Comma-separated list of color balance algorithms to evaluate. "
+              "Currently available: GT,learning_based,grayworld,nothing. "
+              "Use a colon to set a specific model for the learning-based "
+              "algorithm, e.g. learning_based:model1.yml,learning_based:model2.yml"))
+    parser.add_argument(
+        "-i",
+        "--input_folder",
+        metavar="INPUT_FOLDER",
+        default="",
+        help=("Folder containing input images to evaluate on. Assumes minimally "
+              "processed png images like in the Gehler-Shi (http://www.cs.sfu.ca/~colour/data/shi_gehler/) "
+              "or NUS 8-camera (http://www.comp.nus.edu.sg/~whitebal/illuminant/illuminant.html) datasets"))
+    parser.add_argument(
+        "-g",
+        "--ground_truth",
+        metavar="GROUND_TRUTH",
+        default="real_illum_568..mat",
+        help=("Path to the mat file containing ground truth illuminations. Currently "
+              "supports formats supplied by the Gehler-Shi and NUS 8-camera datasets."))
+    parser.add_argument(
+        "-o",
+        "--out",
+        metavar="OUT",
+        default="./white_balance_eval_result.html",
+        help="Path to the output html table")
+    parser.add_argument(
+        "-s",
+        "--state",
+        metavar="STATE_JSON",
+        default="./WB_evaluation_state.json",
+        help=("Path to a json file that stores the current evaluation state"))
+    parser.add_argument(
+        "-t",
+        "--stats",
+        metavar="STATS",
+        default="mean,median,p05,p20,p80,p95",
+        help=("Comma-separated list of error statistics to compute and list "
+              "in the output table. All the available ones are used by default"))
+    parser.add_argument(
+        "-b",
+        "--input_bit_depth",
+        metavar="INPUT_BIT_DEPTH",
+        default="",
+        help=("Assumed bit depth for input images. Should be specified in order to "
+              "use full bit depth for evaluation (for instance, -b 12 for 12 bit images). "
+              "Otherwise, input images are converted to 8 bit prior to the evaluation."))
+    parser.add_argument(
+        "-d",
+        "--dst_folder",
+        metavar="DST_FOLDER",
+        default="",
+        help=("If specified, this folder will be used to store the color correction results"))
+    parser.add_argument(
+        "-r",
+        "--range",
+        metavar="RANGE",
+        default="0,0",
+        help=("Comma-separated range of images from the dataset to evaluate on (for instance: 0,568). "
+              "All available images are used by default."))
+    parser.add_argument(
+        "-m",
+        "--model_folder",
+        metavar="MODEL_FOLDER",
+        default="",
+        help=("Path to the folder containing models for the learning-based color balance algorithm (optional)"))
+    args, other_args = parser.parse_known_args()
+
+    if not os.path.exists(args.input_folder):
+        print("Error: " + args.input_folder + (" does not exist. Please, correctly "
+                                                 "specify the -i parameter"))
+        sys.exit(1)
+
+    if not os.path.exists(args.ground_truth):
+        print("Error: " + args.ground_truth + (" does not exist. Please, correctly "
+                                                 "specify the -g parameter"))
+        sys.exit(1)
+
+    state = {}
+    if os.path.isfile(args.state):
+        state = load_json(args.state)
+
+    algorithm_list = parse_sequence(args.algorithms)
+    img_range = map(int, parse_sequence(args.range))
+    if len(img_range)!=2:
+        print("Error: Please specify the -r parameter in form <first_image_index>,<last_image_index>")
+        sys.exit(1)
+
+    img_files = sorted(os.listdir(args.input_folder))
+    (gt_illuminants,black_levels) = load_ground_truth(args.ground_truth)
+
+    for algorithm in algorithm_list:
+        i = 0
+        if algorithm not in state.keys():
+            state[algorithm] = {}
+        sz = len(img_files)
+        for file in img_files:
+            if file not in state[algorithm].keys() and\
+             ((i>=img_range[0] and i<img_range[1]) or img_range[0]==img_range[1]==0):
+                cur_path = os.path.join(args.input_folder, file)
+                im = cv2.imread(cur_path, -1).astype(np.float32)
+                im -= black_levels[i]
+                range_thresh = 255
+                if len(args.input_bit_depth)>0:
+                    range_thresh = 2**int(args.input_bit_depth) - 1
+                    im = np.clip(im, 0, range_thresh).astype(np.uint16)
+                else:
+                    im = stretch_to_8bit(im)
+
+                (time,angular_err) = evaluate(im, algorithm, gt_illuminants[i], i, range_thresh,
+                                              256 if range_thresh > 255 else 64, args.dst_folder, args.model_folder)
+                state[algorithm][file] = {"angular_error": angular_err, "time": time}
+                sys.stdout.write("Algorithm: %-20s Done: [%3d/%3d]\r" % (algorithm, i, sz)),
+                sys.stdout.flush()
+                save_json(state, args.state)
+            i+=1
+    save_json(state, args.state)
+    build_html_table(args.out, state, parse_sequence(args.stats), [img_files[img_range[0]], img_files[img_range[1]-1]])
diff --git a/contrib/modules/xphoto/samples/grayworld_color_balance.cpp b/contrib/modules/xphoto/samples/grayworld_color_balance.cpp
deleted file mode 100644
index caaa0a4..0000000
--- a/contrib/modules/xphoto/samples/grayworld_color_balance.cpp
+++ /dev/null
@@ -1,62 +0,0 @@
-#include "opencv2/xphoto.hpp"
-
-#include "opencv2/imgproc.hpp"
-#include "opencv2/highgui.hpp"
-
-#include "opencv2/core/utility.hpp"
-
-using namespace cv;
-using namespace std;
-
-const char* keys =
-{
-    "{i || input image name}"
-    "{o || output image name}"
-};
-
-int main( int argc, const char** argv )
-{
-    bool printHelp = ( argc == 1 );
-    printHelp = printHelp || ( argc == 2 && string(argv[1]) == "--help" );
-    printHelp = printHelp || ( argc == 2 && string(argv[1]) == "-h" );
-
-    if ( printHelp )
-    {
-        printf("\nThis sample demonstrates the grayworld balance algorithm\n"
-            "Call:\n"
-            "    simple_color_blance -i=in_image_name [-o=out_image_name]\n\n");
-        return 0;
-    }
-
-    CommandLineParser parser(argc, argv, keys);
-    if ( !parser.check() )
-    {
-        parser.printErrors();
-        return -1;
-    }
-
-    string inFilename = parser.get<string>("i");
-    string outFilename = parser.get<string>("o");
-
-    Mat src = imread(inFilename, 1);
-    if ( src.empty() )
-    {
-        printf("Cannot read image file: %s\n", inFilename.c_str());
-        return -1;
-    }
-
-    Mat res(src.size(), src.type());
-    xphoto::autowbGrayworld(src, res);
-
-    if ( outFilename == "" )
-    {
-        namedWindow("after white balance", 1);
-        imshow("after white balance", res);
-
-        waitKey(0);
-    }
-    else
-        imwrite(outFilename, res);
-
-    return 0;
-}
diff --git a/contrib/modules/xphoto/samples/learn_color_balance.py b/contrib/modules/xphoto/samples/learn_color_balance.py
new file mode 100644
index 0000000..c3b7fbc
--- /dev/null
+++ b/contrib/modules/xphoto/samples/learn_color_balance.py
@@ -0,0 +1,290 @@
+#!/usr/bin/env python
+from __future__ import print_function
+import os, sys, argparse
+import numpy as np
+import scipy.io
+from sklearn.tree import DecisionTreeRegressor
+import cv2
+import random
+
+
+def parse_sequence(input_str):
+    if len(input_str) == 0:
+        return []
+    else:
+        return [o.strip() for o in input_str.split(",") if o]
+
+
+def convert_to_8bit(arr, clip_percentile = 2.5):
+    arr = np.clip(arr * (255.0 / np.percentile(arr, 100 - clip_percentile)), 0, 255)
+    return arr.astype(np.uint8)
+
+
+def learn_regression_tree_ensemble(img_features, gt_illuminants, num_trees, max_tree_depth):
+    eps = 0.001
+    inst = [[img_features[i], gt_illuminants[i][0] / (sum(gt_illuminants[i]) + eps),
+                              gt_illuminants[i][1] / (sum(gt_illuminants[i]) + eps)] for i in range(len(img_features))]
+
+    inst.sort(key = lambda obj: obj[1]) #sort by r chromaticity
+    stride = int(np.ceil(len(inst) / float(num_trees+1)))
+    sz = 2*stride
+    dst_model = []
+    for tree_idx in range(num_trees):
+        #local group in the training data is additionally weighted by num_trees
+        local_group_range = range(tree_idx*stride, min(tree_idx*stride+sz, len(inst)))
+        X = num_trees * [inst[i][0] for i in local_group_range]
+        y_r = num_trees * [inst[i][1] for i in local_group_range]
+        y_g = num_trees * [inst[i][2] for i in local_group_range]
+
+        #add the rest of the training data:
+        X = X + [inst[i][0] for i in range(len(inst)) if i not in local_group_range]
+        y_r = y_r + [inst[i][1] for i in range(len(inst)) if i not in local_group_range]
+        y_g = y_g + [inst[i][2] for i in range(len(inst)) if i not in local_group_range]
+
+        local_model = []
+        for feature_idx in range(len(X[0])):
+            tree_r = DecisionTreeRegressor(max_depth = max_tree_depth, random_state = 1234)
+            tree_r.fit([el[feature_idx][0] for el in X], y_r)
+            tree_g = DecisionTreeRegressor(max_depth = max_tree_depth, random_state = 1234)
+            tree_g.fit([el[feature_idx][0] for el in X], y_g)
+            local_model.append([tree_r, tree_g])
+        dst_model.append(local_model)
+    return dst_model
+
+
+def get_tree_node_lists(tree, tree_depth):
+    dst_feature_idx = (2**tree_depth-1) * [0]
+    dst_thresh_vals = (2**tree_depth-1) * [.5]
+    dst_leaf_vals   = (2**tree_depth) * [-1]
+    leaf_idx_offset = (2**tree_depth-1)
+    left      = tree.tree_.children_left
+    right     = tree.tree_.children_right
+    threshold = tree.tree_.threshold
+    value = tree.tree_.value
+    feature = tree.tree_.feature
+
+    def recurse(left, right, threshold, feature, node, dst_idx, cur_depth):
+        if (threshold[node] != -2):
+            dst_feature_idx[dst_idx] = feature[node]
+            dst_thresh_vals[dst_idx] = threshold[node]
+            if left[node] != -1:
+                recurse (left, right, threshold, feature, left[node], 2*dst_idx+1, cur_depth + 1)
+            if right[node] != -1:
+                recurse (left, right, threshold, feature, right[node], 2*dst_idx+2, cur_depth + 1)
+        else:
+            range_start = 2**(tree_depth - cur_depth) * dst_idx + (2**(tree_depth - cur_depth) - 1) - leaf_idx_offset
+            range_end = 2**(tree_depth - cur_depth) * dst_idx + (2**(tree_depth - cur_depth+1) - 2) - leaf_idx_offset + 1
+            dst_leaf_vals[range_start:range_end] = (range_end - range_start) * [value[node][0][0]]
+
+    recurse(left, right, threshold, feature, 0, 0, 0)
+    return (dst_feature_idx, dst_thresh_vals, dst_leaf_vals)
+
+
+def generate_code(model, input_params, use_YML, out_file):
+    feature_idx = []
+    thresh_vals = []
+    leaf_vals = []
+    depth = int(input_params["--max_tree_depth"])
+    for local_model in model:
+        for feature in local_model:
+            (local_feature_idx, local_thresh_vals, local_leaf_vals) = get_tree_node_lists(feature[0], depth)
+            feature_idx += local_feature_idx
+            thresh_vals += local_thresh_vals
+            leaf_vals += local_leaf_vals
+            (local_feature_idx, local_thresh_vals, local_leaf_vals) = get_tree_node_lists(feature[1], depth)
+            feature_idx += local_feature_idx
+            thresh_vals += local_thresh_vals
+            leaf_vals += local_leaf_vals
+    if use_YML:
+        fs = cv2.FileStorage(out_file, 1)
+        fs.write("num_trees", len(model))
+        fs.write("num_tree_nodes", 2**depth)
+        fs.write("feature_idx", np.array(feature_idx).astype(np.uint8))
+        fs.write("thresh_vals", np.array(thresh_vals).astype(np.float32))
+        fs.write("leaf_vals", np.array(leaf_vals).astype(np.float32))
+        fs.release()
+    else:
+        res = "/* This file was automatically generated by learn_color_balance.py script\n" +\
+              " * using the following parameters:\n"
+        for key in input_params:
+            res += " " + key + " " + input_params[key]
+        res += "\n */\n"
+        res += "const int num_features = 4;\n"
+        res += "const int _num_trees = " + str(len(model)) + ";\n"
+        res += "const int _num_tree_nodes = " + str(2**depth) + ";\n"
+
+        res += "unsigned char _feature_idx[_num_trees*num_features*2*(_num_tree_nodes-1)] = {" + str(feature_idx[0])
+        for i in range(1,len(feature_idx)):
+            res += "," + str(feature_idx[i])
+        res += "};\n"
+
+        res += "float _thresh_vals[_num_trees*num_features*2*(_num_tree_nodes-1)] = {" + ("%.3ff" % thresh_vals[0])[1:]
+        for i in range(1,len(thresh_vals)):
+            res += "," + ("%.3ff" % thresh_vals[i])[1:]
+        res += "};\n"
+
+        res += "float _leaf_vals[_num_trees*num_features*2*_num_tree_nodes] = {" + ("%.3ff" % leaf_vals[0])[1:]
+        for i in range(1,len(leaf_vals)):
+            res += "," + ("%.3ff" % leaf_vals[i])[1:]
+        res += "};\n"
+        f = open(out_file,"w")
+        f.write(res)
+        f.close()
+
+
+def load_ground_truth(gt_path):
+    gt = scipy.io.loadmat(gt_path)
+    base_gt_illuminants = []
+    black_levels = []
+    if "groundtruth_illuminants" in gt.keys() and "darkness_level" in gt.keys():
+        #NUS 8-camera dataset format
+        base_gt_illuminants = gt["groundtruth_illuminants"]
+        black_levels = len(base_gt_illuminants) * [gt["darkness_level"][0][0]]
+    elif "real_rgb" in gt.keys():
+        #Gehler-Shi dataset format
+        base_gt_illuminants = gt["real_rgb"]
+        black_levels = 87 * [0] + (len(base_gt_illuminants) - 87) * [129]
+    else:
+        print("Error: unknown ground-truth format, only formats of Gehler-Shi and NUS 8-camera datasets are supported")
+        sys.exit(1)
+
+    return (base_gt_illuminants, black_levels)
+
+
+if __name__ == '__main__':
+    parser = argparse.ArgumentParser(
+        description=("A tool for training the learning-based "
+                     "color balance algorithm. Currently supports "
+                     "training only on the Gehler-Shi and NUS 8-camera datasets."),
+        formatter_class=argparse.RawDescriptionHelpFormatter)
+    parser.add_argument(
+        "-i",
+        "--input_folder",
+        metavar="INPUT_FOLDER",
+        default="",
+        help=("Folder containing the training dataset. Assumes minimally "
+              "processed png images like in the Gehler-Shi (http://www.cs.sfu.ca/~colour/data/shi_gehler/) "
+              "or NUS 8-camera (http://www.comp.nus.edu.sg/~whitebal/illuminant/illuminant.html) datasets"))
+    parser.add_argument(
+        "-g",
+        "--ground_truth",
+        metavar="GROUND_TRUTH",
+        default="real_illum_568..mat",
+        help=("Path to the mat file containing ground truth illuminations. Currently "
+              "supports formats supplied by the Gehler-Shi and NUS 8-camera datasets."))
+    parser.add_argument(
+        "-r",
+        "--range",
+        metavar="RANGE",
+        default="0,0",
+        help="Range of images from the input dataset to use for training")
+    parser.add_argument(
+        "-o",
+        "--out",
+        metavar="OUT",
+        default="color_balance_model.yml",
+        help="Path to the output learnt model. Either a .yml (for loading during runtime) "
+             "or .hpp (for compiling with the main code) file ")
+    parser.add_argument(
+        "--hist_bin_num",
+        metavar="HIST_BIN_NUM",
+        default="64",
+        help=("Size of one dimension of a three-dimensional RGB histogram employed in the "
+              "feature extraction step."))
+    parser.add_argument(
+        "--num_trees",
+        metavar="NUM_TREES",
+        default="20",
+        help=("Parameter to control the size of the regression tree ensemble"))
+    parser.add_argument(
+        "--max_tree_depth",
+        metavar="MAX_TREE_DEPTH",
+        default="4",
+        help=("Maxmimum depth of regression trees constructed during training."))
+    parser.add_argument(
+        "-a",
+        "--num_augmented",
+        metavar="NUM_AUGMENTED",
+        default="2",
+        help=("Number of augmented samples per one training image. Training set "
+              "augmentation tends to improve the learnt model robustness."))
+
+    args, other_args = parser.parse_known_args()
+
+    if not os.path.exists(args.input_folder):
+        print("Error: " + args.input_folder + (" does not exist. Please, correctly "
+                                                 "specify the -i parameter"))
+        sys.exit(1)
+
+    if not os.path.exists(args.ground_truth):
+        print("Error: " + args.ground_truth + (" does not exist. Please, correctly "
+                                                 "specify the -g parameter"))
+        sys.exit(1)
+
+    img_range = map(int,parse_sequence(args.range))
+    if len(img_range)!=2:
+        print("Error: Please specify the -r parameter in form <first_image_index>,<last_image_index>")
+        sys.exit(1)
+
+    use_YML = None
+    if args.out.endswith(".yml"):
+        use_YML = True
+    elif args.out.endswith(".hpp"):
+        use_YML = False
+    else:
+        print("Error: Only .hpp and .yml are supported as output formats")
+        sys.exit(1)
+
+    hist_bin_num = int(args.hist_bin_num)
+    num_trees = int(args.num_trees)
+    max_tree_depth = int(args.max_tree_depth)
+    img_files = sorted(os.listdir(args.input_folder))
+    (base_gt_illuminants,black_levels) = load_ground_truth(args.ground_truth)
+
+    features = []
+    gt_illuminants = []
+    i=0
+    sz = len(img_files)
+    random.seed(1234)
+    inst = cv2.xphoto.createLearningBasedWB()
+    inst.setRangeMaxVal(255)
+    inst.setSaturationThreshold(0.98)
+    inst.setHistBinNum(hist_bin_num)
+    for file in img_files:
+        if (i>=img_range[0] and i<img_range[1]) or (img_range[0]==img_range[1]==0):
+            cur_path = os.path.join(args.input_folder,file)
+            im = cv2.imread(cur_path, -1).astype(np.float32)
+            im -= black_levels[i]
+            im_8bit = convert_to_8bit(im)
+            cur_img_features = inst.extractSimpleFeatures(im_8bit, None)
+            features.append(cur_img_features.tolist())
+            gt_illuminants.append(base_gt_illuminants[i].tolist())
+
+            for iter in range(int(args.num_augmented)):
+                R_coef = random.uniform(0.2, 5.0)
+                G_coef = random.uniform(0.2, 5.0)
+                B_coef = random.uniform(0.2, 5.0)
+                im_8bit = im
+                im_8bit[:,:,0] *= B_coef
+                im_8bit[:,:,1] *= G_coef
+                im_8bit[:,:,2] *= R_coef
+                im_8bit = convert_to_8bit(im)
+                cur_img_features = inst.extractSimpleFeatures(im_8bit, None)
+                features.append(cur_img_features.tolist())
+                illum = base_gt_illuminants[i]
+                illum[0] *= R_coef
+                illum[1] *= G_coef
+                illum[2] *= B_coef
+                gt_illuminants.append(illum.tolist())
+
+            sys.stdout.write("Computing features: [%3d/%3d]\r" % (i, sz)),
+            sys.stdout.flush()
+        i+=1
+
+    print("\nLearning the model...")
+    model = learn_regression_tree_ensemble(features, gt_illuminants, num_trees, max_tree_depth)
+    print("Writing the model...")
+    generate_code(model,{"-r":args.range, "--hist_bin_num": args.hist_bin_num, "--num_trees": args.num_trees,
+                         "--max_tree_depth": args.max_tree_depth, "--num_augmented": args.num_augmented},
+                  use_YML, args.out)
+    print("Done")
diff --git a/contrib/modules/xphoto/samples/simple_color_balance.cpp b/contrib/modules/xphoto/samples/simple_color_balance.cpp
deleted file mode 100644
index 4159544..0000000
--- a/contrib/modules/xphoto/samples/simple_color_balance.cpp
+++ /dev/null
@@ -1,60 +0,0 @@
-#include "opencv2/xphoto.hpp"
-
-#include "opencv2/imgproc.hpp"
-#include "opencv2/highgui.hpp"
-
-#include "opencv2/core/utility.hpp"
-#include "opencv2/imgproc/types_c.h"
-
-const char* keys =
-{
-    "{i || input image name}"
-    "{o || output image name}"
-};
-
-int main( int argc, const char** argv )
-{
-    bool printHelp = ( argc == 1 );
-    printHelp = printHelp || ( argc == 2 && std::string(argv[1]) == "--help" );
-    printHelp = printHelp || ( argc == 2 && std::string(argv[1]) == "-h" );
-
-    if ( printHelp )
-    {
-        printf("\nThis sample demonstrates simple color balance algorithm\n"
-            "Call:\n"
-            "    simple_color_blance -i=in_image_name [-o=out_image_name]\n\n");
-        return 0;
-    }
-
-    cv::CommandLineParser parser(argc, argv, keys);
-    if ( !parser.check() )
-    {
-        parser.printErrors();
-        return -1;
-    }
-
-    std::string inFilename = parser.get<std::string>("i");
-    std::string outFilename = parser.get<std::string>("o");
-
-    cv::Mat src = cv::imread(inFilename, 1);
-    if ( src.empty() )
-    {
-        printf("Cannot read image file: %s\n", inFilename.c_str());
-        return -1;
-    }
-
-    cv::Mat res(src.size(), src.type());
-    cv::xphoto::balanceWhite(src, res, cv::xphoto::WHITE_BALANCE_SIMPLE);
-
-    if ( outFilename == "" )
-    {
-        cv::namedWindow("after white balance", 1);
-        cv::imshow("after white balance", res);
-
-        cv::waitKey(0);
-    }
-    else
-        cv::imwrite(outFilename, res);
-
-    return 0;
-}
\ No newline at end of file
diff --git a/contrib/modules/xphoto/src/bm3d_denoising_invoker_commons.hpp b/contrib/modules/xphoto/src/bm3d_denoising_invoker_commons.hpp
new file mode 100644
index 0000000..65ecaf4
--- /dev/null
+++ b/contrib/modules/xphoto/src/bm3d_denoising_invoker_commons.hpp
@@ -0,0 +1,165 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+//  By downloading, copying, installing or using the software you agree to this license.
+//  If you do not agree to this license, do not download, install,
+//  copy or use the software.
+//
+//
+//                        Intel License Agreement
+//                For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective icvers.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+//   * Redistribution's of source code must retain the above copyright notice,
+//     this list of conditions and the following disclaimer.
+//
+//   * Redistribution's in binary form must reproduce the above copyright notice,
+//     this list of conditions and the following disclaimer in the documentation
+//     and/or other materials provided with the distribution.
+//
+//   * The name of Intel Corporation may not be used to endorse or promote products
+//     derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#ifndef __OPENCV_BM3D_DENOISING_INVOKER_COMMONS_HPP__
+#define __OPENCV_BM3D_DENOISING_INVOKER_COMMONS_HPP__
+
+#include "bm3d_denoising_invoker_structs.hpp"
+
+// std::isnan is a part of C++11 and it is not supported in MSVS2010/2012
+#if defined _MSC_VER && _MSC_VER < 1800 /* MSVC 2013 */
+#include <float.h>
+namespace std {
+    template <typename T> bool isnan(T value) { return _isnan(value) != 0; }
+}
+#endif
+
+namespace cv
+{
+namespace xphoto
+{
+
+// Returns largest power of 2 smaller than the input value
+inline int getLargestPowerOf2SmallerThan(unsigned x)
+{
+    x = x | (x >> 1);
+    x = x | (x >> 2);
+    x = x | (x >> 4);
+    x = x | (x >> 8);
+    x = x | (x >> 16);
+    return x - (x >> 1);
+}
+
+// Returns true if x is a power of 2. Otherwise false.
+inline bool isPowerOf2(int x)
+{
+    return (x > 0) && !(x & (x - 1));
+}
+
+
+template <typename T>
+inline static void shrink(T &val, T &nonZeroCount, const T &threshold)
+{
+    if (std::abs(val) < threshold)
+        val = 0;
+    else
+        ++nonZeroCount;
+}
+
+template <typename T>
+inline static void hardThreshold2D(T *dst, T *thrMap, const int &templateWindowSizeSq)
+{
+    for (int i = 1; i < templateWindowSizeSq; ++i)
+    {
+        if (std::abs(dst[i] < thrMap[i]))
+            dst[i] = 0;
+    }
+}
+
+template <int N, typename T, typename DT, typename CT>
+inline static T HardThreshold(BlockMatch<T, DT, CT> *z, const int &n, T *&thrMap)
+{
+    T nonZeroCount = 0;
+
+    for (int i = 0; i < N; ++i)
+        shrink(z[i][n], nonZeroCount, *thrMap++);
+
+    return nonZeroCount;
+}
+
+template <typename T, typename DT, typename CT>
+inline static T HardThreshold(BlockMatch<T, DT, CT> *z, const int &n, T *&thrMap, const int &N)
+{
+    T nonZeroCount = 0;
+
+    for (int i = 0; i < N; ++i)
+        shrink(z[i][n], nonZeroCount, *thrMap++);
+
+    return nonZeroCount;
+}
+
+template <int N, typename T, typename DT, typename CT>
+inline static int WienerFiltering(BlockMatch<T, DT, CT> *zSrc, BlockMatch<T, DT, CT> *zBasic, const int &n, T *&thrMap)
+{
+    int wienerCoeffs = 0;
+
+    for (int i = 0; i < N; ++i)
+    {
+        // Possible optimization point here to get rid of floats and casts
+        int basicSq = zBasic[i][n] * zBasic[i][n];
+        int sigmaSq = *thrMap * *thrMap;
+        int denom = basicSq + sigmaSq;
+        float wie = (denom == 0) ? 1.0f : ((float)basicSq / (float)denom);
+
+        zBasic[i][n] = (T)(zSrc[i][n] * wie);
+        wienerCoeffs += (int)wie;
+        ++thrMap;
+    }
+
+    return wienerCoeffs;
+}
+
+template <typename T, typename DT, typename CT>
+inline static int WienerFiltering(BlockMatch<T, DT, CT> *zSrc, BlockMatch<T, DT, CT> *zBasic, const int &n, T *&thrMap, const unsigned &N)
+{
+    int wienerCoeffs = 0;
+
+    for (unsigned i = 0; i < N; ++i)
+    {
+        // Possible optimization point here to get rid of floats and casts
+        int basicSq = zBasic[i][n] * zBasic[i][n];
+        int sigmaSq = *thrMap * *thrMap;
+        int denom = basicSq + sigmaSq;
+        float wie = (denom == 0) ? 1.0f : ((float)basicSq / (float)denom);
+
+        zBasic[i][n] = (T)(zSrc[i][n] * wie);
+        wienerCoeffs += (int)wie;
+        ++thrMap;
+    }
+
+    return wienerCoeffs;
+}
+
+
+}  // namespace xphoto
+}  // namespace cv
+
+#endif
diff --git a/contrib/modules/xphoto/src/bm3d_denoising_invoker_step1.hpp b/contrib/modules/xphoto/src/bm3d_denoising_invoker_step1.hpp
new file mode 100644
index 0000000..ab214e1
--- /dev/null
+++ b/contrib/modules/xphoto/src/bm3d_denoising_invoker_step1.hpp
@@ -0,0 +1,517 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+//  By downloading, copying, installing or using the software you agree to this license.
+//  If you do not agree to this license, do not download, install,
+//  copy or use the software.
+//
+//
+//                        Intel License Agreement
+//                For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective icvers.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+//   * Redistribution's of source code must retain the above copyright notice,
+//     this list of conditions and the following disclaimer.
+//
+//   * Redistribution's in binary form must reproduce the above copyright notice,
+//     this list of conditions and the following disclaimer in the documentation
+//     and/or other materials provided with the distribution.
+//
+//   * The name of Intel Corporation may not be used to endorse or promote products
+//     derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#ifndef __OPENCV_BM3D_DENOISING_INVOKER_STEP1_HPP__
+#define __OPENCV_BM3D_DENOISING_INVOKER_STEP1_HPP__
+
+#include "bm3d_denoising_invoker_commons.hpp"
+#include "bm3d_denoising_transforms.hpp"
+#include "kaiser_window.hpp"
+
+namespace cv
+{
+namespace xphoto
+{
+
+template <typename T, typename D, typename WT, typename TT, typename TC>
+struct Bm3dDenoisingInvokerStep1 : public ParallelLoopBody
+{
+public:
+    Bm3dDenoisingInvokerStep1(
+        const Mat& src,
+        Mat& dst,
+        const int &templateWindowSize,
+        const int &searchWindowSize,
+        const float &h,
+        const int &hBM,
+        const int &groupSize,
+        const int &slidingStep,
+        const float &beta);
+
+    virtual ~Bm3dDenoisingInvokerStep1();
+    void operator() (const Range& range) const;
+
+private:
+    // Unimplemented operator in order to satisfy compiler warning.
+    void operator= (const Bm3dDenoisingInvokerStep1&);
+
+    void calcDistSumsForFirstElementInRow(
+        int i,
+        Array2d<int>& distSums,
+        Array3d<int>& colDistSums,
+        Array3d<int>& lastColDistSums,
+        BlockMatch<TT, int, TT> *bm,
+        int &elementSize) const;
+
+    void calcDistSumsForAllElementsInFirstRow(
+        int i,
+        int j,
+        int firstColNum,
+        Array2d<int>& distSums,
+        Array3d<int>& colDistSums,
+        Array3d<int>& lastColDistSums,
+        BlockMatch<TT, int, TT> *bm,
+        int &elementSize) const;
+
+    // Image containers
+    const Mat& src_;
+    Mat& dst_;
+    Mat srcExtended_;
+
+    // Border size of the extended src and basic images
+    int borderSize_;
+
+    // Template and window size
+    int templateWindowSize_;
+    int searchWindowSize_;
+
+    // Half template and window size
+    int halfTemplateWindowSize_;
+    int halfSearchWindowSize_;
+
+    // Squared template and window size
+    int templateWindowSizeSq_;
+    int searchWindowSizeSq_;
+
+    // Block matching threshold
+    int hBM_;
+
+    // Maximum size of 3D group
+    int groupSize_;
+
+    // Sliding step
+    const int slidingStep_;
+
+    // Threshold map
+    TT *thrMap_;
+
+    // Kaiser window
+    float *kaiser_;
+};
+
+template <typename T, typename D, typename WT, typename TT, typename TC>
+Bm3dDenoisingInvokerStep1<T, D, WT, TT, TC>::Bm3dDenoisingInvokerStep1(
+    const Mat& src,
+    Mat& dst,
+    const int &templateWindowSize,
+    const int &searchWindowSize,
+    const float &h,
+    const int &hBM,
+    const int &groupSize,
+    const int &slidingStep,
+    const float &beta) :
+    src_(src), dst_(dst), groupSize_(groupSize), slidingStep_(slidingStep), thrMap_(NULL), kaiser_(NULL)
+{
+    groupSize_ = getLargestPowerOf2SmallerThan(groupSize);
+    CV_Assert(groupSize > 0);
+
+    halfTemplateWindowSize_ = templateWindowSize >> 1;
+    halfSearchWindowSize_ = searchWindowSize >> 1;
+    templateWindowSize_ = templateWindowSize;
+    searchWindowSize_ = searchWindowSize;
+    templateWindowSizeSq_ = templateWindowSize_ * templateWindowSize_;
+    searchWindowSizeSq_ = searchWindowSize_ * searchWindowSize_;
+
+    // Extend image to avoid border problem
+    borderSize_ = halfSearchWindowSize_ + halfTemplateWindowSize_;
+    copyMakeBorder(src_, srcExtended_, borderSize_, borderSize_, borderSize_, borderSize_, BORDER_DEFAULT);
+
+    // Calculate block matching threshold
+    hBM_ = D::template calcBlockMatchingThreshold<int>(hBM, templateWindowSizeSq_);
+
+    // Select transforms depending on the template size
+    TC::RegisterTransforms2D(templateWindowSize_);
+
+    // Precompute threshold map
+    TC::calcThresholdMap3D(thrMap_, h, templateWindowSize_, groupSize_);
+
+    // Generate kaiser window
+    calcKaiserWindow2D(kaiser_, templateWindowSize_, beta);
+}
+
+template<typename T, typename D, typename WT, typename TT, typename TC>
+inline Bm3dDenoisingInvokerStep1<T, D, WT, TT, TC>::~Bm3dDenoisingInvokerStep1()
+{
+    delete[] thrMap_;
+    delete[] kaiser_;
+}
+
+template <typename T, typename D, typename WT, typename TT, typename TC>
+void Bm3dDenoisingInvokerStep1<T, D, WT, TT, TC>::operator() (const Range& range) const
+{
+    const int size = (range.size() + 2 * borderSize_) * srcExtended_.cols;
+    std::vector<WT> weightedSum(size, 0.0);
+    std::vector<WT> weights(size, 0.0);
+    int row_from = range.start;
+    int row_to = range.end - 1;
+
+    // Local vars for faster processing
+    const int blockSize = templateWindowSize_;
+    const int blockSizeSq = templateWindowSizeSq_;
+    const int halfBlockSize = halfTemplateWindowSize_;
+    const int searchWindowSize = searchWindowSize_;
+    const int searchWindowSizeSq = searchWindowSizeSq_;
+    const TT halfSearchWindowSize = (TT)halfSearchWindowSize_;
+    const int hBM = hBM_;
+    const int groupSize = groupSize_;
+
+    const int step = srcExtended_.cols;
+    const int dstStep = srcExtended_.cols;
+    const int weiStep = srcExtended_.cols;
+    const int dstcstep = dstStep - blockSize;
+    const int weicstep = weiStep - blockSize;
+
+    // Buffer to store 3D group
+    BlockMatch<TT, int, TT> *bm = new BlockMatch<TT, int, TT>[searchWindowSizeSq];
+    for (int i = 0; i < searchWindowSizeSq; ++i)
+        bm[i].init(blockSizeSq);
+
+    // First element in a group is always the reference patch. Hence distance is 0.
+    bm[0](0, halfSearchWindowSize, halfSearchWindowSize);
+
+    // Sums of columns and rows for current pixel
+    Array2d<int> distSums(searchWindowSize, searchWindowSize);
+
+    // Sums of columns for current pixel (for lazy calc optimization)
+    Array3d<int> colDistSums(blockSize, searchWindowSize, searchWindowSize);
+
+    // Last elements of column sum (for each element in a row)
+    Array3d<int> lastColDistSums(src_.cols, searchWindowSize, searchWindowSize);
+
+    int firstColNum = -1;
+    for (int j = row_from, jj = 0; j <= row_to; j += slidingStep_, jj += slidingStep_)
+    {
+        for (int i = 0; i < src_.cols; i += slidingStep_)
+        {
+            const T *currentPixel = srcExtended_.ptr<T>(0) + step*j + i;
+            int elementSize = 1;
+
+            // Calculate distSums using moving average filter approach.
+            if (i == 0)
+            {
+                // Calculate distSums for the first element in a row
+                calcDistSumsForFirstElementInRow(j, distSums, colDistSums, lastColDistSums, bm, elementSize);
+                firstColNum = 0;
+            }
+            else
+            {
+                if (j == row_from)
+                {
+                    // Calculate distSums for all elements in the first row
+                    calcDistSumsForAllElementsInFirstRow(
+                        j, i, firstColNum, distSums, colDistSums, lastColDistSums, bm, elementSize);
+                }
+                else
+                {
+                    const int start_bx = blockSize + i - 1;
+                    const int start_by = j - 1;
+                    const int ax = halfSearchWindowSize + start_bx;
+                    const int ay = halfSearchWindowSize + start_by;
+
+                    const T a_up = srcExtended_.at<T>(ay, ax);
+                    const T a_down = srcExtended_.at<T>(ay + blockSize, ax);
+
+                    for (TT y = 0; y < searchWindowSize; y++)
+                    {
+                        int *distSumsRow = distSums.row_ptr(y);
+                        int *colDistSumsRow = colDistSums.row_ptr(firstColNum, y);
+                        int *lastColDistSumsRow = lastColDistSums.row_ptr(i, y);
+
+                        const T *b_up_ptr = srcExtended_.ptr<T>(start_by + y);
+                        const T *b_down_ptr = srcExtended_.ptr<T>(start_by + y + blockSize);
+
+                        for (TT x = 0; x < searchWindowSize; x++)
+                        {
+                            // Remove from current pixel sum column sum with index "firstColNum"
+                            distSumsRow[x] -= colDistSumsRow[x];
+
+                            const int bx = start_bx + x;
+                            colDistSumsRow[x] = lastColDistSumsRow[x] +
+                                D::template calcUpDownDist<T>(a_up, a_down, b_up_ptr[bx], b_down_ptr[bx]);
+
+                            distSumsRow[x] += colDistSumsRow[x];
+                            lastColDistSumsRow[x] = colDistSumsRow[x];
+
+                            if (x == halfSearchWindowSize && y == halfSearchWindowSize)
+                                continue;
+
+                            // Save the distance, coordinate and increase the counter
+                            if (distSumsRow[x] < hBM)
+                                bm[elementSize++](distSumsRow[x], x, y);
+                        }
+                    }
+                }
+
+                firstColNum = (firstColNum + 1) % blockSize;
+            }
+
+            // Sort bm by distance (first element is already sorted)
+            std::sort(bm + 1, bm + elementSize);
+
+            // Find the nearest power of 2 and cap the group size from the top
+            elementSize = getLargestPowerOf2SmallerThan(elementSize);
+            if (elementSize > groupSize)
+                elementSize = groupSize;
+
+            // Transform 2D patches
+            for (int n = 0; n < elementSize; ++n)
+            {
+                const T *candidatePatch = currentPixel + step * bm[n].coord_y + bm[n].coord_x;
+                TC::forwardTransform2D(candidatePatch, bm[n].data(), step, blockSize);
+            }
+
+            // Transform and shrink 1D columns
+            TT sumNonZero = 0;
+            TT *thrMapPtr1D = thrMap_ + (elementSize - 1) * blockSizeSq;
+            switch (elementSize)
+            {
+            case 16:
+                for (int n = 0; n < blockSizeSq; n++)
+                {
+                    TC::forwardTransform16(bm, n);
+                    sumNonZero += HardThreshold<16>(bm, n, thrMapPtr1D);
+                    TC::inverseTransform16(bm, n);
+                }
+                break;
+            case 8:
+                for (int n = 0; n < blockSizeSq; n++)
+                {
+                    TC::forwardTransform8(bm, n);
+                    sumNonZero += HardThreshold<8>(bm, n, thrMapPtr1D);
+                    TC::inverseTransform8(bm, n);
+                }
+                break;
+            case 4:
+                for (int n = 0; n < blockSizeSq; n++)
+                {
+                    TC::forwardTransform4(bm, n);
+                    sumNonZero += HardThreshold<4>(bm, n, thrMapPtr1D);
+                    TC::inverseTransform4(bm, n);
+                }
+                break;
+            case 2:
+                for (int n = 0; n < blockSizeSq; n++)
+                {
+                    TC::forwardTransform2(bm, n);
+                    TC::forwardTransform2(bm, n);
+                    sumNonZero += HardThreshold<2>(bm, n, thrMapPtr1D);
+                    TC::inverseTransform2(bm, n);
+                }
+                break;
+            case 1:
+                {
+                    TT *block = bm[0].data();
+                    for (int n = 0; n < blockSizeSq; n++)
+                        shrink(block[n], sumNonZero, *thrMapPtr1D++);
+                }
+                break;
+            default:
+                for (int n = 0; n < blockSizeSq; n++)
+                {
+                    TC::forwardTransformN(bm, n, elementSize);
+                    sumNonZero += HardThreshold(bm, n, thrMapPtr1D, elementSize);
+                    TC::inverseTransformN(bm, n, elementSize);
+                }
+            }
+
+            // Inverse 2D transform
+            for (int n = 0; n < elementSize; ++n)
+                TC::inverseTransform2D(bm[n].data(), blockSize);
+
+            // Aggregate the results (increase sumNonZero to avoid division by zero)
+            float weight = 1.0f / (float)(++sumNonZero);
+
+            // Scale weight by element size
+            weight *= elementSize;
+            weight /= groupSize;
+
+            // Put patches back to their original positions
+            WT *dstPtr = weightedSum.data() + jj * dstStep + i;
+            WT *weiPtr = weights.data() + jj * dstStep + i;
+            const float *kaiser = kaiser_;
+
+            for (int l = 0; l < elementSize; ++l)
+            {
+                const TT *block = bm[l].data();
+                int offset = bm[l].coord_y * dstStep + bm[l].coord_x;
+                WT *d = dstPtr + offset;
+                WT *dw = weiPtr + offset;
+
+                for (int n = 0; n < blockSize; ++n)
+                {
+                    for (int m = 0; m < blockSize; ++m)
+                    {
+                        unsigned idx = n * blockSize + m;
+                        *d += kaiser[idx] * block[idx] * weight;
+                        *dw += kaiser[idx] * weight;
+                        ++d, ++dw;
+                    }
+                    d += dstcstep;
+                    dw += weicstep;
+                }
+            }
+        } // i
+    } // j
+
+    // Cleanup
+    for (int i = 0; i < searchWindowSizeSq; ++i)
+        bm[i].release();
+    delete[] bm;
+
+    // Divide accumulation buffer by the corresponding weights
+    for (int i = row_from, ii = 0; i <= row_to; ++i, ++ii)
+    {
+        T *d = dst_.ptr<T>(i);
+        float *dE = weightedSum.data() + (ii + halfSearchWindowSize + halfBlockSize) * dstStep + halfSearchWindowSize;
+        float *dw = weights.data() + (ii + halfSearchWindowSize + halfBlockSize) * dstStep + halfSearchWindowSize;
+        for (int j = 0; j < dst_.cols; ++j)
+            d[j] = cv::saturate_cast<T>(dE[j + halfBlockSize] / dw[j + halfBlockSize]);
+    }
+}
+
+template <typename T, typename D, typename WT, typename TT, typename TC>
+inline void Bm3dDenoisingInvokerStep1<T, D, WT, TT, TC>::calcDistSumsForFirstElementInRow(
+    int i,
+    Array2d<int>& distSums,
+    Array3d<int>& colDistSums,
+    Array3d<int>& lastColDistSums,
+    BlockMatch<TT, int, TT> *bm,
+    int &elementSize) const
+{
+    int j = 0;
+    const int hBM = hBM_;
+    const int blockSize = templateWindowSize_;
+    const int searchWindowSize = searchWindowSize_;
+    const TT halfSearchWindowSize = (TT)halfSearchWindowSize_;
+    const int ay = halfSearchWindowSize + i;
+    const int ax = halfSearchWindowSize + j;
+
+    for (TT y = 0; y < searchWindowSize; ++y)
+    {
+        for (TT x = 0; x < searchWindowSize; ++x)
+        {
+            // Zeroize arrays
+            distSums[y][x] = 0;
+            for (int tx = 0; tx < blockSize; tx++)
+                colDistSums[tx][y][x] = 0;
+
+            int start_y = i + y;
+            int start_x = j + x;
+
+            for (int ty = 0; ty < blockSize; ty++)
+                for (int tx = 0; tx < blockSize; tx++)
+                {
+                    int dist = D::template calcDist<T>(
+                        srcExtended_,
+                        ay + ty,
+                        ax + tx,
+                        start_y + ty,
+                        start_x + tx);
+
+                    distSums[y][x] += dist;
+                    colDistSums[tx][y][x] += dist;
+                }
+
+            lastColDistSums[j][y][x] = colDistSums[blockSize - 1][y][x];
+
+            if (x == halfSearchWindowSize && y == halfSearchWindowSize)
+                continue;
+
+            if (distSums[y][x] < hBM)
+                bm[elementSize++](distSums[y][x], x, y);
+        }
+    }
+}
+
+template <typename T, typename D, typename WT, typename TT, typename TC>
+inline void Bm3dDenoisingInvokerStep1<T, D, WT, TT, TC>::calcDistSumsForAllElementsInFirstRow(
+    int i,
+    int j,
+    int firstColNum,
+    Array2d<int>& distSums,
+    Array3d<int>& colDistSums,
+    Array3d<int>& lastColDistSums,
+    BlockMatch<TT, int, TT> *bm,
+    int &elementSize) const
+{
+    const int hBM = hBM_;
+    const int blockSize = templateWindowSize_;
+    const int searchWindowSize = searchWindowSize_;
+    const TT halfSearchWindowSize = (TT)halfSearchWindowSize_;
+
+    const int bx_start = blockSize - 1 + j;
+    const int ax = halfSearchWindowSize + bx_start;
+    const int ay = halfSearchWindowSize + i;
+
+    for (TT y = 0; y < searchWindowSize; ++y)
+    {
+        for (TT x = 0; x < searchWindowSize; ++x)
+        {
+            distSums[y][x] -= colDistSums[firstColNum][y][x];
+
+            colDistSums[firstColNum][y][x] = 0;
+            int by = i + y;
+            int bx = bx_start + x;
+
+            for (int ty = 0; ty < blockSize; ty++)
+                colDistSums[firstColNum][y][x] += D::template calcDist<T>(
+                    srcExtended_,
+                    ay + ty,
+                    ax,
+                    by + ty,
+                    bx);
+
+            distSums[y][x] += colDistSums[firstColNum][y][x];
+            lastColDistSums[j][y][x] = colDistSums[firstColNum][y][x];
+
+            if (x == halfSearchWindowSize && y == halfSearchWindowSize)
+                continue;
+
+            if (distSums[y][x] < hBM)
+                bm[elementSize++](distSums[y][x], x, y);
+        }
+    }
+}
+
+}  // namespace xphoto
+}  // namespace cv
+
+#endif
\ No newline at end of file
diff --git a/contrib/modules/xphoto/src/bm3d_denoising_invoker_step2.hpp b/contrib/modules/xphoto/src/bm3d_denoising_invoker_step2.hpp
new file mode 100644
index 0000000..835a61e
--- /dev/null
+++ b/contrib/modules/xphoto/src/bm3d_denoising_invoker_step2.hpp
@@ -0,0 +1,540 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+//  By downloading, copying, installing or using the software you agree to this license.
+//  If you do not agree to this license, do not download, install,
+//  copy or use the software.
+//
+//
+//                        Intel License Agreement
+//                For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective icvers.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+//   * Redistribution's of source code must retain the above copyright notice,
+//     this list of conditions and the following disclaimer.
+//
+//   * Redistribution's in binary form must reproduce the above copyright notice,
+//     this list of conditions and the following disclaimer in the documentation
+//     and/or other materials provided with the distribution.
+//
+//   * The name of Intel Corporation may not be used to endorse or promote products
+//     derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#ifndef __OPENCV_BM3D_DENOISING_INVOKER_STEP2_HPP__
+#define __OPENCV_BM3D_DENOISING_INVOKER_STEP2_HPP__
+
+#include "bm3d_denoising_invoker_commons.hpp"
+#include "bm3d_denoising_transforms.hpp"
+#include "kaiser_window.hpp"
+
+namespace cv
+{
+namespace xphoto
+{
+
+template <typename T, typename D, typename WT, typename TT, typename TC>
+struct Bm3dDenoisingInvokerStep2 : public ParallelLoopBody
+{
+public:
+    Bm3dDenoisingInvokerStep2(
+        const Mat& src,
+        const Mat& basic,
+        Mat& dst,
+        const int &templateWindowSize,
+        const int &searchWindowSize,
+        const float &h,
+        const int &hBM,
+        const int &groupSize,
+        const int &slidingStep,
+        const float &beta);
+
+    virtual ~Bm3dDenoisingInvokerStep2();
+    void operator() (const Range& range) const;
+
+private:
+    // Unimplemented operator in order to satisfy compiler warning.
+    void operator= (const Bm3dDenoisingInvokerStep2&);
+
+    void calcDistSumsForFirstElementInRow(
+        int i,
+        Array2d<int>& distSums,
+        Array3d<int>& colDistSums,
+        Array3d<int>& lastColDistSums,
+        BlockMatch<TT, int, TT> *bm,
+        int &elementSize) const;
+
+    void calcDistSumsForAllElementsInFirstRow(
+        int i,
+        int j,
+        int firstColNum,
+        Array2d<int>& distSums,
+        Array3d<int>& colDistSums,
+        Array3d<int>& lastColDistSums,
+        BlockMatch<TT, int, TT> *bm,
+        int &elementSize) const;
+
+    // Image containers
+    const Mat& src_;
+    const Mat& basic_;
+    Mat& dst_;
+    Mat srcExtended_;
+    Mat basicExtended_;
+
+    // Border size of the extended src and basic images
+    int borderSize_;
+
+    // Template and window size
+    int templateWindowSize_;
+    int searchWindowSize_;
+
+    // Half template and window size
+    int halfTemplateWindowSize_;
+    int halfSearchWindowSize_;
+
+    // Squared template and window size
+    int templateWindowSizeSq_;
+    int searchWindowSizeSq_;
+
+    // Block matching threshold
+    int hBM_;
+
+    // Maximum size of 3D group
+    int groupSize_;
+
+    // Sliding step
+    const int slidingStep_;
+
+    // Threshold map
+    TT *thrMap_;
+
+    // Kaiser window
+    float *kaiser_;
+};
+
+template <typename T, typename D, typename WT, typename TT, typename TC>
+Bm3dDenoisingInvokerStep2<T, D, WT, TT, TC>::Bm3dDenoisingInvokerStep2(
+    const Mat& src,
+    const Mat& basic,
+    Mat& dst,
+    const int &templateWindowSize,
+    const int &searchWindowSize,
+    const float &h,
+    const int &hBM,
+    const int &groupSize,
+    const int &slidingStep,
+    const float &beta) :
+    src_(src), basic_(basic), dst_(dst), groupSize_(groupSize), slidingStep_(slidingStep), thrMap_(NULL), kaiser_(NULL)
+{
+    groupSize_ = getLargestPowerOf2SmallerThan(groupSize);
+    CV_Assert(groupSize > 0);
+
+    halfTemplateWindowSize_ = templateWindowSize >> 1;
+    halfSearchWindowSize_ = searchWindowSize >> 1;
+    templateWindowSize_ = templateWindowSize;
+    searchWindowSize_ = searchWindowSize;
+    templateWindowSizeSq_ = templateWindowSize_ * templateWindowSize_;
+    searchWindowSizeSq_ = searchWindowSize_ * searchWindowSize_;
+
+    // Extend image to avoid border problem
+    borderSize_ = halfSearchWindowSize_ + halfTemplateWindowSize_;
+    copyMakeBorder(src_, srcExtended_, borderSize_, borderSize_, borderSize_, borderSize_, BORDER_DEFAULT);
+    copyMakeBorder(basic_, basicExtended_, borderSize_, borderSize_, borderSize_, borderSize_, BORDER_DEFAULT);
+
+    // Calculate block matching threshold
+    hBM_ = D::template calcBlockMatchingThreshold<int>(hBM, templateWindowSizeSq_);
+
+    // Select transforms depending on the template size
+    TC::RegisterTransforms2D(templateWindowSize_);
+
+    // Precompute threshold map
+    TC::calcThresholdMap3D(thrMap_, h, templateWindowSize_, groupSize_);
+
+    // Generate kaiser window
+    calcKaiserWindow2D(kaiser_, templateWindowSize_, beta);
+}
+
+template<typename T, typename D, typename WT, typename TT, typename TC>
+inline Bm3dDenoisingInvokerStep2<T, D, WT, TT, TC>::~Bm3dDenoisingInvokerStep2()
+{
+    delete[] thrMap_;
+    delete[] kaiser_;
+}
+
+template <typename T, typename D, typename WT, typename TT, typename TC>
+void Bm3dDenoisingInvokerStep2<T, D, WT, TT, TC>::operator() (const Range& range) const
+{
+    const int size = (range.size() + 2 * borderSize_) * srcExtended_.cols;
+    std::vector<WT> weightedSum(size, 0.0);
+    std::vector<WT> weights(size, 0.0);
+    int row_from = range.start;
+    int row_to = range.end - 1;
+
+    // Local vars for faster processing
+    const int blockSize = templateWindowSize_;
+    const int blockSizeSq = templateWindowSizeSq_;
+    const int halfBlockSize = halfTemplateWindowSize_;
+    const int searchWindowSize = searchWindowSize_;
+    const int searchWindowSizeSq = searchWindowSizeSq_;
+    const TT halfSearchWindowSize = (TT)halfSearchWindowSize_;
+    const int hBM = hBM_;
+    const int groupSize = groupSize_;
+
+    const int step = srcExtended_.cols;
+    const int dstStep = srcExtended_.cols;
+    const int weiStep = srcExtended_.cols;
+    const int dstcstep = dstStep - blockSize;
+    const int weicstep = weiStep - blockSize;
+
+    // Buffer to store 3D group
+    BlockMatch<TT, int, TT> *bmBasic = new BlockMatch<TT, int, TT>[searchWindowSizeSq];
+    BlockMatch<TT, int, TT> *bmSrc = new BlockMatch<TT, int, TT>[searchWindowSizeSq];
+    for (int i = 0; i < searchWindowSizeSq; ++i)
+    {
+        bmBasic[i].init(blockSizeSq);
+        bmSrc[i].init(blockSizeSq);
+    }
+
+    // First element in a group is always the reference patch. Hence distance is 0.
+    bmBasic[0](0, halfSearchWindowSize, halfSearchWindowSize);
+    bmSrc[0](0, halfSearchWindowSize, halfSearchWindowSize);
+
+    // Sums of columns and rows for current pixel
+    Array2d<int> distSums(searchWindowSize, searchWindowSize);
+
+    // Sums of columns for current pixel (for lazy calc optimization)
+    Array3d<int> colDistSums(blockSize, searchWindowSize, searchWindowSize);
+
+    // Last elements of column sum (for each element in a row)
+    Array3d<int> lastColDistSums(src_.cols, searchWindowSize, searchWindowSize);
+
+    int firstColNum = -1;
+    for (int j = row_from, jj = 0; j <= row_to; j += slidingStep_, jj += slidingStep_)
+    {
+        for (int i = 0; i < src_.cols; i += slidingStep_)
+        {
+            const T *currentPixelSrc = srcExtended_.ptr<T>(0) + step*j + i;
+            const T *currentPixelBasic = basicExtended_.ptr<T>(0) + step*j + i;
+
+            int elementSize = 1;
+
+            // Calculate distSums using moving average filter approach.
+            if (i == 0)
+            {
+                // Calculate distSums for the first element in a row
+                calcDistSumsForFirstElementInRow(j, distSums, colDistSums, lastColDistSums, bmBasic, elementSize);
+                firstColNum = 0;
+            }
+            else
+            {
+                if (j == row_from)
+                {
+                    // Calculate distSums for all elements in the first row
+                    calcDistSumsForAllElementsInFirstRow(
+                        j, i, firstColNum, distSums, colDistSums, lastColDistSums, bmBasic, elementSize);
+                }
+                else
+                {
+                    const int start_bx = blockSize + i - 1;
+                    const int start_by = j - 1;
+                    const int ax = halfSearchWindowSize + start_bx;
+                    const int ay = halfSearchWindowSize + start_by;
+
+                    const T a_up = basicExtended_.at<T>(ay, ax);
+                    const T a_down = basicExtended_.at<T>(ay + blockSize, ax);
+
+                    for (TT y = 0; y < searchWindowSize; y++)
+                    {
+                        int *distSumsRow = distSums.row_ptr(y);
+                        int *colDistSumsRow = colDistSums.row_ptr(firstColNum, y);
+                        int *lastColDistSumsRow = lastColDistSums.row_ptr(i, y);
+
+                        const T *b_up_ptr = basicExtended_.ptr<T>(start_by + y);
+                        const T *b_down_ptr = basicExtended_.ptr<T>(start_by + y + blockSize);
+
+                        for (TT x = 0; x < searchWindowSize; x++)
+                        {
+                            // Remove from current pixel sum column sum with index "firstColNum"
+                            distSumsRow[x] -= colDistSumsRow[x];
+
+                            const int bx = start_bx + x;
+                            colDistSumsRow[x] = lastColDistSumsRow[x] +
+                                D::template calcUpDownDist<T>(a_up, a_down, b_up_ptr[bx], b_down_ptr[bx]);
+
+                            distSumsRow[x] += colDistSumsRow[x];
+                            lastColDistSumsRow[x] = colDistSumsRow[x];
+
+                            if (x == halfSearchWindowSize && y == halfSearchWindowSize)
+                                continue;
+
+                            // Save the distance, coordinate and increase the counter
+                            if (distSumsRow[x] < hBM)
+                                bmBasic[elementSize++](distSumsRow[x], x, y);
+                        }
+                    }
+                }
+
+                firstColNum = (firstColNum + 1) % blockSize;
+            }
+
+            // Sort bmBasic by distance (first element is already sorted)
+            std::sort(bmBasic + 1, bmBasic + elementSize);
+
+            // Find the nearest power of 2 and cap the group size from the top
+            elementSize = getLargestPowerOf2SmallerThan(elementSize);
+            if (elementSize > groupSize)
+                elementSize = groupSize;
+
+            // Transform 2D patches
+            for (int n = 0; n < elementSize; ++n)
+            {
+                const T *candidatePatchSrc = currentPixelSrc + step * bmBasic[n].coord_y + bmBasic[n].coord_x;
+                const T *candidatePatchBasic = currentPixelBasic + step * bmBasic[n].coord_y + bmBasic[n].coord_x;
+                TC::forwardTransform2D(candidatePatchSrc, bmSrc[n].data(), step, blockSize);
+                TC::forwardTransform2D(candidatePatchBasic, bmBasic[n].data(), step, blockSize);
+            }
+
+            // Transform and shrink 1D columns
+            int wienerCoefficients = 0;
+            TT *thrMapPtr1D = thrMap_ + (elementSize - 1) * blockSizeSq;
+            switch (elementSize)
+            {
+            case 16:
+                for (int n = 0; n < blockSizeSq; n++)
+                {
+                    TC::forwardTransform16(bmSrc, n);
+                    TC::forwardTransform16(bmBasic, n);
+                    wienerCoefficients += WienerFiltering<16>(bmSrc, bmBasic, n, thrMapPtr1D);
+                    TC::inverseTransform16(bmBasic, n);
+                }
+                break;
+            case 8:
+                for (int n = 0; n < blockSizeSq; n++)
+                {
+                    TC::forwardTransform8(bmSrc, n);
+                    TC::forwardTransform8(bmBasic, n);
+                    wienerCoefficients += WienerFiltering<8>(bmSrc, bmBasic, n, thrMapPtr1D);
+                    TC::inverseTransform8(bmBasic, n);
+                }
+                break;
+            case 4:
+                for (int n = 0; n < blockSizeSq; n++)
+                {
+                    TC::forwardTransform4(bmSrc, n);
+                    TC::forwardTransform4(bmBasic, n);
+                    wienerCoefficients += WienerFiltering<4>(bmSrc, bmBasic, n, thrMapPtr1D);
+                    TC::inverseTransform4(bmBasic, n);
+                }
+                break;
+            case 2:
+                for (int n = 0; n < blockSizeSq; n++)
+                {
+                    TC::forwardTransform2(bmSrc, n);
+                    TC::forwardTransform2(bmBasic, n);
+                    wienerCoefficients += WienerFiltering<2>(bmSrc, bmBasic, n, thrMapPtr1D);
+                    TC::inverseTransform2(bmBasic, n);
+                }
+                break;
+            case 1:
+            {
+                for (int n = 0; n < blockSizeSq; n++)
+                    wienerCoefficients += WienerFiltering<1>(bmSrc, bmBasic, n, thrMapPtr1D);
+            }
+            break;
+            default:
+                for (int n = 0; n < blockSizeSq; n++)
+                {
+                    TC::forwardTransformN(bmSrc, n, elementSize);
+                    TC::forwardTransformN(bmBasic, n, elementSize);
+                    wienerCoefficients += WienerFiltering(bmSrc, bmBasic, n, thrMapPtr1D, elementSize);
+                    TC::inverseTransformN(bmBasic, n, elementSize);
+                }
+            }
+
+            // Inverse 2D transform
+            for (int n = 0; n < elementSize; ++n)
+                TC::inverseTransform2D(bmBasic[n].data(), blockSize);
+
+            // Aggregate the results (increase sumNonZero to avoid division by zero)
+            float weight = 1.0f / (float)(++wienerCoefficients);
+
+            // Scale weight by element size
+            weight *= elementSize;
+            weight /= groupSize;
+
+            // Put patches back to their original positions
+            WT *dstPtr = weightedSum.data() + jj * dstStep + i;
+            WT *weiPtr = weights.data() + jj * dstStep + i;
+            const float *kaiser = kaiser_;
+
+            for (int l = 0; l < elementSize; ++l)
+            {
+                const TT *block = bmBasic[l].data();
+                int offset = bmBasic[l].coord_y * dstStep + bmBasic[l].coord_x;
+                WT *d = dstPtr + offset;
+                WT *dw = weiPtr + offset;
+
+                for (int n = 0; n < blockSize; ++n)
+                {
+                    for (int m = 0; m < blockSize; ++m)
+                    {
+                        unsigned idx = n * blockSize + m;
+                        *d += kaiser[idx] * block[idx] * weight;
+                        *dw += kaiser[idx] * weight;
+                        ++d, ++dw;
+                    }
+                    d += dstcstep;
+                    dw += weicstep;
+                }
+            }
+        } // i
+    } // j
+
+    // Cleanup
+    for (int i = 0; i < searchWindowSizeSq; ++i)
+    {
+        bmBasic[i].release();
+        bmSrc[i].release();
+    }
+
+    delete[] bmSrc;
+    delete[] bmBasic;
+
+    // Divide accumulation buffer by the corresponding weights
+    for (int i = row_from, ii = 0; i <= row_to; ++i, ++ii)
+    {
+        T *d = dst_.ptr<T>(i);
+        float *dE = weightedSum.data() + (ii + halfSearchWindowSize + halfBlockSize) * dstStep + halfSearchWindowSize;
+        float *dw = weights.data() + (ii + halfSearchWindowSize + halfBlockSize) * dstStep + halfSearchWindowSize;
+        for (int j = 0; j < dst_.cols; ++j)
+            d[j] = cv::saturate_cast<T>(dE[j + halfBlockSize] / dw[j + halfBlockSize]);
+    }
+}
+
+
+template <typename T, typename D, typename WT, typename TT, typename TC>
+inline void Bm3dDenoisingInvokerStep2<T, D, WT, TT, TC>::calcDistSumsForFirstElementInRow(
+    int i,
+    Array2d<int>& distSums,
+    Array3d<int>& colDistSums,
+    Array3d<int>& lastColDistSums,
+    BlockMatch<TT, int, TT> *bm,
+    int &elementSize) const
+{
+    int j = 0;
+    const int hBM = hBM_;
+    const int blockSize = templateWindowSize_;
+    const int searchWindowSize = searchWindowSize_;
+    const TT halfSearchWindowSize = (TT)halfSearchWindowSize_;
+    const int ay = halfSearchWindowSize + i;
+    const int ax = halfSearchWindowSize + j;
+
+    for (TT y = 0; y < searchWindowSize; ++y)
+    {
+        for (TT x = 0; x < searchWindowSize; ++x)
+        {
+            // Zeroize arrays
+            distSums[y][x] = 0;
+            for (int tx = 0; tx < blockSize; tx++)
+                colDistSums[tx][y][x] = 0;
+
+            int start_y = i + y;
+            int start_x = j + x;
+
+            for (int ty = 0; ty < blockSize; ty++)
+                for (int tx = 0; tx < blockSize; tx++)
+                {
+                    int dist = D::template calcDist<T>(
+                        basicExtended_,
+                        ay + ty,
+                        ax + tx,
+                        start_y + ty,
+                        start_x + tx);
+
+                    distSums[y][x] += dist;
+                    colDistSums[tx][y][x] += dist;
+                }
+
+            lastColDistSums[j][y][x] = colDistSums[blockSize - 1][y][x];
+
+            if (x == halfSearchWindowSize && y == halfSearchWindowSize)
+                continue;
+
+            if (distSums[y][x] < hBM)
+                bm[elementSize++](distSums[y][x], x, y);
+        }
+    }
+}
+
+template <typename T, typename D, typename WT, typename TT, typename TC>
+inline void Bm3dDenoisingInvokerStep2<T, D, WT, TT, TC>::calcDistSumsForAllElementsInFirstRow(
+    int i,
+    int j,
+    int firstColNum,
+    Array2d<int>& distSums,
+    Array3d<int>& colDistSums,
+    Array3d<int>& lastColDistSums,
+    BlockMatch<TT, int, TT> *bm,
+    int &elementSize) const
+{
+    const int hBM = hBM_;
+    const int blockSize = templateWindowSize_;
+    const int searchWindowSize = searchWindowSize_;
+    const TT halfSearchWindowSize = (TT)halfSearchWindowSize_;
+
+    const int bx_start = blockSize - 1 + j;
+    const int ax = halfSearchWindowSize + bx_start;
+    const int ay = halfSearchWindowSize + i;
+
+    for (TT y = 0; y < searchWindowSize; ++y)
+    {
+        for (TT x = 0; x < searchWindowSize; ++x)
+        {
+            distSums[y][x] -= colDistSums[firstColNum][y][x];
+
+            colDistSums[firstColNum][y][x] = 0;
+            int by = i + y;
+            int bx = bx_start + x;
+
+            for (int ty = 0; ty < blockSize; ty++)
+                colDistSums[firstColNum][y][x] += D::template calcDist<T>(
+                    basicExtended_,
+                    ay + ty,
+                    ax,
+                    by + ty,
+                    bx);
+
+            distSums[y][x] += colDistSums[firstColNum][y][x];
+            lastColDistSums[j][y][x] = colDistSums[firstColNum][y][x];
+
+            if (x == halfSearchWindowSize && y == halfSearchWindowSize)
+                continue;
+
+            if (distSums[y][x] < hBM)
+                bm[elementSize++](distSums[y][x], x, y);
+        }
+    }
+}
+
+}  // namespace xphoto
+}  // namespace cv
+
+#endif
\ No newline at end of file
diff --git a/contrib/modules/xphoto/src/bm3d_denoising_invoker_structs.hpp b/contrib/modules/xphoto/src/bm3d_denoising_invoker_structs.hpp
new file mode 100644
index 0000000..1db0dc7
--- /dev/null
+++ b/contrib/modules/xphoto/src/bm3d_denoising_invoker_structs.hpp
@@ -0,0 +1,366 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+//  By downloading, copying, installing or using the software you agree to this license.
+//  If you do not agree to this license, do not download, install,
+//  copy or use the software.
+//
+//
+//                        Intel License Agreement
+//                For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective icvers.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+//   * Redistribution's of source code must retain the above copyright notice,
+//     this list of conditions and the following disclaimer.
+//
+//   * Redistribution's in binary form must reproduce the above copyright notice,
+//     this list of conditions and the following disclaimer in the documentation
+//     and/or other materials provided with the distribution.
+//
+//   * The name of Intel Corporation may not be used to endorse or promote products
+//     derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#ifndef __OPENCV_BM3D_DENOISING_INVOKER_STRUCTS_HPP__
+#define __OPENCV_BM3D_DENOISING_INVOKER_STRUCTS_HPP__
+
+namespace cv
+{
+namespace xphoto
+{
+
+template <typename T, typename DT, typename CT>
+class BlockMatch
+{
+public:
+    // Data accessor
+    T* data()
+    {
+        return data_;
+    }
+
+    // Const version of data accessor
+    const T* data() const
+    {
+        return data_;
+    }
+
+    // Allocate memory for data
+    void init(const int &blockSizeSq)
+    {
+        data_ = new T[blockSizeSq];
+    }
+
+    // Release data memory
+    void release()
+    {
+        delete[] data_;
+    }
+
+    // Overloaded operator for convenient assignment
+    void operator()(const DT &_dist, const CT &_coord_x, const CT &_coord_y)
+    {
+        dist = _dist;
+        coord_x = _coord_x;
+        coord_y = _coord_y;
+    }
+
+    // Overloaded array subscript operator
+    T& operator[](const std::size_t &idx)
+    {
+        return data_[idx];
+    };
+
+    // Overloaded const array subscript operator
+    const T& operator[](const std::size_t &idx) const
+    {
+        return data_[idx];
+    };
+
+    // Overloaded comparison operator for sorting
+    bool operator<(const BlockMatch& right) const
+    {
+        return dist < right.dist;
+    }
+
+    // Block matching distance
+    DT dist;
+
+    // Relative coordinates to the current search window
+    CT coord_x;
+    CT coord_y;
+
+private:
+    // Pointer to the pixel values of the block
+    T *data_;
+};
+
+class DistAbs
+{
+    template <typename T>
+    struct calcDist_
+    {
+        static inline int f(const T &a, const T &b)
+        {
+            return std::abs(a - b);
+        }
+    };
+
+    template <typename ET>
+    struct calcDist_<Vec<ET, 2> >
+    {
+        static inline int f(const Vec<ET, 2> a, const Vec<ET, 2> b)
+        {
+            return std::abs((int)(a[0] - b[0])) + std::abs((int)(a[1] - b[1]));
+        }
+    };
+
+    template <typename ET>
+    struct calcDist_<Vec<ET, 3> >
+    {
+        static inline int f(const Vec<ET, 3> a, const Vec<ET, 3> b)
+        {
+            return
+                std::abs((int)(a[0] - b[0])) +
+                std::abs((int)(a[1] - b[1])) +
+                std::abs((int)(a[2] - b[2]));
+        }
+    };
+
+    template <typename ET>
+    struct calcDist_<Vec<ET, 4> >
+    {
+        static inline int f(const Vec<ET, 4> a, const Vec<ET, 4> b)
+        {
+            return
+                std::abs((int)(a[0] - b[0])) +
+                std::abs((int)(a[1] - b[1])) +
+                std::abs((int)(a[2] - b[2])) +
+                std::abs((int)(a[3] - b[3]));
+        }
+    };
+
+public:
+    template <typename T>
+    static inline int calcDist(const T &a, const T &b)
+    {
+        return calcDist_<T>::f(a, b);
+    }
+
+    template <typename T>
+    static inline int calcDist(const Mat& m, int i1, int j1, int i2, int j2)
+    {
+        const T a = m.at<T>(i1, j1);
+        const T b = m.at<T>(i2, j2);
+        return calcDist<T>(a, b);
+    }
+
+    template <typename T>
+    static inline int calcUpDownDist(T a_up, T a_down, T b_up, T b_down)
+    {
+        return calcDist<T>(a_down, b_down) - calcDist<T>(a_up, b_up);
+    };
+
+    template <typename T>
+    static inline T calcBlockMatchingThreshold(const T &blockMatchThrL2, const T &blockSizeSq)
+    {
+        return (T)(std::sqrt((double)blockMatchThrL2) * blockSizeSq);
+    }
+};
+
+class DistSquared
+{
+    template <typename T>
+    struct calcDist_
+    {
+        static inline int f(const T &a, const T &b)
+        {
+            return (a - b) * (a - b);
+        }
+    };
+
+    template <typename ET>
+    struct calcDist_<Vec<ET, 2> >
+    {
+        static inline int f(const Vec<ET, 2> a, const Vec<ET, 2> b)
+        {
+            return (int)(a[0] - b[0])*(int)(a[0] - b[0]) + (int)(a[1] - b[1])*(int)(a[1] - b[1]);
+        }
+    };
+
+    template <typename ET>
+    struct calcDist_<Vec<ET, 3> >
+    {
+        static inline int f(const Vec<ET, 3> a, const Vec<ET, 3> b)
+        {
+            return
+                (int)(a[0] - b[0])*(int)(a[0] - b[0]) +
+                (int)(a[1] - b[1])*(int)(a[1] - b[1]) +
+                (int)(a[2] - b[2])*(int)(a[2] - b[2]);
+        }
+    };
+
+    template <typename ET>
+    struct calcDist_<Vec<ET, 4> >
+    {
+        static inline int f(const Vec<ET, 4> a, const Vec<ET, 4> b)
+        {
+            return
+                (int)(a[0] - b[0])*(int)(a[0] - b[0]) +
+                (int)(a[1] - b[1])*(int)(a[1] - b[1]) +
+                (int)(a[2] - b[2])*(int)(a[2] - b[2]) +
+                (int)(a[3] - b[3])*(int)(a[3] - b[3]);
+        }
+    };
+
+    template <typename T> struct calcUpDownDist_
+    {
+        static inline int f(T a_up, T a_down, T b_up, T b_down)
+        {
+            int A = a_down - b_down;
+            int B = a_up - b_up;
+            return (A - B)*(A + B);
+        }
+    };
+
+    template <typename ET, int n> struct calcUpDownDist_<Vec<ET, n> >
+    {
+    private:
+        typedef Vec<ET, n> T;
+    public:
+        static inline int f(T a_up, T a_down, T b_up, T b_down)
+        {
+            return calcDist<T>(a_down, b_down) - calcDist<T>(a_up, b_up);
+        }
+    };
+
+public:
+    template <typename T>
+    static inline int calcDist(const T &a, const T &b)
+    {
+        return calcDist_<T>::f(a, b);
+    }
+
+    template <typename T>
+    static inline int calcDist(const Mat& m, int i1, int j1, int i2, int j2)
+    {
+        const T a = m.at<T>(i1, j1);
+        const T b = m.at<T>(i2, j2);
+        return calcDist<T>(a, b);
+    }
+
+    template <typename T>
+    static inline int calcUpDownDist(T a_up, T a_down, T b_up, T b_down)
+    {
+        return calcUpDownDist_<T>::f(a_up, a_down, b_up, b_down);
+    };
+
+    template <typename T>
+    static inline T calcBlockMatchingThreshold(const T &blockMatchThrL2, const T &blockSizeSq)
+    {
+        return blockMatchThrL2 * blockSizeSq;
+    }
+};
+
+template <class T>
+struct Array2d
+{
+    T* a;
+    int n1, n2;
+    bool needToDeallocArray;
+
+    Array2d(const Array2d& array2d) :
+        a(array2d.a), n1(array2d.n1), n2(array2d.n2), needToDeallocArray(false)
+    {
+        if (array2d.needToDeallocArray)
+        {
+            CV_Error(Error::BadDataPtr, "Copy constructor for self allocating arrays not supported");
+        }
+    }
+
+    Array2d(T* _a, int _n1, int _n2) :
+        a(_a), n1(_n1), n2(_n2), needToDeallocArray(false)
+    {
+    }
+
+    Array2d(int _n1, int _n2) :
+        n1(_n1), n2(_n2), needToDeallocArray(true)
+    {
+        a = new T[n1*n2];
+    }
+
+    ~Array2d()
+    {
+        if (needToDeallocArray)
+            delete[] a;
+    }
+
+    T* operator [] (int i)
+    {
+        return a + i*n2;
+    }
+
+    inline T* row_ptr(int i)
+    {
+        return (*this)[i];
+    }
+};
+
+template <class T>
+struct Array3d
+{
+    T* a;
+    int n1, n2, n3;
+    bool needToDeallocArray;
+
+    Array3d(T* _a, int _n1, int _n2, int _n3) :
+        a(_a), n1(_n1), n2(_n2), n3(_n3), needToDeallocArray(false)
+    {
+    }
+
+    Array3d(int _n1, int _n2, int _n3) :
+        n1(_n1), n2(_n2), n3(_n3), needToDeallocArray(true)
+    {
+        a = new T[n1*n2*n3];
+    }
+
+    ~Array3d()
+    {
+        if (needToDeallocArray)
+            delete[] a;
+    }
+
+    Array2d<T> operator [] (int i)
+    {
+        Array2d<T> array2d(a + i*n2*n3, n2, n3);
+        return array2d;
+    }
+
+    inline T* row_ptr(int i1, int i2)
+    {
+        return a + i1*n2*n3 + i2*n3;
+    }
+};
+
+}  // namespace xphoto
+}  // namespace cv
+
+#endif
\ No newline at end of file
diff --git a/contrib/modules/xphoto/src/bm3d_denoising_transforms.hpp b/contrib/modules/xphoto/src/bm3d_denoising_transforms.hpp
new file mode 100644
index 0000000..33eee25
--- /dev/null
+++ b/contrib/modules/xphoto/src/bm3d_denoising_transforms.hpp
@@ -0,0 +1,73 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+//  By downloading, copying, installing or using the software you agree to this license.
+//  If you do not agree to this license, do not download, install,
+//  copy or use the software.
+//
+//
+//                        Intel License Agreement
+//                For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective icvers.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+//   * Redistribution's of source code must retain the above copyright notice,
+//     this list of conditions and the following disclaimer.
+//
+//   * Redistribution's in binary form must reproduce the above copyright notice,
+//     this list of conditions and the following disclaimer in the documentation
+//     and/or other materials provided with the distribution.
+//
+//   * The name of Intel Corporation may not be used to endorse or promote products
+//     derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#ifndef __OPENCV_BM3D_DENOISING_TRANSFORMS_HPP__
+#define __OPENCV_BM3D_DENOISING_TRANSFORMS_HPP__
+
+#include "bm3d_denoising_transforms_haar.hpp"
+
+namespace cv
+{
+namespace xphoto
+{
+
+// Following class contains interface of the tranform domain functions.
+template <typename T, typename TT>
+class Transform
+{
+  public:
+    // 2D transforms
+    typedef void(*Forward2D)(const T *ptr, TT *dst, const int &step, const int blockSize);
+    typedef void(*Inverse2D)(TT *src, const int blockSize);
+
+    // 1D transforms
+    typedef void(*Forward1D)(BlockMatch<TT, int, TT> *z, const int &n, const unsigned &N);
+    typedef void(*Inverse1D)(BlockMatch<TT, int, TT> *z, const int &n, const unsigned &N);
+
+    // Specialized 1D transforms
+    typedef void(*Forward1Ds)(BlockMatch<TT, int, TT> *z, const int &n);
+    typedef void(*Inverse1Ds)(BlockMatch<TT, int, TT> *z, const int &n);
+};
+
+}  // namespace xphoto
+}  // namespace cv
+
+#endif
\ No newline at end of file
diff --git a/contrib/modules/xphoto/src/bm3d_denoising_transforms_1D.hpp b/contrib/modules/xphoto/src/bm3d_denoising_transforms_1D.hpp
new file mode 100644
index 0000000..595e1a9
--- /dev/null
+++ b/contrib/modules/xphoto/src/bm3d_denoising_transforms_1D.hpp
@@ -0,0 +1,376 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+//  By downloading, copying, installing or using the software you agree to this license.
+//  If you do not agree to this license, do not download, install,
+//  copy or use the software.
+//
+//
+//                        Intel License Agreement
+//                For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective icvers.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+//   * Redistribution's of source code must retain the above copyright notice,
+//     this list of conditions and the following disclaimer.
+//
+//   * Redistribution's in binary form must reproduce the above copyright notice,
+//     this list of conditions and the following disclaimer in the documentation
+//     and/or other materials provided with the distribution.
+//
+//   * The name of Intel Corporation may not be used to endorse or promote products
+//     derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#ifndef __OPENCV_BM3D_DENOISING_TRANSFORMS_1D_HPP__
+#define __OPENCV_BM3D_DENOISING_TRANSFORMS_1D_HPP__
+
+namespace cv
+{
+namespace xphoto
+{
+
+class HaarTransform1D
+{
+    static void CalculateIndicesN(unsigned *diffIndices, const unsigned &size, const unsigned &N)
+    {
+        unsigned diffIdx = 1;
+        unsigned diffAllIdx = 0;
+        for (unsigned i = 1; i <= N; i <<= 1)
+        {
+            diffAllIdx += (i >> 1);
+            for (unsigned j = 0; j < (i >> 1); ++j)
+                diffIndices[diffIdx++] = size - (--diffAllIdx);
+            diffAllIdx += i;
+        }
+    }
+
+public:
+    /// 1D forward transformations of array of arbitrary size
+    template <typename T, typename DT, typename CT>
+    inline static void ForwardTransformN(BlockMatch<T, DT, CT> *src, const int &n, const unsigned &N)
+    {
+        const unsigned size = N + (N << 1) - 2;
+        T *dstX = new T[size];
+
+        // Fill dstX with source values
+        for (unsigned i = 0; i < N; ++i)
+            dstX[i] = src[i][n];
+
+        unsigned idx = 0, dstIdx = N;
+        for (unsigned i = N; i > 1; i >>= 1)
+        {
+            // Get sums
+            for (unsigned j = 0; j < (i >> 1); ++j)
+                dstX[dstIdx++] = (dstX[idx + 2 * j] + dstX[idx + j * 2 + 1] + 1) >> 1;
+
+            // Get diffs
+            for (unsigned j = 0; j < (i >> 1); ++j)
+                dstX[dstIdx++] = dstX[idx + 2 * j] - dstX[idx + j * 2 + 1];
+
+            idx = dstIdx - i;
+        }
+
+        // Calculate indices in the destination matrix.
+        unsigned *diffIndices = new unsigned[N];
+        CalculateIndicesN(diffIndices, size, N);
+
+        // Fill in destination matrix
+        src[0][n] = dstX[size - 2];
+        for (unsigned i = 1; i < N; ++i)
+            src[i][n] = dstX[diffIndices[i]];
+
+        delete[] dstX;
+        delete[] diffIndices;
+    }
+
+    /// 1D inverse transformation of array of arbitrary size
+    template <typename T, typename DT, typename CT>
+    inline static void InverseTransformN(BlockMatch<T, DT, CT> *src, const int &n, const unsigned &N)
+    {
+        const unsigned dstSize = (N << 1) - 2;
+        T *dstX = new T[dstSize];
+        T *srcX = new T[N];
+
+        // Fill srcX with source values
+        srcX[0] = src[0][n] * 2;
+        for (unsigned i = 1; i < N; ++i)
+            srcX[i] = src[i][n];
+
+        // Take care of first two elements
+        dstX[0] = srcX[0] + srcX[1];
+        dstX[1] = srcX[0] - srcX[1];
+
+        unsigned idx = 0, dstIdx = 2;
+        for (unsigned i = 4; i < N; i <<= 1)
+        {
+            for (unsigned j = 0; j < (i >> 1); ++j)
+            {
+                dstX[dstIdx++] = dstX[idx + j] + srcX[idx + 2 + j];
+                dstX[dstIdx++] = dstX[idx + j] - srcX[idx + 2 + j];
+            }
+            idx += (i >> 1);
+        }
+
+        // Handle the last X elements
+        dstIdx = 0;
+        for (unsigned j = 0; j < (N >> 1); ++j)
+        {
+            src[dstIdx++][n] = (dstX[idx + j] + srcX[idx + 2 + j]) >> 1;
+            src[dstIdx++][n] = (dstX[idx + j] - srcX[idx + 2 + j]) >> 1;
+        }
+
+        delete[] srcX;
+        delete[] dstX;
+    }
+
+    /// 1D forward transformations of fixed array size: 2, 4, 8 and 16
+
+    template <typename T, typename DT, typename CT>
+    inline static void ForwardTransform2(BlockMatch<T, DT, CT> *z, const int &n)
+    {
+        T sum = (z[0][n] + z[1][n] + 1) >> 1;
+        T dif = z[0][n] - z[1][n];
+
+        z[0][n] = sum;
+        z[1][n] = dif;
+    }
+
+    template <typename T, typename DT, typename CT>
+    inline static void ForwardTransform4(BlockMatch<T, DT, CT> *z, const int &n)
+    {
+        T sum0 = (z[0][n] + z[1][n] + 1) >> 1;
+        T sum1 = (z[2][n] + z[3][n] + 1) >> 1;
+        T dif0 = z[0][n] - z[1][n];
+        T dif1 = z[2][n] - z[3][n];
+
+        T sum00 = (sum0 + sum1 + 1) >> 1;
+        T dif00 = sum0 - sum1;
+
+        z[0][n] = sum00;
+        z[1][n] = dif00;
+        z[2][n] = dif0;
+        z[3][n] = dif1;
+    }
+
+    template <typename T, typename DT, typename CT>
+    inline static void ForwardTransform8(BlockMatch<T, DT, CT> *z, const int &n)
+    {
+        T sum0 = (z[0][n] + z[1][n] + 1) >> 1;
+        T sum1 = (z[2][n] + z[3][n] + 1) >> 1;
+        T sum2 = (z[4][n] + z[5][n] + 1) >> 1;
+        T sum3 = (z[6][n] + z[7][n] + 1) >> 1;
+        T dif0 = z[0][n] - z[1][n];
+        T dif1 = z[2][n] - z[3][n];
+        T dif2 = z[4][n] - z[5][n];
+        T dif3 = z[6][n] - z[7][n];
+
+        T sum00 = (sum0 + sum1 + 1) >> 1;
+        T sum11 = (sum2 + sum3 + 1) >> 1;
+        T dif00 = sum0 - sum1;
+        T dif11 = sum2 - sum3;
+
+        T sum000 = (sum00 + sum11 + 1) >> 1;
+        T dif000 = sum00 - sum11;
+
+        z[0][n] = sum000;
+        z[1][n] = dif000;
+        z[2][n] = dif00;
+        z[3][n] = dif11;
+        z[4][n] = dif0;
+        z[5][n] = dif1;
+        z[6][n] = dif2;
+        z[7][n] = dif3;
+    }
+
+    template <typename T, typename DT, typename CT>
+    inline static void ForwardTransform16(BlockMatch<T, DT, CT> *z, const int &n)
+    {
+        T sum0 = (z[0][n] + z[1][n] + 1) >> 1;
+        T sum1 = (z[2][n] + z[3][n] + 1) >> 1;
+        T sum2 = (z[4][n] + z[5][n] + 1) >> 1;
+        T sum3 = (z[6][n] + z[7][n] + 1) >> 1;
+        T sum4 = (z[8][n] + z[9][n] + 1) >> 1;
+        T sum5 = (z[10][n] + z[11][n] + 1) >> 1;
+        T sum6 = (z[12][n] + z[13][n] + 1) >> 1;
+        T sum7 = (z[14][n] + z[15][n] + 1) >> 1;
+        T dif0 = z[0][n] - z[1][n];
+        T dif1 = z[2][n] - z[3][n];
+        T dif2 = z[4][n] - z[5][n];
+        T dif3 = z[6][n] - z[7][n];
+        T dif4 = z[8][n] - z[9][n];
+        T dif5 = z[10][n] - z[11][n];
+        T dif6 = z[12][n] - z[13][n];
+        T dif7 = z[14][n] - z[15][n];
+
+        T sum00 = (sum0 + sum1 + 1) >> 1;
+        T sum11 = (sum2 + sum3 + 1) >> 1;
+        T sum22 = (sum4 + sum5 + 1) >> 1;
+        T sum33 = (sum6 + sum7 + 1) >> 1;
+        T dif00 = sum0 - sum1;
+        T dif11 = sum2 - sum3;
+        T dif22 = sum4 - sum5;
+        T dif33 = sum6 - sum7;
+
+        T sum000 = (sum00 + sum11 + 1) >> 1;
+        T sum111 = (sum22 + sum33 + 1) >> 1;
+        T dif000 = sum00 - sum11;
+        T dif111 = sum22 - sum33;
+
+        T sum0000 = (sum000 + sum111 + 1) >> 1;
+        T dif0000 = dif000 - dif111;
+
+        z[0][n] = sum0000;
+        z[1][n] = dif0000;
+        z[2][n] = dif000;
+        z[3][n] = dif111;
+        z[4][n] = dif00;
+        z[5][n] = dif11;
+        z[6][n] = dif22;
+        z[7][n] = dif33;
+        z[8][n] = dif0;
+        z[9][n] = dif1;
+        z[10][n] = dif2;
+        z[11][n] = dif3;
+        z[12][n] = dif4;
+        z[13][n] = dif5;
+        z[14][n] = dif6;
+        z[15][n] = dif7;
+    }
+
+    /// 1D inverse transformations of fixed array size: 2, 4, 8 and 16
+
+    template <typename T, typename DT, typename CT>
+    inline static void InverseTransform2(BlockMatch<T, DT, CT> *src, const int &n)
+    {
+        T src0 = src[0][n] * 2;
+        T src1 = src[1][n];
+
+        src[0][n] = (src0 + src1) >> 1;
+        src[1][n] = (src0 - src1) >> 1;
+    }
+
+    template <typename T, typename DT, typename CT>
+    inline static void InverseTransform4(BlockMatch<T, DT, CT> *src, const int &n)
+    {
+        T src0 = src[0][n] * 2;
+        T src1 = src[1][n];
+        T src2 = src[2][n];
+        T src3 = src[3][n];
+
+        T sum0 = src0 + src1;
+        T dif0 = src0 - src1;
+
+        src[0][n] = (sum0 + src2) >> 1;
+        src[1][n] = (sum0 - src2) >> 1;
+        src[2][n] = (dif0 + src3) >> 1;
+        src[3][n] = (dif0 - src3) >> 1;
+    }
+
+    template <typename T, typename DT, typename CT>
+    inline static void InverseTransform8(BlockMatch<T, DT, CT> *src, const int &n)
+    {
+        T src0 = src[0][n] * 2;
+        T src1 = src[1][n];
+        T src2 = src[2][n];
+        T src3 = src[3][n];
+        T src4 = src[4][n];
+        T src5 = src[5][n];
+        T src6 = src[6][n];
+        T src7 = src[7][n];
+
+        T sum0 = src0 + src1;
+        T dif0 = src0 - src1;
+
+        T sum00 = sum0 + src2;
+        T dif00 = sum0 - src2;
+        T sum11 = dif0 + src3;
+        T dif11 = dif0 - src3;
+
+        src[0][n] = (sum00 + src4) >> 1;
+        src[1][n] = (sum00 - src4) >> 1;
+        src[2][n] = (dif00 + src5) >> 1;
+        src[3][n] = (dif00 - src5) >> 1;
+        src[4][n] = (sum11 + src6) >> 1;
+        src[5][n] = (sum11 - src6) >> 1;
+        src[6][n] = (dif11 + src7) >> 1;
+        src[7][n] = (dif11 - src7) >> 1;
+    }
+
+    template <typename T, typename DT, typename CT>
+    inline static void InverseTransform16(BlockMatch<T, DT, CT> *src, const int &n)
+    {
+        T src0 = src[0][n] * 2;
+        T src1 = src[1][n];
+        T src2 = src[2][n];
+        T src3 = src[3][n];
+        T src4 = src[4][n];
+        T src5 = src[5][n];
+        T src6 = src[6][n];
+        T src7 = src[7][n];
+        T src8 = src[8][n];
+        T src9 = src[9][n];
+        T src10 = src[10][n];
+        T src11 = src[11][n];
+        T src12 = src[12][n];
+        T src13 = src[13][n];
+        T src14 = src[14][n];
+        T src15 = src[15][n];
+
+        T sum0 = src0 + src1;
+        T dif0 = src0 - src1;
+
+        T sum00 = sum0 + src2;
+        T dif00 = sum0 - src2;
+        T sum11 = dif0 + src3;
+        T dif11 = dif0 - src3;
+
+        T sum000 = sum00 + src4;
+        T dif000 = sum00 - src4;
+        T sum111 = dif00 + src5;
+        T dif111 = dif00 - src5;
+        T sum222 = sum11 + src6;
+        T dif222 = sum11 - src6;
+        T sum333 = dif11 + src7;
+        T dif333 = dif11 - src7;
+
+        src[0][n] = (sum000 + src8) >> 1;
+        src[1][n] = (sum000 - src8) >> 1;
+        src[2][n] = (dif000 + src9) >> 1;
+        src[3][n] = (dif000 - src9) >> 1;
+        src[4][n] = (sum111 + src10) >> 1;
+        src[5][n] = (sum111 - src10) >> 1;
+        src[6][n] = (dif111 + src11) >> 1;
+        src[7][n] = (dif111 - src11) >> 1;
+        src[8][n] = (sum222 + src12) >> 1;
+        src[9][n] = (sum222 - src12) >> 1;
+        src[10][n] = (dif222 + src13) >> 1;
+        src[11][n] = (dif222 - src13) >> 1;
+        src[12][n] = (sum333 + src14) >> 1;
+        src[13][n] = (sum333 - src14) >> 1;
+        src[14][n] = (dif333 + src15) >> 1;
+        src[15][n] = (dif333 - src15) >> 1;
+    }
+};
+
+}  // namespace xphoto
+}  // namespace cv
+
+#endif
\ No newline at end of file
diff --git a/contrib/modules/xphoto/src/bm3d_denoising_transforms_2D.hpp b/contrib/modules/xphoto/src/bm3d_denoising_transforms_2D.hpp
new file mode 100644
index 0000000..f5ef915
--- /dev/null
+++ b/contrib/modules/xphoto/src/bm3d_denoising_transforms_2D.hpp
@@ -0,0 +1,511 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+//  By downloading, copying, installing or using the software you agree to this license.
+//  If you do not agree to this license, do not download, install,
+//  copy or use the software.
+//
+//
+//                        Intel License Agreement
+//                For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective icvers.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+//   * Redistribution's of source code must retain the above copyright notice,
+//     this list of conditions and the following disclaimer.
+//
+//   * Redistribution's in binary form must reproduce the above copyright notice,
+//     this list of conditions and the following disclaimer in the documentation
+//     and/or other materials provided with the distribution.
+//
+//   * The name of Intel Corporation may not be used to endorse or promote products
+//     derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#ifndef __OPENCV_BM3D_DENOISING_TRANSFORMS_2D_HPP__
+#define __OPENCV_BM3D_DENOISING_TRANSFORMS_2D_HPP__
+
+namespace cv
+{
+namespace xphoto
+{
+
+class HaarTransform2D
+{
+    template <int X>
+    static void CalculateIndices(unsigned *diffIndices, const unsigned &size)
+    {
+        unsigned diffIdx = 1;
+        unsigned diffAllIdx = 0;
+        for (unsigned i = 1; i <= X; i <<= 1)
+        {
+            diffAllIdx += (i >> 1);
+            for (unsigned j = 0; j < (i >> 1); ++j)
+                diffIndices[diffIdx++] = size - (--diffAllIdx);
+            diffAllIdx += i;
+        }
+    }
+
+public:
+    /// Transforms for 2D block of arbitrary size
+    template <typename T, typename TT, int X, int N>
+    inline static void ForwardTransformX(const T *src, TT *dst, const int &step)
+    {
+        const unsigned size = X + (X << 1) - 2;
+        TT dstX[size];
+
+        // Fill dstX with source values
+        for (unsigned i = 0; i < X; ++i)
+            dstX[i] = *(src + i * step);
+
+        unsigned idx = 0, dstIdx = X;
+        for (unsigned i = X; i > 1; i >>= 1)
+        {
+            // Get sums
+            for (unsigned j = 0; j < (i >> 1); ++j)
+                dstX[dstIdx++] = (dstX[idx + 2 * j] + dstX[idx + j * 2 + 1] + 1) >> 1;
+
+            // Get diffs
+            for (unsigned j = 0; j < (i >> 1); ++j)
+                dstX[dstIdx++] = dstX[idx + 2 * j] - dstX[idx + j * 2 + 1];
+
+            idx = dstIdx - i;
+        }
+
+        // Calculate indices in the destination matrix.
+        unsigned diffIndices[X];
+        CalculateIndices<X>(diffIndices, size);
+
+        // Fill in destination matrix
+        dst[0] = dstX[size - 2];
+        for (int i = 1; i < X; ++i)
+            dst[i * N] = dstX[diffIndices[i]];
+    }
+
+    template <typename T, typename TT, int X>
+    inline static void ForwardTransformXxX(const T *ptr, TT *dst, const int &step, const int /*blockSize*/)
+    {
+        TT temp[X * X];
+
+        // Transform columns first
+        for (unsigned i = 0; i < X; ++i)
+            ForwardTransformX<T, TT, X, X>(ptr + i, temp + i, step);
+
+        // Then transform rows
+        for (unsigned i = 0; i < X; ++i)
+            ForwardTransformX<TT, TT, X, 1>(temp + i * X, dst + i * X, 1);
+    }
+
+    template <typename T, int X, int N>
+    inline static void InverseTransformX(T *src, T *dst)
+    {
+        const unsigned dstSize = (X << 1) - 2;
+        T dstX[dstSize];
+        T srcX[X];
+
+        // Fill srcX with source values
+        srcX[0] = src[0] * 2;
+        for (int i = 1; i < X; ++i)
+            srcX[i] = src[i * N];
+
+        // Take care of first two elements
+        dstX[0] = srcX[0] + srcX[1];
+        dstX[1] = srcX[0] - srcX[1];
+
+        unsigned idx = 0, dstIdx = 2;
+        for (int i = 4; i < X; i <<= 1)
+        {
+            for (int j = 0; j < (i >> 1); ++j)
+            {
+                dstX[dstIdx++] = dstX[idx + j] + srcX[idx + 2 + j];
+                dstX[dstIdx++] = dstX[idx + j] - srcX[idx + 2 + j];
+            }
+            idx += (i >> 1);
+        }
+
+        // Handle the last X elements
+        dstIdx = 0;
+        for (int j = 0; j < (X >> 1); ++j)
+        {
+            dst[dstIdx++ * N] = (dstX[idx + j] + srcX[idx + 2 + j]) >> 1;
+            dst[dstIdx++ * N] = (dstX[idx + j] - srcX[idx + 2 + j]) >> 1;
+        }
+    }
+
+    template <typename T, int X>
+    inline static void InverseTransformXxX(T *src, const int /*blockSize*/)
+    {
+        T temp[X * X];
+
+        // Invert columns first
+        for (int i = 0; i < X; ++i)
+            InverseTransformX<T, X, X>(src + i, temp + i);
+
+        // Then invert rows
+        for (int i = 0; i < X; ++i)
+            InverseTransformX<T, X, 1>(temp + i * X, src + i * X);
+    }
+
+    // Same as above but X and N are arguments, not template parameters.
+
+    static void CalculateIndices(int *diffIndices, const int &size, const int &X)
+    {
+        int diffIdx = 1;
+        int diffAllIdx = 0;
+        for (int i = 1; i <= X; i <<= 1)
+        {
+            diffAllIdx += (i >> 1);
+            for (int j = 0; j < (i >> 1); ++j)
+                diffIndices[diffIdx++] = size - (--diffAllIdx);
+            diffAllIdx += i;
+        }
+    }
+
+    template <typename T, typename TT>
+    inline static void ForwardTransformX(const T *src, TT *dst, const int &step, const int &X, const int &N)
+    {
+        const int size = X + (X << 1) - 2;
+        TT *dstX = new TT[size];
+
+        // Fill dstX with source values
+        for (int i = 0; i < X; ++i)
+            dstX[i] = *(src + i * step);
+
+        int idx = 0, dstIdx = X;
+        for (int i = X; i > 1; i >>= 1)
+        {
+            // Get sums
+            for (int j = 0; j < (i >> 1); ++j)
+                dstX[dstIdx++] = (dstX[idx + 2 * j] + dstX[idx + j * 2 + 1] + 1) >> 1;
+
+            // Get diffs
+            for (int j = 0; j < (i >> 1); ++j)
+                dstX[dstIdx++] = dstX[idx + 2 * j] - dstX[idx + j * 2 + 1];
+
+            idx = dstIdx - i;
+        }
+
+        // Calculate indices in the destination matrix.
+        int *diffIndices = new int[X];
+        CalculateIndices(diffIndices, size, X);
+
+        // Fill in destination matrix
+        dst[0] = dstX[size - 2];
+        for (int i = 1; i < X; ++i)
+            dst[i * N] = dstX[diffIndices[i]];
+
+        delete[] diffIndices;
+        delete[] dstX;
+    }
+
+    template <typename T, typename TT>
+    inline static void ForwardTransformXxX(const T *ptr, TT *dst, const int &step, const int X)
+    {
+        TT *temp = new TT[X * X];
+
+        // Transform columns first
+        for (int i = 0; i < X; ++i)
+            ForwardTransformX<T, TT>(ptr + i, temp + i, step, X, X);
+
+        // Then transform rows
+        for (int i = 0; i < X; ++i)
+            ForwardTransformX<TT, TT>(temp + i * X, dst + i * X, 1, X, 1);
+
+        delete[] temp;
+    }
+
+    template <typename T>
+    inline static void InverseTransformX(T *src, T *dst, const int &X, const int &N)
+    {
+        const unsigned dstSize = (X << 1) - 2;
+        T *dstX = new T[dstSize];
+        T *srcX = new T[X];
+
+        // Fill srcX with source values
+        srcX[0] = src[0] * 2;
+        for (int i = 1; i < X; ++i)
+            srcX[i] = src[i * N];
+
+        // Take care of first two elements
+        dstX[0] = srcX[0] + srcX[1];
+        dstX[1] = srcX[0] - srcX[1];
+
+        unsigned idx = 0, dstIdx = 2;
+        for (int i = 4; i < X; i <<= 1)
+        {
+            for (int j = 0; j < (i >> 1); ++j)
+            {
+                dstX[dstIdx++] = dstX[idx + j] + srcX[idx + 2 + j];
+                dstX[dstIdx++] = dstX[idx + j] - srcX[idx + 2 + j];
+            }
+            idx += (i >> 1);
+        }
+
+        // Handle the last X elements
+        dstIdx = 0;
+        for (int j = 0; j < (X >> 1); ++j)
+        {
+            dst[dstIdx++ * N] = (dstX[idx + j] + srcX[idx + 2 + j]) >> 1;
+            dst[dstIdx++ * N] = (dstX[idx + j] - srcX[idx + 2 + j]) >> 1;
+        }
+
+        delete[] dstX;
+        delete[] srcX;
+    }
+
+    template <typename T>
+    inline static void InverseTransformXxX(T *src, const int X)
+    {
+        T *temp = new T[X * X];
+
+        // Invert columns first
+        for (int i = 0; i < X; ++i)
+            InverseTransformX<T>(src + i, temp + i, X, X);
+
+        // Then invert rows
+        for (int i = 0; i < X; ++i)
+            InverseTransformX<T>(temp + i * X, src + i * X, X, 1);
+
+        delete[] temp;
+    }
+
+    /// Transforms for 2x2 2D block
+
+    template <typename T, typename TT, int N>
+    inline static void ForwardTransform2(const T *src, TT *dst, const int &step)
+    {
+        const T *src0 = src;
+        const T *src1 = src + 1 * step;
+
+        dst[0 * N] = (*src0 + *src1 + 1) >> 1;
+        dst[1 * N] = *src0 - *src1;
+    }
+
+    template <typename T, typename TT>
+    inline static void ForwardTransform2x2(const T *ptr, TT *dst, const int &step, const int /*blockSize*/)
+    {
+        TT temp[4];
+
+        // Transform columns first
+        for (int i = 0; i < 2; ++i)
+            ForwardTransform2<T, TT, 2>(ptr + i, temp + i, step);
+
+        // Then transform rows
+        for (int i = 0; i < 2; ++i)
+            ForwardTransform2<TT, TT, 1>(temp + i * 2, dst + i * 2, 1);
+    }
+
+    template <typename TT, int N>
+    inline static void InverseTransform2(TT *src, TT *dst)
+    {
+        TT src0 = src[0 * N] * 2;
+        TT src1 = src[1 * N];
+
+        dst[0 * N] = (src0 + src1) >> 1;
+        dst[1 * N] = (src0 - src1) >> 1;
+    }
+
+    template <typename T>
+    inline static void InverseTransform2x2(T *src, const int /*blockSize*/)
+    {
+        T temp[4];
+
+        // Invert columns first
+        for (int i = 0; i < 2; ++i)
+            InverseTransform2<T, 2>(src + i, temp + i);
+
+        // Then invert rows
+        for (int i = 0; i < 2; ++i)
+            InverseTransform2<T, 1>(temp + i * 2, src + i * 2);
+    }
+
+    /// Transforms for 4x4 2D block
+
+    template <typename T, typename TT, int N>
+    inline static void ForwardTransform4(const T *src, TT *dst, const int &step)
+    {
+        const T *src0 = src;
+        const T *src1 = src + 1 * step;
+        const T *src2 = src + 2 * step;
+        const T *src3 = src + 3 * step;
+
+        TT sum0 = (*src0 + *src1 + 1) >> 1;
+        TT sum1 = (*src2 + *src3 + 1) >> 1;
+        TT dif0 = *src0 - *src1;
+        TT dif1 = *src2 - *src3;
+
+        TT sum00 = (sum0 + sum1 + 1) >> 1;
+        TT dif00 = sum0 - sum1;
+
+        dst[0 * N] = sum00;
+        dst[1 * N] = dif00;
+        dst[2 * N] = dif0;
+        dst[3 * N] = dif1;
+    }
+
+    template <typename T, typename TT>
+    inline static void ForwardTransform4x4(const T *ptr, TT *dst, const int &step, const int /*blockSize*/)
+    {
+        TT temp[16];
+
+        // Transform columns first
+        for (int i = 0; i < 4; ++i)
+            ForwardTransform4<T, TT, 4>(ptr + i, temp + i, step);
+
+        // Then transform rows
+        for (int i = 0; i < 4; ++i)
+            ForwardTransform4<TT, TT, 1>(temp + i * 4, dst + i * 4, 1);
+    }
+
+    template <typename TT, int N>
+    inline static void InverseTransform4(TT *src, TT *dst)
+    {
+        TT src0 = src[0 * N] * 2;
+        TT src1 = src[1 * N];
+        TT src2 = src[2 * N];
+        TT src3 = src[3 * N];
+
+        TT sum0 = src0 + src1;
+        TT dif0 = src0 - src1;
+
+        dst[0 * N] = (sum0 + src2) >> 1;
+        dst[1 * N] = (sum0 - src2) >> 1;
+        dst[2 * N] = (dif0 + src3) >> 1;
+        dst[3 * N] = (dif0 - src3) >> 1;
+    }
+
+    template <typename T>
+    inline static void InverseTransform4x4(T *src, const int /*blockSize*/)
+    {
+        T temp[16];
+
+        // Invert columns first
+        for (int i = 0; i < 4; ++i)
+            InverseTransform4<T, 4>(src + i, temp + i);
+
+        // Then invert rows
+        for (int i = 0; i < 4; ++i)
+            InverseTransform4<T, 1>(temp + i * 4, src + i * 4);
+    }
+
+    /// Transforms for 8x8 2D block
+
+    template <typename T, typename TT, int N>
+    inline static void ForwardTransform8(const T *src, TT *dst, const int &step)
+    {
+        const T *src0 = src;
+        const T *src1 = src + 1 * step;
+        const T *src2 = src + 2 * step;
+        const T *src3 = src + 3 * step;
+        const T *src4 = src + 4 * step;
+        const T *src5 = src + 5 * step;
+        const T *src6 = src + 6 * step;
+        const T *src7 = src + 7 * step;
+
+        TT sum0 = (*src0 + *src1 + 1) >> 1;
+        TT sum1 = (*src2 + *src3 + 1) >> 1;
+        TT sum2 = (*src4 + *src5 + 1) >> 1;
+        TT sum3 = (*src6 + *src7 + 1) >> 1;
+        TT dif0 = *src0 - *src1;
+        TT dif1 = *src2 - *src3;
+        TT dif2 = *src4 - *src5;
+        TT dif3 = *src6 - *src7;
+
+        TT sum00 = (sum0 + sum1 + 1) >> 1;
+        TT sum11 = (sum2 + sum3 + 1) >> 1;
+        TT dif00 = sum0 - sum1;
+        TT dif11 = sum2 - sum3;
+
+        TT sum000 = (sum00 + sum11 + 1) >> 1;
+        TT dif000 = sum00 - sum11;
+
+        dst[0 * N] = sum000;
+        dst[1 * N] = dif000;
+        dst[2 * N] = dif00;
+        dst[3 * N] = dif11;
+        dst[4 * N] = dif0;
+        dst[5 * N] = dif1;
+        dst[6 * N] = dif2;
+        dst[7 * N] = dif3;
+    }
+
+    template <typename T, typename TT>
+    inline static void ForwardTransform8x8(const T *ptr, TT *dst, const int &step, const int /*blockSize*/)
+    {
+        TT temp[64];
+
+        // Transform columns first
+        for (int i = 0; i < 8; ++i)
+            ForwardTransform8<T, TT, 8>(ptr + i, temp + i, step);
+
+        // Then transform rows
+        for (int i = 0; i < 8; ++i)
+            ForwardTransform8<TT, TT, 1>(temp + i * 8, dst + i * 8, 1);
+    }
+
+    template <typename T, int N>
+    inline static void InverseTransform8(T *src, T *dst)
+    {
+        T src0 = src[0] * 2;
+        T src1 = src[1 * N];
+        T src2 = src[2 * N];
+        T src3 = src[3 * N];
+        T src4 = src[4 * N];
+        T src5 = src[5 * N];
+        T src6 = src[6 * N];
+        T src7 = src[7 * N];
+
+        T sum0 = src0 + src1;
+        T dif0 = src0 - src1;
+
+        T sum00 = sum0 + src2;
+        T dif00 = sum0 - src2;
+        T sum11 = dif0 + src3;
+        T dif11 = dif0 - src3;
+
+        dst[0 * N] = (sum00 + src4) >> 1;
+        dst[1 * N] = (sum00 - src4) >> 1;
+        dst[2 * N] = (dif00 + src5) >> 1;
+        dst[3 * N] = (dif00 - src5) >> 1;
+        dst[4 * N] = (sum11 + src6) >> 1;
+        dst[5 * N] = (sum11 - src6) >> 1;
+        dst[6 * N] = (dif11 + src7) >> 1;
+        dst[7 * N] = (dif11 - src7) >> 1;
+    }
+
+    template <typename T>
+    inline static void InverseTransform8x8(T *src, const int /*blockSize*/)
+    {
+        T temp[64];
+
+        // Invert columns first
+        for (int i = 0; i < 8; ++i)
+            InverseTransform8<T, 8>(src + i, temp + i);
+
+        // Then invert rows
+        for (int i = 0; i < 8; ++i)
+            InverseTransform8<T, 1>(temp + i * 8, src + i * 8);
+    }
+};
+
+}  // namespace xphoto
+}  // namespace cv
+
+#endif
\ No newline at end of file
diff --git a/contrib/modules/xphoto/src/bm3d_denoising_transforms_haar.hpp b/contrib/modules/xphoto/src/bm3d_denoising_transforms_haar.hpp
new file mode 100644
index 0000000..489b2ae
--- /dev/null
+++ b/contrib/modules/xphoto/src/bm3d_denoising_transforms_haar.hpp
@@ -0,0 +1,290 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+//  By downloading, copying, installing or using the software you agree to this license.
+//  If you do not agree to this license, do not download, install,
+//  copy or use the software.
+//
+//
+//                        Intel License Agreement
+//                For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective icvers.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+//   * Redistribution's of source code must retain the above copyright notice,
+//     this list of conditions and the following disclaimer.
+//
+//   * Redistribution's in binary form must reproduce the above copyright notice,
+//     this list of conditions and the following disclaimer in the documentation
+//     and/or other materials provided with the distribution.
+//
+//   * The name of Intel Corporation may not be used to endorse or promote products
+//     derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#ifndef __OPENCV_BM3D_DENOISING_TRANSFORMS_HAAR_HPP__
+#define __OPENCV_BM3D_DENOISING_TRANSFORMS_HAAR_HPP__
+
+#include "bm3d_denoising_transforms_1D.hpp"
+#include "bm3d_denoising_transforms_2D.hpp"
+
+namespace cv
+{
+namespace xphoto
+{
+
+// Forward declaration
+template <typename T, typename TT>
+class Transform;
+
+template <typename T, typename TT>
+class HaarTransform
+{
+    static void calcCoefficients1D(cv::Mat &coeff1D, const int &numberOfElements)
+    {
+        // Generate base array and initialize with zeros
+        cv::Mat baseArr = cv::Mat::zeros(numberOfElements, numberOfElements, CV_32FC1);
+
+        // Calculate base array coefficients.
+        int currentRow = 0;
+        for (int i = numberOfElements; i > 0; i /= 2)
+        {
+            for (int k = 0, sign = -1; k < numberOfElements; ++k)
+            {
+                // Alternate sign every i-th element
+                if (k % i == 0)
+                    sign *= -1;
+
+                // Move to the next row every 2*i-th element
+                if (k != 0 && (k % (2 * i) == 0))
+                    ++currentRow;
+
+                baseArr.at<float>(currentRow, k) = sign * 1.0f / i;
+            }
+            ++currentRow;
+        }
+
+        // Square each elements of the base array
+        float *ptr = baseArr.ptr<float>(0);
+        for (unsigned i = 0; i < baseArr.total(); ++i)
+            ptr[i] = ptr[i] * ptr[i];
+
+        // Multiply baseArray with 1D vector of ones
+        cv::Mat unitaryArr = cv::Mat::ones(numberOfElements, 1, CV_32FC1);
+        coeff1D = baseArr * unitaryArr;
+    }
+
+    // Method to generate threshold coefficients for 1D transform depending on the number of elements.
+    static void fillHaarCoefficients1D(float *thrCoeff1D, int &idx, const int &numberOfElements)
+    {
+        cv::Mat coeff1D;
+        calcCoefficients1D(coeff1D, numberOfElements);
+
+        // Square root the array to get standard deviation
+        float *ptr = coeff1D.ptr<float>(0);
+        for (unsigned i = 0; i < coeff1D.total(); ++i)
+        {
+            ptr[i] = std::sqrt(ptr[i]);
+            thrCoeff1D[idx++] = ptr[i];
+        }
+    }
+
+    // Method to generate threshold coefficients for 2D transform depending on the number of elements.
+    static void fillHaarCoefficients2D(float *thrCoeff2D, const int &templateWindowSize)
+    {
+        cv::Mat coeff1D;
+        calcCoefficients1D(coeff1D, templateWindowSize);
+
+        // Calculate 2D array
+        cv::Mat coeff1Dt;
+        cv::transpose(coeff1D, coeff1Dt);
+        cv::Mat coeff2D = coeff1D * coeff1Dt;
+
+        // Square root the array to get standard deviation
+        float *ptr = coeff2D.ptr<float>(0);
+        for (unsigned i = 0; i < coeff2D.total(); ++i)
+            thrCoeff2D[i] = std::sqrt(ptr[i]);
+    }
+
+public:
+    // Method to calculate 1D threshold map based on the maximum number of elements
+    // Allocates memory for the output array.
+    static void calcThresholdMap1D(float *&thrMap1D, const int &numberOfElements)
+    {
+        CV_Assert(numberOfElements > 0);
+
+        // Allocate memory for the array
+        const int arrSize = (numberOfElements << 1) - 1;
+        if (thrMap1D == NULL)
+            thrMap1D = new float[arrSize];
+
+        for (int i = 1, idx = 0; i <= numberOfElements; i *= 2)
+            fillHaarCoefficients1D(thrMap1D, idx, i);
+    }
+
+    // Method to calculate 2D threshold map based on the maximum number of elements
+    // Allocates memory for the output array.
+    static void calcThresholdMap2D(float *&thrMap2D, const int &templateWindowSize)
+    {
+        // Allocate memory for the array
+        if (thrMap2D == NULL)
+            thrMap2D = new float[templateWindowSize * templateWindowSize];
+
+        fillHaarCoefficients2D(thrMap2D, templateWindowSize);
+    }
+
+    // Method to calculate 3D threshold map based on the maximum number of elements.
+    // Allocates memory for the output array.
+    static void calcThresholdMap3D(
+        TT *&outThrMap1D,
+        const float &hardThr1D,
+        const int &templateWindowSize,
+        const int &groupSize)
+    {
+        const int templateWindowSizeSq = templateWindowSize * templateWindowSize;
+
+        // Allocate memory for the output array
+        if (outThrMap1D == NULL)
+            outThrMap1D = new TT[templateWindowSizeSq * ((groupSize << 1) - 1)];
+
+        // Generate 1D coefficients map
+        float *thrMap1D = NULL;
+        calcThresholdMap1D(thrMap1D, groupSize);
+
+        // Generate 2D coefficients map
+        float *thrMap2D = NULL;
+        calcThresholdMap2D(thrMap2D, templateWindowSize);
+
+        // Generate 3D threshold map
+        TT *thrMapPtr1D = outThrMap1D;
+        for (int i = 1, ii = 0; i <= groupSize; ++ii, i *= 2)
+        {
+            float coeff = (i == 1) ? 1.0f : std::sqrt(2.0f * std::log((float)i));
+            for (int jj = 0; jj < templateWindowSizeSq; ++jj)
+            {
+                for (int ii1 = 0; ii1 < (1 << ii); ++ii1)
+                {
+                    int indexIn1D = (1 << ii) - 1 + ii1;
+                    int indexIn2D = jj;
+                    int thr = static_cast<int>(thrMap1D[indexIn1D] * thrMap2D[indexIn2D] * hardThr1D * coeff);
+
+                    // Set DC component to zero
+                    if (jj == 0 && ii1 == 0)
+                        thr = 0;
+
+                    *thrMapPtr1D++ = cv::saturate_cast<TT>(thr);
+                }
+            }
+        }
+
+        delete[] thrMap1D;
+        delete[] thrMap2D;
+    }
+
+    // Method that registers 2D transform calls
+    static void RegisterTransforms2D(const int &templateWindowSize)
+    {
+        // Check if template window size is a power of two
+        if (!isPowerOf2(templateWindowSize))
+            CV_Error(Error::StsBadArg, "Unsupported template size! Template size must be power of two!");
+
+        switch (templateWindowSize)
+        {
+        case 2:
+            forwardTransform2D = HaarTransform2D::ForwardTransform2x2<T, TT>;
+            inverseTransform2D = HaarTransform2D::InverseTransform2x2<TT>;
+            break;
+        case 4:
+            forwardTransform2D = HaarTransform2D::ForwardTransform4x4<T, TT>;
+            inverseTransform2D = HaarTransform2D::InverseTransform4x4<TT>;
+            break;
+        case 8:
+            forwardTransform2D = HaarTransform2D::ForwardTransform8x8<T, TT>;
+            inverseTransform2D = HaarTransform2D::InverseTransform8x8<TT>;
+            break;
+        case 16:
+            forwardTransform2D = HaarTransform2D::ForwardTransformXxX<T, TT, 16>;
+            inverseTransform2D = HaarTransform2D::InverseTransformXxX<TT, 16>;
+            break;
+        case 32:
+            forwardTransform2D = HaarTransform2D::ForwardTransformXxX<T, TT, 32>;
+            inverseTransform2D = HaarTransform2D::InverseTransformXxX<TT, 32>;
+            break;
+        case 64:
+            forwardTransform2D = HaarTransform2D::ForwardTransformXxX<T, TT, 64>;
+            inverseTransform2D = HaarTransform2D::InverseTransformXxX<TT, 64>;
+            break;
+        default:
+            forwardTransform2D = HaarTransform2D::ForwardTransformXxX<T, TT>;
+            inverseTransform2D = HaarTransform2D::InverseTransformXxX<TT>;
+        }
+    }
+
+    // 2D transform pointers
+    static typename Transform<T, TT>::Forward2D forwardTransform2D;
+    static typename Transform<T, TT>::Inverse2D inverseTransform2D;
+
+    // 1D transform pointers
+    static typename Transform<T, TT>::Forward1D forwardTransformN;
+    static typename Transform<T, TT>::Inverse1D inverseTransformN;
+
+    // Specialized 1D forward transform pointers
+    static typename Transform<T, TT>::Forward1Ds forwardTransform2;
+    static typename Transform<T, TT>::Forward1Ds forwardTransform4;
+    static typename Transform<T, TT>::Forward1Ds forwardTransform8;
+    static typename Transform<T, TT>::Forward1Ds forwardTransform16;
+
+    // Specialized 1D inverse transform pointers
+    static typename Transform<T, TT>::Inverse1Ds inverseTransform2;
+    static typename Transform<T, TT>::Inverse1Ds inverseTransform4;
+    static typename Transform<T, TT>::Inverse1Ds inverseTransform8;
+    static typename Transform<T, TT>::Inverse1Ds inverseTransform16;
+};
+
+/// Explicit static members initialization
+
+#define INITIALIZE_HAAR_TRANSFORM(type, member, value)              \
+template <typename T, typename TT>                                  \
+typename Transform<T, TT>::type HaarTransform<T, TT>::member = value;
+
+// 2D transforms
+INITIALIZE_HAAR_TRANSFORM(Forward2D, forwardTransform2D, NULL)
+INITIALIZE_HAAR_TRANSFORM(Inverse2D, inverseTransform2D, NULL)
+
+// 1D transforms
+INITIALIZE_HAAR_TRANSFORM(Forward1D, forwardTransformN, HaarTransform1D::ForwardTransformN)
+INITIALIZE_HAAR_TRANSFORM(Inverse1D, inverseTransformN, HaarTransform1D::InverseTransformN)
+
+// Specialized 1D forward transforms
+INITIALIZE_HAAR_TRANSFORM(Forward1Ds, forwardTransform2, HaarTransform1D::ForwardTransform2)
+INITIALIZE_HAAR_TRANSFORM(Forward1Ds, forwardTransform4, HaarTransform1D::ForwardTransform4)
+INITIALIZE_HAAR_TRANSFORM(Forward1Ds, forwardTransform8, HaarTransform1D::ForwardTransform8)
+INITIALIZE_HAAR_TRANSFORM(Forward1Ds, forwardTransform16, HaarTransform1D::ForwardTransform16)
+
+// Specialized 1D inverse transforms
+INITIALIZE_HAAR_TRANSFORM(Inverse1Ds, inverseTransform2, HaarTransform1D::InverseTransform2)
+INITIALIZE_HAAR_TRANSFORM(Inverse1Ds, inverseTransform4, HaarTransform1D::InverseTransform4)
+INITIALIZE_HAAR_TRANSFORM(Inverse1Ds, inverseTransform8, HaarTransform1D::InverseTransform8)
+INITIALIZE_HAAR_TRANSFORM(Inverse1Ds, inverseTransform16, HaarTransform1D::InverseTransform16)
+
+}  // namespace xphoto
+}  // namespace cv
+
+#endif
\ No newline at end of file
diff --git a/contrib/modules/xphoto/src/bm3d_image_denoising.cpp b/contrib/modules/xphoto/src/bm3d_image_denoising.cpp
new file mode 100644
index 0000000..0145094
--- /dev/null
+++ b/contrib/modules/xphoto/src/bm3d_image_denoising.cpp
@@ -0,0 +1,347 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+//  By downloading, copying, installing or using the software you agree to this license.
+//  If you do not agree to this license, do not download, install,
+//  copy or use the software.
+//
+//
+//                        Intel License Agreement
+//                For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective icvers.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+//   * Redistribution's of source code must retain the above copyright notice,
+//     this list of conditions and the following disclaimer.
+//
+//   * Redistribution's in binary form must reproduce the above copyright notice,
+//     this list of conditions and the following disclaimer in the documentation
+//     and/or other materials provided with the distribution.
+//
+//   * The name of Intel Corporation may not be used to endorse or promote products
+//     derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "opencv2/xphoto.hpp"
+#include "opencv2/core.hpp"
+
+#ifdef OPENCV_ENABLE_NONFREE
+
+#include "bm3d_denoising_invoker_step1.hpp"
+#include "bm3d_denoising_invoker_step2.hpp"
+#include "bm3d_denoising_transforms.hpp"
+
+#endif
+
+namespace cv
+{
+namespace xphoto
+{
+
+#ifdef OPENCV_ENABLE_NONFREE
+
+template<typename ST, typename D, typename TT>
+static void bm3dDenoising_(
+    const Mat& src,
+    Mat& basic,
+    Mat& dst,
+    const float& h,
+    const int &templateWindowSize,
+    const int &searchWindowSize,
+    const int &hBMStep1,
+    const int &hBMStep2,
+    const int &groupSize,
+    const int &slidingStep,
+    const float &beta,
+    const int &step)
+{
+    double granularity = (double)std::max(1., (double)src.total() / (1 << 16));
+
+    switch (CV_MAT_CN(src.type())) {
+    case 1:
+        if (step == BM3D_STEP1 || step == BM3D_STEPALL)
+        {
+            parallel_for_(cv::Range(0, src.rows),
+                Bm3dDenoisingInvokerStep1<ST, D, float, TT, HaarTransform<ST, TT> >(
+                    src,
+                    basic,
+                    templateWindowSize,
+                    searchWindowSize,
+                    h,
+                    hBMStep1,
+                    groupSize,
+                    slidingStep,
+                    beta),
+                granularity);
+        }
+        if (step == BM3D_STEP2 || step == BM3D_STEPALL)
+        {
+            parallel_for_(cv::Range(0, src.rows),
+                Bm3dDenoisingInvokerStep2<ST, D, float, TT, HaarTransform<ST, TT> >(
+                    src,
+                    basic,
+                    dst,
+                    templateWindowSize,
+                    searchWindowSize,
+                    h,
+                    hBMStep2,
+                    groupSize,
+                    slidingStep,
+                    beta),
+                granularity);
+        }
+        break;
+    default:
+        CV_Error(Error::StsBadArg,
+            "Unsupported number of channels! Only 1 channel is supported at the moment.");
+    }
+}
+
+void bm3dDenoising(
+    InputArray _src,
+    InputOutputArray _basic,
+    OutputArray _dst,
+    float h,
+    int templateWindowSize,
+    int searchWindowSize,
+    int blockMatchingStep1,
+    int blockMatchingStep2,
+    int groupSize,
+    int slidingStep,
+    float beta,
+    int normType,
+    int step,
+    int transformType)
+{
+    int type = _src.type(), depth = CV_MAT_DEPTH(type), cn = CV_MAT_CN(type);
+    CV_Assert(1 == cn);
+    CV_Assert(HAAR == transformType);
+    CV_Assert(searchWindowSize > templateWindowSize);
+    CV_Assert(slidingStep > 0 && slidingStep < templateWindowSize);
+
+    Size srcSize = _src.size();
+
+    switch (step)
+    {
+    case BM3D_STEP1:
+        _basic.create(srcSize, type);
+        break;
+    case BM3D_STEP2:
+        CV_Assert(type == _basic.type());
+        _dst.create(srcSize, type);
+        break;
+    case BM3D_STEPALL:
+        _dst.create(srcSize, type);
+        break;
+    default:
+        CV_Error(Error::StsBadArg, "Unsupported BM3D step!");
+    }
+
+    Mat src = _src.getMat();
+    Mat basic = _basic.getMat().empty() ? Mat(srcSize, type) : _basic.getMat();
+    Mat dst = _dst.getMat();
+
+    switch (normType) {
+    case cv::NORM_L2:
+        switch (depth) {
+        case CV_8U:
+            bm3dDenoising_<uchar, DistSquared, short>(
+                src,
+                basic,
+                dst,
+                h,
+                templateWindowSize,
+                searchWindowSize,
+                blockMatchingStep1,
+                blockMatchingStep2,
+                groupSize,
+                slidingStep,
+                beta,
+                step);
+            break;
+        default:
+            CV_Error(Error::StsBadArg,
+                "Unsupported depth! Only CV_8U is supported for NORM_L2");
+        }
+        break;
+    case cv::NORM_L1:
+        switch (depth) {
+        case CV_8U:
+            bm3dDenoising_<uchar, DistAbs, short>(
+                src,
+                basic,
+                dst,
+                h,
+                templateWindowSize,
+                searchWindowSize,
+                blockMatchingStep1,
+                blockMatchingStep2,
+                groupSize,
+                slidingStep,
+                beta,
+                step);
+            break;
+        case CV_16U:
+            bm3dDenoising_<ushort, DistAbs, int>(
+                src,
+                basic,
+                dst,
+                h,
+                templateWindowSize,
+                searchWindowSize,
+                blockMatchingStep1,
+                blockMatchingStep2,
+                groupSize,
+                slidingStep,
+                beta,
+                step);
+            break;
+        default:
+            CV_Error(Error::StsBadArg,
+                "Unsupported depth! Only CV_8U and CV_16U are supported for NORM_L1");
+        }
+        break;
+    default:
+        CV_Error(Error::StsBadArg,
+            "Unsupported norm type! Only NORM_L2 and NORM_L1 are supported");
+    }
+}
+
+void bm3dDenoising(
+    InputArray _src,
+    OutputArray _dst,
+    float h,
+    int templateWindowSize,
+    int searchWindowSize,
+    int blockMatchingStep1,
+    int blockMatchingStep2,
+    int groupSize,
+    int slidingStep,
+    float beta,
+    int normType,
+    int step,
+    int transformType)
+{
+    if (step == BM3D_STEP2)
+        CV_Error(Error::StsBadArg,
+            "Unsupported step type! To use BM3D_STEP2 one need to provide basic image.");
+
+    Mat basic;
+
+    bm3dDenoising(
+        _src,
+        basic,
+        _dst,
+        h,
+        templateWindowSize,
+        searchWindowSize,
+        blockMatchingStep1,
+        blockMatchingStep2,
+        groupSize,
+        slidingStep,
+        beta,
+        normType,
+        step,
+        transformType);
+
+    if (step == BM3D_STEP1)
+        _dst.assign(basic);
+}
+
+#else
+
+void bm3dDenoising(
+    InputArray _src,
+    InputOutputArray _basic,
+    OutputArray _dst,
+    float h,
+    int templateWindowSize,
+    int searchWindowSize,
+    int blockMatchingStep1,
+    int blockMatchingStep2,
+    int groupSize,
+    int slidingStep,
+    float beta,
+    int normType,
+    int step,
+    int transformType)
+{
+    // Empty implementation
+
+    CV_UNUSED(_src);
+    CV_UNUSED(_basic);
+    CV_UNUSED(_dst);
+    CV_UNUSED(h);
+    CV_UNUSED(templateWindowSize);
+    CV_UNUSED(searchWindowSize);
+    CV_UNUSED(blockMatchingStep1);
+    CV_UNUSED(blockMatchingStep2);
+    CV_UNUSED(groupSize);
+    CV_UNUSED(slidingStep);
+    CV_UNUSED(beta);
+    CV_UNUSED(normType);
+    CV_UNUSED(step);
+    CV_UNUSED(transformType);
+
+    CV_Error(Error::StsNotImplemented,
+        "This algorithm is patented and is excluded in this configuration;"
+        "Set OPENCV_ENABLE_NONFREE CMake option and rebuild the library");
+}
+
+void bm3dDenoising(
+    InputArray _src,
+    OutputArray _dst,
+    float h,
+    int templateWindowSize,
+    int searchWindowSize,
+    int blockMatchingStep1,
+    int blockMatchingStep2,
+    int groupSize,
+    int slidingStep,
+    float beta,
+    int normType,
+    int step,
+    int transformType)
+{
+    // Empty implementation
+
+    CV_UNUSED(_src);
+    CV_UNUSED(_dst);
+    CV_UNUSED(h);
+    CV_UNUSED(templateWindowSize);
+    CV_UNUSED(searchWindowSize);
+    CV_UNUSED(blockMatchingStep1);
+    CV_UNUSED(blockMatchingStep2);
+    CV_UNUSED(groupSize);
+    CV_UNUSED(slidingStep);
+    CV_UNUSED(beta);
+    CV_UNUSED(normType);
+    CV_UNUSED(step);
+    CV_UNUSED(transformType);
+
+    CV_Error(Error::StsNotImplemented,
+        "This algorithm is patented and is excluded in this configuration;"
+        "Set OPENCV_ENABLE_NONFREE CMake option and rebuild the library");
+}
+
+#endif
+
+}  // namespace xphoto
+}  // namespace cv
\ No newline at end of file
diff --git a/contrib/modules/xphoto/src/grayworld_white_balance.cpp b/contrib/modules/xphoto/src/grayworld_white_balance.cpp
index 15530d3..9d38c26 100644
--- a/contrib/modules/xphoto/src/grayworld_white_balance.cpp
+++ b/contrib/modules/xphoto/src/grayworld_white_balance.cpp
@@ -37,177 +37,314 @@
 //
 //M*/
 
-#include "opencv2/xphoto.hpp"
-
 #include "opencv2/core.hpp"
 #include "opencv2/core/hal/intrin.hpp"
+#include "opencv2/xphoto.hpp"
 
-namespace cv { namespace xphoto {
+namespace cv
+{
+namespace xphoto
+{
 
-    void autowbGrayworld(InputArray _src, OutputArray _dst, float thresh)
-    {
+void calculateChannelSums(uint &sumB, uint &sumG, uint &sumR, uchar *src_data, int src_len, float thresh);
+void calculateChannelSums(uint64 &sumB, uint64 &sumG, uint64 &sumR, ushort *src_data, int src_len, float thresh);
+
+class GrayworldWBImpl : public GrayworldWB
+{
+  private:
+    float thresh;
 
+  public:
+    GrayworldWBImpl() { thresh = 0.9f; }
+    float getSaturationThreshold() const { return thresh; }
+    void setSaturationThreshold(float val) { thresh = val; }
+    void balanceWhite(InputArray _src, OutputArray _dst)
+    {
+        CV_Assert(!_src.empty());
+        CV_Assert(_src.isContinuous());
+        CV_Assert(_src.type() == CV_8UC3 || _src.type() == CV_16UC3);
         Mat src = _src.getMat();
-        CV_Assert(!src.empty());
-        CV_Assert(src.isContinuous());
-
-        // TODO: Handle CV_8UC1
-        // TODO: Handle types other than CV_8U
-        CV_Assert(src.type() == CV_8UC3);
-
-        _dst.create(src.size(), src.type());
-        Mat dst = _dst.getMat();
-        CV_Assert(dst.isContinuous());
-
-        int width  = src.cols,
-            height = src.rows,
-            N      = width*height,
-            N3     = N*3;
-
-        // Calculate sum of pixel values of each channel
-        const uchar* src_data = src.ptr<uchar>(0);
-        unsigned long sum1 = 0, sum2 = 0, sum3 = 0;
-        unsigned int thresh255 = cvRound(thresh * 255);
-        int i = 0;
-#if CV_SIMD128
-        v_uint8x16 v_inB, v_inG, v_inR;
-        v_uint16x8 v_s1, v_s2;
-        v_uint32x4 v_iB1, v_iB2, v_iB3, v_iB4,
-                   v_iG1, v_iG2, v_iG3, v_iG4,
-                   v_iR1, v_iR2, v_iR3, v_iR4,
-                   v_255 = v_setall_u32(255),
-                   v_thresh = v_setall_u32(thresh255),
-                   v_min1, v_min2, v_min3, v_min4,
-                   v_max1, v_max2, v_max3, v_max4,
-                   v_m1, v_m2, v_m3, v_m4,
-                   v_SB = v_setzero_u32(),
-                   v_SG = v_setzero_u32(),
-                   v_SR = v_setzero_u32();
-
-        for ( ; i < N3 - 47; i += 48 )
-        {
-            // NOTE: This block assumes BGR channels in naming variables
 
-            // Load 3x uint8x16 and deinterleave into vectors of each channel
-            v_load_deinterleave(&src_data[i], v_inB, v_inG, v_inR);
+        int N = src.cols * src.rows, N3 = N * 3;
 
-            // Split into four int vectors per channel
-            v_expand(v_inB, v_s1, v_s2);
-            v_expand(v_s1, v_iB1, v_iB2);
-            v_expand(v_s2, v_iB3, v_iB4);
-
-            v_expand(v_inG, v_s1, v_s2);
-            v_expand(v_s1, v_iG1, v_iG2);
-            v_expand(v_s2, v_iG3, v_iG4);
-
-            v_expand(v_inR, v_s1, v_s2);
-            v_expand(v_s1, v_iR1, v_iR2);
-            v_expand(v_s2, v_iR3, v_iR4);
-
-            // Get mins and maxs
-            v_min1 = v_min(v_iB1, v_min(v_iG1, v_iR1));
-            v_min2 = v_min(v_iB2, v_min(v_iG2, v_iR2));
-            v_min3 = v_min(v_iB3, v_min(v_iG3, v_iR3));
-            v_min4 = v_min(v_iB4, v_min(v_iG4, v_iR4));
-
-            v_max1 = v_max(v_iB1, v_max(v_iG1, v_iR1));
-            v_max2 = v_max(v_iB2, v_max(v_iG2, v_iR2));
-            v_max3 = v_max(v_iB3, v_max(v_iG3, v_iR3));
-            v_max4 = v_max(v_iB4, v_max(v_iG4, v_iR4));
-
-            // Calculate masks
-            v_m1 = ~((v_max1 - v_min1) * v_255 > v_thresh * v_max1);
-            v_m2 = ~((v_max2 - v_min2) * v_255 > v_thresh * v_max2);
-            v_m3 = ~((v_max3 - v_min3) * v_255 > v_thresh * v_max3);
-            v_m4 = ~((v_max4 - v_min4) * v_255 > v_thresh * v_max4);
-
-            // Apply mask
-            v_SB += (v_iB1 & v_m1) + (v_iB2 & v_m2) + (v_iB3 & v_m3) + (v_iB4 & v_m4);
-            v_SG += (v_iG1 & v_m1) + (v_iG2 & v_m2) + (v_iG3 & v_m3) + (v_iG4 & v_m4);
-            v_SR += (v_iR1 & v_m1) + (v_iR2 & v_m2) + (v_iR3 & v_m3) + (v_iR4 & v_m4);
+        double dsumB = 0.0, dsumG = 0.0, dsumR = 0.0;
+        if (src.type() == CV_8UC3)
+        {
+            uint sumB = 0, sumG = 0, sumR = 0;
+            calculateChannelSums(sumB, sumG, sumR, src.ptr<uchar>(), N3, thresh);
+            dsumB = (double)sumB;
+            dsumG = (double)sumG;
+            dsumR = (double)sumR;
         }
-
-        // Perform final reduction
-        sum1 = v_reduce_sum(v_SB);
-        sum2 = v_reduce_sum(v_SG);
-        sum3 = v_reduce_sum(v_SR);
-#endif
-        unsigned int minRGB, maxRGB;
-        for ( ; i < N3; i += 3 )
+        else if (src.type() == CV_16UC3)
         {
-            minRGB = min(src_data[i], min(src_data[i + 1], src_data[i + 2]));
-            maxRGB = max(src_data[i], max(src_data[i + 1], src_data[i + 2]));
-            if ( (maxRGB - minRGB) * 255 > thresh255 * maxRGB ) continue;
-            sum1 += src_data[i];
-            sum2 += src_data[i + 1];
-            sum3 += src_data[i + 2];
+            uint64 sumB = 0, sumG = 0, sumR = 0;
+            calculateChannelSums(sumB, sumG, sumR, src.ptr<ushort>(), N3, thresh);
+            dsumB = (double)sumB;
+            dsumG = (double)sumG;
+            dsumR = (double)sumR;
         }
 
         // Find inverse of averages
-        double dinv1 = sum1 == 0 ? 0.f : (double)N / (double)sum1,
-               dinv2 = sum2 == 0 ? 0.f : (double)N / (double)sum2,
-               dinv3 = sum3 == 0 ? 0.f : (double)N / (double)sum3;
+        double max_sum = max(dsumB, max(dsumR, dsumG));
+        const double eps = 0.1;
+        float dinvB = dsumB < eps ? 0.f : (float)(max_sum / dsumB),
+              dinvG = dsumG < eps ? 0.f : (float)(max_sum / dsumG),
+              dinvR = dsumR < eps ? 0.f : (float)(max_sum / dsumR);
 
-        // Find maximum
-        double inv_max = max(dinv1, max(dinv2, dinv3));
+        // Use the inverse of averages as channel gains:
+        applyChannelGains(src, _dst, dinvB, dinvG, dinvR);
+    }
+};
 
-        // Convert to floats
-        float inv1 = (float) dinv1,
-              inv2 = (float) dinv2,
-              inv3 = (float) dinv3;
+/* Computes sums for each channel, while ignoring saturated pixels which are determined by thresh
+ * (version for CV_8UC3)
+ */
+void calculateChannelSums(uint &sumB, uint &sumG, uint &sumR, uchar *src_data, int src_len, float thresh)
+{
+    sumB = sumG = sumR = 0;
+    ushort thresh255 = (ushort)cvRound(thresh * 255);
+    int i = 0;
+#if CV_SIMD128
+    v_uint8x16 v_inB, v_inG, v_inR, v_min_val, v_max_val;
+    v_uint16x8 v_iB1, v_iB2, v_iG1, v_iG2, v_iR1, v_iR2;
+    v_uint16x8 v_min1, v_min2, v_max1, v_max2, v_m1, v_m2;
+    v_uint16x8 v_255 = v_setall_u16(255), v_thresh = v_setall_u16(thresh255);
+    v_uint32x4 v_uint1, v_uint2;
+    v_uint32x4 v_SB = v_setzero_u32(), v_SG = v_setzero_u32(), v_SR = v_setzero_u32();
 
-        // Scale by maximum
-        if ( inv_max > 0 )
-        {
-            inv1 = (float)((double)inv1 / inv_max);
-            inv2 = (float)((double)inv2 / inv_max);
-            inv3 = (float)((double)inv3 / inv_max);
-        }
+    for (; i < src_len - 47; i += 48)
+    {
+        // Load 3x uint8x16 and deinterleave into vectors of each channel
+        v_load_deinterleave(&src_data[i], v_inB, v_inG, v_inR);
 
-        // Fixed point arithmetic, mul by 2^8 then shift back 8 bits
-        int i_inv1 = cvRound(inv1 * (1 << 8)),
-            i_inv2 = cvRound(inv2 * (1 << 8)),
-            i_inv3 = cvRound(inv3 * (1 << 8));
+        // Get min and max
+        v_min_val = v_min(v_inB, v_min(v_inG, v_inR));
+        v_max_val = v_max(v_inB, v_max(v_inG, v_inR));
+
+        // Split into two ushort vectors per channel
+        v_expand(v_inB, v_iB1, v_iB2);
+        v_expand(v_inG, v_iG1, v_iG2);
+        v_expand(v_inR, v_iR1, v_iR2);
+        v_expand(v_min_val, v_min1, v_min2);
+        v_expand(v_max_val, v_max1, v_max2);
+
+        // Calculate masks
+        v_m1 = ~((v_max1 - v_min1) * v_255 > v_thresh * v_max1);
+        v_m2 = ~((v_max2 - v_min2) * v_255 > v_thresh * v_max2);
+
+        // Apply masks
+        v_iB1 = (v_iB1 & v_m1) + (v_iB2 & v_m2);
+        v_iG1 = (v_iG1 & v_m1) + (v_iG2 & v_m2);
+        v_iR1 = (v_iR1 & v_m1) + (v_iR2 & v_m2);
+
+        // Split and add to the sums:
+        v_expand(v_iB1, v_uint1, v_uint2);
+        v_SB += v_uint1 + v_uint2;
+        v_expand(v_iG1, v_uint1, v_uint2);
+        v_SG += v_uint1 + v_uint2;
+        v_expand(v_iR1, v_uint1, v_uint2);
+        v_SR += v_uint1 + v_uint2;
+    }
+
+    sumB = v_reduce_sum(v_SB);
+    sumG = v_reduce_sum(v_SG);
+    sumR = v_reduce_sum(v_SR);
+#endif
+    unsigned int minRGB, maxRGB;
+    for (; i < src_len; i += 3)
+    {
+        minRGB = min(src_data[i], min(src_data[i + 1], src_data[i + 2]));
+        maxRGB = max(src_data[i], max(src_data[i + 1], src_data[i + 2]));
+        if ((maxRGB - minRGB) * 255 > thresh255 * maxRGB)
+            continue;
+        sumB += src_data[i];
+        sumG += src_data[i + 1];
+        sumR += src_data[i + 2];
+    }
+}
+
+/* Computes sums for each channel, while ignoring saturated pixels which are determined by thresh
+ * (version for CV_16UC3)
+ */
+void calculateChannelSums(uint64 &sumB, uint64 &sumG, uint64 &sumR, ushort *src_data, int src_len, float thresh)
+{
+    sumB = sumG = sumR = 0;
+    uint thresh65535 = cvRound(thresh * 65535);
+    int i = 0;
+#if CV_SIMD128
+    v_uint16x8 v_inB, v_inG, v_inR, v_min_val, v_max_val;
+    v_uint32x4 v_iB1, v_iB2, v_iG1, v_iG2, v_iR1, v_iR2;
+    v_uint32x4 v_min1, v_min2, v_max1, v_max2, v_m1, v_m2;
+    v_uint32x4 v_65535 = v_setall_u32(65535), v_thresh = v_setall_u32(thresh65535);
+    v_uint64x2 v_u64_1, v_u64_2;
+    v_uint64x2 v_SB = v_setzero_u64(), v_SG = v_setzero_u64(), v_SR = v_setzero_u64();
+
+    for (; i < src_len - 23; i += 24)
+    {
+        // Load 3x uint16x8 and deinterleave into vectors of each channel
+        v_load_deinterleave(&src_data[i], v_inB, v_inG, v_inR);
+
+        // Get min and max
+        v_min_val = v_min(v_inB, v_min(v_inG, v_inR));
+        v_max_val = v_max(v_inB, v_max(v_inG, v_inR));
+
+        // Split into two uint vectors per channel
+        v_expand(v_inB, v_iB1, v_iB2);
+        v_expand(v_inG, v_iG1, v_iG2);
+        v_expand(v_inR, v_iR1, v_iR2);
+        v_expand(v_min_val, v_min1, v_min2);
+        v_expand(v_max_val, v_max1, v_max2);
 
-        // Scale input pixel values
-        uchar* dst_data = dst.ptr<uchar>(0);
-        i = 0;
+        // Calculate masks
+        v_m1 = ~((v_max1 - v_min1) * v_65535 > v_thresh * v_max1);
+        v_m2 = ~((v_max2 - v_min2) * v_65535 > v_thresh * v_max2);
+
+        // Apply masks
+        v_iB1 = (v_iB1 & v_m1) + (v_iB2 & v_m2);
+        v_iG1 = (v_iG1 & v_m1) + (v_iG2 & v_m2);
+        v_iR1 = (v_iR1 & v_m1) + (v_iR2 & v_m2);
+
+        // Split and add to the sums:
+        v_expand(v_iB1, v_u64_1, v_u64_2);
+        v_SB += v_u64_1 + v_u64_2;
+        v_expand(v_iG1, v_u64_1, v_u64_2);
+        v_SG += v_u64_1 + v_u64_2;
+        v_expand(v_iR1, v_u64_1, v_u64_2);
+        v_SR += v_u64_1 + v_u64_2;
+    }
+
+    // Perform final reduction
+    uint64 sum_arr[2];
+    v_store(sum_arr, v_SB);
+    sumB = sum_arr[0] + sum_arr[1];
+    v_store(sum_arr, v_SG);
+    sumG = sum_arr[0] + sum_arr[1];
+    v_store(sum_arr, v_SR);
+    sumR = sum_arr[0] + sum_arr[1];
+#endif
+    unsigned int minRGB, maxRGB;
+    for (; i < src_len; i += 3)
+    {
+        minRGB = min(src_data[i], min(src_data[i + 1], src_data[i + 2]));
+        maxRGB = max(src_data[i], max(src_data[i + 1], src_data[i + 2]));
+        if ((maxRGB - minRGB) * 65535 > thresh65535 * maxRGB)
+            continue;
+        sumB += src_data[i];
+        sumG += src_data[i + 1];
+        sumR += src_data[i + 2];
+    }
+}
+
+void applyChannelGains(InputArray _src, OutputArray _dst, float gainB, float gainG, float gainR)
+{
+    Mat src = _src.getMat();
+    CV_Assert(!src.empty());
+    CV_Assert(src.isContinuous());
+    CV_Assert(src.type() == CV_8UC3 || src.type() == CV_16UC3);
+
+    _dst.create(src.size(), src.type());
+    Mat dst = _dst.getMat();
+    int N3 = 3 * src.cols * src.rows;
+    int i = 0;
+
+    // Scale gains by their maximum (fixed point approximation works only when all gains are <=1)
+    float gain_max = max(gainB, max(gainG, gainR));
+    if (gain_max > 0)
+    {
+        gainB /= gain_max;
+        gainG /= gain_max;
+        gainR /= gain_max;
+    }
+
+    if (src.type() == CV_8UC3)
+    {
+        // Fixed point arithmetic, mul by 2^8 then shift back 8 bits
+        int i_gainB = cvRound(gainB * (1 << 8)), i_gainG = cvRound(gainG * (1 << 8)),
+            i_gainR = cvRound(gainR * (1 << 8));
+        const uchar *src_data = src.ptr<uchar>();
+        uchar *dst_data = dst.ptr<uchar>();
 #if CV_SIMD128
+        v_uint8x16 v_inB, v_inG, v_inR;
         v_uint8x16 v_outB, v_outG, v_outR;
-        v_uint16x8 v_sB1, v_sB2, v_sG1, v_sG2, v_sR1, v_sR2,
-                   v_invB = v_setall_u16((unsigned short) i_inv1),
-                   v_invG = v_setall_u16((unsigned short) i_inv2),
-                   v_invR = v_setall_u16((unsigned short) i_inv3);
+        v_uint16x8 v_sB1, v_sB2, v_sG1, v_sG2, v_sR1, v_sR2;
+        v_uint16x8 v_gainB = v_setall_u16((ushort)i_gainB), v_gainG = v_setall_u16((ushort)i_gainG),
+                   v_gainR = v_setall_u16((ushort)i_gainR);
 
-        for ( ; i < N3 - 47; i += 48 )
+        for (; i < N3 - 47; i += 48)
         {
-            // Load 16 x 8bit uchars
+            // Load 3x uint8x16 and deinterleave into vectors of each channel
             v_load_deinterleave(&src_data[i], v_inB, v_inG, v_inR);
 
-            // Split into four int vectors per channel
+            // Split into two ushort vectors per channel
             v_expand(v_inB, v_sB1, v_sB2);
             v_expand(v_inG, v_sG1, v_sG2);
             v_expand(v_inR, v_sR1, v_sR2);
 
-            // Multiply by scaling factors
-            v_sB1 = (v_sB1 * v_invB) >> 8;
-            v_sB2 = (v_sB2 * v_invB) >> 8;
-            v_sG1 = (v_sG1 * v_invG) >> 8;
-            v_sG2 = (v_sG2 * v_invG) >> 8;
-            v_sR1 = (v_sR1 * v_invR) >> 8;
-            v_sR2 = (v_sR2 * v_invR) >> 8;
+            // Multiply by gains
+            v_sB1 = (v_sB1 * v_gainB) >> 8;
+            v_sB2 = (v_sB2 * v_gainB) >> 8;
+            v_sG1 = (v_sG1 * v_gainG) >> 8;
+            v_sG2 = (v_sG2 * v_gainG) >> 8;
+            v_sR1 = (v_sR1 * v_gainR) >> 8;
+            v_sR2 = (v_sR2 * v_gainR) >> 8;
 
             // Pack into vectors of v_uint8x16
-            v_store_interleave(&dst_data[i], v_pack(v_sB1, v_sB2),
-                v_pack(v_sG1, v_sG2), v_pack(v_sR1, v_sR2));
+            v_store_interleave(&dst_data[i], v_pack(v_sB1, v_sB2), v_pack(v_sG1, v_sG2), v_pack(v_sR1, v_sR2));
+        }
+#endif
+        for (; i < N3; i += 3)
+        {
+            dst_data[i] = (uchar)((src_data[i] * i_gainB) >> 8);
+            dst_data[i + 1] = (uchar)((src_data[i + 1] * i_gainG) >> 8);
+            dst_data[i + 2] = (uchar)((src_data[i + 2] * i_gainR) >> 8);
+        }
+    }
+    else if (src.type() == CV_16UC3)
+    {
+        // Fixed point arithmetic, mul by 2^16 then shift back 16 bits
+        int i_gainB = cvRound(gainB * (1 << 16)), i_gainG = cvRound(gainG * (1 << 16)),
+            i_gainR = cvRound(gainR * (1 << 16));
+        const ushort *src_data = src.ptr<ushort>();
+        ushort *dst_data = dst.ptr<ushort>();
+#if CV_SIMD128
+        v_uint16x8 v_inB, v_inG, v_inR;
+        v_uint16x8 v_outB, v_outG, v_outR;
+        v_uint32x4 v_sB1, v_sB2, v_sG1, v_sG2, v_sR1, v_sR2;
+        v_uint32x4 v_gainB = v_setall_u32((uint)i_gainB), v_gainG = v_setall_u32((uint)i_gainG),
+                   v_gainR = v_setall_u32((uint)i_gainR);
+
+        for (; i < N3 - 23; i += 24)
+        {
+            // Load 3x uint16x8 and deinterleave into vectors of each channel
+            v_load_deinterleave(&src_data[i], v_inB, v_inG, v_inR);
+
+            // Split into two uint vectors per channel
+            v_expand(v_inB, v_sB1, v_sB2);
+            v_expand(v_inG, v_sG1, v_sG2);
+            v_expand(v_inR, v_sR1, v_sR2);
+
+            // Multiply by scaling factors
+            v_sB1 = (v_sB1 * v_gainB) >> 16;
+            v_sB2 = (v_sB2 * v_gainB) >> 16;
+            v_sG1 = (v_sG1 * v_gainG) >> 16;
+            v_sG2 = (v_sG2 * v_gainG) >> 16;
+            v_sR1 = (v_sR1 * v_gainR) >> 16;
+            v_sR2 = (v_sR2 * v_gainR) >> 16;
+
+            // Pack into vectors of v_uint16x8
+            v_store_interleave(&dst_data[i], v_pack(v_sB1, v_sB2), v_pack(v_sG1, v_sG2), v_pack(v_sR1, v_sR2));
         }
 #endif
-        for ( ; i < N3; i += 3 )
+        for (; i < N3; i += 3)
         {
-            dst_data[i]     = (uchar)((src_data[i]     * i_inv1) >> 8);
-            dst_data[i + 1] = (uchar)((src_data[i + 1] * i_inv2) >> 8);
-            dst_data[i + 2] = (uchar)((src_data[i + 2] * i_inv3) >> 8);
+            dst_data[i] = (ushort)((src_data[i] * i_gainB) >> 16);
+            dst_data[i + 1] = (ushort)((src_data[i + 1] * i_gainG) >> 16);
+            dst_data[i + 2] = (ushort)((src_data[i + 2] * i_gainR) >> 16);
         }
     }
+}
 
-}}
+Ptr<GrayworldWB> createGrayworldWB() { return makePtr<GrayworldWBImpl>(); }
+}
+}
diff --git a/contrib/modules/xphoto/src/inpainting.cpp b/contrib/modules/xphoto/src/inpainting.cpp
index 00b9424..6796254 100644
--- a/contrib/modules/xphoto/src/inpainting.cpp
+++ b/contrib/modules/xphoto/src/inpainting.cpp
@@ -58,8 +58,6 @@
 #include "opencv2/core/types.hpp"
 #include "opencv2/core/types_c.h"
 
-#include "opencv2/highgui.hpp"
-
 #include "photomontage.hpp"
 #include "annf.hpp"
 #include "advanced_types.hpp"
diff --git a/contrib/modules/xphoto/src/kaiser_window.hpp b/contrib/modules/xphoto/src/kaiser_window.hpp
new file mode 100644
index 0000000..f5aa1ff
--- /dev/null
+++ b/contrib/modules/xphoto/src/kaiser_window.hpp
@@ -0,0 +1,129 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+//  By downloading, copying, installing or using the software you agree to this license.
+//  If you do not agree to this license, do not download, install,
+//  copy or use the software.
+//
+//
+//                        Intel License Agreement
+//                For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective icvers.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+//   * Redistribution's of source code must retain the above copyright notice,
+//     this list of conditions and the following disclaimer.
+//
+//   * Redistribution's in binary form must reproduce the above copyright notice,
+//     this list of conditions and the following disclaimer in the documentation
+//     and/or other materials provided with the distribution.
+//
+//   * The name of Intel Corporation may not be used to endorse or promote products
+//     derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#ifndef __OPENCV_BM3D_DENOISING_KAISER_WINDOW_HPP__
+#define __OPENCV_BM3D_DENOISING_KAISER_WINDOW_HPP__
+
+#include "opencv2/core.hpp"
+#include <cmath>
+
+namespace cv
+{
+namespace xphoto
+{
+
+static int factorial(int n)
+{
+    if (n == 0)
+        return 1;
+
+    int val = 1;
+    for (int idx = 1; idx <= n; ++idx)
+        val *= idx;
+
+    return val;
+}
+
+template <int MAX_ITER>
+static float bessel0(const float &x)
+{
+    float sum = 0.0f;
+
+    for (int m = 0; m < MAX_ITER; ++m)
+    {
+        float factM = (float)factorial(m);
+        float inc = std::pow(1.0f / factM * std::pow(x * 0.5f, (float)m), 2.0f);
+        sum += inc;
+
+        if ((inc / sum) < 0.001F)
+            break;
+    }
+
+    return sum;
+}
+
+#define MAX_ITER_BESSEL 100
+
+static void calcKaiserWindow1D(cv::Mat &dst, const int N, const float beta)
+{
+    if (dst.empty())
+        dst.create(cv::Size(1, N), CV_32FC1);
+
+    CV_Assert(dst.total() == (size_t)N);
+    CV_Assert(dst.type() == CV_32FC1);
+    CV_Assert(N > 0);
+
+    float *p = dst.ptr<float>(0);
+    for (int i = 0; i < N; ++i)
+    {
+        float b = beta * std::sqrt(1.0f - std::pow(2.0f * i / (N - 1.0f) - 1.0f, 2.0f));
+        p[i] = bessel0<MAX_ITER_BESSEL>(b) / bessel0<MAX_ITER_BESSEL>(beta);
+    }
+}
+
+static void calcKaiserWindow2D(float *&kaiser, const int N, const float beta)
+{
+    if (kaiser == NULL)
+        kaiser = new float[N * N];
+
+    if (beta == 0.0f)
+    {
+        for (int i = 0; i < N * N; ++i)
+            kaiser[i] = 1.0f;
+        return;
+    }
+
+    cv::Mat kaiser1D;
+    calcKaiserWindow1D(kaiser1D, N, beta);
+
+    cv::Mat kaiser1Dt;
+    cv::transpose(kaiser1D, kaiser1Dt);
+
+    cv::Mat kaiser2D = kaiser1D * kaiser1Dt;
+    float *p = kaiser2D.ptr<float>(0);
+    for (unsigned i = 0; i < kaiser2D.total(); ++i)
+        kaiser[i] = p[i];
+}
+
+}  // namespace xphoto
+}  // namespace cv
+
+#endif
\ No newline at end of file
diff --git a/contrib/modules/xphoto/src/learning_based_color_balance.cpp b/contrib/modules/xphoto/src/learning_based_color_balance.cpp
new file mode 100644
index 0000000..d9a8563
--- /dev/null
+++ b/contrib/modules/xphoto/src/learning_based_color_balance.cpp
@@ -0,0 +1,611 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+//  By downloading, copying, installing or using the software you agree to this license.
+//  If you do not agree to this license, do not download, install,
+//  copy or use the software.
+//
+//
+//                           License Agreement
+//                For Open Source Computer Vision Library
+//
+// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
+// Copyright (C) 2009-2011, Willow Garage Inc., all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+//   * Redistribution's of source code must retain the above copyright notice,
+//     this list of conditions and the following disclaimer.
+//
+//   * Redistribution's in binary form must reproduce the above copyright notice,
+//     this list of conditions and the following disclaimer in the documentation
+//     and/or other materials provided with the distribution.
+//
+//   * The name of Intel Corporation may not be used to endorse or promote products
+//     derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "learning_based_color_balance_model.hpp"
+#include "opencv2/core.hpp"
+#include "opencv2/core/hal/intrin.hpp"
+#include "opencv2/imgproc.hpp"
+#include "opencv2/xphoto.hpp"
+
+using namespace std;
+#define EPS 0.00001f
+
+namespace cv
+{
+namespace xphoto
+{
+
+inline void getChromaticity(Vec2f &dst, float R, float G, float B)
+{
+    dst[0] = R / (R + G + B + EPS);
+    dst[1] = G / (R + G + B + EPS);
+}
+
+struct hist_elem
+{
+    float hist_val;
+    float r, g;
+    hist_elem(float _hist_val, Vec2f chromaticity) : hist_val(_hist_val), r(chromaticity[0]), g(chromaticity[1]) {}
+};
+bool operator<(const hist_elem &a, const hist_elem &b);
+bool operator<(const hist_elem &a, const hist_elem &b) { return a.hist_val > b.hist_val; }
+
+class LearningBasedWBImpl : public LearningBasedWB
+{
+  private:
+    int range_max_val, hist_bin_num, palette_size;
+    float saturation_thresh, palette_bandwidth, prediction_thresh;
+    int num_trees, num_tree_nodes, tree_depth;
+    uchar *feature_idx;
+    float *thresh_vals, *leaf_vals;
+    Mat feature_idx_Mat, thresh_vals_Mat, leaf_vals_Mat;
+    Mat mask;
+    int src_max_val;
+
+    void preprocessing(Mat &src);
+    void getAverageAndBrightestColorChromaticity(Vec2f &average_chromaticity, Vec2f &brightest_chromaticity, Mat &src);
+    void getColorPaletteMode(Vec2f &dst, hist_elem *palette);
+    void getHistogramBasedFeatures(Vec2f &dominant_chromaticity, Vec2f &chromaticity_palette_mode, Mat &src);
+
+    float regressionTreePredict(Vec2f src, uchar *tree_feature_idx, float *tree_thresh_vals, float *tree_leaf_vals);
+    Vec2f predictIlluminant(vector<Vec2f> features);
+
+  public:
+    LearningBasedWBImpl(String path_to_model)
+    {
+        range_max_val = 255;
+        saturation_thresh = 0.98f;
+        hist_bin_num = 64;
+        palette_size = 300;
+        palette_bandwidth = 0.1f;
+        prediction_thresh = 0.025f;
+        if (path_to_model.empty())
+        {
+            /* use the default model */
+            num_trees = _num_trees;
+            num_tree_nodes = _num_tree_nodes;
+            feature_idx = _feature_idx;
+            thresh_vals = _thresh_vals;
+            leaf_vals = _leaf_vals;
+        }
+        else
+        {
+            /* load model from file */
+            FileStorage fs(path_to_model, 0);
+            num_trees = fs["num_trees"];
+            num_tree_nodes = fs["num_tree_nodes"];
+            fs["feature_idx"] >> feature_idx_Mat;
+            fs["thresh_vals"] >> thresh_vals_Mat;
+            fs["leaf_vals"] >> leaf_vals_Mat;
+            feature_idx = feature_idx_Mat.ptr<uchar>();
+            thresh_vals = thresh_vals_Mat.ptr<float>();
+            leaf_vals = leaf_vals_Mat.ptr<float>();
+        }
+    }
+
+    int getRangeMaxVal() const { return range_max_val; }
+    void setRangeMaxVal(int val) { range_max_val = val; }
+
+    float getSaturationThreshold() const { return saturation_thresh; }
+    void setSaturationThreshold(float val) { saturation_thresh = val; }
+
+    int getHistBinNum() const { return hist_bin_num; }
+    void setHistBinNum(int val) { hist_bin_num = val; }
+
+    void extractSimpleFeatures(InputArray _src, OutputArray _dst)
+    {
+        CV_Assert(!_src.empty());
+        CV_Assert(_src.isContinuous());
+        CV_Assert(_src.type() == CV_8UC3 || _src.type() == CV_16UC3);
+        Mat src = _src.getMat();
+        vector<Vec2f> dst(num_features);
+
+        preprocessing(src);
+        getAverageAndBrightestColorChromaticity(dst[0], dst[1], src);
+        getHistogramBasedFeatures(dst[2], dst[3], src);
+        Mat(dst).convertTo(_dst, CV_32F);
+    }
+
+    void balanceWhite(InputArray _src, OutputArray _dst)
+    {
+        CV_Assert(!_src.empty());
+        CV_Assert(_src.isContinuous());
+        CV_Assert(_src.type() == CV_8UC3 || _src.type() == CV_16UC3);
+        Mat src = _src.getMat();
+
+        vector<Vec2f> features;
+        extractSimpleFeatures(src, features);
+        Vec2f illuminant = predictIlluminant(features);
+
+        float denom = 1 - illuminant[0] - illuminant[1];
+        float gainB = 1.0f;
+        float gainG = denom / illuminant[1];
+        float gainR = denom / illuminant[0];
+        applyChannelGains(src, _dst, gainB, gainG, gainR);
+    }
+};
+
+/* Computes a mask for non-saturated pixels and maximum pixel value
+ * which are then used for feature computation
+ */
+void LearningBasedWBImpl::preprocessing(Mat &src)
+{
+    mask.create(src.size(), CV_8U);
+    uchar *mask_ptr = mask.ptr<uchar>();
+    int src_len = src.rows * src.cols;
+    int thresh = (int)(saturation_thresh * range_max_val);
+    int i = 0;
+    int local_max;
+    src_max_val = -1;
+
+    if (src.type() == CV_8UC3)
+    {
+        uchar *src_ptr = src.ptr<uchar>();
+#if CV_SIMD128
+        v_uint8x16 v_inB, v_inG, v_inR, v_local_max;
+        v_uint8x16 v_global_max = v_setall_u8(0), v_mask, v_thresh = v_setall_u8((uchar)thresh);
+        for (; i < src_len - 15; i += 16)
+        {
+            v_load_deinterleave(src_ptr + 3 * i, v_inB, v_inG, v_inR);
+            v_local_max = v_max(v_inB, v_max(v_inG, v_inR));
+            v_global_max = v_max(v_local_max, v_global_max);
+            v_mask = (v_local_max < v_thresh);
+            v_store(mask_ptr + i, v_mask);
+        }
+        uchar global_max[16];
+        v_store(global_max, v_global_max);
+        for (int j = 0; j < 16; j++)
+        {
+            if (global_max[j] > src_max_val)
+                src_max_val = global_max[j];
+        }
+#endif
+        for (; i < src_len; i++)
+        {
+            local_max = max(src_ptr[3 * i], max(src_ptr[3 * i + 1], src_ptr[3 * i + 2]));
+            if (local_max > src_max_val)
+                src_max_val = local_max;
+            if (local_max < thresh)
+                mask_ptr[i] = 255;
+            else
+                mask_ptr[i] = 0;
+        }
+    }
+    else if (src.type() == CV_16UC3)
+    {
+        ushort *src_ptr = src.ptr<ushort>();
+#if CV_SIMD128
+        v_uint16x8 v_inB, v_inG, v_inR, v_local_max;
+        v_uint16x8 v_global_max = v_setall_u16(0), v_mask, v_thresh = v_setall_u16((ushort)thresh);
+        for (; i < src_len - 7; i += 8)
+        {
+            v_load_deinterleave(src_ptr + 3 * i, v_inB, v_inG, v_inR);
+            v_local_max = v_max(v_inB, v_max(v_inG, v_inR));
+            v_global_max = v_max(v_local_max, v_global_max);
+            v_mask = (v_local_max < v_thresh);
+            v_pack_store(mask_ptr + i, v_mask);
+        }
+        ushort global_max[8];
+        v_store(global_max, v_global_max);
+        for (int j = 0; j < 8; j++)
+        {
+            if (global_max[j] > src_max_val)
+                src_max_val = global_max[j];
+        }
+#endif
+        for (; i < src_len; i++)
+        {
+            local_max = max(src_ptr[3 * i], max(src_ptr[3 * i + 1], src_ptr[3 * i + 2]));
+            if (local_max > src_max_val)
+                src_max_val = local_max;
+            if (local_max < thresh)
+                mask_ptr[i] = 255;
+            else
+                mask_ptr[i] = 0;
+        }
+    }
+}
+
+void LearningBasedWBImpl::getAverageAndBrightestColorChromaticity(Vec2f &average_chromaticity,
+                                                                  Vec2f &brightest_chromaticity, Mat &src)
+{
+    int i = 0;
+    int src_len = src.rows * src.cols;
+    uchar *mask_ptr = mask.ptr<uchar>();
+    uint brightestB = 0, brightestG = 0, brightestR = 0;
+    uint max_sum = 0;
+    if (src.type() == CV_8UC3)
+    {
+        uint sumB = 0, sumG = 0, sumR = 0;
+        uchar *src_ptr = src.ptr<uchar>();
+#if CV_SIMD128
+        v_uint8x16 v_inB, v_inG, v_inR, v_mask;
+        v_uint16x8 v_sR1, v_sR2, v_sG1, v_sG2, v_sB1, v_sB2, v_sum;
+        v_uint16x8 v_max_sum = v_setall_u16(0), v_max_mask, v_brightestR, v_brightestG, v_brightestB;
+        v_uint32x4 v_uint1, v_uint2, v_SB = v_setzero_u32(), v_SG = v_setzero_u32(), v_SR = v_setzero_u32();
+        for (; i < src_len - 15; i += 16)
+        {
+            v_load_deinterleave(src_ptr + 3 * i, v_inB, v_inG, v_inR);
+            v_mask = v_load(mask_ptr + i);
+
+            v_inB &= v_mask;
+            v_inG &= v_mask;
+            v_inR &= v_mask;
+
+            v_expand(v_inB, v_sB1, v_sB2);
+            v_expand(v_inG, v_sG1, v_sG2);
+            v_expand(v_inR, v_sR1, v_sR2);
+
+            // update the brightest (R,G,B) tuple (process left half):
+            v_sum = v_sB1 + v_sG1 + v_sR1;
+            v_max_mask = (v_sum > v_max_sum);
+            v_max_sum = v_max(v_sum, v_max_sum);
+            v_brightestB = (v_sB1 & v_max_mask) + (v_brightestB & (~v_max_mask));
+            v_brightestG = (v_sG1 & v_max_mask) + (v_brightestG & (~v_max_mask));
+            v_brightestR = (v_sR1 & v_max_mask) + (v_brightestR & (~v_max_mask));
+
+            // update the brightest (R,G,B) tuple (process right half):
+            v_sum = v_sB2 + v_sG2 + v_sR2;
+            v_max_mask = (v_sum > v_max_sum);
+            v_max_sum = v_max(v_sum, v_max_sum);
+            v_brightestB = (v_sB2 & v_max_mask) + (v_brightestB & (~v_max_mask));
+            v_brightestG = (v_sG2 & v_max_mask) + (v_brightestG & (~v_max_mask));
+            v_brightestR = (v_sR2 & v_max_mask) + (v_brightestR & (~v_max_mask));
+
+            // update sums:
+            v_sB1 = v_sB1 + v_sB2;
+            v_sG1 = v_sG1 + v_sG2;
+            v_sR1 = v_sR1 + v_sR2;
+            v_expand(v_sB1, v_uint1, v_uint2);
+            v_SB += v_uint1 + v_uint2;
+            v_expand(v_sG1, v_uint1, v_uint2);
+            v_SG += v_uint1 + v_uint2;
+            v_expand(v_sR1, v_uint1, v_uint2);
+            v_SR += v_uint1 + v_uint2;
+        }
+        sumB = v_reduce_sum(v_SB);
+        sumG = v_reduce_sum(v_SG);
+        sumR = v_reduce_sum(v_SR);
+        ushort brightestB_arr[8], brightestG_arr[8], brightestR_arr[8], max_sum_arr[8];
+        v_store(brightestB_arr, v_brightestB);
+        v_store(brightestG_arr, v_brightestG);
+        v_store(brightestR_arr, v_brightestR);
+        v_store(max_sum_arr, v_max_sum);
+        for (int j = 0; j < 8; j++)
+        {
+            if (max_sum_arr[j] > max_sum)
+            {
+                max_sum = max_sum_arr[j];
+                brightestB = brightestB_arr[j];
+                brightestG = brightestG_arr[j];
+                brightestR = brightestR_arr[j];
+            }
+        }
+#endif
+        for (; i < src_len; i++)
+        {
+            uint sum_val = src_ptr[3 * i] + src_ptr[3 * i + 1] + src_ptr[3 * i + 2];
+            if (mask_ptr[i])
+            {
+                sumB += src_ptr[3 * i];
+                sumG += src_ptr[3 * i + 1];
+                sumR += src_ptr[3 * i + 2];
+                if (sum_val > max_sum)
+                {
+                    max_sum = sum_val;
+                    brightestB = src_ptr[3 * i];
+                    brightestG = src_ptr[3 * i + 1];
+                    brightestR = src_ptr[3 * i + 2];
+                }
+            }
+        }
+        double maxRGB = (double)max(sumR, max(sumG, sumB));
+        getChromaticity(average_chromaticity, (float)(sumR / maxRGB), (float)(sumG / maxRGB), (float)(sumB / maxRGB));
+        getChromaticity(brightest_chromaticity, (float)brightestR, (float)brightestG, (float)brightestB);
+    }
+    else if (src.type() == CV_16UC3)
+    {
+        uint64 sumB = 0, sumG = 0, sumR = 0;
+        ushort *src_ptr = src.ptr<ushort>();
+#if CV_SIMD128
+        v_uint16x8 v_inB, v_inG, v_inR, v_mask, v_mask_lower = v_setall_u16(255);
+        v_uint32x4 v_iR1, v_iR2, v_iG1, v_iG2, v_iB1, v_iB2, v_sum;
+        v_uint32x4 v_max_sum = v_setall_u32(0), v_max_mask, v_brightestR, v_brightestG, v_brightestB;
+        v_uint64x2 v_uint64_1, v_uint64_2, v_SB = v_setzero_u64(), v_SG = v_setzero_u64(), v_SR = v_setzero_u64();
+        for (; i < src_len - 7; i += 8)
+        {
+            v_load_deinterleave(src_ptr + 3 * i, v_inB, v_inG, v_inR);
+            v_mask = v_load_expand(mask_ptr + i);
+            v_mask = v_mask | ((v_mask & v_mask_lower) << 8);
+
+            v_inB &= v_mask;
+            v_inG &= v_mask;
+            v_inR &= v_mask;
+
+            v_expand(v_inB, v_iB1, v_iB2);
+            v_expand(v_inG, v_iG1, v_iG2);
+            v_expand(v_inR, v_iR1, v_iR2);
+
+            // update the brightest (R,G,B) tuple (process left half):
+            v_sum = v_iB1 + v_iG1 + v_iR1;
+            v_max_mask = (v_sum > v_max_sum);
+            v_max_sum = v_max(v_sum, v_max_sum);
+            v_brightestB = (v_iB1 & v_max_mask) + (v_brightestB & (~v_max_mask));
+            v_brightestG = (v_iG1 & v_max_mask) + (v_brightestG & (~v_max_mask));
+            v_brightestR = (v_iR1 & v_max_mask) + (v_brightestR & (~v_max_mask));
+
+            // update the brightest (R,G,B) tuple (process right half):
+            v_sum = v_iB2 + v_iG2 + v_iR2;
+            v_max_mask = (v_sum > v_max_sum);
+            v_max_sum = v_max(v_sum, v_max_sum);
+            v_brightestB = (v_iB2 & v_max_mask) + (v_brightestB & (~v_max_mask));
+            v_brightestG = (v_iG2 & v_max_mask) + (v_brightestG & (~v_max_mask));
+            v_brightestR = (v_iR2 & v_max_mask) + (v_brightestR & (~v_max_mask));
+
+            // update sums:
+            v_iB1 = v_iB1 + v_iB2;
+            v_iG1 = v_iG1 + v_iG2;
+            v_iR1 = v_iR1 + v_iR2;
+            v_expand(v_iB1, v_uint64_1, v_uint64_2);
+            v_SB += v_uint64_1 + v_uint64_2;
+            v_expand(v_iG1, v_uint64_1, v_uint64_2);
+            v_SG += v_uint64_1 + v_uint64_2;
+            v_expand(v_iR1, v_uint64_1, v_uint64_2);
+            v_SR += v_uint64_1 + v_uint64_2;
+        }
+        uint64 sum_arr[2];
+        v_store(sum_arr, v_SB);
+        sumB = sum_arr[0] + sum_arr[1];
+        v_store(sum_arr, v_SG);
+        sumG = sum_arr[0] + sum_arr[1];
+        v_store(sum_arr, v_SR);
+        sumR = sum_arr[0] + sum_arr[1];
+        uint brightestB_arr[4], brightestG_arr[4], brightestR_arr[4], max_sum_arr[4];
+        v_store(brightestB_arr, v_brightestB);
+        v_store(brightestG_arr, v_brightestG);
+        v_store(brightestR_arr, v_brightestR);
+        v_store(max_sum_arr, v_max_sum);
+        for (int j = 0; j < 4; j++)
+        {
+            if (max_sum_arr[j] > max_sum)
+            {
+                max_sum = max_sum_arr[j];
+                brightestB = brightestB_arr[j];
+                brightestG = brightestG_arr[j];
+                brightestR = brightestR_arr[j];
+            }
+        }
+#endif
+        for (; i < src_len; i++)
+        {
+            uint sum_val = src_ptr[3 * i] + src_ptr[3 * i + 1] + src_ptr[3 * i + 2];
+            if (mask_ptr[i])
+            {
+                sumB += src_ptr[3 * i];
+                sumG += src_ptr[3 * i + 1];
+                sumR += src_ptr[3 * i + 2];
+                if (sum_val > max_sum)
+                {
+                    max_sum = sum_val;
+                    brightestB = src_ptr[3 * i];
+                    brightestG = src_ptr[3 * i + 1];
+                    brightestR = src_ptr[3 * i + 2];
+                }
+            }
+        }
+        double maxRGB = (double)max(sumR, max(sumG, sumB));
+        getChromaticity(average_chromaticity, (float)(sumR / maxRGB), (float)(sumG / maxRGB), (float)(sumB / maxRGB));
+        getChromaticity(brightest_chromaticity, (float)brightestR, (float)brightestG, (float)brightestB);
+    }
+}
+
+/* Returns the most high-density point (i.e. mode) of the color palette.
+ * Uses a simplistic kernel density estimator with a Epanechnikov kernel and
+ * fixed bandwidth.
+ */
+void LearningBasedWBImpl::getColorPaletteMode(Vec2f &dst, hist_elem *palette)
+{
+    float max_density = -1.0f;
+    float denom = palette_bandwidth * palette_bandwidth;
+    for (int i = 0; i < palette_size; i++)
+    {
+        float cur_density = 0.0f;
+        float cur_dist_sq;
+
+        for (int j = 0; j < palette_size; j++)
+        {
+            cur_dist_sq = (palette[i].r - palette[j].r) * (palette[i].r - palette[j].r) +
+                          (palette[i].g - palette[j].g) * (palette[i].g - palette[j].g);
+            cur_density += max((1.0f - (cur_dist_sq / denom)), 0.0f);
+        }
+
+        if (cur_density > max_density)
+        {
+            max_density = cur_density;
+            dst[0] = palette[i].r;
+            dst[1] = palette[i].g;
+        }
+    }
+}
+
+void LearningBasedWBImpl::getHistogramBasedFeatures(Vec2f &dominant_chromaticity, Vec2f &chromaticity_palette_mode,
+                                                    Mat &src)
+{
+    MatND hist;
+    int channels[] = {0, 1, 2};
+    int histSize[] = {hist_bin_num, hist_bin_num, hist_bin_num};
+    float range[] = {0, (float)max(hist_bin_num, src_max_val)};
+    const float *ranges[] = {range, range, range};
+    calcHist(&src, 1, channels, mask, hist, 3, histSize, ranges);
+
+    int dominant_B = 0, dominant_G = 0, dominant_R = 0;
+    double max_hist_val = 0;
+    float *hist_ptr = hist.ptr<float>();
+    for (int i = 0; i < hist_bin_num; i++)
+        for (int j = 0; j < hist_bin_num; j++)
+            for (int k = 0; k < hist_bin_num; k++)
+            {
+                if (*hist_ptr > max_hist_val)
+                {
+                    max_hist_val = *hist_ptr;
+                    dominant_B = i;
+                    dominant_G = j;
+                    dominant_R = k;
+                }
+                hist_ptr++;
+            }
+    getChromaticity(dominant_chromaticity, (float)dominant_R, (float)dominant_G, (float)dominant_B);
+
+    vector<hist_elem> palette;
+    palette.reserve(palette_size);
+    hist_ptr = hist.ptr<float>();
+    // extract top palette_size most common colors and add them to the palette:
+    for (int i = 0; i < hist_bin_num; i++)
+        for (int j = 0; j < hist_bin_num; j++)
+            for (int k = 0; k < hist_bin_num; k++)
+            {
+                float bin_count = *hist_ptr;
+                if (bin_count < EPS)
+                {
+                    hist_ptr++;
+                    continue;
+                }
+                Vec2f chromaticity;
+                getChromaticity(chromaticity, (float)k, (float)j, (float)i);
+                hist_elem el(bin_count, chromaticity);
+
+                if (palette.size() < (uint)palette_size)
+                {
+                    palette.push_back(el);
+                    if (palette.size() == (uint)palette_size)
+                        make_heap(palette.begin(), palette.end());
+                }
+                else if (bin_count > palette.front().hist_val)
+                {
+                    pop_heap(palette.begin(), palette.end());
+                    palette.back() = el;
+                    push_heap(palette.begin(), palette.end());
+                }
+                hist_ptr++;
+            }
+    getColorPaletteMode(chromaticity_palette_mode, (hist_elem *)(&palette[0]));
+}
+
+float LearningBasedWBImpl::regressionTreePredict(Vec2f src, uchar *tree_feature_idx, float *tree_thresh_vals,
+                                                 float *tree_leaf_vals)
+{
+    int node_idx = 0;
+    for (int i = 0; i < tree_depth; i++)
+    {
+        if (src[tree_feature_idx[node_idx]] <= tree_thresh_vals[node_idx])
+            node_idx = 2 * node_idx + 1;
+        else
+            node_idx = 2 * node_idx + 2;
+    }
+    return tree_leaf_vals[node_idx - num_tree_nodes + 1];
+}
+
+Vec2f LearningBasedWBImpl::predictIlluminant(vector<Vec2f> features)
+{
+    int feature_model_size = 2 * (num_tree_nodes - 1);
+    int local_model_size = num_features * feature_model_size;
+    int feature_model_size_leaf = 2 * num_tree_nodes;
+    int local_model_size_leaf = num_features * feature_model_size_leaf;
+    tree_depth = cvRound( (log(static_cast<float>(num_tree_nodes)) / log(2.0f)) );
+
+    vector<float> consensus_r, consensus_g;
+    vector<float> all_r, all_g;
+    for (int i = 0; i < num_trees; i++)
+    {
+        Vec2f local_predictions[num_features];
+        for (int j = 0; j < num_features; j++)
+        {
+            float r = regressionTreePredict(features[j], feature_idx + local_model_size * i + feature_model_size * j,
+                                            thresh_vals + local_model_size * i + feature_model_size * j,
+                                            leaf_vals + local_model_size_leaf * i + feature_model_size_leaf * j);
+            float g = regressionTreePredict(
+              features[j], feature_idx + local_model_size * i + feature_model_size * j + feature_model_size / 2,
+              thresh_vals + local_model_size * i + feature_model_size * j + feature_model_size / 2,
+              leaf_vals + local_model_size_leaf * i + feature_model_size_leaf * j + feature_model_size_leaf / 2);
+            local_predictions[j] = Vec2f(r, g);
+            all_r.push_back(r);
+            all_g.push_back(g);
+        }
+        int agreement_degree = 0;
+        for (int j = 0; j < num_features - 1; j++)
+            for (int k = j + 1; k < num_features; k++)
+            {
+                if (norm(local_predictions[j] - local_predictions[k]) < prediction_thresh)
+                    agreement_degree++;
+            }
+        if (agreement_degree >= 3)
+        {
+            for (int j = 0; j < num_features; j++)
+            {
+                consensus_r.push_back(local_predictions[j][0]);
+                consensus_g.push_back(local_predictions[j][1]);
+            }
+        }
+    }
+
+    float illuminant_r, illuminant_g;
+    if (consensus_r.size() == 0)
+    {
+        nth_element(all_r.begin(), all_r.begin() + all_r.size() / 2, all_r.end());
+        illuminant_r = all_r[all_r.size() / 2];
+        nth_element(all_g.begin(), all_g.begin() + all_g.size() / 2, all_g.end());
+        illuminant_g = all_g[all_g.size() / 2];
+    }
+    else
+    {
+        nth_element(consensus_r.begin(), consensus_r.begin() + consensus_r.size() / 2, consensus_r.end());
+        illuminant_r = consensus_r[consensus_r.size() / 2];
+        nth_element(consensus_g.begin(), consensus_g.begin() + consensus_g.size() / 2, consensus_g.end());
+        illuminant_g = consensus_g[consensus_g.size() / 2];
+    }
+    return Vec2f(illuminant_r, illuminant_g);
+}
+
+Ptr<LearningBasedWB> createLearningBasedWB(const String& path_to_model)
+{
+    Ptr<LearningBasedWB> inst = makePtr<LearningBasedWBImpl>(path_to_model);
+    return inst;
+}
+}
+}
diff --git a/contrib/modules/xphoto/src/learning_based_color_balance_model.hpp b/contrib/modules/xphoto/src/learning_based_color_balance_model.hpp
new file mode 100644
index 0000000..e46d8f6
--- /dev/null
+++ b/contrib/modules/xphoto/src/learning_based_color_balance_model.hpp
@@ -0,0 +1,365 @@
+/* This file was automatically generated by learn_color_balance.py script
+ * using the following parameters:
+ --num_trees 20 --hist_bin_num 64 --max_tree_depth 4 --num_augmented 2 -r 0,0
+ */
+const int num_features = 4;
+const int _num_trees = 20;
+const int _num_tree_nodes = 16;
+unsigned char _feature_idx[_num_trees * num_features * 2 * (_num_tree_nodes - 1)] = {
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1,
+  0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1,
+  0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0,
+  0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0,
+  0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0,
+  1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0,
+  1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0, 0,
+  1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1,
+  0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1,
+  0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1,
+  0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0,
+  1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0,
+  0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1,
+  0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1,
+  0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,
+  1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1,
+  1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1,
+  0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1,
+  0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1,
+  1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
+  0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1,
+  1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0,
+  0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0,
+  1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0,
+  0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1,
+  1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0,
+  0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0,
+  0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1,
+  1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
+float _thresh_vals[_num_trees * num_features * 2 * (_num_tree_nodes - 1)] = {
+  .193f, .098f, .455f, .040f, .145f, .316f, .571f, .016f, .058f, .137f, .174f, .276f, .356f, .515f, .730f, .606f, .324f,
+  .794f, .230f, .440f, .683f, .878f, .134f, .282f, .406f, .532f, .036f, .747f, .830f, .931f, .196f, .145f, .363f, .047f,
+  .351f, .279f, .519f, .013f, .887f, .191f, .193f, .361f, .316f, .576f, .445f, .524f, .368f, .752f, .271f, .477f, .636f,
+  .798f, .146f, .249f, .423f, .521f, .446f, .023f, .795f, .908f, .259f, .026f, .557f, .125f, .121f, .432f, .774f, .500f,
+  .500f, .984f, .202f, .307f, .509f, .038f, .042f, .667f, .500f, .000f, .014f, .560f, .984f, .000f, .125f, .333f, .553f,
+  .333f, .860f, .000f, .500f, .000f, .193f, .114f, .432f, .032f, .157f, .310f, .567f, .013f, .048f, .127f, .428f, .271f,
+  .370f, .511f, .762f, .615f, .325f, .833f, .193f, .440f, .728f, .887f, .086f, .230f, .411f, .546f, .671f, .009f, .863f,
+  .944f, .283f, .174f, .515f, .087f, .209f, .356f, .693f, .059f, .145f, .344f, .254f, .316f, .455f, .571f, .811f, .537f,
+  .343f, .751f, .243f, .435f, .630f, .813f, .134f, .310f, .391f, .487f, .597f, .683f, .755f, .878f, .307f, .145f, .446f,
+  .063f, .349f, .457f, .576f, .021f, .792f, .268f, .250f, .421f, .463f, .574f, .610f, .478f, .354f, .636f, .271f, .423f,
+  .529f, .795f, .146f, .257f, .124f, .458f, .043f, .022f, .752f, .836f, .307f, .026f, .557f, .125f, .135f, .435f, .774f,
+  .500f, .500f, .984f, .238f, .500f, .509f, .038f, .042f, .600f, .400f, .000f, .014f, .500f, .667f, .000f, .125f, .250f,
+  .455f, .097f, .333f, .984f, .000f, .000f, .271f, .155f, .511f, .078f, .198f, .372f, .696f, .059f, .123f, .183f, .237f,
+  .310f, .432f, .564f, .875f, .546f, .324f, .728f, .195f, .423f, .616f, .823f, .131f, .281f, .355f, .490f, .581f, .677f,
+  .775f, .885f, .300f, .192f, .515f, .109f, .248f, .374f, .693f, .065f, .157f, .580f, .276f, .341f, .455f, .571f, .811f,
+  .532f, .324f, .679f, .196f, .421f, .630f, .804f, .111f, .252f, .348f, .447f, .565f, .247f, .755f, .866f, .335f, .188f,
+  .503f, .104f, .270f, .521f, .607f, .021f, .134f, .364f, .332f, .421f, .571f, .576f, .836f, .458f, .294f, .523f, .171f,
+  .413f, .501f, .651f, .065f, .273f, .354f, .062f, .052f, .489f, .523f, .784f, .307f, .026f, .557f, .125f, .156f, .432f,
+  .774f, .500f, .500f, .984f, .200f, .399f, .509f, .038f, .042f, .560f, .429f, .000f, .014f, .138f, .667f, .000f, .125f,
+  .222f, .500f, .522f, .286f, .984f, .500f, .000f, .295f, .186f, .564f, .104f, .293f, .432f, .762f, .059f, .127f, .271f,
+  .593f, .353f, .511f, .630f, .875f, .538f, .324f, .685f, .195f, .423f, .616f, .791f, .099f, .281f, .389f, .452f, .581f,
+  .293f, .728f, .842f, .320f, .211f, .521f, .098f, .251f, .403f, .693f, .058f, .158f, .580f, .469f, .188f, .455f, .571f,
+  .811f, .532f, .324f, .717f, .193f, .415f, .587f, .791f, .122f, .265f, .391f, .457f, .559f, .665f, .753f, .835f, .405f,
+  .305f, .503f, .135f, .457f, .483f, .607f, .044f, .182f, .394f, .569f, .156f, .484f, .576f, .836f, .455f, .294f, .576f,
+  .248f, .376f, .482f, .651f, .089f, .273f, .181f, .430f, .472f, .500f, .265f, .784f, .414f, .228f, .557f, .026f, .620f,
+  .476f, .774f, .500f, .156f, .595f, .304f, .322f, .509f, .038f, .042f, .533f, .391f, .683f, .106f, .175f, .286f, .010f,
+  .026f, .226f, .500f, .429f, .197f, .655f, .000f, .800f, .386f, .218f, .564f, .082f, .295f, .479f, .762f, .043f, .155f,
+  .293f, .440f, .432f, .511f, .630f, .875f, .544f, .306f, .705f, .185f, .412f, .606f, .791f, .109f, .263f, .372f, .502f,
+  .315f, .685f, .741f, .855f, .365f, .221f, .544f, .110f, .307f, .455f, .730f, .059f, .179f, .276f, .468f, .403f, .515f,
+  .678f, .860f, .520f, .340f, .683f, .196f, .440f, .591f, .754f, .122f, .274f, .394f, .464f, .556f, .622f, .723f, .835f,
+  .375f, .147f, .503f, .055f, .319f, .436f, .607f, .018f, .773f, .624f, .298f, .467f, .450f, .576f, .836f, .454f, .287f,
+  .571f, .163f, .376f, .308f, .648f, .086f, .236f, .373f, .427f, .477f, .496f, .333f, .795f, .500f, .307f, .774f, .026f,
+  .462f, .557f, .042f, .125f, .191f, .406f, .500f, .509f, .038f, .000f, .138f, .600f, .400f, .000f, .073f, .500f, .010f,
+  .000f, .026f, .275f, .226f, .588f, .984f, .688f, .000f, .000f, .386f, .245f, .564f, .097f, .343f, .479f, .762f, .048f,
+  .180f, .424f, .466f, .432f, .511f, .630f, .875f, .541f, .335f, .702f, .193f, .413f, .602f, .791f, .116f, .296f, .376f,
+  .481f, .210f, .641f, .741f, .863f, .341f, .145f, .531f, .087f, .283f, .455f, .729f, .047f, .109f, .189f, .469f, .375f,
+  .515f, .571f, .811f, .553f, .324f, .683f, .196f, .425f, .607f, .761f, .122f, .252f, .368f, .499f, .248f, .648f, .723f,
+  .848f, .365f, .135f, .503f, .082f, .279f, .503f, .607f, .044f, .086f, .182f, .319f, .395f, .448f, .576f, .836f, .454f,
+  .287f, .571f, .163f, .389f, .308f, .752f, .086f, .250f, .373f, .436f, .498f, .496f, .636f, .834f, .500f, .307f, .774f,
+  .026f, .474f, .557f, .042f, .125f, .000f, .414f, .561f, .509f, .038f, .000f, .138f, .560f, .626f, .000f, .400f, .174f,
+  .984f, .000f, .073f, .500f, .852f, .226f, .667f, .500f, .000f, .000f, .353f, .141f, .564f, .073f, .265f, .432f, .762f,
+  .032f, .106f, .193f, .478f, .470f, .511f, .630f, .875f, .605f, .325f, .728f, .193f, .437f, .652f, .855f, .116f, .264f,
+  .412f, .502f, .202f, .685f, .776f, .912f, .341f, .161f, .531f, .087f, .298f, .455f, .729f, .047f, .109f, .185f, .467f,
+  .375f, .515f, .571f, .811f, .580f, .324f, .685f, .196f, .425f, .607f, .824f, .122f, .252f, .368f, .512f, .231f, .648f,
+  .749f, .885f, .365f, .135f, .503f, .082f, .319f, .499f, .607f, .044f, .086f, .702f, .384f, .439f, .465f, .576f, .836f,
+  .478f, .287f, .594f, .163f, .454f, .502f, .784f, .086f, .250f, .364f, .345f, .500f, .370f, .651f, .836f, .476f, .295f,
+  .557f, .026f, .474f, .509f, .774f, .125f, .000f, .333f, .364f, .495f, .405f, .038f, .042f, .560f, .626f, .000f, .400f,
+  .174f, .010f, .000f, .059f, .500f, .852f, .226f, .667f, .667f, .000f, .000f, .419f, .157f, .564f, .078f, .295f, .479f,
+  .762f, .043f, .124f, .256f, .353f, .432f, .511f, .630f, .875f, .605f, .325f, .713f, .193f, .423f, .677f, .842f, .116f,
+  .264f, .385f, .502f, .621f, .177f, .756f, .912f, .388f, .174f, .564f, .095f, .310f, .456f, .730f, .047f, .143f, .276f,
+  .468f, .431f, .515f, .682f, .860f, .352f, .215f, .591f, .124f, .290f, .536f, .723f, .064f, .172f, .244f, .318f, .428f,
+  .548f, .666f, .825f, .394f, .146f, .503f, .055f, .349f, .499f, .607f, .018f, .773f, .271f, .327f, .439f, .465f, .576f,
+  .836f, .464f, .287f, .588f, .163f, .377f, .502f, .752f, .086f, .250f, .237f, .454f, .464f, .370f, .636f, .834f, .476f,
+  .000f, .557f, .282f, .000f, .509f, .774f, .026f, .481f, .000f, .000f, .495f, .405f, .038f, .042f, .556f, .626f, .000f,
+  .343f, .174f, .010f, .000f, .023f, .559f, .852f, .226f, .667f, .667f, .000f, .000f, .468f, .157f, .567f, .078f, .305f,
+  .511f, .762f, .043f, .124f, .271f, .464f, .511f, .193f, .630f, .875f, .351f, .208f, .602f, .116f, .302f, .489f, .720f,
+  .059f, .164f, .281f, .325f, .414f, .282f, .654f, .842f, .388f, .174f, .564f, .095f, .313f, .456f, .730f, .047f, .143f,
+  .279f, .468f, .431f, .515f, .682f, .860f, .356f, .215f, .591f, .124f, .290f, .539f, .753f, .064f, .174f, .274f, .318f,
+  .435f, .556f, .647f, .848f, .411f, .146f, .411f, .055f, .349f, .490f, .499f, .018f, .773f, .271f, .327f, .181f, .610f,
+  .467f, .448f, .287f, .163f, .454f, .086f, .262f, .359f, .636f, .041f, .476f, .200f, .633f, .257f, .428f, .522f, .795f,
+  .435f, .000f, .557f, .049f, .000f, .509f, .774f, .330f, .282f, .500f, .000f, .462f, .405f, .038f, .042f, .393f, .029f,
+  .000f, .026f, .226f, .602f, .000f, .500f, .183f, .163f, .337f, .500f, .984f, .500f, .000f, .468f, .157f, .567f, .078f,
+  .314f, .511f, .762f, .043f, .124f, .271f, .456f, .511f, .193f, .630f, .875f, .355f, .208f, .602f, .116f, .296f, .414f,
+  .761f, .059f, .179f, .263f, .324f, .381f, .502f, .681f, .855f, .356f, .174f, .537f, .095f, .289f, .455f, .729f, .047f,
+  .143f, .186f, .471f, .403f, .515f, .588f, .811f, .352f, .215f, .568f, .147f, .282f, .435f, .723f, .077f, .191f, .265f,
+  .318f, .395f, .543f, .630f, .824f, .439f, .141f, .443f, .051f, .363f, .490f, .479f, .018f, .773f, .279f, .446f, .223f,
+  .607f, .504f, .491f, .298f, .179f, .454f, .086f, .264f, .350f, .571f, .041f, .122f, .390f, .287f, .324f, .431f, .502f,
+  .752f, .500f, .307f, .774f, .026f, .500f, .557f, .042f, .125f, .000f, .434f, .524f, .509f, .038f, .000f, .138f, .447f,
+  .225f, .000f, .026f, .226f, .600f, .000f, .500f, .337f, .667f, .333f, .269f, .984f, .500f, .000f, .425f, .157f, .564f,
+  .078f, .314f, .511f, .762f, .043f, .124f, .269f, .467f, .479f, .561f, .630f, .875f, .372f, .208f, .602f, .148f, .296f,
+  .441f, .775f, .072f, .179f, .230f, .324f, .408f, .516f, .652f, .863f, .403f, .179f, .571f, .095f, .337f, .456f, .730f,
+  .047f, .145f, .267f, .458f, .056f, .521f, .682f, .860f, .352f, .193f, .568f, .095f, .282f, .435f, .696f, .056f, .147f,
+  .230f, .318f, .395f, .534f, .630f, .808f, .484f, .141f, .454f, .051f, .372f, .605f, .487f, .018f, .773f, .316f, .483f,
+  .490f, .610f, .486f, .490f, .298f, .200f, .472f, .122f, .275f, .397f, .571f, .061f, .174f, .370f, .364f, .349f, .435f,
+  .499f, .752f, .500f, .307f, .667f, .026f, .500f, .661f, .774f, .125f, .000f, .398f, .524f, .557f, .167f, .760f, .042f,
+  .500f, .667f, .000f, .429f, .138f, .984f, .000f, .029f, .364f, .906f, .226f, .667f, .500f, .000f, .000f, .488f, .157f,
+  .567f, .078f, .366f, .511f, .762f, .043f, .124f, .309f, .487f, .511f, .193f, .630f, .875f, .376f, .208f, .575f, .148f,
+  .302f, .452f, .687f, .072f, .182f, .230f, .325f, .413f, .516f, .621f, .833f, .452f, .179f, .571f, .095f, .349f, .515f,
+  .730f, .047f, .145f, .244f, .444f, .456f, .206f, .682f, .860f, .368f, .215f, .568f, .124f, .290f, .444f, .689f, .063f,
+  .188f, .252f, .343f, .406f, .516f, .630f, .804f, .162f, .085f, .490f, .044f, .086f, .372f, .454f, .015f, .424f, .463f,
+  .134f, .262f, .478f, .607f, .490f, .462f, .297f, .583f, .163f, .349f, .522f, .702f, .065f, .237f, .315f, .428f, .499f,
+  .397f, .636f, .795f, .500f, .310f, .667f, .026f, .432f, .661f, .000f, .125f, .146f, .500f, .332f, .557f, .167f, .774f,
+  .000f, .537f, .667f, .000f, .400f, .138f, .984f, .000f, .029f, .500f, .906f, .226f, .667f, .500f, .000f, .000f, .511f,
+  .157f, .696f, .078f, .361f, .564f, .875f, .043f, .124f, .223f, .404f, .561f, .630f, .762f, .896f, .376f, .209f, .578f,
+  .116f, .296f, .452f, .687f, .058f, .179f, .264f, .332f, .413f, .516f, .621f, .833f, .455f, .189f, .571f, .098f, .274f,
+  .515f, .730f, .056f, .148f, .244f, .354f, .233f, .206f, .682f, .860f, .381f, .230f, .565f, .124f, .315f, .496f, .673f,
+  .064f, .177f, .282f, .351f, .441f, .528f, .622f, .804f, .146f, .082f, .503f, .044f, .086f, .349f, .607f, .015f, .424f,
+  .085f, .134f, .262f, .298f, .576f, .836f, .349f, .271f, .466f, .146f, .297f, .413f, .608f, .065f, .200f, .364f, .318f,
+  .441f, .291f, .531f, .752f, .535f, .000f, .226f, .286f, .000f, .000f, .348f, .026f, .432f, .000f, .000f, .667f, .000f,
+  .333f, .423f, .500f, .391f, .000f, .073f, .500f, .600f, .000f, .026f, .226f, .455f, .551f, .379f, .984f, .000f, .000f,
+  .564f, .184f, .762f, .089f, .404f, .630f, .875f, .044f, .141f, .271f, .332f, .614f, .752f, .864f, .896f, .385f, .230f,
+  .590f, .116f, .332f, .505f, .687f, .059f, .185f, .283f, .506f, .452f, .546f, .626f, .833f, .254f, .161f, .456f, .087f,
+  .189f, .300f, .571f, .047f, .109f, .179f, .209f, .275f, .375f, .521f, .730f, .395f, .230f, .565f, .112f, .348f, .505f,
+  .751f, .064f, .177f, .290f, .387f, .441f, .282f, .623f, .848f, .146f, .055f, .503f, .018f, .773f, .316f, .607f, .011f,
+  .428f, .134f, .887f, .236f, .358f, .576f, .836f, .349f, .271f, .472f, .146f, .364f, .413f, .636f, .065f, .200f, .288f,
+  .366f, .441f, .398f, .516f, .795f, .592f, .000f, .774f, .282f, .000f, .735f, .042f, .026f, .476f, .000f, .000f, .038f,
+  .127f, .000f, .138f, .500f, .391f, .000f, .029f, .500f, .522f, .000f, .026f, .226f, .455f, .535f, .260f, .984f, .000f,
+  .000f, .250f, .155f, .564f, .078f, .198f, .404f, .762f, .043f, .124f, .183f, .223f, .295f, .432f, .630f, .875f, .385f,
+  .230f, .574f, .116f, .330f, .505f, .728f, .065f, .173f, .283f, .554f, .453f, .546f, .626f, .842f, .285f, .161f, .515f,
+  .087f, .209f, .441f, .693f, .047f, .109f, .184f, .264f, .334f, .456f, .571f, .811f, .352f, .198f, .555f, .124f, .274f,
+  .449f, .723f, .076f, .172f, .236f, .318f, .402f, .519f, .622f, .824f, .236f, .146f, .503f, .055f, .147f, .366f, .607f,
+  .018f, .773f, .146f, .188f, .280f, .499f, .576f, .836f, .329f, .262f, .449f, .163f, .364f, .350f, .588f, .086f, .200f,
+  .296f, .366f, .331f, .412f, .482f, .784f, .571f, .000f, .774f, .307f, .000f, .234f, .042f, .026f, .406f, .000f, .000f,
+  .647f, .620f, .000f, .138f, .500f, .400f, .000f, .109f, .068f, .537f, .000f, .026f, .226f, .500f, .447f, .522f, .984f,
+  .000f, .000f, .268f, .157f, .511f, .078f, .198f, .346f, .696f, .043f, .124f, .183f, .237f, .313f, .458f, .564f, .875f,
+  .351f, .208f, .571f, .116f, .265f, .460f, .728f, .065f, .164f, .230f, .308f, .412f, .516f, .632f, .842f, .300f, .161f,
+  .521f, .087f, .209f, .360f, .693f, .047f, .109f, .184f, .276f, .313f, .452f, .571f, .811f, .351f, .196f, .558f, .122f,
+  .274f, .449f, .723f, .072f, .166f, .236f, .318f, .421f, .520f, .617f, .824f, .190f, .134f, .503f, .051f, .402f, .280f,
+  .607f, .018f, .773f, .156f, .616f, .389f, .345f, .576f, .836f, .326f, .237f, .466f, .179f, .294f, .350f, .636f, .086f,
+  .407f, .277f, .338f, .295f, .415f, .562f, .795f, .307f, .026f, .774f, .125f, .000f, .543f, .042f, .500f, .500f, .205f,
+  .000f, .420f, .321f, .000f, .138f, .447f, .371f, .560f, .026f, .226f, .500f, .000f, .125f, .297f, .187f, .304f, .500f,
+  .522f, .984f, .000f, .256f, .155f, .564f, .078f, .193f, .314f, .762f, .043f, .124f, .428f, .223f, .258f, .470f, .630f,
+  .875f, .338f, .193f, .582f, .116f, .264f, .465f, .728f, .065f, .164f, .230f, .296f, .414f, .531f, .652f, .842f, .316f,
+  .174f, .571f, .095f, .276f, .433f, .730f, .047f, .143f, .209f, .300f, .343f, .521f, .682f, .860f, .343f, .193f, .587f,
+  .105f, .274f, .438f, .751f, .066f, .166f, .230f, .318f, .381f, .519f, .648f, .848f, .271f, .146f, .503f, .055f, .403f,
+  .366f, .607f, .018f, .773f, .365f, .445f, .444f, .517f, .576f, .836f, .324f, .237f, .478f, .115f, .287f, .350f, .636f,
+  .074f, .405f, .387f, .337f, .295f, .431f, .522f, .795f, .307f, .026f, .667f, .125f, .984f, .426f, .000f, .500f, .500f,
+  .156f, .000f, .500f, .557f, .972f, .000f, .429f, .434f, .000f, .023f, .226f, .560f, .000f, .125f, .222f, .760f, .500f,
+  .500f, .667f, .000f, .000f, .310f, .157f, .564f, .078f, .256f, .425f, .762f, .043f, .124f, .193f, .258f, .350f, .511f,
+  .630f, .875f, .337f, .182f, .597f, .101f, .264f, .443f, .728f, .063f, .161f, .216f, .296f, .395f, .522f, .652f, .842f,
+  .341f, .174f, .516f, .095f, .276f, .431f, .678f, .047f, .143f, .209f, .300f, .391f, .460f, .571f, .811f, .324f, .193f,
+  .543f, .122f, .254f, .434f, .689f, .066f, .145f, .230f, .431f, .391f, .508f, .597f, .808f, .271f, .146f, .366f, .055f,
+  .365f, .357f, .503f, .018f, .773f, .249f, .417f, .316f, .444f, .517f, .607f, .308f, .200f, .472f, .115f, .264f, .357f,
+  .571f, .058f, .138f, .260f, .364f, .338f, .431f, .499f, .752f, .414f, .049f, .557f, .125f, .307f, .438f, .000f, .500f,
+  .330f, .984f, .333f, .446f, .122f, .014f, .000f, .391f, .333f, .518f, .026f, .174f, .500f, .000f, .125f, .279f, .760f,
+  .299f, .500f, .408f, .667f, .000f, .310f, .157f, .479f, .078f, .255f, .370f, .564f, .043f, .124f, .193f, .271f, .483f,
+  .418f, .512f, .762f, .335f, .182f, .597f, .086f, .265f, .423f, .728f, .041f, .129f, .230f, .302f, .375f, .522f, .652f,
+  .842f, .374f, .184f, .544f, .095f, .300f, .455f, .811f, .047f, .145f, .254f, .341f, .404f, .516f, .569f, .860f, .326f,
+  .196f, .584f, .118f, .252f, .434f, .751f, .064f, .141f, .236f, .290f, .391f, .508f, .648f, .848f, .316f, .146f, .421f,
+  .055f, .279f, .454f, .503f, .018f, .773f, .183f, .280f, .347f, .571f, .499f, .605f, .294f, .161f, .499f, .086f, .225f,
+  .364f, .636f, .058f, .476f, .200f, .264f, .347f, .454f, .571f, .795f, .500f, .520f, .307f, .462f, .571f, .000f, .450f,
+  .051f, .220f, .557f, .833f, .984f, .000f, .655f, .532f, .355f, .073f, .556f, .026f, .138f, .500f, .000f, .500f, .183f,
+  .906f, .299f, .410f, .333f, .984f, .000f, .370f, .157f, .559f, .078f, .271f, .483f, .762f, .043f, .124f, .198f, .310f,
+  .418f, .512f, .752f, .022f, .308f, .161f, .582f, .086f, .230f, .414f, .728f, .042f, .116f, .193f, .281f, .346f, .489f,
+  .632f, .842f, .455f, .184f, .729f, .095f, .316f, .579f, .811f, .047f, .145f, .276f, .356f, .544f, .666f, .806f, .860f,
+  .326f, .174f, .584f, .088f, .247f, .435f, .751f, .042f, .141f, .215f, .290f, .368f, .528f, .648f, .848f, .347f, .306f,
+  .553f, .146f, .364f, .433f, .610f, .055f, .198f, .338f, .451f, .445f, .432f, .096f, .836f, .294f, .161f, .499f, .108f,
+  .204f, .381f, .636f, .041f, .474f, .198f, .262f, .324f, .362f, .571f, .795f, .500f, .569f, .307f, .101f, .774f, .000f,
+  .423f, .043f, .465f, .121f, .000f, .984f, .000f, .500f, .524f, .333f, .675f, .560f, .292f, .138f, .429f, .000f, .073f,
+  .550f, .000f, .195f, .377f, .500f, .984f, .000f, .479f, .183f, .704f, .082f, .310f, .567f, .875f, .043f, .141f, .271f,
+  .372f, .511f, .630f, .762f, .896f, .325f, .164f, .602f, .086f, .230f, .414f, .761f, .040f, .131f, .197f, .283f, .352f,
+  .516f, .685f, .855f};
+float _leaf_vals[_num_trees * num_features * 2 * _num_tree_nodes] = {
+  .011f, .029f, .047f, .064f, .075f, .102f, .141f, .172f, .212f, .259f, .308f, .364f, .443f, .497f, .592f, .767f, .069f,
+  .165f, .241f, .278f, .357f, .412f, .463f, .540f, .562f, .623f, .676f, .734f, .797f, .838f, .894f, .944f, .014f, .040f,
+  .061f, .033f, .040f, .160f, .181f, .101f, .123f, .047f, .195f, .282f, .374f, .775f, .248f, .068f, .064f, .155f, .177f,
+  .351f, .409f, .479f, .576f, .451f, .677f, .784f, .817f, .764f, .823f, .860f, .898f, .941f, .154f, .154f, .248f, .248f,
+  .050f, .081f, .177f, .227f, .252f, .309f, .385f, .428f, .441f, .525f, .616f, .689f, .435f, .137f, .208f, .406f, .457f,
+  .483f, .518f, .576f, .669f, .844f, .593f, .706f, .853f, .853f, .895f, .925f, .012f, .029f, .047f, .067f, .111f, .134f,
+  .148f, .178f, .214f, .261f, .311f, .357f, .420f, .476f, .592f, .773f, .057f, .143f, .194f, .262f, .358f, .415f, .465f,
+  .541f, .602f, .649f, .655f, .739f, .808f, .849f, .894f, .944f, .050f, .068f, .089f, .118f, .146f, .187f, .211f, .230f,
+  .263f, .308f, .364f, .443f, .497f, .581f, .690f, .832f, .079f, .171f, .263f, .306f, .356f, .401f, .452f, .486f, .538f,
+  .577f, .629f, .687f, .722f, .766f, .834f, .900f, .046f, .066f, .083f, .064f, .090f, .113f, .143f, .235f, .289f, .416f,
+  .094f, .204f, .454f, .074f, .697f, .836f, .067f, .156f, .200f, .332f, .266f, .411f, .473f, .514f, .627f, .575f, .758f,
+  .676f, .775f, .826f, .864f, .900f, .162f, .162f, .248f, .248f, .079f, .102f, .165f, .241f, .281f, .337f, .385f, .428f,
+  .441f, .525f, .616f, .689f, .397f, .137f, .166f, .307f, .421f, .443f, .525f, .486f, .527f, .585f, .687f, .611f, .767f,
+  .821f, .942f, .916f, .055f, .073f, .090f, .110f, .165f, .188f, .207f, .225f, .261f, .312f, .358f, .420f, .475f, .579f,
+  .693f, .875f, .079f, .164f, .238f, .277f, .325f, .378f, .448f, .487f, .527f, .557f, .610f, .648f, .716f, .769f, .830f,
+  .896f, .038f, .090f, .112f, .131f, .206f, .160f, .224f, .249f, .286f, .334f, .370f, .443f, .497f, .581f, .690f, .832f,
+  .056f, .153f, .221f, .278f, .311f, .365f, .420f, .463f, .524f, .562f, .625f, .699f, .696f, .762f, .829f, .889f, .024f,
+  .093f, .104f, .119f, .104f, .154f, .153f, .216f, .273f, .376f, .202f, .138f, .609f, .690f, .814f, .930f, .027f, .098f,
+  .158f, .252f, .304f, .393f, .706f, .462f, .630f, .554f, .845f, .643f, .852f, .694f, .781f, .858f, .169f, .169f, .248f,
+  .248f, .105f, .124f, .110f, .197f, .308f, .242f, .385f, .428f, .441f, .525f, .616f, .689f, .375f, .137f, .146f, .314f,
+  .412f, .437f, .454f, .520f, .510f, .615f, .692f, .576f, .701f, .701f, .780f, .846f, .039f, .091f, .109f, .125f, .209f,
+  .256f, .251f, .126f, .295f, .350f, .420f, .475f, .568f, .625f, .738f, .875f, .055f, .153f, .236f, .281f, .338f, .390f,
+  .425f, .462f, .522f, .563f, .609f, .687f, .674f, .721f, .776f, .846f, .034f, .078f, .123f, .148f, .201f, .153f, .215f,
+  .253f, .239f, .335f, .382f, .446f, .502f, .581f, .690f, .832f, .063f, .145f, .220f, .284f, .340f, .386f, .424f, .467f,
+  .520f, .550f, .611f, .671f, .718f, .758f, .792f, .854f, .065f, .117f, .138f, .163f, .225f, .371f, .188f, .145f, .457f,
+  .345f, .102f, .276f, .609f, .690f, .814f, .930f, .032f, .133f, .188f, .247f, .268f, .350f, .427f, .495f, .538f, .578f,
+  .641f, .835f, .700f, .759f, .780f, .868f, .187f, .187f, .135f, .170f, .218f, .144f, .261f, .340f, .416f, .335f, .388f,
+  .428f, .441f, .525f, .616f, .689f, .367f, .273f, .143f, .308f, .382f, .439f, .410f, .470f, .524f, .461f, .626f, .528f,
+  .583f, .702f, .673f, .773f, .031f, .068f, .124f, .154f, .217f, .154f, .255f, .302f, .358f, .405f, .435f, .475f, .568f,
+  .625f, .738f, .875f, .061f, .144f, .221f, .261f, .325f, .366f, .448f, .495f, .538f, .590f, .618f, .659f, .686f, .739f,
+  .791f, .858f, .034f, .079f, .149f, .175f, .198f, .231f, .249f, .327f, .353f, .382f, .443f, .489f, .570f, .649f, .740f,
+  .882f, .076f, .148f, .218f, .296f, .357f, .400f, .444f, .472f, .516f, .554f, .597f, .630f, .678f, .722f, .781f, .864f,
+  .021f, .055f, .135f, .053f, .180f, .150f, .370f, .214f, .331f, .530f, .219f, .326f, .609f, .690f, .814f, .930f, .049f,
+  .095f, .149f, .216f, .370f, .294f, .443f, .489f, .526f, .594f, .621f, .747f, .656f, .762f, .780f, .884f, .216f, .248f,
+  .160f, .190f, .197f, .356f, .296f, .341f, .391f, .428f, .441f, .525f, .593f, .668f, .760f, .637f, .388f, .250f, .155f,
+  .334f, .419f, .456f, .497f, .448f, .591f, .542f, .552f, .719f, .656f, .709f, .849f, .897f, .034f, .078f, .151f, .184f,
+  .211f, .253f, .262f, .351f, .358f, .405f, .435f, .475f, .568f, .625f, .738f, .875f, .076f, .148f, .229f, .303f, .341f,
+  .376f, .444f, .480f, .548f, .510f, .594f, .638f, .685f, .742f, .800f, .882f, .028f, .062f, .089f, .114f, .174f, .196f,
+  .241f, .294f, .335f, .371f, .443f, .482f, .511f, .590f, .714f, .832f, .075f, .157f, .223f, .281f, .342f, .386f, .450f,
+  .489f, .542f, .590f, .611f, .653f, .682f, .728f, .783f, .893f, .041f, .076f, .186f, .109f, .175f, .195f, .209f, .227f,
+  .274f, .355f, .196f, .314f, .609f, .690f, .814f, .930f, .049f, .097f, .161f, .221f, .415f, .304f, .454f, .492f, .527f,
+  .581f, .629f, .747f, .685f, .758f, .836f, .914f, .225f, .248f, .187f, .074f, .228f, .365f, .295f, .337f, .391f, .428f,
+  .441f, .525f, .593f, .668f, .760f, .637f, .413f, .277f, .431f, .456f, .115f, .162f, .254f, .334f, .503f, .661f, .515f,
+  .515f, .696f, .751f, .836f, .897f, .023f, .057f, .090f, .116f, .180f, .197f, .239f, .283f, .338f, .365f, .420f, .475f,
+  .568f, .625f, .738f, .875f, .074f, .157f, .227f, .282f, .365f, .410f, .451f, .504f, .577f, .610f, .646f, .679f, .728f,
+  .782f, .855f, .923f, .028f, .062f, .089f, .120f, .165f, .204f, .243f, .304f, .335f, .371f, .443f, .482f, .511f, .590f,
+  .714f, .832f, .073f, .157f, .220f, .287f, .343f, .393f, .451f, .489f, .567f, .596f, .616f, .650f, .711f, .760f, .840f,
+  .917f, .041f, .076f, .186f, .092f, .203f, .116f, .222f, .261f, .330f, .438f, .214f, .316f, .609f, .690f, .814f, .930f,
+  .049f, .104f, .163f, .221f, .414f, .448f, .513f, .561f, .566f, .744f, .614f, .683f, .721f, .761f, .854f, .915f, .228f,
+  .248f, .196f, .096f, .300f, .225f, .295f, .344f, .466f, .385f, .403f, .468f, .441f, .525f, .616f, .689f, .414f, .307f,
+  .445f, .460f, .115f, .162f, .254f, .334f, .459f, .495f, .501f, .705f, .680f, .751f, .836f, .897f, .031f, .065f, .100f,
+  .132f, .201f, .221f, .280f, .333f, .374f, .405f, .435f, .475f, .568f, .625f, .738f, .875f, .073f, .157f, .226f, .288f,
+  .349f, .401f, .450f, .489f, .589f, .621f, .649f, .680f, .718f, .759f, .843f, .923f, .029f, .067f, .107f, .140f, .207f,
+  .227f, .279f, .339f, .369f, .393f, .444f, .494f, .575f, .651f, .740f, .882f, .042f, .093f, .147f, .184f, .220f, .256f,
+  .290f, .323f, .402f, .455f, .495f, .540f, .619f, .687f, .748f, .876f, .021f, .055f, .098f, .053f, .206f, .221f, .389f,
+  .239f, .343f, .438f, .228f, .316f, .609f, .690f, .814f, .930f, .049f, .104f, .160f, .221f, .235f, .426f, .455f, .529f,
+  .623f, .551f, .600f, .677f, .697f, .760f, .836f, .914f, .232f, .201f, .231f, .309f, .117f, .096f, .070f, .044f, .466f,
+  .385f, .403f, .468f, .441f, .525f, .616f, .689f, .418f, .251f, .450f, .394f, .115f, .162f, .254f, .334f, .460f, .488f,
+  .494f, .703f, .680f, .751f, .836f, .897f, .031f, .065f, .100f, .132f, .207f, .229f, .289f, .342f, .435f, .346f, .461f,
+  .482f, .568f, .625f, .738f, .875f, .043f, .093f, .146f, .180f, .241f, .278f, .307f, .330f, .391f, .451f, .472f, .524f,
+  .610f, .651f, .741f, .874f, .029f, .067f, .107f, .140f, .212f, .233f, .269f, .343f, .369f, .393f, .444f, .494f, .575f,
+  .651f, .740f, .882f, .042f, .093f, .151f, .188f, .238f, .271f, .293f, .321f, .408f, .459f, .513f, .553f, .609f, .672f,
+  .777f, .893f, .021f, .055f, .098f, .053f, .210f, .226f, .355f, .247f, .439f, .514f, .637f, .836f, .333f, .420f, .227f,
+  .313f, .019f, .060f, .098f, .133f, .147f, .179f, .237f, .125f, .196f, .407f, .451f, .477f, .572f, .654f, .774f, .903f,
+  .239f, .375f, .204f, .250f, .150f, .150f, .096f, .057f, .426f, .383f, .403f, .468f, .441f, .525f, .616f, .689f, .407f,
+  .407f, .126f, .244f, .134f, .203f, .294f, .406f, .449f, .469f, .573f, .482f, .751f, .751f, .836f, .897f, .031f, .065f,
+  .100f, .132f, .212f, .232f, .281f, .348f, .435f, .346f, .461f, .482f, .568f, .625f, .738f, .875f, .043f, .093f, .152f,
+  .190f, .235f, .262f, .295f, .330f, .354f, .417f, .455f, .492f, .620f, .685f, .768f, .888f, .029f, .067f, .107f, .140f,
+  .167f, .219f, .238f, .298f, .352f, .382f, .443f, .485f, .532f, .596f, .714f, .832f, .056f, .105f, .161f, .195f, .230f,
+  .267f, .289f, .322f, .367f, .414f, .462f, .529f, .579f, .667f, .742f, .875f, .021f, .053f, .094f, .052f, .214f, .235f,
+  .288f, .235f, .451f, .530f, .632f, .826f, .316f, .233f, .466f, .356f, .019f, .060f, .084f, .110f, .192f, .162f, .235f,
+  .287f, .418f, .363f, .447f, .482f, .573f, .631f, .724f, .880f, .243f, .248f, .210f, .074f, .237f, .308f, .378f, .334f,
+  .391f, .428f, .441f, .525f, .593f, .668f, .760f, .637f, .398f, .398f, .235f, .418f, .105f, .166f, .287f, .405f, .458f,
+  .482f, .589f, .488f, .630f, .630f, .751f, .866f, .031f, .065f, .100f, .132f, .218f, .235f, .269f, .344f, .400f, .435f,
+  .478f, .396f, .568f, .625f, .738f, .875f, .056f, .106f, .160f, .190f, .215f, .248f, .292f, .331f, .383f, .415f, .459f,
+  .503f, .594f, .678f, .783f, .898f, .029f, .067f, .108f, .144f, .226f, .241f, .293f, .353f, .275f, .384f, .446f, .502f,
+  .579f, .651f, .740f, .882f, .038f, .077f, .112f, .161f, .202f, .241f, .289f, .323f, .362f, .410f, .462f, .515f, .582f,
+  .658f, .727f, .868f, .021f, .053f, .094f, .052f, .227f, .249f, .316f, .237f, .483f, .630f, .726f, .836f, .583f, .493f,
+  .274f, .426f, .034f, .080f, .109f, .146f, .210f, .181f, .285f, .223f, .385f, .436f, .469f, .544f, .576f, .619f, .714f,
+  .880f, .250f, .248f, .218f, .074f, .241f, .293f, .378f, .334f, .408f, .522f, .409f, .317f, .547f, .397f, .616f, .689f,
+  .410f, .308f, .440f, .469f, .111f, .160f, .250f, .328f, .516f, .674f, .506f, .506f, .685f, .751f, .836f, .897f, .031f,
+  .065f, .100f, .132f, .229f, .267f, .359f, .244f, .442f, .346f, .461f, .482f, .568f, .625f, .738f, .875f, .056f, .106f,
+  .160f, .190f, .219f, .255f, .302f, .340f, .392f, .421f, .463f, .496f, .578f, .642f, .717f, .869f, .029f, .067f, .108f,
+  .144f, .223f, .250f, .318f, .362f, .400f, .444f, .476f, .508f, .579f, .651f, .740f, .882f, .032f, .096f, .155f, .192f,
+  .227f, .255f, .306f, .349f, .381f, .418f, .464f, .519f, .589f, .653f, .721f, .867f, .018f, .049f, .037f, .080f, .201f,
+  .248f, .091f, .152f, .229f, .253f, .323f, .259f, .632f, .826f, .274f, .428f, .028f, .096f, .165f, .230f, .434f, .361f,
+  .449f, .500f, .554f, .596f, .610f, .679f, .678f, .743f, .801f, .903f, .260f, .248f, .208f, .243f, .259f, .302f, .414f,
+  .315f, .408f, .522f, .409f, .317f, .535f, .620f, .357f, .692f, .405f, .266f, .432f, .463f, .111f, .170f, .250f, .328f,
+  .535f, .656f, .525f, .525f, .693f, .751f, .836f, .897f, .031f, .065f, .100f, .132f, .211f, .249f, .320f, .372f, .478f,
+  .396f, .568f, .608f, .647f, .738f, .849f, .902f, .032f, .095f, .153f, .190f, .237f, .269f, .305f, .344f, .390f, .423f,
+  .465f, .514f, .581f, .637f, .718f, .869f, .033f, .072f, .110f, .152f, .214f, .250f, .273f, .316f, .419f, .449f, .476f,
+  .508f, .579f, .651f, .740f, .882f, .039f, .095f, .144f, .185f, .250f, .296f, .323f, .362f, .416f, .467f, .502f, .531f,
+  .589f, .643f, .714f, .867f, .018f, .049f, .036f, .079f, .095f, .246f, .091f, .131f, .233f, .268f, .342f, .294f, .609f,
+  .690f, .814f, .930f, .037f, .093f, .146f, .175f, .270f, .226f, .408f, .339f, .448f, .303f, .472f, .506f, .580f, .640f,
+  .726f, .880f, .273f, .235f, .283f, .319f, .117f, .096f, .070f, .044f, .475f, .609f, .357f, .692f, .414f, .278f, .536f,
+  .462f, .374f, .229f, .139f, .344f, .414f, .441f, .505f, .402f, .496f, .572f, .606f, .526f, .680f, .751f, .836f, .897f,
+  .031f, .072f, .110f, .157f, .239f, .277f, .437f, .352f, .565f, .578f, .631f, .514f, .748f, .578f, .849f, .902f, .039f,
+  .095f, .152f, .202f, .252f, .305f, .345f, .432f, .423f, .467f, .509f, .544f, .592f, .640f, .713f, .869f, .028f, .062f,
+  .089f, .120f, .152f, .173f, .191f, .211f, .252f, .277f, .302f, .324f, .446f, .502f, .592f, .767f, .043f, .090f, .136f,
+  .191f, .256f, .311f, .359f, .390f, .424f, .470f, .492f, .534f, .593f, .655f, .776f, .893f, .012f, .032f, .021f, .058f,
+  .093f, .135f, .059f, .026f, .228f, .270f, .292f, .324f, .609f, .690f, .814f, .930f, .042f, .097f, .141f, .176f, .218f,
+  .342f, .143f, .270f, .446f, .303f, .480f, .516f, .580f, .627f, .774f, .903f, .292f, .238f, .299f, .331f, .117f, .096f,
+  .070f, .044f, .430f, .536f, .612f, .347f, .593f, .668f, .760f, .637f, .386f, .214f, .133f, .342f, .405f, .444f, .507f,
+  .442f, .464f, .479f, .565f, .517f, .680f, .751f, .836f, .897f, .031f, .065f, .100f, .131f, .165f, .188f, .204f, .222f,
+  .275f, .303f, .336f, .383f, .568f, .625f, .738f, .875f, .046f, .101f, .141f, .193f, .256f, .302f, .345f, .451f, .425f,
+  .468f, .509f, .535f, .586f, .649f, .744f, .874f, .028f, .062f, .089f, .120f, .155f, .189f, .214f, .247f, .310f, .338f,
+  .392f, .444f, .497f, .581f, .690f, .832f, .049f, .101f, .142f, .181f, .211f, .247f, .287f, .325f, .377f, .426f, .473f,
+  .530f, .587f, .645f, .745f, .875f, .021f, .055f, .098f, .053f, .280f, .306f, .168f, .226f, .257f, .314f, .351f, .309f,
+  .609f, .690f, .814f, .930f, .048f, .102f, .140f, .185f, .274f, .321f, .143f, .250f, .443f, .359f, .443f, .483f, .542f,
+  .609f, .746f, .894f, .317f, .252f, .324f, .348f, .117f, .096f, .070f, .044f, .594f, .404f, .499f, .531f, .593f, .668f,
+  .760f, .637f, .402f, .260f, .124f, .345f, .382f, .444f, .423f, .448f, .473f, .511f, .563f, .516f, .680f, .751f, .836f,
+  .897f, .031f, .065f, .100f, .132f, .166f, .188f, .207f, .225f, .301f, .322f, .341f, .404f, .475f, .579f, .693f, .875f,
+  .048f, .100f, .142f, .187f, .216f, .244f, .283f, .318f, .378f, .430f, .473f, .525f, .586f, .642f, .744f, .874f, .028f,
+  .062f, .089f, .120f, .155f, .189f, .215f, .249f, .274f, .345f, .363f, .409f, .502f, .581f, .690f, .832f, .053f, .095f,
+  .132f, .175f, .211f, .243f, .288f, .326f, .399f, .434f, .474f, .527f, .579f, .637f, .745f, .875f, .021f, .053f, .092f,
+  .052f, .054f, .108f, .180f, .116f, .204f, .271f, .321f, .362f, .609f, .690f, .814f, .930f, .054f, .105f, .177f, .148f,
+  .216f, .260f, .394f, .301f, .226f, .381f, .443f, .484f, .588f, .680f, .774f, .903f, .339f, .339f, .248f, .248f, .222f,
+  .288f, .111f, .057f, .352f, .366f, .422f, .505f, .593f, .668f, .760f, .637f, .387f, .016f, .160f, .380f, .113f, .221f,
+  .346f, .410f, .442f, .482f, .474f, .496f, .563f, .508f, .700f, .866f, .031f, .065f, .100f, .131f, .148f, .177f, .202f,
+  .218f, .338f, .280f, .357f, .420f, .568f, .625f, .738f, .875f, .053f, .098f, .135f, .175f, .212f, .242f, .277f, .307f,
+  .384f, .434f, .476f, .536f, .594f, .644f, .744f, .874f, .029f, .067f, .107f, .140f, .184f, .215f, .249f, .274f, .335f,
+  .376f, .406f, .479f, .579f, .651f, .740f, .882f, .056f, .085f, .129f, .177f, .209f, .238f, .289f, .323f, .361f, .413f,
+  .471f, .539f, .601f, .677f, .776f, .893f, .021f, .055f, .098f, .053f, .138f, .211f, .281f, .183f, .345f, .232f, .387f,
+  .290f, .609f, .690f, .814f, .930f, .057f, .083f, .167f, .124f, .232f, .182f, .401f, .293f, .226f, .358f, .445f, .497f,
+  .581f, .654f, .774f, .903f, .353f, .353f, .248f, .248f, .112f, .240f, .290f, .096f, .354f, .374f, .393f, .433f, .595f,
+  .468f, .648f, .692f, .378f, .016f, .106f, .339f, .119f, .191f, .327f, .397f, .446f, .477f, .512f, .549f, .680f, .751f,
+  .836f, .897f, .031f, .065f, .100f, .132f, .172f, .211f, .338f, .261f, .349f, .375f, .402f, .437f, .568f, .625f, .738f,
+  .875f, .057f, .086f, .129f, .173f, .199f, .232f, .280f, .306f, .366f, .419f, .471f, .531f, .592f, .652f, .744f, .874f,
+  .029f, .067f, .107f, .140f, .184f, .215f, .249f, .286f, .371f, .396f, .420f, .443f, .477f, .533f, .682f, .832f, .047f,
+  .094f, .134f, .165f, .205f, .237f, .277f, .306f, .366f, .411f, .466f, .519f, .558f, .619f, .727f, .868f, .021f, .055f,
+  .098f, .053f, .115f, .175f, .238f, .195f, .305f, .390f, .332f, .232f, .424f, .243f, .626f, .826f, .030f, .071f, .108f,
+  .138f, .195f, .114f, .295f, .240f, .320f, .362f, .424f, .489f, .542f, .613f, .730f, .880f, .385f, .385f, .248f, .375f,
+  .172f, .262f, .393f, .347f, .364f, .416f, .412f, .433f, .448f, .486f, .648f, .533f, .354f, .016f, .183f, .308f, .111f,
+  .177f, .269f, .346f, .414f, .440f, .454f, .520f, .507f, .544f, .700f, .866f, .031f, .065f, .100f, .132f, .172f, .210f,
+  .232f, .261f, .323f, .361f, .390f, .418f, .444f, .468f, .548f, .773f, .030f, .072f, .110f, .153f, .205f, .246f, .283f,
+  .312f, .355f, .399f, .461f, .532f, .594f, .652f, .744f, .874f, .029f, .067f, .108f, .147f, .206f, .237f, .286f, .334f,
+  .358f, .424f, .461f, .494f, .522f, .565f, .791f, .882f, .039f, .091f, .132f, .168f, .214f, .244f, .278f, .311f, .373f,
+  .413f, .465f, .521f, .596f, .677f, .776f, .893f, .021f, .055f, .098f, .053f, .166f, .219f, .411f, .273f, .379f, .461f,
+  .256f, .206f, .501f, .264f, .587f, .816f, .031f, .066f, .104f, .139f, .154f, .187f, .203f, .241f, .318f, .360f, .414f,
+  .493f, .621f, .692f, .775f, .903f, .429f, .223f, .430f, .462f, .480f, .504f, .532f, .555f, .170f, .266f, .111f, .057f,
+  .327f, .407f, .441f, .475f, .307f, .307f, .126f, .257f, .091f, .171f, .253f, .332f, .390f, .420f, .457f, .488f, .573f,
+  .503f, .700f, .866f, .031f, .065f, .100f, .132f, .176f, .215f, .261f, .311f, .386f, .439f, .466f, .489f, .562f, .514f,
+  .612f, .773f, .033f, .073f, .102f, .146f, .177f, .216f, .255f, .295f, .323f, .388f, .450f, .502f, .580f, .644f, .744f,
+  .874f, .029f, .067f, .108f, .147f, .210f, .259f, .308f, .364f, .503f, .543f, .584f, .646f, .723f, .578f, .791f, .882f,
+  .028f, .068f, .122f, .163f, .194f, .231f, .273f, .310f, .357f, .403f, .464f, .533f, .596f, .677f, .776f, .893f, .048f,
+  .094f, .177f, .218f, .307f, .432f, .273f, .229f, .500f, .253f, .603f, .513f, .754f, .673f, .825f, .930f, .018f, .062f,
+  .102f, .129f, .142f, .173f, .188f, .226f, .391f, .313f, .471f, .402f, .621f, .692f, .775f, .903f, .489f, .443f, .207f,
+  .494f, .541f, .577f, .648f, .720f, .175f, .237f, .111f, .057f, .287f, .335f, .409f, .374f, .264f, .187f, .285f, .318f,
+  .156f, .106f, .341f, .251f, .380f, .391f, .432f, .475f, .584f, .513f, .700f, .866f, .031f, .068f, .108f, .157f, .212f,
+  .261f, .312f, .371f, .483f, .517f, .571f, .611f, .665f, .738f, .849f, .902f, .028f, .068f, .120f, .154f, .188f, .219f,
+  .259f, .305f, .338f, .387f, .454f, .520f, .609f, .691f, .768f, .888f};
diff --git a/contrib/modules/xphoto/src/simple_color_balance.cpp b/contrib/modules/xphoto/src/simple_color_balance.cpp
index f755e71..e357dd7 100644
--- a/contrib/modules/xphoto/src/simple_color_balance.cpp
+++ b/contrib/modules/xphoto/src/simple_color_balance.cpp
@@ -37,175 +37,176 @@
 //
 //M*/
 
-#include <vector>
 #include <algorithm>
-#include <iterator>
 #include <iostream>
-
-#include "opencv2/xphoto.hpp"
-
-#include "opencv2/imgproc.hpp"
+#include <iterator>
+#include <vector>
 
 #include "opencv2/core.hpp"
-#include "opencv2/core/core_c.h"
-
-#include "opencv2/core/types.hpp"
-#include "opencv2/core/types_c.h"
+#include "opencv2/imgproc.hpp"
+#include "opencv2/xphoto.hpp"
 
 namespace cv
 {
 namespace xphoto
 {
 
-    template <typename T>
-    void balanceWhite(std::vector < Mat_<T> > &src, Mat &dst,
-        const float inputMin, const float inputMax,
-        const float outputMin, const float outputMax, const int algorithmType)
+template <typename T>
+void balanceWhiteSimple(std::vector<Mat_<T> > &src, Mat &dst, const float inputMin, const float inputMax,
+                        const float outputMin, const float outputMax, const float p)
+{
+    /********************* Simple white balance *********************/
+    const float s1 = p; // low quantile
+    const float s2 = p; // high quantile
+
+    int depth = 2; // depth of histogram tree
+    if (src[0].depth() != CV_8U)
+        ++depth;
+    int bins = 16; // number of bins at each histogram level
+
+    int nElements = int(pow((float)bins, (float)depth));
+    // number of elements in histogram tree
+
+    for (size_t i = 0; i < src.size(); ++i)
     {
-        switch ( algorithmType )
+        std::vector<int> hist(nElements, 0);
+
+        typename Mat_<T>::iterator beginIt = src[i].begin();
+        typename Mat_<T>::iterator endIt = src[i].end();
+
+        for (typename Mat_<T>::iterator it = beginIt; it != endIt; ++it)
+        // histogram filling
         {
-            case WHITE_BALANCE_SIMPLE:
-                {
-                    /********************* Simple white balance *********************/
-                    float s1 = 2.0f; // low quantile
-                    float s2 = 2.0f; // high quantile
-
-                    int depth = 2; // depth of histogram tree
-                    if (src[0].depth() != CV_8U)
-                        ++depth;
-                    int bins = 16; // number of bins at each histogram level
-
-                    int nElements = int( pow((float)bins, (float)depth) );
-                     // number of elements in histogram tree
-
-                    for (size_t i = 0; i < src.size(); ++i)
-                    {
-                        std::vector <int> hist(nElements, 0);
-
-                        typename Mat_<T>::iterator beginIt = src[i].begin();
-                        typename Mat_<T>::iterator endIt = src[i].end();
-
-                        for (typename Mat_<T>::iterator it = beginIt; it != endIt; ++it)
-                         // histogram filling
-                        {
-                            int pos = 0;
-                            float minValue = inputMin - 0.5f;
-                            float maxValue = inputMax + 0.5f;
-                            T val = *it;
-
-                            float interval = float(maxValue - minValue) / bins;
-
-                            for (int j = 0; j < depth; ++j)
-                            {
-                                int currentBin = int( (val - minValue + 1e-4f) / interval );
-                                ++hist[pos + currentBin];
-
-                                pos = (pos + currentBin)*bins;
-
-                                minValue = minValue + currentBin*interval;
-                                maxValue = minValue + interval;
-
-                                interval /= bins;
-                            }
-                        }
-
-                        int total = int( src[i].total() );
-
-                        int p1 = 0, p2 = bins - 1;
-                        int n1 = 0, n2 = total;
-
-                        float minValue = inputMin - 0.5f;
-                        float maxValue = inputMax + 0.5f;
-
-                        float interval = (maxValue - minValue) / float(bins);
-
-                        for (int j = 0; j < depth; ++j)
-                         // searching for s1 and s2
-                        {
-                            while (n1 + hist[p1] < s1 * total / 100.0f)
-                            {
-                                n1 += hist[p1++];
-                                minValue += interval;
-                            }
-                            p1 *= bins;
-
-                            while (n2 - hist[p2] > (100.0f - s2) * total / 100.0f)
-                            {
-                                n2 -= hist[p2--];
-                                maxValue -= interval;
-                            }
-                            p2 = p2*bins - 1;
-
-                            interval /= bins;
-                        }
-
-                        src[i] = (outputMax - outputMin) * (src[i] - minValue)
-                            / (maxValue - minValue) + outputMin;
-                    }
-                    /****************************************************************/
-                    break;
-                }
-            default:
-                CV_Error_( CV_StsNotImplemented,
-                    ("Unsupported algorithm type (=%d)", algorithmType) );
+            int pos = 0;
+            float minValue = inputMin - 0.5f;
+            float maxValue = inputMax + 0.5f;
+            T val = *it;
+
+            float interval = float(maxValue - minValue) / bins;
+
+            for (int j = 0; j < depth; ++j)
+            {
+                int currentBin = int((val - minValue + 1e-4f) / interval);
+                ++hist[pos + currentBin];
+
+                pos = (pos + currentBin) * bins;
+
+                minValue = minValue + currentBin * interval;
+                maxValue = minValue + interval;
+
+                interval /= bins;
+            }
         }
 
-        dst.create(/**/ src[0].size(), CV_MAKETYPE( src[0].depth(), int( src.size() ) ) /**/);
-        cv::merge(src, dst);
+        int total = int(src[i].total());
+
+        int p1 = 0, p2 = bins - 1;
+        int n1 = 0, n2 = total;
+
+        float minValue = inputMin - 0.5f;
+        float maxValue = inputMax + 0.5f;
+
+        float interval = (maxValue - minValue) / float(bins);
+
+        for (int j = 0; j < depth; ++j)
+        // searching for s1 and s2
+        {
+            while (n1 + hist[p1] < s1 * total / 100.0f)
+            {
+                n1 += hist[p1++];
+                minValue += interval;
+            }
+            p1 *= bins;
+
+            while (n2 - hist[p2] > (100.0f - s2) * total / 100.0f)
+            {
+                n2 -= hist[p2--];
+                maxValue -= interval;
+            }
+            p2 = (p2 + 1) * bins - 1;
+
+            interval /= bins;
+        }
+
+        src[i] = (outputMax - outputMin) * (src[i] - minValue) / (maxValue - minValue) + outputMin;
     }
+    /****************************************************************/
+
+    dst.create(/**/ src[0].size(), CV_MAKETYPE(src[0].depth(), int(src.size())) /**/);
+    cv::merge(src, dst);
+}
+
+class SimpleWBImpl : public SimpleWB
+{
+  private:
+    float inputMin, inputMax, outputMin, outputMax, p;
 
-    /*!
-    * Wrappers over different white balance algorithm
-    *
-    * \param src : source image (RGB)
-    * \param dst : destination image
-    *
-    * \param inputMin : minimum input value
-    * \param inputMax : maximum input value
-    * \param outputMin : minimum output value
-    * \param outputMax : maximum output value
-    *
-    * \param algorithmType : type of the algorithm to use
-    */
-    void balanceWhite(const Mat &src, Mat &dst, const int algorithmType,
-        const float inputMin, const float inputMax,
-        const float outputMin, const float outputMax)
+  public:
+    SimpleWBImpl()
     {
-        switch ( src.depth() )
+        inputMin = 0.0f;
+        inputMax = 255.0f;
+        outputMin = 0.0f;
+        outputMax = 255.0f;
+        p = 2.0f;
+    }
+
+    float getInputMin() const { return inputMin; }
+    void setInputMin(float val) { inputMin = val; }
+
+    float getInputMax() const { return inputMax; }
+    void setInputMax(float val) { inputMax = val; }
+
+    float getOutputMin() const { return outputMin; }
+    void setOutputMin(float val) { outputMin = val; }
+
+    float getOutputMax() const { return outputMax; }
+    void setOutputMax(float val) { outputMax = val; }
+
+    float getP() const { return p; }
+    void setP(float val) { p = val; }
+
+    void balanceWhite(InputArray _src, OutputArray _dst)
+    {
+        CV_Assert(!_src.empty());
+        CV_Assert(_src.depth() == CV_8U || _src.depth() == CV_16S || _src.depth() == CV_32S || _src.depth() == CV_32F);
+        Mat src = _src.getMat();
+        Mat &dst = _dst.getMatRef();
+
+        switch (src.depth())
+        {
+        case CV_8U:
+        {
+            std::vector<Mat_<uchar> > mv;
+            split(src, mv);
+            balanceWhiteSimple(mv, dst, inputMin, inputMax, outputMin, outputMax, p);
+            break;
+        }
+        case CV_16S:
         {
-            case CV_8U:
-                {
-                    std::vector < Mat_<uchar> > mv;
-                    split(src, mv);
-                    balanceWhite(mv, dst, inputMin, inputMax, outputMin, outputMax, algorithmType);
-                    break;
-                }
-            case CV_16S:
-                {
-                    std::vector < Mat_<short> > mv;
-                    split(src, mv);
-                    balanceWhite(mv, dst, inputMin, inputMax, outputMin, outputMax, algorithmType);
-                    break;
-                }
-            case CV_32S:
-                {
-                    std::vector < Mat_<int> > mv;
-                    split(src, mv);
-                    balanceWhite(mv, dst, inputMin, inputMax, outputMin, outputMax, algorithmType);
-                    break;
-                }
-            case CV_32F:
-                {
-                    std::vector < Mat_<float> > mv;
-                    split(src, mv);
-                    balanceWhite(mv, dst, inputMin, inputMax, outputMin, outputMax, algorithmType);
-                    break;
-                }
-            default:
-                CV_Error_( CV_StsNotImplemented,
-                    ("Unsupported source image format (=%d)", src.type()) );
-                break;
+            std::vector<Mat_<short> > mv;
+            split(src, mv);
+            balanceWhiteSimple(mv, dst, inputMin, inputMax, outputMin, outputMax, p);
+            break;
+        }
+        case CV_32S:
+        {
+            std::vector<Mat_<int> > mv;
+            split(src, mv);
+            balanceWhiteSimple(mv, dst, inputMin, inputMax, outputMin, outputMax, p);
+            break;
+        }
+        case CV_32F:
+        {
+            std::vector<Mat_<float> > mv;
+            split(src, mv);
+            balanceWhiteSimple(mv, dst, inputMin, inputMax, outputMin, outputMax, p);
+            break;
+        }
         }
     }
+};
+
+Ptr<SimpleWB> createSimpleWB() { return makePtr<SimpleWBImpl>(); }
 }
 }
diff --git a/contrib/modules/xphoto/test/simple_color_balance.cpp b/contrib/modules/xphoto/test/simple_color_balance.cpp
index bf30271..b1f4413 100644
--- a/contrib/modules/xphoto/test/simple_color_balance.cpp
+++ b/contrib/modules/xphoto/test/simple_color_balance.cpp
@@ -5,8 +5,8 @@ namespace cvtest
     TEST(xphoto_simplecolorbalance, regression)
     {
         cv::String dir = cvtest::TS::ptr()->get_data_path() + "cv/xphoto/simple_white_balance/";
-        int nTests = 12;
-        float threshold = 0.005f;
+        int nTests = 8;
+        cv::Ptr<cv::xphoto::WhiteBalancer> wb = cv::xphoto::createSimpleWB();
 
         for (int i = 0; i < nTests; ++i)
         {
@@ -14,17 +14,41 @@ namespace cvtest
             cv::Mat src = cv::imread( srcName, 1 );
             ASSERT_TRUE(!src.empty());
 
-            cv::String previousResultName = dir + cv::format( "results/%02d.png", i + 1 );
+            cv::String previousResultName = dir + cv::format( "results/%02d.jpg", i + 1 );
             cv::Mat previousResult = cv::imread( previousResultName, 1 );
 
             cv::Mat currentResult;
-            cv::xphoto::balanceWhite(src, currentResult, cv::xphoto::WHITE_BALANCE_SIMPLE);
+            wb->balanceWhite(src, currentResult);
 
-            cv::Mat sqrError = ( currentResult - previousResult )
-                .mul( currentResult - previousResult );
-            cv::Scalar mse = cv::sum(sqrError) / cv::Scalar::all( double( sqrError.total()*sqrError.channels() ) );
+            double psnr = cv::PSNR(currentResult, previousResult);
 
-            EXPECT_LE( mse[0]+mse[1]+mse[2]+mse[3], threshold );
+            EXPECT_GE( psnr, 30 );
         }
     }
+
+    TEST(xphoto_simplecolorbalance, max_value)
+    {
+        const float oldMax = 24000., newMax = 65536.;
+
+        Mat test = Mat::zeros(3,3,CV_32FC1);
+        test.at<float>(0, 0) = oldMax;
+        test.at<float>(0, 1) = oldMax / 2;
+        test.at<float>(0, 2) = oldMax / 4;
+
+        double minSrc, maxSrc;
+        cv::minMaxIdx(test, &minSrc, &maxSrc);
+
+        cv::Ptr<cv::xphoto::SimpleWB> wb = cv::xphoto::createSimpleWB();
+        wb->setInputMin((float)minSrc);
+        wb->setInputMax((float)maxSrc);
+        wb->setOutputMin(0);
+        wb->setOutputMax(newMax);
+
+        wb->balanceWhite(test, test);
+
+        double minDst, maxDst;
+        cv::minMaxIdx(test, &minDst, &maxDst);
+
+        ASSERT_NEAR(maxDst, newMax, newMax*1e-4);
+    }
 }
diff --git a/contrib/modules/xphoto/test/test_denoise_bm3d.cpp b/contrib/modules/xphoto/test/test_denoise_bm3d.cpp
new file mode 100644
index 0000000..01968ae
--- /dev/null
+++ b/contrib/modules/xphoto/test/test_denoise_bm3d.cpp
@@ -0,0 +1,465 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+//  By downloading, copying, installing or using the software you agree to this license.
+//  If you do not agree to this license, do not download, install,
+//  copy or use the software.
+//
+//
+//                           License Agreement
+//                For Open Source Computer Vision Library
+//
+// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
+// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+//   * Redistribution's of source code must retain the above copyright notice,
+//     this list of conditions and the following disclaimer.
+//
+//   * Redistribution's in binary form must reproduce the above copyright notice,
+//     this list of conditions and the following disclaimer in the documentation
+//     and/or other materials provided with the distribution.
+//
+//   * The name of the copyright holders may not be used to endorse or promote products
+//     derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "test_precomp.hpp"
+#include <string>
+
+//#define DUMP_RESULTS
+//#define TEST_TRANSFORMS
+
+#ifdef TEST_TRANSFORMS
+#include "..\..\xphoto\src\bm3d_denoising_invoker_commons.hpp"
+#include "..\..\xphoto\src\bm3d_denoising_transforms.hpp"
+#include "..\..\xphoto\src\kaiser_window.hpp"
+using namespace cv::xphoto;
+#endif
+
+#ifdef DUMP_RESULTS
+#  define DUMP(image, path) imwrite(path, image)
+#else
+#  define DUMP(image, path)
+#endif
+
+#ifdef OPENCV_ENABLE_NONFREE
+
+namespace cvtest
+{
+    TEST(xphoto_DenoisingBm3dGrayscale, regression_L2)
+    {
+        std::string folder = std::string(cvtest::TS::ptr()->get_data_path()) + "cv/xphoto/bm3d_image_denoising/";
+        std::string original_path = folder + "lena_noised_gaussian_sigma=10.png";
+        std::string expected_path = folder + "lena_noised_denoised_bm3d_wiener_grayscale_l2_tw=4_sw=16_h=10_bm=400.png";
+
+        cv::Mat original = cv::imread(original_path, cv::IMREAD_GRAYSCALE);
+        cv::Mat expected = cv::imread(expected_path, cv::IMREAD_GRAYSCALE);
+
+        ASSERT_FALSE(original.empty()) << "Could not load input image " << original_path;
+        ASSERT_FALSE(expected.empty()) << "Could not load reference image " << expected_path;
+
+        // BM3D: two different calls doing exactly the same thing
+        cv::Mat result, resultSec;
+        cv::xphoto::bm3dDenoising(original, cv::Mat(), resultSec, 10, 4, 16, 2500, 400, 8, 1, 0.0f, cv::NORM_L2, cv::xphoto::BM3D_STEPALL);
+        cv::xphoto::bm3dDenoising(original, result, 10, 4, 16, 2500, 400, 8, 1, 0.0f, cv::NORM_L2, cv::xphoto::BM3D_STEPALL);
+
+        DUMP(result, expected_path + ".res.png");
+
+        ASSERT_EQ(cvtest::norm(result, resultSec, cv::NORM_L2), 0);
+        ASSERT_LT(cvtest::norm(result, expected, cv::NORM_L2), 200);
+    }
+
+    TEST(xphoto_DenoisingBm3dGrayscale, regression_L2_separate)
+    {
+        std::string folder = std::string(cvtest::TS::ptr()->get_data_path()) + "cv/xphoto/bm3d_image_denoising/";
+        std::string original_path = folder + "lena_noised_gaussian_sigma=10.png";
+        std::string expected_basic_path = folder + "lena_noised_denoised_bm3d_grayscale_l2_tw=4_sw=16_h=10_bm=2500.png";
+        std::string expected_path = folder + "lena_noised_denoised_bm3d_wiener_grayscale_l2_tw=4_sw=16_h=10_bm=400.png";
+
+        cv::Mat original = cv::imread(original_path, cv::IMREAD_GRAYSCALE);
+        cv::Mat expected_basic = cv::imread(expected_basic_path, cv::IMREAD_GRAYSCALE);
+        cv::Mat expected = cv::imread(expected_path, cv::IMREAD_GRAYSCALE);
+
+        ASSERT_FALSE(original.empty()) << "Could not load input image " << original_path;
+        ASSERT_FALSE(expected_basic.empty()) << "Could not load reference image " << expected_basic_path;
+        ASSERT_FALSE(expected.empty()) << "Could not load input image " << expected_path;
+
+        cv::Mat basic, result;
+
+        // BM3D step 1
+        cv::xphoto::bm3dDenoising(original, basic, 10, 4, 16, 2500, -1, 8, 1, 0.0f, cv::NORM_L2, cv::xphoto::BM3D_STEP1);
+        ASSERT_LT(cvtest::norm(basic, expected_basic, cv::NORM_L2), 200);
+        DUMP(basic, expected_basic_path + ".res.basic.png");
+
+        // BM3D step 2
+        cv::xphoto::bm3dDenoising(original, basic, result, 10, 4, 16, 2500, 400, 8, 1, 0.0f, cv::NORM_L2, cv::xphoto::BM3D_STEP2);
+        ASSERT_LT(cvtest::norm(basic, expected_basic, cv::NORM_L2), 200);
+        DUMP(basic, expected_basic_path + ".res.basic2.png");
+
+        DUMP(result, expected_path + ".res.png");
+
+        ASSERT_LT(cvtest::norm(result, expected, cv::NORM_L2), 200);
+    }
+
+    TEST(xphoto_DenoisingBm3dGrayscale, regression_L1)
+    {
+        std::string folder = std::string(cvtest::TS::ptr()->get_data_path()) + "cv/xphoto/bm3d_image_denoising/";
+        std::string original_path = folder + "lena_noised_gaussian_sigma=10.png";
+        std::string expected_path = folder + "lena_noised_denoised_bm3d_grayscale_l1_tw=4_sw=16_h=10_bm=2500.png";
+
+        cv::Mat original = cv::imread(original_path, cv::IMREAD_GRAYSCALE);
+        cv::Mat expected = cv::imread(expected_path, cv::IMREAD_GRAYSCALE);
+
+        ASSERT_FALSE(original.empty()) << "Could not load input image " << original_path;
+        ASSERT_FALSE(expected.empty()) << "Could not load reference image " << expected_path;
+
+        cv::Mat result;
+        cv::xphoto::bm3dDenoising(original, result, 10, 4, 16, 2500, -1, 8, 1, 0.0f, cv::NORM_L1, cv::xphoto::BM3D_STEP1);
+
+        DUMP(result, expected_path + ".res.png");
+
+        ASSERT_LT(cvtest::norm(result, expected, cv::NORM_L2), 200);
+    }
+
+    TEST(xphoto_DenoisingBm3dGrayscale, regression_L2_8x8)
+    {
+        std::string folder = std::string(cvtest::TS::ptr()->get_data_path()) + "cv/xphoto/bm3d_image_denoising/";
+        std::string original_path = folder + "lena_noised_gaussian_sigma=10.png";
+        std::string expected_path = folder + "lena_noised_denoised_bm3d_grayscale_l2_tw=8_sw=16_h=10_bm=2500.png";
+
+        cv::Mat original = cv::imread(original_path, cv::IMREAD_GRAYSCALE);
+        cv::Mat expected = cv::imread(expected_path, cv::IMREAD_GRAYSCALE);
+
+        ASSERT_FALSE(original.empty()) << "Could not load input image " << original_path;
+        ASSERT_FALSE(expected.empty()) << "Could not load reference image " << expected_path;
+
+        cv::Mat result;
+        cv::xphoto::bm3dDenoising(original, result, 10, 8, 16, 2500, -1, 8, 1, 0.0f, cv::NORM_L2, cv::xphoto::BM3D_STEP1);
+
+        DUMP(result, expected_path + ".res.png");
+
+        ASSERT_LT(cvtest::norm(result, expected, cv::NORM_L2), 200);
+    }
+
+#ifdef TEST_TRANSFORMS
+
+    TEST(xphoto_DenoisingBm3dKaiserWindow, regression_4)
+    {
+        float beta = 2.0f;
+        int N = 4;
+
+        cv::Mat kaiserWindow;
+        calcKaiserWindow1D(kaiserWindow, N, beta);
+
+        float kaiser4[] = {
+            0.43869004f,
+            0.92432547f,
+            0.92432547f,
+            0.43869004f
+        };
+
+        for (int i = 0; i < N; ++i)
+            ASSERT_FLOAT_EQ(kaiser4[i], kaiserWindow.at<float>(i));
+    }
+
+    TEST(xphoto_DenoisingBm3dKaiserWindow, regression_8)
+    {
+        float beta = 2.0f;
+        int N = 8;
+
+        cv::Mat kaiserWindow;
+        calcKaiserWindow1D(kaiserWindow, N, beta);
+
+        float kaiser8[] = {
+            0.43869004f,
+            0.68134475f,
+            0.87685609f,
+            0.98582518f,
+            0.98582518f,
+            0.87685609f,
+            0.68134463f,
+            0.43869004f
+        };
+
+        for (int i = 0; i < N; ++i)
+            ASSERT_FLOAT_EQ(kaiser8[i], kaiserWindow.at<float>(i));
+    }
+
+    TEST(xphoto_DenoisingBm3dTransforms, regression_2D_generic)
+    {
+        const int templateWindowSize = 8;
+        const int templateWindowSizeSq = templateWindowSize * templateWindowSize;
+
+        uchar src[templateWindowSizeSq];
+        short dst[templateWindowSizeSq];
+        short dstSec[templateWindowSizeSq];
+
+        // Initialize array
+        for (uchar i = 0; i < templateWindowSizeSq; ++i)
+            src[i] = (i % 10) * 10;
+
+        // Use tailored transforms
+        HaarTransform<uchar, short>::RegisterTransforms2D(templateWindowSize);
+        HaarTransform<uchar, short>::forwardTransform2D(src, dst, templateWindowSize, templateWindowSize);
+        HaarTransform<uchar, short>::inverseTransform2D(dst, templateWindowSize);
+
+        // Use generic transforms
+        HaarTransform2D::ForwardTransformXxX<uchar, short, templateWindowSize>(src, dstSec, templateWindowSize, templateWindowSize);
+        HaarTransform2D::InverseTransformXxX<short, templateWindowSize>(dstSec, templateWindowSize);
+
+        for (unsigned i = 0; i < templateWindowSizeSq; ++i)
+            ASSERT_EQ(dst[i], dstSec[i]);
+    }
+
+    TEST(xphoto_DenoisingBm3dTransforms, regression_2D_4x4)
+    {
+        const int templateWindowSize = 4;
+        const int templateWindowSizeSq = templateWindowSize * templateWindowSize;
+
+        uchar src[templateWindowSizeSq];
+        short dst[templateWindowSizeSq];
+
+        // Initialize array
+        for (uchar i = 0; i < templateWindowSizeSq; ++i)
+        {
+            src[i] = i;
+        }
+
+        HaarTransform2D::ForwardTransform4x4(src, dst, templateWindowSize, templateWindowSize);
+        HaarTransform2D::InverseTransform4x4(dst, templateWindowSize);
+
+        for (uchar i = 0; i < templateWindowSizeSq; ++i)
+            ASSERT_EQ(static_cast<short>(src[i]), dst[i]);
+    }
+
+    TEST(xphoto_DenoisingBm3dTransforms, regression_2D_8x8)
+    {
+        const int templateWindowSize = 8;
+        const int templateWindowSizeSq = templateWindowSize * templateWindowSize;
+
+        uchar src[templateWindowSizeSq];
+        short dst[templateWindowSizeSq];
+
+        // Initialize array
+        for (uchar i = 0; i < templateWindowSizeSq; ++i)
+        {
+            src[i] = i;
+        }
+
+        HaarTransform2D::ForwardTransform8x8(src, dst, templateWindowSize, templateWindowSize);
+        HaarTransform2D::InverseTransform8x8(dst, templateWindowSize);
+
+        for (uchar i = 0; i < templateWindowSizeSq; ++i)
+            ASSERT_EQ(static_cast<short>(src[i]), dst[i]);
+    }
+
+    template <typename T, typename DT, typename CT>
+    static void Test1dTransform(
+        T *thrMap,
+        int groupSize,
+        int templateWindowSizeSq,
+        BlockMatch<T, DT, CT> *bm,
+        BlockMatch<T, DT, CT> *bmOrig,
+        int expectedNonZeroCount = -1)
+    {
+        if (expectedNonZeroCount < 0)
+            expectedNonZeroCount = groupSize * templateWindowSizeSq;
+
+        // Test group size
+        short sumNonZero = 0;
+        T *thrMapPtr1D = thrMap + (groupSize - 1) * templateWindowSizeSq;
+        for (int n = 0; n < templateWindowSizeSq; n++)
+        {
+            switch (groupSize)
+            {
+            case 16:
+                HaarTransform1D::ForwardTransform16(bm, n);
+                sumNonZero += HardThreshold<16>(bm, n, thrMapPtr1D);
+                HaarTransform1D::InverseTransform16(bm, n);
+                break;
+            case 8:
+                HaarTransform1D::ForwardTransform8(bm, n);
+                sumNonZero += HardThreshold<8>(bm, n, thrMapPtr1D);
+                HaarTransform1D::InverseTransform8(bm, n);
+                break;
+            case 4:
+                HaarTransform1D::ForwardTransform4(bm, n);
+                sumNonZero += HardThreshold<4>(bm, n, thrMapPtr1D);
+                HaarTransform1D::InverseTransform4(bm, n);
+                break;
+            case 2:
+                HaarTransform1D::ForwardTransform2(bm, n);
+                sumNonZero += HardThreshold<2>(bm, n, thrMapPtr1D);
+                HaarTransform1D::InverseTransform2(bm, n);
+                break;
+            default:
+                HaarTransform1D::ForwardTransformN(bm, n, groupSize);
+                sumNonZero += HardThreshold(bm, n, thrMapPtr1D, groupSize);
+                HaarTransform1D::InverseTransformN(bm, n, groupSize);
+            }
+        }
+
+        // Assert transform
+        if (expectedNonZeroCount == groupSize * templateWindowSizeSq)
+        {
+            for (int i = 0; i < groupSize; ++i)
+                for (int j = 0; j < templateWindowSizeSq; ++j)
+                    ASSERT_EQ(bm[i][j], bmOrig[i][j]);
+        }
+
+        // Assert shrinkage
+        ASSERT_EQ(sumNonZero, expectedNonZeroCount);
+    }
+
+    TEST(xphoto_DenoisingBm3dTransforms, regression_1D_transform)
+    {
+        const int templateWindowSize = 4;
+        const int templateWindowSizeSq = templateWindowSize * templateWindowSize;
+        const int searchWindowSize = 16;
+        const int searchWindowSizeSq = searchWindowSize * searchWindowSize;
+        const float h = 10;
+        int maxGroupSize = 64;
+
+        // Precompute separate maps for transform and shrinkage verification
+        short *thrMapTransform = NULL;
+        short *thrMapShrinkage = NULL;
+        HaarTransform<short, short>::calcThresholdMap3D(thrMapTransform, 0, templateWindowSize, maxGroupSize);
+        HaarTransform<short, short>::calcThresholdMap3D(thrMapShrinkage, h, templateWindowSize, maxGroupSize);
+
+        // Generate some data
+        BlockMatch<short, int, short> *bm = new BlockMatch<short, int, short>[maxGroupSize];
+        BlockMatch<short, int, short> *bmOrig = new BlockMatch<short, int, short>[maxGroupSize];
+        for (int i = 0; i < maxGroupSize; ++i)
+        {
+            bm[i].init(templateWindowSizeSq);
+            bmOrig[i].init(templateWindowSizeSq);
+        }
+
+        for (short i = 0; i < maxGroupSize; ++i)
+        {
+            for (short j = 0; j < templateWindowSizeSq; ++j)
+            {
+                bm[i][j] = (j + 1);
+                bmOrig[i][j] = bm[i][j];
+            }
+        }
+
+        // Verify transforms
+        Test1dTransform<short, int, short>(thrMapTransform, 2, templateWindowSizeSq, bm, bmOrig);
+        Test1dTransform<short, int, short>(thrMapTransform, 4, templateWindowSizeSq, bm, bmOrig);
+        Test1dTransform<short, int, short>(thrMapTransform, 8, templateWindowSizeSq, bm, bmOrig);
+        Test1dTransform<short, int, short>(thrMapTransform, 16, templateWindowSizeSq, bm, bmOrig);
+        Test1dTransform<short, int, short>(thrMapTransform, 32, templateWindowSizeSq, bm, bmOrig);
+        Test1dTransform<short, int, short>(thrMapTransform, 64, templateWindowSizeSq, bm, bmOrig);
+
+        // Verify shrinkage
+        Test1dTransform<short, int, short>(thrMapShrinkage, 2, templateWindowSizeSq, bm, bmOrig, 6);
+        Test1dTransform<short, int, short>(thrMapShrinkage, 4, templateWindowSizeSq, bm, bmOrig, 6);
+        Test1dTransform<short, int, short>(thrMapShrinkage, 8, templateWindowSizeSq, bm, bmOrig, 6);
+        Test1dTransform<short, int, short>(thrMapShrinkage, 16, templateWindowSizeSq, bm, bmOrig, 6);
+        Test1dTransform<short, int, short>(thrMapShrinkage, 32, templateWindowSizeSq, bm, bmOrig, 6);
+        Test1dTransform<short, int, short>(thrMapShrinkage, 64, templateWindowSizeSq, bm, bmOrig, 14);
+    }
+
+    const float sqrt2 = std::sqrt(2.0f);
+
+    TEST(xphoto_DenoisingBm3dTransforms, regression_1D_generate)
+    {
+        const int numberOfElements = 8;
+        const int arrSize = (numberOfElements << 1) - 1;
+        float *thrMap1D = NULL;
+        HaarTransform<short, short>::calcThresholdMap1D(thrMap1D, numberOfElements);
+
+        // Expected array
+        const float kThrMap1D[arrSize] = {
+            1.0f,  // 1 element
+            sqrt2 / 2.0f,    sqrt2, // 2 elements
+            0.5f,            1.0f,            sqrt2,       sqrt2,  // 4 elements
+            sqrt2 / 4.0f,    sqrt2 / 2.0f,    1.0f,        1.0f,  sqrt2, sqrt2, sqrt2, sqrt2  // 8 elements
+        };
+
+        for (int j = 0; j < arrSize; ++j)
+            ASSERT_EQ(thrMap1D[j], kThrMap1D[j]);
+
+        delete[] thrMap1D;
+    }
+
+    TEST(xphoto_DenoisingBm3dTransforms, regression_2D_generate_4x4)
+    {
+        const int templateWindowSize = 4;
+        float *thrMap2D = NULL;
+        HaarTransform<short, short>::calcThresholdMap2D(thrMap2D, templateWindowSize);
+
+        // Expected array
+        const float kThrMap4x4[templateWindowSize * templateWindowSize] = {
+            0.25f,           0.5f,       sqrt2 / 2.0f,    sqrt2 / 2.0f,
+            0.5f,            1.0f,       sqrt2,           sqrt2,
+            sqrt2 / 2.0f,    sqrt2,      2.0f,            2.0f,
+            sqrt2 / 2.0f,    sqrt2,      2.0f,            2.0f
+        };
+
+        for (int j = 0; j < templateWindowSize * templateWindowSize; ++j)
+            ASSERT_EQ(thrMap2D[j], kThrMap4x4[j]);
+
+        delete[] thrMap2D;
+    }
+
+    TEST(xphoto_DenoisingBm3dTransforms, regression_2D_generate_8x8)
+    {
+        const int templateWindowSize = 8;
+        float *thrMap2D = NULL;
+        HaarTransform<short, short>::calcThresholdMap2D(thrMap2D, templateWindowSize);
+
+        // Expected array
+        const float kThrMap8x8[templateWindowSize * templateWindowSize] = {
+            0.125f,       0.25f,        sqrt2 / 4.0f, sqrt2 / 4.0f, 0.5f,  0.5f,  0.5f,  0.5f,
+            0.25f,        0.5f,         sqrt2 / 2.0f, sqrt2 / 2.0f, 1.0f,  1.0f,  1.0f,  1.0f,
+            sqrt2 / 4.0f, sqrt2 / 2.0f, 1.0f,         1.0f,         sqrt2, sqrt2, sqrt2, sqrt2,
+            sqrt2 / 4.0f, sqrt2 / 2.0f, 1.0f,         1.0f,         sqrt2, sqrt2, sqrt2, sqrt2,
+            0.5f,         1.0f,         sqrt2,        sqrt2,        2.0f,  2.0f,  2.0f,  2.0f,
+            0.5f,         1.0f,         sqrt2,        sqrt2,        2.0f,  2.0f,  2.0f,  2.0f,
+            0.5f,         1.0f,         sqrt2,        sqrt2,        2.0f,  2.0f,  2.0f,  2.0f,
+            0.5f,         1.0f,         sqrt2,        sqrt2,        2.0f,  2.0f,  2.0f,  2.0f
+        };
+
+        for (int j = 0; j < templateWindowSize * templateWindowSize; ++j)
+            ASSERT_EQ(thrMap2D[j], kThrMap8x8[j]);
+
+        delete[] thrMap2D;
+    }
+
+    TEST(xphoto_Bm3dDenoising, powerOf2)
+    {
+        ASSERT_EQ(8, getLargestPowerOf2SmallerThan(9));
+        ASSERT_EQ(16, getLargestPowerOf2SmallerThan(21));
+        ASSERT_EQ(4, getLargestPowerOf2SmallerThan(7));
+        ASSERT_EQ(8, getLargestPowerOf2SmallerThan(8));
+        ASSERT_EQ(4, getLargestPowerOf2SmallerThan(5));
+        ASSERT_EQ(4, getLargestPowerOf2SmallerThan(4));
+        ASSERT_EQ(2, getLargestPowerOf2SmallerThan(3));
+        ASSERT_EQ(1, getLargestPowerOf2SmallerThan(1));
+        ASSERT_EQ(0, getLargestPowerOf2SmallerThan(0));
+    }
+
+#endif  // TEST_TRANSFORMS
+
+}
+
+#endif  // OPENCV_ENABLE_NONFREE
\ No newline at end of file
diff --git a/contrib/modules/xphoto/test/test_grayworld.cpp b/contrib/modules/xphoto/test/test_grayworld.cpp
index 81ae287..dbdada0 100644
--- a/contrib/modules/xphoto/test/test_grayworld.cpp
+++ b/contrib/modules/xphoto/test/test_grayworld.cpp
@@ -66,9 +66,11 @@ namespace cvtest {
     TEST(xphoto_grayworld_white_balance, regression)
     {
         String dir = cvtest::TS::ptr()->get_data_path() + "cv/xphoto/simple_white_balance/";
-        const int nTests = 14;
+        const int nTests = 8;
         const float wb_thresh = 0.5f;
         const float acc_thresh = 2.f;
+        Ptr<xphoto::GrayworldWB> wb = xphoto::createGrayworldWB();
+        wb->setSaturationThreshold(wb_thresh);
 
         for ( int i = 0; i < nTests; ++i )
         {
@@ -80,8 +82,14 @@ namespace cvtest {
             ref_autowbGrayworld(src, referenceResult, wb_thresh);
 
             Mat currentResult;
-            xphoto::autowbGrayworld(src, currentResult, wb_thresh);
+            wb->balanceWhite(src, currentResult);
+            ASSERT_LE(cv::norm(currentResult, referenceResult, NORM_INF), acc_thresh);
 
+            // test the 16-bit depth:
+            Mat currentResult_16U, src_16U;
+            src.convertTo(src_16U, CV_16UC3, 256.0);
+            wb->balanceWhite(src_16U, currentResult_16U);
+            currentResult_16U.convertTo(currentResult, CV_8UC3, 1/256.0);
             ASSERT_LE(cv::norm(currentResult, referenceResult, NORM_INF), acc_thresh);
         }
     }
diff --git a/contrib/modules/xphoto/test/test_learning_based_color_balance.cpp b/contrib/modules/xphoto/test/test_learning_based_color_balance.cpp
new file mode 100644
index 0000000..47b12c4
--- /dev/null
+++ b/contrib/modules/xphoto/test/test_learning_based_color_balance.cpp
@@ -0,0 +1,42 @@
+#include "test_precomp.hpp"
+using namespace cv;
+namespace cvtest
+{
+TEST(xphoto_simplefeatures, regression)
+{
+    float acc_thresh = 0.01f;
+
+    // Generate a test image:
+    Mat test_im(1000, 1000, CV_8UC3);
+    RNG rng(1234);
+    rng.fill(test_im, RNG::NORMAL, Scalar(64, 100, 128), Scalar(10, 10, 10));
+    threshold(test_im, test_im, 200.0, 255.0, THRESH_TRUNC);
+    test_im.at<Vec3b>(0, 0) = Vec3b(240, 220, 200);
+
+    // Which should have the following features:
+    Vec2f ref1(128.0f / (64 + 100 + 128), 100.0f / (64 + 100 + 128));
+    Vec2f ref2(200.0f / (240 + 220 + 200), 220.0f / (240 + 220 + 200));
+
+    vector<Vec2f> dst_features;
+    Ptr<xphoto::LearningBasedWB> wb = xphoto::createLearningBasedWB();
+    wb->setRangeMaxVal(255);
+    wb->setSaturationThreshold(0.98f);
+    wb->setHistBinNum(64);
+    wb->extractSimpleFeatures(test_im, dst_features);
+    ASSERT_LE(cv::norm(dst_features[0], ref1, NORM_INF), acc_thresh);
+    ASSERT_LE(cv::norm(dst_features[1], ref2, NORM_INF), acc_thresh);
+    ASSERT_LE(cv::norm(dst_features[2], ref1, NORM_INF), acc_thresh);
+    ASSERT_LE(cv::norm(dst_features[3], ref1, NORM_INF), acc_thresh);
+
+    // check 16 bit depth:
+    test_im.convertTo(test_im, CV_16U, 256.0);
+    wb->setRangeMaxVal(65535);
+    wb->setSaturationThreshold(0.98f);
+    wb->setHistBinNum(128);
+    wb->extractSimpleFeatures(test_im, dst_features);
+    ASSERT_LE(cv::norm(dst_features[0], ref1, NORM_INF), acc_thresh);
+    ASSERT_LE(cv::norm(dst_features[1], ref2, NORM_INF), acc_thresh);
+    ASSERT_LE(cv::norm(dst_features[2], ref1, NORM_INF), acc_thresh);
+    ASSERT_LE(cv::norm(dst_features[3], ref1, NORM_INF), acc_thresh);
+}
+}
diff --git a/contrib/modules/xphoto/tutorials/training_white_balance.markdown b/contrib/modules/xphoto/tutorials/training_white_balance.markdown
new file mode 100644
index 0000000..eac4c84
--- /dev/null
+++ b/contrib/modules/xphoto/tutorials/training_white_balance.markdown
@@ -0,0 +1,42 @@
+Training the learning-based white balance algorithm {#tutorial_xphoto_training_white_balance}
+===================================================
+
+Introduction
+------------
+
+Many traditional white balance algorithms are statistics-based, i.e. they rely on the fact that certain assumptions should hold in properly white-balanced images
+like the well-known grey-world assumption. However, better results can often be achieved by leveraging large datasets of images with ground-truth
+illuminants in a learning-based framework. This tutorial demonstrates how to train a learning-based white balance algorithm and evaluate the quality of the results.
+
+
+How to train a model
+--------------------
+
+-#  Download a dataset for training. In this tutorial we will use the [Gehler-Shi dataset ](http://www.cs.sfu.ca/~colour/data/shi_gehler/). Extract all 568 training images
+    in one folder. A file containing ground-truth illuminant values (real_illum_568..mat) is downloaded separately.
+
+-#  We will be using a [Python script ](https://github.com/opencv/opencv_contrib/tree/master/modules/xphoto/samples/learn_color_balance.py) for training.
+    Call it with the following parameters:
+    @code
+        python learn_color_balance.py -i <path to the folder with training images> -g <path to real_illum_568..mat> -r 0,378 --num_trees 30 --max_tree_depth 6 --num_augmented 0
+    @endcode
+    This should start training a model on the first 378 images (2/3 of the whole dataset). We set the size of the model to be 30 regression tree pairs per feature and limit
+    the tree depth to be no more then 6. By default the resulting model will be saved to color_balance_model.yml
+
+-#  Use the trained model by passing its path when constructing an instance of LearningBasedWB:
+    @code{.cpp}
+    Ptr<xphoto::LearningBasedWB> wb = xphoto::createLearningBasedWB(modelFilename);
+    @endcode
+
+
+How to evaluate a model
+----------------------
+
+-#  We will use a [benchmarking script ](https://github.com/opencv/opencv_contrib/tree/master/modules/xphoto/samples/color_balance_benchmark.py) to compare
+    the model that we've trained with the classic grey-world algorithm on the remaining 1/3 of the dataset. Call the script with the following parameters:
+    @code
+        python color_balance_benchmark.py -a grayworld,learning_based:color_balance_model.yml -m <full path to folder containing the model> -i <path to the folder with training images> -g <path to real_illum_568..mat> -r 379,567 -d "img"
+    @endcode
+
+-# The objective evaluation results are stored in white_balance_eval_result.html and the resulting white-balanced images are stored in the img folder for a qualitative
+   comparison of algorithms. Different algorithms are compared in terms of angular error between the estimated and ground-truth illuminants.
\ No newline at end of file
diff --git a/contrib/samples/data/corridor.jpg b/contrib/samples/data/corridor.jpg
new file mode 100644
index 0000000..6ebef4e
Binary files /dev/null and b/contrib/samples/data/corridor.jpg differ
diff --git a/contrib/samples/python2/dis_opt_flow.py b/contrib/samples/python2/dis_opt_flow.py
new file mode 100644
index 0000000..731a3aa
--- /dev/null
+++ b/contrib/samples/python2/dis_opt_flow.py
@@ -0,0 +1,114 @@
+#!/usr/bin/env python
+
+'''
+example to show optical flow estimation using DISOpticalFlow
+
+USAGE: dis_opt_flow.py [<video_source>]
+
+Keys:
+ 1  - toggle HSV flow visualization
+ 2  - toggle glitch
+ 3  - toggle spatial propagation of flow vectors
+ 4  - toggle temporal propagation of flow vectors
+ESC - exit
+'''
+
+# Python 2/3 compatibility
+from __future__ import print_function
+
+import numpy as np
+import cv2
+import video
+
+
+def draw_flow(img, flow, step=16):
+    h, w = img.shape[:2]
+    y, x = np.mgrid[step/2:h:step, step/2:w:step].reshape(2,-1).astype(int)
+    fx, fy = flow[y,x].T
+    lines = np.vstack([x, y, x+fx, y+fy]).T.reshape(-1, 2, 2)
+    lines = np.int32(lines + 0.5)
+    vis = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)
+    cv2.polylines(vis, lines, 0, (0, 255, 0))
+    for (x1, y1), (x2, y2) in lines:
+        cv2.circle(vis, (x1, y1), 1, (0, 255, 0), -1)
+    return vis
+
+
+def draw_hsv(flow):
+    h, w = flow.shape[:2]
+    fx, fy = flow[:,:,0], flow[:,:,1]
+    ang = np.arctan2(fy, fx) + np.pi
+    v = np.sqrt(fx*fx+fy*fy)
+    hsv = np.zeros((h, w, 3), np.uint8)
+    hsv[...,0] = ang*(180/np.pi/2)
+    hsv[...,1] = 255
+    hsv[...,2] = np.minimum(v*4, 255)
+    bgr = cv2.cvtColor(hsv, cv2.COLOR_HSV2BGR)
+    return bgr
+
+
+def warp_flow(img, flow):
+    h, w = flow.shape[:2]
+    flow = -flow
+    flow[:,:,0] += np.arange(w)
+    flow[:,:,1] += np.arange(h)[:,np.newaxis]
+    res = cv2.remap(img, flow, None, cv2.INTER_LINEAR)
+    return res
+
+
+if __name__ == '__main__':
+    import sys
+    print(__doc__)
+    try:
+        fn = sys.argv[1]
+    except IndexError:
+        fn = 0
+
+    cam = video.create_capture(fn)
+    ret, prev = cam.read()
+    prevgray = cv2.cvtColor(prev, cv2.COLOR_BGR2GRAY)
+    show_hsv = False
+    show_glitch = False
+    use_spatial_propagation = False
+    use_temporal_propagation = True
+    cur_glitch = prev.copy()
+    inst = cv2.optflow.createOptFlow_DIS(cv2.optflow.DISOPTICAL_FLOW_PRESET_MEDIUM)
+    inst.setUseSpatialPropagation(use_spatial_propagation)
+
+    flow = None
+    while True:
+        ret, img = cam.read()
+        gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
+        if flow is not None and use_temporal_propagation:
+            #warp previous flow to get an initial approximation for the current flow:
+            flow = inst.calc(prevgray, gray, warp_flow(flow,flow))
+        else:
+            flow = inst.calc(prevgray, gray, None)
+        prevgray = gray
+
+        cv2.imshow('flow', draw_flow(gray, flow))
+        if show_hsv:
+            cv2.imshow('flow HSV', draw_hsv(flow))
+        if show_glitch:
+            cur_glitch = warp_flow(cur_glitch, flow)
+            cv2.imshow('glitch', cur_glitch)
+
+        ch = 0xFF & cv2.waitKey(5)
+        if ch == 27:
+            break
+        if ch == ord('1'):
+            show_hsv = not show_hsv
+            print('HSV flow visualization is', ['off', 'on'][show_hsv])
+        if ch == ord('2'):
+            show_glitch = not show_glitch
+            if show_glitch:
+                cur_glitch = img.copy()
+            print('glitch is', ['off', 'on'][show_glitch])
+        if ch == ord('3'):
+            use_spatial_propagation = not use_spatial_propagation
+            inst.setUseSpatialPropagation(use_spatial_propagation)
+            print('spatial propagation is', ['off', 'on'][use_spatial_propagation])
+        if ch == ord('4'):
+            use_temporal_propagation = not use_temporal_propagation
+            print('temporal propagation is', ['off', 'on'][use_temporal_propagation])
+    cv2.destroyAllWindows()
diff --git a/data/haarcascades/haarcascade_frontalcatface.xml b/data/haarcascades/haarcascade_frontalcatface.xml
old mode 100644
new mode 100755
index 0ec79f6..67893dc
--- a/data/haarcascades/haarcascade_frontalcatface.xml
+++ b/data/haarcascades/haarcascade_frontalcatface.xml
@@ -22,15 +22,20 @@
 
  KNOWN LIMITATIONS:
 
- Sometimes, the detector mistakenly thinks that a human face is a cat face. In
- situations where either a human or a cat might be encountered, use both a
- human face detector and a cat face detector. Then, if a detected human face
- and a detected cat face intersect, reject the cat face.
-
  An upright subject is assumed. In situations where the cat's face might be
  sideways or upside down (e.g. the cat is rolling over), try various rotations
  of the input image.
 
+ CHANGELOG:
+
+ 2016-08-06: Re-trained with more negative samples and more stages. False
+   positives are much rarer now. If you tailored your code for the cascade's
+   previous version, now you should re-adjust the arguments of
+   CascadeClassifier::detectMultiScale. For example, decrease the value of the
+   minNeighbors argument. You do not need to use a human face detector to
+   cross-check the positives anymore.
+ 2014-04-25: First release (at https://bitbucket.org/Joe_Howse/angora-blue)
+
  //////////////////////////////////////////////////////////////////////////
  | Contributors License Agreement
  | IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
@@ -39,7 +44,7 @@
  |   If you do not agree to this license, do not download, install,
  |   copy or use the software.
  |
- | Copyright (c) 2014, Joseph Howse (Nummist Media Corporation Limited,
+ | Copyright (c) 2014-2016, Joseph Howse (Nummist Media Corporation Limited,
  | Halifax, Nova Scotia, Canada). All rights reserved.
  |
  | Redistribution and use in source and binary forms, with or without
@@ -77,7 +82,7 @@
   <width>24</width>
   <stageParams>
     <boostType>GAB</boostType>
-    <minHitRate>9.9900001287460327e-01</minHitRate>
+    <minHitRate>9.9500000476837158e-01</minHitRate>
     <maxFalseAlarm>5.0000000000000000e-01</maxFalseAlarm>
     <weightTrimRate>9.4999999999999996e-01</weightTrimRate>
     <maxDepth>1</maxDepth>
@@ -86,13234 +91,14292 @@
     <maxCatCount>0</maxCatCount>
     <featSize>1</featSize>
     <mode>BASIC</mode></featureParams>
-  <stageNum>15</stageNum>
+  <stageNum>20</stageNum>
   <stages>
     <!-- stage 0 -->
     <_>
-      <maxWeakCount>25</maxWeakCount>
-      <stageThreshold>-1.7760953903198242e+00</stageThreshold>
+      <maxWeakCount>16</maxWeakCount>
+      <stageThreshold>-1.4806525707244873e+00</stageThreshold>
       <weakClassifiers>
         <_>
           <internalNodes>
-            0 -1 445 -1.4772760681807995e-02</internalNodes>
+            0 -1 472 -1.5126220881938934e-02</internalNodes>
           <leafValues>
-            8.4035199880599976e-01 -1.2701500952243805e-01</leafValues></_>
+            7.5887596607208252e-01 -3.4230688214302063e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 792 4.5831585302948952e-03</internalNodes>
+            0 -1 839 3.9337221533060074e-03</internalNodes>
           <leafValues>
-            -2.3791725933551788e-01 6.1978793144226074e-01</leafValues></_>
+            -3.3288389444351196e-01 5.2361363172531128e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 813 -1.5044892206788063e-02</internalNodes>
+            0 -1 858 -1.5044892206788063e-02</internalNodes>
           <leafValues>
-            5.7160794734954834e-01 -2.0493283867835999e-01</leafValues></_>
+            5.5565774440765381e-01 -2.2505992650985718e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 367 -1.2275323271751404e-02</internalNodes>
+            0 -1 387 -1.2927042320370674e-02</internalNodes>
           <leafValues>
-            5.7243120670318604e-01 -1.9821420311927795e-01</leafValues></_>
+            5.7442700862884521e-01 -1.9708566367626190e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 842 8.3929381798952818e-04</internalNodes>
+            0 -1 137 5.5960696190595627e-03</internalNodes>
           <leafValues>
-            -2.7865329384803772e-01 4.3508478999137878e-01</leafValues></_>
+            -3.0430641770362854e-01 4.0241482853889465e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 231 1.5758406370878220e-02</internalNodes>
+            0 -1 207 1.5758406370878220e-02</internalNodes>
           <leafValues>
-            -2.2696593403816223e-01 4.9478942155838013e-01</leafValues></_>
+            -1.9767063856124878e-01 4.5033392310142517e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 581 5.0025805830955505e-02</internalNodes>
+            0 -1 678 2.4262722581624985e-02</internalNodes>
           <leafValues>
-            -1.5532729029655457e-01 6.8103748559951782e-01</leafValues></_>
+            -1.6931040585041046e-01 5.9707510471343994e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 727 1.3194808736443520e-02</internalNodes>
+            0 -1 267 -3.5242564976215363e-02</internalNodes>
           <leafValues>
-            -1.7704419791698456e-01 5.8701574802398682e-01</leafValues></_>
+            6.5973556041717529e-01 -1.4519356191158295e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 5 2.8080096468329430e-02</internalNodes>
+            0 -1 687 2.6568008586764336e-02</internalNodes>
           <leafValues>
-            -1.6797901690006256e-01 5.7502186298370361e-01</leafValues></_>
+            -1.3476610183715820e-01 5.4296624660491943e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 704 2.1941341459751129e-02</internalNodes>
+            0 -1 228 4.7154121100902557e-02</internalNodes>
           <leafValues>
-            -1.4689344167709351e-01 5.2395468950271606e-01</leafValues></_>
+            -1.7337851226329803e-01 4.6071702241897583e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 279 -4.7663945704698563e-02</internalNodes>
+            0 -1 925 -5.3081759251654148e-03</internalNodes>
           <leafValues>
-            6.5710687637329102e-01 -1.1819842457771301e-01</leafValues></_>
+            5.4976856708526611e-01 -1.1913410574197769e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 278 3.5373851656913757e-02</internalNodes>
+            0 -1 608 5.3415738046169281e-02</internalNodes>
           <leafValues>
-            -9.7323395311832428e-02 7.4618083238601685e-01</leafValues></_>
+            -1.2382411211729050e-01 6.3972741365432739e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 254 1.4257467410061508e-04</internalNodes>
+            0 -1 671 -3.0798995867371559e-03</internalNodes>
           <leafValues>
-            -2.8882622718811035e-01 2.8288537263870239e-01</leafValues></_>
+            -8.2048600912094116e-01 1.0249497741460800e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 253 3.8169793784618378e-02</internalNodes>
+            0 -1 676 -2.3766520898789167e-03</internalNodes>
           <leafValues>
-            -1.4375060796737671e-01 4.9739924073219299e-01</leafValues></_>
+            -7.0665025711059570e-01 6.7025005817413330e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 142 6.5595638006925583e-03</internalNodes>
+            0 -1 180 1.1965663870796561e-03</internalNodes>
           <leafValues>
-            1.2217019498348236e-01 -6.4208990335464478e-01</leafValues></_>
+            -2.4753804504871368e-01 3.0198124051094055e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 753 -7.5260535813868046e-03</internalNodes>
+            0 -1 830 -4.2106406763195992e-03</internalNodes>
           <leafValues>
-            -7.7927684783935547e-01 8.4750138223171234e-02</leafValues></_>
+            3.8455343246459961e-01 -1.8334107100963593e-01</leafValues></_></weakClassifiers></_>
+    <!-- stage 1 -->
+    <_>
+      <maxWeakCount>26</maxWeakCount>
+      <stageThreshold>-1.4618960618972778e+00</stageThreshold>
+      <weakClassifiers>
         <_>
           <internalNodes>
-            0 -1 754 1.1342750862240791e-02</internalNodes>
+            0 -1 725 1.0133055038750172e-02</internalNodes>
           <leafValues>
-            -2.2101284563541412e-01 3.4454554319381714e-01</leafValues></_>
+            -2.8207325935363770e-01 6.2703561782836914e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 645 -1.8045576289296150e-03</internalNodes>
+            0 -1 356 3.8468956947326660e-02</internalNodes>
           <leafValues>
-            -7.8645682334899902e-01 9.7392335534095764e-02</leafValues></_>
+            -1.4483113586902618e-01 7.4971008300781250e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 457 -6.6228499636054039e-03</internalNodes>
+            0 -1 2 -3.7523733917623758e-03</internalNodes>
           <leafValues>
-            3.1783181428909302e-01 -2.0665900409221649e-01</leafValues></_>
+            4.2959973216056824e-01 -2.1445912122726440e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 50 1.0336233302950859e-02</internalNodes>
+            0 -1 844 9.9978316575288773e-04</internalNodes>
           <leafValues>
-            9.1840714216232300e-02 -7.7336055040359497e-01</leafValues></_>
+            -1.9259409606456757e-01 4.2325544357299805e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 552 -2.4216776713728905e-02</internalNodes>
+            0 -1 387 -1.6786376014351845e-02</internalNodes>
           <leafValues>
-            3.6742198467254639e-01 -1.9339990615844727e-01</leafValues></_>
+            5.0582861900329590e-01 -1.8607729673385620e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 64 1.4514809474349022e-02</internalNodes>
+            0 -1 208 3.0330579727888107e-02</internalNodes>
           <leafValues>
-            -1.3652153313159943e-01 4.2311781644821167e-01</leafValues></_>
+            -2.1100421249866486e-01 4.2819553613662720e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 645 2.1728668361902237e-03</internalNodes>
+            0 -1 206 1.5150709077715874e-02</internalNodes>
           <leafValues>
-            7.9096116125583649e-02 -7.6427251100540161e-01</leafValues></_>
+            -2.1129198372364044e-01 3.6263525485992432e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 467 -3.9529249072074890e-02</internalNodes>
+            0 -1 451 -3.6349350120872259e-03</internalNodes>
           <leafValues>
-            5.7755863666534424e-01 -1.0801278799772263e-01</leafValues></_>
+            3.9500275254249573e-01 -1.8650630116462708e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 640 1.5566367655992508e-02</internalNodes>
+            0 -1 270 -7.2061517275869846e-03</internalNodes>
           <leafValues>
-            -1.0259374976158142e-01 4.9773094058036804e-01</leafValues></_></weakClassifiers></_>
-    <!-- stage 1 -->
-    <_>
-      <maxWeakCount>34</maxWeakCount>
-      <stageThreshold>-1.6417213678359985e+00</stageThreshold>
-      <weakClassifiers>
+            -7.2816300392150879e-01 1.1153221875429153e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 699 8.2648023962974548e-03</internalNodes>
+            0 -1 866 -2.0212728530168533e-02</internalNodes>
           <leafValues>
-            -1.0913594812154770e-01 7.7392864227294922e-01</leafValues></_>
+            5.6296736001968384e-01 -1.2056054919958115e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 697 1.4094283804297447e-02</internalNodes>
+            0 -1 265 2.5640423409640789e-03</internalNodes>
           <leafValues>
-            -1.4461971819400787e-01 7.1108609437942505e-01</leafValues></_>
+            -2.3753854632377625e-01 3.5794413089752197e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 4 6.3192001543939114e-03</internalNodes>
+            0 -1 230 -6.2726587057113647e-03</internalNodes>
           <leafValues>
-            -2.3035119473934174e-01 4.4546401500701904e-01</leafValues></_>
+            -6.7750877141952515e-01 1.2570948898792267e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 227 2.0388111472129822e-02</internalNodes>
+            0 -1 126 7.8710336238145828e-03</internalNodes>
           <leafValues>
-            -2.6455581188201904e-01 3.6559283733367920e-01</leafValues></_>
+            6.9211356341838837e-02 -7.6449161767959595e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 206 1.4826779253780842e-02</internalNodes>
+            0 -1 306 5.9134580194950104e-02</internalNodes>
           <leafValues>
-            -2.0881411433219910e-01 4.6142515540122986e-01</leafValues></_>
+            -1.7324967682361603e-01 3.3361187577247620e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 821 2.1515905857086182e-02</internalNodes>
+            0 -1 185 -2.8770491480827332e-03</internalNodes>
           <leafValues>
-            -1.4785310626029968e-01 6.4220702648162842e-01</leafValues></_>
+            3.6101511120796204e-01 -1.6122241318225861e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 919 1.4720780309289694e-03</internalNodes>
+            0 -1 388 -5.7046953588724136e-03</internalNodes>
           <leafValues>
-            -2.2546350955963135e-01 3.6676284670829773e-01</leafValues></_>
+            -6.7659336328506470e-01 8.4153175354003906e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 814 -2.6044776663184166e-02</internalNodes>
+            0 -1 13 -7.8070178627967834e-02</internalNodes>
           <leafValues>
-            4.1465434432029724e-01 -1.5356495976448059e-01</leafValues></_>
+            6.0763663053512573e-01 -1.1037797480821609e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 202 -1.0589402168989182e-02</internalNodes>
+            0 -1 321 6.5858578309416771e-03</internalNodes>
           <leafValues>
-            4.1222676634788513e-01 -1.6899079084396362e-01</leafValues></_>
+            9.3060031533241272e-02 -7.0068693161010742e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 203 6.9683273322880268e-03</internalNodes>
+            0 -1 796 -2.0920131355524063e-03</internalNodes>
           <leafValues>
-            1.0854535549879074e-01 -7.1554762125015259e-01</leafValues></_>
+            2.8173315525054932e-01 -1.8406434357166290e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 326 1.1014346033334732e-02</internalNodes>
+            0 -1 578 -2.1252598613500595e-02</internalNodes>
           <leafValues>
-            -1.7490877211093903e-01 4.4723153114318848e-01</leafValues></_>
+            3.9672371745109558e-01 -1.5127600729465485e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 387 -1.1037060990929604e-02</internalNodes>
+            0 -1 770 -3.2937981188297272e-02</internalNodes>
           <leafValues>
-            4.4173675775527954e-01 -1.3834878802299500e-01</leafValues></_>
+            3.9487251639366150e-01 -1.3228580355644226e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 581 6.2014400959014893e-02</internalNodes>
+            0 -1 1016 4.9491915851831436e-03</internalNodes>
           <leafValues>
-            -1.1345938593149185e-01 6.1101204156875610e-01</leafValues></_>
+            1.1234261840581894e-01 -4.7414371371269226e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 318 6.0412874445319176e-03</internalNodes>
+            0 -1 215 3.4271054901182652e-03</internalNodes>
           <leafValues>
-            1.0154686868190765e-01 -7.2787815332412720e-01</leafValues></_>
+            7.8623600304126740e-02 -5.7828009128570557e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 281 -5.8582504279911518e-03</internalNodes>
+            0 -1 200 -6.0859560035169125e-03</internalNodes>
           <leafValues>
-            -6.0382944345474243e-01 8.4109157323837280e-02</leafValues></_>
+            -5.0091904401779175e-01 9.1926425695419312e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 885 7.3200068436563015e-04</internalNodes>
+            0 -1 990 1.2116413563489914e-02</internalNodes>
           <leafValues>
-            -1.6661356389522552e-01 3.7944686412811279e-01</leafValues></_>
+            -1.7154470086097717e-01 2.6759135723114014e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 702 1.9083185121417046e-02</internalNodes>
+            0 -1 456 8.2814376801252365e-03</internalNodes>
           <leafValues>
-            -1.2449446320533752e-01 4.2328220605850220e-01</leafValues></_>
+            -1.2938241660594940e-01 3.5665917396545410e-01</leafValues></_></weakClassifiers></_>
+    <!-- stage 2 -->
+    <_>
+      <maxWeakCount>26</maxWeakCount>
+      <stageThreshold>-1.4103703498840332e+00</stageThreshold>
+      <weakClassifiers>
         <_>
           <internalNodes>
-            0 -1 978 6.8236114457249641e-03</internalNodes>
+            0 -1 532 -1.0988018475472927e-02</internalNodes>
           <leafValues>
-            1.0009460896253586e-01 -5.7412278652191162e-01</leafValues></_>
+            6.4358645677566528e-01 -2.3149165511131287e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 655 -8.0357380211353302e-03</internalNodes>
+            0 -1 750 -7.8163212165236473e-03</internalNodes>
           <leafValues>
-            3.5114383697509766e-01 -1.5984705090522766e-01</leafValues></_>
+            5.4850798845291138e-01 -1.7881108820438385e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 476 5.3236715495586395e-02</internalNodes>
+            0 -1 289 7.1337133646011353e-02</internalNodes>
           <leafValues>
-            -1.1999151855707169e-01 4.5052844285964966e-01</leafValues></_>
+            -1.7631703615188599e-01 4.5873588323593140e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 380 -2.5083746761083603e-02</internalNodes>
+            0 -1 549 5.2656695246696472e-02</internalNodes>
           <leafValues>
-            4.2925071716308594e-01 -1.3847301900386810e-01</leafValues></_>
+            -1.3836050033569336e-01 5.6253266334533691e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 834 -7.7097099274396896e-03</internalNodes>
+            0 -1 8 1.5166129916906357e-02</internalNodes>
           <leafValues>
-            4.2245966196060181e-01 -1.4710718393325806e-01</leafValues></_>
+            -2.0990008115768433e-01 4.0483391284942627e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 22 1.1426717042922974e-02</internalNodes>
+            0 -1 970 -1.4538960531353951e-03</internalNodes>
           <leafValues>
-            7.3091737926006317e-02 -7.6901757717132568e-01</leafValues></_>
+            3.3692672848701477e-01 -2.1745139360427856e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 980 -4.7868257388472557e-03</internalNodes>
+            0 -1 875 1.1136244982481003e-02</internalNodes>
           <leafValues>
-            -5.4498624801635742e-01 8.9874587953090668e-02</leafValues></_>
+            -1.5003634989261627e-01 5.2208083868026733e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 797 9.9204876460134983e-04</internalNodes>
+            0 -1 925 -3.3187635708600283e-03</internalNodes>
           <leafValues>
-            -1.5133780241012573e-01 3.5266080498695374e-01</leafValues></_>
+            3.9145255088806152e-01 -1.9418042898178101e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 747 -7.3156114667654037e-03</internalNodes>
+            0 -1 485 4.9791105091571808e-02</internalNodes>
           <leafValues>
-            -7.7262216806411743e-01 7.4858717620372772e-02</leafValues></_>
+            -1.0192432254552841e-01 5.4612094163894653e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 239 5.6915655732154846e-03</internalNodes>
+            0 -1 828 4.3476112186908722e-02</internalNodes>
           <leafValues>
-            5.7124871760606766e-02 -6.7257982492446899e-01</leafValues></_>
+            -1.2768918275833130e-01 5.0825607776641846e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 854 -9.5818340778350830e-03</internalNodes>
+            0 -1 719 -2.8149634599685669e-03</internalNodes>
           <leafValues>
-            3.5280853509902954e-01 -1.5295246243476868e-01</leafValues></_>
+            -7.0453292131423950e-01 1.2536850571632385e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 155 2.3029895499348640e-02</internalNodes>
+            0 -1 846 1.6101204091683030e-03</internalNodes>
           <leafValues>
-            8.0654025077819824e-02 -6.6331261396408081e-01</leafValues></_>
+            -2.6965174078941345e-01 2.2737979888916016e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 63 8.3062853664159775e-03</internalNodes>
+            0 -1 715 -1.5866891480982304e-03</internalNodes>
           <leafValues>
-            -1.8261365592479706e-01 2.9241952300071716e-01</leafValues></_>
+            -6.6891485452651978e-01 1.1686278134584427e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 166 1.2940693646669388e-02</internalNodes>
+            0 -1 677 -3.2338392920792103e-03</internalNodes>
           <leafValues>
-            6.2763690948486328e-02 -7.9858863353729248e-01</leafValues></_>
+            -6.7284232378005981e-01 6.6228114068508148e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 855 4.5793736353516579e-03</internalNodes>
+            0 -1 479 -9.9909156560897827e-03</internalNodes>
           <leafValues>
-            -1.6761651635169983e-01 2.8498283028602600e-01</leafValues></_>
+            3.6961549520492554e-01 -1.5993835031986237e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 639 3.1311963684856892e-03</internalNodes>
+            0 -1 350 4.8409838229417801e-02</internalNodes>
           <leafValues>
-            6.4963281154632568e-02 -7.1869355440139771e-01</leafValues></_>
+            -1.0068884491920471e-01 5.0648134946823120e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 438 6.2793528195470572e-04</internalNodes>
+            0 -1 273 8.0585200339555740e-03</internalNodes>
           <leafValues>
-            -1.4610730111598969e-01 3.1872764229774475e-01</leafValues></_></weakClassifiers></_>
-    <!-- stage 2 -->
-    <_>
-      <maxWeakCount>47</maxWeakCount>
-      <stageThreshold>-1.8195210695266724e+00</stageThreshold>
-      <weakClassifiers>
+            -1.6782654821872711e-01 3.5382467508316040e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 389 2.8032548725605011e-02</internalNodes>
+            0 -1 338 -1.1718695983290672e-02</internalNodes>
           <leafValues>
-            3.9794921875000000e-02 7.6527571678161621e-01</leafValues></_>
+            4.3832498788833618e-01 -1.2780784070491791e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 512 -1.3777698390185833e-02</internalNodes>
+            0 -1 594 5.7147610932588577e-03</internalNodes>
           <leafValues>
-            4.8011425137519836e-01 -2.0891545712947845e-01</leafValues></_>
+            7.5814604759216309e-02 -7.2597140073776245e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 768 -1.5191626735031605e-03</internalNodes>
+            0 -1 603 -2.0917234942317009e-03</internalNodes>
           <leafValues>
-            4.3561527132987976e-01 -1.9825626909732819e-01</leafValues></_>
+            -6.0916984081268311e-01 8.4811411798000336e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 234 5.4982006549835205e-02</internalNodes>
+            0 -1 855 5.7651996612548828e-03</internalNodes>
           <leafValues>
-            -1.9595552980899811e-01 5.1033991575241089e-01</leafValues></_>
+            -1.9243443012237549e-01 2.8976503014564514e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 2 -3.8968096487224102e-03</internalNodes>
+            0 -1 565 -2.8093710541725159e-02</internalNodes>
           <leafValues>
-            3.6698764562606812e-01 -2.1704223752021790e-01</leafValues></_>
+            5.4229170083999634e-01 -1.0005526244640350e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 875 -1.0689822956919670e-02</internalNodes>
+            0 -1 136 8.9291334152221680e-03</internalNodes>
           <leafValues>
-            5.7506144046783447e-01 -1.2323237210512161e-01</leafValues></_>
+            8.3808921277523041e-02 -6.3219338655471802e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 423 -3.6211537662893534e-03</internalNodes>
+            0 -1 268 -5.1958961412310600e-03</internalNodes>
           <leafValues>
-            3.9189809560775757e-01 -2.0496053993701935e-01</leafValues></_>
+            -5.4964137077331543e-01 7.9588212072849274e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 368 -5.6232484057545662e-03</internalNodes>
+            0 -1 95 9.2318728566169739e-03</internalNodes>
           <leafValues>
-            -7.0911335945129395e-01 8.9780956506729126e-02</leafValues></_>
+            -1.2818163633346558e-01 4.2056322097778320e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 311 7.6950237154960632e-02</internalNodes>
+            0 -1 964 -2.0556427538394928e-02</internalNodes>
           <leafValues>
-            -1.6086885333061218e-01 3.9858064055442810e-01</leafValues></_>
+            3.2048463821411133e-01 -1.3858842849731445e-01</leafValues></_></weakClassifiers></_>
+    <!-- stage 3 -->
+    <_>
+      <maxWeakCount>35</maxWeakCount>
+      <stageThreshold>-1.4265209436416626e+00</stageThreshold>
+      <weakClassifiers>
         <_>
           <internalNodes>
-            0 -1 211 -9.4812046736478806e-03</internalNodes>
+            0 -1 683 1.8821602687239647e-02</internalNodes>
           <leafValues>
-            4.4439849257469177e-01 -1.4388205111026764e-01</leafValues></_>
+            -1.7807419598102570e-01 5.9040957689285278e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 637 4.8636407591402531e-03</internalNodes>
+            0 -1 471 -9.5066539943218231e-03</internalNodes>
           <leafValues>
-            8.3068624138832092e-02 -7.4362516403198242e-01</leafValues></_>
+            5.0587177276611328e-01 -1.7767964303493500e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 616 -2.9443078674376011e-03</internalNodes>
+            0 -1 884 1.3296608813107014e-03</internalNodes>
           <leafValues>
-            -6.1576569080352783e-01 8.1917040050029755e-02</leafValues></_>
+            -1.6886346042156219e-01 3.6326614022254944e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 573 -2.0938962697982788e-03</internalNodes>
+            0 -1 473 3.5266026854515076e-02</internalNodes>
           <leafValues>
-            -5.7727062702178955e-01 9.1147974133491516e-02</leafValues></_>
+            -1.1824090778827667e-01 5.8951085805892944e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 796 2.7704227250069380e-03</internalNodes>
+            0 -1 340 1.7804209142923355e-02</internalNodes>
           <leafValues>
-            -1.9285553693771362e-01 3.1007087230682373e-01</leafValues></_>
+            -1.4211210608482361e-01 5.1762068271636963e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 386 1.2979362159967422e-02</internalNodes>
+            0 -1 1001 4.7029324923641980e-04</internalNodes>
           <leafValues>
-            -1.4128974080085754e-01 3.8875201344490051e-01</leafValues></_>
+            -2.4296821653842926e-01 2.5087893009185791e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 61 -1.1832339689135551e-02</internalNodes>
+            0 -1 182 7.1838246658444405e-03</internalNodes>
           <leafValues>
-            -7.8204095363616943e-01 7.2949714958667755e-02</leafValues></_>
+            9.2609666287899017e-02 -6.7694115638732910e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 265 3.3956445753574371e-02</internalNodes>
+            0 -1 390 -5.7565318420529366e-03</internalNodes>
           <leafValues>
-            -1.3892538845539093e-01 3.9772579073905945e-01</leafValues></_>
+            -7.3053181171417236e-01 8.2794629037380219e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 650 4.9063982442021370e-03</internalNodes>
+            0 -1 203 2.0850602537393570e-02</internalNodes>
           <leafValues>
-            8.1131778657436371e-02 -7.2757917642593384e-01</leafValues></_>
+            -1.7353208363056183e-01 3.3287450671195984e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 649 -2.3896694183349609e-03</internalNodes>
+            0 -1 805 3.1848326325416565e-03</internalNodes>
           <leafValues>
-            -6.3438212871551514e-01 7.6958425343036652e-02</leafValues></_>
+            -2.0941653847694397e-01 2.6059800386428833e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 27 2.7626976370811462e-02</internalNodes>
+            0 -1 234 -7.5752258300781250e-02</internalNodes>
           <leafValues>
-            -1.7219249904155731e-01 3.7336668372154236e-01</leafValues></_>
+            5.1588213443756104e-01 -1.0057342052459717e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 539 3.9899977855384350e-03</internalNodes>
+            0 -1 5 2.8725115582346916e-02</internalNodes>
           <leafValues>
-            7.0482976734638214e-02 -6.6334074735641479e-01</leafValues></_>
+            -1.5012685954570770e-01 4.1436919569969177e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 503 -1.3984958641231060e-03</internalNodes>
+            0 -1 175 -1.7325732856988907e-02</internalNodes>
           <leafValues>
-            4.2500507831573486e-01 -1.2214981764554977e-01</leafValues></_>
+            3.8678762316703796e-01 -1.3586300611495972e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 878 1.3496846659108996e-03</internalNodes>
+            0 -1 47 -3.2187681645154953e-03</internalNodes>
           <leafValues>
-            -1.1209741979837418e-01 4.0830954909324646e-01</leafValues></_>
+            -5.1590150594711304e-01 1.1511231958866119e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 709 -3.9141997694969177e-03</internalNodes>
+            0 -1 1020 -6.1595086008310318e-03</internalNodes>
           <leafValues>
-            -5.3290998935699463e-01 9.4373866915702820e-02</leafValues></_>
+            -7.0271849632263184e-01 5.5648274719715118e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 153 4.9622595310211182e-02</internalNodes>
+            0 -1 768 -8.7264683097600937e-03</internalNodes>
           <leafValues>
-            -9.4219848513603210e-02 4.9830704927444458e-01</leafValues></_>
+            2.6393634080886841e-01 -1.8446569144725800e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 89 -6.2201134860515594e-02</internalNodes>
+            0 -1 57 8.1868227571249008e-03</internalNodes>
           <leafValues>
-            5.1749163866043091e-01 -9.4065755605697632e-02</leafValues></_>
+            8.0838531255722046e-02 -5.5512112379074097e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 100 -9.0873138979077339e-03</internalNodes>
+            0 -1 139 -7.8468751162290573e-03</internalNodes>
           <leafValues>
-            -6.6816878318786621e-01 7.1877375245094299e-02</leafValues></_>
+            -5.7306796312332153e-01 8.3454042673110962e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 142 7.8745372593402863e-03</internalNodes>
+            0 -1 665 2.9962153639644384e-03</internalNodes>
           <leafValues>
-            6.2571905553340912e-02 -6.6562908887863159e-01</leafValues></_>
+            6.2645487487316132e-02 -5.8123600482940674e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 489 6.6907280124723911e-03</internalNodes>
+            0 -1 414 -4.3795984238386154e-03</internalNodes>
           <leafValues>
-            -1.0588129609823227e-01 4.0728682279586792e-01</leafValues></_>
+            2.2211562097072601e-01 -1.9649308919906616e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 811 8.9093092828989029e-03</internalNodes>
+            0 -1 908 -6.3172029331326485e-03</internalNodes>
           <leafValues>
-            -1.3461567461490631e-01 3.1837779283523560e-01</leafValues></_>
+            -6.6067039966583252e-01 6.4884319901466370e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 908 3.9681773632764816e-03</internalNodes>
+            0 -1 465 1.3302030274644494e-03</internalNodes>
           <leafValues>
-            7.1942776441574097e-02 -6.0182863473892212e-01</leafValues></_>
+            -1.0496762394905090e-01 4.2326071858406067e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 547 1.1530296877026558e-02</internalNodes>
+            0 -1 951 -4.3333107605576515e-03</internalNodes>
           <leafValues>
-            -1.2775546312332153e-01 3.0782708525657654e-01</leafValues></_>
+            -4.9972066283226013e-01 8.7225496768951416e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 497 -3.0327122658491135e-02</internalNodes>
+            0 -1 244 -3.5346355289220810e-03</internalNodes>
           <leafValues>
-            3.6777910590171814e-01 -1.4219322800636292e-01</leafValues></_>
+            3.0818134546279907e-01 -1.4765550196170807e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 765 -8.5609289817512035e-04</internalNodes>
+            0 -1 256 -8.7353587150573730e-03</internalNodes>
           <leafValues>
-            2.3868902027606964e-01 -1.7458973824977875e-01</leafValues></_>
+            -6.5214675664901733e-01 7.1881487965583801e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 30 -8.7312739342451096e-03</internalNodes>
+            0 -1 491 -1.5620354562997818e-02</internalNodes>
           <leafValues>
-            -5.7229250669479370e-01 6.7568361759185791e-02</leafValues></_>
+            3.5721915960311890e-01 -1.1427627503871918e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 515 3.6238119006156921e-02</internalNodes>
+            0 -1 778 -3.9745438843965530e-03</internalNodes>
           <leafValues>
-            -9.3856818974018097e-02 4.3806123733520508e-01</leafValues></_>
+            -6.6090464591979980e-01 6.2067609280347824e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 859 -1.7243899405002594e-02</internalNodes>
+            0 -1 689 -6.7040426656603813e-03</internalNodes>
           <leafValues>
-            3.2672104239463806e-01 -1.2465524673461914e-01</leafValues></_>
+            2.7337384223937988e-01 -1.4059108495712280e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 571 3.0146117787808180e-03</internalNodes>
+            0 -1 125 3.5359347239136696e-03</internalNodes>
           <leafValues>
-            8.4438301622867584e-02 -4.7965818643569946e-01</leafValues></_>
+            6.1201948672533035e-02 -6.0017114877700806e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 390 -6.5812864340841770e-03</internalNodes>
+            0 -1 118 6.0818484053015709e-03</internalNodes>
           <leafValues>
-            -6.5075701475143433e-01 5.2506592124700546e-02</leafValues></_>
+            -1.5247075259685516e-01 2.4383027851581573e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 379 -2.6519154198467731e-03</internalNodes>
+            0 -1 880 -7.2771648410707712e-04</internalNodes>
           <leafValues>
-            3.9998021721839905e-01 -1.2199153006076813e-01</leafValues></_>
+            3.0065426230430603e-01 -1.2037902325391769e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 336 2.2568926215171814e-03</internalNodes>
+            0 -1 643 4.6168416738510132e-03</internalNodes>
           <leafValues>
-            -1.1875165253877640e-01 3.6033150553703308e-01</leafValues></_>
+            5.5311698466539383e-02 -7.5343269109725952e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 342 7.8723561018705368e-03</internalNodes>
+            0 -1 676 2.5280299596488476e-03</internalNodes>
           <leafValues>
-            6.2930762767791748e-02 -7.2076427936553955e-01</leafValues></_>
+            5.7204965502023697e-02 -5.3993463516235352e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 826 5.7557085528969765e-04</internalNodes>
+            0 -1 878 1.5074670314788818e-02</internalNodes>
           <leafValues>
-            -1.9064085185527802e-01 1.9888252019882202e-01</leafValues></_>
+            -9.6106290817260742e-02 3.9084190130233765e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 197 -4.9874491989612579e-02</internalNodes>
+            0 -1 831 -8.4932018071413040e-03</internalNodes>
           <leafValues>
-            3.3844900131225586e-01 -1.0514739900827408e-01</leafValues></_>
+            3.4130987524986267e-01 -1.4117397367954254e-01</leafValues></_></weakClassifiers></_>
+    <!-- stage 4 -->
+    <_>
+      <maxWeakCount>37</maxWeakCount>
+      <stageThreshold>-1.3977209329605103e+00</stageThreshold>
+      <weakClassifiers>
         <_>
           <internalNodes>
-            0 -1 934 -5.1496019586920738e-03</internalNodes>
+            0 -1 794 -2.5338861159980297e-03</internalNodes>
           <leafValues>
-            2.3594251275062561e-01 -1.7097522318363190e-01</leafValues></_>
+            5.7321399450302124e-01 -2.0396080613136292e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 800 -4.2706914246082306e-03</internalNodes>
+            0 -1 588 -6.5112011507153511e-03</internalNodes>
           <leafValues>
-            3.9194715023040771e-01 -9.3349114060401917e-02</leafValues></_>
+            3.7378740310668945e-01 -2.5049039721488953e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 493 -1.0737263411283493e-01</internalNodes>
+            0 -1 238 1.6318978741765022e-03</internalNodes>
           <leafValues>
-            5.6014204025268555e-01 -6.5082974731922150e-02</leafValues></_></weakClassifiers></_>
-    <!-- stage 3 -->
-    <_>
-      <maxWeakCount>54</maxWeakCount>
-      <stageThreshold>-1.6577893495559692e+00</stageThreshold>
-      <weakClassifiers>
+            -2.1858637034893036e-01 3.5027471184730530e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 508 -9.3684419989585876e-03</internalNodes>
+            0 -1 189 3.3452022820711136e-02</internalNodes>
           <leafValues>
-            7.2173911333084106e-01 -1.8106427043676376e-02</leafValues></_>
+            -1.4827065169811249e-01 4.7324529290199280e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 255 1.2989062815904617e-03</internalNodes>
+            0 -1 192 -1.1114047840237617e-02</internalNodes>
           <leafValues>
-            -2.0532198250293732e-01 4.2473095655441284e-01</leafValues></_>
+            4.1662359237670898e-01 -2.1660456061363220e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 795 3.6645986139774323e-02</internalNodes>
+            0 -1 527 -1.2996498262509704e-03</internalNodes>
           <leafValues>
-            -1.6229844093322754e-01 5.1024991273880005e-01</leafValues></_>
+            4.7613915801048279e-01 -1.6742442548274994e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 163 7.4745947495102882e-03</internalNodes>
+            0 -1 648 -3.2986078877002001e-03</internalNodes>
           <leafValues>
-            -2.5622242689132690e-01 3.1706622242927551e-01</leafValues></_>
+            -6.7662662267684937e-01 8.6653761565685272e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 812 -6.4315330237150192e-03</internalNodes>
+            0 -1 4 6.6831205040216446e-03</internalNodes>
           <leafValues>
-            3.1292220950126648e-01 -2.2839428484439850e-01</leafValues></_>
+            -2.0158858597278595e-01 2.6189696788787842e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 341 3.9290782064199448e-02</internalNodes>
+            0 -1 482 2.1282089874148369e-03</internalNodes>
           <leafValues>
-            -1.3426035642623901e-01 5.8237910270690918e-01</leafValues></_>
+            -1.1156299710273743e-01 4.0097075700759888e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 459 7.8858569264411926e-02</internalNodes>
+            0 -1 682 -9.0472139418125153e-03</internalNodes>
           <leafValues>
-            -1.5872669219970703e-01 4.5478171110153198e-01</leafValues></_>
+            3.2078295946121216e-01 -1.6775439679622650e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 528 -2.8797138482332230e-02</internalNodes>
+            0 -1 226 -5.3160609677433968e-03</internalNodes>
           <leafValues>
-            5.3397864103317261e-01 -1.1107259988784790e-01</leafValues></_>
+            -5.5567348003387451e-01 1.2950280308723450e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 376 -1.0816241614520550e-02</internalNodes>
+            0 -1 205 7.9724024981260300e-03</internalNodes>
           <leafValues>
-            4.7242766618728638e-01 -9.8347179591655731e-02</leafValues></_>
+            -2.1466700732707977e-01 2.2514854371547699e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 5 2.8447926044464111e-02</internalNodes>
+            0 -1 920 -2.1980279125273228e-03</internalNodes>
           <leafValues>
-            -1.5696190297603607e-01 3.9995491504669189e-01</leafValues></_>
+            2.8711742162704468e-01 -1.6561916470527649e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 594 -4.1472744196653366e-03</internalNodes>
+            0 -1 312 5.3897619247436523e-02</internalNodes>
           <leafValues>
-            -6.5492427349090576e-01 8.9378200471401215e-02</leafValues></_>
+            -1.4823001623153687e-01 3.4951418638229370e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 780 3.7436613347381353e-03</internalNodes>
+            0 -1 13 -7.6241128146648407e-02</internalNodes>
           <leafValues>
-            -1.6716095805168152e-01 2.9251593351364136e-01</leafValues></_>
+            6.0101884603500366e-01 -8.8328786194324493e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 958 6.8116746842861176e-03</internalNodes>
+            0 -1 129 -8.3202747628092766e-03</internalNodes>
           <leafValues>
-            8.5507057607173920e-02 -6.0906678438186646e-01</leafValues></_>
+            -7.2828358411788940e-01 8.7956465780735016e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 128 4.9823587760329247e-03</internalNodes>
+            0 -1 401 5.3778752684593201e-02</internalNodes>
           <leafValues>
-            6.6678501665592194e-02 -5.8637374639511108e-01</leafValues></_>
+            -1.0316975414752960e-01 5.0247919559478760e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 401 4.1811540722846985e-03</internalNodes>
+            0 -1 416 -1.2401826679706573e-02</internalNodes>
           <leafValues>
-            -1.0231449455022812e-01 4.5615595579147339e-01</leafValues></_>
+            2.7538898587226868e-01 -1.5569972991943359e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 162 -1.0445066727697849e-02</internalNodes>
+            0 -1 986 1.3729928061366081e-02</internalNodes>
           <leafValues>
-            -7.6294642686843872e-01 5.7752605527639389e-02</leafValues></_>
+            -1.3373774290084839e-01 3.0739122629165649e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 315 -6.1920420266687870e-03</internalNodes>
+            0 -1 905 -2.2788168862462044e-03</internalNodes>
           <leafValues>
-            -6.6523051261901855e-01 5.2041802555322647e-02</leafValues></_>
+            2.2555501759052277e-01 -1.9497908651828766e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 925 -2.3358925245702267e-03</internalNodes>
+            0 -1 667 3.6288173869252205e-03</internalNodes>
           <leafValues>
-            3.2779076695442200e-01 -1.3041152060031891e-01</leafValues></_>
+            4.8981692641973495e-02 -7.9248648881912231e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 314 -5.6658107787370682e-03</internalNodes>
+            0 -1 85 5.2453137934207916e-02</internalNodes>
           <leafValues>
-            -6.8133842945098877e-01 5.6511644273996353e-02</leafValues></_>
+            -1.3389803469181061e-01 3.2700663805007935e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 819 -1.0911209508776665e-02</internalNodes>
+            0 -1 821 3.1685843132436275e-03</internalNodes>
           <leafValues>
-            3.3160626888275146e-01 -1.2574554979801178e-01</leafValues></_>
+            -1.4415425062179565e-01 2.8044179081916809e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 765 -1.7958178650587797e-03</internalNodes>
+            0 -1 193 8.9051481336355209e-03</internalNodes>
           <leafValues>
-            3.0492588877677917e-01 -1.5025834739208221e-01</leafValues></_>
+            6.1227656900882721e-02 -7.0277702808380127e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 961 -4.0859095752239227e-03</internalNodes>
+            0 -1 837 -1.3966157566756010e-03</internalNodes>
           <leafValues>
-            -5.3059929609298706e-01 7.3518328368663788e-02</leafValues></_>
+            4.2409667372703552e-01 -1.0888981819152832e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 232 -2.0980034023523331e-02</internalNodes>
+            0 -1 271 -6.7695947363972664e-03</internalNodes>
           <leafValues>
-            3.0610927939414978e-01 -1.2851184606552124e-01</leafValues></_>
+            -5.1588076353073120e-01 8.3254821598529816e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 452 -7.3018344119191170e-03</internalNodes>
+            0 -1 404 2.2157761268317699e-03</internalNodes>
           <leafValues>
-            3.7514328956604004e-01 -1.2826474010944366e-01</leafValues></_>
+            -1.3696527481079102e-01 2.8638482093811035e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 465 -2.9183469712734222e-02</internalNodes>
+            0 -1 619 2.7808796148747206e-03</internalNodes>
           <leafValues>
-            4.8722788691520691e-01 -8.4734588861465454e-02</leafValues></_>
+            7.1316704154014587e-02 -6.0322999954223633e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 609 4.1865529492497444e-03</internalNodes>
+            0 -1 515 4.5836241915822029e-03</internalNodes>
           <leafValues>
-            7.4395999312400818e-02 -5.8252948522567749e-01</leafValues></_>
+            -1.2486589699983597e-01 3.2929363846778870e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 662 -1.3149678707122803e-02</internalNodes>
+            0 -1 1042 -5.1459800451993942e-03</internalNodes>
           <leafValues>
-            2.9923921823501587e-01 -1.3687820732593536e-01</leafValues></_>
+            -5.3781992197036743e-01 7.6631128787994385e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 209 2.3594651371240616e-02</internalNodes>
+            0 -1 1043 2.4449056945741177e-03</internalNodes>
           <leafValues>
-            6.2197674065828323e-02 -6.3622504472732544e-01</leafValues></_>
+            8.5920669138431549e-02 -4.0670683979988098e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 630 -1.7678245902061462e-02</internalNodes>
+            0 -1 71 -2.7756379917263985e-02</internalNodes>
           <leafValues>
-            3.3281046152114868e-01 -1.2175620347261429e-01</leafValues></_>
+            3.7449231743812561e-01 -1.0538945347070694e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 544 -1.0656865313649178e-02</internalNodes>
+            0 -1 809 -1.8243372440338135e-02</internalNodes>
           <leafValues>
-            3.7733754515647888e-01 -1.0491474717855453e-01</leafValues></_>
+            3.4281516075134277e-01 -9.9502928555011749e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 710 5.6399200111627579e-03</internalNodes>
+            0 -1 372 3.8416781462728977e-03</internalNodes>
           <leafValues>
-            5.4276369512081146e-02 -7.2659504413604736e-01</leafValues></_>
+            7.3987491428852081e-02 -4.8903524875640869e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 536 5.9759367257356644e-02</internalNodes>
+            0 -1 376 -1.2322908267378807e-02</internalNodes>
           <leafValues>
-            -9.3571089208126068e-02 4.3768402934074402e-01</leafValues></_>
+            2.1036790311336517e-01 -1.5852701663970947e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 836 1.5957858413457870e-03</internalNodes>
+            0 -1 391 -4.1760304011404514e-03</internalNodes>
           <leafValues>
-            -7.4856951832771301e-02 4.6114641427993774e-01</leafValues></_>
+            3.1288132071495056e-01 -1.1697492748498917e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 331 -3.4797050058841705e-02</internalNodes>
+            0 -1 859 -2.8026863932609558e-02</internalNodes>
           <leafValues>
-            4.3322169780731201e-01 -1.0314103215932846e-01</leafValues></_>
+            3.3711743354797363e-01 -1.2294299900531769e-01</leafValues></_></weakClassifiers></_>
+    <!-- stage 5 -->
+    <_>
+      <maxWeakCount>42</maxWeakCount>
+      <stageThreshold>-1.3775455951690674e+00</stageThreshold>
+      <weakClassifiers>
         <_>
           <internalNodes>
-            0 -1 357 7.0810377597808838e-02</internalNodes>
+            0 -1 725 1.3382414355874062e-02</internalNodes>
           <leafValues>
-            -1.3931407034397125e-01 2.7839028835296631e-01</leafValues></_>
+            -1.7922241985797882e-01 5.0368404388427734e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 688 1.0995890479534864e-03</internalNodes>
+            0 -1 967 1.9935802556574345e-03</internalNodes>
           <leafValues>
-            8.2519724965095520e-02 -4.6114745736122131e-01</leafValues></_>
+            -2.5249919295310974e-01 3.5295018553733826e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 271 1.1323073413223028e-03</internalNodes>
+            0 -1 891 -1.3569685397669673e-03</internalNodes>
           <leafValues>
-            -1.1879909038543701e-01 3.1659367680549622e-01</leafValues></_>
+            4.1222429275512695e-01 -1.8140394985675812e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 59 2.5819817557930946e-02</internalNodes>
+            0 -1 911 2.5418698787689209e-03</internalNodes>
           <leafValues>
-            -1.0563226789236069e-01 3.3343997597694397e-01</leafValues></_>
+            -2.3195247352123260e-01 2.5945317745208740e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 127 -3.0109258368611336e-03</internalNodes>
+            0 -1 362 1.1867792345583439e-03</internalNodes>
           <leafValues>
-            -4.3363004922866821e-01 9.0100899338722229e-02</leafValues></_>
+            -1.1509010195732117e-01 4.0095508098602295e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 738 6.4696911722421646e-03</internalNodes>
+            0 -1 280 -4.0491363033652306e-03</internalNodes>
           <leafValues>
-            4.3469883501529694e-02 -6.7987263202667236e-01</leafValues></_>
+            -7.6275551319122314e-01 8.0663219094276428e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 659 1.6815876588225365e-02</internalNodes>
+            0 -1 264 2.4698153138160706e-02</internalNodes>
           <leafValues>
-            -9.4611480832099915e-02 3.5600626468658447e-01</leafValues></_>
+            -9.9053405225276947e-02 4.6469488739967346e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 642 -1.0637525469064713e-02</internalNodes>
+            0 -1 832 1.3041709549725056e-02</internalNodes>
           <leafValues>
-            1.9808849692344666e-01 -1.5571328997612000e-01</leafValues></_>
+            -1.3049817085266113e-01 4.7066822648048401e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 433 -4.1952659375965595e-03</internalNodes>
+            0 -1 257 -2.0927201956510544e-02</internalNodes>
           <leafValues>
-            -5.3476226329803467e-01 6.5039873123168945e-02</leafValues></_>
+            -7.2363191843032837e-01 7.5520738959312439e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 442 -1.5134566929191351e-03</internalNodes>
+            0 -1 41 1.6108792275190353e-02</internalNodes>
           <leafValues>
-            4.2552566528320312e-01 -8.3483003079891205e-02</leafValues></_>
+            8.9385204017162323e-02 -5.0678378343582153e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 375 -1.1657587019726634e-03</internalNodes>
+            0 -1 872 -8.6308103054761887e-03</internalNodes>
           <leafValues>
-            2.4901403486728668e-01 -1.2862072885036469e-01</leafValues></_>
+            3.1878158450126648e-01 -1.3526505231857300e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 495 5.2369404584169388e-03</internalNodes>
+            0 -1 347 1.2651814613491297e-03</internalNodes>
           <leafValues>
-            5.4264735430479050e-02 -6.5448409318923950e-01</leafValues></_>
+            -1.2344279885292053e-01 4.0271109342575073e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 325 3.1857702415436506e-03</internalNodes>
+            0 -1 735 -3.0170590616762638e-03</internalNodes>
           <leafValues>
-            -1.0423248261213303e-01 3.4729331731796265e-01</leafValues></_>
+            -5.6960099935531616e-01 7.0437252521514893e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 468 3.2315873540937901e-03</internalNodes>
+            0 -1 538 -3.5529488231986761e-03</internalNodes>
           <leafValues>
-            7.3592320084571838e-02 -4.5663174986839294e-01</leafValues></_>
+            2.0624065399169922e-01 -1.8426756560802460e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 61 8.1546325236558914e-03</internalNodes>
+            0 -1 735 2.8021419420838356e-03</internalNodes>
           <leafValues>
-            5.8343004435300827e-02 -4.7462043166160583e-01</leafValues></_>
+            7.2748780250549316e-02 -5.3796368837356567e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 261 1.2796278111636639e-02</internalNodes>
+            0 -1 447 -9.9331419914960861e-04</internalNodes>
           <leafValues>
-            -1.0276926308870316e-01 3.4186348319053650e-01</leafValues></_>
+            2.4827398359775543e-01 -1.5866567194461823e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 321 -2.3663226515054703e-02</internalNodes>
+            0 -1 440 -7.1950745768845081e-03</internalNodes>
           <leafValues>
-            2.8974771499633789e-01 -1.2335656583309174e-01</leafValues></_>
+            -5.0943744182586670e-01 7.3041573166847229e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 648 -1.9080806523561478e-03</internalNodes>
+            0 -1 906 -8.7737981230020523e-03</internalNodes>
           <leafValues>
-            -7.0497012138366699e-01 5.8831237256526947e-02</leafValues></_>
+            2.4838714301586151e-01 -1.5162147581577301e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 633 3.0501103028655052e-03</internalNodes>
+            0 -1 608 5.6750684976577759e-02</internalNodes>
           <leafValues>
-            5.1351051777601242e-02 -5.2438431978225708e-01</leafValues></_>
+            -8.4416143596172333e-02 4.4269657135009766e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 204 -4.1300453245639801e-02</internalNodes>
+            0 -1 772 1.8110256642103195e-03</internalNodes>
           <leafValues>
-            -4.2261663079261780e-01 6.5464369952678680e-02</leafValues></_></weakClassifiers></_>
-    <!-- stage 4 -->
-    <_>
-      <maxWeakCount>66</maxWeakCount>
-      <stageThreshold>-1.6743642091751099e+00</stageThreshold>
-      <weakClassifiers>
+            -1.7787678539752960e-01 2.2753682732582092e-01</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 117 6.1733853071928024e-02</internalNodes>
+          <leafValues>
+            -1.4452947676181793e-01 2.6785543560981750e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 699 1.3901394791901112e-02</internalNodes>
+            0 -1 718 1.7999792471528053e-03</internalNodes>
           <leafValues>
-            4.2875479906797409e-02 7.1057194471359253e-01</leafValues></_>
+            5.3869031369686127e-02 -7.0216673612594604e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 444 -1.0640731081366539e-02</internalNodes>
+            0 -1 718 -1.7839821521192789e-03</internalNodes>
           <leafValues>
-            5.9900563955307007e-01 -1.4475977420806885e-01</leafValues></_>
+            -7.3474282026290894e-01 4.3809492141008377e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 763 -4.2351996526122093e-03</internalNodes>
+            0 -1 795 -2.2269869223237038e-03</internalNodes>
           <leafValues>
-            4.9660456180572510e-01 -1.1618923395872116e-01</leafValues></_>
+            2.5256577134132385e-01 -1.4765015244483948e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 834 1.3073073700070381e-02</internalNodes>
+            0 -1 845 7.7408831566572189e-04</internalNodes>
           <leafValues>
-            -1.6428959369659424e-01 5.0240677595138550e-01</leafValues></_>
+            -1.6781617701053619e-01 2.5267890095710754e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 879 -5.0384560599923134e-03</internalNodes>
+            0 -1 710 9.6316616982221603e-03</internalNodes>
           <leafValues>
-            4.1822317242622375e-01 -1.4690572023391724e-01</leafValues></_>
+            5.8525908738374710e-02 -6.3684886693954468e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 443 1.2402677675709128e-03</internalNodes>
+            0 -1 181 -1.1892126873135567e-02</internalNodes>
           <leafValues>
-            -2.0295573770999908e-01 2.7518931031227112e-01</leafValues></_>
+            2.6363542675971985e-01 -1.4106634259223938e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 688 -1.8025336321443319e-03</internalNodes>
+            0 -1 326 4.8407237976789474e-02</internalNodes>
           <leafValues>
-            -7.3610079288482666e-01 7.6008267700672150e-02</leafValues></_>
+            -1.0837136209011078e-01 3.6018091440200806e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 282 9.2999219894409180e-02</internalNodes>
+            0 -1 572 -1.0315750539302826e-01</internalNodes>
           <leafValues>
-            -1.4368277788162231e-01 3.3687326312065125e-01</leafValues></_>
+            -7.3309695720672607e-01 6.4976803958415985e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 293 2.1399226039648056e-02</internalNodes>
+            0 -1 415 -2.6544972788542509e-03</internalNodes>
           <leafValues>
-            -1.6605213284492493e-01 3.0147713422775269e-01</leafValues></_>
+            2.7709859609603882e-01 -1.3764445483684540e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 703 9.3348361551761627e-03</internalNodes>
+            0 -1 1033 -4.8850756138563156e-03</internalNodes>
           <leafValues>
-            -1.6568347811698914e-01 3.0875685811042786e-01</leafValues></_>
+            -5.0026285648345947e-01 6.8797707557678223e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 382 -5.8921691961586475e-03</internalNodes>
+            0 -1 299 -1.1310833506286144e-02</internalNodes>
           <leafValues>
-            -5.6214910745620728e-01 8.5347160696983337e-02</leafValues></_>
+            2.5653550028800964e-01 -1.3755545020103455e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 260 -1.4118023682385683e-03</internalNodes>
+            0 -1 152 -3.8394361734390259e-02</internalNodes>
           <leafValues>
-            2.6530963182449341e-01 -1.8439114093780518e-01</leafValues></_>
+            2.6404461264610291e-01 -1.3614650070667267e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 360 -1.1060921475291252e-02</internalNodes>
+            0 -1 486 5.8298893272876740e-03</internalNodes>
           <leafValues>
-            2.5005301833152771e-01 -1.7930330336093903e-01</leafValues></_>
+            6.0382172465324402e-02 -5.9578329324722290e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 751 -3.8227883633226156e-03</internalNodes>
+            0 -1 393 2.2631133906543255e-03</internalNodes>
           <leafValues>
-            -6.9963920116424561e-01 6.4229309558868408e-02</leafValues></_>
+            -1.0302778333425522e-01 3.4782779216766357e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 900 -8.4845684468746185e-03</internalNodes>
+            0 -1 629 -1.8709234893321991e-02</internalNodes>
           <leafValues>
-            -6.6004335880279541e-01 5.2848633378744125e-02</leafValues></_>
+            -7.6758313179016113e-01 4.6181913465261459e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 21 6.9843865931034088e-03</internalNodes>
+            0 -1 67 3.7359733134508133e-02</internalNodes>
           <leafValues>
-            5.5426578968763351e-02 -6.1068946123123169e-01</leafValues></_>
+            -1.3407541811466217e-01 2.5607112050056458e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 952 4.8600544687360525e-04</internalNodes>
+            0 -1 504 -5.3099328652024269e-03</internalNodes>
           <leafValues>
-            -1.8981190025806427e-01 2.1059055626392365e-01</leafValues></_>
+            -6.9016355276107788e-01 4.7683756798505783e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 111 3.5324528813362122e-02</internalNodes>
+            0 -1 527 -1.5396323287859559e-03</internalNodes>
           <leafValues>
-            -8.3993434906005859e-02 5.1941823959350586e-01</leafValues></_>
+            3.7874689698219299e-01 -9.2663109302520752e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 97 3.9002462290227413e-03</internalNodes>
+            0 -1 470 -2.6333518326282501e-03</internalNodes>
           <leafValues>
-            7.6367795467376709e-02 -5.7813030481338501e-01</leafValues></_>
+            2.9358446598052979e-01 -1.2460695207118988e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 374 -4.5398771762847900e-03</internalNodes>
+            0 -1 171 1.6515964642167091e-02</internalNodes>
           <leafValues>
-            3.3430457115173340e-01 -1.2331557273864746e-01</leafValues></_>
+            -1.4082725346088409e-01 2.3664724826812744e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 652 -3.1904221978038549e-03</internalNodes>
+            0 -1 681 -4.4658156111836433e-03</internalNodes>
           <leafValues>
-            -5.5545800924301147e-01 7.3627986013889313e-02</leafValues></_>
+            -5.9253305196762085e-01 5.5994171649217606e-02</leafValues></_></weakClassifiers></_>
+    <!-- stage 6 -->
+    <_>
+      <maxWeakCount>50</maxWeakCount>
+      <stageThreshold>-1.3835698366165161e+00</stageThreshold>
+      <weakClassifiers>
         <_>
           <internalNodes>
-            0 -1 14 -7.7975630760192871e-02</internalNodes>
+            0 -1 898 1.5156399458646774e-03</internalNodes>
           <leafValues>
-            4.8881098628044128e-01 -8.1377774477005005e-02</leafValues></_>
+            -1.0024535655975342e-01 5.8807808160781860e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 7 -1.1978685855865479e-02</internalNodes>
+            0 -1 802 -3.5168868489563465e-03</internalNodes>
           <leafValues>
-            2.7509516477584839e-01 -1.6613669693470001e-01</leafValues></_>
+            4.0972998738288879e-01 -1.6088742017745972e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 29 -8.3151785656809807e-03</internalNodes>
+            0 -1 180 2.3035616613924503e-03</internalNodes>
           <leafValues>
-            -5.9314393997192383e-01 7.2014525532722473e-02</leafValues></_>
+            -1.8985269963741302e-01 2.9883998632431030e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 466 1.3827871531248093e-02</internalNodes>
+            0 -1 254 4.5840561389923096e-02</internalNodes>
           <leafValues>
-            -1.2803319096565247e-01 2.9465702176094055e-01</leafValues></_>
+            -1.4383240044116974e-01 4.7528687119483948e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 356 2.0103808492422104e-02</internalNodes>
+            0 -1 405 5.5156396701931953e-03</internalNodes>
           <leafValues>
-            6.9175720214843750e-02 -5.6205666065216064e-01</leafValues></_>
+            -1.7356806993484497e-01 3.4583050012588501e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 530 -4.7183044254779816e-02</internalNodes>
+            0 -1 436 3.9731184951961040e-03</internalNodes>
           <leafValues>
-            3.6449643969535828e-01 -1.0480687767267227e-01</leafValues></_>
+            7.8886620700359344e-02 -5.6442558765411377e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 613 9.7303036600351334e-03</internalNodes>
+            0 -1 412 -5.6995991617441177e-03</internalNodes>
           <leafValues>
-            -9.7578004002571106e-02 3.6821505427360535e-01</leafValues></_>
+            -4.7576662898063660e-01 9.4875656068325043e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 667 -3.9133569225668907e-03</internalNodes>
+            0 -1 539 -9.6501735970377922e-03</internalNodes>
           <leafValues>
-            -5.1443296670913696e-01 7.2868466377258301e-02</leafValues></_>
+            2.3381656408309937e-01 -1.8310526013374329e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 666 3.0236630700528622e-03</internalNodes>
+            0 -1 209 6.1656545847654343e-02</internalNodes>
           <leafValues>
-            5.5799212306737900e-02 -5.3572463989257812e-01</leafValues></_>
+            -1.4697165787220001e-01 3.6247691512107849e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 304 4.3436158448457718e-03</internalNodes>
+            0 -1 398 1.1418928205966949e-01</internalNodes>
           <leafValues>
-            -1.5579865872859955e-01 2.0468661189079285e-01</leafValues></_>
+            -8.8033527135848999e-02 4.4633501768112183e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 51 1.4063127338886261e-02</internalNodes>
+            0 -1 3 -1.1903396807610989e-02</internalNodes>
           <leafValues>
-            3.6827385425567627e-02 -8.5656464099884033e-01</leafValues></_>
+            3.3496665954589844e-01 -1.2121009081602097e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 842 1.3388927327468991e-03</internalNodes>
+            0 -1 546 -4.1371315717697144e-02</internalNodes>
           <leafValues>
-            -1.2769578397274017e-01 2.8884974122047424e-01</leafValues></_>
+            4.1400006413459778e-01 -9.7229279577732086e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 791 -1.0684424778446555e-03</internalNodes>
+            0 -1 380 7.8342631459236145e-03</internalNodes>
           <leafValues>
-            3.4348404407501221e-01 -9.6543140709400177e-02</leafValues></_>
+            -1.6631671786308289e-01 2.5738984346389771e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 779 -2.3754546418786049e-03</internalNodes>
+            0 -1 304 -4.5139621943235397e-03</internalNodes>
           <leafValues>
-            -5.2730453014373779e-01 6.6801987588405609e-02</leafValues></_>
+            -4.6883803606033325e-01 8.7662570178508759e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 549 -4.5106699690222740e-03</internalNodes>
+            0 -1 929 1.5914421528577805e-03</internalNodes>
           <leafValues>
-            -5.4066735506057739e-01 5.1074951887130737e-02</leafValues></_>
+            -1.1636006087064743e-01 3.2739594578742981e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 487 5.6549627333879471e-03</internalNodes>
+            0 -1 942 -5.2607608959078789e-03</internalNodes>
           <leafValues>
-            -9.0248994529247284e-02 3.5249757766723633e-01</leafValues></_>
+            -6.7755740880966187e-01 5.1752120256423950e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 494 -3.3719413913786411e-03</internalNodes>
+            0 -1 941 3.1824512407183647e-03</internalNodes>
           <leafValues>
-            2.8907671570777893e-01 -1.1475016921758652e-01</leafValues></_>
+            5.2379645407199860e-02 -6.0918039083480835e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 135 1.2221395969390869e-02</internalNodes>
+            0 -1 939 -3.6813789047300816e-03</internalNodes>
           <leafValues>
-            -1.0579165816307068e-01 3.0012521147727966e-01</leafValues></_>
+            4.8251116275787354e-01 -9.2318780720233917e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 79 3.2931473106145859e-03</internalNodes>
+            0 -1 622 -4.3226117268204689e-03</internalNodes>
           <leafValues>
-            7.7675424516201019e-02 -4.1641706228256226e-01</leafValues></_>
+            -5.7561415433883667e-01 5.9672243893146515e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 79 -3.7331613712012768e-03</internalNodes>
+            0 -1 250 -7.1843853220343590e-03</internalNodes>
           <leafValues>
-            -4.6958047151565552e-01 7.6012723147869110e-02</leafValues></_>
+            2.6631006598472595e-01 -1.4015418291091919e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 15 -3.0090190470218658e-02</internalNodes>
+            0 -1 871 2.1028071641921997e-03</internalNodes>
           <leafValues>
-            -6.2376546859741211e-01 4.4617597013711929e-02</leafValues></_>
+            -1.1286304146051407e-01 3.5946926474571228e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 538 -1.1998139321804047e-02</internalNodes>
+            0 -1 22 8.5248583927750587e-03</internalNodes>
           <leafValues>
-            3.4000751376152039e-01 -9.7472421824932098e-02</leafValues></_>
+            6.9424033164978027e-02 -5.2462881803512573e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 592 2.5055123493075371e-02</internalNodes>
+            0 -1 147 6.9785099476575851e-03</internalNodes>
           <leafValues>
-            -7.5190685689449310e-02 4.1993573307991028e-01</leafValues></_>
+            5.6668873876333237e-02 -5.6192052364349365e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 233 9.7161782905459404e-03</internalNodes>
+            0 -1 474 -5.2639590576291084e-03</internalNodes>
           <leafValues>
-            5.5982969701290131e-02 -6.0615026950836182e-01</leafValues></_>
+            -5.8648955821990967e-01 5.0352573394775391e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 198 -8.3486355841159821e-02</internalNodes>
+            0 -1 406 2.8417459689080715e-03</internalNodes>
           <leafValues>
-            3.7426739931106567e-01 -8.7825424969196320e-02</leafValues></_>
+            -1.3425759971141815e-01 2.7325555682182312e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 110 3.8952599279582500e-03</internalNodes>
+            0 -1 394 -1.3187457807362080e-02</internalNodes>
           <leafValues>
-            -1.3330259919166565e-01 2.6031884551048279e-01</leafValues></_>
+            4.0453648567199707e-01 -9.1843754053115845e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 648 -9.8262424580752850e-04</internalNodes>
+            0 -1 722 -6.7344801500439644e-03</internalNodes>
           <leafValues>
-            -3.9980980753898621e-01 8.2922257483005524e-02</leafValues></_>
+            -7.5647395849227905e-01 5.0157479941844940e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 58 8.4215197712182999e-03</internalNodes>
+            0 -1 187 2.1363141015172005e-02</internalNodes>
           <leafValues>
-            -1.3371372222900391e-01 2.4220858514308929e-01</leafValues></_>
+            4.7982390969991684e-02 -5.5388218164443970e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 287 1.2292047031223774e-03</internalNodes>
+            0 -1 623 1.6145884292200208e-03</internalNodes>
           <leafValues>
-            -7.7718295156955719e-02 3.8342806696891785e-01</leafValues></_>
+            7.9808227717876434e-02 -3.7233716249465942e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 682 -1.2375478632748127e-02</internalNodes>
+            0 -1 525 -2.2595757618546486e-03</internalNodes>
           <leafValues>
-            2.3885957896709442e-01 -1.2220640480518341e-01</leafValues></_>
+            2.8343635797500610e-01 -1.1216876655817032e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 292 5.4268687963485718e-03</internalNodes>
+            0 -1 214 1.4407988637685776e-02</internalNodes>
           <leafValues>
-            5.5337987840175629e-02 -5.6287312507629395e-01</leafValues></_>
+            -1.0392460227012634e-01 3.1299999356269836e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 418 -5.5062575265765190e-03</internalNodes>
+            0 -1 476 -1.4912552433088422e-03</internalNodes>
           <leafValues>
-            -5.7845181226730347e-01 4.2599424719810486e-02</leafValues></_>
+            2.8538599610328674e-01 -1.0644508898258209e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 614 1.0439271107316017e-02</internalNodes>
+            0 -1 195 9.8895151168107986e-03</internalNodes>
           <leafValues>
-            -8.1215575337409973e-02 3.8115817308425903e-01</leafValues></_>
+            5.0090074539184570e-02 -6.2053185701370239e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 296 -2.6399283669888973e-03</internalNodes>
+            0 -1 115 4.2754956521093845e-03</internalNodes>
           <leafValues>
-            -4.5001742243766785e-01 6.7338116466999054e-02</leafValues></_>
+            6.5051443874835968e-02 -4.2582303285598755e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 898 2.6166734751313925e-03</internalNodes>
+            0 -1 754 -2.5489409454166889e-03</internalNodes>
           <leafValues>
-            5.5316500365734100e-02 -4.4958963990211487e-01</leafValues></_>
+            3.1278640031814575e-01 -9.9601686000823975e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 759 5.4496107622981071e-03</internalNodes>
+            0 -1 717 -6.0358326882123947e-03</internalNodes>
           <leafValues>
-            -8.1449449062347412e-02 3.8300925493240356e-01</leafValues></_>
+            2.2685267031192780e-01 -1.3849361240863800e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 762 3.4203347750008106e-03</internalNodes>
+            0 -1 875 1.1879121884703636e-02</internalNodes>
           <leafValues>
-            -8.8027402758598328e-02 3.0551746487617493e-01</leafValues></_>
+            -8.9687183499336243e-02 3.7642294168472290e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 19 9.3909027054905891e-03</internalNodes>
+            0 -1 111 1.2982923537492752e-02</internalNodes>
           <leafValues>
-            5.8738458901643753e-02 -4.9437648057937622e-01</leafValues></_>
+            4.3990727514028549e-02 -7.3371982574462891e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 276 9.6318572759628296e-03</internalNodes>
+            0 -1 993 -2.8599319048225880e-03</internalNodes>
           <leafValues>
-            -1.0816254466772079e-01 2.7723982930183411e-01</leafValues></_>
+            -4.3102917075157166e-01 5.9561621397733688e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 87 1.9004285335540771e-02</internalNodes>
+            0 -1 737 -3.5829999251291156e-04</internalNodes>
           <leafValues>
-            -8.2863554358482361e-02 3.1288793683052063e-01</leafValues></_>
+            1.7152757942676544e-01 -1.6511310636997223e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 580 -8.5283098742365837e-03</internalNodes>
+            0 -1 27 2.5972571223974228e-02</internalNodes>
           <leafValues>
-            2.9951119422912598e-01 -8.9406743645668030e-02</leafValues></_>
+            -1.2855969369411469e-01 2.2820757329463959e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 242 6.2621399760246277e-02</internalNodes>
+            0 -1 516 4.2565623298287392e-03</internalNodes>
           <leafValues>
-            -1.0106554627418518e-01 2.6782277226448059e-01</leafValues></_>
+            5.7662181556224823e-02 -5.3734982013702393e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 372 1.5604515559971333e-02</internalNodes>
+            0 -1 50 -2.9159568250179291e-02</internalNodes>
           <leafValues>
-            -1.0081429034471512e-01 2.9597061872482300e-01</leafValues></_>
+            -6.3020753860473633e-01 4.0746636688709259e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 351 1.3034233450889587e-01</internalNodes>
+            0 -1 413 3.1341956928372383e-03</internalNodes>
           <leafValues>
-            -8.0539934337139130e-02 3.4444472193717957e-01</leafValues></_>
+            -8.1374719738960266e-02 4.1371321678161621e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 53 4.5186877250671387e-02</internalNodes>
+            0 -1 935 -1.3592604082077742e-03</internalNodes>
           <leafValues>
-            5.8131664991378784e-02 -5.4693692922592163e-01</leafValues></_></weakClassifiers></_>
-    <!-- stage 5 -->
+            3.2382342219352722e-01 -9.7880341112613678e-02</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 758 -6.9904811680316925e-03</internalNodes>
+          <leafValues>
+            -6.8850576877593994e-01 4.2428225278854370e-02</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 93 -8.7879784405231476e-03</internalNodes>
+          <leafValues>
+            -5.8945190906524658e-01 3.7613209336996078e-02</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 491 -1.7947785556316376e-02</internalNodes>
+          <leafValues>
+            3.1659606099128723e-01 -8.7437197566032410e-02</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 490 8.0379713326692581e-03</internalNodes>
+          <leafValues>
+            -1.1311284452676773e-01 3.0860018730163574e-01</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 716 3.0642822384834290e-03</internalNodes>
+          <leafValues>
+            4.8351831734180450e-02 -6.0563534498214722e-01</leafValues></_></weakClassifiers></_>
+    <!-- stage 7 -->
     <_>
-      <maxWeakCount>72</maxWeakCount>
-      <stageThreshold>-1.6700928211212158e+00</stageThreshold>
+      <maxWeakCount>54</maxWeakCount>
+      <stageThreshold>-1.3756012916564941e+00</stageThreshold>
       <weakClassifiers>
         <_>
           <internalNodes>
-            0 -1 763 -2.0017849747091532e-03</internalNodes>
+            0 -1 798 -1.7431776504963636e-03</internalNodes>
           <leafValues>
-            6.7056620121002197e-01 1.8883759155869484e-02</leafValues></_>
+            5.5538344383239746e-01 -1.0357239097356796e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 508 -1.5712467953562737e-02</internalNodes>
+            0 -1 425 4.4551412574946880e-03</internalNodes>
           <leafValues>
-            5.8154827356338501e-01 -1.4273743331432343e-01</leafValues></_>
+            -1.2460361421108246e-01 5.1942145824432373e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 146 2.4972280953079462e-03</internalNodes>
+            0 -1 843 3.5308140795677900e-03</internalNodes>
           <leafValues>
-            -1.8454430997371674e-01 3.4281551837921143e-01</leafValues></_>
+            -2.2974169254302979e-01 2.7043044567108154e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 824 5.7405559346079826e-03</internalNodes>
+            0 -1 532 -1.5887852758169174e-02</internalNodes>
           <leafValues>
-            -1.7856663465499878e-01 5.1571351289749146e-01</leafValues></_>
+            4.1745069622993469e-01 -1.1281611770391464e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 869 8.1182969734072685e-04</internalNodes>
+            0 -1 7 1.1611310765147209e-02</internalNodes>
           <leafValues>
-            -2.6075574755668640e-01 2.2161382436752319e-01</leafValues></_>
+            -1.9416445493698120e-01 2.5554594397544861e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 889 1.9957972690463066e-03</internalNodes>
+            0 -1 935 1.5740045346319675e-03</internalNodes>
           <leafValues>
-            -1.6690193116664886e-01 3.1083983182907104e-01</leafValues></_>
+            -1.2263108044862747e-01 3.8852572441101074e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 943 7.9797822982072830e-03</internalNodes>
+            0 -1 547 5.1882643252611160e-02</internalNodes>
           <leafValues>
-            -1.7903617024421692e-01 2.7573335170745850e-01</leafValues></_>
+            -7.5461924076080322e-02 5.0257563591003418e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 733 1.0206390172243118e-02</internalNodes>
+            0 -1 251 -3.8624972105026245e-02</internalNodes>
           <leafValues>
-            -9.3843363225460052e-02 5.3358590602874756e-01</leafValues></_>
+            4.0001305937767029e-01 -9.6231088042259216e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 388 3.4904260188341141e-02</internalNodes>
+            0 -1 272 -3.9408572018146515e-02</internalNodes>
           <leafValues>
-            -8.6874812841415405e-02 5.0340282917022705e-01</leafValues></_>
+            3.0533725023269653e-01 -1.6677139699459076e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 564 -3.8090778980404139e-03</internalNodes>
+            0 -1 29 7.5884531252086163e-03</internalNodes>
           <leafValues>
-            2.3382174968719482e-01 -1.7857478559017181e-01</leafValues></_>
+            9.8107770085334778e-02 -5.8249044418334961e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 160 2.0690055098384619e-03</internalNodes>
+            0 -1 218 7.2114326059818268e-02</internalNodes>
           <leafValues>
-            -1.8347945809364319e-01 2.1276330947875977e-01</leafValues></_>
+            -1.4419755339622498e-01 2.8208708763122559e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 367 -1.3203858397901058e-02</internalNodes>
+            0 -1 268 5.5582458153367043e-03</internalNodes>
           <leafValues>
-            3.0799895524978638e-01 -1.0921970754861832e-01</leafValues></_>
+            7.2843901813030243e-02 -5.5255079269409180e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 91 1.6044422984123230e-02</internalNodes>
+            0 -1 877 -4.7345291823148727e-03</internalNodes>
           <leafValues>
-            -1.2722490727901459e-01 3.5042104125022888e-01</leafValues></_>
+            3.3209753036499023e-01 -1.2499606609344482e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 52 -2.8435707092285156e-02</internalNodes>
+            0 -1 577 5.1413839682936668e-03</internalNodes>
           <leafValues>
-            -6.9257086515426636e-01 6.0832630842924118e-02</leafValues></_>
+            6.4787313342094421e-02 -6.4880597591400146e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 593 -3.5719089210033417e-03</internalNodes>
+            0 -1 999 5.4608630016446114e-03</internalNodes>
           <leafValues>
-            -6.1009460687637329e-01 5.5150210857391357e-02</leafValues></_>
+            3.7491828203201294e-02 -7.5315922498703003e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 526 -3.3032532781362534e-02</internalNodes>
+            0 -1 542 -8.6404485045932233e-05</internalNodes>
           <leafValues>
-            3.9706656336784363e-01 -1.0905303061008453e-01</leafValues></_>
+            1.7464619874954224e-01 -1.8258170783519745e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 863 -3.4918042365461588e-03</internalNodes>
+            0 -1 442 6.1132330447435379e-03</internalNodes>
           <leafValues>
-            2.2872641682624817e-01 -1.6809244453907013e-01</leafValues></_>
+            7.5624085962772369e-02 -4.3711006641387939e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 449 -1.2281725648790598e-03</internalNodes>
+            0 -1 889 -7.0670098066329956e-03</internalNodes>
           <leafValues>
-            2.8336051106452942e-01 -1.2107009440660477e-01</leafValues></_>
+            2.1796958148479462e-01 -1.4547325670719147e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 268 1.5130165964365005e-02</internalNodes>
+            0 -1 347 9.4080460257828236e-04</internalNodes>
           <leafValues>
-            7.4081726372241974e-02 -5.0906944274902344e-01</leafValues></_>
+            -1.2536728382110596e-01 2.8143358230590820e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 342 -5.2624624222517014e-03</internalNodes>
+            0 -1 580 -2.6800869964063168e-03</internalNodes>
           <leafValues>
-            -5.1471787691116333e-01 5.6423079222440720e-02</leafValues></_>
+            -4.2977494001388550e-01 8.2963027060031891e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 438 1.3198424130678177e-03</internalNodes>
+            0 -1 297 5.8945640921592712e-03</internalNodes>
           <leafValues>
-            -9.7633212804794312e-02 3.6938476562500000e-01</leafValues></_>
+            4.2834181338548660e-02 -6.0937494039535522e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 194 -3.9102118462324142e-03</internalNodes>
+            0 -1 465 1.0121082887053490e-03</internalNodes>
           <leafValues>
-            -7.5149536132812500e-01 5.1220502704381943e-02</leafValues></_>
+            -1.1036285758018494e-01 2.9971688985824585e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 235 7.7746850438416004e-03</internalNodes>
+            0 -1 56 3.1157936900854111e-03</internalNodes>
           <leafValues>
-            -1.6232925653457642e-01 2.0670217275619507e-01</leafValues></_>
+            7.3115289211273193e-02 -4.3226471543312073e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 555 -1.9946731626987457e-02</internalNodes>
+            0 -1 411 -3.3052214421331882e-03</internalNodes>
           <leafValues>
-            3.0092230439186096e-01 -9.9984362721443176e-02</leafValues></_>
+            -4.9826300144195557e-01 5.1225960254669189e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 457 -4.9132145941257477e-03</internalNodes>
+            0 -1 109 8.3188470453023911e-03</internalNodes>
           <leafValues>
-            2.1954736113548279e-01 -1.6271042823791504e-01</leafValues></_>
+            5.0362452864646912e-02 -4.8688000440597534e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 970 -6.4505757763981819e-03</internalNodes>
+            0 -1 393 -2.5094528682529926e-03</internalNodes>
           <leafValues>
-            -4.9815052747726440e-01 6.7167595028877258e-02</leafValues></_>
+            2.6902040839195251e-01 -1.0433372855186462e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 581 -6.7926600575447083e-02</internalNodes>
+            0 -1 924 1.1217880528420210e-03</internalNodes>
           <leafValues>
-            4.3458208441734314e-01 -7.7230423688888550e-02</leafValues></_>
+            -1.1188100278377533e-01 3.1254816055297852e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 789 -3.7927636876702309e-03</internalNodes>
+            0 -1 716 -2.9259414877742529e-03</internalNodes>
           <leafValues>
-            2.6469963788986206e-01 -1.2098944932222366e-01</leafValues></_>
+            -5.7495939731597900e-01 5.3564101457595825e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 38 -2.7826299890875816e-02</internalNodes>
+            0 -1 733 -1.1687271296977997e-02</internalNodes>
           <leafValues>
-            2.9173719882965088e-01 -1.0972167551517487e-01</leafValues></_>
+            2.5880128145217896e-01 -1.0639669001102448e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 332 6.0029705055058002e-03</internalNodes>
+            0 -1 763 3.5054073669016361e-03</internalNodes>
           <leafValues>
-            -1.0543220490217209e-01 3.6175185441970825e-01</leafValues></_>
+            5.4045904427766800e-02 -5.5625277757644653e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 972 1.4797106850892305e-03</internalNodes>
+            0 -1 552 1.9068794324994087e-02</internalNodes>
           <leafValues>
-            6.5247461199760437e-02 -5.3303873538970947e-01</leafValues></_>
+            -1.1246301978826523e-01 2.5745245814323425e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 102 9.7709074616432190e-03</internalNodes>
+            0 -1 230 4.6145436353981495e-03</internalNodes>
           <leafValues>
-            3.5595752298831940e-02 -6.8972426652908325e-01</leafValues></_>
+            6.7216314375400543e-02 -4.1385611891746521e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 874 4.5413424959406257e-04</internalNodes>
+            0 -1 857 -8.2267355173826218e-03</internalNodes>
           <leafValues>
-            -1.7233507335186005e-01 1.6001893579959869e-01</leafValues></_>
+            2.1265375614166260e-01 -1.3443692028522491e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 687 -1.4395804610103369e-03</internalNodes>
+            0 -1 149 -1.4355888590216637e-02</internalNodes>
           <leafValues>
-            -5.1606172323226929e-01 5.5443800985813141e-02</leafValues></_>
+            2.5618723034858704e-01 -1.0785522311925888e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 25 -2.4502794444561005e-01</internalNodes>
+            0 -1 61 8.0431215465068817e-03</internalNodes>
           <leafValues>
-            -8.0270200967788696e-01 2.9995493590831757e-02</leafValues></_>
+            -1.4258129894733429e-01 2.2692860662937164e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 410 4.2062443681061268e-03</internalNodes>
+            0 -1 170 -5.6914249435067177e-03</internalNodes>
           <leafValues>
-            5.0134483724832535e-02 -4.9082162976264954e-01</leafValues></_>
+            -4.8886317014694214e-01 6.0331270098686218e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 46 1.4561998657882214e-02</internalNodes>
+            0 -1 133 -2.5912215933203697e-03</internalNodes>
           <leafValues>
-            -1.2065179646015167e-01 2.4143299460411072e-01</leafValues></_>
+            2.1062785387039185e-01 -1.4967896044254303e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 74 -3.3104062080383301e-02</internalNodes>
+            0 -1 461 5.5204275995492935e-03</internalNodes>
           <leafValues>
-            3.6770820617675781e-01 -7.8033976256847382e-02</leafValues></_>
+            -8.1333734095096588e-02 3.8316065073013306e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 463 3.2625906169414520e-02</internalNodes>
+            0 -1 515 5.3790090605616570e-03</internalNodes>
           <leafValues>
-            -8.5231229662895203e-02 3.3994022011756897e-01</leafValues></_>
+            -9.3129634857177734e-02 3.2883483171463013e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 411 -1.1897137388586998e-02</internalNodes>
+            0 -1 199 -7.2196200489997864e-03</internalNodes>
           <leafValues>
-            2.6476562023162842e-01 -1.0443684458732605e-01</leafValues></_>
+            -6.6427856683731079e-01 4.4702950865030289e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 816 5.7352259755134583e-03</internalNodes>
+            0 -1 94 -8.3873540163040161e-02</internalNodes>
           <leafValues>
-            5.5395182222127914e-02 -5.1973640918731689e-01</leafValues></_>
+            -7.9910254478454590e-01 2.7107261121273041e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 170 -1.5062794089317322e-02</internalNodes>
+            0 -1 513 -3.4268260933458805e-03</internalNodes>
           <leafValues>
-            -7.5300645828247070e-01 3.0149688944220543e-02</leafValues></_>
+            2.5298807024955750e-01 -1.0898132622241974e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 661 -7.9075228422880173e-03</internalNodes>
+            0 -1 763 -3.7466005887836218e-03</internalNodes>
           <leafValues>
-            2.8287026286125183e-01 -1.0227695107460022e-01</leafValues></_>
+            -5.5346089601516724e-01 5.2094604820013046e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 394 3.2159998081624508e-03</internalNodes>
+            0 -1 276 1.2452949304133654e-03</internalNodes>
           <leafValues>
-            -6.5929308533668518e-02 3.6590230464935303e-01</leafValues></_>
+            -8.2017965614795685e-02 3.5483068227767944e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 987 -2.5269058533012867e-03</internalNodes>
+            0 -1 1013 -6.2445802614092827e-03</internalNodes>
           <leafValues>
-            -4.7419819235801697e-01 5.8165557682514191e-02</leafValues></_>
+            -5.0969594717025757e-01 5.4533429443836212e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 845 -1.8206760287284851e-03</internalNodes>
+            0 -1 276 -1.1970927007496357e-03</internalNodes>
           <leafValues>
-            2.5627982616424561e-01 -1.1308469623327255e-01</leafValues></_>
+            3.6470764875411987e-01 -7.7394872903823853e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 66 1.4899271540343761e-02</internalNodes>
+            0 -1 757 3.0796977225691080e-03</internalNodes>
           <leafValues>
-            3.6266356706619263e-02 -7.6167815923690796e-01</leafValues></_>
+            5.3208738565444946e-02 -5.0689512491226196e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 965 3.8532419130206108e-03</internalNodes>
+            0 -1 33 -3.9015077054500580e-02</internalNodes>
           <leafValues>
-            2.6696149259805679e-02 -7.5058454275131226e-01</leafValues></_>
+            1.9598089158535004e-01 -1.3218660652637482e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 723 -6.1673661693930626e-03</internalNodes>
+            0 -1 680 -7.7085788361728191e-03</internalNodes>
           <leafValues>
-            3.5572922229766846e-01 -8.2323268055915833e-02</leafValues></_>
+            2.2754703462123871e-01 -1.2544488906860352e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 822 -7.0832269266247749e-03</internalNodes>
+            0 -1 655 3.2509677112102509e-02</internalNodes>
           <leafValues>
-            2.1490900218486786e-01 -1.3906964659690857e-01</leafValues></_>
+            -6.7099742591381073e-02 4.1469818353652954e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 724 3.5079419612884521e-03</internalNodes>
+            0 -1 569 3.0232844874262810e-03</internalNodes>
           <leafValues>
-            4.7017443925142288e-02 -6.3156962394714355e-01</leafValues></_>
+            6.6373795270919800e-02 -4.2127549648284912e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 878 1.2706735869869590e-03</internalNodes>
+            0 -1 54 2.5392756797373295e-03</internalNodes>
           <leafValues>
-            -1.0659208893775940e-01 3.1986060738563538e-01</leafValues></_>
+            -1.1576391756534576e-01 2.3464009165763855e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 362 -3.0069730710238218e-03</internalNodes>
+            0 -1 1013 6.8497275933623314e-03</internalNodes>
           <leafValues>
-            -7.9292476177215576e-01 3.8936499506235123e-02</leafValues></_>
+            4.5596633106470108e-02 -5.8435302972793579e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 3 2.5489944964647293e-03</internalNodes>
+            0 -1 231 -4.4358119368553162e-02</internalNodes>
           <leafValues>
-            -1.4662979543209076e-01 2.0257341861724854e-01</leafValues></_>
+            -3.9718165993690491e-01 6.2707424163818359e-02</leafValues></_></weakClassifiers></_>
+    <!-- stage 8 -->
+    <_>
+      <maxWeakCount>63</maxWeakCount>
+      <stageThreshold>-1.4057025909423828e+00</stageThreshold>
+      <weakClassifiers>
         <_>
           <internalNodes>
-            0 -1 151 2.7439245022833347e-03</internalNodes>
+            0 -1 804 5.0806580111384392e-03</internalNodes>
           <leafValues>
-            -9.1609120368957520e-02 3.0721578001976013e-01</leafValues></_>
+            -7.9617008566856384e-02 5.6362086534500122e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 608 -2.5972947478294373e-03</internalNodes>
+            0 -1 965 2.0602284930646420e-03</internalNodes>
           <leafValues>
-            -4.2591169476509094e-01 6.7926779389381409e-02</leafValues></_>
+            -1.8717131018638611e-01 3.4062680602073669e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 717 1.4116591773927212e-03</internalNodes>
+            0 -1 495 6.1347078531980515e-02</internalNodes>
           <leafValues>
-            -1.2321621179580688e-01 2.4072754383087158e-01</leafValues></_>
+            -1.3253036141395569e-01 4.0938606858253479e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 603 -2.5579232722520828e-02</internalNodes>
+            0 -1 13 -6.0383215546607971e-02</internalNodes>
           <leafValues>
-            5.7537192106246948e-01 -4.9050308763980865e-02</leafValues></_>
+            4.1172346472740173e-01 -1.4447186887264252e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 407 -5.6264195591211319e-03</internalNodes>
+            0 -1 478 -3.0238348990678787e-03</internalNodes>
           <leafValues>
-            -5.2892494201660156e-01 6.0454059392213821e-02</leafValues></_>
+            3.4262558817863464e-01 -1.0982885956764221e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 413 -1.8926127813756466e-03</internalNodes>
+            0 -1 458 4.0474245324730873e-03</internalNodes>
           <leafValues>
-            2.4074989557266235e-01 -1.2150175124406815e-01</leafValues></_>
+            7.1186766028404236e-02 -5.0650447607040405e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 96 -1.0207362473011017e-02</internalNodes>
+            0 -1 633 -2.0359824411571026e-03</internalNodes>
           <leafValues>
-            -6.7782247066497803e-01 4.3572813272476196e-02</leafValues></_>
+            2.2166600823402405e-01 -1.6060648858547211e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 157 -3.1391347292810678e-03</internalNodes>
+            0 -1 887 2.7303429305902682e-05</internalNodes>
           <leafValues>
-            1.9982162117958069e-01 -1.3408482074737549e-01</leafValues></_>
+            -2.6211214065551758e-01 1.2801185250282288e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 218 -3.1065782532095909e-03</internalNodes>
+            0 -1 352 1.2323079630732536e-02</internalNodes>
           <leafValues>
-            2.2946853935718536e-01 -1.2754726409912109e-01</leafValues></_>
+            8.2502633333206177e-02 -4.5231887698173523e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 866 -5.2223210223019123e-03</internalNodes>
+            0 -1 878 2.2477287799119949e-02</internalNodes>
           <leafValues>
-            -5.0463259220123291e-01 4.9872294068336487e-02</leafValues></_>
+            -7.7229477465152740e-02 4.5144733786582947e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 428 -3.4163258969783783e-03</internalNodes>
+            0 -1 395 -1.4673802070319653e-02</internalNodes>
           <leafValues>
-            2.1628817915916443e-01 -1.1369658261537552e-01</leafValues></_>
+            3.5660189390182495e-01 -1.1584777384996414e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 901 5.1404302939772606e-03</internalNodes>
+            0 -1 141 9.9029816687107086e-02</internalNodes>
           <leafValues>
-            -9.6477277576923370e-02 2.4602085351943970e-01</leafValues></_>
+            -1.6957059502601624e-01 2.2625257074832916e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 425 5.8603808283805847e-03</internalNodes>
+            0 -1 144 -1.0632930323481560e-02</internalNodes>
           <leafValues>
-            4.0628310292959213e-02 -6.3314515352249146e-01</leafValues></_>
+            -5.6829780340194702e-01 7.1929946541786194e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 936 -1.1338826734572649e-03</internalNodes>
+            0 -1 808 2.5341216474771500e-02</internalNodes>
           <leafValues>
-            3.4083816409111023e-01 -7.9400509595870972e-02</leafValues></_>
+            -1.2931844592094421e-01 2.6161769032478333e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 936 8.0572068691253662e-04</internalNodes>
+            0 -1 816 5.8172484859824181e-03</internalNodes>
           <leafValues>
-            -9.5763482153415680e-02 3.2283502817153931e-01</leafValues></_>
+            -1.5375703573226929e-01 2.0636843144893646e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 431 -4.8957285471260548e-03</internalNodes>
+            0 -1 68 -2.0786169171333313e-01</internalNodes>
           <leafValues>
-            -5.3353887796401978e-01 4.9622885882854462e-02</leafValues></_>
+            3.9931070804595947e-01 -7.7051497995853424e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 675 7.1027994155883789e-02</internalNodes>
+            0 -1 140 2.2137831151485443e-01</internalNodes>
           <leafValues>
-            -6.2327813357114792e-02 4.5151355862617493e-01</leafValues></_>
+            -7.2486869990825653e-02 3.9756566286087036e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 911 -1.5200550667941570e-02</internalNodes>
+            0 -1 554 3.4148676786571741e-04</internalNodes>
           <leafValues>
-            2.5859493017196655e-01 -1.0548926889896393e-01</leafValues></_></weakClassifiers></_>
-    <!-- stage 6 -->
-    <_>
-      <maxWeakCount>81</maxWeakCount>
-      <stageThreshold>-1.5793150663375854e+00</stageThreshold>
-      <weakClassifiers>
+            -1.5928100049495697e-01 1.8005076050758362e-01</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 307 -6.7202709615230560e-03</internalNodes>
+          <leafValues>
+            -6.7838191986083984e-01 4.5886330306529999e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 562 -5.8624427765607834e-03</internalNodes>
+            0 -1 392 1.4110710471868515e-03</internalNodes>
           <leafValues>
-            6.2237185239791870e-01 -1.5120165422558784e-02</leafValues></_>
+            -9.7257830202579498e-02 3.2224002480506897e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 507 4.7948276624083519e-03</internalNodes>
+            0 -1 266 4.2120069265365601e-02</internalNodes>
           <leafValues>
-            -1.8684723973274231e-01 4.3783110380172729e-01</leafValues></_>
+            -8.8405482470989227e-02 3.2538983225822449e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 870 2.4864529259502888e-03</internalNodes>
+            0 -1 242 -1.3846142683178186e-03</internalNodes>
           <leafValues>
-            -1.9763210415840149e-01 3.4098726511001587e-01</leafValues></_>
+            2.0695628225803375e-01 -1.5275791287422180e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 210 -7.7013596892356873e-03</internalNodes>
+            0 -1 817 3.5425978712737560e-03</internalNodes>
           <leafValues>
-            3.4580937027931213e-01 -2.2749660909175873e-01</leafValues></_>
+            -1.2709444761276245e-01 2.1816165745258331e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 768 -1.8182904459536076e-03</internalNodes>
+            0 -1 959 3.3351695165038109e-03</internalNodes>
           <leafValues>
-            3.7125843763351440e-01 -1.4019212126731873e-01</leafValues></_>
+            4.8398405313491821e-02 -6.0871434211730957e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 791 -1.4325398951768875e-03</internalNodes>
+            0 -1 958 -3.3201207406818867e-03</internalNodes>
           <leafValues>
-            4.4040992856025696e-01 -1.0599569976329803e-01</leafValues></_>
+            -4.8987022042274475e-01 5.5623263120651245e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 161 5.4927580058574677e-03</internalNodes>
+            0 -1 915 1.0103111853823066e-03</internalNodes>
           <leafValues>
-            8.4835931658744812e-02 -5.3435057401657104e-01</leafValues></_>
+            -1.5765775740146637e-01 1.6940611600875854e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 837 -7.0448440965265036e-04</internalNodes>
+            0 -1 151 4.9717966467142105e-03</internalNodes>
           <leafValues>
-            2.8704917430877686e-01 -1.4405579864978790e-01</leafValues></_>
+            5.1272217184305191e-02 -5.4395431280136108e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 220 -5.7945270091295242e-03</internalNodes>
+            0 -1 799 1.7913591582328081e-03</internalNodes>
           <leafValues>
-            -5.1373738050460815e-01 8.3974525332450867e-02</leafValues></_>
+            -7.2745941579341888e-02 4.0087917447090149e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 376 -1.1944295838475227e-02</internalNodes>
+            0 -1 102 -1.3228422030806541e-02</internalNodes>
           <leafValues>
-            3.5980853438377380e-01 -1.0862441360950470e-01</leafValues></_>
+            -3.5441592335700989e-01 7.9325266182422638e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 385 3.4179994836449623e-03</internalNodes>
+            0 -1 276 2.0421743392944336e-03</internalNodes>
           <leafValues>
-            -1.2899027764797211e-01 3.3064863085746765e-01</leafValues></_>
+            -5.9137169271707535e-02 4.6143886446952820e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 805 -7.2756269946694374e-03</internalNodes>
+            0 -1 276 -5.9784355107694864e-04</internalNodes>
           <leafValues>
-            2.3903866112232208e-01 -1.6133096814155579e-01</leafValues></_>
+            2.5433012843132019e-01 -1.0601133853197098e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 647 -8.5910838097333908e-03</internalNodes>
+            0 -1 396 -5.1422840915620327e-03</internalNodes>
           <leafValues>
-            -8.4211397171020508e-01 4.1614245623350143e-02</leafValues></_>
+            -4.4627833366394043e-01 6.1951976269483566e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 283 -3.7941135466098785e-02</internalNodes>
+            0 -1 86 6.4243013039231300e-03</internalNodes>
           <leafValues>
-            2.4674071371555328e-01 -1.4177341759204865e-01</leafValues></_>
+            3.1528502702713013e-02 -7.2403544187545776e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 149 -3.6782763898372650e-02</internalNodes>
+            0 -1 1035 3.4636156633496284e-03</internalNodes>
           <leafValues>
-            3.1695553660392761e-01 -1.1061279475688934e-01</leafValues></_>
+            3.7317775189876556e-02 -5.4165351390838623e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 31 -1.1086702346801758e-01</internalNodes>
+            0 -1 14 3.2000489532947540e-02</internalNodes>
           <leafValues>
-            -7.7248167991638184e-01 4.9090590327978134e-02</leafValues></_>
+            3.0169567093253136e-02 -7.1302002668380737e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 23 -4.3419219553470612e-02</internalNodes>
+            0 -1 498 -5.8225672692060471e-03</internalNodes>
           <leafValues>
-            -6.3905894756317139e-01 4.7248683869838715e-02</leafValues></_>
+            -4.4310861825942993e-01 4.7724053263664246e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 229 7.1155801415443420e-03</internalNodes>
+            0 -1 24 -8.4763765335083008e-03</internalNodes>
           <leafValues>
-            5.5369954556226730e-02 -5.6675219535827637e-01</leafValues></_>
+            -6.0832363367080688e-01 3.6428902298212051e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 9 2.9427852481603622e-02</internalNodes>
+            0 -1 598 2.7582058683037758e-03</internalNodes>
           <leafValues>
-            -1.0744783282279968e-01 3.1137129664421082e-01</leafValues></_>
+            -1.0180406272411346e-01 2.4450653791427612e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 13 -5.6870315223932266e-02</internalNodes>
+            0 -1 695 -3.0314538162201643e-03</internalNodes>
           <leafValues>
-            4.8549285531044006e-01 -8.4140487015247345e-02</leafValues></_>
+            -5.6130182743072510e-01 4.1730970144271851e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 845 -2.1800836548209190e-03</internalNodes>
+            0 -1 691 3.8132141344249249e-03</internalNodes>
           <leafValues>
-            3.0136430263519287e-01 -1.0869345813989639e-01</leafValues></_>
+            4.3826375156641006e-02 -4.8639413714408875e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 345 1.2336489744484425e-03</internalNodes>
+            0 -1 799 -1.1944114230573177e-03</internalNodes>
           <leafValues>
-            -8.9073576033115387e-02 3.3233630657196045e-01</leafValues></_>
+            1.9191412627696991e-01 -1.2599647045135498e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 737 2.7930366341024637e-03</internalNodes>
+            0 -1 751 -3.2212696969509125e-02</internalNodes>
           <leafValues>
-            -1.1784177273511887e-01 2.3968270421028137e-01</leafValues></_>
+            -7.3205161094665527e-01 3.3331435173749924e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 300 -1.4338749647140503e-01</internalNodes>
+            0 -1 521 -1.0144908446818590e-03</internalNodes>
           <leafValues>
-            4.7303047776222229e-01 -5.1608867943286896e-02</leafValues></_>
+            3.0479896068572998e-01 -8.2489714026451111e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 113 7.9552028328180313e-03</internalNodes>
+            0 -1 836 -1.4355147257447243e-02</internalNodes>
           <leafValues>
-            6.0302641242742538e-02 -4.7011384367942810e-01</leafValues></_>
+            2.1706604957580566e-01 -1.0914804041385651e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 397 -4.6112807467579842e-03</internalNodes>
+            0 -1 574 -4.8122168518602848e-03</internalNodes>
           <leafValues>
-            -4.2084765434265137e-01 7.6558656990528107e-02</leafValues></_>
+            -6.7199075222015381e-01 4.0943562984466553e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 361 7.8915785998106003e-03</internalNodes>
+            0 -1 236 3.3706519752740860e-04</internalNodes>
           <leafValues>
-            -1.3884299993515015e-01 2.0495900511741638e-01</leafValues></_>
+            -1.4588885009288788e-01 1.6099508106708527e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 196 -2.9021099209785461e-02</internalNodes>
+            0 -1 43 -1.8943618983030319e-02</internalNodes>
           <leafValues>
-            3.3683353662490845e-01 -8.6431317031383514e-02</leafValues></_>
+            -5.9796541929244995e-01 3.7877634167671204e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 32 8.7932050228118896e-03</internalNodes>
+            0 -1 69 1.5444982796907425e-02</internalNodes>
           <leafValues>
-            -1.2117365747690201e-01 2.3939569294452667e-01</leafValues></_>
+            2.6846721768379211e-02 -7.2375786304473877e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 692 -4.3326904997229576e-03</internalNodes>
+            0 -1 303 1.0463559068739414e-02</internalNodes>
           <leafValues>
-            -6.3044422864913940e-01 4.8393115401268005e-02</leafValues></_>
+            3.2184243202209473e-02 -6.0756552219390869e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 729 -1.6151482705026865e-03</internalNodes>
+            0 -1 292 2.5047133676707745e-03</internalNodes>
           <leafValues>
-            3.0203807353973389e-01 -9.2361047863960266e-02</leafValues></_>
+            -1.1925315856933594e-01 1.9379882514476776e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 239 -3.6242920905351639e-03</internalNodes>
+            0 -1 797 -1.4791900292038918e-02</internalNodes>
           <leafValues>
-            -4.0946927666664124e-01 7.3978066444396973e-02</leafValues></_>
+            1.9981779158115387e-01 -1.2553811073303223e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 142 -8.0828834325075150e-03</internalNodes>
+            0 -1 146 -6.1217732727527618e-03</internalNodes>
           <leafValues>
-            -6.1597609519958496e-01 4.0132850408554077e-02</leafValues></_>
+            -4.2455345392227173e-01 5.5959124118089676e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 427 -1.8987425137311220e-03</internalNodes>
+            0 -1 563 -3.5850135609507561e-03</internalNodes>
           <leafValues>
-            2.5910443067550659e-01 -1.0553860664367676e-01</leafValues></_>
+            3.2560044527053833e-01 -7.1894593536853790e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 776 3.4845639020204544e-03</internalNodes>
+            0 -1 1048 -3.2580485567450523e-03</internalNodes>
           <leafValues>
-            4.1376896202564240e-02 -6.4275610446929932e-01</leafValues></_>
+            -5.4515779018402100e-01 4.5138467103242874e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 728 -1.3704899698495865e-02</internalNodes>
+            0 -1 367 8.5870809853076935e-03</internalNodes>
           <leafValues>
-            2.7235555648803711e-01 -1.0047114640474319e-01</leafValues></_>
+            -9.2699222266674042e-02 2.7361676096916199e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 88 -9.5059927552938461e-03</internalNodes>
+            0 -1 384 -3.5999938845634460e-03</internalNodes>
           <leafValues>
-            2.3305405676364899e-01 -1.2722322344779968e-01</leafValues></_>
+            1.7715592682361603e-01 -1.3859097659587860e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 424 -1.7753308638930321e-02</internalNodes>
+            0 -1 650 1.5299995429813862e-03</internalNodes>
           <leafValues>
-            2.7121108770370483e-01 -9.8972275853157043e-02</leafValues></_>
+            -1.0419535636901855e-01 2.1118766069412231e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 60 4.1816420853137970e-02</internalNodes>
+            0 -1 413 2.7578026056289673e-03</internalNodes>
           <leafValues>
-            -8.6314909160137177e-02 2.9308396577835083e-01</leafValues></_>
+            -7.0944413542747498e-02 2.9870492219924927e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 470 -5.2781165577471256e-03</internalNodes>
+            0 -1 283 -6.1489176005125046e-03</internalNodes>
           <leafValues>
-            -4.3240407109260559e-01 6.6678449511528015e-02</leafValues></_>
+            -5.1581281423568726e-01 4.6433247625827789e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 947 -3.5982416011393070e-03</internalNodes>
+            0 -1 979 8.3175086183473468e-04</internalNodes>
           <leafValues>
-            -4.0664613246917725e-01 5.9939380735158920e-02</leafValues></_>
+            -8.4185592830181122e-02 2.8132751584053040e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 350 -3.3817887306213379e-03</internalNodes>
+            0 -1 979 -6.7444925662130117e-04</internalNodes>
           <leafValues>
-            2.1198178827762604e-01 -1.2401402741670609e-01</leafValues></_>
+            2.6548036932945251e-01 -9.7815677523612976e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 148 -8.4468610584735870e-03</internalNodes>
+            0 -1 555 -5.6643221527338028e-02</internalNodes>
           <leafValues>
-            -5.0658410787582397e-01 5.6176334619522095e-02</leafValues></_>
+            3.8170987367630005e-01 -6.2833912670612335e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 522 -1.5873050317168236e-02</internalNodes>
+            0 -1 602 -7.5360340997576714e-03</internalNodes>
           <leafValues>
-            3.0237907171249390e-01 -8.9766949415206909e-02</leafValues></_>
+            2.2137185931205750e-01 -1.0336405038833618e-01</leafValues></_></weakClassifiers></_>
+    <!-- stage 9 -->
+    <_>
+      <maxWeakCount>54</maxWeakCount>
+      <stageThreshold>-1.3439358472824097e+00</stageThreshold>
+      <weakClassifiers>
         <_>
           <internalNodes>
-            0 -1 948 5.2925320342183113e-03</internalNodes>
+            0 -1 526 -4.8420722596347332e-03</internalNodes>
           <leafValues>
-            4.7194946557283401e-02 -5.8447927236557007e-01</leafValues></_>
+            5.7400572299957275e-01 -9.5008336007595062e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 514 -1.4822685159742832e-02</internalNodes>
+            0 -1 786 -5.9993756003677845e-03</internalNodes>
           <leafValues>
-            2.7581340074539185e-01 -1.0343603044748306e-01</leafValues></_>
+            4.5479923486709595e-01 -1.5483228862285614e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 678 -1.2328238226473331e-02</internalNodes>
+            0 -1 531 -3.1531709246337414e-03</internalNodes>
           <leafValues>
-            1.9257421791553497e-01 -1.3730424642562866e-01</leafValues></_>
+            4.2504432797431946e-01 -1.2935030460357666e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 887 5.4736144840717316e-02</internalNodes>
+            0 -1 884 1.2363551650196314e-03</internalNodes>
           <leafValues>
-            -1.0764957219362259e-01 2.4070124328136444e-01</leafValues></_>
+            -1.5872104465961456e-01 3.1463247537612915e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 484 -2.0030699670314789e-03</internalNodes>
+            0 -1 925 -6.7780278623104095e-03</internalNodes>
           <leafValues>
-            2.8992170095443726e-01 -8.6155213415622711e-02</leafValues></_>
+            4.1302111744880676e-01 -1.7017546296119690e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 347 4.9616778269410133e-03</internalNodes>
+            0 -1 259 1.3960017822682858e-03</internalNodes>
           <leafValues>
-            3.7793070077896118e-02 -6.8241751194000244e-01</leafValues></_>
+            -1.3419999182224274e-01 3.3868113160133362e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 171 2.1582433953881264e-02</internalNodes>
+            0 -1 564 -3.5894233733415604e-03</internalNodes>
           <leafValues>
-            -9.2316769063472748e-02 2.6424714922904968e-01</leafValues></_>
+            3.3102113008499146e-01 -1.1498286575078964e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 131 -9.5060802996158600e-03</internalNodes>
+            0 -1 551 5.4187951609492302e-03</internalNodes>
           <leafValues>
-            2.0518042147159576e-01 -1.1375468224287033e-01</leafValues></_>
+            -1.2790408730506897e-01 3.1275641918182373e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 238 7.4238084256649017e-02</internalNodes>
+            0 -1 934 -3.3248444087803364e-03</internalNodes>
           <leafValues>
-            -7.0650860667228699e-02 3.3061835169792175e-01</leafValues></_>
+            -5.1654219627380371e-01 7.1216024458408356e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 567 5.8014206588268280e-03</internalNodes>
+            0 -1 49 7.9970825463533401e-03</internalNodes>
           <leafValues>
-            3.9557952433824539e-02 -6.0553658008575439e-01</leafValues></_>
+            6.3098005950450897e-02 -5.8896148204803467e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 489 8.3722146227955818e-03</internalNodes>
+            0 -1 124 6.0347835533320904e-03</internalNodes>
           <leafValues>
-            -6.6242359578609467e-02 3.5559263825416565e-01</leafValues></_>
+            6.4018696546554565e-02 -4.7639665007591248e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 115 5.9322156012058258e-03</internalNodes>
+            0 -1 124 -6.9478121586143970e-03</internalNodes>
           <leafValues>
-            5.1374353468418121e-02 -4.4348692893981934e-01</leafValues></_>
+            -6.0485291481018066e-01 7.2506561875343323e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 503 -1.5613199211657047e-03</internalNodes>
+            0 -1 30 1.9063859945163131e-03</internalNodes>
           <leafValues>
-            3.3984366059303284e-01 -7.1964941918849945e-02</leafValues></_>
+            -1.8492227792739868e-01 1.9994279742240906e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 201 -1.6189547255635262e-02</internalNodes>
+            0 -1 752 2.1343495696783066e-02</internalNodes>
           <leafValues>
-            2.0777270197868347e-01 -1.2065915018320084e-01</leafValues></_>
+            -8.6192794144153595e-02 4.8719888925552368e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 589 3.7794266827404499e-03</internalNodes>
+            0 -1 261 -2.2514071315526962e-03</internalNodes>
           <leafValues>
-            4.0290340781211853e-02 -5.5574357509613037e-01</leafValues></_>
+            3.5809755325317383e-01 -7.6123438775539398e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 213 -9.3125496059656143e-03</internalNodes>
+            0 -1 480 -4.4778124429285526e-03</internalNodes>
           <leafValues>
-            2.5648719072341919e-01 -9.4139434397220612e-02</leafValues></_>
+            -4.5578238368034363e-01 7.3516018688678741e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 927 8.9797464897856116e-04</internalNodes>
+            0 -1 533 3.9280336350202560e-03</internalNodes>
           <leafValues>
-            -1.0596609860658646e-01 3.0083754658699036e-01</leafValues></_>
+            6.2599055469036102e-02 -5.2695369720458984e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 593 4.1124280542135239e-03</internalNodes>
+            0 -1 365 -4.5666974037885666e-03</internalNodes>
           <leafValues>
-            4.3452557176351547e-02 -5.6017982959747314e-01</leafValues></_>
+            -6.1827522516250610e-01 4.1984613984823227e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 447 -5.7592550292611122e-03</internalNodes>
+            0 -1 743 -6.1424830928444862e-03</internalNodes>
           <leafValues>
-            -5.5715996026992798e-01 3.6530554294586182e-02</leafValues></_>
+            3.0607789754867554e-01 -9.1138295829296112e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 956 -1.7109992913901806e-03</internalNodes>
+            0 -1 1019 3.4258943051099777e-03</internalNodes>
           <leafValues>
-            2.4350115656852722e-01 -9.9780716001987457e-02</leafValues></_>
+            5.5657953023910522e-02 -5.3350126743316650e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 975 -1.9408876076340675e-02</internalNodes>
+            0 -1 731 3.3122287131845951e-03</internalNodes>
           <leafValues>
-            -7.3736822605133057e-01 3.4421972930431366e-02</leafValues></_>
+            -1.5935245156288147e-01 1.7000633478164673e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 269 -1.8505988642573357e-02</internalNodes>
+            0 -1 135 7.4128687381744385e-02</internalNodes>
           <leafValues>
-            2.3959811031818390e-01 -1.0179302841424942e-01</leafValues></_>
+            3.3975400030612946e-02 -6.4646822214126587e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 974 -3.4968159161508083e-03</internalNodes>
+            0 -1 496 -6.0862921178340912e-02</internalNodes>
           <leafValues>
-            -4.5450085401535034e-01 5.2533198148012161e-02</leafValues></_>
+            3.1012952327728271e-01 -9.1380268335342407e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 722 3.2340791076421738e-03</internalNodes>
+            0 -1 575 -4.3243117630481720e-02</internalNodes>
           <leafValues>
-            -9.7867593169212341e-02 2.5210717320442200e-01</leafValues></_>
+            -4.5051410794258118e-01 6.6722445189952850e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 853 -2.1103646140545607e-03</internalNodes>
+            0 -1 322 -5.4576778784394264e-03</internalNodes>
           <leafValues>
-            2.7718135714530945e-01 -8.3934187889099121e-02</leafValues></_>
+            -4.8368638753890991e-01 5.5113438516855240e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 310 -6.0913376510143280e-03</internalNodes>
+            0 -1 196 -2.1073617972433567e-03</internalNodes>
           <leafValues>
-            -5.0269359350204468e-01 4.7654323279857635e-02</leafValues></_>
+            2.3326623439788818e-01 -1.2007984519004822e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 316 -1.4657910168170929e-01</internalNodes>
+            0 -1 252 -1.1282963678240776e-02</internalNodes>
           <leafValues>
-            -5.8180803060531616e-01 3.7255339324474335e-02</leafValues></_>
+            2.9159554839134216e-01 -1.0025029629468918e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 721 -5.7285130023956299e-02</internalNodes>
+            0 -1 339 2.9302681796252728e-03</internalNodes>
           <leafValues>
-            -8.1681364774703979e-01 2.3416126146912575e-02</leafValues></_>
+            -8.5840485990047455e-02 3.3159431815147400e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 560 -1.0855928063392639e-02</internalNodes>
+            0 -1 53 -2.8825225308537483e-03</internalNodes>
           <leafValues>
-            1.6488714516162872e-01 -1.3668881356716156e-01</leafValues></_>
+            -5.3361582756042480e-01 5.7994876056909561e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 511 1.4742083847522736e-02</internalNodes>
+            0 -1 76 6.2230005860328674e-03</internalNodes>
           <leafValues>
-            3.0842842534184456e-02 -7.8335261344909668e-01</leafValues></_>
+            4.4393569231033325e-02 -5.3072142601013184e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 701 -1.8798124045133591e-02</internalNodes>
+            0 -1 971 1.1437942739576101e-03</internalNodes>
           <leafValues>
-            3.1507465243339539e-01 -7.6406344771385193e-02</leafValues></_>
+            -9.5763660967350006e-02 2.8212538361549377e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 458 1.8614485859870911e-02</internalNodes>
+            0 -1 1052 1.2469270732253790e-03</internalNodes>
           <leafValues>
-            -8.0178938806056976e-02 3.0463775992393494e-01</leafValues></_>
+            6.5446242690086365e-02 -4.1902217268943787e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 803 -4.1011158376932144e-02</internalNodes>
+            0 -1 612 -1.1369751766324043e-02</internalNodes>
           <leafValues>
-            -6.7428815364837646e-01 3.5076040774583817e-02</leafValues></_>
+            -7.0747911930084229e-01 3.4916084259748459e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 260 -1.5514190308749676e-03</internalNodes>
+            0 -1 35 1.0013033449649811e-01</internalNodes>
           <leafValues>
-            1.9351305067539215e-01 -1.0952673852443695e-01</leafValues></_>
+            -6.7160040140151978e-02 4.2184004187583923e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 83 7.6966043561697006e-03</internalNodes>
+            0 -1 653 -2.6742245536297560e-03</internalNodes>
           <leafValues>
-            3.2414216548204422e-02 -6.0751897096633911e-01</leafValues></_>
+            1.7217047512531281e-01 -1.6229687631130219e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 154 -1.7850721254944801e-02</internalNodes>
+            0 -1 713 -3.4254738129675388e-03</internalNodes>
           <leafValues>
-            2.0461367070674896e-01 -1.0080502927303314e-01</leafValues></_>
+            2.9603767395019531e-01 -8.9177258312702179e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 298 2.3059733211994171e-03</internalNodes>
+            0 -1 669 1.5813322970643640e-03</internalNodes>
           <leafValues>
-            -1.3565167784690857e-01 1.7179486155509949e-01</leafValues></_></weakClassifiers></_>
-    <!-- stage 7 -->
-    <_>
-      <maxWeakCount>88</maxWeakCount>
-      <stageThreshold>-1.6158927679061890e+00</stageThreshold>
-      <weakClassifiers>
+            4.8733744770288467e-02 -5.6422549486160278e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 877 3.6321599036455154e-03</internalNodes>
+            0 -1 917 2.7555555789149366e-05</internalNodes>
           <leafValues>
-            8.3464950323104858e-02 7.0313382148742676e-01</leafValues></_>
+            -1.7079097032546997e-01 1.4066468179225922e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 450 -2.8561335057020187e-03</internalNodes>
+            0 -1 466 -8.2116597332060337e-04</internalNodes>
           <leafValues>
-            5.3444284200668335e-01 -1.4426039159297943e-01</leafValues></_>
+            1.8260034918785095e-01 -1.3242910802364349e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 767 -1.6910845879465342e-03</internalNodes>
+            0 -1 353 -1.0168720036745071e-02</internalNodes>
           <leafValues>
-            4.5417416095733643e-01 -1.4539502561092377e-01</leafValues></_>
+            -4.1390055418014526e-01 6.5349683165550232e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 330 2.4872912093997002e-02</internalNodes>
+            0 -1 96 2.5848036631941795e-02</internalNodes>
           <leafValues>
-            -1.5180622041225433e-01 4.7290563583374023e-01</leafValues></_>
+            4.6910341829061508e-02 -4.7531116008758545e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 326 -1.3844612985849380e-02</internalNodes>
+            0 -1 75 5.9797330759465694e-03</internalNodes>
           <leafValues>
-            4.3979367613792419e-01 -1.9149754941463470e-01</leafValues></_>
+            4.5450355857610703e-02 -4.5701387524604797e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 223 -2.0526167005300522e-02</internalNodes>
+            0 -1 81 -2.4257015902549028e-03</internalNodes>
           <leafValues>
-            3.5583654046058655e-01 -1.7526121437549591e-01</leafValues></_>
+            1.8431460857391357e-01 -1.1879430711269379e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 513 -1.0601939633488655e-02</internalNodes>
+            0 -1 346 -4.1334740817546844e-02</internalNodes>
           <leafValues>
-            2.1787860989570618e-01 -1.8377628922462463e-01</leafValues></_>
+            3.0460721254348755e-01 -9.4910860061645508e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 43 1.5976445749402046e-02</internalNodes>
+            0 -1 537 7.5982198119163513e-02</internalNodes>
           <leafValues>
-            8.6497880518436432e-02 -4.3799200654029846e-01</leafValues></_>
+            -6.5890170633792877e-02 3.3325287699699402e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 698 -4.9493601545691490e-03</internalNodes>
+            0 -1 318 -2.7852014682139270e-05</internalNodes>
           <leafValues>
-            2.3401068150997162e-01 -1.5603557229042053e-01</leafValues></_>
+            1.4771287143230438e-01 -1.4524473249912262e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 182 2.8549194335937500e-02</internalNodes>
+            0 -1 669 -1.4885163400322199e-03</internalNodes>
           <leafValues>
-            -1.4324828982353210e-01 2.4674744904041290e-01</leafValues></_>
+            -4.6987643837928772e-01 4.7233786433935165e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 125 5.9233225882053375e-02</internalNodes>
+            0 -1 897 -3.3519542776048183e-03</internalNodes>
           <leafValues>
-            -1.0831536352634430e-01 3.3649173378944397e-01</leafValues></_>
+            2.4128976464271545e-01 -9.3788638710975647e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 436 9.5888428390026093e-02</internalNodes>
+            0 -1 935 1.3348343782126904e-03</internalNodes>
           <leafValues>
-            -1.0589215904474258e-01 3.7052422761917114e-01</leafValues></_>
+            -9.9509775638580322e-02 2.9368522763252258e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 453 -7.5694853439927101e-03</internalNodes>
+            0 -1 704 3.2456549815833569e-03</internalNodes>
           <leafValues>
-            2.3113159835338593e-01 -1.4907826483249664e-01</leafValues></_>
+            -9.8895303905010223e-02 2.3363485932350159e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 496 4.7857249155640602e-03</internalNodes>
+            0 -1 611 4.2385179549455643e-03</internalNodes>
           <leafValues>
-            5.1639214158058167e-02 -6.2650465965270996e-01</leafValues></_>
+            5.9986904263496399e-02 -4.5745995640754700e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 145 5.4310320410877466e-04</internalNodes>
+            0 -1 170 8.4751443937420845e-03</internalNodes>
           <leafValues>
-            -1.8886238336563110e-01 1.5287129580974579e-01</leafValues></_>
+            3.0937874689698219e-02 -6.7139619588851929e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 941 2.6117763482034206e-03</internalNodes>
+            0 -1 995 3.0964510515332222e-03</internalNodes>
           <leafValues>
-            6.6002741456031799e-02 -4.4275501370429993e-01</leafValues></_>
+            3.0879957601428032e-02 -6.2686437368392944e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 940 -8.0328416079282761e-03</internalNodes>
+            0 -1 212 2.3455230984836817e-03</internalNodes>
           <leafValues>
-            -5.1598960161209106e-01 5.6888539344072342e-02</leafValues></_>
+            -1.3303077220916748e-01 1.6908498108386993e-01</leafValues></_></weakClassifiers></_>
+    <!-- stage 10 -->
+    <_>
+      <maxWeakCount>72</maxWeakCount>
+      <stageThreshold>-1.4052674770355225e+00</stageThreshold>
+      <weakClassifiers>
         <_>
           <internalNodes>
-            0 -1 842 1.2324389535933733e-03</internalNodes>
+            0 -1 534 -8.4834604058414698e-04</internalNodes>
           <leafValues>
-            -1.2387900799512863e-01 2.6769712567329407e-01</leafValues></_>
+            4.6746683120727539e-01 -1.2498743087053299e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 830 -9.7260549664497375e-03</internalNodes>
+            0 -1 838 1.1534148361533880e-03</internalNodes>
           <leafValues>
-            3.5000637173652649e-01 -1.0784699767827988e-01</leafValues></_>
+            -2.1341361105442047e-01 3.0533915758132935e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 334 8.6696096695959568e-04</internalNodes>
+            0 -1 728 1.3660041615366936e-02</internalNodes>
           <leafValues>
-            -1.1435680836439133e-01 2.5563576817512512e-01</leafValues></_>
+            -1.5390963852405548e-01 3.2113197445869446e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 258 -3.4542869776487350e-02</internalNodes>
+            0 -1 528 -1.3363182079046965e-03</internalNodes>
           <leafValues>
-            -5.8313912153244019e-01 5.1875289529561996e-02</leafValues></_>
+            2.4346974492073059e-01 -1.8074017763137817e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 342 7.5529976747930050e-03</internalNodes>
+            0 -1 1002 5.5064354091882706e-04</internalNodes>
           <leafValues>
-            3.6179721355438232e-02 -6.9380182027816772e-01</leafValues></_>
+            -1.9600959122180939e-01 2.1903340518474579e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 550 4.0939049795269966e-03</internalNodes>
+            0 -1 340 2.8026416897773743e-02</internalNodes>
           <leafValues>
-            4.1062511503696442e-02 -5.9848028421401978e-01</leafValues></_>
+            -9.9956467747688293e-02 5.1314896345138550e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 354 2.8113774023950100e-03</internalNodes>
+            0 -1 930 -9.8200759384781122e-04</internalNodes>
           <leafValues>
-            5.5211704224348068e-02 -4.7554171085357666e-01</leafValues></_>
+            2.0671010017395020e-01 -1.9585600495338440e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 353 -3.5045309923589230e-03</internalNodes>
+            0 -1 249 -1.9661948084831238e-02</internalNodes>
           <leafValues>
-            -3.9402753114700317e-01 6.9415092468261719e-02</leafValues></_>
+            -5.1859843730926514e-01 7.9988524317741394e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 373 1.7898422665894032e-03</internalNodes>
+            0 -1 514 5.7550622150301933e-03</internalNodes>
           <leafValues>
-            -7.6636046171188354e-02 4.0437600016593933e-01</leafValues></_>
+            -1.0230549424886703e-01 2.9102912545204163e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 486 4.0369415655732155e-03</internalNodes>
+            0 -1 854 4.8226406797766685e-03</internalNodes>
           <leafValues>
-            -9.7471550107002258e-02 2.7784994244575500e-01</leafValues></_>
+            -1.2503834068775177e-01 2.2606587409973145e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 430 -8.5533969104290009e-03</internalNodes>
+            0 -1 1025 -3.5137422382831573e-03</internalNodes>
           <leafValues>
-            3.3252051472663879e-01 -1.0098887234926224e-01</leafValues></_>
+            -6.8291509151458740e-01 4.6296034008264542e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 69 2.6041156053543091e-01</internalNodes>
+            0 -1 468 2.7717142074834555e-05</internalNodes>
           <leafValues>
-            -4.3942935764789581e-02 5.0610113143920898e-01</leafValues></_>
+            -2.1390475332736969e-01 1.3291628658771515e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 892 1.4894269406795502e-03</internalNodes>
+            0 -1 875 -2.2634968161582947e-02</internalNodes>
           <leafValues>
-            -7.6404698193073273e-02 3.0335766077041626e-01</leafValues></_>
+            4.0156257152557373e-01 -9.0922117233276367e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 101 -4.8547232151031494e-01</internalNodes>
+            0 -1 890 -2.6544253341853619e-04</internalNodes>
           <leafValues>
-            6.1892670392990112e-01 -3.9150018244981766e-02</leafValues></_>
+            2.1944612264633179e-01 -1.5686984360218048e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 895 -7.6227495446801186e-04</internalNodes>
+            0 -1 45 1.7469950020313263e-02</internalNodes>
           <leafValues>
-            1.9151827692985535e-01 -1.2709514796733856e-01</leafValues></_>
+            5.9605021029710770e-02 -5.4529672861099243e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 553 -4.8853931948542595e-03</internalNodes>
+            0 -1 812 3.6130528897047043e-03</internalNodes>
           <leafValues>
-            -5.6353646516799927e-01 4.4611949473619461e-02</leafValues></_>
+            5.2721742540597916e-02 -4.4890201091766357e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 649 1.8246687250211835e-03</internalNodes>
+            0 -1 813 -3.8260491564869881e-03</internalNodes>
           <leafValues>
-            6.3832193613052368e-02 -3.6079093813896179e-01</leafValues></_>
+            -5.1076781749725342e-01 4.7858215868473053e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 2 -3.7001366727054119e-03</internalNodes>
+            0 -1 348 -4.6305969590321183e-04</internalNodes>
           <leafValues>
-            1.9149990379810333e-01 -1.3052800297737122e-01</leafValues></_>
+            2.0340332388877869e-01 -1.3007256388664246e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 324 -5.1008379086852074e-03</internalNodes>
+            0 -1 685 -7.3791583999991417e-03</internalNodes>
           <leafValues>
-            4.0633511543273926e-01 -6.6167853772640228e-02</leafValues></_>
+            -5.4855078458786011e-01 5.1355980336666107e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 15 -1.7046853899955750e-02</internalNodes>
+            0 -1 397 -4.1331160813570023e-02</internalNodes>
           <leafValues>
-            -3.5266619920730591e-01 7.1908973157405853e-02</leafValues></_>
+            -3.7914556264877319e-01 6.2432620674371719e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 415 7.4824336916208267e-03</internalNodes>
+            0 -1 720 -1.4983891742303967e-03</internalNodes>
           <leafValues>
-            5.7628002017736435e-02 -4.6899631619453430e-01</leafValues></_>
+            -5.2967226505279541e-01 4.2461462318897247e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 955 -1.0255416855216026e-02</internalNodes>
+            0 -1 785 -2.5054097641259432e-03</internalNodes>
           <leafValues>
-            -5.3142738342285156e-01 4.1362568736076355e-02</leafValues></_>
+            2.0288434624671936e-01 -1.2341590225696564e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 500 2.2401358000934124e-03</internalNodes>
+            0 -1 259 -7.1871257387101650e-04</internalNodes>
           <leafValues>
-            -7.4236951768398285e-02 3.2401573657989502e-01</leafValues></_>
+            2.4784520268440247e-01 -9.8167583346366882e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 893 -1.1338146403431892e-02</internalNodes>
+            0 -1 260 -6.8983237724751234e-04</internalNodes>
           <leafValues>
-            -5.8281844854354858e-01 4.3767549097537994e-02</leafValues></_>
+            2.7780577540397644e-01 -9.7512029111385345e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 532 8.4229296771809459e-04</internalNodes>
+            0 -1 274 4.8434769269078970e-04</internalNodes>
           <leafValues>
-            -1.2624698877334595e-01 1.8474358320236206e-01</leafValues></_>
+            -1.1704409867525101e-01 2.4324342608451843e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 117 2.7594935148954391e-02</internalNodes>
+            0 -1 508 -3.6378027871251106e-03</internalNodes>
           <leafValues>
-            4.2021647095680237e-02 -5.0711041688919067e-01</leafValues></_>
+            -5.7295501232147217e-01 4.9037151038646698e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 828 3.0329828150570393e-03</internalNodes>
+            0 -1 709 -2.6648804545402527e-02</internalNodes>
           <leafValues>
-            -7.0778228342533112e-02 3.3471760153770447e-01</leafValues></_>
+            -6.0253041982650757e-01 3.6413222551345825e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 984 -8.9767086319625378e-04</internalNodes>
+            0 -1 825 -4.3416651897132397e-03</internalNodes>
           <leafValues>
-            -2.8313115239143372e-01 8.4212802350521088e-02</leafValues></_>
+            4.7109794616699219e-01 -5.9058945626020432e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 912 -4.3688914738595486e-03</internalNodes>
+            0 -1 60 -2.7588163502514362e-03</internalNodes>
           <leafValues>
-            -4.8104682564735413e-01 4.6536806970834732e-02</leafValues></_>
+            -4.9160134792327881e-01 5.4663125425577164e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 817 -6.5738772973418236e-03</internalNodes>
+            0 -1 987 4.7046472318470478e-03</internalNodes>
           <leafValues>
-            1.8955506384372711e-01 -1.1803213506937027e-01</leafValues></_>
+            3.7025094032287598e-02 -5.6842529773712158e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 768 1.6207897569984198e-03</internalNodes>
+            0 -1 77 4.9029560759663582e-03</internalNodes>
           <leafValues>
-            -6.5827853977680206e-02 3.2122904062271118e-01</leafValues></_>
+            4.8207473009824753e-02 -4.2965477705001831e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 641 4.8786089755594730e-03</internalNodes>
+            0 -1 837 -7.0135248824954033e-04</internalNodes>
           <leafValues>
-            3.4384466707706451e-02 -7.0796263217926025e-01</leafValues></_>
+            2.2556030750274658e-01 -9.9117368459701538e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 118 -7.3928516358137131e-03</internalNodes>
+            0 -1 332 2.7165210340172052e-03</internalNodes>
           <leafValues>
-            -4.5154401659965515e-01 4.3622057884931564e-02</leafValues></_>
+            4.3833449482917786e-02 -5.5271440744400024e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 287 2.2087101824581623e-03</internalNodes>
+            0 -1 837 8.9941755868494511e-04</internalNodes>
           <leafValues>
-            -4.4949851930141449e-02 4.9991622567176819e-01</leafValues></_>
+            -8.9474648237228394e-02 2.6415902376174927e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 187 2.9001948423683643e-03</internalNodes>
+            0 -1 723 -1.7575379461050034e-03</internalNodes>
           <leafValues>
-            5.1781963557004929e-02 -4.2971140146255493e-01</leafValues></_>
+            -5.7822185754776001e-01 4.4655490666627884e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 287 -9.9636090453714132e-04</internalNodes>
+            0 -1 323 2.2079560905694962e-02</internalNodes>
           <leafValues>
-            3.0347472429275513e-01 -7.4883252382278442e-02</leafValues></_>
+            -9.1862626373767853e-02 2.6927500963211060e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 121 6.3986405730247498e-03</internalNodes>
+            0 -1 247 -2.4989219382405281e-03</internalNodes>
           <leafValues>
-            3.8914524018764496e-02 -5.6881076097488403e-01</leafValues></_>
+            1.9282613694667816e-01 -1.4004705846309662e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 433 -5.2966945804655552e-03</internalNodes>
+            0 -1 388 4.4558709487318993e-03</internalNodes>
           <leafValues>
-            -5.5442500114440918e-01 3.3734291791915894e-02</leafValues></_>
+            5.2965965121984482e-02 -4.6530798077583313e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 540 9.2505104839801788e-03</internalNodes>
+            0 -1 345 8.9809950441122055e-03</internalNodes>
           <leafValues>
-            -9.5525965094566345e-02 2.2353705763816833e-01</leafValues></_>
+            -6.9099865853786469e-02 3.5005539655685425e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 942 3.2701031304895878e-03</internalNodes>
+            0 -1 589 -4.6078087761998177e-03</internalNodes>
           <leafValues>
-            -8.7515957653522491e-02 2.7356430888175964e-01</leafValues></_>
+            1.5373907983303070e-01 -1.5948937833309174e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 938 -9.0824589133262634e-03</internalNodes>
+            0 -1 10 -8.9063167572021484e-02</internalNodes>
           <leafValues>
-            2.2333034873008728e-01 -9.6923373639583588e-02</leafValues></_>
+            4.8500600457191467e-01 -5.1386959850788116e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 981 -3.0515873804688454e-03</internalNodes>
+            0 -1 540 4.8636873252689838e-03</internalNodes>
           <leafValues>
-            -4.0757030248641968e-01 5.0947520881891251e-02</leafValues></_>
+            5.1732856780290604e-02 -4.9787709116935730e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 518 6.3385991379618645e-03</internalNodes>
+            0 -1 992 -5.4465518333017826e-03</internalNodes>
           <leafValues>
-            -6.0888923704624176e-02 3.5273307561874390e-01</leafValues></_>
+            1.5584819018840790e-01 -1.4326727390289307e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 568 -3.4346987958997488e-03</internalNodes>
+            0 -1 788 6.4384475350379944e-02</internalNodes>
           <leafValues>
-            2.9356080293655396e-01 -8.1172131001949310e-02</leafValues></_>
+            3.1540591269731522e-02 -7.1331930160522461e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 141 -3.9428919553756714e-03</internalNodes>
+            0 -1 25 -9.3528348952531815e-03</internalNodes>
           <leafValues>
-            -4.9512249231338501e-01 4.4033303856849670e-02</leafValues></_>
+            -5.8800560235977173e-01 3.2534934580326080e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 363 -9.1780513525009155e-02</internalNodes>
+            0 -1 374 6.5686285961419344e-04</internalNodes>
           <leafValues>
-            -3.9046007394790649e-01 5.0150144845247269e-02</leafValues></_>
+            -1.6972899436950684e-01 1.4208021759986877e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 259 -6.6375046968460083e-02</internalNodes>
+            0 -1 744 -6.5707243047654629e-03</internalNodes>
           <leafValues>
-            -6.0851734876632690e-01 3.0974121764302254e-02</leafValues></_>
+            3.1901842355728149e-01 -7.0233277976512909e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 621 -6.9266660138964653e-03</internalNodes>
+            0 -1 370 7.0676081813871861e-03</internalNodes>
           <leafValues>
-            -7.3090195655822754e-01 2.3663638159632683e-02</leafValues></_>
+            3.0735086649656296e-02 -7.6451587677001953e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 105 -3.5928614437580109e-02</internalNodes>
+            0 -1 875 -1.1614331044256687e-02</internalNodes>
           <leafValues>
-            1.8060323596000671e-01 -1.1467467248439789e-01</leafValues></_>
+            2.0416912436485291e-01 -1.0650242120027542e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 848 -4.6623144298791885e-03</internalNodes>
+            0 -1 227 -3.0933439731597900e-02</internalNodes>
           <leafValues>
-            2.3666681349277496e-01 -1.0607369244098663e-01</leafValues></_>
+            -3.5186296701431274e-01 6.3158944249153137e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 597 6.3546001911163330e-02</internalNodes>
+            0 -1 31 8.9404191821813583e-03</internalNodes>
           <leafValues>
-            3.3510908484458923e-02 -6.6823011636734009e-01</leafValues></_>
+            4.1301336139440536e-02 -5.2171415090560913e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 303 1.0070858988910913e-03</internalNodes>
+            0 -1 542 -3.0004943255335093e-04</internalNodes>
           <leafValues>
-            -1.1336669325828552e-01 1.9138091802597046e-01</leafValues></_>
+            1.8332102894783020e-01 -1.1965552717447281e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 297 2.0964080467820168e-03</internalNodes>
+            0 -1 753 -4.2704585939645767e-03</internalNodes>
           <leafValues>
-            -1.3783766329288483e-01 1.6943521797657013e-01</leafValues></_>
+            -4.1220253705978394e-01 5.2136015146970749e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 278 -3.7955917418003082e-02</internalNodes>
+            0 -1 979 9.1349193826317787e-04</internalNodes>
           <leafValues>
-            4.2277663946151733e-01 -5.3925208747386932e-02</leafValues></_>
+            -8.2035504281520844e-02 2.7817621827125549e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 915 1.5981765463948250e-03</internalNodes>
+            0 -1 97 2.8089310973882675e-02</internalNodes>
           <leafValues>
-            7.2201833128929138e-02 -2.9906082153320312e-01</leafValues></_>
+            6.0909613966941833e-02 -3.7705209851264954e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 266 -1.0036448948085308e-03</internalNodes>
+            0 -1 979 -1.1489203898236156e-03</internalNodes>
           <leafValues>
-            3.0661484599113464e-01 -7.1594037115573883e-02</leafValues></_>
+            2.9547268152236938e-01 -7.8550107777118683e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 167 -8.7398784235119820e-03</internalNodes>
+            0 -1 766 -8.5876882076263428e-04</internalNodes>
           <leafValues>
-            -4.0562248229980469e-01 5.0554409623146057e-02</leafValues></_>
+            1.6158875823020935e-01 -1.3613829016685486e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 132 3.8445743266493082e-03</internalNodes>
+            0 -1 862 3.3645064104348421e-03</internalNodes>
           <leafValues>
-            3.0860245227813721e-02 -5.6328177452087402e-01</leafValues></_>
+            3.6055568605661392e-02 -5.5788111686706543e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 559 2.9180462006479502e-03</internalNodes>
+            0 -1 1034 -1.2699423357844353e-02</internalNodes>
           <leafValues>
-            -9.4123579561710358e-02 2.1829530596733093e-01</leafValues></_>
+            -4.2199519276618958e-01 4.3876208364963531e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 705 -4.4532963074743748e-03</internalNodes>
+            0 -1 158 -1.3306856155395508e-01</internalNodes>
           <leafValues>
-            2.2356307506561279e-01 -1.0032130777835846e-01</leafValues></_>
+            -7.5723612308502197e-01 2.4755204096436501e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 979 2.8718812391161919e-03</internalNodes>
+            0 -1 822 4.9831219017505646e-02</internalNodes>
           <leafValues>
-            5.8825947344303131e-02 -3.5275349020957947e-01</leafValues></_>
+            2.5250671431422234e-02 -6.3122928142547607e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 392 -9.6740125445649028e-04</internalNodes>
+            0 -1 569 5.8193420991301537e-03</internalNodes>
           <leafValues>
-            2.2895433008670807e-01 -8.8445298373699188e-02</leafValues></_>
+            2.2189516574144363e-02 -7.2821933031082153e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 384 6.3862642273306847e-03</internalNodes>
+            0 -1 422 -6.3158385455608368e-03</internalNodes>
           <leafValues>
-            -7.9845495522022247e-02 2.6533949375152588e-01</leafValues></_>
+            1.9480472803115845e-01 -1.0275462269783020e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 739 -1.8584533827379346e-03</internalNodes>
+            0 -1 58 -2.6879269629716873e-02</internalNodes>
           <leafValues>
-            -3.5019376873970032e-01 5.8831077069044113e-02</leafValues></_>
+            -4.3909311294555664e-01 4.5222271233797073e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 47 -4.1777163743972778e-02</internalNodes>
+            0 -1 900 -1.6478844918310642e-03</internalNodes>
           <leafValues>
-            -7.5915527343750000e-01 2.5032732635736465e-02</leafValues></_>
+            2.7425831556320190e-01 -7.7650256454944611e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 798 1.7466493882238865e-03</internalNodes>
+            0 -1 947 4.4362144544720650e-03</internalNodes>
           <leafValues>
-            -7.8535526990890503e-02 2.5856694579124451e-01</leafValues></_>
+            3.2876692712306976e-02 -6.0907542705535889e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 873 -1.7557941377162933e-02</internalNodes>
+            0 -1 760 -1.5154483262449503e-03</internalNodes>
           <leafValues>
-            1.5769363939762115e-01 -1.2735258042812347e-01</leafValues></_>
+            2.2985421121120453e-01 -8.5810013115406036e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 622 -2.0210664719343185e-02</internalNodes>
+            0 -1 157 7.0627350360155106e-03</internalNodes>
           <leafValues>
-            2.4479819834232330e-01 -8.0905362963676453e-02</leafValues></_>
+            3.4827440977096558e-02 -5.9273594617843628e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 623 -1.2817385140806437e-03</internalNodes>
+            0 -1 393 4.5482232235372066e-03</internalNodes>
           <leafValues>
-            2.0145194232463837e-01 -1.1555081605911255e-01</leafValues></_>
+            -5.2113339304924011e-02 4.0603092312812805e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 173 -4.6622417867183685e-03</internalNodes>
+            0 -1 183 -3.9095789194107056e-02</internalNodes>
           <leafValues>
-            -5.7475388050079346e-01 3.5327285528182983e-02</leafValues></_>
+            2.5562492012977600e-01 -8.1410482525825500e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 624 7.2181676514446735e-03</internalNodes>
+            0 -1 718 -1.9122204976156354e-03</internalNodes>
           <leafValues>
-            -6.5562173724174500e-02 2.9846385121345520e-01</leafValues></_></weakClassifiers></_>
-    <!-- stage 8 -->
+            -6.5523076057434082e-01 3.1964879482984543e-02</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 622 5.1604928448796272e-03</internalNodes>
+          <leafValues>
+            2.8228869661688805e-02 -6.0336226224899292e-01</leafValues></_></weakClassifiers></_>
+    <!-- stage 11 -->
     <_>
-      <maxWeakCount>91</maxWeakCount>
-      <stageThreshold>-1.4331817626953125e+00</stageThreshold>
+      <maxWeakCount>63</maxWeakCount>
+      <stageThreshold>-1.2550007104873657e+00</stageThreshold>
       <weakClassifiers>
         <_>
           <internalNodes>
-            0 -1 508 -1.0981839150190353e-02</internalNodes>
+            0 -1 532 -1.3708438724279404e-02</internalNodes>
           <leafValues>
-            6.4476418495178223e-01 5.4893907159566879e-02</leafValues></_>
+            4.5314663648605347e-01 -1.2558805942535400e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 256 4.4120610691606998e-03</internalNodes>
+            0 -1 32 1.2687301263213158e-02</internalNodes>
           <leafValues>
-            -1.1835748702287674e-01 5.0045996904373169e-01</leafValues></_>
+            -1.5584127604961395e-01 3.8753288984298706e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 735 2.8575016185641289e-03</internalNodes>
+            0 -1 254 3.3966779708862305e-02</internalNodes>
           <leafValues>
-            -1.3248406350612640e-01 4.2942702770233154e-01</leafValues></_>
+            -1.1772038787603378e-01 4.0628942847251892e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 326 2.0933073014020920e-02</internalNodes>
+            0 -1 756 8.0258902162313461e-03</internalNodes>
           <leafValues>
-            -1.2826231122016907e-01 5.0430470705032349e-01</leafValues></_>
+            -1.4661933481693268e-01 4.0369525551795959e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 742 -1.4590121805667877e-02</internalNodes>
+            0 -1 2 -4.2836386710405350e-03</internalNodes>
           <leafValues>
-            3.1983098387718201e-01 -1.6088847815990448e-01</leafValues></_>
+            2.2167153656482697e-01 -1.9662868976593018e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 581 6.0559157282114029e-02</internalNodes>
+            0 -1 164 -2.7807329315692186e-03</internalNodes>
           <leafValues>
-            -7.2834797203540802e-02 4.6935465931892395e-01</leafValues></_>
+            -4.6929144859313965e-01 6.9577261805534363e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 537 3.3241603523492813e-02</internalNodes>
+            0 -1 172 1.9090694840997458e-03</internalNodes>
           <leafValues>
-            -1.2657077610492706e-01 3.8025194406509399e-01</leafValues></_>
+            5.9488739818334579e-02 -6.3101488351821899e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 377 -1.5009621158242226e-02</internalNodes>
+            0 -1 426 3.1442400068044662e-03</internalNodes>
           <leafValues>
-            3.6463224887847900e-01 -9.8299026489257812e-02</leafValues></_>
+            -1.1149841547012329e-01 3.0095639824867249e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 888 1.5744348056614399e-03</internalNodes>
+            0 -1 324 -2.8418585658073425e-02</internalNodes>
           <leafValues>
-            -1.1195008456707001e-01 3.1572943925857544e-01</leafValues></_>
+            3.6157062649726868e-01 -9.6387691795825958e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 574 -2.3936885409057140e-03</internalNodes>
+            0 -1 449 -4.4032465666532516e-03</internalNodes>
           <leafValues>
-            -4.7027668356895447e-01 7.1979902684688568e-02</leafValues></_>
+            3.2977014780044556e-01 -9.8187342286109924e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 263 4.7012902796268463e-03</internalNodes>
+            0 -1 400 -2.6041134260594845e-03</internalNodes>
           <leafValues>
-            9.1855168342590332e-02 -3.6548766493797302e-01</leafValues></_>
+            2.8221642971038818e-01 -1.0142992436885834e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 899 3.9329114370048046e-03</internalNodes>
+            0 -1 357 -5.8917067945003510e-03</internalNodes>
           <leafValues>
-            4.4214393943548203e-02 -5.6691557168960571e-01</leafValues></_>
+            -5.8254349231719971e-01 6.0040380805730820e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 898 -2.8009498491883278e-03</internalNodes>
+            0 -1 998 1.3956660404801369e-03</internalNodes>
           <leafValues>
-            -4.8461133241653442e-01 5.4654970765113831e-02</leafValues></_>
+            -1.6574928164482117e-01 1.7746162414550781e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 134 -4.2012645862996578e-03</internalNodes>
+            0 -1 1022 -1.7630932852625847e-03</internalNodes>
           <leafValues>
-            1.9422210752964020e-01 -1.4497868716716766e-01</leafValues></_>
+            -5.7597070932388306e-01 6.2388133257627487e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 61 -8.7564159184694290e-03</internalNodes>
+            0 -1 697 -1.3517161132767797e-03</internalNodes>
           <leafValues>
-            -4.9580562114715576e-01 5.6972313672304153e-02</leafValues></_>
+            -5.1934504508972168e-01 4.7232870012521744e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 843 3.0297664925456047e-03</internalNodes>
+            0 -1 507 -3.8743610493838787e-03</internalNodes>
           <leafValues>
-            -1.4587514102458954e-01 2.3592919111251831e-01</leafValues></_>
+            2.9165247082710266e-01 -9.9355563521385193e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 882 -1.1956840753555298e-02</internalNodes>
+            0 -1 765 1.0973589494824409e-02</internalNodes>
           <leafValues>
-            3.6318615078926086e-01 -8.9037798345088959e-02</leafValues></_>
+            -7.7571205794811249e-02 3.4312543272972107e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 267 -9.4736125320196152e-03</internalNodes>
+            0 -1 128 -3.5274624824523926e-03</internalNodes>
           <leafValues>
-            -6.6952317953109741e-01 5.2261870354413986e-02</leafValues></_>
+            -6.7513287067413330e-01 3.6897819489240646e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 147 -7.3966579511761665e-03</internalNodes>
+            0 -1 605 -2.4239125195890665e-03</internalNodes>
           <leafValues>
-            -5.5038225650787354e-01 4.5135255903005600e-02</leafValues></_>
+            2.5701349973678589e-01 -1.0465545207262039e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 909 5.1108570769429207e-03</internalNodes>
+            0 -1 727 -8.3098262548446655e-03</internalNodes>
           <leafValues>
-            4.1587084531784058e-02 -5.5355554819107056e-01</leafValues></_>
+            2.6842510700225830e-01 -9.9635124206542969e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 178 2.1153174340724945e-02</internalNodes>
+            0 -1 269 -2.7831714600324631e-02</internalNodes>
           <leafValues>
-            -9.0628616511821747e-02 2.9272273182868958e-01</leafValues></_>
+            -3.9901316165924072e-01 6.5086022019386292e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 690 -4.0524005889892578e-03</internalNodes>
+            0 -1 399 8.1690559163689613e-03</internalNodes>
           <leafValues>
-            -5.5750316381454468e-01 4.8259153962135315e-02</leafValues></_>
+            -1.1402101069688797e-01 2.2761905193328857e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 208 -4.5195231214165688e-03</internalNodes>
+            0 -1 368 2.8635351918637753e-03</internalNodes>
           <leafValues>
-            2.4507603049278259e-01 -1.1037164181470871e-01</leafValues></_>
+            -1.4034478366374969e-01 1.8733198940753937e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 802 2.9709473252296448e-02</internalNodes>
+            0 -1 286 -2.1204156801104546e-03</internalNodes>
           <leafValues>
-            -9.0624623000621796e-02 3.0535447597503662e-01</leafValues></_>
+            -5.9949654340744019e-01 4.9501683562994003e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 596 -2.4458598345518112e-02</internalNodes>
+            0 -1 669 -9.4446074217557907e-04</internalNodes>
           <leafValues>
-            3.8106867671012878e-01 -6.5381005406379700e-02</leafValues></_>
+            -3.8145086169242859e-01 5.9254929423332214e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 833 2.3627276532351971e-03</internalNodes>
+            0 -1 686 2.1901372820138931e-03</internalNodes>
           <leafValues>
-            -8.9016206562519073e-02 2.7661785483360291e-01</leafValues></_>
+            3.6901079118251801e-02 -5.6260800361633301e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 576 2.5604534894227982e-03</internalNodes>
+            0 -1 103 4.2550573125481606e-03</internalNodes>
           <leafValues>
-            4.9425628036260605e-02 -5.4407423734664917e-01</leafValues></_>
+            -9.8831087350845337e-02 2.3313422501087189e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 164 1.1583864688873291e-02</internalNodes>
+            0 -1 281 4.2771790176630020e-03</internalNodes>
           <leafValues>
-            3.7279289215803146e-02 -6.2233042716979980e-01</leafValues></_>
+            4.2207289487123489e-02 -5.6859022378921509e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 745 -6.5262932330369949e-03</internalNodes>
+            0 -1 422 -7.8792609274387360e-03</internalNodes>
           <leafValues>
-            2.2733294963836670e-01 -1.1270135641098022e-01</leafValues></_>
+            2.2428077459335327e-01 -9.9518932402133942e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 747 -5.5729500018060207e-03</internalNodes>
+            0 -1 561 -3.5514549817889929e-03</internalNodes>
           <leafValues>
-            -5.2463114261627197e-01 4.3969567865133286e-02</leafValues></_>
+            -5.6150603294372559e-01 3.9242122322320938e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 892 2.7682324871420860e-03</internalNodes>
+            0 -1 738 -6.8606354761868715e-04</internalNodes>
           <leafValues>
-            -5.6408800184726715e-02 4.5612502098083496e-01</leafValues></_>
+            2.1056549251079559e-01 -1.2413132935762405e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 683 5.3484998643398285e-03</internalNodes>
+            0 -1 433 5.2483025938272476e-03</internalNodes>
           <leafValues>
-            5.1867362111806870e-02 -4.8760178685188293e-01</leafValues></_>
+            3.4256864339113235e-02 -7.2566890716552734e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 165 5.3632212802767754e-03</internalNodes>
+            0 -1 658 -3.6910744383931160e-03</internalNodes>
           <leafValues>
-            4.4008553028106689e-02 -4.8531344532966614e-01</leafValues></_>
+            2.6440864801406860e-01 -8.9745096862316132e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 168 -4.5866379514336586e-03</internalNodes>
+            0 -1 127 2.0369128324091434e-03</internalNodes>
           <leafValues>
-            -4.7415995597839355e-01 4.6904686838388443e-02</leafValues></_>
+            4.6990364789962769e-02 -5.3132331371307373e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 448 -2.4732598103582859e-03</internalNodes>
+            0 -1 662 3.8735207635909319e-03</internalNodes>
           <leafValues>
-            3.5594299435615540e-01 -6.6797487437725067e-02</leafValues></_>
+            -9.1540865600109100e-02 2.7486115694046021e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 504 -1.3544519897550344e-03</internalNodes>
+            0 -1 126 6.0556940734386444e-03</internalNodes>
           <leafValues>
-            2.5692245364189148e-01 -1.0549759119749069e-01</leafValues></_>
+            5.3909529000520706e-02 -4.6437451243400574e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 226 2.0623015239834785e-02</internalNodes>
+            0 -1 912 4.8301572678610682e-04</internalNodes>
           <leafValues>
-            -1.2213230878114700e-01 1.8851162493228912e-01</leafValues></_>
+            -1.6165176033973694e-01 1.3917934894561768e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 106 -2.5555126368999481e-02</internalNodes>
+            0 -1 101 -1.4880476519465446e-02</internalNodes>
           <leafValues>
-            2.1115033328533173e-01 -1.1155050992965698e-01</leafValues></_>
+            -5.9634107351303101e-01 3.9811171591281891e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 650 -2.6123304851353168e-03</internalNodes>
+            0 -1 609 2.9731846880167723e-03</internalNodes>
           <leafValues>
-            -4.3362092971801758e-01 5.9404496103525162e-02</leafValues></_>
+            3.0903076753020287e-02 -6.2935864925384521e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 454 -2.0256865769624710e-02</internalNodes>
+            0 -1 90 -1.1181155219674110e-02</internalNodes>
           <leafValues>
-            2.3865076899528503e-01 -1.1111994832754135e-01</leafValues></_>
+            3.5473996400833130e-01 -6.4499482512474060e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 636 -1.3834737241268158e-02</internalNodes>
+            0 -1 1009 -9.8370900377631187e-04</internalNodes>
           <leafValues>
-            2.4716469645500183e-01 -9.9341392517089844e-02</leafValues></_>
+            2.9858112335205078e-01 -8.4500424563884735e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 438 1.0408030357211828e-03</internalNodes>
+            0 -1 975 -1.0228222236037254e-03</internalNodes>
           <leafValues>
-            -8.5192345082759857e-02 2.8685340285301208e-01</leafValues></_>
+            2.7100124955177307e-01 -1.0033085197210312e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 693 -7.8561680857092142e-04</internalNodes>
+            0 -1 913 2.0134919323027134e-03</internalNodes>
           <leafValues>
-            -3.1685733795166016e-01 7.3741830885410309e-02</leafValues></_>
+            4.3533660471439362e-02 -5.4969471693038940e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 845 -3.1890799291431904e-03</internalNodes>
+            0 -1 881 -3.1473359558731318e-03</internalNodes>
           <leafValues>
-            2.8838813304901123e-01 -7.9454399645328522e-02</leafValues></_>
+            3.1102818250656128e-01 -8.0141142010688782e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 556 -1.8864404410123825e-02</internalNodes>
+            0 -1 991 -2.9232497327029705e-03</internalNodes>
           <leafValues>
-            -6.1039513349533081e-01 3.4549634903669357e-02</leafValues></_>
+            -6.7808300256729126e-01 3.5025410354137421e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 930 1.9871932454407215e-03</internalNodes>
+            0 -1 494 -3.8992143236100674e-03</internalNodes>
           <leafValues>
-            -6.4915224909782410e-02 3.3199799060821533e-01</leafValues></_>
+            2.5711989402770996e-01 -8.4509201347827911e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 307 -4.4487272389233112e-03</internalNodes>
+            0 -1 547 -3.8403570652008057e-02</internalNodes>
           <leafValues>
-            -4.8411524295806885e-01 4.3471843004226685e-02</leafValues></_>
+            2.8463324904441833e-01 -7.5673028826713562e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 124 1.1506278999149799e-02</internalNodes>
+            0 -1 700 -2.2210094612091780e-03</internalNodes>
           <leafValues>
-            3.4361593425273895e-02 -5.1601499319076538e-01</leafValues></_>
+            -5.6876182556152344e-01 4.0759250521659851e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 299 -4.9164015799760818e-03</internalNodes>
+            0 -1 989 6.9615743122994900e-03</internalNodes>
           <leafValues>
-            2.8029051423072815e-01 -7.6438650488853455e-02</leafValues></_>
+            -7.8118488192558289e-02 2.8128826618194580e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 937 6.8624541163444519e-03</internalNodes>
+            0 -1 948 -1.8219950143247843e-03</internalNodes>
           <leafValues>
-            -1.3434819877147675e-01 1.7164944112300873e-01</leafValues></_>
+            1.8647159636020660e-01 -1.3465921580791473e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 788 1.2513504363596439e-02</internalNodes>
+            0 -1 697 1.0106971021741629e-03</internalNodes>
           <leafValues>
-            -8.2097627222537994e-02 2.6367199420928955e-01</leafValues></_>
+            5.7168632745742798e-02 -4.1419604420661926e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 144 2.5324244052171707e-02</internalNodes>
+            0 -1 945 -3.3746981061995029e-03</internalNodes>
           <leafValues>
-            -9.8793335258960724e-02 2.1438889205455780e-01</leafValues></_>
+            -5.2892911434173584e-01 4.0065344423055649e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 491 4.2827110737562180e-03</internalNodes>
+            0 -1 1030 -8.5245687514543533e-03</internalNodes>
           <leafValues>
-            4.8010587692260742e-02 -5.3329360485076904e-01</leafValues></_>
+            -5.0935691595077515e-01 3.8823168724775314e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 172 -1.0588562116026878e-02</internalNodes>
+            0 -1 1012 -2.2426969371736050e-03</internalNodes>
           <leafValues>
-            2.0557209849357605e-01 -1.1096615344285965e-01</leafValues></_>
+            2.5891116261482239e-01 -8.8167145848274231e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 195 7.3749665170907974e-03</internalNodes>
+            0 -1 402 -5.9730862267315388e-03</internalNodes>
           <leafValues>
-            4.2330745607614517e-02 -4.9726718664169312e-01</leafValues></_>
+            -4.3465223908424377e-01 4.9864508211612701e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 477 -1.0184315964579582e-02</internalNodes>
+            0 -1 452 -5.5482299067080021e-03</internalNodes>
           <leafValues>
-            2.2020325064659119e-01 -1.0080294311046600e-01</leafValues></_>
+            2.5288850069046021e-01 -9.3322932720184326e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 305 -3.1706739682704210e-03</internalNodes>
+            0 -1 51 3.7344563007354736e-01</internalNodes>
           <leafValues>
-            -4.1845852136611938e-01 5.4482847452163696e-02</leafValues></_>
+            -4.9019347876310349e-02 4.3872711062431335e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 670 2.5342048611491919e-03</internalNodes>
+            0 -1 615 -4.0881419554352760e-03</internalNodes>
           <leafValues>
-            -6.9553844630718231e-02 3.2299628853797913e-01</leafValues></_>
+            3.1952694058418274e-01 -7.7735908329486847e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 521 -8.4150061011314392e-03</internalNodes>
+            0 -1 202 3.1661842949688435e-03</internalNodes>
           <leafValues>
-            2.6279926300048828e-01 -9.3804508447647095e-02</leafValues></_>
+            -1.0995075106620789e-01 1.7701222002506256e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 76 4.0150225162506104e-02</internalNodes>
+            0 -1 17 -2.1666671335697174e-01</internalNodes>
           <leafValues>
-            2.9147522523999214e-02 -7.8112679719924927e-01</leafValues></_>
+            -4.5134860277175903e-01 4.9127347767353058e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 177 -4.3324208818376064e-03</internalNodes>
+            0 -1 241 -3.1139418482780457e-02</internalNodes>
           <leafValues>
-            -5.2339142560958862e-01 3.6419976502656937e-02</leafValues></_>
+            2.5138390064239502e-01 -9.4933450222015381e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 39 -4.0873344987630844e-02</internalNodes>
+            0 -1 459 9.1597874416038394e-04</internalNodes>
           <leafValues>
-            3.7220278382301331e-01 -6.1695497483015060e-02</leafValues></_>
+            -7.4231699109077454e-02 3.1368830800056458e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 13 5.9101730585098267e-02</internalNodes>
+            0 -1 747 -6.1164153739809990e-03</internalNodes>
           <leafValues>
-            -5.1950857043266296e-02 4.1701674461364746e-01</leafValues></_>
+            -7.0417582988739014e-01 3.4018490463495255e-02</leafValues></_></weakClassifiers></_>
+    <!-- stage 12 -->
+    <_>
+      <maxWeakCount>77</maxWeakCount>
+      <stageThreshold>-1.3230814933776855e+00</stageThreshold>
+      <weakClassifiers>
         <_>
           <internalNodes>
-            0 -1 628 -3.1048480886965990e-03</internalNodes>
+            0 -1 522 -3.3400340471416712e-03</internalNodes>
           <leafValues>
-            2.1874889731407166e-01 -9.0781040489673615e-02</leafValues></_>
+            4.2352598905563354e-01 -1.2572944164276123e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 627 3.5321055911481380e-03</internalNodes>
+            0 -1 799 -2.3890279699116945e-03</internalNodes>
           <leafValues>
-            -8.2859635353088379e-02 2.9276433587074280e-01</leafValues></_>
+            3.8169610500335693e-01 -1.4501731097698212e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 668 -1.2976058060303330e-03</internalNodes>
+            0 -1 448 -2.4045775644481182e-03</internalNodes>
           <leafValues>
-            -4.3279412388801575e-01 4.9447599798440933e-02</leafValues></_>
+            3.4690696001052856e-01 -1.2821178138256073e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 176 1.1339010670781136e-02</internalNodes>
+            0 -1 524 1.2546034995466471e-03</internalNodes>
           <leafValues>
-            2.6531336829066277e-02 -6.9358879327774048e-01</leafValues></_>
+            -1.4823316037654877e-01 2.9894015192985535e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 969 8.8861025869846344e-03</internalNodes>
+            0 -1 752 -1.8236635252833366e-02</internalNodes>
           <leafValues>
-            2.6764476671814919e-02 -6.1700969934463501e-01</leafValues></_>
+            3.0641126632690430e-01 -1.2427721172571182e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 659 1.1916678398847580e-02</internalNodes>
+            0 -1 229 4.1921215597540140e-04</internalNodes>
           <leafValues>
-            -9.7341567277908325e-02 2.0659063756465912e-01</leafValues></_>
+            -1.8449674546718597e-01 1.7403297126293182e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 804 1.2824826873838902e-02</internalNodes>
+            0 -1 914 -3.0837533995509148e-03</internalNodes>
           <leafValues>
-            -8.5851043462753296e-02 2.6430803537368774e-01</leafValues></_>
+            -6.2562137842178345e-01 3.4162398427724838e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 820 -4.0587522089481354e-03</internalNodes>
+            0 -1 587 -3.4897932782769203e-03</internalNodes>
           <leafValues>
-            1.8127168715000153e-01 -1.1241084337234497e-01</leafValues></_>
+            2.0127655565738678e-01 -1.4677318930625916e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 931 5.4964423179626465e-04</internalNodes>
+            0 -1 882 -3.4818234853446484e-03</internalNodes>
           <leafValues>
-            -9.1979973018169403e-02 2.1896743774414062e-01</leafValues></_>
+            2.9465374350547791e-01 -1.0961814969778061e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 324 1.5558412997052073e-03</internalNodes>
+            0 -1 13 6.2356598675251007e-02</internalNodes>
           <leafValues>
-            -7.7465757727622986e-02 2.5980666279792786e-01</leafValues></_>
+            -9.8056003451347351e-02 3.1733244657516479e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 587 4.3281335383653641e-03</internalNodes>
+            0 -1 607 -1.8334560096263885e-02</internalNodes>
           <leafValues>
-            3.4584067761898041e-02 -6.2342578172683716e-01</leafValues></_>
+            3.1992998719215393e-01 -7.8213296830654144e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 34 -1.4533417299389839e-02</internalNodes>
+            0 -1 885 3.7803263403475285e-03</internalNodes>
           <leafValues>
-            2.0229732990264893e-01 -1.0071664303541183e-01</leafValues></_>
+            5.3678415715694427e-02 -5.0315982103347778e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 644 5.6288111954927444e-03</internalNodes>
+            0 -1 1027 -3.6906298249959946e-02</internalNodes>
           <leafValues>
-            3.9174310863018036e-02 -5.0741255283355713e-01</leafValues></_>
+            -6.3056147098541260e-01 3.8218058645725250e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 936 7.9474167432636023e-04</internalNodes>
+            0 -1 923 4.6968068927526474e-03</internalNodes>
           <leafValues>
-            -8.0158397555351257e-02 2.3534512519836426e-01</leafValues></_>
+            -1.1338837444782257e-01 2.6388064026832581e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 585 -1.0926688089966774e-02</internalNodes>
+            0 -1 708 -1.1566210538148880e-02</internalNodes>
           <leafValues>
-            -5.9471416473388672e-01 3.1198443844914436e-02</leafValues></_>
+            1.6388712823390961e-01 -1.6043519973754883e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 677 -8.2422709092497826e-03</internalNodes>
+            0 -1 489 3.1895786523818970e-03</internalNodes>
           <leafValues>
-            2.0226760208606720e-01 -1.1066834628582001e-01</leafValues></_>
+            6.0215596109628677e-02 -4.7157511115074158e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 923 -3.6351364105939865e-03</internalNodes>
+            0 -1 50 -2.5480750948190689e-02</internalNodes>
           <leafValues>
-            -6.4762312173843384e-01 2.9601249843835831e-02</leafValues></_>
+            -5.5096846818923950e-01 3.9257630705833435e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 784 -2.7860058471560478e-03</internalNodes>
+            0 -1 480 3.9267786778509617e-03</internalNodes>
           <leafValues>
-            4.2289113998413086e-01 -4.8328761011362076e-02</leafValues></_>
+            6.1174295842647552e-02 -4.1686600446701050e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 56 1.4032858889549971e-03</internalNodes>
+            0 -1 874 4.2923549190163612e-03</internalNodes>
           <leafValues>
-            7.7722996473312378e-02 -2.5018605589866638e-01</leafValues></_>
+            -6.9901801645755768e-02 3.6233785748481750e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 56 -4.9225967377424240e-03</internalNodes>
+            0 -1 929 1.5720827504992485e-03</internalNodes>
           <leafValues>
-            -5.3430163860321045e-01 3.4801222383975983e-02</leafValues></_>
+            -9.2891335487365723e-02 2.6970732212066650e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 566 -1.2032099068164825e-02</internalNodes>
+            0 -1 937 4.2968937195837498e-03</internalNodes>
           <leafValues>
-            2.3754563927650452e-01 -8.4349773824214935e-02</leafValues></_>
+            4.5402236282825470e-02 -6.1771476268768311e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 464 5.9743728488683701e-03</internalNodes>
+            0 -1 223 5.8442405425012112e-03</internalNodes>
           <leafValues>
-            -9.6527986228466034e-02 2.0883874595165253e-01</leafValues></_>
+            3.4459017217159271e-02 -6.2251347303390503e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 288 9.0228002518415451e-03</internalNodes>
+            0 -1 663 2.6888614520430565e-03</internalNodes>
           <leafValues>
-            2.6527268812060356e-02 -7.1255648136138916e-01</leafValues></_>
+            3.6230482161045074e-02 -5.7353609800338745e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 94 -4.3231204152107239e-02</internalNodes>
+            0 -1 424 4.4175283983349800e-03</internalNodes>
           <leafValues>
-            -4.5857131481170654e-01 3.5763122141361237e-02</leafValues></_>
+            -6.4959764480590820e-02 3.7311050295829773e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 262 1.9863661378622055e-02</internalNodes>
+            0 -1 138 1.4900951646268368e-03</internalNodes>
           <leafValues>
-            3.8993570953607559e-02 -4.7274601459503174e-01</leafValues></_>
+            -1.0781793296337128e-01 2.0226408541202545e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 364 1.7278429004363716e-04</internalNodes>
+            0 -1 373 2.4665119126439095e-03</internalNodes>
           <leafValues>
-            -1.2378288805484772e-01 1.5123386681079865e-01</leafValues></_>
+            5.7804334908723831e-02 -4.1689205169677734e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 81 8.4997266530990601e-03</internalNodes>
+            0 -1 441 9.3985523562878370e-04</internalNodes>
           <leafValues>
-            3.8503456860780716e-02 -4.7635042667388916e-01</leafValues></_>
+            -1.4865192770957947e-01 1.3861793279647827e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 434 -1.3840992469340563e-03</internalNodes>
+            0 -1 132 -5.3606871515512466e-03</internalNodes>
           <leafValues>
-            2.4361917376518250e-01 -7.7643536031246185e-02</leafValues></_></weakClassifiers></_>
-    <!-- stage 9 -->
-    <_>
-      <maxWeakCount>100</maxWeakCount>
-      <stageThreshold>-1.4933127164840698e+00</stageThreshold>
-      <weakClassifiers>
+            1.8524695932865143e-01 -1.1567704379558563e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 769 -2.4473592638969421e-03</internalNodes>
+            0 -1 636 -4.6638157218694687e-03</internalNodes>
           <leafValues>
-            6.4225250482559204e-01 1.1617031693458557e-01</leafValues></_>
+            1.6163532435894012e-01 -1.3586524128913879e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 918 2.5613610632717609e-03</internalNodes>
+            0 -1 120 3.7256032228469849e-03</internalNodes>
           <leafValues>
-            -1.4125512540340424e-01 4.1756254434585571e-01</leafValues></_>
+            5.2170656621456146e-02 -4.2538973689079285e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 450 -3.6349727306514978e-03</internalNodes>
+            0 -1 106 -8.9184641838073730e-03</internalNodes>
           <leafValues>
-            4.2445364594459534e-01 -1.2421201914548874e-01</leafValues></_>
+            -5.0052535533905029e-01 4.7540370374917984e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 243 7.6568350195884705e-02</internalNodes>
+            0 -1 474 5.6020710617303848e-03</internalNodes>
           <leafValues>
-            -2.0400929450988770e-01 2.4128499627113342e-01</leafValues></_>
+            3.4621786326169968e-02 -5.4071390628814697e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 455 4.6866592019796371e-03</internalNodes>
+            0 -1 475 -3.7551699206233025e-03</internalNodes>
           <leafValues>
-            7.2638466954231262e-02 -5.3155571222305298e-01</leafValues></_>
+            -3.9268767833709717e-01 5.2867397665977478e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 319 -3.9937674999237061e-02</internalNodes>
+            0 -1 567 4.0759481489658356e-03</internalNodes>
           <leafValues>
-            4.3441477417945862e-01 -8.1894725561141968e-02</leafValues></_>
+            3.7209436297416687e-02 -4.7708320617675781e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 376 -1.7270710319280624e-02</internalNodes>
+            0 -1 413 4.1836635209619999e-03</internalNodes>
           <leafValues>
-            4.9218431115150452e-01 -8.1687144935131073e-02</leafValues></_>
+            -5.8815345168113708e-02 3.6573976278305054e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 67 1.0907177627086639e-01</internalNodes>
+            0 -1 477 -9.3902507796883583e-04</internalNodes>
           <leafValues>
-            -1.3829828798770905e-01 3.0388528108596802e-01</leafValues></_>
+            1.9424098730087280e-01 -1.1125016957521439e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 563 -8.6617004126310349e-03</internalNodes>
+            0 -1 985 -9.9178254604339600e-03</internalNodes>
           <leafValues>
-            2.4966995418071747e-01 -1.4650684595108032e-01</leafValues></_>
+            -5.9317117929458618e-01 3.3418238162994385e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 257 5.3433720022439957e-03</internalNodes>
+            0 -1 646 3.3355036284774542e-03</internalNodes>
           <leafValues>
-            5.6382026523351669e-02 -4.7699481248855591e-01</leafValues></_>
+            -8.7399490177631378e-02 2.4422888457775116e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 359 -7.3083816096186638e-03</internalNodes>
+            0 -1 646 -3.4440397284924984e-03</internalNodes>
           <leafValues>
-            1.6508759558200836e-01 -1.8176083266735077e-01</leafValues></_>
+            2.9363137483596802e-01 -7.5259201228618622e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 322 -1.2855050154030323e-03</internalNodes>
+            0 -1 42 2.1378418896347284e-03</internalNodes>
           <leafValues>
-            2.5566878914833069e-01 -1.1560125648975372e-01</leafValues></_>
+            5.6551665067672729e-02 -3.9630606770515442e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 799 1.6045335214585066e-03</internalNodes>
+            0 -1 1005 -4.5215697027742863e-03</internalNodes>
           <leafValues>
-            -1.5024451911449432e-01 1.8980197608470917e-01</leafValues></_>
+            1.6443158686161041e-01 -1.1997994035482407e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 711 -3.2996428199112415e-03</internalNodes>
+            0 -1 47 -1.2263706885278225e-03</internalNodes>
           <leafValues>
-            -5.4483765363693237e-01 5.2060887217521667e-02</leafValues></_>
+            -2.6839572191238403e-01 7.8797832131385803e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 646 -2.1930811926722527e-03</internalNodes>
+            0 -1 926 -7.3856199160218239e-03</internalNodes>
           <leafValues>
-            -5.0953930616378784e-01 4.9616143107414246e-02</leafValues></_>
+            -7.5282222032546997e-01 2.3323338478803635e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 830 -1.3328871689736843e-02</internalNodes>
+            0 -1 1044 1.1934632435441017e-02</internalNodes>
           <leafValues>
-            3.2616052031517029e-01 -8.1101849675178528e-02</leafValues></_>
+            3.9068166166543961e-02 -4.3301787972450256e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 333 3.5710524767637253e-02</internalNodes>
+            0 -1 826 -4.2066089808940887e-03</internalNodes>
           <leafValues>
-            -9.0930387377738953e-02 3.1067803502082825e-01</leafValues></_>
+            3.1933805346488953e-01 -6.1786398291587830e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 488 6.7417006939649582e-03</internalNodes>
+            0 -1 779 -1.5679887728765607e-03</internalNodes>
           <leafValues>
-            -7.7294938266277313e-02 3.2216030359268188e-01</leafValues></_>
+            2.1744215488433838e-01 -9.4651907682418823e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 11 -8.1952005624771118e-02</internalNodes>
+            0 -1 78 2.5083343498408794e-03</internalNodes>
           <leafValues>
-            5.3666585683822632e-01 -5.9473395347595215e-02</leafValues></_>
+            5.7137917727231979e-02 -3.3361336588859558e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 8 9.2416517436504364e-03</internalNodes>
+            0 -1 660 3.6224797368049622e-03</internalNodes>
           <leafValues>
-            -1.2617717683315277e-01 2.0812577009201050e-01</leafValues></_>
+            3.1345754861831665e-02 -5.7247912883758545e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 619 -2.0654057152569294e-03</internalNodes>
+            0 -1 870 -7.7814143151044846e-03</internalNodes>
           <leafValues>
-            -4.8568764328956604e-01 5.2649311721324921e-02</leafValues></_>
+            2.9652404785156250e-01 -6.6501826047897339e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 66 -1.3702171854674816e-02</internalNodes>
+            0 -1 800 -4.1631370550021529e-04</internalNodes>
           <leafValues>
-            -6.6060936450958252e-01 3.5181287676095963e-02</leafValues></_>
+            2.2159980237483978e-01 -1.0610108822584152e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 393 -3.0807605944573879e-03</internalNodes>
+            0 -1 596 4.7841453924775124e-03</internalNodes>
           <leafValues>
-            -4.4769099354743958e-01 4.8634912818670273e-02</leafValues></_>
+            3.3327136188745499e-02 -5.7043993473052979e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 57 -1.2945728376507759e-02</internalNodes>
+            0 -1 347 1.2740758247673512e-03</internalNodes>
           <leafValues>
-            -5.4323107004165649e-01 4.0633078664541245e-02</leafValues></_>
+            -7.9592645168304443e-02 2.4728350341320038e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 240 -1.3134386390447617e-02</internalNodes>
+            0 -1 59 -2.0162630826234818e-02</internalNodes>
           <leafValues>
-            -4.7699347138404846e-01 4.5706178992986679e-02</leafValues></_>
+            -7.0677626132965088e-01 2.7118822559714317e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 434 1.6984546091407537e-03</internalNodes>
+            0 -1 165 -2.5762226432561874e-02</internalNodes>
           <leafValues>
-            -7.0986136794090271e-02 3.2597315311431885e-01</leafValues></_>
+            -5.9367066621780396e-01 2.7015525847673416e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 599 3.8461894728243351e-03</internalNodes>
+            0 -1 255 -1.1241633910685778e-03</internalNodes>
           <leafValues>
-            4.0658432990312576e-02 -5.7832121849060059e-01</leafValues></_>
+            2.9121127724647522e-01 -6.5690472722053528e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 189 -1.7426438629627228e-02</internalNodes>
+            0 -1 818 2.9669383540749550e-02</internalNodes>
           <leafValues>
-            -4.3611589074134827e-01 4.5463379472494125e-02</leafValues></_>
+            3.4585461020469666e-02 -5.4837781190872192e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 730 -2.6193801313638687e-03</internalNodes>
+            0 -1 501 -6.3295168802142143e-03</internalNodes>
           <leafValues>
-            2.5506833195686340e-01 -8.7045751512050629e-02</leafValues></_>
+            2.3453639447689056e-01 -8.5172846913337708e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 150 -1.0474737733602524e-02</internalNodes>
+            0 -1 1046 4.0143523365259171e-03</internalNodes>
           <leafValues>
-            2.3522177338600159e-01 -9.5193855464458466e-02</leafValues></_>
+            3.5306803882122040e-02 -5.4817456007003784e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 776 -2.0476649515330791e-03</internalNodes>
+            0 -1 949 -2.4633856955915689e-03</internalNodes>
           <leafValues>
-            -4.0278571844100952e-01 5.3846791386604309e-02</leafValues></_>
+            1.6164709627628326e-01 -1.1111633479595184e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 492 5.0511634908616543e-03</internalNodes>
+            0 -1 38 -2.6468174532055855e-02</internalNodes>
           <leafValues>
-            3.5829022526741028e-02 -5.8457142114639282e-01</leafValues></_>
+            2.5775042176246643e-01 -7.2721429169178009e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 400 -2.6015858165919781e-03</internalNodes>
+            0 -1 1047 -2.5992670562118292e-03</internalNodes>
           <leafValues>
-            2.8992271423339844e-01 -7.7776394784450531e-02</leafValues></_>
+            -3.1405648589134216e-01 5.9779226779937744e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 191 1.4678405132144690e-03</internalNodes>
+            0 -1 809 -2.2960878908634186e-02</internalNodes>
           <leafValues>
-            4.2822040617465973e-02 -5.0615262985229492e-01</leafValues></_>
+            2.8405818343162537e-01 -6.8080194294452667e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 119 3.4870039671659470e-03</internalNodes>
+            0 -1 437 -1.6940593719482422e-02</internalNodes>
           <leafValues>
-            -8.2636579871177673e-02 2.5724917650222778e-01</leafValues></_>
+            3.0056476593017578e-01 -6.7668616771697998e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 104 -1.9308419525623322e-01</internalNodes>
+            0 -1 528 1.7171052750200033e-03</internalNodes>
           <leafValues>
-            3.6281177401542664e-01 -6.3503719866275787e-02</leafValues></_>
+            -6.5253980457782745e-02 2.9430890083312988e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 545 1.9733399152755737e-02</internalNodes>
+            0 -1 142 -5.2873874083161354e-03</internalNodes>
           <leafValues>
-            -8.6004406213760376e-02 2.5530698895454407e-01</leafValues></_>
+            -4.5413893461227417e-01 4.3044254183769226e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 37 -3.2536339014768600e-02</internalNodes>
+            0 -1 14 -1.8073642626404762e-02</internalNodes>
           <leafValues>
-            -5.8808100223541260e-01 3.7802245467901230e-02</leafValues></_>
+            -3.4945023059844971e-01 5.2509855479001999e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 382 8.8406521826982498e-03</internalNodes>
+            0 -1 627 -2.0803229417651892e-03</internalNodes>
           <leafValues>
-            2.5931548327207565e-02 -6.5399199724197388e-01</leafValues></_>
+            -4.0171647071838379e-01 4.5229051262140274e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 844 -1.0922113433480263e-03</internalNodes>
+            0 -1 918 -1.1218651343369856e-04</internalNodes>
           <leafValues>
-            2.0415900647640228e-01 -1.0292074084281921e-01</leafValues></_>
+            1.2830497324466705e-01 -1.4649079740047455e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 892 1.5520181041210890e-03</internalNodes>
+            0 -1 84 -6.6526420414447784e-03</internalNodes>
           <leafValues>
-            -8.4858812391757965e-02 3.0234101414680481e-01</leafValues></_>
+            -3.4429419040679932e-01 5.4524090141057968e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 601 3.6752538289874792e-03</internalNodes>
+            0 -1 162 -4.1576132178306580e-02</internalNodes>
           <leafValues>
-            3.9351969957351685e-02 -5.4435199499130249e-01</leafValues></_>
+            -5.5132204294204712e-01 3.2239176332950592e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 825 -1.7198601737618446e-02</internalNodes>
+            0 -1 659 -3.2582432031631470e-03</internalNodes>
           <leafValues>
-            -6.8883073329925537e-01 2.4503545835614204e-02</leafValues></_>
+            2.1904261410236359e-01 -9.0739406645298004e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 783 -4.8199836164712906e-03</internalNodes>
+            0 -1 711 -4.4706808403134346e-03</internalNodes>
           <leafValues>
-            3.3481866121292114e-01 -6.0483735054731369e-02</leafValues></_>
+            2.2556288540363312e-01 -9.5258384943008423e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 838 8.6327344179153442e-03</internalNodes>
+            0 -1 177 -6.5750535577535629e-03</internalNodes>
           <leafValues>
-            2.9317237436771393e-02 -7.1339315176010132e-01</leafValues></_>
+            -4.8511472344398499e-01 4.1734144091606140e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 761 5.9000156819820404e-02</internalNodes>
+            0 -1 251 -3.7532784044742584e-02</internalNodes>
           <leafValues>
-            2.5574376806616783e-02 -6.3106632232666016e-01</leafValues></_>
+            2.0968079566955566e-01 -8.8354945182800293e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 782 1.0106523986905813e-03</internalNodes>
+            0 -1 530 -1.2600638438016176e-03</internalNodes>
           <leafValues>
-            -1.0588756203651428e-01 1.9086131453514099e-01</leafValues></_>
+            2.2111406922340393e-01 -9.0988010168075562e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 880 1.1946363374590874e-03</internalNodes>
+            0 -1 28 -2.3967802524566650e-02</internalNodes>
           <leafValues>
-            -8.1224068999290466e-02 2.6191043853759766e-01</leafValues></_>
+            -6.2524855136871338e-01 3.0603738501667976e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 348 8.8360151275992393e-03</internalNodes>
+            0 -1 225 -3.1747903674840927e-02</internalNodes>
           <leafValues>
-            -7.4570186436176300e-02 2.7295246720314026e-01</leafValues></_>
+            -6.2007570266723633e-01 2.5801742449402809e-02</leafValues></_></weakClassifiers></_>
+    <!-- stage 13 -->
+    <_>
+      <maxWeakCount>84</maxWeakCount>
+      <stageThreshold>-1.3265128135681152e+00</stageThreshold>
+      <weakClassifiers>
         <_>
           <internalNodes>
-            0 -1 80 -3.8921819068491459e-03</internalNodes>
+            0 -1 801 -2.4247136898338795e-03</internalNodes>
           <leafValues>
-            -4.6577858924865723e-01 4.1507720947265625e-02</leafValues></_>
+            4.3507692217826843e-01 -1.1363404244184494e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 75 2.6258802972733974e-03</internalNodes>
+            0 -1 239 3.6287805996835232e-03</internalNodes>
           <leafValues>
-            6.9952867925167084e-02 -2.7727422118186951e-01</leafValues></_>
+            -1.5781879425048828e-01 3.3899685740470886e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 600 4.6104520559310913e-02</internalNodes>
+            0 -1 591 -4.2556263506412506e-03</internalNodes>
           <leafValues>
-            2.8723197057843208e-02 -6.4130103588104248e-01</leafValues></_>
+            2.2901295125484467e-01 -2.0403152704238892e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 152 -2.3556766100227833e-03</internalNodes>
+            0 -1 847 1.6322638839483261e-03</internalNodes>
           <leafValues>
-            1.6910773515701294e-01 -1.2073179334402084e-01</leafValues></_>
+            -1.9230945408344269e-01 2.0004445314407349e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 271 2.0879062358289957e-03</internalNodes>
+            0 -1 338 1.4746835455298424e-02</internalNodes>
           <leafValues>
-            -6.1540558934211731e-02 3.1166607141494751e-01</leafValues></_>
+            -1.2184409052133560e-01 3.9130899310112000e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 726 -2.7457359246909618e-03</internalNodes>
+            0 -1 192 -1.5139304101467133e-02</internalNodes>
           <leafValues>
-            -4.3359285593032837e-01 4.4867228716611862e-02</leafValues></_>
+            2.6918080449104309e-01 -1.4086124300956726e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 643 -5.7035693898797035e-03</internalNodes>
+            0 -1 21 -7.4753491207957268e-03</internalNodes>
           <leafValues>
-            -6.3301932811737061e-01 2.7553720399737358e-02</leafValues></_>
+            2.1792158484458923e-01 -1.6056208312511444e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 272 -2.3487601429224014e-03</internalNodes>
+            0 -1 287 2.3232740350067616e-03</internalNodes>
           <leafValues>
-            2.7741125226020813e-01 -7.1828551590442657e-02</leafValues></_>
+            -1.6489887237548828e-01 1.7108000814914703e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 312 -1.2618269771337509e-02</internalNodes>
+            0 -1 899 -2.7532558888196945e-03</internalNodes>
           <leafValues>
-            -6.0198032855987549e-01 3.3369537442922592e-02</leafValues></_>
+            -5.3275841474533081e-01 5.2368167787790298e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 73 -1.2911427766084671e-02</internalNodes>
+            0 -1 896 -3.9793960750102997e-03</internalNodes>
           <leafValues>
-            1.9097310304641724e-01 -9.6765249967575073e-02</leafValues></_>
+            3.4057796001434326e-01 -8.0085732042789459e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 241 2.5069573894143105e-02</internalNodes>
+            0 -1 608 7.1728855371475220e-02</internalNodes>
           <leafValues>
-            2.9379865154623985e-02 -6.2714409828186035e-01</leafValues></_>
+            -7.2147607803344727e-02 4.0667375922203064e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 676 7.4739558622241020e-03</internalNodes>
+            0 -1 883 -5.3792679682374001e-04</internalNodes>
           <leafValues>
-            -6.2408778816461563e-02 3.2309064269065857e-01</leafValues></_>
+            1.7865169048309326e-01 -1.4902706444263458e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 960 -5.5288206785917282e-03</internalNodes>
+            0 -1 248 6.0019297525286674e-03</internalNodes>
           <leafValues>
-            -4.4652014970779419e-01 4.4482827186584473e-02</leafValues></_>
+            7.1029536426067352e-02 -3.9921376109123230e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 707 5.1614809781312943e-03</internalNodes>
+            0 -1 369 6.9427289068698883e-02</internalNodes>
           <leafValues>
-            -1.0451946407556534e-01 1.8219007551670074e-01</leafValues></_>
+            -9.5279395580291748e-02 2.6865223050117493e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 306 -4.6268366277217865e-03</internalNodes>
+            0 -1 130 -8.8401548564434052e-03</internalNodes>
           <leafValues>
-            2.4900399148464203e-01 -7.5879700481891632e-02</leafValues></_>
+            -5.3491175174713135e-01 5.0447739660739899e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 280 -5.0914911553263664e-03</internalNodes>
+            0 -1 699 -1.4551014639437199e-02</internalNodes>
           <leafValues>
-            -3.8135659694671631e-01 4.8699565231800079e-02</leafValues></_>
+            1.9883459806442261e-01 -1.1586152762174606e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 338 1.3252631761133671e-03</internalNodes>
+            0 -1 754 -1.7498439410701394e-03</internalNodes>
           <leafValues>
-            -8.2675725221633911e-02 2.3466596007347107e-01</leafValues></_>
+            2.2214990854263306e-01 -9.8238572478294373e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 989 -2.9426435939967632e-03</internalNodes>
+            0 -1 246 -2.1636944264173508e-02</internalNodes>
           <leafValues>
-            -3.2485908269882202e-01 5.8781418949365616e-02</leafValues></_>
+            2.8814041614532471e-01 -8.2750618457794189e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 352 7.1004321798682213e-03</internalNodes>
+            0 -1 833 1.2786949053406715e-02</internalNodes>
           <leafValues>
-            -1.0710758715867996e-01 1.6876961290836334e-01</leafValues></_>
+            -8.7337315082550049e-02 2.6530647277832031e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 448 1.6454465221613646e-03</internalNodes>
+            0 -1 57 -8.7271071970462799e-03</internalNodes>
           <leafValues>
-            -6.8138562142848969e-02 2.6411062479019165e-01</leafValues></_>
+            -5.3538525104522705e-01 5.0595279783010483e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 335 -4.4519053772091866e-03</internalNodes>
+            0 -1 1039 3.3185956999659538e-03</internalNodes>
           <leafValues>
-            -6.5162777900695801e-01 3.1989157199859619e-02</leafValues></_>
+            4.5733701437711716e-02 -4.4758048653602600e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 422 -5.6191058829426765e-03</internalNodes>
+            0 -1 795 -1.2216938193887472e-03</internalNodes>
           <leafValues>
-            2.2833730280399323e-01 -8.4053449332714081e-02</leafValues></_>
+            1.5257745981216431e-01 -1.4963941276073456e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 225 -5.4375766776502132e-03</internalNodes>
+            0 -1 562 3.9857804775238037e-02</internalNodes>
           <leafValues>
-            -4.2135429382324219e-01 4.7153089195489883e-02</leafValues></_>
+            -8.5655666887760162e-02 2.6823255419731140e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 427 1.4303867937996984e-03</internalNodes>
+            0 -1 764 2.4454984813928604e-03</internalNodes>
           <leafValues>
-            -8.1828169524669647e-02 2.2752483189105988e-01</leafValues></_>
+            4.6102020889520645e-02 -5.0574064254760742e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 579 5.3636888042092323e-03</internalNodes>
+            0 -1 98 -4.2114150524139404e-01</internalNodes>
           <leafValues>
-            4.6839229762554169e-02 -4.3641954660415649e-01</leafValues></_>
+            6.9476419687271118e-01 -3.2907195389270782e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 471 6.7459633573889732e-03</internalNodes>
+            0 -1 558 2.3470625281333923e-02</internalNodes>
           <leafValues>
-            4.8482794314622879e-02 -3.7357741594314575e-01</leafValues></_>
+            -8.6790844798088074e-02 2.2723633050918579e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 888 1.8225495005026460e-03</internalNodes>
+            0 -1 253 -1.1454307474195957e-02</internalNodes>
           <leafValues>
-            -7.2007156908512115e-02 2.6155912876129150e-01</leafValues></_>
+            2.5413584709167480e-01 -8.8991768658161163e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 107 -6.8536788225173950e-02</internalNodes>
+            0 -1 624 5.0260839052498341e-03</internalNodes>
           <leafValues>
-            2.3726168274879456e-01 -8.8266216218471527e-02</leafValues></_>
+            3.8961157202720642e-02 -5.9463697671890259e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 806 8.4726633504033089e-03</internalNodes>
+            0 -1 873 1.6196466749534011e-03</internalNodes>
           <leafValues>
-            3.0765017494559288e-02 -6.1803394556045532e-01</leafValues></_>
+            -9.0231269598007202e-02 2.6204809546470642e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 129 1.6150671988725662e-02</internalNodes>
+            0 -1 408 8.1676244735717773e-02</internalNodes>
           <leafValues>
-            -6.9989733397960663e-02 2.7056843042373657e-01</leafValues></_>
+            -8.0785289406776428e-02 2.5112318992614746e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 414 7.6075509190559387e-02</internalNodes>
+            0 -1 483 -5.4313270375132561e-03</internalNodes>
           <leafValues>
-            -6.6986277699470520e-02 2.6545816659927368e-01</leafValues></_>
+            1.6463221609592438e-01 -1.3186016678810120e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 713 -2.4037770926952362e-03</internalNodes>
+            0 -1 291 5.7006161659955978e-03</internalNodes>
           <leafValues>
-            2.0211938023567200e-01 -1.1674832552671432e-01</leafValues></_>
+            -1.3998855650424957e-01 1.4326113462448120e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 78 1.8187157809734344e-02</internalNodes>
+            0 -1 221 -7.5926873832941055e-03</internalNodes>
           <leafValues>
-            3.7632372230291367e-02 -5.2273052930831909e-01</leafValues></_>
+            -5.5559343099594116e-01 3.7072587758302689e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 569 -1.3952046632766724e-02</internalNodes>
+            0 -1 618 7.5261802412569523e-03</internalNodes>
           <leafValues>
-            3.2746854424476624e-01 -6.3546165823936462e-02</leafValues></_>
+            2.8434989973902702e-02 -5.8689045906066895e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 18 -2.6383304595947266e-01</internalNodes>
+            0 -1 869 -6.3516031950712204e-03</internalNodes>
           <leafValues>
-            -4.4734519720077515e-01 4.3956480920314789e-02</leafValues></_>
+            1.4447389543056488e-01 -1.4542055130004883e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 84 3.7522446364164352e-03</internalNodes>
+            0 -1 980 -7.6800247188657522e-04</internalNodes>
           <leafValues>
-            3.8990244269371033e-02 -4.2726546525955200e-01</leafValues></_>
+            1.8556322157382965e-01 -1.0404425859451294e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 287 1.4125283341854811e-03</internalNodes>
+            0 -1 941 -4.4167470186948776e-03</internalNodes>
           <leafValues>
-            -5.6341815739870071e-02 3.3222517371177673e-01</leafValues></_>
+            -7.0306748151779175e-01 3.0874395743012428e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 582 4.1739037260413170e-03</internalNodes>
+            0 -1 1010 3.3405693247914314e-03</internalNodes>
           <leafValues>
-            -8.1689253449440002e-02 2.1681067347526550e-01</leafValues></_>
+            -6.6534630954265594e-02 3.4018290042877197e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 982 -6.1572249978780746e-03</internalNodes>
+            0 -1 114 1.1457607150077820e-02</internalNodes>
           <leafValues>
-            -4.6595495939254761e-01 4.0940407663583755e-02</leafValues></_>
+            3.3658623695373535e-02 -6.1056423187255859e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 482 -4.0140310302376747e-03</internalNodes>
+            0 -1 1000 -1.8547235522419214e-03</internalNodes>
           <leafValues>
-            -4.4917678833007812e-01 3.6913067102432251e-02</leafValues></_>
+            -7.4722522497177124e-01 2.2372998297214508e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 315 5.7834591716527939e-03</internalNodes>
+            0 -1 9 -1.9720013439655304e-01</internalNodes>
           <leafValues>
-            3.7202619016170502e-02 -4.4926682114601135e-01</leafValues></_>
+            -5.9932583570480347e-01 2.9283462092280388e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 375 -2.7866717427968979e-03</internalNodes>
+            0 -1 544 -2.6251156814396381e-03</internalNodes>
           <leafValues>
-            2.3668289184570312e-01 -7.8896284103393555e-02</leafValues></_>
+            -3.0683135986328125e-01 5.5391944944858551e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 740 -2.0863343961536884e-03</internalNodes>
+            0 -1 17 -2.7104711532592773e-01</internalNodes>
           <leafValues>
-            -3.1535735726356506e-01 5.4699663072824478e-02</leafValues></_>
+            -6.4121168851852417e-01 2.6428909972310066e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 16 -3.5249911248683929e-02</internalNodes>
+            0 -1 349 1.0233232751488686e-02</internalNodes>
           <leafValues>
-            2.3871497809886932e-01 -7.4336178600788116e-02</leafValues></_>
+            4.5153360813856125e-02 -3.6883556842803955e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 12 1.9735466688871384e-02</internalNodes>
+            0 -1 363 4.0971953421831131e-03</internalNodes>
           <leafValues>
-            -6.9253593683242798e-02 2.7050065994262695e-01</leafValues></_>
+            4.1385501623153687e-02 -4.3035930395126343e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 977 6.9166612811386585e-03</internalNodes>
+            0 -1 464 -8.8650803081691265e-04</internalNodes>
           <leafValues>
-            3.9671208709478378e-02 -4.5562696456909180e-01</leafValues></_>
+            1.6314724087715149e-01 -1.1271495372056961e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 180 1.2886511161923409e-02</internalNodes>
+            0 -1 721 -4.1144760325551033e-03</internalNodes>
           <leafValues>
-            -5.7705853134393692e-02 3.0492311716079712e-01</leafValues></_>
+            -5.5176359415054321e-01 3.3540870994329453e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 680 -4.3238401412963867e-02</internalNodes>
+            0 -1 940 -9.8663510289043188e-04</internalNodes>
           <leafValues>
-            -6.9368255138397217e-01 2.5768887251615524e-02</leafValues></_>
+            2.1676342189311981e-01 -8.5408315062522888e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 858 5.2338346838951111e-02</internalNodes>
+            0 -1 428 6.0831783339381218e-03</internalNodes>
           <leafValues>
-            -4.1087090969085693e-02 4.6693238615989685e-01</leafValues></_>
+            -8.7310679256916046e-02 2.3208071291446686e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 903 -3.8494272157549858e-03</internalNodes>
+            0 -1 789 -1.4624604955315590e-02</internalNodes>
           <leafValues>
-            1.6975462436676025e-01 -1.2150127440690994e-01</leafValues></_>
+            -5.9713214635848999e-01 3.0128041282296181e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 897 1.1914474889636040e-02</internalNodes>
+            0 -1 787 1.3654056005179882e-02</internalNodes>
           <leafValues>
-            -7.7901296317577362e-02 2.2727672755718231e-01</leafValues></_></weakClassifiers></_>
-    <!-- stage 10 -->
-    <_>
-      <maxWeakCount>100</maxWeakCount>
-      <stageThreshold>-1.5521451234817505e+00</stageThreshold>
-      <weakClassifiers>
+            2.4816744029521942e-02 -6.2301605939865112e-01</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 820 4.2229411192238331e-03</internalNodes>
+          <leafValues>
+            -7.3886208236217499e-02 2.4938605725765228e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 700 1.0511254891753197e-02</internalNodes>
+            0 -1 168 1.3268929906189442e-03</internalNodes>
           <leafValues>
-            7.8954458236694336e-02 6.2691432237625122e-01</leafValues></_>
+            4.0760166943073273e-02 -4.3510803580284119e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 501 -4.5915953814983368e-03</internalNodes>
+            0 -1 275 -9.6903974190354347e-04</internalNodes>
           <leafValues>
-            4.8032283782958984e-01 -1.2750500440597534e-01</leafValues></_>
+            2.2486831247806549e-01 -7.8642837703227997e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 920 1.5926066553220153e-03</internalNodes>
+            0 -1 274 1.0329007636755705e-03</internalNodes>
           <leafValues>
-            -2.2285957634449005e-01 2.5022059679031372e-01</leafValues></_>
+            -7.3648050427436829e-02 2.6808246970176697e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 265 4.7702826559543610e-02</internalNodes>
+            0 -1 474 -4.2711962014436722e-03</internalNodes>
           <leafValues>
-            -1.6401256620883942e-01 4.6663716435432434e-01</leafValues></_>
+            -4.0931078791618347e-01 4.7851666808128357e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 801 3.6355913616716862e-03</internalNodes>
+            0 -1 983 -3.7627927958965302e-03</internalNodes>
           <leafValues>
-            -9.0887933969497681e-02 4.3753233551979065e-01</leafValues></_>
+            -5.0520634651184082e-01 3.0405685305595398e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 505 -2.9029550496488810e-03</internalNodes>
+            0 -1 979 -1.7928264569491148e-03</internalNodes>
           <leafValues>
-            3.1178581714630127e-01 -1.4401906728744507e-01</leafValues></_>
+            3.3886525034904480e-01 -5.3929597139358521e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 811 6.0793287120759487e-03</internalNodes>
+            0 -1 148 3.9475625380873680e-03</internalNodes>
           <leafValues>
-            -1.6874884068965912e-01 2.2609569132328033e-01</leafValues></_>
+            3.4511350095272064e-02 -5.2250456809997559e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 200 4.1879736818373203e-04</internalNodes>
+            0 -1 827 -4.4537894427776337e-03</internalNodes>
           <leafValues>
-            -1.9620604813098907e-01 1.5544828772544861e-01</leafValues></_>
+            2.2575919330120087e-01 -7.4650920927524567e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 886 2.2689576144330204e-04</internalNodes>
+            0 -1 774 -2.9974281787872314e-02</internalNodes>
           <leafValues>
-            -1.9928123056888580e-01 1.4717149734497070e-01</leafValues></_>
+            -6.0629475116729736e-01 3.4456655383110046e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 138 -8.1100836396217346e-02</internalNodes>
+            0 -1 123 2.6775486767292023e-02</internalNodes>
           <leafValues>
-            -5.1434135437011719e-01 5.8547608554363251e-02</leafValues></_>
+            -8.8883727788925171e-02 2.0147153735160828e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 108 2.7355052530765533e-02</internalNodes>
+            0 -1 302 -4.4971965253353119e-03</internalNodes>
           <leafValues>
-            6.0101613402366638e-02 -4.1557094454765320e-01</leafValues></_>
+            -5.3158396482467651e-01 3.3491309732198715e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 967 -2.4958662688732147e-03</internalNodes>
+            0 -1 620 -1.5196309424936771e-02</internalNodes>
           <leafValues>
-            -5.0487858057022095e-01 5.1647525280714035e-02</leafValues></_>
+            2.8140705823898315e-01 -6.4074374735355377e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 420 -1.5961761819198728e-03</internalNodes>
+            0 -1 560 -2.1833679638803005e-03</internalNodes>
           <leafValues>
-            2.1670737862586975e-01 -1.2691333889961243e-01</leafValues></_>
+            2.1953551471233368e-01 -8.5029341280460358e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 369 2.1885756403207779e-02</internalNodes>
+            0 -1 317 -5.4325433447957039e-03</internalNodes>
           <leafValues>
-            -8.3462193608283997e-02 3.1052881479263306e-01</leafValues></_>
+            -4.8182886838912964e-01 3.8184959441423416e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 760 -1.3334145769476891e-02</internalNodes>
+            0 -1 463 -3.9055421948432922e-03</internalNodes>
           <leafValues>
-            3.0464804172515869e-01 -8.8519357144832611e-02</leafValues></_>
+            -3.5678783059120178e-01 4.5511916279792786e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 688 -1.9117443589493632e-03</internalNodes>
+            0 -1 1017 -5.0043486990034580e-03</internalNodes>
           <leafValues>
-            -6.8484777212142944e-01 4.3931856751441956e-02</leafValues></_>
+            -3.5324424505233765e-01 4.9539435654878616e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 689 2.2813947871327400e-03</internalNodes>
+            0 -1 595 4.2052613571286201e-03</internalNodes>
           <leafValues>
-            4.6766888350248337e-02 -4.8588466644287109e-01</leafValues></_>
+            -7.6765090227127075e-02 2.4410718679428101e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 164 -8.7422672659158707e-03</internalNodes>
+            0 -1 642 -2.9198043048381805e-03</internalNodes>
           <leafValues>
-            -4.9902194738388062e-01 4.8665110021829605e-02</leafValues></_>
+            2.8657916188240051e-01 -9.1479435563087463e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 758 -4.0188119746744633e-03</internalNodes>
+            0 -1 116 1.4442477375268936e-02</internalNodes>
           <leafValues>
-            2.2568543255329132e-01 -1.1153879016637802e-01</leafValues></_>
+            2.2604020312428474e-02 -7.7516084909439087e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 966 1.3594499323517084e-03</internalNodes>
+            0 -1 956 1.0879908688366413e-02</internalNodes>
           <leafValues>
-            4.2799551039934158e-02 -5.6778526306152344e-01</leafValues></_>
+            -8.9434660971164703e-02 1.8898591399192810e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 718 -6.5033760620281100e-04</internalNodes>
+            0 -1 707 1.2304648756980896e-01</internalNodes>
           <leafValues>
-            2.0394213497638702e-01 -1.1888848990201950e-01</leafValues></_>
+            2.9145279899239540e-02 -5.6789475679397583e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 473 -3.1412184238433838e-02</internalNodes>
+            0 -1 301 5.4486069828271866e-02</internalNodes>
           <leafValues>
-            2.5797879695892334e-01 -9.3766883015632629e-02</leafValues></_>
+            -8.0465197563171387e-02 2.1073351800441742e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 139 -9.2636439949274063e-03</internalNodes>
+            0 -1 37 -1.0112209245562553e-02</internalNodes>
           <leafValues>
-            -5.6845456361770630e-01 4.3344158679246902e-02</leafValues></_>
+            2.5688818097114563e-01 -7.3113977909088135e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 383 -4.1950333863496780e-02</internalNodes>
+            0 -1 145 -4.3551158159971237e-03</internalNodes>
           <leafValues>
-            -3.3588516712188721e-01 6.3371837139129639e-02</leafValues></_>
+            -4.0537205338478088e-01 5.1149621605873108e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 881 2.9165907762944698e-03</internalNodes>
+            0 -1 377 2.8712721541523933e-03</internalNodes>
           <leafValues>
-            -6.9124616682529449e-02 3.5223892331123352e-01</leafValues></_>
+            -8.9186541736125946e-02 2.0391693711280823e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 904 -1.0271451901644468e-03</internalNodes>
+            0 -1 220 2.4744076654314995e-02</internalNodes>
           <leafValues>
-            1.8418928980827332e-01 -1.1801387369632721e-01</leafValues></_>
+            3.1359996646642685e-02 -5.9586691856384277e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 663 2.6636901311576366e-03</internalNodes>
+            0 -1 19 6.0209888033568859e-03</internalNodes>
           <leafValues>
-            -1.0614035278558731e-01 2.1366043388843536e-01</leafValues></_>
+            -8.2612000405788422e-02 2.1787849068641663e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 629 -1.8712934106588364e-02</internalNodes>
+            0 -1 852 6.0595902614295483e-03</internalNodes>
           <leafValues>
-            2.4622038006782532e-01 -9.3236625194549561e-02</leafValues></_>
+            4.7610606998205185e-02 -3.5010379552841187e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 33 -4.8551969230175018e-03</internalNodes>
+            0 -1 324 -2.1957855671644211e-02</internalNodes>
           <leafValues>
-            3.0577266216278076e-01 -7.4214689433574677e-02</leafValues></_>
+            2.2477181255817413e-01 -7.5377546250820160e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 156 2.4788705632090569e-03</internalNodes>
+            0 -1 385 -3.9967135526239872e-03</internalNodes>
           <leafValues>
-            -8.6660243570804596e-02 2.9340657591819763e-01</leafValues></_>
+            4.3043723702430725e-01 -3.9885677397251129e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 291 -4.3734526261687279e-03</internalNodes>
+            0 -1 745 -2.0381226204335690e-03</internalNodes>
           <leafValues>
-            -5.0270831584930420e-01 4.9233034253120422e-02</leafValues></_>
+            -5.8131587505340576e-01 3.2071832567453384e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 318 -4.9623926170170307e-03</internalNodes>
+            0 -1 337 3.8902673404663801e-03</internalNodes>
           <leafValues>
-            -4.4072946906089783e-01 4.5711714774370193e-02</leafValues></_>
+            -6.0279250144958496e-02 2.9424437880516052e-01</leafValues></_></weakClassifiers></_>
+    <!-- stage 14 -->
+    <_>
+      <maxWeakCount>82</maxWeakCount>
+      <stageThreshold>-1.2607949972152710e+00</stageThreshold>
+      <weakClassifiers>
         <_>
           <internalNodes>
-            0 -1 82 3.0696424655616283e-03</internalNodes>
+            0 -1 798 -1.9003680208697915e-03</internalNodes>
           <leafValues>
-            5.5255725979804993e-02 -3.7899428606033325e-01</leafValues></_>
+            4.8600798845291138e-01 -7.5834542512893677e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 157 -8.1601645797491074e-03</internalNodes>
+            0 -1 238 1.5605278313159943e-03</internalNodes>
           <leafValues>
-            2.6425153017044067e-01 -8.2545064389705658e-02</leafValues></_>
+            -1.9763922691345215e-01 2.5329649448394775e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 137 -1.4500592369586229e-03</internalNodes>
+            0 -1 584 -4.8138713464140892e-03</internalNodes>
           <leafValues>
-            1.8156392872333527e-01 -1.2637530267238617e-01</leafValues></_>
+            3.5302931070327759e-01 -1.2585695087909698e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 339 -3.7104606162756681e-03</internalNodes>
+            0 -1 870 5.7447804138064384e-03</internalNodes>
           <leafValues>
-            1.9824002683162689e-01 -1.0828326642513275e-01</leafValues></_>
+            -1.5453046560287476e-01 3.5572248697280884e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 673 -8.7567782029509544e-03</internalNodes>
+            0 -1 806 3.2787662930786610e-03</internalNodes>
           <leafValues>
-            2.8610706329345703e-01 -7.3251776397228241e-02</leafValues></_>
+            -1.8419209122657776e-01 1.6216333210468292e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 317 -1.8970356322824955e-03</internalNodes>
+            0 -1 423 2.8142044320702553e-03</internalNodes>
           <leafValues>
-            -6.0897153615951538e-01 3.7743657827377319e-02</leafValues></_>
+            -9.4009101390838623e-02 2.7667456865310669e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 20 3.8996827602386475e-01</internalNodes>
+            0 -1 259 1.8096582498401403e-03</internalNodes>
           <leafValues>
-            -5.8310892432928085e-02 3.6127504706382751e-01</leafValues></_>
+            -8.9050479233264923e-02 2.9622453451156616e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 396 -4.9336552619934082e-03</internalNodes>
+            0 -1 988 7.2106244042515755e-03</internalNodes>
           <leafValues>
-            3.0048343539237976e-01 -6.4242139458656311e-02</leafValues></_>
+            -1.0854976624250412e-01 2.2157947719097137e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 54 2.5108925998210907e-02</internalNodes>
+            0 -1 342 1.3368867337703705e-02</internalNodes>
           <leafValues>
-            2.5090903043746948e-02 -8.1637203693389893e-01</leafValues></_>
+            5.8126326650381088e-02 -3.8564166426658630e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 429 4.2880335822701454e-03</internalNodes>
+            0 -1 276 1.6755410470068455e-03</internalNodes>
           <leafValues>
-            -8.1443257629871368e-02 2.6617726683616638e-01</leafValues></_>
+            -6.9541916251182556e-02 3.6275833845138550e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 456 -5.6165808928199112e-05</internalNodes>
+            0 -1 198 -4.5782830566167831e-03</internalNodes>
           <leafValues>
-            1.4481364190578461e-01 -1.6212667524814606e-01</leafValues></_>
+            -5.6317430734634399e-01 3.9351724088191986e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 406 3.0591385439038277e-03</internalNodes>
+            0 -1 729 3.6364984698593616e-03</internalNodes>
           <leafValues>
-            2.8733581304550171e-02 -7.0054715871810913e-01</leafValues></_>
+            -1.5140864253044128e-01 1.4790520071983337e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 185 -3.0338061042129993e-03</internalNodes>
+            0 -1 928 -1.1279541999101639e-02</internalNodes>
           <leafValues>
-            -8.2671564817428589e-01 1.9727285951375961e-02</leafValues></_>
+            -4.8907181620597839e-01 5.1109701395034790e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 787 -2.1344989072531462e-03</internalNodes>
+            0 -1 867 -1.2224027886986732e-02</internalNodes>
           <leafValues>
-            1.6036525368690491e-01 -1.2014801055192947e-01</leafValues></_>
+            -6.0496371984481812e-01 3.5609807819128036e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 246 2.4434458464384079e-02</internalNodes>
+            0 -1 769 -2.8662174940109253e-02</internalNodes>
           <leafValues>
-            -1.0801825672388077e-01 2.0232307910919189e-01</leafValues></_>
+            2.4556699395179749e-01 -9.9369116127490997e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 214 -6.6356086172163486e-03</internalNodes>
+            0 -1 496 6.7924216389656067e-02</internalNodes>
           <leafValues>
-            1.9015397131443024e-01 -1.0796815156936646e-01</leafValues></_>
+            -7.8038521111011505e-02 3.3691942691802979e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 781 -8.2725454121828079e-03</internalNodes>
+            0 -1 962 2.2719642147421837e-03</internalNodes>
           <leafValues>
-            3.1057110428810120e-01 -8.6532585322856903e-02</leafValues></_>
+            5.8022607117891312e-02 -4.7124773263931274e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 95 -7.1973735466599464e-03</internalNodes>
+            0 -1 210 8.5627539083361626e-03</internalNodes>
           <leafValues>
-            -5.8514142036437988e-01 3.6453813314437866e-02</leafValues></_>
+            3.4671626985073090e-02 -4.6883812546730042e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 461 -1.3809885131195188e-03</internalNodes>
+            0 -1 362 1.1866856366395950e-03</internalNodes>
           <leafValues>
-            1.6234619915485382e-01 -1.2079101055860519e-01</leafValues></_>
+            -8.0339640378952026e-02 2.5030750036239624e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 408 1.2584345415234566e-02</internalNodes>
+            0 -1 979 8.1023329403251410e-04</internalNodes>
           <leafValues>
-            -8.4917336702346802e-02 2.3094473779201508e-01</leafValues></_>
+            -8.0605715513229370e-02 2.5741192698478699e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 907 8.0425739288330078e-03</internalNodes>
+            0 -1 281 -4.0647285059094429e-03</internalNodes>
           <leafValues>
-            4.0869396179914474e-02 -5.2088880538940430e-01</leafValues></_>
+            -5.0938653945922852e-01 4.0403041988611221e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 446 4.0921196341514587e-02</internalNodes>
+            0 -1 309 -1.9617568701505661e-02</internalNodes>
           <leafValues>
-            -5.4803006350994110e-02 3.5920065641403198e-01</leafValues></_>
+            -5.4703706502914429e-01 3.5078343003988266e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 635 -3.6556557752192020e-03</internalNodes>
+            0 -1 233 6.9989012554287910e-03</internalNodes>
           <leafValues>
-            3.0303934216499329e-01 -6.9975942373275757e-02</leafValues></_>
+            2.6246270164847374e-02 -6.0453557968139648e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 275 -2.6071248576045036e-03</internalNodes>
+            0 -1 450 -6.2460554763674736e-03</internalNodes>
           <leafValues>
-            1.7682927846908569e-01 -1.1164762824773788e-01</leafValues></_>
+            2.3062629997730255e-01 -8.3763726055622101e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 289 -5.8146800845861435e-02</internalNodes>
+            0 -1 529 7.5731135439127684e-04</internalNodes>
           <leafValues>
-            -3.7277954816818237e-01 5.6890588253736496e-02</leafValues></_>
+            -9.5188923180103302e-02 2.3367822170257568e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 120 -2.2651627659797668e-01</internalNodes>
+            0 -1 462 -3.2256892882287502e-03</internalNodes>
           <leafValues>
-            4.0828245878219604e-01 -5.9184983372688293e-02</leafValues></_>
+            2.1003848314285278e-01 -1.2173316627740860e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 738 5.7799168862402439e-03</internalNodes>
+            0 -1 941 -2.8797222767025232e-03</internalNodes>
           <leafValues>
-            4.0102362632751465e-02 -5.5016636848449707e-01</leafValues></_>
+            -4.8621371388435364e-01 4.3998546898365021e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 302 1.6304963501170278e-03</internalNodes>
+            0 -1 740 5.9399371966719627e-03</internalNodes>
           <leafValues>
-            -1.2154985219240189e-01 1.5898743271827698e-01</leafValues></_>
+            2.7645273134112358e-02 -6.2591820955276489e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 672 2.0045600831508636e-03</internalNodes>
+            0 -1 742 -5.4768389090895653e-03</internalNodes>
           <leafValues>
-            2.9790198430418968e-02 -5.8250021934509277e-01</leafValues></_>
+            2.5695452094078064e-01 -8.1276804208755493e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 371 -2.0879322662949562e-02</internalNodes>
+            0 -1 107 -2.2785080596804619e-02</internalNodes>
           <leafValues>
-            2.1142369508743286e-01 -8.7382547557353973e-02</leafValues></_>
+            -6.7479509115219116e-01 2.9845010489225388e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 954 -7.2442064993083477e-04</internalNodes>
+            0 -1 240 -6.0453559271991253e-03</internalNodes>
           <leafValues>
-            2.3263402283191681e-01 -8.1574723124504089e-02</leafValues></_>
+            -4.5132589340209961e-01 4.0413774549961090e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 971 -7.4541047215461731e-03</internalNodes>
+            0 -1 216 5.9022027999162674e-03</internalNodes>
           <leafValues>
-            -4.5152980089187622e-01 4.5829907059669495e-02</leafValues></_>
+            4.6321801841259003e-02 -3.9377251267433167e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 930 -8.5284758824855089e-04</internalNodes>
+            0 -1 775 -1.1740738991647959e-03</internalNodes>
           <leafValues>
-            2.1253970265388489e-01 -9.1697148978710175e-02</leafValues></_>
+            2.2063454985618591e-01 -8.9038714766502380e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 193 2.0642249728552997e-04</internalNodes>
+            0 -1 835 -3.7963264621794224e-03</internalNodes>
           <leafValues>
-            -1.3943105936050415e-01 1.3452273607254028e-01</leafValues></_>
+            1.7901860177516937e-01 -1.0518371313810349e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 922 3.2144919969141483e-03</internalNodes>
+            0 -1 871 2.4132090620696545e-03</internalNodes>
           <leafValues>
-            2.8089782223105431e-02 -6.4253503084182739e-01</leafValues></_>
+            -9.3182116746902466e-02 2.9489630460739136e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 964 -4.6502160839736462e-03</internalNodes>
+            0 -1 543 4.5318575575947762e-04</internalNodes>
           <leafValues>
-            2.4156840145587921e-01 -7.5992465019226074e-02</leafValues></_>
+            -1.4386458694934845e-01 1.3717848062515259e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 391 -7.9781133681535721e-03</internalNodes>
+            0 -1 1029 1.8930386751890182e-02</internalNodes>
           <leafValues>
-            -6.4584964513778687e-01 2.7661839500069618e-02</leafValues></_>
+            3.3168405294418335e-02 -5.5337232351303101e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 535 5.7130996137857437e-03</internalNodes>
+            0 -1 652 -2.6878318749368191e-03</internalNodes>
           <leafValues>
-            3.4437701106071472e-02 -4.5668947696685791e-01</leafValues></_>
+            -5.4439735412597656e-01 3.1048862263560295e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 625 5.4299971088767052e-03</internalNodes>
+            0 -1 672 -3.9407592266798019e-03</internalNodes>
           <leafValues>
-            -8.4557615220546722e-02 2.4553726613521576e-01</leafValues></_>
+            -6.5507227182388306e-01 2.4424355477094650e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 949 2.3061740212142467e-03</internalNodes>
+            0 -1 599 2.1629813127219677e-03</internalNodes>
           <leafValues>
-            3.6576978862285614e-02 -5.1891702413558960e-01</leafValues></_>
+            -1.0160741209983826e-01 1.8277852237224579e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 815 5.0157017540186644e-04</internalNodes>
+            0 -1 222 -2.9370808042585850e-03</internalNodes>
           <leafValues>
-            -1.1976727843284607e-01 1.6033935546875000e-01</leafValues></_>
+            -4.7847637534141541e-01 3.8538910448551178e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 525 -1.9801128655672073e-04</internalNodes>
+            0 -1 6 3.8221649825572968e-02</internalNodes>
           <leafValues>
-            1.5492685139179230e-01 -1.1399404704570770e-01</leafValues></_>
+            -7.6206430792808533e-02 2.3375664651393890e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 840 2.1493299864232540e-03</internalNodes>
+            0 -1 393 -3.1483019702136517e-03</internalNodes>
           <leafValues>
-            -8.7143458425998688e-02 2.1080201864242554e-01</leafValues></_>
+            2.5192636251449585e-01 -7.3695883154869080e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 45 -1.0518108028918505e-03</internalNodes>
+            0 -1 613 -4.5907422900199890e-03</internalNodes>
           <leafValues>
-            1.7875078320503235e-01 -9.7399607300758362e-02</leafValues></_>
+            -6.2766075134277344e-01 2.8896089643239975e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 590 9.2383408918976784e-03</internalNodes>
+            0 -1 26 -9.5378428697586060e-02</internalNodes>
           <leafValues>
-            3.2961033284664154e-02 -5.5265057086944580e-01</leafValues></_>
+            -7.4559724330902100e-01 2.1207747980952263e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 41 3.6674018949270248e-02</internalNodes>
+            0 -1 639 2.0872952882200480e-03</internalNodes>
           <leafValues>
-            -5.6394163519144058e-02 3.2619351148605347e-01</leafValues></_>
+            -8.7810918688774109e-02 2.0629811286926270e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 725 1.8489698413759470e-03</internalNodes>
+            0 -1 635 -6.9244997575879097e-03</internalNodes>
           <leafValues>
-            -7.7260658144950867e-02 2.3810040950775146e-01</leafValues></_>
+            1.8590562045574188e-01 -9.8790608346462250e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 723 -3.9793262258172035e-03</internalNodes>
+            0 -1 590 2.4594084825366735e-03</internalNodes>
           <leafValues>
-            2.3499612510204315e-01 -8.8490329682826996e-02</leafValues></_>
+            -1.0049589723348618e-01 2.2963477671146393e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 619 3.7299278192222118e-03</internalNodes>
+            0 -1 1021 -5.2931695245206356e-03</internalNodes>
           <leafValues>
-            3.1517989933490753e-02 -6.3558888435363770e-01</leafValues></_>
+            -4.5924744009971619e-01 4.3104480952024460e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 916 4.9755964428186417e-03</internalNodes>
+            0 -1 994 4.8847724683582783e-03</internalNodes>
           <leafValues>
-            2.8343016281723976e-02 -5.1388341188430786e-01</leafValues></_>
+            4.6008609235286713e-02 -4.4277390837669373e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 77 2.8308688197284937e-03</internalNodes>
+            0 -1 454 1.4400177169591188e-03</internalNodes>
           <leafValues>
-            -1.1687427759170532e-01 1.4075778424739838e-01</leafValues></_>
+            -5.9334080666303635e-02 3.0132320523262024e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 72 -4.3399848043918610e-02</internalNodes>
+            0 -1 156 -8.6052305996417999e-03</internalNodes>
           <leafValues>
-            3.3840376138687134e-01 -6.5363220870494843e-02</leafValues></_>
+            1.9737368822097778e-01 -8.9747570455074310e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 174 4.4767763465642929e-03</internalNodes>
+            0 -1 193 -6.1248587444424629e-03</internalNodes>
           <leafValues>
-            5.3890492767095566e-02 -3.8843661546707153e-01</leafValues></_>
+            -4.5141929388046265e-01 3.8760874420404434e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 443 1.4579682610929012e-03</internalNodes>
+            0 -1 464 -1.8148655071854591e-03</internalNodes>
           <leafValues>
-            -9.5170073211193085e-02 1.7093485593795776e-01</leafValues></_>
+            2.2768247127532959e-01 -8.2637414336204529e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 217 4.3643731623888016e-03</internalNodes>
+            0 -1 330 -8.5119507275521755e-04</internalNodes>
           <leafValues>
-            -1.0353569686412811e-01 1.9202291965484619e-01</leafValues></_>
+            1.9616322219371796e-01 -1.0013028979301453e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 416 -6.4208358526229858e-03</internalNodes>
+            0 -1 417 1.4472046867012978e-02</internalNodes>
           <leafValues>
-            -5.2469170093536377e-01 3.1174579635262489e-02</leafValues></_>
+            -8.8336527347564697e-02 1.9660694897174835e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 399 -1.0310811921954155e-03</internalNodes>
+            0 -1 628 1.4135142788290977e-02</internalNodes>
           <leafValues>
-            2.1713955700397491e-01 -8.0816701054573059e-02</leafValues></_>
+            -6.4112767577171326e-02 3.1887489557266235e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 924 -4.0359990671277046e-03</internalNodes>
+            0 -1 390 4.8004039563238621e-03</internalNodes>
           <leafValues>
-            -5.2423858642578125e-01 3.4388832747936249e-02</leafValues></_>
+            4.8681098967790604e-02 -4.6234726905822754e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 750 -5.9410361573100090e-03</internalNodes>
+            0 -1 279 -3.3503584563732147e-02</internalNodes>
           <leafValues>
-            2.1114565432071686e-01 -8.0375924706459045e-02</leafValues></_>
+            2.5094386935234070e-01 -8.0808885395526886e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 720 -4.7730140388011932e-02</internalNodes>
+            0 -1 943 2.4153569247573614e-03</internalNodes>
           <leafValues>
-            -6.6018968820571899e-01 2.6816543191671371e-02</leafValues></_>
+            -7.2777584195137024e-02 2.6076248288154602e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 777 -6.1359764076769352e-03</internalNodes>
+            0 -1 34 -1.3153228908777237e-02</internalNodes>
           <leafValues>
-            2.6270267367362976e-01 -7.4918255209922791e-02</leafValues></_>
+            2.3979008197784424e-01 -7.6283767819404602e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 370 -3.2268161885440350e-03</internalNodes>
+            0 -1 718 -8.5048296023160219e-04</internalNodes>
           <leafValues>
-            -3.3210110664367676e-01 5.3716354072093964e-02</leafValues></_>
+            -3.2108953595161438e-01 5.7150222361087799e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 872 2.7645970694720745e-03</internalNodes>
+            0 -1 511 2.0031477324664593e-03</internalNodes>
           <leafValues>
-            2.4829804897308350e-02 -6.3309198617935181e-01</leafValues></_>
+            -7.5618073344230652e-02 2.3024985194206238e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 460 6.1914063990116119e-03</internalNodes>
+            0 -1 505 -3.9609652012586594e-03</internalNodes>
           <leafValues>
-            -7.9355642199516296e-02 2.0996589958667755e-01</leafValues></_>
+            -4.3856775760650635e-01 3.7756573408842087e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 890 -6.0850339941680431e-03</internalNodes>
+            0 -1 311 5.9846425428986549e-03</internalNodes>
           <leafValues>
-            1.8700407445430756e-01 -9.2255704104900360e-02</leafValues></_>
+            3.5378426313400269e-02 -4.7760033607482910e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 847 3.8954569026827812e-03</internalNodes>
+            0 -1 83 2.0205255597829819e-02</internalNodes>
           <leafValues>
-            -6.2000993639230728e-02 2.9947289824485779e-01</leafValues></_>
+            -8.0130979418754578e-02 2.2919151186943054e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 559 7.9390443861484528e-03</internalNodes>
+            0 -1 927 -2.7492402587085962e-03</internalNodes>
           <leafValues>
-            -4.7935441136360168e-02 3.3055123686790466e-01</leafValues></_>
+            2.1395626664161682e-01 -7.6452419161796570e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 136 -7.4474988505244255e-03</internalNodes>
+            0 -1 506 -8.3101191557943821e-04</internalNodes>
           <leafValues>
-            -2.7902829647064209e-01 5.9020437300205231e-02</leafValues></_></weakClassifiers></_>
-    <!-- stage 11 -->
-    <_>
-      <maxWeakCount>100</maxWeakCount>
-      <stageThreshold>-1.5058170557022095e+00</stageThreshold>
-      <weakClassifiers>
+            1.6961804032325745e-01 -9.9106967449188232e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 764 6.6398456692695618e-03</internalNodes>
+            0 -1 604 -1.8657972104847431e-03</internalNodes>
           <leafValues>
-            1.5219502151012421e-01 7.0482629537582397e-01</leafValues></_>
+            -3.8131290674209595e-01 4.6056091785430908e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 451 -7.4103027582168579e-03</internalNodes>
+            0 -1 74 2.0824437960982323e-03</internalNodes>
           <leafValues>
-            4.4995731115341187e-01 -1.0949239879846573e-01</leafValues></_>
+            6.4966239035129547e-02 -2.3824627697467804e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 509 -1.2679899111390114e-02</internalNodes>
+            0 -1 70 -4.4267112389206886e-03</internalNodes>
           <leafValues>
-            3.1908708810806274e-01 -1.3895240426063538e-01</leafValues></_>
+            -3.5809823870658875e-01 4.6749643981456757e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 221 1.0303283110260963e-02</internalNodes>
+            0 -1 211 1.3552411692216992e-03</internalNodes>
           <leafValues>
-            -1.7546384036540985e-01 2.9695376753807068e-01</leafValues></_>
+            -1.2307690829038620e-01 1.3934792578220367e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 331 -4.7976471483707428e-02</internalNodes>
+            0 -1 213 -4.4114869087934494e-03</internalNodes>
           <leafValues>
-            4.4112482666969299e-01 -1.1231642961502075e-01</leafValues></_>
+            2.6617470383644104e-01 -7.4502207338809967e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 810 3.2145732548087835e-03</internalNodes>
+            0 -1 432 5.2309304010123014e-04</internalNodes>
           <leafValues>
-            -1.8380118906497955e-01 2.3316045105457306e-01</leafValues></_>
+            -1.0876630991697311e-01 1.5687976777553558e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 793 2.4557339493185282e-03</internalNodes>
+            0 -1 976 6.4505764748901129e-04</internalNodes>
           <leafValues>
-            -1.4323309063911438e-01 2.3558256030082703e-01</leafValues></_>
+            -8.0842182040214539e-02 2.0263716578483582e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 595 -5.2055031061172485e-02</internalNodes>
+            0 -1 975 2.0405012182891369e-03</internalNodes>
           <leafValues>
-            -4.4221264123916626e-01 7.0444636046886444e-02</leafValues></_>
+            -6.2390543520450592e-02 3.3067914843559265e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 51 7.7533419243991375e-03</internalNodes>
+            0 -1 888 1.9838459789752960e-02</internalNodes>
           <leafValues>
-            5.6696638464927673e-02 -5.1518803834915161e-01</leafValues></_>
+            2.3488542065024376e-02 -8.1695795059204102e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 534 4.7272985102608800e-04</internalNodes>
+            0 -1 953 2.3998366668820381e-03</internalNodes>
           <leafValues>
-            -1.5081474184989929e-01 1.8353472650051117e-01</leafValues></_>
+            4.1017178446054459e-02 -3.7197592854499817e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 43 -1.7044700682163239e-02</internalNodes>
+            0 -1 664 -1.1092903092503548e-02</internalNodes>
           <leafValues>
-            -4.3840527534484863e-01 6.8837635219097137e-02</leafValues></_>
+            -5.5750596523284912e-01 2.9520254582166672e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 883 -3.5762921907007694e-03</internalNodes>
+            0 -1 981 1.4876715838909149e-02</internalNodes>
           <leafValues>
-            2.4851283431053162e-01 -1.0779865086078644e-01</leafValues></_>
+            -6.5797492861747742e-02 2.5957426428794861e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 839 -2.4369158782064915e-03</internalNodes>
+            0 -1 621 -3.0385032296180725e-02</internalNodes>
           <leafValues>
-            3.0688673257827759e-01 -8.9006565511226654e-02</leafValues></_>
+            2.2640630602836609e-01 -7.6991938054561615e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 933 -3.6047215107828379e-03</internalNodes>
+            0 -1 666 1.2216348201036453e-02</internalNodes>
           <leafValues>
-            2.7542102336883545e-01 -1.0634675621986389e-01</leafValues></_>
+            -7.0106968283653259e-02 2.4013392627239227e-01</leafValues></_></weakClassifiers></_>
+    <!-- stage 15 -->
+    <_>
+      <maxWeakCount>94</maxWeakCount>
+      <stageThreshold>-1.2798616886138916e+00</stageThreshold>
+      <weakClassifiers>
         <_>
           <internalNodes>
-            0 -1 36 -1.1534212157130241e-02</internalNodes>
+            0 -1 801 -3.8322431501001120e-03</internalNodes>
           <leafValues>
-            -5.5281609296798706e-01 4.9770243465900421e-02</leafValues></_>
+            4.8065602779388428e-01 -4.9388073384761810e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 405 2.7643658686429262e-03</internalNodes>
+            0 -1 966 2.5449637323617935e-03</internalNodes>
           <leafValues>
-            2.9803691431879997e-02 -7.3425543308258057e-01</leafValues></_>
+            -1.7564620077610016e-01 2.5865191221237183e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 849 -2.6033269241452217e-03</internalNodes>
+            0 -1 448 -5.4743299260735512e-03</internalNodes>
           <leafValues>
-            -4.4093501567840576e-01 5.0419628620147705e-02</leafValues></_>
+            4.9321442842483521e-01 -7.0596724748611450e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 245 4.8673897981643677e-02</internalNodes>
+            0 -1 294 1.5188493765890598e-02</internalNodes>
           <leafValues>
-            5.8146391063928604e-02 -3.7859597802162170e-01</leafValues></_>
+            -1.8555639684200287e-01 1.5278494358062744e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 898 -4.4065229594707489e-03</internalNodes>
+            0 -1 954 7.5815798481926322e-04</internalNodes>
           <leafValues>
-            -6.9404369592666626e-01 3.1734105199575424e-02</leafValues></_>
+            -1.5043407678604126e-01 1.8612807989120483e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 973 1.6997805796563625e-03</internalNodes>
+            0 -1 963 -3.4232349134981632e-03</internalNodes>
           <leafValues>
-            3.6800261586904526e-02 -5.4090088605880737e-01</leafValues></_>
+            -4.5882478356361389e-01 4.3279532343149185e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 484 1.8069827929139137e-03</internalNodes>
+            0 -1 842 2.4103666655719280e-03</internalNodes>
           <leafValues>
-            -8.9325174689292908e-02 2.5629612803459167e-01</leafValues></_>
+            -8.4217190742492676e-02 2.6687353849411011e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 487 -4.4371248222887516e-03</internalNodes>
+            0 -1 340 -2.3144368082284927e-02</internalNodes>
           <leafValues>
-            2.3971243202686310e-01 -1.0280106216669083e-01</leafValues></_>
+            2.9155749082565308e-01 -9.9449791014194489e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 973 -2.2968063130974770e-03</internalNodes>
+            0 -1 419 -4.2331898584961891e-03</internalNodes>
           <leafValues>
-            -5.8439761400222778e-01 4.1789893060922623e-02</leafValues></_>
+            -3.7696760892868042e-01 8.0511704087257385e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 950 1.4388319104909897e-03</internalNodes>
+            0 -1 282 4.9294121563434601e-03</internalNodes>
           <leafValues>
-            -1.2928913533687592e-01 1.6424950957298279e-01</leafValues></_>
+            -1.3016121089458466e-01 1.8470372259616852e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 685 -6.5411212854087353e-03</internalNodes>
+            0 -1 481 -2.7466980100143701e-05</internalNodes>
           <leafValues>
-            1.7306149005889893e-01 -1.3702909648418427e-01</leafValues></_>
+            1.4074377715587616e-01 -1.7928679287433624e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 414 -9.8783060908317566e-02</internalNodes>
+            0 -1 724 2.2430901881307364e-03</internalNodes>
           <leafValues>
-            4.2455860972404480e-01 -5.3996428847312927e-02</leafValues></_>
+            -1.4674974977970123e-01 1.5197925269603729e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 533 -1.5466672182083130e-01</internalNodes>
+            0 -1 849 7.5493026524782181e-03</internalNodes>
           <leafValues>
-            -4.6163687109947205e-01 5.4335389286279678e-02</leafValues></_>
+            2.4894557893276215e-02 -6.5740859508514404e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 626 -2.3389626294374466e-03</internalNodes>
+            0 -1 245 -3.3066330943256617e-03</internalNodes>
           <leafValues>
-            -6.5777504444122314e-01 2.6686858385801315e-02</leafValues></_>
+            1.8501703441143036e-01 -1.1837758123874664e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 397 5.0454838201403618e-03</internalNodes>
+            0 -1 345 6.9540860131382942e-03</internalNodes>
           <leafValues>
-            4.9083609133958817e-02 -3.7508815526962280e-01</leafValues></_>
+            -7.3770649731159210e-02 2.9017251729965210e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 326 2.5655250996351242e-02</internalNodes>
+            0 -1 790 -8.6210696026682854e-03</internalNodes>
           <leafValues>
-            -5.0410125404596329e-02 4.6358433365821838e-01</leafValues></_>
+            2.0990766584873199e-01 -1.0644201189279556e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 402 2.6888975407928228e-03</internalNodes>
+            0 -1 978 -6.0504255816340446e-04</internalNodes>
           <leafValues>
-            -8.7988443672657013e-02 2.4659486114978790e-01</leafValues></_>
+            2.2373022139072418e-01 -9.6104651689529419e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 455 -3.9576226845383644e-03</internalNodes>
+            0 -1 46 -4.5433510094881058e-03</internalNodes>
           <leafValues>
-            -3.4467720985412598e-01 6.0443773865699768e-02</leafValues></_>
+            -5.4173427820205688e-01 4.7511249780654907e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 396 3.9240214973688126e-03</internalNodes>
+            0 -1 694 -2.2248399909585714e-03</internalNodes>
           <leafValues>
-            -7.2165921330451965e-02 3.6404970288276672e-01</leafValues></_>
+            -4.6854707598686218e-01 3.8701556622982025e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 988 1.3846965739503503e-03</internalNodes>
+            0 -1 10 -5.3389102220535278e-02</internalNodes>
           <leafValues>
-            5.7182963937520981e-02 -3.8552245497703552e-01</leafValues></_>
+            2.9293462634086609e-01 -7.2517670691013336e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 945 -8.4817763417959213e-03</internalNodes>
+            0 -1 13 4.6098522841930389e-02</internalNodes>
           <leafValues>
-            1.8708378076553345e-01 -1.1441195011138916e-01</leafValues></_>
+            -1.0042577981948853e-01 2.3779328167438507e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 944 2.6850812137126923e-03</internalNodes>
+            0 -1 243 7.7845109626650810e-03</internalNodes>
           <leafValues>
-            3.1117379665374756e-02 -6.2151008844375610e-01</leafValues></_>
+            3.7205196917057037e-02 -4.9194374680519104e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 688 1.8728687427937984e-03</internalNodes>
+            0 -1 182 6.0175172984600067e-03</internalNodes>
           <leafValues>
-            2.9517510905861855e-02 -5.8275890350341797e-01</leafValues></_>
+            4.4034618884325027e-02 -4.3780878186225891e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 448 -1.4214152470231056e-03</internalNodes>
+            0 -1 876 4.8966710455715656e-03</internalNodes>
           <leafValues>
-            2.1085265278816223e-01 -8.4942653775215149e-02</leafValues></_>
+            -1.0375351458787918e-01 1.9480220973491669e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 186 -1.4164925087243319e-03</internalNodes>
+            0 -1 494 -3.1284091528505087e-03</internalNodes>
           <leafValues>
-            -5.0255894660949707e-01 3.4562669694423676e-02</leafValues></_>
+            2.3669239878654480e-01 -9.6020378172397614e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 572 2.7755820192396641e-03</internalNodes>
+            0 -1 190 -1.3859109021723270e-03</internalNodes>
           <leafValues>
-            -8.5956700146198273e-02 2.1839313209056854e-01</leafValues></_>
+            2.8487151861190796e-01 -7.2190955281257629e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 517 6.0641965828835964e-03</internalNodes>
+            0 -1 191 2.6260318700224161e-03</internalNodes>
           <leafValues>
-            3.4184314310550690e-02 -5.6067311763763428e-01</leafValues></_>
+            -8.5511997342109680e-02 3.0152606964111328e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 773 -2.9663506429642439e-03</internalNodes>
+            0 -1 65 1.7782470583915710e-01</internalNodes>
           <leafValues>
-            2.6388403773307800e-01 -7.4524797499179840e-02</leafValues></_>
+            -6.4100205898284912e-02 3.3825826644897461e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 986 -1.7851786687970161e-02</internalNodes>
+            0 -1 50 1.7538113519549370e-02</internalNodes>
           <leafValues>
-            -3.5538297891616821e-01 5.5470395833253860e-02</leafValues></_>
+            5.9994459152221680e-02 -3.5529783368110657e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 62 -7.7814348042011261e-03</internalNodes>
+            0 -1 946 -3.2135979272425175e-03</internalNodes>
           <leafValues>
-            2.5654977560043335e-01 -7.7634811401367188e-02</leafValues></_>
+            1.3668337464332581e-01 -1.3979049026966095e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 140 6.2794378027319908e-04</internalNodes>
+            0 -1 461 6.1371903866529465e-03</internalNodes>
           <leafValues>
-            -1.1543263494968414e-01 1.7257589101791382e-01</leafValues></_>
+            -6.2439329922199249e-02 3.0614212155342102e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 845 -2.0482162944972515e-03</internalNodes>
+            0 -1 467 -4.6563488431274891e-03</internalNodes>
           <leafValues>
-            2.0133562386035919e-01 -9.2291958630084991e-02</leafValues></_>
+            -4.3073609471321106e-01 4.9068968743085861e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 852 -2.0528757013380527e-03</internalNodes>
+            0 -1 668 -4.0680947713553905e-03</internalNodes>
           <leafValues>
-            2.4054610729217529e-01 -9.5314949750900269e-02</leafValues></_>
+            -4.6810126304626465e-01 3.7441805005073547e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 894 1.9264804432168603e-03</internalNodes>
+            0 -1 696 1.4199400320649147e-03</internalNodes>
           <leafValues>
-            -8.8165275752544403e-02 2.1321870386600494e-01</leafValues></_>
+            -8.7975829839706421e-02 2.1591611206531525e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 116 1.0841939598321915e-02</internalNodes>
+            0 -1 851 3.5254685208201408e-03</internalNodes>
           <leafValues>
-            3.4955434501171112e-02 -5.3944343328475952e-01</leafValues></_>
+            4.6650484204292297e-02 -4.3687531352043152e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 224 -7.5648901984095573e-03</internalNodes>
+            0 -1 487 1.8623860552906990e-02</internalNodes>
           <leafValues>
-            -7.1435016393661499e-01 2.2735377773642540e-02</leafValues></_>
+            -7.6216101646423340e-02 2.3812168836593628e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 503 -7.4579543434083462e-04</internalNodes>
+            0 -1 314 -2.6926528662443161e-02</internalNodes>
           <leafValues>
-            2.0245671272277832e-01 -9.3201741576194763e-02</leafValues></_>
+            -6.7117422819137573e-01 2.9464269056916237e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 274 -1.2499685399234295e-03</internalNodes>
+            0 -1 632 2.2593191824853420e-03</internalNodes>
           <leafValues>
-            1.4646218717098236e-01 -1.3543428480625153e-01</leafValues></_>
+            2.8521748259663582e-02 -5.4787307977676392e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 270 5.8323808480054140e-04</internalNodes>
+            0 -1 919 1.7519816174171865e-04</internalNodes>
           <leafValues>
-            -9.3358881771564484e-02 2.0619191229343414e-01</leafValues></_>
+            -1.6111046075820923e-01 1.0367503762245178e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 439 1.9810695201158524e-02</internalNodes>
+            0 -1 493 1.0614154860377312e-02</internalNodes>
           <leafValues>
-            2.7015892788767815e-02 -7.5727492570877075e-01</leafValues></_>
+            4.5461904257535934e-02 -3.8087964057922363e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 175 5.9376070275902748e-03</internalNodes>
+            0 -1 20 -4.4702589511871338e-03</internalNodes>
           <leafValues>
-            -1.2178353220224380e-01 1.6173928976058960e-01</leafValues></_>
+            1.4304992556571960e-01 -1.3372300565242767e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 914 1.5689490828663111e-03</internalNodes>
+            0 -1 557 6.2367701902985573e-03</internalNodes>
           <leafValues>
-            3.1975947320461273e-02 -6.0493367910385132e-01</leafValues></_>
+            -7.7783808112144470e-02 2.1545551717281342e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 575 2.5749076157808304e-03</internalNodes>
+            0 -1 76 4.6502514742314816e-03</internalNodes>
           <leafValues>
-            -9.0526103973388672e-02 2.2666496038436890e-01</leafValues></_>
+            4.6132039278745651e-02 -3.7130251526832581e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 90 7.9413484781980515e-03</internalNodes>
+            0 -1 544 -4.3315230868756771e-03</internalNodes>
           <leafValues>
-            5.1273416727781296e-02 -3.9284336566925049e-01</leafValues></_>
+            -4.1549521684646606e-01 3.8484618067741394e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 15 3.2074376940727234e-02</internalNodes>
+            0 -1 764 -1.6567837446928024e-03</internalNodes>
           <leafValues>
-            2.7649452909827232e-02 -6.5098905563354492e-01</leafValues></_>
+            -3.4637498855590820e-01 4.6623144298791885e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 891 -4.8892917111515999e-03</internalNodes>
+            0 -1 415 4.7653233632445335e-03</internalNodes>
           <leafValues>
-            -4.7998306155204773e-01 3.3806797116994858e-02</leafValues></_>
+            -5.0808548927307129e-02 3.4609997272491455e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 475 -5.4039997048676014e-03</internalNodes>
+            0 -1 413 -3.2579647377133369e-03</internalNodes>
           <leafValues>
-            2.8928443789482117e-01 -6.7743733525276184e-02</leafValues></_>
+            2.6948198676109314e-01 -8.5287831723690033e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 531 6.3710450194776058e-03</internalNodes>
+            0 -1 614 2.3307730443775654e-03</internalNodes>
           <leafValues>
-            -9.2935405671596527e-02 1.9695936143398285e-01</leafValues></_>
+            -7.4774339795112610e-02 2.3053503036499023e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 578 -1.8336625071242452e-03</internalNodes>
+            0 -1 176 -2.7928136289119720e-02</internalNodes>
           <leafValues>
-            -3.5492643713951111e-01 5.1711678504943848e-02</leafValues></_>
+            1.9429244101047516e-01 -8.7820984423160553e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 917 2.1252036094665527e-03</internalNodes>
+            0 -1 366 -9.8205050453543663e-03</internalNodes>
           <leafValues>
-            2.0353749394416809e-02 -7.2820025682449341e-01</leafValues></_>
+            -5.9664642810821533e-01 3.1795132905244827e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 233 1.1279534548521042e-02</internalNodes>
+            0 -1 767 4.9811266362667084e-03</internalNodes>
           <leafValues>
-            2.5639204308390617e-02 -5.8714842796325684e-01</leafValues></_>
+            -1.1911241710186005e-01 1.5268225967884064e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 679 -1.1507571488618851e-01</internalNodes>
+            0 -1 508 -2.4869772605597973e-03</internalNodes>
           <leafValues>
-            -7.1453052759170532e-01 2.0069327205419540e-02</leafValues></_>
+            -3.8041505217552185e-01 4.4293139129877090e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 757 -1.9626193679869175e-03</internalNodes>
+            0 -1 780 5.4475376382470131e-03</internalNodes>
           <leafValues>
-            1.6723833978176117e-01 -1.0802425444126129e-01</leafValues></_>
+            -4.6219147741794586e-02 3.9531415700912476e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 756 4.7044735401868820e-03</internalNodes>
+            0 -1 277 -2.1438062191009521e-02</internalNodes>
           <leafValues>
-            -5.0709329545497894e-02 3.6821383237838745e-01</leafValues></_>
+            -5.2191144227981567e-01 3.4259662032127380e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 951 1.8476420082151890e-03</internalNodes>
+            0 -1 566 -4.1901203803718090e-03</internalNodes>
           <leafValues>
-            2.8631281107664108e-02 -6.8395125865936279e-01</leafValues></_>
+            -5.2377271652221680e-01 2.8632357716560364e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 546 -5.4538771510124207e-03</internalNodes>
+            0 -1 262 -4.7237933613359928e-03</internalNodes>
           <leafValues>
-            -6.8269199132919312e-01 2.0947692915797234e-02</leafValues></_>
+            1.8694585561752319e-01 -8.3333678543567657e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 130 -1.0074324905872345e-02</internalNodes>
+            0 -1 845 1.2320578098297119e-03</internalNodes>
           <leafValues>
-            -5.0528079271316528e-01 2.8627410531044006e-02</leafValues></_>
+            -9.6744544804096222e-02 1.8287587165832520e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 207 -3.2069636508822441e-03</internalNodes>
+            0 -1 617 2.0271677523851395e-02</internalNodes>
           <leafValues>
-            1.8038518726825714e-01 -9.3303814530372620e-02</leafValues></_>
+            -6.4628154039382935e-02 2.7641129493713379e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 327 3.5637444816529751e-03</internalNodes>
+            0 -1 375 -1.0729704797267914e-01</internalNodes>
           <leafValues>
-            -6.5284818410873413e-02 3.2510238885879517e-01</leafValues></_>
+            4.3015307188034058e-01 -3.8674801588058472e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 247 2.1060477010905743e-03</internalNodes>
+            0 -1 166 -4.0820333361625671e-01</internalNodes>
           <leafValues>
-            3.0474457889795303e-02 -5.9379291534423828e-01</leafValues></_>
+            5.0520670413970947e-01 -3.0450601130723953e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 568 4.2934687808156013e-03</internalNodes>
+            0 -1 305 4.4355981051921844e-02</internalNodes>
           <leafValues>
-            -7.1521542966365814e-02 2.4279323220252991e-01</leafValues></_>
+            -9.2204704880714417e-02 1.7342080175876617e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 809 8.2498760893940926e-03</internalNodes>
+            0 -1 879 -1.0999260703101754e-03</internalNodes>
           <leafValues>
-            3.7760157138109207e-02 -4.5278856158256531e-01</leafValues></_>
+            2.0996508002281189e-01 -7.7222190797328949e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 606 2.5047136005014181e-03</internalNodes>
+            0 -1 325 -3.2928451895713806e-02</internalNodes>
           <leafValues>
-            -7.9689919948577881e-02 2.0523649454116821e-01</leafValues></_>
+            2.7598264813423157e-01 -6.4115919172763824e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 651 -1.7786353128030896e-03</internalNodes>
+            0 -1 52 2.3981094360351562e-02</internalNodes>
           <leafValues>
-            -6.7214471101760864e-01 2.7108855545520782e-02</leafValues></_>
+            2.5229524821043015e-02 -6.9560426473617554e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 93 5.6851857900619507e-01</internalNodes>
+            0 -1 961 4.1703339666128159e-03</internalNodes>
           <leafValues>
-            -2.9719989746809006e-02 6.2848883867263794e-01</leafValues></_>
+            2.9712976887822151e-02 -4.8132696747779846e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 1 -3.9951098151504993e-03</internalNodes>
+            0 -1 776 -1.4920771354809403e-03</internalNodes>
           <leafValues>
-            1.6902630031108856e-01 -9.6066430211067200e-02</leafValues></_>
+            1.6165184974670410e-01 -9.6420668065547943e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 790 -1.1912260204553604e-02</internalNodes>
+            0 -1 652 1.8172110430896282e-03</internalNodes>
           <leafValues>
-            1.8001109361648560e-01 -1.0152278095483780e-01</leafValues></_>
+            4.2247310280799866e-02 -3.5703054070472717e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 13 -3.2837040722370148e-02</internalNodes>
+            0 -1 739 -2.5937356986105442e-03</internalNodes>
           <leafValues>
-            2.2790163755416870e-01 -7.5773715972900391e-02</leafValues></_>
+            2.2665317356586456e-01 -6.9081544876098633e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 714 -9.5821768045425415e-03</internalNodes>
+            0 -1 706 -2.4995308369398117e-02</internalNodes>
           <leafValues>
-            2.8319683670997620e-01 -6.0501150786876678e-02</leafValues></_>
+            -6.3855916261672974e-01 2.8458235785365105e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 584 -7.0154434069991112e-03</internalNodes>
+            0 -1 909 1.2001263909041882e-02</internalNodes>
           <leafValues>
-            3.7711927294731140e-01 -4.5414235442876816e-02</leafValues></_>
+            1.4999576844274998e-02 -7.8175085783004761e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 598 2.2930791601538658e-03</internalNodes>
+            0 -1 640 2.2153530735522509e-03</internalNodes>
           <leafValues>
-            -9.7957342863082886e-02 1.8666461110115051e-01</leafValues></_>
+            -8.8839285075664520e-02 1.8819671869277954e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 409 3.6181495524942875e-03</internalNodes>
+            0 -1 179 2.7237991162110120e-05</internalNodes>
           <leafValues>
-            -8.5584357380867004e-02 2.1272744238376617e-01</leafValues></_>
+            -1.4949426054954529e-01 9.8739065229892731e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 169 -3.5851418506354094e-03</internalNodes>
+            0 -1 91 -2.6735704392194748e-02</internalNodes>
           <leafValues>
-            -3.2166537642478943e-01 5.0518564879894257e-02</leafValues></_>
+            -4.5522138476371765e-01 3.2516691833734512e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 736 2.0358990877866745e-03</internalNodes>
+            0 -1 644 -2.3417242337018251e-03</internalNodes>
           <leafValues>
-            -9.0195730328559875e-02 1.7850238084793091e-01</leafValues></_>
+            -3.1453001499176025e-01 4.7598775476217270e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 328 3.0855672433972359e-02</internalNodes>
+            0 -1 72 4.7831580042839050e-02</internalNodes>
           <leafValues>
-            7.0852726697921753e-02 -2.3407098650932312e-01</leafValues></_>
+            2.1954061463475227e-02 -6.1162966489791870e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 543 -2.8650071471929550e-03</internalNodes>
+            0 -1 160 -5.7228151708841324e-03</internalNodes>
           <leafValues>
-            2.5149047374725342e-01 -7.0797137916088104e-02</leafValues></_>
+            -6.3381904363632202e-01 2.0299639552831650e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 658 6.9189509376883507e-03</internalNodes>
+            0 -1 163 3.4780064597725868e-03</internalNodes>
           <leafValues>
-            -7.6844424009323120e-02 2.2756692767143250e-01</leafValues></_>
+            3.1021401286125183e-02 -4.2342424392700195e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 831 3.2940365374088287e-02</internalNodes>
+            0 -1 385 -5.4140854626893997e-03</internalNodes>
           <leafValues>
-            -6.0664962977170944e-02 2.7875399589538574e-01</leafValues></_>
+            4.7739461064338684e-01 -3.4031655639410019e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 835 8.9268945157527924e-03</internalNodes>
+            0 -1 383 1.5283382963389158e-03</internalNodes>
           <leafValues>
-            -8.5170723497867584e-02 2.3205895721912384e-01</leafValues></_>
+            -9.6935935318470001e-02 1.9429819285869598e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 645 -7.8886147821322083e-04</internalNodes>
+            0 -1 428 -8.6789112538099289e-03</internalNodes>
           <leafValues>
-            -2.9130771756172180e-01 6.2974251806735992e-02</leafValues></_>
+            2.4826894700527191e-01 -6.0082063078880310e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 71 -5.6759864091873169e-03</internalNodes>
+            0 -1 901 3.0333681497722864e-03</internalNodes>
           <leafValues>
-            -4.1244068741798401e-01 3.6539580672979355e-02</leafValues></_>
+            -7.4087560176849365e-02 2.6165533065795898e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 273 1.2777841184288263e-03</internalNodes>
+            0 -1 684 6.5222466364502907e-03</internalNodes>
           <leafValues>
-            -8.5783556103706360e-02 1.8866100907325745e-01</leafValues></_>
+            3.0176062136888504e-02 -5.5570882558822632e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 887 3.7156887352466583e-02</internalNodes>
+            0 -1 902 5.9719551354646683e-03</internalNodes>
           <leafValues>
-            -1.0894140601158142e-01 1.4975252747535706e-01</leafValues></_>
+            2.3057831451296806e-02 -5.7078248262405396e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 92 -5.7424330711364746e-01</internalNodes>
+            0 -1 155 -1.3977952767163515e-03</internalNodes>
           <leafValues>
-            7.2750979661941528e-01 -2.4812746793031693e-02</leafValues></_>
+            1.5342144668102264e-01 -9.8401337862014771e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 222 -1.3634916394948959e-03</internalNodes>
+            0 -1 897 5.9919534251093864e-03</internalNodes>
           <leafValues>
-            2.2405619919300079e-01 -6.9666981697082520e-02</leafValues></_>
+            -3.9796624332666397e-02 3.5881185531616211e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 814 3.3075414597988129e-02</internalNodes>
+            0 -1 354 2.6286500506103039e-03</internalNodes>
           <leafValues>
-            -5.6832231581211090e-02 3.0118697881698608e-01</leafValues></_></weakClassifiers></_>
-    <!-- stage 12 -->
+            -9.3140766024589539e-02 1.6334943473339081e-01</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 296 -4.4777179136872292e-03</internalNodes>
+          <leafValues>
+            -4.8081240057945251e-01 3.2935630530118942e-02</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 333 5.2724601700901985e-03</internalNodes>
+          <leafValues>
+            3.0787551775574684e-02 -4.5133110880851746e-01</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 1049 -3.2540475949645042e-03</internalNodes>
+          <leafValues>
+            -4.7695344686508179e-01 2.8554188087582588e-02</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 736 1.8083681166172028e-01</internalNodes>
+          <leafValues>
+            2.7366345748305321e-02 -4.9431446194648743e-01</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 431 2.7535988483577967e-03</internalNodes>
+          <leafValues>
+            1.9968675449490547e-02 -6.4471620321273804e-01</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 15 -1.4123708009719849e-02</internalNodes>
+          <leafValues>
+            -5.2748751640319824e-01 2.4596616625785828e-02</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 421 -3.2076485455036163e-02</internalNodes>
+          <leafValues>
+            -7.2171974182128906e-01 1.6940405592322350e-02</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 434 -3.2569766044616699e-02</internalNodes>
+          <leafValues>
+            2.2400286793708801e-01 -6.3403561711311340e-02</leafValues></_></weakClassifiers></_>
+    <!-- stage 16 -->
     <_>
       <maxWeakCount>100</maxWeakCount>
-      <stageThreshold>-1.5318367481231689e+00</stageThreshold>
+      <stageThreshold>-1.2990239858627319e+00</stageThreshold>
       <weakClassifiers>
         <_>
           <internalNodes>
-            0 -1 770 -2.2907990496605635e-03</internalNodes>
+            0 -1 728 1.1235726065933704e-02</internalNodes>
           <leafValues>
-            5.9861046075820923e-01 8.8971912860870361e-02</leafValues></_>
+            -1.2534695863723755e-01 3.9147180318832397e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 256 3.1865492928773165e-03</internalNodes>
+            0 -1 922 5.0947451964020729e-03</internalNodes>
           <leafValues>
-            -1.5604956448078156e-01 3.8612595200538635e-01</leafValues></_>
+            -1.2666413187980652e-01 4.0618515014648438e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 561 -8.0397585406899452e-03</internalNodes>
+            0 -1 891 -1.5323986299335957e-03</internalNodes>
           <leafValues>
-            2.8996115922927856e-01 -1.8175528943538666e-01</leafValues></_>
+            2.8940162062644958e-01 -1.4350101351737976e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 850 4.3595694005489349e-03</internalNodes>
+            0 -1 284 3.7766513414680958e-03</internalNodes>
           <leafValues>
-            -8.0427564680576324e-02 5.0874835252761841e-01</leafValues></_>
+            -1.9189934432506561e-01 1.4756591618061066e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 264 2.8643116354942322e-02</internalNodes>
+            0 -1 514 4.8757870681583881e-03</internalNodes>
           <leafValues>
-            -1.7203453183174133e-01 3.2913634181022644e-01</leafValues></_>
+            -1.2341982126235962e-01 2.3298588395118713e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 896 -3.1282915733754635e-03</internalNodes>
+            0 -1 344 3.1278211623430252e-02</internalNodes>
           <leafValues>
-            3.7550333142280579e-01 -9.1347120702266693e-02</leafValues></_>
+            -7.6286941766738892e-02 3.4027433395385742e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 778 1.4058926608413458e-03</internalNodes>
+            0 -1 63 6.3753505237400532e-03</internalNodes>
           <leafValues>
-            -1.9007267057895660e-01 1.6663856804370880e-01</leafValues></_>
+            7.3992513120174408e-02 -3.2609656453132629e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 230 1.0209476575255394e-02</internalNodes>
+            0 -1 936 -9.8742637783288956e-04</internalNodes>
           <leafValues>
-            -1.2146373838186264e-01 2.3719595372676849e-01</leafValues></_>
+            2.4873960018157959e-01 -9.0153135359287262e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 313 6.0191084630787373e-03</internalNodes>
+            0 -1 217 -3.0144110321998596e-02</internalNodes>
           <leafValues>
-            5.1051452755928040e-02 -5.5820345878601074e-01</leafValues></_>
+            -5.1088541746139526e-01 5.0071869045495987e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 395 -4.7453744336962700e-03</internalNodes>
+            0 -1 268 4.7727730125188828e-03</internalNodes>
           <leafValues>
-            1.6992042958736420e-01 -1.6199907660484314e-01</leafValues></_>
+            5.1353454589843750e-02 -4.1142973303794861e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 771 1.5875545796006918e-03</internalNodes>
+            0 -1 420 6.4554966986179352e-02</internalNodes>
           <leafValues>
-            -1.0143589228391647e-01 2.6255446672439575e-01</leafValues></_>
+            4.5133572071790695e-02 -4.8264691233634949e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 183 -2.7861427515745163e-03</internalNodes>
+            0 -1 744 8.0438675358891487e-03</internalNodes>
           <leafValues>
-            -4.0354993939399719e-01 6.7644119262695312e-02</leafValues></_>
+            -6.3803412020206451e-02 3.0405151844024658e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 56 4.0722191333770752e-03</internalNodes>
+            0 -1 1051 1.0576066561043262e-03</internalNodes>
           <leafValues>
-            4.1441403329372406e-02 -5.5184590816497803e-01</leafValues></_>
+            4.9984093755483627e-02 -3.3949175477027893e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 953 1.0626179864630103e-03</internalNodes>
+            0 -1 938 6.8522170186042786e-03</internalNodes>
           <leafValues>
-            -1.4222721755504608e-01 1.7192882299423218e-01</leafValues></_>
+            3.5091523081064224e-02 -6.7847234010696411e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 280 4.7259610146284103e-03</internalNodes>
+            0 -1 860 -1.7977621406316757e-02</internalNodes>
           <leafValues>
-            5.1823709160089493e-02 -3.9256933331489563e-01</leafValues></_>
+            -3.7503832578659058e-01 4.0370170027017593e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 766 -2.6500346139073372e-03</internalNodes>
+            0 -1 748 -2.9955487698316574e-02</internalNodes>
           <leafValues>
-            -3.5642188787460327e-01 6.6784784197807312e-02</leafValues></_>
+            -4.2023807764053345e-01 4.2222321033477783e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 375 3.9345081895589828e-03</internalNodes>
+            0 -1 14 2.0934976637363434e-02</internalNodes>
           <leafValues>
-            -6.1840496957302094e-02 3.9278426766395569e-01</leafValues></_>
+            4.3809924274682999e-02 -4.1159108281135559e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 334 8.9293124619871378e-04</internalNodes>
+            0 -1 499 -1.0348223149776459e-03</internalNodes>
           <leafValues>
-            -1.0518563538789749e-01 2.3271512985229492e-01</leafValues></_>
+            1.7594149708747864e-01 -1.0171056538820267e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 381 5.7920545339584351e-02</internalNodes>
+            0 -1 15 1.1026043444871902e-02</internalNodes>
           <leafValues>
-            -6.8776324391365051e-02 3.3801963925361633e-01</leafValues></_>
+            3.7518307566642761e-02 -4.9795153737068176e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 529 -6.6577367484569550e-02</internalNodes>
+            0 -1 201 4.1434396989643574e-03</internalNodes>
           <leafValues>
-            4.2277967929840088e-01 -6.3239939510822296e-02</leafValues></_>
+            -7.7400334179401398e-02 2.3505100607872009e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 184 -5.5271089076995850e-03</internalNodes>
+            0 -1 423 -1.4838734641671181e-03</internalNodes>
           <leafValues>
-            -4.1861197352409363e-01 6.0344558209180832e-02</leafValues></_>
+            2.9909220337867737e-01 -9.2648021876811981e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 355 3.3537389244884253e-03</internalNodes>
+            0 -1 1025 4.0641101077198982e-03</internalNodes>
           <leafValues>
-            -1.5910768508911133e-01 1.7853063344955444e-01</leafValues></_>
+            3.8187902420759201e-02 -5.9566622972488403e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 427 -2.3959013633430004e-03</internalNodes>
+            0 -1 108 -2.6055248454213142e-03</internalNodes>
           <leafValues>
-            2.5072932243347168e-01 -8.5364922881126404e-02</leafValues></_>
+            1.4647382497787476e-01 -1.1769902706146240e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 244 -2.1867034956812859e-03</internalNodes>
+            0 -1 834 -1.8873009830713272e-02</internalNodes>
           <leafValues>
-            -5.6374865770339966e-01 3.5474341362714767e-02</leafValues></_>
+            2.0791313052177429e-01 -9.1127894818782806e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 602 2.4597872979938984e-03</internalNodes>
+            0 -1 960 1.0428125038743019e-02</internalNodes>
           <leafValues>
-            3.1019955873489380e-02 -5.5415368080139160e-01</leafValues></_>
+            4.3083548545837402e-02 -4.1407048702239990e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 577 -2.9149088077247143e-03</internalNodes>
+            0 -1 460 1.9560819491744041e-03</internalNodes>
           <leafValues>
-            -4.6299308538436890e-01 3.7638399749994278e-02</leafValues></_>
+            -6.5898597240447998e-02 2.6488196849822998e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 905 -1.5585927758365870e-03</internalNodes>
+            0 -1 402 6.1143590137362480e-03</internalNodes>
           <leafValues>
-            1.4355151355266571e-01 -1.3060651719570160e-01</leafValues></_>
+            4.7718580812215805e-02 -4.3339842557907104e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 70 -3.1853761523962021e-02</internalNodes>
+            0 -1 411 3.9817169308662415e-03</internalNodes>
           <leafValues>
-            -4.6954944729804993e-01 3.7520393729209900e-02</leafValues></_>
+            2.8663935139775276e-02 -5.4472506046295166e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 472 -5.1449546590447426e-03</internalNodes>
+            0 -1 497 -9.0858177281916142e-04</internalNodes>
           <leafValues>
-            2.7591976523399353e-01 -6.6930308938026428e-02</leafValues></_>
+            1.2656490504741669e-01 -1.3804104924201965e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 55 -1.7139092087745667e-03</internalNodes>
+            0 -1 548 -5.1833119243383408e-02</internalNodes>
           <leafValues>
-            -3.8028663396835327e-01 4.9521040171384811e-02</leafValues></_>
+            2.9838389158248901e-01 -6.4876683056354523e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 98 -1.0931883752346039e-01</internalNodes>
+            0 -1 550 -6.1461031436920166e-02</internalNodes>
           <leafValues>
-            -4.1068795323371887e-01 4.0003888309001923e-02</leafValues></_>
+            2.2751982510089874e-01 -7.7075794339179993e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 158 -2.5099035352468491e-02</internalNodes>
+            0 -1 771 -3.8890805444680154e-04</internalNodes>
           <leafValues>
-            4.3478006124496460e-01 -5.5282033979892731e-02</leafValues></_>
+            1.4823918044567108e-01 -1.2443733215332031e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 435 8.1472359597682953e-03</internalNodes>
+            0 -1 819 6.3632195815443993e-03</internalNodes>
           <leafValues>
-            -4.5095365494489670e-02 3.9842218160629272e-01</leafValues></_>
+            3.3928975462913513e-02 -5.5825293064117432e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 765 -1.9677784293889999e-03</internalNodes>
+            0 -1 929 2.3877150379121304e-03</internalNodes>
           <leafValues>
-            1.8696348369121552e-01 -1.1214685440063477e-01</leafValues></_>
+            -6.0555700212717056e-02 2.9875907301902771e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 656 -2.6076552458107471e-03</internalNodes>
+            0 -1 718 2.1584378555417061e-03</internalNodes>
           <leafValues>
-            2.2791831195354462e-01 -8.7665997445583344e-02</leafValues></_>
+            2.6707226410508156e-02 -6.5327596664428711e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 490 -4.1761510074138641e-03</internalNodes>
+            0 -1 972 1.3073299778625369e-03</internalNodes>
           <leafValues>
-            -6.8348854780197144e-01 2.8925698250532150e-02</leafValues></_>
+            -6.5057143568992615e-02 2.8509995341300964e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 774 1.3159511610865593e-02</internalNodes>
+            0 -1 1023 2.7173646230949089e-05</internalNodes>
           <leafValues>
-            2.1792927756905556e-02 -7.0727092027664185e-01</leafValues></_>
+            -1.4736446738243103e-01 1.1435943096876144e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 548 -5.1895831711590290e-03</internalNodes>
+            0 -1 630 2.5558518245816231e-03</internalNodes>
           <leafValues>
-            -6.6959971189498901e-01 2.1171124652028084e-02</leafValues></_>
+            2.2957315668463707e-02 -6.1825275421142578e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 323 -1.5662111341953278e-02</internalNodes>
+            0 -1 435 4.4789682142436504e-03</internalNodes>
           <leafValues>
-            -3.6895245313644409e-01 4.1785925626754761e-02</leafValues></_>
+            3.6877695471048355e-02 -4.1827708482742310e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 0 -2.4020818527787924e-03</internalNodes>
+            0 -1 335 -4.0298998355865479e-02</internalNodes>
           <leafValues>
-            1.7773237824440002e-01 -1.0461435467004776e-01</leafValues></_>
+            -6.8164646625518799e-01 2.1755648776888847e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 631 1.9489541649818420e-02</internalNodes>
+            0 -1 782 -3.2729938626289368e-02</internalNodes>
           <leafValues>
-            3.1142184510827065e-02 -5.4499447345733643e-01</leafValues></_>
+            -5.4164266586303711e-01 2.6013873517513275e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 143 4.9672335386276245e-01</internalNodes>
+            0 -1 1011 -1.6982981469482183e-03</internalNodes>
           <leafValues>
-            -2.4833207949995995e-02 7.6724356412887573e-01</leafValues></_>
+            3.5175332427024841e-01 -4.7216285020112991e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 403 3.2806373201310635e-03</internalNodes>
+            0 -1 331 3.6859638057649136e-03</internalNodes>
           <leafValues>
-            -6.8504363298416138e-02 2.2050221264362335e-01</leafValues></_>
+            4.9838334321975708e-02 -3.0565607547760010e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 638 2.1590515971183777e-03</internalNodes>
+            0 -1 235 1.8905990291386843e-03</internalNodes>
           <leafValues>
-            2.5587400421500206e-02 -6.2128585577011108e-01</leafValues></_>
+            2.3341298103332520e-02 -6.6700172424316406e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 604 5.2638887427747250e-04</internalNodes>
+            0 -1 714 4.9954187124967575e-03</internalNodes>
           <leafValues>
-            -9.3414209783077240e-02 1.7369781434535980e-01</leafValues></_>
+            2.5513354688882828e-02 -5.4635345935821533e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 510 -2.1490573417395353e-03</internalNodes>
+            0 -1 336 -5.5998284369707108e-03</internalNodes>
           <leafValues>
-            -4.4394543766975403e-01 3.9975218474864960e-02</leafValues></_>
+            2.9532432556152344e-01 -5.9350244700908661e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 605 1.9845911301672459e-03</internalNodes>
+            0 -1 1008 -1.0907559189945459e-03</internalNodes>
           <leafValues>
-            -8.5414819419384003e-02 2.0132684707641602e-01</leafValues></_>
+            1.8265166878700256e-01 -9.8137028515338898e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 565 -3.2773464918136597e-03</internalNodes>
+            0 -1 975 -7.4323470471426845e-04</internalNodes>
           <leafValues>
-            2.4408425390720367e-01 -7.3116399347782135e-02</leafValues></_>
+            1.9020494818687439e-01 -8.7386451661586761e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 523 2.1245577372610569e-03</internalNodes>
+            0 -1 914 2.7787161525338888e-03</internalNodes>
           <leafValues>
-            2.9403384774923325e-02 -5.7607394456863403e-01</leafValues></_>
+            3.2241951674222946e-02 -4.8055323958396912e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 286 1.4500851975753903e-03</internalNodes>
+            0 -1 153 2.4344769772142172e-03</internalNodes>
           <leafValues>
-            -6.6218085587024689e-02 2.4264883995056152e-01</leafValues></_>
+            4.6477138996124268e-02 -2.9923307895660400e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 939 -4.5542549341917038e-03</internalNodes>
+            0 -1 293 2.8132982552051544e-03</internalNodes>
           <leafValues>
-            -5.8058720827102661e-01 2.8668973594903946e-02</leafValues></_>
+            -9.0026579797267914e-02 1.6738441586494446e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 343 4.7045715153217316e-02</internalNodes>
+            0 -1 73 3.2191604375839233e-02</internalNodes>
           <leafValues>
-            3.6376014351844788e-02 -4.1573047637939453e-01</leafValues></_>
+            -6.3697919249534607e-02 2.8380525112152100e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 349 7.7028926461935043e-03</internalNodes>
+            0 -1 656 -1.8642821814864874e-03</internalNodes>
           <leafValues>
-            -7.7403679490089417e-02 2.1597269177436829e-01</leafValues></_>
+            2.0616722106933594e-01 -7.4722714722156525e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 53 -4.1527286171913147e-02</internalNodes>
+            0 -1 657 4.0091956034302711e-03</internalNodes>
           <leafValues>
-            -3.4835410118103027e-01 4.8530772328376770e-02</leafValues></_>
+            -7.1015752851963043e-02 2.5589218735694885e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 748 -9.1361545491963625e-04</internalNodes>
+            0 -1 150 -5.1108514890074730e-03</internalNodes>
           <leafValues>
-            1.8357329070568085e-01 -9.0061083436012268e-02</leafValues></_>
+            -4.8940917849540710e-01 3.4555420279502869e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 674 -5.0414498895406723e-02</internalNodes>
+            0 -1 600 -1.9523575901985168e-02</internalNodes>
           <leafValues>
-            2.5009948015213013e-01 -6.4314760267734528e-02</leafValues></_>
+            3.1921747326850891e-01 -5.1439035683870316e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 398 7.4737053364515305e-03</internalNodes>
+            0 -1 298 -1.4431261457502842e-02</internalNodes>
           <leafValues>
-            -5.7431813329458237e-02 2.8318390250205994e-01</leafValues></_>
+            1.4213174581527710e-01 -1.1113181710243225e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 654 2.3173280060291290e-03</internalNodes>
+            0 -1 732 4.5302580110728741e-04</internalNodes>
           <leafValues>
-            3.7970397621393204e-02 -5.6861978769302368e-01</leafValues></_>
+            -1.0926237702369690e-01 1.4363190531730652e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 874 4.5855477219447494e-04</internalNodes>
+            0 -1 78 -5.4108840413391590e-03</internalNodes>
           <leafValues>
-            -1.3554716110229492e-01 1.1426483094692230e-01</leafValues></_>
+            -4.6926099061965942e-01 3.1095381826162338e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 103 1.8236173782497644e-03</internalNodes>
+            0 -1 259 1.6963672824203968e-03</internalNodes>
           <leafValues>
-            2.6509260758757591e-02 -5.5975830554962158e-01</leafValues></_>
+            -6.7337587475776672e-02 2.2115154564380646e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 732 -1.3565555214881897e-02</internalNodes>
+            0 -1 190 1.8719944637268782e-03</internalNodes>
           <leafValues>
-            3.5292169451713562e-01 -4.7534435987472534e-02</leafValues></_>
+            -5.8433420956134796e-02 2.7830049395561218e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 285 -1.2756066862493753e-03</internalNodes>
+            0 -1 1014 -8.3780642598867416e-03</internalNodes>
           <leafValues>
-            2.5920400023460388e-01 -5.7072717696428299e-02</leafValues></_>
+            -4.6290600299835205e-01 3.3701810985803604e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 746 6.7418040707707405e-03</internalNodes>
+            0 -1 510 1.0720299184322357e-01</internalNodes>
           <leafValues>
-            3.2604463398456573e-02 -4.5861816406250000e-01</leafValues></_>
+            2.6600774377584457e-02 -5.0957643985748291e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 827 6.5548229031264782e-04</internalNodes>
+            0 -1 670 -1.5523867914453149e-03</internalNodes>
           <leafValues>
-            -8.4788605570793152e-02 1.8131427466869354e-01</leafValues></_>
+            -5.7974040508270264e-01 2.2188233211636543e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 929 2.1027602255344391e-02</internalNodes>
+            0 -1 649 -1.0537400841712952e-02</internalNodes>
           <leafValues>
-            -6.9927647709846497e-02 2.4611653387546539e-01</leafValues></_>
+            -4.3835061788558960e-01 2.9434528201818466e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 695 1.8613610416650772e-02</internalNodes>
+            0 -1 1038 3.1337797641754150e-02</internalNodes>
           <leafValues>
-            -3.6128688603639603e-02 4.4170859456062317e-01</leafValues></_>
+            2.0445786416530609e-02 -6.3010692596435547e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 99 -4.9805632233619690e-01</internalNodes>
+            0 -1 1004 -5.1124744117259979e-02</internalNodes>
           <leafValues>
-            5.9478044509887695e-01 -2.6719097048044205e-02</leafValues></_>
+            -6.7282766103744507e-01 1.8230145797133446e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 620 -3.2723334152251482e-03</internalNodes>
+            0 -1 362 -6.0091790510341525e-04</internalNodes>
           <leafValues>
-            2.2165246307849884e-01 -6.8788610398769379e-02</leafValues></_>
+            2.0237097144126892e-01 -7.2557553648948669e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 583 -3.5375617444515228e-03</internalNodes>
+            0 -1 409 1.6933252336457372e-03</internalNodes>
           <leafValues>
-            -6.1987191438674927e-01 2.6597078889608383e-02</leafValues></_>
+            -5.9000160545110703e-02 2.4010565876960754e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 632 3.9524696767330170e-03</internalNodes>
+            0 -1 18 5.7134744711220264e-03</internalNodes>
           <leafValues>
-            -7.5478851795196533e-02 2.1777774393558502e-01</leafValues></_>
+            2.9386352747678757e-02 -5.1309728622436523e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 681 -9.3436334282159805e-03</internalNodes>
+            0 -1 429 -9.6922749653458595e-03</internalNodes>
           <leafValues>
-            -8.0256491899490356e-01 2.2864339873194695e-02</leafValues></_>
+            -5.4907989501953125e-01 2.3704739287495613e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 671 -1.0151248425245285e-03</internalNodes>
+            0 -1 308 -1.2504560872912407e-02</internalNodes>
           <leafValues>
-            -3.1884235143661499e-01 4.3938383460044861e-02</leafValues></_>
+            -6.1863696575164795e-01 1.9876839593052864e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 516 -7.0278989151120186e-03</internalNodes>
+            0 -1 382 -9.1812955215573311e-03</internalNodes>
           <leafValues>
-            1.4721503853797913e-01 -1.1400235444307327e-01</leafValues></_>
+            -4.7697570919990540e-01 2.5203671306371689e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 611 -9.1165518388152122e-03</internalNodes>
+            0 -1 570 2.8069302439689636e-02</internalNodes>
           <leafValues>
-            2.6830977201461792e-01 -6.4460486173629761e-02</leafValues></_>
+            -5.5565606802701950e-02 2.5318285822868347e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 35 3.3993504941463470e-02</internalNodes>
+            0 -1 573 4.6324366703629494e-03</internalNodes>
           <leafValues>
-            2.7748649939894676e-02 -5.5171352624893188e-01</leafValues></_>
+            2.5273589417338371e-02 -5.9603255987167358e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 557 -2.6347138918936253e-03</internalNodes>
+            0 -1 784 2.9409723356366158e-03</internalNodes>
           <leafValues>
-            1.7853704094886780e-01 -8.4178321063518524e-02</leafValues></_>
+            -5.1576137542724609e-02 2.9322555661201477e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 712 -1.3291095383465290e-03</internalNodes>
+            0 -1 159 -1.6009721904993057e-02</internalNodes>
           <leafValues>
-            -2.8526228666305542e-01 5.6452732533216476e-02</leafValues></_>
+            2.9389014840126038e-01 -4.7874812036752701e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 719 1.2167419772595167e-03</internalNodes>
+            0 -1 355 -2.0468614995479584e-02</internalNodes>
           <leafValues>
-            -7.7132880687713623e-02 1.9538262486457825e-01</leafValues></_>
+            1.4383009076118469e-01 -1.0160042345523834e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 856 1.9806078635156155e-03</internalNodes>
+            0 -1 868 2.3338340222835541e-02</internalNodes>
           <leafValues>
-            2.6976436376571655e-02 -5.4301941394805908e-01</leafValues></_>
+            -5.7301126420497894e-02 2.9121819138526917e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 617 5.0783145707100630e-04</internalNodes>
+            0 -1 921 -2.1875634789466858e-02</internalNodes>
           <leafValues>
-            -9.5295064151287079e-02 1.5398529171943665e-01</leafValues></_>
+            -6.4106851816177368e-01 2.4203805252909660e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 440 -5.0868269056081772e-02</internalNodes>
+            0 -1 427 1.1228370480239391e-02</internalNodes>
           <leafValues>
-            -6.3152486085891724e-01 2.3585954681038857e-02</leafValues></_>
+            -5.2143514156341553e-02 2.8465506434440613e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 503 -1.4806092949584126e-03</internalNodes>
+            0 -1 197 -4.3659657239913940e-03</internalNodes>
           <leafValues>
-            2.6132494211196899e-01 -6.3322558999061584e-02</leafValues></_>
+            -6.0558545589447021e-01 2.5440702214837074e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 28 -1.8584117293357849e-02</internalNodes>
+            0 -1 824 1.1577639961615205e-03</internalNodes>
           <leafValues>
-            1.6097819805145264e-01 -1.1777820438146591e-01</leafValues></_>
+            -8.9793093502521515e-02 1.6500258445739746e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 250 2.7171591296792030e-02</internalNodes>
+            0 -1 781 1.1090341955423355e-02</internalNodes>
           <leafValues>
-            -8.3719044923782349e-02 1.9814659655094147e-01</leafValues></_>
+            2.4472476914525032e-02 -6.1380225419998169e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 390 -6.8197408691048622e-03</internalNodes>
+            0 -1 1015 4.7660744749009609e-03</internalNodes>
           <leafValues>
-            -5.4431658983230591e-01 2.8722483664751053e-02</leafValues></_>
+            4.1726417839527130e-02 -3.2548862695693970e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 696 -9.1905370354652405e-03</internalNodes>
+            0 -1 864 2.4865168597898446e-05</internalNodes>
           <leafValues>
-            1.5037034451961517e-01 -1.0166583955287933e-01</leafValues></_>
+            -1.2436556816101074e-01 1.1702288687229156e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 192 -9.7952038049697876e-04</internalNodes>
+            0 -1 823 -7.6379198580980301e-03</internalNodes>
           <leafValues>
-            -2.9014238715171814e-01 4.9301091581583023e-02</leafValues></_>
+            -4.9008071422576904e-01 2.9381709173321724e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 884 -2.1513784304261208e-03</internalNodes>
+            0 -1 445 -3.2750256359577179e-03</internalNodes>
           <leafValues>
-            2.4622270464897156e-01 -6.0794923454523087e-02</leafValues></_>
+            1.7950019240379333e-01 -8.0592408776283264e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 881 -2.0869732834398746e-03</internalNodes>
+            0 -1 448 1.3944536913186312e-03</internalNodes>
           <leafValues>
-            2.0386496186256409e-01 -8.8516488671302795e-02</leafValues></_>
+            -8.0001771450042725e-02 2.2785140573978424e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 42 -1.2946429662406445e-02</internalNodes>
+            0 -1 444 1.9776031840592623e-03</internalNodes>
           <leafValues>
-            -5.2757191658020020e-01 2.9759777709841728e-02</leafValues></_>
+            3.4109916538000107e-02 -4.8504865169525146e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 985 -3.5145760048180819e-03</internalNodes>
+            0 -1 39 -3.9329148828983307e-02</internalNodes>
           <leafValues>
-            -4.7929930686950684e-01 2.8995612636208534e-02</leafValues></_>
+            -6.8790251016616821e-01 1.7370922490954399e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 212 2.4212854914367199e-03</internalNodes>
+            0 -1 645 -2.8447234071791172e-03</internalNodes>
           <leafValues>
-            -6.4840331673622131e-02 2.4126507341861725e-01</leafValues></_>
+            2.3028372228145599e-01 -6.6618286073207855e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 199 2.1736249327659607e-03</internalNodes>
+            0 -1 232 3.2375190407037735e-02</internalNodes>
           <leafValues>
-            2.2003039717674255e-02 -7.0873755216598511e-01</leafValues></_>
+            -7.5743824243545532e-02 1.7864570021629333e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 365 -3.5567809827625751e-03</internalNodes>
+            0 -1 5 5.1314428448677063e-02</internalNodes>
           <leafValues>
-            2.9770645499229431e-01 -5.5486857891082764e-02</leafValues></_>
+            -5.3142681717872620e-02 2.8643575310707092e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 249 -1.9639974460005760e-02</internalNodes>
+            0 -1 79 4.6999715268611908e-03</internalNodes>
           <leafValues>
-            -7.8722274303436279e-01 2.1807981655001640e-02</leafValues></_>
+            3.5749543458223343e-02 -4.0437424182891846e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 653 8.1145912408828735e-03</internalNodes>
+            0 -1 173 -2.0850417204201221e-03</internalNodes>
           <leafValues>
-            2.0471598953008652e-02 -5.9867942333221436e-01</leafValues></_>
+            -3.0815458297729492e-01 4.2763352394104004e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 706 1.2241180054843426e-02</internalNodes>
+            0 -1 455 -9.1223767958581448e-04</internalNodes>
           <leafValues>
-            1.6892330721020699e-02 -7.4894833564758301e-01</leafValues></_>
+            2.1245715022087097e-01 -6.7729450762271881e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 794 3.2565161585807800e-02</internalNodes>
+            0 -1 690 -2.2479293693322688e-04</internalNodes>
           <leafValues>
-            1.8086636438965797e-02 -6.3382810354232788e-01</leafValues></_>
+            1.3159312307834625e-01 -1.0141336172819138e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 498 1.2451345100998878e-02</internalNodes>
+            0 -1 974 3.1234124675393105e-02</internalNodes>
           <leafValues>
-            -6.6715493798255920e-02 2.1516454219818115e-01</leafValues></_>
+            -8.9100256562232971e-02 1.5734429657459259e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 284 -2.9989825561642647e-02</internalNodes>
+            0 -1 465 -1.5079543227329850e-03</internalNodes>
           <leafValues>
-            2.0229698717594147e-01 -6.8314045667648315e-02</leafValues></_></weakClassifiers></_>
-    <!-- stage 13 -->
+            3.2412421703338623e-01 -4.4387526810169220e-02</leafValues></_></weakClassifiers></_>
+    <!-- stage 17 -->
     <_>
       <maxWeakCount>100</maxWeakCount>
-      <stageThreshold>-1.6178516149520874e+00</stageThreshold>
+      <stageThreshold>-1.2500010728836060e+00</stageThreshold>
       <weakClassifiers>
         <_>
           <internalNodes>
-            0 -1 499 -3.4503117203712463e-03</internalNodes>
+            0 -1 803 -5.5631361901760101e-03</internalNodes>
           <leafValues>
-            6.1788332462310791e-01 1.1437324434518814e-01</leafValues></_>
+            4.5343571901321411e-01 -5.2330773323774338e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 876 4.8226695507764816e-03</internalNodes>
+            0 -1 426 4.1911248117685318e-03</internalNodes>
           <leafValues>
-            -1.0551112145185471e-01 4.8962607979774475e-01</leafValues></_>
+            -1.2266161292791367e-01 3.6830583214759827e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 772 5.1433052867650986e-03</internalNodes>
+            0 -1 424 -1.8559540621936321e-03</internalNodes>
           <leafValues>
-            -1.1823723465204239e-01 4.1509538888931274e-01</leafValues></_>
+            2.4044598639011383e-01 -1.5207393467426300e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 786 1.8649311736226082e-02</internalNodes>
+            0 -1 532 -1.1846812441945076e-02</internalNodes>
           <leafValues>
-            -1.4054079353809357e-01 4.4154295325279236e-01</leafValues></_>
+            2.7016878128051758e-01 -1.1934488266706467e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 133 -2.9543964192271233e-03</internalNodes>
+            0 -1 180 1.0401019826531410e-03</internalNodes>
           <leafValues>
-            2.5874784588813782e-01 -1.4265626668930054e-01</leafValues></_>
+            -2.3527304828166962e-01 9.5964968204498291e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 851 3.1133145093917847e-03</internalNodes>
+            0 -1 462 9.3873767182230949e-03</internalNodes>
           <leafValues>
-            -8.1695765256881714e-02 3.6735343933105469e-01</leafValues></_>
+            -5.6923847645521164e-02 4.2236638069152832e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 49 -3.0071800574660301e-03</internalNodes>
+            0 -1 13 9.0843521058559418e-02</internalNodes>
           <leafValues>
-            -3.8455182313919067e-01 7.1067951619625092e-02</leafValues></_>
+            -6.3625380396842957e-02 3.8295668363571167e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 219 -1.9453115761280060e-02</internalNodes>
+            0 -1 439 -1.6221515834331512e-03</internalNodes>
           <leafValues>
-            2.1075683832168579e-01 -1.2884819507598877e-01</leafValues></_>
+            1.8148291110992432e-01 -1.3424767553806305e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 462 -4.8584998585283756e-03</internalNodes>
+            0 -1 875 -1.8008962273597717e-02</internalNodes>
           <leafValues>
-            1.6113398969173431e-01 -1.7580857872962952e-01</leafValues></_>
+            2.7346464991569519e-01 -7.6283894479274750e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 474 8.2634367048740387e-02</internalNodes>
+            0 -1 278 8.6509017273783684e-03</internalNodes>
           <leafValues>
-            -5.9177018702030182e-02 4.0204021334648132e-01</leafValues></_>
+            5.8148156851530075e-02 -5.2620184421539307e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 340 4.5589236542582512e-03</internalNodes>
+            0 -1 726 2.8817038983106613e-03</internalNodes>
           <leafValues>
-            -1.5169224143028259e-01 2.1497711539268494e-01</leafValues></_>
+            2.6940831914544106e-02 -4.7911167144775391e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 810 5.7522351853549480e-03</internalNodes>
+            0 -1 263 -6.1017833650112152e-03</internalNodes>
           <leafValues>
-            -1.0400034487247467e-01 2.3692265152931213e-01</leafValues></_>
+            1.7878855764865875e-01 -1.2378337979316711e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 30 1.0916464030742645e-02</internalNodes>
+            0 -1 403 -5.9294269885867834e-04</internalNodes>
           <leafValues>
-            3.2482013106346130e-02 -6.6799944639205933e-01</leafValues></_>
+            -2.7179723978042603e-01 8.0951526761054993e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 334 1.2513624969869852e-03</internalNodes>
+            0 -1 996 3.1696190126240253e-04</internalNodes>
           <leafValues>
-            -9.2966683208942413e-02 2.5203207135200500e-01</leafValues></_>
+            -1.7311862111091614e-01 1.0296358913183212e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 24 8.5552372038364410e-03</internalNodes>
+            0 -1 519 6.6280784085392952e-03</internalNodes>
           <leafValues>
-            4.2838018387556076e-02 -5.4950177669525146e-01</leafValues></_>
+            -5.8870136737823486e-02 2.9477587342262268e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 365 1.9793706014752388e-03</internalNodes>
+            0 -1 916 -4.5112203806638718e-03</internalNodes>
           <leafValues>
-            -1.0328737646341324e-01 2.2137698531150818e-01</leafValues></_>
+            -5.9672296047210693e-01 2.7053238824009895e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 308 -2.3129612207412720e-02</internalNodes>
+            0 -1 679 -4.3381296098232269e-02</internalNodes>
           <leafValues>
-            -5.9918802976608276e-01 3.7120997905731201e-02</leafValues></_>
+            -4.2040801048278809e-01 4.0890187025070190e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 347 -2.5169795844703913e-03</internalNodes>
+            0 -1 813 2.0323593635112047e-03</internalNodes>
           <leafValues>
-            -4.0429180860519409e-01 4.7458905726671219e-02</leafValues></_>
+            5.5178079754114151e-02 -3.0439695715904236e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 290 -2.7680140919983387e-03</internalNodes>
+            0 -1 973 1.8127080984413624e-03</internalNodes>
           <leafValues>
-            -4.1959136724472046e-01 4.7375876456499100e-02</leafValues></_>
+            -8.2048252224922180e-02 2.1907366812229156e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 394 4.4881463982164860e-03</internalNodes>
+            0 -1 359 -6.6424394026398659e-03</internalNodes>
           <leafValues>
-            -5.3955338895320892e-02 4.0468615293502808e-01</leafValues></_>
+            -4.7840338945388794e-01 4.4878169894218445e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 648 1.1571742361411452e-03</internalNodes>
+            0 -1 903 -8.5755460895597935e-04</internalNodes>
           <leafValues>
-            6.1304513365030289e-02 -3.6215540766716003e-01</leafValues></_>
+            1.3301849365234375e-01 -1.2699788808822632e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 731 3.6775614134967327e-03</internalNodes>
+            0 -1 904 3.4769098274409771e-03</internalNodes>
           <leafValues>
-            3.5641182214021683e-02 -5.1911950111389160e-01</leafValues></_>
+            -7.1578972041606903e-02 2.5448271632194519e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 828 2.4001342244446278e-03</internalNodes>
+            0 -1 950 -1.8520625308156013e-03</internalNodes>
           <leafValues>
-            -8.0022528767585754e-02 2.6706510782241821e-01</leafValues></_>
+            1.5127970278263092e-01 -1.2349219620227814e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 823 -1.4416232006624341e-03</internalNodes>
+            0 -1 777 5.4582338780164719e-03</internalNodes>
           <leafValues>
-            2.5601235032081604e-01 -8.7470635771751404e-02</leafValues></_>
+            3.5001352429389954e-02 -4.8021456599235535e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 382 5.0148535519838333e-03</internalNodes>
+            0 -1 894 -6.4206691458821297e-03</internalNodes>
           <leafValues>
-            5.7711403816938400e-02 -3.5666841268539429e-01</leafValues></_>
+            -5.6509351730346680e-01 2.6883032172918320e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 399 2.9201959259808064e-03</internalNodes>
+            0 -1 895 8.2498416304588318e-03</internalNodes>
           <leafValues>
-            -7.3214575648307800e-02 2.7563962340354919e-01</leafValues></_>
+            4.3442543596029282e-02 -3.7965279817581177e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 741 -2.8012858820147812e-05</internalNodes>
+            0 -1 825 3.0813394114375114e-03</internalNodes>
           <leafValues>
-            1.3044390082359314e-01 -1.5220497548580170e-01</leafValues></_>
+            -5.6544844061136246e-02 3.2101437449455261e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 962 2.6261559687554836e-03</internalNodes>
+            0 -1 865 2.8121876530349255e-03</internalNodes>
           <leafValues>
-            6.3371658325195312e-02 -2.9989096522331238e-01</leafValues></_>
+            -7.1444042026996613e-02 2.8035575151443481e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 114 -1.9985539838671684e-02</internalNodes>
+            0 -1 418 -1.1791236698627472e-02</internalNodes>
           <leafValues>
-            -7.0204716920852661e-01 2.5756308808922768e-02</leafValues></_>
+            2.0067863166332245e-01 -1.0047248005867004e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 277 4.0448461659252644e-03</internalNodes>
+            0 -1 476 1.4931729529052973e-03</internalNodes>
           <leafValues>
-            -9.9051415920257568e-02 2.0554924011230469e-01</leafValues></_>
+            -6.6428750753402710e-02 2.6187655329704285e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 294 7.6400241814553738e-03</internalNodes>
+            0 -1 364 -2.8772680088877678e-03</internalNodes>
           <leafValues>
-            4.8610400408506393e-02 -4.0662041306495667e-01</leafValues></_>
+            -4.5838123559951782e-01 4.2477916926145554e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 252 1.5262419357895851e-02</internalNodes>
+            0 -1 592 -4.5857336372137070e-03</internalNodes>
           <leafValues>
-            -9.2194251716136932e-02 2.0623819530010223e-01</leafValues></_>
+            1.2718579173088074e-01 -1.3642288744449615e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 752 -6.1596641317009926e-03</internalNodes>
+            0 -1 585 -1.3770985417068005e-02</internalNodes>
           <leafValues>
-            -5.0260418653488159e-01 3.7245232611894608e-02</leafValues></_>
+            -6.4000308513641357e-01 2.7297915890812874e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 785 -2.5804866105318069e-02</internalNodes>
+            0 -1 746 -3.6472730338573456e-02</internalNodes>
           <leafValues>
-            -5.2190864086151123e-01 3.0063979327678680e-02</leafValues></_>
+            -5.1465278863906860e-01 3.1265191733837128e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 368 -4.6107484959065914e-03</internalNodes>
+            0 -1 378 1.0626764036715031e-02</internalNodes>
           <leafValues>
-            -4.2041480541229248e-01 3.7473026663064957e-02</leafValues></_>
+            2.4199636653065681e-02 -6.3441967964172363e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 936 -1.6811741515994072e-03</internalNodes>
+            0 -1 509 -3.6817211657762527e-03</internalNodes>
           <leafValues>
-            3.3520191907882690e-01 -5.3664822131395340e-02</leafValues></_>
+            -4.4575414061546326e-01 3.1119547784328461e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 936 1.0210975306108594e-03</internalNodes>
+            0 -1 856 -3.4752404317259789e-03</internalNodes>
           <leafValues>
-            -7.0165649056434631e-02 2.7230393886566162e-01</leafValues></_>
+            1.4008119702339172e-01 -1.0539831966161728e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 519 -2.7257478795945644e-03</internalNodes>
+            0 -1 815 -4.7973562031984329e-03</internalNodes>
           <leafValues>
-            -3.7600108981132507e-01 4.8897936940193176e-02</leafValues></_>
+            2.8762820363044739e-01 -6.0662355273962021e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 645 1.7022072570398450e-03</internalNodes>
+            0 -1 773 6.4153699204325676e-03</internalNodes>
           <leafValues>
-            3.2578211277723312e-02 -4.8195156455039978e-01</leafValues></_>
+            -1.1230263859033585e-01 1.4087037742137909e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 237 2.0580790005624294e-03</internalNodes>
+            0 -1 814 -1.0156400967389345e-03</internalNodes>
           <leafValues>
-            -1.1316970735788345e-01 1.4754198491573334e-01</leafValues></_>
+            -3.3441004157066345e-01 4.3477565050125122e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 520 1.9031974952667952e-03</internalNodes>
+            0 -1 968 3.3057793043553829e-03</internalNodes>
           <leafValues>
-            6.1289772391319275e-02 -2.7776253223419189e-01</leafValues></_>
+            1.9609324634075165e-02 -7.0060092210769653e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 65 -4.5437026768922806e-02</internalNodes>
+            0 -1 100 -5.3275022655725479e-03</internalNodes>
           <leafValues>
-            2.8187385201454163e-01 -6.1310045421123505e-02</leafValues></_>
+            2.4580952525138855e-01 -6.0118518769741058e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 10 -2.0433391630649567e-01</internalNodes>
+            0 -1 469 1.5886269975453615e-03</internalNodes>
           <leafValues>
-            -4.8491853475570679e-01 3.7197910249233246e-02</leafValues></_>
+            -7.7446170151233673e-02 1.9878011941909790e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 902 -2.2007026709616184e-03</internalNodes>
+            0 -1 520 4.7287968918681145e-03</internalNodes>
           <leafValues>
-            -4.8433649539947510e-01 2.8523173183202744e-02</leafValues></_>
+            3.0098341405391693e-02 -5.0950014591217041e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 506 2.4706670083105564e-03</internalNodes>
+            0 -1 741 -1.9788878853432834e-04</internalNodes>
           <leafValues>
-            -8.0774910748004913e-02 2.0636586844921112e-01</leafValues></_>
+            1.5142950415611267e-01 -9.6688762307167053e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 337 -1.1496900115162134e-03</internalNodes>
+            0 -1 389 -4.9208370037376881e-03</internalNodes>
           <leafValues>
-            2.0466096699237823e-01 -7.8325189650058746e-02</leafValues></_>
+            -4.5343187451362610e-01 3.7627156823873520e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 390 -4.3232389725744724e-03</internalNodes>
+            0 -1 361 4.5094583183526993e-02</internalNodes>
           <leafValues>
-            -3.4593367576599121e-01 4.9537312239408493e-02</leafValues></_>
+            -8.5510566830635071e-02 1.7849470674991608e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 112 -9.3772150576114655e-03</internalNodes>
+            0 -1 944 1.4799998607486486e-03</internalNodes>
           <leafValues>
-            -5.5802655220031738e-01 2.5828598067164421e-02</leafValues></_>
+            -6.4638271927833557e-02 2.3496921360492706e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 755 -1.6863006167113781e-03</internalNodes>
+            0 -1 517 1.0061380267143250e-01</internalNodes>
           <leafValues>
-            1.9700750708580017e-01 -8.0926463007926941e-02</leafValues></_>
+            -3.0139762908220291e-02 4.9012109637260437e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 759 5.5908015929162502e-03</internalNodes>
+            0 -1 688 -5.2844230085611343e-03</internalNodes>
           <leafValues>
-            -5.8355998247861862e-02 3.0854061245918274e-01</leafValues></_>
+            1.7104546725749969e-01 -8.7710574269294739e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 483 -4.9319159006699920e-04</internalNodes>
+            0 -1 626 -8.3214940968900919e-04</internalNodes>
           <leafValues>
-            1.3386693596839905e-01 -1.1287388950586319e-01</leafValues></_>
+            -2.6654696464538574e-01 5.3875535726547241e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 551 -5.3560961037874222e-02</internalNodes>
+            0 -1 190 -8.8889291509985924e-04</internalNodes>
           <leafValues>
-            3.3912947773933411e-01 -4.4598836451768875e-02</leafValues></_>
+            1.8824113905429840e-01 -8.0119885504245758e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 542 -2.4220649152994156e-02</internalNodes>
+            0 -1 191 2.2177316714078188e-03</internalNodes>
           <leafValues>
-            -4.5232787728309631e-01 4.1364260017871857e-02</leafValues></_>
+            -6.9703146815299988e-02 2.0391084253787994e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 798 1.2709838338196278e-03</internalNodes>
+            0 -1 674 -1.1522162239998579e-03</internalNodes>
           <leafValues>
-            -8.8080756366252899e-02 1.8180713057518005e-01</leafValues></_>
+            -3.6508113145828247e-01 3.9048090577125549e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 236 -4.4361655600368977e-03</internalNodes>
+            0 -1 1036 -1.0836161673069000e-02</internalNodes>
           <leafValues>
-            -4.2694598436355591e-01 3.6063931882381439e-02</leafValues></_>
+            -5.8106678724288940e-01 2.1713526919484138e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 791 -6.5719988197088242e-04</internalNodes>
+            0 -1 82 -1.6731536388397217e-01</internalNodes>
           <leafValues>
-            1.8804629147052765e-01 -8.5146181285381317e-02</leafValues></_>
+            -4.7344669699668884e-01 2.6662701740860939e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 715 1.8579278141260147e-02</internalNodes>
+            0 -1 515 -9.5267388969659805e-03</internalNodes>
           <leafValues>
-            4.4604945927858353e-02 -3.7216106057167053e-01</leafValues></_>
+            2.7732986211776733e-01 -5.6512769311666489e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 857 3.0188630335032940e-03</internalNodes>
+            0 -1 329 6.6450019367039204e-03</internalNodes>
           <leafValues>
-            -9.7823068499565125e-02 1.5584464371204376e-01</leafValues></_>
+            2.9381312429904938e-02 -5.3565382957458496e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 868 1.6309421043843031e-03</internalNodes>
+            0 -1 104 -2.1554589271545410e-02</internalNodes>
           <leafValues>
-            3.5910408943891525e-02 -4.3541318178176880e-01</leafValues></_>
+            -6.2839144468307495e-01 1.8782904371619225e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 139 1.3791467994451523e-02</internalNodes>
+            0 -1 892 1.4288825332187116e-04</internalNodes>
           <leafValues>
-            1.7177715897560120e-02 -7.7653616666793823e-01</leafValues></_>
+            -1.2763719260692596e-01 1.0616952925920486e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 248 1.0393885895609856e-03</internalNodes>
+            0 -1 319 1.8068919889628887e-03</internalNodes>
           <leafValues>
-            -1.2292464822530746e-01 1.1997509002685547e-01</leafValues></_>
+            4.2757544666528702e-02 -3.2102146744728088e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 417 -1.8992213299497962e-03</internalNodes>
+            0 -1 979 1.2280542869120836e-03</internalNodes>
           <leafValues>
-            -5.8449220657348633e-01 2.3935828357934952e-02</leafValues></_>
+            -5.7478122413158417e-02 2.5948432087898254e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 366 -4.4655447709374130e-04</internalNodes>
+            0 -1 89 2.6250675320625305e-02</internalNodes>
           <leafValues>
-            1.8246568739414215e-01 -8.1576324999332428e-02</leafValues></_>
+            -9.5928788185119629e-02 1.4502045512199402e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 85 1.1696915607899427e-03</internalNodes>
+            0 -1 336 1.8192850984632969e-03</internalNodes>
           <leafValues>
-            4.1298836469650269e-02 -3.7100258469581604e-01</leafValues></_>
+            -6.8028703331947327e-02 2.3167446255683899e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 906 -8.9874223340302706e-04</internalNodes>
+            0 -1 44 -4.8545510508120060e-03</internalNodes>
           <leafValues>
-            1.3932932913303375e-01 -1.0641934722661972e-01</leafValues></_>
+            -4.3374514579772949e-01 3.6196250468492508e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 862 5.9534879401326180e-03</internalNodes>
+            0 -1 762 2.8766903560608625e-03</internalNodes>
           <leafValues>
-            2.6781413704156876e-02 -6.1212611198425293e-01</leafValues></_>
+            3.8431353867053986e-02 -3.3900904655456543e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 861 -8.0954860895872116e-03</internalNodes>
+            0 -1 793 4.4511677697300911e-03</internalNodes>
           <leafValues>
-            2.6603493094444275e-01 -5.9750139713287354e-02</leafValues></_>
+            -4.8704307526350021e-02 2.9764902591705322e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 287 -8.2374701742082834e-04</internalNodes>
+            0 -1 545 -9.9098179489374161e-03</internalNodes>
           <leafValues>
-            2.1638387441635132e-01 -6.4249947667121887e-02</leafValues></_>
+            2.5863200426101685e-01 -5.7418409734964371e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 271 -7.6250307029113173e-04</internalNodes>
+            0 -1 2 -2.6503708213567734e-03</internalNodes>
           <leafValues>
-            2.0882584154605865e-01 -8.5345618426799774e-02</leafValues></_>
+            1.3571591675281525e-01 -1.1608450859785080e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 959 2.3917213547974825e-03</internalNodes>
+            0 -1 1 -3.0543167144060135e-02</internalNodes>
           <leafValues>
-            2.9081748798489571e-02 -5.5320137739181519e-01</leafValues></_>
+            2.8910955786705017e-01 -5.1689133048057556e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 957 -5.6062731891870499e-03</internalNodes>
+            0 -1 698 -2.6757145300507545e-02</internalNodes>
           <leafValues>
-            -3.1231331825256348e-01 4.6577330678701401e-02</leafValues></_>
+            1.8446540832519531e-01 -7.7666454017162323e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 807 1.2068089097738266e-02</internalNodes>
+            0 -1 131 -2.2985447198152542e-02</internalNodes>
           <leafValues>
-            -6.9983117282390594e-02 2.1360129117965698e-01</leafValues></_>
+            -3.5471677780151367e-01 4.1345477104187012e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 664 -6.1361752450466156e-03</internalNodes>
+            0 -1 536 9.5467511564493179e-03</internalNodes>
           <leafValues>
-            1.5866123139858246e-01 -8.9951172471046448e-02</leafValues></_>
+            -5.5719308555126190e-02 2.4589607119560242e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 686 2.7342736721038818e-03</internalNodes>
+            0 -1 730 2.6181992143392563e-03</internalNodes>
           <leafValues>
-            4.6424146741628647e-02 -3.2302507758140564e-01</leafValues></_>
+            -1.0256808251142502e-01 1.3319683074951172e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 190 2.5015277788043022e-02</internalNodes>
+            0 -1 1031 -3.5491142421960831e-02</internalNodes>
           <leafValues>
-            -9.2339992523193359e-02 1.6995115578174591e-01</leafValues></_>
+            -5.9519535303115845e-01 2.2935084998607635e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 6 3.6676183342933655e-02</internalNodes>
+            0 -1 703 1.5474080573767424e-03</internalNodes>
           <leafValues>
-            -8.1868082284927368e-02 2.0542381703853607e-01</leafValues></_>
+            -8.4649838507175446e-02 1.6198579967021942e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 641 2.9560746625065804e-03</internalNodes>
+            0 -1 861 -3.4878745209425688e-03</internalNodes>
           <leafValues>
-            4.2714115232229233e-02 -3.9473703503608704e-01</leafValues></_>
+            -5.0121647119522095e-01 2.6359066367149353e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 478 -5.4626376368105412e-04</internalNodes>
+            0 -1 601 3.6612942349165678e-03</internalNodes>
           <leafValues>
-            1.7010760307312012e-01 -9.1078221797943115e-02</leafValues></_>
+            -7.2178244590759277e-02 1.8415448069572449e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 479 3.5485455300658941e-03</internalNodes>
+            0 -1 692 -2.1762652322649956e-03</internalNodes>
           <leafValues>
-            -7.2080396115779877e-02 2.2900597751140594e-01</leafValues></_>
+            2.1102276444435120e-01 -6.4692504703998566e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 485 -3.1973507720977068e-03</internalNodes>
+            0 -1 66 -6.9864131510257721e-03</internalNodes>
           <leafValues>
-            2.0531810820102692e-01 -8.5912480950355530e-02</leafValues></_>
+            -4.3104550242424011e-01 3.3448409289121628e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 867 -2.5095739401876926e-03</internalNodes>
+            0 -1 64 4.7067347913980484e-03</internalNodes>
           <leafValues>
-            -3.3782237768173218e-01 5.3629480302333832e-02</leafValues></_>
+            4.7681909054517746e-02 -3.1132212281227112e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 312 1.2365024536848068e-02</internalNodes>
+            0 -1 1054 -7.0012239739298820e-03</internalNodes>
           <leafValues>
-            2.7145428583025932e-02 -5.5763113498687744e-01</leafValues></_>
+            -3.4665238857269287e-01 3.6263268440961838e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 910 2.0736612379550934e-02</internalNodes>
+            0 -1 36 1.0144514963030815e-02</internalNodes>
           <leafValues>
-            -6.0063906013965607e-02 2.5700190663337708e-01</leafValues></_>
+            3.3140499144792557e-02 -3.7149414420127869e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 15 2.6504596695303917e-02</internalNodes>
+            0 -1 927 2.5893552228808403e-03</internalNodes>
           <leafValues>
-            3.4878112375736237e-02 -4.7980275750160217e-01</leafValues></_>
+            -5.6186988949775696e-02 2.3859155178070068e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 976 -9.5798689872026443e-03</internalNodes>
+            0 -1 877 -3.8091647438704967e-03</internalNodes>
           <leafValues>
-            -6.1055964231491089e-01 2.1064205095171928e-02</leafValues></_>
+            1.8803173303604126e-01 -9.0667806565761566e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 615 1.9744917750358582e-02</internalNodes>
+            0 -1 559 -2.5004068017005920e-01</internalNodes>
           <leafValues>
-            -4.9393177032470703e-02 3.0676594376564026e-01</leafValues></_>
+            -5.7437247037887573e-01 2.3015361279249191e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 865 3.0523580498993397e-03</internalNodes>
+            0 -1 651 -8.5459719412028790e-04</internalNodes>
           <leafValues>
-            4.1798073798418045e-02 -3.5442468523979187e-01</leafValues></_>
+            -3.0019384622573853e-01 4.1898671537637711e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 612 -4.3955976143479347e-03</internalNodes>
+            0 -1 556 -1.5604835003614426e-02</internalNodes>
           <leafValues>
-            2.5482681393623352e-01 -5.6209251284599304e-02</leafValues></_>
+            -5.8520871400833130e-01 2.1410541608929634e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 469 2.2425290662795305e-03</internalNodes>
+            0 -1 654 -1.9794562458992004e-01</internalNodes>
           <leafValues>
-            -9.7824580967426300e-02 1.7274166643619537e-01</leafValues></_>
+            -6.7963910102844238e-01 1.6488522291183472e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 541 7.1967259049415588e-02</internalNodes>
+            0 -1 896 -1.9824346527457237e-03</internalNodes>
           <leafValues>
-            -3.9488561451435089e-02 3.6034339666366577e-01</leafValues></_>
+            1.4493939280509949e-01 -8.7999224662780762e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 181 8.4581580013036728e-03</internalNodes>
+            0 -1 582 -2.1158650517463684e-02</internalNodes>
           <leafValues>
-            3.5755772143602371e-02 -4.4762039184570312e-01</leafValues></_>
+            -6.4664304256439209e-01 2.4590896442532539e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 665 3.3080112189054489e-03</internalNodes>
+            0 -1 837 -9.3553803162649274e-04</internalNodes>
           <leafValues>
-            2.2785754874348640e-02 -5.3823727369308472e-01</leafValues></_>
+            1.8229192495346069e-01 -7.2682343423366547e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 437 -1.1890231398865581e-03</internalNodes>
+            0 -1 610 -1.1120189446955919e-03</internalNodes>
           <leafValues>
-            1.7143265902996063e-01 -8.1015840172767639e-02</leafValues></_>
+            1.5188181400299072e-01 -8.6225852370262146e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 434 -1.7523975111544132e-03</internalNodes>
+            0 -1 316 1.1543033272027969e-01</internalNodes>
           <leafValues>
-            2.5996673107147217e-01 -6.9269210100173950e-02</leafValues></_>
+            -4.7091111540794373e-02 3.5574361681938171e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 921 5.4229743545874953e-04</internalNodes>
+            0 -1 568 -5.2959467284381390e-03</internalNodes>
           <leafValues>
-            -7.4078343808650970e-02 2.0903676748275757e-01</leafValues></_>
+            2.0496748387813568e-01 -6.1289250850677490e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 963 3.9791758172214031e-03</internalNodes>
+            0 -1 310 -2.6194794103503227e-02</internalNodes>
           <leafValues>
-            4.0985044091939926e-02 -3.6837655305862427e-01</leafValues></_>
+            1.7320305109024048e-01 -1.1094193905591965e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 829 -6.9316523149609566e-03</internalNodes>
+            0 -1 167 1.4183738268911839e-02</internalNodes>
           <leafValues>
-            -4.1581609845161438e-01 3.2475329935550690e-02</leafValues></_>
+            -9.7011148929595947e-02 1.4372280240058899e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 17 4.1018679738044739e-02</internalNodes>
+            0 -1 1032 -3.6340979859232903e-03</internalNodes>
           <leafValues>
-            -6.6409081220626831e-02 2.3296032845973969e-01</leafValues></_>
+            -4.0951785445213318e-01 3.0991807579994202e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 86 3.3051387872546911e-03</internalNodes>
+            0 -1 1028 1.4448106288909912e-02</internalNodes>
           <leafValues>
-            -8.2739837467670441e-02 1.9939082860946655e-01</leafValues></_>
+            -6.1627220362424850e-02 2.0916682481765747e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 179 -1.3641032390296459e-02</internalNodes>
+            0 -1 982 -1.1399465613067150e-02</internalNodes>
           <leafValues>
-            1.6623613238334656e-01 -8.6717613041400909e-02</leafValues></_></weakClassifiers></_>
-    <!-- stage 14 -->
+            1.8926219642162323e-01 -8.7004892528057098e-02</leafValues></_></weakClassifiers></_>
+    <!-- stage 18 -->
     <_>
       <maxWeakCount>100</maxWeakCount>
-      <stageThreshold>-1.6119387149810791e+00</stageThreshold>
+      <stageThreshold>-1.2953979969024658e+00</stageThreshold>
       <weakClassifiers>
         <_>
           <internalNodes>
-            0 -1 508 -1.0795817710459232e-02</internalNodes>
+            0 -1 725 1.6048721969127655e-02</internalNodes>
           <leafValues>
-            5.7589554786682129e-01 9.1795757412910461e-02</leafValues></_>
+            -9.5187164843082428e-02 3.7635341286659241e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 844 -1.4518407406285405e-03</internalNodes>
+            0 -1 239 4.1785854846239090e-03</internalNodes>
           <leafValues>
-            3.8668358325958252e-01 -1.4567533135414124e-01</leafValues></_>
+            -1.4184002578258514e-01 3.1887301802635193e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 205 1.2619893066585064e-02</internalNodes>
+            0 -1 526 -6.7659835331141949e-03</internalNodes>
           <leafValues>
-            -1.3285328447818756e-01 3.8423144817352295e-01</leafValues></_>
+            3.7005490064620972e-01 -8.9318118989467621e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 812 -8.6567001417279243e-03</internalNodes>
+            0 -1 186 1.4478694647550583e-02</internalNodes>
           <leafValues>
-            2.0455244183540344e-01 -1.9482232630252838e-01</leafValues></_>
+            -1.3418816030025482e-01 2.8370034694671631e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 329 8.7269591167569160e-03</internalNodes>
+            0 -1 411 -1.8653089646250010e-03</internalNodes>
           <leafValues>
-            -9.0128563344478607e-02 4.0668380260467529e-01</leafValues></_>
+            -3.5015934705734253e-01 6.9187328219413757e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 846 -4.8108389601111412e-03</internalNodes>
+            0 -1 901 3.7634610198438168e-03</internalNodes>
           <leafValues>
-            4.0858918428421021e-01 -7.6686508953571320e-02</leafValues></_>
+            -7.7612839639186859e-02 3.0384179949760437e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 441 2.7277414119453169e-05</internalNodes>
+            0 -1 353 8.9913085103034973e-03</internalNodes>
           <leafValues>
-            -2.1661256253719330e-01 1.3865883648395538e-01</leafValues></_>
+            6.0584690421819687e-02 -4.7271341085433960e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 426 -9.6549151930958033e-04</internalNodes>
+            0 -1 121 -3.0867164023220539e-03</internalNodes>
           <leafValues>
-            1.9036890566349030e-01 -1.3512735068798065e-01</leafValues></_>
+            1.6870087385177612e-01 -1.3231597840785980e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 215 -1.1629101354628801e-03</internalNodes>
+            0 -1 388 -4.0246914140880108e-03</internalNodes>
           <leafValues>
-            2.7597144246101379e-01 -8.5875771939754486e-02</leafValues></_>
+            -4.1840493679046631e-01 6.4627721905708313e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 708 3.2347193919122219e-03</internalNodes>
+            0 -1 896 4.8679644241929054e-03</internalNodes>
           <leafValues>
-            -1.4792887866497040e-01 1.6230462491512299e-01</leafValues></_>
+            -5.6233335286378860e-02 4.2156839370727539e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 344 -6.0261571779847145e-03</internalNodes>
+            0 -1 480 5.5472417734563351e-03</internalNodes>
           <leafValues>
-            -5.2146345376968384e-01 3.9669245481491089e-02</leafValues></_>
+            3.7891130894422531e-02 -5.1408857107162476e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 502 3.7499368190765381e-03</internalNodes>
+            0 -1 1003 6.5884483046829700e-04</internalNodes>
           <leafValues>
-            4.7719169408082962e-02 -4.2560356855392456e-01</leafValues></_>
+            -1.6457377374172211e-01 1.1204792559146881e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 432 -2.2638911381363869e-02</internalNodes>
+            0 -1 1050 -1.0980388615280390e-03</internalNodes>
           <leafValues>
-            2.7776387333869934e-01 -8.2894414663314819e-02</leafValues></_>
+            -3.3544427156448364e-01 4.6025454998016357e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 375 2.8850757516920567e-03</internalNodes>
+            0 -1 583 -2.8328509069979191e-03</internalNodes>
           <leafValues>
-            -7.3187254369258881e-02 3.4045669436454773e-01</leafValues></_>
+            2.3426958918571472e-01 -7.2758100926876068e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 743 9.2617822811007500e-03</internalNodes>
+            0 -1 56 1.5504788607358932e-03</internalNodes>
           <leafValues>
-            -6.1159532517194748e-02 3.4422287344932556e-01</leafValues></_>
+            6.2664858996868134e-02 -2.5632002949714661e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 419 4.7564059495925903e-03</internalNodes>
+            0 -1 348 -6.2153179896995425e-04</internalNodes>
           <leafValues>
-            4.2927626520395279e-02 -5.0712525844573975e-01</leafValues></_>
+            1.7485393583774567e-01 -9.9982917308807373e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 588 1.0375332832336426e-01</internalNodes>
+            0 -1 675 -1.4540781266987324e-02</internalNodes>
           <leafValues>
-            3.7820540368556976e-02 -5.4858410358428955e-01</leafValues></_>
+            -4.4969236850738525e-01 3.7324137985706329e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 527 -1.1948650702834129e-02</internalNodes>
+            0 -1 792 -1.6624422278255224e-03</internalNodes>
           <leafValues>
-            3.0298843979835510e-01 -7.0214085280895233e-02</leafValues></_>
+            1.4047256112098694e-01 -1.1892398446798325e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 346 1.7851736396551132e-02</internalNodes>
+            0 -1 893 1.6246617306023836e-03</internalNodes>
           <leafValues>
-            -8.9291095733642578e-02 2.2659333050251007e-01</leafValues></_>
+            6.1172962188720703e-02 -2.7449882030487061e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 928 1.7700281459838152e-03</internalNodes>
+            0 -1 87 -1.1364535987377167e-01</internalNodes>
           <leafValues>
-            -9.0894356369972229e-02 2.3938187956809998e-01</leafValues></_>
+            -4.3175131082534790e-01 3.8861453533172607e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 42 1.0000608861446381e-02</internalNodes>
+            0 -1 29 6.3355863094329834e-03</internalNodes>
           <leafValues>
-            5.4091196507215500e-02 -4.5715424418449402e-01</leafValues></_>
+            4.3615639209747314e-02 -3.7530297040939331e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 554 5.1841903477907181e-03</internalNodes>
+            0 -1 88 -7.9950205981731415e-03</internalNodes>
           <leafValues>
-            4.4081535190343857e-02 -4.0113139152526855e-01</leafValues></_>
+            -5.6157833337783813e-01 2.7148496359586716e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 216 1.9869320094585419e-03</internalNodes>
+            0 -1 825 -6.0972268693149090e-03</internalNodes>
           <leafValues>
-            -8.6456976830959320e-02 2.3278492689132690e-01</leafValues></_>
+            4.7499263286590576e-01 -3.5678520798683167e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 29 7.3318472132086754e-03</internalNodes>
+            0 -1 933 1.3845593202859163e-03</internalNodes>
           <leafValues>
-            4.4677142053842545e-02 -4.3628835678100586e-01</leafValues></_>
+            -1.1575383692979813e-01 1.3405258953571320e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 224 5.3855171427130699e-03</internalNodes>
+            0 -1 351 8.5432223975658417e-02</internalNodes>
           <leafValues>
-            3.1241770833730698e-02 -5.7641702890396118e-01</leafValues></_>
+            -5.6930482387542725e-02 3.1373351812362671e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 287 -5.8841239660978317e-04</internalNodes>
+            0 -1 661 -1.2029780447483063e-01</internalNodes>
           <leafValues>
-            2.1748071908950806e-01 -9.8720036447048187e-02</leafValues></_>
+            -4.7989824414253235e-01 3.8594469428062439e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 48 -4.6296482905745506e-03</internalNodes>
+            0 -1 829 -8.3766942843794823e-03</internalNodes>
           <leafValues>
-            -5.0439667701721191e-01 3.9307218044996262e-02</leafValues></_>
+            -2.0806340873241425e-01 7.6934777200222015e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 159 1.0425396263599396e-02</internalNodes>
+            0 -1 673 -4.6590538695454597e-03</internalNodes>
           <leafValues>
-            -6.9303810596466064e-02 2.8114342689514160e-01</leafValues></_>
+            -5.0349289178848267e-01 3.0419014394283295e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 821 3.4709304571151733e-02</internalNodes>
+            0 -1 453 -3.2761119306087494e-02</internalNodes>
           <leafValues>
-            -4.4065892696380615e-02 4.7260922193527222e-01</leafValues></_>
+            3.2354715466499329e-01 -5.6276485323905945e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 913 -1.9787646830081940e-02</internalNodes>
+            0 -1 783 8.3009023219347000e-03</internalNodes>
           <leafValues>
-            -6.3054060935974121e-01 3.7138473242521286e-02</leafValues></_>
+            -8.3831317722797394e-02 2.3335608839988708e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 832 -1.0857213288545609e-02</internalNodes>
+            0 -1 848 5.7156109251081944e-03</internalNodes>
           <leafValues>
-            -3.4433662891387939e-01 4.5778658241033554e-02</leafValues></_>
+            -8.6484365165233612e-02 1.8363620340824127e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 228 -3.3750114962458611e-03</internalNodes>
+            0 -1 518 -1.0080671310424805e-01</internalNodes>
           <leafValues>
-            -4.4760662317276001e-01 3.7368919700384140e-02</leafValues></_>
+            3.8774350285530090e-01 -4.0828518569469452e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 799 7.1516213938593864e-04</internalNodes>
+            0 -1 14 -2.5552421808242798e-02</internalNodes>
           <leafValues>
-            -1.4026457071304321e-01 1.2475384026765823e-01</leafValues></_>
+            -5.0166463851928711e-01 3.8269419223070145e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 694 -3.0070471111685038e-03</internalNodes>
+            0 -1 23 -6.1748407781124115e-02</internalNodes>
           <leafValues>
-            -5.2588617801666260e-01 3.0897416174411774e-02</leafValues></_>
+            -3.5811841487884521e-01 4.6544160693883896e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 634 -3.0869825277477503e-03</internalNodes>
+            0 -1 702 -1.2269845232367516e-02</internalNodes>
           <leafValues>
-            2.8596574068069458e-01 -6.7343741655349731e-02</leafValues></_>
+            2.0786920189857483e-01 -7.8518457710742950e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 358 -4.3112646788358688e-02</internalNodes>
+            0 -1 11 2.8048269450664520e-02</internalNodes>
           <leafValues>
-            -7.0135027170181274e-01 2.6632267981767654e-02</leafValues></_>
+            -5.6248739361763000e-02 2.8977242112159729e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 672 -1.2020026333630085e-03</internalNodes>
+            0 -1 523 -7.2269486263394356e-03</internalNodes>
           <leafValues>
-            -3.8874247670173645e-01 4.1288472712039948e-02</leafValues></_>
+            -7.2842431068420410e-01 2.3379294201731682e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 716 -3.8164458237588406e-04</internalNodes>
+            0 -1 952 4.7771912068128586e-03</internalNodes>
           <leafValues>
-            1.3130629062652588e-01 -1.3220198452472687e-01</leafValues></_>
+            2.3226773366332054e-02 -5.6412339210510254e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 412 -4.4994866475462914e-03</internalNodes>
+            0 -1 276 2.8181755915284157e-03</internalNodes>
           <leafValues>
-            -2.8277575969696045e-01 6.8065464496612549e-02</leafValues></_>
+            -3.3893339335918427e-02 4.3989458680152893e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 586 -4.2400006204843521e-03</internalNodes>
+            0 -1 194 -8.4437360055744648e-04</internalNodes>
           <leafValues>
-            -5.7234168052673340e-01 2.4768881499767303e-02</leafValues></_>
+            1.9623728096485138e-01 -7.8485630452632904e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 610 3.3328742720186710e-03</internalNodes>
+            0 -1 407 -4.3037505820393562e-03</internalNodes>
           <leafValues>
-            -6.9700233638286591e-02 2.3259970545768738e-01</leafValues></_>
+            -3.6311796307563782e-01 4.0526941418647766e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 26 -1.4152936637401581e-02</internalNodes>
+            0 -1 105 4.9789976328611374e-03</internalNodes>
           <leafValues>
-            -6.5485191345214844e-01 2.5028359144926071e-02</leafValues></_>
+            4.8658054322004318e-02 -3.1162264943122864e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 331 -3.3239413052797318e-02</internalNodes>
+            0 -1 1041 -5.0353109836578369e-03</internalNodes>
           <leafValues>
-            2.1122130751609802e-01 -8.0384172499179840e-02</leafValues></_>
+            -5.5396872758865356e-01 2.3420164361596107e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 40 3.9529884234070778e-03</internalNodes>
+            0 -1 837 -1.3716940302401781e-03</internalNodes>
           <leafValues>
-            -7.4974447488784790e-02 2.7394378185272217e-01</leafValues></_>
+            2.2532704472541809e-01 -6.2741614878177643e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 657 2.0498572848737240e-03</internalNodes>
+            0 -1 910 3.3456790260970592e-03</internalNodes>
           <leafValues>
-            3.5124473273754120e-02 -5.0805884599685669e-01</leafValues></_>
+            3.8516163825988770e-02 -3.6224716901779175e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 670 1.3978367205709219e-03</internalNodes>
+            0 -1 476 1.9023896893486381e-03</internalNodes>
           <leafValues>
-            -8.5583955049514771e-02 1.9296622276306152e-01</leafValues></_>
+            -5.4677281528711319e-02 2.5294607877731323e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 983 3.1700683757662773e-03</internalNodes>
+            0 -1 1037 -1.4274399727582932e-03</internalNodes>
           <leafValues>
-            4.6254437416791916e-02 -3.5503390431404114e-01</leafValues></_>
+            -3.7934723496437073e-01 3.8707002997398376e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 946 -1.0263657895848155e-03</internalNodes>
+            0 -1 512 1.1010284069925547e-03</internalNodes>
           <leafValues>
-            1.3199952244758606e-01 -1.2064760923385620e-01</leafValues></_>
+            -9.5659099519252777e-02 1.4958517253398895e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 109 -4.1109144687652588e-02</internalNodes>
+            0 -1 219 -4.4154529459774494e-03</internalNodes>
           <leafValues>
-            1.7420990765094757e-01 -9.8242506384849548e-02</leafValues></_>
+            -5.1156622171401978e-01 2.5640288367867470e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 618 1.5759501606225967e-02</internalNodes>
+            0 -1 448 3.7023271434009075e-03</internalNodes>
           <leafValues>
-            -7.5842045247554779e-02 2.3157498240470886e-01</leafValues></_>
+            -4.3221119791269302e-02 3.2581970095634460e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 449 -9.5934671116992831e-04</internalNodes>
+            0 -1 237 -5.4480084218084812e-03</internalNodes>
           <leafValues>
-            1.8444137275218964e-01 -9.2052407562732697e-02</leafValues></_>
+            -4.7611567378044128e-01 3.5773757845163345e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 864 5.4162740707397461e-03</internalNodes>
+            0 -1 313 -3.1974539160728455e-04</internalNodes>
           <leafValues>
-            3.1357165426015854e-02 -5.3519624471664429e-01</leafValues></_>
+            1.1916244029998779e-01 -1.1832383275032043e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 866 3.4875022247433662e-03</internalNodes>
+            0 -1 381 -2.8494147583842278e-02</internalNodes>
           <leafValues>
-            4.8432532697916031e-02 -3.3630362153053284e-01</leafValues></_>
+            -6.5004557371139526e-01 2.0599177107214928e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 660 1.3441047631204128e-03</internalNodes>
+            0 -1 941 -2.7449331246316433e-03</internalNodes>
           <leafValues>
-            -8.3214677870273590e-02 2.0162117481231689e-01</leafValues></_>
+            -3.9275056123733521e-01 3.3223718404769897e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 684 -2.3109107278287411e-03</internalNodes>
+            0 -1 937 4.1362000629305840e-03</internalNodes>
           <leafValues>
-            1.8354012072086334e-01 -8.8427804410457611e-02</leafValues></_>
+            2.7191400527954102e-02 -4.7952741384506226e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 481 5.1613273099064827e-03</internalNodes>
+            0 -1 638 3.3568721264600754e-03</internalNodes>
           <leafValues>
-            -6.8671047687530518e-02 2.2440080344676971e-01</leafValues></_>
+            -6.0983922332525253e-02 2.2964073717594147e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 251 -2.3844663053750992e-02</internalNodes>
+            0 -1 571 -5.7129040360450745e-03</internalNodes>
           <leafValues>
-            -6.2796258926391602e-01 2.7813719585537910e-02</leafValues></_>
+            -5.9052920341491699e-01 2.3388050496578217e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 421 3.7013965193182230e-03</internalNodes>
+            0 -1 477 -1.1567326728254557e-03</internalNodes>
           <leafValues>
-            -6.7407652735710144e-02 2.7093955874443054e-01</leafValues></_>
+            1.5093772113323212e-01 -9.1553181409835815e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 633 3.9885155856609344e-03</internalNodes>
+            0 -1 143 -8.9379055425524712e-03</internalNodes>
           <leafValues>
-            3.4067343920469284e-02 -5.4420226812362671e-01</leafValues></_>
+            -3.5481104254722595e-01 3.6294396966695786e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 309 1.8910076469182968e-02</internalNodes>
+            0 -1 811 3.6097350530326366e-03</internalNodes>
           <leafValues>
-            4.2769759893417358e-02 -3.3686736226081848e-01</leafValues></_>
+            3.2780081033706665e-02 -3.8517734408378601e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 808 1.2143498286604881e-02</internalNodes>
+            0 -1 975 2.0727193914353848e-03</internalNodes>
           <leafValues>
-            1.9569551572203636e-02 -7.1214914321899414e-01</leafValues></_>
+            -5.3627125918865204e-02 2.5666573643684387e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 188 -5.6570172309875488e-03</internalNodes>
+            0 -1 977 -1.8177125602960587e-03</internalNodes>
           <leafValues>
-            -3.6661344766616821e-01 3.4494820982217789e-02</leafValues></_>
+            2.0363596081733704e-01 -7.0555560290813446e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 570 2.1571468096226454e-03</internalNodes>
+            0 -1 932 -3.3223466016352177e-03</internalNodes>
           <leafValues>
-            -8.9639738202095032e-02 1.5742646157741547e-01</leafValues></_>
+            -4.8926571011543274e-01 2.8675178065896034e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 565 1.8860616255551577e-03</internalNodes>
+            0 -1 553 -4.4222660362720490e-03</internalNodes>
           <leafValues>
-            -8.5441410541534424e-02 1.7696820199489594e-01</leafValues></_>
+            -4.0920063853263855e-01 3.0863059684634209e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 669 1.0152467293664813e-03</internalNodes>
+            0 -1 705 -7.8024319373071194e-04</internalNodes>
           <leafValues>
-            3.8969900459051132e-02 -3.7170857191085815e-01</leafValues></_>
+            1.2166435271501541e-01 -1.0897941887378693e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 775 -7.2436146438121796e-03</internalNodes>
+            0 -1 850 7.9855127260088921e-03</internalNodes>
           <leafValues>
-            1.7777322232723236e-01 -8.3921253681182861e-02</leafValues></_>
+            2.5865448638796806e-02 -4.8917418718338013e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 860 -3.7075001746416092e-03</internalNodes>
+            0 -1 99 -2.7752606911235489e-05</internalNodes>
           <leafValues>
-            1.8386960029602051e-01 -9.2291206121444702e-02</leafValues></_>
+            1.1611134558916092e-01 -1.1225233227014542e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 607 -1.4369469135999680e-03</internalNodes>
+            0 -1 641 3.0770362354815006e-03</internalNodes>
           <leafValues>
-            -2.7023202180862427e-01 5.5822439491748810e-02</leafValues></_>
+            -6.4753420650959015e-02 1.9632078707218170e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 926 -1.7798715271055698e-03</internalNodes>
+            0 -1 593 -2.1007210016250610e-03</internalNodes>
           <leafValues>
-            1.4900380373001099e-01 -9.8068036139011383e-02</leafValues></_>
+            1.9681814312934875e-01 -9.4167068600654602e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 558 1.9487005192786455e-03</internalNodes>
+            0 -1 112 -6.1383144930005074e-03</internalNodes>
           <leafValues>
-            -7.6331101357936859e-02 1.8935331702232361e-01</leafValues></_>
+            -3.9225277304649353e-01 3.5275831818580627e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 871 2.8823004104197025e-03</internalNodes>
+            0 -1 119 1.1184177361428738e-02</internalNodes>
           <leafValues>
-            4.2902354151010513e-02 -3.5214039683341980e-01</leafValues></_>
+            2.9410628601908684e-02 -4.3673589825630188e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 378 -5.6123267859220505e-03</internalNodes>
+            0 -1 1007 1.0432782582938671e-03</internalNodes>
           <leafValues>
-            -4.7632521390914917e-01 2.6048270985484123e-02</leafValues></_>
+            -6.7393802106380463e-02 1.9237922132015228e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 301 1.6383089125156403e-02</internalNodes>
+            0 -1 931 8.5366604616865516e-04</internalNodes>
           <leafValues>
-            -8.9606925845146179e-02 1.4743074774742126e-01</leafValues></_>
+            -8.4067851305007935e-02 1.6720806062221527e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 44 3.4455281496047974e-01</internalNodes>
+            0 -1 55 -3.3059090375900269e-02</internalNodes>
           <leafValues>
-            -2.0530648529529572e-02 7.2817444801330566e-01</leafValues></_>
+            2.6451063156127930e-01 -5.2662543952465057e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 448 2.7680541388690472e-03</internalNodes>
+            0 -1 161 -8.7435375899076462e-03</internalNodes>
           <leafValues>
-            -3.8598377257585526e-02 3.5294523835182190e-01</leafValues></_>
+            -3.0780994892120361e-01 4.8419766128063202e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 480 3.8404709193855524e-03</internalNodes>
+            0 -1 907 -1.1587596964091063e-03</internalNodes>
           <leafValues>
-            -8.0346472561359406e-02 1.8624457716941833e-01</leafValues></_>
+            1.4863640069961548e-01 -9.4251774251461029e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 11 -4.3602049350738525e-02</internalNodes>
+            0 -1 295 -2.2717786952853203e-02</internalNodes>
           <leafValues>
-            2.4986675381660461e-01 -7.1408227086067200e-02</leafValues></_>
+            -4.2414310574531555e-01 3.5150803625583649e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 2 -3.6010099574923515e-03</internalNodes>
+            0 -1 810 -8.4660220891237259e-03</internalNodes>
           <leafValues>
-            1.6942474246025085e-01 -1.0419391095638275e-01</leafValues></_>
+            2.5765278935432434e-01 -5.4796367883682251e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 320 -6.1740418896079063e-03</internalNodes>
+            0 -1 492 -1.4943551504984498e-03</internalNodes>
           <leafValues>
-            -4.6275594830513000e-01 3.1903993338346481e-02</leafValues></_>
+            -2.7729934453964233e-01 4.9375709146261215e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 898 3.4251257311552763e-03</internalNodes>
+            0 -1 0 -7.5480109080672264e-04</internalNodes>
           <leafValues>
-            2.5748182088136673e-02 -4.8371604084968567e-01</leafValues></_>
+            1.2197802960872650e-01 -1.0845532268285751e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 841 -3.9031119085848331e-03</internalNodes>
+            0 -1 853 2.9903287068009377e-03</internalNodes>
           <leafValues>
-            1.6738632321357727e-01 -8.4549814462661743e-02</leafValues></_>
+            -8.4785357117652893e-02 1.5424512326717377e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 935 -7.3322677053511143e-04</internalNodes>
+            0 -1 1040 1.7600806895643473e-03</internalNodes>
           <leafValues>
-            2.1091395616531372e-01 -7.2518013417720795e-02</leafValues></_>
+            7.0044547319412231e-02 -1.9795240461826324e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 932 2.7150693349540234e-03</internalNodes>
+            0 -1 154 1.2243577279150486e-02</internalNodes>
           <leafValues>
-            -5.7143334299325943e-02 2.7224695682525635e-01</leafValues></_>
+            -7.8472696244716644e-02 1.7095038294792175e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 937 1.7057932913303375e-02</internalNodes>
+            0 -1 80 -2.7739753946661949e-02</internalNodes>
           <leafValues>
-            -6.3262723386287689e-02 2.4493633210659027e-01</leafValues></_>
+            2.0475350320339203e-01 -6.9862313568592072e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 968 2.2439109161496162e-03</internalNodes>
+            0 -1 300 -6.4486754126846790e-03</internalNodes>
           <leafValues>
-            6.1605937778949738e-02 -2.5090345740318298e-01</leafValues></_>
+            -3.7651637196540833e-01 3.3540505915880203e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 122 9.2767914757132530e-03</internalNodes>
+            0 -1 341 -1.3427068479359150e-02</internalNodes>
           <leafValues>
-            3.9061944931745529e-02 -3.7177914381027222e-01</leafValues></_>
+            1.5320046246051788e-01 -8.3272159099578857e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 930 -1.3303438900038600e-03</internalNodes>
+            0 -1 360 8.2654636353254318e-03</internalNodes>
           <leafValues>
-            2.2685268521308899e-01 -6.3722826540470123e-02</leafValues></_>
+            -8.1395141780376434e-02 1.9696740806102753e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 818 -2.8938084840774536e-02</internalNodes>
+            0 -1 616 3.0615129508078098e-03</internalNodes>
           <leafValues>
-            -6.6085141897201538e-01 2.1666957065463066e-02</leafValues></_>
+            -5.8534789830446243e-02 2.1799990534782410e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 744 -5.0926357507705688e-03</internalNodes>
+            0 -1 616 -1.4359520282596350e-03</internalNodes>
           <leafValues>
-            1.7695400118827820e-01 -7.9500846564769745e-02</leafValues></_>
+            1.8553669750690460e-01 -7.9428143799304962e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 749 5.3870421834290028e-03</internalNodes>
+            0 -1 488 2.8793164528906345e-03</internalNodes>
           <leafValues>
-            -5.5856045335531235e-02 2.7346748113632202e-01</leafValues></_>
+            3.7499722093343735e-02 -3.5483118891716003e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 524 -8.0796808470040560e-04</internalNodes>
+            0 -1 631 -9.0899681672453880e-03</internalNodes>
           <leafValues>
-            -2.2386504709720612e-01 6.8852454423904419e-02</leafValues></_>
+            -5.9031629562377930e-01 2.0012531429529190e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 591 3.9214566349983215e-03</internalNodes>
+            0 -1 896 1.6797243151813745e-03</internalNodes>
           <leafValues>
-            2.2929171100258827e-02 -5.9076148271560669e-01</leafValues></_>
+            -6.8868115544319153e-02 1.8992543220520020e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 691 -6.5161995589733124e-03</internalNodes>
+            0 -1 581 -1.1759581044316292e-02</internalNodes>
           <leafValues>
-            -5.5175542831420898e-01 2.0790172740817070e-02</leafValues></_>
+            3.6288693547248840e-01 -3.3578243106603622e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 295 -1.6703434521332383e-03</internalNodes>
+            0 -1 749 3.8305222988128662e-03</internalNodes>
           <leafValues>
-            -3.5234490036964417e-01 3.4917417913675308e-02</leafValues></_>
+            -6.6793553531169891e-02 1.9304293394088745e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 126 -3.2307719811797142e-03</internalNodes>
+            0 -1 1018 1.2506111524999142e-03</internalNodes>
           <leafValues>
-            1.5907490253448486e-01 -7.8541077673435211e-02</leafValues></_>
+            -8.1618689000606537e-02 1.5481384098529816e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 123 5.0736088305711746e-03</internalNodes>
+            0 -1 379 -1.6119323670864105e-02</internalNodes>
           <leafValues>
-            -7.3796175420284271e-02 1.7231710255146027e-01</leafValues></_>
+            1.4024992287158966e-01 -9.3965478241443634e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 68 -1.9738268107175827e-02</internalNodes>
+            0 -1 576 -7.2789913974702358e-04</internalNodes>
           <leafValues>
-            2.4731338024139404e-01 -5.3791344165802002e-02</leafValues></_>
+            1.9554650783538818e-01 -7.2329640388488770e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 404 6.9891922175884247e-03</internalNodes>
+            0 -1 178 1.4888901496306062e-03</internalNodes>
           <leafValues>
-            -6.1806734651327133e-02 2.1923109889030457e-01</leafValues></_>
+            3.3372651785612106e-02 -4.0691211819648743e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 851 -2.6465239934623241e-03</internalNodes>
+            0 -1 984 -4.9822013825178146e-03</internalNodes>
           <leafValues>
-            2.8577965497970581e-01 -6.6506840288639069e-02</leafValues></_>
+            -3.3125448226928711e-01 3.6899805068969727e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 734 3.3399839885532856e-03</internalNodes>
+            0 -1 1053 9.4443336129188538e-03</internalNodes>
           <leafValues>
-            3.4735739231109619e-02 -3.9448723196983337e-01</leafValues></_></weakClassifiers></_></stages>
-  <features>
+            3.1763385981321335e-02 -3.7651473283767700e-01</leafValues></_></weakClassifiers></_>
+    <!-- stage 19 -->
     <_>
-      <rects>
+      <maxWeakCount>100</maxWeakCount>
+      <stageThreshold>-1.3101767301559448e+00</stageThreshold>
+      <weakClassifiers>
         <_>
-          0 0 6 1 -1.</_>
+          <internalNodes>
+            0 -1 535 -1.2652185745537281e-02</internalNodes>
+          <leafValues>
+            4.0350878238677979e-01 -8.6829073727130890e-02</leafValues></_>
         <_>
-          3 0 3 1 2.</_></rects>
-      <tilted>0</tilted></_>
-    <_>
-      <rects>
+          <internalNodes>
+            0 -1 386 4.8778904601931572e-03</internalNodes>
+          <leafValues>
+            -9.1208808124065399e-02 4.8882400989532471e-01</leafValues></_>
         <_>
-          0 0 6 2 -1.</_>
+          <internalNodes>
+            0 -1 875 -2.4099014699459076e-02</internalNodes>
+          <leafValues>
+            3.6089360713958740e-01 -1.1495783179998398e-01</leafValues></_>
         <_>
-          3 0 3 2 2.</_></rects>
-      <tilted>0</tilted></_>
-    <_>
-      <rects>
+          <internalNodes>
+            0 -1 955 1.7244052141904831e-03</internalNodes>
+          <leafValues>
+            -1.5974776446819305e-01 1.6197346150875092e-01</leafValues></_>
         <_>
-          0 0 8 1 -1.</_>
+          <internalNodes>
+            0 -1 478 -3.6334272008389235e-03</internalNodes>
+          <leafValues>
+            2.7575418353080750e-01 -9.4314105808734894e-02</leafValues></_>
         <_>
-          4 0 4 1 2.</_></rects>
-      <tilted>0</tilted></_>
-    <_>
-      <rects>
+          <internalNodes>
+            0 -1 874 -3.4076566807925701e-03</internalNodes>
+          <leafValues>
+            2.2806543111801147e-01 -1.1266379803419113e-01</leafValues></_>
         <_>
-          0 0 8 4 -1.</_>
+          <internalNodes>
+            0 -1 343 8.8951038196682930e-03</internalNodes>
+          <leafValues>
+            -6.6720969974994659e-02 3.3090111613273621e-01</leafValues></_>
         <_>
-          0 0 4 2 2.</_>
+          <internalNodes>
+            0 -1 886 -2.4365000426769257e-03</internalNodes>
+          <leafValues>
+            -4.6264356374740601e-01 5.9559248387813568e-02</leafValues></_>
         <_>
-          4 2 4 2 2.</_></rects>
-      <tilted>0</tilted></_>
-    <_>
-      <rects>
+          <internalNodes>
+            0 -1 134 1.6330357640981674e-02</internalNodes>
+          <leafValues>
+            6.1187297105789185e-02 -4.2252638936042786e-01</leafValues></_>
         <_>
-          0 0 8 6 -1.</_>
+          <internalNodes>
+            0 -1 92 8.4438512567430735e-04</internalNodes>
+          <leafValues>
+            -1.6640183329582214e-01 1.1608948558568954e-01</leafValues></_>
         <_>
-          0 0 4 3 2.</_>
+          <internalNodes>
+            0 -1 841 2.9493896290659904e-03</internalNodes>
+          <leafValues>
+            -9.1952294111251831e-02 2.0670032501220703e-01</leafValues></_>
         <_>
-          4 3 4 3 2.</_></rects>
-      <tilted>0</tilted></_>
-    <_>
-      <rects>
+          <internalNodes>
+            0 -1 40 3.4696407616138458e-02</internalNodes>
+          <leafValues>
+            -8.0334044992923737e-02 2.8779104351997375e-01</leafValues></_>
         <_>
-          0 0 8 12 -1.</_>
+          <internalNodes>
+            0 -1 893 -3.3343117684125900e-03</internalNodes>
+          <leafValues>
+            -5.9474521875381470e-01 3.6547001451253891e-02</leafValues></_>
         <_>
-          0 0 4 6 2.</_>
+          <internalNodes>
+            0 -1 761 9.3975086929276586e-04</internalNodes>
+          <leafValues>
+            -1.5703736245632172e-01 1.1884722858667374e-01</leafValues></_>
         <_>
-          4 6 4 6 2.</_></rects>
-      <tilted>0</tilted></_>
-    <_>
-      <rects>
+          <internalNodes>
+            0 -1 174 -3.4337402321398258e-03</internalNodes>
+          <leafValues>
+            -5.6122291088104248e-01 3.2535579055547714e-02</leafValues></_>
         <_>
-          0 0 8 16 -1.</_>
+          <internalNodes>
+            0 -1 1010 2.6463428512215614e-03</internalNodes>
+          <leafValues>
+            -7.0756055414676666e-02 2.5195503234863281e-01</leafValues></_>
         <_>
-          0 0 4 8 2.</_>
+          <internalNodes>
+            0 -1 334 -5.4167490452528000e-04</internalNodes>
+          <leafValues>
+            1.2782673537731171e-01 -1.3642209768295288e-01</leafValues></_>
         <_>
-          4 8 4 8 2.</_></rects>
-      <tilted>0</tilted></_>
-    <_>
-      <rects>
+          <internalNodes>
+            0 -1 219 2.6469756849110126e-03</internalNodes>
+          <leafValues>
+            4.3448049575090408e-02 -4.2012536525726318e-01</leafValues></_>
         <_>
-          0 0 10 3 -1.</_>
+          <internalNodes>
+            0 -1 467 -3.8945327978581190e-03</internalNodes>
+          <leafValues>
+            -3.4613665938377380e-01 4.6863511204719543e-02</leafValues></_>
         <_>
-          5 0 5 3 2.</_></rects>
-      <tilted>0</tilted></_>
-    <_>
-      <rects>
+          <internalNodes>
+            0 -1 258 1.0849055834114552e-03</internalNodes>
+          <leafValues>
+            -7.2841711342334747e-02 2.2674085199832916e-01</leafValues></_>
         <_>
-          0 0 10 6 -1.</_>
+          <internalNodes>
+            0 -1 258 -9.8655023612082005e-04</internalNodes>
+          <leafValues>
+            2.5967630743980408e-01 -8.0196425318717957e-02</leafValues></_>
         <_>
-          0 0 5 3 2.</_>
+          <internalNodes>
+            0 -1 204 4.3801497668027878e-03</internalNodes>
+          <leafValues>
+            2.8548270463943481e-02 -6.2486541271209717e-01</leafValues></_>
         <_>
-          5 3 5 3 2.</_></rects>
-      <tilted>0</tilted></_>
-    <_>
-      <rects>
+          <internalNodes>
+            0 -1 554 3.1944573856890202e-04</internalNodes>
+          <leafValues>
+            -1.4062304794788361e-01 1.1761485785245895e-01</leafValues></_>
         <_>
-          0 0 10 10 -1.</_>
+          <internalNodes>
+            0 -1 300 6.6440929658710957e-03</internalNodes>
+          <leafValues>
+            3.2654736191034317e-02 -4.6211913228034973e-01</leafValues></_>
         <_>
-          0 0 5 5 2.</_>
+          <internalNodes>
+            0 -1 42 7.0357543881982565e-04</internalNodes>
+          <leafValues>
+            7.5751155614852905e-02 -1.9804775714874268e-01</leafValues></_>
         <_>
-          5 5 5 5 2.</_></rects>
-      <tilted>0</tilted></_>
-    <_>
-      <rects>
+          <internalNodes>
+            0 -1 446 5.4024737328290939e-03</internalNodes>
+          <leafValues>
+            -6.1951220035552979e-02 2.4502439796924591e-01</leafValues></_>
         <_>
-          0 0 18 14 -1.</_>
+          <internalNodes>
+            0 -1 502 7.2796619497239590e-03</internalNodes>
+          <leafValues>
+            -5.9379905462265015e-02 2.5588110089302063e-01</leafValues></_>
         <_>
-          6 0 6 14 3.</_></rects>
-      <tilted>0</tilted></_>
-    <_>
-      <rects>
+          <internalNodes>
+            0 -1 169 -1.5059831552207470e-02</internalNodes>
+          <leafValues>
+            -6.6548824310302734e-01 2.2492453455924988e-02</leafValues></_>
         <_>
-          0 0 14 10 -1.</_>
+          <internalNodes>
+            0 -1 270 -4.6248016878962517e-03</internalNodes>
+          <leafValues>
+            -3.4483894705772400e-01 4.2247168719768524e-02</leafValues></_>
         <_>
-          0 0 7 5 2.</_>
+          <internalNodes>
+            0 -1 290 1.4736279845237732e-03</internalNodes>
+          <leafValues>
+            3.3624436706304550e-02 -4.1066497564315796e-01</leafValues></_>
         <_>
-          7 5 7 5 2.</_></rects>
-      <tilted>0</tilted></_>
-    <_>
-      <rects>
+          <internalNodes>
+            0 -1 110 4.0667224675416946e-03</internalNodes>
+          <leafValues>
+            -8.6238399147987366e-02 1.6550070047378540e-01</leafValues></_>
         <_>
-          0 0 24 1 -1.</_>
+          <internalNodes>
+            0 -1 113 -1.2728295987471938e-03</internalNodes>
+          <leafValues>
+            1.9737298786640167e-01 -9.5425128936767578e-02</leafValues></_>
         <_>
-          8 0 8 1 3.</_></rects>
-      <tilted>0</tilted></_>
-    <_>
+          <internalNodes>
+            0 -1 957 -1.5297440811991692e-02</internalNodes>
+          <leafValues>
+            -5.9287589788436890e-01 2.3890895769000053e-02</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 969 -2.9415758326649666e-03</internalNodes>
+          <leafValues>
+            -4.8744291067123413e-01 2.8945079073309898e-02</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 840 9.3173712957650423e-04</internalNodes>
+          <leafValues>
+            -8.9065223932266235e-02 1.6721877455711365e-01</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 791 2.1161064505577087e-03</internalNodes>
+          <leafValues>
+            -5.8501452207565308e-02 2.7767315506935120e-01</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 579 -3.7564497906714678e-03</internalNodes>
+          <leafValues>
+            2.6502594351768494e-01 -5.3400754928588867e-02</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 224 1.9215289503335953e-02</internalNodes>
+          <leafValues>
+            3.6197379231452942e-02 -3.9996260404586792e-01</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 276 -5.8480387087911367e-04</internalNodes>
+          <leafValues>
+            1.7670612037181854e-01 -8.0434471368789673e-02</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 62 1.7193648964166641e-02</internalNodes>
+          <leafValues>
+            2.1810308098793030e-02 -6.6349571943283081e-01</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 394 -1.5182361006736755e-02</internalNodes>
+          <leafValues>
+            2.4825552105903625e-01 -6.3092373311519623e-02</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 712 3.0793007463216782e-03</internalNodes>
+          <leafValues>
+            2.4977168068289757e-02 -5.3303867578506470e-01</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 410 -2.4421955458819866e-03</internalNodes>
+          <leafValues>
+            -3.6828973889350891e-01 3.3543743193149567e-02</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 1011 7.0760864764451981e-04</internalNodes>
+          <leafValues>
+            -7.0839107036590576e-02 1.9299270212650299e-01</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 280 -2.9198618140071630e-03</internalNodes>
+          <leafValues>
+            -4.2773759365081787e-01 3.4788779914379120e-02</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 77 4.9937088042497635e-03</internalNodes>
+          <leafValues>
+            3.5642433911561966e-02 -3.7421676516532898e-01</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 701 3.1980490311980247e-03</internalNodes>
+          <leafValues>
+            -6.5103210508823395e-02 2.1381905674934387e-01</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 320 -1.1253832839429379e-02</internalNodes>
+          <leafValues>
+            1.9790579378604889e-01 -7.1859836578369141e-02</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 496 -3.6279223859310150e-02</internalNodes>
+          <leafValues>
+            1.7960831522941589e-01 -9.7373597323894501e-02</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 606 2.5160997174680233e-03</internalNodes>
+          <leafValues>
+            4.7910790890455246e-02 -2.7035105228424072e-01</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 597 1.2429051566869020e-03</internalNodes>
+          <leafValues>
+            -7.8723609447479248e-02 1.7209371924400330e-01</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 600 -1.6120750457048416e-02</internalNodes>
+          <leafValues>
+            2.6868200302124023e-01 -5.0688084214925766e-02</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 676 1.9487962126731873e-03</internalNodes>
+          <leafValues>
+            4.2773328721523285e-02 -3.2401460409164429e-01</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 371 7.1887858211994171e-04</internalNodes>
+          <leafValues>
+            -9.3979224562644958e-02 1.4450067281723022e-01</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 315 2.4896476417779922e-02</internalNodes>
+          <leafValues>
+            3.0655095353722572e-02 -4.5330229401588440e-01</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 1026 -3.9382722228765488e-02</internalNodes>
+          <leafValues>
+            -7.5473642349243164e-01 1.4460344798862934e-02</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 16 1.6916246712207794e-01</internalNodes>
+          <leafValues>
+            1.8219815567135811e-02 -6.0212779045104980e-01</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 327 2.6912155590252951e-05</internalNodes>
+          <leafValues>
+            -1.3110430538654327e-01 1.0080647468566895e-01</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 720 -1.1350987479090691e-03</internalNodes>
+          <leafValues>
+            -3.5285457968711853e-01 3.5424951463937759e-02</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 275 -5.3854554425925016e-04</internalNodes>
+          <leafValues>
+            1.6519539058208466e-01 -8.5205554962158203e-02</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 1006 -7.9703063238412142e-04</internalNodes>
+          <leafValues>
+            1.2170238047838211e-01 -1.1191177368164062e-01</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 1055 6.4357938244938850e-03</internalNodes>
+          <leafValues>
+            2.3892326280474663e-02 -5.2907115221023560e-01</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 184 3.5384115763008595e-03</internalNodes>
+          <leafValues>
+            1.5895446762442589e-02 -7.3063355684280396e-01</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 503 -5.9715351089835167e-03</internalNodes>
+          <leafValues>
+            -4.9897637963294983e-01 2.2720154374837875e-02</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 500 -1.3486531376838684e-01</internalNodes>
+          <leafValues>
+            4.7622504830360413e-01 -3.0212458223104477e-02</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 824 1.5813487116247416e-03</internalNodes>
+          <leafValues>
+            -6.4366899430751801e-02 1.9106543064117432e-01</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 438 1.2239011703059077e-03</internalNodes>
+          <leafValues>
+            3.5654775798320770e-02 -3.6865225434303284e-01</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 871 1.5586249064654112e-03</internalNodes>
+          <leafValues>
+            -7.6894849538803101e-02 1.7627324163913727e-01</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 807 8.1224087625741959e-03</internalNodes>
+          <leafValues>
+            -9.0349502861499786e-02 1.4695085585117340e-01</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 693 -1.1717316228896379e-03</internalNodes>
+          <leafValues>
+            -4.2172068357467651e-01 3.2626960426568985e-02</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 863 3.1573872547596693e-03</internalNodes>
+          <leafValues>
+            1.6080003231763840e-02 -7.3708915710449219e-01</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 328 -6.0417165514081717e-04</internalNodes>
+          <leafValues>
+            1.3188406825065613e-01 -1.0221557319164276e-01</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 870 5.9989960864186287e-03</internalNodes>
+          <leafValues>
+            -5.6194521486759186e-02 2.4262723326683044e-01</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 285 9.2063043266534805e-03</internalNodes>
+          <leafValues>
+            -7.4052155017852783e-02 1.9847218692302704e-01</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 759 5.9181386604905128e-03</internalNodes>
+          <leafValues>
+            2.7928760275244713e-02 -5.3380137681961060e-01</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 637 2.2121241781860590e-03</internalNodes>
+          <leafValues>
+            -7.4788182973861694e-02 1.9799898564815521e-01</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 634 1.5453733503818512e-03</internalNodes>
+          <leafValues>
+            -8.1615962088108063e-02 1.7845135927200317e-01</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 48 -2.7309993747621775e-03</internalNodes>
+          <leafValues>
+            -2.9415401816368103e-01 4.8099983483552933e-02</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 288 1.5755122527480125e-02</internalNodes>
+          <leafValues>
+            -8.2719191908836365e-02 1.5387716889381409e-01</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 358 -5.5120363831520081e-02</internalNodes>
+          <leafValues>
+            -2.7076271176338196e-01 5.2753895521163940e-02</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 188 2.9593750834465027e-01</internalNodes>
+          <leafValues>
+            -2.5313137099146843e-02 5.3404790163040161e-01</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 755 -1.1218986473977566e-03</internalNodes>
+          <leafValues>
+            1.1400944739580154e-01 -1.1270149052143097e-01</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 12 -3.7802509963512421e-02</internalNodes>
+          <leafValues>
+            3.1571185588836670e-01 -4.9672659486532211e-02</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 122 7.6384171843528748e-03</internalNodes>
+          <leafValues>
+            -1.0544487833976746e-01 1.6579298675060272e-01</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 586 6.8679507821798325e-03</internalNodes>
+          <leafValues>
+            -6.0160953551530838e-02 2.2640766203403473e-01</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 443 5.1510091871023178e-02</internalNodes>
+          <leafValues>
+            2.6919802650809288e-02 -5.1188707351684570e-01</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 997 -1.7317479476332664e-02</internalNodes>
+          <leafValues>
+            2.8218811750411987e-01 -4.4739942997694016e-02</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 430 8.3876429125666618e-03</internalNodes>
+          <leafValues>
+            -5.7016383856534958e-02 2.2617760300636292e-01</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 625 9.2909142374992371e-02</internalNodes>
+          <leafValues>
+            3.1283479183912277e-02 -4.9390810728073120e-01</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 457 4.8232711851596832e-03</internalNodes>
+          <leafValues>
+            2.4896934628486633e-02 -4.5571261644363403e-01</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 484 2.3969253525137901e-03</internalNodes>
+          <leafValues>
+            2.3365976288914680e-02 -4.8319596052169800e-01</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 599 -3.8546645082533360e-03</internalNodes>
+          <leafValues>
+            2.0274488627910614e-01 -5.8264043182134628e-02</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 647 -1.2048919452354312e-03</internalNodes>
+          <leafValues>
+            -3.4361392259597778e-01 3.4746967256069183e-02</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 734 -1.6053356230258942e-02</internalNodes>
+          <leafValues>
+            1.8685258924961090e-01 -6.7979305982589722e-02</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 1045 -2.1703056991100311e-02</internalNodes>
+          <leafValues>
+            -5.0804340839385986e-01 2.5113353505730629e-02</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 541 -1.9719875417649746e-03</internalNodes>
+          <leafValues>
+            -2.7325069904327393e-01 4.3638698756694794e-02</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 465 -1.3189280871301889e-03</internalNodes>
+          <leafValues>
+            2.5198838114738464e-01 -4.8170279711484909e-02</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 465 1.3257672544568777e-03</internalNodes>
+          <leafValues>
+            -6.6290155053138733e-02 2.6572498679161072e-01</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 1024 -2.5993511080741882e-03</internalNodes>
+          <leafValues>
+            -7.1209841966629028e-01 1.9255550578236580e-02</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 926 4.0416182018816471e-03</internalNodes>
+          <leafValues>
+            2.4820772930979729e-02 -4.3810126185417175e-01</leafValues></_></weakClassifiers></_></stages>
+  <features>
+    <_>
+      <rects>
+        <_>
+          0 0 2 4 -1.</_>
+        <_>
+          0 2 2 2 2.</_></rects>
+      <tilted>0</tilted></_>
+    <_>
+      <rects>
+        <_>
+          0 0 6 14 -1.</_>
+        <_>
+          0 0 3 7 2.</_>
+        <_>
+          3 7 3 7 2.</_></rects>
+      <tilted>0</tilted></_>
+    <_>
+      <rects>
+        <_>
+          0 0 8 1 -1.</_>
+        <_>
+          4 0 4 1 2.</_></rects>
+      <tilted>0</tilted></_>
+    <_>
+      <rects>
+        <_>
+          0 0 8 2 -1.</_>
+        <_>
+          4 0 4 2 2.</_></rects>
+      <tilted>0</tilted></_>
+    <_>
+      <rects>
+        <_>
+          0 0 8 6 -1.</_>
+        <_>
+          0 0 4 3 2.</_>
+        <_>
+          4 3 4 3 2.</_></rects>
+      <tilted>0</tilted></_>
+    <_>
+      <rects>
+        <_>
+          0 0 8 12 -1.</_>
+        <_>
+          0 0 4 6 2.</_>
+        <_>
+          4 6 4 6 2.</_></rects>
+      <tilted>0</tilted></_>
+    <_>
+      <rects>
+        <_>
+          0 0 8 14 -1.</_>
+        <_>
+          0 0 4 7 2.</_>
+        <_>
+          4 7 4 7 2.</_></rects>
+      <tilted>0</tilted></_>
+    <_>
+      <rects>
+        <_>
+          0 0 10 6 -1.</_>
+        <_>
+          0 0 5 3 2.</_>
+        <_>
+          5 3 5 3 2.</_></rects>
+      <tilted>0</tilted></_>
+    <_>
+      <rects>
+        <_>
+          0 0 10 8 -1.</_>
+        <_>
+          0 0 5 4 2.</_>
+        <_>
+          5 4 5 4 2.</_></rects>
+      <tilted>0</tilted></_>
+    <_>
+      <rects>
+        <_>
+          0 0 18 13 -1.</_>
+        <_>
+          6 0 6 13 3.</_></rects>
+      <tilted>0</tilted></_>
+    <_>
+      <rects>
+        <_>
+          0 0 14 10 -1.</_>
+        <_>
+          0 0 7 5 2.</_>
+        <_>
+          7 5 7 5 2.</_></rects>
+      <tilted>0</tilted></_>
+    <_>
+      <rects>
+        <_>
+          0 0 24 1 -1.</_>
+        <_>
+          8 0 8 1 3.</_></rects>
+      <tilted>0</tilted></_>
+    <_>
+      <rects>
+        <_>
+          0 0 16 6 -1.</_>
+        <_>
+          0 0 8 3 2.</_>
+        <_>
+          8 3 8 3 2.</_></rects>
+      <tilted>0</tilted></_>
+    <_>
+      <rects>
+        <_>
+          0 0 16 10 -1.</_>
+        <_>
+          0 0 8 5 2.</_>
+        <_>
+          8 5 8 5 2.</_></rects>
+      <tilted>0</tilted></_>
+    <_>
+      <rects>
+        <_>
+          0 0 24 1 -1.</_>
+        <_>
+          12 0 12 1 2.</_></rects>
+      <tilted>0</tilted></_>
+    <_>
+      <rects>
+        <_>
+          0 0 24 2 -1.</_>
+        <_>
+          0 0 12 1 2.</_>
+        <_>
+          12 1 12 1 2.</_></rects>
+      <tilted>0</tilted></_>
+    <_>
+      <rects>
+        <_>
+          0 0 12 12 -1.</_>
+        <_>
+          0 6 12 6 2.</_></rects>
+      <tilted>0</tilted></_>
+    <_>
+      <rects>
+        <_>
+          0 0 15 18 -1.</_>
+        <_>
+          0 6 15 6 3.</_></rects>
+      <tilted>0</tilted></_>
+    <_>
+      <rects>
+        <_>
+          0 1 1 6 -1.</_>
+        <_>
+          0 3 1 2 3.</_></rects>
+      <tilted>0</tilted></_>
+    <_>
+      <rects>
+        <_>
+          0 1 4 6 -1.</_>
+        <_>
+          2 1 2 6 2.</_></rects>
+      <tilted>0</tilted></_>
+    <_>
+      <rects>
+        <_>
+          0 1 15 1 -1.</_>
+        <_>
+          5 1 5 1 3.</_></rects>
+      <tilted>0</tilted></_>
+    <_>
+      <rects>
+        <_>
+          0 1 10 2 -1.</_>
+        <_>
+          5 1 5 2 2.</_></rects>
+      <tilted>0</tilted></_>
+    <_>
+      <rects>
+        <_>
+          0 2 24 2 -1.</_>
+        <_>
+          0 2 12 1 2.</_>
+        <_>
+          12 3 12 1 2.</_></rects>
+      <tilted>0</tilted></_>
+    <_>
+      <rects>
+        <_>
+          0 2 24 10 -1.</_>
+        <_>
+          0 2 12 5 2.</_>
+        <_>
+          12 7 12 5 2.</_></rects>
+      <tilted>0</tilted></_>
+    <_>
+      <rects>
+        <_>
+          0 3 7 3 -1.</_>
+        <_>
+          0 4 7 1 3.</_></rects>
+      <tilted>0</tilted></_>
+    <_>
+      <rects>
+        <_>
+          0 3 24 2 -1.</_>
+        <_>
+          0 3 12 1 2.</_>
+        <_>
+          12 4 12 1 2.</_></rects>
+      <tilted>0</tilted></_>
+    <_>
+      <rects>
+        <_>
+          0 4 6 12 -1.</_>
+        <_>
+          0 8 6 4 3.</_></rects>
+      <tilted>0</tilted></_>
+    <_>
+      <rects>
+        <_>
+          0 4 24 6 -1.</_>
+        <_>
+          0 6 24 2 3.</_></rects>
+      <tilted>0</tilted></_>
+    <_>
+      <rects>
+        <_>
+          0 5 2 9 -1.</_>
+        <_>
+          0 8 2 3 3.</_></rects>
+      <tilted>0</tilted></_>
+    <_>
+      <rects>
+        <_>
+          0 5 24 2 -1.</_>
+        <_>
+          0 5 12 1 2.</_>
+        <_>
+          12 6 12 1 2.</_></rects>
+      <tilted>0</tilted></_>
+    <_>
+      <rects>
+        <_>
+          0 6 6 3 -1.</_>
+        <_>
+          0 7 6 1 3.</_></rects>
+      <tilted>0</tilted></_>
+    <_>
+      <rects>
+        <_>
+          0 6 24 2 -1.</_>
+        <_>
+          0 6 12 1 2.</_>
+        <_>
+          12 7 12 1 2.</_></rects>
+      <tilted>0</tilted></_>
+    <_>
+      <rects>
+        <_>
+          0 6 22 3 -1.</_>
+        <_>
+          0 7 22 1 3.</_></rects>
+      <tilted>0</tilted></_>
+    <_>
+      <rects>
+        <_>
+          0 6 24 9 -1.</_>
+        <_>
+          0 9 24 3 3.</_></rects>
+      <tilted>0</tilted></_>
+    <_>
+      <rects>
+        <_>
+          0 7 16 1 -1.</_>
+        <_>
+          8 7 8 1 2.</_></rects>
+      <tilted>0</tilted></_>
+    <_>
+      <rects>
+        <_>
+          0 7 24 3 -1.</_>
+        <_>
+          8 7 8 3 3.</_></rects>
+      <tilted>0</tilted></_>
+    <_>
+      <rects>
+        <_>
+          0 7 24 2 -1.</_>
+        <_>
+          0 7 12 1 2.</_>
+        <_>
+          12 8 12 1 2.</_></rects>
+      <tilted>0</tilted></_>
+    <_>
+      <rects>
+        <_>
+          0 8 4 6 -1.</_>
+        <_>
+          2 8 2 6 2.</_></rects>
+      <tilted>0</tilted></_>
+    <_>
+      <rects>
+        <_>
+          0 8 6 15 -1.</_>
+        <_>
+          3 8 3 15 2.</_></rects>
+      <tilted>0</tilted></_>
+    <_>
+      <rects>
+        <_>
+          0 8 4 9 -1.</_>
+        <_>
+          0 11 4 3 3.</_></rects>
+      <tilted>0</tilted></_>
+    <_>
+      <rects>
+        <_>
+          0 8 24 1 -1.</_>
+        <_>
+          8 8 8 1 3.</_></rects>
+      <tilted>0</tilted></_>
+    <_>
+      <rects>
+        <_>
+          0 8 24 4 -1.</_>
+        <_>
+          0 8 12 2 2.</_>
+        <_>
+          12 10 12 2 2.</_></rects>
+      <tilted>0</tilted></_>
+    <_>
+      <rects>
+        <_>
+          0 9 2 3 -1.</_>
+        <_>
+          0 10 2 1 3.</_></rects>
+      <tilted>0</tilted></_>
+    <_>
+      <rects>
+        <_>
+          0 9 2 9 -1.</_>
+        <_>
+          0 12 2 3 3.</_></rects>
+      <tilted>0</tilted></_>
+    <_>
+      <rects>
+        <_>
+          0 9 5 3 -1.</_>
+        <_>
+          0 10 5 1 3.</_></rects>
+      <tilted>0</tilted></_>
+    <_>
+      <rects>
+        <_>
+          0 9 5 6 -1.</_>
+        <_>
+          0 11 5 2 3.</_></rects>
+      <tilted>0</tilted></_>
+    <_>
+      <rects>
+        <_>
+          0 9 7 2 -1.</_>
+        <_>
+          0 10 7 1 2.</_></rects>
+      <tilted>0</tilted></_>
+    <_>
+      <rects>
+        <_>
+          0 9 8 2 -1.</_>
+        <_>
+          0 10 8 1 2.</_></rects>
+      <tilted>0</tilted></_>
+    <_>
+      <rects>
+        <_>
+          0 9 10 2 -1.</_>
+        <_>
+          0 10 10 1 2.</_></rects>
+      <tilted>0</tilted></_>
+    <_>
+      <rects>
+        <_>
+          0 9 22 2 -1.</_>
+        <_>
+          0 9 11 1 2.</_>
+        <_>
+          11 10 11 1 2.</_></rects>
+      <tilted>0</tilted></_>
+    <_>
+      <rects>
+        <_>
+          0 9 24 4 -1.</_>
+        <_>
+          0 9 12 2 2.</_>
+        <_>
+          12 11 12 2 2.</_></rects>
+      <tilted>0</tilted></_>
+    <_>
       <rects>
         <_>
-          0 0 16 8 -1.</_>
+          0 9 24 15 -1.</_>
+        <_>
+          12 9 12 15 2.</_></rects>
+      <tilted>0</tilted></_>
+    <_>
+      <rects>
         <_>
-          0 0 8 4 2.</_>
+          0 9 15 3 -1.</_>
         <_>
-          8 4 8 4 2.</_></rects>
+          0 10 15 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          0 0 16 10 -1.</_>
+          0 10 2 3 -1.</_>
         <_>
-          0 0 8 5 2.</_>
+          0 11 2 1 3.</_></rects>
+      <tilted>0</tilted></_>
+    <_>
+      <rects>
         <_>
-          8 5 8 5 2.</_></rects>
+          0 10 6 1 -1.</_>
+        <_>
+          3 10 3 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          0 0 24 1 -1.</_>
+          0 10 6 14 -1.</_>
         <_>
-          12 0 12 1 2.</_></rects>
+          3 10 3 14 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          0 1 24 2 -1.</_>
+          0 10 4 3 -1.</_>
         <_>
-          8 1 8 2 3.</_></rects>
+          0 11 4 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          0 1 16 8 -1.</_>
+          0 10 24 2 -1.</_>
         <_>
-          0 1 8 4 2.</_>
+          0 10 12 1 2.</_>
         <_>
-          8 5 8 4 2.</_></rects>
+          12 11 12 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          0 1 16 18 -1.</_>
+          0 10 24 4 -1.</_>
+        <_>
+          0 10 12 2 2.</_>
         <_>
-          0 7 16 6 3.</_></rects>
+          12 12 12 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          0 2 24 2 -1.</_>
+          0 10 13 3 -1.</_>
         <_>
-          0 2 12 1 2.</_>
+          0 11 13 1 3.</_></rects>
+      <tilted>0</tilted></_>
+    <_>
+      <rects>
         <_>
-          12 3 12 1 2.</_></rects>
+          0 11 2 3 -1.</_>
+        <_>
+          0 12 2 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          0 2 24 19 -1.</_>
+          0 11 6 8 -1.</_>
+        <_>
+          0 11 3 4 2.</_>
         <_>
-          12 2 12 19 2.</_></rects>
+          3 15 3 4 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          0 3 8 3 -1.</_>
+          0 11 10 3 -1.</_>
         <_>
-          0 4 8 1 3.</_></rects>
+          0 12 10 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          0 3 24 2 -1.</_>
+          0 11 24 2 -1.</_>
         <_>
-          0 3 12 1 2.</_>
+          0 11 12 1 2.</_>
         <_>
-          12 4 12 1 2.</_></rects>
+          12 12 12 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          0 4 6 9 -1.</_>
+          0 12 3 10 -1.</_>
         <_>
-          0 7 6 3 3.</_></rects>
+          1 12 1 10 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          0 4 24 2 -1.</_>
+          0 12 22 10 -1.</_>
+        <_>
+          11 12 11 10 2.</_></rects>
+      <tilted>0</tilted></_>
+    <_>
+      <rects>
         <_>
-          0 4 12 1 2.</_>
+          0 13 3 9 -1.</_>
         <_>
-          12 5 12 1 2.</_></rects>
+          1 13 1 9 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          0 4 13 15 -1.</_>
+          0 13 12 10 -1.</_>
         <_>
-          0 9 13 5 3.</_></rects>
+          6 13 6 10 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          0 4 14 3 -1.</_>
+          0 13 24 10 -1.</_>
         <_>
-          0 5 14 1 3.</_></rects>
+          12 13 12 10 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          0 4 23 6 -1.</_>
+          0 14 24 2 -1.</_>
+        <_>
+          0 14 12 1 2.</_>
         <_>
-          0 6 23 2 3.</_></rects>
+          12 15 12 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          0 5 9 9 -1.</_>
+          0 15 3 8 -1.</_>
         <_>
-          0 8 9 3 3.</_></rects>
+          1 15 1 8 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          0 5 24 2 -1.</_>
+          0 15 12 8 -1.</_>
         <_>
-          0 5 12 1 2.</_>
+          0 15 6 4 2.</_>
         <_>
-          12 6 12 1 2.</_></rects>
+          6 19 6 4 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          0 6 24 2 -1.</_>
+          0 15 10 6 -1.</_>
         <_>
-          0 6 12 1 2.</_>
+          0 17 10 2 3.</_></rects>
+      <tilted>0</tilted></_>
+    <_>
+      <rects>
         <_>
-          12 7 12 1 2.</_></rects>
+          0 16 12 8 -1.</_>
+        <_>
+          0 16 6 4 2.</_>
+        <_>
+          6 20 6 4 2.</_></rects>
+      <tilted>0</tilted></_>
+    <_>
+      <rects>
+        <_>
+          0 17 3 7 -1.</_>
+        <_>
+          1 17 1 7 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          0 6 18 8 -1.</_>
+          0 18 6 3 -1.</_>
         <_>
-          0 10 18 4 2.</_></rects>
+          0 19 6 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          0 6 24 3 -1.</_>
+          0 19 6 3 -1.</_>
         <_>
-          0 7 24 1 3.</_></rects>
+          0 20 6 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          0 7 8 2 -1.</_>
+          0 20 6 3 -1.</_>
+        <_>
+          0 21 6 1 3.</_></rects>
+      <tilted>0</tilted></_>
+    <_>
+      <rects>
         <_>
-          0 7 4 1 2.</_>
+          0 21 4 3 -1.</_>
         <_>
-          4 8 4 1 2.</_></rects>
+          0 22 4 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          0 7 9 6 -1.</_>
+          0 21 5 3 -1.</_>
         <_>
-          0 9 9 2 3.</_></rects>
+          0 22 5 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          0 7 22 4 -1.</_>
+          0 22 22 2 -1.</_>
+        <_>
+          11 22 11 2 2.</_></rects>
+      <tilted>0</tilted></_>
+    <_>
+      <rects>
         <_>
-          0 7 11 2 2.</_>
+          1 0 6 1 -1.</_>
         <_>
-          11 9 11 2 2.</_></rects>
+          4 0 3 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          0 7 24 2 -1.</_>
+          1 0 15 13 -1.</_>
         <_>
-          0 7 12 1 2.</_>
+          6 0 5 13 3.</_></rects>
+      <tilted>0</tilted></_>
+    <_>
+      <rects>
         <_>
-          12 8 12 1 2.</_></rects>
+          1 0 12 6 -1.</_>
+        <_>
+          1 0 6 3 2.</_>
+        <_>
+          7 3 6 3 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          0 7 24 4 -1.</_>
+          1 1 22 2 -1.</_>
         <_>
-          0 7 12 2 2.</_>
+          1 1 11 1 2.</_>
         <_>
-          12 9 12 2 2.</_></rects>
+          12 2 11 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          0 7 20 6 -1.</_>
+          1 2 23 9 -1.</_>
         <_>
-          0 9 20 2 3.</_></rects>
+          1 5 23 3 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          0 8 6 14 -1.</_>
+          1 3 4 3 -1.</_>
         <_>
-          3 8 3 14 2.</_></rects>
+          1 4 4 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          0 8 8 2 -1.</_>
+          1 3 12 18 -1.</_>
         <_>
-          0 8 4 1 2.</_>
+          5 3 4 18 3.</_></rects>
+      <tilted>0</tilted></_>
+    <_>
+      <rects>
+        <_>
+          1 4 8 3 -1.</_>
         <_>
-          4 9 4 1 2.</_></rects>
+          1 5 8 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          0 8 24 1 -1.</_>
+          1 4 23 6 -1.</_>
         <_>
-          8 8 8 1 3.</_></rects>
+          1 6 23 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          0 8 24 2 -1.</_>
+          1 6 6 4 -1.</_>
         <_>
-          0 8 12 1 2.</_>
+          1 6 3 2 2.</_>
         <_>
-          12 9 12 1 2.</_></rects>
+          4 8 3 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          0 8 24 4 -1.</_>
+          1 6 3 9 -1.</_>
         <_>
-          0 8 12 2 2.</_>
+          1 9 3 3 3.</_></rects>
+      <tilted>0</tilted></_>
+    <_>
+      <rects>
         <_>
-          12 10 12 2 2.</_></rects>
+          1 6 4 3 -1.</_>
+        <_>
+          1 7 4 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          0 8 24 9 -1.</_>
+          1 6 22 2 -1.</_>
+        <_>
+          1 6 11 1 2.</_>
         <_>
-          12 8 12 9 2.</_></rects>
+          12 7 11 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          0 9 4 1 -1.</_>
+          1 6 12 8 -1.</_>
         <_>
-          2 9 2 1 2.</_></rects>
+          1 10 12 4 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          0 9 6 12 -1.</_>
+          1 7 8 4 -1.</_>
         <_>
-          0 9 3 6 2.</_>
+          1 7 4 2 2.</_>
         <_>
-          3 15 3 6 2.</_></rects>
+          5 9 4 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          0 9 4 9 -1.</_>
+          1 7 20 4 -1.</_>
         <_>
-          0 12 4 3 3.</_></rects>
+          1 7 10 2 2.</_>
+        <_>
+          11 9 10 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          0 9 7 2 -1.</_>
+          1 7 22 6 -1.</_>
         <_>
-          0 10 7 1 2.</_></rects>
+          1 7 11 3 2.</_>
+        <_>
+          12 10 11 3 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          0 9 11 2 -1.</_>
+          1 7 22 14 -1.</_>
         <_>
-          0 10 11 1 2.</_></rects>
+          12 7 11 14 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          0 9 22 2 -1.</_>
+          1 8 1 2 -1.</_>
         <_>
-          0 9 11 1 2.</_>
+          1 9 1 1 2.</_></rects>
+      <tilted>0</tilted></_>
+    <_>
+      <rects>
         <_>
-          11 10 11 1 2.</_></rects>
+          1 8 8 2 -1.</_>
+        <_>
+          1 8 4 1 2.</_>
+        <_>
+          5 9 4 1 2.</_></rects>
+      <tilted>0</tilted></_>
+    <_>
+      <rects>
+        <_>
+          1 8 7 4 -1.</_>
+        <_>
+          1 10 7 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          0 9 24 2 -1.</_>
+          1 8 22 4 -1.</_>
         <_>
-          0 9 12 1 2.</_>
+          1 8 11 2 2.</_>
         <_>
-          12 10 12 1 2.</_></rects>
+          12 10 11 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          0 9 24 4 -1.</_>
+          1 9 4 3 -1.</_>
         <_>
-          0 9 12 2 2.</_>
+          3 9 2 3 2.</_></rects>
+      <tilted>0</tilted></_>
+    <_>
+      <rects>
         <_>
-          12 11 12 2 2.</_></rects>
+          1 9 4 6 -1.</_>
+        <_>
+          1 11 4 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          0 9 24 6 -1.</_>
+          1 9 20 2 -1.</_>
         <_>
-          0 9 12 3 2.</_>
+          1 9 10 1 2.</_>
         <_>
-          12 12 12 3 2.</_></rects>
+          11 10 10 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          0 9 15 3 -1.</_>
+          1 10 3 13 -1.</_>
         <_>
-          0 10 15 1 3.</_></rects>
+          2 10 1 13 3.</_></rects>
+      <tilted>0</tilted></_>
+    <_>
+      <rects>
+        <_>
+          1 10 4 6 -1.</_>
+        <_>
+          1 12 4 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          0 10 2 2 -1.</_>
+          1 10 8 3 -1.</_>
+        <_>
+          1 11 8 1 3.</_></rects>
+      <tilted>0</tilted></_>
+    <_>
+      <rects>
+        <_>
+          1 10 20 2 -1.</_>
+        <_>
+          1 10 10 1 2.</_>
         <_>
-          0 11 2 1 2.</_></rects>
+          11 11 10 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          0 10 3 3 -1.</_>
+          1 11 6 2 -1.</_>
         <_>
-          0 11 3 1 3.</_></rects>
+          4 11 3 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          0 10 3 6 -1.</_>
+          1 11 22 2 -1.</_>
+        <_>
+          1 11 11 1 2.</_>
         <_>
-          0 12 3 2 3.</_></rects>
+          12 12 11 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          0 10 6 8 -1.</_>
+          1 12 3 8 -1.</_>
+        <_>
+          2 12 1 8 3.</_></rects>
+      <tilted>0</tilted></_>
+    <_>
+      <rects>
         <_>
-          0 10 3 4 2.</_>
+          1 12 4 1 -1.</_>
         <_>
-          3 14 3 4 2.</_></rects>
+          3 12 2 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          0 10 8 10 -1.</_>
+          1 12 20 2 -1.</_>
         <_>
-          0 10 4 5 2.</_>
+          1 12 10 1 2.</_>
         <_>
-          4 15 4 5 2.</_></rects>
+          11 13 10 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          0 10 8 11 -1.</_>
+          1 13 3 8 -1.</_>
         <_>
-          4 10 4 11 2.</_></rects>
+          2 13 1 8 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          0 10 24 2 -1.</_>
+          1 13 9 3 -1.</_>
         <_>
-          0 10 12 1 2.</_>
+          1 14 9 1 3.</_></rects>
+      <tilted>0</tilted></_>
+    <_>
+      <rects>
         <_>
-          12 11 12 1 2.</_></rects>
+          1 13 21 8 -1.</_>
+        <_>
+          1 17 21 4 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          0 11 6 2 -1.</_>
+          1 15 8 2 -1.</_>
         <_>
-          3 11 3 2 2.</_></rects>
+          5 15 4 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          0 11 6 8 -1.</_>
+          1 17 22 2 -1.</_>
         <_>
-          0 11 3 4 2.</_>
+          1 17 11 1 2.</_>
         <_>
-          3 15 3 4 2.</_></rects>
+          12 18 11 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          0 11 8 8 -1.</_>
+          1 18 3 6 -1.</_>
         <_>
-          0 11 4 4 2.</_>
+          2 18 1 6 3.</_></rects>
+      <tilted>0</tilted></_>
+    <_>
+      <rects>
+        <_>
+          2 0 6 1 -1.</_>
         <_>
-          4 15 4 4 2.</_></rects>
+          5 0 3 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          0 11 8 13 -1.</_>
+          2 0 8 6 -1.</_>
         <_>
-          4 11 4 13 2.</_></rects>
+          2 0 4 3 2.</_>
+        <_>
+          6 3 4 3 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          0 11 24 2 -1.</_>
+          2 0 12 5 -1.</_>
         <_>
-          0 11 12 1 2.</_>
+          8 0 6 5 2.</_></rects>
+      <tilted>0</tilted></_>
+    <_>
+      <rects>
         <_>
-          12 12 12 1 2.</_></rects>
+          2 3 20 2 -1.</_>
+        <_>
+          2 3 10 1 2.</_>
+        <_>
+          12 4 10 1 2.</_></rects>
+      <tilted>0</tilted></_>
+    <_>
+      <rects>
+        <_>
+          2 4 3 3 -1.</_>
+        <_>
+          2 5 3 1 3.</_></rects>
+      <tilted>0</tilted></_>
+    <_>
+      <rects>
+        <_>
+          2 4 20 2 -1.</_>
+        <_>
+          2 4 10 1 2.</_>
+        <_>
+          12 5 10 1 2.</_></rects>
+      <tilted>0</tilted></_>
+    <_>
+      <rects>
+        <_>
+          2 5 1 3 -1.</_>
+        <_>
+          2 6 1 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          0 11 21 10 -1.</_>
+          2 5 2 3 -1.</_>
         <_>
-          0 16 21 5 2.</_></rects>
+          2 6 2 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          0 12 8 4 -1.</_>
+          2 5 20 2 -1.</_>
         <_>
-          4 12 4 4 2.</_></rects>
+          2 5 10 1 2.</_>
+        <_>
+          12 6 10 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          0 12 24 9 -1.</_>
+          2 6 22 2 -1.</_>
+        <_>
+          2 6 11 1 2.</_>
         <_>
-          12 12 12 9 2.</_></rects>
+          13 7 11 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          0 13 24 4 -1.</_>
+          2 6 22 4 -1.</_>
         <_>
-          0 13 12 2 2.</_>
+          2 6 11 2 2.</_>
         <_>
-          12 15 12 2 2.</_></rects>
+          13 8 11 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          0 14 3 7 -1.</_>
+          2 7 15 3 -1.</_>
         <_>
-          1 14 1 7 3.</_></rects>
+          2 8 15 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          0 14 10 8 -1.</_>
+          2 8 8 3 -1.</_>
         <_>
-          5 14 5 8 2.</_></rects>
+          2 9 8 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          0 15 8 8 -1.</_>
+          2 8 20 4 -1.</_>
         <_>
-          0 15 4 4 2.</_>
+          2 8 10 2 2.</_>
         <_>
-          4 19 4 4 2.</_></rects>
+          12 10 10 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          0 15 12 8 -1.</_>
+          2 9 20 8 -1.</_>
         <_>
-          0 15 6 4 2.</_>
+          2 9 10 4 2.</_>
         <_>
-          6 19 6 4 2.</_></rects>
+          12 13 10 4 2.</_></rects>
+      <tilted>0</tilted></_>
+    <_>
+      <rects>
+        <_>
+          2 9 22 2 -1.</_>
+        <_>
+          2 9 11 1 2.</_>
+        <_>
+          13 10 11 1 2.</_></rects>
+      <tilted>0</tilted></_>
+    <_>
+      <rects>
+        <_>
+          2 9 19 3 -1.</_>
+        <_>
+          2 10 19 1 3.</_></rects>
+      <tilted>0</tilted></_>
+    <_>
+      <rects>
+        <_>
+          2 10 4 1 -1.</_>
+        <_>
+          4 10 2 1 2.</_></rects>
+      <tilted>0</tilted></_>
+    <_>
+      <rects>
+        <_>
+          2 10 22 2 -1.</_>
+        <_>
+          2 10 11 1 2.</_>
+        <_>
+          13 11 11 1 2.</_></rects>
+      <tilted>0</tilted></_>
+    <_>
+      <rects>
+        <_>
+          2 10 22 14 -1.</_>
+        <_>
+          13 10 11 14 2.</_></rects>
+      <tilted>0</tilted></_>
+    <_>
+      <rects>
+        <_>
+          2 10 20 12 -1.</_>
+        <_>
+          2 16 20 6 2.</_></rects>
+      <tilted>0</tilted></_>
+    <_>
+      <rects>
+        <_>
+          2 11 3 5 -1.</_>
+        <_>
+          3 11 1 5 3.</_></rects>
+      <tilted>0</tilted></_>
+    <_>
+      <rects>
+        <_>
+          2 11 20 2 -1.</_>
+        <_>
+          2 11 10 1 2.</_>
+        <_>
+          12 12 10 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          0 16 3 8 -1.</_>
+          2 11 22 2 -1.</_>
+        <_>
+          2 11 11 1 2.</_>
         <_>
-          1 16 1 8 3.</_></rects>
+          13 12 11 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          0 16 8 6 -1.</_>
+          2 12 3 5 -1.</_>
         <_>
-          0 18 8 2 3.</_></rects>
+          3 12 1 5 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          0 17 6 3 -1.</_>
+          2 12 3 9 -1.</_>
         <_>
-          3 17 3 3 2.</_></rects>
+          3 12 1 9 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          0 17 4 6 -1.</_>
+          2 12 3 11 -1.</_>
         <_>
-          0 19 4 2 3.</_></rects>
+          3 12 1 11 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          0 18 3 6 -1.</_>
+          2 14 3 3 -1.</_>
         <_>
-          1 18 1 6 3.</_></rects>
+          3 14 1 3 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          0 19 3 4 -1.</_>
+          2 14 8 8 -1.</_>
+        <_>
+          2 14 4 4 2.</_>
         <_>
-          1 19 1 4 3.</_></rects>
+          6 18 4 4 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          0 19 9 3 -1.</_>
+          2 17 3 5 -1.</_>
         <_>
-          0 20 9 1 3.</_></rects>
+          3 17 1 5 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          0 20 4 3 -1.</_>
+          2 17 3 6 -1.</_>
         <_>
-          0 21 4 1 3.</_></rects>
+          3 17 1 6 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          0 20 6 3 -1.</_>
+          2 17 21 4 -1.</_>
         <_>
-          0 21 6 1 3.</_></rects>
+          9 17 7 4 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          0 21 3 3 -1.</_>
+          2 18 3 5 -1.</_>
         <_>
-          0 22 3 1 3.</_></rects>
+          3 18 1 5 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          0 22 1 2 -1.</_>
+          2 18 10 4 -1.</_>
         <_>
-          0 23 1 1 2.</_></rects>
+          7 18 5 4 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          1 0 10 1 -1.</_>
+          2 20 6 2 -1.</_>
         <_>
-          6 0 5 1 2.</_></rects>
+          5 20 3 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          1 0 12 6 -1.</_>
-        <_>
-          1 0 6 3 2.</_>
+          2 21 12 2 -1.</_>
         <_>
-          7 3 6 3 2.</_></rects>
+          8 21 6 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          1 0 7 9 -1.</_>
+          3 0 3 5 -1.</_>
         <_>
-          1 3 7 3 3.</_></rects>
+          4 0 1 5 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          1 0 14 10 -1.</_>
+          3 0 9 22 -1.</_>
         <_>
-          1 0 7 5 2.</_>
-        <_>
-          8 5 7 5 2.</_></rects>
+          6 0 3 22 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          1 0 22 2 -1.</_>
+          3 0 12 4 -1.</_>
         <_>
-          1 0 11 1 2.</_>
+          3 0 6 2 2.</_>
         <_>
-          12 1 11 1 2.</_></rects>
+          9 2 6 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          1 2 6 10 -1.</_>
+          3 1 3 3 -1.</_>
         <_>
-          1 2 3 5 2.</_>
-        <_>
-          4 7 3 5 2.</_></rects>
+          4 1 1 3 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          1 2 22 20 -1.</_>
+          3 1 3 20 -1.</_>
         <_>
-          12 2 11 20 2.</_></rects>
+          4 1 1 20 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          1 2 22 21 -1.</_>
+          3 1 6 20 -1.</_>
         <_>
-          12 2 11 21 2.</_></rects>
+          5 1 2 20 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          1 3 15 3 -1.</_>
+          3 2 3 3 -1.</_>
         <_>
-          6 3 5 3 3.</_></rects>
+          4 2 1 3 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          1 3 6 3 -1.</_>
+          3 3 3 3 -1.</_>
         <_>
-          1 4 6 1 3.</_></rects>
+          4 3 1 3 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          1 3 22 2 -1.</_>
-        <_>
-          1 3 11 1 2.</_>
+          3 3 3 9 -1.</_>
         <_>
-          12 4 11 1 2.</_></rects>
+          3 6 3 3 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          1 4 4 3 -1.</_>
+          3 3 20 19 -1.</_>
         <_>
-          1 5 4 1 3.</_></rects>
+          13 3 10 19 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          1 4 12 17 -1.</_>
+          3 3 19 4 -1.</_>
         <_>
-          5 4 4 17 3.</_></rects>
+          3 5 19 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          1 4 20 20 -1.</_>
+          3 4 1 3 -1.</_>
         <_>
-          11 4 10 20 2.</_></rects>
+          3 5 1 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          1 4 22 2 -1.</_>
+          3 4 6 3 -1.</_>
         <_>
-          1 4 11 1 2.</_>
-        <_>
-          12 5 11 1 2.</_></rects>
+          5 4 2 3 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          1 4 22 19 -1.</_>
+          3 4 18 2 -1.</_>
+        <_>
+          3 4 9 1 2.</_>
         <_>
-          12 4 11 19 2.</_></rects>
+          12 5 9 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          1 5 22 2 -1.</_>
-        <_>
-          1 5 11 1 2.</_>
+          3 4 16 6 -1.</_>
         <_>
-          12 6 11 1 2.</_></rects>
+          3 6 16 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          1 6 2 2 -1.</_>
+          3 5 3 1 -1.</_>
         <_>
-          1 6 1 1 2.</_>
-        <_>
-          2 7 1 1 2.</_></rects>
+          4 5 1 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          1 6 16 17 -1.</_>
+          3 5 3 2 -1.</_>
         <_>
-          9 6 8 17 2.</_></rects>
+          4 5 1 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          1 6 21 9 -1.</_>
+          3 5 2 3 -1.</_>
         <_>
-          1 9 21 3 3.</_></rects>
+          3 6 2 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          1 6 22 6 -1.</_>
+          3 5 10 3 -1.</_>
         <_>
-          1 8 22 2 3.</_></rects>
+          8 5 5 3 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          1 6 23 9 -1.</_>
+          3 5 18 3 -1.</_>
         <_>
-          1 9 23 3 3.</_></rects>
+          9 5 6 3 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          1 7 22 6 -1.</_>
+          3 5 18 2 -1.</_>
         <_>
-          1 7 11 3 2.</_>
+          3 5 9 1 2.</_>
         <_>
-          12 10 11 3 2.</_></rects>
+          12 6 9 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          1 8 19 12 -1.</_>
+          3 6 2 1 -1.</_>
         <_>
-          1 12 19 4 3.</_></rects>
+          4 6 1 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          1 9 6 2 -1.</_>
+          3 6 1 3 -1.</_>
         <_>
-          4 9 3 2 2.</_></rects>
+          3 7 1 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          1 9 12 3 -1.</_>
+          3 6 3 3 -1.</_>
         <_>
-          5 9 4 3 3.</_></rects>
+          3 7 3 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          1 10 3 8 -1.</_>
+          3 6 6 6 -1.</_>
         <_>
-          2 10 1 8 3.</_></rects>
+          3 8 6 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          1 10 20 2 -1.</_>
+          3 6 18 2 -1.</_>
         <_>
-          1 10 10 1 2.</_>
+          3 6 9 1 2.</_>
         <_>
-          11 11 10 1 2.</_></rects>
+          12 7 9 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          1 10 12 3 -1.</_>
+          3 6 17 6 -1.</_>
         <_>
-          1 11 12 1 3.</_></rects>
+          3 8 17 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          1 11 3 8 -1.</_>
+          3 7 3 1 -1.</_>
         <_>
-          2 11 1 8 3.</_></rects>
+          4 7 1 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          1 11 20 2 -1.</_>
+          3 7 4 2 -1.</_>
         <_>
-          1 11 10 1 2.</_>
-        <_>
-          11 12 10 1 2.</_></rects>
+          3 8 4 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          1 11 22 4 -1.</_>
-        <_>
-          1 11 11 2 2.</_>
+          3 7 6 6 -1.</_>
         <_>
-          12 13 11 2 2.</_></rects>
+          3 9 6 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          1 12 3 11 -1.</_>
+          3 7 18 4 -1.</_>
+        <_>
+          3 7 9 2 2.</_>
         <_>
-          2 12 1 11 3.</_></rects>
+          12 9 9 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          1 12 6 1 -1.</_>
+          3 7 20 11 -1.</_>
         <_>
-          4 12 3 1 2.</_></rects>
+          13 7 10 11 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          1 12 20 12 -1.</_>
+          3 7 17 6 -1.</_>
         <_>
-          11 12 10 12 2.</_></rects>
+          3 9 17 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          1 13 3 5 -1.</_>
+          3 9 3 1 -1.</_>
         <_>
-          2 13 1 5 3.</_></rects>
+          4 9 1 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          1 13 22 2 -1.</_>
-        <_>
-          1 13 11 1 2.</_>
+          3 9 3 2 -1.</_>
         <_>
-          12 14 11 1 2.</_></rects>
+          4 9 1 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          1 14 4 4 -1.</_>
+          3 9 9 2 -1.</_>
         <_>
-          3 14 2 4 2.</_></rects>
+          6 9 3 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          1 14 22 2 -1.</_>
+          3 9 18 2 -1.</_>
         <_>
-          1 14 11 1 2.</_>
+          3 9 9 1 2.</_>
         <_>
-          12 15 11 1 2.</_></rects>
+          12 10 9 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          1 14 23 6 -1.</_>
+          3 10 3 1 -1.</_>
         <_>
-          1 17 23 3 2.</_></rects>
+          4 10 1 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          1 15 14 2 -1.</_>
+          3 10 3 13 -1.</_>
         <_>
-          1 15 7 1 2.</_>
-        <_>
-          8 16 7 1 2.</_></rects>
+          4 10 1 13 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          1 17 3 5 -1.</_>
+          3 10 6 2 -1.</_>
         <_>
-          2 17 1 5 3.</_></rects>
+          3 11 6 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          1 17 3 7 -1.</_>
+          3 11 3 2 -1.</_>
         <_>
-          2 17 1 7 3.</_></rects>
+          4 11 1 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          1 18 10 6 -1.</_>
-        <_>
-          1 18 5 3 2.</_>
+          3 11 3 3 -1.</_>
         <_>
-          6 21 5 3 2.</_></rects>
+          4 11 1 3 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          1 18 9 3 -1.</_>
+          3 11 3 5 -1.</_>
         <_>
-          1 19 9 1 3.</_></rects>
+          4 11 1 5 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          1 21 12 3 -1.</_>
+          3 11 3 13 -1.</_>
         <_>
-          7 21 6 3 2.</_></rects>
+          4 11 1 13 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          2 0 3 2 -1.</_>
+          3 11 6 2 -1.</_>
         <_>
-          3 0 1 2 3.</_></rects>
-      <tilted>0</tilted></_>
-    <_>
-      <rects>
-        <_>
-          2 0 6 1 -1.</_>
+          3 11 3 1 2.</_>
         <_>
-          5 0 3 1 2.</_></rects>
+          6 12 3 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          2 0 9 2 -1.</_>
+          3 11 3 4 -1.</_>
         <_>
-          5 0 3 2 3.</_></rects>
+          3 13 3 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          2 0 21 1 -1.</_>
+          3 11 4 8 -1.</_>
         <_>
-          9 0 7 1 3.</_></rects>
+          3 15 4 4 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          2 1 3 23 -1.</_>
+          3 12 3 3 -1.</_>
         <_>
-          3 1 1 23 3.</_></rects>
+          4 12 1 3 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          2 1 4 2 -1.</_>
+          3 12 3 6 -1.</_>
         <_>
-          4 1 2 2 2.</_></rects>
+          3 15 3 3 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          2 2 22 10 -1.</_>
+          3 12 9 7 -1.</_>
         <_>
-          2 2 11 5 2.</_>
-        <_>
-          13 7 11 5 2.</_></rects>
+          6 12 3 7 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          2 3 22 2 -1.</_>
-        <_>
-          2 3 11 1 2.</_>
+          3 12 4 8 -1.</_>
         <_>
-          13 4 11 1 2.</_></rects>
+          3 16 4 4 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          2 4 6 1 -1.</_>
+          3 12 8 8 -1.</_>
         <_>
-          5 4 3 1 2.</_></rects>
+          3 16 8 4 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          2 4 3 3 -1.</_>
+          3 12 19 6 -1.</_>
         <_>
-          2 5 3 1 3.</_></rects>
+          3 15 19 3 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          2 4 20 2 -1.</_>
+          3 13 18 2 -1.</_>
         <_>
-          2 4 10 1 2.</_>
+          3 13 9 1 2.</_>
         <_>
-          12 5 10 1 2.</_></rects>
+          12 14 9 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          2 4 22 16 -1.</_>
+          3 15 4 2 -1.</_>
         <_>
-          13 4 11 16 2.</_></rects>
+          5 15 2 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          2 4 18 6 -1.</_>
+          3 15 4 3 -1.</_>
         <_>
-          2 6 18 2 3.</_></rects>
+          5 15 2 3 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          2 6 3 3 -1.</_>
+          3 15 6 2 -1.</_>
         <_>
-          2 7 3 1 3.</_></rects>
+          6 15 3 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          2 6 4 3 -1.</_>
+          3 16 8 8 -1.</_>
+        <_>
+          3 16 4 4 2.</_>
         <_>
-          2 7 4 1 3.</_></rects>
+          7 20 4 4 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          2 6 20 2 -1.</_>
+          3 20 3 4 -1.</_>
         <_>
-          2 6 10 1 2.</_>
-        <_>
-          12 7 10 1 2.</_></rects>
+          4 20 1 4 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          2 6 22 2 -1.</_>
-        <_>
-          2 6 11 1 2.</_>
+          4 1 3 8 -1.</_>
         <_>
-          13 7 11 1 2.</_></rects>
+          5 1 1 8 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          2 7 21 6 -1.</_>
+          4 1 3 12 -1.</_>
         <_>
-          2 9 21 2 3.</_></rects>
+          4 5 3 4 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          2 7 22 2 -1.</_>
+          4 1 15 10 -1.</_>
         <_>
-          2 8 22 1 2.</_></rects>
+          4 6 15 5 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          2 8 6 2 -1.</_>
-        <_>
-          2 8 3 1 2.</_>
+          4 2 3 3 -1.</_>
         <_>
-          5 9 3 1 2.</_></rects>
+          5 2 1 3 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          2 8 6 3 -1.</_>
+          4 2 6 5 -1.</_>
         <_>
-          2 9 6 1 3.</_></rects>
+          6 2 2 5 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          2 8 21 2 -1.</_>
+          4 2 16 2 -1.</_>
         <_>
-          9 8 7 2 3.</_></rects>
+          4 2 8 1 2.</_>
+        <_>
+          12 3 8 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          2 8 7 9 -1.</_>
+          4 3 3 2 -1.</_>
         <_>
-          2 11 7 3 3.</_></rects>
+          5 3 1 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          2 8 22 4 -1.</_>
-        <_>
-          2 8 11 2 2.</_>
+          4 3 6 1 -1.</_>
         <_>
-          13 10 11 2 2.</_></rects>
+          6 3 2 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          2 9 4 1 -1.</_>
+          4 3 6 5 -1.</_>
         <_>
-          4 9 2 1 2.</_></rects>
+          6 3 2 5 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          2 9 9 1 -1.</_>
+          4 3 9 3 -1.</_>
         <_>
-          5 9 3 1 3.</_></rects>
+          7 3 3 3 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          2 9 9 2 -1.</_>
+          4 3 16 2 -1.</_>
         <_>
-          5 9 3 2 3.</_></rects>
+          4 3 8 1 2.</_>
+        <_>
+          12 4 8 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          2 9 6 4 -1.</_>
+          4 3 16 8 -1.</_>
         <_>
-          2 9 3 2 2.</_>
+          4 3 8 4 2.</_>
         <_>
-          5 11 3 2 2.</_></rects>
+          12 7 8 4 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          2 9 7 3 -1.</_>
+          4 3 17 8 -1.</_>
         <_>
-          2 10 7 1 3.</_></rects>
+          4 7 17 4 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          2 9 18 2 -1.</_>
+          4 4 1 4 -1.</_>
         <_>
-          2 9 9 1 2.</_>
-        <_>
-          11 10 9 1 2.</_></rects>
+          4 6 1 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          2 9 22 2 -1.</_>
+          4 4 16 2 -1.</_>
         <_>
-          2 9 11 1 2.</_>
+          4 4 8 1 2.</_>
         <_>
-          13 10 11 1 2.</_></rects>
+          12 5 8 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          2 9 21 3 -1.</_>
+          4 4 16 10 -1.</_>
         <_>
-          2 10 21 1 3.</_></rects>
+          4 4 8 5 2.</_>
+        <_>
+          12 9 8 5 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          2 10 22 2 -1.</_>
-        <_>
-          2 10 11 1 2.</_>
+          4 4 20 6 -1.</_>
         <_>
-          13 11 11 1 2.</_></rects>
+          4 6 20 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          2 11 3 6 -1.</_>
+          4 5 16 2 -1.</_>
+        <_>
+          4 5 8 1 2.</_>
         <_>
-          3 11 1 6 3.</_></rects>
+          12 6 8 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          2 11 3 13 -1.</_>
+          4 5 16 9 -1.</_>
         <_>
-          3 11 1 13 3.</_></rects>
+          4 8 16 3 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          2 11 22 2 -1.</_>
+          4 6 2 2 -1.</_>
         <_>
-          2 11 11 1 2.</_>
+          4 6 1 1 2.</_>
         <_>
-          13 12 11 1 2.</_></rects>
+          5 7 1 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          2 12 3 4 -1.</_>
+          4 6 2 2 -1.</_>
         <_>
-          3 12 1 4 3.</_></rects>
+          4 7 2 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          2 12 3 5 -1.</_>
+          4 6 6 1 -1.</_>
         <_>
-          3 12 1 5 3.</_></rects>
+          6 6 2 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          2 12 22 2 -1.</_>
-        <_>
-          2 12 11 1 2.</_>
+          4 6 2 3 -1.</_>
         <_>
-          13 13 11 1 2.</_></rects>
+          4 7 2 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          2 13 10 10 -1.</_>
-        <_>
-          2 13 5 5 2.</_>
+          4 6 3 3 -1.</_>
         <_>
-          7 18 5 5 2.</_></rects>
+          4 7 3 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          2 14 6 10 -1.</_>
+          4 6 16 2 -1.</_>
         <_>
-          2 14 3 5 2.</_>
+          4 6 8 1 2.</_>
         <_>
-          5 19 3 5 2.</_></rects>
+          12 7 8 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          2 15 2 6 -1.</_>
+          4 6 15 6 -1.</_>
         <_>
-          2 15 1 3 2.</_>
-        <_>
-          3 18 1 3 2.</_></rects>
+          4 8 15 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          2 15 3 9 -1.</_>
+          4 7 2 3 -1.</_>
         <_>
-          3 15 1 9 3.</_></rects>
+          4 8 2 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          2 15 6 4 -1.</_>
+          4 7 4 3 -1.</_>
         <_>
-          5 15 3 4 2.</_></rects>
+          6 7 2 3 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          2 15 7 3 -1.</_>
+          4 7 4 3 -1.</_>
         <_>
-          2 16 7 1 3.</_></rects>
+          4 8 4 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          2 17 3 4 -1.</_>
+          4 7 5 3 -1.</_>
         <_>
-          3 17 1 4 3.</_></rects>
+          4 8 5 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          2 17 12 6 -1.</_>
-        <_>
-          2 17 6 3 2.</_>
+          4 7 5 6 -1.</_>
         <_>
-          8 20 6 3 2.</_></rects>
+          4 9 5 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          2 21 14 3 -1.</_>
+          4 7 7 3 -1.</_>
         <_>
-          9 21 7 3 2.</_></rects>
+          4 8 7 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          3 0 12 4 -1.</_>
+          4 7 18 2 -1.</_>
         <_>
-          3 0 6 2 2.</_>
+          4 7 9 1 2.</_>
         <_>
-          9 2 6 2 2.</_></rects>
+          13 8 9 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          3 1 18 2 -1.</_>
+          4 7 18 4 -1.</_>
         <_>
-          3 1 9 1 2.</_>
+          4 7 9 2 2.</_>
         <_>
-          12 2 9 1 2.</_></rects>
+          13 9 9 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          3 2 17 6 -1.</_>
+          4 7 16 3 -1.</_>
         <_>
-          3 5 17 3 2.</_></rects>
+          4 8 16 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          3 3 3 3 -1.</_>
+          4 7 16 6 -1.</_>
         <_>
-          4 3 1 3 3.</_></rects>
+          4 9 16 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          3 3 18 2 -1.</_>
+          4 7 17 2 -1.</_>
         <_>
-          3 3 9 1 2.</_>
-        <_>
-          12 4 9 1 2.</_></rects>
+          4 8 17 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          3 4 1 3 -1.</_>
+          4 7 17 3 -1.</_>
         <_>
-          3 5 1 1 3.</_></rects>
+          4 8 17 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          3 4 2 2 -1.</_>
-        <_>
-          3 4 1 1 2.</_>
+          4 7 17 6 -1.</_>
         <_>
-          4 5 1 1 2.</_></rects>
+          4 9 17 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          3 4 3 3 -1.</_>
+          4 8 2 2 -1.</_>
+        <_>
+          4 8 1 1 2.</_>
         <_>
-          3 5 3 1 3.</_></rects>
+          5 9 1 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          3 4 18 2 -1.</_>
+          4 8 16 2 -1.</_>
         <_>
-          3 4 9 1 2.</_>
+          4 8 8 1 2.</_>
         <_>
-          12 5 9 1 2.</_></rects>
+          12 9 8 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          3 4 18 4 -1.</_>
+          4 8 18 4 -1.</_>
         <_>
-          3 4 9 2 2.</_>
+          4 8 9 2 2.</_>
         <_>
-          12 6 9 2 2.</_></rects>
+          13 10 9 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          3 4 20 6 -1.</_>
+          4 9 2 1 -1.</_>
         <_>
-          3 6 20 2 3.</_></rects>
+          5 9 1 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          3 5 2 1 -1.</_>
+          4 9 3 1 -1.</_>
         <_>
-          4 5 1 1 2.</_></rects>
+          5 9 1 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          3 5 1 3 -1.</_>
+          4 9 2 2 -1.</_>
         <_>
-          3 6 1 1 3.</_></rects>
+          4 9 1 1 2.</_>
+        <_>
+          5 10 1 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          3 5 2 2 -1.</_>
+          4 9 2 2 -1.</_>
         <_>
-          3 6 2 1 2.</_></rects>
+          5 9 1 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          3 5 2 3 -1.</_>
+          4 9 6 1 -1.</_>
         <_>
-          3 6 2 1 3.</_></rects>
+          6 9 2 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          3 5 20 2 -1.</_>
+          4 9 2 9 -1.</_>
         <_>
-          3 5 10 1 2.</_>
-        <_>
-          13 6 10 1 2.</_></rects>
+          4 12 2 3 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          3 5 17 6 -1.</_>
+          4 9 15 1 -1.</_>
         <_>
-          3 7 17 2 3.</_></rects>
+          9 9 5 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          3 5 17 9 -1.</_>
+          4 9 5 3 -1.</_>
         <_>
-          3 8 17 3 3.</_></rects>
+          4 10 5 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          3 5 19 9 -1.</_>
+          4 9 15 2 -1.</_>
         <_>
-          3 8 19 3 3.</_></rects>
+          9 9 5 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          3 6 2 2 -1.</_>
-        <_>
-          3 6 1 1 2.</_>
+          4 9 15 3 -1.</_>
         <_>
-          4 7 1 1 2.</_></rects>
+          9 9 5 3 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          3 6 2 3 -1.</_>
+          4 9 16 2 -1.</_>
+        <_>
+          4 9 8 1 2.</_>
         <_>
-          3 7 2 1 3.</_></rects>
+          12 10 8 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          3 6 9 6 -1.</_>
+          4 9 16 6 -1.</_>
         <_>
-          6 6 3 6 3.</_></rects>
+          4 9 8 3 2.</_>
+        <_>
+          12 12 8 3 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          3 6 5 6 -1.</_>
+          4 9 18 2 -1.</_>
+        <_>
+          4 9 9 1 2.</_>
         <_>
-          3 8 5 2 3.</_></rects>
+          13 10 9 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          3 6 18 2 -1.</_>
+          4 9 20 2 -1.</_>
         <_>
-          3 6 9 1 2.</_>
+          4 9 10 1 2.</_>
         <_>
-          12 7 9 1 2.</_></rects>
+          14 10 10 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          3 6 20 8 -1.</_>
-        <_>
-          3 6 10 4 2.</_>
+          4 9 17 9 -1.</_>
         <_>
-          13 10 10 4 2.</_></rects>
+          4 12 17 3 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          3 6 18 3 -1.</_>
+          4 9 18 3 -1.</_>
         <_>
-          3 7 18 1 3.</_></rects>
+          4 10 18 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          3 7 6 10 -1.</_>
-        <_>
-          3 7 3 5 2.</_>
+          4 10 2 1 -1.</_>
         <_>
-          6 12 3 5 2.</_></rects>
+          5 10 1 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          3 7 5 2 -1.</_>
+          4 10 3 1 -1.</_>
         <_>
-          3 8 5 1 2.</_></rects>
+          5 10 1 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          3 7 6 3 -1.</_>
+          4 10 2 2 -1.</_>
+        <_>
+          4 10 1 1 2.</_>
         <_>
-          3 8 6 1 3.</_></rects>
+          5 11 1 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          3 7 18 4 -1.</_>
-        <_>
-          3 7 9 2 2.</_>
+          4 10 6 3 -1.</_>
         <_>
-          12 9 9 2 2.</_></rects>
+          7 10 3 3 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          3 7 17 3 -1.</_>
+          4 10 18 2 -1.</_>
         <_>
-          3 8 17 1 3.</_></rects>
+          4 10 9 1 2.</_>
+        <_>
+          13 11 9 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          3 7 18 2 -1.</_>
+          4 10 17 6 -1.</_>
         <_>
-          3 8 18 1 2.</_></rects>
+          4 12 17 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          3 8 2 3 -1.</_>
+          4 11 3 2 -1.</_>
         <_>
-          4 8 1 3 2.</_></rects>
+          5 11 1 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          3 8 18 3 -1.</_>
+          4 11 3 3 -1.</_>
         <_>
-          3 9 18 1 3.</_></rects>
+          5 11 1 3 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          3 8 20 3 -1.</_>
+          4 11 1 8 -1.</_>
         <_>
-          3 9 20 1 3.</_></rects>
+          4 15 1 4 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          3 9 3 1 -1.</_>
+          4 11 3 6 -1.</_>
         <_>
-          4 9 1 1 3.</_></rects>
+          5 11 1 6 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          3 9 3 2 -1.</_>
+          4 11 6 3 -1.</_>
         <_>
-          4 9 1 2 3.</_></rects>
+          6 11 2 3 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          3 9 4 6 -1.</_>
-        <_>
-          3 9 2 3 2.</_>
+          4 11 15 2 -1.</_>
         <_>
-          5 12 2 3 2.</_></rects>
+          4 12 15 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          3 9 6 4 -1.</_>
+          4 12 3 1 -1.</_>
         <_>
-          3 11 6 2 2.</_></rects>
+          5 12 1 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          3 9 8 9 -1.</_>
+          4 12 4 4 -1.</_>
         <_>
-          3 12 8 3 3.</_></rects>
+          6 12 2 4 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          3 9 20 2 -1.</_>
+          4 12 3 8 -1.</_>
         <_>
-          3 9 10 1 2.</_>
-        <_>
-          13 10 10 1 2.</_></rects>
+          4 16 3 4 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          3 9 19 3 -1.</_>
+          4 12 17 12 -1.</_>
         <_>
-          3 10 19 1 3.</_></rects>
+          4 16 17 4 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          3 10 4 2 -1.</_>
-        <_>
-          3 10 2 1 2.</_>
+          4 13 3 1 -1.</_>
         <_>
-          5 11 2 1 2.</_></rects>
+          5 13 1 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          3 10 18 6 -1.</_>
+          4 13 3 9 -1.</_>
         <_>
-          3 12 18 2 3.</_></rects>
+          4 16 3 3 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          3 11 3 4 -1.</_>
+          4 14 4 2 -1.</_>
         <_>
-          4 11 1 4 3.</_></rects>
+          6 14 2 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          3 11 3 5 -1.</_>
+          4 15 4 2 -1.</_>
         <_>
-          4 11 1 5 3.</_></rects>
+          6 15 2 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          3 11 4 10 -1.</_>
+          4 15 9 4 -1.</_>
         <_>
-          3 16 4 5 2.</_></rects>
+          7 15 3 4 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          3 11 7 8 -1.</_>
+          4 15 16 4 -1.</_>
+        <_>
+          4 15 8 2 2.</_>
         <_>
-          3 15 7 4 2.</_></rects>
+          12 17 8 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          3 12 3 2 -1.</_>
+          4 18 3 5 -1.</_>
         <_>
-          4 12 1 2 3.</_></rects>
+          5 18 1 5 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          3 12 3 10 -1.</_>
+          4 18 3 6 -1.</_>
         <_>
-          4 12 1 10 3.</_></rects>
+          5 18 1 6 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          3 12 3 6 -1.</_>
+          4 18 15 5 -1.</_>
         <_>
-          3 15 3 3 2.</_></rects>
+          9 18 5 5 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          3 12 4 8 -1.</_>
+          4 18 9 6 -1.</_>
         <_>
-          3 16 4 4 2.</_></rects>
+          4 21 9 3 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          3 12 10 8 -1.</_>
+          5 1 14 2 -1.</_>
         <_>
-          3 12 5 4 2.</_>
+          5 1 7 1 2.</_>
         <_>
-          8 16 5 4 2.</_></rects>
+          12 2 7 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          3 12 18 2 -1.</_>
+          5 1 11 8 -1.</_>
         <_>
-          3 12 9 1 2.</_>
-        <_>
-          12 13 9 1 2.</_></rects>
+          5 5 11 4 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          3 13 19 6 -1.</_>
+          5 2 3 3 -1.</_>
         <_>
-          3 16 19 3 2.</_></rects>
+          6 2 1 3 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          3 14 4 9 -1.</_>
+          5 2 6 2 -1.</_>
         <_>
-          3 17 4 3 3.</_></rects>
+          7 2 2 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          3 16 3 4 -1.</_>
+          5 2 14 2 -1.</_>
+        <_>
+          5 2 7 1 2.</_>
         <_>
-          4 16 1 4 3.</_></rects>
+          12 3 7 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          3 16 4 3 -1.</_>
+          5 2 14 8 -1.</_>
         <_>
-          5 16 2 3 2.</_></rects>
+          5 6 14 4 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          3 16 21 7 -1.</_>
+          5 2 16 10 -1.</_>
         <_>
-          10 16 7 7 3.</_></rects>
+          5 7 16 5 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          3 18 3 6 -1.</_>
+          5 3 6 1 -1.</_>
         <_>
-          4 18 1 6 3.</_></rects>
+          7 3 2 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          4 0 3 23 -1.</_>
+          5 3 6 2 -1.</_>
         <_>
-          5 0 1 23 3.</_></rects>
+          7 3 2 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          4 0 6 5 -1.</_>
+          5 3 4 10 -1.</_>
+        <_>
+          5 3 2 5 2.</_>
         <_>
-          6 0 2 5 3.</_></rects>
+          7 8 2 5 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          4 0 17 12 -1.</_>
+          5 3 9 12 -1.</_>
         <_>
-          4 4 17 4 3.</_></rects>
+          8 3 3 12 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          4 1 16 12 -1.</_>
+          5 3 14 2 -1.</_>
+        <_>
+          5 3 7 1 2.</_>
         <_>
-          4 7 16 6 2.</_></rects>
+          12 4 7 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          4 3 3 1 -1.</_>
+          5 3 15 8 -1.</_>
         <_>
-          5 3 1 1 3.</_></rects>
+          5 7 15 4 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          4 3 16 10 -1.</_>
+          5 4 2 4 -1.</_>
         <_>
-          4 3 8 5 2.</_>
+          5 4 1 2 2.</_>
         <_>
-          12 8 8 5 2.</_></rects>
+          6 6 1 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          4 3 14 6 -1.</_>
+          5 4 6 4 -1.</_>
         <_>
-          4 6 14 3 2.</_></rects>
+          7 4 2 4 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          4 4 1 3 -1.</_>
+          5 4 4 12 -1.</_>
         <_>
-          4 5 1 1 3.</_></rects>
+          7 4 2 12 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          4 4 2 4 -1.</_>
+          5 4 12 8 -1.</_>
         <_>
-          4 6 2 2 2.</_></rects>
+          9 4 4 8 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          4 4 6 2 -1.</_>
+          5 4 14 2 -1.</_>
+        <_>
+          5 4 7 1 2.</_>
         <_>
-          7 4 3 2 2.</_></rects>
+          12 5 7 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          4 4 13 6 -1.</_>
+          5 5 2 2 -1.</_>
+        <_>
+          5 5 1 1 2.</_>
         <_>
-          4 7 13 3 2.</_></rects>
+          6 6 1 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          4 5 6 4 -1.</_>
+          5 5 2 4 -1.</_>
+        <_>
+          5 5 1 2 2.</_>
         <_>
-          6 5 2 4 3.</_></rects>
+          6 7 1 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          4 5 14 6 -1.</_>
+          5 5 6 6 -1.</_>
         <_>
-          4 7 14 2 3.</_></rects>
+          5 7 6 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          4 5 16 6 -1.</_>
+          5 5 14 2 -1.</_>
+        <_>
+          5 5 7 1 2.</_>
         <_>
-          4 8 16 3 2.</_></rects>
+          12 6 7 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          4 6 1 3 -1.</_>
+          5 5 16 2 -1.</_>
         <_>
-          4 7 1 1 3.</_></rects>
+          5 5 8 1 2.</_>
+        <_>
+          13 6 8 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          4 6 2 3 -1.</_>
+          5 5 13 6 -1.</_>
         <_>
-          4 7 2 1 3.</_></rects>
+          5 7 13 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          4 6 3 3 -1.</_>
+          5 5 14 6 -1.</_>
         <_>
-          4 7 3 1 3.</_></rects>
+          5 7 14 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          4 6 16 2 -1.</_>
-        <_>
-          4 6 8 1 2.</_>
+          5 5 15 6 -1.</_>
         <_>
-          12 7 8 1 2.</_></rects>
+          5 7 15 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          4 6 16 6 -1.</_>
+          5 5 15 9 -1.</_>
         <_>
-          4 6 8 3 2.</_>
-        <_>
-          12 9 8 3 2.</_></rects>
+          5 8 15 3 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          4 6 10 8 -1.</_>
+          5 6 1 2 -1.</_>
         <_>
-          4 10 10 4 2.</_></rects>
+          5 7 1 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          4 7 2 3 -1.</_>
+          5 6 2 4 -1.</_>
+        <_>
+          5 6 1 2 2.</_>
         <_>
-          4 8 2 1 3.</_></rects>
+          6 8 1 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          4 7 5 6 -1.</_>
+          5 6 6 1 -1.</_>
         <_>
-          4 9 5 2 3.</_></rects>
+          7 6 2 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          4 7 16 4 -1.</_>
+          5 6 4 3 -1.</_>
         <_>
-          4 7 8 2 2.</_>
-        <_>
-          12 9 8 2 2.</_></rects>
+          5 7 4 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          4 7 18 2 -1.</_>
+          5 6 14 2 -1.</_>
         <_>
-          4 7 9 1 2.</_>
+          5 6 7 1 2.</_>
         <_>
-          13 8 9 1 2.</_></rects>
+          12 7 7 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          4 7 16 6 -1.</_>
+          5 7 2 2 -1.</_>
         <_>
-          4 9 16 2 3.</_></rects>
+          6 7 1 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          4 7 17 6 -1.</_>
+          5 7 2 6 -1.</_>
         <_>
-          4 9 17 2 3.</_></rects>
+          5 7 1 3 2.</_>
+        <_>
+          6 10 1 3 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          4 8 2 2 -1.</_>
-        <_>
-          4 8 1 1 2.</_>
+          5 7 4 1 -1.</_>
         <_>
-          5 9 1 1 2.</_></rects>
+          7 7 2 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          4 8 16 2 -1.</_>
-        <_>
-          4 8 8 1 2.</_>
+          5 7 6 5 -1.</_>
         <_>
-          12 9 8 1 2.</_></rects>
+          7 7 2 5 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          4 8 16 4 -1.</_>
-        <_>
-          4 8 8 2 2.</_>
+          5 7 3 2 -1.</_>
         <_>
-          12 10 8 2 2.</_></rects>
+          5 8 3 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          4 8 15 6 -1.</_>
+          5 7 3 3 -1.</_>
         <_>
-          4 10 15 2 3.</_></rects>
+          5 8 3 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          4 9 2 1 -1.</_>
+          5 7 3 6 -1.</_>
         <_>
-          5 9 1 1 2.</_></rects>
+          5 9 3 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          4 9 3 1 -1.</_>
+          5 7 4 3 -1.</_>
         <_>
-          5 9 1 1 3.</_></rects>
+          5 8 4 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          4 9 3 2 -1.</_>
+          5 7 4 6 -1.</_>
         <_>
-          5 9 1 2 3.</_></rects>
+          5 9 4 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          4 9 2 4 -1.</_>
+          5 7 5 6 -1.</_>
         <_>
-          4 9 1 2 2.</_>
-        <_>
-          5 11 1 2 2.</_></rects>
+          5 9 5 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          4 9 6 1 -1.</_>
+          5 7 14 4 -1.</_>
         <_>
-          6 9 2 1 3.</_></rects>
+          5 7 7 2 2.</_>
+        <_>
+          12 9 7 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          4 9 2 6 -1.</_>
+          5 7 14 2 -1.</_>
         <_>
-          4 11 2 2 3.</_></rects>
+          5 8 14 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          4 9 8 6 -1.</_>
+          5 7 14 4 -1.</_>
         <_>
-          4 9 4 3 2.</_>
-        <_>
-          8 12 4 3 2.</_></rects>
+          5 9 14 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          4 9 5 3 -1.</_>
+          5 7 15 2 -1.</_>
         <_>
-          4 10 5 1 3.</_></rects>
+          5 8 15 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          4 9 15 2 -1.</_>
+          5 7 15 6 -1.</_>
         <_>
-          9 9 5 2 3.</_></rects>
+          5 9 15 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          4 9 15 4 -1.</_>
+          5 8 1 3 -1.</_>
         <_>
-          9 9 5 4 3.</_></rects>
+          5 9 1 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          4 9 16 2 -1.</_>
+          5 8 2 2 -1.</_>
         <_>
-          4 9 8 1 2.</_>
+          5 8 1 1 2.</_>
         <_>
-          12 10 8 1 2.</_></rects>
+          6 9 1 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          4 9 18 2 -1.</_>
-        <_>
-          4 9 9 1 2.</_>
+          5 8 4 5 -1.</_>
         <_>
-          13 10 9 1 2.</_></rects>
+          7 8 2 5 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          4 9 15 15 -1.</_>
+          5 8 12 4 -1.</_>
         <_>
-          4 14 15 5 3.</_></rects>
+          9 8 4 4 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          4 9 17 9 -1.</_>
+          5 8 15 3 -1.</_>
         <_>
-          4 12 17 3 3.</_></rects>
+          10 8 5 3 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          4 9 20 6 -1.</_>
+          5 8 14 4 -1.</_>
         <_>
-          4 11 20 2 3.</_></rects>
+          5 8 7 2 2.</_>
+        <_>
+          12 10 7 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          4 10 2 1 -1.</_>
+          5 9 4 4 -1.</_>
         <_>
-          5 10 1 1 2.</_></rects>
+          7 9 2 4 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          4 10 3 1 -1.</_>
+          5 9 4 3 -1.</_>
         <_>
-          5 10 1 1 3.</_></rects>
+          5 10 4 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          4 10 2 2 -1.</_>
+          5 9 8 8 -1.</_>
         <_>
-          4 10 1 1 2.</_>
+          5 9 4 4 2.</_>
         <_>
-          5 11 1 1 2.</_></rects>
+          9 13 4 4 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          4 10 3 5 -1.</_>
+          5 9 15 2 -1.</_>
         <_>
-          5 10 1 5 3.</_></rects>
+          10 9 5 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          4 10 16 10 -1.</_>
+          5 9 14 2 -1.</_>
         <_>
-          4 10 8 5 2.</_>
+          5 9 7 1 2.</_>
         <_>
-          12 15 8 5 2.</_></rects>
+          12 10 7 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          4 11 3 2 -1.</_>
+          5 9 14 12 -1.</_>
         <_>
-          5 11 1 2 3.</_></rects>
+          5 9 7 6 2.</_>
+        <_>
+          12 15 7 6 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          4 11 3 3 -1.</_>
+          5 9 18 2 -1.</_>
         <_>
-          5 11 1 3 3.</_></rects>
+          5 9 9 1 2.</_>
+        <_>
+          14 10 9 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          4 11 3 5 -1.</_>
+          5 9 13 3 -1.</_>
         <_>
-          5 11 1 5 3.</_></rects>
+          5 10 13 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          4 11 3 10 -1.</_>
+          5 9 15 6 -1.</_>
         <_>
-          4 16 3 5 2.</_></rects>
+          5 12 15 3 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          4 11 16 2 -1.</_>
+          5 10 2 2 -1.</_>
         <_>
-          4 11 8 1 2.</_>
+          5 10 1 1 2.</_>
         <_>
-          12 12 8 1 2.</_></rects>
+          6 11 1 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          4 12 3 1 -1.</_>
+          5 10 3 3 -1.</_>
         <_>
-          5 12 1 1 3.</_></rects>
+          6 10 1 3 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          4 12 3 2 -1.</_>
+          5 11 3 2 -1.</_>
         <_>
-          5 12 1 2 3.</_></rects>
+          6 11 1 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          4 12 1 6 -1.</_>
+          5 11 3 3 -1.</_>
         <_>
-          4 15 1 3 2.</_></rects>
+          6 11 1 3 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          4 12 4 4 -1.</_>
+          5 11 3 13 -1.</_>
         <_>
-          6 12 2 4 2.</_></rects>
+          6 11 1 13 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          4 12 4 4 -1.</_>
+          5 11 14 2 -1.</_>
         <_>
-          4 14 4 2 2.</_></rects>
+          5 12 14 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          4 12 18 8 -1.</_>
+          5 12 1 6 -1.</_>
         <_>
-          13 12 9 8 2.</_></rects>
+          5 15 1 3 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          4 13 9 5 -1.</_>
+          5 13 15 8 -1.</_>
         <_>
-          7 13 3 5 3.</_></rects>
+          5 17 15 4 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          4 14 4 2 -1.</_>
+          5 14 3 3 -1.</_>
         <_>
-          6 14 2 2 2.</_></rects>
+          5 15 3 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          4 16 4 1 -1.</_>
+          5 15 2 2 -1.</_>
         <_>
-          6 16 2 1 2.</_></rects>
+          6 15 1 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          4 16 9 2 -1.</_>
+          5 19 3 5 -1.</_>
         <_>
-          7 16 3 2 3.</_></rects>
+          6 19 1 5 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          4 19 3 4 -1.</_>
+          5 21 3 3 -1.</_>
         <_>
-          5 19 1 4 3.</_></rects>
+          6 21 1 3 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          4 22 12 2 -1.</_>
+          6 0 1 6 -1.</_>
         <_>
-          4 23 12 1 2.</_></rects>
+          6 3 1 3 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          5 2 3 3 -1.</_>
+          6 0 11 10 -1.</_>
         <_>
-          6 2 1 3 3.</_></rects>
+          6 5 11 5 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          5 2 4 12 -1.</_>
+          6 1 6 12 -1.</_>
         <_>
-          5 2 2 6 2.</_>
-        <_>
-          7 8 2 6 2.</_></rects>
+          8 1 2 12 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          5 2 4 12 -1.</_>
+          6 2 3 6 -1.</_>
         <_>
-          7 2 2 12 2.</_></rects>
+          7 2 1 6 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          5 2 14 2 -1.</_>
-        <_>
-          5 2 7 1 2.</_>
+          6 2 6 2 -1.</_>
         <_>
-          12 3 7 1 2.</_></rects>
+          8 2 2 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          5 2 16 10 -1.</_>
+          6 2 6 10 -1.</_>
         <_>
-          5 7 16 5 2.</_></rects>
+          8 2 2 10 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          5 3 6 2 -1.</_>
+          6 2 12 4 -1.</_>
         <_>
-          7 3 2 2 3.</_></rects>
+          6 4 12 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          5 3 14 2 -1.</_>
-        <_>
-          5 3 7 1 2.</_>
+          6 3 6 4 -1.</_>
         <_>
-          12 4 7 1 2.</_></rects>
+          8 3 2 4 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          5 4 5 3 -1.</_>
+          6 3 9 1 -1.</_>
         <_>
-          5 5 5 1 3.</_></rects>
+          9 3 3 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          5 4 14 2 -1.</_>
-        <_>
-          5 4 7 1 2.</_>
+          6 4 3 3 -1.</_>
         <_>
-          12 5 7 1 2.</_></rects>
+          7 4 1 3 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          5 4 16 18 -1.</_>
-        <_>
-          5 4 8 9 2.</_>
+          6 4 6 4 -1.</_>
         <_>
-          13 13 8 9 2.</_></rects>
+          8 4 2 4 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          5 5 2 2 -1.</_>
-        <_>
-          5 5 1 1 2.</_>
+          6 5 3 2 -1.</_>
         <_>
-          6 6 1 1 2.</_></rects>
+          7 5 1 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          5 5 14 2 -1.</_>
-        <_>
-          5 5 7 1 2.</_>
+          6 5 3 3 -1.</_>
         <_>
-          12 6 7 1 2.</_></rects>
+          7 5 1 3 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          5 5 14 6 -1.</_>
+          6 5 2 9 -1.</_>
         <_>
-          5 7 14 2 3.</_></rects>
+          6 8 2 3 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          5 6 14 2 -1.</_>
+          6 5 12 2 -1.</_>
         <_>
-          5 6 7 1 2.</_>
+          6 5 6 1 2.</_>
         <_>
-          12 7 7 1 2.</_></rects>
+          12 6 6 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          5 6 19 6 -1.</_>
+          6 6 4 1 -1.</_>
         <_>
-          5 8 19 2 3.</_></rects>
+          8 6 2 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          5 7 1 3 -1.</_>
+          6 6 12 2 -1.</_>
         <_>
-          5 8 1 1 3.</_></rects>
+          6 6 6 1 2.</_>
+        <_>
+          12 7 6 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          5 7 4 6 -1.</_>
+          6 7 1 6 -1.</_>
         <_>
-          7 7 2 6 2.</_></rects>
+          6 9 1 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          5 7 3 2 -1.</_>
+          6 7 2 2 -1.</_>
         <_>
-          5 8 3 1 2.</_></rects>
+          6 8 2 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          5 7 4 3 -1.</_>
+          6 7 2 3 -1.</_>
         <_>
-          5 8 4 1 3.</_></rects>
+          6 8 2 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          5 7 4 6 -1.</_>
+          6 7 2 6 -1.</_>
         <_>
-          5 9 4 2 3.</_></rects>
+          6 9 2 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          5 7 5 2 -1.</_>
+          6 7 3 6 -1.</_>
         <_>
-          5 8 5 1 2.</_></rects>
+          6 9 3 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          5 7 14 10 -1.</_>
+          6 7 12 2 -1.</_>
         <_>
-          5 7 7 5 2.</_>
+          6 7 6 1 2.</_>
         <_>
-          12 12 7 5 2.</_></rects>
+          12 8 6 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          5 7 14 2 -1.</_>
+          6 7 8 12 -1.</_>
         <_>
-          5 8 14 1 2.</_></rects>
+          6 13 8 6 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          5 7 15 4 -1.</_>
+          6 7 12 15 -1.</_>
         <_>
-          5 9 15 2 2.</_></rects>
+          6 12 12 5 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          5 7 15 6 -1.</_>
+          6 8 2 6 -1.</_>
         <_>
-          5 9 15 2 3.</_></rects>
+          6 11 2 3 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          5 7 16 2 -1.</_>
+          6 8 3 2 -1.</_>
         <_>
-          5 8 16 1 2.</_></rects>
+          6 9 3 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          5 7 16 6 -1.</_>
+          6 8 12 3 -1.</_>
         <_>
-          5 9 16 2 3.</_></rects>
+          10 8 4 3 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          5 8 1 3 -1.</_>
+          6 8 12 2 -1.</_>
         <_>
-          5 9 1 1 3.</_></rects>
+          6 8 6 1 2.</_>
+        <_>
+          12 9 6 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          5 8 2 4 -1.</_>
+          6 9 2 2 -1.</_>
         <_>
-          5 8 1 2 2.</_>
-        <_>
-          6 10 1 2 2.</_></rects>
+          6 10 2 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          5 8 3 2 -1.</_>
+          6 9 2 3 -1.</_>
         <_>
-          5 9 3 1 2.</_></rects>
+          6 10 2 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          5 9 3 1 -1.</_>
+          6 9 6 1 -1.</_>
         <_>
-          6 9 1 1 3.</_></rects>
+          9 9 3 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          5 9 1 3 -1.</_>
+          6 9 3 3 -1.</_>
         <_>
-          5 10 1 1 3.</_></rects>
+          6 10 3 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          5 9 1 9 -1.</_>
+          6 9 12 2 -1.</_>
+        <_>
+          6 9 6 1 2.</_>
         <_>
-          5 12 1 3 3.</_></rects>
+          12 10 6 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          5 9 8 1 -1.</_>
+          6 9 13 12 -1.</_>
         <_>
-          9 9 4 1 2.</_></rects>
+          6 13 13 4 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          5 9 15 2 -1.</_>
+          6 10 1 3 -1.</_>
         <_>
-          10 9 5 2 3.</_></rects>
+          6 11 1 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          5 9 14 2 -1.</_>
-        <_>
-          5 9 7 1 2.</_>
+          6 10 2 2 -1.</_>
         <_>
-          12 10 7 1 2.</_></rects>
+          7 10 1 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          5 9 14 8 -1.</_>
-        <_>
-          5 9 7 4 2.</_>
+          6 10 2 3 -1.</_>
         <_>
-          12 13 7 4 2.</_></rects>
+          7 10 1 3 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          5 9 16 2 -1.</_>
-        <_>
-          5 9 8 1 2.</_>
+          6 10 3 14 -1.</_>
         <_>
-          13 10 8 1 2.</_></rects>
+          7 10 1 14 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          5 10 2 2 -1.</_>
-        <_>
-          5 10 1 1 2.</_>
+          6 10 2 3 -1.</_>
         <_>
-          6 11 1 1 2.</_></rects>
+          6 11 2 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          5 10 15 1 -1.</_>
+          6 10 6 3 -1.</_>
         <_>
-          10 10 5 1 3.</_></rects>
+          8 10 2 3 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          5 11 3 2 -1.</_>
+          6 10 3 3 -1.</_>
         <_>
-          6 11 1 2 3.</_></rects>
+          6 11 3 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          5 11 14 2 -1.</_>
+          6 10 9 5 -1.</_>
         <_>
-          5 12 14 1 2.</_></rects>
+          9 10 3 5 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          5 12 17 2 -1.</_>
+          6 10 12 1 -1.</_>
         <_>
-          5 13 17 1 2.</_></rects>
+          10 10 4 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          5 13 4 6 -1.</_>
+          6 10 8 4 -1.</_>
         <_>
-          5 13 2 3 2.</_>
+          6 10 4 2 2.</_>
         <_>
-          7 16 2 3 2.</_></rects>
+          10 12 4 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          5 13 18 10 -1.</_>
-        <_>
-          14 13 9 10 2.</_></rects>
-      <tilted>0</tilted></_>
-    <_>
-      <rects>
+          6 10 12 2 -1.</_>
         <_>
-          5 15 9 3 -1.</_>
+          6 10 6 1 2.</_>
         <_>
-          8 15 3 3 3.</_></rects>
+          12 11 6 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          5 17 3 7 -1.</_>
+          6 10 12 12 -1.</_>
+        <_>
+          6 10 6 6 2.</_>
         <_>
-          6 17 1 7 3.</_></rects>
+          12 16 6 6 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          5 21 3 3 -1.</_>
+          6 10 18 1 -1.</_>
         <_>
-          6 21 1 3 3.</_></rects>
+          15 10 9 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          6 0 3 6 -1.</_>
+          6 10 13 3 -1.</_>
         <_>
-          6 3 3 3 2.</_></rects>
+          6 11 13 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          6 0 12 2 -1.</_>
+          6 11 2 2 -1.</_>
         <_>
-          12 0 6 2 2.</_></rects>
+          6 12 2 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          6 0 14 12 -1.</_>
+          6 11 2 3 -1.</_>
         <_>
-          6 6 14 6 2.</_></rects>
+          6 12 2 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          6 1 6 7 -1.</_>
+          6 11 3 2 -1.</_>
         <_>
-          8 1 2 7 3.</_></rects>
+          6 12 3 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          6 1 6 11 -1.</_>
+          6 11 3 3 -1.</_>
         <_>
-          8 1 2 11 3.</_></rects>
+          6 12 3 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          6 2 6 12 -1.</_>
+          6 11 12 3 -1.</_>
         <_>
-          8 2 2 12 3.</_></rects>
+          6 12 12 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          6 2 12 4 -1.</_>
+          6 11 13 3 -1.</_>
         <_>
-          6 4 12 2 2.</_></rects>
+          6 12 13 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          6 3 2 2 -1.</_>
+          6 12 14 2 -1.</_>
         <_>
-          6 4 2 1 2.</_></rects>
+          6 12 7 1 2.</_>
+        <_>
+          13 13 7 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          6 3 14 18 -1.</_>
-        <_>
-          6 3 7 9 2.</_>
+          6 12 13 2 -1.</_>
         <_>
-          13 12 7 9 2.</_></rects>
+          6 13 13 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          6 4 1 2 -1.</_>
+          6 14 1 3 -1.</_>
         <_>
-          6 5 1 1 2.</_></rects>
+          6 15 1 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          6 4 3 3 -1.</_>
+          6 14 2 2 -1.</_>
         <_>
-          7 4 1 3 3.</_></rects>
+          7 14 1 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          6 5 2 1 -1.</_>
+          6 15 2 3 -1.</_>
         <_>
-          7 5 1 1 2.</_></rects>
+          6 16 2 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          6 5 2 9 -1.</_>
+          6 17 10 6 -1.</_>
         <_>
-          6 8 2 3 3.</_></rects>
+          6 20 10 3 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          6 5 12 2 -1.</_>
-        <_>
-          6 5 6 1 2.</_>
+          6 18 3 6 -1.</_>
         <_>
-          12 6 6 1 2.</_></rects>
+          7 18 1 6 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          6 5 12 6 -1.</_>
+          6 19 3 5 -1.</_>
         <_>
-          6 7 12 2 3.</_></rects>
+          7 19 1 5 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          6 6 10 2 -1.</_>
+          6 20 9 4 -1.</_>
         <_>
-          6 6 5 1 2.</_>
-        <_>
-          11 7 5 1 2.</_></rects>
+          6 22 9 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          6 6 12 6 -1.</_>
+          6 23 3 1 -1.</_>
         <_>
-          6 8 12 2 3.</_></rects>
+          7 23 1 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          6 6 14 4 -1.</_>
+          7 0 2 8 -1.</_>
+        <_>
+          7 0 1 4 2.</_>
         <_>
-          6 8 14 2 2.</_></rects>
+          8 4 1 4 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          6 7 1 3 -1.</_>
+          7 0 10 1 -1.</_>
         <_>
-          6 8 1 1 3.</_></rects>
+          12 0 5 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          6 7 1 6 -1.</_>
+          7 1 2 4 -1.</_>
         <_>
-          6 9 1 2 3.</_></rects>
+          7 3 2 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          6 7 2 3 -1.</_>
+          7 1 10 1 -1.</_>
         <_>
-          6 8 2 1 3.</_></rects>
+          12 1 5 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          6 7 2 6 -1.</_>
+          7 2 4 21 -1.</_>
         <_>
-          6 9 2 2 3.</_></rects>
+          9 2 2 21 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          6 7 3 6 -1.</_>
+          7 3 1 3 -1.</_>
         <_>
-          6 9 3 2 3.</_></rects>
+          7 4 1 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          6 8 2 4 -1.</_>
+          7 3 3 5 -1.</_>
         <_>
-          7 8 1 4 2.</_></rects>
+          8 3 1 5 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          6 8 2 3 -1.</_>
+          7 4 3 10 -1.</_>
         <_>
-          6 9 2 1 3.</_></rects>
+          8 4 1 10 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          6 8 9 6 -1.</_>
+          7 5 2 2 -1.</_>
         <_>
-          9 8 3 6 3.</_></rects>
+          8 5 1 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          6 8 12 3 -1.</_>
+          7 5 3 2 -1.</_>
         <_>
-          10 8 4 3 3.</_></rects>
+          8 5 1 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          6 8 12 2 -1.</_>
-        <_>
-          6 8 6 1 2.</_>
+          7 5 3 3 -1.</_>
         <_>
-          12 9 6 1 2.</_></rects>
+          8 5 1 3 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          6 8 8 12 -1.</_>
+          7 5 3 6 -1.</_>
         <_>
-          6 14 8 6 2.</_></rects>
+          8 5 1 6 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          6 9 2 6 -1.</_>
+          7 5 2 7 -1.</_>
         <_>
-          6 11 2 2 3.</_></rects>
+          8 5 1 7 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          6 9 3 3 -1.</_>
+          7 5 2 6 -1.</_>
         <_>
-          6 10 3 1 3.</_></rects>
+          7 7 2 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          6 9 3 6 -1.</_>
+          7 5 11 6 -1.</_>
         <_>
-          6 12 3 3 2.</_></rects>
+          7 7 11 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          6 9 6 6 -1.</_>
+          7 6 3 1 -1.</_>
         <_>
-          6 9 3 3 2.</_>
-        <_>
-          9 12 3 3 2.</_></rects>
+          8 6 1 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          6 9 12 2 -1.</_>
+          7 6 1 3 -1.</_>
         <_>
-          10 9 4 2 3.</_></rects>
+          7 7 1 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          6 9 12 3 -1.</_>
+          7 6 4 6 -1.</_>
         <_>
-          10 9 4 3 3.</_></rects>
+          9 6 2 6 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          6 9 12 2 -1.</_>
+          7 6 10 2 -1.</_>
         <_>
-          6 9 6 1 2.</_>
+          7 6 5 1 2.</_>
         <_>
-          12 10 6 1 2.</_></rects>
+          12 7 5 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          6 9 14 2 -1.</_>
+          7 6 12 2 -1.</_>
         <_>
-          6 9 7 1 2.</_>
+          7 6 6 1 2.</_>
         <_>
-          13 10 7 1 2.</_></rects>
+          13 7 6 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          6 10 1 3 -1.</_>
+          7 7 1 2 -1.</_>
         <_>
-          6 11 1 1 3.</_></rects>
+          7 8 1 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          6 10 2 3 -1.</_>
+          7 7 1 3 -1.</_>
         <_>
-          7 10 1 3 2.</_></rects>
+          7 8 1 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          6 10 2 3 -1.</_>
+          7 7 1 6 -1.</_>
         <_>
-          6 11 2 1 3.</_></rects>
+          7 9 1 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          6 10 6 3 -1.</_>
+          7 7 2 4 -1.</_>
         <_>
-          8 10 2 3 3.</_></rects>
+          7 9 2 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          6 10 3 3 -1.</_>
+          7 7 10 2 -1.</_>
         <_>
-          6 11 3 1 3.</_></rects>
+          7 7 5 1 2.</_>
+        <_>
+          12 8 5 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          6 10 12 2 -1.</_>
-        <_>
-          6 10 6 1 2.</_>
+          7 8 1 3 -1.</_>
         <_>
-          12 11 6 1 2.</_></rects>
+          7 9 1 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          6 10 13 3 -1.</_>
+          7 8 2 2 -1.</_>
         <_>
-          6 11 13 1 3.</_></rects>
+          7 8 1 1 2.</_>
+        <_>
+          8 9 1 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          6 11 2 2 -1.</_>
+          7 8 2 4 -1.</_>
         <_>
-          6 12 2 1 2.</_></rects>
+          7 8 1 2 2.</_>
+        <_>
+          8 10 1 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          6 11 2 3 -1.</_>
+          7 8 10 2 -1.</_>
         <_>
-          6 12 2 1 3.</_></rects>
+          7 8 5 1 2.</_>
+        <_>
+          12 9 5 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          6 11 3 2 -1.</_>
+          7 9 1 2 -1.</_>
         <_>
-          6 12 3 1 2.</_></rects>
+          7 10 1 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          6 11 3 3 -1.</_>
+          7 9 1 3 -1.</_>
         <_>
-          6 12 3 1 3.</_></rects>
+          7 10 1 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          6 11 4 3 -1.</_>
+          7 9 3 3 -1.</_>
         <_>
-          6 12 4 1 3.</_></rects>
+          8 9 1 3 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          6 11 16 3 -1.</_>
+          7 9 4 6 -1.</_>
+        <_>
+          7 9 2 3 2.</_>
         <_>
-          6 12 16 1 3.</_></rects>
+          9 12 2 3 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          6 14 1 3 -1.</_>
+          7 9 6 10 -1.</_>
         <_>
-          6 15 1 1 3.</_></rects>
+          7 9 3 5 2.</_>
+        <_>
+          10 14 3 5 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          6 16 1 3 -1.</_>
+          7 9 12 2 -1.</_>
         <_>
-          6 17 1 1 3.</_></rects>
+          11 9 4 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          6 17 3 6 -1.</_>
+          7 9 10 2 -1.</_>
+        <_>
+          7 9 5 1 2.</_>
         <_>
-          7 17 1 6 3.</_></rects>
+          12 10 5 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          6 17 11 4 -1.</_>
+          7 9 12 2 -1.</_>
+        <_>
+          7 9 6 1 2.</_>
         <_>
-          6 19 11 2 2.</_></rects>
+          13 10 6 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          6 18 12 2 -1.</_>
+          7 10 3 1 -1.</_>
         <_>
-          6 19 12 1 2.</_></rects>
+          8 10 1 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          6 19 3 5 -1.</_>
+          7 10 1 3 -1.</_>
         <_>
-          7 19 1 5 3.</_></rects>
+          7 11 1 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          6 20 14 4 -1.</_>
+          7 10 2 3 -1.</_>
         <_>
-          6 22 14 2 2.</_></rects>
+          7 11 2 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          7 0 10 1 -1.</_>
+          7 10 6 4 -1.</_>
         <_>
-          12 0 5 1 2.</_></rects>
+          9 10 2 4 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          7 0 7 2 -1.</_>
+          7 10 10 2 -1.</_>
+        <_>
+          7 10 5 1 2.</_>
         <_>
-          7 1 7 1 2.</_></rects>
+          12 11 5 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          7 0 11 10 -1.</_>
+          7 11 2 1 -1.</_>
         <_>
-          7 5 11 5 2.</_></rects>
+          8 11 1 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          7 1 10 1 -1.</_>
+          7 11 2 2 -1.</_>
         <_>
-          12 1 5 1 2.</_></rects>
+          7 12 2 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          7 1 10 2 -1.</_>
-        <_>
-          7 1 5 1 2.</_>
+          7 11 6 4 -1.</_>
         <_>
-          12 2 5 1 2.</_></rects>
+          9 11 2 4 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          7 2 2 2 -1.</_>
+          7 14 1 3 -1.</_>
         <_>
-          7 2 1 1 2.</_>
-        <_>
-          8 3 1 1 2.</_></rects>
+          7 15 1 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          7 2 10 2 -1.</_>
-        <_>
-          7 2 5 1 2.</_>
+          7 16 10 8 -1.</_>
         <_>
-          12 3 5 1 2.</_></rects>
+          7 20 10 4 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          7 3 10 2 -1.</_>
+          7 18 3 6 -1.</_>
         <_>
-          7 3 5 1 2.</_>
-        <_>
-          12 4 5 1 2.</_></rects>
+          8 18 1 6 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          7 4 2 4 -1.</_>
+          7 18 9 6 -1.</_>
         <_>
-          8 4 1 4 2.</_></rects>
+          7 20 9 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          7 4 3 4 -1.</_>
+          7 19 3 3 -1.</_>
         <_>
-          8 4 1 4 3.</_></rects>
+          8 19 1 3 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          7 4 3 7 -1.</_>
+          7 20 3 4 -1.</_>
         <_>
-          8 4 1 7 3.</_></rects>
+          8 20 1 4 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          7 4 2 8 -1.</_>
+          7 20 7 4 -1.</_>
         <_>
-          8 4 1 8 2.</_></rects>
+          7 22 7 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          7 4 9 7 -1.</_>
+          7 20 11 4 -1.</_>
         <_>
-          10 4 3 7 3.</_></rects>
+          7 22 11 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          7 4 10 2 -1.</_>
-        <_>
-          7 4 5 1 2.</_>
+          7 22 3 2 -1.</_>
         <_>
-          12 5 5 1 2.</_></rects>
+          8 22 1 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          7 5 2 2 -1.</_>
+          8 0 8 2 -1.</_>
         <_>
-          8 5 1 2 2.</_></rects>
+          12 0 4 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          7 5 3 2 -1.</_>
+          8 0 8 2 -1.</_>
         <_>
-          8 5 1 2 3.</_></rects>
+          8 1 8 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          7 5 3 6 -1.</_>
+          8 0 8 10 -1.</_>
         <_>
-          8 5 1 6 3.</_></rects>
+          8 5 8 5 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          7 5 3 7 -1.</_>
+          8 0 16 10 -1.</_>
+        <_>
+          8 0 8 5 2.</_>
         <_>
-          8 5 1 7 3.</_></rects>
+          16 5 8 5 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          7 5 3 6 -1.</_>
+          8 0 10 3 -1.</_>
         <_>
-          7 7 3 2 3.</_></rects>
+          8 1 10 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          7 5 10 2 -1.</_>
-        <_>
-          7 5 5 1 2.</_>
+          8 1 8 1 -1.</_>
         <_>
-          12 6 5 1 2.</_></rects>
+          12 1 4 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          7 5 11 6 -1.</_>
+          8 2 3 2 -1.</_>
         <_>
-          7 7 11 2 3.</_></rects>
+          9 2 1 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          7 6 10 2 -1.</_>
-        <_>
-          7 6 5 1 2.</_>
+          8 2 8 20 -1.</_>
         <_>
-          12 7 5 1 2.</_></rects>
+          12 2 4 20 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          7 7 1 3 -1.</_>
+          8 3 3 8 -1.</_>
         <_>
-          7 8 1 1 3.</_></rects>
+          9 3 1 8 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          7 7 1 6 -1.</_>
+          8 3 3 9 -1.</_>
         <_>
-          7 9 1 2 3.</_></rects>
+          9 3 1 9 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          7 7 12 15 -1.</_>
+          8 3 6 1 -1.</_>
         <_>
-          7 12 12 5 3.</_></rects>
+          11 3 3 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          7 8 1 3 -1.</_>
+          8 3 4 3 -1.</_>
         <_>
-          7 9 1 1 3.</_></rects>
+          8 4 4 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          7 8 2 2 -1.</_>
+          8 3 8 2 -1.</_>
         <_>
-          7 8 1 1 2.</_>
+          8 3 4 1 2.</_>
         <_>
-          8 9 1 1 2.</_></rects>
+          12 4 4 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          7 8 3 16 -1.</_>
+          8 4 3 2 -1.</_>
         <_>
-          8 8 1 16 3.</_></rects>
+          9 4 1 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          7 8 4 16 -1.</_>
+          8 4 2 8 -1.</_>
         <_>
-          9 8 2 16 2.</_></rects>
+          9 4 1 8 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          7 9 1 2 -1.</_>
+          8 4 3 3 -1.</_>
         <_>
-          7 10 1 1 2.</_></rects>
+          8 5 3 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          7 9 2 2 -1.</_>
+          8 4 8 2 -1.</_>
         <_>
-          7 9 1 1 2.</_>
+          8 4 4 1 2.</_>
         <_>
-          8 10 1 1 2.</_></rects>
+          12 5 4 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          7 9 2 3 -1.</_>
+          8 4 7 15 -1.</_>
         <_>
-          7 10 2 1 3.</_></rects>
+          8 9 7 5 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          7 9 4 6 -1.</_>
-        <_>
-          7 9 2 3 2.</_>
+          8 5 3 2 -1.</_>
         <_>
-          9 12 2 3 2.</_></rects>
+          9 5 1 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          7 9 6 10 -1.</_>
-        <_>
-          7 9 3 5 2.</_>
+          8 5 2 3 -1.</_>
         <_>
-          10 14 3 5 2.</_></rects>
+          9 5 1 3 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          7 9 12 2 -1.</_>
+          8 5 3 5 -1.</_>
         <_>
-          11 9 4 2 3.</_></rects>
+          9 5 1 5 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          7 9 10 2 -1.</_>
-        <_>
-          7 9 5 1 2.</_>
+          8 5 2 6 -1.</_>
         <_>
-          12 10 5 1 2.</_></rects>
+          9 5 1 6 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          7 10 3 1 -1.</_>
+          8 5 3 7 -1.</_>
         <_>
-          8 10 1 1 3.</_></rects>
+          9 5 1 7 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          7 10 1 3 -1.</_>
+          8 5 4 3 -1.</_>
         <_>
-          7 11 1 1 3.</_></rects>
+          8 6 4 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          7 10 2 3 -1.</_>
+          8 5 8 12 -1.</_>
         <_>
-          7 11 2 1 3.</_></rects>
+          12 5 4 12 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          7 10 4 4 -1.</_>
-        <_>
-          7 10 2 2 2.</_>
+          8 5 8 19 -1.</_>
         <_>
-          9 12 2 2 2.</_></rects>
+          12 5 4 19 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          7 10 4 4 -1.</_>
+          8 6 3 5 -1.</_>
         <_>
-          9 10 2 4 2.</_></rects>
+          9 6 1 5 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          7 10 6 5 -1.</_>
-        <_>
-          9 10 2 5 3.</_></rects>
-      <tilted>0</tilted></_>
-    <_>
-      <rects>
+          8 6 10 2 -1.</_>
         <_>
-          7 10 9 7 -1.</_>
+          8 6 5 1 2.</_>
         <_>
-          10 10 3 7 3.</_></rects>
+          13 7 5 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          7 10 10 2 -1.</_>
+          8 8 2 2 -1.</_>
         <_>
-          7 10 5 1 2.</_>
+          8 8 1 1 2.</_>
         <_>
-          12 11 5 1 2.</_></rects>
+          9 9 1 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          7 11 2 1 -1.</_>
+          8 8 1 6 -1.</_>
         <_>
-          8 11 1 1 2.</_></rects>
+          8 10 1 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          7 11 6 4 -1.</_>
+          8 8 3 3 -1.</_>
         <_>
-          9 11 2 4 3.</_></rects>
+          8 9 3 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          7 13 12 3 -1.</_>
+          8 9 1 3 -1.</_>
         <_>
-          11 13 4 3 3.</_></rects>
+          8 10 1 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          7 13 13 10 -1.</_>
+          8 9 3 2 -1.</_>
         <_>
-          7 18 13 5 2.</_></rects>
+          9 9 1 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          7 15 6 3 -1.</_>
+          8 9 2 6 -1.</_>
+        <_>
+          8 9 1 3 2.</_>
         <_>
-          9 15 2 3 3.</_></rects>
+          9 12 1 3 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          7 16 1 6 -1.</_>
+          8 10 2 1 -1.</_>
         <_>
-          7 19 1 3 2.</_></rects>
+          9 10 1 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          7 16 9 2 -1.</_>
+          8 10 3 1 -1.</_>
         <_>
-          10 16 3 2 3.</_></rects>
+          9 10 1 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          7 17 11 6 -1.</_>
+          8 10 2 2 -1.</_>
+        <_>
+          8 10 1 1 2.</_>
         <_>
-          7 20 11 3 2.</_></rects>
+          9 11 1 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          7 18 5 6 -1.</_>
+          8 10 2 2 -1.</_>
         <_>
-          7 20 5 2 3.</_></rects>
+          9 10 1 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          7 18 9 6 -1.</_>
+          8 10 3 2 -1.</_>
         <_>
-          7 21 9 3 2.</_></rects>
+          9 10 1 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          7 18 10 6 -1.</_>
+          8 10 4 8 -1.</_>
+        <_>
+          8 10 2 4 2.</_>
         <_>
-          7 20 10 2 3.</_></rects>
+          10 14 2 4 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          7 18 11 6 -1.</_>
+          8 10 8 2 -1.</_>
+        <_>
+          8 10 4 1 2.</_>
         <_>
-          7 21 11 3 2.</_></rects>
+          12 11 4 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          7 20 3 4 -1.</_>
+          8 11 2 2 -1.</_>
         <_>
-          8 20 1 4 3.</_></rects>
+          8 11 1 1 2.</_>
+        <_>
+          9 12 1 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          7 20 9 3 -1.</_>
+          8 11 4 8 -1.</_>
+        <_>
+          8 11 2 4 2.</_>
         <_>
-          7 21 9 1 3.</_></rects>
+          10 15 2 4 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          8 0 8 1 -1.</_>
+          8 11 4 10 -1.</_>
+        <_>
+          8 11 2 5 2.</_>
         <_>
-          12 0 4 1 2.</_></rects>
+          10 16 2 5 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          8 0 10 1 -1.</_>
+          8 13 9 10 -1.</_>
         <_>
-          13 0 5 1 2.</_></rects>
+          8 18 9 5 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          8 0 8 2 -1.</_>
+          8 15 4 4 -1.</_>
         <_>
-          8 1 8 1 2.</_></rects>
+          10 15 2 4 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          8 0 16 8 -1.</_>
-        <_>
-          8 0 8 4 2.</_>
+          8 16 9 3 -1.</_>
         <_>
-          16 4 8 4 2.</_></rects>
+          11 16 3 3 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          8 0 16 10 -1.</_>
-        <_>
-          8 0 8 5 2.</_>
+          8 19 3 5 -1.</_>
         <_>
-          16 5 8 5 2.</_></rects>
+          9 19 1 5 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          8 0 9 2 -1.</_>
+          8 20 3 3 -1.</_>
         <_>
-          8 1 9 1 2.</_></rects>
+          9 20 1 3 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          8 1 9 10 -1.</_>
+          9 0 1 2 -1.</_>
         <_>
-          8 6 9 5 2.</_></rects>
+          9 1 1 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          8 3 6 10 -1.</_>
+          9 0 2 4 -1.</_>
         <_>
-          10 3 2 10 3.</_></rects>
+          10 0 1 4 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          8 4 3 1 -1.</_>
+          9 0 6 1 -1.</_>
         <_>
-          9 4 1 1 3.</_></rects>
+          12 0 3 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          8 4 3 5 -1.</_>
+          9 0 5 4 -1.</_>
         <_>
-          9 4 1 5 3.</_></rects>
+          9 2 5 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          8 4 2 7 -1.</_>
+          9 0 6 10 -1.</_>
         <_>
-          9 4 1 7 2.</_></rects>
+          9 5 6 5 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          8 4 3 9 -1.</_>
+          9 0 14 8 -1.</_>
         <_>
-          9 4 1 9 3.</_></rects>
+          9 0 7 4 2.</_>
+        <_>
+          16 4 7 4 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          8 4 8 2 -1.</_>
-        <_>
-          8 4 4 1 2.</_>
+          9 0 7 10 -1.</_>
         <_>
-          12 5 4 1 2.</_></rects>
+          9 5 7 5 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          8 5 1 4 -1.</_>
+          9 0 14 10 -1.</_>
+        <_>
+          9 0 7 5 2.</_>
         <_>
-          8 7 1 2 2.</_></rects>
+          16 5 7 5 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          8 5 3 2 -1.</_>
+          9 0 14 12 -1.</_>
         <_>
-          9 5 1 2 3.</_></rects>
+          9 0 7 6 2.</_>
+        <_>
+          16 6 7 6 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          8 5 3 5 -1.</_>
+          9 1 3 12 -1.</_>
         <_>
-          9 5 1 5 3.</_></rects>
+          10 1 1 12 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          8 5 2 6 -1.</_>
+          9 1 4 15 -1.</_>
         <_>
-          9 5 1 6 2.</_></rects>
+          11 1 2 15 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          8 5 3 6 -1.</_>
+          9 1 6 1 -1.</_>
         <_>
-          9 5 1 6 3.</_></rects>
+          12 1 3 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          8 5 2 7 -1.</_>
+          9 2 2 2 -1.</_>
         <_>
-          9 5 1 7 2.</_></rects>
+          10 2 1 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          8 5 3 7 -1.</_>
+          9 2 6 18 -1.</_>
         <_>
-          9 5 1 7 3.</_></rects>
+          12 2 3 18 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          8 5 2 3 -1.</_>
+          9 2 15 3 -1.</_>
         <_>
-          8 6 2 1 3.</_></rects>
+          9 3 15 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          8 5 4 3 -1.</_>
+          9 3 3 9 -1.</_>
         <_>
-          8 6 4 1 3.</_></rects>
+          10 3 1 9 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          8 5 8 2 -1.</_>
-        <_>
-          8 5 4 1 2.</_>
+          9 3 8 6 -1.</_>
         <_>
-          12 6 4 1 2.</_></rects>
+          9 6 8 3 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          8 5 8 19 -1.</_>
+          9 3 15 15 -1.</_>
         <_>
-          12 5 4 19 2.</_></rects>
+          9 8 15 5 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          8 6 3 5 -1.</_>
+          9 4 3 4 -1.</_>
         <_>
-          9 6 1 5 3.</_></rects>
+          10 4 1 4 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          8 6 8 2 -1.</_>
+          9 4 6 2 -1.</_>
         <_>
-          8 6 4 1 2.</_>
+          9 4 3 1 2.</_>
         <_>
-          12 7 4 1 2.</_></rects>
+          12 5 3 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          8 6 10 2 -1.</_>
-        <_>
-          8 6 5 1 2.</_>
+          9 4 14 5 -1.</_>
         <_>
-          13 7 5 1 2.</_></rects>
+          16 4 7 5 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          8 7 12 6 -1.</_>
+          9 5 2 5 -1.</_>
         <_>
-          12 7 4 6 3.</_></rects>
+          10 5 1 5 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          8 7 16 1 -1.</_>
+          9 5 3 6 -1.</_>
         <_>
-          16 7 8 1 2.</_></rects>
+          10 5 1 6 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          8 8 1 6 -1.</_>
+          9 5 4 15 -1.</_>
         <_>
-          8 10 1 2 3.</_></rects>
+          11 5 2 15 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          8 9 2 4 -1.</_>
-        <_>
-          8 9 1 2 2.</_>
+          9 5 3 3 -1.</_>
         <_>
-          9 11 1 2 2.</_></rects>
+          9 6 3 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          8 9 2 6 -1.</_>
-        <_>
-          8 9 1 3 2.</_>
+          9 5 4 3 -1.</_>
         <_>
-          9 12 1 3 2.</_></rects>
+          9 6 4 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          8 9 8 2 -1.</_>
-        <_>
-          8 9 4 1 2.</_>
+          9 6 4 4 -1.</_>
         <_>
-          12 10 4 1 2.</_></rects>
+          11 6 2 4 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          8 10 2 1 -1.</_>
+          9 6 3 3 -1.</_>
         <_>
-          9 10 1 1 2.</_></rects>
+          9 7 3 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          8 10 3 1 -1.</_>
+          9 6 6 7 -1.</_>
         <_>
-          9 10 1 1 3.</_></rects>
+          12 6 3 7 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          8 10 3 2 -1.</_>
+          9 6 4 3 -1.</_>
         <_>
-          9 10 1 2 3.</_></rects>
+          9 7 4 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          8 10 2 8 -1.</_>
+          9 6 15 10 -1.</_>
         <_>
-          8 10 1 4 2.</_>
-        <_>
-          9 14 1 4 2.</_></rects>
+          9 11 15 5 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          8 10 4 2 -1.</_>
+          9 7 6 2 -1.</_>
+        <_>
+          9 7 3 1 2.</_>
         <_>
-          10 10 2 2 2.</_></rects>
+          12 8 3 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          8 10 4 8 -1.</_>
-        <_>
-          8 10 2 4 2.</_>
+          9 8 3 3 -1.</_>
         <_>
-          10 14 2 4 2.</_></rects>
+          9 9 3 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          8 11 4 8 -1.</_>
-        <_>
-          8 11 2 4 2.</_>
+          9 8 7 10 -1.</_>
         <_>
-          10 15 2 4 2.</_></rects>
+          9 13 7 5 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          8 14 1 3 -1.</_>
+          9 9 2 2 -1.</_>
         <_>
-          8 15 1 1 3.</_></rects>
+          10 9 1 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          8 14 3 10 -1.</_>
+          9 9 3 3 -1.</_>
         <_>
-          9 14 1 10 3.</_></rects>
+          9 10 3 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          8 16 9 3 -1.</_>
+          9 9 9 6 -1.</_>
         <_>
-          11 16 3 3 3.</_></rects>
+          12 9 3 6 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          8 16 9 4 -1.</_>
+          9 10 2 4 -1.</_>
+        <_>
+          9 10 1 2 2.</_>
         <_>
-          11 16 3 4 3.</_></rects>
+          10 12 1 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          8 17 10 6 -1.</_>
+          9 10 6 2 -1.</_>
         <_>
-          8 19 10 2 3.</_></rects>
+          9 10 3 1 2.</_>
+        <_>
+          12 11 3 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          8 17 10 6 -1.</_>
+          9 10 8 1 -1.</_>
         <_>
-          8 20 10 3 2.</_></rects>
+          13 10 4 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          8 18 9 6 -1.</_>
+          9 10 15 3 -1.</_>
         <_>
-          11 18 3 6 3.</_></rects>
+          9 11 15 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          8 19 3 5 -1.</_>
+          9 11 2 4 -1.</_>
         <_>
-          9 19 1 5 3.</_></rects>
+          9 11 1 2 2.</_>
+        <_>
+          10 13 1 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          8 19 7 3 -1.</_>
+          9 11 2 6 -1.</_>
         <_>
-          8 20 7 1 3.</_></rects>
+          9 11 1 3 2.</_>
+        <_>
+          10 14 1 3 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          8 20 3 3 -1.</_>
+          9 13 2 11 -1.</_>
         <_>
-          9 20 1 3 3.</_></rects>
+          10 13 1 11 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          8 20 3 4 -1.</_>
+          9 14 6 3 -1.</_>
         <_>
-          9 20 1 4 3.</_></rects>
+          11 14 2 3 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          8 20 7 4 -1.</_>
+          9 16 4 3 -1.</_>
         <_>
-          8 22 7 2 2.</_></rects>
+          11 16 2 3 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          8 20 12 4 -1.</_>
+          9 16 6 4 -1.</_>
         <_>
-          8 22 12 2 2.</_></rects>
+          11 16 2 4 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          8 22 3 1 -1.</_>
+          9 16 6 8 -1.</_>
         <_>
-          9 22 1 1 3.</_></rects>
+          11 16 2 8 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          8 22 3 2 -1.</_>
+          9 16 6 3 -1.</_>
         <_>
-          9 22 1 2 3.</_></rects>
+          9 17 6 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          9 0 1 2 -1.</_>
+          9 17 6 2 -1.</_>
         <_>
-          9 1 1 1 2.</_></rects>
+          11 17 2 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          9 0 5 10 -1.</_>
+          9 17 6 7 -1.</_>
         <_>
-          9 5 5 5 2.</_></rects>
+          11 17 2 7 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          9 0 6 4 -1.</_>
+          9 18 5 3 -1.</_>
         <_>
-          9 2 6 2 2.</_></rects>
+          9 19 5 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          9 0 6 8 -1.</_>
+          9 19 3 5 -1.</_>
         <_>
-          9 4 6 4 2.</_></rects>
+          10 19 1 5 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          9 0 7 10 -1.</_>
+          9 19 7 3 -1.</_>
         <_>
-          9 5 7 5 2.</_></rects>
+          9 20 7 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          9 0 14 10 -1.</_>
-        <_>
-          9 0 7 5 2.</_>
+          9 20 3 4 -1.</_>
         <_>
-          16 5 7 5 2.</_></rects>
+          10 20 1 4 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          9 0 8 4 -1.</_>
+          9 20 3 2 -1.</_>
         <_>
-          9 2 8 2 2.</_></rects>
+          9 21 3 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          9 1 2 3 -1.</_>
+          9 20 5 3 -1.</_>
         <_>
-          10 1 1 3 2.</_></rects>
+          9 21 5 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          9 1 15 15 -1.</_>
+          9 20 6 3 -1.</_>
         <_>
-          9 6 15 5 3.</_></rects>
+          9 21 6 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          9 2 2 2 -1.</_>
+          9 20 6 4 -1.</_>
         <_>
-          10 2 1 2 2.</_></rects>
+          9 22 6 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          9 2 6 1 -1.</_>
+          9 20 7 3 -1.</_>
         <_>
-          12 2 3 1 2.</_></rects>
+          9 21 7 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          9 2 6 22 -1.</_>
+          9 20 8 4 -1.</_>
         <_>
-          12 2 3 22 2.</_></rects>
+          9 22 8 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          9 2 6 8 -1.</_>
+          9 21 3 2 -1.</_>
         <_>
-          9 6 6 4 2.</_></rects>
+          10 21 1 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          9 4 4 9 -1.</_>
+          9 22 3 2 -1.</_>
         <_>
-          11 4 2 9 2.</_></rects>
+          10 22 1 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          9 4 3 3 -1.</_>
+          10 0 1 6 -1.</_>
         <_>
-          9 5 3 1 3.</_></rects>
+          10 3 1 3 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          9 4 3 6 -1.</_>
+          10 0 6 1 -1.</_>
         <_>
-          9 7 3 3 2.</_></rects>
+          13 0 3 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          9 4 6 18 -1.</_>
+          10 0 4 8 -1.</_>
         <_>
-          12 4 3 18 2.</_></rects>
+          10 4 4 4 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          9 4 12 2 -1.</_>
+          10 0 14 10 -1.</_>
+        <_>
+          10 0 7 5 2.</_>
         <_>
-          13 4 4 2 3.</_></rects>
+          17 5 7 5 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          9 5 2 6 -1.</_>
+          10 1 4 2 -1.</_>
+        <_>
+          10 1 2 1 2.</_>
         <_>
-          10 5 1 6 2.</_></rects>
+          12 2 2 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          9 5 6 5 -1.</_>
+          10 2 1 6 -1.</_>
         <_>
-          11 5 2 5 3.</_></rects>
+          10 5 1 3 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          9 5 4 15 -1.</_>
+          10 3 6 1 -1.</_>
         <_>
-          11 5 2 15 2.</_></rects>
+          13 3 3 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          9 5 3 3 -1.</_>
+          10 3 9 1 -1.</_>
         <_>
-          9 6 3 1 3.</_></rects>
+          13 3 3 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          9 6 4 9 -1.</_>
+          10 3 3 3 -1.</_>
         <_>
-          11 6 2 9 2.</_></rects>
+          10 4 3 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          9 6 3 3 -1.</_>
+          10 4 3 3 -1.</_>
         <_>
-          9 7 3 1 3.</_></rects>
+          11 4 1 3 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          9 6 4 3 -1.</_>
+          10 4 2 8 -1.</_>
         <_>
-          9 7 4 1 3.</_></rects>
+          11 4 1 8 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          9 7 6 2 -1.</_>
-        <_>
-          9 7 3 1 2.</_>
+          10 5 3 3 -1.</_>
         <_>
-          12 8 3 1 2.</_></rects>
+          11 5 1 3 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          9 7 8 6 -1.</_>
+          10 5 4 11 -1.</_>
         <_>
-          13 7 4 6 2.</_></rects>
+          12 5 2 11 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          9 8 9 9 -1.</_>
+          10 6 6 3 -1.</_>
         <_>
-          12 8 3 9 3.</_></rects>
+          10 7 6 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          9 8 4 3 -1.</_>
+          10 7 2 3 -1.</_>
         <_>
-          9 9 4 1 3.</_></rects>
+          10 8 2 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          9 9 5 3 -1.</_>
+          10 7 4 7 -1.</_>
         <_>
-          9 10 5 1 3.</_></rects>
+          12 7 2 7 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          9 10 9 5 -1.</_>
+          10 7 9 6 -1.</_>
         <_>
-          12 10 3 5 3.</_></rects>
+          13 7 3 6 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          9 10 15 3 -1.</_>
+          10 7 4 3 -1.</_>
         <_>
-          9 11 15 1 3.</_></rects>
+          10 8 4 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          9 11 3 5 -1.</_>
+          10 8 2 3 -1.</_>
         <_>
-          10 11 1 5 3.</_></rects>
+          10 9 2 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          9 15 6 1 -1.</_>
+          10 8 4 2 -1.</_>
         <_>
-          11 15 2 1 3.</_></rects>
+          10 9 4 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          9 15 6 2 -1.</_>
+          10 8 8 10 -1.</_>
         <_>
-          11 15 2 2 3.</_></rects>
+          10 13 8 5 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          9 15 9 9 -1.</_>
+          10 9 1 3 -1.</_>
         <_>
-          12 15 3 9 3.</_></rects>
+          10 10 1 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          9 16 6 3 -1.</_>
+          10 9 2 3 -1.</_>
         <_>
-          11 16 2 3 3.</_></rects>
+          10 10 2 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          9 16 6 4 -1.</_>
+          10 9 6 4 -1.</_>
         <_>
-          11 16 2 4 3.</_></rects>
+          13 9 3 4 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          9 16 6 7 -1.</_>
+          10 10 14 3 -1.</_>
         <_>
-          11 16 2 7 3.</_></rects>
+          10 11 14 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          9 17 6 4 -1.</_>
+          10 11 1 3 -1.</_>
         <_>
-          11 17 2 4 3.</_></rects>
+          10 12 1 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          9 17 5 3 -1.</_>
+          10 11 4 3 -1.</_>
         <_>
-          9 18 5 1 3.</_></rects>
+          10 12 4 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          9 18 8 6 -1.</_>
+          10 12 1 3 -1.</_>
         <_>
-          9 20 8 2 3.</_></rects>
+          10 13 1 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          9 19 3 5 -1.</_>
+          10 12 2 8 -1.</_>
         <_>
-          10 19 1 5 3.</_></rects>
+          10 12 1 4 2.</_>
+        <_>
+          11 16 1 4 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          9 19 6 3 -1.</_>
+          10 15 4 3 -1.</_>
         <_>
-          9 20 6 1 3.</_></rects>
+          10 16 4 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          9 19 6 4 -1.</_>
+          10 15 6 6 -1.</_>
         <_>
-          9 21 6 2 2.</_></rects>
+          10 17 6 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          9 19 8 3 -1.</_>
+          10 16 6 8 -1.</_>
+        <_>
+          10 16 3 4 2.</_>
         <_>
-          9 20 8 1 3.</_></rects>
+          13 20 3 4 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          9 20 3 4 -1.</_>
+          10 16 4 2 -1.</_>
         <_>
-          10 20 1 4 3.</_></rects>
+          10 17 4 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          9 20 5 3 -1.</_>
+          10 16 4 3 -1.</_>
         <_>
-          9 21 5 1 3.</_></rects>
+          10 17 4 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          9 21 3 2 -1.</_>
+          10 17 4 3 -1.</_>
         <_>
-          10 21 1 2 3.</_></rects>
+          10 18 4 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          9 21 3 3 -1.</_>
+          10 17 5 3 -1.</_>
         <_>
-          10 21 1 3 3.</_></rects>
+          10 18 5 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          9 21 6 2 -1.</_>
+          10 18 5 3 -1.</_>
         <_>
-          9 22 6 1 2.</_></rects>
+          10 19 5 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          9 22 3 2 -1.</_>
+          10 19 5 3 -1.</_>
         <_>
-          10 22 1 2 3.</_></rects>
+          10 20 5 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          10 0 4 1 -1.</_>
+          10 20 3 3 -1.</_>
         <_>
-          12 0 2 1 2.</_></rects>
+          11 20 1 3 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          10 0 4 2 -1.</_>
-        <_>
-          10 0 2 1 2.</_>
+          10 20 3 4 -1.</_>
         <_>
-          12 1 2 1 2.</_></rects>
+          11 20 1 4 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          10 0 4 4 -1.</_>
-        <_>
-          10 0 2 2 2.</_>
+          10 20 4 3 -1.</_>
         <_>
-          12 2 2 2 2.</_></rects>
+          10 21 4 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          10 0 3 6 -1.</_>
+          10 20 5 3 -1.</_>
         <_>
-          10 3 3 3 2.</_></rects>
+          10 21 5 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          10 0 14 10 -1.</_>
-        <_>
-          10 0 7 5 2.</_>
+          10 21 3 1 -1.</_>
         <_>
-          17 5 7 5 2.</_></rects>
+          11 21 1 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          10 1 2 9 -1.</_>
+          10 21 3 3 -1.</_>
         <_>
-          11 1 1 9 2.</_></rects>
+          11 21 1 3 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          10 1 4 2 -1.</_>
-        <_>
-          10 1 2 1 2.</_>
+          10 21 6 3 -1.</_>
         <_>
-          12 2 2 1 2.</_></rects>
+          12 21 2 3 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          10 3 2 9 -1.</_>
+          10 21 5 2 -1.</_>
         <_>
-          11 3 1 9 2.</_></rects>
+          10 22 5 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          10 3 9 1 -1.</_>
+          10 22 3 1 -1.</_>
         <_>
-          13 3 3 1 3.</_></rects>
+          11 22 1 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          10 3 6 2 -1.</_>
-        <_>
-          10 3 3 1 2.</_>
+          10 22 3 2 -1.</_>
         <_>
-          13 4 3 1 2.</_></rects>
+          11 22 1 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          10 4 3 3 -1.</_>
+          11 0 2 12 -1.</_>
         <_>
-          10 5 3 1 3.</_></rects>
+          11 4 2 4 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          10 4 7 15 -1.</_>
+          11 0 12 19 -1.</_>
         <_>
-          10 9 7 5 3.</_></rects>
+          15 0 4 19 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          10 5 3 3 -1.</_>
+          11 2 4 20 -1.</_>
         <_>
-          10 6 3 1 3.</_></rects>
+          13 2 2 20 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          10 6 7 3 -1.</_>
+          11 3 3 3 -1.</_>
         <_>
-          10 7 7 1 3.</_></rects>
+          12 3 1 3 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          10 7 2 3 -1.</_>
+          11 3 3 5 -1.</_>
         <_>
-          10 8 2 1 3.</_></rects>
+          12 3 1 5 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          10 7 4 14 -1.</_>
+          11 3 3 6 -1.</_>
         <_>
-          12 7 2 14 2.</_></rects>
+          12 3 1 6 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          10 7 3 3 -1.</_>
+          11 3 3 7 -1.</_>
         <_>
-          10 8 3 1 3.</_></rects>
+          12 3 1 7 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          10 7 4 3 -1.</_>
+          11 3 2 3 -1.</_>
         <_>
-          10 8 4 1 3.</_></rects>
+          11 4 2 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          10 7 8 12 -1.</_>
+          11 3 12 14 -1.</_>
         <_>
-          10 13 8 6 2.</_></rects>
+          15 3 4 14 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          10 9 10 8 -1.</_>
-        <_>
-          10 9 5 4 2.</_>
+          11 4 3 5 -1.</_>
         <_>
-          15 13 5 4 2.</_></rects>
+          12 4 1 5 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          10 9 6 8 -1.</_>
+          11 4 2 3 -1.</_>
         <_>
-          10 13 6 4 2.</_></rects>
+          11 5 2 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          10 10 2 6 -1.</_>
+          11 4 9 1 -1.</_>
         <_>
-          11 10 1 6 2.</_></rects>
+          14 4 3 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          10 10 2 3 -1.</_>
+          11 4 3 3 -1.</_>
         <_>
-          10 11 2 1 3.</_></rects>
+          11 5 3 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          10 10 14 4 -1.</_>
+          11 5 8 4 -1.</_>
         <_>
-          10 12 14 2 2.</_></rects>
+          11 7 8 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          10 11 2 3 -1.</_>
+          11 6 2 3 -1.</_>
         <_>
-          10 12 2 1 3.</_></rects>
+          11 7 2 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          10 12 1 3 -1.</_>
+          11 6 4 3 -1.</_>
         <_>
-          10 13 1 1 3.</_></rects>
+          11 7 4 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          10 15 8 3 -1.</_>
+          11 7 1 3 -1.</_>
         <_>
-          14 15 4 3 2.</_></rects>
+          11 8 1 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          10 16 3 2 -1.</_>
+          11 7 2 2 -1.</_>
         <_>
-          11 16 1 2 3.</_></rects>
+          11 7 1 1 2.</_>
+        <_>
+          12 8 1 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          10 17 4 3 -1.</_>
+          11 7 2 3 -1.</_>
         <_>
-          10 18 4 1 3.</_></rects>
+          11 8 2 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          10 18 12 2 -1.</_>
+          11 7 4 2 -1.</_>
         <_>
-          10 18 6 1 2.</_>
+          11 7 2 1 2.</_>
         <_>
-          16 19 6 1 2.</_></rects>
+          13 8 2 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          10 20 3 2 -1.</_>
+          11 7 4 3 -1.</_>
         <_>
-          11 20 1 2 3.</_></rects>
+          11 8 4 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          10 20 3 3 -1.</_>
+          11 8 1 3 -1.</_>
         <_>
-          11 20 1 3 3.</_></rects>
+          11 9 1 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          10 20 3 4 -1.</_>
+          11 8 1 10 -1.</_>
         <_>
-          11 20 1 4 3.</_></rects>
+          11 13 1 5 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          10 20 4 3 -1.</_>
+          11 8 2 3 -1.</_>
         <_>
-          10 21 4 1 3.</_></rects>
+          11 9 2 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          10 20 4 4 -1.</_>
+          11 8 3 3 -1.</_>
         <_>
-          10 22 4 2 2.</_></rects>
+          11 9 3 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          10 20 5 3 -1.</_>
+          11 8 8 8 -1.</_>
         <_>
-          10 21 5 1 3.</_></rects>
+          11 8 4 4 2.</_>
+        <_>
+          15 12 4 4 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          10 20 5 4 -1.</_>
+          11 8 7 10 -1.</_>
         <_>
-          10 22 5 2 2.</_></rects>
+          11 13 7 5 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          10 20 10 4 -1.</_>
+          11 9 6 6 -1.</_>
         <_>
-          10 20 5 2 2.</_>
-        <_>
-          15 22 5 2 2.</_></rects>
+          13 9 2 6 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          10 20 14 4 -1.</_>
-        <_>
-          10 20 7 2 2.</_>
+          11 9 4 3 -1.</_>
         <_>
-          17 22 7 2 2.</_></rects>
+          11 10 4 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          10 21 3 3 -1.</_>
+          11 10 6 4 -1.</_>
         <_>
-          11 21 1 3 3.</_></rects>
+          13 10 2 4 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          10 21 2 2 -1.</_>
+          11 10 6 8 -1.</_>
         <_>
-          10 22 2 1 2.</_></rects>
+          11 10 3 4 2.</_>
+        <_>
+          14 14 3 4 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          10 21 14 2 -1.</_>
+          11 10 4 3 -1.</_>
         <_>
-          17 21 7 2 2.</_></rects>
+          11 11 4 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          10 22 3 2 -1.</_>
+          11 10 5 3 -1.</_>
         <_>
-          11 22 1 2 3.</_></rects>
+          11 11 5 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          11 1 3 7 -1.</_>
+          11 11 1 3 -1.</_>
         <_>
-          12 1 1 7 3.</_></rects>
+          11 12 1 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          11 1 6 1 -1.</_>
+          11 11 10 10 -1.</_>
+        <_>
+          11 11 5 5 2.</_>
         <_>
-          13 1 2 1 3.</_></rects>
+          16 16 5 5 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          11 1 4 15 -1.</_>
+          11 13 6 2 -1.</_>
         <_>
-          13 1 2 15 2.</_></rects>
+          13 13 2 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          11 2 3 4 -1.</_>
+          11 14 2 9 -1.</_>
         <_>
-          12 2 1 4 3.</_></rects>
+          11 17 2 3 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          11 2 2 12 -1.</_>
+          11 15 1 2 -1.</_>
         <_>
-          12 2 1 12 2.</_></rects>
+          11 16 1 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          11 2 2 13 -1.</_>
+          11 20 3 4 -1.</_>
         <_>
-          12 2 1 13 2.</_></rects>
+          12 20 1 4 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          11 3 1 3 -1.</_>
+          11 20 3 3 -1.</_>
         <_>
-          11 4 1 1 3.</_></rects>
+          11 21 3 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          11 3 3 5 -1.</_>
+          11 21 2 1 -1.</_>
         <_>
-          12 3 1 5 3.</_></rects>
+          12 21 1 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          11 3 3 7 -1.</_>
+          11 21 3 2 -1.</_>
         <_>
-          12 3 1 7 3.</_></rects>
+          12 21 1 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          11 3 6 12 -1.</_>
+          11 21 2 3 -1.</_>
         <_>
-          13 3 2 12 3.</_></rects>
+          12 21 1 3 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          11 3 4 13 -1.</_>
+          11 21 3 2 -1.</_>
         <_>
-          13 3 2 13 2.</_></rects>
+          11 22 3 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          11 3 9 2 -1.</_>
+          11 23 3 1 -1.</_>
         <_>
-          14 3 3 2 3.</_></rects>
+          12 23 1 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          11 4 3 5 -1.</_>
+          12 0 8 12 -1.</_>
         <_>
-          12 4 1 5 3.</_></rects>
+          12 0 4 6 2.</_>
+        <_>
+          16 6 4 6 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          11 4 3 3 -1.</_>
+          12 0 12 6 -1.</_>
         <_>
-          11 5 3 1 3.</_></rects>
+          12 0 6 3 2.</_>
+        <_>
+          18 3 6 3 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          11 5 3 3 -1.</_>
+          12 1 1 3 -1.</_>
         <_>
-          12 5 1 3 3.</_></rects>
+          12 2 1 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          11 5 3 4 -1.</_>
+          12 1 2 7 -1.</_>
         <_>
-          12 5 1 4 3.</_></rects>
+          13 1 1 7 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          11 5 4 10 -1.</_>
+          12 1 12 4 -1.</_>
         <_>
-          13 5 2 10 2.</_></rects>
+          12 1 6 2 2.</_>
+        <_>
+          18 3 6 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          11 5 4 3 -1.</_>
+          12 2 3 3 -1.</_>
         <_>
-          11 6 4 1 3.</_></rects>
+          13 2 1 3 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          11 6 1 3 -1.</_>
+          12 2 3 7 -1.</_>
         <_>
-          11 7 1 1 3.</_></rects>
+          13 2 1 7 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          11 6 2 3 -1.</_>
+          12 2 6 1 -1.</_>
         <_>
-          11 7 2 1 3.</_></rects>
+          14 2 2 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          11 6 6 5 -1.</_>
+          12 2 6 4 -1.</_>
         <_>
-          13 6 2 5 3.</_></rects>
+          14 2 2 4 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          11 6 3 3 -1.</_>
+          12 2 6 18 -1.</_>
         <_>
-          11 7 3 1 3.</_></rects>
+          12 8 6 6 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          11 6 9 11 -1.</_>
+          12 3 6 11 -1.</_>
         <_>
-          14 6 3 11 3.</_></rects>
+          14 3 2 11 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          11 6 4 3 -1.</_>
+          12 3 9 3 -1.</_>
         <_>
-          11 7 4 1 3.</_></rects>
+          15 3 3 3 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          11 6 5 3 -1.</_>
+          12 3 12 3 -1.</_>
         <_>
-          11 7 5 1 3.</_></rects>
+          12 4 12 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          11 7 1 3 -1.</_>
+          12 4 2 12 -1.</_>
         <_>
-          11 8 1 1 3.</_></rects>
+          13 4 1 12 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          11 7 2 3 -1.</_>
+          12 4 2 3 -1.</_>
         <_>
-          11 8 2 1 3.</_></rects>
+          12 5 2 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          11 7 5 3 -1.</_>
+          12 5 3 5 -1.</_>
         <_>
-          11 8 5 1 3.</_></rects>
+          13 5 1 5 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          11 8 1 3 -1.</_>
+          12 5 4 3 -1.</_>
         <_>
-          11 9 1 1 3.</_></rects>
+          12 6 4 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          11 8 2 3 -1.</_>
+          12 6 1 3 -1.</_>
         <_>
-          11 9 2 1 3.</_></rects>
+          12 7 1 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          11 8 3 3 -1.</_>
+          12 6 2 3 -1.</_>
         <_>
-          11 9 3 1 3.</_></rects>
+          12 7 2 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          11 9 2 2 -1.</_>
+          12 6 8 4 -1.</_>
         <_>
-          11 9 1 1 2.</_>
+          12 6 4 2 2.</_>
         <_>
-          12 10 1 1 2.</_></rects>
+          16 8 4 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          11 9 3 3 -1.</_>
+          12 7 1 3 -1.</_>
         <_>
-          11 10 3 1 3.</_></rects>
+          12 8 1 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          11 9 4 3 -1.</_>
+          12 7 2 3 -1.</_>
         <_>
-          11 10 4 1 3.</_></rects>
+          12 8 2 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          11 10 1 3 -1.</_>
+          12 8 1 3 -1.</_>
         <_>
-          11 11 1 1 3.</_></rects>
+          12 9 1 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          11 10 6 4 -1.</_>
+          12 8 3 3 -1.</_>
         <_>
-          13 10 2 4 3.</_></rects>
+          12 9 3 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          11 10 8 2 -1.</_>
-        <_>
-          11 10 4 1 2.</_>
+          12 8 4 3 -1.</_>
         <_>
-          15 11 4 1 2.</_></rects>
+          12 9 4 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          11 11 1 3 -1.</_>
+          12 9 1 3 -1.</_>
         <_>
-          11 12 1 1 3.</_></rects>
+          12 10 1 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          11 12 6 3 -1.</_>
+          12 10 2 12 -1.</_>
         <_>
-          13 12 2 3 3.</_></rects>
+          12 10 1 6 2.</_>
+        <_>
+          13 16 1 6 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          11 14 9 3 -1.</_>
+          12 10 4 10 -1.</_>
+        <_>
+          12 10 2 5 2.</_>
         <_>
-          14 14 3 3 3.</_></rects>
+          14 15 2 5 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          11 16 3 3 -1.</_>
+          12 11 2 3 -1.</_>
         <_>
-          11 17 3 1 3.</_></rects>
+          12 12 2 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          11 18 5 6 -1.</_>
+          12 11 4 4 -1.</_>
         <_>
-          11 20 5 2 3.</_></rects>
+          14 11 2 4 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          11 18 12 6 -1.</_>
+          12 11 4 8 -1.</_>
         <_>
-          11 18 6 3 2.</_>
+          12 11 2 4 2.</_>
         <_>
-          17 21 6 3 2.</_></rects>
+          14 15 2 4 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          11 19 2 4 -1.</_>
+          12 15 6 5 -1.</_>
         <_>
-          11 21 2 2 2.</_></rects>
+          14 15 2 5 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          11 19 12 4 -1.</_>
+          12 15 10 4 -1.</_>
         <_>
-          11 19 6 2 2.</_>
+          12 15 5 2 2.</_>
         <_>
-          17 21 6 2 2.</_></rects>
+          17 17 5 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          11 20 3 2 -1.</_>
+          12 16 4 3 -1.</_>
         <_>
-          12 20 1 2 3.</_></rects>
+          14 16 2 3 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          11 20 3 3 -1.</_>
+          12 17 3 3 -1.</_>
         <_>
-          12 20 1 3 3.</_></rects>
+          13 17 1 3 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          11 20 3 4 -1.</_>
-        <_>
-          12 20 1 4 3.</_></rects>
-      <tilted>0</tilted></_>
-    <_>
-      <rects>
+          12 17 8 6 -1.</_>
         <_>
-          11 21 3 1 -1.</_>
+          12 17 4 3 2.</_>
         <_>
-          12 21 1 1 3.</_></rects>
+          16 20 4 3 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          11 21 2 2 -1.</_>
+          12 18 12 6 -1.</_>
         <_>
-          11 21 1 1 2.</_>
+          12 18 6 3 2.</_>
         <_>
-          12 22 1 1 2.</_></rects>
+          18 21 6 3 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          11 21 3 2 -1.</_>
+          12 21 3 3 -1.</_>
         <_>
-          11 22 3 1 2.</_></rects>
+          13 21 1 3 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          11 22 3 1 -1.</_>
+          13 0 11 14 -1.</_>
         <_>
-          12 22 1 1 3.</_></rects>
+          13 7 11 7 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          11 23 3 1 -1.</_>
+          13 2 2 3 -1.</_>
         <_>
-          12 23 1 1 3.</_></rects>
+          14 2 1 3 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          12 0 12 1 -1.</_>
+          13 3 1 4 -1.</_>
         <_>
-          18 0 6 1 2.</_></rects>
+          13 5 1 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          12 0 12 10 -1.</_>
-        <_>
-          12 0 6 5 2.</_>
+          13 3 3 3 -1.</_>
         <_>
-          18 5 6 5 2.</_></rects>
+          14 3 1 3 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          12 0 12 12 -1.</_>
+          13 3 6 1 -1.</_>
         <_>
-          12 0 6 6 2.</_>
-        <_>
-          18 6 6 6 2.</_></rects>
+          15 3 2 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          12 1 2 12 -1.</_>
+          13 4 1 2 -1.</_>
         <_>
-          13 1 1 12 2.</_></rects>
+          13 5 1 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          12 1 6 7 -1.</_>
+          13 4 3 7 -1.</_>
         <_>
-          14 1 2 7 3.</_></rects>
+          14 4 1 7 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          12 1 6 15 -1.</_>
+          13 4 3 8 -1.</_>
         <_>
-          14 1 2 15 3.</_></rects>
+          14 4 1 8 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          12 1 9 13 -1.</_>
+          13 5 3 6 -1.</_>
         <_>
-          15 1 3 13 3.</_></rects>
+          14 5 1 6 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          12 2 9 4 -1.</_>
+          13 6 1 3 -1.</_>
         <_>
-          15 2 3 4 3.</_></rects>
+          13 7 1 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          12 3 6 1 -1.</_>
+          13 7 6 6 -1.</_>
         <_>
-          14 3 2 1 3.</_></rects>
+          15 7 2 6 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          12 3 6 9 -1.</_>
+          13 7 3 3 -1.</_>
         <_>
-          14 3 2 9 3.</_></rects>
+          13 8 3 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          12 3 6 3 -1.</_>
+          13 8 6 8 -1.</_>
         <_>
-          12 4 6 1 3.</_></rects>
+          15 8 2 8 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          12 4 2 6 -1.</_>
+          13 9 3 4 -1.</_>
         <_>
-          13 4 1 6 2.</_></rects>
+          14 9 1 4 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          12 4 8 6 -1.</_>
+          13 9 4 3 -1.</_>
         <_>
-          12 4 4 3 2.</_>
-        <_>
-          16 7 4 3 2.</_></rects>
+          15 9 2 3 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          12 5 3 3 -1.</_>
+          13 9 6 4 -1.</_>
         <_>
-          12 6 3 1 3.</_></rects>
+          15 9 2 4 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          12 6 1 3 -1.</_>
+          13 9 9 2 -1.</_>
         <_>
-          12 7 1 1 3.</_></rects>
+          16 9 3 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          12 7 1 3 -1.</_>
+          13 9 9 2 -1.</_>
         <_>
-          12 8 1 1 3.</_></rects>
+          13 10 9 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          12 7 2 3 -1.</_>
+          13 10 3 2 -1.</_>
         <_>
-          12 8 2 1 3.</_></rects>
+          14 10 1 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          12 7 3 3 -1.</_>
+          13 10 4 1 -1.</_>
         <_>
-          12 8 3 1 3.</_></rects>
+          15 10 2 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          12 7 4 3 -1.</_>
+          13 10 4 4 -1.</_>
+        <_>
+          13 10 2 2 2.</_>
         <_>
-          12 8 4 1 3.</_></rects>
+          15 12 2 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          12 8 3 3 -1.</_>
+          13 11 2 3 -1.</_>
         <_>
-          12 9 3 1 3.</_></rects>
+          13 12 2 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          12 9 1 3 -1.</_>
+          13 11 3 3 -1.</_>
         <_>
-          12 10 1 1 3.</_></rects>
+          13 12 3 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          12 9 2 3 -1.</_>
+          13 12 3 3 -1.</_>
         <_>
-          12 10 2 1 3.</_></rects>
+          13 13 3 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          12 9 4 6 -1.</_>
+          13 13 2 6 -1.</_>
         <_>
-          12 9 2 3 2.</_>
+          13 13 1 3 2.</_>
         <_>
-          14 12 2 3 2.</_></rects>
+          14 16 1 3 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          12 9 6 7 -1.</_>
+          13 15 2 5 -1.</_>
         <_>
-          14 9 2 7 3.</_></rects>
+          14 15 1 5 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          12 9 6 6 -1.</_>
+          13 19 3 3 -1.</_>
         <_>
-          12 9 3 3 2.</_>
-        <_>
-          15 12 3 3 2.</_></rects>
+          14 19 1 3 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          12 10 6 2 -1.</_>
+          13 20 3 3 -1.</_>
         <_>
-          14 10 2 2 3.</_></rects>
+          14 20 1 3 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          12 10 4 10 -1.</_>
-        <_>
-          12 10 2 5 2.</_>
+          13 22 3 2 -1.</_>
         <_>
-          14 15 2 5 2.</_></rects>
+          14 22 1 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          12 11 4 8 -1.</_>
-        <_>
-          12 11 2 4 2.</_>
+          14 0 1 10 -1.</_>
         <_>
-          14 15 2 4 2.</_></rects>
+          14 5 1 5 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          12 11 6 10 -1.</_>
-        <_>
-          12 11 3 5 2.</_>
+          14 0 2 7 -1.</_>
         <_>
-          15 16 3 5 2.</_></rects>
+          15 0 1 7 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          12 11 8 8 -1.</_>
+          14 0 2 22 -1.</_>
         <_>
-          12 11 4 4 2.</_>
+          14 0 1 11 2.</_>
         <_>
-          16 15 4 4 2.</_></rects>
+          15 11 1 11 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          12 12 9 3 -1.</_>
+          14 0 10 6 -1.</_>
+        <_>
+          14 0 5 3 2.</_>
         <_>
-          15 12 3 3 3.</_></rects>
+          19 3 5 3 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          12 12 10 8 -1.</_>
+          14 0 10 8 -1.</_>
         <_>
-          12 12 5 4 2.</_>
+          14 0 5 4 2.</_>
         <_>
-          17 16 5 4 2.</_></rects>
+          19 4 5 4 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          12 13 4 8 -1.</_>
+          14 0 10 12 -1.</_>
         <_>
-          12 13 2 4 2.</_>
+          14 0 5 6 2.</_>
         <_>
-          14 17 2 4 2.</_></rects>
+          19 6 5 6 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          12 14 3 7 -1.</_>
+          14 1 2 2 -1.</_>
         <_>
-          13 14 1 7 3.</_></rects>
+          15 1 1 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          12 14 8 4 -1.</_>
+          14 1 4 4 -1.</_>
         <_>
-          12 14 4 2 2.</_>
-        <_>
-          16 16 4 2 2.</_></rects>
+          14 3 4 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          12 16 4 3 -1.</_>
+          14 1 10 2 -1.</_>
         <_>
-          14 16 2 3 2.</_></rects>
+          19 1 5 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          12 19 3 5 -1.</_>
+          14 2 6 7 -1.</_>
         <_>
-          13 19 1 5 3.</_></rects>
+          16 2 2 7 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          12 20 3 4 -1.</_>
+          14 3 2 4 -1.</_>
+        <_>
+          14 3 1 2 2.</_>
         <_>
-          13 20 1 4 3.</_></rects>
+          15 5 1 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          12 21 3 3 -1.</_>
+          14 4 3 3 -1.</_>
         <_>
-          13 21 1 3 3.</_></rects>
+          15 4 1 3 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          12 22 3 2 -1.</_>
+          14 4 6 1 -1.</_>
         <_>
-          13 22 1 2 3.</_></rects>
+          16 4 2 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          13 0 1 10 -1.</_>
+          14 4 3 3 -1.</_>
         <_>
-          13 5 1 5 2.</_></rects>
+          14 5 3 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          13 1 2 12 -1.</_>
+          14 5 3 2 -1.</_>
         <_>
-          14 1 1 12 2.</_></rects>
+          15 5 1 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          13 1 6 8 -1.</_>
+          14 5 3 3 -1.</_>
         <_>
-          15 1 2 8 3.</_></rects>
+          15 5 1 3 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          13 2 2 3 -1.</_>
+          14 5 4 2 -1.</_>
         <_>
-          14 2 1 3 2.</_></rects>
+          16 5 2 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          13 2 2 6 -1.</_>
-        <_>
-          13 2 1 3 2.</_>
+          14 5 3 10 -1.</_>
         <_>
-          14 5 1 3 2.</_></rects>
+          14 10 3 5 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          13 3 1 4 -1.</_>
+          14 5 4 6 -1.</_>
         <_>
-          13 5 1 2 2.</_></rects>
+          14 7 4 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          13 3 2 4 -1.</_>
+          14 6 3 2 -1.</_>
         <_>
-          13 3 1 2 2.</_>
-        <_>
-          14 5 1 2 2.</_></rects>
+          15 6 1 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          13 3 6 8 -1.</_>
+          14 6 3 4 -1.</_>
         <_>
-          15 3 2 8 3.</_></rects>
+          15 6 1 4 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          13 4 6 9 -1.</_>
+          14 6 2 6 -1.</_>
         <_>
-          15 4 2 9 3.</_></rects>
+          15 6 1 6 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          13 5 3 5 -1.</_>
+          14 6 6 2 -1.</_>
         <_>
-          14 5 1 5 3.</_></rects>
+          16 6 2 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          13 5 3 6 -1.</_>
+          14 6 6 17 -1.</_>
         <_>
-          14 5 1 6 3.</_></rects>
+          16 6 2 17 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          13 6 2 3 -1.</_>
+          14 8 2 13 -1.</_>
         <_>
-          13 7 2 1 3.</_></rects>
+          15 8 1 13 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          13 7 2 4 -1.</_>
+          14 8 4 6 -1.</_>
         <_>
-          14 7 1 4 2.</_></rects>
+          14 10 4 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          13 8 2 3 -1.</_>
+          14 9 2 2 -1.</_>
         <_>
-          13 9 2 1 3.</_></rects>
+          15 9 1 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          13 8 6 8 -1.</_>
-        <_>
-          13 8 3 4 2.</_>
+          14 9 3 2 -1.</_>
         <_>
-          16 12 3 4 2.</_></rects>
+          15 9 1 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          13 9 9 2 -1.</_>
+          14 9 2 4 -1.</_>
         <_>
-          16 9 3 2 3.</_></rects>
+          14 9 1 2 2.</_>
+        <_>
+          15 11 1 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          13 10 3 1 -1.</_>
+          14 9 2 3 -1.</_>
         <_>
-          14 10 1 1 3.</_></rects>
+          15 9 1 3 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          13 10 3 2 -1.</_>
+          14 9 4 1 -1.</_>
         <_>
-          14 10 1 2 3.</_></rects>
+          16 9 2 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          13 10 2 3 -1.</_>
+          14 9 6 1 -1.</_>
         <_>
-          13 11 2 1 3.</_></rects>
+          16 9 2 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          13 10 4 8 -1.</_>
+          14 9 9 9 -1.</_>
         <_>
-          13 10 2 4 2.</_>
-        <_>
-          15 14 2 4 2.</_></rects>
+          14 12 9 3 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          13 10 9 1 -1.</_>
+          14 10 2 1 -1.</_>
         <_>
-          16 10 3 1 3.</_></rects>
+          15 10 1 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          13 11 2 3 -1.</_>
+          14 10 3 1 -1.</_>
         <_>
-          13 12 2 1 3.</_></rects>
+          15 10 1 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          13 11 4 2 -1.</_>
+          14 10 2 2 -1.</_>
         <_>
-          13 11 2 1 2.</_>
+          14 10 1 1 2.</_>
         <_>
-          15 12 2 1 2.</_></rects>
+          15 11 1 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          13 15 6 1 -1.</_>
+          14 10 2 2 -1.</_>
         <_>
-          15 15 2 1 3.</_></rects>
+          15 10 1 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          13 17 8 1 -1.</_>
+          14 10 3 2 -1.</_>
         <_>
-          17 17 4 1 2.</_></rects>
+          15 10 1 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          13 19 3 5 -1.</_>
+          14 10 3 3 -1.</_>
         <_>
-          14 19 1 5 3.</_></rects>
+          15 10 1 3 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          13 20 3 2 -1.</_>
+          14 10 2 6 -1.</_>
+        <_>
+          14 10 1 3 2.</_>
         <_>
-          14 20 1 2 3.</_></rects>
+          15 13 1 3 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          13 21 3 3 -1.</_>
+          14 12 6 2 -1.</_>
         <_>
-          14 21 1 3 3.</_></rects>
+          16 12 2 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          14 0 1 2 -1.</_>
+          14 12 6 5 -1.</_>
         <_>
-          14 1 1 1 2.</_></rects>
+          16 12 2 5 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          14 0 10 6 -1.</_>
+          14 14 8 6 -1.</_>
         <_>
-          14 0 5 3 2.</_>
+          14 14 4 3 2.</_>
         <_>
-          19 3 5 3 2.</_></rects>
+          18 17 4 3 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          14 1 1 8 -1.</_>
+          14 14 10 10 -1.</_>
         <_>
-          14 5 1 4 2.</_></rects>
+          14 14 5 5 2.</_>
+        <_>
+          19 19 5 5 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          14 2 3 8 -1.</_>
+          14 16 10 8 -1.</_>
+        <_>
+          14 16 5 4 2.</_>
         <_>
-          15 2 1 8 3.</_></rects>
+          19 20 5 4 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          14 2 3 12 -1.</_>
+          14 18 8 4 -1.</_>
         <_>
-          15 2 1 12 3.</_></rects>
+          14 18 4 2 2.</_>
+        <_>
+          18 20 4 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          14 2 7 3 -1.</_>
+          14 19 3 4 -1.</_>
         <_>
-          14 3 7 1 3.</_></rects>
+          15 19 1 4 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          14 3 6 3 -1.</_>
+          14 19 3 5 -1.</_>
         <_>
-          14 4 6 1 3.</_></rects>
+          15 19 1 5 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          14 4 1 4 -1.</_>
+          14 20 3 4 -1.</_>
         <_>
-          14 6 1 2 2.</_></rects>
+          15 20 1 4 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          14 4 3 6 -1.</_>
+          14 23 3 1 -1.</_>
         <_>
-          15 4 1 6 3.</_></rects>
+          15 23 1 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          14 4 3 7 -1.</_>
+          15 0 8 1 -1.</_>
         <_>
-          15 4 1 7 3.</_></rects>
+          19 0 4 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          14 4 3 3 -1.</_>
+          15 0 8 2 -1.</_>
         <_>
-          14 5 3 1 3.</_></rects>
+          19 0 4 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          14 4 7 3 -1.</_>
+          15 2 2 10 -1.</_>
         <_>
-          14 5 7 1 3.</_></rects>
+          16 2 1 10 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          14 4 8 3 -1.</_>
+          15 2 6 7 -1.</_>
         <_>
-          14 5 8 1 3.</_></rects>
+          17 2 2 7 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          14 4 10 6 -1.</_>
+          15 2 5 3 -1.</_>
         <_>
-          14 6 10 2 3.</_></rects>
+          15 3 5 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          14 5 3 2 -1.</_>
+          15 4 2 6 -1.</_>
         <_>
-          15 5 1 2 3.</_></rects>
+          16 4 1 6 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          14 5 3 3 -1.</_>
+          15 4 2 8 -1.</_>
         <_>
-          15 5 1 3 3.</_></rects>
+          16 4 1 8 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          14 5 3 4 -1.</_>
+          15 4 6 8 -1.</_>
         <_>
-          15 5 1 4 3.</_></rects>
+          18 4 3 8 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          14 5 2 6 -1.</_>
+          15 4 8 3 -1.</_>
         <_>
-          15 5 1 6 2.</_></rects>
+          15 5 8 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          14 5 3 6 -1.</_>
+          15 5 2 2 -1.</_>
         <_>
-          15 5 1 6 3.</_></rects>
+          16 5 1 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          14 5 5 6 -1.</_>
+          15 5 3 2 -1.</_>
         <_>
-          14 7 5 2 3.</_></rects>
+          16 5 1 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          14 7 6 16 -1.</_>
+          15 5 3 3 -1.</_>
         <_>
-          16 7 2 16 3.</_></rects>
+          16 5 1 3 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          14 8 2 6 -1.</_>
-        <_>
-          14 8 1 3 2.</_>
+          15 5 3 6 -1.</_>
         <_>
-          15 11 1 3 2.</_></rects>
+          16 5 1 6 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          14 9 2 3 -1.</_>
+          15 6 3 18 -1.</_>
         <_>
-          15 9 1 3 2.</_></rects>
+          15 12 3 6 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          14 9 2 8 -1.</_>
+          15 6 6 7 -1.</_>
         <_>
-          14 9 1 4 2.</_>
-        <_>
-          15 13 1 4 2.</_></rects>
+          18 6 3 7 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          14 9 4 1 -1.</_>
+          15 6 8 4 -1.</_>
         <_>
-          16 9 2 1 2.</_></rects>
+          15 6 4 2 2.</_>
+        <_>
+          19 8 4 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          14 9 9 2 -1.</_>
+          15 7 3 6 -1.</_>
         <_>
-          14 10 9 1 2.</_></rects>
+          15 9 3 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          14 10 2 1 -1.</_>
+          15 7 5 4 -1.</_>
         <_>
-          15 10 1 1 2.</_></rects>
+          15 9 5 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          14 10 3 1 -1.</_>
+          15 7 5 6 -1.</_>
         <_>
-          15 10 1 1 3.</_></rects>
+          15 9 5 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          14 10 2 2 -1.</_>
+          15 7 6 6 -1.</_>
         <_>
-          15 10 1 2 2.</_></rects>
+          15 9 6 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          14 10 3 2 -1.</_>
+          15 7 7 3 -1.</_>
         <_>
-          15 10 1 2 3.</_></rects>
+          15 8 7 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          14 10 2 3 -1.</_>
+          15 7 9 6 -1.</_>
         <_>
-          15 10 1 3 2.</_></rects>
+          15 9 9 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          14 10 2 6 -1.</_>
+          15 8 2 2 -1.</_>
         <_>
-          14 10 1 3 2.</_>
+          15 8 1 1 2.</_>
         <_>
-          15 13 1 3 2.</_></rects>
+          16 9 1 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          14 10 2 8 -1.</_>
+          15 8 2 4 -1.</_>
         <_>
-          14 10 1 4 2.</_>
+          15 8 1 2 2.</_>
         <_>
-          15 14 1 4 2.</_></rects>
+          16 10 1 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          14 13 3 8 -1.</_>
+          15 8 1 12 -1.</_>
         <_>
-          15 13 1 8 3.</_></rects>
+          15 14 1 6 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          14 18 8 6 -1.</_>
+          15 9 2 2 -1.</_>
         <_>
-          14 18 4 3 2.</_>
+          15 9 1 1 2.</_>
         <_>
-          18 21 4 3 2.</_></rects>
+          16 10 1 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          14 22 3 2 -1.</_>
+          15 9 3 4 -1.</_>
         <_>
-          15 22 1 2 3.</_></rects>
+          16 9 1 4 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          15 0 3 11 -1.</_>
+          15 9 2 3 -1.</_>
         <_>
-          16 0 1 11 3.</_></rects>
+          15 10 2 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          15 2 4 4 -1.</_>
+          15 9 7 3 -1.</_>
         <_>
-          15 4 4 2 2.</_></rects>
+          15 10 7 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          15 3 2 3 -1.</_>
+          15 10 2 1 -1.</_>
         <_>
-          15 4 2 1 3.</_></rects>
+          16 10 1 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          15 4 2 9 -1.</_>
+          15 10 3 1 -1.</_>
         <_>
-          16 4 1 9 2.</_></rects>
+          16 10 1 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          15 4 6 6 -1.</_>
+          15 10 3 4 -1.</_>
         <_>
-          15 6 6 2 3.</_></rects>
+          16 10 1 4 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          15 5 2 2 -1.</_>
+          15 10 3 5 -1.</_>
         <_>
-          16 5 1 2 2.</_></rects>
+          16 10 1 5 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          15 5 3 3 -1.</_>
+          15 12 4 8 -1.</_>
         <_>
-          16 5 1 3 3.</_></rects>
+          15 12 2 4 2.</_>
+        <_>
+          17 16 2 4 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          15 6 3 1 -1.</_>
+          15 15 4 3 -1.</_>
         <_>
-          16 6 1 1 3.</_></rects>
+          15 16 4 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          15 6 3 8 -1.</_>
+          15 16 5 3 -1.</_>
         <_>
-          15 10 3 4 2.</_></rects>
+          15 17 5 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          15 7 4 6 -1.</_>
+          15 19 3 4 -1.</_>
         <_>
-          15 9 4 2 3.</_></rects>
+          16 19 1 4 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          15 7 6 3 -1.</_>
+          15 19 9 3 -1.</_>
         <_>
-          15 8 6 1 3.</_></rects>
+          15 20 9 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          15 7 6 6 -1.</_>
+          15 20 6 3 -1.</_>
         <_>
-          15 9 6 2 3.</_></rects>
+          18 20 3 3 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          15 7 7 3 -1.</_>
+          16 0 8 1 -1.</_>
         <_>
-          15 8 7 1 3.</_></rects>
+          20 0 4 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          15 7 9 6 -1.</_>
+          16 0 8 2 -1.</_>
         <_>
-          15 9 9 2 3.</_></rects>
+          20 0 4 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          15 8 2 2 -1.</_>
+          16 0 8 4 -1.</_>
         <_>
-          15 8 1 1 2.</_>
+          16 0 4 2 2.</_>
         <_>
-          16 9 1 1 2.</_></rects>
+          20 2 4 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          15 9 1 10 -1.</_>
+          16 0 8 6 -1.</_>
+        <_>
+          16 0 4 3 2.</_>
         <_>
-          15 14 1 5 2.</_></rects>
+          20 3 4 3 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          15 9 3 5 -1.</_>
+          16 0 8 8 -1.</_>
+        <_>
+          16 0 4 4 2.</_>
         <_>
-          16 9 1 5 3.</_></rects>
+          20 4 4 4 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          15 9 6 4 -1.</_>
+          16 0 8 12 -1.</_>
+        <_>
+          16 0 4 6 2.</_>
         <_>
-          18 9 3 4 2.</_></rects>
+          20 6 4 6 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          15 9 3 15 -1.</_>
+          16 1 4 13 -1.</_>
         <_>
-          15 14 3 5 3.</_></rects>
+          18 1 2 13 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          15 9 6 3 -1.</_>
+          16 2 3 2 -1.</_>
         <_>
-          15 10 6 1 3.</_></rects>
+          17 2 1 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          15 10 2 1 -1.</_>
+          16 3 2 3 -1.</_>
         <_>
-          16 10 1 1 2.</_></rects>
+          16 4 2 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          15 10 3 1 -1.</_>
+          16 4 1 3 -1.</_>
         <_>
-          16 10 1 1 3.</_></rects>
+          16 5 1 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          15 10 3 4 -1.</_>
+          16 4 2 2 -1.</_>
         <_>
-          16 10 1 4 3.</_></rects>
+          16 4 1 1 2.</_>
+        <_>
+          17 5 1 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          15 10 3 3 -1.</_>
+          16 5 2 3 -1.</_>
         <_>
-          15 11 3 1 3.</_></rects>
+          17 5 1 3 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          15 11 3 2 -1.</_>
+          16 6 2 9 -1.</_>
         <_>
-          15 12 3 1 2.</_></rects>
+          16 9 2 3 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          15 11 3 12 -1.</_>
+          16 6 4 4 -1.</_>
         <_>
-          15 15 3 4 3.</_></rects>
+          18 6 2 4 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          15 11 9 6 -1.</_>
+          16 6 3 9 -1.</_>
         <_>
-          15 13 9 2 3.</_></rects>
+          16 9 3 3 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          15 14 2 10 -1.</_>
+          16 6 7 6 -1.</_>
         <_>
-          15 19 2 5 2.</_></rects>
+          16 8 7 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          15 14 8 3 -1.</_>
+          16 7 1 6 -1.</_>
         <_>
-          19 14 4 3 2.</_></rects>
+          16 9 1 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          15 14 5 3 -1.</_>
+          16 7 2 3 -1.</_>
         <_>
-          15 15 5 1 3.</_></rects>
+          16 8 2 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          15 16 6 8 -1.</_>
-        <_>
-          15 16 3 4 2.</_>
+          16 7 2 6 -1.</_>
         <_>
-          18 20 3 4 2.</_></rects>
+          16 9 2 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          15 17 7 3 -1.</_>
+          16 7 3 2 -1.</_>
         <_>
-          15 18 7 1 3.</_></rects>
+          16 8 3 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          15 19 9 3 -1.</_>
+          16 7 3 3 -1.</_>
         <_>
-          15 20 9 1 3.</_></rects>
+          16 8 3 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          16 0 8 1 -1.</_>
+          16 7 3 6 -1.</_>
         <_>
-          20 0 4 1 2.</_></rects>
+          16 9 3 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          16 0 8 2 -1.</_>
+          16 7 6 4 -1.</_>
         <_>
-          20 0 4 2 2.</_></rects>
+          16 7 3 2 2.</_>
+        <_>
+          19 9 3 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          16 0 8 6 -1.</_>
-        <_>
-          16 0 4 3 2.</_>
+          16 7 4 3 -1.</_>
         <_>
-          20 3 4 3 2.</_></rects>
+          16 8 4 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          16 0 8 8 -1.</_>
-        <_>
-          16 0 4 4 2.</_>
+          16 7 4 6 -1.</_>
         <_>
-          20 4 4 4 2.</_></rects>
+          16 9 4 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          16 0 8 12 -1.</_>
-        <_>
-          16 0 4 6 2.</_>
+          16 8 1 2 -1.</_>
         <_>
-          20 6 4 6 2.</_></rects>
+          16 9 1 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          16 3 2 4 -1.</_>
+          16 8 2 2 -1.</_>
         <_>
-          16 3 1 2 2.</_>
+          16 8 1 1 2.</_>
         <_>
-          17 5 1 2 2.</_></rects>
+          17 9 1 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          16 3 7 3 -1.</_>
+          16 8 2 2 -1.</_>
         <_>
-          16 4 7 1 3.</_></rects>
+          16 9 2 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          16 4 2 9 -1.</_>
+          16 8 8 2 -1.</_>
         <_>
-          16 7 2 3 3.</_></rects>
+          16 8 4 1 2.</_>
+        <_>
+          20 9 4 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          16 5 4 10 -1.</_>
-        <_>
-          16 5 2 5 2.</_>
+          16 9 3 1 -1.</_>
         <_>
-          18 10 2 5 2.</_></rects>
+          17 9 1 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          16 5 8 6 -1.</_>
-        <_>
-          16 5 4 3 2.</_>
+          16 9 1 3 -1.</_>
         <_>
-          20 8 4 3 2.</_></rects>
+          16 10 1 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          16 6 2 6 -1.</_>
+          16 9 2 3 -1.</_>
         <_>
-          16 8 2 2 3.</_></rects>
+          17 9 1 3 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          16 6 3 9 -1.</_>
+          16 9 4 1 -1.</_>
         <_>
-          16 9 3 3 3.</_></rects>
+          18 9 2 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          16 6 6 6 -1.</_>
+          16 9 2 2 -1.</_>
         <_>
-          16 8 6 2 3.</_></rects>
+          16 10 2 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          16 7 1 3 -1.</_>
+          16 9 4 4 -1.</_>
         <_>
-          16 8 1 1 3.</_></rects>
+          18 9 2 4 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          16 7 1 6 -1.</_>
+          16 9 6 6 -1.</_>
         <_>
-          16 9 1 2 3.</_></rects>
+          16 9 3 3 2.</_>
+        <_>
+          19 12 3 3 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          16 7 3 16 -1.</_>
+          16 10 1 2 -1.</_>
         <_>
-          17 7 1 16 3.</_></rects>
+          16 11 1 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          16 7 4 1 -1.</_>
+          16 10 1 3 -1.</_>
         <_>
-          18 7 2 1 2.</_></rects>
+          16 11 1 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          16 7 2 2 -1.</_>
+          16 10 2 2 -1.</_>
+        <_>
+          16 10 1 1 2.</_>
         <_>
-          16 8 2 1 2.</_></rects>
+          17 11 1 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          16 7 2 3 -1.</_>
+          16 10 2 2 -1.</_>
         <_>
-          16 8 2 1 3.</_></rects>
+          17 10 1 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          16 7 4 2 -1.</_>
+          16 10 2 5 -1.</_>
         <_>
-          18 7 2 2 2.</_></rects>
+          17 10 1 5 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          16 7 2 6 -1.</_>
+          16 10 3 13 -1.</_>
         <_>
-          16 9 2 2 3.</_></rects>
+          17 10 1 13 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          16 7 2 15 -1.</_>
+          16 10 2 3 -1.</_>
         <_>
-          16 12 2 5 3.</_></rects>
+          16 11 2 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          16 7 4 6 -1.</_>
+          16 10 3 3 -1.</_>
         <_>
-          18 7 2 6 2.</_></rects>
+          16 11 3 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          16 7 3 3 -1.</_>
+          16 11 1 2 -1.</_>
         <_>
-          16 8 3 1 3.</_></rects>
+          16 12 1 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          16 7 3 6 -1.</_>
+          16 11 3 2 -1.</_>
         <_>
-          16 9 3 2 3.</_></rects>
+          17 11 1 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          16 7 4 6 -1.</_>
+          16 11 2 2 -1.</_>
         <_>
-          16 9 4 2 3.</_></rects>
+          16 12 2 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          16 8 1 2 -1.</_>
+          16 11 2 3 -1.</_>
         <_>
-          16 9 1 1 2.</_></rects>
+          16 12 2 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          16 8 2 2 -1.</_>
-        <_>
-          16 8 1 1 2.</_>
+          16 13 3 3 -1.</_>
         <_>
-          17 9 1 1 2.</_></rects>
+          16 14 3 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          16 8 2 5 -1.</_>
+          16 14 4 1 -1.</_>
         <_>
-          17 8 1 5 2.</_></rects>
+          18 14 2 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          16 8 2 2 -1.</_>
+          16 15 4 3 -1.</_>
         <_>
-          16 9 2 1 2.</_></rects>
+          18 15 2 3 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          16 8 6 2 -1.</_>
-        <_>
-          16 8 3 1 2.</_>
+          16 15 6 2 -1.</_>
         <_>
-          19 9 3 1 2.</_></rects>
+          19 15 3 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          16 8 6 3 -1.</_>
+          16 15 8 3 -1.</_>
         <_>
-          16 9 6 1 3.</_></rects>
+          20 15 4 3 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          16 9 1 3 -1.</_>
+          16 16 4 1 -1.</_>
         <_>
-          16 10 1 1 3.</_></rects>
+          18 16 2 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          16 9 6 3 -1.</_>
+          16 17 3 7 -1.</_>
         <_>
-          16 10 6 1 3.</_></rects>
+          17 17 1 7 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          16 10 1 3 -1.</_>
+          16 17 6 3 -1.</_>
         <_>
-          16 11 1 1 3.</_></rects>
+          16 18 6 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          16 10 2 3 -1.</_>
+          16 19 3 4 -1.</_>
         <_>
-          16 11 2 1 3.</_></rects>
+          17 19 1 4 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          16 10 6 2 -1.</_>
-        <_>
-          16 10 3 1 2.</_>
+          17 0 6 1 -1.</_>
         <_>
-          19 11 3 1 2.</_></rects>
+          20 0 3 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          16 10 4 2 -1.</_>
+          17 2 1 4 -1.</_>
         <_>
-          16 11 4 1 2.</_></rects>
+          17 4 1 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          16 10 6 4 -1.</_>
+          17 3 3 1 -1.</_>
         <_>
-          16 12 6 2 2.</_></rects>
+          18 3 1 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          16 11 3 2 -1.</_>
+          17 3 3 2 -1.</_>
         <_>
-          17 11 1 2 3.</_></rects>
+          18 3 1 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          16 11 2 2 -1.</_>
+          17 3 2 8 -1.</_>
         <_>
-          16 12 2 1 2.</_></rects>
+          17 3 1 4 2.</_>
+        <_>
+          18 7 1 4 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          16 11 2 3 -1.</_>
+          17 3 3 3 -1.</_>
         <_>
-          16 12 2 1 3.</_></rects>
+          17 4 3 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          16 11 3 3 -1.</_>
+          17 4 1 3 -1.</_>
         <_>
-          16 12 3 1 3.</_></rects>
+          17 5 1 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          16 11 4 2 -1.</_>
+          17 4 2 2 -1.</_>
         <_>
-          16 12 4 1 2.</_></rects>
+          18 4 1 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          16 11 8 6 -1.</_>
+          17 4 2 6 -1.</_>
         <_>
-          16 11 4 3 2.</_>
+          17 4 1 3 2.</_>
         <_>
-          20 14 4 3 2.</_></rects>
+          18 7 1 3 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          16 12 4 8 -1.</_>
-        <_>
-          16 12 2 4 2.</_>
+          17 6 1 6 -1.</_>
         <_>
-          18 16 2 4 2.</_></rects>
+          17 8 1 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          16 13 2 2 -1.</_>
+          17 6 4 8 -1.</_>
         <_>
-          16 13 1 1 2.</_>
+          17 6 2 4 2.</_>
         <_>
-          17 14 1 1 2.</_></rects>
+          19 10 2 4 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          16 13 4 6 -1.</_>
-        <_>
-          16 13 2 3 2.</_>
+          17 6 3 3 -1.</_>
         <_>
-          18 16 2 3 2.</_></rects>
+          17 7 3 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          16 13 8 8 -1.</_>
+          17 6 5 3 -1.</_>
         <_>
-          20 13 4 8 2.</_></rects>
+          17 7 5 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          16 14 8 5 -1.</_>
+          17 7 1 3 -1.</_>
         <_>
-          20 14 4 5 2.</_></rects>
+          17 8 1 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          16 15 4 4 -1.</_>
+          17 7 1 6 -1.</_>
         <_>
-          18 15 2 4 2.</_></rects>
+          17 9 1 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          16 15 4 8 -1.</_>
+          17 7 2 6 -1.</_>
         <_>
-          16 15 2 4 2.</_>
+          17 7 1 3 2.</_>
         <_>
-          18 19 2 4 2.</_></rects>
+          18 10 1 3 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          16 15 3 3 -1.</_>
+          17 7 2 3 -1.</_>
         <_>
-          16 16 3 1 3.</_></rects>
+          17 8 2 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          16 15 6 3 -1.</_>
+          17 8 6 4 -1.</_>
         <_>
-          19 15 3 3 2.</_></rects>
+          17 10 6 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          16 16 3 3 -1.</_>
+          17 9 3 1 -1.</_>
         <_>
-          16 17 3 1 3.</_></rects>
+          18 9 1 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          16 18 3 3 -1.</_>
+          17 9 2 6 -1.</_>
         <_>
-          17 18 1 3 3.</_></rects>
+          17 9 1 3 2.</_>
+        <_>
+          18 12 1 3 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          16 18 3 6 -1.</_>
+          17 9 4 2 -1.</_>
+        <_>
+          17 9 2 1 2.</_>
         <_>
-          17 18 1 6 3.</_></rects>
+          19 10 2 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          16 20 3 4 -1.</_>
+          17 9 3 2 -1.</_>
         <_>
-          17 20 1 4 3.</_></rects>
+          17 10 3 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          16 22 3 1 -1.</_>
+          17 9 5 3 -1.</_>
         <_>
-          17 22 1 1 3.</_></rects>
+          17 10 5 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          17 0 1 8 -1.</_>
+          17 9 7 2 -1.</_>
         <_>
-          17 4 1 4 2.</_></rects>
+          17 10 7 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          17 0 6 1 -1.</_>
+          17 10 1 3 -1.</_>
         <_>
-          20 0 3 1 2.</_></rects>
+          17 11 1 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          17 2 3 3 -1.</_>
+          17 10 2 2 -1.</_>
+        <_>
+          17 10 1 1 2.</_>
         <_>
-          18 2 1 3 3.</_></rects>
+          18 11 1 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          17 3 3 1 -1.</_>
+          17 10 2 4 -1.</_>
         <_>
-          18 3 1 1 3.</_></rects>
+          18 10 1 4 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          17 3 4 15 -1.</_>
+          17 10 3 4 -1.</_>
         <_>
-          17 8 4 5 3.</_></rects>
+          18 10 1 4 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          17 4 2 6 -1.</_>
+          17 10 4 2 -1.</_>
         <_>
-          17 4 1 3 2.</_>
+          17 10 2 1 2.</_>
         <_>
-          18 7 1 3 2.</_></rects>
+          19 11 2 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          17 5 1 9 -1.</_>
+          17 11 1 3 -1.</_>
         <_>
-          17 8 1 3 3.</_></rects>
+          17 12 1 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          17 6 3 3 -1.</_>
+          17 11 3 2 -1.</_>
         <_>
-          17 7 3 1 3.</_></rects>
+          18 11 1 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          17 6 4 3 -1.</_>
+          17 11 3 3 -1.</_>
         <_>
-          17 7 4 1 3.</_></rects>
+          18 11 1 3 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          17 7 1 3 -1.</_>
+          17 11 2 2 -1.</_>
         <_>
-          17 8 1 1 3.</_></rects>
+          17 12 2 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          17 7 1 6 -1.</_>
+          17 11 4 2 -1.</_>
         <_>
-          17 9 1 2 3.</_></rects>
+          17 11 2 1 2.</_>
+        <_>
+          19 12 2 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          17 7 2 2 -1.</_>
+          17 12 3 2 -1.</_>
         <_>
-          17 8 2 1 2.</_></rects>
+          18 12 1 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          17 7 2 3 -1.</_>
+          17 13 4 5 -1.</_>
         <_>
-          17 8 2 1 3.</_></rects>
+          19 13 2 5 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          17 7 2 6 -1.</_>
+          17 14 2 3 -1.</_>
         <_>
-          17 9 2 2 3.</_></rects>
+          17 15 2 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          17 7 3 3 -1.</_>
+          17 14 4 2 -1.</_>
         <_>
-          17 8 3 1 3.</_></rects>
+          19 14 2 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          17 8 1 3 -1.</_>
+          17 15 4 2 -1.</_>
         <_>
-          17 9 1 1 3.</_></rects>
+          19 15 2 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          17 8 2 2 -1.</_>
-        <_>
-          17 8 1 1 2.</_>
+          17 16 4 3 -1.</_>
         <_>
-          18 9 1 1 2.</_></rects>
+          19 16 2 3 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          17 8 1 4 -1.</_>
+          17 17 3 7 -1.</_>
         <_>
-          17 10 1 2 2.</_></rects>
+          18 17 1 7 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          17 8 5 14 -1.</_>
+          17 19 3 4 -1.</_>
         <_>
-          17 15 5 7 2.</_></rects>
+          18 19 1 4 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          17 9 3 1 -1.</_>
+          17 21 3 3 -1.</_>
         <_>
-          18 9 1 1 3.</_></rects>
+          18 21 1 3 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          17 9 1 4 -1.</_>
+          18 0 4 1 -1.</_>
         <_>
-          17 11 1 2 2.</_></rects>
+          20 0 2 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          17 9 4 6 -1.</_>
+          18 0 6 1 -1.</_>
         <_>
-          17 11 4 2 3.</_></rects>
+          21 0 3 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          17 9 7 2 -1.</_>
+          18 0 6 4 -1.</_>
         <_>
-          17 10 7 1 2.</_></rects>
+          21 0 3 4 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          17 10 1 3 -1.</_>
+          18 1 1 12 -1.</_>
         <_>
-          17 11 1 1 3.</_></rects>
+          18 5 1 4 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          17 10 3 14 -1.</_>
+          18 2 3 3 -1.</_>
         <_>
-          18 10 1 14 3.</_></rects>
+          19 2 1 3 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          17 10 4 1 -1.</_>
+          18 3 3 2 -1.</_>
         <_>
-          19 10 2 1 2.</_></rects>
+          19 3 1 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          17 10 2 3 -1.</_>
+          18 3 1 9 -1.</_>
         <_>
-          17 11 2 1 3.</_></rects>
+          18 6 1 3 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          17 10 4 2 -1.</_>
-        <_>
-          17 10 2 1 2.</_>
+          18 3 3 4 -1.</_>
         <_>
-          19 11 2 1 2.</_></rects>
+          19 3 1 4 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          17 10 6 5 -1.</_>
+          18 4 3 2 -1.</_>
         <_>
-          20 10 3 5 2.</_></rects>
+          19 4 1 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          17 11 3 2 -1.</_>
+          18 4 3 4 -1.</_>
         <_>
-          18 11 1 2 3.</_></rects>
+          19 4 1 4 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          17 11 3 3 -1.</_>
+          18 5 6 15 -1.</_>
         <_>
-          18 11 1 3 3.</_></rects>
+          21 5 3 15 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          17 11 3 11 -1.</_>
+          18 6 2 3 -1.</_>
         <_>
-          18 11 1 11 3.</_></rects>
+          18 7 2 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          17 11 3 4 -1.</_>
+          18 6 3 3 -1.</_>
         <_>
-          17 13 3 2 2.</_></rects>
+          18 7 3 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          17 12 3 1 -1.</_>
+          18 6 4 3 -1.</_>
         <_>
-          18 12 1 1 3.</_></rects>
+          18 7 4 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          17 13 4 5 -1.</_>
+          18 7 3 1 -1.</_>
         <_>
-          19 13 2 5 2.</_></rects>
+          19 7 1 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          17 15 4 1 -1.</_>
+          18 7 2 2 -1.</_>
         <_>
-          19 15 2 1 2.</_></rects>
+          19 7 1 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          17 15 4 3 -1.</_>
+          18 7 3 2 -1.</_>
         <_>
-          19 15 2 3 2.</_></rects>
+          18 8 3 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          17 16 4 1 -1.</_>
+          18 8 1 3 -1.</_>
         <_>
-          19 16 2 1 2.</_></rects>
+          18 9 1 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          17 18 7 3 -1.</_>
+          18 8 2 2 -1.</_>
+        <_>
+          18 8 1 1 2.</_>
         <_>
-          17 19 7 1 3.</_></rects>
+          19 9 1 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          17 20 3 4 -1.</_>
+          18 8 2 3 -1.</_>
         <_>
-          18 20 1 4 3.</_></rects>
+          18 9 2 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          18 0 3 4 -1.</_>
+          18 8 3 14 -1.</_>
         <_>
-          19 0 1 4 3.</_></rects>
+          18 15 3 7 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          18 0 6 12 -1.</_>
-        <_>
-          18 0 3 6 2.</_>
+          18 9 3 1 -1.</_>
         <_>
-          21 6 3 6 2.</_></rects>
+          19 9 1 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          18 0 6 14 -1.</_>
+          18 9 2 2 -1.</_>
         <_>
-          18 0 3 7 2.</_>
+          18 9 1 1 2.</_>
         <_>
-          21 7 3 7 2.</_></rects>
+          19 10 1 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          18 3 3 3 -1.</_>
+          18 9 3 2 -1.</_>
         <_>
-          19 3 1 3 3.</_></rects>
+          19 9 1 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          18 3 2 9 -1.</_>
+          18 10 2 1 -1.</_>
         <_>
-          18 6 2 3 3.</_></rects>
+          19 10 1 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          18 4 2 2 -1.</_>
+          18 10 2 2 -1.</_>
         <_>
-          18 4 1 1 2.</_>
+          18 10 1 1 2.</_>
         <_>
-          19 5 1 1 2.</_></rects>
+          19 11 1 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          18 4 3 2 -1.</_>
+          18 10 2 2 -1.</_>
         <_>
-          19 4 1 2 3.</_></rects>
+          18 11 2 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          18 4 4 3 -1.</_>
+          18 10 6 4 -1.</_>
         <_>
-          18 5 4 1 3.</_></rects>
+          21 10 3 4 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          18 5 2 2 -1.</_>
+          18 10 6 5 -1.</_>
         <_>
-          18 5 1 1 2.</_>
-        <_>
-          19 6 1 1 2.</_></rects>
+          21 10 3 5 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          18 6 2 3 -1.</_>
+          18 11 3 2 -1.</_>
         <_>
-          18 7 2 1 3.</_></rects>
+          19 11 1 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          18 6 3 3 -1.</_>
+          18 11 3 6 -1.</_>
         <_>
-          18 7 3 1 3.</_></rects>
+          19 11 1 6 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          18 6 5 3 -1.</_>
+          18 11 3 9 -1.</_>
         <_>
-          18 7 5 1 3.</_></rects>
+          19 11 1 9 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          18 7 1 2 -1.</_>
+          18 11 3 8 -1.</_>
         <_>
-          18 8 1 1 2.</_></rects>
+          18 15 3 4 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          18 7 3 1 -1.</_>
+          18 12 3 4 -1.</_>
         <_>
-          19 7 1 1 3.</_></rects>
+          19 12 1 4 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          18 7 2 2 -1.</_>
+          18 12 2 6 -1.</_>
         <_>
-          19 7 1 2 2.</_></rects>
+          18 15 2 3 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          18 7 3 2 -1.</_>
+          18 12 6 2 -1.</_>
         <_>
-          19 7 1 2 3.</_></rects>
+          21 12 3 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          18 7 2 3 -1.</_>
+          18 12 3 12 -1.</_>
         <_>
-          18 8 2 1 3.</_></rects>
+          18 16 3 4 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          18 7 3 3 -1.</_>
+          18 13 3 1 -1.</_>
         <_>
-          18 8 3 1 3.</_></rects>
+          19 13 1 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          18 8 1 3 -1.</_>
+          18 14 6 6 -1.</_>
         <_>
-          18 9 1 1 3.</_></rects>
+          21 14 3 6 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          18 8 2 3 -1.</_>
+          18 20 3 4 -1.</_>
         <_>
-          18 9 2 1 3.</_></rects>
+          19 20 1 4 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          18 8 6 8 -1.</_>
+          18 20 6 3 -1.</_>
         <_>
-          21 8 3 8 2.</_></rects>
+          18 21 6 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          18 9 3 1 -1.</_>
+          19 2 2 4 -1.</_>
         <_>
-          19 9 1 1 3.</_></rects>
+          19 2 1 2 2.</_>
+        <_>
+          20 4 1 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          18 9 2 2 -1.</_>
-        <_>
-          18 9 1 1 2.</_>
+          19 4 1 4 -1.</_>
         <_>
-          19 10 1 1 2.</_></rects>
+          19 6 1 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          18 9 3 2 -1.</_>
+          19 4 1 20 -1.</_>
         <_>
-          19 9 1 2 3.</_></rects>
+          19 14 1 10 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          18 9 4 2 -1.</_>
+          19 4 2 4 -1.</_>
         <_>
-          20 9 2 2 2.</_></rects>
+          19 6 2 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          18 9 3 9 -1.</_>
+          19 4 4 3 -1.</_>
         <_>
-          18 12 3 3 3.</_></rects>
+          19 5 4 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          18 10 2 1 -1.</_>
+          19 5 2 2 -1.</_>
         <_>
-          19 10 1 1 2.</_></rects>
+          19 5 1 1 2.</_>
+        <_>
+          20 6 1 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          18 10 2 2 -1.</_>
-        <_>
-          18 10 1 1 2.</_>
+          19 6 1 3 -1.</_>
         <_>
-          19 11 1 1 2.</_></rects>
+          19 7 1 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          18 10 2 8 -1.</_>
+          19 6 2 3 -1.</_>
         <_>
-          18 14 2 4 2.</_></rects>
+          19 7 2 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          18 10 6 4 -1.</_>
+          19 6 5 3 -1.</_>
         <_>
-          21 10 3 4 2.</_></rects>
+          19 7 5 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          18 11 3 2 -1.</_>
+          19 6 5 9 -1.</_>
         <_>
-          19 11 1 2 3.</_></rects>
+          19 9 5 3 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          18 11 3 12 -1.</_>
+          19 7 1 12 -1.</_>
         <_>
-          19 11 1 12 3.</_></rects>
+          19 11 1 4 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          18 12 3 3 -1.</_>
+          19 7 2 3 -1.</_>
         <_>
-          19 12 1 3 3.</_></rects>
+          19 8 2 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          18 12 6 1 -1.</_>
+          19 8 1 3 -1.</_>
         <_>
-          21 12 3 1 2.</_></rects>
+          19 9 1 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          18 12 3 6 -1.</_>
+          19 8 2 3 -1.</_>
         <_>
-          18 15 3 3 2.</_></rects>
+          20 8 1 3 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          18 15 1 3 -1.</_>
+          19 9 2 1 -1.</_>
         <_>
-          18 16 1 1 3.</_></rects>
+          20 9 1 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          18 15 6 5 -1.</_>
+          19 9 3 2 -1.</_>
         <_>
-          21 15 3 5 2.</_></rects>
+          20 9 1 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          18 16 4 2 -1.</_>
+          19 10 2 2 -1.</_>
         <_>
-          20 16 2 2 2.</_></rects>
+          19 10 1 1 2.</_>
+        <_>
+          20 11 1 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          18 17 3 6 -1.</_>
+          19 10 4 1 -1.</_>
         <_>
-          19 17 1 6 3.</_></rects>
+          21 10 2 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          18 18 3 5 -1.</_>
+          19 11 3 7 -1.</_>
         <_>
-          19 18 1 5 3.</_></rects>
+          20 11 1 7 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          19 0 3 1 -1.</_>
+          19 11 3 10 -1.</_>
         <_>
-          20 0 1 1 3.</_></rects>
+          20 11 1 10 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          19 4 2 4 -1.</_>
+          19 11 3 11 -1.</_>
         <_>
-          19 6 2 2 2.</_></rects>
+          20 11 1 11 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          19 5 2 2 -1.</_>
-        <_>
-          19 5 1 1 2.</_>
+          19 11 3 13 -1.</_>
         <_>
-          20 6 1 1 2.</_></rects>
+          20 11 1 13 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          19 6 1 3 -1.</_>
+          19 14 3 10 -1.</_>
         <_>
-          19 7 1 1 3.</_></rects>
+          20 14 1 10 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          19 6 2 3 -1.</_>
+          19 15 3 2 -1.</_>
         <_>
-          19 7 2 1 3.</_></rects>
+          19 16 3 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          19 9 2 1 -1.</_>
+          19 18 3 3 -1.</_>
         <_>
-          20 9 1 1 2.</_></rects>
+          20 18 1 3 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          19 10 3 14 -1.</_>
+          19 18 3 6 -1.</_>
         <_>
-          20 10 1 14 3.</_></rects>
+          20 18 1 6 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          19 10 4 1 -1.</_>
+          19 20 5 3 -1.</_>
         <_>
-          21 10 2 1 2.</_></rects>
+          19 21 5 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          19 11 3 12 -1.</_>
+          20 4 1 3 -1.</_>
         <_>
-          20 11 1 12 3.</_></rects>
+          20 5 1 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          19 12 3 10 -1.</_>
+          20 5 1 2 -1.</_>
         <_>
-          20 12 1 10 3.</_></rects>
+          20 6 1 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          19 13 3 1 -1.</_>
+          20 5 1 3 -1.</_>
         <_>
-          20 13 1 1 3.</_></rects>
+          20 6 1 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          19 17 3 7 -1.</_>
+          20 5 2 3 -1.</_>
         <_>
-          20 17 1 7 3.</_></rects>
+          20 6 2 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          19 18 3 5 -1.</_>
+          20 5 3 9 -1.</_>
         <_>
-          20 18 1 5 3.</_></rects>
+          20 8 3 3 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          19 18 3 6 -1.</_>
+          20 6 4 9 -1.</_>
         <_>
-          20 18 1 6 3.</_></rects>
+          20 9 4 3 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          19 20 4 3 -1.</_>
+          20 8 4 16 -1.</_>
         <_>
-          19 21 4 1 3.</_></rects>
+          22 8 2 16 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          20 1 4 4 -1.</_>
+          20 9 4 6 -1.</_>
         <_>
-          22 1 2 4 2.</_></rects>
+          20 11 4 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          20 4 2 3 -1.</_>
+          20 10 3 10 -1.</_>
         <_>
-          20 5 2 1 3.</_></rects>
+          21 10 1 10 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          20 5 2 2 -1.</_>
+          20 10 3 9 -1.</_>
+        <_>
+          20 13 3 3 3.</_></rects>
+      <tilted>0</tilted></_>
+    <_>
+      <rects>
         <_>
-          20 5 1 1 2.</_>
+          20 16 3 3 -1.</_>
         <_>
-          21 6 1 1 2.</_></rects>
+          21 16 1 3 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          20 5 2 3 -1.</_>
+          20 17 3 7 -1.</_>
         <_>
-          20 6 2 1 3.</_></rects>
+          21 17 1 7 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          20 11 4 3 -1.</_>
+          20 17 4 6 -1.</_>
         <_>
-          20 12 4 1 3.</_></rects>
+          20 19 4 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          20 12 3 8 -1.</_>
+          20 18 3 3 -1.</_>
         <_>
-          21 12 1 8 3.</_></rects>
+          21 18 1 3 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          20 12 3 11 -1.</_>
+          21 1 2 4 -1.</_>
         <_>
-          21 12 1 11 3.</_></rects>
+          21 3 2 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          20 12 3 12 -1.</_>
+          21 5 1 3 -1.</_>
         <_>
-          21 12 1 12 3.</_></rects>
+          21 6 1 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          20 18 3 1 -1.</_>
+          21 6 3 9 -1.</_>
         <_>
-          21 18 1 1 3.</_></rects>
+          21 9 3 3 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          21 4 1 3 -1.</_>
+          21 10 3 3 -1.</_>
         <_>
-          21 5 1 1 3.</_></rects>
+          21 11 3 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          21 9 3 3 -1.</_>
+          21 13 3 7 -1.</_>
         <_>
-          21 10 3 1 3.</_></rects>
+          22 13 1 7 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          21 9 3 6 -1.</_>
+          21 16 3 3 -1.</_>
         <_>
-          21 11 3 2 3.</_></rects>
+          22 16 1 3 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          21 10 2 4 -1.</_>
+          21 16 3 7 -1.</_>
         <_>
-          21 12 2 2 2.</_></rects>
+          22 16 1 7 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          21 12 3 9 -1.</_>
+          21 17 3 5 -1.</_>
         <_>
-          22 12 1 9 3.</_></rects>
+          22 17 1 5 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          21 13 3 11 -1.</_>
+          21 17 3 6 -1.</_>
         <_>
-          22 13 1 11 3.</_></rects>
+          21 19 3 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          21 15 3 4 -1.</_>
+          21 17 3 6 -1.</_>
         <_>
-          22 15 1 4 3.</_></rects>
+          21 20 3 3 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          21 15 3 9 -1.</_>
+          21 19 3 3 -1.</_>
         <_>
-          22 15 1 9 3.</_></rects>
+          22 19 1 3 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          21 16 3 3 -1.</_>
+          21 19 3 5 -1.</_>
         <_>
-          22 16 1 3 3.</_></rects>
+          22 19 1 5 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          21 16 3 8 -1.</_>
+          22 10 2 3 -1.</_>
         <_>
-          22 16 1 8 3.</_></rects>
+          22 11 2 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          21 20 3 4 -1.</_>
+          22 11 2 3 -1.</_>
         <_>
-          22 20 1 4 3.</_></rects>
+          22 12 2 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          21 22 3 2 -1.</_>
+          23 7 1 3 -1.</_>
         <_>
-          22 22 1 2 3.</_></rects>
+          23 8 1 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          22 10 2 3 -1.</_>
+          23 9 1 3 -1.</_>
         <_>
-          22 11 2 1 3.</_></rects>
+          23 10 1 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          22 12 2 12 -1.</_>
+          23 10 1 3 -1.</_>
         <_>
-          22 16 2 4 3.</_></rects>
+          23 11 1 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          22 20 2 3 -1.</_>
+          23 14 1 9 -1.</_>
         <_>
-          22 21 2 1 3.</_></rects>
+          23 17 1 3 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          23 10 1 3 -1.</_>
+          23 15 1 9 -1.</_>
         <_>
-          23 11 1 1 3.</_></rects>
+          23 18 1 3 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          23 17 1 6 -1.</_>
+          23 18 1 6 -1.</_>
         <_>
-          23 19 1 2 3.</_></rects>
+          23 20 1 2 3.</_></rects>
       <tilted>0</tilted></_></features></cascade>
 </opencv_storage>
diff --git a/data/haarcascades/haarcascade_frontalcatface_extended.xml b/data/haarcascades/haarcascade_frontalcatface_extended.xml
old mode 100644
new mode 100755
index 0777644..ccee995
--- a/data/haarcascades/haarcascade_frontalcatface_extended.xml
+++ b/data/haarcascades/haarcascade_frontalcatface_extended.xml
@@ -22,15 +22,20 @@
 
  KNOWN LIMITATIONS:
 
- Sometimes, the detector mistakenly thinks that a human face is a cat face. In
- situations where either a human or a cat might be encountered, use both a
- human face detector and a cat face detector. Then, if a detected human face
- and a detected cat face intersect, reject the cat face.
-
  An upright subject is assumed. In situations where the cat's face might be
  sideways or upside down (e.g. the cat is rolling over), try various rotations
  of the input image.
 
+ CHANGELOG:
+
+ 2016-08-06: Re-trained with more negative samples and more stages. False
+   positives are much rarer now. If you tailored your code for the cascade's
+   previous version, now you should re-adjust the arguments of
+   CascadeClassifier::detectMultiScale. For example, decrease the value of the
+   minNeighbors argument. You do not need to use a human face detector to
+   cross-check the positives anymore.
+ 2014-04-25: First release (at https://bitbucket.org/Joe_Howse/angora-blue)
+
  //////////////////////////////////////////////////////////////////////////
  | Contributors License Agreement
  | IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
@@ -39,7 +44,7 @@
  |   If you do not agree to this license, do not download, install,
  |   copy or use the software.
  |
- | Copyright (c) 2014, Joseph Howse (Nummist Media Corporation Limited,
+ | Copyright (c) 2014-2016, Joseph Howse (Nummist Media Corporation Limited,
  | Halifax, Nova Scotia, Canada). All rights reserved.
  |
  | Redistribution and use in source and binary forms, with or without
@@ -77,7 +82,7 @@
   <width>24</width>
   <stageParams>
     <boostType>GAB</boostType>
-    <minHitRate>9.9900001287460327e-01</minHitRate>
+    <minHitRate>9.9500000476837158e-01</minHitRate>
     <maxFalseAlarm>5.0000000000000000e-01</maxFalseAlarm>
     <weightTrimRate>9.4999999999999996e-01</weightTrimRate>
     <maxDepth>1</maxDepth>
@@ -86,6786 +91,7159 @@
     <maxCatCount>0</maxCatCount>
     <featSize>1</featSize>
     <mode>ALL</mode></featureParams>
-  <stageNum>15</stageNum>
+  <stageNum>20</stageNum>
   <stages>
     <!-- stage 0 -->
     <_>
-      <maxWeakCount>28</maxWeakCount>
-      <stageThreshold>-2.0972909927368164e+00</stageThreshold>
+      <maxWeakCount>13</maxWeakCount>
+      <stageThreshold>-1.4294912815093994e+00</stageThreshold>
       <weakClassifiers>
         <_>
           <internalNodes>
-            0 -1 388 -1.4772760681807995e-02</internalNodes>
+            0 -1 394 -1.5126220881938934e-02</internalNodes>
           <leafValues>
-            8.4035199880599976e-01 -1.2701500952243805e-01</leafValues></_>
+            7.5887596607208252e-01 -3.4230688214302063e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 736 4.5831585302948952e-03</internalNodes>
+            0 -1 737 3.9337221533060074e-03</internalNodes>
           <leafValues>
-            -2.3791725933551788e-01 6.1978793144226074e-01</leafValues></_>
+            -3.3288389444351196e-01 5.2361363172531128e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 754 -1.5044892206788063e-02</internalNodes>
+            0 -1 757 -1.5044892206788063e-02</internalNodes>
           <leafValues>
-            5.7160794734954834e-01 -2.0493283867835999e-01</leafValues></_>
+            5.5565774440765381e-01 -2.2505992650985718e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 437 -1.5646889805793762e-02</internalNodes>
+            0 -1 450 -1.5777055174112320e-02</internalNodes>
           <leafValues>
-            7.6283878087997437e-01 -1.6358052194118500e-01</leafValues></_>
+            7.2692525386810303e-01 -1.6206762194633484e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 432 3.0781796202063560e-02</internalNodes>
+            0 -1 443 3.0781796202063560e-02</internalNodes>
           <leafValues>
-            -1.8158669769763947e-01 7.5050812959671021e-01</leafValues></_>
+            -1.8173390626907349e-01 7.3483395576477051e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 238 1.8483418971300125e-02</internalNodes>
+            0 -1 220 1.8483418971300125e-02</internalNodes>
           <leafValues>
-            -2.0087972283363342e-01 5.2843624353408813e-01</leafValues></_>
+            -1.8690711259841919e-01 5.0116515159606934e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 680 1.3191045261919498e-02</internalNodes>
+            0 -1 681 1.3474167324602604e-02</internalNodes>
           <leafValues>
-            -1.5244702994823456e-01 5.8166426420211792e-01</leafValues></_>
+            -1.5681208670139313e-01 5.8611637353897095e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 531 5.3334265947341919e-02</internalNodes>
+            0 -1 554 5.3415738046169281e-02</internalNodes>
           <leafValues>
-            -1.6860350966453552e-01 7.1358704566955566e-01</leafValues></_>
+            -1.6418528556823730e-01 6.8128466606140137e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 782 8.3916599396616220e-04</internalNodes>
+            0 -1 741 5.4243900813162327e-03</internalNodes>
           <leafValues>
-            -2.1746076643466949e-01 4.2143425345420837e-01</leafValues></_>
+            -1.8231739103794098e-01 4.6716138720512390e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 333 1.7697989940643311e-02</internalNodes>
+            0 -1 336 1.7689792439341545e-02</internalNodes>
           <leafValues>
-            -1.3514791429042816e-01 6.1385941505432129e-01</leafValues></_>
+            -1.3713267445564270e-01 6.0434049367904663e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 290 -2.8310909867286682e-02</internalNodes>
+            0 -1 187 2.2149257711134851e-04</internalNodes>
           <leafValues>
-            5.3606474399566650e-01 -1.5554395318031311e-01</leafValues></_>
+            -2.7738124132156372e-01 2.8165665268898010e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 147 4.1034919559024274e-04</internalNodes>
+            0 -1 288 -2.8517641127109528e-02</internalNodes>
           <leafValues>
-            -2.8903219103813171e-01 3.1018218398094177e-01</leafValues></_>
+            5.5257320404052734e-01 -1.2970162928104401e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 537 3.9831817150115967e-02</internalNodes>
+            0 -1 369 4.3854981660842896e-02</internalNodes>
           <leafValues>
-            -1.8419378995895386e-01 4.3500679731369019e-01</leafValues></_>
+            -1.9231440126895905e-01 4.2093500494956970e-01</leafValues></_></weakClassifiers></_>
+    <!-- stage 1 -->
+    <_>
+      <maxWeakCount>27</maxWeakCount>
+      <stageThreshold>-1.5509251356124878e+00</stageThreshold>
+      <weakClassifiers>
         <_>
           <internalNodes>
-            0 -1 558 -5.2749719470739365e-03</internalNodes>
+            0 -1 337 2.4014184251427650e-02</internalNodes>
           <leafValues>
-            -8.7773287296295166e-01 1.1703799664974213e-01</leafValues></_>
+            -2.1038578450679779e-01 7.3892170190811157e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 811 -3.6777660250663757e-02</internalNodes>
+            0 -1 475 -5.5319909006357193e-03</internalNodes>
           <leafValues>
-            4.1285938024520874e-01 -2.1606418490409851e-01</leafValues></_>
+            4.4344031810760498e-01 -2.8907662630081177e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 324 9.4376102089881897e-02</internalNodes>
+            0 -1 4 2.7481060475111008e-02</internalNodes>
           <leafValues>
-            -1.0109311342239380e-01 6.0879749059677124e-01</leafValues></_>
+            -1.9128543138504028e-01 5.1661676168441772e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 564 -1.6132533550262451e-02</internalNodes>
+            0 -1 457 -1.1628001928329468e-02</internalNodes>
           <leafValues>
-            5.1245921850204468e-01 -1.5503944456577301e-01</leafValues></_>
+            5.1978123188018799e-01 -1.7051684856414795e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 507 -6.9251265376806259e-03</internalNodes>
+            0 -1 393 1.5159824397414923e-03</internalNodes>
           <leafValues>
-            4.2284211516380310e-01 -1.5949958562850952e-01</leafValues></_>
+            -2.9784303903579712e-01 3.9050224423408508e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 882 -8.4776207804679871e-03</internalNodes>
+            0 -1 901 1.3662670738995075e-02</internalNodes>
           <leafValues>
-            4.0007081627845764e-01 -1.6089719533920288e-01</leafValues></_>
+            -1.4316783845424652e-01 4.4111710786819458e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 110 -9.0452972799539566e-03</internalNodes>
+            0 -1 780 -3.6911026109009981e-03</internalNodes>
           <leafValues>
-            -7.6785671710968018e-01 9.3979701399803162e-02</leafValues></_>
+            3.2185173034667969e-01 -2.3853960633277893e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 246 3.0019454658031464e-02</internalNodes>
+            0 -1 769 3.3176485449075699e-02</internalNodes>
           <leafValues>
-            -1.3505084812641144e-01 4.7249373793601990e-01</leafValues></_>
+            -7.4603199958801270e-02 7.5860917568206787e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 804 3.6142929457128048e-03</internalNodes>
+            0 -1 317 -5.7046953588724136e-03</internalNodes>
           <leafValues>
-            8.1217512488365173e-02 -7.7168470621109009e-01</leafValues></_>
+            -7.5004047155380249e-01 1.0240622609853745e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 806 -4.7642881982028484e-03</internalNodes>
+            0 -1 73 7.9660946503281593e-03</internalNodes>
           <leafValues>
-            -7.8209573030471802e-01 6.2777772545814514e-02</leafValues></_>
+            9.8882928490638733e-02 -7.3491615056991577e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 816 3.0351843684911728e-02</internalNodes>
+            0 -1 739 3.0965393409132957e-02</internalNodes>
           <leafValues>
-            -1.1295587569475174e-01 5.8056473731994629e-01</leafValues></_>
+            -1.6046196222305298e-01 4.5570060610771179e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 146 -5.9288680553436279e-02</internalNodes>
+            0 -1 612 -4.0078125894069672e-03</internalNodes>
           <leafValues>
-            5.5029523372650146e-01 -1.1994160711765289e-01</leafValues></_>
+            -7.1539020538330078e-01 6.9276176393032074e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 11 2.2238820791244507e-02</internalNodes>
+            0 -1 647 -8.2283765077590942e-03</internalNodes>
           <leafValues>
-            -1.4121483266353607e-01 4.5770901441574097e-01</leafValues></_>
+            3.2576236128807068e-01 -1.8509653210639954e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 294 -4.1477128863334656e-02</internalNodes>
+            0 -1 170 3.4253271296620369e-03</internalNodes>
           <leafValues>
-            5.7035386562347412e-01 -1.0164763778448105e-01</leafValues></_>
+            1.0964145511388779e-01 -5.8205413818359375e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 710 -1.1866136919707060e-03</internalNodes>
+            0 -1 434 9.0980646200478077e-04</internalNodes>
           <leafValues>
-            3.4064662456512451e-01 -1.6186751425266266e-01</leafValues></_></weakClassifiers></_>
-    <!-- stage 1 -->
-    <_>
-      <maxWeakCount>30</maxWeakCount>
-      <stageThreshold>-1.5367478132247925e+00</stageThreshold>
-      <weakClassifiers>
+            -2.0425215363502502e-01 2.7488732337951660e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 654 8.4006171673536301e-03</internalNodes>
+            0 -1 427 5.9772443026304245e-02</internalNodes>
           <leafValues>
-            -1.0249307751655579e-01 7.6660197973251343e-01</leafValues></_>
+            -1.3786207139492035e-01 4.0762668848037720e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 443 -1.0703811421990395e-02</internalNodes>
+            0 -1 209 -4.1712004691362381e-02</internalNodes>
           <leafValues>
-            6.9929075241088867e-01 -1.6515852510929108e-01</leafValues></_>
+            4.9409377574920654e-01 -1.1713714897632599e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 1 6.3192001543939114e-03</internalNodes>
+            0 -1 248 -3.0311278998851776e-02</internalNodes>
           <leafValues>
-            -2.2415910661220551e-01 4.3903940916061401e-01</leafValues></_>
+            5.1191121339797974e-01 -1.0507214814424515e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 651 2.0642649382352829e-02</internalNodes>
+            0 -1 339 -6.5785087645053864e-03</internalNodes>
           <leafValues>
-            -1.8032769858837128e-01 5.8923733234405518e-01</leafValues></_>
+            -7.6472043991088867e-01 8.0923363566398621e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 378 4.0111690759658813e-03</internalNodes>
+            0 -1 37 1.1685060337185860e-02</internalNodes>
           <leafValues>
-            -2.4117745459079742e-01 5.4825514554977417e-01</leafValues></_>
+            5.0379037857055664e-02 -7.9744982719421387e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 173 2.0640484988689423e-02</internalNodes>
+            0 -1 423 6.5714016556739807e-02</internalNodes>
           <leafValues>
-            -2.4204613268375397e-01 4.0820708870887756e-01</leafValues></_>
+            -1.1398456245660782e-01 4.9489131569862366e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 116 -9.2923976480960846e-03</internalNodes>
+            0 -1 755 9.7422497346997261e-03</internalNodes>
           <leafValues>
-            3.6315548419952393e-01 -2.0153710246086121e-01</leafValues></_>
+            -1.4347794651985168e-01 3.6561754345893860e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 851 3.5129714757204056e-02</internalNodes>
+            0 -1 870 4.9857441335916519e-03</internalNodes>
           <leafValues>
-            -1.3475686311721802e-01 6.5953320264816284e-01</leafValues></_>
+            7.9834438860416412e-02 -7.2391557693481445e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 333 2.0278891548514366e-02</internalNodes>
+            0 -1 735 -1.1547822505235672e-03</internalNodes>
           <leafValues>
-            -1.0143157839775085e-01 5.9142571687698364e-01</leafValues></_>
+            4.1867440938949585e-01 -1.2869183719158173e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 737 6.4985908102244139e-04</internalNodes>
+            0 -1 519 -4.4658007100224495e-03</internalNodes>
           <leafValues>
-            -1.9716840982437134e-01 3.4134888648986816e-01</leafValues></_>
+            -6.7933702468872070e-01 8.2867160439491272e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 287 -6.6223340108990669e-03</internalNodes>
+            0 -1 862 3.6325352266430855e-03</internalNodes>
           <leafValues>
-            -6.9885939359664917e-01 9.7095526754856110e-02</leafValues></_>
+            6.6807270050048828e-02 -6.0182958841323853e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 82 7.4231177568435669e-03</internalNodes>
+            0 -1 127 7.4123376980423927e-03</internalNodes>
           <leafValues>
-            9.8552420735359192e-02 -6.5358603000640869e-01</leafValues></_>
+            -1.5108695626258850e-01 3.2046884298324585e-01</leafValues></_></weakClassifiers></_>
+    <!-- stage 2 -->
+    <_>
+      <maxWeakCount>26</maxWeakCount>
+      <stageThreshold>-1.3890913724899292e+00</stageThreshold>
+      <weakClassifiers>
         <_>
           <internalNodes>
-            0 -1 692 -3.0081106349825859e-02</internalNodes>
+            0 -1 619 1.7836617305874825e-02</internalNodes>
           <leafValues>
-            4.5352721214294434e-01 -1.4968612790107727e-01</leafValues></_>
+            -2.1508488059043884e-01 6.6796410083770752e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 62 -6.0633812099695206e-02</internalNodes>
+            0 -1 457 -8.5781915113329887e-03</internalNodes>
           <leafValues>
-            6.5072047710418701e-01 -9.9382333457469940e-02</leafValues></_>
+            5.0962758064270020e-01 -2.2129471600055695e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 814 -5.1941806450486183e-03</internalNodes>
+            0 -1 165 3.1586211174726486e-02</internalNodes>
           <leafValues>
-            3.9397239685058594e-01 -1.6142791509628296e-01</leafValues></_>
+            -2.1485456824302673e-01 4.2591696977615356e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 261 6.0986238531768322e-03</internalNodes>
+            0 -1 518 2.5690056383609772e-02</internalNodes>
           <leafValues>
-            8.6411900818347931e-02 -7.3878693580627441e-01</leafValues></_>
+            -1.5910078585147858e-01 6.7842948436737061e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 108 -8.2402750849723816e-03</internalNodes>
+            0 -1 768 -2.2857591509819031e-02</internalNodes>
           <leafValues>
-            -7.4236625432968140e-01 6.7853815853595734e-02</leafValues></_>
+            5.7221925258636475e-01 -1.3710150122642517e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 908 -3.0396101996302605e-02</internalNodes>
+            0 -1 741 4.7176675871014595e-03</internalNodes>
           <leafValues>
-            4.9337482452392578e-01 -1.3200622797012329e-01</leafValues></_>
+            -2.3617559671401978e-01 3.9870622754096985e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 188 5.1566954702138901e-02</internalNodes>
+            0 -1 615 -2.3281413596123457e-03</internalNodes>
           <leafValues>
-            -1.3631668686866760e-01 4.2621469497680664e-01</leafValues></_>
+            -7.0095318555831909e-01 1.3746888935565948e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 150 -9.3598978128284216e-04</internalNodes>
+            0 -1 139 1.0266102617606521e-03</internalNodes>
           <leafValues>
-            3.2463693618774414e-01 -2.0737074315547943e-01</leafValues></_>
+            -2.6873087882995605e-01 2.6495781540870667e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 905 7.0394594222307205e-03</internalNodes>
+            0 -1 2 -7.6808528974652290e-03</internalNodes>
           <leafValues>
-            8.9326366782188416e-02 -6.1088448762893677e-01</leafValues></_>
+            3.6925876140594482e-01 -2.1339643001556396e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 396 -6.5201576799154282e-03</internalNodes>
+            0 -1 454 6.4357556402683258e-02</internalNodes>
           <leafValues>
-            3.7555626034736633e-01 -1.5273806452751160e-01</leafValues></_>
+            -1.1779088526964188e-01 5.5030888319015503e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 103 3.9127394556999207e-03</internalNodes>
+            0 -1 296 8.9486092329025269e-02</internalNodes>
           <leafValues>
-            8.3254240453243256e-02 -7.3406547307968140e-01</leafValues></_>
+            -1.4395782351493835e-01 5.3468054533004761e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 39 9.5308097079396248e-03</internalNodes>
+            0 -1 253 -5.6334878318011761e-03</internalNodes>
           <leafValues>
-            -1.7045913636684418e-01 3.2230368256568909e-01</leafValues></_>
+            -6.5704786777496338e-01 1.3971389830112457e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 796 1.5843525528907776e-02</internalNodes>
+            0 -1 834 -8.0200601369142532e-03</internalNodes>
           <leafValues>
-            -1.4033445715904236e-01 3.9502236247062683e-01</leafValues></_>
+            3.6956611275672913e-01 -1.8284171819686890e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 555 5.9641832485795021e-03</internalNodes>
+            0 -1 732 8.3984360098838806e-03</internalNodes>
           <leafValues>
-            6.4340040087699890e-02 -8.5145986080169678e-01</leafValues></_>
+            -1.3507588207721710e-01 4.4903004169464111e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 601 -4.8106643371284008e-03</internalNodes>
+            0 -1 246 -5.7764705270528793e-03</internalNodes>
           <leafValues>
-            -6.9040679931640625e-01 6.5658122301101685e-02</leafValues></_>
+            -6.5459579229354858e-01 1.1050829291343689e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 731 -9.3304895563051105e-04</internalNodes>
+            0 -1 630 3.9896301925182343e-02</internalNodes>
           <leafValues>
-            4.1242164373397827e-01 -1.4879603683948517e-01</leafValues></_>
+            -1.5822732448577881e-01 3.6069712042808533e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 779 4.1272714734077454e-03</internalNodes>
+            0 -1 11 -6.8376958370208740e-02</internalNodes>
           <leafValues>
-            -1.2624038755893707e-01 4.6513134241104126e-01</leafValues></_>
+            6.2642019987106323e-01 -8.3647280931472778e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 184 2.2929732222110033e-03</internalNodes>
+            0 -1 696 -2.7075063437223434e-02</internalNodes>
           <leafValues>
-            1.0915581136941910e-01 -5.1519250869750977e-01</leafValues></_></weakClassifiers></_>
-    <!-- stage 2 -->
-    <_>
-      <maxWeakCount>44</maxWeakCount>
-      <stageThreshold>-1.6336240768432617e+00</stageThreshold>
-      <weakClassifiers>
+            4.0549215674400330e-01 -1.4247153699398041e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 334 2.5117650628089905e-02</internalNodes>
+            0 -1 933 6.8107023835182190e-03</internalNodes>
           <leafValues>
-            3.5861257463693619e-02 8.1681501865386963e-01</leafValues></_>
+            7.7754773199558258e-02 -6.4665120840072632e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 459 -6.6137146204710007e-03</internalNodes>
+            0 -1 131 3.6659452598541975e-03</internalNodes>
           <leafValues>
-            4.6177890896797180e-01 -2.3009553551673889e-01</leafValues></_>
+            7.9356946051120758e-02 -5.4679936170578003e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 394 -3.1423813197761774e-03</internalNodes>
+            0 -1 182 2.3308303207159042e-02</internalNodes>
           <leafValues>
-            4.0471413731575012e-01 -2.0868653059005737e-01</leafValues></_>
+            -1.4383231103420258e-01 3.4179633855819702e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 0 -3.7308693863451481e-03</internalNodes>
+            0 -1 389 -3.2547116279602051e-02</internalNodes>
           <leafValues>
-            3.2831424474716187e-01 -2.6703229546546936e-01</leafValues></_>
+            3.6395668983459473e-01 -1.2551946938037872e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 178 7.8482955694198608e-02</internalNodes>
+            0 -1 471 1.6501296311616898e-02</internalNodes>
           <leafValues>
-            -1.5199472010135651e-01 4.6242395043373108e-01</leafValues></_>
+            -1.0674661397933960e-01 4.2714300751686096e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 772 -2.6338286697864532e-03</internalNodes>
+            0 -1 616 -2.9296698048710823e-03</internalNodes>
           <leafValues>
-            3.1739279627799988e-01 -2.3944588005542755e-01</leafValues></_>
+            -5.7476091384887695e-01 8.5429534316062927e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 75 9.2347152531147003e-02</internalNodes>
+            0 -1 828 1.3306898763403296e-03</internalNodes>
           <leafValues>
-            -1.5557752549648285e-01 6.0793381929397583e-01</leafValues></_>
+            -1.2303277105093002e-01 3.7224721908569336e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 315 -1.6786376014351845e-02</internalNodes>
+            0 -1 18 9.8933260887861252e-03</internalNodes>
           <leafValues>
-            5.2824962139129639e-01 -1.1138658970594406e-01</leafValues></_>
+            6.7675270140171051e-02 -6.7935848236083984e-01</leafValues></_></weakClassifiers></_>
+    <!-- stage 3 -->
+    <_>
+      <maxWeakCount>31</maxWeakCount>
+      <stageThreshold>-1.4026626348495483e+00</stageThreshold>
+      <weakClassifiers>
         <_>
           <internalNodes>
-            0 -1 755 -3.8150474429130554e-02</internalNodes>
+            0 -1 876 -1.4927964657545090e-02</internalNodes>
           <leafValues>
-            4.3382674455642700e-01 -1.4826944470405579e-01</leafValues></_>
+            6.3834953308105469e-01 -1.8698258697986603e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 318 4.3135927990078926e-03</internalNodes>
+            0 -1 467 -1.1759694665670395e-02</internalNodes>
           <leafValues>
-            1.1878431588411331e-01 -5.8886390924453735e-01</leafValues></_>
+            5.0763273239135742e-01 -2.0944127440452576e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 412 7.1479372680187225e-02</internalNodes>
+            0 -1 775 1.1289508081972599e-02</internalNodes>
           <leafValues>
-            -1.0972832888364792e-01 5.7183718681335449e-01</leafValues></_>
+            -1.4533838629722595e-01 5.3039866685867310e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 104 7.3613431304693222e-03</internalNodes>
+            0 -1 335 1.3691024854779243e-02</internalNodes>
           <leafValues>
-            9.7729764878749847e-02 -6.5627050399780273e-01</leafValues></_>
+            -1.3143934309482574e-01 5.9853446483612061e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 414 5.1306895911693573e-02</internalNodes>
+            0 -1 399 -8.6051290854811668e-03</internalNodes>
           <leafValues>
-            -1.6079875826835632e-01 4.0451571345329285e-01</leafValues></_>
+            3.1604155898094177e-01 -2.2497664391994476e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 367 -4.7303801402449608e-03</internalNodes>
+            0 -1 898 1.1611104011535645e-02</internalNodes>
           <leafValues>
-            -6.5826851129531860e-01 8.7291486561298370e-02</leafValues></_>
+            -1.7180299758911133e-01 3.6340636014938354e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 712 -1.8283914541825652e-03</internalNodes>
+            0 -1 919 5.4911419283598661e-04</internalNodes>
           <leafValues>
-            3.7762144207954407e-01 -1.4564067125320435e-01</leafValues></_>
+            -2.0625770092010498e-01 3.0243906378746033e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 131 5.1737688481807709e-03</internalNodes>
+            0 -1 448 -1.1997690424323082e-02</internalNodes>
           <leafValues>
-            8.7748050689697266e-02 -6.2685465812683105e-01</leafValues></_>
+            6.7541980743408203e-01 -1.0784135758876801e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 647 -3.2173446379601955e-03</internalNodes>
+            0 -1 610 -2.0809918642044067e-03</internalNodes>
           <leafValues>
-            -7.3641878366470337e-01 5.7915702462196350e-02</leafValues></_>
+            -5.7404327392578125e-01 1.1769672483205795e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 819 -5.4384516552090645e-03</internalNodes>
+            0 -1 277 6.8656861782073975e-02</internalNodes>
           <leafValues>
-            4.2479231953620911e-01 -1.2763169407844543e-01</leafValues></_>
+            -1.4633083343505859e-01 4.1269731521606445e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 159 2.6621888391673565e-03</internalNodes>
+            0 -1 215 -4.5645810663700104e-02</internalNodes>
           <leafValues>
-            -2.1836103498935699e-01 3.1271252036094666e-01</leafValues></_>
+            5.4341620206832886e-01 -1.1726979166269302e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 125 1.2338031083345413e-02</internalNodes>
+            0 -1 890 -1.8052812665700912e-02</internalNodes>
           <leafValues>
-            7.9128213226795197e-02 -8.1891500949859619e-01</leafValues></_>
+            3.6646232008934021e-01 -1.3256482779979706e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 639 -1.0976660996675491e-02</internalNodes>
+            0 -1 897 9.2329997569322586e-03</internalNodes>
           <leafValues>
-            2.9887822270393372e-01 -1.8205311894416809e-01</leafValues></_>
+            9.1808989644050598e-02 -6.4987671375274658e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 646 1.4158659614622593e-03</internalNodes>
+            0 -1 142 -2.9587259050458670e-03</internalNodes>
           <leafValues>
-            8.9180864393711090e-02 -5.9163159132003784e-01</leafValues></_>
+            2.4805040657520294e-01 -2.0830279588699341e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 141 -2.0067330449819565e-02</internalNodes>
+            0 -1 151 -7.1467030793428421e-03</internalNodes>
           <leafValues>
-            2.6213398575782776e-01 -1.7981344461441040e-01</leafValues></_>
+            -6.6564339399337769e-01 8.8065519928932190e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 95 3.1120348721742630e-03</internalNodes>
+            0 -1 756 -5.7738199830055237e-03</internalNodes>
           <leafValues>
-            8.4207154810428619e-02 -5.7088595628738403e-01</leafValues></_>
+            2.4252247810363770e-01 -2.1394193172454834e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 121 -9.9351592361927032e-03</internalNodes>
+            0 -1 207 6.4636822789907455e-03</internalNodes>
           <leafValues>
-            -7.2243571281433105e-01 5.1867216825485229e-02</leafValues></_>
+            8.4821723401546478e-02 -6.4125812053680420e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 198 1.3314767275005579e-03</internalNodes>
+            0 -1 527 -2.8782974928617477e-02</internalNodes>
           <leafValues>
-            -1.7091234028339386e-01 2.5805294513702393e-01</leafValues></_>
+            3.5874211788177490e-01 -1.4370997250080109e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 211 3.5102412104606628e-02</internalNodes>
+            0 -1 715 -1.8174832221120596e-03</internalNodes>
           <leafValues>
-            -1.1150742322206497e-01 4.2247176170349121e-01</leafValues></_>
+            3.7480926513671875e-01 -1.2761794030666351e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 780 2.4332102388143539e-02</internalNodes>
+            0 -1 590 -1.9234847277402878e-03</internalNodes>
           <leafValues>
-            -1.2760649621486664e-01 3.5613566637039185e-01</leafValues></_>
+            -5.6678783893585205e-01 9.0299606323242188e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 913 3.4916624426841736e-03</internalNodes>
+            0 -1 588 2.8048637323081493e-03</internalNodes>
           <leafValues>
-            7.4707798659801483e-02 -6.2106835842132568e-01</leafValues></_>
+            8.5870750248432159e-02 -5.8541411161422729e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 554 3.1960286200046539e-02</internalNodes>
+            0 -1 178 7.0693701505661011e-02</internalNodes>
           <leafValues>
-            -8.5123799741268158e-02 5.5780071020126343e-01</leafValues></_>
+            -1.2318307906389236e-01 3.9827430248260498e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 210 2.5646466761827469e-02</internalNodes>
+            0 -1 554 6.2659628689289093e-02</internalNodes>
           <leafValues>
-            9.6616283059120178e-02 -4.8778736591339111e-01</leafValues></_>
+            -9.1229990124702454e-02 5.0639665126800537e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 65 4.8584854230284691e-03</internalNodes>
+            0 -1 321 -3.7420655135065317e-03</internalNodes>
           <leafValues>
-            5.4295353591442108e-02 -6.2732213735580444e-01</leafValues></_>
+            3.5059738159179688e-01 -1.2444343417882919e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 525 -4.3544219806790352e-03</internalNodes>
+            0 -1 273 6.8388320505619049e-03</internalNodes>
           <leafValues>
-            -5.7990497350692749e-01 5.8335512876510620e-02</leafValues></_>
+            -1.0419095307588577e-01 4.5085826516151428e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 818 1.5392700443044305e-03</internalNodes>
+            0 -1 76 7.1193519979715347e-03</internalNodes>
           <leafValues>
-            -1.0273179411888123e-01 4.0286800265312195e-01</leafValues></_>
+            9.1205865144729614e-02 -5.2279585599899292e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 625 -3.5907807759940624e-03</internalNodes>
+            0 -1 791 -9.8787562455981970e-04</internalNodes>
           <leafValues>
-            -5.7972615957260132e-01 7.4733175337314606e-02</leafValues></_>
+            2.8105542063713074e-01 -1.5169830620288849e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 742 -2.6264857500791550e-02</internalNodes>
+            0 -1 639 1.8099821172654629e-03</internalNodes>
           <leafValues>
-            3.9446443319320679e-01 -1.1581628769636154e-01</leafValues></_>
+            6.5428622066974640e-02 -6.9196063280105591e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 458 1.6059044748544693e-02</internalNodes>
+            0 -1 726 -6.0212425887584686e-03</internalNodes>
           <leafValues>
-            -1.0167770087718964e-01 3.6267307400703430e-01</leafValues></_>
+            -6.2636482715606689e-01 5.1543414592742920e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 233 -4.1905373334884644e-02</internalNodes>
+            0 -1 818 5.1644006744027138e-03</internalNodes>
           <leafValues>
-            4.7364938259124756e-01 -8.8032789528369904e-02</leafValues></_>
+            6.3040286302566528e-02 -6.3455927371978760e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 42 2.0880695432424545e-02</internalNodes>
+            0 -1 205 9.4506526365876198e-03</internalNodes>
           <leafValues>
-            -1.2106557935476303e-01 3.8552695512771606e-01</leafValues></_>
+            -1.3443979620933533e-01 3.1506177783012390e-01</leafValues></_></weakClassifiers></_>
+    <!-- stage 4 -->
+    <_>
+      <maxWeakCount>38</maxWeakCount>
+      <stageThreshold>-1.4621645212173462e+00</stageThreshold>
+      <weakClassifiers>
         <_>
           <internalNodes>
-            0 -1 959 3.2229241915047169e-03</internalNodes>
+            0 -1 383 -1.5925668179988861e-02</internalNodes>
           <leafValues>
-            6.9974288344383240e-02 -6.0391223430633545e-01</leafValues></_>
+            6.2127149105072021e-01 -1.8520653247833252e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 830 7.0135584101080894e-03</internalNodes>
+            0 -1 648 1.0260052047669888e-02</internalNodes>
           <leafValues>
-            -1.0977950692176819e-01 3.7435680627822876e-01</leafValues></_>
+            -2.4736632406711578e-01 4.2336893081665039e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 798 -6.5330024808645248e-03</internalNodes>
+            0 -1 3 5.7025998830795288e-03</internalNodes>
           <leafValues>
-            -6.9873285293579102e-01 5.8301825076341629e-02</leafValues></_>
+            -2.3670144379138947e-01 3.3228391408920288e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 766 -6.3728205859661102e-03</internalNodes>
+            0 -1 264 9.3164276331663132e-03</internalNodes>
           <leafValues>
-            2.4119727313518524e-01 -1.5554191172122955e-01</leafValues></_>
+            -1.7946784198284149e-01 4.6311038732528687e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 598 -3.9798039942979813e-03</internalNodes>
+            0 -1 830 -5.0438079051673412e-03</internalNodes>
           <leafValues>
-            3.2675772905349731e-01 -1.1990765482187271e-01</leafValues></_></weakClassifiers></_>
-    <!-- stage 3 -->
-    <_>
-      <maxWeakCount>48</maxWeakCount>
-      <stageThreshold>-1.6315091848373413e+00</stageThreshold>
-      <weakClassifiers>
+            4.4613519310951233e-01 -1.6072992980480194e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 398 -1.6997709870338440e-02</internalNodes>
+            0 -1 793 2.8381291776895523e-03</internalNodes>
           <leafValues>
-            7.5603079795837402e-01 1.9442643970251083e-03</leafValues></_>
+            -1.8486896157264709e-01 3.5892590880393982e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 858 -1.5086915343999863e-02</internalNodes>
+            0 -1 455 6.7377656698226929e-02</internalNodes>
           <leafValues>
-            6.3829183578491211e-01 -1.4418891072273254e-01</leafValues></_>
+            -1.7760114371776581e-01 3.9539518952369690e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 734 7.5988154858350754e-03</internalNodes>
+            0 -1 44 -8.7916189804673195e-03</internalNodes>
           <leafValues>
-            -1.6574914753437042e-01 4.6998679637908936e-01</leafValues></_>
+            -5.9182339906692505e-01 1.1145308613777161e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 440 -7.5363442301750183e-03</internalNodes>
+            0 -1 874 1.3353329151868820e-02</internalNodes>
           <leafValues>
-            4.4424122571945190e-01 -1.8298716843128204e-01</leafValues></_>
+            -1.1993711441755295e-01 4.8862439393997192e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 441 1.0129272937774658e-02</internalNodes>
+            0 -1 324 -1.0008489713072777e-02</internalNodes>
           <leafValues>
-            -2.0301033556461334e-01 5.5256271362304688e-01</leafValues></_>
+            4.1768664121627808e-01 -1.2453128397464752e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 732 3.0099015682935715e-02</internalNodes>
+            0 -1 795 -1.4410717412829399e-03</internalNodes>
           <leafValues>
-            -9.0159557759761810e-02 5.2430152893066406e-01</leafValues></_>
+            3.4100320935249329e-01 -1.6849595308303833e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 880 1.0154332034289837e-02</internalNodes>
+            0 -1 123 1.1647527664899826e-01</internalNodes>
           <leafValues>
-            -2.1865487098693848e-01 3.7318554520606995e-01</leafValues></_>
+            -9.7596585750579834e-02 4.2289251089096069e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 753 -5.7211541570723057e-03</internalNodes>
+            0 -1 301 -9.8112244158983231e-03</internalNodes>
           <leafValues>
-            2.9541808366775513e-01 -2.3727707564830780e-01</leafValues></_>
+            2.6155915856361389e-01 -2.0234876871109009e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 609 -2.3081460967659950e-03</internalNodes>
+            0 -1 425 6.3042029738426208e-02</internalNodes>
           <leafValues>
-            -6.5867960453033447e-01 8.6644835770130157e-02</leafValues></_>
+            -1.2662252783775330e-01 3.6811619997024536e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 892 3.4120366908609867e-03</internalNodes>
+            0 -1 553 -1.7675247043371201e-02</internalNodes>
           <leafValues>
-            7.3793835937976837e-02 -6.1988431215286255e-01</leafValues></_>
+            4.1690909862518311e-01 -1.1987055838108063e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 423 1.1280932230874896e-03</internalNodes>
+            0 -1 105 4.0485346689820290e-03</internalNodes>
           <leafValues>
-            -1.7844060063362122e-01 2.9092252254486084e-01</leafValues></_>
+            7.0249855518341064e-02 -7.3556905984878540e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 252 3.4356258809566498e-02</internalNodes>
+            0 -1 675 8.2748252898454666e-03</internalNodes>
           <leafValues>
-            -1.4515927433967590e-01 3.3726382255554199e-01</leafValues></_>
+            -1.6168670356273651e-01 2.8835350275039673e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 583 4.2802840471267700e-02</internalNodes>
+            0 -1 313 -5.0843162462115288e-03</internalNodes>
           <leafValues>
-            -1.0719767957925797e-01 4.7673487663269043e-01</leafValues></_>
+            -5.8562570810317993e-01 8.9675068855285645e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 395 -2.2776997648179531e-03</internalNodes>
+            0 -1 249 6.0826279222965240e-03</internalNodes>
           <leafValues>
-            3.6087805032730103e-01 -1.2924250960350037e-01</leafValues></_>
+            4.7766357660293579e-02 -6.8612217903137207e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 390 6.0573252849280834e-03</internalNodes>
+            0 -1 48 8.5826087743043900e-03</internalNodes>
           <leafValues>
-            6.6139653325080872e-02 -7.4114394187927246e-01</leafValues></_>
+            -1.6963686048984528e-01 2.6875671744346619e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 271 -1.0843809694051743e-02</internalNodes>
+            0 -1 38 2.4908576160669327e-02</internalNodes>
           <leafValues>
-            4.1086801886558533e-01 -1.3518220186233521e-01</leafValues></_>
+            8.5034154355525970e-02 -5.7059210538864136e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 265 2.5435941293835640e-02</internalNodes>
+            0 -1 879 2.0448346622288227e-03</internalNodes>
           <leafValues>
-            -1.2997664511203766e-01 3.8705968856811523e-01</leafValues></_>
+            -1.8642950057983398e-01 2.3178242146968842e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 649 1.6918467590585351e-03</internalNodes>
+            0 -1 16 2.4130716919898987e-02</internalNodes>
           <leafValues>
-            9.5908589661121368e-02 -6.5462106466293335e-01</leafValues></_>
+            -1.2823060154914856e-01 3.4394741058349609e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 690 2.5078756734728813e-03</internalNodes>
+            0 -1 154 -4.7494415193796158e-03</internalNodes>
           <leafValues>
-            5.6727513670921326e-02 -6.1011266708374023e-01</leafValues></_>
+            -7.1827727556228638e-01 6.8053275346755981e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 77 -1.0462226346135139e-02</internalNodes>
+            0 -1 199 -1.7751917243003845e-02</internalNodes>
           <leafValues>
-            3.6109340190887451e-01 -1.2214753031730652e-01</leafValues></_>
+            -5.5972510576248169e-01 5.2141726016998291e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 157 -1.6778277233242989e-02</internalNodes>
+            0 -1 339 5.5826390162110329e-03</internalNodes>
           <leafValues>
-            -5.3534448146820068e-01 8.2928635179996490e-02</leafValues></_>
+            4.8266090452671051e-02 -5.9813541173934937e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 831 -1.5040259808301926e-02</internalNodes>
+            0 -1 387 1.4416726771742105e-03</internalNodes>
           <leafValues>
-            2.8428143262863159e-01 -1.4685547351837158e-01</leafValues></_>
+            -9.2707693576812744e-02 4.1495534777641296e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 907 -6.6617773845791817e-03</internalNodes>
+            0 -1 192 -2.1779362577944994e-03</internalNodes>
           <leafValues>
-            -5.6624877452850342e-01 7.8970976173877716e-02</leafValues></_>
+            2.7112621068954468e-01 -1.5071788430213928e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 695 8.1638405099511147e-03</internalNodes>
+            0 -1 607 3.0656920280307531e-03</internalNodes>
           <leafValues>
-            -1.6379712522029877e-01 2.6822853088378906e-01</leafValues></_>
+            6.0340058058500290e-02 -6.5465551614761353e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 52 1.9468305632472038e-02</internalNodes>
+            0 -1 469 1.9947460293769836e-01</internalNodes>
           <leafValues>
-            -1.2091565877199173e-01 3.3373209834098816e-01</leafValues></_>
+            -9.5098674297332764e-02 3.9016976952552795e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 164 -6.4643016085028648e-03</internalNodes>
+            0 -1 857 -2.0255323499441147e-02</internalNodes>
           <leafValues>
-            -6.3222587108612061e-01 6.6180422902107239e-02</leafValues></_>
+            4.3044877052307129e-01 -8.8302992284297943e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 284 3.5924967378377914e-02</internalNodes>
+            0 -1 446 5.4685659706592560e-03</internalNodes>
           <leafValues>
-            -1.0186699032783508e-01 4.2578670382499695e-01</leafValues></_>
+            -8.7241113185882568e-02 3.9513549208641052e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 354 1.6905765980482101e-02</internalNodes>
+            0 -1 463 -1.0883151553571224e-03</internalNodes>
           <leafValues>
-            -1.3217522203922272e-01 3.3241125941276550e-01</leafValues></_>
+            2.9802373051643372e-01 -1.3696449995040894e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 515 5.7176817208528519e-03</internalNodes>
+            0 -1 655 -5.0911568105220795e-03</internalNodes>
           <leafValues>
-            6.6569112241268158e-02 -6.5681034326553345e-01</leafValues></_>
+            -6.2439930438995361e-01 6.2544539570808411e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 276 -1.0900674387812614e-03</internalNodes>
+            0 -1 221 -5.2395770326256752e-03</internalNodes>
           <leafValues>
-            3.9689606428146362e-01 -1.1235479265451431e-01</leafValues></_>
+            -6.9036418199539185e-01 4.5142117887735367e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 760 -2.3833939805626869e-02</internalNodes>
+            0 -1 955 4.0486194193363190e-02</internalNodes>
           <leafValues>
-            3.8570886850357056e-01 -1.0193232446908951e-01</leafValues></_>
+            -7.5753845274448395e-02 5.2426725625991821e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 344 -1.4802538789808750e-02</internalNodes>
+            0 -1 300 4.1610337793827057e-03</internalNodes>
           <leafValues>
-            3.4205844998359680e-01 -1.4262656867504120e-01</leafValues></_>
+            6.6071115434169769e-02 -5.8079534769058228e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 448 3.9707131683826447e-02</internalNodes>
+            0 -1 272 -6.4253048039972782e-03</internalNodes>
           <leafValues>
-            -9.5635637640953064e-02 4.4075250625610352e-01</leafValues></_>
+            3.0481830239295959e-01 -1.1435022950172424e-01</leafValues></_></weakClassifiers></_>
+    <!-- stage 5 -->
+    <_>
+      <maxWeakCount>44</maxWeakCount>
+      <stageThreshold>-1.4235107898712158e+00</stageThreshold>
+      <weakClassifiers>
         <_>
           <internalNodes>
-            0 -1 547 6.4531993120908737e-03</internalNodes>
+            0 -1 716 -2.2738082334399223e-03</internalNodes>
           <leafValues>
-            5.7593464851379395e-02 -7.0275545120239258e-01</leafValues></_>
+            5.9519726037979126e-01 -1.6779936850070953e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 922 -4.7811353579163551e-03</internalNodes>
+            0 -1 457 -1.2204157188534737e-02</internalNodes>
           <leafValues>
-            2.7453303337097168e-01 -1.3652370870113373e-01</leafValues></_>
+            4.6985983848571777e-01 -1.7339397966861725e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 896 3.3349171280860901e-03</internalNodes>
+            0 -1 754 3.1242824625223875e-03</internalNodes>
           <leafValues>
-            5.8540347963571548e-02 -7.1738266944885254e-01</leafValues></_>
+            -2.2488421201705933e-01 3.4029743075370789e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 127 -1.0832921601831913e-02</internalNodes>
+            0 -1 777 -3.9868438616394997e-03</internalNodes>
           <leafValues>
-            -6.2031352519989014e-01 4.7055520117282867e-02</leafValues></_>
+            3.8314539194107056e-01 -1.8952924013137817e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 696 -3.5385387018322945e-03</internalNodes>
+            0 -1 538 -5.4737669415771961e-03</internalNodes>
           <leafValues>
-            2.7126258611679077e-01 -1.3402579724788666e-01</leafValues></_>
+            2.4583901464939117e-01 -2.3114782571792603e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 785 -2.1408915519714355e-02</internalNodes>
+            0 -1 453 1.5154287219047546e-02</internalNodes>
           <leafValues>
-            3.6707195639610291e-01 -1.0640451312065125e-01</leafValues></_>
+            -1.0675037652254105e-01 5.8347207307815552e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 617 6.6339373588562012e-02</internalNodes>
+            0 -1 397 -1.4294658321887255e-03</internalNodes>
           <leafValues>
-            -1.0504902899265289e-01 3.3936560153961182e-01</leafValues></_>
+            3.8292840123176575e-01 -1.2911921739578247e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 581 2.2766939364373684e-03</internalNodes>
+            0 -1 750 -7.4405185878276825e-03</internalNodes>
           <leafValues>
-            7.2598882019519806e-02 -5.3970605134963989e-01</leafValues></_>
+            2.8356546163558960e-01 -1.7810684442520142e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 626 1.6875732690095901e-03</internalNodes>
+            0 -1 786 -4.0357224643230438e-03</internalNodes>
           <leafValues>
-            8.7735749781131744e-02 -4.0284165740013123e-01</leafValues></_>
+            2.6303085684776306e-01 -1.6862161457538605e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 623 8.4530832245945930e-03</internalNodes>
+            0 -1 618 -5.8342106640338898e-03</internalNodes>
           <leafValues>
-            -9.3997113406658173e-02 4.1698867082595825e-01</leafValues></_>
+            3.2040205597877502e-01 -1.4103877544403076e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 429 5.5649573914706707e-03</internalNodes>
+            0 -1 161 1.7279960215091705e-02</internalNodes>
           <leafValues>
-            -8.7597280740737915e-02 3.8827970623970032e-01</leafValues></_>
+            -1.7433850467205048e-01 2.7985212206840515e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 429 -3.5470342263579369e-03</internalNodes>
+            0 -1 292 2.2125110030174255e-02</internalNodes>
           <leafValues>
-            3.3585703372955322e-01 -1.3658957183361053e-01</leafValues></_>
+            -1.1797516793012619e-01 4.0373948216438293e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 954 4.2132395319640636e-03</internalNodes>
+            0 -1 958 -4.4059187173843384e-02</internalNodes>
           <leafValues>
-            7.2930902242660522e-02 -5.1745194196701050e-01</leafValues></_>
+            5.2820503711700439e-01 -7.0916719734668732e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 527 3.4532562131062150e-04</internalNodes>
+            0 -1 194 -3.8316637277603149e-02</internalNodes>
           <leafValues>
-            -1.7970138788223267e-01 2.1011430025100708e-01</leafValues></_>
+            3.8833045959472656e-01 -1.0811555385589600e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 828 -4.0376763790845871e-03</internalNodes>
+            0 -1 178 4.5704744756221771e-02</internalNodes>
           <leafValues>
-            2.7334249019622803e-01 -1.3640886545181274e-01</leafValues></_></weakClassifiers></_>
-    <!-- stage 4 -->
-    <_>
-      <maxWeakCount>57</maxWeakCount>
-      <stageThreshold>-1.5859905481338501e+00</stageThreshold>
-      <weakClassifiers>
+            -1.7566929757595062e-01 3.4665411710739136e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 376 -1.5983805060386658e-02</internalNodes>
+            0 -1 434 1.1523386929184198e-03</internalNodes>
           <leafValues>
-            7.4085760116577148e-01 5.4202862083911896e-02</leafValues></_>
+            -1.7257389426231384e-01 2.5989890098571777e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 654 1.4518834650516510e-02</internalNodes>
+            0 -1 121 -1.0491746477782726e-02</internalNodes>
           <leafValues>
-            -1.6582691669464111e-01 5.1249128580093384e-01</leafValues></_>
+            -6.1285555362701416e-01 7.1230083703994751e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 820 -1.0167414322495461e-02</internalNodes>
+            0 -1 395 -4.5014433562755585e-03</internalNodes>
           <leafValues>
-            4.5000806450843811e-01 -1.3064502179622650e-01</leafValues></_>
+            -5.7712453603744507e-01 5.8887075632810593e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 493 2.7079641819000244e-02</internalNodes>
+            0 -1 950 -3.7281280383467674e-03</internalNodes>
           <leafValues>
-            -1.6735902428627014e-01 6.3848841190338135e-01</leafValues></_>
+            -6.7359894514083862e-01 5.2957162261009216e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 774 1.9515088060870767e-03</internalNodes>
+            0 -1 331 3.4461893141269684e-02</internalNodes>
           <leafValues>
-            -1.1798944324254990e-01 3.9749121665954590e-01</leafValues></_>
+            -1.0375578701496124e-01 3.7974634766578674e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 332 1.3693260028958321e-02</internalNodes>
+            0 -1 462 -1.3906960375607014e-03</internalNodes>
           <leafValues>
-            -8.5312500596046448e-02 5.4718613624572754e-01</leafValues></_>
+            3.9171192049980164e-01 -1.0048408061265945e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 254 6.0192337259650230e-03</internalNodes>
+            0 -1 85 1.6332454979419708e-02</internalNodes>
           <leafValues>
-            5.7217631489038467e-02 -6.6589832305908203e-01</leafValues></_>
+            8.6256101727485657e-02 -4.5887523889541626e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 139 -5.6810788810253143e-03</internalNodes>
+            0 -1 356 -6.0738036409020424e-03</internalNodes>
           <leafValues>
-            -5.7089996337890625e-01 8.1808418035507202e-02</leafValues></_>
+            -5.2265202999114990e-01 6.5308839082717896e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 898 4.8240914475172758e-04</internalNodes>
+            0 -1 486 -3.3630726393312216e-03</internalNodes>
           <leafValues>
-            -2.2115968167781830e-01 2.1608626842498779e-01</leafValues></_>
+            -5.6505429744720459e-01 5.5844355374574661e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 699 -6.6948928870260715e-03</internalNodes>
+            0 -1 418 -1.5329496003687382e-02</internalNodes>
           <leafValues>
-            -6.5513664484024048e-01 7.3252275586128235e-02</leafValues></_>
+            3.4475114941596985e-01 -1.0086353123188019e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 607 -1.4181779697537422e-02</internalNodes>
+            0 -1 587 -9.0496204793453217e-03</internalNodes>
           <leafValues>
-            3.2152280211448669e-01 -1.5524932742118835e-01</leafValues></_>
+            2.9553902149200439e-01 -1.1406829208135605e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 172 1.6027893871068954e-02</internalNodes>
+            0 -1 794 -3.1109917908906937e-03</internalNodes>
           <leafValues>
-            -1.3886103034019470e-01 3.2296729087829590e-01</leafValues></_>
+            -4.4897687435150146e-01 7.3615357279777527e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 379 3.8102023303508759e-02</internalNodes>
+            0 -1 939 3.3499556593596935e-03</internalNodes>
           <leafValues>
-            -8.4586337208747864e-02 5.0823771953582764e-01</leafValues></_>
+            5.4718658328056335e-02 -5.4810231924057007e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 627 -6.8796845152974129e-03</internalNodes>
+            0 -1 188 1.8374501960352063e-03</internalNodes>
           <leafValues>
-            2.8458747267723083e-01 -1.6626659035682678e-01</leafValues></_>
+            -1.3522666692733765e-01 2.4655479192733765e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 316 -5.7869823649525642e-03</internalNodes>
+            0 -1 908 2.6134990621358156e-03</internalNodes>
           <leafValues>
-            -6.7561829090118408e-01 6.7125916481018066e-02</leafValues></_>
+            6.6369861364364624e-02 -4.7342041134834290e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 84 -1.0403458960354328e-02</internalNodes>
+            0 -1 65 -7.4155852198600769e-03</internalNodes>
           <leafValues>
-            -6.8244606256484985e-01 5.5120140314102173e-02</leafValues></_>
+            2.0866124331951141e-01 -1.5775154531002045e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 253 7.2765655815601349e-02</internalNodes>
+            0 -1 515 3.9352793246507645e-03</internalNodes>
           <leafValues>
-            -1.2289700657129288e-01 3.4603855013847351e-01</leafValues></_>
+            5.1660846918821335e-02 -6.2589824199676514e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 145 -5.2832886576652527e-02</internalNodes>
+            0 -1 735 -1.0450070258229971e-03</internalNodes>
           <leafValues>
-            3.6294373869895935e-01 -1.1915811896324158e-01</leafValues></_>
+            3.3525371551513672e-01 -1.0084854811429977e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 791 -2.0185699686408043e-03</internalNodes>
+            0 -1 784 1.2639444321393967e-03</internalNodes>
           <leafValues>
-            3.0245268344879150e-01 -1.5617357194423676e-01</leafValues></_>
+            -1.2103077769279480e-01 2.7691018581390381e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 606 -2.8552478179335594e-03</internalNodes>
+            0 -1 479 7.7577251940965652e-03</internalNodes>
           <leafValues>
-            -6.5382599830627441e-01 6.9692179560661316e-02</leafValues></_>
+            4.6813234686851501e-02 -7.3385792970657349e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 167 -3.6076260730624199e-03</internalNodes>
+            0 -1 18 -1.0632604360580444e-02</internalNodes>
           <leafValues>
-            -5.5573904514312744e-01 6.0684457421302795e-02</leafValues></_>
+            -7.1024382114410400e-01 3.3777639269828796e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 85 -1.2505692429840565e-03</internalNodes>
+            0 -1 183 1.8631946295499802e-02</internalNodes>
           <leafValues>
-            2.2487366199493408e-01 -1.7713856697082520e-01</leafValues></_>
+            -1.4613701403141022e-01 2.1491082012653351e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 643 1.6213182359933853e-02</internalNodes>
+            0 -1 608 4.9128942191600800e-03</internalNodes>
           <leafValues>
-            6.7865289747714996e-02 -5.5539685487747192e-01</leafValues></_>
+            5.3445268422365189e-02 -6.3314527273178101e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 24 -2.7728214859962463e-02</internalNodes>
+            0 -1 473 -9.8230186849832535e-03</internalNodes>
           <leafValues>
-            -5.8333241939544678e-01 5.7263575494289398e-02</leafValues></_>
+            2.6917773485183716e-01 -1.1376978456974030e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 267 -1.2375607620924711e-03</internalNodes>
+            0 -1 910 -3.0754944309592247e-03</internalNodes>
           <leafValues>
-            2.9786622524261475e-01 -1.2998357415199280e-01</leafValues></_>
+            -5.0787961483001709e-01 6.1582125723361969e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 622 2.4766498245298862e-03</internalNodes>
+            0 -1 659 -6.7374799400568008e-03</internalNodes>
           <leafValues>
-            8.8138826191425323e-02 -4.3225872516632080e-01</leafValues></_>
+            2.3871047794818878e-01 -1.2552142143249512e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 382 1.0034437291324139e-03</internalNodes>
+            0 -1 507 -1.1759715154767036e-02</internalNodes>
           <leafValues>
-            -1.1115902662277222e-01 3.2714295387268066e-01</leafValues></_>
+            3.3646693825721741e-01 -9.4460532069206238e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 374 -6.4956350252032280e-03</internalNodes>
+            0 -1 318 -4.1377237066626549e-03</internalNodes>
           <leafValues>
-            -7.0529288053512573e-01 6.1914756894111633e-02</leafValues></_>
+            -5.0522220134735107e-01 6.2668189406394958e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 409 -1.2748142704367638e-02</internalNodes>
+            0 -1 320 1.7267453949898481e-03</internalNodes>
           <leafValues>
-            3.6699298024177551e-01 -1.0546508431434631e-01</leafValues></_>
+            -8.0607026815414429e-02 3.8304185867309570e-01</leafValues></_></weakClassifiers></_>
+    <!-- stage 6 -->
+    <_>
+      <maxWeakCount>47</maxWeakCount>
+      <stageThreshold>-1.4313566684722900e+00</stageThreshold>
+      <weakClassifiers>
         <_>
           <internalNodes>
-            0 -1 494 -5.6289080530405045e-03</internalNodes>
+            0 -1 882 -1.1920252814888954e-02</internalNodes>
           <leafValues>
-            -8.3690512180328369e-01 4.8901058733463287e-02</leafValues></_>
+            5.6617152690887451e-01 -1.5811842679977417e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 846 -3.0219005420804024e-03</internalNodes>
+            0 -1 568 -4.3085627257823944e-03</internalNodes>
           <leafValues>
-            2.2210697829723358e-01 -1.6297030448913574e-01</leafValues></_>
+            4.4759327173233032e-01 -1.6846470534801483e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 938 2.9230308718979359e-03</internalNodes>
+            0 -1 883 1.1177745182067156e-03</internalNodes>
           <leafValues>
-            8.0248229205608368e-02 -4.7586214542388916e-01</leafValues></_>
+            -1.5351393818855286e-01 4.3508940935134888e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 620 -1.6901228576898575e-02</internalNodes>
+            0 -1 798 3.5418532788753510e-02</internalNodes>
           <leafValues>
-            3.2134863734245300e-01 -1.1946766823530197e-01</leafValues></_>
+            -1.2973460555076599e-01 3.6943939328193665e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 452 -1.6434368444606662e-03</internalNodes>
+            0 -1 393 2.2405586205422878e-03</internalNodes>
           <leafValues>
-            3.5056352615356445e-01 -1.0065372288227081e-01</leafValues></_>
+            -1.8800468742847443e-01 3.2498928904533386e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 104 6.0744080692529678e-03</internalNodes>
+            0 -1 265 -1.7982896417379379e-02</internalNodes>
           <leafValues>
-            7.7158488333225250e-02 -5.0687175989151001e-01</leafValues></_>
+            4.5607218146324158e-01 -1.0459473729133606e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 677 -6.2521770596504211e-02</internalNodes>
+            0 -1 152 -4.9088716506958008e-02</internalNodes>
           <leafValues>
-            3.5145899653434753e-01 -1.0493072122335434e-01</leafValues></_>
+            3.4279289841651917e-01 -1.5114119648933411e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 738 1.4936760999262333e-03</internalNodes>
+            0 -1 275 7.1780886501073837e-03</internalNodes>
           <leafValues>
-            -1.1596123874187469e-01 3.1784045696258545e-01</leafValues></_>
+            6.3825756311416626e-02 -6.2449872493743896e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 935 -4.6554272994399071e-03</internalNodes>
+            0 -1 849 3.9123920723795891e-03</internalNodes>
           <leafValues>
-            -5.8499008417129517e-01 6.5426386892795563e-02</leafValues></_>
+            7.1502417325973511e-02 -6.3956946134567261e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 718 5.1631154492497444e-03</internalNodes>
+            0 -1 689 -4.1980943642556667e-03</internalNodes>
           <leafValues>
-            4.6380143612623215e-02 -6.5920770168304443e-01</leafValues></_>
+            2.1998657286167145e-01 -1.9890366494655609e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 431 5.7699503377079964e-03</internalNodes>
+            0 -1 660 -4.5476644299924374e-03</internalNodes>
           <leafValues>
-            -1.0032630711793900e-01 3.4062737226486206e-01</leafValues></_>
+            2.1866278350353241e-01 -1.9852560758590698e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 306 -9.6255233511328697e-03</internalNodes>
+            0 -1 944 -4.4158436357975006e-03</internalNodes>
           <leafValues>
-            2.2360336780548096e-01 -1.5362788736820221e-01</leafValues></_>
+            2.3959043622016907e-01 -1.7090958356857300e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 372 -2.8061982244253159e-02</internalNodes>
+            0 -1 281 -4.7058244235813618e-03</internalNodes>
           <leafValues>
-            2.5125834345817566e-01 -1.2988410890102386e-01</leafValues></_>
+            -5.1537507772445679e-01 9.0310461819171906e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 807 7.1229478344321251e-03</internalNodes>
+            0 -1 116 -8.7488889694213867e-03</internalNodes>
           <leafValues>
-            5.3426012396812439e-02 -6.4893049001693726e-01</leafValues></_>
+            2.2937677800655365e-01 -1.8315380811691284e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 46 1.4473337680101395e-02</internalNodes>
+            0 -1 645 -3.1655649654567242e-03</internalNodes>
           <leafValues>
-            -1.2796792387962341e-01 2.5788536667823792e-01</leafValues></_>
+            -7.3091191053390503e-01 6.5193220973014832e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 240 -4.4487215578556061e-02</internalNodes>
+            0 -1 267 6.4696683548390865e-03</internalNodes>
           <leafValues>
-            4.8267531394958496e-01 -7.5288593769073486e-02</leafValues></_>
+            -1.1077737808227539e-01 3.7207809090614319e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 408 3.3553102985024452e-03</internalNodes>
+            0 -1 615 2.2985613904893398e-03</internalNodes>
           <leafValues>
-            6.5222866833209991e-02 -5.3387296199798584e-01</leafValues></_>
+            7.7800542116165161e-02 -5.1104581356048584e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 6 2.6522833853960037e-02</internalNodes>
+            0 -1 359 4.5809363946318626e-03</internalNodes>
           <leafValues>
-            4.7097213566303253e-02 -5.7117742300033569e-01</leafValues></_>
+            5.7778771966695786e-02 -5.7898092269897461e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 407 5.3791850805282593e-03</internalNodes>
+            0 -1 188 1.1279166210442781e-03</internalNodes>
           <leafValues>
-            4.9663346260786057e-02 -5.0957924127578735e-01</leafValues></_>
+            -1.7981146275997162e-01 1.9939005374908447e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 684 -8.8640749454498291e-03</internalNodes>
+            0 -1 347 -1.2820301577448845e-02</internalNodes>
           <leafValues>
-            3.3878505229949951e-01 -8.6965307593345642e-02</leafValues></_>
+            5.1867282390594482e-01 -6.9989629089832306e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 78 2.7605522423982620e-02</internalNodes>
+            0 -1 810 4.4866472482681274e-02</internalNodes>
           <leafValues>
-            4.4678669422864914e-02 -6.9978964328765869e-01</leafValues></_>
+            -1.4253044128417969e-01 3.0062338709831238e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 944 -1.1171739548444748e-02</internalNodes>
+            0 -1 412 -3.5413210280239582e-03</internalNodes>
           <leafValues>
-            -7.3840415477752686e-01 3.0841451138257980e-02</leafValues></_>
+            -5.7618641853332520e-01 6.0328345745801926e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 731 -1.0616163490340114e-03</internalNodes>
+            0 -1 362 -7.4678594246506691e-03</internalNodes>
           <leafValues>
-            3.0718466639518738e-01 -9.7260892391204834e-02</leafValues></_>
+            -5.0187259912490845e-01 6.1294022947549820e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 169 -7.2728879749774933e-03</internalNodes>
+            0 -1 678 1.8058011308312416e-02</internalNodes>
           <leafValues>
-            -7.1966600418090820e-01 4.3096855282783508e-02</leafValues></_>
+            5.3603217005729675e-02 -5.8919399976730347e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 924 -1.1083125136792660e-02</internalNodes>
+            0 -1 935 -6.8098572082817554e-03</internalNodes>
           <leafValues>
-            3.8436344265937805e-01 -8.1930950284004211e-02</leafValues></_>
+            -5.4100829362869263e-01 5.5898215621709824e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 674 -7.1662524715065956e-03</internalNodes>
+            0 -1 307 3.6491458304226398e-03</internalNodes>
           <leafValues>
-            2.0970225334167480e-01 -1.5484949946403503e-01</leafValues></_>
+            4.7378763556480408e-02 -5.9323132038116455e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 20 8.2661323249340057e-03</internalNodes>
+            0 -1 284 1.4524955768138170e-03</internalNodes>
           <leafValues>
-            5.9242360293865204e-02 -5.1503551006317139e-01</leafValues></_>
+            -8.8994570076465607e-02 3.8729071617126465e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 748 7.3844827711582184e-03</internalNodes>
+            0 -1 219 -6.2408884987235069e-03</internalNodes>
           <leafValues>
-            3.3728431910276413e-02 -7.2390365600585938e-01</leafValues></_></weakClassifiers></_>
-    <!-- stage 5 -->
-    <_>
-      <maxWeakCount>61</maxWeakCount>
-      <stageThreshold>-1.5647197961807251e+00</stageThreshold>
-      <weakClassifiers>
+            -6.6442847251892090e-01 5.1082015037536621e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 443 -7.5000515207648277e-03</internalNodes>
+            0 -1 744 -9.9360430613160133e-04</internalNodes>
           <leafValues>
-            6.9735616445541382e-01 -7.0126228965818882e-03</leafValues></_>
+            3.2972389459609985e-01 -1.0494423657655716e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 713 -2.5447460357099771e-03</internalNodes>
+            0 -1 285 3.9777760393917561e-03</internalNodes>
           <leafValues>
-            5.4742383956909180e-01 -1.3766847550868988e-01</leafValues></_>
+            5.4083213210105896e-02 -6.2114214897155762e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 278 6.3486215658485889e-03</internalNodes>
+            0 -1 380 -1.4884659089148045e-02</internalNodes>
           <leafValues>
-            -1.5121677517890930e-01 6.0269719362258911e-01</leafValues></_>
+            2.4066454172134399e-01 -1.2317410856485367e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 860 2.5572092272341251e-03</internalNodes>
+            0 -1 436 3.3154981210827827e-03</internalNodes>
           <leafValues>
-            -2.1577885746955872e-01 3.9897701144218445e-01</leafValues></_>
+            -1.1744727939367294e-01 2.9429042339324951e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 510 -6.5959235653281212e-03</internalNodes>
+            0 -1 976 -4.7508114948868752e-03</internalNodes>
           <leafValues>
-            3.2995587587356567e-01 -2.0266638696193695e-01</leafValues></_>
+            -4.5763325691223145e-01 6.7066885530948639e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 857 1.5824008733034134e-02</internalNodes>
+            0 -1 779 -1.1973761022090912e-02</internalNodes>
           <leafValues>
-            -1.4384938776493073e-01 5.4570239782333374e-01</leafValues></_>
+            2.5750914216041565e-01 -1.1354148387908936e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 335 3.4904260188341141e-02</internalNodes>
+            0 -1 740 4.9072699621319771e-03</internalNodes>
           <leafValues>
-            -1.0439507663249969e-01 5.3645384311676025e-01</leafValues></_>
+            -1.1266437917947769e-01 3.0022394657135010e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 2 7.4804951436817646e-03</internalNodes>
+            0 -1 56 6.5630510449409485e-02</internalNodes>
           <leafValues>
-            -1.7777608335018158e-01 3.0247840285301208e-01</leafValues></_>
+            -1.0180503129959106e-01 3.0517497658729553e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 61 -5.1247365772724152e-02</internalNodes>
+            0 -1 354 -2.3393325507640839e-02</internalNodes>
           <leafValues>
-            5.7459318637847900e-01 -1.0999230295419693e-01</leafValues></_>
+            3.2443770766258240e-01 -9.5363102853298187e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 629 -5.0416901707649231e-02</internalNodes>
+            0 -1 834 -3.8902116939425468e-03</internalNodes>
           <leafValues>
-            4.6202743053436279e-01 -8.9995197951793671e-02</leafValues></_>
+            2.0148487389087677e-01 -1.4944279193878174e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 177 1.2860384769737720e-02</internalNodes>
+            0 -1 185 -2.5926973670721054e-02</internalNodes>
           <leafValues>
-            -1.5580976009368896e-01 2.6711037755012512e-01</leafValues></_>
+            -4.4917497038841248e-01 6.9752328097820282e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 645 2.3457493633031845e-02</internalNodes>
+            0 -1 173 -7.1825529448688030e-03</internalNodes>
           <leafValues>
-            5.4399158805608749e-02 -7.5605469942092896e-01</leafValues></_>
+            -5.6838059425354004e-01 4.9584377557039261e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 775 -3.4703868441283703e-03</internalNodes>
+            0 -1 548 -9.9399685859680176e-03</internalNodes>
           <leafValues>
-            2.3663245141506195e-01 -1.6793093085289001e-01</leafValues></_>
+            3.0747908353805542e-01 -1.1064232140779495e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 256 4.2368983849883080e-03</internalNodes>
+            0 -1 978 -3.6286246031522751e-03</internalNodes>
           <leafValues>
-            6.2613829970359802e-02 -6.2294322252273560e-01</leafValues></_>
+            -6.0276371240615845e-01 5.2405584603548050e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 727 -8.7803313508629799e-03</internalNodes>
+            0 -1 820 1.5756220091134310e-03</internalNodes>
           <leafValues>
-            3.0670607089996338e-01 -1.2937802076339722e-01</leafValues></_>
+            -1.1615782976150513e-01 2.6717522740364075e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 38 7.3221437633037567e-03</internalNodes>
+            0 -1 426 3.5662509500980377e-02</internalNodes>
           <leafValues>
-            8.7675094604492188e-02 -4.8196199536323547e-01</leafValues></_>
+            -1.0885569453239441e-01 2.9044550657272339e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 176 5.7109566405415535e-03</internalNodes>
+            0 -1 554 5.3282946348190308e-02</internalNodes>
           <leafValues>
-            -1.6586679220199585e-01 2.4693855643272400e-01</leafValues></_>
+            -8.1855505704879761e-02 4.0298762917518616e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 393 -1.0330275399610400e-03</internalNodes>
+            0 -1 988 3.3901704009622335e-03</internalNodes>
           <leafValues>
-            2.8573888540267944e-01 -1.2924034893512726e-01</leafValues></_>
+            5.5047694593667984e-02 -5.4021596908569336e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 558 -4.1551878675818443e-03</internalNodes>
+            0 -1 384 1.3204356655478477e-03</internalNodes>
           <leafValues>
-            -6.7751622200012207e-01 5.5871110409498215e-02</leafValues></_>
+            -9.4643965363502502e-02 3.0430349707603455e-01</leafValues></_></weakClassifiers></_>
+    <!-- stage 7 -->
+    <_>
+      <maxWeakCount>48</maxWeakCount>
+      <stageThreshold>-1.3744181394577026e+00</stageThreshold>
+      <weakClassifiers>
         <_>
           <internalNodes>
-            0 -1 770 -8.7040066719055176e-03</internalNodes>
+            0 -1 788 3.9594387635588646e-03</internalNodes>
           <leafValues>
-            2.6861536502838135e-01 -1.4459304511547089e-01</leafValues></_>
+            -1.5454453229904175e-01 4.9922767281532288e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 196 3.9226360619068146e-02</internalNodes>
+            0 -1 467 -1.6322813928127289e-02</internalNodes>
           <leafValues>
-            -1.0390799492597580e-01 3.5152482986450195e-01</leafValues></_>
+            4.2537182569503784e-01 -1.5276345610618591e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 115 -4.7440445050597191e-03</internalNodes>
+            0 -1 746 1.6230947803705931e-03</internalNodes>
           <leafValues>
-            2.5985953211784363e-01 -1.4647118747234344e-01</leafValues></_>
+            -2.2640861570835114e-01 2.5220483541488647e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 375 -3.9255903102457523e-03</internalNodes>
+            0 -1 115 -6.0441931709647179e-03</internalNodes>
           <leafValues>
-            -5.1697838306427002e-01 7.4196860194206238e-02</leafValues></_>
+            2.2711095213890076e-01 -2.1762822568416595e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 273 -1.0538822039961815e-02</internalNodes>
+            0 -1 6 1.1688062921166420e-02</internalNodes>
           <leafValues>
-            3.7007546424865723e-01 -1.1099486052989960e-01</leafValues></_>
+            -1.6991630196571350e-01 2.8343129158020020e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 336 -6.4126476645469666e-03</internalNodes>
+            0 -1 624 -3.1942571513354778e-03</internalNodes>
           <leafValues>
-            -6.8768596649169922e-01 6.5695002675056458e-02</leafValues></_>
+            -6.2475329637527466e-01 7.3184341192245483e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 614 -6.6444426774978638e-03</internalNodes>
+            0 -1 11 -7.6569117605686188e-02</internalNodes>
           <leafValues>
-            2.3941572010517120e-01 -1.5043427050113678e-01</leafValues></_>
+            5.5236744880676270e-01 -7.7832877635955811e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 784 3.6154527217149734e-02</internalNodes>
+            0 -1 306 1.8717286875471473e-03</internalNodes>
           <leafValues>
-            -9.1301433742046356e-02 4.3764653801918030e-01</leafValues></_>
+            8.4293909370899200e-02 -5.2716743946075439e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 321 2.0614354871213436e-03</internalNodes>
+            0 -1 351 3.5880310460925102e-03</internalNodes>
           <leafValues>
-            -1.0028914362192154e-01 3.4935840964317322e-01</leafValues></_>
+            -1.2907223403453827e-01 3.3967444300651550e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 937 -2.6316416915506124e-03</internalNodes>
+            0 -1 176 -5.7136151008307934e-03</internalNodes>
           <leafValues>
-            -4.7376596927642822e-01 7.9684391617774963e-02</leafValues></_>
+            -5.9208476543426514e-01 7.7793844044208527e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 136 -6.9046420976519585e-03</internalNodes>
+            0 -1 150 -1.9309867173433304e-02</internalNodes>
           <leafValues>
-            -5.4207211732864380e-01 5.3584035485982895e-02</leafValues></_>
+            2.5386241078376770e-01 -1.7397734522819519e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 792 -7.9165250062942505e-03</internalNodes>
+            0 -1 327 -2.4289516732096672e-03</internalNodes>
           <leafValues>
-            2.3244017362594604e-01 -1.4517860114574432e-01</leafValues></_>
+            3.2221227884292603e-01 -1.2751287221908569e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 285 6.6963117569684982e-03</internalNodes>
+            0 -1 25 -8.5500031709671021e-02</internalNodes>
           <leafValues>
-            5.6810487061738968e-02 -6.3260114192962646e-01</leafValues></_>
+            -7.7962499856948853e-01 5.0715133547782898e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 810 -1.8640372902154922e-02</internalNodes>
+            0 -1 770 5.7447291910648346e-03</internalNodes>
           <leafValues>
-            2.3912836611270905e-01 -1.4180511236190796e-01</leafValues></_>
+            -1.1523491144180298e-01 3.6400210857391357e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 451 -1.2744618579745293e-03</internalNodes>
+            0 -1 781 5.8936916291713715e-02</internalNodes>
           <leafValues>
-            3.5026183724403381e-01 -9.4078496098518372e-02</leafValues></_>
+            -8.7829843163490295e-02 4.1893997788429260e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 385 -6.6458717919886112e-03</internalNodes>
+            0 -1 984 -4.1379006579518318e-03</internalNodes>
           <leafValues>
-            -6.4737498760223389e-01 5.4980348795652390e-02</leafValues></_>
+            -6.3083720207214355e-01 6.4935714006423950e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 759 5.5033955723047256e-03</internalNodes>
+            0 -1 565 -4.6407114714384079e-03</internalNodes>
           <leafValues>
-            3.6262378096580505e-02 -7.0103096961975098e-01</leafValues></_>
+            -6.5650087594985962e-01 5.4394256323575974e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 371 -6.0990457423031330e-03</internalNodes>
+            0 -1 877 1.5865347813814878e-03</internalNodes>
           <leafValues>
-            3.1506294012069702e-01 -1.0298713296651840e-01</leafValues></_>
+            -1.7255148291587830e-01 2.3248092830181122e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 955 -9.5215532928705215e-04</internalNodes>
+            0 -1 624 2.8971401043236256e-03</internalNodes>
           <leafValues>
-            -3.3243876695632935e-01 9.4536833465099335e-02</leafValues></_>
+            6.0526229441165924e-02 -5.4368048906326294e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 133 -4.8709083348512650e-03</internalNodes>
+            0 -1 773 1.5737174544483423e-03</internalNodes>
           <leafValues>
-            -5.5286788940429688e-01 4.8858009278774261e-02</leafValues></_>
+            -1.1744406074285507e-01 3.0534917116165161e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 476 -1.9530812278389931e-03</internalNodes>
+            0 -1 609 1.6838097944855690e-03</internalNodes>
           <leafValues>
-            2.6475632190704346e-01 -1.2214422971010208e-01</leafValues></_>
+            6.6153712570667267e-02 -5.9224641323089600e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 852 -1.6108162701129913e-02</internalNodes>
+            0 -1 912 3.2287575304508209e-03</internalNodes>
           <leafValues>
-            2.4747616052627563e-01 -1.4181286096572876e-01</leafValues></_>
+            5.2678912878036499e-02 -5.7474386692047119e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 747 -3.3051617443561554e-02</internalNodes>
+            0 -1 850 -3.1512752175331116e-03</internalNodes>
           <leafValues>
-            4.7526669502258301e-01 -6.3493676483631134e-02</leafValues></_>
+            3.7773844599723816e-01 -8.7322145700454712e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 465 -2.0969051867723465e-02</internalNodes>
+            0 -1 894 8.2073279190808535e-04</internalNodes>
           <leafValues>
-            3.7475255131721497e-01 -8.7978623807430267e-02</leafValues></_>
+            -1.0513201355934143e-01 3.4025487303733826e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 862 -1.1976938694715500e-03</internalNodes>
+            0 -1 603 2.8983387164771557e-03</internalNodes>
           <leafValues>
-            2.8161275386810303e-01 -1.0515356063842773e-01</leafValues></_>
+            5.1720291376113892e-02 -6.5431916713714600e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 937 3.0867555178701878e-03</internalNodes>
+            0 -1 852 -5.7246205396950245e-03</internalNodes>
           <leafValues>
-            6.1260223388671875e-02 -5.0152593851089478e-01</leafValues></_>
+            -7.8483843803405762e-01 3.5195719450712204e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 261 5.4881181567907333e-03</internalNodes>
+            0 -1 44 -1.1572695337235928e-02</internalNodes>
           <leafValues>
-            5.0317917019128799e-02 -5.4196691513061523e-01</leafValues></_>
+            -6.7286187410354614e-01 3.5210411995649338e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 302 -3.6943652667105198e-03</internalNodes>
+            0 -1 80 -1.4562263153493404e-02</internalNodes>
           <leafValues>
-            -5.8759558200836182e-01 4.4150535017251968e-02</leafValues></_>
+            2.4655815958976746e-01 -1.2278749793767929e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 91 2.3760091513395309e-02</internalNodes>
+            0 -1 269 7.8490225132554770e-04</internalNodes>
           <leafValues>
-            -1.0199809074401855e-01 3.0310767889022827e-01</leafValues></_>
+            -1.4652141928672791e-01 3.0276218056678772e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 86 -2.1728422492742538e-02</internalNodes>
+            0 -1 725 -1.4289810787886381e-03</internalNodes>
           <leafValues>
-            3.1364366412162781e-01 -1.0069291293621063e-01</leafValues></_>
+            1.8906314671039581e-01 -1.5791040658950806e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 36 -2.5134570896625519e-02</internalNodes>
+            0 -1 108 -9.4615388661623001e-03</internalNodes>
           <leafValues>
-            -5.1455682516098022e-01 5.5909216403961182e-02</leafValues></_>
+            -6.9036215543746948e-01 3.9911076426506042e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 17 2.5713320821523666e-02</internalNodes>
+            0 -1 21 2.3225568234920502e-02</internalNodes>
           <leafValues>
-            -1.2262356281280518e-01 2.5486063957214355e-01</leafValues></_>
+            5.0278317183256149e-02 -5.2323836088180542e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 600 3.4806665498763323e-03</internalNodes>
+            0 -1 959 1.4046948403120041e-02</internalNodes>
           <leafValues>
-            4.3244410306215286e-02 -7.0197206735610962e-01</leafValues></_>
+            -7.9005211591720581e-02 4.0158179402351379e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 96 -3.8689947687089443e-03</internalNodes>
+            0 -1 126 3.7851710803806782e-03</internalNodes>
           <leafValues>
-            -5.8558273315429688e-01 4.0547560900449753e-02</leafValues></_>
+            -1.3530673086643219e-01 2.1973098814487457e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 787 -1.0773935355246067e-03</internalNodes>
+            0 -1 142 -3.6725951358675957e-03</internalNodes>
           <leafValues>
-            3.0767098069190979e-01 -9.5467783510684967e-02</leafValues></_>
+            1.9924460351467133e-01 -1.5001934766769409e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 789 2.9714959673583508e-03</internalNodes>
+            0 -1 963 -3.1669549643993378e-03</internalNodes>
           <leafValues>
-            -7.1951679885387421e-02 3.9655500650405884e-01</leafValues></_>
+            -4.2041611671447754e-01 7.4019186198711395e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 67 -8.8994875550270081e-03</internalNodes>
+            0 -1 695 -1.3667810708284378e-02</internalNodes>
           <leafValues>
-            -6.3042962551116943e-01 4.7020766884088516e-02</leafValues></_>
+            2.5204744935035706e-01 -1.2807497382164001e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 588 6.7773810587823391e-03</internalNodes>
+            0 -1 214 -3.5862527787685394e-02</internalNodes>
           <leafValues>
-            -7.5779460370540619e-02 3.6968868970870972e-01</leafValues></_>
+            3.2997950911521912e-01 -8.9863941073417664e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 508 -8.9795496314764023e-03</internalNodes>
+            0 -1 946 -6.2667285092175007e-03</internalNodes>
           <leafValues>
-            2.2023639082908630e-01 -1.3685037195682526e-01</leafValues></_>
+            -5.5024039745330811e-01 5.7369034737348557e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 258 -1.4680022373795509e-02</internalNodes>
+            0 -1 438 -6.4383493736386299e-03</internalNodes>
           <leafValues>
-            2.9656830430030823e-01 -9.4061806797981262e-02</leafValues></_>
+            3.3817592263221741e-01 -9.3247875571250916e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 208 -9.5530468970537186e-03</internalNodes>
+            0 -1 439 5.4173925891518593e-03</internalNodes>
           <leafValues>
-            2.9208987951278687e-01 -1.0542043298482895e-01</leafValues></_>
+            -1.0427469760179520e-01 2.9482829570770264e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 847 -1.4967216411605477e-03</internalNodes>
+            0 -1 400 -1.5132453292608261e-02</internalNodes>
           <leafValues>
-            2.1045146882534027e-01 -1.3942880928516388e-01</leafValues></_></weakClassifiers></_>
-    <!-- stage 6 -->
-    <_>
-      <maxWeakCount>67</maxWeakCount>
-      <stageThreshold>-1.5504211187362671e+00</stageThreshold>
-      <weakClassifiers>
+            3.2000914216041565e-01 -9.8272062838077545e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 454 -1.0960219427943230e-02</internalNodes>
+            0 -1 606 -1.2513613328337669e-02</internalNodes>
           <leafValues>
-            6.5447217226028442e-01 5.0713799893856049e-02</leafValues></_>
+            2.8962445259094238e-01 -1.2084391713142395e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 864 -1.1516783386468887e-02</internalNodes>
+            0 -1 91 -9.8966564983129501e-03</internalNodes>
           <leafValues>
-            4.6027910709381104e-01 -1.5864185988903046e-01</leafValues></_>
+            -5.8358079195022583e-01 5.1291342824697495e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 751 3.3400617539882660e-03</internalNodes>
+            0 -1 932 1.3835988938808441e-02</internalNodes>
           <leafValues>
-            -2.1552324295043945e-01 3.4321418404579163e-01</leafValues></_>
+            -9.0702146291732788e-02 3.2527267932891846e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 154 -3.8353595882654190e-03</internalNodes>
+            0 -1 92 3.6492943763732910e-03</internalNodes>
           <leafValues>
-            3.3496814966201782e-01 -2.3464411497116089e-01</leafValues></_>
+            8.4720104932785034e-02 -3.4649613499641418e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 57 -5.9523088857531548e-03</internalNodes>
+            0 -1 478 -1.3878188095986843e-02</internalNodes>
           <leafValues>
-            2.8272038698196411e-01 -2.0106634497642517e-01</leafValues></_>
+            2.9309025406837463e-01 -9.6585884690284729e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 788 -1.3916005846112967e-03</internalNodes>
+            0 -1 580 2.8816664125770330e-03</internalNodes>
           <leafValues>
-            3.4103384613990784e-01 -1.5115562081336975e-01</leafValues></_>
+            -1.0839603841304779e-01 2.5134062767028809e-01</leafValues></_></weakClassifiers></_>
+    <!-- stage 8 -->
+    <_>
+      <maxWeakCount>57</maxWeakCount>
+      <stageThreshold>-1.3757541179656982e+00</stageThreshold>
+      <weakClassifiers>
         <_>
           <internalNodes>
-            0 -1 325 -2.2318472620099783e-03</internalNodes>
+            0 -1 742 -4.1507836431264877e-03</internalNodes>
           <leafValues>
-            3.1695351004600525e-01 -1.6021527349948883e-01</leafValues></_>
+            4.7857573628425598e-01 -1.5079282224178314e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 677 8.3244532346725464e-02</internalNodes>
+            0 -1 539 -4.2431484907865524e-03</internalNodes>
           <leafValues>
-            -8.9079469442367554e-02 5.3136157989501953e-01</leafValues></_>
+            2.7976706624031067e-01 -2.1182695031166077e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 832 4.8591636121273041e-02</internalNodes>
+            0 -1 422 7.2727665305137634e-02</internalNodes>
           <leafValues>
-            -1.0279218852519989e-01 3.9601847529411316e-01</leafValues></_>
+            -1.1322361230850220e-01 4.6931907534599304e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 921 9.5052458345890045e-03</internalNodes>
+            0 -1 120 7.3349894955754280e-03</internalNodes>
           <leafValues>
-            5.5167526006698608e-02 -7.4528604745864868e-01</leafValues></_>
+            -2.2507375478744507e-01 2.3486614227294922e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 612 -3.7635704502463341e-03</internalNodes>
+            0 -1 79 -1.3757663965225220e-01</internalNodes>
           <leafValues>
-            -6.5434825420379639e-01 5.7055845856666565e-02</leafValues></_>
+            5.5153369903564453e-01 -8.4895148873329163e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 809 1.7548685718793422e-04</internalNodes>
+            0 -1 592 6.8098353222012520e-04</internalNodes>
           <leafValues>
-            -2.3401582241058350e-01 1.6428647935390472e-01</leafValues></_>
+            -1.7585472762584686e-01 2.2849111258983612e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 156 -5.4875545203685760e-02</internalNodes>
+            0 -1 110 2.7579340338706970e-01</internalNodes>
           <leafValues>
-            2.5605452060699463e-01 -1.5396752953529358e-01</leafValues></_>
+            -1.1671220511198044e-01 3.2674804329872131e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 5 -6.1811439692974091e-02</internalNodes>
+            0 -1 921 5.4910051403567195e-04</internalNodes>
           <leafValues>
-            4.2922756075859070e-01 -8.8362246751785278e-02</leafValues></_>
+            -2.0603717863559723e-01 1.8896938860416412e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 229 1.3979763025417924e-03</internalNodes>
+            0 -1 155 -5.5065844208002090e-03</internalNodes>
           <leafValues>
-            -7.3071695864200592e-02 4.5563563704490662e-01</leafValues></_>
+            -5.7701790332794189e-01 6.9212622940540314e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 229 -5.5876211263239384e-04</internalNodes>
+            0 -1 824 -8.3996364846825600e-03</internalNodes>
           <leafValues>
-            2.9506489634513855e-01 -1.2031728774309158e-01</leafValues></_>
+            4.6683028340339661e-01 -7.4202880263328552e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 31 -4.3148966506123543e-03</internalNodes>
+            0 -1 843 -1.1010931339114904e-03</internalNodes>
           <leafValues>
-            -5.7403188943862915e-01 6.6134005784988403e-02</leafValues></_>
+            1.9711431860923767e-01 -1.7736457288265228e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 228 -5.3551131859421730e-03</internalNodes>
+            0 -1 217 -4.4837296009063721e-03</internalNodes>
           <leafValues>
-            -5.2288484573364258e-01 6.9182172417640686e-02</leafValues></_>
+            -6.0108631849288940e-01 4.9327563494443893e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 117 -3.6877401173114777e-02</internalNodes>
+            0 -1 211 2.5086081586778164e-03</internalNodes>
           <leafValues>
-            3.3143782615661621e-01 -1.2777587771415710e-01</leafValues></_>
+            6.9480538368225098e-02 -4.8671180009841919e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 364 4.1612848639488220e-02</internalNodes>
+            0 -1 201 1.5808893367648125e-03</internalNodes>
           <leafValues>
-            -1.4963860809803009e-01 2.9361200332641602e-01</leafValues></_>
+            -1.0519328713417053e-01 3.2050549983978271e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 423 6.6619878634810448e-04</internalNodes>
+            0 -1 210 1.4971228083595634e-03</internalNodes>
           <leafValues>
-            -1.8005952239036560e-01 2.1171462535858154e-01</leafValues></_>
+            -8.4364958107471466e-02 4.3016371130943298e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 155 2.2130949422717094e-02</internalNodes>
+            0 -1 343 -2.6089220773428679e-03</internalNodes>
           <leafValues>
-            5.7936761528253555e-02 -5.9410941600799561e-01</leafValues></_>
+            -4.2146065831184387e-01 8.8990658521652222e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 469 1.2182788923382759e-02</internalNodes>
+            0 -1 42 -7.7147269621491432e-03</internalNodes>
           <leafValues>
-            -1.1940150707960129e-01 2.9696035385131836e-01</leafValues></_>
+            -6.6330111026763916e-01 5.0671890377998352e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 182 2.8001153841614723e-03</internalNodes>
+            0 -1 85 -1.7141735181212425e-02</internalNodes>
           <leafValues>
-            -1.4503511786460876e-01 2.2681860625743866e-01</leafValues></_>
+            -4.8750495910644531e-01 5.6981299072504044e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 945 2.8729443438351154e-03</internalNodes>
+            0 -1 146 1.3850606046617031e-02</internalNodes>
           <leafValues>
-            6.5800048410892487e-02 -4.9987852573394775e-01</leafValues></_>
+            7.4964463710784912e-02 -4.4079580903053284e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 63 -5.0598740577697754e-01</internalNodes>
+            0 -1 341 -1.4932476915419102e-03</internalNodes>
           <leafValues>
-            6.1999630928039551e-01 -5.6771270930767059e-02</leafValues></_>
+            3.1057041883468628e-01 -1.0369800031185150e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 219 -9.6983816474676132e-03</internalNodes>
+            0 -1 382 -8.3094676956534386e-03</internalNodes>
           <leafValues>
-            3.2087686657905579e-01 -9.7375035285949707e-02</leafValues></_>
+            2.2514784336090088e-01 -1.4621259272098541e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 497 3.0797901563346386e-03</internalNodes>
+            0 -1 462 -7.2969077154994011e-04</internalNodes>
           <leafValues>
-            -1.2448154389858246e-01 2.5827226042747498e-01</leafValues></_>
+            2.6934301853179932e-01 -1.2512375414371490e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 451 -1.5816848026588559e-03</internalNodes>
+            0 -1 430 -1.3652374967932701e-02</internalNodes>
           <leafValues>
-            4.1313612461090088e-01 -9.0998791158199310e-02</leafValues></_>
+            -4.9215099215507507e-01 7.3141731321811676e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 101 -9.5680113881826401e-03</internalNodes>
+            0 -1 20 9.4011947512626648e-03</internalNodes>
           <leafValues>
-            -7.0231872797012329e-01 5.5185325443744659e-02</leafValues></_>
+            4.1364993900060654e-02 -6.5001028776168823e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 94 3.1543439254164696e-03</internalNodes>
+            0 -1 657 4.0921592153608799e-03</internalNodes>
           <leafValues>
-            4.8739165067672729e-02 -5.4295998811721802e-01</leafValues></_>
+            4.0478449314832687e-02 -5.9830683469772339e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 224 -7.8436743933707476e-04</internalNodes>
+            0 -1 847 1.5591707779094577e-03</internalNodes>
           <leafValues>
-            3.0286926031112671e-01 -1.0217373818159103e-01</leafValues></_>
+            -9.3049824237823486e-02 3.1007137894630432e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 143 4.3993473052978516e-01</internalNodes>
+            0 -1 973 3.4408085048198700e-03</internalNodes>
           <leafValues>
-            -4.0746804326772690e-02 7.4451828002929688e-01</leafValues></_>
+            4.7337688505649567e-02 -6.5880972146987915e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 565 -3.5277460701763630e-03</internalNodes>
+            0 -1 847 -1.3411687687039375e-03</internalNodes>
           <leafValues>
-            -4.5241990685462952e-01 7.3149621486663818e-02</leafValues></_>
+            2.8307750821113586e-01 -1.0693576931953430e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 468 8.3879064768552780e-03</internalNodes>
+            0 -1 534 -5.7181939482688904e-03</internalNodes>
           <leafValues>
-            3.3294096589088440e-02 -7.2618806362152100e-01</leafValues></_>
+            -4.7754487395286560e-01 6.3519261777400970e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 818 9.9020544439554214e-04</internalNodes>
+            0 -1 374 -5.0096530467271805e-03</internalNodes>
           <leafValues>
-            -1.0716802626848221e-01 2.8766462206840515e-01</leafValues></_>
+            -6.1091655492782593e-01 3.9555240422487259e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 825 -2.9110300820320845e-03</internalNodes>
+            0 -1 1 -4.1508115828037262e-03</internalNodes>
           <leafValues>
-            2.8586754202842712e-01 -1.1559913307428360e-01</leafValues></_>
+            2.1694649755954742e-01 -1.3193054497241974e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 242 -5.1425592973828316e-03</internalNodes>
+            0 -1 844 -1.6968715935945511e-02</internalNodes>
           <leafValues>
-            -6.1106848716735840e-01 4.6430643647909164e-02</leafValues></_>
+            2.7644789218902588e-01 -1.0202119499444962e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 69 1.7738080024719238e-01</internalNodes>
+            0 -1 103 1.0276203043758869e-02</internalNodes>
           <leafValues>
-            -7.0887565612792969e-02 4.1917768120765686e-01</leafValues></_>
+            -9.0598084032535553e-02 2.9703584313392639e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 389 -1.1850059032440186e-02</internalNodes>
+            0 -1 350 -1.8649294506758451e-03</internalNodes>
           <leafValues>
-            3.1747487187385559e-01 -1.0234380513429642e-01</leafValues></_>
+            2.8791305422782898e-01 -9.2735975980758667e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 529 -1.0039219632744789e-02</internalNodes>
+            0 -1 942 3.3354205079376698e-03</internalNodes>
           <leafValues>
-            2.0376846194267273e-01 -1.4407536387443542e-01</leafValues></_>
+            5.3746312856674194e-02 -5.0940161943435669e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 676 1.9497467204928398e-02</internalNodes>
+            0 -1 396 -1.4105688314884901e-03</internalNodes>
           <leafValues>
-            4.7855406999588013e-02 -5.7639378309249878e-01</leafValues></_>
+            2.4489782750606537e-01 -1.1008579283952713e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 193 5.5466167628765106e-02</internalNodes>
+            0 -1 611 2.3928448557853699e-02</internalNodes>
           <leafValues>
-            -7.4624486267566681e-02 4.1103851795196533e-01</leafValues></_>
+            5.2839644253253937e-02 -4.9896511435508728e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 893 -3.9324127137660980e-03</internalNodes>
+            0 -1 807 -3.8580424152314663e-03</internalNodes>
           <leafValues>
-            -5.5429047346115112e-01 5.0012629479169846e-02</leafValues></_>
+            -4.8197838664054871e-01 5.3767576813697815e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 662 -8.9037272846326232e-04</internalNodes>
+            0 -1 679 -3.0590491369366646e-03</internalNodes>
           <leafValues>
-            2.0536813139915466e-01 -1.3225764036178589e-01</leafValues></_>
+            -5.2978992462158203e-01 4.6741079539060593e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 3 4.6562731266021729e-02</internalNodes>
+            0 -1 468 -2.9391471762210131e-03</internalNodes>
           <leafValues>
-            -9.1293826699256897e-02 2.9735872149467468e-01</leafValues></_>
+            -3.4711557626724243e-01 6.9464050233364105e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 548 -1.5474244952201843e-01</internalNodes>
+            0 -1 667 -7.0184348151087761e-03</internalNodes>
           <leafValues>
-            -8.6353981494903564e-01 3.4763321280479431e-02</leafValues></_>
+            3.1962895393371582e-01 -8.3362981677055359e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 893 2.4359119124710560e-03</internalNodes>
+            0 -1 664 1.0384586639702320e-03</internalNodes>
           <leafValues>
-            5.9721726924180984e-02 -4.1146609187126160e-01</leafValues></_>
+            -1.0797444730997086e-01 2.4896475672721863e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 402 1.3576634228229523e-02</internalNodes>
+            0 -1 628 -8.0418614670634270e-03</internalNodes>
           <leafValues>
-            -9.4201639294624329e-02 3.0719256401062012e-01</leafValues></_>
+            -7.3527222871780396e-01 3.6740459501743317e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 456 -9.8991915583610535e-03</internalNodes>
+            0 -1 193 -3.1738542020320892e-02</internalNodes>
           <leafValues>
-            2.6257899403572083e-01 -9.5683693885803223e-02</leafValues></_>
+            2.6166516542434692e-01 -1.0992183536291122e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 479 -3.0812243930995464e-03</internalNodes>
+            0 -1 194 3.6780342459678650e-02</internalNodes>
           <leafValues>
-            2.1774919331073761e-01 -1.1509665846824646e-01</leafValues></_>
+            -8.7741106748580933e-02 3.7106978893280029e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 275 -1.9958070479333401e-03</internalNodes>
+            0 -1 494 -6.4193591475486755e-02</internalNodes>
           <leafValues>
-            3.5399836301803589e-01 -7.2066798806190491e-02</leafValues></_>
+            3.1807181239128113e-01 -8.8648937642574310e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 919 3.0025159940123558e-03</internalNodes>
+            0 -1 46 3.4801474213600159e-01</internalNodes>
           <leafValues>
-            4.2854189872741699e-02 -6.0343819856643677e-01</leafValues></_>
+            -5.5967021733522415e-02 5.3631168603897095e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 836 -1.1377423070371151e-03</internalNodes>
+            0 -1 490 7.5712919235229492e-02</internalNodes>
           <leafValues>
-            2.0119668543338776e-01 -1.2889184057712555e-01</leafValues></_>
+            -5.9786085039377213e-02 4.1973164677619934e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 661 3.7626659031957388e-03</internalNodes>
+            0 -1 983 7.8374873846769333e-03</internalNodes>
           <leafValues>
-            4.6901285648345947e-02 -5.7279956340789795e-01</leafValues></_>
+            -6.8252839148044586e-02 3.9001336693763733e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 724 -3.9297584444284439e-03</internalNodes>
+            0 -1 867 3.3967243507504463e-03</internalNodes>
           <leafValues>
-            3.5875543951988220e-01 -7.3908790946006775e-02</leafValues></_>
+            5.7270396500825882e-02 -4.7492286562919617e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 885 -2.5286607444286346e-02</internalNodes>
+            0 -1 158 3.2095968723297119e-02</internalNodes>
           <leafValues>
-            3.5751584172248840e-01 -6.7418299615383148e-02</leafValues></_>
+            3.0982470139861107e-02 -7.2973543405532837e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 749 -3.9539579302072525e-03</internalNodes>
+            0 -1 939 4.1734268888831139e-03</internalNodes>
           <leafValues>
-            2.0609807968139648e-01 -1.4521332085132599e-01</leafValues></_>
+            3.0397623777389526e-02 -6.8009066581726074e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 911 -5.7711899280548096e-03</internalNodes>
+            0 -1 545 3.2336891163140535e-03</internalNodes>
           <leafValues>
-            -5.2898341417312622e-01 4.7179169952869415e-02</leafValues></_>
+            -9.4194613397121429e-02 2.5351443886756897e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 701 -3.3264106605201960e-03</internalNodes>
+            0 -1 55 -3.8070861250162125e-02</internalNodes>
           <leafValues>
-            2.2409056127071381e-01 -1.1467082053422928e-01</leafValues></_>
+            2.7447724342346191e-01 -8.3862110972404480e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 703 6.1332453042268753e-02</internalNodes>
+            0 -1 358 4.6657784841954708e-03</internalNodes>
           <leafValues>
-            3.7662509828805923e-02 -7.1230965852737427e-01</leafValues></_>
+            3.7179920822381973e-02 -6.7654901742935181e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 251 -1.4834193512797356e-02</internalNodes>
+            0 -1 247 -3.9379103109240532e-03</internalNodes>
           <leafValues>
-            -5.5149120092391968e-01 3.9850924164056778e-02</leafValues></_>
+            -5.9923279285430908e-01 3.2963614910840988e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 7 -1.0773484408855438e-01</internalNodes>
+            0 -1 699 -4.8031057231128216e-03</internalNodes>
           <leafValues>
-            -4.9263399839401245e-01 4.9221854656934738e-02</leafValues></_>
+            2.2248022258281708e-01 -1.0560184717178345e-01</leafValues></_></weakClassifiers></_>
+    <!-- stage 9 -->
+    <_>
+      <maxWeakCount>55</maxWeakCount>
+      <stageThreshold>-1.3843152523040771e+00</stageThreshold>
+      <weakClassifiers>
         <_>
           <internalNodes>
-            0 -1 648 -6.5140398219227791e-03</internalNodes>
+            0 -1 456 6.7532630637288094e-03</internalNodes>
           <leafValues>
-            -6.7663580179214478e-01 3.3736269921064377e-02</leafValues></_>
+            -1.5934121608734131e-01 5.1630091667175293e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 30 -2.4242542684078217e-02</internalNodes>
+            0 -1 685 1.6582473181188107e-03</internalNodes>
           <leafValues>
-            -6.9796782732009888e-01 2.7110328897833824e-02</leafValues></_>
+            -1.4192129671573639e-01 4.6970281004905701e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 393 -1.7814380116760731e-03</internalNodes>
+            0 -1 741 8.5381623357534409e-03</internalNodes>
           <leafValues>
-            2.9062062501907349e-01 -8.0135107040405273e-02</leafValues></_>
+            -1.4064009487628937e-01 4.3454051017761230e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 801 4.7076190821826458e-03</internalNodes>
+            0 -1 711 -5.8347072452306747e-02</internalNodes>
           <leafValues>
-            3.7101462483406067e-02 -6.7659527063369751e-01</leafValues></_></weakClassifiers></_>
-    <!-- stage 7 -->
-    <_>
-      <maxWeakCount>80</maxWeakCount>
-      <stageThreshold>-1.5639265775680542e+00</stageThreshold>
-      <weakClassifiers>
+            4.8053690791130066e-01 -1.1435888707637787e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 561 -4.3974462896585464e-03</internalNodes>
+            0 -1 200 7.5503322295844555e-04</internalNodes>
           <leafValues>
-            7.1587848663330078e-01 8.4948554635047913e-02</leafValues></_>
+            -1.6613751649856567e-01 3.5059270262718201e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 198 1.8174322322010994e-03</internalNodes>
+            0 -1 463 -1.6263198340311646e-03</internalNodes>
           <leafValues>
-            -1.7691791057586670e-01 4.3212845921516418e-01</leafValues></_>
+            3.3983412384986877e-01 -1.2952369451522827e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 735 -5.5131856352090836e-03</internalNodes>
+            0 -1 982 -4.9476943910121918e-02</internalNodes>
           <leafValues>
-            4.5490756630897522e-01 -1.4189453423023224e-01</leafValues></_>
+            5.1085108518600464e-01 -7.6757252216339111e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 282 1.1955455876886845e-02</internalNodes>
+            0 -1 148 1.5736839268356562e-03</internalNodes>
           <leafValues>
-            -2.0918996632099152e-01 4.3714949488639832e-01</leafValues></_>
+            -9.8503805696964264e-02 4.2097148299217224e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 819 -3.4246121067553759e-03</internalNodes>
+            0 -1 970 2.8940830379724503e-03</internalNodes>
           <leafValues>
-            3.5878163576126099e-01 -1.5395726263523102e-01</leafValues></_>
+            8.0476768314838409e-02 -5.9272909164428711e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 187 -4.3844994157552719e-02</internalNodes>
+            0 -1 470 -8.5198890883475542e-04</internalNodes>
           <leafValues>
-            4.3700152635574341e-01 -1.2767519056797028e-01</leafValues></_>
+            2.7713751792907715e-01 -1.2991340458393097e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 839 -6.3555962406098843e-03</internalNodes>
+            0 -1 513 -3.2718123402446508e-03</internalNodes>
           <leafValues>
-            2.9515129327774048e-01 -1.6441816091537476e-01</leafValues></_>
+            3.1215441226959229e-01 -1.2980756163597107e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 534 -2.6965860743075609e-03</internalNodes>
+            0 -1 244 6.0219354927539825e-03</internalNodes>
           <leafValues>
-            1.9414065778255463e-01 -2.0237676799297333e-01</leafValues></_>
+            7.2135269641876221e-02 -5.9813290834426880e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 460 -1.3908351771533489e-02</internalNodes>
+            0 -1 81 2.3065296933054924e-02</internalNodes>
           <leafValues>
-            2.5903883576393127e-01 -1.5587335824966431e-01</leafValues></_>
+            7.1330830454826355e-02 -5.3722465038299561e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 343 -1.4053133316338062e-02</internalNodes>
+            0 -1 187 2.7176631192560308e-05</internalNodes>
           <leafValues>
-            5.4957073926925659e-01 -8.1244736909866333e-02</leafValues></_>
+            -2.6853099465370178e-01 1.4315985143184662e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 918 -5.3004794754087925e-03</internalNodes>
+            0 -1 401 5.4575498215854168e-03</internalNodes>
           <leafValues>
-            -5.8528614044189453e-01 7.3730856180191040e-02</leafValues></_>
+            5.5034745484590530e-02 -5.7176333665847778e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 491 -3.1702318228781223e-03</internalNodes>
+            0 -1 391 2.5911496777553111e-05</internalNodes>
           <leafValues>
-            1.9391658902168274e-01 -1.8859483301639557e-01</leafValues></_>
+            -2.3133303225040436e-01 1.4060766994953156e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 474 -4.5197797007858753e-03</internalNodes>
+            0 -1 12 2.1752633154392242e-02</internalNodes>
           <leafValues>
-            -5.4193162918090820e-01 5.9990171343088150e-02</leafValues></_>
+            5.9929180890321732e-02 -5.0224888324737549e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 956 -5.4979130625724792e-02</internalNodes>
+            0 -1 860 3.5099866800010204e-03</internalNodes>
           <leafValues>
-            4.7812277078628540e-01 -6.7818723618984222e-02</leafValues></_>
+            4.7387380152940750e-02 -5.8126205205917358e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 876 8.1017805496230721e-04</internalNodes>
+            0 -1 755 8.6558861657977104e-03</internalNodes>
           <leafValues>
-            -9.5595575869083405e-02 3.1569144129753113e-01</leafValues></_>
+            -1.3651072978973389e-01 2.2407715022563934e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 841 -2.8012446127831936e-03</internalNodes>
+            0 -1 990 3.0432851053774357e-03</internalNodes>
           <leafValues>
-            -4.9929830431938171e-01 6.8443782627582550e-02</leafValues></_>
+            5.7905938476324081e-02 -5.5585581064224243e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 833 -6.0123754665255547e-03</internalNodes>
+            0 -1 240 3.4083288628607988e-03</internalNodes>
           <leafValues>
-            3.8719713687896729e-01 -8.9717194437980652e-02</leafValues></_>
+            4.6358574181795120e-02 -5.6204903125762939e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 842 3.6350139416754246e-03</internalNodes>
+            0 -1 241 -4.1327420622110367e-03</internalNodes>
           <leafValues>
-            6.6413506865501404e-02 -4.8185935616493225e-01</leafValues></_>
+            -4.3748503923416138e-01 6.6312022507190704e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 452 -1.3544321991503239e-03</internalNodes>
+            0 -1 887 5.4382300004363060e-04</internalNodes>
           <leafValues>
-            2.5372084975242615e-01 -1.2267075479030609e-01</leafValues></_>
+            -1.2188895046710968e-01 2.6694831252098083e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 827 -3.1020103488117456e-03</internalNodes>
+            0 -1 886 2.0359107293188572e-03</internalNodes>
           <leafValues>
-            2.7389132976531982e-01 -1.1379010230302811e-01</leafValues></_>
+            -6.9375663995742798e-02 4.1734528541564941e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 767 1.5349574387073517e-03</internalNodes>
+            0 -1 894 5.6087510893121362e-04</internalNodes>
           <leafValues>
-            -1.0861707478761673e-01 2.8958576917648315e-01</leafValues></_>
+            -1.2235503643751144e-01 2.9018589854240417e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 170 6.4284317195415497e-03</internalNodes>
+            0 -1 957 5.4084453731775284e-03</internalNodes>
           <leafValues>
-            5.9735804796218872e-02 -5.6773471832275391e-01</leafValues></_>
+            5.1494579762220383e-02 -6.3784217834472656e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 280 -8.9295972138643265e-03</internalNodes>
+            0 -1 99 1.9748538732528687e-02</internalNodes>
           <leafValues>
-            -6.7040807008743286e-01 3.8283705711364746e-02</leafValues></_>
+            -7.0414997637271881e-02 4.8995351791381836e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 764 -1.7896143253892660e-03</internalNodes>
+            0 -1 147 -2.0231239497661591e-02</internalNodes>
           <leafValues>
-            2.1716582775115967e-01 -1.4856858551502228e-01</leafValues></_>
+            -5.9452813863754272e-01 5.5317912250757217e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 523 6.2072295695543289e-03</internalNodes>
+            0 -1 763 -8.5184378549456596e-03</internalNodes>
           <leafValues>
-            -8.8489770889282227e-02 3.3571973443031311e-01</leafValues></_>
+            -4.9081006646156311e-01 5.1023125648498535e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 526 1.9034199649468064e-03</internalNodes>
+            0 -1 952 6.4936149865388870e-03</internalNodes>
           <leafValues>
-            6.7696519196033478e-02 -4.5386880636215210e-01</leafValues></_>
+            -8.6577519774436951e-02 3.6036944389343262e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 524 -2.1953256800770760e-03</internalNodes>
+            0 -1 30 -4.0995404124259949e-02</internalNodes>
           <leafValues>
-            -4.2716285586357117e-01 6.5683454275131226e-02</leafValues></_>
+            4.0132537484169006e-01 -7.1912504732608795e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 215 5.3394897840917110e-03</internalNodes>
+            0 -1 501 3.1340471468865871e-03</internalNodes>
           <leafValues>
-            -1.0160661488771439e-01 2.9586192965507507e-01</leafValues></_>
+            -1.2547470629215240e-01 2.2158138453960419e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 763 2.0328685641288757e-03</internalNodes>
+            0 -1 184 -1.9882351160049438e-02</internalNodes>
           <leafValues>
-            -9.5586851239204407e-02 3.0505907535552979e-01</leafValues></_>
+            -7.1213179826736450e-01 4.2412471026182175e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 160 4.3488927185535431e-03</internalNodes>
+            0 -1 559 2.0461969077587128e-02</internalNodes>
           <leafValues>
-            7.9764112830162048e-02 -3.8651520013809204e-01</leafValues></_>
+            -1.0324169695377350e-01 2.9102885723114014e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 518 -4.0209172293543816e-03</internalNodes>
+            0 -1 686 -1.2761610560119152e-03</internalNodes>
           <leafValues>
-            3.0502754449844360e-01 -8.9127995073795319e-02</leafValues></_>
+            2.3810100555419922e-01 -1.1509060114622116e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 234 -4.8844739794731140e-02</internalNodes>
+            0 -1 549 -3.3783772960305214e-03</internalNodes>
           <leafValues>
-            4.2813199758529663e-01 -6.7647248506546021e-02</leafValues></_>
+            -5.6838840246200562e-01 5.6331343948841095e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 360 6.9915860891342163e-02</internalNodes>
+            0 -1 302 5.0912564620375633e-03</internalNodes>
           <leafValues>
-            -8.3985306322574615e-02 3.2602414488792419e-01</leafValues></_>
+            4.7987211495637894e-02 -4.7997272014617920e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 535 4.9919363111257553e-02</internalNodes>
+            0 -1 508 -4.1752815246582031e-02</internalNodes>
           <leafValues>
-            -7.2998367249965668e-02 4.6169292926788330e-01</leafValues></_>
+            -5.9290748834609985e-01 4.2219188064336777e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 606 3.0068659689277411e-03</internalNodes>
+            0 -1 263 -1.3672109693288803e-02</internalNodes>
           <leafValues>
-            5.5069219321012497e-02 -6.1965858936309814e-01</leafValues></_>
+            2.7416154742240906e-01 -9.8633147776126862e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 158 1.7419853247702122e-03</internalNodes>
+            0 -1 329 4.5463615097105503e-03</internalNodes>
           <leafValues>
-            -8.2020215690135956e-02 3.6006987094879150e-01</leafValues></_>
+            -9.5323033630847931e-02 3.3586710691452026e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 168 -4.1090780869126320e-03</internalNodes>
+            0 -1 472 -1.1957241222262383e-02</internalNodes>
           <leafValues>
-            -5.2174150943756104e-01 5.6436747312545776e-02</leafValues></_>
+            1.6140049695968628e-01 -1.6837921738624573e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 665 -4.5902859419584274e-03</internalNodes>
+            0 -1 95 -2.4866103194653988e-03</internalNodes>
           <leafValues>
-            2.2742575407028198e-01 -1.2061754614114761e-01</leafValues></_>
+            -3.8348227739334106e-01 6.6880211234092712e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 27 -2.8690489009022713e-02</internalNodes>
+            0 -1 130 3.3222150523215532e-03</internalNodes>
           <leafValues>
-            -3.5808193683624268e-01 7.5659923255443573e-02</leafValues></_>
+            4.9669362604618073e-02 -5.2419567108154297e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 926 4.1000463068485260e-02</internalNodes>
+            0 -1 767 1.2700627557933331e-03</internalNodes>
           <leafValues>
-            -6.2531292438507080e-02 4.5491513609886169e-01</leafValues></_>
+            -1.0981336981058121e-01 2.4314954876899719e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 126 -4.2531453073024750e-03</internalNodes>
+            0 -1 643 -4.0526064112782478e-03</internalNodes>
           <leafValues>
-            -6.1825770139694214e-01 4.9510892480611801e-02</leafValues></_>
+            -5.4617625474929810e-01 4.6236973255872726e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 670 -1.4550488442182541e-02</internalNodes>
+            0 -1 889 -1.7611857037991285e-03</internalNodes>
           <leafValues>
-            -7.7191162109375000e-01 2.5961024686694145e-02</leafValues></_>
+            2.0527404546737671e-01 -1.1924317479133606e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 288 -7.4881664477288723e-04</internalNodes>
+            0 -1 832 -2.8845192864537239e-03</internalNodes>
           <leafValues>
-            2.8547286987304688e-01 -8.8079601526260376e-02</leafValues></_>
+            2.0061042904853821e-01 -1.4499643445014954e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 337 1.3214498758316040e-03</internalNodes>
+            0 -1 969 -9.4242449849843979e-03</internalNodes>
           <leafValues>
-            -7.6633729040622711e-02 3.7057441473007202e-01</leafValues></_>
+            -7.2513866424560547e-01 3.4894362092018127e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 455 5.3907292895019054e-03</internalNodes>
+            0 -1 972 3.7029895465821028e-03</internalNodes>
           <leafValues>
-            4.9379035830497742e-02 -5.7583230733871460e-01</leafValues></_>
+            5.5003125220537186e-02 -4.1173446178436279e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 838 -2.4113813415169716e-03</internalNodes>
+            0 -1 785 -8.4825151134282351e-04</internalNodes>
           <leafValues>
-            2.0829583704471588e-01 -1.3430447876453400e-01</leafValues></_>
+            2.6719486713409424e-01 -9.9083028733730316e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 87 1.1464932933449745e-02</internalNodes>
+            0 -1 54 1.5727356076240540e-02</internalNodes>
           <leafValues>
-            4.9434442073106766e-02 -6.5971946716308594e-01</leafValues></_>
+            -1.2551975250244141e-01 2.0588764548301697e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 486 -1.3421529904007912e-02</internalNodes>
+            0 -1 106 5.9068910777568817e-03</internalNodes>
           <leafValues>
-            -7.4524301290512085e-01 2.5121277198195457e-02</leafValues></_>
+            6.0179408639669418e-02 -4.1827461123466492e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 910 2.8626890853047371e-03</internalNodes>
+            0 -1 27 -3.9538964629173279e-02</internalNodes>
           <leafValues>
-            6.1505425721406937e-02 -3.5306212306022644e-01</leafValues></_>
+            3.4726879000663757e-01 -7.4968926608562469e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 416 1.1442219838500023e-02</internalNodes>
+            0 -1 10 4.7501657158136368e-02</internalNodes>
           <leafValues>
-            5.3547207266092300e-02 -4.0409806370735168e-01</leafValues></_>
+            -7.6978117227554321e-02 3.5068345069885254e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 538 5.7390062138438225e-03</internalNodes>
+            0 -1 259 -5.9454172151163220e-04</internalNodes>
           <leafValues>
-            -9.7106143832206726e-02 2.4726873636245728e-01</leafValues></_>
+            1.6073931753635406e-01 -1.5279982984066010e-01</leafValues></_></weakClassifiers></_>
+    <!-- stage 10 -->
+    <_>
+      <maxWeakCount>58</maxWeakCount>
+      <stageThreshold>-1.2862224578857422e+00</stageThreshold>
+      <weakClassifiers>
         <_>
           <internalNodes>
-            0 -1 485 -1.3369014486670494e-02</internalNodes>
+            0 -1 882 -1.3625519350171089e-02</internalNodes>
           <leafValues>
-            3.4151887893676758e-01 -9.5434606075286865e-02</leafValues></_>
+            5.0128185749053955e-01 -1.1663150042295456e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 611 3.3499381970614195e-03</internalNodes>
+            0 -1 375 -2.2920668125152588e-03</internalNodes>
           <leafValues>
-            4.9335762858390808e-02 -4.9601793289184570e-01</leafValues></_>
+            3.9538189768791199e-01 -1.3872602581977844e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 281 1.2374855577945709e-02</internalNodes>
+            0 -1 792 1.0770710650831461e-03</internalNodes>
           <leafValues>
-            -5.7205036282539368e-02 5.0581747293472290e-01</leafValues></_>
+            -1.7133137583732605e-01 3.1510788202285767e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 500 2.7577474713325500e-02</internalNodes>
+            0 -1 452 -1.2591466307640076e-02</internalNodes>
           <leafValues>
-            -8.7777808308601379e-02 2.9972809553146362e-01</leafValues></_>
+            3.9579889178276062e-01 -1.4279782772064209e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 43 2.1137124300003052e-01</internalNodes>
+            0 -1 460 -4.7927081584930420e-02</internalNodes>
           <leafValues>
-            -6.2023047357797623e-02 4.0350961685180664e-01</leafValues></_>
+            -4.9305588006973267e-01 5.6685980409383774e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 221 -3.5103857517242432e-02</internalNodes>
+            0 -1 474 -2.5895023718476295e-03</internalNodes>
           <leafValues>
-            2.9696103930473328e-01 -8.2776337862014771e-02</leafValues></_>
+            1.6586430370807648e-01 -2.2577352821826935e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 292 -2.8949903789907694e-03</internalNodes>
+            0 -1 112 9.8585948348045349e-02</internalNodes>
           <leafValues>
-            -3.7250569462776184e-01 6.6616289317607880e-02</leafValues></_>
+            -7.2541341185569763e-02 5.3971153497695923e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 511 3.6181407049298286e-03</internalNodes>
+            0 -1 521 7.2299325838685036e-03</internalNodes>
           <leafValues>
-            -9.3407385051250458e-02 2.5402054190635681e-01</leafValues></_>
+            7.2869211435317993e-02 -6.0541796684265137e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 445 1.1848636902868748e-02</internalNodes>
+            0 -1 202 -6.0262705665081739e-04</internalNodes>
           <leafValues>
-            -8.2135058939456940e-02 2.9939675331115723e-01</leafValues></_>
+            2.7961328625679016e-01 -1.3374039530754089e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 438 -1.0207802988588810e-02</internalNodes>
+            0 -1 253 5.3171166218817234e-03</internalNodes>
           <leafValues>
-            2.1719035506248474e-01 -1.1622364073991776e-01</leafValues></_>
+            6.1562143266201019e-02 -5.3435516357421875e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 257 3.0942540615797043e-02</internalNodes>
+            0 -1 109 -7.3790093883872032e-03</internalNodes>
           <leafValues>
-            4.5177377760410309e-02 -5.0523322820663452e-01</leafValues></_>
+            -5.8770626783370972e-01 5.2599798887968063e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 16 -3.1778869032859802e-01</internalNodes>
+            0 -1 179 2.2994203027337790e-04</internalNodes>
           <leafValues>
-            -8.8358139991760254e-01 2.1195204928517342e-02</leafValues></_>
+            -2.2165967524051666e-01 1.6663813591003418e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 513 -1.0037058964371681e-02</internalNodes>
+            0 -1 366 -2.7968082576990128e-03</internalNodes>
           <leafValues>
-            -5.8986192941665649e-01 3.0863022431731224e-02</leafValues></_>
+            -4.5023602247238159e-01 6.7983791232109070e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 888 9.1691948473453522e-03</internalNodes>
+            0 -1 949 -4.4262632727622986e-03</internalNodes>
           <leafValues>
-            -6.4322948455810547e-02 3.7386918067932129e-01</leafValues></_>
+            -5.4457426071166992e-01 5.3928002715110779e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 658 1.3658402487635612e-02</internalNodes>
+            0 -1 431 -6.1236601322889328e-03</internalNodes>
           <leafValues>
-            -1.0158041864633560e-01 2.6782375574111938e-01</leafValues></_>
+            2.9386061429977417e-01 -1.0868654400110245e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 309 2.7183804195374250e-03</internalNodes>
+            0 -1 364 6.1672870069742203e-03</internalNodes>
           <leafValues>
-            5.5635135620832443e-02 -3.9148023724555969e-01</leafValues></_>
+            6.7409984767436981e-02 -4.2896196246147156e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 310 1.3893332798033953e-03</internalNodes>
+            0 -1 335 1.5454929322004318e-02</internalNodes>
           <leafValues>
-            -1.2399668246507645e-01 1.7072468996047974e-01</leafValues></_>
+            -9.3371987342834473e-02 3.2237896323204041e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 283 -1.8156928941607475e-02</internalNodes>
+            0 -1 285 -5.5358107201755047e-03</internalNodes>
           <leafValues>
-            -6.3868224620819092e-01 3.4263785928487778e-02</leafValues></_>
+            -6.3797932863235474e-01 4.7232467681169510e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 408 6.4471308141946793e-03</internalNodes>
+            0 -1 210 -5.8793288189917803e-04</internalNodes>
           <leafValues>
-            1.8927905708551407e-02 -8.5299736261367798e-01</leafValues></_>
+            2.6480975747108459e-01 -1.1852940917015076e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 44 1.4844031073153019e-02</internalNodes>
+            0 -1 203 1.2575921136885881e-03</internalNodes>
           <leafValues>
-            -1.2482391297817230e-01 1.7663741111755371e-01</leafValues></_>
+            -1.2490244954824448e-01 2.8103300929069519e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 50 -1.9531816244125366e-02</internalNodes>
+            0 -1 41 3.3034523949027061e-03</internalNodes>
           <leafValues>
-            3.1519362330436707e-01 -8.2499116659164429e-02</leafValues></_>
+            6.2105692923069000e-02 -4.5968556404113770e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 90 2.2133110091090202e-02</internalNodes>
+            0 -1 45 -2.6582641527056694e-02</internalNodes>
           <leafValues>
-            -9.0632885694503784e-02 2.2813312709331512e-01</leafValues></_>
+            -5.0849837064743042e-01 5.3966015577316284e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 119 -5.8851181529462337e-03</internalNodes>
+            0 -1 49 2.7427850291132927e-02</internalNodes>
           <leafValues>
-            2.0633347332477570e-01 -1.1403661221265793e-01</leafValues></_>
+            5.2529457956552505e-02 -5.3614085912704468e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 773 1.4685674104839563e-03</internalNodes>
+            0 -1 39 -2.1938718855381012e-03</internalNodes>
           <leafValues>
-            -6.8528242409229279e-02 3.6765024065971375e-01</leafValues></_>
+            -5.6713318824768066e-01 4.6497207134962082e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 856 -5.6167589500546455e-03</internalNodes>
+            0 -1 926 8.5861550178378820e-04</internalNodes>
           <leafValues>
-            2.1468248963356018e-01 -1.1975194513797760e-01</leafValues></_>
+            -1.1162154376506805e-01 2.8105884790420532e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 530 -1.0915055871009827e-01</internalNodes>
+            0 -1 886 -8.4925384726375341e-04</internalNodes>
           <leafValues>
-            4.9222618341445923e-01 -4.6790093183517456e-02</leafValues></_>
+            3.1280112266540527e-01 -1.2138028442859650e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 638 -4.3774135410785675e-03</internalNodes>
+            0 -1 956 2.9905270785093307e-03</internalNodes>
           <leafValues>
-            2.6555654406547546e-01 -8.1355758011341095e-02</leafValues></_>
+            6.1607286334037781e-02 -5.1581907272338867e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 97 -5.5184490047395229e-03</internalNodes>
+            0 -1 968 5.8231391012668610e-03</internalNodes>
           <leafValues>
-            -4.7854590415954590e-01 4.9387764185667038e-02</leafValues></_>
+            4.7376025468111038e-02 -5.1492005586624146e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 646 -1.8072805833071470e-03</internalNodes>
+            0 -1 480 4.2811138555407524e-03</internalNodes>
           <leafValues>
-            -6.4401823282241821e-01 3.1085403636097908e-02</leafValues></_></weakClassifiers></_>
-    <!-- stage 8 -->
-    <_>
-      <maxWeakCount>91</maxWeakCount>
-      <stageThreshold>-1.5610778331756592e+00</stageThreshold>
-      <weakClassifiers>
+            3.2761037349700928e-02 -6.7820072174072266e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 821 -1.1308195069432259e-02</internalNodes>
+            0 -1 915 9.5272483304142952e-04</internalNodes>
           <leafValues>
-            6.4171379804611206e-01 6.3050843775272369e-02</leafValues></_>
+            -1.5452747046947479e-01 1.7837351560592651e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 454 -1.6007030382752419e-02</internalNodes>
+            0 -1 270 -2.7698231860995293e-04</internalNodes>
           <leafValues>
-            4.6389564871788025e-01 -1.2460056692361832e-01</leafValues></_>
+            1.8924367427825928e-01 -1.3868112862110138e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 782 1.5086517669260502e-03</internalNodes>
+            0 -1 370 3.0586202628910542e-03</internalNodes>
           <leafValues>
-            -1.4270767569541931e-01 3.3293032646179199e-01</leafValues></_>
+            5.3298473358154297e-02 -4.7908756136894226e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 207 -5.5297352373600006e-02</internalNodes>
+            0 -1 639 2.0293965935707092e-03</internalNodes>
           <leafValues>
-            4.7708284854888916e-01 -1.1913372576236725e-01</leafValues></_>
+            3.1667634844779968e-02 -6.7199909687042236e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 209 1.3316229917109013e-02</internalNodes>
+            0 -1 639 -1.8073513638228178e-03</internalNodes>
           <leafValues>
-            -1.6993317008018494e-01 3.8821667432785034e-01</leafValues></_>
+            -6.4894622564315796e-01 3.3469315618276596e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 752 8.1390906125307083e-03</internalNodes>
+            0 -1 320 -1.1197938583791256e-03</internalNodes>
           <leafValues>
-            -1.5329377353191376e-01 2.8196957707405090e-01</leafValues></_>
+            2.2734998166561127e-01 -1.1382233351469040e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 313 -1.5794128412380815e-03</internalNodes>
+            0 -1 828 1.2703117681667209e-03</internalNodes>
           <leafValues>
-            -4.3692907691001892e-01 1.1585860699415207e-01</leafValues></_>
+            -9.7680233418941498e-02 2.9997348785400391e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 346 -7.4164522811770439e-03</internalNodes>
+            0 -1 835 -1.8036495894193649e-03</internalNodes>
           <leafValues>
-            -7.0102095603942871e-01 3.1883224844932556e-02</leafValues></_>
+            2.3566392064094543e-01 -1.1566326767206192e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 347 2.9237023554742336e-03</internalNodes>
+            0 -1 222 2.3318463936448097e-03</internalNodes>
           <leafValues>
-            -1.2032959610223770e-01 3.1826072931289673e-01</leafValues></_>
+            5.5787801742553711e-02 -4.4648987054824829e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 412 8.3931483328342438e-02</internalNodes>
+            0 -1 111 1.8485619220882654e-03</internalNodes>
           <leafValues>
-            -7.1062639355659485e-02 5.1401311159133911e-01</leafValues></_>
+            -1.0420991480350494e-01 2.4521166086196899e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 879 5.1326253451406956e-03</internalNodes>
+            0 -1 101 8.2633290439844131e-03</internalNodes>
           <leafValues>
-            -1.5315851569175720e-01 2.3686404526233673e-01</leafValues></_>
+            5.3129263222217560e-02 -4.8460647463798523e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 10 1.2808490544557571e-02</internalNodes>
+            0 -1 760 2.7392050469643436e-05</internalNodes>
           <leafValues>
-            -1.2817305326461792e-01 2.8131189942359924e-01</leafValues></_>
+            -1.7487643659114838e-01 1.3620604574680328e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 327 5.5591724812984467e-02</internalNodes>
+            0 -1 352 2.6163433212786913e-03</internalNodes>
           <leafValues>
-            -9.7707554697990417e-02 3.7602767348289490e-01</leafValues></_>
+            -9.9586494266986847e-02 2.4075058102607727e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 650 -2.4632480926811695e-03</internalNodes>
+            0 -1 94 3.6149267107248306e-03</internalNodes>
           <leafValues>
-            -5.5093276500701904e-01 6.5490268170833588e-02</leafValues></_>
+            4.2312353849411011e-02 -5.5195075273513794e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 661 -3.1798938289284706e-03</internalNodes>
+            0 -1 403 1.4812931418418884e-02</internalNodes>
           <leafValues>
-            -5.6288594007492065e-01 5.3227964788675308e-02</leafValues></_>
+            -6.7619144916534424e-02 3.7573158740997314e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 652 -1.4345918316394091e-03</internalNodes>
+            0 -1 814 -2.8877586591988802e-03</internalNodes>
           <leafValues>
-            -5.1232701539993286e-01 5.7506360113620758e-02</leafValues></_>
+            -5.3493702411651611e-01 5.1065266132354736e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 861 1.9692238420248032e-03</internalNodes>
+            0 -1 930 3.5591312916949391e-04</internalNodes>
           <leafValues>
-            -1.6736923158168793e-01 1.8856795132160187e-01</leafValues></_>
+            -1.2231220304965973e-01 1.9974029064178467e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 261 -5.5519137531518936e-03</internalNodes>
+            0 -1 36 -1.0347569361329079e-02</internalNodes>
           <leafValues>
-            -5.2823477983474731e-01 5.2204202860593796e-02</leafValues></_>
+            -6.3408315181732178e-01 4.0167611092329025e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 342 3.1600738875567913e-03</internalNodes>
+            0 -1 34 -4.4028884731233120e-03</internalNodes>
           <leafValues>
-            -8.0669216811656952e-02 3.6808264255523682e-01</leafValues></_>
+            -5.1359844207763672e-01 4.3052427470684052e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 144 7.3207332752645016e-03</internalNodes>
+            0 -1 856 -1.6173283802345395e-03</internalNodes>
           <leafValues>
-            5.4134551435709000e-02 -5.3350186347961426e-01</leafValues></_>
+            1.4859439432621002e-01 -1.4985026419162750e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 303 3.5804554354399443e-03</internalNodes>
+            0 -1 996 -3.1839800067245960e-03</internalNodes>
           <leafValues>
-            4.3425790965557098e-02 -5.3225243091583252e-01</leafValues></_>
+            -4.1493499279022217e-01 6.0393124818801880e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 368 -3.4314931835979223e-03</internalNodes>
+            0 -1 960 -7.9784039407968521e-03</internalNodes>
           <leafValues>
-            3.3590000867843628e-01 -7.8590616583824158e-02</leafValues></_>
+            2.8296649456024170e-01 -8.6312569677829742e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 958 6.8407682701945305e-03</internalNodes>
+            0 -1 797 2.8750954661518335e-03</internalNodes>
           <leafValues>
-            4.5175880193710327e-02 -6.1210322380065918e-01</leafValues></_>
+            -6.7822508513927460e-02 3.2967612147331238e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 957 -4.1379006579518318e-03</internalNodes>
+            0 -1 992 -1.1433581821620464e-03</internalNodes>
           <leafValues>
-            -5.3888756036758423e-01 4.4202055782079697e-02</leafValues></_>
+            -3.4375748038291931e-01 6.8774074316024780e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 350 1.3155659660696983e-02</internalNodes>
+            0 -1 668 1.7783213406801224e-03</internalNodes>
           <leafValues>
-            -7.9103693366050720e-02 3.3573821187019348e-01</leafValues></_>
+            -8.8273152709007263e-02 2.6904863119125366e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 356 3.1921269837766886e-03</internalNodes>
+            0 -1 670 -6.3564153388142586e-03</internalNodes>
           <leafValues>
-            5.7063572108745575e-02 -5.0549602508544922e-01</leafValues></_>
+            3.4165042638778687e-01 -7.6342806220054626e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 906 2.3588772863149643e-02</internalNodes>
+            0 -1 712 5.8753319084644318e-02</internalNodes>
           <leafValues>
-            -8.3102487027645111e-02 3.0777907371520996e-01</leafValues></_>
+            3.6884155124425888e-02 -7.0002478361129761e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 464 -6.1599123291671276e-03</internalNodes>
+            0 -1 345 -1.2118986342102289e-03</internalNodes>
           <leafValues>
-            1.6074487566947937e-01 -1.5700389444828033e-01</leafValues></_>
+            1.8067996203899384e-01 -1.2888990342617035e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 830 6.4594233408570290e-03</internalNodes>
+            0 -1 268 -3.4786794334650040e-02</internalNodes>
           <leafValues>
-            -9.5241472125053406e-02 3.0516397953033447e-01</leafValues></_>
+            2.8380703926086426e-01 -1.0494612902402878e-01</leafValues></_></weakClassifiers></_>
+    <!-- stage 11 -->
+    <_>
+      <maxWeakCount>61</maxWeakCount>
+      <stageThreshold>-1.3526766300201416e+00</stageThreshold>
+      <weakClassifiers>
         <_>
           <internalNodes>
-            0 -1 581 -2.0677673164755106e-03</internalNodes>
+            0 -1 875 9.3241240829229355e-03</internalNodes>
           <leafValues>
-            -5.0822901725769043e-01 5.9834387153387070e-02</leafValues></_>
+            -1.1945860832929611e-01 4.8265087604522705e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 872 2.0666117779910564e-03</internalNodes>
+            0 -1 573 -4.0869116783142090e-03</internalNodes>
           <leafValues>
-            -7.2401538491249084e-02 3.5851547122001648e-01</leafValues></_>
+            2.7903670072555542e-01 -2.3448269069194794e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 231 5.3266487084329128e-03</internalNodes>
+            0 -1 676 8.3140000700950623e-02</internalNodes>
           <leafValues>
-            5.4928623139858246e-02 -4.8396179080009460e-01</leafValues></_>
+            -8.5437655448913574e-02 5.4905670881271362e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 930 -7.7358852140605450e-03</internalNodes>
+            0 -1 802 2.6708254590630531e-03</internalNodes>
           <leafValues>
-            -4.8261037468910217e-01 4.4207476079463959e-02</leafValues></_>
+            -1.6097296774387360e-01 3.5868695378303528e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 909 7.9007837921380997e-03</internalNodes>
+            0 -1 75 2.2817514836788177e-03</internalNodes>
           <leafValues>
-            -9.4954080879688263e-02 2.7517431974411011e-01</leafValues></_>
+            -1.6324259340763092e-01 2.3956388235092163e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 470 4.0566008538007736e-03</internalNodes>
+            0 -1 745 6.7889376077800989e-04</internalNodes>
           <leafValues>
-            4.3646700680255890e-02 -5.8921122550964355e-01</leafValues></_>
+            -2.5205141305923462e-01 1.6190616786479950e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 245 3.5946490243077278e-03</internalNodes>
+            0 -1 811 3.1512721907347441e-03</internalNodes>
           <leafValues>
-            -1.3110473752021790e-01 1.8304315209388733e-01</leafValues></_>
+            -1.3325424492359161e-01 2.7017220854759216e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 206 -2.6677086949348450e-02</internalNodes>
+            0 -1 53 5.7821646332740784e-02</internalNodes>
           <leafValues>
-            2.8980365395545959e-01 -8.3346247673034668e-02</leafValues></_>
+            -6.7158013582229614e-02 4.1875806450843811e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 213 5.4062507115304470e-03</internalNodes>
+            0 -1 442 2.8442896902561188e-02</internalNodes>
           <leafValues>
-            -9.1766953468322754e-02 2.9673796892166138e-01</leafValues></_>
+            5.5711831897497177e-02 -5.8136337995529175e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 230 -5.1793372258543968e-03</internalNodes>
+            0 -1 644 -1.7370734130963683e-03</internalNodes>
           <leafValues>
-            -6.1112493276596069e-01 4.3332517147064209e-02</leafValues></_>
+            -6.7132610082626343e-01 3.2464105635881424e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 397 -9.1262701898813248e-03</internalNodes>
+            0 -1 324 -1.9680276513099670e-02</internalNodes>
           <leafValues>
-            2.1878185868263245e-01 -1.1105874925851822e-01</leafValues></_>
+            3.9044600725173950e-01 -8.8745564222335815e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 387 9.5943324267864227e-03</internalNodes>
+            0 -1 224 1.0001409798860550e-02</internalNodes>
           <leafValues>
-            -8.7977558374404907e-02 3.2010060548782349e-01</leafValues></_>
+            -1.5947268903255463e-01 2.7087828516960144e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 668 -5.0256419926881790e-03</internalNodes>
+            0 -1 644 1.2495646951720119e-03</internalNodes>
           <leafValues>
-            2.1040959656238556e-01 -1.0872460156679153e-01</leafValues></_>
+            8.3702936768531799e-02 -4.6324184536933899e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 681 3.0062482692301273e-03</internalNodes>
+            0 -1 144 3.0510198324918747e-02</internalNodes>
           <leafValues>
-            -1.0699967294931412e-01 2.9316556453704834e-01</leafValues></_>
+            -1.0709584504365921e-01 3.2648065686225891e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 744 1.1852329596877098e-02</internalNodes>
+            0 -1 995 -3.7916197907179594e-03</internalNodes>
           <leafValues>
-            3.9550069719552994e-02 -6.0533910989761353e-01</leafValues></_>
+            -6.1073684692382812e-01 4.7788143157958984e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 533 -5.2753865718841553e-02</internalNodes>
+            0 -1 880 8.5655774455517530e-04</internalNodes>
           <leafValues>
-            2.6370123028755188e-01 -9.2691496014595032e-02</leafValues></_>
+            -2.0807541906833649e-01 1.5517778694629669e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 446 3.8847257383167744e-03</internalNodes>
+            0 -1 986 -3.2812850549817085e-03</internalNodes>
           <leafValues>
-            6.4825706183910370e-02 -4.1523045301437378e-01</leafValues></_>
+            -5.8795136213302612e-01 4.5926980674266815e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 556 -2.6287192013114691e-03</internalNodes>
+            0 -1 499 3.6125673796050251e-04</internalNodes>
           <leafValues>
-            -5.0846499204635620e-01 4.2991567403078079e-02</leafValues></_>
+            -1.6806155443191528e-01 1.7441834509372711e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 330 2.2053448483347893e-03</internalNodes>
+            0 -1 591 -1.2282358948141336e-03</internalNodes>
           <leafValues>
-            -1.0581049323081970e-01 2.3079065978527069e-01</leafValues></_>
+            -4.7641313076019287e-01 5.6790668517351151e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 552 -3.7466879002749920e-03</internalNodes>
+            0 -1 411 9.3263220041990280e-03</internalNodes>
           <leafValues>
-            -5.2957397699356079e-01 4.6158149838447571e-02</leafValues></_>
+            -7.4045926332473755e-02 3.7817317247390747e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 501 -2.9029445722699165e-03</internalNodes>
+            0 -1 591 7.4745330493897200e-04</internalNodes>
           <leafValues>
-            -4.1290035843849182e-01 5.1479596644639969e-02</leafValues></_>
+            8.0762349069118500e-02 -3.5692575573921204e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 13 3.7801317870616913e-02</internalNodes>
+            0 -1 900 7.4315653182566166e-03</internalNodes>
           <leafValues>
-            -1.0680335760116577e-01 2.2418104112148285e-01</leafValues></_>
+            -8.5764542222023010e-02 3.2155406475067139e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 73 -8.4752835333347321e-02</internalNodes>
+            0 -1 776 2.7057509869337082e-02</internalNodes>
           <leafValues>
-            -7.8421443700790405e-01 3.0642487108707428e-02</leafValues></_>
+            6.9296583533287048e-02 -4.2836430668830872e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 619 9.6596507355570793e-03</internalNodes>
+            0 -1 504 3.9283365011215210e-02</internalNodes>
           <leafValues>
-            -9.7389675676822662e-02 2.4497544765472412e-01</leafValues></_>
+            -1.0806435346603394e-01 2.9007008671760559e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 519 7.2564175352454185e-03</internalNodes>
+            0 -1 23 -3.4139624238014221e-01</internalNodes>
           <leafValues>
-            -9.8195895552635193e-02 2.9686492681503296e-01</leafValues></_>
+            5.0227731466293335e-01 -6.3795588910579681e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 33 -1.0029030963778496e-02</internalNodes>
+            0 -1 502 -1.8172953277826309e-02</internalNodes>
           <leafValues>
-            -5.6505876779556274e-01 4.1911888867616653e-02</leafValues></_>
+            2.7207729220390320e-01 -1.0322675853967667e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 540 -9.7039304673671722e-03</internalNodes>
+            0 -1 509 1.5265008434653282e-02</internalNodes>
           <leafValues>
-            2.1148304641246796e-01 -1.0376640409231186e-01</leafValues></_>
+            -1.0788526386022568e-01 2.4405729770660400e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 425 -1.8890092615038157e-03</internalNodes>
+            0 -1 465 -1.4973650686442852e-03</internalNodes>
           <leafValues>
-            2.2384525835514069e-01 -1.0597650706768036e-01</leafValues></_>
+            2.8644701838493347e-01 -1.0436929017305374e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 587 -1.4225458726286888e-03</internalNodes>
+            0 -1 674 2.1207414101809263e-03</internalNodes>
           <leafValues>
-            2.1189780533313751e-01 -1.1053096503019333e-01</leafValues></_>
+            4.5713264495134354e-02 -6.6571021080017090e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 301 4.3249968439340591e-03</internalNodes>
+            0 -1 254 1.3393461704254150e-02</internalNodes>
           <leafValues>
-            4.1859358549118042e-02 -5.3136503696441650e-01</leafValues></_>
+            -8.4284797310829163e-02 3.6480179429054260e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 418 -2.5746987666934729e-03</internalNodes>
+            0 -1 560 9.7873376216739416e-04</internalNodes>
           <leafValues>
-            -3.3480682969093323e-01 6.2653385102748871e-02</leafValues></_>
+            -1.2960052490234375e-01 2.2095513343811035e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 822 1.9772505387663841e-02</internalNodes>
+            0 -1 747 -4.9731796607375145e-03</internalNodes>
           <leafValues>
-            -5.8535441756248474e-02 3.9204162359237671e-01</leafValues></_>
+            2.7467787265777588e-01 -1.0236363112926483e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 255 -9.6579845994710922e-03</internalNodes>
+            0 -1 294 -7.9883169382810593e-03</internalNodes>
           <leafValues>
-            2.2001895308494568e-01 -9.4623439013957977e-02</leafValues></_>
+            -5.3638678789138794e-01 5.3369920700788498e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 320 1.5255061443895102e-03</internalNodes>
+            0 -1 413 2.3855306208133698e-03</internalNodes>
           <leafValues>
-            -8.3463013172149658e-02 3.1410121917724609e-01</leafValues></_>
+            5.4967612028121948e-02 -4.2117682099342346e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 136 6.2276879325509071e-03</internalNodes>
+            0 -1 899 -3.0849636532366276e-03</internalNodes>
           <leafValues>
-            5.6847181171178818e-02 -4.1030114889144897e-01</leafValues></_>
+            2.6192533969879150e-01 -9.4207443296909332e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 214 9.0132874902337790e-04</internalNodes>
+            0 -1 653 4.3416069820523262e-03</internalNodes>
           <leafValues>
-            -8.4593303501605988e-02 2.7151137590408325e-01</leafValues></_>
+            -1.5543100237846375e-01 1.6663897037506104e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 953 -4.6218577772378922e-03</internalNodes>
+            0 -1 451 3.8728015497326851e-03</internalNodes>
           <leafValues>
-            -4.0008178353309631e-01 5.6437231600284576e-02</leafValues></_>
+            4.9280565232038498e-02 -4.9337747693061829e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 730 -1.5077156014740467e-02</internalNodes>
+            0 -1 563 1.8099667504429817e-03</internalNodes>
           <leafValues>
-            2.3747061192989349e-01 -9.1518931090831757e-02</leafValues></_>
+            4.2697191238403320e-02 -5.2748012542724609e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 34 2.1273698657751083e-02</internalNodes>
+            0 -1 157 -3.3727339468896389e-03</internalNodes>
           <leafValues>
-            5.3466927260160446e-02 -4.5392176508903503e-01</leafValues></_>
+            2.0491680502891541e-01 -1.2846539914608002e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 227 -6.0164434835314751e-03</internalNodes>
+            0 -1 344 3.1393815297633410e-03</internalNodes>
           <leafValues>
-            2.3596890270709991e-01 -1.2803076207637787e-01</leafValues></_>
+            -7.3090612888336182e-02 3.4941059350967407e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 148 8.9327711611986160e-03</internalNodes>
+            0 -1 851 3.2568261958658695e-03</internalNodes>
           <leafValues>
-            4.2524505406618118e-02 -5.8664286136627197e-01</leafValues></_>
+            4.5729346573352814e-02 -5.7302659749984741e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 118 7.3118656873703003e-03</internalNodes>
+            0 -1 853 -2.0513155031949282e-03</internalNodes>
           <leafValues>
-            -6.9641888141632080e-02 3.3589112758636475e-01</leafValues></_>
+            -5.4655516147613525e-01 3.8907390087842941e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 616 2.6424862444400787e-03</internalNodes>
+            0 -1 656 -2.7090720832347870e-03</internalNodes>
           <leafValues>
-            3.4661941230297089e-02 -6.7860239744186401e-01</leafValues></_>
+            -5.2781039476394653e-01 3.8093525916337967e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 641 5.9287068434059620e-03</internalNodes>
+            0 -1 738 -3.6282267421483994e-02</internalNodes>
           <leafValues>
-            2.7298627421259880e-02 -6.5472942590713501e-01</leafValues></_>
+            -5.8760797977447510e-01 3.4759882837533951e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 877 -7.8424429520964622e-03</internalNodes>
+            0 -1 558 3.7925848737359047e-03</internalNodes>
           <leafValues>
-            -6.3548064231872559e-01 2.7554484084248543e-02</leafValues></_>
+            -8.5966393351554871e-02 2.6226586103439331e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 541 -2.1585542708635330e-03</internalNodes>
+            0 -1 991 -3.7565450184047222e-03</internalNodes>
           <leafValues>
-            2.2929325699806213e-01 -9.0029284358024597e-02</leafValues></_>
+            -5.7828390598297119e-01 3.9440535008907318e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 484 1.5804420690983534e-03</internalNodes>
+            0 -1 906 -7.8137982636690140e-03</internalNodes>
           <leafValues>
-            -9.7765833139419556e-02 2.2442239522933960e-01</leafValues></_>
+            3.5042202472686768e-01 -6.6597603261470795e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 478 -1.2139983475208282e-02</internalNodes>
+            0 -1 904 -3.1100357882678509e-03</internalNodes>
           <leafValues>
-            2.9934337735176086e-01 -7.2730682790279388e-02</leafValues></_>
+            1.8389418721199036e-01 -1.4107073843479156e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 149 2.2737295366823673e-03</internalNodes>
+            0 -1 449 9.1797057539224625e-03</internalNodes>
           <leafValues>
-            4.6053361147642136e-02 -4.7994795441627502e-01</leafValues></_>
+            -6.2711343169212341e-02 3.4819519519805908e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 229 2.0574156660586596e-03</internalNodes>
+            0 -1 255 -2.9698751866817474e-02</internalNodes>
           <leafValues>
-            -4.9065478146076202e-02 4.6873793005943298e-01</leafValues></_>
+            2.8956320881843567e-01 -8.5679493844509125e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 132 5.9092035517096519e-03</internalNodes>
+            0 -1 720 7.9502481967210770e-03</internalNodes>
           <leafValues>
-            3.3293012529611588e-02 -6.2421238422393799e-01</leafValues></_>
+            3.9165180176496506e-02 -6.0753583908081055e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 569 -2.0584808662533760e-02</internalNodes>
+            0 -1 621 2.2064188960939646e-03</internalNodes>
           <leafValues>
-            2.6486057043075562e-01 -7.6441936194896698e-02</leafValues></_>
+            3.5431943833827972e-02 -5.5480444431304932e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 92 1.1120462790131569e-02</internalNodes>
+            0 -1 175 -3.1044434756040573e-02</internalNodes>
           <leafValues>
-            4.4590156525373459e-02 -5.2196294069290161e-01</leafValues></_>
+            -6.2628567218780518e-01 3.1049268320202827e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 797 -3.4440308809280396e-03</internalNodes>
+            0 -1 0 -1.3199620880186558e-03</internalNodes>
           <leafValues>
-            1.5679638087749481e-01 -1.3589784502983093e-01</leafValues></_>
+            1.5564316511154175e-01 -1.3879336416721344e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 963 -1.0556755587458611e-02</internalNodes>
+            0 -1 397 -9.6068280981853604e-04</internalNodes>
           <leafValues>
-            3.0609151721000671e-01 -7.2761178016662598e-02</leafValues></_>
+            1.9332279264926910e-01 -1.1179215461015701e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 67 8.1238988786935806e-03</internalNodes>
+            0 -1 43 7.4608568102121353e-03</internalNodes>
           <leafValues>
-            4.4047191739082336e-02 -4.8989585041999817e-01</leafValues></_>
+            5.7219974696636200e-02 -4.2135125398635864e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 25 -1.1493992060422897e-02</internalNodes>
+            0 -1 293 -4.3320422992110252e-03</internalNodes>
           <leafValues>
-            2.0072945952415466e-01 -1.1034463346004486e-01</leafValues></_>
+            -6.8079024553298950e-01 2.9504306614398956e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 586 2.3690698668360710e-02</internalNodes>
+            0 -1 274 -6.5548438578844070e-03</internalNodes>
           <leafValues>
-            -1.2550449371337891e-01 1.8665367364883423e-01</leafValues></_>
+            2.9043409228324890e-01 -8.7089523673057556e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 871 1.5682559460401535e-02</internalNodes>
+            0 -1 204 4.2611984536051750e-03</internalNodes>
           <leafValues>
-            -7.4671298265457153e-02 2.8130453824996948e-01</leafValues></_>
+            -8.5929870605468750e-02 3.1930494308471680e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 399 -3.3444758504629135e-02</internalNodes>
+            0 -1 635 -7.2978977113962173e-03</internalNodes>
           <leafValues>
-            2.6843747496604919e-01 -8.3811916410923004e-02</leafValues></_>
+            1.4620631933212280e-01 -1.7617914080619812e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 610 3.0884463340044022e-02</internalNodes>
+            0 -1 225 -2.2543172817677259e-03</internalNodes>
           <leafValues>
-            -9.9225074052810669e-02 2.2484876215457916e-01</leafValues></_>
+            -5.9305733442306519e-01 3.9764832705259323e-02</leafValues></_></weakClassifiers></_>
+    <!-- stage 12 -->
+    <_>
+      <maxWeakCount>70</maxWeakCount>
+      <stageThreshold>-1.3067549467086792e+00</stageThreshold>
+      <weakClassifiers>
         <_>
           <internalNodes>
-            0 -1 222 -4.0955815464258194e-02</internalNodes>
+            0 -1 742 -5.6160744279623032e-03</internalNodes>
           <leafValues>
-            1.8551258742809296e-01 -1.1869347840547562e-01</leafValues></_></weakClassifiers></_>
-    <!-- stage 9 -->
-    <_>
-      <maxWeakCount>90</maxWeakCount>
-      <stageThreshold>-1.4453492164611816e+00</stageThreshold>
-      <weakClassifiers>
+            4.7913768887519836e-01 -9.8717339336872101e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 735 -4.5189578086137772e-03</internalNodes>
+            0 -1 536 -5.6263338774442673e-03</internalNodes>
           <leafValues>
-            6.7139738798141479e-01 9.2261902987957001e-02</leafValues></_>
+            2.8639736771583557e-01 -1.7997759580612183e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 199 4.2574461549520493e-03</internalNodes>
+            0 -1 795 -1.6268140170723200e-03</internalNodes>
           <leafValues>
-            -1.1547925323247910e-01 4.7692731022834778e-01</leafValues></_>
+            3.0874463915824890e-01 -1.3907180726528168e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 395 -3.0073656234890223e-03</internalNodes>
+            0 -1 802 -1.3920383062213659e-03</internalNodes>
           <leafValues>
-            3.6661648750305176e-01 -1.3400055468082428e-01</leafValues></_>
+            3.2034638524055481e-01 -1.3876211643218994e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 185 2.0850619673728943e-01</internalNodes>
+            0 -1 826 3.4234612248837948e-03</internalNodes>
           <leafValues>
-            -1.7360156774520874e-01 2.8776788711547852e-01</leafValues></_>
+            -1.0860712081193924e-01 3.2174232602119446e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 263 -3.3409267663955688e-02</internalNodes>
+            0 -1 525 4.3767906725406647e-02</internalNodes>
           <leafValues>
-            4.2965263128280640e-01 -1.1280254274606705e-01</leafValues></_>
+            -1.3255064189434052e-01 3.7021124362945557e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 444 8.2403160631656647e-03</internalNodes>
+            0 -1 401 -4.4696494005620480e-03</internalNodes>
           <leafValues>
-            -1.3494767248630524e-01 3.0936670303344727e-01</leafValues></_>
+            -4.5687621831893921e-01 8.2243621349334717e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 201 -5.4142652079463005e-03</internalNodes>
+            0 -1 332 -7.1945399977266788e-03</internalNodes>
           <leafValues>
-            -5.0563532114028931e-01 6.3294559717178345e-02</leafValues></_>
+            -6.4334297180175781e-01 4.5623987913131714e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 691 -1.3661640696227551e-02</internalNodes>
+            0 -1 273 6.5287351608276367e-03</internalNodes>
           <leafValues>
-            2.6760646700859070e-01 -1.3282431662082672e-01</leafValues></_>
+            -8.9336074888706207e-02 3.3727860450744629e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 5 -6.6441677510738373e-02</internalNodes>
+            0 -1 771 2.8297028038650751e-03</internalNodes>
           <leafValues>
-            4.2027309536933899e-01 -9.1117665171623230e-02</leafValues></_>
+            -1.0177894681692123e-01 3.5831856727600098e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 363 -3.6823814734816551e-03</internalNodes>
+            0 -1 925 1.1526069603860378e-02</internalNodes>
           <leafValues>
-            -6.0496860742568970e-01 6.3766337931156158e-02</leafValues></_>
+            7.5238041579723358e-02 -4.8319393396377563e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 363 3.5007880069315434e-03</internalNodes>
+            0 -1 207 4.7937319613993168e-03</internalNodes>
           <leafValues>
-            5.9523750096559525e-02 -5.4523044824600220e-01</leafValues></_>
+            5.7682428508996964e-02 -4.7086900472640991e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 223 1.5307647408917546e-03</internalNodes>
+            0 -1 395 -3.6777029745280743e-03</internalNodes>
           <leafValues>
-            -1.1713726073503494e-01 3.1415259838104248e-01</leafValues></_>
+            -4.2743790149688721e-01 7.4363298714160919e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 769 -1.7609039321541786e-02</internalNodes>
+            0 -1 839 -8.0760312266647816e-04</internalNodes>
           <leafValues>
-            3.9622062444686890e-01 -8.1705585122108459e-02</leafValues></_>
+            1.4320656657218933e-01 -1.9929704070091248e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 878 2.3612366989254951e-02</internalNodes>
+            0 -1 233 3.7253312766551971e-03</internalNodes>
           <leafValues>
-            -1.1964736133813858e-01 2.8404179215431213e-01</leafValues></_>
+            5.2736207842826843e-02 -5.2105212211608887e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 9 -1.2014270760118961e-02</internalNodes>
+            0 -1 416 -2.3560712113976479e-02</internalNodes>
           <leafValues>
-            2.7746838331222534e-01 -1.1446747928857803e-01</leafValues></_>
+            4.0658730268478394e-01 -7.3024936020374298e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 450 -4.6456828713417053e-03</internalNodes>
+            0 -1 311 -4.5593185350298882e-03</internalNodes>
           <leafValues>
-            -5.3870040178298950e-01 5.2098110318183899e-02</leafValues></_>
+            -6.3590377569198608e-01 3.5127460956573486e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 447 5.3105363622307777e-03</internalNodes>
+            0 -1 551 -2.4863984435796738e-03</internalNodes>
           <leafValues>
-            -1.0284136235713959e-01 3.0061340332031250e-01</leafValues></_>
+            -4.5599257946014404e-01 5.3035512566566467e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 463 -3.2729478552937508e-03</internalNodes>
+            0 -1 424 -2.6802124921232462e-03</internalNodes>
           <leafValues>
-            1.9203263521194458e-01 -1.6125205159187317e-01</leafValues></_>
+            1.9116453826427460e-01 -1.3404799997806549e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 329 9.8467990756034851e-03</internalNodes>
+            0 -1 11 -7.7647715806961060e-02</internalNodes>
           <leafValues>
-            4.8938397318124771e-02 -5.1129150390625000e-01</leafValues></_>
+            4.1297465562820435e-01 -6.3970938324928284e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 270 3.2083394471555948e-03</internalNodes>
+            0 -1 566 2.3329094983637333e-03</internalNodes>
           <leafValues>
-            -8.5019417107105255e-02 3.4343490004539490e-01</leafValues></_>
+            -1.2160944193601608e-01 2.3117628693580627e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 228 5.5270073935389519e-03</internalNodes>
+            0 -1 5 -6.6609308123588562e-03</internalNodes>
           <leafValues>
-            6.3495978713035583e-02 -4.8666983842849731e-01</leafValues></_>
+            2.2600707411766052e-01 -1.2069495767354965e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 866 -2.3475135676562786e-03</internalNodes>
+            0 -1 133 -5.0821684300899506e-02</internalNodes>
           <leafValues>
-            2.5843459367752075e-01 -1.1678623408079147e-01</leafValues></_>
+            3.2217630743980408e-01 -7.6335281133651733e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 689 -1.5939555596560240e-03</internalNodes>
+            0 -1 537 -7.0379404351115227e-03</internalNodes>
           <leafValues>
-            -3.2783389091491699e-01 8.0364800989627838e-02</leafValues></_>
+            1.8399104475975037e-01 -1.4812190830707550e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 422 -4.1191074997186661e-03</internalNodes>
+            0 -1 134 -3.3276520669460297e-02</internalNodes>
           <leafValues>
-            -5.5736887454986572e-01 4.6545837074518204e-02</leafValues></_>
+            -6.0358065366744995e-01 3.5330448299646378e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 834 1.7747837118804455e-03</internalNodes>
+            0 -1 392 7.5909225270152092e-03</internalNodes>
           <leafValues>
-            -7.7934704720973969e-02 3.3011713624000549e-01</leafValues></_>
+            3.1779482960700989e-02 -6.4767998456954956e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 789 -1.6894178697839379e-03</internalNodes>
+            0 -1 613 -5.6639023125171661e-02</internalNodes>
           <leafValues>
-            2.2780518233776093e-01 -1.1316975951194763e-01</leafValues></_>
+            -4.6455994248390198e-01 4.6072337776422501e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 625 -2.0341284107416868e-03</internalNodes>
+            0 -1 124 3.7777128163725138e-03</internalNodes>
           <leafValues>
-            -3.8829386234283447e-01 6.9249257445335388e-02</leafValues></_>
+            5.7451672852039337e-02 -3.7793967127799988e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 655 -3.4458152949810028e-03</internalNodes>
+            0 -1 271 8.9145395904779434e-03</internalNodes>
           <leafValues>
-            -4.0543556213378906e-01 5.8193698525428772e-02</leafValues></_>
+            -7.5942978262901306e-02 3.1487807631492615e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 813 -9.3588102608919144e-03</internalNodes>
+            0 -1 841 -1.4818884432315826e-02</internalNodes>
           <leafValues>
-            3.1281456351280212e-01 -7.8269012272357941e-02</leafValues></_>
+            2.7122247219085693e-01 -9.8314434289932251e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 322 -4.9023423343896866e-03</internalNodes>
+            0 -1 381 -5.5922558531165123e-03</internalNodes>
           <leafValues>
-            -4.0507251024246216e-01 6.6911309957504272e-02</leafValues></_>
+            -6.4762401580810547e-01 4.1314963251352310e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 68 -4.8415181040763855e-01</internalNodes>
+            0 -1 595 3.1491921981796622e-04</internalNodes>
           <leafValues>
-            6.5363335609436035e-01 -4.0620740503072739e-02</leafValues></_>
+            -1.4864055812358856e-01 1.4411780238151550e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 18 2.6781920343637466e-02</internalNodes>
+            0 -1 136 -5.7063563726842403e-03</internalNodes>
           <leafValues>
-            -1.0990447551012039e-01 2.1767459809780121e-01</leafValues></_>
+            -4.6024248003959656e-01 4.7999884933233261e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 800 -9.4280913472175598e-03</internalNodes>
+            0 -1 210 -1.2257394846528769e-03</internalNodes>
           <leafValues>
-            -7.4746483564376831e-01 2.9869174584746361e-02</leafValues></_>
+            3.2288366556167603e-01 -7.0425607264041901e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 492 -7.7869845554232597e-03</internalNodes>
+            0 -1 775 -1.6291948035359383e-02</internalNodes>
           <leafValues>
-            3.0222293734550476e-01 -8.3480700850486755e-02</leafValues></_>
+            2.7573275566101074e-01 -8.3055868744850159e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 426 3.5958206281065941e-03</internalNodes>
+            0 -1 156 -8.1639690324664116e-04</internalNodes>
           <leafValues>
-            -8.2547821104526520e-02 2.9035624861717224e-01</leafValues></_>
+            1.7044979333877563e-01 -1.4129574596881866e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 487 5.8124819770455360e-03</internalNodes>
+            0 -1 975 5.1114819943904877e-03</internalNodes>
           <leafValues>
-            -9.7843483090400696e-02 2.6563084125518799e-01</leafValues></_>
+            3.3882420510053635e-02 -6.9941717386245728e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 66 -6.3764736987650394e-03</internalNodes>
+            0 -1 977 -2.8371806256473064e-03</internalNodes>
           <leafValues>
-            -4.6169018745422363e-01 5.5747114121913910e-02</leafValues></_>
+            -3.7707236409187317e-01 5.7759616523981094e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 186 -7.2099521756172180e-02</internalNodes>
+            0 -1 772 5.3479857742786407e-03</internalNodes>
           <leafValues>
-            -7.3345041275024414e-01 2.8517069295048714e-02</leafValues></_>
+            4.1541736572980881e-02 -4.8687714338302612e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 120 -8.2340046763420105e-02</internalNodes>
+            0 -1 735 1.1360908392816782e-03</internalNodes>
           <leafValues>
-            -6.5312498807907104e-01 2.9036073014140129e-02</leafValues></_>
+            -7.8717894852161407e-02 2.9692038893699646e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 927 -1.5001616440713406e-02</internalNodes>
+            0 -1 947 1.4100213302299380e-03</internalNodes>
           <leafValues>
-            -6.3826096057891846e-01 3.2474573701620102e-02</leafValues></_>
+            4.3843001127243042e-02 -5.1339787244796753e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 288 1.1907238513231277e-03</internalNodes>
+            0 -1 387 8.7079760851338506e-04</internalNodes>
           <leafValues>
-            -7.9208493232727051e-02 2.9137271642684937e-01</leafValues></_>
+            -9.8695866763591766e-02 2.2730629146099091e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 594 3.1184246763586998e-03</internalNodes>
+            0 -1 211 -5.4065873846411705e-03</internalNodes>
           <leafValues>
-            4.7656070441007614e-02 -4.7487255930900574e-01</leafValues></_>
+            -6.3011974096298218e-01 3.7802927196025848e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 603 8.2192681729793549e-03</internalNodes>
+            0 -1 816 -1.6894804313778877e-02</internalNodes>
           <leafValues>
-            2.6732290163636208e-02 -7.3682332038879395e-01</leafValues></_>
+            -5.0091201066970825e-01 3.5215172916650772e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 264 7.1536734700202942e-02</internalNodes>
+            0 -1 766 1.4164673630148172e-03</internalNodes>
           <leafValues>
-            -6.6174156963825226e-02 3.4596624970436096e-01</leafValues></_>
+            -8.8441111147403717e-02 2.4102251231670380e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 707 -1.3247081078588963e-02</internalNodes>
+            0 -1 704 -1.1464871931821108e-03</internalNodes>
           <leafValues>
-            2.2122915089130402e-01 -1.1525890231132507e-01</leafValues></_>
+            1.9273723661899567e-01 -1.1090471595525742e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 88 6.4605651423335075e-03</internalNodes>
+            0 -1 861 -3.2706123311072588e-03</internalNodes>
           <leafValues>
-            5.1374625414609909e-02 -4.2834889888763428e-01</leafValues></_>
+            -4.5202803611755371e-01 4.7059688717126846e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 714 -1.9957395270466805e-03</internalNodes>
+            0 -1 70 1.1416582390666008e-02</internalNodes>
           <leafValues>
-            2.8387853503227234e-01 -8.6039707064628601e-02</leafValues></_>
+            2.6714416220784187e-02 -6.9660711288452148e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 939 2.5912611745297909e-03</internalNodes>
+            0 -1 310 2.7643535286188126e-03</internalNodes>
           <leafValues>
-            6.0468357056379318e-02 -3.9721179008483887e-01</leafValues></_>
+            4.7252438962459564e-02 -3.9458727836608887e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 716 1.9276916980743408e-02</internalNodes>
+            0 -1 435 2.4567130021750927e-03</internalNodes>
           <leafValues>
-            -8.2993559539318085e-02 3.0764940381050110e-01</leafValues></_>
+            -7.5188823044300079e-02 2.9944056272506714e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 887 -4.9096969887614250e-03</internalNodes>
+            0 -1 441 -7.3516201227903366e-03</internalNodes>
           <leafValues>
-            2.7268949151039124e-01 -8.6130671203136444e-02</leafValues></_>
+            2.8476437926292419e-01 -9.2367134988307953e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 950 3.6836266517639160e-03</internalNodes>
+            0 -1 662 -4.3670929968357086e-02</internalNodes>
           <leafValues>
-            5.9468954801559448e-02 -3.9446946978569031e-01</leafValues></_>
+            -6.8588620424270630e-01 3.3353023231029510e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 520 3.0758073553442955e-03</internalNodes>
+            0 -1 138 -6.4992159605026245e-02</internalNodes>
           <leafValues>
-            -9.7390249371528625e-02 2.4346484243869781e-01</leafValues></_>
+            -7.9678738117218018e-01 2.0331909880042076e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 522 -4.2319851927459240e-03</internalNodes>
+            0 -1 286 -1.1700032278895378e-02</internalNodes>
           <leafValues>
-            3.0930569767951965e-01 -7.9394333064556122e-02</leafValues></_>
+            -6.1183351278305054e-01 2.7328895404934883e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 405 7.2837145999073982e-03</internalNodes>
+            0 -1 589 3.0743866227567196e-03</internalNodes>
           <leafValues>
-            4.7933470457792282e-02 -4.8675662279129028e-01</leafValues></_>
+            -7.7295452356338501e-02 2.6685911417007446e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 467 -6.2543689273297787e-03</internalNodes>
+            0 -1 584 -1.5546076931059361e-02</internalNodes>
           <leafValues>
-            -4.8621338605880737e-01 4.2082890868186951e-02</leafValues></_>
+            -5.5246621370315552e-01 4.0912687778472900e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 872 -1.1530111078172922e-03</internalNodes>
+            0 -1 40 6.5568592399358749e-03</internalNodes>
           <leafValues>
-            2.6954403519630432e-01 -8.6280718445777893e-02</leafValues></_>
+            -1.0432150214910507e-01 1.9379787147045135e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 560 4.0323145687580109e-02</internalNodes>
+            0 -1 29 -8.0047458410263062e-02</internalNodes>
           <leafValues>
-            -9.4530344009399414e-02 2.3481069505214691e-01</leafValues></_>
+            3.9228948950767517e-01 -5.2565738558769226e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 15 -1.2282184325158596e-02</internalNodes>
+            0 -1 227 1.5684183686971664e-02</internalNodes>
           <leafValues>
-            -7.2538161277770996e-01 3.0701907351613045e-02</leafValues></_>
+            -1.1151826381683350e-01 1.8633136153221130e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 678 3.7427488714456558e-02</internalNodes>
+            0 -1 546 2.3603178560733795e-03</internalNodes>
           <leafValues>
-            2.9119925573468208e-02 -6.4663606882095337e-01</leafValues></_>
+            -1.0219112038612366e-01 2.0333246886730194e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 568 2.5721127167344093e-03</internalNodes>
+            0 -1 585 -3.5169085022062063e-03</internalNodes>
           <leafValues>
-            4.9338530749082565e-02 -4.0851938724517822e-01</leafValues></_>
+            2.7427124977111816e-01 -8.6362943053245544e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 925 -2.0106829702854156e-02</internalNodes>
+            0 -1 476 9.4871241599321365e-03</internalNodes>
           <leafValues>
-            -6.2753307819366455e-01 3.1198438256978989e-02</leafValues></_>
+            3.5626750439405441e-02 -6.2631088495254517e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 936 2.5536534376442432e-03</internalNodes>
+            0 -1 629 -9.3261618167161942e-03</internalNodes>
           <leafValues>
-            2.3092683404684067e-02 -7.4033683538436890e-01</leafValues></_>
+            -7.1806514263153076e-01 2.4241568520665169e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 876 -1.3628168962895870e-03</internalNodes>
+            0 -1 666 -6.3302312046289444e-03</internalNodes>
           <leafValues>
-            3.4928113222122192e-01 -6.5548241138458252e-02</leafValues></_>
+            2.1094995737075806e-01 -9.2475786805152893e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 875 -9.9153746850788593e-04</internalNodes>
+            0 -1 598 -2.8244811110198498e-03</internalNodes>
           <leafValues>
-            2.2522389888763428e-01 -9.1688700020313263e-02</leafValues></_>
+            2.6596403121948242e-01 -8.0099694430828094e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 965 5.0148647278547287e-03</internalNodes>
+            0 -1 145 -1.1591307818889618e-02</internalNodes>
           <leafValues>
-            3.9175543934106827e-02 -5.5856782197952271e-01</leafValues></_>
+            2.3619163036346436e-01 -8.5169024765491486e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 853 9.1358053032308817e-04</internalNodes>
+            0 -1 117 2.1401243284344673e-03</internalNodes>
           <leafValues>
-            -1.2273798882961273e-01 1.8954706192016602e-01</leafValues></_>
+            -1.0995808988809586e-01 2.1230246126651764e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 762 1.6373313963413239e-02</internalNodes>
+            0 -1 562 4.2046746239066124e-03</internalNodes>
           <leafValues>
-            3.9829690009355545e-02 -5.7986593246459961e-01</leafValues></_>
+            3.6688093096017838e-02 -6.1654287576675415e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 544 1.4575564302504063e-02</internalNodes>
+            0 -1 605 1.1085141450166702e-03</internalNodes>
           <leafValues>
-            -8.6225226521492004e-02 2.4198558926582336e-01</leafValues></_>
+            -8.0656312406063080e-02 2.7754181623458862e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 967 5.1754433661699295e-04</internalNodes>
+            0 -1 829 -8.2805287092924118e-03</internalNodes>
           <leafValues>
-            8.9498788118362427e-02 -2.1777628362178802e-01</leafValues></_>
+            -6.5883606672286987e-01 3.6048211157321930e-02</leafValues></_></weakClassifiers></_>
+    <!-- stage 13 -->
+    <_>
+      <maxWeakCount>70</maxWeakCount>
+      <stageThreshold>-1.2368309497833252e+00</stageThreshold>
+      <weakClassifiers>
         <_>
           <internalNodes>
-            0 -1 79 -1.1098009534180164e-02</internalNodes>
+            0 -1 716 -3.3105849288403988e-03</internalNodes>
           <leafValues>
-            2.2925806045532227e-01 -8.3799630403518677e-02</leafValues></_>
+            5.0566112995147705e-01 -8.2956805825233459e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 308 2.4133864790201187e-02</internalNodes>
+            0 -1 190 4.5855166390538216e-03</internalNodes>
           <leafValues>
-            -1.0102383792400360e-01 2.0877565443515778e-01</leafValues></_>
+            -1.3226345181465149e-01 3.9034894108772278e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 152 -3.7758771330118179e-02</internalNodes>
+            0 -1 576 -2.6665716432034969e-03</internalNodes>
           <leafValues>
-            4.3367731571197510e-01 -5.1683723926544189e-02</leafValues></_>
+            2.7508354187011719e-01 -1.3807572424411774e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 218 9.0820249170064926e-03</internalNodes>
+            0 -1 734 1.8106825649738312e-02</internalNodes>
           <leafValues>
-            4.0468864142894745e-02 -5.4790335893630981e-01</leafValues></_>
+            -1.2738862633705139e-01 3.5449108481407166e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 385 -3.8959060329943895e-03</internalNodes>
+            0 -1 830 -5.7813120074570179e-03</internalNodes>
           <leafValues>
-            -3.4300115704536438e-01 5.6340463459491730e-02</leafValues></_>
+            2.7463605999946594e-01 -1.2951526045799255e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 815 -1.0297749191522598e-02</internalNodes>
+            0 -1 379 8.9321136474609375e-03</internalNodes>
           <leafValues>
-            2.9084947705268860e-01 -8.1125274300575256e-02</leafValues></_>
+            4.8491790890693665e-02 -5.8104276657104492e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 815 8.3358399569988251e-03</internalNodes>
+            0 -1 17 6.2806839123368263e-03</internalNodes>
           <leafValues>
-            -6.9515161216259003e-02 3.0880457162857056e-01</leafValues></_>
+            -1.3215491175651550e-01 2.1852293610572815e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 805 4.1338298469781876e-02</internalNodes>
+            0 -1 9 -4.3670572340488434e-02</internalNodes>
           <leafValues>
-            3.2240319997072220e-02 -6.5160977840423584e-01</leafValues></_>
+            3.8786840438842773e-01 -7.4191503226757050e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 345 2.6844158768653870e-02</internalNodes>
+            0 -1 554 -6.2309622764587402e-02</internalNodes>
           <leafValues>
-            -6.5987348556518555e-02 3.1071534752845764e-01</leafValues></_>
+            3.3408007025718689e-01 -8.7087221443653107e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 93 -4.4573536142706871e-03</internalNodes>
+            0 -1 686 -3.2859744969755411e-03</internalNodes>
           <leafValues>
-            -3.4222671389579773e-01 6.0962244868278503e-02</leafValues></_>
+            3.3486780524253845e-01 -8.9008949697017670e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 217 -5.6259175762534142e-03</internalNodes>
+            0 -1 346 -3.9627305231988430e-03</internalNodes>
           <leafValues>
-            1.9679838418960571e-01 -9.9301390349864960e-02</leafValues></_>
+            2.6155433058738708e-01 -9.5614455640316010e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 130 -3.4068014472723007e-02</internalNodes>
+            0 -1 434 1.0877416934818029e-03</internalNodes>
           <leafValues>
-            -5.7343089580535889e-01 3.5370521247386932e-02</leafValues></_>
+            -1.4199735224246979e-01 1.8414285778999329e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 415 -4.1321285068988800e-02</internalNodes>
+            0 -1 249 5.4819821380078793e-03</internalNodes>
           <leafValues>
-            -5.4799556732177734e-01 3.2511439174413681e-02</leafValues></_>
+            7.4260123074054718e-02 -5.6989872455596924e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 702 -4.5842211693525314e-03</internalNodes>
+            0 -1 916 4.9011572264134884e-04</internalNodes>
           <leafValues>
-            2.0696444809436798e-01 -9.3100592494010925e-02</leafValues></_>
+            -1.9576059281826019e-01 1.3506270945072174e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 705 -8.6525538936257362e-03</internalNodes>
+            0 -1 911 -7.7052684500813484e-03</internalNodes>
           <leafValues>
-            -5.2304923534393311e-01 4.0334302932024002e-02</leafValues></_>
+            -5.0443643331527710e-01 6.1383318156003952e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 656 -8.1807989627122879e-03</internalNodes>
+            0 -1 164 4.8691947013139725e-03</internalNodes>
           <leafValues>
-            3.0393254756927490e-01 -6.9615311920642853e-02</leafValues></_>
+            4.3469026684761047e-02 -5.2802342176437378e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 867 -6.2429648824036121e-03</internalNodes>
+            0 -1 344 2.4673391599208117e-03</internalNodes>
           <leafValues>
-            -5.0806474685668945e-01 4.2720243334770203e-02</leafValues></_>
+            -8.9178681373596191e-02 3.0606627464294434e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 660 -4.3397732079029083e-03</internalNodes>
+            0 -1 172 -3.6682826466858387e-03</internalNodes>
           <leafValues>
-            -4.7173827886581421e-01 3.7593103945255280e-02</leafValues></_>
+            -6.5514552593231201e-01 4.7427203506231308e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 392 -2.4694669991731644e-03</internalNodes>
+            0 -1 365 2.5194899644702673e-03</internalNodes>
           <leafValues>
-            3.4972354769706726e-01 -6.2289424240589142e-02</leafValues></_>
+            4.9365170300006866e-02 -4.0812951326370239e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 496 4.6105296351015568e-03</internalNodes>
+            0 -1 531 5.8970693498849869e-03</internalNodes>
           <leafValues>
-            4.8353113234043121e-02 -3.9337757229804993e-01</leafValues></_>
+            3.5579398274421692e-02 -6.4191317558288574e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 368 1.5546558424830437e-03</internalNodes>
+            0 -1 842 1.7767311073839664e-03</internalNodes>
           <leafValues>
-            -8.5152842104434967e-02 2.4539804458618164e-01</leafValues></_></weakClassifiers></_>
-    <!-- stage 10 -->
-    <_>
-      <maxWeakCount>100</maxWeakCount>
-      <stageThreshold>-1.6321692466735840e+00</stageThreshold>
-      <weakClassifiers>
+            -8.6629316210746765e-02 2.7705979347229004e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 443 -9.9800406023859978e-03</internalNodes>
+            0 -1 885 4.0457276627421379e-03</internalNodes>
           <leafValues>
-            6.5110075473785400e-01 7.0068746805191040e-02</leafValues></_>
+            5.6002113968133926e-02 -4.7005215287208557e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 656 1.2785504572093487e-02</internalNodes>
+            0 -1 522 3.2862280495464802e-03</internalNodes>
           <leafValues>
-            -1.5662825107574463e-01 4.5551964640617371e-01</leafValues></_>
+            -1.2930884957313538e-01 2.0613414049148560e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 197 4.0613190503790975e-04</internalNodes>
+            0 -1 322 1.4660503948107362e-03</internalNodes>
           <leafValues>
-            -2.3326659202575684e-01 2.4264821410179138e-01</leafValues></_>
+            -9.9395424127578735e-02 3.3950179815292358e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 0 -4.4671623036265373e-03</internalNodes>
+            0 -1 266 1.9015703350305557e-02</internalNodes>
           <leafValues>
-            3.0027064681053162e-01 -1.7738959193229675e-01</leafValues></_>
+            6.0197159647941589e-02 -5.1893943548202515e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 733 7.1196053177118301e-03</internalNodes>
+            0 -1 102 -7.1178808808326721e-02</internalNodes>
           <leafValues>
-            -1.3141728937625885e-01 4.3263924121856689e-01</leafValues></_>
+            -4.3668299913406372e-01 4.7340013086795807e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 855 7.1185962297022343e-03</internalNodes>
+            0 -1 795 -4.6305771684274077e-04</internalNodes>
           <leafValues>
-            -1.5669579803943634e-01 3.3418005704879761e-01</leafValues></_>
+            1.4736598730087280e-01 -1.5406486392021179e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 725 4.5672003179788589e-03</internalNodes>
+            0 -1 298 -4.7644632868468761e-03</internalNodes>
           <leafValues>
-            -1.2860487401485443e-01 3.1136614084243774e-01</leafValues></_>
+            -5.0336647033691406e-01 4.4053792953491211e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 859 -1.0435921140015125e-03</internalNodes>
+            0 -1 761 -8.5318256169557571e-03</internalNodes>
           <leafValues>
-            1.9418887794017792e-01 -1.7872068285942078e-01</leafValues></_>
+            -5.9967356920242310e-01 3.2567754387855530e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 111 -8.6360834538936615e-03</internalNodes>
+            0 -1 713 -2.7496295515447855e-03</internalNodes>
           <leafValues>
-            -6.0729598999023438e-01 3.6422688513994217e-02</leafValues></_>
+            1.3502316176891327e-01 -1.6025592386722565e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 685 6.4469715580344200e-03</internalNodes>
+            0 -1 607 4.2666587978601456e-03</internalNodes>
           <leafValues>
-            -1.7270094156265259e-01 1.8412014842033386e-01</leafValues></_>
+            2.5802688673138618e-02 -7.8170543909072876e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 920 -3.2128435559570789e-03</internalNodes>
+            0 -1 216 -2.9856398701667786e-02</internalNodes>
           <leafValues>
-            -5.6947451829910278e-01 5.5858459323644638e-02</leafValues></_>
+            2.4982222914695740e-01 -8.8180385529994965e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 202 2.9547505080699921e-02</internalNodes>
+            0 -1 226 2.2136634215712547e-03</internalNodes>
           <leafValues>
-            5.4511282593011856e-02 -4.9024525284767151e-01</leafValues></_>
+            -1.4314906299114227e-01 1.6945528984069824e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 161 -5.3524523973464966e-03</internalNodes>
+            0 -1 640 1.6336794942617416e-02</internalNodes>
           <leafValues>
-            -4.3886002898216248e-01 5.9159737080335617e-02</leafValues></_>
+            4.6008959412574768e-02 -4.9338266253471375e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 159 2.2656358778476715e-03</internalNodes>
+            0 -1 459 7.9861842095851898e-03</internalNodes>
           <leafValues>
-            -1.4958912134170532e-01 1.9237321615219116e-01</leafValues></_>
+            -1.1460029333829880e-01 1.9282819330692291e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 272 -1.7663020640611649e-02</internalNodes>
+            0 -1 650 -1.7455726629123092e-03</internalNodes>
           <leafValues>
-            3.4963962435722351e-01 -9.8792962729930878e-02</leafValues></_>
+            1.7520657181739807e-01 -1.2269173562526703e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 135 -1.4769199490547180e-01</internalNodes>
+            0 -1 124 -6.2451506964862347e-03</internalNodes>
           <leafValues>
-            3.8789209723472595e-01 -7.4754111468791962e-02</leafValues></_>
+            -4.5638361573219299e-01 4.8106320202350616e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 961 -1.2649353593587875e-02</internalNodes>
+            0 -1 406 8.5668899118900299e-03</internalNodes>
           <leafValues>
-            3.6447465419769287e-01 -7.8627258539199829e-02</leafValues></_>
+            -8.0403454601764679e-02 3.0411326885223389e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 203 -1.6667589545249939e-01</internalNodes>
+            0 -1 974 8.6863581091165543e-03</internalNodes>
           <leafValues>
-            3.1024694442749023e-01 -9.8567992448806763e-02</leafValues></_>
+            3.4176670014858246e-02 -7.3028022050857544e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 823 1.5327525325119495e-03</internalNodes>
+            0 -1 36 1.0814646258950233e-02</internalNodes>
           <leafValues>
-            -8.7889634072780609e-02 3.3739477396011353e-01</leafValues></_>
+            2.5131458416581154e-02 -6.7325627803802490e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 37 -4.9399482086300850e-03</internalNodes>
+            0 -1 709 4.4222913682460785e-02</internalNodes>
           <leafValues>
-            -6.0582613945007324e-01 4.7072298824787140e-02</leafValues></_>
+            3.9326712489128113e-02 -5.1067680120468140e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 663 1.6168793663382530e-03</internalNodes>
+            0 -1 903 3.7128489930182695e-03</internalNodes>
           <leafValues>
-            -1.1102212965488434e-01 2.4625547230243683e-01</leafValues></_>
+            -1.3248492777347565e-01 1.6692358255386353e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 38 -7.9764677211642265e-03</internalNodes>
+            0 -1 129 -4.6475054696202278e-03</internalNodes>
           <leafValues>
-            -4.5467814803123474e-01 5.6168641895055771e-02</leafValues></_>
+            1.7683532834053040e-01 -1.2570241093635559e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 803 2.1164701320230961e-03</internalNodes>
+            0 -1 291 4.2433524504303932e-03</internalNodes>
           <leafValues>
-            3.9522409439086914e-02 -5.8244407176971436e-01</leafValues></_>
+            3.6985948681831360e-02 -5.8369445800781250e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 423 1.2181616621091962e-03</internalNodes>
+            0 -1 315 -5.1774000748991966e-03</internalNodes>
           <leafValues>
-            -1.1960548907518387e-01 1.8955740332603455e-01</leafValues></_>
+            5.1487326622009277e-01 -4.1473735123872757e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 414 6.2020774930715561e-02</internalNodes>
+            0 -1 855 4.2645614594221115e-03</internalNodes>
           <leafValues>
-            -9.2262148857116699e-02 2.4536235630512238e-01</leafValues></_>
+            3.7253957241773605e-02 -5.7676959037780762e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 98 1.5368127264082432e-02</internalNodes>
+            0 -1 83 4.8632645048201084e-03</internalNodes>
           <leafValues>
-            -7.4950158596038818e-02 3.8813439011573792e-01</leafValues></_>
+            -6.7035257816314697e-02 3.1131938099861145e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 631 -3.6116694100201130e-03</internalNodes>
+            0 -1 250 2.6089766994118690e-02</internalNodes>
           <leafValues>
-            -5.8402395248413086e-01 4.3880671262741089e-02</leafValues></_>
+            -8.2920446991920471e-02 3.0445784330368042e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 669 -5.4048337042331696e-03</internalNodes>
+            0 -1 625 -1.9001008477061987e-03</internalNodes>
           <leafValues>
-            2.7466323971748352e-01 -8.3315111696720123e-02</leafValues></_>
+            -4.3419414758682251e-01 4.6812325716018677e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 190 -5.7541755959391594e-03</internalNodes>
+            0 -1 891 -6.0952613130211830e-03</internalNodes>
           <leafValues>
-            -4.8696601390838623e-01 5.0719954073429108e-02</leafValues></_>
+            -5.1850622892379761e-01 3.6754775792360306e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 868 -8.8466441957280040e-04</internalNodes>
+            0 -1 564 1.2120242230594158e-02</internalNodes>
           <leafValues>
-            1.4997816085815430e-01 -1.4873522520065308e-01</leafValues></_>
+            -7.4773810803890228e-02 2.6738941669464111e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 419 -1.3690529391169548e-02</internalNodes>
+            0 -1 817 -1.8978580832481384e-02</internalNodes>
           <leafValues>
-            -4.2396122217178345e-01 5.1716264337301254e-02</leafValues></_>
+            2.5657230615615845e-01 -8.0304212868213654e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 231 -9.2098396271467209e-03</internalNodes>
+            0 -1 338 4.3438978493213654e-02</internalNodes>
           <leafValues>
-            -6.8742758035659790e-01 2.8357446193695068e-02</leafValues></_>
+            -6.2818735837936401e-02 3.2261833548545837e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 433 -1.0102453641593456e-02</internalNodes>
+            0 -1 773 9.4384723342955112e-04</internalNodes>
           <leafValues>
-            3.0423650145530701e-01 -7.5886160135269165e-02</leafValues></_>
+            -9.8582215607166290e-02 2.2370135784149170e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 789 -2.1283417008817196e-03</internalNodes>
+            0 -1 519 -4.1803726926445961e-03</internalNodes>
           <leafValues>
-            2.2551217675209045e-01 -9.5488928258419037e-02</leafValues></_>
+            -4.9802374839782715e-01 4.3809909373521805e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 675 2.2938135080039501e-03</internalNodes>
+            0 -1 195 -9.7246468067169189e-03</internalNodes>
           <leafValues>
-            3.2833088189363480e-02 -6.4737302064895630e-01</leafValues></_>
+            2.2823798656463623e-01 -9.8547600209712982e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 795 -2.0679826848208904e-03</internalNodes>
+            0 -1 658 2.7193846181035042e-03</internalNodes>
           <leafValues>
-            2.9072764515876770e-01 -8.1707596778869629e-02</leafValues></_>
+            -9.1188244521617889e-02 2.2684387862682343e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 495 1.8802012782543898e-03</internalNodes>
+            0 -1 174 6.2224082648754120e-03</internalNodes>
           <leafValues>
-            -1.0236340761184692e-01 2.4278828501701355e-01</leafValues></_>
+            3.2258503139019012e-02 -6.0108250379562378e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 566 -1.5465463511645794e-03</internalNodes>
+            0 -1 77 -4.8602908849716187e-01</internalNodes>
           <leafValues>
-            -3.8903787732124329e-01 5.6320030242204666e-02</leafValues></_>
+            6.3337916135787964e-01 -3.3006772398948669e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 630 6.3281953334808350e-03</internalNodes>
+            0 -1 550 -5.3604291751980782e-03</internalNodes>
           <leafValues>
-            -9.9905796349048615e-02 2.2087195515632629e-01</leafValues></_>
+            2.9434949159622192e-01 -6.1312302947044373e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 704 3.3235952258110046e-02</internalNodes>
+            0 -1 541 5.5021280422806740e-03</internalNodes>
           <leafValues>
-            5.0302099436521530e-02 -4.9443060159683228e-01</leafValues></_>
+            4.1839476674795151e-02 -4.5681878924369812e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 894 -1.9428483210504055e-03</internalNodes>
+            0 -1 326 -1.3823953922837973e-03</internalNodes>
           <leafValues>
-            -6.7564088106155396e-01 2.7948424220085144e-02</leafValues></_>
+            1.6067574918270111e-01 -1.1796293407678604e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 849 1.1729343095794320e-03</internalNodes>
+            0 -1 514 2.0954519510269165e-02</internalNodes>
           <leafValues>
-            -1.1950153112411499e-01 1.8506029248237610e-01</leafValues></_>
+            -5.7253565639257431e-02 3.3830171823501587e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 941 5.4220901802182198e-03</internalNodes>
+            0 -1 409 7.4234008789062500e-03</internalNodes>
           <leafValues>
-            5.0924405455589294e-02 -4.3448522686958313e-01</leafValues></_>
+            -7.4798591434955597e-02 2.6430690288543701e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 768 3.0700212810188532e-03</internalNodes>
+            0 -1 578 2.1767318248748779e-03</internalNodes>
           <leafValues>
-            -7.6845921576023102e-02 2.6929470896720886e-01</leafValues></_>
+            -8.0530151724815369e-02 2.5947657227516174e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 914 2.6065693236887455e-03</internalNodes>
+            0 -1 623 1.8930230289697647e-03</internalNodes>
           <leafValues>
-            5.5169116705656052e-02 -3.9985677599906921e-01</leafValues></_>
+            -8.1788897514343262e-02 2.2988820075988770e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 884 2.6848190464079380e-03</internalNodes>
+            0 -1 533 6.9275917485356331e-03</internalNodes>
           <leafValues>
-            2.7681041508913040e-02 -6.6643798351287842e-01</leafValues></_>
+            2.6962997391819954e-02 -7.6910203695297241e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 471 4.9525322392582893e-03</internalNodes>
+            0 -1 334 6.7140227183699608e-03</internalNodes>
           <leafValues>
-            -7.8715771436691284e-02 2.6918828487396240e-01</leafValues></_>
+            2.3244854062795639e-02 -6.8406605720520020e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 466 -1.2217788025736809e-02</internalNodes>
+            0 -1 632 -3.4494437277317047e-02</internalNodes>
           <leafValues>
-            2.5042393803596497e-01 -9.2959709465503693e-02</leafValues></_>
+            -6.5257686376571655e-01 2.4584138765931129e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 51 -9.7617935389280319e-03</internalNodes>
+            0 -1 787 1.9636256620287895e-03</internalNodes>
           <leafValues>
-            -5.8083361387252808e-01 4.1861489415168762e-02</leafValues></_>
+            -9.1118760406970978e-02 2.0629465579986572e-01</leafValues></_></weakClassifiers></_>
+    <!-- stage 14 -->
+    <_>
+      <maxWeakCount>80</maxWeakCount>
+      <stageThreshold>-1.3304495811462402e+00</stageThreshold>
+      <weakClassifiers>
         <_>
           <internalNodes>
-            0 -1 528 -3.0802208930253983e-03</internalNodes>
+            0 -1 572 -9.1053368523716927e-03</internalNodes>
           <leafValues>
-            -5.4920911788940430e-01 3.1410869210958481e-02</leafValues></_>
+            4.8031216859817505e-01 -9.3147851526737213e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 499 8.8869817554950714e-03</internalNodes>
+            0 -1 715 -2.1384856663644314e-03</internalNodes>
           <leafValues>
-            -5.7799737900495529e-02 3.5997068881988525e-01</leafValues></_>
+            3.4027156233787537e-01 -1.4834050834178925e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 383 -1.6894126310944557e-03</internalNodes>
+            0 -1 953 1.2453617528080940e-02</internalNodes>
           <leafValues>
-            1.5611077845096588e-01 -1.3526220619678497e-01</leafValues></_>
+            -8.0359503626823425e-02 4.7585478425025940e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 80 1.1576576158404350e-02</internalNodes>
+            0 -1 198 5.0965799018740654e-03</internalNodes>
           <leafValues>
-            2.6843478903174400e-02 -7.7421426773071289e-01</leafValues></_>
+            -1.6364066302776337e-01 2.9590085148811340e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 283 -1.0315187275409698e-02</internalNodes>
+            0 -1 477 -3.1894792336970568e-03</internalNodes>
           <leafValues>
-            -3.7911209464073181e-01 4.7785960137844086e-02</leafValues></_>
+            1.7039565742015839e-01 -2.1295401453971863e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 216 9.3458819901570678e-04</internalNodes>
+            0 -1 314 -1.4799979981034994e-03</internalNodes>
           <leafValues>
-            -1.0482961684465408e-01 1.9531208276748657e-01</leafValues></_>
+            -4.1050529479980469e-01 5.3783610463142395e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 225 -2.1154026035219431e-03</internalNodes>
+            0 -1 66 6.0710287652909756e-03</internalNodes>
           <leafValues>
-            3.2437980175018311e-01 -7.0380724966526031e-02</leafValues></_>
+            -1.5162153542041779e-01 1.8406888842582703e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 328 7.0915305987000465e-03</internalNodes>
+            0 -1 401 4.3081510812044144e-03</internalNodes>
           <leafValues>
-            3.1504381448030472e-02 -7.1498668193817139e-01</leafValues></_>
+            5.0293717533349991e-02 -4.6324169635772705e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 968 1.5262098750099540e-03</internalNodes>
+            0 -1 970 1.8933035898953676e-03</internalNodes>
           <leafValues>
-            4.3178513646125793e-02 -4.1175857186317444e-01</leafValues></_>
+            6.5655551850795746e-02 -3.9198148250579834e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 194 -2.6456830091774464e-03</internalNodes>
+            0 -1 782 -1.6021143645048141e-02</internalNodes>
           <leafValues>
-            -6.6830241680145264e-01 2.7078842744231224e-02</leafValues></_>
+            2.2748421132564545e-01 -1.0609938949346542e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 722 1.3623384293168783e-03</internalNodes>
+            0 -1 928 -8.9298677630722523e-04</internalNodes>
           <leafValues>
-            -9.6260324120521545e-02 1.9846718013286591e-01</leafValues></_>
+            3.1164079904556274e-01 -1.1380065232515335e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 672 -3.4019351005554199e-03</internalNodes>
+            0 -1 888 -1.4284942299127579e-03</internalNodes>
           <leafValues>
-            1.3638894259929657e-01 -1.4331445097923279e-01</leafValues></_>
+            2.7966943383216858e-01 -9.6580952405929565e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 667 -4.2538799345493317e-02</internalNodes>
+            0 -1 822 2.5015190243721008e-02</internalNodes>
           <leafValues>
-            -6.8543094396591187e-01 2.7219040319323540e-02</leafValues></_>
+            4.2534209787845612e-02 -6.2623745203018188e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 572 5.1494771614670753e-03</internalNodes>
+            0 -1 583 -2.8645459096878767e-03</internalNodes>
           <leafValues>
-            -8.3506844937801361e-02 2.4553795158863068e-01</leafValues></_>
+            -4.1426309943199158e-01 5.1780503243207932e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 509 -1.3525998219847679e-03</internalNodes>
+            0 -1 902 3.2044243998825550e-03</internalNodes>
           <leafValues>
-            2.0083853602409363e-01 -1.1441762000322342e-01</leafValues></_>
+            -1.1883606761693954e-01 1.9546063244342804e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 889 -4.7460300847887993e-03</internalNodes>
+            0 -1 319 -1.0433372110128403e-02</internalNodes>
           <leafValues>
-            -5.8234161138534546e-01 3.3193428069353104e-02</leafValues></_>
+            2.6159819960594177e-01 -9.3164652585983276e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 559 -1.8419034779071808e-02</internalNodes>
+            0 -1 287 -9.7299478948116302e-03</internalNodes>
           <leafValues>
-            2.5098413228988647e-01 -7.8263558447360992e-02</leafValues></_>
+            -4.9464005231857300e-01 5.0998747348785400e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 837 -3.6029946058988571e-03</internalNodes>
+            0 -1 206 -2.1688457578420639e-02</internalNodes>
           <leafValues>
-            2.5004243850708008e-01 -7.8106440603733063e-02</leafValues></_>
+            5.6923902034759521e-01 -4.9958106130361557e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 12 1.0855928063392639e-02</internalNodes>
+            0 -1 38 -2.9492072761058807e-02</internalNodes>
           <leafValues>
-            3.8721837103366852e-02 -5.0439488887786865e-01</leafValues></_>
+            -6.1336356401443481e-01 4.7003138810396194e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 6 3.1823229044675827e-02</internalNodes>
+            0 -1 35 -2.4866596795618534e-03</internalNodes>
           <leafValues>
-            2.8006808832287788e-02 -6.5438795089721680e-01</leafValues></_>
+            -3.9986124634742737e-01 5.7781789451837540e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 35 9.0156495571136475e-02</internalNodes>
+            0 -1 965 4.0488247759640217e-03</internalNodes>
           <leafValues>
-            3.6854032427072525e-02 -4.6750095486640930e-01</leafValues></_>
+            4.6429801732301712e-02 -4.4500553607940674e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 876 8.1275019329041243e-04</internalNodes>
+            0 -1 735 -9.3909690622240305e-04</internalNodes>
           <leafValues>
-            -8.1435337662696838e-02 2.3081797361373901e-01</leafValues></_>
+            2.4617424607276917e-01 -9.0848781168460846e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 843 -2.2238264791667461e-03</internalNodes>
+            0 -1 989 -5.2673118188977242e-03</internalNodes>
           <leafValues>
-            -4.6506562829017639e-01 4.2775552719831467e-02</leafValues></_>
+            -6.4129960536956787e-01 3.5207435488700867e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 21 8.5265887901186943e-03</internalNodes>
+            0 -1 806 -6.1755320057272911e-03</internalNodes>
           <leafValues>
-            -9.9068634212017059e-02 1.8661868572235107e-01</leafValues></_>
+            1.7039734125137329e-01 -1.3195209205150604e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 601 5.0247795879840851e-03</internalNodes>
+            0 -1 201 1.5832348726689816e-03</internalNodes>
           <leafValues>
-            3.5677276551723480e-02 -5.6390231847763062e-01</leafValues></_>
+            -9.2635877430438995e-02 2.5755262374877930e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 353 1.2137264013290405e-02</internalNodes>
+            0 -1 914 2.8633023612201214e-03</internalNodes>
           <leafValues>
-            2.3600205779075623e-02 -6.9947057962417603e-01</leafValues></_>
+            5.0923369824886322e-02 -4.6171438694000244e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 687 5.8652815641835332e-04</internalNodes>
+            0 -1 12 -2.3722708225250244e-02</internalNodes>
           <leafValues>
-            -1.0546504706144333e-01 1.8301849067211151e-01</leafValues></_>
+            -4.5609694719314575e-01 4.3677136301994324e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 783 -1.2803040444850922e-02</internalNodes>
+            0 -1 419 5.8846692554652691e-03</internalNodes>
           <leafValues>
-            2.4169570207595825e-01 -9.3701913952827454e-02</leafValues></_>
+            5.1512561738491058e-02 -4.4899132847785950e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 362 1.9234570208936930e-03</internalNodes>
+            0 -1 201 -8.2513026427477598e-04</internalNodes>
           <leafValues>
-            4.1152808815240860e-02 -5.3527724742889404e-01</leafValues></_>
+            2.4914309382438660e-01 -8.9795768260955811e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 413 -5.1119372248649597e-02</internalNodes>
+            0 -1 690 -2.9888928402215242e-03</internalNodes>
           <leafValues>
-            2.0418803393840790e-01 -1.0016205906867981e-01</leafValues></_>
+            -4.0133482217788696e-01 5.5449619889259338e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 643 2.0427668467164040e-02</internalNodes>
+            0 -1 237 1.8384978175163269e-02</internalNodes>
           <leafValues>
-            3.8303721696138382e-02 -5.6752574443817139e-01</leafValues></_>
+            4.9513496458530426e-02 -4.2024865746498108e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 916 1.0702429572120309e-03</internalNodes>
+            0 -1 947 -2.4238843470811844e-03</internalNodes>
           <leafValues>
-            -1.1941519379615784e-01 1.5449772775173187e-01</leafValues></_>
+            -6.7325645685195923e-01 2.8972415253520012e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 45 6.3908234238624573e-02</internalNodes>
+            0 -1 724 8.1563717685639858e-04</internalNodes>
           <leafValues>
-            -8.0574154853820801e-02 2.4723786115646362e-01</leafValues></_>
+            -1.4400914311408997e-01 1.5184181928634644e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 239 -8.9891534298658371e-03</internalNodes>
+            0 -1 315 2.1788734011352062e-03</internalNodes>
           <leafValues>
-            2.7232396602630615e-01 -7.9600028693675995e-02</leafValues></_>
+            -8.2650899887084961e-02 2.5927037000656128e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 181 -7.4440538883209229e-03</internalNodes>
+            0 -1 376 3.7263201083987951e-03</internalNodes>
           <leafValues>
-            1.7151834070682526e-01 -1.1733634769916534e-01</leafValues></_>
+            -6.3213117420673370e-02 3.8062268495559692e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 298 9.3747628852725029e-03</internalNodes>
+            0 -1 631 3.0819473322480917e-03</internalNodes>
           <leafValues>
-            -5.8857422322034836e-02 3.3993646502494812e-01</leafValues></_>
+            3.9066124707460403e-02 -6.2055569887161255e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 890 3.9659179747104645e-03</internalNodes>
+            0 -1 691 2.7417289093136787e-03</internalNodes>
           <leafValues>
-            3.7981141358613968e-02 -5.3772449493408203e-01</leafValues></_>
+            3.2166294753551483e-02 -5.6402361392974854e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 698 -2.7701430954039097e-03</internalNodes>
+            0 -1 581 -3.8205389864742756e-03</internalNodes>
           <leafValues>
-            2.1686923503875732e-01 -9.1246932744979858e-02</leafValues></_>
+            2.5668358802795410e-01 -7.9121366143226624e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 592 -3.0083605088293552e-03</internalNodes>
+            0 -1 61 -1.2516178190708160e-02</internalNodes>
           <leafValues>
-            -5.1033967733383179e-01 3.8351774215698242e-02</leafValues></_>
+            -7.0402121543884277e-01 3.2493114471435547e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 40 5.2285091951489449e-03</internalNodes>
+            0 -1 60 4.6941628679633141e-03</internalNodes>
           <leafValues>
-            6.6746503114700317e-02 -2.5510028004646301e-01</leafValues></_>
+            4.7352086752653122e-02 -4.0129581093788147e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 542 2.6635453104972839e-03</internalNodes>
+            0 -1 483 5.0501096993684769e-03</internalNodes>
           <leafValues>
-            -8.8651068508625031e-02 2.1260604262351990e-01</leafValues></_>
+            -1.0563907027244568e-01 2.3647888004779816e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 545 -3.4417591989040375e-02</internalNodes>
+            0 -1 497 1.5111428685486317e-02</internalNodes>
           <leafValues>
-            -6.6850775480270386e-01 3.1463332474231720e-02</leafValues></_>
+            -6.7443214356899261e-02 2.7579694986343384e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 550 -9.7544072195887566e-04</internalNodes>
+            0 -1 423 7.4835181236267090e-02</internalNodes>
           <leafValues>
-            2.0566202700138092e-01 -1.0702812671661377e-01</leafValues></_>
+            -6.2918186187744141e-02 3.6493194103240967e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 361 1.6097709536552429e-01</internalNodes>
+            0 -1 498 1.3086002320051193e-02</internalNodes>
           <leafValues>
-            -4.7826759517192841e-02 3.8993999361991882e-01</leafValues></_>
+            2.9699811711907387e-02 -7.4420636892318726e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 489 1.0004348587244749e-03</internalNodes>
+            0 -1 778 -5.4838880896568298e-03</internalNodes>
           <leafValues>
-            -1.0796900838613510e-01 2.1362201869487762e-01</leafValues></_>
+            2.2497597336769104e-01 -8.8018722832202911e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 420 4.0136128664016724e-03</internalNodes>
+            0 -1 261 3.3699360210448503e-03</internalNodes>
           <leafValues>
-            -8.1376187503337860e-02 2.2793699800968170e-01</leafValues></_>
+            -6.9213069975376129e-02 2.9263094067573547e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 562 3.2076346687972546e-03</internalNodes>
+            0 -1 118 7.7881952747702599e-03</internalNodes>
           <leafValues>
-            -1.0031759738922119e-01 2.2700363397598267e-01</leafValues></_>
+            5.8034870773553848e-02 -3.9803403615951538e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 53 -4.1395910084247589e-03</internalNodes>
+            0 -1 421 -1.9298251718282700e-02</internalNodes>
           <leafValues>
-            -4.5727050304412842e-01 4.4953804463148117e-02</leafValues></_>
+            2.1273820102214813e-01 -9.6075013279914856e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 595 4.9559203907847404e-03</internalNodes>
+            0 -1 440 1.3059679418802261e-02</internalNodes>
           <leafValues>
-            3.0349666252732277e-02 -5.6468343734741211e-01</leafValues></_>
+            4.0989801287651062e-02 -4.9787399172782898e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 835 1.9516122993081808e-03</internalNodes>
+            0 -1 510 -2.2303011268377304e-02</internalNodes>
           <leafValues>
-            -8.4078930318355560e-02 2.1666139364242554e-01</leafValues></_>
+            -6.5915608406066895e-01 2.7258813381195068e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 200 2.8487551957368851e-02</internalNodes>
+            0 -1 260 -5.2872681990265846e-03</internalNodes>
           <leafValues>
-            -5.8517321944236755e-02 3.7208831310272217e-01</leafValues></_></weakClassifiers></_>
-    <!-- stage 11 -->
-    <_>
-      <maxWeakCount>100</maxWeakCount>
-      <stageThreshold>-1.5313543081283569e+00</stageThreshold>
-      <weakClassifiers>
+            2.9461637139320374e-01 -6.9564543664455414e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 865 -1.1964191682636738e-02</internalNodes>
+            0 -1 464 6.0780980857089162e-04</internalNodes>
           <leafValues>
-            6.5611332654953003e-01 8.7084025144577026e-02</leafValues></_>
+            -9.5468334853649139e-02 2.0951601862907410e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 570 -3.6326241679489613e-03</internalNodes>
+            0 -1 444 4.8917778767645359e-03</internalNodes>
           <leafValues>
-            3.0753159523010254e-01 -2.0207116007804871e-01</leafValues></_>
+            3.9317954331636429e-02 -5.3803342580795288e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 739 1.6091932775452733e-03</internalNodes>
+            0 -1 238 -1.0402110219001770e-01</internalNodes>
           <leafValues>
-            -2.1601480245590210e-01 2.4574394524097443e-01</leafValues></_>
+            5.4199391603469849e-01 -3.9763871580362320e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 151 -1.0807140171527863e-01</internalNodes>
+            0 -1 687 3.8908584974706173e-03</internalNodes>
           <leafValues>
-            5.8551537990570068e-01 -8.0984398722648621e-02</leafValues></_>
+            3.8185238838195801e-02 -5.3280067443847656e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 122 6.6386028192937374e-03</internalNodes>
+            0 -1 353 8.0125425010919571e-03</internalNodes>
           <leafValues>
-            -2.3309321701526642e-01 2.5712442398071289e-01</leafValues></_>
+            -7.8310973942279816e-02 2.4926608800888062e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 480 6.6436373163014650e-04</internalNodes>
+            0 -1 954 -3.4356187097728252e-03</internalNodes>
           <leafValues>
-            -1.7002807557582855e-01 2.2093741595745087e-01</leafValues></_>
+            2.3415692150592804e-01 -9.2279240489006042e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 109 5.9623841661959887e-04</internalNodes>
+            0 -1 896 -5.2030328661203384e-03</internalNodes>
           <leafValues>
-            -2.1071858704090118e-01 1.5259474515914917e-01</leafValues></_>
+            -5.0255048274993896e-01 4.4738721102476120e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 296 -2.1322746761143208e-03</internalNodes>
+            0 -1 555 -5.5568795651197433e-03</internalNodes>
           <leafValues>
-            -3.6114820837974548e-01 7.9649142920970917e-02</leafValues></_>
+            2.8329169750213623e-01 -7.0860259234905243e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 102 -6.9360136985778809e-03</internalNodes>
+            0 -1 627 -7.6205702498555183e-03</internalNodes>
           <leafValues>
-            -5.2729552984237671e-01 5.9225857257843018e-02</leafValues></_>
+            2.5350978970527649e-01 -7.2612494230270386e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 1 7.2746481746435165e-03</internalNodes>
+            0 -1 309 2.7379104495048523e-01</internalNodes>
           <leafValues>
-            -1.5284915268421173e-01 2.0500071346759796e-01</leafValues></_>
+            -5.6398060172796249e-02 3.6085364222526550e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 793 -2.4507325142621994e-03</internalNodes>
+            0 -1 622 7.3067229241132736e-03</internalNodes>
           <leafValues>
-            -4.4374018907546997e-01 6.2125567346811295e-02</leafValues></_>
+            -6.2759615480899811e-02 3.1996127963066101e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 677 -1.1941835284233093e-01</internalNodes>
+            0 -1 415 3.2574313227087259e-03</internalNodes>
           <leafValues>
-            5.9646230936050415e-01 -5.0393357872962952e-02</leafValues></_>
+            4.1181974112987518e-02 -4.9355933070182800e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 830 2.4319710209965706e-03</internalNodes>
+            0 -1 57 -1.2764024734497070e-01</internalNodes>
           <leafValues>
-            -1.4628271758556366e-01 2.2020979225635529e-01</leafValues></_>
+            2.5147503614425659e-01 -7.5440123677253723e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 503 4.0825735777616501e-03</internalNodes>
+            0 -1 530 -3.2227888703346252e-02</internalNodes>
           <leafValues>
-            4.6519946306943893e-02 -6.0437613725662231e-01</leafValues></_>
+            3.9548832178115845e-01 -4.7284111380577087e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 112 3.3597379922866821e-02</internalNodes>
+            0 -1 764 2.3350853472948074e-02</internalNodes>
           <leafValues>
-            5.5770415812730789e-02 -4.4832473993301392e-01</leafValues></_>
+            -7.2977773845195770e-02 2.5172060728073120e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 142 -4.1159454733133316e-02</internalNodes>
+            0 -1 26 2.7610745746642351e-05</internalNodes>
           <leafValues>
-            -4.2802116274833679e-01 5.6050233542919159e-02</leafValues></_>
+            -1.3625738024711609e-01 1.3250400125980377e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 357 -3.1343686860054731e-03</internalNodes>
+            0 -1 808 6.9611091166734695e-03</internalNodes>
           <leafValues>
-            -4.5189481973648071e-01 4.5713383704423904e-02</leafValues></_>
+            2.9794082045555115e-02 -5.8855760097503662e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 449 -3.9362995885312557e-03</internalNodes>
+            0 -1 210 -9.9057564511895180e-04</internalNodes>
           <leafValues>
-            2.6333171129226685e-01 -8.6672604084014893e-02</leafValues></_>
+            2.5895762443542480e-01 -7.1211874485015869e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 274 -3.4228354692459106e-02</internalNodes>
+            0 -1 218 -3.7965672090649605e-03</internalNodes>
           <leafValues>
-            2.8555384278297424e-01 -8.0961830914020538e-02</leafValues></_>
+            -6.4451014995574951e-01 3.5450231283903122e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 192 2.3194378241896629e-02</internalNodes>
+            0 -1 346 3.9518065750598907e-03</internalNodes>
           <leafValues>
-            -1.0957508534193039e-01 2.6531192660331726e-01</leafValues></_>
+            -6.3615679740905762e-02 3.0333930253982544e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 812 1.1790241114795208e-03</internalNodes>
+            0 -1 282 -5.4976264946162701e-03</internalNodes>
           <leafValues>
-            -1.2578412890434265e-01 2.2350181639194489e-01</leafValues></_>
+            -4.3285435438156128e-01 4.7526597976684570e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 757 2.4525973945856094e-02</internalNodes>
+            0 -1 721 7.1266246959567070e-03</internalNodes>
           <leafValues>
-            3.9447281509637833e-02 -6.4369696378707886e-01</leafValues></_>
+            -6.6810697317123413e-02 2.8491511940956116e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 234 -5.5821083486080170e-02</internalNodes>
+            0 -1 912 -3.0366722494363785e-03</internalNodes>
           <leafValues>
-            3.8404938578605652e-01 -6.1516307294368744e-02</leafValues></_>
+            -4.3046197295188904e-01 4.4313102960586548e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 297 8.5053090006113052e-03</internalNodes>
+            0 -1 714 -1.7097850795835257e-03</internalNodes>
           <leafValues>
-            -1.1682828515768051e-01 2.0639540255069733e-01</leafValues></_>
+            2.5873449444770813e-01 -7.3857538402080536e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 28 -4.6913616359233856e-02</internalNodes>
+            0 -1 702 -4.4310283847153187e-03</internalNodes>
           <leafValues>
-            -3.3303919434547424e-01 6.8057745695114136e-02</leafValues></_>
+            2.1451152861118317e-01 -8.7626561522483826e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 531 -6.0622256249189377e-02</internalNodes>
+            0 -1 47 -3.9760642684996128e-03</internalNodes>
           <leafValues>
-            3.0634361505508423e-01 -8.0411903560161591e-02</leafValues></_>
+            -4.6889033913612366e-01 3.8441929966211319e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 962 3.3126091584563255e-03</internalNodes>
+            0 -1 683 -2.9741778969764709e-02</internalNodes>
           <leafValues>
-            6.4039744436740875e-02 -3.6264923214912415e-01</leafValues></_>
+            -5.5860131978988647e-01 3.0309556052088737e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 923 -6.2155202031135559e-03</internalNodes>
+            0 -1 13 1.3289751112461090e-01</internalNodes>
           <leafValues>
-            2.6324889063835144e-01 -8.5208639502525330e-02</leafValues></_>
+            2.8634676709771156e-02 -5.6014162302017212e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 840 -3.6174536217004061e-03</internalNodes>
+            0 -1 386 -1.1272695846855640e-03</internalNodes>
           <leafValues>
-            -6.3895624876022339e-01 3.7891831248998642e-02</leafValues></_>
+            1.7104774713516235e-01 -1.0818520933389664e-01</leafValues></_></weakClassifiers></_>
+    <!-- stage 15 -->
+    <_>
+      <maxWeakCount>83</maxWeakCount>
+      <stageThreshold>-1.2789946794509888e+00</stageThreshold>
+      <weakClassifiers>
         <_>
           <internalNodes>
-            0 -1 321 -3.0694848392158747e-03</internalNodes>
+            0 -1 649 1.3820428401231766e-02</internalNodes>
           <leafValues>
-            2.7301403880119324e-01 -8.3168596029281616e-02</leafValues></_>
+            -1.0330537706613541e-01 4.5001628994941711e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 106 -1.6663860296830535e-03</internalNodes>
+            0 -1 834 -1.0161036625504494e-02</internalNodes>
           <leafValues>
-            -4.9059715867042542e-01 4.4817935675382614e-02</leafValues></_>
+            3.2188063859939575e-01 -1.5805941820144653e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 36 1.6716115176677704e-02</internalNodes>
+            0 -1 398 -3.8372592534869909e-03</internalNodes>
           <leafValues>
-            6.0621056705713272e-02 -3.4729966521263123e-01</leafValues></_>
+            3.2943242788314819e-01 -1.1501405388116837e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 401 1.3494723476469517e-02</internalNodes>
+            0 -1 769 3.4624878317117691e-02</internalNodes>
           <leafValues>
-            3.1516350805759430e-02 -6.2451899051666260e-01</leafValues></_>
+            -9.8698168992996216e-02 5.4050970077514648e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 321 1.9665439613163471e-03</internalNodes>
+            0 -1 437 5.7967011816799641e-03</internalNodes>
           <leafValues>
-            -8.6126960813999176e-02 2.5302976369857788e-01</leafValues></_>
+            -1.1608023941516876e-01 2.8170758485794067e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 477 -2.8690965846180916e-02</internalNodes>
+            0 -1 754 4.7825248911976814e-03</internalNodes>
           <leafValues>
-            2.9214075207710266e-01 -6.8187572062015533e-02</leafValues></_>
+            -1.3033217191696167e-01 2.4669390916824341e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 430 5.4161301814019680e-03</internalNodes>
+            0 -1 74 7.1141775697469711e-04</internalNodes>
           <leafValues>
-            -8.5594080388545990e-02 2.6200750470161438e-01</leafValues></_>
+            -2.0435671508312225e-01 1.1761441081762314e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 269 -3.6381594836711884e-02</internalNodes>
+            0 -1 22 -2.9168082401156425e-02</internalNodes>
           <leafValues>
-            -5.9561169147491455e-01 3.6925114691257477e-02</leafValues></_>
+            -6.2692928314208984e-01 5.5113222450017929e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 421 -6.7269792780280113e-03</internalNodes>
+            0 -1 796 2.1553519181907177e-03</internalNodes>
           <leafValues>
-            -7.9720497131347656e-01 2.4374464526772499e-02</leafValues></_>
+            5.3858544677495956e-02 -4.2096143960952759e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 947 -7.4932668358087540e-03</internalNodes>
+            0 -1 894 -2.1254396997392178e-03</internalNodes>
           <leafValues>
-            -8.1190264225006104e-01 1.9826157018542290e-02</leafValues></_>
+            4.2603659629821777e-01 -5.0405498594045639e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 165 -5.5202767252922058e-03</internalNodes>
+            0 -1 894 8.4234733367338777e-04</internalNodes>
           <leafValues>
-            1.8447315692901611e-01 -1.1608960479497910e-01</leafValues></_>
+            -9.3583315610885620e-02 2.6316204667091370e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 869 2.9039490036666393e-03</internalNodes>
+            0 -1 948 -1.6576268244534731e-03</internalNodes>
           <leafValues>
-            6.3957199454307556e-02 -3.0787152051925659e-01</leafValues></_>
+            -3.5802370309829712e-01 6.8603202700614929e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 41 2.4206712841987610e-01</internalNodes>
+            0 -1 554 6.5620511770248413e-02</internalNodes>
           <leafValues>
-            -3.4878797829151154e-02 5.9678316116333008e-01</leafValues></_>
+            -6.4758449792861938e-02 3.8339248299598694e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 901 5.8509008958935738e-03</internalNodes>
+            0 -1 361 -1.8485928885638714e-03</internalNodes>
           <leafValues>
-            -8.4465004503726959e-02 2.3755706846714020e-01</leafValues></_>
+            1.7337062954902649e-01 -1.3676019012928009e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 943 1.1404031887650490e-02</internalNodes>
+            0 -1 305 -1.8170465528964996e-01</internalNodes>
           <leafValues>
-            -6.2884598970413208e-02 3.3538460731506348e-01</leafValues></_>
+            4.0350264310836792e-01 -5.3196940571069717e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 946 -6.4798449166119099e-03</internalNodes>
+            0 -1 848 -3.4317909739911556e-03</internalNodes>
           <leafValues>
-            2.6907229423522949e-01 -8.0378860235214233e-02</leafValues></_>
+            -5.2157330513000488e-01 4.6489212661981583e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 175 -1.5257325768470764e-01</internalNodes>
+            0 -1 800 -2.7482535224407911e-03</internalNodes>
           <leafValues>
-            3.7274152040481567e-01 -5.3593669086694717e-02</leafValues></_>
+            -5.1078474521636963e-01 4.3557438999414444e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 300 -7.8410096466541290e-03</internalNodes>
+            0 -1 731 -4.7894287854433060e-03</internalNodes>
           <leafValues>
-            3.5559067130088806e-01 -6.0485389083623886e-02</leafValues></_>
+            3.4981805086135864e-01 -6.5036587417125702e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 895 4.6420615399256349e-04</internalNodes>
+            0 -1 706 -3.3211666159331799e-03</internalNodes>
           <leafValues>
-            -1.3953977823257446e-01 1.4700867235660553e-01</leafValues></_>
+            2.1143883466720581e-01 -1.1754662543535233e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 365 -2.7928948402404785e-03</internalNodes>
+            0 -1 677 3.5642951726913452e-02</internalNodes>
           <leafValues>
-            -3.7794330716133118e-01 5.3649291396141052e-02</leafValues></_>
+            3.7131600081920624e-02 -6.2165355682373047e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 761 -6.2361196614801884e-03</internalNodes>
+            0 -1 481 -3.1561930663883686e-03</internalNodes>
           <leafValues>
-            2.3622865974903107e-01 -8.5419490933418274e-02</leafValues></_>
+            -4.2197883129119873e-01 4.7645546495914459e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 758 -1.0482727549970150e-02</internalNodes>
+            0 -1 872 5.2224877290427685e-03</internalNodes>
           <leafValues>
-            -4.9808895587921143e-01 4.5149747282266617e-02</leafValues></_>
+            -1.0117106884717941e-01 2.1957167983055115e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 728 5.1559107378125191e-03</internalNodes>
+            0 -1 140 2.5758458301424980e-02</internalNodes>
           <leafValues>
-            -8.4864191710948944e-02 2.6940858364105225e-01</leafValues></_>
+            -9.6981137990951538e-02 3.0423089861869812e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 854 1.3875829055905342e-02</internalNodes>
+            0 -1 567 2.8883803170174360e-03</internalNodes>
           <leafValues>
-            -6.8634092807769775e-02 3.0264788866043091e-01</leafValues></_>
+            4.4947806745767593e-02 -5.5540132522583008e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 549 2.0931879989802837e-03</internalNodes>
+            0 -1 484 2.6014349423348904e-03</internalNodes>
           <leafValues>
-            -8.1713855266571045e-02 2.2649072110652924e-01</leafValues></_>
+            4.5947834849357605e-02 -4.1711980104446411e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 580 2.2430280223488808e-03</internalNodes>
+            0 -1 257 -7.8792509157210588e-04</internalNodes>
           <leafValues>
-            3.2463703304529190e-02 -6.4346092939376831e-01</leafValues></_>
+            1.5732656419277191e-01 -1.2769798934459686e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 686 9.5147592946887016e-03</internalNodes>
+            0 -1 252 4.2199464514851570e-03</internalNodes>
           <leafValues>
-            2.9569771140813828e-02 -5.5541282892227173e-01</leafValues></_>
+            -9.4008974730968475e-02 2.6868444681167603e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 358 -1.5026458539068699e-02</internalNodes>
+            0 -1 571 -2.4246796965599060e-03</internalNodes>
           <leafValues>
-            2.9199507832527161e-01 -6.7493163049221039e-02</leafValues></_>
+            -4.9610009789466858e-01 4.6141009777784348e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 576 -3.0254235025495291e-03</internalNodes>
+            0 -1 465 -1.8996626604348421e-03</internalNodes>
           <leafValues>
-            -3.6120423674583435e-01 5.3320098668336868e-02</leafValues></_>
+            2.6260954141616821e-01 -8.5721127688884735e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 543 -3.7556474562734365e-03</internalNodes>
+            0 -1 945 1.8048105994239450e-03</internalNodes>
           <leafValues>
-            2.4651855230331421e-01 -7.6555579900741577e-02</leafValues></_>
+            7.1231566369533539e-02 -3.2751160860061646e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 870 5.2875939756631851e-02</internalNodes>
+            0 -1 249 -5.6593962945044041e-03</internalNodes>
           <leafValues>
-            -6.2019556760787964e-02 3.0396047234535217e-01</leafValues></_>
+            -5.0264769792556763e-01 4.0275387465953827e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 915 -6.4307113643735647e-04</internalNodes>
+            0 -1 940 -3.4701074473559856e-03</internalNodes>
           <leafValues>
-            1.4872814714908600e-01 -1.2868101894855499e-01</leafValues></_>
+            -4.9033272266387939e-01 3.6995064467191696e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 802 -2.7651647105813026e-02</internalNodes>
+            0 -1 766 1.1992279905825853e-03</internalNodes>
           <leafValues>
-            -4.7678905725479126e-01 4.2087376117706299e-02</leafValues></_>
+            -9.3982182443141937e-02 2.2527951002120972e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 673 -2.5210313033312559e-03</internalNodes>
+            0 -1 528 -3.3614276908338070e-03</internalNodes>
           <leafValues>
-            -6.7401230335235596e-01 2.5271434336900711e-02</leafValues></_>
+            1.5591301023960114e-01 -1.3875743746757507e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 107 -1.7504607094451785e-03</internalNodes>
+            0 -1 758 9.2923380434513092e-03</internalNodes>
           <leafValues>
-            -6.6526460647583008e-01 2.3153429850935936e-02</leafValues></_>
+            2.8368480503559113e-02 -6.3946157693862915e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 137 -1.2022716924548149e-02</internalNodes>
+            0 -1 98 -1.6806223988533020e-01</internalNodes>
           <leafValues>
-            -6.5252929925918579e-01 2.4157531559467316e-02</leafValues></_>
+            -6.3519150018692017e-01 2.4432161822915077e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 23 -1.6721414402127266e-02</internalNodes>
+            0 -1 614 -1.5483988681808114e-03</internalNodes>
           <leafValues>
-            2.0145316421985626e-01 -8.8073857128620148e-02</leafValues></_>
+            -4.9389392137527466e-01 3.4452050924301147e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 664 -6.1156335286796093e-03</internalNodes>
+            0 -1 961 7.9401559196412563e-04</internalNodes>
           <leafValues>
-            2.3662807047367096e-01 -8.2179009914398193e-02</leafValues></_>
+            -1.6395612061023712e-01 1.1427336186170578e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 726 4.1717891581356525e-03</internalNodes>
+            0 -1 245 -5.3670424968004227e-03</internalNodes>
           <leafValues>
-            3.0463650822639465e-02 -6.4868044853210449e-01</leafValues></_>
+            -5.4615026712417603e-01 3.2274313271045685e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 83 1.0461646597832441e-03</internalNodes>
+            0 -1 923 -5.1019818056374788e-04</internalNodes>
           <leafValues>
-            -1.0331799834966660e-01 1.7261520028114319e-01</leafValues></_>
+            1.4040225744247437e-01 -1.2673649191856384e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 158 -7.5713603291660547e-04</internalNodes>
+            0 -1 846 -9.6546392887830734e-04</internalNodes>
           <leafValues>
-            2.2451940178871155e-01 -9.4167023897171021e-02</leafValues></_>
+            2.3117446899414062e-01 -7.7826015651226044e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 377 -5.1019098609685898e-03</internalNodes>
+            0 -1 994 -9.7423873376101255e-04</internalNodes>
           <leafValues>
-            1.7748890817165375e-01 -1.0525784641504288e-01</leafValues></_>
+            -4.0673121809959412e-01 4.6749390661716461e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 951 5.8564399369060993e-03</internalNodes>
+            0 -1 970 -4.7841384075582027e-03</internalNodes>
           <leafValues>
-            2.7441246435046196e-02 -6.8668657541275024e-01</leafValues></_>
+            -5.0288796424865723e-01 3.4186109900474548e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 331 3.8241008296608925e-03</internalNodes>
+            0 -1 89 6.8537802435457706e-03</internalNodes>
           <leafValues>
-            -6.8950459361076355e-02 2.7575340867042542e-01</leafValues></_>
+            5.0501946359872818e-02 -3.5414797067642212e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 174 1.1478068307042122e-02</internalNodes>
+            0 -1 651 4.1695050895214081e-03</internalNodes>
           <leafValues>
-            3.9409350603818893e-02 -5.4299759864807129e-01</leafValues></_>
+            -6.8471699953079224e-02 2.8334242105484009e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 605 -1.4753835275769234e-03</internalNodes>
+            0 -1 391 2.6521178369875997e-05</internalNodes>
           <leafValues>
-            -4.5533245801925659e-01 3.6614906042814255e-02</leafValues></_>
+            -1.7646598815917969e-01 1.0057727992534637e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 605 9.4340764917433262e-04</internalNodes>
+            0 -1 674 -1.8193974392488599e-03</internalNodes>
           <leafValues>
-            6.0544602572917938e-02 -2.9981470108032227e-01</leafValues></_>
+            -5.2059328556060791e-01 3.4266594797372818e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 599 -3.6590839736163616e-03</internalNodes>
+            0 -1 284 1.1680822353810072e-03</internalNodes>
           <leafValues>
-            2.3720666766166687e-01 -8.0204457044601440e-02</leafValues></_>
+            -7.5169444084167480e-02 2.3740953207015991e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 100 -3.1423069536685944e-02</internalNodes>
+            0 -1 284 -5.8111123507842422e-04</internalNodes>
           <leafValues>
-            -7.1167147159576416e-01 2.8132835403084755e-02</leafValues></_>
+            2.4673853814601898e-01 -8.9036554098129272e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 403 3.5741357132792473e-03</internalNodes>
+            0 -1 789 5.5753946304321289e-02</internalNodes>
           <leafValues>
-            1.7519874498248100e-02 -8.3257293701171875e-01</leafValues></_>
+            -4.8898559063673019e-02 3.7110447883605957e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 585 -6.8605719134211540e-03</internalNodes>
+            0 -1 388 -6.0947462916374207e-03</internalNodes>
           <leafValues>
-            -6.9204151630401611e-01 2.0872814580798149e-02</leafValues></_>
+            -4.8019152879714966e-01 3.6990296095609665e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 902 -8.8996449485421181e-03</internalNodes>
+            0 -1 988 3.3249799162149429e-03</internalNodes>
           <leafValues>
-            1.8208101391792297e-01 -9.8315775394439697e-02</leafValues></_>
+            3.2017692923545837e-02 -4.8544195294380188e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 881 6.5573323518037796e-03</internalNodes>
+            0 -1 586 -1.1994136497378349e-02</internalNodes>
           <leafValues>
-            -7.4690498411655426e-02 2.5062057375907898e-01</leafValues></_>
+            2.7767661213874817e-01 -6.2677264213562012e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 912 1.4275535941123962e-02</internalNodes>
+            0 -1 940 1.9462420605123043e-03</internalNodes>
           <leafValues>
-            2.7385318651795387e-02 -6.8721151351928711e-01</leafValues></_>
+            5.7167824357748032e-02 -3.2460683584213257e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 241 -2.1887188777327538e-03</internalNodes>
+            0 -1 482 -3.5742400214076042e-03</internalNodes>
           <leafValues>
-            -4.7836220264434814e-01 3.3499576151371002e-02</leafValues></_>
+            2.1856486797332764e-01 -7.7333562076091766e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 6 1.9212976098060608e-02</internalNodes>
+            0 -1 543 3.4013153053820133e-03</internalNodes>
           <leafValues>
-            5.0344366580247879e-02 -3.3104887604713440e-01</leafValues></_>
+            -9.4114005565643311e-02 2.3269242048263550e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 521 1.0552004911005497e-02</internalNodes>
+            0 -1 859 6.4494553953409195e-03</internalNodes>
           <leafValues>
-            -9.7779601812362671e-02 2.0047651231288910e-01</leafValues></_>
+            3.4765381366014481e-02 -5.1627504825592041e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 883 -4.9180793575942516e-04</internalNodes>
+            0 -1 163 -1.2767435982823372e-02</internalNodes>
           <leafValues>
-            1.4232192933559418e-01 -1.3171885907649994e-01</leafValues></_>
+            2.5566741824150085e-01 -6.7411571741104126e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 964 3.2934427261352539e-02</internalNodes>
+            0 -1 230 2.2043818607926369e-03</internalNodes>
           <leafValues>
-            2.9324809089303017e-02 -5.8789533376693726e-01</leafValues></_>
+            -1.3278621435165405e-01 1.7942063510417938e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 305 -1.9249429460614920e-03</internalNodes>
+            0 -1 229 -4.0757502429187298e-03</internalNodes>
           <leafValues>
-            1.5106591582298279e-01 -1.2231025844812393e-01</leafValues></_>
+            -3.8042715191841125e-01 4.4863421469926834e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 729 -4.4266097247600555e-03</internalNodes>
+            0 -1 730 2.2066584788262844e-03</internalNodes>
           <leafValues>
-            2.6083472371101379e-01 -7.3457822203636169e-02</leafValues></_>
+            -7.0331946015357971e-02 2.5572371482849121e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 666 -3.5673312842845917e-02</internalNodes>
+            0 -1 700 2.2714279592037201e-02</internalNodes>
           <leafValues>
-            -6.6919100284576416e-01 2.9960991814732552e-02</leafValues></_>
+            4.1653785854578018e-02 -4.4101753830909729e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 602 -8.5658043622970581e-02</internalNodes>
+            0 -1 749 -1.1373223736882210e-02</internalNodes>
           <leafValues>
-            -5.1538497209548950e-01 2.9327427968382835e-02</leafValues></_>
+            3.2443967461585999e-01 -5.8059785515069962e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 348 -3.5126551985740662e-02</internalNodes>
+            0 -1 835 1.8165379296988249e-03</internalNodes>
           <leafValues>
-            2.3199184238910675e-01 -7.9689562320709229e-02</leafValues></_>
+            -7.2351627051830292e-02 2.2953742742538452e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 123 5.8309547603130341e-03</internalNodes>
+            0 -1 235 -2.8745923191308975e-03</internalNodes>
           <leafValues>
-            3.0431609600782394e-02 -6.1856180429458618e-01</leafValues></_>
+            -3.9090758562088013e-01 4.6148840337991714e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 22 -4.4557070359587669e-03</internalNodes>
+            0 -1 673 -5.7676057331264019e-03</internalNodes>
           <leafValues>
-            2.6333442330360413e-01 -7.0679754018783569e-02</leafValues></_>
+            2.4503223598003387e-01 -7.2128646075725555e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 373 1.2730281800031662e-02</internalNodes>
+            0 -1 177 1.2852130457758904e-02</internalNodes>
           <leafValues>
-            -6.6051281988620758e-02 3.1401801109313965e-01</leafValues></_>
+            -1.1143829673528671e-01 1.6758553683757782e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 498 -4.6875262632966042e-03</internalNodes>
+            0 -1 141 -4.2651765048503876e-02</internalNodes>
           <leafValues>
-            1.9294278323650360e-01 -1.0184600949287415e-01</leafValues></_>
+            2.3846423625946045e-01 -7.9255387187004089e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 195 -2.9066612478345633e-03</internalNodes>
+            0 -1 24 -6.8766735494136810e-03</internalNodes>
           <leafValues>
-            1.9944235682487488e-01 -9.2275582253932953e-02</leafValues></_>
+            -3.9145267009735107e-01 5.2240811288356781e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 482 -3.1784668099135160e-03</internalNodes>
+            0 -1 15 -1.5351611375808716e-01</internalNodes>
           <leafValues>
-            -4.1009154915809631e-01 4.5929219573736191e-02</leafValues></_>
+            -5.4598790407180786e-01 2.9950620606541634e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 618 -3.7226981949061155e-03</internalNodes>
+            0 -1 280 -1.7586871981620789e-02</internalNodes>
           <leafValues>
-            2.2945560514926910e-01 -7.6773315668106079e-02</leafValues></_></weakClassifiers></_>
-    <!-- stage 12 -->
-    <_>
-      <maxWeakCount>100</maxWeakCount>
-      <stageThreshold>-1.6428810358047485e+00</stageThreshold>
-      <weakClassifiers>
+            2.4160921573638916e-01 -7.7404774725437164e-02</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 557 2.8469474054872990e-03</internalNodes>
+          <leafValues>
+            -7.1562752127647400e-02 2.3895153403282166e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 777 3.3433635253459215e-03</internalNodes>
+            0 -1 493 -2.6379337534308434e-02</internalNodes>
           <leafValues>
-            7.8417956829071045e-02 6.1746358871459961e-01</leafValues></_>
+            2.7370086312294006e-01 -6.5483018755912781e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 171 4.1375826112926006e-03</internalNodes>
+            0 -1 759 -6.6346197854727507e-04</internalNodes>
           <leafValues>
-            -1.0486003011465073e-01 4.9714615941047668e-01</leafValues></_>
+            1.7174075543880463e-01 -1.0841262340545654e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 512 -5.4358085617423058e-03</internalNodes>
+            0 -1 736 1.4637422282248735e-03</internalNodes>
           <leafValues>
-            2.9817372560501099e-01 -1.8134090304374695e-01</leafValues></_>
+            -1.1365657299757004e-01 1.6123561561107635e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 734 5.7432046160101891e-03</internalNodes>
+            0 -1 569 -1.3798776781186461e-03</internalNodes>
           <leafValues>
-            -2.1621760725975037e-01 2.8316897153854370e-01</leafValues></_>
+            2.3192690312862396e-01 -7.5626462697982788e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 56 -2.2321434225887060e-03</internalNodes>
+            0 -1 516 -6.8256547674536705e-03</internalNodes>
           <leafValues>
-            2.0751045644283295e-01 -1.5781952440738678e-01</leafValues></_>
+            2.4984428286552429e-01 -7.2457753121852875e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 113 1.4339581131935120e-02</internalNodes>
+            0 -1 312 -9.0181883424520493e-03</internalNodes>
           <leafValues>
-            -9.7252883017063141e-02 4.0868076682090759e-01</leafValues></_>
+            2.0358866453170776e-01 -9.5499873161315918e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 205 -1.1081973090767860e-02</internalNodes>
+            0 -1 218 3.1383798923343420e-03</internalNodes>
           <leafValues>
-            3.3920571208000183e-01 -1.0915800184011459e-01</leafValues></_>
+            4.0804021060466766e-02 -4.9618390202522278e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 332 1.4586398378014565e-02</internalNodes>
+            0 -1 171 -1.8526764586567879e-02</internalNodes>
           <leafValues>
-            -8.6110286414623260e-02 3.1800067424774170e-01</leafValues></_>
+            2.2743205726146698e-01 -8.6628310382366180e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 369 -1.6978669445961714e-03</internalNodes>
+            0 -1 594 -2.2562327794730663e-03</internalNodes>
           <leafValues>
-            2.5036969780921936e-01 -1.2437737733125687e-01</leafValues></_>
+            -3.2850387692451477e-01 5.9250634163618088e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 708 1.2829914689064026e-02</internalNodes>
+            0 -1 432 -4.1183121502399445e-03</internalNodes>
           <leafValues>
-            5.1119163632392883e-02 -5.4143118858337402e-01</leafValues></_>
+            -5.0281947851181030e-01 3.2455049455165863e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 675 -1.6196181531995535e-03</internalNodes>
+            0 -1 96 4.8136096447706223e-03</internalNodes>
           <leafValues>
-            -5.3631567955017090e-01 4.6280529350042343e-02</leafValues></_>
+            3.1708184629678726e-02 -4.9248033761978149e-01</leafValues></_></weakClassifiers></_>
+    <!-- stage 16 -->
+    <_>
+      <maxWeakCount>90</maxWeakCount>
+      <stageThreshold>-1.2794928550720215e+00</stageThreshold>
+      <weakClassifiers>
         <_>
           <internalNodes>
-            0 -1 897 -2.3190132342278957e-03</internalNodes>
+            0 -1 568 -4.7569684684276581e-03</internalNodes>
           <leafValues>
-            -4.3289941549301147e-01 6.0517251491546631e-02</leafValues></_>
+            4.4339472055435181e-01 -1.0486443340778351e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 212 3.5206928849220276e-02</internalNodes>
+            0 -1 795 -2.5423073675483465e-03</internalNodes>
           <leafValues>
-            -9.1207198798656464e-02 3.1217202544212341e-01</leafValues></_>
+            3.9922216534614563e-01 -1.0431514680385590e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 763 3.1395033001899719e-03</internalNodes>
+            0 -1 649 1.1162508279085159e-02</internalNodes>
           <leafValues>
-            -7.8746505081653595e-02 3.6259949207305908e-01</leafValues></_>
+            -1.5686489641666412e-01 2.3129878938198090e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 262 1.1297637596726418e-02</internalNodes>
+            0 -1 847 1.7287035007029772e-03</internalNodes>
           <leafValues>
-            7.4857383966445923e-02 -3.7226554751396179e-01</leafValues></_>
+            -1.5123696625232697e-01 2.9676723480224609e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 786 4.6712577342987061e-02</internalNodes>
+            0 -1 265 2.5025676935911179e-02</internalNodes>
           <leafValues>
-            -9.2495582997798920e-02 2.9710096120834351e-01</leafValues></_>
+            -5.1661748439073563e-02 4.8509848117828369e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 323 -6.8688929080963135e-02</internalNodes>
+            0 -1 78 1.2561861425638199e-02</internalNodes>
           <leafValues>
-            -4.8226192593574524e-01 4.9391020089387894e-02</leafValues></_>
+            -1.1817755550146103e-01 2.6937758922576904e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 969 -3.5051193553954363e-03</internalNodes>
+            0 -1 812 4.6598571352660656e-03</internalNodes>
           <leafValues>
-            -4.8506668210029602e-01 4.1722387075424194e-02</leafValues></_>
+            -1.3565555214881897e-01 2.1206009387969971e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 694 1.1046628467738628e-02</internalNodes>
+            0 -1 434 7.4310216587036848e-04</internalNodes>
           <leafValues>
-            -5.4003205150365829e-02 4.2598679661750793e-01</leafValues></_>
+            -1.7020516097545624e-01 1.5990819036960602e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 26 -2.0021714270114899e-02</internalNodes>
+            0 -1 231 1.0259399190545082e-02</internalNodes>
           <leafValues>
-            -4.3884435296058655e-01 4.9609564244747162e-02</leafValues></_>
+            -1.4796857535839081e-01 1.8798792362213135e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 59 1.1850561946630478e-02</internalNodes>
+            0 -1 278 -1.2777388095855713e-02</internalNodes>
           <leafValues>
-            -7.8088991343975067e-02 2.7602908015251160e-01</leafValues></_>
+            -5.4041445255279541e-01 4.8501875251531601e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 180 4.1900265961885452e-02</internalNodes>
+            0 -1 489 -1.1427352204918861e-02</internalNodes>
           <leafValues>
-            -9.9447727203369141e-02 2.0865923166275024e-01</leafValues></_>
+            -5.1071381568908691e-01 4.8088576644659042e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 590 -2.9064953327178955e-02</internalNodes>
+            0 -1 819 2.8340169592411257e-05</internalNodes>
           <leafValues>
-            2.9170644283294678e-01 -7.3766425251960754e-02</leafValues></_>
+            -2.0961570739746094e-01 1.0582420229911804e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 474 -2.6618237607181072e-03</internalNodes>
+            0 -1 325 -6.4714960753917694e-03</internalNodes>
           <leafValues>
-            -3.2550674676895142e-01 7.5278282165527344e-02</leafValues></_>
+            -5.0862830877304077e-01 4.8812258988618851e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 342 3.2252955716103315e-03</internalNodes>
+            0 -1 367 1.3540303334593773e-02</internalNodes>
           <leafValues>
-            -6.9696784019470215e-02 3.1337058544158936e-01</leafValues></_>
+            2.7134107425808907e-02 -7.1317195892333984e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 582 7.8913231845945120e-04</internalNodes>
+            0 -1 210 1.8916794797405601e-03</internalNodes>
           <leafValues>
-            6.9301478564739227e-02 -3.2840612530708313e-01</leafValues></_>
+            -6.2187314033508301e-02 3.6233416199684143e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 287 6.6613638773560524e-03</internalNodes>
+            0 -1 51 1.0457850992679596e-02</internalNodes>
           <leafValues>
-            4.5366134494543076e-02 -4.4648596644401550e-01</leafValues></_>
+            4.0487006306648254e-02 -5.3173840045928955e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 721 1.9416993018239737e-03</internalNodes>
+            0 -1 893 -9.0822251513600349e-04</internalNodes>
           <leafValues>
-            -1.3086521625518799e-01 1.5360382199287415e-01</leafValues></_>
+            2.0090451836585999e-01 -1.0807146877050400e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 633 6.0106818564236164e-03</internalNodes>
+            0 -1 535 -1.9299473613500595e-02</internalNodes>
           <leafValues>
-            4.8219148069620132e-02 -4.1355597972869873e-01</leafValues></_>
+            -6.4914399385452271e-01 4.0790289640426636e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 267 -6.8208400625735521e-04</internalNodes>
+            0 -1 663 -8.2283990923315287e-04</internalNodes>
           <leafValues>
-            1.6169321537017822e-01 -1.2492433935403824e-01</leafValues></_>
+            1.5708251297473907e-01 -1.3143004477024078e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 756 1.0027646087110043e-02</internalNodes>
+            0 -1 523 3.7520762998610735e-03</internalNodes>
           <leafValues>
-            3.0267864465713501e-02 -6.4555937051773071e-01</leafValues></_>
+            3.8761712610721588e-02 -4.9775493144989014e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 948 -6.4138583838939667e-03</internalNodes>
+            0 -1 762 8.2424264401197433e-03</internalNodes>
           <leafValues>
-            -6.9905740022659302e-01 2.3570762947201729e-02</leafValues></_>
+            3.6369498819112778e-02 -5.1153117418289185e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 270 4.4392300769686699e-03</internalNodes>
+            0 -1 805 -1.1945937294512987e-03</internalNodes>
           <leafValues>
-            -5.8655023574829102e-02 3.3790254592895508e-01</leafValues></_>
+            1.3862735033035278e-01 -1.3917639851570129e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 556 3.8361353799700737e-03</internalNodes>
+            0 -1 985 -1.0589268989861012e-02</internalNodes>
           <leafValues>
-            3.1548105180263519e-02 -6.6295272111892700e-01</leafValues></_>
+            3.2981950044631958e-01 -7.6042778789997101e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 872 -1.0007477831095457e-03</internalNodes>
+            0 -1 128 2.6780981570482254e-02</internalNodes>
           <leafValues>
-            2.2688214480876923e-01 -8.8843353092670441e-02</leafValues></_>
+            4.6954374760389328e-02 -4.5390221476554871e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 928 4.7894790768623352e-03</internalNodes>
+            0 -1 705 5.2458671852946281e-03</internalNodes>
           <leafValues>
-            3.0278960242867470e-02 -6.1569523811340332e-01</leafValues></_>
+            -4.7804936766624451e-02 4.0361502766609192e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 946 5.6278239935636520e-03</internalNodes>
+            0 -1 729 1.0518019553273916e-03</internalNodes>
           <leafValues>
-            -7.8841529786586761e-02 2.4433708190917969e-01</leafValues></_>
+            -1.0052871704101562e-01 1.9928459823131561e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 942 -7.3229577392339706e-03</internalNodes>
+            0 -1 407 3.9210864342749119e-03</internalNodes>
           <leafValues>
-            3.3265948295593262e-01 -6.7663870751857758e-02</leafValues></_>
+            3.6381114274263382e-02 -5.4954099655151367e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 29 -4.5515028759837151e-03</internalNodes>
+            0 -1 873 -1.5182888135313988e-02</internalNodes>
           <leafValues>
-            -4.6472606062889099e-01 4.3983772397041321e-02</leafValues></_>
+            2.8286656737327576e-01 -7.6106920838356018e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 293 1.8201436614617705e-03</internalNodes>
+            0 -1 279 2.7552489191293716e-03</internalNodes>
           <leafValues>
-            -8.1468850374221802e-02 2.3861412703990936e-01</leafValues></_>
+            -1.2027227133512497e-01 2.0814672112464905e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 134 -1.1703525483608246e-01</internalNodes>
+            0 -1 869 1.3051946647465229e-02</internalNodes>
           <leafValues>
-            -6.7043519020080566e-01 2.9206298291683197e-02</leafValues></_>
+            3.6561664193868637e-02 -6.8296074867248535e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 314 -5.0897812470793724e-03</internalNodes>
+            0 -1 849 4.4104140251874924e-03</internalNodes>
           <leafValues>
-            5.1766836643218994e-01 -4.1514929383993149e-02</leafValues></_>
+            2.9448021203279495e-02 -5.9994471073150635e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 72 -8.7873879820108414e-03</internalNodes>
+            0 -1 799 2.3885946720838547e-03</internalNodes>
           <leafValues>
-            -5.2038532495498657e-01 4.0998894721269608e-02</leafValues></_>
+            3.9816807955503464e-02 -4.6116915345191956e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 183 -5.6120483204722404e-03</internalNodes>
+            0 -1 551 2.3683100007474422e-03</internalNodes>
           <leafValues>
-            -7.3375105857849121e-01 2.1229419857263565e-02</leafValues></_>
+            4.9801617860794067e-02 -3.9546611905097961e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 244 1.0250378400087357e-02</internalNodes>
+            0 -1 707 -4.1178334504365921e-03</internalNodes>
           <leafValues>
-            2.5667199864983559e-02 -6.1355572938919067e-01</leafValues></_>
+            1.6903834044933319e-01 -1.1102814227342606e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 771 -4.8573492094874382e-03</internalNodes>
+            0 -1 466 -2.7111368253827095e-03</internalNodes>
           <leafValues>
-            1.6895917057991028e-01 -1.1120435595512390e-01</leafValues></_>
+            2.0166625082492828e-01 -9.3054622411727905e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 312 2.5750461965799332e-02</internalNodes>
+            0 -1 360 -2.4442467838525772e-03</internalNodes>
           <leafValues>
-            3.5605397075414658e-02 -5.4535841941833496e-01</leafValues></_>
+            1.3419428467750549e-01 -1.4021472632884979e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 932 4.1080308146774769e-03</internalNodes>
+            0 -1 104 -6.9398069754242897e-03</internalNodes>
           <leafValues>
-            5.0505056977272034e-02 -3.3836016058921814e-01</leafValues></_>
+            -4.7041961550712585e-01 3.8327444344758987e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 317 3.9434060454368591e-03</internalNodes>
+            0 -1 14 -7.5376339256763458e-02</internalNodes>
           <leafValues>
-            -8.8688671588897705e-02 2.0660057663917542e-01</leafValues></_>
+            3.5196593403816223e-01 -5.8293107897043228e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 553 6.5294457599520683e-03</internalNodes>
+            0 -1 270 -7.3061959119513631e-04</internalNodes>
           <leafValues>
-            -1.2931570410728455e-01 1.6514816880226135e-01</leafValues></_>
+            2.0563322305679321e-01 -9.7862586379051208e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 931 2.2269077599048615e-02</internalNodes>
+            0 -1 339 -4.4864090159535408e-03</internalNodes>
           <leafValues>
-            -4.7366518527269363e-02 3.8508006930351257e-01</leafValues></_>
+            -4.3219071626663208e-01 4.6815373003482819e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 455 3.5300105810165405e-03</internalNodes>
+            0 -1 679 -3.3369990997016430e-03</internalNodes>
           <leafValues>
-            5.3873997181653976e-02 -3.3755952119827271e-01</leafValues></_>
+            -5.7968968152999878e-01 3.2250367105007172e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 286 -2.4763222783803940e-02</internalNodes>
+            0 -1 636 -5.7756435126066208e-03</internalNodes>
           <leafValues>
-            -3.2349804043769836e-01 5.6731209158897400e-02</leafValues></_>
+            -6.3823670148849487e-01 2.6716385036706924e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 790 3.1297234818339348e-03</internalNodes>
+            0 -1 352 3.8174313958734274e-03</internalNodes>
           <leafValues>
-            -6.7191042006015778e-02 2.7804708480834961e-01</leafValues></_>
+            -7.8204549849033356e-02 2.4104152619838715e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 621 -1.7003760440275073e-03</internalNodes>
+            0 -1 414 3.9163082838058472e-03</internalNodes>
           <leafValues>
-            -4.2539414763450623e-01 4.3875113129615784e-02</leafValues></_>
+            4.0961768478155136e-02 -4.2656800150871277e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 750 8.3633856847882271e-03</internalNodes>
+            0 -1 670 -3.7615487817674875e-03</internalNodes>
           <leafValues>
-            3.0976327136158943e-02 -5.2819561958312988e-01</leafValues></_>
+            2.0846015214920044e-01 -8.6097449064254761e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 473 -8.7768933735787868e-04</internalNodes>
+            0 -1 371 -9.5803234726190567e-03</internalNodes>
           <leafValues>
-            1.9984373450279236e-01 -9.0307638049125671e-02</leafValues></_>
+            -7.0837384462356567e-01 2.8397833928465843e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 874 -9.2862239107489586e-03</internalNodes>
+            0 -1 93 1.4632595703005791e-02</internalNodes>
           <leafValues>
-            -6.9824051856994629e-01 2.5733994320034981e-02</leafValues></_>
+            1.8669826909899712e-02 -7.4236363172531128e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 393 -1.1124708689749241e-03</internalNodes>
+            0 -1 234 5.3799869492650032e-03</internalNodes>
           <leafValues>
-            1.9901444017887115e-01 -9.2606224119663239e-02</leafValues></_>
+            3.0915707349777222e-02 -4.7074958682060242e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 575 -3.2134181819856167e-03</internalNodes>
+            0 -1 701 -2.4318110663443804e-03</internalNodes>
           <leafValues>
-            2.3832809925079346e-01 -7.1890726685523987e-02</leafValues></_>
+            3.0304560065269470e-01 -5.6169599294662476e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 516 5.9113521128892899e-03</internalNodes>
+            0 -1 641 3.8594864308834076e-02</internalNodes>
           <leafValues>
-            -6.7413553595542908e-02 2.7445399761199951e-01</leafValues></_>
+            2.5472542271018028e-02 -6.8472218513488770e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 615 -4.5188870280981064e-03</internalNodes>
+            0 -1 125 1.6673290729522705e-01</internalNodes>
           <leafValues>
-            -4.0147483348846436e-01 4.4757787138223648e-02</leafValues></_>
+            -5.9959251433610916e-02 2.9591250419616699e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 48 2.8254585340619087e-03</internalNodes>
+            0 -1 854 -5.0129964947700500e-03</internalNodes>
           <leafValues>
-            4.3743204325437546e-02 -3.7922030687332153e-01</leafValues></_>
+            1.9718486070632935e-01 -9.4902090728282928e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 637 -2.6064300909638405e-03</internalNodes>
+            0 -1 960 -9.3115903437137604e-03</internalNodes>
           <leafValues>
-            2.0811253786087036e-01 -8.2700952887535095e-02</leafValues></_>
+            2.8306549787521362e-01 -6.8168632686138153e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 635 1.0516709880903363e-03</internalNodes>
+            0 -1 804 -2.7176579460501671e-03</internalNodes>
           <leafValues>
-            -8.9635595679283142e-02 2.6205003261566162e-01</leafValues></_>
+            2.4883794784545898e-01 -7.3830418288707733e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 453 -1.2204772792756557e-03</internalNodes>
+            0 -1 787 6.9358374457806349e-04</internalNodes>
           <leafValues>
-            2.0626722276210785e-01 -8.6367763578891754e-02</leafValues></_>
+            -1.2474948167800903e-01 1.6316886246204376e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 765 5.0495425239205360e-03</internalNodes>
+            0 -1 783 1.3523821253329515e-03</internalNodes>
           <leafValues>
-            4.5425735414028168e-02 -4.1301593184471130e-01</leafValues></_>
+            -7.3475763201713562e-02 3.0120497941970825e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 440 -3.2243374735116959e-03</internalNodes>
+            0 -1 532 -2.6339504867792130e-02</internalNodes>
           <leafValues>
-            1.4690431952476501e-01 -1.2587989866733551e-01</leafValues></_>
+            4.7823980450630188e-01 -3.9222836494445801e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 340 -2.3263287730515003e-03</internalNodes>
+            0 -1 866 3.3510509878396988e-02</internalNodes>
           <leafValues>
-            -4.1975629329681396e-01 4.7924898564815521e-02</leafValues></_>
+            -3.8013227283954620e-02 4.1955846548080444e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 307 -5.4887672886252403e-03</internalNodes>
+            0 -1 694 -2.8097369067836553e-05</internalNodes>
           <leafValues>
-            -4.1799965500831604e-01 3.8171879947185516e-02</leafValues></_>
+            1.2249568104743958e-01 -1.4184975624084473e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 628 4.6792116016149521e-02</internalNodes>
+            0 -1 988 -4.0141213685274124e-03</internalNodes>
           <leafValues>
-            -5.7823952287435532e-02 3.2188871502876282e-01</leafValues></_>
+            -4.5551317930221558e-01 3.6903131753206253e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 824 2.3481161333620548e-03</internalNodes>
+            0 -1 934 5.7984986342489719e-03</internalNodes>
           <leafValues>
-            -5.3754303604364395e-02 3.0415624380111694e-01</leafValues></_>
+            3.9383981376886368e-02 -4.0305584669113159e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 179 -3.5063792020082474e-03</internalNodes>
+            0 -1 753 7.5392555445432663e-03</internalNodes>
           <leafValues>
-            -3.8483345508575439e-01 4.7024305909872055e-02</leafValues></_>
+            -9.3996182084083557e-02 1.8520636856555939e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 247 1.6757374396547675e-03</internalNodes>
+            0 -1 943 4.5007485896348953e-03</internalNodes>
           <leafValues>
-            -1.3115778565406799e-01 1.6631519794464111e-01</leafValues></_>
+            4.2565450072288513e-02 -4.0628531575202942e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 232 1.1546656489372253e-02</internalNodes>
+            0 -1 500 5.0333794206380844e-03</internalNodes>
           <leafValues>
-            -5.0141811370849609e-02 3.1787791848182678e-01</leafValues></_>
+            -6.7051678895950317e-02 2.5224363803863525e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 504 1.8043547868728638e-02</internalNodes>
+            0 -1 511 8.7359821191057563e-04</internalNodes>
           <leafValues>
-            2.5008214637637138e-02 -7.1255826950073242e-01</leafValues></_>
+            -9.5469102263450623e-02 1.7292767763137817e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 204 -3.1235523521900177e-02</internalNodes>
+            0 -1 771 3.0778967775404453e-03</internalNodes>
           <leafValues>
-            2.1876916289329529e-01 -7.7429860830307007e-02</leafValues></_>
+            -6.1908006668090820e-02 2.5266119837760925e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 248 9.7835529595613480e-03</internalNodes>
+            0 -1 835 -2.2874618880450726e-03</internalNodes>
           <leafValues>
-            -5.6040864437818527e-02 2.7669593691825867e-01</leafValues></_>
+            1.9187310338020325e-01 -8.5145145654678345e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 341 2.8905952349305153e-03</internalNodes>
+            0 -1 634 4.0947222150862217e-03</internalNodes>
           <leafValues>
-            5.1800269633531570e-02 -3.1925117969512939e-01</leafValues></_>
+            3.0908439308404922e-02 -5.5290663242340088e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 436 7.8792851418256760e-03</internalNodes>
+            0 -1 488 2.1358881145715714e-02</internalNodes>
           <leafValues>
-            -6.0856487601995468e-02 2.8146442770957947e-01</leafValues></_>
+            4.0033571422100067e-02 -3.8174301385879517e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 717 1.3523480854928493e-02</internalNodes>
+            0 -1 159 -4.5840246602892876e-03</internalNodes>
           <leafValues>
-            2.4503752589225769e-02 -7.2409152984619141e-01</leafValues></_>
+            -5.2027910947799683e-01 3.0034648254513741e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 966 3.1048720702528954e-03</internalNodes>
+            0 -1 232 9.8655056208372116e-03</internalNodes>
           <leafValues>
-            4.5725930482149124e-02 -3.3751598000526428e-01</leafValues></_>
+            2.1588459610939026e-02 -6.3089925050735474e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 808 -1.0647572576999664e-02</internalNodes>
+            0 -1 223 2.5678081437945366e-03</internalNodes>
           <leafValues>
-            -5.4894274473190308e-01 2.8428088873624802e-02</leafValues></_>
+            -1.1046713590621948e-01 1.4713281393051147e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 49 -4.8104384914040565e-03</internalNodes>
+            0 -1 688 -2.6078277733176947e-03</internalNodes>
           <leafValues>
-            2.0432402193546295e-01 -8.2248799502849579e-02</leafValues></_>
+            2.7103677392005920e-01 -5.9257075190544128e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 4 2.7336277067661285e-02</internalNodes>
+            0 -1 355 2.6908484287559986e-03</internalNodes>
           <leafValues>
-            -6.7068248987197876e-02 2.3702095448970795e-01</leafValues></_>
+            2.7514556422829628e-02 -6.3733005523681641e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 940 -1.7123305797576904e-01</internalNodes>
+            0 -1 715 -1.3983637327328324e-03</internalNodes>
           <leafValues>
-            5.2998173236846924e-01 -3.1578365713357925e-02</leafValues></_>
+            1.5699537098407745e-01 -1.0462216287851334e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 781 -4.3723154813051224e-03</internalNodes>
+            0 -1 433 1.0498151183128357e-01</internalNodes>
           <leafValues>
-            2.8745722770690918e-01 -5.7618625462055206e-02</leafValues></_>
+            3.0471364036202431e-02 -4.9990084767341614e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 743 6.7968526855111122e-03</internalNodes>
+            0 -1 491 -1.4592260122299194e-01</internalNodes>
           <leafValues>
-            -6.3940502703189850e-02 2.5016403198242188e-01</leafValues></_>
+            3.2007977366447449e-01 -5.2097231149673462e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 47 -1.6302993753924966e-03</internalNodes>
+            0 -1 825 7.8754723072052002e-03</internalNodes>
           <leafValues>
-            -2.6190960407257080e-01 6.1918053776025772e-02</leafValues></_>
+            -6.7778728902339935e-02 2.8044930100440979e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 712 1.7953850328922272e-03</internalNodes>
+            0 -1 262 -5.3792521357536316e-03</internalNodes>
           <leafValues>
-            -5.3176742047071457e-02 3.0019727349281311e-01</leafValues></_>
+            2.1354769170284271e-01 -8.2902953028678894e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 311 6.2259500846266747e-03</internalNodes>
+            0 -1 420 -1.0021779686212540e-02</internalNodes>
           <leafValues>
-            3.1048897653818130e-02 -5.6447005271911621e-01</leafValues></_>
+            2.5685080885887146e-01 -7.3165819048881531e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 712 -1.4370339922606945e-03</internalNodes>
+            0 -1 1 -4.2762188240885735e-03</internalNodes>
           <leafValues>
-            1.8240424990653992e-01 -8.9968219399452209e-02</leafValues></_>
+            1.7162682116031647e-01 -9.7696490585803986e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 226 -9.0678166598081589e-03</internalNodes>
+            0 -1 67 1.0965526103973389e-02</internalNodes>
           <leafValues>
-            -6.3961440324783325e-01 2.3404622450470924e-02</leafValues></_>
+            -7.5053967535495758e-02 2.3615135252475739e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 604 -8.2531813532114029e-03</internalNodes>
+            0 -1 328 -4.4276113621890545e-03</internalNodes>
           <leafValues>
-            -5.9389066696166992e-01 2.3573497310280800e-02</leafValues></_>
+            2.5747051835060120e-01 -6.3898853957653046e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 573 -2.2232248447835445e-03</internalNodes>
+            0 -1 276 -8.6840223520994186e-03</internalNodes>
           <leafValues>
-            1.9480818510055542e-01 -8.3372615277767181e-02</leafValues></_>
+            -4.7478455305099487e-01 3.6790292710065842e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 355 -6.5612345933914185e-03</internalNodes>
+            0 -1 938 2.8339526616036892e-03</internalNodes>
           <leafValues>
-            -4.2599579691886902e-01 3.7793021649122238e-02</leafValues></_>
+            4.0944386273622513e-02 -3.6514538526535034e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 571 1.2282801326364279e-03</internalNodes>
+            0 -1 790 7.6391562819480896e-02</internalNodes>
           <leafValues>
-            -8.5198581218719482e-02 1.9753733277320862e-01</leafValues></_>
+            -4.9489263445138931e-02 3.4142583608627319e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 162 -1.0268764197826385e-01</internalNodes>
+            0 -1 148 1.9103729864582419e-03</internalNodes>
           <leafValues>
-            -3.9634877443313599e-01 4.0690928697586060e-02</leafValues></_>
+            -5.6329321116209030e-02 2.9177185893058777e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 711 -1.5864435583353043e-02</internalNodes>
+            0 -1 304 5.2499733865261078e-02</internalNodes>
           <leafValues>
-            1.9112223386764526e-01 -8.7620854377746582e-02</leafValues></_>
+            2.8848636895418167e-02 -5.9306102991104126e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 715 4.8304852680303156e-04</internalNodes>
+            0 -1 956 -5.0793914124369621e-03</internalNodes>
           <leafValues>
-            -1.2651769816875458e-01 1.5627197921276093e-01</leafValues></_></weakClassifiers></_>
-    <!-- stage 13 -->
+            -5.0588577985763550e-01 2.8303196653723717e-02</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 967 -7.1491668932139874e-03</internalNodes>
+          <leafValues>
+            -6.2660187482833862e-01 2.3113224655389786e-02</leafValues></_></weakClassifiers></_>
+    <!-- stage 17 -->
     <_>
-      <maxWeakCount>100</maxWeakCount>
-      <stageThreshold>-1.5192077159881592e+00</stageThreshold>
+      <maxWeakCount>88</maxWeakCount>
+      <stageThreshold>-1.2153301239013672e+00</stageThreshold>
       <weakClassifiers>
         <_>
           <internalNodes>
-            0 -1 563 -7.2759687900543213e-03</internalNodes>
+            0 -1 803 3.5730558447539806e-03</internalNodes>
           <leafValues>
-            6.4157706499099731e-01 1.0701754689216614e-01</leafValues></_>
+            -4.2218949645757675e-02 5.5067819356918335e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 713 -3.8208619225770235e-03</internalNodes>
+            0 -1 520 1.0531613603234291e-02</internalNodes>
           <leafValues>
-            4.9172374606132507e-01 -9.4503603875637054e-02</leafValues></_>
+            -1.0848262906074524e-01 4.2079353332519531e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 817 3.4225741401314735e-03</internalNodes>
+            0 -1 570 -2.8240748215466738e-03</internalNodes>
           <leafValues>
-            -1.3255690038204193e-01 3.2899302244186401e-01</leafValues></_>
+            1.5155430138111115e-01 -2.2742147743701935e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 384 3.3628481905907393e-03</internalNodes>
+            0 -1 384 -1.6008135862648487e-03</internalNodes>
           <leafValues>
-            -1.6529263556003571e-01 3.8905930519104004e-01</leafValues></_>
+            2.9879093170166016e-01 -1.0573560744524002e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 400 4.2874794453382492e-03</internalNodes>
+            0 -1 90 -1.2082614004611969e-02</internalNodes>
           <leafValues>
-            6.4744032919406891e-02 -4.9827992916107178e-01</leafValues></_>
+            2.5803449749946594e-01 -1.1197961121797562e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 462 -3.3541000448167324e-03</internalNodes>
+            0 -1 746 9.8490377422422171e-04</internalNodes>
           <leafValues>
-            1.6614496707916260e-01 -1.8601009249687195e-01</leafValues></_>
+            -1.8312133848667145e-01 1.3942104578018188e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 683 -1.8176173325628042e-03</internalNodes>
+            0 -1 347 1.3184763491153717e-02</internalNodes>
           <leafValues>
-            2.6610982418060303e-01 -1.1267235130071640e-01</leafValues></_>
+            -1.0306112468242645e-01 2.5403776764869690e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 268 -2.2096108645200729e-02</internalNodes>
+            0 -1 143 2.5388993322849274e-02</internalNodes>
           <leafValues>
-            3.2448813319206238e-01 -8.3371557295322418e-02</leafValues></_>
+            6.4101323485374451e-02 -4.2444714903831482e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 751 5.8036940172314644e-03</internalNodes>
+            0 -1 196 7.8083951957523823e-03</internalNodes>
           <leafValues>
-            -1.2335725873708725e-01 2.5443312525749207e-01</leafValues></_>
+            -7.8133262693881989e-02 3.2170715928077698e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 243 4.7676274552941322e-03</internalNodes>
+            0 -1 921 1.2125947978347540e-03</internalNodes>
           <leafValues>
-            -1.4914961159229279e-01 1.8570756912231445e-01</leafValues></_>
+            -1.4831624925136566e-01 1.6055701673030853e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 386 2.7053440135205165e-05</internalNodes>
+            0 -1 920 -5.7722916826605797e-03</internalNodes>
           <leafValues>
-            -2.1181178092956543e-01 1.1339543759822845e-01</leafValues></_>
+            -6.2254351377487183e-01 4.7926213592290878e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 917 -2.5647766888141632e-03</internalNodes>
+            0 -1 987 -6.7740413360297680e-03</internalNodes>
           <leafValues>
-            -4.3090465664863586e-01 5.7283867150545120e-02</leafValues></_>
+            -6.4991837739944458e-01 1.9058052450418472e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 5 -9.9645227193832397e-02</internalNodes>
+            0 -1 291 -2.8847754001617432e-03</internalNodes>
           <leafValues>
-            4.7573822736740112e-01 -5.1954109221696854e-02</leafValues></_>
+            -5.1574712991714478e-01 4.2939033359289169e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 794 2.8423275798559189e-03</internalNodes>
+            0 -1 922 -5.1092512905597687e-02</internalNodes>
           <leafValues>
-            -7.9270146787166595e-02 3.1205773353576660e-01</leafValues></_>
+            -7.1794927120208740e-01 3.0500946566462517e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 336 -4.7821709886193275e-03</internalNodes>
+            0 -1 303 -3.0863287393003702e-03</internalNodes>
           <leafValues>
-            -4.4589859247207642e-01 5.0418782979249954e-02</leafValues></_>
+            -5.1027435064315796e-01 3.7360988557338715e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 770 1.6041981056332588e-02</internalNodes>
+            0 -1 593 -3.1833123648539186e-04</internalNodes>
           <leafValues>
-            -7.6039068400859833e-02 3.0843210220336914e-01</leafValues></_>
+            1.1626140773296356e-01 -1.7245446145534515e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 778 -3.6943168379366398e-03</internalNodes>
+            0 -1 210 1.2636608444154263e-03</internalNodes>
           <leafValues>
-            2.7407246828079224e-01 -8.8150359690189362e-02</leafValues></_>
+            -7.4942886829376221e-02 2.7081242203712463e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 71 8.4026419790461659e-04</internalNodes>
+            0 -1 693 -2.7436314150691032e-02</internalNodes>
           <leafValues>
-            -1.5873835980892181e-01 1.3953365385532379e-01</leafValues></_>
+            -5.7718968391418457e-01 3.3168055117130280e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 70 -8.0992765724658966e-03</internalNodes>
+            0 -1 342 -1.8837231909856200e-03</internalNodes>
           <leafValues>
-            -5.3085809946060181e-01 3.9269823580980301e-02</leafValues></_>
+            -3.0960574746131897e-01 6.1044581234455109e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 826 3.7676268257200718e-03</internalNodes>
+            0 -1 797 3.2289433293044567e-03</internalNodes>
           <leafValues>
-            7.0321731269359589e-02 -3.0400907993316650e-01</leafValues></_>
+            -6.8203814327716827e-02 2.9658797383308411e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 719 -8.4449478890746832e-04</internalNodes>
+            0 -1 503 -3.6236688029021025e-03</internalNodes>
           <leafValues>
-            1.6032356023788452e-01 -1.2606577575206757e-01</leafValues></_>
+            -4.9605649709701538e-01 4.2492914944887161e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 424 1.9298447296023369e-03</internalNodes>
+            0 -1 135 -1.3776571722701192e-03</internalNodes>
           <leafValues>
-            -7.4880234897136688e-02 2.8130438923835754e-01</leafValues></_>
+            1.3447758555412292e-01 -1.3678476214408875e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 517 -3.1593129970133305e-03</internalNodes>
+            0 -1 579 2.9051192104816437e-03</internalNodes>
           <leafValues>
-            -4.1825935244560242e-01 4.7720715403556824e-02</leafValues></_>
+            -1.2944447994232178e-01 1.4306847751140594e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 19 7.7791810035705566e-03</internalNodes>
+            0 -1 722 4.4553354382514954e-03</internalNodes>
           <leafValues>
-            4.1349764913320541e-02 -4.5770570635795593e-01</leafValues></_>
+            3.8421813398599625e-02 -4.5035859942436218e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 427 -3.2682183664292097e-03</internalNodes>
+            0 -1 622 1.0964765213429928e-02</internalNodes>
           <leafValues>
-            2.1473638713359833e-01 -9.5344312489032745e-02</leafValues></_>
+            -4.8769049346446991e-02 3.9813303947448730e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 490 -2.2884239442646503e-03</internalNodes>
+            0 -1 682 2.8863823972642422e-03</internalNodes>
           <leafValues>
-            2.4062317609786987e-01 -9.0378150343894958e-02</leafValues></_>
+            5.1313977688550949e-02 -3.6272794008255005e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 844 2.5960609782487154e-03</internalNodes>
+            0 -1 283 8.8652484118938446e-03</internalNodes>
           <leafValues>
-            3.4732636064291000e-02 -6.1617314815521240e-01</leafValues></_>
+            -9.4886533915996552e-02 2.1068450808525085e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 32 8.0937854945659637e-03</internalNodes>
+            0 -1 333 -1.9646657630801201e-02</internalNodes>
           <leafValues>
-            3.9185214787721634e-02 -4.7461858391761780e-01</leafValues></_>
+            2.2927023470401764e-01 -1.0384474694728851e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 289 5.6226095184683800e-03</internalNodes>
+            0 -1 684 -2.3328745737671852e-03</internalNodes>
           <leafValues>
-            3.3066269010305405e-02 -5.4723787307739258e-01</leafValues></_>
+            -3.0931735038757324e-01 6.4516365528106689e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 249 3.3066368196159601e-03</internalNodes>
+            0 -1 8 -4.0204055607318878e-02</internalNodes>
           <leafValues>
-            -1.0691711306571960e-01 1.8520861864089966e-01</leafValues></_>
+            2.7381995320320129e-01 -7.6448827981948853e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 277 -6.9545931182801723e-03</internalNodes>
+            0 -1 100 1.9051276147365570e-02</internalNodes>
           <leafValues>
-            2.8144246339797974e-01 -6.7726366221904755e-02</leafValues></_>
+            4.9466736614704132e-02 -3.6089882254600525e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 37 2.0960648544132710e-03</internalNodes>
+            0 -1 936 1.1553505435585976e-02</internalNodes>
           <leafValues>
-            6.5764650702476501e-02 -3.1323519349098206e-01</leafValues></_>
+            -7.4454858899116516e-02 2.5223839282989502e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 546 -2.9915343038737774e-03</internalNodes>
+            0 -1 76 6.0810474678874016e-03</internalNodes>
           <leafValues>
-            2.4481751024723053e-01 -7.8186720609664917e-02</leafValues></_>
+            4.9583721905946732e-02 -3.6660569906234741e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 461 9.8559018224477768e-03</internalNodes>
+            0 -1 212 5.4147411137819290e-03</internalNodes>
           <leafValues>
-            2.9282161965966225e-02 -6.9216150045394897e-01</leafValues></_>
+            3.2274514436721802e-02 -4.9895319342613220e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 567 -9.9846869707107544e-03</internalNodes>
+            0 -1 544 4.6544210053980350e-03</internalNodes>
           <leafValues>
-            3.1725984811782837e-01 -6.4144395291805267e-02</leafValues></_>
+            2.5989409536123276e-02 -6.1053085327148438e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 417 4.0295444428920746e-02</internalNodes>
+            0 -1 166 2.4446439929306507e-03</internalNodes>
           <leafValues>
-            -1.0545746237039566e-01 1.9351178407669067e-01</leafValues></_>
+            -1.2073440849781036e-01 1.4529803395271301e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 359 -4.5808870345354080e-03</internalNodes>
+            0 -1 698 4.6318914974108338e-04</internalNodes>
           <leafValues>
-            -2.7045866847038269e-01 6.3011758029460907e-02</leafValues></_>
+            -1.0553400218486786e-01 1.7337696254253387e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 76 -3.4120261669158936e-02</internalNodes>
+            0 -1 642 -3.7485856562852859e-02</internalNodes>
           <leafValues>
-            -5.0046062469482422e-01 3.3663876354694366e-02</leafValues></_>
+            -4.0581890940666199e-01 4.1759915649890900e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 475 5.9857115149497986e-02</internalNodes>
+            0 -1 529 -2.0438145846128464e-02</internalNodes>
           <leafValues>
-            -6.3651382923126221e-02 2.9614394903182983e-01</leafValues></_>
+            2.9171264171600342e-01 -6.6287793219089508e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 434 3.9175078272819519e-03</internalNodes>
+            0 -1 524 -3.8345486391335726e-03</internalNodes>
           <leafValues>
-            3.2706990838050842e-02 -5.7929420471191406e-01</leafValues></_>
+            1.5750087797641754e-01 -1.2569475173950195e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 60 1.1147339828312397e-02</internalNodes>
+            0 -1 884 8.8059913832694292e-04</internalNodes>
           <leafValues>
-            -7.9590849578380585e-02 2.3456735908985138e-01</leafValues></_>
+            -1.0610871762037277e-01 1.7642241716384888e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 642 -2.5253929197788239e-03</internalNodes>
+            0 -1 33 2.0514219067990780e-03</internalNodes>
           <leafValues>
-            -5.9936809539794922e-01 2.9250813648104668e-02</leafValues></_>
+            3.4303460270166397e-02 -5.5235451459884644e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 578 -1.6680266708135605e-02</internalNodes>
+            0 -1 851 -3.5282317548990250e-03</internalNodes>
           <leafValues>
-            3.0521371960639954e-01 -5.8340109884738922e-02</leafValues></_>
+            -5.3414058685302734e-01 3.0512372031807899e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 800 7.4669495224952698e-03</internalNodes>
+            0 -1 506 6.1051873490214348e-03</internalNodes>
           <leafValues>
-            3.1027967110276222e-02 -6.2497019767761230e-01</leafValues></_>
+            -8.4812760353088379e-02 1.9969700276851654e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 913 2.8406577184796333e-03</internalNodes>
+            0 -1 137 -6.4141638576984406e-03</internalNodes>
           <leafValues>
-            4.1042126715183258e-02 -4.1006734967231750e-01</leafValues></_>
+            -4.0772309899330139e-01 4.3864764273166656e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 702 -4.7403648495674133e-03</internalNodes>
+            0 -1 823 1.7272554337978363e-02</internalNodes>
           <leafValues>
-            2.0529302954673767e-01 -8.8142603635787964e-02</leafValues></_>
+            2.1965105086565018e-02 -6.9809681177139282e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 700 3.7362352013587952e-03</internalNodes>
+            0 -1 512 -1.9691141787916422e-03</internalNodes>
           <leafValues>
-            -6.1495106667280197e-02 3.4078758955001831e-01</leafValues></_>
+            1.8511210381984711e-01 -9.0554594993591309e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 679 -4.4546797871589661e-02</internalNodes>
+            0 -1 59 -5.5513512343168259e-03</internalNodes>
           <leafValues>
-            -8.9466398954391479e-01 2.2682141512632370e-02</leafValues></_>
+            -4.2040807008743286e-01 4.0062893182039261e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 416 9.0460591018199921e-03</internalNodes>
+            0 -1 626 -1.1905157566070557e-01</internalNodes>
           <leafValues>
-            4.8672281205654144e-02 -3.3261755108833313e-01</leafValues></_>
+            -6.4312189817428589e-01 2.3472266271710396e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 574 -3.9043920114636421e-03</internalNodes>
+            0 -1 290 4.0823101997375488e-02</internalNodes>
           <leafValues>
-            2.2659721970558167e-01 -7.7551431953907013e-02</leafValues></_>
+            -7.3068141937255859e-02 2.4851579964160919e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 380 1.0861126706004143e-02</internalNodes>
+            0 -1 119 -8.1011475995182991e-03</internalNodes>
           <leafValues>
-            -7.7613808214664459e-02 2.2056312859058380e-01</leafValues></_>
+            2.2747313976287842e-01 -7.5412914156913757e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 338 -1.2531490065157413e-03</internalNodes>
+            0 -1 87 4.7750310041010380e-03</internalNodes>
           <leafValues>
-            2.2868460416793823e-01 -8.1201769411563873e-02</leafValues></_>
+            -7.8901365399360657e-02 2.3182301223278046e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 339 -5.6936070322990417e-03</internalNodes>
+            0 -1 404 -2.7586806565523148e-02</internalNodes>
           <leafValues>
-            -5.6885385513305664e-01 3.6236546933650970e-02</leafValues></_>
+            -6.4926701784133911e-01 2.5375340133905411e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 140 1.4989164192229509e-03</internalNodes>
+            0 -1 907 4.3069543316960335e-03</internalNodes>
           <leafValues>
-            3.5795394331216812e-02 -4.7115951776504517e-01</leafValues></_>
+            2.4360222741961479e-02 -5.7372909784317017e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 81 4.8389505594968796e-02</internalNodes>
+            0 -1 385 -6.1931653181090951e-04</internalNodes>
           <leafValues>
-            2.8578057885169983e-02 -5.6662684679031372e-01</leafValues></_>
+            2.2557340562343597e-01 -7.5787223875522614e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 706 -6.7009456455707550e-02</internalNodes>
+            0 -1 50 -1.1459679901599884e-01</internalNodes>
           <leafValues>
-            3.6811140179634094e-01 -4.8919521272182465e-02</leafValues></_>
+            3.0668416619300842e-01 -5.2840072661638260e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 129 -6.9928979501128197e-03</internalNodes>
+            0 -1 239 3.1560026109218597e-02</internalNodes>
           <leafValues>
-            2.2268642485141754e-01 -8.1494621932506561e-02</leafValues></_>
+            -9.5666781067848206e-02 1.7659574747085571e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 506 -5.0552012398838997e-03</internalNodes>
+            0 -1 871 1.5142546035349369e-03</internalNodes>
           <leafValues>
-            -3.9911568164825439e-01 4.8226438462734222e-02</leafValues></_>
+            -9.2694908380508423e-02 2.0833927392959595e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 577 -1.6228569438681006e-03</internalNodes>
+            0 -1 731 4.7312509268522263e-03</internalNodes>
           <leafValues>
-            2.0442382991313934e-01 -9.1497577726840973e-02</leafValues></_>
+            -4.9851816147565842e-02 3.4422698616981506e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 812 1.4232760295271873e-03</internalNodes>
+            0 -1 253 -5.9051956050097942e-03</internalNodes>
           <leafValues>
-            -8.9272662997245789e-02 1.9328704476356506e-01</leafValues></_>
+            -4.6798244118690491e-01 3.6009732633829117e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 435 1.4769298955798149e-02</internalNodes>
+            0 -1 703 3.3569703809916973e-03</internalNodes>
           <leafValues>
-            4.3185703456401825e-02 -4.1162547469139099e-01</leafValues></_>
+            -5.1445800811052322e-02 3.3950069546699524e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 688 1.0630609467625618e-02</internalNodes>
+            0 -1 966 -1.1821147799491882e-01</internalNodes>
           <leafValues>
-            2.0712809637188911e-02 -7.4652433395385742e-01</leafValues></_>
+            4.6877983212471008e-01 -3.2708466053009033e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 366 -4.6220947988331318e-03</internalNodes>
+            0 -1 363 -8.8651233818382025e-04</internalNodes>
           <leafValues>
-            -2.6612642407417297e-01 6.2285874038934708e-02</leafValues></_>
+            1.5177871286869049e-01 -1.0880727320909500e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 608 -2.2310419008135796e-03</internalNodes>
+            0 -1 680 -2.5330238044261932e-02</internalNodes>
           <leafValues>
-            -6.4442801475524902e-01 2.2920599207282066e-02</leafValues></_>
+            1.7184022068977356e-01 -9.8979160189628601e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 259 -7.5279012322425842e-02</internalNodes>
+            0 -1 770 5.5901473388075829e-03</internalNodes>
           <leafValues>
-            -5.4105269908905029e-01 2.7185589075088501e-02</leafValues></_>
+            -7.1004293859004974e-02 2.7359166741371155e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 319 6.8284743465483189e-03</internalNodes>
+            0 -1 189 1.2344302609562874e-02</internalNodes>
           <leafValues>
-            -8.5639610886573792e-02 1.9920121133327484e-01</leafValues></_>
+            3.2738436013460159e-02 -5.2876019477844238e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 410 -7.6434519141912460e-03</internalNodes>
+            0 -1 348 -7.4871592223644257e-03</internalNodes>
           <leafValues>
-            2.4088086187839508e-01 -6.8174593150615692e-02</leafValues></_>
+            -5.1955360174179077e-01 2.7597136795520782e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 644 -3.6089830100536346e-03</internalNodes>
+            0 -1 646 -2.6753707788884640e-03</internalNodes>
           <leafValues>
-            1.8979941308498383e-01 -9.1478735208511353e-02</leafValues></_>
+            -4.7180628776550293e-01 3.1411368399858475e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 105 4.5644217729568481e-01</internalNodes>
+            0 -1 168 -3.2419776543974876e-03</internalNodes>
           <leafValues>
-            -3.5746987909078598e-02 5.1038581132888794e-01</leafValues></_>
+            1.5980260074138641e-01 -9.5776490867137909e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 55 4.3285787105560303e-03</internalNodes>
+            0 -1 169 8.8083129376173019e-03</internalNodes>
           <leafValues>
-            5.0642926245927811e-02 -3.4335514903068542e-01</leafValues></_>
+            -8.2104682922363281e-02 2.0850872993469238e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 114 -3.0497182160615921e-03</internalNodes>
+            0 -1 58 2.7282098308205605e-03</internalNodes>
           <leafValues>
-            1.5943552553653717e-01 -1.0838232934474945e-01</leafValues></_>
+            6.1908718198537827e-02 -2.6338595151901245e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 153 2.9164180159568787e-03</internalNodes>
+            0 -1 671 5.0587565638124943e-03</internalNodes>
           <leafValues>
-            -6.2386274337768555e-02 2.6772892475128174e-01</leafValues></_>
+            -8.2083821296691895e-02 1.9557759165763855e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 536 -6.7837955430150032e-03</internalNodes>
+            0 -1 708 -2.1199107170104980e-02</internalNodes>
           <leafValues>
-            -2.8828456997871399e-01 5.4219286888837814e-02</leafValues></_>
+            -5.0425887107849121e-01 3.0914928764104843e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 318 4.7922343946993351e-03</internalNodes>
+            0 -1 723 3.4958114847540855e-03</internalNodes>
           <leafValues>
-            4.1374113410711288e-02 -3.9169260859489441e-01</leafValues></_>
+            -8.2294017076492310e-02 1.9164223968982697e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 933 1.1295514181256294e-02</internalNodes>
+            0 -1 842 1.5914414543658495e-03</internalNodes>
           <leafValues>
-            -5.8489643037319183e-02 2.8171694278717041e-01</leafValues></_>
+            -6.9352962076663971e-02 2.1474194526672363e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 847 -1.9917660392820835e-03</internalNodes>
+            0 -1 193 -5.0045788288116455e-02</internalNodes>
           <leafValues>
-            1.6076046228408813e-01 -1.1378295719623566e-01</leafValues></_>
+            2.4582423269748688e-01 -6.2959901988506317e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 613 -1.5121680917218328e-03</internalNodes>
+            0 -1 19 -4.1983526200056076e-02</internalNodes>
           <leafValues>
-            -4.2076098918914795e-01 3.7524472922086716e-02</leafValues></_>
+            -6.3210010528564453e-01 2.5985429063439369e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 266 -2.0562859252095222e-02</internalNodes>
+            0 -1 402 -6.9432961754500866e-04</internalNodes>
           <leafValues>
-            1.6639313101768494e-01 -9.5253549516201019e-02</leafValues></_>
+            2.2444137930870056e-01 -7.0591680705547333e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 709 -2.3025400936603546e-02</internalNodes>
+            0 -1 540 6.0177911072969437e-03</internalNodes>
           <leafValues>
-            -3.1259611248970032e-01 5.8197792619466782e-02</leafValues></_>
+            3.7622205913066864e-02 -4.1375440359115601e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 584 -3.6875833757221699e-03</internalNodes>
+            0 -1 492 4.7936867922544479e-03</internalNodes>
           <leafValues>
-            2.2967162728309631e-01 -7.0608235895633698e-02</leafValues></_>
+            -9.0203136205673218e-02 1.7498855292797089e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 632 1.2718647718429565e-02</internalNodes>
+            0 -1 390 -4.7484524548053741e-03</internalNodes>
           <leafValues>
-            4.4480670243501663e-02 -4.1392150521278381e-01</leafValues></_>
+            -3.9998278021812439e-01 3.8966752588748932e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 392 1.1408344144001603e-03</internalNodes>
+            0 -1 620 -7.7324017882347107e-02</internalNodes>
           <leafValues>
-            -8.0126009881496429e-02 2.2867898643016815e-01</leafValues></_>
+            -4.8634868860244751e-01 2.9687402769923210e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 138 2.8175862506031990e-02</internalNodes>
+            0 -1 417 1.1184449307620525e-02</internalNodes>
           <leafValues>
-            -7.3071323335170746e-02 2.3685938119888306e-01</leafValues></_>
+            -4.9598570913076401e-02 3.2780852913856506e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 596 6.4620561897754669e-02</internalNodes>
+            0 -1 132 -1.0921864770352840e-02</internalNodes>
           <leafValues>
-            4.4116552919149399e-02 -4.2114758491516113e-01</leafValues></_>
+            1.7756749689579010e-01 -8.5219532251358032e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 237 -2.5126901455223560e-03</internalNodes>
+            0 -1 357 4.5135535299777985e-02</internalNodes>
           <leafValues>
-            1.7448952794075012e-01 -9.9981509149074554e-02</leafValues></_>
+            2.8995228931307793e-02 -5.3758519887924194e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 949 -2.7390490286052227e-03</internalNodes>
+            0 -1 341 -1.1866749264299870e-03</internalNodes>
           <leafValues>
-            -3.7159797549247742e-01 4.5618161559104919e-02</leafValues></_>
+            1.8304300308227539e-01 -8.5605643689632416e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 351 4.5697823166847229e-02</internalNodes>
+            0 -1 609 2.0626676268875599e-03</internalNodes>
           <leafValues>
-            2.5755234062671661e-02 -5.6903475522994995e-01</leafValues></_>
+            2.5438303127884865e-02 -5.9883767366409302e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 720 -8.8378116488456726e-03</internalNodes>
+            0 -1 251 2.7453177608549595e-05</internalNodes>
           <leafValues>
-            1.5099802613258362e-01 -9.9460050463676453e-02</leafValues></_>
+            -1.3831512629985809e-01 1.0590004175901413e-01</leafValues></_></weakClassifiers></_>
+    <!-- stage 18 -->
+    <_>
+      <maxWeakCount>98</maxWeakCount>
+      <stageThreshold>-1.2823635339736938e+00</stageThreshold>
+      <weakClassifiers>
         <_>
           <internalNodes>
-            0 -1 488 3.5273849498480558e-03</internalNodes>
+            0 -1 840 -8.7535101920366287e-03</internalNodes>
           <leafValues>
-            4.6311099082231522e-02 -3.4411522746086121e-01</leafValues></_>
+            3.7845414876937866e-01 -1.2724789977073669e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 876 8.8435463840141892e-04</internalNodes>
+            0 -1 376 -5.7867290452122688e-03</internalNodes>
           <leafValues>
-            -6.9374859333038330e-02 2.2488924860954285e-01</leafValues></_>
+            4.6451708674430847e-01 -1.0028645396232605e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 876 -1.6139955259859562e-03</internalNodes>
+            0 -1 467 -1.5636831521987915e-02</internalNodes>
           <leafValues>
-            3.3221766352653503e-01 -5.1287319511175156e-02</leafValues></_>
+            2.7137696743011475e-01 -1.3237486779689789e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 970 4.1209710761904716e-03</internalNodes>
+            0 -1 743 7.9419813118875027e-04</internalNodes>
           <leafValues>
-            3.1247327104210854e-02 -5.1796287298202515e-01</leafValues></_>
+            -2.2457434237003326e-01 1.8765783309936523e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 593 6.8625092506408691e-02</internalNodes>
+            0 -1 511 9.8101666662842035e-04</internalNodes>
           <leafValues>
-            -4.8976749181747437e-02 3.6052888631820679e-01</leafValues></_>
+            -1.1674020439386368e-01 2.3788549005985260e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 128 1.9539505243301392e-02</internalNodes>
+            0 -1 148 -1.1779682245105505e-03</internalNodes>
           <leafValues>
-            -3.5133589059114456e-02 4.0571358799934387e-01</leafValues></_>
+            2.5913080573081970e-01 -8.3949849009513855e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 295 1.0195776820182800e-02</internalNodes>
+            0 -1 330 9.6748135983943939e-03</internalNodes>
           <leafValues>
-            2.9883516952395439e-02 -5.4385137557983398e-01</leafValues></_>
+            -8.3296068012714386e-02 3.4700453281402588e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 636 -9.7053672652691603e-04</internalNodes>
+            0 -1 307 2.9431451112031937e-03</internalNodes>
           <leafValues>
-            1.7753951251506805e-01 -8.5428759455680847e-02</leafValues></_>
+            4.6826824545860291e-02 -5.1865130662918091e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 299 7.0950109511613846e-03</internalNodes>
+            0 -1 918 -1.0496248723939061e-03</internalNodes>
           <leafValues>
-            2.6922283694148064e-02 -5.7553297281265259e-01</leafValues></_>
+            -2.9976195096969604e-01 6.9594070315361023e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 89 3.3868722617626190e-02</internalNodes>
+            0 -1 697 -1.6385620459914207e-02</internalNodes>
           <leafValues>
-            2.4893242865800858e-02 -5.1963424682617188e-01</leafValues></_>
+            2.1480703353881836e-01 -9.7807772457599640e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 799 8.9386161416769028e-03</internalNodes>
+            0 -1 910 4.9830954521894455e-03</internalNodes>
           <leafValues>
-            -6.5781995654106140e-02 2.1598634123802185e-01</leafValues></_>
+            2.2837642580270767e-02 -7.7743059396743774e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 934 -1.1335080489516258e-03</internalNodes>
+            0 -1 796 -3.1421617604792118e-03</internalNodes>
           <leafValues>
-            1.3626587390899658e-01 -1.2551343441009521e-01</leafValues></_></weakClassifiers></_>
-    <!-- stage 14 -->
-    <_>
-      <maxWeakCount>100</maxWeakCount>
-      <stageThreshold>-1.5342161655426025e+00</stageThreshold>
-      <weakClassifiers>
+            -5.6898134946823120e-01 3.6988433450460434e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 442 6.4967479556798935e-03</internalNodes>
+            0 -1 901 1.6069117933511734e-02</internalNodes>
           <leafValues>
-            9.2756643891334534e-02 6.3256287574768066e-01</leafValues></_>
+            -1.0548119246959686e-01 1.9650301337242126e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 735 -7.0229507982730865e-03</internalNodes>
+            0 -1 751 1.5043821185827255e-02</internalNodes>
           <leafValues>
-            4.7454160451889038e-01 -9.1181516647338867e-02</leafValues></_>
+            -1.0749972611665726e-01 2.0178599655628204e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 788 -1.1249051894992590e-03</internalNodes>
+            0 -1 295 6.8444460630416870e-03</internalNodes>
           <leafValues>
-            2.7701923251152039e-01 -1.5582662820816040e-01</leafValues></_>
+            5.0306834280490875e-02 -4.3162798881530762e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 272 2.1593673154711723e-02</internalNodes>
+            0 -1 827 1.1850953102111816e-02</internalNodes>
           <leafValues>
-            -1.2302023172378540e-01 4.3630394339561462e-01</leafValues></_>
+            3.2905589789152145e-02 -5.1617246866226196e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 657 2.7066322509199381e-03</internalNodes>
+            0 -1 831 2.1246306598186493e-02</internalNodes>
           <leafValues>
-            -1.9653171300888062e-01 1.8972468376159668e-01</leafValues></_>
+            -6.3726536929607391e-02 3.0544599890708923e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 789 1.9835126586258411e-03</internalNodes>
+            0 -1 256 1.1852337047457695e-02</internalNodes>
           <leafValues>
-            -1.0700473189353943e-01 3.2027366757392883e-01</leafValues></_>
+            -8.9553833007812500e-02 2.9359081387519836e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 381 -2.2188067436218262e-02</internalNodes>
+            0 -1 323 -2.5085010565817356e-03</internalNodes>
           <leafValues>
-            -3.4057390689849854e-01 9.7314909100532532e-02</leafValues></_>
+            2.2805334627628326e-01 -9.5263637602329254e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 900 6.6005333792418242e-04</internalNodes>
+            0 -1 752 7.5797801837325096e-03</internalNodes>
           <leafValues>
-            -1.9594040513038635e-01 1.6130633652210236e-01</leafValues></_>
+            3.8756053894758224e-02 -5.7552194595336914e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 189 9.8964036442339420e-04</internalNodes>
+            0 -1 86 5.4980744607746601e-03</internalNodes>
           <leafValues>
-            -1.6125436127185822e-01 1.5948192775249481e-01</leafValues></_>
+            4.6144284307956696e-02 -3.6506399512290955e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 557 5.2934061735868454e-02</internalNodes>
+            0 -1 208 -3.0190458055585623e-03</internalNodes>
           <leafValues>
-            -7.4111364781856537e-02 3.6531463265419006e-01</leafValues></_>
+            -2.9709556698799133e-01 7.5851216912269592e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 423 9.6504454268142581e-04</internalNodes>
+            0 -1 552 -7.0441095158457756e-03</internalNodes>
           <leafValues>
-            -1.4388854801654816e-01 1.8791662156581879e-01</leafValues></_>
+            1.6086654365062714e-01 -1.1914677917957306e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 326 -6.5498230978846550e-03</internalNodes>
+            0 -1 364 -6.9178184494376183e-03</internalNodes>
           <leafValues>
-            -5.1886290311813354e-01 4.9368891865015030e-02</leafValues></_>
+            -4.1069602966308594e-01 4.4916272163391113e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 309 -3.1677065417170525e-03</internalNodes>
+            0 -1 351 5.0740875303745270e-03</internalNodes>
           <leafValues>
-            -4.5819568634033203e-01 4.6636309474706650e-02</leafValues></_>
+            -7.4677795171737671e-02 2.4945564568042755e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 58 -3.8453172892332077e-03</internalNodes>
+            0 -1 121 -1.0403880849480629e-02</internalNodes>
           <leafValues>
-            1.8924130499362946e-01 -1.2508736550807953e-01</leafValues></_>
+            -5.3336864709854126e-01 3.9480298757553101e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 279 1.0155377909541130e-02</internalNodes>
+            0 -1 323 2.3738082963973284e-03</internalNodes>
           <leafValues>
-            -7.4480414390563965e-02 3.1350296735763550e-01</leafValues></_>
+            -7.8084513545036316e-02 2.3774850368499756e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 275 9.4711792189627886e-04</internalNodes>
+            0 -1 391 2.7033074729843065e-05</internalNodes>
           <leafValues>
-            -1.0617389529943466e-01 2.3810641467571259e-01</leafValues></_>
+            -1.8558554351329803e-01 9.6640095114707947e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 892 -2.4116779677569866e-03</internalNodes>
+            0 -1 167 2.9049259610474110e-03</internalNodes>
           <leafValues>
-            -3.9038985967636108e-01 6.1166737228631973e-02</leafValues></_>
+            4.6409133821725845e-02 -3.9720407128334045e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 260 -3.9347349666059017e-03</internalNodes>
+            0 -1 181 -5.6298477575182915e-03</internalNodes>
           <leafValues>
-            -5.7243233919143677e-01 3.4851558506488800e-02</leafValues></_>
+            -4.5908093452453613e-01 3.7730857729911804e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 328 6.6558746621012688e-03</internalNodes>
+            0 -1 638 5.0751655362546444e-03</internalNodes>
           <leafValues>
-            2.8953079134225845e-02 -6.2028181552886963e-01</leafValues></_>
+            2.3507807403802872e-02 -6.4602053165435791e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 341 -2.2842539474368095e-03</internalNodes>
+            0 -1 909 -7.5826002284884453e-04</internalNodes>
           <leafValues>
-            -3.3340734243392944e-01 5.2056297659873962e-02</leafValues></_>
+            1.2444372475147247e-01 -1.3639765977859497e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 829 7.6677929610013962e-04</internalNodes>
+            0 -1 11 -9.7201213240623474e-02</internalNodes>
           <leafValues>
-            -9.4001799821853638e-02 2.0127503573894501e-01</leafValues></_>
+            3.9986947178840637e-01 -4.4366274029016495e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 8 -3.9554573595523834e-02</internalNodes>
+            0 -1 496 -2.3840454220771790e-01</internalNodes>
           <leafValues>
-            3.9717516303062439e-01 -5.0761125981807709e-02</leafValues></_>
+            -5.3094118833541870e-01 3.8410611450672150e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 166 -2.2336144000291824e-02</internalNodes>
+            0 -1 114 -1.3428549282252789e-02</internalNodes>
           <leafValues>
-            2.0378184318542480e-01 -1.0499230772256851e-01</leafValues></_>
+            2.2794343531131744e-01 -7.7827021479606628e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 682 4.1007921099662781e-03</internalNodes>
+            0 -1 64 -5.0623202696442604e-04</internalNodes>
           <leafValues>
-            3.9605572819709778e-02 -5.6042844057083130e-01</leafValues></_>
+            1.5778008103370667e-01 -1.2732668220996857e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 187 -6.3549563288688660e-02</internalNodes>
+            0 -1 931 -8.6578715126961470e-04</internalNodes>
           <leafValues>
-            5.9350001811981201e-01 -3.4742560237646103e-02</leafValues></_>
+            1.4809772372245789e-01 -1.1785575747489929e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 370 3.7244942504912615e-03</internalNodes>
+            0 -1 544 -2.7892580255866051e-03</internalNodes>
           <leafValues>
-            -5.1448952406644821e-02 3.1930196285247803e-01</leafValues></_>
+            -4.2324438691139221e-01 4.1194166988134384e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 483 1.2377202510833740e-02</internalNodes>
+            0 -1 654 2.9110969044268131e-03</internalNodes>
           <leafValues>
-            3.3052973449230194e-02 -6.5478527545928955e-01</leafValues></_>
+            -1.2145258486270905e-01 1.4758351445198059e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 499 -1.0786693543195724e-02</internalNodes>
+            0 -1 122 -1.7908504605293274e-01</internalNodes>
           <leafValues>
-            2.4589619040489197e-01 -7.2101429104804993e-02</leafValues></_>
+            4.0684828162193298e-01 -4.6298943459987640e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 439 -1.4055164530873299e-02</internalNodes>
+            0 -1 894 4.2685694643296301e-04</internalNodes>
           <leafValues>
-            3.5272973775863647e-01 -5.8014977723360062e-02</leafValues></_>
+            -9.4548642635345459e-02 1.8615303933620453e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 391 -1.4940403401851654e-02</internalNodes>
+            0 -1 72 1.9871112704277039e-01</internalNodes>
           <leafValues>
-            -4.5820471644401550e-01 4.5480247586965561e-02</leafValues></_>
+            -5.6818448007106781e-02 3.2197028398513794e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 850 1.8285561818629503e-03</internalNodes>
+            0 -1 892 1.2496551498770714e-03</internalNodes>
           <leafValues>
-            3.2248783856630325e-02 -4.9957463145256042e-01</leafValues></_>
+            -7.0664338767528534e-02 2.5729593634605408e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 26 1.8330020830035210e-02</internalNodes>
+            0 -1 447 1.6119793057441711e-02</internalNodes>
           <leafValues>
-            4.6777416020631790e-02 -3.7174671888351440e-01</leafValues></_>
+            -5.0713617354631424e-02 3.9684635400772095e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 579 -1.1065398575738072e-03</internalNodes>
+            0 -1 964 -2.5047704111784697e-03</internalNodes>
           <leafValues>
-            -3.4255436062812805e-01 4.5848693698644638e-02</leafValues></_>
+            -3.5733562707901001e-01 4.9460943788290024e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 481 -2.7136057615280151e-03</internalNodes>
+            0 -1 672 5.2866833284497261e-03</internalNodes>
           <leafValues>
-            2.4459818005561829e-01 -6.8955913186073303e-02</leafValues></_>
+            3.2510578632354736e-02 -4.4326359033584595e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 163 3.5836829338222742e-03</internalNodes>
+            0 -1 633 -3.4677600488066673e-03</internalNodes>
           <leafValues>
-            3.9574686437845230e-02 -4.1517943143844604e-01</leafValues></_>
+            2.3254001140594482e-01 -7.3516972362995148e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 205 1.3739100657403469e-02</internalNodes>
+            0 -1 600 -3.3557973802089691e-03</internalNodes>
           <leafValues>
-            -6.2165945768356323e-02 2.8256937861442566e-01</leafValues></_>
+            2.3221854865550995e-01 -6.9719336926937103e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 763 -1.1374817695468664e-03</internalNodes>
+            0 -1 801 -6.3276281580328941e-03</internalNodes>
           <leafValues>
-            1.6939654946327209e-01 -1.0761212557554245e-01</leafValues></_>
+            -4.0112924575805664e-01 4.3525256216526031e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 731 -1.1336053721606731e-03</internalNodes>
+            0 -1 218 -4.3456726707518101e-03</internalNodes>
           <leafValues>
-            2.4757325649261475e-01 -7.0519238710403442e-02</leafValues></_>
+            -6.8020933866500854e-01 1.9806224852800369e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 551 2.4884669110178947e-03</internalNodes>
+            0 -1 604 6.2400596216320992e-03</internalNodes>
           <leafValues>
-            4.3731488287448883e-02 -4.3731775879859924e-01</leafValues></_>
+            1.8352568149566650e-02 -7.0223194360733032e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 693 9.1567426919937134e-02</internalNodes>
+            0 -1 979 3.3795731142163277e-03</internalNodes>
           <leafValues>
-            -6.4225792884826660e-02 2.6794373989105225e-01</leafValues></_>
+            4.3487045913934708e-02 -3.0831974744796753e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 863 8.1775393337011337e-03</internalNodes>
+            0 -1 937 1.3499217107892036e-02</internalNodes>
           <leafValues>
-            -6.9729812443256378e-02 2.7086481451988220e-01</leafValues></_>
+            -4.4923197478055954e-02 3.2624542713165283e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 539 -3.1169723719358444e-02</internalNodes>
+            0 -1 408 -1.0585743002593517e-03</internalNodes>
           <leafValues>
-            -5.1539027690887451e-01 4.1658539324998856e-02</leafValues></_>
+            1.6033367812633514e-01 -9.8465800285339355e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 589 -1.8694017082452774e-02</internalNodes>
+            0 -1 405 -5.3765797056257725e-03</internalNodes>
           <leafValues>
-            2.1681772172451019e-01 -8.8622607290744781e-02</leafValues></_>
+            2.6544988155364990e-01 -6.7050188779830933e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 472 5.7301642373204231e-03</internalNodes>
+            0 -1 980 -2.4880110286176205e-03</internalNodes>
           <leafValues>
-            -7.2939246892929077e-02 2.3475584387779236e-01</leafValues></_>
+            -2.9397118091583252e-01 5.4097402840852737e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 890 1.6503074439242482e-03</internalNodes>
+            0 -1 505 -2.1792344748973846e-02</internalNodes>
           <leafValues>
-            6.9048069417476654e-02 -2.8440928459167480e-01</leafValues></_>
+            -7.2506862878799438e-01 1.9187789410352707e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 191 -7.0378202944993973e-03</internalNodes>
+            0 -1 714 4.7056311741471291e-03</internalNodes>
           <leafValues>
-            -4.7214046120643616e-01 3.5182151943445206e-02</leafValues></_>
+            -5.2215453237295151e-02 3.1615570187568665e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 591 -2.3838514462113380e-03</internalNodes>
+            0 -1 669 -4.2645912617444992e-03</internalNodes>
           <leafValues>
-            1.9753867387771606e-01 -8.9424118399620056e-02</leafValues></_>
+            2.3567616939544678e-01 -6.8938009440898895e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 349 7.9844584688544273e-03</internalNodes>
+            0 -1 774 5.8556320145726204e-03</internalNodes>
           <leafValues>
-            -7.4890352785587311e-02 2.3181028664112091e-01</leafValues></_>
+            4.2000979185104370e-02 -4.6045160293579102e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 124 1.3400901807472110e-03</internalNodes>
+            0 -1 926 1.3632343616336584e-03</internalNodes>
           <leafValues>
-            -1.0847068578004837e-01 1.9428721070289612e-01</leafValues></_>
+            -6.5663956105709076e-02 2.3397234082221985e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 123 -2.9489169828593731e-03</internalNodes>
+            0 -1 895 -6.0495175421237946e-03</internalNodes>
           <leafValues>
-            -4.0673759579658508e-01 4.7985706478357315e-02</leafValues></_>
+            -4.3943586945533752e-01 3.6742802709341049e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 952 -5.9452969580888748e-03</internalNodes>
+            0 -1 308 6.7223357036709785e-03</internalNodes>
           <leafValues>
-            -4.5123618841171265e-01 3.6464843899011612e-02</leafValues></_>
+            1.9922675564885139e-02 -6.8767511844635010e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 659 2.3310778196901083e-03</internalNodes>
+            0 -1 917 -5.1960002630949020e-02</internalNodes>
           <leafValues>
-            -8.0826595425605774e-02 2.1532072126865387e-01</leafValues></_>
+            -7.5993520021438599e-01 1.5627101063728333e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 54 -1.9684966653585434e-02</internalNodes>
+            0 -1 542 3.3762669190764427e-03</internalNodes>
           <leafValues>
-            2.3020596802234650e-01 -8.1534743309020996e-02</leafValues></_>
+            -7.7943108975887299e-02 1.9545321166515350e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 723 -1.6875991132110357e-03</internalNodes>
+            0 -1 582 -1.8302195239812136e-03</internalNodes>
           <leafValues>
-            2.3354543745517731e-01 -7.0870727300643921e-02</leafValues></_>
+            1.9154363870620728e-01 -9.4946600496768951e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 697 -1.5521588502451777e-03</internalNodes>
+            0 -1 71 -4.3824277818202972e-03</internalNodes>
           <leafValues>
-            1.7072069644927979e-01 -1.0233023017644882e-01</leafValues></_>
+            -5.3172159194946289e-01 2.8438575565814972e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 667 -3.8005404174327850e-02</internalNodes>
+            0 -1 107 4.8605538904666901e-03</internalNodes>
           <leafValues>
-            -6.0487842559814453e-01 2.8272373601794243e-02</leafValues></_>
+            1.8084224313497543e-02 -7.0419138669967651e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 624 -2.1617640741169453e-03</internalNodes>
+            0 -1 289 -5.0755832344293594e-03</internalNodes>
           <leafValues>
-            -5.5644184350967407e-01 2.5939555838704109e-02</leafValues></_>
+            1.3961549103260040e-01 -1.0557857155799866e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 653 -2.6441088411957026e-03</internalNodes>
+            0 -1 349 9.0303886681795120e-03</internalNodes>
           <leafValues>
-            -4.4886007905006409e-01 3.1817246228456497e-02</leafValues></_>
+            -5.6681722402572632e-02 3.0537691712379456e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 214 -7.3187379166483879e-04</internalNodes>
+            0 -1 52 1.7635107040405273e-01</internalNodes>
           <leafValues>
-            2.2164805233478546e-01 -7.6915167272090912e-02</leafValues></_>
+            -3.5581633448600769e-02 3.9358299970626831e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 532 -3.4191065933555365e-03</internalNodes>
+            0 -1 728 1.1068049352616072e-03</internalNodes>
           <leafValues>
-            -4.4704499840736389e-01 3.5689469426870346e-02</leafValues></_>
+            -9.6729792654514313e-02 1.6677951812744141e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 597 1.4393313322216272e-03</internalNodes>
+            0 -1 162 1.1059102602303028e-02</internalNodes>
           <leafValues>
-            -8.1237293779850006e-02 2.0022353529930115e-01</leafValues></_>
+            2.9283966869115829e-02 -5.1121145486831665e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 352 1.0892877355217934e-02</internalNodes>
+            0 -1 236 -5.0462923943996429e-02</internalNodes>
           <leafValues>
-            -5.9532187879085541e-02 2.6124969124794006e-01</leafValues></_>
+            -4.2722624540328979e-01 3.1082244589924812e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 250 2.5800592266023159e-03</internalNodes>
+            0 -1 316 -3.8071773014962673e-03</internalNodes>
           <leafValues>
-            5.3012363612651825e-02 -3.0210506916046143e-01</leafValues></_>
+            2.9747742414474487e-01 -5.1289469003677368e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 873 -3.7106748204678297e-03</internalNodes>
+            0 -1 373 -1.5183673240244389e-03</internalNodes>
           <leafValues>
-            -3.7514480948448181e-01 4.0868300944566727e-02</leafValues></_>
+            1.8215130269527435e-01 -1.0301912575960159e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 291 -8.9250775054097176e-03</internalNodes>
+            0 -1 258 2.1069757640361786e-02</internalNodes>
           <leafValues>
-            1.8222920596599579e-01 -8.4776028990745544e-02</leafValues></_>
+            2.4503789842128754e-02 -5.8991265296936035e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 211 -4.4729106128215790e-02</internalNodes>
+            0 -1 68 6.6435593180358410e-03</internalNodes>
           <leafValues>
-            2.5505220890045166e-01 -6.6192351281642914e-02</leafValues></_>
+            4.3313629925251007e-02 -3.1504327058792114e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 64 -1.0527699440717697e-01</internalNodes>
+            0 -1 574 -8.2504414021968842e-03</internalNodes>
           <leafValues>
-            -4.8529133200645447e-01 3.4933239221572876e-02</leafValues></_>
+            -4.7998124361038208e-01 3.0433293431997299e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 411 -6.5371848642826080e-02</internalNodes>
+            0 -1 617 -1.0892231017351151e-02</internalNodes>
           <leafValues>
-            3.7187507748603821e-01 -5.8592520654201508e-02</leafValues></_>
+            3.1449675559997559e-01 -5.2475348114967346e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 99 5.1612589508295059e-02</internalNodes>
+            0 -1 213 8.1554818898439407e-03</internalNodes>
           <leafValues>
-            -7.6325275003910065e-02 2.1536968648433685e-01</leafValues></_>
+            3.9224579930305481e-02 -3.8470247387886047e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 511 4.2564887553453445e-03</internalNodes>
+            0 -1 838 -5.4475883953273296e-03</internalNodes>
           <leafValues>
-            -7.7395483851432800e-02 2.1907977759838104e-01</leafValues></_>
+            -6.5578418970108032e-01 2.0117431879043579e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 671 -3.5104658454656601e-03</internalNodes>
+            0 -1 487 -2.6005427935160697e-04</internalNodes>
           <leafValues>
-            -4.1962492465972900e-01 4.1911821812391281e-02</leafValues></_>
+            1.4328984916210175e-01 -9.8999619483947754e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 746 -9.5827406039461493e-04</internalNodes>
+            0 -1 461 1.3821206521242857e-03</internalNodes>
           <leafValues>
-            1.7163562774658203e-01 -1.0379400104284286e-01</leafValues></_>
+            -5.2590593695640564e-02 2.7557003498077393e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 886 -3.3416904509067535e-02</internalNodes>
+            0 -1 445 -1.1740636080503464e-02</internalNodes>
           <leafValues>
-            -5.5419611930847168e-01 3.4831445664167404e-02</leafValues></_>
+            2.7564841508865356e-01 -5.9799015522003174e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 406 7.4058589525520802e-03</internalNodes>
+            0 -1 941 2.7866149321198463e-03</internalNodes>
           <leafValues>
-            -6.6642671823501587e-02 2.6589548587799072e-01</leafValues></_>
+            5.0002526491880417e-02 -3.5232934355735779e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 304 -7.3020011186599731e-03</internalNodes>
+            0 -1 962 6.6179647110402584e-03</internalNodes>
           <leafValues>
-            1.7654685676097870e-01 -8.7743707001209259e-02</leafValues></_>
+            -6.3348092138767242e-02 2.3150660097599030e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 505 -4.5689288526773453e-03</internalNodes>
+            0 -1 297 -1.3244405854493380e-03</internalNodes>
           <leafValues>
-            1.9193352758884430e-01 -8.0177433788776398e-02</leafValues></_>
+            -2.6642721891403198e-01 5.5936500430107117e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 740 -8.1814359873533249e-03</internalNodes>
+            0 -1 485 1.1830568313598633e-02</internalNodes>
           <leafValues>
-            2.3826718330383301e-01 -6.4945526421070099e-02</leafValues></_>
+            -6.9061063230037689e-02 2.1172530949115753e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 404 4.5117912814021111e-03</internalNodes>
+            0 -1 644 2.5925931986421347e-03</internalNodes>
           <leafValues>
-            3.0824853107333183e-02 -5.3869700431823730e-01</leafValues></_>
+            1.9716180860996246e-02 -7.7208590507507324e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 502 2.8812256641685963e-03</internalNodes>
+            0 -1 748 -2.8010653331875801e-03</internalNodes>
           <leafValues>
-            -9.6859149634838104e-02 1.6199249029159546e-01</leafValues></_>
+            1.3846111297607422e-01 -9.7015053033828735e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 845 2.4804673157632351e-03</internalNodes>
+            0 -1 144 -4.7637272626161575e-02</internalNodes>
           <leafValues>
-            2.1523499861359596e-02 -7.0121616125106812e-01</leafValues></_>
+            2.1245625615119934e-01 -7.0445045828819275e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 640 6.8080224096775055e-02</internalNodes>
+            0 -1 197 1.3677144888788462e-03</internalNodes>
           <leafValues>
-            2.1451909095048904e-02 -6.2823659181594849e-01</leafValues></_>
+            -8.5676178336143494e-02 1.9613882899284363e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 428 3.8525110576301813e-03</internalNodes>
+            0 -1 556 -1.3261453807353973e-01</internalNodes>
           <leafValues>
-            -8.2842335104942322e-02 1.9410280883312225e-01</leafValues></_>
+            4.3639957904815674e-01 -3.4653130918741226e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 904 -2.5594229809939861e-03</internalNodes>
+            0 -1 69 7.1225965023040771e-01</internalNodes>
           <leafValues>
-            1.9102296233177185e-01 -8.5406452417373657e-02</leafValues></_>
+            1.9474601373076439e-02 -8.7232232093811035e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 929 5.3212735801935196e-03</internalNodes>
+            0 -1 149 -5.9057516045868397e-03</internalNodes>
           <leafValues>
-            -7.8593194484710693e-02 2.2497585415840149e-01</leafValues></_>
+            -3.7135502696037292e-01 3.5206548869609833e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 235 3.1688171438872814e-03</internalNodes>
+            0 -1 971 3.5532126203179359e-03</internalNodes>
           <leafValues>
-            3.6922473460435867e-02 -4.5733535289764404e-01</leafValues></_>
+            -6.6334858536720276e-02 2.3531165719032288e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 848 1.5939949080348015e-02</internalNodes>
+            0 -1 31 -1.9724387675523758e-02</internalNodes>
           <leafValues>
-            3.7862829864025116e-02 -3.9459064602851868e-01</leafValues></_>
+            2.5173032283782959e-01 -5.7575348764657974e-02</leafValues></_></weakClassifiers></_>
+    <!-- stage 19 -->
+    <_>
+      <maxWeakCount>100</maxWeakCount>
+      <stageThreshold>-1.3067311048507690e+00</stageThreshold>
+      <weakClassifiers>
         <_>
           <internalNodes>
-            0 -1 634 2.3682378232479095e-03</internalNodes>
+            0 -1 458 8.1832958385348320e-03</internalNodes>
           <leafValues>
-            3.5111214965581894e-02 -4.3085646629333496e-01</leafValues></_>
+            -1.1180391162633896e-01 3.9526882767677307e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 741 1.2975309044122696e-02</internalNodes>
+            0 -1 717 -5.5650249123573303e-03</internalNodes>
           <leafValues>
-            -7.1412295103073120e-02 2.1616001427173615e-01</leafValues></_>
+            3.3437621593475342e-01 -1.2654128670692444e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 960 -9.9381525069475174e-03</internalNodes>
+            0 -1 577 8.1406952813267708e-04</internalNodes>
           <leafValues>
-            2.7434283494949341e-01 -5.9007227420806885e-02</leafValues></_>
+            -1.7086146771907806e-01 1.8384252488613129e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 14 -4.4495373964309692e-02</internalNodes>
+            0 -1 113 -2.0645279437303543e-03</internalNodes>
           <leafValues>
-            -5.7859867811203003e-01 2.8963629156351089e-02</leafValues></_>
+            1.7057111859321594e-01 -1.7103828489780426e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 457 1.0330894030630589e-02</internalNodes>
+            0 -1 864 1.9037863239645958e-03</internalNodes>
           <leafValues>
-            -6.5200082957744598e-02 2.6670095324516296e-01</leafValues></_>
+            -1.6791534423828125e-01 1.5749432146549225e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 745 -4.2830477468669415e-03</internalNodes>
+            0 -1 242 1.1136581189930439e-02</internalNodes>
           <leafValues>
-            -5.2546054124832153e-01 3.3751774579286575e-02</leafValues></_>
+            4.0173061192035675e-02 -3.7364640831947327e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 899 1.5691295266151428e-02</internalNodes>
+            0 -1 228 5.6379067245870829e-04</internalNodes>
           <leafValues>
-            2.9164802283048630e-02 -4.8206093907356262e-01</leafValues></_>
+            -1.6792711615562439e-01 1.4207355678081512e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 903 -1.2077906867489219e-03</internalNodes>
+            0 -1 797 -3.3720356877893209e-03</internalNodes>
           <leafValues>
-            2.4997046589851379e-01 -6.1069376766681671e-02</leafValues></_>
+            2.5698736310005188e-01 -7.5178287923336029e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 220 6.6226916387677193e-03</internalNodes>
+            0 -1 710 -1.7311582341790199e-02</internalNodes>
           <leafValues>
-            4.8671871423721313e-02 -3.4221932291984558e-01</leafValues></_>
+            -5.2065086364746094e-01 4.7350786626338959e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 236 -5.1539484411478043e-03</internalNodes>
+            0 -1 845 -3.3407085575163364e-03</internalNodes>
           <leafValues>
-            -3.5398313403129578e-01 4.2696069926023483e-02</leafValues></_>
+            -4.5184752345085144e-01 3.2597322016954422e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 74 -2.4832391645759344e-03</internalNodes>
+            0 -1 661 -3.4317255020141602e-02</internalNodes>
           <leafValues>
-            2.0646870136260986e-01 -7.5708754360675812e-02</leafValues></_>
+            2.5700893998146057e-01 -8.3455510437488556e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 891 3.0503068119287491e-03</internalNodes>
+            0 -1 423 -6.8267658352851868e-02</internalNodes>
           <leafValues>
-            2.1991817280650139e-02 -6.9251579046249390e-01</leafValues></_>
+            2.8288829326629639e-01 -7.8631594777107239e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 514 9.2179588973522186e-03</internalNodes>
+            0 -1 951 2.8722581191686913e-05</internalNodes>
           <leafValues>
-            1.7923980951309204e-02 -7.2638368606567383e-01</leafValues></_>
+            -1.8466357886791229e-01 1.1576397716999054e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 776 3.7863249890506268e-03</internalNodes>
+            0 -1 267 9.9579263478517532e-03</internalNodes>
           <leafValues>
-            -6.6987045109272003e-02 2.2602997720241547e-01</leafValues></_></weakClassifiers></_></stages>
-  <features>
-    <_>
-      <rects>
+            -6.3400641083717346e-02 3.6796927452087402e-01</leafValues></_>
         <_>
-          0 0 8 1 -1.</_>
+          <internalNodes>
+            0 -1 733 -1.8424488604068756e-02</internalNodes>
+          <leafValues>
+            2.4584248661994934e-01 -9.4283707439899445e-02</leafValues></_>
         <_>
-          4 0 4 1 2.</_></rects>
-      <tilted>0</tilted></_>
-    <_>
-      <rects>
+          <internalNodes>
+            0 -1 837 6.8876314908266068e-03</internalNodes>
+          <leafValues>
+            -9.9725127220153809e-02 2.8111982345581055e-01</leafValues></_>
         <_>
-          0 0 8 6 -1.</_>
+          <internalNodes>
+            0 -1 657 -2.2637452930212021e-03</internalNodes>
+          <leafValues>
+            -4.1033151745796204e-01 6.1188895255327225e-02</leafValues></_>
         <_>
-          0 0 4 3 2.</_>
+          <internalNodes>
+            0 -1 191 -8.5531552031170577e-05</internalNodes>
+          <leafValues>
+            1.1543370783329010e-01 -1.6276736557483673e-01</leafValues></_>
         <_>
-          4 3 4 3 2.</_></rects>
-      <tilted>0</tilted></_>
-    <_>
-      <rects>
+          <internalNodes>
+            0 -1 32 3.3203132450580597e-02</internalNodes>
+          <leafValues>
+            4.8811107873916626e-02 -3.7535405158996582e-01</leafValues></_>
         <_>
-          0 0 10 6 -1.</_>
+          <internalNodes>
+            0 -1 929 5.1993243396282196e-03</internalNodes>
+          <leafValues>
+            3.9811953902244568e-02 -4.8758861422538757e-01</leafValues></_>
         <_>
-          0 0 5 3 2.</_>
+          <internalNodes>
+            0 -1 365 4.8818998038768768e-03</internalNodes>
+          <leafValues>
+            2.4118293076753616e-02 -6.7809182405471802e-01</leafValues></_>
         <_>
-          5 3 5 3 2.</_></rects>
-      <tilted>0</tilted></_>
-    <_>
-      <rects>
+          <internalNodes>
+            0 -1 82 -7.2956003248691559e-02</internalNodes>
+          <leafValues>
+            1.8825025856494904e-01 -9.5193333923816681e-02</leafValues></_>
         <_>
-          0 0 24 5 -1.</_>
+          <internalNodes>
+            0 -1 836 9.4123989343643188e-02</internalNodes>
+          <leafValues>
+            -7.2761356830596924e-02 2.7999758720397949e-01</leafValues></_>
         <_>
-          6 0 12 5 2.</_></rects>
-      <tilted>0</tilted></_>
-    <_>
-      <rects>
+          <internalNodes>
+            0 -1 718 1.0472428984940052e-03</internalNodes>
+          <leafValues>
+            -7.4624419212341309e-02 2.4220877885818481e-01</leafValues></_>
         <_>
-          0 0 16 6 -1.</_>
+          <internalNodes>
+            0 -1 446 8.0979522317647934e-03</internalNodes>
+          <leafValues>
+            -5.4950036108493805e-02 3.0833497643470764e-01</leafValues></_>
         <_>
-          0 0 8 3 2.</_>
+          <internalNodes>
+            0 -1 463 -2.8517602477222681e-03</internalNodes>
+          <leafValues>
+            3.2442548871040344e-01 -7.1306072175502777e-02</leafValues></_>
         <_>
-          8 3 8 3 2.</_></rects>
-      <tilted>0</tilted></_>
-    <_>
-      <rects>
+          <internalNodes>
+            0 -1 63 3.7457090802490711e-03</internalNodes>
+          <leafValues>
+            5.7812750339508057e-02 -3.3119776844978333e-01</leafValues></_>
         <_>
-          0 0 16 10 -1.</_>
+          <internalNodes>
+            0 -1 217 -3.9520347490906715e-03</internalNodes>
+          <leafValues>
+            -4.3750977516174316e-01 3.9293695241212845e-02</leafValues></_>
         <_>
-          0 0 8 5 2.</_>
+          <internalNodes>
+            0 -1 865 -5.8175362646579742e-03</internalNodes>
+          <leafValues>
+            2.0937338471412659e-01 -8.1724949181079865e-02</leafValues></_>
         <_>
-          8 5 8 5 2.</_></rects>
-      <tilted>0</tilted></_>
-    <_>
-      <rects>
+          <internalNodes>
+            0 -1 878 7.8594256192445755e-03</internalNodes>
+          <leafValues>
+            4.8747915774583817e-02 -4.1596582531929016e-01</leafValues></_>
         <_>
-          0 0 24 1 -1.</_>
+          <internalNodes>
+            0 -1 913 -6.7130924435332417e-04</internalNodes>
+          <leafValues>
+            1.4715777337551117e-01 -1.2916122376918793e-01</leafValues></_>
         <_>
-          12 0 12 1 2.</_></rects>
-      <tilted>0</tilted></_>
-    <_>
-      <rects>
+          <internalNodes>
+            0 -1 62 -4.2964564636349678e-03</internalNodes>
+          <leafValues>
+            -3.5870963335037231e-01 4.8831127583980560e-02</leafValues></_>
         <_>
-          0 0 24 12 -1.</_>
+          <internalNodes>
+            0 -1 868 -3.8814521394670010e-03</internalNodes>
+          <leafValues>
+            -4.7464737296104431e-01 3.4466378390789032e-02</leafValues></_>
         <_>
-          0 0 12 6 2.</_>
+          <internalNodes>
+            0 -1 950 -1.8017216352745891e-03</internalNodes>
+          <leafValues>
+            -3.5517925024032593e-01 4.9101348966360092e-02</leafValues></_>
         <_>
-          12 6 12 6 2.</_></rects>
-      <tilted>0</tilted></_>
-    <_>
-      <rects>
+          <internalNodes>
+            0 -1 813 7.7566690742969513e-03</internalNodes>
+          <leafValues>
+            2.7035165578126907e-02 -5.5951416492462158e-01</leafValues></_>
         <_>
-          0 1 8 10 -1.</_>
+          <internalNodes>
+            0 -1 886 1.9125882536172867e-03</internalNodes>
+          <leafValues>
+            -6.3309118151664734e-02 2.5223699212074280e-01</leafValues></_>
         <_>
-          0 1 4 5 2.</_>
+          <internalNodes>
+            0 -1 886 -9.9804997444152832e-04</internalNodes>
+          <leafValues>
+            2.4349449574947357e-01 -8.9007876813411713e-02</leafValues></_>
         <_>
-          4 6 4 5 2.</_></rects>
-      <tilted>0</tilted></_>
-    <_>
-      <rects>
+          <internalNodes>
+            0 -1 97 -7.5093598570674658e-04</internalNodes>
+          <leafValues>
+            1.3702079653739929e-01 -1.2293258309364319e-01</leafValues></_>
         <_>
-          0 1 10 2 -1.</_>
+          <internalNodes>
+            0 -1 7 1.0788314975798130e-02</internalNodes>
+          <leafValues>
+            -7.3592424392700195e-02 2.3694764077663422e-01</leafValues></_>
         <_>
-          5 1 5 2 2.</_></rects>
-      <tilted>0</tilted></_>
-    <_>
-      <rects>
+          <internalNodes>
+            0 -1 428 -1.2814668007194996e-03</internalNodes>
+          <leafValues>
+            1.7014959454536438e-01 -9.3263216316699982e-02</leafValues></_>
         <_>
-          0 1 10 6 -1.</_>
+          <internalNodes>
+            0 -1 851 3.5997035447508097e-03</internalNodes>
+          <leafValues>
+            2.4880735203623772e-02 -5.7666695117950439e-01</leafValues></_>
         <_>
-          0 1 5 3 2.</_>
+          <internalNodes>
+            0 -1 410 5.9913634322583675e-03</internalNodes>
+          <leafValues>
+            -6.6571407020092010e-02 2.3750782012939453e-01</leafValues></_>
         <_>
-          5 4 5 3 2.</_></rects>
-      <tilted>0</tilted></_>
-    <_>
-      <rects>
+          <internalNodes>
+            0 -1 299 3.7381309084594250e-03</internalNodes>
+          <leafValues>
+            3.7266705185174942e-02 -4.3619966506958008e-01</leafValues></_>
         <_>
-          0 1 10 10 -1.</_>
+          <internalNodes>
+            0 -1 372 8.8815446943044662e-03</internalNodes>
+          <leafValues>
+            3.0544634908437729e-02 -4.6924960613250732e-01</leafValues></_>
         <_>
-          0 1 5 5 2.</_>
+          <internalNodes>
+            0 -1 243 -3.1860180199146271e-02</internalNodes>
+          <leafValues>
+            -4.8059463500976562e-01 3.1165035441517830e-02</leafValues></_>
         <_>
-          5 6 5 5 2.</_></rects>
-      <tilted>0</tilted></_>
-    <_>
-      <rects>
+          <internalNodes>
+            0 -1 881 -5.4914336651563644e-03</internalNodes>
+          <leafValues>
+            1.7584608495235443e-01 -9.0091012418270111e-02</leafValues></_>
         <_>
-          0 1 24 2 -1.</_>
+          <internalNodes>
+            0 -1 821 -1.2325609102845192e-02</internalNodes>
+          <leafValues>
+            3.4678825736045837e-01 -5.6969922035932541e-02</leafValues></_>
         <_>
-          0 1 12 1 2.</_>
+          <internalNodes>
+            0 -1 281 5.8694169856607914e-03</internalNodes>
+          <leafValues>
+            3.9381653070449829e-02 -4.6237498521804810e-01</leafValues></_>
         <_>
-          12 2 12 1 2.</_></rects>
-      <tilted>0</tilted></_>
-    <_>
-      <rects>
+          <internalNodes>
+            0 -1 207 -5.0925426185131073e-03</internalNodes>
+          <leafValues>
+            -4.0191245079040527e-01 4.1170045733451843e-02</leafValues></_>
         <_>
-          0 2 18 9 -1.</_>
+          <internalNodes>
+            0 -1 636 4.5132841914892197e-03</internalNodes>
+          <leafValues>
+            2.7933681383728981e-02 -4.8419687151908875e-01</leafValues></_>
         <_>
-          0 5 18 3 3.</_></rects>
-      <tilted>0</tilted></_>
-    <_>
-      <rects>
+          <internalNodes>
+            0 -1 665 2.2130757570266724e-02</internalNodes>
+          <leafValues>
+            2.1358741447329521e-02 -6.0434627532958984e-01</leafValues></_>
         <_>
-          0 3 6 9 -1.</_>
+          <internalNodes>
+            0 -1 597 -1.8624030053615570e-03</internalNodes>
+          <leafValues>
+            1.9556084275245667e-01 -7.8905813395977020e-02</leafValues></_>
         <_>
-          0 6 6 3 3.</_></rects>
-      <tilted>0</tilted></_>
-    <_>
-      <rects>
+          <internalNodes>
+            0 -1 599 3.2466566190123558e-03</internalNodes>
+          <leafValues>
+            -8.3141714334487915e-02 2.5859814882278442e-01</leafValues></_>
         <_>
-          0 3 24 2 -1.</_>
+          <internalNodes>
+            0 -1 575 1.9641252234578133e-02</internalNodes>
+          <leafValues>
+            2.1901637315750122e-02 -7.2247391939163208e-01</leafValues></_>
         <_>
-          0 3 12 1 2.</_>
+          <internalNodes>
+            0 -1 271 1.2722628191113472e-02</internalNodes>
+          <leafValues>
+            -4.9173772335052490e-02 3.1656193733215332e-01</leafValues></_>
         <_>
-          12 4 12 1 2.</_></rects>
-      <tilted>0</tilted></_>
+          <internalNodes>
+            0 -1 210 -3.9457585080526769e-04</internalNodes>
+          <leafValues>
+            1.7969387769699097e-01 -1.0087045282125473e-01</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 88 -3.0111533123999834e-04</internalNodes>
+          <leafValues>
+            1.2916654348373413e-01 -1.5019074082374573e-01</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 84 -4.1901473887264729e-03</internalNodes>
+          <leafValues>
+            1.6727919876575470e-01 -9.4101771712303162e-02</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 186 -2.9096096754074097e-02</internalNodes>
+          <leafValues>
+            2.4397623538970947e-01 -6.5033406019210815e-02</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 815 -3.0687432736158371e-02</internalNodes>
+          <leafValues>
+            -5.3695982694625854e-01 3.6870311945676804e-02</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 596 8.9634142816066742e-02</internalNodes>
+          <leafValues>
+            -4.5044522732496262e-02 3.7668040394783020e-01</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 765 -1.8486939370632172e-02</internalNodes>
+          <leafValues>
+            -4.5869186520576477e-01 3.6696173250675201e-02</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 561 -2.0481455139815807e-03</internalNodes>
+          <leafValues>
+            1.9705456495285034e-01 -8.1085532903671265e-02</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 160 7.9915560781955719e-03</internalNodes>
+          <leafValues>
+            2.6794398203492165e-02 -6.0658437013626099e-01</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 368 -4.5167207717895508e-03</internalNodes>
+          <leafValues>
+            -3.5664665699005127e-01 4.1606105864048004e-02</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 429 -8.8896900415420532e-03</internalNodes>
+          <leafValues>
+            -5.6794744729995728e-01 2.4264462292194366e-02</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 601 -2.7863893657922745e-02</internalNodes>
+          <leafValues>
+            -6.6293621063232422e-01 1.7915287986397743e-02</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 153 1.9837494473904371e-03</internalNodes>
+          <leafValues>
+            -5.5686347186565399e-02 2.7396288514137268e-01</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 624 -2.9144049622118473e-03</internalNodes>
+          <leafValues>
+            -4.3623712658882141e-01 3.1940482556819916e-02</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 924 -1.1720246402546763e-03</internalNodes>
+          <leafValues>
+            1.5299941599369049e-01 -8.8886320590972900e-02</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 927 2.1249109413474798e-03</internalNodes>
+          <leafValues>
+            -7.1360021829605103e-02 2.0698173344135284e-01</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 602 4.6013649553060532e-03</internalNodes>
+          <leafValues>
+            2.5328675284981728e-02 -5.1310408115386963e-01</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 644 -9.4112986698746681e-04</internalNodes>
+          <leafValues>
+            -2.9404127597808838e-01 4.4868268072605133e-02</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 719 5.2681900560855865e-03</internalNodes>
+          <leafValues>
+            -6.4163528382778168e-02 2.2999708354473114e-01</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 652 1.4232876710593700e-03</internalNodes>
+          <leafValues>
+            -7.8037962317466736e-02 1.9061613082885742e-01</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 858 -1.0191567242145538e-02</internalNodes>
+          <leafValues>
+            -5.7409489154815674e-01 2.2581731900572777e-02</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 547 -4.9564028158783913e-03</internalNodes>
+          <leafValues>
+            2.4646909534931183e-01 -5.9094201773405075e-02</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 545 2.2057720925658941e-03</internalNodes>
+          <leafValues>
+            -9.8776444792747498e-02 1.9191808998584747e-01</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 809 -4.7279503196477890e-03</internalNodes>
+          <leafValues>
+            -2.9638877511024475e-01 4.7132529318332672e-02</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 905 1.8900397699326277e-03</internalNodes>
+          <leafValues>
+            -1.2390431761741638e-01 1.2199163436889648e-01</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 692 -3.9616838330402970e-04</internalNodes>
+          <leafValues>
+            -2.0177872478961945e-01 6.7829817533493042e-02</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 378 1.5198520850390196e-03</internalNodes>
+          <leafValues>
+            -5.0418090075254440e-02 2.8014704585075378e-01</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 377 -3.0729006975889206e-03</internalNodes>
+          <leafValues>
+            1.6384753584861755e-01 -9.6394442021846771e-02</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 637 3.3707641065120697e-02</internalNodes>
+          <leafValues>
+            3.3062599599361420e-02 -4.3530252575874329e-01</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 993 -2.7547087520360947e-03</internalNodes>
+          <leafValues>
+            -6.2498420476913452e-01 2.0407166332006454e-02</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 993 1.0800797026604414e-03</internalNodes>
+          <leafValues>
+            4.3235320597887039e-02 -3.1784874200820923e-01</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 981 -2.4060246068984270e-03</internalNodes>
+          <leafValues>
+            1.3923163712024689e-01 -9.8239123821258545e-02</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 727 4.6191983856260777e-03</internalNodes>
+          <leafValues>
+            2.3523205891251564e-02 -6.0865134000778198e-01</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 284 2.1874131634831429e-03</internalNodes>
+          <leafValues>
+            -4.4655255973339081e-02 3.2406413555145264e-01</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 137 7.9257078468799591e-03</internalNodes>
+          <leafValues>
+            2.8643675148487091e-02 -5.0231784582138062e-01</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 340 9.6561573445796967e-03</internalNodes>
+          <leafValues>
+            -6.7481219768524170e-02 2.0780794322490692e-01</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 180 -4.3771188706159592e-02</internalNodes>
+          <leafValues>
+            2.0091144740581512e-01 -8.7350860238075256e-02</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 28 -3.9570517838001251e-02</internalNodes>
+          <leafValues>
+            -6.9823634624481201e-01 2.2996466606855392e-02</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 517 -7.4827047064900398e-03</internalNodes>
+          <leafValues>
+            -3.2485857605934143e-01 4.2747449129819870e-02</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 863 -9.5894857076928020e-04</internalNodes>
+          <leafValues>
+            1.3692225515842438e-01 -1.0624063760042191e-01</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 495 -5.6482471525669098e-02</internalNodes>
+          <leafValues>
+            2.7130955457687378e-01 -5.5133864283561707e-02</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 526 -5.5641448125243187e-03</internalNodes>
+          <leafValues>
+            -6.5910613536834717e-01 2.6108600199222565e-02</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 833 4.5432001352310181e-03</internalNodes>
+          <leafValues>
+            -1.0277131199836731e-01 1.4715240895748138e-01</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 804 -1.9441416952759027e-03</internalNodes>
+          <leafValues>
+            1.7929133772850037e-01 -7.8247167170047760e-02</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 615 1.5584268840029836e-03</internalNodes>
+          <leafValues>
+            5.2101351320743561e-02 -2.7727204561233521e-01</leafValues></_></weakClassifiers></_></stages>
+  <features>
     <_>
       <rects>
         <_>
-          0 4 16 15 -1.</_>
+          0 0 6 1 -1.</_>
         <_>
-          0 9 16 5 3.</_></rects>
+          3 0 3 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          0 4 22 6 -1.</_>
+          0 0 8 1 -1.</_>
         <_>
-          0 6 22 2 3.</_></rects>
+          4 0 4 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          0 4 24 6 -1.</_>
+          0 0 8 2 -1.</_>
         <_>
-          0 6 24 2 3.</_></rects>
+          4 0 4 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          0 5 24 2 -1.</_>
+          0 0 8 6 -1.</_>
         <_>
-          0 5 12 1 2.</_>
+          0 0 4 3 2.</_>
         <_>
-          12 6 12 1 2.</_></rects>
+          4 3 4 3 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          0 6 24 2 -1.</_>
+          0 0 8 12 -1.</_>
         <_>
-          0 6 12 1 2.</_>
+          0 0 4 6 2.</_>
         <_>
-          12 7 12 1 2.</_></rects>
+          4 6 4 6 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          0 6 24 3 -1.</_>
+          0 0 10 1 -1.</_>
         <_>
-          0 7 24 1 3.</_></rects>
+          5 0 5 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          0 7 8 2 -1.</_>
+          0 0 10 6 -1.</_>
         <_>
-          0 7 4 1 2.</_>
+          0 0 5 3 2.</_>
         <_>
-          4 8 4 1 2.</_></rects>
+          5 3 5 3 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          0 7 24 1 -1.</_>
+          0 0 24 1 -1.</_>
         <_>
-          8 7 8 1 3.</_></rects>
+          6 0 12 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          0 7 24 4 -1.</_>
-        <_>
-          0 7 12 2 2.</_>
+          0 0 24 2 -1.</_>
         <_>
-          12 9 12 2 2.</_></rects>
+          6 0 12 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          0 7 22 4 -1.</_>
+          0 0 14 8 -1.</_>
+        <_>
+          0 0 7 4 2.</_>
         <_>
-          0 8 22 2 2.</_></rects>
+          7 4 7 4 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          0 8 24 4 -1.</_>
+          0 0 16 8 -1.</_>
         <_>
-          0 8 12 2 2.</_>
+          0 0 8 4 2.</_>
         <_>
-          12 10 12 2 2.</_></rects>
+          8 4 8 4 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          0 8 24 6 -1.</_>
+          0 0 16 10 -1.</_>
         <_>
-          0 8 12 3 2.</_>
+          0 0 8 5 2.</_>
         <_>
-          12 11 12 3 2.</_></rects>
+          8 5 8 5 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          0 8 24 8 -1.</_>
-        <_>
-          0 8 12 4 2.</_>
+          0 0 24 1 -1.</_>
         <_>
-          12 12 12 4 2.</_></rects>
+          12 0 12 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          0 9 4 3 -1.</_>
+          0 0 13 10 -1.</_>
         <_>
-          0 10 4 1 3.</_></rects>
+          0 5 13 5 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          0 9 4 8 -1.</_>
+          0 1 16 10 -1.</_>
         <_>
-          0 11 4 4 2.</_></rects>
+          0 1 8 5 2.</_>
+        <_>
+          8 6 8 5 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          0 9 7 2 -1.</_>
+          0 1 13 15 -1.</_>
         <_>
-          0 10 7 1 2.</_></rects>
+          0 6 13 5 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          0 9 20 2 -1.</_>
+          0 2 8 12 -1.</_>
         <_>
-          0 9 10 1 2.</_>
+          0 2 4 6 2.</_>
         <_>
-          10 10 10 1 2.</_></rects>
+          4 8 4 6 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          0 9 22 2 -1.</_>
+          0 2 10 4 -1.</_>
         <_>
-          0 9 11 1 2.</_>
+          0 2 5 2 2.</_>
         <_>
-          11 10 11 1 2.</_></rects>
+          5 4 5 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          0 9 22 4 -1.</_>
+          0 4 24 2 -1.</_>
         <_>
-          0 9 11 2 2.</_>
+          0 4 12 1 2.</_>
         <_>
-          11 11 11 2 2.</_></rects>
+          12 5 12 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          0 9 22 10 -1.</_>
+          0 5 4 9 -1.</_>
         <_>
-          0 9 11 5 2.</_>
-        <_>
-          11 14 11 5 2.</_></rects>
+          0 8 4 3 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          0 9 24 4 -1.</_>
+          0 5 24 2 -1.</_>
         <_>
-          0 9 12 2 2.</_>
+          0 5 12 1 2.</_>
         <_>
-          12 11 12 2 2.</_></rects>
+          12 6 12 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          0 10 3 3 -1.</_>
+          0 5 24 4 -1.</_>
         <_>
-          0 11 3 1 3.</_></rects>
+          0 5 12 2 2.</_>
+        <_>
+          12 7 12 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          0 10 24 2 -1.</_>
+          0 6 5 8 -1.</_>
         <_>
-          0 10 12 1 2.</_>
-        <_>
-          12 11 12 1 2.</_></rects>
+          0 8 5 4 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          0 11 6 8 -1.</_>
-        <_>
-          0 11 3 4 2.</_>
+          0 6 22 17 -1.</_>
         <_>
-          3 15 3 4 2.</_></rects>
+          11 6 11 17 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          0 11 24 2 -1.</_>
+          0 6 24 2 -1.</_>
         <_>
-          0 11 12 1 2.</_>
+          0 6 12 1 2.</_>
         <_>
-          12 12 12 1 2.</_></rects>
+          12 7 12 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          0 11 24 7 -1.</_>
+          0 6 14 8 -1.</_>
         <_>
-          12 11 12 7 2.</_></rects>
+          0 10 14 4 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          0 12 6 10 -1.</_>
+          0 7 2 3 -1.</_>
         <_>
-          3 12 3 10 2.</_></rects>
+          0 8 2 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          0 13 22 10 -1.</_>
+          0 7 6 16 -1.</_>
         <_>
-          11 13 11 10 2.</_></rects>
+          3 7 3 16 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          0 14 8 6 -1.</_>
+          0 7 4 9 -1.</_>
         <_>
-          4 14 4 6 2.</_></rects>
+          0 10 4 3 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          0 15 18 7 -1.</_>
+          0 7 8 17 -1.</_>
         <_>
-          9 15 9 7 2.</_></rects>
+          4 7 4 17 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          0 16 10 3 -1.</_>
+          0 7 24 2 -1.</_>
         <_>
-          5 16 5 3 2.</_></rects>
+          6 7 12 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          0 17 3 3 -1.</_>
+          0 8 4 16 -1.</_>
         <_>
-          1 17 1 3 3.</_></rects>
+          2 8 2 16 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          0 17 3 4 -1.</_>
+          0 8 24 6 -1.</_>
+        <_>
+          0 8 12 3 2.</_>
         <_>
-          1 17 1 4 3.</_></rects>
+          12 11 12 3 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          0 18 6 4 -1.</_>
+          0 9 1 3 -1.</_>
         <_>
-          3 18 3 4 2.</_></rects>
+          0 10 1 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          0 18 10 4 -1.</_>
+          0 9 7 2 -1.</_>
         <_>
-          5 18 5 4 2.</_></rects>
+          0 10 7 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          0 18 9 3 -1.</_>
+          0 9 8 2 -1.</_>
         <_>
-          0 19 9 1 3.</_></rects>
+          0 10 8 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          0 18 18 6 -1.</_>
+          0 9 22 2 -1.</_>
         <_>
-          0 18 9 3 2.</_>
+          0 9 11 1 2.</_>
         <_>
-          9 21 9 3 2.</_></rects>
+          11 10 11 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          0 19 3 5 -1.</_>
+          0 9 24 2 -1.</_>
         <_>
-          1 19 1 5 3.</_></rects>
+          0 9 12 1 2.</_>
+        <_>
+          12 10 12 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          0 20 24 2 -1.</_>
+          0 9 24 4 -1.</_>
+        <_>
+          0 9 12 2 2.</_>
         <_>
-          6 20 12 2 2.</_></rects>
+          12 11 12 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          0 21 6 3 -1.</_>
+          0 10 2 2 -1.</_>
         <_>
-          0 22 6 1 3.</_></rects>
+          0 11 2 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          1 0 6 1 -1.</_>
+          0 10 4 10 -1.</_>
         <_>
-          4 0 3 1 2.</_></rects>
+          2 10 2 10 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          1 0 12 3 -1.</_>
+          0 10 4 3 -1.</_>
         <_>
-          4 0 6 3 2.</_></rects>
+          0 11 4 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          1 0 8 1 -1.</_>
+          0 10 5 3 -1.</_>
         <_>
-          5 0 4 1 2.</_></rects>
+          0 11 5 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          1 0 20 1 -1.</_>
+          0 10 22 2 -1.</_>
+        <_>
+          0 10 11 1 2.</_>
         <_>
-          6 0 10 1 2.</_></rects>
+          11 11 11 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          1 0 14 4 -1.</_>
+          0 10 24 2 -1.</_>
         <_>
-          1 0 7 2 2.</_>
+          0 10 12 1 2.</_>
         <_>
-          8 2 7 2 2.</_></rects>
+          12 11 12 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          1 0 14 8 -1.</_>
+          0 10 24 4 -1.</_>
         <_>
-          1 0 7 4 2.</_>
+          0 10 12 2 2.</_>
         <_>
-          8 4 7 4 2.</_></rects>
+          12 12 12 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          1 0 14 10 -1.</_>
-        <_>
-          1 0 7 5 2.</_>
+          0 10 24 14 -1.</_>
         <_>
-          8 5 7 5 2.</_></rects>
+          12 10 12 14 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          1 3 22 21 -1.</_>
+          0 11 3 3 -1.</_>
         <_>
-          12 3 11 21 2.</_></rects>
+          0 12 3 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          1 3 14 12 -1.</_>
+          0 11 6 8 -1.</_>
+        <_>
+          0 11 3 4 2.</_>
         <_>
-          1 6 14 6 2.</_></rects>
+          3 15 3 4 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          1 4 5 3 -1.</_>
+          0 11 24 4 -1.</_>
         <_>
-          1 5 5 1 3.</_></rects>
+          0 11 12 2 2.</_>
+        <_>
+          12 13 12 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          1 4 9 3 -1.</_>
+          0 12 18 7 -1.</_>
         <_>
-          1 5 9 1 3.</_></rects>
+          9 12 9 7 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          1 4 22 2 -1.</_>
+          0 12 22 2 -1.</_>
         <_>
-          1 4 11 1 2.</_>
+          0 12 11 1 2.</_>
         <_>
-          12 5 11 1 2.</_></rects>
+          11 13 11 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          1 4 22 18 -1.</_>
+          0 12 24 6 -1.</_>
         <_>
-          12 4 11 18 2.</_></rects>
+          12 12 12 6 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          1 5 21 6 -1.</_>
+          0 13 24 3 -1.</_>
         <_>
-          8 7 7 2 9.</_></rects>
+          6 13 12 3 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          1 5 22 2 -1.</_>
-        <_>
-          1 5 11 1 2.</_>
+          0 14 8 7 -1.</_>
         <_>
-          12 6 11 1 2.</_></rects>
+          4 14 4 7 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          1 6 4 3 -1.</_>
+          0 14 12 10 -1.</_>
         <_>
-          1 7 4 1 3.</_></rects>
+          0 14 6 5 2.</_>
+        <_>
+          6 19 6 5 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          1 6 22 2 -1.</_>
-        <_>
-          1 6 11 1 2.</_>
+          0 14 18 8 -1.</_>
         <_>
-          12 7 11 1 2.</_></rects>
+          6 14 6 8 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          1 6 13 8 -1.</_>
+          0 14 20 10 -1.</_>
         <_>
-          1 10 13 4 2.</_></rects>
+          10 14 10 10 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          1 7 6 2 -1.</_>
-        <_>
-          1 7 3 1 2.</_>
+          0 15 3 8 -1.</_>
         <_>
-          4 8 3 1 2.</_></rects>
+          1 15 1 8 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          1 7 12 6 -1.</_>
+          0 16 3 7 -1.</_>
         <_>
-          5 9 4 2 9.</_></rects>
+          1 16 1 7 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          1 7 4 9 -1.</_>
+          0 19 6 3 -1.</_>
         <_>
-          1 10 4 3 3.</_></rects>
+          0 20 6 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          1 7 21 2 -1.</_>
+          0 19 9 3 -1.</_>
         <_>
-          1 8 21 1 2.</_></rects>
+          0 20 9 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          1 8 20 4 -1.</_>
-        <_>
-          1 8 10 2 2.</_>
+          0 21 6 3 -1.</_>
         <_>
-          11 10 10 2 2.</_></rects>
+          0 22 6 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          1 8 23 3 -1.</_>
+          0 21 7 3 -1.</_>
         <_>
-          1 9 23 1 3.</_></rects>
+          0 22 7 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          1 9 20 2 -1.</_>
-        <_>
-          1 9 10 1 2.</_>
+          1 0 1 4 -1.</_>
         <_>
-          11 10 10 1 2.</_></rects>
+          1 2 1 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          1 9 20 6 -1.</_>
-        <_>
-          1 9 10 3 2.</_>
+          1 0 12 3 -1.</_>
         <_>
-          11 12 10 3 2.</_></rects>
+          4 0 6 3 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          1 9 22 2 -1.</_>
+          1 0 8 6 -1.</_>
         <_>
-          1 9 11 1 2.</_>
+          1 0 4 3 2.</_>
         <_>
-          12 10 11 1 2.</_></rects>
+          5 3 4 3 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          1 10 4 1 -1.</_>
+          1 0 8 4 -1.</_>
         <_>
-          3 10 2 1 2.</_></rects>
+          5 0 4 4 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          1 10 22 2 -1.</_>
+          1 0 22 2 -1.</_>
         <_>
-          1 10 11 1 2.</_>
+          1 0 11 1 2.</_>
         <_>
-          12 11 11 1 2.</_></rects>
+          12 1 11 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          1 12 8 1 -1.</_>
+          1 3 21 15 -1.</_>
         <_>
-          3 12 4 1 2.</_></rects>
+          8 8 7 5 9.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          1 12 8 12 -1.</_>
-        <_>
-          1 12 4 6 2.</_>
+          1 3 11 3 -1.</_>
         <_>
-          5 18 4 6 2.</_></rects>
+          1 4 11 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          1 12 20 2 -1.</_>
+          1 5 3 3 -1.</_>
         <_>
-          1 12 10 1 2.</_>
-        <_>
-          11 13 10 1 2.</_></rects>
+          1 6 3 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          1 13 3 11 -1.</_>
+          1 5 21 6 -1.</_>
         <_>
-          2 13 1 11 3.</_></rects>
+          8 7 7 2 9.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          1 13 22 4 -1.</_>
+          1 5 22 2 -1.</_>
         <_>
-          1 13 11 2 2.</_>
+          1 5 11 1 2.</_>
         <_>
-          12 15 11 2 2.</_></rects>
+          12 6 11 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          1 13 19 4 -1.</_>
+          1 6 4 3 -1.</_>
         <_>
-          1 15 19 2 2.</_></rects>
+          1 7 4 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          1 14 10 10 -1.</_>
-        <_>
-          1 14 5 5 2.</_>
+          1 6 5 3 -1.</_>
         <_>
-          6 19 5 5 2.</_></rects>
+          1 7 5 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          1 14 22 2 -1.</_>
+          1 6 22 2 -1.</_>
         <_>
-          1 14 11 1 2.</_>
+          1 6 11 1 2.</_>
         <_>
-          12 15 11 1 2.</_></rects>
+          12 7 11 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          1 15 3 8 -1.</_>
+          1 6 22 17 -1.</_>
         <_>
-          2 15 1 8 3.</_></rects>
+          12 6 11 17 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          1 16 3 1 -1.</_>
+          1 6 20 3 -1.</_>
         <_>
-          2 17 1 1 3.</_></rects>
-      <tilted>1</tilted></_>
+          1 7 20 1 3.</_></rects>
+      <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          1 16 3 3 -1.</_>
+          1 7 12 6 -1.</_>
         <_>
-          2 16 1 3 3.</_></rects>
+          5 9 4 2 9.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          1 17 3 1 -1.</_>
+          1 7 8 6 -1.</_>
         <_>
-          2 18 1 1 3.</_></rects>
-      <tilted>1</tilted></_>
+          1 9 8 2 3.</_></rects>
+      <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          1 17 3 7 -1.</_>
+          1 7 20 4 -1.</_>
+        <_>
+          1 7 10 2 2.</_>
         <_>
-          2 17 1 7 3.</_></rects>
+          11 9 10 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          2 0 20 1 -1.</_>
+          1 7 22 12 -1.</_>
         <_>
-          7 0 10 1 2.</_></rects>
+          1 11 22 4 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          2 0 14 12 -1.</_>
+          1 8 8 2 -1.</_>
         <_>
-          2 0 7 6 2.</_>
+          1 8 4 1 2.</_>
         <_>
-          9 6 7 6 2.</_></rects>
+          5 9 4 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          2 0 22 1 -1.</_>
+          1 8 9 3 -1.</_>
         <_>
-          13 0 11 1 2.</_></rects>
+          1 9 9 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          2 3 10 3 -1.</_>
+          1 8 22 4 -1.</_>
+        <_>
+          1 8 11 2 2.</_>
         <_>
-          2 4 10 1 3.</_></rects>
+          12 10 11 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          2 3 20 2 -1.</_>
+          1 9 20 2 -1.</_>
         <_>
-          2 3 10 1 2.</_>
+          1 9 10 1 2.</_>
         <_>
-          12 4 10 1 2.</_></rects>
+          11 10 10 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          2 4 3 3 -1.</_>
+          1 10 4 3 -1.</_>
         <_>
-          2 5 3 1 3.</_></rects>
+          3 10 2 3 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          2 4 20 2 -1.</_>
+          1 10 4 4 -1.</_>
         <_>
-          2 4 10 1 2.</_>
-        <_>
-          12 5 10 1 2.</_></rects>
+          1 11 4 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          2 4 22 18 -1.</_>
+          1 10 22 2 -1.</_>
+        <_>
+          1 10 11 1 2.</_>
         <_>
-          13 4 11 18 2.</_></rects>
+          12 11 11 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          2 5 1 3 -1.</_>
+          1 10 21 4 -1.</_>
         <_>
-          2 6 1 1 3.</_></rects>
+          1 11 21 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          2 5 2 2 -1.</_>
-        <_>
-          2 5 1 1 2.</_>
+          1 11 3 13 -1.</_>
         <_>
-          3 6 1 1 2.</_></rects>
+          2 11 1 13 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          2 5 20 2 -1.</_>
-        <_>
-          2 5 10 1 2.</_>
+          1 13 3 10 -1.</_>
         <_>
-          12 6 10 1 2.</_></rects>
+          2 13 1 10 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          2 6 3 3 -1.</_>
+          1 14 22 2 -1.</_>
+        <_>
+          1 14 11 1 2.</_>
         <_>
-          2 7 3 1 3.</_></rects>
+          12 15 11 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          2 6 20 2 -1.</_>
+          1 16 3 1 -1.</_>
         <_>
-          2 6 10 1 2.</_>
+          2 17 1 1 3.</_></rects>
+      <tilted>1</tilted></_>
+    <_>
+      <rects>
         <_>
-          12 7 10 1 2.</_></rects>
-      <tilted>0</tilted></_>
+          1 17 4 1 -1.</_>
+        <_>
+          2 18 2 1 2.</_></rects>
+      <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          2 6 22 2 -1.</_>
+          1 19 4 1 -1.</_>
+        <_>
+          2 20 2 1 2.</_></rects>
+      <tilted>1</tilted></_>
+    <_>
+      <rects>
         <_>
-          2 6 11 1 2.</_>
+          2 0 4 1 -1.</_>
         <_>
-          13 7 11 1 2.</_></rects>
+          4 0 2 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          2 6 22 6 -1.</_>
+          2 0 12 14 -1.</_>
         <_>
-          2 6 11 3 2.</_>
-        <_>
-          13 9 11 3 2.</_></rects>
+          6 0 4 14 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          2 6 19 3 -1.</_>
+          2 0 20 1 -1.</_>
         <_>
-          2 7 19 1 3.</_></rects>
+          7 0 10 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          2 7 7 3 -1.</_>
+          2 0 22 1 -1.</_>
         <_>
-          2 8 7 1 3.</_></rects>
+          13 0 11 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          2 7 7 4 -1.</_>
+          2 2 22 2 -1.</_>
+        <_>
+          2 2 11 1 2.</_>
         <_>
-          2 8 7 2 2.</_></rects>
+          13 3 11 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          2 7 21 4 -1.</_>
+          2 2 22 10 -1.</_>
         <_>
-          2 8 21 2 2.</_></rects>
+          2 2 11 5 2.</_>
+        <_>
+          13 7 11 5 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          2 7 21 6 -1.</_>
+          2 3 20 1 -1.</_>
         <_>
-          2 9 21 2 3.</_></rects>
+          7 3 10 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          2 8 5 2 -1.</_>
+          2 3 20 2 -1.</_>
         <_>
-          2 8 5 1 2.</_></rects>
-      <tilted>1</tilted></_>
+          2 3 10 1 2.</_>
+        <_>
+          12 4 10 1 2.</_></rects>
+      <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          2 8 20 3 -1.</_>
+          2 4 3 3 -1.</_>
         <_>
-          2 9 20 1 3.</_></rects>
+          2 5 3 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          2 9 20 8 -1.</_>
+          2 4 20 2 -1.</_>
         <_>
-          2 9 10 4 2.</_>
+          2 4 10 1 2.</_>
         <_>
-          12 13 10 4 2.</_></rects>
+          12 5 10 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          2 9 22 2 -1.</_>
+          2 5 2 3 -1.</_>
         <_>
-          2 9 11 1 2.</_>
-        <_>
-          13 10 11 1 2.</_></rects>
+          2 6 2 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          2 9 19 3 -1.</_>
+          2 5 20 2 -1.</_>
+        <_>
+          2 5 10 1 2.</_>
         <_>
-          2 10 19 1 3.</_></rects>
+          12 6 10 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          2 10 3 1 -1.</_>
+          2 6 20 2 -1.</_>
+        <_>
+          2 6 10 1 2.</_>
         <_>
-          3 11 1 1 3.</_></rects>
-      <tilted>1</tilted></_>
+          12 7 10 1 2.</_></rects>
+      <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          2 10 4 1 -1.</_>
+          2 6 21 18 -1.</_>
         <_>
-          4 10 2 1 2.</_></rects>
+          2 15 21 9 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          2 10 22 2 -1.</_>
+          2 7 6 2 -1.</_>
         <_>
-          2 10 11 1 2.</_>
+          2 7 3 1 2.</_>
         <_>
-          13 11 11 1 2.</_></rects>
+          5 8 3 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          2 11 3 1 -1.</_>
+          2 7 9 6 -1.</_>
         <_>
-          3 12 1 1 3.</_></rects>
-      <tilted>1</tilted></_>
+          5 9 3 2 9.</_></rects>
+      <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          2 11 22 2 -1.</_>
-        <_>
-          2 11 11 1 2.</_>
+          2 7 7 3 -1.</_>
         <_>
-          13 12 11 1 2.</_></rects>
+          2 8 7 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          2 11 11 2 -1.</_>
+          2 7 18 2 -1.</_>
         <_>
-          2 11 11 1 2.</_></rects>
-      <tilted>1</tilted></_>
+          2 8 18 1 2.</_></rects>
+      <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          2 11 18 3 -1.</_>
+          2 7 18 3 -1.</_>
         <_>
-          2 12 18 1 3.</_></rects>
+          2 8 18 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          2 13 20 4 -1.</_>
+          2 7 21 4 -1.</_>
         <_>
-          2 13 10 2 2.</_>
+          2 8 21 2 2.</_></rects>
+      <tilted>0</tilted></_>
+    <_>
+      <rects>
+        <_>
+          2 8 4 2 -1.</_>
         <_>
-          12 15 10 2 2.</_></rects>
+          4 8 2 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          2 15 3 7 -1.</_>
+          2 8 22 2 -1.</_>
+        <_>
+          2 8 11 1 2.</_>
         <_>
-          3 15 1 7 3.</_></rects>
+          13 9 11 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          2 16 4 1 -1.</_>
+          2 9 7 2 -1.</_>
         <_>
-          3 17 2 1 2.</_></rects>
+          2 9 7 1 2.</_></rects>
       <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          2 17 3 5 -1.</_>
+          2 9 20 3 -1.</_>
         <_>
-          3 17 1 5 3.</_></rects>
+          2 10 20 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          3 0 9 16 -1.</_>
+          2 11 22 2 -1.</_>
+        <_>
+          2 11 11 1 2.</_>
         <_>
-          6 0 3 16 3.</_></rects>
+          13 12 11 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          3 0 18 3 -1.</_>
+          2 12 22 7 -1.</_>
         <_>
-          3 0 9 3 2.</_></rects>
-      <tilted>1</tilted></_>
+          13 12 11 7 2.</_></rects>
+      <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          3 2 18 2 -1.</_>
+          2 12 19 10 -1.</_>
         <_>
-          3 2 9 1 2.</_>
-        <_>
-          12 3 9 1 2.</_></rects>
+          2 17 19 5 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          3 3 12 1 -1.</_>
+          2 13 3 8 -1.</_>
         <_>
-          6 3 6 1 2.</_></rects>
+          3 13 1 8 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          3 3 20 3 -1.</_>
+          2 13 20 10 -1.</_>
         <_>
-          8 3 10 3 2.</_></rects>
+          12 13 10 10 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          3 3 18 2 -1.</_>
+          2 15 6 2 -1.</_>
         <_>
-          3 3 9 1 2.</_>
+          5 15 3 2 2.</_></rects>
+      <tilted>0</tilted></_>
+    <_>
+      <rects>
         <_>
-          12 4 9 1 2.</_></rects>
+          2 15 6 3 -1.</_>
+        <_>
+          5 15 3 3 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          3 4 1 3 -1.</_>
+          2 15 20 4 -1.</_>
+        <_>
+          2 15 10 2 2.</_>
         <_>
-          3 5 1 1 3.</_></rects>
+          12 17 10 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          3 4 5 16 -1.</_>
+          2 16 6 6 -1.</_>
+        <_>
+          2 16 3 3 2.</_>
         <_>
-          3 8 5 8 2.</_></rects>
+          5 19 3 3 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          3 4 18 8 -1.</_>
+          2 17 3 1 -1.</_>
         <_>
-          3 4 9 4 2.</_>
+          3 18 1 1 3.</_></rects>
+      <tilted>1</tilted></_>
+    <_>
+      <rects>
         <_>
-          12 8 9 4 2.</_></rects>
+          2 18 3 5 -1.</_>
+        <_>
+          3 18 1 5 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          3 4 20 19 -1.</_>
+          2 21 12 3 -1.</_>
         <_>
-          13 4 10 19 2.</_></rects>
+          8 21 6 3 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          3 5 20 2 -1.</_>
+          3 2 20 1 -1.</_>
         <_>
-          3 5 10 1 2.</_>
+          3 2 10 1 2.</_></rects>
+      <tilted>1</tilted></_>
+    <_>
+      <rects>
         <_>
-          13 6 10 1 2.</_></rects>
+          3 3 8 6 -1.</_>
+        <_>
+          5 3 4 6 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          3 5 16 9 -1.</_>
+          3 4 6 4 -1.</_>
+        <_>
+          3 4 3 2 2.</_>
         <_>
-          3 8 16 3 3.</_></rects>
+          6 6 3 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          3 5 20 9 -1.</_>
+          3 4 18 2 -1.</_>
         <_>
-          3 8 20 3 3.</_></rects>
+          3 4 9 1 2.</_>
+        <_>
+          12 5 9 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          3 6 2 3 -1.</_>
+          3 5 20 2 -1.</_>
+        <_>
+          3 5 10 1 2.</_>
         <_>
-          3 7 2 1 3.</_></rects>
+          13 6 10 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          3 6 18 2 -1.</_>
+          3 5 20 6 -1.</_>
         <_>
-          3 6 9 1 2.</_>
+          3 5 10 3 2.</_>
         <_>
-          12 7 9 1 2.</_></rects>
+          13 8 10 3 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          3 7 3 1 -1.</_>
+          3 6 3 3 -1.</_>
         <_>
-          4 7 1 1 3.</_></rects>
+          3 7 3 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          3 7 3 2 -1.</_>
+          3 6 16 8 -1.</_>
         <_>
-          3 8 3 1 2.</_></rects>
+          3 8 16 4 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          3 7 9 6 -1.</_>
+          3 6 19 6 -1.</_>
         <_>
-          6 9 3 2 9.</_></rects>
+          3 8 19 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          3 7 20 2 -1.</_>
+          3 7 5 4 -1.</_>
         <_>
-          8 7 10 2 2.</_></rects>
+          3 8 5 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          3 7 6 2 -1.</_>
+          3 7 18 6 -1.</_>
+        <_>
+          3 7 9 3 2.</_>
         <_>
-          3 8 6 1 2.</_></rects>
+          12 10 9 3 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          3 7 7 3 -1.</_>
+          3 7 17 6 -1.</_>
         <_>
-          3 8 7 1 3.</_></rects>
+          3 9 17 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          3 7 18 4 -1.</_>
+          3 7 19 2 -1.</_>
         <_>
-          3 7 9 2 2.</_>
-        <_>
-          12 9 9 2 2.</_></rects>
+          3 8 19 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          3 7 19 12 -1.</_>
+          3 8 18 4 -1.</_>
+        <_>
+          3 8 9 2 2.</_>
         <_>
-          3 11 19 4 3.</_></rects>
+          12 10 9 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
@@ -6886,18 +7264,16 @@
     <_>
       <rects>
         <_>
-          3 9 6 3 -1.</_>
+          3 9 3 3 -1.</_>
         <_>
-          3 10 6 1 3.</_></rects>
-      <tilted>0</tilted></_>
+          4 10 1 3 3.</_></rects>
+      <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          3 9 16 2 -1.</_>
+          3 9 8 9 -1.</_>
         <_>
-          3 9 8 1 2.</_>
-        <_>
-          11 10 8 1 2.</_></rects>
+          3 12 8 3 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
@@ -6911,11 +7287,16 @@
     <_>
       <rects>
         <_>
-          3 9 20 12 -1.</_>
+          3 9 19 9 -1.</_>
+        <_>
+          3 12 19 3 3.</_></rects>
+      <tilted>0</tilted></_>
+    <_>
+      <rects>
         <_>
-          3 9 10 6 2.</_>
+          3 10 3 1 -1.</_>
         <_>
-          13 15 10 6 2.</_></rects>
+          4 10 1 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
@@ -6934,184 +7315,190 @@
     <_>
       <rects>
         <_>
-          3 10 15 3 -1.</_>
+          3 10 2 4 -1.</_>
         <_>
-          3 11 15 1 3.</_></rects>
+          3 11 2 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          3 10 20 8 -1.</_>
+          3 10 8 3 -1.</_>
         <_>
-          3 12 20 4 2.</_></rects>
+          3 11 8 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          3 11 3 1 -1.</_>
+          3 10 18 4 -1.</_>
         <_>
-          4 12 1 1 3.</_></rects>
-      <tilted>1</tilted></_>
+          3 10 9 2 2.</_>
+        <_>
+          12 12 9 2 2.</_></rects>
+      <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          3 11 3 3 -1.</_>
+          3 11 3 1 -1.</_>
         <_>
-          4 11 1 3 3.</_></rects>
-      <tilted>0</tilted></_>
+          4 12 1 1 3.</_></rects>
+      <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          3 11 3 4 -1.</_>
+          3 11 3 8 -1.</_>
         <_>
-          4 11 1 4 3.</_></rects>
+          4 11 1 8 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          3 11 3 7 -1.</_>
+          3 11 4 8 -1.</_>
         <_>
-          4 11 1 7 3.</_></rects>
+          3 15 4 4 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          3 11 6 2 -1.</_>
+          3 11 18 2 -1.</_>
         <_>
-          3 11 3 1 2.</_>
+          3 11 9 1 2.</_>
         <_>
-          6 12 3 1 2.</_></rects>
+          12 12 9 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          3 11 3 8 -1.</_>
+          3 11 10 2 -1.</_>
         <_>
-          3 15 3 4 2.</_></rects>
-      <tilted>0</tilted></_>
+          3 11 10 1 2.</_></rects>
+      <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          3 11 7 8 -1.</_>
+          3 12 3 2 -1.</_>
         <_>
-          3 15 7 4 2.</_></rects>
-      <tilted>0</tilted></_>
+          4 13 1 2 3.</_></rects>
+      <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          3 11 20 2 -1.</_>
-        <_>
-          3 11 10 1 2.</_>
+          3 12 8 12 -1.</_>
         <_>
-          13 12 10 1 2.</_></rects>
+          3 16 8 4 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          3 11 20 8 -1.</_>
+          3 15 4 3 -1.</_>
         <_>
-          13 11 10 8 2.</_></rects>
+          5 15 2 3 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          3 12 4 8 -1.</_>
+          3 16 3 1 -1.</_>
         <_>
-          5 12 2 8 2.</_></rects>
-      <tilted>0</tilted></_>
+          4 17 1 1 3.</_></rects>
+      <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          3 12 3 8 -1.</_>
+          3 16 6 4 -1.</_>
         <_>
-          3 16 3 4 2.</_></rects>
+          3 16 3 2 2.</_>
+        <_>
+          6 18 3 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          3 12 18 8 -1.</_>
+          3 16 8 6 -1.</_>
+        <_>
+          3 16 4 3 2.</_>
         <_>
-          3 16 18 4 2.</_></rects>
+          7 19 4 3 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          3 13 3 3 -1.</_>
+          3 20 3 4 -1.</_>
         <_>
-          4 13 1 3 3.</_></rects>
+          4 20 1 4 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          3 13 19 6 -1.</_>
+          4 0 6 4 -1.</_>
         <_>
-          3 16 19 3 2.</_></rects>
-      <tilted>0</tilted></_>
+          6 2 2 4 3.</_></rects>
+      <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          3 14 6 10 -1.</_>
+          4 2 3 2 -1.</_>
         <_>
-          3 14 3 5 2.</_>
-        <_>
-          6 19 3 5 2.</_></rects>
+          5 2 1 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          3 15 6 2 -1.</_>
+          4 2 16 2 -1.</_>
+        <_>
+          4 2 8 1 2.</_>
         <_>
-          6 15 3 2 2.</_></rects>
+          12 3 8 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          3 16 4 1 -1.</_>
+          4 3 6 1 -1.</_>
         <_>
-          4 17 2 1 2.</_></rects>
-      <tilted>1</tilted></_>
+          6 3 2 1 3.</_></rects>
+      <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          3 20 3 3 -1.</_>
+          4 3 9 3 -1.</_>
         <_>
-          4 20 1 3 3.</_></rects>
+          7 3 3 3 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          4 0 16 20 -1.</_>
+          4 3 16 2 -1.</_>
         <_>
-          4 10 16 10 2.</_></rects>
+          4 3 8 1 2.</_>
+        <_>
+          12 4 8 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          4 2 8 13 -1.</_>
+          4 3 9 6 -1.</_>
         <_>
-          6 2 4 13 2.</_></rects>
+          4 6 9 3 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          4 2 16 1 -1.</_>
+          4 3 16 8 -1.</_>
         <_>
-          4 2 8 1 2.</_></rects>
-      <tilted>1</tilted></_>
+          4 7 16 4 2.</_></rects>
+      <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          4 3 16 8 -1.</_>
+          4 4 1 4 -1.</_>
         <_>
-          4 7 16 4 2.</_></rects>
+          4 6 1 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          4 4 2 4 -1.</_>
+          4 4 9 4 -1.</_>
         <_>
-          4 6 2 2 2.</_></rects>
-      <tilted>0</tilted></_>
+          7 7 3 4 3.</_></rects>
+      <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
@@ -7124,46 +7511,39 @@
     <_>
       <rects>
         <_>
-          4 4 18 2 -1.</_>
-        <_>
-          4 4 9 1 2.</_>
+          4 4 18 6 -1.</_>
         <_>
-          13 5 9 1 2.</_></rects>
+          4 6 18 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          4 4 10 6 -1.</_>
+          4 4 20 6 -1.</_>
         <_>
-          4 7 10 3 2.</_></rects>
+          4 6 20 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          4 4 17 6 -1.</_>
+          4 5 4 5 -1.</_>
         <_>
-          4 7 17 3 2.</_></rects>
+          6 5 2 5 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          4 5 1 3 -1.</_>
-        <_>
-          4 6 1 1 3.</_></rects>
-      <tilted>0</tilted></_>
-    <_>
-      <rects>
+          4 5 16 6 -1.</_>
         <_>
-          4 5 3 3 -1.</_>
+          4 5 8 3 2.</_>
         <_>
-          5 6 1 3 3.</_></rects>
-      <tilted>1</tilted></_>
+          12 8 8 3 2.</_></rects>
+      <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          4 5 17 6 -1.</_>
+          4 5 15 6 -1.</_>
         <_>
-          4 8 17 3 2.</_></rects>
+          4 7 15 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
@@ -7182,409 +7562,403 @@
     <_>
       <rects>
         <_>
-          4 6 3 3 -1.</_>
+          4 6 6 2 -1.</_>
         <_>
-          4 7 3 1 3.</_></rects>
+          6 6 2 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          4 6 4 9 -1.</_>
+          4 6 3 3 -1.</_>
         <_>
-          4 9 4 3 3.</_></rects>
+          4 7 3 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          4 6 16 2 -1.</_>
+          4 6 6 2 -1.</_>
         <_>
-          4 6 8 1 2.</_>
+          4 6 3 1 2.</_>
         <_>
-          12 7 8 1 2.</_></rects>
+          7 7 3 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          4 6 16 6 -1.</_>
-        <_>
-          4 6 8 3 2.</_>
+          4 7 4 3 -1.</_>
         <_>
-          12 9 8 3 2.</_></rects>
+          4 8 4 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          4 6 20 18 -1.</_>
+          4 7 15 6 -1.</_>
         <_>
-          14 6 10 18 2.</_></rects>
+          4 9 15 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          4 6 15 6 -1.</_>
+          4 7 16 6 -1.</_>
         <_>
-          4 8 15 2 3.</_></rects>
+          4 9 16 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          4 6 16 4 -1.</_>
+          4 7 17 3 -1.</_>
         <_>
-          4 7 16 2 2.</_></rects>
+          4 8 17 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          4 6 16 4 -1.</_>
+          4 8 3 3 -1.</_>
         <_>
-          4 8 16 2 2.</_></rects>
+          5 9 1 1 9.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          4 7 6 6 -1.</_>
+          4 8 2 3 -1.</_>
         <_>
-          6 9 2 2 9.</_></rects>
+          4 9 2 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          4 7 5 4 -1.</_>
+          4 8 5 4 -1.</_>
         <_>
-          3 8 5 2 2.</_></rects>
-      <tilted>1</tilted></_>
+          4 9 5 2 2.</_></rects>
+      <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          4 7 5 6 -1.</_>
+          4 8 18 4 -1.</_>
+        <_>
+          4 8 9 2 2.</_>
         <_>
-          4 9 5 2 3.</_></rects>
+          13 10 9 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          4 7 16 6 -1.</_>
-        <_>
-          4 7 8 3 2.</_>
+          4 9 2 1 -1.</_>
         <_>
-          12 10 8 3 2.</_></rects>
+          5 9 1 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          4 7 16 6 -1.</_>
+          4 9 3 1 -1.</_>
         <_>
-          4 9 16 2 3.</_></rects>
+          5 9 1 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          4 7 17 6 -1.</_>
+          4 9 2 2 -1.</_>
+        <_>
+          4 9 1 1 2.</_>
         <_>
-          4 9 17 2 3.</_></rects>
+          5 10 1 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          4 7 18 2 -1.</_>
+          4 9 2 4 -1.</_>
+        <_>
+          4 9 1 2 2.</_>
         <_>
-          4 8 18 1 2.</_></rects>
+          5 11 1 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          4 8 2 2 -1.</_>
-        <_>
-          4 8 1 1 2.</_>
+          4 9 3 2 -1.</_>
         <_>
-          5 9 1 1 2.</_></rects>
-      <tilted>0</tilted></_>
+          4 9 3 1 2.</_></rects>
+      <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          4 8 3 3 -1.</_>
+          4 9 6 6 -1.</_>
         <_>
-          5 9 1 1 9.</_></rects>
+          4 9 3 3 2.</_>
+        <_>
+          7 12 3 3 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          4 8 2 3 -1.</_>
+          4 9 16 1 -1.</_>
         <_>
-          4 9 2 1 3.</_></rects>
+          8 9 8 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          4 8 4 4 -1.</_>
+          4 9 16 2 -1.</_>
         <_>
-          3 9 4 2 2.</_></rects>
-      <tilted>1</tilted></_>
+          4 9 8 1 2.</_>
+        <_>
+          12 10 8 1 2.</_></rects>
+      <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          4 8 14 2 -1.</_>
+          4 9 18 2 -1.</_>
         <_>
-          4 8 7 1 2.</_>
+          4 9 9 1 2.</_>
         <_>
-          11 9 7 1 2.</_></rects>
+          13 10 9 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          4 8 7 4 -1.</_>
+          4 9 11 4 -1.</_>
         <_>
-          3 9 7 2 2.</_></rects>
+          4 9 11 2 2.</_></rects>
       <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          4 8 16 2 -1.</_>
+          4 10 2 2 -1.</_>
         <_>
-          4 8 8 1 2.</_>
+          4 10 1 1 2.</_>
         <_>
-          12 9 8 1 2.</_></rects>
+          5 11 1 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          4 8 9 4 -1.</_>
+          4 10 3 1 -1.</_>
         <_>
-          4 8 9 2 2.</_></rects>
+          5 11 1 1 3.</_></rects>
       <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          4 8 19 12 -1.</_>
+          4 10 3 2 -1.</_>
         <_>
-          4 12 19 4 3.</_></rects>
-      <tilted>0</tilted></_>
+          5 11 1 2 3.</_></rects>
+      <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          4 9 3 1 -1.</_>
+          4 10 3 14 -1.</_>
         <_>
-          5 9 1 1 3.</_></rects>
+          5 10 1 14 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          4 9 2 2 -1.</_>
-        <_>
-          4 9 1 1 2.</_>
+          4 10 9 4 -1.</_>
         <_>
-          5 10 1 1 2.</_></rects>
-      <tilted>0</tilted></_>
+          4 10 9 2 2.</_></rects>
+      <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          4 9 2 2 -1.</_>
+          4 10 10 4 -1.</_>
         <_>
-          5 9 1 2 2.</_></rects>
-      <tilted>0</tilted></_>
+          4 10 10 2 2.</_></rects>
+      <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          4 9 3 2 -1.</_>
+          4 10 16 6 -1.</_>
         <_>
-          5 10 1 2 3.</_></rects>
-      <tilted>1</tilted></_>
+          4 12 16 2 3.</_></rects>
+      <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          4 9 4 6 -1.</_>
+          4 11 3 1 -1.</_>
         <_>
-          4 11 4 2 3.</_></rects>
-      <tilted>0</tilted></_>
+          5 12 1 1 3.</_></rects>
+      <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          4 9 16 2 -1.</_>
-        <_>
-          4 9 8 1 2.</_>
+          4 11 3 2 -1.</_>
         <_>
-          12 10 8 1 2.</_></rects>
+          5 11 1 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          4 10 2 2 -1.</_>
-        <_>
-          4 10 1 1 2.</_>
+          4 11 3 4 -1.</_>
         <_>
-          5 11 1 1 2.</_></rects>
+          5 11 1 4 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          4 10 3 1 -1.</_>
+          4 11 3 10 -1.</_>
         <_>
-          5 11 1 1 3.</_></rects>
-      <tilted>1</tilted></_>
+          4 16 3 5 2.</_></rects>
+      <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          4 10 3 2 -1.</_>
+          4 12 3 1 -1.</_>
         <_>
-          5 11 1 2 3.</_></rects>
+          5 13 1 1 3.</_></rects>
       <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          4 10 4 4 -1.</_>
+          4 12 3 2 -1.</_>
         <_>
-          3 11 4 2 2.</_></rects>
-      <tilted>1</tilted></_>
+          5 12 1 2 3.</_></rects>
+      <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          4 10 9 4 -1.</_>
+          4 12 1 6 -1.</_>
         <_>
-          4 10 9 2 2.</_></rects>
-      <tilted>1</tilted></_>
+          4 15 1 3 2.</_></rects>
+      <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          4 10 10 4 -1.</_>
+          4 12 2 8 -1.</_>
         <_>
-          4 10 10 2 2.</_></rects>
-      <tilted>1</tilted></_>
+          4 16 2 4 2.</_></rects>
+      <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          4 11 3 2 -1.</_>
+          4 13 3 1 -1.</_>
         <_>
-          5 11 1 2 3.</_></rects>
+          5 13 1 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          4 11 3 6 -1.</_>
+          4 13 4 3 -1.</_>
         <_>
-          5 11 1 6 3.</_></rects>
+          6 13 2 3 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          4 11 3 2 -1.</_>
+          4 13 9 5 -1.</_>
         <_>
-          4 11 3 1 2.</_></rects>
-      <tilted>1</tilted></_>
+          7 13 3 5 3.</_></rects>
+      <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          4 11 3 10 -1.</_>
+          4 14 4 1 -1.</_>
         <_>
-          4 16 3 5 2.</_></rects>
+          6 14 2 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          4 11 7 2 -1.</_>
+          4 15 3 2 -1.</_>
         <_>
-          4 11 7 1 2.</_></rects>
+          5 16 1 2 3.</_></rects>
       <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          4 11 9 4 -1.</_>
+          4 15 4 3 -1.</_>
         <_>
-          4 11 9 2 2.</_></rects>
-      <tilted>1</tilted></_>
+          6 15 2 3 2.</_></rects>
+      <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          4 12 3 1 -1.</_>
+          4 15 9 4 -1.</_>
         <_>
-          5 12 1 1 3.</_></rects>
+          7 15 3 4 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          4 12 3 3 -1.</_>
+          4 15 4 4 -1.</_>
         <_>
-          5 12 1 3 3.</_></rects>
+          4 16 4 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          4 12 2 6 -1.</_>
+          4 17 3 1 -1.</_>
         <_>
-          4 15 2 3 2.</_></rects>
-      <tilted>0</tilted></_>
+          5 18 1 1 3.</_></rects>
+      <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          4 12 16 2 -1.</_>
+          4 18 3 6 -1.</_>
         <_>
-          4 12 8 1 2.</_>
-        <_>
-          12 13 8 1 2.</_></rects>
+          5 18 1 6 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          4 13 4 4 -1.</_>
+          4 20 3 4 -1.</_>
         <_>
-          6 13 2 4 2.</_></rects>
+          5 20 1 4 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          4 13 10 10 -1.</_>
-        <_>
-          4 13 5 5 2.</_>
+          5 0 6 18 -1.</_>
         <_>
-          9 18 5 5 2.</_></rects>
+          7 0 2 18 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          4 14 4 2 -1.</_>
+          5 2 4 12 -1.</_>
         <_>
-          6 14 2 2 2.</_></rects>
+          7 2 2 12 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          4 14 5 4 -1.</_>
+          5 2 14 2 -1.</_>
         <_>
-          3 15 5 2 2.</_></rects>
+          5 2 7 2 2.</_></rects>
       <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          4 15 4 3 -1.</_>
+          5 2 15 6 -1.</_>
         <_>
-          6 15 2 3 2.</_></rects>
+          5 5 15 3 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          4 19 3 4 -1.</_>
+          5 3 1 3 -1.</_>
         <_>
-          5 19 1 4 3.</_></rects>
-      <tilted>0</tilted></_>
+          4 4 1 1 3.</_></rects>
+      <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          5 0 14 1 -1.</_>
+          5 3 2 3 -1.</_>
         <_>
-          12 0 7 1 2.</_></rects>
-      <tilted>0</tilted></_>
+          4 4 2 1 3.</_></rects>
+      <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          5 1 10 8 -1.</_>
+          5 3 4 9 -1.</_>
         <_>
-          5 5 10 4 2.</_></rects>
+          7 3 2 9 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          5 1 12 10 -1.</_>
+          5 3 9 3 -1.</_>
         <_>
-          5 6 12 5 2.</_></rects>
+          8 4 3 1 9.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
@@ -7598,94 +7972,92 @@
     <_>
       <rects>
         <_>
-          5 3 7 4 -1.</_>
+          5 4 2 3 -1.</_>
         <_>
-          4 4 7 2 2.</_></rects>
+          4 5 2 1 3.</_></rects>
       <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          5 4 2 2 -1.</_>
+          5 4 16 2 -1.</_>
         <_>
-          5 4 2 1 2.</_></rects>
-      <tilted>1</tilted></_>
+          5 4 8 1 2.</_>
+        <_>
+          13 5 8 1 2.</_></rects>
+      <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          5 4 14 6 -1.</_>
-        <_>
-          5 4 7 3 2.</_>
+          5 5 1 3 -1.</_>
         <_>
-          12 7 7 3 2.</_></rects>
-      <tilted>0</tilted></_>
+          4 6 1 1 3.</_></rects>
+      <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          5 4 9 4 -1.</_>
+          5 5 4 9 -1.</_>
         <_>
-          4 5 9 2 2.</_></rects>
-      <tilted>1</tilted></_>
+          5 8 4 3 3.</_></rects>
+      <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          5 4 18 8 -1.</_>
+          5 5 14 2 -1.</_>
         <_>
-          5 4 9 4 2.</_>
+          5 5 7 1 2.</_>
         <_>
-          14 8 9 4 2.</_></rects>
+          12 6 7 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          5 5 1 3 -1.</_>
+          5 5 15 6 -1.</_>
         <_>
-          4 6 1 1 3.</_></rects>
-      <tilted>1</tilted></_>
+          5 7 15 2 3.</_></rects>
+      <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          5 5 14 2 -1.</_>
-        <_>
-          5 5 7 1 2.</_>
+          5 6 1 2 -1.</_>
         <_>
-          12 6 7 1 2.</_></rects>
+          5 7 1 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          5 5 14 4 -1.</_>
-        <_>
-          5 5 7 2 2.</_>
+          5 6 4 4 -1.</_>
         <_>
-          12 7 7 2 2.</_></rects>
+          5 7 4 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          5 5 14 6 -1.</_>
+          5 6 14 2 -1.</_>
         <_>
-          5 7 14 2 3.</_></rects>
+          5 6 7 1 2.</_>
+        <_>
+          12 7 7 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          5 5 14 9 -1.</_>
+          5 6 14 4 -1.</_>
         <_>
-          5 8 14 3 3.</_></rects>
+          5 7 14 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          5 6 15 8 -1.</_>
+          5 6 14 6 -1.</_>
         <_>
-          5 8 15 4 2.</_></rects>
+          5 8 14 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          5 6 16 6 -1.</_>
+          5 6 15 4 -1.</_>
         <_>
-          5 8 16 2 3.</_></rects>
+          5 7 15 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
@@ -7697,16 +8069,23 @@
     <_>
       <rects>
         <_>
-          5 7 3 6 -1.</_>
+          5 7 4 15 -1.</_>
+        <_>
+          6 7 2 15 2.</_></rects>
+      <tilted>0</tilted></_>
+    <_>
+      <rects>
         <_>
-          6 9 1 2 9.</_></rects>
+          5 7 4 1 -1.</_>
+        <_>
+          7 7 2 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          5 7 6 7 -1.</_>
+          5 7 3 2 -1.</_>
         <_>
-          7 7 2 7 3.</_></rects>
+          5 8 3 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
@@ -7718,6 +8097,13 @@
     <_>
       <rects>
         <_>
+          5 7 3 4 -1.</_>
+        <_>
+          5 8 3 2 2.</_></rects>
+      <tilted>0</tilted></_>
+    <_>
+      <rects>
+        <_>
           5 7 3 6 -1.</_>
         <_>
           5 9 3 2 3.</_></rects>
@@ -7725,6 +8111,13 @@
     <_>
       <rects>
         <_>
+          5 7 4 4 -1.</_>
+        <_>
+          5 9 4 2 2.</_></rects>
+      <tilted>0</tilted></_>
+    <_>
+      <rects>
+        <_>
           5 7 4 6 -1.</_>
         <_>
           5 9 4 2 3.</_></rects>
@@ -7732,16 +8125,25 @@
     <_>
       <rects>
         <_>
-          5 7 5 4 -1.</_>
+          5 7 16 4 -1.</_>
         <_>
-          4 8 5 2 2.</_></rects>
-      <tilted>1</tilted></_>
+          5 7 8 2 2.</_>
+        <_>
+          13 9 8 2 2.</_></rects>
+      <tilted>0</tilted></_>
+    <_>
+      <rects>
+        <_>
+          5 7 14 2 -1.</_>
+        <_>
+          5 8 14 1 2.</_></rects>
+      <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          5 7 15 6 -1.</_>
+          5 7 16 6 -1.</_>
         <_>
-          5 9 15 2 3.</_></rects>
+          5 9 16 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
@@ -7769,6 +8171,13 @@
     <_>
       <rects>
         <_>
+          5 8 3 4 -1.</_>
+        <_>
+          4 9 3 2 2.</_></rects>
+      <tilted>1</tilted></_>
+    <_>
+      <rects>
+        <_>
           5 8 4 4 -1.</_>
         <_>
           5 9 4 2 2.</_></rects>
@@ -7792,16 +8201,18 @@
     <_>
       <rects>
         <_>
-          5 8 13 2 -1.</_>
+          5 8 16 2 -1.</_>
+        <_>
+          5 8 8 1 2.</_>
         <_>
-          5 9 13 1 2.</_></rects>
+          13 9 8 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          5 8 15 4 -1.</_>
+          5 8 13 16 -1.</_>
         <_>
-          5 9 15 2 2.</_></rects>
+          5 12 13 8 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
@@ -7813,13 +8224,20 @@
     <_>
       <rects>
         <_>
-          5 9 15 2 -1.</_>
+          5 9 4 3 -1.</_>
         <_>
-          10 9 5 2 3.</_></rects>
+          5 10 4 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
+          5 9 4 4 -1.</_>
+        <_>
+          5 9 4 2 2.</_></rects>
+      <tilted>1</tilted></_>
+    <_>
+      <rects>
+        <_>
           5 9 14 2 -1.</_>
         <_>
           5 9 7 1 2.</_>
@@ -7829,36 +8247,48 @@
     <_>
       <rects>
         <_>
-          5 9 14 6 -1.</_>
+          5 9 16 2 -1.</_>
         <_>
-          5 9 7 3 2.</_>
+          5 9 8 1 2.</_>
         <_>
-          12 12 7 3 2.</_></rects>
+          13 10 8 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          5 9 16 2 -1.</_>
+          5 9 15 3 -1.</_>
         <_>
-          5 9 8 1 2.</_>
+          5 10 15 1 3.</_></rects>
+      <tilted>0</tilted></_>
+    <_>
+      <rects>
         <_>
-          13 10 8 1 2.</_></rects>
+          5 10 2 2 -1.</_>
+        <_>
+          5 10 1 1 2.</_>
+        <_>
+          6 11 1 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          5 10 2 2 -1.</_>
+          5 10 3 1 -1.</_>
         <_>
-          5 10 1 1 2.</_>
+          6 11 1 1 3.</_></rects>
+      <tilted>1</tilted></_>
+    <_>
+      <rects>
         <_>
-          6 11 1 1 2.</_></rects>
+          5 10 3 14 -1.</_>
+        <_>
+          6 10 1 14 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          5 10 2 4 -1.</_>
+          5 10 4 3 -1.</_>
         <_>
-          6 10 1 4 2.</_></rects>
+          7 10 2 3 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
@@ -7870,23 +8300,23 @@
     <_>
       <rects>
         <_>
-          5 10 17 4 -1.</_>
+          5 10 14 3 -1.</_>
         <_>
-          5 11 17 2 2.</_></rects>
+          5 11 14 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          5 11 3 3 -1.</_>
+          5 10 16 8 -1.</_>
         <_>
-          6 11 1 3 3.</_></rects>
+          5 12 16 4 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          5 11 2 2 -1.</_>
+          5 11 3 2 -1.</_>
         <_>
-          5 12 2 1 2.</_></rects>
+          6 11 1 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
@@ -7898,103 +8328,107 @@
     <_>
       <rects>
         <_>
-          5 14 3 3 -1.</_>
+          5 12 3 2 -1.</_>
         <_>
-          6 15 1 1 9.</_></rects>
+          6 12 1 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          5 15 4 2 -1.</_>
-        <_>
-          6 16 2 2 2.</_></rects>
-      <tilted>1</tilted></_>
-    <_>
-      <rects>
+          5 12 14 2 -1.</_>
         <_>
-          5 15 8 5 -1.</_>
+          5 12 7 1 2.</_>
         <_>
-          7 15 4 5 2.</_></rects>
+          12 13 7 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          5 15 5 3 -1.</_>
+          5 13 14 2 -1.</_>
         <_>
-          4 16 5 1 3.</_></rects>
-      <tilted>1</tilted></_>
+          5 13 7 1 2.</_>
+        <_>
+          12 14 7 1 2.</_></rects>
+      <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          5 16 4 3 -1.</_>
+          5 13 14 10 -1.</_>
         <_>
-          5 17 4 1 3.</_></rects>
+          5 18 14 5 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          5 16 6 2 -1.</_>
+          5 15 4 1 -1.</_>
         <_>
-          5 16 6 1 2.</_></rects>
+          6 16 2 1 2.</_></rects>
       <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          5 17 3 1 -1.</_>
+          5 15 3 2 -1.</_>
         <_>
-          6 18 1 1 3.</_></rects>
+          6 16 1 2 3.</_></rects>
       <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          5 20 3 1 -1.</_>
+          5 19 3 4 -1.</_>
         <_>
-          6 21 1 1 3.</_></rects>
-      <tilted>1</tilted></_>
+          6 19 1 4 3.</_></rects>
+      <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          5 20 3 3 -1.</_>
+          5 20 3 4 -1.</_>
         <_>
-          6 20 1 3 3.</_></rects>
+          6 20 1 4 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          5 20 8 3 -1.</_>
+          6 1 6 11 -1.</_>
         <_>
-          9 20 4 3 2.</_></rects>
+          8 1 2 11 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          6 0 10 4 -1.</_>
+          6 1 12 2 -1.</_>
+        <_>
+          6 1 6 1 2.</_>
         <_>
-          6 1 10 2 2.</_></rects>
+          12 2 6 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          6 1 6 11 -1.</_>
+          6 2 1 3 -1.</_>
         <_>
-          8 1 2 11 3.</_></rects>
-      <tilted>0</tilted></_>
+          5 3 1 1 3.</_></rects>
+      <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          6 1 12 2 -1.</_>
+          6 2 4 6 -1.</_>
         <_>
-          6 1 6 1 2.</_>
+          6 2 4 3 2.</_></rects>
+      <tilted>1</tilted></_>
+    <_>
+      <rects>
         <_>
-          12 2 6 1 2.</_></rects>
-      <tilted>0</tilted></_>
+          6 2 12 6 -1.</_>
+        <_>
+          6 2 6 6 2.</_></rects>
+      <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          6 2 7 8 -1.</_>
+          6 3 1 2 -1.</_>
         <_>
-          6 6 7 4 2.</_></rects>
-      <tilted>0</tilted></_>
+          6 3 1 1 2.</_></rects>
+      <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
@@ -8005,27 +8439,48 @@
     <_>
       <rects>
         <_>
-          6 3 4 1 -1.</_>
+          6 3 6 1 -1.</_>
+        <_>
+          8 3 2 1 3.</_></rects>
+      <tilted>0</tilted></_>
+    <_>
+      <rects>
+        <_>
+          6 3 18 21 -1.</_>
+        <_>
+          15 3 9 21 2.</_></rects>
+      <tilted>0</tilted></_>
+    <_>
+      <rects>
+        <_>
+          6 4 1 3 -1.</_>
         <_>
-          7 4 2 1 2.</_></rects>
+          5 5 1 1 3.</_></rects>
       <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          6 3 6 1 -1.</_>
+          6 4 4 3 -1.</_>
         <_>
-          8 3 2 1 3.</_></rects>
+          6 5 4 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          6 4 3 4 -1.</_>
+          6 4 5 4 -1.</_>
         <_>
-          6 4 3 2 2.</_></rects>
+          5 5 5 2 2.</_></rects>
       <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
+          6 4 6 3 -1.</_>
+        <_>
+          6 5 6 1 3.</_></rects>
+      <tilted>0</tilted></_>
+    <_>
+      <rects>
+        <_>
           6 5 1 3 -1.</_>
         <_>
           5 6 1 1 3.</_></rects>
@@ -8040,9 +8495,9 @@
     <_>
       <rects>
         <_>
-          6 5 2 9 -1.</_>
+          6 5 3 3 -1.</_>
         <_>
-          6 8 2 3 3.</_></rects>
+          7 5 1 3 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
@@ -8056,25 +8511,32 @@
     <_>
       <rects>
         <_>
-          6 6 3 3 -1.</_>
+          6 6 10 2 -1.</_>
         <_>
-          5 7 3 1 3.</_></rects>
-      <tilted>1</tilted></_>
+          6 6 5 1 2.</_>
+        <_>
+          11 7 5 1 2.</_></rects>
+      <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          6 6 12 2 -1.</_>
+          6 6 5 3 -1.</_>
+        <_>
+          5 7 5 1 3.</_></rects>
+      <tilted>1</tilted></_>
+    <_>
+      <rects>
         <_>
-          6 6 6 1 2.</_>
+          6 7 1 3 -1.</_>
         <_>
-          12 7 6 1 2.</_></rects>
+          6 8 1 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          6 6 15 4 -1.</_>
+          6 7 1 6 -1.</_>
         <_>
-          6 7 15 2 2.</_></rects>
+          6 9 1 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
@@ -8093,26 +8555,26 @@
     <_>
       <rects>
         <_>
-          6 7 12 2 -1.</_>
-        <_>
-          6 7 6 1 2.</_>
+          6 7 3 6 -1.</_>
         <_>
-          12 8 6 1 2.</_></rects>
+          6 9 3 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          6 7 9 12 -1.</_>
+          6 7 12 2 -1.</_>
+        <_>
+          6 7 6 1 2.</_>
         <_>
-          6 13 9 6 2.</_></rects>
+          12 8 6 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          6 7 13 15 -1.</_>
+          6 8 3 1 -1.</_>
         <_>
-          6 12 13 5 3.</_></rects>
-      <tilted>0</tilted></_>
+          7 9 1 1 3.</_></rects>
+      <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
@@ -8123,50 +8585,57 @@
     <_>
       <rects>
         <_>
-          6 8 12 2 -1.</_>
-        <_>
-          6 8 6 1 2.</_>
+          6 8 2 3 -1.</_>
         <_>
-          12 9 6 1 2.</_></rects>
-      <tilted>0</tilted></_>
+          5 9 2 1 3.</_></rects>
+      <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          6 8 12 12 -1.</_>
+          6 8 3 4 -1.</_>
         <_>
-          6 11 12 6 2.</_></rects>
+          6 9 3 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          6 9 2 2 -1.</_>
+          6 8 3 3 -1.</_>
         <_>
-          6 9 1 2 2.</_></rects>
+          5 9 3 1 3.</_></rects>
       <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          6 9 3 6 -1.</_>
+          6 8 12 3 -1.</_>
         <_>
-          7 10 1 6 3.</_></rects>
-      <tilted>1</tilted></_>
+          9 8 6 3 2.</_></rects>
+      <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          6 9 2 3 -1.</_>
+          6 8 12 2 -1.</_>
+        <_>
+          6 8 6 1 2.</_>
         <_>
-          6 10 2 1 3.</_></rects>
+          12 9 6 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          6 9 2 4 -1.</_>
+          6 8 13 6 -1.</_>
         <_>
-          6 10 2 2 2.</_></rects>
+          6 10 13 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
+          6 9 2 2 -1.</_>
+        <_>
+          6 9 1 2 2.</_></rects>
+      <tilted>1</tilted></_>
+    <_>
+      <rects>
+        <_>
           6 9 12 1 -1.</_>
         <_>
           9 9 6 1 2.</_></rects>
@@ -8204,9 +8673,9 @@
     <_>
       <rects>
         <_>
-          6 10 1 2 -1.</_>
+          6 9 12 3 -1.</_>
         <_>
-          6 11 1 1 2.</_></rects>
+          6 10 12 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
@@ -8218,23 +8687,16 @@
     <_>
       <rects>
         <_>
-          6 10 3 1 -1.</_>
-        <_>
-          7 11 1 1 3.</_></rects>
-      <tilted>1</tilted></_>
-    <_>
-      <rects>
-        <_>
-          6 10 2 2 -1.</_>
+          6 10 2 3 -1.</_>
         <_>
-          7 10 1 2 2.</_></rects>
+          7 10 1 3 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          6 10 2 3 -1.</_>
+          6 10 2 4 -1.</_>
         <_>
-          7 10 1 3 2.</_></rects>
+          7 10 1 4 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
@@ -8246,24 +8708,24 @@
     <_>
       <rects>
         <_>
-          6 10 12 1 -1.</_>
+          6 10 2 4 -1.</_>
         <_>
-          9 10 6 1 2.</_></rects>
+          6 11 2 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          6 10 9 4 -1.</_>
+          6 10 3 3 -1.</_>
         <_>
-          9 10 3 4 3.</_></rects>
+          6 11 3 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          6 10 4 6 -1.</_>
+          6 10 12 1 -1.</_>
         <_>
-          4 12 4 2 3.</_></rects>
-      <tilted>1</tilted></_>
+          9 10 6 1 2.</_></rects>
+      <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
@@ -8276,87 +8738,94 @@
     <_>
       <rects>
         <_>
-          6 11 3 3 -1.</_>
+          6 10 13 3 -1.</_>
         <_>
-          6 12 3 1 3.</_></rects>
+          6 11 13 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          6 11 12 6 -1.</_>
+          6 11 2 3 -1.</_>
         <_>
-          9 11 6 6 2.</_></rects>
+          6 12 2 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          6 11 13 2 -1.</_>
+          6 11 3 2 -1.</_>
         <_>
-          6 12 13 1 2.</_></rects>
+          6 12 3 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          6 14 6 4 -1.</_>
+          6 11 3 3 -1.</_>
         <_>
-          5 15 6 2 2.</_></rects>
-      <tilted>1</tilted></_>
+          6 12 3 1 3.</_></rects>
+      <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          6 15 6 3 -1.</_>
+          6 11 13 3 -1.</_>
         <_>
-          6 15 3 3 2.</_></rects>
-      <tilted>1</tilted></_>
+          6 12 13 1 3.</_></rects>
+      <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          6 15 5 4 -1.</_>
+          6 13 7 4 -1.</_>
         <_>
-          5 16 5 2 2.</_></rects>
+          6 13 7 2 2.</_></rects>
       <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          6 16 3 3 -1.</_>
+          6 14 1 3 -1.</_>
         <_>
-          7 17 1 1 9.</_></rects>
+          6 15 1 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          6 16 11 8 -1.</_>
+          6 15 3 4 -1.</_>
         <_>
-          6 18 11 4 2.</_></rects>
-      <tilted>0</tilted></_>
+          7 16 1 4 3.</_></rects>
+      <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          6 17 4 2 -1.</_>
+          6 15 6 3 -1.</_>
+        <_>
+          6 15 3 3 2.</_></rects>
+      <tilted>1</tilted></_>
+    <_>
+      <rects>
         <_>
-          7 18 2 2 2.</_></rects>
+          6 18 3 1 -1.</_>
+        <_>
+          7 19 1 1 3.</_></rects>
       <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          6 19 3 3 -1.</_>
+          6 19 3 5 -1.</_>
         <_>
-          7 19 1 3 3.</_></rects>
+          7 19 1 5 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          6 20 3 1 -1.</_>
+          7 0 3 4 -1.</_>
         <_>
-          7 21 1 1 3.</_></rects>
+          7 0 3 2 2.</_></rects>
       <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          6 20 7 4 -1.</_>
+          7 0 4 2 -1.</_>
         <_>
-          6 22 7 2 2.</_></rects>
-      <tilted>0</tilted></_>
+          7 0 4 1 2.</_></rects>
+      <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
@@ -8367,37 +8836,53 @@
     <_>
       <rects>
         <_>
-          7 0 9 10 -1.</_>
+          7 1 2 6 -1.</_>
+        <_>
+          7 1 1 3 2.</_>
         <_>
-          7 5 9 5 2.</_></rects>
+          8 4 1 3 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          7 1 9 12 -1.</_>
+          7 1 10 1 -1.</_>
         <_>
-          10 5 3 4 9.</_></rects>
+          12 1 5 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
           7 2 1 3 -1.</_>
         <_>
-          7 3 1 1 3.</_></rects>
-      <tilted>0</tilted></_>
+          6 3 1 1 3.</_></rects>
+      <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          7 2 1 3 -1.</_>
+          7 2 1 4 -1.</_>
         <_>
-          6 3 1 1 3.</_></rects>
+          6 3 1 2 2.</_></rects>
+      <tilted>1</tilted></_>
+    <_>
+      <rects>
+        <_>
+          7 2 3 4 -1.</_>
+        <_>
+          6 3 3 2 2.</_></rects>
       <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          7 2 11 10 -1.</_>
+          7 2 6 3 -1.</_>
+        <_>
+          7 3 6 1 3.</_></rects>
+      <tilted>0</tilted></_>
+    <_>
+      <rects>
+        <_>
+          7 2 13 10 -1.</_>
         <_>
-          7 7 11 5 2.</_></rects>
+          7 7 13 5 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
@@ -8409,32 +8894,39 @@
     <_>
       <rects>
         <_>
-          7 3 1 6 -1.</_>
+          7 3 2 4 -1.</_>
         <_>
-          5 5 1 2 3.</_></rects>
+          6 4 2 2 2.</_></rects>
       <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          7 4 10 2 -1.</_>
+          7 3 4 2 -1.</_>
         <_>
-          7 4 5 1 2.</_>
+          7 3 4 1 2.</_></rects>
+      <tilted>1</tilted></_>
+    <_>
+      <rects>
         <_>
-          12 5 5 1 2.</_></rects>
+          7 4 3 3 -1.</_>
+        <_>
+          8 4 1 3 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          7 5 3 2 -1.</_>
+          7 4 10 2 -1.</_>
         <_>
-          8 5 1 2 3.</_></rects>
+          7 4 5 1 2.</_>
+        <_>
+          12 5 5 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          7 5 2 3 -1.</_>
+          7 5 3 2 -1.</_>
         <_>
-          8 5 1 3 2.</_></rects>
+          8 5 1 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
@@ -8446,30 +8938,30 @@
     <_>
       <rects>
         <_>
-          7 5 3 6 -1.</_>
+          7 5 3 5 -1.</_>
         <_>
-          8 5 1 6 3.</_></rects>
+          8 5 1 5 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          7 5 9 17 -1.</_>
+          7 6 3 1 -1.</_>
         <_>
-          10 5 3 17 3.</_></rects>
+          8 6 1 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          7 5 4 4 -1.</_>
+          7 6 1 4 -1.</_>
         <_>
-          6 6 4 2 2.</_></rects>
+          7 6 1 2 2.</_></rects>
       <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          7 5 5 3 -1.</_>
+          7 6 6 10 -1.</_>
         <_>
-          7 6 5 1 3.</_></rects>
+          9 6 2 10 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
@@ -8483,44 +8975,39 @@
     <_>
       <rects>
         <_>
-          7 6 8 4 -1.</_>
+          7 6 5 3 -1.</_>
         <_>
-          6 7 8 2 2.</_></rects>
+          6 7 5 1 3.</_></rects>
       <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          7 7 4 4 -1.</_>
+          7 6 8 4 -1.</_>
         <_>
-          8 8 2 4 2.</_></rects>
+          6 7 8 2 2.</_></rects>
       <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          7 7 2 4 -1.</_>
+          7 7 1 3 -1.</_>
         <_>
-          7 9 2 2 2.</_></rects>
+          7 8 1 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          7 7 5 6 -1.</_>
-        <_>
-          5 9 5 2 3.</_></rects>
-      <tilted>1</tilted></_>
-    <_>
-      <rects>
+          7 7 2 2 -1.</_>
         <_>
-          7 7 6 4 -1.</_>
+          7 7 1 1 2.</_>
         <_>
-          6 8 6 2 2.</_></rects>
-      <tilted>1</tilted></_>
+          8 8 1 1 2.</_></rects>
+      <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          7 7 6 12 -1.</_>
+          7 8 1 3 -1.</_>
         <_>
-          7 13 6 6 2.</_></rects>
+          7 9 1 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
@@ -8534,16 +9021,16 @@
     <_>
       <rects>
         <_>
-          7 8 4 4 -1.</_>
+          7 8 2 2 -1.</_>
         <_>
-          8 8 2 4 2.</_></rects>
-      <tilted>0</tilted></_>
+          7 8 1 2 2.</_></rects>
+      <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          7 8 2 4 -1.</_>
+          7 8 12 7 -1.</_>
         <_>
-          7 9 2 2 2.</_></rects>
+          11 8 4 7 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
@@ -8564,25 +9051,25 @@
     <_>
       <rects>
         <_>
-          7 9 6 3 -1.</_>
+          7 9 2 3 -1.</_>
         <_>
-          9 9 2 3 3.</_></rects>
-      <tilted>0</tilted></_>
+          7 9 1 3 2.</_></rects>
+      <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          7 9 6 10 -1.</_>
-        <_>
-          7 9 3 5 2.</_>
+          7 9 2 3 -1.</_>
         <_>
-          10 14 3 5 2.</_></rects>
+          7 10 2 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          7 9 12 2 -1.</_>
+          7 9 6 10 -1.</_>
+        <_>
+          7 9 3 5 2.</_>
         <_>
-          11 9 4 2 3.</_></rects>
+          10 14 3 5 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
@@ -8596,155 +9083,195 @@
     <_>
       <rects>
         <_>
-          7 9 10 4 -1.</_>
-        <_>
-          7 9 5 2 2.</_>
+          7 10 3 1 -1.</_>
         <_>
-          12 11 5 2 2.</_></rects>
+          8 10 1 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          7 10 3 1 -1.</_>
+          7 10 1 3 -1.</_>
         <_>
-          8 10 1 1 3.</_></rects>
+          7 11 1 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          7 10 1 3 -1.</_>
+          7 10 2 3 -1.</_>
         <_>
-          7 11 1 1 3.</_></rects>
+          7 11 2 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          7 10 4 3 -1.</_>
+          7 10 6 5 -1.</_>
         <_>
-          8 10 2 3 2.</_></rects>
+          9 10 2 5 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          7 10 2 3 -1.</_>
+          7 10 9 4 -1.</_>
         <_>
-          7 11 2 1 3.</_></rects>
+          10 10 3 4 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          7 10 4 4 -1.</_>
+          7 10 10 2 -1.</_>
+        <_>
+          7 10 5 1 2.</_>
         <_>
-          9 10 2 4 2.</_></rects>
+          12 11 5 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          7 10 6 4 -1.</_>
+          7 11 1 2 -1.</_>
         <_>
-          9 10 2 4 3.</_></rects>
+          7 12 1 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          7 10 6 8 -1.</_>
+          7 15 5 4 -1.</_>
+        <_>
+          6 16 5 2 2.</_></rects>
+      <tilted>1</tilted></_>
+    <_>
+      <rects>
         <_>
-          7 10 3 4 2.</_>
+          7 16 6 2 -1.</_>
         <_>
-          10 14 3 4 2.</_></rects>
-      <tilted>0</tilted></_>
+          9 18 2 2 3.</_></rects>
+      <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          7 10 12 5 -1.</_>
+          7 16 4 2 -1.</_>
         <_>
-          11 10 4 5 3.</_></rects>
-      <tilted>0</tilted></_>
+          7 16 4 1 2.</_></rects>
+      <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          7 10 10 2 -1.</_>
+          7 16 4 4 -1.</_>
         <_>
-          7 10 5 1 2.</_>
+          6 17 4 2 2.</_></rects>
+      <tilted>1</tilted></_>
+    <_>
+      <rects>
         <_>
-          12 11 5 1 2.</_></rects>
-      <tilted>0</tilted></_>
+          7 17 3 1 -1.</_>
+        <_>
+          8 18 1 1 3.</_></rects>
+      <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          7 11 3 12 -1.</_>
+          7 17 1 4 -1.</_>
         <_>
-          8 11 1 12 3.</_></rects>
+          7 19 1 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          7 13 9 3 -1.</_>
+          7 17 3 6 -1.</_>
         <_>
-          10 13 3 3 3.</_></rects>
+          7 20 3 3 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          7 14 1 3 -1.</_>
+          7 17 4 3 -1.</_>
         <_>
-          7 15 1 1 3.</_></rects>
-      <tilted>0</tilted></_>
+          6 18 4 1 3.</_></rects>
+      <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          7 17 3 1 -1.</_>
+          7 17 5 2 -1.</_>
         <_>
-          8 18 1 1 3.</_></rects>
+          7 17 5 1 2.</_></rects>
       <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          7 17 4 2 -1.</_>
+          7 18 3 1 -1.</_>
         <_>
-          8 18 2 2 2.</_></rects>
+          8 19 1 1 3.</_></rects>
       <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          7 17 5 2 -1.</_>
+          7 19 3 1 -1.</_>
         <_>
-          7 17 5 1 2.</_></rects>
+          8 20 1 1 3.</_></rects>
+      <tilted>1</tilted></_>
+    <_>
+      <rects>
+        <_>
+          7 19 3 5 -1.</_>
+        <_>
+          8 19 1 5 3.</_></rects>
+      <tilted>0</tilted></_>
+    <_>
+      <rects>
+        <_>
+          7 20 3 1 -1.</_>
+        <_>
+          8 21 1 1 3.</_></rects>
       <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          7 18 3 6 -1.</_>
+          7 20 9 4 -1.</_>
+        <_>
+          7 22 9 2 2.</_></rects>
+      <tilted>0</tilted></_>
+    <_>
+      <rects>
+        <_>
+          7 20 10 4 -1.</_>
+        <_>
+          7 21 10 2 2.</_></rects>
+      <tilted>0</tilted></_>
+    <_>
+      <rects>
+        <_>
+          7 20 10 4 -1.</_>
         <_>
-          8 18 1 6 3.</_></rects>
+          7 22 10 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          7 20 3 1 -1.</_>
+          8 0 8 1 -1.</_>
         <_>
-          8 21 1 1 3.</_></rects>
-      <tilted>1</tilted></_>
+          12 0 4 1 2.</_></rects>
+      <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          7 20 7 4 -1.</_>
+          8 0 7 4 -1.</_>
         <_>
-          7 22 7 2 2.</_></rects>
+          8 2 7 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          8 0 5 4 -1.</_>
+          8 0 16 6 -1.</_>
+        <_>
+          8 0 8 3 2.</_>
         <_>
-          8 2 5 2 2.</_></rects>
+          16 3 8 3 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          8 0 7 10 -1.</_>
+          8 0 8 10 -1.</_>
         <_>
-          8 5 7 5 2.</_></rects>
+          8 5 8 5 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
@@ -8758,11 +9285,9 @@
     <_>
       <rects>
         <_>
-          8 0 16 12 -1.</_>
-        <_>
-          8 0 8 6 2.</_>
+          8 0 9 4 -1.</_>
         <_>
-          16 6 8 6 2.</_></rects>
+          8 1 9 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
@@ -8774,53 +9299,44 @@
     <_>
       <rects>
         <_>
-          8 1 3 6 -1.</_>
-        <_>
-          8 1 3 3 2.</_></rects>
-      <tilted>1</tilted></_>
-    <_>
-      <rects>
-        <_>
-          8 1 8 2 -1.</_>
+          8 1 8 8 -1.</_>
         <_>
-          12 1 4 2 2.</_></rects>
+          8 5 8 4 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          8 1 16 6 -1.</_>
+          8 1 12 10 -1.</_>
         <_>
-          6 3 16 2 3.</_></rects>
-      <tilted>1</tilted></_>
+          8 6 12 5 2.</_></rects>
+      <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          8 2 8 2 -1.</_>
-        <_>
-          8 2 4 1 2.</_>
+          8 2 3 3 -1.</_>
         <_>
-          12 3 4 1 2.</_></rects>
+          9 2 1 3 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          8 3 2 6 -1.</_>
+          8 2 2 4 -1.</_>
         <_>
-          6 5 2 2 3.</_></rects>
+          7 3 2 2 2.</_></rects>
       <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          8 4 3 9 -1.</_>
+          8 2 2 6 -1.</_>
         <_>
-          9 4 1 9 3.</_></rects>
-      <tilted>0</tilted></_>
+          6 4 2 2 3.</_></rects>
+      <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          8 4 4 3 -1.</_>
+          8 3 3 8 -1.</_>
         <_>
-          8 5 4 1 3.</_></rects>
+          9 3 1 8 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
@@ -8834,37 +9350,30 @@
     <_>
       <rects>
         <_>
-          8 5 2 1 -1.</_>
-        <_>
-          8 5 1 1 2.</_></rects>
-      <tilted>1</tilted></_>
-    <_>
-      <rects>
-        <_>
-          8 5 2 2 -1.</_>
+          8 4 7 15 -1.</_>
         <_>
-          9 5 1 2 2.</_></rects>
+          8 9 7 5 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          8 5 4 3 -1.</_>
+          8 5 2 1 -1.</_>
         <_>
-          9 5 2 3 2.</_></rects>
-      <tilted>0</tilted></_>
+          8 5 1 1 2.</_></rects>
+      <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          8 5 3 4 -1.</_>
+          8 5 3 2 -1.</_>
         <_>
-          9 5 1 4 3.</_></rects>
+          9 5 1 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          8 5 3 5 -1.</_>
+          8 5 2 5 -1.</_>
         <_>
-          9 5 1 5 3.</_></rects>
+          9 5 1 5 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
@@ -8892,11 +9401,25 @@
         <_>
           8 5 3 7 -1.</_>
         <_>
-          9 5 1 7 3.</_></rects>
+          9 6 1 7 3.</_></rects>
+      <tilted>1</tilted></_>
+    <_>
+      <rects>
+        <_>
+          8 5 3 8 -1.</_>
+        <_>
+          9 5 1 8 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
+          8 5 3 6 -1.</_>
+        <_>
+          8 5 3 3 2.</_></rects>
+      <tilted>1</tilted></_>
+    <_>
+      <rects>
+        <_>
           8 5 4 6 -1.</_>
         <_>
           6 7 4 2 3.</_></rects>
@@ -8904,6 +9427,15 @@
     <_>
       <rects>
         <_>
+          8 5 10 2 -1.</_>
+        <_>
+          8 5 5 1 2.</_>
+        <_>
+          13 6 5 1 2.</_></rects>
+      <tilted>0</tilted></_>
+    <_>
+      <rects>
+        <_>
           8 5 5 3 -1.</_>
         <_>
           7 6 5 1 3.</_></rects>
@@ -8911,47 +9443,47 @@
     <_>
       <rects>
         <_>
-          8 6 4 2 -1.</_>
-        <_>
-          8 6 2 1 2.</_>
+          8 6 3 6 -1.</_>
         <_>
-          10 7 2 1 2.</_></rects>
+          9 6 1 6 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          8 6 4 2 -1.</_>
+          8 6 3 4 -1.</_>
         <_>
-          8 6 2 2 2.</_></rects>
+          7 7 3 2 2.</_></rects>
       <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          8 6 4 3 -1.</_>
+          8 6 4 2 -1.</_>
         <_>
-          7 7 4 1 3.</_></rects>
+          8 6 4 1 2.</_></rects>
       <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          8 6 4 4 -1.</_>
+          8 6 4 3 -1.</_>
         <_>
-          7 7 4 2 2.</_></rects>
+          7 7 4 1 3.</_></rects>
       <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          8 6 5 4 -1.</_>
+          8 6 4 4 -1.</_>
         <_>
-          7 7 5 2 2.</_></rects>
+          7 7 4 2 2.</_></rects>
       <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
           8 6 10 2 -1.</_>
         <_>
-          8 6 10 1 2.</_></rects>
-      <tilted>1</tilted></_>
+          8 6 5 1 2.</_>
+        <_>
+          13 7 5 1 2.</_></rects>
+      <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
@@ -8969,67 +9501,60 @@
     <_>
       <rects>
         <_>
-          8 7 4 2 -1.</_>
-        <_>
-          8 7 4 1 2.</_></rects>
-      <tilted>1</tilted></_>
-    <_>
-      <rects>
-        <_>
-          8 7 4 3 -1.</_>
+          8 7 9 5 -1.</_>
         <_>
-          7 8 4 1 3.</_></rects>
+          11 10 3 5 3.</_></rects>
       <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          8 7 5 2 -1.</_>
+          8 7 9 8 -1.</_>
         <_>
-          8 7 5 1 2.</_></rects>
+          11 10 3 8 3.</_></rects>
       <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          8 7 8 4 -1.</_>
+          8 7 4 2 -1.</_>
         <_>
-          7 8 8 2 2.</_></rects>
+          8 7 4 1 2.</_></rects>
       <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          8 8 2 2 -1.</_>
+          8 7 4 3 -1.</_>
         <_>
-          8 8 1 2 2.</_></rects>
+          7 8 4 1 3.</_></rects>
       <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          8 8 2 3 -1.</_>
+          8 7 5 2 -1.</_>
         <_>
-          7 9 2 1 3.</_></rects>
+          8 7 5 1 2.</_></rects>
       <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          8 8 8 5 -1.</_>
+          8 7 8 2 -1.</_>
         <_>
-          10 10 4 5 2.</_></rects>
+          8 7 8 1 2.</_></rects>
       <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          8 9 3 3 -1.</_>
+          8 7 10 12 -1.</_>
         <_>
-          9 9 1 3 3.</_></rects>
+          8 13 10 6 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          8 9 10 2 -1.</_>
+          8 8 2 2 -1.</_>
         <_>
-          8 9 5 1 2.</_>
+          8 8 1 1 2.</_>
         <_>
-          13 10 5 1 2.</_></rects>
+          9 9 1 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
@@ -9050,11 +9575,27 @@
         <_>
           8 10 2 2 -1.</_>
         <_>
+          8 10 1 1 2.</_>
+        <_>
+          9 11 1 1 2.</_></rects>
+      <tilted>0</tilted></_>
+    <_>
+      <rects>
+        <_>
+          8 10 2 2 -1.</_>
+        <_>
           9 10 1 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
+          8 10 3 2 -1.</_>
+        <_>
+          9 10 1 2 3.</_></rects>
+      <tilted>0</tilted></_>
+    <_>
+      <rects>
+        <_>
           8 10 4 8 -1.</_>
         <_>
           8 10 2 4 2.</_>
@@ -9073,74 +9614,67 @@
     <_>
       <rects>
         <_>
-          8 11 6 5 -1.</_>
+          8 10 15 12 -1.</_>
         <_>
-          10 11 2 5 3.</_></rects>
+          13 14 5 4 9.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          8 11 4 10 -1.</_>
+          8 11 2 2 -1.</_>
         <_>
-          8 11 2 5 2.</_>
+          8 11 1 1 2.</_>
         <_>
-          10 16 2 5 2.</_></rects>
+          9 12 1 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          8 13 7 4 -1.</_>
-        <_>
-          8 13 7 2 2.</_></rects>
-      <tilted>1</tilted></_>
-    <_>
-      <rects>
-        <_>
-          8 16 8 3 -1.</_>
+          8 13 9 3 -1.</_>
         <_>
-          10 16 4 3 2.</_></rects>
+          11 13 3 3 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          8 16 9 3 -1.</_>
+          8 15 9 6 -1.</_>
         <_>
-          11 16 3 3 3.</_></rects>
+          11 15 3 6 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          8 17 3 7 -1.</_>
+          8 15 8 6 -1.</_>
         <_>
-          9 17 1 7 3.</_></rects>
+          8 17 8 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          8 17 8 2 -1.</_>
+          8 16 8 2 -1.</_>
         <_>
-          10 17 4 2 2.</_></rects>
+          10 16 4 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          8 17 9 1 -1.</_>
+          8 16 8 3 -1.</_>
         <_>
-          11 17 3 1 3.</_></rects>
+          10 16 4 3 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          8 17 9 7 -1.</_>
+          8 17 3 3 -1.</_>
         <_>
-          11 17 3 7 3.</_></rects>
-      <tilted>0</tilted></_>
+          9 18 1 3 3.</_></rects>
+      <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          8 17 8 6 -1.</_>
+          8 17 8 3 -1.</_>
         <_>
-          8 20 8 3 2.</_></rects>
+          10 17 4 3 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
@@ -9152,13 +9686,6 @@
     <_>
       <rects>
         <_>
-          8 18 3 2 -1.</_>
-        <_>
-          9 19 1 2 3.</_></rects>
-      <tilted>1</tilted></_>
-    <_>
-      <rects>
-        <_>
           8 18 3 6 -1.</_>
         <_>
           9 18 1 6 3.</_></rects>
@@ -9166,13 +9693,6 @@
     <_>
       <rects>
         <_>
-          8 18 8 6 -1.</_>
-        <_>
-          8 20 8 2 3.</_></rects>
-      <tilted>0</tilted></_>
-    <_>
-      <rects>
-        <_>
           8 19 3 1 -1.</_>
         <_>
           9 20 1 1 3.</_></rects>
@@ -9180,1098 +9700,1025 @@
     <_>
       <rects>
         <_>
-          8 19 8 3 -1.</_>
+          8 19 3 4 -1.</_>
         <_>
-          8 20 8 1 3.</_></rects>
+          9 19 1 4 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          8 20 8 4 -1.</_>
+          8 19 7 3 -1.</_>
         <_>
-          8 21 8 2 2.</_></rects>
+          8 20 7 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          9 0 2 2 -1.</_>
+          8 19 9 4 -1.</_>
         <_>
-          9 1 2 1 2.</_></rects>
+          8 20 9 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          9 0 6 1 -1.</_>
+          8 20 3 3 -1.</_>
         <_>
-          12 0 3 1 2.</_></rects>
+          9 20 1 3 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          9 0 6 9 -1.</_>
-        <_>
-          9 0 3 9 2.</_></rects>
-      <tilted>1</tilted></_>
-    <_>
-      <rects>
-        <_>
-          9 0 6 2 -1.</_>
-        <_>
-          9 1 6 1 2.</_></rects>
-      <tilted>0</tilted></_>
-    <_>
-      <rects>
+          8 20 16 4 -1.</_>
         <_>
-          9 0 6 8 -1.</_>
+          8 20 8 2 2.</_>
         <_>
-          9 4 6 4 2.</_></rects>
+          16 22 8 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          9 0 7 4 -1.</_>
+          8 21 3 3 -1.</_>
         <_>
-          9 2 7 2 2.</_></rects>
+          9 21 1 3 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          9 0 11 4 -1.</_>
+          9 0 1 2 -1.</_>
         <_>
-          9 1 11 2 2.</_></rects>
+          9 1 1 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          9 1 2 3 -1.</_>
+          9 0 3 6 -1.</_>
         <_>
-          10 1 1 3 2.</_></rects>
-      <tilted>0</tilted></_>
+          7 2 3 2 3.</_></rects>
+      <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          9 1 2 6 -1.</_>
-        <_>
-          9 1 1 3 2.</_>
+          9 0 6 3 -1.</_>
         <_>
-          10 4 1 3 2.</_></rects>
+          12 0 3 3 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          9 1 6 2 -1.</_>
-        <_>
-          9 1 3 1 2.</_>
+          9 0 6 9 -1.</_>
         <_>
-          12 2 3 1 2.</_></rects>
-      <tilted>0</tilted></_>
+          9 0 3 9 2.</_></rects>
+      <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          9 1 3 4 -1.</_>
+          9 0 8 9 -1.</_>
         <_>
-          8 2 3 2 2.</_></rects>
+          9 0 4 9 2.</_></rects>
       <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          9 2 2 4 -1.</_>
+          9 0 5 4 -1.</_>
         <_>
-          10 2 1 4 2.</_></rects>
+          9 2 5 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          9 2 6 8 -1.</_>
+          9 0 5 8 -1.</_>
         <_>
-          11 2 2 8 3.</_></rects>
+          9 4 5 4 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          9 3 1 6 -1.</_>
-        <_>
-          7 5 1 2 3.</_></rects>
-      <tilted>1</tilted></_>
-    <_>
-      <rects>
+          9 0 14 12 -1.</_>
         <_>
-          9 4 2 9 -1.</_>
+          9 0 7 6 2.</_>
         <_>
-          10 4 1 9 2.</_></rects>
+          16 6 7 6 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          9 4 8 2 -1.</_>
+          9 0 8 10 -1.</_>
         <_>
-          9 4 4 1 2.</_>
-        <_>
-          13 5 4 1 2.</_></rects>
+          9 5 8 5 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          9 5 2 1 -1.</_>
-        <_>
-          9 5 1 1 2.</_></rects>
-      <tilted>1</tilted></_>
-    <_>
-      <rects>
-        <_>
-          9 5 3 4 -1.</_>
+          9 0 15 18 -1.</_>
         <_>
-          10 5 1 4 3.</_></rects>
+          9 6 15 6 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          9 5 3 9 -1.</_>
+          9 1 2 8 -1.</_>
         <_>
-          10 6 1 9 3.</_></rects>
-      <tilted>1</tilted></_>
-    <_>
-      <rects>
-        <_>
-          9 5 4 3 -1.</_>
-        <_>
-          8 6 4 1 3.</_></rects>
-      <tilted>1</tilted></_>
+          9 5 2 4 2.</_></rects>
+      <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          9 6 2 6 -1.</_>
+          9 1 3 4 -1.</_>
         <_>
-          7 8 2 2 3.</_></rects>
+          8 2 3 2 2.</_></rects>
       <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          9 6 3 3 -1.</_>
+          9 2 2 2 -1.</_>
         <_>
-          9 7 3 1 3.</_></rects>
+          10 2 1 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          9 7 1 2 -1.</_>
-        <_>
-          9 7 1 1 2.</_></rects>
-      <tilted>1</tilted></_>
-    <_>
-      <rects>
-        <_>
-          9 7 2 2 -1.</_>
+          9 2 1 6 -1.</_>
         <_>
-          9 7 1 2 2.</_></rects>
-      <tilted>1</tilted></_>
+          9 5 1 3 2.</_></rects>
+      <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          9 7 2 2 -1.</_>
+          9 2 3 10 -1.</_>
         <_>
-          9 7 2 1 2.</_></rects>
-      <tilted>1</tilted></_>
+          10 2 1 10 3.</_></rects>
+      <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          9 7 2 4 -1.</_>
+          9 2 8 4 -1.</_>
         <_>
-          8 8 2 2 2.</_></rects>
+          11 4 4 4 2.</_></rects>
       <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          9 7 3 3 -1.</_>
-        <_>
-          8 8 3 1 3.</_></rects>
-      <tilted>1</tilted></_>
-    <_>
-      <rects>
+          9 2 6 2 -1.</_>
         <_>
-          9 8 6 5 -1.</_>
+          9 2 3 1 2.</_>
         <_>
-          11 10 2 5 3.</_></rects>
-      <tilted>1</tilted></_>
+          12 3 3 1 2.</_></rects>
+      <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          9 8 3 3 -1.</_>
+          9 2 7 8 -1.</_>
         <_>
-          9 9 3 1 3.</_></rects>
+          9 6 7 4 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          9 9 2 7 -1.</_>
+          9 3 3 7 -1.</_>
         <_>
-          10 9 1 7 2.</_></rects>
-      <tilted>0</tilted></_>
+          10 4 1 7 3.</_></rects>
+      <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          9 9 2 3 -1.</_>
+          9 3 3 12 -1.</_>
         <_>
-          9 10 2 1 3.</_></rects>
+          10 3 1 12 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          9 9 15 2 -1.</_>
+          9 3 6 7 -1.</_>
         <_>
-          9 10 15 1 2.</_></rects>
+          11 3 2 7 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          9 10 4 8 -1.</_>
+          9 3 12 3 -1.</_>
         <_>
-          10 10 2 8 2.</_></rects>
+          13 4 4 1 9.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          9 11 4 3 -1.</_>
+          9 3 11 4 -1.</_>
         <_>
-          9 12 4 1 3.</_></rects>
-      <tilted>0</tilted></_>
+          8 4 11 2 2.</_></rects>
+      <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          9 12 4 8 -1.</_>
-        <_>
-          9 12 2 4 2.</_>
+          9 4 3 8 -1.</_>
         <_>
-          11 16 2 4 2.</_></rects>
-      <tilted>0</tilted></_>
+          10 5 1 8 3.</_></rects>
+      <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          9 12 9 4 -1.</_>
+          9 5 2 1 -1.</_>
         <_>
-          12 12 3 4 3.</_></rects>
-      <tilted>0</tilted></_>
+          9 5 1 1 2.</_></rects>
+      <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          9 16 4 1 -1.</_>
+          9 5 3 4 -1.</_>
         <_>
-          11 16 2 1 2.</_></rects>
+          10 5 1 4 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          9 16 6 4 -1.</_>
+          9 5 3 6 -1.</_>
         <_>
-          11 16 2 4 3.</_></rects>
+          10 5 1 6 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          9 16 6 4 -1.</_>
+          9 5 6 4 -1.</_>
         <_>
-          9 17 6 2 2.</_></rects>
+          11 5 2 4 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          9 17 6 2 -1.</_>
+          9 5 3 3 -1.</_>
         <_>
-          11 17 2 2 3.</_></rects>
+          9 6 3 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          9 18 3 3 -1.</_>
+          9 5 4 3 -1.</_>
         <_>
-          10 19 1 3 3.</_></rects>
+          8 6 4 1 3.</_></rects>
       <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          9 19 3 2 -1.</_>
+          9 6 3 2 -1.</_>
         <_>
-          10 20 1 2 3.</_></rects>
+          10 7 1 2 3.</_></rects>
       <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          9 19 3 5 -1.</_>
+          9 6 2 6 -1.</_>
         <_>
-          10 19 1 5 3.</_></rects>
-      <tilted>0</tilted></_>
+          7 8 2 2 3.</_></rects>
+      <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          9 19 6 4 -1.</_>
+          9 6 4 3 -1.</_>
         <_>
-          9 20 6 2 2.</_></rects>
+          9 7 4 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          9 20 3 1 -1.</_>
+          9 6 4 3 -1.</_>
         <_>
-          10 21 1 1 3.</_></rects>
+          8 7 4 1 3.</_></rects>
       <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          9 20 5 4 -1.</_>
-        <_>
-          9 21 5 2 2.</_></rects>
-      <tilted>0</tilted></_>
-    <_>
-      <rects>
-        <_>
-          9 20 5 4 -1.</_>
+          9 7 2 3 -1.</_>
         <_>
-          9 22 5 2 2.</_></rects>
-      <tilted>0</tilted></_>
+          9 7 1 3 2.</_></rects>
+      <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          9 20 6 3 -1.</_>
+          9 7 2 2 -1.</_>
         <_>
-          9 21 6 1 3.</_></rects>
-      <tilted>0</tilted></_>
+          9 7 2 1 2.</_></rects>
+      <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          9 20 12 2 -1.</_>
-        <_>
-          15 20 6 2 2.</_></rects>
-      <tilted>0</tilted></_>
-    <_>
-      <rects>
+          9 7 6 2 -1.</_>
         <_>
-          9 20 7 3 -1.</_>
+          9 7 3 1 2.</_>
         <_>
-          9 21 7 1 3.</_></rects>
+          12 8 3 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          9 20 7 4 -1.</_>
+          9 8 2 3 -1.</_>
         <_>
-          9 21 7 2 2.</_></rects>
-      <tilted>0</tilted></_>
+          8 9 2 1 3.</_></rects>
+      <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          9 21 3 3 -1.</_>
+          9 8 6 5 -1.</_>
         <_>
-          10 21 1 3 3.</_></rects>
-      <tilted>0</tilted></_>
+          11 10 2 5 3.</_></rects>
+      <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          9 21 4 3 -1.</_>
+          9 8 3 3 -1.</_>
         <_>
-          10 21 2 3 2.</_></rects>
+          9 9 3 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          9 22 3 2 -1.</_>
+          9 8 9 9 -1.</_>
         <_>
-          10 22 1 2 3.</_></rects>
+          12 8 3 9 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          10 0 1 2 -1.</_>
-        <_>
-          10 0 1 1 2.</_></rects>
-      <tilted>1</tilted></_>
-    <_>
-      <rects>
-        <_>
-          10 0 4 2 -1.</_>
+          9 9 2 12 -1.</_>
         <_>
-          10 0 2 1 2.</_>
+          9 9 1 6 2.</_>
         <_>
-          12 1 2 1 2.</_></rects>
+          10 15 1 6 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          10 0 6 8 -1.</_>
-        <_>
-          12 2 2 8 3.</_></rects>
-      <tilted>1</tilted></_>
-    <_>
-      <rects>
-        <_>
-          10 0 6 10 -1.</_>
+          9 9 6 3 -1.</_>
         <_>
-          10 0 3 10 2.</_></rects>
+          11 11 2 3 3.</_></rects>
       <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          10 0 14 10 -1.</_>
-        <_>
-          10 0 7 5 2.</_>
+          9 9 6 4 -1.</_>
         <_>
-          17 5 7 5 2.</_></rects>
-      <tilted>0</tilted></_>
+          11 11 2 4 3.</_></rects>
+      <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          10 1 4 1 -1.</_>
+          9 9 3 3 -1.</_>
         <_>
-          12 1 2 1 2.</_></rects>
+          9 10 3 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          10 1 9 9 -1.</_>
+          9 9 6 4 -1.</_>
         <_>
-          13 4 3 9 3.</_></rects>
-      <tilted>1</tilted></_>
+          12 9 3 4 2.</_></rects>
+      <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          10 1 12 2 -1.</_>
+          9 10 3 3 -1.</_>
         <_>
-          14 1 4 2 3.</_></rects>
+          9 11 3 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          10 1 14 8 -1.</_>
-        <_>
-          10 1 7 4 2.</_>
+          9 10 5 3 -1.</_>
         <_>
-          17 5 7 4 2.</_></rects>
+          9 11 5 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          10 2 1 6 -1.</_>
+          9 10 14 3 -1.</_>
         <_>
-          8 4 1 2 3.</_></rects>
-      <tilted>1</tilted></_>
+          9 11 14 1 3.</_></rects>
+      <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          10 2 10 10 -1.</_>
+          9 13 4 6 -1.</_>
         <_>
-          10 7 10 5 2.</_></rects>
+          9 13 2 3 2.</_>
+        <_>
+          11 16 2 3 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          10 3 2 12 -1.</_>
+          9 13 9 4 -1.</_>
         <_>
-          11 3 1 12 2.</_></rects>
+          12 13 3 4 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          10 3 9 3 -1.</_>
+          9 16 6 5 -1.</_>
         <_>
-          13 4 3 1 9.</_></rects>
+          11 16 2 5 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          10 3 14 2 -1.</_>
+          9 17 6 2 -1.</_>
         <_>
-          17 3 7 2 2.</_></rects>
+          11 17 2 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          10 4 3 4 -1.</_>
+          9 18 3 3 -1.</_>
         <_>
-          11 4 1 4 3.</_></rects>
-      <tilted>0</tilted></_>
+          10 19 1 3 3.</_></rects>
+      <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          10 4 3 5 -1.</_>
+          9 19 3 2 -1.</_>
         <_>
-          11 4 1 5 3.</_></rects>
-      <tilted>0</tilted></_>
+          10 20 1 2 3.</_></rects>
+      <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          10 4 3 6 -1.</_>
+          9 19 6 3 -1.</_>
         <_>
-          11 4 1 6 3.</_></rects>
+          9 20 6 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          10 4 4 10 -1.</_>
+          9 19 7 3 -1.</_>
         <_>
-          12 4 2 10 2.</_></rects>
+          9 20 7 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          10 4 9 3 -1.</_>
+          9 20 3 3 -1.</_>
         <_>
-          13 4 3 3 3.</_></rects>
+          10 20 1 3 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          10 5 2 6 -1.</_>
+          9 20 5 3 -1.</_>
         <_>
-          11 5 1 6 2.</_></rects>
+          9 21 5 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          10 5 6 3 -1.</_>
+          9 20 6 3 -1.</_>
         <_>
-          10 6 6 1 3.</_></rects>
+          9 21 6 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          10 5 14 9 -1.</_>
+          9 20 7 3 -1.</_>
         <_>
-          10 8 14 3 3.</_></rects>
+          9 21 7 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          10 6 3 3 -1.</_>
+          9 20 7 4 -1.</_>
         <_>
-          11 6 1 3 3.</_></rects>
+          9 22 7 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          10 6 2 4 -1.</_>
+          9 21 3 3 -1.</_>
         <_>
-          11 6 1 4 2.</_></rects>
+          10 21 1 3 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          10 6 2 3 -1.</_>
+          9 21 8 2 -1.</_>
         <_>
-          10 7 2 1 3.</_></rects>
+          9 22 8 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          10 6 3 3 -1.</_>
+          10 0 4 1 -1.</_>
         <_>
-          10 7 3 1 3.</_></rects>
+          12 0 2 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          10 6 3 4 -1.</_>
+          10 0 3 12 -1.</_>
         <_>
-          10 6 3 2 2.</_></rects>
-      <tilted>1</tilted></_>
+          10 4 3 4 3.</_></rects>
+      <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          10 6 6 7 -1.</_>
+          10 0 4 8 -1.</_>
         <_>
-          13 6 3 7 2.</_></rects>
+          10 4 4 4 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          10 6 4 3 -1.</_>
+          10 0 14 10 -1.</_>
+        <_>
+          10 0 7 5 2.</_>
         <_>
-          10 7 4 1 3.</_></rects>
+          17 5 7 5 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          10 7 2 3 -1.</_>
+          10 2 4 6 -1.</_>
         <_>
-          10 8 2 1 3.</_></rects>
+          11 2 2 6 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          10 7 6 6 -1.</_>
+          10 2 6 10 -1.</_>
         <_>
-          12 9 2 6 3.</_></rects>
+          10 2 3 10 2.</_></rects>
       <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          10 7 3 3 -1.</_>
+          10 3 2 5 -1.</_>
         <_>
-          10 8 3 1 3.</_></rects>
+          11 3 1 5 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          10 8 6 4 -1.</_>
+          10 4 3 5 -1.</_>
         <_>
-          12 10 2 4 3.</_></rects>
-      <tilted>1</tilted></_>
+          11 4 1 5 3.</_></rects>
+      <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          10 8 6 10 -1.</_>
+          10 4 4 19 -1.</_>
         <_>
-          12 10 2 10 3.</_></rects>
-      <tilted>1</tilted></_>
+          12 4 2 19 2.</_></rects>
+      <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          10 9 1 3 -1.</_>
+          10 5 1 2 -1.</_>
         <_>
-          9 10 1 1 3.</_></rects>
+          10 5 1 1 2.</_></rects>
       <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          10 9 2 7 -1.</_>
+          10 5 4 3 -1.</_>
         <_>
-          11 9 1 7 2.</_></rects>
+          11 5 2 3 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          10 9 2 3 -1.</_>
+          10 5 3 3 -1.</_>
         <_>
-          9 10 2 1 3.</_></rects>
-      <tilted>1</tilted></_>
+          10 6 3 1 3.</_></rects>
+      <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          10 9 8 6 -1.</_>
+          10 6 1 3 -1.</_>
         <_>
-          12 9 4 6 2.</_></rects>
+          10 7 1 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          10 9 4 3 -1.</_>
+          10 6 4 6 -1.</_>
         <_>
-          10 10 4 1 3.</_></rects>
+          12 6 2 6 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          10 10 1 3 -1.</_>
+          10 7 4 3 -1.</_>
         <_>
-          10 11 1 1 3.</_></rects>
+          10 8 4 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          10 10 4 5 -1.</_>
+          10 8 1 2 -1.</_>
         <_>
-          11 11 2 5 2.</_></rects>
+          10 8 1 1 2.</_></rects>
       <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          10 10 2 3 -1.</_>
+          10 8 2 2 -1.</_>
         <_>
-          10 11 2 1 3.</_></rects>
+          10 9 2 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          10 10 6 7 -1.</_>
+          10 9 1 3 -1.</_>
         <_>
-          12 12 2 7 3.</_></rects>
+          9 10 1 1 3.</_></rects>
       <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          10 10 3 3 -1.</_>
+          10 9 2 3 -1.</_>
         <_>
-          9 11 3 1 3.</_></rects>
-      <tilted>1</tilted></_>
+          11 9 1 3 2.</_></rects>
+      <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          10 15 4 2 -1.</_>
+          10 9 2 12 -1.</_>
+        <_>
+          10 9 1 6 2.</_>
         <_>
-          11 15 2 2 2.</_></rects>
+          11 15 1 6 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          10 15 6 3 -1.</_>
+          10 9 2 3 -1.</_>
         <_>
-          12 15 2 3 3.</_></rects>
+          10 10 2 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          10 15 5 3 -1.</_>
+          10 9 2 3 -1.</_>
         <_>
-          10 16 5 1 3.</_></rects>
-      <tilted>0</tilted></_>
+          9 10 2 1 3.</_></rects>
+      <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          10 18 5 4 -1.</_>
+          10 10 3 3 -1.</_>
         <_>
-          10 19 5 2 2.</_></rects>
-      <tilted>0</tilted></_>
+          9 11 3 1 3.</_></rects>
+      <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          10 19 4 4 -1.</_>
+          10 11 5 3 -1.</_>
         <_>
-          10 20 4 2 2.</_></rects>
+          10 12 5 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          10 20 3 4 -1.</_>
+          10 12 14 3 -1.</_>
         <_>
-          11 20 1 4 3.</_></rects>
+          10 13 14 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          10 20 3 4 -1.</_>
+          10 17 4 2 -1.</_>
         <_>
-          10 21 3 2 2.</_></rects>
+          11 17 2 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          10 20 7 4 -1.</_>
+          10 17 2 6 -1.</_>
         <_>
-          10 22 7 2 2.</_></rects>
+          10 17 1 3 2.</_>
+        <_>
+          11 20 1 3 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          10 21 3 1 -1.</_>
+          10 17 3 3 -1.</_>
         <_>
-          11 21 1 1 3.</_></rects>
+          10 18 3 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          10 22 3 1 -1.</_>
+          10 17 6 2 -1.</_>
         <_>
-          11 22 1 1 3.</_></rects>
+          13 17 3 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          10 22 3 2 -1.</_>
+          10 18 5 4 -1.</_>
         <_>
-          11 22 1 2 3.</_></rects>
+          10 19 5 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          10 23 3 1 -1.</_>
+          10 19 5 4 -1.</_>
         <_>
-          11 23 1 1 3.</_></rects>
+          10 20 5 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          11 0 12 10 -1.</_>
-        <_>
-          11 0 6 5 2.</_>
+          10 19 6 3 -1.</_>
         <_>
-          17 5 6 5 2.</_></rects>
+          10 20 6 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          11 1 3 6 -1.</_>
+          10 20 3 4 -1.</_>
         <_>
-          12 1 1 6 3.</_></rects>
+          11 20 1 4 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          11 1 6 1 -1.</_>
+          10 20 6 4 -1.</_>
         <_>
-          13 1 2 1 3.</_></rects>
+          12 20 2 4 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          11 1 7 10 -1.</_>
+          10 20 5 4 -1.</_>
         <_>
-          11 6 7 5 2.</_></rects>
+          10 21 5 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          11 2 3 4 -1.</_>
+          10 20 5 4 -1.</_>
         <_>
-          12 2 1 4 3.</_></rects>
+          10 22 5 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          11 2 2 11 -1.</_>
+          10 20 14 4 -1.</_>
         <_>
-          12 2 1 11 2.</_></rects>
+          10 20 7 2 2.</_>
+        <_>
+          17 22 7 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          11 2 4 14 -1.</_>
+          10 21 3 3 -1.</_>
         <_>
-          13 2 2 14 2.</_></rects>
+          11 21 1 3 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          11 2 4 22 -1.</_>
+          10 21 5 2 -1.</_>
         <_>
-          13 2 2 22 2.</_></rects>
+          10 22 5 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          11 3 3 5 -1.</_>
+          10 22 3 2 -1.</_>
         <_>
-          12 3 1 5 3.</_></rects>
+          11 22 1 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          11 3 2 3 -1.</_>
+          10 23 3 1 -1.</_>
         <_>
-          11 4 2 1 3.</_></rects>
+          11 23 1 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          11 3 6 9 -1.</_>
+          11 0 1 2 -1.</_>
         <_>
-          13 6 2 3 9.</_></rects>
-      <tilted>0</tilted></_>
+          11 0 1 1 2.</_></rects>
+      <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          11 4 3 3 -1.</_>
+          11 0 1 4 -1.</_>
         <_>
-          11 5 3 1 3.</_></rects>
-      <tilted>0</tilted></_>
+          10 1 1 2 2.</_></rects>
+      <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          11 4 4 3 -1.</_>
+          11 0 4 1 -1.</_>
         <_>
-          11 5 4 1 3.</_></rects>
+          13 0 2 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          11 4 4 8 -1.</_>
+          11 1 1 2 -1.</_>
         <_>
-          11 4 4 4 2.</_></rects>
+          11 1 1 1 2.</_></rects>
       <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          11 5 3 2 -1.</_>
+          11 2 8 9 -1.</_>
         <_>
-          12 5 1 2 3.</_></rects>
-      <tilted>0</tilted></_>
+          13 4 4 9 2.</_></rects>
+      <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          11 5 4 6 -1.</_>
+          11 3 3 3 -1.</_>
         <_>
-          12 5 2 6 2.</_></rects>
+          12 3 1 3 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          11 6 4 5 -1.</_>
+          11 3 3 4 -1.</_>
         <_>
-          12 6 2 5 2.</_></rects>
+          12 3 1 4 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          11 6 2 3 -1.</_>
+          11 4 3 4 -1.</_>
         <_>
-          11 7 2 1 3.</_></rects>
+          12 4 1 4 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          11 6 4 3 -1.</_>
+          11 4 3 5 -1.</_>
         <_>
-          11 7 4 1 3.</_></rects>
+          12 4 1 5 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          11 6 4 8 -1.</_>
+          11 4 3 7 -1.</_>
         <_>
-          11 6 4 4 2.</_></rects>
+          12 5 1 7 3.</_></rects>
       <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          11 6 5 3 -1.</_>
+          11 4 4 1 -1.</_>
         <_>
-          11 7 5 1 3.</_></rects>
+          13 4 2 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          11 6 6 3 -1.</_>
+          11 4 2 3 -1.</_>
         <_>
-          11 7 6 1 3.</_></rects>
+          11 5 2 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          11 7 1 3 -1.</_>
+          11 4 4 3 -1.</_>
         <_>
-          11 8 1 1 3.</_></rects>
+          11 5 4 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          11 7 2 3 -1.</_>
+          11 5 3 1 -1.</_>
         <_>
-          11 8 2 1 3.</_></rects>
+          12 5 1 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          11 7 6 9 -1.</_>
+          11 5 4 11 -1.</_>
         <_>
-          13 7 2 9 3.</_></rects>
+          13 5 2 11 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          11 8 1 3 -1.</_>
+          11 6 2 3 -1.</_>
         <_>
-          11 9 1 1 3.</_></rects>
+          11 7 2 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          11 8 2 3 -1.</_>
+          11 6 4 3 -1.</_>
         <_>
-          11 9 2 1 3.</_></rects>
+          11 7 4 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          11 8 6 9 -1.</_>
+          11 7 1 3 -1.</_>
         <_>
-          13 10 2 9 3.</_></rects>
-      <tilted>1</tilted></_>
+          11 8 1 1 3.</_></rects>
+      <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          11 8 3 2 -1.</_>
+          11 7 2 3 -1.</_>
         <_>
-          11 9 3 1 2.</_></rects>
+          11 8 2 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          11 8 3 3 -1.</_>
+          11 7 2 6 -1.</_>
         <_>
-          11 9 3 1 3.</_></rects>
-      <tilted>0</tilted></_>
+          11 7 2 3 2.</_></rects>
+      <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          11 9 1 3 -1.</_>
+          11 7 3 3 -1.</_>
         <_>
-          11 10 1 1 3.</_></rects>
+          11 8 3 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          11 10 6 4 -1.</_>
+          11 7 3 8 -1.</_>
         <_>
-          13 10 2 4 3.</_></rects>
-      <tilted>0</tilted></_>
+          11 7 3 4 2.</_></rects>
+      <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          11 10 4 3 -1.</_>
+          11 8 1 3 -1.</_>
         <_>
-          11 11 4 1 3.</_></rects>
+          11 9 1 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          11 11 1 3 -1.</_>
+          11 8 2 3 -1.</_>
         <_>
-          11 12 1 1 3.</_></rects>
+          11 9 2 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          11 12 9 9 -1.</_>
+          11 9 3 3 -1.</_>
         <_>
-          14 15 3 3 9.</_></rects>
+          11 10 3 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          11 14 4 2 -1.</_>
+          11 10 4 5 -1.</_>
         <_>
-          13 14 2 2 2.</_></rects>
-      <tilted>0</tilted></_>
+          12 11 2 5 2.</_></rects>
+      <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          11 16 4 8 -1.</_>
+          11 10 6 3 -1.</_>
         <_>
-          11 18 4 4 2.</_></rects>
+          13 10 2 3 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          11 18 12 6 -1.</_>
+          11 10 6 8 -1.</_>
         <_>
-          11 18 6 3 2.</_>
+          11 10 3 4 2.</_>
         <_>
-          17 21 6 3 2.</_></rects>
+          14 14 3 4 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          11 20 3 1 -1.</_>
+          11 10 8 6 -1.</_>
         <_>
-          12 20 1 1 3.</_></rects>
-      <tilted>0</tilted></_>
+          9 12 8 2 3.</_></rects>
+      <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          11 20 3 4 -1.</_>
+          11 11 1 3 -1.</_>
         <_>
-          12 20 1 4 3.</_></rects>
+          11 12 1 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          11 20 4 4 -1.</_>
+          11 14 3 3 -1.</_>
         <_>
-          11 22 4 2 2.</_></rects>
-      <tilted>0</tilted></_>
+          10 15 3 1 3.</_></rects>
+      <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          11 21 3 1 -1.</_>
+          11 16 3 3 -1.</_>
         <_>
-          12 21 1 1 3.</_></rects>
+          11 17 3 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
@@ -10283,61 +10730,45 @@
     <_>
       <rects>
         <_>
-          11 22 4 2 -1.</_>
-        <_>
-          12 22 2 2 2.</_></rects>
-      <tilted>0</tilted></_>
-    <_>
-      <rects>
-        <_>
-          12 0 12 2 -1.</_>
+          11 22 3 2 -1.</_>
         <_>
-          15 0 6 2 2.</_></rects>
+          12 22 1 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          12 0 6 6 -1.</_>
-        <_>
-          12 0 3 6 2.</_></rects>
-      <tilted>1</tilted></_>
-    <_>
-      <rects>
-        <_>
-          12 0 12 10 -1.</_>
-        <_>
-          12 0 6 5 2.</_>
+          12 0 9 17 -1.</_>
         <_>
-          18 5 6 5 2.</_></rects>
+          15 0 3 17 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          12 1 4 10 -1.</_>
+          12 2 2 14 -1.</_>
         <_>
-          13 1 2 10 2.</_></rects>
+          13 2 1 14 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          12 2 2 3 -1.</_>
+          12 3 6 1 -1.</_>
         <_>
-          12 3 2 1 3.</_></rects>
+          14 3 2 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
           12 3 8 3 -1.</_>
         <_>
-          14 3 4 3 2.</_></rects>
+          12 4 8 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          12 3 9 3 -1.</_>
+          12 3 12 6 -1.</_>
         <_>
-          12 4 9 1 3.</_></rects>
-      <tilted>0</tilted></_>
+          10 5 12 2 3.</_></rects>
+      <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
@@ -10348,290 +10779,306 @@
     <_>
       <rects>
         <_>
-          12 5 2 2 -1.</_>
+          12 4 9 3 -1.</_>
         <_>
-          13 5 1 2 2.</_></rects>
+          15 5 3 1 9.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          12 5 3 2 -1.</_>
+          12 5 3 5 -1.</_>
         <_>
-          13 5 1 2 3.</_></rects>
+          13 5 1 5 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          12 5 2 5 -1.</_>
+          12 5 3 3 -1.</_>
         <_>
-          13 5 1 5 2.</_></rects>
+          12 6 3 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          12 5 4 6 -1.</_>
+          12 5 9 8 -1.</_>
         <_>
-          13 5 2 6 2.</_></rects>
+          15 5 3 8 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          12 5 6 7 -1.</_>
+          12 5 4 3 -1.</_>
         <_>
-          14 5 2 7 3.</_></rects>
+          12 6 4 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          12 5 3 8 -1.</_>
+          12 6 2 8 -1.</_>
         <_>
-          12 5 3 4 2.</_></rects>
+          12 6 2 4 2.</_></rects>
       <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          12 5 4 3 -1.</_>
+          12 6 3 3 -1.</_>
         <_>
-          12 6 4 1 3.</_></rects>
+          12 7 3 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          12 6 1 4 -1.</_>
+          12 7 1 3 -1.</_>
         <_>
-          12 7 1 2 2.</_></rects>
+          12 8 1 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          12 6 1 8 -1.</_>
+          12 7 1 8 -1.</_>
         <_>
-          12 6 1 4 2.</_></rects>
+          12 7 1 4 2.</_></rects>
       <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          12 6 2 10 -1.</_>
+          12 7 2 6 -1.</_>
         <_>
-          13 6 1 10 2.</_></rects>
-      <tilted>0</tilted></_>
+          12 7 2 3 2.</_></rects>
+      <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          12 6 8 1 -1.</_>
+          12 7 2 8 -1.</_>
         <_>
-          12 6 4 1 2.</_></rects>
+          12 7 2 4 2.</_></rects>
       <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          12 7 1 3 -1.</_>
+          12 7 3 3 -1.</_>
         <_>
-          12 8 1 1 3.</_></rects>
+          12 8 3 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          12 7 2 3 -1.</_>
+          12 8 1 3 -1.</_>
         <_>
-          12 8 2 1 3.</_></rects>
+          12 9 1 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          12 7 4 3 -1.</_>
+          12 8 2 3 -1.</_>
         <_>
-          12 8 4 1 3.</_></rects>
+          12 9 2 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          12 8 1 3 -1.</_>
+          12 9 2 3 -1.</_>
         <_>
-          12 9 1 1 3.</_></rects>
+          12 10 2 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          12 8 2 3 -1.</_>
+          12 10 6 4 -1.</_>
         <_>
-          12 9 2 1 3.</_></rects>
+          14 10 2 4 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          12 8 6 8 -1.</_>
+          12 10 4 10 -1.</_>
         <_>
-          12 8 3 4 2.</_>
+          12 10 2 5 2.</_>
         <_>
-          15 12 3 4 2.</_></rects>
+          14 15 2 5 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          12 9 1 3 -1.</_>
+          12 11 4 8 -1.</_>
+        <_>
+          12 11 2 4 2.</_>
         <_>
-          12 10 1 1 3.</_></rects>
+          14 15 2 4 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          12 9 2 3 -1.</_>
+          12 13 4 3 -1.</_>
         <_>
-          12 10 2 1 3.</_></rects>
+          13 13 2 3 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          12 10 4 10 -1.</_>
+          12 14 3 2 -1.</_>
         <_>
-          12 10 2 5 2.</_>
+          13 15 1 2 3.</_></rects>
+      <tilted>1</tilted></_>
+    <_>
+      <rects>
         <_>
-          14 15 2 5 2.</_></rects>
+          12 15 2 4 -1.</_>
+        <_>
+          12 15 1 2 2.</_>
+        <_>
+          13 17 1 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          12 10 3 3 -1.</_>
+          12 15 4 5 -1.</_>
         <_>
-          12 11 3 1 3.</_></rects>
+          14 15 2 5 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          12 11 4 8 -1.</_>
-        <_>
-          12 11 2 4 2.</_>
+          12 16 6 2 -1.</_>
         <_>
-          14 15 2 4 2.</_></rects>
+          14 16 2 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          12 16 4 4 -1.</_>
+          12 19 3 5 -1.</_>
         <_>
-          14 16 2 4 2.</_></rects>
+          13 19 1 5 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          12 17 6 6 -1.</_>
+          12 21 3 2 -1.</_>
         <_>
-          12 20 6 3 2.</_></rects>
+          13 21 1 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          12 18 3 4 -1.</_>
+          12 21 3 3 -1.</_>
         <_>
-          12 19 3 2 2.</_></rects>
+          13 21 1 3 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          12 19 3 4 -1.</_>
+          13 0 2 10 -1.</_>
         <_>
-          13 19 1 4 3.</_></rects>
+          13 0 1 5 2.</_>
+        <_>
+          14 5 1 5 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          12 21 3 3 -1.</_>
+          13 0 4 12 -1.</_>
         <_>
-          13 21 1 3 3.</_></rects>
+          14 0 2 12 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          13 2 4 2 -1.</_>
+          13 0 6 10 -1.</_>
         <_>
-          14 2 2 2 2.</_></rects>
+          15 0 2 10 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          13 2 2 6 -1.</_>
+          13 0 11 8 -1.</_>
+        <_>
+          11 2 11 4 2.</_></rects>
+      <tilted>1</tilted></_>
+    <_>
+      <rects>
         <_>
-          13 2 1 3 2.</_>
+          13 1 6 8 -1.</_>
         <_>
-          14 5 1 3 2.</_></rects>
+          15 1 2 8 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          13 2 2 10 -1.</_>
+          13 2 4 2 -1.</_>
         <_>
-          14 2 1 10 2.</_></rects>
+          14 2 2 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          13 2 2 14 -1.</_>
+          13 3 2 4 -1.</_>
+        <_>
+          13 3 1 2 2.</_>
         <_>
-          14 2 1 14 2.</_></rects>
+          14 5 1 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          13 2 8 6 -1.</_>
+          13 3 6 3 -1.</_>
         <_>
-          15 2 4 6 2.</_></rects>
+          15 4 2 1 9.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          13 2 6 7 -1.</_>
+          13 4 4 7 -1.</_>
         <_>
-          15 2 2 7 3.</_></rects>
+          14 4 2 7 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          13 3 4 8 -1.</_>
+          13 4 3 8 -1.</_>
         <_>
-          14 3 2 8 2.</_></rects>
+          14 4 1 8 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          13 4 3 7 -1.</_>
+          13 5 3 2 -1.</_>
         <_>
-          14 4 1 7 3.</_></rects>
+          14 5 1 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          13 4 8 2 -1.</_>
+          13 5 3 5 -1.</_>
         <_>
-          15 4 4 2 2.</_></rects>
+          14 5 1 5 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          13 4 4 3 -1.</_>
+          13 5 3 6 -1.</_>
         <_>
-          13 5 4 1 3.</_></rects>
+          14 5 1 6 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          13 5 6 6 -1.</_>
+          13 5 3 8 -1.</_>
         <_>
-          15 5 2 6 3.</_></rects>
+          14 5 1 8 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          13 6 1 3 -1.</_>
+          13 5 6 1 -1.</_>
         <_>
-          13 7 1 1 3.</_></rects>
+          15 5 2 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          13 6 6 6 -1.</_>
+          13 6 7 4 -1.</_>
         <_>
-          15 6 2 6 3.</_></rects>
+          13 7 7 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
@@ -10643,10 +11090,12 @@
     <_>
       <rects>
         <_>
-          13 7 1 8 -1.</_>
+          13 7 4 8 -1.</_>
         <_>
-          13 7 1 4 2.</_></rects>
-      <tilted>1</tilted></_>
+          13 7 2 4 2.</_>
+        <_>
+          15 11 2 4 2.</_></rects>
+      <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
@@ -10664,9 +11113,23 @@
     <_>
       <rects>
         <_>
-          13 8 6 5 -1.</_>
+          13 7 8 1 -1.</_>
+        <_>
+          13 7 4 1 2.</_></rects>
+      <tilted>1</tilted></_>
+    <_>
+      <rects>
+        <_>
+          13 8 2 3 -1.</_>
+        <_>
+          13 9 2 1 3.</_></rects>
+      <tilted>0</tilted></_>
+    <_>
+      <rects>
+        <_>
+          13 8 9 3 -1.</_>
         <_>
-          15 8 2 5 3.</_></rects>
+          16 9 3 1 9.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
@@ -10680,67 +11143,67 @@
     <_>
       <rects>
         <_>
-          13 9 3 3 -1.</_>
+          13 9 2 3 -1.</_>
         <_>
-          14 9 1 3 3.</_></rects>
+          13 10 2 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          13 9 2 3 -1.</_>
+          13 9 6 4 -1.</_>
         <_>
-          13 10 2 1 3.</_></rects>
+          15 9 2 4 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          13 10 3 2 -1.</_>
+          13 9 10 2 -1.</_>
         <_>
-          14 10 1 2 3.</_></rects>
+          13 10 10 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          13 11 4 8 -1.</_>
+          13 10 3 1 -1.</_>
         <_>
-          13 11 2 4 2.</_>
-        <_>
-          15 15 2 4 2.</_></rects>
+          14 10 1 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          13 12 8 5 -1.</_>
+          13 10 3 2 -1.</_>
         <_>
-          15 12 4 5 2.</_></rects>
+          14 10 1 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          13 13 7 3 -1.</_>
+          13 11 2 3 -1.</_>
         <_>
-          13 14 7 1 3.</_></rects>
+          13 12 2 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          13 14 4 1 -1.</_>
+          13 13 2 6 -1.</_>
+        <_>
+          13 13 1 3 2.</_>
         <_>
-          14 14 2 1 2.</_></rects>
+          14 16 1 3 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          13 17 3 7 -1.</_>
+          13 13 4 6 -1.</_>
         <_>
-          14 17 1 7 3.</_></rects>
-      <tilted>0</tilted></_>
+          14 14 2 6 2.</_></rects>
+      <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          13 21 3 3 -1.</_>
+          13 20 3 4 -1.</_>
         <_>
-          14 21 1 3 3.</_></rects>
+          14 20 1 4 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
@@ -10752,6 +11215,27 @@
     <_>
       <rects>
         <_>
+          13 23 3 1 -1.</_>
+        <_>
+          14 23 1 1 3.</_></rects>
+      <tilted>0</tilted></_>
+    <_>
+      <rects>
+        <_>
+          14 0 3 11 -1.</_>
+        <_>
+          15 1 1 11 3.</_></rects>
+      <tilted>1</tilted></_>
+    <_>
+      <rects>
+        <_>
+          14 0 2 3 -1.</_>
+        <_>
+          14 1 2 1 3.</_></rects>
+      <tilted>0</tilted></_>
+    <_>
+      <rects>
+        <_>
           14 0 10 6 -1.</_>
         <_>
           14 0 5 3 2.</_>
@@ -10761,60 +11245,71 @@
     <_>
       <rects>
         <_>
-          14 0 10 10 -1.</_>
+          14 0 10 10 -1.</_>
+        <_>
+          14 0 5 5 2.</_>
+        <_>
+          19 5 5 5 2.</_></rects>
+      <tilted>0</tilted></_>
+    <_>
+      <rects>
+        <_>
+          14 1 10 6 -1.</_>
         <_>
-          14 0 5 5 2.</_>
+          14 1 5 3 2.</_>
         <_>
-          19 5 5 5 2.</_></rects>
+          19 4 5 3 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          14 0 10 9 -1.</_>
+          14 2 1 2 -1.</_>
         <_>
-          11 3 10 3 3.</_></rects>
+          14 2 1 1 2.</_></rects>
       <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          14 1 1 8 -1.</_>
+          14 2 3 8 -1.</_>
         <_>
-          14 5 1 4 2.</_></rects>
+          15 2 1 8 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          14 2 10 2 -1.</_>
+          14 2 6 7 -1.</_>
         <_>
-          19 2 5 2 2.</_></rects>
+          16 2 2 7 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          14 3 2 8 -1.</_>
+          14 3 2 4 -1.</_>
+        <_>
+          14 3 1 2 2.</_>
         <_>
-          15 3 1 8 2.</_></rects>
+          15 5 1 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          14 4 3 3 -1.</_>
+          14 3 2 7 -1.</_>
         <_>
-          15 4 1 3 3.</_></rects>
+          15 3 1 7 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          14 4 3 4 -1.</_>
+          14 5 3 2 -1.</_>
         <_>
-          15 4 1 4 3.</_></rects>
+          15 5 1 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          14 4 8 3 -1.</_>
+          14 5 2 3 -1.</_>
         <_>
-          14 5 8 1 3.</_></rects>
+          15 5 1 3 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
@@ -10833,30 +11328,30 @@
     <_>
       <rects>
         <_>
-          14 6 3 5 -1.</_>
+          14 5 2 7 -1.</_>
         <_>
-          15 6 1 5 3.</_></rects>
+          15 5 1 7 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          14 6 6 17 -1.</_>
+          14 5 6 4 -1.</_>
         <_>
-          16 6 2 17 3.</_></rects>
+          16 5 2 4 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          14 6 8 2 -1.</_>
+          14 6 6 3 -1.</_>
         <_>
-          14 6 4 2 2.</_></rects>
+          14 6 3 3 2.</_></rects>
       <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          14 7 4 3 -1.</_>
+          14 7 4 16 -1.</_>
         <_>
-          15 7 2 3 2.</_></rects>
+          15 7 2 16 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
@@ -10868,122 +11363,134 @@
     <_>
       <rects>
         <_>
-          14 8 6 3 -1.</_>
+          14 7 6 16 -1.</_>
         <_>
-          16 9 2 1 9.</_></rects>
+          16 7 2 16 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          14 8 6 1 -1.</_>
+          14 7 9 4 -1.</_>
         <_>
-          14 8 3 1 2.</_></rects>
-      <tilted>1</tilted></_>
+          14 8 9 2 2.</_></rects>
+      <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          14 8 6 2 -1.</_>
+          14 9 2 4 -1.</_>
         <_>
-          14 8 3 2 2.</_></rects>
-      <tilted>1</tilted></_>
+          14 9 1 2 2.</_>
+        <_>
+          15 11 1 2 2.</_></rects>
+      <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          14 9 4 1 -1.</_>
+          14 10 3 1 -1.</_>
         <_>
-          16 9 2 1 2.</_></rects>
+          15 10 1 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          14 9 6 6 -1.</_>
+          14 10 2 2 -1.</_>
         <_>
-          12 11 6 2 3.</_></rects>
-      <tilted>1</tilted></_>
+          15 10 1 2 2.</_></rects>
+      <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          14 10 3 1 -1.</_>
+          14 10 3 3 -1.</_>
         <_>
-          15 10 1 1 3.</_></rects>
+          15 10 1 3 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          14 10 2 2 -1.</_>
+          14 12 2 1 -1.</_>
         <_>
-          15 10 1 2 2.</_></rects>
+          15 12 1 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          14 10 2 6 -1.</_>
+          14 14 3 4 -1.</_>
+        <_>
+          15 15 1 4 3.</_></rects>
+      <tilted>1</tilted></_>
+    <_>
+      <rects>
         <_>
-          14 10 1 3 2.</_>
+          14 14 5 3 -1.</_>
         <_>
-          15 13 1 3 2.</_></rects>
+          14 15 5 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          14 15 1 2 -1.</_>
+          14 15 3 3 -1.</_>
         <_>
-          14 15 1 1 2.</_></rects>
+          15 16 1 3 3.</_></rects>
       <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          14 16 8 8 -1.</_>
-        <_>
-          14 16 4 4 2.</_>
+          14 19 3 5 -1.</_>
         <_>
-          18 20 4 4 2.</_></rects>
+          15 19 1 5 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          14 17 9 3 -1.</_>
+          14 21 10 1 -1.</_>
         <_>
-          14 18 9 1 3.</_></rects>
+          19 21 5 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          14 20 3 4 -1.</_>
+          15 0 2 2 -1.</_>
         <_>
-          15 20 1 4 3.</_></rects>
-      <tilted>0</tilted></_>
+          15 0 1 2 2.</_></rects>
+      <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          15 0 3 1 -1.</_>
+          15 0 4 2 -1.</_>
         <_>
-          16 1 1 1 3.</_></rects>
+          16 1 2 2 2.</_></rects>
       <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          15 0 4 13 -1.</_>
+          15 3 6 3 -1.</_>
         <_>
-          16 1 2 13 2.</_></rects>
-      <tilted>1</tilted></_>
+          15 4 6 1 3.</_></rects>
+      <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          15 1 3 4 -1.</_>
+          15 4 2 3 -1.</_>
         <_>
-          15 3 3 2 2.</_></rects>
+          15 5 2 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          15 3 2 2 -1.</_>
+          15 5 2 1 -1.</_>
         <_>
-          15 3 2 1 2.</_></rects>
+          15 5 1 1 2.</_></rects>
       <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
+          15 5 2 2 -1.</_>
+        <_>
+          16 5 1 2 2.</_></rects>
+      <tilted>0</tilted></_>
+    <_>
+      <rects>
+        <_>
           15 5 3 2 -1.</_>
         <_>
           16 5 1 2 3.</_></rects>
@@ -10998,56 +11505,54 @@
     <_>
       <rects>
         <_>
-          15 5 2 7 -1.</_>
+          15 7 4 4 -1.</_>
         <_>
-          16 5 1 7 2.</_></rects>
+          15 9 4 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          15 5 4 2 -1.</_>
+          15 7 4 6 -1.</_>
         <_>
-          15 5 2 1 2.</_>
-        <_>
-          17 6 2 1 2.</_></rects>
+          15 9 4 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          15 5 5 6 -1.</_>
+          15 7 5 6 -1.</_>
         <_>
-          15 7 5 2 3.</_></rects>
+          15 9 5 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          15 6 3 2 -1.</_>
+          15 8 2 2 -1.</_>
         <_>
-          16 7 1 2 3.</_></rects>
-      <tilted>1</tilted></_>
+          15 8 1 1 2.</_>
+        <_>
+          16 9 1 1 2.</_></rects>
+      <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          15 6 3 5 -1.</_>
+          15 8 2 1 -1.</_>
         <_>
-          16 6 1 5 3.</_></rects>
-      <tilted>0</tilted></_>
+          15 8 1 1 2.</_></rects>
+      <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          15 7 5 6 -1.</_>
+          15 8 1 12 -1.</_>
         <_>
-          15 9 5 2 3.</_></rects>
+          15 14 1 6 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          15 8 2 2 -1.</_>
-        <_>
-          15 8 1 1 2.</_>
+          15 8 6 2 -1.</_>
         <_>
-          16 9 1 1 2.</_></rects>
-      <tilted>0</tilted></_>
+          15 8 3 2 2.</_></rects>
+      <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
@@ -11058,9 +11563,9 @@
     <_>
       <rects>
         <_>
-          15 8 4 4 -1.</_>
+          15 8 5 4 -1.</_>
         <_>
-          15 9 4 2 2.</_></rects>
+          15 9 5 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
@@ -11079,23 +11584,25 @@
     <_>
       <rects>
         <_>
-          15 9 1 10 -1.</_>
+          15 10 3 1 -1.</_>
         <_>
-          15 14 1 5 2.</_></rects>
+          16 10 1 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          15 10 2 1 -1.</_>
+          15 10 2 2 -1.</_>
         <_>
-          16 10 1 1 2.</_></rects>
+          15 10 1 1 2.</_>
+        <_>
+          16 11 1 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          15 10 3 1 -1.</_>
+          15 10 2 2 -1.</_>
         <_>
-          16 10 1 1 3.</_></rects>
+          16 10 1 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
@@ -11107,81 +11614,55 @@
     <_>
       <rects>
         <_>
-          15 10 4 4 -1.</_>
-        <_>
-          14 11 4 2 2.</_></rects>
-      <tilted>1</tilted></_>
-    <_>
-      <rects>
-        <_>
-          15 11 7 4 -1.</_>
-        <_>
-          14 12 7 2 2.</_></rects>
-      <tilted>1</tilted></_>
-    <_>
-      <rects>
-        <_>
-          15 12 6 6 -1.</_>
-        <_>
-          17 14 2 6 3.</_></rects>
-      <tilted>1</tilted></_>
-    <_>
-      <rects>
-        <_>
-          15 13 3 4 -1.</_>
+          15 10 3 4 -1.</_>
         <_>
-          16 14 1 4 3.</_></rects>
+          14 11 3 2 2.</_></rects>
       <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          15 13 3 11 -1.</_>
+          15 10 5 4 -1.</_>
         <_>
-          16 13 1 11 3.</_></rects>
+          15 11 5 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          15 13 2 3 -1.</_>
+          15 10 5 4 -1.</_>
         <_>
-          15 14 2 1 3.</_></rects>
-      <tilted>0</tilted></_>
+          14 11 5 2 2.</_></rects>
+      <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          15 14 1 8 -1.</_>
+          15 15 8 3 -1.</_>
         <_>
-          15 16 1 4 2.</_></rects>
+          19 15 4 3 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          15 14 8 10 -1.</_>
+          15 15 8 8 -1.</_>
         <_>
-          15 14 4 5 2.</_>
+          15 15 4 4 2.</_>
         <_>
-          19 19 4 5 2.</_></rects>
+          19 19 4 4 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          15 15 4 3 -1.</_>
+          15 16 5 3 -1.</_>
         <_>
-          15 16 4 1 3.</_></rects>
+          15 17 5 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          15 16 8 2 -1.</_>
-        <_>
-          19 16 4 2 2.</_></rects>
-      <tilted>0</tilted></_>
-    <_>
-      <rects>
+          15 18 8 6 -1.</_>
         <_>
-          15 16 6 3 -1.</_>
+          15 18 4 3 2.</_>
         <_>
-          15 17 6 1 3.</_></rects>
+          19 21 4 3 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
@@ -11218,25 +11699,37 @@
     <_>
       <rects>
         <_>
-          16 0 8 16 -1.</_>
+          16 1 3 3 -1.</_>
+        <_>
+          17 2 1 1 9.</_></rects>
+      <tilted>0</tilted></_>
+    <_>
+      <rects>
+        <_>
+          16 1 2 1 -1.</_>
         <_>
-          16 0 4 8 2.</_>
+          16 1 1 1 2.</_></rects>
+      <tilted>1</tilted></_>
+    <_>
+      <rects>
+        <_>
+          16 2 1 2 -1.</_>
         <_>
-          20 8 4 8 2.</_></rects>
+          16 3 1 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          16 1 3 3 -1.</_>
+          16 2 3 3 -1.</_>
         <_>
-          17 2 1 1 9.</_></rects>
+          17 3 1 1 9.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          16 1 6 2 -1.</_>
+          16 2 4 2 -1.</_>
         <_>
-          18 3 2 2 3.</_></rects>
+          17 3 2 2 2.</_></rects>
       <tilted>1</tilted></_>
     <_>
       <rects>
@@ -11248,44 +11741,58 @@
     <_>
       <rects>
         <_>
-          16 2 4 3 -1.</_>
+          16 3 4 12 -1.</_>
         <_>
-          16 3 4 1 3.</_></rects>
-      <tilted>0</tilted></_>
+          17 4 2 12 2.</_></rects>
+      <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          16 2 4 8 -1.</_>
+          16 4 6 3 -1.</_>
         <_>
-          14 4 4 4 2.</_></rects>
+          15 5 6 1 3.</_></rects>
       <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          16 6 3 3 -1.</_>
+          16 5 1 2 -1.</_>
         <_>
-          17 7 1 3 3.</_></rects>
+          16 5 1 1 2.</_></rects>
       <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          16 6 4 4 -1.</_>
+          16 5 3 2 -1.</_>
         <_>
-          18 6 2 4 2.</_></rects>
+          17 5 1 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          16 7 2 3 -1.</_>
+          16 5 3 9 -1.</_>
         <_>
-          16 8 2 1 3.</_></rects>
+          16 8 3 3 3.</_></rects>
+      <tilted>0</tilted></_>
+    <_>
+      <rects>
+        <_>
+          16 6 6 2 -1.</_>
+        <_>
+          18 8 2 2 3.</_></rects>
+      <tilted>1</tilted></_>
+    <_>
+      <rects>
+        <_>
+          16 7 1 6 -1.</_>
+        <_>
+          16 9 1 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          16 7 2 4 -1.</_>
+          16 7 2 3 -1.</_>
         <_>
-          16 8 2 2 2.</_></rects>
+          16 8 2 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
@@ -11297,39 +11804,51 @@
     <_>
       <rects>
         <_>
-          16 7 4 10 -1.</_>
-        <_>
-          16 7 2 5 2.</_>
+          16 7 3 2 -1.</_>
         <_>
-          18 12 2 5 2.</_></rects>
+          16 8 3 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
           16 7 3 2 -1.</_>
         <_>
-          16 8 3 1 2.</_></rects>
+          16 7 3 1 2.</_></rects>
+      <tilted>1</tilted></_>
+    <_>
+      <rects>
+        <_>
+          16 7 3 6 -1.</_>
+        <_>
+          16 9 3 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          16 7 3 3 -1.</_>
+          16 7 6 4 -1.</_>
+        <_>
+          16 7 3 4 2.</_></rects>
+      <tilted>1</tilted></_>
+    <_>
+      <rects>
+        <_>
+          16 7 4 3 -1.</_>
         <_>
-          16 8 3 1 3.</_></rects>
+          16 8 4 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          16 7 3 6 -1.</_>
+          16 7 5 3 -1.</_>
         <_>
-          16 9 3 2 3.</_></rects>
+          16 8 5 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          16 7 4 6 -1.</_>
+          16 7 5 6 -1.</_>
         <_>
-          16 9 4 2 3.</_></rects>
+          16 9 5 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
@@ -11341,9 +11860,16 @@
     <_>
       <rects>
         <_>
-          16 7 7 4 -1.</_>
+          16 7 7 8 -1.</_>
+        <_>
+          14 9 7 4 2.</_></rects>
+      <tilted>1</tilted></_>
+    <_>
+      <rects>
+        <_>
+          16 7 8 6 -1.</_>
         <_>
-          16 8 7 2 2.</_></rects>
+          16 9 8 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
@@ -11362,6 +11888,15 @@
     <_>
       <rects>
         <_>
+          16 8 2 2 -1.</_>
+        <_>
+          16 8 1 1 2.</_>
+        <_>
+          17 9 1 1 2.</_></rects>
+      <tilted>0</tilted></_>
+    <_>
+      <rects>
+        <_>
           16 8 3 3 -1.</_>
         <_>
           17 9 1 1 9.</_></rects>
@@ -11369,9 +11904,9 @@
     <_>
       <rects>
         <_>
-          16 8 3 1 -1.</_>
+          16 8 2 1 -1.</_>
         <_>
-          17 9 1 1 3.</_></rects>
+          16 8 1 1 2.</_></rects>
       <tilted>1</tilted></_>
     <_>
       <rects>
@@ -11383,537 +11918,590 @@
     <_>
       <rects>
         <_>
-          16 8 2 4 -1.</_>
+          16 8 5 6 -1.</_>
         <_>
-          16 9 2 2 2.</_></rects>
-      <tilted>0</tilted></_>
+          14 10 5 2 3.</_></rects>
+      <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          16 8 3 4 -1.</_>
+          16 8 7 8 -1.</_>
         <_>
-          16 9 3 2 2.</_></rects>
+          14 10 7 4 2.</_></rects>
+      <tilted>1</tilted></_>
+    <_>
+      <rects>
+        <_>
+          16 9 3 1 -1.</_>
+        <_>
+          17 9 1 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          16 8 3 16 -1.</_>
+          16 9 1 3 -1.</_>
         <_>
-          16 12 3 8 2.</_></rects>
+          16 10 1 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          16 8 8 2 -1.</_>
+          16 9 5 3 -1.</_>
         <_>
-          16 8 4 1 2.</_>
+          16 10 5 1 3.</_></rects>
+      <tilted>0</tilted></_>
+    <_>
+      <rects>
+        <_>
+          16 9 8 2 -1.</_>
         <_>
-          20 9 4 1 2.</_></rects>
+          16 10 8 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          16 9 1 3 -1.</_>
+          16 10 1 3 -1.</_>
         <_>
-          16 10 1 1 3.</_></rects>
+          16 11 1 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          16 9 3 6 -1.</_>
+          16 10 2 2 -1.</_>
         <_>
-          14 11 3 2 3.</_></rects>
-      <tilted>1</tilted></_>
+          17 10 1 2 2.</_></rects>
+      <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          16 9 5 6 -1.</_>
+          16 10 2 3 -1.</_>
         <_>
-          14 11 5 2 3.</_></rects>
-      <tilted>1</tilted></_>
+          16 11 2 1 3.</_></rects>
+      <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          16 9 6 6 -1.</_>
+          16 10 6 6 -1.</_>
         <_>
-          14 11 6 2 3.</_></rects>
+          14 12 6 2 3.</_></rects>
       <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          16 9 8 6 -1.</_>
+          16 11 3 1 -1.</_>
         <_>
-          14 11 8 2 3.</_></rects>
-      <tilted>1</tilted></_>
+          17 11 1 1 3.</_></rects>
+      <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          16 10 1 2 -1.</_>
+          16 11 3 2 -1.</_>
         <_>
-          16 11 1 1 2.</_></rects>
+          17 11 1 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          16 10 1 3 -1.</_>
+          16 11 3 13 -1.</_>
         <_>
-          16 11 1 1 3.</_></rects>
+          17 11 1 13 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          16 10 2 3 -1.</_>
+          16 11 2 2 -1.</_>
         <_>
-          16 11 2 1 3.</_></rects>
+          16 12 2 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          16 10 3 3 -1.</_>
+          16 11 2 3 -1.</_>
         <_>
-          16 11 3 1 3.</_></rects>
+          16 12 2 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          16 10 5 2 -1.</_>
+          16 11 3 3 -1.</_>
         <_>
-          16 11 5 1 2.</_></rects>
+          16 12 3 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          16 10 6 8 -1.</_>
+          16 14 4 2 -1.</_>
         <_>
-          16 12 6 4 2.</_></rects>
+          18 14 2 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          16 11 3 2 -1.</_>
+          16 14 6 3 -1.</_>
         <_>
-          17 11 1 2 3.</_></rects>
+          19 14 3 3 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          16 11 2 2 -1.</_>
+          16 19 3 5 -1.</_>
         <_>
-          16 12 2 1 2.</_></rects>
+          17 19 1 5 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          16 11 3 2 -1.</_>
+          16 19 2 3 -1.</_>
         <_>
-          16 12 3 1 2.</_></rects>
+          15 20 2 1 3.</_></rects>
+      <tilted>1</tilted></_>
+    <_>
+      <rects>
+        <_>
+          16 19 8 3 -1.</_>
+        <_>
+          16 20 8 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          16 14 8 10 -1.</_>
+          17 0 6 15 -1.</_>
+        <_>
+          19 2 2 15 3.</_></rects>
+      <tilted>1</tilted></_>
+    <_>
+      <rects>
         <_>
-          16 14 4 5 2.</_>
+          17 0 6 1 -1.</_>
         <_>
-          20 19 4 5 2.</_></rects>
+          20 0 3 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          16 16 8 2 -1.</_>
+          17 0 6 2 -1.</_>
         <_>
-          20 16 4 2 2.</_></rects>
+          20 0 3 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          16 18 3 6 -1.</_>
+          17 2 3 3 -1.</_>
         <_>
-          17 18 1 6 3.</_></rects>
+          18 3 1 1 9.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          16 18 8 3 -1.</_>
+          17 3 3 2 -1.</_>
         <_>
-          20 18 4 3 2.</_></rects>
+          18 3 1 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          16 19 2 3 -1.</_>
+          17 3 3 9 -1.</_>
         <_>
-          15 20 2 1 3.</_></rects>
-      <tilted>1</tilted></_>
+          18 6 1 3 9.</_></rects>
+      <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          16 20 1 3 -1.</_>
+          17 3 6 2 -1.</_>
         <_>
-          15 21 1 1 3.</_></rects>
+          19 5 2 2 3.</_></rects>
       <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          17 1 6 2 -1.</_>
+          17 3 3 8 -1.</_>
         <_>
-          17 1 3 2 2.</_></rects>
+          15 5 3 4 2.</_></rects>
       <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          17 3 3 1 -1.</_>
+          17 3 5 3 -1.</_>
         <_>
-          18 3 1 1 3.</_></rects>
+          17 4 5 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          17 3 2 3 -1.</_>
+          17 4 2 6 -1.</_>
+        <_>
+          17 4 1 3 2.</_>
         <_>
-          17 4 2 1 3.</_></rects>
+          18 7 1 3 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          17 3 6 3 -1.</_>
+          17 5 1 2 -1.</_>
         <_>
-          19 5 2 3 3.</_></rects>
+          17 5 1 1 2.</_></rects>
       <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          17 3 3 3 -1.</_>
+          17 5 3 4 -1.</_>
         <_>
-          17 4 3 1 3.</_></rects>
-      <tilted>0</tilted></_>
+          18 6 1 4 3.</_></rects>
+      <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          17 3 7 3 -1.</_>
+          17 5 6 2 -1.</_>
         <_>
-          17 4 7 1 3.</_></rects>
-      <tilted>0</tilted></_>
+          17 5 3 2 2.</_></rects>
+      <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          17 4 4 2 -1.</_>
+          17 5 7 3 -1.</_>
         <_>
-          18 5 2 2 2.</_></rects>
+          16 6 7 1 3.</_></rects>
       <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          17 4 2 6 -1.</_>
+          17 6 2 3 -1.</_>
         <_>
-          17 4 1 3 2.</_>
+          17 6 1 3 2.</_></rects>
+      <tilted>1</tilted></_>
+    <_>
+      <rects>
         <_>
-          18 7 1 3 2.</_></rects>
+          17 6 3 4 -1.</_>
+        <_>
+          18 7 1 4 3.</_></rects>
+      <tilted>1</tilted></_>
+    <_>
+      <rects>
+        <_>
+          17 6 3 3 -1.</_>
+        <_>
+          17 7 3 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          17 4 6 5 -1.</_>
+          17 6 6 1 -1.</_>
         <_>
-          19 6 2 5 3.</_></rects>
+          17 6 3 1 2.</_></rects>
       <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          17 4 7 16 -1.</_>
+          17 7 1 3 -1.</_>
         <_>
-          17 8 7 8 2.</_></rects>
+          17 8 1 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          17 5 1 2 -1.</_>
+          17 7 1 3 -1.</_>
         <_>
-          17 5 1 1 2.</_></rects>
+          16 8 1 1 3.</_></rects>
       <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          17 5 3 4 -1.</_>
+          17 7 1 6 -1.</_>
         <_>
-          18 6 1 4 3.</_></rects>
-      <tilted>1</tilted></_>
+          17 9 1 2 3.</_></rects>
+      <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          17 6 1 9 -1.</_>
+          17 7 3 6 -1.</_>
         <_>
-          17 9 1 3 3.</_></rects>
+          18 9 1 2 9.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          17 6 3 4 -1.</_>
+          17 7 3 2 -1.</_>
+        <_>
+          18 8 1 2 3.</_></rects>
+      <tilted>1</tilted></_>
+    <_>
+      <rects>
+        <_>
+          17 7 2 3 -1.</_>
+        <_>
+          17 7 1 3 2.</_></rects>
+      <tilted>1</tilted></_>
+    <_>
+      <rects>
+        <_>
+          17 7 3 3 -1.</_>
+        <_>
+          18 8 1 3 3.</_></rects>
+      <tilted>1</tilted></_>
+    <_>
+      <rects>
+        <_>
+          17 7 2 3 -1.</_>
         <_>
-          18 7 1 4 3.</_></rects>
-      <tilted>1</tilted></_>
+          17 8 2 1 3.</_></rects>
+      <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          17 6 6 3 -1.</_>
+          17 7 6 9 -1.</_>
         <_>
-          19 8 2 3 3.</_></rects>
+          14 10 6 3 3.</_></rects>
       <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          17 6 3 3 -1.</_>
+          17 8 3 3 -1.</_>
         <_>
-          17 7 3 1 3.</_></rects>
+          18 9 1 1 9.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          17 7 1 3 -1.</_>
+          17 8 2 4 -1.</_>
         <_>
-          17 8 1 1 3.</_></rects>
+          17 8 1 2 2.</_>
+        <_>
+          18 10 1 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          17 7 1 6 -1.</_>
+          17 8 2 8 -1.</_>
         <_>
-          17 9 1 2 3.</_></rects>
+          17 8 1 4 2.</_>
+        <_>
+          18 12 1 4 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          17 7 3 3 -1.</_>
+          17 8 3 4 -1.</_>
         <_>
-          18 8 1 3 3.</_></rects>
+          18 9 1 4 3.</_></rects>
       <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          17 7 4 5 -1.</_>
+          17 8 4 6 -1.</_>
         <_>
-          18 8 2 5 2.</_></rects>
+          15 10 4 2 3.</_></rects>
       <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          17 7 4 9 -1.</_>
+          17 9 3 1 -1.</_>
         <_>
-          18 8 2 9 2.</_></rects>
-      <tilted>1</tilted></_>
+          18 9 1 1 3.</_></rects>
+      <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          17 7 2 2 -1.</_>
+          17 9 2 6 -1.</_>
+        <_>
+          17 9 1 3 2.</_>
         <_>
-          17 8 2 1 2.</_></rects>
+          18 12 1 3 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          17 7 3 2 -1.</_>
+          17 9 6 10 -1.</_>
+        <_>
+          17 9 3 5 2.</_>
         <_>
-          17 8 3 1 2.</_></rects>
+          20 14 3 5 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          17 7 3 3 -1.</_>
+          17 9 7 2 -1.</_>
         <_>
-          17 8 3 1 3.</_></rects>
+          17 10 7 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          17 7 3 2 -1.</_>
+          17 10 3 1 -1.</_>
         <_>
-          17 7 3 1 2.</_></rects>
-      <tilted>1</tilted></_>
+          18 10 1 1 3.</_></rects>
+      <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          17 7 5 2 -1.</_>
+          17 10 1 3 -1.</_>
         <_>
-          17 8 5 1 2.</_></rects>
+          17 11 1 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          17 7 5 4 -1.</_>
+          17 10 2 3 -1.</_>
         <_>
-          17 8 5 2 2.</_></rects>
+          18 10 1 3 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          17 8 2 2 -1.</_>
-        <_>
-          17 8 1 1 2.</_>
+          17 10 2 4 -1.</_>
         <_>
-          18 9 1 1 2.</_></rects>
+          18 10 1 4 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          17 8 3 3 -1.</_>
+          17 10 4 2 -1.</_>
         <_>
-          18 9 1 1 9.</_></rects>
+          17 10 2 1 2.</_>
+        <_>
+          19 11 2 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          17 8 6 9 -1.</_>
+          17 11 3 2 -1.</_>
         <_>
-          20 8 3 9 2.</_></rects>
+          18 11 1 2 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          17 8 7 8 -1.</_>
+          17 11 3 3 -1.</_>
         <_>
-          15 10 7 4 2.</_></rects>
-      <tilted>1</tilted></_>
+          18 11 1 3 3.</_></rects>
+      <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          17 9 3 3 -1.</_>
+          17 12 3 1 -1.</_>
         <_>
-          18 10 1 1 9.</_></rects>
+          18 12 1 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          17 10 1 3 -1.</_>
+          17 12 6 2 -1.</_>
         <_>
-          17 11 1 1 3.</_></rects>
+          20 12 3 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          17 10 4 1 -1.</_>
+          17 15 2 3 -1.</_>
         <_>
-          19 10 2 1 2.</_></rects>
+          17 16 2 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          17 10 2 4 -1.</_>
+          17 15 4 3 -1.</_>
         <_>
-          17 11 2 2 2.</_></rects>
+          19 15 2 3 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          17 10 2 2 -1.</_>
+          17 15 4 4 -1.</_>
         <_>
-          17 10 2 1 2.</_></rects>
+          17 15 2 4 2.</_></rects>
       <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          17 10 4 4 -1.</_>
+          17 18 2 4 -1.</_>
         <_>
-          17 11 4 2 2.</_></rects>
-      <tilted>0</tilted></_>
+          16 19 2 2 2.</_></rects>
+      <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          17 10 4 8 -1.</_>
+          17 18 5 3 -1.</_>
         <_>
-          17 12 4 4 2.</_></rects>
+          17 19 5 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          17 11 2 2 -1.</_>
+          17 19 1 3 -1.</_>
         <_>
-          18 11 1 2 2.</_></rects>
-      <tilted>0</tilted></_>
+          16 20 1 1 3.</_></rects>
+      <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          17 11 3 2 -1.</_>
+          17 20 1 3 -1.</_>
         <_>
-          18 11 1 2 3.</_></rects>
-      <tilted>0</tilted></_>
+          16 21 1 1 3.</_></rects>
+      <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          17 11 3 3 -1.</_>
+          17 20 3 4 -1.</_>
         <_>
-          18 11 1 3 3.</_></rects>
+          18 20 1 4 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          17 12 3 1 -1.</_>
+          18 0 2 2 -1.</_>
         <_>
-          18 12 1 1 3.</_></rects>
-      <tilted>0</tilted></_>
+          18 0 1 2 2.</_></rects>
+      <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          17 14 1 3 -1.</_>
+          18 0 6 1 -1.</_>
         <_>
-          17 15 1 1 3.</_></rects>
+          21 0 3 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          17 14 2 2 -1.</_>
+          18 0 6 5 -1.</_>
         <_>
-          17 14 1 1 2.</_>
-        <_>
-          18 15 1 1 2.</_></rects>
+          21 0 3 5 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          17 14 4 4 -1.</_>
-        <_>
-          19 14 2 4 2.</_></rects>
-      <tilted>0</tilted></_>
-    <_>
-      <rects>
+          18 0 6 12 -1.</_>
         <_>
-          17 15 4 2 -1.</_>
+          18 0 3 6 2.</_>
         <_>
-          19 15 2 2 2.</_></rects>
+          21 6 3 6 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          17 17 2 4 -1.</_>
+          18 2 3 1 -1.</_>
         <_>
-          17 17 2 2 2.</_></rects>
+          19 3 1 1 3.</_></rects>
       <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          18 0 4 1 -1.</_>
-        <_>
-          20 0 2 1 2.</_></rects>
-      <tilted>0</tilted></_>
-    <_>
-      <rects>
-        <_>
-          18 3 3 1 -1.</_>
+          18 2 4 1 -1.</_>
         <_>
-          19 3 1 1 3.</_></rects>
-      <tilted>0</tilted></_>
+          19 3 2 1 2.</_></rects>
+      <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          18 4 6 5 -1.</_>
+          18 2 4 3 -1.</_>
         <_>
-          20 6 2 5 3.</_></rects>
+          19 3 2 3 2.</_></rects>
       <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          18 4 6 19 -1.</_>
+          18 4 4 3 -1.</_>
         <_>
-          21 4 3 19 2.</_></rects>
+          18 5 4 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
@@ -11925,72 +12513,72 @@
     <_>
       <rects>
         <_>
-          18 5 4 9 -1.</_>
+          18 6 2 3 -1.</_>
         <_>
-          19 6 2 9 2.</_></rects>
+          18 6 1 3 2.</_></rects>
       <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          18 6 2 4 -1.</_>
+          18 6 4 3 -1.</_>
         <_>
-          18 6 1 4 2.</_></rects>
+          19 7 2 3 2.</_></rects>
       <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          18 6 3 4 -1.</_>
+          18 6 4 4 -1.</_>
         <_>
-          19 7 1 4 3.</_></rects>
+          19 7 2 4 2.</_></rects>
       <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          18 6 4 4 -1.</_>
+          18 6 2 5 -1.</_>
         <_>
-          19 7 2 4 2.</_></rects>
+          18 6 1 5 2.</_></rects>
       <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          18 6 4 5 -1.</_>
+          18 6 4 6 -1.</_>
         <_>
-          19 7 2 5 2.</_></rects>
+          19 7 2 6 2.</_></rects>
       <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
           18 6 2 3 -1.</_>
         <_>
-          17 7 2 1 3.</_></rects>
-      <tilted>1</tilted></_>
+          18 7 2 1 3.</_></rects>
+      <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          18 6 3 3 -1.</_>
+          18 6 4 1 -1.</_>
         <_>
-          18 7 3 1 3.</_></rects>
-      <tilted>0</tilted></_>
+          18 6 2 1 2.</_></rects>
+      <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          18 6 4 3 -1.</_>
+          18 6 5 3 -1.</_>
         <_>
-          18 7 4 1 3.</_></rects>
+          18 7 5 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          18 7 1 3 -1.</_>
+          18 6 6 3 -1.</_>
         <_>
-          18 8 1 1 3.</_></rects>
+          18 7 6 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          18 7 3 4 -1.</_>
+          18 7 3 2 -1.</_>
         <_>
-          19 8 1 4 3.</_></rects>
+          19 8 1 2 3.</_></rects>
       <tilted>1</tilted></_>
     <_>
       <rects>
@@ -12002,72 +12590,74 @@
     <_>
       <rects>
         <_>
-          18 7 3 6 -1.</_>
+          18 8 1 3 -1.</_>
         <_>
-          19 8 1 6 3.</_></rects>
-      <tilted>1</tilted></_>
+          18 9 1 1 3.</_></rects>
+      <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          18 7 2 3 -1.</_>
+          18 8 2 3 -1.</_>
         <_>
-          18 8 2 1 3.</_></rects>
+          18 9 2 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          18 7 2 2 -1.</_>
+          18 8 2 2 -1.</_>
         <_>
-          18 7 2 1 2.</_></rects>
+          18 8 2 1 2.</_></rects>
       <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          18 7 3 3 -1.</_>
+          18 9 3 1 -1.</_>
         <_>
-          18 8 3 1 3.</_></rects>
+          19 9 1 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          18 8 2 2 -1.</_>
+          18 9 2 2 -1.</_>
         <_>
-          18 8 2 1 2.</_></rects>
-      <tilted>1</tilted></_>
+          18 9 1 1 2.</_>
+        <_>
+          19 10 1 1 2.</_></rects>
+      <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          18 8 3 9 -1.</_>
+          18 9 3 2 -1.</_>
         <_>
-          15 11 3 3 3.</_></rects>
-      <tilted>1</tilted></_>
+          19 9 1 2 3.</_></rects>
+      <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          18 8 6 5 -1.</_>
+          18 9 2 4 -1.</_>
         <_>
-          21 8 3 5 2.</_></rects>
+          18 11 2 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          18 9 3 1 -1.</_>
+          18 9 6 9 -1.</_>
         <_>
-          19 9 1 1 3.</_></rects>
+          21 9 3 9 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          18 9 6 2 -1.</_>
+          18 9 6 3 -1.</_>
         <_>
-          18 10 6 1 2.</_></rects>
+          18 10 6 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          18 9 6 3 -1.</_>
+          18 10 2 1 -1.</_>
         <_>
-          18 10 6 1 3.</_></rects>
+          19 10 1 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
@@ -12088,81 +12678,79 @@
     <_>
       <rects>
         <_>
-          18 10 3 5 -1.</_>
+          18 10 6 2 -1.</_>
         <_>
-          19 10 1 5 3.</_></rects>
+          18 11 6 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          18 11 4 8 -1.</_>
+          18 11 3 4 -1.</_>
         <_>
-          18 15 4 4 2.</_></rects>
+          19 11 1 4 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          18 12 2 6 -1.</_>
+          18 11 3 13 -1.</_>
         <_>
-          18 15 2 3 2.</_></rects>
+          19 11 1 13 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          18 12 2 8 -1.</_>
+          18 11 2 8 -1.</_>
         <_>
-          18 16 2 4 2.</_></rects>
+          18 15 2 4 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          18 12 6 2 -1.</_>
+          18 11 6 1 -1.</_>
         <_>
-          21 12 3 2 2.</_></rects>
+          21 11 3 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          18 12 6 8 -1.</_>
-        <_>
-          18 12 3 4 2.</_>
+          18 12 6 2 -1.</_>
         <_>
-          21 16 3 4 2.</_></rects>
+          21 12 3 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          18 14 2 4 -1.</_>
+          18 12 3 8 -1.</_>
         <_>
-          19 14 1 4 2.</_></rects>
+          18 16 3 4 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          18 15 1 3 -1.</_>
+          18 13 2 4 -1.</_>
         <_>
-          18 16 1 1 3.</_></rects>
+          18 15 2 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          18 15 4 5 -1.</_>
+          18 14 4 4 -1.</_>
         <_>
-          18 15 2 5 2.</_></rects>
-      <tilted>1</tilted></_>
+          18 16 4 2 2.</_></rects>
+      <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          18 15 3 6 -1.</_>
+          18 15 4 5 -1.</_>
         <_>
-          16 17 3 2 3.</_></rects>
-      <tilted>1</tilted></_>
+          20 15 2 5 2.</_></rects>
+      <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          18 17 2 4 -1.</_>
+          18 16 2 4 -1.</_>
         <_>
-          18 17 1 4 2.</_></rects>
+          18 16 2 2 2.</_></rects>
       <tilted>1</tilted></_>
     <_>
       <rects>
@@ -12188,10 +12776,10 @@
     <_>
       <rects>
         <_>
-          19 0 3 1 -1.</_>
+          19 0 2 3 -1.</_>
         <_>
-          20 0 1 1 3.</_></rects>
-      <tilted>0</tilted></_>
+          19 0 1 3 2.</_></rects>
+      <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
@@ -12202,6 +12790,13 @@
     <_>
       <rects>
         <_>
+          19 2 4 3 -1.</_>
+        <_>
+          20 3 2 3 2.</_></rects>
+      <tilted>1</tilted></_>
+    <_>
+      <rects>
+        <_>
           19 3 3 1 -1.</_>
         <_>
           20 4 1 1 3.</_></rects>
@@ -12209,12 +12804,24 @@
     <_>
       <rects>
         <_>
-          19 4 2 2 -1.</_>
+          19 4 1 2 -1.</_>
+        <_>
+          19 4 1 1 2.</_></rects>
+      <tilted>1</tilted></_>
+    <_>
+      <rects>
+        <_>
+          19 4 3 1 -1.</_>
+        <_>
+          20 5 1 1 3.</_></rects>
+      <tilted>1</tilted></_>
+    <_>
+      <rects>
         <_>
-          19 4 1 1 2.</_>
+          19 4 1 3 -1.</_>
         <_>
-          20 5 1 1 2.</_></rects>
-      <tilted>0</tilted></_>
+          18 5 1 1 3.</_></rects>
+      <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
@@ -12225,9 +12832,9 @@
     <_>
       <rects>
         <_>
-          19 4 2 3 -1.</_>
+          19 4 5 9 -1.</_>
         <_>
-          19 5 2 1 3.</_></rects>
+          19 7 5 3 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
@@ -12246,282 +12853,312 @@
     <_>
       <rects>
         <_>
-          19 6 1 6 -1.</_>
+          19 6 1 3 -1.</_>
         <_>
-          19 6 1 3 2.</_></rects>
+          18 7 1 1 3.</_></rects>
       <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          19 6 3 3 -1.</_>
+          19 6 2 3 -1.</_>
         <_>
-          19 7 3 1 3.</_></rects>
+          19 7 2 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          19 8 3 3 -1.</_>
+          19 6 5 9 -1.</_>
         <_>
-          20 9 1 3 3.</_></rects>
-      <tilted>1</tilted></_>
+          19 9 5 3 3.</_></rects>
+      <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          19 8 4 11 -1.</_>
+          19 7 1 3 -1.</_>
         <_>
-          21 8 2 11 2.</_></rects>
+          19 8 1 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          19 9 2 1 -1.</_>
+          19 7 3 4 -1.</_>
         <_>
-          20 9 1 1 2.</_></rects>
+          20 7 1 4 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          19 10 2 4 -1.</_>
+          19 7 2 4 -1.</_>
+        <_>
+          19 7 2 2 2.</_></rects>
+      <tilted>1</tilted></_>
+    <_>
+      <rects>
+        <_>
+          19 8 1 3 -1.</_>
         <_>
-          19 12 2 2 2.</_></rects>
+          19 9 1 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          19 11 3 13 -1.</_>
+          19 8 3 3 -1.</_>
         <_>
-          20 11 1 13 3.</_></rects>
+          20 8 1 3 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          19 12 4 8 -1.</_>
+          19 9 2 1 -1.</_>
         <_>
-          19 12 2 8 2.</_></rects>
+          20 9 1 1 2.</_></rects>
+      <tilted>0</tilted></_>
+    <_>
+      <rects>
+        <_>
+          19 9 2 2 -1.</_>
+        <_>
+          19 9 2 1 2.</_></rects>
       <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          19 13 3 8 -1.</_>
+          19 10 2 2 -1.</_>
         <_>
-          20 13 1 8 3.</_></rects>
+          19 10 1 1 2.</_>
+        <_>
+          20 11 1 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          19 13 4 7 -1.</_>
+          19 10 3 4 -1.</_>
         <_>
-          19 13 2 7 2.</_></rects>
-      <tilted>1</tilted></_>
+          19 11 3 2 2.</_></rects>
+      <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          19 15 4 5 -1.</_>
+          19 12 4 8 -1.</_>
         <_>
-          20 16 2 5 2.</_></rects>
+          20 13 2 8 2.</_></rects>
       <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          19 17 3 6 -1.</_>
+          19 12 3 10 -1.</_>
+        <_>
+          20 12 1 10 3.</_></rects>
+      <tilted>0</tilted></_>
+    <_>
+      <rects>
+        <_>
+          19 12 3 12 -1.</_>
         <_>
-          20 17 1 6 3.</_></rects>
+          20 12 1 12 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          19 17 3 7 -1.</_>
+          19 13 3 9 -1.</_>
         <_>
-          20 17 1 7 3.</_></rects>
+          20 13 1 9 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          19 17 3 4 -1.</_>
+          19 14 4 6 -1.</_>
         <_>
-          18 18 3 2 2.</_></rects>
+          20 15 2 6 2.</_></rects>
       <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          19 18 1 3 -1.</_>
+          19 15 3 6 -1.</_>
         <_>
-          18 19 1 1 3.</_></rects>
+          20 16 1 6 3.</_></rects>
       <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          19 19 1 3 -1.</_>
+          19 17 1 3 -1.</_>
         <_>
-          18 20 1 1 3.</_></rects>
+          18 18 1 1 3.</_></rects>
       <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          20 0 2 2 -1.</_>
+          19 18 1 3 -1.</_>
         <_>
-          20 0 1 2 2.</_></rects>
+          18 19 1 1 3.</_></rects>
       <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          20 3 1 4 -1.</_>
+          19 19 1 3 -1.</_>
         <_>
-          19 4 1 2 2.</_></rects>
+          18 20 1 1 3.</_></rects>
       <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          20 4 3 1 -1.</_>
+          19 19 1 4 -1.</_>
         <_>
-          21 5 1 1 3.</_></rects>
+          18 20 1 2 2.</_></rects>
       <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          20 4 3 2 -1.</_>
+          19 20 1 3 -1.</_>
         <_>
-          21 5 1 2 3.</_></rects>
+          18 21 1 1 3.</_></rects>
       <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          20 4 2 3 -1.</_>
+          19 21 5 3 -1.</_>
         <_>
-          20 5 2 1 3.</_></rects>
+          19 22 5 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          20 5 3 1 -1.</_>
+          20 0 4 4 -1.</_>
         <_>
-          21 6 1 1 3.</_></rects>
+          19 1 4 2 2.</_></rects>
       <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          20 8 1 4 -1.</_>
+          20 3 3 1 -1.</_>
         <_>
-          20 8 1 2 2.</_></rects>
+          21 4 1 1 3.</_></rects>
       <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          20 8 4 3 -1.</_>
+          20 3 3 2 -1.</_>
         <_>
-          21 9 2 3 2.</_></rects>
+          21 4 1 2 3.</_></rects>
       <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          20 8 3 4 -1.</_>
+          20 4 1 3 -1.</_>
         <_>
-          21 9 1 4 3.</_></rects>
-      <tilted>1</tilted></_>
+          20 5 1 1 3.</_></rects>
+      <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          20 8 4 4 -1.</_>
+          20 4 3 1 -1.</_>
         <_>
-          21 9 2 4 2.</_></rects>
+          21 5 1 1 3.</_></rects>
       <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          20 8 4 6 -1.</_>
+          20 4 3 2 -1.</_>
         <_>
-          20 10 4 2 3.</_></rects>
-      <tilted>0</tilted></_>
+          21 5 1 2 3.</_></rects>
+      <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          20 9 4 10 -1.</_>
+          20 5 3 1 -1.</_>
         <_>
-          20 9 2 10 2.</_></rects>
+          21 6 1 1 3.</_></rects>
       <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          20 9 4 3 -1.</_>
+          20 6 4 3 -1.</_>
+        <_>
+          20 7 4 1 3.</_></rects>
+      <tilted>0</tilted></_>
+    <_>
+      <rects>
+        <_>
+          20 8 3 2 -1.</_>
         <_>
-          19 10 4 1 3.</_></rects>
+          21 9 1 2 3.</_></rects>
       <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          20 10 1 3 -1.</_>
+          20 8 3 3 -1.</_>
         <_>
-          19 11 1 1 3.</_></rects>
+          21 9 1 3 3.</_></rects>
       <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          20 10 4 3 -1.</_>
+          20 9 3 2 -1.</_>
         <_>
-          21 11 2 3 2.</_></rects>
+          21 10 1 2 3.</_></rects>
       <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          20 10 3 10 -1.</_>
+          20 9 4 10 -1.</_>
         <_>
-          21 10 1 10 3.</_></rects>
-      <tilted>0</tilted></_>
+          20 9 2 10 2.</_></rects>
+      <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          20 12 4 8 -1.</_>
+          20 10 1 3 -1.</_>
         <_>
-          21 13 2 8 2.</_></rects>
+          19 11 1 1 3.</_></rects>
       <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          20 13 3 8 -1.</_>
+          20 10 2 2 -1.</_>
         <_>
-          21 13 1 8 3.</_></rects>
-      <tilted>0</tilted></_>
+          20 10 2 1 2.</_></rects>
+      <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          20 15 4 5 -1.</_>
+          20 11 4 9 -1.</_>
         <_>
-          21 16 2 5 2.</_></rects>
+          20 11 2 9 2.</_></rects>
       <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          20 15 4 4 -1.</_>
+          20 14 4 6 -1.</_>
         <_>
-          22 15 2 4 2.</_></rects>
-      <tilted>0</tilted></_>
+          21 15 2 6 2.</_></rects>
+      <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          20 17 3 5 -1.</_>
+          20 14 2 7 -1.</_>
         <_>
-          21 17 1 5 3.</_></rects>
-      <tilted>0</tilted></_>
+          20 14 1 7 2.</_></rects>
+      <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          20 18 3 1 -1.</_>
+          20 15 3 4 -1.</_>
         <_>
-          21 18 1 1 3.</_></rects>
-      <tilted>0</tilted></_>
+          19 16 3 2 2.</_></rects>
+      <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          20 18 1 3 -1.</_>
+          20 16 4 4 -1.</_>
         <_>
-          19 19 1 1 3.</_></rects>
+          21 17 2 4 2.</_></rects>
       <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          20 19 3 4 -1.</_>
+          20 17 3 5 -1.</_>
         <_>
-          21 19 1 4 3.</_></rects>
+          21 17 1 5 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
@@ -12533,37 +13170,37 @@
     <_>
       <rects>
         <_>
-          21 2 3 16 -1.</_>
+          20 20 4 3 -1.</_>
         <_>
-          21 2 3 8 2.</_></rects>
-      <tilted>1</tilted></_>
+          20 21 4 1 3.</_></rects>
+      <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          21 3 3 2 -1.</_>
+          21 1 2 16 -1.</_>
         <_>
-          22 4 1 2 3.</_></rects>
+          21 1 2 8 2.</_></rects>
       <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          21 8 3 3 -1.</_>
+          21 1 3 4 -1.</_>
         <_>
-          22 9 1 3 3.</_></rects>
-      <tilted>1</tilted></_>
+          21 2 3 2 2.</_></rects>
+      <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          21 8 3 5 -1.</_>
+          21 3 3 2 -1.</_>
         <_>
-          22 9 1 5 3.</_></rects>
+          22 4 1 2 3.</_></rects>
       <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          21 9 3 3 -1.</_>
+          21 4 3 3 -1.</_>
         <_>
-          20 10 3 1 3.</_></rects>
+          22 5 1 3 3.</_></rects>
       <tilted>1</tilted></_>
     <_>
       <rects>
@@ -12575,58 +13212,65 @@
     <_>
       <rects>
         <_>
-          21 10 2 5 -1.</_>
+          21 10 2 2 -1.</_>
         <_>
-          21 10 1 5 2.</_></rects>
+          21 10 1 2 2.</_></rects>
       <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          21 10 3 3 -1.</_>
+          21 10 3 4 -1.</_>
         <_>
-          21 11 3 1 3.</_></rects>
+          21 11 3 2 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          21 11 1 3 -1.</_>
+          21 11 1 2 -1.</_>
+        <_>
+          21 11 1 1 2.</_></rects>
+      <tilted>1</tilted></_>
+    <_>
+      <rects>
+        <_>
+          21 15 2 3 -1.</_>
         <_>
-          20 12 1 1 3.</_></rects>
+          20 16 2 1 3.</_></rects>
       <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          21 15 1 3 -1.</_>
+          21 16 1 3 -1.</_>
         <_>
-          20 16 1 1 3.</_></rects>
+          20 17 1 1 3.</_></rects>
       <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          21 15 3 6 -1.</_>
+          21 16 3 8 -1.</_>
         <_>
-          22 15 1 6 3.</_></rects>
+          22 16 1 8 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          21 16 1 3 -1.</_>
+          21 16 2 3 -1.</_>
         <_>
-          20 17 1 1 3.</_></rects>
+          20 17 2 1 3.</_></rects>
       <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          21 16 3 7 -1.</_>
+          21 17 1 3 -1.</_>
         <_>
-          22 16 1 7 3.</_></rects>
-      <tilted>0</tilted></_>
+          20 18 1 1 3.</_></rects>
+      <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          21 16 3 8 -1.</_>
+          21 17 3 7 -1.</_>
         <_>
-          22 16 1 8 3.</_></rects>
+          22 17 1 7 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
@@ -12638,100 +13282,100 @@
     <_>
       <rects>
         <_>
-          21 22 3 2 -1.</_>
+          22 1 2 4 -1.</_>
         <_>
-          22 22 1 2 3.</_></rects>
-      <tilted>0</tilted></_>
+          21 2 2 2 2.</_></rects>
+      <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          22 2 1 18 -1.</_>
+          22 2 1 16 -1.</_>
         <_>
-          22 2 1 9 2.</_></rects>
+          22 2 1 8 2.</_></rects>
       <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          22 10 1 3 -1.</_>
+          22 9 2 4 -1.</_>
         <_>
-          21 11 1 1 3.</_></rects>
+          22 9 1 4 2.</_></rects>
       <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          22 10 2 3 -1.</_>
+          22 10 1 3 -1.</_>
         <_>
-          21 11 2 1 3.</_></rects>
+          21 11 1 1 3.</_></rects>
       <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          22 11 1 3 -1.</_>
+          22 10 2 7 -1.</_>
         <_>
-          21 12 1 1 3.</_></rects>
+          22 10 1 7 2.</_></rects>
       <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          22 11 2 6 -1.</_>
+          22 10 2 3 -1.</_>
         <_>
-          22 11 1 6 2.</_></rects>
-      <tilted>1</tilted></_>
+          22 11 2 1 3.</_></rects>
+      <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          22 11 2 9 -1.</_>
+          22 10 2 3 -1.</_>
         <_>
-          22 11 1 9 2.</_></rects>
+          21 11 2 1 3.</_></rects>
       <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          22 12 2 3 -1.</_>
+          22 11 1 3 -1.</_>
         <_>
-          21 13 2 1 3.</_></rects>
+          21 12 1 1 3.</_></rects>
       <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          22 13 2 9 -1.</_>
+          22 12 1 3 -1.</_>
         <_>
-          22 13 1 9 2.</_></rects>
+          21 13 1 1 3.</_></rects>
       <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          22 13 2 8 -1.</_>
+          22 13 1 3 -1.</_>
         <_>
-          20 15 2 4 2.</_></rects>
+          21 14 1 1 3.</_></rects>
       <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          22 17 1 4 -1.</_>
+          22 16 1 3 -1.</_>
         <_>
-          21 18 1 2 2.</_></rects>
+          21 17 1 1 3.</_></rects>
       <tilted>1</tilted></_>
     <_>
       <rects>
         <_>
-          22 18 1 4 -1.</_>
+          23 7 1 3 -1.</_>
         <_>
-          21 19 1 2 2.</_></rects>
-      <tilted>1</tilted></_>
+          23 8 1 1 3.</_></rects>
+      <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          23 9 1 3 -1.</_>
+          23 10 1 3 -1.</_>
         <_>
-          23 10 1 1 3.</_></rects>
+          23 11 1 1 3.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
         <_>
-          23 10 1 3 -1.</_>
+          23 11 1 2 -1.</_>
         <_>
-          23 11 1 1 3.</_></rects>
+          23 12 1 1 2.</_></rects>
       <tilted>0</tilted></_>
     <_>
       <rects>
@@ -12743,8 +13387,8 @@
     <_>
       <rects>
         <_>
-          23 12 1 3 -1.</_>
+          23 15 1 4 -1.</_>
         <_>
-          22 13 1 1 3.</_></rects>
+          22 16 1 2 2.</_></rects>
       <tilted>1</tilted></_></features></cascade>
 </opencv_storage>
diff --git a/data/haarcascades_cuda/haarcascade_upperbody.xml b/data/haarcascades_cuda/haarcascade_upperbody.xml
index 98452e2..f22f8e6 100644
--- a/data/haarcascades_cuda/haarcascade_upperbody.xml
+++ b/data/haarcascades_cuda/haarcascade_upperbody.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0"?>
-<!-
+<!--
    22x18 upperbody detector (see the detailed description below).
 
 //////////////////////////////////////////////////////////////////////////
diff --git a/data/lbpcascades/lbpcascade_frontalcatface.xml b/data/lbpcascades/lbpcascade_frontalcatface.xml
index 4d8d829..3b4b1bf 100644
--- a/data/lbpcascades/lbpcascade_frontalcatface.xml
+++ b/data/lbpcascades/lbpcascade_frontalcatface.xml
@@ -21,15 +21,20 @@
 
  KNOWN LIMITATIONS:
 
- Sometimes, the detector mistakenly thinks that a human face is a cat face. In
- situations where either a human or a cat might be encountered, use both a
- human face detector and a cat face detector. Then, if a detected human face
- and a detected cat face intersect, reject the cat face.
-
  An upright subject is assumed. In situations where the cat's face might be
  sideways or upside down (e.g. the cat is rolling over), try various rotations
  of the input image.
 
+ CHANGELOG:
+
+ 2016-08-06: Re-trained with more negative samples and more stages. False
+   positives are much rarer now. If you tailored your code for the cascade's
+   previous version, now you should re-adjust the arguments of
+   CascadeClassifier::detectMultiScale. For example, decrease the value of the
+   minNeighbors argument. You do not need to use a human face detector to
+   cross-check the positives anymore.
+ 2014-04-25: First release (at https://bitbucket.org/Joe_Howse/angora-blue)
+
  //////////////////////////////////////////////////////////////////////////
  | Contributors License Agreement
  | IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
@@ -38,7 +43,7 @@
  |   If you do not agree to this license, do not download, install,
  |   copy or use the software.
  |
- | Copyright (c) 2014, Joseph Howse (Nummist Media Corporation Limited,
+ | Copyright (c) 2014-2016, Joseph Howse (Nummist Media Corporation Limited,
  | Halifax, Nova Scotia, Canada). All rights reserved.
  |
  | Redistribution and use in source and binary forms, with or without
@@ -76,7 +81,7 @@
   <width>24</width>
   <stageParams>
     <boostType>GAB</boostType>
-    <minHitRate>9.9900001287460327e-01</minHitRate>
+    <minHitRate>9.9500000476837158e-01</minHitRate>
     <maxFalseAlarm>5.0000000000000000e-01</maxFalseAlarm>
     <weightTrimRate>9.4999999999999996e-01</weightTrimRate>
     <maxDepth>1</maxDepth>
@@ -84,2400 +89,2737 @@
   <featureParams>
     <maxCatCount>256</maxCatCount>
     <featSize>1</featSize></featureParams>
-  <stageNum>15</stageNum>
+  <stageNum>20</stageNum>
   <stages>
     <!-- stage 0 -->
     <_>
+      <maxWeakCount>9</maxWeakCount>
+      <stageThreshold>-1.5429834127426147e+00</stageThreshold>
+      <weakClassifiers>
+        <_>
+          <internalNodes>
+            0 -1 104 1599056782 -3801105 836281000 -134348801 -10616883
+            1430585292 -33555461 -170000676</internalNodes>
+          <leafValues>
+            -5.4490309953689575e-01 5.6734609603881836e-01</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 294 204479732 1065172189 790634493 1060117940
+            -289603585 -1075077121 -1092617217 -1073741825</internalNodes>
+          <leafValues>
+            -5.6601214408874512e-01 3.9540845155715942e-01</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 71 -547356836 1566019389 -77856769 -551952545
+            -539172900 -10560035 -52600869 994540299</internalNodes>
+          <leafValues>
+            -4.4183051586151123e-01 4.4477555155754089e-01</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 148 -620691696 486545936 825237297 521165584 436288155
+            536422827 1026760619 523727735</internalNodes>
+          <leafValues>
+            -4.9225500226020813e-01 3.4415841102600098e-01</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 8 2065692655 -539494441 1911927792 -2108480 455801071
+            67664201 -1084369169 1926622918</internalNodes>
+          <leafValues>
+            -4.0782809257507324e-01 3.7964683771133423e-01</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 343 791362869 -1075233419 -573079553 -33596427
+            -1610973955 -262147 1026375359 -1107337903</internalNodes>
+          <leafValues>
+            -4.4104734063148499e-01 3.3767992258071899e-01</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 247 -770966446 -10095278 -717226475 1462226875
+            1326402382 -70331239 1175244766 1326179231</internalNodes>
+          <leafValues>
+            -3.6573803424835205e-01 4.1576108336448669e-01</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 137 -1898553987 -42050596 -1074372609 -38388009
+            -50700804 -268436101 -352819484 -1163887504</internalNodes>
+          <leafValues>
+            -4.2117568850517273e-01 3.3924096822738647e-01</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 188 -321131994 712703979 -1157694222 586350586
+            1085998084 1281738876 -403229068 -925369374</internalNodes>
+          <leafValues>
+            -5.1358664035797119e-01 2.6718941330909729e-01</leafValues></_></weakClassifiers></_>
+    <!-- stage 1 -->
+    <_>
       <maxWeakCount>12</maxWeakCount>
-      <stageThreshold>-1.7687875032424927e+00</stageThreshold>
+      <stageThreshold>-1.2918862104415894e+00</stageThreshold>
       <weakClassifiers>
         <_>
           <internalNodes>
-            0 -1 102 391095182 -138018897 -1311235414 -134348801
-            -10637363 1363472332 -168428565 -170000676</internalNodes>
+            0 -1 54 1397073902 2013244398 -177098006 -201331986
+            2002780074 1006612398 -1110 -67132758</internalNodes>
           <leafValues>
-            -3.8902848958969116e-01 7.1630239486694336e-01</leafValues></_>
+            -4.0280899405479431e-01 5.0070983171463013e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 266 135269620 1065172957 761273949 1068766640
-            -285409281 -1075109889 -1073808385 -1073741825</internalNodes>
+            0 -1 80 -16823041 -41857 205806847 509368831 -1431699272
+            -130942 167828670 -635806469</internalNodes>
           <leafValues>
-            -5.0905084609985352e-01 4.4736129045486450e-01</leafValues></_>
+            -3.7250527739524841e-01 4.8033073544502258e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 248 -882714626 -11077637 -2105857 -5255203 1594642431
-            -536896039 -540028929 266295295</internalNodes>
+            0 -1 228 -866136833 419433907 182275839 536546047 201854172
+            28121467 214781439 268402175</internalNodes>
           <leafValues>
-            -4.0175846219062805e-01 4.7943404316902161e-01</leafValues></_>
+            -4.5891678333282471e-01 3.6297130584716797e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 5 -617089137 -547883529 1911919584 -2239534 1530067199
-            1140914475 -1092824836 1892022980</internalNodes>
+            0 -1 270 -1561337117 -1426066718 -1010829325 -38805262
+            1202713555 -324545872 1441789815 -134233869</internalNodes>
           <leafValues>
-            -4.2830348014831543e-01 4.3316614627838135e-01</leafValues></_>
+            -3.5680472850799561e-01 4.3237748742103577e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 103 251265151 2145342812 1501453661 1046368729
-            -1975908196 -1105592134 -1897996802 -88470342</internalNodes>
+            0 -1 259 -597278700 268435458 -550058223 855800610 149425288
+            775302951 -118555396 -272630117</internalNodes>
           <leafValues>
-            -3.9837184548377991e-01 4.3966090679168701e-01</leafValues></_>
+            -4.8106637597084045e-01 2.9466137290000916e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 249 653255651 -1427184958 -736368649 -1052429
-            1722766161 -455896464 1155912595 -167811855</internalNodes>
+            0 -1 327 -1111901448 1023973552 253008120 500562168 -5242881
+            -1156710915 1340989437 -536879105</internalNodes>
           <leafValues>
-            -3.9872139692306519e-01 3.9076396822929382e-01</leafValues></_>
+            -3.2977777719497681e-01 4.3013024330139160e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 98 -147601648 452990736 522407185 1599686417 1169689768
-            407507112 -1762308210 1599803223</internalNodes>
+            0 -1 77 -537179120 521143296 -21635309 2134891643 1350441722
+            -632386648 -1129300294 -263173</internalNodes>
           <leafValues>
-            -4.5285862684249878e-01 3.3382070064544678e-01</leafValues></_>
+            -3.6992338299751282e-01 3.5658127069473267e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 300 805836816 1351616140 -1629160611 -1696006160
-            2133143824 -1418430667 -1093085224 -91160647</internalNodes>
+            0 -1 164 -1362153945 741281595 -1496274305 720813755
+            2088729719 2146431455 -251775916 -185278474</internalNodes>
           <leafValues>
-            -5.1765918731689453e-01 2.8637027740478516e-01</leafValues></_>
+            -4.7965702414512634e-01 2.5329035520553589e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 206 771753813 1072999924 -637907073 1072594908
-            1022435188 -1073874507 -1076936836 -1141628556</internalNodes>
+            0 -1 129 2009068661 286465811 -1714126495 320044919
+            -321273376 1216088341 -187041632 276299767</internalNodes>
           <leafValues>
-            -4.5144259929656982e-01 3.3236411213874817e-01</leafValues></_>
+            -4.0860968828201294e-01 3.0382931232452393e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 188 -1493176369 712675187 -55120016 -1570308126
-            1845183255 -34048033 -1090533504 -386469418</internalNodes>
+            0 -1 222 70785877 1041800816 -75508353 1071923196 2113290236
+            -1074941012 -1075086339 -1351740304</internalNodes>
           <leafValues>
-            -3.6836385726928711e-01 4.1354060173034668e-01</leafValues></_>
+            -3.9227196574211121e-01 3.2063353061676025e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 84 1876927247 -103435857 821334050 -202379046
-            -607136374 354198146 1878387370 -455740474</internalNodes>
+            0 -1 52 -733166882 -44852481 -145568001 -15114497 -924915460
+            -33678721 -88592641 1063732851</internalNodes>
           <leafValues>
-            -3.8681995868682861e-01 3.9221677184104919e-01</leafValues></_>
+            -3.7047380208969116e-01 3.1812894344329834e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 85 70388767 580795691 -83467 1051082410 -287417474
-            -1076176594 -57439237 -1430597793</internalNodes>
+            0 -1 32 -2097737981 1148364791 -1210636301 -1330585805
+            123014973 2113833983 -32925 -236603423</internalNodes>
           <leafValues>
-            -4.1789534687995911e-01 3.5533955693244934e-01</leafValues></_></weakClassifiers></_>
-    <!-- stage 1 -->
+            -4.2788907885551453e-01 2.8403493762016296e-01</leafValues></_></weakClassifiers></_>
+    <!-- stage 2 -->
     <_>
       <maxWeakCount>13</maxWeakCount>
-      <stageThreshold>-1.3504111766815186e+00</stageThreshold>
+      <stageThreshold>-1.3729060888290405e+00</stageThreshold>
       <weakClassifiers>
         <_>
           <internalNodes>
-            0 -1 52 -582353192 453631753 -1189740547 490856223
-            -1064974120 -1927684129 1413925631 151519071</internalNodes>
+            0 -1 316 1058750395 -1080312336 -1078198785 -3 -1145389058
+            -1078318408 -1079328769 -1077958496</internalNodes>
           <leafValues>
-            -2.2373910248279572e-01 6.7752838134765625e-01</leafValues></_>
+            -2.5900188088417053e-01 6.1616760492324829e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 213 -576729857 454575443 -1996943617 536547583
-            206047452 -1088734277 210521343 264241151</internalNodes>
+            0 -1 151 -201887221 1915747883 -218104097 3145727 -92571030
+            -117772190 -88408321 -1566377217</internalNodes>
           <leafValues>
-            -3.7819463014602661e-01 5.2549731731414795e-01</leafValues></_>
+            -3.7379077076911926e-01 4.5426961779594421e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 275 -249562832 -1181502479 -174589519 -1112427119
-            -1189167448 -1081345300 -1534158677 -1431310669</internalNodes>
+            0 -1 96 386868111 1607319551 2145227774 -81921 2136981469
+            1564794828 -3277827 -171573810</internalNodes>
           <leafValues>
-            -3.6486798524856567e-01 4.7923672199249268e-01</leafValues></_>
+            -3.5450288653373718e-01 4.5893719792366028e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 125 -1405482952 -15924365 -1147527681 -10535319
-            -1345282310 -1103133 698354938 -1073790989</internalNodes>
+            0 -1 2 -551362576 -73215120 -364212554 -11998256 71434372
+            -1616176195 209715400 -840182021</internalNodes>
           <leafValues>
-            -4.9668836593627930e-01 3.3489266037940979e-01</leafValues></_>
+            -4.2596518993377686e-01 3.3351564407348633e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 82 2135911182 -553255561 -1835761112 -744206088
-            1443360719 1427151980 -208273409 -136971281</internalNodes>
+            0 -1 82 247336735 586821439 -134217729 1056866239
+            -1090551809 -9217 -33628162 -1430597650</internalNodes>
           <leafValues>
-            -4.9673599004745483e-01 2.9186215996742249e-01</leafValues></_>
+            -3.8904032111167908e-01 3.6951214075088501e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 64 750650461 -1141224741 228524031 1066678329
-            -392530945 -1119829 -389633282 -1909948481</internalNodes>
+            0 -1 249 -672137222 -74448921 -21891587 -136323721
+            1322253791 -822281795 1565482863 1465906911</internalNodes>
           <leafValues>
-            -4.4474920630455017e-01 3.3087861537933350e-01</leafValues></_>
+            -3.2322180271148682e-01 4.2339357733726501e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 80 -8364 961050640 -337450 -170150085 -4518372
-            1480613384 -270925857 -203948193</internalNodes>
+            0 -1 319 -1347239947 1069203248 -2097163 -1610678308
+            -1879052295 -268437506 -1934079492 -1935110672</internalNodes>
           <leafValues>
-            -3.6774283647537231e-01 3.8125535845756531e-01</leafValues></_>
+            -4.0132158994674683e-01 3.3234956860542297e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 304 -1279559723 488853328 894958865 523048208
-            -1111801861 -1113625095 -1410843652 -1615113099</internalNodes>
+            0 -1 37 -1068709308 -1102522849 1644484342 -268379409
+            1443710532 -11090094 -213845121 -12059649</internalNodes>
           <leafValues>
-            -3.8107365369796753e-01 3.7617510557174683e-01</leafValues></_>
+            -4.2390203475952148e-01 2.9791557788848877e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 27 -1038891372 866262272 -1124866827 -7307515 2556056
-            -1947784189 145625549 -537934001</internalNodes>
+            0 -1 202 -285495441 -1427182081 -290198603 -527241618
+            -419467196 -855709209 -268509632 -922957372</internalNodes>
           <leafValues>
-            -3.3774635195732117e-01 4.1467228531837463e-01</leafValues></_>
+            -3.6988914012908936e-01 3.4229919314384460e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 214 1313841735 674152170 -1368464720 -1597048870
-            759309825 -295860621 1709856085 -587729545</internalNodes>
+            0 -1 43 -18449 1073711035 -1319386462 -203620626 2070804431
+            854521820 -134545716 1442310948</internalNodes>
           <leafValues>
-            -4.4100293517112732e-01 3.1954705715179443e-01</leafValues></_>
+            -4.0420171618461609e-01 3.0070811510086060e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 310 -1432731787 -1219055176 -42533035 -1126253868
-            -2038280772 -55715078 -2000923144 -1936931520</internalNodes>
+            0 -1 205 225460085 1069170549 -1213441 -268681410 536639980
+            -272859906 -1344397956 -1090621548</internalNodes>
           <leafValues>
-            -4.3541839718818665e-01 3.1401738524436951e-01</leafValues></_>
+            -4.0233635902404785e-01 3.1345960497856140e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 180 232552309 -537305729 -3104297 -67617446 -1211085572
-            -20391173 -1968567044 -1392871087</internalNodes>
+            0 -1 65 1347781250 -252185797 18161683 335127199 -918162925
+            -68564231 1079360443 1080539939</internalNodes>
           <leafValues>
-            -3.7881413102149963e-01 3.5767501592636108e-01</leafValues></_>
+            -4.4784346222877502e-01 2.6452672481536865e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 46 -36984309 904630143 823414970 -188744006 1900770270
-            1399711367 -473188378 1969748707</internalNodes>
+            0 -1 40 138021973 914534260 -1628242049 179970033 2088664692
+            -279028579 -285573707 -1431115148</internalNodes>
           <leafValues>
-            -4.0620720386505127e-01 3.2759186625480652e-01</leafValues></_></weakClassifiers></_>
-    <!-- stage 2 -->
+            -4.6739324927330017e-01 2.6337191462516785e-01</leafValues></_></weakClassifiers></_>
+    <!-- stage 3 -->
     <_>
-      <maxWeakCount>19</maxWeakCount>
-      <stageThreshold>-1.3998974561691284e+00</stageThreshold>
+      <maxWeakCount>15</maxWeakCount>
+      <stageThreshold>-1.3434195518493652e+00</stageThreshold>
       <weakClassifiers>
         <_>
           <internalNodes>
-            0 -1 128 -236980233 16777207 -520752904 15793139 -168428203
-            1979187191 -33554947 -251920389</internalNodes>
+            0 -1 312 1594941436 -539099137 1597374397 2136866813
+            2133434303 -2359299 -180801 532360959</internalNodes>
           <leafValues>
-            -1.7629407346248627e-01 6.5313565731048584e-01</leafValues></_>
+            -3.9849624037742615e-01 4.3070858716964722e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 230 -871825409 -580752385 -713042433 -540061189
-            1549092351 -587761733 1607687679 1577014783</internalNodes>
+            0 -1 107 -1687737718 -136351793 819208354 -201466130
+            -304104530 1430290438 -74187782 -254479670</internalNodes>
           <leafValues>
-            -3.1553706526756287e-01 4.9262753129005432e-01</leafValues></_>
+            -5.2847045660018921e-01 2.9759022593498230e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 79 -545306406 -547422721 474111600 -570360321 -507816
-            1599364180 -11379845 -12845089</internalNodes>
+            0 -1 106 1593187583 -57860 494558719 1568543997 -1430627078
+            -17168194 -22085633 -17167126</internalNodes>
           <leafValues>
-            -3.5872745513916016e-01 4.0607807040214539e-01</leafValues></_>
+            -3.2349127531051636e-01 4.4297724962234497e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 123 -252337502 -658267397 7348400 821935103 1377280435
-            47000107 -169347101 939467707</internalNodes>
+            0 -1 233 -289936401 719515647 1894970098 -67961857
+            1429694295 1079178739 1417049205 -235416077</internalNodes>
           <leafValues>
-            -5.1070415973663330e-01 2.8583043813705444e-01</leafValues></_>
+            -4.0733993053436279e-01 3.3705353736877441e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 45 645859107 708031411 -168346241 -1330581136 81734679
-            783767351 -45193 -34341517</internalNodes>
+            0 -1 338 -804225008 -1130847023 -1644863659 -626985985
+            -1151011816 -67830287 -1090585640 -72811781</internalNodes>
           <leafValues>
-            -4.4308465719223022e-01 2.9009637236595154e-01</leafValues></_>
+            -4.0251138806343079e-01 3.1045806407928467e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 241 -154214396 268437506 -680474855 864167714 684199820
-            204876327 -52122180 -262209</internalNodes>
+            0 -1 30 1325133735 -235668011 -4196493 -1297076240 37159747
+            -1078198341 -5247041 -17338573</internalNodes>
           <leafValues>
-            -4.1140288114547729e-01 2.9478433728218079e-01</leafValues></_>
+            -3.5516351461410522e-01 3.3867400884628296e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 265 -1365070662 -380938 -1139629826 -35735556 49021040
-            1020949984 219416278 -293</internalNodes>
+            0 -1 61 1563885570 990015234 1715350066 -1612515566
+            2121997646 -562425 -1460130098 -2</internalNodes>
           <leafValues>
-            -3.9993125200271606e-01 2.9704034328460693e-01</leafValues></_>
+            -3.6495906114578247e-01 3.1801441311836243e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 295 217001265 -1346379851 1862205053 -1342447907
-            30277700 -1360008036 -1988349004 -287317952</internalNodes>
+            0 -1 35 -486805761 -30385 -164631585 -67393017 -662962177
+            -269484302 -302258246 -298365693</internalNodes>
           <leafValues>
-            -3.9956006407737732e-01 2.8518736362457275e-01</leafValues></_>
+            -2.5626540184020996e-01 4.6705508232116699e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 72 290390927 534606847 534719466 -100668033 1607942091
-            1499327373 -101712435 -187324532</internalNodes>
+            0 -1 242 582106997 -1375949832 -2097155 -1611859716
+            -1078984707 -71372812 -1174471336 -1364685600</internalNodes>
           <leafValues>
-            -3.0478826165199280e-01 3.7477290630340576e-01</leafValues></_>
+            -3.4055373072624207e-01 3.2303497195243835e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 136 -285336459 2110655990 -2013274145 2143051605
-            -1124443700 -9506961 -604210584 -1161806512</internalNodes>
+            0 -1 213 1857005319 651918339 -1159732176 -294652937
+            2146914899 1349774535 -2097404 -50856010</internalNodes>
           <leafValues>
-            -4.0837058424949646e-01 2.7444043755531311e-01</leafValues></_>
+            -3.3969157934188843e-01 3.1695431470870972e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 55 -62093618 -581362746 -141373441 -10940834 -840543755
-            -638181765 1859448799 996361303</internalNodes>
+            0 -1 292 -1364537606 -1925122 -36259590 -102826180
+            -2098986320 243153064 -1515278601 -137380105</internalNodes>
           <leafValues>
-            -3.7610772252082825e-01 3.0961802601814270e-01</leafValues></_>
+            -3.3688172698020935e-01 3.2412472367286682e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 110 -404233212 134685696 -2016460609 -1379932177
-            -540018825 -2163729 806790835 607646519</internalNodes>
+            0 -1 211 -824758745 174632251 -469831961 -1428162053
+            1157038145 213857255 -186772236 -185273869</internalNodes>
           <leafValues>
-            -4.3601146340370178e-01 2.5886246562004089e-01</leafValues></_>
+            -4.0657189488410950e-01 2.5756362080574036e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 288 -907025790 1474249959 -806494209 -10763 -283444824
-            -364917254 -828244229 -1968201565</internalNodes>
+            0 -1 110 -16884641 -36276290 -160105525 -659501198 -652220
+            -295070 -2176776 -15009184</internalNodes>
           <leafValues>
-            -2.6032009720802307e-01 4.3652611970901489e-01</leafValues></_>
+            -2.8538039326667786e-01 3.6766386032104492e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 229 -18370769 -757680277 788372142 -2072580242
-            -273678553 745365463 -134222107 -229310606</internalNodes>
+            0 -1 90 -792331710 -1069030682 13697279 -2057320217
+            -175702061 -60841468 -222841601 1783605027</internalNodes>
           <leafValues>
-            -3.0938607454299927e-01 3.5719990730285645e-01</leafValues></_>
+            -3.4717887639999390e-01 2.9574045538902283e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 14 -1603048865 578088863 -390533121 140676846
-            -495489499 -42082971 -4194586 -26017865</internalNodes>
+            0 -1 234 749378744 935105716 -1397302147 1001388025
+            255328920 -1799926224 -1397966593 -1074790917</internalNodes>
           <leafValues>
-            -3.1977957487106323e-01 3.4310647845268250e-01</leafValues></_>
+            -3.7167704105377197e-01 2.8397652506828308e-01</leafValues></_></weakClassifiers></_>
+    <!-- stage 4 -->
+    <_>
+      <maxWeakCount>15</maxWeakCount>
+      <stageThreshold>-1.2288014888763428e+00</stageThreshold>
+      <weakClassifiers>
         <_>
           <internalNodes>
-            0 -1 249 1643111394 -1211240000 1172894578 -641010466
-            1181712375 -2068614428 1433624934 -671119917</internalNodes>
+            0 -1 271 -290784257 -542572545 -167807627 -2061 209652223
+            -1093158913 1157580031 1173837303</internalNodes>
           <leafValues>
-            -3.3919364213943481e-01 3.4504517912864685e-01</leafValues></_>
+            -3.3414435386657715e-01 4.7178736329078674e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 164 1606136599 587595301 -21521312 1079307891 62912316
-            2136471350 -285346140 -201854089</internalNodes>
+            0 -1 317 -2098253 -1146358896 1476391185 -704777743
+            -1140850693 -1415582030 -7696 -640683845</internalNodes>
           <leafValues>
-            -3.1577944755554199e-01 3.4307131171226501e-01</leafValues></_>
+            -2.5055918097496033e-01 5.2570897340774536e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 152 785525471 1052180799 1060533999 2120755670
-            1316621908 -270833354 -73736274 -361439920</internalNodes>
+            0 -1 132 -100663299 272629759 -789195536 544341979
+            -167781039 1966601201 -515 -234881025</internalNodes>
           <leafValues>
-            -3.4840318560600281e-01 3.2924604415893555e-01</leafValues></_>
+            -3.5798946022987366e-01 3.6239877343177795e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 47 1824524292 1056221828 -268623876 -1615033532
-            -2092452655 144493033 502744181 -571159100</internalNodes>
+            0 -1 48 -2105507696 -1366759952 -1126500363 -570630416
+            -317934356 -33619969 -36643332 -2304812</internalNodes>
           <leafValues>
-            -4.5537719130516052e-01 2.4885603785514832e-01</leafValues></_></weakClassifiers></_>
-    <!-- stage 3 -->
+            -3.9822307229042053e-01 2.8633421659469604e-01</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 74 -792677742 -101713185 7352369 298695163 -1761297729
+            6029312 -25184257 1608465947</internalNodes>
+          <leafValues>
+            -4.2175698280334473e-01 2.4120111763477325e-01</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 223 169615221 -1174487300 -281051137 -1090642276
+            -4703305 -33558539 1073692156 -1359214592</internalNodes>
+          <leafValues>
+            -3.8317176699638367e-01 2.8932854533195496e-01</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 75 -102806438 -9703431 1045568568 503377755 -547864488
+            1534349686 1867669466 -82706561</internalNodes>
+          <leafValues>
+            -3.8330292701721191e-01 2.9036629199981689e-01</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 332 784272181 -1073742539 -554188937 -67127948
+            938153105 -1091568641 -1917947412 -2140908</internalNodes>
+          <leafValues>
+            -3.4002754092216492e-01 3.1559377908706665e-01</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 214 256847367 707514298 -1090536922 -286331166
+            1877943126 258930467 -52826284 -50858080</internalNodes>
+          <leafValues>
+            -4.0559005737304688e-01 2.5587162375450134e-01</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 210 -176953385 839001603 -118293121 -46662093
+            -928341523 783159107 1824812218 -294654113</internalNodes>
+          <leafValues>
+            -2.2742739319801331e-01 4.4131305813789368e-01</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 291 -292556917 -268603344 -882511881 -142650156
+            -1955672434 -84524073 -941787305 -807451567</internalNodes>
+          <leafValues>
+            -2.8523033857345581e-01 3.5285699367523193e-01</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 86 -1006633234 -8464643 -1800132448 -126160132
+            1597972294 2137374137 2130142532 -67635593</internalNodes>
+          <leafValues>
+            -3.6786875128746033e-01 2.6055160164833069e-01</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 347 809435409 188951103 -1134973121 -1196245185
+            926905404 -2113948 -1122058375 -93651077</internalNodes>
+          <leafValues>
+            -3.1239312887191772e-01 3.1785130500793457e-01</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 47 -242549308 -1693329125 2124733233 857453163
+            -233386788 -69871665 -1055992678 173495071</internalNodes>
+          <leafValues>
+            -3.7436348199844360e-01 2.9003840684890747e-01</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 88 1543496623 -1277707265 1375580878 -1141900354
+            -202408001 1073719014 -20973842 -454167574</internalNodes>
+          <leafValues>
+            -2.5309252738952637e-01 3.8837322592735291e-01</leafValues></_></weakClassifiers></_>
+    <!-- stage 5 -->
     <_>
       <maxWeakCount>17</maxWeakCount>
-      <stageThreshold>-1.6478537321090698e+00</stageThreshold>
+      <stageThreshold>-1.3014856576919556e+00</stageThreshold>
       <weakClassifiers>
         <_>
           <internalNodes>
-            0 -1 99 1126020910 939511791 -137494546 -134218002 928378510
-            667815688 -131090 -21878</internalNodes>
+            0 -1 56 -16777228 1343290737 -73730 1979579903 -167772964
+            1145364445 -1 1969225695</internalNodes>
           <leafValues>
-            -1.9173553586006165e-01 6.1490827798843384e-01</leafValues></_>
+            -3.7386018037796021e-01 4.0434870123863220e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 277 1066647483 -1078215472 -1078199809 -515 -1078280194
-            -1079276888 -1112801281 -1077956952</internalNodes>
+            0 -1 329 -1078722575 -1078454128 991133557 -4369067
+            -1079247105 -1145394016 522813437 -1080337223</internalNodes>
           <leafValues>
-            -2.5890102982521057e-01 6.0596489906311035e-01</leafValues></_>
+            -3.0502972006797791e-01 4.3909499049186707e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 280 -1347239939 -1078263848 -6291491 -1073954860
-            -1883246595 -1075838997 -1346850307 -1393015372</internalNodes>
+            0 -1 252 -806361310 -492110674 -268445968 -1049642
+            2002778951 1024456291 2012705892 -135792649</internalNodes>
           <leafValues>
-            -3.5419720411300659e-01 3.9201220870018005e-01</leafValues></_>
+            -4.1819226741790771e-01 2.9456692934036255e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 148 -16582767 990936848 -15337711 1024534289 522275741
-            530061615 1786740027 2132761183</internalNodes>
+            0 -1 279 -52962084 805379072 -99820514 1040191240 -857961316
+            -1164230721 -318841633 -1185</internalNodes>
           <leafValues>
-            -4.0790781378746033e-01 3.3604335784912109e-01</leafValues></_>
+            -3.2393226027488708e-01 3.5176092386245728e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 33 -1024790785 -33673381 -715534345 -5787889 -721957121
-            -17850629 -654587205 -27048190</internalNodes>
+            0 -1 131 -148956144 992812800 463421370 920482344
+            -1626551044 512506296 -8586248 -4198469</internalNodes>
           <leafValues>
-            -3.0084383487701416e-01 4.4991242885589600e-01</leafValues></_>
+            -4.0920355916023254e-01 2.6287314295768738e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 173 779038223 578498431 -26263553 -1430717601
-            1426011767 1870118397 -726064396 -184550929</internalNodes>
+            0 -1 67 -1947229405 577929191 -1142967369 819199477
+            1610560307 1002176493 -268443355 -185204747</internalNodes>
           <leafValues>
-            -4.3469619750976562e-01 2.9388919472694397e-01</leafValues></_>
+            -3.9257824420928955e-01 2.6880934834480286e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 207 11804501 -1074249744 2143289343 -1359077380
-            2074886065 -262692 -1075003396 -1431820272</internalNodes>
+            0 -1 173 2136997887 492685274 610548733 501067503 1428159743
+            139549608 1843232763 1146223423</internalNodes>
           <leafValues>
-            -4.1263562440872192e-01 2.8357046842575073e-01</leafValues></_>
+            -2.6709714531898499e-01 3.5500597953796387e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 263 -620104768 -83232282 -548406795 -1074143767
-            -828717122 -21770245 251698105 68943602</internalNodes>
+            0 -1 323 -173546237 2012723003 -208685715 1965110275
+            -1648389341 -1207969861 -1532023285 -2068848597</internalNodes>
           <leafValues>
-            -3.8648277521133423e-01 3.0467325448989868e-01</leafValues></_>
+            -2.9938983917236328e-01 3.2542988657951355e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 161 1391411790 41936415 -228930992 1892677067
-            1987802112 1480885434 -1362 -219942962</internalNodes>
+            0 -1 72 -1025850814 -226835760 -10485921 -537564929
+            1390123691 -201328836 -1152983169 -229685189</internalNodes>
           <leafValues>
-            -3.7596645951271057e-01 3.1412878632545471e-01</leafValues></_>
+            -2.8262135386466980e-01 3.3869415521621704e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 308 248452913 1071429554 -251663105 -538972499
-            -1928628395 -1346437645 -1745150348 -33596064</internalNodes>
+            0 -1 300 186646459 772435664 -277088299 -811293964 510621556
+            -2003902767 768513520 -858982156</internalNodes>
           <leafValues>
-            -3.9380916953086853e-01 2.8952071070671082e-01</leafValues></_>
+            -3.5066390037536621e-01 2.6261052489280701e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 182 626985985 930297719 -286325569 -147866829
-            -692197027 2138802865 -117701012 -118164992</internalNodes>
+            0 -1 277 -1901527179 -1079583240 1608384509 -1214321156
+            -1475544131 -1618224659 -1350140680 -1343693700</internalNodes>
           <leafValues>
-            -3.5818240046501160e-01 3.2363671064376831e-01</leafValues></_>
+            -3.1748643517494202e-01 2.9679971933364868e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 60 -1361623937 -1149491078 5825754 508056955 -88210408
-            -655077264 -1174209542 -33408130</internalNodes>
+            0 -1 57 -1370792705 -151110594 137920254 505970139 -16908198
+            -119123852 2113992958 -27118721</internalNodes>
           <leafValues>
-            -3.4054177999496460e-01 3.2592311501502991e-01</leafValues></_>
+            -2.9851835966110229e-01 3.1736648082733154e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 184 1311738415 -1375274001 1726672390 -829228034
-            2070837764 1208920803 -67308591 -419954764</internalNodes>
+            0 -1 34 -421870864 -121460494 -69399301 -37695628 1854146044
+            -572886810 -1662657067 -2754955</internalNodes>
           <leafValues>
-            -3.7184986472129822e-01 2.8876912593841553e-01</leafValues></_>
+            -3.1197559833526611e-01 2.9238173365592957e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 1 -566173704 -81765536 -328487245 -545227007 8650948
-            -1342492099 8915104 -307505157</internalNodes>
+            0 -1 20 -395053825 -1172089085 -20972641 -36479168 16188668
+            170858277 1862209791 -43004073</internalNodes>
           <leafValues>
-            -3.2362362742424011e-01 3.4028744697570801e-01</leafValues></_>
+            -2.6653704047203064e-01 3.6648163199424744e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 223 787644405 1052643324 -671622145 1060113936
-            -1543669260 -621052931 497506684 -1094759403</internalNodes>
+            0 -1 162 -876099570 -1028677841 346016622 -791218210
+            -798236064 1141175622 -19929374 -733615388</internalNodes>
           <leafValues>
-            -3.8580575585365295e-01 2.8625565767288208e-01</leafValues></_>
+            -3.3825182914733887e-01 2.6917472481727600e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 90 -754941560 -598092101 -1244290303 281751211
-            1463866633 1153550863 -806946917 38740739</internalNodes>
+            0 -1 314 268538656 1006620135 2070388735 2065690825
+            -1156937026 -1545866585 -350495013 193696921</internalNodes>
           <leafValues>
-            -4.4092047214508057e-01 2.5595286488533020e-01</leafValues></_>
+            -3.5214114189147949e-01 2.6037210226058960e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 167 184294525 -9037826 -21186597 -1497857980
-            -1372058532 -1233225231 -341673474 -1099675796</internalNodes>
+            0 -1 344 649287281 -1970393800 -524355 1006436977
+            -1880457436 -1364230690 -575458832 -1711323724</internalNodes>
           <leafValues>
-            -3.7506091594696045e-01 2.9585087299346924e-01</leafValues></_></weakClassifiers></_>
-    <!-- stage 4 -->
+            -3.5447227954864502e-01 2.6205524802207947e-01</leafValues></_></weakClassifiers></_>
+    <!-- stage 6 -->
     <_>
-      <maxWeakCount>21</maxWeakCount>
-      <stageThreshold>-1.4008288383483887e+00</stageThreshold>
+      <maxWeakCount>19</maxWeakCount>
+      <stageThreshold>-1.5306358337402344e+00</stageThreshold>
       <weakClassifiers>
         <_>
           <internalNodes>
-            0 -1 233 -814746846 -2111111254 -553913104 -2097922
-            2004869959 1141046786 1970763104 -134744334</internalNodes>
+            0 -1 325 -14630984 -4473090 -1074397189 -33964034 -72302598
+            -1074020356 -1073741825 798731006</internalNodes>
           <leafValues>
-            -2.1097929775714874e-01 5.7671958208084106e-01</leafValues></_>
+            -3.5602328181266785e-01 4.2827311158180237e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 75 -8396836 -538976473 -16384001 -10879489 -8397857
-            -10498599 -45416465 1595899679</internalNodes>
+            0 -1 130 -551551009 486645509 1899748147 355677975 222889183
+            -1073921969 -8405249 863993727</internalNodes>
           <leafValues>
-            -3.1942996382713318e-01 4.6969848871231079e-01</leafValues></_>
+            -3.4908288717269897e-01 3.5527125000953674e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 4 -824512541 -524299 -344077 -72323247 206048519
-            -1409589837 -84975873 -805875917</internalNodes>
+            0 -1 98 1599900924 -103183170 2077315071 -8544581 2147076347
+            -348676 -6751554 1039993019</internalNodes>
           <leafValues>
-            -3.0280569195747375e-01 4.2180880904197693e-01</leafValues></_>
+            -4.1958260536193848e-01 2.6830750703811646e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 290 -1086615304 956872912 223108216 496889077
-            -1097860099 956429808 1601034749 -538976769</internalNodes>
+            0 -1 341 -551306566 -1928790024 409301104 -570567172
+            155380464 201374866 1307966709 -840957953</internalNodes>
           <leafValues>
-            -3.5371550917625427e-01 3.6481952667236328e-01</leafValues></_>
+            -2.9362049698829651e-01 3.5112550854682922e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 146 -85985781 1914665473 1351604943 269482959
-            -118967717 -264571342 -71633409 -1574764609</internalNodes>
+            0 -1 159 -25168073 792404277 -1048577 -1077938185 -50397955
+            -1125161865 -118697795 -17040197</internalNodes>
           <leafValues>
-            -3.5075160861015320e-01 3.4602758288383484e-01</leafValues></_>
+            -2.4668307602405548e-01 4.3156060576438904e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 81 -579450864 489695248 -568994533 -671905287
-            1484394168 -21040594 -1132978498 -4358</internalNodes>
+            0 -1 102 -254483728 -134352193 1078993009 -438445569
+            -145493001 236195840 2010188607 803207983</internalNodes>
           <leafValues>
-            -3.6514815688133240e-01 3.3418157696723938e-01</leafValues></_>
+            -4.0355175733566284e-01 2.2437272965908051e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 300 -1071640576 -1794071852 -589571267 -622299971
-            -128680624 -107152175 -1128604712 -93782371</internalNodes>
+            0 -1 270 543941090 32109282 -158607600 -539249547 1450174403
+            -2037673760 1430348867 -706789133</internalNodes>
           <leafValues>
-            -4.3749809265136719e-01 2.3641848564147949e-01</leafValues></_>
+            -3.8295698165893555e-01 2.4519409239292145e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 43 1347789474 278788859 1078009887 1450704633 755482275
-            -890279806 1601682923 1145430595</internalNodes>
+            0 -1 194 1820081525 1073508181 -237185025 -1627884305
+            -1208341124 -1549315 786959612 -1360889776</internalNodes>
           <leafValues>
-            -4.5889991521835327e-01 2.1458856761455536e-01</leafValues></_>
+            -3.9130604267120361e-01 2.4020861089229584e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 58 -67811136 507778012 2090770170 940627838 -547680164
-            -564395008 -1507362 -15533189</internalNodes>
+            0 -1 123 -126746406 -16910241 1317990340 2140139227
+            -152170248 -665943862 -494767108 -1308598001</internalNodes>
           <leafValues>
-            -3.4613710641860962e-01 2.9729354381561279e-01</leafValues></_>
+            -3.3991897106170654e-01 2.5616830587387085e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 40 708451453 915939127 2086399799 -1364049961
-            -111247856 -278977 -562528515 -1432293672</internalNodes>
+            0 -1 169 -25173426 1157590007 -1462405486 9141882 1563902020
+            1986233998 -121111822 1375206347</internalNodes>
           <leafValues>
-            -4.1620507836341858e-01 2.4089127779006958e-01</leafValues></_>
+            -3.9309167861938477e-01 2.3203048110008240e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 279 -1423966541 177905074 -199210 -1914114123
-            1966529760 -2068908586 -574294864 -841165576</internalNodes>
+            0 -1 119 -2109765118 -1549312122 1974331919 -15794219
+            -68435067 -10513465 -203437628 -207886460</internalNodes>
           <leafValues>
-            -3.1373840570449829e-01 3.2040333747863770e-01</leafValues></_>
+            -3.2824972271919250e-01 2.5953757762908936e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 198 1848585743 -1940984369 1618804030 -285289836
-            1994084869 67912305 -4262128 -303498266</internalNodes>
+            0 -1 293 532419764 -2413864 1004477621 931662384 -1970602497
+            -1095996537 -839968773 -1411438117</internalNodes>
           <leafValues>
-            -3.6098247766494751e-01 2.7308923006057739e-01</leafValues></_>
+            -4.1732871532440186e-01 2.0762878656387329e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 83 -34593 -42134437 83156217 534796439 -206958426
-            -542489456 -301270341 -1910021</internalNodes>
+            0 -1 139 1857947903 1492633971 -1101013025 975886606
+            1350846468 -121757915 -130875788 -869224848</internalNodes>
           <leafValues>
-            -2.1900075674057007e-01 4.6534782648086548e-01</leafValues></_>
+            -3.4800508618354797e-01 2.4446432292461395e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 255 -732498730 808132612 -1694705650 637674514
-            -856846932 790002977 -1523128100 -5768257</internalNodes>
+            0 -1 103 -2466598 -4662086 -978313286 -784675555 454565560
+            487593980 1603337147 -7147781</internalNodes>
           <leafValues>
-            -3.0635869503021240e-01 3.2308223843574524e-01</leafValues></_>
+            -2.7047672867774963e-01 3.1779998540878296e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 142 -272658653 -2039881873 -1093759223 -295772198
-            316478038 1219928242 1542411604 -523960875</internalNodes>
+            0 -1 109 -1561869790 120520547 1657708544 -1898513430
+            -1614825521 2092432685 1538717248 -289931533</internalNodes>
           <leafValues>
-            -4.1005435585975647e-01 2.4376337230205536e-01</leafValues></_>
+            -4.0362039208412170e-01 2.1034663915634155e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 314 -1886651248 233035768 -579887888 -644481803
-            -1924527808 72215888 -813972012 -838860849</internalNodes>
+            0 -1 180 1084531215 -707808258 -1210116245 -439570458
+            897553343 1907884029 -135266566 -188437888</internalNodes>
           <leafValues>
-            -3.2710522413253784e-01 3.0177840590476990e-01</leafValues></_>
+            -2.8848439455032349e-01 2.9848706722259521e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 109 -626385315 -541893255 -289637249 -2982538
-            -285318128 -335644678 -934750724 -1937614</internalNodes>
+            0 -1 70 -526324565 -2473047 -1752530953 -720765307
+            -829754181 -88588561 725799882 -1423966207</internalNodes>
           <leafValues>
-            -3.0264344811439514e-01 3.4333297610282898e-01</leafValues></_>
+            -2.9072195291519165e-01 2.8631457686424255e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 127 -675308008 858262544 -546392130 -86565344 889738476
-            1024209296 -539034113 -17892421</internalNodes>
+            0 -1 186 -1035688188 -2075351177 1742138910 -1361646049
+            2038259221 1281666845 -10016229 -927864043</internalNodes>
           <leafValues>
-            -3.0164864659309387e-01 3.2610884308815002e-01</leafValues></_>
+            -4.0738871693611145e-01 2.1433149278163910e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 76 289874895 1574889454 356325874 -1257339986
-            2013148111 1523362314 -209587256 -51584276</internalNodes>
+            0 -1 111 -193049515 -579904651 -1078067337 -1125110406
+            657196408 -308999 -269432520 -1626310360</internalNodes>
           <leafValues>
-            -3.0728715658187866e-01 3.2666257023811340e-01</leafValues></_>
+            -3.4779027104377747e-01 2.4815729260444641e-01</leafValues></_></weakClassifiers></_>
+    <!-- stage 7 -->
+    <_>
+      <maxWeakCount>19</maxWeakCount>
+      <stageThreshold>-1.5291346311569214e+00</stageThreshold>
+      <weakClassifiers>
         <_>
           <internalNodes>
-            0 -1 191 207364212 -1629723097 -69798913 180098791 445713016
-            -1342538933 -112443395 -1436022512</internalNodes>
+            0 -1 251 -13959169 -28639242 -402655813 -34537805 256249855
+            -568918017 1146377727 1413838847</internalNodes>
           <leafValues>
-            -4.8653569817543030e-01 2.1469378471374512e-01</leafValues></_>
+            -3.0813953280448914e-01 4.0832179784774780e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 316 -1891992271 534502897 -709725931 -1133905467
-            -1625325679 -1098169635 -1377993223 -1175556795</internalNodes>
+            0 -1 58 -2117889 -6785 -88080641 -1078673830 1592918250
+            -130866 -28588321 -67420082</internalNodes>
           <leafValues>
-            -3.6775574088096619e-01 2.6944977045059204e-01</leafValues></_></weakClassifiers></_>
-    <!-- stage 5 -->
+            -2.4101538956165314e-01 4.6791258454322815e-01</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 104 63906446 1607320575 -243471634 -35783681
+            -1106396194 1430561736 -201721409 -168502531</internalNodes>
+          <leafValues>
+            -4.4818142056465149e-01 2.3805019259452820e-01</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 313 -201338603 -10642115 1604312349 -1120184061
+            -570443331 -16641 -588542516 -1936978931</internalNodes>
+          <leafValues>
+            -2.7106782793998718e-01 3.9553779363632202e-01</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 42 -1358982349 -1862229200 -537145985 -1122992815
+            178914341 -1439598077 1593789951 -272634817</internalNodes>
+          <leafValues>
+            -3.2034155726432800e-01 3.0296289920806885e-01</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 318 -1440743437 235588504 -10494472 -1887027976
+            -1288767504 -1398099527 -843000652 -863175440</internalNodes>
+          <leafValues>
+            -3.0287060141563416e-01 3.1029415130615234e-01</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 292 -555045126 -361514 762749686 -139778 235667694
+            -1093395212 -11471106 -6309889</internalNodes>
+          <leafValues>
+            -3.0765682458877563e-01 3.1880700588226318e-01</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 196 250872917 -68273685 -1078051329 -1082508571
+            -1091283460 -1168712 -1417288 -1363666432</internalNodes>
+          <leafValues>
+            -3.3388796448707581e-01 2.7029579877853394e-01</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 219 -290476795 -465649810 -35918852 -289735302
+            -34138796 -84935682 -318770912 -857082906</internalNodes>
+          <leafValues>
+            -3.2501670718193054e-01 2.7079197764396667e-01</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 351 255542577 -1383080455 -134234123 -35669132
+            225794545 -1073809475 501579485 -43919</internalNodes>
+          <leafValues>
+            -3.1916373968124390e-01 2.6903003454208374e-01</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 133 215553112 -1107551056 251485533 -1117840291
+            -23183686 -1157685096 148380684 -1359280118</internalNodes>
+          <leafValues>
+            -3.4327763319015503e-01 2.6013481616973877e-01</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 229 1781507627 11182978 -1532302414 -453707565
+            2112190021 1230535507 1940017765 -723454538</internalNodes>
+          <leafValues>
+            -4.0361833572387695e-01 2.0124079287052155e-01</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 35 1659037435 -1074583282 -585441281 -1142706330
+            -487432961 -50689038 -752619781 2119369219</internalNodes>
+          <leafValues>
+            -2.8866782784461975e-01 2.8524476289749146e-01</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 5 -277098501 -426275 -537657353 -80707839 148375995
+            -1443515977 -1360028481 -290306189</internalNodes>
+          <leafValues>
+            -2.2325216233730316e-01 4.0045592188835144e-01</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 342 -12845061 -1146450256 1643999573 -578956079
+            -1430327361 -1364660568 1068039673 -826557192</internalNodes>
+          <leafValues>
+            -1.7625236511230469e-01 4.5335152745246887e-01</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 246 -5334 16170343 -1563618650 -559235090 -213913050
+            543944397 -82347060 -186319018</internalNodes>
+          <leafValues>
+            -3.3681878447532654e-01 2.5925871729850769e-01</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 200 706711043 240052095 -1057817422 -288572133
+            2104128000 107326306 -142977008 -184549550</internalNodes>
+          <leafValues>
+            -4.0993413329124451e-01 1.9274616241455078e-01</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 207 678842645 -554033765 -299117059 -2195490 787765744
+            -85783809 801398270 -1342553048</internalNodes>
+          <leafValues>
+            -3.0899345874786377e-01 2.7749294042587280e-01</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 239 -352653541 -1464975560 -1711377924 1006431154
+            -1914849861 -1997605505 -723791652 -2005992518</internalNodes>
+          <leafValues>
+            -2.7373707294464111e-01 3.1265005469322205e-01</leafValues></_></weakClassifiers></_>
+    <!-- stage 8 -->
     <_>
       <maxWeakCount>20</maxWeakCount>
-      <stageThreshold>-1.6370692253112793e+00</stageThreshold>
+      <stageThreshold>-1.2624083757400513e+00</stageThreshold>
       <weakClassifiers>
         <_>
           <internalNodes>
-            0 -1 246 -544546902 -40378434 1166794751 -553126475
-            1124863438 -6684681 252464271 252663279</internalNodes>
+            0 -1 152 -536896171 528166667 -89134213 863190787 -10787
+            -42746009 -135004165 861372191</internalNodes>
           <leafValues>
-            -1.7677198350429535e-01 5.9283459186553955e-01</leafValues></_>
+            -3.0395314097404480e-01 4.0150311589241028e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 105 -1688231254 -136322578 542408738 -167781650
-            -284181590 88186882 -74646534 -254480182</internalNodes>
+            0 -1 316 1058061817 1069530432 1072045437 -779 -1079460102
+            -1078220624 -1086607877 -1347745096</internalNodes>
           <leafValues>
-            -4.8250266909599304e-01 3.2293373346328735e-01</leafValues></_>
+            -3.1513056159019470e-01 3.4505581855773926e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 291 -1087113223 -1153788752 923893117 -40019499
-            -1444151361 -1145394000 520297981 -7610887</internalNodes>
+            0 -1 231 -681586977 321007414 1157254391 -135793561
+            1280068831 961635295 1153779199 1107294463</internalNodes>
           <leafValues>
-            -2.7269113063812256e-01 4.6762999892234802e-01</leafValues></_>
+            -3.4076648950576782e-01 2.9044425487518311e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 163 1431698391 477399807 5291197 215258107 2097218267
-            1070271552 1347764095 1497759739</internalNodes>
+            0 -1 281 13565963 -1605663761 -1068499969 -1551382549
+            -957611569 -88150085 -486669105 -489698353</internalNodes>
           <leafValues>
-            -3.6439743638038635e-01 3.3937779068946838e-01</leafValues></_>
+            -2.9677531123161316e-01 3.0763381719589233e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 49 -494878000 -1408572168 -1216184843 -570753839
-            -1385631492 -1572929 -37698091 -140075</internalNodes>
+            0 -1 326 -1053826398 -721436430 -280231937 -975176521
+            -409225541 -71593733 -6291717 -1413486341</internalNodes>
           <leafValues>
-            -3.4019106626510620e-01 3.2104432582855225e-01</leafValues></_>
+            -2.8983283042907715e-01 3.1503608822822571e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 101 -15196934 2140689563 1546672602 1591347871
-            1544035576 488135152 2142261182 -4259841</internalNodes>
+            0 -1 183 1163896751 1977614331 671051643 -138674226
+            2144851967 1470987751 -58725393 -188420220</internalNodes>
           <leafValues>
-            -3.7342280149459839e-01 2.8317087888717651e-01</leafValues></_>
+            -2.0130541920661926e-01 3.9263197779655457e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 195 -357586129 70201151 -292424585 -1468006937
-            1163158101 45494091 -492310284 -184618257</internalNodes>
+            0 -1 38 -16788225 -25265109 -1172116865 974286447 -18980838
+            -2269836 -349111681 -30245109</internalNodes>
           <leafValues>
-            -4.2928436398506165e-01 2.4182404577732086e-01</leafValues></_>
+            -2.6475778222084045e-01 3.2654273509979248e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 219 -346034385 -1509510400 -590396300 -56691898
-            -2013314811 -11148442 -790137804 -17301901</internalNodes>
+            0 -1 84 1433881682 1597703946 1291197240 -9438094 1526162906
+            -394281474 -50917514 -414</internalNodes>
           <leafValues>
-            -3.2902050018310547e-01 3.1380781531333923e-01</leafValues></_>
+            -2.9093095660209656e-01 2.9709726572036743e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 276 51573280 869252567 856020959 2136817673 -1825854798
-            1786292453 1863958011 51070032</internalNodes>
+            0 -1 49 -603945842 -1315963413 -414862337 -9040081
+            -925350721 -117485633 -68928293 841171459</internalNodes>
           <leafValues>
-            -4.4989612698554993e-01 2.3105476796627045e-01</leafValues></_>
+            -3.6999693512916565e-01 2.1880353987216949e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 239 221945781 -1351824656 -369627303 -1616906768
-            180205816 -1398111810 986511580 -2002860624</internalNodes>
+            0 -1 335 -235151561 906503990 -6316714 948108800 -319324675
+            -16843053 -603980191 -117506534</internalNodes>
           <leafValues>
-            -3.3374428749084473e-01 3.0387389659881592e-01</leafValues></_>
+            -2.7334323525428772e-01 3.0180162191390991e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 88 -12577 1384049145 -1464090918 -265274512 1423314444
-            -330608884 -134684970 -95228557</internalNodes>
+            0 -1 66 -1413764333 724760368 601747389 -6095968 37694209
+            -1342441059 92217889 -273154057</internalNodes>
           <leafValues>
-            -2.9424193501472473e-01 3.4667330980300903e-01</leafValues></_>
+            -2.6323935389518738e-01 2.9735177755355835e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 215 -349179217 304152230 -725813534 -44849422 206658671
-            1343674791 1143817582 1414000887</internalNodes>
+            0 -1 163 -335559766 -453021782 -323533214 1893203877
+            -270539322 17588935 -186715916 -252379394</internalNodes>
           <leafValues>
-            -3.5459104180335999e-01 2.8464645147323608e-01</leafValues></_>
+            -3.0761030316352844e-01 2.5141632556915283e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 44 2135942447 398828943 961557154 -85264382 -9441329
-            191609019 -135559186 1155988198</internalNodes>
+            0 -1 328 -13631567 -1212417327 403124577 89128053 905935803
+            805306111 455804405 -1913655045</internalNodes>
           <leafValues>
-            -3.9276805520057678e-01 2.5532895326614380e-01</leafValues></_>
+            -2.4577388167381287e-01 3.1640377640724182e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 322 792354069 -1442292348 -725922817 -1075650752
-            -1345299339 -270808291 1585978709 -1363456899</internalNodes>
+            0 -1 338 -1805103104 -204178216 -1109225537 -645859592
+            -1179295532 -17539075 -1342640193 -1085605221</internalNodes>
           <leafValues>
-            -4.0223011374473572e-01 2.3934543132781982e-01</leafValues></_>
+            -2.7292105555534363e-01 2.8334984183311462e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 51 -963985190 526195161 -632047017 -13433768 -170216210
-            -584509261 -1147462405 2122007633</internalNodes>
+            0 -1 113 184427503 2077949879 2130628607 -1972228222
+            267784191 -122913 -19677458 -87003834</internalNodes>
           <leafValues>
-            -3.5836115479469299e-01 2.7841308712959290e-01</leafValues></_>
+            -2.6322066783905029e-01 2.9420077800750732e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 69 1282640527 -221028405 -1115770991 -1312815327
-            518459295 -5010698 -8421409 -52340448</internalNodes>
+            0 -1 81 105097999 1542832493 298852512 -33591146 -7371798
+            1171296972 -159057160 -792331574</internalNodes>
           <leafValues>
-            -3.0360385775566101e-01 3.3305782079696655e-01</leafValues></_>
+            -3.1270226836204529e-01 2.4914608895778656e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 63 240090463 1543015448 1657994909 1376934782
-            2121953054 -3393448 774963198 -364875945</internalNodes>
+            0 -1 287 -1423199312 -1691103151 -1814751664 -1613770752
+            990048439 1006682272 1472720818 -805482223</internalNodes>
           <leafValues>
-            -3.1514179706573486e-01 3.1063860654830933e-01</leafValues></_>
+            -3.1640163064002991e-01 2.3388214409351349e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 149 -117441008 272437552 -2011728848 808844177
-            -115035003 901066096 -392587048 829815772</internalNodes>
+            0 -1 18 706367007 709894941 -1978089477 -1976242714
+            1047418708 -9413867 -8999074 -94175241</internalNodes>
           <leafValues>
-            -4.1897901892662048e-01 2.3548045754432678e-01</leafValues></_>
+            -3.4782758355140686e-01 2.1951326727867126e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 41 -285250029 -1342531469 -1337688454 76061301
-            2140621344 -26490526 -230505742 -498673325</internalNodes>
+            0 -1 320 -1074273477 -1349648528 -26397387 -305765168
+            -1750336135 -1414551302 -820448067 -1996649316</internalNodes>
           <leafValues>
-            -3.7328067421913147e-01 2.7277800440788269e-01</leafValues></_>
+            -2.4355542659759521e-01 3.1015169620513916e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 186 197109511 113539807 -1663738276 652405614
-            2079664708 -1381909716 -83887277 -340414799</internalNodes>
+            0 -1 151 -25443838 1937727008 -398471218 40370095 -231164274
+            -1339821902 -97325926 -88867841</internalNodes>
           <leafValues>
-            -3.5890376567840576e-01 2.7977034449577332e-01</leafValues></_></weakClassifiers></_>
-    <!-- stage 6 -->
+            -2.6998028159141541e-01 2.8467071056365967e-01</leafValues></_></weakClassifiers></_>
+    <!-- stage 9 -->
     <_>
-      <maxWeakCount>24</maxWeakCount>
-      <stageThreshold>-1.3530069589614868e+00</stageThreshold>
+      <maxWeakCount>19</maxWeakCount>
+      <stageThreshold>-1.3592376708984375e+00</stageThreshold>
       <weakClassifiers>
         <_>
           <internalNodes>
-            0 -1 231 -607125512 -203956738 -146407939 -549587593
-            2106032085 -7015967 1296916047 1465901007</internalNodes>
+            0 -1 348 -995118944 -930416974 345887952 -570558340 88531328
+            -1945218639 -587737611 -570425861</internalNodes>
           <leafValues>
-            -1.2551400065422058e-01 6.0037857294082642e-01</leafValues></_>
+            -2.9777532815933228e-01 4.2831858992576599e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 126 -12041 289127191 -1961178373 858913587 -452995643
-            -573056619 -184946437 811859443</internalNodes>
+            0 -1 253 -67110358 1893122090 1893397120 -86249774
+            1180660851 7567942 1349997680 -134220065</internalNodes>
           <leafValues>
-            -3.1659016013145447e-01 4.0386086702346802e-01</leafValues></_>
+            -3.9622232317924500e-01 2.9791569709777832e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 305 -4456453 -1079345488 1601271281 1566430416
-            -1145044997 -1363497544 -807547663 -846209539</internalNodes>
+            0 -1 75 -539240230 -648023297 469764112 1593868287 -11661110
+            1532777684 -552444965 -14942209</internalNodes>
           <leafValues>
-            -2.4047850072383881e-01 4.9467754364013672e-01</leafValues></_>
+            -2.9889813065528870e-01 3.6522966623306274e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 205 -422843738 730826189 -93007646 -1561338070
-            1156254860 82792447 -359691576 -318767125</internalNodes>
+            0 -1 289 -67125368 -79955026 -2020348961 -35793731
+            -1077342273 -616575495 -1089623397 497024223</internalNodes>
           <leafValues>
-            -4.0942522883415222e-01 2.8118029236793518e-01</leafValues></_>
+            -3.4431287646293640e-01 2.9128664731979370e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 130 286242991 1430640951 -1315388758 -5384739
-            1897658847 1435892732 -241122312 -190447622</internalNodes>
+            0 -1 166 1384071754 1113049038 -758590950 1895815884
+            -763411890 1209352476 -89797814 -220206337</internalNodes>
           <leafValues>
-            -3.6675310134887695e-01 2.7747273445129395e-01</leafValues></_>
+            -4.1682410240173340e-01 2.1082815527915955e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 155 -360711817 1044065557 -202645505 -1078462473
-            -554253058 -123796300 -991681292 -117447077</internalNodes>
+            0 -1 105 -254496094 -18879841 14000245 771751931 -11010061
+            134742528 -8912901 929018859</internalNodes>
           <leafValues>
-            -2.2938863933086395e-01 4.3152013421058655e-01</leafValues></_>
+            -3.7486401200294495e-01 2.4162678420543671e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 33 -486546689 -38568697 -114385161 -1078244605
-            -1398768130 -16859405 -387455605 -95221245</internalNodes>
+            0 -1 179 -654313675 742329655 -262625 1060896639 -390366980
+            74072179 -253568780 -289418469</internalNodes>
           <leafValues>
-            -2.5292310118675232e-01 4.0669292211532593e-01</leafValues></_>
+            -2.5083890557289124e-01 3.3719986677169800e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 197 -347108861 707787566 -271712714 -286066182
-            1660625669 23327763 -118368650 -16781581</internalNodes>
+            0 -1 315 -73668360 1565910264 2081358045 2146916605
+            -1621517064 357571729 -1480983299 -24065</internalNodes>
           <leafValues>
-            -3.2693040370941162e-01 2.9912397265434265e-01</leafValues></_>
+            -2.4764552712440491e-01 3.5451245307922363e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 48 44773155 -1400496480 -2013315201 -2130179 1928269391
-            2146108387 1871512017 -2109991</internalNodes>
+            0 -1 301 -811597901 -1364218069 -1648402160 -325060800
+            -1976643936 -1364209682 -975732736 -856689421</internalNodes>
           <leafValues>
-            -3.1153312325477600e-01 3.0730357766151428e-01</leafValues></_>
+            -2.7585402131080627e-01 3.0668458342552185e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 277 817397681 -4651712 -1074593921 -4489223 -1464975366
-            -1080350544 1068207931 -1414856608</internalNodes>
+            0 -1 285 -16801110 1942398638 2139043338 1884201710
+            1565129044 1073771567 1927598335 1089267455</internalNodes>
           <leafValues>
-            -2.7505692839622498e-01 3.4677764773368835e-01</leafValues></_>
+            -3.5849529504776001e-01 2.3467011749744415e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 158 -805311870 -1362548369 -186736224 -220270666
-            1742698308 1147947264 -251792176 -789512618</internalNodes>
+            0 -1 124 -552751172 -106362566 379098395 -619987142
+            2056910831 -256982033 -448484726 991891214</internalNodes>
           <leafValues>
-            -3.9942753314971924e-01 2.4047489464282990e-01</leafValues></_>
+            -3.6114555597305298e-01 2.2252097725868225e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 65 -700036014 -675626240 648044818 -69944464 -389395237
-            -215288017 -1719763715 -12588054</internalNodes>
+            0 -1 28 -922792361 135407106 915543278 -1441729929
+            -209763771 -33465743 -85987393 -79495181</internalNodes>
           <leafValues>
-            -3.1749448180198669e-01 3.0149078369140625e-01</leafValues></_>
+            -2.9683136940002441e-01 2.8010207414627075e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 319 765664309 -1401170476 -22282241 -1880818860
-            -1688316571 -52824373 -1730200112 -889291499</internalNodes>
+            0 -1 174 -65566202 5422903 -1572145044 -617562398 -77657088
+            1967600929 854335524 -8915084</internalNodes>
           <leafValues>
-            -3.5558241605758667e-01 2.6557549834251404e-01</leafValues></_>
+            -3.7435227632522583e-01 2.1536998450756073e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 272 -1164201800 -1716289100 -378039852 -1409579788
-            -1121338919 -1880520559 932112367 -1869871980</internalNodes>
+            0 -1 22 -487912721 -800642866 2009588683 -1392279546
+            1656090575 1071632022 -2052634693 -2044509181</internalNodes>
           <leafValues>
-            -3.6485251784324646e-01 2.5734969973564148e-01</leafValues></_>
+            -3.0010569095611572e-01 2.6017066836357117e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 22 -21049601 -25866473 325725 1043995470 1592678894
-            -269259937 -971837858 -8913089</internalNodes>
+            0 -1 226 -741397974 -774903581 1081934016 -260181765
+            2068804966 -935049268 1908400875 -168901016</internalNodes>
           <leafValues>
-            -2.2092992067337036e-01 4.2716163396835327e-01</leafValues></_>
+            -2.7382543683052063e-01 2.9915502667427063e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 138 763233167 2004741991 -277961986 -35997914 897543679
-            1741158903 -50331667 -1578882304</internalNodes>
+            0 -1 44 1817520043 -1431149805 -35670017 848351552
+            1036462355 -1879155406 -302153961 -67637897</internalNodes>
           <leafValues>
-            -3.0084916949272156e-01 3.0936580896377563e-01</leafValues></_>
+            -3.3639410138130188e-01 2.2802397608757019e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 92 66036611 -2133412515 2136683646 -184645734
-            1604280073 202711897 -1379383 -186590399</internalNodes>
+            0 -1 311 -1330405232 -1146452984 -920726316 -1147304716
+            -1089883143 -1260027579 -1255145527 -1869873152</internalNodes>
           <leafValues>
-            -3.7059250473976135e-01 2.4178710579872131e-01</leafValues></_>
+            -3.6143729090690613e-01 2.2017471492290497e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 196 -326382376 361846096 -2045590179 1068964371
-            705563792 -1156488704 1208497115 994048507</internalNodes>
+            0 -1 255 -488642849 338857182 1447921202 -691318883
+            1085163095 23216146 1883555028 -209735809</internalNodes>
           <leafValues>
-            -3.2299432158470154e-01 2.8366291522979736e-01</leafValues></_>
+            -2.8023749589920044e-01 2.8233993053436279e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 70 -412097022 -1568018524 -1342448718 -1253932
-            -1260185663 1258275150 -2067820288 -138937659</internalNodes>
+            0 -1 6 -857296913 -38559749 -1123606723 -1326175183
+            214765461 1826707963 1609522143 250940451</internalNodes>
           <leafValues>
-            -3.5679051280021667e-01 2.6213440299034119e-01</leafValues></_>
+            -2.9626613855361938e-01 2.7211683988571167e-01</leafValues></_></weakClassifiers></_>
+    <!-- stage 10 -->
+    <_>
+      <maxWeakCount>20</maxWeakCount>
+      <stageThreshold>-1.2654424905776978e+00</stageThreshold>
+      <weakClassifiers>
         <_>
           <internalNodes>
-            0 -1 193 -714615533 270672129 -306258157 -1758339253
-            47808742 -1902768889 -1941903362 -893526249</internalNodes>
+            0 -1 274 -152045826 -542116132 -671384098 -536871169
+            71611552 4511120 1691862270 2144334079</internalNodes>
           <leafValues>
-            -2.5351437926292419e-01 3.6361116170883179e-01</leafValues></_>
+            -3.2745066285133362e-01 3.7415373325347900e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 165 -318796273 1227399022 -1369769360 -675875878
-            -344383672 1582766693 -86017024 -344793116</internalNodes>
+            0 -1 55 -562049324 1347689172 838916858 323023775 -10528232
+            1547698176 -79496197 -16257057</internalNodes>
           <leafValues>
-            -3.1456202268600464e-01 3.0873265862464905e-01</leafValues></_>
+            -3.2601267099380493e-01 3.1999495625495911e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 93 -1045815078 -235892117 -571835429 -3460789
-            -108525848 -1332172392 -1503517894 -1300229375</internalNodes>
+            0 -1 155 -150864973 823197205 855899696 1897004151
+            1359478447 239799783 -1119879173 2071721983</internalNodes>
           <leafValues>
-            -3.5038644075393677e-01 2.6677846908569336e-01</leafValues></_>
+            -3.1169268488883972e-01 3.2441514730453491e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 15 -1976677263 3726998 -392242219 214976380 -1048834204
-            -44384235 -81855380 -1434428367</internalNodes>
+            0 -1 131 -8122216 -1694493696 1544425874 1971917534
+            1494268856 974434736 -47924226 -1081103685</internalNodes>
           <leafValues>
-            -4.1762107610702515e-01 2.1475161612033844e-01</leafValues></_>
+            -3.4951829910278320e-01 2.8645709156990051e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 166 209059956 2146573530 1933758719 -1670893344
-            -1206231472 -538281424 -605128624 -88975308</internalNodes>
+            0 -1 2 -148702222 -39652368 -926160348 -4129301 71565440
+            1002386359 4456576 -269484065</internalNodes>
           <leafValues>
-            -4.3403875827789307e-01 2.1460674703121185e-01</leafValues></_></weakClassifiers></_>
-    <!-- stage 7 -->
-    <_>
-      <maxWeakCount>26</maxWeakCount>
-      <stageThreshold>-1.3850060701370239e+00</stageThreshold>
-      <weakClassifiers>
+            -3.2985246181488037e-01 2.8976812958717346e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 250 1118499839 -796332098 -134253196 -6424581 259721215
-            -1671186434 100533499 1170700287</internalNodes>
+            0 -1 269 -537196528 367210120 -810330341 -1611069392
+            452626939 -275337221 -1889288261 -4456709</internalNodes>
           <leafValues>
-            -1.3170924782752991e-01 5.9910702705383301e-01</leafValues></_>
+            -3.6027029156684875e-01 2.2897857427597046e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 94 1570566140 2106702270 -577478657 -9625925 -36328709
-            -75449636 -394325 1071454459</internalNodes>
+            0 -1 46 581575179 144736896 -1511062769 771591377 13044399
+            613156333 461832575 -33602083</internalNodes>
           <leafValues>
-            -3.8424813747406006e-01 3.6834198236465454e-01</leafValues></_>
+            -3.1637319922447205e-01 2.6715582609176636e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 278 -136315975 -1187792752 1568109937 -571788877
-            -86048838 -1433673030 -1190563400 -1984968261</internalNodes>
+            0 -1 72 -631190908 -791476526 2102263115 -707719041
+            -1824344143 -221118035 1935670155 -681895917</internalNodes>
           <leafValues>
-            -2.4970491230487823e-01 4.7245621681213379e-01</leafValues></_>
+            -3.1301385164260864e-01 2.6414388418197632e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 155 -25692619 573911103 -1090519553 -1074266633
-            -1124204292 -1199619017 -387151619 -1363171157</internalNodes>
+            0 -1 143 -395337586 1290599162 -1480586611 -1107445125
+            -780276278 1222177164 1909323816 1431695206</internalNodes>
           <leafValues>
-            -2.7256563305854797e-01 4.0413850545883179e-01</leafValues></_>
+            -3.1736305356025696e-01 2.5901272892951965e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 299 270536720 -82027755 -542052353 -744834006
-            -172433515 -36839897 -2048335877 -1356137589</internalNodes>
+            0 -1 327 -1618216774 487712984 335544528 478095577 -16078406
+            185086393 210310393 1339020735</internalNodes>
           <leafValues>
-            -3.7769773602485657e-01 2.3510186374187469e-01</leafValues></_>
+            -3.2663252949714661e-01 2.4670498073101044e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 102 133774 1573843455 290464424 -173151905 771865036
-            1430562872 -109382744 -246039832</internalNodes>
+            0 -1 266 102918451 -821892609 49152511 -286461629 2080379763
+            2137245875 2051079551 -858486798</internalNodes>
           <leafValues>
-            -4.7037139534950256e-01 2.0533446967601776e-01</leafValues></_>
+            -3.4607407450675964e-01 2.0814558863639832e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 127 -618460144 -1256386552 -1618575940 1972721552
-            469800920 504635776 -846791686 -69254485</internalNodes>
+            0 -1 115 1965030149 69155845 -270820041 -1078461449
+            -136584193 762821931 -588278748 674225702</internalNodes>
           <leafValues>
-            -3.5127875208854675e-01 2.5741419196128845e-01</leafValues></_>
+            -3.3318042755126953e-01 2.3290997743606567e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 85 150343455 40910711 -1248068641 -1430372421
-            -1895949361 -21272033 -331755522 -1431642114</internalNodes>
+            0 -1 181 -489698686 -2131832314 -1039863296 818323586
+            -523765334 440824136 -780927062 -528941364</internalNodes>
           <leafValues>
-            -3.7984871864318848e-01 2.3182238638401031e-01</leafValues></_>
+            -3.0289414525032043e-01 2.5606787204742432e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 286 -13916067 -237157163 1069283741 -7496371
-            -1771992641 -17192227 -1383805025 -2004252467</internalNodes>
+            0 -1 7 -1968533749 -1158234249 -1903504601 1289568835
+            -2110509277 1055784827 -16777649 -1061695641</internalNodes>
           <leafValues>
-            -2.1929037570953369e-01 3.8296228647232056e-01</leafValues></_>
+            -3.1121507287025452e-01 2.4493122100830078e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 206 9705301 508957948 -71469059 431911901 2041834229
-            -1141023756 -38047748 -1432742364</internalNodes>
+            0 -1 59 -1258926881 -549822406 408301535 2050653013
+            -1703261576 -76779424 973269887 -98400385</internalNodes>
           <leafValues>
-            -3.4404903650283813e-01 2.3727993667125702e-01</leafValues></_>
+            -2.7002063393592834e-01 2.7681529521942139e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 162 -28187574 1457201967 -1799949806 542855772
-            -22592508 347566595 -86051214 -254279713</internalNodes>
+            0 -1 272 -758193574 1389009342 -1059925886 -5881636 12990686
+            2163886 1106474407 1364714403</internalNodes>
           <leafValues>
-            -3.3773353695869446e-01 2.3899486660957336e-01</leafValues></_>
+            -3.4319832921028137e-01 2.2524215281009674e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 78 1353317010 -353449217 14955059 233737419 1113314227
-            1272002592 2140215167 200230499</internalNodes>
+            0 -1 89 2010493580 1490924031 558703340 1878899615
+            2136242133 256903807 1130158729 818193091</internalNodes>
           <leafValues>
-            -3.5864931344985962e-01 2.1981315314769745e-01</leafValues></_>
+            -4.1370552778244019e-01 1.7945855855941772e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 50 -592281584 1487966200 -1782854276 -34165307
-            -911392552 -588393496 -86945955 -302569115</internalNodes>
+            0 -1 306 -202440190 -738220126 82060896 -477207729
+            -153700670 -570891389 -199329793 -203755569</internalNodes>
           <leafValues>
-            -2.9026558995246887e-01 2.8104048967361450e-01</leafValues></_>
+            -2.5417929887771606e-01 2.9859820008277893e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 301 -14053072 -2064062200 -928567823 -983051523
-            201916593 150423153 -1859132687 -1929383993</internalNodes>
+            0 -1 264 -221254326 1925904495 1704207914 1894699598
+            -451424859 4246980 -49167940 1886450374</internalNodes>
           <leafValues>
-            -3.2115238904953003e-01 2.5486564636230469e-01</leafValues></_>
+            -3.4114065766334534e-01 2.2073985636234283e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 79 -607531822 2133030428 1045592120 922799991
-            -1958080364 -631876516 -551887109 -116138161</internalNodes>
+            0 -1 53 -98573686 -233458620 -1145323521 -580784361
+            1931469735 -260055489 -1291736289 -1421354481</internalNodes>
           <leafValues>
-            -2.5716596841812134e-01 3.1999784708023071e-01</leafValues></_>
+            -2.1690982580184937e-01 3.4113904833793640e-01</leafValues></_></weakClassifiers></_>
+    <!-- stage 11 -->
+    <_>
+      <maxWeakCount>21</maxWeakCount>
+      <stageThreshold>-1.2858563661575317e+00</stageThreshold>
+      <weakClassifiers>
         <_>
           <internalNodes>
-            0 -1 7 -1897370238 2088280021 -27542220 955523029 143789824
-            -1732421377 -270311431 -319465097</internalNodes>
+            0 -1 288 -268513282 -170008577 -1615475234 -37777945
+            -54096706 -3303955 -268497714 233768959</internalNodes>
           <leafValues>
-            -3.7310892343521118e-01 2.2297158837318420e-01</leafValues></_>
+            -2.9269060492515564e-01 3.6005640029907227e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 151 2117994623 -596493511 -42869249 2123389533
-            -102873516 -1194255940 -1077870956 -1369933454</internalNodes>
+            0 -1 171 2139094807 590479159 -422320014 544275186
+            1609553655 1064828726 -268463004 1979187191</internalNodes>
           <leafValues>
-            -3.2065725326538086e-01 2.5838941335678101e-01</leafValues></_>
+            -3.9009553194046021e-01 2.6665380597114563e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 141 -402659162 81777018 894353956 -1095917410
-            1470100164 1429538625 -675679616 22405077</internalNodes>
+            0 -1 337 240061441 237972797 -1342754881 782424635 956105749
+            -1115687441 -557891589 -1360330817</internalNodes>
           <leafValues>
-            -3.9470222592353821e-01 2.1365866065025330e-01</leafValues></_>
+            -3.6515378952026367e-01 2.4825972318649292e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 306 371408657 -1390197839 -610304075 -1084394735
-            740911518 -1442850385 1025329500 -1085287308</internalNodes>
+            0 -1 39 -20737 -21921 1387329791 -1145902337 -19250950
+            -8502569 -126817537 -77082373</internalNodes>
           <leafValues>
-            -3.5310438275337219e-01 2.2878694534301758e-01</leafValues></_>
+            -1.8133202195167542e-01 4.5872864127159119e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 96 1411399848 1607023650 2118667161 2115963630
-            825267416 -1300086616 866705067 1593838595</internalNodes>
+            0 -1 136 -562084225 -588480681 -1099243521 506624528
+            1316756572 -84124547 -33784228 -365920720</internalNodes>
           <leafValues>
-            -3.7212049961090088e-01 2.1682462096214294e-01</leafValues></_>
+            -3.9777505397796631e-01 1.8508131802082062e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 236 -1023751505 1654647882 654289424 -221611870
-            1142643327 2865238 1353434162 -218116589</internalNodes>
+            0 -1 217 785362727 216853359 -402800844 -287899666
+            1395881781 1156951983 -134349248 -185271564</internalNodes>
           <leafValues>
-            -3.0895259976387024e-01 2.7360698580741882e-01</leafValues></_>
+            -3.4530290961265564e-01 2.4639949202537537e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 25 263714691 -1500250442 -572970029 1029922655
-            461194497 -1384691616 902512981 -831890189</internalNodes>
+            0 -1 68 -1062206256 1283745013 -34114723 -655764 1070420469
+            365214205 -805365315 -7516835</internalNodes>
           <leafValues>
-            -2.8019675612449646e-01 2.8230005502700806e-01</leafValues></_>
+            -3.2642650604248047e-01 2.5048437714576721e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 157 -1009275158 703439343 1881063906 1407643120
-            1357622212 1698779727 -175905592 -799737222</internalNodes>
+            0 -1 190 1474272223 1432203262 499659167 532543359 307625983
+            340797832 1059537791 1944010239</internalNodes>
           <leafValues>
-            -3.0597987771034241e-01 2.6828068494796753e-01</leafValues></_>
+            -2.8207024931907654e-01 2.8570288419723511e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 24 -655102849 1007864659 -1544094705 -1540313220
-            -574699 -47065227 -1091975362 -278732953</internalNodes>
+            0 -1 310 -48295664 -646879950 -749237799 -1153479021
+            -1097202291 -33608429 -1514198007 146252931</internalNodes>
           <leafValues>
-            -2.5672450661659241e-01 3.1667667627334595e-01</leafValues></_>
+            -3.7337026000022888e-01 2.1691022813320160e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 103 347621596 1037305260 358617181 753140063 -61713220
-            -610393186 -1106322953 -1350956022</internalNodes>
+            0 -1 145 -54539121 1325248383 -1444411622 -1078132833
+            2097041119 1281153237 -135827344 1899100997</internalNodes>
           <leafValues>
-            -3.4445220232009888e-01 2.3471401631832123e-01</leafValues></_>
+            -3.1012156605720520e-01 2.4879796802997589e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 36 -923349290 256096042 219291806 -1155987134
-            2086406828 1508909094 -2007541485 1887403703</internalNodes>
+            0 -1 208 215618933 536625151 -537774081 -1073979708
+            1022653716 -1077149825 -1073987588 -1426440928</internalNodes>
           <leafValues>
-            -3.4530115127563477e-01 2.3805907368659973e-01</leafValues></_></weakClassifiers></_>
-    <!-- stage 8 -->
-    <_>
-      <maxWeakCount>25</maxWeakCount>
-      <stageThreshold>-1.2224140167236328e+00</stageThreshold>
-      <weakClassifiers>
+            -3.5794767737388611e-01 2.0182034373283386e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 252 -22088450 -5325374 -33282 -258 12993776 67429556
-            1976988926 2005923583</internalNodes>
+            0 -1 275 -460354046 75902886 -1114232776 144879392
+            1700742225 200101343 -20972316 -268435457</internalNodes>
           <leafValues>
-            -1.9573126733303070e-01 5.5536717176437378e-01</leafValues></_>
+            -3.3210799098014832e-01 2.3649631440639496e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 216 -941896961 288549683 -965260547 1902502507
-            1287981311 723742655 1157582079 1173354239</internalNodes>
+            0 -1 331 -1120698607 -1816316560 -1115727883 -771893903
+            -1498071255 -1342570824 698559600 -1935190671</internalNodes>
           <leafValues>
-            -3.0669313669204712e-01 3.6197665333747864e-01</leafValues></_>
+            -3.1769388914108276e-01 2.3492129147052765e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 62 -571494657 -2099490 -25243649 -1082480054 2115633354
-            -130996 -329130274 -67419570</internalNodes>
+            0 -1 26 171629823 667944063 135529717 34762367 1819038997
+            1002177831 1348229755 2135252863</internalNodes>
           <leafValues>
-            -2.4500623345375061e-01 4.3682980537414551e-01</leafValues></_>
+            -3.5822075605392456e-01 2.1465454995632172e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 19 -704647185 2113917365 -428522838 -141168226
-            2123362255 2006664827 -254348594 1459088068</internalNodes>
+            0 -1 154 -637551088 286731008 -121898852 540119849
+            -716208703 -1779023243 -386809896 1901461404</internalNodes>
           <leafValues>
-            -3.4159252047538757e-01 2.9353541135787964e-01</leafValues></_>
+            -4.3143102526664734e-01 1.6342623531818390e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 285 -138414285 -168045645 -550635909 -240708569
-            -36728913 -33554641 -890270582 -2069142366</internalNodes>
+            0 -1 184 1860151087 1929903535 1385154026 1995326315
+            -186651217 1908896727 -1578172729 1690632140</internalNodes>
           <leafValues>
-            -2.8817924857139587e-01 3.4106674790382385e-01</leafValues></_>
+            -3.0808129906654358e-01 2.3992852866649628e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 77 -220544510 -184926009 2147213135 -209757985
-            -1177821558 -139002180 845151099 -8701317</internalNodes>
+            0 -1 261 -750652672 825569187 363565347 226880649 1425642663
+            1027652669 -1527280645 234220511</internalNodes>
           <leafValues>
-            -2.2831186652183533e-01 3.8085940480232239e-01</leafValues></_>
+            -2.8312164545059204e-01 2.6677671074867249e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 256 12976195 569051735 -1044464777 -2131832853
-            -1863693873 -889525281 -1060633090 -1024468017</internalNodes>
+            0 -1 283 -319861241 1113296810 -274206881 -358425573
+            2079722844 -400747690 -318934163 -10490913</internalNodes>
           <leafValues>
-            -3.4035223722457886e-01 2.4870637059211731e-01</leafValues></_>
+            -2.8361973166465759e-01 2.6147827506065369e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 225 243431285 -1342397538 -1074439183 -198404
-            -1147339787 -1950366979 -1176535299 -1346857836</internalNodes>
+            0 -1 100 1152141516 -134536513 1728012219 -613438294
+            289388027 -172525705 2052631547 523382314</internalNodes>
           <leafValues>
-            -2.9916274547576904e-01 2.7878564596176147e-01</leafValues></_>
+            -3.5195887088775635e-01 1.9971875846385956e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 188 -389107962 -1496674445 -1433293856 1650520822
-            -808004780 -340166498 -270808076 -327882656</internalNodes>
+            0 -1 250 1915726114 799985062 -863564618 -1796286242
+            1412398914 902102177 1130850167 -206571550</internalNodes>
           <leafValues>
-            -3.6523097753524780e-01 2.3002453148365021e-01</leafValues></_>
+            -3.5833287239074707e-01 2.0236967504024506e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 249 -1561660693 -1964116758 -433068176 -674252332
-            76465114 -86789644 1441781719 -167788045</internalNodes>
+            0 -1 95 -455700956 82848733 132951356 -67846796 -33744443
+            248862805 -1162704376 -1075833039</internalNodes>
           <leafValues>
-            -2.6452550292015076e-01 3.1857562065124512e-01</leafValues></_>
+            -3.7909838557243347e-01 1.7440141737461090e-01</leafValues></_></weakClassifiers></_>
+    <!-- stage 12 -->
+    <_>
+      <maxWeakCount>24</maxWeakCount>
+      <stageThreshold>-1.2824541330337524e+00</stageThreshold>
+      <weakClassifiers>
         <_>
           <internalNodes>
-            0 -1 30 83758542 1352905533 -25477260 888412977 1174342621
-            -581240613 -1877419 954559493</internalNodes>
+            0 -1 80 -45825 -536920833 1280073215 495738239 -88473416
+            -130820 -570238469 -71639553</internalNodes>
           <leafValues>
-            -3.9430552721023560e-01 2.1380217373371124e-01</leafValues></_>
+            -1.6788482666015625e-01 4.4611564278602600e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 291 1060338993 -1618339632 1411411797 -1111518927
-            1038801631 -1171216200 431569585 -1627714192</internalNodes>
+            0 -1 228 -572535553 397093339 -1062400257 1610558363
+            214714620 1068935571 68145083 532673471</internalNodes>
           <leafValues>
-            -3.1174781918525696e-01 2.5848281383514404e-01</leafValues></_>
+            -3.1849989295005798e-01 2.7583411335945129e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 174 1272433155 241160959 -187054076 -1428167714
-            1656705620 178680903 -188744156 -92279086</internalNodes>
+            0 -1 317 -1231 -1819561582 1911910833 1570722209 -1093
+            -1685331270 -1076924144 -2002009685</internalNodes>
           <leafValues>
-            -3.5104271769523621e-01 2.4124261736869812e-01</leafValues></_>
+            -2.7908280491828918e-01 2.8472077846527100e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 100 276007552 1448970891 1624277552 1433388541
-            -144262781 203467264 -747113541 1187367471</internalNodes>
+            0 -1 258 -1942309903 -1342795280 -4194443 -1073899024
+            -1354893895 -1079265281 529358301 -1447062096</internalNodes>
           <leafValues>
-            -4.3640381097793579e-01 2.0373314619064331e-01</leafValues></_>
+            -2.6034539937973022e-01 2.9407960176467896e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 265 514492090 -1084506382 802327294 -574652997
-            -1951495942 -1115800400 -1734105369 -745080833</internalNodes>
+            0 -1 282 -486603761 538575875 2129538959 34218767 -573161380
+            -70690275 -285287348 -2363473</internalNodes>
           <leafValues>
-            -2.6869311928749084e-01 3.1262946128845215e-01</leafValues></_>
+            -3.4062975645065308e-01 2.0401223003864288e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 238 975568369 -1078429260 -1073778819 -1246039248
-            -566763547 -574710393 -1879731715 -1363518280</internalNodes>
+            0 -1 291 -1349524722 -69233725 -1720626217 -536900587
+            -2143975798 -12746304 118214239 1599029333</internalNodes>
           <leafValues>
-            -2.5506082177162170e-01 3.2470330595970154e-01</leafValues></_>
+            -3.2409128546714783e-01 2.2399894893169403e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 116 -197130578 -69435407 25570034 -1282381057
-            -736477475 1078203406 1072176808 -224107914</internalNodes>
+            0 -1 120 -269775230 1408819148 -390615384 -8392706 -1057528
+            1464277268 -1276123648 2004090628</internalNodes>
           <leafValues>
-            -3.3984503149986267e-01 2.3857665061950684e-01</leafValues></_>
+            -3.6182680726051331e-01 1.8862281739711761e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 170 2006936207 2046780255 -906124674 -571018634
-            465548283 1995414095 -469838166 -53152636</internalNodes>
+            0 -1 78 521087406 894214626 828121640 -236406052 935394252
+            1426326282 -507511876 -138091528</internalNodes>
           <leafValues>
-            -2.3337669670581818e-01 3.4638467431068420e-01</leafValues></_>
+            -4.3280023336410522e-01 1.7912270128726959e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 261 -1993607757 -1984171376 -1964620068 -1377319864
-            -878651982 2100351409 -540935193 -846344047</internalNodes>
+            0 -1 349 196050803 -1364574018 2042330965 -841132080
+            -1466964805 -1882464834 1636143569 -860888828</internalNodes>
           <leafValues>
-            -2.5745591521263123e-01 3.1530505418777466e-01</leafValues></_>
+            -2.9185295104980469e-01 2.3511406779289246e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 129 -585119904 520350737 -1602237728 387020659
-            -316697172 -809628610 -341521253 1937239575</internalNodes>
+            0 -1 19 -21018037 1783262287 -1597196625 -1442780128
+            -414100906 -277852304 -355078554 -46081177</internalNodes>
           <leafValues>
-            -3.0576938390731812e-01 2.6786401867866516e-01</leafValues></_>
+            -2.9949510097503662e-01 2.4424977600574493e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 303 -48760835 -1382112048 1192391029 185356020
-            783760374 -1402171184 959454513 -1431708544</internalNodes>
+            0 -1 12 49418002 -2003701765 -313130209 -2000720353
+            1219644673 -285278209 -872858825 1123765061</internalNodes>
           <leafValues>
-            -2.8466665744781494e-01 3.0237734317779541e-01</leafValues></_>
+            -4.4975990056991577e-01 1.4456595480442047e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 321 700150833 -1366030659 -590225483 -1393138060
-            -1364311531 -1142207587 2140558729 -1370849424</internalNodes>
+            0 -1 52 -364085048 491458118 -675123209 -541193660
+            -839658244 -262730335 -604312834 2115044436</internalNodes>
           <leafValues>
-            -3.7198981642723083e-01 2.3002536594867706e-01</leafValues></_>
+            -3.9896175265312195e-01 1.7343275249004364e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 228 -1054166 -201341212 1923367016 1916986952
-            1992519431 1213361995 1174402160 -1068174746</internalNodes>
+            0 -1 160 -470817137 156157702 -1967203869 -772802881
+            -246418489 1363658693 -218633237 -245891170</internalNodes>
           <leafValues>
-            -3.4979847073554993e-01 2.4561876058578491e-01</leafValues></_>
+            -2.1532715857028961e-01 3.3184850215911865e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 106 -1907696549 -268565315 -1342514689 336742770
-            -1439790339 -1301623122 -1342275841 -1440064298</internalNodes>
+            0 -1 175 -352409586 -1190861826 -1642823092 -71631894
+            -923852796 1998658431 -399708968 -11345840</internalNodes>
           <leafValues>
-            -2.6577013731002808e-01 3.1544610857963562e-01</leafValues></_>
+            -2.8774553537368774e-01 2.3346234858036041e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 210 -257776636 1915752044 -1649103180 -1095126373
-            1422147805 210473965 2022068463 1660109363</internalNodes>
+            0 -1 178 1146397583 1440677111 1789980602 -168959196
+            1607858623 1003980783 -95098146 -520838912</internalNodes>
           <leafValues>
-            -3.7758591771125793e-01 2.2004681825637817e-01</leafValues></_></weakClassifiers></_>
-    <!-- stage 9 -->
-    <_>
-      <maxWeakCount>28</maxWeakCount>
-      <stageThreshold>-1.3550500869750977e+00</stageThreshold>
-      <weakClassifiers>
+            -2.7916902303695679e-01 2.3335020244121552e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 273 1595195384 1608363967 1595766713 -572674083
-            1226391547 -44180227 2111155631 531574527</internalNodes>
+            0 -1 352 -50332877 -1350565899 -589480591 -849224360
+            -2014845531 -1930707058 -1980770927 -857737763</internalNodes>
           <leafValues>
-            -1.6430117189884186e-01 5.4418802261352539e-01</leafValues></_>
+            -1.8601153790950775e-01 3.3500474691390991e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 39 -5377 -57601 538639103 -347397 -17301286 -4259105
-            -79502593 -77380901</internalNodes>
+            0 -1 116 -679517179 235021312 -2015978753 -308288545 -3083
+            -1148969 572941047 -1531453593</internalNodes>
           <leafValues>
-            -1.8002209067344666e-01 5.2194720506668091e-01</leafValues></_>
+            -2.8746202588081360e-01 2.3165051639080048e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 177 1566441471 2103287797 492075325 500554077
-            1998422011 -155652 192249721 1565917179</internalNodes>
+            0 -1 246 -283094 -78995521 989667876 -388040262 1269563143
+            376496915 -180422212 1906376566</internalNodes>
           <leafValues>
-            -2.7448469400405884e-01 3.6767318844795227e-01</leafValues></_>
+            -3.3096152544021606e-01 1.9776308536529541e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 3 -524550921 -1669383407 -574620225 -33590459 143458441
-            256708119 -805314577 -6324385</internalNodes>
+            0 -1 97 -182451973 -202104337 -1497597953 -141604069
+            -417856360 -236145225 -14023781 -1308484861</internalNodes>
           <leafValues>
-            -2.3465685546398163e-01 4.0192386507987976e-01</leafValues></_>
+            -2.5251045823097229e-01 2.6549828052520752e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 71 -846691120 1439476212 -690689 -2237091 -67570179
-            -36374787 -2105923 -143907</internalNodes>
+            0 -1 298 1873775874 -1934907533 -1096029424 -930612685
+            -2068250556 -1915946543 1105810433 -977930811</internalNodes>
           <leafValues>
-            -2.7146762609481812e-01 3.2002952694892883e-01</leafValues></_>
+            -4.1322487592697144e-01 1.5656088292598724e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 294 263139089 -581452515 2010774399 -2106799 477955253
-            -72357417 267875276 -1097712</internalNodes>
+            0 -1 327 -559975688 -1098343184 56689852 -541071107
+            -1096812098 -1650825224 -821928707 -570434053</internalNodes>
           <leafValues>
-            -3.5161617398262024e-01 2.3248630762100220e-01</leafValues></_>
+            -2.2519363462924957e-01 2.9129114747047424e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 302 -15214854 -1884686344 167600312 -581052707 37857013
-            202028220 1305828853 -840957953</internalNodes>
+            0 -1 322 1760817168 2014969105 -1342718095 -115803287
+            -1804093744 -249891400 -828918088 -1133191201</internalNodes>
           <leafValues>
-            -2.6214873790740967e-01 3.0466583371162415e-01</leafValues></_>
+            -2.5303143262863159e-01 2.6384234428405762e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 169 613396271 2003697295 1738141229 -35000540
-            2147446463 2131993840 -10096690 1690603136</internalNodes>
+            0 -1 201 -337401329 79624186 -157749454 -2107704234
+            2136683024 1450477407 -277792234 -789447723</internalNodes>
           <leafValues>
-            -3.2117179036140442e-01 2.4732810258865356e-01</leafValues></_>
+            -3.5275053977966309e-01 1.8988111615180969e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 281 -1355025965 -1961980240 -671219723 -283264688
-            -1936837383 -1952736320 -908474131 -875701004</internalNodes>
+            0 -1 85 1483955794 880441222 1177964078 -1207814558
+            1556696189 -13904937 -805344549 -21761033</internalNodes>
           <leafValues>
-            -2.4713008105754852e-01 3.1776627898216248e-01</leafValues></_>
+            -2.9593563079833984e-01 2.2950462996959686e-01</leafValues></_></weakClassifiers></_>
+    <!-- stage 13 -->
+    <_>
+      <maxWeakCount>25</maxWeakCount>
+      <stageThreshold>-1.1346004009246826e+00</stageThreshold>
+      <weakClassifiers>
         <_>
           <internalNodes>
-            0 -1 232 -894441054 -1880167002 -853281294 -338827028
-            1348301603 877440640 1936192066 -135400158</internalNodes>
+            0 -1 135 248384512 -2230281 -67167425 -278721 -1430323288
+            -4097 -1364709878 -1427136853</internalNodes>
           <leafValues>
-            -3.2655048370361328e-01 2.4388861656188965e-01</leafValues></_>
+            -2.7531594038009644e-01 3.4290844202041626e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 288 -553260894 -155221559 -13927175 -570440513
-            -23332102 -93644167 -1079190789 -1431330575</internalNodes>
+            0 -1 192 1473642495 274004474 933182335 500809723 1997913085
+            487862028 2077977039 1608383199</internalNodes>
           <leafValues>
-            -2.4785453081130981e-01 3.1448525190353394e-01</leafValues></_>
+            -2.5518363714218140e-01 3.2124108076095581e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 190 672423253 -570534469 -174826505 -1074210146
-            -1158800264 -67208458 802954712 -1079507880</internalNodes>
+            0 -1 150 -671627180 1440067463 -55773956 -252462474
+            -212729877 -1744769111 -298451490 805420943</internalNodes>
           <leafValues>
-            -3.1213754415512085e-01 2.4356111884117126e-01</leafValues></_>
+            -3.4691503643989563e-01 2.3676414787769318e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 120 -656932646 -651487779 -956164148 2064599515
-            -136440708 -588512112 -1232981444 -1979159765</internalNodes>
+            0 -1 3 -186646854 -72960256 -822609825 -856193 5046414
+            733941519 1287603359 -129</internalNodes>
           <leafValues>
-            -3.0449146032333374e-01 2.5301957130432129e-01</leafValues></_>
+            -2.4629610776901245e-01 3.0966648459434509e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 243 1649084931 672964650 -1105808049 713205535
-            2036285460 -666148121 -55162040 -18875393</internalNodes>
+            0 -1 324 -1334507507 -1115837163 -1198804579 1034753295
+            -237926227 -69613103 -269694261 -2138504179</internalNodes>
           <leafValues>
-            -3.4271252155303955e-01 2.1502359211444855e-01</leafValues></_>
+            -3.6555841565132141e-01 1.9017384946346283e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 11 -152656190 868356183 -501591426 -201146046
-            -546953661 1982915527 -759837225 -751304729</internalNodes>
+            0 -1 45 0 -824089359 -278966017 -749744779 8831144
+            -347413507 -1475415988 -855648819</internalNodes>
           <leafValues>
-            -3.6129125952720642e-01 2.0629832148551941e-01</leafValues></_>
+            -3.4803688526153564e-01 2.1789649128913879e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 107 -537765384 1060665394 2014012895 -1179616664
-            -22202433 -1074072677 -147975202 -1147076845</internalNodes>
+            0 -1 340 1112532642 1173963979 -811315745 99566887
+            -777275981 -439360269 -376451157 133893287</internalNodes>
           <leafValues>
-            -2.9889339208602905e-01 2.5862032175064087e-01</leafValues></_>
+            -3.0945461988449097e-01 2.2969539463520050e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 199 -328257785 -858932225 -530764942 -826874930
-            -82742922 -1671853892 -218380796 -169018736</internalNodes>
+            0 -1 297 185535267 790098739 711963921 -268439240 218058052
+            -294925 -1396768448 -2100139</internalNodes>
           <leafValues>
-            -3.1055119633674622e-01 2.3958165943622589e-01</leafValues></_>
+            -3.6581969261169434e-01 1.7462332546710968e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 154 494120195 870143859 -1647046746 -36192340
-            2139319279 803383587 -332148852 -175859072</internalNodes>
+            0 -1 292 -21844242 -6605322 -1616468484 -536912933
+            -1499165960 -1126293580 925141758 -20448289</internalNodes>
           <leafValues>
-            -2.8900969028472900e-01 2.5575104355812073e-01</leafValues></_>
+            -2.5863876938819885e-01 2.6582530140876770e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 282 -811560420 827561735 -12914945 -80101505
-            -1361111928 -1185616587 -1407676420 -16973965</internalNodes>
+            0 -1 304 522433969 772063152 -1143210539 -1383027464
+            -1405567063 -1431049791 221093305 -1933786908</internalNodes>
           <leafValues>
-            -2.4221476912498474e-01 3.2213848829269409e-01</leafValues></_>
+            -2.9382315278053284e-01 2.4171116948127747e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 28 -1807515438 -1923894982 -1525713421 -149168351
-            240714426 -1418935881 419048443 426584671</internalNodes>
+            0 -1 119 -202381694 -798150994 -5573602 -41028290
+            -1178601783 -77728283 -135801400 -145231988</internalNodes>
           <leafValues>
-            -3.4787160158157349e-01 2.1293328702449799e-01</leafValues></_>
+            -2.2170369327068329e-01 3.1273341178894043e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 147 -67165120 453708801 -1303483468 895300097
-            1246742261 -70442158 -982536969 1920335427</internalNodes>
+            0 -1 128 -203439442 280484343 -191502652 1082521539
+            1518288386 574050238 -360088850 -84153089</internalNodes>
           <leafValues>
-            -3.4275433421134949e-01 2.1697193384170532e-01</leafValues></_>
+            -3.2988098263740540e-01 2.0559535920619965e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 84 1234906919 2103279727 -1846517728 -34739694
-            2067706763 1171293376 -104744214 -776609560</internalNodes>
+            0 -1 36 -1473073466 1917855318 -364848516 1483753731
+            522944080 -1504285156 -282021901 -79439061</internalNodes>
           <leafValues>
-            -3.1936296820640564e-01 2.2989478707313538e-01</leafValues></_>
+            -2.9433536529541016e-01 2.1896927058696747e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 203 -148968905 1008481713 788164595 781877169 240125438
-            -1348980802 1087673598 -1963666822</internalNodes>
+            0 -1 185 -270062289 741719453 2088717183 -159405089
+            -1063525273 -201780627 -990061324 -189792529</internalNodes>
           <leafValues>
-            -2.6340115070343018e-01 2.8225165605545044e-01</leafValues></_>
+            -2.8305205702781677e-01 2.3085375130176544e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 292 1837891345 -1365117008 931935797 254075285
-            1304075707 781882527 284906609 -1998401051</internalNodes>
+            0 -1 64 781209199 -604801249 -137056771 -1644152576
+            1425768019 -4985945 -33825329 -352630170</internalNodes>
           <leafValues>
-            -3.0138608813285828e-01 2.5070127844810486e-01</leafValues></_>
+            -2.5803419947624207e-01 2.3583941161632538e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 31 -2141011328 549559667 -576755279 -1989065165
-            -1471060704 -1108160073 -825160949 47662087</internalNodes>
+            0 -1 218 -684139841 891109289 -2146903425 497252031
+            1814861009 1063463728 69532089 1061139391</internalNodes>
           <leafValues>
-            -4.3011611700057983e-01 1.7580580711364746e-01</leafValues></_>
+            -2.3609955608844757e-01 2.6694893836975098e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 244 -747375089 -747702293 -219779522 1890186598
-            -335684346 1718484847 1643894306 -206110753</internalNodes>
+            0 -1 195 1560171645 -1625665705 -1891663905 -1109320513
+            -127236 -67273237 -268804357 -5614422</internalNodes>
           <leafValues>
-            -2.3109740018844604e-01 3.2786485552787781e-01</leafValues></_>
+            -2.2031366825103760e-01 2.8743496537208557e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 26 -1784488175 -36553927 -1031147589 -369559501
-            125374437 -1648822347 8863969 -1498451769</internalNodes>
+            0 -1 289 -368723304 -1087131273 -2028144723 465693884
+            1523430298 -71370269 -1182790141 144305137</internalNodes>
           <leafValues>
-            -2.3490820825099945e-01 3.1162357330322266e-01</leafValues></_>
+            -3.6453738808631897e-01 1.7253066599369049e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 259 -1071476830 -1095595629 -1920078129 -1444498449
-            810365109 -21630982 -290653569 -392299569</internalNodes>
+            0 -1 199 787998475 677575591 -739252480 -285290066 508918644
+            1719481202 -179306992 -51386418</internalNodes>
           <leafValues>
-            -2.5611433386802673e-01 2.9074308276176453e-01</leafValues></_></weakClassifiers></_>
-    <!-- stage 10 -->
-    <_>
-      <maxWeakCount>30</maxWeakCount>
-      <stageThreshold>-1.3058989048004150e+00</stageThreshold>
-      <weakClassifiers>
+            -3.0859819054603577e-01 2.0732647180557251e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 262 -270610434 -134359075 -811399758 -681603633
-            -286489698 -45513244 -1344862513 227476639</internalNodes>
+            0 -1 14 -221256090 -30629334 -1778521617 -141047802 70346658
+            -453359515 1744520459 -268644849</internalNodes>
           <leafValues>
-            -1.0025274008512497e-01 5.5719470977783203e-01</leafValues></_>
+            -2.7200087904930115e-01 2.2423355281352997e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 104 -2097187 353744664 -1074283233 962461525 -17042946
-            2132074456 -185611768 173014862</internalNodes>
+            0 -1 142 1622928902 583970724 1109312096 1904539840
+            1969219012 1980786278 1948496000 1911025111</internalNodes>
           <leafValues>
-            -2.9774430394172668e-01 3.4969726204872131e-01</leafValues></_>
+            -3.3403554558753967e-01 1.9454947113990784e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 192 -201591309 322053939 -66051 -1150042305 -1967374172
-            720309079 -1929450275 -9437249</internalNodes>
+            0 -1 112 -295762925 915309558 -1095828421 1019540600
+            -1141749996 -1192305118 -17631630 -903815374</internalNodes>
           <leafValues>
-            -2.2600507736206055e-01 3.8218078017234802e-01</leafValues></_>
+            -3.0503559112548828e-01 2.0471774041652679e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 290 -1690568520 1023449340 21823732 -1646306859
-            -661660161 529059241 -845261571 -536871425</internalNodes>
+            0 -1 330 1865153393 185138952 -955431147 431881140 698022290
+            142707862 1294169361 217054693</internalNodes>
           <leafValues>
-            -2.8739321231842041e-01 2.8658962249755859e-01</leafValues></_>
+            -3.3315172791481018e-01 1.9509385526180267e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 253 -894497022 101363498 -1468636304 174491490
-            1306476909 100485583 -17240860 -50397265</internalNodes>
+            0 -1 50 1057818511 484285945 -170124612 1005093883
+            -1156844547 1371617765 -69795876 -1257986355</internalNodes>
           <leafValues>
-            -4.0346711874008179e-01 1.7318421602249146e-01</leafValues></_>
+            -2.9253959655761719e-01 2.2863319516181946e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 83 -318927617 2139044223 -1908122241 779509119
-            -1159705360 -13892400 239132095 -1357193897</internalNodes>
+            0 -1 216 567255330 -707734926 -925572514 -624041174
+            1433628799 21294608 156263627 -721438458</internalNodes>
           <leafValues>
-            -2.4370998144149780e-01 3.1787887215614319e-01</leafValues></_>
+            -2.8726491332054138e-01 2.1820212900638580e-01</leafValues></_></weakClassifiers></_>
+    <!-- stage 14 -->
+    <_>
+      <maxWeakCount>25</maxWeakCount>
+      <stageThreshold>-1.2997064590454102e+00</stageThreshold>
+      <weakClassifiers>
         <_>
           <internalNodes>
-            0 -1 240 -1372487695 -1464797736 -608961161 -539484303
-            -1347732485 -1107560232 -1770177028 -1397928683</internalNodes>
+            0 -1 296 -1372705244 -53892 -276885633 -1880289792
+            -620822785 -393217 -142745633 -268474549</internalNodes>
           <leafValues>
-            -2.9030051827430725e-01 2.7010890841484070e-01</leafValues></_>
+            -2.2954036295413971e-01 3.6702767014503479e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 162 -77617562 1723582851 -388105926 10740970 2075870464
-            2001443802 -264144166 1912602619</internalNodes>
+            0 -1 69 -10514724 -1625446526 -12058789 1028355882
+            -106955041 -6565701 -146018337 1599032783</internalNodes>
           <leafValues>
-            -3.6183983087539673e-01 2.2234350442886353e-01</leafValues></_>
+            -3.4712401032447815e-01 2.4896951019763947e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 209 1737993987 575323583 570599958 -1593901402
-            -537396969 800103342 -218367233 -210440396</internalNodes>
+            0 -1 76 -1430331393 -1752738851 226721247 1059010911
+            145900799 -1429468513 615153631 988436415</internalNodes>
           <leafValues>
-            -3.0187138915061951e-01 2.5218242406845093e-01</leafValues></_>
+            -3.3930867910385132e-01 2.3344205319881439e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 115 -3692022 -33948459 -1481085416 -169476374
-            -243802706 1464294676 -138677344 -135135404</internalNodes>
+            0 -1 270 -506747998 -1362439710 -745936942 -39853582
+            1334757315 -124603168 2009421779 -672148493</internalNodes>
           <leafValues>
-            -2.6393750309944153e-01 2.8237256407737732e-01</leafValues></_>
+            -2.8237146139144897e-01 2.7164348959922791e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 38 652099711 -1564843973 104523854 704662580 2126923816
-            -548581264 -351211922 -63803885</internalNodes>
+            0 -1 321 -4203299 1360986883 -3412641 956312066 -171979299
+            -315445 -1843240 -80744689</internalNodes>
           <leafValues>
-            -3.4199714660644531e-01 2.2430206835269928e-01</leafValues></_>
+            -2.1301591396331787e-01 3.5703513026237488e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 42 -1969279581 -1481414863 -1376914049 -1163909120
-            207957301 -1456248013 -347640417 -358126493</internalNodes>
+            0 -1 149 -689977121 -662996513 -1725966451 2068778907
+            -251700994 419184760 -93683841 -99614885</internalNodes>
           <leafValues>
-            -3.2226172089576721e-01 2.3534862697124481e-01</leafValues></_>
+            -2.3296064138412476e-01 3.1665518879890442e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 97 -721363152 486579872 1882454289 1434257045
-            1611566751 1289487287 996045691 1005540351</internalNodes>
+            0 -1 309 -285179488 -9441281 1043235368 -1342265362
+            874839541 2133912549 -1032021509 -1392732225</internalNodes>
           <leafValues>
-            -3.4691241383552551e-01 2.1465319395065308e-01</leafValues></_>
+            -2.8806942701339722e-01 2.2282725572586060e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 146 -613203450 1931612930 -221388928 2357067 -95798262
-            -1633004965 -1206355046 -1305281858</internalNodes>
+            0 -1 114 1475815183 2107337983 -224023574 -2176766
+            2147067887 1876795342 1818099336 1707645312</internalNodes>
           <leafValues>
-            -3.5142555832862854e-01 2.2679552435874939e-01</leafValues></_>
+            -3.1313076615333557e-01 2.1244764328002930e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 53 726466699 -783429313 -1320406822 -3624870 1498638047
-            293610405 -545215571 -171145013</internalNodes>
+            0 -1 329 -1657544715 -1145500528 997257077 503141457
+            763625151 -1430741832 153165617 266033296</internalNodes>
           <leafValues>
-            -2.8053104877471924e-01 2.5749957561492920e-01</leafValues></_>
+            -3.0358061194419861e-01 2.2090645134449005e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 258 -96033630 1940556686 -497037664 -252647058
-            703265613 1079474790 -142103350 1089273046</internalNodes>
+            0 -1 177 1147035391 -50398729 -8725505 1072834859 2090734480
+            -115489 -570483718 -270631374</internalNodes>
           <leafValues>
-            -3.5805869102478027e-01 1.9770637154579163e-01</leafValues></_>
+            -1.8830235302448273e-01 3.3752456307411194e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 29 801058311 -1581801242 219502516 -808469412 264711475
-            -2031926289 805127380 -840973936</internalNodes>
+            0 -1 299 -1356597325 -1388052592 -847288592 -314052611
+            -1927458391 -896273511 -1943219992 -855777356</internalNodes>
           <leafValues>
-            -3.1421071290969849e-01 2.3023897409439087e-01</leafValues></_>
+            -2.6349818706512451e-01 2.4316447973251343e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 172 -431184122 -2146638145 -899408814 -320144615
-            -413827291 -936008940 -1376277757 -856306909</internalNodes>
+            0 -1 91 1683333818 -928527617 73759575 1290403503 1430371123
+            -103067615 1875204903 1786229266</internalNodes>
           <leafValues>
-            -3.3034646511077881e-01 2.2980070114135742e-01</leafValues></_>
+            -3.6631527543067932e-01 1.7680935561656952e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 296 -1934886608 -1103642657 -1616127841 2141970916
-            12401112 -606080117 -28750412 -975218195</internalNodes>
+            0 -1 75 -723572486 1398781951 2102550384 -15679489
+            1677216988 -883140642 -552403973 -619446289</internalNodes>
           <leafValues>
-            -3.0468633770942688e-01 2.4846823513507843e-01</leafValues></_>
+            -2.4558630585670471e-01 2.6674869656562805e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 137 1828669055 -890173322 1056472031 1383623540
-            -356497848 -275776488 -319784148 -45023438</internalNodes>
+            0 -1 31 -909118669 -1568492624 -15803021 -1602693664
+            1276055058 203659013 2128997939 -285229957</internalNodes>
           <leafValues>
-            -2.7311590313911438e-01 2.6826277375221252e-01</leafValues></_>
+            -3.1990760564804077e-01 1.9987310469150543e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 9 1255206898 -1667881507 -10989766 54528930 1868912080
-            1497103356 -1096470729 195839511</internalNodes>
+            0 -1 153 -641211774 456884155 -371067230 828505907
+            1660797068 1414657751 -654513950 -260707437</internalNodes>
           <leafValues>
-            -3.6629125475883484e-01 2.0582148432731628e-01</leafValues></_>
+            -2.5050690770149231e-01 2.5742626190185547e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 221 -374953039 110804926 -627248196 1059075576
-            -271092824 -1449292838 -306539616 -1950680360</internalNodes>
+            0 -1 24 -229906089 -739840258 535355359 -1513324470
+            -706239233 -106463539 396649887 -2030041851</internalNodes>
           <leafValues>
-            -2.7446079254150391e-01 2.6614543795585632e-01</leafValues></_>
+            -2.5204655528068542e-01 2.6508477330207825e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 77 1079656456 1450316376 -44560086 -86675865 821811859
-            -203750610 1644870683 862142514</internalNodes>
+            0 -1 16 -956904237 -900393 744684798 440408308 1474759700
+            2144675413 -1203478660 -15336458</internalNodes>
           <leafValues>
-            -4.1938367486000061e-01 1.8087086081504822e-01</leafValues></_>
+            -2.3463597893714905e-01 2.7154859900474548e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 0 -290783281 -303164749 -1470447878 -1487432078
-            916915428 -88877852 1774133328 -992512778</internalNodes>
+            0 -1 245 -53498110 -768948404 114700466 -262216722
+            1751010824 1074124611 1456993248 1358295782</internalNodes>
           <leafValues>
-            -2.6362594962120056e-01 2.8109744191169739e-01</leafValues></_>
+            -3.6311113834381104e-01 1.7788498103618622e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 234 -756036050 839304974 -287378334 -278205702
-            1541888379 252445922 1089229910 1534066638</internalNodes>
+            0 -1 103 -2450246 -1080320589 1308138658 825785752 482925554
+            487604154 -283631617 -72380437</internalNodes>
           <leafValues>
-            -3.4634828567504883e-01 2.1581955254077911e-01</leafValues></_>
+            -2.4650368094444275e-01 2.5755673646926880e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 276 855880616 863230344 1428139679 995299387
-            -1190999286 -2031656420 -1089224709 393285777</internalNodes>
+            0 -1 126 1058870580 903144469 -83886593 -1392513810
+            -1611137039 -33792596 2145253024 -1402167248</internalNodes>
           <leafValues>
-            -3.6159241199493408e-01 2.0310276746749878e-01</leafValues></_>
+            -2.3422972857952118e-01 2.8370600938796997e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 311 -1512047005 -894771811 -1683823949 -598542090
-            1995129382 -1899059137 1498537061 -838863787</internalNodes>
+            0 -1 222 70522484 -1663270860 2006973951 737044894 734095092
+            2113182189 -1113780932 -1398140368</internalNodes>
           <leafValues>
-            -2.8326958417892456e-01 2.6241222023963928e-01</leafValues></_>
+            -4.2064115405082703e-01 1.4178343117237091e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 315 -1885077515 -1147345968 765009497 190991824
-            -1880224543 -1444116296 170661041 -1880099595</internalNodes>
+            0 -1 326 1107681440 1184465408 1697245882 -575681545
+            -1209274896 -441716737 -274206977 -1497652999</internalNodes>
           <leafValues>
-            -2.7807191014289856e-01 2.6050725579261780e-01</leafValues></_>
+            -2.6777487993240356e-01 2.3421689867973328e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 135 -678450904 253998378 1239066322 -181932174
-            1262701314 1057893524 -413531308 -638649353</internalNodes>
+            0 -1 238 -876378345 -2002059937 -402854058 2047008718
+            -977546123 96466271 -724044704 -855902004</internalNodes>
           <leafValues>
-            -3.3198201656341553e-01 2.2709015011787415e-01</leafValues></_>
+            -2.6567915081977844e-01 2.4086490273475647e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 34 -581179905 -1848462196 1945061311 -5371768
-            -323621137 -1263209313 1589634526 -1983639545</internalNodes>
+            0 -1 215 -939802373 1936008783 249448665 -1680407978
+            1336956126 721695808 1217691803 968323227</internalNodes>
           <leafValues>
-            -2.1172577142715454e-01 3.3727011084556580e-01</leafValues></_></weakClassifiers></_>
-    <!-- stage 11 -->
+            -2.6731696724891663e-01 2.3347604274749756e-01</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 235 1312794114 5408 -1306041678 -1593904412 2071675925
+            373612661 1106728032 -51052590</internalNodes>
+          <leafValues>
+            -4.5101743936538696e-01 1.3724696636199951e-01</leafValues></_></weakClassifiers></_>
+    <!-- stage 15 -->
     <_>
-      <maxWeakCount>28</maxWeakCount>
-      <stageThreshold>-1.5291974544525146e+00</stageThreshold>
+      <maxWeakCount>26</maxWeakCount>
+      <stageThreshold>-1.3585999011993408e+00</stageThreshold>
       <weakClassifiers>
         <_>
           <internalNodes>
-            0 -1 118 1460139419 453084545 822327865 822292283 352929169
-            417272919 135004047 924844031</internalNodes>
+            0 -1 99 -16253125 -1862205680 924703251 353705495 18354879
+            -1646443061 1061106495 521109375</internalNodes>
           <leafValues>
-            -8.1135094165802002e-02 5.6568491458892822e-01</leafValues></_>
+            -2.6204770803451538e-01 3.2944434881210327e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 80 -715128994 1934810962 -672407682 -201597282
-            -35692578 809635668 -268435489 2147483551</internalNodes>
+            0 -1 106 1589402879 2111243421 -1921360385 498991519
+            -1430778630 -1095235424 -299958273 -1415968598</internalNodes>
           <leafValues>
-            -3.0913391709327698e-01 3.3743736147880554e-01</leafValues></_>
+            -2.9923591017723083e-01 2.6061478257179260e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 247 1122941951 1555757531 -694977567 -540019318
-            137302463 470541003 1136607934 1306525407</internalNodes>
+            0 -1 256 -269500670 -1934972022 -212386444 -340983920
+            -840985607 216660013 -838930280 -855967046</internalNodes>
           <leafValues>
-            -3.1006491184234619e-01 3.1824222207069397e-01</leafValues></_>
+            -3.1109735369682312e-01 2.4578146636486053e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 260 -720124792 -536901237 1570357663 -1650861895
-            -552270619 -68301133 1302024703 79667599</internalNodes>
+            0 -1 290 -785411968 -793272784 -1244701525 -1863077704
+            -252760056 -138438225 -325343096 -1934628726</internalNodes>
           <leafValues>
-            -3.3839857578277588e-01 2.5523734092712402e-01</leafValues></_>
+            -3.1990429759025574e-01 2.4755740165710449e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 17 -8193062 -6097966 -1548746898 -379066394 143198346
-            -645407521 12583050 -472923985</internalNodes>
+            0 -1 210 -69535757 858989363 -101122561 -1154744385
+            -1426397852 787417871 -1394279747 -1049665</internalNodes>
           <leafValues>
-            -2.4971115589141846e-01 3.2822373509407043e-01</leafValues></_>
+            -2.4644587934017181e-01 3.1389617919921875e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 237 -825768185 724487963 -390073602 -330379374
-            1107247415 83879931 -993921692 -452988933</internalNodes>
+            0 -1 33 44994211 548056274 1050609429 -269234960 235348991
+            -1461066343 133104023 -536881691</internalNodes>
           <leafValues>
-            -3.0709245800971985e-01 2.5717419385910034e-01</leafValues></_>
+            -3.0615699291229248e-01 2.1291562914848328e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 58 -824653104 303085300 -1502438950 676395390
-            1255626832 486565974 -815202689 -79167553</internalNodes>
+            0 -1 169 -19927354 -998541361 -1031864744 548925694
+            2058738946 1086813587 -117441590 -236978209</internalNodes>
           <leafValues>
-            -3.6309060454368591e-01 2.1628698706626892e-01</leafValues></_>
+            -2.8440350294113159e-01 2.4974717199802399e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 67 1465723394 105884335 67529631 1199566589 -1622165645
-            1811892772 1549268950 1652352758</internalNodes>
+            0 -1 225 -403723614 -137498998 12815458 -201331990
+            -143659953 -292815449 -1025137984 -146418144</internalNodes>
           <leafValues>
-            -4.2343840003013611e-01 1.6860494017601013e-01</leafValues></_>
+            -2.7793189883232117e-01 2.1837951242923737e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 185 148088327 717657079 -1158484046 -2098532510
-            1870465024 1417516115 -834205 -218760204</internalNodes>
+            0 -1 8 -245367841 -2134021 1724214226 -33737026 -546361345
+            2104391438 -235029522 1894053750</internalNodes>
           <leafValues>
-            -3.6911985278129578e-01 2.0653814077377319e-01</leafValues></_>
+            -2.3921246826648712e-01 2.5940048694610596e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 300 -461242368 1477725653 -1215242820 -90145126
-            1009057732 -704735 -1141055496 -1162708353</internalNodes>
+            0 -1 110 -50344201 2021002463 -295113026 503381792
+            1802897488 -1216649 -649569682 -29165030</internalNodes>
           <leafValues>
-            -3.3464974164962769e-01 2.3336097598075867e-01</leafValues></_>
+            -2.3499047756195068e-01 2.6225870847702026e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 293 -1423237359 -1789315824 -574109707 -1107438219
-            -1363603597 -872691976 -1657075536 -1933638287</internalNodes>
+            0 -1 122 -789934932 1559100927 -1917276468 -484037
+            -573975107 1557186265 -1157693928 -13043150</internalNodes>
           <leafValues>
-            -3.1273457407951355e-01 2.2250117361545563e-01</leafValues></_>
+            -2.7699887752532959e-01 2.1751758456230164e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 194 -144708057 1699343849 -1838157252 -177211402
-            -159396385 625472608 -135793676 -521076854</internalNodes>
+            0 -1 243 -1356859599 -2071938592 -1711301131 -1108552207
+            1067300539 -1648756997 -1988182799 -2007106383</internalNodes>
           <leafValues>
-            -2.3151670396327972e-01 3.2311838865280151e-01</leafValues></_>
+            -2.2797892987728119e-01 2.6686671376228333e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 168 -1931608011 913325143 -171254849 266627963
-            -2035524252 -69309961 -81258276 -98535933</internalNodes>
+            0 -1 100 1414807752 -136118094 1570099167 1610550975
+            1428132782 -1565038658 1393646523 59441770</internalNodes>
           <leafValues>
-            -2.9178491234779358e-01 2.4896363914012909e-01</leafValues></_>
+            -3.6224871873855591e-01 1.7005157470703125e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 91 1087671428 82841500 -823391220 -1623396996
-            -102804027 1314177621 -1141613796 -1074263479</internalNodes>
+            0 -1 198 -1372390622 -1105023217 43974655 -1372390929
+            1012170358 -1352684673 229665733 1794436783</internalNodes>
           <leafValues>
-            -3.8546600937843323e-01 1.7542295157909393e-01</leafValues></_>
+            -3.7763473391532898e-01 1.4173112809658051e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 159 -933240178 -1878596882 1715175556 -1194366298
-            411894039 268454833 -470873276 719547915</internalNodes>
+            0 -1 316 638615286 -1109868352 524464629 -1113590375
+            964831210 -1371914704 153292152 -1346434008</internalNodes>
           <leafValues>
-            -3.2228979468345642e-01 2.1430800855159760e-01</leafValues></_>
+            -3.1874561309814453e-01 1.9032885134220123e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 220 -939528673 -1404420134 -369182724 1002367802
-            15711733 -1410089155 1960793528 -2001995142</internalNodes>
+            0 -1 305 -269486329 -1908425238 -1208756943 -323096206
+            -1547964669 -1433756185 -1767970460 -924320141</internalNodes>
           <leafValues>
-            -2.3454265296459198e-01 3.0028054118156433e-01</leafValues></_>
+            -2.5788185000419617e-01 2.3276108503341675e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 113 536155908 470828324 -1369532674 -1364256937
-            965751798 -35376543 78916068 750088039</internalNodes>
+            0 -1 193 918434045 498645434 798903545 -1142289332 784082164
+            1851118315 682499324 -340128680</internalNodes>
           <leafValues>
-            -4.0617641806602478e-01 1.7761451005935669e-01</leafValues></_>
+            -2.8957661986351013e-01 2.0316053926944733e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 35 -2071666137 -5603018 -1985288769 -1434200 1335921899
-            -1427144213 -1685518963 -1157538765</internalNodes>
+            0 -1 55 -905778490 67121822 -1743743400 -2012053637
+            -1636832684 -917214628 -17762321 2135162719</internalNodes>
           <leafValues>
-            -2.4697369337081909e-01 2.9498186707496643e-01</leafValues></_>
+            -3.3608233928680420e-01 1.7717513442039490e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 229 -288895194 586300718 -1428684760 -123278042
-            -121959099 946274053 -1125681616 1348531058</internalNodes>
+            0 -1 29 -1758265669 915073431 -283673347 -948315937 86215958
+            -1624023241 90637669 -823733761</internalNodes>
           <leafValues>
-            -4.4196075201034546e-01 1.6939437389373779e-01</leafValues></_>
+            -2.1280290186405182e-01 2.7446863055229187e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 21 -1431908781 2021291639 -1130434561 980837616
-            575372375 -335353565 -1127443082 -8913481</internalNodes>
+            0 -1 285 -8461782 -86087006 -687954246 -521941938 -614269955
+            1611715303 -151198213 1958209278</internalNodes>
           <leafValues>
-            -2.6150795817375183e-01 2.7675113081932068e-01</leafValues></_>
+            -2.6345619559288025e-01 2.2300323843955994e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 68 -1163937995 319737271 1308060341 -1120611591
-            215961812 -849912353 -825672464 -121636649</internalNodes>
+            0 -1 212 -1832397616 -766332258 -412702245 -1292380803
+            1220365911 -822484818 -282100849 1398793395</internalNodes>
           <leafValues>
-            -2.0028464496135712e-01 3.5346552729606628e-01</leafValues></_>
+            -2.9608255624771118e-01 2.0772157609462738e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 112 -1550874873 68414247 420172119 -1144260794
-            -508579405 -134226281 -772565676 -204480722</internalNodes>
+            0 -1 62 -872994057 1071450172 -1104786213 -317692670
+            -67746216 -50513552 -88453541 -128910506</internalNodes>
           <leafValues>
-            -2.3316873610019684e-01 3.1222426891326904e-01</leafValues></_>
+            -2.5465941429138184e-01 2.4114270508289337e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 218 -541341454 531709016 -1735251873 1326185481
-            -1933801064 801776562 1154066423 1474264822</internalNodes>
+            0 -1 10 81939939 183556950 -539144585 -353355856 165875573
+            -1782603781 -338732685 -491295903</internalNodes>
           <leafValues>
-            -2.6953682303428650e-01 2.8109839558601379e-01</leafValues></_>
+            -3.2701194286346436e-01 1.8006059527397156e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 181 1280835701 -19635873 -1961789445 -282569314
-            2036092788 -1093054601 -151512323 -1347805666</internalNodes>
+            0 -1 134 1886692082 -1729102165 542420273 631107582
+            -546201661 1476403972 -169532509 1997277933</internalNodes>
           <leafValues>
-            -2.9192847013473511e-01 2.4838224053382874e-01</leafValues></_>
+            -3.5394954681396484e-01 1.6798554360866547e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 95 -311496552 764872328 -498934241 504728371
-            -1669213988 -1084285404 -22094113 977657810</internalNodes>
+            0 -1 311 -1700548176 -1715829716 -1343244964 -1155942204
+            -53954163 -27257407 -1547772419 -2131951339</internalNodes>
           <leafValues>
-            -3.2798394560813904e-01 2.1226845681667328e-01</leafValues></_>
+            -3.2425084710121155e-01 1.8224255740642548e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 309 -830243037 -455709770 -1109557600 -394303915
-            1283690960 229296318 285572161 -1936864027</internalNodes>
+            0 -1 203 -490033404 -1438717153 1991554832 -1507676246
+            801593156 -1468572866 -17199788 -391776096</internalNodes>
           <leafValues>
-            -2.9578369855880737e-01 2.4679656326770782e-01</leafValues></_>
+            -3.5948479175567627e-01 1.6648940742015839e-01</leafValues></_></weakClassifiers></_>
+    <!-- stage 16 -->
+    <_>
+      <maxWeakCount>29</maxWeakCount>
+      <stageThreshold>-1.1730608940124512e+00</stageThreshold>
+      <weakClassifiers>
         <_>
           <internalNodes>
-            0 -1 202 -353374409 -1910657629 -153750156 -291312600
-            -824232155 -1323582188 -1830135484 -1029119357</internalNodes>
+            0 -1 338 -793735168 -175047596 -35594563 -1145503875
+            -99305999 -8398955 -71640065 -71630853</internalNodes>
           <leafValues>
-            -3.0753603577613831e-01 2.2499974071979523e-01</leafValues></_>
+            -2.0565655827522278e-01 3.6647084355354309e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 150 1861152279 336385887 -1598237261 1532541780
-            717032533 845016530 -1129812228 -567126192</internalNodes>
+            0 -1 58 -1388802 -135286154 -1154293889 689875534
+            -1412562742 -2424758 -81338657 -13958585</internalNodes>
           <leafValues>
-            -2.7896767854690552e-01 2.5912684202194214e-01</leafValues></_></weakClassifiers></_>
-    <!-- stage 12 -->
-    <_>
-      <maxWeakCount>32</maxWeakCount>
-      <stageThreshold>-1.3275781869888306e+00</stageThreshold>
-      <weakClassifiers>
+            -2.5342568755149841e-01 2.9973617196083069e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 235 -9764865 -604078086 -173773889 -2987398 1279545343
-            -557388648 1149200335 1195863143</internalNodes>
+            0 -1 273 -424689729 1793992298 -69797944 -47701166 147718827
+            217783198 1417368059 1174403067</internalNodes>
           <leafValues>
-            -2.8027681633830070e-02 5.9074550867080688e-01</leafValues></_>
+            -3.0622813105583191e-01 2.2849719226360321e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 55 -715992866 -553046580 -170277985 -572962233
-            -202911505 -562080269 -271361 2136426523</internalNodes>
+            0 -1 162 -421534290 -481301273 -343938830 -202899458
+            -756039285 1195863875 -218106116 -169345076</internalNodes>
           <leafValues>
-            -2.9094350337982178e-01 3.2474684715270996e-01</leafValues></_>
+            -2.2961020469665527e-01 2.8787249326705933e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 2 -285213773 -97321424 -537973381 -1342251019 249102355
-            186786323 -1879110913 -269489669</internalNodes>
+            0 -1 334 -8389857 -2043769330 -69534958 -2010610142
+            -19399681 -860957441 -40118413 -59769989</internalNodes>
           <leafValues>
-            -2.4952219426631927e-01 3.3645749092102051e-01</leafValues></_>
+            -2.6856726408004761e-01 2.2150200605392456e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 274 -5251811 -46589657 -577170147 -1649982203 -147523
-            -67650657 -307360312 -1945170545</internalNodes>
+            0 -1 342 -4194317 -1097160528 1129927121 -572583600
+            -1480608773 -1388663112 1299799505 -840960547</internalNodes>
           <leafValues>
-            -2.2803187370300293e-01 3.6403229832649231e-01</leafValues></_>
+            -1.8076962232589722e-01 3.2131236791610718e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 132 1587350780 -6418628 -1073864867 -604037841
-            -21053701 -1195406672 784076557 -1342501334</internalNodes>
+            0 -1 127 1407140879 -538213336 -41173601 -854589681
+            -689245505 -92547849 1284158459 168487359</internalNodes>
           <leafValues>
-            -2.9213908314704895e-01 2.7659067511558533e-01</leafValues></_>
+            -3.0466887354850769e-01 1.9067247211933136e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 176 -826544217 -1431112397 -488065488 540212786
-            -722778748 1157429871 -270294508 -520884270</internalNodes>
+            0 -1 204 -337910785 -18153601 -805309444 1917893626
+            -11014155 -1074659969 -67119620 -76515328</internalNodes>
           <leafValues>
-            -3.5402128100395203e-01 2.1517892181873322e-01</leafValues></_>
+            -1.9108071923255920e-01 2.9606026411056519e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 87 712975879 79833691 -1361412946 686460060 -691335585
-            -125978095 -285512546 -1430258133</internalNodes>
+            0 -1 4 -1374747297 -1672142509 -690225283 -61276329
+            113970219 -1175502287 1247706719 -545947789</internalNodes>
           <leafValues>
-            -3.1391125917434692e-01 2.2734560072422028e-01</leafValues></_>
+            -2.3365408182144165e-01 2.5229984521865845e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 200 -976172866 286760680 6735455 198928110 1074026973
-            990905122 10809743 255401983</internalNodes>
+            0 -1 27 -587211009 616612637 -996282177 1350760431 743900160
+            -183233459 -1076131105 -546181281</internalNodes>
           <leafValues>
-            -3.5261881351470947e-01 2.0989060401916504e-01</leafValues></_>
+            -2.4930721521377563e-01 2.2612276673316956e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 224 774125429 -1154154632 -439675595 -1111523364
-            1012643517 -1454645 798207228 -1128575640</internalNodes>
+            0 -1 286 -8147552 -1625113614 1286228632 -353481008
+            822466289 1966144435 -285295617 1291708404</internalNodes>
           <leafValues>
-            -2.6199585199356079e-01 2.7558091282844543e-01</leafValues></_>
+            -2.7701693773269653e-01 2.1534711122512817e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 251 -487657822 48661756 -659241758 -135899942
-            1153834238 10993310 1170301815 1424455655</internalNodes>
+            0 -1 308 490673157 1427765332 -1746674373 -1860839277
+            290395277 -1685050565 -1197556801 -1465123113</internalNodes>
           <leafValues>
-            -4.2886912822723389e-01 1.5836857259273529e-01</leafValues></_>
+            -2.6409074664115906e-01 2.2850526869297028e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 61 721311231 -1653716997 -1990311447 531501487
-            -1965404323 -67478251 171464059 184576600</internalNodes>
+            0 -1 125 298128335 -187922961 861671868 -33787650
+            -1141802097 516205188 -270663748 -255530164</internalNodes>
           <leafValues>
-            -3.8873490691184998e-01 1.7470200359821320e-01</leafValues></_>
+            -2.7780425548553467e-01 2.1246871352195740e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 57 327418278 390873324 -1341550100 -1277569843
-            890828715 1352696428 762946218 871965384</internalNodes>
+            0 -1 141 1375730695 627907893 -51644163 -268568093
+            -503710475 -23415107 2095341716 -1406671321</internalNodes>
           <leafValues>
-            -4.1405329108238220e-01 1.7622730135917664e-01</leafValues></_>
+            -2.1832446753978729e-01 2.5456944108009338e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 313 1356549140 -1631210850 -1129431843 -1204505275
-            -93539215 -1074227267 -386080853 -84902083</internalNodes>
+            0 -1 83 1479937050 1527130690 779251298 -1753555086
+            738741914 1273777055 1391749242 -269504542</internalNodes>
           <leafValues>
-            -2.7681437134742737e-01 2.4316167831420898e-01</leafValues></_>
+            -3.3689221739768982e-01 1.6092190146446228e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 157 -488643058 180875078 -329274718 -236520514
-            -1068514035 1145270019 1940253924 1625680036</internalNodes>
+            0 -1 227 -940593661 706414255 -1899740490 -1493243222
+            -129536651 1683451935 -731306 -185673886</internalNodes>
           <leafValues>
-            -3.7754905223846436e-01 1.7737720906734467e-01</leafValues></_>
+            -2.9129263758659363e-01 1.9923964142799377e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 318 1568653099 -1486684233 -270730127 -320215680
-            -1480112719 -1448552587 444420880 -859837569</internalNodes>
+            0 -1 268 1214682914 -1107497954 -50963712 -36048662
+            2122380642 -1060772926 494353798 1572299255</internalNodes>
           <leafValues>
-            -2.4140998721122742e-01 2.7932175993919373e-01</leafValues></_>
+            -3.1202444434165955e-01 1.9046534597873688e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 189 -17905025 1950769147 -402672769 2131932059
-            251095909 -1377736845 -268624424 1935896624</internalNodes>
+            0 -1 51 -526218504 -655159201 -1651243249 -1083324983
+            -1061447364 -1165127435 -1313734326 587291393</internalNodes>
           <leafValues>
-            -2.4894605576992035e-01 2.6565098762512207e-01</leafValues></_>
+            -3.1355553865432739e-01 1.8095606565475464e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 56 -229980658 1379962893 -378530289 -1286386082
-            541532620 -136587009 1094085135 657713951</internalNodes>
+            0 -1 138 -16841511 1409112829 -1225064449 -144016265
+            -285320164 -3236505 -109781282 -16712598</internalNodes>
           <leafValues>
-            -2.9520252346992493e-01 2.2449728846549988e-01</leafValues></_>
+            -2.2392266988754272e-01 2.6122003793716431e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 271 -383212128 -6160449 -283244184 -1365334076
-            762609077 1768025015 -304497187 -1344499269</internalNodes>
+            0 -1 187 1811899910 1188020131 -427336262 681310146
+            1283408900 1086641242 -201490620 -67766399</internalNodes>
           <leafValues>
-            -2.8447866439819336e-01 2.4520753324031830e-01</leafValues></_>
+            -3.1929084658622742e-01 1.8652729690074921e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 212 -823677149 33812366 63268002 -1196492664 759909893
-            73716507 -306223978 -151718043</internalNodes>
+            0 -1 92 -1566333438 -1239270996 -1135107763 -1114249923
+            -536288113 -707011874 -1302858034 -1326459420</internalNodes>
           <leafValues>
-            -3.2939437031745911e-01 2.0377136766910553e-01</leafValues></_>
+            -2.6035124063491821e-01 2.1769930422306061e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 312 -1374019853 713820810 -669067463 -2043769806
-            -847767619 -1963069954 1575449037 -450464140</internalNodes>
+            0 -1 346 139396887 44502064 537054341 437190617 719719428
+            -793069360 -663781634 -1368724662</internalNodes>
           <leafValues>
-            -3.0366918444633484e-01 2.2024095058441162e-01</leafValues></_>
+            -2.9000744223594666e-01 1.9265611469745636e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 114 -470316922 717621094 -923928028 -172110089
-            -175398463 2009855399 -194461440 -243275802</internalNodes>
+            0 -1 265 -250095070 2097181951 1243884576 263172296
+            1408750261 289431972 2143664050 754312418</internalNodes>
           <leafValues>
-            -2.6190644502639771e-01 2.6647549867630005e-01</leafValues></_>
+            -2.8242233395576477e-01 2.0532251894474030e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 140 1951769299 1434447053 -1336849665 -721425681
-            -78677193 -2902011 2045245095 -24300714</internalNodes>
+            0 -1 206 620238429 1536959391 -6758403 535174905 1047149052
+            921712776 -1362093858 -5615942</internalNodes>
           <leafValues>
-            -2.2465880215167999e-01 3.1657159328460693e-01</leafValues></_>
+            -2.5363510847091675e-01 2.1782724559307098e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 267 -861210968 688568240 -1004941864 -35890713
-            -662335344 8503434 1128813796 1162868189</internalNodes>
+            0 -1 340 -943787582 1390929134 2007850965 1575994853
+            -1768757774 -404895814 -1244790789 -949809617</internalNodes>
           <leafValues>
-            -4.0748140215873718e-01 1.7012281715869904e-01</leafValues></_>
+            -2.1436288952827454e-01 2.7378448843955994e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 8 1909956778 -958730002 73759065 117326543 -170462666
-            -1638796928 -144999309 1180628626</internalNodes>
+            0 -1 21 -69011461 -6135840 -472170147 1668209188 225380825
+            -1694527907 15597764 -958430977</internalNodes>
           <leafValues>
-            -3.5050147771835327e-01 1.8371912837028503e-01</leafValues></_>
+            -1.7761918902397156e-01 2.9578888416290283e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 156 -1007695481 -1609761269 -218186094 -1297941718
-            1501545350 1348355905 -785383567 -535441850</internalNodes>
+            0 -1 63 2145317171 -1615352016 -337285123 796003570
+            525665077 -1366597353 -286321259 -903181106</internalNodes>
           <leafValues>
-            -2.8428241610527039e-01 2.3429898917675018e-01</leafValues></_>
+            -2.3187226057052612e-01 2.3607331514358521e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 277 -1088815371 1060734832 -4223497 1069000375
-            -1138325508 -23580996 -1751106129 -1447097814</internalNodes>
+            0 -1 191 -495277538 434272486 -501947458 526441212
+            -1496864652 -1100739471 -792975140 -619624103</internalNodes>
           <leafValues>
-            -2.0420564711093903e-01 3.2137596607208252e-01</leafValues></_>
+            -2.5271594524383545e-01 2.1627274155616760e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 10 1861672606 -668397946 1208024407 1141008467
-            793079834 440603748 -705639574 -48042237</internalNodes>
+            0 -1 303 -805569741 680173544 -709755055 -1378886831
+            -1378621171 -1963028225 -1398473520 -2003306283</internalNodes>
           <leafValues>
-            -2.7496239542961121e-01 2.4548499286174774e-01</leafValues></_>
+            -2.5094878673553467e-01 2.2561351954936981e-01</leafValues></_></weakClassifiers></_>
+    <!-- stage 17 -->
+    <_>
+      <maxWeakCount>29</maxWeakCount>
+      <stageThreshold>-1.3573215007781982e+00</stageThreshold>
+      <weakClassifiers>
         <_>
           <internalNodes>
-            0 -1 283 -992769979 767790999 -48337487 2140880143 215229748
-            418870965 -320966916 1188940671</internalNodes>
+            0 -1 348 -34622032 -173542149 -656574992 -572523139
+            -1051863563 -863055138 -570565121 -572522497</internalNodes>
           <leafValues>
-            -2.7034837007522583e-01 2.4777430295944214e-01</leafValues></_>
+            -1.2100619077682495e-01 4.5341226458549500e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 254 -1532809423 -1493812843 -1351098395 -172312296
-            -515160205 -1498547284 268291320 -1426238432</internalNodes>
+            0 -1 170 -77594885 1060339475 -2139947270 807665435
+            399475712 1041203007 -251923474 1920204539</internalNodes>
           <leafValues>
-            -2.8834709525108337e-01 2.2686660289764404e-01</leafValues></_>
+            -2.7747187018394470e-01 2.7045109868049622e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 298 -3221657 908227842 -305164460 942829106 -357061387
-            -1565722789 -9463718 -360710886</internalNodes>
+            0 -1 316 899790847 -4383371 -1087668481 -16941 -2034717186
+            -1078292832 -1346650113 -1079270742</internalNodes>
           <leafValues>
-            -2.2364138066768646e-01 3.1509658694267273e-01</leafValues></_>
+            -2.1022592484951019e-01 3.3468201756477356e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 93 -735960950 -170126554 1909113855 -23709394
-            -1542321238 -737632549 -361625941 867181313</internalNodes>
+            0 -1 0 -279969793 -1 -292628226 -268437778 267325424
+            -880878352 216613332 -268443403</internalNodes>
           <leafValues>
-            -3.6416807770729065e-01 1.8943277001380920e-01</leafValues></_>
+            -2.3492383956909180e-01 2.7808070182800293e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 297 -1427114189 -1498618581 -224896028 -1392720912
-            -1096677881 -972078302 -136092556 -1000345005</internalNodes>
+            0 -1 68 -656374532 -590854788 -1141031683 -539111939
+            -286464771 -705056771 -1611816999 -14883</internalNodes>
           <leafValues>
-            -3.1630918383598328e-01 2.1302369236946106e-01</leafValues></_></weakClassifiers></_>
-    <!-- stage 13 -->
-    <_>
-      <maxWeakCount>36</maxWeakCount>
-      <stageThreshold>-1.3241410255432129e+00</stageThreshold>
-      <weakClassifiers>
+            -1.9249799847602844e-01 3.0399987101554871e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 264 -1886982258 -671648799 -570864297 -606221228
-            -1899852152 -3292975 236208719 1600077909</internalNodes>
+            0 -1 276 258465713 462159759 15965472 2103961046 1280627108
+            -268435525 2026765496 -1025</internalNodes>
           <leafValues>
-            -7.9810082912445068e-02 5.2391374111175537e-01</leafValues></_>
+            -2.4311806261539459e-01 2.4972844123840332e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 226 -85990657 570624531 -67109121 992976191 -386251554
-            -1965159927 -83923475 -1048581</internalNodes>
+            0 -1 144 -419434834 1657591678 -455923284 -5386498
+            -1216358521 1371620740 2013263792 1442179056</internalNodes>
           <leafValues>
-            -1.8287384510040283e-01 4.4005623459815979e-01</leafValues></_>
+            -2.8065973520278931e-01 2.2235853970050812e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 278 -37758029 -1146357328 -206212751 -572669447
-            -3147333 -1147409733 -67110471 -1714697285</internalNodes>
+            0 -1 73 -255016286 -723652609 1892807313 -35652917
+            -568542589 1275961346 -142606437 1154327186</internalNodes>
           <leafValues>
-            -2.0388080179691315e-01 4.2895537614822388e-01</leafValues></_>
+            -3.2926952838897705e-01 1.6259366273880005e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 145 -183247173 1023475216 1027163441 1527839249
-            1017224859 1738217629 1060840379 1065315199</internalNodes>
+            0 -1 167 3384620 904725092 -504505106 -10623284 1932031989
+            -2330160 -1248468832 -1126046076</internalNodes>
           <leafValues>
-            -3.3740916848182678e-01 2.1529236435890198e-01</leafValues></_>
+            -2.8664493560791016e-01 2.2413903474807739e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 103 481318143 -134278060 -1749526563 -1078064995
-            -1372435270 -1162474278 -358945793 -1431173974</internalNodes>
+            0 -1 284 -1026571858 -1026883601 -488570970 -492639282
+            1508886477 -1060260628 -1479752754 1962733263</internalNodes>
           <leafValues>
-            -2.8765675425529480e-01 2.5110965967178345e-01</leafValues></_>
+            -2.9589930176734924e-01 1.9247196614742279e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 268 -805831759 -302189077 -591401807 -305135631
-            144606625 -1936723969 -992408563 -855769927</internalNodes>
+            0 -1 341 -78686238 -2027290630 -378837808 -570440104
+            1632253693 101381112 1498878421 -841095201</internalNodes>
           <leafValues>
-            -2.2018201649188995e-01 3.1721305847167969e-01</leafValues></_>
+            -2.3898813128471375e-01 2.4848675727844238e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 20 -534756686 1380106992 -2462279 -33757488 28591869
-            -456875269 -1610624779 -1051657</internalNodes>
+            0 -1 108 -1971972962 -8706569 2096520703 594690133
+            -1434911233 -341858 -1163260049 -1440077729</internalNodes>
           <leafValues>
-            -2.6303508877754211e-01 2.5412750244140625e-01</leafValues></_>
+            -2.8525370359420776e-01 2.0041574537754059e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 175 1342137858 36560521 -895533800 683603905 1263879488
-            1146407324 -1450126 -537788681</internalNodes>
+            0 -1 113 1339985527 -934921 -1409937733 -895471966
+            1451110391 -1073836291 -268755217 -760410</internalNodes>
           <leafValues>
-            -3.6383235454559326e-01 1.9057570397853851e-01</leafValues></_>
+            -2.0745021104812622e-01 2.7934357523918152e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 66 1340125183 -134742145 -692979981 -1214109056
-            1289101223 -4839633 -21061633 -369409502</internalNodes>
+            0 -1 87 -1360393537 1727751901 -889274753 2081439599
+            1607743092 -67350714 -1091371394 -27240650</internalNodes>
           <leafValues>
-            -2.0452670753002167e-01 3.3919993042945862e-01</leafValues></_>
+            -2.3077887296676636e-01 2.4403619766235352e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 269 193720319 100840569 -303833102 763156184 978053077
-            531299573 -839056136 -1929622308</internalNodes>
+            0 -1 72 -17272190 -730449666 983947743 -134882993 1883483442
+            -72060809 1044905951 -211072966</internalNodes>
           <leafValues>
-            -2.7057421207427979e-01 2.3806059360504150e-01</leafValues></_>
+            -2.6235556602478027e-01 2.0745755732059479e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 73 1437966890 -129122561 1958795834 1556596447
-            1598142386 1074702522 -272384141 1205144459</internalNodes>
+            0 -1 189 -210252097 1884165717 -50659376 860389370 -33585068
+            2132105077 -553789572 -9176254</internalNodes>
           <leafValues>
-            -3.8338547945022583e-01 1.6122914850711823e-01</leafValues></_>
+            -1.9577032327651978e-01 2.8605857491493225e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 171 1115680527 115249619 895027446 -92284851 1599078213
-            1735769988 -537445018 1689910980</internalNodes>
+            0 -1 244 -12107230 1405347498 9728696 -774898706 1468220672
+            1174850371 1180713096 1409800424</internalNodes>
           <leafValues>
-            -3.6433032155036926e-01 1.7980493605136871e-01</leafValues></_>
+            -3.3929014205932617e-01 1.6556024551391602e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 144 1900011604 2069139451 1149891166 -1061030506
-            1967646922 -937402003 -1292100642 838974267</internalNodes>
+            0 -1 307 -994181088 1291627471 1262103330 -354443110
+            1962482852 1291513853 1151615436 1157370878</internalNodes>
           <leafValues>
-            -3.2297107577323914e-01 1.9990013539791107e-01</leafValues></_>
+            -4.2177367210388184e-01 1.3324783742427826e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 86 1216302162 1437731410 -1922152432 -586510344
-            -937599750 1065827099 -621007040 -86024589</internalNodes>
+            0 -1 267 -307502430 988475890 1831374754 -1645284694
+            2130962323 221299939 -582233169 -875695884</internalNodes>
           <leafValues>
-            -2.9406809806823730e-01 2.1769714355468750e-01</leafValues></_>
+            -2.4994827806949615e-01 2.2937348484992981e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 288 34597026 -688274366 1187213567 -671108889
-            -1508901182 -1308638469 -559091031 247438496</internalNodes>
+            0 -1 278 -1916848333 -1945176701 -1778585227 -2064614508
+            -122685775 -1462060545 176022580 -862585616</internalNodes>
           <leafValues>
-            -3.2822206616401672e-01 1.8776336312294006e-01</leafValues></_>
+            -2.7523562312126160e-01 2.1038419008255005e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 207 103046517 133606652 1733190463 -1346628911
-            -1148684048 -22091807 901613945 -1460139888</internalNodes>
+            0 -1 15 1794562783 -1707697032 8965707 201493599 -1078044347
+            2071358036 -228402354 -16253105</internalNodes>
           <leafValues>
-            -3.3780130743980408e-01 1.9073766469955444e-01</leafValues></_>
+            -2.4676196277141571e-01 2.2217004001140594e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 111 -746085629 -676994367 1095924655 -1122388257
-            -212397823 -202506293 -205057719 -208672818</internalNodes>
+            0 -1 329 -570688129 -559096592 461864797 -1648504323
+            -1381270595 -1162301576 748698989 -1140857537</internalNodes>
           <leafValues>
-            -1.8210665881633759e-01 3.4192490577697754e-01</leafValues></_>
+            -1.3901424407958984e-01 3.8346973061561584e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 74 -425549783 -371579759 -351371857 -575060349
-            -1214609473 -88295489 419684031 -1624088569</internalNodes>
+            0 -1 336 1356057541 815348525 -54210793 825603867 -185511716
+            2030008165 -1397949527 -105647169</internalNodes>
           <leafValues>
-            -2.2647747397422791e-01 2.7878209948539734e-01</leafValues></_>
+            -1.8459501862525940e-01 2.9480937123298645e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 208 -894491986 -219288836 1075036258 -1764754717
-            -573582558 -1807733298 1383817634 -196806592</internalNodes>
+            0 -1 241 -1373456459 -1213441040 -1090789891 -1087429059
+            -1397245955 -1074004547 -1883766851 -1079288824</internalNodes>
           <leafValues>
-            -2.9377350211143494e-01 2.1309736371040344e-01</leafValues></_>
+            -2.1159930527210236e-01 2.6970177888870239e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 201 -2106874097 -931096794 1687396770 -828052004
-            2015982962 -126682795 -294764796 -323961156</internalNodes>
+            0 -1 168 2001407789 335849869 -147476753 -1053743 895956974
+            2104879189 76816574 -186254656</internalNodes>
           <leafValues>
-            -3.2405611872673035e-01 1.9604462385177612e-01</leafValues></_>
+            -2.4863779544830322e-01 2.2415082156658173e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 222 -2042653379 1051606960 500611353 1069291288
-            -1453967943 -1919900749 -547038872 -1414655812</internalNodes>
+            0 -1 161 -1071127926 -104798275 1634638992 -201508730
+            1308444431 1370014335 -43939345 735390534</internalNodes>
           <leafValues>
-            -2.6115354895591736e-01 2.3542492091655731e-01</leafValues></_>
+            -2.4622464179992676e-01 2.2192895412445068e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 314 -588537600 -844176924 1464154596 -637687780
-            487338116 68063409 -1978163723 -840968737</internalNodes>
+            0 -1 260 746016303 709037870 45760155 141491407 1256916534
+            185498431 812100448 -602305968</internalNodes>
           <leafValues>
-            -2.7114504575729370e-01 2.3290830850601196e-01</leafValues></_>
+            -3.7083637714385986e-01 1.5087808668613434e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 317 120290097 -1288032431 1651243885 -76200631
-            -2068365766 -1346655489 246316733 -1108265899</internalNodes>
+            0 -1 118 2084023842 2097190758 -39176271 -570569955
+            -688182614 -1748393229 1173046543 1430650494</internalNodes>
           <leafValues>
-            -3.0526432394981384e-01 2.0446150004863739e-01</leafValues></_>
+            -2.4530048668384552e-01 2.2491128742694855e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 16 -822121865 -768454985 -352395443 -367512593
-            -1091080379 -202815919 -279024202 -28119438</internalNodes>
+            0 -1 23 1900052178 -1459537106 -167381666 1029895584
+            -675654745 -1737122 844265207 1512783454</internalNodes>
           <leafValues>
-            -2.4680423736572266e-01 2.5303974747657776e-01</leafValues></_>
+            -3.1983017921447754e-01 1.8673284351825714e-01</leafValues></_></weakClassifiers></_>
+    <!-- stage 18 -->
+    <_>
+      <maxWeakCount>30</maxWeakCount>
+      <stageThreshold>-1.1131941080093384e+00</stageThreshold>
+      <weakClassifiers>
         <_>
           <internalNodes>
-            0 -1 39 -624497410 423430210 168884479 707847256 -901496725
-            2133000198 -1135412149 1936933458</internalNodes>
+            0 -1 254 -26289153 -67174410 -335742017 -272455006
+            1212186622 -20513038 172322783 1162040387</internalNodes>
           <leafValues>
-            -3.1653416156768799e-01 2.0023956894874573e-01</leafValues></_>
+            -2.4323463439941406e-01 3.2466232776641846e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 242 1650942474 1345050478 886355088 1168828219
-            1112207884 1231876612 1550108076 1951460330</internalNodes>
+            0 -1 48 -528449376 -101669640 -553748993 -536903943
+            1018034165 -17510413 -570626819 -10529</internalNodes>
           <leafValues>
-            -3.2898175716400146e-01 1.8093948066234589e-01</leafValues></_>
+            -2.5142908096313477e-01 2.8689405322074890e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 124 369300756 891056133 -1916674564 -1374783349
-            996154237 -1145226207 -5607004 744775764</internalNodes>
+            0 -1 240 -1539 -1130741968 -34078723 1032337712 -1251478531
+            -1665269762 -1075314726 -1145380949</internalNodes>
           <leafValues>
-            -3.2225444912910461e-01 1.9573701918125153e-01</leafValues></_>
+            -1.8148881196975708e-01 3.5420870780944824e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 211 205577554 1071184148 -1263948549 1998946051
-            1260935961 -304903199 -606843718 1677159567</internalNodes>
+            0 -1 280 -83887105 817571843 -1039149548 1548950080
+            -1465058162 -1157678437 -1463092262 -201326609</internalNodes>
           <leafValues>
-            -3.0931469798088074e-01 2.0338173210620880e-01</leafValues></_>
+            -1.6771338880062103e-01 3.5687464475631714e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 143 -591418226 177508317 -1342069760 -4867939
-            1927953629 272683209 -1222155904 1886512754</internalNodes>
+            0 -1 57 -532737 -35715969 135855871 -1145344385 -16888678
+            -83947472 -1440547846 -15532193</internalNodes>
           <leafValues>
-            -3.4405741095542908e-01 1.8495233356952667e-01</leafValues></_>
+            -1.8111394345760345e-01 3.3908957242965698e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 265 -21049686 -28131359 1073478397 -34340880
-            -2075882246 -1093124168 -64807690 -1243108611</internalNodes>
+            0 -1 11 720900064 2130477023 -1412285101 955268081
+            -2069885116 -55066689 -1073778857 2096463733</internalNodes>
           <leafValues>
-            -2.2883313894271851e-01 2.9109308123588562e-01</leafValues></_>
+            -3.9165833592414856e-01 1.3025353848934174e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 307 781346419 639805680 -546181353 -1174989674
-            -1555551183 -893031525 -2006836811 -1392561707</internalNodes>
+            0 -1 101 -1346721094 453313040 838687891 1466900303
+            -1399343880 -1362120449 -1204875206 2078743195</internalNodes>
           <leafValues>
-            -3.0891278386116028e-01 2.1537151932716370e-01</leafValues></_>
+            -3.0911612510681152e-01 1.8588562309741974e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 134 -26563529 576995058 1442217478 -1427177744
-            -68769859 -1241776649 -424779152 -285805586</internalNodes>
+            0 -1 264 -202906070 1938124526 -409308124 1894181886
+            1886745604 73722021 -169346204 1624557028</internalNodes>
           <leafValues>
-            -2.3855516314506531e-01 2.6137462258338928e-01</leafValues></_>
+            -3.7369936704635620e-01 1.6779878735542297e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 178 -491860352 1783772447 -1761018371 989361018
-            2037451840 -988741302 2128769468 1865931536</internalNodes>
+            0 -1 315 253329560 487885008 764610172 1031107061 353634728
+            340804628 54078428 1065330931</internalNodes>
           <leafValues>
-            -3.3605426549911499e-01 1.9781108200550079e-01</leafValues></_>
+            -4.6387240290641785e-01 9.7853913903236389e-02</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 59 -1359078146 -21349537 1081098827 794979703 147593312
-            -343136234 308281456 -1121813221</internalNodes>
+            0 -1 221 1018691377 213157736 -1922048203 -1935119200
+            1002285621 -1923389008 220951933 -2001869391</internalNodes>
           <leafValues>
-            -3.4179690480232239e-01 1.8693566322326660e-01</leafValues></_>
+            -2.8209856152534485e-01 1.9869700074195862e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 131 -467418588 607934740 -510185553 -839002645
-            2000942967 1793376114 710533396 209909344</internalNodes>
+            0 -1 131 -145809672 -585615056 -1115156804 1607413650
+            1024261612 944513264 -1966100738 -6315329</internalNodes>
           <leafValues>
-            -3.9927759766578674e-01 1.5319514274597168e-01</leafValues></_>
+            -2.5250333547592163e-01 2.1315294504165649e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 6 -251463749 -1087866735 954640701 -1345720208
-            257393053 -1721918337 71237772 -522239782</internalNodes>
+            0 -1 236 -273750513 1726356523 -25760220 -1359572570
+            -708967119 2113503015 1155493984 -1057490414</internalNodes>
           <leafValues>
-            -2.0329028367996216e-01 3.1257370114326477e-01</leafValues></_></weakClassifiers></_>
-    <!-- stage 14 -->
-    <_>
-      <maxWeakCount>36</maxWeakCount>
-      <stageThreshold>-1.3515049219131470e+00</stageThreshold>
-      <weakClassifiers>
+            -2.9303619265556335e-01 2.0555299520492554e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 121 -583157832 -41345124 -1667477754 -47472728
-            -1631649861 -192782657 -1106464817 1060048799</internalNodes>
+            0 -1 94 323820494 491589631 963097087 -1677743793 1968422864
+            122533774 -13255752 2009905796</internalNodes>
           <leafValues>
-            -6.6292375326156616e-02 5.3096652030944824e-01</leafValues></_>
+            -3.3369639515876770e-01 1.6422146558761597e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 250 -961874181 -589629441 -202714187 -33687726
-            246352127 -1125919869 1090470655 1441756927</internalNodes>
+            0 -1 147 -227028310 322043889 -97472590 993106459 -935679349
+            1170424128 -355628373 -1186994445</internalNodes>
           <leafValues>
-            -2.9468271136283875e-01 2.9257065057754517e-01</leafValues></_>
+            -2.3621979355812073e-01 2.4498730897903442e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 284 -219161456 1561959797 -1157910723 -644253203
-            -37769852 -1175163461 -358812998 -1146105857</internalNodes>
+            0 -1 302 522927795 -1425531232 -1757151367 -349047764
+            505005821 -1367184427 1026187772 -2002064200</internalNodes>
           <leafValues>
-            -2.2191908955574036e-01 3.5355353355407715e-01</leafValues></_>
+            -2.7412149310112000e-01 1.9911617040634155e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 133 -1395773932 -19337 -872592385 -1082417169
-            -268501000 -203988001 -1360523750 -1430265925</internalNodes>
+            0 -1 339 895166720 2111801021 1608646093 1966952754
+            -270845440 -14704805 797543682 146244640</internalNodes>
           <leafValues>
-            -2.6642906665802002e-01 2.7330449223518372e-01</leafValues></_>
+            -3.7740421295166016e-01 1.6069526970386505e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 89 937245647 533051903 22876957 837784063 -113164289
-            1593942211 1207413693 1942338443</internalNodes>
+            0 -1 157 1323192543 -699121475 -560546497 4377727 -795736016
+            -617006470 -94369186 -25800110</internalNodes>
           <leafValues>
-            -3.1208184361457825e-01 2.1690289676189423e-01</leafValues></_>
+            -2.7069774270057678e-01 1.9588492810726166e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 245 -135270614 1911454511 -694266878 1894711038
-            1380414469 1078062543 -200939772 1616172018</internalNodes>
+            0 -1 327 -818173702 520657616 646455540 -2083557932
+            -75238914 420007072 1594772940 231600639</internalNodes>
           <leafValues>
-            -3.7340530753135681e-01 2.0424529910087585e-01</leafValues></_>
+            -3.1584987044334412e-01 1.7538470029830933e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 79 -673199910 2132653981 -1105191310 -1622098985
-            -279161640 1874615084 2066898922 -82575381</internalNodes>
+            0 -1 1 -148176937 -22288910 -828264777 -858011334 549667459
+            -104350212 83820556 -521682689</internalNodes>
           <leafValues>
-            -2.7581161260604858e-01 2.3679631948471069e-01</leafValues></_>
+            -1.8492446839809418e-01 2.9220038652420044e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 108 -88609193 -764250339 -21964208 1785903000
-            -705804525 -281542881 -17301633 -29425689</internalNodes>
+            0 -1 123 -253231012 -573137851 -1892901128 1566408309
+            -1769517004 -666343243 -1438498978 -1574952149</internalNodes>
           <leafValues>
-            -2.1142585575580597e-01 3.1125506758689880e-01</leafValues></_>
+            -3.1360149383544922e-01 1.7211912572383881e-01</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 60 170284113 586555385 1058684927 947969752 -1950608368
+            -385672127 -1672070998 -1168986245</internalNodes>
+          <leafValues>
+            -3.3217278122901917e-01 1.5771922469139099e-01</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 248 1432934647 967738510 1321343231 -1294596018
+            1010881693 478544329 145528063 1050558707</internalNodes>
+          <leafValues>
+            -2.6398298144340515e-01 2.1170960366725922e-01</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 209 1165995551 424529746 -728651937 -169112117
+            1305345535 2025713070 -338894882 1081454374</internalNodes>
+          <leafValues>
+            -2.2665287554264069e-01 2.3902100324630737e-01</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 257 -167798992 1502279678 -537643148 2040558008
+            -319819863 -1915752500 1705108696 -858081046</internalNodes>
+          <leafValues>
+            -2.0653969049453735e-01 2.7062198519706726e-01</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 333 800009831 1001521851 -124862633 533722757 935548439
+            -1187270792 2020438516 -349479616</internalNodes>
+          <leafValues>
+            -2.8587275743484497e-01 1.8258976936340332e-01</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 263 -1004379104 -317547503 -1375022085 -1350509633
+            -1535534960 -559793401 -1261510978 -1412440193</internalNodes>
+          <leafValues>
+            -2.5795167684555054e-01 2.0566099882125854e-01</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 146 465286027 242062640 1583158025 -1699742834
+            824414919 851244643 -1124620860 -795411494</internalNodes>
+          <leafValues>
+            -2.4531027674674988e-01 2.1592345833778381e-01</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 25 -2043693556 -725407700 793901503 -36185267 5371426
+            653472838 1473727247 129745679</internalNodes>
+          <leafValues>
+            -3.0099743604660034e-01 1.7710824310779572e-01</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 292 -1275032352 -23523116 1030926068 -570510472
+            33719442 719784182 96905635 -1916299537</internalNodes>
+          <leafValues>
+            -2.9368206858634949e-01 1.8733473122119904e-01</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 9 1373348482 -2133926229 953967473 1290797039
+            -354421821 777789632 1265367830 1148839750</internalNodes>
+          <leafValues>
+            -3.7210872769355774e-01 1.5113249421119690e-01</leafValues></_></weakClassifiers></_>
+    <!-- stage 19 -->
+    <_>
+      <maxWeakCount>32</maxWeakCount>
+      <stageThreshold>-1.1860446929931641e+00</stageThreshold>
+      <weakClassifiers>
         <_>
           <internalNodes>
-            0 -1 287 2117156824 2142892795 -1715733421 -1118208017
-            1981329130 -1132205343 -531030662 218086646</internalNodes>
+            0 -1 165 1356843726 1624768255 -826079028 -286274834
+            1507794655 -722342276 -3191601 -352325921</internalNodes>
           <leafValues>
-            -3.1311789155006409e-01 2.2028388082981110e-01</leafValues></_>
+            -1.7216572165489197e-01 3.7796711921691895e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 217 657173799 1208409516 -304231172 -319884740
-            829234695 822389124 -1816709292 -725510</internalNodes>
+            0 -1 313 -780169199 2100304165 -586083043 -1123467235
+            -638110531 -4406601 -274183091 201852044</internalNodes>
           <leafValues>
-            -3.4273931384086609e-01 1.9222305715084076e-01</leafValues></_>
+            -3.2011264562606812e-01 2.1122068166732788e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 270 -102301694 -135807070 -1880672401 -253298777
-            -354657254 -100668629 2011055773 -155453461</internalNodes>
+            0 -1 133 -571204388 -100720840 -1619059363 -539550628
+            -19218498 -193040 -88209091 -1086649846</internalNodes>
           <leafValues>
-            -2.4226696789264679e-01 2.7088710665702820e-01</leafValues></_>
+            -2.5261041522026062e-01 2.6258233189582825e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 191 215240020 -1148310119 -707214049 -1112003969
-            1860719544 -6638593 -4317491 -1414921888</internalNodes>
+            0 -1 117 -1828478207 -1843284467 -485637257 -1828588787
+            -988301809 -3170571 1124595215 -206576893</internalNodes>
           <leafValues>
-            -3.1184914708137512e-01 2.1366736292839050e-01</leafValues></_>
+            -2.2752490639686584e-01 2.6724869012832642e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 18 -873476105 -30229647 -168296643 -1682912767
-            161284371 -1972125919 -12305 -268965957</internalNodes>
+            0 -1 156 -25473825 877659895 -67700993 2077895802 -18998020
+            -69575009 -640262 -21489648</internalNodes>
           <leafValues>
-            -2.1284404397010803e-01 3.0867013335227966e-01</leafValues></_>
+            -2.6945993304252625e-01 2.0498518645763397e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 289 -449986302 74968807 2145360303 20911369 1088274818
-            1642837031 -1026366551 53429507</internalNodes>
+            0 -1 252 1800381322 61586570 -598811408 -805833218
+            1363795719 21154001 -790399642 -19401985</internalNodes>
           <leafValues>
-            -3.2960832118988037e-01 1.9843052327632904e-01</leafValues></_>
+            -2.7357041835784912e-01 2.2086700797080994e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 187 -294473945 1289282231 -69736418 -366809570
-            585961254 -894112782 -352349116 -857431116</internalNodes>
+            0 -1 13 -1601560401 -1678195249 -800754625 -819308539
+            1645503999 -1361531665 -491535701 -552874238</internalNodes>
           <leafValues>
-            -3.4131202101707458e-01 1.7822383344173431e-01</leafValues></_>
+            -2.4950334429740906e-01 2.1326830983161926e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 117 -260075316 810653599 -307212416 -1090154618
-            1085218542 2014454434 -889360754 840974879</internalNodes>
+            0 -1 197 -1130634113 775889725 -1098908817 -1382023297
+            -252264234 -1460797259 -391364236 -1203775120</internalNodes>
           <leafValues>
-            -2.8617727756500244e-01 2.1801990270614624e-01</leafValues></_>
+            -2.2527810931205750e-01 2.4279835820198059e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 32 683352887 144804986 883838777 -470815534 749351701
-            -1376201987 -1007927147 -269498899</internalNodes>
+            0 -1 350 792411409 1058027552 -110125307 2134056272
+            605163321 -1347378309 1504534524 226299985</internalNodes>
           <leafValues>
-            -2.7213591337203979e-01 2.3029308021068573e-01</leafValues></_>
+            -4.0245848894119263e-01 1.2799273431301117e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 160 -221779237 2055449126 1356126973 1739434813
-            -69756111 -78052576 -724205593 927834891</internalNodes>
+            0 -1 347 1050083335 406261055 -1363608721 597939991
+            -146861538 -1075839447 -122225990 -73208017</internalNodes>
           <leafValues>
-            -2.1148133277893066e-01 2.9901567101478577e-01</leafValues></_>
+            -2.2469925880432129e-01 2.3744599521160126e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 139 -327161337 -541288917 -1074706625 2069214763
-            1422886542 -570618263 1425911455 1965665867</internalNodes>
+            0 -1 85 1582192403 1062343974 1627149746 -704505584
+            1569152382 -607155889 -671101020 -67379489</internalNodes>
           <leafValues>
-            -1.9790525734424591e-01 3.1719624996185303e-01</leafValues></_>
+            -2.4716284871101379e-01 2.0234791934490204e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 12 -286652406 -1499051796 -2055991469 557910223
-            226286607 -307013288 537285247 1340571263</internalNodes>
+            0 -1 232 -911388934 285282595 -1026079813 96171241
+            -1995666022 998839072 9210339 769654523</internalNodes>
           <leafValues>
-            -3.5588899254798889e-01 1.8802331387996674e-01</leafValues></_>
+            -2.7387142181396484e-01 1.9601228833198547e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 204 -440754172 -1969605175 -11230786 -1369112738
-            -164163787 -439228643 -440438364 -855854880</internalNodes>
+            0 -1 345 -1232081117 -1601765464 1841782352 -1359108881
+            206394688 214450860 -570607531 -866268431</internalNodes>
           <leafValues>
-            -3.3756810426712036e-01 1.8606249988079071e-01</leafValues></_>
+            -3.0001869797706604e-01 1.6920509934425354e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 54 -2103276886 1587028506 -1920974049 -382890163
-            -50953603 -625169247 -75998374 847320848</internalNodes>
+            0 -1 295 -4458576 -1314131792 1398469949 -1792059607
+            -1345405187 -1079051090 1452237728 -1919952197</internalNodes>
           <leafValues>
-            -3.3854812383651733e-01 1.8501213192939758e-01</leafValues></_>
+            -1.9607956707477570e-01 2.6292434334754944e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 149 -912264192 1437763456 -117442116 1477965101
-            -109596288 -782313675 -520249859 -174065925</internalNodes>
+            0 -1 79 1506257807 1575786835 -1278408030 -1253124710
+            -82575398 1430293160 1930209224 -796269912</internalNodes>
           <leafValues>
-            -2.3874689638614655e-01 2.6692461967468262e-01</leafValues></_>
+            -2.9750382900238037e-01 1.7626072466373444e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 179 -74761 -1193108610 -1627717634 -1141359812
-            -1350594860 -1212204947 -1900803076 -68466436</internalNodes>
+            0 -1 237 -426011871 401504059 -655056592 -96541869
+            1174138997 83593771 1356719392 -1057033481</internalNodes>
           <leafValues>
-            -1.8434369564056396e-01 3.4898519515991211e-01</leafValues></_>
+            -2.6239070296287537e-01 2.0239675045013428e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 320 -806388957 -1603323478 -319904391 -1889144109
-            -1427144299 -1074553867 -1577597820 -822218338</internalNodes>
+            0 -1 224 528217457 -1887267120 -21899275 230954172 182253557
+            -1078346768 673994781 -1465425804</internalNodes>
           <leafValues>
-            -1.9554206728935242e-01 3.1441712379455566e-01</leafValues></_>
+            -2.4917839467525482e-01 2.0696680247783661e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 13 -495530405 -1200567737 -562818530 1426283955
-            -646798267 -42047966 -283939201 -15210669</internalNodes>
+            0 -1 140 1077257734 1897370406 -259859707 1059435291
+            1506651014 -1718550481 1420667359 1969609218</internalNodes>
           <leafValues>
-            -2.0684894919395447e-01 3.0842429399490356e-01</leafValues></_>
+            -2.4424369633197784e-01 2.1042110025882721e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 227 -204473205 -111677525 1659697788 -168822810
-            164468462 95878471 1418323918 -705698930</internalNodes>
+            0 -1 230 -134218838 2137809570 -218175868 -139728728
+            2147479551 1513965270 -436767017 -19926812</internalNodes>
           <leafValues>
-            -1.5447042882442474e-01 4.0702703595161438e-01</leafValues></_>
+            -2.1578867733478546e-01 2.3687294125556946e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 122 332207055 1368372207 1371537916 1541155303
-            1377022927 1195687084 -845629564 -191055413</internalNodes>
+            0 -1 41 1061133429 -1680215183 951637661 -1082528295
+            -1722602208 -281648288 -576384764 -1426137478</internalNodes>
           <leafValues>
-            -2.6908680796623230e-01 2.3349469900131226e-01</leafValues></_>
+            -2.3583492636680603e-01 2.2509087622165680e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 183 2095555624 -1858958714 880848550 -1086881165
-            1278302507 2017585116 -2100032289 83174071</internalNodes>
+            0 -1 326 -1035541888 1145865728 -431122728 1154338362
+            -692060765 -187976868 -205526277 111929518</internalNodes>
           <leafValues>
-            -3.3865603804588318e-01 1.8762224912643433e-01</leafValues></_>
+            -3.4106892347335815e-01 1.7086119949817657e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 257 -1599264894 1347540775 548331985 566406079
-            -490018643 2125284619 -542620802 -507647254</internalNodes>
+            0 -1 158 763361143 740787839 -1648101507 -1076559121
+            -256380937 758360290 -1207635964 68200468</internalNodes>
           <leafValues>
-            -2.4964332580566406e-01 2.5305619835853577e-01</leafValues></_>
+            -3.1536939740180969e-01 1.5365907549858093e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 153 -928904029 -73474081 -431055591 -1365072480
-            1082731439 -1163105435 -401696790 -331068832</internalNodes>
+            0 -1 176 -1898557315 -1344526497 1827929727 1610372479
+            -2220468 -110762 -560275617 -1168483765</internalNodes>
           <leafValues>
-            -2.4641251564025879e-01 2.5806349515914917e-01</leafValues></_>
+            -2.1805766224861145e-01 2.4546204507350922e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 261 -1551324256 227211248 -139191220 -1912739520
-            1712117749 1864425601 1605297047 232734801</internalNodes>
+            0 -1 262 -167774321 -749754393 -772349322 1946088623 -529788
+            -570036402 -404621404 -202506274</internalNodes>
           <leafValues>
-            -3.6956688761711121e-01 1.7259617149829865e-01</leafValues></_>
+            -1.4736793935298920e-01 3.7225186824798584e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 37 2062683840 -1171226870 -634334626 -42988729
-            -177907627 1819501884 -1554858149 -81568901</internalNodes>
+            0 -1 121 337917444 140836324 -1369830227 -1342456915
+            -1175112267 2101116535 -1384838109 741831797</internalNodes>
           <leafValues>
-            -2.8280401229858398e-01 2.3210345208644867e-01</leafValues></_>
+            -3.9851671457290649e-01 1.3316881656646729e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 101 -52896752 2073648803 -104703392 -1877326687
-            1482183868 486564792 -1181155586 -1078764545</internalNodes>
+            0 -1 172 -10244980 1412480785 2134521425 1932578931
+            1778322640 1063337502 1048517040 -142620803</internalNodes>
           <leafValues>
-            -2.6182973384857178e-01 2.4921841919422150e-01</leafValues></_>
+            -2.2908750176429749e-01 2.3318812251091003e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 119 931876834 -1689820513 -175925869 295803187
-            1288847768 -1394638455 -527053926 -1609099725</internalNodes>
+            0 -1 220 739784564 884511140 894928089 1065491218 122138060
+            524623529 391056888 532291626</internalNodes>
           <leafValues>
-            -2.8890526294708252e-01 2.2244787216186523e-01</leafValues></_>
+            -3.5874554514884949e-01 1.4738923311233521e-01</leafValues></_>
         <_>
           <internalNodes>
-            0 -1 23 674383927 640705886 -1980567045 775069703 941246324
-            -1074502869 821615185 -1439559299</internalNodes>
+            0 -1 182 -1557157214 -1407349557 276451840 542158770
+            -767297572 1620822855 -1963265624 -1002119198</internalNodes>
           <leafValues>
-            -3.7707689404487610e-01 1.7476500570774078e-01</leafValues></_></weakClassifiers></_></stages>
+            -3.2322171330451965e-01 1.5725640952587128e-01</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 98 1561639164 -577384833 -972029477 -26394741
+            1433517817 -1145825634 2090400506 1064572985</internalNodes>
+          <leafValues>
+            -3.8865497708320618e-01 1.4794999361038208e-01</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 17 1785851519 234900079 -867150209 -1033437237
+            -338602732 -9149625 -888193454 -33498413</internalNodes>
+          <leafValues>
+            -2.5603562593460083e-01 2.1439185738563538e-01</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 93 1062021007 670948845 -237027440 889116157 2002805591
+            1966188591 -1350453384 1885696686</internalNodes>
+          <leafValues>
+            -3.7720784544944763e-01 1.3390180468559265e-01</leafValues></_>
+        <_>
+          <internalNodes>
+            0 -1 129 -239339312 255035166 -873625424 958256640 -59805472
+            1222090819 -746264190 269999815</internalNodes>
+          <leafValues>
+            -3.5460588335990906e-01 1.4317318797111511e-01</leafValues></_></weakClassifiers></_></stages>
   <features>
     <_>
       <rect>
         0 0 2 2</rect></_>
     <_>
       <rect>
+        0 0 2 4</rect></_>
+    <_>
+      <rect>
         0 0 3 4</rect></_>
     <_>
       <rect>
-        0 0 5 3</rect></_>
+        0 0 4 4</rect></_>
     <_>
       <rect>
-        0 0 5 4</rect></_>
+        0 0 5 7</rect></_>
     <_>
       <rect>
         0 0 6 3</rect></_>
     <_>
       <rect>
-        0 0 8 1</rect></_>
+        0 0 6 4</rect></_>
     <_>
       <rect>
-        0 1 2 3</rect></_>
+        0 0 6 6</rect></_>
     <_>
       <rect>
-        0 1 6 4</rect></_>
+        0 0 8 1</rect></_>
     <_>
       <rect>
-        0 2 8 5</rect></_>
+        0 1 8 5</rect></_>
     <_>
       <rect>
-        0 7 6 2</rect></_>
+        0 3 6 2</rect></_>
     <_>
       <rect>
-        0 9 2 2</rect></_>
+        0 3 6 3</rect></_>
     <_>
       <rect>
-        0 9 3 1</rect></_>
+        0 4 6 4</rect></_>
     <_>
       <rect>
-        0 9 5 3</rect></_>
+        0 6 3 2</rect></_>
     <_>
       <rect>
-        0 14 3 3</rect></_>
+        0 8 3 1</rect></_>
     <_>
       <rect>
-        0 15 2 2</rect></_>
+        0 9 2 2</rect></_>
     <_>
       <rect>
-        0 16 1 2</rect></_>
+        0 10 2 2</rect></_>
     <_>
       <rect>
-        0 17 2 2</rect></_>
+        0 14 3 3</rect></_>
     <_>
       <rect>
-        1 0 2 4</rect></_>
+        0 15 2 2</rect></_>
     <_>
       <rect>
-        1 0 5 3</rect></_>
+        0 17 3 2</rect></_>
     <_>
       <rect>
-        1 0 7 1</rect></_>
+        1 0 4 4</rect></_>
     <_>
       <rect>
-        1 6 2 1</rect></_>
+        1 1 2 3</rect></_>
     <_>
       <rect>
-        1 9 1 1</rect></_>
+        1 6 2 2</rect></_>
     <_>
       <rect>
-        1 9 2 2</rect></_>
+        1 6 4 3</rect></_>
     <_>
       <rect>
-        1 15 1 2</rect></_>
+        1 7 2 1</rect></_>
     <_>
       <rect>
-        1 16 2 2</rect></_>
+        1 8 2 1</rect></_>
     <_>
       <rect>
-        2 0 2 2</rect></_>
+        1 8 2 3</rect></_>
     <_>
       <rect>
-        2 0 2 3</rect></_>
+        1 12 2 1</rect></_>
     <_>
       <rect>
-        2 0 3 4</rect></_>
+        1 16 2 2</rect></_>
     <_>
       <rect>
-        2 1 3 7</rect></_>
+        2 0 2 3</rect></_>
     <_>
       <rect>
-        2 4 1 1</rect></_>
+        2 0 5 3</rect></_>
     <_>
       <rect>
-        2 4 5 2</rect></_>
+        2 1 4 2</rect></_>
     <_>
       <rect>
-        2 4 5 4</rect></_>
+        2 3 5 2</rect></_>
     <_>
       <rect>
         2 5 1 1</rect></_>
     <_>
       <rect>
-        2 6 2 2</rect></_>
-    <_>
-      <rect>
-        2 7 1 1</rect></_>
+        2 6 2 1</rect></_>
     <_>
       <rect>
-        2 7 2 1</rect></_>
+        2 6 2 2</rect></_>
     <_>
       <rect>
-        2 8 3 3</rect></_>
+        2 9 1 1</rect></_>
     <_>
       <rect>
-        2 9 1 1</rect></_>
+        2 9 2 1</rect></_>
     <_>
       <rect>
         2 10 1 1</rect></_>
@@ -2489,40 +2831,31 @@
         2 15 1 2</rect></_>
     <_>
       <rect>
-        2 19 2 1</rect></_>
-    <_>
-      <rect>
-        3 0 4 3</rect></_>
+        3 0 1 1</rect></_>
     <_>
       <rect>
-        3 0 6 6</rect></_>
+        3 0 3 3</rect></_>
     <_>
       <rect>
-        3 0 7 1</rect></_>
+        3 0 6 1</rect></_>
     <_>
       <rect>
         3 2 4 2</rect></_>
     <_>
       <rect>
-        3 2 6 1</rect></_>
-    <_>
-      <rect>
-        3 4 2 2</rect></_>
+        3 4 1 2</rect></_>
     <_>
       <rect>
         3 5 1 1</rect></_>
     <_>
       <rect>
-        3 6 1 1</rect></_>
+        3 5 3 3</rect></_>
     <_>
       <rect>
-        3 6 2 1</rect></_>
-    <_>
-      <rect>
-        3 6 2 3</rect></_>
+        3 6 1 1</rect></_>
     <_>
       <rect>
-        3 6 3 3</rect></_>
+        3 6 2 2</rect></_>
     <_>
       <rect>
         3 6 6 1</rect></_>
@@ -2543,49 +2876,46 @@
         3 9 1 1</rect></_>
     <_>
       <rect>
-        3 9 1 2</rect></_>
+        3 9 3 1</rect></_>
     <_>
       <rect>
         3 10 1 1</rect></_>
     <_>
       <rect>
-        3 10 1 2</rect></_>
-    <_>
-      <rect>
         3 10 2 1</rect></_>
     <_>
       <rect>
         3 11 1 1</rect></_>
     <_>
       <rect>
-        3 11 1 3</rect></_>
+        3 12 1 1</rect></_>
     <_>
       <rect>
-        3 13 3 3</rect></_>
+        3 13 3 2</rect></_>
     <_>
       <rect>
-        4 0 4 2</rect></_>
+        3 18 2 2</rect></_>
     <_>
       <rect>
-        4 0 6 7</rect></_>
+        4 0 2 2</rect></_>
     <_>
       <rect>
-        4 1 1 1</rect></_>
+        4 0 4 2</rect></_>
     <_>
       <rect>
-        4 1 4 3</rect></_>
+        4 0 5 6</rect></_>
     <_>
       <rect>
-        4 4 2 1</rect></_>
+        4 2 2 2</rect></_>
     <_>
       <rect>
-        4 6 1 1</rect></_>
+        4 5 3 1</rect></_>
     <_>
       <rect>
-        4 6 5 1</rect></_>
+        4 6 1 1</rect></_>
     <_>
       <rect>
-        4 6 5 4</rect></_>
+        4 6 2 3</rect></_>
     <_>
       <rect>
         4 7 1 1</rect></_>
@@ -2594,10 +2924,10 @@
         4 7 2 2</rect></_>
     <_>
       <rect>
-        4 7 5 1</rect></_>
+        4 8 1 1</rect></_>
     <_>
       <rect>
-        4 8 1 1</rect></_>
+        4 8 5 3</rect></_>
     <_>
       <rect>
         4 8 5 4</rect></_>
@@ -2606,7 +2936,7 @@
         4 9 1 1</rect></_>
     <_>
       <rect>
-        4 9 2 1</rect></_>
+        4 9 1 3</rect></_>
     <_>
       <rect>
         4 9 3 5</rect></_>
@@ -2615,6 +2945,9 @@
         4 9 5 1</rect></_>
     <_>
       <rect>
+        4 9 6 1</rect></_>
+    <_>
+      <rect>
         4 10 1 1</rect></_>
     <_>
       <rect>
@@ -2624,49 +2957,64 @@
         4 12 1 2</rect></_>
     <_>
       <rect>
-        4 14 3 3</rect></_>
+        4 12 3 3</rect></_>
     <_>
       <rect>
-        4 15 1 1</rect></_>
+        4 13 3 3</rect></_>
     <_>
       <rect>
-        4 18 2 1</rect></_>
+        4 14 2 2</rect></_>
     <_>
       <rect>
-        5 2 5 3</rect></_>
+        4 17 3 1</rect></_>
     <_>
       <rect>
-        5 3 4 4</rect></_>
+        4 21 2 1</rect></_>
     <_>
       <rect>
-        5 6 1 1</rect></_>
+        5 0 5 1</rect></_>
     <_>
       <rect>
-        5 6 4 1</rect></_>
+        5 0 5 4</rect></_>
     <_>
       <rect>
-        5 7 1 1</rect></_>
+        5 1 5 5</rect></_>
     <_>
       <rect>
-        5 7 1 2</rect></_>
+        5 1 5 6</rect></_>
     <_>
       <rect>
-        5 7 2 2</rect></_>
+        5 4 1 1</rect></_>
     <_>
       <rect>
-        5 8 1 1</rect></_>
+        5 5 5 1</rect></_>
     <_>
       <rect>
-        5 8 3 4</rect></_>
+        5 5 5 2</rect></_>
     <_>
       <rect>
-        5 8 3 5</rect></_>
+        5 6 1 1</rect></_>
     <_>
       <rect>
-        5 8 5 1</rect></_>
+        5 6 5 1</rect></_>
     <_>
       <rect>
-        5 8 5 3</rect></_>
+        5 7 1 1</rect></_>
+    <_>
+      <rect>
+        5 7 1 2</rect></_>
+    <_>
+      <rect>
+        5 7 3 4</rect></_>
+    <_>
+      <rect>
+        5 8 1 1</rect></_>
+    <_>
+      <rect>
+        5 8 2 4</rect></_>
+    <_>
+      <rect>
+        5 8 5 4</rect></_>
     <_>
       <rect>
         5 9 1 1</rect></_>
@@ -2675,10 +3023,10 @@
         5 9 5 1</rect></_>
     <_>
       <rect>
-        5 10 1 1</rect></_>
+        5 9 5 3</rect></_>
     <_>
       <rect>
-        5 10 2 1</rect></_>
+        5 10 1 1</rect></_>
     <_>
       <rect>
         5 10 5 1</rect></_>
@@ -2687,43 +3035,46 @@
         5 11 1 1</rect></_>
     <_>
       <rect>
-        5 13 1 3</rect></_>
+        5 13 2 1</rect></_>
     <_>
       <rect>
-        5 16 1 1</rect></_>
+        5 17 1 1</rect></_>
     <_>
       <rect>
-        5 18 1 2</rect></_>
+        5 17 1 2</rect></_>
     <_>
       <rect>
-        6 0 6 5</rect></_>
+        5 20 1 1</rect></_>
     <_>
       <rect>
-        6 1 1 2</rect></_>
+        6 0 3 1</rect></_>
     <_>
       <rect>
-        6 3 1 1</rect></_>
+        6 0 4 1</rect></_>
     <_>
       <rect>
-        6 3 6 3</rect></_>
+        6 0 6 2</rect></_>
     <_>
       <rect>
-        6 4 1 1</rect></_>
+        6 0 6 5</rect></_>
     <_>
       <rect>
-        6 5 1 1</rect></_>
+        6 1 1 2</rect></_>
     <_>
       <rect>
-        6 5 1 2</rect></_>
+        6 3 1 2</rect></_>
     <_>
       <rect>
-        6 6 2 2</rect></_>
+        6 4 1 1</rect></_>
+    <_>
+      <rect>
+        6 5 1 1</rect></_>
     <_>
       <rect>
-        6 6 2 4</rect></_>
+        6 5 6 3</rect></_>
     <_>
       <rect>
-        6 6 3 3</rect></_>
+        6 6 1 1</rect></_>
     <_>
       <rect>
         6 7 1 1</rect></_>
@@ -2735,73 +3086,79 @@
         6 7 4 1</rect></_>
     <_>
       <rect>
-        6 7 4 4</rect></_>
+        6 7 6 1</rect></_>
     <_>
       <rect>
-        6 7 6 1</rect></_>
+        6 8 1 1</rect></_>
     <_>
       <rect>
-        6 8 1 4</rect></_>
+        6 8 2 1</rect></_>
     <_>
       <rect>
         6 8 2 2</rect></_>
     <_>
       <rect>
+        6 8 2 3</rect></_>
+    <_>
+      <rect>
         6 9 1 1</rect></_>
     <_>
       <rect>
         6 9 2 1</rect></_>
     <_>
       <rect>
-        6 9 2 2</rect></_>
+        6 10 1 1</rect></_>
     <_>
       <rect>
-        6 9 5 1</rect></_>
+        6 10 4 3</rect></_>
     <_>
       <rect>
-        6 9 6 2</rect></_>
+        6 11 1 1</rect></_>
     <_>
       <rect>
-        6 10 1 1</rect></_>
+        6 18 1 1</rect></_>
     <_>
       <rect>
-        6 11 1 1</rect></_>
+        6 18 1 2</rect></_>
     <_>
       <rect>
-        6 13 1 1</rect></_>
+        6 19 1 1</rect></_>
     <_>
       <rect>
-        6 13 2 1</rect></_>
+        6 21 2 1</rect></_>
     <_>
       <rect>
-        6 18 1 2</rect></_>
+        7 0 1 4</rect></_>
     <_>
       <rect>
-        6 20 1 1</rect></_>
+        7 0 5 3</rect></_>
     <_>
       <rect>
-        7 0 3 1</rect></_>
+        7 4 1 1</rect></_>
     <_>
       <rect>
-        7 2 1 3</rect></_>
+        7 4 1 2</rect></_>
     <_>
       <rect>
-        7 3 4 5</rect></_>
+        7 5 1 1</rect></_>
     <_>
       <rect>
-        7 5 1 1</rect></_>
+        7 6 1 1</rect></_>
     <_>
       <rect>
-        7 5 2 1</rect></_>
+        7 6 2 1</rect></_>
     <_>
       <rect>
-        7 6 1 1</rect></_>
+        7 6 2 3</rect></_>
     <_>
       <rect>
-        7 7 1 2</rect></_>
+        7 6 2 5</rect></_>
+    <_>
+      <rect>
+        7 7 1 1</rect></_>
     <_>
       <rect>
-        7 7 2 4</rect></_>
+        7 7 1 2</rect></_>
     <_>
       <rect>
         7 8 1 1</rect></_>
@@ -2810,25 +3167,22 @@
         7 8 1 2</rect></_>
     <_>
       <rect>
-        7 8 2 4</rect></_>
+        7 8 2 2</rect></_>
     <_>
       <rect>
         7 9 1 1</rect></_>
     <_>
       <rect>
-        7 16 1 1</rect></_>
+        7 9 2 3</rect></_>
     <_>
       <rect>
-        7 21 1 1</rect></_>
+        7 18 1 1</rect></_>
     <_>
       <rect>
-        7 21 2 1</rect></_>
+        7 20 2 1</rect></_>
     <_>
       <rect>
-        8 0 2 1</rect></_>
-    <_>
-      <rect>
-        8 0 3 1</rect></_>
+        8 0 5 1</rect></_>
     <_>
       <rect>
         8 0 5 3</rect></_>
@@ -2837,73 +3191,103 @@
         8 3 1 1</rect></_>
     <_>
       <rect>
+        8 3 1 3</rect></_>
+    <_>
+      <rect>
         8 4 1 1</rect></_>
     <_>
       <rect>
         8 5 1 1</rect></_>
     <_>
       <rect>
-        8 5 1 2</rect></_>
+        8 5 5 1</rect></_>
     <_>
       <rect>
-        8 7 3 4</rect></_>
+        8 6 1 2</rect></_>
     <_>
       <rect>
         8 8 1 1</rect></_>
     <_>
       <rect>
+        8 8 4 1</rect></_>
+    <_>
+      <rect>
+        8 8 4 2</rect></_>
+    <_>
+      <rect>
         8 9 1 1</rect></_>
     <_>
       <rect>
-        8 9 3 5</rect></_>
+        8 9 1 2</rect></_>
     <_>
       <rect>
         8 11 1 1</rect></_>
     <_>
       <rect>
-        8 14 1 1</rect></_>
+        8 12 1 2</rect></_>
+    <_>
+      <rect>
+        8 13 3 3</rect></_>
     <_>
       <rect>
-        8 19 1 1</rect></_>
+        8 14 1 1</rect></_>
     <_>
       <rect>
-        8 20 1 1</rect></_>
+        8 15 1 1</rect></_>
     <_>
       <rect>
         8 21 1 1</rect></_>
     <_>
       <rect>
-        9 0 2 3</rect></_>
+        8 21 2 1</rect></_>
     <_>
       <rect>
-        9 1 2 1</rect></_>
+        9 0 2 2</rect></_>
     <_>
       <rect>
-        9 5 2 1</rect></_>
+        9 0 5 3</rect></_>
     <_>
       <rect>
-        9 5 2 3</rect></_>
+        9 1 2 2</rect></_>
     <_>
       <rect>
-        9 5 4 1</rect></_>
+        9 2 1 1</rect></_>
     <_>
       <rect>
-        9 7 1 1</rect></_>
+        9 3 1 1</rect></_>
     <_>
       <rect>
-        9 9 1 1</rect></_>
+        9 3 2 2</rect></_>
+    <_>
+      <rect>
+        9 4 2 1</rect></_>
+    <_>
+      <rect>
+        9 4 4 1</rect></_>
+    <_>
+      <rect>
+        9 5 2 3</rect></_>
     <_>
       <rect>
-        9 11 1 1</rect></_>
+        9 9 1 1</rect></_>
     <_>
       <rect>
-        9 12 2 4</rect></_>
+        9 10 1 1</rect></_>
     <_>
       <rect>
         9 15 1 1</rect></_>
     <_>
       <rect>
-        9 17 1 1</rect></_>
+        9 15 2 2</rect></_>
+    <_>
+      <rect>
+        9 16 1 1</rect></_>
+    <_>
+      <rect>
+        9 16 2 2</rect></_>
+    <_>
+      <rect>
+        9 18 1 1</rect></_>
     <_>
       <rect>
         9 18 1 2</rect></_>
@@ -2912,19 +3296,22 @@
         9 20 1 1</rect></_>
     <_>
       <rect>
-        10 0 2 2</rect></_>
+        9 21 1 1</rect></_>
     <_>
       <rect>
-        10 6 3 3</rect></_>
+        10 0 4 3</rect></_>
     <_>
       <rect>
-        10 7 1 1</rect></_>
+        10 4 4 2</rect></_>
     <_>
       <rect>
-        10 8 1 1</rect></_>
+        10 6 1 1</rect></_>
     <_>
       <rect>
-        10 9 1 1</rect></_>
+        10 7 1 1</rect></_>
+    <_>
+      <rect>
+        10 8 1 1</rect></_>
     <_>
       <rect>
         10 11 1 1</rect></_>
@@ -2933,7 +3320,13 @@
         10 12 1 1</rect></_>
     <_>
       <rect>
-        10 15 1 1</rect></_>
+        10 14 1 1</rect></_>
+    <_>
+      <rect>
+        10 18 1 2</rect></_>
+    <_>
+      <rect>
+        10 19 1 1</rect></_>
     <_>
       <rect>
         10 20 1 1</rect></_>
@@ -2942,46 +3335,43 @@
         10 21 1 1</rect></_>
     <_>
       <rect>
-        11 0 4 4</rect></_>
+        11 0 1 3</rect></_>
     <_>
       <rect>
-        11 1 4 4</rect></_>
+        11 0 4 4</rect></_>
     <_>
       <rect>
-        11 3 1 1</rect></_>
+        11 2 3 2</rect></_>
     <_>
       <rect>
-        11 4 3 1</rect></_>
+        11 5 4 3</rect></_>
     <_>
       <rect>
-        11 6 3 6</rect></_>
+        11 6 1 1</rect></_>
     <_>
       <rect>
         11 7 1 1</rect></_>
     <_>
       <rect>
-        11 8 1 1</rect></_>
-    <_>
-      <rect>
-        11 9 1 1</rect></_>
+        11 7 2 4</rect></_>
     <_>
       <rect>
-        11 9 2 3</rect></_>
+        11 8 2 2</rect></_>
     <_>
       <rect>
-        11 10 1 1</rect></_>
+        11 9 1 1</rect></_>
     <_>
       <rect>
-        11 11 1 1</rect></_>
+        11 9 2 4</rect></_>
     <_>
       <rect>
-        11 12 2 3</rect></_>
+        11 12 1 1</rect></_>
     <_>
       <rect>
-        11 13 1 1</rect></_>
+        11 18 1 1</rect></_>
     <_>
       <rect>
-        11 15 3 1</rect></_>
+        11 18 3 2</rect></_>
     <_>
       <rect>
         11 20 1 1</rect></_>
@@ -2990,16 +3380,13 @@
         11 21 1 1</rect></_>
     <_>
       <rect>
-        12 3 1 1</rect></_>
-    <_>
-      <rect>
-        12 5 1 1</rect></_>
+        11 21 2 1</rect></_>
     <_>
       <rect>
-        12 5 2 3</rect></_>
+        12 2 1 1</rect></_>
     <_>
       <rect>
-        12 5 3 3</rect></_>
+        12 3 1 1</rect></_>
     <_>
       <rect>
         12 6 1 1</rect></_>
@@ -3011,31 +3398,37 @@
         12 8 1 1</rect></_>
     <_>
       <rect>
-        12 8 2 2</rect></_>
+        12 8 2 1</rect></_>
     <_>
       <rect>
         12 8 2 3</rect></_>
     <_>
       <rect>
-        12 9 1 1</rect></_>
+        12 8 2 4</rect></_>
     <_>
       <rect>
-        12 10 2 3</rect></_>
+        12 9 2 1</rect></_>
     <_>
       <rect>
-        12 11 1 1</rect></_>
+        12 9 2 5</rect></_>
     <_>
       <rect>
-        12 16 1 1</rect></_>
+        12 10 1 1</rect></_>
     <_>
       <rect>
-        12 17 1 1</rect></_>
+        12 12 1 1</rect></_>
     <_>
       <rect>
-        12 18 1 1</rect></_>
+        12 13 1 1</rect></_>
     <_>
       <rect>
-        12 18 1 2</rect></_>
+        12 14 1 1</rect></_>
+    <_>
+      <rect>
+        12 16 1 1</rect></_>
+    <_>
+      <rect>
+        12 18 1 1</rect></_>
     <_>
       <rect>
         12 20 1 1</rect></_>
@@ -3044,7 +3437,7 @@
         12 21 1 1</rect></_>
     <_>
       <rect>
-        13 0 3 3</rect></_>
+        12 21 2 1</rect></_>
     <_>
       <rect>
         13 3 1 1</rect></_>
@@ -3056,7 +3449,10 @@
         13 5 1 1</rect></_>
     <_>
       <rect>
-        13 6 2 3</rect></_>
+        13 6 3 3</rect></_>
+    <_>
+      <rect>
+        13 7 1 4</rect></_>
     <_>
       <rect>
         13 7 3 2</rect></_>
@@ -3065,6 +3461,9 @@
         13 8 1 1</rect></_>
     <_>
       <rect>
+        13 8 2 2</rect></_>
+    <_>
+      <rect>
         13 9 1 1</rect></_>
     <_>
       <rect>
@@ -3077,40 +3476,46 @@
         13 11 1 1</rect></_>
     <_>
       <rect>
-        13 13 1 1</rect></_>
+        13 15 1 1</rect></_>
     <_>
       <rect>
-        13 19 1 1</rect></_>
+        13 16 1 1</rect></_>
     <_>
       <rect>
         13 20 1 1</rect></_>
     <_>
       <rect>
-        13 21 1 1</rect></_>
-    <_>
-      <rect>
         14 0 3 4</rect></_>
     <_>
       <rect>
-        14 3 1 2</rect></_>
+        14 1 2 1</rect></_>
     <_>
       <rect>
-        14 3 2 1</rect></_>
+        14 3 1 3</rect></_>
     <_>
       <rect>
         14 4 1 1</rect></_>
     <_>
       <rect>
+        14 4 3 2</rect></_>
+    <_>
+      <rect>
         14 5 1 1</rect></_>
     <_>
       <rect>
-        14 6 2 3</rect></_>
+        14 5 1 2</rect></_>
+    <_>
+      <rect>
+        14 6 2 1</rect></_>
+    <_>
+      <rect>
+        14 7 1 1</rect></_>
     <_>
       <rect>
-        14 7 1 3</rect></_>
+        14 7 1 2</rect></_>
     <_>
       <rect>
-        14 7 2 2</rect></_>
+        14 7 2 5</rect></_>
     <_>
       <rect>
         14 8 1 1</rect></_>
@@ -3122,31 +3527,46 @@
         14 9 1 1</rect></_>
     <_>
       <rect>
+        14 9 1 2</rect></_>
+    <_>
+      <rect>
         14 9 2 1</rect></_>
     <_>
       <rect>
         14 13 1 1</rect></_>
     <_>
       <rect>
-        14 21 1 1</rect></_>
+        14 14 2 2</rect></_>
+    <_>
+      <rect>
+        14 18 1 2</rect></_>
+    <_>
+      <rect>
+        14 21 2 1</rect></_>
     <_>
       <rect>
         15 0 3 4</rect></_>
     <_>
       <rect>
+        15 0 3 5</rect></_>
+    <_>
+      <rect>
         15 1 1 2</rect></_>
     <_>
       <rect>
-        15 2 1 2</rect></_>
+        15 2 2 2</rect></_>
     <_>
       <rect>
-        15 5 1 1</rect></_>
+        15 3 2 1</rect></_>
+    <_>
+      <rect>
+        15 4 1 1</rect></_>
     <_>
       <rect>
-        15 6 2 1</rect></_>
+        15 5 1 1</rect></_>
     <_>
       <rect>
-        15 6 2 2</rect></_>
+        15 6 1 1</rect></_>
     <_>
       <rect>
         15 7 1 1</rect></_>
@@ -3158,30 +3578,69 @@
         15 7 2 2</rect></_>
     <_>
       <rect>
+        15 7 3 2</rect></_>
+    <_>
+      <rect>
         15 8 1 1</rect></_>
     <_>
       <rect>
         15 9 1 1</rect></_>
     <_>
       <rect>
+        15 9 1 4</rect></_>
+    <_>
+      <rect>
         15 9 1 5</rect></_>
     <_>
       <rect>
-        15 9 2 1</rect></_>
+        15 10 2 1</rect></_>
+    <_>
+      <rect>
+        15 11 1 1</rect></_>
+    <_>
+      <rect>
+        15 13 2 2</rect></_>
+    <_>
+      <rect>
+        15 15 3 2</rect></_>
     <_>
       <rect>
-        15 15 3 3</rect></_>
+        15 16 2 2</rect></_>
     <_>
       <rect>
         15 17 1 1</rect></_>
     <_>
       <rect>
+        15 17 3 2</rect></_>
+    <_>
+      <rect>
+        15 18 1 1</rect></_>
+    <_>
+      <rect>
+        15 18 3 2</rect></_>
+    <_>
+      <rect>
+        15 19 1 1</rect></_>
+    <_>
+      <rect>
+        15 21 3 1</rect></_>
+    <_>
+      <rect>
         16 4 1 1</rect></_>
     <_>
       <rect>
+        16 5 1 1</rect></_>
+    <_>
+      <rect>
+        16 5 2 2</rect></_>
+    <_>
+      <rect>
         16 6 1 1</rect></_>
     <_>
       <rect>
+        16 6 2 2</rect></_>
+    <_>
+      <rect>
         16 7 1 1</rect></_>
     <_>
       <rect>
@@ -3191,10 +3650,10 @@
         16 7 2 1</rect></_>
     <_>
       <rect>
-        16 7 2 2</rect></_>
+        16 8 1 1</rect></_>
     <_>
       <rect>
-        16 8 1 1</rect></_>
+        16 9 1 1</rect></_>
     <_>
       <rect>
         16 10 1 1</rect></_>
@@ -3209,13 +3668,10 @@
         16 17 1 2</rect></_>
     <_>
       <rect>
-        16 18 1 1</rect></_>
+        16 19 1 1</rect></_>
     <_>
       <rect>
-        17 4 2 2</rect></_>
-    <_>
-      <rect>
-        17 5 1 1</rect></_>
+        17 1 2 3</rect></_>
     <_>
       <rect>
         17 6 2 1</rect></_>
@@ -3233,10 +3689,10 @@
         17 8 1 1</rect></_>
     <_>
       <rect>
-        17 8 2 1</rect></_>
+        17 9 1 1</rect></_>
     <_>
       <rect>
-        17 9 1 1</rect></_>
+        17 9 2 2</rect></_>
     <_>
       <rect>
         17 10 1 1</rect></_>
@@ -3251,86 +3707,62 @@
         17 12 1 2</rect></_>
     <_>
       <rect>
-        17 13 1 2</rect></_>
-    <_>
-      <rect>
-        17 13 1 3</rect></_>
+        17 13 1 1</rect></_>
     <_>
       <rect>
-        17 21 2 1</rect></_>
+        18 0 2 1</rect></_>
     <_>
       <rect>
         18 0 2 2</rect></_>
     <_>
       <rect>
-        18 4 1 2</rect></_>
+        18 4 2 2</rect></_>
     <_>
       <rect>
-        18 6 1 1</rect></_>
+        18 5 1 1</rect></_>
     <_>
       <rect>
-        18 8 2 2</rect></_>
+        18 6 1 1</rect></_>
     <_>
       <rect>
-        18 9 1 1</rect></_>
+        18 6 1 2</rect></_>
     <_>
       <rect>
-        18 9 1 2</rect></_>
+        18 8 1 1</rect></_>
     <_>
       <rect>
-        18 9 1 3</rect></_>
+        18 9 1 1</rect></_>
     <_>
       <rect>
         18 10 1 1</rect></_>
     <_>
       <rect>
-        18 11 1 2</rect></_>
+        18 11 1 3</rect></_>
     <_>
       <rect>
         18 12 1 1</rect></_>
     <_>
       <rect>
-        18 13 1 2</rect></_>
-    <_>
-      <rect>
         18 17 2 2</rect></_>
     <_>
       <rect>
-        18 18 1 2</rect></_>
-    <_>
-      <rect>
-        18 19 2 1</rect></_>
+        19 4 1 1</rect></_>
     <_>
       <rect>
-        19 0 1 1</rect></_>
-    <_>
-      <rect>
-        19 6 1 1</rect></_>
+        19 5 1 1</rect></_>
     <_>
       <rect>
         19 9 1 1</rect></_>
     <_>
       <rect>
-        19 9 1 2</rect></_>
-    <_>
-      <rect>
-        19 10 1 4</rect></_>
+        19 11 1 1</rect></_>
     <_>
       <rect>
         19 12 1 2</rect></_>
     <_>
       <rect>
-        20 10 1 1</rect></_>
-    <_>
-      <rect>
-        20 15 1 2</rect></_>
-    <_>
-      <rect>
-        21 10 1 1</rect></_>
-    <_>
-      <rect>
-        21 14 1 2</rect></_>
+        19 15 1 2</rect></_>
     <_>
       <rect>
-        21 15 1 3</rect></_></features></cascade>
+        20 10 1 1</rect></_></features></cascade>
 </opencv_storage>
diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt
index c8ee763..f956cde 100644
--- a/doc/CMakeLists.txt
+++ b/doc/CMakeLists.txt
@@ -42,6 +42,7 @@ if(BUILD_DOCS AND DOXYGEN_FOUND)
   set(paths_bib)
   set(paths_sample)
   set(paths_tutorial)
+  set(paths_hal_interface)
   set(refs_main)
   set(refs_extra)
   set(deps)
@@ -87,6 +88,11 @@ if(BUILD_DOCS AND DOXYGEN_FOUND)
           file(APPEND "${tutorial_contrib_root}" "- ${m}. @subpage ${tutorial_id}\n")
         endforeach()
       endif()
+      # HAL replacement file
+      set(replacement_header "${OPENCV_MODULE_opencv_${m}_LOCATION}/src/hal_replacement.hpp")
+      if(EXISTS "${replacement_header}")
+        list(APPEND paths_hal_interface "${replacement_header}")
+      endif()
 
       # BiBTeX file
       set(bib_file "${docs_dir}/${m}.bib")
@@ -131,7 +137,7 @@ if(BUILD_DOCS AND DOXYGEN_FOUND)
   set(example_path "${CMAKE_SOURCE_DIR}/samples")
 
   # set export variables
-  string(REPLACE ";" " \\\n" CMAKE_DOXYGEN_INPUT_LIST "${rootfile} ; ${faqfile} ; ${paths_include} ; ${paths_doc} ; ${tutorial_path} ; ${tutorial_py_path} ; ${paths_tutorial} ; ${tutorial_contrib_root}")
+  string(REPLACE ";" " \\\n" CMAKE_DOXYGEN_INPUT_LIST "${rootfile} ; ${faqfile} ; ${paths_include} ; ${paths_hal_interface} ; ${paths_doc} ; ${tutorial_path} ; ${tutorial_py_path} ; ${paths_tutorial} ; ${tutorial_contrib_root}")
   string(REPLACE ";" " \\\n" CMAKE_DOXYGEN_IMAGE_PATH "${paths_doc} ; ${tutorial_path} ; ${tutorial_py_path} ; ${paths_tutorial}")
   # TODO: remove paths_doc from EXAMPLE_PATH after face module tutorials/samples moved to separate folders
   string(REPLACE ";" " \\\n" CMAKE_DOXYGEN_EXAMPLE_PATH  "${example_path} ; ${paths_doc} ; ${paths_sample}")
@@ -153,12 +159,6 @@ if(BUILD_DOCS AND DOXYGEN_FOUND)
   list(APPEND CMAKE_DOXYGEN_HTML_FILES "${CMAKE_CURRENT_SOURCE_DIR}/mymath.sty")
   string(REPLACE ";" " \\\n" CMAKE_DOXYGEN_HTML_FILES "${CMAKE_DOXYGEN_HTML_FILES}")
 
-  if(PLANTUML_JAR)
-    set(CMAKE_DOXYGEN_PLANTUML_SUPPORT "PLANTUML_JAR_PATH      = ${PLANTUML_JAR}\n")
-  else()
-    set(CMAKE_DOXYGEN_PLANTUML_SUPPORT "ALIASES               += startuml{1}=\"@warning __No plantuml!__ \\n \\n @if DUMMY_PLANTUML_CODE\" enduml=\"@endif\"\n")
-  endif()
-
   # writing file
   configure_file(Doxyfile.in ${doxyfile} @ONLY)
   configure_file(root.markdown.in ${rootfile} @ONLY)
@@ -171,4 +171,10 @@ if(BUILD_DOCS AND DOXYGEN_FOUND)
     DESTINATION "${OPENCV_DOC_INSTALL_PATH}"
     COMPONENT "docs" OPTIONAL
   )
+
+  # Alias to build/install docs only
+  add_custom_target(install_docs
+      DEPENDS doxygen
+      COMMAND "${CMAKE_COMMAND}" -DCMAKE_INSTALL_COMPONENT=docs -P "${CMAKE_BINARY_DIR}/cmake_install.cmake"
+  )
 endif()
diff --git a/doc/Doxyfile.in b/doc/Doxyfile.in
index c4da726..2e4ac70 100644
--- a/doc/Doxyfile.in
+++ b/doc/Doxyfile.in
@@ -31,10 +31,17 @@ MULTILINE_CPP_IS_BRIEF = NO
 INHERIT_DOCS           = YES
 SEPARATE_MEMBER_PAGES  = NO
 TAB_SIZE               = 4
-ALIASES                =
+ALIASES               += add_toggle{1}="@htmlonly[block] <div class='newInnerHTML'>\1</div><div> <script type="text/javascript"> addToggle(); </script>@endhtmlonly"
+ALIASES               += add_toggle_cpp="@htmlonly[block] <div class='newInnerHTML' title='cpp' style='display: none;'>C++</div><div class='toggleable_div label_cpp' style='display: none;'>@endhtmlonly"
+ALIASES               += add_toggle_java="@htmlonly[block] <div class='newInnerHTML' title='java' style='display: none;'>Java</div><div class='toggleable_div label_java' style='display: none;'>@endhtmlonly"
+ALIASES               += add_toggle_python="@htmlonly[block] <div class='newInnerHTML' title='python' style='display: none;'>Python</div><div class='toggleable_div label_python' style='display: none;'>@endhtmlonly"
+ALIASES               += end_toggle="@htmlonly[block] </div> @endhtmlonly"
+ALIASES               += prev_tutorial{1}="**Prev  Tutorial:** \ref \1 \n"
+ALIASES               += next_tutorial{1}="**Next  Tutorial:** \ref \1 \n"
+ALIASES               += youtube{1}="@htmlonly[block]<div align='center'><iframe title='my title' width='560' height='349' src='http://www.youtube.com/embed/\1?rel=0' frameborder='0' align='middle' allowfullscreen></iframe></div>@endhtmlonly"
 TCL_SUBST              =
 OPTIMIZE_OUTPUT_FOR_C  = NO
-OPTIMIZE_OUTPUT_JAVA   = NO
+OPTIMIZE_OUTPUT_JAVA   = YES
 OPTIMIZE_FOR_FORTRAN   = NO
 OPTIMIZE_OUTPUT_VHDL   = NO
 EXTENSION_MAPPING      =
@@ -150,7 +157,7 @@ BINARY_TOC             = NO
 TOC_EXPAND             = NO
 GENERATE_QHP           = @CMAKE_DOXYGEN_GENERATE_QHP@
 QCH_FILE               = ../opencv- at OPENCV_VERSION@.qch
-QHP_NAMESPACE          = org.itseez.opencv. at OPENCV_VERSION@
+QHP_NAMESPACE          = org.opencv. at OPENCV_VERSION@
 QHP_VIRTUAL_FOLDER     = opencv
 QHP_CUST_FILTER_NAME   =
 QHP_CUST_FILTER_ATTRS  =
@@ -286,4 +293,3 @@ DOT_TRANSPARENT        = NO
 DOT_MULTI_TARGETS      = NO
 GENERATE_LEGEND        = YES
 DOT_CLEANUP            = YES
- at CMAKE_DOXYGEN_PLANTUML_SUPPORT@
diff --git a/doc/footer.html b/doc/footer.html
index e9a2ed7..c636144 100644
--- a/doc/footer.html
+++ b/doc/footer.html
@@ -17,5 +17,74 @@ $generatedby  <a href="http://www.doxygen.org/index.html">
 </a> $doxygenversion
 </small></address>
 <!--END !GENERATE_TREEVIEW-->
+<script type="text/javascript">
+//<![CDATA[
+function addButton(label, buttonName) {
+    var b = document.createElement("BUTTON");
+    b.innerHTML = buttonName;
+    b.setAttribute('class', 'toggleable_button label_' + label);
+    b.onclick = function() {
+        $('.toggleable_button').css({
+            border: '2px outset',
+            'border-radius': '4px'
+        });
+        $('.toggleable_button.label_' + label).css({
+            border: '2px inset',
+            'border-radius': '4px'
+        });
+        $('.toggleable_div').css('display', 'none');
+        $('.toggleable_div.label_' + label).css('display', 'block');
+    };
+    b.style.border = '2px outset';
+    b.style.borderRadius = '4px';
+    b.style.margin = '2px';
+    return b;
+}
+function buttonsToAdd($elements, $heading, $type) {
+    if ($elements.length === 0) {
+        $elements = $("" + $type + ":contains(" + $heading.html() + ")").parent().prev("div.newInnerHTML");
+    }
+    var arr = jQuery.makeArray($elements);
+    var seen = {};
+    arr.forEach(function(e) {
+        var txt = e.innerHTML;
+        if (!seen[txt]) {
+            $button = addButton(e.title, txt);
+            if (Object.keys(seen).length == 0) {
+                var linebreak1 = document.createElement("br");
+                var linebreak2 = document.createElement("br");
+                ($heading).append(linebreak1);
+                ($heading).append(linebreak2);
+            }
+            ($heading).append($button);
+            seen[txt] = true;
+        }
+    });
+    return;
+}
+$("h2").each(function() {
+    $heading = $(this);
+    $smallerHeadings = $(this).nextUntil("h2").filter("h3").add($(this).nextUntil("h2").find("h3"));
+    if ($smallerHeadings.length) {
+        $smallerHeadings.each(function() {
+            var $elements = $(this).nextUntil("h3").filter("div.newInnerHTML");
+            buttonsToAdd($elements, $(this), "h3");
+        });
+    } else {
+        var $elements = $(this).nextUntil("h2").filter("div.newInnerHTML");
+        buttonsToAdd($elements, $heading, "h2");
+    }
+});
+$(".toggleable_button").first().click();
+var $clickDefault = $('.toggleable_button.label_python').first();
+if ($clickDefault.length) {
+    $clickDefault.click();
+}
+$clickDefault = $('.toggleable_button.label_cpp').first();
+if ($clickDefault.length) {
+    $clickDefault.click();
+}
+//]]>
+</script>
 </body>
 </html>
diff --git a/doc/header.html b/doc/header.html
index bbaf1d5..94d42b4 100644
--- a/doc/header.html
+++ b/doc/header.html
@@ -54,4 +54,34 @@ $extrastylesheet
 </table>
 </div>
 <!--END TITLEAREA-->
+<script type="text/javascript">
+//<![CDATA[
+function getLabelName(innerHTML) {
+    var str = innerHTML.toLowerCase();
+    // Replace all '+' with 'p'
+    str = str.split('+').join('p');
+    // Replace all ' ' with '_'
+    str = str.split(' ').join('_');
+    // Replace all '#' with 'sharp'
+    str = str.split('#').join('sharp');
+    // Replace other special characters with 'ascii' + code
+    for (var i = 0; i < str.length; i++) {
+        var charCode = str.charCodeAt(i);
+        if (!(charCode == 95 || (charCode > 96 && charCode < 123) || (charCode > 47 && charCode < 58)))
+            str = str.substr(0, i) + 'ascii' + charCode + str.substr(i + 1);
+    }
+    return str;
+}
+function addToggle() {
+    var $getDiv = $('div.newInnerHTML').last();
+    var buttonName = $getDiv.html();
+    var label = getLabelName(buttonName.trim());
+    $getDiv.attr("title", label);
+    $getDiv.hide();
+    $getDiv = $getDiv.next();
+    $getDiv.attr("class", "toggleable_div label_" + label);
+    $getDiv.hide();
+}
+//]]>
+</script>
 <!-- end header part -->
diff --git a/doc/mymath.js b/doc/mymath.js
index df9f551..fb65fab 100644
--- a/doc/mymath.js
+++ b/doc/mymath.js
@@ -1,4 +1,4 @@
-
+//<![CDATA[
 MathJax.Hub.Config(
 {
   TeX: {
@@ -15,3 +15,4 @@ MathJax.Hub.Config(
   }
 }
 );
+//]]>
diff --git a/doc/opencv.bib b/doc/opencv.bib
index 021c5b4..29a2ae4 100644
--- a/doc/opencv.bib
+++ b/doc/opencv.bib
@@ -457,6 +457,11 @@
   title = {ROF and TV-L1 denoising with Primal-Dual algorithm},
   url = {http://znah.net/rof-and-tv-l1-denoising-with-primal-dual-algorithm.html}
 }
+ at MISC{VandLec,
+  author = {Vandenberghe, Lieven},
+  title = {QR Factorization},
+  url = {http://www.seas.ucla.edu/~vandenbe/133A/lectures/qr.pdf}
+}
 @ARTICLE{MHT2011,
   author = {Getreuer, Pascal},
   title = {Malvar-He-Cutler Linear Image Demosaicking},
@@ -750,7 +755,7 @@
   organization = {ACM}
 }
 @INPROCEEDINGS{Viola01,
-  author = {Viola, Paul and Jones, Michael},
+  author = {Viola, Paul and Jones, Michael J.},
   title = {Rapid object detection using a boosted cascade of simple features},
   booktitle = {Computer Vision and Pattern Recognition, 2001. CVPR 2001. Proceedings of the 2001 IEEE Computer Society Conference on},
   year = {2001},
@@ -758,6 +763,16 @@
   volume = {1},
   organization = {IEEE}
 }
+ at ARTICLE{Viola04,
+  author = {Viola, Paul and Jones, Michael J.},
+  title = {Robust real-time face detection},
+  journal = {International Journal of Computer Vision},
+  year = {2004},
+  volume = {57},
+  number = {2},
+  pages = {137--154},
+  publisher = {Kluwer Academic Publishers}
+}
 @INPROCEEDINGS{WJ10,
   author = {Xu, Wei and Mulligan, Jane},
   title = {Performance evaluation of color correction approaches for automatic multi-view image and video stitching},
@@ -874,3 +889,11 @@
   year={2007},
   organization={IEEE}
 }
+ at incollection{bottou2010large,
+  title={Large-scale machine learning with stochastic gradient descent},
+  author={Bottou, L{\'e}on},
+  booktitle={Proceedings of COMPSTAT'2010},
+  pages={177--186},
+  year={2010},
+  publisher={Springer}
+}
diff --git a/doc/pattern_tools/gen_pattern.py b/doc/pattern_tools/gen_pattern.py
index ebeeb12..85b3ea4 100755
--- a/doc/pattern_tools/gen_pattern.py
+++ b/doc/pattern_tools/gen_pattern.py
@@ -61,7 +61,7 @@ class PatternMaker:
 
   def save(self):
     c = canvas(self.g,width="%d%s"%(self.width,self.units),height="%d%s"%(self.height,self.units),viewBox="0 0 %d %d"%(self.width,self.height))
-    c.inkview(self.output)
+    c.save(self.output)
 
 
 def main():
diff --git a/doc/py_tutorials/py_bindings/py_bindings_basics/py_bindings_basics.markdown b/doc/py_tutorials/py_bindings/py_bindings_basics/py_bindings_basics.markdown
index e256bce..4f48ae7 100644
--- a/doc/py_tutorials/py_bindings/py_bindings_basics/py_bindings_basics.markdown
+++ b/doc/py_tutorials/py_bindings/py_bindings_basics/py_bindings_basics.markdown
@@ -142,5 +142,6 @@ public:
 So these are the major extension macros available in OpenCV. Typically, a developer has to put
 proper macros in their appropriate positions. Rest is done by generator scripts. Sometimes, there
 may be an exceptional cases where generator scripts cannot create the wrappers. Such functions need
-to be handled manually. But most of the time, a code written according to OpenCV coding guidelines
-will be automatically wrapped by generator scripts.
+to be handled manually, to do this write your own pyopencv_*.hpp extending headers and put them into
+misc/python subdirectory of your module. But most of the time, a code written according to OpenCV
+coding guidelines will be automatically wrapped by generator scripts.
\ No newline at end of file
diff --git a/doc/py_tutorials/py_calib3d/py_calibration/py_calibration.markdown b/doc/py_tutorials/py_calib3d/py_calibration/py_calibration.markdown
index 3655400..1e22ced 100644
--- a/doc/py_tutorials/py_calib3d/py_calibration/py_calibration.markdown
+++ b/doc/py_tutorials/py_calib3d/py_calibration/py_calibration.markdown
@@ -121,21 +121,21 @@ images = glob.glob('*.jpg')
 
 for fname in images:
     img = cv2.imread(fname)
-    gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
+    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
 
     # Find the chess board corners
-    ret, corners = cv2.findChessboardCorners(gray, (7,6),None)
+    ret, corners = cv2.findChessboardCorners(gray, (7,6), None)
 
     # If found, add object points, image points (after refining them)
     if ret == True:
         objpoints.append(objp)
 
-        cv2.cornerSubPix(gray,corners,(11,11),(-1,-1),criteria)
+        corners2=cv2.cornerSubPix(gray,corners, (11,11), (-1,-1), criteria)
         imgpoints.append(corners)
 
         # Draw and display the corners
-        cv2.drawChessboardCorners(img, (7,6), corners2,ret)
-        cv2.imshow('img',img)
+        cv2.drawChessboardCorners(img, (7,6), corners2, ret)
+        cv2.imshow('img', img)
         cv2.waitKey(500)
 
 cv2.destroyAllWindows()
@@ -150,7 +150,7 @@ So now we have our object points and image points we are ready to go for calibra
 use the function, **cv2.calibrateCamera()**. It returns the camera matrix, distortion coefficients,
 rotation and translation vectors etc.
 @code{.py}
-ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(objpoints, imgpoints, gray.shape[::-1],None,None)
+ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(objpoints, imgpoints, gray.shape[::-1], None, None)
 @endcode
 ### Undistortion
 
@@ -165,7 +165,7 @@ So we take a new image (left12.jpg in this case. That is the first image in this
 @code{.py}
 img = cv2.imread('left12.jpg')
 h,  w = img.shape[:2]
-newcameramtx, roi=cv2.getOptimalNewCameraMatrix(mtx,dist,(w,h),1,(w,h))
+newcameramtx, roi=cv2.getOptimalNewCameraMatrix(mtx, dist, (w,h), 1, (w,h))
 @endcode
 #### 1. Using **cv2.undistort()**
 
@@ -175,9 +175,9 @@ This is the shortest path. Just call the function and use ROI obtained above to
 dst = cv2.undistort(img, mtx, dist, None, newcameramtx)
 
 # crop the image
-x,y,w,h = roi
+x, y, w, h = roi
 dst = dst[y:y+h, x:x+w]
-cv2.imwrite('calibresult.png',dst)
+cv2.imwrite('calibresult.png', dst)
 @endcode
 #### 2. Using **remapping**
 
@@ -185,13 +185,13 @@ This is curved path. First find a mapping function from distorted image to undis
 use the remap function.
 @code{.py}
 # undistort
-mapx,mapy = cv2.initUndistortRectifyMap(mtx,dist,None,newcameramtx,(w,h),5)
-dst = cv2.remap(img,mapx,mapy,cv2.INTER_LINEAR)
+mapx, mapy = cv2.initUndistortRectifyMap(mtx, dist, None, newcameramtx, (w,h), 5)
+dst = cv2.remap(img, mapx, mapy, cv2.INTER_LINEAR)
 
 # crop the image
-x,y,w,h = roi
+x, y, w, h = roi
 dst = dst[y:y+h, x:x+w]
-cv2.imwrite('calibresult.png',dst)
+cv2.imwrite('calibresult.png', dst)
 @endcode
 Both the methods give the same result. See the result below:
 
@@ -215,8 +215,8 @@ calibration images.
 mean_error = 0
 for i in xrange(len(objpoints)):
     imgpoints2, _ = cv2.projectPoints(objpoints[i], rvecs[i], tvecs[i], mtx, dist)
-    error = cv2.norm(imgpoints[i],imgpoints2, cv2.NORM_L2)/len(imgpoints2)
-    tot_error += error
+    error = cv2.norm(imgpoints[i], imgpoints2, cv2.NORM_L2)/len(imgpoints2)
+    mean_error += error
 
 print "total error: ", mean_error/len(objpoints)
 @endcode
diff --git a/doc/py_tutorials/py_calib3d/py_pose/py_pose.markdown b/doc/py_tutorials/py_calib3d/py_pose/py_pose.markdown
index f0d4826..0ec22c6 100644
--- a/doc/py_tutorials/py_calib3d/py_pose/py_pose.markdown
+++ b/doc/py_tutorials/py_calib3d/py_pose/py_pose.markdown
@@ -70,15 +70,15 @@ for fname in glob.glob('left*.jpg'):
         corners2 = cv2.cornerSubPix(gray,corners,(11,11),(-1,-1),criteria)
 
         # Find the rotation and translation vectors.
-        rvecs, tvecs, inliers = cv2.solvePnPRansac(objp, corners2, mtx, dist)
+        ret,rvecs, tvecs, inliers = cv2.solvePnP(objp, corners2, mtx, dist)
 
         # project 3D points to image plane
         imgpts, jac = cv2.projectPoints(axis, rvecs, tvecs, mtx, dist)
 
         img = draw(img,corners2,imgpts)
         cv2.imshow('img',img)
-        k = cv2.waitKey(0) & 0xff
-        if k == 's':
+        k = cv2.waitKey(0) & 0xFF
+        if k == ord('s'):
             cv2.imwrite(fname[:6]+'.png', img)
 
 cv2.destroyAllWindows()
diff --git a/doc/py_tutorials/py_core/py_basic_ops/py_basic_ops.markdown b/doc/py_tutorials/py_core/py_basic_ops/py_basic_ops.markdown
index a9b4905..19992fc 100644
--- a/doc/py_tutorials/py_core/py_basic_ops/py_basic_ops.markdown
+++ b/doc/py_tutorials/py_core/py_basic_ops/py_basic_ops.markdown
@@ -173,7 +173,7 @@ from matplotlib import pyplot as plt
 
 BLUE = [255,0,0]
 
-img1 = cv2.imread('opencv_logo.png')
+img1 = cv2.imread('opencv-logo.png')
 
 replicate = cv2.copyMakeBorder(img1,10,10,10,10,cv2.BORDER_REPLICATE)
 reflect = cv2.copyMakeBorder(img1,10,10,10,10,cv2.BORDER_REFLECT)
diff --git a/doc/py_tutorials/py_core/py_image_arithmetics/py_image_arithmetics.markdown b/doc/py_tutorials/py_core/py_image_arithmetics/py_image_arithmetics.markdown
index 609e610..8995c93 100644
--- a/doc/py_tutorials/py_core/py_image_arithmetics/py_image_arithmetics.markdown
+++ b/doc/py_tutorials/py_core/py_image_arithmetics/py_image_arithmetics.markdown
@@ -51,7 +51,7 @@ is given 0.3. cv2.addWeighted() applies following equation on the image.
 Here \f$\gamma\f$ is taken as zero.
 @code{.py}
 img1 = cv2.imread('ml.png')
-img2 = cv2.imread('opencv_logo.jpg')
+img2 = cv2.imread('opencv-logo.png')
 
 dst = cv2.addWeighted(img1,0.7,img2,0.3,0)
 
@@ -77,7 +77,7 @@ bitwise operations as below:
 @code{.py}
 # Load two images
 img1 = cv2.imread('messi5.jpg')
-img2 = cv2.imread('opencv_logo.png')
+img2 = cv2.imread('opencv-logo.png')
 
 # I want to put logo on top-left corner, So I create a ROI
 rows,cols,channels = img2.shape
diff --git a/doc/py_tutorials/py_feature2d/py_brief/py_brief.markdown b/doc/py_tutorials/py_feature2d/py_brief/py_brief.markdown
index e2c0ed4..57e284c 100644
--- a/doc/py_tutorials/py_feature2d/py_brief/py_brief.markdown
+++ b/doc/py_tutorials/py_feature2d/py_brief/py_brief.markdown
@@ -49,7 +49,7 @@ BRIEF in OpenCV
 Below code shows the computation of BRIEF descriptors with the help of CenSurE detector. (CenSurE
 detector is called STAR detector in OpenCV)
 
-note, that you need [opencv contrib](https://github.com/Itseez/opencv_contrib)) to use this.
+note, that you need [opencv contrib](https://github.com/opencv/opencv_contrib)) to use this.
 @code{.py}
 import numpy as np
 import cv2
@@ -61,7 +61,7 @@ img = cv2.imread('simple.jpg',0)
 star = cv2.xfeatures2d.StarDetector_create()
 
 # Initiate BRIEF extractor
-brief = cv2.BriefDescriptorExtractor_create()
+brief = cv2.xfeatures2d.BriefDescriptorExtractor_create()
 
 # find the keypoints with STAR
 kp = star.detect(img,None)
@@ -69,10 +69,10 @@ kp = star.detect(img,None)
 # compute the descriptors with BRIEF
 kp, des = brief.compute(img, kp)
 
-print brief.getInt('bytes')
+print brief.descriptorSize()
 print des.shape
 @endcode
-The function brief.getInt('bytes') gives the \f$n_d\f$ size used in bytes. By default it is 32. Next one
+The function brief.getDescriptorSize() gives the \f$n_d\f$ size used in bytes. By default it is 32. Next one
 is matching, which will be done in another chapter.
 
 Additional Resources
diff --git a/doc/py_tutorials/py_feature2d/py_fast/py_fast.markdown b/doc/py_tutorials/py_feature2d/py_fast/py_fast.markdown
index 1534c57..e30107e 100644
--- a/doc/py_tutorials/py_feature2d/py_fast/py_fast.markdown
+++ b/doc/py_tutorials/py_feature2d/py_fast/py_fast.markdown
@@ -105,23 +105,23 @@ fast = cv2.FastFeatureDetector_create()
 
 # find and draw the keypoints
 kp = fast.detect(img,None)
-img2 = cv2.drawKeypoints(img, kp, color=(255,0,0))
+img2 = cv2.drawKeypoints(img, kp, None, color=(255,0,0))
 
 # Print all default params
-print "Threshold: ", fast.getInt('threshold')
-print "nonmaxSuppression: ", fast.getBool('nonmaxSuppression')
-print "neighborhood: ", fast.getInt('type')
+print "Threshold: ", fast.getThreshold()
+print "nonmaxSuppression: ", fast.getNonmaxSuppression()
+print "neighborhood: ", fast.getType()
 print "Total Keypoints with nonmaxSuppression: ", len(kp)
 
 cv2.imwrite('fast_true.png',img2)
 
 # Disable nonmaxSuppression
-fast.setBool('nonmaxSuppression',0)
+fast.setNonmaxSuppression(0)
 kp = fast.detect(img,None)
 
 print "Total Keypoints without nonmaxSuppression: ", len(kp)
 
-img3 = cv2.drawKeypoints(img, kp, color=(255,0,0))
+img3 = cv2.drawKeypoints(img, kp, None, color=(255,0,0))
 
 cv2.imwrite('fast_false.png',img3)
 @endcode
diff --git a/doc/py_tutorials/py_feature2d/py_features_meaning/py_features_meaning.markdown b/doc/py_tutorials/py_feature2d/py_features_meaning/py_features_meaning.markdown
index 79d09c5..166ffba 100644
--- a/doc/py_tutorials/py_feature2d/py_features_meaning/py_features_meaning.markdown
+++ b/doc/py_tutorials/py_feature2d/py_features_meaning/py_features_meaning.markdown
@@ -22,61 +22,61 @@ Well, the questions and imaginations continue. But it all depends on the most ba
 you play jigsaw puzzles? How do you arrange lots of scrambled image pieces into a big single image?
 How can you stitch a lot of natural images to a single image?
 
-The answer is, we are looking for specific patterns or specific features which are unique, which can
-be easily tracked, which can be easily compared. If we go for a definition of such a feature, we may
-find it difficult to express it in words, but we know what are they. If some one asks you to point
+The answer is, we are looking for specific patterns or specific features which are unique, can
+be easily tracked and can be easily compared. If we go for a definition of such a feature, we may
+find it difficult to express it in words, but we know what they are. If someone asks you to point
 out one good feature which can be compared across several images, you can point out one. That is
-why, even small children can simply play these games. We search for these features in an image, we
-find them, we find the same features in other images, we align them. That's it. (In jigsaw puzzle,
+why even small children can simply play these games. We search for these features in an image,
+find them, look for the same features in other images and align them. That's it. (In jigsaw puzzle,
 we look more into continuity of different images). All these abilities are present in us inherently.
 
 So our one basic question expands to more in number, but becomes more specific. **What are these
-features?**. *(The answer should be understandable to a computer also.)*
+features?**. (The answer should be understandable also to a computer.)
 
-Well, it is difficult to say how humans find these features. It is already programmed in our brain.
+It is difficult to say how humans find these features. This is already programmed in our brain.
 But if we look deep into some pictures and search for different patterns, we will find something
 interesting. For example, take below image:
 
 ![image](images/feature_building.jpg)
 
-Image is very simple. At the top of image, six small image patches are given. Question for you is to
-find the exact location of these patches in the original image. How many correct results you can
-find ?
+The image is very simple. At the top of image, six small image patches are given. Question for you is to
+find the exact location of these patches in the original image. How many correct results can you
+find?
 
-A and B are flat surfaces, and they are spread in a lot of area. It is difficult to find the exact
+A and B are flat surfaces and they are spread over a lot of area. It is difficult to find the exact
 location of these patches.
 
-C and D are much more simpler. They are edges of the building. You can find an approximate location,
-but exact location is still difficult. It is because, along the edge, it is same everywhere. Normal
-to the edge, it is different. So edge is a much better feature compared to flat area, but not good
-enough (It is good in jigsaw puzzle for comparing continuity of edges).
+C and D are much more simple. They are edges of the building. You can find an approximate location,
+but exact location is still difficult. This is because the pattern is same everywhere along the edge.
+At the edge, however, it is different. An edge is therefore better feature compared to flat area, but
+not good enough (It is good in jigsaw puzzle for comparing continuity of edges).
 
-Finally, E and F are some corners of the building. And they can be easily found out. Because at
-corners, wherever you move this patch, it will look different. So they can be considered as a good
-feature. So now we move into more simpler (and widely used image) for better understanding.
+Finally, E and F are some corners of the building. And they can be easily found. Because at the
+corners, wherever you move this patch, it will look different. So they can be considered as good
+features. So now we move into simpler (and widely used image) for better understanding.
 
 ![image](images/feature_simple.png)
 
-Just like above, blue patch is flat area and difficult to find and track. Wherever you move the blue
-patch, it looks the same. For black patch, it is an edge. If you move it in vertical direction (i.e.
-along the gradient) it changes. Put along the edge (parallel to edge), it looks the same. And for
+Just like above, the blue patch is flat area and difficult to find and track. Wherever you move the blue
+patch it looks the same. The black patch has an edge. If you move it in vertical direction (i.e.
+along the gradient) it changes. Moved along the edge (parallel to edge), it looks the same. And for
 red patch, it is a corner. Wherever you move the patch, it looks different, means it is unique. So
 basically, corners are considered to be good features in an image. (Not just corners, in some cases
 blobs are considered good features).
 
 So now we answered our question, "what are these features?". But next question arises. How do we
-find them? Or how do we find the corners?. That also we answered in an intuitive way, i.e., look for
+find them? Or how do we find the corners?. We answered that in an intuitive way, i.e., look for
 the regions in images which have maximum variation when moved (by a small amount) in all regions
 around it. This would be projected into computer language in coming chapters. So finding these image
 features is called **Feature Detection**.
 
-So we found the features in image (Assume you did it). Once you found it, you should find the same
-in the other images. What we do? We take a region around the feature, we explain it in our own
-words, like "upper part is blue sky, lower part is building region, on that building there are some
-glasses etc" and you search for the same area in other images. Basically, you are describing the
-feature. Similar way, computer also should describe the region around the feature so that it can
+We found the features in the images. Once you have found it, you should be able to find the same
+in the other images. How is this done? We take a region around the feature, we explain it in our own
+words, like "upper part is blue sky, lower part is region from a building, on that building there is
+glass etc" and you search for the same area in the other images. Basically, you are describing the
+feature. Similarly, a computer also should describe the region around the feature so that it can
 find it in other images. So called description is called **Feature Description**. Once you have the
-features and its description, you can find same features in all images and align them, stitch them
+features and its description, you can find same features in all images and align them, stitch them together
 or do whatever you want.
 
 So in this module, we are looking to different algorithms in OpenCV to find features, describe them,
diff --git a/doc/py_tutorials/py_feature2d/py_orb/py_orb.markdown b/doc/py_tutorials/py_feature2d/py_orb/py_orb.markdown
index c1917eb..49c558a 100644
--- a/doc/py_tutorials/py_feature2d/py_orb/py_orb.markdown
+++ b/doc/py_tutorials/py_feature2d/py_orb/py_orb.markdown
@@ -79,8 +79,8 @@ kp = orb.detect(img,None)
 kp, des = orb.compute(img, kp)
 
 # draw only keypoints location,not size and orientation
-img2 = cv2.drawKeypoints(img,kp,color=(0,255,0), flags=0)
-plt.imshow(img2),plt.show()
+img2 = cv2.drawKeypoints(img, kp, None, color=(0,255,0), flags=0)
+plt.imshow(img2), plt.show()
 @endcode
 See the result below:
 
diff --git a/doc/py_tutorials/py_feature2d/py_sift_intro/py_sift_intro.markdown b/doc/py_tutorials/py_feature2d/py_sift_intro/py_sift_intro.markdown
index b12505a..2b4b516 100644
--- a/doc/py_tutorials/py_feature2d/py_sift_intro/py_sift_intro.markdown
+++ b/doc/py_tutorials/py_feature2d/py_sift_intro/py_sift_intro.markdown
@@ -104,7 +104,7 @@ greater than 0.8, they are rejected. It eliminaters around 90% of false matches
 
 So this is a summary of SIFT algorithm. For more details and understanding, reading the original
 paper is highly recommended. Remember one thing, this algorithm is patented. So this algorithm is
-included in [the opencv contrib repo](https://github.com/Itseez/opencv_contrib)
+included in [the opencv contrib repo](https://github.com/opencv/opencv_contrib)
 
 SIFT in OpenCV
 --------------
@@ -122,7 +122,7 @@ gray= cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
 sift = cv2.xfeatures2d.SIFT_create()
 kp = sift.detect(gray,None)
 
-img=cv2.drawKeypoints(gray,kp)
+img=cv2.drawKeypoints(gray,kp,img)
 
 cv2.imwrite('sift_keypoints.jpg',img)
 @endcode
@@ -135,7 +135,7 @@ OpenCV also provides **cv2.drawKeyPoints()** function which draws the small circ
 of keypoints. If you pass a flag, **cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS** to it, it will
 draw a circle with size of keypoint and it will even show its orientation. See below example.
 @code{.py}
-img=cv2.drawKeypoints(gray,kp,flags=cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)
+img=cv2.drawKeypoints(gray,kp,img,flags=cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)
 cv2.imwrite('sift_keypoints.jpg',img)
 @endcode
 See the two results below:
diff --git a/doc/py_tutorials/py_gui/py_video_display/py_video_display.markdown b/doc/py_tutorials/py_gui/py_video_display/py_video_display.markdown
index 7b532ac..7275488 100644
--- a/doc/py_tutorials/py_gui/py_video_display/py_video_display.markdown
+++ b/doc/py_tutorials/py_gui/py_video_display/py_video_display.markdown
@@ -51,8 +51,7 @@ Otherwise open it using **cap.open()**.
 
 You can also access some of the features of this video using **cap.get(propId)** method where propId
 is a number from 0 to 18. Each number denotes a property of the video (if it is applicable to that
-video) and full details can be seen here: [Property
-Identifier](http://docs.opencv.org/modules/highgui/doc/reading_and_writing_video.html#videocapture-get).
+video) and full details can be seen here: cv::VideoCapture::get() .
 Some of these values can be modified using **cap.set(propId, value)**. Value is the new value you
 want.
 
diff --git a/doc/py_tutorials/py_imgproc/py_contours/py_contour_features/py_contour_features.markdown b/doc/py_tutorials/py_imgproc/py_contours/py_contour_features/py_contour_features.markdown
index 06ac8e4..237725e 100644
--- a/doc/py_tutorials/py_imgproc/py_contours/py_contour_features/py_contour_features.markdown
+++ b/doc/py_tutorials/py_imgproc/py_contours/py_contour_features/py_contour_features.markdown
@@ -23,7 +23,7 @@ import numpy as np
 
 img = cv2.imread('star.jpg',0)
 ret,thresh = cv2.threshold(img,127,255,0)
-contours,hierarchy = cv2.findContours(thresh, 1, 2)
+im2,contours,hierarchy = cv2.findContours(thresh, 1, 2)
 
 cnt = contours[0]
 M = cv2.moments(cnt)
diff --git a/doc/py_tutorials/py_imgproc/py_contours/py_contours_more_functions/py_contours_more_functions.markdown b/doc/py_tutorials/py_imgproc/py_contours/py_contours_more_functions/py_contours_more_functions.markdown
index 66ab006..2a96cb0 100644
--- a/doc/py_tutorials/py_imgproc/py_contours/py_contours_more_functions/py_contours_more_functions.markdown
+++ b/doc/py_tutorials/py_imgproc/py_contours/py_contours_more_functions/py_contours_more_functions.markdown
@@ -38,8 +38,8 @@ import numpy as np
 
 img = cv2.imread('star.jpg')
 img_gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
-ret, thresh = cv2.threshold(img_gray, 127, 255,0)
-contours,hierarchy = cv2.findContours(thresh,2,1)
+ret,thresh = cv2.threshold(img_gray, 127, 255,0)
+im2,contours,hierarchy = cv2.findContours(thresh,2,1)
 cnt = contours[0]
 
 hull = cv2.convexHull(cnt,returnPoints = False)
@@ -93,9 +93,9 @@ img2 = cv2.imread('star2.jpg',0)
 
 ret, thresh = cv2.threshold(img1, 127, 255,0)
 ret, thresh2 = cv2.threshold(img2, 127, 255,0)
-contours,hierarchy = cv2.findContours(thresh,2,1)
+im2,contours,hierarchy = cv2.findContours(thresh,2,1)
 cnt1 = contours[0]
-contours,hierarchy = cv2.findContours(thresh2,2,1)
+im2,contours,hierarchy = cv2.findContours(thresh2,2,1)
 cnt2 = contours[0]
 
 ret = cv2.matchShapes(cnt1,cnt2,1,0.0)
diff --git a/doc/py_tutorials/py_imgproc/py_filtering/py_filtering.markdown b/doc/py_tutorials/py_imgproc/py_filtering/py_filtering.markdown
index 95bfef2..bc3e87b 100644
--- a/doc/py_tutorials/py_imgproc/py_filtering/py_filtering.markdown
+++ b/doc/py_tutorials/py_imgproc/py_filtering/py_filtering.markdown
@@ -69,7 +69,7 @@ import cv2
 import numpy as np
 from matplotlib import pyplot as plt
 
-img = cv2.imread('opencv_logo.png')
+img = cv2.imread('opencv-logo-white.png')
 
 blur = cv2.blur(img,(5,5))
 
diff --git a/doc/py_tutorials/py_imgproc/py_geometric_transformations/py_geometric_transformations.markdown b/doc/py_tutorials/py_imgproc/py_geometric_transformations/py_geometric_transformations.markdown
index bce3374..a71878f 100644
--- a/doc/py_tutorials/py_imgproc/py_geometric_transformations/py_geometric_transformations.markdown
+++ b/doc/py_tutorials/py_imgproc/py_geometric_transformations/py_geometric_transformations.markdown
@@ -135,7 +135,7 @@ matrix.
 
 See the code below:
 @code{.py}
-img = cv2.imread('sudokusmall.png')
+img = cv2.imread('sudoku.png')
 rows,cols,ch = img.shape
 
 pts1 = np.float32([[56,65],[368,52],[28,387],[389,390]])
diff --git a/doc/py_tutorials/py_imgproc/py_grabcut/py_grabcut.markdown b/doc/py_tutorials/py_imgproc/py_grabcut/py_grabcut.markdown
index 98392b3..a44a727 100644
--- a/doc/py_tutorials/py_imgproc/py_grabcut/py_grabcut.markdown
+++ b/doc/py_tutorials/py_imgproc/py_grabcut/py_grabcut.markdown
@@ -17,7 +17,7 @@ graph cuts](http://dl.acm.org/citation.cfm?id=1015720) . An algorithm was needed
 extraction with minimal user interaction, and the result was GrabCut.
 
 How it works from user point of view ? Initially user draws a rectangle around the foreground region
-(foreground region shoule be completely inside the rectangle). Then algorithm segments it
+(foreground region should be completely inside the rectangle). Then algorithm segments it
 iteratively to get the best result. Done. But in some cases, the segmentation won't be fine, like,
 it may have marked some foreground region as background and vice versa. In that case, user need to
 do fine touch-ups. Just give some strokes on the images where some faulty results are there. Strokes
diff --git a/doc/py_tutorials/py_imgproc/py_houghcircles/py_houghcircles.markdown b/doc/py_tutorials/py_imgproc/py_houghcircles/py_houghcircles.markdown
index 159e479..50fc05c 100644
--- a/doc/py_tutorials/py_imgproc/py_houghcircles/py_houghcircles.markdown
+++ b/doc/py_tutorials/py_imgproc/py_houghcircles/py_houghcircles.markdown
@@ -23,7 +23,7 @@ explained in the documentation. So we directly go to the code.
 import cv2
 import numpy as np
 
-img = cv2.imread('opencv_logo.png',0)
+img = cv2.imread('opencv-logo-white.png',0)
 img = cv2.medianBlur(img,5)
 cimg = cv2.cvtColor(img,cv2.COLOR_GRAY2BGR)
 
diff --git a/doc/py_tutorials/py_imgproc/py_houghlines/py_houghlines.markdown b/doc/py_tutorials/py_imgproc/py_houghlines/py_houghlines.markdown
index 881cf2a..5b569ed 100644
--- a/doc/py_tutorials/py_imgproc/py_houghlines/py_houghlines.markdown
+++ b/doc/py_tutorials/py_imgproc/py_houghlines/py_houghlines.markdown
@@ -73,7 +73,7 @@ represents the minimum length of line that should be detected.
 import cv2
 import numpy as np
 
-img = cv2.imread('dave.jpg')
+img = cv2.imread('sudoku.png')
 gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
 edges = cv2.Canny(gray,50,150,apertureSize = 3)
 
@@ -121,7 +121,7 @@ the parameters of lines, and you had to find all the points. Here, everything is
 import cv2
 import numpy as np
 
-img = cv2.imread('dave.jpg')
+img = cv2.imread('sudoku.png')
 gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
 edges = cv2.Canny(gray,50,150,apertureSize = 3)
 lines = cv2.HoughLinesP(edges,1,np.pi/180,100,minLineLength=100,maxLineGap=10)
diff --git a/doc/py_tutorials/py_imgproc/py_thresholding/py_thresholding.markdown b/doc/py_tutorials/py_imgproc/py_thresholding/py_thresholding.markdown
index b9cc029..5fc6240 100644
--- a/doc/py_tutorials/py_imgproc/py_thresholding/py_thresholding.markdown
+++ b/doc/py_tutorials/py_imgproc/py_thresholding/py_thresholding.markdown
@@ -87,7 +87,7 @@ import cv2
 import numpy as np
 from matplotlib import pyplot as plt
 
-img = cv2.imread('dave.jpg',0)
+img = cv2.imread('sudoku.png',0)
 img = cv2.medianBlur(img,5)
 
 ret,th1 = cv2.threshold(img,127,255,cv2.THRESH_BINARY)
diff --git a/doc/py_tutorials/py_ml/py_knn/py_knn_opencv/py_knn_opencv.markdown b/doc/py_tutorials/py_ml/py_knn/py_knn_opencv/py_knn_opencv.markdown
index 195afdf..c58658d 100644
--- a/doc/py_tutorials/py_ml/py_knn/py_knn_opencv/py_knn_opencv.markdown
+++ b/doc/py_tutorials/py_ml/py_knn/py_knn_opencv/py_knn_opencv.markdown
@@ -42,9 +42,9 @@ train_labels = np.repeat(k,250)[:,np.newaxis]
 test_labels = train_labels.copy()
 
 # Initiate kNN, train the data, then test it with test data for k=1
-knn = cv2.KNearest()
-knn.train(train,train_labels)
-ret,result,neighbours,dist = knn.find_nearest(test,k=5)
+knn = cv2.ml.KNearest_create()
+knn.train(train, cv2.ml.ROW_SAMPLE, train_labels)
+ret,result,neighbours,dist = knn.findNearest(test,k=5)
 
 # Now we check the accuracy of classification
 # For that, compare the result with test_labels and check which are wrong
@@ -103,9 +103,9 @@ responses, trainData = np.hsplit(train,[1])
 labels, testData = np.hsplit(test,[1])
 
 # Initiate the kNN, classify, measure accuracy.
-knn = cv2.KNearest()
-knn.train(trainData, responses)
-ret, result, neighbours, dist = knn.find_nearest(testData, k=5)
+knn = cv2.ml.KNearest_create()
+knn.train(trainData, cv2.ml.ROW_SAMPLE, responses)
+ret, result, neighbours, dist = knn.findNearest(testData, k=5)
 
 correct = np.count_nonzero(result == labels)
 accuracy = correct*100.0/10000
diff --git a/doc/py_tutorials/py_ml/py_knn/py_knn_understanding/py_knn_understanding.markdown b/doc/py_tutorials/py_ml/py_knn/py_knn_understanding/py_knn_understanding.markdown
index 3d7be5a..5eae4b2 100644
--- a/doc/py_tutorials/py_ml/py_knn/py_knn_understanding/py_knn_understanding.markdown
+++ b/doc/py_tutorials/py_ml/py_knn/py_knn_understanding/py_knn_understanding.markdown
@@ -114,9 +114,9 @@ So let's see how it works. New comer is marked in green color.
 newcomer = np.random.randint(0,100,(1,2)).astype(np.float32)
 plt.scatter(newcomer[:,0],newcomer[:,1],80,'g','o')
 
-knn = cv2.KNearest()
-knn.train(trainData,responses)
-ret, results, neighbours ,dist = knn.find_nearest(newcomer, 3)
+knn = cv2.ml.KNearest_create()
+knn.train(trainData, cv2.ml.ROW_SAMPLE, responses)
+ret, results, neighbours ,dist = knn.findNearest(newcomer, 3)
 
 print "result: ", results,"\n"
 print "neighbours: ", neighbours,"\n"
@@ -140,7 +140,7 @@ obtained as arrays.
 @code{.py}
 # 10 new comers
 newcomers = np.random.randint(0,100,(10,2)).astype(np.float32)
-ret, results,neighbours,dist = knn.find_nearest(newcomer, 3)
+ret, results,neighbours,dist = knn.findNearest(newcomer, 3)
 # The results also will contain 10 labels.
 @endcode
 Additional Resources
diff --git a/doc/py_tutorials/py_ml/py_svm/py_svm_opencv/py_svm_opencv.markdown b/doc/py_tutorials/py_ml/py_svm/py_svm_opencv/py_svm_opencv.markdown
index ffd38f8..b9ee47d 100644
--- a/doc/py_tutorials/py_ml/py_svm/py_svm_opencv/py_svm_opencv.markdown
+++ b/doc/py_tutorials/py_ml/py_svm/py_svm_opencv/py_svm_opencv.markdown
@@ -64,9 +64,6 @@ import numpy as np
 SZ=20
 bin_n = 16 # Number of bins
 
-svm_params = dict( kernel_type = cv2.SVM_LINEAR,
-                    svm_type = cv2.SVM_C_SVC,
-                    C=2.67, gamma=5.383 )
 
 affine_flags = cv2.WARP_INVERSE_MAP|cv2.INTER_LINEAR
 
@@ -105,8 +102,13 @@ hogdata = [map(hog,row) for row in deskewed]
 trainData = np.float32(hogdata).reshape(-1,64)
 responses = np.float32(np.repeat(np.arange(10),250)[:,np.newaxis])
 
-svm = cv2.SVM()
-svm.train(trainData,responses, params=svm_params)
+svm = cv2.ml.SVM_create()
+svm.setKernel(cv2.ml.SVM_LINEAR)
+svm.setType(cv2.ml.SVM_C_SVC)
+svm.setC(2.67)
+svm.setGamma(5.383)
+
+svm.train(trainData, cv2.ml.ROW_SAMPLE, responses)
 svm.save('svm_data.dat')
 
 ######     Now testing      ########################
@@ -114,7 +116,7 @@ svm.save('svm_data.dat')
 deskewed = [map(deskew,row) for row in test_cells]
 hogdata = [map(hog,row) for row in deskewed]
 testData = np.float32(hogdata).reshape(-1,bin_n*4)
-result = svm.predict_all(testData)
+result = svm.predict(testData)
 
 #######   Check Accuracy   ########################
 mask = result==responses
diff --git a/doc/py_tutorials/py_setup/py_intro/py_intro.markdown b/doc/py_tutorials/py_setup/py_intro/py_intro.markdown
index 007a71c..c8041bb 100644
--- a/doc/py_tutorials/py_setup/py_intro/py_intro.markdown
+++ b/doc/py_tutorials/py_setup/py_intro/py_intro.markdown
@@ -58,7 +58,7 @@ OpenCV Needs You !!!
 Since OpenCV is an open source initiative, all are welcome to make contributions to the library,
 documentation, and tutorials. If you find any mistake in this tutorial (from a small spelling
 mistake to an egregious error in code or concept), feel free to correct it by cloning OpenCV in
-[GitHub](https://github.com/Itseez/opencv) and submitting a pull request. OpenCV developers will
+[GitHub](https://github.com/opencv/opencv) and submitting a pull request. OpenCV developers will
 check your pull request, give you important feedback and (once it passes the approval of the
 reviewer) it will be merged into OpenCV. You will then become an open source contributor :-)
 
diff --git a/doc/py_tutorials/py_setup/py_setup_in_fedora/py_setup_in_fedora.markdown b/doc/py_tutorials/py_setup/py_setup_in_fedora/py_setup_in_fedora.markdown
index b8f57e7..da65dd4 100644
--- a/doc/py_tutorials/py_setup/py_setup_in_fedora/py_setup_in_fedora.markdown
+++ b/doc/py_tutorials/py_setup/py_setup_in_fedora/py_setup_in_fedora.markdown
@@ -119,7 +119,7 @@ Or you can download latest source from OpenCV's github repo. (If you want to con
 choose this. It always keeps your OpenCV up-to-date). For that, you need to install **Git** first.
 @code{.sh}
 yum install git
-git clone https://github.com/Itseez/opencv.git
+git clone https://github.com/opencv/opencv.git
 @endcode
 It will create a folder OpenCV in home directory (or the directory you specify). The cloning may
 take some time depending upon your internet connection.
diff --git a/doc/py_tutorials/py_setup/py_setup_in_windows/py_setup_in_windows.markdown b/doc/py_tutorials/py_setup/py_setup_in_windows/py_setup_in_windows.markdown
index 807e546..3ff4e82 100644
--- a/doc/py_tutorials/py_setup/py_setup_in_windows/py_setup_in_windows.markdown
+++ b/doc/py_tutorials/py_setup/py_setup_in_windows/py_setup_in_windows.markdown
@@ -76,7 +76,7 @@ Building OpenCV from source
 
 -#  Download OpenCV source. It can be from
     [Sourceforge](http://sourceforge.net/projects/opencvlibrary/) (for official release version) or
-    from [Github](https://github.com/Itseez/opencv) (for latest source).
+    from [Github](https://github.com/opencv/opencv) (for latest source).
 -#  Extract it to a folder, opencv and create a new folder build in it.
 -#  Open CMake-gui (*Start \> All Programs \> CMake-gui*)
 -#  Fill the fields as follows (see the image below):
diff --git a/doc/tutorials/calib3d/camera_calibration/camera_calibration.markdown b/doc/tutorials/calib3d/camera_calibration/camera_calibration.markdown
index 1a7b906..2c69731 100644
--- a/doc/tutorials/calib3d/camera_calibration/camera_calibration.markdown
+++ b/doc/tutorials/calib3d/camera_calibration/camera_calibration.markdown
@@ -77,13 +77,13 @@ Source code
 
 You may also find the source code in the `samples/cpp/tutorial_code/calib3d/camera_calibration/`
 folder of the OpenCV source library or [download it from here
-](https://github.com/Itseez/opencv/tree/master/samples/cpp/tutorial_code/calib3d/camera_calibration/camera_calibration.cpp). The program has a
+](https://github.com/opencv/opencv/tree/master/samples/cpp/tutorial_code/calib3d/camera_calibration/camera_calibration.cpp). The program has a
 single argument: the name of its configuration file. If none is given then it will try to open the
 one named "default.xml". [Here's a sample configuration file
-](https://github.com/Itseez/opencv/tree/master/samples/cpp/tutorial_code/calib3d/camera_calibration/in_VID5.xml) in XML format. In the
+](https://github.com/opencv/opencv/tree/master/samples/cpp/tutorial_code/calib3d/camera_calibration/in_VID5.xml) in XML format. In the
 configuration file you may choose to use camera as an input, a video file or an image list. If you
 opt for the last one, you will need to create a configuration file where you enumerate the images to
-use. Here's [an example of this ](https://github.com/Itseez/opencv/tree/master/samples/cpp/tutorial_code/calib3d/camera_calibration/VID5.xml).
+use. Here's [an example of this ](https://github.com/opencv/opencv/tree/master/samples/cpp/tutorial_code/calib3d/camera_calibration/VID5.xml).
 The important part to remember is that the images need to be specified using the absolute path or
 the relative one from your application's working directory. You may find all this in the samples
 directory mentioned above.
diff --git a/doc/tutorials/calib3d/interactive_calibration/images/charuco_board.png b/doc/tutorials/calib3d/interactive_calibration/images/charuco_board.png
new file mode 100644
index 0000000..947a94c
Binary files /dev/null and b/doc/tutorials/calib3d/interactive_calibration/images/charuco_board.png differ
diff --git a/doc/tutorials/calib3d/interactive_calibration/images/dualCircles.jpg b/doc/tutorials/calib3d/interactive_calibration/images/dualCircles.jpg
new file mode 100644
index 0000000..7a28bde
Binary files /dev/null and b/doc/tutorials/calib3d/interactive_calibration/images/dualCircles.jpg differ
diff --git a/doc/tutorials/calib3d/interactive_calibration/images/screen_charuco.jpg b/doc/tutorials/calib3d/interactive_calibration/images/screen_charuco.jpg
new file mode 100644
index 0000000..eb6503c
Binary files /dev/null and b/doc/tutorials/calib3d/interactive_calibration/images/screen_charuco.jpg differ
diff --git a/doc/tutorials/calib3d/interactive_calibration/images/screen_finish.jpg b/doc/tutorials/calib3d/interactive_calibration/images/screen_finish.jpg
new file mode 100644
index 0000000..ac2f284
Binary files /dev/null and b/doc/tutorials/calib3d/interactive_calibration/images/screen_finish.jpg differ
diff --git a/doc/tutorials/calib3d/interactive_calibration/interactive_calibration.markdown b/doc/tutorials/calib3d/interactive_calibration/interactive_calibration.markdown
new file mode 100644
index 0000000..0c4d67e
--- /dev/null
+++ b/doc/tutorials/calib3d/interactive_calibration/interactive_calibration.markdown
@@ -0,0 +1,198 @@
+Interactive camera calibration application {#tutorial_interactive_calibration}
+==============================
+
+According to classical calibration technique user must collect all data first and when run @ref cv::calibrateCamera function
+to obtain camera parameters. If average re-projection error is huge or if estimated parameters seems to be wrong, process of
+selection or collecting data and starting of @ref cv::calibrateCamera repeats.
+
+Interactive calibration process assumes that after each new data portion user can see results and errors estimation, also
+he can delete last data portion and finally, when dataset for calibration is big enough starts process of auto data selection.
+
+Main application features
+------
+
+The sample application will:
+
+-   Determine the distortion matrix and confidence interval for each element
+-   Determine the camera matrix and confidence interval for each element
+-   Take input from camera or video file
+-   Read configuration from XML file
+-   Save the results into XML file
+-   Calculate re-projection error
+-   Reject patterns views on sharp angles to prevent appear of ill-conditioned jacobian blocks
+-   Auto switch calibration flags (fix aspect ratio and elements of distortion matrix if needed)
+-   Auto detect when calibration is done by using several criteria
+-   Auto capture of static patterns (user doesn't need press any keys to capture frame, just don't move pattern for a second)
+
+Supported patterns:
+
+-   Black-white chessboard
+-   Asymmetrical circle pattern
+-   Dual asymmetrical circle pattern
+-   chAruco (chessboard with Aruco markers)
+
+Description of parameters
+------
+
+Application has two groups of parameters: primary (passed through command line) and advances (passed through XML file).
+
+### Primary parameters:
+
+All of this parameters are passed to application through a command line.
+
+-[parameter]=[default value]: description
+
+-  -v=[filename]: get video from filename, default input -- camera with id=0
+-  -ci=[0]: get video from camera with specified id
+-  -flip=[false]: vertical flip of input frames
+-  -t=[circles]: pattern for calibration (circles, chessboard, dualCircles, chAruco)
+-  -sz=[16.3]: distance between two nearest centers of circles or squares on calibration board
+-  -dst=[295] distance between white and black parts of daulCircles pattern
+-  -w=[width]: width of pattern (in corners or circles)
+-  -h=[height]: height of pattern (in corners or circles)
+-  -of=[camParams.xml]: output file name
+-  -ft=[true]: auto tuning of calibration flags
+-  -vis=[grid]: captured boards visualization (grid, window)
+-  -d=[0.8]: delay between captures in seconds
+-  -pf=[defaultConfig.xml]: advanced application parameters file
+
+### Advanced parameters:
+
+By default values of advanced parameters are stored in defaultConfig.xml
+
+ at code{.xml}
+<?xml version="1.0"?>
+<opencv_storage>
+<charuco_dict>0</charuco_dict>
+<charuco_square_lenght>200</charuco_square_lenght>
+<charuco_marker_size>100</charuco_marker_size>
+<calibration_step>1</calibration_step>
+<max_frames_num>30</max_frames_num>
+<min_frames_num>10</min_frames_num>
+<solver_eps>1e-7</solver_eps>
+<solver_max_iters>30</solver_max_iters>
+<fast_solver>0</fast_solver>
+<frame_filter_conv_param>0.1</frame_filter_conv_param>
+<camera_resolution>1280 720</camera_resolution>
+</opencv_storage>
+ at endcode
+
+-  *charuco_dict*: name of special dictionary, which has been used for generation of chAruco pattern
+-  *charuco_square_lenght*: size of square on chAruco board (in pixels)
+-  *charuco_marker_size*: size of Aruco markers on chAruco board (in pixels)
+-  *calibration_step*: interval in frames between launches of @ref cv::calibrateCamera
+-  *max_frames_num*: if number of frames for calibration is greater then this value frames filter starts working.
+After filtration size of calibration dataset is equals to *max_frames_num*
+-  *min_frames_num*: if number of frames is greater then this value turns on auto flags tuning, undistorted view and quality evaluation
+-  *solver_eps*: precision of Levenberg-Marquardt solver in @ref cv::calibrateCamera
+-  *solver_max_iters*: iterations limit of solver
+-  *fast_solver*: if this value is nonzero and Lapack is found QR decomposition is used instead of SVD in solver.
+QR faster than SVD, but potentially less precise
+-  *frame_filter_conv_param*: parameter which used in linear convolution of bicriterial frames filter
+-  *camera_resolution*: resolution of camera which is used for calibration
+
+**Note:** *charuco_dict*, *charuco_square_lenght* and *charuco_marker_size* are used for chAruco pattern generation
+(see Aruco module description for details: [Aruco tutorials](https://github.com/opencv/opencv_contrib/tree/master/modules/aruco/tutorials))
+
+Default chAruco pattern:
+
+![](images/charuco_board.png)
+
+Dual circles pattern
+------
+
+To make this pattern you need standard OpenCV circles pattern and binary inverted one.
+Place two patterns on one plane in order when all horizontal lines of circles in one pattern are
+ continuations of similar lines in another.
+Measure distance between patterns as shown at picture below pass it as **dst** command line parameter. Also measure distance between centers of nearest circles and pass
+this value as **sz** command line parameter.
+
+![](images/dualCircles.jpg)
+
+This pattern is very sensitive to quality of production and measurements.
+
+
+Data filtration
+------
+When size of calibration dataset is greater then *max_frames_num* starts working
+data filter. It tries to remove "bad" frames from dataset. Filter removes the frame
+ on which \f$loss\_function\f$ takes maximum.
+
+\f[loss\_function(i)=\alpha RMS(i)+(1-\alpha)reducedGridQuality(i)\f]
+
+**RMS** is an average re-projection error calculated for frame *i*, **reducedGridQuality**
+ is scene coverage quality evaluation without frame *i*. \f$\alpha\f$ is equals to
+ **frame_filter_conv_param**.
+
+
+Calibration process
+------
+
+To start calibration just run application. Place pattern ahead the camera and fixate pattern in some pose.
+After that wait for capturing (will be shown message like "Frame #i captured").
+Current focal distance and re-projection error will be shown at the main screen. Move pattern to the next position  and repeat procedure. Try to cover image plane
+uniformly and don't show pattern on sharp angles to the image plane.
+
+![](images/screen_charuco.jpg)
+
+If calibration seems to be successful (confidence intervals and average re-projection
+ error are small, frame coverage quality and number of pattern views are big enough)
+  application will show a message like on screen below.
+
+
+![](images/screen_finish.jpg)
+
+Hot keys:
+
+- Esc -- exit application
+- s -- save current data to XML file
+- r -- delete last frame
+- d -- delete all frames
+- u -- enable/disable applying of undistortion
+- v -- switch visualization mode
+
+Results
+------
+
+As result you will get camera parameters and confidence intervals for them.
+
+Example of output XML file:
+
+ at code{.xml}
+<?xml version="1.0"?>
+<opencv_storage>
+<calibrationDate>"Thu 07 Apr 2016 04:23:03 PM MSK"</calibrationDate>
+<framesCount>21</framesCount>
+<cameraResolution>
+  1280 720</cameraResolution>
+<cameraMatrix type_id="opencv-matrix">
+  <rows>3</rows>
+  <cols>3</cols>
+  <dt>d</dt>
+  <data>
+    1.2519588293098975e+03 0. 6.6684948780852471e+02 0.
+    1.2519588293098975e+03 3.6298123112613683e+02 0. 0. 1.</data></cameraMatrix>
+<cameraMatrix_std_dev type_id="opencv-matrix">
+  <rows>4</rows>
+  <cols>1</cols>
+  <dt>d</dt>
+  <data>
+    0. 1.2887048808572649e+01 2.8536856683866230e+00
+    2.8341737483430314e+00</data></cameraMatrix_std_dev>
+<dist_coeffs type_id="opencv-matrix">
+  <rows>1</rows>
+  <cols>5</cols>
+  <dt>d</dt>
+  <data>
+    1.3569117181595716e-01 -8.2513063822554633e-01 0. 0.
+    1.6412101575010554e+00</data></dist_coeffs>
+<dist_coeffs_std_dev type_id="opencv-matrix">
+  <rows>5</rows>
+  <cols>1</cols>
+  <dt>d</dt>
+  <data>
+    1.5570675523402111e-02 8.7229075437543435e-02 0. 0.
+    1.8382427901856876e-01</data></dist_coeffs_std_dev>
+<avg_reprojection_error>4.2691743074130178e-01</avg_reprojection_error>
+</opencv_storage>
+ at endcode
diff --git a/doc/tutorials/calib3d/table_of_content_calib3d.markdown b/doc/tutorials/calib3d/table_of_content_calib3d.markdown
index adbda4b..50e9d12 100644
--- a/doc/tutorials/calib3d/table_of_content_calib3d.markdown
+++ b/doc/tutorials/calib3d/table_of_content_calib3d.markdown
@@ -30,3 +30,14 @@ how to find out from the 2D images information about the 3D world.
 
     Real time pose estimation of a textured object using ORB features, FlannBased matcher, PnP
     approach plus Ransac and Linear Kalman Filter to reject possible bad poses.
+
+-   @subpage tutorial_interactive_calibration
+
+    *Compatibility:* \> OpenCV 3.1
+
+    *Author:* Vladislav Sovrasov
+
+    Camera calibration by using either the chessboard, chAruco, asymmetrical circle or dual asymmetrical circle
+    pattern. Calibration process is continious, so you can see results after each new pattern shot.
+    As an output you get average reprojection error, intrinsic camera parameters, distortion coefficients and
+     confidence intervals for all of evaluated variables.
diff --git a/doc/tutorials/core/adding_images/adding_images.markdown b/doc/tutorials/core/adding_images/adding_images.markdown
index 1565e7e..012a248 100644
--- a/doc/tutorials/core/adding_images/adding_images.markdown
+++ b/doc/tutorials/core/adding_images/adding_images.markdown
@@ -25,51 +25,13 @@ By varying \f$\alpha\f$ from \f$0 \rightarrow 1\f$ this operator can be used to
 *cross-dissolve* between two images or videos, as seen in slide shows and film productions (cool,
 eh?)
 
-Code
-----
-
-As usual, after the not-so-lengthy explanation, let's go to the code:
- at code{.cpp}
-#include <opencv2/opencv.hpp>
-#include <iostream>
-
-using namespace cv;
-
-int main( int argc, char** argv )
-{
- double alpha = 0.5; double beta; double input;
-
- Mat src1, src2, dst;
-
- /// Ask the user enter alpha
- std::cout<<" Simple Linear Blender "<<std::endl;
- std::cout<<"-----------------------"<<std::endl;
- std::cout<<"* Enter alpha [0-1]: ";
- std::cin>>input;
-
- /// We use the alpha provided by the user if it is between 0 and 1
- if( input >= 0.0 && input <= 1.0 )
-   { alpha = input; }
-
- /// Read image ( same size, same type )
- src1 = imread("../../images/LinuxLogo.jpg");
- src2 = imread("../../images/WindowsLogo.jpg");
-
- if( !src1.data ) { printf("Error loading src1 \n"); return -1; }
- if( !src2.data ) { printf("Error loading src2 \n"); return -1; }
-
- /// Create Windows
- namedWindow("Linear Blend", 1);
-
- beta = ( 1.0 - alpha );
- addWeighted( src1, alpha, src2, beta, 0.0, dst);
+Source Code
+-----------
 
- imshow( "Linear Blend", dst );
+Download the source code from
+[here](https://github.com/opencv/opencv/tree/master/samples/cpp/tutorial_code/core/AddingImages/AddingImages.cpp).
+ at include cpp/tutorial_code/core/AddingImages/AddingImages.cpp
 
- waitKey(0);
- return 0;
-}
- at endcode
 Explanation
 -----------
 
@@ -78,25 +40,21 @@ Explanation
     \f[g(x) = (1 - \alpha)f_{0}(x) + \alpha f_{1}(x)\f]
 
     We need two source images (\f$f_{0}(x)\f$ and \f$f_{1}(x)\f$). So, we load them in the usual way:
-    @code{.cpp}
-    src1 = imread("../../images/LinuxLogo.jpg");
-    src2 = imread("../../images/WindowsLogo.jpg");
-    @endcode
+    @snippet cpp/tutorial_code/core/AddingImages/AddingImages.cpp load
+
     **warning**
 
     Since we are *adding* *src1* and *src2*, they both have to be of the same size (width and
     height) and type.
 
--#  Now we need to generate the `g(x)` image. For this, the function add_weighted:addWeighted  comes quite handy:
-    @code{.cpp}
-    beta = ( 1.0 - alpha );
-    addWeighted( src1, alpha, src2, beta, 0.0, dst);
-    @endcode
+-#  Now we need to generate the `g(x)` image. For this, the function @ref cv::addWeighted comes quite handy:
+    @snippet cpp/tutorial_code/core/AddingImages/AddingImages.cpp blend_images
     since @ref cv::addWeighted  produces:
     \f[dst = \alpha \cdot src1 + \beta \cdot src2 + \gamma\f]
     In this case, `gamma` is the argument \f$0.0\f$ in the code above.
 
 -#  Create windows, show the images and wait for the user to end the program.
+    @snippet cpp/tutorial_code/core/AddingImages/AddingImages.cpp display
 
 Result
 ------
diff --git a/doc/tutorials/core/basic_geometric_drawing/basic_geometric_drawing.markdown b/doc/tutorials/core/basic_geometric_drawing/basic_geometric_drawing.markdown
index 61134bd..c27e329 100644
--- a/doc/tutorials/core/basic_geometric_drawing/basic_geometric_drawing.markdown
+++ b/doc/tutorials/core/basic_geometric_drawing/basic_geometric_drawing.markdown
@@ -47,70 +47,27 @@ Code
 ----
 
 -   This code is in your OpenCV sample folder. Otherwise you can grab it from
-    [here](https://github.com/Itseez/opencv/tree/master/samples/cpp/tutorial_code/core/Matrix/Drawing_1.cpp)
+    [here](https://github.com/opencv/opencv/tree/master/samples/cpp/tutorial_code/core/Matrix/Drawing_1.cpp)
+    @include samples/cpp/tutorial_code/core/Matrix/Drawing_1.cpp
 
 Explanation
 -----------
 
--#  Since we plan to draw two examples (an atom and a rook), we have to create 02 images and two
+-#  Since we plan to draw two examples (an atom and a rook), we have to create two images and two
     windows to display them.
-    @code{.cpp}
-    /// Windows names
-    char atom_window[] = "Drawing 1: Atom";
-    char rook_window[] = "Drawing 2: Rook";
+    @snippet cpp/tutorial_code/core/Matrix/Drawing_1.cpp create_images
 
-    /// Create black empty images
-    Mat atom_image = Mat::zeros( w, w, CV_8UC3 );
-    Mat rook_image = Mat::zeros( w, w, CV_8UC3 );
-    @endcode
 -#  We created functions to draw different geometric shapes. For instance, to draw the atom we used
     *MyEllipse* and *MyFilledCircle*:
-    @code{.cpp}
-    /// 1. Draw a simple atom:
-
-    /// 1.a. Creating ellipses
-    MyEllipse( atom_image, 90 );
-    MyEllipse( atom_image, 0 );
-    MyEllipse( atom_image, 45 );
-    MyEllipse( atom_image, -45 );
+    @snippet cpp/tutorial_code/core/Matrix/Drawing_1.cpp draw_atom
 
-    /// 1.b. Creating circles
-    MyFilledCircle( atom_image, Point( w/2.0, w/2.0) );
-    @endcode
 -#  And to draw the rook we employed *MyLine*, *rectangle* and a *MyPolygon*:
-    @code{.cpp}
-    /// 2. Draw a rook
-
-    /// 2.a. Create a convex polygon
-    MyPolygon( rook_image );
-
-    /// 2.b. Creating rectangles
-    rectangle( rook_image,
-           Point( 0, 7*w/8.0 ),
-           Point( w, w),
-           Scalar( 0, 255, 255 ),
-           -1,
-           8 );
-
-    /// 2.c. Create a few lines
-    MyLine( rook_image, Point( 0, 15*w/16 ), Point( w, 15*w/16 ) );
-    MyLine( rook_image, Point( w/4, 7*w/8 ), Point( w/4, w ) );
-    MyLine( rook_image, Point( w/2, 7*w/8 ), Point( w/2, w ) );
-    MyLine( rook_image, Point( 3*w/4, 7*w/8 ), Point( 3*w/4, w ) );
-    @endcode
+    @snippet cpp/tutorial_code/core/Matrix/Drawing_1.cpp draw_rook
+
 -#  Let's check what is inside each of these functions:
     -   *MyLine*
-        @code{.cpp}
-        void MyLine( Mat img, Point start, Point end )
-        {
-            int thickness = 2;
-            int lineType = 8;
-            line( img, start, end,
-                  Scalar( 0, 0, 0 ),
-                  thickness,
-                  lineType );
-        }
-        @endcode
+        @snippet cpp/tutorial_code/core/Matrix/Drawing_1.cpp myline
+
         As we can see, *MyLine* just call the function @ref cv::line , which does the following:
 
         -   Draw a line from Point **start** to Point **end**
@@ -120,95 +77,31 @@ Explanation
         -   The line thickness is set to **thickness** (in this case 2)
         -   The line is a 8-connected one (**lineType** = 8)
     -   *MyEllipse*
-        @code{.cpp}
-        void MyEllipse( Mat img, double angle )
-        {
-            int thickness = 2;
-            int lineType = 8;
-
-            ellipse( img,
-               Point( w/2.0, w/2.0 ),
-               Size( w/4.0, w/16.0 ),
-               angle,
-               0,
-               360,
-               Scalar( 255, 0, 0 ),
-               thickness,
-               lineType );
-        }
-        @endcode
+        @snippet cpp/tutorial_code/core/Matrix/Drawing_1.cpp myellipse
+
         From the code above, we can observe that the function @ref cv::ellipse draws an ellipse such
         that:
 
         -   The ellipse is displayed in the image **img**
-        -   The ellipse center is located in the point **(w/2.0, w/2.0)** and is enclosed in a box
-            of size **(w/4.0, w/16.0)**
+        -   The ellipse center is located in the point **(w/2, w/2)** and is enclosed in a box
+            of size **(w/4, w/16)**
         -   The ellipse is rotated **angle** degrees
         -   The ellipse extends an arc between **0** and **360** degrees
-        -   The color of the figure will be **Scalar( 255, 0, 0)** which means blue in RGB value.
+        -   The color of the figure will be **Scalar( 255, 0, 0)** which means blue in BGR value.
         -   The ellipse's **thickness** is 2.
     -   *MyFilledCircle*
-        @code{.cpp}
-        void MyFilledCircle( Mat img, Point center )
-        {
-            int thickness = -1;
-            int lineType = 8;
-
-            circle( img,
-                center,
-                w/32.0,
-                Scalar( 0, 0, 255 ),
-                thickness,
-                lineType );
-        }
-        @endcode
+        @snippet cpp/tutorial_code/core/Matrix/Drawing_1.cpp myfilledcircle
+
         Similar to the ellipse function, we can observe that *circle* receives as arguments:
 
         -   The image where the circle will be displayed (**img**)
         -   The center of the circle denoted as the Point **center**
-        -   The radius of the circle: **w/32.0**
+        -   The radius of the circle: **w/32**
         -   The color of the circle: **Scalar(0, 0, 255)** which means *Red* in BGR
         -   Since **thickness** = -1, the circle will be drawn filled.
     -   *MyPolygon*
-        @code{.cpp}
-        void MyPolygon( Mat img )
-        {
-            int lineType = 8;
-
-            /* Create some points */
-            Point rook_points[1][20];
-            rook_points[0][0] = Point( w/4.0, 7*w/8.0 );
-            rook_points[0][1] = Point( 3*w/4.0, 7*w/8.0 );
-            rook_points[0][2] = Point( 3*w/4.0, 13*w/16.0 );
-            rook_points[0][3] = Point( 11*w/16.0, 13*w/16.0 );
-            rook_points[0][4] = Point( 19*w/32.0, 3*w/8.0 );
-            rook_points[0][5] = Point( 3*w/4.0, 3*w/8.0 );
-            rook_points[0][6] = Point( 3*w/4.0, w/8.0 );
-            rook_points[0][7] = Point( 26*w/40.0, w/8.0 );
-            rook_points[0][8] = Point( 26*w/40.0, w/4.0 );
-            rook_points[0][9] = Point( 22*w/40.0, w/4.0 );
-            rook_points[0][10] = Point( 22*w/40.0, w/8.0 );
-            rook_points[0][11] = Point( 18*w/40.0, w/8.0 );
-            rook_points[0][12] = Point( 18*w/40.0, w/4.0 );
-            rook_points[0][13] = Point( 14*w/40.0, w/4.0 );
-            rook_points[0][14] = Point( 14*w/40.0, w/8.0 );
-            rook_points[0][15] = Point( w/4.0, w/8.0 );
-            rook_points[0][16] = Point( w/4.0, 3*w/8.0 );
-            rook_points[0][17] = Point( 13*w/32.0, 3*w/8.0 );
-            rook_points[0][18] = Point( 5*w/16.0, 13*w/16.0 );
-            rook_points[0][19] = Point( w/4.0, 13*w/16.0) ;
-
-            const Point* ppt[1] = { rook_points[0] };
-            int npt[] = { 20 };
-
-            fillPoly( img,
-                      ppt,
-                      npt,
-                          1,
-                      Scalar( 255, 255, 255 ),
-                      lineType );
-        }
-        @endcode
+        @snippet cpp/tutorial_code/core/Matrix/Drawing_1.cpp mypolygon
+
         To draw a filled polygon we use the function @ref cv::fillPoly . We note that:
 
         -   The polygon will be drawn on **img**
@@ -218,22 +111,17 @@ Explanation
         -   The color of the polygon is defined by **Scalar( 255, 255, 255)**, which is the BGR
             value for *white*
     -   *rectangle*
-        @code{.cpp}
-        rectangle( rook_image,
-                   Point( 0, 7*w/8.0 ),
-                   Point( w, w),
-                   Scalar( 0, 255, 255 ),
-                   -1, 8 );
-        @endcode
+        @snippet cpp/tutorial_code/core/Matrix/Drawing_1.cpp rectangle
+
         Finally we have the @ref cv::rectangle function (we did not create a special function for
         this guy). We note that:
 
         -   The rectangle will be drawn on **rook_image**
-        -   Two opposite vertices of the rectangle are defined by *\* Point( 0, 7*w/8.0 )*\*
+        -   Two opposite vertices of the rectangle are defined by *\* Point( 0, 7*w/8 )*\*
             andPoint( w, w)*\*
         -   The color of the rectangle is given by **Scalar(0, 255, 255)** which is the BGR value
             for *yellow*
-        -   Since the thickness value is given by **-1**, the rectangle will be filled.
+        -   Since the thickness value is given by **FILLED (-1)**, the rectangle will be filled.
 
 Result
 ------
diff --git a/doc/tutorials/core/discrete_fourier_transform/discrete_fourier_transform.markdown b/doc/tutorials/core/discrete_fourier_transform/discrete_fourier_transform.markdown
index 1e2d520..22bbc87 100644
--- a/doc/tutorials/core/discrete_fourier_transform/discrete_fourier_transform.markdown
+++ b/doc/tutorials/core/discrete_fourier_transform/discrete_fourier_transform.markdown
@@ -15,7 +15,7 @@ Source code
 -----------
 
 You can [download this from here
-](https://github.com/Itseez/opencv/tree/master/samples/cpp/tutorial_code/core/discrete_fourier_transform/discrete_fourier_transform.cpp) or
+](https://github.com/opencv/opencv/tree/master/samples/cpp/tutorial_code/core/discrete_fourier_transform/discrete_fourier_transform.cpp) or
 find it in the
 `samples/cpp/tutorial_code/core/discrete_fourier_transform/discrete_fourier_transform.cpp` of the
 OpenCV source code library.
@@ -140,7 +140,7 @@ An application idea would be to determine the geometrical orientation present in
 example, let us find out if a text is horizontal or not? Looking at some text you'll notice that the
 text lines sort of form also horizontal lines and the letters form sort of vertical lines. These two
 main components of a text snippet may be also seen in case of the Fourier transform. Let us use
-[this horizontal ](https://github.com/Itseez/opencv/tree/master/samples/data/imageTextN.png) and [this rotated](https://github.com/Itseez/opencv/tree/master/samples/data/imageTextR.png)
+[this horizontal ](https://github.com/opencv/opencv/tree/master/samples/data/imageTextN.png) and [this rotated](https://github.com/opencv/opencv/tree/master/samples/data/imageTextR.png)
 image about a text.
 
 In case of the horizontal text:
diff --git a/doc/tutorials/core/file_input_output_with_xml_yml/file_input_output_with_xml_yml.markdown b/doc/tutorials/core/file_input_output_with_xml_yml/file_input_output_with_xml_yml.markdown
index 7576e57..1052133 100644
--- a/doc/tutorials/core/file_input_output_with_xml_yml/file_input_output_with_xml_yml.markdown
+++ b/doc/tutorials/core/file_input_output_with_xml_yml/file_input_output_with_xml_yml.markdown
@@ -16,7 +16,7 @@ Source code
 -----------
 
 You can [download this from here
-](https://github.com/Itseez/opencv/tree/master/samples/cpp/tutorial_code/core/file_input_output/file_input_output.cpp) or find it in the
+](https://github.com/opencv/opencv/tree/master/samples/cpp/tutorial_code/core/file_input_output/file_input_output.cpp) or find it in the
 `samples/cpp/tutorial_code/core/file_input_output/file_input_output.cpp` of the OpenCV source code
 library.
 
diff --git a/doc/tutorials/core/how_to_scan_images/how_to_scan_images.markdown b/doc/tutorials/core/how_to_scan_images/how_to_scan_images.markdown
index 1121caf..409ebdb 100644
--- a/doc/tutorials/core/how_to_scan_images/how_to_scan_images.markdown
+++ b/doc/tutorials/core/how_to_scan_images/how_to_scan_images.markdown
@@ -51,7 +51,7 @@ three major ways of going through an image pixel by pixel. To make things a litt
 will make the scanning for each image using all of these methods, and print out how long it took.
 
 You can download the full source code [here
-](https://github.com/Itseez/opencv/tree/master/samples/cpp/tutorial_code/core/how_to_scan_images/how_to_scan_images.cpp) or look it up in
+](https://github.com/opencv/opencv/tree/master/samples/cpp/tutorial_code/core/how_to_scan_images/how_to_scan_images.cpp) or look it up in
 the samples directory of OpenCV at the cpp tutorial code for the core section. Its basic usage is:
 @code{.bash}
 how_to_scan_images imageName.jpg intValueToReduce [G]
diff --git a/doc/tutorials/core/how_to_use_ippa_conversion/how_to_use_ippa_conversion.markdown b/doc/tutorials/core/how_to_use_ippa_conversion/how_to_use_ippa_conversion.markdown
index b851bbf..50f3b54 100644
--- a/doc/tutorials/core/how_to_use_ippa_conversion/how_to_use_ippa_conversion.markdown
+++ b/doc/tutorials/core/how_to_use_ippa_conversion/how_to_use_ippa_conversion.markdown
@@ -16,7 +16,7 @@ Code
 
 You may also find the source code in the
 `samples/cpp/tutorial_code/core/ippasync/ippasync_sample.cpp` file of the OpenCV source library or
-download it from [here](https://github.com/Itseez/opencv/tree/master/samples/cpp/tutorial_code/core/ippasync/ippasync_sample.cpp).
+download it from [here](https://github.com/opencv/opencv/tree/master/samples/cpp/tutorial_code/core/ippasync/ippasync_sample.cpp).
 
 @include cpp/tutorial_code/core/ippasync/ippasync_sample.cpp
 
diff --git a/doc/tutorials/core/interoperability_with_OpenCV_1/interoperability_with_OpenCV_1.markdown b/doc/tutorials/core/interoperability_with_OpenCV_1/interoperability_with_OpenCV_1.markdown
index 3837e47..d28786a 100644
--- a/doc/tutorials/core/interoperability_with_OpenCV_1/interoperability_with_OpenCV_1.markdown
+++ b/doc/tutorials/core/interoperability_with_OpenCV_1/interoperability_with_OpenCV_1.markdown
@@ -85,7 +85,7 @@ L = Mat(pI);
 A case study
 ------------
 
-Now that you have the basics done [here's](https://github.com/Itseez/opencv/tree/master/samples/cpp/tutorial_code/core/interoperability_with_OpenCV_1/interoperability_with_OpenCV_1.cpp)
+Now that you have the basics done [here's](https://github.com/opencv/opencv/tree/master/samples/cpp/tutorial_code/core/interoperability_with_OpenCV_1/interoperability_with_OpenCV_1.cpp)
 an example that mixes the usage of the C interface with the C++ one. You will also find it in the
 sample directory of the OpenCV source code library at the
 `samples/cpp/tutorial_code/core/interoperability_with_OpenCV_1/interoperability_with_OpenCV_1.cpp` .
@@ -132,7 +132,7 @@ output:
 
 You may observe a runtime instance of this on the [YouTube
 here](https://www.youtube.com/watch?v=qckm-zvo31w) and you can [download the source code from here
-](https://github.com/Itseez/opencv/tree/master/samples/cpp/tutorial_code/core/interoperability_with_OpenCV_1/interoperability_with_OpenCV_1.cpp)
+](https://github.com/opencv/opencv/tree/master/samples/cpp/tutorial_code/core/interoperability_with_OpenCV_1/interoperability_with_OpenCV_1.cpp)
 or find it in the
 `samples/cpp/tutorial_code/core/interoperability_with_OpenCV_1/interoperability_with_OpenCV_1.cpp`
 of the OpenCV source code library.
diff --git a/doc/tutorials/core/mat-mask-operations/mat_mask_operations.markdown b/doc/tutorials/core/mat-mask-operations/mat_mask_operations.markdown
index 48b7b13..ca95243 100644
--- a/doc/tutorials/core/mat-mask-operations/mat_mask_operations.markdown
+++ b/doc/tutorials/core/mat-mask-operations/mat_mask_operations.markdown
@@ -1,6 +1,9 @@
 Mask operations on matrices {#tutorial_mat_mask_operations}
 ===========================
 
+ at prev_tutorial{tutorial_how_to_scan_images}
+ at next_tutorial{tutorial_mat_operations}
+
 Mask operations on matrices are quite simple. The idea is that we recalculate each pixels value in
 an image according to a mask matrix (also known as kernel). This mask holds values that will adjust
 how much influence neighboring pixels (and the current pixel) have on the new pixel value. From a
@@ -25,123 +28,166 @@ the zero-zero index) on the pixel you want to calculate and sum up the pixel val
 the overlapped matrix values. It's the same thing, however in case of large matrices the latter
 notation is a lot easier to look over.
 
+ at add_toggle_cpp
 Now let us see how we can make this happen by using the basic pixel access method or by using the
 @ref cv::filter2D function.
+ at end_toggle
+
+ at add_toggle_java
+Now let us see how we can make this happen by using the basic pixel access method or by using the
+**Imgproc.filter2D()** function.
+ at end_toggle
+
+ at add_toggle_python
+Now let us see how we can make this happen by using the basic pixel access method or by using the
+**cv2.filter2D()** function.
+ at end_toggle
 
 The Basic Method
 ----------------
 
 Here's a function that will do this:
- at code{.cpp}
-void Sharpen(const Mat& myImage, Mat& Result)
-{
-    CV_Assert(myImage.depth() == CV_8U);  // accept only uchar images
-
-    Result.create(myImage.size(), myImage.type());
-    const int nChannels = myImage.channels();
-
-    for(int j = 1; j < myImage.rows - 1; ++j)
-    {
-        const uchar* previous = myImage.ptr<uchar>(j - 1);
-        const uchar* current  = myImage.ptr<uchar>(j    );
-        const uchar* next     = myImage.ptr<uchar>(j + 1);
-
-        uchar* output = Result.ptr<uchar>(j);
-
-        for(int i = nChannels; i < nChannels * (myImage.cols - 1); ++i)
-        {
-            *output++ = saturate_cast<uchar>(5 * current[i]
-                         -current[i - nChannels] - current[i + nChannels] - previous[i] - next[i]);
-        }
-    }
-
-    Result.row(0).setTo(Scalar(0));
-    Result.row(Result.rows - 1).setTo(Scalar(0));
-    Result.col(0).setTo(Scalar(0));
-    Result.col(Result.cols - 1).setTo(Scalar(0));
-}
- at endcode
+ at add_toggle_cpp
+ at snippet samples/cpp/tutorial_code/core/mat_mask_operations/mat_mask_operations.cpp basic_method
+
 At first we make sure that the input images data is in unsigned char format. For this we use the
 @ref cv::CV_Assert function that throws an error when the expression inside it is false.
- at code{.cpp}
-CV_Assert(myImage.depth() == CV_8U);  // accept only uchar images
+ at snippet samples/cpp/tutorial_code/core/mat_mask_operations/mat_mask_operations.cpp 8_bit
+ at end_toggle
+
+ at add_toggle_java
+ at snippet samples/java/tutorial_code/core/mat_mask_operations/MatMaskOperations.java basic_method
+
+At first we make sure that the input images data in unsigned 8 bit format.
+ at snippet samples/java/tutorial_code/core/mat_mask_operations/MatMaskOperations.java 8_bit
+ at end_toggle
+
+ at add_toggle_python
+ at snippet samples/python/tutorial_code/core/mat_mask_operations/mat_mask_operations.py basic_method
+
+At first we make sure that the input images data in unsigned 8 bit format.
+ at code{.py}
+my_image = cv2.cvtColor(my_image, cv2.CV_8U)
 @endcode
+
+ at end_toggle
+
 We create an output image with the same size and the same type as our input. As you can see in the
 @ref tutorial_how_to_scan_images_storing "storing" section, depending on the number of channels we may have one or more
-subcolumns. We will iterate through them via pointers so the total number of elements depends from
+subcolumns.
+
+ at add_toggle_cpp
+We will iterate through them via pointers so the total number of elements depends on
 this number.
- at code{.cpp}
-Result.create(myImage.size(), myImage.type());
-const int nChannels = myImage.channels();
+ at snippet samples/cpp/tutorial_code/core/mat_mask_operations/mat_mask_operations.cpp create_channels
+ at end_toggle
+
+ at add_toggle_java
+ at snippet samples/java/tutorial_code/core/mat_mask_operations/MatMaskOperations.java create_channels
+ at end_toggle
+
+ at add_toggle_python
+ at code{.py}
+height, width, n_channels = my_image.shape
+result = np.zeros(my_image.shape, my_image.dtype)
 @endcode
+ at end_toggle
+
+ at add_toggle_cpp
 We'll use the plain C [] operator to access pixels. Because we need to access multiple rows at the
 same time we'll acquire the pointers for each of them (a previous, a current and a next line). We
 need another pointer to where we're going to save the calculation. Then simply access the right
 items with the [] operator. For moving the output pointer ahead we simply increase this (with one
 byte) after each operation:
- at code{.cpp}
-for(int j = 1; j < myImage.rows - 1; ++j)
-{
-    const uchar* previous = myImage.ptr<uchar>(j - 1);
-    const uchar* current  = myImage.ptr<uchar>(j    );
-    const uchar* next     = myImage.ptr<uchar>(j + 1);
-
-    uchar* output = Result.ptr<uchar>(j);
-
-    for(int i = nChannels; i < nChannels * (myImage.cols - 1); ++i)
-    {
-        *output++ = saturate_cast<uchar>(5 * current[i]
-                     -current[i - nChannels] - current[i + nChannels] - previous[i] - next[i]);
-    }
-}
- at endcode
+ at snippet samples/cpp/tutorial_code/core/mat_mask_operations/mat_mask_operations.cpp basic_method_loop
+
 On the borders of the image the upper notation results inexistent pixel locations (like minus one -
 minus one). In these points our formula is undefined. A simple solution is to not apply the kernel
 in these points and, for example, set the pixels on the borders to zeros:
- at code{.cpp}
-Result.row(0).setTo(Scalar(0));               // The top row
-Result.row(Result.rows - 1).setTo(Scalar(0)); // The bottom row
-Result.col(0).setTo(Scalar(0));               // The left column
-Result.col(Result.cols - 1).setTo(Scalar(0)); // The right column
- at endcode
+
+ at snippet samples/cpp/tutorial_code/core/mat_mask_operations/mat_mask_operations.cpp borders
+ at end_toggle
+
+ at add_toggle_java
+We need to access multiple rows and columns which can be done by adding or subtracting 1 to the current center (i,j).
+Then we apply the sum and put the new value in the Result matrix.
+ at snippet samples/java/tutorial_code/core/mat_mask_operations/MatMaskOperations.java basic_method_loop
+
+On the borders of the image the upper notation results in inexistent pixel locations (like (-1,-1)).
+In these points our formula is undefined. A simple solution is to not apply the kernel
+in these points and, for example, set the pixels on the borders to zeros:
+
+ at snippet samples/java/tutorial_code/core/mat_mask_operations/MatMaskOperations.java borders
+ at end_toggle
+
+ at add_toggle_python
+We need to access multiple rows and columns which can be done by adding or subtracting 1 to the current center (i,j).
+Then we apply the sum and put the new value in the Result matrix.
+ at snippet samples/python/tutorial_code/core/mat_mask_operations/mat_mask_operations.py basic_method_loop
+ at end_toggle
 
 The filter2D function
 ---------------------
 
 Applying such filters are so common in image processing that in OpenCV there exist a function that
 will take care of applying the mask (also called a kernel in some places). For this you first need
-to define a *Mat* object that holds the mask:
- at code{.cpp}
-Mat kern = (Mat_<char>(3,3) <<  0, -1,  0,
-                               -1,  5, -1,
-                                0, -1,  0);
- at endcode
-Then call the @ref cv::filter2D function specifying the input, the output image and the kernell to
+to define an object that holds the mask:
+ at add_toggle_cpp
+ at snippet samples/cpp/tutorial_code/core/mat_mask_operations/mat_mask_operations.cpp kern
+
+Then call the @ref cv::filter2D function specifying the input, the output image and the kernel to
 use:
- at code{.cpp}
-filter2D(I, K, I.depth(), kern);
- at endcode
-The function even has a fifth optional argument to specify the center of the kernel, and a sixth one
-for determining what to do in the regions where the operation is undefined (borders). Using this
-function has the advantage that it's shorter, less verbose and because there are some optimization
-techniques implemented it is usually faster than the *hand-coded method*. For example in my test
-while the second one took only 13 milliseconds the first took around 31 milliseconds. Quite some
-difference.
+ at snippet samples/cpp/tutorial_code/core/mat_mask_operations/mat_mask_operations.cpp filter2D
+
+The function even has a fifth optional argument to specify the center of the kernel, a sixth
+for adding an optional value to the filtered pixels before storing them in K and a seventh one
+for determining what to do in the regions where the operation is undefined (borders).
+ at end_toggle
+
+ at add_toggle_java
+ at snippet samples/java/tutorial_code/core/mat_mask_operations/MatMaskOperations.java kern
+
+Then call the **Imgproc.filter2D()** function specifying the input, the output image and the kernel to
+use:
+ at snippet samples/java/tutorial_code/core/mat_mask_operations/MatMaskOperations.java filter2D
+The function even has a fifth optional argument to specify the center of the kernel, a sixth
+for adding an optional value to the filtered pixels before storing them in K and a seventh one
+for determining what to do in the regions where the operation is undefined (borders).
+ at end_toggle
+
+ at add_toggle_python
+ at snippet samples/python/tutorial_code/core/mat_mask_operations/mat_mask_operations.py kern
+
+Then call the **cv2.filter2D()** function specifying the input, the output image and the kernell to
+use:
+ at snippet samples/python/tutorial_code/core/mat_mask_operations/mat_mask_operations.py filter2D
+ at end_toggle
+
+This function is shorter, less verbose and, because there are some optimizations, it is usually faster
+than the *hand-coded method*. For example in my test while the second one took only 13
+milliseconds the first took around 31 milliseconds. Quite some difference.
 
 For example:
 
 ![](images/resultMatMaskFilter2D.png)
 
+ at add_toggle_cpp
 You can download this source code from [here
-](https://github.com/Itseez/opencv/tree/master/samples/cpp/tutorial_code/core/mat_mask_operations/mat_mask_operations.cpp) or look in the
+](https://github.com/opencv/opencv/tree/master/samples/cpp/tutorial_code/core/mat_mask_operations/mat_mask_operations.cpp) or look in the
 OpenCV source code libraries sample directory at
 `samples/cpp/tutorial_code/core/mat_mask_operations/mat_mask_operations.cpp`.
 
 Check out an instance of running the program on our [YouTube
 channel](http://www.youtube.com/watch?v=7PF1tAU9se4) .
-
-\htmlonly
-<div align="center">
-<iframe width="560" height="349" src="https://www.youtube.com/embed/7PF1tAU9se4?hd=1" frameborder="0" allowfullscreen></iframe>
-</div>
-\endhtmlonly
+ at youtube{7PF1tAU9se4}
+ at end_toggle
+
+ at add_toggle_java
+You can look in the OpenCV source code libraries sample directory at
+`samples/java/tutorial_code/core/mat_mask_operations/MatMaskOperations.java`.
+ at end_toggle
+
+ at add_toggle_python
+You can look in the OpenCV source code libraries sample directory at
+`samples/python/tutorial_code/core/mat_mask_operations/mat_mask_operations.py`.
+ at end_toggle
diff --git a/doc/tutorials/core/mat_the_basic_image_container/mat_the_basic_image_container.markdown b/doc/tutorials/core/mat_the_basic_image_container/mat_the_basic_image_container.markdown
index 6598974..9e290b8 100644
--- a/doc/tutorials/core/mat_the_basic_image_container/mat_the_basic_image_container.markdown
+++ b/doc/tutorials/core/mat_the_basic_image_container/mat_the_basic_image_container.markdown
@@ -258,7 +258,7 @@ OpenCV offers support for output of other common OpenCV data structures too via
     ![](images/MatBasicContainerOut15.png)
 
 Most of the samples here have been included in a small console application. You can download it from
-[here](https://github.com/Itseez/opencv/tree/master/samples/cpp/tutorial_code/core/mat_the_basic_image_container/mat_the_basic_image_container.cpp)
+[here](https://github.com/opencv/opencv/tree/master/samples/cpp/tutorial_code/core/mat_the_basic_image_container/mat_the_basic_image_container.cpp)
 or in the core section of the cpp samples.
 
 You can also find a quick video demonstration of this on
diff --git a/doc/tutorials/core/table_of_content_core.markdown b/doc/tutorials/core/table_of_content_core.markdown
index 99e0048..70d9c81 100644
--- a/doc/tutorials/core/table_of_content_core.markdown
+++ b/doc/tutorials/core/table_of_content_core.markdown
@@ -25,6 +25,8 @@ understanding how to manipulate the images on a pixel level.
 
 -   @subpage tutorial_mat_mask_operations
 
+    *Languages:* C++, Java, Python
+
     *Compatibility:* \> OpenCV 2.0
 
     *Author:* Bernát Gábor
diff --git a/doc/tutorials/features2d/akaze_tracking/akaze_tracking.markdown b/doc/tutorials/features2d/akaze_tracking/akaze_tracking.markdown
index 41bbfdd..518cada 100644
--- a/doc/tutorials/features2d/akaze_tracking/akaze_tracking.markdown
+++ b/doc/tutorials/features2d/akaze_tracking/akaze_tracking.markdown
@@ -28,9 +28,9 @@ To do the tracking we need a video and object position on the first frame.
 You can download our example video and data from
 [here](https://docs.google.com/file/d/0B72G7D4snftJandBb0taLVJHMFk).
 
-To run the code you have to specify input and output video path and object bounding box.
+To run the code you have to specify input (camera id or video_file). Then, select a bounding box with the mouse, and press any key to start tracking
 @code{.none}
-./planar_tracking blais.mp4 result.avi blais_bb.xml.gz
+./planar_tracking blais.mp4
 @endcode
 
 Source Code
diff --git a/doc/tutorials/features2d/feature_homography/feature_homography.markdown b/doc/tutorials/features2d/feature_homography/feature_homography.markdown
index dd96302..ec7913c 100644
--- a/doc/tutorials/features2d/feature_homography/feature_homography.markdown
+++ b/doc/tutorials/features2d/feature_homography/feature_homography.markdown
@@ -75,7 +75,7 @@ int main( int argc, char** argv )
   std::vector< DMatch > good_matches;
 
   for( int i = 0; i < descriptors_object.rows; i++ )
-  { if( matches[i].distance < 3*min_dist )
+  { if( matches[i].distance <= 3*min_dist )
      { good_matches.push_back( matches[i]); }
   }
 
diff --git a/doc/tutorials/features2d/trackingmotion/corner_subpixeles/corner_subpixeles.markdown b/doc/tutorials/features2d/trackingmotion/corner_subpixeles/corner_subpixeles.markdown
index be9b976..946fd77 100644
--- a/doc/tutorials/features2d/trackingmotion/corner_subpixeles/corner_subpixeles.markdown
+++ b/doc/tutorials/features2d/trackingmotion/corner_subpixeles/corner_subpixeles.markdown
@@ -16,106 +16,9 @@ Code
 ----
 
 This tutorial code's is shown lines below. You can also download it from
-[here](https://github.com/Itseez/opencv/tree/master/samples/cpp/tutorial_code/TrackingMotion/cornerSubPix_Demo.cpp)
- at code{.cpp}
-#include "opencv2/highgui.hpp"
-#include "opencv2/imgproc.hpp"
-#include <iostream>
-#include <stdio.h>
-#include <stdlib.h>
+[here](https://github.com/opencv/opencv/tree/master/samples/cpp/tutorial_code/TrackingMotion/cornerSubPix_Demo.cpp)
+ at include samples/cpp/tutorial_code/TrackingMotion/cornerSubPix_Demo.cpp
 
-using namespace cv;
-using namespace std;
-
-/// Global variables
-Mat src, src_gray;
-
-int maxCorners = 10;
-int maxTrackbar = 25;
-
-RNG rng(12345);
-char* source_window = "Image";
-
-/// Function header
-void goodFeaturesToTrack_Demo( int, void* );
-
-/* @function main */
-int main( int argc, char** argv )
-{
-  /// Load source image and convert it to gray
-  src = imread( argv[1], 1 );
-  cvtColor( src, src_gray, COLOR_BGR2GRAY );
-
-  /// Create Window
-  namedWindow( source_window, WINDOW_AUTOSIZE );
-
-  /// Create Trackbar to set the number of corners
-  createTrackbar( "Max  corners:", source_window, &maxCorners, maxTrackbar, goodFeaturesToTrack_Demo);
-
-  imshow( source_window, src );
-
-  goodFeaturesToTrack_Demo( 0, 0 );
-
-  waitKey(0);
-  return(0);
-}
-
-/*
- * @function goodFeaturesToTrack_Demo.cpp
- * @brief Apply Shi-Tomasi corner detector
- */
-void goodFeaturesToTrack_Demo( int, void* )
-{
-  if( maxCorners < 1 ) { maxCorners = 1; }
-
-  /// Parameters for Shi-Tomasi algorithm
-  vector<Point2f> corners;
-  double qualityLevel = 0.01;
-  double minDistance = 10;
-  int blockSize = 3;
-  bool useHarrisDetector = false;
-  double k = 0.04;
-
-  /// Copy the source image
-  Mat copy;
-  copy = src.clone();
-
-  /// Apply corner detection
-  goodFeaturesToTrack( src_gray,
-               corners,
-               maxCorners,
-               qualityLevel,
-               minDistance,
-               Mat(),
-               blockSize,
-               useHarrisDetector,
-               k );
-
-
-  /// Draw corners detected
-  cout<<"** Number of corners detected: "<<corners.size()<<endl;
-  int r = 4;
-  for( int i = 0; i < corners.size(); i++ )
-     { circle( copy, corners[i], r, Scalar(rng.uniform(0,255), rng.uniform(0,255),
-                                                 rng.uniform(0,255)), -1, 8, 0 ); }
-
-  /// Show what you got
-  namedWindow( source_window, WINDOW_AUTOSIZE );
-  imshow( source_window, copy );
-
-  /// Set the neeed parameters to find the refined corners
-  Size winSize = Size( 5, 5 );
-  Size zeroZone = Size( -1, -1 );
-  TermCriteria criteria = TermCriteria( TermCriteria::EPS + TermCriteria::MAX_ITER, 40, 0.001 );
-
-  /// Calculate the refined corner locations
-  cornerSubPix( src_gray, corners, winSize, zeroZone, criteria );
-
-  /// Write them down
-  for( int i = 0; i < corners.size(); i++ )
-     { cout<<" -- Refined Corner ["<<i<<"]  ("<<corners[i].x<<","<<corners[i].y<<")"<<endl; }
-}
- at endcode
 Explanation
 -----------
 
diff --git a/doc/tutorials/features2d/trackingmotion/generic_corner_detector/generic_corner_detector.markdown b/doc/tutorials/features2d/trackingmotion/generic_corner_detector/generic_corner_detector.markdown
index dd04afc..7aba636 100644
--- a/doc/tutorials/features2d/trackingmotion/generic_corner_detector/generic_corner_detector.markdown
+++ b/doc/tutorials/features2d/trackingmotion/generic_corner_detector/generic_corner_detector.markdown
@@ -20,7 +20,7 @@ Code
 ----
 
 This tutorial code's is shown lines below. You can also download it from
-[here](https://github.com/Itseez/opencv/tree/master/samples/cpp/tutorial_code/TrackingMotion/cornerDetector_Demo.cpp)
+[here](https://github.com/opencv/opencv/tree/master/samples/cpp/tutorial_code/TrackingMotion/cornerDetector_Demo.cpp)
 
 @include cpp/tutorial_code/TrackingMotion/cornerDetector_Demo.cpp
 
diff --git a/doc/tutorials/features2d/trackingmotion/good_features_to_track/good_features_to_track.markdown b/doc/tutorials/features2d/trackingmotion/good_features_to_track/good_features_to_track.markdown
index e4d9769..7c48aa1 100644
--- a/doc/tutorials/features2d/trackingmotion/good_features_to_track/good_features_to_track.markdown
+++ b/doc/tutorials/features2d/trackingmotion/good_features_to_track/good_features_to_track.markdown
@@ -15,96 +15,9 @@ Code
 ----
 
 This tutorial code's is shown lines below. You can also download it from
-[here](https://github.com/Itseez/opencv/tree/master/samples/cpp/tutorial_code/TrackingMotion/goodFeaturesToTrack_Demo.cpp)
- at code{.cpp}
-#include "opencv2/highgui.hpp"
-#include "opencv2/imgproc.hpp"
-#include <iostream>
-#include <stdio.h>
-#include <stdlib.h>
+[here](https://github.com/opencv/opencv/tree/master/samples/cpp/tutorial_code/TrackingMotion/goodFeaturesToTrack_Demo.cpp)
+ at include samples/cpp/tutorial_code/TrackingMotion/goodFeaturesToTrack_Demo.cpp
 
-using namespace cv;
-using namespace std;
-
-/// Global variables
-Mat src, src_gray;
-
-int maxCorners = 23;
-int maxTrackbar = 100;
-
-RNG rng(12345);
-char* source_window = "Image";
-
-/// Function header
-void goodFeaturesToTrack_Demo( int, void* );
-
-/*
- * @function main
- */
-int main( int argc, char** argv )
-{
-  /// Load source image and convert it to gray
-  src = imread( argv[1], 1 );
-  cvtColor( src, src_gray, COLOR_BGR2GRAY );
-
-  /// Create Window
-  namedWindow( source_window, WINDOW_AUTOSIZE );
-
-  /// Create Trackbar to set the number of corners
-  createTrackbar( "Max  corners:", source_window, &maxCorners, maxTrackbar, goodFeaturesToTrack_Demo );
-
-  imshow( source_window, src );
-
-  goodFeaturesToTrack_Demo( 0, 0 );
-
-  waitKey(0);
-  return(0);
-}
-
-/*
- * @function goodFeaturesToTrack_Demo.cpp
- * @brief Apply Shi-Tomasi corner detector
- */
-void goodFeaturesToTrack_Demo( int, void* )
-{
-  if( maxCorners < 1 ) { maxCorners = 1; }
-
-  /// Parameters for Shi-Tomasi algorithm
-  vector<Point2f> corners;
-  double qualityLevel = 0.01;
-  double minDistance = 10;
-  int blockSize = 3;
-  bool useHarrisDetector = false;
-  double k = 0.04;
-
-  /// Copy the source image
-  Mat copy;
-  copy = src.clone();
-
-  /// Apply corner detection
-  goodFeaturesToTrack( src_gray,
-               corners,
-               maxCorners,
-               qualityLevel,
-               minDistance,
-               Mat(),
-               blockSize,
-               useHarrisDetector,
-               k );
-
-
-  /// Draw corners detected
-  cout<<"** Number of corners detected: "<<corners.size()<<endl;
-  int r = 4;
-  for( size_t i = 0; i < corners.size(); i++ )
-     { circle( copy, corners[i], r, Scalar(rng.uniform(0,255), rng.uniform(0,255),
-              rng.uniform(0,255)), -1, 8, 0 ); }
-
-  /// Show what you got
-  namedWindow( source_window, WINDOW_AUTOSIZE );
-  imshow( source_window, copy );
-}
- at endcode
 Explanation
 -----------
 
diff --git a/doc/tutorials/features2d/trackingmotion/harris_detector/harris_detector.markdown b/doc/tutorials/features2d/trackingmotion/harris_detector/harris_detector.markdown
index add7db8..a36f219 100644
--- a/doc/tutorials/features2d/trackingmotion/harris_detector/harris_detector.markdown
+++ b/doc/tutorials/features2d/trackingmotion/harris_detector/harris_detector.markdown
@@ -119,80 +119,9 @@ Code
 ----
 
 This tutorial code's is shown lines below. You can also download it from
-[here](https://github.com/Itseez/opencv/tree/master/samples/cpp/tutorial_code/TrackingMotion/cornerHarris_Demo.cpp)
- at code{.cpp}
-#include "opencv2/highgui.hpp"
-#include "opencv2/imgproc.hpp"
-#include <iostream>
-#include <stdio.h>
-#include <stdlib.h>
-
-using namespace cv;
-using namespace std;
-
-/// Global variables
-Mat src, src_gray;
-int thresh = 200;
-int max_thresh = 255;
-
-char* source_window = "Source image";
-char* corners_window = "Corners detected";
-
-/// Function header
-void cornerHarris_demo( int, void* );
-
-/* @function main */
-int main( int argc, char** argv )
-{
-  /// Load source image and convert it to gray
-  src = imread( argv[1], 1 );
-  cvtColor( src, src_gray, COLOR_BGR2GRAY );
-
-  /// Create a window and a trackbar
-  namedWindow( source_window, WINDOW_AUTOSIZE );
-  createTrackbar( "Threshold: ", source_window, &thresh, max_thresh, cornerHarris_demo );
-  imshow( source_window, src );
-
-  cornerHarris_demo( 0, 0 );
-
-  waitKey(0);
-  return(0);
-}
-
-/* @function cornerHarris_demo */
-void cornerHarris_demo( int, void* )
-{
-
-  Mat dst, dst_norm, dst_norm_scaled;
-  dst = Mat::zeros( src.size(), CV_32FC1 );
-
-  /// Detector parameters
-  int blockSize = 2;
-  int apertureSize = 3;
-  double k = 0.04;
-
-  /// Detecting corners
-  cornerHarris( src_gray, dst, blockSize, apertureSize, k, BORDER_DEFAULT );
-
-  /// Normalizing
-  normalize( dst, dst_norm, 0, 255, NORM_MINMAX, CV_32FC1, Mat() );
-  convertScaleAbs( dst_norm, dst_norm_scaled );
-
-  /// Drawing a circle around corners
-  for( int j = 0; j < dst_norm.rows ; j++ )
-     { for( int i = 0; i < dst_norm.cols; i++ )
-          {
-            if( (int) dst_norm.at<float>(j,i) > thresh )
-              {
-               circle( dst_norm_scaled, Point( i, j ), 5,  Scalar(0), 2, 8, 0 );
-              }
-          }
-     }
-  /// Showing the result
-  namedWindow( corners_window, WINDOW_AUTOSIZE );
-  imshow( corners_window, dst_norm_scaled );
-}
- at endcode
+[here](https://github.com/opencv/opencv/tree/master/samples/cpp/tutorial_code/TrackingMotion/cornerHarris_Demo.cpp)
+ at include samples/cpp/tutorial_code/TrackingMotion/cornerHarris_Demo.cpp
+
 Explanation
 -----------
 
diff --git a/doc/tutorials/gpu/gpu-basics-similarity/gpu_basics_similarity.markdown b/doc/tutorials/gpu/gpu-basics-similarity/gpu_basics_similarity.markdown
index cf8aba9..b229896 100644
--- a/doc/tutorials/gpu/gpu-basics-similarity/gpu_basics_similarity.markdown
+++ b/doc/tutorials/gpu/gpu-basics-similarity/gpu_basics_similarity.markdown
@@ -24,7 +24,7 @@ The source code
 
 You may also find the source code and these video file in the
 `samples/cpp/tutorial_code/gpu/gpu-basics-similarity/gpu-basics-similarity` folder of the OpenCV
-source library or download it from [here](https://github.com/Itseez/opencv/tree/master/samples/cpp/tutorial_code/gpu/gpu-basics-similarity/gpu-basics-similarity.cpp).
+source library or download it from [here](https://github.com/opencv/opencv/tree/master/samples/cpp/tutorial_code/gpu/gpu-basics-similarity/gpu-basics-similarity.cpp).
 The full source code is quite long (due to the controlling of the application via the command line
 arguments and performance measurement). Therefore, to avoid cluttering up these sections with those
 you'll find here only the functions itself.
diff --git a/doc/tutorials/highgui/intelperc.markdown b/doc/tutorials/highgui/intelperc.markdown
deleted file mode 100644
index b5f2ed6..0000000
--- a/doc/tutorials/highgui/intelperc.markdown
+++ /dev/null
@@ -1,82 +0,0 @@
-Using Creative Senz3D and other Intel Perceptual Computing SDK compatible depth sensors {#tutorial_intelperc}
-=======================================================================================
-
-Depth sensors compatible with Intel Perceptual Computing SDK are supported through VideoCapture
-class. Depth map, RGB image and some other formats of output can be retrieved by using familiar
-interface of VideoCapture.
-
-In order to use depth sensor with OpenCV you should do the following preliminary steps:
-
--#  Install Intel Perceptual Computing SDK (from here <http://www.intel.com/software/perceptual>).
-
--#  Configure OpenCV with Intel Perceptual Computing SDK support by setting WITH_INTELPERC flag in
-    CMake. If Intel Perceptual Computing SDK is found in install folders OpenCV will be built with
-    Intel Perceptual Computing SDK library (see a status INTELPERC in CMake log). If CMake process
-    doesn't find Intel Perceptual Computing SDK installation folder automatically, the user should
-    change corresponding CMake variables INTELPERC_LIB_DIR and INTELPERC_INCLUDE_DIR to the
-    proper value.
-
--#  Build OpenCV.
-
-VideoCapture can retrieve the following data:
-
--#  data given from depth generator:
-    -   CAP_INTELPERC_DEPTH_MAP - each pixel is a 16-bit integer. The value indicates the
-            distance from an object to the camera's XY plane or the Cartesian depth. (CV_16UC1)
-    -   CAP_INTELPERC_UVDEPTH_MAP - each pixel contains two 32-bit floating point values in
-        the range of 0-1, representing the mapping of depth coordinates to the color
-        coordinates. (CV_32FC2)
-    -   CAP_INTELPERC_IR_MAP - each pixel is a 16-bit integer. The value indicates the
-        intensity of the reflected laser beam. (CV_16UC1)
-
--#  data given from RGB image generator:
-    -   CAP_INTELPERC_IMAGE - color image. (CV_8UC3)
-
-In order to get depth map from depth sensor use VideoCapture::operator \>\>, e. g. :
- at code{.cpp}
-    VideoCapture capture( CAP_INTELPERC );
-    for(;;)
-    {
-        Mat depthMap;
-        capture >> depthMap;
-
-        if( waitKey( 30 ) >= 0 )
-            break;
-    }
- at endcode
-For getting several data maps use VideoCapture::grab and VideoCapture::retrieve, e.g. :
- at code{.cpp}
-    VideoCapture capture(CAP_INTELPERC);
-    for(;;)
-    {
-        Mat depthMap;
-        Mat image;
-        Mat irImage;
-
-        capture.grab();
-
-        capture.retrieve( depthMap, CAP_INTELPERC_DEPTH_MAP );
-        capture.retrieve(    image, CAP_INTELPERC_IMAGE );
-        capture.retrieve(  irImage, CAP_INTELPERC_IR_MAP);
-
-        if( waitKey( 30 ) >= 0 )
-            break;
-    }
- at endcode
-For setting and getting some property of sensor\` data generators use VideoCapture::set and
-VideoCapture::get methods respectively, e.g. :
- at code{.cpp}
-    VideoCapture capture( CAP_INTELPERC );
-    capture.set( CAP_INTELPERC_DEPTH_GENERATOR | CAP_PROP_INTELPERC_PROFILE_IDX, 0 );
-    cout << "FPS    " << capture.get( CAP_INTELPERC_DEPTH_GENERATOR+CAP_PROP_FPS ) << endl;
- at endcode
-Since two types of sensor's data generators are supported (image generator and depth generator),
-there are two flags that should be used to set/get property of the needed generator:
-
--   CAP_INTELPERC_IMAGE_GENERATOR -- a flag for access to the image generator properties.
--   CAP_INTELPERC_DEPTH_GENERATOR -- a flag for access to the depth generator properties. This
-    flag value is assumed by default if neither of the two possible values of the property is set.
-
-For more information please refer to the example of usage
-[intelperc_capture.cpp](https://github.com/Itseez/opencv/tree/master/samples/cpp/intelperc_capture.cpp)
-in opencv/samples/cpp folder.
diff --git a/doc/tutorials/highgui/kinect_openni.markdown b/doc/tutorials/highgui/kinect_openni.markdown
deleted file mode 100644
index c9c33a2..0000000
--- a/doc/tutorials/highgui/kinect_openni.markdown
+++ /dev/null
@@ -1,138 +0,0 @@
-Using Kinect and other OpenNI compatible depth sensors {#tutorial_kinect_openni}
-======================================================
-
-Depth sensors compatible with OpenNI (Kinect, XtionPRO, ...) are supported through VideoCapture
-class. Depth map, BGR image and some other formats of output can be retrieved by using familiar
-interface of VideoCapture.
-
-In order to use depth sensor with OpenCV you should do the following preliminary steps:
-
--#  Install OpenNI library (from here <http://www.openni.org/downloadfiles>) and PrimeSensor Module
-    for OpenNI (from here <https://github.com/avin2/SensorKinect>). The installation should be done
-    to default folders listed in the instructions of these products, e.g.:
-    @code{.text}
-    OpenNI:
-        Linux & MacOSX:
-            Libs into: /usr/lib
-            Includes into: /usr/include/ni
-        Windows:
-            Libs into: c:/Program Files/OpenNI/Lib
-            Includes into: c:/Program Files/OpenNI/Include
-    PrimeSensor Module:
-        Linux & MacOSX:
-            Bins into: /usr/bin
-        Windows:
-            Bins into: c:/Program Files/Prime Sense/Sensor/Bin
-    @endcode
-    If one or both products were installed to the other folders, the user should change
-    corresponding CMake variables OPENNI_LIB_DIR, OPENNI_INCLUDE_DIR or/and
-    OPENNI_PRIME_SENSOR_MODULE_BIN_DIR.
-
--#  Configure OpenCV with OpenNI support by setting WITH_OPENNI flag in CMake. If OpenNI is found
-    in install folders OpenCV will be built with OpenNI library (see a status OpenNI in CMake log)
-    whereas PrimeSensor Modules can not be found (see a status OpenNI PrimeSensor Modules in CMake
-    log). Without PrimeSensor module OpenCV will be successfully compiled with OpenNI library, but
-    VideoCapture object will not grab data from Kinect sensor.
-
--#  Build OpenCV.
-
-VideoCapture can retrieve the following data:
-
--#  data given from depth generator:
-    -   CAP_OPENNI_DEPTH_MAP - depth values in mm (CV_16UC1)
-    -   CAP_OPENNI_POINT_CLOUD_MAP - XYZ in meters (CV_32FC3)
-    -   CAP_OPENNI_DISPARITY_MAP - disparity in pixels (CV_8UC1)
-    -   CAP_OPENNI_DISPARITY_MAP_32F - disparity in pixels (CV_32FC1)
-    -   CAP_OPENNI_VALID_DEPTH_MASK - mask of valid pixels (not ocluded, not shaded etc.)
-        (CV_8UC1)
-
--#  data given from BGR image generator:
-    -   CAP_OPENNI_BGR_IMAGE - color image (CV_8UC3)
-    -   CAP_OPENNI_GRAY_IMAGE - gray image (CV_8UC1)
-
-In order to get depth map from depth sensor use VideoCapture::operator \>\>, e. g. :
- at code{.cpp}
-    VideoCapture capture( CAP_OPENNI );
-    for(;;)
-    {
-        Mat depthMap;
-        capture >> depthMap;
-
-        if( waitKey( 30 ) >= 0 )
-            break;
-    }
- at endcode
-For getting several data maps use VideoCapture::grab and VideoCapture::retrieve, e.g. :
- at code{.cpp}
-    VideoCapture capture(0); // or CAP_OPENNI
-    for(;;)
-    {
-        Mat depthMap;
-        Mat bgrImage;
-
-        capture.grab();
-
-        capture.retrieve( depthMap, CAP_OPENNI_DEPTH_MAP );
-        capture.retrieve( bgrImage, CAP_OPENNI_BGR_IMAGE );
-
-        if( waitKey( 30 ) >= 0 )
-            break;
-    }
- at endcode
-For setting and getting some property of sensor\` data generators use VideoCapture::set and
-VideoCapture::get methods respectively, e.g. :
- at code{.cpp}
-    VideoCapture capture( CAP_OPENNI );
-    capture.set( CAP_OPENNI_IMAGE_GENERATOR_OUTPUT_MODE, CAP_OPENNI_VGA_30HZ );
-    cout << "FPS    " << capture.get( CAP_OPENNI_IMAGE_GENERATOR+CAP_PROP_FPS ) << endl;
- at endcode
-Since two types of sensor's data generators are supported (image generator and depth generator),
-there are two flags that should be used to set/get property of the needed generator:
-
--   CAP_OPENNI_IMAGE_GENERATOR -- A flag for access to the image generator properties.
--   CAP_OPENNI_DEPTH_GENERATOR -- A flag for access to the depth generator properties. This flag
-    value is assumed by default if neither of the two possible values of the property is not set.
-
-Some depth sensors (for example XtionPRO) do not have image generator. In order to check it you can
-get CAP_OPENNI_IMAGE_GENERATOR_PRESENT property.
- at code{.cpp}
-bool isImageGeneratorPresent = capture.get( CAP_PROP_OPENNI_IMAGE_GENERATOR_PRESENT ) != 0; // or == 1
- at endcode
-Flags specifing the needed generator type must be used in combination with particular generator
-property. The following properties of cameras available through OpenNI interfaces are supported:
-
--   For image generator:
-
-    -   CAP_PROP_OPENNI_OUTPUT_MODE -- Three output modes are supported: CAP_OPENNI_VGA_30HZ
-        used by default (image generator returns images in VGA resolution with 30 FPS),
-        CAP_OPENNI_SXGA_15HZ (image generator returns images in SXGA resolution with 15 FPS) and
-        CAP_OPENNI_SXGA_30HZ (image generator returns images in SXGA resolution with 30 FPS, the
-        mode is supported by XtionPRO Live); depth generator's maps are always in VGA resolution.
-
--   For depth generator:
-
-    -   CAP_PROP_OPENNI_REGISTRATION -- Flag that registers the remapping depth map to image map
-        by changing depth generator's view point (if the flag is "on") or sets this view point to
-        its normal one (if the flag is "off"). The registration process’s resulting images are
-        pixel-aligned,which means that every pixel in the image is aligned to a pixel in the depth
-        image.
-
-        Next properties are available for getting only:
-
-    -   CAP_PROP_OPENNI_FRAME_MAX_DEPTH -- A maximum supported depth of Kinect in mm.
-    -   CAP_PROP_OPENNI_BASELINE -- Baseline value in mm.
-    -   CAP_PROP_OPENNI_FOCAL_LENGTH -- A focal length in pixels.
-    -   CAP_PROP_FRAME_WIDTH -- Frame width in pixels.
-    -   CAP_PROP_FRAME_HEIGHT -- Frame height in pixels.
-    -   CAP_PROP_FPS -- Frame rate in FPS.
-
--   Some typical flags combinations "generator type + property" are defined as single flags:
-
-    -   CAP_OPENNI_IMAGE_GENERATOR_OUTPUT_MODE = CAP_OPENNI_IMAGE_GENERATOR + CAP_PROP_OPENNI_OUTPUT_MODE
-    -   CAP_OPENNI_DEPTH_GENERATOR_BASELINE = CAP_OPENNI_DEPTH_GENERATOR + CAP_PROP_OPENNI_BASELINE
-    -   CAP_OPENNI_DEPTH_GENERATOR_FOCAL_LENGTH = CAP_OPENNI_DEPTH_GENERATOR + CAP_PROP_OPENNI_FOCAL_LENGTH
-    -   CAP_OPENNI_DEPTH_GENERATOR_REGISTRATION = CAP_OPENNI_DEPTH_GENERATOR + CAP_PROP_OPENNI_REGISTRATION
-
-For more information please refer to the example of usage
-[openni_capture.cpp](https://github.com/Itseez/opencv/tree/master/samples/cpp/openni_capture.cpp) in
-opencv/samples/cpp folder.
diff --git a/doc/tutorials/highgui/raster-gdal/raster_io_gdal.markdown b/doc/tutorials/highgui/raster-gdal/raster_io_gdal.markdown
deleted file mode 100644
index 95137be..0000000
--- a/doc/tutorials/highgui/raster-gdal/raster_io_gdal.markdown
+++ /dev/null
@@ -1,101 +0,0 @@
-Reading Geospatial Raster files with GDAL {#tutorial_raster_io_gdal}
-=========================================
-
-Geospatial raster data is a heavily used product in Geographic Information Systems and
-Photogrammetry. Raster data typically can represent imagery and Digital Elevation Models (DEM). The
-standard library for loading GIS imagery is the Geographic Data Abstraction Library [(GDAL)](http://www.gdal.org). In this
-example, we will show techniques for loading GIS raster formats using native OpenCV functions. In
-addition, we will show some an example of how OpenCV can use this data for novel and interesting
-purposes.
-
-Goals
------
-
-The primary objectives for this tutorial:
-
--   How to use OpenCV [imread](@ref imread) to load satellite imagery.
--   How to use OpenCV [imread](@ref imread) to load SRTM Digital Elevation Models
--   Given the corner coordinates of both the image and DEM, correllate the elevation data to the
-    image to find elevations for each pixel.
--   Show a basic, easy-to-implement example of a terrain heat map.
--   Show a basic use of DEM data coupled with ortho-rectified imagery.
-
-To implement these goals, the following code takes a Digital Elevation Model as well as a GeoTiff
-image of San Francisco as input. The image and DEM data is processed and generates a terrain heat
-map of the image as well as labels areas of the city which would be affected should the water level
-of the bay rise 10, 50, and 100 meters.
-
-Code
-----
-
- at include cpp/tutorial_code/HighGUI/GDAL_IO/gdal-image.cpp
-
-How to Read Raster Data using GDAL
-----------------------------------
-
-This demonstration uses the default OpenCV imread function. The primary difference is that in order
-to force GDAL to load the image, you must use the appropriate flag.
- at code{.cpp}
-cv::Mat image = cv::imread( argv[1], cv::IMREAD_LOAD_GDAL );
- at endcode
-When loading digital elevation models, the actual numeric value of each pixel is essential and
-cannot be scaled or truncated. For example, with image data a pixel represented as a double with a
-value of 1 has an equal appearance to a pixel which is represented as an unsigned character with a
-value of 255. With terrain data, the pixel value represents the elevation in meters. In order to
-ensure that OpenCV preserves the native value, use the GDAL flag in imread with the ANYDEPTH flag.
- at code{.cpp}
-cv::Mat dem = cv::imread( argv[2], cv::IMREAD_LOAD_GDAL | cv::IMREAD_ANYDEPTH );
- at endcode
-If you know beforehand the type of DEM model you are loading, then it may be a safe bet to test the
-Mat::type() or Mat::depth() using an assert or other mechanism. NASA or DOD specification documents
-can provide the input types for various elevation models. The major types, SRTM and DTED, are both
-signed shorts.
-
-Notes
------
-
-### Lat/Lon (Geographic) Coordinates should normally be avoided
-
-The Geographic Coordinate System is a spherical coordinate system, meaning that using them with
-Cartesian mathematics is technically incorrect. This demo uses them to increase the readability and
-is accurate enough to make the point. A better coordinate system would be Universal Transverse
-Mercator.
-
-### Finding the corner coordinates
-
-One easy method to find the corner coordinates of an image is to use the command-line tool gdalinfo.
-For imagery which is ortho-rectified and contains the projection information, you can use the [USGS
-EarthExplorer](http://http://earthexplorer.usgs.gov).
- at code{.bash}
-\f$> gdalinfo N37W123.hgt
-
-   Driver: SRTMHGT/SRTMHGT File Format
-   Files: N37W123.hgt
-   Size is 3601, 3601
-   Coordinate System is:
-   GEOGCS["WGS 84",
-   DATUM["WGS_1984",
-
-   ... more output ...
-
-   Corner Coordinates:
-   Upper Left  (-123.0001389,  38.0001389) (123d 0' 0.50"W, 38d 0' 0.50"N)
-   Lower Left  (-123.0001389,  36.9998611) (123d 0' 0.50"W, 36d59'59.50"N)
-   Upper Right (-121.9998611,  38.0001389) (121d59'59.50"W, 38d 0' 0.50"N)
-   Lower Right (-121.9998611,  36.9998611) (121d59'59.50"W, 36d59'59.50"N)
-   Center      (-122.5000000,  37.5000000) (122d30' 0.00"W, 37d30' 0.00"N)
-
-    ... more output ...
- at endcode
-Results
--------
-
-Below is the output of the program. Use the first image as the input. For the DEM model, download
-the SRTM file located at the USGS here.
-[<http://dds.cr.usgs.gov/srtm/version2_1/SRTM1/Region_04/N37W123.hgt.zip>](http://dds.cr.usgs.gov/srtm/version2_1/SRTM1/Region_04/N37W123.hgt.zip)
-
-![Input Image](images/gdal_output.jpg)
-
-![Heat Map](images/gdal_heat-map.jpg)
-
-![Heat Map Overlay](images/gdal_flood-zone.jpg)
diff --git a/doc/tutorials/highgui/table_of_content_highgui.markdown b/doc/tutorials/highgui/table_of_content_highgui.markdown
index 3ff0e03..a8f1d4e 100644
--- a/doc/tutorials/highgui/table_of_content_highgui.markdown
+++ b/doc/tutorials/highgui/table_of_content_highgui.markdown
@@ -1,8 +1,7 @@
 High Level GUI and Media (highgui module) {#tutorial_table_of_content_highgui}
 =========================================
 
-This section contains valuable tutorials about how to read/save your image/video files and how to
-use the built-in graphical user interface of the library.
+This section contains tutorials about how to use the built-in graphical user interface of the library.
 
 -   @subpage tutorial_trackbar
 
@@ -11,33 +10,3 @@ use the built-in graphical user interface of the library.
     *Author:* Ana Huamán
 
     We will learn how to add a Trackbar to our applications
-
--   @subpage tutorial_video_input_psnr_ssim
-
-    *Compatibility:* \> OpenCV 2.0
-
-    *Author:* Bernát Gábor
-
-    You will learn how to read video streams, and how to calculate similarity values such as PSNR
-    or SSIM.
-
--   @subpage tutorial_video_write
-
-    *Compatibility:* \> OpenCV 2.0
-
-    *Author:* Bernát Gábor
-
-    Whenever you work with video feeds you may eventually want to save your image processing
-    result in a form of a new video file. Here's how to do it.
-
--   @subpage tutorial_raster_io_gdal
-
-    *Compatibility:* \> OpenCV 2.0
-
-    *Author:* Marvin Smith
-
-    Read common GIS Raster and DEM files to display and manipulate geographic data.
-
--   @subpage tutorial_kinect_openni
-
--   @subpage tutorial_intelperc
diff --git a/doc/tutorials/highgui/trackbar/trackbar.markdown b/doc/tutorials/highgui/trackbar/trackbar.markdown
index 50c13fa..b39572c 100644
--- a/doc/tutorials/highgui/trackbar/trackbar.markdown
+++ b/doc/tutorials/highgui/trackbar/trackbar.markdown
@@ -4,7 +4,7 @@ Adding a Trackbar to our applications! {#tutorial_trackbar}
 -   In the previous tutorials (about *linear blending* and the *brightness and contrast
     adjustments*) you might have noted that we needed to give some **input** to our programs, such
     as \f$\alpha\f$ and \f$beta\f$. We accomplished that by entering this data using the Terminal
--   Well, it is time to use some fancy GUI tools. OpenCV provides some GUI utilities (*highgui.h*)
+-   Well, it is time to use some fancy GUI tools. OpenCV provides some GUI utilities (*highgui.hpp*)
     for you. An example of this is a **Trackbar**
 
     ![](images/Adding_Trackbars_Tutorial_Trackbar.png)
@@ -24,104 +24,36 @@ Code
 
 Let's modify the program made in the tutorial @ref tutorial_adding_images. We will let the user enter the
 \f$\alpha\f$ value by using the Trackbar.
- at code{.cpp}
-#include <opencv2/opencv.hpp>
-using namespace cv;
-
-/// Global Variables
-const int alpha_slider_max = 100;
-int alpha_slider;
-double alpha;
-double beta;
-
-/// Matrices to store images
-Mat src1;
-Mat src2;
-Mat dst;
-
-/*
- * @function on_trackbar
- * @brief Callback for trackbar
- */
-void on_trackbar( int, void* )
-{
-  alpha = (double) alpha_slider/alpha_slider_max ;
-  beta = ( 1.0 - alpha );
-
-  addWeighted( src1, alpha, src2, beta, 0.0, dst);
-
-  imshow( "Linear Blend", dst );
-}
-
-int main( int argc, char** argv )
-{
-  /// Read image ( same size, same type )
-  src1 = imread("../../images/LinuxLogo.jpg");
-  src2 = imread("../../images/WindowsLogo.jpg");
-
-  if( !src1.data ) { printf("Error loading src1 \n"); return -1; }
-  if( !src2.data ) { printf("Error loading src2 \n"); return -1; }
-
-  /// Initialize values
-  alpha_slider = 0;
-
-  /// Create Windows
-  namedWindow("Linear Blend", 1);
-
-  /// Create Trackbars
-  char TrackbarName[50];
-  sprintf( TrackbarName, "Alpha x %d", alpha_slider_max );
-
-  createTrackbar( TrackbarName, "Linear Blend", &alpha_slider, alpha_slider_max, on_trackbar );
-
-  /// Show some stuff
-  on_trackbar( alpha_slider, 0 );
-
-  /// Wait until user press some key
-  waitKey(0);
-  return 0;
-}
- at endcode
+This tutorial code's is shown lines below. You can also download it from
+[here](https://github.com/opencv/opencv/tree/master/samples/cpp/tutorial_code/HighGUI/AddingImagesTrackbar.cpp)
+ at include cpp/tutorial_code/HighGUI/AddingImagesTrackbar.cpp
 
 Explanation
 -----------
 
 We only analyze the code that is related to Trackbar:
 
--#  First, we load 02 images, which are going to be blended.
-    @code{.cpp}
-    src1 = imread("../../images/LinuxLogo.jpg");
-    src2 = imread("../../images/WindowsLogo.jpg");
-    @endcode
+-#  First, we load two images, which are going to be blended.
+    @snippet cpp/tutorial_code/HighGUI/AddingImagesTrackbar.cpp load
+
 -#  To create a trackbar, first we have to create the window in which it is going to be located. So:
-    @code{.cpp}
-    namedWindow("Linear Blend", 1);
-    @endcode
+    @snippet cpp/tutorial_code/HighGUI/AddingImagesTrackbar.cpp window
+
 -#  Now we can create the Trackbar:
-    @code{.cpp}
-    createTrackbar( TrackbarName, "Linear Blend", &alpha_slider, alpha_slider_max, on_trackbar );
-    @endcode
+    @snippet cpp/tutorial_code/HighGUI/AddingImagesTrackbar.cpp create_trackbar
+
     Note the following:
 
     -   Our Trackbar has a label **TrackbarName**
-    -   The Trackbar is located in the window named **"Linear Blend"**
+    -   The Trackbar is located in the window named **Linear Blend**
     -   The Trackbar values will be in the range from \f$0\f$ to **alpha_slider_max** (the minimum
         limit is always **zero**).
     -   The numerical value of Trackbar is stored in **alpha_slider**
     -   Whenever the user moves the Trackbar, the callback function **on_trackbar** is called
 
 -#  Finally, we have to define the callback function **on_trackbar**
-    @code{.cpp}
-    void on_trackbar( int, void* )
-    {
-     alpha = (double) alpha_slider/alpha_slider_max ;
-     beta = ( 1.0 - alpha );
-
-     addWeighted( src1, alpha, src2, beta, 0.0, dst);
+    @snippet cpp/tutorial_code/HighGUI/AddingImagesTrackbar.cpp on_trackbar
 
-     imshow( "Linear Blend", dst );
-    }
-    @endcode
     Note that:
     -   We use the value of **alpha_slider** (integer) to get a double value for **alpha**.
     -   **alpha_slider** is updated each time the trackbar is displaced by the user.
@@ -135,7 +67,7 @@ Result
 
     ![](images/Adding_Trackbars_Tutorial_Result_0.jpg)
 
--   As a manner of practice, you can also add 02 trackbars for the program made in
+-   As a manner of practice, you can also add two trackbars for the program made in
     @ref tutorial_basic_linear_transform. One trackbar to set \f$\alpha\f$ and another for \f$\beta\f$. The output might
     look like:
 
diff --git a/doc/tutorials/highgui/video-input-psnr-ssim/video_input_psnr_ssim.markdown b/doc/tutorials/highgui/video-input-psnr-ssim/video_input_psnr_ssim.markdown
deleted file mode 100644
index 1e61a87..0000000
--- a/doc/tutorials/highgui/video-input-psnr-ssim/video_input_psnr_ssim.markdown
+++ /dev/null
@@ -1,251 +0,0 @@
-Video Input with OpenCV and similarity measurement {#tutorial_video_input_psnr_ssim}
-==================================================
-
-Goal
-----
-
-Today it is common to have a digital video recording system at your disposal. Therefore, you will
-eventually come to the situation that you no longer process a batch of images, but video streams.
-These may be of two kinds: real-time image feed (in the case of a webcam) or prerecorded and hard
-disk drive stored files. Luckily OpenCV threats these two in the same manner, with the same C++
-class. So here's what you'll learn in this tutorial:
-
--   How to open and read video streams
--   Two ways for checking image similarity: PSNR and SSIM
-
-The source code
----------------
-
-As a test case where to show off these using OpenCV I've created a small program that reads in two
-video files and performs a similarity check between them. This is something you could use to check
-just how well a new video compressing algorithms works. Let there be a reference (original) video
-like [this small Megamind clip
-](https://github.com/Itseez/opencv/tree/master/samples/cpp/tutorial_code/HighGUI/video-input-psnr-ssim/video/Megamind.avi) and [a compressed
-version of it ](https://github.com/Itseez/opencv/tree/master/samples/cpp/tutorial_code/HighGUI/video-input-psnr-ssim/video/Megamind_bugy.avi).
-You may also find the source code and these video file in the
-`samples/cpp/tutorial_code/HighGUI/video-input-psnr-ssim/` folder of the OpenCV source library.
-
- at include cpp/tutorial_code/HighGUI/video-input-psnr-ssim/video-input-psnr-ssim.cpp
-
-How to read a video stream (online-camera or offline-file)?
------------------------------------------------------------
-
-Essentially, all the functionalities required for video manipulation is integrated in the @ref cv::VideoCapture
-C++ class. This on itself builds on the FFmpeg open source library. This is a basic
-dependency of OpenCV so you shouldn't need to worry about this. A video is composed of a succession
-of images, we refer to these in the literature as frames. In case of a video file there is a *frame
-rate* specifying just how long is between two frames. While for the video cameras usually there is a
-limit of just how many frames they can digitalize per second, this property is less important as at
-any time the camera sees the current snapshot of the world.
-
-The first task you need to do is to assign to a @ref cv::VideoCapture class its source. You can do
-this either via the @ref cv::VideoCapture::VideoCapture or its @ref cv::VideoCapture::open function. If this argument is an
-integer then you will bind the class to a camera, a device. The number passed here is the ID of the
-device, assigned by the operating system. If you have a single camera attached to your system its ID
-will probably be zero and further ones increasing from there. If the parameter passed to these is a
-string it will refer to a video file, and the string points to the location and name of the file.
-For example, to the upper source code a valid command line is:
- at code{.bash}
-video/Megamind.avi video/Megamind_bug.avi  35 10
- at endcode
-We do a similarity check. This requires a reference and a test case video file. The first two
-arguments refer to this. Here we use a relative address. This means that the application will look
-into its current working directory and open the video folder and try to find inside this the
-*Megamind.avi* and the *Megamind_bug.avi*.
- at code{.cpp}
-const string sourceReference = argv[1],sourceCompareWith = argv[2];
-
-VideoCapture captRefrnc(sourceReference);
-// or
-VideoCapture captUndTst;
-captUndTst.open(sourceCompareWith);
- at endcode
-To check if the binding of the class to a video source was successful or not use the @ref cv::VideoCapture::isOpened
-function:
- at code{.cpp}
-if ( !captRefrnc.isOpened())
-  {
-  cout  << "Could not open reference " << sourceReference << endl;
-  return -1;
-  }
- at endcode
-Closing the video is automatic when the objects destructor is called. However, if you want to close
-it before this you need to call its @ref cv::VideoCapture::release function. The frames of the video are just
-simple images. Therefore, we just need to extract them from the @ref cv::VideoCapture object and put
-them inside a *Mat* one. The video streams are sequential. You may get the frames one after another
-by the @ref cv::VideoCapture::read or the overloaded \>\> operator:
- at code{.cpp}
-Mat frameReference, frameUnderTest;
-captRefrnc >> frameReference;
-captUndTst.open(frameUnderTest);
- at endcode
-The upper read operations will leave empty the *Mat* objects if no frame could be acquired (either
-cause the video stream was closed or you got to the end of the video file). We can check this with a
-simple if:
- at code{.cpp}
-if( frameReference.empty()  || frameUnderTest.empty())
-{
- // exit the program
-}
- at endcode
-A read method is made of a frame grab and a decoding applied on that. You may call explicitly these
-two by using the @ref cv::VideoCapture::grab and then the @ref cv::VideoCapture::retrieve functions.
-
-Videos have many-many information attached to them besides the content of the frames. These are
-usually numbers, however in some case it may be short character sequences (4 bytes or less). Due to
-this to acquire these information there is a general function named @ref cv::VideoCapture::get that returns double
-values containing these properties. Use bitwise operations to decode the characters from a double
-type and conversions where valid values are only integers. Its single argument is the ID of the
-queried property. For example, here we get the size of the frames in the reference and test case
-video file; plus the number of frames inside the reference.
- at code{.cpp}
-Size refS = Size((int) captRefrnc.get(CAP_PROP_FRAME_WIDTH),
-                 (int) captRefrnc.get(CAP_PROP_FRAME_HEIGHT)),
-
-cout << "Reference frame resolution: Width=" << refS.width << "  Height=" << refS.height
-     << " of nr#: " << captRefrnc.get(CAP_PROP_FRAME_COUNT) << endl;
- at endcode
-When you are working with videos you may often want to control these values yourself. To do this
-there is a @ref cv::VideoCapture::set function. Its first argument remains the name of the property you want to
-change and there is a second of double type containing the value to be set. It will return true if
-it succeeds and false otherwise. Good examples for this is seeking in a video file to a given time
-or frame:
- at code{.cpp}
-captRefrnc.set(CAP_PROP_POS_MSEC, 1.2);  // go to the 1.2 second in the video
-captRefrnc.set(CAP_PROP_POS_FRAMES, 10); // go to the 10th frame of the video
-// now a read operation would read the frame at the set position
- at endcode
-For properties you can read and change look into the documentation of the @ref cv::VideoCapture::get and
- at ref cv::VideoCapture::set functions.
-
-Image similarity - PSNR and SSIM
---------------------------------
-
-We want to check just how imperceptible our video converting operation went, therefore we need a
-system to check frame by frame the similarity or differences. The most common algorithm used for
-this is the PSNR (aka **Peak signal-to-noise ratio**). The simplest definition of this starts out
-from the *mean squad error*. Let there be two images: I1 and I2; with a two dimensional size i and
-j, composed of c number of channels.
-
-\f[MSE = \frac{1}{c*i*j} \sum{(I_1-I_2)^2}\f]
-
-Then the PSNR is expressed as:
-
-\f[PSNR = 10 \cdot \log_{10} \left( \frac{MAX_I^2}{MSE} \right)\f]
-
-Here the \f$MAX_I^2\f$ is the maximum valid value for a pixel. In case of the simple single byte image
-per pixel per channel this is 255. When two images are the same the MSE will give zero, resulting in
-an invalid divide by zero operation in the PSNR formula. In this case the PSNR is undefined and as
-we'll need to handle this case separately. The transition to a logarithmic scale is made because the
-pixel values have a very wide dynamic range. All this translated to OpenCV and a C++ function looks
-like:
- at code{.cpp}
-double getPSNR(const Mat& I1, const Mat& I2)
-{
- Mat s1;
- absdiff(I1, I2, s1);       // |I1 - I2|
- s1.convertTo(s1, CV_32F);  // cannot make a square on 8 bits
- s1 = s1.mul(s1);           // |I1 - I2|^2
-
- Scalar s = sum(s1);        // sum elements per channel
-
- double sse = s.val[0] + s.val[1] + s.val[2]; // sum channels
-
- if( sse <= 1e-10) // for small values return zero
-     return 0;
- else
- {
-     double  mse =sse /(double)(I1.channels() * I1.total());
-     double psnr = 10.0*log10((255*255)/mse);
-     return psnr;
- }
-}
- at endcode
-Typically result values are anywhere between 30 and 50 for video compression, where higher is
-better. If the images significantly differ you'll get much lower ones like 15 and so. This
-similarity check is easy and fast to calculate, however in practice it may turn out somewhat
-inconsistent with human eye perception. The **structural similarity** algorithm aims to correct
-this.
-
-Describing the methods goes well beyond the purpose of this tutorial. For that I invite you to read
-the article introducing it. Nevertheless, you can get a good image of it by looking at the OpenCV
-implementation below.
-
- at sa
-    SSIM is described more in-depth in the: "Z. Wang, A. C. Bovik, H. R. Sheikh and E. P.
-    Simoncelli, "Image quality assessment: From error visibility to structural similarity," IEEE
-    Transactions on Image Processing, vol. 13, no. 4, pp. 600-612, Apr. 2004." article.
-
- at code{.cpp}
-Scalar getMSSIM( const Mat& i1, const Mat& i2)
-{
- const double C1 = 6.5025, C2 = 58.5225;
- /***************************** INITS **********************************/
- int d     = CV_32F;
-
- Mat I1, I2;
- i1.convertTo(I1, d);           // cannot calculate on one byte large values
- i2.convertTo(I2, d);
-
- Mat I2_2   = I2.mul(I2);        // I2^2
- Mat I1_2   = I1.mul(I1);        // I1^2
- Mat I1_I2  = I1.mul(I2);        // I1 * I2
-
- /***********************PRELIMINARY COMPUTING ******************************/
-
- Mat mu1, mu2;   //
- GaussianBlur(I1, mu1, Size(11, 11), 1.5);
- GaussianBlur(I2, mu2, Size(11, 11), 1.5);
-
- Mat mu1_2   =   mu1.mul(mu1);
- Mat mu2_2   =   mu2.mul(mu2);
- Mat mu1_mu2 =   mu1.mul(mu2);
-
- Mat sigma1_2, sigma2_2, sigma12;
-
- GaussianBlur(I1_2, sigma1_2, Size(11, 11), 1.5);
- sigma1_2 -= mu1_2;
-
- GaussianBlur(I2_2, sigma2_2, Size(11, 11), 1.5);
- sigma2_2 -= mu2_2;
-
- GaussianBlur(I1_I2, sigma12, Size(11, 11), 1.5);
- sigma12 -= mu1_mu2;
-
- ///////////////////////////////// FORMULA ////////////////////////////////
- Mat t1, t2, t3;
-
- t1 = 2 * mu1_mu2 + C1;
- t2 = 2 * sigma12 + C2;
- t3 = t1.mul(t2);              // t3 = ((2*mu1_mu2 + C1).*(2*sigma12 + C2))
-
- t1 = mu1_2 + mu2_2 + C1;
- t2 = sigma1_2 + sigma2_2 + C2;
- t1 = t1.mul(t2);               // t1 =((mu1_2 + mu2_2 + C1).*(sigma1_2 + sigma2_2 + C2))
-
- Mat ssim_map;
- divide(t3, t1, ssim_map);      // ssim_map =  t3./t1;
-
- Scalar mssim = mean( ssim_map ); // mssim = average of ssim map
- return mssim;
-}
- at endcode
-This will return a similarity index for each channel of the image. This value is between zero and
-one, where one corresponds to perfect fit. Unfortunately, the many Gaussian blurring is quite
-costly, so while the PSNR may work in a real time like environment (24 frame per second) this will
-take significantly more than to accomplish similar performance results.
-
-Therefore, the source code presented at the start of the tutorial will perform the PSNR measurement
-for each frame, and the SSIM only for the frames where the PSNR falls below an input value. For
-visualization purpose we show both images in an OpenCV window and print the PSNR and MSSIM values to
-the console. Expect to see something like:
-
-![](images/outputVideoInput.png)
-
-You may observe a runtime instance of this on the [YouTube here](https://www.youtube.com/watch?v=iOcNljutOgg).
-
-\htmlonly
-<div align="center">
-<iframe title="Video Input with OpenCV (Plus PSNR and MSSIM)" width="560" height="349" src="http://www.youtube.com/embed/iOcNljutOgg?rel=0&loop=1" frameborder="0" allowfullscreen align="middle"></iframe>
-</div>
-\endhtmlonly
diff --git a/doc/tutorials/highgui/video-write/video_write.markdown b/doc/tutorials/highgui/video-write/video_write.markdown
deleted file mode 100644
index d10f6d0..0000000
--- a/doc/tutorials/highgui/video-write/video_write.markdown
+++ /dev/null
@@ -1,160 +0,0 @@
-Creating a video with OpenCV {#tutorial_video_write}
-============================
-
-Goal
-----
-
-Whenever you work with video feeds you may eventually want to save your image processing result in a
-form of a new video file. For simple video outputs you can use the OpenCV built-in @ref cv::VideoWriter
-class, designed for this.
-
--   How to create a video file with OpenCV
--   What type of video files you can create with OpenCV
--   How to extract a given color channel from a video
-
-As a simple demonstration I'll just extract one of the BGR color channels of an input video file
-into a new video. You can control the flow of the application from its console line arguments:
-
--   The first argument points to the video file to work on
--   The second argument may be one of the characters: R G B. This will specify which of the channels
-    to extract.
--   The last argument is the character Y (Yes) or N (No). If this is no, the codec used for the
-    input video file will be the same as for the output. Otherwise, a window will pop up and allow
-    you to select yourself the codec to use.
-
-For example, a valid command line would look like:
- at code{.bash}
-video-write.exe video/Megamind.avi R Y
- at endcode
-The source code
----------------
-
-You may also find the source code and these video file in the
-`samples/cpp/tutorial_code/highgui/video-write/` folder of the OpenCV source library or [download it
-from here ](https://github.com/Itseez/opencv/tree/master/samples/cpp/tutorial_code/HighGUI/video-write/video-write.cpp).
-
- at include cpp/tutorial_code/HighGUI/video-write/video-write.cpp
-
-The structure of a video
-------------------------
-
-For start, you should have an idea of just how a video file looks. Every video file in itself is a
-container. The type of the container is expressed in the files extension (for example *avi*, *mov*
-or *mkv*). This contains multiple elements like: video feeds, audio feeds or other tracks (like for
-example subtitles). How these feeds are stored is determined by the codec used for each one of them.
-In case of the audio tracks commonly used codecs are *mp3* or *aac*. For the video files the list is
-somehow longer and includes names such as *XVID*, *DIVX*, *H264* or *LAGS* (*Lagarith Lossless
-Codec*). The full list of codecs you may use on a system depends on just what one you have
-installed.
-
-![](images/videoFileStructure.png)
-
-As you can see things can get really complicated with videos. However, OpenCV is mainly a computer
-vision library, not a video stream, codec and write one. Therefore, the developers tried to keep
-this part as simple as possible. Due to this OpenCV for video containers supports only the *avi*
-extension, its first version. A direct limitation of this is that you cannot save a video file
-larger than 2 GB. Furthermore you can only create and expand a single video track inside the
-container. No audio or other track editing support here. Nevertheless, any video codec present on
-your system might work. If you encounter some of these limitations you will need to look into more
-specialized video writing libraries such as *FFMpeg* or codecs as *HuffYUV*, *CorePNG* and *LCL*. As
-an alternative, create the video track with OpenCV and expand it with sound tracks or convert it to
-other formats by using video manipulation programs such as *VirtualDub* or *AviSynth*.
-
-The *VideoWriter* class
------------------------
-
-The content written here builds on the assumption you
-already read the @ref tutorial_video_input_psnr_ssim tutorial and you know how to read video files. To create a
-video file you just need to create an instance of the @ref cv::VideoWriter class. You can specify
-its properties either via parameters in the constructor or later on via the @ref cv::VideoWriter::open function.
-Either way, the parameters are the same: 1. The name of the output that contains the container type
-in its extension. At the moment only *avi* is supported. We construct this from the input file, add
-to this the name of the channel to use, and finish it off with the container extension.
- at code{.cpp}
-const string source      = argv[1];            // the source file name
-string::size_type pAt = source.find_last_of('.');   // Find extension point
-const string NAME = source.substr(0, pAt) + argv[2][0] + ".avi";   // Form the new name with container
- at endcode
--#  The codec to use for the video track. Now all the video codecs have a unique short name of
-    maximum four characters. Hence, the *XVID*, *DIVX* or *H264* names. This is called a four
-    character code. You may also ask this from an input video by using its *get* function. Because
-    the *get* function is a general function it always returns double values. A double value is
-    stored on 64 bits. Four characters are four bytes, meaning 32 bits. These four characters are
-    coded in the lower 32 bits of the *double*. A simple way to throw away the upper 32 bits would
-    be to just convert this value to *int*:
-    @code{.cpp}
-    VideoCapture inputVideo(source);                                // Open input
-    int ex = static_cast<int>(inputVideo.get(CAP_PROP_FOURCC));     // Get Codec Type- Int form
-    @endcode
-    OpenCV internally works with this integer type and expect this as its second parameter. Now to
-    convert from the integer form to string we may use two methods: a bitwise operator and a union
-    method. The first one extracting from an int the characters looks like (an "and" operation, some
-    shifting and adding a 0 at the end to close the string):
-    @code{.cpp}
-    char EXT[] = {ex & 0XFF , (ex & 0XFF00) >> 8,(ex & 0XFF0000) >> 16,(ex & 0XFF000000) >> 24, 0};
-    @endcode
-    You can do the same thing with the *union* as:
-    @code{.cpp}
-    union { int v; char c[5];} uEx ;
-    uEx.v = ex;                              // From Int to char via union
-    uEx.c[4]='\0';
-    @endcode
-    The advantage of this is that the conversion is done automatically after assigning, while for
-    the bitwise operator you need to do the operations whenever you change the codec type. In case
-    you know the codecs four character code beforehand, you can use the *CV_FOURCC* macro to build
-    the integer:
-    @code{.cpp}
-    CV_FOURCC('P','I','M,'1') // this is an MPEG1 codec from the characters to integer
-    @endcode
-    If you pass for this argument minus one than a window will pop up at runtime that contains all
-    the codec installed on your system and ask you to select the one to use:
-
-    ![](images/videoCompressSelect.png)
-
--#  The frame per second for the output video. Again, here I keep the input videos frame per second
-    by using the *get* function.
--#  The size of the frames for the output video. Here too I keep the input videos frame size per
-    second by using the *get* function.
--#  The final argument is an optional one. By default is true and says that the output will be a
-    colorful one (so for write you will send three channel images). To create a gray scale video
-    pass a false parameter here.
-
-Here it is, how I use it in the sample:
- at code{.cpp}
-VideoWriter outputVideo;
-Size S = Size((int) inputVideo.get(CAP_PROP_FRAME_WIDTH),    //Acquire input size
-              (int) inputVideo.get(CAP_PROP_FRAME_HEIGHT));
-outputVideo.open(NAME , ex, inputVideo.get(CAP_PROP_FPS),S, true);
- at endcode
-Afterwards, you use the @ref cv::VideoWriter::isOpened() function to find out if the open operation succeeded or
-not. The video file automatically closes when the *VideoWriter* object is destroyed. After you open
-the object with success you can send the frames of the video in a sequential order by using the
- at ref cv::VideoWriter::write function of the class. Alternatively, you can use its overloaded operator \<\< :
- at code{.cpp}
-outputVideo.write(res);  //or
-outputVideo << res;
- at endcode
-Extracting a color channel from an BGR image means to set to zero the BGR values of the other
-channels. You can either do this with image scanning operations or by using the split and merge
-operations. You first split the channels up into different images, set the other channels to zero
-images of the same size and type and finally merge them back:
- at code{.cpp}
-split(src, spl);                 // process - extract only the correct channel
-for( int i =0; i < 3; ++i)
-   if (i != channel)
-      spl[i] = Mat::zeros(S, spl[0].type());
-merge(spl, res);
- at endcode
-Put all this together and you'll get the upper source code, whose runtime result will show something
-around the idea:
-
-![](images/resultOutputWideoWrite.png)
-
-You may observe a runtime instance of this on the [YouTube
-here](https://www.youtube.com/watch?v=jpBwHxsl1_0).
-
-\htmlonly
-<div align="center">
-<iframe title="Creating a video with OpenCV" width="560" height="349" src="http://www.youtube.com/embed/jpBwHxsl1_0?rel=0&loop=1" frameborder="0" allowfullscreen align="middle"></iframe>
-</div>
-\endhtmlonly
diff --git a/doc/tutorials/highgui/images/gdal-io.jpg b/doc/tutorials/imgcodecs/images/gdal-io.jpg
similarity index 100%
rename from doc/tutorials/highgui/images/gdal-io.jpg
rename to doc/tutorials/imgcodecs/images/gdal-io.jpg
diff --git a/doc/tutorials/highgui/raster-gdal/images/gdal_flood-zone.jpg b/doc/tutorials/imgcodecs/raster-gdal/images/gdal_flood-zone.jpg
similarity index 100%
rename from doc/tutorials/highgui/raster-gdal/images/gdal_flood-zone.jpg
rename to doc/tutorials/imgcodecs/raster-gdal/images/gdal_flood-zone.jpg
diff --git a/doc/tutorials/highgui/raster-gdal/images/gdal_heat-map.jpg b/doc/tutorials/imgcodecs/raster-gdal/images/gdal_heat-map.jpg
similarity index 100%
rename from doc/tutorials/highgui/raster-gdal/images/gdal_heat-map.jpg
rename to doc/tutorials/imgcodecs/raster-gdal/images/gdal_heat-map.jpg
diff --git a/doc/tutorials/highgui/raster-gdal/images/gdal_output.jpg b/doc/tutorials/imgcodecs/raster-gdal/images/gdal_output.jpg
similarity index 100%
rename from doc/tutorials/highgui/raster-gdal/images/gdal_output.jpg
rename to doc/tutorials/imgcodecs/raster-gdal/images/gdal_output.jpg
diff --git a/doc/tutorials/imgcodecs/raster-gdal/raster_io_gdal.markdown b/doc/tutorials/imgcodecs/raster-gdal/raster_io_gdal.markdown
new file mode 100644
index 0000000..2193d26
--- /dev/null
+++ b/doc/tutorials/imgcodecs/raster-gdal/raster_io_gdal.markdown
@@ -0,0 +1,97 @@
+Reading Geospatial Raster files with GDAL {#tutorial_raster_io_gdal}
+=========================================
+
+Geospatial raster data is a heavily used product in Geographic Information Systems and
+Photogrammetry. Raster data typically can represent imagery and Digital Elevation Models (DEM). The
+standard library for loading GIS imagery is the Geographic Data Abstraction Library [(GDAL)](http://www.gdal.org). In this
+example, we will show techniques for loading GIS raster formats using native OpenCV functions. In
+addition, we will show some an example of how OpenCV can use this data for novel and interesting
+purposes.
+
+Goals
+-----
+
+The primary objectives for this tutorial:
+
+-   How to use OpenCV [imread](@ref imread) to load satellite imagery.
+-   How to use OpenCV [imread](@ref imread) to load SRTM Digital Elevation Models
+-   Given the corner coordinates of both the image and DEM, correllate the elevation data to the
+    image to find elevations for each pixel.
+-   Show a basic, easy-to-implement example of a terrain heat map.
+-   Show a basic use of DEM data coupled with ortho-rectified imagery.
+
+To implement these goals, the following code takes a Digital Elevation Model as well as a GeoTiff
+image of San Francisco as input. The image and DEM data is processed and generates a terrain heat
+map of the image as well as labels areas of the city which would be affected should the water level
+of the bay rise 10, 50, and 100 meters.
+
+Code
+----
+
+ at include cpp/tutorial_code/imgcodecs/GDAL_IO/gdal-image.cpp
+
+How to Read Raster Data using GDAL
+----------------------------------
+
+This demonstration uses the default OpenCV imread function. The primary difference is that in order
+to force GDAL to load the image, you must use the appropriate flag.
+ at snippet cpp/tutorial_code/imgcodecs/GDAL_IO/gdal-image.cpp load1
+When loading digital elevation models, the actual numeric value of each pixel is essential and
+cannot be scaled or truncated. For example, with image data a pixel represented as a double with a
+value of 1 has an equal appearance to a pixel which is represented as an unsigned character with a
+value of 255. With terrain data, the pixel value represents the elevation in meters. In order to
+ensure that OpenCV preserves the native value, use the GDAL flag in imread with the ANYDEPTH flag.
+ at snippet cpp/tutorial_code/imgcodecs/GDAL_IO/gdal-image.cpp load2
+If you know beforehand the type of DEM model you are loading, then it may be a safe bet to test the
+Mat::type() or Mat::depth() using an assert or other mechanism. NASA or DOD specification documents
+can provide the input types for various elevation models. The major types, SRTM and DTED, are both
+signed shorts.
+
+Notes
+-----
+
+### Lat/Lon (Geographic) Coordinates should normally be avoided
+
+The Geographic Coordinate System is a spherical coordinate system, meaning that using them with
+Cartesian mathematics is technically incorrect. This demo uses them to increase the readability and
+is accurate enough to make the point. A better coordinate system would be Universal Transverse
+Mercator.
+
+### Finding the corner coordinates
+
+One easy method to find the corner coordinates of an image is to use the command-line tool gdalinfo.
+For imagery which is ortho-rectified and contains the projection information, you can use the [USGS
+EarthExplorer](http://http://earthexplorer.usgs.gov).
+ at code{.bash}
+\f$> gdalinfo N37W123.hgt
+
+   Driver: SRTMHGT/SRTMHGT File Format
+   Files: N37W123.hgt
+   Size is 3601, 3601
+   Coordinate System is:
+   GEOGCS["WGS 84",
+   DATUM["WGS_1984",
+
+   ... more output ...
+
+   Corner Coordinates:
+   Upper Left  (-123.0001389,  38.0001389) (123d 0' 0.50"W, 38d 0' 0.50"N)
+   Lower Left  (-123.0001389,  36.9998611) (123d 0' 0.50"W, 36d59'59.50"N)
+   Upper Right (-121.9998611,  38.0001389) (121d59'59.50"W, 38d 0' 0.50"N)
+   Lower Right (-121.9998611,  36.9998611) (121d59'59.50"W, 36d59'59.50"N)
+   Center      (-122.5000000,  37.5000000) (122d30' 0.00"W, 37d30' 0.00"N)
+
+    ... more output ...
+ at endcode
+Results
+-------
+
+Below is the output of the program. Use the first image as the input. For the DEM model, download
+the SRTM file located at the USGS here.
+[<http://dds.cr.usgs.gov/srtm/version2_1/SRTM1/Region_04/N37W123.hgt.zip>](http://dds.cr.usgs.gov/srtm/version2_1/SRTM1/Region_04/N37W123.hgt.zip)
+
+![Input Image](images/gdal_output.jpg)
+
+![Heat Map](images/gdal_heat-map.jpg)
+
+![Heat Map Overlay](images/gdal_flood-zone.jpg)
diff --git a/doc/tutorials/imgcodecs/table_of_content_highgui.markdown b/doc/tutorials/imgcodecs/table_of_content_highgui.markdown
new file mode 100644
index 0000000..e78e827
--- /dev/null
+++ b/doc/tutorials/imgcodecs/table_of_content_highgui.markdown
@@ -0,0 +1,12 @@
+Image Input and Output (imgcodecs module) {#tutorial_table_of_content_imgcodecs}
+=========================================
+
+This section contains tutorials about how to read/save your image files.
+
+-   @subpage tutorial_raster_io_gdal
+
+    *Compatibility:* \> OpenCV 2.0
+
+    *Author:* Marvin Smith
+
+    Read common GIS Raster and DEM files to display and manipulate geographic data.
diff --git a/doc/tutorials/imgproc/erosion_dilatation/erosion_dilatation.markdown b/doc/tutorials/imgproc/erosion_dilatation/erosion_dilatation.markdown
index 831bba8..947bd6f 100644
--- a/doc/tutorials/imgproc/erosion_dilatation/erosion_dilatation.markdown
+++ b/doc/tutorials/imgproc/erosion_dilatation/erosion_dilatation.markdown
@@ -44,6 +44,14 @@ Morphological Operations
 
 The background (bright) dilates around the black regions of the letter.
 
+To better grasp the idea and avoid possible confusion, in this another example we have inverted the original
+image such as the object in white is now the letter. We have performed two dilatations with a rectangular
+structuring element of size `3x3`.
+
+![Left image: original image inverted, right image: resulting dilatation](images/Morphology_1_Tutorial_Theory_Dilatation_2.png)
+
+The dilatation makes the object in white bigger.
+
 ### Erosion
 
 -   This operation is the sister of dilation. What this does is to compute a local minimum over the
@@ -56,11 +64,18 @@ The background (bright) dilates around the black regions of the letter.
 
     ![](images/Morphology_1_Tutorial_Theory_Erosion.png)
 
+In the same manner, the corresponding image resulting of the erosion operation on the inverted original image (two erosions
+with a rectangular structuring element of size `3x3`):
+
+![Left image: original image inverted, right image: resulting erosion](images/Morphology_1_Tutorial_Theory_Erosion_2.png)
+
+The erosion makes the object in white smaller.
+
 Code
 ----
 
 This tutorial code's is shown lines below. You can also download it from
-[here](https://github.com/Itseez/opencv/tree/master/samples/cpp/tutorial_code/ImgProc/Morphology_1.cpp)
+[here](https://github.com/opencv/opencv/tree/master/samples/cpp/tutorial_code/ImgProc/Morphology_1.cpp)
 @include samples/cpp/tutorial_code/ImgProc/Morphology_1.cpp
 
 Explanation
@@ -71,7 +86,7 @@ Explanation
 
     -   Load an image (can be BGR or grayscale)
     -   Create two windows (one for dilation output, the other for erosion)
-    -   Create a set of 02 Trackbars for each operation:
+    -   Create a set of two Trackbars for each operation:
         -   The first trackbar "Element" returns either **erosion_elem** or **dilation_elem**
         -   The second trackbar "Kernel size" return **erosion_size** or **dilation_size** for the
             corresponding operation.
@@ -81,23 +96,8 @@ Explanation
     Let's analyze these two functions:
 
 -#  **erosion:**
-    @code{.cpp}
-    /*  @function Erosion  */
-    void Erosion( int, void* )
-    {
-      int erosion_type;
-      if( erosion_elem == 0 ){ erosion_type = MORPH_RECT; }
-      else if( erosion_elem == 1 ){ erosion_type = MORPH_CROSS; }
-      else if( erosion_elem == 2) { erosion_type = MORPH_ELLIPSE; }
-
-      Mat element = getStructuringElement( erosion_type,
-                               Size( 2*erosion_size + 1, 2*erosion_size+1 ),
-                           Point( erosion_size, erosion_size ) );
-      /// Apply the erosion operation
-      erode( src, erosion_dst, element );
-      imshow( "Erosion Demo", erosion_dst );
-    }
-    @endcode
+    @snippet cpp/tutorial_code/ImgProc/Morphology_1.cpp erosion
+
     -   The function that performs the *erosion* operation is @ref cv::erode . As we can see, it
         receives three arguments:
         -   *src*: The source image
@@ -105,11 +105,8 @@ Explanation
         -   *element*: This is the kernel we will use to perform the operation. If we do not
             specify, the default is a simple `3x3` matrix. Otherwise, we can specify its
             shape. For this, we need to use the function cv::getStructuringElement :
-            @code{.cpp}
-            Mat element = getStructuringElement( erosion_type,
-                                          Size( 2*erosion_size + 1, 2*erosion_size+1 ),
-                                          Point( erosion_size, erosion_size ) );
-            @endcode
+            @snippet cpp/tutorial_code/ImgProc/Morphology_1.cpp kernel
+
             We can choose any of three shapes for our kernel:
 
             -   Rectangular box: MORPH_RECT
@@ -129,23 +126,7 @@ Reference for more details.
     The code is below. As you can see, it is completely similar to the snippet of code for **erosion**.
     Here we also have the option of defining our kernel, its anchor point and the size of the operator
     to be used.
-    @code{.cpp}
-    /* @function Dilation */
-    void Dilation( int, void* )
-    {
-      int dilation_type;
-      if( dilation_elem == 0 ){ dilation_type = MORPH_RECT; }
-      else if( dilation_elem == 1 ){ dilation_type = MORPH_CROSS; }
-      else if( dilation_elem == 2) { dilation_type = MORPH_ELLIPSE; }
-
-      Mat element = getStructuringElement( dilation_type,
-                                           Size( 2*dilation_size + 1, 2*dilation_size+1 ),
-                           Point( dilation_size, dilation_size ) );
-      /// Apply the dilation operation
-      dilate( src, dilation_dst, element );
-      imshow( "Dilation Demo", dilation_dst );
-    }
-    @endcode
+    @snippet cpp/tutorial_code/ImgProc/Morphology_1.cpp dilation
 
 Results
 -------
diff --git a/doc/tutorials/imgproc/erosion_dilatation/images/Morphology_1_Tutorial_Theory_Dilatation_2.png b/doc/tutorials/imgproc/erosion_dilatation/images/Morphology_1_Tutorial_Theory_Dilatation_2.png
new file mode 100644
index 0000000..bdca7c6
Binary files /dev/null and b/doc/tutorials/imgproc/erosion_dilatation/images/Morphology_1_Tutorial_Theory_Dilatation_2.png differ
diff --git a/doc/tutorials/imgproc/erosion_dilatation/images/Morphology_1_Tutorial_Theory_Erosion_2.png b/doc/tutorials/imgproc/erosion_dilatation/images/Morphology_1_Tutorial_Theory_Erosion_2.png
new file mode 100644
index 0000000..5e666ee
Binary files /dev/null and b/doc/tutorials/imgproc/erosion_dilatation/images/Morphology_1_Tutorial_Theory_Erosion_2.png differ
diff --git a/doc/tutorials/imgproc/gausian_median_blur_bilateral_filter/gausian_median_blur_bilateral_filter.markdown b/doc/tutorials/imgproc/gausian_median_blur_bilateral_filter/gausian_median_blur_bilateral_filter.markdown
index 43753ca..753b368 100644
--- a/doc/tutorials/imgproc/gausian_median_blur_bilateral_filter/gausian_median_blur_bilateral_filter.markdown
+++ b/doc/tutorials/imgproc/gausian_median_blur_bilateral_filter/gausian_median_blur_bilateral_filter.markdown
@@ -16,8 +16,7 @@ Theory
 ------
 
 @note The explanation below belongs to the book [Computer Vision: Algorithms and
-Applications](http://szeliski.org/Book/) by Richard Szeliski and to *LearningOpenCV* .. container::
-enumeratevisibleitemswithsquare
+Applications](http://szeliski.org/Book/) by Richard Szeliski and to *LearningOpenCV*
 
 -   *Smoothing*, also called *blurring*, is a simple and frequently used image processing
     operation.
@@ -94,98 +93,9 @@ Code
     -   Applies 4 different kinds of filters (explained in Theory) and show the filtered images
         sequentially
 -   **Downloadable code**: Click
-    [here](https://github.com/Itseez/opencv/tree/master/samples/cpp/tutorial_code/ImgProc/Smoothing.cpp)
+    [here](https://github.com/opencv/opencv/tree/master/samples/cpp/tutorial_code/ImgProc/Smoothing.cpp)
 -   **Code at glance:**
- at code{.cpp}
-#include "opencv2/imgproc.hpp"
-#include "opencv2/highgui.hpp"
-
-using namespace std;
-using namespace cv;
-
-/// Global Variables
-int DELAY_CAPTION = 1500;
-int DELAY_BLUR = 100;
-int MAX_KERNEL_LENGTH = 31;
-
-Mat src; Mat dst;
-char window_name[] = "Filter Demo 1";
-
-/// Function headers
-int display_caption( char* caption );
-int display_dst( int delay );
-
-/*
- * function main
- */
- int main( int argc, char** argv )
- {
-   namedWindow( window_name, WINDOW_AUTOSIZE );
-
-   /// Load the source image
-   src = imread( "../images/lena.jpg", 1 );
-
-   if( display_caption( "Original Image" ) != 0 ) { return 0; }
-
-   dst = src.clone();
-   if( display_dst( DELAY_CAPTION ) != 0 ) { return 0; }
-
-   /// Applying Homogeneous blur
-   if( display_caption( "Homogeneous Blur" ) != 0 ) { return 0; }
-
-   for ( int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2 )
-       { blur( src, dst, Size( i, i ), Point(-1,-1) );
-         if( display_dst( DELAY_BLUR ) != 0 ) { return 0; } }
-
-    /// Applying Gaussian blur
-    if( display_caption( "Gaussian Blur" ) != 0 ) { return 0; }
-
-    for ( int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2 )
-        { GaussianBlur( src, dst, Size( i, i ), 0, 0 );
-          if( display_dst( DELAY_BLUR ) != 0 ) { return 0; } }
-
-     /// Applying Median blur
- if( display_caption( "Median Blur" ) != 0 ) { return 0; }
-
- for ( int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2 )
-         { medianBlur ( src, dst, i );
-           if( display_dst( DELAY_BLUR ) != 0 ) { return 0; } }
-
- /// Applying Bilateral Filter
- if( display_caption( "Bilateral Blur" ) != 0 ) { return 0; }
-
- for ( int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2 )
-         { bilateralFilter ( src, dst, i, i*2, i/2 );
-           if( display_dst( DELAY_BLUR ) != 0 ) { return 0; } }
-
- /// Wait until user press a key
- display_caption( "End: Press a key!" );
-
- waitKey(0);
- return 0;
- }
-
- int display_caption( char* caption )
- {
-   dst = Mat::zeros( src.size(), src.type() );
-   putText( dst, caption,
-            Point( src.cols/4, src.rows/2),
-            FONT_HERSHEY_COMPLEX, 1, Scalar(255, 255, 255) );
-
-   imshow( window_name, dst );
-   int c = waitKey( DELAY_CAPTION );
-   if( c >= 0 ) { return -1; }
-   return 0;
-  }
-
-  int display_dst( int delay )
-  {
-    imshow( window_name, dst );
-    int c = waitKey ( delay );
-    if( c >= 0 ) { return -1; }
-    return 0;
-  }
- at endcode
+    @include samples/cpp/tutorial_code/ImgProc/Smoothing.cpp
 
 Explanation
 -----------
@@ -195,11 +105,8 @@ Explanation
 -#  **Normalized Block Filter:**
 
     OpenCV offers the function @ref cv::blur to perform smoothing with this filter.
-    @code{.cpp}
-    for ( int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2 )
-        { blur( src, dst, Size( i, i ), Point(-1,-1) );
-          if( display_dst( DELAY_BLUR ) != 0 ) { return 0; } }
-    @endcode
+    @snippet cpp/tutorial_code/ImgProc/Smoothing.cpp blur
+
     We specify 4 arguments (more details, check the Reference):
 
     -   *src*: Source image
@@ -213,11 +120,8 @@ Explanation
 -#  **Gaussian Filter:**
 
     It is performed by the function @ref cv::GaussianBlur :
-    @code{.cpp}
-    for ( int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2 )
-        { GaussianBlur( src, dst, Size( i, i ), 0, 0 );
-          if( display_dst( DELAY_BLUR ) != 0 ) { return 0; } }
-    @endcode
+    @snippet cpp/tutorial_code/ImgProc/Smoothing.cpp gaussianblur
+
     Here we use 4 arguments (more details, check the OpenCV reference):
 
     -   *src*: Source image
@@ -233,11 +137,8 @@ Explanation
 -#  **Median Filter:**
 
     This filter is provided by the @ref cv::medianBlur function:
-    @code{.cpp}
-    for ( int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2 )
-        { medianBlur ( src, dst, i );
-          if( display_dst( DELAY_BLUR ) != 0 ) { return 0; } }
-    @endcode
+    @snippet cpp/tutorial_code/ImgProc/Smoothing.cpp medianblur
+
     We use three arguments:
 
     -   *src*: Source image
@@ -247,11 +148,8 @@ Explanation
 -#  **Bilateral Filter**
 
     Provided by OpenCV function @ref cv::bilateralFilter
-    @code{.cpp}
-    for ( int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2 )
-        { bilateralFilter ( src, dst, i, i*2, i/2 );
-          if( display_dst( DELAY_BLUR ) != 0 ) { return 0; } }
-    @endcode
+    @snippet cpp/tutorial_code/ImgProc/Smoothing.cpp bilateralfilter
+
     We use 5 arguments:
 
     -   *src*: Source image
diff --git a/doc/tutorials/imgproc/histograms/back_projection/back_projection.markdown b/doc/tutorials/imgproc/histograms/back_projection/back_projection.markdown
index fa4ff72..8657541 100644
--- a/doc/tutorials/imgproc/histograms/back_projection/back_projection.markdown
+++ b/doc/tutorials/imgproc/histograms/back_projection/back_projection.markdown
@@ -70,13 +70,13 @@ Code
 -   **Downloadable code**:
 
     -#  Click
-        [here](https://github.com/Itseez/opencv/tree/master/samples/cpp/tutorial_code/Histograms_Matching/calcBackProject_Demo1.cpp)
+        [here](https://github.com/opencv/opencv/tree/master/samples/cpp/tutorial_code/Histograms_Matching/calcBackProject_Demo1.cpp)
         for the basic version (explained in this tutorial).
     -#  For stuff slightly fancier (using H-S histograms and floodFill to define a mask for the
         skin area) you can check the [improved
-        demo](https://github.com/Itseez/opencv/tree/master/samples/cpp/tutorial_code/Histograms_Matching/calcBackProject_Demo2.cpp)
+        demo](https://github.com/opencv/opencv/tree/master/samples/cpp/tutorial_code/Histograms_Matching/calcBackProject_Demo2.cpp)
     -#  ...or you can always check out the classical
-        [camshiftdemo](https://github.com/Itseez/opencv/tree/master/samples/cpp/camshiftdemo.cpp)
+        [camshiftdemo](https://github.com/opencv/opencv/tree/master/samples/cpp/camshiftdemo.cpp)
         in samples.
 
 -   **Code at glance:**
diff --git a/doc/tutorials/imgproc/histograms/histogram_calculation/histogram_calculation.markdown b/doc/tutorials/imgproc/histograms/histogram_calculation/histogram_calculation.markdown
index a966d90..2907bf3 100644
--- a/doc/tutorials/imgproc/histograms/histogram_calculation/histogram_calculation.markdown
+++ b/doc/tutorials/imgproc/histograms/histogram_calculation/histogram_calculation.markdown
@@ -66,7 +66,7 @@ Code
     -   Calculate the Histogram of each 1-channel plane by calling the function @ref cv::calcHist
     -   Plot the three histograms in a window
 -   **Downloadable code**: Click
-    [here](https://github.com/Itseez/opencv/tree/master/samples/cpp/tutorial_code/Histograms_Matching/calcHist_Demo.cpp)
+    [here](https://github.com/opencv/opencv/tree/master/samples/cpp/tutorial_code/Histograms_Matching/calcHist_Demo.cpp)
 -   **Code at glance:**
     @include samples/cpp/tutorial_code/Histograms_Matching/calcHist_Demo.cpp
 
diff --git a/doc/tutorials/imgproc/histograms/histogram_comparison/histogram_comparison.markdown b/doc/tutorials/imgproc/histograms/histogram_comparison/histogram_comparison.markdown
index 8b7399f..37ae5ea 100644
--- a/doc/tutorials/imgproc/histograms/histogram_comparison/histogram_comparison.markdown
+++ b/doc/tutorials/imgproc/histograms/histogram_comparison/histogram_comparison.markdown
@@ -44,7 +44,7 @@ Code
         histogram of the lower half base image and with the same base image histogram.
     -   Display the numerical matching parameters obtained.
 -   **Downloadable code**: Click
-    [here](https://github.com/Itseez/opencv/tree/master/samples/cpp/tutorial_code/Histograms_Matching/compareHist_Demo.cpp)
+    [here](https://github.com/opencv/opencv/tree/master/samples/cpp/tutorial_code/Histograms_Matching/compareHist_Demo.cpp)
 -   **Code at glance:**
 
 @include cpp/tutorial_code/Histograms_Matching/compareHist_Demo.cpp
diff --git a/doc/tutorials/imgproc/histograms/histogram_equalization/histogram_equalization.markdown b/doc/tutorials/imgproc/histograms/histogram_equalization/histogram_equalization.markdown
index f3a2746..2d803cc 100644
--- a/doc/tutorials/imgproc/histograms/histogram_equalization/histogram_equalization.markdown
+++ b/doc/tutorials/imgproc/histograms/histogram_equalization/histogram_equalization.markdown
@@ -62,7 +62,7 @@ Code
     -   Equalize the Histogram by using the OpenCV function @ref cv::equalizeHist
     -   Display the source and equalized images in a window.
 -   **Downloadable code**: Click
-    [here](https://github.com/Itseez/opencv/tree/master/samples/cpp/tutorial_code/Histograms_Matching/EqualizeHist_Demo.cpp)
+    [here](https://github.com/opencv/opencv/tree/master/samples/cpp/tutorial_code/Histograms_Matching/EqualizeHist_Demo.cpp)
 -   **Code at glance:**
     @include samples/cpp/tutorial_code/Histograms_Matching/EqualizeHist_Demo.cpp
 
diff --git a/doc/tutorials/imgproc/histograms/template_matching/images/Template_Matching_Mask_Example.jpg b/doc/tutorials/imgproc/histograms/template_matching/images/Template_Matching_Mask_Example.jpg
new file mode 100644
index 0000000..711faec
Binary files /dev/null and b/doc/tutorials/imgproc/histograms/template_matching/images/Template_Matching_Mask_Example.jpg differ
diff --git a/doc/tutorials/imgproc/histograms/template_matching/template_matching.markdown b/doc/tutorials/imgproc/histograms/template_matching/template_matching.markdown
index c39fd15..1dc3ca8 100644
--- a/doc/tutorials/imgproc/histograms/template_matching/template_matching.markdown
+++ b/doc/tutorials/imgproc/histograms/template_matching/template_matching.markdown
@@ -19,6 +19,10 @@ Theory
 Template matching is a technique for finding areas of an image that match (are similar) to a
 template image (patch).
 
+While the patch must be a rectangle it may be that not all of the
+rectangle is relevant.  In such a case, a mask can be used to isolate the portion of the patch
+that should be used to find the match.
+
 ### How does it work?
 
 -   We need two primary components:
@@ -51,6 +55,30 @@ template image (patch).
 -   In practice, we use the function @ref cv::minMaxLoc to locate the highest value (or lower,
     depending of the type of matching method) in the *R* matrix.
 
+### How does the mask work?
+- If masking is needed for the match, three components are required:
+
+    -#  **Source image (I):** The image in which we expect to find a match to the template image
+    -#  **Template image (T):** The patch image which will be compared to the template image
+    -#  **Mask image (M):** The mask, a grayscale image that masks the template
+
+
+-   Only two matching methods currently accept a mask: CV_TM_SQDIFF and CV_TM_CCORR_NORMED (see
+    below for explanation of all the matching methods available in opencv).
+
+
+-   The mask must have the same dimensions as the template
+
+
+-   The mask should have a CV_8U or CV_32F depth and the same number of channels
+    as the template image. In CV_8U case, the mask values are treated as binary,
+    i.e. zero and non-zero. In CV_32F case, the values should fall into [0..1]
+    range and the template pixels will be multiplied by the corresponding mask pixel
+    values. Since the input images in the sample have the CV_8UC3 type, the mask
+    is also read as color image.
+
+    ![](images/Template_Matching_Mask_Example.jpg)
+
 ### Which are the matching methods available in OpenCV?
 
 Good question. OpenCV implements Template matching in the function @ref cv::matchTemplate . The
@@ -88,15 +116,16 @@ Code
 ----
 
 -   **What does this program do?**
-    -   Loads an input image and a image patch (*template*)
+    -   Loads an input image, an image patch (*template*), and optionally a mask
     -   Perform a template matching procedure by using the OpenCV function @ref cv::matchTemplate
         with any of the 6 matching methods described before. The user can choose the method by
-        entering its selection in the Trackbar.
+        entering its selection in the Trackbar.  If a mask is supplied, it will only be used for
+        the methods that support masking
     -   Normalize the output of the matching procedure
     -   Localize the location with higher matching probability
     -   Draw a rectangle around the area corresponding to the highest match
 -   **Downloadable code**: Click
-    [here](https://github.com/Itseez/opencv/tree/master/samples/cpp/tutorial_code/Histograms_Matching/MatchTemplate_Demo.cpp)
+    [here](https://github.com/opencv/opencv/tree/master/samples/cpp/tutorial_code/Histograms_Matching/MatchTemplate_Demo.cpp)
 -   **Code at glance:**
     @include samples/cpp/tutorial_code/Histograms_Matching/MatchTemplate_Demo.cpp
 
@@ -113,10 +142,14 @@ Explanation
     int match_method;
     int max_Trackbar = 5;
     @endcode
--#  Load the source image and template:
+-#  Load the source image, template, and optionally, if supported for the matching method, a mask:
     @code{.cpp}
-    img = imread( argv[1], 1 );
-    templ = imread( argv[2], 1 );
+     bool method_accepts_mask = (CV_TM_SQDIFF == match_method || match_method == CV_TM_CCORR_NORMED);
+  if (use_mask && method_accepts_mask)
+    { matchTemplate( img, templ, result, match_method, mask); }
+  else
+    { matchTemplate( img, templ, result, match_method); }
+
     @endcode
 -#  Create the windows to show the results:
     @code{.cpp}
@@ -150,10 +183,14 @@ Explanation
     @endcode
 -#  Perform the template matching operation:
     @code{.cpp}
-    matchTemplate( img, templ, result, match_method );
+    bool method_accepts_mask = (CV_TM_SQDIFF == match_method || match_method == CV_TM_CCORR_NORMED);
+    if (use_mask && method_accepts_mask)
+        { matchTemplate( img, templ, result, match_method, mask); }
+    else
+        { matchTemplate( img, templ, result, match_method); }
     @endcode
-    the arguments are naturally the input image **I**, the template **T**, the result **R** and the
-    match_method (given by the Trackbar)
+    the arguments are naturally the input image **I**, the template **T**, the result **R**, the
+    match_method (given by the Trackbar), and optionally the mask image **M**
 
 -#  We normalize the results:
     @code{.cpp}
diff --git a/doc/tutorials/imgproc/imgtrans/canny_detector/canny_detector.markdown b/doc/tutorials/imgproc/imgtrans/canny_detector/canny_detector.markdown
index aa61992..f9f2a2a 100644
--- a/doc/tutorials/imgproc/imgtrans/canny_detector/canny_detector.markdown
+++ b/doc/tutorials/imgproc/imgtrans/canny_detector/canny_detector.markdown
@@ -12,7 +12,7 @@ Theory
 ------
 
 The *Canny Edge detector* was developed by John F. Canny in 1986. Also known to many as the
-*optimal detector*, Canny algorithm aims to satisfy three main criteria:
+*optimal detector*, the Canny algorithm aims to satisfy three main criteria:
 -   **Low error rate:** Meaning a good detection of only existent edges.
 -   **Good localization:** The distance between edge pixels detected and real edge pixels have
     to be minimized.
@@ -74,24 +74,15 @@ Code
     -   Applies the mask obtained on the original image and display it in a window.
 
 -#  The tutorial code's is shown lines below. You can also download it from
-    [here](https://github.com/Itseez/opencv/tree/master/samples/cpp/tutorial_code/ImgTrans/CannyDetector_Demo.cpp)
+    [here](https://github.com/opencv/opencv/tree/master/samples/cpp/tutorial_code/ImgTrans/CannyDetector_Demo.cpp)
     @include samples/cpp/tutorial_code/ImgTrans/CannyDetector_Demo.cpp
 
 Explanation
 -----------
 
 -#  Create some needed variables:
-    @code{.cpp}
-    Mat src, src_gray;
-    Mat dst, detected_edges;
-
-    int edgeThresh = 1;
-    int lowThreshold;
-    int const max_lowThreshold = 100;
-    int ratio = 3;
-    int kernel_size = 3;
-    char* window_name = "Edge Map";
-    @endcode
+    @snippet cpp/tutorial_code/ImgTrans/CannyDetector_Demo.cpp variables
+
     Note the following:
 
     -#  We establish a ratio of lower:upper threshold of 3:1 (with the variable *ratio*)
@@ -100,29 +91,16 @@ Explanation
     -#  We set a maximum value for the lower Threshold of \f$100\f$.
 
 -#  Loads the source image:
-    @code{.cpp}
-    /// Load an image
-    src = imread( argv[1] );
+    @snippet cpp/tutorial_code/ImgTrans/CannyDetector_Demo.cpp load
 
-    if( !src.data )
-      { return -1; }
-    @endcode
 -#  Create a matrix of the same type and size of *src* (to be *dst*)
-    @code{.cpp}
-    dst.create( src.size(), src.type() );
-    @endcode
+    @snippet cpp/tutorial_code/ImgTrans/CannyDetector_Demo.cpp create_mat
 -#  Convert the image to grayscale (using the function @ref cv::cvtColor :
-    @code{.cpp}
-    cvtColor( src, src_gray, COLOR_BGR2GRAY );
-    @endcode
+    @snippet cpp/tutorial_code/ImgTrans/CannyDetector_Demo.cpp convert_to_gray
 -#  Create a window to display the results
-    @code{.cpp}
-    namedWindow( window_name, WINDOW_AUTOSIZE );
-    @endcode
+    @snippet cpp/tutorial_code/ImgTrans/CannyDetector_Demo.cpp create_window
 -#  Create a Trackbar for the user to enter the lower threshold for our Canny detector:
-    @code{.cpp}
-    createTrackbar( "Min Threshold:", window_name, &lowThreshold, max_lowThreshold, CannyThreshold );
-    @endcode
+    @snippet cpp/tutorial_code/ImgTrans/CannyDetector_Demo.cpp create_trackbar
     Observe the following:
 
     -#  The variable to be controlled by the Trackbar is *lowThreshold* with a limit of
@@ -132,13 +110,9 @@ Explanation
 
 -#  Let's check the *CannyThreshold* function, step by step:
     -#  First, we blur the image with a filter of kernel size 3:
-        @code{.cpp}
-        blur( src_gray, detected_edges, Size(3,3) );
-        @endcode
+        @snippet cpp/tutorial_code/ImgTrans/CannyDetector_Demo.cpp reduce_noise
     -#  Second, we apply the OpenCV function @ref cv::Canny :
-        @code{.cpp}
-        Canny( detected_edges, detected_edges, lowThreshold, lowThreshold*ratio, kernel_size );
-        @endcode
+        @snippet cpp/tutorial_code/ImgTrans/CannyDetector_Demo.cpp canny
         where the arguments are:
 
         -   *detected_edges*: Source image, grayscale
@@ -150,23 +124,16 @@ Explanation
             internally)
 
 -#  We fill a *dst* image with zeros (meaning the image is completely black).
-    @code{.cpp}
-    dst = Scalar::all(0);
-    @endcode
+    @snippet cpp/tutorial_code/ImgTrans/CannyDetector_Demo.cpp fill
 -#  Finally, we will use the function @ref cv::Mat::copyTo to map only the areas of the image that are
     identified as edges (on a black background).
-    @code{.cpp}
-    src.copyTo( dst, detected_edges);
-    @endcode
     @ref cv::Mat::copyTo copy the *src* image onto *dst*. However, it will only copy the pixels in the
     locations where they have non-zero values. Since the output of the Canny detector is the edge
     contours on a black background, the resulting *dst* will be black in all the area but the
     detected edges.
-
+    @snippet cpp/tutorial_code/ImgTrans/CannyDetector_Demo.cpp copyto
 -#  We display our result:
-    @code{.cpp}
-    imshow( window_name, dst );
-    @endcode
+    @snippet cpp/tutorial_code/ImgTrans/CannyDetector_Demo.cpp display
 
 Result
 ------
diff --git a/doc/tutorials/imgproc/imgtrans/copyMakeBorder/copyMakeBorder.markdown b/doc/tutorials/imgproc/imgtrans/copyMakeBorder/copyMakeBorder.markdown
index d6cf3df..6b6efdf 100644
--- a/doc/tutorials/imgproc/imgtrans/copyMakeBorder/copyMakeBorder.markdown
+++ b/doc/tutorials/imgproc/imgtrans/copyMakeBorder/copyMakeBorder.markdown
@@ -46,68 +46,36 @@ Code
     -   The program finishes when the user presses 'ESC'
 
 -#  The tutorial code's is shown lines below. You can also download it from
-    [here](https://github.com/Itseez/opencv/tree/master/samples/cpp/tutorial_code/ImgTrans/copyMakeBorder_demo.cpp)
+    [here](https://github.com/opencv/opencv/tree/master/samples/cpp/tutorial_code/ImgTrans/copyMakeBorder_demo.cpp)
     @include samples/cpp/tutorial_code/ImgTrans/copyMakeBorder_demo.cpp
 
 Explanation
 -----------
 
 -#  First we declare the variables we are going to use:
-    @code{.cpp}
-    Mat src, dst;
-    int top, bottom, left, right;
-    int borderType;
-    Scalar value;
-    char* window_name = "copyMakeBorder Demo";
-    RNG rng(12345);
-    @endcode
+    @snippet cpp/tutorial_code/ImgTrans/copyMakeBorder_demo.cpp variables
+
     Especial attention deserves the variable *rng* which is a random number generator. We use it to
     generate the random border color, as we will see soon.
 
 -#  As usual we load our source image *src*:
-    @code{.cpp}
-    src = imread( argv[1] );
-
-    if( !src.data )
-    { return -1;
-      printf(" No data entered, please enter the path to an image file \n");
-    }
-    @endcode
+    @snippet cpp/tutorial_code/ImgTrans/copyMakeBorder_demo.cpp load
+
 -#  After giving a short intro of how to use the program, we create a window:
-    @code{.cpp}
-    namedWindow( window_name, WINDOW_AUTOSIZE );
-    @endcode
+    @snippet cpp/tutorial_code/ImgTrans/copyMakeBorder_demo.cpp create_window
 -#  Now we initialize the argument that defines the size of the borders (*top*, *bottom*, *left* and
     *right*). We give them a value of 5% the size of *src*.
-    @code{.cpp}
-    top = (int) (0.05*src.rows); bottom = (int) (0.05*src.rows);
-    left = (int) (0.05*src.cols); right = (int) (0.05*src.cols);
-    @endcode
--#  The program begins a *while* loop. If the user presses 'c' or 'r', the *borderType* variable
+    @snippet cpp/tutorial_code/ImgTrans/copyMakeBorder_demo.cpp init_arguments
+-#  The program runs in a **for** loop. If the user presses 'c' or 'r', the *borderType* variable
     takes the value of *BORDER_CONSTANT* or *BORDER_REPLICATE* respectively:
-    @code{.cpp}
-    while( true )
-     {
-       c = waitKey(500);
-
-       if( (char)c == 27 )
-         { break; }
-       else if( (char)c == 'c' )
-         { borderType = BORDER_CONSTANT; }
-       else if( (char)c == 'r' )
-         { borderType = BORDER_REPLICATE; }
-    @endcode
+    @snippet cpp/tutorial_code/ImgTrans/copyMakeBorder_demo.cpp check_keypress
 -#  In each iteration (after 0.5 seconds), the variable *value* is updated...
-    @code{.cpp}
-    value = Scalar( rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255) );
-    @endcode
+    @snippet cpp/tutorial_code/ImgTrans/copyMakeBorder_demo.cpp update_value
     with a random value generated by the **RNG** variable *rng*. This value is a number picked
     randomly in the range \f$[0,255]\f$
 
 -#  Finally, we call the function @ref cv::copyMakeBorder to apply the respective padding:
-    @code{.cpp}
-    copyMakeBorder( src, dst, top, bottom, left, right, borderType, value );
-    @endcode
+    @snippet cpp/tutorial_code/ImgTrans/copyMakeBorder_demo.cpp copymakeborder
     The arguments are:
 
     -#  *src*: Source image
@@ -120,9 +88,7 @@ Explanation
         pixels.
 
 -#  We display our output image in the image created previously
-    @code{.cpp}
-    imshow( window_name, dst );
-    @endcode
+    @snippet cpp/tutorial_code/ImgTrans/copyMakeBorder_demo.cpp display
 
 Results
 -------
diff --git a/doc/tutorials/imgproc/imgtrans/distance_transformation/distance_transform.markdown b/doc/tutorials/imgproc/imgtrans/distance_transformation/distance_transform.markdown
index 1e49982..0ba6b71 100644
--- a/doc/tutorials/imgproc/imgtrans/distance_transformation/distance_transform.markdown
+++ b/doc/tutorials/imgproc/imgtrans/distance_transformation/distance_transform.markdown
@@ -17,7 +17,7 @@ Code
 ----
 
 This tutorial code's is shown lines below. You can also download it from
-    [here](https://github.com/Itseez/opencv/tree/master/samples/cpp/tutorial_code/ImgTrans/imageSegmentation.cpp).
+    [here](https://github.com/opencv/opencv/tree/master/samples/cpp/tutorial_code/ImgTrans/imageSegmentation.cpp).
 @include samples/cpp/tutorial_code/ImgTrans/imageSegmentation.cpp
 
 Explanation / Result
diff --git a/doc/tutorials/imgproc/imgtrans/filter_2d/filter_2d.markdown b/doc/tutorials/imgproc/imgtrans/filter_2d/filter_2d.markdown
index 079bbed..a091464 100644
--- a/doc/tutorials/imgproc/imgtrans/filter_2d/filter_2d.markdown
+++ b/doc/tutorials/imgproc/imgtrans/filter_2d/filter_2d.markdown
@@ -62,101 +62,26 @@ Code
     -   The filter output (with each kernel) will be shown during 500 milliseconds
 
 -#  The tutorial code's is shown lines below. You can also download it from
-    [here](https://github.com/Itseez/opencv/tree/master/samples/cpp/tutorial_code/ImgTrans/filter2D_demo.cpp)
- at code{.cpp}
-#include "opencv2/imgproc.hpp"
-#include "opencv2/highgui.hpp"
-#include <stdlib.h>
-#include <stdio.h>
-
-using namespace cv;
-
-/* @function main */
-int main ( int argc, char** argv )
-{
-  /// Declare variables
-  Mat src, dst;
-
-  Mat kernel;
-  Point anchor;
-  double delta;
-  int ddepth;
-  int kernel_size;
-  char* window_name = "filter2D Demo";
-
-  int c;
-
-  /// Load an image
-  src = imread( argv[1] );
-
-  if( !src.data )
-  { return -1; }
-
-  /// Create window
-  namedWindow( window_name, WINDOW_AUTOSIZE );
-
-  /// Initialize arguments for the filter
-  anchor = Point( -1, -1 );
-  delta = 0;
-  ddepth = -1;
-
-  /// Loop - Will filter the image with different kernel sizes each 0.5 seconds
-  int ind = 0;
-  while( true )
-    {
-      c = waitKey(500);
-      /// Press 'ESC' to exit the program
-      if( (char)c == 27 )
-        { break; }
-
-      /// Update kernel size for a normalized box filter
-      kernel_size = 3 + 2*( ind%5 );
-      kernel = Mat::ones( kernel_size, kernel_size, CV_32F )/ (float)(kernel_size*kernel_size);
-
-      /// Apply filter
-      filter2D(src, dst, ddepth , kernel, anchor, delta, BORDER_DEFAULT );
-      imshow( window_name, dst );
-      ind++;
-    }
-
-  return 0;
-}
- at endcode
+    [here](https://github.com/opencv/opencv/tree/master/samples/cpp/tutorial_code/ImgTrans/filter2D_demo.cpp)
+    @include cpp/tutorial_code/ImgTrans/filter2D_demo.cpp
+
 Explanation
 -----------
 
 -#  Load an image
-    @code{.cpp}
-    src = imread( argv[1] );
-
-    if( !src.data )
-      { return -1; }
-    @endcode
--#  Create a window to display the result
-    @code{.cpp}
-    namedWindow( window_name, WINDOW_AUTOSIZE );
-    @endcode
+    @snippet cpp/tutorial_code/ImgTrans/filter2D_demo.cpp load
 -#  Initialize the arguments for the linear filter
-    @code{.cpp}
-    anchor = Point( -1, -1 );
-    delta = 0;
-    ddepth = -1;
-    @endcode
+    @snippet cpp/tutorial_code/ImgTrans/filter2D_demo.cpp init_arguments
 -#  Perform an infinite loop updating the kernel size and applying our linear filter to the input
     image. Let's analyze that more in detail:
 -#  First we define the kernel our filter is going to use. Here it is:
-    @code{.cpp}
-    kernel_size = 3 + 2*( ind%5 );
-    kernel = Mat::ones( kernel_size, kernel_size, CV_32F )/ (float)(kernel_size*kernel_size);
-    @endcode
+    @snippet cpp/tutorial_code/ImgTrans/filter2D_demo.cpp update_kernel
     The first line is to update the *kernel_size* to odd values in the range: \f$[3,11]\f$. The second
     line actually builds the kernel by setting its value to a matrix filled with \f$1's\f$ and
     normalizing it by dividing it between the number of elements.
 
 -#  After setting the kernel, we can generate the filter by using the function @ref cv::filter2D :
-    @code{.cpp}
-    filter2D(src, dst, ddepth , kernel, anchor, delta, BORDER_DEFAULT );
-    @endcode
+    @snippet cpp/tutorial_code/ImgTrans/filter2D_demo.cpp apply_filter
     The arguments denote:
 
     -#  *src*: Source image
diff --git a/doc/tutorials/imgproc/imgtrans/hough_circle/hough_circle.markdown b/doc/tutorials/imgproc/imgtrans/hough_circle/hough_circle.markdown
index e796c05..9f39519 100644
--- a/doc/tutorials/imgproc/imgtrans/hough_circle/hough_circle.markdown
+++ b/doc/tutorials/imgproc/imgtrans/hough_circle/hough_circle.markdown
@@ -39,72 +39,42 @@ Code
     -   Applies the *Hough Circle Transform* to the blurred image .
     -   Display the detected circle in a window.
 
--#  The sample code that we will explain can be downloaded from [here](https://github.com/Itseez/opencv/tree/master/samples/cpp/houghcircles.cpp).
+-#  The sample code that we will explain can be downloaded from [here](https://github.com/opencv/opencv/tree/master/samples/cpp/houghcircles.cpp).
     A slightly fancier version (which shows trackbars for
-    changing the threshold values) can be found [here](https://github.com/Itseez/opencv/tree/master/samples/cpp/tutorial_code/ImgTrans/HoughCircle_Demo.cpp).
+    changing the threshold values) can be found [here](https://github.com/opencv/opencv/tree/master/samples/cpp/tutorial_code/ImgTrans/HoughCircle_Demo.cpp).
     @include samples/cpp/houghcircles.cpp
 
 Explanation
 -----------
 
 -#  Load an image
-    @code{.cpp}
-    src = imread( argv[1], 1 );
-
-    if( !src.data )
-      { return -1; }
-    @endcode
+    @snippet samples/cpp/houghcircles.cpp load
 -#  Convert it to grayscale:
-    @code{.cpp}
-    cvtColor( src, src_gray, COLOR_BGR2GRAY );
-    @endcode
--#  Apply a Gaussian blur to reduce noise and avoid false circle detection:
-    @code{.cpp}
-    GaussianBlur( src_gray, src_gray, Size(9, 9), 2, 2 );
-    @endcode
+    @snippet samples/cpp/houghcircles.cpp convert_to_gray
+-#  Apply a Median blur to reduce noise and avoid false circle detection:
+    @snippet samples/cpp/houghcircles.cpp reduce_noise
 -#  Proceed to apply Hough Circle Transform:
-    @code{.cpp}
-    vector<Vec3f> circles;
-
-    HoughCircles( src_gray, circles, HOUGH_GRADIENT, 1, src_gray.rows/8, 200, 100, 0, 0 );
-    @endcode
+    @snippet samples/cpp/houghcircles.cpp houghcircles
     with the arguments:
 
-    -   *src_gray*: Input image (grayscale).
+    -   *gray*: Input image (grayscale).
     -   *circles*: A vector that stores sets of 3 values: \f$x_{c}, y_{c}, r\f$ for each detected
         circle.
     -   *HOUGH_GRADIENT*: Define the detection method. Currently this is the only one available in
         OpenCV.
     -   *dp = 1*: The inverse ratio of resolution.
-    -   *min_dist = src_gray.rows/8*: Minimum distance between detected centers.
+    -   *min_dist = gray.rows/16*: Minimum distance between detected centers.
     -   *param_1 = 200*: Upper threshold for the internal Canny edge detector.
     -   *param_2* = 100\*: Threshold for center detection.
     -   *min_radius = 0*: Minimum radio to be detected. If unknown, put zero as default.
     -   *max_radius = 0*: Maximum radius to be detected. If unknown, put zero as default.
 
 -#  Draw the detected circles:
-    @code{.cpp}
-    for( size_t i = 0; i < circles.size(); i++ )
-    {
-       Point center(cvRound(circles[i][0]), cvRound(circles[i][1]));
-       int radius = cvRound(circles[i][2]);
-       // circle center
-       circle( src, center, 3, Scalar(0,255,0), -1, 8, 0 );
-       // circle outline
-       circle( src, center, radius, Scalar(0,0,255), 3, 8, 0 );
-     }
-    @endcode
+    @snippet samples/cpp/houghcircles.cpp draw
     You can see that we will draw the circle(s) on red and the center(s) with a small green dot
 
--#  Display the detected circle(s):
-    @code{.cpp}
-    namedWindow( "Hough Circle Transform Demo", WINDOW_AUTOSIZE );
-    imshow( "Hough Circle Transform Demo", src );
-    @endcode
--#  Wait for the user to exit the program
-    @code{.cpp}
-    waitKey(0);
-    @endcode
+-#  Display the detected circle(s) and wait for the user to exit the program:
+    @snippet samples/cpp/houghcircles.cpp display
 
 Result
 ------
diff --git a/doc/tutorials/imgproc/imgtrans/hough_lines/hough_lines.markdown b/doc/tutorials/imgproc/imgtrans/hough_lines/hough_lines.markdown
index 8de6629..584c3f8 100644
--- a/doc/tutorials/imgproc/imgtrans/hough_lines/hough_lines.markdown
+++ b/doc/tutorials/imgproc/imgtrans/hough_lines/hough_lines.markdown
@@ -95,9 +95,9 @@ Code
     -   Applies either a *Standard Hough Line Transform* or a *Probabilistic Line Transform*.
     -   Display the original image and the detected line in two windows.
 
--#  The sample code that we will explain can be downloaded from [here](https://github.com/Itseez/opencv/tree/master/samples/cpp/houghlines.cpp). A slightly fancier version
+-#  The sample code that we will explain can be downloaded from [here](https://github.com/opencv/opencv/tree/master/samples/cpp/houghlines.cpp). A slightly fancier version
     (which shows both Hough standard and probabilistic with trackbars for changing the threshold
-    values) can be found [here](https://github.com/Itseez/opencv/tree/master/samples/cpp/tutorial_code/ImgTrans/HoughLines_Demo.cpp).
+    values) can be found [here](https://github.com/opencv/opencv/tree/master/samples/cpp/tutorial_code/ImgTrans/HoughLines_Demo.cpp).
     @include samples/cpp/houghlines.cpp
 
 Explanation
diff --git a/doc/tutorials/imgproc/imgtrans/laplace_operator/laplace_operator.markdown b/doc/tutorials/imgproc/imgtrans/laplace_operator/laplace_operator.markdown
index 104c244..f178170 100644
--- a/doc/tutorials/imgproc/imgtrans/laplace_operator/laplace_operator.markdown
+++ b/doc/tutorials/imgproc/imgtrans/laplace_operator/laplace_operator.markdown
@@ -51,40 +51,22 @@ Code
     -   Display the result in a window
 
 -#  The tutorial code's is shown lines below. You can also download it from
-    [here](https://github.com/Itseez/opencv/tree/master/samples/cpp/tutorial_code/ImgTrans/Laplace_Demo.cpp)
+    [here](https://github.com/opencv/opencv/tree/master/samples/cpp/tutorial_code/ImgTrans/Laplace_Demo.cpp)
     @include samples/cpp/tutorial_code/ImgTrans/Laplace_Demo.cpp
 
 Explanation
 -----------
 
 -#  Create some needed variables:
-    @code{.cpp}
-    Mat src, src_gray, dst;
-    int kernel_size = 3;
-    int scale = 1;
-    int delta = 0;
-    int ddepth = CV_16S;
-    char* window_name = "Laplace Demo";
-    @endcode
+    @snippet cpp/tutorial_code/ImgTrans/Laplace_Demo.cpp variables
 -#  Loads the source image:
-    @code{.cpp}
-    src = imread( argv[1] );
-
-    if( !src.data )
-      { return -1; }
-    @endcode
+    @snippet cpp/tutorial_code/ImgTrans/Laplace_Demo.cpp load
 -#  Apply a Gaussian blur to reduce noise:
-    @code{.cpp}
-    GaussianBlur( src, src, Size(3,3), 0, 0, BORDER_DEFAULT );
-    @endcode
+    @snippet cpp/tutorial_code/ImgTrans/Laplace_Demo.cpp reduce_noise
 -#  Convert the image to grayscale using @ref cv::cvtColor
-    @code{.cpp}
-    cvtColor( src, src_gray, COLOR_RGB2GRAY );
-    @endcode
+    @snippet cpp/tutorial_code/ImgTrans/Laplace_Demo.cpp convert_to_gray
 -#  Apply the Laplacian operator to the grayscale image:
-    @code{.cpp}
-    Laplacian( src_gray, dst, ddepth, kernel_size, scale, delta, BORDER_DEFAULT );
-    @endcode
+    @snippet cpp/tutorial_code/ImgTrans/Laplace_Demo.cpp laplacian
     where the arguments are:
 
     -   *src_gray*: The input image.
@@ -96,13 +78,9 @@ Explanation
     -   *scale*, *delta* and *BORDER_DEFAULT*: We leave them as default values.
 
 -#  Convert the output from the Laplacian operator to a *CV_8U* image:
-    @code{.cpp}
-    convertScaleAbs( dst, abs_dst );
-    @endcode
+    @snippet cpp/tutorial_code/ImgTrans/Laplace_Demo.cpp convert
 -#  Display the result in a window:
-    @code{.cpp}
-    imshow( window_name, abs_dst );
-    @endcode
+    @snippet cpp/tutorial_code/ImgTrans/Laplace_Demo.cpp display
 
 Results
 -------
diff --git a/doc/tutorials/imgproc/imgtrans/remap/remap.markdown b/doc/tutorials/imgproc/imgtrans/remap/remap.markdown
index fd70f01..34a0b90 100644
--- a/doc/tutorials/imgproc/imgtrans/remap/remap.markdown
+++ b/doc/tutorials/imgproc/imgtrans/remap/remap.markdown
@@ -52,7 +52,7 @@ Code
     -   Wait for the user to exit the program
 
 -#  The tutorial code's is shown lines below. You can also download it from
-    [here](https://github.com/Itseez/opencv/tree/master/samples/cpp/tutorial_code/ImgTrans/Remap_Demo.cpp)
+    [here](https://github.com/opencv/opencv/tree/master/samples/cpp/tutorial_code/ImgTrans/Remap_Demo.cpp)
     @include samples/cpp/tutorial_code/ImgTrans/Remap_Demo.cpp
 
 Explanation
@@ -85,9 +85,9 @@ Explanation
     while( true )
     {
       /// Each 1 sec. Press ESC to exit the program
-      int c = waitKey( 1000 );
+      char c = (char)waitKey( 1000 );
 
-      if( (char)c == 27 )
+      if( c == 27 )
         { break; }
 
       /// Update map_x & map_y. Then apply remap
diff --git a/doc/tutorials/imgproc/imgtrans/sobel_derivatives/sobel_derivatives.markdown b/doc/tutorials/imgproc/imgtrans/sobel_derivatives/sobel_derivatives.markdown
index 185f891..3112b08 100644
--- a/doc/tutorials/imgproc/imgtrans/sobel_derivatives/sobel_derivatives.markdown
+++ b/doc/tutorials/imgproc/imgtrans/sobel_derivatives/sobel_derivatives.markdown
@@ -108,47 +108,23 @@ Code
         bright on a darker background.
 
 -#  The tutorial code's is shown lines below. You can also download it from
-    [here](https://github.com/Itseez/opencv/tree/master/samples/cpp/tutorial_code/ImgTrans/Sobel_Demo.cpp)
+    [here](https://github.com/opencv/opencv/tree/master/samples/cpp/tutorial_code/ImgTrans/Sobel_Demo.cpp)
     @include samples/cpp/tutorial_code/ImgTrans/Sobel_Demo.cpp
 
 Explanation
 -----------
 
 -#  First we declare the variables we are going to use:
-    @code{.cpp}
-    Mat src, src_gray;
-    Mat grad;
-    char* window_name = "Sobel Demo - Simple Edge Detector";
-    int scale = 1;
-    int delta = 0;
-    int ddepth = CV_16S;
-    @endcode
+    @snippet cpp/tutorial_code/ImgTrans/Sobel_Demo.cpp variables
 -#  As usual we load our source image *src*:
-    @code{.cpp}
-    src = imread( argv[1] );
-
-    if( !src.data )
-    { return -1; }
-    @endcode
+    @snippet cpp/tutorial_code/ImgTrans/Sobel_Demo.cpp load
 -#  First, we apply a @ref cv::GaussianBlur to our image to reduce the noise ( kernel size = 3 )
-    @code{.cpp}
-    GaussianBlur( src, src, Size(3,3), 0, 0, BORDER_DEFAULT );
-    @endcode
+    @snippet cpp/tutorial_code/ImgTrans/Sobel_Demo.cpp reduce_noise
 -#  Now we convert our filtered image to grayscale:
-    @code{.cpp}
-    cvtColor( src, src_gray, COLOR_RGB2GRAY );
-    @endcode
+    @snippet cpp/tutorial_code/ImgTrans/Sobel_Demo.cpp convert_to_gray
 -#  Second, we calculate the "*derivatives*" in *x* and *y* directions. For this, we use the
     function @ref cv::Sobel as shown below:
-    @code{.cpp}
-    Mat grad_x, grad_y;
-    Mat abs_grad_x, abs_grad_y;
-
-    /// Gradient X
-    Sobel( src_gray, grad_x, ddepth, 1, 0, 3, scale, delta, BORDER_DEFAULT );
-    /// Gradient Y
-    Sobel( src_gray, grad_y, ddepth, 0, 1, 3, scale, delta, BORDER_DEFAULT );
-    @endcode
+    @snippet cpp/tutorial_code/ImgTrans/Sobel_Demo.cpp sobel
     The function takes the following arguments:
 
     -   *src_gray*: In our example, the input image. Here it is *CV_8U*
@@ -162,19 +138,12 @@ Explanation
     \f$y_{order} = 0\f$. We do analogously for the *y* direction.
 
 -#  We convert our partial results back to *CV_8U*:
-    @code{.cpp}
-    convertScaleAbs( grad_x, abs_grad_x );
-    convertScaleAbs( grad_y, abs_grad_y );
-    @endcode
+    @snippet cpp/tutorial_code/ImgTrans/Sobel_Demo.cpp convert
 -#  Finally, we try to approximate the *gradient* by adding both directional gradients (note that
     this is not an exact calculation at all! but it is good for our purposes).
-    @code{.cpp}
-    addWeighted( abs_grad_x, 0.5, abs_grad_y, 0.5, 0, grad );
-    @endcode
+    @snippet cpp/tutorial_code/ImgTrans/Sobel_Demo.cpp blend
 -#  Finally, we show our result:
-    @code{.cpp}
-    imshow( window_name, grad );
-    @endcode
+    @snippet cpp/tutorial_code/ImgTrans/Sobel_Demo.cpp display
 
 Results
 -------
diff --git a/doc/tutorials/imgproc/imgtrans/warp_affine/warp_affine.markdown b/doc/tutorials/imgproc/imgtrans/warp_affine/warp_affine.markdown
index 3612c32..934e8db 100644
--- a/doc/tutorials/imgproc/imgtrans/warp_affine/warp_affine.markdown
+++ b/doc/tutorials/imgproc/imgtrans/warp_affine/warp_affine.markdown
@@ -89,7 +89,7 @@ Code
     -   Waits until the user exits the program
 
 -#  The tutorial code's is shown lines below. You can also download it from
-    [here](https://github.com/Itseez/opencv/tree/master/samples/cpp/tutorial_code/ImgTrans/Geometric_Transforms_Demo.cpp)
+    [here](https://github.com/opencv/opencv/tree/master/samples/cpp/tutorial_code/ImgTrans/Geometric_Transforms_Demo.cpp)
     @include samples/cpp/tutorial_code/ImgTrans/Geometric_Transforms_Demo.cpp
 
 Explanation
diff --git a/doc/tutorials/imgproc/morph_lines_detection/moprh_lines_detection.md b/doc/tutorials/imgproc/morph_lines_detection/moprh_lines_detection.md
index 2fd260c..23b748d 100644
--- a/doc/tutorials/imgproc/morph_lines_detection/moprh_lines_detection.md
+++ b/doc/tutorials/imgproc/morph_lines_detection/moprh_lines_detection.md
@@ -48,7 +48,7 @@ A structuring element can have many common shapes, such as lines, diamonds, disk
 Code
 ----
 
-This tutorial code's is shown lines below. You can also download it from [here](https://github.com/Itseez/opencv/tree/master/samples/cpp/tutorial_code/ImgProc/Morphology_3.cpp).
+This tutorial code's is shown lines below. You can also download it from [here](https://github.com/opencv/opencv/tree/master/samples/cpp/tutorial_code/ImgProc/Morphology_3.cpp).
 @include samples/cpp/tutorial_code/ImgProc/Morphology_3.cpp
 
 Explanation / Result
diff --git a/doc/tutorials/imgproc/opening_closing_hats/images/Morphology_2_Tutorial_Theory_Closing_2.png b/doc/tutorials/imgproc/opening_closing_hats/images/Morphology_2_Tutorial_Theory_Closing_2.png
new file mode 100644
index 0000000..57b7905
Binary files /dev/null and b/doc/tutorials/imgproc/opening_closing_hats/images/Morphology_2_Tutorial_Theory_Closing_2.png differ
diff --git a/doc/tutorials/imgproc/opening_closing_hats/images/Morphology_2_Tutorial_Theory_Opening_2.png b/doc/tutorials/imgproc/opening_closing_hats/images/Morphology_2_Tutorial_Theory_Opening_2.png
new file mode 100644
index 0000000..973e13a
Binary files /dev/null and b/doc/tutorials/imgproc/opening_closing_hats/images/Morphology_2_Tutorial_Theory_Opening_2.png differ
diff --git a/doc/tutorials/imgproc/opening_closing_hats/opening_closing_hats.markdown b/doc/tutorials/imgproc/opening_closing_hats/opening_closing_hats.markdown
index e1eaed7..c941413 100644
--- a/doc/tutorials/imgproc/opening_closing_hats/opening_closing_hats.markdown
+++ b/doc/tutorials/imgproc/opening_closing_hats/opening_closing_hats.markdown
@@ -24,7 +24,7 @@ In the previous tutorial we covered two basic Morphology operations:
 -   Dilation.
 
 Based on these two we can effectuate more sophisticated transformations to our images. Here we
-discuss briefly 05 operations offered by OpenCV:
+discuss briefly 5 operations offered by OpenCV:
 
 ### Opening
 
@@ -40,6 +40,11 @@ discuss briefly 05 operations offered by OpenCV:
 
     ![](images/Morphology_2_Tutorial_Theory_Opening.png)
 
+For the sake of clarity, we have performed the opening operation (`7x7` rectangular structuring element)
+on the same original image but inverted such as the object in white is now the letter.
+
+![Left image: original image inverted, right image: resulting opening](images/Morphology_2_Tutorial_Theory_Opening_2.png)
+
 ### Closing
 
 -   It is obtained by the dilation of an image followed by an erosion.
@@ -50,6 +55,10 @@ discuss briefly 05 operations offered by OpenCV:
 
     ![](images/Morphology_2_Tutorial_Theory_Closing.png)
 
+On the inverted image, we have performed the closing operation (`7x7` rectangular structuring element):
+
+![Left image: original image inverted, right image: resulting closing](images/Morphology_2_Tutorial_Theory_Closing_2.png)
+
 ### Morphological Gradient
 
 -   It is the difference between the dilation and the erosion of an image.
@@ -80,77 +89,8 @@ Code
 ----
 
 This tutorial code's is shown lines below. You can also download it from
-[here](https://github.com/Itseez/opencv/tree/master/samples/cpp/tutorial_code/ImgProc/Morphology_2.cpp)
- at code{.cpp}
-#include "opencv2/imgproc.hpp"
-#include "opencv2/highgui.hpp"
-#include <stdlib.h>
-#include <stdio.h>
-
-using namespace cv;
-
-/// Global variables
-Mat src, dst;
-
-int morph_elem = 0;
-int morph_size = 0;
-int morph_operator = 0;
-int const max_operator = 4;
-int const max_elem = 2;
-int const max_kernel_size = 21;
-
-char* window_name = "Morphology Transformations Demo";
-
-/* Function Headers */
-void Morphology_Operations( int, void* );
-
-/* @function main */
-int main( int argc, char** argv )
-{
-  /// Load an image
-  src = imread( argv[1] );
-
-  if( !src.data )
-  { return -1; }
-
- /// Create window
- namedWindow( window_name, WINDOW_AUTOSIZE );
-
- /// Create Trackbar to select Morphology operation
- createTrackbar("Operator:\n 0: Opening - 1: Closing \n 2: Gradient - 3: Top Hat \n 4: Black Hat", window_name, &morph_operator, max_operator, Morphology_Operations );
-
- /// Create Trackbar to select kernel type
- createTrackbar( "Element:\n 0: Rect - 1: Cross - 2: Ellipse", window_name,
-         &morph_elem, max_elem,
-         Morphology_Operations );
-
- /// Create Trackbar to choose kernel size
- createTrackbar( "Kernel size:\n 2n +1", window_name,
-         &morph_size, max_kernel_size,
-         Morphology_Operations );
-
- /// Default start
- Morphology_Operations( 0, 0 );
-
- waitKey(0);
- return 0;
- }
-
- /*
-  * @function Morphology_Operations
-  */
-void Morphology_Operations( int, void* )
-{
-  // Since MORPH_X : 2,3,4,5 and 6
-  int operation = morph_operator + 2;
-
-  Mat element = getStructuringElement( morph_elem, Size( 2*morph_size + 1, 2*morph_size+1 ), Point( morph_size, morph_size ) );
-
-  /// Apply the specified morphology operation
-  morphologyEx( src, dst, operation, element );
-  imshow( window_name, dst );
-  }
- at endcode
+[here](https://github.com/opencv/opencv/tree/master/samples/cpp/tutorial_code/ImgProc/Morphology_2.cpp)
+ at include cpp/tutorial_code/ImgProc/Morphology_2.cpp
 
 Explanation
 -----------
@@ -158,47 +98,23 @@ Explanation
 -#  Let's check the general structure of the program:
     -   Load an image
     -   Create a window to display results of the Morphological operations
-    -   Create 03 Trackbars for the user to enter parameters:
-        -   The first trackbar **"Operator"** returns the kind of morphology operation to use
+    -   Create three Trackbars for the user to enter parameters:
+        -   The first trackbar **Operator** returns the kind of morphology operation to use
             (**morph_operator**).
-            @code{.cpp}
-            createTrackbar("Operator:\n 0: Opening - 1: Closing \n 2: Gradient - 3: Top Hat \n 4: Black Hat",
-                           window_name, &morph_operator, max_operator,
-                           Morphology_Operations );
-            @endcode
-        -   The second trackbar **"Element"** returns **morph_elem**, which indicates what kind of
+            @snippet cpp/tutorial_code/ImgProc/Morphology_2.cpp create_trackbar1
+
+        -   The second trackbar **Element** returns **morph_elem**, which indicates what kind of
             structure our kernel is:
-            @code{.cpp}
-            createTrackbar( "Element:\n 0: Rect - 1: Cross - 2: Ellipse", window_name,
-                    &morph_elem, max_elem,
-                    Morphology_Operations );
-            @endcode
-        -   The final trackbar **"Kernel Size"** returns the size of the kernel to be used
+            @snippet cpp/tutorial_code/ImgProc/Morphology_2.cpp create_trackbar2
+
+        -   The final trackbar **Kernel Size** returns the size of the kernel to be used
             (**morph_size**)
-            @code{.cpp}
-            createTrackbar( "Kernel size:\n 2n +1", window_name,
-                    &morph_size, max_kernel_size,
-                    Morphology_Operations );
-            @endcode
+            @snippet cpp/tutorial_code/ImgProc/Morphology_2.cpp create_trackbar3
+
     -   Every time we move any slider, the user's function **Morphology_Operations** will be called
         to effectuate a new morphology operation and it will update the output image based on the
         current trackbar values.
-        @code{.cpp}
-        /*
-         * @function Morphology_Operations
-         */
-        void Morphology_Operations( int, void* )
-        {
-            // Since MORPH_X : 2,3,4,5 and 6
-            int operation = morph_operator + 2;
-
-            Mat element = getStructuringElement( morph_elem, Size( 2*morph_size + 1, 2*morph_size+1 ), Point( morph_size, morph_size ) );
-
-            /// Apply the specified morphology operation
-            morphologyEx( src, dst, operation, element );
-            imshow( window_name, dst );
-        }
-        @endcode
+        @snippet cpp/tutorial_code/ImgProc/Morphology_2.cpp morphology_operations
 
         We can observe that the key function to perform the morphology transformations is @ref
         cv::morphologyEx . In this example we use four arguments (leaving the rest as defaults):
@@ -216,9 +132,7 @@ Explanation
 
             As you can see the values range from \<2-6\>, that is why we add (+2) to the values
             entered by the Trackbar:
-            @code{.cpp}
-            int operation = morph_operator + 2;
-            @endcode
+            @snippet cpp/tutorial_code/ImgProc/Morphology_2.cpp operation
         -   **element**: The kernel to be used. We use the function @ref cv::getStructuringElement
             to define our own structure.
 
diff --git a/doc/tutorials/imgproc/pyramids/pyramids.markdown b/doc/tutorials/imgproc/pyramids/pyramids.markdown
index 1a07d8c..5210ec0 100644
--- a/doc/tutorials/imgproc/pyramids/pyramids.markdown
+++ b/doc/tutorials/imgproc/pyramids/pyramids.markdown
@@ -66,7 +66,7 @@ Code
 ----
 
 This tutorial code's is shown lines below. You can also download it from
-[here](https://github.com/Itseez/opencv/tree/master/samples/cpp/tutorial_code/ImgProc/Pyramids.cpp)
+[here](https://github.com/opencv/opencv/tree/master/samples/cpp/tutorial_code/ImgProc/Pyramids.cpp)
 
 @include samples/cpp/tutorial_code/ImgProc/Pyramids.cpp
 
@@ -77,13 +77,7 @@ Let's check the general structure of the program:
 
 -   Load an image (in this case it is defined in the program, the user does not have to enter it
     as an argument)
-    @code{.cpp}
-    /// Test image - Make sure it s divisible by 2^{n}
-    src = imread( "../images/chicky_512.jpg" );
-    if( !src.data )
-      { printf(" No data! -- Exiting the program \n");
-        return -1; }
-    @endcode
+    @snippet cpp/tutorial_code/ImgProc/Pyramids.cpp load
 
 -   Create a Mat object to store the result of the operations (*dst*) and one to save temporal
     results (*tmp*).
@@ -95,40 +89,16 @@ Let's check the general structure of the program:
     @endcode
 
 -   Create a window to display the result
-    @code{.cpp}
-    namedWindow( window_name, WINDOW_AUTOSIZE );
-    imshow( window_name, dst );
-    @endcode
+    @snippet cpp/tutorial_code/ImgProc/Pyramids.cpp create_window
 
 -   Perform an infinite loop waiting for user input.
-    @code{.cpp}
-    while( true )
-    {
-      int c;
-      c = waitKey(10);
-
-      if( (char)c == 27 )
-        { break; }
-      if( (char)c == 'u' )
-        { pyrUp( tmp, dst, Size( tmp.cols*2, tmp.rows*2 ) );
-          printf( "** Zoom In: Image x 2 \n" );
-        }
-      else if( (char)c == 'd' )
-       { pyrDown( tmp, dst, Size( tmp.cols/2, tmp.rows/2 ) );
-         printf( "** Zoom Out: Image / 2 \n" );
-       }
-
-      imshow( window_name, dst );
-      tmp = dst;
-    }
-    @endcode
+    @snippet cpp/tutorial_code/ImgProc/Pyramids.cpp infinite_loop
+
     Our program exits if the user presses *ESC*. Besides, it has two options:
 
     -   **Perform upsampling (after pressing 'u')**
-        @code{.cpp}
-        pyrUp( tmp, dst, Size( tmp.cols*2, tmp.rows*2 )
-        @endcode
-        We use the function @ref cv::pyrUp with 03 arguments:
+        @snippet cpp/tutorial_code/ImgProc/Pyramids.cpp pyrup
+        We use the function @ref cv::pyrUp with three arguments:
 
         -   *tmp*: The current image, it is initialized with the *src* original image.
         -   *dst*: The destination image (to be shown on screen, supposedly the double of the
@@ -136,11 +106,8 @@ Let's check the general structure of the program:
         -   *Size( tmp.cols*2, tmp.rows\*2 )\* : The destination size. Since we are upsampling,
             @ref cv::pyrUp expects a size double than the input image (in this case *tmp*).
     -   **Perform downsampling (after pressing 'd')**
-        @code{.cpp}
-        pyrDown( tmp, dst, Size( tmp.cols/2, tmp.rows/2 )
-        @endcode
-        Similarly as with @ref cv::pyrUp , we use the function @ref cv::pyrDown with 03
-        arguments:
+        @snippet cpp/tutorial_code/ImgProc/Pyramids.cpp pyrdown
+        Similarly as with @ref cv::pyrUp , we use the function @ref cv::pyrDown with three arguments:
 
         -   *tmp*: The current image, it is initialized with the *src* original image.
         -   *dst*: The destination image (to be shown on screen, supposedly half the input
@@ -151,15 +118,13 @@ Let's check the general structure of the program:
         both dimensions). Otherwise, an error will be shown.
     -   Finally, we update the input image **tmp** with the current image displayed, so the
         subsequent operations are performed on it.
-        @code{.cpp}
-        tmp = dst;
-        @endcode
+        @snippet cpp/tutorial_code/ImgProc/Pyramids.cpp update_tmp
 
 Results
 -------
 
 -   After compiling the code above we can test it. The program calls an image **chicky_512.jpg**
-    that comes in the *tutorial_code/image* folder. Notice that this image is \f$512 \times 512\f$,
+    that comes in the *samples/data* folder. Notice that this image is \f$512 \times 512\f$,
     hence a downsample won't generate any error (\f$512 = 2^{9}\f$). The original image is shown below:
 
     ![](images/Pyramids_Tutorial_Original_Image.jpg)
diff --git a/doc/tutorials/imgproc/shapedescriptors/bounding_rects_circles/bounding_rects_circles.markdown b/doc/tutorials/imgproc/shapedescriptors/bounding_rects_circles/bounding_rects_circles.markdown
index 499ad91..56d886d 100644
--- a/doc/tutorials/imgproc/shapedescriptors/bounding_rects_circles/bounding_rects_circles.markdown
+++ b/doc/tutorials/imgproc/shapedescriptors/bounding_rects_circles/bounding_rects_circles.markdown
@@ -16,12 +16,55 @@ Code
 ----
 
 This tutorial code's is shown lines below. You can also download it from
-[here](https://github.com/Itseez/opencv/tree/master/samples/cpp/tutorial_code/ShapeDescriptors/generalContours_demo1.cpp)
+[here](https://github.com/opencv/opencv/tree/master/samples/cpp/tutorial_code/ShapeDescriptors/generalContours_demo1.cpp)
 @include samples/cpp/tutorial_code/ShapeDescriptors/generalContours_demo1.cpp
 
 Explanation
 -----------
 
+The main function is rather simple, as follows from the comments we do the following:
+-#  Open the image, convert it into grayscale and blur it to get rid of the noise.
+    @snippet samples/cpp/tutorial_code/ShapeDescriptors/generalContours_demo1.cpp setup
+-# Create a window with header "Source" and display the source file in it.
+    @snippet samples/cpp/tutorial_code/ShapeDescriptors/generalContours_demo1.cpp createWindow
+-# Create a trackbar on the source_window and assign a callback function to it
+   In general callback functions are used to react to some kind of signal, in our
+   case it's trackbar's state change.
+   @snippet samples/cpp/tutorial_code/ShapeDescriptors/generalContours_demo1.cpp taskbar
+-# Explicit one-time call of `thresh_callback` is necessary to display
+   the "Contours" window simultaniously with the "Source" window.
+   @snippet samples/cpp/tutorial_code/ShapeDescriptors/generalContours_demo1.cpp callback00
+-# Wait for user to close the windows.
+   @snippet samples/cpp/tutorial_code/ShapeDescriptors/generalContours_demo1.cpp waitForIt
+
+
+The callback function `thresh_callback` does all the interesting job.
+
+
+-# Writes to `threshold_output` the threshold of the grayscale picture (you can check out about thresholding @ref tutorial_threshold "here").
+   @snippet samples/cpp/tutorial_code/ShapeDescriptors/generalContours_demo1.cpp threshold
+-# Finds contours and saves them to the vectors `contour` and `hierarchy`.
+    @snippet samples/cpp/tutorial_code/ShapeDescriptors/generalContours_demo1.cpp findContours
+-# For every found contour we now apply approximation to polygons
+   with accuracy +-3 and stating that the curve must me closed.
+
+   After that we find a bounding rect for every polygon and save it to `boundRect`.
+
+   At last we find a minimum enclosing circle for every polygon and
+   save it to `center` and `radius` vectors.
+   @snippet samples/cpp/tutorial_code/ShapeDescriptors/generalContours_demo1.cpp allthework
+
+We found everything we need, all we have to do is to draw.
+
+-# Create new Mat of unsigned 8-bit chars, filled with zeros.
+   It will contain all the drawings we are going to make (rects and circles).
+   @snippet samples/cpp/tutorial_code/ShapeDescriptors/generalContours_demo1.cpp zeroMat
+-# For every contour: pick a random color, draw the contour, the bounding rectangle and
+   the minimal enclosing circle with it,
+   @snippet samples/cpp/tutorial_code/ShapeDescriptors/generalContours_demo1.cpp forContour
+-# Display the results: create a new window "Contours" and show everything we added to drawings on it.
+   @snippet samples/cpp/tutorial_code/ShapeDescriptors/generalContours_demo1.cpp showDrawings
+
 Result
 ------
 
diff --git a/doc/tutorials/imgproc/shapedescriptors/bounding_rotated_ellipses/bounding_rotated_ellipses.markdown b/doc/tutorials/imgproc/shapedescriptors/bounding_rotated_ellipses/bounding_rotated_ellipses.markdown
index 5dcf69c..e7b3a94 100644
--- a/doc/tutorials/imgproc/shapedescriptors/bounding_rotated_ellipses/bounding_rotated_ellipses.markdown
+++ b/doc/tutorials/imgproc/shapedescriptors/bounding_rotated_ellipses/bounding_rotated_ellipses.markdown
@@ -16,7 +16,7 @@ Code
 ----
 
 This tutorial code's is shown lines below. You can also download it from
-[here](https://github.com/Itseez/opencv/tree/master/samples/cpp/tutorial_code/ShapeDescriptors/generalContours_demo2.cpp)
+[here](https://github.com/opencv/opencv/tree/master/samples/cpp/tutorial_code/ShapeDescriptors/generalContours_demo2.cpp)
 @include samples/cpp/tutorial_code/ShapeDescriptors/generalContours_demo2.cpp
 
 Explanation
diff --git a/doc/tutorials/imgproc/shapedescriptors/find_contours/find_contours.markdown b/doc/tutorials/imgproc/shapedescriptors/find_contours/find_contours.markdown
index 71329db1..11d1d9f 100644
--- a/doc/tutorials/imgproc/shapedescriptors/find_contours/find_contours.markdown
+++ b/doc/tutorials/imgproc/shapedescriptors/find_contours/find_contours.markdown
@@ -16,7 +16,7 @@ Code
 ----
 
 This tutorial code's is shown lines below. You can also download it from
-[here](https://github.com/Itseez/opencv/tree/master/samples/cpp/tutorial_code/ShapeDescriptors/findContours_demo.cpp)
+[here](https://github.com/opencv/opencv/tree/master/samples/cpp/tutorial_code/ShapeDescriptors/findContours_demo.cpp)
 @include samples/cpp/tutorial_code/ShapeDescriptors/findContours_demo.cpp
 
 Explanation
diff --git a/doc/tutorials/imgproc/shapedescriptors/hull/hull.markdown b/doc/tutorials/imgproc/shapedescriptors/hull/hull.markdown
index 5af9de1..38df720 100644
--- a/doc/tutorials/imgproc/shapedescriptors/hull/hull.markdown
+++ b/doc/tutorials/imgproc/shapedescriptors/hull/hull.markdown
@@ -15,7 +15,7 @@ Code
 ----
 
 This tutorial code's is shown lines below. You can also download it from
-[here](https://github.com/Itseez/opencv/tree/master/samples/cpp/tutorial_code/ShapeDescriptors/hull_demo.cpp)
+[here](https://github.com/opencv/opencv/tree/master/samples/cpp/tutorial_code/ShapeDescriptors/hull_demo.cpp)
 
 @include samples/cpp/tutorial_code/ShapeDescriptors/hull_demo.cpp
 
diff --git a/doc/tutorials/imgproc/shapedescriptors/moments/moments.markdown b/doc/tutorials/imgproc/shapedescriptors/moments/moments.markdown
index 9398701..3ef4c13 100644
--- a/doc/tutorials/imgproc/shapedescriptors/moments/moments.markdown
+++ b/doc/tutorials/imgproc/shapedescriptors/moments/moments.markdown
@@ -17,7 +17,7 @@ Code
 ----
 
 This tutorial code's is shown lines below. You can also download it from
-[here](https://github.com/Itseez/opencv/tree/master/samples/cpp/tutorial_code/ShapeDescriptors/moments_demo.cpp)
+[here](https://github.com/opencv/opencv/tree/master/samples/cpp/tutorial_code/ShapeDescriptors/moments_demo.cpp)
 @include samples/cpp/tutorial_code/ShapeDescriptors/moments_demo.cpp
 
 Explanation
diff --git a/doc/tutorials/imgproc/shapedescriptors/point_polygon_test/point_polygon_test.markdown b/doc/tutorials/imgproc/shapedescriptors/point_polygon_test/point_polygon_test.markdown
index 03f6128..4ffb98b 100644
--- a/doc/tutorials/imgproc/shapedescriptors/point_polygon_test/point_polygon_test.markdown
+++ b/doc/tutorials/imgproc/shapedescriptors/point_polygon_test/point_polygon_test.markdown
@@ -15,7 +15,7 @@ Code
 ----
 
 This tutorial code's is shown lines below. You can also download it from
-[here](https://github.com/Itseez/opencv/tree/master/samples/cpp/tutorial_code/ShapeDescriptors/pointPolygonTest_demo.cpp)
+[here](https://github.com/opencv/opencv/tree/master/samples/cpp/tutorial_code/ShapeDescriptors/pointPolygonTest_demo.cpp)
 @include samples/cpp/tutorial_code/ShapeDescriptors/pointPolygonTest_demo.cpp
 
 Explanation
diff --git a/doc/tutorials/imgproc/table_of_content_imgproc.markdown b/doc/tutorials/imgproc/table_of_content_imgproc.markdown
index 77de126..486c644 100644
--- a/doc/tutorials/imgproc/table_of_content_imgproc.markdown
+++ b/doc/tutorials/imgproc/table_of_content_imgproc.markdown
@@ -51,6 +51,14 @@ In this section you will learn about the image processing (manipulation) functio
 
     After so much processing, it is time to decide which pixels stay!
 
+-   @subpage tutorial_threshold_inRange
+
+    *Compatibility:* \> OpenCV 2.0
+
+    *Author:* Rishiraj Surti
+
+    Thresholding operations using inRange function.
+
 -   @subpage tutorial_filter_2d
 
     *Compatibility:* \> OpenCV 2.0
diff --git a/doc/tutorials/imgproc/threshold/threshold.markdown b/doc/tutorials/imgproc/threshold/threshold.markdown
index b78ae9c..c93650a 100644
--- a/doc/tutorials/imgproc/threshold/threshold.markdown
+++ b/doc/tutorials/imgproc/threshold/threshold.markdown
@@ -97,7 +97,7 @@ Code
 ----
 
 The tutorial code's is shown lines below. You can also download it from
-[here](https://github.com/Itseez/opencv/tree/master/samples/cpp/tutorial_code/ImgProc/Threshold.cpp)
+[here](https://github.com/opencv/opencv/tree/master/samples/cpp/tutorial_code/ImgProc/Threshold.cpp)
 @include samples/cpp/tutorial_code/ImgProc/Threshold.cpp
 
 Explanation
@@ -106,51 +106,23 @@ Explanation
 -#  Let's check the general structure of the program:
     -   Load an image. If it is BGR we convert it to Grayscale. For this, remember that we can use
         the function @ref cv::cvtColor :
-        @code{.cpp}
-        src = imread( argv[1], 1 );
+        @snippet cpp/tutorial_code/ImgProc/Threshold.cpp load
 
-        /// Convert the image to Gray
-        cvtColor( src, src_gray, COLOR_BGR2GRAY );
-        @endcode
     -   Create a window to display the result
-        @code{.cpp}
-        namedWindow( window_name, WINDOW_AUTOSIZE );
-        @endcode
+        @snippet cpp/tutorial_code/ImgProc/Threshold.cpp window
+
     -   Create \f$2\f$ trackbars for the user to enter user input:
 
         -   **Type of thresholding**: Binary, To Zero, etc...
         -   **Threshold value**
-        @code{.cpp}
-        createTrackbar( trackbar_type,
-             window_name, &threshold_type,
-             max_type, Threshold_Demo );
-
-        createTrackbar( trackbar_value,
-             window_name, &threshold_value,
-             max_value, Threshold_Demo );
-        @endcode
+        @snippet cpp/tutorial_code/ImgProc/Threshold.cpp trackbar
+
     -   Wait until the user enters the threshold value, the type of thresholding (or until the
         program exits)
     -   Whenever the user changes the value of any of the Trackbars, the function *Threshold_Demo*
         is called:
-        @code{.cpp}
-        /*
-         * @function Threshold_Demo
-         */
-        void Threshold_Demo( int, void* )
-        {
-          /* 0: Binary
-             1: Binary Inverted
-             2: Threshold Truncated
-             3: Threshold to Zero
-             4: Threshold to Zero Inverted
-           */
-
-          threshold( src_gray, dst, threshold_value, max_BINARY_value,threshold_type );
-
-          imshow( window_name, dst );
-        }
-        @endcode
+        @snippet cpp/tutorial_code/ImgProc/Threshold.cpp Threshold_Demo
+
         As you can see, the function @ref cv::threshold is invoked. We give \f$5\f$ parameters:
 
         -   *src_gray*: Our input image
diff --git a/doc/tutorials/imgproc/threshold_inRange/images/Threshold_inRange_Tutorial_Result_input.jpeg b/doc/tutorials/imgproc/threshold_inRange/images/Threshold_inRange_Tutorial_Result_input.jpeg
new file mode 100644
index 0000000..6d23ca1
Binary files /dev/null and b/doc/tutorials/imgproc/threshold_inRange/images/Threshold_inRange_Tutorial_Result_input.jpeg differ
diff --git a/doc/tutorials/imgproc/threshold_inRange/images/Threshold_inRange_Tutorial_Result_output.jpeg b/doc/tutorials/imgproc/threshold_inRange/images/Threshold_inRange_Tutorial_Result_output.jpeg
new file mode 100644
index 0000000..c586513
Binary files /dev/null and b/doc/tutorials/imgproc/threshold_inRange/images/Threshold_inRange_Tutorial_Result_output.jpeg differ
diff --git a/doc/tutorials/imgproc/threshold_inRange/threshold_inRange.markdown b/doc/tutorials/imgproc/threshold_inRange/threshold_inRange.markdown
new file mode 100644
index 0000000..101fa01
--- /dev/null
+++ b/doc/tutorials/imgproc/threshold_inRange/threshold_inRange.markdown
@@ -0,0 +1,56 @@
+Thresholding Operations using inRange {#tutorial_threshold_inRange}
+=============================
+
+Goal
+----
+
+In this tutorial you will learn how to:
+
+-   Perform basic thresholding operations using OpenCV function @ref cv::inRange
+-   Detect an object based on the range of pixel values it has
+
+Theory
+-----------
+-   In the previous tutorial, we learnt how perform thresholding using @ref cv::threshold function.
+-   In this tutorial, we will learn how to do it using @ref cv::inRange function.
+-   The concept remains same, but now we add a range of pixel values we need.
+
+Code
+----
+
+The tutorial code's is shown lines below. You can also download it from
+[here](https://github.com/opencv/opencv/tree/master/samples/cpp/tutorial_code/ImgProc/Threshold_inRange.cpp)
+ at include samples/cpp/tutorial_code/ImgProc/Threshold_inRange.cpp
+
+Explanation
+-----------
+
+-#  Let's check the general structure of the program:
+    -   Create two Matrix elements to store the frames
+        @snippet samples/cpp/tutorial_code/ImgProc/Threshold_inRange.cpp mat
+    -   Capture the video stream from default capturing device.
+        @snippet samples/cpp/tutorial_code/ImgProc/Threshold_inRange.cpp cap
+    -   Create a window to display the default frame and the threshold frame.
+        @snippet samples/cpp/tutorial_code/ImgProc/Threshold_inRange.cpp window
+    -   Create trackbars to set the range of RGB values
+        @snippet samples/cpp/tutorial_code/ImgProc/Threshold_inRange.cpp trackbar
+    -   Until the user want the program to exit do the following
+        @snippet samples/cpp/tutorial_code/ImgProc/Threshold_inRange.cpp while
+    -   Show the images
+        @snippet samples/cpp/tutorial_code/ImgProc/Threshold_inRange.cpp show
+    -   For a trackbar which controls the lower range, say for example Red value:
+        @snippet samples/cpp/tutorial_code/ImgProc/Threshold_inRange.cpp low
+    -   For a trackbar which controls the upper range, say for example Red value:
+        @snippet samples/cpp/tutorial_code/ImgProc/Threshold_inRange.cpp high
+    -   It is necessary to find the maximum and minimum value to avoid discrepancies such as
+        the high value of threshold becoming less the low value.
+
+Results
+-------
+
+-#  After compiling this program, run it. The program will open two windows
+
+-#  As you set the RGB range values from the trackbar, the resulting frame will be visible in the other window.
+
+    ![](images/Threshold_inRange_Tutorial_Result_input.jpeg)
+    ![](images/Threshold_inRange_Tutorial_Result_output.jpeg)
diff --git a/doc/tutorials/introduction/android_binary_package/android_ocl_intro.markdown b/doc/tutorials/introduction/android_binary_package/android_ocl_intro.markdown
index b775176..3dab6e8 100644
--- a/doc/tutorials/introduction/android_binary_package/android_ocl_intro.markdown
+++ b/doc/tutorials/introduction/android_binary_package/android_ocl_intro.markdown
@@ -17,7 +17,7 @@ If you need help with anything of the above, you may refer to our @ref tutorial_
 This tutorial also assumes you have an Android operated device with OpenCL enabled.
 
 The related source code is located within OpenCV samples at
-[opencv/samples/android/tutorial-4-opencl](https://github.com/Itseez/opencv/tree/master/samples/android/tutorial-4-opencl/) directory.
+[opencv/samples/android/tutorial-4-opencl](https://github.com/opencv/opencv/tree/master/samples/android/tutorial-4-opencl/) directory.
 
 Preface
 -------
@@ -244,7 +244,7 @@ As you can see, inheritors for `Camera` and `Camera2` APIs should implement the
 @endcode
 
 Let's leave the details of their implementation beyond of this tutorial, please refer the
-[source code](https://github.com/Itseez/opencv/tree/master/samples/android/tutorial-4-opencl/) to see them.
+[source code](https://github.com/opencv/opencv/tree/master/samples/android/tutorial-4-opencl/) to see them.
 
 Preview Frames modification
 ---------------------------
diff --git a/doc/tutorials/introduction/biicode/images/bii_lena.png b/doc/tutorials/introduction/biicode/images/bii_lena.png
new file mode 100644
index 0000000..387f9db
Binary files /dev/null and b/doc/tutorials/introduction/biicode/images/bii_lena.png differ
diff --git a/doc/tutorials/introduction/building_tegra_cuda/building_tegra_cuda.markdown b/doc/tutorials/introduction/building_tegra_cuda/building_tegra_cuda.markdown
new file mode 100644
index 0000000..9c384a0
--- /dev/null
+++ b/doc/tutorials/introduction/building_tegra_cuda/building_tegra_cuda.markdown
@@ -0,0 +1,656 @@
+Building OpenCV for Tegra with CUDA {#tutorial_building_tegra_cuda}
+===================================
+
+ at tableofcontents
+
+OpenCV with CUDA for Tegra
+==========================
+
+This document is a basic guide to building the OpenCV libraries with CUDA support for use in the Tegra environment. It covers the basic elements of building the version 3.1.0 libraries from source code for three (3) different types of platforms:
+
+* NVIDIA DRIVE™ PX 2 (V4L)
+* NVIDIA<sup>®</sup> Tegra<sup>®</sup> Linux Driver Package (L4T)
+* Desktop Linux (Ubuntu 14.04 LTS and 16.04 LTS)
+
+This document is not an exhaustive guide to all of the options available when building OpenCV. Specifically, it covers the basic options used when building each platform but does not cover any options that are not needed (or are unchanged from their default values). Additionally, the installation of the CUDA toolkit is not covered here.
+
+This document is focused on building the 3.1.0 version of OpenCV, but the guidelines here may also work for building from the master branch of the git repository. There are differences in some of the CMake options for builds of the 2.4.13 version of OpenCV, which are summarized below in the @ref tutorial_building_tegra_cuda_opencv_24X section.
+
+Most of the configuration commands are based on the system having CUDA 8.0 installed. In the case of the Jetson TK1, an older CUDA is used because 8.0 is not supported for that platform. These instructions may also work with older versions of CUDA, but are only tested with 8.0.
+
+### A Note on Native Compilation vs. Cross-Compilation
+
+The OpenCV build system supports native compilation for all the supported platforms, as well as cross-compilation for platforms such as ARM and others. The native compilation process is simpler, whereas the cross-compilation is generally faster.
+
+At the present time, this document focuses only on native compilation.
+
+Getting the Source Code {#tutorial_building_tegra_cuda_getting_the_code}
+=======================
+
+There are two (2) ways to get the OpenCV source code:
+
+* Direct download from the [OpenCV downloads](http://opencv.org/downloads.html) page
+* Cloning the git repositories hosted on [GitHub](https://github.com/opencv)
+
+For this guide, the focus is on using the git repositories. This is because the 3.1.0 version of OpenCV will not build with CUDA 8.0 without applying a few small upstream changes from the git repository.
+
+OpenCV
+------
+
+Start with the `opencv` repository:
+
+    # Clone the opencv repository locally:
+    $ git clone https://github.com/opencv/opencv.git
+
+To build the 3.1.0 version (as opposed to building the most-recent source), you must check out a branch based on the `3.1.0` tag:
+
+    $ cd opencv
+    $ git checkout -b v3.1.0 3.1.0
+
+__Note:__ This operation creates a new local branch in your clone's repository.
+
+There are some upstream changes that must be applied via the `git cherry-pick` command. The first of these is to apply a fix for building specifically with the 8.0 version of CUDA that was not part of the 3.1.0 release:
+
+    # While still in the opencv directory:
+    $ git cherry-pick 10896
+
+You will see the following output from the command:
+
+    [v3.1.0 d6d69a7] GraphCut deprecated in CUDA 7.5 and removed in 8.0
+     Author: Vladislav Vinogradov <vlad.vinogradov at itseez.com>
+     1 file changed, 2 insertions(+), 1 deletion(-)
+
+Secondly, there is a fix for a CMake macro call that is problematic on some systems:
+
+    $ git cherry pick cdb9c
+
+You should see output similar to:
+
+    [v3.1.0-28613 e5ac2e4] gpu samples: fix REMOVE_ITEM error
+     Author: Alexander Alekhin <alexander.alekhin at itseez.com>
+     1 file changed, 1 insertion(+), 1 deletion(-)
+
+The last upstream fix that is needed deals with the `pkg-config` configuration file that is bundled with the developer package (`libopencv-dev`):
+
+    $ git cherry-pick 24dbb
+
+You should see output similar to:
+
+    [v3.1.0 3a6d7ab] pkg-config: modules list contains only OpenCV modules (fixes #5852)
+     Author: Alexander Alekhin <alexander.alekhin at itseez.com>
+     1 file changed, 7 insertions(+), 4 deletions(-)
+
+At this point, the `opencv` repository is ready for building.
+
+OpenCV Extra
+------------
+
+The `opencv_extra` repository contains extra data for the OpenCV library, including the data files used by the tests and demos. It must be cloned separately:
+
+    # In the same base directory from which you cloned OpenCV:
+    $ git clone https://github.com/opencv/opencv_extra.git
+
+As with the OpenCV source, you must use the same method as above to set the source tree to the 3.1.0 version. When you are building from a specific tag, both repositories must be checked out at that tag.
+
+    $ cd opencv_extra
+    $ git checkout -b v3.1.0 3.1.0
+
+You may opt to not fetch this repository if you do not plan on running the tests or installing the test-data along with the samples and example programs. If it is not referenced in the invocation of CMake, it will not be used.
+
+__Note:__ If you plan to run the tests, some tests expect the data to be present and will fail without it.
+
+Preparation and Prerequisites {#tutorial_building_tegra_cuda_preparation}
+=============================
+
+To build OpenCV, you need a directory to create the configuration and build the libraries. You also need a number of 3rd-party libraries upon which OpenCV depends.
+
+Prerequisites for Ubuntu Linux
+------------------------------
+
+These are the basic requirements for building OpenCV for Tegra on Linux:
+
+* CMake 2.8.10 or newer
+* CUDA toolkit 8.0 (7.0 or 7.5 may also be used)
+* Build tools (make, gcc, g++)
+* Python 2.6 or greater
+
+These are the same regardless of the platform (DRIVE PX 2, Desktop, etc.).
+
+A number of development packages are required for building on Linux:
+
+* libglew-dev
+* libtiff5-dev
+* zlib1g-dev
+* libjpeg-dev
+* libpng12-dev
+* libjasper-dev
+* libavcodec-dev
+* libavformat-dev
+* libavutil-dev
+* libpostproc-dev
+* libswscale-dev
+* libeigen3-dev
+* libtbb-dev
+* libgtk2.0-dev
+* pkg-config
+
+Some of the packages above are in the `universe` repository for Ubuntu Linux systems. If you have not already enabled that repository, you need to do the following before trying to install all of the packages listed above:
+
+    $ sudo apt-add-repository universe
+    $ sudo apt-get update
+
+The following command can be pasted into a shell in order to install the required packages:
+
+    $ sudo apt-get install \
+        libglew-dev \
+        libtiff5-dev \
+        zlib1g-dev \
+        libjpeg-dev \
+        libpng12-dev \
+        libjasper-dev \
+        libavcodec-dev \
+        libavformat-dev \
+        libavutil-dev \
+        libpostproc-dev \
+        libswscale-dev \
+        libeigen3-dev \
+        libtbb-dev \
+        libgtk2.0-dev \
+        pkg-config
+
+(Line-breaks and continuation characters are added for readability.)
+
+If you want the Python bindings to be built, you will also need the appropriate packages for either or both of Python 2 and Python 3:
+
+* python-dev / python3-dev
+* python-numpy / python3-numpy
+* python-py / python3-py
+* python-pytest / python3-pytest
+
+The commands that will do this:
+
+    $ sudo apt-get install python-dev python-numpy python-py python-pytest
+    # And, optionally:
+    $ sudo apt-get install python3-dev python3-numpy python3-py python3-pytest
+
+Once all the necessary packages are installed, you can configure the build.
+
+Preparing the Build Area
+------------------------
+
+Software projects that use the CMake system for configuring their builds expect the actual builds to be done outside of the source tree itself. For configuring and building OpenCV, create a directory called "build" in the same base directory into which you cloned the git repositories:
+
+    $ mkdir build
+    $ cd build
+
+You are now ready to configure and build OpenCV.
+
+Configuring OpenCV for Building {#tutorial_building_tegra_cuda_configuring}
+===============================
+
+The CMake configuration options given below for the different platforms are targeted towards the functionality needed for Tegra. They are based on the original configuration options used for building OpenCV 2.4.13.
+
+The build of OpenCV is configured with CMake. If run with no parameters, it detects what it needs to know about your system. However, it may have difficulty finding the CUDA files if they are not in a standard location, and it may try to build some options that you might otherwise not want included, so the following invocations of CMake are recommended.
+
+In each `cmake` command listed in the following sub-sections, line-breaks and indentation are added for readability. Continuation characters are also added in examples for Linux-based platforms, allowing you to copy and paste the examples directly into a shell. When entering these commands by hand, enter the command and options as a single line. For a detailed explanation of the parameters passed to `cmake`, see the "CMake Parameter Reference" section.
+
+For the Linux-based platforms, the shown value for the `CMAKE_INSTALL_PREFIX` parameter is `/usr`. You can set this to whatever you want, based on the layout of your system.
+
+In each of the `cmake` invocations below, the last parameter, `OPENCV_TEST_DATA_PATH`, tells the build system where to find the test-data that is provided by the `opencv_extra` repository. When this is included, a `make install` installs this test-data alongside the libraries and example code, and a `make test` automatically provides this path to the tests that have to load data from it. If you did not clone the `opencv_extra` repository, do not include this parameter.
+
+Vibrante V4L Configuration
+--------------------------
+
+Supported platform: Drive PX 2
+
+    $ cmake \
+        -DCMAKE_BUILD_TYPE=Release \
+        -DCMAKE_INSTALL_PREFIX=/usr \
+        -DBUILD_PNG=OFF \
+        -DBUILD_TIFF=OFF \
+        -DBUILD_TBB=OFF \
+        -DBUILD_JPEG=OFF \
+        -DBUILD_JASPER=OFF \
+        -DBUILD_ZLIB=OFF \
+        -DBUILD_EXAMPLES=ON \
+        -DBUILD_opencv_java=OFF \
+        -DBUILD_opencv_python2=ON \
+        -DBUILD_opencv_python3=OFF \
+        -DENABLE_NEON=ON \
+        -DWITH_OPENCL=OFF \
+        -DWITH_OPENMP=OFF \
+        -DWITH_FFMPEG=ON \
+        -DWITH_GSTREAMER=OFF \
+        -DWITH_GSTREAMER_0_10=OFF \
+        -DWITH_CUDA=ON \
+        -DWITH_GTK=ON \
+        -DWITH_VTK=OFF \
+        -DWITH_TBB=ON \
+        -DWITH_1394=OFF \
+        -DWITH_OPENEXR=OFF \
+        -DCUDA_TOOLKIT_ROOT_DIR=/usr/local/cuda-8.0 \
+        -DCUDA_ARCH_BIN=6.2 \
+        -DCUDA_ARCH_PTX="" \
+        -DINSTALL_C_EXAMPLES=ON \
+        -DINSTALL_TESTS=OFF \
+        -DOPENCV_TEST_DATA_PATH=../opencv_extra/testdata \
+        ../opencv
+
+The configuration provided above builds the Python bindings for Python 2 (but not Python 3) as part of the build process. If you want the Python 3 bindings (or do not want the Python 2 bindings), change the values of `BUILD_opencv_python2` and/or `BUILD_opencv_python3` as needed. To enable bindings, set the value to `ON`, to disable them set it to `OFF`:
+
+    -DBUILD_opencv_python2=OFF
+
+Jetson L4T Configuration
+------------------------
+
+Supported platforms:
+
+* Jetson TK1
+* Jetson TX1
+
+Configuration is slightly different for the Jetson TK1 and the Jetson TX1 systems.
+
+### Jetson TK1
+
+    $ cmake \
+        -DCMAKE_BUILD_TYPE=Release \
+        -DCMAKE_INSTALL_PREFIX=/usr \
+        -DCMAKE_CXX_FLAGS=-Wa,-mimplicit-it=thumb \
+        -DBUILD_PNG=OFF \
+        -DBUILD_TIFF=OFF \
+        -DBUILD_TBB=OFF \
+        -DBUILD_JPEG=OFF \
+        -DBUILD_JASPER=OFF \
+        -DBUILD_ZLIB=OFF \
+        -DBUILD_EXAMPLES=ON \
+        -DBUILD_opencv_java=OFF \
+        -DBUILD_opencv_python2=ON \
+        -DBUILD_opencv_python3=OFF \
+        -DENABLE_NEON=ON \
+        -DWITH_OPENCL=OFF \
+        -DWITH_OPENMP=OFF \
+        -DWITH_FFMPEG=ON \
+        -DWITH_GSTREAMER=OFF \
+        -DWITH_GSTREAMER_0_10=OFF \
+        -DWITH_CUDA=ON \
+        -DWITH_GTK=ON \
+        -DWITH_VTK=OFF \
+        -DWITH_TBB=ON \
+        -DWITH_1394=OFF \
+        -DWITH_OPENEXR=OFF \
+        -DCUDA_TOOLKIT_ROOT_DIR=/usr/local/cuda-6.5 \
+        -DCUDA_ARCH_BIN=3.2 \
+        -DCUDA_ARCH_PTX="" \
+        -DINSTALL_C_EXAMPLES=ON \
+        -DINSTALL_TESTS=OFF \
+        -DOPENCV_TEST_DATA_PATH=../opencv_extra/testdata \
+        ../opencv
+
+__Note:__ This uses CUDA 6.5, not 8.0.
+
+### Jetson TX1
+
+    $ cmake \
+        -DCMAKE_BUILD_TYPE=Release \
+        -DCMAKE_INSTALL_PREFIX=/usr \
+        -DBUILD_PNG=OFF \
+        -DBUILD_TIFF=OFF \
+        -DBUILD_TBB=OFF \
+        -DBUILD_JPEG=OFF \
+        -DBUILD_JASPER=OFF \
+        -DBUILD_ZLIB=OFF \
+        -DBUILD_EXAMPLES=ON \
+        -DBUILD_opencv_java=OFF \
+        -DBUILD_opencv_python2=ON \
+        -DBUILD_opencv_python3=OFF \
+        -DENABLE_PRECOMPILED_HEADERS=OFF \
+        -DWITH_OPENCL=OFF \
+        -DWITH_OPENMP=OFF \
+        -DWITH_FFMPEG=ON \
+        -DWITH_GSTREAMER=OFF \
+        -DWITH_GSTREAMER_0_10=OFF \
+        -DWITH_CUDA=ON \
+        -DWITH_GTK=ON \
+        -DWITH_VTK=OFF \
+        -DWITH_TBB=ON \
+        -DWITH_1394=OFF \
+        -DWITH_OPENEXR=OFF \
+        -DCUDA_TOOLKIT_ROOT_DIR=/usr/local/cuda-8.0 \
+        -DCUDA_ARCH_BIN=5.3 \
+        -DCUDA_ARCH_PTX="" \
+        -DINSTALL_C_EXAMPLES=ON \
+        -DINSTALL_TESTS=OFF \
+        -DOPENCV_TEST_DATA_PATH=../opencv_extra/testdata \
+        ../opencv
+
+__Note:__ This configuration does not set the `ENABLE_NEON` parameter.
+
+Ubuntu Desktop Linux Configuration
+----------------------------------
+
+Supported platforms:
+
+* Ubuntu Desktop Linux 14.04 LTS
+* Ubuntu Desktop Linux 16.04 LTS
+
+The configuration options given to `cmake` below are targeted towards the functionality needed for Tegra. For a desktop system, you may wish to adjust some options to enable (or disable) certain features. The features enabled below are based on the building of OpenCV 2.4.13.
+
+    $ cmake \
+        -DCMAKE_BUILD_TYPE=Release \
+        -DCMAKE_INSTALL_PREFIX=/usr \
+        -DBUILD_PNG=OFF \
+        -DBUILD_TIFF=OFF \
+        -DBUILD_TBB=OFF \
+        -DBUILD_JPEG=OFF \
+        -DBUILD_JASPER=OFF \
+        -DBUILD_ZLIB=OFF \
+        -DBUILD_EXAMPLES=ON \
+        -DBUILD_opencv_java=OFF \
+        -DBUILD_opencv_python2=ON \
+        -DBUILD_opencv_python3=OFF \
+        -DWITH_OPENCL=OFF \
+        -DWITH_OPENMP=OFF \
+        -DWITH_FFMPEG=ON \
+        -DWITH_GSTREAMER=OFF \
+        -DWITH_GSTREAMER_0_10=OFF \
+        -DWITH_CUDA=ON \
+        -DWITH_GTK=ON \
+        -DWITH_VTK=OFF \
+        -DWITH_TBB=ON \
+        -DWITH_1394=OFF \
+        -DWITH_OPENEXR=OFF \
+        -DCUDA_TOOLKIT_ROOT_DIR=/usr/local/cuda-8.0 \
+        -DCUDA_ARCH_BIN='3.0 3.5 5.0 6.0 6.2' \
+        -DCUDA_ARCH_PTX="" \
+        -DINSTALL_C_EXAMPLES=ON \
+        -DINSTALL_TESTS=OFF \
+        -DOPENCV_TEST_DATA_PATH=../opencv_extra/testdata \
+        ../opencv
+
+This configuration is nearly identical to that for V4L and L4T, except that the `CUDA_ARCH_BIN` parameter specifies multiple architectures so as to support a variety of GPU boards. For a desktop, you have the option of omitting this parameter, and CMake will instead run a small test program that probes for the supported architectures. However, the libraries produced might not work on Ubuntu systems with different cards.
+
+As with previous examples, the configuration given above builds the Python bindings for Python 2 (but not Python 3) as part of the build process.
+
+Building OpenCV {#tutorial_building_tegra_cuda_building}
+===============
+
+Once `cmake` finishes configuring OpenCV, building is done using the standard `make` utility.
+
+Building with `make`
+--------------------
+
+The only parameter that is needed for the invocation of `make` is the `-j` parameter for specifying how many parallel threads to use. This varies depending on the system and how much memory is available, other running processes, etc. The following table offers suggested values for this parameter:
+
+|Platform|Suggested value|Notes|
+|--------|---------------|-----|
+|DRIVE PX 2|6| |
+|Jetson TK1|3|If the build fails due to a compiler-related error, try again with a smaller number of threads. Also consider rebooting the system if it has been running for a long time since the last reboot.|
+|Jetson TX1|4| |
+|Ubuntu Desktop|7|The actual value will vary with the number of cores you have and the amount of physical memory. Because of the resource requirements of compiling the CUDA code, it is not recommended to go above 7.|
+
+Based on the value you select, build (assuming you selected 6):
+
+    $ make -j6
+
+By default, CMake hides the details of the build steps. If you need to see more detail about each compilation unit, etc., you can enable verbose output:
+
+    $ make -j6 VERBOSE=1
+
+Testing OpenCV {#tutorial_building_tegra_cuda_testing}
+==============
+
+Once the build completes successfully, you have the option of running the extensive set of tests that OpenCV provides. If you did not clone the `opencv_extra` repository and specify the path to `testdata` in the `cmake` invocation, then testing is not recommended.
+
+Testing under Linux
+-------------------
+
+To run the basic tests under Linux, execute:
+
+    $ make test
+
+This executes `ctest` to carry out the tests, as specified in CTest syntax within the OpenCV repository. The `ctest` harness takes many different parameters (too many to list here, see the manual page for CTest to see the full set), and if you wish to pass any of them, you can do so by specifying them in a `make` command-line parameter called `ARGS`:
+
+    $ make test ARGS="--verbose --parallel 3"
+
+In this example, there are two (2) arguments passed to `ctest`: `--verbose` and `--parallel 3`. The first argument causes the output from `ctest` to be more detailed, and the second causes `ctest` to run as many as three (3) tests in parallel. As with choosing a thread count for building, base any choice for testing on the available number of processor cores, physical memory, etc. Some of the tests do attempt to allocate significant amounts of memory.
+
+### Known Issues with Tests
+
+At present, not all of the tests in the OpenCV test suite pass. There are tests that fail whether or not CUDA is compiled, and there are tests that are only specific to CUDA that also do not currently pass.
+
+__Note:__ There are no tests that pass without CUDA but fail only when CUDA is included.
+
+As the full lists of failing tests vary based on platform, it is impractical to list them here.
+
+Installing OpenCV {#tutorial_building_tegra_cuda_installing}
+=================
+
+Installing OpenCV is very straightforward. For the Linux-based platforms, the command is:
+
+    $ make install
+
+Depending on the chosen installation location, you may need root privilege to install.
+
+Building OpenCV 2.4.X {#tutorial_building_tegra_cuda_opencv_24X}
+=====================
+
+If you wish to build your own version of the 2.4 version of OpenCV, there are only a few adjustments that must be made. At the time of this writing, the latest version on the 2.4 tree is 2.4.13. These instructions may work for later versions of 2.4, though they have not been tested for any earlier versions.
+
+__Note:__ The 2.4.X OpenCV source does not have the extra modules and code for Tegra that was upstreamed into the 3.X versions of OpenCV. This part of the guide is only for cases where you want to build a vanilla version of OpenCV 2.4.
+
+Selecting the 2.4 Source
+------------------------
+
+First you must select the correct source branch or tag. If you want a specific version such as 2.4.13, you want to make a local branch based on the tag, as was done with the 3.1.0 tag above:
+
+    # Within the opencv directory:
+    $ git checkout -b v2.4.13 2.4.13
+
+    # Within the opencv_extra directory:
+    $ git checkout -b v2.4.13 2.4.13
+
+If you simply want the newest code from the 2.4 line of OpenCV, there is a `2.4` branch already in the repository. You can check that out instead of a specific tag:
+
+    $ git checkout 2.4
+
+There is no need for the `git cherry-pick` commands used with 3.1.0 when building the 2.4.13 source.
+
+Configuring
+-----------
+
+Configuring is done with CMake as before. The primary difference is that OpenCV 2.4 only provides Python bindings for Python 2, and thus does not distinguish between Python 2 and Python 3 in the CMake parameters. There is only one parameter, `BUILD_opencv_python`. In addition, there is a build-related parameter that controls features in 2.4 that are not in 3.1.0. This parameter is `BUILD_opencv_nonfree`.
+
+Configuration still takes place in a separate directory that must be a sibling to the `opencv` and `opencv_extra` directories.
+
+### Configuring Vibrante V4L
+
+For DRIVE PX 2:
+
+    $ cmake \
+        -DCMAKE_BUILD_TYPE=Release \
+        -DCMAKE_INSTALL_PREFIX=/usr \
+        -DBUILD_PNG=OFF \
+        -DBUILD_TIFF=OFF \
+        -DBUILD_TBB=OFF \
+        -DBUILD_JPEG=OFF \
+        -DBUILD_JASPER=OFF \
+        -DBUILD_ZLIB=OFF \
+        -DBUILD_EXAMPLES=ON \
+        -DBUILD_opencv_java=OFF \
+        -DBUILD_opencv_nonfree=OFF \
+        -DBUILD_opencv_python=ON \
+        -DENABLE_NEON=ON \
+        -DWITH_OPENCL=OFF \
+        -DWITH_OPENMP=OFF \
+        -DWITH_FFMPEG=ON \
+        -DWITH_GSTREAMER=OFF \
+        -DWITH_GSTREAMER_0_10=OFF \
+        -DWITH_CUDA=ON \
+        -DWITH_GTK=ON \
+        -DWITH_VTK=OFF \
+        -DWITH_TBB=ON \
+        -DWITH_1394=OFF \
+        -DWITH_OPENEXR=OFF \
+        -DCUDA_TOOLKIT_ROOT_DIR=/usr/local/cuda-8.0 \
+        -DCUDA_ARCH_BIN=6.2 \
+        -DCUDA_ARCH_PTX="" \
+        -DINSTALL_C_EXAMPLES=ON \
+        -DINSTALL_TESTS=ON \
+        -DOPENCV_TEST_DATA_PATH=../opencv_extra/testdata \
+        ../opencv
+
+### Configuring Jetson L4T
+
+For Jetson TK1:
+
+    $ cmake \
+        -DCMAKE_BUILD_TYPE=Release \
+        -DCMAKE_INSTALL_PREFIX=/usr \
+        -DBUILD_PNG=OFF \
+        -DBUILD_TIFF=OFF \
+        -DBUILD_TBB=OFF \
+        -DBUILD_JPEG=OFF \
+        -DBUILD_JASPER=OFF \
+        -DBUILD_ZLIB=OFF \
+        -DBUILD_EXAMPLES=ON \
+        -DBUILD_opencv_java=OFF \
+        -DBUILD_opencv_nonfree=OFF \
+        -DBUILD_opencv_python=ON \
+        -DENABLE_NEON=ON \
+        -DWITH_OPENCL=OFF \
+        -DWITH_OPENMP=OFF \
+        -DWITH_FFMPEG=ON \
+        -DWITH_GSTREAMER=OFF \
+        -DWITH_GSTREAMER_0_10=OFF \
+        -DWITH_CUDA=ON \
+        -DWITH_GTK=ON \
+        -DWITH_VTK=OFF \
+        -DWITH_TBB=ON \
+        -DWITH_1394=OFF \
+        -DWITH_OPENEXR=OFF \
+        -DCUDA_TOOLKIT_ROOT_DIR=/usr/local/cuda-6.5 \
+        -DCUDA_ARCH_BIN=3.2 \
+        -DCUDA_ARCH_PTX="" \
+        -DINSTALL_C_EXAMPLES=ON \
+        -DINSTALL_TESTS=ON \
+        -DOPENCV_TEST_DATA_PATH=../opencv_extra/testdata \
+        ../opencv
+
+For Jetson TX1:
+
+    $ cmake \
+        -DCMAKE_BUILD_TYPE=Release \
+        -DCMAKE_INSTALL_PREFIX=/usr \
+        -DBUILD_PNG=OFF \
+        -DBUILD_TIFF=OFF \
+        -DBUILD_TBB=OFF \
+        -DBUILD_JPEG=OFF \
+        -DBUILD_JASPER=OFF \
+        -DBUILD_ZLIB=OFF \
+        -DBUILD_EXAMPLES=ON \
+        -DBUILD_opencv_java=OFF \
+        -DBUILD_opencv_nonfree=OFF \
+        -DBUILD_opencv_python=ON \
+        -DENABLE_PRECOMPILED_HEADERS=OFF \
+        -DWITH_OPENCL=OFF \
+        -DWITH_OPENMP=OFF \
+        -DWITH_FFMPEG=ON \
+        -DWITH_GSTREAMER=OFF \
+        -DWITH_GSTREAMER_0_10=OFF \
+        -DWITH_CUDA=ON \
+        -DWITH_GTK=ON \
+        -DWITH_VTK=OFF \
+        -DWITH_TBB=ON \
+        -DWITH_1394=OFF \
+        -DWITH_OPENEXR=OFF \
+        -DCUDA_TOOLKIT_ROOT_DIR=/usr/local/cuda-8.0 \
+        -DCUDA_ARCH_BIN=5.3 \
+        -DCUDA_ARCH_PTX="" \
+        -DINSTALL_C_EXAMPLES=ON \
+        -DINSTALL_TESTS=ON \
+        -DOPENCV_TEST_DATA_PATH=../opencv_extra/testdata \
+        ../opencv
+
+### Configuring Desktop Ubuntu Linux
+
+For both 14.04 LTS and 16.04 LTS:
+
+    $ cmake \
+        -DCMAKE_BUILD_TYPE=Release \
+        -DCMAKE_INSTALL_PREFIX=/usr \
+        -DBUILD_PNG=OFF \
+        -DBUILD_TIFF=OFF \
+        -DBUILD_TBB=OFF \
+        -DBUILD_JPEG=OFF \
+        -DBUILD_JASPER=OFF \
+        -DBUILD_ZLIB=OFF \
+        -DBUILD_EXAMPLES=ON \
+        -DBUILD_opencv_java=OFF \
+        -DBUILD_opencv_nonfree=OFF \
+        -DBUILD_opencv_python=ON \
+        -DWITH_OPENCL=OFF \
+        -DWITH_OPENMP=OFF \
+        -DWITH_FFMPEG=ON \
+        -DWITH_GSTREAMER=OFF \
+        -DWITH_GSTREAMER_0_10=OFF \
+        -DWITH_CUDA=ON \
+        -DWITH_GTK=ON \
+        -DWITH_VTK=OFF \
+        -DWITH_TBB=ON \
+        -DWITH_1394=OFF \
+        -DWITH_OPENEXR=OFF \
+        -DCUDA_TOOLKIT_ROOT_DIR=/usr/local/cuda-8.0 \
+        -DCUDA_ARCH_BIN='3.0 3.5 5.0 6.0 6.2' \
+        -DCUDA_ARCH_PTX="" \
+        -DINSTALL_C_EXAMPLES=ON \
+        -DINSTALL_TESTS=ON \
+        -DOPENCV_TEST_DATA_PATH=../opencv_extra/testdata \
+        ../opencv
+
+Building, Testing and Installing
+--------------------------------
+
+Once configured, the steps of building, testing, and installing are the same as above for the 3.1.0 source.
+
+CMake Parameter Reference {#tutorial_building_tegra_cuda_parameter_reference}
+=========================
+
+The following is a table of all the parameters passed to CMake in the recommended invocations above. Some of these are parameters from CMake itself, while most are specific to OpenCV.
+
+|Parameter|Our Default Value|What It Does|Notes|
+|---------|-----------------|------------|-----|
+|BUILD_EXAMPLES|ON|Governs whether the C/C++ examples are built| |
+|BUILD_JASPER|OFF|Governs whether the Jasper library (`libjasper`) is built from source in the `3rdparty` directory| |
+|BUILD_JPEG|OFF|As above, for `libjpeg`| |
+|BUILD_PNG|OFF|As above, for `libpng`| |
+|BUILD_TBB|OFF|As above, for `tbb`| |
+|BUILD_TIFF|OFF|As above, for `libtiff`| |
+|BUILD_ZLIB|OFF|As above, for `zlib`| |
+|BUILD_opencv_java|OFF|Controls the building of the Java bindings for OpenCV|Building the Java bindings requires OpenCV libraries be built for static linking only|
+|BUILD_opencv_nonfree|OFF|Controls the building of non-free (non-open-source) elements|Used only for building 2.4.X|
+|BUILD_opencv_python|ON|Controls the building of the Python 2 bindings in OpenCV 2.4.X|Used only for building 2.4.X|
+|BUILD_opencv_python2|ON|Controls the building of the Python 2 bindings in OpenCV 3.1.0|Not used in 2.4.X|
+|BUILD_opencv_python3|OFF|Controls the building of the Python 3 bindings in OpenCV 3.1.0|Not used in 2.4.X|
+|CMAKE_BUILD_TYPE|Release|Selects the type of build (release vs. development)|Is generally either `Release` or `Debug`|
+|CMAKE_INSTALL_PREFIX|/usr|Sets the root for installation of the libraries and header files| |
+|CUDA_ARCH_BIN|varies|Sets the CUDA architecture(s) for which code is compiled|Usually only passed for platforms with known specific cards. OpenCV includes a small program that determines the architectures of the system's installed card if you do not pass this parameter. Here, for Ubuntu desktop, the value is a list to maximize card support.|
+|CUDA_ARCH_PTX|""|Builds PTX intermediate code for the specified virtual PTX architectures| |
+|CUDA_TOOLKIT_ROOT_DIR|/usr/local/cuda-8.0 (for Linux)|Specifies the location of the CUDA include files and libraries| |
+|ENABLE_NEON|ON|Enables the use of NEON SIMD extensions for ARM chips|Only passed for builds on ARM platforms|
+|ENABLE_PRECOMPILED_HEADERS|OFF|Enables/disables support for pre-compiled headers|Only specified on some of the ARM platforms|
+|INSTALL_C_EXAMPLES|ON|Enables the installation of the C example files as part of `make install`| |
+|INSTALL_TESTS|ON|Enables the installation of the tests as part of `make install`| |
+|OPENCV_TEST_DATA_PATH|../opencv_extra/testdata|Path to the `testdata` directory in the `opencv_extra` repository| |
+|WITH_1394|OFF|Specifies whether to include IEEE-1394 support| |
+|WITH_CUDA|ON|Specifies whether to include CUDA support| |
+|WITH_FFMPEG|ON|Specifies whether to include FFMPEG support| |
+|WITH_GSTREAMER|OFF|Specifies whether to include GStreamer 1.0 support| |
+|WITH_GSTREAMER_0_10|OFF|Specifies whether to include GStreamer 0.10 support| |
+|WITH_GTK|ON|Specifies whether to include GTK 2.0 support|Only given on Linux platforms, not Microsoft Windows|
+|WITH_OPENCL|OFF|Specifies whether to include OpenCL runtime support| |
+|WITH_OPENEXR|OFF|Specifies whether to include ILM support via OpenEXR| |
+|WITH_OPENMP|OFF|Specifies whether to include OpenMP runtime support| |
+|WITH_TBB|ON|Specifies whether to include Intel TBB support| |
+|WITH_VTK|OFF|Specifies whether to include VTK support| |
+
+Copyright © 2016, NVIDIA CORPORATION. All rights reserved.
diff --git a/doc/tutorials/introduction/clojure_dev_intro/clojure_dev_intro.markdown b/doc/tutorials/introduction/clojure_dev_intro/clojure_dev_intro.markdown
index 5af9608..7765e1a 100644
--- a/doc/tutorials/introduction/clojure_dev_intro/clojure_dev_intro.markdown
+++ b/doc/tutorials/introduction/clojure_dev_intro/clojure_dev_intro.markdown
@@ -40,7 +40,7 @@ I'm assuming you already installed [xcode](https://developer.apple.com/xcode/),
 @code{.bash}
 cd ~/
 mkdir opt
-git clone https://github.com/Itseez/opencv.git
+git clone https://github.com/opencv/opencv.git
 cd opencv
 git checkout 2.4
 mkdir build
diff --git a/doc/tutorials/introduction/crosscompilation/arm_crosscompile_with_cmake.markdown b/doc/tutorials/introduction/crosscompilation/arm_crosscompile_with_cmake.markdown
index 1b9dc30..3ef08f8 100644
--- a/doc/tutorials/introduction/crosscompilation/arm_crosscompile_with_cmake.markdown
+++ b/doc/tutorials/introduction/crosscompilation/arm_crosscompile_with_cmake.markdown
@@ -33,7 +33,7 @@ Getting OpenCV Source Code
 --------------------------
 
 You can use the latest stable OpenCV version available in *sourceforge* or you can grab the latest
-snapshot from our [Git repository](https://github.com/Itseez/opencv.git).
+snapshot from our [Git repository](https://github.com/opencv/opencv.git).
 
 ### Getting the Latest Stable OpenCV Version
 
@@ -42,12 +42,12 @@ snapshot from our [Git repository](https://github.com/Itseez/opencv.git).
 
 ### Getting the Cutting-edge OpenCV from the Git Repository
 
-Launch Git client and clone [OpenCV repository](http://github.com/itseez/opencv)
+Launch Git client and clone [OpenCV repository](http://github.com/opencv/opencv)
 
 In Linux it can be achieved with the following command in Terminal:
 @code{.bash}
 cd ~/<my_working _directory>
-git clone https://github.com/Itseez/opencv.git
+git clone https://github.com/opencv/opencv.git
 @endcode
 
 Building OpenCV
diff --git a/doc/tutorials/introduction/desktop_java/java_dev_intro.markdown b/doc/tutorials/introduction/desktop_java/java_dev_intro.markdown
index 9e8048d..c6e8c06 100644
--- a/doc/tutorials/introduction/desktop_java/java_dev_intro.markdown
+++ b/doc/tutorials/introduction/desktop_java/java_dev_intro.markdown
@@ -36,7 +36,7 @@ from the [OpenCV SourceForge repository](http://sourceforge.net/projects/opencvl
 sources.
 
 Another option to get OpenCV sources is to clone [OpenCV git
-repository](https://github.com/Itseez/opencv/). In order to build OpenCV with Java bindings you need
+repository](https://github.com/opencv/opencv/). In order to build OpenCV with Java bindings you need
 JDK (Java Development Kit) (we recommend [Oracle/Sun JDK 6 or
 7](http://www.oracle.com/technetwork/java/javase/downloads/)), [Apache Ant](http://ant.apache.org/)
 and Python v2.6 or higher to be installed.
@@ -45,7 +45,7 @@ and Python v2.6 or higher to be installed.
 
 Let's build OpenCV:
 @code{.bash}
-git clone git://github.com/Itseez/opencv.git
+git clone git://github.com/opencv/opencv.git
 cd opencv
 git checkout 2.4
 mkdir build
diff --git a/doc/tutorials/introduction/display_image/display_image.markdown b/doc/tutorials/introduction/display_image/display_image.markdown
index c4a1f1d..f0eea98 100644
--- a/doc/tutorials/introduction/display_image/display_image.markdown
+++ b/doc/tutorials/introduction/display_image/display_image.markdown
@@ -14,7 +14,7 @@ Source Code
 -----------
 
 Download the source code from
-[here](https://github.com/Itseez/opencv/tree/master/samples/cpp/tutorial_code/introduction/display_image/display_image.cpp).
+[here](https://github.com/opencv/opencv/tree/master/samples/cpp/tutorial_code/introduction/display_image/display_image.cpp).
 
 @include cpp/tutorial_code/introduction/display_image/display_image.cpp
 
diff --git a/doc/tutorials/introduction/documenting_opencv/documentation_tutorial.markdown b/doc/tutorials/introduction/documenting_opencv/documentation_tutorial.markdown
index f1d9f9c..c51d7be 100644
--- a/doc/tutorials/introduction/documenting_opencv/documentation_tutorial.markdown
+++ b/doc/tutorials/introduction/documenting_opencv/documentation_tutorial.markdown
@@ -439,6 +439,83 @@ Then include this snippet into documentation:
 compatibility with the old rST documentation. But newly created samples should be included with the
 _snippet_ command, since this method is less affected by the changes in processed file.
 
+### Toggle buttons inclusion commands {#tutorial_documentation_toggle_buttons_commands_include}
+
+Toggle buttons are used to display the selected configuration (e.g. programming language, OS, IDE).
+
+To use the buttons in documentation, _add_toggle_ and _end_toggle_ commands are used.
+
+The command _add_toggle_ can be
+- general: _add_toggle{Button Name}_
+- for C++: _add_toggle_cpp_
+- for Java: _add_toggle_java_
+- for Python: _add_toggle_python_
+
+Example:
+ at verbatim
+ at add_toggle{Button Name}
+
+  text / code / doxygen commands
+
+ at end_toggle
+ at endverbatim
+
+For example using toggle buttons with text and [code](@ref tutorial_documentation_commands_include) snippets:
+
+ at verbatim
+
+### Buttons Example
+
+ at add_toggle_cpp
+
+   Text for C++ button
+   @snippet samples/cpp/tutorial_code/introduction/documentation/documentation.cpp hello_world
+
+ at end_toggle
+
+ at add_toggle_java
+
+   Text for Java button
+   @snippet samples/java/tutorial_code/introduction/documentation/Documentation.java  hello_world
+
+ at end_toggle
+
+ at add_toggle_python
+
+   Text for Python button
+   @snippet samples/python/tutorial_code/introduction/documentation/documentation.py hello_world
+
+ at end_toggle
+
+ at endverbatim
+
+Result looks like this:
+
+### Buttons Example
+
+ at add_toggle_cpp
+
+   Text for C++ button
+   @snippet samples/cpp/tutorial_code/introduction/documentation/documentation.cpp hello_world
+
+ at end_toggle
+
+ at add_toggle_java
+
+   Text for Java button
+   @snippet samples/java/tutorial_code/introduction/documentation/Documentation.java  hello_world
+
+ at end_toggle
+
+ at add_toggle_python
+
+   Text for Python button
+   @snippet samples/python/tutorial_code/introduction/documentation/documentation.py hello_world
+
+ at end_toggle
+
+As you can see, the buttons are added automatically under the previous heading.
+
 ### Grouping commands {#tutorial_documentation_commands_group}
 
 All code entities should be put into named groups representing OpenCV modules and their internal
@@ -536,6 +613,8 @@ Write the tutorial {#tutorial_documentation_steps_tutorial}
 
     If you want to insert code blocks from this file into your tutorial, mark them with special doxygen comments (see [here](@ref tutorial_documentation_commands_include)).
 
+    If you want to write the tutorial in more than one programming language, use the toggle buttons for alternative comments and code (see [here](@ref tutorial_documentation_toggle_buttons_commands_include)).
+
 3.  Collect results  of the application work. It can be "before/after" images or some numbers
     representing performance or even a video.
 
@@ -552,22 +631,21 @@ Write the tutorial {#tutorial_documentation_steps_tutorial}
 
 5.  Modify your new page:
     -   Add page title and identifier, usually prefixed with <em>"tutorial_"</em> (see [here](@ref tutorial_documentation_md_page)).
+        You can add a link to the previous and next tutorial using the identifier
+        @verbatim
+ at prev_tutorial{identifier}
+ at next_tutorial{identifier}
+        @endverbatim
+        @warning Do **not** write the **hashtag (#)**, example: \n Incorrect: @verbatim @prev_tutorial{#tutorial_documentation} @endverbatim Correct: @verbatim @prev_tutorial{tutorial_documentation} @endverbatim
     -   Add brief description of your idea and tutorial goals.
     -   Describe your program and/or its interesting pieces.
     -   Describe your results, insert previously added images or other results.
 
-        To add a video use _htmlonly_, _endhtmlonly_ commands with raw html block inside:
+        To add a youtube video, e.g. www.youtube.com/watch?v= **ViPN810E0SU**, use _youtube_{**Video ID**}:
         @verbatim
- at htmlonly
-<div align="center">
-<iframe
-    title="my title" width="560" height="349"
-    src="http://www.youtube.com/embed/ViPN810E0SU?rel=0&loop=1"
-    frameborder="0" allowfullscreen align="middle">
-</iframe>
-</div>
- at endhtmlonly
+ at youtube{ViPN810E0SU}
         @endverbatim
+
     -   Add bibliographic references if any (see [here](@ref tutorial_documentation_commands_cite)).
 
 6.  Add newly created tutorial to the corresponding table of contents. Just find
@@ -576,6 +654,8 @@ Write the tutorial {#tutorial_documentation_steps_tutorial}
     @verbatim
 -   @subpage tutorial_windows_visual_studio_image_watch
 
+    _Languages:_ C++, Java, Python
+
     _Compatibility:_ \>= OpenCV 2.4
 
     _Author:_ Wolf Kienzle
diff --git a/doc/tutorials/introduction/ios_install/ios_install.markdown b/doc/tutorials/introduction/ios_install/ios_install.markdown
index 00faf68..9a82e15 100644
--- a/doc/tutorials/introduction/ios_install/ios_install.markdown
+++ b/doc/tutorials/introduction/ios_install/ios_install.markdown
@@ -9,13 +9,13 @@ Required Packages
 
 ### Getting the Cutting-edge OpenCV from Git Repository
 
-Launch GIT client and clone OpenCV repository from [here](http://github.com/itseez/opencv)
+Launch GIT client and clone OpenCV repository from [here](http://github.com/opencv/opencv)
 
 In MacOS it can be done using the following command in Terminal:
 
 @code{.bash}
 cd ~/<my_working _directory>
-git clone https://github.com/Itseez/opencv.git
+git clone https://github.com/opencv/opencv.git
 @endcode
 
 Building OpenCV from Source, using CMake and Command Line
diff --git a/doc/tutorials/introduction/linux_eclipse/images/a10.png b/doc/tutorials/introduction/linux_eclipse/images/a10.png
index d3603ba..08739a4 100644
Binary files a/doc/tutorials/introduction/linux_eclipse/images/a10.png and b/doc/tutorials/introduction/linux_eclipse/images/a10.png differ
diff --git a/doc/tutorials/introduction/linux_eclipse/linux_eclipse.markdown b/doc/tutorials/introduction/linux_eclipse/linux_eclipse.markdown
index 2e575c1..4aca7ee 100644
--- a/doc/tutorials/introduction/linux_eclipse/linux_eclipse.markdown
+++ b/doc/tutorials/introduction/linux_eclipse/linux_eclipse.markdown
@@ -96,12 +96,12 @@ Making a project
 
                 /usr/local/lib
 
-            Then in **Libraries(-l)** add the OpenCV libraries that you may need. Usually just the 3 first
+            Then in **Libraries(-l)** add the OpenCV libraries that you may need. Usually just the 4 first
             on the list below are enough (for simple applications) . In my case, I am putting all of them
             since I plan to use the whole bunch:
 
-            opencv_core opencv_imgproc opencv_highgui opencv_ml opencv_video opencv_features2d
-            opencv_calib3d opencv_objdetect opencv_contrib opencv_legacy opencv_flann
+            opencv_core opencv_imgproc opencv_imgcodecs opencv_highgui opencv_ml opencv_videoio opencv_video opencv_features2d
+            opencv_calib3d opencv_objdetect opencv_flann
 
             ![](images/a10.png)
 
@@ -112,7 +112,7 @@ Making a project
             @endcode
             My output (in case you want to check) was:
             @code{.bash}
-            -L/usr/local/lib -lopencv_core -lopencv_imgproc -lopencv_highgui -lopencv_ml -lopencv_video -lopencv_features2d -lopencv_calib3d -lopencv_objdetect -lopencv_contrib -lopencv_legacy -lopencv_flann
+            -L/usr/local/lib -lopencv_core -lopencv_imgproc -lopencv_highgui -lopencv_ml -lopencv_video -lopencv_features2d -lopencv_calib3d -lopencv_objdetect -lopencv_videoio -lopencv_imgcodecs -lopencv_flann
             @endcode
             Now you are done. Click **OK**
 
diff --git a/doc/tutorials/introduction/linux_install/linux_install.markdown b/doc/tutorials/introduction/linux_install/linux_install.markdown
index b1868f8..dfbdd4c 100644
--- a/doc/tutorials/introduction/linux_install/linux_install.markdown
+++ b/doc/tutorials/introduction/linux_install/linux_install.markdown
@@ -16,6 +16,7 @@ Required Packages
 -   [optional] libtbb2 libtbb-dev
 -   [optional] libdc1394 2.x
 -   [optional] libjpeg-dev, libpng-dev, libtiff-dev, libjasper-dev, libdc1394-22-dev
+-   [optional] CUDA Toolkit 6.5 or higher
 
 The packages can be installed using a terminal and the following commands or by using Synaptic
 Manager:
@@ -28,7 +29,7 @@ Getting OpenCV Source Code
 --------------------------
 
 You can use the latest stable OpenCV version or you can grab the latest snapshot from our [Git
-repository](https://github.com/Itseez/opencv.git).
+repository](https://github.com/opencv/opencv.git).
 
 ### Getting the Latest Stable OpenCV Version
 
@@ -37,14 +38,14 @@ repository](https://github.com/Itseez/opencv.git).
 
 ### Getting the Cutting-edge OpenCV from the Git Repository
 
-Launch Git client and clone [OpenCV repository](http://github.com/itseez/opencv). If you need
-modules from [OpenCV contrib repository](http://github.com/itseez/opencv_contrib) then clone it too.
+Launch Git client and clone [OpenCV repository](http://github.com/opencv/opencv). If you need
+modules from [OpenCV contrib repository](http://github.com/opencv/opencv_contrib) then clone it too.
 
 For example
 @code{.bash}
 cd ~/<my_working_directory>
-git clone https://github.com/Itseez/opencv.git
-git clone https://github.com/Itseez/opencv_contrib.git
+git clone https://github.com/opencv/opencv.git
+git clone https://github.com/opencv/opencv_contrib.git
 @endcode
 Building OpenCV from Source Using CMake
 ---------------------------------------
@@ -73,6 +74,9 @@ Building OpenCV from Source Using CMake
     -   run: “Configure”
     -   run: “Generate”
 
+    @note
+    Use `cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr/local ..` , without spaces after -D if the above example doesn't work.
+
 -#  Description of some parameters
     -   build type: `CMAKE_BUILD_TYPE=Release\Debug`
     -   to build with modules from opencv_contrib set OPENCV_EXTRA_MODULES_PATH to \<path to
@@ -114,11 +118,11 @@ Building OpenCV from Source Using CMake
 -#  [optional] Running tests
 
     -   Get the required test data from [OpenCV extra
-        repository](https://github.com/Itseez/opencv_extra).
+        repository](https://github.com/opencv/opencv_extra).
 
     For example
     @code{.bash}
-    git clone https://github.com/Itseez/opencv_extra.git
+    git clone https://github.com/opencv/opencv_extra.git
     @endcode
     -   set OPENCV_TEST_DATA_PATH environment variable to \<path to opencv_extra/testdata\>.
     -   execute tests from build directory.
diff --git a/doc/tutorials/introduction/table_of_content_introduction.markdown b/doc/tutorials/introduction/table_of_content_introduction.markdown
index 780d0c1..37820a8 100644
--- a/doc/tutorials/introduction/table_of_content_introduction.markdown
+++ b/doc/tutorials/introduction/table_of_content_introduction.markdown
@@ -126,6 +126,14 @@ Additionally you can find very basic sample source code to introduce you to the
 
     We will learn how to setup OpenCV cross compilation environment for ARM Linux.
 
+-   @subpage tutorial_building_tegra_cuda
+
+    _Compatibility:_ \>= OpenCV 3.1.0
+
+    _Author:_ Randy J. Ray
+
+    This tutorial will help you build OpenCV 3.1.0 for NVIDIA<sup>®</sup> Tegra<sup>®</sup> systems with CUDA 8.0.
+
 -   @subpage tutorial_display_image
 
     _Compatibility:_ \> OpenCV 2.0
diff --git a/doc/tutorials/introduction/transition_guide/transition_guide.markdown b/doc/tutorials/introduction/transition_guide/transition_guide.markdown
index b0bc443..3b9620a 100644
--- a/doc/tutorials/introduction/transition_guide/transition_guide.markdown
+++ b/doc/tutorials/introduction/transition_guide/transition_guide.markdown
@@ -12,7 +12,7 @@ OpenCV 3.0 introduced many new algorithms and features comparing to version 2.4.
 This section describes most notable changes in general, all details and examples of transition actions are in the next part of the document.
 
 ##### Contrib repository
-<https://github.com/Itseez/opencv_contrib>
+<https://github.com/opencv/opencv_contrib>
 
 This is a place for all new, experimental and non-free algorithms. It does not receive so much attention from the support team comparing to main repository, but the community makes an effort to keep it in a good shape.
 
diff --git a/doc/tutorials/introduction/windows_install/windows_install.markdown b/doc/tutorials/introduction/windows_install/windows_install.markdown
index c8808b4..179f430 100644
--- a/doc/tutorials/introduction/windows_install/windows_install.markdown
+++ b/doc/tutorials/introduction/windows_install/windows_install.markdown
@@ -43,7 +43,7 @@ These videos above are long-obsolete and contain inaccurate information. Be care
 solutions described in those videos are no longer supported and may even break your install.
 
 If you are building your own libraries you can take the source files from our [Git
-repository](https://github.com/Itseez/opencv.git).
+repository](https://github.com/opencv/opencv.git).
 
 Building the OpenCV library from scratch requires a couple of tools installed beforehand:
 
@@ -83,9 +83,8 @@ of them, you need to download and install them on your system.
     more of our algorithms to work on the GPUs is a constant effort of the OpenCV team.
 -   [OpenEXR](http://www.openexr.com/downloads.html) source files are required for the library to work with this high dynamic range (HDR)
     image file format.
--   The [OpenNI Framework](http://www.openni.org/) contains a set of open source APIs that provide support for natural
-    interaction with devices via methods such as voice command recognition, hand gestures and body
-    motion tracking.
+-   The OpenNI Framework contains a set of open source APIs that provide support for natural interaction with devices via methods such as voice command recognition, hand gestures and body
+    motion tracking. Prebuilt binaries can be found [here](http://structure.io/openni). The source code of [OpenNI](https://github.com/OpenNI/OpenNI) and [OpenNI2](https://github.com/OpenNI/OpenNI2) are also available on Github.
 -   [Miktex]( http://miktex.org/2.9/setup) is the best [TEX](https://secure.wikimedia.org/wikipedia/en/wiki/TeX) implementation on
     the Windows OS. It is required to build the *OpenCV documentation*.
 -   [Sphinx](http://sphinx.pocoo.org/) is a python documentation generator and is the tool that will actually create the
@@ -114,7 +113,7 @@ libraries). If you do not need the support for some of these you can just freely
     you're doing -- it's OK.
     -#  Clone the repository to the selected directory. After clicking *Clone* button, a window will
         appear where you can select from what repository you want to download source files
-        (<https://github.com/Itseez/opencv.git>) and to what directory (`D:/OpenCV`).
+        (<https://github.com/opencv/opencv.git>) and to what directory (`D:/OpenCV`).
     -#  Push the OK button and be patient as the repository is quite a heavy download. It will take
         some time depending on your Internet connection.
 
diff --git a/doc/tutorials/introduction/windows_visual_studio_Opencv/windows_visual_studio_Opencv.markdown b/doc/tutorials/introduction/windows_visual_studio_Opencv/windows_visual_studio_Opencv.markdown
index 7d5df93..3be7f5b 100644
--- a/doc/tutorials/introduction/windows_visual_studio_Opencv/windows_visual_studio_Opencv.markdown
+++ b/doc/tutorials/introduction/windows_visual_studio_Opencv/windows_visual_studio_Opencv.markdown
@@ -71,9 +71,9 @@ application. In contrast the *Release* is an optimized version, where the goal i
 application run as fast as possible or to be as small as possible. You may figure that these modes
 also require different rules to use during build. Therefore, there exist different rule packages for
 each of your build modes. These rule packages are called inside the IDE as *project properties* and
-you can view and modify them by using the *Property Manger*. You can bring up this with
-View --\> Property Pages. Expand it and you can see the existing rule packages (called *Proporty
-Sheets*).
+you can view and modify them by using the *Property Manager*. You can bring this up with
+View --\> Property Pages (For Visual Studio 2013 onwards, go to View --\> Other Windows --\> Property Manager).
+Expand it and you can see the existing rule packages (called *Property Sheets*).
 
 ![](images/PropertyPageExample.jpg)
 
@@ -189,7 +189,7 @@ Test it!
 --------
 
 Now to try this out download our little test [source code
-](https://github.com/Itseez/opencv/tree/master/samples/cpp/tutorial_code/introduction/windows_visual_studio_Opencv/introduction_windows_vs.cpp)
+](https://github.com/opencv/opencv/tree/master/samples/cpp/tutorial_code/introduction/windows_visual_studio_Opencv/introduction_windows_vs.cpp)
 or get it from the sample code folder of the OpenCV sources. Add this to your project and build it.
 Here's its content:
 
@@ -205,7 +205,7 @@ the *IDE* the console window will not close once finished. It will wait for a ke
 This is important to remember when you code inside the code open and save commands. You're resources
 will be saved ( and queried for at opening!!!) relatively to your working directory. This is unless
 you give a full, explicit path as parameter for the I/O functions. In the code above we open [this
-OpenCV logo](https://github.com/Itseez/opencv/tree/master/samples/data/opencv-logo.png). Before starting up the application make sure you place
+OpenCV logo](https://github.com/opencv/opencv/tree/master/samples/data/opencv-logo.png). Before starting up the application make sure you place
 the image file in your current working directory. Modify the image file name inside the code to try
 it out on other images too. Run it and voil á:
 
diff --git a/doc/tutorials/ml/introduction_to_pca/introduction_to_pca.markdown b/doc/tutorials/ml/introduction_to_pca/introduction_to_pca.markdown
index 78ed547..82274ef 100644
--- a/doc/tutorials/ml/introduction_to_pca/introduction_to_pca.markdown
+++ b/doc/tutorials/ml/introduction_to_pca/introduction_to_pca.markdown
@@ -92,10 +92,10 @@ Source Code
 -----------
 
 This tutorial code's is shown lines below. You can also download it from
-    [here](https://github.com/Itseez/opencv/tree/master/samples/cpp/tutorial_code/ml/introduction_to_pca/introduction_to_pca.cpp).
+    [here](https://github.com/opencv/tree/master/samples/cpp/tutorial_code/ml/introduction_to_pca/introduction_to_pca.cpp).
 @include cpp/tutorial_code/ml/introduction_to_pca/introduction_to_pca.cpp
 
- at note Another example using PCA for dimensionality reduction while maintaining an amount of variance can be found at [opencv_source_code/samples/cpp/pca.cpp](https://github.com/Itseez/opencv/tree/master/samples/cpp/pca.cpp)
+ at note Another example using PCA for dimensionality reduction while maintaining an amount of variance can be found at [opencv_source_code/samples/cpp/pca.cpp](https://github.com/opencv/tree/master/samples/cpp/pca.cpp)
 
 Explanation
 -----------
diff --git a/doc/tutorials/ml/non_linear_svms/non_linear_svms.markdown b/doc/tutorials/ml/non_linear_svms/non_linear_svms.markdown
index 52b544d..1a18870 100644
--- a/doc/tutorials/ml/non_linear_svms/non_linear_svms.markdown
+++ b/doc/tutorials/ml/non_linear_svms/non_linear_svms.markdown
@@ -87,7 +87,7 @@ Source Code
 -----------
 
 You may also find the source code in `samples/cpp/tutorial_code/ml/non_linear_svms` folder of the OpenCV source library or
-[download it from here](https://github.com/Itseez/opencv/tree/master/samples/cpp/tutorial_code/ml/non_linear_svms/non_linear_svms.cpp).
+[download it from here](https://github.com/opencv/tree/master/samples/cpp/tutorial_code/ml/non_linear_svms/non_linear_svms.cpp).
 
 @note The following code has been implemented with OpenCV 3.0 classes and functions. An equivalent version of the code
 using OpenCV 2.4 can be found in [this page.](http://docs.opencv.org/2.4/doc/tutorials/ml/non_linear_svms/non_linear_svms.html#nonlinearsvms)
diff --git a/doc/tutorials/objdetect/cascade_classifier/cascade_classifier.markdown b/doc/tutorials/objdetect/cascade_classifier/cascade_classifier.markdown
index 382046f..6589a1c 100644
--- a/doc/tutorials/objdetect/cascade_classifier/cascade_classifier.markdown
+++ b/doc/tutorials/objdetect/cascade_classifier/cascade_classifier.markdown
@@ -18,95 +18,11 @@ Code
 ----
 
 This tutorial code's is shown lines below. You can also download it from
-[here](https://github.com/Itseez/opencv/tree/master/samples/cpp/tutorial_code/objectDetection/objectDetection.cpp)
+[here](https://github.com/opencv/opencv/tree/master/samples/cpp/tutorial_code/objectDetection/objectDetection.cpp)
 . The second version (using LBP for face detection) can be [found
-here](https://github.com/Itseez/opencv/tree/master/samples/cpp/tutorial_code/objectDetection/objectDetection2.cpp)
- at code{.cpp}
-#include "opencv2/objdetect.hpp"
-#include "opencv2/highgui.hpp"
-#include "opencv2/imgproc.hpp"
+here](https://github.com/opencv/opencv/tree/master/samples/cpp/tutorial_code/objectDetection/objectDetection2.cpp)
+ at include samples/cpp/tutorial_code/objectDetection/objectDetection.cpp
 
-#include <iostream>
-#include <stdio.h>
-
-using namespace std;
-using namespace cv;
-
-/* Function Headers */
-void detectAndDisplay( Mat frame );
-
-/* Global variables */
-String face_cascade_name = "haarcascade_frontalface_alt.xml";
-String eyes_cascade_name = "haarcascade_eye_tree_eyeglasses.xml";
-CascadeClassifier face_cascade;
-CascadeClassifier eyes_cascade;
-String window_name = "Capture - Face detection";
-
-/* @function main */
-int main( void )
-{
-    VideoCapture capture;
-    Mat frame;
-
-    //-- 1. Load the cascades
-    if( !face_cascade.load( face_cascade_name ) ){ printf("--(!)Error loading face cascade\n"); return -1; };
-    if( !eyes_cascade.load( eyes_cascade_name ) ){ printf("--(!)Error loading eyes cascade\n"); return -1; };
-
-    //-- 2. Read the video stream
-    capture.open( -1 );
-    if ( ! capture.isOpened() ) { printf("--(!)Error opening video capture\n"); return -1; }
-
-    while (  capture.read(frame) )
-    {
-        if( frame.empty() )
-        {
-            printf(" --(!) No captured frame -- Break!");
-            break;
-        }
-
-        //-- 3. Apply the classifier to the frame
-        detectAndDisplay( frame );
-
-        int c = waitKey(10);
-        if( (char)c == 27 ) { break; } // escape
-    }
-    return 0;
-}
-
-/* @function detectAndDisplay */
-void detectAndDisplay( Mat frame )
-{
-    std::vector<Rect> faces;
-    Mat frame_gray;
-
-    cvtColor( frame, frame_gray, COLOR_BGR2GRAY );
-    equalizeHist( frame_gray, frame_gray );
-
-    //-- Detect faces
-    face_cascade.detectMultiScale( frame_gray, faces, 1.1, 2, 0|CASCADE_SCALE_IMAGE, Size(30, 30) );
-
-    for( size_t i = 0; i < faces.size(); i++ )
-    {
-        Point center( faces[i].x + faces[i].width/2, faces[i].y + faces[i].height/2 );
-        ellipse( frame, center, Size( faces[i].width/2, faces[i].height/2), 0, 0, 360, Scalar( 255, 0, 255 ), 4, 8, 0 );
-
-        Mat faceROI = frame_gray( faces[i] );
-        std::vector<Rect> eyes;
-
-        //-- In each face, detect eyes
-        eyes_cascade.detectMultiScale( faceROI, eyes, 1.1, 2, 0 |CASCADE_SCALE_IMAGE, Size(30, 30) );
-
-        for( size_t j = 0; j < eyes.size(); j++ )
-        {
-            Point eye_center( faces[i].x + eyes[j].x + eyes[j].width/2, faces[i].y + eyes[j].y + eyes[j].height/2 );
-            int radius = cvRound( (eyes[j].width + eyes[j].height)*0.25 );
-            circle( frame, eye_center, radius, Scalar( 255, 0, 0 ), 4, 8, 0 );
-        }
-    }
-    //-- Show what you got
-    imshow( window_name, frame );
-}
- at endcode
 Explanation
 -----------
 
diff --git a/doc/tutorials/objdetect/images/visualisation_single_stage.png b/doc/tutorials/objdetect/images/visualisation_single_stage.png
new file mode 100644
index 0000000..e87bc22
Binary files /dev/null and b/doc/tutorials/objdetect/images/visualisation_single_stage.png differ
diff --git a/doc/tutorials/objdetect/images/visualisation_video.png b/doc/tutorials/objdetect/images/visualisation_video.png
new file mode 100644
index 0000000..f3ce484
Binary files /dev/null and b/doc/tutorials/objdetect/images/visualisation_video.png differ
diff --git a/doc/tutorials/objdetect/traincascade.markdown b/doc/tutorials/objdetect/traincascade.markdown
index 3e7db48..4edc07b 100644
--- a/doc/tutorials/objdetect/traincascade.markdown
+++ b/doc/tutorials/objdetect/traincascade.markdown
@@ -4,66 +4,30 @@ Cascade Classifier Training {#tutorial_traincascade}
 Introduction
 ------------
 
-The work with a cascade classifier inlcudes two major stages: training and detection. Detection
-stage is described in a documentation of objdetect module of general OpenCV documentation.
-Documentation gives some basic information about cascade classifier. Current guide is describing how
-to train a cascade classifier: preparation of the training data and running the training application.
+Working with a boosted cascade of weak classifiers includes two major stages: the training and the detection stage. The detection stage using either HAAR or LBP based models, is described in the @ref tutorial_cascade_classifier "object detection tutorial". This documentation gives an overview of the functionality needed to train your own boosted cascade of weak classifiers. The current guide will walk through all the different stages: collecting training data, preparation of the training [...]
+
+To support this tutorial, several official OpenCV applications will be used: [opencv_createsamples](https://github.com/opencv/opencv/tree/master/apps/createsamples), [opencv_annotation](https://github.com/opencv/opencv/tree/master/apps/annotation), [opencv_traincascade](https://github.com/opencv/opencv/tree/master/apps/traincascade) and [opencv_visualisation](https://github.com/opencv/opencv/tree/master/apps/visualisation).
 
 ### Important notes
 
-There are two applications in OpenCV to train cascade classifier: opencv_haartraining and
-opencv_traincascade. opencv_traincascade is a newer version, written in C++ in accordance to
-OpenCV 2.x API. But the main difference between this two applications is that opencv_traincascade
-supports both Haar @cite Viola01 and @cite Liao2007 (Local Binary Patterns) features. LBP features
-are integer in contrast to Haar features, so both training and detection with LBP are several times
-faster then with Haar features. Regarding the LBP and Haar detection quality, it depends on
-training: the quality of training dataset first of all and training parameters too. It's possible to
-train a LBP-based classifier that will provide almost the same quality as Haar-based one.
-
-opencv_traincascade and opencv_haartraining store the trained classifier in different file
-formats. Note, the newer cascade detection interface (see CascadeClassifier class in objdetect
-module) support both formats. opencv_traincascade can save (export) a trained cascade in the older
-format. But opencv_traincascade and opencv_haartraining can not load (import) a classifier in
-another format for the futher training after interruption.
-
-Note that opencv_traincascade application can use TBB for multi-threading. To use it in multicore
-mode OpenCV must be built with TBB.
-
-Also there are some auxilary utilities related to the training.
-
--   opencv_createsamples is used to prepare a training dataset of positive and test samples.
-    opencv_createsamples produces dataset of positive samples in a format that is supported by
-    both opencv_haartraining and opencv_traincascade applications. The output is a file
-    with \*.vec extension, it is a binary format which contains images.
--   opencv_performance may be used to evaluate the quality of classifiers, but for trained by
-    opencv_haartraining only. It takes a collection of marked up images, runs the classifier and
-    reports the performance, i.e. number of found objects, number of missed objects, number of
-    false alarms and other information.
-
-Since opencv_haartraining is an obsolete application, only opencv_traincascade will be described
-futher. opencv_createsamples utility is needed to prepare a training data for opencv_traincascade,
-so it will be described too.
-
-Training data preparation
--------------------------
-
-For training we need a set of samples. There are two types of samples: negative and positive.
-Negative samples correspond to non-object images. Positive samples correspond to images with
-detected objects. Set of negative samples must be prepared manually, whereas set of positive samples
-is created using opencv_createsamples utility.
+ - If you come accross any tutorial mentioning the old opencv_haartraining tool <i>(which is deprecated and still using the OpenCV1.x interface)</i>, then please ignore that tutorial and stick to the opencv_traincascade tool. This tool is a newer version, written in C++ in accordance to the OpenCV 2.x and OpenCV 3.x API. The opencv_traincascade supports both HAAR like wavelet features @cite Viola01 and LBP (Local Binary Patterns) @cite Liao2007 features. LBP features yield integer precis [...]
+
+ - The newer cascade classifier detection interface from OpenCV 2.x and OpenCV 3.x (@ref cv::CascadeClassifier) supports working with both old and new model formats. opencv_traincascade can even save (export) a trained cascade in the older format if for some reason you are stuck using the old interface. At least training the model could then be done in the most stable interface.
+
+ - The opencv_traincascade application can use TBB for multi-threading. To use it in multicore mode OpenCV must be built with TBB support enabled.
+
+Preparation of the training data
+--------------------------------
+
+For training a boosted cascade of weak classifiers we need a set of positive samples (containing actual objects you want to detect) and a set of negative images (containing everything you do not want to detect). The set of negative samples must be prepared manually, whereas set of positive samples is created using the opencv_createsamples application.
 
 ### Negative Samples
 
-Negative samples are taken from arbitrary images. These images must not contain detected objects.
-Negative samples are enumerated in a special file. It is a text file in which each line contains an
-image filename (relative to the directory of the description file) of negative sample image. This
-file must be created manually. Note that negative samples and sample images are also called
-background samples or background images, and are used interchangeably in this document.
-Described images may be of different sizes. But each image should be (but not nessesarily) larger
-than a training window size, because these images are used to subsample negative image to the
-training size.
+Negative samples are taken from arbitrary images, not containing objects you want to detect. These negative images, from which the samples are generated, should be listed in a special negative image file containing one image path per line <i>(can be absolute or relative)</i>. Note that negative samples and sample images are also called background samples or background images, and are used interchangeably in this document.
 
-An example of description file:
+Described images may be of different sizes. However, each image should be equal or larger than the desired training window size <i>(which corresponds to the model dimensions, most of the times being the average size of your object)</i>, because these images are used to subsample a given negative image into several image samples having this training window size.
+
+An example of such a negative description file:
 
 Directory structure:
 @code{.text}
@@ -72,100 +36,55 @@ Directory structure:
   img2.jpg
 bg.txt
 @endcode
+
 File bg.txt:
 @code{.text}
 img/img1.jpg
 img/img2.jpg
 @endcode
-### Positive Samples
-
-Positive samples are created by opencv_createsamples utility. They may be created from a single
-image with object or from a collection of previously marked up images.
-
-Please note that you need a large dataset of positive samples before you give it to the mentioned
-utility, because it only applies perspective transformation. For example you may need only one
-positive sample for absolutely rigid object like an OpenCV logo, but you definetely need hundreds
-and even thousands of positive samples for faces. In the case of faces you should consider all the
-race and age groups, emotions and perhaps beard styles.
-
-So, a single object image may contain a company logo. Then a large set of positive samples is
-created from the given object image by random rotating, changing the logo intensity as well as
-placing the logo on arbitrary background. The amount and range of randomness can be controlled by
-command line arguments of opencv_createsamples utility.
-
-Command line arguments:
-
--   -vec \<vec_file_name\>
 
-    Name of the output file containing the positive samples for training.
+Your set of negative window samples will be used to tell the machine learning step, boosting in this case, what not to look for, when trying to find your objects of interest.
 
--   -img \<image_file_name\>
-
-    Source object image (e.g., a company logo).
-
--   -bg \<background_file_name\>
-
-    Background description file; contains a list of images which are used as a background for
-    randomly distorted versions of the object.
-
--   -num \<number_of_samples\>
-
-    Number of positive samples to generate.
-
--   -bgcolor \<background_color\>
-
-    Background color (currently grayscale images are assumed); the background color denotes the
-    transparent color. Since there might be compression artifacts, the amount of color tolerance
-    can be specified by -bgthresh. All pixels withing bgcolor-bgthresh and bgcolor+bgthresh range
-    are interpreted as transparent.
-
--   -bgthresh \<background_color_threshold\>
--   -inv
-
-    If specified, colors will be inverted.
+### Positive Samples
 
--   -randinv
+Positive samples are created by the opencv_createsamples application. They are used by the boosting process to define what the model should actually look for when trying to find your objects of interest. The application supports two ways of generating a positive sample dataset.
 
-    If specified, colors will be inverted randomly.
+ 1. You can generate a bunch of positives from a single positive object image.
+ 2. You can supply all the positives yourself and only use the tool to cut them out, resize them and put them in the opencv needed binary format.
 
--   -maxidev \<max_intensity_deviation\>
+While the first approach works decently for fixed objects, like very rigid logo's, it tends to fail rather soon for less rigid objects. In that case we do suggest to use the second approach. Many tutorials on the web even state that 100 real object images, can lead to a better model than 1000 artificially generated positives, by using the opencv_createsamples application. If you however do decide to take the first approach, keep some things in mind:
 
-    Maximal intensity deviation of pixels in foreground samples.
+ - Please note that you need more than a single positive samples before you give it to the mentioned application, because it only applies perspective transformation.
+ - If you want a robust model, take samples that cover the wide range of varieties that can occur within your object class. For example in the case of faces you should consider different races and age groups, emotions and perhaps beard styles. This also applies when using the second approach.
 
--   -maxxangle \<max_x_rotation_angle\>
--   -maxyangle \<max_y_rotation_angle\>
--   -maxzangle \<max_z_rotation_angle\>
+The first approach takes a single object image with for example a company logo and creates a large set of positive samples from the given object image by randomly rotating the object, changing the image intensity as well as placing the image on arbitrary backgrounds. The amount and range of randomness can be controlled by command line arguments of the opencv_createsamples application.
 
-    Maximum rotation angles must be given in radians.
+Command line arguments:
 
--   -show
+ - `-vec <vec_file_name>` : Name of the output file containing the positive samples for training.
 
-    Useful debugging option. If specified, each sample will be shown. Pressing Esc will continue
-    the samples creation process without.
+ - `-img <image_file_name>` : Source object image (e.g., a company logo).
 
--   -w \<sample_width\>
+ - `-bg <background_file_name>` : Background description file; contains a list of images which are used as a background for randomly distorted versions of the object.
 
-    Width (in pixels) of the output samples.
+ - `-num <number_of_samples>` : Number of positive samples to generate.
 
--   -h \<sample_height\>
+ - `-bgcolor <background_color>` : Background color (currently grayscale images are assumed); the background color denotes the transparent color. Since there might be compression artifacts, the amount of color tolerance can be specified by -bgthresh. All pixels withing bgcolor-bgthresh and bgcolor+bgthresh range are interpreted as transparent.
 
-    Height (in pixels) of the output samples.
+ - `-bgthresh <background_color_threshold>`
+ - `-inv` : If specified, colors will be inverted.
+ - `-randinv` : If specified, colors will be inverted randomly.
+ - `-maxidev <max_intensity_deviation>` : Maximal intensity deviation of pixels in foreground samples.
+ - `-maxxangle <max_x_rotation_angle>` : Maximal rotation angle towards x-axis, must be given in radians.
+ - `-maxyangle <max_y_rotation_angle>` : Maximal rotation angle towards y-axis, must be given in radians.
+ - `-maxzangle <max_z_rotation_angle>` : Maximal rotation angle towards z-axis, must be given in radians.
+ - `-show` : Useful debugging option. If specified, each sample will be shown. Pressing Esc will continue the samples creation process without showing each sample.
+ - `-w <sample_width>` : Width (in pixels) of the output samples.
+ - `-h <sample_height>` : Height (in pixels) of the output samples.
 
-For following procedure is used to create a sample object instance: The source image is rotated
-randomly around all three axes. The chosen angle is limited my -max?angle. Then pixels having the
-intensity from [bg_color-bg_color_threshold; bg_color+bg_color_threshold] range are
-interpreted as transparent. White noise is added to the intensities of the foreground. If the -inv
-key is specified then foreground pixel intensities are inverted. If -randinv key is specified then
-algorithm randomly selects whether inversion should be applied to this sample. Finally, the obtained
-image is placed onto an arbitrary background from the background description file, resized to the
-desired size specified by -w and -h and stored to the vec-file, specified by the -vec command line
-option.
+When running opencv_createsamples in this way, the following procedure is used to create a sample object instance: The given source image is rotated randomly around all three axes. The chosen angle is limited by `-maxxangle`, `-maxyangle` and `-maxzangle`. Then pixels having the intensity from the [bg_color-bg_color_threshold; bg_color+bg_color_threshold] range are interpreted as transparent. White noise is added to the intensities of the foreground. If the `-inv` key is specified then f [...]
 
-Positive samples also may be obtained from a collection of previously marked up images. This
-collection is described by a text file similar to background description file. Each line of this
-file corresponds to an image. The first element of the line is the filename. It is followed by the
-number of object instances. The following numbers are the coordinates of objects bounding rectangles
-(x, y, width, height).
+Positive samples also may be obtained from a collection of previously marked up images, which is the desired way when building robust object models. This collection is described by a text file similar to the background description file. Each line of this file corresponds to an image. The first element of the line is the filename, followed by the number of object annotations, followed by numbers describing the coordinates of the objects bounding rectangles (x, y, width, height).
 
 An example of description file:
 
@@ -184,146 +103,115 @@ img/img2.jpg  2  100 200 50 50   50 30 25 25
 Image img1.jpg contains single object instance with the following coordinates of bounding rectangle:
 (140, 100, 45, 45). Image img2.jpg contains two object instances.
 
-In order to create positive samples from such collection, -info argument should be specified instead
-of \`-img\`:
+In order to create positive samples from such collection, `-info` argument should be specified instead of `-img`:
 
--   -info \<collection_file_name\>
+ - `-info <collection_file_name>` : Description file of marked up images collection.
 
-    Description file of marked up images collection.
+Note that in this case, parameters like `-bg, -bgcolor, -bgthreshold, -inv, -randinv, -maxxangle, -maxyangle, -maxzangle` are simply ignored and not used anymore. The scheme of samples creation in this case is as follows. The object instances are taken from the given images, by cutting out the supplied bounding boxes from the original images. Then they are resized to target samples size (defined by `-w` and `-h`) and stored in output vec-file, defined by the `-vec` parameter. No distorti [...]
 
-The scheme of samples creation in this case is as follows. The object instances are taken from
-images. Then they are resized to target samples size and stored in output vec-file. No distortion is
-applied, so the only affecting arguments are -w, -h, -show and -num.
+The manual process of creating the `-info` file can also been done by using the opencv_annotation tool. This is an open source tool for visually selecting the regions of interest of your object instances in any given images. The following subsection will discuss in more detail on how to use this application.
 
-opencv_createsamples utility may be used for examining samples stored in positive samples file. In
-order to do this only -vec, -w and -h parameters should be specified.
+#### Extra remarks
 
-Note that for training, it does not matter how vec-files with positive samples are generated. But
-opencv_createsamples utility is the only one way to collect/create a vector file of positive
-samples, provided by OpenCV.
+ - opencv_createsamples utility may be used for examining samples stored in any given positive samples file. In order to do this only `-vec`, `-w` and `-h` parameters should be specified.
+ - Example of vec-file is available here `opencv/data/vec_files/trainingfaces_24-24.vec`. It can be used to train a face detector with the following window size: `-w 24 -h 24`.
 
-Example of vec-file is available here opencv/data/vec_files/trainingfaces_24-24.vec. It can be
-used to train a face detector with the following window size: -w 24 -h 24.
+### Using OpenCV's integrated annotation tool
 
-Cascade Training
-----------------
+Since OpenCV 3.x the community has been supplying and maintaining a open source annotation tool, used for generating the `-info` file. The tool can be accessed by the command opencv_annotation if the OpenCV applications where build.
 
-The next step is the training of classifier. As mentioned above opencv_traincascade or
-opencv_haartraining may be used to train a cascade classifier, but only the newer
-opencv_traincascade will be described futher.
+Using the tool is quite straightforward. The tool accepts several required and some optional parameters:
 
-Command line arguments of opencv_traincascade application grouped by purposes:
+ - `--annotations` <b>(required)</b> : path to annotations txt file, where you want to store your annotations, which is then passed to the `-info` parameter [example - /data/annotations.txt]
+ - `--images` <b>(required)</b> : path to folder containing the images with your objects [example - /data/testimages/]
+ - `--maxWindowHeight` <i>(optional)</i> : if the input image is larger in height then the given resolution here, resize the image for easier annotation, using `--resizeFactor`.
+ - `--resizeFactor` <i>(optional)</i> : factor used to resize the input image when using the `--maxWindowHeight` parameter.
 
--#  Common arguments:
+Note that the optional parameters can only be used together. An example of a command that could be used can be seen below
 
-    -   -data \<cascade_dir_name\>
-
-        Where the trained classifier should be stored.
-
-    -   -vec \<vec_file_name\>
-
-        vec-file with positive samples (created by opencv_createsamples utility).
-
-    -   -bg \<background_file_name\>
-
-        Background description file.
-
-    -   -numPos \<number_of_positive_samples\>
-    -   -numNeg \<number_of_negative_samples\>
-
-        Number of positive/negative samples used in training for every classifier stage.
-
-    -   -numStages \<number_of_stages\>
-
-        Number of cascade stages to be trained.
-
-    -   -precalcValBufSize \<precalculated_vals_buffer_size_in_Mb\>
-
-        Size of buffer for precalculated feature values (in Mb).
-
-    -   -precalcIdxBufSize \<precalculated_idxs_buffer_size_in_Mb\>
-
-        Size of buffer for precalculated feature indices (in Mb). The more memory you have the
-        faster the training process.
-
-    -   -baseFormatSave
-
-        This argument is actual in case of Haar-like features. If it is specified, the cascade will
-        be saved in the old format.
-
-    -   -numThreads \<max_number_of_threads\>
-
-        Maximum number of threads to use during training. Notice that the actual number of used
-        threads may be lower, depending on your machine and compilation options.
-
-    -   -acceptanceRatioBreakValue \<break_value\>
-
-        This argument is used to determine how precise your model should keep learning and when to stop.
-        A good guideline is to train not further than 10e-5, to ensure the model does not overtrain on your training data.
-        By default this value is set to -1 to disable this feature.
-
--#  Cascade parameters:
-
-    -   -stageType \<BOOST(default)\>
+ at code{.text}
+opencv_annotation --annotations=/path/to/annotations/file.txt --images=/path/to/image/folder/
+ at endcode
 
-        Type of stages. Only boosted classifier are supported as a stage type at the moment.
+This command will fire up a window containing the first image and your mouse cursor which will be used for annotation. A video on how to use the annotation tool can be found [here](https://www.youtube.com/watch?v=EV5gmvoCTSk). Basically there are several keystrokes that trigger an action. The left mouse button is used to select the first corner of your object, then keeps drawing until you are fine, and stops when a second left mouse button click is registered. After each selection you ha [...]
 
-    -   -featureType\<{HAAR(default), LBP}\>
+ - Pressing `c` : confirm the annotation, turning the annotation green and confirming it is stored
+ - Pressing `d` : delete the last annotation from the list of annotations (easy for removing wrong annotations)
+ - Pressing `n` : continue to the next image
+ - Pressing `ESC` : this will exit the annotation software
 
-        Type of features: HAAR - Haar-like features, LBP - local binary patterns.
+Finally you will end up with a usable annotation file that can be passed to the `-info` argument of opencv_createsamples.
 
-    -   -w \<sampleWidth\>
-    -   -h \<sampleHeight\>
+Cascade Training
+----------------
 
-        Size of training samples (in pixels). Must have exactly the same values as used during
-        training samples creation (opencv_createsamples utility).
+The next step is the actual training of the boosted cascade of weak classifiers, based on the positive and negative dataset that was prepared beforehand.
 
--#  Boosted classifer parameters:
+Command line arguments of opencv_traincascade application grouped by purposes:
 
-    -   -bt \<{DAB, RAB, LB, GAB(default)}\>
+- Common arguments:
+  - `-data <cascade_dir_name>` : Where the trained classifier should be stored. This folder should be created manually beforehand.
+  - `-vec <vec_file_name>` : vec-file with positive samples (created by opencv_createsamples utility).
+  - `-bg <background_file_name>` : Background description file. This is the file containing the negative sample images.
+  - `-numPos <number_of_positive_samples>` : Number of positive samples used in training for every classifier stage.
+  - `-numNeg <number_of_negative_samples>` : Number of negative samples used in training for every classifier stage.
+  - `-numStages <number_of_stages>` : Number of cascade stages to be trained.
+  - `-precalcValBufSize <precalculated_vals_buffer_size_in_Mb>` : Size of buffer for precalculated feature values (in Mb). The more memory you assign the faster the training process, however keep in mind that `-precalcValBufSize` and `-precalcIdxBufSize` combined should not exceed you available system memory.
+  - `-precalcIdxBufSize <precalculated_idxs_buffer_size_in_Mb>` : Size of buffer for precalculated feature indices (in Mb). The more memory you assign the faster the training process, however keep in mind that `-precalcValBufSize` and `-precalcIdxBufSize` combined should not exceed you available system memory.
+  - `-baseFormatSave` : This argument is actual in case of Haar-like features. If it is specified, the cascade will be saved in the old format. This is only available for backwards compatibility reasons and to allow users stuck to the old deprecated interface, to at least train models using the newer interface.
+  - `-numThreads <max_number_of_threads>` : Maximum number of threads to use during training. Notice that the actual number of used threads may be lower, depending on your machine and compilation options. By default, the maximum available threads are selected if you built OpenCV with TBB support, which is needed for this optimization.
+  - `-acceptanceRatioBreakValue <break_value>` : This argument is used to determine how precise your model should keep learning and when to stop. A good guideline is to train not further than 10e-5, to ensure the model does not overtrain on your training data. By default this value is set to -1 to disable this feature.
 
-        Type of boosted classifiers: DAB - Discrete AdaBoost, RAB - Real AdaBoost, LB - LogitBoost,
-        GAB - Gentle AdaBoost.
+- Cascade parameters:
+  - `-stageType <BOOST(default)>` : Type of stages. Only boosted classifiers are supported as a stage type at the moment.
+  - `-featureType<{HAAR(default), LBP}>` : Type of features: HAAR - Haar-like features, LBP - local binary patterns.
+  - `-w <sampleWidth>` :  Width of training samples (in pixels). Must have exactly the same value as used during training samples creation (opencv_createsamples utility).
+  - `-h <sampleHeight>` : Height of training samples (in pixels). Must have exactly the same value as used during training samples creation (opencv_createsamples utility).
 
-    -   -minHitRate \<min_hit_rate\>
+- Boosted classifer parameters:
+  - `-bt <{DAB, RAB, LB, GAB(default)}>` : Type of boosted classifiers: DAB - Discrete AdaBoost, RAB - Real AdaBoost, LB - LogitBoost, GAB - Gentle AdaBoost.
+  - `-minHitRate <min_hit_rate>` : Minimal desired hit rate for each stage of the classifier. Overall hit rate may be estimated as (min_hit_rate ^ number_of_stages), @cite Viola04 §4.1.
+  - `-maxFalseAlarmRate <max_false_alarm_rate>` : Maximal desired false alarm rate for each stage of the classifier. Overall false alarm rate may be estimated as (max_false_alarm_rate ^ number_of_stages), @cite Viola04 §4.1.
+  - `-weightTrimRate <weight_trim_rate>` : Specifies whether trimming should be used and its weight. A decent choice is 0.95.
+  - `-maxDepth <max_depth_of_weak_tree>` : Maximal depth of a weak tree. A decent choice is 1, that is case of stumps.
+  - `-maxWeakCount <max_weak_tree_count>` : Maximal count of weak trees for every cascade stage. The boosted classifier (stage) will have so many weak trees (<=maxWeakCount), as needed to achieve the given `-maxFalseAlarmRate`.
 
-        Minimal desired hit rate for each stage of the classifier. Overall hit rate may be estimated
-        as (min_hit_rate\^number_of_stages).
+- Haar-like feature parameters:
+  - `-mode <BASIC (default) | CORE | ALL>` : Selects the type of Haar features set used in training. BASIC use only upright features, while ALL uses the full set of upright and 45 degree rotated feature set. See @cite Lienhart02 for more details.
 
-    -   -maxFalseAlarmRate \<max_false_alarm_rate\>
+- Local Binary Patterns parameters: Local Binary Patterns don't have parameters.
 
-        Maximal desired false alarm rate for each stage of the classifier. Overall false alarm rate
-        may be estimated as (max_false_alarm_rate\^number_of_stages).
+After the opencv_traincascade application has finished its work, the trained cascade will be saved in `cascade.xml` file in the `-data` folder. Other files in this folder are created for the case of interrupted training, so you may delete them after completion of training.
 
-    -   -weightTrimRate \<weight_trim_rate\>
+Training is finished and you can test your cascade classifier!
 
-        Specifies whether trimming should be used and its weight. A decent choice is 0.95.
+Visualising Cascade Classifiers
+-------------------------------
 
-    -   -maxDepth \<max_depth_of_weak_tree\>
+From time to time it can be usefull to visualise the trained cascade, to see which features it selected and how complex its stages are. For this OpenCV supplies a opencv_visualisation application. This application has the following commands:
 
-        Maximal depth of a weak tree. A decent choice is 1, that is case of stumps.
+ - `--image` <b>(required)</b> : path to a reference image for your object model. This should be an annotation with dimensions [`-w`,`-h`] as passed to both opencv_createsamples and opencv_traincascade application.
+ - `--model` <b>(required)</b> : path to the trained model, which should be in the folder supplied to the `-data` parameter of the opencv_traincascade application.
+ - `--data` <i>(optional)</i> : if a data folder is supplied, which has to be manually created beforehand, stage output and a video of the features will be stored.
 
-    -   -maxWeakCount \<max_weak_tree_count\>
+An example command can be seen below
 
-        Maximal count of weak trees for every cascade stage. The boosted classifier (stage) will
-        have so many weak trees (\<=maxWeakCount), as needed to achieve the
-        given -maxFalseAlarmRate.
+ at code{.text}
+opencv_visualisation --image=/data/object.png --model=/data/model.xml --data=/data/result/
+ at endcode
 
--#  Haar-like feature parameters:
+Some limitations of the current visualisation tool
+ - Only handles cascade classifier models, trained with the opencv_traincascade tool, containing __stumps__ as decision trees [default settings].
+ - The image provided needs to be a sample window with the original model dimensions, passed to the `--image` parameter.
 
-    -   -mode \<BASIC (default) | CORE | ALL\>
+Example of the HAAR/LBP face model ran on a given window of Angelina Jolie, which had the same preprocessing as cascade classifier files -->24x24 pixel image, grayscale conversion and histogram equalisation:
 
-        Selects the type of Haar features set used in training. BASIC use only upright features,
-        while ALL uses the full set of upright and 45 degree rotated feature set. See @cite Lienhart02
-        for more details.
+_A video is made with for each stage each feature visualised:_
 
--#  Local Binary Patterns parameters:
+![](images/visualisation_video.png)
 
-    Local Binary Patterns don't have parameters.
+_Each stage is stored as an image for future validation of the features:_
 
-After the opencv_traincascade application has finished its work, the trained cascade will be saved
-in cascade.xml file in the folder, which was passed as -data parameter. Other files in this folder
-are created for the case of interrupted training, so you may delete them after completion of
-training.
+![](images/visualisation_single_stage.png)
 
-Training is finished and you can test you cascade classifier!
+_This work was created for [OpenCV 3 Blueprints](https://www.packtpub.com/application-development/opencv-3-blueprints) by StevenPuttemans but Packt Publishing agreed integration into OpenCV._
diff --git a/doc/tutorials/stitching/stitcher/images/boat.jpg b/doc/tutorials/stitching/stitcher/images/boat.jpg
new file mode 100644
index 0000000..da8dd48
Binary files /dev/null and b/doc/tutorials/stitching/stitcher/images/boat.jpg differ
diff --git a/doc/tutorials/stitching/stitcher/images/budapest.jpg b/doc/tutorials/stitching/stitcher/images/budapest.jpg
new file mode 100644
index 0000000..a4cd0d4
Binary files /dev/null and b/doc/tutorials/stitching/stitcher/images/budapest.jpg differ
diff --git a/doc/tutorials/stitching/stitcher/images/newspaper.jpg b/doc/tutorials/stitching/stitcher/images/newspaper.jpg
new file mode 100644
index 0000000..eff7c51
Binary files /dev/null and b/doc/tutorials/stitching/stitcher/images/newspaper.jpg differ
diff --git a/doc/tutorials/stitching/stitcher/stitcher.markdown b/doc/tutorials/stitching/stitcher/stitcher.markdown
new file mode 100644
index 0000000..d28bd21
--- /dev/null
+++ b/doc/tutorials/stitching/stitcher/stitcher.markdown
@@ -0,0 +1,115 @@
+High level stitching API (Stitcher class) {#tutorial_stitcher}
+=========================================
+
+Goal
+----
+
+In this tutorial you will learn how to:
+
+-   use the high-level stitching API for stitching provided by
+    -   @ref cv::Stitcher
+-   learn how to use preconfigured Stitcher configurations to stitch images
+    using different camera models.
+
+Code
+----
+
+This tutorial code's is shown lines below. You can also download it from
+[here](https://github.com/opencv/opencv/tree/master/samples/cpp/samples/cpp/stitching.cpp).
+
+ at include samples/cpp/stitching.cpp
+
+Explanation
+-----------
+
+The most important code part is:
+
+ at code{.cpp}
+Mat pano;
+Ptr<Stitcher> stitcher = Stitcher::create(mode, try_use_gpu);
+Stitcher::Status status = stitcher->stitch(imgs, pano);
+
+if (status != Stitcher::OK)
+{
+    cout << "Can't stitch images, error code = " << int(status) << endl;
+    return -1;
+}
+ at endcode
+
+A new instance of stitcher is created and the @ref cv::Stitcher::stitch will
+do all the hard work.
+
+ at ref cv::Stitcher::create can create stitcher in one of the predefined
+configurations (argument `mode`). See @ref cv::Stitcher::Mode for details. These
+configurations will setup multiple stitcher properties to operate in one of
+predefined scenarios. After you create stitcher in one of predefined
+configurations you can adjust stitching by setting any of the stitcher
+properties.
+
+If you have cuda device @ref cv::Stitcher can be configured to offload certain
+operations to GPU. If you prefer this configuration set `try_use_gpu` to true.
+OpenCL acceleration will be used transparently based on global OpenCV settings
+regardless of this flag.
+
+Stitching might fail for several reasons, you should always check if
+everything went good and resulting pano is stored in `pano`. See
+ at ref cv::Stitcher::Status documentation for possible error codes.
+
+Camera models
+-------------
+
+There are currently 2 camera models implemented in stitching pipeline.
+
+- _Homography model_ expecting perspective transformations between images
+  implemented in @ref cv::detail::BestOf2NearestMatcher cv::detail::HomographyBasedEstimator
+  cv::detail::BundleAdjusterReproj cv::detail::BundleAdjusterRay
+- _Affine model_ expecting affine transformation with 6 DOF or 4 DOF implemented in
+  @ref cv::detail::AffineBestOf2NearestMatcher cv::detail::AffineBasedEstimator
+  cv::detail::BundleAdjusterAffine cv::detail::BundleAdjusterAffinePartial cv::AffineWarper
+
+Homography model is useful for creating photo panoramas captured by camera,
+while affine-based model can be used to stitch scans and object captured by
+specialized devices.
+
+ at note
+Certain detailed settings of @ref cv::Stitcher might not make sense. Especially
+you should not mix classes implementing affine model and classes implementing
+Homography model, as they work with different transformations.
+
+Try it out
+----------
+
+If you enabled building samples you can found binary under
+`build/bin/cpp-example-stitching`. This example is a console application, run it without
+arguments to see help. `opencv_extra` provides some sample data for testing all available
+configurations.
+
+to try panorama mode run:
+```
+./cpp-example-stitching --mode panorama <path to opencv_extra>/testdata/stitching/boat*
+```
+![](images/boat.jpg)
+
+to try scans mode run (dataset from home-grade scanner):
+```
+./cpp-example-stitching --mode scans <path to opencv_extra>/testdata/stitching/newspaper*
+```
+![](images/newspaper.jpg)
+
+or (dataset from professional book scanner):
+```
+./cpp-example-stitching --mode scans <path to opencv_extra>/testdata/stitching/budapest*
+```
+![](images/budapest.jpg)
+
+ at note
+Examples above expects POSIX platform, on windows you have to provide all files names explicitly
+(e.g. `boat1.jpg` `boat2.jpg`...) as windows command line does not support `*` expansion.
+
+See also
+--------
+
+If you want to study internals of the stitching pipeline or you want to experiment with detailed
+configuration see
+[stitching_detailed.cpp](https://github.com/opencv/opencv/tree/master/samples/cpp/stitching_detailed.cpp)
+in `opencv/samples/cpp` folder.
diff --git a/doc/tutorials/stitching/table_of_content_stitching.markdown b/doc/tutorials/stitching/table_of_content_stitching.markdown
new file mode 100644
index 0000000..d85571c
--- /dev/null
+++ b/doc/tutorials/stitching/table_of_content_stitching.markdown
@@ -0,0 +1,15 @@
+Images stitching (stitching module) {#tutorial_table_of_content_stitching}
+===================================
+
+Sometimes a single image can't capture it all. Here you will learn how to join
+more images together to create a large pano. Doesn't matter if you want to
+create a photo panorama or you want to stitch scans.
+
+-   @subpage tutorial_stitcher
+
+    *Compatibility:* \>= OpenCV 3.2
+
+    *Author:* Jiri Horner
+
+    You will use high level stitching api to create a photo panorama. You will
+    learn about Stitcher class and its configurations.
diff --git a/doc/tutorials/tutorials.markdown b/doc/tutorials/tutorials.markdown
index 552420c..1f1a7e9 100644
--- a/doc/tutorials/tutorials.markdown
+++ b/doc/tutorials/tutorials.markdown
@@ -25,10 +25,17 @@ As always, we would be happy to hear your comments and receive your contribution
 
 -   @subpage tutorial_table_of_content_highgui
 
-    This section
-    contains valuable tutorials about how to read/save your image/video files and how to use the
+    This section contains valuable tutorials about how to use the
     built-in graphical user interface of the library.
 
+-   @subpage tutorial_table_of_content_imgcodecs
+
+    These tutorials show how to read and write images using imgcodecs module.
+
+-   @subpage tutorial_table_of_content_videoio
+
+    These tutorials show how to read and write videos using videio module.
+
 -   @subpage tutorial_table_of_content_calib3d
 
     Although we got
@@ -61,6 +68,10 @@ As always, we would be happy to hear your comments and receive your contribution
     Use OpenCV for
     advanced photo processing.
 
+-   @subpage tutorial_table_of_content_stitching
+
+    Learn how to create beautiful photo panoramas and more with OpenCV stitching pipeline.
+
 -   @subpage tutorial_table_of_content_gpu
 
     Squeeze out every
diff --git a/doc/tutorials/video/background_subtraction/background_subtraction.markdown b/doc/tutorials/video/background_subtraction/background_subtraction.markdown
index f9b7eeb..8ed68f5 100644
--- a/doc/tutorials/video/background_subtraction/background_subtraction.markdown
+++ b/doc/tutorials/video/background_subtraction/background_subtraction.markdown
@@ -45,7 +45,7 @@ Two different methods are used to generate two foreground masks:
 -#  @ref cv::BackgroundSubtractorMOG2
 
 The results as well as the input data are shown on the screen.
-The source file can be downloaded [here ](https://github.com/Itseez/opencv/tree/master/samples/cpp/tutorial_code/video/bg_sub.cpp).
+The source file can be downloaded [here ](https://github.com/opencv/opencv/tree/master/samples/cpp/tutorial_code/video/bg_sub.cpp).
 
 @include samples/cpp/tutorial_code/video/bg_sub.cpp
 
diff --git a/doc/tutorials/highgui/images/video-input-psnr-ssim.png b/doc/tutorials/videoio/images/video-input-psnr-ssim.png
similarity index 100%
rename from doc/tutorials/highgui/images/video-input-psnr-ssim.png
rename to doc/tutorials/videoio/images/video-input-psnr-ssim.png
diff --git a/doc/tutorials/highgui/images/video-write.png b/doc/tutorials/videoio/images/video-write.png
similarity index 100%
rename from doc/tutorials/highgui/images/video-write.png
rename to doc/tutorials/videoio/images/video-write.png
diff --git a/doc/tutorials/videoio/intelperc.markdown b/doc/tutorials/videoio/intelperc.markdown
new file mode 100644
index 0000000..188a69e
--- /dev/null
+++ b/doc/tutorials/videoio/intelperc.markdown
@@ -0,0 +1,82 @@
+Using Creative Senz3D and other Intel Perceptual Computing SDK compatible depth sensors {#tutorial_intelperc}
+=======================================================================================
+
+Depth sensors compatible with Intel Perceptual Computing SDK are supported through VideoCapture
+class. Depth map, RGB image and some other formats of output can be retrieved by using familiar
+interface of VideoCapture.
+
+In order to use depth sensor with OpenCV you should do the following preliminary steps:
+
+-#  Install Intel Perceptual Computing SDK (from here <http://www.intel.com/software/perceptual>).
+
+-#  Configure OpenCV with Intel Perceptual Computing SDK support by setting WITH_INTELPERC flag in
+    CMake. If Intel Perceptual Computing SDK is found in install folders OpenCV will be built with
+    Intel Perceptual Computing SDK library (see a status INTELPERC in CMake log). If CMake process
+    doesn't find Intel Perceptual Computing SDK installation folder automatically, the user should
+    change corresponding CMake variables INTELPERC_LIB_DIR and INTELPERC_INCLUDE_DIR to the
+    proper value.
+
+-#  Build OpenCV.
+
+VideoCapture can retrieve the following data:
+
+-#  data given from depth generator:
+    -   CAP_INTELPERC_DEPTH_MAP - each pixel is a 16-bit integer. The value indicates the
+            distance from an object to the camera's XY plane or the Cartesian depth. (CV_16UC1)
+    -   CAP_INTELPERC_UVDEPTH_MAP - each pixel contains two 32-bit floating point values in
+        the range of 0-1, representing the mapping of depth coordinates to the color
+        coordinates. (CV_32FC2)
+    -   CAP_INTELPERC_IR_MAP - each pixel is a 16-bit integer. The value indicates the
+        intensity of the reflected laser beam. (CV_16UC1)
+
+-#  data given from RGB image generator:
+    -   CAP_INTELPERC_IMAGE - color image. (CV_8UC3)
+
+In order to get depth map from depth sensor use VideoCapture::operator \>\>, e. g. :
+ at code{.cpp}
+    VideoCapture capture( CAP_INTELPERC );
+    for(;;)
+    {
+        Mat depthMap;
+        capture >> depthMap;
+
+        if( waitKey( 30 ) >= 0 )
+            break;
+    }
+ at endcode
+For getting several data maps use VideoCapture::grab and VideoCapture::retrieve, e.g. :
+ at code{.cpp}
+    VideoCapture capture(CAP_INTELPERC);
+    for(;;)
+    {
+        Mat depthMap;
+        Mat image;
+        Mat irImage;
+
+        capture.grab();
+
+        capture.retrieve( depthMap, CAP_INTELPERC_DEPTH_MAP );
+        capture.retrieve(    image, CAP_INTELPERC_IMAGE );
+        capture.retrieve(  irImage, CAP_INTELPERC_IR_MAP);
+
+        if( waitKey( 30 ) >= 0 )
+            break;
+    }
+ at endcode
+For setting and getting some property of sensor\` data generators use VideoCapture::set and
+VideoCapture::get methods respectively, e.g. :
+ at code{.cpp}
+    VideoCapture capture( CAP_INTELPERC );
+    capture.set( CAP_INTELPERC_DEPTH_GENERATOR | CAP_PROP_INTELPERC_PROFILE_IDX, 0 );
+    cout << "FPS    " << capture.get( CAP_INTELPERC_DEPTH_GENERATOR+CAP_PROP_FPS ) << endl;
+ at endcode
+Since two types of sensor's data generators are supported (image generator and depth generator),
+there are two flags that should be used to set/get property of the needed generator:
+
+-   CAP_INTELPERC_IMAGE_GENERATOR -- a flag for access to the image generator properties.
+-   CAP_INTELPERC_DEPTH_GENERATOR -- a flag for access to the depth generator properties. This
+    flag value is assumed by default if neither of the two possible values of the property is set.
+
+For more information please refer to the example of usage
+[intelperc_capture.cpp](https://github.com/opencv/tree/master/samples/cpp/intelperc_capture.cpp)
+in opencv/samples/cpp folder.
diff --git a/doc/tutorials/videoio/kinect_openni.markdown b/doc/tutorials/videoio/kinect_openni.markdown
new file mode 100644
index 0000000..82ec13e
--- /dev/null
+++ b/doc/tutorials/videoio/kinect_openni.markdown
@@ -0,0 +1,138 @@
+Using Kinect and other OpenNI compatible depth sensors {#tutorial_kinect_openni}
+======================================================
+
+Depth sensors compatible with OpenNI (Kinect, XtionPRO, ...) are supported through VideoCapture
+class. Depth map, BGR image and some other formats of output can be retrieved by using familiar
+interface of VideoCapture.
+
+In order to use depth sensor with OpenCV you should do the following preliminary steps:
+
+-#  Install OpenNI library (from here <http://www.openni.org/downloadfiles>) and PrimeSensor Module
+    for OpenNI (from here <https://github.com/avin2/SensorKinect>). The installation should be done
+    to default folders listed in the instructions of these products, e.g.:
+    @code{.text}
+    OpenNI:
+        Linux & MacOSX:
+            Libs into: /usr/lib
+            Includes into: /usr/include/ni
+        Windows:
+            Libs into: c:/Program Files/OpenNI/Lib
+            Includes into: c:/Program Files/OpenNI/Include
+    PrimeSensor Module:
+        Linux & MacOSX:
+            Bins into: /usr/bin
+        Windows:
+            Bins into: c:/Program Files/Prime Sense/Sensor/Bin
+    @endcode
+    If one or both products were installed to the other folders, the user should change
+    corresponding CMake variables OPENNI_LIB_DIR, OPENNI_INCLUDE_DIR or/and
+    OPENNI_PRIME_SENSOR_MODULE_BIN_DIR.
+
+-#  Configure OpenCV with OpenNI support by setting WITH_OPENNI flag in CMake. If OpenNI is found
+    in install folders OpenCV will be built with OpenNI library (see a status OpenNI in CMake log)
+    whereas PrimeSensor Modules can not be found (see a status OpenNI PrimeSensor Modules in CMake
+    log). Without PrimeSensor module OpenCV will be successfully compiled with OpenNI library, but
+    VideoCapture object will not grab data from Kinect sensor.
+
+-#  Build OpenCV.
+
+VideoCapture can retrieve the following data:
+
+-#  data given from depth generator:
+    -   CAP_OPENNI_DEPTH_MAP - depth values in mm (CV_16UC1)
+    -   CAP_OPENNI_POINT_CLOUD_MAP - XYZ in meters (CV_32FC3)
+    -   CAP_OPENNI_DISPARITY_MAP - disparity in pixels (CV_8UC1)
+    -   CAP_OPENNI_DISPARITY_MAP_32F - disparity in pixels (CV_32FC1)
+    -   CAP_OPENNI_VALID_DEPTH_MASK - mask of valid pixels (not ocluded, not shaded etc.)
+        (CV_8UC1)
+
+-#  data given from BGR image generator:
+    -   CAP_OPENNI_BGR_IMAGE - color image (CV_8UC3)
+    -   CAP_OPENNI_GRAY_IMAGE - gray image (CV_8UC1)
+
+In order to get depth map from depth sensor use VideoCapture::operator \>\>, e. g. :
+ at code{.cpp}
+    VideoCapture capture( CAP_OPENNI );
+    for(;;)
+    {
+        Mat depthMap;
+        capture >> depthMap;
+
+        if( waitKey( 30 ) >= 0 )
+            break;
+    }
+ at endcode
+For getting several data maps use VideoCapture::grab and VideoCapture::retrieve, e.g. :
+ at code{.cpp}
+    VideoCapture capture(0); // or CAP_OPENNI
+    for(;;)
+    {
+        Mat depthMap;
+        Mat bgrImage;
+
+        capture.grab();
+
+        capture.retrieve( depthMap, CAP_OPENNI_DEPTH_MAP );
+        capture.retrieve( bgrImage, CAP_OPENNI_BGR_IMAGE );
+
+        if( waitKey( 30 ) >= 0 )
+            break;
+    }
+ at endcode
+For setting and getting some property of sensor\` data generators use VideoCapture::set and
+VideoCapture::get methods respectively, e.g. :
+ at code{.cpp}
+    VideoCapture capture( CAP_OPENNI );
+    capture.set( CAP_OPENNI_IMAGE_GENERATOR_OUTPUT_MODE, CAP_OPENNI_VGA_30HZ );
+    cout << "FPS    " << capture.get( CAP_OPENNI_IMAGE_GENERATOR+CAP_PROP_FPS ) << endl;
+ at endcode
+Since two types of sensor's data generators are supported (image generator and depth generator),
+there are two flags that should be used to set/get property of the needed generator:
+
+-   CAP_OPENNI_IMAGE_GENERATOR -- A flag for access to the image generator properties.
+-   CAP_OPENNI_DEPTH_GENERATOR -- A flag for access to the depth generator properties. This flag
+    value is assumed by default if neither of the two possible values of the property is not set.
+
+Some depth sensors (for example XtionPRO) do not have image generator. In order to check it you can
+get CAP_OPENNI_IMAGE_GENERATOR_PRESENT property.
+ at code{.cpp}
+bool isImageGeneratorPresent = capture.get( CAP_PROP_OPENNI_IMAGE_GENERATOR_PRESENT ) != 0; // or == 1
+ at endcode
+Flags specifing the needed generator type must be used in combination with particular generator
+property. The following properties of cameras available through OpenNI interfaces are supported:
+
+-   For image generator:
+
+    -   CAP_PROP_OPENNI_OUTPUT_MODE -- Three output modes are supported: CAP_OPENNI_VGA_30HZ
+        used by default (image generator returns images in VGA resolution with 30 FPS),
+        CAP_OPENNI_SXGA_15HZ (image generator returns images in SXGA resolution with 15 FPS) and
+        CAP_OPENNI_SXGA_30HZ (image generator returns images in SXGA resolution with 30 FPS, the
+        mode is supported by XtionPRO Live); depth generator's maps are always in VGA resolution.
+
+-   For depth generator:
+
+    -   CAP_PROP_OPENNI_REGISTRATION -- Flag that registers the remapping depth map to image map
+        by changing depth generator's view point (if the flag is "on") or sets this view point to
+        its normal one (if the flag is "off"). The registration process’s resulting images are
+        pixel-aligned,which means that every pixel in the image is aligned to a pixel in the depth
+        image.
+
+        Next properties are available for getting only:
+
+    -   CAP_PROP_OPENNI_FRAME_MAX_DEPTH -- A maximum supported depth of Kinect in mm.
+    -   CAP_PROP_OPENNI_BASELINE -- Baseline value in mm.
+    -   CAP_PROP_OPENNI_FOCAL_LENGTH -- A focal length in pixels.
+    -   CAP_PROP_FRAME_WIDTH -- Frame width in pixels.
+    -   CAP_PROP_FRAME_HEIGHT -- Frame height in pixels.
+    -   CAP_PROP_FPS -- Frame rate in FPS.
+
+-   Some typical flags combinations "generator type + property" are defined as single flags:
+
+    -   CAP_OPENNI_IMAGE_GENERATOR_OUTPUT_MODE = CAP_OPENNI_IMAGE_GENERATOR + CAP_PROP_OPENNI_OUTPUT_MODE
+    -   CAP_OPENNI_DEPTH_GENERATOR_BASELINE = CAP_OPENNI_DEPTH_GENERATOR + CAP_PROP_OPENNI_BASELINE
+    -   CAP_OPENNI_DEPTH_GENERATOR_FOCAL_LENGTH = CAP_OPENNI_DEPTH_GENERATOR + CAP_PROP_OPENNI_FOCAL_LENGTH
+    -   CAP_OPENNI_DEPTH_GENERATOR_REGISTRATION = CAP_OPENNI_DEPTH_GENERATOR + CAP_PROP_OPENNI_REGISTRATION
+
+For more information please refer to the example of usage
+[openni_capture.cpp](https://github.com/opencv/tree/master/samples/cpp/openni_capture.cpp) in
+opencv/samples/cpp folder.
diff --git a/doc/tutorials/videoio/table_of_content_videoio.markdown b/doc/tutorials/videoio/table_of_content_videoio.markdown
new file mode 100644
index 0000000..4f62765
--- /dev/null
+++ b/doc/tutorials/videoio/table_of_content_videoio.markdown
@@ -0,0 +1,23 @@
+Video Input and Output (videoio module) {#tutorial_table_of_content_videoio}
+=========================================
+
+This section contains tutorials about how to read/save your video files.
+
+-   @subpage tutorial_video_input_psnr_ssim
+
+    *Compatibility:* \> OpenCV 2.0
+
+    *Author:* Bernát Gábor
+
+    You will learn how to read video streams, and how to calculate similarity values such as PSNR
+    or SSIM.
+
+-   @subpage tutorial_video_write
+
+    *Compatibility:* \> OpenCV 2.0
+
+    *Author:* Bernát Gábor
+
+-   @subpage tutorial_kinect_openni
+
+-   @subpage tutorial_intelperc
diff --git a/doc/tutorials/highgui/video-input-psnr-ssim/images/outputVideoInput.png b/doc/tutorials/videoio/video-input-psnr-ssim/images/outputVideoInput.png
similarity index 100%
rename from doc/tutorials/highgui/video-input-psnr-ssim/images/outputVideoInput.png
rename to doc/tutorials/videoio/video-input-psnr-ssim/images/outputVideoInput.png
diff --git a/doc/tutorials/videoio/video-input-psnr-ssim/video_input_psnr_ssim.markdown b/doc/tutorials/videoio/video-input-psnr-ssim/video_input_psnr_ssim.markdown
new file mode 100644
index 0000000..fdaad3a
--- /dev/null
+++ b/doc/tutorials/videoio/video-input-psnr-ssim/video_input_psnr_ssim.markdown
@@ -0,0 +1,251 @@
+Video Input with OpenCV and similarity measurement {#tutorial_video_input_psnr_ssim}
+==================================================
+
+Goal
+----
+
+Today it is common to have a digital video recording system at your disposal. Therefore, you will
+eventually come to the situation that you no longer process a batch of images, but video streams.
+These may be of two kinds: real-time image feed (in the case of a webcam) or prerecorded and hard
+disk drive stored files. Luckily OpenCV threats these two in the same manner, with the same C++
+class. So here's what you'll learn in this tutorial:
+
+-   How to open and read video streams
+-   Two ways for checking image similarity: PSNR and SSIM
+
+The source code
+---------------
+
+As a test case where to show off these using OpenCV I've created a small program that reads in two
+video files and performs a similarity check between them. This is something you could use to check
+just how well a new video compressing algorithms works. Let there be a reference (original) video
+like [this small Megamind clip
+](https://github.com/opencv/opencv/tree/master/samples/data/Megamind.avi) and [a compressed
+version of it ](https://github.com/opencv/opencv/tree/master/samples/data/Megamind_bugy.avi).
+You may also find the source code and these video file in the
+`samples/data` folder of the OpenCV source library.
+
+ at include cpp/tutorial_code/videoio/video-input-psnr-ssim/video-input-psnr-ssim.cpp
+
+How to read a video stream (online-camera or offline-file)?
+-----------------------------------------------------------
+
+Essentially, all the functionalities required for video manipulation is integrated in the @ref cv::VideoCapture
+C++ class. This on itself builds on the FFmpeg open source library. This is a basic
+dependency of OpenCV so you shouldn't need to worry about this. A video is composed of a succession
+of images, we refer to these in the literature as frames. In case of a video file there is a *frame
+rate* specifying just how long is between two frames. While for the video cameras usually there is a
+limit of just how many frames they can digitalize per second, this property is less important as at
+any time the camera sees the current snapshot of the world.
+
+The first task you need to do is to assign to a @ref cv::VideoCapture class its source. You can do
+this either via the @ref cv::VideoCapture::VideoCapture or its @ref cv::VideoCapture::open function. If this argument is an
+integer then you will bind the class to a camera, a device. The number passed here is the ID of the
+device, assigned by the operating system. If you have a single camera attached to your system its ID
+will probably be zero and further ones increasing from there. If the parameter passed to these is a
+string it will refer to a video file, and the string points to the location and name of the file.
+For example, to the upper source code a valid command line is:
+ at code{.bash}
+video/Megamind.avi video/Megamind_bug.avi  35 10
+ at endcode
+We do a similarity check. This requires a reference and a test case video file. The first two
+arguments refer to this. Here we use a relative address. This means that the application will look
+into its current working directory and open the video folder and try to find inside this the
+*Megamind.avi* and the *Megamind_bug.avi*.
+ at code{.cpp}
+const string sourceReference = argv[1],sourceCompareWith = argv[2];
+
+VideoCapture captRefrnc(sourceReference);
+// or
+VideoCapture captUndTst;
+captUndTst.open(sourceCompareWith);
+ at endcode
+To check if the binding of the class to a video source was successful or not use the @ref cv::VideoCapture::isOpened
+function:
+ at code{.cpp}
+if ( !captRefrnc.isOpened())
+  {
+  cout  << "Could not open reference " << sourceReference << endl;
+  return -1;
+  }
+ at endcode
+Closing the video is automatic when the objects destructor is called. However, if you want to close
+it before this you need to call its @ref cv::VideoCapture::release function. The frames of the video are just
+simple images. Therefore, we just need to extract them from the @ref cv::VideoCapture object and put
+them inside a *Mat* one. The video streams are sequential. You may get the frames one after another
+by the @ref cv::VideoCapture::read or the overloaded \>\> operator:
+ at code{.cpp}
+Mat frameReference, frameUnderTest;
+captRefrnc >> frameReference;
+captUndTst.open(frameUnderTest);
+ at endcode
+The upper read operations will leave empty the *Mat* objects if no frame could be acquired (either
+cause the video stream was closed or you got to the end of the video file). We can check this with a
+simple if:
+ at code{.cpp}
+if( frameReference.empty()  || frameUnderTest.empty())
+{
+ // exit the program
+}
+ at endcode
+A read method is made of a frame grab and a decoding applied on that. You may call explicitly these
+two by using the @ref cv::VideoCapture::grab and then the @ref cv::VideoCapture::retrieve functions.
+
+Videos have many-many information attached to them besides the content of the frames. These are
+usually numbers, however in some case it may be short character sequences (4 bytes or less). Due to
+this to acquire these information there is a general function named @ref cv::VideoCapture::get that returns double
+values containing these properties. Use bitwise operations to decode the characters from a double
+type and conversions where valid values are only integers. Its single argument is the ID of the
+queried property. For example, here we get the size of the frames in the reference and test case
+video file; plus the number of frames inside the reference.
+ at code{.cpp}
+Size refS = Size((int) captRefrnc.get(CAP_PROP_FRAME_WIDTH),
+                 (int) captRefrnc.get(CAP_PROP_FRAME_HEIGHT)),
+
+cout << "Reference frame resolution: Width=" << refS.width << "  Height=" << refS.height
+     << " of nr#: " << captRefrnc.get(CAP_PROP_FRAME_COUNT) << endl;
+ at endcode
+When you are working with videos you may often want to control these values yourself. To do this
+there is a @ref cv::VideoCapture::set function. Its first argument remains the name of the property you want to
+change and there is a second of double type containing the value to be set. It will return true if
+it succeeds and false otherwise. Good examples for this is seeking in a video file to a given time
+or frame:
+ at code{.cpp}
+captRefrnc.set(CAP_PROP_POS_MSEC, 1.2);  // go to the 1.2 second in the video
+captRefrnc.set(CAP_PROP_POS_FRAMES, 10); // go to the 10th frame of the video
+// now a read operation would read the frame at the set position
+ at endcode
+For properties you can read and change look into the documentation of the @ref cv::VideoCapture::get and
+ at ref cv::VideoCapture::set functions.
+
+Image similarity - PSNR and SSIM
+--------------------------------
+
+We want to check just how imperceptible our video converting operation went, therefore we need a
+system to check frame by frame the similarity or differences. The most common algorithm used for
+this is the PSNR (aka **Peak signal-to-noise ratio**). The simplest definition of this starts out
+from the *mean squad error*. Let there be two images: I1 and I2; with a two dimensional size i and
+j, composed of c number of channels.
+
+\f[MSE = \frac{1}{c*i*j} \sum{(I_1-I_2)^2}\f]
+
+Then the PSNR is expressed as:
+
+\f[PSNR = 10 \cdot \log_{10} \left( \frac{MAX_I^2}{MSE} \right)\f]
+
+Here the \f$MAX_I^2\f$ is the maximum valid value for a pixel. In case of the simple single byte image
+per pixel per channel this is 255. When two images are the same the MSE will give zero, resulting in
+an invalid divide by zero operation in the PSNR formula. In this case the PSNR is undefined and as
+we'll need to handle this case separately. The transition to a logarithmic scale is made because the
+pixel values have a very wide dynamic range. All this translated to OpenCV and a C++ function looks
+like:
+ at code{.cpp}
+double getPSNR(const Mat& I1, const Mat& I2)
+{
+ Mat s1;
+ absdiff(I1, I2, s1);       // |I1 - I2|
+ s1.convertTo(s1, CV_32F);  // cannot make a square on 8 bits
+ s1 = s1.mul(s1);           // |I1 - I2|^2
+
+ Scalar s = sum(s1);        // sum elements per channel
+
+ double sse = s.val[0] + s.val[1] + s.val[2]; // sum channels
+
+ if( sse <= 1e-10) // for small values return zero
+     return 0;
+ else
+ {
+     double  mse =sse /(double)(I1.channels() * I1.total());
+     double psnr = 10.0*log10((255*255)/mse);
+     return psnr;
+ }
+}
+ at endcode
+Typically result values are anywhere between 30 and 50 for video compression, where higher is
+better. If the images significantly differ you'll get much lower ones like 15 and so. This
+similarity check is easy and fast to calculate, however in practice it may turn out somewhat
+inconsistent with human eye perception. The **structural similarity** algorithm aims to correct
+this.
+
+Describing the methods goes well beyond the purpose of this tutorial. For that I invite you to read
+the article introducing it. Nevertheless, you can get a good image of it by looking at the OpenCV
+implementation below.
+
+ at sa
+    SSIM is described more in-depth in the: "Z. Wang, A. C. Bovik, H. R. Sheikh and E. P.
+    Simoncelli, "Image quality assessment: From error visibility to structural similarity," IEEE
+    Transactions on Image Processing, vol. 13, no. 4, pp. 600-612, Apr. 2004." article.
+
+ at code{.cpp}
+Scalar getMSSIM( const Mat& i1, const Mat& i2)
+{
+ const double C1 = 6.5025, C2 = 58.5225;
+ /***************************** INITS **********************************/
+ int d     = CV_32F;
+
+ Mat I1, I2;
+ i1.convertTo(I1, d);           // cannot calculate on one byte large values
+ i2.convertTo(I2, d);
+
+ Mat I2_2   = I2.mul(I2);        // I2^2
+ Mat I1_2   = I1.mul(I1);        // I1^2
+ Mat I1_I2  = I1.mul(I2);        // I1 * I2
+
+ /***********************PRELIMINARY COMPUTING ******************************/
+
+ Mat mu1, mu2;   //
+ GaussianBlur(I1, mu1, Size(11, 11), 1.5);
+ GaussianBlur(I2, mu2, Size(11, 11), 1.5);
+
+ Mat mu1_2   =   mu1.mul(mu1);
+ Mat mu2_2   =   mu2.mul(mu2);
+ Mat mu1_mu2 =   mu1.mul(mu2);
+
+ Mat sigma1_2, sigma2_2, sigma12;
+
+ GaussianBlur(I1_2, sigma1_2, Size(11, 11), 1.5);
+ sigma1_2 -= mu1_2;
+
+ GaussianBlur(I2_2, sigma2_2, Size(11, 11), 1.5);
+ sigma2_2 -= mu2_2;
+
+ GaussianBlur(I1_I2, sigma12, Size(11, 11), 1.5);
+ sigma12 -= mu1_mu2;
+
+ ///////////////////////////////// FORMULA ////////////////////////////////
+ Mat t1, t2, t3;
+
+ t1 = 2 * mu1_mu2 + C1;
+ t2 = 2 * sigma12 + C2;
+ t3 = t1.mul(t2);              // t3 = ((2*mu1_mu2 + C1).*(2*sigma12 + C2))
+
+ t1 = mu1_2 + mu2_2 + C1;
+ t2 = sigma1_2 + sigma2_2 + C2;
+ t1 = t1.mul(t2);               // t1 =((mu1_2 + mu2_2 + C1).*(sigma1_2 + sigma2_2 + C2))
+
+ Mat ssim_map;
+ divide(t3, t1, ssim_map);      // ssim_map =  t3./t1;
+
+ Scalar mssim = mean( ssim_map ); // mssim = average of ssim map
+ return mssim;
+}
+ at endcode
+This will return a similarity index for each channel of the image. This value is between zero and
+one, where one corresponds to perfect fit. Unfortunately, the many Gaussian blurring is quite
+costly, so while the PSNR may work in a real time like environment (24 frame per second) this will
+take significantly more than to accomplish similar performance results.
+
+Therefore, the source code presented at the start of the tutorial will perform the PSNR measurement
+for each frame, and the SSIM only for the frames where the PSNR falls below an input value. For
+visualization purpose we show both images in an OpenCV window and print the PSNR and MSSIM values to
+the console. Expect to see something like:
+
+![](images/outputVideoInput.png)
+
+You may observe a runtime instance of this on the [YouTube here](https://www.youtube.com/watch?v=iOcNljutOgg).
+
+\htmlonly
+<div align="center">
+<iframe title="Video Input with OpenCV (Plus PSNR and MSSIM)" width="560" height="349" src="http://www.youtube.com/embed/iOcNljutOgg?rel=0&loop=1" frameborder="0" allowfullscreen align="middle"></iframe>
+</div>
+\endhtmlonly
diff --git a/doc/tutorials/highgui/video-write/images/resultOutputWideoWrite.png b/doc/tutorials/videoio/video-write/images/resultOutputWideoWrite.png
similarity index 100%
rename from doc/tutorials/highgui/video-write/images/resultOutputWideoWrite.png
rename to doc/tutorials/videoio/video-write/images/resultOutputWideoWrite.png
diff --git a/doc/tutorials/highgui/video-write/images/videoCompressSelect.png b/doc/tutorials/videoio/video-write/images/videoCompressSelect.png
similarity index 100%
rename from doc/tutorials/highgui/video-write/images/videoCompressSelect.png
rename to doc/tutorials/videoio/video-write/images/videoCompressSelect.png
diff --git a/doc/tutorials/highgui/video-write/images/videoFileStructure.png b/doc/tutorials/videoio/video-write/images/videoFileStructure.png
similarity index 100%
rename from doc/tutorials/highgui/video-write/images/videoFileStructure.png
rename to doc/tutorials/videoio/video-write/images/videoFileStructure.png
diff --git a/doc/tutorials/videoio/video-write/video_write.markdown b/doc/tutorials/videoio/video-write/video_write.markdown
new file mode 100644
index 0000000..38c9151
--- /dev/null
+++ b/doc/tutorials/videoio/video-write/video_write.markdown
@@ -0,0 +1,160 @@
+Creating a video with OpenCV {#tutorial_video_write}
+============================
+
+Goal
+----
+
+Whenever you work with video feeds you may eventually want to save your image processing result in a
+form of a new video file. For simple video outputs you can use the OpenCV built-in @ref cv::VideoWriter
+class, designed for this.
+
+-   How to create a video file with OpenCV
+-   What type of video files you can create with OpenCV
+-   How to extract a given color channel from a video
+
+As a simple demonstration I'll just extract one of the BGR color channels of an input video file
+into a new video. You can control the flow of the application from its console line arguments:
+
+-   The first argument points to the video file to work on
+-   The second argument may be one of the characters: R G B. This will specify which of the channels
+    to extract.
+-   The last argument is the character Y (Yes) or N (No). If this is no, the codec used for the
+    input video file will be the same as for the output. Otherwise, a window will pop up and allow
+    you to select yourself the codec to use.
+
+For example, a valid command line would look like:
+ at code{.bash}
+video-write.exe video/Megamind.avi R Y
+ at endcode
+The source code
+---------------
+
+You may also find the source code and these video file in the
+`samples/cpp/tutorial_code/videoio/video-write/` folder of the OpenCV source library or [download it
+from here ](https://github.com/opencv/opencv/tree/master/samples/cpp/tutorial_code/videoio/video-write/video-write.cpp).
+
+ at include cpp/tutorial_code/videoio/video-write/video-write.cpp
+
+The structure of a video
+------------------------
+
+For start, you should have an idea of just how a video file looks. Every video file in itself is a
+container. The type of the container is expressed in the files extension (for example *avi*, *mov*
+or *mkv*). This contains multiple elements like: video feeds, audio feeds or other tracks (like for
+example subtitles). How these feeds are stored is determined by the codec used for each one of them.
+In case of the audio tracks commonly used codecs are *mp3* or *aac*. For the video files the list is
+somehow longer and includes names such as *XVID*, *DIVX*, *H264* or *LAGS* (*Lagarith Lossless
+Codec*). The full list of codecs you may use on a system depends on just what one you have
+installed.
+
+![](images/videoFileStructure.png)
+
+As you can see things can get really complicated with videos. However, OpenCV is mainly a computer
+vision library, not a video stream, codec and write one. Therefore, the developers tried to keep
+this part as simple as possible. Due to this OpenCV for video containers supports only the *avi*
+extension, its first version. A direct limitation of this is that you cannot save a video file
+larger than 2 GB. Furthermore you can only create and expand a single video track inside the
+container. No audio or other track editing support here. Nevertheless, any video codec present on
+your system might work. If you encounter some of these limitations you will need to look into more
+specialized video writing libraries such as *FFMpeg* or codecs as *HuffYUV*, *CorePNG* and *LCL*. As
+an alternative, create the video track with OpenCV and expand it with sound tracks or convert it to
+other formats by using video manipulation programs such as *VirtualDub* or *AviSynth*.
+
+The *VideoWriter* class
+-----------------------
+
+The content written here builds on the assumption you
+already read the @ref tutorial_video_input_psnr_ssim tutorial and you know how to read video files. To create a
+video file you just need to create an instance of the @ref cv::VideoWriter class. You can specify
+its properties either via parameters in the constructor or later on via the @ref cv::VideoWriter::open function.
+Either way, the parameters are the same: 1. The name of the output that contains the container type
+in its extension. At the moment only *avi* is supported. We construct this from the input file, add
+to this the name of the channel to use, and finish it off with the container extension.
+ at code{.cpp}
+const string source      = argv[1];            // the source file name
+string::size_type pAt = source.find_last_of('.');   // Find extension point
+const string NAME = source.substr(0, pAt) + argv[2][0] + ".avi";   // Form the new name with container
+ at endcode
+-#  The codec to use for the video track. Now all the video codecs have a unique short name of
+    maximum four characters. Hence, the *XVID*, *DIVX* or *H264* names. This is called a four
+    character code. You may also ask this from an input video by using its *get* function. Because
+    the *get* function is a general function it always returns double values. A double value is
+    stored on 64 bits. Four characters are four bytes, meaning 32 bits. These four characters are
+    coded in the lower 32 bits of the *double*. A simple way to throw away the upper 32 bits would
+    be to just convert this value to *int*:
+    @code{.cpp}
+    VideoCapture inputVideo(source);                                // Open input
+    int ex = static_cast<int>(inputVideo.get(CAP_PROP_FOURCC));     // Get Codec Type- Int form
+    @endcode
+    OpenCV internally works with this integer type and expect this as its second parameter. Now to
+    convert from the integer form to string we may use two methods: a bitwise operator and a union
+    method. The first one extracting from an int the characters looks like (an "and" operation, some
+    shifting and adding a 0 at the end to close the string):
+    @code{.cpp}
+    char EXT[] = {ex & 0XFF , (ex & 0XFF00) >> 8,(ex & 0XFF0000) >> 16,(ex & 0XFF000000) >> 24, 0};
+    @endcode
+    You can do the same thing with the *union* as:
+    @code{.cpp}
+    union { int v; char c[5];} uEx ;
+    uEx.v = ex;                              // From Int to char via union
+    uEx.c[4]='\0';
+    @endcode
+    The advantage of this is that the conversion is done automatically after assigning, while for
+    the bitwise operator you need to do the operations whenever you change the codec type. In case
+    you know the codecs four character code beforehand, you can use the *CV_FOURCC* macro to build
+    the integer:
+    @code{.cpp}
+    CV_FOURCC('P','I','M,'1') // this is an MPEG1 codec from the characters to integer
+    @endcode
+    If you pass for this argument minus one than a window will pop up at runtime that contains all
+    the codec installed on your system and ask you to select the one to use:
+
+    ![](images/videoCompressSelect.png)
+
+-#  The frame per second for the output video. Again, here I keep the input videos frame per second
+    by using the *get* function.
+-#  The size of the frames for the output video. Here too I keep the input videos frame size per
+    second by using the *get* function.
+-#  The final argument is an optional one. By default is true and says that the output will be a
+    colorful one (so for write you will send three channel images). To create a gray scale video
+    pass a false parameter here.
+
+Here it is, how I use it in the sample:
+ at code{.cpp}
+VideoWriter outputVideo;
+Size S = Size((int) inputVideo.get(CAP_PROP_FRAME_WIDTH),    //Acquire input size
+              (int) inputVideo.get(CAP_PROP_FRAME_HEIGHT));
+outputVideo.open(NAME , ex, inputVideo.get(CAP_PROP_FPS),S, true);
+ at endcode
+Afterwards, you use the @ref cv::VideoWriter::isOpened() function to find out if the open operation succeeded or
+not. The video file automatically closes when the *VideoWriter* object is destroyed. After you open
+the object with success you can send the frames of the video in a sequential order by using the
+ at ref cv::VideoWriter::write function of the class. Alternatively, you can use its overloaded operator \<\< :
+ at code{.cpp}
+outputVideo.write(res);  //or
+outputVideo << res;
+ at endcode
+Extracting a color channel from an BGR image means to set to zero the BGR values of the other
+channels. You can either do this with image scanning operations or by using the split and merge
+operations. You first split the channels up into different images, set the other channels to zero
+images of the same size and type and finally merge them back:
+ at code{.cpp}
+split(src, spl);                 // process - extract only the correct channel
+for( int i =0; i < 3; ++i)
+   if (i != channel)
+      spl[i] = Mat::zeros(S, spl[0].type());
+merge(spl, res);
+ at endcode
+Put all this together and you'll get the upper source code, whose runtime result will show something
+around the idea:
+
+![](images/resultOutputWideoWrite.png)
+
+You may observe a runtime instance of this on the [YouTube
+here](https://www.youtube.com/watch?v=jpBwHxsl1_0).
+
+\htmlonly
+<div align="center">
+<iframe title="Creating a video with OpenCV" width="560" height="349" src="http://www.youtube.com/embed/jpBwHxsl1_0?rel=0&loop=1" frameborder="0" allowfullscreen align="middle"></iframe>
+</div>
+\endhtmlonly
diff --git a/doc/tutorials/viz/creating_widgets/creating_widgets.markdown b/doc/tutorials/viz/creating_widgets/creating_widgets.markdown
index ea84fe3..4e4f6e5 100644
--- a/doc/tutorials/viz/creating_widgets/creating_widgets.markdown
+++ b/doc/tutorials/viz/creating_widgets/creating_widgets.markdown
@@ -12,7 +12,7 @@ In this tutorial you will learn how to
 Code
 ----
 
-You can download the code from [here ](https://github.com/Itseez/opencv/tree/master/samples/cpp/tutorial_code/viz/creating_widgets.cpp).
+You can download the code from [here ](https://github.com/opencv/opencv/tree/master/samples/cpp/tutorial_code/viz/creating_widgets.cpp).
 @include samples/cpp/tutorial_code/viz/creating_widgets.cpp
 
 Explanation
diff --git a/doc/tutorials/viz/launching_viz/launching_viz.markdown b/doc/tutorials/viz/launching_viz/launching_viz.markdown
index 25914dc..07719c6 100644
--- a/doc/tutorials/viz/launching_viz/launching_viz.markdown
+++ b/doc/tutorials/viz/launching_viz/launching_viz.markdown
@@ -14,7 +14,7 @@ In this tutorial you will learn how to
 Code
 ----
 
-You can download the code from [here ](https://github.com/Itseez/opencv/tree/master/samples/cpp/tutorial_code/viz/launching_viz.cpp).
+You can download the code from [here ](https://github.com/opencv/opencv/tree/master/samples/cpp/tutorial_code/viz/launching_viz.cpp).
 @include samples/cpp/tutorial_code/viz/launching_viz.cpp
 
 Explanation
diff --git a/doc/tutorials/viz/transformations/transformations.markdown b/doc/tutorials/viz/transformations/transformations.markdown
index 8b9c1f6..512ce80 100644
--- a/doc/tutorials/viz/transformations/transformations.markdown
+++ b/doc/tutorials/viz/transformations/transformations.markdown
@@ -13,7 +13,7 @@ In this tutorial you will learn how to
 Code
 ----
 
-You can download the code from [here ](https://github.com/Itseez/opencv/tree/master/samples/cpp/tutorial_code/viz/transformations.cpp).
+You can download the code from [here ](https://github.com/opencv/opencv/tree/master/samples/cpp/tutorial_code/viz/transformations.cpp).
 @include samples/cpp/tutorial_code/viz/transformations.cpp
 
 Explanation
diff --git a/doc/tutorials/viz/widget_pose/widget_pose.markdown b/doc/tutorials/viz/widget_pose/widget_pose.markdown
index 7e6a1b9..382ae98 100644
--- a/doc/tutorials/viz/widget_pose/widget_pose.markdown
+++ b/doc/tutorials/viz/widget_pose/widget_pose.markdown
@@ -13,7 +13,7 @@ In this tutorial you will learn how to
 Code
 ----
 
-You can download the code from [here ](https://github.com/Itseez/opencv/tree/master/samples/cpp/tutorial_code/viz/widget_pose.cpp).
+You can download the code from [here ](https://github.com/opencv/opencv/tree/master/samples/cpp/tutorial_code/viz/widget_pose.cpp).
 @include samples/cpp/tutorial_code/viz/widget_pose.cpp
 
 Explanation
diff --git a/include/opencv/cv.h b/include/opencv/cv.h
index 0aefc6d..19a74e2 100644
--- a/include/opencv/cv.h
+++ b/include/opencv/cv.h
@@ -40,8 +40,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_OLD_CV_H__
-#define __OPENCV_OLD_CV_H__
+#ifndef OPENCV_OLD_CV_H
+#define OPENCV_OLD_CV_H
 
 #if defined(_MSC_VER)
     #define CV_DO_PRAGMA(x) __pragma(x)
diff --git a/include/opencv/cv.hpp b/include/opencv/cv.hpp
index e498d7a..8673956 100644
--- a/include/opencv/cv.hpp
+++ b/include/opencv/cv.hpp
@@ -40,8 +40,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_OLD_CV_HPP__
-#define __OPENCV_OLD_CV_HPP__
+#ifndef OPENCV_OLD_CV_HPP
+#define OPENCV_OLD_CV_HPP
 
 //#if defined(__GNUC__)
 //#warning "This is a deprecated opencv header provided for compatibility. Please include a header from a corresponding opencv module"
diff --git a/include/opencv/cvaux.h b/include/opencv/cvaux.h
index fe86c5d..c0367cc 100644
--- a/include/opencv/cvaux.h
+++ b/include/opencv/cvaux.h
@@ -39,8 +39,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_OLD_AUX_H__
-#define __OPENCV_OLD_AUX_H__
+#ifndef OPENCV_OLD_AUX_H
+#define OPENCV_OLD_AUX_H
 
 //#if defined(__GNUC__)
 //#warning "This is a deprecated opencv header provided for compatibility. Please include a header from a corresponding opencv module"
diff --git a/include/opencv/cvaux.hpp b/include/opencv/cvaux.hpp
index b0e60a3..4888eef 100644
--- a/include/opencv/cvaux.hpp
+++ b/include/opencv/cvaux.hpp
@@ -39,8 +39,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_OLD_AUX_HPP__
-#define __OPENCV_OLD_AUX_HPP__
+#ifndef OPENCV_OLD_AUX_HPP
+#define OPENCV_OLD_AUX_HPP
 
 //#if defined(__GNUC__)
 //#warning "This is a deprecated opencv header provided for compatibility. Please include a header from a corresponding opencv module"
diff --git a/include/opencv/cvwimage.h b/include/opencv/cvwimage.h
index de89c92..ec0ab14 100644
--- a/include/opencv/cvwimage.h
+++ b/include/opencv/cvwimage.h
@@ -38,8 +38,8 @@
 // the use of this software, even if advised of the possibility of such damage.
 
 
-#ifndef __OPENCV_OLD_WIMAGE_HPP__
-#define __OPENCV_OLD_WIMAGE_HPP__
+#ifndef OPENCV_OLD_WIMAGE_HPP
+#define OPENCV_OLD_WIMAGE_HPP
 
 #include "opencv2/core/wimage.hpp"
 
diff --git a/include/opencv/cxcore.h b/include/opencv/cxcore.h
index 0982bd7..dc070c7 100644
--- a/include/opencv/cxcore.h
+++ b/include/opencv/cxcore.h
@@ -40,8 +40,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_OLD_CXCORE_H__
-#define __OPENCV_OLD_CXCORE_H__
+#ifndef OPENCV_OLD_CXCORE_H
+#define OPENCV_OLD_CXCORE_H
 
 //#if defined(__GNUC__)
 //#warning "This is a deprecated opencv header provided for compatibility. Please include a header from a corresponding opencv module"
diff --git a/include/opencv/cxcore.hpp b/include/opencv/cxcore.hpp
index 9af4ac7..c371677 100644
--- a/include/opencv/cxcore.hpp
+++ b/include/opencv/cxcore.hpp
@@ -40,8 +40,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_OLD_CXCORE_HPP__
-#define __OPENCV_OLD_CXCORE_HPP__
+#ifndef OPENCV_OLD_CXCORE_HPP
+#define OPENCV_OLD_CXCORE_HPP
 
 //#if defined(__GNUC__)
 //#warning "This is a deprecated opencv header provided for compatibility. Please include a header from a corresponding opencv module"
diff --git a/include/opencv/cxeigen.hpp b/include/opencv/cxeigen.hpp
index 1f04d1a..1d3df91 100644
--- a/include/opencv/cxeigen.hpp
+++ b/include/opencv/cxeigen.hpp
@@ -40,8 +40,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_OLD_EIGEN_HPP__
-#define __OPENCV_OLD_EIGEN_HPP__
+#ifndef OPENCV_OLD_EIGEN_HPP
+#define OPENCV_OLD_EIGEN_HPP
 
 #include "opencv2/core/eigen.hpp"
 
diff --git a/include/opencv/cxmisc.h b/include/opencv/cxmisc.h
index 6c93a0c..9b9bc82 100644
--- a/include/opencv/cxmisc.h
+++ b/include/opencv/cxmisc.h
@@ -1,5 +1,5 @@
-#ifndef __OPENCV_OLD_CXMISC_H__
-#define __OPENCV_OLD_CXMISC_H__
+#ifndef OPENCV_OLD_CXMISC_H
+#define OPENCV_OLD_CXMISC_H
 
 #ifdef __cplusplus
 #  include "opencv2/core/utility.hpp"
diff --git a/include/opencv/highgui.h b/include/opencv/highgui.h
index 0261029..69b394e 100644
--- a/include/opencv/highgui.h
+++ b/include/opencv/highgui.h
@@ -39,8 +39,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_OLD_HIGHGUI_H__
-#define __OPENCV_OLD_HIGHGUI_H__
+#ifndef OPENCV_OLD_HIGHGUI_H
+#define OPENCV_OLD_HIGHGUI_H
 
 #include "opencv2/core/core_c.h"
 #include "opencv2/highgui/highgui_c.h"
diff --git a/include/opencv/ml.h b/include/opencv/ml.h
index d8e967f..0c376ba 100644
--- a/include/opencv/ml.h
+++ b/include/opencv/ml.h
@@ -38,8 +38,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_OLD_ML_H__
-#define __OPENCV_OLD_ML_H__
+#ifndef OPENCV_OLD_ML_H
+#define OPENCV_OLD_ML_H
 
 #include "opencv2/core/core_c.h"
 #include "opencv2/ml.hpp"
diff --git a/include/opencv2/opencv.hpp b/include/opencv2/opencv.hpp
index fd9ca58..532d7a3 100644
--- a/include/opencv2/opencv.hpp
+++ b/include/opencv2/opencv.hpp
@@ -40,19 +40,97 @@
 //
 //M*/
 
-#ifndef __OPENCV_ALL_HPP__
-#define __OPENCV_ALL_HPP__
+#ifndef OPENCV_ALL_HPP
+#define OPENCV_ALL_HPP
 
+// File that defines what modules where included during the build of OpenCV
+// These are purely the defines of the correct HAVE_OPENCV_modulename values
+#include "opencv2/opencv_modules.hpp"
+
+// Then the list of defines is checked to include the correct headers
+// Core library is always included --> without no OpenCV functionality available
 #include "opencv2/core.hpp"
+
+// Then the optional modules are checked
+#ifdef HAVE_OPENCV_CALIB3D
+#include "opencv2/calib3d.hpp"
+#endif
+#ifdef HAVE_OPENCV_FEATURES2D
+#include "opencv2/features2d.hpp"
+#endif
+#ifdef HAVE_OPENCV_FLANN
+#include "opencv2/flann.hpp"
+#endif
+#ifdef HAVE_OPENCV_HIGHGUI
+#include "opencv2/highgui.hpp"
+#endif
+#ifdef HAVE_OPENCV_IMGCODECS
+#include "opencv2/imgcodecs.hpp"
+#endif
+#ifdef HAVE_OPENCV_IMGPROC
 #include "opencv2/imgproc.hpp"
+#endif
+#ifdef HAVE_OPENCV_ML
+#include "opencv2/ml.hpp"
+#endif
+#ifdef HAVE_OPENCV_OBJDETECT
+#include "opencv2/objdetect.hpp"
+#endif
+#ifdef HAVE_OPENCV_PHOTO
 #include "opencv2/photo.hpp"
+#endif
+#ifdef HAVE_OPENCV_SHAPE
+#include "opencv2/shape.hpp"
+#endif
+#ifdef HAVE_OPENCV_STITCHING
+#include "opencv2/stitching.hpp"
+#endif
+#ifdef HAVE_OPENCV_SUPERRES
+#include "opencv2/superres.hpp"
+#endif
+#ifdef HAVE_OPENCV_VIDEO
 #include "opencv2/video.hpp"
-#include "opencv2/features2d.hpp"
-#include "opencv2/objdetect.hpp"
-#include "opencv2/calib3d.hpp"
-#include "opencv2/imgcodecs.hpp"
+#endif
+#ifdef HAVE_OPENCV_VIDEOIO
 #include "opencv2/videoio.hpp"
-#include "opencv2/highgui.hpp"
-#include "opencv2/ml.hpp"
+#endif
+#ifdef HAVE_OPENCV_VIDEOSTAB
+#include "opencv2/videostab.hpp"
+#endif
+#ifdef HAVE_OPENCV_VIZ
+#include "opencv2/viz.hpp"
+#endif
+
+// Finally CUDA specific entries are checked and added
+#ifdef HAVE_OPENCV_CUDAARITHM
+#include "opencv2/cudaarithm.hpp"
+#endif
+#ifdef HAVE_OPENCV_CUDABGSEGM
+#include "opencv2/cudabgsegm.hpp"
+#endif
+#ifdef HAVE_OPENCV_CUDACODEC
+#include "opencv2/cudacodec.hpp"
+#endif
+#ifdef HAVE_OPENCV_CUDAFEATURES2D
+#include "opencv2/cudafeatures2d.hpp"
+#endif
+#ifdef HAVE_OPENCV_CUDAFILTERS
+#include "opencv2/cudafilters.hpp"
+#endif
+#ifdef HAVE_OPENCV_CUDAIMGPROC
+#include "opencv2/cudaimgproc.hpp"
+#endif
+#ifdef HAVE_OPENCV_CUDAOBJDETECT
+#include "opencv2/cudaobjdetect.hpp"
+#endif
+#ifdef HAVE_OPENCV_CUDAOPTFLOW
+#include "opencv2/cudaoptflow.hpp"
+#endif
+#ifdef HAVE_OPENCV_CUDASTEREO
+#include "opencv2/cudastereo.hpp"
+#endif
+#ifdef HAVE_OPENCV_CUDAWARPING
+#include "opencv2/cudawarping.hpp"
+#endif
 
 #endif
diff --git a/modules/calib3d/doc/pics/distortion_examples.png b/modules/calib3d/doc/pics/distortion_examples.png
new file mode 100644
index 0000000..4650d44
Binary files /dev/null and b/modules/calib3d/doc/pics/distortion_examples.png differ
diff --git a/modules/calib3d/doc/pics/pinhole_camera_model.png b/modules/calib3d/doc/pics/pinhole_camera_model.png
new file mode 100644
index 0000000..3594de9
Binary files /dev/null and b/modules/calib3d/doc/pics/pinhole_camera_model.png differ
diff --git a/modules/calib3d/include/opencv2/calib3d.hpp b/modules/calib3d/include/opencv2/calib3d.hpp
index ddffffe..362e81f 100644
--- a/modules/calib3d/include/opencv2/calib3d.hpp
+++ b/modules/calib3d/include/opencv2/calib3d.hpp
@@ -41,8 +41,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_CALIB3D_HPP__
-#define __OPENCV_CALIB3D_HPP__
+#ifndef OPENCV_CALIB3D_HPP
+#define OPENCV_CALIB3D_HPP
 
 #include "opencv2/core.hpp"
 #include "opencv2/features2d.hpp"
@@ -96,6 +96,10 @@ u = f_x*x' + c_x \\
 v = f_y*y' + c_y
 \end{array}\f]
 
+The following figure illustrates the pinhole camera model.
+
+![Pinhole camera model](pics/pinhole_camera_model.png)
+
 Real lenses usually have some distortion, mostly radial distortion and slight tangential distortion.
 So, the above model is extended as:
 
@@ -114,6 +118,10 @@ v = f_y*y'' + c_y
 tangential distortion coefficients. \f$s_1\f$, \f$s_2\f$, \f$s_3\f$, and \f$s_4\f$, are the thin prism distortion
 coefficients. Higher-order coefficients are not considered in OpenCV.
 
+The next figure shows two common types of radial distortion: barrel distortion (typically \f$ k_1 > 0 \f$ and pincushion distortion (typically \f$ k_1 < 0 \f$).
+
+![](pics/distortion_examples.png)
+
 In some cases the image sensor may be tilted in order to focus an oblique plane in front of the
 camera (Scheimpfug condition). This can be useful for particle image velocimetry (PIV) or
 triangulation with a laser fan. The tilt causes a perspective distortion of \f$x''\f$ and
@@ -190,7 +198,7 @@ pattern (every view is described by several 3D-2D point correspondences).
 
     \f[x = Xc_1 \\ y = Xc_2 \\ z = Xc_3\f]
 
-    The pinehole projection coordinates of P is [a; b] where
+    The pinhole projection coordinates of P is [a; b] where
 
     \f[a = x / z \ and \ b = y / z \\ r^2 = a^2 + b^2 \\ \theta = atan(r)\f]
 
@@ -200,12 +208,12 @@ pattern (every view is described by several 3D-2D point correspondences).
 
     The distorted point coordinates are [x'; y'] where
 
-    \f[x' = (\theta_d / r) x \\ y' = (\theta_d / r) y \f]
+    \f[x' = (\theta_d / r) a \\ y' = (\theta_d / r) b \f]
 
     Finally, conversion into pixel coordinates: The final pixel coordinates vector [u; v] where:
 
     \f[u = f_x (x' + \alpha y') + c_x \\
-    v = f_y yy + c_y\f]
+    v = f_y y' + c_y\f]
 
     @defgroup calib3d_c C API
 
@@ -259,6 +267,7 @@ enum { CALIB_USE_INTRINSIC_GUESS = 0x00001,
        CALIB_FIX_S1_S2_S3_S4     = 0x10000,
        CALIB_TILTED_MODEL        = 0x40000,
        CALIB_FIX_TAUX_TAUY       = 0x80000,
+       CALIB_USE_QR              = 0x100000, //!< use QR instead of SVD decomposition for solving. Faster but potentially less precise
        // only for stereo
        CALIB_FIX_INTRINSIC       = 0x00100,
        CALIB_SAME_FOCAL_LENGTH   = 0x00200,
@@ -316,7 +325,7 @@ mask values are ignored.
 @param maxIters The maximum number of RANSAC iterations, 2000 is the maximum it can be.
 @param confidence Confidence level, between 0 and 1.
 
-The functions find and return the perspective transformation \f$H\f$ between the source and the
+The function finds and returns the perspective transformation \f$H\f$ between the source and the
 destination planes:
 
 \f[s_i  \vecthree{x'_i}{y'_i}{1} \sim H  \vecthree{x_i}{y_i}{1}\f]
@@ -351,8 +360,9 @@ determined up to a scale. Thus, it is normalized so that \f$h_{33}=1\f$. Note th
 cannot be estimated, an empty one will be returned.
 
 @sa
-   getAffineTransform, getPerspectiveTransform, estimateRigidTransform, warpPerspective,
-    perspectiveTransform
+getAffineTransform, estimateAffine2D, estimateAffinePartial2D, getPerspectiveTransform, warpPerspective,
+perspectiveTransform
+
 
 @note
    -   A example on calculating a homography for image matching can be found at
@@ -383,7 +393,7 @@ and a rotation matrix.
 
 It optionally returns three rotation matrices, one for each axis, and the three Euler angles in
 degrees (as the return value) that could be used in OpenGL. Note, there is always more than one
-sequence of rotations about the three principle axes that results in the same orientation of an
+sequence of rotations about the three principal axes that results in the same orientation of an
 object, eg. see @cite Slabaugh . Returned tree rotation matrices and corresponding three Euler angules
 are only one of the possible solutions.
  */
@@ -409,7 +419,7 @@ matrix and the position of a camera.
 
 It optionally returns three rotation matrices, one for each axis, and three Euler angles that could
 be used in OpenGL. Note, there is always more than one sequence of rotations about the three
-principle axes that results in the same orientation of an object, eg. see @cite Slabaugh . Returned
+principal axes that results in the same orientation of an object, eg. see @cite Slabaugh . Returned
 tree rotation matrices and corresponding three Euler angules are only one of the possible solutions.
 
 The function is based on RQDecomp3x3 .
@@ -515,9 +525,9 @@ CV_EXPORTS_W void projectPoints( InputArray objectPoints,
 
 /** @brief Finds an object pose from 3D-2D point correspondences.
 
- at param objectPoints Array of object points in the object coordinate space, 3xN/Nx3 1-channel or
+ at param objectPoints Array of object points in the object coordinate space, Nx3 1-channel or
 1xN/Nx1 3-channel, where N is the number of points. vector\<Point3f\> can be also passed here.
- at param imagePoints Array of corresponding image points, 2xN/Nx2 1-channel or 1xN/Nx1 2-channel,
+ at param imagePoints Array of corresponding image points, Nx2 1-channel or 1xN/Nx1 2-channel,
 where N is the number of points. vector\<Point2f\> can be also passed here.
 @param cameraMatrix Input camera matrix \f$A = \vecthreethree{fx}{0}{cx}{0}{fy}{cy}{0}{0}{1}\f$ .
 @param distCoeffs Input vector of distortion coefficients
@@ -564,6 +574,9 @@ projections, as well as the camera matrix and the distortion coefficients.
         - Thus, given some data D = np.array(...) where D.shape = (N,M), in order to use a subset of
         it as, e.g., imagePoints, one must effectively copy it into a new array: imagePoints =
         np.ascontiguousarray(D[:,:2]).reshape((N,1,2))
+   -   The methods **SOLVEPNP_DLS** and **SOLVEPNP_UPNP** cannot be used as the current implementations are
+       unstable and sometimes give completly wrong results. If you pass one of these two flags,
+       **SOLVEPNP_EPNP** method will be used instead.
  */
 CV_EXPORTS_W bool solvePnP( InputArray objectPoints, InputArray imagePoints,
                             InputArray cameraMatrix, InputArray distCoeffs,
@@ -572,9 +585,9 @@ CV_EXPORTS_W bool solvePnP( InputArray objectPoints, InputArray imagePoints,
 
 /** @brief Finds an object pose from 3D-2D point correspondences using the RANSAC scheme.
 
- at param objectPoints Array of object points in the object coordinate space, 3xN/Nx3 1-channel or
+ at param objectPoints Array of object points in the object coordinate space, Nx3 1-channel or
 1xN/Nx1 3-channel, where N is the number of points. vector\<Point3f\> can be also passed here.
- at param imagePoints Array of corresponding image points, 2xN/Nx2 1-channel or 1xN/Nx1 2-channel,
+ at param imagePoints Array of corresponding image points, Nx2 1-channel or 1xN/Nx1 2-channel,
 where N is the number of points. vector\<Point2f\> can be also passed here.
 @param cameraMatrix Input camera matrix \f$A = \vecthreethree{fx}{0}{cx}{0}{fy}{cy}{0}{0}{1}\f$ .
 @param distCoeffs Input vector of distortion coefficients
@@ -767,6 +780,14 @@ k-th translation vector (see the next output parameter description) brings the c
 from the model coordinate space (in which object points are specified) to the world coordinate
 space, that is, a real position of the calibration pattern in the k-th pattern view (k=0.. *M* -1).
 @param tvecs Output vector of translation vectors estimated for each pattern view.
+ at param stdDeviationsIntrinsics Output vector of standard deviations estimated for intrinsic parameters.
+ Order of deviations values:
+\f$(f_x, f_y, c_x, c_y, k_1, k_2, p_1, p_2, k_3, k_4, k_5, k_6 , s_1, s_2, s_3,
+ s_4, \tau_x, \tau_y)\f$ If one of parameters is not estimated, it's deviation is equals to zero.
+ at param stdDeviationsExtrinsics Output vector of standard deviations estimated for extrinsic parameters.
+ Order of deviations values: \f$(R_1, T_1, \dotsc , R_M, T_M)\f$ where M is number of pattern views,
+ \f$R_i, T_i\f$ are concatenated 1x3 vectors.
+ @param perViewErrors Output vector of the RMS re-projection error estimated for each pattern view.
 @param flags Different flags that may be zero or a combination of the following values:
 -   **CV_CALIB_USE_INTRINSIC_GUESS** cameraMatrix contains valid initial values of
 fx, fy, cx, cy that are optimized further. Otherwise, (cx, cy) is initially set to the image
@@ -805,6 +826,8 @@ the optimization. If CV_CALIB_USE_INTRINSIC_GUESS is set, the coefficient from t
 supplied distCoeffs matrix is used. Otherwise, it is set to 0.
 @param criteria Termination criteria for the iterative optimization algorithm.
 
+ at return the overall RMS re-projection error.
+
 The function estimates the intrinsic camera parameters and extrinsic parameters for each of the
 views. The algorithm is based on @cite Zhang2000 and @cite BouguetMCT . The coordinates of 3D object
 points and their corresponding 2D projections in each view must be specified. That may be achieved
@@ -829,8 +852,6 @@ The algorithm performs the following steps:
     the projected (using the current estimates for camera parameters and the poses) object points
     objectPoints. See projectPoints for details.
 
-The function returns the final re-projection error.
-
 @note
    If you use a non-square (=non-NxN) grid and findChessboardCorners for calibration, and
     calibrateCamera returns bad values (zero distortion coefficients, an image center very far from
@@ -841,6 +862,24 @@ The function returns the final re-projection error.
 @sa
    findChessboardCorners, solvePnP, initCameraMatrix2D, stereoCalibrate, undistort
  */
+CV_EXPORTS_AS(calibrateCameraExtended) double calibrateCamera( InputArrayOfArrays objectPoints,
+                                     InputArrayOfArrays imagePoints, Size imageSize,
+                                     InputOutputArray cameraMatrix, InputOutputArray distCoeffs,
+                                     OutputArrayOfArrays rvecs, OutputArrayOfArrays tvecs,
+                                     OutputArray stdDeviationsIntrinsics,
+                                     OutputArray stdDeviationsExtrinsics,
+                                     OutputArray perViewErrors,
+                                     int flags = 0, TermCriteria criteria = TermCriteria(
+                                        TermCriteria::COUNT + TermCriteria::EPS, 30, DBL_EPSILON) );
+
+/** @overload double calibrateCamera( InputArrayOfArrays objectPoints,
+                                     InputArrayOfArrays imagePoints, Size imageSize,
+                                     InputOutputArray cameraMatrix, InputOutputArray distCoeffs,
+                                     OutputArrayOfArrays rvecs, OutputArrayOfArrays tvecs,
+                                     OutputArray stdDeviations, OutputArray perViewErrors,
+                                     int flags = 0, TermCriteria criteria = TermCriteria(
+                                        TermCriteria::COUNT + TermCriteria::EPS, 30, DBL_EPSILON) )
+ */
 CV_EXPORTS_W double calibrateCamera( InputArrayOfArrays objectPoints,
                                      InputArrayOfArrays imagePoints, Size imageSize,
                                      InputOutputArray cameraMatrix, InputOutputArray distCoeffs,
@@ -1245,12 +1284,12 @@ same camera matrix.
 @param method Method for computing a fundamental matrix.
 -   **RANSAC** for the RANSAC algorithm.
 -   **MEDS** for the LMedS algorithm.
+ at param prob Parameter used for the RANSAC or LMedS methods only. It specifies a desirable level of
+confidence (probability) that the estimated matrix is correct.
 @param threshold Parameter used for RANSAC. It is the maximum distance from a point to an epipolar
 line in pixels, beyond which the point is considered an outlier and is not used for computing the
 final fundamental matrix. It can be set to something like 1-3, depending on the accuracy of the
 point localization, image resolution, and the image noise.
- at param prob Parameter used for the RANSAC or LMedS methods only. It specifies a desirable level of
-confidence (probability) that the estimated matrix is correct.
 @param mask Output array of N elements, every element of which is set to 0 for outliers and to 1
 for the other points. The array is computed only in the RANSAC and LMedS methods.
 
@@ -1273,8 +1312,8 @@ CV_EXPORTS_W Mat findEssentialMat( InputArray points1, InputArray points2,
 be floating-point (single or double precision).
 @param points2 Array of the second image points of the same size and format as points1 .
 @param focal focal length of the camera. Note that this function assumes that points1 and points2
-are feature points from cameras with same focal length and principle point.
- at param pp principle point of the camera.
+are feature points from cameras with same focal length and principal point.
+ at param pp principal point of the camera.
 @param method Method for computing a fundamental matrix.
 -   **RANSAC** for the RANSAC algorithm.
 -   **LMEDS** for the LMedS algorithm.
@@ -1372,8 +1411,8 @@ floating-point (single or double precision).
 @param R Recovered relative rotation.
 @param t Recoverd relative translation.
 @param focal Focal length of the camera. Note that this function assumes that points1 and points2
-are feature points from cameras with same focal length and principle point.
- at param pp Principle point of the camera.
+are feature points from cameras with same focal length and principal point.
+ at param pp principal point of the camera.
 @param mask Input/output mask for inliers in points1 and points2.
 :   If it is not empty, then it marks inliers in points1 and points2 for then given essential
 matrix E. Only these inliers will be used to recover pose. In the output mask only inliers
@@ -1548,6 +1587,93 @@ CV_EXPORTS_W  int estimateAffine3D(InputArray src, InputArray dst,
                                    OutputArray out, OutputArray inliers,
                                    double ransacThreshold = 3, double confidence = 0.99);
 
+/** @brief Computes an optimal affine transformation between two 2D point sets.
+
+ at param from First input 2D point set.
+ at param to Second input 2D point set.
+ at param inliers Output vector indicating which points are inliers.
+ at param method Robust method used to compute tranformation. The following methods are possible:
+-   cv::RANSAC - RANSAC-based robust method
+-   cv::LMEDS - Least-Median robust method
+RANSAC is the default method.
+ at param ransacReprojThreshold Maximum reprojection error in the RANSAC algorithm to consider
+a point as an inlier. Applies only to RANSAC.
+ at param maxIters The maximum number of robust method iterations, 2000 is the maximum it can be.
+ at param confidence Confidence level, between 0 and 1, for the estimated transformation. Anything
+between 0.95 and 0.99 is usually good enough. Values too close to 1 can slow down the estimation
+significantly. Values lower than 0.8-0.9 can result in an incorrectly estimated transformation.
+ at param refineIters Maximum number of iterations of refining algorithm (Levenberg-Marquardt).
+Passing 0 will disable refining, so the output matrix will be output of robust method.
+
+ at return Output 2D affine transformation matrix \f$2 \times 3\f$ or empty matrix if transformation
+could not be estimated.
+
+The function estimates an optimal 2D affine transformation between two 2D point sets using the
+selected robust algorithm.
+
+The computed transformation is then refined further (using only inliers) with the
+Levenberg-Marquardt method to reduce the re-projection error even more.
+
+ at note
+The RANSAC method can handle practically any ratio of outliers but need a threshold to
+distinguish inliers from outliers. The method LMeDS does not need any threshold but it works
+correctly only when there are more than 50% of inliers.
+
+ at sa estimateAffinePartial2D, getAffineTransform
+*/
+CV_EXPORTS_W cv::Mat estimateAffine2D(InputArray from, InputArray to, OutputArray inliers = noArray(),
+                                  int method = RANSAC, double ransacReprojThreshold = 3,
+                                  size_t maxIters = 2000, double confidence = 0.99,
+                                  size_t refineIters = 10);
+
+/** @brief Computes an optimal limited affine transformation with 4 degrees of freedom between
+two 2D point sets.
+
+ at param from First input 2D point set.
+ at param to Second input 2D point set.
+ at param inliers Output vector indicating which points are inliers.
+ at param method Robust method used to compute tranformation. The following methods are possible:
+-   cv::RANSAC - RANSAC-based robust method
+-   cv::LMEDS - Least-Median robust method
+RANSAC is the default method.
+ at param ransacReprojThreshold Maximum reprojection error in the RANSAC algorithm to consider
+a point as an inlier. Applies only to RANSAC.
+ at param maxIters The maximum number of robust method iterations, 2000 is the maximum it can be.
+ at param confidence Confidence level, between 0 and 1, for the estimated transformation. Anything
+between 0.95 and 0.99 is usually good enough. Values too close to 1 can slow down the estimation
+significantly. Values lower than 0.8-0.9 can result in an incorrectly estimated transformation.
+ at param refineIters Maximum number of iterations of refining algorithm (Levenberg-Marquardt).
+Passing 0 will disable refining, so the output matrix will be output of robust method.
+
+ at return Output 2D affine transformation (4 degrees of freedom) matrix \f$2 \times 3\f$ or
+empty matrix if transformation could not be estimated.
+
+The function estimates an optimal 2D affine transformation with 4 degrees of freedom limited to
+combinations of translation, rotation, and uniform scaling. Uses the selected algorithm for robust
+estimation.
+
+The computed transformation is then refined further (using only inliers) with the
+Levenberg-Marquardt method to reduce the re-projection error even more.
+
+Estimated transformation matrix is:
+\f[ \begin{bmatrix} \cos(\theta)s & -\sin(\theta)s & tx \\
+                \sin(\theta)s & \cos(\theta)s & ty
+\end{bmatrix} \f]
+Where \f$ \theta \f$ is the rotation angle, \f$ s \f$ the scaling factor and \f$ tx, ty \f$ are
+translations in \f$ x, y \f$ axes respectively.
+
+ at note
+The RANSAC method can handle practically any ratio of outliers but need a threshold to
+distinguish inliers from outliers. The method LMeDS does not need any threshold but it works
+correctly only when there are more than 50% of inliers.
+
+ at sa estimateAffine2D, getAffineTransform
+*/
+CV_EXPORTS_W cv::Mat estimateAffinePartial2D(InputArray from, InputArray to, OutputArray inliers = noArray(),
+                                  int method = RANSAC, double ransacReprojThreshold = 3,
+                                  size_t maxIters = 2000, double confidence = 0.99,
+                                  size_t refineIters = 10);
+
 /** @brief Decompose a homography matrix to rotation(s), translation(s) and plane normal(s).
 
 @param H The input homography matrix between two images.
@@ -1756,15 +1882,16 @@ namespace fisheye
 //! @{
 
     enum{
-        CALIB_USE_INTRINSIC_GUESS   = 1,
-        CALIB_RECOMPUTE_EXTRINSIC   = 2,
-        CALIB_CHECK_COND            = 4,
-        CALIB_FIX_SKEW              = 8,
-        CALIB_FIX_K1                = 16,
-        CALIB_FIX_K2                = 32,
-        CALIB_FIX_K3                = 64,
-        CALIB_FIX_K4                = 128,
-        CALIB_FIX_INTRINSIC         = 256
+        CALIB_USE_INTRINSIC_GUESS   = 1 << 0,
+        CALIB_RECOMPUTE_EXTRINSIC   = 1 << 1,
+        CALIB_CHECK_COND            = 1 << 2,
+        CALIB_FIX_SKEW              = 1 << 3,
+        CALIB_FIX_K1                = 1 << 4,
+        CALIB_FIX_K2                = 1 << 5,
+        CALIB_FIX_K3                = 1 << 6,
+        CALIB_FIX_K4                = 1 << 7,
+        CALIB_FIX_INTRINSIC         = 1 << 8,
+        CALIB_FIX_PRINCIPAL_POINT   = 1 << 9
     };
 
     /** @brief Projects points using fisheye model
@@ -1802,6 +1929,10 @@ namespace fisheye
     @param D Input vector of distortion coefficients \f$(k_1, k_2, k_3, k_4)\f$.
     @param alpha The skew coefficient.
     @param distorted Output array of image points, 1xN/Nx1 2-channel, or vector\<Point2f\> .
+
+    Note that the function assumes the camera matrix of the undistorted points to be indentity.
+    This means if you want to transform back points undistorted with undistortPoints() you have to
+    multiply them with \f$P^{-1}\f$.
      */
     CV_EXPORTS_W void distortPoints(InputArray undistorted, OutputArray distorted, InputArray K, InputArray D, double alpha = 0);
 
@@ -1910,8 +2041,10 @@ namespace fisheye
     of intrinsic optimization.
     -   **fisheye::CALIB_CHECK_COND** The functions will check validity of condition number.
     -   **fisheye::CALIB_FIX_SKEW** Skew coefficient (alpha) is set to zero and stay zero.
-    -   **fisheye::CALIB_FIX_K1..4** Selected distortion coefficients are set to zeros and stay
-    zero.
+    -   **fisheye::CALIB_FIX_K1..fisheye::CALIB_FIX_K4** Selected distortion coefficients
+    are set to zeros and stay zero.
+    -   **fisheye::CALIB_FIX_PRINCIPAL_POINT** The principal point is not changed during the global
+optimization. It stays at the center or at a different location specified when CALIB_USE_INTRINSIC_GUESS is set too.
     @param criteria Termination criteria for the iterative optimization algorithm.
      */
     CV_EXPORTS_W double calibrate(InputArrayOfArrays objectPoints, InputArrayOfArrays imagePoints, const Size& image_size,
diff --git a/modules/calib3d/include/opencv2/calib3d/calib3d_c.h b/modules/calib3d/include/opencv2/calib3d/calib3d_c.h
index 0e77aa8..1069b58 100644
--- a/modules/calib3d/include/opencv2/calib3d/calib3d_c.h
+++ b/modules/calib3d/include/opencv2/calib3d/calib3d_c.h
@@ -41,8 +41,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_CALIB3D_C_H__
-#define __OPENCV_CALIB3D_C_H__
+#ifndef OPENCV_CALIB3D_C_H
+#define OPENCV_CALIB3D_C_H
 
 #include "opencv2/core/core_c.h"
 
@@ -246,6 +246,7 @@ CVAPI(void) cvDrawChessboardCorners( CvArr* image, CvSize pattern_size,
 #define CV_CALIB_TILTED_MODEL  262144
 #define CV_CALIB_FIX_TAUX_TAUY  524288
 
+#define CV_CALIB_NINTRINSIC 18
 
 /* Finds intrinsic and extrinsic camera parameters
    from a few views of known calibration pattern */
@@ -422,4 +423,4 @@ public:
 
 #endif
 
-#endif /* __OPENCV_CALIB3D_C_H__ */
+#endif /* OPENCV_CALIB3D_C_H */
diff --git a/modules/calib3d/misc/java/test/Calib3dTest.java b/modules/calib3d/misc/java/test/Calib3dTest.java
index 73ccc8f..add668f 100644
--- a/modules/calib3d/misc/java/test/Calib3dTest.java
+++ b/modules/calib3d/misc/java/test/Calib3dTest.java
@@ -1,7 +1,6 @@
 package org.opencv.test.calib3d;
 
 import org.opencv.calib3d.Calib3d;
-import org.opencv.core.Core;
 import org.opencv.core.CvType;
 import org.opencv.core.Mat;
 import org.opencv.core.MatOfDouble;
@@ -237,6 +236,8 @@ public class Calib3dTest extends OpenCVTestCase {
     }
 
     public void testFindFundamentalMatListOfPointListOfPoint() {
+        fail("Not yet implemented");
+/*
         int minFundamentalMatPoints = 8;
 
         MatOfPoint2f pts = new MatOfPoint2f();
@@ -253,6 +254,7 @@ public class Calib3dTest extends OpenCVTestCase {
         truth = new Mat(3, 3, CvType.CV_64F);
         truth.put(0, 0, 0, -0.577, 0.288, 0.577, 0, 0.288, -0.288, -0.288, 0);
         assertMatEqual(truth, fm, EPS);
+*/
     }
 
     public void testFindFundamentalMatListOfPointListOfPointInt() {
diff --git a/modules/calib3d/perf/perf_affine2d.cpp b/modules/calib3d/perf/perf_affine2d.cpp
new file mode 100644
index 0000000..b893c39
--- /dev/null
+++ b/modules/calib3d/perf/perf_affine2d.cpp
@@ -0,0 +1,170 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+//                           License Agreement
+//                For Open Source Computer Vision Library
+//                        (3-clause BSD License)
+//
+// Copyright (C) 2015-2016, OpenCV Foundation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+//   * Redistributions of source code must retain the above copyright notice,
+//     this list of conditions and the following disclaimer.
+//
+//   * Redistributions in binary form must reproduce the above copyright notice,
+//     this list of conditions and the following disclaimer in the documentation
+//     and/or other materials provided with the distribution.
+//
+//   * Neither the names of the copyright holders nor the names of the contributors
+//     may be used to endorse or promote products derived from this software
+//     without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall copyright holders or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "perf_precomp.hpp"
+#include <algorithm>
+#include <functional>
+
+namespace cvtest
+{
+
+using std::tr1::tuple;
+using std::tr1::get;
+using namespace perf;
+using namespace testing;
+using namespace cv;
+
+CV_ENUM(Method, RANSAC, LMEDS)
+typedef tuple<int, double, Method, size_t> AffineParams;
+typedef TestBaseWithParam<AffineParams> EstimateAffine;
+#define ESTIMATE_PARAMS Combine(Values(100000, 5000, 100), Values(0.99, 0.95, 0.9), Method::all(), Values(10, 0))
+
+static float rngIn(float from, float to) { return from + (to-from) * (float)theRNG(); }
+
+static Mat rngPartialAffMat() {
+    double theta = rngIn(0, (float)CV_PI*2.f);
+    double scale = rngIn(0, 3);
+    double tx = rngIn(-2, 2);
+    double ty = rngIn(-2, 2);
+    double aff[2*3] = { std::cos(theta) * scale, -std::sin(theta) * scale, tx,
+                        std::sin(theta) * scale,  std::cos(theta) * scale, ty };
+    return Mat(2, 3, CV_64F, aff).clone();
+}
+
+PERF_TEST_P( EstimateAffine, EstimateAffine2D, ESTIMATE_PARAMS )
+{
+    AffineParams params = GetParam();
+    const int n = get<0>(params);
+    const double confidence = get<1>(params);
+    const int method = get<2>(params);
+    const size_t refining = get<3>(params);
+
+    Mat aff(2, 3, CV_64F);
+    cv::randu(aff, -2., 2.);
+
+    // LMEDS can't handle more than 50% outliers (by design)
+    int m;
+    if (method == LMEDS)
+        m = 3*n/5;
+    else
+        m = 2*n/5;
+    const float shift_outl = 15.f;
+    const float noise_level = 20.f;
+
+    Mat fpts(1, n, CV_32FC2);
+    Mat tpts(1, n, CV_32FC2);
+
+    randu(fpts, 0., 100.);
+    transform(fpts, tpts, aff);
+
+    /* adding noise to some points */
+    Mat outliers = tpts.colRange(m, n);
+    outliers.reshape(1) += shift_outl;
+
+    Mat noise (outliers.size(), outliers.type());
+    randu(noise, 0., noise_level);
+    outliers += noise;
+
+    Mat aff_est;
+    vector<uchar> inliers (n);
+
+    warmup(inliers, WARMUP_WRITE);
+    warmup(fpts, WARMUP_READ);
+    warmup(tpts, WARMUP_READ);
+
+    TEST_CYCLE()
+    {
+        aff_est = estimateAffine2D(fpts, tpts, inliers, method, 3, 2000, confidence, refining);
+    }
+
+    // we already have accuracy tests
+    SANITY_CHECK_NOTHING();
+}
+
+PERF_TEST_P( EstimateAffine, EstimateAffinePartial2D, ESTIMATE_PARAMS )
+{
+    AffineParams params = GetParam();
+    const int n = get<0>(params);
+    const double confidence = get<1>(params);
+    const int method = get<2>(params);
+    const size_t refining = get<3>(params);
+
+    Mat aff = rngPartialAffMat();
+
+    int m;
+    // LMEDS can't handle more than 50% outliers (by design)
+    if (method == LMEDS)
+        m = 3*n/5;
+    else
+        m = 2*n/5;
+    const float shift_outl = 15.f;    const float noise_level = 20.f;
+
+    Mat fpts(1, n, CV_32FC2);
+    Mat tpts(1, n, CV_32FC2);
+
+    randu(fpts, 0., 100.);
+    transform(fpts, tpts, aff);
+
+    /* adding noise*/
+    Mat outliers = tpts.colRange(m, n);
+    outliers.reshape(1) += shift_outl;
+
+    Mat noise (outliers.size(), outliers.type());
+    randu(noise, 0., noise_level);
+    outliers += noise;
+
+    Mat aff_est;
+    vector<uchar> inliers (n);
+
+    warmup(inliers, WARMUP_WRITE);
+    warmup(fpts, WARMUP_READ);
+    warmup(tpts, WARMUP_READ);
+
+    TEST_CYCLE()
+    {
+        aff_est = estimateAffinePartial2D(fpts, tpts, inliers, method, 3, 2000, confidence, refining);
+    }
+
+    // we already have accuracy tests
+    SANITY_CHECK_NOTHING();
+}
+
+} // namespace cvtest
diff --git a/modules/calib3d/src/calibinit.cpp b/modules/calib3d/src/calibinit.cpp
index d2641fe..2e9f07a 100644
--- a/modules/calib3d/src/calibinit.cpp
+++ b/modules/calib3d/src/calibinit.cpp
@@ -59,23 +59,30 @@
 
 \************************************************************************************/
 
+/************************************************************************************\
+  This version adds a new and improved variant of chessboard corner detection
+  that works better in poor lighting condition. It is based on work from
+  Oliver Schreer and Stefano Masneri. This method works faster than the previous
+  one and reverts back to the older method in case no chessboard detection is
+  possible. Overall performance improves also because now the method avoids
+  performing the same computation multiple times when not necessary.
+
+\************************************************************************************/
+
 #include "precomp.hpp"
 #include "opencv2/imgproc/imgproc_c.h"
 #include "opencv2/calib3d/calib3d_c.h"
 #include "circlesgrid.hpp"
 #include <stdarg.h>
+#include <vector>
+
+using namespace cv;
+using namespace std;
 
 //#define ENABLE_TRIM_COL_ROW
 
 //#define DEBUG_CHESSBOARD
-#ifdef DEBUG_CHESSBOARD
-#  include "opencv2/opencv_modules.hpp"
-#  ifdef HAVE_OPENCV_HIGHGUI
-#    include "opencv2/highgui.hpp"
-#  else
-#    undef DEBUG_CHESSBOARD
-#  endif
-#endif
+
 #ifdef DEBUG_CHESSBOARD
 static int PRINTF( const char* fmt, ... )
 {
@@ -84,13 +91,9 @@ static int PRINTF( const char* fmt, ... )
     return vprintf(fmt, args);
 }
 #else
-static int PRINTF( const char*, ... )
-{
-    return 0;
-}
+#define PRINTF(...)
 #endif
 
-
 //=====================================================================================
 // Implementation for the enhanced calibration object detection
 //=====================================================================================
@@ -151,10 +154,42 @@ struct CvCBQuad
 
 //=====================================================================================
 
-//static CvMat* debug_img = 0;
+#ifdef DEBUG_CHESSBOARD
+#include "opencv2/highgui.hpp"
+#include "opencv2/imgproc.hpp"
+static void SHOW(const std::string & name, Mat & img)
+{
+    imshow(name, img);
+    while ((uchar)waitKey(0) != 'q') {}
+}
+static void SHOW_QUADS(const std::string & name, const Mat & img_, CvCBQuad * quads, int quads_count)
+{
+    Mat img = img_.clone();
+    if (img.channels() == 1)
+        cvtColor(img, img, COLOR_GRAY2BGR);
+    for (int i = 0; i < quads_count; ++i)
+    {
+        CvCBQuad & quad = quads[i];
+        for (int j = 0; j < 4; ++j)
+        {
+            line(img, quad.corners[j]->pt, quad.corners[(j + 1) % 4]->pt, Scalar(0, 240, 0), 1, LINE_AA);
+        }
+    }
+    imshow(name, img);
+    while ((uchar)waitKey(0) != 'q') {}
+}
+#else
+#define SHOW(...)
+#define SHOW_QUADS(...)
+#endif
+
+//=====================================================================================
 
 static int icvGenerateQuads( CvCBQuad **quads, CvCBCorner **corners,
-                             CvMemStorage *storage, CvMat *image, int flags, int *max_quad_buf_size);
+                             CvMemStorage *storage, const Mat &image_, int flags, int *max_quad_buf_size);
+
+static bool processQuads(CvCBQuad *quads, int quad_count, CvSize pattern_size, int max_quad_buf_size,
+                         CvMemStorage * storage, CvCBCorner *corners, CvPoint2D32f *out_corners, int *out_corner_count, int & prev_sqr_size);
 
 /*static int
 icvGenerateQuadsEx( CvCBQuad **out_quads, CvCBCorner **out_corners,
@@ -191,38 +226,199 @@ static void icvRemoveQuadFromGroup(CvCBQuad **quads, int count, CvCBQuad *q0);
 
 static int icvCheckBoardMonotony( CvPoint2D32f* corners, CvSize pattern_size );
 
-#if 0
-static void
-icvCalcAffineTranf2D32f(CvPoint2D32f* pts1, CvPoint2D32f* pts2, int count, CvMat* affine_trans)
+/***************************************************************************************************/
+//COMPUTE INTENSITY HISTOGRAM OF INPUT IMAGE
+static int icvGetIntensityHistogram( const Mat & img, std::vector<int>& piHist )
 {
-    int i, j;
-    int real_count = 0;
-    for( j = 0; j < count; j++ )
+    // sum up all pixel in row direction and divide by number of columns
+    for ( int j=0; j<img.rows; j++ )
+    {
+        const uchar * row = img.ptr(j);
+        for ( int i=0; i<img.cols; i++ )
+        {
+            piHist[row[i]]++;
+        }
+    }
+    return 0;
+}
+/***************************************************************************************************/
+//SMOOTH HISTOGRAM USING WINDOW OF SIZE 2*iWidth+1
+static int icvSmoothHistogram( const std::vector<int>& piHist, std::vector<int>& piHistSmooth, int iWidth )
+{
+    int iIdx;
+    for ( int i=0; i<256; i++)
+    {
+        int iSmooth = 0;
+        for ( int ii=-iWidth; ii<=iWidth; ii++)
+        {
+            iIdx = i+ii;
+            if (iIdx > 0 && iIdx < 256)
+            {
+                iSmooth += piHist[iIdx];
+            }
+        }
+        piHistSmooth[i] = iSmooth/(2*iWidth+1);
+    }
+    return 0;
+}
+/***************************************************************************************************/
+//COMPUTE FAST HISTOGRAM GRADIENT
+static int icvGradientOfHistogram( const std::vector<int>& piHist, std::vector<int>& piHistGrad )
+{
+    piHistGrad[0] = 0;
+    for ( int i=1; i<255; i++)
+    {
+        piHistGrad[i] = piHist[i-1] - piHist[i+1];
+        if ( abs(piHistGrad[i]) < 100 )
+        {
+            if ( piHistGrad[i-1] == 0)
+                piHistGrad[i] = -100;
+            else
+                piHistGrad[i] = piHistGrad[i-1];
+        }
+    }
+    return 0;
+}
+/***************************************************************************************************/
+//PERFORM SMART IMAGE THRESHOLDING BASED ON ANALYSIS OF INTENSTY HISTOGRAM
+static bool icvBinarizationHistogramBased( Mat & img )
+{
+    CV_Assert(img.channels() == 1 && img.depth() == CV_8U);
+    int iCols = img.cols;
+    int iRows = img.rows;
+    int iMaxPix = iCols*iRows;
+    int iMaxPix1 = iMaxPix/100;
+    const int iNumBins = 256;
+    std::vector<int> piHistIntensity(iNumBins, 0);
+    std::vector<int> piHistSmooth(iNumBins, 0);
+    std::vector<int> piHistGrad(iNumBins, 0);
+    std::vector<int> piAccumSum(iNumBins, 0);
+    std::vector<int> piMaxPos(20, 0);
+    int iThresh = 0;
+    int iIdx;
+    int iWidth = 1;
+
+    icvGetIntensityHistogram( img, piHistIntensity );
+
+    // get accumulated sum starting from bright
+    piAccumSum[iNumBins-1] = piHistIntensity[iNumBins-1];
+    for ( int i=iNumBins-2; i>=0; i-- )
+    {
+        piAccumSum[i] = piHistIntensity[i] + piAccumSum[i+1];
+    }
+
+    // first smooth the distribution
+    icvSmoothHistogram( piHistIntensity, piHistSmooth, iWidth );
+
+    // compute gradient
+    icvGradientOfHistogram( piHistSmooth, piHistGrad );
+
+    // check for zeros
+    int iCntMaxima = 0;
+    for ( int i=iNumBins-2; (i>2) && (iCntMaxima<20); i--)
+    {
+        if ( (piHistGrad[i-1] < 0) && (piHistGrad[i] > 0) )
+        {
+            piMaxPos[iCntMaxima] = i;
+            iCntMaxima++;
+        }
+    }
+
+    iIdx = 0;
+    int iSumAroundMax = 0;
+    for ( int i=0; i<iCntMaxima; i++ )
+    {
+        iIdx = piMaxPos[i];
+        iSumAroundMax = piHistSmooth[iIdx-1] + piHistSmooth[iIdx] + piHistSmooth[iIdx+1];
+        if ( iSumAroundMax < iMaxPix1 && iIdx < 64 )
+        {
+            for ( int j=i; j<iCntMaxima-1; j++ )
+            {
+                piMaxPos[j] = piMaxPos[j+1];
+            }
+            iCntMaxima--;
+            i--;
+        }
+    }
+    if ( iCntMaxima == 1)
+    {
+        iThresh = piMaxPos[0]/2;
+    }
+    else if ( iCntMaxima == 2)
+    {
+        iThresh = (piMaxPos[0] + piMaxPos[1])/2;
+    }
+    else // iCntMaxima >= 3
     {
-        if( pts1[j].x >= 0 ) real_count++;
+        // CHECKING THRESHOLD FOR WHITE
+        int iIdxAccSum = 0, iAccum = 0;
+        for (int i=iNumBins-1; i>0; i--)
+        {
+            iAccum += piHistIntensity[i];
+            // iMaxPix/18 is about 5,5%, minimum required number of pixels required for white part of chessboard
+            if ( iAccum > (iMaxPix/18) )
+            {
+                iIdxAccSum = i;
+                break;
+            }
+        }
+
+        int iIdxBGMax = 0;
+        int iBrightMax = piMaxPos[0];
+        // printf("iBrightMax = %d\n", iBrightMax);
+        for ( int n=0; n<iCntMaxima-1; n++)
+        {
+            iIdxBGMax = n+1;
+            if ( piMaxPos[n] < iIdxAccSum )
+            {
+                break;
+            }
+            iBrightMax = piMaxPos[n];
+        }
+
+        // CHECKING THRESHOLD FOR BLACK
+        int iMaxVal = piHistIntensity[piMaxPos[iIdxBGMax]];
+
+        //IF TOO CLOSE TO 255, jump to next maximum
+        if ( piMaxPos[iIdxBGMax] >= 250 && iIdxBGMax < iCntMaxima )
+        {
+            iIdxBGMax++;
+            iMaxVal = piHistIntensity[piMaxPos[iIdxBGMax]];
+        }
+
+        for ( int n=iIdxBGMax + 1; n<iCntMaxima; n++)
+        {
+            if ( piHistIntensity[piMaxPos[n]] >= iMaxVal )
+            {
+                iMaxVal = piHistIntensity[piMaxPos[n]];
+                iIdxBGMax = n;
+            }
+        }
+
+        //SETTING THRESHOLD FOR BINARIZATION
+        int iDist2 = (iBrightMax - piMaxPos[iIdxBGMax])/2;
+        iThresh = iBrightMax - iDist2;
+        PRINTF("THRESHOLD SELECTED = %d, BRIGHTMAX = %d, DARKMAX = %d\n", iThresh, iBrightMax, piMaxPos[iIdxBGMax]);
     }
-    if(real_count < 3) return;
-    cv::Ptr<CvMat> xy = cvCreateMat( 2*real_count, 6, CV_32FC1 );
-    cv::Ptr<CvMat> uv = cvCreateMat( 2*real_count, 1, CV_32FC1 );
-    //estimate affine transfromation
-    for( i = 0, j = 0; j < count; j++ )
+
+
+    if ( iThresh > 0 )
     {
-        if( pts1[j].x >= 0 )
+        for ( int jj=0; jj<iRows; jj++)
         {
-            CV_MAT_ELEM( *xy, float, i*2+1, 2 ) = CV_MAT_ELEM( *xy, float, i*2, 0 ) = pts2[j].x;
-            CV_MAT_ELEM( *xy, float, i*2+1, 3 ) = CV_MAT_ELEM( *xy, float, i*2, 1 ) = pts2[j].y;
-            CV_MAT_ELEM( *xy, float, i*2, 2 ) = CV_MAT_ELEM( *xy, float, i*2, 3 ) = CV_MAT_ELEM( *xy, float, i*2, 5 ) = \
-                CV_MAT_ELEM( *xy, float, i*2+1, 0 ) = CV_MAT_ELEM( *xy, float, i*2+1, 1 ) = CV_MAT_ELEM( *xy, float, i*2+1, 4 ) = 0;
-            CV_MAT_ELEM( *xy, float, i*2, 4 ) = CV_MAT_ELEM( *xy, float, i*2+1, 5 ) = 1;
-            CV_MAT_ELEM( *uv, float, i*2, 0 ) = pts1[j].x;
-            CV_MAT_ELEM( *uv, float, i*2+1, 0 ) = pts1[j].y;
-            i++;
+            uchar * row = img.ptr(jj);
+            for ( int ii=0; ii<iCols; ii++)
+            {
+                if ( row[ii] < iThresh )
+                    row[ii] = 0;
+                else
+                    row[ii] = 255;
+            }
         }
     }
 
-    cvSolve( xy, uv, affine_trans, CV_SVD );
+    return true;
 }
-#endif
 
 CV_IMPL
 int cvFindChessboardCorners( const void* arr, CvSize pattern_size,
@@ -230,39 +426,24 @@ int cvFindChessboardCorners( const void* arr, CvSize pattern_size,
                              int flags )
 {
     int found = 0;
-    CvCBQuad *quads = 0, **quad_group = 0;
-    CvCBCorner *corners = 0, **corner_group = 0;
+    CvCBQuad *quads = 0;
+    CvCBCorner *corners = 0;
+
+    cv::Ptr<CvMemStorage> storage;
 
     try
     {
     int k = 0;
     const int min_dilations = 0;
     const int max_dilations = 7;
-    cv::Ptr<CvMat> norm_img, thresh_img;
-#ifdef DEBUG_CHESSBOARD
-    cv::Ptr<IplImage> dbg_img;
-    cv::Ptr<IplImage> dbg1_img;
-    cv::Ptr<IplImage> dbg2_img;
-#endif
-    cv::Ptr<CvMemStorage> storage;
-
-    CvMat stub, *img = (CvMat*)arr;
-
-    int expected_corners_num = (pattern_size.width/2+1)*(pattern_size.height/2+1);
-
-    int prev_sqr_size = 0;
 
     if( out_corner_count )
         *out_corner_count = 0;
 
-    IplImage _img;
-    int quad_count = 0, group_idx = 0, dilations = 0;
+    Mat img = cvarrToMat((CvMat*)arr).clone();
 
-    img = cvGetMat( img, &stub );
-    //debug_img = img;
-
-    if( CV_MAT_DEPTH( img->type ) != CV_8U || CV_MAT_CN( img->type ) == 2 )
-        CV_Error( CV_StsUnsupportedFormat, "Only 8-bit grayscale or color images are supported" );
+    if( img.depth() != CV_8U || (img.channels() != 1 && img.channels() != 3) )
+       CV_Error( CV_StsUnsupportedFormat, "Only 8-bit grayscale or color images are supported" );
 
     if( pattern_size.width <= 2 || pattern_size.height <= 2 )
         CV_Error( CV_StsOutOfRange, "Both width and height of the pattern should have bigger than 2" );
@@ -270,302 +451,180 @@ int cvFindChessboardCorners( const void* arr, CvSize pattern_size,
     if( !out_corners )
         CV_Error( CV_StsNullPtr, "Null pointer to corners" );
 
-    storage.reset(cvCreateMemStorage(0));
-    thresh_img.reset(cvCreateMat( img->rows, img->cols, CV_8UC1 ));
-
-#ifdef DEBUG_CHESSBOARD
-    dbg_img = cvCreateImage(cvGetSize(img), IPL_DEPTH_8U, 3 );
-    dbg1_img = cvCreateImage(cvGetSize(img), IPL_DEPTH_8U, 3 );
-    dbg2_img = cvCreateImage(cvGetSize(img), IPL_DEPTH_8U, 3 );
-#endif
-
-    if( CV_MAT_CN(img->type) != 1 || (flags & CV_CALIB_CB_NORMALIZE_IMAGE) )
+    if (img.channels() != 1)
     {
-        // equalize the input image histogram -
-        // that should make the contrast between "black" and "white" areas big enough
-        norm_img.reset(cvCreateMat( img->rows, img->cols, CV_8UC1 ));
+        cvtColor(img, img, COLOR_BGR2GRAY);
+    }
 
-        if( CV_MAT_CN(img->type) != 1 )
-        {
-            cvCvtColor( img, norm_img, CV_BGR2GRAY );
-            img = norm_img;
-        }
 
-        if( flags & CV_CALIB_CB_NORMALIZE_IMAGE )
-        {
-            cvEqualizeHist( img, norm_img );
-            img = norm_img;
-        }
-    }
+    Mat thresh_img_new = img.clone();
+    icvBinarizationHistogramBased( thresh_img_new ); // process image in-place
+    SHOW("New binarization", thresh_img_new);
 
     if( flags & CV_CALIB_CB_FAST_CHECK)
     {
-        cvGetImage(img, &_img);
-        int check_chessboard_result = cvCheckChessboard(&_img, pattern_size);
-        if(check_chessboard_result <= 0)
+        //perform new method for checking chessboard using a binary image.
+        //image is binarised using a threshold dependent on the image histogram
+        if (checkChessboardBinary(thresh_img_new, pattern_size) <= 0) //fall back to the old method
         {
-            return 0;
+            if (checkChessboard(img, pattern_size) <= 0)
+            {
+                return found;
+            }
         }
     }
 
+    storage.reset(cvCreateMemStorage(0));
+
+    int prev_sqr_size = 0;
+
     // Try our standard "1" dilation, but if the pattern is not found, iterate the whole procedure with higher dilations.
     // This is necessary because some squares simply do not separate properly with a single dilation.  However,
     // we want to use the minimum number of dilations possible since dilations cause the squares to become smaller,
     // making it difficult to detect smaller squares.
-    for( k = 0; k < 6; k++ )
+    for( int dilations = min_dilations; dilations <= max_dilations; dilations++ )
     {
+        if (found)
+            break;      // already found it
+
+        //USE BINARY IMAGE COMPUTED USING icvBinarizationHistogramBased METHOD
+        dilate( thresh_img_new, thresh_img_new, Mat(), Point(-1, -1), 1 );
+
+        // So we can find rectangles that go to the edge, we draw a white line around the image edge.
+        // Otherwise FindContours will miss those clipped rectangle contours.
+        // The border color will be the image mean, because otherwise we risk screwing up filters like cvSmooth()...
+        rectangle( thresh_img_new, Point(0,0), Point(thresh_img_new.cols-1, thresh_img_new.rows-1), Scalar(255,255,255), 3, LINE_8);
         int max_quad_buf_size = 0;
-        for( dilations = min_dilations; dilations <= max_dilations; dilations++ )
+        cvFree(&quads);
+        cvFree(&corners);
+        int quad_count = icvGenerateQuads( &quads, &corners, storage, thresh_img_new, flags, &max_quad_buf_size );
+        PRINTF("Quad count: %d/%d\n", quad_count, (pattern_size.width/2+1)*(pattern_size.height/2+1));
+        SHOW_QUADS("New quads", thresh_img_new, quads, quad_count);
+        if (processQuads(quads, quad_count, pattern_size, max_quad_buf_size, storage, corners, out_corners, out_corner_count, prev_sqr_size))
+            found = 1;
+    }
+
+    PRINTF("Chessboard detection result 0: %d\n", found);
+
+    // revert to old, slower, method if detection failed
+    if (!found)
+    {
+        if( flags & CV_CALIB_CB_NORMALIZE_IMAGE )
         {
-            if (found)
-                break;      // already found it
+            equalizeHist( img, img );
+        }
 
-            cvFree(&quads);
-            cvFree(&corners);
+        Mat thresh_img;
+        prev_sqr_size = 0;
 
-            /*if( k == 1 )
-            {
-                //Pattern was not found using binarization
-                // Run multi-level quads extraction
-                // In case one-level binarization did not give enough number of quads
-                CV_CALL( quad_count = icvGenerateQuadsEx( &quads, &corners, storage, img, thresh_img, dilations, flags ));
-                PRINTF("EX quad count: %d/%d\n", quad_count, expected_corners_num);
-            }
-            else*/
+        PRINTF("Fallback to old algorithm\n");
+        const bool useAdaptive = flags & CV_CALIB_CB_ADAPTIVE_THRESH;
+        if (!useAdaptive)
+        {
+            // empiric threshold level
+            // thresholding performed here and not inside the cycle to save processing time
+            double mean = cv::mean(img).val[0];
+            int thresh_level = MAX(cvRound( mean - 10 ), 10);
+            threshold( img, thresh_img, thresh_level, 255, THRESH_BINARY );
+        }
+        //if flag CV_CALIB_CB_ADAPTIVE_THRESH is not set it doesn't make sense to iterate over k
+        int max_k = useAdaptive ? 6 : 1;
+        for( k = 0; k < max_k; k++ )
+        {
+            for( int dilations = min_dilations; dilations <= max_dilations; dilations++ )
             {
+                if (found)
+                    break;      // already found it
+
                 // convert the input grayscale image to binary (black-n-white)
-                if( flags & CV_CALIB_CB_ADAPTIVE_THRESH )
+                if (useAdaptive)
                 {
-                    int block_size = cvRound(prev_sqr_size == 0 ?
-                        MIN(img->cols,img->rows)*(k%2 == 0 ? 0.2 : 0.1): prev_sqr_size*2)|1;
-
+                    int block_size = cvRound(prev_sqr_size == 0
+                                             ? MIN(img.cols, img.rows) * (k % 2 == 0 ? 0.2 : 0.1)
+                                             : prev_sqr_size * 2);
+                    block_size = block_size | 1;
                     // convert to binary
-                    cvAdaptiveThreshold( img, thresh_img, 255,
-                        CV_ADAPTIVE_THRESH_MEAN_C, CV_THRESH_BINARY, block_size, (k/2)*5 );
+                    adaptiveThreshold( img, thresh_img, 255, ADAPTIVE_THRESH_MEAN_C, THRESH_BINARY, block_size, (k/2)*5 );
                     if (dilations > 0)
-                        cvDilate( thresh_img, thresh_img, 0, dilations-1 );
+                        dilate( thresh_img, thresh_img, Mat(), Point(-1, -1), dilations-1 );
+
                 }
                 else
                 {
-                    // Make dilation before the thresholding.
-                    // It splits chessboard corners
-                    //cvDilate( img, thresh_img, 0, 1 );
-
-                    // empiric threshold level
-                    double mean = cvAvg( img ).val[0];
-                    int thresh_level = cvRound( mean - 10 );
-                    thresh_level = MAX( thresh_level, 10 );
-
-                    cvThreshold( img, thresh_img, thresh_level, 255, CV_THRESH_BINARY );
-                    cvDilate( thresh_img, thresh_img, 0, dilations );
+                    dilate( thresh_img, thresh_img, Mat(), Point(-1, -1), 1 );
                 }
-
-#ifdef DEBUG_CHESSBOARD
-                cvCvtColor(thresh_img,dbg_img,CV_GRAY2BGR);
-#endif
+                SHOW("Old binarization", thresh_img);
 
                 // So we can find rectangles that go to the edge, we draw a white line around the image edge.
                 // Otherwise FindContours will miss those clipped rectangle contours.
                 // The border color will be the image mean, because otherwise we risk screwing up filters like cvSmooth()...
-                cvRectangle( thresh_img, cvPoint(0,0), cvPoint(thresh_img->cols-1,
-                    thresh_img->rows-1), CV_RGB(255,255,255), 3, 8);
-
-                quad_count = icvGenerateQuads( &quads, &corners, storage, thresh_img, flags, &max_quad_buf_size);
-
-                PRINTF("Quad count: %d/%d\n", quad_count, expected_corners_num);
-            }
-
-
-#ifdef DEBUG_CHESSBOARD
-            cvCopy(dbg_img, dbg1_img);
-            cvNamedWindow("all_quads", 1);
-            // copy corners to temp array
-            for(int i = 0; i < quad_count; i++ )
-            {
-                for (int k=0; k<4; k++)
-                {
-                    CvPoint2D32f pt1, pt2;
-                    CvScalar color = CV_RGB(30,255,30);
-                    pt1 = quads[i].corners[k]->pt;
-                    pt2 = quads[i].corners[(k+1)%4]->pt;
-                    pt2.x = (pt1.x + pt2.x)/2;
-                    pt2.y = (pt1.y + pt2.y)/2;
-                    if (k>0)
-                        color = CV_RGB(200,200,0);
-                    cvLine( dbg1_img, cvPointFrom32f(pt1), cvPointFrom32f(pt2), color, 3, 8);
-                }
+                rectangle( thresh_img, Point(0,0), Point(thresh_img.cols-1, thresh_img.rows-1), Scalar(255,255,255), 3, LINE_8);
+                int max_quad_buf_size = 0;
+                cvFree(&quads);
+                cvFree(&corners);
+                int quad_count = icvGenerateQuads( &quads, &corners, storage, thresh_img, flags, &max_quad_buf_size);
+                PRINTF("Quad count: %d/%d\n", quad_count, (pattern_size.width/2+1)*(pattern_size.height/2+1));
+                SHOW_QUADS("Old quads", thresh_img, quads, quad_count);
+                if (processQuads(quads, quad_count, pattern_size, max_quad_buf_size, storage, corners, out_corners, out_corner_count, prev_sqr_size))
+                    found = 1;
             }
+        }
+    }
 
-
-            cvShowImage("all_quads", (IplImage*)dbg1_img);
-            cvWaitKey();
-#endif
-
-            if( quad_count <= 0 )
-                continue;
-
-            // Find quad's neighbors
-            icvFindQuadNeighbors( quads, quad_count );
-
-            // allocate extra for adding in icvOrderFoundQuads
-            cvFree(&quad_group);
-            cvFree(&corner_group);
-            quad_group = (CvCBQuad**)cvAlloc( sizeof(quad_group[0]) * max_quad_buf_size);
-            corner_group = (CvCBCorner**)cvAlloc( sizeof(corner_group[0]) * max_quad_buf_size * 4 );
-
-            for( group_idx = 0; ; group_idx++ )
-            {
-                int count = 0;
-                count = icvFindConnectedQuads( quads, quad_count, quad_group, group_idx, storage );
-
-                int icount = count;
-                if( count == 0 )
-                    break;
-
-                // order the quad corners globally
-                // maybe delete or add some
-                PRINTF("Starting ordering of inner quads\n");
-                count = icvOrderFoundConnectedQuads(count, quad_group, &quad_count, &quads, &corners,
-                    pattern_size, max_quad_buf_size, storage );
-                PRINTF("Orig count: %d  After ordering: %d\n", icount, count);
-
-
-#ifdef DEBUG_CHESSBOARD
-                cvCopy(dbg_img,dbg2_img);
-                cvNamedWindow("connected_group", 1);
-                // copy corners to temp array
-                for(int i = 0; i < quad_count; i++ )
-                {
-                    if (quads[i].group_idx == group_idx)
-                        for (int k=0; k<4; k++)
-                        {
-                            CvPoint2D32f pt1, pt2;
-                            CvScalar color = CV_RGB(30,255,30);
-                            if (quads[i].ordered)
-                                color = CV_RGB(255,30,30);
-                            pt1 = quads[i].corners[k]->pt;
-                            pt2 = quads[i].corners[(k+1)%4]->pt;
-                            pt2.x = (pt1.x + pt2.x)/2;
-                            pt2.y = (pt1.y + pt2.y)/2;
-                            if (k>0)
-                                color = CV_RGB(200,200,0);
-                            cvLine( dbg2_img, cvPointFrom32f(pt1), cvPointFrom32f(pt2), color, 3, 8);
-                        }
-                }
-                cvShowImage("connected_group", (IplImage*)dbg2_img);
-                cvWaitKey();
-#endif
-
-                if (count == 0)
-                    continue;       // haven't found inner quads
-
-
-                // If count is more than it should be, this will remove those quads
-                // which cause maximum deviation from a nice square pattern.
-                count = icvCleanFoundConnectedQuads( count, quad_group, pattern_size );
-                PRINTF("Connected group: %d  orig count: %d cleaned: %d\n", group_idx, icount, count);
-
-                count = icvCheckQuadGroup( quad_group, count, corner_group, pattern_size );
-                PRINTF("Connected group: %d  count: %d  cleaned: %d\n", group_idx, icount, count);
-
-                {
-                int n = count > 0 ? pattern_size.width * pattern_size.height : -count;
-                n = MIN( n, pattern_size.width * pattern_size.height );
-                float sum_dist = 0;
-                int total = 0;
-
-                for(int i = 0; i < n; i++ )
-                {
-                    int ni = 0;
-                    float avgi = corner_group[i]->meanDist(&ni);
-                    sum_dist += avgi*ni;
-                    total += ni;
-                }
-                prev_sqr_size = cvRound(sum_dist/MAX(total, 1));
-
-                if( count > 0 || (out_corner_count && -count > *out_corner_count) )
-                {
-                    // copy corners to output array
-                    for(int i = 0; i < n; i++ )
-                        out_corners[i] = corner_group[i]->pt;
-
-                    if( out_corner_count )
-                        *out_corner_count = n;
-
-                    if( count == pattern_size.width*pattern_size.height &&
-                        icvCheckBoardMonotony( out_corners, pattern_size ))
-                    {
-                        found = 1;
-                        break;
-                    }
-                }
-                }
-            }
-        }//dilations
-    }//
+    PRINTF("Chessboard detection result 1: %d\n", found);
 
     if( found )
         found = icvCheckBoardMonotony( out_corners, pattern_size );
 
+    PRINTF("Chessboard detection result 2: %d\n", found);
+
     // check that none of the found corners is too close to the image boundary
     if( found )
     {
         const int BORDER = 8;
         for( k = 0; k < pattern_size.width*pattern_size.height; k++ )
         {
-            if( out_corners[k].x <= BORDER || out_corners[k].x > img->cols - BORDER ||
-                out_corners[k].y <= BORDER || out_corners[k].y > img->rows - BORDER )
+            if( out_corners[k].x <= BORDER || out_corners[k].x > img.cols - BORDER ||
+                out_corners[k].y <= BORDER || out_corners[k].y > img.rows - BORDER )
                 break;
         }
 
         found = k == pattern_size.width*pattern_size.height;
     }
 
-    if( found && pattern_size.height % 2 == 0 && pattern_size.width % 2 == 0 )
-    {
-        int last_row = (pattern_size.height-1)*pattern_size.width;
-        double dy0 = out_corners[last_row].y - out_corners[0].y;
-        if( dy0 < 0 )
-        {
-            int n = pattern_size.width*pattern_size.height;
-            for(int i = 0; i < n/2; i++ )
-            {
-                CvPoint2D32f temp;
-                CV_SWAP(out_corners[i], out_corners[n-i-1], temp);
-            }
-        }
-    }
+    PRINTF("Chessboard detection result 3: %d\n", found);
 
     if( found )
     {
-        cv::Ptr<CvMat> gray;
-        if( CV_MAT_CN(img->type) != 1 )
-        {
-            gray.reset(cvCreateMat(img->rows, img->cols, CV_8UC1));
-            cvCvtColor(img, gray, CV_BGR2GRAY);
-        }
-        else
+        if ( pattern_size.height % 2 == 0 && pattern_size.width % 2 == 0 )
         {
-            gray.reset(cvCloneMat(img));
+            int last_row = (pattern_size.height-1)*pattern_size.width;
+            double dy0 = out_corners[last_row].y - out_corners[0].y;
+            if( dy0 < 0 )
+            {
+                int n = pattern_size.width*pattern_size.height;
+                for(int i = 0; i < n/2; i++ )
+                {
+                    CvPoint2D32f temp;
+                    CV_SWAP(out_corners[i], out_corners[n-i-1], temp);
+                }
+            }
         }
         int wsize = 2;
-        cvFindCornerSubPix( gray, out_corners, pattern_size.width*pattern_size.height,
-            cvSize(wsize, wsize), cvSize(-1,-1), cvTermCriteria(CV_TERMCRIT_EPS+CV_TERMCRIT_ITER, 15, 0.1));
+        CvMat old_img(img);
+        cvFindCornerSubPix( &old_img, out_corners, pattern_size.width*pattern_size.height,
+                            cvSize(wsize, wsize), cvSize(-1,-1),
+                            cvTermCriteria(CV_TERMCRIT_EPS+CV_TERMCRIT_ITER, 15, 0.1));
     }
     }
     catch(...)
     {
         cvFree(&quads);
         cvFree(&corners);
-        cvFree(&quad_group);
-        cvFree(&corner_group);
         throw;
     }
-
     cvFree(&quads);
     cvFree(&corners);
-    cvFree(&quad_group);
-    cvFree(&corner_group);
     return found;
 }
 
@@ -1043,7 +1102,7 @@ icvRemoveQuadFromGroup(CvCBQuad **quads, int count, CvCBQuad *q0)
                         q0->count--;
                         break;
                     }
-                    break;
+                break;
             }
         }
     }
@@ -1653,8 +1712,9 @@ static void icvFindQuadNeighbors( CvCBQuad *quads, int quad_count )
 
 static int
 icvGenerateQuads( CvCBQuad **out_quads, CvCBCorner **out_corners,
-                  CvMemStorage *storage, CvMat *image, int flags, int *max_quad_buf_size )
+                  CvMemStorage *storage, const cv::Mat & image_, int flags, int *max_quad_buf_size )
 {
+    CvMat image_old(image_), *image = &image_old;
     int quad_count = 0;
     cv::Ptr<CvMemStorage> temp_storage;
 
@@ -1798,6 +1858,88 @@ icvGenerateQuads( CvCBQuad **out_quads, CvCBCorner **out_corners,
     return quad_count;
 }
 
+static bool processQuads(CvCBQuad *quads, int quad_count, CvSize pattern_size, int max_quad_buf_size,
+                         CvMemStorage * storage, CvCBCorner *corners, CvPoint2D32f *out_corners, int *out_corner_count, int & prev_sqr_size)
+{
+    if( quad_count <= 0 )
+        return false;
+
+    bool found = false;
+
+    // Find quad's neighbors
+    icvFindQuadNeighbors( quads, quad_count );
+
+    // allocate extra for adding in icvOrderFoundQuads
+    CvCBQuad **quad_group = 0;
+    CvCBCorner **corner_group = 0;
+
+    quad_group = (CvCBQuad**)cvAlloc( sizeof(quad_group[0]) * max_quad_buf_size);
+    corner_group = (CvCBCorner**)cvAlloc( sizeof(corner_group[0]) * max_quad_buf_size * 4 );
+
+    for( int group_idx = 0; ; group_idx++ )
+    {
+        int count = icvFindConnectedQuads( quads, quad_count, quad_group, group_idx, storage );
+
+        if( count == 0 )
+            break;
+
+        // order the quad corners globally
+        // maybe delete or add some
+        PRINTF("Starting ordering of inner quads (%d)\n", count);
+        count = icvOrderFoundConnectedQuads(count, quad_group, &quad_count, &quads, &corners,
+                                            pattern_size, max_quad_buf_size, storage );
+        PRINTF("Finished ordering of inner quads (%d)\n", count);
+
+        if (count == 0)
+            continue;       // haven't found inner quads
+
+        // If count is more than it should be, this will remove those quads
+        // which cause maximum deviation from a nice square pattern.
+        count = icvCleanFoundConnectedQuads( count, quad_group, pattern_size );
+        PRINTF("Connected group: %d, count: %d\n", group_idx, count);
+
+        count = icvCheckQuadGroup( quad_group, count, corner_group, pattern_size );
+        PRINTF("Connected group: %d, count: %d\n", group_idx, count);
+
+        int n = count > 0 ? pattern_size.width * pattern_size.height : -count;
+        n = MIN( n, pattern_size.width * pattern_size.height );
+        float sum_dist = 0;
+        int total = 0;
+
+        for(int i = 0; i < n; i++ )
+        {
+            int ni = 0;
+            float avgi = corner_group[i]->meanDist(&ni);
+            sum_dist += avgi*ni;
+            total += ni;
+        }
+        prev_sqr_size = cvRound(sum_dist/MAX(total, 1));
+
+        if( count > 0 || (out_corner_count && -count > *out_corner_count) )
+        {
+            // copy corners to output array
+            for(int i = 0; i < n; i++ )
+                out_corners[i] = corner_group[i]->pt;
+
+            if( out_corner_count )
+                *out_corner_count = n;
+
+            if( count == pattern_size.width*pattern_size.height
+                    && icvCheckBoardMonotony( out_corners, pattern_size ))
+            {
+                found = true;
+                break;
+            }
+        }
+    }
+
+    cvFree(&quad_group);
+    cvFree(&corner_group);
+
+    return found;
+}
+
+//==================================================================================================
 
 CV_IMPL void
 cvDrawChessboardCorners( CvArr* _image, CvSize pattern_size,
@@ -1907,6 +2049,8 @@ cvDrawChessboardCorners( CvArr* _image, CvSize pattern_size,
 bool cv::findChessboardCorners( InputArray _image, Size patternSize,
                             OutputArray corners, int flags )
 {
+    CV_INSTRUMENT_REGION()
+
     int count = patternSize.area()*2;
     std::vector<Point2f> tmpcorners(count+1);
     Mat image = _image.getMat(); CvMat c_image = image;
@@ -1936,10 +2080,12 @@ void cv::drawChessboardCorners( InputOutputArray _image, Size patternSize,
                             InputArray _corners,
                             bool patternWasFound )
 {
+    CV_INSTRUMENT_REGION()
+
     Mat corners = _corners.getMat();
     if( corners.empty() )
         return;
-    Mat image = _image.getMat(); CvMat c_image = _image.getMat();
+    Mat image = _image.getMat(); CvMat c_image = image;
     int nelems = corners.checkVector(2, CV_32F, true);
     CV_Assert(nelems >= 0);
     cvDrawChessboardCorners( &c_image, patternSize, corners.ptr<CvPoint2D32f>(),
@@ -1949,6 +2095,8 @@ void cv::drawChessboardCorners( InputOutputArray _image, Size patternSize,
 bool cv::findCirclesGrid( InputArray _image, Size patternSize,
                           OutputArray _centers, int flags, const Ptr<FeatureDetector> &blobDetector )
 {
+    CV_INSTRUMENT_REGION()
+
     bool isAsymmetricGrid = (flags & CALIB_CB_ASYMMETRIC_GRID) ? true : false;
     bool isSymmetricGrid  = (flags & CALIB_CB_SYMMETRIC_GRID ) ? true : false;
     CV_Assert(isAsymmetricGrid ^ isSymmetricGrid);
diff --git a/modules/calib3d/src/calibration.cpp b/modules/calib3d/src/calibration.cpp
index dbf92c7..b90e71c 100644
--- a/modules/calib3d/src/calibration.cpp
+++ b/modules/calib3d/src/calibration.cpp
@@ -52,7 +52,6 @@
     that is (in a large extent) based on the paper:
     Z. Zhang. "A flexible new technique for camera calibration".
     IEEE Transactions on Pattern Analysis and Machine Intelligence, 22(11):1330-1334, 2000.
-
     The 1st initial port was done by Valery Mosyagin.
 */
 
@@ -287,7 +286,6 @@ CV_IMPL int cvRodrigues2( const CvMat* src, CvMat* dst, CvMat* jacobian )
 
     if( src->cols == 1 || src->rows == 1 )
     {
-        double rx, ry, rz, theta;
         int step = src->rows > 1 ? src->step / elem_size : 1;
 
         if( src->rows + src->cols*CV_MAT_CN(src->type) - 1 != 3 )
@@ -296,19 +294,21 @@ CV_IMPL int cvRodrigues2( const CvMat* src, CvMat* dst, CvMat* jacobian )
         if( dst->rows != 3 || dst->cols != 3 || CV_MAT_CN(dst->type) != 1 )
             CV_Error( CV_StsBadSize, "Output matrix must be 3x3, single-channel floating point matrix" );
 
+        Point3d r;
         if( depth == CV_32F )
         {
-            rx = src->data.fl[0];
-            ry = src->data.fl[step];
-            rz = src->data.fl[step*2];
+            r.x = src->data.fl[0];
+            r.y = src->data.fl[step];
+            r.z = src->data.fl[step*2];
         }
         else
         {
-            rx = src->data.db[0];
-            ry = src->data.db[step];
-            rz = src->data.db[step*2];
+            r.x = src->data.db[0];
+            r.y = src->data.db[step];
+            r.z = src->data.db[step*2];
         }
-        theta = std::sqrt(rx*rx + ry*ry + rz*rz);
+
+        double theta = norm(r);
 
         if( theta < DBL_EPSILON )
         {
@@ -323,54 +323,48 @@ CV_IMPL int cvRodrigues2( const CvMat* src, CvMat* dst, CvMat* jacobian )
         }
         else
         {
-            const double I[] = { 1, 0, 0, 0, 1, 0, 0, 0, 1 };
-
             double c = cos(theta);
             double s = sin(theta);
             double c1 = 1. - c;
             double itheta = theta ? 1./theta : 0.;
 
-            rx *= itheta; ry *= itheta; rz *= itheta;
+            r *= itheta;
 
-            double rrt[] = { rx*rx, rx*ry, rx*rz, rx*ry, ry*ry, ry*rz, rx*rz, ry*rz, rz*rz };
-            double _r_x_[] = { 0, -rz, ry, rz, 0, -rx, -ry, rx, 0 };
-            double R[9];
-            CvMat matR = cvMat( 3, 3, CV_64F, R );
+            Matx33d rrt( r.x*r.x, r.x*r.y, r.x*r.z, r.x*r.y, r.y*r.y, r.y*r.z, r.x*r.z, r.y*r.z, r.z*r.z );
+            Matx33d r_x(    0, -r.z,  r.y,
+                          r.z,    0, -r.x,
+                         -r.y,  r.x,    0 );
 
             // R = cos(theta)*I + (1 - cos(theta))*r*rT + sin(theta)*[r_x]
-            // where [r_x] is [0 -rz ry; rz 0 -rx; -ry rx 0]
-            for( k = 0; k < 9; k++ )
-                R[k] = c*I[k] + c1*rrt[k] + s*_r_x_[k];
+            Matx33d R = c*Matx33d::eye() + c1*rrt + s*r_x;
 
-            cvConvert( &matR, dst );
+            Mat(R).convertTo(cvarrToMat(dst), dst->type);
 
             if( jacobian )
             {
-                double drrt[] = { rx+rx, ry, rz, ry, 0, 0, rz, 0, 0,
-                                  0, rx, 0, rx, ry+ry, rz, 0, rz, 0,
-                                  0, 0, rx, 0, 0, ry, rx, ry, rz+rz };
+                const double I[] = { 1, 0, 0, 0, 1, 0, 0, 0, 1 };
+                double drrt[] = { r.x+r.x, r.y, r.z, r.y, 0, 0, r.z, 0, 0,
+                                  0, r.x, 0, r.x, r.y+r.y, r.z, 0, r.z, 0,
+                                  0, 0, r.x, 0, 0, r.y, r.x, r.y, r.z+r.z };
                 double d_r_x_[] = { 0, 0, 0, 0, 0, -1, 0, 1, 0,
                                     0, 0, 1, 0, 0, 0, -1, 0, 0,
                                     0, -1, 0, 1, 0, 0, 0, 0, 0 };
                 for( i = 0; i < 3; i++ )
                 {
-                    double ri = i == 0 ? rx : i == 1 ? ry : rz;
+                    double ri = i == 0 ? r.x : i == 1 ? r.y : r.z;
                     double a0 = -s*ri, a1 = (s - 2*c1*itheta)*ri, a2 = c1*itheta;
                     double a3 = (c - s*itheta)*ri, a4 = s*itheta;
                     for( k = 0; k < 9; k++ )
-                        J[i*9+k] = a0*I[k] + a1*rrt[k] + a2*drrt[i*9+k] +
-                                   a3*_r_x_[k] + a4*d_r_x_[i*9+k];
+                        J[i*9+k] = a0*I[k] + a1*rrt.val[k] + a2*drrt[i*9+k] +
+                                   a3*r_x.val[k] + a4*d_r_x_[i*9+k];
                 }
             }
         }
     }
     else if( src->cols == 3 && src->rows == 3 )
     {
-        double R[9], U[9], V[9], W[3], rx, ry, rz;
-        CvMat matR = cvMat( 3, 3, CV_64F, R );
-        CvMat matU = cvMat( 3, 3, CV_64F, U );
-        CvMat matV = cvMat( 3, 3, CV_64F, V );
-        CvMat matW = cvMat( 3, 1, CV_64F, W );
+        Matx33d U, Vt;
+        Vec3d W;
         double theta, s, c;
         int step = dst->rows > 1 ? dst->step / elem_size : 1;
 
@@ -378,8 +372,9 @@ CV_IMPL int cvRodrigues2( const CvMat* src, CvMat* dst, CvMat* jacobian )
             (dst->rows != 3 || dst->cols != 1 || CV_MAT_CN(dst->type) != 1))
             CV_Error( CV_StsBadSize, "Output matrix must be 1x3 or 3x1" );
 
-        cvConvert( src, &matR );
-        if( !cvCheckArr( &matR, CV_CHECK_RANGE+CV_CHECK_QUIET, -100, 100 ) )
+        Matx33d R = cvarrToMat(src);
+
+        if( !checkRange(R, true, NULL, -100, 100) )
         {
             cvZero(dst);
             if( jacobian )
@@ -387,15 +382,13 @@ CV_IMPL int cvRodrigues2( const CvMat* src, CvMat* dst, CvMat* jacobian )
             return 0;
         }
 
-        cvSVD( &matR, &matW, &matU, &matV, CV_SVD_MODIFY_A + CV_SVD_U_T + CV_SVD_V_T );
-        cvGEMM( &matU, &matV, 1, 0, 0, &matR, CV_GEMM_A_T );
+        SVD::compute(R, W, U, Vt);
+        R = U*Vt;
 
-        rx = R[7] - R[5];
-        ry = R[2] - R[6];
-        rz = R[3] - R[1];
+        Point3d r(R(2, 1) - R(1, 2), R(0, 2) - R(2, 0), R(1, 0) - R(0, 1));
 
-        s = std::sqrt((rx*rx + ry*ry + rz*rz)*0.25);
-        c = (R[0] + R[4] + R[8] - 1)*0.5;
+        s = std::sqrt((r.x*r.x + r.y*r.y + r.z*r.z)*0.25);
+        c = (R(0, 0) + R(1, 1) + R(2, 2) - 1)*0.5;
         c = c > 1. ? 1. : c < -1. ? -1. : c;
         theta = acos(c);
 
@@ -404,21 +397,19 @@ CV_IMPL int cvRodrigues2( const CvMat* src, CvMat* dst, CvMat* jacobian )
             double t;
 
             if( c > 0 )
-                rx = ry = rz = 0;
+                r = Point3d(0, 0, 0);
             else
             {
-                t = (R[0] + 1)*0.5;
-                rx = std::sqrt(MAX(t,0.));
-                t = (R[4] + 1)*0.5;
-                ry = std::sqrt(MAX(t,0.))*(R[1] < 0 ? -1. : 1.);
-                t = (R[8] + 1)*0.5;
-                rz = std::sqrt(MAX(t,0.))*(R[2] < 0 ? -1. : 1.);
-                if( fabs(rx) < fabs(ry) && fabs(rx) < fabs(rz) && (R[5] > 0) != (ry*rz > 0) )
-                    rz = -rz;
-                theta /= std::sqrt(rx*rx + ry*ry + rz*rz);
-                rx *= theta;
-                ry *= theta;
-                rz *= theta;
+                t = (R(0, 0) + 1)*0.5;
+                r.x = std::sqrt(MAX(t,0.));
+                t = (R(1, 1) + 1)*0.5;
+                r.y = std::sqrt(MAX(t,0.))*(R(0, 1) < 0 ? -1. : 1.);
+                t = (R(2, 2) + 1)*0.5;
+                r.z = std::sqrt(MAX(t,0.))*(R(0, 2) < 0 ? -1. : 1.);
+                if( fabs(r.x) < fabs(r.y) && fabs(r.x) < fabs(r.z) && (R(1, 2) > 0) != (r.y*r.z > 0) )
+                    r.z = -r.z;
+                theta /= norm(r);
+                r *= theta;
             }
 
             if( jacobian )
@@ -455,16 +446,16 @@ CV_IMPL int cvRodrigues2( const CvMat* src, CvMat* dst, CvMat* jacobian )
                 // var2 = [om;theta]
                 double dvar2dvar[] =
                 {
-                    vth, 0, 0, rx, 0,
-                    0, vth, 0, ry, 0,
-                    0, 0, vth, rz, 0,
+                    vth, 0, 0, r.x, 0,
+                    0, vth, 0, r.y, 0,
+                    0, 0, vth, r.z, 0,
                     0, 0, 0, 0, 1
                 };
                 double domegadvar2[] =
                 {
-                    theta, 0, 0, rx*vth,
-                    0, theta, 0, ry*vth,
-                    0, 0, theta, rz*vth
+                    theta, 0, 0, r.x*vth,
+                    0, theta, 0, r.y*vth,
+                    0, 0, theta, r.z*vth
                 };
 
                 CvMat _dvardR = cvMat( 5, 9, CV_64FC1, dvardR );
@@ -483,20 +474,20 @@ CV_IMPL int cvRodrigues2( const CvMat* src, CvMat* dst, CvMat* jacobian )
             }
 
             vth *= theta;
-            rx *= vth; ry *= vth; rz *= vth;
+            r *= vth;
         }
 
         if( depth == CV_32F )
         {
-            dst->data.fl[0] = (float)rx;
-            dst->data.fl[step] = (float)ry;
-            dst->data.fl[step*2] = (float)rz;
+            dst->data.fl[0] = (float)r.x;
+            dst->data.fl[step] = (float)r.y;
+            dst->data.fl[step*2] = (float)r.z;
         }
         else
         {
-            dst->data.db[0] = rx;
-            dst->data.db[step] = ry;
-            dst->data.db[step*2] = rz;
+            dst->data.db[0] = r.x;
+            dst->data.db[step] = r.y;
+            dst->data.db[step*2] = r.z;
         }
     }
 
@@ -796,7 +787,7 @@ CV_IMPL void cvProjectPoints2( const CvMat* objectPoints,
         {
             if( dpdc_p )
             {
-                dpdc_p[0] = 1; dpdc_p[1] = 0;
+                dpdc_p[0] = 1; dpdc_p[1] = 0; // dp_xdc_x; dp_xdc_y
                 dpdc_p[dpdc_step] = 0;
                 dpdc_p[dpdc_step+1] = 1;
                 dpdc_p += dpdc_step*2;
@@ -806,7 +797,7 @@ CV_IMPL void cvProjectPoints2( const CvMat* objectPoints,
             {
                 if( fixedAspectRatio )
                 {
-                    dpdf_p[0] = 0; dpdf_p[1] = xd*aspectRatio;
+                    dpdf_p[0] = 0; dpdf_p[1] = xd*aspectRatio; // dp_xdf_x; dp_xdf_y
                     dpdf_p[dpdf_step] = 0;
                     dpdf_p[dpdf_step+1] = yd;
                 }
@@ -904,9 +895,9 @@ CV_IMPL void cvProjectPoints2( const CvMat* objectPoints,
                     double dicdist2_dt = -icdist2*icdist2*(k[5]*dr2dt + 2*k[6]*r2*dr2dt + 3*k[7]*r4*dr2dt);
                     double da1dt = 2*(x*dydt[j] + y*dxdt[j]);
                     double dmxdt = (dxdt[j]*cdist*icdist2 + x*dcdist_dt*icdist2 + x*cdist*dicdist2_dt +
-                                       k[2]*da1dt + k[3]*(dr2dt + 2*x*dxdt[j]) + k[8]*dr2dt + 2*r2*k[9]*dr2dt);
+                                       k[2]*da1dt + k[3]*(dr2dt + 4*x*dxdt[j]) + k[8]*dr2dt + 2*r2*k[9]*dr2dt);
                     double dmydt = (dydt[j]*cdist*icdist2 + y*dcdist_dt*icdist2 + y*cdist*dicdist2_dt +
-                                       k[2]*(dr2dt + 2*y*dydt[j]) + k[3]*da1dt + k[10]*dr2dt + 2*r2*k[11]*dr2dt);
+                                       k[2]*(dr2dt + 4*y*dydt[j]) + k[3]*da1dt + k[10]*dr2dt + 2*r2*k[11]*dr2dt);
                     dXdYd = dMatTilt*Vec2d(dmxdt, dmydt);
                     dpdt_p[j] = fx*dXdYd(0);
                     dpdt_p[dpdt_step+j] = fy*dXdYd(1);
@@ -943,9 +934,9 @@ CV_IMPL void cvProjectPoints2( const CvMat* objectPoints,
                     double dicdist2_dr = -icdist2*icdist2*(k[5] + 2*k[6]*r2 + 3*k[7]*r4)*dr2dr;
                     double da1dr = 2*(x*dydr + y*dxdr);
                     double dmxdr = (dxdr*cdist*icdist2 + x*dcdist_dr*icdist2 + x*cdist*dicdist2_dr +
-                                       k[2]*da1dr + k[3]*(dr2dr + 2*x*dxdr) + (k[8] + 2*r2*k[9])*dr2dr);
+                                       k[2]*da1dr + k[3]*(dr2dr + 4*x*dxdr) + (k[8] + 2*r2*k[9])*dr2dr);
                     double dmydr = (dydr*cdist*icdist2 + y*dcdist_dr*icdist2 + y*cdist*dicdist2_dr +
-                                       k[2]*(dr2dr + 2*y*dydr) + k[3]*da1dr + (k[10] + 2*r2*k[11])*dr2dr);
+                                       k[2]*(dr2dr + 4*y*dydr) + k[3]*da1dr + (k[10] + 2*r2*k[11])*dr2dr);
                     dXdYd = dMatTilt*Vec2d(dmxdr, dmydr);
                     dpdr_p[j] = fx*dXdYd(0);
                     dpdr_p[dpdr_step+j] = fy*dXdYd(1);
@@ -1189,7 +1180,6 @@ CV_IMPL void cvFindExtrinsicCameraParams2( const CvMat* objectPoints,
     cvConvert( &_t, tvec );
 }
 
-
 CV_IMPL void cvInitIntrinsicParams2D( const CvMat* objectPoints,
                          const CvMat* imagePoints, const CvMat* npoints,
                          CvSize imageSize, CvMat* cameraMatrix,
@@ -1219,8 +1209,8 @@ CV_IMPL void cvInitIntrinsicParams2D( const CvMat* objectPoints,
 
     matA.reset(cvCreateMat( 2*nimages, 2, CV_64F ));
     _b.reset(cvCreateMat( 2*nimages, 1, CV_64F ));
-    a[2] = (!imageSize.width) ? 0.5 : (imageSize.width - 1)*0.5;
-    a[5] = (!imageSize.height) ? 0.5 : (imageSize.height - 1)*0.5;
+    a[2] = (!imageSize.width) ? 0.5 : (imageSize.width)*0.5;
+    a[5] = (!imageSize.height) ? 0.5 : (imageSize.height)*0.5;
     _allH.reset(cvCreateMat( nimages, 9, CV_64F ));
 
     // extract vanishing points in order to obtain initial value for the focal length
@@ -1278,15 +1268,37 @@ CV_IMPL void cvInitIntrinsicParams2D( const CvMat* objectPoints,
     cvConvert( &_a, cameraMatrix );
 }
 
+static void subMatrix(const cv::Mat& src, cv::Mat& dst, const std::vector<uchar>& cols,
+                      const std::vector<uchar>& rows) {
+    int nonzeros_cols = cv::countNonZero(cols);
+    cv::Mat tmp(src.rows, nonzeros_cols, CV_64FC1);
 
-/* finds intrinsic and extrinsic camera parameters
-   from a few views of known calibration pattern */
-CV_IMPL double cvCalibrateCamera2( const CvMat* objectPoints,
+    for (int i = 0, j = 0; i < (int)cols.size(); i++)
+    {
+        if (cols[i])
+        {
+            src.col(i).copyTo(tmp.col(j++));
+        }
+    }
+
+    int nonzeros_rows  = cv::countNonZero(rows);
+    dst.create(nonzeros_rows, nonzeros_cols, CV_64FC1);
+    for (int i = 0, j = 0; i < (int)rows.size(); i++)
+    {
+        if (rows[i])
+        {
+            tmp.row(i).copyTo(dst.row(j++));
+        }
+    }
+}
+
+static double cvCalibrateCamera2Internal( const CvMat* objectPoints,
                     const CvMat* imagePoints, const CvMat* npoints,
                     CvSize imageSize, CvMat* cameraMatrix, CvMat* distCoeffs,
-                    CvMat* rvecs, CvMat* tvecs, int flags, CvTermCriteria termCrit )
+                    CvMat* rvecs, CvMat* tvecs, CvMat* stdDevs,
+                    CvMat* perViewErrors, int flags, CvTermCriteria termCrit )
 {
-    const int NINTRINSIC = 18;
+    const int NINTRINSIC = CV_CALIB_NINTRINSIC;
     double reprojErr = 0;
 
     Matx33d A;
@@ -1346,6 +1358,20 @@ CV_IMPL double cvCalibrateCamera2( const CvMat* objectPoints,
                 "1xn or nx1 array or 1-channel nx3 array, where n is the number of views" );
     }
 
+    if( stdDevs )
+    {
+        cn = CV_MAT_CN(stdDevs->type);
+        if( !CV_IS_MAT(stdDevs) ||
+            (CV_MAT_DEPTH(stdDevs->type) != CV_32F && CV_MAT_DEPTH(stdDevs->type) != CV_64F) ||
+            ((stdDevs->rows != (nimages*6 + NINTRINSIC) || stdDevs->cols*cn != 1) &&
+            (stdDevs->rows != 1 || stdDevs->cols != (nimages*6 + NINTRINSIC) || cn != 1)) )
+#define STR__(x) #x
+#define STR_(x) STR__(x)
+            CV_Error( CV_StsBadArg, "the output array of standard deviations vectors must be 1-channel "
+                "1x(n*6 + NINTRINSIC) or (n*6 + NINTRINSIC)x1 array, where n is the number of views,"
+                " NINTRINSIC = " STR_(CV_CALIB_NINTRINSIC));
+    }
+
     if( (CV_MAT_TYPE(cameraMatrix->type) != CV_32FC1 &&
         CV_MAT_TYPE(cameraMatrix->type) != CV_64FC1) ||
         cameraMatrix->rows != 3 || cameraMatrix->cols != 3 )
@@ -1375,6 +1401,7 @@ CV_IMPL double cvCalibrateCamera2( const CvMat* objectPoints,
 
     Mat matM( 1, total, CV_64FC3 );
     Mat _m( 1, total, CV_64FC2 );
+    Mat allErrors(1, total, CV_64FC2);
 
     if(CV_MAT_CN(objectPoints->type) == 3) {
         cvarrToMat(objectPoints).convertTo(matM, CV_64F);
@@ -1458,6 +1485,9 @@ CV_IMPL double cvCalibrateCamera2( const CvMat* objectPoints,
     if(flags & CALIB_USE_LU) {
         solver.solveMethod = DECOMP_LU;
     }
+    else if(flags & CALIB_USE_QR) {
+        solver.solveMethod = DECOMP_QR;
+    }
 
     {
     double* param = solver.param->data.db;
@@ -1466,6 +1496,8 @@ CV_IMPL double cvCalibrateCamera2( const CvMat* objectPoints,
     param[0] = A(0, 0); param[1] = A(1, 1); param[2] = A(0, 2); param[3] = A(1, 2);
     std::copy(k, k + 14, param + 4);
 
+    if(flags & CALIB_FIX_ASPECT_RATIO)
+        mask[0] = 0;
     if( flags & CV_CALIB_FIX_FOCAL_LENGTH )
         mask[0] = mask[1] = 0;
     if( flags & CV_CALIB_FIX_PRINCIPAL_POINT )
@@ -1526,6 +1558,7 @@ CV_IMPL double cvCalibrateCamera2( const CvMat* objectPoints,
         double* _errNorm = 0;
         bool proceed = solver.updateAlt( _param, _JtJ, _JtErr, _errNorm );
         double *param = solver.param->data.db, *pparam = solver.prevParam->data.db;
+        bool calcJ = solver.state == CvLevMarq::CALC_J || (!proceed && stdDevs);
 
         if( flags & CALIB_FIX_ASPECT_RATIO )
         {
@@ -1536,8 +1569,10 @@ CV_IMPL double cvCalibrateCamera2( const CvMat* objectPoints,
         A(0, 0) = param[0]; A(1, 1) = param[1]; A(0, 2) = param[2]; A(1, 2) = param[3];
         std::copy(param + 4, param + 4 + 14, k);
 
-        if( !proceed )
+        if ( !proceed && !stdDevs && !perViewErrors )
             break;
+        else if ( !proceed && stdDevs )
+            cvZero(_JtJ);
 
         reprojErr = 0;
 
@@ -1551,6 +1586,7 @@ CV_IMPL double cvCalibrateCamera2( const CvMat* objectPoints,
 
             CvMat _Mi(matM.colRange(pos, pos + ni));
             CvMat _mi(_m.colRange(pos, pos + ni));
+            CvMat _me(allErrors.colRange(pos, pos + ni));
 
             _Je.resize(ni*2); _Ji.resize(ni*2); _err.resize(ni*2);
             CvMat _dpdr(_Je.colRange(0, 3));
@@ -1560,7 +1596,7 @@ CV_IMPL double cvCalibrateCamera2( const CvMat* objectPoints,
             CvMat _dpdk(_Ji.colRange(4, NINTRINSIC));
             CvMat _mp(_err.reshape(2, 1));
 
-            if( solver.state == CvLevMarq::CALC_J )
+            if( calcJ )
             {
                  cvProjectPoints2( &_Mi, &_ri, &_ti, &matA, &_k, &_mp, &_dpdr, &_dpdt,
                                   (flags & CALIB_FIX_FOCAL_LENGTH) ? 0 : &_dpdf,
@@ -1571,8 +1607,10 @@ CV_IMPL double cvCalibrateCamera2( const CvMat* objectPoints,
                 cvProjectPoints2( &_Mi, &_ri, &_ti, &matA, &_k, &_mp );
 
             cvSub( &_mp, &_mi, &_mp );
+            if (perViewErrors || stdDevs)
+                cvCopy(&_mp, &_me);
 
-            if( solver.state == CvLevMarq::CALC_J )
+            if( calcJ )
             {
                 Mat JtJ(cvarrToMat(_JtJ)), JtErr(cvarrToMat(_JtErr));
 
@@ -1589,15 +1627,52 @@ CV_IMPL double cvCalibrateCamera2( const CvMat* objectPoints,
         }
         if( _errNorm )
             *_errNorm = reprojErr;
+
+        if( !proceed )
+        {
+            if( stdDevs )
+            {
+                Mat mask = cvarrToMat(solver.mask);
+                int nparams_nz = countNonZero(mask);
+                Mat JtJinv, JtJN;
+                JtJN.create(nparams_nz, nparams_nz, CV_64F);
+                subMatrix(cvarrToMat(_JtJ), JtJN, mask, mask);
+                completeSymm(JtJN, false);
+                cv::invert(JtJN, JtJinv, DECOMP_SVD);
+                //sigma2 is deviation of the noise
+                //see any papers about variance of the least squares estimator for
+                //detailed description of the variance estimation methods
+                double sigma2 = norm(allErrors, NORM_L2SQR) / (total - nparams_nz);
+                Mat stdDevsM = cvarrToMat(stdDevs);
+                int j = 0;
+                for ( int s = 0; s < nparams; s++ )
+                    if( mask.data[s] )
+                    {
+                        stdDevsM.at<double>(s) = std::sqrt(JtJinv.at<double>(j,j) * sigma2);
+                        j++;
+                    }
+                    else
+                        stdDevsM.at<double>(s) = 0.;
+            }
+            break;
+        }
     }
 
     // 4. store the results
     cvConvert( &matA, cameraMatrix );
     cvConvert( &_k, distCoeffs );
 
-    for( i = 0; i < nimages; i++ )
+    for( i = 0, pos = 0; i < nimages; i++ )
     {
         CvMat src, dst;
+        if( perViewErrors )
+        {
+            ni = npoints->data.i[i*npstep];
+            perViewErrors->data.db[i] = std::sqrt(cv::norm(allErrors.colRange(pos, pos + ni),
+                                                           NORM_L2SQR) / ni);
+            pos+=ni;
+        }
+
         if( rvecs )
         {
             src = cvMat( 3, 1, CV_64F, solver.param->data.db + NINTRINSIC + i*6 );
@@ -1630,62 +1705,39 @@ CV_IMPL double cvCalibrateCamera2( const CvMat* objectPoints,
 }
 
 
+/* finds intrinsic and extrinsic camera parameters
+   from a few views of known calibration pattern */
+CV_IMPL double cvCalibrateCamera2( const CvMat* objectPoints,
+                    const CvMat* imagePoints, const CvMat* npoints,
+                    CvSize imageSize, CvMat* cameraMatrix, CvMat* distCoeffs,
+                    CvMat* rvecs, CvMat* tvecs, int flags, CvTermCriteria termCrit )
+{
+    return cvCalibrateCamera2Internal(objectPoints, imagePoints, npoints, imageSize, cameraMatrix,
+                                      distCoeffs, rvecs, tvecs, NULL, NULL, flags, termCrit);
+}
+
 void cvCalibrationMatrixValues( const CvMat *calibMatr, CvSize imgSize,
     double apertureWidth, double apertureHeight, double *fovx, double *fovy,
     double *focalLength, CvPoint2D64f *principalPoint, double *pasp )
 {
-    double alphax, alphay, mx, my;
-    int imgWidth = imgSize.width, imgHeight = imgSize.height;
-
     /* Validate parameters. */
-
     if(calibMatr == 0)
         CV_Error(CV_StsNullPtr, "Some of parameters is a NULL pointer!");
 
     if(!CV_IS_MAT(calibMatr))
         CV_Error(CV_StsUnsupportedFormat, "Input parameters must be a matrices!");
 
-    if(calibMatr->cols != 3 || calibMatr->rows != 3)
-        CV_Error(CV_StsUnmatchedSizes, "Size of matrices must be 3x3!");
-
-    alphax = cvmGet(calibMatr, 0, 0);
-    alphay = cvmGet(calibMatr, 1, 1);
-    assert(imgWidth != 0 && imgHeight != 0 && alphax != 0.0 && alphay != 0.0);
-
-    /* Calculate pixel aspect ratio. */
-    if(pasp)
-        *pasp = alphay / alphax;
-
-    /* Calculate number of pixel per realworld unit. */
-
-    if(apertureWidth != 0.0 && apertureHeight != 0.0) {
-        mx = imgWidth / apertureWidth;
-        my = imgHeight / apertureHeight;
-    } else {
-        mx = 1.0;
-        if(pasp)
-            my = *pasp;
-        else
-            my = 1.0;
-    }
-
-    /* Calculate fovx and fovy. */
-
-    if(fovx)
-        *fovx = 2 * atan(imgWidth / (2 * alphax)) * 180.0 / CV_PI;
-
-    if(fovy)
-        *fovy = 2 * atan(imgHeight / (2 * alphay)) * 180.0 / CV_PI;
-
-    /* Calculate focal length. */
-
-    if(focalLength)
-        *focalLength = alphax / mx;
-
-    /* Calculate principle point. */
+    double dummy;
+    Point2d pp;
+    cv::calibrationMatrixValues(cvarrToMat(calibMatr), imgSize, apertureWidth, apertureHeight,
+            fovx ? *fovx : dummy,
+            fovy ? *fovy : dummy,
+            focalLength ? *focalLength : dummy,
+            pp,
+            pasp ? *pasp : dummy);
 
     if(principalPoint)
-        *principalPoint = cvPoint2D64f(cvmGet(calibMatr, 0, 2) / mx, cvmGet(calibMatr, 1, 2) / my);
+        *principalPoint = cvPoint2D64f(pp.x, pp.y);
 }
 
 
@@ -1780,7 +1832,7 @@ double cvStereoCalibrate( const CvMat* _objectPoints, const CvMat* _imagePoints1
         if( !(flags & (CV_CALIB_FIX_INTRINSIC|CV_CALIB_USE_INTRINSIC_GUESS)))
         {
             cvCalibrateCamera2( objectPoints, imagePoints[k],
-                npoints, imageSize, &K[k], &Dist[k], 0, 0, flags );
+                npoints, imageSize, &K[k], &Dist[k], NULL, NULL, flags );
         }
     }
 
@@ -1863,14 +1915,12 @@ double cvStereoCalibrate( const CvMat* _objectPoints, const CvMat* _imagePoints1
 
     /*
        Compute initial estimate of pose
-
        For each image, compute:
           R(om) is the rotation matrix of om
           om(R) is the rotation vector of R
           R_ref = R(om_right) * R(om_left)'
           T_ref_list = [T_ref_list; T_right - R_ref * T_left]
           om_ref_list = {om_ref_list; om(R_ref)]
-
        om = median(om_ref_list)
        T = median(T_ref_list)
     */
@@ -2297,8 +2347,8 @@ void cvStereoRectify( const CvMat* _cameraMatrix1, const CvMat* _cameraMatrix2,
         for( i = 0; i < 4; i++ )
         {
             int j = (i<2) ? 0 : 1;
-            _pts[i].x = (float)((i % 2)*(nx-1));
-            _pts[i].y = (float)(j*(ny-1));
+            _pts[i].x = (float)((i % 2)*(nx));
+            _pts[i].y = (float)(j*(ny));
         }
         cvUndistortPoints( &pts, &pts, A, Dk, 0, 0 );
         cvConvertPointsHomogeneous( &pts, &pts_3 );
@@ -2312,8 +2362,8 @@ void cvStereoRectify( const CvMat* _cameraMatrix1, const CvMat* _cameraMatrix2,
         _a_tmp[1][2]=0.0;
         cvProjectPoints2( &pts_3, k == 0 ? _R1 : _R2, &Z, &A_tmp, 0, &pts );
         CvScalar avg = cvAvg(&pts);
-        cc_new[k].x = (nx-1)/2 - avg.val[0];
-        cc_new[k].y = (ny-1)/2 - avg.val[1];
+        cc_new[k].x = (nx)/2 - avg.val[0];
+        cc_new[k].y = (ny)/2 - avg.val[1];
     }
 
     // vertical focal length must be the same for both images to keep the epipolar constraint
@@ -2446,8 +2496,8 @@ void cvGetOptimalNewCameraMatrix( const CvMat* cameraMatrix, const CvMat* distCo
     {
         double cx0 = M[0][2];
         double cy0 = M[1][2];
-        double cx = (newImgSize.width-1)*0.5;
-        double cy = (newImgSize.height-1)*0.5;
+        double cx = (newImgSize.width)*0.5;
+        double cy = (newImgSize.height)*0.5;
 
         icvGetRectangles( cameraMatrix, distCoeffs, 0, cameraMatrix, imgSize, inner, outer );
         double s0 = std::max(std::max(std::max((double)cx/(cx0 - inner.x), (double)cy/(cy0 - inner.y)),
@@ -2481,14 +2531,14 @@ void cvGetOptimalNewCameraMatrix( const CvMat* cameraMatrix, const CvMat* distCo
         icvGetRectangles( cameraMatrix, distCoeffs, 0, 0, imgSize, inner, outer );
 
         // Projection mapping inner rectangle to viewport
-        double fx0 = (newImgSize.width  - 1) / inner.width;
-        double fy0 = (newImgSize.height - 1) / inner.height;
+        double fx0 = (newImgSize.width) / inner.width;
+        double fy0 = (newImgSize.height) / inner.height;
         double cx0 = -fx0 * inner.x;
         double cy0 = -fy0 * inner.y;
 
         // Projection mapping outer rectangle to viewport
-        double fx1 = (newImgSize.width  - 1) / outer.width;
-        double fy1 = (newImgSize.height - 1) / outer.height;
+        double fx1 = (newImgSize.width) / outer.width;
+        double fy1 = (newImgSize.height) / outer.height;
         double cx1 = -fx1 * outer.x;
         double cy1 = -fy1 * outer.y;
 
@@ -2552,8 +2602,8 @@ CV_IMPL int cvStereoRectifyUncalibrated(
     cvGEMM( &U, &W, 1, 0, 0, &W, CV_GEMM_A_T );
     cvMatMul( &W, &V, &F );
 
-    cx = cvRound( (imgSize.width-1)*0.5 );
-    cy = cvRound( (imgSize.height-1)*0.5 );
+    cx = cvRound( (imgSize.width)*0.5 );
+    cy = cvRound( (imgSize.height)*0.5 );
 
     cvZero( _H1 );
     cvZero( _H2 );
@@ -2705,6 +2755,8 @@ void cv::reprojectImageTo3D( InputArray _disparity,
                              OutputArray __3dImage, InputArray _Qmat,
                              bool handleMissingValues, int dtype )
 {
+    CV_INSTRUMENT_REGION()
+
     Mat disparity = _disparity.getMat(), Q = _Qmat.getMat();
     int stype = disparity.type();
 
@@ -3099,7 +3151,6 @@ static void collectCalibrationData( InputArrayOfArrays objectPoints,
     }
 }
 
-
 static Mat prepareCameraMatrix(Mat& cameraMatrix0, int rtype)
 {
     Mat cameraMatrix = Mat::eye(3, 3, rtype);
@@ -3108,9 +3159,10 @@ static Mat prepareCameraMatrix(Mat& cameraMatrix0, int rtype)
     return cameraMatrix;
 }
 
-static Mat prepareDistCoeffs(Mat& distCoeffs0, int rtype)
+static Mat prepareDistCoeffs(Mat& distCoeffs0, int rtype, int outputSize = 14)
 {
-    Mat distCoeffs = Mat::zeros(distCoeffs0.cols == 1 ? Size(1, 14) : Size(14, 1), rtype);
+    CV_Assert((int)distCoeffs0.total() <= outputSize);
+    Mat distCoeffs = Mat::zeros(distCoeffs0.cols == 1 ? Size(1, outputSize) : Size(outputSize, 1), rtype);
     if( distCoeffs0.size() == Size(1, 4) ||
        distCoeffs0.size() == Size(1, 5) ||
        distCoeffs0.size() == Size(1, 8) ||
@@ -3133,6 +3185,8 @@ static Mat prepareDistCoeffs(Mat& distCoeffs0, int rtype)
 
 void cv::Rodrigues(InputArray _src, OutputArray _dst, OutputArray _jacobian)
 {
+    CV_INSTRUMENT_REGION()
+
     Mat src = _src.getMat();
     bool v2m = src.cols == 1 || src.rows == 1;
     _dst.create(3, v2m ? 3 : 1, src.depth());
@@ -3151,6 +3205,8 @@ void cv::Rodrigues(InputArray _src, OutputArray _dst, OutputArray _jacobian)
 void cv::matMulDeriv( InputArray _Amat, InputArray _Bmat,
                       OutputArray _dABdA, OutputArray _dABdB )
 {
+    CV_INSTRUMENT_REGION()
+
     Mat A = _Amat.getMat(), B = _Bmat.getMat();
     _dABdA.create(A.rows*B.cols, A.rows*A.cols, A.type());
     _dABdB.create(A.rows*B.cols, B.rows*B.cols, A.type());
@@ -3178,54 +3234,20 @@ void cv::composeRT( InputArray _rvec1, InputArray _tvec1,
           c_tvec2 = tvec2, c_rvec3 = rvec3, c_tvec3 = tvec3;
     CvMat c_dr3dr1, c_dr3dt1, c_dr3dr2, c_dr3dt2, c_dt3dr1, c_dt3dt1, c_dt3dr2, c_dt3dt2;
     CvMat *p_dr3dr1=0, *p_dr3dt1=0, *p_dr3dr2=0, *p_dr3dt2=0, *p_dt3dr1=0, *p_dt3dt1=0, *p_dt3dr2=0, *p_dt3dt2=0;
-
-    if( _dr3dr1.needed() )
-    {
-        _dr3dr1.create(3, 3, rtype);
-        p_dr3dr1 = &(c_dr3dr1 = _dr3dr1.getMat());
+#define CV_COMPOSE_RT_PARAM(name) \
+    Mat name; \
+    if (_ ## name.needed())\
+    { \
+        _ ## name.create(3, 3, rtype); \
+        name = _ ## name.getMat(); \
+        p_ ## name = &(c_ ## name = name); \
     }
 
-    if( _dr3dt1.needed() )
-    {
-        _dr3dt1.create(3, 3, rtype);
-        p_dr3dt1 = &(c_dr3dt1 = _dr3dt1.getMat());
-    }
-
-    if( _dr3dr2.needed() )
-    {
-        _dr3dr2.create(3, 3, rtype);
-        p_dr3dr2 = &(c_dr3dr2 = _dr3dr2.getMat());
-    }
-
-    if( _dr3dt2.needed() )
-    {
-        _dr3dt2.create(3, 3, rtype);
-        p_dr3dt2 = &(c_dr3dt2 = _dr3dt2.getMat());
-    }
-
-    if( _dt3dr1.needed() )
-    {
-        _dt3dr1.create(3, 3, rtype);
-        p_dt3dr1 = &(c_dt3dr1 = _dt3dr1.getMat());
-    }
-
-    if( _dt3dt1.needed() )
-    {
-        _dt3dt1.create(3, 3, rtype);
-        p_dt3dt1 = &(c_dt3dt1 = _dt3dt1.getMat());
-    }
-
-    if( _dt3dr2.needed() )
-    {
-        _dt3dr2.create(3, 3, rtype);
-        p_dt3dr2 = &(c_dt3dr2 = _dt3dr2.getMat());
-    }
-
-    if( _dt3dt2.needed() )
-    {
-        _dt3dt2.create(3, 3, rtype);
-        p_dt3dt2 = &(c_dt3dt2 = _dt3dt2.getMat());
-    }
+    CV_COMPOSE_RT_PARAM(dr3dr1); CV_COMPOSE_RT_PARAM(dr3dt1);
+    CV_COMPOSE_RT_PARAM(dr3dr2); CV_COMPOSE_RT_PARAM(dr3dt2);
+    CV_COMPOSE_RT_PARAM(dt3dr1); CV_COMPOSE_RT_PARAM(dt3dt1);
+    CV_COMPOSE_RT_PARAM(dt3dr2); CV_COMPOSE_RT_PARAM(dt3dt2);
+#undef CV_COMPOSE_RT_PARAM
 
     cvComposeRT(&c_rvec1, &c_tvec1, &c_rvec2, &c_tvec2, &c_rvec3, &c_tvec3,
                 p_dr3dr1, p_dr3dt1, p_dr3dr2, p_dr3dt2,
@@ -3250,7 +3272,8 @@ void cv::projectPoints( InputArray _opoints,
     CvMat *pdpdrot=0, *pdpdt=0, *pdpdf=0, *pdpdc=0, *pdpddist=0;
 
     _ipoints.create(npoints, 1, CV_MAKETYPE(depth, 2), -1, true);
-    CvMat c_imagePoints = _ipoints.getMat();
+    Mat imagePoints = _ipoints.getMat();
+    CvMat c_imagePoints(imagePoints);
     CvMat c_objectPoints = opoints;
     Mat cameraMatrix = _cameraMatrix.getMat();
 
@@ -3285,6 +3308,8 @@ cv::Mat cv::initCameraMatrix2D( InputArrayOfArrays objectPoints,
                                 InputArrayOfArrays imagePoints,
                                 Size imageSize, double aspectRatio )
 {
+    CV_INSTRUMENT_REGION()
+
     Mat objPt, imgPt, npoints, cameraMatrix(3, 3, CV_64F);
     collectCalibrationData( objectPoints, imagePoints, noArray(),
                             objPt, imgPt, 0, npoints );
@@ -3295,16 +3320,34 @@ cv::Mat cv::initCameraMatrix2D( InputArrayOfArrays objectPoints,
 }
 
 
+
 double cv::calibrateCamera( InputArrayOfArrays _objectPoints,
                             InputArrayOfArrays _imagePoints,
                             Size imageSize, InputOutputArray _cameraMatrix, InputOutputArray _distCoeffs,
                             OutputArrayOfArrays _rvecs, OutputArrayOfArrays _tvecs, int flags, TermCriteria criteria )
 {
+    CV_INSTRUMENT_REGION()
+
+    return calibrateCamera(_objectPoints, _imagePoints, imageSize, _cameraMatrix, _distCoeffs,
+                                         _rvecs, _tvecs, noArray(), noArray(), noArray(), flags, criteria);
+}
+
+double cv::calibrateCamera(InputArrayOfArrays _objectPoints,
+                            InputArrayOfArrays _imagePoints,
+                            Size imageSize, InputOutputArray _cameraMatrix, InputOutputArray _distCoeffs,
+                            OutputArrayOfArrays _rvecs, OutputArrayOfArrays _tvecs,
+                            OutputArray stdDeviationsIntrinsics,
+                            OutputArray stdDeviationsExtrinsics,
+                            OutputArray _perViewErrors, int flags, TermCriteria criteria )
+{
+    CV_INSTRUMENT_REGION()
+
     int rtype = CV_64F;
     Mat cameraMatrix = _cameraMatrix.getMat();
     cameraMatrix = prepareCameraMatrix(cameraMatrix, rtype);
     Mat distCoeffs = _distCoeffs.getMat();
-    distCoeffs = prepareDistCoeffs(distCoeffs, rtype);
+    distCoeffs = (flags & CALIB_THIN_PRISM_MODEL) && !(flags & CALIB_TILTED_MODEL)  ? prepareDistCoeffs(distCoeffs, rtype, 12) :
+                                                      prepareDistCoeffs(distCoeffs, rtype);
     if( !(flags & CALIB_RATIONAL_MODEL) &&
     (!(flags & CALIB_THIN_PRISM_MODEL)) &&
     (!(flags & CALIB_TILTED_MODEL)))
@@ -3312,14 +3355,17 @@ double cv::calibrateCamera( InputArrayOfArrays _objectPoints,
 
     int nimages = int(_objectPoints.total());
     CV_Assert( nimages > 0 );
-    Mat objPt, imgPt, npoints, rvecM, tvecM;
+    Mat objPt, imgPt, npoints, rvecM, tvecM, stdDeviationsM, errorsM;
 
-    bool rvecs_needed = _rvecs.needed(), tvecs_needed = _tvecs.needed();
+    bool rvecs_needed = _rvecs.needed(), tvecs_needed = _tvecs.needed(),
+            stddev_needed = stdDeviationsIntrinsics.needed(), errors_needed = _perViewErrors.needed(),
+            stddev_ext_needed = stdDeviationsExtrinsics.needed();
 
     bool rvecs_mat_vec = _rvecs.isMatVector();
     bool tvecs_mat_vec = _tvecs.isMatVector();
 
-    if( rvecs_needed ) {
+    if( rvecs_needed )
+    {
         _rvecs.create(nimages, 1, CV_64FC3);
 
         if(rvecs_mat_vec)
@@ -3328,7 +3374,8 @@ double cv::calibrateCamera( InputArrayOfArrays _objectPoints,
             rvecM = _rvecs.getMat();
     }
 
-    if( tvecs_needed ) {
+    if( tvecs_needed )
+    {
         _tvecs.create(nimages, 1, CV_64FC3);
 
         if(tvecs_mat_vec)
@@ -3337,16 +3384,46 @@ double cv::calibrateCamera( InputArrayOfArrays _objectPoints,
             tvecM = _tvecs.getMat();
     }
 
+    if( stddev_needed || stddev_ext_needed )
+    {
+        stdDeviationsM.create(nimages*6 + CV_CALIB_NINTRINSIC, 1, CV_64F);
+    }
+
+    if( errors_needed )
+    {
+        _perViewErrors.create(nimages, 1, CV_64F);
+        errorsM = _perViewErrors.getMat();
+    }
+
     collectCalibrationData( _objectPoints, _imagePoints, noArray(),
                             objPt, imgPt, 0, npoints );
     CvMat c_objPt = objPt, c_imgPt = imgPt, c_npoints = npoints;
     CvMat c_cameraMatrix = cameraMatrix, c_distCoeffs = distCoeffs;
-    CvMat c_rvecM = rvecM, c_tvecM = tvecM;
+    CvMat c_rvecM = rvecM, c_tvecM = tvecM, c_stdDev = stdDeviationsM, c_errors = errorsM;
 
-    double reprojErr = cvCalibrateCamera2(&c_objPt, &c_imgPt, &c_npoints, imageSize,
+    double reprojErr = cvCalibrateCamera2Internal(&c_objPt, &c_imgPt, &c_npoints, imageSize,
                                           &c_cameraMatrix, &c_distCoeffs,
                                           rvecs_needed ? &c_rvecM : NULL,
-                                          tvecs_needed ? &c_tvecM : NULL, flags, criteria );
+                                          tvecs_needed ? &c_tvecM : NULL,
+                                          stddev_needed ? &c_stdDev : NULL,
+                                          errors_needed ? &c_errors : NULL, flags, criteria );
+
+    if( stddev_needed )
+    {
+        stdDeviationsIntrinsics.create(CV_CALIB_NINTRINSIC, 1, CV_64F);
+        Mat stdDeviationsIntrinsicsMat = stdDeviationsIntrinsics.getMat();
+        std::memcpy(stdDeviationsIntrinsicsMat.ptr(), stdDeviationsM.ptr(),
+                    CV_CALIB_NINTRINSIC*sizeof(double));
+    }
+
+    if ( stddev_ext_needed )
+    {
+        stdDeviationsExtrinsics.create(nimages*6, 1, CV_64F);
+        Mat stdDeviationsExtrinsicsMat = stdDeviationsExtrinsics.getMat();
+        std::memcpy(stdDeviationsExtrinsicsMat.ptr(),
+                    stdDeviationsM.ptr() + CV_CALIB_NINTRINSIC*sizeof(double),
+                    nimages*6*sizeof(double));
+    }
 
     // overly complicated and inefficient rvec/ tvec handling to support vector<Mat>
     for(int i = 0; i < nimages; i++ )
@@ -3377,10 +3454,39 @@ void cv::calibrationMatrixValues( InputArray _cameraMatrix, Size imageSize,
                                   double& fovx, double& fovy, double& focalLength,
                                   Point2d& principalPoint, double& aspectRatio )
 {
-    Mat cameraMatrix = _cameraMatrix.getMat();
-    CvMat c_cameraMatrix = cameraMatrix;
-    cvCalibrationMatrixValues( &c_cameraMatrix, imageSize, apertureWidth, apertureHeight,
-        &fovx, &fovy, &focalLength, (CvPoint2D64f*)&principalPoint, &aspectRatio );
+    CV_INSTRUMENT_REGION()
+
+    if(_cameraMatrix.size() != Size(3, 3))
+        CV_Error(CV_StsUnmatchedSizes, "Size of cameraMatrix must be 3x3!");
+
+    Matx33d K = _cameraMatrix.getMat();
+
+    CV_DbgAssert(imageSize.width != 0 && imageSize.height != 0 && K(0, 0) != 0.0 && K(1, 1) != 0.0);
+
+    /* Calculate pixel aspect ratio. */
+    aspectRatio = K(1, 1) / K(0, 0);
+
+    /* Calculate number of pixel per realworld unit. */
+    double mx, my;
+    if(apertureWidth != 0.0 && apertureHeight != 0.0) {
+        mx = imageSize.width / apertureWidth;
+        my = imageSize.height / apertureHeight;
+    } else {
+        mx = 1.0;
+        my = aspectRatio;
+    }
+
+    /* Calculate fovx and fovy. */
+    fovx = atan2(K(0, 2), K(0, 0)) + atan2(imageSize.width  - K(0, 2), K(0, 0));
+    fovy = atan2(K(1, 2), K(1, 1)) + atan2(imageSize.height - K(1, 2), K(1, 1));
+    fovx *= 180.0 / CV_PI;
+    fovy *= 180.0 / CV_PI;
+
+    /* Calculate focal length. */
+    focalLength = K(0, 0) / mx;
+
+    /* Calculate principle point. */
+    principalPoint = Point2d(K(0, 2) / mx, K(1, 2) / my);
 }
 
 double cv::stereoCalibrate( InputArrayOfArrays _objectPoints,
@@ -3489,6 +3595,8 @@ bool cv::stereoRectifyUncalibrated( InputArray _points1, InputArray _points2,
                                     InputArray _Fmat, Size imgSize,
                                     OutputArray _Hmat1, OutputArray _Hmat2, double threshold )
 {
+    CV_INSTRUMENT_REGION()
+
     int rtype = CV_64F;
     _Hmat1.create(3, 3, rtype);
     _Hmat2.create(3, 3, rtype);
@@ -3506,6 +3614,8 @@ cv::Mat cv::getOptimalNewCameraMatrix( InputArray _cameraMatrix,
                                        Size imgSize, double alpha, Size newImgSize,
                                        Rect* validPixROI, bool centerPrincipalPoint )
 {
+    CV_INSTRUMENT_REGION()
+
     Mat cameraMatrix = _cameraMatrix.getMat(), distCoeffs = _distCoeffs.getMat();
     CvMat c_cameraMatrix = cameraMatrix, c_distCoeffs = distCoeffs;
 
@@ -3526,27 +3636,30 @@ cv::Vec3d cv::RQDecomp3x3( InputArray _Mmat,
                            OutputArray _Qy,
                            OutputArray _Qz )
 {
+    CV_INSTRUMENT_REGION()
+
     Mat M = _Mmat.getMat();
     _Rmat.create(3, 3, M.type());
     _Qmat.create(3, 3, M.type());
+    Mat Rmat = _Rmat.getMat();
+    Mat Qmat = _Qmat.getMat();
     Vec3d eulerAngles;
 
-    CvMat matM = M, matR = _Rmat.getMat(), matQ = _Qmat.getMat(), Qx, Qy, Qz, *pQx=0, *pQy=0, *pQz=0;
-    if( _Qx.needed() )
-    {
-        _Qx.create(3, 3, M.type());
-        pQx = &(Qx = _Qx.getMat());
-    }
-    if( _Qy.needed() )
-    {
-        _Qy.create(3, 3, M.type());
-        pQy = &(Qy = _Qy.getMat());
-    }
-    if( _Qz.needed() )
-    {
-        _Qz.create(3, 3, M.type());
-        pQz = &(Qz = _Qz.getMat());
-    }
+    CvMat matM = M, matR = Rmat, matQ = Qmat;
+#define CV_RQDecomp3x3_PARAM(name) \
+    Mat name; \
+    CvMat c_ ## name, *p ## name = NULL; \
+    if( _ ## name.needed() ) \
+    { \
+        _ ## name.create(3, 3, M.type()); \
+        name = _ ## name.getMat(); \
+        c_ ## name = name; p ## name = &c_ ## name; \
+    }
+
+    CV_RQDecomp3x3_PARAM(Qx);
+    CV_RQDecomp3x3_PARAM(Qy);
+    CV_RQDecomp3x3_PARAM(Qz);
+#undef CV_RQDecomp3x3_PARAM
     cvRQDecomp3x3(&matM, &matR, &matQ, pQx, pQy, pQz, (CvPoint3D64f*)&eulerAngles[0]);
     return eulerAngles;
 }
@@ -3557,33 +3670,35 @@ void cv::decomposeProjectionMatrix( InputArray _projMatrix, OutputArray _cameraM
                                     OutputArray _rotMatrixX, OutputArray _rotMatrixY,
                                     OutputArray _rotMatrixZ, OutputArray _eulerAngles )
 {
+    CV_INSTRUMENT_REGION()
+
     Mat projMatrix = _projMatrix.getMat();
     int type = projMatrix.type();
     _cameraMatrix.create(3, 3, type);
     _rotMatrix.create(3, 3, type);
     _transVect.create(4, 1, type);
-    CvMat c_projMatrix = projMatrix, c_cameraMatrix = _cameraMatrix.getMat();
-    CvMat c_rotMatrix = _rotMatrix.getMat(), c_transVect = _transVect.getMat();
-    CvMat c_rotMatrixX, *p_rotMatrixX = 0;
-    CvMat c_rotMatrixY, *p_rotMatrixY = 0;
-    CvMat c_rotMatrixZ, *p_rotMatrixZ = 0;
+    Mat cameraMatrix = _cameraMatrix.getMat();
+    Mat rotMatrix = _rotMatrix.getMat();
+    Mat transVect = _transVect.getMat();
+    CvMat c_projMatrix = projMatrix, c_cameraMatrix = cameraMatrix;
+    CvMat c_rotMatrix = rotMatrix, c_transVect = transVect;
     CvPoint3D64f *p_eulerAngles = 0;
 
-    if( _rotMatrixX.needed() )
-    {
-        _rotMatrixX.create(3, 3, type);
-        p_rotMatrixX = &(c_rotMatrixX = _rotMatrixX.getMat());
-    }
-    if( _rotMatrixY.needed() )
-    {
-        _rotMatrixY.create(3, 3, type);
-        p_rotMatrixY = &(c_rotMatrixY = _rotMatrixY.getMat());
-    }
-    if( _rotMatrixZ.needed() )
-    {
-        _rotMatrixZ.create(3, 3, type);
-        p_rotMatrixZ = &(c_rotMatrixZ = _rotMatrixZ.getMat());
+#define CV_decomposeProjectionMatrix_PARAM(name) \
+    Mat name; \
+    CvMat c_ ## name, *p_ ## name = NULL; \
+    if( _ ## name.needed() ) \
+    { \
+        _ ## name.create(3, 3, type); \
+        name = _ ## name.getMat(); \
+        c_ ## name = name; p_ ## name = &c_ ## name; \
     }
+
+    CV_decomposeProjectionMatrix_PARAM(rotMatrixX);
+    CV_decomposeProjectionMatrix_PARAM(rotMatrixY);
+    CV_decomposeProjectionMatrix_PARAM(rotMatrixZ);
+#undef CV_decomposeProjectionMatrix_PARAM
+
     if( _eulerAngles.needed() )
     {
         _eulerAngles.create(3, 1, CV_64F, -1, true);
diff --git a/modules/calib3d/src/checkchessboard.cpp b/modules/calib3d/src/checkchessboard.cpp
index 715fe73..ea34878 100644
--- a/modules/calib3d/src/checkchessboard.cpp
+++ b/modules/calib3d/src/checkchessboard.cpp
@@ -46,26 +46,26 @@
 #include <vector>
 #include <algorithm>
 
-//#define DEBUG_WINDOWS
-
-#if defined(DEBUG_WINDOWS)
-#  include "opencv2/opencv_modules.hpp"
-#  ifdef HAVE_OPENCV_HIGHGUI
-#    include "opencv2/highgui.hpp"
-#  else
-#    undef DEBUG_WINDOWS
-#  endif
-#endif
-
-static void icvGetQuadrangleHypotheses(CvSeq* contours, std::vector<std::pair<float, int> >& quads, int class_id)
+using namespace cv;
+using namespace std;
+
+static void icvGetQuadrangleHypotheses(const std::vector<std::vector< cv::Point > > & contours, const std::vector< cv::Vec4i > & hierarchy, std::vector<std::pair<float, int> >& quads, int class_id)
 {
     const float min_aspect_ratio = 0.3f;
     const float max_aspect_ratio = 3.0f;
     const float min_box_size = 10.0f;
 
-    for(CvSeq* seq = contours; seq != NULL; seq = seq->h_next)
+    typedef std::vector< std::vector< cv::Point > >::const_iterator iter_t;
+    iter_t i;
+    for (i = contours.begin(); i != contours.end(); ++i)
     {
-        CvBox2D box = cvMinAreaRect2(seq);
+        const iter_t::difference_type idx = i - contours.begin();
+        if (hierarchy.at(idx)[3] != -1)
+            continue; // skip holes
+
+        const std::vector< cv::Point > & c = *i;
+        cv::RotatedRect box = cv::minAreaRect(c);
+
         float box_size = MAX(box.size.width, box.size.height);
         if(box_size < min_box_size)
         {
@@ -96,6 +96,64 @@ inline bool less_pred(const std::pair<float, int>& p1, const std::pair<float, in
     return p1.first < p2.first;
 }
 
+static void fillQuads(Mat & white, Mat & black, double white_thresh, double black_thresh, vector<pair<float, int> > & quads)
+{
+    Mat thresh;
+    {
+        vector< vector<Point> > contours;
+        vector< Vec4i > hierarchy;
+        threshold(white, thresh, white_thresh, 255, THRESH_BINARY);
+        findContours(thresh, contours, hierarchy, RETR_CCOMP, CHAIN_APPROX_SIMPLE);
+        icvGetQuadrangleHypotheses(contours, hierarchy, quads, 1);
+    }
+
+    {
+        vector< vector<Point> > contours;
+        vector< Vec4i > hierarchy;
+        threshold(black, thresh, black_thresh, 255, THRESH_BINARY_INV);
+        findContours(thresh, contours, hierarchy, RETR_CCOMP, CHAIN_APPROX_SIMPLE);
+        icvGetQuadrangleHypotheses(contours, hierarchy, quads, 0);
+    }
+}
+
+static bool checkQuads(vector<pair<float, int> > & quads, const cv::Size & size)
+{
+    const size_t min_quads_count = size.width*size.height/2;
+    std::sort(quads.begin(), quads.end(), less_pred);
+
+    // now check if there are many hypotheses with similar sizes
+    // do this by floodfill-style algorithm
+    const float size_rel_dev = 0.4f;
+
+    for(size_t i = 0; i < quads.size(); i++)
+    {
+        size_t j = i + 1;
+        for(; j < quads.size(); j++)
+        {
+            if(quads[j].first/quads[i].first > 1.0f + size_rel_dev)
+            {
+                break;
+            }
+        }
+
+        if(j + 1 > min_quads_count + i)
+        {
+            // check the number of black and white squares
+            std::vector<int> counts;
+            countClasses(quads, i, j, counts);
+            const int black_count = cvRound(ceil(size.width/2.0)*ceil(size.height/2.0));
+            const int white_count = cvRound(floor(size.width/2.0)*floor(size.height/2.0));
+            if(counts[0] < black_count*0.75 ||
+               counts[1] < white_count*0.75)
+            {
+                continue;
+            }
+            return true;
+        }
+    }
+    return false;
+}
+
 // does a fast check if a chessboard is in the input image. This is a workaround to
 // a problem of cvFindChessboardCorners being slow on images with no chessboard
 // - src: input image
@@ -104,104 +162,64 @@ inline bool less_pred(const std::pair<float, int>& p1, const std::pair<float, in
 // 0 if there is no chessboard, -1 in case of error
 int cvCheckChessboard(IplImage* src, CvSize size)
 {
-    if(src->nChannels > 1)
-    {
-        cvError(CV_BadNumChannels, "cvCheckChessboard", "supports single-channel images only",
-                __FILE__, __LINE__);
-    }
+    cv::Mat img = cv::cvarrToMat(src);
+    return checkChessboard(img, size);
+}
 
-    if(src->depth != 8)
-    {
-        cvError(CV_BadDepth, "cvCheckChessboard", "supports depth=8 images only",
-                __FILE__, __LINE__);
-    }
+int checkChessboard(const cv::Mat & img, const cv::Size & size)
+{
+    CV_Assert(img.channels() == 1 && img.depth() == CV_8U);
 
     const int erosion_count = 1;
     const float black_level = 20.f;
     const float white_level = 130.f;
     const float black_white_gap = 70.f;
 
-#if defined(DEBUG_WINDOWS)
-    cvNamedWindow("1", 1);
-    cvShowImage("1", src);
-    cvWaitKey(0);
-#endif //DEBUG_WINDOWS
-
-    CvMemStorage* storage = cvCreateMemStorage();
-
-    IplImage* white = cvCloneImage(src);
-    IplImage* black = cvCloneImage(src);
-
-    cvErode(white, white, NULL, erosion_count);
-    cvDilate(black, black, NULL, erosion_count);
-    IplImage* thresh = cvCreateImage(cvGetSize(src), IPL_DEPTH_8U, 1);
+    Mat white;
+    Mat black;
+    erode(img, white, Mat(), Point(-1, -1), erosion_count);
+    dilate(img, black, Mat(), Point(-1, -1), erosion_count);
 
     int result = 0;
     for(float thresh_level = black_level; thresh_level < white_level && !result; thresh_level += 20.0f)
     {
-        cvThreshold(white, thresh, thresh_level + black_white_gap, 255, CV_THRESH_BINARY);
-
-#if defined(DEBUG_WINDOWS)
-        cvShowImage("1", thresh);
-        cvWaitKey(0);
-#endif //DEBUG_WINDOWS
-
-        CvSeq* first = 0;
-        std::vector<std::pair<float, int> > quads;
-        cvFindContours(thresh, storage, &first, sizeof(CvContour), CV_RETR_CCOMP);
-        icvGetQuadrangleHypotheses(first, quads, 1);
-
-        cvThreshold(black, thresh, thresh_level, 255, CV_THRESH_BINARY_INV);
-
-#if defined(DEBUG_WINDOWS)
-        cvShowImage("1", thresh);
-        cvWaitKey(0);
-#endif //DEBUG_WINDOWS
+        vector<pair<float, int> > quads;
+        fillQuads(white, black, thresh_level + black_white_gap, thresh_level, quads);
+        if (checkQuads(quads, size))
+            result = 1;
+    }
+    return result;
+}
 
-        cvFindContours(thresh, storage, &first, sizeof(CvContour), CV_RETR_CCOMP);
-        icvGetQuadrangleHypotheses(first, quads, 0);
+// does a fast check if a chessboard is in the input image. This is a workaround to
+// a problem of cvFindChessboardCorners being slow on images with no chessboard
+// - src: input binary image
+// - size: chessboard size
+// Returns 1 if a chessboard can be in this image and findChessboardCorners should be called,
+// 0 if there is no chessboard, -1 in case of error
+int checkChessboardBinary(const cv::Mat & img, const cv::Size & size)
+{
+    CV_Assert(img.channels() == 1 && img.depth() == CV_8U);
 
-        const size_t min_quads_count = size.width*size.height/2;
-        std::sort(quads.begin(), quads.end(), less_pred);
+    Mat white = img.clone();
+    Mat black = img.clone();
 
-        // now check if there are many hypotheses with similar sizes
-        // do this by floodfill-style algorithm
-        const float size_rel_dev = 0.4f;
+    int result = 0;
+    for ( int erosion_count = 0; erosion_count <= 3; erosion_count++ )
+    {
+        if ( 1 == result )
+            break;
 
-        for(size_t i = 0; i < quads.size(); i++)
+        if ( 0 != erosion_count ) // first iteration keeps original images
         {
-            size_t j = i + 1;
-            for(; j < quads.size(); j++)
-            {
-                if(quads[j].first/quads[i].first > 1.0f + size_rel_dev)
-                {
-                    break;
-                }
-            }
-
-            if(j + 1 > min_quads_count + i)
-            {
-                // check the number of black and white squares
-                std::vector<int> counts;
-                countClasses(quads, i, j, counts);
-                const int black_count = cvRound(ceil(size.width/2.0)*ceil(size.height/2.0));
-                const int white_count = cvRound(floor(size.width/2.0)*floor(size.height/2.0));
-                if(counts[0] < black_count*0.75 ||
-                   counts[1] < white_count*0.75)
-                {
-                    continue;
-                }
-                result = 1;
-                break;
-            }
+            erode(white, white, Mat(), Point(-1, -1), 1);
+            dilate(black, black, Mat(), Point(-1, -1), 1);
         }
-    }
-
-
-    cvReleaseImage(&thresh);
-    cvReleaseImage(&white);
-    cvReleaseImage(&black);
-    cvReleaseMemStorage(&storage);
 
+        vector<pair<float, int> > quads;
+        fillQuads(white, black, 128, 128, quads);
+        if (checkQuads(quads, size))
+            result = 1;
+    }
     return result;
 }
diff --git a/modules/calib3d/src/circlesgrid.cpp b/modules/calib3d/src/circlesgrid.cpp
index 39abd8a..2038e52 100644
--- a/modules/calib3d/src/circlesgrid.cpp
+++ b/modules/calib3d/src/circlesgrid.cpp
@@ -129,7 +129,7 @@ void CirclesGridClusterFinder::hierarchicalClustering(const std::vector<Point2f>
     }
 
     patternPoints.reserve(clusters[patternClusterIdx].size());
-    for(std::list<size_t>::iterator it = clusters[patternClusterIdx].begin(); it != clusters[patternClusterIdx].end(); it++)
+    for(std::list<size_t>::iterator it = clusters[patternClusterIdx].begin(); it != clusters[patternClusterIdx].end();++it)
     {
         patternPoints.push_back(points[*it]);
     }
@@ -320,7 +320,7 @@ void CirclesGridClusterFinder::getSortedCorners(const std::vector<cv::Point2f> &
 
   std::vector<Point2f>::const_iterator firstCornerIterator = std::find(hull2f.begin(), hull2f.end(), firstCorner);
   sortedCorners.clear();
-  for(std::vector<Point2f>::const_iterator it = firstCornerIterator; it != hull2f.end(); it++)
+  for(std::vector<Point2f>::const_iterator it = firstCornerIterator; it != hull2f.end();++it)
   {
     std::vector<Point2f>::const_iterator itCorners = std::find(corners.begin(), corners.end(), *it);
     if(itCorners != corners.end())
@@ -328,7 +328,7 @@ void CirclesGridClusterFinder::getSortedCorners(const std::vector<cv::Point2f> &
       sortedCorners.push_back(*it);
     }
   }
-  for(std::vector<Point2f>::const_iterator it = hull2f.begin(); it != firstCornerIterator; it++)
+  for(std::vector<Point2f>::const_iterator it = hull2f.begin(); it != firstCornerIterator;++it)
   {
     std::vector<Point2f>::const_iterator itCorners = std::find(corners.begin(), corners.end(), *it);
     if(itCorners != corners.end())
@@ -493,21 +493,21 @@ void Graph::floydWarshall(cv::Mat &distanceMatrix, int infinity) const
   const int n = (int)getVerticesCount();
   distanceMatrix.create(n, n, CV_32SC1);
   distanceMatrix.setTo(infinity);
-  for (Vertices::const_iterator it1 = vertices.begin(); it1 != vertices.end(); it1++)
+  for (Vertices::const_iterator it1 = vertices.begin(); it1 != vertices.end();++it1)
   {
     distanceMatrix.at<int> ((int)it1->first, (int)it1->first) = 0;
-    for (Neighbors::const_iterator it2 = it1->second.neighbors.begin(); it2 != it1->second.neighbors.end(); it2++)
+    for (Neighbors::const_iterator it2 = it1->second.neighbors.begin(); it2 != it1->second.neighbors.end();++it2)
     {
       CV_Assert( it1->first != *it2 );
       distanceMatrix.at<int> ((int)it1->first, (int)*it2) = edgeWeight;
     }
   }
 
-  for (Vertices::const_iterator it1 = vertices.begin(); it1 != vertices.end(); it1++)
+  for (Vertices::const_iterator it1 = vertices.begin(); it1 != vertices.end();++it1)
   {
-    for (Vertices::const_iterator it2 = vertices.begin(); it2 != vertices.end(); it2++)
+    for (Vertices::const_iterator it2 = vertices.begin(); it2 != vertices.end();++it2)
     {
-      for (Vertices::const_iterator it3 = vertices.begin(); it3 != vertices.end(); it3++)
+      for (Vertices::const_iterator it3 = vertices.begin(); it3 != vertices.end();++it3)
       {
       int i1 = (int)it1->first, i2 = (int)it2->first, i3 = (int)it3->first;
         int val1 = distanceMatrix.at<int> (i2, i3);
@@ -618,10 +618,10 @@ void CirclesGridFinder::rng2gridGraph(Graph &rng, std::vector<cv::Point2f> &vect
   for (size_t i = 0; i < rng.getVerticesCount(); i++)
   {
     Graph::Neighbors neighbors1 = rng.getNeighbors(i);
-    for (Graph::Neighbors::iterator it1 = neighbors1.begin(); it1 != neighbors1.end(); it1++)
+    for (Graph::Neighbors::iterator it1 = neighbors1.begin(); it1 != neighbors1.end(); ++it1)
     {
       Graph::Neighbors neighbors2 = rng.getNeighbors(*it1);
-      for (Graph::Neighbors::iterator it2 = neighbors2.begin(); it2 != neighbors2.end(); it2++)
+      for (Graph::Neighbors::iterator it2 = neighbors2.begin(); it2 != neighbors2.end(); ++it2)
       {
         if (i < *it2)
         {
diff --git a/modules/calib3d/src/compat_ptsetreg.cpp b/modules/calib3d/src/compat_ptsetreg.cpp
index e0f387d..774129e 100644
--- a/modules/calib3d/src/compat_ptsetreg.cpp
+++ b/modules/calib3d/src/compat_ptsetreg.cpp
@@ -241,6 +241,8 @@ bool CvLevMarq::updateAlt( const CvMat*& _param, CvMat*& _JtJ, CvMat*& _JtErr, d
         cvNorm(param, prevParam, CV_RELATIVE_L2) < criteria.epsilon )
     {
         _param = param;
+        _JtJ = JtJ;
+        _JtErr = JtErr;
         state = DONE;
         return false;
     }
diff --git a/modules/calib3d/src/fisheye.cpp b/modules/calib3d/src/fisheye.cpp
index 3d737e7..df68cf1 100644
--- a/modules/calib3d/src/fisheye.cpp
+++ b/modules/calib3d/src/fisheye.cpp
@@ -62,12 +62,16 @@ namespace cv { namespace
 void cv::fisheye::projectPoints(InputArray objectPoints, OutputArray imagePoints, const Affine3d& affine,
     InputArray K, InputArray D, double alpha, OutputArray jacobian)
 {
+    CV_INSTRUMENT_REGION()
+
     projectPoints(objectPoints, imagePoints, affine.rvec(), affine.translation(), K, D, alpha, jacobian);
 }
 
 void cv::fisheye::projectPoints(InputArray objectPoints, OutputArray imagePoints, InputArray _rvec,
         InputArray _tvec, InputArray _K, InputArray _D, double alpha, OutputArray jacobian)
 {
+    CV_INSTRUMENT_REGION()
+
     // will support only 3-channel data now for points
     CV_Assert(objectPoints.type() == CV_32FC3 || objectPoints.type() == CV_64FC3);
     imagePoints.create(objectPoints.size(), CV_MAKETYPE(objectPoints.depth(), 2));
@@ -249,6 +253,8 @@ void cv::fisheye::projectPoints(InputArray objectPoints, OutputArray imagePoints
 
 void cv::fisheye::distortPoints(InputArray undistorted, OutputArray distorted, InputArray K, InputArray D, double alpha)
 {
+    CV_INSTRUMENT_REGION()
+
     // will support only 2-channel data now for points
     CV_Assert(undistorted.type() == CV_32FC2 || undistorted.type() == CV_64FC2);
     distorted.create(undistorted.size(), undistorted.type());
@@ -311,6 +317,8 @@ void cv::fisheye::distortPoints(InputArray undistorted, OutputArray distorted, I
 
 void cv::fisheye::undistortPoints( InputArray distorted, OutputArray undistorted, InputArray K, InputArray D, InputArray R, InputArray P)
 {
+    CV_INSTRUMENT_REGION()
+
     // will support only 2-channel data now for points
     CV_Assert(distorted.type() == CV_32FC2 || distorted.type() == CV_64FC2);
     undistorted.create(distorted.size(), distorted.type());
@@ -369,6 +377,12 @@ void cv::fisheye::undistortPoints( InputArray distorted, OutputArray undistorted
         double scale = 1.0;
 
         double theta_d = sqrt(pw[0]*pw[0] + pw[1]*pw[1]);
+
+        // the current camera model is only valid up to 180° FOV
+        // for larger FOV the loop below does not converge
+        // clip values so we still get plausible results for super fisheye images > 180°
+        theta_d = min(max(-CV_PI/2., theta_d), CV_PI/2.);
+
         if (theta_d > 1e-8)
         {
             // compensate distortion iteratively
@@ -401,12 +415,14 @@ void cv::fisheye::undistortPoints( InputArray distorted, OutputArray undistorted
 void cv::fisheye::initUndistortRectifyMap( InputArray K, InputArray D, InputArray R, InputArray P,
     const cv::Size& size, int m1type, OutputArray map1, OutputArray map2 )
 {
+    CV_INSTRUMENT_REGION()
+
     CV_Assert( m1type == CV_16SC2 || m1type == CV_32F || m1type <=0 );
     map1.create( size, m1type <= 0 ? CV_16SC2 : m1type );
     map2.create( size, map1.type() == CV_16SC2 ? CV_16UC1 : CV_32F );
 
     CV_Assert((K.depth() == CV_32F || K.depth() == CV_64F) && (D.depth() == CV_32F || D.depth() == CV_64F));
-    CV_Assert((P.depth() == CV_32F || P.depth() == CV_64F) && (R.depth() == CV_32F || R.depth() == CV_64F));
+    CV_Assert((P.empty() || P.depth() == CV_32F || P.depth() == CV_64F) && (R.empty() || R.depth() == CV_32F || R.depth() == CV_64F));
     CV_Assert(K.size() == Size(3, 3) && (D.empty() || D.total() == 4));
     CV_Assert(R.empty() || R.size() == Size(3, 3) || R.total() * R.channels() == 3);
     CV_Assert(P.empty() || P.size() == Size(3, 3) || P.size() == Size(4, 3));
@@ -497,6 +513,8 @@ void cv::fisheye::initUndistortRectifyMap( InputArray K, InputArray D, InputArra
 void cv::fisheye::undistortImage(InputArray distorted, OutputArray undistorted,
         InputArray K, InputArray D, InputArray Knew, const Size& new_size)
 {
+    CV_INSTRUMENT_REGION()
+
     Size size = new_size.area() != 0 ? new_size : distorted.size();
 
     cv::Mat map1, map2;
@@ -511,18 +529,24 @@ void cv::fisheye::undistortImage(InputArray distorted, OutputArray undistorted,
 void cv::fisheye::estimateNewCameraMatrixForUndistortRectify(InputArray K, InputArray D, const Size &image_size, InputArray R,
     OutputArray P, double balance, const Size& new_size, double fov_scale)
 {
+    CV_INSTRUMENT_REGION()
+
     CV_Assert( K.size() == Size(3, 3)       && (K.depth() == CV_32F || K.depth() == CV_64F));
     CV_Assert(D.empty() || ((D.total() == 4) && (D.depth() == CV_32F || D.depth() == CV_64F)));
 
     int w = image_size.width, h = image_size.height;
     balance = std::min(std::max(balance, 0.0), 1.0);
 
-    cv::Mat points(1, 4, CV_64FC2);
+    cv::Mat points(1, 8, CV_64FC2);
     Vec2d* pptr = points.ptr<Vec2d>();
-    pptr[0] = Vec2d(w/2, 0);
-    pptr[1] = Vec2d(w, h/2);
-    pptr[2] = Vec2d(w/2, h);
-    pptr[3] = Vec2d(0, h/2);
+    pptr[0] = Vec2d(0, 0);
+    pptr[1] = Vec2d(w/2, 0);
+    pptr[2] = Vec2d(w, 0);
+    pptr[3] = Vec2d(w, h/2);
+    pptr[4] = Vec2d(w, h);
+    pptr[5] = Vec2d(w/2, h);
+    pptr[6] = Vec2d(0, h);
+    pptr[7] = Vec2d(0, h/2);
 
 #if 0
     const int N = 10;
@@ -532,7 +556,6 @@ void cv::fisheye::estimateNewCameraMatrixForUndistortRectify(InputArray K, Input
     {
         pptr[k++] = Vec2d(w/2,   0) - Vec2d(w/8,   0) + Vec2d(w/4/N*i,   0);
         pptr[k++] = Vec2d(w/2, h-1) - Vec2d(w/8, h-1) + Vec2d(w/4/N*i, h-1);
-
         pptr[k++] = Vec2d(0,   h/2) - Vec2d(0,   h/8) + Vec2d(0,   h/4/N*i);
         pptr[k++] = Vec2d(w-1, h/2) - Vec2d(w-1, h/8) + Vec2d(w-1, h/4/N*i);
     }
@@ -553,10 +576,14 @@ void cv::fisheye::estimateNewCameraMatrixForUndistortRectify(InputArray K, Input
     double minx = DBL_MAX, miny = DBL_MAX, maxx = -DBL_MAX, maxy = -DBL_MAX;
     for(size_t i = 0; i < points.total(); ++i)
     {
-        miny = std::min(miny, pptr[i][1]);
-        maxy = std::max(maxy, pptr[i][1]);
-        minx = std::min(minx, pptr[i][0]);
-        maxx = std::max(maxx, pptr[i][0]);
+        if(i!=1 && i!=5){
+            minx = std::min(minx, std::abs(pptr[i][0]-cn[0]));
+        }
+        if(i!=3 && i!=7){
+            miny = std::min(miny, std::abs(pptr[i][1]-cn[1]));
+        }
+        maxy = std::max(maxy, std::abs(pptr[i][1]-cn[1]));
+        maxx = std::max(maxx, std::abs(pptr[i][0]-cn[0]));
     }
 
 #if 0
@@ -570,13 +597,13 @@ void cv::fisheye::estimateNewCameraMatrixForUndistortRectify(InputArray K, Input
     }
 #endif
 
-    double f1 = w * 0.5/(cn[0] - minx);
-    double f2 = w * 0.5/(maxx - cn[0]);
-    double f3 = h * 0.5 * aspect_ratio/(cn[1] - miny);
-    double f4 = h * 0.5 * aspect_ratio/(maxy - cn[1]);
+    double f1 = w * 0.5/(minx);
+    double f2 = w * 0.5/(maxx);
+    double f3 = h * 0.5 * aspect_ratio/(miny);
+    double f4 = h * 0.5 * aspect_ratio/(maxy);
 
-    double fmin = std::min(f1, std::min(f2, std::min(f3, f4)));
-    double fmax = std::max(f1, std::max(f2, std::max(f3, f4)));
+    double fmax = std::max(f1, f3);
+    double fmin = std::min(f2, f4);
 
     double f = balance * fmin + (1.0 - balance) * fmax;
     f *= fov_scale > 0 ? 1.0/fov_scale : 1.0;
@@ -609,6 +636,8 @@ void cv::fisheye::stereoRectify( InputArray K1, InputArray D1, InputArray K2, In
         InputArray _R, InputArray _tvec, OutputArray R1, OutputArray R2, OutputArray P1, OutputArray P2,
         OutputArray Q, int flags, const Size& newImageSize, double balance, double fov_scale)
 {
+    CV_INSTRUMENT_REGION()
+
     CV_Assert((_R.size() == Size(3, 3) || _R.total() * _R.channels() == 3) && (_R.depth() == CV_32F || _R.depth() == CV_64F));
     CV_Assert(_tvec.total() * _tvec.channels() == 3 && (_tvec.depth() == CV_32F || _tvec.depth() == CV_64F));
 
@@ -691,6 +720,8 @@ double cv::fisheye::calibrate(InputArrayOfArrays objectPoints, InputArrayOfArray
                                     InputOutputArray K, InputOutputArray D, OutputArrayOfArrays rvecs, OutputArrayOfArrays tvecs,
                                     int flags , cv::TermCriteria criteria)
 {
+    CV_INSTRUMENT_REGION()
+
     CV_Assert(!objectPoints.empty() && !imagePoints.empty() && objectPoints.total() == imagePoints.total());
     CV_Assert(objectPoints.type() == CV_32FC3 || objectPoints.type() == CV_64FC3);
     CV_Assert(imagePoints.type() == CV_32FC2 || imagePoints.type() == CV_64FC2);
@@ -709,8 +740,8 @@ double cv::fisheye::calibrate(InputArrayOfArrays objectPoints, InputArrayOfArray
 
     finalParam.isEstimate[0] = 1;
     finalParam.isEstimate[1] = 1;
-    finalParam.isEstimate[2] = 1;
-    finalParam.isEstimate[3] = 1;
+    finalParam.isEstimate[2] = flags & CALIB_FIX_PRINCIPAL_POINT ? 0 : 1;
+    finalParam.isEstimate[3] = flags & CALIB_FIX_PRINCIPAL_POINT ? 0 : 1;
     finalParam.isEstimate[4] = flags & CALIB_FIX_SKEW ? 0 : 1;
     finalParam.isEstimate[5] = flags & CALIB_FIX_K1 ? 0 : 1;
     finalParam.isEstimate[6] = flags & CALIB_FIX_K2 ? 0 : 1;
@@ -794,13 +825,22 @@ double cv::fisheye::calibrate(InputArrayOfArrays objectPoints, InputArrayOfArray
 
     if (K.needed()) cv::Mat(_K).convertTo(K, K.empty() ? CV_64FC1 : K.type());
     if (D.needed()) cv::Mat(finalParam.k).convertTo(D, D.empty() ? CV_64FC1 : D.type());
-    if (rvecs.kind()==_InputArray::STD_VECTOR_MAT)
+    if (rvecs.isMatVector())
     {
-        int i;
-        for( i = 0; i < (int)objectPoints.total(); i++ )
+        int N = (int)objectPoints.total();
+
+        if(rvecs.empty())
+            rvecs.create(N, 1, CV_64FC3);
+
+        if(tvecs.empty())
+            tvecs.create(N, 1, CV_64FC3);
+
+        for(int i = 0; i < N; i++ )
         {
-            rvecs.getMat(i)=omc[i];
-            tvecs.getMat(i)=Tc[i];
+            rvecs.create(3, 1, CV_64F, i, true);
+            tvecs.create(3, 1, CV_64F, i, true);
+            memcpy(rvecs.getMat(i).ptr(), omc[i].val, sizeof(Vec3d));
+            memcpy(tvecs.getMat(i).ptr(), Tc[i].val, sizeof(Vec3d));
         }
     }
     else
@@ -819,6 +859,8 @@ double cv::fisheye::stereoCalibrate(InputArrayOfArrays objectPoints, InputArrayO
                                     InputOutputArray K1, InputOutputArray D1, InputOutputArray K2, InputOutputArray D2, Size imageSize,
                                     OutputArray R, OutputArray T, int flags, TermCriteria criteria)
 {
+    CV_INSTRUMENT_REGION()
+
     CV_Assert(!objectPoints.empty() && !imagePoints1.empty() && !imagePoints2.empty());
     CV_Assert(objectPoints.total() == imagePoints1.total() || imagePoints1.total() == imagePoints2.total());
     CV_Assert(objectPoints.type() == CV_32FC3 || objectPoints.type() == CV_64FC3);
@@ -1004,8 +1046,10 @@ double cv::fisheye::stereoCalibrate(InputArrayOfArrays objectPoints, InputArrayO
         int b = cv::countNonZero(intrinsicRight.isEstimate);
         cv::Mat deltas;
         solve(J.t() * J, J.t()*e, deltas);
-        intrinsicLeft = intrinsicLeft + deltas.rowRange(0, a);
-        intrinsicRight = intrinsicRight + deltas.rowRange(a, a + b);
+        if (a > 0)
+            intrinsicLeft = intrinsicLeft + deltas.rowRange(0, a);
+        if (b > 0)
+            intrinsicRight = intrinsicRight + deltas.rowRange(a, a + b);
         omcur = omcur + cv::Vec3d(deltas.rowRange(a + b, a + b + 3));
         Tcur = Tcur + cv::Vec3d(deltas.rowRange(a + b + 3, a + b + 6));
         for (int image_idx = 0; image_idx < n_images; ++image_idx)
@@ -1141,6 +1185,8 @@ void cv::internal::projectPoints(cv::InputArray objectPoints, cv::OutputArray im
                    cv::InputArray _rvec,cv::InputArray _tvec,
                    const IntrinsicParams& param, cv::OutputArray jacobian)
 {
+    CV_INSTRUMENT_REGION()
+
     CV_Assert(!objectPoints.empty() && objectPoints.type() == CV_64FC3);
     Matx33d K(param.f[0], param.f[0] * param.alpha, param.c[0],
                        0,               param.f[1], param.c[1],
@@ -1193,6 +1239,8 @@ void cv::internal::ComputeExtrinsicRefine(const Mat& imagePoints, const Mat& obj
 
 cv::Mat cv::internal::ComputeHomography(Mat m, Mat M)
 {
+    CV_INSTRUMENT_REGION()
+
     int Np = m.cols;
 
     if (m.rows < 3)
@@ -1292,15 +1340,17 @@ cv::Mat cv::internal::ComputeHomography(Mat m, Mat M)
 
 cv::Mat cv::internal::NormalizePixels(const Mat& imagePoints, const IntrinsicParams& param)
 {
+    CV_INSTRUMENT_REGION()
+
     CV_Assert(!imagePoints.empty() && imagePoints.type() == CV_64FC2);
 
     Mat distorted((int)imagePoints.total(), 1, CV_64FC2), undistorted;
-    const Vec2d* ptr   = imagePoints.ptr<Vec2d>(0);
-    Vec2d* ptr_d = distorted.ptr<Vec2d>(0);
+    const Vec2d* ptr   = imagePoints.ptr<Vec2d>();
+    Vec2d* ptr_d = distorted.ptr<Vec2d>();
     for (size_t i = 0; i < imagePoints.total(); ++i)
     {
         ptr_d[i] = (ptr[i] - param.c).mul(Vec2d(1.0 / param.f[0], 1.0 / param.f[1]));
-        ptr_d[i][0] = ptr_d[i][0] - param.alpha * ptr_d[i][1];
+        ptr_d[i][0] -= param.alpha * ptr_d[i][1];
     }
     cv::fisheye::undistortPoints(distorted, undistorted, Matx33d::eye(), param.k);
     return undistorted;
@@ -1308,12 +1358,11 @@ cv::Mat cv::internal::NormalizePixels(const Mat& imagePoints, const IntrinsicPar
 
 void cv::internal::InitExtrinsics(const Mat& _imagePoints, const Mat& _objectPoints, const IntrinsicParams& param, Mat& omckk, Mat& Tckk)
 {
-
     CV_Assert(!_objectPoints.empty() && _objectPoints.type() == CV_64FC3);
     CV_Assert(!_imagePoints.empty() && _imagePoints.type() == CV_64FC2);
 
-    Mat imagePointsNormalized = NormalizePixels(_imagePoints.t(), param).reshape(1).t();
-    Mat objectPoints = Mat(_objectPoints.t()).reshape(1).t();
+    Mat imagePointsNormalized = NormalizePixels(_imagePoints, param).reshape(1).t();
+    Mat objectPoints = _objectPoints.reshape(1).t();
     Mat objectPointsMean, covObjectPoints;
     Mat Rckk;
     int Np = imagePointsNormalized.cols;
@@ -1366,9 +1415,12 @@ void cv::internal::CalibrateExtrinsics(InputArrayOfArrays objectPoints, InputArr
         objectPoints.getMat(image_idx).convertTo(object,  CV_64FC3);
         imagePoints.getMat (image_idx).convertTo(image, CV_64FC2);
 
-        InitExtrinsics(image, object, param, omckk, Tckk);
+        bool imT = image.rows < image.cols;
+        bool obT = object.rows < object.cols;
 
-        ComputeExtrinsicRefine(image, object, omckk, Tckk, JJ_kk, maxIter, param, thresh_cond);
+        InitExtrinsics(imT ? image.t() : image, obT ? object.t() : object, param, omckk, Tckk);
+
+        ComputeExtrinsicRefine(!imT ? image.t() : image, !obT ? object.t() : object, omckk, Tckk, JJ_kk, maxIter, param, thresh_cond);
         if (check_cond)
         {
             SVD svd(JJ_kk, SVD::NO_UV);
@@ -1379,7 +1431,6 @@ void cv::internal::CalibrateExtrinsics(InputArrayOfArrays objectPoints, InputArr
     }
 }
 
-
 void cv::internal::ComputeJacobians(InputArrayOfArrays objectPoints, InputArrayOfArrays imagePoints,
                       const IntrinsicParams& param,  InputArray omc, InputArray Tc,
                       const int& check_cond, const double& thresh_cond, Mat& JJ2, Mat& ex3)
@@ -1401,12 +1452,13 @@ void cv::internal::ComputeJacobians(InputArrayOfArrays objectPoints, InputArrayO
         objectPoints.getMat(image_idx).convertTo(object, CV_64FC3);
         imagePoints.getMat (image_idx).convertTo(image, CV_64FC2);
 
+        bool imT = image.rows < image.cols;
         Mat om(omc.getMat().col(image_idx)), T(Tc.getMat().col(image_idx));
 
         std::vector<Point2d> x;
         Mat jacobians;
         projectPoints(object, x, om, T, param, jacobians);
-        Mat exkk = image.t() - Mat(x);
+        Mat exkk = (imT ? image.t() : image) - Mat(x);
 
         Mat A(jacobians.rows, 9, CV_64FC1);
         jacobians.colRange(0, 4).copyTo(A.colRange(0, 4));
@@ -1452,20 +1504,28 @@ void cv::internal::EstimateUncertainties(InputArrayOfArrays objectPoints, InputA
     CV_Assert(!omc.empty() && omc.type() == CV_64FC3);
     CV_Assert(!Tc.empty() && Tc.type() == CV_64FC3);
 
-    Mat ex((int)(objectPoints.getMat(0).total() * objectPoints.total()), 1, CV_64FC2);
-
+    int total_ex = 0;
+    for (int image_idx = 0; image_idx < (int)objectPoints.total(); ++image_idx)
+    {
+        total_ex += (int)objectPoints.getMat(image_idx).total();
+    }
+    Mat ex(total_ex, 1, CV_64FC2);
+    int insert_idx = 0;
     for (int image_idx = 0; image_idx < (int)objectPoints.total(); ++image_idx)
     {
         Mat image, object;
         objectPoints.getMat(image_idx).convertTo(object, CV_64FC3);
         imagePoints.getMat (image_idx).convertTo(image, CV_64FC2);
 
+        bool imT = image.rows < image.cols;
+
         Mat om(omc.getMat().col(image_idx)), T(Tc.getMat().col(image_idx));
 
         std::vector<Point2d> x;
         projectPoints(object, x, om, T, params, noArray());
-        Mat ex_ = image.t() - Mat(x);
-        ex_.copyTo(ex.rowRange(ex_.rows * image_idx,  ex_.rows * (image_idx + 1)));
+        Mat ex_ = (imT ? image.t() : image) - Mat(x);
+        ex_.copyTo(ex.rowRange(insert_idx, insert_idx + ex_.rows));
+        insert_idx += ex_.rows;
     }
 
     meanStdDev(ex, noArray(), std_err);
diff --git a/modules/calib3d/src/five-point.cpp b/modules/calib3d/src/five-point.cpp
index 92e652b..1d39e20 100644
--- a/modules/calib3d/src/five-point.cpp
+++ b/modules/calib3d/src/five-point.cpp
@@ -405,6 +405,8 @@ protected:
 cv::Mat cv::findEssentialMat( InputArray _points1, InputArray _points2, InputArray _cameraMatrix,
                               int method, double prob, double threshold, OutputArray _mask)
 {
+    CV_INSTRUMENT_REGION()
+
     Mat points1, points2, cameraMatrix;
     _points1.getMat().convertTo(points1, CV_64F);
     _points2.getMat().convertTo(points2, CV_64F);
@@ -450,6 +452,8 @@ cv::Mat cv::findEssentialMat( InputArray _points1, InputArray _points2, InputArr
 cv::Mat cv::findEssentialMat( InputArray _points1, InputArray _points2, double focal, Point2d pp,
                               int method, double prob, double threshold, OutputArray _mask)
 {
+    CV_INSTRUMENT_REGION()
+
     Mat cameraMatrix = (Mat_<double>(3,3) << focal, 0, pp.x, 0, focal, pp.y, 0, 0, 1);
     return cv::findEssentialMat(_points1, _points2, cameraMatrix, method, prob, threshold, _mask);
 }
@@ -457,6 +461,8 @@ cv::Mat cv::findEssentialMat( InputArray _points1, InputArray _points2, double f
 int cv::recoverPose( InputArray E, InputArray _points1, InputArray _points2, InputArray _cameraMatrix,
                      OutputArray _R, OutputArray _t, InputOutputArray _mask)
 {
+    CV_INSTRUMENT_REGION()
+
     Mat points1, points2, cameraMatrix;
     _points1.getMat().convertTo(points1, CV_64F);
     _points2.getMat().convertTo(points2, CV_64F);
@@ -616,6 +622,8 @@ int cv::recoverPose( InputArray E, InputArray _points1, InputArray _points2, Out
 
 void cv::decomposeEssentialMat( InputArray _E, OutputArray _R1, OutputArray _R2, OutputArray _t )
 {
+    CV_INSTRUMENT_REGION()
+
     Mat E = _E.getMat().reshape(1, 3);
     CV_Assert(E.cols == 3 && E.rows == 3);
 
diff --git a/modules/calib3d/src/fundam.cpp b/modules/calib3d/src/fundam.cpp
index 57e3699..63bdff2 100644
--- a/modules/calib3d/src/fundam.cpp
+++ b/modules/calib3d/src/fundam.cpp
@@ -47,29 +47,6 @@
 namespace cv
 {
 
-static bool haveCollinearPoints( const Mat& m, int count )
-{
-    int j, k, i = count-1;
-    const Point2f* ptr = m.ptr<Point2f>();
-
-    // check that the i-th selected point does not belong
-    // to a line connecting some previously selected points
-    for( j = 0; j < i; j++ )
-    {
-        double dx1 = ptr[j].x - ptr[i].x;
-        double dy1 = ptr[j].y - ptr[i].y;
-        for( k = 0; k < j; k++ )
-        {
-            double dx2 = ptr[k].x - ptr[i].x;
-            double dy2 = ptr[k].y - ptr[i].y;
-            if( fabs(dx2*dy1 - dy2*dx1) <= FLT_EPSILON*(fabs(dx1) + fabs(dy1) + fabs(dx2) + fabs(dy2)))
-                return true;
-        }
-    }
-    return false;
-}
-
-
 class HomographyEstimatorCallback : public PointSetRegistrator::Callback
 {
 public:
@@ -343,6 +320,8 @@ cv::Mat cv::findHomography( InputArray _points1, InputArray _points2,
                             int method, double ransacReprojThreshold, OutputArray _mask,
                             const int maxIters, const double confidence)
 {
+    CV_INSTRUMENT_REGION()
+
     const double defaultRANSACReprojThreshold = 3;
     bool result = false;
 
@@ -411,7 +390,13 @@ cv::Mat cv::findHomography( InputArray _points1, InputArray _points2,
             tempMask.copyTo(_mask);
     }
     else
+    {
         H.release();
+        if(_mask.needed() ) {
+            tempMask = Mat::zeros(npoints >= 0 ? npoints : 0, 1, CV_8U);
+            tempMask.copyTo(_mask);
+        }
+    }
 
     return H;
 }
@@ -708,6 +693,8 @@ cv::Mat cv::findFundamentalMat( InputArray _points1, InputArray _points2,
                                 int method, double param1, double param2,
                                 OutputArray _mask )
 {
+    CV_INSTRUMENT_REGION()
+
     Mat points1 = _points1.getMat(), points2 = _points2.getMat();
     Mat m1, m2, F;
     int npoints = -1;
@@ -777,6 +764,8 @@ cv::Mat cv::findFundamentalMat( InputArray _points1, InputArray _points2,
 void cv::computeCorrespondEpilines( InputArray _points, int whichImage,
                                     InputArray _Fmat, OutputArray _lines )
 {
+    CV_INSTRUMENT_REGION()
+
     double f[9];
     Mat tempF(3, 3, CV_64F, f);
     Mat points = _points.getMat(), F = _Fmat.getMat();
@@ -850,6 +839,8 @@ void cv::computeCorrespondEpilines( InputArray _points, int whichImage,
 
 void cv::convertPointsFromHomogeneous( InputArray _src, OutputArray _dst )
 {
+    CV_INSTRUMENT_REGION()
+
     Mat src = _src.getMat();
     if( !src.isContinuous() )
         src = src.clone();
@@ -949,6 +940,8 @@ void cv::convertPointsFromHomogeneous( InputArray _src, OutputArray _dst )
 
 void cv::convertPointsToHomogeneous( InputArray _src, OutputArray _dst )
 {
+    CV_INSTRUMENT_REGION()
+
     Mat src = _src.getMat();
     if( !src.isContinuous() )
         src = src.clone();
@@ -961,7 +954,7 @@ void cv::convertPointsToHomogeneous( InputArray _src, OutputArray _dst )
     }
     CV_Assert( npoints >= 0 && (depth == CV_32S || depth == CV_32F || depth == CV_64F));
 
-    int dtype = CV_MAKETYPE(depth <= CV_32F ? CV_32F : CV_64F, cn+1);
+    int dtype = CV_MAKETYPE(depth, cn+1);
     _dst.create(npoints, 1, dtype);
     Mat dst = _dst.getMat();
     if( !dst.isContinuous() )
@@ -1030,6 +1023,8 @@ void cv::convertPointsToHomogeneous( InputArray _src, OutputArray _dst )
 
 void cv::convertPointsHomogeneous( InputArray _src, OutputArray _dst )
 {
+    CV_INSTRUMENT_REGION()
+
     int stype = _src.type(), dtype = _dst.type();
     CV_Assert( _dst.fixedType() );
 
@@ -1039,8 +1034,11 @@ void cv::convertPointsHomogeneous( InputArray _src, OutputArray _dst )
         convertPointsToHomogeneous(_src, _dst);
 }
 
-double cv::sampsonDistance(InputArray _pt1, InputArray _pt2, InputArray _F) {
-    CV_Assert(_pt1.type() == CV_64F && _pt1.type() == CV_64F && _F.type() == CV_64F);
+double cv::sampsonDistance(InputArray _pt1, InputArray _pt2, InputArray _F)
+{
+    CV_INSTRUMENT_REGION()
+
+    CV_Assert(_pt1.type() == CV_64F && _pt2.type() == CV_64F && _F.type() == CV_64F);
     CV_DbgAssert(_pt1.rows() == 3 && _F.size() == Size(3, 3) && _pt1.rows() == _pt2.rows());
 
     Mat pt1(_pt1.getMat());
diff --git a/modules/calib3d/src/homography_decomp.cpp b/modules/calib3d/src/homography_decomp.cpp
index 1a64261..9007d0a 100644
--- a/modules/calib3d/src/homography_decomp.cpp
+++ b/modules/calib3d/src/homography_decomp.cpp
@@ -447,7 +447,7 @@ int decomposeHomographyMat(InputArray _H,
     Mat K = _K.getMat().reshape(1, 3);
     CV_Assert(K.cols == 3 && K.rows == 3);
 
-    auto_ptr<HomographyDecomp> hdecomp(new HomographyDecompInria);
+    cv::Ptr<HomographyDecomp> hdecomp(new HomographyDecompInria);
 
     vector<CameraMotion> motions;
     hdecomp->decomposeHomography(H, K, motions);
diff --git a/modules/calib3d/src/p3p.cpp b/modules/calib3d/src/p3p.cpp
index 882868d..f91925b 100644
--- a/modules/calib3d/src/p3p.cpp
+++ b/modules/calib3d/src/p3p.cpp
@@ -33,6 +33,8 @@ p3p::p3p(double _fx, double _fy, double _cx, double _cy)
 
 bool p3p::solve(cv::Mat& R, cv::Mat& tvec, const cv::Mat& opoints, const cv::Mat& ipoints)
 {
+    CV_INSTRUMENT_REGION()
+
     double rotation_matrix[3][3], translation[3];
     std::vector<double> points;
     if (opoints.depth() == ipoints.depth())
diff --git a/modules/calib3d/src/precomp.hpp b/modules/calib3d/src/precomp.hpp
index 83a513d..3208680 100644
--- a/modules/calib3d/src/precomp.hpp
+++ b/modules/calib3d/src/precomp.hpp
@@ -115,6 +115,32 @@ template<typename T> inline int compressElems( T* ptr, const uchar* mask, int ms
     return j;
 }
 
+static inline bool haveCollinearPoints( const Mat& m, int count )
+{
+    int j, k, i = count-1;
+    const Point2f* ptr = m.ptr<Point2f>();
+
+    // check that the i-th selected point does not belong
+    // to a line connecting some previously selected points
+    // also checks that points are not too close to each other
+    for( j = 0; j < i; j++ )
+    {
+        double dx1 = ptr[j].x - ptr[i].x;
+        double dy1 = ptr[j].y - ptr[i].y;
+        for( k = 0; k < j; k++ )
+        {
+            double dx2 = ptr[k].x - ptr[i].x;
+            double dy2 = ptr[k].y - ptr[i].y;
+            if( fabs(dx2*dy1 - dy2*dx1) <= FLT_EPSILON*(fabs(dx1) + fabs(dy1) + fabs(dx2) + fabs(dy2)))
+                return true;
+        }
+    }
+    return false;
 }
 
+} // namespace cv
+
+int checkChessboard(const cv::Mat & img, const cv::Size & size);
+int checkChessboardBinary(const cv::Mat & img, const cv::Size & size);
+
 #endif
diff --git a/modules/calib3d/src/ptsetreg.cpp b/modules/calib3d/src/ptsetreg.cpp
index 75a73a5..cbf8175 100644
--- a/modules/calib3d/src/ptsetreg.cpp
+++ b/modules/calib3d/src/ptsetreg.cpp
@@ -109,9 +109,9 @@ public:
         cv::AutoBuffer<int> _idx(modelPoints);
         int* idx = _idx;
         int i = 0, j, k, iters = 0;
-        int esz1 = (int)m1.elemSize(), esz2 = (int)m2.elemSize();
         int d1 = m1.channels() > 1 ? m1.channels() : m1.cols;
         int d2 = m2.channels() > 1 ? m2.channels() : m2.cols;
+        int esz1 = (int)m1.elemSize1()*d1, esz2 = (int)m2.elemSize1()*d2;
         int count = m1.checkVector(d1), count2 = m2.checkVector(d2);
         const int *m1ptr = m1.ptr<int>(), *m2ptr = m2.ptr<int>();
 
@@ -206,7 +206,7 @@ public:
 
         for( iter = 0; iter < niters; iter++ )
         {
-            int i, goodCount, nmodels;
+            int i, nmodels;
             if( count > modelPoints )
             {
                 bool found = getSubset( m1, m2, ms1, ms2, rng, 10000 );
@@ -227,7 +227,7 @@ public:
             for( i = 0; i < nmodels; i++ )
             {
                 Mat model_i = model.rowRange( i*modelSize.height, (i+1)*modelSize.height );
-                goodCount = findInliers( m1, m2, model_i, err, mask, threshold );
+                int goodCount = findInliers( m1, m2, model_i, err, mask, threshold );
 
                 if( goodCount > MAX(maxGoodCount, modelPoints-1) )
                 {
@@ -284,7 +284,7 @@ public:
         int d1 = m1.channels() > 1 ? m1.channels() : m1.cols;
         int d2 = m2.channels() > 1 ? m2.channels() : m2.cols;
         int count = m1.checkVector(d1), count2 = m2.checkVector(d2);
-        double minMedian = DBL_MAX, sigma;
+        double minMedian = DBL_MAX;
 
         RNG rng((uint64)-1);
 
@@ -344,10 +344,8 @@ public:
                 else
                     errf = err;
                 CV_Assert( errf.isContinuous() && errf.type() == CV_32F && (int)errf.total() == count );
-                std::sort(errf.ptr<int>(), errf.ptr<int>() + count);
-
-                double median = count % 2 != 0 ?
-                errf.at<float>(count/2) : (errf.at<float>(count/2-1) + errf.at<float>(count/2))*0.5;
+                std::nth_element(errf.ptr<int>(), errf.ptr<int>() + count/2, errf.ptr<int>() + count);
+                double median = errf.at<float>(count/2);
 
                 if( median < minMedian )
                 {
@@ -359,7 +357,7 @@ public:
 
         if( minMedian < DBL_MAX )
         {
-            sigma = 2.5*1.4826*(1 + 5./(count - modelPoints))*std::sqrt(minMedian);
+            double sigma = 2.5*1.4826*(1 + 5./(count - modelPoints))*std::sqrt(minMedian);
             sigma = MAX( sigma, 0.001 );
 
             count = findInliers( m1, m2, bestModel, err, mask, sigma );
@@ -462,7 +460,7 @@ public:
             double b = F[4]*f.x + F[5]*f.y + F[ 6]*f.z + F[ 7] - t.y;
             double c = F[8]*f.x + F[9]*f.y + F[10]*f.z + F[11] - t.z;
 
-            errptr[i] = (float)std::sqrt(a*a + b*b + c*c);
+            errptr[i] = (float)(a*a + b*b + c*c);
         }
     }
 
@@ -501,12 +499,277 @@ public:
     }
 };
 
-}
+class Affine2DEstimatorCallback : public PointSetRegistrator::Callback
+{
+public:
+    int runKernel( InputArray _m1, InputArray _m2, OutputArray _model ) const
+    {
+        Mat m1 = _m1.getMat(), m2 = _m2.getMat();
+        const Point2f* from = m1.ptr<Point2f>();
+        const Point2f* to   = m2.ptr<Point2f>();
+        _model.create(2, 3, CV_64F);
+        Mat M_mat = _model.getMat();
+        double *M = M_mat.ptr<double>();
+
+        // we need 3 points to estimate affine transform
+        double x1 = from[0].x;
+        double y1 = from[0].y;
+        double x2 = from[1].x;
+        double y2 = from[1].y;
+        double x3 = from[2].x;
+        double y3 = from[2].y;
+
+        double X1 = to[0].x;
+        double Y1 = to[0].y;
+        double X2 = to[1].x;
+        double Y2 = to[1].y;
+        double X3 = to[2].x;
+        double Y3 = to[2].y;
+
+        /*
+        We want to solve AX = B
+
+            | x1 y1  1  0  0  0 |
+            |  0  0  0 x1 y1  1 |
+            | x2 y2  1  0  0  0 |
+        A = |  0  0  0 x2 y2  1 |
+            | x3 y3  1  0  0  0 |
+            |  0  0  0 x3 y3  1 |
+        B = (X1, Y1, X2, Y2, X3, Y3).t()
+        X = (a, b, c, d, e, f).t()
+
+        As the estimate of (a, b, c) only depends on the Xi, and (d, e, f) only
+        depends on the Yi, we do the *trick* to solve each one analytically.
+
+        | X1 |   | x1 y1 1 |   | a |
+        | X2 | = | x2 y2 1 | * | b |
+        | X3 |   | x3 y3 1 |   | c |
+
+        | Y1 |   | x1 y1 1 |   | d |
+        | Y2 | = | x2 y2 1 | * | e |
+        | Y3 |   | x3 y3 1 |   | f |
+        */
+
+        double d = 1. / ( x1*(y2-y3) + x2*(y3-y1) + x3*(y1-y2) );
+
+        M[0] = d * ( X1*(y2-y3) + X2*(y3-y1) + X3*(y1-y2) );
+        M[1] = d * ( X1*(x3-x2) + X2*(x1-x3) + X3*(x2-x1) );
+        M[2] = d * ( X1*(x2*y3 - x3*y2) + X2*(x3*y1 - x1*y3) + X3*(x1*y2 - x2*y1) );
+
+        M[3] = d * ( Y1*(y2-y3) + Y2*(y3-y1) + Y3*(y1-y2) );
+        M[4] = d * ( Y1*(x3-x2) + Y2*(x1-x3) + Y3*(x2-x1) );
+        M[5] = d * ( Y1*(x2*y3 - x3*y2) + Y2*(x3*y1 - x1*y3) + Y3*(x1*y2 - x2*y1) );
+        return 1;
+    }
+
+    void computeError( InputArray _m1, InputArray _m2, InputArray _model, OutputArray _err ) const
+    {
+        Mat m1 = _m1.getMat(), m2 = _m2.getMat(), model = _model.getMat();
+        const Point2f* from = m1.ptr<Point2f>();
+        const Point2f* to   = m2.ptr<Point2f>();
+        const double* F = model.ptr<double>();
+
+        int count = m1.checkVector(2);
+        CV_Assert( count > 0 );
+
+        _err.create(count, 1, CV_32F);
+        Mat err = _err.getMat();
+        float* errptr = err.ptr<float>();
+        // transform matrix to floats
+        float F0 = (float)F[0], F1 = (float)F[1], F2 = (float)F[2];
+        float F3 = (float)F[3], F4 = (float)F[4], F5 = (float)F[5];
+
+        for(int i = 0; i < count; i++ )
+        {
+            const Point2f& f = from[i];
+            const Point2f& t = to[i];
+
+            float a = F0*f.x + F1*f.y + F2 - t.x;
+            float b = F3*f.x + F4*f.y + F5 - t.y;
+
+            errptr[i] = a*a + b*b;
+        }
+    }
+
+    bool checkSubset( InputArray _ms1, InputArray, int count ) const
+    {
+        Mat ms1 = _ms1.getMat();
+        // check colinearity and also check that points are too close
+        // only ms1 affects actual estimation stability
+        return !haveCollinearPoints(ms1, count);
+    }
+};
+
+class AffinePartial2DEstimatorCallback : public Affine2DEstimatorCallback
+{
+public:
+    int runKernel( InputArray _m1, InputArray _m2, OutputArray _model ) const
+    {
+        Mat m1 = _m1.getMat(), m2 = _m2.getMat();
+        const Point2f* from = m1.ptr<Point2f>();
+        const Point2f* to   = m2.ptr<Point2f>();
+        _model.create(2, 3, CV_64F);
+        Mat M_mat = _model.getMat();
+        double *M = M_mat.ptr<double>();
+
+        // we need only 2 points to estimate transform
+        double x1 = from[0].x;
+        double y1 = from[0].y;
+        double x2 = from[1].x;
+        double y2 = from[1].y;
+
+        double X1 = to[0].x;
+        double Y1 = to[0].y;
+        double X2 = to[1].x;
+        double Y2 = to[1].y;
+
+        /*
+        we are solving AS = B
+            | x1 -y1 1 0 |
+            | y1  x1 0 1 |
+        A = | x2 -y2 1 0 |
+            | y2  x2 0 1 |
+        B = (X1, Y1, X2, Y2).t()
+        we solve that analytically
+        */
+        double d = 1./((x1-x2)*(x1-x2) + (y1-y2)*(y1-y2));
+
+        // solution vector
+        double S0 = d * ( (X1-X2)*(x1-x2) + (Y1-Y2)*(y1-y2) );
+        double S1 = d * ( (Y1-Y2)*(x1-x2) - (X1-X2)*(y1-y2) );
+        double S2 = d * ( (Y1-Y2)*(x1*y2 - x2*y1) - (X1*y2 - X2*y1)*(y1-y2) - (X1*x2 - X2*x1)*(x1-x2) );
+        double S3 = d * (-(X1-X2)*(x1*y2 - x2*y1) - (Y1*x2 - Y2*x1)*(x1-x2) - (Y1*y2 - Y2*y1)*(y1-y2) );
+
+        // set model, rotation part is antisymmetric
+        M[0] = M[4] = S0;
+        M[1] = -S1;
+        M[2] = S2;
+        M[3] = S1;
+        M[5] = S3;
+        return 1;
+    }
+};
 
-int cv::estimateAffine3D(InputArray _from, InputArray _to,
-                         OutputArray _out, OutputArray _inliers,
-                         double param1, double param2)
+class Affine2DRefineCallback : public LMSolver::Callback
 {
+public:
+    Affine2DRefineCallback(InputArray _src, InputArray _dst)
+    {
+        src = _src.getMat();
+        dst = _dst.getMat();
+    }
+
+    bool compute(InputArray _param, OutputArray _err, OutputArray _Jac) const
+    {
+        int i, count = src.checkVector(2);
+        Mat param = _param.getMat();
+        _err.create(count*2, 1, CV_64F);
+        Mat err = _err.getMat(), J;
+        if( _Jac.needed())
+        {
+            _Jac.create(count*2, param.rows, CV_64F);
+            J = _Jac.getMat();
+            CV_Assert( J.isContinuous() && J.cols == 6 );
+        }
+
+        const Point2f* M = src.ptr<Point2f>();
+        const Point2f* m = dst.ptr<Point2f>();
+        const double* h = param.ptr<double>();
+        double* errptr = err.ptr<double>();
+        double* Jptr = J.data ? J.ptr<double>() : 0;
+
+        for( i = 0; i < count; i++ )
+        {
+            double Mx = M[i].x, My = M[i].y;
+            double xi = h[0]*Mx + h[1]*My + h[2];
+            double yi = h[3]*Mx + h[4]*My + h[5];
+            errptr[i*2] = xi - m[i].x;
+            errptr[i*2+1] = yi - m[i].y;
+
+            /*
+            Jacobian should be:
+                {x, y, 1, 0, 0, 0}
+                {0, 0, 0, x, y, 1}
+            */
+            if( Jptr )
+            {
+                Jptr[0] = Mx; Jptr[1] = My; Jptr[2] = 1.;
+                Jptr[3] = Jptr[4] = Jptr[5] = 0.;
+                Jptr[6] = Jptr[7] = Jptr[8] = 0.;
+                Jptr[9] = Mx; Jptr[10] = My; Jptr[11] = 1.;
+
+                Jptr += 6*2;
+            }
+        }
+
+        return true;
+    }
+
+    Mat src, dst;
+};
+
+class AffinePartial2DRefineCallback : public LMSolver::Callback
+{
+public:
+    AffinePartial2DRefineCallback(InputArray _src, InputArray _dst)
+    {
+        src = _src.getMat();
+        dst = _dst.getMat();
+    }
+
+    bool compute(InputArray _param, OutputArray _err, OutputArray _Jac) const
+    {
+        int i, count = src.checkVector(2);
+        Mat param = _param.getMat();
+        _err.create(count*2, 1, CV_64F);
+        Mat err = _err.getMat(), J;
+        if( _Jac.needed())
+        {
+            _Jac.create(count*2, param.rows, CV_64F);
+            J = _Jac.getMat();
+            CV_Assert( J.isContinuous() && J.cols == 4 );
+        }
+
+        const Point2f* M = src.ptr<Point2f>();
+        const Point2f* m = dst.ptr<Point2f>();
+        const double* h = param.ptr<double>();
+        double* errptr = err.ptr<double>();
+        double* Jptr = J.data ? J.ptr<double>() : 0;
+
+        for( i = 0; i < count; i++ )
+        {
+            double Mx = M[i].x, My = M[i].y;
+            double xi = h[0]*Mx - h[1]*My + h[2];
+            double yi = h[1]*Mx + h[0]*My + h[3];
+            errptr[i*2] = xi - m[i].x;
+            errptr[i*2+1] = yi - m[i].y;
+
+            /*
+            Jacobian should be:
+                {x, -y, 1, 0}
+                {y,  x, 0, 1}
+            */
+            if( Jptr )
+            {
+                Jptr[0] = Mx; Jptr[1] = -My; Jptr[2] = 1.; Jptr[3] = 0.;
+                Jptr[4] = My; Jptr[5] =  Mx; Jptr[6] = 0.; Jptr[7] = 1.;
+
+                Jptr += 4*2;
+            }
+        }
+
+        return true;
+    }
+
+    Mat src, dst;
+};
+
+int estimateAffine3D(InputArray _from, InputArray _to,
+                     OutputArray _out, OutputArray _inliers,
+                     double param1, double param2)
+{
+    CV_INSTRUMENT_REGION()
+
     Mat from = _from.getMat(), to = _to.getMat();
     int count = from.checkVector(3);
 
@@ -524,3 +787,152 @@ int cv::estimateAffine3D(InputArray _from, InputArray _to,
 
     return createRANSACPointSetRegistrator(makePtr<Affine3DEstimatorCallback>(), 4, param1, param2)->run(dFrom, dTo, _out, _inliers);
 }
+
+Mat estimateAffine2D(InputArray _from, InputArray _to, OutputArray _inliers,
+                     const int method, const double ransacReprojThreshold,
+                     const size_t maxIters, const double confidence,
+                     const size_t refineIters)
+{
+    Mat from = _from.getMat(), to = _to.getMat();
+    int count = from.checkVector(2);
+    bool result = false;
+    Mat H;
+
+    CV_Assert( count >= 0 && to.checkVector(2) == count );
+
+    if (from.type() != CV_32FC2 || to.type() != CV_32FC2)
+    {
+        Mat tmp;
+        from.convertTo(tmp, CV_32FC2);
+        from = tmp;
+        to.convertTo(tmp, CV_32FC2);
+        to = tmp;
+    }
+    // convert to N x 1 vectors
+    from = from.reshape(2, count);
+    to = to.reshape(2, count);
+
+    Mat inliers;
+    if(_inliers.needed())
+    {
+        _inliers.create(count, 1, CV_8U, -1, true);
+        inliers = _inliers.getMat();
+    }
+
+    // run robust method
+    Ptr<PointSetRegistrator::Callback> cb = makePtr<Affine2DEstimatorCallback>();
+    if( method == RANSAC )
+        result = createRANSACPointSetRegistrator(cb, 3, ransacReprojThreshold, confidence, static_cast<int>(maxIters))->run(from, to, H, inliers);
+    else if( method == LMEDS )
+        result = createLMeDSPointSetRegistrator(cb, 3, confidence, static_cast<int>(maxIters))->run(from, to, H, inliers);
+    else
+        CV_Error(Error::StsBadArg, "Unknown or unsupported robust estimation method");
+
+    if(result && count > 3 && refineIters)
+    {
+        // reorder to start with inliers
+        compressElems(from.ptr<Point2f>(), inliers.ptr<uchar>(), 1, count);
+        int inliers_count = compressElems(to.ptr<Point2f>(), inliers.ptr<uchar>(), 1, count);
+        if(inliers_count > 0)
+        {
+            Mat src = from.rowRange(0, inliers_count);
+            Mat dst = to.rowRange(0, inliers_count);
+            Mat Hvec = H.reshape(1, 6);
+            createLMSolver(makePtr<Affine2DRefineCallback>(src, dst), static_cast<int>(refineIters))->run(Hvec);
+        }
+    }
+
+    if (!result)
+    {
+        H.release();
+        if(_inliers.needed())
+        {
+            inliers = Mat::zeros(count, 1, CV_8U);
+            inliers.copyTo(_inliers);
+        }
+    }
+
+    return H;
+}
+
+Mat estimateAffinePartial2D(InputArray _from, InputArray _to, OutputArray _inliers,
+                            const int method, const double ransacReprojThreshold,
+                            const size_t maxIters, const double confidence,
+                            const size_t refineIters)
+{
+    Mat from = _from.getMat(), to = _to.getMat();
+    const int count = from.checkVector(2);
+    bool result = false;
+    Mat H;
+
+    CV_Assert( count >= 0 && to.checkVector(2) == count );
+
+    if (from.type() != CV_32FC2 || to.type() != CV_32FC2)
+    {
+        Mat tmp;
+        from.convertTo(tmp, CV_32FC2);
+        from = tmp;
+        to.convertTo(tmp, CV_32FC2);
+        to = tmp;
+    }
+    // convert to N x 1 vectors
+    from = from.reshape(2, count);
+    to = to.reshape(2, count);
+
+    Mat inliers;
+    if(_inliers.needed())
+    {
+        _inliers.create(count, 1, CV_8U, -1, true);
+        inliers = _inliers.getMat();
+    }
+
+    // run robust estimation
+    Ptr<PointSetRegistrator::Callback> cb = makePtr<AffinePartial2DEstimatorCallback>();
+    if( method == RANSAC )
+        result = createRANSACPointSetRegistrator(cb, 2, ransacReprojThreshold, confidence, static_cast<int>(maxIters))->run(from, to, H, inliers);
+    else if( method == LMEDS )
+        result = createLMeDSPointSetRegistrator(cb, 2, confidence, static_cast<int>(maxIters))->run(from, to, H, inliers);
+    else
+        CV_Error(Error::StsBadArg, "Unknown or unsupported robust estimation method");
+
+    if(result && count > 2 && refineIters)
+    {
+        // reorder to start with inliers
+        compressElems(from.ptr<Point2f>(), inliers.ptr<uchar>(), 1, count);
+        int inliers_count = compressElems(to.ptr<Point2f>(), inliers.ptr<uchar>(), 1, count);
+        if(inliers_count > 0)
+        {
+            Mat src = from.rowRange(0, inliers_count);
+            Mat dst = to.rowRange(0, inliers_count);
+            // H is
+            //     a -b tx
+            //     b  a ty
+            // Hvec model for LevMarq is
+            //     (a, b, tx, ty)
+            double *Hptr = H.ptr<double>();
+            double Hvec_buf[4] = {Hptr[0], Hptr[3], Hptr[2], Hptr[5]};
+            Mat Hvec (4, 1, CV_64F, Hvec_buf);
+            createLMSolver(makePtr<AffinePartial2DRefineCallback>(src, dst), static_cast<int>(refineIters))->run(Hvec);
+            // update H with refined parameters
+            Hptr[0] = Hptr[4] = Hvec_buf[0];
+            Hptr[1] = -Hvec_buf[1];
+            Hptr[2] = Hvec_buf[2];
+            Hptr[3] = Hvec_buf[1];
+            Hptr[5] = Hvec_buf[3];
+        }
+    }
+
+    if (!result)
+    {
+        H.release();
+        if(_inliers.needed())
+        {
+            inliers = Mat::zeros(count, 1, CV_8U);
+            inliers.copyTo(_inliers);
+        }
+    }
+
+    return H;
+}
+
+} // namespace cv
diff --git a/modules/calib3d/src/quadsubpix.cpp b/modules/calib3d/src/quadsubpix.cpp
index 2e98a46..a640a67 100644
--- a/modules/calib3d/src/quadsubpix.cpp
+++ b/modules/calib3d/src/quadsubpix.cpp
@@ -163,6 +163,8 @@ static int segment_hist_max(const Mat& hist, int& low_thresh, int& high_thresh)
 
 bool cv::find4QuadCornerSubpix(InputArray _img, InputOutputArray _corners, Size region_size)
 {
+    CV_INSTRUMENT_REGION()
+
     Mat img = _img.getMat(), cornersM = _corners.getMat();
     int ncorners = cornersM.checkVector(2, CV_32F);
     CV_Assert( ncorners >= 0 );
diff --git a/modules/calib3d/src/rho.cpp b/modules/calib3d/src/rho.cpp
index 2f27728..728c3f6 100644
--- a/modules/calib3d/src/rho.cpp
+++ b/modules/calib3d/src/rho.cpp
@@ -44,7 +44,7 @@
  */
 
 /* Includes */
-#include <precomp.hpp>
+#include "precomp.hpp"
 #include <opencv2/core.hpp>
 #include <stdlib.h>
 #include <stdio.h>
@@ -2370,7 +2370,7 @@ static inline float  sacLMGain(const float*  dH,
 static inline int    sacChol8x8Damped(const float (*A)[8],
                                       float         lambda,
                                       float       (*L)[8]){
-    const register int N = 8;
+    const int N = 8;
     int i, j, k;
     float  lambdap1 = lambda + 1.0f;
     float  x;
diff --git a/modules/calib3d/src/solvepnp.cpp b/modules/calib3d/src/solvepnp.cpp
index 8b20cf7..e205580 100644
--- a/modules/calib3d/src/solvepnp.cpp
+++ b/modules/calib3d/src/solvepnp.cpp
@@ -56,6 +56,8 @@ bool solvePnP( InputArray _opoints, InputArray _ipoints,
                InputArray _cameraMatrix, InputArray _distCoeffs,
                OutputArray _rvec, OutputArray _tvec, bool useExtrinsicGuess, int flags )
 {
+    CV_INSTRUMENT_REGION()
+
     Mat opoints = _opoints.getMat(), ipoints = _ipoints.getMat();
     int npoints = std::max(opoints.checkVector(3, CV_32F), opoints.checkVector(3, CV_64F));
     CV_Assert( npoints >= 0 && npoints == std::max(ipoints.checkVector(2, CV_32F), ipoints.checkVector(2, CV_64F)) );
@@ -158,7 +160,7 @@ public:
           rvec(_rvec), tvec(_tvec) {}
 
     /* Pre: True */
-    /* Post: compute _model with given points an return number of found models */
+    /* Post: compute _model with given points and return number of found models */
     int runKernel( InputArray _m1, InputArray _m2, OutputArray _model ) const
     {
         Mat opoints = _m1.getMat(), ipoints = _m2.getMat();
@@ -195,7 +197,7 @@ public:
         float* err = _err.getMat().ptr<float>();
 
         for ( i = 0; i < count; ++i)
-            err[i] = (float)norm( ipoints_ptr[i] - projpoints_ptr[i] );
+            err[i] = (float)norm( Matx21f(ipoints_ptr[i] - projpoints_ptr[i]), NORM_L2SQR );
 
     }
 
@@ -214,6 +216,7 @@ bool solvePnPRansac(InputArray _opoints, InputArray _ipoints,
                         int iterationsCount, float reprojectionError, double confidence,
                         OutputArray _inliers, int flags)
 {
+    CV_INSTRUMENT_REGION()
 
     Mat opoints0 = _opoints.getMat(), ipoints0 = _ipoints.getMat();
     Mat opoints, ipoints;
@@ -270,6 +273,8 @@ bool solvePnPRansac(InputArray _opoints, InputArray _ipoints,
     {
         vector<Point3d> opoints_inliers;
         vector<Point2d> ipoints_inliers;
+        opoints = opoints.reshape(3);
+        ipoints = ipoints.reshape(2);
         opoints.convertTo(opoints_inliers, CV_64F);
         ipoints.convertTo(ipoints_inliers, CV_64F);
 
diff --git a/modules/calib3d/src/stereobm.cpp b/modules/calib3d/src/stereobm.cpp
index eb7daad..cd86131 100644
--- a/modules/calib3d/src/stereobm.cpp
+++ b/modules/calib3d/src/stereobm.cpp
@@ -317,7 +317,8 @@ prefilterXSobel( const Mat& src, Mat& dst, int ftzero )
 }
 
 
-static const int DISPARITY_SHIFT = 4;
+static const int DISPARITY_SHIFT_16S = 4;
+static const int DISPARITY_SHIFT_32S = 8;
 
 #if CV_SSE2
 static void findStereoCorrespondenceBM_SSE2( const Mat& left, const Mat& right,
@@ -337,7 +338,7 @@ static void findStereoCorrespondenceBM_SSE2( const Mat& left, const Mat& right,
     int ftzero = state.preFilterCap;
     int textureThreshold = state.textureThreshold;
     int uniquenessRatio = state.uniquenessRatio;
-    short FILTERED = (short)((mindisp - 1) << DISPARITY_SHIFT);
+    short FILTERED = (short)((mindisp - 1) << DISPARITY_SHIFT_16S);
 
     ushort *sad, *hsad0, *hsad, *hsad_sub;
     int *htext;
@@ -524,28 +525,27 @@ static void findStereoCorrespondenceBM_SSE2( const Mat& left, const Mat& right,
             if( uniquenessRatio > 0 )
             {
                 int thresh = minsad + (minsad * uniquenessRatio/100);
-                __m128i thresh8 = _mm_set1_epi16((short)(thresh + 1));
-                __m128i d1 = _mm_set1_epi16((short)(mind-1)), d2 = _mm_set1_epi16((short)(mind+1));
-                __m128i dd_16 = _mm_add_epi16(dd_8, dd_8);
-                d8 = _mm_sub_epi16(d0_8, dd_16);
+                __m128i thresh4 = _mm_set1_epi32(thresh + 1);
+                __m128i d1 = _mm_set1_epi32(mind-1), d2 = _mm_set1_epi32(mind+1);
+                __m128i dd_4 = _mm_set1_epi32(4);
+                __m128i d4 = _mm_set_epi32(3,2,1,0);
+                __m128i z = _mm_setzero_si128();
 
-                for( d = 0; d < ndisp; d += 16 )
+                for( d = 0; d < ndisp; d += 8 )
                 {
-                    __m128i usad8 = _mm_load_si128((__m128i*)(sad + d));
-                    __m128i vsad8 = _mm_load_si128((__m128i*)(sad + d + 8));
-                    mask = _mm_cmpgt_epi16( thresh8, _mm_min_epi16(usad8,vsad8));
-                    d8 = _mm_add_epi16(d8, dd_16);
-                    if( !_mm_movemask_epi8(mask) )
-                        continue;
-                    mask = _mm_cmpgt_epi16( thresh8, usad8);
-                    mask = _mm_and_si128(mask, _mm_or_si128(_mm_cmpgt_epi16(d1,d8), _mm_cmpgt_epi16(d8,d2)));
+                    __m128i usad4 = _mm_loadu_si128((__m128i*)(sad + d));
+                    __m128i vsad4 = _mm_unpackhi_epi16(usad4, z);
+                    usad4 = _mm_unpacklo_epi16(usad4, z);
+                    mask = _mm_cmpgt_epi32( thresh4, usad4);
+                    mask = _mm_and_si128(mask, _mm_or_si128(_mm_cmpgt_epi32(d1,d4), _mm_cmpgt_epi32(d4,d2)));
                     if( _mm_movemask_epi8(mask) )
                         break;
-                    __m128i t8 = _mm_add_epi16(d8, dd_8);
-                    mask = _mm_cmpgt_epi16( thresh8, vsad8);
-                    mask = _mm_and_si128(mask, _mm_or_si128(_mm_cmpgt_epi16(d1,t8), _mm_cmpgt_epi16(t8,d2)));
+                    d4 = _mm_add_epi16(d4, dd_4);
+                    mask = _mm_cmpgt_epi32( thresh4, vsad4);
+                    mask = _mm_and_si128(mask, _mm_or_si128(_mm_cmpgt_epi32(d1,d4), _mm_cmpgt_epi32(d4,d2)));
                     if( _mm_movemask_epi8(mask) )
                         break;
+                    d4 = _mm_add_epi16(d4, dd_4);
                 }
                 if( d < ndisp )
                 {
@@ -568,10 +568,11 @@ static void findStereoCorrespondenceBM_SSE2( const Mat& left, const Mat& right,
 }
 #endif
 
+template <typename mType>
 static void
-findStereoCorrespondenceBM( const Mat& left, const Mat& right,
+findStereoCorrespondenceBM_( const Mat& left, const Mat& right,
                            Mat& disp, Mat& cost, const StereoBMParams& state,
-                           uchar* buf, int _dy0, int _dy1 )
+                           uchar* buf, int _dy0, int _dy1, const int disp_shift )
 {
 
     const int ALIGN = 16;
@@ -587,7 +588,7 @@ findStereoCorrespondenceBM( const Mat& left, const Mat& right,
     int ftzero = state.preFilterCap;
     int textureThreshold = state.textureThreshold;
     int uniquenessRatio = state.uniquenessRatio;
-    short FILTERED = (short)((mindisp - 1) << DISPARITY_SHIFT);
+    mType FILTERED = (mType)((mindisp - 1) << disp_shift);
 
 #if CV_NEON
     CV_Assert (ndisp % 8 == 0);
@@ -603,7 +604,7 @@ findStereoCorrespondenceBM( const Mat& left, const Mat& right,
     const uchar* lptr0 = left.ptr() + lofs;
     const uchar* rptr0 = right.ptr() + rofs;
     const uchar *lptr, *lptr_sub, *rptr;
-    short* dptr = disp.ptr<short>();
+    mType* dptr = disp.ptr<mType>();
     int sstep = (int)left.step;
     int dstep = (int)(disp.step/sizeof(dptr[0]));
     int cstep = (height+dy0+dy1)*ndisp;
@@ -846,13 +847,27 @@ findStereoCorrespondenceBM( const Mat& left, const Mat& right,
                 sad[ndisp] = sad[ndisp-2];
                 int p = sad[mind+1], n = sad[mind-1];
                 d = p + n - 2*sad[mind] + std::abs(p - n);
-                dptr[y*dstep] = (short)(((ndisp - mind - 1 + mindisp)*256 + (d != 0 ? (p-n)*256/d : 0) + 15) >> 4);
+                dptr[y*dstep] = (mType)(((ndisp - mind - 1 + mindisp)*256 + (d != 0 ? (p-n)*256/d : 0) + 15)
+                                 >> (DISPARITY_SHIFT_32S - disp_shift));
                 costptr[y*coststep] = sad[mind];
             }
         }
     }
 }
 
+static void
+findStereoCorrespondenceBM( const Mat& left, const Mat& right,
+                            Mat& disp, Mat& cost, const StereoBMParams& state,
+                            uchar* buf, int _dy0, int _dy1 )
+{
+    if(disp.type() == CV_16S)
+        findStereoCorrespondenceBM_<short>(left, right, disp, cost, state,
+                                           buf, _dy0, _dy1, DISPARITY_SHIFT_16S );
+     else
+        findStereoCorrespondenceBM_<int>(left, right, disp, cost, state,
+                                         buf, _dy0, _dy1, DISPARITY_SHIFT_32S );
+}
+
 #ifdef HAVE_OPENCL
 static bool ocl_prefiltering(InputArray left0, InputArray right0, OutputArray left, OutputArray right, StereoBMParams* state)
 {
@@ -1045,6 +1060,8 @@ public:
 
     void compute( InputArray leftarr, InputArray rightarr, OutputArray disparr )
     {
+        CV_INSTRUMENT_REGION()
+
         int dtype = disparr.fixedType() ? disparr.type() : params.dispType;
         Size leftsize = leftarr.size();
 
@@ -1080,7 +1097,14 @@ public:
         if( params.uniquenessRatio < 0 )
             CV_Error( Error::StsOutOfRange, "uniqueness ratio must be non-negative" );
 
-        int FILTERED = (params.minDisparity - 1) << DISPARITY_SHIFT;
+        int disp_shift;
+        if (dtype == CV_16SC1)
+            disp_shift = DISPARITY_SHIFT_16S;
+        else
+            disp_shift = DISPARITY_SHIFT_32S;
+
+
+        int FILTERED = (params.minDisparity - 1) << disp_shift;
 
 #ifdef HAVE_OPENCL
         if(ocl::useOpenCL() && disparr.isUMat() && params.textureThreshold == 0)
@@ -1093,7 +1117,7 @@ public:
                     if( params.speckleRange >= 0 && params.speckleWindowSize > 0 )
                         filterSpeckles(disparr.getMat(), FILTERED, params.speckleWindowSize, params.speckleRange, slidingSumBuf);
                     if (dtype == CV_32F)
-                        disparr.getUMat().convertTo(disparr, CV_32FC1, 1./(1 << DISPARITY_SHIFT), 0);
+                        disparr.getUMat().convertTo(disparr, CV_32FC1, 1./(1 << disp_shift), 0);
                     CV_IMPL_ADD(CV_IMPL_OCL);
                     return;
                 }
@@ -1122,14 +1146,14 @@ public:
 
         if( lofs >= width || rofs >= width || width1 < 1 )
         {
-            disp0 = Scalar::all( FILTERED * ( disp0.type() < CV_32F ? 1 : 1./(1 << DISPARITY_SHIFT) ) );
+            disp0 = Scalar::all( FILTERED * ( disp0.type() < CV_32F ? 1 : 1./(1 << disp_shift) ) );
             return;
         }
 
         Mat disp = disp0;
         if( dtype == CV_32F )
         {
-            dispbuf.create(disp0.size(), CV_16S);
+            dispbuf.create(disp0.size(), CV_32S);
             disp = dispbuf;
         }
 
@@ -1178,7 +1202,7 @@ public:
             filterSpeckles(disp, FILTERED, params.speckleWindowSize, params.speckleRange, slidingSumBuf);
 
         if (disp0.data != disp.data)
-            disp.convertTo(disp0, disp0.type(), 1./(1 << DISPARITY_SHIFT), 0);
+            disp.convertTo(disp0, disp0.type(), 1./(1 << disp_shift), 0);
     }
 
     int getMinDisparity() const { return params.minDisparity; }
@@ -1225,6 +1249,7 @@ public:
 
     void write(FileStorage& fs) const
     {
+        writeFormat(fs);
         fs << "name" << name_
         << "minDisparity" << params.minDisparity
         << "numDisparities" << params.numDisparities
diff --git a/modules/calib3d/src/stereosgbm.cpp b/modules/calib3d/src/stereosgbm.cpp
index 1c085f9..27ce62e 100644
--- a/modules/calib3d/src/stereosgbm.cpp
+++ b/modules/calib3d/src/stereosgbm.cpp
@@ -131,6 +131,9 @@ static void calcPixelCostBT( const Mat& img1, const Mat& img2, int y,
     int D = maxD - minD, width1 = maxX1 - minX1, width2 = maxX2 - minX2;
     const PixType *row1 = img1.ptr<PixType>(y), *row2 = img2.ptr<PixType>(y);
     PixType *prow1 = buffer + width2*2, *prow2 = prow1 + width*cn*2;
+#if CV_SIMD128
+    bool useSIMD = hasSIMD128();
+#endif
 
     tab += tabOfs;
 
@@ -181,7 +184,6 @@ static void calcPixelCostBT( const Mat& img1, const Mat& img2, int y,
     buffer -= minX2;
     cost -= minX1*D + minD; // simplify the cost indices inside the loop
 
-#if 1
     for( c = 0; c < cn*2; c++, prow1 += width, prow2 += width )
     {
         int diff_scale = c < cn ? 0 : 2;
@@ -209,60 +211,27 @@ static void calcPixelCostBT( const Mat& img1, const Mat& img2, int y,
             int u1 = std::max(ul, ur); u1 = std::max(u1, u);
 
         #if CV_SIMD128
-            v_uint8x16 _u  = v_setall_u8((uchar)u), _u0 = v_setall_u8((uchar)u0);
-            v_uint8x16 _u1 = v_setall_u8((uchar)u1);
-
-            for( int d = minD; d < maxD; d += 16 )
-            {
-                v_uint8x16 _v  = v_load(prow2  + width-x-1 + d);
-                v_uint8x16 _v0 = v_load(buffer + width-x-1 + d);
-                v_uint8x16 _v1 = v_load(buffer + width-x-1 + d + width2);
-                v_uint8x16 c0 = v_max(_u - _v1, _v0 - _u);
-                v_uint8x16 c1 = v_max(_v - _u1, _u0 - _v);
-                v_uint8x16 diff = v_min(c0, c1);
-
-                v_int16x8 _c0 = v_load_aligned(cost + x*D + d);
-                v_int16x8 _c1 = v_load_aligned(cost + x*D + d + 8);
-
-                v_uint16x8 diff1,diff2;
-                v_expand(diff,diff1,diff2);
-                v_store_aligned(cost + x*D + d,     _c0 + v_reinterpret_as_s16(diff1 >> diff_scale));
-                v_store_aligned(cost + x*D + d + 8, _c1 + v_reinterpret_as_s16(diff2 >> diff_scale));
-            }
-        #else
-            for( int d = minD; d < maxD; d++ )
-            {
-                int v = prow2[width-x-1 + d];
-                int v0 = buffer[width-x-1 + d];
-                int v1 = buffer[width-x-1 + d + width2];
-                int c0 = std::max(0, u - v1); c0 = std::max(c0, v0 - u);
-                int c1 = std::max(0, v - u1); c1 = std::max(c1, u0 - v);
-
-                cost[x*D + d] = (CostType)(cost[x*D+d] + (std::min(c0, c1) >> diff_scale));
-            }
-        #endif
-        }
-    }
-#else
-    for( c = 0; c < cn*2; c++, prow1 += width, prow2 += width )
-    {
-        for( x = minX1; x < maxX1; x++ )
-        {
-            int u = prow1[x];
-        #if CV_SSE2
             if( useSIMD )
             {
-                __m128i _u = _mm_set1_epi8(u), z = _mm_setzero_si128();
+                v_uint8x16 _u  = v_setall_u8((uchar)u), _u0 = v_setall_u8((uchar)u0);
+                v_uint8x16 _u1 = v_setall_u8((uchar)u1);
 
                 for( int d = minD; d < maxD; d += 16 )
                 {
-                    __m128i _v = _mm_loadu_si128((const __m128i*)(prow2 + width-1-x + d));
-                    __m128i diff = _mm_adds_epu8(_mm_subs_epu8(_u,_v), _mm_subs_epu8(_v,_u));
-                    __m128i c0 = _mm_load_si128((__m128i*)(cost + x*D + d));
-                    __m128i c1 = _mm_load_si128((__m128i*)(cost + x*D + d + 8));
-
-                    _mm_store_si128((__m128i*)(cost + x*D + d), _mm_adds_epi16(c0, _mm_unpacklo_epi8(diff,z)));
-                    _mm_store_si128((__m128i*)(cost + x*D + d + 8), _mm_adds_epi16(c1, _mm_unpackhi_epi8(diff,z)));
+                    v_uint8x16 _v  = v_load(prow2  + width-x-1 + d);
+                    v_uint8x16 _v0 = v_load(buffer + width-x-1 + d);
+                    v_uint8x16 _v1 = v_load(buffer + width-x-1 + d + width2);
+                    v_uint8x16 c0 = v_max(_u - _v1, _v0 - _u);
+                    v_uint8x16 c1 = v_max(_v - _u1, _u0 - _v);
+                    v_uint8x16 diff = v_min(c0, c1);
+
+                    v_int16x8 _c0 = v_load_aligned(cost + x*D + d);
+                    v_int16x8 _c1 = v_load_aligned(cost + x*D + d + 8);
+
+                    v_uint16x8 diff1,diff2;
+                    v_expand(diff,diff1,diff2);
+                    v_store_aligned(cost + x*D + d,     _c0 + v_reinterpret_as_s16(diff1 >> diff_scale));
+                    v_store_aligned(cost + x*D + d + 8, _c1 + v_reinterpret_as_s16(diff2 >> diff_scale));
                 }
             }
             else
@@ -270,13 +239,17 @@ static void calcPixelCostBT( const Mat& img1, const Mat& img2, int y,
             {
                 for( int d = minD; d < maxD; d++ )
                 {
-                    int v = prow2[width-1-x + d];
-                    cost[x*D + d] = (CostType)(cost[x*D + d] + (CostType)std::abs(u - v));
+                    int v = prow2[width-x-1 + d];
+                    int v0 = buffer[width-x-1 + d];
+                    int v1 = buffer[width-x-1 + d + width2];
+                    int c0 = std::max(0, u - v1); c0 = std::max(c0, v0 - u);
+                    int c1 = std::max(0, v - u1); c1 = std::max(c1, u0 - v);
+
+                    cost[x*D + d] = (CostType)(cost[x*D+d] + (std::min(c0, c1) >> diff_scale));
                 }
             }
         }
     }
-#endif
 }
 
 
@@ -304,7 +277,8 @@ static void computeDisparitySGBM( const Mat& img1, const Mat& img2,
                                  Mat& disp1, const StereoSGBMParams& params,
                                  Mat& buffer )
 {
-#if CV_SSE2
+#if CV_SIMD128
+    // maxDisparity is supposed to multiple of 16, so we can forget doing else
     static const uchar LSBTab[] =
     {
         0, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
@@ -316,8 +290,9 @@ static void computeDisparitySGBM( const Mat& img1, const Mat& img2,
         6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,
         5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0
     };
+    static const v_uint16x8 v_LSB = v_uint16x8(0x1, 0x2, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80);
 
-    volatile bool useSIMD = checkHardwareSupport(CV_CPU_SSE2);
+    bool useSIMD = hasSIMD128();
 #endif
 
     const int ALIGN = 16;
@@ -391,7 +366,7 @@ static void computeDisparitySGBM( const Mat& img1, const Mat& img2,
     PixType* tempBuf = (PixType*)(disp2ptr + width);
 
     // add P2 to every C(x,y). it saves a few operations in the inner loops
-    for( k = 0; k < width1*D; k++ )
+    for(k = 0; k < (int)CSBufSize; k++ )
         Cbuf[k] = (CostType)P2;
 
     for( int pass = 1; pass <= npasses; pass++ )
@@ -461,21 +436,20 @@ static void computeDisparitySGBM( const Mat& img1, const Mat& img2,
                                 const CostType* pixAdd = pixDiff + std::min(x + SW2*D, (width1-1)*D);
                                 const CostType* pixSub = pixDiff + std::max(x - (SW2+1)*D, 0);
 
-                            #if CV_SSE2
+                            #if CV_SIMD128
                                 if( useSIMD )
                                 {
                                     for( d = 0; d < D; d += 8 )
                                     {
-                                        __m128i hv = _mm_load_si128((const __m128i*)(hsumAdd + x - D + d));
-                                        __m128i Cx = _mm_load_si128((__m128i*)(Cprev + x + d));
-                                        hv = _mm_adds_epi16(_mm_subs_epi16(hv,
-                                                                           _mm_load_si128((const __m128i*)(pixSub + d))),
-                                                            _mm_load_si128((const __m128i*)(pixAdd + d)));
-                                        Cx = _mm_adds_epi16(_mm_subs_epi16(Cx,
-                                                                           _mm_load_si128((const __m128i*)(hsumSub + x + d))),
-                                                            hv);
-                                        _mm_store_si128((__m128i*)(hsumAdd + x + d), hv);
-                                        _mm_store_si128((__m128i*)(C + x + d), Cx);
+                                        v_int16x8 hv = v_load(hsumAdd + x - D + d);
+                                        v_int16x8 Cx = v_load(Cprev + x + d);
+                                        v_int16x8 psub = v_load(pixSub + d);
+                                        v_int16x8 padd = v_load(pixAdd + d);
+                                        hv = (hv - psub + padd);
+                                        psub = v_load(hsumSub + x + d);
+                                        Cx = Cx - psub + hv;
+                                        v_store(hsumAdd + x + d, hv);
+                                        v_store(C + x + d, Cx);
                                     }
                                 }
                                 else
@@ -558,73 +532,79 @@ static void computeDisparitySGBM( const Mat& img1, const Mat& img2,
                 const CostType* Cp = C + x*D;
                 CostType* Sp = S + x*D;
 
-            #if CV_SSE2
+            #if CV_SIMD128
                 if( useSIMD )
                 {
-                    __m128i _P1 = _mm_set1_epi16((short)P1);
+                    v_int16x8 _P1 = v_setall_s16((short)P1);
 
-                    __m128i _delta0 = _mm_set1_epi16((short)delta0);
-                    __m128i _delta1 = _mm_set1_epi16((short)delta1);
-                    __m128i _delta2 = _mm_set1_epi16((short)delta2);
-                    __m128i _delta3 = _mm_set1_epi16((short)delta3);
-                    __m128i _minL0 = _mm_set1_epi16((short)MAX_COST);
+                    v_int16x8 _delta0 = v_setall_s16((short)delta0);
+                    v_int16x8 _delta1 = v_setall_s16((short)delta1);
+                    v_int16x8 _delta2 = v_setall_s16((short)delta2);
+                    v_int16x8 _delta3 = v_setall_s16((short)delta3);
+                    v_int16x8 _minL0 = v_setall_s16((short)MAX_COST);
 
                     for( d = 0; d < D; d += 8 )
                     {
-                        __m128i Cpd = _mm_load_si128((const __m128i*)(Cp + d));
-                        __m128i L0, L1, L2, L3;
+                        v_int16x8 Cpd = v_load(Cp + d);
+                        v_int16x8 L0, L1, L2, L3;
 
-                        L0 = _mm_load_si128((const __m128i*)(Lr_p0 + d));
-                        L1 = _mm_load_si128((const __m128i*)(Lr_p1 + d));
-                        L2 = _mm_load_si128((const __m128i*)(Lr_p2 + d));
-                        L3 = _mm_load_si128((const __m128i*)(Lr_p3 + d));
+                        L0 = v_load(Lr_p0 + d);
+                        L1 = v_load(Lr_p1 + d);
+                        L2 = v_load(Lr_p2 + d);
+                        L3 = v_load(Lr_p3 + d);
 
-                        L0 = _mm_min_epi16(L0, _mm_adds_epi16(_mm_loadu_si128((const __m128i*)(Lr_p0 + d - 1)), _P1));
-                        L0 = _mm_min_epi16(L0, _mm_adds_epi16(_mm_loadu_si128((const __m128i*)(Lr_p0 + d + 1)), _P1));
+                        L0 = v_min(L0, (v_load(Lr_p0 + d - 1) + _P1));
+                        L0 = v_min(L0, (v_load(Lr_p0 + d + 1) + _P1));
 
-                        L1 = _mm_min_epi16(L1, _mm_adds_epi16(_mm_loadu_si128((const __m128i*)(Lr_p1 + d - 1)), _P1));
-                        L1 = _mm_min_epi16(L1, _mm_adds_epi16(_mm_loadu_si128((const __m128i*)(Lr_p1 + d + 1)), _P1));
+                        L1 = v_min(L1, (v_load(Lr_p1 + d - 1) + _P1));
+                        L1 = v_min(L1, (v_load(Lr_p1 + d + 1) + _P1));
 
-                        L2 = _mm_min_epi16(L2, _mm_adds_epi16(_mm_loadu_si128((const __m128i*)(Lr_p2 + d - 1)), _P1));
-                        L2 = _mm_min_epi16(L2, _mm_adds_epi16(_mm_loadu_si128((const __m128i*)(Lr_p2 + d + 1)), _P1));
+                        L2 = v_min(L2, (v_load(Lr_p2 + d - 1) + _P1));
+                        L2 = v_min(L2, (v_load(Lr_p2 + d + 1) + _P1));
 
-                        L3 = _mm_min_epi16(L3, _mm_adds_epi16(_mm_loadu_si128((const __m128i*)(Lr_p3 + d - 1)), _P1));
-                        L3 = _mm_min_epi16(L3, _mm_adds_epi16(_mm_loadu_si128((const __m128i*)(Lr_p3 + d + 1)), _P1));
+                        L3 = v_min(L3, (v_load(Lr_p3 + d - 1) + _P1));
+                        L3 = v_min(L3, (v_load(Lr_p3 + d + 1) + _P1));
 
-                        L0 = _mm_min_epi16(L0, _delta0);
-                        L0 = _mm_adds_epi16(_mm_subs_epi16(L0, _delta0), Cpd);
+                        L0 = v_min(L0, _delta0);
+                        L0 = ((L0 - _delta0) + Cpd);
 
-                        L1 = _mm_min_epi16(L1, _delta1);
-                        L1 = _mm_adds_epi16(_mm_subs_epi16(L1, _delta1), Cpd);
+                        L1 = v_min(L1, _delta1);
+                        L1 = ((L1 - _delta1) + Cpd);
 
-                        L2 = _mm_min_epi16(L2, _delta2);
-                        L2 = _mm_adds_epi16(_mm_subs_epi16(L2, _delta2), Cpd);
+                        L2 = v_min(L2, _delta2);
+                        L2 = ((L2 - _delta2) + Cpd);
 
-                        L3 = _mm_min_epi16(L3, _delta3);
-                        L3 = _mm_adds_epi16(_mm_subs_epi16(L3, _delta3), Cpd);
+                        L3 = v_min(L3, _delta3);
+                        L3 = ((L3 - _delta3) + Cpd);
 
-                        _mm_store_si128( (__m128i*)(Lr_p + d), L0);
-                        _mm_store_si128( (__m128i*)(Lr_p + d + D2), L1);
-                        _mm_store_si128( (__m128i*)(Lr_p + d + D2*2), L2);
-                        _mm_store_si128( (__m128i*)(Lr_p + d + D2*3), L3);
+                        v_store(Lr_p + d, L0);
+                        v_store(Lr_p + d + D2, L1);
+                        v_store(Lr_p + d + D2*2, L2);
+                        v_store(Lr_p + d + D2*3, L3);
 
-                        __m128i t0 = _mm_min_epi16(_mm_unpacklo_epi16(L0, L2), _mm_unpackhi_epi16(L0, L2));
-                        __m128i t1 = _mm_min_epi16(_mm_unpacklo_epi16(L1, L3), _mm_unpackhi_epi16(L1, L3));
-                        t0 = _mm_min_epi16(_mm_unpacklo_epi16(t0, t1), _mm_unpackhi_epi16(t0, t1));
-                        _minL0 = _mm_min_epi16(_minL0, t0);
+                        // Get minimum from in L0-L3
+                        v_int16x8 t02L, t02H, t13L, t13H, t0123L, t0123H;
+                        v_zip(L0, L2, t02L, t02H);            // L0[0] L2[0] L0[1] L2[1]...
+                        v_zip(L1, L3, t13L, t13H);            // L1[0] L3[0] L1[1] L3[1]...
+                        v_int16x8 t02 = v_min(t02L, t02H);    // L0[i] L2[i] L0[i] L2[i]...
+                        v_int16x8 t13 = v_min(t13L, t13H);    // L1[i] L3[i] L1[i] L3[i]...
+                        v_zip(t02, t13, t0123L, t0123H);      // L0[i] L1[i] L2[i] L3[i]...
+                        v_int16x8 t0 = v_min(t0123L, t0123H);
+                        _minL0 = v_min(_minL0, t0);
 
-                        __m128i Sval = _mm_load_si128((const __m128i*)(Sp + d));
+                        v_int16x8 Sval = v_load(Sp + d);
 
-                        L0 = _mm_adds_epi16(L0, L1);
-                        L2 = _mm_adds_epi16(L2, L3);
-                        Sval = _mm_adds_epi16(Sval, L0);
-                        Sval = _mm_adds_epi16(Sval, L2);
+                        L0 = L0 + L1;
+                        L2 = L2 + L3;
+                        Sval = Sval + L0;
+                        Sval = Sval + L2;
 
-                        _mm_store_si128((__m128i*)(Sp + d), Sval);
+                        v_store(Sp + d, Sval);
                     }
 
-                    _minL0 = _mm_min_epi16(_minL0, _mm_srli_si128(_minL0, 8));
-                    _mm_storel_epi64((__m128i*)&minLr[0][xm], _minL0);
+                    v_int32x4 minL, minH;
+                    v_expand(_minL0, minL, minH);
+                    v_pack_store(&minLr[0][xm], v_min(minL, minH));
                 }
                 else
             #endif
@@ -686,55 +666,54 @@ static void computeDisparitySGBM( const Mat& img1, const Mat& img2,
 
                         const CostType* Cp = C + x*D;
 
-                    #if CV_SSE2
+                    #if CV_SIMD128
                         if( useSIMD )
                         {
-                            __m128i _P1 = _mm_set1_epi16((short)P1);
-                            __m128i _delta0 = _mm_set1_epi16((short)delta0);
+                            v_int16x8 _P1 = v_setall_s16((short)P1);
+                            v_int16x8 _delta0 = v_setall_s16((short)delta0);
 
-                            __m128i _minL0 = _mm_set1_epi16((short)minL0);
-                            __m128i _minS = _mm_set1_epi16(MAX_COST), _bestDisp = _mm_set1_epi16(-1);
-                            __m128i _d8 = _mm_setr_epi16(0, 1, 2, 3, 4, 5, 6, 7), _8 = _mm_set1_epi16(8);
+                            v_int16x8 _minL0 = v_setall_s16((short)minL0);
+                            v_int16x8 _minS = v_setall_s16(MAX_COST), _bestDisp = v_setall_s16(-1);
+                            v_int16x8 _d8 = v_int16x8(0, 1, 2, 3, 4, 5, 6, 7), _8 = v_setall_s16(8);
 
                             for( d = 0; d < D; d += 8 )
                             {
-                                __m128i Cpd = _mm_load_si128((const __m128i*)(Cp + d)), L0;
-
-                                L0 = _mm_load_si128((const __m128i*)(Lr_p0 + d));
-                                L0 = _mm_min_epi16(L0, _mm_adds_epi16(_mm_loadu_si128((const __m128i*)(Lr_p0 + d - 1)), _P1));
-                                L0 = _mm_min_epi16(L0, _mm_adds_epi16(_mm_loadu_si128((const __m128i*)(Lr_p0 + d + 1)), _P1));
-                                L0 = _mm_min_epi16(L0, _delta0);
-                                L0 = _mm_adds_epi16(_mm_subs_epi16(L0, _delta0), Cpd);
-
-                                _mm_store_si128((__m128i*)(Lr_p + d), L0);
-                                _minL0 = _mm_min_epi16(_minL0, L0);
-                                L0 = _mm_adds_epi16(L0, *(__m128i*)(Sp + d));
-                                _mm_store_si128((__m128i*)(Sp + d), L0);
-
-                                __m128i mask = _mm_cmpgt_epi16(_minS, L0);
-                                _minS = _mm_min_epi16(_minS, L0);
-                                _bestDisp = _mm_xor_si128(_bestDisp, _mm_and_si128(_mm_xor_si128(_bestDisp,_d8), mask));
-                                _d8 = _mm_adds_epi16(_d8, _8);
+                                v_int16x8 Cpd = v_load(Cp + d);
+                                v_int16x8 L0 = v_load(Lr_p0 + d);
+
+                                L0 = v_min(L0, v_load(Lr_p0 + d - 1) + _P1);
+                                L0 = v_min(L0, v_load(Lr_p0 + d + 1) + _P1);
+                                L0 = v_min(L0, _delta0);
+                                L0 = L0 - _delta0 + Cpd;
+
+                                v_store(Lr_p + d, L0);
+                                _minL0 = v_min(_minL0, L0);
+                                L0 = L0 + v_load(Sp + d);
+                                v_store(Sp + d, L0);
+
+                                v_int16x8 mask = _minS > L0;
+                                _minS = v_min(_minS, L0);
+                                _bestDisp = _bestDisp ^ ((_bestDisp ^ _d8) & mask);
+                                _d8 += _8;
                             }
+                            short bestDispBuf[8];
+                            v_store(bestDispBuf, _bestDisp);
 
-                            short CV_DECL_ALIGNED(16) bestDispBuf[8];
-                            _mm_store_si128((__m128i*)bestDispBuf, _bestDisp);
-
-                            _minL0 = _mm_min_epi16(_minL0, _mm_srli_si128(_minL0, 8));
-                            _minL0 = _mm_min_epi16(_minL0, _mm_srli_si128(_minL0, 4));
-                            _minL0 = _mm_min_epi16(_minL0, _mm_srli_si128(_minL0, 2));
+                            v_int32x4 min32L, min32H;
+                            v_expand(_minL0, min32L, min32H);
+                            minLr[0][xm] = (CostType)std::min(v_reduce_min(min32L), v_reduce_min(min32H));
 
-                            __m128i qS = _mm_min_epi16(_minS, _mm_srli_si128(_minS, 8));
-                            qS = _mm_min_epi16(qS, _mm_srli_si128(qS, 4));
-                            qS = _mm_min_epi16(qS, _mm_srli_si128(qS, 2));
+                            v_expand(_minS, min32L, min32H);
+                            minS = std::min(v_reduce_min(min32L), v_reduce_min(min32H));
 
-                            minLr[0][xm] = (CostType)_mm_cvtsi128_si32(_minL0);
-                            minS = (CostType)_mm_cvtsi128_si32(qS);
+                            v_int16x8 ss = v_setall_s16((short)minS);
+                            v_uint16x8 minMask = v_reinterpret_as_u16(ss == _minS);
+                            v_uint16x8 minBit = minMask & v_LSB;
 
-                            qS = _mm_shuffle_epi32(_mm_unpacklo_epi16(qS, qS), 0);
-                            qS = _mm_cmpeq_epi16(_minS, qS);
-                            int idx = _mm_movemask_epi8(_mm_packs_epi16(qS, qS)) & 255;
+                            v_uint32x4 minBitL, minBitH;
+                            v_expand(minBit, minBitL, minBitH);
 
+                            int idx = v_reduce_sum(minBitL) + v_reduce_sum(minBitH);
                             bestDisp = bestDispBuf[LSBTab[idx]];
                         }
                         else
@@ -759,13 +738,40 @@ static void computeDisparitySGBM( const Mat& img1, const Mat& img2,
                     }
                     else
                     {
-                        for( d = 0; d < D; d++ )
+                    #if CV_SIMD128
+                        if( useSIMD )
                         {
-                            int Sval = Sp[d];
-                            if( Sval < minS )
+                            v_int16x8 _minS = v_setall_s16(MAX_COST), _bestDisp = v_setall_s16(-1);
+                            v_int16x8 _d8 = v_int16x8(0, 1, 2, 3, 4, 5, 6, 7), _8 = v_setall_s16(8);
+
+                            for( d = 0; d < D; d+= 8 )
                             {
-                                minS = Sval;
-                                bestDisp = d;
+                                v_int16x8 L0 = v_load(Sp + d);
+                                v_int16x8 mask = L0 < _minS;
+                                _minS = v_min( L0, _minS );
+                                _bestDisp = _bestDisp ^ ((_bestDisp ^ _d8) & mask);
+                                _d8 = _d8 + _8;
+                            }
+                            v_int32x4 _d0, _d1;
+                            v_expand(_minS, _d0, _d1);
+                            minS = (int)std::min(v_reduce_min(_d0), v_reduce_min(_d1));
+                            v_int16x8 v_mask = v_setall_s16((short)minS) == _minS;
+
+                            _bestDisp = (_bestDisp & v_mask) | (v_setall_s16(SHRT_MAX) & ~v_mask);
+                            v_expand(_bestDisp, _d0, _d1);
+                            bestDisp = (int)std::min(v_reduce_min(_d0), v_reduce_min(_d1));
+                        }
+                        else
+                    #endif
+                        {
+                            for( d = 0; d < D; d++ )
+                            {
+                                int Sval = Sp[d];
+                                if( Sval < minS )
+                                {
+                                    minS = Sval;
+                                    bestDisp = d;
+                                }
                             }
                         }
                     }
@@ -850,6 +856,10 @@ struct SGBM3WayMainLoop : public ParallelLoopBody
     int costBufSize, hsumBufNRows;
     int TAB_OFS, ftzero;
 
+#if CV_SIMD128
+    bool useSIMD;
+#endif
+
     PixType* clipTab;
 
     SGBM3WayMainLoop(Mat *_buffers, const Mat& _img1, const Mat& _img2, Mat* _dst_disp, const StereoSGBMParams& params, PixType* _clipTab, int _nstripes, int _stripe_overlap);
@@ -879,6 +889,10 @@ buffers(_buffers), img1(&_img1), img2(&_img2), dst_disp(_dst_disp), clipTab(_cli
     hsumBufNRows = SH2*2 + 2;
     TAB_OFS = 256*4;
     ftzero = std::max(params.preFilterCap, 15) | 1;
+
+#if CV_SIMD128
+    useSIMD = hasSIMD128();
+#endif
 }
 
 void getBufferPointers(Mat& buffer, int width, int width1, int D, int num_ch, int SH2, int P2,
@@ -979,20 +993,25 @@ void SGBM3WayMainLoop::getRawMatchingCost(CostType* C, // target cost-volume row
                     const CostType* pixSub = pixDiff + std::max(x - (SW2+1)*D, 0);
 
 #if CV_SIMD128
-                    v_int16x8 hv_reg;
-                    for( d = 0; d < D; d+=8 )
+                    if(useSIMD)
                     {
-                        hv_reg = v_load_aligned(hsumAdd+x-D+d) + (v_load_aligned(pixAdd+d) - v_load_aligned(pixSub+d));
-                        v_store_aligned(hsumAdd+x+d,hv_reg);
-                        v_store_aligned(C+x+d,v_load_aligned(C+x+d)+(hv_reg-v_load_aligned(hsumSub+x+d)));
+                        v_int16x8 hv_reg;
+                        for( d = 0; d < D; d+=8 )
+                        {
+                            hv_reg = v_load_aligned(hsumAdd+x-D+d) + (v_load_aligned(pixAdd+d) - v_load_aligned(pixSub+d));
+                            v_store_aligned(hsumAdd+x+d,hv_reg);
+                            v_store_aligned(C+x+d,v_load_aligned(C+x+d)+(hv_reg-v_load_aligned(hsumSub+x+d)));
+                        }
                     }
-#else
-                    for( d = 0; d < D; d++ )
+                    else
+#endif
                     {
-                        int hv = hsumAdd[x + d] = (CostType)(hsumAdd[x - D + d] + pixAdd[d] - pixSub[d]);
-                        C[x + d] = (CostType)(C[x + d] + hv - hsumSub[x + d]);
+                        for( d = 0; d < D; d++ )
+                        {
+                            int hv = hsumAdd[x + d] = (CostType)(hsumAdd[x - D + d] + pixAdd[d] - pixSub[d]);
+                            C[x + d] = (CostType)(C[x + d] + hv - hsumSub[x + d]);
+                        }
                     }
-#endif
                 }
             }
             else
@@ -1019,34 +1038,13 @@ void SGBM3WayMainLoop::getRawMatchingCost(CostType* C, // target cost-volume row
 
 #if CV_SIMD128
 // define some additional reduce operations:
-inline short min(const v_int16x8& a)
+inline short min_pos(const v_int16x8& val, const v_int16x8& pos, const short min_val)
 {
-    short CV_DECL_ALIGNED(16) buf[8];
-    v_store_aligned(buf, a);
-    short s0 = std::min(buf[0], buf[1]);
-    short s1 = std::min(buf[2], buf[3]);
-    short s2 = std::min(buf[4], buf[5]);
-    short s3 = std::min(buf[6], buf[7]);
-    return std::min(std::min(s0, s1),std::min(s2, s3));
-}
+    v_int16x8 v_min = v_setall_s16(min_val);
+    v_int16x8 v_mask = v_min == val;
+    v_int16x8 v_pos = (pos & v_mask) | (v_setall_s16(SHRT_MAX) & ~v_mask);
 
-inline short min_pos(const v_int16x8& val,const v_int16x8& pos)
-{
-    short CV_DECL_ALIGNED(16) val_buf[8];
-    v_store_aligned(val_buf, val);
-    short CV_DECL_ALIGNED(16) pos_buf[8];
-    v_store_aligned(pos_buf, pos);
-    short res_pos = 0;
-    short min_val = SHRT_MAX;
-    if(val_buf[0]<min_val) {min_val=val_buf[0]; res_pos=pos_buf[0];}
-    if(val_buf[1]<min_val) {min_val=val_buf[1]; res_pos=pos_buf[1];}
-    if(val_buf[2]<min_val) {min_val=val_buf[2]; res_pos=pos_buf[2];}
-    if(val_buf[3]<min_val) {min_val=val_buf[3]; res_pos=pos_buf[3];}
-    if(val_buf[4]<min_val) {min_val=val_buf[4]; res_pos=pos_buf[4];}
-    if(val_buf[5]<min_val) {min_val=val_buf[5]; res_pos=pos_buf[5];}
-    if(val_buf[6]<min_val) {min_val=val_buf[6]; res_pos=pos_buf[6];}
-    if(val_buf[7]<min_val) {min_val=val_buf[7]; res_pos=pos_buf[7];}
-    return res_pos;
+    return v_reduce_min(v_pos);
 }
 #endif
 
@@ -1056,104 +1054,109 @@ inline void accumulateCostsLeftTop(CostType* leftBuf, CostType* leftBuf_prev, Co
                                    CostType& leftMinCost, CostType& topMinCost, int D, int P1, int P2)
 {
 #if CV_SIMD128
-    v_int16x8 P1_reg = v_setall_s16(cv::saturate_cast<CostType>(P1));
+    if(hasSIMD128())
+    {
+        v_int16x8 P1_reg = v_setall_s16(cv::saturate_cast<CostType>(P1));
 
-    v_int16x8 leftMinCostP2_reg   = v_setall_s16(cv::saturate_cast<CostType>(leftMinCost+P2));
-    v_int16x8 leftMinCost_new_reg = v_setall_s16(SHRT_MAX);
-    v_int16x8 src0_leftBuf        = v_setall_s16(SHRT_MAX);
-    v_int16x8 src1_leftBuf        = v_load_aligned(leftBuf_prev);
+        v_int16x8 leftMinCostP2_reg   = v_setall_s16(cv::saturate_cast<CostType>(leftMinCost+P2));
+        v_int16x8 leftMinCost_new_reg = v_setall_s16(SHRT_MAX);
+        v_int16x8 src0_leftBuf        = v_setall_s16(SHRT_MAX);
+        v_int16x8 src1_leftBuf        = v_load_aligned(leftBuf_prev);
 
-    v_int16x8 topMinCostP2_reg   = v_setall_s16(cv::saturate_cast<CostType>(topMinCost+P2));
-    v_int16x8 topMinCost_new_reg = v_setall_s16(SHRT_MAX);
-    v_int16x8 src0_topBuf        = v_setall_s16(SHRT_MAX);
-    v_int16x8 src1_topBuf        = v_load_aligned(topBuf);
+        v_int16x8 topMinCostP2_reg   = v_setall_s16(cv::saturate_cast<CostType>(topMinCost+P2));
+        v_int16x8 topMinCost_new_reg = v_setall_s16(SHRT_MAX);
+        v_int16x8 src0_topBuf        = v_setall_s16(SHRT_MAX);
+        v_int16x8 src1_topBuf        = v_load_aligned(topBuf);
 
-    v_int16x8 src2;
-    v_int16x8 src_shifted_left,src_shifted_right;
-    v_int16x8 res;
+        v_int16x8 src2;
+        v_int16x8 src_shifted_left,src_shifted_right;
+        v_int16x8 res;
 
-    for(int i=0;i<D-8;i+=8)
-    {
-        //process leftBuf:
-        //lookahead load:
-        src2 = v_load_aligned(leftBuf_prev+i+8);
+        for(int i=0;i<D-8;i+=8)
+        {
+            //process leftBuf:
+            //lookahead load:
+            src2 = v_load_aligned(leftBuf_prev+i+8);
+
+            //get shifted versions of the current block and add P1:
+            src_shifted_left  = v_extract<7> (src0_leftBuf,src1_leftBuf) + P1_reg;
+            src_shifted_right = v_extract<1> (src1_leftBuf,src2        ) + P1_reg;
+
+            // process and save current block:
+            res = v_load_aligned(costs+i) + (v_min(v_min(src_shifted_left,src_shifted_right),v_min(src1_leftBuf,leftMinCostP2_reg))-leftMinCostP2_reg);
+            leftMinCost_new_reg = v_min(leftMinCost_new_reg,res);
+            v_store_aligned(leftBuf+i, res);
+
+            //update src buffers:
+            src0_leftBuf = src1_leftBuf;
+            src1_leftBuf = src2;
+
+            //process topBuf:
+            //lookahead load:
+            src2 = v_load_aligned(topBuf+i+8);
+
+            //get shifted versions of the current block and add P1:
+            src_shifted_left  = v_extract<7> (src0_topBuf,src1_topBuf) + P1_reg;
+            src_shifted_right = v_extract<1> (src1_topBuf,src2       ) + P1_reg;
+
+            // process and save current block:
+            res = v_load_aligned(costs+i) + (v_min(v_min(src_shifted_left,src_shifted_right),v_min(src1_topBuf,topMinCostP2_reg))-topMinCostP2_reg);
+            topMinCost_new_reg = v_min(topMinCost_new_reg,res);
+            v_store_aligned(topBuf+i, res);
+
+            //update src buffers:
+            src0_topBuf = src1_topBuf;
+            src1_topBuf = src2;
+        }
 
-        //get shifted versions of the current block and add P1:
+        // a bit different processing for the last cycle of the loop:
+        //process leftBuf:
+        src2 = v_setall_s16(SHRT_MAX);
         src_shifted_left  = v_extract<7> (src0_leftBuf,src1_leftBuf) + P1_reg;
         src_shifted_right = v_extract<1> (src1_leftBuf,src2        ) + P1_reg;
 
-        // process and save current block:
-        res = v_load_aligned(costs+i) + (v_min(v_min(src_shifted_left,src_shifted_right),v_min(src1_leftBuf,leftMinCostP2_reg))-leftMinCostP2_reg);
-        leftMinCost_new_reg = v_min(leftMinCost_new_reg,res);
-        v_store_aligned(leftBuf+i, res);
-
-        //update src buffers:
-        src0_leftBuf = src1_leftBuf;
-        src1_leftBuf = src2;
+        res = v_load_aligned(costs+D-8) + (v_min(v_min(src_shifted_left,src_shifted_right),v_min(src1_leftBuf,leftMinCostP2_reg))-leftMinCostP2_reg);
+        leftMinCost = v_reduce_min(v_min(leftMinCost_new_reg,res));
+        v_store_aligned(leftBuf+D-8, res);
 
         //process topBuf:
-        //lookahead load:
-        src2 = v_load_aligned(topBuf+i+8);
-
-        //get shifted versions of the current block and add P1:
+        src2 = v_setall_s16(SHRT_MAX);
         src_shifted_left  = v_extract<7> (src0_topBuf,src1_topBuf) + P1_reg;
         src_shifted_right = v_extract<1> (src1_topBuf,src2       ) + P1_reg;
 
-        // process and save current block:
-        res = v_load_aligned(costs+i) + (v_min(v_min(src_shifted_left,src_shifted_right),v_min(src1_topBuf,topMinCostP2_reg))-topMinCostP2_reg);
-        topMinCost_new_reg = v_min(topMinCost_new_reg,res);
-        v_store_aligned(topBuf+i, res);
-
-        //update src buffers:
-        src0_topBuf = src1_topBuf;
-        src1_topBuf = src2;
+        res = v_load_aligned(costs+D-8) + (v_min(v_min(src_shifted_left,src_shifted_right),v_min(src1_topBuf,topMinCostP2_reg))-topMinCostP2_reg);
+        topMinCost = v_reduce_min(v_min(topMinCost_new_reg,res));
+        v_store_aligned(topBuf+D-8, res);
     }
-
-    // a bit different processing for the last cycle of the loop:
-    //process leftBuf:
-    src2 = v_setall_s16(SHRT_MAX);
-    src_shifted_left  = v_extract<7> (src0_leftBuf,src1_leftBuf) + P1_reg;
-    src_shifted_right = v_extract<1> (src1_leftBuf,src2        ) + P1_reg;
-
-    res = v_load_aligned(costs+D-8) + (v_min(v_min(src_shifted_left,src_shifted_right),v_min(src1_leftBuf,leftMinCostP2_reg))-leftMinCostP2_reg);
-    leftMinCost = min(v_min(leftMinCost_new_reg,res));
-    v_store_aligned(leftBuf+D-8, res);
-
-    //process topBuf:
-    src2 = v_setall_s16(SHRT_MAX);
-    src_shifted_left  = v_extract<7> (src0_topBuf,src1_topBuf) + P1_reg;
-    src_shifted_right = v_extract<1> (src1_topBuf,src2       ) + P1_reg;
-
-    res = v_load_aligned(costs+D-8) + (v_min(v_min(src_shifted_left,src_shifted_right),v_min(src1_topBuf,topMinCostP2_reg))-topMinCostP2_reg);
-    topMinCost = min(v_min(topMinCost_new_reg,res));
-    v_store_aligned(topBuf+D-8, res);
-#else
-    CostType leftMinCost_new = SHRT_MAX;
-    CostType topMinCost_new  = SHRT_MAX;
-    int leftMinCost_P2  = leftMinCost + P2;
-    int topMinCost_P2   = topMinCost  + P2;
-    CostType leftBuf_prev_i_minus_1 = SHRT_MAX;
-    CostType topBuf_i_minus_1       = SHRT_MAX;
-    CostType tmp;
-
-    for(int i=0;i<D-1;i++)
+    else
+#endif
     {
-        leftBuf[i] = cv::saturate_cast<CostType>(costs[i] + std::min(std::min(leftBuf_prev_i_minus_1+P1,leftBuf_prev[i+1]+P1),std::min((int)leftBuf_prev[i],leftMinCost_P2))-leftMinCost_P2);
-        leftBuf_prev_i_minus_1 = leftBuf_prev[i];
-        leftMinCost_new = std::min(leftMinCost_new,leftBuf[i]);
-
-        tmp = topBuf[i];
-        topBuf[i]  = cv::saturate_cast<CostType>(costs[i] + std::min(std::min(topBuf_i_minus_1+P1,topBuf[i+1]+P1),std::min((int)topBuf[i],topMinCost_P2))-topMinCost_P2);
-        topBuf_i_minus_1 = tmp;
-        topMinCost_new  = std::min(topMinCost_new,topBuf[i]);
-    }
+        CostType leftMinCost_new = SHRT_MAX;
+        CostType topMinCost_new  = SHRT_MAX;
+        int leftMinCost_P2  = leftMinCost + P2;
+        int topMinCost_P2   = topMinCost  + P2;
+        CostType leftBuf_prev_i_minus_1 = SHRT_MAX;
+        CostType topBuf_i_minus_1       = SHRT_MAX;
+        CostType tmp;
+
+        for(int i=0;i<D-1;i++)
+        {
+            leftBuf[i] = cv::saturate_cast<CostType>(costs[i] + std::min(std::min(leftBuf_prev_i_minus_1+P1,leftBuf_prev[i+1]+P1),std::min((int)leftBuf_prev[i],leftMinCost_P2))-leftMinCost_P2);
+            leftBuf_prev_i_minus_1 = leftBuf_prev[i];
+            leftMinCost_new = std::min(leftMinCost_new,leftBuf[i]);
+
+            tmp = topBuf[i];
+            topBuf[i]  = cv::saturate_cast<CostType>(costs[i] + std::min(std::min(topBuf_i_minus_1+P1,topBuf[i+1]+P1),std::min((int)topBuf[i],topMinCost_P2))-topMinCost_P2);
+            topBuf_i_minus_1 = tmp;
+            topMinCost_new  = std::min(topMinCost_new,topBuf[i]);
+        }
 
-    leftBuf[D-1] = cv::saturate_cast<CostType>(costs[D-1] + std::min(leftBuf_prev_i_minus_1+P1,std::min((int)leftBuf_prev[D-1],leftMinCost_P2))-leftMinCost_P2);
-    leftMinCost = std::min(leftMinCost_new,leftBuf[D-1]);
+        leftBuf[D-1] = cv::saturate_cast<CostType>(costs[D-1] + std::min(leftBuf_prev_i_minus_1+P1,std::min((int)leftBuf_prev[D-1],leftMinCost_P2))-leftMinCost_P2);
+        leftMinCost = std::min(leftMinCost_new,leftBuf[D-1]);
 
-    topBuf[D-1]  = cv::saturate_cast<CostType>(costs[D-1] + std::min(topBuf_i_minus_1+P1,std::min((int)topBuf[D-1],topMinCost_P2))-topMinCost_P2);
-    topMinCost  = std::min(topMinCost_new,topBuf[D-1]);
-#endif
+        topBuf[D-1]  = cv::saturate_cast<CostType>(costs[D-1] + std::min(topBuf_i_minus_1+P1,std::min((int)topBuf[D-1],topMinCost_P2))-topMinCost_P2);
+        topMinCost  = std::min(topMinCost_new,topBuf[D-1]);
+    }
 }
 
 // performing in-place SGM cost accumulation from right to left (the result is stored in rightBuf) and
@@ -1163,96 +1166,101 @@ inline void accumulateCostsRight(CostType* rightBuf, CostType* topBuf, CostType*
                                  CostType& rightMinCost, int D, int P1, int P2, int& optimal_disp, CostType& min_cost)
 {
 #if CV_SIMD128
-    v_int16x8 P1_reg = v_setall_s16(cv::saturate_cast<CostType>(P1));
+    if(hasSIMD128())
+    {
+        v_int16x8 P1_reg = v_setall_s16(cv::saturate_cast<CostType>(P1));
 
-    v_int16x8 rightMinCostP2_reg   = v_setall_s16(cv::saturate_cast<CostType>(rightMinCost+P2));
-    v_int16x8 rightMinCost_new_reg = v_setall_s16(SHRT_MAX);
-    v_int16x8 src0_rightBuf        = v_setall_s16(SHRT_MAX);
-    v_int16x8 src1_rightBuf        = v_load(rightBuf);
+        v_int16x8 rightMinCostP2_reg   = v_setall_s16(cv::saturate_cast<CostType>(rightMinCost+P2));
+        v_int16x8 rightMinCost_new_reg = v_setall_s16(SHRT_MAX);
+        v_int16x8 src0_rightBuf        = v_setall_s16(SHRT_MAX);
+        v_int16x8 src1_rightBuf        = v_load(rightBuf);
 
-    v_int16x8 src2;
-    v_int16x8 src_shifted_left,src_shifted_right;
-    v_int16x8 res;
+        v_int16x8 src2;
+        v_int16x8 src_shifted_left,src_shifted_right;
+        v_int16x8 res;
 
-    v_int16x8 min_sum_cost_reg = v_setall_s16(SHRT_MAX);
-    v_int16x8 min_sum_pos_reg  = v_setall_s16(0);
-    v_int16x8 loop_idx(0,1,2,3,4,5,6,7);
-    v_int16x8 eight_reg = v_setall_s16(8);
+        v_int16x8 min_sum_cost_reg = v_setall_s16(SHRT_MAX);
+        v_int16x8 min_sum_pos_reg  = v_setall_s16(0);
+        v_int16x8 loop_idx(0,1,2,3,4,5,6,7);
+        v_int16x8 eight_reg = v_setall_s16(8);
 
-    for(int i=0;i<D-8;i+=8)
-    {
-        //lookahead load:
-        src2 = v_load_aligned(rightBuf+i+8);
+        for(int i=0;i<D-8;i+=8)
+        {
+            //lookahead load:
+            src2 = v_load_aligned(rightBuf+i+8);
+
+            //get shifted versions of the current block and add P1:
+            src_shifted_left  = v_extract<7> (src0_rightBuf,src1_rightBuf) + P1_reg;
+            src_shifted_right = v_extract<1> (src1_rightBuf,src2         ) + P1_reg;
+
+            // process and save current block:
+            res = v_load_aligned(costs+i) + (v_min(v_min(src_shifted_left,src_shifted_right),v_min(src1_rightBuf,rightMinCostP2_reg))-rightMinCostP2_reg);
+            rightMinCost_new_reg = v_min(rightMinCost_new_reg,res);
+            v_store_aligned(rightBuf+i, res);
+
+            // compute and save total cost:
+            res = res + v_load_aligned(leftBuf+i) + v_load_aligned(topBuf+i);
+            v_store_aligned(leftBuf+i, res);
+
+            // track disparity value with the minimum cost:
+            min_sum_cost_reg = v_min(min_sum_cost_reg,res);
+            min_sum_pos_reg = min_sum_pos_reg + ((min_sum_cost_reg == res) & (loop_idx - min_sum_pos_reg));
+            loop_idx = loop_idx+eight_reg;
+
+            //update src:
+            src0_rightBuf    = src1_rightBuf;
+            src1_rightBuf    = src2;
+        }
 
-        //get shifted versions of the current block and add P1:
+        // a bit different processing for the last cycle of the loop:
+        src2 = v_setall_s16(SHRT_MAX);
         src_shifted_left  = v_extract<7> (src0_rightBuf,src1_rightBuf) + P1_reg;
         src_shifted_right = v_extract<1> (src1_rightBuf,src2         ) + P1_reg;
 
-        // process and save current block:
-        res = v_load_aligned(costs+i) + (v_min(v_min(src_shifted_left,src_shifted_right),v_min(src1_rightBuf,rightMinCostP2_reg))-rightMinCostP2_reg);
-        rightMinCost_new_reg = v_min(rightMinCost_new_reg,res);
-        v_store_aligned(rightBuf+i, res);
+        res = v_load_aligned(costs+D-8) + (v_min(v_min(src_shifted_left,src_shifted_right),v_min(src1_rightBuf,rightMinCostP2_reg))-rightMinCostP2_reg);
+        rightMinCost = v_reduce_min(v_min(rightMinCost_new_reg,res));
+        v_store_aligned(rightBuf+D-8, res);
 
-        // compute and save total cost:
-        res = res + v_load_aligned(leftBuf+i) + v_load_aligned(topBuf+i);
-        v_store_aligned(leftBuf+i, res);
+        res = res + v_load_aligned(leftBuf+D-8) + v_load_aligned(topBuf+D-8);
+        v_store_aligned(leftBuf+D-8, res);
 
-        // track disparity value with the minimum cost:
         min_sum_cost_reg = v_min(min_sum_cost_reg,res);
+        min_cost = v_reduce_min(min_sum_cost_reg);
         min_sum_pos_reg = min_sum_pos_reg + ((min_sum_cost_reg == res) & (loop_idx - min_sum_pos_reg));
-        loop_idx = loop_idx+eight_reg;
-
-        //update src:
-        src0_rightBuf    = src1_rightBuf;
-        src1_rightBuf    = src2;
+        optimal_disp = min_pos(min_sum_cost_reg,min_sum_pos_reg, min_cost);
     }
-
-    // a bit different processing for the last cycle of the loop:
-    src2 = v_setall_s16(SHRT_MAX);
-    src_shifted_left  = v_extract<7> (src0_rightBuf,src1_rightBuf) + P1_reg;
-    src_shifted_right = v_extract<1> (src1_rightBuf,src2         ) + P1_reg;
-
-    res = v_load_aligned(costs+D-8) + (v_min(v_min(src_shifted_left,src_shifted_right),v_min(src1_rightBuf,rightMinCostP2_reg))-rightMinCostP2_reg);
-    rightMinCost = min(v_min(rightMinCost_new_reg,res));
-    v_store_aligned(rightBuf+D-8, res);
-
-    res = res + v_load_aligned(leftBuf+D-8) + v_load_aligned(topBuf+D-8);
-    v_store_aligned(leftBuf+D-8, res);
-
-    min_sum_cost_reg = v_min(min_sum_cost_reg,res);
-    min_cost = min(min_sum_cost_reg);
-    min_sum_pos_reg = min_sum_pos_reg + ((min_sum_cost_reg == res) & (loop_idx - min_sum_pos_reg));
-    optimal_disp = min_pos(min_sum_cost_reg,min_sum_pos_reg);
-#else
-    CostType rightMinCost_new = SHRT_MAX;
-    int rightMinCost_P2  = rightMinCost + P2;
-    CostType rightBuf_i_minus_1 = SHRT_MAX;
-    CostType tmp;
-    min_cost = SHRT_MAX;
-
-    for(int i=0;i<D-1;i++)
+    else
+#endif
     {
-        tmp = rightBuf[i];
-        rightBuf[i]  = cv::saturate_cast<CostType>(costs[i] + std::min(std::min(rightBuf_i_minus_1+P1,rightBuf[i+1]+P1),std::min((int)rightBuf[i],rightMinCost_P2))-rightMinCost_P2);
-        rightBuf_i_minus_1 = tmp;
-        rightMinCost_new  = std::min(rightMinCost_new,rightBuf[i]);
-        leftBuf[i] = cv::saturate_cast<CostType>((int)leftBuf[i]+rightBuf[i]+topBuf[i]);
-        if(leftBuf[i]<min_cost)
+        CostType rightMinCost_new = SHRT_MAX;
+        int rightMinCost_P2  = rightMinCost + P2;
+        CostType rightBuf_i_minus_1 = SHRT_MAX;
+        CostType tmp;
+        min_cost = SHRT_MAX;
+
+        for(int i=0;i<D-1;i++)
         {
-            optimal_disp = i;
-            min_cost = leftBuf[i];
+            tmp = rightBuf[i];
+            rightBuf[i]  = cv::saturate_cast<CostType>(costs[i] + std::min(std::min(rightBuf_i_minus_1+P1,rightBuf[i+1]+P1),std::min((int)rightBuf[i],rightMinCost_P2))-rightMinCost_P2);
+            rightBuf_i_minus_1 = tmp;
+            rightMinCost_new  = std::min(rightMinCost_new,rightBuf[i]);
+            leftBuf[i] = cv::saturate_cast<CostType>((int)leftBuf[i]+rightBuf[i]+topBuf[i]);
+            if(leftBuf[i]<min_cost)
+            {
+                optimal_disp = i;
+                min_cost = leftBuf[i];
+            }
         }
-    }
 
-    rightBuf[D-1]  = cv::saturate_cast<CostType>(costs[D-1] + std::min(rightBuf_i_minus_1+P1,std::min((int)rightBuf[D-1],rightMinCost_P2))-rightMinCost_P2);
-    rightMinCost  = std::min(rightMinCost_new,rightBuf[D-1]);
-    leftBuf[D-1] = cv::saturate_cast<CostType>((int)leftBuf[D-1]+rightBuf[D-1]+topBuf[D-1]);
-    if(leftBuf[D-1]<min_cost)
-    {
-        optimal_disp = D-1;
-        min_cost = leftBuf[D-1];
+        rightBuf[D-1]  = cv::saturate_cast<CostType>(costs[D-1] + std::min(rightBuf_i_minus_1+P1,std::min((int)rightBuf[D-1],rightMinCost_P2))-rightMinCost_P2);
+        rightMinCost  = std::min(rightMinCost_new,rightBuf[D-1]);
+        leftBuf[D-1] = cv::saturate_cast<CostType>((int)leftBuf[D-1]+rightBuf[D-1]+topBuf[D-1]);
+        if(leftBuf[D-1]<min_cost)
+        {
+            optimal_disp = D-1;
+            min_cost = leftBuf[D-1];
+        }
     }
-#endif
 }
 
 void SGBM3WayMainLoop::operator () (const Range& range) const
@@ -1324,42 +1332,47 @@ void SGBM3WayMainLoop::operator () (const Range& range) const
             if(uniquenessRatio>0)
             {
 #if CV_SIMD128
-                horPassCostVolume+=x;
-                int thresh = (100*min_cost)/(100-uniquenessRatio);
-                v_int16x8 thresh_reg = v_setall_s16((short)(thresh+1));
-                v_int16x8 d1 = v_setall_s16((short)(best_d-1));
-                v_int16x8 d2 = v_setall_s16((short)(best_d+1));
-                v_int16x8 eight_reg = v_setall_s16(8);
-                v_int16x8 cur_d(0,1,2,3,4,5,6,7);
-                v_int16x8 mask,cost1,cost2;
-
-                for( d = 0; d < D; d+=16 )
+                if(useSIMD)
                 {
-                    cost1 = v_load_aligned(horPassCostVolume+d);
-                    cost2 = v_load_aligned(horPassCostVolume+d+8);
+                    horPassCostVolume+=x;
+                    int thresh = (100*min_cost)/(100-uniquenessRatio);
+                    v_int16x8 thresh_reg = v_setall_s16((short)(thresh+1));
+                    v_int16x8 d1 = v_setall_s16((short)(best_d-1));
+                    v_int16x8 d2 = v_setall_s16((short)(best_d+1));
+                    v_int16x8 eight_reg = v_setall_s16(8);
+                    v_int16x8 cur_d(0,1,2,3,4,5,6,7);
+                    v_int16x8 mask,cost1,cost2;
+
+                    for( d = 0; d < D; d+=16 )
+                    {
+                        cost1 = v_load_aligned(horPassCostVolume+d);
+                        cost2 = v_load_aligned(horPassCostVolume+d+8);
 
-                    mask = cost1 < thresh_reg;
-                    mask = mask & ( (cur_d<d1) | (cur_d>d2) );
-                    if( v_signmask(mask) )
-                        break;
+                        mask = cost1 < thresh_reg;
+                        mask = mask & ( (cur_d<d1) | (cur_d>d2) );
+                        if( v_signmask(mask) )
+                            break;
 
-                    cur_d = cur_d+eight_reg;
+                        cur_d = cur_d+eight_reg;
 
-                    mask = cost2 < thresh_reg;
-                    mask = mask & ( (cur_d<d1) | (cur_d>d2) );
-                    if( v_signmask(mask) )
-                        break;
+                        mask = cost2 < thresh_reg;
+                        mask = mask & ( (cur_d<d1) | (cur_d>d2) );
+                        if( v_signmask(mask) )
+                            break;
 
-                    cur_d = cur_d+eight_reg;
+                        cur_d = cur_d+eight_reg;
+                    }
+                    horPassCostVolume-=x;
                 }
-                horPassCostVolume-=x;
-#else
-                for( d = 0; d < D; d++ )
+                else
+#endif
                 {
-                    if( horPassCostVolume[x+d]*(100 - uniquenessRatio) < min_cost*100 && std::abs(d - best_d) > 1 )
-                        break;
+                    for( d = 0; d < D; d++ )
+                    {
+                        if( horPassCostVolume[x+d]*(100 - uniquenessRatio) < min_cost*100 && std::abs(d - best_d) > 1 )
+                            break;
+                    }
                 }
-#endif
                 if( d < D )
                     continue;
             }
@@ -1458,6 +1471,8 @@ public:
 
     void compute( InputArray leftarr, InputArray rightarr, OutputArray disparr )
     {
+        CV_INSTRUMENT_REGION()
+
         Mat left = leftarr.getMat(), right = rightarr.getMat();
         CV_Assert( left.size() == right.size() && left.type() == right.type() &&
                    left.depth() == CV_8U );
@@ -1512,6 +1527,7 @@ public:
 
     void write(FileStorage& fs) const
     {
+        writeFormat(fs);
         fs << "name" << name_
         << "minDisparity" << params.minDisparity
         << "numDisparities" << params.numDisparities
@@ -1691,6 +1707,8 @@ void filterSpecklesImpl(cv::Mat& img, int newVal, int maxSpeckleSize, int maxDif
 #ifdef HAVE_IPP
 static bool ipp_filterSpeckles(Mat &img, int maxSpeckleSize, int newVal, int maxDiff)
 {
+    CV_INSTRUMENT_REGION_IPP()
+
 #if IPP_VERSION_X100 >= 810
     int type = img.type();
     Ipp32s bufsize = 0;
@@ -1708,12 +1726,12 @@ static bool ipp_filterSpeckles(Mat &img, int maxSpeckleSize, int newVal, int max
 
     if (type == CV_8UC1)
     {
-        status = ippiMarkSpeckles_8u_C1IR(img.ptr<Ipp8u>(), (int)img.step, roisize,
+        status = CV_INSTRUMENT_FUN_IPP(ippiMarkSpeckles_8u_C1IR, img.ptr<Ipp8u>(), (int)img.step, roisize,
                                             (Ipp8u)newVal, maxSpeckleSize, (Ipp8u)maxDiff, ippiNormL1, pBuffer);
     }
     else
     {
-        status = ippiMarkSpeckles_16s_C1IR(img.ptr<Ipp16s>(), (int)img.step, roisize,
+        status = CV_INSTRUMENT_FUN_IPP(ippiMarkSpeckles_16s_C1IR, img.ptr<Ipp16s>(), (int)img.step, roisize,
                                             (Ipp16s)newVal, maxSpeckleSize, (Ipp16s)maxDiff, ippiNormL1, pBuffer);
     }
     if(pBuffer) ippFree(pBuffer);
@@ -1732,6 +1750,8 @@ static bool ipp_filterSpeckles(Mat &img, int maxSpeckleSize, int newVal, int max
 void cv::filterSpeckles( InputOutputArray _img, double _newval, int maxSpeckleSize,
                          double _maxDiff, InputOutputArray __buf )
 {
+    CV_INSTRUMENT_REGION()
+
     Mat img = _img.getMat();
     int type = img.type();
     Mat temp, &_buf = __buf.needed() ? __buf.getMatRef() : temp;
@@ -1750,6 +1770,8 @@ void cv::filterSpeckles( InputOutputArray _img, double _newval, int maxSpeckleSi
 void cv::validateDisparity( InputOutputArray _disp, InputArray _cost, int minDisparity,
                             int numberOfDisparities, int disp12MaxDiff )
 {
+    CV_INSTRUMENT_REGION()
+
     Mat disp = _disp.getMat(), cost = _cost.getMat();
     int cols = disp.cols, rows = disp.rows;
     int minD = minDisparity, maxD = minDisparity + numberOfDisparities;
diff --git a/modules/calib3d/src/triangulate.cpp b/modules/calib3d/src/triangulate.cpp
index 0fa5e3d..33c7fd7 100644
--- a/modules/calib3d/src/triangulate.cpp
+++ b/modules/calib3d/src/triangulate.cpp
@@ -393,6 +393,8 @@ void cv::triangulatePoints( InputArray _projMatr1, InputArray _projMatr2,
                             InputArray _projPoints1, InputArray _projPoints2,
                             OutputArray _points4D )
 {
+    CV_INSTRUMENT_REGION()
+
     Mat matr1 = _projMatr1.getMat(), matr2 = _projMatr2.getMat();
     Mat points1 = _projPoints1.getMat(), points2 = _projPoints2.getMat();
 
@@ -414,6 +416,8 @@ void cv::triangulatePoints( InputArray _projMatr1, InputArray _projMatr2,
 void cv::correctMatches( InputArray _F, InputArray _points1, InputArray _points2,
                          OutputArray _newPoints1, OutputArray _newPoints2 )
 {
+    CV_INSTRUMENT_REGION()
+
     Mat F = _F.getMat();
     Mat points1 = _points1.getMat(), points2 = _points2.getMat();
 
diff --git a/modules/calib3d/test/test_affine2d_estimator.cpp b/modules/calib3d/test/test_affine2d_estimator.cpp
new file mode 100644
index 0000000..de9f700
--- /dev/null
+++ b/modules/calib3d/test/test_affine2d_estimator.cpp
@@ -0,0 +1,130 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+//                           License Agreement
+//                For Open Source Computer Vision Library
+//                        (3-clause BSD License)
+//
+// Copyright (C) 2015-2016, OpenCV Foundation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+//   * Redistributions of source code must retain the above copyright notice,
+//     this list of conditions and the following disclaimer.
+//
+//   * Redistributions in binary form must reproduce the above copyright notice,
+//     this list of conditions and the following disclaimer in the documentation
+//     and/or other materials provided with the distribution.
+//
+//   * Neither the names of the copyright holders nor the names of the contributors
+//     may be used to endorse or promote products derived from this software
+//     without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall copyright holders or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "test_precomp.hpp"
+
+using namespace cv;
+using namespace std;
+using namespace testing;
+
+#include <vector>
+#include <numeric>
+
+CV_ENUM(Method, RANSAC, LMEDS)
+typedef TestWithParam<Method> EstimateAffine2D;
+
+static float rngIn(float from, float to) { return from + (to-from) * (float)theRNG(); }
+
+TEST_P(EstimateAffine2D, test3Points)
+{
+    // try more transformations
+    for (size_t i = 0; i < 500; ++i)
+    {
+        Mat aff(2, 3, CV_64F);
+        cv::randu(aff, 1., 3.);
+
+        Mat fpts(1, 3, CV_32FC2);
+        Mat tpts(1, 3, CV_32FC2);
+
+        // setting points that are not in the same line
+        fpts.at<Point2f>(0) = Point2f( rngIn(1,2), rngIn(5,6) );
+        fpts.at<Point2f>(1) = Point2f( rngIn(3,4), rngIn(3,4) );
+        fpts.at<Point2f>(2) = Point2f( rngIn(1,2), rngIn(3,4) );
+
+        transform(fpts, tpts, aff);
+
+        vector<uchar> inliers;
+        Mat aff_est = estimateAffine2D(fpts, tpts, inliers, GetParam() /* method */);
+
+        EXPECT_NEAR(0., cvtest::norm(aff_est, aff, NORM_INF), 1e-3);
+
+        // all must be inliers
+        EXPECT_EQ(countNonZero(inliers), 3);
+    }
+}
+
+TEST_P(EstimateAffine2D, testNPoints)
+{
+    // try more transformations
+    for (size_t i = 0; i < 500; ++i)
+    {
+        Mat aff(2, 3, CV_64F);
+        cv::randu(aff, -2., 2.);
+        const int method = GetParam();
+        const int n = 100;
+        int m;
+        // LMEDS can't handle more than 50% outliers (by design)
+        if (method == LMEDS)
+            m = 3*n/5;
+        else
+            m = 2*n/5;
+        const float shift_outl = 15.f;
+        const float noise_level = 20.f;
+
+        Mat fpts(1, n, CV_32FC2);
+        Mat tpts(1, n, CV_32FC2);
+
+        randu(fpts, 0., 100.);
+        transform(fpts, tpts, aff);
+
+        /* adding noise to some points */
+        Mat outliers = tpts.colRange(m, n);
+        outliers.reshape(1) += shift_outl;
+
+        Mat noise (outliers.size(), outliers.type());
+        randu(noise, 0., noise_level);
+        outliers += noise;
+
+        vector<uchar> inliers;
+        Mat aff_est = estimateAffine2D(fpts, tpts, inliers, method);
+
+        EXPECT_FALSE(aff_est.empty()) << "estimation failed, unable to estimate transform";
+
+        EXPECT_NEAR(0., cvtest::norm(aff_est, aff, NORM_INF), 1e-4);
+
+        bool inliers_good = count(inliers.begin(), inliers.end(), 1) == m &&
+            m == accumulate(inliers.begin(), inliers.begin() + m, 0);
+
+        EXPECT_TRUE(inliers_good);
+    }
+}
+
+INSTANTIATE_TEST_CASE_P(Calib3d, EstimateAffine2D, Method::all());
diff --git a/modules/calib3d/test/test_affine3d_estimator.cpp b/modules/calib3d/test/test_affine3d_estimator.cpp
index 2608815..aa41bf3 100644
--- a/modules/calib3d/test/test_affine3d_estimator.cpp
+++ b/modules/calib3d/test/test_affine3d_estimator.cpp
@@ -194,4 +194,4 @@ void CV_Affine3D_EstTest::run( int /* start_from */)
     ts->set_failed_test_info(cvtest::TS::OK);
 }
 
-TEST(Calib3d_EstimateAffineTransform, accuracy) { CV_Affine3D_EstTest test; test.safe_run(); }
+TEST(Calib3d_EstimateAffine3D, accuracy) { CV_Affine3D_EstTest test; test.safe_run(); }
diff --git a/modules/calib3d/test/test_affine_partial2d_estimator.cpp b/modules/calib3d/test/test_affine_partial2d_estimator.cpp
new file mode 100644
index 0000000..dde7d7d
--- /dev/null
+++ b/modules/calib3d/test/test_affine_partial2d_estimator.cpp
@@ -0,0 +1,140 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+//                           License Agreement
+//                For Open Source Computer Vision Library
+//                        (3-clause BSD License)
+//
+// Copyright (C) 2015-2016, OpenCV Foundation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+//   * Redistributions of source code must retain the above copyright notice,
+//     this list of conditions and the following disclaimer.
+//
+//   * Redistributions in binary form must reproduce the above copyright notice,
+//     this list of conditions and the following disclaimer in the documentation
+//     and/or other materials provided with the distribution.
+//
+//   * Neither the names of the copyright holders nor the names of the contributors
+//     may be used to endorse or promote products derived from this software
+//     without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall copyright holders or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "test_precomp.hpp"
+
+using namespace cv;
+using namespace std;
+using namespace testing;
+
+#include <vector>
+#include <numeric>
+
+CV_ENUM(Method, RANSAC, LMEDS)
+typedef TestWithParam<Method> EstimateAffinePartial2D;
+
+static float rngIn(float from, float to) { return from + (to-from) * (float)theRNG(); }
+
+// get random matrix of affine transformation limited to combinations of translation,
+// rotation, and uniform scaling
+static Mat rngPartialAffMat() {
+    double theta = rngIn(0, (float)CV_PI*2.f);
+    double scale = rngIn(0, 3);
+    double tx = rngIn(-2, 2);
+    double ty = rngIn(-2, 2);
+    double aff[2*3] = { std::cos(theta) * scale, -std::sin(theta) * scale, tx,
+                        std::sin(theta) * scale,  std::cos(theta) * scale, ty };
+    return Mat(2, 3, CV_64F, aff).clone();
+}
+
+TEST_P(EstimateAffinePartial2D, test2Points)
+{
+    // try more transformations
+    for (size_t i = 0; i < 500; ++i)
+    {
+        Mat aff = rngPartialAffMat();
+
+        // setting points that are no in the same line
+        Mat fpts(1, 2, CV_32FC2);
+        Mat tpts(1, 2, CV_32FC2);
+
+        fpts.at<Point2f>(0) = Point2f( rngIn(1,2), rngIn(5,6) );
+        fpts.at<Point2f>(1) = Point2f( rngIn(3,4), rngIn(3,4) );
+
+        transform(fpts, tpts, aff);
+
+        vector<uchar> inliers;
+        Mat aff_est = estimateAffinePartial2D(fpts, tpts, inliers, GetParam() /* method */);
+
+        EXPECT_NEAR(0., cvtest::norm(aff_est, aff, NORM_INF), 1e-3);
+
+        // all must be inliers
+        EXPECT_EQ(countNonZero(inliers), 2);
+    }
+}
+
+TEST_P(EstimateAffinePartial2D, testNPoints)
+{
+    // try more transformations
+    for (size_t i = 0; i < 500; ++i)
+    {
+        Mat aff = rngPartialAffMat();
+
+        const int method = GetParam();
+        const int n = 100;
+        int m;
+        // LMEDS can't handle more than 50% outliers (by design)
+        if (method == LMEDS)
+            m = 3*n/5;
+        else
+            m = 2*n/5;
+        const float shift_outl = 15.f;
+        const float noise_level = 20.f;
+
+        Mat fpts(1, n, CV_32FC2);
+        Mat tpts(1, n, CV_32FC2);
+
+        randu(fpts, 0., 100.);
+        transform(fpts, tpts, aff);
+
+        /* adding noise to some points */
+        Mat outliers = tpts.colRange(m, n);
+        outliers.reshape(1) += shift_outl;
+
+        Mat noise (outliers.size(), outliers.type());
+        randu(noise, 0., noise_level);
+        outliers += noise;
+
+        vector<uchar> inliers;
+        Mat aff_est = estimateAffinePartial2D(fpts, tpts, inliers, method);
+
+        EXPECT_FALSE(aff_est.empty());
+
+        EXPECT_NEAR(0., cvtest::norm(aff_est, aff, NORM_INF), 1e-4);
+
+        bool inliers_good = count(inliers.begin(), inliers.end(), 1) == m &&
+            m == accumulate(inliers.begin(), inliers.begin() + m, 0);
+
+        EXPECT_TRUE(inliers_good);
+    }
+}
+
+INSTANTIATE_TEST_CASE_P(Calib3d, EstimateAffinePartial2D, Method::all());
diff --git a/modules/calib3d/test/test_cameracalibration.cpp b/modules/calib3d/test/test_cameracalibration.cpp
index 2053e06..0f07405 100644
--- a/modules/calib3d/test/test_cameracalibration.cpp
+++ b/modules/calib3d/test/test_cameracalibration.cpp
@@ -259,7 +259,7 @@ protected:
     virtual void calibrate( int imageCount, int* pointCounts,
         CvSize imageSize, CvPoint2D64f* imagePoints, CvPoint3D64f* objectPoints,
         double* distortionCoeffs, double* cameraMatrix, double* translationVectors,
-        double* rotationMatrices, int flags ) = 0;
+        double* rotationMatrices, double *stdDevs, double* perViewErrors, int flags ) = 0;
     virtual void project( int pointCount, CvPoint3D64f* objectPoints,
         double* rotationMatrix, double*  translationVector,
         double* cameraMatrix, double* distortion, CvPoint2D64f* imagePoints ) = 0;
@@ -303,9 +303,13 @@ void CV_CameraCalibrationTest::run( int start_from )
 
     double*       transVects;
     double*       rotMatrs;
+    double*       stdDevs;
+    double*       perViewErrors;
 
     double*       goodTransVects;
     double*       goodRotMatrs;
+    double*       goodPerViewErrors;
+    double*       goodStdDevs;
 
     double          cameraMatrix[3*3];
     double          distortion[5]={0,0,0,0,0};
@@ -424,9 +428,13 @@ void CV_CameraCalibrationTest::run( int start_from )
         /* Allocate memory for translate vectors and rotmatrixs*/
         transVects     = (double*)cvAlloc(3 * 1 * numImages * sizeof(double));
         rotMatrs       = (double*)cvAlloc(3 * 3 * numImages * sizeof(double));
+        stdDevs        = (double*)cvAlloc((CV_CALIB_NINTRINSIC + 6*numImages) * sizeof(double));
+        perViewErrors  = (double*)cvAlloc(numImages * sizeof(double));
 
         goodTransVects = (double*)cvAlloc(3 * 1 * numImages * sizeof(double));
         goodRotMatrs   = (double*)cvAlloc(3 * 3 * numImages * sizeof(double));
+        goodPerViewErrors  = (double*)cvAlloc(numImages * sizeof(double));
+        goodStdDevs = (double*)cvAlloc((CV_CALIB_NINTRINSIC + 6*numImages) * sizeof(double));
 
         /* Read object points */
         i = 0;/* shift for current point */
@@ -501,6 +509,13 @@ void CV_CameraCalibrationTest::run( int start_from )
             }
         }
 
+        /* Read good stdDeviations */
+        for (i = 0; i < CV_CALIB_NINTRINSIC + numImages*6; i++)
+        {
+            values_read = fscanf(file, "%lf", goodStdDevs + i);
+            CV_Assert(values_read == 1);
+        }
+
         calibFlags = 0
                      // + CV_CALIB_FIX_PRINCIPAL_POINT
                      // + CV_CALIB_ZERO_TANGENT_DIST
@@ -526,6 +541,8 @@ void CV_CameraCalibrationTest::run( int start_from )
                     cameraMatrix,
                     transVects,
                     rotMatrs,
+                    stdDevs,
+                    perViewErrors,
                     calibFlags );
 
         /* ---- Reproject points to the image ---- */
@@ -553,6 +570,8 @@ void CV_CameraCalibrationTest::run( int start_from )
         meanDy = 0;
         for( currImage = 0; currImage < numImages; currImage++ )
         {
+            double imageMeanDx = 0;
+            double imageMeanDy = 0;
             for( currPoint = 0; currPoint < etalonSize.width * etalonSize.height; currPoint++ )
             {
                 rx = reprojectPoints[i].x;
@@ -563,6 +582,9 @@ void CV_CameraCalibrationTest::run( int start_from )
                 meanDx += dx;
                 meanDy += dy;
 
+                imageMeanDx += dx*dx;
+                imageMeanDy += dy*dy;
+
                 dx = fabs(dx);
                 dy = fabs(dy);
 
@@ -573,6 +595,13 @@ void CV_CameraCalibrationTest::run( int start_from )
                     maxDy = dy;
                 i++;
             }
+            goodPerViewErrors[currImage] = sqrt( (imageMeanDx + imageMeanDy) /
+                                           (etalonSize.width * etalonSize.height));
+
+            //only for c-version of test (it does not provides evaluation of perViewErrors
+            //and returns zeros)
+            if(perViewErrors[currImage] == 0.0)
+                perViewErrors[currImage] = goodPerViewErrors[currImage];
         }
 
         meanDx /= numImages * etalonSize.width * etalonSize.height;
@@ -613,6 +642,23 @@ void CV_CameraCalibrationTest::run( int start_from )
         if( code < 0 )
             goto _exit_;
 
+        /* ----- Compare per view re-projection errors ----- */
+        code = compare(perViewErrors,goodPerViewErrors, numImages,0.1,"per view errors vector");
+        if( code < 0 )
+            goto _exit_;
+
+        /* ----- Compare standard deviations of parameters ----- */
+        //only for c-version of test (it does not provides evaluation of stdDevs
+        //and returns zeros)
+        for ( i = 0; i < CV_CALIB_NINTRINSIC + 6*numImages; i++)
+        {
+            if(stdDevs[i] == 0.0)
+                stdDevs[i] = goodStdDevs[i];
+        }
+        code = compare(stdDevs,goodStdDevs, CV_CALIB_NINTRINSIC + 6*numImages,.5,"stdDevs vector");
+        if( code < 0 )
+            goto _exit_;
+
         if( maxDx > 1.0 )
         {
             ts->printf( cvtest::TS::LOG,
@@ -636,8 +682,12 @@ void CV_CameraCalibrationTest::run( int start_from )
 
         cvFree(&transVects);
         cvFree(&rotMatrs);
+        cvFree(&stdDevs);
+        cvFree(&perViewErrors);
         cvFree(&goodTransVects);
         cvFree(&goodRotMatrs);
+        cvFree(&goodPerViewErrors);
+        cvFree(&goodStdDevs);
 
         fclose(file);
         file = 0;
@@ -676,20 +726,28 @@ protected:
     virtual void calibrate( int imageCount, int* pointCounts,
         CvSize imageSize, CvPoint2D64f* imagePoints, CvPoint3D64f* objectPoints,
         double* distortionCoeffs, double* cameraMatrix, double* translationVectors,
-        double* rotationMatrices, int flags );
+        double* rotationMatrices, double *stdDevs, double* perViewErrors, int flags );
     virtual void project( int pointCount, CvPoint3D64f* objectPoints,
         double* rotationMatrix, double*  translationVector,
         double* cameraMatrix, double* distortion, CvPoint2D64f* imagePoints );
 };
 
-void CV_CameraCalibrationTest_C::calibrate( int imageCount, int* pointCounts,
+void CV_CameraCalibrationTest_C::calibrate(int imageCount, int* pointCounts,
         CvSize imageSize, CvPoint2D64f* imagePoints, CvPoint3D64f* objectPoints,
         double* distortionCoeffs, double* cameraMatrix, double* translationVectors,
-        double* rotationMatrices, int flags )
+        double* rotationMatrices, double *stdDevs, double *perViewErrors, int flags )
 {
     int i, total = 0;
     for( i = 0; i < imageCount; i++ )
+    {
+        perViewErrors[i] = 0.0;
         total += pointCounts[i];
+    }
+
+    for( i = 0; i < CV_CALIB_NINTRINSIC + imageCount*6; i++)
+    {
+        stdDevs[i] = 0.0;
+    }
 
     CvMat _objectPoints = cvMat(1, total, CV_64FC3, objectPoints);
     CvMat _imagePoints = cvMat(1, total, CV_64FC2, imagePoints);
@@ -700,8 +758,7 @@ void CV_CameraCalibrationTest_C::calibrate( int imageCount, int* pointCounts,
     CvMat _translationVectors = cvMat(imageCount, 3, CV_64F, translationVectors);
 
     cvCalibrateCamera2(&_objectPoints, &_imagePoints, &_pointCounts, imageSize,
-                       &_cameraMatrix, &_distCoeffs, &_rotationMatrices, &_translationVectors,
-                       flags);
+                       &_cameraMatrix, &_distCoeffs, &_rotationMatrices, &_translationVectors, flags);
 }
 
 void CV_CameraCalibrationTest_C::project( int pointCount, CvPoint3D64f* objectPoints,
@@ -728,22 +785,24 @@ protected:
     virtual void calibrate( int imageCount, int* pointCounts,
         CvSize imageSize, CvPoint2D64f* imagePoints, CvPoint3D64f* objectPoints,
         double* distortionCoeffs, double* cameraMatrix, double* translationVectors,
-        double* rotationMatrices, int flags );
+        double* rotationMatrices, double *stdDevs, double* perViewErrors,  int flags );
     virtual void project( int pointCount, CvPoint3D64f* objectPoints,
         double* rotationMatrix, double*  translationVector,
         double* cameraMatrix, double* distortion, CvPoint2D64f* imagePoints );
 };
 
-void CV_CameraCalibrationTest_CPP::calibrate( int imageCount, int* pointCounts,
+void CV_CameraCalibrationTest_CPP::calibrate(int imageCount, int* pointCounts,
         CvSize _imageSize, CvPoint2D64f* _imagePoints, CvPoint3D64f* _objectPoints,
         double* _distortionCoeffs, double* _cameraMatrix, double* translationVectors,
-        double* rotationMatrices, int flags )
+        double* rotationMatrices, double *stdDevs, double *perViewErrors, int flags )
 {
     vector<vector<Point3f> > objectPoints( imageCount );
     vector<vector<Point2f> > imagePoints( imageCount );
     Size imageSize = _imageSize;
     Mat cameraMatrix, distCoeffs(1,4,CV_64F,Scalar::all(0));
     vector<Mat> rvecs, tvecs;
+    Mat stdDevsMatInt, stdDevsMatExt;
+    Mat perViewErrorsMat;
 
     CvPoint3D64f* op = _objectPoints;
     CvPoint2D64f* ip = _imagePoints;
@@ -770,8 +829,23 @@ void CV_CameraCalibrationTest_CPP::calibrate( int imageCount, int* pointCounts,
                      distCoeffs,
                      rvecs,
                      tvecs,
+                     stdDevsMatInt,
+                     stdDevsMatExt,
+                     perViewErrorsMat,
                      flags );
 
+    assert( stdDevsMatInt.type() == CV_64F );
+    assert( stdDevsMatInt.total() == static_cast<size_t>(CV_CALIB_NINTRINSIC) );
+    memcpy( stdDevs, stdDevsMatInt.ptr(), CV_CALIB_NINTRINSIC*sizeof(double) );
+
+    assert( stdDevsMatExt.type() == CV_64F );
+    assert( stdDevsMatExt.total() == static_cast<size_t>(6*imageCount) );
+    memcpy( stdDevs + CV_CALIB_NINTRINSIC, stdDevsMatExt.ptr(), 6*imageCount*sizeof(double) );
+
+    assert( perViewErrorsMat.type() == CV_64F);
+    assert( perViewErrorsMat.total() == static_cast<size_t>(imageCount) );
+    memcpy( perViewErrors, perViewErrorsMat.ptr(), imageCount*sizeof(double) );
+
     assert( cameraMatrix.type() == CV_64FC1 );
     memcpy( _cameraMatrix, cameraMatrix.ptr(), 9*sizeof(double) );
 
@@ -875,8 +949,8 @@ void CV_CalibrationMatrixValuesTest::run(int)
         ny = goodAspectRatio;
     }
 
-    goodFovx = 2 * atan( imageSize.width / (2 * fx)) * 180.0 / CV_PI;
-    goodFovy = 2 * atan( imageSize.height / (2 * fy)) * 180.0 / CV_PI;
+    goodFovx = (atan2(cx, fx) + atan2(imageSize.width  - cx, fx)) * 180.0 / CV_PI;
+    goodFovy = (atan2(cy, fy) + atan2(imageSize.height - cy, fy)) * 180.0 / CV_PI;
 
     goodFocalLength = fx / nx;
 
@@ -1232,7 +1306,8 @@ void CV_ProjectPointsTest_C::project( const Mat& opoints, const Mat& rvec, const
     dpdf.create(npoints*2, 2, CV_64F);
     dpdc.create(npoints*2, 2, CV_64F);
     dpddist.create(npoints*2, distCoeffs.rows + distCoeffs.cols - 1, CV_64F);
-    CvMat _objectPoints = opoints, _imagePoints = Mat(ipoints);
+    Mat imagePoints(ipoints);
+    CvMat _objectPoints = opoints, _imagePoints = imagePoints;
     CvMat _rvec = rvec, _tvec = tvec, _cameraMatrix = cameraMatrix, _distCoeffs = distCoeffs;
     CvMat _dpdrot = dpdrot, _dpdt = dpdt, _dpdf = dpdf, _dpdc = dpdc, _dpddist = dpddist;
 
@@ -1272,6 +1347,108 @@ void CV_ProjectPointsTest_CPP::project( const Mat& objectPoints, const Mat& rvec
 
 ///////////////////////////////// Stereo Calibration /////////////////////////////////////
 
+class CV_StereoCalibrationCornerTest : public cvtest::BaseTest
+{
+public:
+    CV_StereoCalibrationCornerTest();
+    ~CV_StereoCalibrationCornerTest();
+    void clear();
+protected:
+    void run(int);
+};
+
+CV_StereoCalibrationCornerTest::CV_StereoCalibrationCornerTest()
+{
+}
+
+
+CV_StereoCalibrationCornerTest::~CV_StereoCalibrationCornerTest()
+{
+    clear();
+}
+
+void CV_StereoCalibrationCornerTest::clear()
+{
+    cvtest::BaseTest::clear();
+}
+
+static bool resizeCameraMatrix(const Mat &in_cm, Mat &dst_cm, double scale)
+{
+    if (in_cm.empty() || in_cm.cols != 3 || in_cm.rows != 3 || in_cm.type() != CV_64FC1)
+        return false;
+    dst_cm = in_cm * scale;
+    dst_cm.at<double>(2, 2) = 1.0;
+    return true;
+}
+
+// see https://github.com/opencv/opencv/pull/6836 for details
+void CV_StereoCalibrationCornerTest::run(int)
+{
+    const Matx33d M1(906.7857732303256, 0.0, 1026.456125870669,
+                            0.0, 906.7857732303256, 540.0531577669913,
+                            0.0, 0.0, 1.0);
+    const Matx33d M2(906.782205162265, 0.0, 1014.619997352785,
+                            0.0, 906.782205162265, 561.9990018887295,
+                            0.0, 0.0, 1.0);
+    const Matx<double, 5, 1> D1(0.0064836857220181504, 0.033880363848984636, 0.0, 0.0, -0.042996356352306114);
+    const Matx<double, 5, 1> D2(0.023754068600491646, -0.02364619610835259, 0.0, 0.0, 0.0015014971456262652);
+
+    const Size imageSize(2048, 1088);
+    const double scale = 0.25;
+
+    const Matx33d Rot(0.999788461750194, -0.015696495349844446, -0.013291041528534329,
+                             0.015233019205877604, 0.999296086451901, -0.034282455101525826,
+                             0.01381980018141639, 0.03407274036010432, 0.9993238021218641);
+    const Matx31d T(-1.552005597952028, 0.0019508251875105093, -0.023335501616116062);
+
+    // generate camera matrices for resized image rectification.
+    Mat srcM1(M1), srcM2(M2);
+    Mat rszM1, rszM2;
+    resizeCameraMatrix(srcM1, rszM1, scale);
+    resizeCameraMatrix(srcM2, rszM2, scale);
+    Size rszImageSize(cvRound(scale * imageSize.width), cvRound(scale * imageSize.height));
+    Size srcImageSize = imageSize;
+    // apply stereoRectify
+    Mat srcR[2], srcP[2], srcQ;
+    Mat rszR[2], rszP[2], rszQ;
+    stereoRectify(srcM1, D1, srcM2, D2, srcImageSize, Rot, T,
+                  srcR[0], srcR[1], srcP[0], srcP[1], srcQ,
+                  CALIB_ZERO_DISPARITY, 0);
+    stereoRectify(rszM1, D1, rszM2, D2, rszImageSize, Rot, T,
+                  rszR[0], rszR[1], rszP[0], rszP[1], rszQ,
+                  CALIB_ZERO_DISPARITY, 0);
+    // generate remap maps
+    Mat srcRmap[2], rszRmap[2];
+    initUndistortRectifyMap(srcM1, D1, srcR[0], srcP[0], srcImageSize, CV_32FC2, srcRmap[0], srcRmap[1]);
+    initUndistortRectifyMap(rszM1, D1, rszR[0], rszP[0], rszImageSize, CV_32FC2, rszRmap[0], rszRmap[1]);
+
+    // generate source image
+    // it's an artificial pattern with white rect in the center
+    Mat image(imageSize, CV_8UC3);
+    image.setTo(0);
+    image(cv::Rect(imageSize.width / 3, imageSize.height / 3, imageSize.width / 3, imageSize.height / 3)).setTo(255);
+
+    // perform remap-resize
+    Mat src_result;
+    remap(image, src_result, srcRmap[0], srcRmap[1], INTER_LINEAR);
+    resize(src_result, src_result, Size(), scale, scale, INTER_LINEAR);
+    // perform resize-remap
+    Mat rsz_result;
+    resize(image, rsz_result, Size(), scale, scale, INTER_LINEAR);
+    remap(rsz_result, rsz_result, rszRmap[0], rszRmap[1], INTER_LINEAR);
+
+    // modifying the camera matrix with resizeCameraMatrix must yield the same
+    // result as calibrating the downscaled images
+    int cnz = countNonZero((cv::Mat(src_result - rsz_result) != 0)(
+                               cv::Rect(src_result.cols / 3, src_result.rows / 3,
+                                        (int)(src_result.cols / 3.1), int(src_result.rows / 3.1))));
+    if (cnz)
+    {
+        ts->printf( cvtest::TS::LOG, "The camera matrix is wrong for downscaled image\n");
+        ts->set_failed_test_info( cvtest::TS::FAIL_BAD_ACCURACY );
+    }
+}
+
 class CV_StereoCalibrationTest : public cvtest::BaseTest
 {
 public:
@@ -1349,27 +1526,27 @@ bool CV_StereoCalibrationTest::checkPandROI( int test_case_idx, const Mat& M, co
             return false;
         }
 
-        // step 2. check that all the points inside ROI belong to the original source image
-        Mat temp(imgsize, CV_8U), utemp, map1, map2;
-        temp = Scalar::all(1);
-        initUndistortRectifyMap(M, D, R, P, imgsize, CV_16SC2, map1, map2);
-        remap(temp, utemp, map1, map2, INTER_LINEAR);
+    // step 2. check that all the points inside ROI belong to the original source image
+    Mat temp(imgsize, CV_8U), utemp, map1, map2;
+    temp = Scalar::all(1);
+    initUndistortRectifyMap(M, D, R, P, imgsize, CV_16SC2, map1, map2);
+    remap(temp, utemp, map1, map2, INTER_LINEAR);
 
-        if(roi.x < 0 || roi.y < 0 || roi.x + roi.width > imgsize.width || roi.y + roi.height > imgsize.height)
-        {
+    if(roi.x < 0 || roi.y < 0 || roi.x + roi.width > imgsize.width || roi.y + roi.height > imgsize.height)
+    {
             ts->printf(cvtest::TS::LOG, "Test #%d. The ROI=(%d, %d, %d, %d) is outside of the imge rectangle\n",
-                test_case_idx, roi.x, roi.y, roi.width, roi.height);
+                            test_case_idx, roi.x, roi.y, roi.width, roi.height);
             return false;
-        }
-        double s = sum(utemp(roi))[0];
-        if( s > roi.area() || roi.area() - s > roi.area()*(1-eps) )
-        {
+    }
+    double s = sum(utemp(roi))[0];
+    if( s > roi.area() || roi.area() - s > roi.area()*(1-eps) )
+    {
             ts->printf(cvtest::TS::LOG, "Test #%d. The ratio of black pixels inside the valid ROI (~%g%%) is too large\n",
-                test_case_idx, s*100./roi.area());
+                            test_case_idx, s*100./roi.area());
             return false;
-        }
+    }
 
-        return true;
+    return true;
 }
 
 void CV_StereoCalibrationTest::run( int )
@@ -1525,9 +1702,10 @@ void CV_StereoCalibrationTest::run( int )
         const float minCoord = -300.0f;
         const float maxCoord = 300.0f;
         const float minDisparity = 0.1f;
-        const float maxDisparity = 600.0f;
+        const float maxDisparity = 60.0f;
         const int pointsCount = 500;
         const float requiredAccuracy = 1e-3f;
+        const float allowToFail = 0.2f; // 20%
         RNG& rng = ts->get_rng();
 
         Mat projectedPoints_1(2, pointsCount, CV_32FC1);
@@ -1556,9 +1734,29 @@ void CV_StereoCalibrationTest::run( int )
         Mat reprojectedPoints;
         perspectiveTransform(sparsePoints, reprojectedPoints, Q);
 
-        if (cvtest::norm(triangulatedPoints, reprojectedPoints, NORM_L2) / sqrt((double)pointsCount) > requiredAccuracy)
+        Mat diff;
+        absdiff(triangulatedPoints, reprojectedPoints, diff);
+        Mat mask = diff > requiredAccuracy;
+        mask = mask.reshape(1);
+        mask = mask.col(0) | mask.col(1) | mask.col(2);
+        int numFailed = countNonZero(mask);
+#if 0
+        std::cout << "numFailed=" << numFailed << std::endl;
+        for (int i = 0; i < triangulatedPoints.rows; i++)
+        {
+            if (mask.at<uchar>(i))
+            {
+                // failed points usually have 'w'~0 (points4d[3])
+                std::cout << "i=" << i << " triangulatePoints=" << triangulatedPoints.row(i) << " reprojectedPoints=" << reprojectedPoints.row(i) << std::endl <<
+                    "     points4d=" << points4d.col(i).t() << " projectedPoints_1=" << projectedPoints_1.col(i).t() << " disparities=" << disparities.col(i).t() << std::endl;
+            }
+        }
+#endif
+
+        if (numFailed >= allowToFail * pointsCount)
         {
-            ts->printf( cvtest::TS::LOG, "Points reprojected with a matrix Q and points reconstructed by triangulation are different, testcase %d\n", testcase);
+            ts->printf( cvtest::TS::LOG, "Points reprojected with a matrix Q and points reconstructed by triangulation are different (tolerance=%g, failed=%d), testcase %d\n",
+                requiredAccuracy, numFailed, testcase);
             ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
         }
 
@@ -1875,7 +2073,7 @@ TEST(Calib3d_ProjectPoints_C, accuracy) { CV_ProjectPointsTest_C  test; test.saf
 TEST(Calib3d_ProjectPoints_CPP, regression) { CV_ProjectPointsTest_CPP test; test.safe_run(); }
 TEST(Calib3d_StereoCalibrate_C, regression) { CV_StereoCalibrationTest_C test; test.safe_run(); }
 TEST(Calib3d_StereoCalibrate_CPP, regression) { CV_StereoCalibrationTest_CPP test; test.safe_run(); }
-
+TEST(Calib3d_StereoCalibrateCorner, regression) { CV_StereoCalibrationCornerTest test; test.safe_run(); }
 
 TEST(Calib3d_Triangulate, accuracy)
 {
diff --git a/modules/calib3d/test/test_chessboardgenerator.cpp b/modules/calib3d/test/test_chessboardgenerator.cpp
index 7c0bd34..8a9c5ea 100644
--- a/modules/calib3d/test/test_chessboardgenerator.cpp
+++ b/modules/calib3d/test/test_chessboardgenerator.cpp
@@ -51,7 +51,7 @@ using namespace cv;
 using namespace std;
 
 ChessBoardGenerator::ChessBoardGenerator(const Size& _patternSize) : sensorWidth(32), sensorHeight(24),
-    squareEdgePointsNum(200), min_cos(std::sqrt(2.f)*0.5f), cov(0.5),
+    squareEdgePointsNum(200), min_cos(std::sqrt(3.f)*0.5f), cov(0.5),
     patternSize(_patternSize), rendererResolutionMultiplier(4), tvec(Mat::zeros(1, 3, CV_32F))
 {
     Rodrigues(Mat::eye(3, 3, CV_32F), rvec);
@@ -85,8 +85,10 @@ void cv::ChessBoardGenerator::generateBasis(Point3f& pb1, Point3f& pb2) const
     {
         n[0] = rng.uniform(-1.f, 1.f);
         n[1] = rng.uniform(-1.f, 1.f);
-        n[2] = rng.uniform(-1.f, 1.f);
+        n[2] = rng.uniform(0.0f, 1.f);
         float len = (float)norm(n);
+        if (len < 1e-3)
+            continue;
         n[0]/=len;
         n[1]/=len;
         n[2]/=len;
diff --git a/modules/calib3d/test/test_chesscorners.cpp b/modules/calib3d/test/test_chesscorners.cpp
index fd3da2e..781eec2 100644
--- a/modules/calib3d/test/test_chesscorners.cpp
+++ b/modules/calib3d/test/test_chesscorners.cpp
@@ -51,29 +51,31 @@ using namespace cv;
 
 #define _L2_ERR
 
-void show_points( const Mat& gray, const Mat& u, const vector<Point2f>& v, Size pattern_size, bool was_found )
+//#define DEBUG_CHESSBOARD
+
+#ifdef DEBUG_CHESSBOARD
+#include "opencv2/highgui.hpp"
+void show_points( const Mat& gray, const Mat& expected, const vector<Point2f>& actual, bool was_found )
 {
     Mat rgb( gray.size(), CV_8U);
     merge(vector<Mat>(3, gray), rgb);
 
-    for(size_t i = 0; i < v.size(); i++ )
-        circle( rgb, v[i], 3, Scalar(255, 0, 0), FILLED);
+    for(size_t i = 0; i < actual.size(); i++ )
+        circle( rgb, actual[i], 5, Scalar(0, 0, 200), 1, LINE_AA);
 
-    if( !u.empty() )
+    if( !expected.empty() )
     {
-        const Point2f* u_data = u.ptr<Point2f>();
-        size_t count = u.cols * u.rows;
+        const Point2f* u_data = expected.ptr<Point2f>();
+        size_t count = expected.cols * expected.rows;
         for(size_t i = 0; i < count; i++ )
-            circle( rgb, u_data[i], 3, Scalar(0, 255, 0), FILLED);
-    }
-    if (!v.empty())
-    {
-        Mat corners((int)v.size(), 1, CV_32FC2, (void*)&v[0]);
-        drawChessboardCorners( rgb, pattern_size, corners, was_found );
+            circle(rgb, u_data[i], 4, Scalar(0, 240, 0), 1, LINE_AA);
     }
-    //namedWindow( "test", 0 ); imshow( "test", rgb ); waitKey(0);
+    putText(rgb, was_found ? "FOUND !!!" : "NOT FOUND", Point(5, 20), FONT_HERSHEY_PLAIN, 1, Scalar(0, 240, 0));
+    imshow( "test", rgb ); while ((uchar)waitKey(0) != 'q') {};
 }
-
+#else
+#define show_points(...)
+#endif
 
 enum Pattern { CHESSBOARD, CIRCLES_GRID, ASYMMETRIC_CIRCLES_GRID };
 
@@ -253,7 +255,6 @@ void CV_ChessboardDetectorTest::run_batch( const string& filename )
                 result = findCirclesGrid(gray, pattern_size, v, CALIB_CB_ASYMMETRIC_GRID | algorithmFlags);
                 break;
         }
-        show_points( gray, Mat(), v, pattern_size, result );
 
         if( result ^ doesContatinChessboard || v.size() != count_exp )
         {
@@ -280,7 +281,7 @@ void CV_ChessboardDetectorTest::run_batch( const string& filename )
             if( pattern == CHESSBOARD )
                 cornerSubPix( gray, v, Size(5, 5), Size(-1,-1), TermCriteria(TermCriteria::EPS|TermCriteria::MAX_ITER, 30, 0.1));
             //find4QuadCornerSubpix(gray, v, Size(5, 5));
-            show_points( gray, expected, v, pattern_size, result  );
+            show_points( gray, expected, v, result  );
 #ifndef WRITE_POINTS
     //        printf("called find4QuadCornerSubpix\n");
             err = calcError(v, expected);
@@ -298,6 +299,10 @@ void CV_ChessboardDetectorTest::run_batch( const string& filename )
             max_precise_error = MAX( max_precise_error, err );
 #endif
         }
+        else
+        {
+            show_points( gray, Mat(), v, result );
+        }
 
 #ifdef WRITE_POINTS
         Mat mat_v(pattern_size, CV_32FC2, (void*)&v[0]);
@@ -368,8 +373,6 @@ bool CV_ChessboardDetectorTest::checkByGenerator()
 {
     bool res = true;
 
-// for some reason, this test sometimes fails on Ubuntu
-#if (defined __APPLE__ && defined __x86_64__) || defined _MSC_VER
     //theRNG() = 0x58e6e895b9913160;
     //cv::DefaultRngAuto dra;
     //theRNG() = *ts->get_rng();
@@ -468,7 +471,6 @@ bool CV_ChessboardDetectorTest::checkByGenerator()
 
         cv::drawChessboardCorners(cb, cbg.cornersSize(), Mat(corners_found), found);
     }
-#endif
 
     return res;
 }
diff --git a/modules/calib3d/test/test_chesscorners_timing.cpp b/modules/calib3d/test/test_chesscorners_timing.cpp
index 61287ab..570c125 100644
--- a/modules/calib3d/test/test_chesscorners_timing.cpp
+++ b/modules/calib3d/test/test_chesscorners_timing.cpp
@@ -113,11 +113,7 @@ void CV_ChessboardDetectorTimingTest::run( int start_from )
         if( img2.empty() )
         {
             ts->printf( cvtest::TS::LOG, "one of chessboard images can't be read: %s\n", filename.c_str() );
-            if( max_idx == 1 )
-            {
-                code = cvtest::TS::FAIL_MISSING_TEST_DATA;
-                goto _exit_;
-            }
+            code = cvtest::TS::FAIL_MISSING_TEST_DATA;
             continue;
         }
 
diff --git a/modules/calib3d/test/test_cornerssubpix.cpp b/modules/calib3d/test/test_cornerssubpix.cpp
index d1f0776..f25c9da 100644
--- a/modules/calib3d/test/test_cornerssubpix.cpp
+++ b/modules/calib3d/test/test_cornerssubpix.cpp
@@ -242,4 +242,18 @@ void CV_ChessboardSubpixelTest::generateIntrinsicParams()
 
 TEST(Calib3d_ChessboardSubPixDetector, accuracy) { CV_ChessboardSubpixelTest test; test.safe_run(); }
 
+TEST(Calib3d_CornerSubPix, regression_7204)
+{
+    cv::Mat image(cv::Size(70, 38), CV_8UC1, cv::Scalar::all(0));
+    image(cv::Rect(65, 26, 5, 5)).setTo(cv::Scalar::all(255));
+    image(cv::Rect(55, 31, 8, 1)).setTo(cv::Scalar::all(255));
+    image(cv::Rect(56, 35, 14, 2)).setTo(cv::Scalar::all(255));
+    image(cv::Rect(66, 24, 4, 2)).setTo(cv::Scalar::all(255));
+    image.at<uchar>(24, 69) = 0;
+    std::vector<cv::Point2f> corners;
+    corners.push_back(cv::Point2f(65, 30));
+    cv::cornerSubPix(image, corners, cv::Size(3, 3), cv::Size(-1, -1),
+        cv::TermCriteria(CV_TERMCRIT_EPS + CV_TERMCRIT_ITER, 30, 0.1));
+}
+
 /* End of file. */
diff --git a/modules/calib3d/test/test_fisheye.cpp b/modules/calib3d/test/test_fisheye.cpp
index 006f378..9ad8c64 100644
--- a/modules/calib3d/test/test_fisheye.cpp
+++ b/modules/calib3d/test/test_fisheye.cpp
@@ -570,6 +570,48 @@ TEST_F(fisheyeTest, stereoCalibrateFixIntrinsic)
     EXPECT_MAT_NEAR(theT, T_correct, 1e-10);
 }
 
+TEST_F(fisheyeTest, CalibrationWithDifferentPointsNumber)
+{
+  const int n_images = 2;
+
+  std::vector<std::vector<cv::Point2d> > imagePoints(n_images);
+  std::vector<std::vector<cv::Point3d> > objectPoints(n_images);
+
+  std::vector<cv::Point2d> imgPoints1(10);
+  std::vector<cv::Point2d> imgPoints2(15);
+
+  std::vector<cv::Point3d> objectPoints1(imgPoints1.size());
+  std::vector<cv::Point3d> objectPoints2(imgPoints2.size());
+
+  for (size_t i = 0; i < imgPoints1.size(); i++)
+  {
+    imgPoints1[i] = cv::Point2d((double)i, (double)i);
+    objectPoints1[i] = cv::Point3d((double)i, (double)i, 10.0);
+  }
+
+  for (size_t i = 0; i < imgPoints2.size(); i++)
+  {
+    imgPoints2[i] = cv::Point2d(i + 0.5, i + 0.5);
+    objectPoints2[i] = cv::Point3d(i + 0.5, i + 0.5, 10.0);
+  }
+
+  imagePoints[0] = imgPoints1;
+  imagePoints[1] = imgPoints2;
+  objectPoints[0] = objectPoints1;
+  objectPoints[1] = objectPoints2;
+
+  cv::Matx33d theK = cv::Matx33d::eye();
+  cv::Vec4d theD;
+
+  int flag = 0;
+  flag |= cv::fisheye::CALIB_RECOMPUTE_EXTRINSIC;
+  flag |= cv::fisheye::CALIB_USE_INTRINSIC_GUESS;
+  flag |= cv::fisheye::CALIB_FIX_SKEW;
+
+  cv::fisheye::calibrate(objectPoints, imagePoints, cv::Size(100, 100), theK, theD,
+    cv::noArray(), cv::noArray(), flag, cv::TermCriteria(3, 20, 1e-6));
+}
+
 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 ///  fisheyeTest::
 
diff --git a/modules/calib3d/test/test_solvepnp_ransac.cpp b/modules/calib3d/test/test_solvepnp_ransac.cpp
index 5e3dbc6..e6e9b6b 100644
--- a/modules/calib3d/test/test_solvepnp_ransac.cpp
+++ b/modules/calib3d/test/test_solvepnp_ransac.cpp
@@ -314,6 +314,45 @@ TEST(Calib3d_SolvePnPRansac, concurrency)
     EXPECT_LT(tnorm, 1e-6);
 }
 
+TEST(Calib3d_SolvePnPRansac, input_type)
+{
+    const int numPoints = 10;
+    Matx33d intrinsics(5.4794130238156129e+002, 0., 2.9835545700043139e+002, 0.,
+        5.4817724002728005e+002, 2.3062194051986233e+002, 0., 0., 1.);
+
+    std::vector<cv::Point3f> points3d;
+    std::vector<cv::Point2f> points2d;
+    for (int i = 0; i < numPoints; i+=2)
+    {
+        points3d.push_back(cv::Point3i(5+i, 3, 2));
+        points3d.push_back(cv::Point3i(5+i, 3+i, 2+i));
+        points2d.push_back(cv::Point2i(0, i));
+        points2d.push_back(cv::Point2i(-i, i));
+    }
+    Mat R1, t1, R2, t2, R3, t3, R4, t4;
+
+    EXPECT_TRUE(solvePnPRansac(points3d, points2d, intrinsics, cv::Mat(), R1, t1));
+
+    Mat points3dMat(points3d);
+    Mat points2dMat(points2d);
+    EXPECT_TRUE(solvePnPRansac(points3dMat, points2dMat, intrinsics, cv::Mat(), R2, t2));
+
+    points3dMat = points3dMat.reshape(3, 1);
+    points2dMat = points2dMat.reshape(2, 1);
+    EXPECT_TRUE(solvePnPRansac(points3dMat, points2dMat, intrinsics, cv::Mat(), R3, t3));
+
+    points3dMat = points3dMat.reshape(1, numPoints);
+    points2dMat = points2dMat.reshape(1, numPoints);
+    EXPECT_TRUE(solvePnPRansac(points3dMat, points2dMat, intrinsics, cv::Mat(), R4, t4));
+
+    EXPECT_LE(norm(R1, R2, NORM_INF), 1e-6);
+    EXPECT_LE(norm(t1, t2, NORM_INF), 1e-6);
+    EXPECT_LE(norm(R1, R3, NORM_INF), 1e-6);
+    EXPECT_LE(norm(t1, t3, NORM_INF), 1e-6);
+    EXPECT_LE(norm(R1, R4, NORM_INF), 1e-6);
+    EXPECT_LE(norm(t1, t4, NORM_INF), 1e-6);
+}
+
 TEST(Calib3d_SolvePnP, double_support)
 {
     Matx33d intrinsics(5.4794130238156129e+002, 0., 2.9835545700043139e+002, 0.,
@@ -322,12 +361,16 @@ TEST(Calib3d_SolvePnP, double_support)
     std::vector<cv::Point2d> points2d;
     std::vector<cv::Point3f> points3dF;
     std::vector<cv::Point2f> points2dF;
-    for (int i = 0; i < 10 ; i++)
+    for (int i = 0; i < 10 ; i+=2)
     {
-        points3d.push_back(cv::Point3d(i,0,0));
-        points3dF.push_back(cv::Point3d(i,0,0));
-        points2d.push_back(cv::Point2d(i,0));
-        points2dF.push_back(cv::Point2d(i,0));
+        points3d.push_back(cv::Point3d(5+i, 3, 2));
+        points3dF.push_back(cv::Point3d(5+i, 3, 2));
+        points3d.push_back(cv::Point3d(5+i, 3+i, 2+i));
+        points3dF.push_back(cv::Point3d(5+i, 3+i, 2+i));
+        points2d.push_back(cv::Point2d(0, i));
+        points2dF.push_back(cv::Point2d(0, i));
+        points2d.push_back(cv::Point2d(-i, i));
+        points2dF.push_back(cv::Point2d(-i, i));
     }
     Mat R,t, RF, tF;
     vector<int> inliers;
@@ -335,8 +378,8 @@ TEST(Calib3d_SolvePnP, double_support)
     solvePnPRansac(points3dF, points2dF, intrinsics, cv::Mat(), RF, tF, true, 100, 8.f, 0.999, inliers, cv::SOLVEPNP_P3P);
     solvePnPRansac(points3d, points2d, intrinsics, cv::Mat(), R, t, true, 100, 8.f, 0.999, inliers, cv::SOLVEPNP_P3P);
 
-    ASSERT_LE(norm(R, Mat_<double>(RF), NORM_INF), 1e-3);
-    ASSERT_LE(norm(t, Mat_<double>(tF), NORM_INF), 1e-3);
+    EXPECT_LE(norm(R, Mat_<double>(RF), NORM_INF), 1e-3);
+    EXPECT_LE(norm(t, Mat_<double>(tF), NORM_INF), 1e-3);
 }
 
 TEST(Calib3d_SolvePnP, translation)
@@ -365,16 +408,16 @@ TEST(Calib3d_SolvePnP, translation)
     tvec = (Mat_<float>(3,1) << 100, 100, 0);
 
     solvePnP(p3d, p2d, cameraIntrinsic, noArray(), rvec, tvec, true);
-    ASSERT_TRUE(checkRange(rvec));
-    ASSERT_TRUE(checkRange(tvec));
+    EXPECT_TRUE(checkRange(rvec));
+    EXPECT_TRUE(checkRange(tvec));
 
     rvec =(Mat_<double>(3,1) << 0, 0, 0);
     tvec = (Mat_<double>(3,1) << 100, 100, 0);
     solvePnP(p3d, p2d, cameraIntrinsic, noArray(), rvec, tvec, true);
-    ASSERT_TRUE(checkRange(rvec));
-    ASSERT_TRUE(checkRange(tvec));
+    EXPECT_TRUE(checkRange(rvec));
+    EXPECT_TRUE(checkRange(tvec));
 
     solvePnP(p3d, p2d, cameraIntrinsic, noArray(), rvec, tvec, false);
-    ASSERT_TRUE(checkRange(rvec));
-    ASSERT_TRUE(checkRange(tvec));
+    EXPECT_TRUE(checkRange(rvec));
+    EXPECT_TRUE(checkRange(tvec));
 }
diff --git a/modules/core/CMakeLists.txt b/modules/core/CMakeLists.txt
index 44085d4..0485a08 100644
--- a/modules/core/CMakeLists.txt
+++ b/modules/core/CMakeLists.txt
@@ -1,5 +1,6 @@
 set(the_description "The Core Functionality")
 ocv_add_module(core
+               "${OPENCV_HAL_LINKER_LIBS}"
                PRIVATE_REQUIRED ${ZLIB_LIBRARIES} "${OPENCL_LIBRARIES}" "${VA_LIBRARIES}"
                OPTIONAL opencv_cudev
                WRAP java python)
@@ -21,13 +22,15 @@ endif()
 file(GLOB lib_cuda_hdrs        "include/opencv2/${name}/cuda/*.hpp"        "include/opencv2/${name}/cuda/*.h")
 file(GLOB lib_cuda_hdrs_detail "include/opencv2/${name}/cuda/detail/*.hpp" "include/opencv2/${name}/cuda/detail/*.h")
 
-source_group("Cuda Headers"         FILES ${lib_cuda_hdrs})
-source_group("Cuda Headers\\Detail" FILES ${lib_cuda_hdrs_detail})
+source_group("Include\\Cuda Headers"         FILES ${lib_cuda_hdrs})
+source_group("Include\\Cuda Headers\\Detail" FILES ${lib_cuda_hdrs_detail})
+
+source_group("Src" FILES "${OPENCV_MODULE_opencv_core_BINARY_DIR}/version_string.inc")
 
 ocv_glob_module_sources(SOURCES "${OPENCV_MODULE_opencv_core_BINARY_DIR}/version_string.inc"
                         HEADERS ${lib_cuda_hdrs} ${lib_cuda_hdrs_detail})
 
-ocv_module_include_directories(${the_module} ${ZLIB_INCLUDE_DIRS})
+ocv_module_include_directories(${the_module} ${ZLIB_INCLUDE_DIRS} ${OPENCL_INCLUDE_DIRS})
 ocv_create_module(${extra_libs})
 
 ocv_add_accuracy_tests()
diff --git a/modules/core/doc/cuda.markdown b/modules/core/doc/cuda.markdown
index fb648e2..ea85007 100644
--- a/modules/core/doc/cuda.markdown
+++ b/modules/core/doc/cuda.markdown
@@ -82,4 +82,4 @@ Block Matching algorithm has been successfully parallelized using the following
 3.  Merge the results into a single disparity map.
 
 With this algorithm, a dual GPU gave a 180% performance increase comparing to the single Fermi GPU.
-For a source code example, see <https://github.com/Itseez/opencv/tree/master/samples/gpu/>.
+For a source code example, see <https://github.com/opencv/opencv/tree/master/samples/gpu/>.
diff --git a/modules/core/doc/intro.markdown b/modules/core/doc/intro.markdown
index 964fb06..41d8078 100644
--- a/modules/core/doc/intro.markdown
+++ b/modules/core/doc/intro.markdown
@@ -22,7 +22,7 @@ libraries. The following modules are available:
 -   **objdetect** - detection of objects and instances of the predefined classes (for example,
     faces, eyes, mugs, people, cars, and so on).
 -   **highgui** - an easy-to-use interface to simple UI capabilities.
--   **videoio** - an easy-to-use interface to video capturing and video codecs.
+-   @ref videoio - an easy-to-use interface to video capturing and video codecs.
 -   **gpu** - GPU-accelerated algorithms from different OpenCV modules.
 -   ... some other helper modules, such as FLANN and Google test wrappers, Python bindings, and
     others.
diff --git a/modules/core/include/opencv2/core.hpp b/modules/core/include/opencv2/core.hpp
index 5592260..6b89c42 100644
--- a/modules/core/include/opencv2/core.hpp
+++ b/modules/core/include/opencv2/core.hpp
@@ -42,8 +42,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_CORE_HPP__
-#define __OPENCV_CORE_HPP__
+#ifndef OPENCV_CORE_HPP
+#define OPENCV_CORE_HPP
 
 #ifndef __cplusplus
 #  error core.hpp header must be compiled as C++
@@ -426,7 +426,7 @@ CV_EXPORTS_W void multiply(InputArray src1, InputArray src2,
 
 /** @brief Performs per-element division of two arrays or a scalar by an array.
 
-The functions divide divide one array by another:
+The function cv::divide divides one array by another:
 \f[\texttt{dst(I) = saturate(src1(I)*scale/src2(I))}\f]
 or a scalar by an array when there is no src1 :
 \f[\texttt{dst(I) = saturate(scale/src2(I))}\f]
@@ -524,6 +524,17 @@ For example:
 CV_EXPORTS_W void convertScaleAbs(InputArray src, OutputArray dst,
                                   double alpha = 1, double beta = 0);
 
+/** @brief Converts an array to half precision floating number.
+
+This function converts FP32 (single precision floating point) from/to FP16 (half precision floating point).  The input array has to have type of CV_32F or
+CV_16S to represent the bit depth.  If the input array is neither of them, the function will raise an error.
+The format of half precision floating point is defined in IEEE 754-2008.
+
+ at param src input array.
+ at param dst output array.
+*/
+CV_EXPORTS_W void convertFp16(InputArray src, OutputArray dst);
+
 /** @brief Performs a look-up table transform of an array.
 
 The function LUT fills the output array with values from the look-up table. Indices of the entries
@@ -542,7 +553,7 @@ CV_EXPORTS_W void LUT(InputArray src, InputArray lut, OutputArray dst);
 
 /** @brief Calculates the sum of array elements.
 
-The functions sum calculate and return the sum of array elements,
+The function cv::sum calculates and returns the sum of array elements,
 independently for each channel.
 @param src input array that must have from 1 to 4 channels.
 @sa  countNonZero, mean, meanStdDev, norm, minMaxLoc, reduce
@@ -588,10 +599,10 @@ CV_EXPORTS_W void findNonZero( InputArray src, OutputArray idx );
 
 /** @brief Calculates an average (mean) of array elements.
 
-The function mean calculates the mean value M of array elements,
+The function cv::mean calculates the mean value M of array elements,
 independently for each channel, and return it:
 \f[\begin{array}{l} N =  \sum _{I: \; \texttt{mask} (I) \ne 0} 1 \\ M_c =  \left ( \sum _{I: \; \texttt{mask} (I) \ne 0}{ \texttt{mtx} (I)_c} \right )/N \end{array}\f]
-When all the mask elements are 0's, the functions return Scalar::all(0)
+When all the mask elements are 0's, the function returns Scalar::all(0)
 @param src input array that should have from 1 to 4 channels so that the result can be stored in
 Scalar_ .
 @param mask optional operation mask.
@@ -601,11 +612,11 @@ CV_EXPORTS_W Scalar mean(InputArray src, InputArray mask = noArray());
 
 /** Calculates a mean and standard deviation of array elements.
 
-The function meanStdDev calculates the mean and the standard deviation M
+The function cv::meanStdDev calculates the mean and the standard deviation M
 of array elements independently for each channel and returns it via the
 output parameters:
 \f[\begin{array}{l} N =  \sum _{I, \texttt{mask} (I)  \ne 0} 1 \\ \texttt{mean} _c =  \frac{\sum_{ I: \; \texttt{mask}(I) \ne 0} \texttt{src} (I)_c}{N} \\ \texttt{stddev} _c =  \sqrt{\frac{\sum_{ I: \; \texttt{mask}(I) \ne 0} \left ( \texttt{src} (I)_c -  \texttt{mean} _c \right )^2}{N}} \end{array}\f]
-When all the mask elements are 0's, the functions return
+When all the mask elements are 0's, the function returns
 mean=stddev=Scalar::all(0).
 @note The calculated standard deviation is only the diagonal of the
 complete normalized covariance matrix. If the full matrix is needed, you
@@ -625,7 +636,7 @@ CV_EXPORTS_W void meanStdDev(InputArray src, OutputArray mean, OutputArray stdde
 /** @brief Calculates an absolute array norm, an absolute difference norm, or a
 relative difference norm.
 
-The functions norm calculate an absolute norm of src1 (when there is no
+The function cv::norm calculates an absolute norm of src1 (when there is no
 src2 ):
 
 \f[norm =  \forkthree{\|\texttt{src1}\|_{L_{\infty}} =  \max _I | \texttt{src1} (I)|}{if  \(\texttt{normType} = \texttt{NORM_INF}\) }
@@ -644,7 +655,7 @@ or
 { \frac{\|\texttt{src1}-\texttt{src2}\|_{L_1} }{\|\texttt{src2}\|_{L_1}} }{if  \(\texttt{normType} = \texttt{NORM_RELATIVE_L1}\) }
 { \frac{\|\texttt{src1}-\texttt{src2}\|_{L_2} }{\|\texttt{src2}\|_{L_2}} }{if  \(\texttt{normType} = \texttt{NORM_RELATIVE_L2}\) }\f]
 
-The functions norm return the calculated norm.
+The function cv::norm returns the calculated norm.
 
 When the mask parameter is specified and it is not empty, the norm is
 calculated only over the region specified by the mask.
@@ -692,7 +703,7 @@ CV_EXPORTS_W void batchDistance(InputArray src1, InputArray src2,
 
 /** @brief Normalizes the norm or value range of an array.
 
-The functions normalize scale and shift the input array elements so that
+The function cv::normalize normalizes scale and shift the input array elements so that
 \f[\| \texttt{dst} \| _{L_p}= \texttt{alpha}\f]
 (where p=Inf, 1 or 2) when normType=NORM_INF, NORM_L1, or NORM_L2, respectively; or so that
 \f[\min _I  \texttt{dst} (I)= \texttt{alpha} , \, \, \max _I  \texttt{dst} (I)= \texttt{beta}\f]
@@ -762,11 +773,11 @@ CV_EXPORTS void normalize( const SparseMat& src, SparseMat& dst, double alpha, i
 
 /** @brief Finds the global minimum and maximum in an array.
 
-The functions minMaxLoc find the minimum and maximum element values and their positions. The
+The function cv::minMaxLoc finds the minimum and maximum element values and their positions. The
 extremums are searched across the whole array or, if mask is not an empty array, in the specified
 array region.
 
-The functions do not work with multi-channel arrays. If you need to find minimum or maximum
+The function do not work with multi-channel arrays. If you need to find minimum or maximum
 elements across all the channels, use Mat::reshape first to reinterpret the array as
 single-channel. Or you may extract the particular channel using either extractImageCOI , or
 mixChannels , or split .
@@ -785,7 +796,7 @@ CV_EXPORTS_W void minMaxLoc(InputArray src, CV_OUT double* minVal,
 
 /** @brief Finds the global minimum and maximum in an array
 
-The function minMaxIdx finds the minimum and maximum element values and their positions. The
+The function cv::minMaxIdx finds the minimum and maximum element values and their positions. The
 extremums are searched across the whole array or, if mask is not an empty array, in the specified
 array region. The function does not work with multi-channel arrays. If you need to find minimum or
 maximum elements across all the channels, use Mat::reshape first to reinterpret the array as
@@ -823,12 +834,12 @@ CV_EXPORTS void minMaxLoc(const SparseMat& a, double* minVal,
 
 /** @brief Reduces a matrix to a vector.
 
-The function reduce reduces the matrix to a vector by treating the matrix rows/columns as a set of
+The function cv::reduce reduces the matrix to a vector by treating the matrix rows/columns as a set of
 1D vectors and performing the specified operation on the vectors until a single row/column is
 obtained. For example, the function can be used to compute horizontal and vertical projections of a
-raster image. In case of REDUCE_SUM and REDUCE_AVG , the output may have a larger element
-bit-depth to preserve accuracy. And multi-channel arrays are also supported in these two reduction
-modes.
+raster image. In case of REDUCE_MAX and REDUCE_MIN , the output image should have the same type as the source one.
+In case of REDUCE_SUM and REDUCE_AVG , the output may have a larger element bit-depth to preserve accuracy.
+And multi-channel arrays are also supported in these two reduction modes.
 @param src input 2D matrix.
 @param dst output vector. Its size and type is defined by dim and dtype parameters.
 @param dim dimension index along which the matrix is reduced. 0 means that the matrix is reduced to
@@ -842,7 +853,7 @@ CV_EXPORTS_W void reduce(InputArray src, OutputArray dst, int dim, int rtype, in
 
 /** @brief Creates one multi-channel array out of several single-channel ones.
 
-The function merge merges several arrays to make a single multi-channel array. That is, each
+The function cv::merge merges several arrays to make a single multi-channel array. That is, each
 element of the output array will be a concatenation of the elements of the input arrays, where
 elements of i-th input array are treated as mv[i].channels()-element vectors.
 
@@ -867,7 +878,7 @@ CV_EXPORTS_W void merge(InputArrayOfArrays mv, OutputArray dst);
 
 /** @brief Divides a multi-channel array into several single-channel arrays.
 
-The functions split split a multi-channel array into separate single-channel arrays:
+The function cv::split splits a multi-channel array into separate single-channel arrays:
 \f[\texttt{mv} [c](I) =  \texttt{src} (I)_c\f]
 If you need to extract a single channel or do some other sophisticated channel permutation, use
 mixChannels .
@@ -889,7 +900,7 @@ output arrays.
 
 The function cv::mixChannels provides an advanced mechanism for shuffling image channels.
 
-cv::split and cv::merge and some forms of cv::cvtColor are partial cases of cv::mixChannels .
+cv::split,cv::merge,cv::extractChannel,cv::insertChannel and some forms of cv::cvtColor are partial cases of cv::mixChannels.
 
 In the example below, the code splits a 4-channel BGRA image into a 3-channel BGR (with B and R
 channels swapped) and a separate alpha-channel image:
@@ -923,7 +934,7 @@ src[0].channels() + src[1].channels()-1, and so on, the same scheme is used for
 channels; as a special case, when fromTo[k\*2] is negative, the corresponding output channel is
 filled with zero .
 @param npairs number of index pairs in `fromTo`.
- at sa cv::split, cv::merge, cv::cvtColor
+ at sa split, merge, extractChannel, insertChannel, cvtColor
 */
 CV_EXPORTS void mixChannels(const Mat* src, size_t nsrcs, Mat* dst, size_t ndsts,
                             const int* fromTo, size_t npairs);
@@ -961,19 +972,25 @@ filled with zero .
 CV_EXPORTS_W void mixChannels(InputArrayOfArrays src, InputOutputArrayOfArrays dst,
                               const std::vector<int>& fromTo);
 
-/** @brief extracts a single channel from src (coi is 0-based index)
- at todo document
+/** @brief Extracts a single channel from src (coi is 0-based index)
+ at param src input array
+ at param dst output array
+ at param coi index of channel to extract
+ at sa mixChannels, split
 */
 CV_EXPORTS_W void extractChannel(InputArray src, OutputArray dst, int coi);
 
-/** @brief inserts a single channel to dst (coi is 0-based index)
- at todo document
+/** @brief Inserts a single channel to dst (coi is 0-based index)
+ at param src input array
+ at param dst output array
+ at param coi index of channel for insertion
+ at sa mixChannels, merge
 */
 CV_EXPORTS_W void insertChannel(InputArray src, InputOutputArray dst, int coi);
 
 /** @brief Flips a 2D array around vertical, horizontal, or both axes.
 
-The function flip flips the array in one of three different ways (row
+The function cv::flip flips the array in one of three different ways (row
 and column indices are 0-based):
 \f[\texttt{dst} _{ij} =
 \left\{
@@ -1005,26 +1022,44 @@ around both axes.
 */
 CV_EXPORTS_W void flip(InputArray src, OutputArray dst, int flipCode);
 
+enum RotateFlags {
+    ROTATE_90_CLOCKWISE = 0, //Rotate 90 degrees clockwise
+    ROTATE_180 = 1, //Rotate 180 degrees clockwise
+    ROTATE_90_COUNTERCLOCKWISE = 2, //Rotate 270 degrees clockwise
+};
+/** @brief Rotates a 2D array in multiples of 90 degrees.
+The function rotate rotates the array in one of three different ways:
+*   Rotate by 90 degrees clockwise (rotateCode = ROTATE_90).
+*   Rotate by 180 degrees clockwise (rotateCode = ROTATE_180).
+*   Rotate by 270 degrees clockwise (rotateCode = ROTATE_270).
+ at param src input array.
+ at param dst output array of the same type as src.  The size is the same with ROTATE_180,
+and the rows and cols are switched for ROTATE_90 and ROTATE_270.
+ at param rotateCode an enum to specify how to rotate the array; see the enum RotateFlags
+ at sa transpose , repeat , completeSymm, flip, RotateFlags
+*/
+CV_EXPORTS_W void rotate(InputArray src, OutputArray dst, int rotateCode);
+
 /** @brief Fills the output array with repeated copies of the input array.
 
-The functions repeat duplicate the input array one or more times along each of the two axes:
+The function cv::repeat duplicates the input array one or more times along each of the two axes:
 \f[\texttt{dst} _{ij}= \texttt{src} _{i\mod src.rows, \; j\mod src.cols }\f]
 The second variant of the function is more convenient to use with @ref MatrixExpressions.
 @param src input array to replicate.
- at param dst output array of the same type as src.
- at param ny Flag to specify how many times the src is repeated along the
+ at param ny Flag to specify how many times the `src` is repeated along the
 vertical axis.
- at param nx Flag to specify how many times the src is repeated along the
+ at param nx Flag to specify how many times the `src` is repeated along the
 horizontal axis.
- at sa reduce
+ at param dst output array of the same type as `src`.
+ at sa cv::reduce
 */
 CV_EXPORTS_W void repeat(InputArray src, int ny, int nx, OutputArray dst);
 
 /** @overload
 @param src input array to replicate.
- at param ny Flag to specify how many times the src is repeated along the
+ at param ny Flag to specify how many times the `src` is repeated along the
 vertical axis.
- at param nx Flag to specify how many times the src is repeated along the
+ at param nx Flag to specify how many times the `src` is repeated along the
 horizontal axis.
   */
 CV_EXPORTS Mat repeat(const Mat& src, int ny, int nx);
@@ -1160,7 +1195,7 @@ CV_EXPORTS_W void vconcat(InputArrayOfArrays src, OutputArray dst);
 Calculates the per-element bit-wise conjunction of two arrays or an
 array and a scalar.
 
-The function calculates the per-element bit-wise logical conjunction for:
+The function cv::bitwise_and calculates the per-element bit-wise logical conjunction for:
 *   Two arrays when src1 and src2 have the same size:
     \f[\texttt{dst} (I) =  \texttt{src1} (I)  \wedge \texttt{src2} (I) \quad \texttt{if mask} (I) \ne0\f]
 *   An array and a scalar when src2 is constructed from Scalar or has
@@ -1187,7 +1222,7 @@ CV_EXPORTS_W void bitwise_and(InputArray src1, InputArray src2,
 /** @brief Calculates the per-element bit-wise disjunction of two arrays or an
 array and a scalar.
 
-The function calculates the per-element bit-wise logical disjunction for:
+The function cv::bitwise_or calculates the per-element bit-wise logical disjunction for:
 *   Two arrays when src1 and src2 have the same size:
     \f[\texttt{dst} (I) =  \texttt{src1} (I)  \vee \texttt{src2} (I) \quad \texttt{if mask} (I) \ne0\f]
 *   An array and a scalar when src2 is constructed from Scalar or has
@@ -1214,7 +1249,7 @@ CV_EXPORTS_W void bitwise_or(InputArray src1, InputArray src2,
 /** @brief Calculates the per-element bit-wise "exclusive or" operation on two
 arrays or an array and a scalar.
 
-The function calculates the per-element bit-wise logical "exclusive-or"
+The function cv::bitwise_xor calculates the per-element bit-wise logical "exclusive-or"
 operation for:
 *   Two arrays when src1 and src2 have the same size:
     \f[\texttt{dst} (I) =  \texttt{src1} (I)  \oplus \texttt{src2} (I) \quad \texttt{if mask} (I) \ne0\f]
@@ -1241,7 +1276,7 @@ CV_EXPORTS_W void bitwise_xor(InputArray src1, InputArray src2,
 
 /** @brief  Inverts every bit of an array.
 
-The function calculates per-element bit-wise inversion of the input
+The function cv::bitwise_not calculates per-element bit-wise inversion of the input
 array:
 \f[\texttt{dst} (I) =  \neg \texttt{src} (I)\f]
 In case of a floating-point input array, its machine-specific bit
@@ -1258,7 +1293,7 @@ CV_EXPORTS_W void bitwise_not(InputArray src, OutputArray dst,
 
 /** @brief Calculates the per-element absolute difference between two arrays or between an array and a scalar.
 
-The function absdiff calculates:
+The function cv::absdiff calculates:
 *   Absolute difference between two arrays when they have the same
     size and type:
     \f[\texttt{dst}(I) =  \texttt{saturate} (| \texttt{src1}(I) -  \texttt{src2}(I)|)\f]
@@ -1333,7 +1368,7 @@ CV_EXPORTS_W void compare(InputArray src1, InputArray src2, OutputArray dst, int
 
 /** @brief Calculates per-element minimum of two arrays or an array and a scalar.
 
-The functions min calculate the per-element minimum of two arrays:
+The function cv::min calculates the per-element minimum of two arrays:
 \f[\texttt{dst} (I)= \min ( \texttt{src1} (I), \texttt{src2} (I))\f]
 or array and a scalar:
 \f[\texttt{dst} (I)= \min ( \texttt{src1} (I), \texttt{value} )\f]
@@ -1354,7 +1389,7 @@ CV_EXPORTS void min(const UMat& src1, const UMat& src2, UMat& dst);
 
 /** @brief Calculates per-element maximum of two arrays or an array and a scalar.
 
-The functions max calculate the per-element maximum of two arrays:
+The function cv::max calculates the per-element maximum of two arrays:
 \f[\texttt{dst} (I)= \max ( \texttt{src1} (I), \texttt{src2} (I))\f]
 or array and a scalar:
 \f[\texttt{dst} (I)= \max ( \texttt{src1} (I), \texttt{value} )\f]
@@ -1375,7 +1410,7 @@ CV_EXPORTS void max(const UMat& src1, const UMat& src2, UMat& dst);
 
 /** @brief Calculates a square root of array elements.
 
-The functions sqrt calculate a square root of each input array element.
+The function cv::sqrt calculates a square root of each input array element.
 In case of multi-channel arrays, each channel is processed
 independently. The accuracy is approximately the same as of the built-in
 std::sqrt .
@@ -1386,7 +1421,7 @@ CV_EXPORTS_W void sqrt(InputArray src, OutputArray dst);
 
 /** @brief Raises every array element to a power.
 
-The function pow raises every element of the input array to power :
+The function cv::pow raises every element of the input array to power :
 \f[\texttt{dst} (I) =  \fork{\texttt{src}(I)^{power}}{if \(\texttt{power}\) is integer}{|\texttt{src}(I)|^{power}}{otherwise}\f]
 
 So, for a non-integer power exponent, the absolute values of input array
@@ -1411,7 +1446,7 @@ CV_EXPORTS_W void pow(InputArray src, double power, OutputArray dst);
 
 /** @brief Calculates the exponent of every array element.
 
-The function exp calculates the exponent of every element of the input
+The function cv::exp calculates the exponent of every element of the input
 array:
 \f[\texttt{dst} [I] = e^{ src(I) }\f]
 
@@ -1427,14 +1462,11 @@ CV_EXPORTS_W void exp(InputArray src, OutputArray dst);
 
 /** @brief Calculates the natural logarithm of every array element.
 
-The function log calculates the natural logarithm of the absolute value
-of every element of the input array:
-\f[\texttt{dst} (I) =  \fork{\log |\texttt{src}(I)|}{if \(\texttt{src}(I) \ne 0\) }{\texttt{C}}{otherwise}\f]
+The function cv::log calculates the natural logarithm of every element of the input array:
+\f[\texttt{dst} (I) =  \log (\texttt{src}(I)) \f]
+
+Output on zero, negative and special (NaN, Inf) values is undefined.
 
-where C is a large negative number (about -700 in the current
-implementation). The maximum relative error is about 7e-6 for
-single-precision input and less than 1e-10 for double-precision input.
-Special values (NaN, Inf) are not handled.
 @param src input array.
 @param dst output array of the same size and type as src .
 @sa exp, cartToPolar, polarToCart, phase, pow, sqrt, magnitude
@@ -1443,7 +1475,7 @@ CV_EXPORTS_W void log(InputArray src, OutputArray dst);
 
 /** @brief Calculates x and y coordinates of 2D vectors from their magnitude and angle.
 
-The function polarToCart calculates the Cartesian coordinates of each 2D
+The function cv::polarToCart calculates the Cartesian coordinates of each 2D
 vector represented by the corresponding elements of magnitude and angle:
 \f[\begin{array}{l} \texttt{x} (I) =  \texttt{magnitude} (I) \cos ( \texttt{angle} (I)) \\ \texttt{y} (I) =  \texttt{magnitude} (I) \sin ( \texttt{angle} (I)) \\ \end{array}\f]
 
@@ -1466,7 +1498,7 @@ CV_EXPORTS_W void polarToCart(InputArray magnitude, InputArray angle,
 
 /** @brief Calculates the magnitude and angle of 2D vectors.
 
-The function cartToPolar calculates either the magnitude, angle, or both
+The function cv::cartToPolar calculates either the magnitude, angle, or both
 for every 2D vector (x(I),y(I)):
 \f[\begin{array}{l} \texttt{magnitude} (I)= \sqrt{\texttt{x}(I)^2+\texttt{y}(I)^2} , \\ \texttt{angle} (I)= \texttt{atan2} ( \texttt{y} (I), \texttt{x} (I))[ \cdot180 / \pi ] \end{array}\f]
 
@@ -1488,7 +1520,7 @@ CV_EXPORTS_W void cartToPolar(InputArray x, InputArray y,
 
 /** @brief Calculates the rotation angle of 2D vectors.
 
-The function phase calculates the rotation angle of each 2D vector that
+The function cv::phase calculates the rotation angle of each 2D vector that
 is formed from the corresponding elements of x and y :
 \f[\texttt{angle} (I) =  \texttt{atan2} ( \texttt{y} (I), \texttt{x} (I))\f]
 
@@ -1507,7 +1539,7 @@ CV_EXPORTS_W void phase(InputArray x, InputArray y, OutputArray angle,
 
 /** @brief Calculates the magnitude of 2D vectors.
 
-The function magnitude calculates the magnitude of 2D vectors formed
+The function cv::magnitude calculates the magnitude of 2D vectors formed
 from the corresponding elements of x and y arrays:
 \f[\texttt{dst} (I) =  \sqrt{\texttt{x}(I)^2 + \texttt{y}(I)^2}\f]
 @param x floating-point array of x-coordinates of the vectors.
@@ -1520,11 +1552,11 @@ CV_EXPORTS_W void magnitude(InputArray x, InputArray y, OutputArray magnitude);
 
 /** @brief Checks every element of an input array for invalid values.
 
-The functions checkRange check that every array element is neither NaN nor infinite. When minVal \>
--DBL_MAX and maxVal \< DBL_MAX, the functions also check that each value is between minVal and
+The function cv::checkRange checks that every array element is neither NaN nor infinite. When minVal \>
+-DBL_MAX and maxVal \< DBL_MAX, the function also checks that each value is between minVal and
 maxVal. In case of multi-channel arrays, each channel is processed independently. If some values
 are out of range, position of the first outlier is stored in pos (when pos != NULL). Then, the
-functions either return false (when quiet=true) or throw an exception.
+function either returns false (when quiet=true) or throws an exception.
 @param a input array.
 @param quiet a flag, indicating whether the functions quietly return false when the array elements
 are out of range or they throw an exception.
@@ -1542,7 +1574,7 @@ CV_EXPORTS_W void patchNaNs(InputOutputArray a, double val = 0);
 
 /** @brief Performs generalized matrix multiplication.
 
-The function performs generalized matrix multiplication similar to the
+The function cv::gemm performs generalized matrix multiplication similar to the
 gemm functions in BLAS level 3. For example,
 `gemm(src1, src2, alpha, src3, beta, dst, GEMM_1_T + GEMM_3_T)`
 corresponds to
@@ -1573,7 +1605,7 @@ CV_EXPORTS_W void gemm(InputArray src1, InputArray src2, double alpha,
 
 /** @brief Calculates the product of a matrix and its transposition.
 
-The function mulTransposed calculates the product of src and its
+The function cv::mulTransposed calculates the product of src and its
 transposition:
 \f[\texttt{dst} = \texttt{scale} ( \texttt{src} - \texttt{delta} )^T ( \texttt{src} - \texttt{delta} )\f]
 if aTa=true , and
@@ -1605,7 +1637,7 @@ CV_EXPORTS_W void mulTransposed( InputArray src, OutputArray dst, bool aTa,
 
 /** @brief Transposes a matrix.
 
-The function transpose transposes the matrix src :
+The function cv::transpose transposes the matrix src :
 \f[\texttt{dst} (i,j) =  \texttt{src} (j,i)\f]
 @note No complex conjugation is done in case of a complex matrix. It it
 should be done separately if needed.
@@ -1616,7 +1648,7 @@ CV_EXPORTS_W void transpose(InputArray src, OutputArray dst);
 
 /** @brief Performs the matrix transformation of every array element.
 
-The function transform performs the matrix transformation of every
+The function cv::transform performs the matrix transformation of every
 element of the array src and stores the results in dst :
 \f[\texttt{dst} (I) =  \texttt{m} \cdot \texttt{src} (I)\f]
 (when m.cols=src.channels() ), or
@@ -1636,13 +1668,13 @@ m.cols or m.cols-1.
 @param dst output array of the same size and depth as src; it has as
 many channels as m.rows.
 @param m transformation 2x2 or 2x3 floating-point matrix.
- at sa perspectiveTransform, getAffineTransform, estimateRigidTransform, warpAffine, warpPerspective
+ at sa perspectiveTransform, getAffineTransform, estimateAffine2D, warpAffine, warpPerspective
 */
 CV_EXPORTS_W void transform(InputArray src, OutputArray dst, InputArray m );
 
 /** @brief Performs the perspective matrix transformation of vectors.
 
-The function perspectiveTransform transforms every element of src by
+The function cv::perspectiveTransform transforms every element of src by
 treating it as a 2D or 3D vector, in the following way:
 \f[(x, y, z)  \rightarrow (x'/w, y'/w, z'/w)\f]
 where
@@ -1669,7 +1701,7 @@ CV_EXPORTS_W void perspectiveTransform(InputArray src, OutputArray dst, InputArr
 
 /** @brief Copies the lower or the upper half of a square matrix to another half.
 
-The function completeSymm copies the lower half of a square matrix to
+The function cv::completeSymm copies the lower half of a square matrix to
 its another half. The matrix diagonal remains unchanged:
 *   \f$\texttt{mtx}_{ij}=\texttt{mtx}_{ji}\f$ for \f$i > j\f$ if
     lowerToUpper=false
@@ -1684,7 +1716,7 @@ CV_EXPORTS_W void completeSymm(InputOutputArray mtx, bool lowerToUpper = false);
 
 /** @brief Initializes a scaled identity matrix.
 
-The function setIdentity initializes a scaled identity matrix:
+The function cv::setIdentity initializes a scaled identity matrix:
 \f[\texttt{mtx} (i,j)= \fork{\texttt{value}}{ if \(i=j\)}{0}{otherwise}\f]
 
 The function can also be emulated using the matrix initializers and the
@@ -1701,7 +1733,7 @@ CV_EXPORTS_W void setIdentity(InputOutputArray mtx, const Scalar& s = Scalar(1))
 
 /** @brief Returns the determinant of a square floating-point matrix.
 
-The function determinant calculates and returns the determinant of the
+The function cv::determinant calculates and returns the determinant of the
 specified matrix. For small matrices ( mtx.cols=mtx.rows\<=3 ), the
 direct method is used. For larger matrices, the function uses LU
 factorization with partial pivoting.
@@ -1716,7 +1748,7 @@ CV_EXPORTS_W double determinant(InputArray mtx);
 
 /** @brief Returns the trace of a matrix.
 
-The function trace returns the sum of the diagonal elements of the
+The function cv::trace returns the sum of the diagonal elements of the
 matrix mtx .
 \f[\mathrm{tr} ( \texttt{mtx} ) =  \sum _i  \texttt{mtx} (i,i)\f]
 @param mtx input matrix.
@@ -1725,7 +1757,7 @@ CV_EXPORTS_W Scalar trace(InputArray mtx);
 
 /** @brief Finds the inverse or pseudo-inverse of a matrix.
 
-The function invert inverts the matrix src and stores the result in dst
+The function cv::invert inverts the matrix src and stores the result in dst
 . When the matrix src is singular or non-square, the function calculates
 the pseudo-inverse matrix (the dst matrix) so that norm(src\*dst - I) is
 minimal, where I is an identity matrix.
@@ -1752,7 +1784,7 @@ CV_EXPORTS_W double invert(InputArray src, OutputArray dst, int flags = DECOMP_L
 
 /** @brief Solves one or more linear systems or least-squares problems.
 
-The function solve solves a linear system or least-squares problem (the
+The function cv::solve solves a linear system or least-squares problem (the
 latter is possible with SVD or QR methods, or by specifying the flag
 DECOMP_NORMAL ):
 \f[\texttt{dst} =  \arg \min _X \| \texttt{src1} \cdot \texttt{X} -  \texttt{src2} \|\f]
@@ -1777,7 +1809,7 @@ CV_EXPORTS_W bool solve(InputArray src1, InputArray src2,
 
 /** @brief Sorts each row or each column of a matrix.
 
-The function sort sorts each matrix row or each matrix column in
+The function cv::sort sorts each matrix row or each matrix column in
 ascending or descending order. So you should pass two operation flags to
 get desired behaviour. If you want to sort matrix rows or columns
 lexicographically, you can use STL std::sort generic function with the
@@ -1792,7 +1824,7 @@ CV_EXPORTS_W void sort(InputArray src, OutputArray dst, int flags);
 
 /** @brief Sorts each row or each column of a matrix.
 
-The function sortIdx sorts each matrix row or each matrix column in the
+The function cv::sortIdx sorts each matrix row or each matrix column in the
 ascending or descending order. So you should pass two operation flags to
 get desired behaviour. Instead of reordering the elements themselves, it
 stores the indices of sorted elements in the output array. For example:
@@ -1826,7 +1858,7 @@ CV_EXPORTS_W int solveCubic(InputArray coeffs, OutputArray roots);
 
 /** @brief Finds the real or complex roots of a polynomial equation.
 
-The function solvePoly finds real and complex roots of a polynomial equation:
+The function cv::solvePoly finds real and complex roots of a polynomial equation:
 \f[\texttt{coeffs} [n] x^{n} +  \texttt{coeffs} [n-1] x^{n-1} + ... +  \texttt{coeffs} [1] x +  \texttt{coeffs} [0] = 0\f]
 @param coeffs array of polynomial coefficients.
 @param roots output (complex) array of roots.
@@ -1836,7 +1868,7 @@ CV_EXPORTS_W double solvePoly(InputArray coeffs, OutputArray roots, int maxIters
 
 /** @brief Calculates eigenvalues and eigenvectors of a symmetric matrix.
 
-The functions eigen calculate just eigenvalues, or eigenvalues and eigenvectors of the symmetric
+The function cv::eigen calculates just eigenvalues, or eigenvalues and eigenvectors of the symmetric
 matrix src:
 @code
     src*eigenvectors.row(i).t() = eigenvalues.at<srcType>(i)*eigenvectors.row(i).t()
@@ -1857,7 +1889,7 @@ CV_EXPORTS_W bool eigen(InputArray src, OutputArray eigenvalues,
 
 /** @brief Calculates the covariance matrix of a set of vectors.
 
-The functions calcCovarMatrix calculate the covariance matrix and, optionally, the mean vector of
+The function cv::calcCovarMatrix calculates the covariance matrix and, optionally, the mean vector of
 the set of input vectors.
 @param samples samples stored as separate matrices
 @param nsamples number of samples
@@ -1907,7 +1939,7 @@ CV_EXPORTS_W void SVBackSubst( InputArray w, InputArray u, InputArray vt,
 
 /** @brief Calculates the Mahalanobis distance between two vectors.
 
-The function Mahalanobis calculates and returns the weighted distance between two vectors:
+The function cv::Mahalanobis calculates and returns the weighted distance between two vectors:
 \f[d( \texttt{vec1} , \texttt{vec2} )= \sqrt{\sum_{i,j}{\texttt{icovar(i,j)}\cdot(\texttt{vec1}(I)-\texttt{vec2}(I))\cdot(\texttt{vec1(j)}-\texttt{vec2(j)})} }\f]
 The covariance matrix may be calculated using the cv::calcCovarMatrix function and then inverted using
 the invert function (preferably using the cv::DECOMP_SVD method, as the most accurate).
@@ -1919,7 +1951,7 @@ CV_EXPORTS_W double Mahalanobis(InputArray v1, InputArray v2, InputArray icovar)
 
 /** @brief Performs a forward or inverse Discrete Fourier transform of a 1D or 2D floating-point array.
 
-The function performs one of the following:
+The function cv::dft performs one of the following:
 -   Forward the Fourier transform of a 1D vector of N elements:
     \f[Y = F^{(N)}  \cdot X,\f]
     where \f$F^{(N)}_{jk}=\exp(-2\pi i j k/N)\f$ and \f$i=\sqrt{-1}\f$
@@ -2067,7 +2099,7 @@ CV_EXPORTS_W void idft(InputArray src, OutputArray dst, int flags = 0, int nonze
 
 /** @brief Performs a forward or inverse discrete Cosine transform of 1D or 2D array.
 
-The function dct performs a forward or inverse discrete Cosine transform (DCT) of a 1D or 2D
+The function cv::dct performs a forward or inverse discrete Cosine transform (DCT) of a 1D or 2D
 floating-point array:
 -   Forward Cosine transform of a 1D vector of N elements:
     \f[Y = C^{(N)}  \cdot X\f]
@@ -2118,7 +2150,7 @@ CV_EXPORTS_W void idct(InputArray src, OutputArray dst, int flags = 0);
 
 /** @brief Performs the per-element multiplication of two Fourier spectrums.
 
-The function mulSpectrums performs the per-element multiplication of the two CCS-packed or complex
+The function cv::mulSpectrums performs the per-element multiplication of the two CCS-packed or complex
 matrices that are results of a real or complex Fourier transform.
 
 The function, together with dft and idft , may be used to calculate convolution (pass conjB=false )
@@ -2145,7 +2177,7 @@ original one. Arrays whose size is a power-of-two (2, 4, 8, 16, 32, ...) are the
 Though, the arrays whose size is a product of 2's, 3's, and 5's (for example, 300 = 5\*5\*3\*2\*2)
 are also processed quite efficiently.
 
-The function getOptimalDFTSize returns the minimum number N that is greater than or equal to vecsize
+The function cv::getOptimalDFTSize returns the minimum number N that is greater than or equal to vecsize
 so that the DFT of a vector of size N can be processed efficiently. In the current implementation N
 = 2 ^p^ \* 3 ^q^ \* 5 ^r^ for some integer p, q, r.
 
@@ -2161,7 +2193,7 @@ CV_EXPORTS_W int getOptimalDFTSize(int vecsize);
 
 /** @brief Returns the default random number generator.
 
-The function theRNG returns the default random number generator. For each thread, there is a
+The function cv::theRNG returns the default random number generator. For each thread, there is a
 separate random number generator, so you can use the function safely in multi-thread environments.
 If you just need to get a single random number using this generator or initialize an array, you can
 use randu or randn instead. But if you are going to generate many random numbers inside a loop, it
@@ -2170,6 +2202,14 @@ is much faster to use this function to retrieve the generator and then use RNG::
 */
 CV_EXPORTS RNG& theRNG();
 
+/** @brief Sets state of default random number generator.
+
+The function cv::setRNGSeed sets state of default random number generator to custom value.
+ at param seed new state for default random number generator
+ at sa RNG, randu, randn
+*/
+CV_EXPORTS_W void setRNGSeed(int seed);
+
 /** @brief Generates a single uniformly-distributed random number or an array of random numbers.
 
 Non-template variant of the function fills the matrix dst with uniformly-distributed
@@ -2184,7 +2224,7 @@ CV_EXPORTS_W void randu(InputOutputArray dst, InputArray low, InputArray high);
 
 /** @brief Fills the array with normally distributed random numbers.
 
-The function randn fills the matrix dst with normally distributed random numbers with the specified
+The function cv::randn fills the matrix dst with normally distributed random numbers with the specified
 mean vector and the standard deviation matrix. The generated random numbers are clipped to fit the
 value range of the output array data type.
 @param dst output array of random numbers; the array must be pre-allocated and have 1 to 4 channels.
@@ -2197,7 +2237,7 @@ CV_EXPORTS_W void randn(InputOutputArray dst, InputArray mean, InputArray stddev
 
 /** @brief Shuffles the array elements randomly.
 
-The function randShuffle shuffles the specified 1D array by randomly choosing pairs of elements and
+The function cv::randShuffle shuffles the specified 1D array by randomly choosing pairs of elements and
 swapping them. The number of such swap operations will be dst.rows\*dst.cols\*iterFactor .
 @param dst input/output numerical 1D array.
 @param iterFactor scale factor that determines the number of random swap operations (see the details
@@ -2316,11 +2356,11 @@ public:
     The operator performs %PCA of the supplied dataset. It is safe to reuse
     the same PCA structure for multiple datasets. That is, if the structure
     has been previously used with another dataset, the existing internal
-    data is reclaimed and the new eigenvalues, @ref eigenvectors , and @ref
+    data is reclaimed and the new @ref eigenvalues, @ref eigenvectors and @ref
     mean are allocated and computed.
 
-    The computed eigenvalues are sorted from the largest to the smallest and
-    the corresponding eigenvectors are stored as eigenvectors rows.
+    The computed @ref eigenvalues are sorted from the largest to the smallest and
+    the corresponding @ref eigenvectors are stored as eigenvectors rows.
 
     @param data input samples stored as the matrix rows or as the matrix
     columns.
@@ -2400,11 +2440,17 @@ public:
      */
     void backProject(InputArray vec, OutputArray result) const;
 
-    /** @brief write and load PCA matrix
+    /** @brief write PCA objects
 
-*/
-    void write(FileStorage& fs ) const;
-    void read(const FileNode& fs);
+    Writes @ref eigenvalues @ref eigenvectors and @ref mean to specified FileStorage
+     */
+    void write(FileStorage& fs) const;
+
+    /** @brief load PCA objects
+
+    Loads @ref eigenvalues @ref eigenvectors and @ref mean from specified FileNode
+     */
+    void read(const FileNode& fn);
 
     Mat eigenvectors; //!< eigenvectors of the covariation matrix
     Mat eigenvalues; //!< eigenvalues of the covariation matrix
@@ -2999,7 +3045,8 @@ public:
 
      This is static template method of Algorithm. It's usage is following (in the case of SVM):
      @code
-     Ptr<SVM> svm = Algorithm::read<SVM>(fn);
+     cv::FileStorage fsRead("example.xml", FileStorage::READ);
+     Ptr<SVM> svm = Algorithm::read<SVM>(fsRead.root());
      @endcode
      In order to make this method work, the derived class must overwrite Algorithm::read(const
      FileNode& fn) and also have static create() method without parameters
@@ -3028,6 +3075,7 @@ public:
     {
         FileStorage fs(filename, FileStorage::READ);
         FileNode fn = objname.empty() ? fs.getFirstTopLevelNode() : fs[objname];
+        if (fn.empty()) return Ptr<_Tp>();
         Ptr<_Tp> obj = _Tp::create();
         obj->read(fn);
         return !obj->empty() ? obj : Ptr<_Tp>();
@@ -3059,6 +3107,9 @@ public:
     /** Returns the algorithm string identifier.
      This string is used as top level xml/yml node tag when the object is saved to a file or string. */
     CV_WRAP virtual String getDefaultName() const;
+
+protected:
+    void writeFormat(FileStorage& fs) const;
 };
 
 struct Param {
@@ -3164,5 +3215,6 @@ template<> struct ParamType<uchar>
 #include "opencv2/core/cvstd.inl.hpp"
 #include "opencv2/core/utility.hpp"
 #include "opencv2/core/optim.hpp"
+#include "opencv2/core/ovx.hpp"
 
-#endif /*__OPENCV_CORE_HPP__*/
+#endif /*OPENCV_CORE_HPP*/
diff --git a/modules/core/include/opencv2/core/affine.hpp b/modules/core/include/opencv2/core/affine.hpp
index 2bce5b9..311ff62 100644
--- a/modules/core/include/opencv2/core/affine.hpp
+++ b/modules/core/include/opencv2/core/affine.hpp
@@ -41,8 +41,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_CORE_AFFINE3_HPP__
-#define __OPENCV_CORE_AFFINE3_HPP__
+#ifndef OPENCV_CORE_AFFINE3_HPP
+#define OPENCV_CORE_AFFINE3_HPP
 
 #ifdef __cplusplus
 
@@ -241,30 +241,25 @@ void cv::Affine3<T>::rotation(const Mat3& R)
 template<typename T> inline
 void cv::Affine3<T>::rotation(const Vec3& _rvec)
 {
-    double rx = _rvec[0], ry = _rvec[1], rz = _rvec[2];
-    double theta = std::sqrt(rx*rx + ry*ry + rz*rz);
+    double theta = norm(_rvec);
 
     if (theta < DBL_EPSILON)
         rotation(Mat3::eye());
     else
     {
-        const double I[] = { 1, 0, 0, 0, 1, 0, 0, 0, 1 };
-
         double c = std::cos(theta);
         double s = std::sin(theta);
         double c1 = 1. - c;
         double itheta = (theta != 0) ? 1./theta : 0.;
 
-        rx *= itheta; ry *= itheta; rz *= itheta;
+        Point3_<T> r = _rvec*itheta;
 
-        double rrt[] = { rx*rx, rx*ry, rx*rz, rx*ry, ry*ry, ry*rz, rx*rz, ry*rz, rz*rz };
-        double _r_x_[] = { 0, -rz, ry, rz, 0, -rx, -ry, rx, 0 };
-        Mat3 R;
+        Mat3 rrt( r.x*r.x, r.x*r.y, r.x*r.z, r.x*r.y, r.y*r.y, r.y*r.z, r.x*r.z, r.y*r.z, r.z*r.z );
+        Mat3 r_x( 0, -r.z, r.y, r.z, 0, -r.x, -r.y, r.x, 0 );
 
         // R = cos(theta)*I + (1 - cos(theta))*r*rT + sin(theta)*[r_x]
         // where [r_x] is [0 -rz ry; rz 0 -rx; -ry rx 0]
-        for(int k = 0; k < 9; ++k)
-            R.val[k] = static_cast<float_type>(c*I[k] + c1*rrt[k] + s*_r_x_[k]);
+        Mat3 R = c*Mat3::eye() + c1*rrt + s*r_x;
 
         rotation(R);
     }
@@ -519,4 +514,4 @@ cv::Affine3<T>::operator Eigen::Transform<T, 3, Eigen::Affine>() const
 
 #endif /* __cplusplus */
 
-#endif /* __OPENCV_CORE_AFFINE3_HPP__ */
+#endif /* OPENCV_CORE_AFFINE3_HPP */
diff --git a/modules/core/include/opencv2/core/base.hpp b/modules/core/include/opencv2/core/base.hpp
index ed633f5..017b484 100644
--- a/modules/core/include/opencv2/core/base.hpp
+++ b/modules/core/include/opencv2/core/base.hpp
@@ -42,13 +42,15 @@
 //
 //M*/
 
-#ifndef __OPENCV_CORE_BASE_HPP__
-#define __OPENCV_CORE_BASE_HPP__
+#ifndef OPENCV_CORE_BASE_HPP
+#define OPENCV_CORE_BASE_HPP
 
 #ifndef __cplusplus
 #  error base.hpp header must be compiled as C++
 #endif
 
+#include "opencv2/opencv_modules.hpp"
+
 #include <climits>
 #include <algorithm>
 
@@ -686,4 +688,4 @@ CV_EXPORTS void setUseIPP(bool flag);
 
 #include "opencv2/core/neon_utils.hpp"
 
-#endif //__OPENCV_CORE_BASE_HPP__
+#endif //OPENCV_CORE_BASE_HPP
diff --git a/modules/core/include/opencv2/core/bufferpool.hpp b/modules/core/include/opencv2/core/bufferpool.hpp
index 76df2d2..9e7b7c2 100644
--- a/modules/core/include/opencv2/core/bufferpool.hpp
+++ b/modules/core/include/opencv2/core/bufferpool.hpp
@@ -4,8 +4,8 @@
 //
 // Copyright (C) 2014, Advanced Micro Devices, Inc., all rights reserved.
 
-#ifndef __OPENCV_CORE_BUFFER_POOL_HPP__
-#define __OPENCV_CORE_BUFFER_POOL_HPP__
+#ifndef OPENCV_CORE_BUFFER_POOL_HPP
+#define OPENCV_CORE_BUFFER_POOL_HPP
 
 namespace cv
 {
@@ -28,4 +28,4 @@ public:
 
 }
 
-#endif // __OPENCV_CORE_BUFFER_POOL_HPP__
+#endif // OPENCV_CORE_BUFFER_POOL_HPP
diff --git a/modules/core/include/opencv2/core/core_c.h b/modules/core/include/opencv2/core/core_c.h
index a0ed632..e12f79d 100644
--- a/modules/core/include/opencv2/core/core_c.h
+++ b/modules/core/include/opencv2/core/core_c.h
@@ -42,8 +42,8 @@
 //M*/
 
 
-#ifndef __OPENCV_CORE_C_H__
-#define __OPENCV_CORE_C_H__
+#ifndef OPENCV_CORE_C_H
+#define OPENCV_CORE_C_H
 
 #include "opencv2/core/types_c.h"
 
@@ -1976,8 +1976,16 @@ CVAPI(void) cvSetIPLAllocators( Cv_iplCreateImageHeader create_header,
 
 The function opens file storage for reading or writing data. In the latter case, a new file is
 created or an existing file is rewritten. The type of the read or written file is determined by the
-filename extension: .xml for XML and .yml or .yaml for YAML. The function returns a pointer to the
-CvFileStorage structure. If the file cannot be opened then the function returns NULL.
+filename extension: .xml for XML, .yml or .yaml for YAML and .json for JSON.
+
+At the same time, it also supports adding parameters like "example.xml?base64". The three ways
+are the same:
+ at snippet samples/cpp/filestorage_base64.cpp suffix_in_file_name
+ at snippet samples/cpp/filestorage_base64.cpp flag_write_base64
+ at snippet samples/cpp/filestorage_base64.cpp flag_write_and_flag_base64
+
+The function returns a pointer to the CvFileStorage structure.
+If the file cannot be opened then the function returns NULL.
 @param filename Name of the file associated with the storage
 @param memstorage Memory storage used for temporary data and for
 :   storing dynamic structures, such as CvSeq or CvGraph . If it is NULL, a temporary memory
@@ -1985,6 +1993,7 @@ CvFileStorage structure. If the file cannot be opened then the function returns
 @param flags Can be one of the following:
 > -   **CV_STORAGE_READ** the storage is open for reading
 > -   **CV_STORAGE_WRITE** the storage is open for writing
+      (use **CV_STORAGE_WRITE | CV_STORAGE_WRITE_BASE64** to write rawdata in Base64)
 @param encoding
  */
 CVAPI(CvFileStorage*)  cvOpenFileStorage( const char* filename, CvMemStorage* memstorage,
@@ -2022,7 +2031,8 @@ One and only one of the two above flags must be specified
 @param type_name Optional parameter - the object type name. In
     case of XML it is written as a type_id attribute of the structure opening tag. In the case of
     YAML it is written after a colon following the structure name (see the example in
-    CvFileStorage description). Mainly it is used with user objects. When the storage is read, the
+    CvFileStorage description). In case of JSON it is written as a name/value pair.
+    Mainly it is used with user objects. When the storage is read, the
     encoded type name is used to determine the object type (see CvTypeInfo and cvFindType ).
 @param attributes This parameter is not used in the current implementation
  */
@@ -2162,7 +2172,7 @@ the file with multiple streams looks like this:
 @endcode
 The YAML file will look like this:
 @code{.yaml}
-    %YAML:1.0
+    %YAML 1.0
     # stream #1 data
     ...
     ---
@@ -2187,6 +2197,28 @@ to a sequence rather than a map.
 CVAPI(void) cvWriteRawData( CvFileStorage* fs, const void* src,
                                 int len, const char* dt );
 
+/** @brief Writes multiple numbers in Base64.
+
+If either CV_STORAGE_WRITE_BASE64 or cv::FileStorage::WRITE_BASE64 is used,
+this function will be the same as cvWriteRawData. If neither, the main
+difference is that it outputs a sequence in Base64 encoding rather than
+in plain text.
+
+This function can only be used to write a sequence with a type "binary".
+
+Consider the following two examples where their output is the same:
+ at snippet samples/cpp/filestorage_base64.cpp without_base64_flag
+and
+ at snippet samples/cpp/filestorage_base64.cpp with_write_base64_flag
+
+ at param fs File storage
+ at param src Pointer to the written array
+ at param len Number of the array elements to write
+ at param dt Specification of each array element, see @ref format_spec "format specification"
+*/
+CVAPI(void) cvWriteRawDataBase64( CvFileStorage* fs, const void* src,
+                                 int len, const char* dt );
+
 /** @brief Returns a unique pointer for a given name.
 
 The function returns a unique pointer for each particular file node name. This pointer can be then
@@ -2468,7 +2500,7 @@ CVAPI(void) cvReadRawData( const CvFileStorage* fs, const CvFileNode* src,
 /** @brief Writes a file node to another file storage.
 
 The function writes a copy of a file node to file storage. Possible applications of the function are
-merging several file storages into one and conversion between XML and YAML formats.
+merging several file storages into one and conversion between XML, YAML and JSON formats.
 @param fs Destination file storage
 @param new_node_name New name of the file node in the destination file storage. To keep the
 existing name, use cvcvGetFileNodeName
diff --git a/modules/core/include/opencv2/core/cuda.hpp b/modules/core/include/opencv2/core/cuda.hpp
index 64bc53e..c538392 100644
--- a/modules/core/include/opencv2/core/cuda.hpp
+++ b/modules/core/include/opencv2/core/cuda.hpp
@@ -41,8 +41,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_CORE_CUDA_HPP__
-#define __OPENCV_CORE_CUDA_HPP__
+#ifndef OPENCV_CORE_CUDA_HPP
+#define OPENCV_CORE_CUDA_HPP
 
 #ifndef __cplusplus
 #  error cuda.hpp header must be compiled as C++
@@ -447,7 +447,26 @@ CV_EXPORTS void unregisterPageLocked(Mat& m);
 functions use the constant GPU memory, and next call may update the memory before the previous one
 has been finished. But calling different operations asynchronously is safe because each operation
 has its own constant buffer. Memory copy/upload/download/set operations to the buffers you hold are
-also safe. :
+also safe.
+
+ at note The Stream class is not thread-safe. Please use different Stream objects for different CPU threads.
+
+ at code
+void thread1()
+{
+    cv::cuda::Stream stream1;
+    cv::cuda::func1(..., stream1);
+}
+
+void thread2()
+{
+    cv::cuda::Stream stream2;
+    cv::cuda::func2(..., stream2);
+}
+ at endcode
+
+ at note By default all CUDA routines are launched in Stream::Null() object, if the stream is not specified by user.
+In multi-threading environment the stream objects must be passed explicitly (see previous note).
  */
 class CV_EXPORTS Stream
 {
@@ -836,6 +855,15 @@ private:
 CV_EXPORTS void printCudaDeviceInfo(int device);
 CV_EXPORTS void printShortCudaDeviceInfo(int device);
 
+/** @brief Converts an array to half precision floating number.
+
+ at param _src input array.
+ at param _dst output array.
+ at param stream Stream for the asynchronous version.
+ at sa convertFp16
+*/
+CV_EXPORTS void convertFp16(InputArray _src, OutputArray _dst, Stream& stream = Stream::Null());
+
 //! @} cudacore_init
 
 }} // namespace cv { namespace cuda {
@@ -843,4 +871,4 @@ CV_EXPORTS void printShortCudaDeviceInfo(int device);
 
 #include "opencv2/core/cuda.inl.hpp"
 
-#endif /* __OPENCV_CORE_CUDA_HPP__ */
+#endif /* OPENCV_CORE_CUDA_HPP */
diff --git a/modules/core/include/opencv2/core/cuda.inl.hpp b/modules/core/include/opencv2/core/cuda.inl.hpp
index 01dc6d7..35ae2e4 100644
--- a/modules/core/include/opencv2/core/cuda.inl.hpp
+++ b/modules/core/include/opencv2/core/cuda.inl.hpp
@@ -41,8 +41,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_CORE_CUDAINL_HPP__
-#define __OPENCV_CORE_CUDAINL_HPP__
+#ifndef OPENCV_CORE_CUDAINL_HPP
+#define OPENCV_CORE_CUDAINL_HPP
 
 #include "opencv2/core/cuda.hpp"
 
@@ -628,4 +628,4 @@ Mat::Mat(const cuda::GpuMat& m)
 
 //! @endcond
 
-#endif // __OPENCV_CORE_CUDAINL_HPP__
+#endif // OPENCV_CORE_CUDAINL_HPP
diff --git a/modules/core/include/opencv2/core/cuda/block.hpp b/modules/core/include/opencv2/core/cuda/block.hpp
index 0c6f063..330cf1d 100644
--- a/modules/core/include/opencv2/core/cuda/block.hpp
+++ b/modules/core/include/opencv2/core/cuda/block.hpp
@@ -40,8 +40,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_CUDA_DEVICE_BLOCK_HPP__
-#define __OPENCV_CUDA_DEVICE_BLOCK_HPP__
+#ifndef OPENCV_CUDA_DEVICE_BLOCK_HPP
+#define OPENCV_CUDA_DEVICE_BLOCK_HPP
 
 /** @file
  * @deprecated Use @ref cudev instead.
@@ -208,4 +208,4 @@ namespace cv { namespace cuda { namespace device
 
 //! @endcond
 
-#endif /* __OPENCV_CUDA_DEVICE_BLOCK_HPP__ */
+#endif /* OPENCV_CUDA_DEVICE_BLOCK_HPP */
diff --git a/modules/core/include/opencv2/core/cuda/border_interpolate.hpp b/modules/core/include/opencv2/core/cuda/border_interpolate.hpp
index a204155..874f705 100644
--- a/modules/core/include/opencv2/core/cuda/border_interpolate.hpp
+++ b/modules/core/include/opencv2/core/cuda/border_interpolate.hpp
@@ -40,8 +40,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_CUDA_BORDER_INTERPOLATE_HPP__
-#define __OPENCV_CUDA_BORDER_INTERPOLATE_HPP__
+#ifndef OPENCV_CUDA_BORDER_INTERPOLATE_HPP
+#define OPENCV_CUDA_BORDER_INTERPOLATE_HPP
 
 #include "saturate_cast.hpp"
 #include "vec_traits.hpp"
@@ -719,4 +719,4 @@ namespace cv { namespace cuda { namespace device
 
 //! @endcond
 
-#endif // __OPENCV_CUDA_BORDER_INTERPOLATE_HPP__
+#endif // OPENCV_CUDA_BORDER_INTERPOLATE_HPP
diff --git a/modules/core/include/opencv2/core/cuda/color.hpp b/modules/core/include/opencv2/core/cuda/color.hpp
index 6faf8c9..dcce280 100644
--- a/modules/core/include/opencv2/core/cuda/color.hpp
+++ b/modules/core/include/opencv2/core/cuda/color.hpp
@@ -40,8 +40,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_CUDA_COLOR_HPP__
-#define __OPENCV_CUDA_COLOR_HPP__
+#ifndef OPENCV_CUDA_COLOR_HPP
+#define OPENCV_CUDA_COLOR_HPP
 
 #include "detail/color_detail.hpp"
 
@@ -306,4 +306,4 @@ namespace cv { namespace cuda { namespace device
 
 //! @endcond
 
-#endif // __OPENCV_CUDA_BORDER_INTERPOLATE_HPP__
+#endif // OPENCV_CUDA_COLOR_HPP
diff --git a/modules/core/include/opencv2/core/cuda/common.hpp b/modules/core/include/opencv2/core/cuda/common.hpp
index b93c3ef..14b1f3f 100644
--- a/modules/core/include/opencv2/core/cuda/common.hpp
+++ b/modules/core/include/opencv2/core/cuda/common.hpp
@@ -40,8 +40,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_CUDA_COMMON_HPP__
-#define __OPENCV_CUDA_COMMON_HPP__
+#ifndef OPENCV_CUDA_COMMON_HPP
+#define OPENCV_CUDA_COMMON_HPP
 
 #include <cuda_runtime.h>
 #include "opencv2/core/cuda_types.hpp"
@@ -106,4 +106,4 @@ namespace cv { namespace cuda
 
 //! @endcond
 
-#endif // __OPENCV_CUDA_COMMON_HPP__
+#endif // OPENCV_CUDA_COMMON_HPP
diff --git a/modules/core/include/opencv2/core/cuda/datamov_utils.hpp b/modules/core/include/opencv2/core/cuda/datamov_utils.hpp
index bb02cf9..6820d0f 100644
--- a/modules/core/include/opencv2/core/cuda/datamov_utils.hpp
+++ b/modules/core/include/opencv2/core/cuda/datamov_utils.hpp
@@ -40,8 +40,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_CUDA_DATAMOV_UTILS_HPP__
-#define __OPENCV_CUDA_DATAMOV_UTILS_HPP__
+#ifndef OPENCV_CUDA_DATAMOV_UTILS_HPP
+#define OPENCV_CUDA_DATAMOV_UTILS_HPP
 
 #include "common.hpp"
 
@@ -110,4 +110,4 @@ namespace cv { namespace cuda { namespace device
 
 //! @endcond
 
-#endif // __OPENCV_CUDA_DATAMOV_UTILS_HPP__
+#endif // OPENCV_CUDA_DATAMOV_UTILS_HPP
diff --git a/modules/core/include/opencv2/core/cuda/detail/color_detail.hpp b/modules/core/include/opencv2/core/cuda/detail/color_detail.hpp
index 1151806..bfb4055 100644
--- a/modules/core/include/opencv2/core/cuda/detail/color_detail.hpp
+++ b/modules/core/include/opencv2/core/cuda/detail/color_detail.hpp
@@ -40,8 +40,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_CUDA_COLOR_DETAIL_HPP__
-#define __OPENCV_CUDA_COLOR_DETAIL_HPP__
+#ifndef OPENCV_CUDA_COLOR_DETAIL_HPP
+#define OPENCV_CUDA_COLOR_DETAIL_HPP
 
 #include "../common.hpp"
 #include "../vec_traits.hpp"
@@ -1977,4 +1977,4 @@ namespace cv { namespace cuda { namespace device
 
 //! @endcond
 
-#endif // __OPENCV_CUDA_COLOR_DETAIL_HPP__
+#endif // OPENCV_CUDA_COLOR_DETAIL_HPP
diff --git a/modules/core/include/opencv2/core/cuda/detail/reduce.hpp b/modules/core/include/opencv2/core/cuda/detail/reduce.hpp
index 0c35eab..ff82c3c 100644
--- a/modules/core/include/opencv2/core/cuda/detail/reduce.hpp
+++ b/modules/core/include/opencv2/core/cuda/detail/reduce.hpp
@@ -40,8 +40,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_CUDA_REDUCE_DETAIL_HPP__
-#define __OPENCV_CUDA_REDUCE_DETAIL_HPP__
+#ifndef OPENCV_CUDA_REDUCE_DETAIL_HPP
+#define OPENCV_CUDA_REDUCE_DETAIL_HPP
 
 #include <thrust/tuple.h>
 #include "../warp.hpp"
@@ -275,7 +275,7 @@ namespace cv { namespace cuda { namespace device
             template <typename Pointer, typename Reference, class Op>
             static __device__ void reduce(Pointer smem, Reference val, unsigned int tid, Op op)
             {
-            #if __CUDA_ARCH__ >= 300
+            #if defined __CUDA_ARCH__ && __CUDA_ARCH__ >= 300
                 (void) smem;
                 (void) tid;
 
@@ -298,7 +298,7 @@ namespace cv { namespace cuda { namespace device
             {
                 const unsigned int laneId = Warp::laneId();
 
-            #if __CUDA_ARCH__ >= 300
+            #if defined __CUDA_ARCH__ && __CUDA_ARCH__ >= 300
                 Unroll<16, Pointer, Reference, Op>::loopShfl(val, op, warpSize);
 
                 if (laneId == 0)
@@ -321,7 +321,7 @@ namespace cv { namespace cuda { namespace device
 
                 if (tid < 32)
                 {
-                #if __CUDA_ARCH__ >= 300
+                #if defined __CUDA_ARCH__ && __CUDA_ARCH__ >= 300
                     Unroll<M / 2, Pointer, Reference, Op>::loopShfl(val, op, M);
                 #else
                     Unroll<M / 2, Pointer, Reference, Op>::loop(smem, val, tid, op);
@@ -362,4 +362,4 @@ namespace cv { namespace cuda { namespace device
 
 //! @endcond
 
-#endif // __OPENCV_CUDA_REDUCE_DETAIL_HPP__
+#endif // OPENCV_CUDA_REDUCE_DETAIL_HPP
diff --git a/modules/core/include/opencv2/core/cuda/detail/reduce_key_val.hpp b/modules/core/include/opencv2/core/cuda/detail/reduce_key_val.hpp
index bab85d7..6a537c9 100644
--- a/modules/core/include/opencv2/core/cuda/detail/reduce_key_val.hpp
+++ b/modules/core/include/opencv2/core/cuda/detail/reduce_key_val.hpp
@@ -40,8 +40,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_CUDA_PRED_VAL_REDUCE_DETAIL_HPP__
-#define __OPENCV_CUDA_PRED_VAL_REDUCE_DETAIL_HPP__
+#ifndef OPENCV_CUDA_PRED_VAL_REDUCE_DETAIL_HPP
+#define OPENCV_CUDA_PRED_VAL_REDUCE_DETAIL_HPP
 
 #include <thrust/tuple.h>
 #include "../warp.hpp"
@@ -499,4 +499,4 @@ namespace cv { namespace cuda { namespace device
 
 //! @endcond
 
-#endif // __OPENCV_CUDA_PRED_VAL_REDUCE_DETAIL_HPP__
+#endif // OPENCV_CUDA_PRED_VAL_REDUCE_DETAIL_HPP
diff --git a/modules/core/include/opencv2/core/cuda/detail/transform_detail.hpp b/modules/core/include/opencv2/core/cuda/detail/transform_detail.hpp
index 96031c8..3b72b03 100644
--- a/modules/core/include/opencv2/core/cuda/detail/transform_detail.hpp
+++ b/modules/core/include/opencv2/core/cuda/detail/transform_detail.hpp
@@ -40,8 +40,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_CUDA_TRANSFORM_DETAIL_HPP__
-#define __OPENCV_CUDA_TRANSFORM_DETAIL_HPP__
+#ifndef OPENCV_CUDA_TRANSFORM_DETAIL_HPP
+#define OPENCV_CUDA_TRANSFORM_DETAIL_HPP
 
 #include "../common.hpp"
 #include "../vec_traits.hpp"
@@ -396,4 +396,4 @@ namespace cv { namespace cuda { namespace device
 
 //! @endcond
 
-#endif // __OPENCV_CUDA_TRANSFORM_DETAIL_HPP__
+#endif // OPENCV_CUDA_TRANSFORM_DETAIL_HPP
diff --git a/modules/core/include/opencv2/core/cuda/detail/type_traits_detail.hpp b/modules/core/include/opencv2/core/cuda/detail/type_traits_detail.hpp
index 3463c78..a78bd2c 100644
--- a/modules/core/include/opencv2/core/cuda/detail/type_traits_detail.hpp
+++ b/modules/core/include/opencv2/core/cuda/detail/type_traits_detail.hpp
@@ -40,8 +40,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_CUDA_TYPE_TRAITS_DETAIL_HPP__
-#define __OPENCV_CUDA_TYPE_TRAITS_DETAIL_HPP__
+#ifndef OPENCV_CUDA_TYPE_TRAITS_DETAIL_HPP
+#define OPENCV_CUDA_TYPE_TRAITS_DETAIL_HPP
 
 #include "../common.hpp"
 #include "../vec_traits.hpp"
@@ -188,4 +188,4 @@ namespace cv { namespace cuda { namespace device
 
 //! @endcond
 
-#endif // __OPENCV_CUDA_TYPE_TRAITS_DETAIL_HPP__
+#endif // OPENCV_CUDA_TYPE_TRAITS_DETAIL_HPP
diff --git a/modules/core/include/opencv2/core/cuda/detail/vec_distance_detail.hpp b/modules/core/include/opencv2/core/cuda/detail/vec_distance_detail.hpp
index 9ca85a5..8283a99 100644
--- a/modules/core/include/opencv2/core/cuda/detail/vec_distance_detail.hpp
+++ b/modules/core/include/opencv2/core/cuda/detail/vec_distance_detail.hpp
@@ -40,8 +40,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_CUDA_VEC_DISTANCE_DETAIL_HPP__
-#define __OPENCV_CUDA_VEC_DISTANCE_DETAIL_HPP__
+#ifndef OPENCV_CUDA_VEC_DISTANCE_DETAIL_HPP
+#define OPENCV_CUDA_VEC_DISTANCE_DETAIL_HPP
 
 #include "../datamov_utils.hpp"
 
@@ -118,4 +118,4 @@ namespace cv { namespace cuda { namespace device
 
 //! @endcond
 
-#endif // __OPENCV_CUDA_VEC_DISTANCE_DETAIL_HPP__
+#endif // OPENCV_CUDA_VEC_DISTANCE_DETAIL_HPP
diff --git a/modules/core/include/opencv2/core/cuda/dynamic_smem.hpp b/modules/core/include/opencv2/core/cuda/dynamic_smem.hpp
index 3488463..42570c6 100644
--- a/modules/core/include/opencv2/core/cuda/dynamic_smem.hpp
+++ b/modules/core/include/opencv2/core/cuda/dynamic_smem.hpp
@@ -40,8 +40,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_CUDA_DYNAMIC_SMEM_HPP__
-#define __OPENCV_CUDA_DYNAMIC_SMEM_HPP__
+#ifndef OPENCV_CUDA_DYNAMIC_SMEM_HPP
+#define OPENCV_CUDA_DYNAMIC_SMEM_HPP
 
 /** @file
  * @deprecated Use @ref cudev instead.
@@ -85,4 +85,4 @@ namespace cv { namespace cuda { namespace device
 
 //! @endcond
 
-#endif // __OPENCV_CUDA_DYNAMIC_SMEM_HPP__
+#endif // OPENCV_CUDA_DYNAMIC_SMEM_HPP
diff --git a/modules/core/include/opencv2/core/cuda/filters.hpp b/modules/core/include/opencv2/core/cuda/filters.hpp
index 9adc00c..c2e24dd 100644
--- a/modules/core/include/opencv2/core/cuda/filters.hpp
+++ b/modules/core/include/opencv2/core/cuda/filters.hpp
@@ -40,8 +40,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_CUDA_FILTERS_HPP__
-#define __OPENCV_CUDA_FILTERS_HPP__
+#ifndef OPENCV_CUDA_FILTERS_HPP
+#define OPENCV_CUDA_FILTERS_HPP
 
 #include "saturate_cast.hpp"
 #include "vec_traits.hpp"
@@ -283,4 +283,4 @@ namespace cv { namespace cuda { namespace device
 
 //! @endcond
 
-#endif // __OPENCV_CUDA_FILTERS_HPP__
+#endif // OPENCV_CUDA_FILTERS_HPP
diff --git a/modules/core/include/opencv2/core/cuda/funcattrib.hpp b/modules/core/include/opencv2/core/cuda/funcattrib.hpp
index fbb236b..f582080 100644
--- a/modules/core/include/opencv2/core/cuda/funcattrib.hpp
+++ b/modules/core/include/opencv2/core/cuda/funcattrib.hpp
@@ -40,8 +40,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_CUDA_DEVICE_FUNCATTRIB_HPP_
-#define __OPENCV_CUDA_DEVICE_FUNCATTRIB_HPP_
+#ifndef OPENCV_CUDA_DEVICE_FUNCATTRIB_HPP
+#define OPENCV_CUDA_DEVICE_FUNCATTRIB_HPP
 
 #include <cstdio>
 
@@ -76,4 +76,4 @@ namespace cv { namespace cuda { namespace device
 
 //! @endcond
 
-#endif  /* __OPENCV_CUDA_DEVICE_FUNCATTRIB_HPP_ */
+#endif  /* OPENCV_CUDA_DEVICE_FUNCATTRIB_HPP */
diff --git a/modules/core/include/opencv2/core/cuda/functional.hpp b/modules/core/include/opencv2/core/cuda/functional.hpp
index ed3943d..5b8a7eb 100644
--- a/modules/core/include/opencv2/core/cuda/functional.hpp
+++ b/modules/core/include/opencv2/core/cuda/functional.hpp
@@ -40,8 +40,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_CUDA_FUNCTIONAL_HPP__
-#define __OPENCV_CUDA_FUNCTIONAL_HPP__
+#ifndef OPENCV_CUDA_FUNCTIONAL_HPP
+#define OPENCV_CUDA_FUNCTIONAL_HPP
 
 #include <functional>
 #include "saturate_cast.hpp"
@@ -794,4 +794,4 @@ namespace cv { namespace cuda { namespace device
 
 //! @endcond
 
-#endif // __OPENCV_CUDA_FUNCTIONAL_HPP__
+#endif // OPENCV_CUDA_FUNCTIONAL_HPP
diff --git a/modules/core/include/opencv2/core/cuda/limits.hpp b/modules/core/include/opencv2/core/cuda/limits.hpp
index b98bdf2..7e15ed6 100644
--- a/modules/core/include/opencv2/core/cuda/limits.hpp
+++ b/modules/core/include/opencv2/core/cuda/limits.hpp
@@ -40,8 +40,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_CUDA_LIMITS_HPP__
-#define __OPENCV_CUDA_LIMITS_HPP__
+#ifndef OPENCV_CUDA_LIMITS_HPP
+#define OPENCV_CUDA_LIMITS_HPP
 
 #include <limits.h>
 #include <float.h>
@@ -125,4 +125,4 @@ template <> struct numeric_limits<double>
 
 //! @endcond
 
-#endif // __OPENCV_CUDA_LIMITS_HPP__
+#endif // OPENCV_CUDA_LIMITS_HPP
diff --git a/modules/core/include/opencv2/core/cuda/reduce.hpp b/modules/core/include/opencv2/core/cuda/reduce.hpp
index 3133c9a..5de3650 100644
--- a/modules/core/include/opencv2/core/cuda/reduce.hpp
+++ b/modules/core/include/opencv2/core/cuda/reduce.hpp
@@ -40,8 +40,12 @@
 //
 //M*/
 
-#ifndef __OPENCV_CUDA_REDUCE_HPP__
-#define __OPENCV_CUDA_REDUCE_HPP__
+#ifndef OPENCV_CUDA_REDUCE_HPP
+#define OPENCV_CUDA_REDUCE_HPP
+
+#ifndef THRUST_DEBUG // eliminate -Wundef warning
+#define THRUST_DEBUG 0
+#endif
 
 #include <thrust/tuple.h>
 #include "detail/reduce.hpp"
@@ -202,4 +206,4 @@ namespace cv { namespace cuda { namespace device
 
 //! @endcond
 
-#endif // __OPENCV_CUDA_UTILITY_HPP__
+#endif // OPENCV_CUDA_REDUCE_HPP
diff --git a/modules/core/include/opencv2/core/cuda/saturate_cast.hpp b/modules/core/include/opencv2/core/cuda/saturate_cast.hpp
index e7633c7..c3a3d1c 100644
--- a/modules/core/include/opencv2/core/cuda/saturate_cast.hpp
+++ b/modules/core/include/opencv2/core/cuda/saturate_cast.hpp
@@ -40,8 +40,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_CUDA_SATURATE_CAST_HPP__
-#define __OPENCV_CUDA_SATURATE_CAST_HPP__
+#ifndef OPENCV_CUDA_SATURATE_CAST_HPP
+#define OPENCV_CUDA_SATURATE_CAST_HPP
 
 #include "common.hpp"
 
@@ -101,7 +101,7 @@ namespace cv { namespace cuda { namespace device
     }
     template<> __device__ __forceinline__ uchar saturate_cast<uchar>(double v)
     {
-    #if __CUDA_ARCH__ >= 130
+    #if defined __CUDA_ARCH__ && __CUDA_ARCH__ >= 130
         uint res = 0;
         asm("cvt.rni.sat.u8.f64 %0, %1;" : "=r"(res) : "d"(v));
         return res;
@@ -149,7 +149,7 @@ namespace cv { namespace cuda { namespace device
     }
     template<> __device__ __forceinline__ schar saturate_cast<schar>(double v)
     {
-    #if __CUDA_ARCH__ >= 130
+    #if defined __CUDA_ARCH__ && __CUDA_ARCH__ >= 130
         uint res = 0;
         asm("cvt.rni.sat.s8.f64 %0, %1;" : "=r"(res) : "d"(v));
         return res;
@@ -191,7 +191,7 @@ namespace cv { namespace cuda { namespace device
     }
     template<> __device__ __forceinline__ ushort saturate_cast<ushort>(double v)
     {
-    #if __CUDA_ARCH__ >= 130
+    #if defined __CUDA_ARCH__ && __CUDA_ARCH__ >= 130
         ushort res = 0;
         asm("cvt.rni.sat.u16.f64 %0, %1;" : "=h"(res) : "d"(v));
         return res;
@@ -226,7 +226,7 @@ namespace cv { namespace cuda { namespace device
     }
     template<> __device__ __forceinline__ short saturate_cast<short>(double v)
     {
-    #if __CUDA_ARCH__ >= 130
+    #if defined __CUDA_ARCH__ && __CUDA_ARCH__ >= 130
         short res = 0;
         asm("cvt.rni.sat.s16.f64 %0, %1;" : "=h"(res) : "d"(v));
         return res;
@@ -289,4 +289,4 @@ namespace cv { namespace cuda { namespace device
 
 //! @endcond
 
-#endif /* __OPENCV_CUDA_SATURATE_CAST_HPP__ */
+#endif /* OPENCV_CUDA_SATURATE_CAST_HPP */
diff --git a/modules/core/include/opencv2/core/cuda/scan.hpp b/modules/core/include/opencv2/core/cuda/scan.hpp
index 687abb5..e07ee65 100644
--- a/modules/core/include/opencv2/core/cuda/scan.hpp
+++ b/modules/core/include/opencv2/core/cuda/scan.hpp
@@ -40,8 +40,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_CUDA_SCAN_HPP__
-#define __OPENCV_CUDA_SCAN_HPP__
+#ifndef OPENCV_CUDA_SCAN_HPP
+#define OPENCV_CUDA_SCAN_HPP
 
 #include "opencv2/core/cuda/common.hpp"
 #include "opencv2/core/cuda/utility.hpp"
@@ -255,4 +255,4 @@ namespace cv { namespace cuda { namespace device
 
 //! @endcond
 
-#endif // __OPENCV_CUDA_SCAN_HPP__
+#endif // OPENCV_CUDA_SCAN_HPP
diff --git a/modules/core/include/opencv2/core/cuda/simd_functions.hpp b/modules/core/include/opencv2/core/cuda/simd_functions.hpp
index b9e0041..3d8c2e0 100644
--- a/modules/core/include/opencv2/core/cuda/simd_functions.hpp
+++ b/modules/core/include/opencv2/core/cuda/simd_functions.hpp
@@ -70,8 +70,8 @@
  * POSSIBILITY OF SUCH DAMAGE.
  */
 
-#ifndef __OPENCV_CUDA_SIMD_FUNCTIONS_HPP__
-#define __OPENCV_CUDA_SIMD_FUNCTIONS_HPP__
+#ifndef OPENCV_CUDA_SIMD_FUNCTIONS_HPP
+#define OPENCV_CUDA_SIMD_FUNCTIONS_HPP
 
 #include "common.hpp"
 
@@ -866,4 +866,4 @@ namespace cv { namespace cuda { namespace device
 
 //! @endcond
 
-#endif // __OPENCV_CUDA_SIMD_FUNCTIONS_HPP__
+#endif // OPENCV_CUDA_SIMD_FUNCTIONS_HPP
diff --git a/modules/core/include/opencv2/core/cuda/transform.hpp b/modules/core/include/opencv2/core/cuda/transform.hpp
index 08a313d..42aa6ea 100644
--- a/modules/core/include/opencv2/core/cuda/transform.hpp
+++ b/modules/core/include/opencv2/core/cuda/transform.hpp
@@ -40,8 +40,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_CUDA_TRANSFORM_HPP__
-#define __OPENCV_CUDA_TRANSFORM_HPP__
+#ifndef OPENCV_CUDA_TRANSFORM_HPP
+#define OPENCV_CUDA_TRANSFORM_HPP
 
 #include "common.hpp"
 #include "utility.hpp"
@@ -72,4 +72,4 @@ namespace cv { namespace cuda { namespace device
 
 //! @endcond
 
-#endif // __OPENCV_CUDA_TRANSFORM_HPP__
+#endif // OPENCV_CUDA_TRANSFORM_HPP
diff --git a/modules/core/include/opencv2/core/cuda/type_traits.hpp b/modules/core/include/opencv2/core/cuda/type_traits.hpp
index f2471eb..8b7a3fd 100644
--- a/modules/core/include/opencv2/core/cuda/type_traits.hpp
+++ b/modules/core/include/opencv2/core/cuda/type_traits.hpp
@@ -40,8 +40,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_CUDA_TYPE_TRAITS_HPP__
-#define __OPENCV_CUDA_TYPE_TRAITS_HPP__
+#ifndef OPENCV_CUDA_TYPE_TRAITS_HPP
+#define OPENCV_CUDA_TYPE_TRAITS_HPP
 
 #include "detail/type_traits_detail.hpp"
 
@@ -87,4 +87,4 @@ namespace cv { namespace cuda { namespace device
 
 //! @endcond
 
-#endif // __OPENCV_CUDA_TYPE_TRAITS_HPP__
+#endif // OPENCV_CUDA_TYPE_TRAITS_HPP
diff --git a/modules/core/include/opencv2/core/cuda/utility.hpp b/modules/core/include/opencv2/core/cuda/utility.hpp
index ed60471..7f5db48 100644
--- a/modules/core/include/opencv2/core/cuda/utility.hpp
+++ b/modules/core/include/opencv2/core/cuda/utility.hpp
@@ -40,8 +40,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_CUDA_UTILITY_HPP__
-#define __OPENCV_CUDA_UTILITY_HPP__
+#ifndef OPENCV_CUDA_UTILITY_HPP
+#define OPENCV_CUDA_UTILITY_HPP
 
 #include "saturate_cast.hpp"
 #include "datamov_utils.hpp"
@@ -54,6 +54,15 @@
 
 namespace cv { namespace cuda { namespace device
 {
+    struct CV_EXPORTS ThrustAllocator
+    {
+        typedef uchar value_type;
+        virtual ~ThrustAllocator();
+        virtual __device__ __host__ uchar* allocate(size_t numBytes) = 0;
+        virtual __device__ __host__ void deallocate(uchar* ptr, size_t numBytes) = 0;
+        static ThrustAllocator& getAllocator();
+        static void setAllocator(ThrustAllocator* allocator);
+    };
     #define OPENCV_CUDA_LOG_WARP_SIZE        (5)
     #define OPENCV_CUDA_WARP_SIZE            (1 << OPENCV_CUDA_LOG_WARP_SIZE)
     #define OPENCV_CUDA_LOG_MEM_BANKS        ((__CUDA_ARCH__ >= 200) ? 5 : 4) // 32 banks on fermi, 16 on tesla
@@ -218,4 +227,4 @@ namespace cv { namespace cuda { namespace device
 
 //! @endcond
 
-#endif // __OPENCV_CUDA_UTILITY_HPP__
+#endif // OPENCV_CUDA_UTILITY_HPP
diff --git a/modules/core/include/opencv2/core/cuda/vec_distance.hpp b/modules/core/include/opencv2/core/cuda/vec_distance.hpp
index 013b747..ef6e510 100644
--- a/modules/core/include/opencv2/core/cuda/vec_distance.hpp
+++ b/modules/core/include/opencv2/core/cuda/vec_distance.hpp
@@ -40,8 +40,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_CUDA_VEC_DISTANCE_HPP__
-#define __OPENCV_CUDA_VEC_DISTANCE_HPP__
+#ifndef OPENCV_CUDA_VEC_DISTANCE_HPP
+#define OPENCV_CUDA_VEC_DISTANCE_HPP
 
 #include "reduce.hpp"
 #include "functional.hpp"
@@ -229,4 +229,4 @@ namespace cv { namespace cuda { namespace device
 
 //! @endcond
 
-#endif // __OPENCV_CUDA_VEC_DISTANCE_HPP__
+#endif // OPENCV_CUDA_VEC_DISTANCE_HPP
diff --git a/modules/core/include/opencv2/core/cuda/vec_math.hpp b/modules/core/include/opencv2/core/cuda/vec_math.hpp
index 8595fb8..9085b92 100644
--- a/modules/core/include/opencv2/core/cuda/vec_math.hpp
+++ b/modules/core/include/opencv2/core/cuda/vec_math.hpp
@@ -40,8 +40,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_CUDA_VECMATH_HPP__
-#define __OPENCV_CUDA_VECMATH_HPP__
+#ifndef OPENCV_CUDA_VECMATH_HPP
+#define OPENCV_CUDA_VECMATH_HPP
 
 #include "vec_traits.hpp"
 #include "saturate_cast.hpp"
@@ -927,4 +927,4 @@ CV_CUDEV_IMPLEMENT_SCALAR_BINARY_FUNC(atan2, ::atan2, double, double, double)
 
 //! @endcond
 
-#endif // __OPENCV_CUDA_VECMATH_HPP__
+#endif // OPENCV_CUDA_VECMATH_HPP
diff --git a/modules/core/include/opencv2/core/cuda/vec_traits.hpp b/modules/core/include/opencv2/core/cuda/vec_traits.hpp
index 905e37f..b5ff281 100644
--- a/modules/core/include/opencv2/core/cuda/vec_traits.hpp
+++ b/modules/core/include/opencv2/core/cuda/vec_traits.hpp
@@ -40,8 +40,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_CUDA_VEC_TRAITS_HPP__
-#define __OPENCV_CUDA_VEC_TRAITS_HPP__
+#ifndef OPENCV_CUDA_VEC_TRAITS_HPP
+#define OPENCV_CUDA_VEC_TRAITS_HPP
 
 #include "common.hpp"
 
@@ -285,4 +285,4 @@ namespace cv { namespace cuda { namespace device
 
 //! @endcond
 
-#endif // __OPENCV_CUDA_VEC_TRAITS_HPP__
+#endif // OPENCV_CUDA_VEC_TRAITS_HPP
diff --git a/modules/core/include/opencv2/core/cuda/warp.hpp b/modules/core/include/opencv2/core/cuda/warp.hpp
index d93afe7..ae1f8ea 100644
--- a/modules/core/include/opencv2/core/cuda/warp.hpp
+++ b/modules/core/include/opencv2/core/cuda/warp.hpp
@@ -40,8 +40,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_CUDA_DEVICE_WARP_HPP__
-#define __OPENCV_CUDA_DEVICE_WARP_HPP__
+#ifndef OPENCV_CUDA_DEVICE_WARP_HPP
+#define OPENCV_CUDA_DEVICE_WARP_HPP
 
 /** @file
  * @deprecated Use @ref cudev instead.
@@ -136,4 +136,4 @@ namespace cv { namespace cuda { namespace device
 
 //! @endcond
 
-#endif /* __OPENCV_CUDA_DEVICE_WARP_HPP__ */
+#endif /* OPENCV_CUDA_DEVICE_WARP_HPP */
diff --git a/modules/core/include/opencv2/core/cuda/warp_shuffle.hpp b/modules/core/include/opencv2/core/cuda/warp_shuffle.hpp
index 5cf42ec..14a9a4d 100644
--- a/modules/core/include/opencv2/core/cuda/warp_shuffle.hpp
+++ b/modules/core/include/opencv2/core/cuda/warp_shuffle.hpp
@@ -40,8 +40,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_CUDA_WARP_SHUFFLE_HPP__
-#define __OPENCV_CUDA_WARP_SHUFFLE_HPP__
+#ifndef OPENCV_CUDA_WARP_SHUFFLE_HPP
+#define OPENCV_CUDA_WARP_SHUFFLE_HPP
 
 /** @file
  * @deprecated Use @ref cudev instead.
@@ -54,7 +54,7 @@ namespace cv { namespace cuda { namespace device
     template <typename T>
     __device__ __forceinline__ T shfl(T val, int srcLane, int width = warpSize)
     {
-    #if __CUDA_ARCH__ >= 300
+    #if defined __CUDA_ARCH__ && __CUDA_ARCH__ >= 300
         return __shfl(val, srcLane, width);
     #else
         return T();
@@ -62,7 +62,7 @@ namespace cv { namespace cuda { namespace device
     }
     __device__ __forceinline__ unsigned int shfl(unsigned int val, int srcLane, int width = warpSize)
     {
-    #if __CUDA_ARCH__ >= 300
+    #if defined __CUDA_ARCH__ && __CUDA_ARCH__ >= 300
         return (unsigned int) __shfl((int) val, srcLane, width);
     #else
         return 0;
@@ -70,7 +70,7 @@ namespace cv { namespace cuda { namespace device
     }
     __device__ __forceinline__ double shfl(double val, int srcLane, int width = warpSize)
     {
-    #if __CUDA_ARCH__ >= 300
+    #if defined __CUDA_ARCH__ && __CUDA_ARCH__ >= 300
         int lo = __double2loint(val);
         int hi = __double2hiint(val);
 
@@ -86,7 +86,7 @@ namespace cv { namespace cuda { namespace device
     template <typename T>
     __device__ __forceinline__ T shfl_down(T val, unsigned int delta, int width = warpSize)
     {
-    #if __CUDA_ARCH__ >= 300
+    #if defined __CUDA_ARCH__ && __CUDA_ARCH__ >= 300
         return __shfl_down(val, delta, width);
     #else
         return T();
@@ -94,7 +94,7 @@ namespace cv { namespace cuda { namespace device
     }
     __device__ __forceinline__ unsigned int shfl_down(unsigned int val, unsigned int delta, int width = warpSize)
     {
-    #if __CUDA_ARCH__ >= 300
+    #if defined __CUDA_ARCH__ && __CUDA_ARCH__ >= 300
         return (unsigned int) __shfl_down((int) val, delta, width);
     #else
         return 0;
@@ -102,7 +102,7 @@ namespace cv { namespace cuda { namespace device
     }
     __device__ __forceinline__ double shfl_down(double val, unsigned int delta, int width = warpSize)
     {
-    #if __CUDA_ARCH__ >= 300
+    #if defined __CUDA_ARCH__ && __CUDA_ARCH__ >= 300
         int lo = __double2loint(val);
         int hi = __double2hiint(val);
 
@@ -118,7 +118,7 @@ namespace cv { namespace cuda { namespace device
     template <typename T>
     __device__ __forceinline__ T shfl_up(T val, unsigned int delta, int width = warpSize)
     {
-    #if __CUDA_ARCH__ >= 300
+    #if defined __CUDA_ARCH__ && __CUDA_ARCH__ >= 300
         return __shfl_up(val, delta, width);
     #else
         return T();
@@ -126,7 +126,7 @@ namespace cv { namespace cuda { namespace device
     }
     __device__ __forceinline__ unsigned int shfl_up(unsigned int val, unsigned int delta, int width = warpSize)
     {
-    #if __CUDA_ARCH__ >= 300
+    #if defined __CUDA_ARCH__ && __CUDA_ARCH__ >= 300
         return (unsigned int) __shfl_up((int) val, delta, width);
     #else
         return 0;
@@ -134,7 +134,7 @@ namespace cv { namespace cuda { namespace device
     }
     __device__ __forceinline__ double shfl_up(double val, unsigned int delta, int width = warpSize)
     {
-    #if __CUDA_ARCH__ >= 300
+    #if defined __CUDA_ARCH__ && __CUDA_ARCH__ >= 300
         int lo = __double2loint(val);
         int hi = __double2hiint(val);
 
@@ -150,4 +150,4 @@ namespace cv { namespace cuda { namespace device
 
 //! @endcond
 
-#endif // __OPENCV_CUDA_WARP_SHUFFLE_HPP__
+#endif // OPENCV_CUDA_WARP_SHUFFLE_HPP
diff --git a/modules/core/include/opencv2/core/cuda_stream_accessor.hpp b/modules/core/include/opencv2/core/cuda_stream_accessor.hpp
index 0f8ee9b..deaf356 100644
--- a/modules/core/include/opencv2/core/cuda_stream_accessor.hpp
+++ b/modules/core/include/opencv2/core/cuda_stream_accessor.hpp
@@ -40,8 +40,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_CORE_CUDA_STREAM_ACCESSOR_HPP__
-#define __OPENCV_CORE_CUDA_STREAM_ACCESSOR_HPP__
+#ifndef OPENCV_CORE_CUDA_STREAM_ACCESSOR_HPP
+#define OPENCV_CORE_CUDA_STREAM_ACCESSOR_HPP
 
 #ifndef __cplusplus
 #  error cuda_stream_accessor.hpp header must be compiled as C++
@@ -83,4 +83,4 @@ namespace cv
     }
 }
 
-#endif /* __OPENCV_CORE_CUDA_STREAM_ACCESSOR_HPP__ */
+#endif /* OPENCV_CORE_CUDA_STREAM_ACCESSOR_HPP */
diff --git a/modules/core/include/opencv2/core/cuda_types.hpp b/modules/core/include/opencv2/core/cuda_types.hpp
index 8df816e..f13a847 100644
--- a/modules/core/include/opencv2/core/cuda_types.hpp
+++ b/modules/core/include/opencv2/core/cuda_types.hpp
@@ -40,8 +40,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_CORE_CUDA_TYPES_HPP__
-#define __OPENCV_CORE_CUDA_TYPES_HPP__
+#ifndef OPENCV_CORE_CUDA_TYPES_HPP
+#define OPENCV_CORE_CUDA_TYPES_HPP
 
 #ifndef __cplusplus
 #  error cuda_types.hpp header must be compiled as C++
@@ -132,4 +132,4 @@ namespace cv
 
 //! @endcond
 
-#endif /* __OPENCV_CORE_CUDA_TYPES_HPP__ */
+#endif /* OPENCV_CORE_CUDA_TYPES_HPP */
diff --git a/modules/core/include/opencv2/core/cvdef.h b/modules/core/include/opencv2/core/cvdef.h
index af2abfb..699b166 100644
--- a/modules/core/include/opencv2/core/cvdef.h
+++ b/modules/core/include/opencv2/core/cvdef.h
@@ -42,8 +42,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_CORE_CVDEF_H__
-#define __OPENCV_CORE_CVDEF_H__
+#ifndef OPENCV_CORE_CVDEF_H
+#define OPENCV_CORE_CVDEF_H
 
 //! @addtogroup core_utils
 //! @{
@@ -112,7 +112,7 @@
 #define CV_CPU_SSE4_1           6
 #define CV_CPU_SSE4_2           7
 #define CV_CPU_POPCNT           8
-
+#define CV_CPU_FP16             9
 #define CV_CPU_AVX              10
 #define CV_CPU_AVX2             11
 #define CV_CPU_FMA3             12
@@ -143,7 +143,7 @@ enum CpuFeatures {
     CPU_SSE4_1          = 6,
     CPU_SSE4_2          = 7,
     CPU_POPCNT          = 8,
-
+    CPU_FP16            = 9,
     CPU_AVX             = 10,
     CPU_AVX2            = 11,
     CPU_FMA3            = 12,
@@ -215,7 +215,7 @@ enum CpuFeatures {
 
 #if (defined WIN32 || defined _WIN32) && defined(_M_ARM)
 # include <Intrin.h>
-# include "arm_neon.h"
+# include <arm_neon.h>
 # define CV_NEON 1
 # define CPU_HAS_NEON_FEATURE (true)
 #elif defined(__ARM_NEON__) || (defined (__ARM_NEON) && defined(__aarch64__))
@@ -303,11 +303,39 @@ enum CpuFeatures {
 #define CV_2PI 6.283185307179586476925286766559
 #define CV_LOG2 0.69314718055994530941723212145818
 
+#if defined __ARM_FP16_FORMAT_IEEE \
+    && !defined __CUDACC__
+#  define CV_FP16_TYPE 1
+#else
+#  define CV_FP16_TYPE 0
+#endif
+
+typedef union Cv16suf
+{
+    short i;
+#if CV_FP16_TYPE
+    __fp16 h;
+#endif
+    struct _fp16Format
+    {
+        unsigned int significand : 10;
+        unsigned int exponent    : 5;
+        unsigned int sign        : 1;
+    } fmt;
+}
+Cv16suf;
+
 typedef union Cv32suf
 {
     int i;
     unsigned u;
     float f;
+    struct _fp32Format
+    {
+        unsigned int significand : 23;
+        unsigned int exponent    : 8;
+        unsigned int sign        : 1;
+    } fmt;
 }
 Cv32suf;
 
@@ -357,67 +385,6 @@ Cv64suf;
 *                                  Matrix type (Mat)                                     *
 \****************************************************************************************/
 
-#define CV_CN_MAX     512
-#define CV_CN_SHIFT   3
-#define CV_DEPTH_MAX  (1 << CV_CN_SHIFT)
-
-#define CV_8U   0
-#define CV_8S   1
-#define CV_16U  2
-#define CV_16S  3
-#define CV_32S  4
-#define CV_32F  5
-#define CV_64F  6
-#define CV_USRTYPE1 7
-
-#define CV_MAT_DEPTH_MASK       (CV_DEPTH_MAX - 1)
-#define CV_MAT_DEPTH(flags)     ((flags) & CV_MAT_DEPTH_MASK)
-
-#define CV_MAKETYPE(depth,cn) (CV_MAT_DEPTH(depth) + (((cn)-1) << CV_CN_SHIFT))
-#define CV_MAKE_TYPE CV_MAKETYPE
-
-#define CV_8UC1 CV_MAKETYPE(CV_8U,1)
-#define CV_8UC2 CV_MAKETYPE(CV_8U,2)
-#define CV_8UC3 CV_MAKETYPE(CV_8U,3)
-#define CV_8UC4 CV_MAKETYPE(CV_8U,4)
-#define CV_8UC(n) CV_MAKETYPE(CV_8U,(n))
-
-#define CV_8SC1 CV_MAKETYPE(CV_8S,1)
-#define CV_8SC2 CV_MAKETYPE(CV_8S,2)
-#define CV_8SC3 CV_MAKETYPE(CV_8S,3)
-#define CV_8SC4 CV_MAKETYPE(CV_8S,4)
-#define CV_8SC(n) CV_MAKETYPE(CV_8S,(n))
-
-#define CV_16UC1 CV_MAKETYPE(CV_16U,1)
-#define CV_16UC2 CV_MAKETYPE(CV_16U,2)
-#define CV_16UC3 CV_MAKETYPE(CV_16U,3)
-#define CV_16UC4 CV_MAKETYPE(CV_16U,4)
-#define CV_16UC(n) CV_MAKETYPE(CV_16U,(n))
-
-#define CV_16SC1 CV_MAKETYPE(CV_16S,1)
-#define CV_16SC2 CV_MAKETYPE(CV_16S,2)
-#define CV_16SC3 CV_MAKETYPE(CV_16S,3)
-#define CV_16SC4 CV_MAKETYPE(CV_16S,4)
-#define CV_16SC(n) CV_MAKETYPE(CV_16S,(n))
-
-#define CV_32SC1 CV_MAKETYPE(CV_32S,1)
-#define CV_32SC2 CV_MAKETYPE(CV_32S,2)
-#define CV_32SC3 CV_MAKETYPE(CV_32S,3)
-#define CV_32SC4 CV_MAKETYPE(CV_32S,4)
-#define CV_32SC(n) CV_MAKETYPE(CV_32S,(n))
-
-#define CV_32FC1 CV_MAKETYPE(CV_32F,1)
-#define CV_32FC2 CV_MAKETYPE(CV_32F,2)
-#define CV_32FC3 CV_MAKETYPE(CV_32F,3)
-#define CV_32FC4 CV_MAKETYPE(CV_32F,4)
-#define CV_32FC(n) CV_MAKETYPE(CV_32F,(n))
-
-#define CV_64FC1 CV_MAKETYPE(CV_64F,1)
-#define CV_64FC2 CV_MAKETYPE(CV_64F,2)
-#define CV_64FC3 CV_MAKETYPE(CV_64F,3)
-#define CV_64FC4 CV_MAKETYPE(CV_64F,4)
-#define CV_64FC(n) CV_MAKETYPE(CV_64F,(n))
-
 #define CV_MAT_CN_MASK          ((CV_CN_MAX - 1) << CV_CN_SHIFT)
 #define CV_MAT_CN(flags)        ((((flags) & CV_MAT_CN_MASK) >> CV_CN_SHIFT) + 1)
 #define CV_MAT_TYPE_MASK        (CV_DEPTH_MAX*CV_CN_MAX - 1)
@@ -451,9 +418,8 @@ Cv64suf;
 *          exchange-add operation for atomic operations on reference counters            *
 \****************************************************************************************/
 
-#if defined __INTEL_COMPILER && !(defined WIN32 || defined _WIN32)
-   // atomic increment on the linux version of the Intel(tm) compiler
-#  define CV_XADD(addr, delta) (int)_InterlockedExchangeAdd(const_cast<void*>(reinterpret_cast<volatile void*>(addr)), delta)
+#ifdef CV_XADD
+  // allow to use user-defined macro
 #elif defined __GNUC__
 #  if defined __clang__ && __clang_major__ >= 3 && !defined __ANDROID__ && !defined __EMSCRIPTEN__ && !defined(__CUDACC__)
 #    ifdef __ATOMIC_ACQ_REL
@@ -512,4 +478,4 @@ Cv64suf;
 
 //! @}
 
-#endif // __OPENCV_CORE_CVDEF_H__
+#endif // OPENCV_CORE_CVDEF_H
diff --git a/modules/core/include/opencv2/core/cvstd.hpp b/modules/core/include/opencv2/core/cvstd.hpp
index edae954..2d40bd0 100644
--- a/modules/core/include/opencv2/core/cvstd.hpp
+++ b/modules/core/include/opencv2/core/cvstd.hpp
@@ -41,8 +41,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_CORE_CVSTD_HPP__
-#define __OPENCV_CORE_CVSTD_HPP__
+#ifndef OPENCV_CORE_CVSTD_HPP
+#define OPENCV_CORE_CVSTD_HPP
 
 #ifndef __cplusplus
 #  error cvstd.hpp header must be compiled as C++
@@ -67,6 +67,11 @@
 
 namespace cv
 {
+    static inline uchar abs(uchar a) { return a; }
+    static inline ushort abs(ushort a) { return a; }
+    static inline unsigned abs(unsigned a) { return a; }
+    static inline uint64 abs(uint64 a) { return a; }
+
     using std::min;
     using std::max;
     using std::abs;
@@ -77,14 +82,6 @@ namespace cv
     using std::log;
 }
 
-namespace std
-{
-    static inline uchar abs(uchar a) { return a; }
-    static inline ushort abs(ushort a) { return a; }
-    static inline unsigned abs(unsigned a) { return a; }
-    static inline uint64 abs(uint64 a) { return a; }
-}
-
 #else
 namespace cv
 {
@@ -1066,4 +1063,4 @@ namespace cv
 
 #include "opencv2/core/ptr.inl.hpp"
 
-#endif //__OPENCV_CORE_CVSTD_HPP__
+#endif //OPENCV_CORE_CVSTD_HPP
diff --git a/modules/core/include/opencv2/core/cvstd.inl.hpp b/modules/core/include/opencv2/core/cvstd.inl.hpp
index ad15406..876def8 100644
--- a/modules/core/include/opencv2/core/cvstd.inl.hpp
+++ b/modules/core/include/opencv2/core/cvstd.inl.hpp
@@ -41,8 +41,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_CORE_CVSTDINL_HPP__
-#define __OPENCV_CORE_CVSTDINL_HPP__
+#ifndef OPENCV_CORE_CVSTDINL_HPP
+#define OPENCV_CORE_CVSTDINL_HPP
 
 #ifndef OPENCV_NOSTL
 #  include <complex>
@@ -264,4 +264,4 @@ std::ostream& operator << (std::ostream& out, const Rect_<_Tp>& rect)
 
 //! @endcond
 
-#endif // __OPENCV_CORE_CVSTDINL_HPP__
+#endif // OPENCV_CORE_CVSTDINL_HPP
diff --git a/modules/core/include/opencv2/core/directx.hpp b/modules/core/include/opencv2/core/directx.hpp
index 764af74..056a85a 100644
--- a/modules/core/include/opencv2/core/directx.hpp
+++ b/modules/core/include/opencv2/core/directx.hpp
@@ -39,8 +39,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_CORE_DIRECTX_HPP__
-#define __OPENCV_CORE_DIRECTX_HPP__
+#ifndef OPENCV_CORE_DIRECTX_HPP
+#define OPENCV_CORE_DIRECTX_HPP
 
 #include "mat.hpp"
 #include "ocl.hpp"
@@ -181,4 +181,4 @@ CV_EXPORTS int getTypeFromD3DFORMAT(const int iD3DFORMAT); // enum D3DTYPE for D
 
 } } // namespace cv::directx
 
-#endif // __OPENCV_CORE_DIRECTX_HPP__
+#endif // OPENCV_CORE_DIRECTX_HPP
diff --git a/modules/core/include/opencv2/core/eigen.hpp b/modules/core/include/opencv2/core/eigen.hpp
index 44df04c..c2f1ee6 100644
--- a/modules/core/include/opencv2/core/eigen.hpp
+++ b/modules/core/include/opencv2/core/eigen.hpp
@@ -42,8 +42,8 @@
 //M*/
 
 
-#ifndef __OPENCV_CORE_EIGEN_HPP__
-#define __OPENCV_CORE_EIGEN_HPP__
+#ifndef OPENCV_CORE_EIGEN_HPP
+#define OPENCV_CORE_EIGEN_HPP
 
 #include "opencv2/core.hpp"
 
diff --git a/modules/core/include/opencv2/core/fast_math.hpp b/modules/core/include/opencv2/core/fast_math.hpp
index b8b241b..c76936a 100644
--- a/modules/core/include/opencv2/core/fast_math.hpp
+++ b/modules/core/include/opencv2/core/fast_math.hpp
@@ -42,8 +42,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_CORE_FAST_MATH_HPP__
-#define __OPENCV_CORE_FAST_MATH_HPP__
+#ifndef OPENCV_CORE_FAST_MATH_HPP
+#define OPENCV_CORE_FAST_MATH_HPP
 
 #include "opencv2/core/cvdef.h"
 
@@ -71,6 +71,7 @@
     #define ARM_ROUND(_value, _asm_string) \
         int res; \
         float temp; \
+        (void)temp; \
         asm(_asm_string : [res] "=r" (res), [temp] "=w" (temp) : [value] "w" (_value)); \
         return res
     // 2. version for double
diff --git a/modules/core/include/opencv2/core/hal/hal.hpp b/modules/core/include/opencv2/core/hal/hal.hpp
index 118913e..68900ec 100644
--- a/modules/core/include/opencv2/core/hal/hal.hpp
+++ b/modules/core/include/opencv2/core/hal/hal.hpp
@@ -42,23 +42,13 @@
 //
 //M*/
 
-#ifndef __OPENCV_HAL_HPP__
-#define __OPENCV_HAL_HPP__
+#ifndef OPENCV_HAL_HPP
+#define OPENCV_HAL_HPP
 
 #include "opencv2/core/cvdef.h"
+#include "opencv2/core/cvstd.hpp"
 #include "opencv2/core/hal/interface.h"
 
-//! @cond IGNORED
-#define CALL_HAL(name, fun, ...) \
-    int res = fun(__VA_ARGS__); \
-    if (res == CV_HAL_ERROR_OK) \
-        return; \
-    else if (res != CV_HAL_ERROR_NOT_IMPLEMENTED) \
-        CV_Error_(cv::Error::StsInternal, \
-            ("HAL implementation " CVAUX_STR(name) " ==> " CVAUX_STR(fun) " returned %d (0x%08x)", res, res));
-//! @endcond
-
-
 namespace cv { namespace hal {
 
 //! @addtogroup core_hal_functions
@@ -74,6 +64,23 @@ CV_EXPORTS int LU32f(float* A, size_t astep, int m, float* b, size_t bstep, int
 CV_EXPORTS int LU64f(double* A, size_t astep, int m, double* b, size_t bstep, int n);
 CV_EXPORTS bool Cholesky32f(float* A, size_t astep, int m, float* b, size_t bstep, int n);
 CV_EXPORTS bool Cholesky64f(double* A, size_t astep, int m, double* b, size_t bstep, int n);
+CV_EXPORTS void SVD32f(float* At, size_t astep, float* W, float* U, size_t ustep, float* Vt, size_t vstep, int m, int n, int flags);
+CV_EXPORTS void SVD64f(double* At, size_t astep, double* W, double* U, size_t ustep, double* Vt, size_t vstep, int m, int n, int flags);
+CV_EXPORTS int QR32f(float* A, size_t astep, int m, int n, int k, float* b, size_t bstep, float* hFactors);
+CV_EXPORTS int QR64f(double* A, size_t astep, int m, int n, int k, double* b, size_t bstep, double* hFactors);
+
+CV_EXPORTS void gemm32f(const float* src1, size_t src1_step, const float* src2, size_t src2_step,
+                        float alpha, const float* src3, size_t src3_step, float beta, float* dst, size_t dst_step,
+                        int m_a, int n_a, int n_d, int flags);
+CV_EXPORTS void gemm64f(const double* src1, size_t src1_step, const double* src2, size_t src2_step,
+                        double alpha, const double* src3, size_t src3_step, double beta, double* dst, size_t dst_step,
+                        int m_a, int n_a, int n_d, int flags);
+CV_EXPORTS void gemm32fc(const float* src1, size_t src1_step, const float* src2, size_t src2_step,
+                        float alpha, const float* src3, size_t src3_step, float beta, float* dst, size_t dst_step,
+                        int m_a, int n_a, int n_d, int flags);
+CV_EXPORTS void gemm64fc(const double* src1, size_t src1_step, const double* src2, size_t src2_step,
+                        double alpha, const double* src3, size_t src3_step, double beta, double* dst, size_t dst_step,
+                        int m_a, int n_a, int n_d, int flags);
 
 CV_EXPORTS int normL1_(const uchar* a, const uchar* b, int n);
 CV_EXPORTS float normL1_(const float* a, const float* b, int n);
@@ -84,7 +91,8 @@ CV_EXPORTS void exp64f(const double* src, double* dst, int n);
 CV_EXPORTS void log32f(const float* src, float* dst, int n);
 CV_EXPORTS void log64f(const double* src, double* dst, int n);
 
-CV_EXPORTS void fastAtan2(const float* y, const float* x, float* dst, int n, bool angleInDegrees);
+CV_EXPORTS void fastAtan32f(const float* y, const float* x, float* dst, int n, bool angleInDegrees);
+CV_EXPORTS void fastAtan64f(const double* y, const double* x, double* dst, int n, bool angleInDegrees);
 CV_EXPORTS void magnitude32f(const float* x, const float* y, float* dst, int n);
 CV_EXPORTS void magnitude64f(const double* x, const double* y, double* dst, int n);
 CV_EXPORTS void sqrt32f(const float* src, float* dst, int len);
@@ -171,13 +179,13 @@ CV_EXPORTS void div32s( const int* src1, size_t step1, const int* src2, size_t s
 CV_EXPORTS void div32f( const float* src1, size_t step1, const float* src2, size_t step2, float* dst, size_t step, int width, int height, void* scale);
 CV_EXPORTS void div64f( const double* src1, size_t step1, const double* src2, size_t step2, double* dst, size_t step, int width, int height, void* scale);
 
-CV_EXPORTS void recip8u( const uchar* src1, size_t step1, const uchar* src2, size_t step2, uchar* dst, size_t step, int width, int height, void* scale);
-CV_EXPORTS void recip8s( const schar* src1, size_t step1, const schar* src2, size_t step2, schar* dst, size_t step, int width, int height, void* scale);
-CV_EXPORTS void recip16u( const ushort* src1, size_t step1, const ushort* src2, size_t step2, ushort* dst, size_t step, int width, int height, void* scale);
-CV_EXPORTS void recip16s( const short* src1, size_t step1, const short* src2, size_t step2, short* dst, size_t step, int width, int height, void* scale);
-CV_EXPORTS void recip32s( const int* src1, size_t step1, const int* src2, size_t step2, int* dst, size_t step, int width, int height, void* scale);
-CV_EXPORTS void recip32f( const float* src1, size_t step1, const float* src2, size_t step2, float* dst, size_t step, int width, int height, void* scale);
-CV_EXPORTS void recip64f( const double* src1, size_t step1, const double* src2, size_t step2, double* dst, size_t step, int width, int height, void* scale);
+CV_EXPORTS void recip8u( const uchar *, size_t, const uchar * src2, size_t step2, uchar* dst, size_t step, int width, int height, void* scale);
+CV_EXPORTS void recip8s( const schar *, size_t, const schar * src2, size_t step2, schar* dst, size_t step, int width, int height, void* scale);
+CV_EXPORTS void recip16u( const ushort *, size_t, const ushort * src2, size_t step2, ushort* dst, size_t step, int width, int height, void* scale);
+CV_EXPORTS void recip16s( const short *, size_t, const short * src2, size_t step2, short* dst, size_t step, int width, int height, void* scale);
+CV_EXPORTS void recip32s( const int *, size_t, const int * src2, size_t step2, int* dst, size_t step, int width, int height, void* scale);
+CV_EXPORTS void recip32f( const float *, size_t, const float * src2, size_t step2, float* dst, size_t step, int width, int height, void* scale);
+CV_EXPORTS void recip64f( const double *, size_t, const double * src2, size_t step2, double* dst, size_t step, int width, int height, void* scale);
 
 CV_EXPORTS void addWeighted8u( const uchar* src1, size_t step1, const uchar* src2, size_t step2, uchar* dst, size_t step, int width, int height, void* _scalars );
 CV_EXPORTS void addWeighted8s( const schar* src1, size_t step1, const schar* src2, size_t step2, schar* dst, size_t step, int width, int height, void* scalars );
@@ -187,6 +195,29 @@ CV_EXPORTS void addWeighted32s( const int* src1, size_t step1, const int* src2,
 CV_EXPORTS void addWeighted32f( const float* src1, size_t step1, const float* src2, size_t step2, float* dst, size_t step, int width, int height, void* scalars );
 CV_EXPORTS void addWeighted64f( const double* src1, size_t step1, const double* src2, size_t step2, double* dst, size_t step, int width, int height, void* scalars );
 
+struct CV_EXPORTS DFT1D
+{
+    static Ptr<DFT1D> create(int len, int count, int depth, int flags, bool * useBuffer = 0);
+    virtual void apply(const uchar *src, uchar *dst) = 0;
+    virtual ~DFT1D() {}
+};
+
+struct CV_EXPORTS DFT2D
+{
+    static Ptr<DFT2D> create(int width, int height, int depth,
+                             int src_channels, int dst_channels,
+                             int flags, int nonzero_rows = 0);
+    virtual void apply(const uchar *src_data, size_t src_step, uchar *dst_data, size_t dst_step) = 0;
+    virtual ~DFT2D() {}
+};
+
+struct CV_EXPORTS DCT2D
+{
+    static Ptr<DCT2D> create(int width, int height, int depth, int flags);
+    virtual void apply(const uchar *src_data, size_t src_step, uchar *dst_data, size_t dst_step) = 0;
+    virtual ~DCT2D() {}
+};
+
 //! @} core_hal
 
 //=============================================================================
@@ -204,6 +235,7 @@ CV_EXPORTS void exp(const double* src, double* dst, int n);
 CV_EXPORTS void log(const float* src, float* dst, int n);
 CV_EXPORTS void log(const double* src, double* dst, int n);
 
+CV_EXPORTS void fastAtan2(const float* y, const float* x, float* dst, int n, bool angleInDegrees);
 CV_EXPORTS void magnitude(const float* x, const float* y, float* dst, int n);
 CV_EXPORTS void magnitude(const double* x, const double* y, double* dst, int n);
 CV_EXPORTS void sqrt(const float* src, float* dst, int len);
@@ -215,4 +247,4 @@ CV_EXPORTS void invSqrt(const double* src, double* dst, int len);
 
 }} //cv::hal
 
-#endif //__OPENCV_HAL_HPP__
+#endif //OPENCV_HAL_HPP
diff --git a/modules/core/include/opencv2/core/hal/interface.h b/modules/core/include/opencv2/core/hal/interface.h
index 51f7606..4a97e65 100644
--- a/modules/core/include/opencv2/core/hal/interface.h
+++ b/modules/core/include/opencv2/core/hal/interface.h
@@ -1,38 +1,34 @@
-#ifndef _HAL_INTERFACE_HPP_INCLUDED_
-#define _HAL_INTERFACE_HPP_INCLUDED_
+#ifndef OPENCV_CORE_HAL_INTERFACE_H
+#define OPENCV_CORE_HAL_INTERFACE_H
 
 //! @addtogroup core_hal_interface
 //! @{
 
+//! @name Return codes
+//! @{
 #define CV_HAL_ERROR_OK 0
 #define CV_HAL_ERROR_NOT_IMPLEMENTED 1
 #define CV_HAL_ERROR_UNKNOWN -1
-
-#define CV_HAL_CMP_EQ 0
-#define CV_HAL_CMP_GT 1
-#define CV_HAL_CMP_GE 2
-#define CV_HAL_CMP_LT 3
-#define CV_HAL_CMP_LE 4
-#define CV_HAL_CMP_NE 5
+//! @}
 
 #ifdef __cplusplus
 #include <cstddef>
 #else
 #include <stddef.h>
+#include <stdbool.h>
 #endif
 
-/* primitive types */
-/*
-  schar  - signed 1 byte integer
-  uchar  - unsigned 1 byte integer
-  short  - signed 2 byte integer
-  ushort - unsigned 2 byte integer
-  int    - signed 4 byte integer
-  uint   - unsigned 4 byte integer
-  int64  - signed 8 byte integer
-  uint64 - unsigned 8 byte integer
-*/
-
+//! @name Data types
+//! primitive types
+//! - schar  - signed 1 byte integer
+//! - uchar  - unsigned 1 byte integer
+//! - short  - signed 2 byte integer
+//! - ushort - unsigned 2 byte integer
+//! - int    - signed 4 byte integer
+//! - uint   - unsigned 4 byte integer
+//! - int64  - signed 8 byte integer
+//! - uint64 - unsigned 8 byte integer
+//! @{
 #if !defined _MSC_VER && !defined __BORLANDC__
 #  if defined __cplusplus && __cplusplus >= 201103L && !defined __APPLE__
 #    include <cstdint>
@@ -64,6 +60,119 @@ typedef signed char schar;
 #  define CV_BIG_UINT(n)  n##ULL
 #endif
 
+#define CV_CN_MAX     512
+#define CV_CN_SHIFT   3
+#define CV_DEPTH_MAX  (1 << CV_CN_SHIFT)
+
+#define CV_8U   0
+#define CV_8S   1
+#define CV_16U  2
+#define CV_16S  3
+#define CV_32S  4
+#define CV_32F  5
+#define CV_64F  6
+#define CV_USRTYPE1 7
+
+#define CV_MAT_DEPTH_MASK       (CV_DEPTH_MAX - 1)
+#define CV_MAT_DEPTH(flags)     ((flags) & CV_MAT_DEPTH_MASK)
+
+#define CV_MAKETYPE(depth,cn) (CV_MAT_DEPTH(depth) + (((cn)-1) << CV_CN_SHIFT))
+#define CV_MAKE_TYPE CV_MAKETYPE
+
+#define CV_8UC1 CV_MAKETYPE(CV_8U,1)
+#define CV_8UC2 CV_MAKETYPE(CV_8U,2)
+#define CV_8UC3 CV_MAKETYPE(CV_8U,3)
+#define CV_8UC4 CV_MAKETYPE(CV_8U,4)
+#define CV_8UC(n) CV_MAKETYPE(CV_8U,(n))
+
+#define CV_8SC1 CV_MAKETYPE(CV_8S,1)
+#define CV_8SC2 CV_MAKETYPE(CV_8S,2)
+#define CV_8SC3 CV_MAKETYPE(CV_8S,3)
+#define CV_8SC4 CV_MAKETYPE(CV_8S,4)
+#define CV_8SC(n) CV_MAKETYPE(CV_8S,(n))
+
+#define CV_16UC1 CV_MAKETYPE(CV_16U,1)
+#define CV_16UC2 CV_MAKETYPE(CV_16U,2)
+#define CV_16UC3 CV_MAKETYPE(CV_16U,3)
+#define CV_16UC4 CV_MAKETYPE(CV_16U,4)
+#define CV_16UC(n) CV_MAKETYPE(CV_16U,(n))
+
+#define CV_16SC1 CV_MAKETYPE(CV_16S,1)
+#define CV_16SC2 CV_MAKETYPE(CV_16S,2)
+#define CV_16SC3 CV_MAKETYPE(CV_16S,3)
+#define CV_16SC4 CV_MAKETYPE(CV_16S,4)
+#define CV_16SC(n) CV_MAKETYPE(CV_16S,(n))
+
+#define CV_32SC1 CV_MAKETYPE(CV_32S,1)
+#define CV_32SC2 CV_MAKETYPE(CV_32S,2)
+#define CV_32SC3 CV_MAKETYPE(CV_32S,3)
+#define CV_32SC4 CV_MAKETYPE(CV_32S,4)
+#define CV_32SC(n) CV_MAKETYPE(CV_32S,(n))
+
+#define CV_32FC1 CV_MAKETYPE(CV_32F,1)
+#define CV_32FC2 CV_MAKETYPE(CV_32F,2)
+#define CV_32FC3 CV_MAKETYPE(CV_32F,3)
+#define CV_32FC4 CV_MAKETYPE(CV_32F,4)
+#define CV_32FC(n) CV_MAKETYPE(CV_32F,(n))
+
+#define CV_64FC1 CV_MAKETYPE(CV_64F,1)
+#define CV_64FC2 CV_MAKETYPE(CV_64F,2)
+#define CV_64FC3 CV_MAKETYPE(CV_64F,3)
+#define CV_64FC4 CV_MAKETYPE(CV_64F,4)
+#define CV_64FC(n) CV_MAKETYPE(CV_64F,(n))
+//! @}
+
+//! @name Comparison operation
+//! @sa cv::CmpTypes
+//! @{
+#define CV_HAL_CMP_EQ 0
+#define CV_HAL_CMP_GT 1
+#define CV_HAL_CMP_GE 2
+#define CV_HAL_CMP_LT 3
+#define CV_HAL_CMP_LE 4
+#define CV_HAL_CMP_NE 5
+//! @}
+
+//! @name Border processing modes
+//! @sa cv::BorderTypes
+//! @{
+#define CV_HAL_BORDER_CONSTANT 0
+#define CV_HAL_BORDER_REPLICATE 1
+#define CV_HAL_BORDER_REFLECT 2
+#define CV_HAL_BORDER_WRAP 3
+#define CV_HAL_BORDER_REFLECT_101 4
+#define CV_HAL_BORDER_TRANSPARENT 5
+#define CV_HAL_BORDER_ISOLATED 16
+//! @}
+
+//! @name DFT flags
+//! @{
+#define CV_HAL_DFT_INVERSE        1
+#define CV_HAL_DFT_SCALE          2
+#define CV_HAL_DFT_ROWS           4
+#define CV_HAL_DFT_COMPLEX_OUTPUT 16
+#define CV_HAL_DFT_REAL_OUTPUT    32
+#define CV_HAL_DFT_TWO_STAGE      64
+#define CV_HAL_DFT_STAGE_COLS    128
+#define CV_HAL_DFT_IS_CONTINUOUS 512
+#define CV_HAL_DFT_IS_INPLACE 1024
+//! @}
+
+//! @name SVD flags
+//! @{
+#define CV_HAL_SVD_NO_UV    1
+#define CV_HAL_SVD_SHORT_UV 2
+#define CV_HAL_SVD_MODIFY_A 4
+#define CV_HAL_SVD_FULL_UV  8
+//! @}
+
+//! @name Gemm flags
+//! @{
+#define CV_HAL_GEMM_1_T 1
+#define CV_HAL_GEMM_2_T 2
+#define CV_HAL_GEMM_3_T 4
+//! @}
+
 //! @}
 
 #endif
diff --git a/modules/core/include/opencv2/core/hal/intrin.hpp b/modules/core/include/opencv2/core/hal/intrin.hpp
index 33e14b4..34075e3 100644
--- a/modules/core/include/opencv2/core/hal/intrin.hpp
+++ b/modules/core/include/opencv2/core/hal/intrin.hpp
@@ -42,8 +42,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_HAL_INTRIN_HPP__
-#define __OPENCV_HAL_INTRIN_HPP__
+#ifndef OPENCV_HAL_INTRIN_HPP
+#define OPENCV_HAL_INTRIN_HPP
 
 #include <cmath>
 #include <float.h>
@@ -317,4 +317,98 @@ template <typename T> struct V_SIMD128Traits
 
 //! @}
 
+//==================================================================================================
+
+//! @cond IGNORED
+
+namespace cv {
+
+template <typename R> struct V_RegTrait128;
+
+template <> struct V_RegTrait128<uchar> {
+    typedef v_uint8x16 reg;
+    typedef v_uint16x8 w_reg;
+    typedef v_uint32x4 q_reg;
+    typedef v_uint8x16 u_reg;
+    static v_uint8x16 zero() { return v_setzero_u8(); }
+    static v_uint8x16 all(uchar val) { return v_setall_u8(val); }
+};
+
+template <> struct V_RegTrait128<schar> {
+    typedef v_int8x16 reg;
+    typedef v_int16x8 w_reg;
+    typedef v_int32x4 q_reg;
+    typedef v_uint8x16 u_reg;
+    static v_int8x16 zero() { return v_setzero_s8(); }
+    static v_int8x16 all(schar val) { return v_setall_s8(val); }
+};
+
+template <> struct V_RegTrait128<ushort> {
+    typedef v_uint16x8 reg;
+    typedef v_uint32x4 w_reg;
+    typedef v_int16x8 int_reg;
+    typedef v_uint16x8 u_reg;
+    static v_uint16x8 zero() { return v_setzero_u16(); }
+    static v_uint16x8 all(ushort val) { return v_setall_u16(val); }
+};
+
+template <> struct V_RegTrait128<short> {
+    typedef v_int16x8 reg;
+    typedef v_int32x4 w_reg;
+    typedef v_uint16x8 u_reg;
+    static v_int16x8 zero() { return v_setzero_s16(); }
+    static v_int16x8 all(short val) { return v_setall_s16(val); }
+};
+
+template <> struct V_RegTrait128<unsigned> {
+    typedef v_uint32x4 reg;
+    typedef v_uint64x2 w_reg;
+    typedef v_int32x4 int_reg;
+    typedef v_uint32x4 u_reg;
+    static v_uint32x4 zero() { return v_setzero_u32(); }
+    static v_uint32x4 all(unsigned val) { return v_setall_u32(val); }
+};
+
+template <> struct V_RegTrait128<int> {
+    typedef v_int32x4 reg;
+    typedef v_int64x2 w_reg;
+    typedef v_uint32x4 u_reg;
+    static v_int32x4 zero() { return v_setzero_s32(); }
+    static v_int32x4 all(int val) { return v_setall_s32(val); }
+};
+
+template <> struct V_RegTrait128<uint64> {
+    typedef v_uint64x2 reg;
+    static v_uint64x2 zero() { return v_setzero_u64(); }
+    static v_uint64x2 all(uint64 val) { return v_setall_u64(val); }
+};
+
+template <> struct V_RegTrait128<int64> {
+    typedef v_int64x2 reg;
+    static v_int64x2 zero() { return v_setzero_s64(); }
+    static v_int64x2 all(int64 val) { return v_setall_s64(val); }
+};
+
+template <> struct V_RegTrait128<float> {
+    typedef v_float32x4 reg;
+    typedef v_int32x4 int_reg;
+    typedef v_float32x4 u_reg;
+    static v_float32x4 zero() { return v_setzero_f32(); }
+    static v_float32x4 all(float val) { return v_setall_f32(val); }
+};
+
+#if CV_SIMD128_64F
+template <> struct V_RegTrait128<double> {
+    typedef v_float64x2 reg;
+    typedef v_int32x4 int_reg;
+    typedef v_float64x2 u_reg;
+    static v_float64x2 zero() { return v_setzero_f64(); }
+    static v_float64x2 all(double val) { return v_setall_f64(val); }
+};
+#endif
+
+} // cv::
+
+//! @endcond
+
 #endif
diff --git a/modules/core/include/opencv2/core/hal/intrin_cpp.hpp b/modules/core/include/opencv2/core/hal/intrin_cpp.hpp
index 3929e0d..93ca397 100644
--- a/modules/core/include/opencv2/core/hal/intrin_cpp.hpp
+++ b/modules/core/include/opencv2/core/hal/intrin_cpp.hpp
@@ -42,8 +42,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_HAL_INTRIN_CPP_HPP__
-#define __OPENCV_HAL_INTRIN_CPP_HPP__
+#ifndef OPENCV_HAL_INTRIN_CPP_HPP
+#define OPENCV_HAL_INTRIN_CPP_HPP
 
 #include <limits>
 #include <cstring>
@@ -103,7 +103,7 @@ block and to save contents of the register to memory block.
 
 These operations allow to reorder or recombine elements in one or multiple vectors.
 
-- Interleave, deinterleave (3 and 4 channels): @ref v_load_deinterleave, @ref v_store_interleave
+- Interleave, deinterleave (2, 3 and 4 channels): @ref v_load_deinterleave, @ref v_store_interleave
 - Expand: @ref v_load_expand, @ref v_load_expand_q, @ref v_expand
 - Pack: @ref v_pack, @ref v_pack_u, @ref v_rshr_pack, @ref v_rshr_pack_u,
 @ref v_pack_store, @ref v_pack_u_store, @ref v_rshr_pack_store, @ref v_rshr_pack_u_store
@@ -116,32 +116,32 @@ These operations allow to reorder or recombine elements in one or multiple vecto
 Element-wise binary and unary operations.
 
 - Arithmetics:
- at ref operator+(const v_reg &a, const v_reg &b) "+",
- at ref operator-(const v_reg &a, const v_reg &b) "-",
- at ref operator*(const v_reg &a, const v_reg &b) "*",
- at ref operator/(const v_reg &a, const v_reg &b) "/",
+ at ref operator +(const v_reg &a, const v_reg &b) "+",
+ at ref operator -(const v_reg &a, const v_reg &b) "-",
+ at ref operator *(const v_reg &a, const v_reg &b) "*",
+ at ref operator /(const v_reg &a, const v_reg &b) "/",
 @ref v_mul_expand
 
 - Non-saturating arithmetics: @ref v_add_wrap, @ref v_sub_wrap
 
 - Bitwise shifts:
- at ref operator<<(const v_reg &a, int s) "<<",
- at ref operator>>(const v_reg &a, int s) ">>",
+ at ref operator <<(const v_reg &a, int s) "<<",
+ at ref operator >>(const v_reg &a, int s) ">>",
 @ref v_shl, @ref v_shr
 
 - Bitwise logic:
 @ref operator&(const v_reg &a, const v_reg &b) "&",
- at ref operator|(const v_reg &a, const v_reg &b) "|",
- at ref operator^(const v_reg &a, const v_reg &b) "^",
- at ref operator~(const v_reg &a) "~"
+ at ref operator |(const v_reg &a, const v_reg &b) "|",
+ at ref operator ^(const v_reg &a, const v_reg &b) "^",
+ at ref operator ~(const v_reg &a) "~"
 
 - Comparison:
- at ref operator>(const v_reg &a, const v_reg &b) ">",
- at ref operator>=(const v_reg &a, const v_reg &b) ">=",
- at ref operator<(const v_reg &a, const v_reg &b) "<",
- at ref operator<=(const v_reg &a, const v_reg &b) "<=",
+ at ref operator >(const v_reg &a, const v_reg &b) ">",
+ at ref operator >=(const v_reg &a, const v_reg &b) ">=",
+ at ref operator <(const v_reg &a, const v_reg &b) "<",
+ at ref operator <=(const v_reg &a, const v_reg &b) "<=",
 @ref operator==(const v_reg &a, const v_reg &b) "==",
- at ref operator!=(const v_reg &a, const v_reg &b) "!="
+ at ref operator !=(const v_reg &a, const v_reg &b) "!="
 
 - min/max: @ref v_min, @ref v_max
 
@@ -455,8 +455,10 @@ template<typename _Tp, int n> inline v_reg<_Tp, n> operator ~ (const v_reg<_Tp,
 {
     v_reg<_Tp, n> c;
     for( int i = 0; i < n; i++ )
+    {
         c.s[i] = V_TypeTraits<_Tp>::reinterpret_from_int(~V_TypeTraits<_Tp>::reinterpret_int(a.s[i]));
-        return c;
+    }
+    return c;
 }
 
 //! @brief Helper macro
@@ -1075,12 +1077,31 @@ v_load_expand_q(const _Tp* ptr)
     return c;
 }
 
-/** @brief Load and deinterleave (4 channels)
+/** @brief Load and deinterleave (2 channels)
 
-Load data from memory deinterleave and store to 4 registers.
+Load data from memory deinterleave and store to 2 registers.
 Scheme:
 @code
-{A1 B1 C1 D1 A2 B2 C2 D2 ...} ==> {A1 A2 ...}, {B1 B2 ...}, {C1 C2 ...}, {D1 D2 ...}
+{A1 B1 A2 B2 ...} ==> {A1 A2 ...}, {B1 B2 ...}
+ at endcode
+For all types except 64-bit. */
+template<typename _Tp, int n> inline void v_load_deinterleave(const _Tp* ptr, v_reg<_Tp, n>& a,
+                                                            v_reg<_Tp, n>& b)
+{
+    int i, i2;
+    for( i = i2 = 0; i < n; i++, i2 += 2 )
+    {
+        a.s[i] = ptr[i2];
+        b.s[i] = ptr[i2+1];
+    }
+}
+
+/** @brief Load and deinterleave (3 channels)
+
+Load data from memory deinterleave and store to 3 registers.
+Scheme:
+ at code
+{A1 B1 C1 A2 B2 C2 ...} ==> {A1 A2 ...}, {B1 B2 ...}, {C1 C2 ...}
 @endcode
 For all types except 64-bit. */
 template<typename _Tp, int n> inline void v_load_deinterleave(const _Tp* ptr, v_reg<_Tp, n>& a,
@@ -1095,12 +1116,12 @@ template<typename _Tp, int n> inline void v_load_deinterleave(const _Tp* ptr, v_
     }
 }
 
-/** @brief Load and deinterleave (3 channels)
+/** @brief Load and deinterleave (4 channels)
 
-Load data from memory deinterleave and store to 3 registers.
+Load data from memory deinterleave and store to 4 registers.
 Scheme:
 @code
-{A1 B1 C1 A2 B2 C2 ...} ==> {A1 A2 ...}, {B1 B2 ...}, {C1 C2 ...}
+{A1 B1 C1 D1 A2 B2 C2 D2 ...} ==> {A1 A2 ...}, {B1 B2 ...}, {C1 C2 ...}, {D1 D2 ...}
 @endcode
 For all types except 64-bit. */
 template<typename _Tp, int n>
@@ -1118,12 +1139,32 @@ inline void v_load_deinterleave(const _Tp* ptr, v_reg<_Tp, n>& a,
     }
 }
 
+/** @brief Interleave and store (2 channels)
+
+Interleave and store data from 2 registers to memory.
+Scheme:
+ at code
+{A1 A2 ...}, {B1 B2 ...} ==> {A1 B1 A2 B2 ...}
+ at endcode
+For all types except 64-bit. */
+template<typename _Tp, int n>
+inline void v_store_interleave( _Tp* ptr, const v_reg<_Tp, n>& a,
+                               const v_reg<_Tp, n>& b)
+{
+    int i, i2;
+    for( i = i2 = 0; i < n; i++, i2 += 2 )
+    {
+        ptr[i2] = a.s[i];
+        ptr[i2+1] = b.s[i];
+    }
+}
+
 /** @brief Interleave and store (3 channels)
 
 Interleave and store data from 3 registers to memory.
 Scheme:
 @code
-{A1 A2 ...}, {B1 B2 ...}, {C1 C2 ...}, {D1 D2 ...} ==> {A1 B1 C1 D1 A2 B2 C2 D2 ...}
+{A1 A2 ...}, {B1 B2 ...}, {C1 C2 ...} ==> {A1 B1 C1 A2 B2 C2 ...}
 @endcode
 For all types except 64-bit. */
 template<typename _Tp, int n>
@@ -1733,6 +1774,17 @@ inline v_float32x4 v_matmul(const v_float32x4& v, const v_float32x4& m0,
 
 //! @}
 
+//! @name Check SIMD support
+//! @{
+//! @brief Check CPU capability of SIMD operation
+static inline bool hasSIMD128()
+{
+    return false;
+}
+
+//! @}
+
+
 }
 
 #endif
diff --git a/modules/core/include/opencv2/core/hal/intrin_neon.hpp b/modules/core/include/opencv2/core/hal/intrin_neon.hpp
index f3e47ca..b000733 100644
--- a/modules/core/include/opencv2/core/hal/intrin_neon.hpp
+++ b/modules/core/include/opencv2/core/hal/intrin_neon.hpp
@@ -42,10 +42,11 @@
 //
 //M*/
 
-#ifndef __OPENCV_HAL_INTRIN_NEON_HPP__
-#define __OPENCV_HAL_INTRIN_NEON_HPP__
+#ifndef OPENCV_HAL_INTRIN_NEON_HPP
+#define OPENCV_HAL_INTRIN_NEON_HPP
 
 #include <algorithm>
+#include "opencv2/core/utility.hpp"
 
 namespace cv
 {
@@ -53,6 +54,28 @@ namespace cv
 //! @cond IGNORED
 
 #define CV_SIMD128 1
+#if defined(__aarch64__)
+#define CV_SIMD128_64F 1
+#else
+#define CV_SIMD128_64F 0
+#endif
+
+#if CV_SIMD128_64F
+#define OPENCV_HAL_IMPL_NEON_REINTERPRET(_Tpv, suffix) \
+template <typename T> static inline \
+_Tpv vreinterpretq_##suffix##_f64(T a) { return (_Tpv) a; } \
+template <typename T> static inline \
+float64x2_t vreinterpretq_f64_##suffix(T a) { return (float64x2_t) a; }
+OPENCV_HAL_IMPL_NEON_REINTERPRET(uint8x16_t, u8)
+OPENCV_HAL_IMPL_NEON_REINTERPRET(int8x16_t, s8)
+OPENCV_HAL_IMPL_NEON_REINTERPRET(uint16x8_t, u16)
+OPENCV_HAL_IMPL_NEON_REINTERPRET(int16x8_t, s16)
+OPENCV_HAL_IMPL_NEON_REINTERPRET(uint32x4_t, u32)
+OPENCV_HAL_IMPL_NEON_REINTERPRET(int32x4_t, s32)
+OPENCV_HAL_IMPL_NEON_REINTERPRET(uint64x2_t, u64)
+OPENCV_HAL_IMPL_NEON_REINTERPRET(int64x2_t, s64)
+OPENCV_HAL_IMPL_NEON_REINTERPRET(float32x4_t, f32)
+#endif
 
 struct v_uint8x16
 {
@@ -232,6 +255,58 @@ struct v_int64x2
     int64x2_t val;
 };
 
+#if CV_SIMD128_64F
+struct v_float64x2
+{
+    typedef double lane_type;
+    enum { nlanes = 2 };
+
+    v_float64x2() {}
+    explicit v_float64x2(float64x2_t v) : val(v) {}
+    v_float64x2(double v0, double v1)
+    {
+        double v[] = {v0, v1};
+        val = vld1q_f64(v);
+    }
+    double get0() const
+    {
+        return vgetq_lane_f64(val, 0);
+    }
+    float64x2_t val;
+};
+#endif
+
+#if defined (HAVE_FP16)
+// Workaround for old comiplers
+template <typename T> static inline int16x4_t vreinterpret_s16_f16(T a)
+{ return (int16x4_t)a; }
+template <typename T> static inline float16x4_t vreinterpret_f16_s16(T a)
+{ return (float16x4_t)a; }
+template <typename T> static inline float16x4_t vld1_f16(const T* ptr)
+{ return vreinterpret_f16_s16(vld1_s16((const short*)ptr)); }
+template <typename T> static inline void vst1_f16(T* ptr, float16x4_t a)
+{ vst1_s16((short*)ptr, vreinterpret_s16_f16(a)); }
+
+struct v_float16x4
+{
+    typedef short lane_type;
+    enum { nlanes = 4 };
+
+    v_float16x4() {}
+    explicit v_float16x4(float16x4_t v) : val(v) {}
+    v_float16x4(short v0, short v1, short v2, short v3)
+    {
+        short v[] = {v0, v1, v2, v3};
+        val = vld1_f16(v);
+    }
+    short get0() const
+    {
+        return vget_lane_s16(vreinterpret_s16_f16(val), 0);
+    }
+    float16x4_t val;
+};
+#endif
+
 #define OPENCV_HAL_IMPL_NEON_INIT(_Tpv, _Tp, suffix) \
 inline v_##_Tpv v_setzero_##suffix() { return v_##_Tpv(vdupq_n_##suffix((_Tp)0)); } \
 inline v_##_Tpv v_setall_##suffix(_Tp v) { return v_##_Tpv(vdupq_n_##suffix(v)); } \
@@ -255,6 +330,21 @@ OPENCV_HAL_IMPL_NEON_INIT(int32x4, int, s32)
 OPENCV_HAL_IMPL_NEON_INIT(uint64x2, uint64, u64)
 OPENCV_HAL_IMPL_NEON_INIT(int64x2, int64, s64)
 OPENCV_HAL_IMPL_NEON_INIT(float32x4, float, f32)
+#if CV_SIMD128_64F
+#define OPENCV_HAL_IMPL_NEON_INIT_64(_Tpv, suffix) \
+inline v_float64x2 v_reinterpret_as_f64(const v_##_Tpv& v) { return v_float64x2(vreinterpretq_f64_##suffix(v.val)); }
+OPENCV_HAL_IMPL_NEON_INIT(float64x2, double, f64)
+OPENCV_HAL_IMPL_NEON_INIT_64(uint8x16, u8)
+OPENCV_HAL_IMPL_NEON_INIT_64(int8x16, s8)
+OPENCV_HAL_IMPL_NEON_INIT_64(uint16x8, u16)
+OPENCV_HAL_IMPL_NEON_INIT_64(int16x8, s16)
+OPENCV_HAL_IMPL_NEON_INIT_64(uint32x4, u32)
+OPENCV_HAL_IMPL_NEON_INIT_64(int32x4, s32)
+OPENCV_HAL_IMPL_NEON_INIT_64(uint64x2, u64)
+OPENCV_HAL_IMPL_NEON_INIT_64(int64x2, s64)
+OPENCV_HAL_IMPL_NEON_INIT_64(float32x4, f32)
+OPENCV_HAL_IMPL_NEON_INIT_64(float64x2, f64)
+#endif
 
 #define OPENCV_HAL_IMPL_NEON_PACK(_Tpvec, _Tp, hreg, suffix, _Tpwvec, wsuffix, pack, op) \
 inline _Tpvec v_##pack(const _Tpwvec& a, const _Tpwvec& b) \
@@ -337,7 +427,13 @@ OPENCV_HAL_IMPL_NEON_BIN_OP(+, v_int64x2, vaddq_s64)
 OPENCV_HAL_IMPL_NEON_BIN_OP(-, v_int64x2, vsubq_s64)
 OPENCV_HAL_IMPL_NEON_BIN_OP(+, v_uint64x2, vaddq_u64)
 OPENCV_HAL_IMPL_NEON_BIN_OP(-, v_uint64x2, vsubq_u64)
-
+#if CV_SIMD128_64F
+OPENCV_HAL_IMPL_NEON_BIN_OP(/, v_float32x4, vdivq_f32)
+OPENCV_HAL_IMPL_NEON_BIN_OP(+, v_float64x2, vaddq_f64)
+OPENCV_HAL_IMPL_NEON_BIN_OP(-, v_float64x2, vsubq_f64)
+OPENCV_HAL_IMPL_NEON_BIN_OP(*, v_float64x2, vmulq_f64)
+OPENCV_HAL_IMPL_NEON_BIN_OP(/, v_float64x2, vdivq_f64)
+#else
 inline v_float32x4 operator / (const v_float32x4& a, const v_float32x4& b)
 {
     float32x4_t reciprocal = vrecpeq_f32(b.val);
@@ -353,6 +449,7 @@ inline v_float32x4& operator /= (v_float32x4& a, const v_float32x4& b)
     a.val = vmulq_f32(a.val, reciprocal);
     return a;
 }
+#endif
 
 inline void v_mul_expand(const v_int16x8& a, const v_int16x8& b,
                          v_int32x4& c, v_int32x4& d)
@@ -421,6 +518,18 @@ inline v_float32x4 operator ~ (const v_float32x4& a)
     return v_float32x4(vreinterpretq_f32_s32(vmvnq_s32(vreinterpretq_s32_f32(a.val))));
 }
 
+#if CV_SIMD128_64F
+inline v_float32x4 v_sqrt(const v_float32x4& x)
+{
+    return v_float32x4(vsqrtq_f32(x.val));
+}
+
+inline v_float32x4 v_invsqrt(const v_float32x4& x)
+{
+    v_float32x4 one = v_setall_f32(1.0f);
+    return one / v_sqrt(x);
+}
+#else
 inline v_float32x4 v_sqrt(const v_float32x4& x)
 {
     float32x4_t x1 = vmaxq_f32(x.val, vdupq_n_f32(FLT_MIN));
@@ -437,10 +546,54 @@ inline v_float32x4 v_invsqrt(const v_float32x4& x)
     e = vmulq_f32(vrsqrtsq_f32(vmulq_f32(x.val, e), e), e);
     return v_float32x4(e);
 }
+#endif
+
+#define OPENCV_HAL_IMPL_NEON_ABS(_Tpuvec, _Tpsvec, usuffix, ssuffix) \
+inline _Tpuvec v_abs(const _Tpsvec& a) { return v_reinterpret_as_##usuffix(_Tpsvec(vabsq_##ssuffix(a.val))); }
+
+OPENCV_HAL_IMPL_NEON_ABS(v_uint8x16, v_int8x16, u8, s8)
+OPENCV_HAL_IMPL_NEON_ABS(v_uint16x8, v_int16x8, u16, s16)
+OPENCV_HAL_IMPL_NEON_ABS(v_uint32x4, v_int32x4, u32, s32)
 
 inline v_float32x4 v_abs(v_float32x4 x)
 { return v_float32x4(vabsq_f32(x.val)); }
 
+#if CV_SIMD128_64F
+#define OPENCV_HAL_IMPL_NEON_DBL_BIT_OP(bin_op, intrin) \
+inline v_float64x2 operator bin_op (const v_float64x2& a, const v_float64x2& b) \
+{ \
+    return v_float64x2(vreinterpretq_f64_s64(intrin(vreinterpretq_s64_f64(a.val), vreinterpretq_s64_f64(b.val)))); \
+} \
+inline v_float64x2& operator bin_op##= (v_float64x2& a, const v_float64x2& b) \
+{ \
+    a.val = vreinterpretq_f64_s64(intrin(vreinterpretq_s64_f64(a.val), vreinterpretq_s64_f64(b.val))); \
+    return a; \
+}
+
+OPENCV_HAL_IMPL_NEON_DBL_BIT_OP(&, vandq_s64)
+OPENCV_HAL_IMPL_NEON_DBL_BIT_OP(|, vorrq_s64)
+OPENCV_HAL_IMPL_NEON_DBL_BIT_OP(^, veorq_s64)
+
+inline v_float64x2 operator ~ (const v_float64x2& a)
+{
+    return v_float64x2(vreinterpretq_f64_s32(vmvnq_s32(vreinterpretq_s32_f64(a.val))));
+}
+
+inline v_float64x2 v_sqrt(const v_float64x2& x)
+{
+    return v_float64x2(vsqrtq_f64(x.val));
+}
+
+inline v_float64x2 v_invsqrt(const v_float64x2& x)
+{
+    v_float64x2 one = v_setall_f64(1.0f);
+    return one / v_sqrt(x);
+}
+
+inline v_float64x2 v_abs(v_float64x2 x)
+{ return v_float64x2(vabsq_f64(x.val)); }
+#endif
+
 // TODO: exp, log, sin, cos
 
 #define OPENCV_HAL_IMPL_NEON_BIN_FUNC(_Tpvec, func, intrin) \
@@ -463,8 +616,23 @@ OPENCV_HAL_IMPL_NEON_BIN_FUNC(v_int32x4, v_min, vminq_s32)
 OPENCV_HAL_IMPL_NEON_BIN_FUNC(v_int32x4, v_max, vmaxq_s32)
 OPENCV_HAL_IMPL_NEON_BIN_FUNC(v_float32x4, v_min, vminq_f32)
 OPENCV_HAL_IMPL_NEON_BIN_FUNC(v_float32x4, v_max, vmaxq_f32)
+#if CV_SIMD128_64F
+OPENCV_HAL_IMPL_NEON_BIN_FUNC(v_float64x2, v_min, vminq_f64)
+OPENCV_HAL_IMPL_NEON_BIN_FUNC(v_float64x2, v_max, vmaxq_f64)
+#endif
 
-
+#if CV_SIMD128_64F
+inline int64x2_t vmvnq_s64(int64x2_t a)
+{
+    int64x2_t vx = vreinterpretq_s64_u32(vdupq_n_u32(0xFFFFFFFF));
+    return veorq_s64(a, vx);
+}
+inline uint64x2_t vmvnq_u64(uint64x2_t a)
+{
+    uint64x2_t vx = vreinterpretq_u64_u32(vdupq_n_u32(0xFFFFFFFF));
+    return veorq_u64(a, vx);
+}
+#endif
 #define OPENCV_HAL_IMPL_NEON_INT_CMP_OP(_Tpvec, cast, suffix, not_suffix) \
 inline _Tpvec operator == (const _Tpvec& a, const _Tpvec& b) \
 { return _Tpvec(cast(vceqq_##suffix(a.val, b.val))); } \
@@ -486,6 +654,11 @@ OPENCV_HAL_IMPL_NEON_INT_CMP_OP(v_int16x8, vreinterpretq_s16_u16, s16, u16)
 OPENCV_HAL_IMPL_NEON_INT_CMP_OP(v_uint32x4, OPENCV_HAL_NOP, u32, u32)
 OPENCV_HAL_IMPL_NEON_INT_CMP_OP(v_int32x4, vreinterpretq_s32_u32, s32, u32)
 OPENCV_HAL_IMPL_NEON_INT_CMP_OP(v_float32x4, vreinterpretq_f32_u32, f32, u32)
+#if CV_SIMD128_64F
+OPENCV_HAL_IMPL_NEON_INT_CMP_OP(v_uint64x2, OPENCV_HAL_NOP, u64, u64)
+OPENCV_HAL_IMPL_NEON_INT_CMP_OP(v_int64x2, vreinterpretq_s64_u64, s64, u64)
+OPENCV_HAL_IMPL_NEON_INT_CMP_OP(v_float64x2, vreinterpretq_f64_u64, f64, u64)
+#endif
 
 OPENCV_HAL_IMPL_NEON_BIN_FUNC(v_uint8x16, v_add_wrap, vaddq_u8)
 OPENCV_HAL_IMPL_NEON_BIN_FUNC(v_int8x16, v_add_wrap, vaddq_s8)
@@ -501,6 +674,9 @@ OPENCV_HAL_IMPL_NEON_BIN_FUNC(v_uint8x16, v_absdiff, vabdq_u8)
 OPENCV_HAL_IMPL_NEON_BIN_FUNC(v_uint16x8, v_absdiff, vabdq_u16)
 OPENCV_HAL_IMPL_NEON_BIN_FUNC(v_uint32x4, v_absdiff, vabdq_u32)
 OPENCV_HAL_IMPL_NEON_BIN_FUNC(v_float32x4, v_absdiff, vabdq_f32)
+#if CV_SIMD128_64F
+OPENCV_HAL_IMPL_NEON_BIN_FUNC(v_float64x2, v_absdiff, vabdq_f64)
+#endif
 
 #define OPENCV_HAL_IMPL_NEON_BIN_FUNC2(_Tpvec, _Tpvec2, cast, func, intrin) \
 inline _Tpvec2 func(const _Tpvec& a, const _Tpvec& b) \
@@ -528,6 +704,24 @@ inline v_float32x4 v_muladd(const v_float32x4& a, const v_float32x4& b, const v_
     return v_float32x4(vmlaq_f32(c.val, a.val, b.val));
 }
 
+#if CV_SIMD128_64F
+inline v_float64x2 v_magnitude(const v_float64x2& a, const v_float64x2& b)
+{
+    v_float64x2 x(vaddq_f64(vmulq_f64(a.val, a.val), vmulq_f64(b.val, b.val)));
+    return v_sqrt(x);
+}
+
+inline v_float64x2 v_sqr_magnitude(const v_float64x2& a, const v_float64x2& b)
+{
+    return v_float64x2(vaddq_f64(vmulq_f64(a.val, a.val), vmulq_f64(b.val, b.val)));
+}
+
+inline v_float64x2 v_muladd(const v_float64x2& a, const v_float64x2& b, const v_float64x2& c)
+{
+    return v_float64x2(vaddq_f64(c.val, vmulq_f64(a.val, b.val)));
+}
+#endif
+
 // trade efficiency for convenience
 #define OPENCV_HAL_IMPL_NEON_SHIFT_OP(_Tpvec, suffix, _Tps, ssuffix) \
 inline _Tpvec operator << (const _Tpvec& a, int n) \
@@ -575,26 +769,49 @@ OPENCV_HAL_IMPL_NEON_LOADSTORE_OP(v_int32x4, int, s32)
 OPENCV_HAL_IMPL_NEON_LOADSTORE_OP(v_uint64x2, uint64, u64)
 OPENCV_HAL_IMPL_NEON_LOADSTORE_OP(v_int64x2, int64, s64)
 OPENCV_HAL_IMPL_NEON_LOADSTORE_OP(v_float32x4, float, f32)
+#if CV_SIMD128_64F
+OPENCV_HAL_IMPL_NEON_LOADSTORE_OP(v_float64x2, double, f64)
+#endif
+
+#if defined (HAVE_FP16)
+// Workaround for old comiplers
+inline v_float16x4 v_load_f16(const short* ptr)
+{ return v_float16x4(vld1_f16(ptr)); }
+inline void v_store_f16(short* ptr, v_float16x4& a)
+{ vst1_f16(ptr, a.val); }
+#endif
+
+#define OPENCV_HAL_IMPL_NEON_REDUCE_OP_8(_Tpvec, _Tpnvec, scalartype, func, vectorfunc, suffix) \
+inline scalartype v_reduce_##func(const _Tpvec& a) \
+{ \
+    _Tpnvec##_t a0 = vp##vectorfunc##_##suffix(vget_low_##suffix(a.val), vget_high_##suffix(a.val)); \
+    a0 = vp##vectorfunc##_##suffix(a0, a0); \
+    return (scalartype)vget_lane_##suffix(vp##vectorfunc##_##suffix(a0, a0),0); \
+}
 
-#define OPENCV_HAL_IMPL_NEON_REDUCE_OP_4(_Tpvec, scalartype, func, scalar_func) \
+OPENCV_HAL_IMPL_NEON_REDUCE_OP_8(v_uint16x8, uint16x4, unsigned short, sum, add, u16)
+OPENCV_HAL_IMPL_NEON_REDUCE_OP_8(v_uint16x8, uint16x4, unsigned short, max, max, u16)
+OPENCV_HAL_IMPL_NEON_REDUCE_OP_8(v_uint16x8, uint16x4, unsigned short, min, min, u16)
+OPENCV_HAL_IMPL_NEON_REDUCE_OP_8(v_int16x8, int16x4, short, sum, add, s16)
+OPENCV_HAL_IMPL_NEON_REDUCE_OP_8(v_int16x8, int16x4, short, max, max, s16)
+OPENCV_HAL_IMPL_NEON_REDUCE_OP_8(v_int16x8, int16x4, short, min, min, s16)
+
+#define OPENCV_HAL_IMPL_NEON_REDUCE_OP_4(_Tpvec, _Tpnvec, scalartype, func, vectorfunc, suffix) \
 inline scalartype v_reduce_##func(const _Tpvec& a) \
 { \
-    scalartype CV_DECL_ALIGNED(16) buf[4]; \
-    v_store_aligned(buf, a); \
-    scalartype s0 = scalar_func(buf[0], buf[1]); \
-    scalartype s1 = scalar_func(buf[2], buf[3]); \
-    return scalar_func(s0, s1); \
+    _Tpnvec##_t a0 = vp##vectorfunc##_##suffix(vget_low_##suffix(a.val), vget_high_##suffix(a.val)); \
+    return (scalartype)vget_lane_##suffix(vp##vectorfunc##_##suffix(a0, vget_high_##suffix(a.val)),0); \
 }
 
-OPENCV_HAL_IMPL_NEON_REDUCE_OP_4(v_uint32x4, unsigned, sum, OPENCV_HAL_ADD)
-OPENCV_HAL_IMPL_NEON_REDUCE_OP_4(v_uint32x4, unsigned, max, std::max)
-OPENCV_HAL_IMPL_NEON_REDUCE_OP_4(v_uint32x4, unsigned, min, std::min)
-OPENCV_HAL_IMPL_NEON_REDUCE_OP_4(v_int32x4, int, sum, OPENCV_HAL_ADD)
-OPENCV_HAL_IMPL_NEON_REDUCE_OP_4(v_int32x4, int, max, std::max)
-OPENCV_HAL_IMPL_NEON_REDUCE_OP_4(v_int32x4, int, min, std::min)
-OPENCV_HAL_IMPL_NEON_REDUCE_OP_4(v_float32x4, float, sum, OPENCV_HAL_ADD)
-OPENCV_HAL_IMPL_NEON_REDUCE_OP_4(v_float32x4, float, max, std::max)
-OPENCV_HAL_IMPL_NEON_REDUCE_OP_4(v_float32x4, float, min, std::min)
+OPENCV_HAL_IMPL_NEON_REDUCE_OP_4(v_uint32x4, uint32x2, unsigned, sum, add, u32)
+OPENCV_HAL_IMPL_NEON_REDUCE_OP_4(v_uint32x4, uint32x2, unsigned, max, max, u32)
+OPENCV_HAL_IMPL_NEON_REDUCE_OP_4(v_uint32x4, uint32x2, unsigned, min, min, u32)
+OPENCV_HAL_IMPL_NEON_REDUCE_OP_4(v_int32x4, int32x2, int, sum, add, s32)
+OPENCV_HAL_IMPL_NEON_REDUCE_OP_4(v_int32x4, int32x2, int, max, max, s32)
+OPENCV_HAL_IMPL_NEON_REDUCE_OP_4(v_int32x4, int32x2, int, min, min, s32)
+OPENCV_HAL_IMPL_NEON_REDUCE_OP_4(v_float32x4, float32x2, float, sum, add, f32)
+OPENCV_HAL_IMPL_NEON_REDUCE_OP_4(v_float32x4, float32x2, float, max, max, f32)
+OPENCV_HAL_IMPL_NEON_REDUCE_OP_4(v_float32x4, float32x2, float, min, min, f32)
 
 inline int v_signmask(const v_uint8x16& a)
 {
@@ -627,6 +844,16 @@ inline int v_signmask(const v_int32x4& a)
 { return v_signmask(v_reinterpret_as_u32(a)); }
 inline int v_signmask(const v_float32x4& a)
 { return v_signmask(v_reinterpret_as_u32(a)); }
+#if CV_SIMD128_64F
+inline int v_signmask(const v_uint64x2& a)
+{
+    int64x1_t m0 = vdup_n_s64(0);
+    uint64x2_t v0 = vshlq_u64(vshrq_n_u64(a.val, 63), vcombine_s64(m0, m0));
+    return (int)vgetq_lane_u64(v0, 0) + ((int)vgetq_lane_u64(v0, 1) << 1);
+}
+inline int v_signmask(const v_float64x2& a)
+{ return v_signmask(v_reinterpret_as_u64(a)); }
+#endif
 
 #define OPENCV_HAL_IMPL_NEON_CHECK_ALLANY(_Tpvec, suffix, shift) \
 inline bool v_check_all(const v_##_Tpvec& a) \
@@ -645,6 +872,9 @@ inline bool v_check_any(const v_##_Tpvec& a) \
 OPENCV_HAL_IMPL_NEON_CHECK_ALLANY(uint8x16, u8, 7)
 OPENCV_HAL_IMPL_NEON_CHECK_ALLANY(uint16x8, u16, 15)
 OPENCV_HAL_IMPL_NEON_CHECK_ALLANY(uint32x4, u32, 31)
+#if CV_SIMD128_64F
+OPENCV_HAL_IMPL_NEON_CHECK_ALLANY(uint64x2, u64, 63)
+#endif
 
 inline bool v_check_all(const v_int8x16& a)
 { return v_check_all(v_reinterpret_as_u8(a)); }
@@ -664,6 +894,17 @@ inline bool v_check_any(const v_int32x4& a)
 inline bool v_check_any(const v_float32x4& a)
 { return v_check_any(v_reinterpret_as_u32(a)); }
 
+#if CV_SIMD128_64F
+inline bool v_check_all(const v_int64x2& a)
+{ return v_check_all(v_reinterpret_as_u64(a)); }
+inline bool v_check_all(const v_float64x2& a)
+{ return v_check_all(v_reinterpret_as_u64(a)); }
+inline bool v_check_any(const v_int64x2& a)
+{ return v_check_any(v_reinterpret_as_u64(a)); }
+inline bool v_check_any(const v_float64x2& a)
+{ return v_check_any(v_reinterpret_as_u64(a)); }
+#endif
+
 #define OPENCV_HAL_IMPL_NEON_SELECT(_Tpvec, suffix, usuffix) \
 inline _Tpvec v_select(const _Tpvec& mask, const _Tpvec& a, const _Tpvec& b) \
 { \
@@ -677,6 +918,9 @@ OPENCV_HAL_IMPL_NEON_SELECT(v_int16x8, s16, u16)
 OPENCV_HAL_IMPL_NEON_SELECT(v_uint32x4, u32, u32)
 OPENCV_HAL_IMPL_NEON_SELECT(v_int32x4, s32, u32)
 OPENCV_HAL_IMPL_NEON_SELECT(v_float32x4, f32, u32)
+#if CV_SIMD128_64F
+OPENCV_HAL_IMPL_NEON_SELECT(v_float64x2, f64, u64)
+#endif
 
 #define OPENCV_HAL_IMPL_NEON_EXPAND(_Tpvec, _Tpwvec, _Tp, suffix) \
 inline void v_expand(const _Tpvec& a, _Tpwvec& b0, _Tpwvec& b1) \
@@ -710,6 +954,27 @@ inline v_int32x4 v_load_expand_q(const schar* ptr)
     return v_int32x4(vmovl_s16(v1));
 }
 
+#if defined(__aarch64__)
+#define OPENCV_HAL_IMPL_NEON_UNPACKS(_Tpvec, suffix) \
+inline void v_zip(const v_##_Tpvec& a0, const v_##_Tpvec& a1, v_##_Tpvec& b0, v_##_Tpvec& b1) \
+{ \
+    b0.val = vzip1q_##suffix(a0.val, a1.val); \
+    b1.val = vzip2q_##suffix(a0.val, a1.val); \
+} \
+inline v_##_Tpvec v_combine_low(const v_##_Tpvec& a, const v_##_Tpvec& b) \
+{ \
+    return v_##_Tpvec(vcombine_##suffix(vget_low_##suffix(a.val), vget_low_##suffix(b.val))); \
+} \
+inline v_##_Tpvec v_combine_high(const v_##_Tpvec& a, const v_##_Tpvec& b) \
+{ \
+    return v_##_Tpvec(vcombine_##suffix(vget_high_##suffix(a.val), vget_high_##suffix(b.val))); \
+} \
+inline void v_recombine(const v_##_Tpvec& a, const v_##_Tpvec& b, v_##_Tpvec& c, v_##_Tpvec& d) \
+{ \
+    c.val = vcombine_##suffix(vget_low_##suffix(a.val), vget_low_##suffix(b.val)); \
+    d.val = vcombine_##suffix(vget_high_##suffix(a.val), vget_high_##suffix(b.val)); \
+}
+#else
 #define OPENCV_HAL_IMPL_NEON_UNPACKS(_Tpvec, suffix) \
 inline void v_zip(const v_##_Tpvec& a0, const v_##_Tpvec& a1, v_##_Tpvec& b0, v_##_Tpvec& b1) \
 { \
@@ -730,6 +995,7 @@ inline void v_recombine(const v_##_Tpvec& a, const v_##_Tpvec& b, v_##_Tpvec& c,
     c.val = vcombine_##suffix(vget_low_##suffix(a.val), vget_low_##suffix(b.val)); \
     d.val = vcombine_##suffix(vget_high_##suffix(a.val), vget_high_##suffix(b.val)); \
 }
+#endif
 
 OPENCV_HAL_IMPL_NEON_UNPACKS(uint8x16, u8)
 OPENCV_HAL_IMPL_NEON_UNPACKS(int8x16, s8)
@@ -738,6 +1004,9 @@ OPENCV_HAL_IMPL_NEON_UNPACKS(int16x8, s16)
 OPENCV_HAL_IMPL_NEON_UNPACKS(uint32x4, u32)
 OPENCV_HAL_IMPL_NEON_UNPACKS(int32x4, s32)
 OPENCV_HAL_IMPL_NEON_UNPACKS(float32x4, f32)
+#if CV_SIMD128_64F
+OPENCV_HAL_IMPL_NEON_UNPACKS(float64x2, f64)
+#endif
 
 #define OPENCV_HAL_IMPL_NEON_EXTRACT(_Tpvec, suffix) \
 template <int s> \
@@ -755,6 +1024,9 @@ OPENCV_HAL_IMPL_NEON_EXTRACT(int32x4, s32)
 OPENCV_HAL_IMPL_NEON_EXTRACT(uint64x2, u64)
 OPENCV_HAL_IMPL_NEON_EXTRACT(int64x2, s64)
 OPENCV_HAL_IMPL_NEON_EXTRACT(float32x4, f32)
+#if CV_SIMD128_64F
+OPENCV_HAL_IMPL_NEON_EXTRACT(float64x2, f64)
+#endif
 
 inline v_int32x4 v_round(const v_float32x4& a)
 {
@@ -782,6 +1054,38 @@ inline v_int32x4 v_ceil(const v_float32x4& a)
 inline v_int32x4 v_trunc(const v_float32x4& a)
 { return v_int32x4(vcvtq_s32_f32(a.val)); }
 
+#if CV_SIMD128_64F
+inline v_int32x4 v_round(const v_float64x2& a)
+{
+    static const int32x2_t zero = vdup_n_s32(0);
+    return v_int32x4(vcombine_s32(vmovn_s64(vcvtaq_s64_f64(a.val)), zero));
+}
+
+inline v_int32x4 v_floor(const v_float64x2& a)
+{
+    static const int32x2_t zero = vdup_n_s32(0);
+    int64x2_t a1 = vcvtq_s64_f64(a.val);
+    uint64x2_t mask = vcgtq_f64(vcvtq_f64_s64(a1), a.val);
+    a1 = vaddq_s64(a1, vreinterpretq_s64_u64(mask));
+    return v_int32x4(vcombine_s32(vmovn_s64(a1), zero));
+}
+
+inline v_int32x4 v_ceil(const v_float64x2& a)
+{
+    static const int32x2_t zero = vdup_n_s32(0);
+    int64x2_t a1 = vcvtq_s64_f64(a.val);
+    uint64x2_t mask = vcgtq_f64(a.val, vcvtq_f64_s64(a1));
+    a1 = vsubq_s64(a1, vreinterpretq_s64_u64(mask));
+    return v_int32x4(vcombine_s32(vmovn_s64(a1), zero));
+}
+
+inline v_int32x4 v_trunc(const v_float64x2& a)
+{
+    static const int32x2_t zero = vdup_n_s32(0);
+    return v_int32x4(vcombine_s32(vmovn_s64(vcvtaq_s64_f64(a.val)), zero));
+}
+#endif
+
 #define OPENCV_HAL_IMPL_NEON_TRANSPOSE4x4(_Tpvec, suffix) \
 inline void v_transpose4x4(const v_##_Tpvec& a0, const v_##_Tpvec& a1, \
                          const v_##_Tpvec& a2, const v_##_Tpvec& a3, \
@@ -809,6 +1113,12 @@ OPENCV_HAL_IMPL_NEON_TRANSPOSE4x4(int32x4, s32)
 OPENCV_HAL_IMPL_NEON_TRANSPOSE4x4(float32x4, f32)
 
 #define OPENCV_HAL_IMPL_NEON_INTERLEAVED(_Tpvec, _Tp, suffix) \
+inline void v_load_deinterleave(const _Tp* ptr, v_##_Tpvec& a, v_##_Tpvec& b) \
+{ \
+    _Tpvec##x2_t v = vld2q_##suffix(ptr); \
+    a.val = v.val[0]; \
+    b.val = v.val[1]; \
+} \
 inline void v_load_deinterleave(const _Tp* ptr, v_##_Tpvec& a, v_##_Tpvec& b, v_##_Tpvec& c) \
 { \
     _Tpvec##x3_t v = vld3q_##suffix(ptr); \
@@ -825,6 +1135,13 @@ inline void v_load_deinterleave(const _Tp* ptr, v_##_Tpvec& a, v_##_Tpvec& b, \
     c.val = v.val[2]; \
     d.val = v.val[3]; \
 } \
+inline void v_store_interleave( _Tp* ptr, const v_##_Tpvec& a, const v_##_Tpvec& b) \
+{ \
+    _Tpvec##x2_t v; \
+    v.val[0] = a.val; \
+    v.val[1] = b.val; \
+    vst2q_##suffix(ptr, v); \
+} \
 inline void v_store_interleave( _Tp* ptr, const v_##_Tpvec& a, const v_##_Tpvec& b, const v_##_Tpvec& c) \
 { \
     _Tpvec##x3_t v; \
@@ -851,12 +1168,65 @@ OPENCV_HAL_IMPL_NEON_INTERLEAVED(int16x8, short, s16)
 OPENCV_HAL_IMPL_NEON_INTERLEAVED(uint32x4, unsigned, u32)
 OPENCV_HAL_IMPL_NEON_INTERLEAVED(int32x4, int, s32)
 OPENCV_HAL_IMPL_NEON_INTERLEAVED(float32x4, float, f32)
+#if CV_SIMD128_64F
+OPENCV_HAL_IMPL_NEON_INTERLEAVED(float64x2, double, f64)
+#endif
 
 inline v_float32x4 v_cvt_f32(const v_int32x4& a)
 {
     return v_float32x4(vcvtq_f32_s32(a.val));
 }
 
+#if CV_SIMD128_64F
+inline v_float32x4 v_cvt_f32(const v_float64x2& a)
+{
+    float32x2_t zero = vdup_n_f32(0.0f);
+    return v_float32x4(vcombine_f32(vcvt_f32_f64(a.val), zero));
+}
+
+inline v_float64x2 v_cvt_f64(const v_int32x4& a)
+{
+    return v_float64x2(vcvt_f64_f32(vcvt_f32_s32(vget_low_s32(a.val))));
+}
+
+inline v_float64x2 v_cvt_f64_high(const v_int32x4& a)
+{
+    return v_float64x2(vcvt_f64_f32(vcvt_f32_s32(vget_high_s32(a.val))));
+}
+
+inline v_float64x2 v_cvt_f64(const v_float32x4& a)
+{
+    return v_float64x2(vcvt_f64_f32(vget_low_f32(a.val)));
+}
+
+inline v_float64x2 v_cvt_f64_high(const v_float32x4& a)
+{
+    return v_float64x2(vcvt_f64_f32(vget_high_f32(a.val)));
+}
+#endif
+
+#if defined (HAVE_FP16)
+inline v_float32x4 v_cvt_f32(const v_float16x4& a)
+{
+    return v_float32x4(vcvt_f32_f16(a.val));
+}
+
+inline v_float16x4 v_cvt_f16(const v_float32x4& a)
+{
+    return v_float16x4(vcvt_f16_f32(a.val));
+}
+#endif
+
+//! @name Check SIMD support
+//! @{
+//! @brief Check CPU capability of SIMD operation
+static inline bool hasSIMD128()
+{
+    return checkHardwareSupport(CV_CPU_NEON);
+}
+
+//! @}
+
 //! @endcond
 
 }
diff --git a/modules/core/include/opencv2/core/hal/intrin_sse.hpp b/modules/core/include/opencv2/core/hal/intrin_sse.hpp
index 1840e03..fc81dac 100644
--- a/modules/core/include/opencv2/core/hal/intrin_sse.hpp
+++ b/modules/core/include/opencv2/core/hal/intrin_sse.hpp
@@ -42,10 +42,11 @@
 //
 //M*/
 
-#ifndef __OPENCV_HAL_SSE_HPP__
-#define __OPENCV_HAL_SSE_HPP__
+#ifndef OPENCV_HAL_SSE_HPP
+#define OPENCV_HAL_SSE_HPP
 
 #include <algorithm>
+#include "opencv2/core/utility.hpp"
 
 #define CV_SIMD128 1
 #define CV_SIMD128_64F 1
@@ -252,6 +253,26 @@ struct v_float64x2
     __m128d val;
 };
 
+#if defined(HAVE_FP16)
+struct v_float16x4
+{
+    typedef short lane_type;
+    enum { nlanes = 4 };
+
+    v_float16x4() {}
+    explicit v_float16x4(__m128i v) : val(v) {}
+    v_float16x4(short v0, short v1, short v2, short v3)
+    {
+        val = _mm_setr_epi16(v0, v1, v2, v3, 0, 0, 0, 0);
+    }
+    short get0() const
+    {
+        return (short)_mm_cvtsi128_si32(val);
+    }
+    __m128i val;
+};
+#endif
+
 #define OPENCV_HAL_IMPL_SSE_INITVEC(_Tpvec, _Tp, suffix, zsuffix, ssuffix, _Tps, cast) \
 inline _Tpvec v_setzero_##suffix() { return _Tpvec(_mm_setzero_##zsuffix()); } \
 inline _Tpvec v_setall_##suffix(_Tp v) { return _Tpvec(_mm_set1_##ssuffix((_Tps)v)); } \
@@ -719,6 +740,18 @@ inline v_float64x2 v_invsqrt(const v_float64x2& x)
     return v_float64x2(_mm_div_pd(v_1, _mm_sqrt_pd(x.val)));
 }
 
+#define OPENCV_HAL_IMPL_SSE_ABS_INT_FUNC(_Tpuvec, _Tpsvec, func, suffix, subWidth) \
+inline _Tpuvec v_abs(const _Tpsvec& x) \
+{ return _Tpuvec(_mm_##func##_ep##suffix(x.val, _mm_sub_ep##subWidth(_mm_setzero_si128(), x.val))); }
+
+OPENCV_HAL_IMPL_SSE_ABS_INT_FUNC(v_uint8x16, v_int8x16, min, u8, i8)
+OPENCV_HAL_IMPL_SSE_ABS_INT_FUNC(v_uint16x8, v_int16x8, max, i16, i16)
+inline v_uint32x4 v_abs(const v_int32x4& x)
+{
+    __m128i s = _mm_srli_epi32(x.val, 31);
+    __m128i f = _mm_srai_epi32(x.val, 31);
+    return v_uint32x4(_mm_add_epi32(_mm_xor_si128(x.val, f), s));
+}
 inline v_float32x4 v_abs(const v_float32x4& x)
 { return v_float32x4(_mm_and_ps(x.val, _mm_castsi128_ps(_mm_set1_epi32(0x7fffffff)))); }
 inline v_float64x2 v_abs(const v_float64x2& x)
@@ -1021,6 +1054,53 @@ inline void v_store_high(_Tp* ptr, const _Tpvec& a) \
 OPENCV_HAL_IMPL_SSE_LOADSTORE_FLT_OP(v_float32x4, float, ps)
 OPENCV_HAL_IMPL_SSE_LOADSTORE_FLT_OP(v_float64x2, double, pd)
 
+#if defined(HAVE_FP16)
+inline v_float16x4 v_load_f16(const short* ptr)
+{ return v_float16x4(_mm_loadl_epi64((const __m128i*)ptr)); }
+inline void v_store_f16(short* ptr, v_float16x4& a)
+{ _mm_storel_epi64((__m128i*)ptr, a.val); }
+#endif
+
+#define OPENCV_HAL_IMPL_SSE_REDUCE_OP_8(_Tpvec, scalartype, func, suffix, sbit) \
+inline scalartype v_reduce_##func(const v_##_Tpvec& a) \
+{ \
+    __m128i val = a.val; \
+    val = _mm_##func##_##suffix(val, _mm_srli_si128(val,8)); \
+    val = _mm_##func##_##suffix(val, _mm_srli_si128(val,4)); \
+    val = _mm_##func##_##suffix(val, _mm_srli_si128(val,2)); \
+    return (scalartype)_mm_cvtsi128_si32(val); \
+} \
+inline unsigned scalartype v_reduce_##func(const v_u##_Tpvec& a) \
+{ \
+    __m128i val = a.val; \
+    __m128i smask = _mm_set1_epi16(sbit); \
+    val = _mm_xor_si128(val, smask); \
+    val = _mm_##func##_##suffix(val, _mm_srli_si128(val,8)); \
+    val = _mm_##func##_##suffix(val, _mm_srli_si128(val,4)); \
+    val = _mm_##func##_##suffix(val, _mm_srli_si128(val,2)); \
+    return (unsigned scalartype)(_mm_cvtsi128_si32(val) ^  sbit); \
+}
+#define OPENCV_HAL_IMPL_SSE_REDUCE_OP_8_SUM(_Tpvec, scalartype, suffix) \
+inline scalartype v_reduce_sum(const v_##_Tpvec& a) \
+{ \
+    __m128i val = a.val; \
+    val = _mm_adds_epi##suffix(val, _mm_srli_si128(val, 8)); \
+    val = _mm_adds_epi##suffix(val, _mm_srli_si128(val, 4)); \
+    val = _mm_adds_epi##suffix(val, _mm_srli_si128(val, 2)); \
+    return (scalartype)_mm_cvtsi128_si32(val); \
+} \
+inline unsigned scalartype v_reduce_sum(const v_u##_Tpvec& a) \
+{ \
+    __m128i val = a.val; \
+    val = _mm_adds_epu##suffix(val, _mm_srli_si128(val, 8)); \
+    val = _mm_adds_epu##suffix(val, _mm_srli_si128(val, 4)); \
+    val = _mm_adds_epu##suffix(val, _mm_srli_si128(val, 2)); \
+    return (unsigned scalartype)_mm_cvtsi128_si32(val); \
+}
+OPENCV_HAL_IMPL_SSE_REDUCE_OP_8(int16x8, short, max, epi16, (short)-32768)
+OPENCV_HAL_IMPL_SSE_REDUCE_OP_8(int16x8, short, min, epi16, (short)-32768)
+OPENCV_HAL_IMPL_SSE_REDUCE_OP_8_SUM(int16x8, short, 16)
+
 #define OPENCV_HAL_IMPL_SSE_REDUCE_OP_4(_Tpvec, scalartype, func, scalar_func) \
 inline scalartype v_reduce_##func(const _Tpvec& a) \
 { \
@@ -1374,6 +1454,27 @@ inline void v_load_deinterleave(const unsigned* ptr, v_uint32x4& a, v_uint32x4&
     v_transpose4x4(u0, u1, u2, u3, a, b, c, d);
 }
 
+// 2-channel, float only
+inline void v_load_deinterleave(const float* ptr, v_float32x4& a, v_float32x4& b)
+{
+    const int mask_lo = _MM_SHUFFLE(2, 0, 2, 0), mask_hi = _MM_SHUFFLE(3, 1, 3, 1);
+
+    __m128 u0 = _mm_loadu_ps(ptr);       // a0 b0 a1 b1
+    __m128 u1 = _mm_loadu_ps((ptr + 4)); // a2 b2 a3 b3
+
+    a.val = _mm_shuffle_ps(u0, u1, mask_lo); // a0 a1 a2 a3
+    b.val = _mm_shuffle_ps(u0, u1, mask_hi); // b0 b1 ab b3
+}
+
+inline void v_store_interleave( short* ptr, const v_int16x8& a, const v_int16x8& b )
+{
+    __m128i t0, t1;
+    t0 = _mm_unpacklo_epi16(a.val, b.val);
+    t1 = _mm_unpackhi_epi16(a.val, b.val);
+    _mm_storeu_si128((__m128i*)(ptr), t0);
+    _mm_storeu_si128((__m128i*)(ptr + 8), t1);
+}
+
 inline void v_store_interleave( uchar* ptr, const v_uint8x16& a, const v_uint8x16& b,
                                 const v_uint8x16& c )
 {
@@ -1529,6 +1630,18 @@ inline void v_store_interleave(unsigned* ptr, const v_uint32x4& a, const v_uint3
     v_store(ptr + 12, t3);
 }
 
+// 2-channel, float only
+inline void v_store_interleave(float* ptr, const v_float32x4& a, const v_float32x4& b)
+{
+    // a0 a1 a2 a3 ...
+    // b0 b1 b2 b3 ...
+    __m128 u0 = _mm_unpacklo_ps(a.val, b.val); // a0 b0 a1 b1
+    __m128 u1 = _mm_unpackhi_ps(a.val, b.val); // a2 b2 a3 b3
+
+    _mm_storeu_ps(ptr, u0);
+    _mm_storeu_ps((ptr + 4), u1);
+}
+
 #define OPENCV_HAL_IMPL_SSE_LOADSTORE_INTERLEAVE(_Tpvec, _Tp, suffix, _Tpuvec, _Tpu, usuffix) \
 inline void v_load_deinterleave( const _Tp* ptr, _Tpvec& a0, \
                                  _Tpvec& b0, _Tpvec& c0 ) \
@@ -1587,11 +1700,43 @@ inline v_float64x2 v_cvt_f64(const v_int32x4& a)
     return v_float64x2(_mm_cvtepi32_pd(a.val));
 }
 
+inline v_float64x2 v_cvt_f64_high(const v_int32x4& a)
+{
+    return v_float64x2(_mm_cvtepi32_pd(_mm_srli_si128(a.val,8)));
+}
+
 inline v_float64x2 v_cvt_f64(const v_float32x4& a)
 {
     return v_float64x2(_mm_cvtps_pd(a.val));
 }
 
+inline v_float64x2 v_cvt_f64_high(const v_float32x4& a)
+{
+    return v_float64x2(_mm_cvtps_pd(_mm_castsi128_ps(_mm_srli_si128(_mm_castps_si128(a.val),8))));
+}
+
+#if defined(HAVE_FP16)
+inline v_float32x4 v_cvt_f32(const v_float16x4& a)
+{
+    return v_float32x4(_mm_cvtph_ps(a.val));
+}
+
+inline v_float16x4 v_cvt_f16(const v_float32x4& a)
+{
+    return v_float16x4(_mm_cvtps_ph(a.val, 0));
+}
+#endif
+
+//! @name Check SIMD support
+//! @{
+//! @brief Check CPU capability of SIMD operation
+static inline bool hasSIMD128()
+{
+    return checkHardwareSupport(CV_CPU_SSE2);
+}
+
+//! @}
+
 //! @endcond
 
 }
diff --git a/modules/core/include/opencv2/core/ippasync.hpp b/modules/core/include/opencv2/core/ippasync.hpp
index 4de8611..0ed8264 100644
--- a/modules/core/include/opencv2/core/ippasync.hpp
+++ b/modules/core/include/opencv2/core/ippasync.hpp
@@ -42,8 +42,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_CORE_IPPASYNC_HPP__
-#define __OPENCV_CORE_IPPASYNC_HPP__
+#ifndef OPENCV_CORE_IPPASYNC_HPP
+#define OPENCV_CORE_IPPASYNC_HPP
 
 #ifdef HAVE_IPP_A
 
diff --git a/modules/core/include/opencv2/core/mat.hpp b/modules/core/include/opencv2/core/mat.hpp
index ffec538..39c197e 100644
--- a/modules/core/include/opencv2/core/mat.hpp
+++ b/modules/core/include/opencv2/core/mat.hpp
@@ -41,8 +41,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_CORE_MAT_HPP__
-#define __OPENCV_CORE_MAT_HPP__
+#ifndef OPENCV_CORE_MAT_HPP
+#define OPENCV_CORE_MAT_HPP
 
 #ifndef __cplusplus
 #  error mat.hpp header must be compiled as C++
@@ -795,6 +795,13 @@ public:
     Mat(int ndims, const int* sizes, int type);
 
     /** @overload
+    @param sizes Array of integers specifying an n-dimensional array shape.
+    @param type Array type. Use CV_8UC1, ..., CV_64FC4 to create 1-4 channel matrices, or
+    CV_8UC(n), ..., CV_64FC(n) to create multi-channel (up to CV_CN_MAX channels) matrices.
+    */
+    Mat(const std::vector<int>& sizes, int type);
+
+    /** @overload
     @param ndims Array dimensionality.
     @param sizes Array of integers specifying an n-dimensional array shape.
     @param type Array type. Use CV_8UC1, ..., CV_64FC4 to create 1-4 channel matrices, or
@@ -806,6 +813,17 @@ public:
     Mat(int ndims, const int* sizes, int type, const Scalar& s);
 
     /** @overload
+    @param sizes Array of integers specifying an n-dimensional array shape.
+    @param type Array type. Use CV_8UC1, ..., CV_64FC4 to create 1-4 channel matrices, or
+    CV_8UC(n), ..., CV_64FC(n) to create multi-channel (up to CV_CN_MAX channels) matrices.
+    @param s An optional value to initialize each matrix element with. To set all the matrix elements to
+    the particular value after the construction, use the assignment operator
+    Mat::operator=(const Scalar& value) .
+    */
+    Mat(const std::vector<int>& sizes, int type, const Scalar& s);
+
+
+    /** @overload
     @param m Array that (as a whole or partly) is assigned to the constructed matrix. No data is copied
     by these constructors. Instead, the header pointing to m data or its sub-array is constructed and
     associated with it. The reference counter, if any, is incremented. So, when you modify the matrix
@@ -862,6 +880,20 @@ public:
     Mat(int ndims, const int* sizes, int type, void* data, const size_t* steps=0);
 
     /** @overload
+    @param sizes Array of integers specifying an n-dimensional array shape.
+    @param type Array type. Use CV_8UC1, ..., CV_64FC4 to create 1-4 channel matrices, or
+    CV_8UC(n), ..., CV_64FC(n) to create multi-channel (up to CV_CN_MAX channels) matrices.
+    @param data Pointer to the user data. Matrix constructors that take data and step parameters do not
+    allocate matrix data. Instead, they just initialize the matrix header that points to the specified
+    data, which means that no data is copied. This operation is very efficient and can be used to
+    process external data using OpenCV functions. The external data is not automatically deallocated, so
+    you should take care of it.
+    @param steps Array of ndims-1 steps in case of a multi-dimensional array (the last step is always
+    set to the element size). If not specified, the matrix is assumed to be continuous.
+    */
+    Mat(const std::vector<int>& sizes, int type, void* data, const size_t* steps=0);
+
+    /** @overload
     @param m Array that (as a whole or partly) is assigned to the constructed matrix. No data is copied
     by these constructors. Instead, the header pointing to m data or its sub-array is constructed and
     associated with it. The reference counter, if any, is incremented. So, when you modify the matrix
@@ -894,6 +926,16 @@ public:
     Mat(const Mat& m, const Range* ranges);
 
     /** @overload
+    @param m Array that (as a whole or partly) is assigned to the constructed matrix. No data is copied
+    by these constructors. Instead, the header pointing to m data or its sub-array is constructed and
+    associated with it. The reference counter, if any, is incremented. So, when you modify the matrix
+    formed using such a constructor, you also modify the corresponding elements of m . If you want to
+    have an independent copy of the sub-array, use Mat::clone() .
+    @param ranges Array of selected ranges of m along each dimensionality.
+    */
+    Mat(const Mat& m, const std::vector<Range>& ranges);
+
+    /** @overload
     @param vec STL vector whose elements form the matrix. The matrix has a single column and the number
     of rows equal to the number of vector elements. Type of the matrix matches the type of vector
     elements. The constructor can handle arbitrary types, for which there is a properly declared
@@ -1046,9 +1088,8 @@ public:
 
     /** @brief creates a diagonal matrix
 
-    The method makes a new header for the specified matrix diagonal. The new matrix is represented as a
-    single-column matrix. Similarly to Mat::row and Mat::col, this is an O(1) operation.
-    @param d Single-column matrix that forms a diagonal matrix
+    The method creates a square diagonal matrix from specified main diagonal.
+    @param d One-dimensional matrix that represents the main diagonal.
      */
     static Mat diag(const Mat& d);
 
@@ -1329,6 +1370,12 @@ public:
     */
     void create(int ndims, const int* sizes, int type);
 
+    /** @overload
+    @param sizes Array of integers specifying a new array shape.
+    @param type New matrix type.
+    */
+    void create(const std::vector<int>& sizes, int type);
+
     /** @brief Increments the reference counter.
 
     The method increments the reference counter associated with the matrix data. If the matrix header
@@ -1479,6 +1526,11 @@ public:
     */
     Mat operator()( const Range* ranges ) const;
 
+    /** @overload
+    @param ranges Array of selected ranges along each array dimension.
+    */
+    Mat operator()(const std::vector<Range>& ranges) const;
+
     // //! converts header to CvMat; no data is copied
     // operator CvMat() const;
     // //! converts header to CvMatND; no data is copied
@@ -1645,10 +1697,16 @@ public:
     /** @overload */
     const uchar* ptr(int i0=0) const;
 
-    /** @overload */
-    uchar* ptr(int i0, int i1);
-    /** @overload */
-    const uchar* ptr(int i0, int i1) const;
+    /** @overload
+    @param row Index along the dimension 0
+    @param col Index along the dimension 1
+    */
+    uchar* ptr(int row, int col);
+    /** @overload
+    @param row Index along the dimension 0
+    @param col Index along the dimension 1
+    */
+    const uchar* ptr(int row, int col) const;
 
     /** @overload */
     uchar* ptr(int i0, int i1, int i2);
@@ -1668,10 +1726,16 @@ public:
     template<typename _Tp> _Tp* ptr(int i0=0);
     /** @overload */
     template<typename _Tp> const _Tp* ptr(int i0=0) const;
-    /** @overload */
-    template<typename _Tp> _Tp* ptr(int i0, int i1);
-    /** @overload */
-    template<typename _Tp> const _Tp* ptr(int i0, int i1) const;
+    /** @overload
+    @param row Index along the dimension 0
+    @param col Index along the dimension 1
+    */
+    template<typename _Tp> _Tp* ptr(int row, int col);
+    /** @overload
+    @param row Index along the dimension 0
+    @param col Index along the dimension 1
+    */
+    template<typename _Tp> const _Tp* ptr(int row, int col) const;
     /** @overload */
     template<typename _Tp> _Tp* ptr(int i0, int i1, int i2);
     /** @overload */
@@ -1702,6 +1766,17 @@ public:
             for(int j = 0; j < H.cols; j++)
                 H.at<double>(i,j)=1./(i+j+1);
     @endcode
+
+    Keep in mind that the size identifier used in the at operator cannot be chosen at random. It depends
+    on the image from which you are trying to retrieve the data. The table below gives a better insight in this:
+     - If matrix is of type `CV_8U` then use `Mat.at<uchar>(y,x)`.
+     - If matrix is of type `CV_8S` then use `Mat.at<schar>(y,x)`.
+     - If matrix is of type `CV_16U` then use `Mat.at<ushort>(y,x)`.
+     - If matrix is of type `CV_16S` then use `Mat.at<short>(y,x)`.
+     - If matrix is of type `CV_32S`  then use `Mat.at<int>(y,x)`.
+     - If matrix is of type `CV_32F`  then use `Mat.at<float>(y,x)`.
+     - If matrix is of type `CV_64F` then use `Mat.at<double>(y,x)`.
+
     @param i0 Index along the dimension 0
      */
     template<typename _Tp> _Tp& at(int i0=0);
@@ -1710,15 +1785,15 @@ public:
     */
     template<typename _Tp> const _Tp& at(int i0=0) const;
     /** @overload
-    @param i0 Index along the dimension 0
-    @param i1 Index along the dimension 1
+    @param row Index along the dimension 0
+    @param col Index along the dimension 1
     */
-    template<typename _Tp> _Tp& at(int i0, int i1);
+    template<typename _Tp> _Tp& at(int row, int col);
     /** @overload
-    @param i0 Index along the dimension 0
-    @param i1 Index along the dimension 1
+    @param row Index along the dimension 0
+    @param col Index along the dimension 1
     */
-    template<typename _Tp> const _Tp& at(int i0, int i1) const;
+    template<typename _Tp> const _Tp& at(int row, int col) const;
 
     /** @overload
     @param i0 Index along the dimension 0
@@ -1805,12 +1880,11 @@ public:
     template<typename _Tp> MatIterator_<_Tp> end();
     template<typename _Tp> MatConstIterator_<_Tp> end() const;
 
-    /** @brief Invoke with arguments functor, and runs the functor over all matrix element.
+    /** @brief Runs the given functor over all matrix elements in parallel.
 
-    The methods runs operation in parallel. Operation is passed by arguments. Operation have to be a
-    function pointer, a function object or a lambda(C++11).
+    The operation passed as argument has to be a function pointer, a function object or a lambda(C++11).
 
-    All of below operation is equal. Put 0xFF to first channel of all matrix elements:
+    Example 1. All of the operations below put 0xFF the first channel of all matrix elements:
     @code
         Mat image(1920, 1080, CV_8UC3);
         typedef cv::Point3_<uint8_t> Pixel;
@@ -1842,18 +1916,18 @@ public:
             p.x = 255;
         });
     @endcode
-    position parameter is index of current pixel:
+    Example 2. Using the pixel's position:
     @code
-        // Creating 3D matrix (255 x 255 x 255) typed uint8_t,
-        //  and initialize all elements by the value which equals elements position.
-        //  i.e. pixels (x,y,z) = (1,2,3) is (b,g,r) = (1,2,3).
+        // Creating 3D matrix (255 x 255 x 255) typed uint8_t
+        // and initialize all elements by the value which equals elements position.
+        // i.e. pixels (x,y,z) = (1,2,3) is (b,g,r) = (1,2,3).
 
         int sizes[] = { 255, 255, 255 };
         typedef cv::Point3_<uint8_t> Pixel;
 
         Mat_<Pixel> image = Mat::zeros(3, sizes, CV_8UC3);
 
-        image.forEachWithPosition([&](Pixel& pixel, const int position[]) -> void{
+        image.forEach<Pixel>([&](Pixel& pixel, const int position[]) -> void {
             pixel.x = position[0];
             pixel.y = position[1];
             pixel.z = position[2];
@@ -1995,6 +2069,8 @@ public:
     Mat_(const Mat_& m, const Rect& roi);
     //! selects a submatrix, n-dim version
     Mat_(const Mat_& m, const Range* ranges);
+    //! selects a submatrix, n-dim version
+    Mat_(const Mat_& m, const std::vector<Range>& ranges);
     //! from a matrix expression
     explicit Mat_(const MatExpr& e);
     //! makes a matrix out of Vec, std::vector, Point_ or Point3_. The matrix will have a single column
@@ -2064,6 +2140,7 @@ public:
     Mat_ operator()( const Range& rowRange, const Range& colRange ) const;
     Mat_ operator()( const Rect& roi ) const;
     Mat_ operator()( const Range* ranges ) const;
+    Mat_ operator()(const std::vector<Range>& ranges) const;
 
     //! more convenient forms of row and element access operators
     _Tp* operator [](int y);
@@ -2084,9 +2161,9 @@ public:
     //! returns read-only reference to the specified element (1D case)
     const _Tp& operator ()(int idx0) const;
     //! returns reference to the specified element (2D case)
-    _Tp& operator ()(int idx0, int idx1);
+    _Tp& operator ()(int row, int col);
     //! returns read-only reference to the specified element (2D case)
-    const _Tp& operator ()(int idx0, int idx1) const;
+    const _Tp& operator ()(int row, int col) const;
     //! returns reference to the specified element (3D case)
     _Tp& operator ()(int idx0, int idx1, int idx2);
     //! returns read-only reference to the specified element (3D case)
@@ -2168,6 +2245,7 @@ public:
     UMat(const UMat& m, const Range& rowRange, const Range& colRange=Range::all());
     UMat(const UMat& m, const Rect& roi);
     UMat(const UMat& m, const Range* ranges);
+    UMat(const UMat& m, const std::vector<Range>& ranges);
     //! builds matrix from std::vector with or without copying the data
     template<typename _Tp> explicit UMat(const std::vector<_Tp>& vec, bool copyData=false);
     //! builds matrix from cv::Vec; the data is copied by default
@@ -2252,6 +2330,7 @@ public:
     void create(int rows, int cols, int type, UMatUsageFlags usageFlags = USAGE_DEFAULT);
     void create(Size size, int type, UMatUsageFlags usageFlags = USAGE_DEFAULT);
     void create(int ndims, const int* sizes, int type, UMatUsageFlags usageFlags = USAGE_DEFAULT);
+    void create(const std::vector<int>& sizes, int type, UMatUsageFlags usageFlags = USAGE_DEFAULT);
 
     //! increases the reference counter; use with care to avoid memleaks
     void addref();
@@ -2273,6 +2352,7 @@ public:
     UMat operator()( Range rowRange, Range colRange ) const;
     UMat operator()( const Rect& roi ) const;
     UMat operator()( const Range* ranges ) const;
+    UMat operator()(const std::vector<Range>& ranges) const;
 
     //! returns true iff the matrix data is continuous
     // (i.e. when there are no gaps between successive rows).
@@ -2359,15 +2439,16 @@ Elements can be accessed using the following methods:
     SparseMat::find), for example:
     @code
         const int dims = 5;
-        int size[] = {10, 10, 10, 10, 10};
+        int size[5] = {10, 10, 10, 10, 10};
         SparseMat sparse_mat(dims, size, CV_32F);
         for(int i = 0; i < 1000; i++)
         {
             int idx[dims];
             for(int k = 0; k < dims; k++)
-                idx[k] = rand()
+                idx[k] = rand() % size[k];
             sparse_mat.ref<float>(idx) += 1.f;
         }
+        cout << "nnz = " << sparse_mat.nzcount() << endl;
     @endcode
 -   Sparse matrix iterators. They are similar to MatIterator but different from NAryMatIterator.
     That is, the iteration loop is familiar to STL users:
@@ -2869,9 +2950,9 @@ public:
     //! copy operator
     MatConstIterator_& operator = (const MatConstIterator_& it);
     //! returns the current matrix element
-    _Tp operator *() const;
+    const _Tp& operator *() const;
     //! returns the i-th matrix element, relative to the current
-    _Tp operator [](ptrdiff_t i) const;
+    const _Tp& operator [](ptrdiff_t i) const;
 
     //! shifts the iterator forward by the specified number of elements
     MatConstIterator_& operator += (ptrdiff_t ofs);
@@ -3135,21 +3216,29 @@ The example below illustrates how you can compute a normalized and threshold 3D
         }
 
         minProb *= image.rows*image.cols;
-        Mat plane;
-        NAryMatIterator it(&hist, &plane, 1);
+
+        // initialize iterator (the style is different from STL).
+        // after initialization the iterator will contain
+        // the number of slices or planes the iterator will go through.
+        // it simultaneously increments iterators for several matrices
+        // supplied as a null terminated list of pointers
+        const Mat* arrays[] = {&hist, 0};
+        Mat planes[1];
+        NAryMatIterator itNAry(arrays, planes, 1);
         double s = 0;
         // iterate through the matrix. on each iteration
-        // it.planes[*] (of type Mat) will be set to the current plane.
-        for(int p = 0; p < it.nplanes; p++, ++it)
+        // itNAry.planes[i] (of type Mat) will be set to the current plane
+        // of the i-th n-dim matrix passed to the iterator constructor.
+        for(int p = 0; p < itNAry.nplanes; p++, ++itNAry)
         {
-            threshold(it.planes[0], it.planes[0], minProb, 0, THRESH_TOZERO);
-            s += sum(it.planes[0])[0];
+            threshold(itNAry.planes[0], itNAry.planes[0], minProb, 0, THRESH_TOZERO);
+            s += sum(itNAry.planes[0])[0];
         }
 
         s = 1./s;
-        it = NAryMatIterator(&hist, &plane, 1);
-        for(int p = 0; p < it.nplanes; p++, ++it)
-            it.planes[0] *= s;
+        itNAry = NAryMatIterator(arrays, planes, 1);
+        for(int p = 0; p < itNAry.nplanes; p++, ++itNAry)
+            itNAry.planes[0] *= s;
     }
 @endcode
  */
@@ -3428,4 +3517,4 @@ CV_EXPORTS MatExpr abs(const MatExpr& e);
 
 #include "opencv2/core/mat.inl.hpp"
 
-#endif // __OPENCV_CORE_MAT_HPP__
+#endif // OPENCV_CORE_MAT_HPP
diff --git a/modules/core/include/opencv2/core/mat.inl.hpp b/modules/core/include/opencv2/core/mat.inl.hpp
index 5410340..4a32de1 100644
--- a/modules/core/include/opencv2/core/mat.inl.hpp
+++ b/modules/core/include/opencv2/core/mat.inl.hpp
@@ -42,8 +42,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_CORE_MATRIX_OPERATIONS_HPP__
-#define __OPENCV_CORE_MATRIX_OPERATIONS_HPP__
+#ifndef OPENCV_CORE_MATRIX_OPERATIONS_HPP
+#define OPENCV_CORE_MATRIX_OPERATIONS_HPP
 
 #ifndef __cplusplus
 #  error mat.inl.hpp header must be compiled as C++
@@ -314,8 +314,12 @@ inline _InputOutputArray::_InputOutputArray(const std::vector<UMat>& vec)
 
 inline _InputOutputArray::_InputOutputArray(const cuda::GpuMat& d_mat)
 { init(FIXED_TYPE + FIXED_SIZE + CUDA_GPU_MAT + ACCESS_RW, &d_mat); }
+
 inline _InputOutputArray::_InputOutputArray(const std::vector<cuda::GpuMat>& d_mat)
-{	init(FIXED_TYPE + FIXED_SIZE + STD_VECTOR_CUDA_GPU_MAT + ACCESS_RW, &d_mat);}
+{ init(FIXED_TYPE + FIXED_SIZE + STD_VECTOR_CUDA_GPU_MAT + ACCESS_RW, &d_mat);}
+
+template<> inline _InputOutputArray::_InputOutputArray(std::vector<cuda::GpuMat>& d_mat)
+{ init(FIXED_TYPE + FIXED_SIZE + STD_VECTOR_CUDA_GPU_MAT + ACCESS_RW, &d_mat);}
 
 inline _InputOutputArray::_InputOutputArray(const ogl::Buffer& buf)
 { init(FIXED_TYPE + FIXED_SIZE + OPENGL_BUFFER + ACCESS_RW, &buf); }
@@ -383,6 +387,23 @@ Mat::Mat(int _dims, const int* _sz, int _type, const Scalar& _s)
 }
 
 inline
+Mat::Mat(const std::vector<int>& _sz, int _type)
+    : flags(MAGIC_VAL), dims(0), rows(0), cols(0), data(0), datastart(0), dataend(0),
+      datalimit(0), allocator(0), u(0), size(&rows)
+{
+    create(_sz, _type);
+}
+
+inline
+Mat::Mat(const std::vector<int>& _sz, int _type, const Scalar& _s)
+    : flags(MAGIC_VAL), dims(0), rows(0), cols(0), data(0), datastart(0), dataend(0),
+      datalimit(0), allocator(0), u(0), size(&rows)
+{
+    create(_sz, _type);
+    *this = _s;
+}
+
+inline
 Mat::Mat(const Mat& m)
     : flags(m.flags), dims(m.dims), rows(m.rows), cols(m.cols), data(m.data),
       datastart(m.datastart), dataend(m.dataend), datalimit(m.datalimit), allocator(m.allocator),
@@ -676,7 +697,8 @@ void Mat::addref()
         CV_XADD(&u->refcount, 1);
 }
 
-inline void Mat::release()
+inline
+void Mat::release()
 {
     if( u && CV_XADD(&u->refcount, -1) == 1 )
         deallocate();
@@ -684,6 +706,16 @@ inline void Mat::release()
     datastart = dataend = datalimit = data = 0;
     for(int i = 0; i < dims; i++)
         size.p[i] = 0;
+#ifdef _DEBUG
+    flags = MAGIC_VAL;
+    dims = rows = cols = 0;
+    if(step.p != step.buf)
+    {
+        fastFree(step.p);
+        step.p = step.buf;
+        size.p = &rows;
+    }
+#endif
 }
 
 inline
@@ -705,6 +737,12 @@ Mat Mat::operator()(const Range* ranges) const
 }
 
 inline
+Mat Mat::operator()(const std::vector<Range>& ranges) const
+{
+    return Mat(*this, ranges);
+}
+
+inline
 bool Mat::isContinuous() const
 {
     return (flags & CONTINUOUS_FLAG) != 0;
@@ -1165,6 +1203,9 @@ Mat::Mat(Mat&& m)
 inline
 Mat& Mat::operator = (Mat&& m)
 {
+    if (this == &m)
+      return *this;
+
     release();
     flags = m.flags; dims = m.dims; rows = m.rows; cols = m.cols; data = m.data;
     datastart = m.datastart; dataend = m.dataend; datalimit = m.datalimit; allocator = m.allocator;
@@ -1339,11 +1380,21 @@ Mat_<_Tp>::Mat_(int _dims, const int* _sz, const _Tp& _s)
 {}
 
 template<typename _Tp> inline
+Mat_<_Tp>::Mat_(int _dims, const int* _sz, _Tp* _data, const size_t* _steps)
+    : Mat(_dims, _sz, DataType<_Tp>::type, _data, _steps)
+{}
+
+template<typename _Tp> inline
 Mat_<_Tp>::Mat_(const Mat_<_Tp>& m, const Range* ranges)
     : Mat(m, ranges)
 {}
 
 template<typename _Tp> inline
+Mat_<_Tp>::Mat_(const Mat_<_Tp>& m, const std::vector<Range>& ranges)
+    : Mat(m, ranges)
+{}
+
+template<typename _Tp> inline
 Mat_<_Tp>::Mat_(const Mat& m)
     : Mat()
 {
@@ -1575,6 +1626,12 @@ Mat_<_Tp> Mat_<_Tp>::operator()( const Range* ranges ) const
 }
 
 template<typename _Tp> inline
+Mat_<_Tp> Mat_<_Tp>::operator()(const std::vector<Range>& ranges) const
+{
+    return Mat_<_Tp>(*this, ranges);
+}
+
+template<typename _Tp> inline
 _Tp* Mat_<_Tp>::operator [](int y)
 {
     CV_DbgAssert( 0 <= y && y < rows );
@@ -2469,7 +2526,7 @@ ptrdiff_t operator - (const MatConstIterator& b, const MatConstIterator& a)
     if( a.m != b.m )
         return ((size_t)(-1) >> 1);
     if( a.sliceEnd == b.sliceEnd )
-        return (b.ptr - a.ptr)/b.elemSize;
+        return (b.ptr - a.ptr)/static_cast<ptrdiff_t>(b.elemSize);
 
     return b.lpos() - a.lpos();
 }
@@ -2538,7 +2595,7 @@ MatConstIterator_<_Tp>& MatConstIterator_<_Tp>::operator = (const MatConstIterat
 }
 
 template<typename _Tp> inline
-_Tp MatConstIterator_<_Tp>::operator *() const
+const _Tp& MatConstIterator_<_Tp>::operator *() const
 {
     return *(_Tp*)(this->ptr);
 }
@@ -2644,7 +2701,7 @@ MatConstIterator_<_Tp> operator - (const MatConstIterator_<_Tp>& a, ptrdiff_t of
 }
 
 template<typename _Tp> inline
-_Tp MatConstIterator_<_Tp>::operator [](ptrdiff_t i) const
+const _Tp& MatConstIterator_<_Tp>::operator [](ptrdiff_t i) const
 {
     return *(_Tp*)MatConstIterator::operator [](i);
 }
@@ -3501,6 +3558,12 @@ UMat UMat::operator()(const Range* ranges) const
 }
 
 inline
+UMat UMat::operator()(const std::vector<Range>& ranges) const
+{
+    return UMat(*this, ranges);
+}
+
+inline
 bool UMat::isContinuous() const
 {
     return (flags & CONTINUOUS_FLAG) != 0;
@@ -3594,6 +3657,8 @@ UMat::UMat(UMat&& m)
 inline
 UMat& UMat::operator = (UMat&& m)
 {
+    if (this == &m)
+      return *this;
     release();
     flags = m.flags; dims = m.dims; rows = m.rows; cols = m.cols;
     allocator = m.allocator; usageFlags = m.usageFlags;
diff --git a/modules/core/include/opencv2/core/matx.hpp b/modules/core/include/opencv2/core/matx.hpp
index ca5f261..0d07c3f 100644
--- a/modules/core/include/opencv2/core/matx.hpp
+++ b/modules/core/include/opencv2/core/matx.hpp
@@ -41,8 +41,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_CORE_MATX_HPP__
-#define __OPENCV_CORE_MATX_HPP__
+#ifndef OPENCV_CORE_MATX_HPP
+#define OPENCV_CORE_MATX_HPP
 
 #ifndef __cplusplus
 #  error matx.hpp header must be compiled as C++
@@ -438,7 +438,7 @@ template<typename _Tp, int m> struct Matx_DetOp
             return p;
         for( int i = 0; i < m; i++ )
             p *= temp(i, i);
-        return 1./p;
+        return p;
     }
 };
 
@@ -1022,17 +1022,17 @@ Vec<_Tp, cn> Vec<_Tp, cn>::cross(const Vec<_Tp, cn>&) const
 template<> inline
 Vec<float, 3> Vec<float, 3>::cross(const Vec<float, 3>& v) const
 {
-    return Vec<float,3>(val[1]*v.val[2] - val[2]*v.val[1],
-                     val[2]*v.val[0] - val[0]*v.val[2],
-                     val[0]*v.val[1] - val[1]*v.val[0]);
+    return Vec<float,3>(this->val[1]*v.val[2] - this->val[2]*v.val[1],
+                     this->val[2]*v.val[0] - this->val[0]*v.val[2],
+                     this->val[0]*v.val[1] - this->val[1]*v.val[0]);
 }
 
 template<> inline
 Vec<double, 3> Vec<double, 3>::cross(const Vec<double, 3>& v) const
 {
-    return Vec<double,3>(val[1]*v.val[2] - val[2]*v.val[1],
-                     val[2]*v.val[0] - val[0]*v.val[2],
-                     val[0]*v.val[1] - val[1]*v.val[0]);
+    return Vec<double,3>(this->val[1]*v.val[2] - this->val[2]*v.val[1],
+                     this->val[2]*v.val[0] - this->val[0]*v.val[2],
+                     this->val[0]*v.val[1] - this->val[1]*v.val[0]);
 }
 
 template<typename _Tp, int cn> template<typename T2> inline
@@ -1404,4 +1404,4 @@ template<typename _Tp> inline Vec<_Tp, 4>& operator *= (Vec<_Tp, 4>& v1, const V
 
 } // cv
 
-#endif // __OPENCV_CORE_MATX_HPP__
+#endif // OPENCV_CORE_MATX_HPP
diff --git a/modules/core/include/opencv2/core/neon_utils.hpp b/modules/core/include/opencv2/core/neon_utils.hpp
index adb750f..573ba99 100644
--- a/modules/core/include/opencv2/core/neon_utils.hpp
+++ b/modules/core/include/opencv2/core/neon_utils.hpp
@@ -39,8 +39,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_HAL_NEON_UTILS_HPP__
-#define __OPENCV_HAL_NEON_UTILS_HPP__
+#ifndef OPENCV_HAL_NEON_UTILS_HPP
+#define OPENCV_HAL_NEON_UTILS_HPP
 
 #include "opencv2/core/cvdef.h"
 
@@ -125,4 +125,4 @@ inline float32x2_t cv_vsqrt_f32(float32x2_t val)
 
 //! @}
 
-#endif // __OPENCV_HAL_NEON_UTILS_HPP__
+#endif // OPENCV_HAL_NEON_UTILS_HPP
diff --git a/modules/core/include/opencv2/core/ocl.hpp b/modules/core/include/opencv2/core/ocl.hpp
index bc989a3..1a9549d 100644
--- a/modules/core/include/opencv2/core/ocl.hpp
+++ b/modules/core/include/opencv2/core/ocl.hpp
@@ -39,8 +39,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_OPENCL_HPP__
-#define __OPENCV_OPENCL_HPP__
+#ifndef OPENCV_OPENCL_HPP
+#define OPENCV_OPENCL_HPP
 
 #include "opencv2/core.hpp"
 
@@ -567,7 +567,18 @@ public:
         i = set(i, a6); i = set(i, a7); i = set(i, a8); i = set(i, a9); i = set(i, a10); i = set(i, a11);
         i = set(i, a12); i = set(i, a13); i = set(i, a14); set(i, a15); return *this;
     }
-
+    /*
+    Run the OpenCL kernel.
+    @param dims the work problem dimensions. It is the length of globalsize and localsize. It can be either 1, 2 or 3.
+    @param globalsize work items for each dimension.
+    It is not the final globalsize passed to OpenCL.
+    Each dimension will be adjusted to the nearest integer divisible by the corresponding value in localsize.
+    If localsize is NULL, it will still be adjusted depending on dims.
+    The adjusted values are greater than or equal to the original values.
+    @param localsize work-group size for each dimension.
+    @param sync specify whether to wait for OpenCL computation to finish before return.
+    @param q command queue
+    */
     bool run(int dims, size_t globalsize[],
              size_t localsize[], bool sync, const Queue& q=Queue());
     bool runTask(bool sync, const Queue& q=Queue());
@@ -728,6 +739,9 @@ CV_EXPORTS MatAllocator* getOpenCLAllocator();
 #ifdef __OPENCV_BUILD
 namespace internal {
 
+CV_EXPORTS bool isOpenCLForced();
+#define OCL_FORCE_CHECK(condition) (cv::ocl::internal::isOpenCLForced() || (condition))
+
 CV_EXPORTS bool isPerformanceCheckBypassed();
 #define OCL_PERFORMANCE_CHECK(condition) (cv::ocl::internal::isPerformanceCheckBypassed() || (condition))
 
diff --git a/modules/core/include/opencv2/core/ocl_genbase.hpp b/modules/core/include/opencv2/core/ocl_genbase.hpp
index d53bc1a..5408958 100644
--- a/modules/core/include/opencv2/core/ocl_genbase.hpp
+++ b/modules/core/include/opencv2/core/ocl_genbase.hpp
@@ -39,8 +39,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_OPENCL_GENBASE_HPP__
-#define __OPENCV_OPENCL_GENBASE_HPP__
+#ifndef OPENCV_OPENCL_GENBASE_HPP
+#define OPENCV_OPENCL_GENBASE_HPP
 
 namespace cv
 {
diff --git a/modules/core/include/opencv2/core/opencl/opencl_svm.hpp b/modules/core/include/opencv2/core/opencl/opencl_svm.hpp
index e9f7ba0..7453082 100644
--- a/modules/core/include/opencv2/core/opencl/opencl_svm.hpp
+++ b/modules/core/include/opencv2/core/opencl/opencl_svm.hpp
@@ -1,7 +1,7 @@
 /* See LICENSE file in the root OpenCV directory */
 
-#ifndef __OPENCV_CORE_OPENCL_SVM_HPP__
-#define __OPENCV_CORE_OPENCL_SVM_HPP__
+#ifndef OPENCV_CORE_OPENCL_SVM_HPP
+#define OPENCV_CORE_OPENCL_SVM_HPP
 
 //
 // Internal usage only (binary compatibility is not guaranteed)
@@ -77,5 +77,5 @@ CV_EXPORTS bool useSVM(UMatUsageFlags usageFlags);
 }}} //namespace cv::ocl::svm
 #endif
 
-#endif // __OPENCV_CORE_OPENCL_SVM_HPP__
+#endif // OPENCV_CORE_OPENCL_SVM_HPP
 /* End of file. */
diff --git a/modules/core/include/opencv2/core/opencl/runtime/autogenerated/opencl_clamdblas.hpp b/modules/core/include/opencv2/core/opencl/runtime/autogenerated/opencl_clamdblas.hpp
index bb1e2f7..65c8493 100644
--- a/modules/core/include/opencv2/core/opencl/runtime/autogenerated/opencl_clamdblas.hpp
+++ b/modules/core/include/opencv2/core/opencl/runtime/autogenerated/opencl_clamdblas.hpp
@@ -1,7 +1,7 @@
 //
 // AUTOGENERATED, DO NOT EDIT
 //
-#ifndef __OPENCV_CORE_OCL_RUNTIME_CLAMDBLAS_HPP__
+#ifndef OPENCV_CORE_OCL_RUNTIME_CLAMDBLAS_HPP
 #error "Invalid usage"
 #endif
 
diff --git a/modules/core/include/opencv2/core/opencl/runtime/autogenerated/opencl_clamdfft.hpp b/modules/core/include/opencv2/core/opencl/runtime/autogenerated/opencl_clamdfft.hpp
index 325145c..1457d7e 100644
--- a/modules/core/include/opencv2/core/opencl/runtime/autogenerated/opencl_clamdfft.hpp
+++ b/modules/core/include/opencv2/core/opencl/runtime/autogenerated/opencl_clamdfft.hpp
@@ -1,7 +1,7 @@
 //
 // AUTOGENERATED, DO NOT EDIT
 //
-#ifndef __OPENCV_CORE_OCL_RUNTIME_CLAMDFFT_HPP__
+#ifndef OPENCV_CORE_OCL_RUNTIME_CLAMDFFT_HPP
 #error "Invalid usage"
 #endif
 
diff --git a/modules/core/include/opencv2/core/opencl/runtime/autogenerated/opencl_core.hpp b/modules/core/include/opencv2/core/opencl/runtime/autogenerated/opencl_core.hpp
index f824ce9..eb9521f 100644
--- a/modules/core/include/opencv2/core/opencl/runtime/autogenerated/opencl_core.hpp
+++ b/modules/core/include/opencv2/core/opencl/runtime/autogenerated/opencl_core.hpp
@@ -1,7 +1,7 @@
 //
 // AUTOGENERATED, DO NOT EDIT
 //
-#ifndef __OPENCV_CORE_OCL_RUNTIME_OPENCL_CORE_HPP__
+#ifndef OPENCV_CORE_OCL_RUNTIME_OPENCL_CORE_HPP
 #error "Invalid usage"
 #endif
 
@@ -95,11 +95,7 @@
 #define clUnloadPlatformCompiler clUnloadPlatformCompiler_
 #define clWaitForEvents clWaitForEvents_
 
-#if defined __APPLE__
-#include <OpenCL/cl.h>
-#else
 #include <CL/cl.h>
-#endif
 
 // generated by parser_cl.py
 #undef clBuildProgram
diff --git a/modules/core/include/opencv2/core/opencl/runtime/autogenerated/opencl_core_wrappers.hpp b/modules/core/include/opencv2/core/opencl/runtime/autogenerated/opencl_core_wrappers.hpp
index cf64b08..216b22b 100644
--- a/modules/core/include/opencv2/core/opencl/runtime/autogenerated/opencl_core_wrappers.hpp
+++ b/modules/core/include/opencv2/core/opencl/runtime/autogenerated/opencl_core_wrappers.hpp
@@ -1,7 +1,7 @@
 //
 // AUTOGENERATED, DO NOT EDIT
 //
-#ifndef __OPENCV_CORE_OCL_RUNTIME_OPENCL_WRAPPERS_HPP__
+#ifndef OPENCV_CORE_OCL_RUNTIME_OPENCL_WRAPPERS_HPP
 #error "Invalid usage"
 #endif
 
diff --git a/modules/core/include/opencv2/core/opencl/runtime/autogenerated/opencl_gl.hpp b/modules/core/include/opencv2/core/opencl/runtime/autogenerated/opencl_gl.hpp
index f37ad15..468f969 100644
--- a/modules/core/include/opencv2/core/opencl/runtime/autogenerated/opencl_gl.hpp
+++ b/modules/core/include/opencv2/core/opencl/runtime/autogenerated/opencl_gl.hpp
@@ -1,7 +1,7 @@
 //
 // AUTOGENERATED, DO NOT EDIT
 //
-#ifndef __OPENCV_CORE_OCL_RUNTIME_OPENCL_GL_HPP__
+#ifndef OPENCV_CORE_OCL_RUNTIME_OPENCL_GL_HPP
 #error "Invalid usage"
 #endif
 
@@ -17,11 +17,7 @@
 #define clGetGLObjectInfo clGetGLObjectInfo_
 #define clGetGLTextureInfo clGetGLTextureInfo_
 
-#if defined __APPLE__
-#include <OpenCL/cl_gl.h>
-#else
 #include <CL/cl_gl.h>
-#endif
 
 // generated by parser_cl.py
 #undef clCreateFromGLBuffer
@@ -45,6 +41,8 @@
 #undef clGetGLTextureInfo
 #define clGetGLTextureInfo clGetGLTextureInfo_pfn
 
+#ifdef cl_khr_gl_sharing
+
 // generated by parser_cl.py
 extern CL_RUNTIME_EXPORT cl_mem (CL_API_CALL*clCreateFromGLBuffer)(cl_context, cl_mem_flags, cl_GLuint, int*);
 extern CL_RUNTIME_EXPORT cl_mem (CL_API_CALL*clCreateFromGLRenderbuffer)(cl_context, cl_mem_flags, cl_GLuint, cl_int*);
@@ -56,3 +54,5 @@ extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clEnqueueReleaseGLObjects)(cl_comma
 extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clGetGLContextInfoKHR)(const cl_context_properties*, cl_gl_context_info, size_t, void*, size_t*);
 extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clGetGLObjectInfo)(cl_mem, cl_gl_object_type*, cl_GLuint*);
 extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL*clGetGLTextureInfo)(cl_mem, cl_gl_texture_info, size_t, void*, size_t*);
+
+#endif // cl_khr_gl_sharing
diff --git a/modules/core/include/opencv2/core/opencl/runtime/autogenerated/opencl_gl_wrappers.hpp b/modules/core/include/opencv2/core/opencl/runtime/autogenerated/opencl_gl_wrappers.hpp
index 105867f..12f342b 100644
--- a/modules/core/include/opencv2/core/opencl/runtime/autogenerated/opencl_gl_wrappers.hpp
+++ b/modules/core/include/opencv2/core/opencl/runtime/autogenerated/opencl_gl_wrappers.hpp
@@ -1,10 +1,12 @@
 //
 // AUTOGENERATED, DO NOT EDIT
 //
-#ifndef __OPENCV_CORE_OCL_RUNTIME_OPENCL_GL_WRAPPERS_HPP__
+#ifndef OPENCV_CORE_OCL_RUNTIME_OPENCL_GL_WRAPPERS_HPP
 #error "Invalid usage"
 #endif
 
+#ifdef cl_khr_gl_sharing
+
 // generated by parser_cl.py
 #undef clCreateFromGLBuffer
 #define clCreateFromGLBuffer clCreateFromGLBuffer_fn
@@ -36,3 +38,5 @@ inline cl_int clGetGLObjectInfo(cl_mem p0, cl_gl_object_type* p1, cl_GLuint* p2)
 #undef clGetGLTextureInfo
 #define clGetGLTextureInfo clGetGLTextureInfo_fn
 inline cl_int clGetGLTextureInfo(cl_mem p0, cl_gl_texture_info p1, size_t p2, void* p3, size_t* p4) { return clGetGLTextureInfo_pfn(p0, p1, p2, p3, p4); }
+
+#endif // cl_khr_gl_sharing
diff --git a/modules/core/include/opencv2/core/opencl/runtime/opencl_clamdblas.hpp b/modules/core/include/opencv2/core/opencl/runtime/opencl_clamdblas.hpp
index b19f911..039ea97 100644
--- a/modules/core/include/opencv2/core/opencl/runtime/opencl_clamdblas.hpp
+++ b/modules/core/include/opencv2/core/opencl/runtime/opencl_clamdblas.hpp
@@ -39,8 +39,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_CORE_OCL_RUNTIME_CLAMDBLAS_HPP__
-#define __OPENCV_CORE_OCL_RUNTIME_CLAMDBLAS_HPP__
+#ifndef OPENCV_CORE_OCL_RUNTIME_CLAMDBLAS_HPP
+#define OPENCV_CORE_OCL_RUNTIME_CLAMDBLAS_HPP
 
 #ifdef HAVE_CLAMDBLAS
 
@@ -56,4 +56,4 @@
 
 #endif // HAVE_CLAMDBLAS
 
-#endif // __OPENCV_CORE_OCL_RUNTIME_CLAMDBLAS_HPP__
+#endif // OPENCV_CORE_OCL_RUNTIME_CLAMDBLAS_HPP
diff --git a/modules/core/include/opencv2/core/opencl/runtime/opencl_clamdfft.hpp b/modules/core/include/opencv2/core/opencl/runtime/opencl_clamdfft.hpp
index 0af9307..94037e9 100644
--- a/modules/core/include/opencv2/core/opencl/runtime/opencl_clamdfft.hpp
+++ b/modules/core/include/opencv2/core/opencl/runtime/opencl_clamdfft.hpp
@@ -39,8 +39,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_CORE_OCL_RUNTIME_CLAMDFFT_HPP__
-#define __OPENCV_CORE_OCL_RUNTIME_CLAMDFFT_HPP__
+#ifndef OPENCV_CORE_OCL_RUNTIME_CLAMDFFT_HPP
+#define OPENCV_CORE_OCL_RUNTIME_CLAMDFFT_HPP
 
 #ifdef HAVE_CLAMDFFT
 
@@ -56,4 +56,4 @@
 
 #endif // HAVE_CLAMDFFT
 
-#endif // __OPENCV_CORE_OCL_RUNTIME_CLAMDFFT_HPP__
+#endif // OPENCV_CORE_OCL_RUNTIME_CLAMDFFT_HPP
diff --git a/modules/core/include/opencv2/core/opencl/runtime/opencl_core.hpp b/modules/core/include/opencv2/core/opencl/runtime/opencl_core.hpp
index bd30f81..f86dfc0 100644
--- a/modules/core/include/opencv2/core/opencl/runtime/opencl_core.hpp
+++ b/modules/core/include/opencv2/core/opencl/runtime/opencl_core.hpp
@@ -39,8 +39,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_CORE_OCL_RUNTIME_OPENCL_CORE_HPP__
-#define __OPENCV_CORE_OCL_RUNTIME_OPENCL_CORE_HPP__
+#ifndef OPENCV_CORE_OCL_RUNTIME_OPENCL_CORE_HPP
+#define OPENCV_CORE_OCL_RUNTIME_OPENCL_CORE_HPP
 
 #ifdef HAVE_OPENCL
 
@@ -92,4 +92,4 @@
 
 #endif // HAVE_OPENCL
 
-#endif // __OPENCV_CORE_OCL_RUNTIME_OPENCL_CORE_HPP__
+#endif // OPENCV_CORE_OCL_RUNTIME_OPENCL_CORE_HPP
diff --git a/modules/core/include/opencv2/core/opencl/runtime/opencl_core_wrappers.hpp b/modules/core/include/opencv2/core/opencl/runtime/opencl_core_wrappers.hpp
index 912429f..38fcae9 100644
--- a/modules/core/include/opencv2/core/opencl/runtime/opencl_core_wrappers.hpp
+++ b/modules/core/include/opencv2/core/opencl/runtime/opencl_core_wrappers.hpp
@@ -39,9 +39,9 @@
 //
 //M*/
 
-#ifndef __OPENCV_CORE_OCL_RUNTIME_OPENCL_WRAPPERS_HPP__
-#define __OPENCV_CORE_OCL_RUNTIME_OPENCL_WRAPPERS_HPP__
+#ifndef OPENCV_CORE_OCL_RUNTIME_OPENCL_WRAPPERS_HPP
+#define OPENCV_CORE_OCL_RUNTIME_OPENCL_WRAPPERS_HPP
 
 #include "autogenerated/opencl_core_wrappers.hpp"
 
-#endif // __OPENCV_CORE_OCL_RUNTIME_OPENCL_WRAPPERS_HPP__
+#endif // OPENCV_CORE_OCL_RUNTIME_OPENCL_WRAPPERS_HPP
diff --git a/modules/core/include/opencv2/core/opencl/runtime/opencl_gl.hpp b/modules/core/include/opencv2/core/opencl/runtime/opencl_gl.hpp
index 7c7a82e..4753165 100644
--- a/modules/core/include/opencv2/core/opencl/runtime/opencl_gl.hpp
+++ b/modules/core/include/opencv2/core/opencl/runtime/opencl_gl.hpp
@@ -39,8 +39,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_CORE_OCL_RUNTIME_OPENCL_GL_HPP__
-#define __OPENCV_CORE_OCL_RUNTIME_OPENCL_GL_HPP__
+#ifndef OPENCV_CORE_OCL_RUNTIME_OPENCL_GL_HPP
+#define OPENCV_CORE_OCL_RUNTIME_OPENCL_GL_HPP
 
 #if defined HAVE_OPENCL && defined HAVE_OPENGL
 
@@ -62,4 +62,4 @@
 
 #endif // defined HAVE_OPENCL && defined HAVE_OPENGL
 
-#endif // __OPENCV_CORE_OCL_RUNTIME_OPENCL_GL_HPP__
+#endif // OPENCV_CORE_OCL_RUNTIME_OPENCL_GL_HPP
diff --git a/modules/core/include/opencv2/core/opencl/runtime/opencl_gl_wrappers.hpp b/modules/core/include/opencv2/core/opencl/runtime/opencl_gl_wrappers.hpp
index 9327d2e..9700004 100644
--- a/modules/core/include/opencv2/core/opencl/runtime/opencl_gl_wrappers.hpp
+++ b/modules/core/include/opencv2/core/opencl/runtime/opencl_gl_wrappers.hpp
@@ -39,9 +39,9 @@
 //
 //M*/
 
-#ifndef __OPENCV_CORE_OCL_RUNTIME_OPENCL_GL_WRAPPERS_HPP__
-#define __OPENCV_CORE_OCL_RUNTIME_OPENCL_GL_WRAPPERS_HPP__
+#ifndef OPENCV_CORE_OCL_RUNTIME_OPENCL_GL_WRAPPERS_HPP
+#define OPENCV_CORE_OCL_RUNTIME_OPENCL_GL_WRAPPERS_HPP
 
 #include "autogenerated/opencl_gl_wrappers.hpp"
 
-#endif // __OPENCV_CORE_OCL_RUNTIME_OPENCL_GL_WRAPPERS_HPP__
+#endif // OPENCV_CORE_OCL_RUNTIME_OPENCL_GL_WRAPPERS_HPP
diff --git a/modules/core/include/opencv2/core/opencl/runtime/opencl_svm_20.hpp b/modules/core/include/opencv2/core/opencl/runtime/opencl_svm_20.hpp
index 7f0ff91..29b78e0 100644
--- a/modules/core/include/opencv2/core/opencl/runtime/opencl_svm_20.hpp
+++ b/modules/core/include/opencv2/core/opencl/runtime/opencl_svm_20.hpp
@@ -1,7 +1,7 @@
 /* See LICENSE file in the root OpenCV directory */
 
-#ifndef __OPENCV_CORE_OCL_RUNTIME_OPENCL_SVM_2_0_HPP__
-#define __OPENCV_CORE_OCL_RUNTIME_OPENCL_SVM_2_0_HPP__
+#ifndef OPENCV_CORE_OCL_RUNTIME_OPENCL_SVM_2_0_HPP
+#define OPENCV_CORE_OCL_RUNTIME_OPENCL_SVM_2_0_HPP
 
 #if defined(HAVE_OPENCL_SVM)
 #include "opencl_core.hpp"
@@ -49,4 +49,4 @@ extern CL_RUNTIME_EXPORT cl_int (CL_API_CALL *clEnqueueSVMUnmap)(cl_command_queu
 
 #endif // HAVE_OPENCL_SVM
 
-#endif // __OPENCV_CORE_OCL_RUNTIME_OPENCL_SVM_2_0_HPP__
+#endif // OPENCV_CORE_OCL_RUNTIME_OPENCL_SVM_2_0_HPP
diff --git a/modules/core/include/opencv2/core/opencl/runtime/opencl_svm_definitions.hpp b/modules/core/include/opencv2/core/opencl/runtime/opencl_svm_definitions.hpp
index a4fd5fc..97c927b 100644
--- a/modules/core/include/opencv2/core/opencl/runtime/opencl_svm_definitions.hpp
+++ b/modules/core/include/opencv2/core/opencl/runtime/opencl_svm_definitions.hpp
@@ -1,7 +1,7 @@
 /* See LICENSE file in the root OpenCV directory */
 
-#ifndef __OPENCV_CORE_OCL_RUNTIME_OPENCL_SVM_DEFINITIONS_HPP__
-#define __OPENCV_CORE_OCL_RUNTIME_OPENCL_SVM_DEFINITIONS_HPP__
+#ifndef OPENCV_CORE_OCL_RUNTIME_OPENCL_SVM_DEFINITIONS_HPP
+#define OPENCV_CORE_OCL_RUNTIME_OPENCL_SVM_DEFINITIONS_HPP
 
 #if defined(HAVE_OPENCL_SVM)
 #if defined(CL_VERSION_2_0)
@@ -39,4 +39,4 @@ typedef cl_uint     cl_kernel_exec_info;
 #endif // CL_VERSION_2_0
 #endif // HAVE_OPENCL_SVM
 
-#endif // __OPENCV_CORE_OCL_RUNTIME_OPENCL_SVM_DEFINITIONS_HPP__
+#endif // OPENCV_CORE_OCL_RUNTIME_OPENCL_SVM_DEFINITIONS_HPP
diff --git a/modules/core/include/opencv2/core/opencl/runtime/opencl_svm_hsa_extension.hpp b/modules/core/include/opencv2/core/opencl/runtime/opencl_svm_hsa_extension.hpp
index 9e50408..497bc3d 100644
--- a/modules/core/include/opencv2/core/opencl/runtime/opencl_svm_hsa_extension.hpp
+++ b/modules/core/include/opencv2/core/opencl/runtime/opencl_svm_hsa_extension.hpp
@@ -1,7 +1,7 @@
 /* See LICENSE file in the root OpenCV directory */
 
-#ifndef __OPENCV_CORE_OCL_RUNTIME_OPENCL_SVM_HSA_EXTENSION_HPP__
-#define __OPENCV_CORE_OCL_RUNTIME_OPENCL_SVM_HSA_EXTENSION_HPP__
+#ifndef OPENCV_CORE_OCL_RUNTIME_OPENCL_SVM_HSA_EXTENSION_HPP
+#define OPENCV_CORE_OCL_RUNTIME_OPENCL_SVM_HSA_EXTENSION_HPP
 
 #if defined(HAVE_OPENCL_SVM)
 #include "opencl_core.hpp"
@@ -163,4 +163,4 @@ typedef CL_API_ENTRY cl_int
 
 #endif // HAVE_OPENCL_SVM
 
-#endif // __OPENCV_CORE_OCL_RUNTIME_OPENCL_SVM_HSA_EXTENSION_HPP__
+#endif // OPENCV_CORE_OCL_RUNTIME_OPENCL_SVM_HSA_EXTENSION_HPP
diff --git a/modules/core/include/opencv2/core/opengl.hpp b/modules/core/include/opencv2/core/opengl.hpp
index fd47c52..8b63d6c 100644
--- a/modules/core/include/opencv2/core/opengl.hpp
+++ b/modules/core/include/opencv2/core/opengl.hpp
@@ -40,8 +40,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_CORE_OPENGL_HPP__
-#define __OPENCV_CORE_OPENGL_HPP__
+#ifndef OPENCV_CORE_OPENGL_HPP
+#define OPENCV_CORE_OPENGL_HPP
 
 #ifndef __cplusplus
 #  error opengl.hpp header must be compiled as C++
@@ -726,4 +726,4 @@ bool cv::ogl::Arrays::empty() const
 
 //! @endcond
 
-#endif /* __OPENCV_CORE_OPENGL_HPP__ */
+#endif /* OPENCV_CORE_OPENGL_HPP */
diff --git a/modules/core/include/opencv2/core/openvx/ovx_defs.hpp b/modules/core/include/opencv2/core/openvx/ovx_defs.hpp
new file mode 100644
index 0000000..3f055dd
--- /dev/null
+++ b/modules/core/include/opencv2/core/openvx/ovx_defs.hpp
@@ -0,0 +1,40 @@
+// This file is part of OpenCV project.
+// It is subject to the license terms in the LICENSE file found in the top-level directory
+// of this distribution and at http://opencv.org/license.html.
+
+// Copyright (C) 2016, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+
+// OpenVX related definitions and declarations
+
+#pragma once
+#ifndef OPENCV_OVX_DEFS_HPP
+#define OPENCV_OVX_DEFS_HPP
+
+#include "cvconfig.h"
+
+// utility macro for running OpenVX-based implementations
+#ifdef HAVE_OPENVX
+
+#define IVX_HIDE_INFO_WARNINGS
+#define IVX_USE_OPENCV
+#include "ivx.hpp"
+
+#define CV_OVX_RUN(condition, func, ...)          \
+    if (cv::useOpenVX() && (condition) && func)   \
+    {                                             \
+        return __VA_ARGS__;                       \
+    }
+
+#else
+    #define CV_OVX_RUN(condition, func, ...)
+#endif // HAVE_OPENVX
+
+// Throw an error in debug mode or try another implementation in release
+#ifdef _DEBUG
+#define VX_DbgThrow(s) CV_Error(cv::Error::StsInternal, (s))
+#else
+#define VX_DbgThrow(s) return false
+#endif
+
+#endif // OPENCV_OVX_DEFS_HPP
diff --git a/modules/core/include/opencv2/core/operations.hpp b/modules/core/include/opencv2/core/operations.hpp
index bced1a7..4a4ad9e 100644
--- a/modules/core/include/opencv2/core/operations.hpp
+++ b/modules/core/include/opencv2/core/operations.hpp
@@ -42,8 +42,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_CORE_OPERATIONS_HPP__
-#define __OPENCV_CORE_OPERATIONS_HPP__
+#ifndef OPENCV_CORE_OPERATIONS_HPP
+#define OPENCV_CORE_OPERATIONS_HPP
 
 #ifndef __cplusplus
 #  error operations.hpp header must be compiled as C++
diff --git a/modules/core/include/opencv2/core/optim.hpp b/modules/core/include/opencv2/core/optim.hpp
index 23e2155..7249e0f 100644
--- a/modules/core/include/opencv2/core/optim.hpp
+++ b/modules/core/include/opencv2/core/optim.hpp
@@ -39,8 +39,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_OPTIM_HPP__
-#define __OPENCV_OPTIM_HPP__
+#ifndef OPENCV_OPTIM_HPP
+#define OPENCV_OPTIM_HPP
 
 #include "opencv2/core.hpp"
 
diff --git a/modules/core/include/opencv2/core/ovx.hpp b/modules/core/include/opencv2/core/ovx.hpp
new file mode 100644
index 0000000..8bb7d54
--- /dev/null
+++ b/modules/core/include/opencv2/core/ovx.hpp
@@ -0,0 +1,28 @@
+// This file is part of OpenCV project.
+// It is subject to the license terms in the LICENSE file found in the top-level directory
+// of this distribution and at http://opencv.org/license.html.
+
+// Copyright (C) 2016, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+
+// OpenVX related definitions and declarations
+
+#pragma once
+#ifndef OPENCV_OVX_HPP
+#define OPENCV_OVX_HPP
+
+#include "cvdef.h"
+
+namespace cv
+{
+/// Check if use of OpenVX is possible
+CV_EXPORTS_W bool haveOpenVX();
+
+/// Check if use of OpenVX is enabled
+CV_EXPORTS_W bool useOpenVX();
+
+/// Enable/disable use of OpenVX
+CV_EXPORTS_W void setUseOpenVX(bool flag);
+} // namespace cv
+
+#endif // OPENCV_OVX_HPP
diff --git a/modules/core/include/opencv2/core/persistence.hpp b/modules/core/include/opencv2/core/persistence.hpp
index 17686dd..3f18d54 100644
--- a/modules/core/include/opencv2/core/persistence.hpp
+++ b/modules/core/include/opencv2/core/persistence.hpp
@@ -41,8 +41,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_CORE_PERSISTENCE_HPP__
-#define __OPENCV_CORE_PERSISTENCE_HPP__
+#ifndef OPENCV_CORE_PERSISTENCE_HPP
+#define OPENCV_CORE_PERSISTENCE_HPP
 
 #ifndef __cplusplus
 #  error persistence.hpp header must be compiled as C++
@@ -57,8 +57,9 @@ Several functions that are described below take CvFileStorage\* as inputs and al
 save or to load hierarchical collections that consist of scalar values, standard CXCore objects
 (such as matrices, sequences, graphs), and user-defined objects.
 
-OpenCV can read and write data in XML (<http://www.w3c.org/XML>) or YAML (<http://www.yaml.org>)
-formats. Below is an example of 3x3 floating-point identity matrix A, stored in XML and YAML files
+OpenCV can read and write data in XML (<http://www.w3c.org/XML>), YAML (<http://www.yaml.org>) or
+JSON (<http://www.json.org/>) formats. Below is an example of 3x3 floating-point identity matrix A,
+stored in XML and YAML files
 using CXCore functions:
 XML:
 @code{.xml}
@@ -85,10 +86,13 @@ As it can be seen from the examples, XML uses nested tags to represent hierarchy
 indentation for that purpose (similar to the Python programming language).
 
 The same functions can read and write data in both formats; the particular format is determined by
-the extension of the opened file, ".xml" for XML files and ".yml" or ".yaml" for YAML.
+the extension of the opened file, ".xml" for XML files, ".yml" or ".yaml" for YAML and ".json" for
+JSON.
  */
 typedef struct CvFileStorage CvFileStorage;
 typedef struct CvFileNode CvFileNode;
+typedef struct CvMat CvMat;
+typedef struct CvMatND CvMatND;
 
 //! @} core_c
 
@@ -99,20 +103,20 @@ namespace cv {
 
 /** @addtogroup core_xml
 
-XML/YAML file storages.     {#xml_storage}
+XML/YAML/JSON file storages.     {#xml_storage}
 =======================
 Writing to a file storage.
 --------------------------
-You can store and then restore various OpenCV data structures to/from XML (<http://www.w3c.org/XML>)
-or YAML (<http://www.yaml.org>) formats. Also, it is possible store and load arbitrarily complex
-data structures, which include OpenCV data structures, as well as primitive data types (integer and
-floating-point numbers and text strings) as their elements.
+You can store and then restore various OpenCV data structures to/from XML (<http://www.w3c.org/XML>),
+YAML (<http://www.yaml.org>) or JSON (<http://www.json.org/>) formats. Also, it is possible store
+and load arbitrarily complex data structures, which include OpenCV data structures, as well as
+primitive data types (integer and floating-point numbers and text strings) as their elements.
 
-Use the following procedure to write something to XML or YAML:
+Use the following procedure to write something to XML, YAML or JSON:
 -# Create new FileStorage and open it for writing. It can be done with a single call to
 FileStorage::FileStorage constructor that takes a filename, or you can use the default constructor
-and then call FileStorage::open. Format of the file (XML or YAML) is determined from the filename
-extension (".xml" and ".yml"/".yaml", respectively)
+and then call FileStorage::open. Format of the file (XML, YAML or JSON) is determined from the filename
+extension (".xml", ".yml"/".yaml" and ".json", respectively)
 -# Write all the data you want using the streaming operator `<<`, just like in the case of STL
 streams.
 -# Close the file using FileStorage::release. FileStorage destructor also closes the file.
@@ -175,19 +179,19 @@ features:
    - { x:344, y:158, lbp:[ 1, 1, 0, 0, 0, 0, 1, 0 ] }
 @endcode
 
-As an exercise, you can replace ".yml" with ".xml" in the sample above and see, how the
+As an exercise, you can replace ".yml" with ".xml" or ".json" in the sample above and see, how the
 corresponding XML file will look like.
 
 Several things can be noted by looking at the sample code and the output:
 
--   The produced YAML (and XML) consists of heterogeneous collections that can be nested. There are 2
-    types of collections: named collections (mappings) and unnamed collections (sequences). In mappings
+-   The produced YAML (and XML/JSON) consists of heterogeneous collections that can be nested. There are
+    2 types of collections: named collections (mappings) and unnamed collections (sequences). In mappings
     each element has a name and is accessed by name. This is similar to structures and std::map in
     C/C++ and dictionaries in Python. In sequences elements do not have names, they are accessed by
     indices. This is similar to arrays and std::vector in C/C++ and lists, tuples in Python.
     "Heterogeneous" means that elements of each single collection can have different types.
 
-    Top-level collection in YAML/XML is a mapping. Each matrix is stored as a mapping, and the matrix
+    Top-level collection in YAML/XML/JSON is a mapping. Each matrix is stored as a mapping, and the matrix
     elements are stored as a sequence. Then, there is a sequence of features, where each feature is
     represented a mapping, and lbp value in a nested sequence.
 
@@ -203,7 +207,7 @@ Several things can be noted by looking at the sample code and the output:
 -   To write a sequence, you first write the special string `[`, then write the elements, then
     write the closing `]`.
 
--   In YAML (but not XML), mappings and sequences can be written in a compact Python-like inline
+-   In YAML/JSON (but not XML), mappings and sequences can be written in a compact Python-like inline
     form. In the sample above matrix elements, as well as each feature, including its lbp value, is
     stored in such inline form. To store a mapping/sequence in a compact form, put `:` after the
     opening character, e.g. use `{:` instead of `{` and `[:` instead of `[`. When the
@@ -211,7 +215,7 @@ Several things can be noted by looking at the sample code and the output:
 
 Reading data from a file storage.
 ---------------------------------
-To read the previously written XML or YAML file, do the following:
+To read the previously written XML, YAML or JSON file, do the following:
 -#  Open the file storage using FileStorage::FileStorage constructor or FileStorage::open method.
     In the current implementation the whole file is parsed and the whole representation of file
     storage is built in memory as a hierarchy of file nodes (see FileNode)
@@ -292,8 +296,8 @@ A complete example using the FileStorage interface
 class CV_EXPORTS FileNode;
 class CV_EXPORTS FileNodeIterator;
 
-/** @brief XML/YAML file storage class that encapsulates all the information necessary for writing or reading
-data to/from a file.
+/** @brief XML/YAML/JSON file storage class that encapsulates all the information necessary for writing or
+reading data to/from a file.
  */
 class CV_EXPORTS_W FileStorage
 {
@@ -309,7 +313,11 @@ public:
         FORMAT_MASK = (7<<3), //!< mask for format flags
         FORMAT_AUTO = 0,      //!< flag, auto format
         FORMAT_XML  = (1<<3), //!< flag, XML format
-        FORMAT_YAML = (2<<3)  //!< flag, YAML format
+        FORMAT_YAML = (2<<3), //!< flag, YAML format
+        FORMAT_JSON = (3<<3), //!< flag, JSON format
+
+        BASE64      = 64,     //!< flag, write rawdata in Base64 by default. (consider using WRITE_BASE64)
+        WRITE_BASE64 = BASE64 | WRITE, //!< flag, enable both WRITE and BASE64
     };
     enum
     {
@@ -328,9 +336,9 @@ public:
 
     /** @overload
     @param source Name of the file to open or the text string to read the data from. Extension of the
-    file (.xml or .yml/.yaml) determines its format (XML or YAML respectively). Also you can append .gz
-    to work with compressed files, for example myHugeMatrix.xml.gz. If both FileStorage::WRITE and
-    FileStorage::MEMORY flags are specified, source is used just to specify the output file format (e.g.
+    file (.xml, .yml/.yaml, or .json) determines its format (XML, YAML or JSON respectively). Also you can
+    append .gz to work with compressed files, for example myHugeMatrix.xml.gz. If both FileStorage::WRITE
+    and FileStorage::MEMORY flags are specified, source is used just to specify the output file format (e.g.
     mydata.xml, .yml etc.).
     @param flags Mode of operation. See  FileStorage::Mode
     @param encoding Encoding of the file. Note that UTF-16 XML encoding is not supported currently and
@@ -349,10 +357,12 @@ public:
     See description of parameters in FileStorage::FileStorage. The method calls FileStorage::release
     before opening the file.
     @param filename Name of the file to open or the text string to read the data from.
-       Extension of the file (.xml or .yml/.yaml) determines its format (XML or YAML respectively).
-        Also you can append .gz to work with compressed files, for example myHugeMatrix.xml.gz. If both
+       Extension of the file (.xml, .yml/.yaml or .json) determines its format (XML, YAML or JSON
+        respectively). Also you can append .gz to work with compressed files, for example myHugeMatrix.xml.gz. If both
         FileStorage::WRITE and FileStorage::MEMORY flags are specified, source is used just to specify
-        the output file format (e.g. mydata.xml, .yml etc.).
+        the output file format (e.g. mydata.xml, .yml etc.). A file name can also contain parameters.
+        You can use this format, "*?base64" (e.g. "file.json?base64" (case sensitive)), as an alternative to
+        FileStorage::BASE64 flag.
     @param flags Mode of operation. One of FileStorage::Mode
     @param encoding Encoding of the file. Note that UTF-16 XML encoding is not supported currently and
     you should use 8-bit encoding instead of it.
@@ -398,7 +408,7 @@ public:
     FileNode operator[](const String& nodename) const;
 
     /** @overload */
-    CV_WRAP FileNode operator[](const char* nodename) const;
+    CV_WRAP_AS(getNode) FileNode operator[](const char* nodename) const;
 
     /** @brief Returns the obsolete C FileStorage structure.
     @returns Pointer to the underlying C FileStorage structure
@@ -425,6 +435,27 @@ public:
      */
     void writeObj( const String& name, const void* obj );
 
+    /**
+     * @brief Simplified writing API to use with bindings.
+     * @param name Name of the written object
+     * @param val Value of the written object
+     */
+    CV_WRAP void write(const String& name, double val);
+    /// @overload
+    CV_WRAP void write(const String& name, const String& val);
+    /// @overload
+    CV_WRAP void write(const String& name, InputArray val);
+
+    /** @brief Writes a comment.
+
+    The function writes a comment into file storage. The comments are skipped when the storage is read.
+    @param comment The written comment, single-line or multi-line
+    @param append If true, the function tries to put the comment at the end of current line.
+    Else if the comment is multi-line, or if it does not fit at the end of the current
+    line, the comment starts a new line.
+     */
+    CV_WRAP void writeComment(const String& comment, bool append = false);
+
     /** @brief Returns the normalized object name for the specified name of a file.
     @param filename Name of a file
     @returns The normalized object name.
@@ -499,12 +530,12 @@ public:
     /** @overload
     @param nodename Name of an element in the mapping node.
     */
-    CV_WRAP FileNode operator[](const char* nodename) const;
+    CV_WRAP_AS(getNode) FileNode operator[](const char* nodename) const;
 
     /** @overload
     @param i Index of an element in the sequence node.
     */
-    CV_WRAP FileNode operator[](int i) const;
+    CV_WRAP_AS(at) FileNode operator[](int i) const;
 
     /** @brief Returns type of the node.
     @returns Type of the node. See FileNode::Type
@@ -566,6 +597,13 @@ public:
     //! reads the registered object and returns pointer to it
     void* readObj() const;
 
+    //! Simplified reading API to use with bindings.
+    CV_WRAP double real() const;
+    //! Simplified reading API to use with bindings.
+    CV_WRAP String string() const;
+    //! Simplified reading API to use with bindings.
+    CV_WRAP Mat mat() const;
+
     // do not use wrapper pointer classes for better efficiency
     const CvFileStorage* fs;
     const CvFileNode* node;
@@ -920,7 +958,6 @@ void write( FileStorage& fs, const std::vector<_Tp>& vec )
     w(vec);
 }
 
-
 template<typename _Tp> static inline
 void write(FileStorage& fs, const String& name, const Point_<_Tp>& pt )
 {
@@ -984,6 +1021,17 @@ void write( FileStorage& fs, const String& name, const std::vector<_Tp>& vec )
     write(fs, vec);
 }
 
+template<typename _Tp> static inline
+void write( FileStorage& fs, const String& name, const std::vector< std::vector<_Tp> >& vec )
+{
+    cv::internal::WriteStructContext ws(fs, name, FileNode::SEQ);
+    for(size_t i = 0; i < vec.size(); i++)
+    {
+        cv::internal::WriteStructContext ws_(fs, name, FileNode::SEQ+(DataType<_Tp>::fmt != 0 ? FileNode::FLOW : 0));
+        write(fs, vec[i]);
+    }
+}
+
 //! @} FileStorage
 
 //! @relates cv::FileNode
@@ -1130,6 +1178,23 @@ void operator >> (const FileNode& n, std::vector<_Tp>& vec)
     it >> vec;
 }
 
+/** @brief Reads KeyPoint from a file storage.
+*/
+//It needs special handling because it contains two types of fields, int & float.
+static inline
+void operator >> (const FileNode& n, std::vector<KeyPoint>& vec)
+{
+    read(n, vec);
+}
+/** @brief Reads DMatch from a file storage.
+*/
+//It needs special handling because it contains two types of fields, int & float.
+static inline
+void operator >> (const FileNode& n, std::vector<DMatch>& vec)
+{
+    read(n, vec);
+}
+
 //! @} FileNode
 
 //! @relates cv::FileNodeIterator
@@ -1181,6 +1246,9 @@ inline FileNode::operator int() const    { int value;    read(*this, value, 0);
 inline FileNode::operator float() const  { float value;  read(*this, value, 0.f);   return value; }
 inline FileNode::operator double() const { double value; read(*this, value, 0.);    return value; }
 inline FileNode::operator String() const { String value; read(*this, value, value); return value; }
+inline double FileNode::real() const  { return double(*this); }
+inline String FileNode::string() const { return String(*this); }
+inline Mat FileNode::mat() const { Mat value; read(*this, value, value);    return value; }
 inline FileNodeIterator FileNode::begin() const { return FileNodeIterator(fs, node); }
 inline FileNodeIterator FileNode::end() const   { return FileNodeIterator(fs, node, size()); }
 inline void FileNode::readRaw( const String& fmt, uchar* vec, size_t len ) const { begin().readRaw( fmt, vec, len ); }
@@ -1190,6 +1258,17 @@ inline String::String(const FileNode& fn): cstr_(0), len_(0) { read(fn, *this, *
 
 //! @endcond
 
+
+CV_EXPORTS void cvStartWriteRawData_Base64(::CvFileStorage * fs, const char* name, int len, const char* dt);
+
+CV_EXPORTS void cvWriteRawData_Base64(::CvFileStorage * fs, const void* _data, int len);
+
+CV_EXPORTS void cvEndWriteRawData_Base64(::CvFileStorage * fs);
+
+CV_EXPORTS void cvWriteMat_Base64(::CvFileStorage* fs, const char* name, const ::CvMat* mat);
+
+CV_EXPORTS void cvWriteMatND_Base64(::CvFileStorage* fs, const char* name, const ::CvMatND* mat);
+
 } // cv
 
-#endif // __OPENCV_CORE_PERSISTENCE_HPP__
+#endif // OPENCV_CORE_PERSISTENCE_HPP
diff --git a/modules/core/include/opencv2/core/private.cuda.hpp b/modules/core/include/opencv2/core/private.cuda.hpp
index d676ce8..01a4ab3 100644
--- a/modules/core/include/opencv2/core/private.cuda.hpp
+++ b/modules/core/include/opencv2/core/private.cuda.hpp
@@ -41,8 +41,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_CORE_PRIVATE_CUDA_HPP__
-#define __OPENCV_CORE_PRIVATE_CUDA_HPP__
+#ifndef OPENCV_CORE_PRIVATE_CUDA_HPP
+#define OPENCV_CORE_PRIVATE_CUDA_HPP
 
 #ifndef __OPENCV_BUILD
 #  error this is a private header which should not be used from outside of the OpenCV library
@@ -64,7 +64,7 @@
 
 #  define NPP_VERSION (NPP_VERSION_MAJOR * 1000 + NPP_VERSION_MINOR * 100 + NPP_VERSION_BUILD)
 
-#  define CUDART_MINIMUM_REQUIRED_VERSION 4020
+#  define CUDART_MINIMUM_REQUIRED_VERSION 6050
 
 #  if (CUDART_VERSION < CUDART_MINIMUM_REQUIRED_VERSION)
 #    error "Insufficient Cuda Runtime library version, please update it."
@@ -169,4 +169,4 @@ namespace cv { namespace cuda
 
 //! @endcond
 
-#endif // __OPENCV_CORE_CUDA_PRIVATE_HPP__
+#endif // OPENCV_CORE_PRIVATE_CUDA_HPP
diff --git a/modules/core/include/opencv2/core/private.hpp b/modules/core/include/opencv2/core/private.hpp
index c71ec62..e428ecf 100644
--- a/modules/core/include/opencv2/core/private.hpp
+++ b/modules/core/include/opencv2/core/private.hpp
@@ -41,8 +41,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_CORE_PRIVATE_HPP__
-#define __OPENCV_CORE_PRIVATE_HPP__
+#ifndef OPENCV_CORE_PRIVATE_HPP
+#define OPENCV_CORE_PRIVATE_HPP
 
 #ifndef __OPENCV_BUILD
 #  error this is a private header which should not be used from outside of the OpenCV library
@@ -60,15 +60,21 @@
 #endif
 
 #ifdef HAVE_TBB
-#  include "tbb/tbb_stddef.h"
-#  if TBB_VERSION_MAJOR*100 + TBB_VERSION_MINOR >= 202
-#    include "tbb/tbb.h"
-#    include "tbb/task.h"
-#    undef min
-#    undef max
-#  else
-#    undef HAVE_TBB
-#  endif
+#  include "tbb/tbb.h"
+#  include "tbb/task.h"
+#  undef min
+#  undef max
+#endif
+
+#if defined HAVE_FP16 && (defined __F16C__ || (defined _MSC_VER && _MSC_VER >= 1700))
+#  include <immintrin.h>
+#  define CV_FP16 1
+#elif defined HAVE_FP16 && defined __GNUC__
+#  define CV_FP16 1
+#endif
+
+#ifndef CV_FP16
+#  define CV_FP16 0
 #endif
 
 //! @cond IGNORED
@@ -221,6 +227,18 @@ static inline IppiSize ippiSize(const cv::Size & _size)
     return size;
 }
 
+static inline IppiPoint ippiPoint(const cv::Point & _point)
+{
+    IppiPoint point = { _point.x, _point.y };
+    return point;
+}
+
+static inline IppiPoint ippiPoint(int x, int y)
+{
+    IppiPoint point = { x, y };
+    return point;
+}
+
 static inline IppiBorderType ippiGetBorderType(int borderTypeNI)
 {
     return borderTypeNI == cv::BORDER_CONSTANT ? ippBorderConst :
@@ -255,8 +273,8 @@ public:
     inline operator const T* () const { return (const T*)m_pBuffer;}
 private:
     // Disable copy operations
-    IppAutoBuffer(IppAutoBuffer &) {};
-    IppAutoBuffer& operator =(const IppAutoBuffer &) {return *this;};
+    IppAutoBuffer(IppAutoBuffer &) {}
+    IppAutoBuffer& operator =(const IppAutoBuffer &) {return *this;}
 
     T* m_pBuffer;
 };
@@ -265,17 +283,6 @@ private:
 #define IPP_VERSION_X100 0
 #endif
 
-// There shoud be no API difference in OpenCV between ICV and IPP since 9.0
-#if (defined HAVE_IPP_ICV_ONLY) && IPP_VERSION_X100 >= 900
-#undef HAVE_IPP_ICV_ONLY
-#endif
-
-#ifdef HAVE_IPP_ICV_ONLY
-#define HAVE_ICV 1
-#else
-#define HAVE_ICV 0
-#endif
-
 #if defined HAVE_IPP
 #if IPP_VERSION_X100 >= 900
 #define IPP_INITIALIZER(FEAT)                           \
@@ -321,7 +328,7 @@ static struct __IppInitializer__ __ipp_initializer__;
 #ifdef CV_IPP_RUN_VERBOSE
 #define CV_IPP_RUN_(condition, func, ...)                                   \
     {                                                                       \
-        if (cv::ipp::useIPP() && (condition) && func)                       \
+        if (cv::ipp::useIPP() && (condition) && (func))                     \
         {                                                                   \
             printf("%s: IPP implementation is running\n", CV_Func);         \
             fflush(stdout);                                                 \
@@ -353,18 +360,24 @@ static struct __IppInitializer__ __ipp_initializer__;
     }
 #else
 #define CV_IPP_RUN_(condition, func, ...)                                   \
-    if (cv::ipp::useIPP() && (condition) && func)                           \
+    if (cv::ipp::useIPP() && (condition) && (func))                         \
     {                                                                       \
         CV_IMPL_ADD(CV_IMPL_IPP);                                           \
         return __VA_ARGS__;                                                 \
     }
 #endif
-
+#define CV_IPP_RUN_FAST(func, ...)                                          \
+    if (cv::ipp::useIPP() && (func))                                        \
+    {                                                                       \
+        CV_IMPL_ADD(CV_IMPL_IPP);                                           \
+        return __VA_ARGS__;                                                 \
+    }
 #else
 #define CV_IPP_RUN_(condition, func, ...)
+#define CV_IPP_RUN_FAST(func, ...)
 #endif
 
-#define CV_IPP_RUN(condition, func, ...) CV_IPP_RUN_(condition, func, __VA_ARGS__)
+#define CV_IPP_RUN(condition, func, ...) CV_IPP_RUN_((condition), (func), __VA_ARGS__)
 
 
 #ifndef IPPI_CALL
@@ -420,6 +433,153 @@ CV_EXPORTS void setUseTegra(bool flag);
 }
 #endif
 
+#ifdef ENABLE_INSTRUMENTATION
+namespace cv
+{
+namespace instr
+{
+struct InstrTLSStruct
+{
+    InstrTLSStruct()
+    {
+        pCurrentNode = NULL;
+    }
+    InstrNode* pCurrentNode;
+};
+
+class InstrStruct
+{
+public:
+    InstrStruct()
+    {
+        useInstr    = false;
+        flags       = FLAGS_MAPPING;
+        maxDepth    = 0;
+
+        rootNode.m_payload = NodeData("ROOT", NULL, 0, NULL, false, TYPE_GENERAL, IMPL_PLAIN);
+        tlsStruct.get()->pCurrentNode = &rootNode;
+    }
+
+    Mutex mutexCreate;
+    Mutex mutexCount;
+
+    bool       useInstr;
+    int        flags;
+    int        maxDepth;
+    InstrNode  rootNode;
+    TLSData<InstrTLSStruct> tlsStruct;
+};
+
+class CV_EXPORTS IntrumentationRegion
+{
+public:
+    IntrumentationRegion(const char* funName, const char* fileName, int lineNum, void *retAddress, bool alwaysExpand, TYPE instrType = TYPE_GENERAL, IMPL implType = IMPL_PLAIN);
+    ~IntrumentationRegion();
+
+private:
+    bool    m_disabled; // region status
+    uint64  m_regionTicks;
+};
+
+CV_EXPORTS InstrStruct& getInstrumentStruct();
+InstrTLSStruct&         getInstrumentTLSStruct();
+CV_EXPORTS InstrNode*   getCurrentNode();
+}
+}
+
+#ifdef _WIN32
+#define CV_INSTRUMENT_GET_RETURN_ADDRESS _ReturnAddress()
+#else
+#define CV_INSTRUMENT_GET_RETURN_ADDRESS __builtin_extract_return_addr(__builtin_return_address(0))
+#endif
+
+// Instrument region
+#define CV_INSTRUMENT_REGION_META(NAME, ALWAYS_EXPAND, TYPE, IMPL)        ::cv::instr::IntrumentationRegion __instr_region__(NAME, __FILE__, __LINE__, CV_INSTRUMENT_GET_RETURN_ADDRESS, ALWAYS_EXPAND, TYPE, IMPL);
+#define CV_INSTRUMENT_REGION_CUSTOM_META(NAME, ALWAYS_EXPAND, TYPE, IMPL)\
+    void *__curr_address__ = [&]() {return CV_INSTRUMENT_GET_RETURN_ADDRESS;}();\
+    ::cv::instr::IntrumentationRegion __instr_region__(NAME, __FILE__, __LINE__, __curr_address__, false, ::cv::instr::TYPE_GENERAL, ::cv::instr::IMPL_PLAIN);
+// Instrument functions with non-void return type
+#define CV_INSTRUMENT_FUN_RT_META(TYPE, IMPL, ERROR_COND, FUN, ...) ([&]()\
+{\
+    if(::cv::instr::useInstrumentation()){\
+        ::cv::instr::IntrumentationRegion __instr__(#FUN, __FILE__, __LINE__, NULL, false, TYPE, IMPL);\
+        try{\
+            auto status = ((FUN)(__VA_ARGS__));\
+            if(ERROR_COND){\
+                ::cv::instr::getCurrentNode()->m_payload.m_funError = true;\
+                CV_INSTRUMENT_MARK_META(IMPL, #FUN " - BadExit");\
+            }\
+            return status;\
+        }catch(...){\
+            ::cv::instr::getCurrentNode()->m_payload.m_funError = true;\
+            CV_INSTRUMENT_MARK_META(IMPL, #FUN " - BadExit");\
+            throw;\
+        }\
+    }else{\
+        return ((FUN)(__VA_ARGS__));\
+    }\
+}())
+// Instrument functions with void return type
+#define CV_INSTRUMENT_FUN_RV_META(TYPE, IMPL, FUN, ...) ([&]()\
+{\
+    if(::cv::instr::useInstrumentation()){\
+        ::cv::instr::IntrumentationRegion __instr__(#FUN, __FILE__, __LINE__, NULL, false, TYPE, IMPL);\
+        try{\
+            (FUN)(__VA_ARGS__);\
+        }catch(...){\
+            ::cv::instr::getCurrentNode()->m_payload.m_funError = true;\
+            CV_INSTRUMENT_MARK_META(IMPL, #FUN "- BadExit");\
+            throw;\
+        }\
+    }else{\
+        (FUN)(__VA_ARGS__);\
+    }\
+}())
+// Instrumentation information marker
+#define CV_INSTRUMENT_MARK_META(IMPL, NAME, ...) {::cv::instr::IntrumentationRegion __instr_mark__(NAME, __FILE__, __LINE__, NULL, false, ::cv::instr::TYPE_MARKER, IMPL);}
+
+///// General instrumentation
+// General OpenCV region instrumentation macro
+#define CV_INSTRUMENT_REGION()              CV_INSTRUMENT_REGION_META(__FUNCTION__, false, ::cv::instr::TYPE_GENERAL, ::cv::instr::IMPL_PLAIN)
+// Custom OpenCV region instrumentation macro
+#define CV_INSTRUMENT_REGION_NAME(NAME)     CV_INSTRUMENT_REGION_CUSTOM_META(NAME,  false, ::cv::instr::TYPE_GENERAL, ::cv::instr::IMPL_PLAIN)
+// Instrumentation for parallel_for_ or other regions which forks and gathers threads
+#define CV_INSTRUMENT_REGION_MT_FORK()      CV_INSTRUMENT_REGION_META(__FUNCTION__, true,  ::cv::instr::TYPE_GENERAL, ::cv::instr::IMPL_PLAIN);
+
+///// IPP instrumentation
+// Wrapper region instrumentation macro
+#define CV_INSTRUMENT_REGION_IPP()          CV_INSTRUMENT_REGION_META(__FUNCTION__, false, ::cv::instr::TYPE_WRAPPER, ::cv::instr::IMPL_IPP)
+// Function instrumentation macro
+#define CV_INSTRUMENT_FUN_IPP(FUN, ...)     CV_INSTRUMENT_FUN_RT_META(::cv::instr::TYPE_FUN, ::cv::instr::IMPL_IPP, status < 0, FUN, __VA_ARGS__)
+// Diagnostic markers
+#define CV_INSTRUMENT_MARK_IPP(NAME)        CV_INSTRUMENT_MARK_META(::cv::instr::IMPL_IPP, NAME)
+
+///// OpenCL instrumentation
+// Wrapper region instrumentation macro
+#define CV_INSTRUMENT_REGION_OPENCL()              CV_INSTRUMENT_REGION_META(__FUNCTION__, false, ::cv::instr::TYPE_WRAPPER, ::cv::instr::IMPL_OPENCL)
+// OpenCL kernel compilation wrapper
+#define CV_INSTRUMENT_REGION_OPENCL_COMPILE(NAME)  CV_INSTRUMENT_REGION_META(NAME, false, ::cv::instr::TYPE_WRAPPER, ::cv::instr::IMPL_OPENCL)
+// OpenCL kernel run wrapper
+#define CV_INSTRUMENT_REGION_OPENCL_RUN(NAME)      CV_INSTRUMENT_REGION_META(NAME, false, ::cv::instr::TYPE_FUN, ::cv::instr::IMPL_OPENCL)
+// Diagnostic markers
+#define CV_INSTRUMENT_MARK_OPENCL(NAME)            CV_INSTRUMENT_MARK_META(::cv::instr::IMPL_OPENCL, NAME)
+#else
+#define CV_INSTRUMENT_REGION_META(...)
+
+#define CV_INSTRUMENT_REGION()
+#define CV_INSTRUMENT_REGION_NAME(...)
+#define CV_INSTRUMENT_REGION_MT_FORK()
+
+#define CV_INSTRUMENT_REGION_IPP()
+#define CV_INSTRUMENT_FUN_IPP(FUN, ...) ((FUN)(__VA_ARGS__))
+#define CV_INSTRUMENT_MARK_IPP(...)
+
+#define CV_INSTRUMENT_REGION_OPENCL()
+#define CV_INSTRUMENT_REGION_OPENCL_COMPILE(...)
+#define CV_INSTRUMENT_REGION_OPENCL_RUN(...)
+#define CV_INSTRUMENT_MARK_OPENCL(...)
+#endif
+
 //! @endcond
 
-#endif // __OPENCV_CORE_PRIVATE_HPP__
+#endif // OPENCV_CORE_PRIVATE_HPP
diff --git a/modules/core/include/opencv2/core/ptr.inl.hpp b/modules/core/include/opencv2/core/ptr.inl.hpp
index 3f6f214..3c095a1 100644
--- a/modules/core/include/opencv2/core/ptr.inl.hpp
+++ b/modules/core/include/opencv2/core/ptr.inl.hpp
@@ -39,8 +39,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_CORE_PTR_INL_HPP__
-#define __OPENCV_CORE_PTR_INL_HPP__
+#ifndef OPENCV_CORE_PTR_INL_HPP
+#define OPENCV_CORE_PTR_INL_HPP
 
 #include <algorithm>
 
@@ -264,6 +264,9 @@ Ptr<T>::Ptr(Ptr&& o) : owner(o.owner), stored(o.stored)
 template<typename T>
 Ptr<T>& Ptr<T>::operator = (Ptr<T>&& o)
 {
+    if (this == &o)
+        return *this;
+
     release();
     owner = o.owner;
     stored = o.stored;
@@ -358,8 +361,19 @@ Ptr<T> makePtr(const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5&
     return Ptr<T>(new T(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10));
 }
 
+template<typename T, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10, typename A11>
+Ptr<T> makePtr(const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6, const A7& a7, const A8& a8, const A9& a9, const A10& a10, const A11& a11)
+{
+    return Ptr<T>(new T(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11));
+}
+
+template<typename T, typename A1, typename A2, typename A3, typename A4, typename A5, typename A6, typename A7, typename A8, typename A9, typename A10, typename A11, typename A12>
+Ptr<T> makePtr(const A1& a1, const A2& a2, const A3& a3, const A4& a4, const A5& a5, const A6& a6, const A7& a7, const A8& a8, const A9& a9, const A10& a10, const A11& a11, const A12& a12)
+{
+    return Ptr<T>(new T(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12));
+}
 } // namespace cv
 
 //! @endcond
 
-#endif // __OPENCV_CORE_PTR_INL_HPP__
+#endif // OPENCV_CORE_PTR_INL_HPP
diff --git a/modules/core/include/opencv2/core/saturate.hpp b/modules/core/include/opencv2/core/saturate.hpp
index 1442eab..79a9a66 100644
--- a/modules/core/include/opencv2/core/saturate.hpp
+++ b/modules/core/include/opencv2/core/saturate.hpp
@@ -42,8 +42,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_CORE_SATURATE_HPP__
-#define __OPENCV_CORE_SATURATE_HPP__
+#ifndef OPENCV_CORE_SATURATE_HPP
+#define OPENCV_CORE_SATURATE_HPP
 
 #include "opencv2/core/cvdef.h"
 #include "opencv2/core/fast_math.hpp"
@@ -147,4 +147,4 @@ template<> inline unsigned saturate_cast<unsigned>(double v) { return cvRound(v)
 
 } // cv
 
-#endif // __OPENCV_CORE_SATURATE_HPP__
+#endif // OPENCV_CORE_SATURATE_HPP
diff --git a/modules/core/include/opencv2/core/sse_utils.hpp b/modules/core/include/opencv2/core/sse_utils.hpp
index c87b029..69efffe 100644
--- a/modules/core/include/opencv2/core/sse_utils.hpp
+++ b/modules/core/include/opencv2/core/sse_utils.hpp
@@ -39,8 +39,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_CORE_SSE_UTILS_HPP__
-#define __OPENCV_CORE_SSE_UTILS_HPP__
+#ifndef OPENCV_CORE_SSE_UTILS_HPP
+#define OPENCV_CORE_SSE_UTILS_HPP
 
 #ifndef __cplusplus
 #  error sse_utils.hpp header must be compiled as C++
@@ -649,4 +649,4 @@ inline void _mm_interleave_ps(__m128 & v_r0, __m128 & v_r1, __m128 & v_g0, __m12
 
 //! @}
 
-#endif //__OPENCV_CORE_SSE_UTILS_HPP__
+#endif //OPENCV_CORE_SSE_UTILS_HPP
diff --git a/modules/core/include/opencv2/core/traits.hpp b/modules/core/include/opencv2/core/traits.hpp
index 49bc844..f83b05f 100644
--- a/modules/core/include/opencv2/core/traits.hpp
+++ b/modules/core/include/opencv2/core/traits.hpp
@@ -41,8 +41,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_CORE_TRAITS_HPP__
-#define __OPENCV_CORE_TRAITS_HPP__
+#ifndef OPENCV_CORE_TRAITS_HPP
+#define OPENCV_CORE_TRAITS_HPP
 
 #include "opencv2/core/cvdef.h"
 
@@ -323,4 +323,4 @@ template<> class TypeDepth<CV_64F>
 
 } // cv
 
-#endif // __OPENCV_CORE_TRAITS_HPP__
+#endif // OPENCV_CORE_TRAITS_HPP
diff --git a/modules/core/include/opencv2/core/types.hpp b/modules/core/include/opencv2/core/types.hpp
index e166556..d5c64ca 100644
--- a/modules/core/include/opencv2/core/types.hpp
+++ b/modules/core/include/opencv2/core/types.hpp
@@ -41,8 +41,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_CORE_TYPES_HPP__
-#define __OPENCV_CORE_TYPES_HPP__
+#ifndef OPENCV_CORE_TYPES_HPP
+#define OPENCV_CORE_TYPES_HPP
 
 #ifndef __cplusplus
 #  error types.hpp header must be compiled as C++
@@ -51,6 +51,7 @@
 #include <climits>
 #include <cfloat>
 #include <vector>
+#include <limits>
 
 #include "opencv2/core/cvdef.h"
 #include "opencv2/core/cvstd.hpp"
@@ -176,6 +177,7 @@ public:
 };
 
 typedef Point_<int> Point2i;
+typedef Point_<int64> Point2l;
 typedef Point_<float> Point2f;
 typedef Point_<double> Point2d;
 typedef Point2i Point;
@@ -231,7 +233,11 @@ public:
     //! conversion to another data type
     template<typename _Tp2> operator Point3_<_Tp2>() const;
     //! conversion to cv::Vec<>
+#if OPENCV_ABI_COMPATIBILITY > 300
+    template<typename _Tp2> operator Vec<_Tp2, 3>() const;
+#else
     operator Vec<_Tp, 3>() const;
+#endif
 
     //! dot product
     _Tp dot(const Point3_& pt) const;
@@ -303,6 +309,7 @@ public:
 };
 
 typedef Size_<int> Size2i;
+typedef Size_<int64> Size2l;
 typedef Size_<float> Size2f;
 typedef Size_<double> Size2d;
 typedef Size2i Size;
@@ -476,8 +483,10 @@ public:
     @param pts The points array for storing rectangle vertices.
     */
     void points(Point2f pts[]) const;
-    //! returns the minimal up-right rectangle containing the rotated rectangle
+    //! returns the minimal up-right integer rectangle containing the rotated rectangle
     Rect boundingRect() const;
+    //! returns the minimal (exact) floating point rectangle containing the rotated rectangle, not intended for use with images
+    Rect_<float> boundingRect2f() const;
 
     Point2f center; //< the rectangle mass center
     Size2f size;    //< width and height of the rectangle
@@ -1326,11 +1335,19 @@ Point3_<_Tp>::operator Point3_<_Tp2>() const
     return Point3_<_Tp2>(saturate_cast<_Tp2>(x), saturate_cast<_Tp2>(y), saturate_cast<_Tp2>(z));
 }
 
+#if OPENCV_ABI_COMPATIBILITY > 300
+template<typename _Tp> template<typename _Tp2> inline
+Point3_<_Tp>::operator Vec<_Tp2, 3>() const
+{
+    return Vec<_Tp2, 3>(x, y, z);
+}
+#else
 template<typename _Tp> inline
 Point3_<_Tp>::operator Vec<_Tp, 3>() const
 {
     return Vec<_Tp, 3>(x, y, z);
 }
+#endif
 
 template<typename _Tp> inline
 Point3_<_Tp>& Point3_<_Tp>::operator = (const Point3_& pt)
@@ -1832,7 +1849,26 @@ Rect_<_Tp> operator | (const Rect_<_Tp>& a, const Rect_<_Tp>& b)
     return c |= b;
 }
 
+/**
+ * @brief measure dissimilarity between two sample sets
+ *
+ * computes the complement of the Jaccard Index as described in <https://en.wikipedia.org/wiki/Jaccard_index>.
+ * For rectangles this reduces to computing the intersection over the union.
+ */
+template<typename _Tp> static inline
+double jaccardDistance(const Rect_<_Tp>& a, const Rect_<_Tp>& b) {
+    _Tp Aa = a.area();
+    _Tp Ab = b.area();
 
+    if ((Aa + Ab) <= std::numeric_limits<_Tp>::epsilon()) {
+        // jaccard_index = 1 -> distance = 0
+        return 0.0;
+    }
+
+    double Aab = (a & b).area();
+    // distance = 1 - jaccard_index
+    return 1.0 - Aab / (Aa + Ab - Aab);
+}
 
 ////////////////////////////// RotatedRect //////////////////////////////
 
@@ -2225,4 +2261,4 @@ TermCriteria::TermCriteria(int _type, int _maxCount, double _epsilon)
 
 } // cv
 
-#endif //__OPENCV_CORE_TYPES_HPP__
+#endif //OPENCV_CORE_TYPES_HPP
diff --git a/modules/core/include/opencv2/core/types_c.h b/modules/core/include/opencv2/core/types_c.h
index cb39587..f82a59e 100644
--- a/modules/core/include/opencv2/core/types_c.h
+++ b/modules/core/include/opencv2/core/types_c.h
@@ -41,8 +41,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_CORE_TYPES_H__
-#define __OPENCV_CORE_TYPES_H__
+#ifndef OPENCV_CORE_TYPES_H
+#define OPENCV_CORE_TYPES_H
 
 #ifdef HAVE_IPL
 #  ifndef __IPL_H__
@@ -1669,6 +1669,9 @@ typedef struct CvFileStorage CvFileStorage;
 #define CV_STORAGE_FORMAT_AUTO   0
 #define CV_STORAGE_FORMAT_XML    8
 #define CV_STORAGE_FORMAT_YAML  16
+#define CV_STORAGE_FORMAT_JSON  24
+#define CV_STORAGE_BASE64       64
+#define CV_STORAGE_WRITE_BASE64  (CV_STORAGE_BASE64 | CV_STORAGE_WRITE)
 
 /** @brief List of attributes. :
 
@@ -1829,6 +1832,6 @@ CvModuleInfo;
 
 /** @} */
 
-#endif /*__OPENCV_CORE_TYPES_H__*/
+#endif /*OPENCV_CORE_TYPES_H*/
 
 /* End of file. */
diff --git a/modules/core/include/opencv2/core/utility.hpp b/modules/core/include/opencv2/core/utility.hpp
index b66ade5..e7a7c2d 100644
--- a/modules/core/include/opencv2/core/utility.hpp
+++ b/modules/core/include/opencv2/core/utility.hpp
@@ -42,13 +42,17 @@
 //
 //M*/
 
-#ifndef __OPENCV_CORE_UTILITY_H__
-#define __OPENCV_CORE_UTILITY_H__
+#ifndef OPENCV_CORE_UTILITY_H
+#define OPENCV_CORE_UTILITY_H
 
 #ifndef __cplusplus
 #  error utility.hpp header must be compiled as C++
 #endif
 
+#if defined(check)
+#  warning Detected Apple 'check' macro definition, it can cause build conflicts. Please, include this header before any Apple headers.
+#endif
+
 #include "opencv2/core.hpp"
 
 namespace cv
@@ -247,7 +251,8 @@ CV_EXPORTS_W const String& getBuildInformation();
 
 The function returns the number of ticks after the certain event (for example, when the machine was
 turned on). It can be used to initialize RNG or to measure a function execution time by reading the
-tick count before and after the function call. See also the tick frequency.
+tick count before and after the function call.
+ at sa getTickFrequency, TickMeter
  */
 CV_EXPORTS_W int64 getTickCount();
 
@@ -260,9 +265,126 @@ execution time in seconds:
     // do something ...
     t = ((double)getTickCount() - t)/getTickFrequency();
 @endcode
+ at sa getTickCount, TickMeter
  */
 CV_EXPORTS_W double getTickFrequency();
 
+/** @brief a Class to measure passing time.
+
+The class computes passing time by counting the number of ticks per second. That is, the following code computes the
+execution time in seconds:
+ at code
+TickMeter tm;
+tm.start();
+// do something ...
+tm.stop();
+std::cout << tm.getTimeSec();
+ at endcode
+ at sa getTickCount, getTickFrequency
+*/
+
+class CV_EXPORTS_W TickMeter
+{
+public:
+    //! the default constructor
+    CV_WRAP TickMeter()
+    {
+    reset();
+    }
+
+    /**
+    starts counting ticks.
+    */
+    CV_WRAP void start()
+    {
+    startTime = cv::getTickCount();
+    }
+
+    /**
+    stops counting ticks.
+    */
+    CV_WRAP void stop()
+    {
+    int64 time = cv::getTickCount();
+    if (startTime == 0)
+    return;
+    ++counter;
+    sumTime += (time - startTime);
+    startTime = 0;
+    }
+
+    /**
+    returns counted ticks.
+    */
+    CV_WRAP int64 getTimeTicks() const
+    {
+    return sumTime;
+    }
+
+    /**
+    returns passed time in microseconds.
+    */
+    CV_WRAP double getTimeMicro() const
+    {
+    return getTimeMilli()*1e3;
+    }
+
+    /**
+    returns passed time in milliseconds.
+    */
+    CV_WRAP double getTimeMilli() const
+    {
+    return getTimeSec()*1e3;
+    }
+
+    /**
+    returns passed time in seconds.
+    */
+    CV_WRAP double getTimeSec()   const
+    {
+    return (double)getTimeTicks() / getTickFrequency();
+    }
+
+    /**
+    returns internal counter value.
+    */
+    CV_WRAP int64 getCounter() const
+    {
+    return counter;
+    }
+
+    /**
+    resets internal values.
+    */
+    CV_WRAP void reset()
+    {
+    startTime = 0;
+    sumTime = 0;
+    counter = 0;
+    }
+
+private:
+    int64 counter;
+    int64 sumTime;
+    int64 startTime;
+};
+
+/** @brief output operator
+ at code
+TickMeter tm;
+tm.start();
+// do something ...
+tm.stop();
+std::cout << tm;
+ at endcode
+*/
+
+static inline
+std::ostream& operator << (std::ostream& out, const TickMeter& tm)
+{
+    return out << tm.getTimeSec() << "sec";
+}
+
 /** @brief Returns the number of CPU ticks.
 
 The function returns the current number of CPU ticks on some architectures (such as x86, x64,
@@ -359,7 +481,7 @@ CV_EXPORTS void parallel_for_(const Range& range, const ParallelLoopBody& body,
 template<typename _Tp, typename Functor> inline
 void Mat::forEach_impl(const Functor& operation) {
     if (false) {
-        operation(*reinterpret_cast<_Tp*>(0), reinterpret_cast<int*>(NULL));
+        operation(*reinterpret_cast<_Tp*>(0), reinterpret_cast<int*>(0));
         // If your compiler fail in this line.
         // Please check that your functor signature is
         //     (_Tp&, const int*)   <- multidimential
@@ -373,8 +495,8 @@ void Mat::forEach_impl(const Functor& operation) {
     {
     public:
         PixelOperationWrapper(Mat_<_Tp>* const frame, const Functor& _operation)
-            : mat(frame), op(_operation) {};
-        virtual ~PixelOperationWrapper(){};
+            : mat(frame), op(_operation) {}
+        virtual ~PixelOperationWrapper(){}
         // ! Overloaded virtual operator
         // convert range call to row call.
         virtual void operator()(const Range &range) const {
@@ -403,7 +525,7 @@ void Mat::forEach_impl(const Functor& operation) {
                     this->rowCall(&idx[0], COLS, DIMS);
                 }
             }
-        };
+        }
     private:
         Mat_<_Tp>* const mat;
         const Functor op;
@@ -440,12 +562,12 @@ void Mat::forEach_impl(const Functor& operation) {
                 op(*pixel++, static_cast<const int*>(idx));
                 idx[1]++;
             }
-        };
+        }
         PixelOperationWrapper& operator=(const PixelOperationWrapper &) {
             CV_Assert(false);
             // We can not remove this implementation because Visual Studio warning C4822.
             return *this;
-        };
+        }
     };
 
     parallel_for_(cv::Range(0, LINES), PixelOperationWrapper(reinterpret_cast<Mat_<_Tp>*>(this), operation));
@@ -528,8 +650,8 @@ private:
     virtual void  deleteDataInstance(void* pData) const {delete (T*)pData;} // Wrapper to release data by template
 
     // Disable TLS copy operations
-    TLSData(TLSData &) {};
-    TLSData& operator =(const TLSData &) {return *this;};
+    TLSData(TLSData &) {}
+    TLSData& operator =(const TLSData &) {return *this;}
 };
 
 /** @brief Designed for command line parsing
@@ -813,10 +935,10 @@ AutoBuffer<_Tp, fixed_size>::allocate(size_t _size)
         return;
     }
     deallocate();
+    sz = _size;
     if(_size > fixed_size)
     {
         ptr = new _Tp[_size];
-        sz = _size;
     }
 }
 
@@ -880,10 +1002,170 @@ template<> inline std::string CommandLineParser::get<std::string>(const String&
 
 //! @endcond
 
+
+// Basic Node class for tree building
+template<class OBJECT>
+class CV_EXPORTS Node
+{
+public:
+    Node()
+    {
+        m_pParent  = 0;
+    }
+    Node(OBJECT& payload) : m_payload(payload)
+    {
+        m_pParent  = 0;
+    }
+    ~Node()
+    {
+        removeChilds();
+        if (m_pParent)
+        {
+            int idx = m_pParent->findChild(this);
+            if (idx >= 0)
+                m_pParent->m_childs.erase(m_pParent->m_childs.begin() + idx);
+        }
+    }
+
+    Node<OBJECT>* findChild(OBJECT& payload) const
+    {
+        for(size_t i = 0; i < this->m_childs.size(); i++)
+        {
+            if(this->m_childs[i]->m_payload == payload)
+                return this->m_childs[i];
+        }
+        return NULL;
+    }
+
+    int findChild(Node<OBJECT> *pNode) const
+    {
+        for (size_t i = 0; i < this->m_childs.size(); i++)
+        {
+            if(this->m_childs[i] == pNode)
+                return (int)i;
+        }
+        return -1;
+    }
+
+    void addChild(Node<OBJECT> *pNode)
+    {
+        if(!pNode)
+            return;
+
+        CV_Assert(pNode->m_pParent == 0);
+        pNode->m_pParent = this;
+        this->m_childs.push_back(pNode);
+    }
+
+    void removeChilds()
+    {
+        for(size_t i = 0; i < m_childs.size(); i++)
+        {
+            m_childs[i]->m_pParent = 0; // avoid excessive parent vector trimming
+            delete m_childs[i];
+        }
+        m_childs.clear();
+    }
+
+    int getDepth()
+    {
+        int   count   = 0;
+        Node *pParent = m_pParent;
+        while(pParent) count++, pParent = pParent->m_pParent;
+        return count;
+    }
+
+public:
+    OBJECT                     m_payload;
+    Node<OBJECT>*              m_pParent;
+    std::vector<Node<OBJECT>*> m_childs;
+};
+
+// Instrumentation external interface
+namespace instr
+{
+
+#if !defined OPENCV_ABI_CHECK
+
+enum TYPE
+{
+    TYPE_GENERAL = 0,   // OpenCV API function, e.g. exported function
+    TYPE_MARKER,        // Information marker
+    TYPE_WRAPPER,       // Wrapper function for implementation
+    TYPE_FUN,           // Simple function call
+};
+
+enum IMPL
+{
+    IMPL_PLAIN = 0,
+    IMPL_IPP,
+    IMPL_OPENCL,
+};
+
+struct NodeDataTls
+{
+    NodeDataTls()
+    {
+        m_ticksTotal = 0;
+    }
+    uint64      m_ticksTotal;
+};
+
+class CV_EXPORTS NodeData
+{
+public:
+    NodeData(const char* funName = 0, const char* fileName = NULL, int lineNum = 0, void* retAddress = NULL, bool alwaysExpand = false, cv::instr::TYPE instrType = TYPE_GENERAL, cv::instr::IMPL implType = IMPL_PLAIN);
+    NodeData(NodeData &ref);
+    ~NodeData();
+    NodeData& operator=(const NodeData&);
+
+    cv::String          m_funName;
+    cv::instr::TYPE     m_instrType;
+    cv::instr::IMPL     m_implType;
+    const char*         m_fileName;
+    int                 m_lineNum;
+    void*               m_retAddress;
+    bool                m_alwaysExpand;
+    bool                m_funError;
+
+    volatile int         m_counter;
+    volatile uint64      m_ticksTotal;
+    TLSData<NodeDataTls> m_tls;
+    int                  m_threads;
+
+    // No synchronization
+    double getTotalMs()   const { return ((double)m_ticksTotal / cv::getTickFrequency()) * 1000; }
+    double getMeanMs()    const { return (((double)m_ticksTotal/m_counter) / cv::getTickFrequency()) * 1000; }
+};
+bool operator==(const NodeData& lhs, const NodeData& rhs);
+
+typedef Node<NodeData> InstrNode;
+
+CV_EXPORTS InstrNode* getTrace();
+
+#endif // !defined OPENCV_ABI_CHECK
+
+
+CV_EXPORTS bool       useInstrumentation();
+CV_EXPORTS void       setUseInstrumentation(bool flag);
+CV_EXPORTS void       resetTrace();
+
+enum FLAGS
+{
+    FLAGS_NONE              = 0,
+    FLAGS_MAPPING           = 0x01,
+    FLAGS_EXPAND_SAME_NAMES = 0x02,
+};
+
+CV_EXPORTS void       setFlags(FLAGS modeFlags);
+static inline void    setFlags(int modeFlags) { setFlags((FLAGS)modeFlags); }
+CV_EXPORTS FLAGS      getFlags();
+}
+
 } //namespace cv
 
 #ifndef DISABLE_OPENCV_24_COMPATIBILITY
 #include "opencv2/core/core_c.h"
 #endif
 
-#endif //__OPENCV_CORE_UTILITY_H__
+#endif //OPENCV_CORE_UTILITY_H
diff --git a/modules/core/include/opencv2/core/va_intel.hpp b/modules/core/include/opencv2/core/va_intel.hpp
index f4bb8a6..3325848 100644
--- a/modules/core/include/opencv2/core/va_intel.hpp
+++ b/modules/core/include/opencv2/core/va_intel.hpp
@@ -5,8 +5,8 @@
 // Copyright (C) 2015, Itseez, Inc., all rights reserved.
 // Third party copyrights are property of their respective owners.
 
-#ifndef __OPENCV_CORE_VA_INTEL_HPP__
-#define __OPENCV_CORE_VA_INTEL_HPP__
+#ifndef OPENCV_CORE_VA_INTEL_HPP
+#define OPENCV_CORE_VA_INTEL_HPP
 
 #ifndef __cplusplus
 #  error va_intel.hpp header must be compiled as C++
@@ -74,4 +74,4 @@ CV_EXPORTS void convertFromVASurface(VADisplay display, VASurfaceID surface, Siz
 
 }} // namespace cv::va_intel
 
-#endif /* __OPENCV_CORE_VA_INTEL_HPP__ */
+#endif /* OPENCV_CORE_VA_INTEL_HPP */
diff --git a/modules/core/include/opencv2/core/version.hpp b/modules/core/include/opencv2/core/version.hpp
index cf1442b..b4c8f25 100644
--- a/modules/core/include/opencv2/core/version.hpp
+++ b/modules/core/include/opencv2/core/version.hpp
@@ -47,18 +47,18 @@
   Usefull to test in user programs
 */
 
-#ifndef __OPENCV_VERSION_HPP__
-#define __OPENCV_VERSION_HPP__
+#ifndef OPENCV_VERSION_HPP
+#define OPENCV_VERSION_HPP
 
 #define CV_VERSION_MAJOR    3
-#define CV_VERSION_MINOR    1
+#define CV_VERSION_MINOR    2
 #define CV_VERSION_REVISION 0
 #define CV_VERSION_STATUS   ""
 
 #define CVAUX_STR_EXP(__A)  #__A
 #define CVAUX_STR(__A)      CVAUX_STR_EXP(__A)
 
-#define CVAUX_STRW_EXP(__A)  L#__A
+#define CVAUX_STRW_EXP(__A)  L ## #__A
 #define CVAUX_STRW(__A)      CVAUX_STRW_EXP(__A)
 
 #define CV_VERSION          CVAUX_STR(CV_VERSION_MAJOR) "." CVAUX_STR(CV_VERSION_MINOR) "." CVAUX_STR(CV_VERSION_REVISION) CV_VERSION_STATUS
diff --git a/modules/core/include/opencv2/core/wimage.hpp b/modules/core/include/opencv2/core/wimage.hpp
index ef9d398..b246c89 100644
--- a/modules/core/include/opencv2/core/wimage.hpp
+++ b/modules/core/include/opencv2/core/wimage.hpp
@@ -39,8 +39,8 @@
 /////////////////////////////////////////////////////////////////////////////////
 //M*/
 
-#ifndef __OPENCV_CORE_WIMAGE_HPP__
-#define __OPENCV_CORE_WIMAGE_HPP__
+#ifndef OPENCV_CORE_WIMAGE_HPP
+#define OPENCV_CORE_WIMAGE_HPP
 
 #include "opencv2/core/core_c.h"
 
diff --git a/modules/core/misc/java/test/CoreTest.java b/modules/core/misc/java/test/CoreTest.java
index 9c60fd5..3187e7c 100644
--- a/modules/core/misc/java/test/CoreTest.java
+++ b/modules/core/misc/java/test/CoreTest.java
@@ -1777,7 +1777,7 @@ public class CoreTest extends OpenCVTestCase {
         };
         Mat roots = new Mat();
 
-        assertEquals(0.0, Core.solvePoly(coeffs, roots));
+        assertGE(1e-6, Math.abs(Core.solvePoly(coeffs, roots)));
 
         truth = new Mat(3, 1, CvType.CV_32FC2) {
             {
diff --git a/modules/core/misc/java/test/MatTest.java b/modules/core/misc/java/test/MatTest.java
index a2570f4..3ff0c8b 100644
--- a/modules/core/misc/java/test/MatTest.java
+++ b/modules/core/misc/java/test/MatTest.java
@@ -494,7 +494,7 @@ public class MatTest extends OpenCVTestCase {
 
     public void testIsSubmatrix() {
         assertFalse(gray0.isSubmatrix());
-        Mat subMat = gray0.submat(0, 0, gray0.rows() / 2, gray0.cols() / 2);
+        Mat subMat = gray0.submat(0, gray0.rows() / 2, 0, gray0.cols() / 2);
         assertTrue(subMat.isSubmatrix());
     }
 
diff --git a/modules/core/perf/opencl/perf_arithm.cpp b/modules/core/perf/opencl/perf_arithm.cpp
index 9cb5ac9..3efccb0 100644
--- a/modules/core/perf/opencl/perf_arithm.cpp
+++ b/modules/core/perf/opencl/perf_arithm.cpp
@@ -91,7 +91,10 @@ OCL_PERF_TEST_P(ExpFixture, Exp, ::testing::Combine(
 
     OCL_TEST_CYCLE() cv::exp(src, dst);
 
-    SANITY_CHECK(dst, 1e-6, ERROR_RELATIVE);
+    if (CV_MAT_DEPTH(type) >= CV_32F)
+        SANITY_CHECK(dst, 1e-5, ERROR_RELATIVE);
+    else
+        SANITY_CHECK(dst, 1);
 }
 
 ///////////// Log ////////////////////////
@@ -113,7 +116,10 @@ OCL_PERF_TEST_P(LogFixture, Log, ::testing::Combine(
 
     OCL_TEST_CYCLE() cv::log(src, dst);
 
-    SANITY_CHECK(dst, 1e-6, ERROR_RELATIVE);
+    if (CV_MAT_DEPTH(type) >= CV_32F)
+        SANITY_CHECK(dst, 1e-5, ERROR_RELATIVE);
+    else
+        SANITY_CHECK(dst, 1);
 }
 
 ///////////// Add ////////////////////////
@@ -193,9 +199,21 @@ OCL_PERF_TEST_P(DivFixture, Divide,
     UMat src1(srcSize, type), src2(srcSize, type), dst(srcSize, type);
     declare.in(src1, src2, WARMUP_RNG).out(dst);
 
+    // remove zeros from src2
+    {
+        Mat m2 = src2.getMat(ACCESS_RW);
+        Mat zero_mask = m2 == 0;
+        Mat fix;
+        zero_mask.convertTo(fix, type); // 0 or 255
+        cv::add(m2, fix, m2);
+    }
+
     OCL_TEST_CYCLE() cv::divide(src1, src2, dst);
 
-    SANITY_CHECK(dst, 1e-6, ERROR_RELATIVE);
+    if (CV_MAT_DEPTH(type) >= CV_32F)
+        SANITY_CHECK(dst, 1e-6, ERROR_RELATIVE);
+    else
+        SANITY_CHECK(dst, 1);
 }
 
 ///////////// Absdiff ////////////////////////
@@ -660,7 +678,10 @@ OCL_PERF_TEST_P(SqrtFixture, Sqrt, ::testing::Combine(
 
     OCL_TEST_CYCLE() cv::sqrt(src, dst);
 
-    SANITY_CHECK(dst, 1e-6, ERROR_RELATIVE);
+    if (CV_MAT_DEPTH(type) >= CV_32F)
+        SANITY_CHECK(dst, 1e-5, ERROR_RELATIVE);
+    else
+        SANITY_CHECK(dst, 1);
 }
 
 ///////////// SetIdentity ////////////////////////
@@ -983,7 +1004,7 @@ OCL_PERF_TEST_P(ConvertScaleAbsFixture, ConvertScaleAbs,
 
     OCL_TEST_CYCLE() cv::convertScaleAbs(src, dst, 0.5, 2);
 
-    SANITY_CHECK(dst);
+    SANITY_CHECK(dst, 1); // CV_8U
 }
 
 ///////////// PatchNaNs ////////////////////////
diff --git a/modules/core/perf/perf_convertTo.cpp b/modules/core/perf/perf_convertTo.cpp
index 8007361..3738e32 100644
--- a/modules/core/perf/perf_convertTo.cpp
+++ b/modules/core/perf/perf_convertTo.cpp
@@ -26,12 +26,16 @@ PERF_TEST_P( Size_DepthSrc_DepthDst_Channels_alpha, convertTo,
     int channels = get<3>(GetParam());
     double alpha = get<4>(GetParam());
 
+    int maxValue = 255;
+
     Mat src(sz, CV_MAKETYPE(depthSrc, channels));
-    randu(src, 0, 255);
+    randu(src, 0, maxValue);
     Mat dst(sz, CV_MAKETYPE(depthDst, channels));
 
     int runs = (sz.width <= 640) ? 8 : 1;
     TEST_CYCLE_MULTIRUN(runs) src.convertTo(dst, depthDst, alpha);
 
-    SANITY_CHECK(dst, alpha == 1.0 ? 1e-12 : 1e-7);
+    double eps = depthSrc <= CV_32S ? 1e-12 : (FLT_EPSILON * maxValue);
+    eps = eps * std::max(1.0, fabs(alpha));
+    SANITY_CHECK(dst, eps);
 }
diff --git a/modules/core/perf/perf_io_base64.cpp b/modules/core/perf/perf_io_base64.cpp
new file mode 100644
index 0000000..799c52c
--- /dev/null
+++ b/modules/core/perf/perf_io_base64.cpp
@@ -0,0 +1,86 @@
+#include "perf_precomp.hpp"
+
+using namespace std;
+using namespace cv;
+using namespace perf;
+using std::tr1::make_tuple;
+using std::tr1::get;
+
+typedef std::tr1::tuple<cv::Size, MatType, String> Size_MatType_Str_t;
+typedef TestBaseWithParam<Size_MatType_Str_t> Size_Mat_StrType;
+
+#define MAT_SIZES      ::perf::sz1080p/*, ::perf::sz4320p*/
+#define MAT_TYPES      CV_8UC1, CV_32FC1
+#define FILE_EXTENSION String(".xml"), String(".yml"), String(".json")
+
+
+PERF_TEST_P(Size_Mat_StrType, fs_text,
+            testing::Combine(testing::Values(MAT_SIZES),
+                             testing::Values(MAT_TYPES),
+                             testing::Values(FILE_EXTENSION))
+             )
+{
+    Size   size = get<0>(GetParam());
+    int    type = get<1>(GetParam());
+    String ext  = get<2>(GetParam());
+
+    Mat src(size.height, size.width, type);
+    Mat dst = src.clone();
+
+    declare.in(src, WARMUP_RNG).out(dst);
+
+    cv::String file_name = cv::tempfile(ext.c_str());
+    cv::String key       = "test_mat";
+
+    TEST_CYCLE_MULTIRUN(2)
+    {
+        {
+            FileStorage fs(file_name, cv::FileStorage::WRITE);
+            fs << key << src;
+            fs.release();
+        }
+        {
+            FileStorage fs(file_name, cv::FileStorage::READ);
+            fs[key] >> dst;
+            fs.release();
+        }
+    }
+
+    remove(file_name.c_str());
+    SANITY_CHECK_NOTHING();
+}
+
+PERF_TEST_P(Size_Mat_StrType, fs_base64,
+            testing::Combine(testing::Values(MAT_SIZES),
+                             testing::Values(MAT_TYPES),
+                             testing::Values(FILE_EXTENSION))
+             )
+{
+    Size   size = get<0>(GetParam());
+    int    type = get<1>(GetParam());
+    String ext  = get<2>(GetParam());
+
+    Mat src(size.height, size.width, type);
+    Mat dst = src.clone();
+
+    cv::String file_name = cv::tempfile(ext.c_str());
+    cv::String key       = "test_mat";
+
+    declare.in(src, WARMUP_RNG).out(dst);
+    TEST_CYCLE_MULTIRUN(2)
+    {
+        {
+            FileStorage fs(file_name, cv::FileStorage::WRITE_BASE64);
+            fs << key << src;
+            fs.release();
+        }
+        {
+            FileStorage fs(file_name, cv::FileStorage::READ);
+            fs[key] >> dst;
+            fs.release();
+        }
+    }
+
+    remove(file_name.c_str());
+    SANITY_CHECK_NOTHING();
+}
diff --git a/modules/core/perf/perf_math.cpp b/modules/core/perf/perf_math.cpp
index 267cc9c..eb3fbb0 100644
--- a/modules/core/perf/perf_math.cpp
+++ b/modules/core/perf/perf_math.cpp
@@ -25,6 +25,20 @@ PERF_TEST_P(VectorLength, phase32f, testing::Values(128, 1000, 128*1024, 512*102
     SANITY_CHECK(angle, 5e-5);
 }
 
+PERF_TEST_P(VectorLength, phase64f, testing::Values(128, 1000, 128*1024, 512*1024, 1024*1024))
+{
+    size_t length = GetParam();
+    vector<double> X(length);
+    vector<double> Y(length);
+    vector<double> angle(length);
+
+    declare.in(X, Y, WARMUP_RNG).out(angle);
+
+    TEST_CYCLE_N(200) cv::phase(X, Y, angle, true);
+
+    SANITY_CHECK(angle, 5e-5);
+}
+
 PERF_TEST_P( MaxDim_MaxPoints, kmeans,
              testing::Combine( testing::Values( 16, 32, 64 ),
                                testing::Values( 300, 400, 500) ) )
diff --git a/modules/core/perf/perf_merge.cpp b/modules/core/perf/perf_merge.cpp
index e7e8d2f..6af7fee 100644
--- a/modules/core/perf/perf_merge.cpp
+++ b/modules/core/perf/perf_merge.cpp
@@ -22,16 +22,19 @@ PERF_TEST_P( Size_SrcDepth_DstChannels, merge,
     int srcDepth = get<1>(GetParam());
     int dstChannels = get<2>(GetParam());
 
+    int maxValue = 255;
+
     vector<Mat> mv;
     for( int i = 0; i < dstChannels; ++i )
     {
         mv.push_back( Mat(sz, CV_MAKETYPE(srcDepth, 1)) );
-        randu(mv[i], 0, 255);
+        randu(mv[i], 0, maxValue);
     }
 
     Mat dst;
     int runs = (sz.width <= 640) ? 8 : 1;
     TEST_CYCLE_MULTIRUN(runs) merge( (vector<Mat> &)mv, dst );
 
-    SANITY_CHECK(dst, 1e-12);
+    double eps = srcDepth <= CV_32S ? 1e-12 : (FLT_EPSILON * maxValue);
+    SANITY_CHECK(dst, eps);
 }
diff --git a/modules/core/perf/perf_split.cpp b/modules/core/perf/perf_split.cpp
index df9095f..553fe6f 100644
--- a/modules/core/perf/perf_split.cpp
+++ b/modules/core/perf/perf_split.cpp
@@ -29,5 +29,9 @@ PERF_TEST_P( Size_Depth_Channels, split,
     int runs = (sz.width <= 640) ? 8 : 1;
     TEST_CYCLE_MULTIRUN(runs) split(m, (vector<Mat>&)mv);
 
+#if defined (__aarch64__)
+    SANITY_CHECK(mv, 2e-5);
+#else
     SANITY_CHECK(mv, 1e-12);
+#endif
 }
diff --git a/modules/core/perf/perf_umat.cpp b/modules/core/perf/perf_umat.cpp
index ddeaa7a..2f45b79 100644
--- a/modules/core/perf/perf_umat.cpp
+++ b/modules/core/perf/perf_umat.cpp
@@ -13,7 +13,6 @@ using namespace ::testing;
 using std::tr1::tuple;
 using std::tr1::get;
 
-namespace {
 
 struct OpenCLState
 {
@@ -64,5 +63,3 @@ OCL_PERF_TEST_P(UMatTest, CustomPtr, Combine(Values(sz1080p, sz2160p), Bool(), :
 
     SANITY_CHECK_NOTHING();
 }
-
-} // namespace cvtest
diff --git a/modules/core/src/algorithm.cpp b/modules/core/src/algorithm.cpp
index b930428..4e7701a 100644
--- a/modules/core/src/algorithm.cpp
+++ b/modules/core/src/algorithm.cpp
@@ -57,7 +57,6 @@ void Algorithm::save(const String& filename) const
 {
     FileStorage fs(filename, FileStorage::WRITE);
     fs << getDefaultName() << "{";
-    fs << "format" << (int)3;
     write(fs);
     fs << "}";
 }
@@ -67,6 +66,11 @@ String Algorithm::getDefaultName() const
     return String("my_object");
 }
 
+void Algorithm::writeFormat(FileStorage& fs) const
+{
+    fs << "format" << (int)3;
+}
+
 }
 
 /* End of file. */
diff --git a/modules/core/src/arithm.cpp b/modules/core/src/arithm.cpp
index c3acca0..4b1c673 100644
--- a/modules/core/src/arithm.cpp
+++ b/modules/core/src/arithm.cpp
@@ -369,58 +369,78 @@ static BinaryFuncC* getMinTab()
 
 void cv::bitwise_and(InputArray a, InputArray b, OutputArray c, InputArray mask)
 {
+    CV_INSTRUMENT_REGION()
+
     BinaryFuncC f = (BinaryFuncC)GET_OPTIMIZED(cv::hal::and8u);
     binary_op(a, b, c, mask, &f, true, OCL_OP_AND);
 }
 
 void cv::bitwise_or(InputArray a, InputArray b, OutputArray c, InputArray mask)
 {
+    CV_INSTRUMENT_REGION()
+
     BinaryFuncC f = (BinaryFuncC)GET_OPTIMIZED(cv::hal::or8u);
     binary_op(a, b, c, mask, &f, true, OCL_OP_OR);
 }
 
 void cv::bitwise_xor(InputArray a, InputArray b, OutputArray c, InputArray mask)
 {
+    CV_INSTRUMENT_REGION()
+
     BinaryFuncC f = (BinaryFuncC)GET_OPTIMIZED(cv::hal::xor8u);
     binary_op(a, b, c, mask, &f, true, OCL_OP_XOR);
 }
 
 void cv::bitwise_not(InputArray a, OutputArray c, InputArray mask)
 {
+    CV_INSTRUMENT_REGION()
+
     BinaryFuncC f = (BinaryFuncC)GET_OPTIMIZED(cv::hal::not8u);
     binary_op(a, a, c, mask, &f, true, OCL_OP_NOT);
 }
 
 void cv::max( InputArray src1, InputArray src2, OutputArray dst )
 {
+    CV_INSTRUMENT_REGION()
+
     binary_op(src1, src2, dst, noArray(), getMaxTab(), false, OCL_OP_MAX );
 }
 
 void cv::min( InputArray src1, InputArray src2, OutputArray dst )
 {
+    CV_INSTRUMENT_REGION()
+
     binary_op(src1, src2, dst, noArray(), getMinTab(), false, OCL_OP_MIN );
 }
 
 void cv::max(const Mat& src1, const Mat& src2, Mat& dst)
 {
+    CV_INSTRUMENT_REGION()
+
     OutputArray _dst(dst);
     binary_op(src1, src2, _dst, noArray(), getMaxTab(), false, OCL_OP_MAX );
 }
 
 void cv::min(const Mat& src1, const Mat& src2, Mat& dst)
 {
+    CV_INSTRUMENT_REGION()
+
     OutputArray _dst(dst);
     binary_op(src1, src2, _dst, noArray(), getMinTab(), false, OCL_OP_MIN );
 }
 
 void cv::max(const UMat& src1, const UMat& src2, UMat& dst)
 {
+    CV_INSTRUMENT_REGION()
+
     OutputArray _dst(dst);
     binary_op(src1, src2, _dst, noArray(), getMaxTab(), false, OCL_OP_MAX );
 }
 
 void cv::min(const UMat& src1, const UMat& src2, UMat& dst)
 {
+    CV_INSTRUMENT_REGION()
+
     OutputArray _dst(dst);
     binary_op(src1, src2, _dst, noArray(), getMinTab(), false, OCL_OP_MIN );
 }
@@ -643,7 +663,7 @@ static void arithm_op(InputArray _src1, InputArray _src2, OutputArray _dst,
         if (!muldiv)
         {
             Mat sc = psrc2->getMat();
-            depth2 = actualScalarDepth(sc.ptr<double>(), cn);
+            depth2 = actualScalarDepth(sc.ptr<double>(), sz2 == Size(1, 1) ? cn2 : cn);
             if( depth2 == CV_64F && (depth1 < CV_32S || depth1 == CV_32F) )
                 depth2 = CV_32F;
         }
@@ -901,12 +921,16 @@ static BinaryFuncC* getAbsDiffTab()
 void cv::add( InputArray src1, InputArray src2, OutputArray dst,
           InputArray mask, int dtype )
 {
+    CV_INSTRUMENT_REGION()
+
     arithm_op(src1, src2, dst, mask, dtype, getAddTab(), false, 0, OCL_OP_ADD );
 }
 
 void cv::subtract( InputArray _src1, InputArray _src2, OutputArray _dst,
                InputArray mask, int dtype )
 {
+    CV_INSTRUMENT_REGION()
+
 #ifdef HAVE_TEGRA_OPTIMIZATION
     if (tegra::useTegra())
     {
@@ -965,6 +989,8 @@ void cv::subtract( InputArray _src1, InputArray _src2, OutputArray _dst,
 
 void cv::absdiff( InputArray src1, InputArray src2, OutputArray dst )
 {
+    CV_INSTRUMENT_REGION()
+
     arithm_op(src1, src2, dst, noArray(), -1, getAbsDiffTab(), false, 0, OCL_OP_ABSDIFF);
 }
 
@@ -1016,6 +1042,8 @@ static BinaryFuncC* getRecipTab()
 void cv::multiply(InputArray src1, InputArray src2,
                   OutputArray dst, double scale, int dtype)
 {
+    CV_INSTRUMENT_REGION()
+
     arithm_op(src1, src2, dst, noArray(), dtype, getMulTab(),
               true, &scale, std::abs(scale - 1.0) < DBL_EPSILON ? OCL_OP_MUL : OCL_OP_MUL_SCALE);
 }
@@ -1023,12 +1051,16 @@ void cv::multiply(InputArray src1, InputArray src2,
 void cv::divide(InputArray src1, InputArray src2,
                 OutputArray dst, double scale, int dtype)
 {
+    CV_INSTRUMENT_REGION()
+
     arithm_op(src1, src2, dst, noArray(), dtype, getDivTab(), true, &scale, OCL_OP_DIV_SCALE);
 }
 
 void cv::divide(double scale, InputArray src2,
                 OutputArray dst, int dtype)
 {
+    CV_INSTRUMENT_REGION()
+
     arithm_op(src2, src2, dst, noArray(), dtype, getRecipTab(), true, &scale, OCL_OP_RECIP_SCALE);
 }
 
@@ -1056,6 +1088,8 @@ static BinaryFuncC* getAddWeightedTab()
 void cv::addWeighted( InputArray src1, double alpha, InputArray src2,
                       double beta, double gamma, OutputArray dst, int dtype )
 {
+    CV_INSTRUMENT_REGION()
+
     double scalars[] = {alpha, beta, gamma};
     arithm_op(src1, src2, dst, noArray(), dtype, getAddWeightedTab(), true, scalars, OCL_OP_ADDW);
 }
@@ -1194,6 +1228,8 @@ static bool ocl_compare(InputArray _src1, InputArray _src2, OutputArray _dst, in
 
 void cv::compare(InputArray _src1, InputArray _src2, OutputArray _dst, int op)
 {
+    CV_INSTRUMENT_REGION()
+
     CV_Assert( op == CMP_LT || op == CMP_LE || op == CMP_EQ ||
                op == CMP_NE || op == CMP_GE || op == CMP_GT );
 
@@ -1889,6 +1925,8 @@ static bool ocl_inRange( InputArray _src, InputArray _lowerb,
 void cv::inRange(InputArray _src, InputArray _lowerb,
                  InputArray _upperb, OutputArray _dst)
 {
+    CV_INSTRUMENT_REGION()
+
     CV_OCL_RUN(_src.dims() <= 2 && _lowerb.dims() <= 2 &&
                _upperb.dims() <= 2 && OCL_PERFORMANCE_CHECK(_dst.isUMat()),
                ocl_inRange(_src, _lowerb, _upperb, _dst))
@@ -2274,7 +2312,7 @@ static inline void fixSteps(int width, int height, size_t elemSize, size_t& step
     CV_IPP_CHECK() \
     { \
         fixSteps(width, height, sizeof(dst[0]), step1, step2, step); \
-        if (0 <= fun(src1, (int)step1, src2, (int)step2, dst, (int)step, ippiSize(width, height), 0)) \
+        if (0 <= CV_INSTRUMENT_FUN_IPP(fun, src1, (int)step1, src2, (int)step2, dst, (int)step, ippiSize(width, height), 0)) \
         { \
             CV_IMPL_ADD(CV_IMPL_IPP); \
             return; \
@@ -2286,7 +2324,7 @@ static inline void fixSteps(int width, int height, size_t elemSize, size_t& step
     CV_IPP_CHECK() \
     { \
         fixSteps(width, height, sizeof(dst[0]), step1, step2, step); \
-        if (0 <= fun(src2, (int)step2, src1, (int)step1, dst, (int)step, ippiSize(width, height), 0)) \
+        if (0 <= CV_INSTRUMENT_FUN_IPP(fun, src2, (int)step2, src1, (int)step1, dst, (int)step, ippiSize(width, height), 0)) \
         { \
             CV_IMPL_ADD(CV_IMPL_IPP); \
             return; \
@@ -2298,7 +2336,7 @@ static inline void fixSteps(int width, int height, size_t elemSize, size_t& step
     CV_IPP_CHECK() \
     { \
         fixSteps(width, height, sizeof(dst[0]), step1, step2, step); \
-        if (0 <= fun(src1, (int)step1, src2, (int)step2, dst, (int)step, ippiSize(width, height))) \
+        if (0 <= CV_INSTRUMENT_FUN_IPP(fun, src1, (int)step1, src2, (int)step2, dst, (int)step, ippiSize(width, height))) \
         { \
             CV_IMPL_ADD(CV_IMPL_IPP); \
             return; \
@@ -2310,7 +2348,7 @@ static inline void fixSteps(int width, int height, size_t elemSize, size_t& step
     CV_IPP_CHECK() \
     { \
         fixSteps(width, height, sizeof(dst[0]), step1, step2, step); \
-        if (0 <= fun(src2, (int)step2, src1, (int)step1, dst, (int)step, ippiSize(width, height))) \
+        if (0 <= CV_INSTRUMENT_FUN_IPP(fun, src2, (int)step2, src1, (int)step1, dst, (int)step, ippiSize(width, height))) \
         { \
             CV_IMPL_ADD(CV_IMPL_IPP); \
             return; \
@@ -2467,7 +2505,7 @@ void sub64f( const double* src1, size_t step1,
         int i = 0; \
         for(; i < height; i++) \
         { \
-            if (0 > fun(s1, s2, d, width)) \
+            if (0 > CV_INSTRUMENT_FUN_IPP(fun, s1, s2, d, width)) \
                 break; \
             s1 = (type*)((uchar*)s1 + step1); \
             s2 = (type*)((uchar*)s2 + step2); \
@@ -2684,7 +2722,7 @@ void absdiff64f( const double* src1, size_t step1,
     CV_IPP_CHECK() \
     { \
         fixSteps(width, height, sizeof(dst[0]), step1, step2, step); (void)src2; \
-        if (0 <= fun(src1, (int)step1, dst, (int)step, ippiSize(width, height))) \
+        if (0 <= CV_INSTRUMENT_FUN_IPP(fun, src1, (int)step1, dst, (int)step, ippiSize(width, height))) \
         { \
             CV_IMPL_ADD(CV_IMPL_IPP); \
             return; \
@@ -2750,7 +2788,7 @@ inline static IppCmpOp convert_cmp(int _cmpop)
         if( op  >= 0 ) \
         { \
             fixSteps(width, height, sizeof(dst[0]), step1, step2, step); \
-            if (0 <= fun(src1, (int)step1, src2, (int)step2, dst, (int)step, ippiSize(width, height), op)) \
+            if (0 <= CV_INSTRUMENT_FUN_IPP(fun, src1, (int)step1, src2, (int)step2, dst, (int)step, ippiSize(width, height), op)) \
             { \
                 CV_IMPL_ADD(CV_IMPL_IPP); \
                 return; \
@@ -3023,7 +3061,7 @@ void cmp64f(const double* src1, size_t step1, const double* src2, size_t step2,
     { \
         if (std::fabs(fscale - 1) <= FLT_EPSILON) \
         { \
-            if (fun(src1, (int)step1, src2, (int)step2, dst, (int)step, ippiSize(width, height), 0) >= 0) \
+            if (CV_INSTRUMENT_FUN_IPP(fun, src1, (int)step1, src2, (int)step2, dst, (int)step, ippiSize(width, height), 0) >= 0) \
             { \
                 CV_IMPL_ADD(CV_IMPL_IPP); \
                 return; \
@@ -3037,7 +3075,7 @@ void cmp64f(const double* src1, size_t step1, const double* src2, size_t step2,
     { \
         if (std::fabs(fscale - 1) <= FLT_EPSILON) \
         { \
-            if (fun(src1, (int)step1, src2, (int)step2, dst, (int)step, ippiSize(width, height)) >= 0) \
+            if (CV_INSTRUMENT_FUN_IPP(fun, src1, (int)step1, src2, (int)step2, dst, (int)step, ippiSize(width, height)) >= 0) \
             { \
                 CV_IMPL_ADD(CV_IMPL_IPP); \
                 return; \
@@ -3123,7 +3161,7 @@ void div8u( const uchar* src1, size_t step1, const uchar* src2, size_t step2,
     if( src1 )
         div_i(src1, step1, src2, step2, dst, step, width, height, *(const double*)scale);
     else
-        recip_i(src1, step1, src2, step2, dst, step, width, height, *(const double*)scale);
+        recip_i(src2, step2, dst, step, width, height, *(const double*)scale);
 }
 
 void div8s( const schar* src1, size_t step1, const schar* src2, size_t step2,
@@ -3172,53 +3210,53 @@ void div64f( const double* src1, size_t step1, const double* src2, size_t step2,
 // Reciprocial
 //=======================================
 
-void recip8u( const uchar* src1, size_t step1, const uchar* src2, size_t step2,
+void recip8u( const uchar*, size_t, const uchar* src2, size_t step2,
                   uchar* dst, size_t step, int width, int height, void* scale)
 {
-    CALL_HAL(recip8u, cv_hal_recip8u, src1, step1, src2, step2, dst, step, width, height, *(const double*)scale)
-    recip_i(src1, step1, src2, step2, dst, step, width, height, *(const double*)scale);
+    CALL_HAL(recip8u, cv_hal_recip8u, src2, step2, dst, step, width, height, *(const double*)scale)
+    recip_i(src2, step2, dst, step, width, height, *(const double*)scale);
 }
 
-void recip8s( const schar* src1, size_t step1, const schar* src2, size_t step2,
+void recip8s( const schar*, size_t, const schar* src2, size_t step2,
                   schar* dst, size_t step, int width, int height, void* scale)
 {
-    CALL_HAL(recip8s, cv_hal_recip8s, src1, step1, src2, step2, dst, step, width, height, *(const double*)scale)
-    recip_i(src1, step1, src2, step2, dst, step, width, height, *(const double*)scale);
+    CALL_HAL(recip8s, cv_hal_recip8s, src2, step2, dst, step, width, height, *(const double*)scale)
+    recip_i(src2, step2, dst, step, width, height, *(const double*)scale);
 }
 
-void recip16u( const ushort* src1, size_t step1, const ushort* src2, size_t step2,
+void recip16u( const ushort*, size_t, const ushort* src2, size_t step2,
                    ushort* dst, size_t step, int width, int height, void* scale)
 {
-    CALL_HAL(recip16u, cv_hal_recip16u, src1, step1, src2, step2, dst, step, width, height, *(const double*)scale)
-    recip_i(src1, step1, src2, step2, dst, step, width, height, *(const double*)scale);
+    CALL_HAL(recip16u, cv_hal_recip16u, src2, step2, dst, step, width, height, *(const double*)scale)
+    recip_i(src2, step2, dst, step, width, height, *(const double*)scale);
 }
 
-void recip16s( const short* src1, size_t step1, const short* src2, size_t step2,
+void recip16s( const short*, size_t, const short* src2, size_t step2,
                    short* dst, size_t step, int width, int height, void* scale)
 {
-    CALL_HAL(recip16s, cv_hal_recip16s, src1, step1, src2, step2, dst, step, width, height, *(const double*)scale)
-    recip_i(src1, step1, src2, step2, dst, step, width, height, *(const double*)scale);
+    CALL_HAL(recip16s, cv_hal_recip16s, src2, step2, dst, step, width, height, *(const double*)scale)
+    recip_i(src2, step2, dst, step, width, height, *(const double*)scale);
 }
 
-void recip32s( const int* src1, size_t step1, const int* src2, size_t step2,
+void recip32s( const int*, size_t, const int* src2, size_t step2,
                    int* dst, size_t step, int width, int height, void* scale)
 {
-    CALL_HAL(recip32s, cv_hal_recip32s, src1, step1, src2, step2, dst, step, width, height, *(const double*)scale)
-    recip_i(src1, step1, src2, step2, dst, step, width, height, *(const double*)scale);
+    CALL_HAL(recip32s, cv_hal_recip32s, src2, step2, dst, step, width, height, *(const double*)scale)
+    recip_i(src2, step2, dst, step, width, height, *(const double*)scale);
 }
 
-void recip32f( const float* src1, size_t step1, const float* src2, size_t step2,
+void recip32f( const float*, size_t, const float* src2, size_t step2,
                    float* dst, size_t step, int width, int height, void* scale)
 {
-    CALL_HAL(recip32f, cv_hal_recip32f, src1, step1, src2, step2, dst, step, width, height, *(const double*)scale)
-    recip_f(src1, step1, src2, step2, dst, step, width, height, *(const double*)scale);
+    CALL_HAL(recip32f, cv_hal_recip32f, src2, step2, dst, step, width, height, *(const double*)scale)
+    recip_f(src2, step2, dst, step, width, height, *(const double*)scale);
 }
 
-void recip64f( const double* src1, size_t step1, const double* src2, size_t step2,
+void recip64f( const double*, size_t, const double* src2, size_t step2,
                    double* dst, size_t step, int width, int height, void* scale)
 {
-    CALL_HAL(recip64f, cv_hal_recip64f, src1, step1, src2, step2, dst, step, width, height, *(const double*)scale)
-    recip_f(src1, step1, src2, step2, dst, step, width, height, *(const double*)scale);
+    CALL_HAL(recip64f, cv_hal_recip64f, src2, step2, dst, step, width, height, *(const double*)scale)
+    recip_f(src2, step2, dst, step, width, height, *(const double*)scale);
 }
 
 //=======================================
diff --git a/modules/core/src/arithm_core.hpp b/modules/core/src/arithm_core.hpp
index 4790586..99b564c 100644
--- a/modules/core/src/arithm_core.hpp
+++ b/modules/core/src/arithm_core.hpp
@@ -97,6 +97,22 @@ template<typename T> struct OpAbsDiff
     T operator()(T a, T b) const { return a > b ? a - b : b - a; }
 };
 
+// specializations to prevent "-0" results
+template<> struct OpAbsDiff<float>
+{
+    typedef float type1;
+    typedef float type2;
+    typedef float rtype;
+    float operator()(float a, float b) const { return std::abs(a - b); }
+};
+template<> struct OpAbsDiff<double>
+{
+    typedef double type1;
+    typedef double type2;
+    typedef double rtype;
+    double operator()(double a, double b) const { return std::abs(a - b); }
+};
+
 template<typename T> struct OpAnd
 {
     typedef T type1;
@@ -528,7 +544,7 @@ div_f( const T* src1, size_t step1, const T* src2, size_t step2,
 }
 
 template<typename T> static void
-recip_i( const T*, size_t, const T* src2, size_t step2,
+recip_i( const T* src2, size_t step2,
          T* dst, size_t step, int width, int height, double scale )
 {
     step2 /= sizeof(src2[0]);
@@ -549,7 +565,7 @@ recip_i( const T*, size_t, const T* src2, size_t step2,
 }
 
 template<typename T> static void
-recip_f( const T*, size_t, const T* src2, size_t step2,
+recip_f( const T* src2, size_t step2,
          T* dst, size_t step, int width, int height, double scale )
 {
     T scale_f = (T)scale;
diff --git a/modules/core/src/arithm_simd.hpp b/modules/core/src/arithm_simd.hpp
index b6a549e..7d72383 100644
--- a/modules/core/src/arithm_simd.hpp
+++ b/modules/core/src/arithm_simd.hpp
@@ -1197,7 +1197,7 @@ template <>
 struct Div_SIMD<uchar>
 {
     bool haveSIMD;
-    Div_SIMD() { haveSIMD = checkHardwareSupport(CV_CPU_SSE2) || checkHardwareSupport(CV_CPU_NEON); }
+    Div_SIMD() { haveSIMD = hasSIMD128(); }
 
     int operator() (const uchar * src1, const uchar * src2, uchar * dst, int width, double scale) const
     {
@@ -1243,7 +1243,7 @@ template <>
 struct Div_SIMD<schar>
 {
     bool haveSIMD;
-    Div_SIMD() { haveSIMD = checkHardwareSupport(CV_CPU_SSE2) || checkHardwareSupport(CV_CPU_NEON); }
+    Div_SIMD() { haveSIMD = hasSIMD128(); }
 
     int operator() (const schar * src1, const schar * src2, schar * dst, int width, double scale) const
     {
@@ -1289,7 +1289,7 @@ template <>
 struct Div_SIMD<ushort>
 {
     bool haveSIMD;
-    Div_SIMD() { haveSIMD = checkHardwareSupport(CV_CPU_SSE2) || checkHardwareSupport(CV_CPU_NEON); }
+    Div_SIMD() { haveSIMD = hasSIMD128(); }
 
     int operator() (const ushort * src1, const ushort * src2, ushort * dst, int width, double scale) const
     {
@@ -1334,7 +1334,7 @@ template <>
 struct Div_SIMD<short>
 {
     bool haveSIMD;
-    Div_SIMD() { haveSIMD = checkHardwareSupport(CV_CPU_SSE2) || checkHardwareSupport(CV_CPU_NEON); }
+    Div_SIMD() { haveSIMD = hasSIMD128(); }
 
     int operator() (const short * src1, const short * src2, short * dst, int width, double scale) const
     {
@@ -1379,7 +1379,7 @@ template <>
 struct Div_SIMD<int>
 {
     bool haveSIMD;
-    Div_SIMD() { haveSIMD = checkHardwareSupport(CV_CPU_SSE2) || checkHardwareSupport(CV_CPU_NEON); }
+    Div_SIMD() { haveSIMD = hasSIMD128(); }
 
     int operator() (const int * src1, const int * src2, int * dst, int width, double scale) const
     {
@@ -1423,7 +1423,7 @@ template <>
 struct Div_SIMD<float>
 {
     bool haveSIMD;
-    Div_SIMD() { haveSIMD = checkHardwareSupport(CV_CPU_SSE2) || checkHardwareSupport(CV_CPU_NEON); }
+    Div_SIMD() { haveSIMD = hasSIMD128(); }
 
     int operator() (const float * src1, const float * src2, float * dst, int width, double scale) const
     {
@@ -1463,7 +1463,7 @@ template <>
 struct Recip_SIMD<uchar>
 {
     bool haveSIMD;
-    Recip_SIMD() { haveSIMD = checkHardwareSupport(CV_CPU_SSE2) || checkHardwareSupport(CV_CPU_NEON); }
+    Recip_SIMD() { haveSIMD = hasSIMD128(); }
 
     int operator() (const uchar * src2, uchar * dst, int width, double scale) const
     {
@@ -1504,7 +1504,7 @@ template <>
 struct Recip_SIMD<schar>
 {
     bool haveSIMD;
-    Recip_SIMD() { haveSIMD = checkHardwareSupport(CV_CPU_SSE2) || checkHardwareSupport(CV_CPU_NEON); }
+    Recip_SIMD() { haveSIMD = hasSIMD128(); }
 
     int operator() (const schar * src2, schar * dst, int width, double scale) const
     {
@@ -1545,7 +1545,7 @@ template <>
 struct Recip_SIMD<ushort>
 {
     bool haveSIMD;
-    Recip_SIMD() { haveSIMD = checkHardwareSupport(CV_CPU_SSE2) || checkHardwareSupport(CV_CPU_NEON); }
+    Recip_SIMD() { haveSIMD = hasSIMD128(); }
 
     int operator() (const ushort * src2, ushort * dst, int width, double scale) const
     {
@@ -1585,7 +1585,7 @@ template <>
 struct Recip_SIMD<short>
 {
     bool haveSIMD;
-    Recip_SIMD() { haveSIMD = checkHardwareSupport(CV_CPU_SSE2) || checkHardwareSupport(CV_CPU_NEON); }
+    Recip_SIMD() { haveSIMD = hasSIMD128(); }
 
     int operator() (const short * src2, short * dst, int width, double scale) const
     {
@@ -1625,7 +1625,7 @@ template <>
 struct Recip_SIMD<int>
 {
     bool haveSIMD;
-    Recip_SIMD() { haveSIMD = checkHardwareSupport(CV_CPU_SSE2) || checkHardwareSupport(CV_CPU_NEON); }
+    Recip_SIMD() { haveSIMD = hasSIMD128(); }
 
     int operator() (const int * src2, int * dst, int width, double scale) const
     {
@@ -1665,7 +1665,7 @@ template <>
 struct Recip_SIMD<float>
 {
     bool haveSIMD;
-    Recip_SIMD() { haveSIMD = checkHardwareSupport(CV_CPU_SSE2) || checkHardwareSupport(CV_CPU_NEON); }
+    Recip_SIMD() { haveSIMD = hasSIMD128(); }
 
     int operator() (const float * src2, float * dst, int width, double scale) const
     {
@@ -1702,7 +1702,7 @@ template <>
 struct Div_SIMD<double>
 {
     bool haveSIMD;
-    Div_SIMD() { haveSIMD = checkHardwareSupport(CV_CPU_SSE2) || checkHardwareSupport(CV_CPU_NEON); }
+    Div_SIMD() { haveSIMD = hasSIMD128(); }
 
     int operator() (const double * src1, const double * src2, double * dst, int width, double scale) const
     {
@@ -1739,7 +1739,7 @@ template <>
 struct Recip_SIMD<double>
 {
     bool haveSIMD;
-    Recip_SIMD() { haveSIMD = checkHardwareSupport(CV_CPU_SSE2) || checkHardwareSupport(CV_CPU_NEON); }
+    Recip_SIMD() { haveSIMD = hasSIMD128(); }
 
     int operator() (const double * src2, double * dst, int width, double scale) const
     {
diff --git a/modules/core/src/array.cpp b/modules/core/src/array.cpp
index 1beb6bf..d22f9c2 100644
--- a/modules/core/src/array.cpp
+++ b/modules/core/src/array.cpp
@@ -115,12 +115,13 @@ cvCreateMatHeader( int rows, int cols, int type )
 {
     type = CV_MAT_TYPE(type);
 
-    if( rows < 0 || cols <= 0 )
+    if( rows < 0 || cols < 0 )
         CV_Error( CV_StsBadSize, "Non-positive width or height" );
 
-    int min_step = CV_ELEM_SIZE(type)*cols;
+    int min_step = CV_ELEM_SIZE(type);
     if( min_step <= 0 )
         CV_Error( CV_StsUnsupportedFormat, "Invalid matrix type" );
+    min_step *= cols;
 
     CvMat* arr = (CvMat*)cvAlloc( sizeof(*arr));
 
@@ -148,7 +149,7 @@ cvInitMatHeader( CvMat* arr, int rows, int cols,
     if( (unsigned)CV_MAT_DEPTH(type) > CV_DEPTH_MAX )
         CV_Error( CV_BadNumChannels, "" );
 
-    if( rows < 0 || cols <= 0 )
+    if( rows < 0 || cols < 0 )
         CV_Error( CV_StsBadSize, "Non-positive cols or rows" );
 
     type = CV_MAT_TYPE( type );
@@ -833,6 +834,9 @@ cvCreateData( CvArr* arr )
 
         if( !CvIPL.allocateData )
         {
+            const int64 imageSize_tmp = (int64)img->widthStep*(int64)img->height;
+            if( (int64)img->imageSize != imageSize_tmp )
+                CV_Error( CV_StsNoMem, "Overflow for imageSize" );
             img->imageData = img->imageDataOrigin =
                         (char*)cvAlloc( (size_t)img->imageSize );
         }
@@ -940,7 +944,10 @@ cvSetData( CvArr* arr, void* data, int step )
             img->widthStep = min_step;
         }
 
-        img->imageSize = img->widthStep * img->height;
+        const int64 imageSize_tmp = (int64)img->widthStep*(int64)img->height;
+        img->imageSize = (int)imageSize_tmp;
+        if( (int64)img->imageSize != imageSize_tmp )
+            CV_Error( CV_StsNoMem, "Overflow for imageSize" );
         img->imageData = img->imageDataOrigin = (char*)data;
 
         if( (((int)(size_t)data | step) & 7) == 0 &&
@@ -2957,7 +2964,10 @@ cvInitImageHeader( IplImage * image, CvSize size, int depth,
     image->widthStep = (((image->width * image->nChannels *
          (image->depth & ~IPL_DEPTH_SIGN) + 7)/8)+ align - 1) & (~(align - 1));
     image->origin = origin;
-    image->imageSize = image->widthStep * image->height;
+    const int64 imageSize_tmp = (int64)image->widthStep*(int64)image->height;
+    image->imageSize = (int)imageSize_tmp;
+    if( (int64)image->imageSize != imageSize_tmp )
+        CV_Error( CV_StsNoMem, "Overflow for imageSize" );
 
     return image;
 }
diff --git a/modules/core/src/convert.cpp b/modules/core/src/convert.cpp
index 6c693a4..e04d89e 100644
--- a/modules/core/src/convert.cpp
+++ b/modules/core/src/convert.cpp
@@ -44,12 +44,16 @@
 #include "precomp.hpp"
 
 #include "opencl_kernels_core.hpp"
+#include "opencv2/core/hal/intrin.hpp"
+
+#include "opencv2/core/openvx/ovx_defs.hpp"
 
 #ifdef __APPLE__
 #undef CV_NEON
 #define CV_NEON 0
 #endif
 
+#define CV_SPLIT_MERGE_MAX_BLOCK_SIZE(cn) ((INT_MAX/4)/cn) // HAL implementation accepts 'int' len, so INT_MAX doesn't work here
 
 /****************************************************************************************\
 *                                       split & merge                                    *
@@ -83,6 +87,8 @@ static MergeFunc getMergeFunc(int depth)
 
 void cv::split(const Mat& src, Mat* mv)
 {
+    CV_INSTRUMENT_REGION()
+
     int k, depth = src.depth(), cn = src.channels();
     if( cn == 1 )
     {
@@ -93,8 +99,8 @@ void cv::split(const Mat& src, Mat* mv)
     SplitFunc func = getSplitFunc(depth);
     CV_Assert( func != 0 );
 
-    int esz = (int)src.elemSize(), esz1 = (int)src.elemSize1();
-    int blocksize0 = (BLOCK_SIZE + esz-1)/esz;
+    size_t esz = src.elemSize(), esz1 = src.elemSize1();
+    size_t blocksize0 = (BLOCK_SIZE + esz-1)/esz;
     AutoBuffer<uchar> _buf((cn+1)*(sizeof(Mat*) + sizeof(uchar*)) + 16);
     const Mat** arrays = (const Mat**)(uchar*)_buf;
     uchar** ptrs = (uchar**)alignPtr(arrays + cn + 1, 16);
@@ -107,14 +113,15 @@ void cv::split(const Mat& src, Mat* mv)
     }
 
     NAryMatIterator it(arrays, ptrs, cn+1);
-    int total = (int)it.size, blocksize = cn <= 4 ? total : std::min(total, blocksize0);
+    size_t total = it.size;
+    size_t blocksize = std::min((size_t)CV_SPLIT_MERGE_MAX_BLOCK_SIZE(cn), cn <= 4 ? total : std::min(total, blocksize0));
 
     for( size_t i = 0; i < it.nplanes; i++, ++it )
     {
-        for( int j = 0; j < total; j += blocksize )
+        for( size_t j = 0; j < total; j += blocksize )
         {
-            int bsz = std::min(total - j, blocksize);
-            func( ptrs[0], &ptrs[1], bsz, cn );
+            size_t bsz = std::min(total - j, blocksize);
+            func( ptrs[0], &ptrs[1], (int)bsz, cn );
 
             if( j + blocksize < total )
             {
@@ -174,6 +181,8 @@ static bool ocl_split( InputArray _m, OutputArrayOfArrays _mv )
 
 void cv::split(InputArray _m, OutputArrayOfArrays _mv)
 {
+    CV_INSTRUMENT_REGION()
+
     CV_OCL_RUN(_m.dims() <= 2 && _mv.isUMatVector(),
                ocl_split(_m, _mv))
 
@@ -199,6 +208,8 @@ void cv::split(InputArray _m, OutputArrayOfArrays _mv)
 
 void cv::merge(const Mat* mv, size_t n, OutputArray _dst)
 {
+    CV_INSTRUMENT_REGION()
+
     CV_Assert( mv && n > 0 );
 
     int depth = mv[0].depth();
@@ -241,8 +252,11 @@ void cv::merge(const Mat* mv, size_t n, OutputArray _dst)
         return;
     }
 
+    MergeFunc func = getMergeFunc(depth);
+    CV_Assert( func != 0 );
+
     size_t esz = dst.elemSize(), esz1 = dst.elemSize1();
-    int blocksize0 = (int)((BLOCK_SIZE + esz-1)/esz);
+    size_t blocksize0 = (int)((BLOCK_SIZE + esz-1)/esz);
     AutoBuffer<uchar> _buf((cn+1)*(sizeof(Mat*) + sizeof(uchar*)) + 16);
     const Mat** arrays = (const Mat**)(uchar*)_buf;
     uchar** ptrs = (uchar**)alignPtr(arrays + cn + 1, 16);
@@ -252,15 +266,15 @@ void cv::merge(const Mat* mv, size_t n, OutputArray _dst)
         arrays[k+1] = &mv[k];
 
     NAryMatIterator it(arrays, ptrs, cn+1);
-    int total = (int)it.size, blocksize = cn <= 4 ? total : std::min(total, blocksize0);
-    MergeFunc func = getMergeFunc(depth);
+    size_t total = (int)it.size;
+    size_t blocksize = std::min((size_t)CV_SPLIT_MERGE_MAX_BLOCK_SIZE(cn), cn <= 4 ? total : std::min(total, blocksize0));
 
     for( i = 0; i < it.nplanes; i++, ++it )
     {
-        for( int j = 0; j < total; j += blocksize )
+        for( size_t j = 0; j < total; j += blocksize )
         {
-            int bsz = std::min(total - j, blocksize);
-            func( (const uchar**)&ptrs[1], ptrs[0], bsz, cn );
+            size_t bsz = std::min(total - j, blocksize);
+            func( (const uchar**)&ptrs[1], ptrs[0], (int)bsz, cn );
 
             if( j + blocksize < total )
             {
@@ -340,6 +354,8 @@ static bool ocl_merge( InputArrayOfArrays _mv, OutputArray _dst )
 
 void cv::merge(InputArrayOfArrays _mv, OutputArray _dst)
 {
+    CV_INSTRUMENT_REGION()
+
     CV_OCL_RUN(_mv.isUMatVector() && _dst.isUMat(),
                ocl_merge(_mv, _dst))
 
@@ -434,6 +450,8 @@ static MixChannelsFunc getMixchFunc(int depth)
 
 void cv::mixChannels( const Mat* src, size_t nsrcs, Mat* dst, size_t ndsts, const int* fromTo, size_t npairs )
 {
+    CV_INSTRUMENT_REGION()
+
     if( npairs == 0 )
         return;
     CV_Assert( src && nsrcs > 0 && dst && ndsts > 0 && fromTo && npairs > 0 );
@@ -610,6 +628,8 @@ static bool ocl_mixChannels(InputArrayOfArrays _src, InputOutputArrayOfArrays _d
 void cv::mixChannels(InputArrayOfArrays src, InputOutputArrayOfArrays dst,
                  const int* fromTo, size_t npairs)
 {
+    CV_INSTRUMENT_REGION()
+
     if (npairs == 0 || fromTo == NULL)
         return;
 
@@ -639,6 +659,8 @@ void cv::mixChannels(InputArrayOfArrays src, InputOutputArrayOfArrays dst,
 void cv::mixChannels(InputArrayOfArrays src, InputOutputArrayOfArrays dst,
                      const std::vector<int>& fromTo)
 {
+    CV_INSTRUMENT_REGION()
+
     if (fromTo.empty())
         return;
 
@@ -667,6 +689,8 @@ void cv::mixChannels(InputArrayOfArrays src, InputOutputArrayOfArrays dst,
 
 void cv::extractChannel(InputArray _src, OutputArray _dst, int coi)
 {
+    CV_INSTRUMENT_REGION()
+
     int type = _src.type(), depth = CV_MAT_DEPTH(type), cn = CV_MAT_CN(type);
     CV_Assert( 0 <= coi && coi < cn );
     int ch[] = { coi, 0 };
@@ -688,6 +712,8 @@ void cv::extractChannel(InputArray _src, OutputArray _dst, int coi)
 
 void cv::insertChannel(InputArray _src, InputOutputArray _dst, int coi)
 {
+    CV_INSTRUMENT_REGION()
+
     int stype = _src.type(), sdepth = CV_MAT_DEPTH(stype), scn = CV_MAT_CN(stype);
     int dtype = _dst.type(), ddepth = CV_MAT_DEPTH(dtype), dcn = CV_MAT_CN(dtype);
     CV_Assert( _src.sameSize(_dst) && sdepth == ddepth );
@@ -4356,10 +4382,373 @@ struct Cvt_SIMD<float, int>
 
 #endif
 
+#if !CV_FP16_TYPE
+// const numbers for floating points format
+const unsigned int kShiftSignificand    = 13;
+const unsigned int kMaskFp16Significand = 0x3ff;
+const unsigned int kBiasFp16Exponent    = 15;
+const unsigned int kBiasFp32Exponent    = 127;
+#endif
+
+#if CV_FP16_TYPE
+static float convertFp16SW(short fp16)
+{
+    // Fp16 -> Fp32
+    Cv16suf a;
+    a.i = fp16;
+    return (float)a.h;
+}
+#else
+static float convertFp16SW(short fp16)
+{
+    // Fp16 -> Fp32
+    Cv16suf b;
+    b.i = fp16;
+    int exponent    = b.fmt.exponent - kBiasFp16Exponent;
+    int significand = b.fmt.significand;
+
+    Cv32suf a;
+    a.i = 0;
+    a.fmt.sign = b.fmt.sign; // sign bit
+    if( exponent == 16 )
+    {
+        // Inf or NaN
+        a.i = a.i | 0x7F800000;
+        if( significand != 0 )
+        {
+            // NaN
+#if defined(__x86_64__) || defined(_M_X64)
+            // 64bit
+            a.i = a.i | 0x7FC00000;
+#endif
+            a.fmt.significand = a.fmt.significand | (significand << kShiftSignificand);
+        }
+        return a.f;
+    }
+    else if ( exponent == -15 )
+    {
+        // subnormal in Fp16
+        if( significand == 0 )
+        {
+            // zero
+            return a.f;
+        }
+        else
+        {
+            int shift = -1;
+            while( ( significand & 0x400 ) == 0 )
+            {
+                significand = significand << 1;
+                shift++;
+            }
+            significand = significand & kMaskFp16Significand;
+            exponent -= shift;
+        }
+    }
+
+    a.fmt.exponent = (exponent+kBiasFp32Exponent);
+    a.fmt.significand = significand << kShiftSignificand;
+    return a.f;
+}
+#endif
+
+#if CV_FP16_TYPE
+static short convertFp16SW(float fp32)
+{
+    // Fp32 -> Fp16
+    Cv16suf a;
+    a.h = (__fp16)fp32;
+    return a.i;
+}
+#else
+static short convertFp16SW(float fp32)
+{
+    // Fp32 -> Fp16
+    Cv32suf a;
+    a.f = fp32;
+    int exponent    = a.fmt.exponent - kBiasFp32Exponent;
+    int significand = a.fmt.significand;
+
+    Cv16suf result;
+    result.i = 0;
+    unsigned int absolute = a.i & 0x7fffffff;
+    if( 0x477ff000 <= absolute )
+    {
+        // Inf in Fp16
+        result.i = result.i | 0x7C00;
+        if( exponent == 128 && significand != 0 )
+        {
+            // NaN
+            result.i = (short)( result.i | 0x200 | ( significand >> kShiftSignificand ) );
+        }
+    }
+    else if ( absolute < 0x33000001 )
+    {
+        // too small for fp16
+        result.i = 0;
+    }
+    else if ( absolute < 0x33c00000 )
+    {
+        result.i = 1;
+    }
+    else if ( absolute < 0x34200001 )
+    {
+        result.i = 2;
+    }
+    else if ( absolute < 0x387fe000 )
+    {
+        // subnormal in Fp16
+        int fp16Significand = significand | 0x800000;
+        int bitShift = (-exponent) - 1;
+        fp16Significand = fp16Significand >> bitShift;
+
+        // special cases to round up
+        bitShift = exponent + 24;
+        int threshold = ( ( 0x400000 >> bitShift ) | ( ( ( significand & ( 0x800000 >> bitShift ) ) >> ( 126 - a.fmt.exponent ) ) ^ 1 ) );
+        if( threshold <= ( significand & ( 0xffffff >> ( exponent + 25 ) ) ) )
+        {
+            fp16Significand++;
+        }
+        result.i = (short)fp16Significand;
+    }
+    else
+    {
+        // usual situation
+        // exponent
+        result.fmt.exponent = ( exponent + kBiasFp16Exponent );
+
+        // significand;
+        short fp16Significand = (short)(significand >> kShiftSignificand);
+        result.fmt.significand = fp16Significand;
+
+        // special cases to round up
+        short lsb10bitsFp32 = (significand & 0x1fff);
+        short threshold = 0x1000 + ( ( fp16Significand & 0x1 ) ? 0 : 1 );
+        if( threshold <= lsb10bitsFp32 )
+        {
+            result.i++;
+        }
+        else if ( fp16Significand == 0x3ff && exponent == -15)
+        {
+            result.i++;
+        }
+    }
+
+    // sign bit
+    result.fmt.sign = a.fmt.sign;
+    return result.i;
+}
+#endif
+
+// template for FP16 HW conversion function
+template<typename T, typename DT> static void
+cvtScaleHalf_( const T* src, size_t sstep, DT* dst, size_t dstep, Size size);
+
+template<> void
+cvtScaleHalf_<float, short>( const float* src, size_t sstep, short* dst, size_t dstep, Size size)
+{
+    sstep /= sizeof(src[0]);
+    dstep /= sizeof(dst[0]);
+
+    if( checkHardwareSupport(CV_CPU_FP16) )
+    {
+        for( ; size.height--; src += sstep, dst += dstep )
+        {
+            int x = 0;
+
+#if defined(__x86_64__) || defined(_M_X64) || defined(_M_IX86) || defined(i386)
+            if ( ( (intptr_t)dst & 0xf ) == 0 )
+#endif
+            {
+#if CV_FP16 && CV_SIMD128
+                for ( ; x <= size.width - 4; x += 4)
+                {
+                    v_float32x4 v_src = v_load(src + x);
+
+                    v_float16x4 v_dst = v_cvt_f16(v_src);
+
+                    v_store_f16(dst + x, v_dst);
+                }
+#endif
+            }
+            for ( ; x < size.width; x++ )
+            {
+                dst[x] = convertFp16SW(src[x]);
+            }
+        }
+    }
+    else
+    {
+        for( ; size.height--; src += sstep, dst += dstep )
+        {
+            int x = 0;
+            for ( ; x < size.width; x++ )
+            {
+                dst[x] = convertFp16SW(src[x]);
+            }
+        }
+    }
+}
+
+template<> void
+cvtScaleHalf_<short, float>( const short* src, size_t sstep, float* dst, size_t dstep, Size size)
+{
+    sstep /= sizeof(src[0]);
+    dstep /= sizeof(dst[0]);
+
+    if( checkHardwareSupport(CV_CPU_FP16) )
+    {
+        for( ; size.height--; src += sstep, dst += dstep )
+        {
+            int x = 0;
+
+#if defined(__x86_64__) || defined(_M_X64) || defined(_M_IX86) || defined(i386)
+            if ( ( (intptr_t)src & 0xf ) == 0 )
+#endif
+            {
+#if CV_FP16 && CV_SIMD128
+                for ( ; x <= size.width - 4; x += 4)
+                {
+                    v_float16x4 v_src = v_load_f16(src + x);
+
+                    v_float32x4 v_dst = v_cvt_f32(v_src);
+
+                    v_store(dst + x, v_dst);
+                }
+#endif
+            }
+            for ( ; x < size.width; x++ )
+            {
+                dst[x] = convertFp16SW(src[x]);
+            }
+        }
+    }
+    else
+    {
+        for( ; size.height--; src += sstep, dst += dstep )
+        {
+            int x = 0;
+            for ( ; x < size.width; x++ )
+            {
+                dst[x] = convertFp16SW(src[x]);
+            }
+        }
+    }
+}
+
+#ifdef HAVE_OPENVX
+
+template<typename T, typename DT>
+static bool _openvx_cvt(const T* src, size_t sstep,
+                        DT* dst, size_t dstep, Size continuousSize)
+{
+    using namespace ivx;
+
+    if(!(continuousSize.width > 0 && continuousSize.height > 0))
+    {
+        return true;
+    }
+
+    //.height is for number of continuous pieces
+    //.width  is for length of one piece
+    Size imgSize = continuousSize;
+    if(continuousSize.height == 1)
+    {
+        if(sstep / sizeof(T) == dstep / sizeof(DT) && sstep / sizeof(T) > 0 &&
+           continuousSize.width % (sstep / sizeof(T)) == 0)
+        {
+            //continuous n-lines image
+            imgSize.width  = sstep / sizeof(T);
+            imgSize.height = continuousSize.width / (sstep / sizeof(T));
+        }
+        else
+        {
+            //1-row image with possibly incorrect step
+            sstep = continuousSize.width * sizeof(T);
+            dstep = continuousSize.width * sizeof(DT);
+        }
+    }
+
+    int srcType = DataType<T>::type, dstType = DataType<DT>::type;
+
+    try
+    {
+        Context context = Context::create();
+
+        // Other conversions are marked as "experimental"
+        if(context.vendorID() == VX_ID_KHRONOS &&
+           !(srcType == CV_8U  && dstType == CV_16S) &&
+           !(srcType == CV_16S && dstType == CV_8U))
+        {
+            return false;
+        }
+
+        Image srcImage = Image::createFromHandle(context, Image::matTypeToFormat(srcType),
+                                                 Image::createAddressing(imgSize.width, imgSize.height,
+                                                                         (vx_uint32)sizeof(T), (vx_uint32)sstep),
+                                                 (void*)src);
+        Image dstImage = Image::createFromHandle(context, Image::matTypeToFormat(dstType),
+                                                 Image::createAddressing(imgSize.width, imgSize.height,
+                                                                         (vx_uint32)sizeof(DT), (vx_uint32)dstep),
+                                                 (void*)dst);
+
+        IVX_CHECK_STATUS(vxuConvertDepth(context, srcImage, dstImage, VX_CONVERT_POLICY_SATURATE, 0));
+
+#ifdef VX_VERSION_1_1
+        //we should take user memory back before release
+        //(it's not done automatically according to standard)
+        srcImage.swapHandle(); dstImage.swapHandle();
+#endif
+    }
+    catch (RuntimeError & e)
+    {
+        VX_DbgThrow(e.what());
+    }
+    catch (WrapperError & e)
+    {
+        VX_DbgThrow(e.what());
+    }
+
+    return true;
+}
+
+template<typename T, typename DT>
+static bool openvx_cvt(const T* src, size_t sstep,
+                       DT* dst, size_t dstep, Size size)
+{
+    (void)src; (void)sstep; (void)dst; (void)dstep; (void)size;
+    return false;
+}
+
+#define DEFINE_OVX_CVT_SPECIALIZATION(T, DT) \
+template<>                                                                    \
+bool openvx_cvt(const T *src, size_t sstep, DT *dst, size_t dstep, Size size) \
+{                                                                             \
+    return _openvx_cvt<T, DT>(src, sstep, dst, dstep, size);                  \
+}
+
+DEFINE_OVX_CVT_SPECIALIZATION(uchar, ushort)
+DEFINE_OVX_CVT_SPECIALIZATION(uchar, short)
+DEFINE_OVX_CVT_SPECIALIZATION(uchar, int)
+DEFINE_OVX_CVT_SPECIALIZATION(ushort, uchar)
+DEFINE_OVX_CVT_SPECIALIZATION(ushort, int)
+DEFINE_OVX_CVT_SPECIALIZATION(short, uchar)
+DEFINE_OVX_CVT_SPECIALIZATION(short, int)
+DEFINE_OVX_CVT_SPECIALIZATION(int, uchar)
+DEFINE_OVX_CVT_SPECIALIZATION(int, ushort)
+DEFINE_OVX_CVT_SPECIALIZATION(int, short)
+
+#endif
+
 template<typename T, typename DT> static void
 cvt_( const T* src, size_t sstep,
       DT* dst, size_t dstep, Size size )
 {
+    CV_OVX_RUN(
+        true,
+        openvx_cvt(src, sstep, dst, dstep, size)
+    )
+
     sstep /= sizeof(src[0]);
     dstep /= sizeof(dst[0]);
     Cvt_SIMD<T, DT> vop;
@@ -4443,6 +4832,13 @@ static void cvtScaleAbs##suffix( const stype* src, size_t sstep, const uchar*, s
     tfunc(src, sstep, dst, dstep, size, (wtype)scale[0], (wtype)scale[1]); \
 }
 
+#define DEF_CVT_SCALE_FP16_FUNC(suffix, stype, dtype) \
+static void cvtScaleHalf##suffix( const stype* src, size_t sstep, const uchar*, size_t, \
+dtype* dst, size_t dstep, Size size, double*) \
+{ \
+    cvtScaleHalf_<stype,dtype>(src, sstep, dst, dstep, size); \
+}
+
 #define DEF_CVT_SCALE_FUNC(suffix, stype, dtype, wtype) \
 static void cvtScale##suffix( const stype* src, size_t sstep, const uchar*, size_t, \
 dtype* dst, size_t dstep, Size size, double* scale) \
@@ -4455,7 +4851,7 @@ dtype* dst, size_t dstep, Size size, double* scale) \
 static void cvt##suffix( const stype* src, size_t sstep, const uchar*, size_t, \
                          dtype* dst, size_t dstep, Size size, double*) \
 { \
-    CV_IPP_RUN(src && dst, ippiConvert_##ippFavor(src, (int)sstep, dst, (int)dstep, ippiSize(size.width, size.height)) >= 0)\
+    CV_IPP_RUN(src && dst, CV_INSTRUMENT_FUN_IPP(ippiConvert_##ippFavor, src, (int)sstep, dst, (int)dstep, ippiSize(size.width, size.height)) >= 0) \
     cvt_(src, sstep, dst, dstep, size); \
 }
 
@@ -4463,7 +4859,7 @@ static void cvt##suffix( const stype* src, size_t sstep, const uchar*, size_t, \
 static void cvt##suffix( const stype* src, size_t sstep, const uchar*, size_t, \
                          dtype* dst, size_t dstep, Size size, double*) \
 { \
-    CV_IPP_RUN(src && dst, ippiConvert_##ippFavor(src, (int)sstep, dst, (int)dstep, ippiSize(size.width, size.height), ippRndFinancial, 0) >= 0)\
+    CV_IPP_RUN(src && dst, CV_INSTRUMENT_FUN_IPP(ippiConvert_##ippFavor, src, (int)sstep, dst, (int)dstep, ippiSize(size.width, size.height), ippRndFinancial, 0) >= 0) \
     cvt_(src, sstep, dst, dstep, size); \
 }
 #else
@@ -4499,6 +4895,9 @@ DEF_CVT_SCALE_ABS_FUNC(32s8u, cvtScaleAbs_, int, uchar, float)
 DEF_CVT_SCALE_ABS_FUNC(32f8u, cvtScaleAbs_, float, uchar, float)
 DEF_CVT_SCALE_ABS_FUNC(64f8u, cvtScaleAbs_, double, uchar, float)
 
+DEF_CVT_SCALE_FP16_FUNC(32f16f, float, short)
+DEF_CVT_SCALE_FP16_FUNC(16f32f, short, float)
+
 DEF_CVT_SCALE_FUNC(8u,     uchar, uchar, float)
 DEF_CVT_SCALE_FUNC(8s8u,   schar, uchar, float)
 DEF_CVT_SCALE_FUNC(16u8u,  ushort, uchar, float)
@@ -4620,6 +5019,17 @@ static BinaryFunc getCvtScaleAbsFunc(int depth)
     return cvtScaleAbsTab[depth];
 }
 
+BinaryFunc getConvertFuncFp16(int ddepth)
+{
+    static BinaryFunc cvtTab[] =
+    {
+        0, 0, 0,
+        (BinaryFunc)(cvtScaleHalf32f16f), 0, (BinaryFunc)(cvtScaleHalf16f32f),
+        0, 0,
+    };
+    return cvtTab[CV_MAT_DEPTH(ddepth)];
+}
+
 BinaryFunc getConvertFunc(int sdepth, int ddepth)
 {
     static BinaryFunc cvtTab[][8] =
@@ -4776,6 +5186,8 @@ static bool ocl_convertScaleAbs( InputArray _src, OutputArray _dst, double alpha
 
 void cv::convertScaleAbs( InputArray _src, OutputArray _dst, double alpha, double beta )
 {
+    CV_INSTRUMENT_REGION()
+
     CV_OCL_RUN(_src.dims() <= 2 && _dst.isUMat(),
                ocl_convertScaleAbs(_src, _dst, alpha, beta))
 
@@ -4804,8 +5216,54 @@ void cv::convertScaleAbs( InputArray _src, OutputArray _dst, double alpha, doubl
     }
 }
 
+void cv::convertFp16( InputArray _src, OutputArray _dst)
+{
+    CV_INSTRUMENT_REGION()
+
+    Mat src = _src.getMat();
+    int ddepth = 0;
+
+    switch( src.depth() )
+    {
+    case CV_32F:
+        ddepth = CV_16S;
+        break;
+    case CV_16S:
+        ddepth = CV_32F;
+        break;
+    default:
+        CV_Error(Error::StsUnsupportedFormat, "Unsupported input depth");
+        return;
+    }
+
+    int type = CV_MAKETYPE(ddepth, src.channels());
+    _dst.create( src.dims, src.size, type );
+    Mat dst = _dst.getMat();
+    BinaryFunc func = getConvertFuncFp16(ddepth);
+    int cn = src.channels();
+    CV_Assert( func != 0 );
+
+    if( src.dims <= 2 )
+    {
+        Size sz = getContinuousSize(src, dst, cn);
+        func( src.data, src.step, 0, 0, dst.data, dst.step, sz, 0);
+    }
+    else
+    {
+        const Mat* arrays[] = {&src, &dst, 0};
+        uchar* ptrs[2];
+        NAryMatIterator it(arrays, ptrs);
+        Size sz((int)(it.size*cn), 1);
+
+        for( size_t i = 0; i < it.nplanes; i++, ++it )
+            func(ptrs[0], 1, 0, 0, ptrs[1], 1, sz, 0);
+    }
+}
+
 void cv::Mat::convertTo(OutputArray _dst, int _type, double alpha, double beta) const
 {
+    CV_INSTRUMENT_REGION()
+
     bool noScale = fabs(alpha-1) < DBL_EPSILON && fabs(beta) < DBL_EPSILON;
 
     if( _type < 0 )
@@ -4940,6 +5398,39 @@ static bool ocl_LUT(InputArray _src, InputArray _lut, OutputArray _dst)
 
 #endif
 
+#ifdef HAVE_OPENVX
+static bool openvx_LUT(Mat src, Mat dst, Mat _lut)
+{
+    if (src.type() != CV_8UC1 || dst.type() != src.type() || _lut.type() != src.type() || !_lut.isContinuous())
+        return false;
+
+    try
+    {
+        ivx::Context ctx = ivx::Context::create();
+
+        ivx::Image
+            ia = ivx::Image::createFromHandle(ctx, VX_DF_IMAGE_U8,
+                ivx::Image::createAddressing(src.cols, src.rows, 1, (vx_int32)(src.step)), src.data),
+            ib = ivx::Image::createFromHandle(ctx, VX_DF_IMAGE_U8,
+                ivx::Image::createAddressing(dst.cols, dst.rows, 1, (vx_int32)(dst.step)), dst.data);
+
+        ivx::LUT lut = ivx::LUT::create(ctx);
+        lut.copyFrom(_lut);
+        ivx::IVX_CHECK_STATUS(vxuTableLookup(ctx, ia, lut, ib));
+    }
+    catch (ivx::RuntimeError & e)
+    {
+        VX_DbgThrow(e.what());
+    }
+    catch (ivx::WrapperError & e)
+    {
+        VX_DbgThrow(e.what());
+    }
+
+    return true;
+}
+#endif
+
 #if defined(HAVE_IPP)
 namespace ipp {
 
@@ -5030,7 +5521,7 @@ public:
         CV_DbgAssert(lutcn == 3 || lutcn == 4);
         if (lutcn == 3)
         {
-            IppStatus status = ippiCopy_8u_C3P3R(lut.ptr(), (int)lut.step[0], lutTable, (int)lut.step[0], sz256);
+            IppStatus status = CV_INSTRUMENT_FUN_IPP(ippiCopy_8u_C3P3R, lut.ptr(), (int)lut.step[0], lutTable, (int)lut.step[0], sz256);
             if (status < 0)
             {
                 setIppErrorStatus();
@@ -5040,7 +5531,7 @@ public:
         }
         else if (lutcn == 4)
         {
-            IppStatus status = ippiCopy_8u_C4P4R(lut.ptr(), (int)lut.step[0], lutTable, (int)lut.step[0], sz256);
+            IppStatus status = CV_INSTRUMENT_FUN_IPP(ippiCopy_8u_C4P4R, lut.ptr(), (int)lut.step[0], lutTable, (int)lut.step[0], sz256);
             if (status < 0)
             {
                 setIppErrorStatus();
@@ -5073,7 +5564,7 @@ public:
 
         if (lutcn == 3)
         {
-            if (ippiLUTPalette_8u_C3R(
+            if (CV_INSTRUMENT_FUN_IPP(ippiLUTPalette_8u_C3R,
                     src.ptr(), (int)src.step[0], dst.ptr(), (int)dst.step[0],
                     ippiSize(dst.size()), lutTable, 8) >= 0)
             {
@@ -5083,7 +5574,7 @@ public:
         }
         else if (lutcn == 4)
         {
-            if (ippiLUTPalette_8u_C4R(
+            if (CV_INSTRUMENT_FUN_IPP(ippiLUTPalette_8u_C4R,
                     src.ptr(), (int)src.step[0], dst.ptr(), (int)dst.step[0],
                     ippiSize(dst.size()), lutTable, 8) >= 0)
             {
@@ -5102,6 +5593,8 @@ private:
 
 static bool ipp_lut(Mat &src, Mat &lut, Mat &dst)
 {
+    CV_INSTRUMENT_REGION_IPP()
+
     int lutcn = lut.channels();
 
     if(src.dims > 2)
@@ -5187,6 +5680,8 @@ private:
 
 void cv::LUT( InputArray _src, InputArray _lut, OutputArray _dst )
 {
+    CV_INSTRUMENT_REGION()
+
     int cn = _src.channels(), depth = _src.depth();
     int lutcn = _lut.channels();
 
@@ -5201,6 +5696,9 @@ void cv::LUT( InputArray _src, InputArray _lut, OutputArray _dst )
     _dst.create(src.dims, src.size, CV_MAKETYPE(_lut.depth(), cn));
     Mat dst = _dst.getMat();
 
+    CV_OVX_RUN(true,
+               openvx_LUT(src, dst, lut))
+
     CV_IPP_RUN(_src.dims() <= 2, ipp_lut(src, lut, dst));
 
     if (_src.dims() <= 2)
@@ -5334,12 +5832,14 @@ static bool ocl_normalize( InputArray _src, InputOutputArray _dst, InputArray _m
 void cv::normalize( InputArray _src, InputOutputArray _dst, double a, double b,
                     int norm_type, int rtype, InputArray _mask )
 {
+    CV_INSTRUMENT_REGION()
+
     double scale = 1, shift = 0;
     if( norm_type == CV_MINMAX )
     {
         double smin = 0, smax = 0;
         double dmin = MIN( a, b ), dmax = MAX( a, b );
-        minMaxLoc( _src, &smin, &smax, 0, 0, _mask );
+        minMaxIdx( _src, &smin, &smax, 0, 0, _mask );
         scale = (dmax - dmin)*(smax - smin > DBL_EPSILON ? 1./(smax - smin) : 0);
         shift = dmin - smin*scale;
     }
@@ -5352,22 +5852,21 @@ void cv::normalize( InputArray _src, InputOutputArray _dst, double a, double b,
     else
         CV_Error( CV_StsBadArg, "Unknown/unsupported norm type" );
 
-    int type = _src.type(), depth = CV_MAT_DEPTH(type), cn = CV_MAT_CN(type);
+    int type = _src.type(), depth = CV_MAT_DEPTH(type);
     if( rtype < 0 )
         rtype = _dst.fixedType() ? _dst.depth() : depth;
-    _dst.createSameSize(_src, CV_MAKETYPE(rtype, cn));
 
     CV_OCL_RUN(_dst.isUMat(),
                ocl_normalize(_src, _dst, _mask, rtype, scale, shift))
 
-    Mat src = _src.getMat(), dst = _dst.getMat();
+    Mat src = _src.getMat();
     if( _mask.empty() )
-        src.convertTo( dst, rtype, scale, shift );
+        src.convertTo( _dst, rtype, scale, shift );
     else
     {
         Mat temp;
         src.convertTo( temp, rtype, scale, shift );
-        temp.copyTo( dst, _mask );
+        temp.copyTo( _dst, _mask );
     }
 }
 
diff --git a/modules/core/src/copy.cpp b/modules/core/src/copy.cpp
index 67bf153..1dd56f3 100644
--- a/modules/core/src/copy.cpp
+++ b/modules/core/src/copy.cpp
@@ -82,7 +82,7 @@ copyMask_(const uchar* _src, size_t sstep, const uchar* mask, size_t mstep, ucha
 template<> void
 copyMask_<uchar>(const uchar* _src, size_t sstep, const uchar* mask, size_t mstep, uchar* _dst, size_t dstep, Size size)
 {
-    CV_IPP_RUN(true, ippiCopy_8u_C1MR(_src, (int)sstep, _dst, (int)dstep, ippiSize(size), mask, (int)mstep) >= 0)
+    CV_IPP_RUN_FAST(CV_INSTRUMENT_FUN_IPP(ippiCopy_8u_C1MR, _src, (int)sstep, _dst, (int)dstep, ippiSize(size), mask, (int)mstep) >= 0)
 
     for( ; size.height--; mask += mstep, _src += sstep, _dst += dstep )
     {
@@ -122,7 +122,7 @@ copyMask_<uchar>(const uchar* _src, size_t sstep, const uchar* mask, size_t mste
 template<> void
 copyMask_<ushort>(const uchar* _src, size_t sstep, const uchar* mask, size_t mstep, uchar* _dst, size_t dstep, Size size)
 {
-    CV_IPP_RUN(true, ippiCopy_16u_C1MR((const Ipp16u *)_src, (int)sstep, (Ipp16u *)_dst, (int)dstep, ippiSize(size), mask, (int)mstep) >= 0)
+    CV_IPP_RUN_FAST(CV_INSTRUMENT_FUN_IPP(ippiCopy_16u_C1MR, (const Ipp16u *)_src, (int)sstep, (Ipp16u *)_dst, (int)dstep, ippiSize(size), mask, (int)mstep) >= 0)
 
     for( ; size.height--; mask += mstep, _src += sstep, _dst += dstep )
     {
@@ -194,7 +194,7 @@ static void copyMask##suffix(const uchar* src, size_t sstep, const uchar* mask,
 static void copyMask##suffix(const uchar* src, size_t sstep, const uchar* mask, size_t mstep, \
                              uchar* dst, size_t dstep, Size size, void*) \
 { \
-    CV_IPP_RUN(true, ippiCopy_##ippfavor((const ipptype *)src, (int)sstep, (ipptype *)dst, (int)dstep, ippiSize(size), (const Ipp8u *)mask, (int)mstep) >= 0)\
+    CV_IPP_RUN_FAST(CV_INSTRUMENT_FUN_IPP(ippiCopy_##ippfavor, (const ipptype *)src, (int)sstep, (ipptype *)dst, (int)dstep, ippiSize(size), (const Ipp8u *)mask, (int)mstep) >= 0)\
     copyMask_<type>(src, sstep, mask, mstep, dst, dstep, size); \
 }
 #else
@@ -251,6 +251,8 @@ BinaryFunc getCopyMaskFunc(size_t esz)
 /* dst = src */
 void Mat::copyTo( OutputArray _dst ) const
 {
+    CV_INSTRUMENT_REGION()
+
     int dtype = _dst.type();
     if( _dst.fixedType() && dtype != type() )
     {
@@ -259,14 +261,13 @@ void Mat::copyTo( OutputArray _dst ) const
         return;
     }
 
-    if( empty() )
-    {
-        _dst.release();
-        return;
-    }
-
     if( _dst.isUMat() )
     {
+        if( empty() )
+        {
+            _dst.release();
+            return;
+        }
         _dst.create( dims, size.p, type() );
         UMat dst = _dst.getUMat();
 
@@ -302,7 +303,7 @@ void Mat::copyTo( OutputArray _dst ) const
                     (size_t)step <= (size_t)INT_MAX &&
                     (size_t)dst.step <= (size_t)INT_MAX
                     ,
-                    ippiCopy_8u_C1R(sptr, (int)step, dptr, (int)dst.step, ippiSize((int)(cols*elemSize()), rows)) >= 0
+                    CV_INSTRUMENT_FUN_IPP(ippiCopy_8u_C1R, sptr, (int)step, dptr, (int)dst.step, ippiSize((int)(cols*elemSize()), rows)) >= 0
             )
 
             Size sz = getContinuousSize(*this, dst);
@@ -333,6 +334,8 @@ void Mat::copyTo( OutputArray _dst ) const
 
 void Mat::copyTo( OutputArray _dst, InputArray _mask ) const
 {
+    CV_INSTRUMENT_REGION()
+
     Mat mask = _mask.getMat();
     if( !mask.data )
     {
@@ -373,6 +376,8 @@ void Mat::copyTo( OutputArray _dst, InputArray _mask ) const
 
 Mat& Mat::operator = (const Scalar& s)
 {
+    CV_INSTRUMENT_REGION()
+
     const Mat* arrays[] = { this };
     uchar* dptr;
     NAryMatIterator it(arrays, &dptr, 1);
@@ -381,7 +386,7 @@ Mat& Mat::operator = (const Scalar& s)
 
     if( is[0] == 0 && is[1] == 0 && is[2] == 0 && is[3] == 0 )
     {
-#if defined HAVE_IPP && !defined HAVE_IPP_ICV_ONLY && IPP_DISABLE_BLOCK
+#if defined HAVE_IPP && IPP_DISABLE_BLOCK
         CV_IPP_CHECK()
         {
             if (dims <= 2 || isContinuous())
@@ -441,6 +446,8 @@ Mat& Mat::operator = (const Scalar& s)
 #if defined HAVE_IPP
 static bool ipp_Mat_setTo(Mat *src, Mat &value, Mat &mask)
 {
+    CV_INSTRUMENT_REGION_IPP()
+
     int cn = src->channels(), depth0 = src->depth();
 
     if (!mask.empty() && (src->dims <= 2 || (src->isContinuous() && mask.isContinuous())) &&
@@ -466,13 +473,13 @@ static bool ipp_Mat_setTo(Mat *src, Mat &value, Mat &mask)
             /*if (depth0 == CV_8U)
                 status = ippiSet_8u_C1MR(*(Ipp8u *)buf, (Ipp8u *)data, dstep, roisize, mask.data, mstep);
             else*/ if (depth0 == CV_16U)
-                status = ippiSet_16u_C1MR(*(Ipp16u *)buf, (Ipp16u *)src->data, dstep, roisize, mask.data, mstep);
+                status = CV_INSTRUMENT_FUN_IPP(ippiSet_16u_C1MR, *(Ipp16u *)buf, (Ipp16u *)src->data, dstep, roisize, mask.data, mstep);
             else if (depth0 == CV_16S)
-                status = ippiSet_16s_C1MR(*(Ipp16s *)buf, (Ipp16s *)src->data, dstep, roisize, mask.data, mstep);
+                status = CV_INSTRUMENT_FUN_IPP(ippiSet_16s_C1MR, *(Ipp16s *)buf, (Ipp16s *)src->data, dstep, roisize, mask.data, mstep);
             else if (depth0 == CV_32S)
-                status = ippiSet_32s_C1MR(*(Ipp32s *)buf, (Ipp32s *)src->data, dstep, roisize, mask.data, mstep);
+                status = CV_INSTRUMENT_FUN_IPP(ippiSet_32s_C1MR, *(Ipp32s *)buf, (Ipp32s *)src->data, dstep, roisize, mask.data, mstep);
             else if (depth0 == CV_32F)
-                status = ippiSet_32f_C1MR(*(Ipp32f *)buf, (Ipp32f *)src->data, dstep, roisize, mask.data, mstep);
+                status = CV_INSTRUMENT_FUN_IPP(ippiSet_32f_C1MR, *(Ipp32f *)buf, (Ipp32f *)src->data, dstep, roisize, mask.data, mstep);
         }
         else if (cn == 3 || cn == 4)
         {
@@ -482,7 +489,7 @@ static bool ipp_Mat_setTo(Mat *src, Mat &value, Mat &mask)
             { \
                 typedef Ipp##ippfavor ipptype; \
                 ipptype ippvalue[4] = { ((ipptype *)buf)[0], ((ipptype *)buf)[1], ((ipptype *)buf)[2], ((ipptype *)buf)[3] }; \
-                status = ippiSet_##ippfavor##_C##ippcn##MR(ippvalue, (ipptype *)src->data, dstep, roisize, mask.data, mstep); \
+                status = CV_INSTRUMENT_FUN_IPP(ippiSet_##ippfavor##_C##ippcn##MR, ippvalue, (ipptype *)src->data, dstep, roisize, mask.data, mstep); \
             } while ((void)0, 0)
 
 #define IPP_SET_CN(ippcn) \
@@ -521,6 +528,8 @@ static bool ipp_Mat_setTo(Mat *src, Mat &value, Mat &mask)
 
 Mat& Mat::setTo(InputArray _value, InputArray _mask)
 {
+    CV_INSTRUMENT_REGION()
+
     if( empty() )
         return *this;
 
@@ -529,7 +538,7 @@ Mat& Mat::setTo(InputArray _value, InputArray _mask)
     CV_Assert( checkScalar(value, type(), _value.kind(), _InputArray::MAT ));
     CV_Assert( mask.empty() || (mask.type() == CV_8U && size == mask.size) );
 
-    CV_IPP_RUN(true, ipp_Mat_setTo((cv::Mat*)this, value, mask), *this)
+    CV_IPP_RUN_FAST(ipp_Mat_setTo((cv::Mat*)this, value, mask), *this)
 
     size_t esz = elemSize();
     BinaryFunc copymask = getCopyMaskFunc(esz);
@@ -706,65 +715,67 @@ static bool ocl_flip(InputArray _src, OutputArray _dst, int flipCode )
 #if defined HAVE_IPP
 static bool ipp_flip( Mat &src, Mat &dst, int flip_mode )
 {
+    CV_INSTRUMENT_REGION_IPP()
+
     int type = src.type();
 
-    typedef IppStatus (CV_STDCALL * ippiMirror)(const void * pSrc, int srcStep, void * pDst, int dstStep, IppiSize roiSize, IppiAxis flip);
-    typedef IppStatus (CV_STDCALL * ippiMirrorI)(const void * pSrcDst, int srcDstStep, IppiSize roiSize, IppiAxis flip);
-    ippiMirror ippFunc = 0;
-    ippiMirrorI ippFuncI = 0;
+    typedef IppStatus (CV_STDCALL * IppiMirror)(const void * pSrc, int srcStep, void * pDst, int dstStep, IppiSize roiSize, IppiAxis flip);
+    typedef IppStatus (CV_STDCALL * IppiMirrorI)(const void * pSrcDst, int srcDstStep, IppiSize roiSize, IppiAxis flip);
+    IppiMirror ippiMirror = 0;
+    IppiMirrorI ippiMirror_I = 0;
 
     if (src.data == dst.data)
     {
         CV_SUPPRESS_DEPRECATED_START
-        ippFuncI =
-            type == CV_8UC1 ? (ippiMirrorI)ippiMirror_8u_C1IR :
-            type == CV_8UC3 ? (ippiMirrorI)ippiMirror_8u_C3IR :
-            type == CV_8UC4 ? (ippiMirrorI)ippiMirror_8u_C4IR :
-            type == CV_16UC1 ? (ippiMirrorI)ippiMirror_16u_C1IR :
-            type == CV_16UC3 ? (ippiMirrorI)ippiMirror_16u_C3IR :
-            type == CV_16UC4 ? (ippiMirrorI)ippiMirror_16u_C4IR :
-            type == CV_16SC1 ? (ippiMirrorI)ippiMirror_16s_C1IR :
-            type == CV_16SC3 ? (ippiMirrorI)ippiMirror_16s_C3IR :
-            type == CV_16SC4 ? (ippiMirrorI)ippiMirror_16s_C4IR :
-            type == CV_32SC1 ? (ippiMirrorI)ippiMirror_32s_C1IR :
-            type == CV_32SC3 ? (ippiMirrorI)ippiMirror_32s_C3IR :
-            type == CV_32SC4 ? (ippiMirrorI)ippiMirror_32s_C4IR :
-            type == CV_32FC1 ? (ippiMirrorI)ippiMirror_32f_C1IR :
-            type == CV_32FC3 ? (ippiMirrorI)ippiMirror_32f_C3IR :
-            type == CV_32FC4 ? (ippiMirrorI)ippiMirror_32f_C4IR : 0;
+        ippiMirror_I =
+            type == CV_8UC1 ? (IppiMirrorI)ippiMirror_8u_C1IR :
+            type == CV_8UC3 ? (IppiMirrorI)ippiMirror_8u_C3IR :
+            type == CV_8UC4 ? (IppiMirrorI)ippiMirror_8u_C4IR :
+            type == CV_16UC1 ? (IppiMirrorI)ippiMirror_16u_C1IR :
+            type == CV_16UC3 ? (IppiMirrorI)ippiMirror_16u_C3IR :
+            type == CV_16UC4 ? (IppiMirrorI)ippiMirror_16u_C4IR :
+            type == CV_16SC1 ? (IppiMirrorI)ippiMirror_16s_C1IR :
+            type == CV_16SC3 ? (IppiMirrorI)ippiMirror_16s_C3IR :
+            type == CV_16SC4 ? (IppiMirrorI)ippiMirror_16s_C4IR :
+            type == CV_32SC1 ? (IppiMirrorI)ippiMirror_32s_C1IR :
+            type == CV_32SC3 ? (IppiMirrorI)ippiMirror_32s_C3IR :
+            type == CV_32SC4 ? (IppiMirrorI)ippiMirror_32s_C4IR :
+            type == CV_32FC1 ? (IppiMirrorI)ippiMirror_32f_C1IR :
+            type == CV_32FC3 ? (IppiMirrorI)ippiMirror_32f_C3IR :
+            type == CV_32FC4 ? (IppiMirrorI)ippiMirror_32f_C4IR : 0;
         CV_SUPPRESS_DEPRECATED_END
     }
     else
     {
-        ippFunc =
-            type == CV_8UC1 ? (ippiMirror)ippiMirror_8u_C1R :
-            type == CV_8UC3 ? (ippiMirror)ippiMirror_8u_C3R :
-            type == CV_8UC4 ? (ippiMirror)ippiMirror_8u_C4R :
-            type == CV_16UC1 ? (ippiMirror)ippiMirror_16u_C1R :
-            type == CV_16UC3 ? (ippiMirror)ippiMirror_16u_C3R :
-            type == CV_16UC4 ? (ippiMirror)ippiMirror_16u_C4R :
-            type == CV_16SC1 ? (ippiMirror)ippiMirror_16s_C1R :
-            type == CV_16SC3 ? (ippiMirror)ippiMirror_16s_C3R :
-            type == CV_16SC4 ? (ippiMirror)ippiMirror_16s_C4R :
-            type == CV_32SC1 ? (ippiMirror)ippiMirror_32s_C1R :
-            type == CV_32SC3 ? (ippiMirror)ippiMirror_32s_C3R :
-            type == CV_32SC4 ? (ippiMirror)ippiMirror_32s_C4R :
-            type == CV_32FC1 ? (ippiMirror)ippiMirror_32f_C1R :
-            type == CV_32FC3 ? (ippiMirror)ippiMirror_32f_C3R :
-            type == CV_32FC4 ? (ippiMirror)ippiMirror_32f_C4R : 0;
+        ippiMirror =
+            type == CV_8UC1 ? (IppiMirror)ippiMirror_8u_C1R :
+            type == CV_8UC3 ? (IppiMirror)ippiMirror_8u_C3R :
+            type == CV_8UC4 ? (IppiMirror)ippiMirror_8u_C4R :
+            type == CV_16UC1 ? (IppiMirror)ippiMirror_16u_C1R :
+            type == CV_16UC3 ? (IppiMirror)ippiMirror_16u_C3R :
+            type == CV_16UC4 ? (IppiMirror)ippiMirror_16u_C4R :
+            type == CV_16SC1 ? (IppiMirror)ippiMirror_16s_C1R :
+            type == CV_16SC3 ? (IppiMirror)ippiMirror_16s_C3R :
+            type == CV_16SC4 ? (IppiMirror)ippiMirror_16s_C4R :
+            type == CV_32SC1 ? (IppiMirror)ippiMirror_32s_C1R :
+            type == CV_32SC3 ? (IppiMirror)ippiMirror_32s_C3R :
+            type == CV_32SC4 ? (IppiMirror)ippiMirror_32s_C4R :
+            type == CV_32FC1 ? (IppiMirror)ippiMirror_32f_C1R :
+            type == CV_32FC3 ? (IppiMirror)ippiMirror_32f_C3R :
+            type == CV_32FC4 ? (IppiMirror)ippiMirror_32f_C4R : 0;
     }
     IppiAxis axis = flip_mode == 0 ? ippAxsHorizontal :
         flip_mode > 0 ? ippAxsVertical : ippAxsBoth;
     IppiSize roisize = { dst.cols, dst.rows };
 
-    if (ippFunc != 0)
+    if (ippiMirror != 0)
     {
-        if (ippFunc(src.ptr(), (int)src.step, dst.ptr(), (int)dst.step, ippiSize(src.cols, src.rows), axis) >= 0)
+        if (CV_INSTRUMENT_FUN_IPP(ippiMirror, src.ptr(), (int)src.step, dst.ptr(), (int)dst.step, ippiSize(src.cols, src.rows), axis) >= 0)
             return true;
     }
-    else if (ippFuncI != 0)
+    else if (ippiMirror_I != 0)
     {
-        if (ippFuncI(dst.ptr(), (int)dst.step, roisize, axis) >= 0)
+        if (CV_INSTRUMENT_FUN_IPP(ippiMirror_I, dst.ptr(), (int)dst.step, roisize, axis) >= 0)
             return true;
     }
 
@@ -775,6 +786,8 @@ static bool ipp_flip( Mat &src, Mat &dst, int flip_mode )
 
 void flip( InputArray _src, OutputArray _dst, int flip_mode )
 {
+    CV_INSTRUMENT_REGION()
+
     CV_Assert( _src.dims() <= 2 );
     Size size = _src.size();
 
@@ -800,7 +813,7 @@ void flip( InputArray _src, OutputArray _dst, int flip_mode )
     _dst.create( size, type );
     Mat dst = _dst.getMat();
 
-    CV_IPP_RUN(true, ipp_flip(src, dst, flip_mode));
+    CV_IPP_RUN_FAST(ipp_flip(src, dst, flip_mode));
 
     size_t esz = CV_ELEM_SIZE(type);
 
@@ -813,6 +826,54 @@ void flip( InputArray _src, OutputArray _dst, int flip_mode )
         flipHoriz( dst.ptr(), dst.step, dst.ptr(), dst.step, dst.size(), esz );
 }
 
+#ifdef HAVE_OPENCL
+
+static bool ocl_rotate(InputArray _src, OutputArray _dst, int rotateMode)
+{
+    switch (rotateMode)
+    {
+    case ROTATE_90_CLOCKWISE:
+        transpose(_src, _dst);
+        flip(_dst, _dst, 1);
+        break;
+    case ROTATE_180:
+        flip(_src, _dst, -1);
+        break;
+    case ROTATE_90_COUNTERCLOCKWISE:
+        transpose(_src, _dst);
+        flip(_dst, _dst, 0);
+        break;
+    default:
+        break;
+    }
+    return true;
+}
+#endif
+
+void rotate(InputArray _src, OutputArray _dst, int rotateMode)
+{
+    CV_Assert(_src.dims() <= 2);
+
+    CV_OCL_RUN(_dst.isUMat(), ocl_rotate(_src, _dst, rotateMode))
+
+    switch (rotateMode)
+    {
+    case ROTATE_90_CLOCKWISE:
+        transpose(_src, _dst);
+        flip(_dst, _dst, 1);
+        break;
+    case ROTATE_180:
+        flip(_src, _dst, -1);
+        break;
+    case ROTATE_90_COUNTERCLOCKWISE:
+        transpose(_src, _dst);
+        flip(_dst, _dst, 0);
+        break;
+    default:
+        break;
+    }
+}
+
 #if defined HAVE_OPENCL && !defined __APPLE__
 
 static bool ocl_repeat(InputArray _src, int ny, int nx, OutputArray _dst)
@@ -845,6 +906,8 @@ static bool ocl_repeat(InputArray _src, int ny, int nx, OutputArray _dst)
 
 void repeat(InputArray _src, int ny, int nx, OutputArray _dst)
 {
+    CV_INSTRUMENT_REGION()
+
     CV_Assert( _src.dims() <= 2 );
     CV_Assert( ny > 0 && nx > 0 );
 
@@ -896,6 +959,8 @@ Mat repeat(const Mat& src, int ny, int nx)
  */
 int cv::borderInterpolate( int p, int len, int borderType )
 {
+    CV_INSTRUMENT_REGION()
+
     if( (unsigned)p < (unsigned)len )
         ;
     else if( borderType == BORDER_REPLICATE )
@@ -1125,6 +1190,8 @@ static bool ocl_copyMakeBorder( InputArray _src, OutputArray _dst, int top, int
 void cv::copyMakeBorder( InputArray _src, OutputArray _dst, int top, int bottom,
                          int left, int right, int borderType, const Scalar& value )
 {
+    CV_INSTRUMENT_REGION()
+
     CV_Assert( top >= 0 && bottom >= 0 && left >= 0 && right >= 0 );
 
     CV_OCL_RUN(_dst.isUMat() && _src.dims() <= 2,
diff --git a/modules/core/src/cuda/gpu_mat.cu b/modules/core/src/cuda/gpu_mat.cu
index f21c5f4..987de9e 100644
--- a/modules/core/src/cuda/gpu_mat.cu
+++ b/modules/core/src/cuda/gpu_mat.cu
@@ -50,11 +50,56 @@
 
 #include "opencv2/core/cuda.hpp"
 #include "opencv2/cudev.hpp"
+#include "opencv2/core/cuda/utility.hpp"
 
 using namespace cv;
 using namespace cv::cuda;
 using namespace cv::cudev;
 
+device::ThrustAllocator::~ThrustAllocator()
+{
+}
+namespace
+{
+    class DefaultThrustAllocator: public cv::cuda::device::ThrustAllocator
+    {
+    public:
+        __device__ __host__ uchar* allocate(size_t numBytes)
+        {
+#ifndef __CUDA_ARCH__
+            uchar* ptr;
+            CV_CUDEV_SAFE_CALL(cudaMalloc(&ptr, numBytes));
+            return ptr;
+#else
+            return NULL;
+#endif
+        }
+        __device__ __host__ void deallocate(uchar* ptr, size_t numBytes)
+        {
+            (void)numBytes;
+#ifndef __CUDA_ARCH__
+            CV_CUDEV_SAFE_CALL(cudaFree(ptr));
+#endif
+        }
+    };
+    DefaultThrustAllocator defaultThrustAllocator;
+    cv::cuda::device::ThrustAllocator* g_thrustAllocator = &defaultThrustAllocator;
+}
+
+
+cv::cuda::device::ThrustAllocator& cv::cuda::device::ThrustAllocator::getAllocator()
+{
+    return *g_thrustAllocator;
+}
+
+void cv::cuda::device::ThrustAllocator::setAllocator(cv::cuda::device::ThrustAllocator* allocator)
+{
+    if(allocator == NULL)
+        g_thrustAllocator = &defaultThrustAllocator;
+    else
+        g_thrustAllocator = allocator;
+}
+
 namespace
 {
     class DefaultAllocator : public GpuMat::Allocator
@@ -465,6 +510,17 @@ namespace
 
         gridTransformUnary_< ConvertToPolicy<scalar_type> >(globPtr<T>(src), globPtr<D>(dst), op, stream);
     }
+
+    template <typename T, typename D>
+    void convertScaleHalf(const GpuMat& src, const GpuMat& dst, Stream& stream)
+    {
+        typedef typename VecTraits<T>::elem_type src_elem_type;
+        typedef typename VecTraits<D>::elem_type dst_elem_type;
+        typedef typename LargerType<src_elem_type, float>::type larger_elem_type;
+        typedef typename LargerType<float, dst_elem_type>::type scalar_type;
+
+        gridTransformUnary_< ConvertToPolicy<scalar_type> >(globPtr<T>(src), globPtr<D>(dst), saturate_cast_fp16_func<T,D>(), stream);
+    }
 }
 
 void cv::cuda::GpuMat::convertTo(OutputArray _dst, int rtype, Stream& stream) const
@@ -538,4 +594,36 @@ void cv::cuda::GpuMat::convertTo(OutputArray _dst, int rtype, double alpha, doub
     funcs[sdepth][ddepth](reshape(1), dst.reshape(1), alpha, beta, stream);
 }
 
+void cv::cuda::convertFp16(InputArray _src, OutputArray _dst, Stream& stream)
+{
+    GpuMat src = _src.getGpuMat();
+    int ddepth = 0;
+
+    switch(src.depth())
+    {
+    case CV_32F:
+        ddepth = CV_16S;
+        break;
+    case CV_16S:
+        ddepth = CV_32F;
+        break;
+    default:
+        CV_Error(Error::StsUnsupportedFormat, "Unsupported input depth");
+        return;
+    }
+    int type = CV_MAKE_TYPE(CV_MAT_DEPTH(ddepth), src.channels());
+    _dst.create(src.size(), type);
+    GpuMat dst = _dst.getGpuMat();
+
+    typedef void (*func_t)(const GpuMat& src, const GpuMat& dst, Stream& stream);
+    static const func_t funcs[] =
+    {
+        0, 0, 0,
+        convertScaleHalf<float, short>, 0, convertScaleHalf<short, float>,
+        0, 0,
+    };
+
+    funcs[ddepth](src.reshape(1), dst.reshape(1), stream);
+}
+
 #endif
diff --git a/modules/core/src/cuda_info.cpp b/modules/core/src/cuda_info.cpp
index 5ad33ce..b412438 100644
--- a/modules/core/src/cuda_info.cpp
+++ b/modules/core/src/cuda_info.cpp
@@ -71,6 +71,7 @@ void cv::cuda::setDevice(int device)
     throw_no_cuda();
 #else
     cudaSafeCall( cudaSetDevice(device) );
+    cudaSafeCall( cudaFree(0) );
 #endif
 }
 
diff --git a/modules/core/src/dxt.cpp b/modules/core/src/dxt.cpp
index 691b297..f553c4f 100644
--- a/modules/core/src/dxt.cpp
+++ b/modules/core/src/dxt.cpp
@@ -173,7 +173,7 @@ DFTFactorize( int n, int* factors )
 }
 
 static void
-DFTInit( int n0, int nf, int* factors, int* itab, int elem_size, void* _wave, int inv_itab )
+DFTInit( int n0, int nf, const int* factors, int* itab, int elem_size, void* _wave, int inv_itab )
 {
     int digits[34], radix[34];
     int n = factors[0], m = 0;
@@ -469,69 +469,109 @@ template<> struct DFT_VecR4<float>
 static IppStatus ippsDFTFwd_CToC( const Complex<float>* src, Complex<float>* dst,
                              const void* spec, uchar* buf)
 {
-    return ippsDFTFwd_CToC_32fc( (const Ipp32fc*)src, (Ipp32fc*)dst,
+    return CV_INSTRUMENT_FUN_IPP(ippsDFTFwd_CToC_32fc, (const Ipp32fc*)src, (Ipp32fc*)dst,
                                  (const IppsDFTSpec_C_32fc*)spec, buf);
 }
 
 static IppStatus ippsDFTFwd_CToC( const Complex<double>* src, Complex<double>* dst,
                              const void* spec, uchar* buf)
 {
-    return ippsDFTFwd_CToC_64fc( (const Ipp64fc*)src, (Ipp64fc*)dst,
+    return CV_INSTRUMENT_FUN_IPP(ippsDFTFwd_CToC_64fc, (const Ipp64fc*)src, (Ipp64fc*)dst,
                                  (const IppsDFTSpec_C_64fc*)spec, buf);
 }
 
 static IppStatus ippsDFTInv_CToC( const Complex<float>* src, Complex<float>* dst,
                              const void* spec, uchar* buf)
 {
-    return ippsDFTInv_CToC_32fc( (const Ipp32fc*)src, (Ipp32fc*)dst,
+    return CV_INSTRUMENT_FUN_IPP(ippsDFTInv_CToC_32fc, (const Ipp32fc*)src, (Ipp32fc*)dst,
                                  (const IppsDFTSpec_C_32fc*)spec, buf);
 }
 
 static IppStatus ippsDFTInv_CToC( const Complex<double>* src, Complex<double>* dst,
                                   const void* spec, uchar* buf)
 {
-    return ippsDFTInv_CToC_64fc( (const Ipp64fc*)src, (Ipp64fc*)dst,
+    return CV_INSTRUMENT_FUN_IPP(ippsDFTInv_CToC_64fc, (const Ipp64fc*)src, (Ipp64fc*)dst,
                                  (const IppsDFTSpec_C_64fc*)spec, buf);
 }
 
 static IppStatus ippsDFTFwd_RToPack( const float* src, float* dst,
                                      const void* spec, uchar* buf)
 {
-    return ippsDFTFwd_RToPack_32f( src, dst, (const IppsDFTSpec_R_32f*)spec, buf);
+    return CV_INSTRUMENT_FUN_IPP(ippsDFTFwd_RToPack_32f, src, dst, (const IppsDFTSpec_R_32f*)spec, buf);
 }
 
 static IppStatus ippsDFTFwd_RToPack( const double* src, double* dst,
                                      const void* spec, uchar* buf)
 {
-    return ippsDFTFwd_RToPack_64f( src, dst, (const IppsDFTSpec_R_64f*)spec, buf);
+    return CV_INSTRUMENT_FUN_IPP(ippsDFTFwd_RToPack_64f, src, dst, (const IppsDFTSpec_R_64f*)spec, buf);
 }
 
 static IppStatus ippsDFTInv_PackToR( const float* src, float* dst,
                                      const void* spec, uchar* buf)
 {
-    return ippsDFTInv_PackToR_32f( src, dst, (const IppsDFTSpec_R_32f*)spec, buf);
+    return CV_INSTRUMENT_FUN_IPP(ippsDFTInv_PackToR_32f, src, dst, (const IppsDFTSpec_R_32f*)spec, buf);
 }
 
 static IppStatus ippsDFTInv_PackToR( const double* src, double* dst,
                                      const void* spec, uchar* buf)
 {
-    return ippsDFTInv_PackToR_64f( src, dst, (const IppsDFTSpec_R_64f*)spec, buf);
+    return CV_INSTRUMENT_FUN_IPP(ippsDFTInv_PackToR_64f, src, dst, (const IppsDFTSpec_R_64f*)spec, buf);
 }
 #endif
 
-enum { DFT_NO_PERMUTE=256, DFT_COMPLEX_INPUT_OR_OUTPUT=512 };
+struct OcvDftOptions;
+
+typedef void (*DFTFunc)(const OcvDftOptions & c, const void* src, void* dst);
+
+struct OcvDftOptions {
+    int nf;
+    int *factors;
+    double scale;
+
+    int* itab;
+    void* wave;
+    int tab_size;
+    int n;
+
+    bool isInverse;
+    bool noPermute;
+    bool isComplex;
+
+    bool haveSSE3;
+
+    DFTFunc dft_func;
+    bool useIpp;
 
-// mixed-radix complex discrete Fourier transform: double-precision version
-template<typename T> static void
-DFT( const Complex<T>* src, Complex<T>* dst, int n,
-     int nf, const int* factors, const int* itab,
-     const Complex<T>* wave, int tab_size,
-     const void*
 #ifdef USE_IPP_DFT
-     spec
+    uchar* ipp_spec;
+    uchar* ipp_work;
 #endif
-     , Complex<T>* buf,
-     int flags, double _scale )
+
+    OcvDftOptions()
+    {
+        nf = 0;
+        factors = 0;
+        scale = 0;
+        itab = 0;
+        wave = 0;
+        tab_size = 0;
+        n = 0;
+        isInverse = false;
+        noPermute = false;
+        isComplex = false;
+        useIpp = false;
+#ifdef USE_IPP_DFT
+        ipp_spec = 0;
+        ipp_work = 0;
+#endif
+        dft_func = 0;
+        haveSSE3 = checkHardwareSupport(CV_CPU_SSE3);
+    }
+};
+
+// mixed-radix complex discrete Fourier transform: double-precision version
+template<typename T> static void
+DFT(const OcvDftOptions & c, const Complex<T>* src, Complex<T>* dst)
 {
     static const T sin_120 = (T)0.86602540378443864676372317075294;
     static const T fft5_2 = (T)0.559016994374947424102293417182819;
@@ -539,20 +579,23 @@ DFT( const Complex<T>* src, Complex<T>* dst, int n,
     static const T fft5_4 = (T)-1.538841768587626701285145288018455;
     static const T fft5_5 = (T)0.363271264002680442947733378740309;
 
-    int n0 = n, f_idx, nx;
-    int inv = flags & DFT_INVERSE;
-    int dw0 = tab_size, dw;
+    const Complex<T>* wave = (Complex<T>*)c.wave;
+    const int * itab = c.itab;
+
+    int n = c.n;
+    int f_idx, nx;
+    int inv = c.isInverse;
+    int dw0 = c.tab_size, dw;
     int i, j, k;
     Complex<T> t;
-    T scale = (T)_scale;
-    int tab_step;
+    T scale = (T)c.scale;
 
-#ifdef USE_IPP_DFT
-    if( spec )
+    if( c.useIpp )
     {
+#ifdef USE_IPP_DFT
         if( !inv )
         {
-            if (ippsDFTFwd_CToC( src, dst, spec, (uchar*)buf ) >= 0)
+            if (ippsDFTFwd_CToC( src, dst, c.ipp_spec, c.ipp_work ) >= 0)
             {
                 CV_IMPL_ADD(CV_IMPL_IPP);
                 return;
@@ -560,22 +603,22 @@ DFT( const Complex<T>* src, Complex<T>* dst, int n,
         }
         else
         {
-            if (ippsDFTInv_CToC( src, dst, spec, (uchar*)buf ) >= 0)
+            if (ippsDFTInv_CToC( src, dst, c.ipp_spec, c.ipp_work ) >= 0)
             {
                 CV_IMPL_ADD(CV_IMPL_IPP);
                 return;
             }
         }
         setIppErrorStatus();
-    }
 #endif
+    }
 
-    tab_step = tab_size == n ? 1 : tab_size == n*2 ? 2 : tab_size/n;
+    int tab_step = c.tab_size == n ? 1 : c.tab_size == n*2 ? 2 : c.tab_size/n;
 
     // 0. shuffle data
     if( dst != src )
     {
-        assert( (flags & DFT_NO_PERMUTE) == 0 );
+        assert( !c.noPermute );
         if( !inv )
         {
             for( i = 0; i <= n - 2; i += 2, itab += 2*tab_step )
@@ -609,10 +652,10 @@ DFT( const Complex<T>* src, Complex<T>* dst, int n,
     }
     else
     {
-        if( (flags & DFT_NO_PERMUTE) == 0 )
+        if( !c.noPermute )
         {
-            CV_Assert( factors[0] == factors[nf-1] );
-            if( nf == 1 )
+            CV_Assert( c.factors[0] == c.factors[c.nf-1] );
+            if( c.nf == 1 )
             {
                 if( (n & 3) == 0 )
                 {
@@ -662,22 +705,22 @@ DFT( const Complex<T>* src, Complex<T>* dst, int n,
 
     n = 1;
     // 1. power-2 transforms
-    if( (factors[0] & 1) == 0 )
+    if( (c.factors[0] & 1) == 0 )
     {
-        if( factors[0] >= 4 && checkHardwareSupport(CV_CPU_SSE3))
+        if( c.factors[0] >= 4 && c.haveSSE3)
         {
             DFT_VecR4<T> vr4;
-            n = vr4(dst, factors[0], n0, dw0, wave);
+            n = vr4(dst, c.factors[0], c.n, dw0, wave);
         }
 
         // radix-4 transform
-        for( ; n*4 <= factors[0]; )
+        for( ; n*4 <= c.factors[0]; )
         {
             nx = n;
             n *= 4;
             dw0 /= 4;
 
-            for( i = 0; i < n0; i += n )
+            for( i = 0; i < c.n; i += n )
             {
                 Complex<T> *v0, *v1;
                 T r0, i0, r1, i1, r2, i2, r3, i3, r4, i4;
@@ -729,14 +772,14 @@ DFT( const Complex<T>* src, Complex<T>* dst, int n,
             }
         }
 
-        for( ; n < factors[0]; )
+        for( ; n < c.factors[0]; )
         {
             // do the remaining radix-2 transform
             nx = n;
             n *= 2;
             dw0 /= 2;
 
-            for( i = 0; i < n0; i += n )
+            for( i = 0; i < c.n; i += n )
             {
                 Complex<T>* v = dst + i;
                 T r0 = v[0].re + v[nx].re;
@@ -761,9 +804,9 @@ DFT( const Complex<T>* src, Complex<T>* dst, int n,
     }
 
     // 2. all the other transforms
-    for( f_idx = (factors[0]&1) ? 0 : 1; f_idx < nf; f_idx++ )
+    for( f_idx = (c.factors[0]&1) ? 0 : 1; f_idx < c.nf; f_idx++ )
     {
-        int factor = factors[f_idx];
+        int factor = c.factors[f_idx];
         nx = n;
         n *= factor;
         dw0 /= factor;
@@ -771,7 +814,7 @@ DFT( const Complex<T>* src, Complex<T>* dst, int n,
         if( factor == 3 )
         {
             // radix-3
-            for( i = 0; i < n0; i += n )
+            for( i = 0; i < c.n; i += n )
             {
                 Complex<T>* v = dst + i;
 
@@ -807,7 +850,7 @@ DFT( const Complex<T>* src, Complex<T>* dst, int n,
         else if( factor == 5 )
         {
             // radix-5
-            for( i = 0; i < n0; i += n )
+            for( i = 0; i < c.n; i += n )
             {
                 for( j = 0, dw = 0; j < nx; j++, dw += dw0 )
                 {
@@ -863,11 +906,12 @@ DFT( const Complex<T>* src, Complex<T>* dst, int n,
         {
             // radix-"factor" - an odd number
             int p, q, factor2 = (factor - 1)/2;
-            int d, dd, dw_f = tab_size/factor;
+            int d, dd, dw_f = c.tab_size/factor;
+            AutoBuffer<Complex<T> > buf(factor2 * 2);
             Complex<T>* a = buf;
-            Complex<T>* b = buf + factor2;
+            Complex<T>* b = a + factor2;
 
-            for( i = 0; i < n0; i += n )
+            for( i = 0; i < c.n; i += n )
             {
                 for( j = 0, dw = 0; j < nx; j++, dw += dw0 )
                 {
@@ -931,7 +975,7 @@ DFT( const Complex<T>* src, Complex<T>* dst, int n,
                             s1.im += r1 - i1; s0.im += r1 + i1;
 
                             d += dd;
-                            d -= -(d >= tab_size) & tab_size;
+                            d -= -(d >= c.tab_size) & c.tab_size;
                         }
 
                         v[k] = s0;
@@ -948,7 +992,7 @@ DFT( const Complex<T>* src, Complex<T>* dst, int n,
         if( inv )
             im_scale = -im_scale;
 
-        for( i = 0; i < n0; i++ )
+        for( i = 0; i < c.n; i++ )
         {
             T t0 = dst[i].re*re_scale;
             T t1 = dst[i].im*im_scale;
@@ -958,7 +1002,7 @@ DFT( const Complex<T>* src, Complex<T>* dst, int n,
     }
     else if( inv )
     {
-        for( i = 0; i <= n0 - 2; i += 2 )
+        for( i = 0; i <= c.n - 2; i += 2 )
         {
             T t0 = -dst[i].im;
             T t1 = -dst[i+1].im;
@@ -966,8 +1010,8 @@ DFT( const Complex<T>* src, Complex<T>* dst, int n,
             dst[i+1].im = t1;
         }
 
-        if( i < n0 )
-            dst[n0-1].im = -dst[n0-1].im;
+        if( i < c.n )
+            dst[c.n-1].im = -dst[c.n-1].im;
     }
 }
 
@@ -977,23 +1021,18 @@ DFT( const Complex<T>* src, Complex<T>* dst, int n,
      re(0), re(1), im(1), ... , re(n/2-1), im((n+1)/2-1) [, re((n+1)/2)] OR ...
      re(0), 0, re(1), im(1), ..., re(n/2-1), im((n+1)/2-1) [, re((n+1)/2), 0] */
 template<typename T> static void
-RealDFT( const T* src, T* dst, int n, int nf, int* factors, const int* itab,
-         const Complex<T>* wave, int tab_size, const void*
-#ifdef USE_IPP_DFT
-         spec
-#endif
-         ,
-         Complex<T>* buf, int flags, double _scale )
+RealDFT(const OcvDftOptions & c, const T* src, T* dst)
 {
-    int complex_output = (flags & DFT_COMPLEX_INPUT_OR_OUTPUT) != 0;
-    T scale = (T)_scale;
-    int j, n2 = n >> 1;
+    int n = c.n;
+    int complex_output = c.isComplex;
+    T scale = (T)c.scale;
+    int j;
     dst += complex_output;
 
-#ifdef USE_IPP_DFT
-    if( spec )
+    if( c.useIpp )
     {
-        if (ippsDFTFwd_RToPack( src, dst, spec, (uchar*)buf ) >=0)
+#ifdef USE_IPP_DFT
+        if (ippsDFTFwd_RToPack( src, dst, c.ipp_spec, c.ipp_work ) >=0)
         {
             if( complex_output )
             {
@@ -1006,9 +1045,9 @@ RealDFT( const T* src, T* dst, int n, int nf, int* factors, const int* itab,
             return;
         }
         setIppErrorStatus();
-    }
 #endif
-    assert( tab_size == n );
+    }
+    assert( c.tab_size == n );
 
     if( n == 1 )
     {
@@ -1028,15 +1067,19 @@ RealDFT( const T* src, T* dst, int n, int nf, int* factors, const int* itab,
         _dst[0].im = 0;
         for( j = 1; j < n; j += 2 )
         {
-            T t0 = src[itab[j]]*scale;
-            T t1 = src[itab[j+1]]*scale;
+            T t0 = src[c.itab[j]]*scale;
+            T t1 = src[c.itab[j+1]]*scale;
             _dst[j].re = t0;
             _dst[j].im = 0;
             _dst[j+1].re = t1;
             _dst[j+1].im = 0;
         }
-        DFT( _dst, _dst, n, nf, factors, itab, wave,
-             tab_size, 0, buf, DFT_NO_PERMUTE, 1 );
+        OcvDftOptions sub_c = c;
+        sub_c.isComplex = false;
+        sub_c.isInverse = false;
+        sub_c.noPermute = true;
+        sub_c.scale = 1.;
+        DFT(sub_c, _dst, _dst);
         if( !complex_output )
             dst[1] = dst[0];
     }
@@ -1045,12 +1088,22 @@ RealDFT( const T* src, T* dst, int n, int nf, int* factors, const int* itab,
         T t0, t;
         T h1_re, h1_im, h2_re, h2_im;
         T scale2 = scale*(T)0.5;
-        factors[0] >>= 1;
+        int n2 = n >> 1;
+
+        c.factors[0] >>= 1;
+
+        OcvDftOptions sub_c = c;
+        sub_c.factors += (c.factors[0] == 1);
+        sub_c.nf -= (c.factors[0] == 1);
+        sub_c.isComplex = false;
+        sub_c.isInverse = false;
+        sub_c.noPermute = false;
+        sub_c.scale = 1.;
+        sub_c.n = n2;
 
-        DFT( (Complex<T>*)src, (Complex<T>*)dst, n2, nf - (factors[0] == 1),
-             factors + (factors[0] == 1),
-             itab, wave, tab_size, 0, buf, 0, 1 );
-        factors[0] <<= 1;
+        DFT(sub_c, (Complex<T>*)src, (Complex<T>*)dst);
+
+        c.factors[0] <<= 1;
 
         t = dst[0] - dst[1];
         dst[0] = (dst[0] + dst[1])*scale;
@@ -1060,6 +1113,8 @@ RealDFT( const T* src, T* dst, int n, int nf, int* factors, const int* itab,
         t = dst[n-1];
         dst[n-1] = dst[1];
 
+        const Complex<T> *wave = (const Complex<T>*)c.wave;
+
         for( j = 2, wave++; j < n2; j += 2, wave++ )
         {
             /* calc odd */
@@ -1103,22 +1158,16 @@ RealDFT( const T* src, T* dst, int n, int nf, int* factors, const int* itab,
       re[0], re[1], im[1], ... , re[n/2-1], im[n/2-1], re[n/2] OR
       re(0), 0, re(1), im(1), ..., re(n/2-1), im((n+1)/2-1) [, re((n+1)/2), 0] */
 template<typename T> static void
-CCSIDFT( const T* src, T* dst, int n, int nf, int* factors, const int* itab,
-         const Complex<T>* wave, int tab_size,
-         const void*
-#ifdef USE_IPP_DFT
-         spec
-#endif
-         , Complex<T>* buf,
-         int flags, double _scale )
+CCSIDFT(const OcvDftOptions & c, const T* src, T* dst)
 {
-    int complex_input = (flags & DFT_COMPLEX_INPUT_OR_OUTPUT) != 0;
-    int j, k, n2 = (n+1) >> 1;
-    T scale = (T)_scale;
+    int n = c.n;
+    int complex_input = c.isComplex;
+    int j, k;
+    T scale = (T)c.scale;
     T save_s1 = 0.;
     T t0, t1, t2, t3, t;
 
-    assert( tab_size == n );
+    assert( c.tab_size == n );
 
     if( complex_input )
     {
@@ -1127,10 +1176,10 @@ CCSIDFT( const T* src, T* dst, int n, int nf, int* factors, const int* itab,
         ((T*)src)[1] = src[0];
         src++;
     }
-#ifdef USE_IPP_DFT
-    if( spec )
+    if( c.useIpp )
     {
-        if (ippsDFTInv_PackToR( src, dst, spec, (uchar*)buf ) >=0)
+#ifdef USE_IPP_DFT
+        if (ippsDFTInv_PackToR( src, dst, c.ipp_spec, c.ipp_work ) >=0)
         {
             if( complex_input )
                 ((T*)src)[0] = (T)save_s1;
@@ -1139,8 +1188,8 @@ CCSIDFT( const T* src, T* dst, int n, int nf, int* factors, const int* itab,
         }
 
         setIppErrorStatus();
-    }
 #endif
+    }
     if( n == 1 )
     {
         dst[0] = (T)(src[0]*scale);
@@ -1158,16 +1207,25 @@ CCSIDFT( const T* src, T* dst, int n, int nf, int* factors, const int* itab,
 
         _dst[0].re = src[0];
         _dst[0].im = 0;
+
+        int n2 = (n+1) >> 1;
+
         for( j = 1; j < n2; j++ )
         {
-            int k0 = itab[j], k1 = itab[n-j];
+            int k0 = c.itab[j], k1 = c.itab[n-j];
             t0 = _src[j].re; t1 = _src[j].im;
             _dst[k0].re = t0; _dst[k0].im = -t1;
             _dst[k1].re = t0; _dst[k1].im = t1;
         }
 
-        DFT( _dst, _dst, n, nf, factors, itab, wave,
-             tab_size, 0, buf, DFT_NO_PERMUTE, 1. );
+        OcvDftOptions sub_c = c;
+        sub_c.isComplex = false;
+        sub_c.isInverse = false;
+        sub_c.noPermute = true;
+        sub_c.scale = 1.;
+        sub_c.n = n;
+
+        DFT(sub_c, _dst, _dst);
         dst[0] *= scale;
         for( j = 1; j < n; j += 2 )
         {
@@ -1180,7 +1238,7 @@ CCSIDFT( const T* src, T* dst, int n, int nf, int* factors, const int* itab,
     else
     {
         int inplace = src == dst;
-        const Complex<T>* w = wave;
+        const Complex<T>* w = (const Complex<T>*)c.wave;
 
         t = src[1];
         t0 = (src[0] + src[n-1]);
@@ -1188,6 +1246,8 @@ CCSIDFT( const T* src, T* dst, int n, int nf, int* factors, const int* itab,
         dst[0] = t0;
         dst[1] = t1;
 
+        int n2 = (n+1) >> 1;
+
         for( j = 2, w++; j < n2; j += 2, w++ )
         {
             T h1_re, h1_im, h2_re, h2_im;
@@ -1218,10 +1278,10 @@ CCSIDFT( const T* src, T* dst, int n, int nf, int* factors, const int* itab,
             else
             {
                 int j2 = j >> 1;
-                k = itab[j2];
+                k = c.itab[j2];
                 dst[k] = t0;
                 dst[k+1] = t1;
-                k = itab[n2-j2];
+                k = c.itab[n2-j2];
                 dst[k] = t2;
                 dst[k+1]= t3;
             }
@@ -1239,19 +1299,26 @@ CCSIDFT( const T* src, T* dst, int n, int nf, int* factors, const int* itab,
             }
             else
             {
-                k = itab[n2];
+                k = c.itab[n2];
                 dst[k*2] = t0;
                 dst[k*2+1] = t1;
             }
         }
 
-        factors[0] >>= 1;
-        DFT( (Complex<T>*)dst, (Complex<T>*)dst, n2,
-             nf - (factors[0] == 1),
-             factors + (factors[0] == 1), itab,
-             wave, tab_size, 0, buf,
-             inplace ? 0 : DFT_NO_PERMUTE, 1. );
-        factors[0] <<= 1;
+        c.factors[0] >>= 1;
+
+        OcvDftOptions sub_c = c;
+        sub_c.factors += (c.factors[0] == 1);
+        sub_c.nf -= (c.factors[0] == 1);
+        sub_c.isComplex = false;
+        sub_c.isInverse = false;
+        sub_c.noPermute = !inplace;
+        sub_c.scale = 1.;
+        sub_c.n = n2;
+
+        DFT(sub_c, (Complex<T>*)dst, (Complex<T>*)dst);
+
+        c.factors[0] <<= 1;
 
         for( j = 0; j < n; j += 2 )
         {
@@ -1436,57 +1503,35 @@ ExpandCCS( uchar* _ptr, int n, int elem_size )
     }
 }
 
-
-typedef void (*DFTFunc)(
-     const void* src, void* dst, int n, int nf, int* factors,
-     const int* itab, const void* wave, int tab_size,
-     const void* spec, void* buf, int inv, double scale );
-
-static void DFT_32f( const Complexf* src, Complexf* dst, int n,
-    int nf, const int* factors, const int* itab,
-    const Complexf* wave, int tab_size,
-    const void* spec, Complexf* buf,
-    int flags, double scale )
+static void DFT_32f(const OcvDftOptions & c, const Complexf* src, Complexf* dst)
 {
-    DFT(src, dst, n, nf, factors, itab, wave, tab_size, spec, buf, flags, scale);
+    DFT(c, src, dst);
 }
 
-static void DFT_64f( const Complexd* src, Complexd* dst, int n,
-    int nf, const int* factors, const int* itab,
-    const Complexd* wave, int tab_size,
-    const void* spec, Complexd* buf,
-    int flags, double scale )
+static void DFT_64f(const OcvDftOptions & c, const Complexd* src, Complexd* dst)
 {
-    DFT(src, dst, n, nf, factors, itab, wave, tab_size, spec, buf, flags, scale);
+    DFT(c, src, dst);
 }
 
 
-static void RealDFT_32f( const float* src, float* dst, int n, int nf, int* factors,
-        const int* itab,  const Complexf* wave, int tab_size, const void* spec,
-        Complexf* buf, int flags, double scale )
+static void RealDFT_32f(const OcvDftOptions & c, const float* src, float* dst)
 {
-    RealDFT( src, dst, n, nf, factors, itab, wave, tab_size, spec, buf, flags, scale);
+    RealDFT(c, src, dst);
 }
 
-static void RealDFT_64f( const double* src, double* dst, int n, int nf, int* factors,
-        const int* itab,  const Complexd* wave, int tab_size, const void* spec,
-        Complexd* buf, int flags, double scale )
+static void RealDFT_64f(const OcvDftOptions & c, const double* src, double* dst)
 {
-    RealDFT( src, dst, n, nf, factors, itab, wave, tab_size, spec, buf, flags, scale);
+    RealDFT(c, src, dst);
 }
 
-static void CCSIDFT_32f( const float* src, float* dst, int n, int nf, int* factors,
-                         const int* itab,  const Complexf* wave, int tab_size, const void* spec,
-                         Complexf* buf, int flags, double scale )
+static void CCSIDFT_32f(const OcvDftOptions & c, const float* src, float* dst)
 {
-    CCSIDFT( src, dst, n, nf, factors, itab, wave, tab_size, spec, buf, flags, scale);
+    CCSIDFT(c, src, dst);
 }
 
-static void CCSIDFT_64f( const double* src, double* dst, int n, int nf, int* factors,
-                         const int* itab,  const Complexd* wave, int tab_size, const void* spec,
-                         Complexd* buf, int flags, double scale )
+static void CCSIDFT_64f(const OcvDftOptions & c, const double* src, double* dst)
 {
-    CCSIDFT( src, dst, n, nf, factors, itab, wave, tab_size, spec, buf, flags, scale);
+    CCSIDFT(c, src, dst);
 }
 
 }
@@ -1508,8 +1553,11 @@ class Dft_C_IPPLoop_Invoker : public ParallelLoopBody
 {
 public:
 
-    Dft_C_IPPLoop_Invoker(const Mat& _src, Mat& _dst, const Dft& _ippidft, int _norm_flag, bool *_ok) :
-        ParallelLoopBody(), src(_src), dst(_dst), ippidft(_ippidft), norm_flag(_norm_flag), ok(_ok)
+    Dft_C_IPPLoop_Invoker(const uchar * _src, size_t _src_step, uchar * _dst, size_t _dst_step, int _width,
+                          const Dft& _ippidft, int _norm_flag, bool *_ok) :
+        ParallelLoopBody(),
+        src(_src), src_step(_src_step), dst(_dst), dst_step(_dst_step), width(_width),
+        ippidft(_ippidft), norm_flag(_norm_flag), ok(_ok)
     {
         *ok = true;
     }
@@ -1523,7 +1571,7 @@ public:
         int sizeSpec=0;
         int sizeInit=0;
 
-        IppiSize srcRoiSize = {src.cols, 1};
+        IppiSize srcRoiSize = {width, 1};
 
         status = ippiDFTGetSize_C_32fc(srcRoiSize, norm_flag, ippAlgHintNone, &sizeSpec, &sizeInit, &sizeBuffer );
         if ( status < 0 )
@@ -1555,7 +1603,8 @@ public:
         }
 
         for( int i = range.start; i < range.end; ++i)
-            if(!ippidft(src.ptr<Ipp32fc>(i), (int)src.step,dst.ptr<Ipp32fc>(i), (int)dst.step, pDFTSpec, (Ipp8u*)pBuffer))
+            if(!ippidft((Ipp32fc*)(src + src_step * i), src_step, (Ipp32fc*)(dst + dst_step * i), dst_step,
+                        pDFTSpec, (Ipp8u*)pBuffer))
             {
                 *ok = false;
             }
@@ -1568,8 +1617,11 @@ public:
     }
 
 private:
-    const Mat& src;
-    Mat& dst;
+    const uchar * src;
+    size_t src_step;
+    uchar * dst;
+    size_t dst_step;
+    int width;
     const Dft& ippidft;
     int norm_flag;
     bool *ok;
@@ -1582,8 +1634,11 @@ class Dft_R_IPPLoop_Invoker : public ParallelLoopBody
 {
 public:
 
-    Dft_R_IPPLoop_Invoker(const Mat& _src, Mat& _dst, const Dft& _ippidft, int _norm_flag, bool *_ok) :
-        ParallelLoopBody(), src(_src), dst(_dst), ippidft(_ippidft), norm_flag(_norm_flag), ok(_ok)
+    Dft_R_IPPLoop_Invoker(const uchar * _src, size_t _src_step, uchar * _dst, size_t _dst_step, int _width,
+                          const Dft& _ippidft, int _norm_flag, bool *_ok) :
+        ParallelLoopBody(),
+        src(_src), src_step(_src_step), dst(_dst), dst_step(_dst_step), width(_width),
+        ippidft(_ippidft), norm_flag(_norm_flag), ok(_ok)
     {
         *ok = true;
     }
@@ -1597,7 +1652,7 @@ public:
         int sizeSpec=0;
         int sizeInit=0;
 
-        IppiSize srcRoiSize = {src.cols, 1};
+        IppiSize srcRoiSize = {width, 1};
 
         status = ippiDFTGetSize_R_32f(srcRoiSize, norm_flag, ippAlgHintNone, &sizeSpec, &sizeInit, &sizeBuffer );
         if ( status < 0 )
@@ -1629,7 +1684,8 @@ public:
         }
 
         for( int i = range.start; i < range.end; ++i)
-            if(!ippidft(src.ptr<float>(i), (int)src.step,dst.ptr<float>(i), (int)dst.step, pDFTSpec, (Ipp8u*)pBuffer))
+            if(!ippidft((float*)(src + src_step * i), src_step, (float*)(dst + dst_step * i), dst_step,
+                        pDFTSpec, (Ipp8u*)pBuffer))
             {
                 *ok = false;
             }
@@ -1642,8 +1698,11 @@ public:
     }
 
 private:
-    const Mat& src;
-    Mat& dst;
+    const uchar * src;
+    size_t src_step;
+    uchar * dst;
+    size_t dst_step;
+    int width;
     const Dft& ippidft;
     int norm_flag;
     bool *ok;
@@ -1652,47 +1711,49 @@ private:
 };
 
 template <typename Dft>
-bool Dft_C_IPPLoop(const Mat& src, Mat& dst, const Dft& ippidft, int norm_flag)
+bool Dft_C_IPPLoop(const uchar * src, size_t src_step, uchar * dst, size_t dst_step, int width, int height, const Dft& ippidft, int norm_flag)
 {
     bool ok;
-    parallel_for_(Range(0, src.rows), Dft_C_IPPLoop_Invoker<Dft>(src, dst, ippidft, norm_flag, &ok), src.total()/(double)(1<<16) );
+    parallel_for_(Range(0, height), Dft_C_IPPLoop_Invoker<Dft>(src, src_step, dst, dst_step, width, ippidft, norm_flag, &ok), (width * height)/(double)(1<<16) );
     return ok;
 }
 
 template <typename Dft>
-bool Dft_R_IPPLoop(const Mat& src, Mat& dst, const Dft& ippidft, int norm_flag)
+bool Dft_R_IPPLoop(const uchar * src, size_t src_step, uchar * dst, size_t dst_step, int width, int height, const Dft& ippidft, int norm_flag)
 {
     bool ok;
-    parallel_for_(Range(0, src.rows), Dft_R_IPPLoop_Invoker<Dft>(src, dst, ippidft, norm_flag, &ok), src.total()/(double)(1<<16) );
+    parallel_for_(Range(0, height), Dft_R_IPPLoop_Invoker<Dft>(src, src_step, dst, dst_step, width, ippidft, norm_flag, &ok), (width * height)/(double)(1<<16) );
     return ok;
 }
 
 struct IPPDFT_C_Functor
 {
-    IPPDFT_C_Functor(ippiDFT_C_Func _func) : func(_func){}
+    IPPDFT_C_Functor(ippiDFT_C_Func _func) : ippiDFT_CToC_32fc_C1R(_func){}
 
-    bool operator()(const Ipp32fc* src, int srcStep, Ipp32fc* dst, int dstStep, const IppiDFTSpec_C_32fc* pDFTSpec, Ipp8u* pBuffer) const
+    bool operator()(const Ipp32fc* src, size_t srcStep, Ipp32fc* dst, size_t dstStep, const IppiDFTSpec_C_32fc* pDFTSpec, Ipp8u* pBuffer) const
     {
-        return func ? func(src, srcStep, dst, dstStep, pDFTSpec, pBuffer) >= 0 : false;
+        return ippiDFT_CToC_32fc_C1R ? CV_INSTRUMENT_FUN_IPP(ippiDFT_CToC_32fc_C1R, src, static_cast<int>(srcStep), dst, static_cast<int>(dstStep), pDFTSpec, pBuffer) >= 0 : false;
     }
 private:
-    ippiDFT_C_Func func;
+    ippiDFT_C_Func ippiDFT_CToC_32fc_C1R;
 };
 
 struct IPPDFT_R_Functor
 {
-    IPPDFT_R_Functor(ippiDFT_R_Func _func) : func(_func){}
+    IPPDFT_R_Functor(ippiDFT_R_Func _func) : ippiDFT_PackToR_32f_C1R(_func){}
 
-    bool operator()(const Ipp32f* src, int srcStep, Ipp32f* dst, int dstStep, const IppiDFTSpec_R_32f* pDFTSpec, Ipp8u* pBuffer) const
+    bool operator()(const Ipp32f* src, size_t srcStep, Ipp32f* dst, size_t dstStep, const IppiDFTSpec_R_32f* pDFTSpec, Ipp8u* pBuffer) const
     {
-        return func ? func(src, srcStep, dst, dstStep, pDFTSpec, pBuffer) >= 0 : false;
+        return ippiDFT_PackToR_32f_C1R ? CV_INSTRUMENT_FUN_IPP(ippiDFT_PackToR_32f_C1R, src, static_cast<int>(srcStep), dst, static_cast<int>(dstStep), pDFTSpec, pBuffer) >= 0 : false;
     }
 private:
-    ippiDFT_R_Func func;
+    ippiDFT_R_Func ippiDFT_PackToR_32f_C1R;
 };
 
-static bool ippi_DFT_C_32F(const Mat& src, Mat& dst, bool inv, int norm_flag)
+static bool ippi_DFT_C_32F(const uchar * src, size_t src_step, uchar * dst, size_t dst_step, int width, int height, bool inv, int norm_flag)
 {
+    CV_INSTRUMENT_REGION_IPP()
+
     IppStatus status;
     Ipp8u* pBuffer = 0;
     Ipp8u* pMemInit= 0;
@@ -1700,7 +1761,7 @@ static bool ippi_DFT_C_32F(const Mat& src, Mat& dst, bool inv, int norm_flag)
     int sizeSpec=0;
     int sizeInit=0;
 
-    IppiSize srcRoiSize = {src.cols, src.rows};
+    IppiSize srcRoiSize = {width, height};
 
     status = ippiDFTGetSize_C_32fc(srcRoiSize, norm_flag, ippAlgHintNone, &sizeSpec, &sizeInit, &sizeBuffer );
     if ( status < 0 )
@@ -1728,9 +1789,9 @@ static bool ippi_DFT_C_32F(const Mat& src, Mat& dst, bool inv, int norm_flag)
     }
 
     if (!inv)
-        status = ippiDFTFwd_CToC_32fc_C1R( src.ptr<Ipp32fc>(), (int)src.step, dst.ptr<Ipp32fc>(), (int)dst.step, pDFTSpec, pBuffer );
+        status = CV_INSTRUMENT_FUN_IPP(ippiDFTFwd_CToC_32fc_C1R, (Ipp32fc*)src, static_cast<int>(src_step), (Ipp32fc*)dst, static_cast<int>(dst_step), pDFTSpec, pBuffer);
     else
-        status = ippiDFTInv_CToC_32fc_C1R( src.ptr<Ipp32fc>(), (int)src.step, dst.ptr<Ipp32fc>(), (int)dst.step, pDFTSpec, pBuffer );
+        status = CV_INSTRUMENT_FUN_IPP(ippiDFTInv_CToC_32fc_C1R, (Ipp32fc*)src, static_cast<int>(src_step), (Ipp32fc*)dst, static_cast<int>(dst_step), pDFTSpec, pBuffer);
 
     if ( sizeBuffer > 0 )
         ippFree( pBuffer );
@@ -1745,8 +1806,10 @@ static bool ippi_DFT_C_32F(const Mat& src, Mat& dst, bool inv, int norm_flag)
     return false;
 }
 
-static bool ippi_DFT_R_32F(const Mat& src, Mat& dst, bool inv, int norm_flag)
+static bool ippi_DFT_R_32F(const uchar * src, size_t src_step, uchar * dst, size_t dst_step, int width, int height, bool inv, int norm_flag)
 {
+    CV_INSTRUMENT_REGION_IPP()
+
     IppStatus status;
     Ipp8u* pBuffer = 0;
     Ipp8u* pMemInit= 0;
@@ -1754,7 +1817,7 @@ static bool ippi_DFT_R_32F(const Mat& src, Mat& dst, bool inv, int norm_flag)
     int sizeSpec=0;
     int sizeInit=0;
 
-    IppiSize srcRoiSize = {src.cols, src.rows};
+    IppiSize srcRoiSize = {width, height};
 
     status = ippiDFTGetSize_R_32f(srcRoiSize, norm_flag, ippAlgHintNone, &sizeSpec, &sizeInit, &sizeBuffer );
     if ( status < 0 )
@@ -1782,9 +1845,9 @@ static bool ippi_DFT_R_32F(const Mat& src, Mat& dst, bool inv, int norm_flag)
     }
 
     if (!inv)
-        status = ippiDFTFwd_RToPack_32f_C1R( src.ptr<float>(), (int)(src.step), dst.ptr<float>(), (int)dst.step, pDFTSpec, pBuffer );
+        status = CV_INSTRUMENT_FUN_IPP(ippiDFTFwd_RToPack_32f_C1R, (float*)src, static_cast<int>(src_step), (float*)dst, static_cast<int>(dst_step), pDFTSpec, pBuffer);
     else
-        status = ippiDFTInv_PackToR_32f_C1R( src.ptr<float>(), (int)src.step, dst.ptr<float>(), (int)dst.step, pDFTSpec, pBuffer );
+        status = CV_INSTRUMENT_FUN_IPP(ippiDFTInv_PackToR_32f_C1R, (float*)src, static_cast<int>(src_step), (float*)dst, static_cast<int>(dst_step), pDFTSpec, pBuffer);
 
     if ( sizeBuffer > 0 )
         ippFree( pBuffer );
@@ -2426,111 +2489,324 @@ static bool ocl_dft_amdfft(InputArray _src, OutputArray _dst, int flags)
 
 namespace cv
 {
-static void complementComplexOutput(Mat& dst, int len, int dft_dims)
+
+template <typename T>
+static void complementComplex(T * ptr, size_t step, int n, int len, int dft_dims)
 {
-    int i, n = dst.cols;
-    size_t elem_size = dst.elemSize1();
-    if( elem_size == sizeof(float) )
+    T* p0 = (T*)ptr;
+    size_t dstep = step/sizeof(p0[0]);
+    for(int i = 0; i < len; i++ )
     {
-        float* p0 = dst.ptr<float>();
-        size_t dstep = dst.step/sizeof(p0[0]);
-        for( i = 0; i < len; i++ )
-        {
-            float* p = p0 + dstep*i;
-            float* q = dft_dims == 1 || i == 0 || i*2 == len ? p : p0 + dstep*(len-i);
+        T* p = p0 + dstep*i;
+        T* q = dft_dims == 1 || i == 0 || i*2 == len ? p : p0 + dstep*(len-i);
 
-            for( int j = 1; j < (n+1)/2; j++ )
-            {
-                p[(n-j)*2] = q[j*2];
-                p[(n-j)*2+1] = -q[j*2+1];
-            }
+        for( int j = 1; j < (n+1)/2; j++ )
+        {
+            p[(n-j)*2] = q[j*2];
+            p[(n-j)*2+1] = -q[j*2+1];
         }
     }
+}
+
+static void complementComplexOutput(int depth, uchar * ptr, size_t step, int count, int len, int dft_dims)
+{
+    if( depth == CV_32F )
+        complementComplex((float*)ptr, step, count, len, dft_dims);
     else
+        complementComplex((double*)ptr, step, count, len, dft_dims);
+}
+
+enum DftMode {
+    InvalidDft = 0,
+    FwdRealToCCS,
+    FwdRealToComplex,
+    FwdComplexToComplex,
+    InvCCSToReal,
+    InvComplexToReal,
+    InvComplexToComplex,
+};
+
+enum DftDims {
+    InvalidDim = 0,
+    OneDim,
+    OneDimColWise,
+    TwoDims
+};
+
+inline const char * modeName(DftMode m)
+{
+    switch (m)
     {
-        double* p0 = dst.ptr<double>();
-        size_t dstep = dst.step/sizeof(p0[0]);
-        for( i = 0; i < len; i++ )
-        {
-            double* p = p0 + dstep*i;
-            double* q = dft_dims == 1 || i == 0 || i*2 == len ? p : p0 + dstep*(len-i);
+    case InvalidDft: return "InvalidDft";
+    case FwdRealToCCS: return "FwdRealToCCS";
+    case FwdRealToComplex: return "FwdRealToComplex";
+    case FwdComplexToComplex: return "FwdComplexToComplex";
+    case InvCCSToReal: return "InvCCSToReal";
+    case InvComplexToReal: return "InvComplexToReal";
+    case InvComplexToComplex: return "InvComplexToComplex";
+    }
+    return 0;
+}
 
-            for( int j = 1; j < (n+1)/2; j++ )
-            {
-                p[(n-j)*2] = q[j*2];
-                p[(n-j)*2+1] = -q[j*2+1];
-            }
-        }
+inline const char * dimsName(DftDims d)
+{
+    switch (d)
+    {
+    case InvalidDim: return "InvalidDim";
+    case OneDim: return "OneDim";
+    case OneDimColWise: return "OneDimColWise";
+    case TwoDims: return "TwoDims";
+    };
+    return 0;
+}
+
+template <typename T>
+inline bool isInv(T mode)
+{
+    switch ((DftMode)mode)
+    {
+        case InvCCSToReal:
+        case InvComplexToReal:
+        case InvComplexToComplex: return true;
+        default: return false;
     }
 }
+
+inline DftMode determineMode(bool inv, int cn1, int cn2)
+{
+    if (!inv)
+    {
+        if (cn1 == 1 && cn2 == 1)
+            return FwdRealToCCS;
+        else if (cn1 == 1 && cn2 == 2)
+            return FwdRealToComplex;
+        else if (cn1 == 2 && cn2 == 2)
+            return FwdComplexToComplex;
+    }
+    else
+    {
+        if (cn1 == 1 && cn2 == 1)
+            return InvCCSToReal;
+        else if (cn1 == 2 && cn2 == 1)
+            return InvComplexToReal;
+        else if (cn1 == 2 && cn2 == 2)
+            return InvComplexToComplex;
+    }
+    return InvalidDft;
 }
 
-void cv::dft( InputArray _src0, OutputArray _dst, int flags, int nonzero_rows )
+
+inline DftDims determineDims(int rows, int cols, bool isRowWise, bool isContinuous)
 {
-#ifdef HAVE_CLAMDFFT
-    CV_OCL_RUN(ocl::haveAmdFft() && ocl::Device::getDefault().type() != ocl::Device::TYPE_CPU &&
-            _dst.isUMat() && _src0.dims() <= 2 && nonzero_rows == 0,
-               ocl_dft_amdfft(_src0, _dst, flags))
-#endif
+    // printf("%d x %d (%d, %d)\n", rows, cols, isRowWise, isContinuous);
+    if (isRowWise)
+        return OneDim;
+    if (cols == 1 && rows > 1) // one-column-shaped input
+    {
+        if (isContinuous)
+            return OneDim;
+        else
+            return OneDimColWise;
+    }
+    if (rows == 1)
+        return OneDim;
+    if (cols > 1 && rows > 1)
+        return TwoDims;
+    return InvalidDim;
+}
 
-#ifdef HAVE_OPENCL
-    CV_OCL_RUN(_dst.isUMat() && _src0.dims() <= 2,
-               ocl_dft(_src0, _dst, flags, nonzero_rows))
-#endif
+class OcvDftImpl : public hal::DFT2D
+{
+protected:
+    Ptr<hal::DFT1D> contextA;
+    Ptr<hal::DFT1D> contextB;
+    bool needBufferA;
+    bool needBufferB;
+    bool inv;
+    int width;
+    int height;
+    DftMode mode;
+    int elem_size;
+    int complex_elem_size;
+    int depth;
+    bool real_transform;
+    int nonzero_rows;
+    bool isRowTransform;
+    bool isScaled;
+    std::vector<int> stages;
+    bool useIpp;
+    int src_channels;
+    int dst_channels;
+
+    AutoBuffer<uchar> tmp_bufA;
+    AutoBuffer<uchar> tmp_bufB;
+    AutoBuffer<uchar> buf0;
+    AutoBuffer<uchar> buf1;
+
+public:
+    OcvDftImpl()
+    {
+        needBufferA = false;
+        needBufferB = false;
+        inv = false;
+        width = 0;
+        height = 0;
+        mode = InvalidDft;
+        elem_size = 0;
+        complex_elem_size = 0;
+        depth = 0;
+        real_transform = false;
+        nonzero_rows = 0;
+        isRowTransform = false;
+        isScaled = false;
+        useIpp = false;
+        src_channels = 0;
+        dst_channels = 0;
+    }
 
-    static DFTFunc dft_tbl[6] =
+    void init(int _width, int _height, int _depth, int _src_channels, int _dst_channels, int flags, int _nonzero_rows)
     {
-        (DFTFunc)DFT_32f,
-        (DFTFunc)RealDFT_32f,
-        (DFTFunc)CCSIDFT_32f,
-        (DFTFunc)DFT_64f,
-        (DFTFunc)RealDFT_64f,
-        (DFTFunc)CCSIDFT_64f
-    };
-    AutoBuffer<uchar> buf;
-    Mat src0 = _src0.getMat(), src = src0;
-    int prev_len = 0, stage = 0;
-    bool inv = (flags & DFT_INVERSE) != 0;
-    int nf = 0, real_transform = src.channels() == 1 || (inv && (flags & DFT_REAL_OUTPUT)!=0);
-    int type = src.type(), depth = src.depth();
-    int elem_size = (int)src.elemSize1(), complex_elem_size = elem_size*2;
-    int factors[34];
-    bool inplace_transform = false;
-#ifdef USE_IPP_DFT
-    AutoBuffer<uchar> ippbuf;
-    int ipp_norm_flag = !(flags & DFT_SCALE) ? 8 : inv ? 2 : 1;
+        bool isComplex = _src_channels != _dst_channels;
+        nonzero_rows = _nonzero_rows;
+        width = _width;
+        height = _height;
+        depth = _depth;
+        src_channels = _src_channels;
+        dst_channels = _dst_channels;
+        bool isInverse = (flags & CV_HAL_DFT_INVERSE) != 0;
+        bool isInplace = (flags & CV_HAL_DFT_IS_INPLACE) != 0;
+        bool isContinuous = (flags & CV_HAL_DFT_IS_CONTINUOUS) != 0;
+        mode = determineMode(isInverse, _src_channels, _dst_channels);
+        inv = isInverse;
+        isRowTransform = (flags & CV_HAL_DFT_ROWS) != 0;
+        isScaled = (flags & CV_HAL_DFT_SCALE) != 0;
+        needBufferA = false;
+        needBufferB = false;
+        real_transform = (mode != FwdComplexToComplex && mode != InvComplexToComplex);
+
+        elem_size = (depth == CV_32F) ? sizeof(float) : sizeof(double);
+        complex_elem_size = elem_size * 2;
+        if( !real_transform )
+            elem_size = complex_elem_size;
+
+#if defined USE_IPP_DFT
+        CV_IPP_CHECK()
+        {
+            if (nonzero_rows == 0 && depth == CV_32F && ((width * height)>(int)(1<<6)))
+            {
+                if (mode == FwdComplexToComplex || mode == InvComplexToComplex || mode == FwdRealToCCS || mode == InvCCSToReal)
+                {
+                    useIpp = true;
+                    return;
+                }
+            }
+        }
 #endif
 
-    CV_Assert( type == CV_32FC1 || type == CV_32FC2 || type == CV_64FC1 || type == CV_64FC2 );
+        DftDims dims = determineDims(height, width, isRowTransform, isContinuous);
+        if (dims == TwoDims)
+        {
+            stages.resize(2);
+            if (mode == InvCCSToReal || mode == InvComplexToReal)
+            {
+                stages[0] = 1;
+                stages[1] = 0;
+            }
+            else
+            {
+                stages[0] = 0;
+                stages[1] = 1;
+            }
+        }
+        else
+        {
+            stages.resize(1);
+            if (dims == OneDimColWise)
+                stages[0] = 1;
+            else
+                stages[0] = 0;
+        }
 
-    if( !inv && src.channels() == 1 && (flags & DFT_COMPLEX_OUTPUT) )
-        _dst.create( src.size(), CV_MAKETYPE(depth, 2) );
-    else if( inv && src.channels() == 2 && (flags & DFT_REAL_OUTPUT) )
-        _dst.create( src.size(), depth );
-    else
-        _dst.create( src.size(), type );
+        for(uint stageIndex = 0; stageIndex < stages.size(); ++stageIndex)
+        {
+            if (stageIndex == 1)
+            {
+                isInplace = true;
+                isComplex = false;
+            }
 
-    Mat dst = _dst.getMat();
+            int stage = stages[stageIndex];
+            bool isLastStage = (stageIndex + 1 == stages.size());
+
+            int len, count;
+
+            int f = 0;
+            if (inv)
+                f |= CV_HAL_DFT_INVERSE;
+            if (isScaled)
+                f |= CV_HAL_DFT_SCALE;
+            if (isRowTransform)
+                f |= CV_HAL_DFT_ROWS;
+            if (isComplex)
+                f |= CV_HAL_DFT_COMPLEX_OUTPUT;
+            if (real_transform)
+                f |= CV_HAL_DFT_REAL_OUTPUT;
+            if (!isLastStage)
+                f |= CV_HAL_DFT_TWO_STAGE;
+
+            if( stage == 0 ) // row-wise transform
+            {
+                if (width == 1 && !isRowTransform )
+                {
+                    len = height;
+                    count = width;
+                }
+                else
+                {
+                    len = width;
+                    count = height;
+                }
+                needBufferA = isInplace;
+                contextA = hal::DFT1D::create(len, count, depth, f, &needBufferA);
+                if (needBufferA)
+                    tmp_bufA.allocate(len * complex_elem_size);
+            }
+            else
+            {
+                len = height;
+                count = width;
+                f |= CV_HAL_DFT_STAGE_COLS;
+                needBufferB = isInplace;
+                contextB = hal::DFT1D::create(len, count, depth, f, &needBufferB);
+                if (needBufferB)
+                    tmp_bufB.allocate(len * complex_elem_size);
+
+                buf0.allocate(len * complex_elem_size);
+                buf1.allocate(len * complex_elem_size);
+            }
+        }
+    }
 
-#if defined USE_IPP_DFT
-    CV_IPP_CHECK()
+    void apply(const uchar * src, size_t src_step, uchar * dst, size_t dst_step)
     {
-        if ((src.depth() == CV_32F) && (src.total()>(int)(1<<6)) && nonzero_rows == 0)
+#if defined USE_IPP_DFT
+        if (useIpp)
         {
-            if ((flags & DFT_ROWS) == 0)
+            int ipp_norm_flag = !isScaled ? 8 : inv ? 2 : 1;
+            if (!isRowTransform)
             {
-                if (src.channels() == 2 && !(inv && (flags & DFT_REAL_OUTPUT)))
+                if (mode == FwdComplexToComplex || mode == InvComplexToComplex)
                 {
-                    if (ippi_DFT_C_32F(src, dst, inv, ipp_norm_flag))
+                    if (ippi_DFT_C_32F(src, src_step, dst, dst_step, width, height, inv, ipp_norm_flag))
                     {
                         CV_IMPL_ADD(CV_IMPL_IPP);
                         return;
                     }
                     setIppErrorStatus();
                 }
-                if (src.channels() == 1 && (inv || !(flags & DFT_COMPLEX_OUTPUT)))
+                else if (mode == FwdRealToCCS || mode == InvCCSToReal)
                 {
-                    if (ippi_DFT_R_32F(src, dst, inv, ipp_norm_flag))
+                    if (ippi_DFT_R_32F(src, src_step, dst, dst_step, width, height, inv, ipp_norm_flag))
                     {
                         CV_IMPL_ADD(CV_IMPL_IPP);
                         return;
@@ -2540,20 +2816,20 @@ void cv::dft( InputArray _src0, OutputArray _dst, int flags, int nonzero_rows )
             }
             else
             {
-                if (src.channels() == 2 && !(inv && (flags & DFT_REAL_OUTPUT)))
+                if (mode == FwdComplexToComplex || mode == InvComplexToComplex)
                 {
                     ippiDFT_C_Func ippiFunc = inv ? (ippiDFT_C_Func)ippiDFTInv_CToC_32fc_C1R : (ippiDFT_C_Func)ippiDFTFwd_CToC_32fc_C1R;
-                    if (Dft_C_IPPLoop(src, dst, IPPDFT_C_Functor(ippiFunc),ipp_norm_flag))
+                    if (Dft_C_IPPLoop(src, src_step, dst, dst_step, width, height, IPPDFT_C_Functor(ippiFunc),ipp_norm_flag))
                     {
                         CV_IMPL_ADD(CV_IMPL_IPP|CV_IMPL_MT);
                         return;
                     }
                     setIppErrorStatus();
                 }
-                if (src.channels() == 1 && (inv || !(flags & DFT_COMPLEX_OUTPUT)))
+                else if (mode == FwdRealToCCS || mode == InvCCSToReal)
                 {
                     ippiDFT_R_Func ippiFunc = inv ? (ippiDFT_R_Func)ippiDFTInv_PackToR_32f_C1R : (ippiDFT_R_Func)ippiDFTFwd_RToPack_32f_C1R;
-                    if (Dft_R_IPPLoop(src, dst, IPPDFT_R_Functor(ippiFunc),ipp_norm_flag))
+                    if (Dft_R_IPPLoop(src, src_step, dst, dst_step, width, height, IPPDFT_R_Functor(ippiFunc),ipp_norm_flag))
                     {
                         CV_IMPL_ADD(CV_IMPL_IPP|CV_IMPL_MT);
                         return;
@@ -2561,346 +2837,540 @@ void cv::dft( InputArray _src0, OutputArray _dst, int flags, int nonzero_rows )
                     setIppErrorStatus();
                 }
             }
+            return;
         }
-    }
 #endif
 
-    if( !real_transform )
-        elem_size = complex_elem_size;
+        for(uint stageIndex = 0; stageIndex < stages.size(); ++stageIndex)
+        {
+            int stage_src_channels = src_channels;
+            int stage_dst_channels = dst_channels;
+
+            if (stageIndex == 1)
+            {
+                src = dst;
+                src_step = dst_step;
+                stage_src_channels = stage_dst_channels;
+            }
 
-    if( src.cols == 1 && nonzero_rows > 0 )
-        CV_Error( CV_StsNotImplemented,
-        "This mode (using nonzero_rows with a single-column matrix) breaks the function's logic, so it is prohibited.\n"
-        "For fast convolution/correlation use 2-column matrix or single-row matrix instead" );
+            int stage = stages[stageIndex];
+            bool isLastStage = (stageIndex + 1 == stages.size());
+            bool isComplex = stage_src_channels != stage_dst_channels;
 
-    // determine, which transform to do first - row-wise
-    // (stage 0) or column-wise (stage 1) transform
-    if( !(flags & DFT_ROWS) && src.rows > 1 &&
-        ((src.cols == 1 && (!src.isContinuous() || !dst.isContinuous())) ||
-         (src.cols > 1 && inv && real_transform)) )
-        stage = 1;
+            if( stage == 0 )
+                rowDft(src, src_step, dst, dst_step, isComplex, isLastStage);
+            else
+                colDft(src, src_step, dst, dst_step, stage_src_channels, stage_dst_channels, isLastStage);
+        }
+    }
 
-    for(;;)
-    {
-        double scale = 1;
-        uchar* wave = 0;
-        int* itab = 0;
-        uchar* ptr;
-        int i, len, count, sz = 0;
-        int use_buf = 0, odd_real = 0;
-        DFTFunc dft_func;
+protected:
 
-        if( stage == 0 ) // row-wise transform
+    void rowDft(const uchar* src_data, size_t src_step, uchar* dst_data, size_t dst_step, bool isComplex, bool isLastStage)
+    {
+        int len, count;
+        if (width == 1 && !isRowTransform )
         {
-            len = !inv ? src.cols : dst.cols;
-            count = src.rows;
-            if( len == 1 && !(flags & DFT_ROWS) )
-            {
-                len = !inv ? src.rows : dst.rows;
-                count = 1;
-            }
-            odd_real = real_transform && (len & 1);
+            len = height;
+            count = width;
         }
         else
         {
-            len = dst.rows;
-            count = !inv ? src0.cols : dst.cols;
-            sz = 2*len*complex_elem_size;
+            len = width;
+            count = height;
         }
+        int dptr_offset = 0;
+        int dst_full_len = len*elem_size;
 
-        void *spec = 0;
-#ifdef USE_IPP_DFT
-        if( CV_IPP_CHECK_COND && (len*count >= 64) ) // use IPP DFT if available
+        if( needBufferA )
         {
-            int specsize=0, initsize=0, worksize=0;
-            IppDFTGetSizeFunc getSizeFunc = 0;
-            IppDFTInitFunc initFunc = 0;
+            if (mode == FwdRealToCCS && (len & 1) && len > 1)
+                dptr_offset = elem_size;
+        }
 
-            if( real_transform && stage == 0 )
+        if( !inv && isComplex )
+            dst_full_len += (len & 1) ? elem_size : complex_elem_size;
+
+        int nz = nonzero_rows;
+        if( nz <= 0 || nz > count )
+            nz = count;
+
+        int i;
+        for( i = 0; i < nz; i++ )
+        {
+            const uchar* sptr = src_data + src_step * i;
+            uchar* dptr0 = dst_data + dst_step * i;
+            uchar* dptr = dptr0;
+
+            if( needBufferA )
+                dptr = tmp_bufA;
+
+            contextA->apply(sptr, dptr);
+
+            if( needBufferA )
+                memcpy( dptr0, dptr + dptr_offset, dst_full_len );
+        }
+
+        for( ; i < count; i++ )
+        {
+            uchar* dptr0 = dst_data + dst_step * i;
+            memset( dptr0, 0, dst_full_len );
+        }
+        if(isLastStage &&  mode == FwdRealToComplex)
+            complementComplexOutput(depth, dst_data, dst_step, len, nz, 1);
+    }
+
+    void colDft(const uchar* src_data, size_t src_step, uchar* dst_data, size_t dst_step, int stage_src_channels, int stage_dst_channels, bool isLastStage)
+    {
+        int len = height;
+        int count = width;
+        int a = 0, b = count;
+        uchar *dbuf0, *dbuf1;
+        const uchar* sptr0 = src_data;
+        uchar* dptr0 = dst_data;
+
+        dbuf0 = buf0, dbuf1 = buf1;
+
+        if( needBufferB )
+        {
+            dbuf1 = tmp_bufB;
+            dbuf0 = buf1;
+        }
+
+        if( real_transform )
+        {
+            int even;
+            a = 1;
+            even = (count & 1) == 0;
+            b = (count+1)/2;
+            if( !inv )
             {
-                if( depth == CV_32F )
+                memset( buf0, 0, len*complex_elem_size );
+                CopyColumn( sptr0, src_step, buf0, complex_elem_size, len, elem_size );
+                sptr0 += stage_dst_channels*elem_size;
+                if( even )
                 {
-                    getSizeFunc = ippsDFTGetSize_R_32f;
-                    initFunc = (IppDFTInitFunc)ippsDFTInit_R_32f;
+                    memset( buf1, 0, len*complex_elem_size );
+                    CopyColumn( sptr0 + (count-2)*elem_size, src_step,
+                                buf1, complex_elem_size, len, elem_size );
                 }
-                else
+            }
+            else if( stage_src_channels == 1 )
+            {
+                CopyColumn( sptr0, src_step, buf0, elem_size, len, elem_size );
+                ExpandCCS( buf0, len, elem_size );
+                if( even )
                 {
-                    getSizeFunc = ippsDFTGetSize_R_64f;
-                    initFunc = (IppDFTInitFunc)ippsDFTInit_R_64f;
+                    CopyColumn( sptr0 + (count-1)*elem_size, src_step,
+                                buf1, elem_size, len, elem_size );
+                    ExpandCCS( buf1, len, elem_size );
                 }
+                sptr0 += elem_size;
             }
             else
             {
-                if( depth == CV_32F )
+                CopyColumn( sptr0, src_step, buf0, complex_elem_size, len, complex_elem_size );
+                if( even )
                 {
-                    getSizeFunc = ippsDFTGetSize_C_32fc;
-                    initFunc = (IppDFTInitFunc)ippsDFTInit_C_32fc;
+                    CopyColumn( sptr0 + b*complex_elem_size, src_step,
+                                   buf1, complex_elem_size, len, complex_elem_size );
+                }
+                sptr0 += complex_elem_size;
+            }
+
+            if( even )
+                contextB->apply(buf1, dbuf1);
+            contextB->apply(buf0, dbuf0);
+
+            if( stage_dst_channels == 1 )
+            {
+                if( !inv )
+                {
+                    // copy the half of output vector to the first/last column.
+                    // before doing that, defgragment the vector
+                    memcpy( dbuf0 + elem_size, dbuf0, elem_size );
+                    CopyColumn( dbuf0 + elem_size, elem_size, dptr0,
+                                   dst_step, len, elem_size );
+                    if( even )
+                    {
+                        memcpy( dbuf1 + elem_size, dbuf1, elem_size );
+                        CopyColumn( dbuf1 + elem_size, elem_size,
+                                       dptr0 + (count-1)*elem_size,
+                                       dst_step, len, elem_size );
+                    }
+                    dptr0 += elem_size;
                 }
                 else
                 {
-                    getSizeFunc = ippsDFTGetSize_C_64fc;
-                    initFunc = (IppDFTInitFunc)ippsDFTInit_C_64fc;
+                    // copy the real part of the complex vector to the first/last column
+                    CopyColumn( dbuf0, complex_elem_size, dptr0, dst_step, len, elem_size );
+                    if( even )
+                        CopyColumn( dbuf1, complex_elem_size, dptr0 + (count-1)*elem_size,
+                                       dst_step, len, elem_size );
+                    dptr0 += elem_size;
                 }
             }
-            if( getSizeFunc(len, ipp_norm_flag, ippAlgHintNone, &specsize, &initsize, &worksize) >= 0 )
-            {
-                ippbuf.allocate(specsize + initsize + 64);
-                spec = alignPtr(&ippbuf[0], 32);
-                uchar* initbuf = alignPtr((uchar*)spec + specsize, 32);
-                if( initFunc(len, ipp_norm_flag, ippAlgHintNone, spec, initbuf) < 0 )
-                    spec = 0;
-                sz += worksize;
-            }
             else
-                setIppErrorStatus();
-        }
-        else
-#endif
-        {
-            if( len != prev_len )
-                nf = DFTFactorize( len, factors );
-
-            inplace_transform = factors[0] == factors[nf-1];
-            sz += len*(complex_elem_size + sizeof(int));
-            i = nf > 1 && (factors[0] & 1) == 0;
-            if( (factors[i] & 1) != 0 && factors[i] > 5 )
-                sz += (factors[i]+1)*complex_elem_size;
-
-            if( (stage == 0 && ((src.data == dst.data && !inplace_transform) || odd_real)) ||
-                (stage == 1 && !inplace_transform) )
             {
-                use_buf = 1;
-                sz += len*complex_elem_size;
+                assert( !inv );
+                CopyColumn( dbuf0, complex_elem_size, dptr0,
+                               dst_step, len, complex_elem_size );
+                if( even )
+                    CopyColumn( dbuf1, complex_elem_size,
+                                   dptr0 + b*complex_elem_size,
+                                   dst_step, len, complex_elem_size );
+                dptr0 += complex_elem_size;
             }
         }
 
-        ptr = (uchar*)buf;
-        buf.allocate( sz + 32 );
-        if( ptr != (uchar*)buf )
-            prev_len = 0; // because we release the buffer,
-                          // force recalculation of
-                          // twiddle factors and permutation table
-        ptr = (uchar*)buf;
-        if( !spec )
-        {
-            wave = ptr;
-            ptr += len*complex_elem_size;
-            itab = (int*)ptr;
-            ptr = (uchar*)cvAlignPtr( ptr + len*sizeof(int), 16 );
-
-            if( len != prev_len || (!inplace_transform && inv && real_transform))
-                DFTInit( len, nf, factors, itab, complex_elem_size,
-                            wave, stage == 0 && inv && real_transform );
-            // otherwise reuse the tables calculated on the previous stage
-        }
-
-        if( stage == 0 )
+        for(int i = a; i < b; i += 2 )
         {
-            uchar* tmp_buf = 0;
-            int dptr_offset = 0;
-            int dst_full_len = len*elem_size;
-            int _flags = (int)inv + (src.channels() != dst.channels() ?
-                         DFT_COMPLEX_INPUT_OR_OUTPUT : 0);
-            if( use_buf )
+            if( i+1 < b )
             {
-                tmp_buf = ptr;
-                ptr += len*complex_elem_size;
-                if( odd_real && !inv && len > 1 &&
-                    !(_flags & DFT_COMPLEX_INPUT_OR_OUTPUT))
-                    dptr_offset = elem_size;
+                CopyFrom2Columns( sptr0, src_step, buf0, buf1, len, complex_elem_size );
+                contextB->apply(buf1, dbuf1);
             }
+            else
+                CopyColumn( sptr0, src_step, buf0, complex_elem_size, len, complex_elem_size );
 
-            if( !inv && (_flags & DFT_COMPLEX_INPUT_OR_OUTPUT) )
-                dst_full_len += (len & 1) ? elem_size : complex_elem_size;
-
-            dft_func = dft_tbl[(!real_transform ? 0 : !inv ? 1 : 2) + (depth == CV_64F)*3];
-
-            if( count > 1 && !(flags & DFT_ROWS) && (!inv || !real_transform) )
-                stage = 1;
-            else if( flags & CV_DXT_SCALE )
-                scale = 1./(len * (flags & DFT_ROWS ? 1 : count));
+            contextB->apply(buf0, dbuf0);
 
-            if( nonzero_rows <= 0 || nonzero_rows > count )
-                nonzero_rows = count;
+            if( i+1 < b )
+                CopyTo2Columns( dbuf0, dbuf1, dptr0, dst_step, len, complex_elem_size );
+            else
+                CopyColumn( dbuf0, complex_elem_size, dptr0, dst_step, len, complex_elem_size );
+            sptr0 += 2*complex_elem_size;
+            dptr0 += 2*complex_elem_size;
+        }
+        if(isLastStage && mode == FwdRealToComplex)
+            complementComplexOutput(depth, dst_data, dst_step, count, len, 2);
+    }
+};
 
-            for( i = 0; i < nonzero_rows; i++ )
-            {
-                const uchar* sptr = src.ptr(i);
-                uchar* dptr0 = dst.ptr(i);
-                uchar* dptr = dptr0;
-
-                if( tmp_buf )
-                    dptr = tmp_buf;
-
-                dft_func( sptr, dptr, len, nf, factors, itab, wave, len, spec, ptr, _flags, scale );
-                if( dptr != dptr0 )
-                    memcpy( dptr0, dptr + dptr_offset, dst_full_len );
-            }
+class OcvDftBasicImpl : public hal::DFT1D
+{
+public:
+    OcvDftOptions opt;
+    int _factors[34];
+    AutoBuffer<uchar> wave_buf;
+    AutoBuffer<int> itab_buf;
+#ifdef USE_IPP_DFT
+    AutoBuffer<uchar> ippbuf;
+    AutoBuffer<uchar> ippworkbuf;
+#endif
 
-            for( ; i < count; i++ )
-            {
-                uchar* dptr0 = dst.ptr(i);
-                memset( dptr0, 0, dst_full_len );
-            }
+public:
+    OcvDftBasicImpl()
+    {
+        opt.factors = _factors;
+    }
+    void init(int len, int count, int depth, int flags, bool *needBuffer)
+    {
+        int prev_len = opt.n;
 
-            if( stage != 1 )
-            {
-                if( !inv && real_transform && dst.channels() == 2 )
-                    complementComplexOutput(dst, nonzero_rows, 1);
-                break;
-            }
-            src = dst;
-        }
-        else
-        {
-            int a = 0, b = count;
-            uchar *buf0, *buf1, *dbuf0, *dbuf1;
-            const uchar* sptr0 = src.ptr();
-            uchar* dptr0 = dst.ptr();
-            buf0 = ptr;
-            ptr += len*complex_elem_size;
-            buf1 = ptr;
-            ptr += len*complex_elem_size;
-            dbuf0 = buf0, dbuf1 = buf1;
+        int stage = (flags & CV_HAL_DFT_STAGE_COLS) != 0 ? 1 : 0;
+        int complex_elem_size = depth == CV_32F ? sizeof(Complex<float>) : sizeof(Complex<double>);
+        opt.isInverse = (flags & CV_HAL_DFT_INVERSE) != 0;
+        bool real_transform = (flags & CV_HAL_DFT_REAL_OUTPUT) != 0;
+        opt.isComplex = (stage == 0) && (flags & CV_HAL_DFT_COMPLEX_OUTPUT) != 0;
+        bool needAnotherStage = (flags & CV_HAL_DFT_TWO_STAGE) != 0;
 
-            if( use_buf )
-            {
-                dbuf1 = ptr;
-                dbuf0 = buf1;
-                ptr += len*complex_elem_size;
-            }
+        opt.scale = 1;
+        opt.tab_size = len;
+        opt.n = len;
 
-            dft_func = dft_tbl[(depth == CV_64F)*3];
+        opt.useIpp = false;
+    #ifdef USE_IPP_DFT
+        opt.ipp_spec = 0;
+        opt.ipp_work = 0;
 
-            if( real_transform && inv && src.cols > 1 )
-                stage = 0;
-            else if( flags & CV_DXT_SCALE )
-                scale = 1./(len * count);
+        if( CV_IPP_CHECK_COND && (opt.n*count >= 64) ) // use IPP DFT if available
+        {
+            int ipp_norm_flag = (flags & CV_HAL_DFT_SCALE) == 0 ? 8 : opt.isInverse ? 2 : 1;
+            int specsize=0, initsize=0, worksize=0;
+            IppDFTGetSizeFunc getSizeFunc = 0;
+            IppDFTInitFunc initFunc = 0;
 
-            if( real_transform )
+            if( real_transform && stage == 0 )
             {
-                int even;
-                a = 1;
-                even = (count & 1) == 0;
-                b = (count+1)/2;
-                if( !inv )
-                {
-                    memset( buf0, 0, len*complex_elem_size );
-                    CopyColumn( sptr0, src.step, buf0, complex_elem_size, len, elem_size );
-                    sptr0 += dst.channels()*elem_size;
-                    if( even )
-                    {
-                        memset( buf1, 0, len*complex_elem_size );
-                        CopyColumn( sptr0 + (count-2)*elem_size, src.step,
-                                    buf1, complex_elem_size, len, elem_size );
-                    }
-                }
-                else if( src.channels() == 1 )
+                if( depth == CV_32F )
                 {
-                    CopyColumn( sptr0, src.step, buf0, elem_size, len, elem_size );
-                    ExpandCCS( buf0, len, elem_size );
-                    if( even )
-                    {
-                        CopyColumn( sptr0 + (count-1)*elem_size, src.step,
-                                    buf1, elem_size, len, elem_size );
-                        ExpandCCS( buf1, len, elem_size );
-                    }
-                    sptr0 += elem_size;
+                    getSizeFunc = ippsDFTGetSize_R_32f;
+                    initFunc = (IppDFTInitFunc)ippsDFTInit_R_32f;
                 }
                 else
                 {
-                    CopyColumn( sptr0, src.step, buf0, complex_elem_size, len, complex_elem_size );
-                    if( even )
-                    {
-                        CopyColumn( sptr0 + b*complex_elem_size, src.step,
-                                       buf1, complex_elem_size, len, complex_elem_size );
-                    }
-                    sptr0 += complex_elem_size;
+                    getSizeFunc = ippsDFTGetSize_R_64f;
+                    initFunc = (IppDFTInitFunc)ippsDFTInit_R_64f;
                 }
-
-                if( even )
-                    dft_func( buf1, dbuf1, len, nf, factors, itab,
-                              wave, len, spec, ptr, inv, scale );
-                dft_func( buf0, dbuf0, len, nf, factors, itab,
-                          wave, len, spec, ptr, inv, scale );
-
-                if( dst.channels() == 1 )
+            }
+            else
+            {
+                if( depth == CV_32F )
                 {
-                    if( !inv )
-                    {
-                        // copy the half of output vector to the first/last column.
-                        // before doing that, defgragment the vector
-                        memcpy( dbuf0 + elem_size, dbuf0, elem_size );
-                        CopyColumn( dbuf0 + elem_size, elem_size, dptr0,
-                                       dst.step, len, elem_size );
-                        if( even )
-                        {
-                            memcpy( dbuf1 + elem_size, dbuf1, elem_size );
-                            CopyColumn( dbuf1 + elem_size, elem_size,
-                                           dptr0 + (count-1)*elem_size,
-                                           dst.step, len, elem_size );
-                        }
-                        dptr0 += elem_size;
-                    }
-                    else
-                    {
-                        // copy the real part of the complex vector to the first/last column
-                        CopyColumn( dbuf0, complex_elem_size, dptr0, dst.step, len, elem_size );
-                        if( even )
-                            CopyColumn( dbuf1, complex_elem_size, dptr0 + (count-1)*elem_size,
-                                           dst.step, len, elem_size );
-                        dptr0 += elem_size;
-                    }
+                    getSizeFunc = ippsDFTGetSize_C_32fc;
+                    initFunc = (IppDFTInitFunc)ippsDFTInit_C_32fc;
                 }
                 else
                 {
-                    assert( !inv );
-                    CopyColumn( dbuf0, complex_elem_size, dptr0,
-                                   dst.step, len, complex_elem_size );
-                    if( even )
-                        CopyColumn( dbuf1, complex_elem_size,
-                                       dptr0 + b*complex_elem_size,
-                                       dst.step, len, complex_elem_size );
-                    dptr0 += complex_elem_size;
+                    getSizeFunc = ippsDFTGetSize_C_64fc;
+                    initFunc = (IppDFTInitFunc)ippsDFTInit_C_64fc;
                 }
             }
+            if( getSizeFunc(opt.n, ipp_norm_flag, ippAlgHintNone, &specsize, &initsize, &worksize) >= 0 )
+            {
+                ippbuf.allocate(specsize + initsize + 64);
+                opt.ipp_spec = alignPtr(&ippbuf[0], 32);
+                ippworkbuf.allocate(worksize + 32);
+                opt.ipp_work = alignPtr(&ippworkbuf[0], 32);
+                uchar* initbuf = alignPtr((uchar*)opt.ipp_spec + specsize, 32);
+                if( initFunc(opt.n, ipp_norm_flag, ippAlgHintNone, opt.ipp_spec, initbuf) >= 0 )
+                    opt.useIpp = true;
+            }
+            else
+                setIppErrorStatus();
+        }
+    #endif
 
-            for( i = a; i < b; i += 2 )
+        if (!opt.useIpp)
+        {
+            if (len != prev_len)
             {
-                if( i+1 < b )
+                opt.nf = DFTFactorize( opt.n, opt.factors );
+            }
+            bool inplace_transform = opt.factors[0] == opt.factors[opt.nf-1];
+            if (len != prev_len || (!inplace_transform && opt.isInverse && real_transform))
+            {
+                wave_buf.allocate(opt.n*complex_elem_size);
+                opt.wave = wave_buf;
+                itab_buf.allocate(opt.n);
+                opt.itab = itab_buf;
+                DFTInit( opt.n, opt.nf, opt.factors, opt.itab, complex_elem_size,
+                         opt.wave, stage == 0 && opt.isInverse && real_transform );
+            }
+            // otherwise reuse the tables calculated on the previous stage
+            if (needBuffer)
+            {
+                if( (stage == 0 && ((*needBuffer && !inplace_transform) || (real_transform && (len & 1)))) ||
+                    (stage == 1 && !inplace_transform) )
                 {
-                    CopyFrom2Columns( sptr0, src.step, buf0, buf1, len, complex_elem_size );
-                    dft_func( buf1, dbuf1, len, nf, factors, itab,
-                              wave, len, spec, ptr, inv, scale );
+                    *needBuffer = true;
                 }
-                else
-                    CopyColumn( sptr0, src.step, buf0, complex_elem_size, len, complex_elem_size );
-
-                dft_func( buf0, dbuf0, len, nf, factors, itab,
-                          wave, len, spec, ptr, inv, scale );
-
-                if( i+1 < b )
-                    CopyTo2Columns( dbuf0, dbuf1, dptr0, dst.step, len, complex_elem_size );
-                else
-                    CopyColumn( dbuf0, complex_elem_size, dptr0, dst.step, len, complex_elem_size );
-                sptr0 += 2*complex_elem_size;
-                dptr0 += 2*complex_elem_size;
             }
+        }
+        else
+        {
+            if (needBuffer)
+            {
+                *needBuffer = false;
+            }
+        }
 
-            if( stage != 0 )
+        {
+            static DFTFunc dft_tbl[6] =
             {
-                if( !inv && real_transform && dst.channels() == 2 && len > 1 )
-                    complementComplexOutput(dst, len, 2);
-                break;
+                (DFTFunc)DFT_32f,
+                (DFTFunc)RealDFT_32f,
+                (DFTFunc)CCSIDFT_32f,
+                (DFTFunc)DFT_64f,
+                (DFTFunc)RealDFT_64f,
+                (DFTFunc)CCSIDFT_64f
+            };
+            int idx = 0;
+            if (stage == 0)
+            {
+                if (real_transform)
+                {
+                    if (!opt.isInverse)
+                        idx = 1;
+                    else
+                        idx = 2;
+                }
             }
-            src = dst;
+            if (depth == CV_64F)
+                idx += 3;
+
+            opt.dft_func = dft_tbl[idx];
+        }
+
+        if(!needAnotherStage && (flags & CV_HAL_DFT_SCALE) != 0)
+        {
+            int rowCount = count;
+            if (stage == 0 && (flags & CV_HAL_DFT_ROWS) != 0)
+                rowCount = 1;
+            opt.scale = 1./(len * rowCount);
+        }
+    }
+
+    void apply(const uchar *src, uchar *dst)
+    {
+        opt.dft_func(opt, src, dst);
+    }
+
+    void free() {}
+};
+
+struct ReplacementDFT1D : public hal::DFT1D
+{
+    cvhalDFT *context;
+    bool isInitialized;
+
+    ReplacementDFT1D() : context(0), isInitialized(false) {}
+    bool init(int len, int count, int depth, int flags, bool *needBuffer)
+    {
+        int res = cv_hal_dftInit1D(&context, len, count, depth, flags, needBuffer);
+        isInitialized = (res == CV_HAL_ERROR_OK);
+        return isInitialized;
+    }
+    void apply(const uchar *src, uchar *dst)
+    {
+        if (isInitialized)
+        {
+            CALL_HAL(dft1D, cv_hal_dft1D, context, src, dst);
+        }
+    }
+    ~ReplacementDFT1D()
+    {
+        if (isInitialized)
+        {
+            CALL_HAL(dftFree1D, cv_hal_dftFree1D, context);
+        }
+    }
+};
+
+struct ReplacementDFT2D : public hal::DFT2D
+{
+    cvhalDFT *context;
+    bool isInitialized;
+
+    ReplacementDFT2D() : context(0), isInitialized(false) {}
+    bool init(int width, int height, int depth,
+              int src_channels, int dst_channels,
+              int flags, int nonzero_rows)
+    {
+        int res = cv_hal_dftInit2D(&context, width, height, depth, src_channels, dst_channels, flags, nonzero_rows);
+        isInitialized = (res == CV_HAL_ERROR_OK);
+        return isInitialized;
+    }
+    void apply(const uchar *src, size_t src_step, uchar *dst, size_t dst_step)
+    {
+        if (isInitialized)
+        {
+            CALL_HAL(dft2D, cv_hal_dft2D, context, src, src_step, dst, dst_step);
         }
     }
+    ~ReplacementDFT2D()
+    {
+        if (isInitialized)
+        {
+            CALL_HAL(dftFree2D, cv_hal_dftFree1D, context);
+        }
+    }
+};
+
+namespace hal {
+
+//================== 1D ======================
+
+Ptr<DFT1D> DFT1D::create(int len, int count, int depth, int flags, bool *needBuffer)
+{
+    {
+        ReplacementDFT1D *impl = new ReplacementDFT1D();
+        if (impl->init(len, count, depth, flags, needBuffer))
+        {
+            return Ptr<DFT1D>(impl);
+        }
+        delete impl;
+    }
+    {
+        OcvDftBasicImpl *impl = new OcvDftBasicImpl();
+        impl->init(len, count, depth, flags, needBuffer);
+        return Ptr<DFT1D>(impl);
+    }
+}
+
+//================== 2D ======================
+
+Ptr<DFT2D> DFT2D::create(int width, int height, int depth,
+                         int src_channels, int dst_channels,
+                         int flags, int nonzero_rows)
+{
+    {
+        ReplacementDFT2D *impl = new ReplacementDFT2D();
+        if (impl->init(width, height, depth, src_channels, dst_channels, flags, nonzero_rows))
+        {
+            return Ptr<DFT2D>(impl);
+        }
+        delete impl;
+    }
+    {
+        if(width == 1 && nonzero_rows > 0 )
+        {
+            CV_Error( CV_StsNotImplemented,
+            "This mode (using nonzero_rows with a single-column matrix) breaks the function's logic, so it is prohibited.\n"
+            "For fast convolution/correlation use 2-column matrix or single-row matrix instead" );
+        }
+        OcvDftImpl *impl = new OcvDftImpl();
+        impl->init(width, height, depth, src_channels, dst_channels, flags, nonzero_rows);
+        return Ptr<DFT2D>(impl);
+    }
+}
+
+} // cv::hal::
+} // cv::
+
+
+void cv::dft( InputArray _src0, OutputArray _dst, int flags, int nonzero_rows )
+{
+    CV_INSTRUMENT_REGION()
+
+#ifdef HAVE_CLAMDFFT
+    CV_OCL_RUN(ocl::haveAmdFft() && ocl::Device::getDefault().type() != ocl::Device::TYPE_CPU &&
+            _dst.isUMat() && _src0.dims() <= 2 && nonzero_rows == 0,
+               ocl_dft_amdfft(_src0, _dst, flags))
+#endif
+
+#ifdef HAVE_OPENCL
+    CV_OCL_RUN(_dst.isUMat() && _src0.dims() <= 2,
+               ocl_dft(_src0, _dst, flags, nonzero_rows))
+#endif
+
+    Mat src0 = _src0.getMat(), src = src0;
+    bool inv = (flags & DFT_INVERSE) != 0;
+    int type = src.type();
+    int depth = src.depth();
+
+    CV_Assert( type == CV_32FC1 || type == CV_32FC2 || type == CV_64FC1 || type == CV_64FC2 );
+
+    if( !inv && src.channels() == 1 && (flags & DFT_COMPLEX_OUTPUT) )
+        _dst.create( src.size(), CV_MAKETYPE(depth, 2) );
+    else if( inv && src.channels() == 2 && (flags & DFT_REAL_OUTPUT) )
+        _dst.create( src.size(), depth );
+    else
+        _dst.create( src.size(), type );
+
+    Mat dst = _dst.getMat();
+
+    int f = 0;
+    if (src.isContinuous() && dst.isContinuous())
+        f |= CV_HAL_DFT_IS_CONTINUOUS;
+    if (inv)
+        f |= CV_HAL_DFT_INVERSE;
+    if (flags & DFT_ROWS)
+        f |= CV_HAL_DFT_ROWS;
+    if (flags & DFT_SCALE)
+        f |= CV_HAL_DFT_SCALE;
+    if (src.data == dst.data)
+        f |= CV_HAL_DFT_IS_INPLACE;
+    Ptr<hal::DFT2D> c = hal::DFT2D::create(src.cols, src.rows, depth, src.channels(), dst.channels(), f, nonzero_rows);
+    c->apply(src.data, src.step, dst.data, dst.step);
 }
 
 
 void cv::idft( InputArray src, OutputArray dst, int flags, int nonzero_rows )
 {
+    CV_INSTRUMENT_REGION()
+
     dft( src, dst, flags | DFT_INVERSE, nonzero_rows );
 }
 
@@ -2942,16 +3412,136 @@ static bool ocl_mulSpectrums( InputArray _srcA, InputArray _srcB,
 
 #endif
 
+namespace {
+
+#define VAL(buf, elem) (((T*)((char*)data ## buf + (step ## buf * (elem))))[0])
+#define MUL_SPECTRUMS_COL(A, B, C) \
+    VAL(C, 0) = VAL(A, 0) * VAL(B, 0); \
+    for (size_t j = 1; j <= rows - 2; j += 2) \
+    { \
+        double a_re = VAL(A, j), a_im = VAL(A, j + 1); \
+        double b_re = VAL(B, j), b_im = VAL(B, j + 1); \
+        if (conjB) b_im = -b_im; \
+        double c_re = a_re * b_re - a_im * b_im; \
+        double c_im = a_re * b_im + a_im * b_re; \
+        VAL(C, j) = (T)c_re; VAL(C, j + 1) = (T)c_im; \
+    } \
+    if ((rows & 1) == 0) \
+        VAL(C, rows-1) = VAL(A, rows-1) * VAL(B, rows-1)
+
+template <typename T, bool conjB> static inline
+void mulSpectrums_processCol_noinplace(const T* dataA, const T* dataB, T* dataC, size_t stepA, size_t stepB, size_t stepC, size_t rows)
+{
+    MUL_SPECTRUMS_COL(A, B, C);
+}
+
+template <typename T, bool conjB> static inline
+void mulSpectrums_processCol_inplaceA(const T* dataB, T* dataAC, size_t stepB, size_t stepAC, size_t rows)
+{
+    MUL_SPECTRUMS_COL(AC, B, AC);
+}
+template <typename T, bool conjB, bool inplaceA> static inline
+void mulSpectrums_processCol(const T* dataA, const T* dataB, T* dataC, size_t stepA, size_t stepB, size_t stepC, size_t rows)
+{
+    if (inplaceA)
+        mulSpectrums_processCol_inplaceA<T, conjB>(dataB, dataC, stepB, stepC, rows);
+    else
+        mulSpectrums_processCol_noinplace<T, conjB>(dataA, dataB, dataC, stepA, stepB, stepC, rows);
+}
+#undef MUL_SPECTRUMS_COL
+#undef VAL
+
+template <typename T, bool conjB, bool inplaceA> static inline
+void mulSpectrums_processCols(const T* dataA, const T* dataB, T* dataC, size_t stepA, size_t stepB, size_t stepC, size_t rows, size_t cols)
+{
+    mulSpectrums_processCol<T, conjB, inplaceA>(dataA, dataB, dataC, stepA, stepB, stepC, rows);
+    if ((cols & 1) == 0)
+    {
+        mulSpectrums_processCol<T, conjB, inplaceA>(dataA + cols - 1, dataB + cols - 1, dataC + cols - 1, stepA, stepB, stepC, rows);
+    }
+}
+
+#define VAL(buf, elem) (data ## buf[(elem)])
+#define MUL_SPECTRUMS_ROW(A, B, C) \
+    for (size_t j = j0; j < j1; j += 2) \
+    { \
+        double a_re = VAL(A, j), a_im = VAL(A, j + 1); \
+        double b_re = VAL(B, j), b_im = VAL(B, j + 1); \
+        if (conjB) b_im = -b_im; \
+        double c_re = a_re * b_re - a_im * b_im; \
+        double c_im = a_re * b_im + a_im * b_re; \
+        VAL(C, j) = (T)c_re; VAL(C, j + 1) = (T)c_im; \
+    }
+template <typename T, bool conjB> static inline
+void mulSpectrums_processRow_noinplace(const T* dataA, const T* dataB, T* dataC, size_t j0, size_t j1)
+{
+    MUL_SPECTRUMS_ROW(A, B, C);
+}
+template <typename T, bool conjB> static inline
+void mulSpectrums_processRow_inplaceA(const T* dataB, T* dataAC, size_t j0, size_t j1)
+{
+    MUL_SPECTRUMS_ROW(AC, B, AC);
+}
+template <typename T, bool conjB, bool inplaceA> static inline
+void mulSpectrums_processRow(const T* dataA, const T* dataB, T* dataC, size_t j0, size_t j1)
+{
+    if (inplaceA)
+        mulSpectrums_processRow_inplaceA<T, conjB>(dataB, dataC, j0, j1);
+    else
+        mulSpectrums_processRow_noinplace<T, conjB>(dataA, dataB, dataC, j0, j1);
+}
+#undef MUL_SPECTRUMS_ROW
+#undef VAL
+
+template <typename T, bool conjB, bool inplaceA> static inline
+void mulSpectrums_processRows(const T* dataA, const T* dataB, T* dataC, size_t stepA, size_t stepB, size_t stepC, size_t rows, size_t cols, size_t j0, size_t j1, bool is_1d_CN1)
+{
+    while (rows-- > 0)
+    {
+        if (is_1d_CN1)
+            dataC[0] = dataA[0]*dataB[0];
+        mulSpectrums_processRow<T, conjB, inplaceA>(dataA, dataB, dataC, j0, j1);
+        if (is_1d_CN1 && (cols & 1) == 0)
+            dataC[j1] = dataA[j1]*dataB[j1];
+
+        dataA = (const T*)(((char*)dataA) + stepA);
+        dataB = (const T*)(((char*)dataB) + stepB);
+        dataC =       (T*)(((char*)dataC) + stepC);
+    }
+}
+
+
+template <typename T, bool conjB, bool inplaceA> static inline
+void mulSpectrums_Impl_(const T* dataA, const T* dataB, T* dataC, size_t stepA, size_t stepB, size_t stepC, size_t rows, size_t cols, size_t j0, size_t j1, bool is_1d, bool isCN1)
+{
+    if (!is_1d && isCN1)
+    {
+        mulSpectrums_processCols<T, conjB, inplaceA>(dataA, dataB, dataC, stepA, stepB, stepC, rows, cols);
+    }
+    mulSpectrums_processRows<T, conjB, inplaceA>(dataA, dataB, dataC, stepA, stepB, stepC, rows, cols, j0, j1, is_1d && isCN1);
+}
+template <typename T, bool conjB> static inline
+void mulSpectrums_Impl(const T* dataA, const T* dataB, T* dataC, size_t stepA, size_t stepB, size_t stepC, size_t rows, size_t cols, size_t j0, size_t j1, bool is_1d, bool isCN1)
+{
+    if (dataA == dataC)
+        mulSpectrums_Impl_<T, conjB, true>(dataA, dataB, dataC, stepA, stepB, stepC, rows, cols, j0, j1, is_1d, isCN1);
+    else
+        mulSpectrums_Impl_<T, conjB, false>(dataA, dataB, dataC, stepA, stepB, stepC, rows, cols, j0, j1, is_1d, isCN1);
+}
+
+} // namespace
+
 void cv::mulSpectrums( InputArray _srcA, InputArray _srcB,
                        OutputArray _dst, int flags, bool conjB )
 {
+    CV_INSTRUMENT_REGION()
+
     CV_OCL_RUN(_dst.isUMat() && _srcA.dims() <= 2 && _srcB.dims() <= 2,
             ocl_mulSpectrums(_srcA, _srcB, _dst, flags, conjB))
 
     Mat srcA = _srcA.getMat(), srcB = _srcB.getMat();
     int depth = srcA.depth(), cn = srcA.channels(), type = srcA.type();
-    int rows = srcA.rows, cols = srcA.cols;
-    int j, k;
+    size_t rows = srcA.rows, cols = srcA.cols;
 
     CV_Assert( type == srcB.type() && srcA.size() == srcB.size() );
     CV_Assert( type == CV_32FC1 || type == CV_32FC2 || type == CV_64FC1 || type == CV_64FC2 );
@@ -2959,149 +3549,42 @@ void cv::mulSpectrums( InputArray _srcA, InputArray _srcB,
     _dst.create( srcA.rows, srcA.cols, type );
     Mat dst = _dst.getMat();
 
-    bool is_1d = (flags & DFT_ROWS) || (rows == 1 || (cols == 1 &&
-             srcA.isContinuous() && srcB.isContinuous() && dst.isContinuous()));
+    // correct inplace support
+    // Case 'dst.data == srcA.data' is handled by implementation,
+    // because it is used frequently (filter2D, matchTemplate)
+    if (dst.data == srcB.data)
+        srcB = srcB.clone(); // workaround for B only
+
+    bool is_1d = (flags & DFT_ROWS)
+        || (rows == 1)
+        || (cols == 1 && srcA.isContinuous() && srcB.isContinuous() && dst.isContinuous());
 
     if( is_1d && !(flags & DFT_ROWS) )
         cols = cols + rows - 1, rows = 1;
 
-    int ncols = cols*cn;
-    int j0 = cn == 1;
-    int j1 = ncols - (cols % 2 == 0 && cn == 1);
+    bool isCN1 = cn == 1;
+    size_t j0 = isCN1 ? 1 : 0;
+    size_t j1 = cols*cn - (((cols & 1) == 0 && cn == 1) ? 1 : 0);
 
-    if( depth == CV_32F )
+    if (depth == CV_32F)
     {
         const float* dataA = srcA.ptr<float>();
         const float* dataB = srcB.ptr<float>();
         float* dataC = dst.ptr<float>();
-
-        size_t stepA = srcA.step/sizeof(dataA[0]);
-        size_t stepB = srcB.step/sizeof(dataB[0]);
-        size_t stepC = dst.step/sizeof(dataC[0]);
-
-        if( !is_1d && cn == 1 )
-        {
-            for( k = 0; k < (cols % 2 ? 1 : 2); k++ )
-            {
-                if( k == 1 )
-                    dataA += cols - 1, dataB += cols - 1, dataC += cols - 1;
-                dataC[0] = dataA[0]*dataB[0];
-                if( rows % 2 == 0 )
-                    dataC[(rows-1)*stepC] = dataA[(rows-1)*stepA]*dataB[(rows-1)*stepB];
-                if( !conjB )
-                    for( j = 1; j <= rows - 2; j += 2 )
-                    {
-                        double re = (double)dataA[j*stepA]*dataB[j*stepB] -
-                                    (double)dataA[(j+1)*stepA]*dataB[(j+1)*stepB];
-                        double im = (double)dataA[j*stepA]*dataB[(j+1)*stepB] +
-                                    (double)dataA[(j+1)*stepA]*dataB[j*stepB];
-                        dataC[j*stepC] = (float)re; dataC[(j+1)*stepC] = (float)im;
-                    }
-                else
-                    for( j = 1; j <= rows - 2; j += 2 )
-                    {
-                        double re = (double)dataA[j*stepA]*dataB[j*stepB] +
-                                    (double)dataA[(j+1)*stepA]*dataB[(j+1)*stepB];
-                        double im = (double)dataA[(j+1)*stepA]*dataB[j*stepB] -
-                                    (double)dataA[j*stepA]*dataB[(j+1)*stepB];
-                        dataC[j*stepC] = (float)re; dataC[(j+1)*stepC] = (float)im;
-                    }
-                if( k == 1 )
-                    dataA -= cols - 1, dataB -= cols - 1, dataC -= cols - 1;
-            }
-        }
-
-        for( ; rows--; dataA += stepA, dataB += stepB, dataC += stepC )
-        {
-            if( is_1d && cn == 1 )
-            {
-                dataC[0] = dataA[0]*dataB[0];
-                if( cols % 2 == 0 )
-                    dataC[j1] = dataA[j1]*dataB[j1];
-            }
-
-            if( !conjB )
-                for( j = j0; j < j1; j += 2 )
-                {
-                    double re = (double)dataA[j]*dataB[j] - (double)dataA[j+1]*dataB[j+1];
-                    double im = (double)dataA[j+1]*dataB[j] + (double)dataA[j]*dataB[j+1];
-                    dataC[j] = (float)re; dataC[j+1] = (float)im;
-                }
-            else
-                for( j = j0; j < j1; j += 2 )
-                {
-                    double re = (double)dataA[j]*dataB[j] + (double)dataA[j+1]*dataB[j+1];
-                    double im = (double)dataA[j+1]*dataB[j] - (double)dataA[j]*dataB[j+1];
-                    dataC[j] = (float)re; dataC[j+1] = (float)im;
-                }
-        }
+        if (!conjB)
+            mulSpectrums_Impl<float, false>(dataA, dataB, dataC, srcA.step, srcB.step, dst.step, rows, cols, j0, j1, is_1d, isCN1);
+        else
+            mulSpectrums_Impl<float, true>(dataA, dataB, dataC, srcA.step, srcB.step, dst.step, rows, cols, j0, j1, is_1d, isCN1);
     }
     else
     {
         const double* dataA = srcA.ptr<double>();
         const double* dataB = srcB.ptr<double>();
         double* dataC = dst.ptr<double>();
-
-        size_t stepA = srcA.step/sizeof(dataA[0]);
-        size_t stepB = srcB.step/sizeof(dataB[0]);
-        size_t stepC = dst.step/sizeof(dataC[0]);
-
-        if( !is_1d && cn == 1 )
-        {
-            for( k = 0; k < (cols % 2 ? 1 : 2); k++ )
-            {
-                if( k == 1 )
-                    dataA += cols - 1, dataB += cols - 1, dataC += cols - 1;
-                dataC[0] = dataA[0]*dataB[0];
-                if( rows % 2 == 0 )
-                    dataC[(rows-1)*stepC] = dataA[(rows-1)*stepA]*dataB[(rows-1)*stepB];
-                if( !conjB )
-                    for( j = 1; j <= rows - 2; j += 2 )
-                    {
-                        double re = dataA[j*stepA]*dataB[j*stepB] -
-                                    dataA[(j+1)*stepA]*dataB[(j+1)*stepB];
-                        double im = dataA[j*stepA]*dataB[(j+1)*stepB] +
-                                    dataA[(j+1)*stepA]*dataB[j*stepB];
-                        dataC[j*stepC] = re; dataC[(j+1)*stepC] = im;
-                    }
-                else
-                    for( j = 1; j <= rows - 2; j += 2 )
-                    {
-                        double re = dataA[j*stepA]*dataB[j*stepB] +
-                                    dataA[(j+1)*stepA]*dataB[(j+1)*stepB];
-                        double im = dataA[(j+1)*stepA]*dataB[j*stepB] -
-                                    dataA[j*stepA]*dataB[(j+1)*stepB];
-                        dataC[j*stepC] = re; dataC[(j+1)*stepC] = im;
-                    }
-                if( k == 1 )
-                    dataA -= cols - 1, dataB -= cols - 1, dataC -= cols - 1;
-            }
-        }
-
-        for( ; rows--; dataA += stepA, dataB += stepB, dataC += stepC )
-        {
-            if( is_1d && cn == 1 )
-            {
-                dataC[0] = dataA[0]*dataB[0];
-                if( cols % 2 == 0 )
-                    dataC[j1] = dataA[j1]*dataB[j1];
-            }
-
-            if( !conjB )
-                for( j = j0; j < j1; j += 2 )
-                {
-                    double re = dataA[j]*dataB[j] - dataA[j+1]*dataB[j+1];
-                    double im = dataA[j+1]*dataB[j] + dataA[j]*dataB[j+1];
-                    dataC[j] = re; dataC[j+1] = im;
-                }
-            else
-                for( j = j0; j < j1; j += 2 )
-                {
-                    double re = dataA[j]*dataB[j] + dataA[j+1]*dataB[j+1];
-                    double im = dataA[j+1]*dataB[j] - dataA[j]*dataB[j+1];
-                    dataC[j] = re; dataC[j+1] = im;
-                }
-        }
+        if (!conjB)
+            mulSpectrums_Impl<double, false>(dataA, dataB, dataC, srcA.step, srcB.step, dst.step, rows, cols, j0, j1, is_1d, isCN1);
+        else
+            mulSpectrums_Impl<double, true>(dataA, dataB, dataC, srcA.step, srcB.step, dst.step, rows, cols, j0, j1, is_1d, isCN1);
     }
 }
 
@@ -3117,11 +3600,12 @@ namespace cv
    http://www.ece.utexas.edu/~bevans/courses/ee381k/lectures/09_DCT/lecture9/:
 */
 template<typename T> static void
-DCT( const T* src, int src_step, T* dft_src, T* dft_dst, T* dst, int dst_step,
-     int n, int nf, int* factors, const int* itab, const Complex<T>* dft_wave,
-     const Complex<T>* dct_wave, const void* spec, Complex<T>* buf )
+DCT( const OcvDftOptions & c, const T* src, size_t src_step, T* dft_src, T* dft_dst, T* dst, size_t dst_step,
+     const Complex<T>* dct_wave )
 {
     static const T sin_45 = (T)0.70710678118654752440084436210485;
+
+    int n = c.n;
     int j, n2 = n >> 1;
 
     src_step /= sizeof(src[0]);
@@ -3140,8 +3624,7 @@ DCT( const T* src, int src_step, T* dft_src, T* dft_dst, T* dst, int dst_step,
         dft_src[n-j-1] = src[src_step];
     }
 
-    RealDFT( dft_src, dft_dst, n, nf, factors,
-             itab, dft_wave, n, spec, buf, 0, 1.0 );
+    RealDFT(c, dft_src, dft_dst);
     src = dft_dst;
 
     dst[0] = (T)(src[0]*dct_wave->re*sin_45);
@@ -3160,11 +3643,11 @@ DCT( const T* src, int src_step, T* dft_src, T* dft_dst, T* dst, int dst_step,
 
 
 template<typename T> static void
-IDCT( const T* src, int src_step, T* dft_src, T* dft_dst, T* dst, int dst_step,
-      int n, int nf, int* factors, const int* itab, const Complex<T>* dft_wave,
-      const Complex<T>* dct_wave, const void* spec, Complex<T>* buf )
+IDCT( const OcvDftOptions & c, const T* src, size_t src_step, T* dft_src, T* dft_dst, T* dst, size_t dst_step,
+      const Complex<T>* dct_wave)
 {
     static const T sin_45 = (T)0.70710678118654752440084436210485;
+    int n = c.n;
     int j, n2 = n >> 1;
 
     src_step /= sizeof(src[0]);
@@ -3189,8 +3672,7 @@ IDCT( const T* src, int src_step, T* dft_src, T* dft_dst, T* dst, int dst_step,
     }
 
     dft_src[n-1] = (T)(src[0]*2*dct_wave->re);
-    CCSIDFT( dft_src, dft_dst, n, nf, factors, itab,
-             dft_wave, n, spec, buf, 0, 1.0 );
+    CCSIDFT(c, dft_src, dft_dst);
 
     for( j = 0; j < n2; j++, dst += dst_step*2 )
     {
@@ -3279,41 +3761,31 @@ DCTInit( int n, int elem_size, void* _wave, int inv )
 }
 
 
-typedef void (*DCTFunc)(const void* src, int src_step, void* dft_src,
-                        void* dft_dst, void* dst, int dst_step, int n,
-                        int nf, int* factors, const int* itab, const void* dft_wave,
-                        const void* dct_wave, const void* spec, void* buf );
+typedef void (*DCTFunc)(const OcvDftOptions & c, const void* src, size_t src_step, void* dft_src,
+                        void* dft_dst, void* dst, size_t dst_step, const void* dct_wave);
 
-static void DCT_32f(const float* src, int src_step, float* dft_src, float* dft_dst,
-                    float* dst, int dst_step, int n, int nf, int* factors, const int* itab,
-                    const Complexf* dft_wave, const Complexf* dct_wave, const void* spec, Complexf* buf )
+static void DCT_32f(const OcvDftOptions & c, const float* src, size_t src_step, float* dft_src, float* dft_dst,
+                    float* dst, size_t dst_step, const Complexf* dct_wave)
 {
-    DCT(src, src_step, dft_src, dft_dst, dst, dst_step,
-        n, nf, factors, itab, dft_wave, dct_wave, spec, buf);
+    DCT(c, src, src_step, dft_src, dft_dst, dst, dst_step, dct_wave);
 }
 
-static void IDCT_32f(const float* src, int src_step, float* dft_src, float* dft_dst,
-                    float* dst, int dst_step, int n, int nf, int* factors, const int* itab,
-                    const Complexf* dft_wave, const Complexf* dct_wave, const void* spec, Complexf* buf )
+static void IDCT_32f(const OcvDftOptions & c, const float* src, size_t src_step, float* dft_src, float* dft_dst,
+                    float* dst, size_t dst_step, const Complexf* dct_wave)
 {
-    IDCT(src, src_step, dft_src, dft_dst, dst, dst_step,
-         n, nf, factors, itab, dft_wave, dct_wave, spec, buf);
+    IDCT(c, src, src_step, dft_src, dft_dst, dst, dst_step, dct_wave);
 }
 
-static void DCT_64f(const double* src, int src_step, double* dft_src, double* dft_dst,
-                    double* dst, int dst_step, int n, int nf, int* factors, const int* itab,
-                    const Complexd* dft_wave, const Complexd* dct_wave, const void* spec, Complexd* buf )
+static void DCT_64f(const OcvDftOptions & c, const double* src, size_t src_step, double* dft_src, double* dft_dst,
+                    double* dst, size_t dst_step, const Complexd* dct_wave)
 {
-    DCT(src, src_step, dft_src, dft_dst, dst, dst_step,
-        n, nf, factors, itab, dft_wave, dct_wave, spec, buf);
+    DCT(c, src, src_step, dft_src, dft_dst, dst, dst_step, dct_wave);
 }
 
-static void IDCT_64f(const double* src, int src_step, double* dft_src, double* dft_dst,
-                     double* dst, int dst_step, int n, int nf, int* factors, const int* itab,
-                     const Complexd* dft_wave, const Complexd* dct_wave, const void* spec, Complexd* buf )
+static void IDCT_64f(const OcvDftOptions & c, const double* src, size_t src_step, double* dft_src, double* dft_dst,
+                     double* dst, size_t dst_step, const Complexd* dct_wave)
 {
-    IDCT(src, src_step, dft_src, dft_dst, dst, dst_step,
-         n, nf, factors, itab, dft_wave, dct_wave, spec, buf);
+    IDCT(c, src, src_step, dft_src, dft_dst, dst, dst_step, dct_wave);
 }
 
 }
@@ -3336,8 +3808,8 @@ typedef IppStatus (CV_STDCALL * ippiDCTGetBufSize)(const void*, int*);
 class DctIPPLoop_Invoker : public ParallelLoopBody
 {
 public:
-    DctIPPLoop_Invoker(const Mat& _src, Mat& _dst, bool _inv, bool *_ok) :
-        ParallelLoopBody(), src(&_src), dst(&_dst), inv(_inv), ok(_ok)
+    DctIPPLoop_Invoker(const uchar * _src, size_t _src_step, uchar * _dst, size_t _dst_step, int _width, bool _inv, bool *_ok) :
+        ParallelLoopBody(), src(_src), src_step(_src_step), dst(_dst), dst_step(_dst_step), width(_width), inv(_inv), ok(_ok)
     {
         *ok = true;
     }
@@ -3348,7 +3820,7 @@ public:
             return;
 
 #if IPP_VERSION_X100 >= 900
-        IppiSize srcRoiSize = {src->cols, 1};
+        IppiSize srcRoiSize = {width, 1};
 
         int specSize    = 0;
         int initSize    = 0;
@@ -3367,7 +3839,7 @@ public:
                 ippFree(pInitBuf);      \
             return;
 
-        ippiDCTFunc     ippDctFun   = inv ? (ippiDCTFunc)ippiDCTInv_32f_C1R         : (ippiDCTFunc)ippiDCTFwd_32f_C1R;
+        ippiDCTFunc     ippiDCT_32f_C1R   = inv ? (ippiDCTFunc)ippiDCTInv_32f_C1R         : (ippiDCTFunc)ippiDCTFwd_32f_C1R;
         ippiDCTInit     ippDctInit     = inv ? (ippiDCTInit)ippiDCTInvInit_32f         : (ippiDCTInit)ippiDCTFwdInit_32f;
         ippiDCTGetSize  ippDctGetSize  = inv ? (ippiDCTGetSize)ippiDCTInvGetSize_32f   : (ippiDCTGetSize)ippiDCTFwdGetSize_32f;
 
@@ -3405,7 +3877,7 @@ public:
 
         for(int i = range.start; i < range.end; ++i)
         {
-            if(ippDctFun(src->ptr<float>(i), (int)src->step,dst->ptr<float>(i), (int)dst->step, pDCTSpec, pBuffer) < 0)
+            if(CV_INSTRUMENT_FUN_IPP(ippiDCT_32f_C1R, (float*)(src + src_step * i), static_cast<int>(src_step), (float*)(dst + dst_step * i), static_cast<int>(dst_step), pDCTSpec, pBuffer) < 0)
             {
                 *ok = false;
                 IPP_RETURN
@@ -3419,7 +3891,7 @@ public:
         uchar* pBuffer = 0;
         int bufSize=0;
 
-        IppiSize srcRoiSize = {src->cols, 1};
+        IppiSize srcRoiSize = {width, 1};
 
         CV_SUPPRESS_DEPRECATED_START
 
@@ -3435,7 +3907,7 @@ public:
 
             for( int i = range.start; i < range.end; ++i)
             {
-                if(ippDctFun(src->ptr<float>(i), (int)src->step,dst->ptr<float>(i), (int)dst->step, pDCTSpec, (Ipp8u*)pBuffer) < 0)
+                if(ippDctFun((float*)(src + src_step * i), static_cast<int>(src_step), (float*)(dst + dst_step * i), static_cast<int>(dst_step), pDCTSpec, (Ipp8u*)pBuffer) < 0)
                 {
                     *ok = false;
                     break;
@@ -3456,27 +3928,32 @@ public:
     }
 
 private:
-    const Mat* src;
-    Mat* dst;
+    const uchar * src;
+    size_t src_step;
+    uchar * dst;
+    size_t dst_step;
+    int width;
     bool inv;
     bool *ok;
 };
 
-static bool DctIPPLoop(const Mat& src, Mat& dst, bool inv)
+static bool DctIPPLoop(const uchar * src, size_t src_step, uchar * dst, size_t dst_step, int width, int height, bool inv)
 {
     bool ok;
-    parallel_for_(Range(0, src.rows), DctIPPLoop_Invoker(src, dst, inv, &ok), src.rows/(double)(1<<4) );
+    parallel_for_(Range(0, height), DctIPPLoop_Invoker(src, src_step, dst, dst_step, width, inv, &ok), height/(double)(1<<4) );
     return ok;
 }
 
-static bool ippi_DCT_32f(const Mat& src, Mat& dst, bool inv, bool row)
+static bool ippi_DCT_32f(const uchar * src, size_t src_step, uchar * dst, size_t dst_step, int width, int height, bool inv, bool row)
 {
+    CV_INSTRUMENT_REGION_IPP()
+
     if(row)
-        return DctIPPLoop(src, dst, inv);
+        return DctIPPLoop(src, src_step, dst, dst_step, width, height, inv);
     else
     {
 #if IPP_VERSION_X100 >= 900
-        IppiSize srcRoiSize = {src.cols, src.rows};
+        IppiSize srcRoiSize = {width, height};
 
         int specSize    = 0;
         int initSize    = 0;
@@ -3494,7 +3971,7 @@ static bool ippi_DCT_32f(const Mat& src, Mat& dst, bool inv, bool row)
             if(pInitBuf)                \
                 ippFree(pInitBuf);      \
 
-        ippiDCTFunc     ippDctFun      = inv ? (ippiDCTFunc)ippiDCTInv_32f_C1R         : (ippiDCTFunc)ippiDCTFwd_32f_C1R;
+        ippiDCTFunc     ippiDCT_32f_C1R      = inv ? (ippiDCTFunc)ippiDCTInv_32f_C1R         : (ippiDCTFunc)ippiDCTFwd_32f_C1R;
         ippiDCTInit     ippDctInit     = inv ? (ippiDCTInit)ippiDCTInvInit_32f         : (ippiDCTInit)ippiDCTFwdInit_32f;
         ippiDCTGetSize  ippDctGetSize  = inv ? (ippiDCTGetSize)ippiDCTInvGetSize_32f   : (ippiDCTGetSize)ippiDCTFwdGetSize_32f;
 
@@ -3524,7 +4001,7 @@ static bool ippi_DCT_32f(const Mat& src, Mat& dst, bool inv, bool row)
             return false;
         }
 
-        if(ippDctFun(src.ptr<float>(), (int)src.step,dst.ptr<float>(), (int)dst.step, pDCTSpec, pBuffer) < 0)
+        if(CV_INSTRUMENT_FUN_IPP(ippiDCT_32f_C1R, (float*)src, static_cast<int>(src_step), (float*)dst, static_cast<int>(dst_step), pDCTSpec, pBuffer) < 0)
         {
             IPP_RELEASE
             return false;
@@ -3540,7 +4017,7 @@ static bool ippi_DCT_32f(const Mat& src, Mat& dst, bool inv, bool row)
         uchar* pBuffer = 0;
         int bufSize=0;
 
-        IppiSize srcRoiSize = {src.cols, src.rows};
+        IppiSize srcRoiSize = {width, height};
 
         CV_SUPPRESS_DEPRECATED_START
 
@@ -3556,7 +4033,7 @@ static bool ippi_DCT_32f(const Mat& src, Mat& dst, bool inv, bool row)
             buf.allocate( bufSize );
             pBuffer = (uchar*)buf;
 
-            status = ippDctFun(src.ptr<float>(), (int)src.step, dst.ptr<float>(), (int)dst.step, pDCTSpec, (Ipp8u*)pBuffer);
+            status = ippDctFun((float*)src, static_cast<int>(src_step), (float*)dst, static_cast<int>(dst_step), pDCTSpec, (Ipp8u*)pBuffer);
         }
 
         if (pDCTSpec)
@@ -3574,145 +4051,222 @@ static bool ippi_DCT_32f(const Mat& src, Mat& dst, bool inv, bool row)
 }
 #endif
 
-void cv::dct( InputArray _src0, OutputArray _dst, int flags )
+namespace cv {
+
+class OcvDctImpl : public hal::DCT2D
 {
-    static DCTFunc dct_tbl[4] =
+public:
+    OcvDftOptions opt;
+
+    int _factors[34];
+    AutoBuffer<uint> wave_buf;
+    AutoBuffer<int> itab_buf;
+
+    DCTFunc dct_func;
+    bool isRowTransform;
+    bool isInverse;
+    bool isContinuous;
+    int start_stage;
+    int end_stage;
+    int width;
+    int height;
+    int depth;
+
+    void init(int _width, int _height, int _depth, int flags)
     {
-        (DCTFunc)DCT_32f,
-        (DCTFunc)IDCT_32f,
-        (DCTFunc)DCT_64f,
-        (DCTFunc)IDCT_64f
-    };
+        width = _width;
+        height = _height;
+        depth = _depth;
+        isInverse = (flags & CV_HAL_DFT_INVERSE) != 0;
+        isRowTransform = (flags & CV_HAL_DFT_ROWS) != 0;
+        isContinuous = (flags & CV_HAL_DFT_IS_CONTINUOUS) != 0;
+        static DCTFunc dct_tbl[4] =
+        {
+            (DCTFunc)DCT_32f,
+            (DCTFunc)IDCT_32f,
+            (DCTFunc)DCT_64f,
+            (DCTFunc)IDCT_64f
+        };
+        dct_func = dct_tbl[(int)isInverse + (depth == CV_64F)*2];
+        opt.nf = 0;
+        opt.isComplex = false;
+        opt.isInverse = false;
+        opt.noPermute = false;
+        opt.scale = 1.;
+        opt.factors = _factors;
+
+        if (isRowTransform || height == 1 || (width == 1 && isContinuous))
+        {
+            start_stage = end_stage = 0;
+        }
+        else
+        {
+            start_stage = (width == 1);
+            end_stage = 1;
+        }
+    }
+    void apply(const uchar *src, size_t src_step, uchar *dst, size_t dst_step)
+    {
+        CV_IPP_RUN(IPP_VERSION_X100 >= 700 && depth == CV_32F, ippi_DCT_32f(src, src_step, dst, dst_step, width, height, isInverse, isRowTransform))
 
-    bool inv = (flags & DCT_INVERSE) != 0;
-    Mat src0 = _src0.getMat(), src = src0;
-    int type = src.type(), depth = src.depth();
-    void *spec = 0;
-
-    double scale = 1.;
-    int prev_len = 0, nf = 0, stage, end_stage;
-    uchar *src_dft_buf = 0, *dst_dft_buf = 0;
-    uchar *dft_wave = 0, *dct_wave = 0;
-    int* itab = 0;
-    uchar* ptr = 0;
-    int elem_size = (int)src.elemSize(), complex_elem_size = elem_size*2;
-    int factors[34], inplace_transform;
-    int i, len, count;
-    AutoBuffer<uchar> buf;
+        AutoBuffer<uchar> dct_wave;
+        AutoBuffer<uchar> src_buf, dst_buf;
+        uchar *src_dft_buf = 0, *dst_dft_buf = 0;
+        int prev_len = 0;
+        int elem_size = (depth == CV_32F) ? sizeof(float) : sizeof(double);
+        int complex_elem_size = elem_size*2;
 
-    CV_Assert( type == CV_32FC1 || type == CV_64FC1 );
-    _dst.create( src.rows, src.cols, type );
-    Mat dst = _dst.getMat();
+        for(int stage = start_stage ; stage <= end_stage; stage++ )
+        {
+            const uchar* sptr = src;
+            uchar* dptr = dst;
+            size_t sstep0, sstep1, dstep0, dstep1;
+            int len, count;
 
-    CV_IPP_RUN(IPP_VERSION_X100 >= 700 && src.type() == CV_32F, ippi_DCT_32f(src, dst, inv, ((flags & DCT_ROWS) != 0)))
+            if( stage == 0 )
+            {
+                len = width;
+                count = height;
+                if( len == 1 && !isRowTransform )
+                {
+                    len = height;
+                    count = 1;
+                }
+                sstep0 = src_step;
+                dstep0 = dst_step;
+                sstep1 = dstep1 = elem_size;
+            }
+            else
+            {
+                len = height;
+                count = width;
+                sstep1 = src_step;
+                dstep1 = dst_step;
+                sstep0 = dstep0 = elem_size;
+            }
 
-    DCTFunc dct_func = dct_tbl[(int)inv + (depth == CV_64F)*2];
+            opt.n = len;
+            opt.tab_size = len;
 
-    if( (flags & DCT_ROWS) || src.rows == 1 ||
-        (src.cols == 1 && (src.isContinuous() && dst.isContinuous())))
-    {
-        stage = end_stage = 0;
+            if( len != prev_len )
+            {
+                if( len > 1 && (len & 1) )
+                    CV_Error( CV_StsNotImplemented, "Odd-size DCT\'s are not implemented" );
+
+                opt.nf = DFTFactorize( len, opt.factors );
+                bool inplace_transform = opt.factors[0] == opt.factors[opt.nf-1];
+
+                wave_buf.allocate(len*complex_elem_size);
+                opt.wave = wave_buf;
+                itab_buf.allocate(len);
+                opt.itab = itab_buf;
+                DFTInit( len, opt.nf, opt.factors, opt.itab, complex_elem_size, opt.wave, isInverse );
+
+                dct_wave.allocate((len/2 + 1)*complex_elem_size);
+                src_buf.allocate(len*elem_size);
+                src_dft_buf = src_buf;
+                if(!inplace_transform)
+                {
+                    dst_buf.allocate(len*elem_size);
+                    dst_dft_buf = dst_buf;
+                }
+                else
+                {
+                    dst_dft_buf = src_buf;
+                }
+                DCTInit( len, complex_elem_size, dct_wave, isInverse);
+                prev_len = len;
+            }
+            // otherwise reuse the tables calculated on the previous stage
+            for(unsigned i = 0; i < static_cast<unsigned>(count); i++ )
+            {
+                dct_func( opt, sptr + i*sstep0, sstep1, src_dft_buf, dst_dft_buf,
+                          dptr + i*dstep0, dstep1, dct_wave);
+            }
+            src = dst;
+            src_step = dst_step;
+        }
     }
-    else
+};
+
+struct ReplacementDCT2D : public hal::DCT2D
+{
+    cvhalDFT *context;
+    bool isInitialized;
+
+    ReplacementDCT2D() : context(0), isInitialized(false) {}
+    bool init(int width, int height, int depth, int flags)
     {
-        stage = src.cols == 1;
-        end_stage = 1;
+        int res = hal_ni_dctInit2D(&context, width, height, depth, flags);
+        isInitialized = (res == CV_HAL_ERROR_OK);
+        return isInitialized;
     }
-
-    for( ; stage <= end_stage; stage++ )
+    void apply(const uchar *src_data, size_t src_step, uchar *dst_data, size_t dst_step)
     {
-        const uchar* sptr = src.ptr();
-        uchar* dptr = dst.ptr();
-        size_t sstep0, sstep1, dstep0, dstep1;
-
-        if( stage == 0 )
+        if (isInitialized)
         {
-            len = src.cols;
-            count = src.rows;
-            if( len == 1 && !(flags & DCT_ROWS) )
-            {
-                len = src.rows;
-                count = 1;
-            }
-            sstep0 = src.step;
-            dstep0 = dst.step;
-            sstep1 = dstep1 = elem_size;
+            CALL_HAL(dct2D, cv_hal_dct2D, context, src_data, src_step, dst_data, dst_step);
         }
-        else
+    }
+    ~ReplacementDCT2D()
+    {
+        if (isInitialized)
         {
-            len = dst.rows;
-            count = dst.cols;
-            sstep1 = src.step;
-            dstep1 = dst.step;
-            sstep0 = dstep0 = elem_size;
+            CALL_HAL(dctFree2D, cv_hal_dctFree2D, context);
         }
+    }
+};
 
-        if( len != prev_len )
-        {
-            int sz;
-
-            if( len > 1 && (len & 1) )
-                CV_Error( CV_StsNotImplemented, "Odd-size DCT\'s are not implemented" );
-
-            sz = len*elem_size;
-            sz += (len/2 + 1)*complex_elem_size;
+namespace hal {
 
-            spec = 0;
-            inplace_transform = 1;
-            {
-                sz += len*(complex_elem_size + sizeof(int)) + complex_elem_size;
+Ptr<DCT2D> DCT2D::create(int width, int height, int depth, int flags)
+{
+    {
+        ReplacementDCT2D *impl = new ReplacementDCT2D();
+        if (impl->init(width, height, depth, flags))
+        {
+            return Ptr<DCT2D>(impl);
+        }
+        delete impl;
+    }
+    {
+        OcvDctImpl *impl = new OcvDctImpl();
+        impl->init(width, height, depth, flags);
+        return Ptr<DCT2D>(impl);
+    }
+}
 
-                nf = DFTFactorize( len, factors );
-                inplace_transform = factors[0] == factors[nf-1];
+} // cv::hal::
+} // cv::
 
-                i = nf > 1 && (factors[0] & 1) == 0;
-                if( (factors[i] & 1) != 0 && factors[i] > 5 )
-                    sz += (factors[i]+1)*complex_elem_size;
+void cv::dct( InputArray _src0, OutputArray _dst, int flags )
+{
+    CV_INSTRUMENT_REGION()
 
-                if( !inplace_transform )
-                    sz += len*elem_size;
-            }
+    Mat src0 = _src0.getMat(), src = src0;
+    int type = src.type(), depth = src.depth();
 
-            buf.allocate( sz + 32 );
-            ptr = (uchar*)buf;
+    CV_Assert( type == CV_32FC1 || type == CV_64FC1 );
+    _dst.create( src.rows, src.cols, type );
+    Mat dst = _dst.getMat();
 
-            if( !spec )
-            {
-                dft_wave = ptr;
-                ptr += len*complex_elem_size;
-                itab = (int*)ptr;
-                ptr = (uchar*)cvAlignPtr( ptr + len*sizeof(int), 16 );
-                DFTInit( len, nf, factors, itab, complex_elem_size, dft_wave, inv );
-            }
+    int f = 0;
+    if ((flags & DFT_ROWS) != 0)
+        f |= CV_HAL_DFT_ROWS;
+    if ((flags & DCT_INVERSE) != 0)
+        f |= CV_HAL_DFT_INVERSE;
+    if (src.isContinuous() && dst.isContinuous())
+        f |= CV_HAL_DFT_IS_CONTINUOUS;
 
-            dct_wave = ptr;
-            ptr += (len/2 + 1)*complex_elem_size;
-            src_dft_buf = dst_dft_buf = ptr;
-            ptr += len*elem_size;
-            if( !inplace_transform )
-            {
-                dst_dft_buf = ptr;
-                ptr += len*elem_size;
-            }
-            DCTInit( len, complex_elem_size, dct_wave, inv );
-            if( !inv )
-                scale += scale;
-            prev_len = len;
-        }
-        // otherwise reuse the tables calculated on the previous stage
-        for( i = 0; i < count; i++ )
-        {
-            dct_func( sptr + i*sstep0, (int)sstep1, src_dft_buf, dst_dft_buf,
-                      dptr + i*dstep0, (int)dstep1, len, nf, factors,
-                      itab, dft_wave, dct_wave, spec, ptr );
-        }
-        src = dst;
-    }
+    Ptr<hal::DCT2D> c = hal::DCT2D::create(src.cols, src.rows, depth, f);
+    c->apply(src.data, src.step, dst.data, dst.step);
 }
 
 
 void cv::idct( InputArray src, OutputArray dst, int flags )
 {
+    CV_INSTRUMENT_REGION()
+
     dct( src, dst, flags | DCT_INVERSE );
 }
 
diff --git a/modules/core/src/glob.cpp b/modules/core/src/glob.cpp
index e0c7f66..9bd3bdb 100644
--- a/modules/core/src/glob.cpp
+++ b/modules/core/src/glob.cpp
@@ -259,6 +259,8 @@ static void glob_rec(const cv::String& directory, const cv::String& wildchart, s
 
 void cv::glob(String pattern, std::vector<String>& result, bool recursive)
 {
+    CV_INSTRUMENT_REGION()
+
     result.clear();
     String path, wildchart;
 
diff --git a/modules/core/src/hal_internal.cpp b/modules/core/src/hal_internal.cpp
new file mode 100644
index 0000000..b2b6dc3
--- /dev/null
+++ b/modules/core/src/hal_internal.cpp
@@ -0,0 +1,601 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+//  By downloading, copying, installing or using the software you agree to this license.
+//  If you do not agree to this license, do not download, install,
+//  copy or use the software.
+//
+//
+//                          License Agreement
+//                For Open Source Computer Vision Library
+//
+// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
+// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
+// Copyright (C) 2013, OpenCV Foundation, all rights reserved.
+// Copyright (C) 2015, Itseez Inc., all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+//   * Redistribution's of source code must retain the above copyright notice,
+//     this list of conditions and the following disclaimer.
+//
+//   * Redistribution's in binary form must reproduce the above copyright notice,
+//     this list of conditions and the following disclaimer in the documentation
+//     and/or other materials provided with the distribution.
+//
+//   * The name of the copyright holders may not be used to endorse or promote products
+//     derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "hal_internal.hpp"
+
+#ifdef HAVE_LAPACK
+
+#include "opencv_lapack.h"
+
+#include <cmath>
+#include <algorithm>
+#include <typeinfo>
+#include <limits>
+#include <complex>
+#include <vector>
+
+#define HAL_GEMM_SMALL_COMPLEX_MATRIX_THRESH 100
+#define HAL_GEMM_SMALL_MATRIX_THRESH 100
+#define HAL_SVD_SMALL_MATRIX_THRESH 25
+#define HAL_QR_SMALL_MATRIX_THRESH 30
+#define HAL_LU_SMALL_MATRIX_THRESH 100
+#define HAL_CHOLESKY_SMALL_MATRIX_THRESH 100
+
+//lapack stores matrices in column-major order so transposing is neded everywhere
+template <typename fptype> static inline void
+transpose_square_inplace(fptype *src, size_t src_ld, size_t m)
+{
+    for(size_t i = 0; i < m - 1; i++)
+        for(size_t j = i + 1; j < m; j++)
+            std::swap(src[j*src_ld + i], src[i*src_ld + j]);
+}
+
+template <typename fptype> static inline void
+transpose(const fptype *src, size_t src_ld, fptype* dst, size_t dst_ld, size_t m, size_t n)
+{
+    for(size_t i = 0; i < m; i++)
+        for(size_t j = 0; j < n; j++)
+            dst[j*dst_ld + i] = src[i*src_ld + j];
+}
+
+template <typename fptype> static inline void
+copy_matrix(const fptype *src, size_t src_ld, fptype* dst, size_t dst_ld, size_t m, size_t n)
+{
+    for(size_t i = 0; i < m; i++)
+        for(size_t j = 0; j < n; j++)
+            dst[i*dst_ld + j] = src[i*src_ld + j];
+}
+
+template <typename fptype> static inline void
+set_value(fptype *dst, size_t dst_ld, fptype value, size_t m, size_t n)
+{
+    for(size_t i = 0; i < m; i++)
+        for(size_t j = 0; j < n; j++)
+            dst[i*dst_ld + j] = value;
+}
+
+template <typename fptype> static inline int
+lapack_LU(fptype* a, size_t a_step, int m, fptype* b, size_t b_step, int n, int* info)
+{
+    int lda = a_step / sizeof(fptype), sign = 0;
+    int* piv = new int[m];
+
+    transpose_square_inplace(a, lda, m);
+
+    if(b)
+    {
+        if(n == 1 && b_step == sizeof(fptype))
+        {
+            if(typeid(fptype) == typeid(float))
+                sgesv_(&m, &n, (float*)a, &lda, piv, (float*)b, &m, info);
+            else if(typeid(fptype) == typeid(double))
+                dgesv_(&m, &n, (double*)a, &lda, piv, (double*)b, &m, info);
+        }
+        else
+        {
+            int ldb = b_step / sizeof(fptype);
+            fptype* tmpB = new fptype[m*n];
+
+            transpose(b, ldb, tmpB, m, m, n);
+
+            if(typeid(fptype) == typeid(float))
+                sgesv_(&m, &n, (float*)a, &lda, piv, (float*)tmpB, &m, info);
+            else if(typeid(fptype) == typeid(double))
+                dgesv_(&m, &n, (double*)a, &lda, piv, (double*)tmpB, &m, info);
+
+            transpose(tmpB, m, b, ldb, n, m);
+            delete[] tmpB;
+        }
+    }
+    else
+    {
+        if(typeid(fptype) == typeid(float))
+            sgetrf_(&m, &m, (float*)a, &lda, piv, info);
+        else if(typeid(fptype) == typeid(double))
+            dgetrf_(&m, &m, (double*)a, &lda, piv, info);
+    }
+
+    if(*info == 0)
+    {
+        for(int i = 0; i < m; i++)
+            sign ^= piv[i] != i + 1;
+        *info = sign ? -1 : 1;
+    }
+    else
+        *info = 0; //in opencv LU function zero means error
+
+    delete[] piv;
+    return CV_HAL_ERROR_OK;
+}
+
+template <typename fptype> static inline int
+lapack_Cholesky(fptype* a, size_t a_step, int m, fptype* b, size_t b_step, int n, bool* info)
+{
+    int lapackStatus = 0;
+    int lda = a_step / sizeof(fptype);
+    char L[] = {'L', '\0'};
+
+    if(b)
+    {
+        if(n == 1 && b_step == sizeof(fptype))
+        {
+            if(typeid(fptype) == typeid(float))
+                sposv_(L, &m, &n, (float*)a, &lda, (float*)b, &m, &lapackStatus);
+            else if(typeid(fptype) == typeid(double))
+                dposv_(L, &m, &n, (double*)a, &lda, (double*)b, &m, &lapackStatus);
+        }
+        else
+        {
+            int ldb = b_step / sizeof(fptype);
+            fptype* tmpB = new fptype[m*n];
+            transpose(b, ldb, tmpB, m, m, n);
+
+            if(typeid(fptype) == typeid(float))
+                sposv_(L, &m, &n, (float*)a, &lda, (float*)tmpB, &m, &lapackStatus);
+            else if(typeid(fptype) == typeid(double))
+                dposv_(L, &m, &n, (double*)a, &lda, (double*)tmpB, &m, &lapackStatus);
+
+            transpose(tmpB, m, b, ldb, n, m);
+            delete[] tmpB;
+        }
+    }
+    else
+    {
+        if(typeid(fptype) == typeid(float))
+            spotrf_(L, &m, (float*)a, &lda, &lapackStatus);
+        else if(typeid(fptype) == typeid(double))
+            dpotrf_(L, &m, (double*)a, &lda, &lapackStatus);
+    }
+
+    if(lapackStatus == 0) *info = true;
+    else *info = false; //in opencv Cholesky function false means error
+
+    return CV_HAL_ERROR_OK;
+}
+
+template <typename fptype> static inline int
+lapack_SVD(fptype* a, size_t a_step, fptype *w, fptype* u, size_t u_step, fptype* vt, size_t v_step, int m, int n, int flags, int* info)
+{
+    int lda = a_step / sizeof(fptype);
+    int ldv = v_step / sizeof(fptype);
+    int ldu = u_step / sizeof(fptype);
+    int lwork = -1;
+    int* iworkBuf = new int[8*std::min(m, n)];
+    fptype work1 = 0;
+
+    //A already transposed and m>=n
+    char mode[] = { ' ', '\0'};
+    if(flags & CV_HAL_SVD_NO_UV)
+    {
+        ldv = 1;
+        mode[0] = 'N';
+    }
+    else if((flags & CV_HAL_SVD_SHORT_UV) && (flags & CV_HAL_SVD_MODIFY_A)) //short SVD, U stored in a
+        mode[0] = 'O';
+    else if((flags & CV_HAL_SVD_SHORT_UV) && !(flags & CV_HAL_SVD_MODIFY_A)) //short SVD, U stored in u if m>=n
+        mode[0] = 'S';
+    else if(flags & CV_HAL_SVD_FULL_UV) //full SVD, U stored in u or in a
+        mode[0] = 'A';
+
+    if((flags & CV_HAL_SVD_MODIFY_A) && (flags & CV_HAL_SVD_FULL_UV)) //U stored in a
+    {
+        u = new fptype[m*m];
+        ldu = m;
+    }
+
+    if(typeid(fptype) == typeid(float))
+        sgesdd_(mode, &m, &n, (float*)a, &lda, (float*)w, (float*)u, &ldu, (float*)vt, &ldv, (float*)&work1, &lwork, iworkBuf, info);
+    else if(typeid(fptype) == typeid(double))
+        dgesdd_(mode, &m, &n, (double*)a, &lda, (double*)w, (double*)u, &ldu, (double*)vt, &ldv, (double*)&work1, &lwork, iworkBuf, info);
+
+    lwork = (int)round(work1); //optimal buffer size
+    fptype* buffer = new fptype[lwork + 1];
+
+    if(typeid(fptype) == typeid(float))
+        sgesdd_(mode, &m, &n, (float*)a, &lda, (float*)w, (float*)u, &ldu, (float*)vt, &ldv, (float*)buffer, &lwork, iworkBuf, info);
+    else if(typeid(fptype) == typeid(double))
+        dgesdd_(mode, &m, &n, (double*)a, &lda, (double*)w, (double*)u, &ldu, (double*)vt, &ldv, (double*)buffer, &lwork, iworkBuf, info);
+
+    if(!(flags & CV_HAL_SVD_NO_UV))
+        transpose_square_inplace(vt, ldv, n);
+
+    if((flags & CV_HAL_SVD_MODIFY_A) && (flags & CV_HAL_SVD_FULL_UV))
+    {
+        for(int i = 0; i < m; i++)
+            for(int j = 0; j < m; j++)
+                a[i*lda + j] = u[i*m + j];
+        delete[] u;
+    }
+
+    delete[] iworkBuf;
+    delete[] buffer;
+    return CV_HAL_ERROR_OK;
+}
+
+template <typename fptype> static inline int
+lapack_QR(fptype* a, size_t a_step, int m, int n, int k, fptype* b, size_t b_step, fptype* dst, int* info)
+{
+    int lda = a_step / sizeof(fptype);
+    char mode[] = { 'N', '\0' };
+    if(m < n)
+        return CV_HAL_ERROR_NOT_IMPLEMENTED;
+
+    std::vector<fptype> tmpAMemHolder;
+    fptype* tmpA;
+    int ldtmpA;
+    if (m == n)
+    {
+        transpose_square_inplace(a, lda, m);
+        tmpA = a;
+        ldtmpA = lda;
+    }
+    else
+    {
+        tmpAMemHolder.resize(m*n);
+        tmpA = &tmpAMemHolder.front();
+        ldtmpA = m;
+        transpose(a, lda, tmpA, m, m, n);
+    }
+
+    int lwork = -1;
+    fptype work1 = 0.;
+
+    if (b)
+    {
+        if (k == 1 && b_step == sizeof(fptype))
+        {
+            if (typeid(fptype) == typeid(float))
+                sgels_(mode, &m, &n, &k, (float*)tmpA, &ldtmpA, (float*)b, &m, (float*)&work1, &lwork, info);
+            else if (typeid(fptype) == typeid(double))
+                dgels_(mode, &m, &n, &k, (double*)tmpA, &ldtmpA, (double*)b, &m, (double*)&work1, &lwork, info);
+
+            lwork = (int)round(work1); //optimal buffer size
+            std::vector<fptype> workBufMemHolder(lwork + 1);
+            fptype* buffer = &workBufMemHolder.front();
+
+            if (typeid(fptype) == typeid(float))
+                sgels_(mode, &m, &n, &k, (float*)tmpA, &ldtmpA, (float*)b, &m, (float*)buffer, &lwork, info);
+            else if (typeid(fptype) == typeid(double))
+                dgels_(mode, &m, &n, &k, (double*)tmpA, &ldtmpA, (double*)b, &m, (double*)buffer, &lwork, info);
+        }
+        else
+        {
+            std::vector<fptype> tmpBMemHolder(m*k);
+            fptype* tmpB = &tmpBMemHolder.front();
+            int ldb = b_step / sizeof(fptype);
+            transpose(b, ldb, tmpB, m, m, k);
+
+            if (typeid(fptype) == typeid(float))
+                sgels_(mode, &m, &n, &k, (float*)tmpA, &ldtmpA, (float*)tmpB, &m, (float*)&work1, &lwork, info);
+            else if (typeid(fptype) == typeid(double))
+                dgels_(mode, &m, &n, &k, (double*)tmpA, &ldtmpA, (double*)tmpB, &m, (double*)&work1, &lwork, info);
+
+            lwork = (int)round(work1); //optimal buffer size
+            std::vector<fptype> workBufMemHolder(lwork + 1);
+            fptype* buffer = &workBufMemHolder.front();
+
+            if (typeid(fptype) == typeid(float))
+                sgels_(mode, &m, &n, &k, (float*)tmpA, &ldtmpA, (float*)tmpB, &m, (float*)buffer, &lwork, info);
+            else if (typeid(fptype) == typeid(double))
+                dgels_(mode, &m, &n, &k, (double*)tmpA, &ldtmpA, (double*)tmpB, &m, (double*)buffer, &lwork, info);
+
+            transpose(tmpB, m, b, ldb, k, m);
+        }
+    }
+    else
+    {
+        if (typeid(fptype) == typeid(float))
+            sgeqrf_(&m, &n, (float*)tmpA, &ldtmpA, (float*)dst, (float*)&work1, &lwork, info);
+        else if (typeid(fptype) == typeid(double))
+            dgeqrf_(&m, &n, (double*)tmpA, &ldtmpA, (double*)dst, (double*)&work1, &lwork, info);
+
+        lwork = (int)round(work1); //optimal buffer size
+        std::vector<fptype> workBufMemHolder(lwork + 1);
+        fptype* buffer = &workBufMemHolder.front();
+
+        if (typeid(fptype) == typeid(float))
+            sgeqrf_(&m, &n, (float*)tmpA, &ldtmpA, (float*)dst, (float*)buffer, &lwork, info);
+        else if (typeid(fptype) == typeid(double))
+            dgeqrf_(&m, &n, (double*)tmpA, &ldtmpA, (double*)dst, (double*)buffer, &lwork, info);
+    }
+
+    if (m == n)
+        transpose_square_inplace(a, lda, m);
+    else
+        transpose(tmpA, m, a, lda, n, m);
+
+    if (*info != 0)
+        *info = 0;
+    else
+        *info = 1;
+
+    return CV_HAL_ERROR_OK;
+}
+
+template <typename fptype> static inline int
+lapack_gemm(const fptype *src1, size_t src1_step, const fptype *src2, size_t src2_step, fptype alpha,
+            const fptype *src3, size_t src3_step, fptype beta, fptype *dst, size_t dst_step, int a_m, int a_n, int d_n, int flags)
+{
+    int ldsrc1 = src1_step / sizeof(fptype);
+    int ldsrc2 = src2_step / sizeof(fptype);
+    int ldsrc3 = src3_step / sizeof(fptype);
+    int lddst = dst_step / sizeof(fptype);
+    int c_m, c_n, d_m;
+    CBLAS_TRANSPOSE transA, transB;
+
+    if(flags & CV_HAL_GEMM_2_T)
+    {
+        transB = CblasTrans;
+        if(flags & CV_HAL_GEMM_1_T )
+        {
+            d_m = a_n;
+        }
+        else
+        {
+            d_m = a_m;
+        }
+    }
+    else
+    {
+        transB = CblasNoTrans;
+        if(flags & CV_HAL_GEMM_1_T )
+        {
+            d_m = a_n;
+        }
+        else
+        {
+            d_m = a_m;
+        }
+    }
+
+    if(flags & CV_HAL_GEMM_3_T)
+    {
+        c_m = d_n;
+        c_n = d_m;
+    }
+    else
+    {
+        c_m = d_m;
+        c_n = d_n;
+    }
+
+    if(flags & CV_HAL_GEMM_1_T )
+    {
+        transA = CblasTrans;
+        std::swap(a_n, a_m);
+    }
+    else
+    {
+        transA = CblasNoTrans;
+    }
+
+    if(src3 != dst && beta != 0.0 && src3_step != 0) {
+        if(flags & CV_HAL_GEMM_3_T)
+            transpose(src3, ldsrc3, dst, lddst, c_m, c_n);
+        else
+            copy_matrix(src3, ldsrc3, dst, lddst, c_m, c_n);
+    }
+    else if (src3 == dst && (flags & CV_HAL_GEMM_3_T)) //actually transposing C in this case done by openCV
+        return CV_HAL_ERROR_NOT_IMPLEMENTED;
+    else if(src3_step == 0 && beta != 0.0)
+        set_value(dst, lddst, (fptype)0.0, d_m, d_n);
+
+    if(typeid(fptype) == typeid(float))
+        cblas_sgemm(CblasRowMajor, transA, transB, a_m, d_n, a_n, (float)alpha, (float*)src1, ldsrc1, (float*)src2, ldsrc2, (float)beta, (float*)dst, lddst);
+    else if(typeid(fptype) == typeid(double))
+        cblas_dgemm(CblasRowMajor, transA, transB, a_m, d_n, a_n, (double)alpha, (double*)src1, ldsrc1, (double*)src2, ldsrc2, (double)beta, (double*)dst, lddst);
+
+    return CV_HAL_ERROR_OK;
+}
+
+
+template <typename fptype> static inline int
+lapack_gemm_c(const fptype *src1, size_t src1_step, const fptype *src2, size_t src2_step, fptype alpha,
+            const fptype *src3, size_t src3_step, fptype beta, fptype *dst, size_t dst_step, int a_m, int a_n, int d_n, int flags)
+{
+    int ldsrc1 = src1_step / sizeof(std::complex<fptype>);
+    int ldsrc2 = src2_step / sizeof(std::complex<fptype>);
+    int ldsrc3 = src3_step / sizeof(std::complex<fptype>);
+    int lddst = dst_step / sizeof(std::complex<fptype>);
+    int c_m, c_n, d_m;
+    CBLAS_TRANSPOSE transA, transB;
+    std::complex<fptype> cAlpha(alpha, 0.0);
+    std::complex<fptype> cBeta(beta, 0.0);
+
+    if(flags & CV_HAL_GEMM_2_T)
+    {
+        transB = CblasTrans;
+        if(flags & CV_HAL_GEMM_1_T )
+        {
+            d_m = a_n;
+        }
+        else
+        {
+            d_m = a_m;
+        }
+    }
+    else
+    {
+        transB = CblasNoTrans;
+        if(flags & CV_HAL_GEMM_1_T )
+        {
+            d_m = a_n;
+        }
+        else
+        {
+            d_m = a_m;
+        }
+    }
+
+    if(flags & CV_HAL_GEMM_3_T)
+    {
+        c_m = d_n;
+        c_n = d_m;
+    }
+    else
+    {
+        c_m = d_m;
+        c_n = d_n;
+    }
+
+    if(flags & CV_HAL_GEMM_1_T )
+    {
+        transA = CblasTrans;
+        std::swap(a_n, a_m);
+    }
+    else
+    {
+        transA = CblasNoTrans;
+    }
+
+    if(src3 != dst && beta != 0.0 && src3_step != 0) {
+        if(flags & CV_HAL_GEMM_3_T)
+            transpose((std::complex<fptype>*)src3, ldsrc3, (std::complex<fptype>*)dst, lddst, c_m, c_n);
+        else
+            copy_matrix((std::complex<fptype>*)src3, ldsrc3, (std::complex<fptype>*)dst, lddst, c_m, c_n);
+    }
+    else if (src3 == dst && (flags & CV_HAL_GEMM_3_T)) //actually transposing C in this case done by openCV
+        return CV_HAL_ERROR_NOT_IMPLEMENTED;
+    else if(src3_step == 0 && beta != 0.0)
+        set_value((std::complex<fptype>*)dst, lddst, std::complex<fptype>(0.0, 0.0), d_m, d_n);
+
+    if(typeid(fptype) == typeid(float))
+        cblas_cgemm(CblasRowMajor, transA, transB, a_m, d_n, a_n, (float*)reinterpret_cast<fptype(&)[2]>(cAlpha), (float*)src1, ldsrc1, (float*)src2, ldsrc2, (float*)reinterpret_cast<fptype(&)[2]>(cBeta), (float*)dst, lddst);
+    else if(typeid(fptype) == typeid(double))
+        cblas_zgemm(CblasRowMajor, transA, transB, a_m, d_n, a_n, (double*)reinterpret_cast<fptype(&)[2]>(cAlpha), (double*)src1, ldsrc1, (double*)src2, ldsrc2, (double*)reinterpret_cast<fptype(&)[2]>(cBeta), (double*)dst, lddst);
+
+    return CV_HAL_ERROR_OK;
+}
+int lapack_LU32f(float* a, size_t a_step, int m, float* b, size_t b_step, int n, int* info)
+{
+    if(m < HAL_LU_SMALL_MATRIX_THRESH)
+        return CV_HAL_ERROR_NOT_IMPLEMENTED;
+    return lapack_LU(a, a_step, m, b, b_step, n, info);
+}
+
+int lapack_LU64f(double* a, size_t a_step, int m, double* b, size_t b_step, int n, int* info)
+{
+    if(m < HAL_LU_SMALL_MATRIX_THRESH)
+        return CV_HAL_ERROR_NOT_IMPLEMENTED;
+    return lapack_LU(a, a_step, m, b, b_step, n, info);
+}
+
+int lapack_Cholesky32f(float* a, size_t a_step, int m, float* b, size_t b_step, int n, bool *info)
+{
+    if(m < HAL_CHOLESKY_SMALL_MATRIX_THRESH)
+        return CV_HAL_ERROR_NOT_IMPLEMENTED;
+    return lapack_Cholesky(a, a_step, m, b, b_step, n, info);
+}
+
+int lapack_Cholesky64f(double* a, size_t a_step, int m, double* b, size_t b_step, int n, bool *info)
+{
+    if(m < HAL_CHOLESKY_SMALL_MATRIX_THRESH)
+        return CV_HAL_ERROR_NOT_IMPLEMENTED;
+    return lapack_Cholesky(a, a_step, m, b, b_step, n, info);
+}
+
+int lapack_SVD32f(float* a, size_t a_step, float *w, float* u, size_t u_step, float* vt, size_t v_step, int m, int n, int flags)
+{
+
+    if(m < HAL_SVD_SMALL_MATRIX_THRESH)
+        return CV_HAL_ERROR_NOT_IMPLEMENTED;
+    int info;
+    return lapack_SVD(a, a_step, w, u, u_step, vt, v_step, m, n, flags, &info);
+}
+
+int lapack_SVD64f(double* a, size_t a_step, double *w, double* u, size_t u_step, double* vt, size_t v_step, int m, int n, int flags)
+{
+
+    if(m < HAL_SVD_SMALL_MATRIX_THRESH)
+        return CV_HAL_ERROR_NOT_IMPLEMENTED;
+    int info;
+    return lapack_SVD(a, a_step, w, u, u_step, vt, v_step, m, n, flags, &info);
+}
+
+int lapack_QR32f(float* src1, size_t src1_step, int m, int n, int k, float* src2, size_t src2_step, float* dst, int* info)
+{
+    if (m < HAL_QR_SMALL_MATRIX_THRESH)
+      return CV_HAL_ERROR_NOT_IMPLEMENTED;
+    return lapack_QR(src1, src1_step, m, n, k, src2, src2_step, dst, info);
+}
+
+int lapack_QR64f(double* src1, size_t src1_step, int m, int n, int k, double* src2, size_t src2_step, double* dst, int* info)
+{
+    if (m < HAL_QR_SMALL_MATRIX_THRESH)
+      return CV_HAL_ERROR_NOT_IMPLEMENTED;
+    return lapack_QR(src1, src1_step, m, n, k, src2, src2_step, dst, info);
+}
+
+int lapack_gemm32f(const float *src1, size_t src1_step, const float *src2, size_t src2_step, float alpha,
+                   const float *src3, size_t src3_step, float beta, float *dst, size_t dst_step, int m, int n, int k, int flags)
+{
+    if(m < HAL_GEMM_SMALL_MATRIX_THRESH)
+        return CV_HAL_ERROR_NOT_IMPLEMENTED;
+    return lapack_gemm(src1, src1_step, src2, src2_step, alpha, src3, src3_step, beta, dst, dst_step, m, n, k, flags);
+}
+
+int lapack_gemm64f(const double *src1, size_t src1_step, const double *src2, size_t src2_step, double alpha,
+                   const double *src3, size_t src3_step, double beta, double *dst, size_t dst_step, int m, int n, int k, int flags)
+{
+    if(m < HAL_GEMM_SMALL_MATRIX_THRESH)
+        return CV_HAL_ERROR_NOT_IMPLEMENTED;
+    return lapack_gemm(src1, src1_step, src2, src2_step, alpha, src3, src3_step, beta, dst, dst_step, m, n, k, flags);
+}
+
+int lapack_gemm32fc(const float *src1, size_t src1_step, const float *src2, size_t src2_step, float alpha,
+                   const float *src3, size_t src3_step, float beta, float *dst, size_t dst_step, int m, int n, int k, int flags)
+{
+    if(m < HAL_GEMM_SMALL_COMPLEX_MATRIX_THRESH)
+        return CV_HAL_ERROR_NOT_IMPLEMENTED;
+    return lapack_gemm_c(src1, src1_step, src2, src2_step, alpha, src3, src3_step, beta, dst, dst_step, m, n, k, flags);
+}
+int lapack_gemm64fc(const double *src1, size_t src1_step, const double *src2, size_t src2_step, double alpha,
+                   const double *src3, size_t src3_step, double beta, double *dst, size_t dst_step, int m, int n, int k, int flags)
+{
+    if(m < HAL_GEMM_SMALL_COMPLEX_MATRIX_THRESH)
+        return CV_HAL_ERROR_NOT_IMPLEMENTED;
+    return lapack_gemm_c(src1, src1_step, src2, src2_step, alpha, src3, src3_step, beta, dst, dst_step, m, n, k, flags);
+}
+
+#endif //HAVE_LAPACK
diff --git a/modules/core/src/hal_internal.hpp b/modules/core/src/hal_internal.hpp
new file mode 100644
index 0000000..129a710
--- /dev/null
+++ b/modules/core/src/hal_internal.hpp
@@ -0,0 +1,103 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+//  By downloading, copying, installing or using the software you agree to this license.
+//  If you do not agree to this license, do not download, install,
+//  copy or use the software.
+//
+//
+//                          License Agreement
+//                For Open Source Computer Vision Library
+//
+// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
+// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
+// Copyright (C) 2013, OpenCV Foundation, all rights reserved.
+// Copyright (C) 2015, Itseez Inc., all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+//   * Redistribution's of source code must retain the above copyright notice,
+//     this list of conditions and the following disclaimer.
+//
+//   * Redistribution's in binary form must reproduce the above copyright notice,
+//     this list of conditions and the following disclaimer in the documentation
+//     and/or other materials provided with the distribution.
+//
+//   * The name of the copyright holders may not be used to endorse or promote products
+//     derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#ifndef OPENCV_CORE_HAL_INTERNAL_HPP
+#define OPENCV_CORE_HAL_INTERNAL_HPP
+
+#include "precomp.hpp"
+
+#ifdef HAVE_LAPACK
+
+int lapack_LU32f(float* a, size_t a_step, int m, float* b, size_t b_step, int n, int* info);
+int lapack_LU64f(double* a, size_t a_step, int m, double* b, size_t b_step, int n, int* info);
+int lapack_Cholesky32f(float* a, size_t a_step, int m, float* b, size_t b_step, int n, bool* info);
+int lapack_Cholesky64f(double* a, size_t a_step, int m, double* b, size_t b_step, int n, bool* info);
+int lapack_SVD32f(float* a, size_t a_step, float* w, float* u, size_t u_step, float* vt, size_t v_step, int m, int n, int flags);
+int lapack_SVD64f(double* a, size_t a_step, double* w, double* u, size_t u_step, double* vt, size_t v_step, int m, int n, int flags);
+int lapack_QR32f(float* src1, size_t src1_step, int m, int n, int k, float* src2, size_t src2_step, float* dst, int* info);
+int lapack_QR64f(double* src1, size_t src1_step, int m, int n, int k, double* src2, size_t src2_step, double* dst, int* info);
+int lapack_gemm32f(const float* src1, size_t src1_step, const float* src2, size_t src2_step,
+                   float alpha, const float* src3, size_t src3_step, float beta, float* dst, size_t dst_step,
+                   int m, int n, int k, int flags);
+int lapack_gemm64f(const double* src1, size_t src1_step, const double* src2, size_t src2_step,
+                   double alpha, const double* src3, size_t src3_step, double beta, double* dst, size_t dst_step,
+                   int m, int n, int k, int flags);
+int lapack_gemm32fc(const float* src1, size_t src1_step, const float* src2, size_t src2_step,
+                   float alpha, const float* src3, size_t src3_step, float beta, float* dst, size_t dst_step,
+                   int m, int n, int k, int flags);
+int lapack_gemm64fc(const double* src1, size_t src1_step, const double* src2, size_t src2_step,
+                   double alpha, const double* src3, size_t src3_step, double beta, double* dst, size_t dst_step,
+                   int m, int n, int k, int flags);
+
+#undef cv_hal_LU32f
+#define cv_hal_LU32f lapack_LU32f
+#undef cv_hal_LU64f
+#define cv_hal_LU64f lapack_LU64f
+
+#undef cv_hal_Cholesky32f
+#define cv_hal_Cholesky32f lapack_Cholesky32f
+#undef cv_hal_Cholesky64f
+#define cv_hal_Cholesky64f lapack_Cholesky64f
+
+#undef cv_hal_SVD32f
+#define cv_hal_SVD32f lapack_SVD32f
+#undef cv_hal_SVD64f
+#define cv_hal_SVD64f lapack_SVD64f
+
+#undef cv_hal_QR32f
+#define cv_hal_QR32f lapack_QR32f
+#undef cv_hal_QR64f
+#define cv_hal_QR64f lapack_QR64f
+
+#undef cv_hal_gemm32f
+#define cv_hal_gemm32f lapack_gemm32f
+#undef cv_hal_gemm64f
+#define cv_hal_gemm64f lapack_gemm64f
+#undef cv_hal_gemm32fc
+#define cv_hal_gemm32fc lapack_gemm32fc
+#undef cv_hal_gemm64fc
+#define cv_hal_gemm64fc lapack_gemm64fc
+
+#endif //HAVE_LAPACK
+#endif //OPENCV_CORE_HAL_INTERNAL_HPP
diff --git a/modules/core/src/hal_replacement.hpp b/modules/core/src/hal_replacement.hpp
index 65866f8..9a1177e 100644
--- a/modules/core/src/hal_replacement.hpp
+++ b/modules/core/src/hal_replacement.hpp
@@ -42,51 +42,119 @@
 //
 //M*/
 
-#ifndef __OPENCV_CORE_HAL_REPLACEMENT_HPP__
-#define __OPENCV_CORE_HAL_REPLACEMENT_HPP__
+#ifndef OPENCV_CORE_HAL_REPLACEMENT_HPP
+#define OPENCV_CORE_HAL_REPLACEMENT_HPP
 
 #include "opencv2/core/hal/interface.h"
 
-inline int hal_ni_add8u(const uchar*, size_t, const uchar*, size_t, uchar*, size_t, int, int) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
-inline int hal_ni_add8s(const schar*, size_t, const schar*, size_t, schar*, size_t, int, int) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
-inline int hal_ni_add16u(const ushort*, size_t, const ushort*, size_t, ushort*, size_t, int, int) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
-inline int hal_ni_add16s(const short*, size_t, const short*, size_t, short*, size_t, int, int) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
-inline int hal_ni_add32s(const int*, size_t, const int*, size_t, int*, size_t, int, int) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
-inline int hal_ni_add32f(const float*, size_t, const float*, size_t, float*, size_t, int, int) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
-inline int hal_ni_add64f(const double*, size_t, const double*, size_t, double*, size_t, int, int) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
-inline int hal_ni_sub8u(const uchar*, size_t, const uchar*, size_t, uchar*, size_t, int, int) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
-inline int hal_ni_sub8s(const schar*, size_t, const schar*, size_t, schar*, size_t, int, int) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
-inline int hal_ni_sub16u(const ushort*, size_t, const ushort*, size_t, ushort*, size_t, int, int) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
-inline int hal_ni_sub16s(const short*, size_t, const short*, size_t, short*, size_t, int, int) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
-inline int hal_ni_sub32s(const int*, size_t, const int*, size_t, int*, size_t, int, int) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
-inline int hal_ni_sub32f(const float*, size_t, const float*, size_t, float*, size_t, int, int) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
-inline int hal_ni_sub64f(const double*, size_t, const double*, size_t, double*, size_t, int, int) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
-inline int hal_ni_max8u(const uchar*, size_t, const uchar*, size_t, uchar*, size_t, int, int) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
-inline int hal_ni_max8s(const schar*, size_t, const schar*, size_t, schar*, size_t, int, int) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
-inline int hal_ni_max16u(const ushort*, size_t, const ushort*, size_t, ushort*, size_t, int, int) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
-inline int hal_ni_max16s(const short*, size_t, const short*, size_t, short*, size_t, int, int) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
-inline int hal_ni_max32s(const int*, size_t, const int*, size_t, int*, size_t, int, int) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
-inline int hal_ni_max32f(const float*, size_t, const float*, size_t, float*, size_t, int, int) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
-inline int hal_ni_max64f(const double*, size_t, const double*, size_t, double*, size_t, int, int) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
-inline int hal_ni_min8u(const uchar*, size_t, const uchar*, size_t, uchar*, size_t, int, int) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
-inline int hal_ni_min8s(const schar*, size_t, const schar*, size_t, schar*, size_t, int, int) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
-inline int hal_ni_min16u(const ushort*, size_t, const ushort*, size_t, ushort*, size_t, int, int) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
-inline int hal_ni_min16s(const short*, size_t, const short*, size_t, short*, size_t, int, int) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
-inline int hal_ni_min32s(const int*, size_t, const int*, size_t, int*, size_t, int, int) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
-inline int hal_ni_min32f(const float*, size_t, const float*, size_t, float*, size_t, int, int) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
-inline int hal_ni_min64f(const double*, size_t, const double*, size_t, double*, size_t, int, int) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
-inline int hal_ni_absdiff8u(const uchar*, size_t, const uchar*, size_t, uchar*, size_t, int, int) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
-inline int hal_ni_absdiff8s(const schar*, size_t, const schar*, size_t, schar*, size_t, int, int) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
-inline int hal_ni_absdiff16u(const ushort*, size_t, const ushort*, size_t, ushort*, size_t, int, int) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
-inline int hal_ni_absdiff16s(const short*, size_t, const short*, size_t, short*, size_t, int, int) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
-inline int hal_ni_absdiff32s(const int*, size_t, const int*, size_t, int*, size_t, int, int) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
-inline int hal_ni_absdiff32f(const float*, size_t, const float*, size_t, float*, size_t, int, int) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
-inline int hal_ni_absdiff64f(const double*, size_t, const double*, size_t, double*, size_t, int, int) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
-inline int hal_ni_and8u(const uchar*, size_t, const uchar*, size_t, uchar*, size_t, int, int) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
-inline int hal_ni_or8u(const uchar*, size_t, const uchar*, size_t, uchar*, size_t, int, int) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
-inline int hal_ni_xor8u(const uchar*, size_t, const uchar*, size_t, uchar*, size_t, int, int) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
-inline int hal_ni_not8u(const uchar*, size_t, uchar*, size_t, int, int) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+#if defined __GNUC__
+#  pragma GCC diagnostic push
+#  pragma GCC diagnostic ignored "-Wunused-parameter"
+#elif defined _MSC_VER
+#  pragma warning( push )
+#  pragma warning( disable: 4100 )
+#endif
+
+//! @addtogroup core_hal_interface
+//! @note Define your functions to override default implementations:
+//! @code
+//! #undef hal_add8u
+//! #define hal_add8u my_add8u
+//! @endcode
+//! @{
+
+/**
+Add: _dst[i] = src1[i] + src2[i]_ @n
+Sub: _dst[i] = src1[i] - src2[i]_
+ at param src1_data,src1_step first source image data and step
+ at param src2_data,src2_step second source image data and step
+ at param dst_data,dst_step destination image data and step
+ at param width,height dimensions of the images
+*/
+//! @addtogroup core_hal_interface_addsub Element-wise add and subtract
+//! @{
+inline int hal_ni_add8u(const uchar *src1_data, size_t src1_step, const uchar *src2_data, size_t src2_step, uchar *dst_data, size_t dst_step, int width, int height) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+inline int hal_ni_add8s(const schar *src1_data, size_t src1_step, const schar *src2_data, size_t src2_step, schar *dst_data, size_t dst_step, int width, int height) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+inline int hal_ni_add16u(const ushort *src1_data, size_t src1_step, const ushort *src2_data, size_t src2_step, ushort *dst_data, size_t dst_step, int width, int height) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+inline int hal_ni_add16s(const short *src1_data, size_t src1_step, const short *src2_data, size_t src2_step, short *dst_data, size_t dst_step, int width, int height) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+inline int hal_ni_add32s(const int *src1_data, size_t src1_step, const int *src2_data, size_t src2_step, int *dst_data, size_t dst_step, int width, int height) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+inline int hal_ni_add32f(const float *src1_data, size_t src1_step, const float *src2_data, size_t src2_step, float *dst_data, size_t dst_step, int width, int height) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+inline int hal_ni_add64f(const double *src1_data, size_t src1_step, const double *src2_data, size_t src2_step, double *dst_data, size_t dst_step, int width, int height) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+
+inline int hal_ni_sub8u(const uchar *src1_data, size_t src1_step, const uchar *src2_data, size_t src2_step, uchar *dst_data, size_t dst_step, int width, int height) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+inline int hal_ni_sub8s(const schar *src1_data, size_t src1_step, const schar *src2_data, size_t src2_step, schar *dst_data, size_t dst_step, int width, int height) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+inline int hal_ni_sub16u(const ushort *src1_data, size_t src1_step, const ushort *src2_data, size_t src2_step, ushort *dst_data, size_t dst_step, int width, int height) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+inline int hal_ni_sub16s(const short *src1_data, size_t src1_step, const short *src2_data, size_t src2_step, short *dst_data, size_t dst_step, int width, int height) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+inline int hal_ni_sub32s(const int *src1_data, size_t src1_step, const int *src2_data, size_t src2_step, int *dst_data, size_t dst_step, int width, int height) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+inline int hal_ni_sub32f(const float *src1_data, size_t src1_step, const float *src2_data, size_t src2_step, float *dst_data, size_t dst_step, int width, int height) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+inline int hal_ni_sub64f(const double *src1_data, size_t src1_step, const double *src2_data, size_t src2_step, double *dst_data, size_t dst_step, int width, int height) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+//! @}
+
+/**
+Minimum: _dst[i] = min(src1[i], src2[i])_ @n
+Maximum: _dst[i] = max(src1[i], src2[i])_
+ at param src1_data,src1_step first source image data and step
+ at param src2_data,src2_step second source image data and step
+ at param dst_data,dst_step destination image data and step
+ at param width,height dimensions of the images
+*/
+//! @addtogroup core_hal_interface_minmax Element-wise minimum or maximum
+//! @{
+inline int hal_ni_max8u(const uchar *src1_data, size_t src1_step, const uchar *src2_data, size_t src2_step, uchar *dst_data, size_t dst_step, int width, int height) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+inline int hal_ni_max8s(const schar *src1_data, size_t src1_step, const schar *src2_data, size_t src2_step, schar *dst_data, size_t dst_step, int width, int height) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+inline int hal_ni_max16u(const ushort *src1_data, size_t src1_step, const ushort *src2_data, size_t src2_step, ushort *dst_data, size_t dst_step, int width, int height) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+inline int hal_ni_max16s(const short *src1_data, size_t src1_step, const short *src2_data, size_t src2_step, short *dst_data, size_t dst_step, int width, int height) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+inline int hal_ni_max32s(const int *src1_data, size_t src1_step, const int *src2_data, size_t src2_step, int *dst_data, size_t dst_step, int width, int height) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+inline int hal_ni_max32f(const float *src1_data, size_t src1_step, const float *src2_data, size_t src2_step, float *dst_data, size_t dst_step, int width, int height) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+inline int hal_ni_max64f(const double *src1_data, size_t src1_step, const double *src2_data, size_t src2_step, double *dst_data, size_t dst_step, int width, int height) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+
+inline int hal_ni_min8u(const uchar *src1_data, size_t src1_step, const uchar *src2_data, size_t src2_step, uchar *dst_data, size_t dst_step, int width, int height) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+inline int hal_ni_min8s(const schar *src1_data, size_t src1_step, const schar *src2_data, size_t src2_step, schar *dst_data, size_t dst_step, int width, int height) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+inline int hal_ni_min16u(const ushort *src1_data, size_t src1_step, const ushort *src2_data, size_t src2_step, ushort *dst_data, size_t dst_step, int width, int height) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+inline int hal_ni_min16s(const short *src1_data, size_t src1_step, const short *src2_data, size_t src2_step, short *dst_data, size_t dst_step, int width, int height) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+inline int hal_ni_min32s(const int *src1_data, size_t src1_step, const int *src2_data, size_t src2_step, int *dst_data, size_t dst_step, int width, int height) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+inline int hal_ni_min32f(const float *src1_data, size_t src1_step, const float *src2_data, size_t src2_step, float *dst_data, size_t dst_step, int width, int height) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+inline int hal_ni_min64f(const double *src1_data, size_t src1_step, const double *src2_data, size_t src2_step, double *dst_data, size_t dst_step, int width, int height) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+//! @}
+
+/**
+Absolute difference: _dst[i] = | src1[i] - src2[i] |_
+ at param src1_data,src1_step first source image data and step
+ at param src2_data,src2_step second source image data and step
+ at param dst_data,dst_step destination image data and step
+ at param width,height dimensions of the images
+ at param scale additional multiplier
+*/
+//! @addtogroup core_hal_interface_absdiff Element-wise absolute difference
+//! @{
+inline int hal_ni_absdiff8u(const uchar *src1_data, size_t src1_step, const uchar *src2_data, size_t src2_step, uchar *dst_data, size_t dst_step, int width, int height) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+inline int hal_ni_absdiff8s(const schar *src1_data, size_t src1_step, const schar *src2_data, size_t src2_step, schar *dst_data, size_t dst_step, int width, int height) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+inline int hal_ni_absdiff16u(const ushort *src1_data, size_t src1_step, const ushort *src2_data, size_t src2_step, ushort *dst_data, size_t dst_step, int width, int height) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+inline int hal_ni_absdiff16s(const short *src1_data, size_t src1_step, const short *src2_data, size_t src2_step, short *dst_data, size_t dst_step, int width, int height) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+inline int hal_ni_absdiff32s(const int *src1_data, size_t src1_step, const int *src2_data, size_t src2_step, int *dst_data, size_t dst_step, int width, int height) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+inline int hal_ni_absdiff32f(const float *src1_data, size_t src1_step, const float *src2_data, size_t src2_step, float *dst_data, size_t dst_step, int width, int height) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+inline int hal_ni_absdiff64f(const double *src1_data, size_t src1_step, const double *src2_data, size_t src2_step, double *dst_data, size_t dst_step, int width, int height) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+//! @}
+
+/**
+Bitwise AND: _dst[i] = src1[i] & src2[i]_ @n
+Bitwise OR: _dst[i] = src1[i] | src2[i]_ @n
+Bitwise XOR: _dst[i] = src1[i] ^ src2[i]_ @n
+Bitwise NOT: _dst[i] = !src[i]_
+ at param src1_data,src1_step first source image data and step
+ at param src2_data,src2_step second source image data and step
+ at param dst_data,dst_step destination image data and step
+ at param width,height dimensions of the images
+ */
+//! @addtogroup core_hal_interface_logical Bitwise logical operations
+//! @{
+inline int hal_ni_and8u(const uchar *src1_data, size_t src1_step, const uchar *src2_data, size_t src2_step, uchar *dst_data, size_t dst_step, int width, int height) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+inline int hal_ni_or8u(const uchar *src1_data, size_t src1_step, const uchar *src2_data, size_t src2_step, uchar *dst_data, size_t dst_step, int width, int height) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+inline int hal_ni_xor8u(const uchar *src1_data, size_t src1_step, const uchar *src2_data, size_t src2_step, uchar *dst_data, size_t dst_step, int width, int height) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+inline int hal_ni_not8u(const uchar *src_data, size_t src_step, uchar *dst_data, size_t dst_step, int width, int height) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+//! @}
 
+//! @cond IGNORED
 #define cv_hal_add8u hal_ni_add8u
 #define cv_hal_add8s hal_ni_add8s
 #define cv_hal_add16u hal_ni_add16u
@@ -126,15 +194,28 @@ inline int hal_ni_not8u(const uchar*, size_t, uchar*, size_t, int, int) { return
 #define cv_hal_or8u hal_ni_or8u
 #define cv_hal_xor8u hal_ni_xor8u
 #define cv_hal_not8u hal_ni_not8u
+//! @endcond
 
-inline int hal_ni_cmp8u(const uchar*, size_t, const uchar*, size_t, uchar*, size_t, int, int, int) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
-inline int hal_ni_cmp8s(const schar*, size_t, const schar*, size_t, uchar*, size_t, int, int, int) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
-inline int hal_ni_cmp16u(const ushort*, size_t, const ushort*, size_t, uchar*, size_t, int, int, int) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
-inline int hal_ni_cmp16s(const short*, size_t, const short*, size_t, uchar*, size_t, int, int, int) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
-inline int hal_ni_cmp32s(const int*, size_t, const int*, size_t, uchar*, size_t, int, int, int) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
-inline int hal_ni_cmp32f(const float*, size_t, const float*, size_t, uchar*, size_t, int, int, int) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
-inline int hal_ni_cmp64f(const double*, size_t, const double*, size_t, uchar*, size_t, int, int, int) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+/**
+Compare: _dst[i] = src1[i] op src2[i]_
+ at param src1_data,src1_step first source image data and step
+ at param src2_data,src2_step second source image data and step
+ at param dst_data,dst_step destination image data and step
+ at param width,height dimensions of the images
+ at param operation one of (CV_HAL_CMP_EQ, CV_HAL_CMP_GT, ...)
+*/
+//! @addtogroup core_hal_interface_compare Element-wise compare
+//! @{
+inline int hal_ni_cmp8u(const uchar *src1_data, size_t src1_step, const uchar *src2_data, size_t src2_step, uchar *dst_data, size_t dst_step, int width, int height, int operation) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+inline int hal_ni_cmp8s(const schar *src1_data, size_t src1_step, const schar *src2_data, size_t src2_step, uchar *dst_data, size_t dst_step, int width, int height, int operation) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+inline int hal_ni_cmp16u(const ushort *src1_data, size_t src1_step, const ushort *src2_data, size_t src2_step, uchar *dst_data, size_t dst_step, int width, int height, int operation) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+inline int hal_ni_cmp16s(const short *src1_data, size_t src1_step, const short *src2_data, size_t src2_step, uchar *dst_data, size_t dst_step, int width, int height, int operation) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+inline int hal_ni_cmp32s(const int *src1_data, size_t src1_step, const int *src2_data, size_t src2_step, uchar *dst_data, size_t dst_step, int width, int height, int operation) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+inline int hal_ni_cmp32f(const float *src1_data, size_t src1_step, const float *src2_data, size_t src2_step, uchar *dst_data, size_t dst_step, int width, int height, int operation) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+inline int hal_ni_cmp64f(const double *src1_data, size_t src1_step, const double *src2_data, size_t src2_step, uchar *dst_data, size_t dst_step, int width, int height, int operation) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+//! @}
 
+//! @cond IGNORED
 #define cv_hal_cmp8u hal_ni_cmp8u
 #define cv_hal_cmp8s hal_ni_cmp8s
 #define cv_hal_cmp16u hal_ni_cmp16u
@@ -142,29 +223,65 @@ inline int hal_ni_cmp64f(const double*, size_t, const double*, size_t, uchar*, s
 #define cv_hal_cmp32s hal_ni_cmp32s
 #define cv_hal_cmp32f hal_ni_cmp32f
 #define cv_hal_cmp64f hal_ni_cmp64f
+//! @endcond
 
-inline int hal_ni_mul8u(const uchar*, size_t, const uchar*, size_t, uchar*, size_t, int, int, double) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
-inline int hal_ni_mul8s(const schar*, size_t, const schar*, size_t, schar*, size_t, int, int, double) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
-inline int hal_ni_mul16u(const ushort*, size_t, const ushort*, size_t, ushort*, size_t, int, int, double) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
-inline int hal_ni_mul16s(const short*, size_t, const short*, size_t, short*, size_t, int, int, double) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
-inline int hal_ni_mul32s(const int*, size_t, const int*, size_t, int*, size_t, int, int, double) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
-inline int hal_ni_mul32f(const float*, size_t, const float*, size_t, float*, size_t, int, int, double) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
-inline int hal_ni_mul64f(const double*, size_t, const double*, size_t, double*, size_t, int, int, double) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
-inline int hal_ni_div8u(const uchar*, size_t, const uchar*, size_t, uchar*, size_t, int, int, double) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
-inline int hal_ni_div8s(const schar*, size_t, const schar*, size_t, schar*, size_t, int, int, double) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
-inline int hal_ni_div16u(const ushort*, size_t, const ushort*, size_t, ushort*, size_t, int, int, double) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
-inline int hal_ni_div16s(const short*, size_t, const short*, size_t, short*, size_t, int, int, double) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
-inline int hal_ni_div32s(const int*, size_t, const int*, size_t, int*, size_t, int, int, double) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
-inline int hal_ni_div32f(const float*, size_t, const float*, size_t, float*, size_t, int, int, double) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
-inline int hal_ni_div64f(const double*, size_t, const double*, size_t, double*, size_t, int, int, double) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
-inline int hal_ni_recip8u(const uchar*, size_t, const uchar*, size_t, uchar*, size_t, int, int, double) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
-inline int hal_ni_recip8s(const schar*, size_t, const schar*, size_t, schar*, size_t, int, int, double) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
-inline int hal_ni_recip16u(const ushort*, size_t, const ushort*, size_t, ushort*, size_t, int, int, double) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
-inline int hal_ni_recip16s(const short*, size_t, const short*, size_t, short*, size_t, int, int, double) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
-inline int hal_ni_recip32s(const int*, size_t, const int*, size_t, int*, size_t, int, int, double) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
-inline int hal_ni_recip32f(const float*, size_t, const float*, size_t, float*, size_t, int, int, double) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
-inline int hal_ni_recip64f(const double*, size_t, const double*, size_t, double*, size_t, int, int, double) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+/**
+Multiply: _dst[i] = scale * src1[i] * src2[i]_
+ at param src1_data,src1_step first source image data and step
+ at param src2_data,src2_step second source image data and step
+ at param dst_data,dst_step destination image data and step
+ at param width,height dimensions of the images
+ at param scale additional multiplier
+*/
+//! @addtogroup core_hal_interface_multiply Element-wise multiply
+//! @{
+inline int hal_ni_mul8u(const uchar *src1_data, size_t src1_step, const uchar *src2_data, size_t src2_step, uchar *dst_data, size_t dst_step, int width, int height, double scale) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+inline int hal_ni_mul8s(const schar *src1_data, size_t src1_step, const schar *src2_data, size_t src2_step, schar *dst_data, size_t dst_step, int width, int height, double scale) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+inline int hal_ni_mul16u(const ushort *src1_data, size_t src1_step, const ushort *src2_data, size_t src2_step, ushort *dst_data, size_t dst_step, int width, int height, double scale) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+inline int hal_ni_mul16s(const short *src1_data, size_t src1_step, const short *src2_data, size_t src2_step, short *dst_data, size_t dst_step, int width, int height, double scale) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+inline int hal_ni_mul32s(const int *src1_data, size_t src1_step, const int *src2_data, size_t src2_step, int *dst_data, size_t dst_step, int width, int height, double scale) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+inline int hal_ni_mul32f(const float *src1_data, size_t src1_step, const float *src2_data, size_t src2_step, float *dst_data, size_t dst_step, int width, int height, double scale) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+inline int hal_ni_mul64f(const double *src1_data, size_t src1_step, const double *src2_data, size_t src2_step, double *dst_data, size_t dst_step, int width, int height, double scale) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+//! @}
 
+/**
+Divide: _dst[i] = scale * src1[i] / src2[i]_
+ at param src1_data,src1_step first source image data and step
+ at param src2_data,src2_step second source image data and step
+ at param dst_data,dst_step destination image data and step
+ at param width,height dimensions of the images
+ at param scale additional multiplier
+*/
+//! @addtogroup core_hal_interface_divide Element-wise divide
+//! @{
+inline int hal_ni_div8u(const uchar *src1_data, size_t src1_step, const uchar *src2_data, size_t src2_step, uchar *dst_data, size_t dst_step, int width, int height, double scale) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+inline int hal_ni_div8s(const schar *src1_data, size_t src1_step, const schar *src2_data, size_t src2_step, schar *dst_data, size_t dst_step, int width, int height, double scale) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+inline int hal_ni_div16u(const ushort *src1_data, size_t src1_step, const ushort *src2_data, size_t src2_step, ushort *dst_data, size_t dst_step, int width, int height, double scale) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+inline int hal_ni_div16s(const short *src1_data, size_t src1_step, const short *src2_data, size_t src2_step, short *dst_data, size_t dst_step, int width, int height, double scale) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+inline int hal_ni_div32s(const int *src1_data, size_t src1_step, const int *src2_data, size_t src2_step, int *dst_data, size_t dst_step, int width, int height, double scale) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+inline int hal_ni_div32f(const float *src1_data, size_t src1_step, const float *src2_data, size_t src2_step, float *dst_data, size_t dst_step, int width, int height, double scale) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+inline int hal_ni_div64f(const double *src1_data, size_t src1_step, const double *src2_data, size_t src2_step, double *dst_data, size_t dst_step, int width, int height, double scale) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+//! @}
+
+/**
+Computes reciprocial: _dst[i] = scale / src[i]_
+ at param src_data,src_step source image data and step
+ at param dst_data,dst_step destination image data and step
+ at param width,height dimensions of the images
+ at param scale additional multiplier
+ */
+//! @addtogroup core_hal_interface_reciprocial Element-wise reciprocial
+//! @{
+inline int hal_ni_recip8u(const uchar *src_data, size_t src_step, uchar *dst_data, size_t dst_step, int width, int height, double scale) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+inline int hal_ni_recip8s(const schar *src_data, size_t src_step, schar *dst_data, size_t dst_step, int width, int height, double scale) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+inline int hal_ni_recip16u(const ushort *src_data, size_t src_step, ushort *dst_data, size_t dst_step, int width, int height, double scale) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+inline int hal_ni_recip16s(const short *src_data, size_t src_step, short *dst_data, size_t dst_step, int width, int height, double scale) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+inline int hal_ni_recip32s(const int *src_data, size_t src_step, int *dst_data, size_t dst_step, int width, int height, double scale) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+inline int hal_ni_recip32f(const float *src_data, size_t src_step, float *dst_data, size_t dst_step, int width, int height, double scale) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+inline int hal_ni_recip64f(const double *src_data, size_t src_step, double *dst_data, size_t dst_step, int width, int height, double scale) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+//! @}
+
+//! @cond IGNORED
 #define cv_hal_mul8u hal_ni_mul8u
 #define cv_hal_mul8s hal_ni_mul8s
 #define cv_hal_mul16u hal_ni_mul16u
@@ -186,15 +303,28 @@ inline int hal_ni_recip64f(const double*, size_t, const double*, size_t, double*
 #define cv_hal_recip32s hal_ni_recip32s
 #define cv_hal_recip32f hal_ni_recip32f
 #define cv_hal_recip64f hal_ni_recip64f
+//! @endcond
 
-inline int hal_ni_addWeighted8u(const uchar*, size_t, const uchar*, size_t, uchar*, size_t, int, int, const double*) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
-inline int hal_ni_addWeighted8s(const schar*, size_t, const schar*, size_t, schar*, size_t, int, int, const double*) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
-inline int hal_ni_addWeighted16u(const ushort*, size_t, const ushort*, size_t, ushort*, size_t, int, int, const double*) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
-inline int hal_ni_addWeighted16s(const short*, size_t, const short*, size_t, short*, size_t, int, int, const double*) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
-inline int hal_ni_addWeighted32s(const int*, size_t, const int*, size_t, int*, size_t, int, int, const double*) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
-inline int hal_ni_addWeighted32f(const float*, size_t, const float*, size_t, float*, size_t, int, int, const double*) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
-inline int hal_ni_addWeighted64f(const double*, size_t, const double*, size_t, double*, size_t, int, int, const double*) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+/**
+Computes weighted sum of two arrays using formula: _dst[i] = a * src1[i] + b * src2[i] + c_
+ at param src1_data,src1_step first source image data and step
+ at param src2_data,src2_step second source image data and step
+ at param dst_data,dst_step destination image data and step
+ at param width,height dimensions of the images
+ at param scalars numbers _a_, _b_, and _c_
+ */
+//! @addtogroup core_hal_interface_addWeighted Element-wise weighted sum
+//! @{
+inline int hal_ni_addWeighted8u(const uchar *src1_data, size_t src1_step, const uchar *src2_data, size_t src2_step, uchar *dst_data, size_t dst_step, int width, int height, const double scalars[3]) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+inline int hal_ni_addWeighted8s(const schar *src1_data, size_t src1_step, const schar *src2_data, size_t src2_step, schar *dst_data, size_t dst_step, int width, int height, const double scalars[3]) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+inline int hal_ni_addWeighted16u(const ushort *src1_data, size_t src1_step, const ushort *src2_data, size_t src2_step, ushort *dst_data, size_t dst_step, int width, int height, const double scalars[3]) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+inline int hal_ni_addWeighted16s(const short *src1_data, size_t src1_step, const short *src2_data, size_t src2_step, short *dst_data, size_t dst_step, int width, int height, const double scalars[3]) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+inline int hal_ni_addWeighted32s(const int *src1_data, size_t src1_step, const int *src2_data, size_t src2_step, int *dst_data, size_t dst_step, int width, int height, const double scalars[3]) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+inline int hal_ni_addWeighted32f(const float *src1_data, size_t src1_step, const float *src2_data, size_t src2_step, float *dst_data, size_t dst_step, int width, int height, const double scalars[3]) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+inline int hal_ni_addWeighted64f(const double *src1_data, size_t src1_step, const double *src2_data, size_t src2_step, double *dst_data, size_t dst_step, int width, int height, const double scalars[3]) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+//! @}
 
+//! @cond IGNORED
 #define cv_hal_addWeighted8u hal_ni_addWeighted8u
 #define cv_hal_addWeighted8s hal_ni_addWeighted8s
 #define cv_hal_addWeighted16u hal_ni_addWeighted16u
@@ -202,27 +332,419 @@ inline int hal_ni_addWeighted64f(const double*, size_t, const double*, size_t, d
 #define cv_hal_addWeighted32s hal_ni_addWeighted32s
 #define cv_hal_addWeighted32f hal_ni_addWeighted32f
 #define cv_hal_addWeighted64f hal_ni_addWeighted64f
+//! @endcond
 
-inline int hal_ni_split8u(const uchar*, uchar**, int, int) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
-inline int hal_ni_split16u(const ushort*, ushort**, int, int) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
-inline int hal_ni_split32s(const int*, int**, int, int) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
-inline int hal_ni_split64s(const int64*, int64**, int, int) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+/**
+ at param src_data array of interleaved values (__len__ x __cn__ items) [ B, G, R, B, G, R, ...]
+ at param dst_data array of pointers to destination arrays (__cn__ items x __len__ items) [ [B, B, ...], [G, G, ...], [R, R, ...] ]
+ at param len number of elements
+ at param cn number of channels
+ */
+//! @addtogroup core_hal_interface_split Channel split
+//! @{
+inline int hal_ni_split8u(const uchar *src_data, uchar **dst_data, int len, int cn) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+inline int hal_ni_split16u(const ushort *src_data, ushort **dst_data, int len, int cn) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+inline int hal_ni_split32s(const int *src_data, int **dst_data, int len, int cn) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+inline int hal_ni_split64s(const int64 *src_data, int64 **dst_data, int len, int cn) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+//! @}
 
+//! @cond IGNORED
 #define cv_hal_split8u hal_ni_split8u
 #define cv_hal_split16u hal_ni_split16u
 #define cv_hal_split32s hal_ni_split32s
 #define cv_hal_split64s hal_ni_split64s
+//! @endcond
 
-inline int hal_ni_merge8u(const uchar**, uchar*, int, int) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
-inline int hal_ni_merge16u(const ushort**, ushort*, int, int) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
-inline int hal_ni_merge32s(const int**, int*, int, int) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
-inline int hal_ni_merge64s(const int64**, int64*, int, int) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+/**
+ at param src_data array of pointers to source arrays (__cn__ items x __len__ items) [ [B, B, ...], [G, G, ...], [R, R, ...] ]
+ at param dst_data destination array of interleaved values (__len__ x __cn__ items) [ B, G, R, B, G, R, ...]
+ at param len number of elements
+ at param cn number of channels
+ */
+//! @addtogroup core_hal_interface_merge Channel merge
+//! @{
+inline int hal_ni_merge8u(const uchar **src_data, uchar *dst_data, int len, int cn) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+inline int hal_ni_merge16u(const ushort **src_data, ushort *dst_data, int len, int cn) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+inline int hal_ni_merge32s(const int **src_data, int *dst_data, int len, int cn) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+inline int hal_ni_merge64s(const int64 **src_data, int64 *dst_data, int len, int cn) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+//! @}
 
+//! @cond IGNORED
 #define cv_hal_merge8u hal_ni_merge8u
 #define cv_hal_merge16u hal_ni_merge16u
 #define cv_hal_merge32s hal_ni_merge32s
 #define cv_hal_merge64s hal_ni_merge64s
+//! @endcond
+
+
+/**
+ at param y,x source Y and X arrays
+ at param dst destination array
+ at param len length of arrays
+ at param angleInDegrees if set to true return angles in degrees, otherwise in radians
+ */
+//! @addtogroup core_hal_interface_fastAtan Atan calculation
+//! @{
+inline int hal_ni_fastAtan32f(const float* y, const float* x, float* dst, int len, bool angleInDegrees) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+inline int hal_ni_fastAtan64f(const double* y, const double* x, double* dst, int len, bool angleInDegrees) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+//! @}
+
+//! @cond IGNORED
+#define cv_hal_fastAtan32f hal_ni_fastAtan32f
+#define cv_hal_fastAtan64f hal_ni_fastAtan64f
+//! @endcond
+
+
+/**
+ at param x,y source X and Y arrays
+ at param dst destination array
+ at param len length of arrays
+ */
+//! @addtogroup core_hal_interface_magnitude Magnitude calculation
+//! @{
+inline int hal_ni_magnitude32f(const float *x, const float *y, float *dst, int len) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+inline int hal_ni_magnitude64f(const double *x, const double  *y, double *dst, int len) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+//! @}
+
+//! @cond IGNORED
+#define cv_hal_magnitude32f hal_ni_magnitude32f
+#define cv_hal_magnitude64f hal_ni_magnitude64f
+//! @endcond
+
+
+/**
+ at param src source array
+ at param dst destination array
+ at param len length of arrays
+ */
+//! @addtogroup core_hal_interface_invSqrt Inverse square root calculation
+//! @{
+inline int hal_ni_invSqrt32f(const float* src, float* dst, int len) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+inline int hal_ni_invSqrt64f(const double* src, double* dst, int len) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+//! @}
+
+//! @cond IGNORED
+#define cv_hal_invSqrt32f hal_ni_invSqrt32f
+#define cv_hal_invSqrt64f hal_ni_invSqrt64f
+//! @endcond
+
+
+/**
+ at param src source array
+ at param dst destination array
+ at param len length of arrays
+ */
+//! @addtogroup core_hal_interface_sqrt Square root calculation
+//! @{
+inline int hal_ni_sqrt32f(const float* src, float* dst, int len) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+inline int hal_ni_sqrt64f(const double* src, double* dst, int len) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+//! @}
+
+//! @cond IGNORED
+#define cv_hal_sqrt32f hal_ni_sqrt32f
+#define cv_hal_sqrt64f hal_ni_sqrt64f
+//! @endcond
+
+
+/**
+ at param src source array
+ at param dst destination array
+ at param len length of arrays
+ */
+//! @addtogroup core_hal_interface_log Natural logarithm calculation
+//! @{
+inline int hal_ni_log32f(const float* src, float* dst, int len) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+inline int hal_ni_log64f(const double* src, double* dst, int len) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+//! @}
+
+//! @cond IGNORED
+#define cv_hal_log32f hal_ni_log32f
+#define cv_hal_log64f hal_ni_log64f
+//! @endcond
+
+
+/**
+ at param src source array
+ at param dst destination array
+ at param len length of arrays
+ */
+//! @addtogroup core_hal_interface_exp Exponent calculation
+//! @{
+inline int hal_ni_exp32f(const float* src, float* dst, int len) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+inline int hal_ni_exp64f(const double* src, double* dst, int len) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+//! @}
+
+//! @cond IGNORED
+#define cv_hal_exp32f hal_ni_exp32f
+#define cv_hal_exp64f hal_ni_exp64f
+//! @endcond
+
+
+/**
+ at brief Dummy structure storing DFT/DCT context
 
+Users can convert this pointer to any type they want. Initialisation and destruction should be made in Init and Free function implementations correspondingly.
+Example:
+ at code{.cpp}
+int my_hal_dftInit2D(cvhalDFT **context, ...) {
+    *context = static_cast<cvhalDFT*>(new MyFilterData());
+    //... init
+}
+
+int my_hal_dftFree2D(cvhalDFT *context) {
+    MyFilterData *c = static_cast<MyFilterData*>(context);
+    delete c;
+}
+ at endcode
+ */
+struct cvhalDFT {};
+
+/**
+ at param context double pointer to context storing all necessary data
+ at param len transformed array length
+ at param count estimated transformation count
+ at param depth array type (CV_32F or CV_64F)
+ at param flags algorithm options (combination of CV_HAL_DFT_INVERSE, CV_HAL_DFT_SCALE, ...)
+ at param needBuffer pointer to boolean variable, if valid pointer provided, then variable value should be set to true to signal that additional memory buffer is needed for operations
+ */
+inline int hal_ni_dftInit1D(cvhalDFT **context, int len, int count, int depth, int flags, bool *needBuffer) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+/**
+ at param context pointer to context storing all necessary data
+ at param src source data
+ at param dst destination data
+ */
+inline int hal_ni_dft1D(cvhalDFT *context, const uchar *src, uchar *dst) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+/**
+ at param context pointer to context storing all necessary data
+ */
+inline int hal_ni_dftFree1D(cvhalDFT *context) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+
+//! @cond IGNORED
+#define cv_hal_dftInit1D hal_ni_dftInit1D
+#define cv_hal_dft1D hal_ni_dft1D
+#define cv_hal_dftFree1D hal_ni_dftFree1D
+//! @endcond
+
+/**
+ at param context double pointer to context storing all necessary data
+ at param width,height image dimensions
+ at param depth image type (CV_32F or CV64F)
+ at param src_channels number of channels in input image
+ at param dst_channels number of channels in output image
+ at param flags algorithm options (combination of CV_HAL_DFT_INVERSE, ...)
+ at param nonzero_rows number of nonzero rows in image, can be used for optimization
+ */
+inline int hal_ni_dftInit2D(cvhalDFT **context, int width, int height, int depth, int src_channels, int dst_channels, int flags, int nonzero_rows) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+/**
+ at param context pointer to context storing all necessary data
+ at param src_data,src_step source image data and step
+ at param dst_data,dst_step destination image data and step
+ */
+inline int hal_ni_dft2D(cvhalDFT *context, const uchar *src_data, size_t src_step, uchar *dst_data, size_t dst_step) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+/**
+ at param context pointer to context storing all necessary data
+ */
+inline int hal_ni_dftFree2D(cvhalDFT *context) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+
+//! @cond IGNORED
+#define cv_hal_dftInit2D hal_ni_dftInit2D
+#define cv_hal_dft2D hal_ni_dft2D
+#define cv_hal_dftFree2D hal_ni_dftFree2D
+//! @endcond
+
+/**
+ at param context double pointer to context storing all necessary data
+ at param width,height image dimensions
+ at param depth image type (CV_32F or CV64F)
+ at param flags algorithm options (combination of CV_HAL_DFT_INVERSE, ...)
+ */
+inline int hal_ni_dctInit2D(cvhalDFT **context, int width, int height, int depth, int flags) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+/**
+ at param context pointer to context storing all necessary data
+ at param src_data,src_step source image data and step
+ at param dst_data,dst_step destination image data and step
+ */
+inline int hal_ni_dct2D(cvhalDFT *context, const uchar *src_data, size_t src_step, uchar *dst_data, size_t dst_step) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+/**
+ at param context pointer to context storing all necessary data
+ */
+inline int hal_ni_dctFree2D(cvhalDFT *context) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+
+//! @cond IGNORED
+#define cv_hal_dctInit2D hal_ni_dctInit2D
+#define cv_hal_dct2D hal_ni_dct2D
+#define cv_hal_dctFree2D hal_ni_dctFree2D
+//! @endcond
+
+
+/**
+Performs \f$LU\f$ decomposition of square matrix \f$A=P*L*U\f$ (where \f$P\f$ is permutation matrix) and solves matrix equation \f$A*X=B\f$.
+Function returns the \f$sign\f$ of permutation \f$P\f$ via parameter info.
+ at param src1 pointer to input matrix \f$A\f$ stored in row major order. After finish of work src1 contains at least \f$U\f$ part of \f$LU\f$
+decomposition which is appropriate for determainant calculation: \f$det(A)=sign*\prod_{j=1}^{M}a_{jj}\f$.
+ at param src1_step number of bytes between two consequent rows of matrix \f$A\f$.
+ at param m size of square matrix \f$A\f$.
+ at param src2 pointer to \f$M\times N\f$ matrix \f$B\f$ which is the right-hand side of system \f$A*X=B\f$. \f$B\f$ stored in row major order.
+If src2 is null pointer only \f$LU\f$ decomposition will be performed. After finish of work src2 contains solution \f$X\f$ of system \f$A*X=B\f$.
+ at param src2_step number of bytes between two consequent rows of matrix \f$B\f$.
+ at param n number of right-hand vectors in \f$M\times N\f$ matrix \f$B\f$.
+ at param info indicates success of decomposition. If *info is equals to zero decomposition failed, othervise *info is equals to \f$sign\f$.
+ */
+//! @addtogroup core_hal_interface_decomp_lu LU matrix decomposition
+//! @{
+inline int hal_ni_LU32f(float* src1, size_t src1_step, int m, float* src2, size_t src2_step, int n, int* info) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+inline int hal_ni_LU64f(double* src1, size_t src1_step, int m, double* src2, size_t src2_step, int n, int* info) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+//! @}
+
+/**
+Performs Cholesky decomposition of matrix \f$A = L*L^T\f$ and solves matrix equation \f$A*X=B\f$.
+ at param src1 pointer to input matrix \f$A\f$ stored in row major order. After finish of work src1 contains lower triangular matrix \f$L\f$.
+ at param src1_step number of bytes between two consequent rows of matrix \f$A\f$.
+ at param m size of square matrix \f$A\f$.
+ at param src2 pointer to \f$M\times N\f$ matrix \f$B\f$ which is the right-hand side of system \f$A*X=B\f$. B stored in row major order.
+If src2 is null pointer only Cholesky decomposition will be performed. After finish of work src2 contains solution \f$X\f$ of system \f$A*X=B\f$.
+ at param src2_step number of bytes between two consequent rows of matrix \f$B\f$.
+ at param n number of right-hand vectors in \f$M\times N\f$ matrix \f$B\f$.
+ at param info indicates success of decomposition. If *info is false decomposition failed.
+ */
+
+//! @addtogroup core_hal_interface_decomp_cholesky Cholesky matrix decomposition
+//! @{
+inline int hal_ni_Cholesky32f(float* src1, size_t src1_step, int m, float* src2, size_t src2_step, int n, bool* info) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+inline int hal_ni_Cholesky64f(double* src1, size_t src1_step, int m, double* src2, size_t src2_step, int n, bool* info) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+//! @}
+
+/**
+Performs singular value decomposition of \f$M\times N\f$(\f$M>N\f$) matrix \f$A = U*\Sigma*V^T\f$.
+ at param src pointer to input \f$M\times N\f$ matrix \f$A\f$ stored in column major order.
+After finish of work src will be filled with rows of \f$U\f$ or not modified (depends of flag CV_HAL_SVD_MODIFY_A).
+ at param src_step number of bytes between two consequent columns of matrix \f$A\f$.
+ at param w pointer to array for singular values of matrix \f$A\f$ (i. e. first \f$N\f$ diagonal elements of matrix \f$\Sigma\f$).
+ at param u pointer to output \f$M\times N\f$ or \f$M\times M\f$ matrix \f$U\f$ (size depends of flags). Pointer must be valid if flag CV_HAL_SVD_MODIFY_A not used.
+ at param u_step number of bytes between two consequent rows of matrix \f$U\f$.
+ at param vt pointer to array for \f$N\times N\f$ matrix \f$V^T\f$.
+ at param vt_step number of bytes between two consequent rows of matrix \f$V^T\f$.
+ at param m number fo rows in matrix \f$A\f$.
+ at param n number of columns in matrix \f$A\f$.
+ at param flags algorithm options (combination of CV_HAL_SVD_FULL_UV, ...).
+ */
+//! @addtogroup core_hal_interface_decomp_svd Singular value matrix decomposition
+//! @{
+inline int hal_ni_SVD32f(float* src, size_t src_step, float* w, float* u, size_t u_step, float* vt, size_t vt_step, int m, int n, int flags) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+inline int hal_ni_SVD64f(double* src, size_t src_step, double* w, double* u, size_t u_step, double* vt, size_t vt_step, int m, int n, int flags) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+//! @}
+
+/**
+Performs QR decomposition of \f$M\times N\f$(\f$M>N\f$) matrix \f$A = Q*R\f$ and solves matrix equation \f$A*X=B\f$.
+ at param src1 pointer to input matrix \f$A\f$ stored in row major order. After finish of work src1 contains upper triangular \f$N\times N\f$ matrix \f$R\f$.
+Lower triangle of src1 will be filled with vectors of elementary reflectors. See @cite VandLec and Lapack's DGEQRF documentation for details.
+ at param src1_step number of bytes between two consequent rows of matrix \f$A\f$.
+ at param m number fo rows in matrix \f$A\f$.
+ at param n number of columns in matrix \f$A\f$.
+ at param k number of right-hand vectors in \f$M\times K\f$ matrix \f$B\f$.
+ at param src2 pointer to \f$M\times K\f$ matrix \f$B\f$ which is the right-hand side of system \f$A*X=B\f$. \f$B\f$ stored in row major order.
+If src2 is null pointer only QR decomposition will be performed. Otherwise system will be solved and src1 will be used as temporary buffer, so
+after finish of work src2 contains solution \f$X\f$ of system \f$A*X=B\f$.
+ at param src2_step number of bytes between two consequent rows of matrix \f$B\f$.
+ at param dst pointer to continiuos \f$N\times 1\f$ array for scalar factors of elementary reflectors. See @cite VandLec for details.
+ at param info indicates success of decomposition. If *info is zero decomposition failed.
+*/
+//! @addtogroup core_hal_interface_decomp_qr QR matrix decomposition
+//! @{
+inline int hal_ni_QR32f(float* src1, size_t src1_step, int m, int n, int k, float* src2, size_t src2_step, float* dst, int* info) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+inline int hal_ni_QR64f(double* src1, size_t src1_step, int m, int n, int k, double* src2, size_t src2_step, double* dst, int* info) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+//! @}
+
+
+
+//! @cond IGNORED
+#define cv_hal_LU32f hal_ni_LU32f
+#define cv_hal_LU64f hal_ni_LU64f
+#define cv_hal_Cholesky32f hal_ni_Cholesky32f
+#define cv_hal_Cholesky64f hal_ni_Cholesky64f
+#define cv_hal_SVD32f hal_ni_SVD32f
+#define cv_hal_SVD64f hal_ni_SVD64f
+#define cv_hal_QR32f hal_ni_QR32f
+#define cv_hal_QR64f hal_ni_QR64f
+//! @endcond
+
+
+/**
+The function performs generalized matrix multiplication similar to the gemm functions in BLAS level 3:
+\f$D = \alpha*AB+\beta*C\f$
+
+ at param src1 pointer to input \f$M\times N\f$ matrix \f$A\f$ or \f$A^T\f$ stored in row major order.
+ at param src1_step number of bytes between two consequent rows of matrix \f$A\f$ or \f$A^T\f$.
+ at param src2 pointer to input \f$N\times K\f$ matrix \f$B\f$ or \f$B^T\f$ stored in row major order.
+ at param src2_step number of bytes between two consequent rows of matrix \f$B\f$ or \f$B^T\f$.
+ at param alpha \f$\alpha\f$ multiplier before \f$AB\f$
+ at param src3 pointer to input \f$M\times K\f$ matrix \f$C\f$ or \f$C^T\f$ stored in row major order.
+ at param src3_step number of bytes between two consequent rows of matrix \f$C\f$ or \f$C^T\f$.
+ at param beta \f$\beta\f$ multiplier before \f$C\f$
+ at param dst pointer to input \f$M\times K\f$ matrix \f$D\f$ stored in row major order.
+ at param dst_step number of bytes between two consequent rows of matrix \f$D\f$.
+ at param m number of rows in matrix \f$A\f$ or \f$A^T\f$, equals to number of rows in matrix \f$D\f$
+ at param n number of columns in matrix \f$A\f$ or \f$A^T\f$
+ at param k number of columns in matrix \f$B\f$ or \f$B^T\f$, equals to number of columns in matrix \f$D\f$
+ at param flags algorithm options (combination of CV_HAL_GEMM_1_T, ...).
+ */
+
+//! @addtogroup core_hal_interface_matrix_multiplication Matrix multiplication
+//! @{
+inline int hal_ni_gemm32f(const float* src1, size_t src1_step, const float* src2, size_t src2_step,
+                          float alpha, const float* src3, size_t src3_step, float beta, float* dst, size_t dst_step,
+                          int m, int n, int k, int flags) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+inline int hal_ni_gemm64f(const double* src1, size_t src1_step, const double* src2, size_t src2_step,
+                          double alpha, const double* src3, size_t src3_step, double beta, double* dst, size_t dst_step,
+                          int m, int n, int k, int flags) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+inline int hal_ni_gemm32fc(const float* src1, size_t src1_step, const float* src2, size_t src2_step,
+                          float alpha, const float* src3, size_t src3_step, float beta, float* dst, size_t dst_step,
+                          int m, int n, int k, int flags) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+inline int hal_ni_gemm64fc(const double* src1, size_t src1_step, const double* src2, size_t src2_step,
+                          double alpha, const double* src3, size_t src3_step, double beta, double* dst, size_t dst_step,
+                          int m, int n, int k, int flags) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+//! @}
+
+//! @cond IGNORED
+#define cv_hal_gemm32f hal_ni_gemm32f
+#define cv_hal_gemm64f hal_ni_gemm64f
+#define cv_hal_gemm32fc hal_ni_gemm32fc
+#define cv_hal_gemm64fc hal_ni_gemm64fc
+//! @endcond
+
+//! @}
+
+
+#if defined __GNUC__
+#  pragma GCC diagnostic pop
+#elif defined _MSC_VER
+#  pragma warning( pop )
+#endif
+
+#include "hal_internal.hpp"
 #include "custom_hal.hpp"
 
+//! @cond IGNORED
+#define CALL_HAL_RET(name, fun, retval, ...) \
+{ \
+    int res = fun(__VA_ARGS__, &retval); \
+    if (res == CV_HAL_ERROR_OK) \
+        return retval; \
+    else if (res != CV_HAL_ERROR_NOT_IMPLEMENTED) \
+        CV_Error_(cv::Error::StsInternal, \
+            ("HAL implementation " CVAUX_STR(name) " ==> " CVAUX_STR(fun) " returned %d (0x%08x)", res, res)); \
+}
+
+
+#define CALL_HAL(name, fun, ...) \
+{ \
+    int res = fun(__VA_ARGS__); \
+    if (res == CV_HAL_ERROR_OK) \
+        return; \
+    else if (res != CV_HAL_ERROR_NOT_IMPLEMENTED) \
+        CV_Error_(cv::Error::StsInternal, \
+            ("HAL implementation " CVAUX_STR(name) " ==> " CVAUX_STR(fun) " returned %d (0x%08x)", res, res)); \
+}
+//! @endcond
+
 #endif
diff --git a/modules/core/src/kmeans.cpp b/modules/core/src/kmeans.cpp
index a81334a..df017ad 100644
--- a/modules/core/src/kmeans.cpp
+++ b/modules/core/src/kmeans.cpp
@@ -219,6 +219,8 @@ double cv::kmeans( InputArray _data, int K,
                    TermCriteria criteria, int attempts,
                    int flags, OutputArray _centers )
 {
+    CV_INSTRUMENT_REGION()
+
     const int SPP_TRIALS = 3;
     Mat data0 = _data.getMat();
     bool isrow = data0.rows == 1;
diff --git a/modules/core/src/lapack.cpp b/modules/core/src/lapack.cpp
index 4fcf3c7..a602eec 100644
--- a/modules/core/src/lapack.cpp
+++ b/modules/core/src/lapack.cpp
@@ -52,21 +52,29 @@ namespace cv
 
 int LU(float* A, size_t astep, int m, float* b, size_t bstep, int n)
 {
+    CV_INSTRUMENT_REGION()
+
     return hal::LU32f(A, astep, m, b, bstep, n);
 }
 
 int LU(double* A, size_t astep, int m, double* b, size_t bstep, int n)
 {
+    CV_INSTRUMENT_REGION()
+
     return hal::LU64f(A, astep, m, b, bstep, n);
 }
 
 bool Cholesky(float* A, size_t astep, int m, float* b, size_t bstep, int n)
 {
+    CV_INSTRUMENT_REGION()
+
     return hal::Cholesky32f(A, astep, m, b, bstep, n);
 }
 
 bool Cholesky(double* A, size_t astep, int m, double* b, size_t bstep, int n)
 {
+    CV_INSTRUMENT_REGION()
+
     return hal::Cholesky64f(A, astep, m, b, bstep, n);
 }
 
@@ -570,11 +578,44 @@ JacobiSVDImpl_(_Tp* At, size_t astep, _Tp* _W, _Tp* Vt, size_t vstep,
 
 static void JacobiSVD(float* At, size_t astep, float* W, float* Vt, size_t vstep, int m, int n, int n1=-1)
 {
-    JacobiSVDImpl_(At, astep, W, Vt, vstep, m, n, !Vt ? 0 : n1 < 0 ? n : n1, FLT_MIN, FLT_EPSILON*2);
+    hal::SVD32f(At, astep, W, NULL, astep, Vt, vstep, m, n, n1);
 }
 
 static void JacobiSVD(double* At, size_t astep, double* W, double* Vt, size_t vstep, int m, int n, int n1=-1)
 {
+    hal::SVD64f(At, astep, W, NULL, astep, Vt, vstep, m, n, n1);
+}
+
+template <typename fptype> static inline int
+decodeSVDParameters(const fptype* U, const fptype* Vt, int m, int n, int n1)
+{
+    int halSVDFlag = 0;
+    if(Vt == NULL)
+        halSVDFlag = CV_HAL_SVD_NO_UV;
+    else if(n1 <= 0 || n1 == n)
+    {
+        halSVDFlag = CV_HAL_SVD_SHORT_UV;
+        if(U == NULL)
+            halSVDFlag |= CV_HAL_SVD_MODIFY_A;
+    }
+    else if(n1 == m)
+    {
+        halSVDFlag = CV_HAL_SVD_FULL_UV;
+        if(U == NULL)
+            halSVDFlag |= CV_HAL_SVD_MODIFY_A;
+    }
+    return halSVDFlag;
+}
+
+void hal::SVD32f(float* At, size_t astep, float* W, float* U, size_t ustep, float* Vt, size_t vstep, int m, int n, int n1)
+{
+    CALL_HAL(SVD32f, cv_hal_SVD32f, At, astep, W, U, ustep, Vt, vstep, m, n, decodeSVDParameters(U, Vt, m, n, n1))
+    JacobiSVDImpl_(At, astep, W, Vt, vstep, m, n, !Vt ? 0 : n1 < 0 ? n : n1, FLT_MIN, FLT_EPSILON*2);
+}
+
+void hal::SVD64f(double* At, size_t astep, double* W, double* U, size_t ustep, double* Vt, size_t vstep, int m, int n, int n1)
+{
+    CALL_HAL(SVD64f, cv_hal_SVD64f, At, astep, W, U, ustep, Vt, vstep, m, n, decodeSVDParameters(U, Vt, m, n, n1))
     JacobiSVDImpl_(At, astep, W, Vt, vstep, m, n, !Vt ? 0 : n1 < 0 ? n : n1, DBL_MIN, DBL_EPSILON*10);
 }
 
@@ -713,6 +754,8 @@ SVBkSb( int m, int n, const double* w, size_t wstep,
 
 double cv::determinant( InputArray _mat )
 {
+    CV_INSTRUMENT_REGION()
+
     Mat mat = _mat.getMat();
     double result = 0;
     int type = mat.type(), rows = mat.rows;
@@ -745,7 +788,6 @@ double cv::determinant( InputArray _mat )
             {
                 for( int i = 0; i < rows; i++ )
                     result *= a.at<float>(i,i);
-                result = 1./result;
             }
         }
     }
@@ -769,7 +811,6 @@ double cv::determinant( InputArray _mat )
             {
                 for( int i = 0; i < rows; i++ )
                     result *= a.at<double>(i,i);
-                result = 1./result;
             }
         }
     }
@@ -791,6 +832,8 @@ double cv::determinant( InputArray _mat )
 
 double cv::invert( InputArray _src, OutputArray _dst, int method )
 {
+    CV_INSTRUMENT_REGION()
+
     bool result = false;
     Mat src = _src.getMat();
     int type = src.type();
@@ -1049,6 +1092,8 @@ double cv::invert( InputArray _src, OutputArray _dst, int method )
 
 bool cv::solve( InputArray _src, InputArray _src2arg, OutputArray _dst, int method )
 {
+    CV_INSTRUMENT_REGION()
+
     bool result = true;
     Mat src = _src.getMat(), _src2 = _src2arg.getMat();
     int type = src.type();
@@ -1193,9 +1238,6 @@ bool cv::solve( InputArray _src, InputArray _src2arg, OutputArray _dst, int meth
         return result;
     }
 
-    if( method == DECOMP_QR )
-        method = DECOMP_SVD;
-
     int m = src.rows, m_ = m, n = src.cols, nb = _src2.cols;
     size_t esz = CV_ELEM_SIZE(type), bufsize = 0;
     size_t vstep = alignSize(n*esz, 16);
@@ -1223,7 +1265,6 @@ bool cv::solve( InputArray _src, InputArray _src2arg, OutputArray _dst, int meth
 
     if( is_normal )
         bufsize += n*nb*esz;
-
     if( method == DECOMP_SVD || method == DECOMP_EIG )
         bufsize += n*5*esz + n*vstep + nb*sizeof(double) + 32;
 
@@ -1276,6 +1317,28 @@ bool cv::solve( InputArray _src, InputArray _src2arg, OutputArray _dst, int meth
         else
             result = hal::Cholesky64f(a.ptr<double>(), a.step, n, dst.ptr<double>(), dst.step, nb);
     }
+    else if( method == DECOMP_QR )
+    {
+        Mat rhsMat;
+        if( is_normal || m == n )
+        {
+            src2.copyTo(dst);
+            rhsMat = dst;
+        }
+        else
+        {
+            rhsMat = Mat(m, nb, type);
+            src2.copyTo(rhsMat);
+        }
+
+        if( type == CV_32F )
+            result = hal::QR32f(a.ptr<float>(), a.step, a.rows, a.cols, rhsMat.cols, rhsMat.ptr<float>(), rhsMat.step, NULL) != 0;
+        else
+            result = hal::QR64f(a.ptr<double>(), a.step, a.rows, a.cols, rhsMat.cols, rhsMat.ptr<double>(), rhsMat.step, NULL) != 0;
+
+        if (rhsMat.rows != dst.rows)
+            rhsMat.rowRange(0, dst.rows).copyTo(dst);
+    }
     else
     {
         ptr = alignPtr(ptr, 16);
@@ -1325,6 +1388,8 @@ bool cv::solve( InputArray _src, InputArray _src2arg, OutputArray _dst, int meth
 
 bool cv::eigen( InputArray _src, OutputArray _evals, OutputArray _evects )
 {
+    CV_INSTRUMENT_REGION()
+
     Mat src = _src.getMat();
     int type = src.type();
     int n = src.rows;
@@ -1433,11 +1498,15 @@ static void _SVDcompute( InputArray _aarr, OutputArray _w,
 
 void SVD::compute( InputArray a, OutputArray w, OutputArray u, OutputArray vt, int flags )
 {
+    CV_INSTRUMENT_REGION()
+
     _SVDcompute(a, w, u, vt, flags);
 }
 
 void SVD::compute( InputArray a, OutputArray w, int flags )
 {
+    CV_INSTRUMENT_REGION()
+
     _SVDcompute(a, w, noArray(), noArray(), flags);
 }
 
@@ -1486,11 +1555,15 @@ void SVD::backSubst( InputArray rhs, OutputArray dst ) const
 
 void cv::SVDecomp(InputArray src, OutputArray w, OutputArray u, OutputArray vt, int flags)
 {
+    CV_INSTRUMENT_REGION()
+
     SVD::compute(src, w, u, vt, flags);
 }
 
 void cv::SVBackSubst(InputArray w, InputArray u, InputArray vt, InputArray rhs, OutputArray dst)
 {
+    CV_INSTRUMENT_REGION()
+
     SVD::backSubst(w, u, vt, rhs, dst);
 }
 
diff --git a/modules/core/src/lda.cpp b/modules/core/src/lda.cpp
index 76e8db2..4ccbf8a 100644
--- a/modules/core/src/lda.cpp
+++ b/modules/core/src/lda.cpp
@@ -898,6 +898,8 @@ public:
     // National Institute of Standards and Technology (NIST).
     void compute(InputArray src)
     {
+        CV_INSTRUMENT_REGION()
+
         if(isSymmetric(src)) {
             // Fall back to OpenCV for a symmetric matrix!
             cv::eigen(src, _eigenvalues, _eigenvectors);
@@ -960,7 +962,7 @@ void LDA::save(const String& filename) const
 void LDA::load(const String& filename) {
     FileStorage fs(filename, FileStorage::READ);
     if (!fs.isOpened())
-       CV_Error(Error::StsError, "File can't be opened for writing!");
+       CV_Error(Error::StsError, "File can't be opened for reading!");
     this->load(fs);
     fs.release();
 }
diff --git a/modules/core/src/mathfuncs.cpp b/modules/core/src/mathfuncs.cpp
index 495711f..b9bdf49 100644
--- a/modules/core/src/mathfuncs.cpp
+++ b/modules/core/src/mathfuncs.cpp
@@ -51,11 +51,6 @@ namespace cv
 
 typedef void (*MathFunc)(const void* src, void* dst, int len);
 
-static const float atan2_p1 = 0.9997878412794807f*(float)(180/CV_PI);
-static const float atan2_p3 = -0.3258083974640975f*(float)(180/CV_PI);
-static const float atan2_p5 = 0.1555786518463281f*(float)(180/CV_PI);
-static const float atan2_p7 = -0.04432655554792128f*(float)(180/CV_PI);
-
 #ifdef HAVE_OPENCL
 
 enum { OCL_OP_LOG=0, OCL_OP_EXP=1, OCL_OP_MAG=2, OCL_OP_PHASE_DEGREES=3, OCL_OP_PHASE_RADIANS=4 };
@@ -100,35 +95,14 @@ static bool ocl_math_op(InputArray _src1, InputArray _src2, OutputArray _dst, in
 
 #endif
 
-float fastAtan2( float y, float x )
-{
-    float ax = std::abs(x), ay = std::abs(y);
-    float a, c, c2;
-    if( ax >= ay )
-    {
-        c = ay/(ax + (float)DBL_EPSILON);
-        c2 = c*c;
-        a = (((atan2_p7*c2 + atan2_p5)*c2 + atan2_p3)*c2 + atan2_p1)*c;
-    }
-    else
-    {
-        c = ax/(ay + (float)DBL_EPSILON);
-        c2 = c*c;
-        a = 90.f - (((atan2_p7*c2 + atan2_p5)*c2 + atan2_p3)*c2 + atan2_p1)*c;
-    }
-    if( x < 0 )
-        a = 180.f - a;
-    if( y < 0 )
-        a = 360.f - a;
-    return a;
-}
-
 /* ************************************************************************** *\
    Fast cube root by Ken Turkowski
    (http://www.worldserver.com/turk/computergraphics/papers.html)
 \* ************************************************************************** */
 float  cubeRoot( float value )
 {
+    CV_INSTRUMENT_REGION()
+
     float fr;
     Cv32suf v, m;
     int ix, s;
@@ -170,6 +144,8 @@ float  cubeRoot( float value )
 
 void magnitude( InputArray src1, InputArray src2, OutputArray dst )
 {
+    CV_INSTRUMENT_REGION()
+
     int type = src1.type(), depth = src1.depth(), cn = src1.channels();
     CV_Assert( src1.size() == src2.size() && type == src2.type() && (depth == CV_32F || depth == CV_64F));
 
@@ -202,9 +178,10 @@ void magnitude( InputArray src1, InputArray src2, OutputArray dst )
     }
 }
 
-
 void phase( InputArray src1, InputArray src2, OutputArray dst, bool angleInDegrees )
 {
+    CV_INSTRUMENT_REGION()
+
     int type = src1.type(), depth = src1.depth(), cn = src1.channels();
     CV_Assert( src1.size() == src2.size() && type == src2.type() && (depth == CV_32F || depth == CV_64F));
 
@@ -218,19 +195,8 @@ void phase( InputArray src1, InputArray src2, OutputArray dst, bool angleInDegre
     const Mat* arrays[] = {&X, &Y, &Angle, 0};
     uchar* ptrs[3];
     NAryMatIterator it(arrays, ptrs);
-    cv::AutoBuffer<float> _buf;
-    float* buf[2] = {0, 0};
-    int j, k, total = (int)(it.size*cn), blockSize = total;
+    int j, total = (int)(it.size*cn), blockSize = total;
     size_t esz1 = X.elemSize1();
-
-    if( depth == CV_64F )
-    {
-        blockSize = std::min(blockSize, ((BLOCK_SIZE+cn-1)/cn)*cn);
-        _buf.allocate(blockSize*2);
-        buf[0] = _buf;
-        buf[1] = buf[0] + blockSize;
-    }
-
     for( size_t i = 0; i < it.nplanes; i++, ++it )
     {
         for( j = 0; j < total; j += blockSize )
@@ -240,53 +206,13 @@ void phase( InputArray src1, InputArray src2, OutputArray dst, bool angleInDegre
             {
                 const float *x = (const float*)ptrs[0], *y = (const float*)ptrs[1];
                 float *angle = (float*)ptrs[2];
-                hal::fastAtan2( y, x, angle, len, angleInDegrees );
+                hal::fastAtan32f( y, x, angle, len, angleInDegrees );
             }
             else
             {
                 const double *x = (const double*)ptrs[0], *y = (const double*)ptrs[1];
                 double *angle = (double*)ptrs[2];
-                k = 0;
-
-#if CV_SSE2
-                if (USE_SSE2)
-                {
-                    for ( ; k <= len - 4; k += 4)
-                    {
-                        __m128 v_dst0 = _mm_movelh_ps(_mm_cvtpd_ps(_mm_loadu_pd(x + k)),
-                                                      _mm_cvtpd_ps(_mm_loadu_pd(x + k + 2)));
-                        __m128 v_dst1 = _mm_movelh_ps(_mm_cvtpd_ps(_mm_loadu_pd(y + k)),
-                                                      _mm_cvtpd_ps(_mm_loadu_pd(y + k + 2)));
-
-                        _mm_storeu_ps(buf[0] + k, v_dst0);
-                        _mm_storeu_ps(buf[1] + k, v_dst1);
-                    }
-                }
-#endif
-
-                for( ; k < len; k++ )
-                {
-                    buf[0][k] = (float)x[k];
-                    buf[1][k] = (float)y[k];
-                }
-
-                hal::fastAtan2( buf[1], buf[0], buf[0], len, angleInDegrees );
-                k = 0;
-
-#if CV_SSE2
-                if (USE_SSE2)
-                {
-                    for ( ; k <= len - 4; k += 4)
-                    {
-                        __m128 v_src = _mm_loadu_ps(buf[0] + k);
-                        _mm_storeu_pd(angle + k, _mm_cvtps_pd(v_src));
-                        _mm_storeu_pd(angle + k + 2, _mm_cvtps_pd(_mm_castsi128_ps(_mm_srli_si128(_mm_castps_si128(v_src), 8))));
-                    }
-                }
-#endif
-
-                for( ; k < len; k++ )
-                    angle[k] = buf[0][k];
+                hal::fastAtan64f(y, x, angle, len, angleInDegrees);
             }
             ptrs[0] += len*esz1;
             ptrs[1] += len*esz1;
@@ -340,6 +266,8 @@ static bool ocl_cartToPolar( InputArray _src1, InputArray _src2,
 void cartToPolar( InputArray src1, InputArray src2,
                   OutputArray dst1, OutputArray dst2, bool angleInDegrees )
 {
+    CV_INSTRUMENT_REGION()
+
     CV_OCL_RUN(dst1.isUMat() && dst2.isUMat(),
             ocl_cartToPolar(src1, src2, dst1, dst2, angleInDegrees))
 
@@ -353,18 +281,9 @@ void cartToPolar( InputArray src1, InputArray src2,
     const Mat* arrays[] = {&X, &Y, &Mag, &Angle, 0};
     uchar* ptrs[4];
     NAryMatIterator it(arrays, ptrs);
-    cv::AutoBuffer<float> _buf;
-    float* buf[2] = {0, 0};
-    int j, k, total = (int)(it.size*cn), blockSize = std::min(total, ((BLOCK_SIZE+cn-1)/cn)*cn);
+    int j, total = (int)(it.size*cn), blockSize = std::min(total, ((BLOCK_SIZE+cn-1)/cn)*cn);
     size_t esz1 = X.elemSize1();
 
-    if( depth == CV_64F )
-    {
-        _buf.allocate(blockSize*2);
-        buf[0] = _buf;
-        buf[1] = buf[0] + blockSize;
-    }
-
     for( size_t i = 0; i < it.nplanes; i++, ++it )
     {
         for( j = 0; j < total; j += blockSize )
@@ -375,55 +294,14 @@ void cartToPolar( InputArray src1, InputArray src2,
                 const float *x = (const float*)ptrs[0], *y = (const float*)ptrs[1];
                 float *mag = (float*)ptrs[2], *angle = (float*)ptrs[3];
                 hal::magnitude32f( x, y, mag, len );
-                hal::fastAtan2( y, x, angle, len, angleInDegrees );
+                hal::fastAtan32f( y, x, angle, len, angleInDegrees );
             }
             else
             {
                 const double *x = (const double*)ptrs[0], *y = (const double*)ptrs[1];
                 double *angle = (double*)ptrs[3];
-
                 hal::magnitude64f(x, y, (double*)ptrs[2], len);
-                k = 0;
-
-#if CV_SSE2
-                if (USE_SSE2)
-                {
-                    for ( ; k <= len - 4; k += 4)
-                    {
-                        __m128 v_dst0 = _mm_movelh_ps(_mm_cvtpd_ps(_mm_loadu_pd(x + k)),
-                                                      _mm_cvtpd_ps(_mm_loadu_pd(x + k + 2)));
-                        __m128 v_dst1 = _mm_movelh_ps(_mm_cvtpd_ps(_mm_loadu_pd(y + k)),
-                                                      _mm_cvtpd_ps(_mm_loadu_pd(y + k + 2)));
-
-                        _mm_storeu_ps(buf[0] + k, v_dst0);
-                        _mm_storeu_ps(buf[1] + k, v_dst1);
-                    }
-                }
-#endif
-
-                for( ; k < len; k++ )
-                {
-                    buf[0][k] = (float)x[k];
-                    buf[1][k] = (float)y[k];
-                }
-
-                hal::fastAtan2( buf[1], buf[0], buf[0], len, angleInDegrees );
-                k = 0;
-
-#if CV_SSE2
-                if (USE_SSE2)
-                {
-                    for ( ; k <= len - 4; k += 4)
-                    {
-                        __m128 v_src = _mm_loadu_ps(buf[0] + k);
-                        _mm_storeu_pd(angle + k, _mm_cvtps_pd(v_src));
-                        _mm_storeu_pd(angle + k + 2, _mm_cvtps_pd(_mm_castsi128_ps(_mm_srli_si128(_mm_castps_si128(v_src), 8))));
-                    }
-                }
-#endif
-
-                for( ; k < len; k++ )
-                    angle[k] = buf[0][k];
+                hal::fastAtan64f(y, x, angle, len, angleInDegrees);
             }
             ptrs[0] += len*esz1;
             ptrs[1] += len*esz1;
@@ -622,6 +500,8 @@ static bool ocl_polarToCart( InputArray _mag, InputArray _angle,
 void polarToCart( InputArray src1, InputArray src2,
                   OutputArray dst1, OutputArray dst2, bool angleInDegrees )
 {
+    CV_INSTRUMENT_REGION()
+
     int type = src2.type(), depth = CV_MAT_DEPTH(type), cn = CV_MAT_CN(type);
     CV_Assert((depth == CV_32F || depth == CV_64F) && (src1.empty() || src1.type() == type));
 
@@ -639,14 +519,14 @@ void polarToCart( InputArray src1, InputArray src2,
     {
         if (Mag.isContinuous() && Angle.isContinuous() && X.isContinuous() && Y.isContinuous() && !angleInDegrees)
         {
-            typedef IppStatus (CV_STDCALL * ippsPolarToCart)(const void * pSrcMagn, const void * pSrcPhase,
+            typedef IppStatus (CV_STDCALL * IppsPolarToCart)(const void * pSrcMagn, const void * pSrcPhase,
                                                              void * pDstRe, void * pDstIm, int len);
-            ippsPolarToCart ippFunc =
-            depth == CV_32F ? (ippsPolarToCart)ippsPolarToCart_32f :
-            depth == CV_64F ? (ippsPolarToCart)ippsPolarToCart_64f : 0;
-            CV_Assert(ippFunc != 0);
+            IppsPolarToCart ippsPolarToCart =
+            depth == CV_32F ? (IppsPolarToCart)ippsPolarToCart_32f :
+            depth == CV_64F ? (IppsPolarToCart)ippsPolarToCart_64f : 0;
+            CV_Assert(ippsPolarToCart != 0);
 
-            IppStatus status = ippFunc(Mag.ptr(), Angle.ptr(), X.ptr(), Y.ptr(), static_cast<int>(cn * X.total()));
+            IppStatus status = CV_INSTRUMENT_FUN_IPP(ippsPolarToCart, Mag.ptr(), Angle.ptr(), X.ptr(), Y.ptr(), static_cast<int>(cn * X.total()));
             if (status >= 0)
             {
                 CV_IMPL_ADD(CV_IMPL_IPP);
@@ -748,45 +628,10 @@ void polarToCart( InputArray src1, InputArray src2,
 *                                          E X P                                         *
 \****************************************************************************************/
 
-#ifdef HAVE_IPP
-static void Exp_32f_ipp(const float *x, float *y, int n)
-{
-    CV_IPP_CHECK()
-    {
-        if (0 <= ippsExp_32f_A21(x, y, n))
-        {
-            CV_IMPL_ADD(CV_IMPL_IPP);
-            return;
-        }
-        setIppErrorStatus();
-    }
-    hal::exp32f(x, y, n);
-}
-
-static void Exp_64f_ipp(const double *x, double *y, int n)
-{
-    CV_IPP_CHECK()
-    {
-        if (0 <= ippsExp_64f_A50(x, y, n))
-        {
-            CV_IMPL_ADD(CV_IMPL_IPP);
-            return;
-        }
-        setIppErrorStatus();
-    }
-    hal::exp64f(x, y, n);
-}
-
-#define Exp_32f Exp_32f_ipp
-#define Exp_64f Exp_64f_ipp
-#else
-#define Exp_32f hal::exp32f
-#define Exp_64f hal::exp64f
-#endif
-
-
 void exp( InputArray _src, OutputArray _dst )
 {
+    CV_INSTRUMENT_REGION()
+
     int type = _src.type(), depth = _src.depth(), cn = _src.channels();
     CV_Assert( depth == CV_32F || depth == CV_64F );
 
@@ -805,9 +650,9 @@ void exp( InputArray _src, OutputArray _dst )
     for( size_t i = 0; i < it.nplanes; i++, ++it )
     {
         if( depth == CV_32F )
-            Exp_32f((const float*)ptrs[0], (float*)ptrs[1], len);
+            hal::exp32f((const float*)ptrs[0], (float*)ptrs[1], len);
         else
-            Exp_64f((const double*)ptrs[0], (double*)ptrs[1], len);
+            hal::exp64f((const double*)ptrs[0], (double*)ptrs[1], len);
     }
 }
 
@@ -816,44 +661,10 @@ void exp( InputArray _src, OutputArray _dst )
 *                                          L O G                                         *
 \****************************************************************************************/
 
-#ifdef HAVE_IPP
-static void Log_32f_ipp(const float *x, float *y, int n)
-{
-    CV_IPP_CHECK()
-    {
-        if (0 <= ippsLn_32f_A21(x, y, n))
-        {
-            CV_IMPL_ADD(CV_IMPL_IPP);
-            return;
-        }
-        setIppErrorStatus();
-    }
-    hal::log32f(x, y, n);
-}
-
-static void Log_64f_ipp(const double *x, double *y, int n)
-{
-    CV_IPP_CHECK()
-    {
-        if (0 <= ippsLn_64f_A50(x, y, n))
-        {
-            CV_IMPL_ADD(CV_IMPL_IPP);
-            return;
-        }
-        setIppErrorStatus();
-    }
-    hal::log64f(x, y, n);
-}
-
-#define Log_32f Log_32f_ipp
-#define Log_64f Log_64f_ipp
-#else
-#define Log_32f hal::log32f
-#define Log_64f hal::log64f
-#endif
-
 void log( InputArray _src, OutputArray _dst )
 {
+    CV_INSTRUMENT_REGION()
+
     int type = _src.type(), depth = _src.depth(), cn = _src.channels();
     CV_Assert( depth == CV_32F || depth == CV_64F );
 
@@ -872,9 +683,9 @@ void log( InputArray _src, OutputArray _dst )
     for( size_t i = 0; i < it.nplanes; i++, ++it )
     {
         if( depth == CV_32F )
-            Log_32f( (const float*)ptrs[0], (float*)ptrs[1], len );
+            hal::log32f( (const float*)ptrs[0], (float*)ptrs[1], len );
         else
-            Log_64f( (const double*)ptrs[0], (double*)ptrs[1], len );
+            hal::log64f( (const double*)ptrs[0], (double*)ptrs[1], len );
     }
 }
 
@@ -1363,6 +1174,8 @@ static void Sqrt_64f(const double* src, double* dst, int n) { hal::sqrt64f(src,
 
 void pow( InputArray _src, double power, OutputArray _dst )
 {
+    CV_INSTRUMENT_REGION()
+
     int type = _src.type(), depth = CV_MAT_DEPTH(type),
             cn = CV_MAT_CN(type), ipower = cvRound(power);
     bool is_ipower = fabs(ipower - power) < DBL_EPSILON;
@@ -1448,12 +1261,12 @@ void pow( InputArray _src, double power, OutputArray _dst )
             {
                 int bsz = std::min(len - j, blockSize);
 
-            #if defined(HAVE_IPP)
+#if defined(HAVE_IPP)
                 CV_IPP_CHECK()
                 {
                     IppStatus status = depth == CV_32F ?
-                    ippsPowx_32f_A21((const float*)ptrs[0], (float)power, (float*)ptrs[1], bsz) :
-                    ippsPowx_64f_A50((const double*)ptrs[0], (double)power, (double*)ptrs[1], bsz);
+                    CV_INSTRUMENT_FUN_IPP(ippsPowx_32f_A21, (const float*)ptrs[0], (float)power, (float*)ptrs[1], bsz) :
+                    CV_INSTRUMENT_FUN_IPP(ippsPowx_64f_A50, (const double*)ptrs[0], (double)power, (double*)ptrs[1], bsz);
 
                     if (status >= 0)
                     {
@@ -1464,7 +1277,7 @@ void pow( InputArray _src, double power, OutputArray _dst )
                     }
                     setIppErrorStatus();
                 }
-            #endif
+#endif
 
                 if( depth == CV_32F )
                 {
@@ -1475,10 +1288,10 @@ void pow( InputArray _src, double power, OutputArray _dst )
                     if( x != x0 )
                         memcpy(x, x0, bsz*esz1);
 
-                    Log_32f(x, y, bsz);
+                    hal::log32f(x, y, bsz);
                     for( k = 0; k < bsz; k++ )
                         y[k] = (float)(y[k]*power);
-                    Exp_32f(y, y, bsz);
+                    hal::exp32f(y, y, bsz);
                     for( k = 0; k < bsz; k++ )
                     {
                         if( x0[k] <= 0 )
@@ -1502,10 +1315,10 @@ void pow( InputArray _src, double power, OutputArray _dst )
                     if( x != x0 )
                         memcpy(x, x0, bsz*esz1);
 
-                    Log_64f(x, y, bsz);
+                    hal::log64f(x, y, bsz);
                     for( k = 0; k < bsz; k++ )
                         y[k] *= power;
-                    Exp_64f(y, y, bsz);
+                    hal::exp64f(y, y, bsz);
 
                     for( k = 0; k < bsz; k++ )
                     {
@@ -1530,6 +1343,8 @@ void pow( InputArray _src, double power, OutputArray _dst )
 
 void sqrt(InputArray a, OutputArray b)
 {
+    CV_INSTRUMENT_REGION()
+
     cv::pow(a, 0.5, b);
 }
 
@@ -1615,6 +1430,8 @@ check_range_function check_range_functions[] =
 
 bool checkRange(InputArray _src, bool quiet, Point* pt, double minVal, double maxVal)
 {
+    CV_INSTRUMENT_REGION()
+
     Mat src = _src.getMat();
 
     if ( src.dims > 2 )
@@ -1752,6 +1569,8 @@ static bool ocl_patchNaNs( InputOutputArray _a, float value )
 
 void patchNaNs( InputOutputArray _a, double _val )
 {
+    CV_INSTRUMENT_REGION()
+
     CV_Assert( _a.depth() == CV_32F );
 
     CV_OCL_RUN(_a.isUMat() && _a.dims() <= 2,
@@ -1917,6 +1736,8 @@ CV_IMPL int cvCheckArr( const CvArr* arr, int flags,
 
 int cv::solveCubic( InputArray _coeffs, OutputArray _roots )
 {
+    CV_INSTRUMENT_REGION()
+
     const int n0 = 3;
     Mat coeffs = _coeffs.getMat();
     int ctype = coeffs.type();
@@ -2062,6 +1883,8 @@ int cv::solveCubic( InputArray _coeffs, OutputArray _roots )
    http://en.wikipedia.org/wiki/Durand%E2%80%93Kerner_method */
 double cv::solvePoly( InputArray _coeffs0, OutputArray _roots0, int maxIters )
 {
+    CV_INSTRUMENT_REGION()
+
     typedef Complex<double> C;
 
     double maxDiff = 0;
diff --git a/modules/core/src/mathfuncs_core.cpp b/modules/core/src/mathfuncs_core.cpp
index 7b3ec31..e0cc5b5 100644
--- a/modules/core/src/mathfuncs_core.cpp
+++ b/modules/core/src/mathfuncs_core.cpp
@@ -42,129 +42,196 @@
 
 #include "precomp.hpp"
 
-#undef HAVE_IPP
+using namespace std;
 
-namespace cv { namespace hal {
+namespace {
 
-///////////////////////////////////// ATAN2 ////////////////////////////////////
 static const float atan2_p1 = 0.9997878412794807f*(float)(180/CV_PI);
 static const float atan2_p3 = -0.3258083974640975f*(float)(180/CV_PI);
 static const float atan2_p5 = 0.1555786518463281f*(float)(180/CV_PI);
 static const float atan2_p7 = -0.04432655554792128f*(float)(180/CV_PI);
 
-void fastAtan2(const float *Y, const float *X, float *angle, int len, bool angleInDegrees )
-{
-    int i = 0;
-    float scale = angleInDegrees ? 1 : (float)(CV_PI/180);
+using namespace cv;
 
-#ifdef HAVE_TEGRA_OPTIMIZATION
-    if (tegra::useTegra() && tegra::FastAtan2_32f(Y, X, angle, len, scale))
-        return;
-#endif
+#if CV_SIMD128
 
-#if CV_SSE2
-    Cv32suf iabsmask; iabsmask.i = 0x7fffffff;
-    __m128 eps = _mm_set1_ps((float)DBL_EPSILON), absmask = _mm_set1_ps(iabsmask.f);
-    __m128 _90 = _mm_set1_ps(90.f), _180 = _mm_set1_ps(180.f), _360 = _mm_set1_ps(360.f);
-    __m128 z = _mm_setzero_ps(), scale4 = _mm_set1_ps(scale);
-    __m128 p1 = _mm_set1_ps(atan2_p1), p3 = _mm_set1_ps(atan2_p3);
-    __m128 p5 = _mm_set1_ps(atan2_p5), p7 = _mm_set1_ps(atan2_p7);
+template <typename T>
+struct v_atan
+{
+    typedef V_RegTrait128<T> Trait;
+    typedef typename Trait::reg VT; // vector type
+    enum { WorkWidth = VT::nlanes * 2 };
 
-    for( ; i <= len - 4; i += 4 )
+    v_atan(const T & scale)
+        : s(Trait::all(scale))
     {
-        __m128 x = _mm_loadu_ps(X + i), y = _mm_loadu_ps(Y + i);
-        __m128 ax = _mm_and_ps(x, absmask), ay = _mm_and_ps(y, absmask);
-        __m128 mask = _mm_cmplt_ps(ax, ay);
-        __m128 tmin = _mm_min_ps(ax, ay), tmax = _mm_max_ps(ax, ay);
-        __m128 c = _mm_div_ps(tmin, _mm_add_ps(tmax, eps));
-        __m128 c2 = _mm_mul_ps(c, c);
-        __m128 a = _mm_mul_ps(c2, p7);
-        a = _mm_mul_ps(_mm_add_ps(a, p5), c2);
-        a = _mm_mul_ps(_mm_add_ps(a, p3), c2);
-        a = _mm_mul_ps(_mm_add_ps(a, p1), c);
-
-        __m128 b = _mm_sub_ps(_90, a);
-        a = _mm_xor_ps(a, _mm_and_ps(_mm_xor_ps(a, b), mask));
-
-        b = _mm_sub_ps(_180, a);
-        mask = _mm_cmplt_ps(x, z);
-        a = _mm_xor_ps(a, _mm_and_ps(_mm_xor_ps(a, b), mask));
-
-        b = _mm_sub_ps(_360, a);
-        mask = _mm_cmplt_ps(y, z);
-        a = _mm_xor_ps(a, _mm_and_ps(_mm_xor_ps(a, b), mask));
-
-        a = _mm_mul_ps(a, scale4);
-        _mm_storeu_ps(angle + i, a);
+        eps = Trait::all(DBL_EPSILON);
+        z = Trait::zero();
+        p7 = Trait::all(atan2_p7);
+        p5 = Trait::all(atan2_p5);
+        p3 = Trait::all(atan2_p3);
+        p1 = Trait::all(atan2_p1);
+        val90 = Trait::all(90.f);
+        val180 = Trait::all(180.f);
+        val360 = Trait::all(360.f);
     }
-#elif CV_NEON
-    float32x4_t eps = vdupq_n_f32((float)DBL_EPSILON);
-    float32x4_t _90 = vdupq_n_f32(90.f), _180 = vdupq_n_f32(180.f), _360 = vdupq_n_f32(360.f);
-    float32x4_t z = vdupq_n_f32(0.0f), scale4 = vdupq_n_f32(scale);
-    float32x4_t p1 = vdupq_n_f32(atan2_p1), p3 = vdupq_n_f32(atan2_p3);
-    float32x4_t p5 = vdupq_n_f32(atan2_p5), p7 = vdupq_n_f32(atan2_p7);
 
-    for( ; i <= len - 4; i += 4 )
+    inline int operator()(int len, const T * Y, const T * X, T * angle)
     {
-        float32x4_t x = vld1q_f32(X + i), y = vld1q_f32(Y + i);
-        float32x4_t ax = vabsq_f32(x), ay = vabsq_f32(y);
-        float32x4_t tmin = vminq_f32(ax, ay), tmax = vmaxq_f32(ax, ay);
-        float32x4_t c = vmulq_f32(tmin, cv_vrecpq_f32(vaddq_f32(tmax, eps)));
-        float32x4_t c2 = vmulq_f32(c, c);
-        float32x4_t a = vmulq_f32(c2, p7);
-        a = vmulq_f32(vaddq_f32(a, p5), c2);
-        a = vmulq_f32(vaddq_f32(a, p3), c2);
-        a = vmulq_f32(vaddq_f32(a, p1), c);
-
-        a = vbslq_f32(vcgeq_f32(ax, ay), a, vsubq_f32(_90, a));
-        a = vbslq_f32(vcltq_f32(x, z), vsubq_f32(_180, a), a);
-        a = vbslq_f32(vcltq_f32(y, z), vsubq_f32(_360, a), a);
-
-        vst1q_f32(angle + i, vmulq_f32(a, scale4));
+        int i = 0;
+        const int c = VT::nlanes;
+        for ( ; i <= len - c * 2; i += c * 2)
+        {
+            VT x1 = v_load(X + i);
+            VT x2 = v_load(X + i + c);
+            VT y1 = v_load(Y + i);
+            VT y2 = v_load(Y + i + c);
+            v_store(&angle[i], s * one(x1, y1));
+            v_store(&angle[i + c], s * one(x2, y2));
+        }
+        return i;
     }
-#endif
 
-    for( ; i < len; i++ )
+private:
+    inline VT one(VT & x, VT & y)
     {
-        float x = X[i], y = Y[i];
-        float ax = std::abs(x), ay = std::abs(y);
-        float a, c, c2;
-        if( ax >= ay )
-        {
-            c = ay/(ax + (float)DBL_EPSILON);
-            c2 = c*c;
-            a = (((atan2_p7*c2 + atan2_p5)*c2 + atan2_p3)*c2 + atan2_p1)*c;
-        }
-        else
-        {
-            c = ax/(ay + (float)DBL_EPSILON);
-            c2 = c*c;
-            a = 90.f - (((atan2_p7*c2 + atan2_p5)*c2 + atan2_p3)*c2 + atan2_p1)*c;
-        }
-        if( x < 0 )
-            a = 180.f - a;
-        if( y < 0 )
-            a = 360.f - a;
-        angle[i] = (float)(a*scale);
+        VT ax = v_abs(x);
+        VT ay = v_abs(y);
+        VT c = v_min(ax, ay) / (v_max(ax, ay) + eps);
+        VT cc = c * c;
+        VT a = (((p7 * cc + p5) * cc + p3) * cc + p1) * c;
+        a = v_select(ax >= ay, a, val90 - a);
+        a = v_select(x < z, val180 - a, a);
+        a = v_select(y < z, val360 - a, a);
+        return a;
     }
-}
 
+private:
+    VT eps;
+    VT z;
+    VT p7;
+    VT p5;
+    VT p3;
+    VT p1;
+    VT val90;
+    VT val180;
+    VT val360;
+    VT s;
+};
 
-void magnitude32f(const float* x, const float* y, float* mag, int len)
+#if !CV_SIMD128_64F
+
+// emulation
+template <>
+struct v_atan<double>
 {
-#if defined HAVE_IPP
-    CV_IPP_CHECK()
+    v_atan(double scale) : impl(static_cast<float>(scale)) {}
+    inline int operator()(int len, const double * Y, const double * X, double * angle)
     {
-        IppStatus status = ippsMagnitude_32f(x, y, mag, len);
-        if (status >= 0)
+        int i = 0;
+        const int c = v_atan<float>::WorkWidth;
+        float bufY[c];
+        float bufX[c];
+        float bufA[c];
+        for ( ; i <= len - c ; i += c)
         {
-            CV_IMPL_ADD(CV_IMPL_IPP);
-            return;
+            for (int j = 0; j < c; ++j)
+            {
+                bufY[j] = static_cast<float>(Y[i + j]);
+                bufX[j] = static_cast<float>(X[i + j]);
+            }
+            impl(c, bufY, bufX, bufA);
+            for (int j = 0; j < c; ++j)
+            {
+                angle[i + j] = bufA[j];
+            }
         }
-        setIppErrorStatus();
+        return i;
     }
+private:
+    v_atan<float> impl;
+};
+#endif
+
 #endif
 
+template <typename T>
+static inline T atanImpl(T y, T x)
+{
+    T ax = std::abs(x), ay = std::abs(y);
+    T a, c, c2;
+    if( ax >= ay )
+    {
+        c = ay/(ax + static_cast<T>(DBL_EPSILON));
+        c2 = c*c;
+        a = (((atan2_p7*c2 + atan2_p5)*c2 + atan2_p3)*c2 + atan2_p1)*c;
+    }
+    else
+    {
+        c = ax/(ay + static_cast<T>(DBL_EPSILON));
+        c2 = c*c;
+        a = 90.f - (((atan2_p7*c2 + atan2_p5)*c2 + atan2_p3)*c2 + atan2_p1)*c;
+    }
+    if( x < 0 )
+        a = 180.f - a;
+    if( y < 0 )
+        a = 360.f - a;
+    return a;
+}
+
+template <typename T>
+static inline void atanImpl(const T *Y, const T *X, T *angle, int len, bool angleInDegrees)
+{
+    int i = 0;
+    T scale = angleInDegrees ? 1 : static_cast<T>(CV_PI/180);
+
+#if CV_SIMD128
+    i = v_atan<T>(scale)(len, Y, X, angle);
+#endif
+
+    for( ; i < len; i++ )
+    {
+        angle[i] = atanImpl<T>(Y[i], X[i]) * scale;
+    }
+}
+
+} // anonymous::
+
+namespace cv { namespace hal {
+
+///////////////////////////////////// ATAN2 ////////////////////////////////////
+
+void fastAtan32f(const float *Y, const float *X, float *angle, int len, bool angleInDegrees )
+{
+    CV_INSTRUMENT_REGION()
+
+    CALL_HAL(fastAtan32f, cv_hal_fastAtan32f, Y, X, angle, len, angleInDegrees);
+    atanImpl<float>(Y, X, angle, len, angleInDegrees);
+}
+
+void fastAtan64f(const double *Y, const double *X, double *angle, int len, bool angleInDegrees)
+{
+    CV_INSTRUMENT_REGION()
+
+    CALL_HAL(fastAtan64f, cv_hal_fastAtan64f, Y, X, angle, len, angleInDegrees);
+    atanImpl<double>(Y, X, angle, len, angleInDegrees);
+}
+
+// deprecated
+void fastAtan2(const float *Y, const float *X, float *angle, int len, bool angleInDegrees )
+{
+    CV_INSTRUMENT_REGION()
+
+    fastAtan32f(Y, X, angle, len, angleInDegrees);
+}
+
+void magnitude32f(const float* x, const float* y, float* mag, int len)
+{
+    CV_INSTRUMENT_REGION()
+
+    CALL_HAL(magnitude32f, cv_hal_magnitude32f, x, y, mag, len);
+    CV_IPP_RUN_FAST(CV_INSTRUMENT_FUN_IPP(ippsMagnitude_32f, x, y, mag, len) >= 0);
+
     int i = 0;
 
 #if CV_SIMD128
@@ -188,18 +255,10 @@ void magnitude32f(const float* x, const float* y, float* mag, int len)
 
 void magnitude64f(const double* x, const double* y, double* mag, int len)
 {
-#if defined(HAVE_IPP)
-    CV_IPP_CHECK()
-    {
-        IppStatus status = ippsMagnitude_64f(x, y, mag, len);
-        if (status >= 0)
-        {
-            CV_IMPL_ADD(CV_IMPL_IPP);
-            return;
-        }
-        setIppErrorStatus();
-    }
-#endif
+    CV_INSTRUMENT_REGION()
+
+    CALL_HAL(magnitude64f, cv_hal_magnitude64f, x, y, mag, len);
+    CV_IPP_RUN_FAST(CV_INSTRUMENT_FUN_IPP(ippsMagnitude_64f, x, y, mag, len) >= 0);
 
     int i = 0;
 
@@ -225,17 +284,10 @@ void magnitude64f(const double* x, const double* y, double* mag, int len)
 
 void invSqrt32f(const float* src, float* dst, int len)
 {
-#if defined(HAVE_IPP)
-    CV_IPP_CHECK()
-    {
-        if (ippsInvSqrt_32f_A21(src, dst, len) >= 0)
-        {
-            CV_IMPL_ADD(CV_IMPL_IPP);
-            return;
-        }
-        setIppErrorStatus();
-    }
-#endif
+    CV_INSTRUMENT_REGION()
+
+    CALL_HAL(invSqrt32f, cv_hal_invSqrt32f, src, dst, len);
+    CV_IPP_RUN_FAST(CV_INSTRUMENT_FUN_IPP(ippsInvSqrt_32f_A21, src, dst, len) >= 0);
 
     int i = 0;
 
@@ -256,6 +308,11 @@ void invSqrt32f(const float* src, float* dst, int len)
 
 void invSqrt64f(const double* src, double* dst, int len)
 {
+    CV_INSTRUMENT_REGION()
+
+    CALL_HAL(invSqrt64f, cv_hal_invSqrt64f, src, dst, len);
+    CV_IPP_RUN_FAST(CV_INSTRUMENT_FUN_IPP(ippsInvSqrt_64f_A50, src, dst, len) >= 0);
+
     int i = 0;
 
 #if CV_SSE2
@@ -271,17 +328,10 @@ void invSqrt64f(const double* src, double* dst, int len)
 
 void sqrt32f(const float* src, float* dst, int len)
 {
-#if defined(HAVE_IPP)
-    CV_IPP_CHECK()
-    {
-        if (ippsSqrt_32f_A21(src, dst, len) >= 0)
-        {
-            CV_IMPL_ADD(CV_IMPL_IPP);
-            return;
-        }
-        setIppErrorStatus();
-    }
-#endif
+    CV_INSTRUMENT_REGION()
+
+    CALL_HAL(sqrt32f, cv_hal_sqrt32f, src, dst, len);
+    CV_IPP_RUN_FAST(CV_INSTRUMENT_FUN_IPP(ippsSqrt_32f_A21, src, dst, len) >= 0);
 
     int i = 0;
 
@@ -302,17 +352,10 @@ void sqrt32f(const float* src, float* dst, int len)
 
 void sqrt64f(const double* src, double* dst, int len)
 {
-#if defined(HAVE_IPP)
-    CV_IPP_CHECK()
-    {
-        if (ippsSqrt_64f_A50(src, dst, len) >= 0)
-        {
-            CV_IMPL_ADD(CV_IMPL_IPP);
-            return;
-        }
-        setIppErrorStatus();
-    }
-#endif
+    CV_INSTRUMENT_REGION()
+
+    CALL_HAL(sqrt64f, cv_hal_sqrt64f, src, dst, len);
+    CV_IPP_RUN_FAST(CV_INSTRUMENT_FUN_IPP(ippsSqrt_64f_A50, src, dst, len) >= 0);
 
     int i = 0;
 
@@ -330,6 +373,62 @@ void sqrt64f(const double* src, double* dst, int len)
         dst[i] = std::sqrt(src[i]);
 }
 
+// Workaround for ICE in MSVS 2015 update 3 (issue #7795)
+// CV_AVX is not used here, because generated code is faster in non-AVX mode.
+// (tested with disabled IPP on i5-6300U)
+#if (defined _MSC_VER && _MSC_VER >= 1900)
+void exp32f(const float *src, float *dst, int n)
+{
+    CV_INSTRUMENT_REGION()
+
+    CALL_HAL(exp32f, cv_hal_exp32f, src, dst, n);
+    CV_IPP_RUN_FAST(CV_INSTRUMENT_FUN_IPP(ippsExp_32f_A21, src, dst, n) >= 0);
+
+    for (int i = 0; i < n; i++)
+    {
+        dst[i] = std::exp(src[i]);
+    }
+}
+
+void exp64f(const double *src, double *dst, int n)
+{
+    CV_INSTRUMENT_REGION()
+
+    CALL_HAL(exp64f, cv_hal_exp64f, src, dst, n);
+    CV_IPP_RUN_FAST(CV_INSTRUMENT_FUN_IPP(ippsExp_64f_A50, src, dst, n) >= 0);
+
+    for (int i = 0; i < n; i++)
+    {
+        dst[i] = std::exp(src[i]);
+    }
+}
+
+void log32f(const float *src, float *dst, int n)
+{
+    CV_INSTRUMENT_REGION()
+
+    CALL_HAL(log32f, cv_hal_log32f, src, dst, n);
+    CV_IPP_RUN_FAST(CV_INSTRUMENT_FUN_IPP(ippsLn_32f_A21, src, dst, n) >= 0);
+
+    for (int i = 0; i < n; i++)
+    {
+        dst[i] = std::log(src[i]);
+    }
+}
+void log64f(const double *src, double *dst, int n)
+{
+    CV_INSTRUMENT_REGION()
+
+    CALL_HAL(log64f, cv_hal_log64f, src, dst, n);
+    CV_IPP_RUN_FAST(CV_INSTRUMENT_FUN_IPP(ippsLn_64f_A50, src, dst, n) >= 0);
+
+    for (int i = 0; i < n; i++)
+    {
+        dst[i] = std::log(src[i]);
+    }
+}
+#else
+
 ////////////////////////////////////// EXP /////////////////////////////////////
 
 typedef union
@@ -433,6 +532,11 @@ static const double exp_max_val = 3000.*(1 << EXPTAB_SCALE); // log10(DBL_MAX) <
 
 void exp32f( const float *_x, float *y, int n )
 {
+    CV_INSTRUMENT_REGION()
+
+    CALL_HAL(exp32f, cv_hal_exp32f, _x, y, n);
+    CV_IPP_RUN_FAST(CV_INSTRUMENT_FUN_IPP(ippsExp_32f_A21, _x, y, n) >= 0);
+
     static const float
     A4 = (float)(1.000000000000002438532970795181890933776 / EXPPOLY_32F_A0),
     A3 = (float)(.6931471805521448196800669615864773144641 / EXPPOLY_32F_A0),
@@ -632,6 +736,11 @@ void exp32f( const float *_x, float *y, int n )
 
 void exp64f( const double *_x, double *y, int n )
 {
+    CV_INSTRUMENT_REGION()
+
+    CALL_HAL(exp64f, cv_hal_exp64f, _x, y, n);
+    CV_IPP_RUN_FAST(CV_INSTRUMENT_FUN_IPP(ippsExp_64f_A50, _x, y, n) >= 0);
+
     static const double
     A5 = .99999999999999999998285227504999 / EXPPOLY_32F_A0,
     A4 = .69314718055994546743029643825322 / EXPPOLY_32F_A0,
@@ -1076,6 +1185,11 @@ static const double ln_2 = 0.69314718055994530941723212145818;
 
 void log32f( const float *_x, float *y, int n )
 {
+    CV_INSTRUMENT_REGION()
+
+    CALL_HAL(log32f, cv_hal_log32f, _x, y, n);
+    CV_IPP_RUN_FAST(CV_INSTRUMENT_FUN_IPP(ippsLn_32f_A21, _x, y, n) >= 0);
+
     static const float shift[] = { 0, -1.f/512 };
     static const float
     A0 = 0.3333333333333333333333333f,
@@ -1220,6 +1334,11 @@ void log32f( const float *_x, float *y, int n )
 
 void log64f( const double *x, double *y, int n )
 {
+    CV_INSTRUMENT_REGION()
+
+    CALL_HAL(log64f, cv_hal_log64f, x, y, n);
+    CV_IPP_RUN_FAST(CV_INSTRUMENT_FUN_IPP(ippsLn_64f_A50, x, y, n) >= 0);
+
     static const double shift[] = { 0, -1./512 };
     static const double
     A7 = 1.0,
@@ -1403,6 +1522,8 @@ void log64f( const double *x, double *y, int n )
     }
 }
 
+#endif // issue 7795
+
 //=============================================================================
 // for compatibility with 3.0
 
@@ -1457,4 +1578,10 @@ void invSqrt(const double* src, double* dst, int len)
 }
 
 
-}} // cv::hal::
+} // cv::hal::
+} // cv::
+
+float cv::fastAtan2( float y, float x )
+{
+    return atanImpl<float>(y, x);
+}
diff --git a/modules/core/src/matmul.cpp b/modules/core/src/matmul.cpp
index bf58dd0..477d4ab 100644
--- a/modules/core/src/matmul.cpp
+++ b/modules/core/src/matmul.cpp
@@ -864,21 +864,11 @@ static bool ocl_gemm( InputArray matA, InputArray matB, double alpha,
     return k.run(2, globalsize, block_size!=1 ? localsize : NULL, false);
 }
 #endif
-}
 
-void cv::gemm( InputArray matA, InputArray matB, double alpha,
-           InputArray matC, double beta, OutputArray _matD, int flags )
+static void gemmImpl( Mat A, Mat B, double alpha,
+           Mat C, double beta, Mat D, int flags )
 {
-#ifdef HAVE_CLAMDBLAS
-    CV_OCL_RUN(ocl::haveAmdBlas() && matA.dims() <= 2 && matB.dims() <= 2 && matC.dims() <= 2 && _matD.isUMat() &&
-        matA.cols() > 20 && matA.rows() > 20 && matB.cols() > 20, // since it works incorrect for small sizes
-        ocl_gemm_amdblas(matA, matB, alpha, matC, beta, _matD, flags))
-#endif
-
-#ifdef HAVE_OPENCL
-    CV_OCL_RUN(_matD.isUMat() && matA.dims() <= 2 && matB.dims() <= 2 && matC.dims() <= 2,
-               ocl_gemm(matA, matB, alpha, matC, beta, _matD, flags))
-#endif
+    CV_INSTRUMENT_REGION()
 
     const int block_lin_size = 128;
     const int block_size = block_lin_size * block_lin_size;
@@ -886,51 +876,29 @@ void cv::gemm( InputArray matA, InputArray matB, double alpha,
     static double zero[] = {0,0,0,0};
     static float zerof[] = {0,0,0,0};
 
-    Mat A = matA.getMat(), B = matB.getMat(), C = beta != 0 ? matC.getMat() : Mat();
     Size a_size = A.size(), d_size;
     int i, len = 0, type = A.type();
 
-    CV_Assert( type == B.type() && (type == CV_32FC1 || type == CV_64FC1 || type == CV_32FC2 || type == CV_64FC2) );
-
     switch( flags & (GEMM_1_T|GEMM_2_T) )
     {
     case 0:
         d_size = Size( B.cols, a_size.height );
         len = B.rows;
-        CV_Assert( a_size.width == len );
         break;
     case 1:
         d_size = Size( B.cols, a_size.width );
         len = B.rows;
-        CV_Assert( a_size.height == len );
         break;
     case 2:
         d_size = Size( B.rows, a_size.height );
         len = B.cols;
-        CV_Assert( a_size.width == len );
         break;
     case 3:
         d_size = Size( B.rows, a_size.width );
         len = B.cols;
-        CV_Assert( a_size.height == len );
         break;
     }
 
-    if( !C.empty() )
-    {
-        CV_Assert( C.type() == type &&
-            (((flags&GEMM_3_T) == 0 && C.rows == d_size.height && C.cols == d_size.width) ||
-             ((flags&GEMM_3_T) != 0 && C.rows == d_size.width && C.cols == d_size.height)));
-    }
-
-    _matD.create( d_size.height, d_size.width, type );
-    Mat D = _matD.getMat();
-    if( (flags & GEMM_3_T) != 0 && C.data == D.data )
-    {
-        transpose( C, C );
-        flags &= ~GEMM_3_T;
-    }
-
     if( flags == 0 && 2 <= len && len <= 4 && (len == d_size.width || len == d_size.height) )
     {
         if( type == CV_32F )
@@ -1194,8 +1162,7 @@ void cv::gemm( InputArray matA, InputArray matB, double alpha,
     GEMMSingleMulFunc singleMulFunc;
     GEMMBlockMulFunc blockMulFunc;
     GEMMStoreFunc storeFunc;
-    Mat *matD = &D, tmat;
-    size_t tmat_size = 0;
+    Mat *matD = &D;
     const uchar* Cdata = C.data;
     size_t Cstep = C.data ? (size_t)C.step : 0;
     AutoBuffer<uchar> buf;
@@ -1226,13 +1193,6 @@ void cv::gemm( InputArray matA, InputArray matB, double alpha,
         storeFunc = (GEMMStoreFunc)GEMMStore_64fc;
     }
 
-    if( D.data == A.data || D.data == B.data )
-    {
-        tmat_size = (size_t)d_size.width*d_size.height*CV_ELEM_SIZE(type);
-        // Allocate tmat later, once the size of buf is known
-        matD = &tmat;
-    }
-
     if( (d_size.width == 1 || len == 1) && !(flags & GEMM_2_T) && B.isContinuous() )
     {
         b_step = d_size.width == 1 ? 0 : CV_ELEM_SIZE(type);
@@ -1306,10 +1266,6 @@ void cv::gemm( InputArray matA, InputArray matB, double alpha,
         (d_size.width <= block_lin_size &&
         d_size.height <= block_lin_size && len <= block_lin_size) )
     {
-        if( tmat_size > 0 ) {
-            buf.allocate(tmat_size);
-            tmat = Mat(d_size.height, d_size.width, type, (uchar*)buf );
-        }
         singleMulFunc( A.ptr(), A.step, B.ptr(), b_step, Cdata, Cstep,
                        matD->ptr(), matD->step, a_size, d_size, alpha, beta, flags );
     }
@@ -1369,14 +1325,12 @@ void cv::gemm( InputArray matA, InputArray matB, double alpha,
             flags &= ~GEMM_1_T;
         }
 
-        buf.allocate(d_buf_size + b_buf_size + a_buf_size + tmat_size);
+        buf.allocate(d_buf_size + b_buf_size + a_buf_size);
         d_buf = (uchar*)buf;
         b_buf = d_buf + d_buf_size;
 
         if( is_a_t )
             a_buf = b_buf + b_buf_size;
-        if( tmat_size > 0 )
-            tmat = Mat(d_size.height, d_size.width, type, b_buf + b_buf_size + a_buf_size );
 
         for( i = 0; i < d_size.height; i += di )
         {
@@ -1455,10 +1409,198 @@ void cv::gemm( InputArray matA, InputArray matB, double alpha,
             }
         }
     }
+    }
+}
+
+template <typename fptype>inline static void
+callGemmImpl(const fptype *src1, size_t src1_step, const fptype *src2, size_t src2_step, fptype alpha,
+          const fptype *src3, size_t src3_step, fptype beta, fptype *dst, size_t dst_step, int m_a, int n_a, int n_d, int flags, int type)
+{
+    CV_StaticAssert(GEMM_1_T == CV_HAL_GEMM_1_T, "Incompatible GEMM_1_T flag in HAL");
+    CV_StaticAssert(GEMM_2_T == CV_HAL_GEMM_2_T, "Incompatible GEMM_2_T flag in HAL");
+    CV_StaticAssert(GEMM_3_T == CV_HAL_GEMM_3_T, "Incompatible GEMM_3_T flag in HAL");
+
+    int b_m, b_n, c_m, c_n, m_d;
+
+    if(flags & GEMM_2_T)
+    {
+        b_m = n_d;
+        if(flags & GEMM_1_T )
+        {
+            b_n = m_a;
+            m_d = n_a;
+        }
+        else
+        {
+            b_n = n_a;
+            m_d = m_a;
+        }
+    }
+    else
+    {
+        b_n = n_d;
+        if(flags & GEMM_1_T )
+        {
+            b_m = m_a;
+            m_d = n_a;
+        }
+        else
+        {
+            m_d = m_a;
+            b_m = n_a;
+        }
+    }
+
+    if(flags & GEMM_3_T)
+    {
+        c_m = n_d;
+        c_n = m_d;
+    }
+    else
+    {
+        c_m = m_d;
+        c_n = n_d;
+    }
+
+    Mat A, B, C;
+    if(src1 != NULL)
+        A = Mat(m_a, n_a, type, (void*)src1, src1_step);
+    if(src2 != NULL)
+        B = Mat(b_m, b_n, type, (void*)src2, src2_step);
+    if(src3 != NULL && beta != 0.0)
+        C = Mat(c_m, c_n, type, (void*)src3, src3_step);
+    Mat D(m_d, n_d, type, (void*)dst, dst_step);
+
+    gemmImpl(A, B, alpha, C, beta, D, flags);
+}
+
+}
+
+void cv::hal::gemm32f(const float* src1, size_t src1_step, const float* src2, size_t src2_step,
+                        float alpha, const float* src3, size_t src3_step, float beta, float* dst, size_t dst_step,
+                        int m_a, int n_a, int n_d, int flags)
+{
+
+    CALL_HAL(gemm32f, cv_hal_gemm32f, src1, src1_step, src2, src2_step, alpha, src3, src3_step, beta, dst, dst_step, m_a, n_a, n_d, flags)
+    callGemmImpl(src1, src1_step, src2, src2_step, alpha, src3, src3_step, beta, dst, dst_step, m_a, n_a, n_d, flags, CV_32F);
+}
+
+void cv::hal::gemm64f(const double* src1, size_t src1_step, const double* src2, size_t src2_step,
+                        double alpha, const double* src3, size_t src3_step, double beta, double* dst, size_t dst_step,
+                        int m_a, int n_a, int n_d, int flags)
+{
+    CALL_HAL(gemm64f, cv_hal_gemm64f, src1, src1_step, src2, src2_step, alpha, src3, src3_step, beta, dst, dst_step, m_a, n_a, n_d, flags)
+    callGemmImpl(src1, src1_step, src2, src2_step, alpha, src3, src3_step, beta, dst, dst_step, m_a, n_a, n_d, flags, CV_64F);
+}
+
+CV_EXPORTS void cv::hal::gemm32fc(const float* src1, size_t src1_step, const float* src2, size_t src2_step,
+                        float alpha, const float* src3, size_t src3_step, float beta, float* dst, size_t dst_step,
+                        int m_a, int n_a, int n_d, int flags)
+{
+    CALL_HAL(gemm32fc, cv_hal_gemm32fc, src1, src1_step, src2, src2_step, alpha, src3, src3_step, beta, dst, dst_step, m_a, n_a, n_d, flags)
+    callGemmImpl(src1, src1_step, src2, src2_step, alpha, src3, src3_step, beta, dst, dst_step, m_a, n_a, n_d, flags, CV_32FC2);
+}
+
+CV_EXPORTS void cv::hal::gemm64fc(const double* src1, size_t src1_step, const double* src2, size_t src2_step,
+                        double alpha, const double* src3, size_t src3_step, double beta, double* dst, size_t dst_step,
+                        int m_a, int n_a, int n_d, int flags)
+{
+    CALL_HAL(gemm64fc, cv_hal_gemm64fc, src1, src1_step, src2, src2_step, alpha, src3, src3_step, beta, dst, dst_step, m_a, n_a, n_d, flags)
+    callGemmImpl(src1, src1_step, src2, src2_step, alpha, src3, src3_step, beta, dst, dst_step, m_a, n_a, n_d, flags, CV_64FC2);
+}
+
+void cv::gemm( InputArray matA, InputArray matB, double alpha,
+           InputArray matC, double beta, OutputArray _matD, int flags )
+{
+#ifdef HAVE_CLAMDBLAS
+    CV_OCL_RUN(ocl::haveAmdBlas() && matA.dims() <= 2 && matB.dims() <= 2 && matC.dims() <= 2 && _matD.isUMat() &&
+        matA.cols() > 20 && matA.rows() > 20 && matB.cols() > 20, // since it works incorrect for small sizes
+        ocl_gemm_amdblas(matA, matB, alpha, matC, beta, _matD, flags))
+#endif
+
+#ifdef HAVE_OPENCL
+    CV_OCL_RUN(_matD.isUMat() && matA.dims() <= 2 && matB.dims() <= 2 && matC.dims() <= 2,
+               ocl_gemm(matA, matB, alpha, matC, beta, _matD, flags))
+#endif
+
+    Mat A = matA.getMat(), B = matB.getMat(), C = beta != 0.0 ? matC.getMat() : Mat();
+    Size a_size = A.size(), d_size;
+    int len = 0, type = A.type();
+
+    CV_Assert( type == B.type() && (type == CV_32FC1 || type == CV_64FC1 || type == CV_32FC2 || type == CV_64FC2) );
+
+    switch( flags & (GEMM_1_T|GEMM_2_T) )
+    {
+    case 0:
+        d_size = Size( B.cols, a_size.height );
+        len = B.rows;
+        CV_Assert( a_size.width == len );
+        break;
+    case 1:
+        d_size = Size( B.cols, a_size.width );
+        len = B.rows;
+        CV_Assert( a_size.height == len );
+        break;
+    case 2:
+        d_size = Size( B.rows, a_size.height );
+        len = B.cols;
+        CV_Assert( a_size.width == len );
+        break;
+    case 3:
+        d_size = Size( B.rows, a_size.width );
+        len = B.cols;
+        CV_Assert( a_size.height == len );
+        break;
+    }
+
+    if( !C.empty() )
+    {
+        CV_Assert( C.type() == type &&
+            (((flags&GEMM_3_T) == 0 && C.rows == d_size.height && C.cols == d_size.width) ||
+             ((flags&GEMM_3_T) != 0 && C.rows == d_size.width && C.cols == d_size.height)));
+    }
+
+    _matD.create( d_size.height, d_size.width, type );
+    Mat D = _matD.getMat();
+    if( (flags & GEMM_3_T) != 0 && C.data == D.data )
+    {
+        transpose( C, C );
+        flags &= ~GEMM_3_T;
+    }
+
+    Mat *DProxyPtr = &D, DProxy;
+    if( D.data == A.data || D.data == B.data )
+    {
+        DProxy = Mat(d_size.height, d_size.width, D.type());
+        DProxyPtr = &DProxy;
+    }
 
-    if( matD != &D )
-        matD->copyTo(D);
+    if( type == CV_32FC1 )
+        hal::gemm32f(A.ptr<float>(), A.step, B.ptr<float>(), B.step, static_cast<float>(alpha),
+                     C.ptr<float>(), C.step, static_cast<float>(beta),
+                     DProxyPtr->ptr<float>(), DProxyPtr->step,
+                     a_size.height, a_size.width, DProxyPtr->cols, flags);
+    else if( type == CV_64FC1 )
+        hal::gemm64f(A.ptr<double>(), A.step, B.ptr<double>(), B.step, alpha,
+                     C.ptr<double>(), C.step, beta,
+                     DProxyPtr->ptr<double>(), DProxyPtr->step,
+                     a_size.height, a_size.width, DProxyPtr->cols, flags);
+    else if( type == CV_32FC2 )
+        hal::gemm32fc(A.ptr<float>(), A.step, B.ptr<float>(), B.step, static_cast<float>(alpha),
+                      C.ptr<float>(), C.step, static_cast<float>(beta),
+                      DProxyPtr->ptr<float>(), DProxyPtr->step,
+                      a_size.height, a_size.width, DProxyPtr->cols, flags);
+    else
+    {
+        CV_Assert( type == CV_64FC2 );
+        hal::gemm64fc(A.ptr<double>(), A.step, B.ptr<double>(), B.step, alpha,
+                      C.ptr<double>(), C.step, beta,
+                      D.ptr<double>(), D.step,
+                      a_size.height, a_size.width, DProxyPtr->cols, flags);
     }
+
+    if(DProxyPtr != &D)
+        DProxyPtr->copyTo(D);
 }
 
 /****************************************************************************************\
@@ -1942,6 +2084,8 @@ static TransformFunc getDiagTransformFunc(int depth)
 
 void cv::transform( InputArray _src, OutputArray _dst, InputArray _mtx )
 {
+    CV_INSTRUMENT_REGION()
+
     Mat src = _src.getMat(), m = _mtx.getMat();
     int depth = src.depth(), scn = src.channels(), dcn = m.rows;
     CV_Assert( scn == m.cols || scn + 1 == m.cols );
@@ -2120,6 +2264,8 @@ perspectiveTransform_64f(const double* src, double* dst, const double* m, int le
 
 void cv::perspectiveTransform( InputArray _src, OutputArray _dst, InputArray _mtx )
 {
+    CV_INSTRUMENT_REGION()
+
     Mat src = _src.getMat(), m = _mtx.getMat();
     int depth = src.depth(), scn = src.channels(), dcn = m.rows-1;
     CV_Assert( scn + 1 == m.cols );
@@ -2314,6 +2460,8 @@ static bool ocl_scaleAdd( InputArray _src1, double alpha, InputArray _src2, Outp
 
 void cv::scaleAdd( InputArray _src1, double alpha, InputArray _src2, OutputArray _dst )
 {
+    CV_INSTRUMENT_REGION()
+
     int type = _src1.type(), depth = CV_MAT_DEPTH(type), cn = CV_MAT_CN(type);
     CV_Assert( type == _src2.type() );
 
@@ -2359,6 +2507,8 @@ void cv::scaleAdd( InputArray _src1, double alpha, InputArray _src2, OutputArray
 
 void cv::calcCovarMatrix( const Mat* data, int nsamples, Mat& covar, Mat& _mean, int flags, int ctype )
 {
+    CV_INSTRUMENT_REGION()
+
     CV_Assert( data && nsamples > 0 );
     Size size = data[0].size();
     int sz = size.width * size.height, esz = (int)data[0].elemSize();
@@ -2399,6 +2549,8 @@ void cv::calcCovarMatrix( const Mat* data, int nsamples, Mat& covar, Mat& _mean,
 
 void cv::calcCovarMatrix( InputArray _src, OutputArray _covar, InputOutputArray _mean, int flags, int ctype )
 {
+    CV_INSTRUMENT_REGION()
+
     if(_src.kind() == _InputArray::STD_VECTOR_MAT)
     {
         std::vector<cv::Mat> src;
@@ -2414,7 +2566,7 @@ void cv::calcCovarMatrix( InputArray _src, OutputArray _covar, InputOutputArray
         Mat _data(static_cast<int>(src.size()), size.area(), type);
 
         int i = 0;
-        for(std::vector<cv::Mat>::iterator each = src.begin(); each != src.end(); each++, i++ )
+        for(std::vector<cv::Mat>::iterator each = src.begin(); each != src.end(); ++each, ++i )
         {
             CV_Assert( (*each).size() == size && (*each).type() == type );
             Mat dataRow(size.height, size.width, type, _data.ptr(i));
@@ -2486,6 +2638,8 @@ void cv::calcCovarMatrix( InputArray _src, OutputArray _covar, InputOutputArray
 
 double cv::Mahalanobis( InputArray _v1, InputArray _v2, InputArray _icovar )
 {
+    CV_INSTRUMENT_REGION()
+
     Mat v1 = _v1.getMat(), v2 = _v2.getMat(), icovar = _icovar.getMat();
     int type = v1.type(), depth = v1.depth();
     Size sz = v1.size();
@@ -2776,6 +2930,8 @@ typedef void (*MulTransposedFunc)(const Mat& src, Mat& dst, const Mat& delta, do
 void cv::mulTransposed( InputArray _src, OutputArray _dst, bool ata,
                         InputArray _delta, double scale, int dtype )
 {
+    CV_INSTRUMENT_REGION()
+
     Mat src = _src.getMat(), delta = _delta.getMat();
     const int gemm_level = 100; // boundary above which GEMM is faster.
     int stype = src.type();
@@ -2919,9 +3075,9 @@ static double dotProd_8u(const uchar* src1, const uchar* src2, int len)
 #if ARITHM_USE_IPP && IPP_DISABLE_BLOCK
     CV_IPP_CHECK()
     {
-        if (0 <= ippiDotProd_8u64f_C1R(src1, (int)(len*sizeof(src1[0])),
+        if (0 <= CV_INSTRUMENT_FUN_IPP(ippiDotProd_8u64f_C1R, (src1, (int)(len*sizeof(src1[0])),
                                        src2, (int)(len*sizeof(src2[0])),
-                                       ippiSize(len, 1), &r))
+                                       ippiSize(len, 1), &r)))
         {
             CV_IMPL_ADD(CV_IMPL_IPP);
             return r;
@@ -3118,7 +3274,7 @@ static double dotProd_16u(const ushort* src1, const ushort* src2, int len)
     CV_IPP_CHECK()
     {
         double r = 0;
-        if (0 <= ippiDotProd_16u64f_C1R(src1, (int)(len*sizeof(src1[0])), src2, (int)(len*sizeof(src2[0])), ippiSize(len, 1), &r))
+        if (0 <= CV_INSTRUMENT_FUN_IPP(ippiDotProd_16u64f_C1R, src1, (int)(len*sizeof(src1[0])), src2, (int)(len*sizeof(src2[0])), ippiSize(len, 1), &r))
         {
             CV_IMPL_ADD(CV_IMPL_IPP);
             return r;
@@ -3135,7 +3291,7 @@ static double dotProd_16s(const short* src1, const short* src2, int len)
     CV_IPP_CHECK()
     {
         double r = 0;
-        if (0 <= ippiDotProd_16s64f_C1R(src1, (int)(len*sizeof(src1[0])), src2, (int)(len*sizeof(src2[0])), ippiSize(len, 1), &r))
+        if (0 <= CV_INSTRUMENT_FUN_IPP(ippiDotProd_16s64f_C1R, src1, (int)(len*sizeof(src1[0])), src2, (int)(len*sizeof(src2[0])), ippiSize(len, 1), &r))
         {
             CV_IMPL_ADD(CV_IMPL_IPP);
             return r;
@@ -3152,7 +3308,7 @@ static double dotProd_32s(const int* src1, const int* src2, int len)
     CV_IPP_CHECK()
     {
         double r = 0;
-        if (0 <= ippiDotProd_32s64f_C1R(src1, (int)(len*sizeof(src1[0])), src2, (int)(len*sizeof(src2[0])), ippiSize(len, 1), &r))
+        if (0 <= CV_INSTRUMENT_FUN_IPP(ippiDotProd_32s64f_C1R, src1, (int)(len*sizeof(src1[0])), src2, (int)(len*sizeof(src2[0])), ippiSize(len, 1), &r))
         {
             CV_IMPL_ADD(CV_IMPL_IPP);
             return r;
@@ -3171,7 +3327,7 @@ static double dotProd_32f(const float* src1, const float* src2, int len)
 #if (ARITHM_USE_IPP == 1)
     CV_IPP_CHECK()
     {
-        if (0 <= ippsDotProd_32f64f(src1, src2, len, &r))
+        if (0 <= CV_INSTRUMENT_FUN_IPP(ippsDotProd_32f64f, src1, src2, len, &r))
         {
             CV_IMPL_ADD(CV_IMPL_IPP);
             return r;
@@ -3209,7 +3365,7 @@ static double dotProd_64f(const double* src1, const double* src2, int len)
     CV_IPP_CHECK()
     {
         double r = 0;
-        if (0 <= ippsDotProd_64f(src1, src2, len, &r))
+        if (0 <= CV_INSTRUMENT_FUN_IPP(ippsDotProd_64f, src1, src2, len, &r))
         {
             CV_IMPL_ADD(CV_IMPL_IPP);
             return r;
@@ -3238,6 +3394,8 @@ static DotProdFunc getDotProdFunc(int depth)
 
 double Mat::dot(InputArray _mat) const
 {
+    CV_INSTRUMENT_REGION()
+
     Mat mat = _mat.getMat();
     int cn = channels();
     DotProdFunc func = getDotProdFunc(depth());
diff --git a/modules/core/src/matop.cpp b/modules/core/src/matop.cpp
index 2a6ec26..e7cfa01 100644
--- a/modules/core/src/matop.cpp
+++ b/modules/core/src/matop.cpp
@@ -333,6 +333,8 @@ void MatOp::augAssignXor(const MatExpr& expr, Mat& m) const
 
 void MatOp::add(const MatExpr& e1, const MatExpr& e2, MatExpr& res) const
 {
+    CV_INSTRUMENT_REGION()
+
     if( this == e2.op )
     {
         double alpha = 1, beta = 1;
@@ -364,6 +366,8 @@ void MatOp::add(const MatExpr& e1, const MatExpr& e2, MatExpr& res) const
 
 void MatOp::add(const MatExpr& expr1, const Scalar& s, MatExpr& res) const
 {
+    CV_INSTRUMENT_REGION()
+
     Mat m1;
     expr1.op->assign(expr1, m1);
     MatOp_AddEx::makeExpr(res, m1, Mat(), 1, 0, s);
@@ -372,6 +376,8 @@ void MatOp::add(const MatExpr& expr1, const Scalar& s, MatExpr& res) const
 
 void MatOp::subtract(const MatExpr& e1, const MatExpr& e2, MatExpr& res) const
 {
+    CV_INSTRUMENT_REGION()
+
     if( this == e2.op )
     {
         double alpha = 1, beta = -1;
@@ -403,6 +409,8 @@ void MatOp::subtract(const MatExpr& e1, const MatExpr& e2, MatExpr& res) const
 
 void MatOp::subtract(const Scalar& s, const MatExpr& expr, MatExpr& res) const
 {
+    CV_INSTRUMENT_REGION()
+
     Mat m;
     expr.op->assign(expr, m);
     MatOp_AddEx::makeExpr(res, m, Mat(), -1, 0, s);
@@ -411,6 +419,8 @@ void MatOp::subtract(const Scalar& s, const MatExpr& expr, MatExpr& res) const
 
 void MatOp::multiply(const MatExpr& e1, const MatExpr& e2, MatExpr& res, double scale) const
 {
+    CV_INSTRUMENT_REGION()
+
     if( this == e2.op )
     {
         Mat m1, m2;
@@ -462,6 +472,8 @@ void MatOp::multiply(const MatExpr& e1, const MatExpr& e2, MatExpr& res, double
 
 void MatOp::multiply(const MatExpr& expr, double s, MatExpr& res) const
 {
+    CV_INSTRUMENT_REGION()
+
     Mat m;
     expr.op->assign(expr, m);
     MatOp_AddEx::makeExpr(res, m, Mat(), s, 0);
@@ -470,6 +482,8 @@ void MatOp::multiply(const MatExpr& expr, double s, MatExpr& res) const
 
 void MatOp::divide(const MatExpr& e1, const MatExpr& e2, MatExpr& res, double scale) const
 {
+    CV_INSTRUMENT_REGION()
+
     if( this == e2.op )
     {
         if( isReciprocal(e1) && isReciprocal(e2) )
@@ -510,6 +524,8 @@ void MatOp::divide(const MatExpr& e1, const MatExpr& e2, MatExpr& res, double sc
 
 void MatOp::divide(double s, const MatExpr& expr, MatExpr& res) const
 {
+    CV_INSTRUMENT_REGION()
+
     Mat m;
     expr.op->assign(expr, m);
     MatOp_Bin::makeExpr(res, '/', m, Mat(), s);
@@ -518,6 +534,8 @@ void MatOp::divide(double s, const MatExpr& expr, MatExpr& res) const
 
 void MatOp::abs(const MatExpr& expr, MatExpr& res) const
 {
+    CV_INSTRUMENT_REGION()
+
     Mat m;
     expr.op->assign(expr, m);
     MatOp_Bin::makeExpr(res, 'a', m, Mat());
@@ -526,6 +544,8 @@ void MatOp::abs(const MatExpr& expr, MatExpr& res) const
 
 void MatOp::transpose(const MatExpr& expr, MatExpr& res) const
 {
+    CV_INSTRUMENT_REGION()
+
     Mat m;
     expr.op->assign(expr, m);
     MatOp_T::makeExpr(res, m, 1);
@@ -590,6 +610,8 @@ Size MatOp::size(const MatExpr& expr) const
 
 int MatOp::type(const MatExpr& expr) const
 {
+    CV_INSTRUMENT_REGION()
+
     return !expr.a.empty() ? expr.a.type() : expr.b.empty() ? expr.b.type() : expr.c.type();
 }
 
@@ -1038,6 +1060,8 @@ MatExpr operator > (double s, const Mat& a)
 
 MatExpr min(const Mat& a, const Mat& b)
 {
+    CV_INSTRUMENT_REGION()
+
     MatExpr e;
     MatOp_Bin::makeExpr(e, 'm', a, b);
     return e;
@@ -1045,6 +1069,8 @@ MatExpr min(const Mat& a, const Mat& b)
 
 MatExpr min(const Mat& a, double s)
 {
+    CV_INSTRUMENT_REGION()
+
     MatExpr e;
     MatOp_Bin::makeExpr(e, 'n', a, s);
     return e;
@@ -1052,6 +1078,8 @@ MatExpr min(const Mat& a, double s)
 
 MatExpr min(double s, const Mat& a)
 {
+    CV_INSTRUMENT_REGION()
+
     MatExpr e;
     MatOp_Bin::makeExpr(e, 'n', a, s);
     return e;
@@ -1059,6 +1087,8 @@ MatExpr min(double s, const Mat& a)
 
 MatExpr max(const Mat& a, const Mat& b)
 {
+    CV_INSTRUMENT_REGION()
+
     MatExpr e;
     MatOp_Bin::makeExpr(e, 'M', a, b);
     return e;
@@ -1066,6 +1096,8 @@ MatExpr max(const Mat& a, const Mat& b)
 
 MatExpr max(const Mat& a, double s)
 {
+    CV_INSTRUMENT_REGION()
+
     MatExpr e;
     MatOp_Bin::makeExpr(e, 'N', a, s);
     return e;
@@ -1073,6 +1105,8 @@ MatExpr max(const Mat& a, double s)
 
 MatExpr max(double s, const Mat& a)
 {
+    CV_INSTRUMENT_REGION()
+
     MatExpr e;
     MatOp_Bin::makeExpr(e, 'N', a, s);
     return e;
@@ -1150,6 +1184,8 @@ MatExpr operator ~(const Mat& a)
 
 MatExpr abs(const Mat& a)
 {
+    CV_INSTRUMENT_REGION()
+
     MatExpr e;
     MatOp_Bin::makeExpr(e, 'a', a, Scalar());
     return e;
@@ -1157,6 +1193,8 @@ MatExpr abs(const Mat& a)
 
 MatExpr abs(const MatExpr& e)
 {
+    CV_INSTRUMENT_REGION()
+
     MatExpr en;
     e.op->abs(e, en);
     return en;
@@ -1179,6 +1217,8 @@ Size MatExpr::size() const
 
 int MatExpr::type() const
 {
+    CV_INSTRUMENT_REGION()
+
     if( isInitializer(*this) )
         return a.type();
     if( isCmp(*this) )
@@ -1261,6 +1301,8 @@ void MatOp_AddEx::assign(const MatExpr& e, Mat& m, int _type) const
 
 void MatOp_AddEx::add(const MatExpr& e, const Scalar& s, MatExpr& res) const
 {
+    CV_INSTRUMENT_REGION()
+
     res = e;
     res.s += s;
 }
@@ -1268,6 +1310,8 @@ void MatOp_AddEx::add(const MatExpr& e, const Scalar& s, MatExpr& res) const
 
 void MatOp_AddEx::subtract(const Scalar& s, const MatExpr& e, MatExpr& res) const
 {
+    CV_INSTRUMENT_REGION()
+
     res = e;
     res.alpha = -res.alpha;
     res.beta = -res.beta;
@@ -1276,6 +1320,8 @@ void MatOp_AddEx::subtract(const Scalar& s, const MatExpr& e, MatExpr& res) cons
 
 void MatOp_AddEx::multiply(const MatExpr& e, double s, MatExpr& res) const
 {
+    CV_INSTRUMENT_REGION()
+
     res = e;
     res.alpha *= s;
     res.beta *= s;
@@ -1284,6 +1330,8 @@ void MatOp_AddEx::multiply(const MatExpr& e, double s, MatExpr& res) const
 
 void MatOp_AddEx::divide(double s, const MatExpr& e, MatExpr& res) const
 {
+    CV_INSTRUMENT_REGION()
+
     if( isScaled(e) )
         MatOp_Bin::makeExpr(res, '/', e.a, Mat(), s/e.alpha);
     else
@@ -1293,6 +1341,8 @@ void MatOp_AddEx::divide(double s, const MatExpr& e, MatExpr& res) const
 
 void MatOp_AddEx::transpose(const MatExpr& e, MatExpr& res) const
 {
+    CV_INSTRUMENT_REGION()
+
     if( isScaled(e) )
         MatOp_T::makeExpr(res, e.a, e.alpha);
     else
@@ -1301,6 +1351,8 @@ void MatOp_AddEx::transpose(const MatExpr& e, MatExpr& res) const
 
 void MatOp_AddEx::abs(const MatExpr& e, MatExpr& res) const
 {
+    CV_INSTRUMENT_REGION()
+
     if( (!e.b.data || e.beta == 0) && fabs(e.alpha) == 1 )
         MatOp_Bin::makeExpr(res, 'a', e.a, -e.s*e.alpha);
     else if( e.b.data && e.alpha + e.beta == 0 && e.alpha*e.beta == -1 )
@@ -1361,6 +1413,8 @@ void MatOp_Bin::assign(const MatExpr& e, Mat& m, int _type) const
 
 void MatOp_Bin::multiply(const MatExpr& e, double s, MatExpr& res) const
 {
+    CV_INSTRUMENT_REGION()
+
     if( e.flags == '*' || e.flags == '/' )
     {
         res = e;
@@ -1372,6 +1426,8 @@ void MatOp_Bin::multiply(const MatExpr& e, double s, MatExpr& res) const
 
 void MatOp_Bin::divide(double s, const MatExpr& e, MatExpr& res) const
 {
+    CV_INSTRUMENT_REGION()
+
     if( e.flags == '/' && (!e.b.data || e.beta == 0) )
         MatOp_AddEx::makeExpr(res, e.a, Mat(), s/e.alpha, 0);
     else
@@ -1427,12 +1483,16 @@ void MatOp_T::assign(const MatExpr& e, Mat& m, int _type) const
 
 void MatOp_T::multiply(const MatExpr& e, double s, MatExpr& res) const
 {
+    CV_INSTRUMENT_REGION()
+
     res = e;
     res.alpha *= s;
 }
 
 void MatOp_T::transpose(const MatExpr& e, MatExpr& res) const
 {
+    CV_INSTRUMENT_REGION()
+
     if( e.alpha == 1 )
         MatOp_Identity::makeExpr(res, e.a);
     else
@@ -1457,6 +1517,8 @@ void MatOp_GEMM::assign(const MatExpr& e, Mat& m, int _type) const
 
 void MatOp_GEMM::add(const MatExpr& e1, const MatExpr& e2, MatExpr& res) const
 {
+    CV_INSTRUMENT_REGION()
+
     bool i1 = isIdentity(e1), i2 = isIdentity(e2);
     double alpha1 = i1 ? 1 : e1.alpha, alpha2 = i2 ? 1 : e2.alpha;
 
@@ -1474,6 +1536,8 @@ void MatOp_GEMM::add(const MatExpr& e1, const MatExpr& e2, MatExpr& res) const
 
 void MatOp_GEMM::subtract(const MatExpr& e1, const MatExpr& e2, MatExpr& res) const
 {
+    CV_INSTRUMENT_REGION()
+
     bool i1 = isIdentity(e1), i2 = isIdentity(e2);
     double alpha1 = i1 ? 1 : e1.alpha, alpha2 = i2 ? 1 : e2.alpha;
 
@@ -1491,6 +1555,8 @@ void MatOp_GEMM::subtract(const MatExpr& e1, const MatExpr& e2, MatExpr& res) co
 
 void MatOp_GEMM::multiply(const MatExpr& e, double s, MatExpr& res) const
 {
+    CV_INSTRUMENT_REGION()
+
     res = e;
     res.alpha *= s;
     res.beta *= s;
@@ -1498,6 +1564,8 @@ void MatOp_GEMM::multiply(const MatExpr& e, double s, MatExpr& res) const
 
 void MatOp_GEMM::transpose(const MatExpr& e, MatExpr& res) const
 {
+    CV_INSTRUMENT_REGION()
+
     res = e;
     res.flags = (!(e.flags & CV_GEMM_A_T) ? CV_GEMM_B_T : 0) |
                 (!(e.flags & CV_GEMM_B_T) ? CV_GEMM_A_T : 0) |
@@ -1577,6 +1645,8 @@ void MatOp_Initializer::assign(const MatExpr& e, Mat& m, int _type) const
 
 void MatOp_Initializer::multiply(const MatExpr& e, double s, MatExpr& res) const
 {
+    CV_INSTRUMENT_REGION()
+
     res = e;
     res.alpha *= s;
 }
@@ -1595,6 +1665,8 @@ inline void MatOp_Initializer::makeExpr(MatExpr& res, int method, int ndims, con
 
 MatExpr Mat::t() const
 {
+    CV_INSTRUMENT_REGION()
+
     MatExpr e;
     MatOp_T::makeExpr(e, *this);
     return e;
@@ -1602,6 +1674,8 @@ MatExpr Mat::t() const
 
 MatExpr Mat::inv(int method) const
 {
+    CV_INSTRUMENT_REGION()
+
     MatExpr e;
     MatOp_Invert::makeExpr(e, method, *this);
     return e;
@@ -1610,6 +1684,8 @@ MatExpr Mat::inv(int method) const
 
 MatExpr Mat::mul(InputArray m, double scale) const
 {
+    CV_INSTRUMENT_REGION()
+
     MatExpr e;
     if(m.kind() == _InputArray::EXPR)
     {
@@ -1623,6 +1699,8 @@ MatExpr Mat::mul(InputArray m, double scale) const
 
 MatExpr Mat::zeros(int rows, int cols, int type)
 {
+    CV_INSTRUMENT_REGION()
+
     MatExpr e;
     MatOp_Initializer::makeExpr(e, '0', Size(cols, rows), type);
     return e;
@@ -1630,6 +1708,8 @@ MatExpr Mat::zeros(int rows, int cols, int type)
 
 MatExpr Mat::zeros(Size size, int type)
 {
+    CV_INSTRUMENT_REGION()
+
     MatExpr e;
     MatOp_Initializer::makeExpr(e, '0', size, type);
     return e;
@@ -1637,6 +1717,8 @@ MatExpr Mat::zeros(Size size, int type)
 
 MatExpr Mat::zeros(int ndims, const int* sizes, int type)
 {
+    CV_INSTRUMENT_REGION()
+
     MatExpr e;
     MatOp_Initializer::makeExpr(e, '0', ndims, sizes, type);
     return e;
@@ -1644,6 +1726,8 @@ MatExpr Mat::zeros(int ndims, const int* sizes, int type)
 
 MatExpr Mat::ones(int rows, int cols, int type)
 {
+    CV_INSTRUMENT_REGION()
+
     MatExpr e;
     MatOp_Initializer::makeExpr(e, '1', Size(cols, rows), type);
     return e;
@@ -1651,6 +1735,8 @@ MatExpr Mat::ones(int rows, int cols, int type)
 
 MatExpr Mat::ones(Size size, int type)
 {
+    CV_INSTRUMENT_REGION()
+
     MatExpr e;
     MatOp_Initializer::makeExpr(e, '1', size, type);
     return e;
@@ -1658,6 +1744,8 @@ MatExpr Mat::ones(Size size, int type)
 
 MatExpr Mat::ones(int ndims, const int* sizes, int type)
 {
+    CV_INSTRUMENT_REGION()
+
     MatExpr e;
     MatOp_Initializer::makeExpr(e, '1', ndims, sizes, type);
     return e;
@@ -1665,6 +1753,8 @@ MatExpr Mat::ones(int ndims, const int* sizes, int type)
 
 MatExpr Mat::eye(int rows, int cols, int type)
 {
+    CV_INSTRUMENT_REGION()
+
     MatExpr e;
     MatOp_Initializer::makeExpr(e, 'I', Size(cols, rows), type);
     return e;
@@ -1672,6 +1762,8 @@ MatExpr Mat::eye(int rows, int cols, int type)
 
 MatExpr Mat::eye(Size size, int type)
 {
+    CV_INSTRUMENT_REGION()
+
     MatExpr e;
     MatOp_Initializer::makeExpr(e, 'I', size, type);
     return e;
diff --git a/modules/core/src/matrix.cpp b/modules/core/src/matrix.cpp
index 4a260eb..c542a9a 100644
--- a/modules/core/src/matrix.cpp
+++ b/modules/core/src/matrix.cpp
@@ -77,9 +77,9 @@ void MatAllocator::download(UMatData* u, void* dstptr,
     {
         CV_Assert( sz[i] <= (size_t)INT_MAX );
         if( sz[i] == 0 )
-        return;
+            return;
         if( srcofs )
-        srcptr += srcofs[i]*(i <= dims-2 ? srcstep[i] : 1);
+            srcptr += srcofs[i]*(i <= dims-2 ? srcstep[i] : 1);
         isz[i] = (int)sz[i];
     }
 
@@ -89,9 +89,9 @@ void MatAllocator::download(UMatData* u, void* dstptr,
     const Mat* arrays[] = { &src, &dst };
     uchar* ptrs[2];
     NAryMatIterator it(arrays, ptrs, 2);
-    size_t j, planesz = it.size;
+    size_t planesz = it.size;
 
-    for( j = 0; j < it.nplanes; j++, ++it )
+    for( size_t j = 0; j < it.nplanes; j++, ++it )
         memcpy(ptrs[1], ptrs[0], planesz);
 }
 
@@ -108,9 +108,9 @@ void MatAllocator::upload(UMatData* u, const void* srcptr, int dims, const size_
     {
         CV_Assert( sz[i] <= (size_t)INT_MAX );
         if( sz[i] == 0 )
-        return;
+            return;
         if( dstofs )
-        dstptr += dstofs[i]*(i <= dims-2 ? dststep[i] : 1);
+            dstptr += dstofs[i]*(i <= dims-2 ? dststep[i] : 1);
         isz[i] = (int)sz[i];
     }
 
@@ -120,9 +120,9 @@ void MatAllocator::upload(UMatData* u, const void* srcptr, int dims, const size_
     const Mat* arrays[] = { &src, &dst };
     uchar* ptrs[2];
     NAryMatIterator it(arrays, ptrs, 2);
-    size_t j, planesz = it.size;
+    size_t planesz = it.size;
 
-    for( j = 0; j < it.nplanes; j++, ++it )
+    for( size_t j = 0; j < it.nplanes; j++, ++it )
         memcpy(ptrs[1], ptrs[0], planesz);
 }
 
@@ -130,6 +130,8 @@ void MatAllocator::copy(UMatData* usrc, UMatData* udst, int dims, const size_t s
                   const size_t srcofs[], const size_t srcstep[],
                   const size_t dstofs[], const size_t dststep[], bool /*sync*/) const
 {
+    CV_INSTRUMENT_REGION()
+
     if(!usrc || !udst)
         return;
     int isz[CV_MAX_DIM];
@@ -153,9 +155,9 @@ void MatAllocator::copy(UMatData* usrc, UMatData* udst, int dims, const size_t s
     const Mat* arrays[] = { &src, &dst };
     uchar* ptrs[2];
     NAryMatIterator it(arrays, ptrs, 2);
-    size_t j, planesz = it.size;
+    size_t planesz = it.size;
 
-    for( j = 0; j < it.nplanes; j++, ++it )
+    for( size_t j = 0; j < it.nplanes; j++, ++it )
         memcpy(ptrs[1], ptrs[0], planesz);
 }
 
@@ -299,8 +301,7 @@ static inline void setSize( Mat& m, int _dims, const int* _sz,
         return;
 
     size_t esz = CV_ELEM_SIZE(m.flags), esz1 = CV_ELEM_SIZE1(m.flags), total = esz;
-    int i;
-    for( i = _dims-1; i >= 0; i-- )
+    for( int i = _dims-1; i >= 0; i-- )
     {
         int s = _sz[i];
         CV_Assert( s >= 0 );
@@ -397,6 +398,14 @@ void Mat::create(int d, const int* _sizes, int _type)
             return;
     }
 
+    int _sizes_backup[CV_MAX_DIM]; // #5991
+    if (_sizes == (this->size.p))
+    {
+        for(i = 0; i < d; i++ )
+            _sizes_backup[i] = _sizes[i];
+        _sizes = _sizes_backup;
+    }
+
     release();
     if( d == 0 )
         return;
@@ -430,6 +439,11 @@ void Mat::create(int d, const int* _sizes, int _type)
     finalizeHdr(*this);
 }
 
+void Mat::create(const std::vector<int>& _sizes, int _type)
+{
+    create((int)_sizes.size(), _sizes.data(), _type);
+}
+
 void Mat::copySize(const Mat& m)
 {
     setSize(*this, m.dims, 0, 0);
@@ -532,20 +546,31 @@ Mat::Mat(int _dims, const int* _sizes, int _type, void* _data, const size_t* _st
 }
 
 
+Mat::Mat(const std::vector<int>& _sizes, int _type, void* _data, const size_t* _steps)
+    : flags(MAGIC_VAL), dims(0), rows(0), cols(0), data(0), datastart(0), dataend(0),
+      datalimit(0), allocator(0), u(0), size(&rows)
+{
+    flags |= CV_MAT_TYPE(_type);
+    datastart = data = (uchar*)_data;
+    setSize(*this, (int)_sizes.size(), _sizes.data(), _steps, true);
+    finalizeHdr(*this);
+}
+
+
 Mat::Mat(const Mat& m, const Range* ranges)
     : flags(MAGIC_VAL), dims(0), rows(0), cols(0), data(0), datastart(0), dataend(0),
       datalimit(0), allocator(0), u(0), size(&rows)
 {
-    int i, d = m.dims;
+    int d = m.dims;
 
     CV_Assert(ranges);
-    for( i = 0; i < d; i++ )
+    for( int i = 0; i < d; i++ )
     {
         Range r = ranges[i];
         CV_Assert( r == Range::all() || (0 <= r.start && r.start < r.end && r.end <= m.size[i]) );
     }
     *this = m;
-    for( i = 0; i < d; i++ )
+    for( int i = 0; i < d; i++ )
     {
         Range r = ranges[i];
         if( r != Range::all() && r != Range(0, size.p[i]))
@@ -558,6 +583,31 @@ Mat::Mat(const Mat& m, const Range* ranges)
     updateContinuityFlag(*this);
 }
 
+Mat::Mat(const Mat& m, const std::vector<Range>& ranges)
+    : flags(MAGIC_VAL), dims(0), rows(0), cols(0), data(0), datastart(0), dataend(0),
+    datalimit(0), allocator(0), u(0), size(&rows)
+{
+    int d = m.dims;
+
+    CV_Assert((int)ranges.size() == d);
+    for (int i = 0; i < d; i++)
+    {
+        Range r = ranges[i];
+        CV_Assert(r == Range::all() || (0 <= r.start && r.start < r.end && r.end <= m.size[i]));
+    }
+    *this = m;
+    for (int i = 0; i < d; i++)
+    {
+        Range r = ranges[i];
+        if (r != Range::all() && r != Range(0, size.p[i]))
+        {
+            size.p[i] = r.end - r.start;
+            data += r.start*step.p[i];
+            flags |= SUBMATRIX_FLAG;
+        }
+    }
+    updateContinuityFlag(*this);
+}
 
 static Mat cvMatNDToMat(const CvMatND* m, bool copyData)
 {
@@ -570,8 +620,8 @@ static Mat cvMatNDToMat(const CvMatND* m, bool copyData)
     int _sizes[CV_MAX_DIM];
     size_t _steps[CV_MAX_DIM];
 
-    int i, d = m->dims;
-    for( i = 0; i < d; i++ )
+    int d = m->dims;
+    for( int i = 0; i < d; i++ )
     {
         _sizes[i] = m->dim[i].size;
         _steps[i] = m->dim[i].step;
@@ -831,9 +881,9 @@ void Mat::push_back(const Mat& elems)
     bool eq = size == elems.size;
     size.p[0] = r;
     if( !eq )
-        CV_Error(CV_StsUnmatchedSizes, "");
+        CV_Error(CV_StsUnmatchedSizes, "Pushed vector length is not equal to matrix row length");
     if( type() != elems.type() )
-        CV_Error(CV_StsUnmatchedFormats, "");
+        CV_Error(CV_StsUnmatchedFormats, "Pushed vector type is not the same as matrix type");
 
     if( isSubmatrix() || dataend + step.p[0]*delta > datalimit )
         reserve( std::max(r + delta, (r*3+1)/2) );
@@ -1048,6 +1098,8 @@ int Mat::checkVector(int _elemChannels, int _depth, bool _requireContinuous) con
 
 void scalarToRawData(const Scalar& s, void* _buf, int type, int unroll_to)
 {
+    CV_INSTRUMENT_REGION()
+
     int i, depth = CV_MAT_DEPTH(type), cn = CV_MAT_CN(type);
     CV_Assert(cn <= 4);
     switch(depth)
@@ -1278,10 +1330,10 @@ void _InputArray::getMatVector(std::vector<Mat>& mv) const
     if( k == MAT )
     {
         const Mat& m = *(const Mat*)obj;
-        int i, n = (int)m.size[0];
+        int n = (int)m.size[0];
         mv.resize(n);
 
-        for( i = 0; i < n; i++ )
+        for( int i = 0; i < n; i++ )
             mv[i] = m.dims == 2 ? Mat(1, m.cols, m.type(), (void*)m.ptr(i)) :
                 Mat(m.dims-1, &m.size[1], m.type(), (void*)m.ptr(i), &m.step[1]);
         return;
@@ -1290,20 +1342,20 @@ void _InputArray::getMatVector(std::vector<Mat>& mv) const
     if( k == EXPR )
     {
         Mat m = *(const MatExpr*)obj;
-        int i, n = m.size[0];
+        int n = m.size[0];
         mv.resize(n);
 
-        for( i = 0; i < n; i++ )
+        for( int i = 0; i < n; i++ )
             mv[i] = m.row(i);
         return;
     }
 
     if( k == MATX )
     {
-        size_t i, n = sz.height, esz = CV_ELEM_SIZE(flags);
+        size_t n = sz.height, esz = CV_ELEM_SIZE(flags);
         mv.resize(n);
 
-        for( i = 0; i < n; i++ )
+        for( size_t i = 0; i < n; i++ )
             mv[i] = Mat(1, sz.width, CV_MAT_TYPE(flags), (uchar*)obj + esz*sz.width*i);
         return;
     }
@@ -1312,11 +1364,11 @@ void _InputArray::getMatVector(std::vector<Mat>& mv) const
     {
         const std::vector<uchar>& v = *(const std::vector<uchar>*)obj;
 
-        size_t i, n = v.size(), esz = CV_ELEM_SIZE(flags);
+        size_t n = v.size(), esz = CV_ELEM_SIZE(flags);
         int t = CV_MAT_DEPTH(flags), cn = CV_MAT_CN(flags);
         mv.resize(n);
 
-        for( i = 0; i < n; i++ )
+        for( size_t i = 0; i < n; i++ )
             mv[i] = Mat(1, cn, t, (void*)(&v[0] + esz*i));
         return;
     }
@@ -1330,11 +1382,11 @@ void _InputArray::getMatVector(std::vector<Mat>& mv) const
     if( k == STD_VECTOR_VECTOR )
     {
         const std::vector<std::vector<uchar> >& vv = *(const std::vector<std::vector<uchar> >*)obj;
-        int i, n = (int)vv.size();
+        int n = (int)vv.size();
         int t = CV_MAT_TYPE(flags);
         mv.resize(n);
 
-        for( i = 0; i < n; i++ )
+        for( int i = 0; i < n; i++ )
         {
             const std::vector<uchar>& v = vv[i];
             mv[i] = Mat(size(i), t, (void*)&v[0]);
@@ -1345,10 +1397,10 @@ void _InputArray::getMatVector(std::vector<Mat>& mv) const
     if( k == STD_VECTOR_MAT )
     {
         const std::vector<Mat>& v = *(const std::vector<Mat>*)obj;
-        size_t i, n = v.size();
+        size_t n = v.size();
         mv.resize(n);
 
-        for( i = 0; i < n; i++ )
+        for( size_t i = 0; i < n; i++ )
             mv[i] = v[i];
         return;
     }
@@ -1356,10 +1408,10 @@ void _InputArray::getMatVector(std::vector<Mat>& mv) const
     if( k == STD_VECTOR_UMAT )
     {
         const std::vector<UMat>& v = *(const std::vector<UMat>*)obj;
-        size_t i, n = v.size();
+        size_t n = v.size();
         mv.resize(n);
 
-        for( i = 0; i < n; i++ )
+        for( size_t i = 0; i < n; i++ )
             mv[i] = v[i].getMat(accessFlags);
         return;
     }
@@ -1381,10 +1433,10 @@ void _InputArray::getUMatVector(std::vector<UMat>& umv) const
     if( k == STD_VECTOR_MAT )
     {
         const std::vector<Mat>& v = *(const std::vector<Mat>*)obj;
-        size_t i, n = v.size();
+        size_t n = v.size();
         umv.resize(n);
 
-        for( i = 0; i < n; i++ )
+        for( size_t i = 0; i < n; i++ )
             umv[i] = v[i].getUMat(accessFlags);
         return;
     }
@@ -1392,10 +1444,10 @@ void _InputArray::getUMatVector(std::vector<UMat>& umv) const
     if( k == STD_VECTOR_UMAT )
     {
         const std::vector<UMat>& v = *(const std::vector<UMat>*)obj;
-        size_t i, n = v.size();
+        size_t n = v.size();
         umv.resize(n);
 
-        for( i = 0; i < n; i++ )
+        for( size_t i = 0; i < n; i++ )
             umv[i] = v[i];
         return;
     }
@@ -1986,6 +2038,9 @@ bool _InputArray::isContinuous(int i) const
         return vv[i].isContinuous();
     }
 
+    if( k == CUDA_GPU_MAT )
+      return i < 0 ? ((const cuda::GpuMat*)obj)->isContinuous() : true;
+
     CV_Error(CV_StsNotImplemented, "Unknown/unsupported array type");
     return false;
 }
@@ -2794,6 +2849,8 @@ InputOutputArray noArray() { return _none; }
 
 void cv::hconcat(const Mat* src, size_t nsrc, OutputArray _dst)
 {
+    CV_INSTRUMENT_REGION()
+
     if( nsrc == 0 || !src )
     {
         _dst.release();
@@ -2801,8 +2858,7 @@ void cv::hconcat(const Mat* src, size_t nsrc, OutputArray _dst)
     }
 
     int totalCols = 0, cols = 0;
-    size_t i;
-    for( i = 0; i < nsrc; i++ )
+    for( size_t i = 0; i < nsrc; i++ )
     {
         CV_Assert( src[i].dims <= 2 &&
                    src[i].rows == src[0].rows &&
@@ -2811,7 +2867,7 @@ void cv::hconcat(const Mat* src, size_t nsrc, OutputArray _dst)
     }
     _dst.create( src[0].rows, totalCols, src[0].type());
     Mat dst = _dst.getMat();
-    for( i = 0; i < nsrc; i++ )
+    for( size_t i = 0; i < nsrc; i++ )
     {
         Mat dpart = dst(Rect(cols, 0, src[i].cols, src[i].rows));
         src[i].copyTo(dpart);
@@ -2821,12 +2877,16 @@ void cv::hconcat(const Mat* src, size_t nsrc, OutputArray _dst)
 
 void cv::hconcat(InputArray src1, InputArray src2, OutputArray dst)
 {
+    CV_INSTRUMENT_REGION()
+
     Mat src[] = {src1.getMat(), src2.getMat()};
     hconcat(src, 2, dst);
 }
 
 void cv::hconcat(InputArray _src, OutputArray dst)
 {
+    CV_INSTRUMENT_REGION()
+
     std::vector<Mat> src;
     _src.getMatVector(src);
     hconcat(!src.empty() ? &src[0] : 0, src.size(), dst);
@@ -2834,6 +2894,8 @@ void cv::hconcat(InputArray _src, OutputArray dst)
 
 void cv::vconcat(const Mat* src, size_t nsrc, OutputArray _dst)
 {
+    CV_INSTRUMENT_REGION()
+
     if( nsrc == 0 || !src )
     {
         _dst.release();
@@ -2841,8 +2903,7 @@ void cv::vconcat(const Mat* src, size_t nsrc, OutputArray _dst)
     }
 
     int totalRows = 0, rows = 0;
-    size_t i;
-    for( i = 0; i < nsrc; i++ )
+    for( size_t i = 0; i < nsrc; i++ )
     {
         CV_Assert(src[i].dims <= 2 &&
                   src[i].cols == src[0].cols &&
@@ -2851,7 +2912,7 @@ void cv::vconcat(const Mat* src, size_t nsrc, OutputArray _dst)
     }
     _dst.create( totalRows, src[0].cols, src[0].type());
     Mat dst = _dst.getMat();
-    for( i = 0; i < nsrc; i++ )
+    for( size_t i = 0; i < nsrc; i++ )
     {
         Mat dpart(dst, Rect(0, rows, src[i].cols, src[i].rows));
         src[i].copyTo(dpart);
@@ -2861,12 +2922,16 @@ void cv::vconcat(const Mat* src, size_t nsrc, OutputArray _dst)
 
 void cv::vconcat(InputArray src1, InputArray src2, OutputArray dst)
 {
+    CV_INSTRUMENT_REGION()
+
     Mat src[] = {src1.getMat(), src2.getMat()};
     vconcat(src, 2, dst);
 }
 
 void cv::vconcat(InputArray _src, OutputArray dst)
 {
+    CV_INSTRUMENT_REGION()
+
     std::vector<Mat> src;
     _src.getMatVector(src);
     vconcat(!src.empty() ? &src[0] : 0, src.size(), dst);
@@ -2916,13 +2981,15 @@ static bool ocl_setIdentity( InputOutputArray _m, const Scalar& s )
 
 void cv::setIdentity( InputOutputArray _m, const Scalar& s )
 {
+    CV_INSTRUMENT_REGION()
+
     CV_Assert( _m.dims() <= 2 );
 
     CV_OCL_RUN(_m.isUMat(),
                ocl_setIdentity(_m, s))
 
     Mat m = _m.getMat();
-    int i, j, rows = m.rows, cols = m.cols, type = m.type();
+    int rows = m.rows, cols = m.cols, type = m.type();
 
     if( type == CV_32FC1 )
     {
@@ -2930,9 +2997,9 @@ void cv::setIdentity( InputOutputArray _m, const Scalar& s )
         float val = (float)s[0];
         size_t step = m.step/sizeof(data[0]);
 
-        for( i = 0; i < rows; i++, data += step )
+        for( int i = 0; i < rows; i++, data += step )
         {
-            for( j = 0; j < cols; j++ )
+            for( int j = 0; j < cols; j++ )
                 data[j] = 0;
             if( i < cols )
                 data[i] = val;
@@ -2944,9 +3011,9 @@ void cv::setIdentity( InputOutputArray _m, const Scalar& s )
         double val = s[0];
         size_t step = m.step/sizeof(data[0]);
 
-        for( i = 0; i < rows; i++, data += step )
+        for( int i = 0; i < rows; i++, data += step )
         {
-            for( j = 0; j < cols; j++ )
+            for( int j = 0; j < cols; j++ )
                 data[j] = j == i ? val : 0;
         }
     }
@@ -2961,9 +3028,11 @@ void cv::setIdentity( InputOutputArray _m, const Scalar& s )
 
 cv::Scalar cv::trace( InputArray _m )
 {
+    CV_INSTRUMENT_REGION()
+
     Mat m = _m.getMat();
     CV_Assert( m.dims <= 2 );
-    int i, type = m.type();
+    int type = m.type();
     int nm = std::min(m.rows, m.cols);
 
     if( type == CV_32FC1 )
@@ -2971,7 +3040,7 @@ cv::Scalar cv::trace( InputArray _m )
         const float* ptr = m.ptr<float>();
         size_t step = m.step/sizeof(ptr[0]) + 1;
         double _s = 0;
-        for( i = 0; i < nm; i++ )
+        for( int i = 0; i < nm; i++ )
             _s += ptr[i*step];
         return _s;
     }
@@ -2981,7 +3050,7 @@ cv::Scalar cv::trace( InputArray _m )
         const double* ptr = m.ptr<double>();
         size_t step = m.step/sizeof(ptr[0]) + 1;
         double _s = 0;
-        for( i = 0; i < nm; i++ )
+        for( int i = 0; i < nm; i++ )
             _s += ptr[i*step];
         return _s;
     }
@@ -3053,12 +3122,11 @@ transpose_( const uchar* src, size_t sstep, uchar* dst, size_t dstep, Size sz )
 template<typename T> static void
 transposeI_( uchar* data, size_t step, int n )
 {
-    int i, j;
-    for( i = 0; i < n; i++ )
+    for( int i = 0; i < n; i++ )
     {
         T* row = (T*)(data + step*i);
         uchar* data1 = data + i*sizeof(T);
-        for( j = i+1; j < n; j++ )
+        for( int j = i+1; j < n; j++ )
             std::swap( row[j], *(T*)(data1 + step*j) );
     }
 }
@@ -3162,62 +3230,64 @@ static bool ocl_transpose( InputArray _src, OutputArray _dst )
 #ifdef HAVE_IPP
 static bool ipp_transpose( Mat &src, Mat &dst )
 {
+    CV_INSTRUMENT_REGION_IPP()
+
     int type = src.type();
-    typedef IppStatus (CV_STDCALL * ippiTranspose)(const void * pSrc, int srcStep, void * pDst, int dstStep, IppiSize roiSize);
-    typedef IppStatus (CV_STDCALL * ippiTransposeI)(const void * pSrcDst, int srcDstStep, IppiSize roiSize);
-    ippiTranspose ippFunc = 0;
-    ippiTransposeI ippFuncI = 0;
+    typedef IppStatus (CV_STDCALL * IppiTranspose)(const void * pSrc, int srcStep, void * pDst, int dstStep, IppiSize roiSize);
+    typedef IppStatus (CV_STDCALL * IppiTransposeI)(const void * pSrcDst, int srcDstStep, IppiSize roiSize);
+    IppiTranspose ippiTranspose = 0;
+    IppiTransposeI ippiTranspose_I = 0;
 
     if (dst.data == src.data && dst.cols == dst.rows)
     {
         CV_SUPPRESS_DEPRECATED_START
-        ippFuncI =
-            type == CV_8UC1 ? (ippiTransposeI)ippiTranspose_8u_C1IR :
-            type == CV_8UC3 ? (ippiTransposeI)ippiTranspose_8u_C3IR :
-            type == CV_8UC4 ? (ippiTransposeI)ippiTranspose_8u_C4IR :
-            type == CV_16UC1 ? (ippiTransposeI)ippiTranspose_16u_C1IR :
-            type == CV_16UC3 ? (ippiTransposeI)ippiTranspose_16u_C3IR :
-            type == CV_16UC4 ? (ippiTransposeI)ippiTranspose_16u_C4IR :
-            type == CV_16SC1 ? (ippiTransposeI)ippiTranspose_16s_C1IR :
-            type == CV_16SC3 ? (ippiTransposeI)ippiTranspose_16s_C3IR :
-            type == CV_16SC4 ? (ippiTransposeI)ippiTranspose_16s_C4IR :
-            type == CV_32SC1 ? (ippiTransposeI)ippiTranspose_32s_C1IR :
-            type == CV_32SC3 ? (ippiTransposeI)ippiTranspose_32s_C3IR :
-            type == CV_32SC4 ? (ippiTransposeI)ippiTranspose_32s_C4IR :
-            type == CV_32FC1 ? (ippiTransposeI)ippiTranspose_32f_C1IR :
-            type == CV_32FC3 ? (ippiTransposeI)ippiTranspose_32f_C3IR :
-            type == CV_32FC4 ? (ippiTransposeI)ippiTranspose_32f_C4IR : 0;
+        ippiTranspose_I =
+            type == CV_8UC1 ? (IppiTransposeI)ippiTranspose_8u_C1IR :
+            type == CV_8UC3 ? (IppiTransposeI)ippiTranspose_8u_C3IR :
+            type == CV_8UC4 ? (IppiTransposeI)ippiTranspose_8u_C4IR :
+            type == CV_16UC1 ? (IppiTransposeI)ippiTranspose_16u_C1IR :
+            type == CV_16UC3 ? (IppiTransposeI)ippiTranspose_16u_C3IR :
+            type == CV_16UC4 ? (IppiTransposeI)ippiTranspose_16u_C4IR :
+            type == CV_16SC1 ? (IppiTransposeI)ippiTranspose_16s_C1IR :
+            type == CV_16SC3 ? (IppiTransposeI)ippiTranspose_16s_C3IR :
+            type == CV_16SC4 ? (IppiTransposeI)ippiTranspose_16s_C4IR :
+            type == CV_32SC1 ? (IppiTransposeI)ippiTranspose_32s_C1IR :
+            type == CV_32SC3 ? (IppiTransposeI)ippiTranspose_32s_C3IR :
+            type == CV_32SC4 ? (IppiTransposeI)ippiTranspose_32s_C4IR :
+            type == CV_32FC1 ? (IppiTransposeI)ippiTranspose_32f_C1IR :
+            type == CV_32FC3 ? (IppiTransposeI)ippiTranspose_32f_C3IR :
+            type == CV_32FC4 ? (IppiTransposeI)ippiTranspose_32f_C4IR : 0;
         CV_SUPPRESS_DEPRECATED_END
     }
     else
     {
-        ippFunc =
-            type == CV_8UC1 ? (ippiTranspose)ippiTranspose_8u_C1R :
-            type == CV_8UC3 ? (ippiTranspose)ippiTranspose_8u_C3R :
-            type == CV_8UC4 ? (ippiTranspose)ippiTranspose_8u_C4R :
-            type == CV_16UC1 ? (ippiTranspose)ippiTranspose_16u_C1R :
-            type == CV_16UC3 ? (ippiTranspose)ippiTranspose_16u_C3R :
-            type == CV_16UC4 ? (ippiTranspose)ippiTranspose_16u_C4R :
-            type == CV_16SC1 ? (ippiTranspose)ippiTranspose_16s_C1R :
-            type == CV_16SC3 ? (ippiTranspose)ippiTranspose_16s_C3R :
-            type == CV_16SC4 ? (ippiTranspose)ippiTranspose_16s_C4R :
-            type == CV_32SC1 ? (ippiTranspose)ippiTranspose_32s_C1R :
-            type == CV_32SC3 ? (ippiTranspose)ippiTranspose_32s_C3R :
-            type == CV_32SC4 ? (ippiTranspose)ippiTranspose_32s_C4R :
-            type == CV_32FC1 ? (ippiTranspose)ippiTranspose_32f_C1R :
-            type == CV_32FC3 ? (ippiTranspose)ippiTranspose_32f_C3R :
-            type == CV_32FC4 ? (ippiTranspose)ippiTranspose_32f_C4R : 0;
+        ippiTranspose =
+            type == CV_8UC1 ? (IppiTranspose)ippiTranspose_8u_C1R :
+            type == CV_8UC3 ? (IppiTranspose)ippiTranspose_8u_C3R :
+            type == CV_8UC4 ? (IppiTranspose)ippiTranspose_8u_C4R :
+            type == CV_16UC1 ? (IppiTranspose)ippiTranspose_16u_C1R :
+            type == CV_16UC3 ? (IppiTranspose)ippiTranspose_16u_C3R :
+            type == CV_16UC4 ? (IppiTranspose)ippiTranspose_16u_C4R :
+            type == CV_16SC1 ? (IppiTranspose)ippiTranspose_16s_C1R :
+            type == CV_16SC3 ? (IppiTranspose)ippiTranspose_16s_C3R :
+            type == CV_16SC4 ? (IppiTranspose)ippiTranspose_16s_C4R :
+            type == CV_32SC1 ? (IppiTranspose)ippiTranspose_32s_C1R :
+            type == CV_32SC3 ? (IppiTranspose)ippiTranspose_32s_C3R :
+            type == CV_32SC4 ? (IppiTranspose)ippiTranspose_32s_C4R :
+            type == CV_32FC1 ? (IppiTranspose)ippiTranspose_32f_C1R :
+            type == CV_32FC3 ? (IppiTranspose)ippiTranspose_32f_C3R :
+            type == CV_32FC4 ? (IppiTranspose)ippiTranspose_32f_C4R : 0;
     }
 
     IppiSize roiSize = { src.cols, src.rows };
-    if (ippFunc != 0)
+    if (ippiTranspose != 0)
     {
-        if (ippFunc(src.ptr(), (int)src.step, dst.ptr(), (int)dst.step, roiSize) >= 0)
+        if (CV_INSTRUMENT_FUN_IPP(ippiTranspose, src.ptr(), (int)src.step, dst.ptr(), (int)dst.step, roiSize) >= 0)
             return true;
     }
-    else if (ippFuncI != 0)
+    else if (ippiTranspose_I != 0)
     {
-        if (ippFuncI(dst.ptr(), (int)dst.step, roiSize) >= 0)
+        if (CV_INSTRUMENT_FUN_IPP(ippiTranspose_I, dst.ptr(), (int)dst.step, roiSize) >= 0)
             return true;
     }
     return false;
@@ -3229,6 +3299,8 @@ static bool ipp_transpose( Mat &src, Mat &dst )
 
 void cv::transpose( InputArray _src, OutputArray _dst )
 {
+    CV_INSTRUMENT_REGION()
+
     int type = _src.type(), esz = CV_ELEM_SIZE(type);
     CV_Assert( _src.dims() <= 2 && esz <= 32 );
 
@@ -3253,7 +3325,7 @@ void cv::transpose( InputArray _src, OutputArray _dst )
         return;
     }
 
-    CV_IPP_RUN(true, ipp_transpose(src, dst))
+    CV_IPP_RUN_FAST(ipp_transpose(src, dst))
 
     if( dst.data == src.data )
     {
@@ -3275,6 +3347,8 @@ void cv::transpose( InputArray _src, OutputArray _dst )
 
 void cv::completeSymm( InputOutputArray _m, bool LtoR )
 {
+    CV_INSTRUMENT_REGION()
+
     Mat m = _m.getMat();
     size_t step = m.step, esz = m.elemSize();
     CV_Assert( m.dims <= 2 && m.rows == m.cols );
@@ -3380,7 +3454,7 @@ reduceC_( const Mat& srcmat, Mat& dstmat )
 {
     typedef typename Op::rtype WT;
     Size size = srcmat.size();
-    int i, k, cn = srcmat.channels();
+    int cn = srcmat.channels();
     size.width *= cn;
     Op op;
 
@@ -3389,13 +3463,14 @@ reduceC_( const Mat& srcmat, Mat& dstmat )
         const T* src = srcmat.ptr<T>(y);
         ST* dst = dstmat.ptr<ST>(y);
         if( size.width == cn )
-            for( k = 0; k < cn; k++ )
+            for( int k = 0; k < cn; k++ )
                 dst[k] = src[k];
         else
         {
-            for( k = 0; k < cn; k++ )
+            for( int k = 0; k < cn; k++ )
             {
                 WT a0 = src[k], a1 = src[k+cn];
+                int i;
                 for( i = 2*cn; i <= size.width - 4*cn; i += 4*cn )
                 {
                     a0 = op(a0, (WT)src[i+k]);
@@ -3409,7 +3484,7 @@ reduceC_( const Mat& srcmat, Mat& dstmat )
                     a0 = op(a0, (WT)src[i+k]);
                 }
                 a0 = op(a0, a1);
-              dst[k] = (ST)a0;
+                dst[k] = (ST)a0;
             }
         }
     }
@@ -3450,43 +3525,43 @@ static inline bool ipp_reduceSumC_8u16u16s32f_64f(const cv::Mat& srcmat, cv::Mat
 
     IppiSize roisize = { srcmat.size().width, 1 };
 
-    typedef IppStatus (CV_STDCALL * ippiSum)(const void * pSrc, int srcStep, IppiSize roiSize, Ipp64f* pSum);
-    typedef IppStatus (CV_STDCALL * ippiSumHint)(const void * pSrc, int srcStep, IppiSize roiSize, Ipp64f* pSum, IppHintAlgorithm hint);
-    ippiSum ippFunc = 0;
-    ippiSumHint ippFuncHint = 0;
+    typedef IppStatus (CV_STDCALL * IppiSum)(const void * pSrc, int srcStep, IppiSize roiSize, Ipp64f* pSum);
+    typedef IppStatus (CV_STDCALL * IppiSumHint)(const void * pSrc, int srcStep, IppiSize roiSize, Ipp64f* pSum, IppHintAlgorithm hint);
+    IppiSum ippiSum = 0;
+    IppiSumHint ippiSumHint = 0;
 
     if(ddepth == CV_64F)
     {
-        ippFunc =
-            stype == CV_8UC1 ? (ippiSum)ippiSum_8u_C1R :
-            stype == CV_8UC3 ? (ippiSum)ippiSum_8u_C3R :
-            stype == CV_8UC4 ? (ippiSum)ippiSum_8u_C4R :
-            stype == CV_16UC1 ? (ippiSum)ippiSum_16u_C1R :
-            stype == CV_16UC3 ? (ippiSum)ippiSum_16u_C3R :
-            stype == CV_16UC4 ? (ippiSum)ippiSum_16u_C4R :
-            stype == CV_16SC1 ? (ippiSum)ippiSum_16s_C1R :
-            stype == CV_16SC3 ? (ippiSum)ippiSum_16s_C3R :
-            stype == CV_16SC4 ? (ippiSum)ippiSum_16s_C4R : 0;
-        ippFuncHint =
-            stype == CV_32FC1 ? (ippiSumHint)ippiSum_32f_C1R :
-            stype == CV_32FC3 ? (ippiSumHint)ippiSum_32f_C3R :
-            stype == CV_32FC4 ? (ippiSumHint)ippiSum_32f_C4R : 0;
+        ippiSum =
+            stype == CV_8UC1 ? (IppiSum)ippiSum_8u_C1R :
+            stype == CV_8UC3 ? (IppiSum)ippiSum_8u_C3R :
+            stype == CV_8UC4 ? (IppiSum)ippiSum_8u_C4R :
+            stype == CV_16UC1 ? (IppiSum)ippiSum_16u_C1R :
+            stype == CV_16UC3 ? (IppiSum)ippiSum_16u_C3R :
+            stype == CV_16UC4 ? (IppiSum)ippiSum_16u_C4R :
+            stype == CV_16SC1 ? (IppiSum)ippiSum_16s_C1R :
+            stype == CV_16SC3 ? (IppiSum)ippiSum_16s_C3R :
+            stype == CV_16SC4 ? (IppiSum)ippiSum_16s_C4R : 0;
+        ippiSumHint =
+            stype == CV_32FC1 ? (IppiSumHint)ippiSum_32f_C1R :
+            stype == CV_32FC3 ? (IppiSumHint)ippiSum_32f_C3R :
+            stype == CV_32FC4 ? (IppiSumHint)ippiSum_32f_C4R : 0;
     }
 
-    if(ippFunc)
+    if(ippiSum)
     {
         for(int y = 0; y < srcmat.size().height; y++)
         {
-            if(ippFunc(srcmat.ptr(y), sstep, roisize, dstmat.ptr<Ipp64f>(y)) < 0)
+            if(CV_INSTRUMENT_FUN_IPP(ippiSum, srcmat.ptr(y), sstep, roisize, dstmat.ptr<Ipp64f>(y)) < 0)
                 return false;
         }
         return true;
     }
-    else if(ippFuncHint)
+    else if(ippiSumHint)
     {
         for(int y = 0; y < srcmat.size().height; y++)
         {
-            if(ippFuncHint(srcmat.ptr(y), sstep, roisize, dstmat.ptr<Ipp64f>(y), ippAlgHintAccurate) < 0)
+            if(CV_INSTRUMENT_FUN_IPP(ippiSumHint, srcmat.ptr(y), sstep, roisize, dstmat.ptr<Ipp64f>(y), ippAlgHintAccurate) < 0)
                 return false;
         }
         return true;
@@ -3497,7 +3572,7 @@ static inline bool ipp_reduceSumC_8u16u16s32f_64f(const cv::Mat& srcmat, cv::Mat
 
 static inline void reduceSumC_8u16u16s32f_64f(const cv::Mat& srcmat, cv::Mat& dstmat)
 {
-    CV_IPP_RUN(true, ipp_reduceSumC_8u16u16s32f_64f(srcmat, dstmat));
+    CV_IPP_RUN_FAST(ipp_reduceSumC_8u16u16s32f_64f(srcmat, dstmat));
 
     cv::ReduceFunc func = 0;
 
@@ -3547,7 +3622,7 @@ static inline bool ipp_reduce##optype##C##favor(const cv::Mat& srcmat, cv::Mat&
         IppiSize roisize = ippiSize(srcmat.size().width, 1);\
         for(int y = 0; y < srcmat.size().height; y++)\
         {\
-            if(ippi##optype##_##favor##_C1R(srcmat.ptr<IppType>(y), sstep, roisize, dstmat.ptr<IppType>(y)) < 0)\
+            if(CV_INSTRUMENT_FUN_IPP(ippi##optype##_##favor##_C1R, srcmat.ptr<IppType>(y), sstep, roisize, dstmat.ptr<IppType>(y)) < 0)\
                 return false;\
         }\
         return true;\
@@ -3556,7 +3631,7 @@ static inline bool ipp_reduce##optype##C##favor(const cv::Mat& srcmat, cv::Mat&
 } \
 static inline void reduce##optype##C##favor(const cv::Mat& srcmat, cv::Mat& dstmat) \
 { \
-    CV_IPP_RUN(true, ipp_reduce##optype##C##favor(srcmat, dstmat)); \
+    CV_IPP_RUN_FAST(ipp_reduce##optype##C##favor(srcmat, dstmat)); \
     cv::reduceC_ < type1, type2, cv::Op##optype < type2 > >(srcmat, dstmat); \
 }
 #endif
@@ -3696,6 +3771,8 @@ static bool ocl_reduce(InputArray _src, OutputArray _dst,
 
 void cv::reduce(InputArray _src, OutputArray _dst, int dim, int op, int dtype)
 {
+    CV_INSTRUMENT_REGION()
+
     CV_Assert( _src.dims() <= 2 );
     int op0 = op;
     int stype = _src.type(), sdepth = CV_MAT_DEPTH(stype), cn = CV_MAT_CN(stype);
@@ -3895,7 +3972,7 @@ template<typename T> static void sort_( const Mat& src, Mat& dst, int flags )
 {
     AutoBuffer<T> buf;
     T* bptr;
-    int i, j, n, len;
+    int n, len;
     bool sortRows = (flags & 1) == CV_SORT_EVERY_ROW;
     bool inplace = src.data == dst.data;
     bool sortDescending = (flags & CV_SORT_DESCENDING) != 0;
@@ -3920,7 +3997,7 @@ template<typename T> static void sort_( const Mat& src, Mat& dst, int flags )
     }
 #endif
 
-    for( i = 0; i < n; i++ )
+    for( int i = 0; i < n; i++ )
     {
         T* ptr = bptr;
         if( sortRows )
@@ -3935,12 +4012,12 @@ template<typename T> static void sort_( const Mat& src, Mat& dst, int flags )
         }
         else
         {
-            for( j = 0; j < len; j++ )
+            for( int j = 0; j < len; j++ )
                 ptr[j] = src.ptr<T>(j)[i];
         }
 
 #ifdef USE_IPP_SORT
-        if (!ippSortFunc || ippSortFunc(ptr, len) < 0)
+        if (!ippSortFunc || CV_INSTRUMENT_FUN_IPP(ippSortFunc, ptr, len) < 0)
 #endif
         {
 #ifdef USE_IPP_SORT
@@ -3951,13 +4028,13 @@ template<typename T> static void sort_( const Mat& src, Mat& dst, int flags )
             if( sortDescending )
             {
 #ifdef USE_IPP_SORT
-                if (!ippFlipFunc || ippFlipFunc(ptr, len) < 0)
+                if (!ippFlipFunc || CV_INSTRUMENT_FUN_IPP(ippFlipFunc, ptr, len) < 0)
 #endif
                 {
 #ifdef USE_IPP_SORT
                     setIppErrorStatus();
 #endif
-                    for( j = 0; j < len/2; j++ )
+                    for( int j = 0; j < len/2; j++ )
                         std::swap(ptr[j], ptr[len-1-j]);
                 }
 #ifdef USE_IPP_SORT
@@ -3976,7 +4053,7 @@ template<typename T> static void sort_( const Mat& src, Mat& dst, int flags )
 #endif
 
         if( !sortRows )
-            for( j = 0; j < len; j++ )
+            for( int j = 0; j < len; j++ )
                 dst.ptr<T>(j)[i] = ptr[j];
     }
 }
@@ -4017,14 +4094,12 @@ template<typename T> static void sortIdx_( const Mat& src, Mat& dst, int flags )
 {
     AutoBuffer<T> buf;
     AutoBuffer<int> ibuf;
-    T* bptr;
-    int* _iptr;
-    int i, j, n, len;
     bool sortRows = (flags & 1) == CV_SORT_EVERY_ROW;
     bool sortDescending = (flags & CV_SORT_DESCENDING) != 0;
 
     CV_Assert( src.data != dst.data );
 
+    int n, len;
     if( sortRows )
         n = src.rows, len = src.cols;
     else
@@ -4033,8 +4108,8 @@ template<typename T> static void sortIdx_( const Mat& src, Mat& dst, int flags )
         buf.allocate(len);
         ibuf.allocate(len);
     }
-    bptr = (T*)buf;
-    _iptr = (int*)ibuf;
+    T* bptr = (T*)buf;
+    int* _iptr = (int*)ibuf;
 
 #if defined USE_IPP_SORT && IPP_DISABLE_BLOCK
     int depth = src.depth();
@@ -4047,7 +4122,7 @@ template<typename T> static void sortIdx_( const Mat& src, Mat& dst, int flags )
     }
 #endif
 
-    for( i = 0; i < n; i++ )
+    for( int i = 0; i < n; i++ )
     {
         T* ptr = bptr;
         int* iptr = _iptr;
@@ -4059,10 +4134,10 @@ template<typename T> static void sortIdx_( const Mat& src, Mat& dst, int flags )
         }
         else
         {
-            for( j = 0; j < len; j++ )
+            for( int j = 0; j < len; j++ )
                 ptr[j] = src.ptr<T>(j)[i];
         }
-        for( j = 0; j < len; j++ )
+        for( int j = 0; j < len; j++ )
             iptr[j] = j;
 
 #if defined USE_IPP_SORT && IPP_DISABLE_BLOCK
@@ -4082,7 +4157,7 @@ template<typename T> static void sortIdx_( const Mat& src, Mat& dst, int flags )
 #if defined USE_IPP_SORT && IPP_DISABLE_BLOCK
                     setIppErrorStatus();
 #endif
-                    for( j = 0; j < len/2; j++ )
+                    for( int j = 0; j < len/2; j++ )
                         std::swap(iptr[j], iptr[len-1-j]);
                 }
 #if defined USE_IPP_SORT && IPP_DISABLE_BLOCK
@@ -4101,7 +4176,7 @@ template<typename T> static void sortIdx_( const Mat& src, Mat& dst, int flags )
 #endif
 
         if( !sortRows )
-            for( j = 0; j < len; j++ )
+            for( int j = 0; j < len; j++ )
                 dst.ptr<int>(j)[i] = iptr[j];
     }
 }
@@ -4112,6 +4187,8 @@ typedef void (*SortFunc)(const Mat& src, Mat& dst, int flags);
 
 void cv::sort( InputArray _src, OutputArray _dst, int flags )
 {
+    CV_INSTRUMENT_REGION()
+
     static SortFunc tab[] =
     {
         sort_<uchar>, sort_<schar>, sort_<ushort>, sort_<short>,
@@ -4127,6 +4204,8 @@ void cv::sort( InputArray _src, OutputArray _dst, int flags )
 
 void cv::sortIdx( InputArray _src, OutputArray _dst, int flags )
 {
+    CV_INSTRUMENT_REGION()
+
     static SortFunc tab[] =
     {
         sortIdx_<uchar>, sortIdx_<schar>, sortIdx_<ushort>, sortIdx_<short>,
@@ -4208,22 +4287,17 @@ cvReduce( const CvArr* srcarr, CvArr* dstarr, int dim, int op )
 CV_IMPL CvArr*
 cvRange( CvArr* arr, double start, double end )
 {
-    int ok = 0;
-
     CvMat stub, *mat = (CvMat*)arr;
-    double delta;
-    int type, step;
+    int step;
     double val = start;
-    int i, j;
-    int rows, cols;
 
     if( !CV_IS_MAT(mat) )
         mat = cvGetMat( mat, &stub);
 
-    rows = mat->rows;
-    cols = mat->cols;
-    type = CV_MAT_TYPE(mat->type);
-    delta = (end-start)/(rows*cols);
+    int rows = mat->rows;
+    int cols = mat->cols;
+    int type = CV_MAT_TYPE(mat->type);
+    double delta = (end-start)/(rows*cols);
 
     if( CV_IS_MAT_CONT(mat->type) )
     {
@@ -4242,29 +4316,28 @@ cvRange( CvArr* arr, double start, double end )
         if( fabs(val - ival) < DBL_EPSILON &&
             fabs(delta - idelta) < DBL_EPSILON )
         {
-            for( i = 0; i < rows; i++, idata += step )
-                for( j = 0; j < cols; j++, ival += idelta )
+            for( int i = 0; i < rows; i++, idata += step )
+                for( int j = 0; j < cols; j++, ival += idelta )
                     idata[j] = ival;
         }
         else
         {
-            for( i = 0; i < rows; i++, idata += step )
-                for( j = 0; j < cols; j++, val += delta )
+            for( int i = 0; i < rows; i++, idata += step )
+                for( int j = 0; j < cols; j++, val += delta )
                     idata[j] = cvRound(val);
         }
     }
     else if( type == CV_32FC1 )
     {
         float* fdata = mat->data.fl;
-        for( i = 0; i < rows; i++, fdata += step )
-            for( j = 0; j < cols; j++, val += delta )
+        for( int i = 0; i < rows; i++, fdata += step )
+            for( int j = 0; j < cols; j++, val += delta )
                 fdata[j] = (float)val;
     }
     else
         CV_Error( CV_StsUnsupportedFormat, "The function only supports 32sC1 and 32fC1 datatypes" );
 
-    ok = 1;
-    return ok ? arr : 0;
+    return arr;
 }
 
 
@@ -4665,7 +4738,7 @@ void MatConstIterator::seek(ptrdiff_t ofs, bool relative)
 
 void MatConstIterator::seek(const int* _idx, bool relative)
 {
-    int i, d = m->dims;
+    int d = m->dims;
     ptrdiff_t ofs = 0;
     if( !_idx )
         ;
@@ -4673,7 +4746,7 @@ void MatConstIterator::seek(const int* _idx, bool relative)
         ofs = _idx[0]*m->size[1] + _idx[1];
     else
     {
-        for( i = 0; i < d; i++ )
+        for( int i = 0; i < d; i++ )
             ofs = ofs*m->size[i] + _idx[i];
     }
     seek(ofs, relative);
@@ -4883,13 +4956,13 @@ SparseMat::SparseMat(const Mat& m)
 
 void SparseMat::create(int d, const int* _sizes, int _type)
 {
-    int i;
     CV_Assert( _sizes && 0 < d && d <= CV_MAX_DIM );
-    for( i = 0; i < d; i++ )
+    for( int i = 0; i < d; i++ )
         CV_Assert( _sizes[i] > 0 );
     _type = CV_MAT_TYPE(_type);
     if( hdr && _type == type() && hdr->dims == d && hdr->refcount == 1 )
     {
+        int i;
         for( i = 0; i < d; i++ )
             if( _sizes[i] != hdr->size[i] )
                 break;
@@ -4899,6 +4972,13 @@ void SparseMat::create(int d, const int* _sizes, int _type)
             return;
         }
     }
+    int _sizes_backup[CV_MAX_DIM]; // #5991
+    if (_sizes == hdr->size)
+    {
+        for(int i = 0; i < d; i++ )
+            _sizes_backup[i] = _sizes[i];
+        _sizes = _sizes_backup;
+    }
     release();
     flags = MAGIC_VAL | _type;
     hdr = new Hdr(d, _sizes, _type);
@@ -4915,9 +4995,9 @@ void SparseMat::copyTo( SparseMat& m ) const
     }
     m.create( hdr->dims, hdr->size, type() );
     SparseMatConstIterator from = begin();
-    size_t i, N = nzcount(), esz = elemSize();
+    size_t N = nzcount(), esz = elemSize();
 
-    for( i = 0; i < N; i++, ++from )
+    for( size_t i = 0; i < N; i++, ++from )
     {
         const Node* n = from.node();
         uchar* to = m.newNode(n->idx, n->hashval);
@@ -4933,9 +5013,9 @@ void SparseMat::copyTo( Mat& m ) const
     m = Scalar(0);
 
     SparseMatConstIterator from = begin();
-    size_t i, N = nzcount(), esz = elemSize();
+    size_t N = nzcount(), esz = elemSize();
 
-    for( i = 0; i < N; i++, ++from )
+    for( size_t i = 0; i < N; i++, ++from )
     {
         const Node* n = from.node();
         copyElem( from.ptr, (ndims > 1 ? m.ptr(n->idx) : m.ptr(n->idx[0])), esz);
@@ -4962,12 +5042,12 @@ void SparseMat::convertTo( SparseMat& m, int rtype, double alpha ) const
         m.create( hdr->dims, hdr->size, rtype );
 
     SparseMatConstIterator from = begin();
-    size_t i, N = nzcount();
+    size_t N = nzcount();
 
     if( alpha == 1 )
     {
         ConvertData cvtfunc = getConvertElem(type(), rtype);
-        for( i = 0; i < N; i++, ++from )
+        for( size_t i = 0; i < N; i++, ++from )
         {
             const Node* n = from.node();
             uchar* to = hdr == m.hdr ? from.ptr : m.newNode(n->idx, n->hashval);
@@ -4977,7 +5057,7 @@ void SparseMat::convertTo( SparseMat& m, int rtype, double alpha ) const
     else
     {
         ConvertScaleData cvtfunc = getConvertScaleElem(type(), rtype);
-        for( i = 0; i < N; i++, ++from )
+        for( size_t i = 0; i < N; i++, ++from )
         {
             const Node* n = from.node();
             uchar* to = hdr == m.hdr ? from.ptr : m.newNode(n->idx, n->hashval);
@@ -4999,12 +5079,12 @@ void SparseMat::convertTo( Mat& m, int rtype, double alpha, double beta ) const
     m = Scalar(beta);
 
     SparseMatConstIterator from = begin();
-    size_t i, N = nzcount();
+    size_t N = nzcount();
 
     if( alpha == 1 && beta == 0 )
     {
         ConvertData cvtfunc = getConvertElem(type(), rtype);
-        for( i = 0; i < N; i++, ++from )
+        for( size_t i = 0; i < N; i++, ++from )
         {
             const Node* n = from.node();
             uchar* to = m.ptr(n->idx);
@@ -5014,7 +5094,7 @@ void SparseMat::convertTo( Mat& m, int rtype, double alpha, double beta ) const
     else
     {
         ConvertScaleData cvtfunc = getConvertScaleElem(type(), rtype);
-        for( i = 0; i < N; i++, ++from )
+        for( size_t i = 0; i < N; i++, ++from )
         {
             const Node* n = from.node();
             uchar* to = m.ptr(n->idx);
@@ -5048,7 +5128,7 @@ uchar* SparseMat::ptr(int i0, bool createMissing, size_t* hashval)
         int idx[] = { i0 };
         return newNode( idx, h );
     }
-    return 0;
+    return NULL;
 }
 
 uchar* SparseMat::ptr(int i0, int i1, bool createMissing, size_t* hashval)
@@ -5070,7 +5150,7 @@ uchar* SparseMat::ptr(int i0, int i1, bool createMissing, size_t* hashval)
         int idx[] = { i0, i1 };
         return newNode( idx, h );
     }
-    return 0;
+    return NULL;
 }
 
 uchar* SparseMat::ptr(int i0, int i1, int i2, bool createMissing, size_t* hashval)
@@ -5093,7 +5173,7 @@ uchar* SparseMat::ptr(int i0, int i1, int i2, bool createMissing, size_t* hashva
         int idx[] = { i0, i1, i2 };
         return newNode( idx, h );
     }
-    return 0;
+    return NULL;
 }
 
 uchar* SparseMat::ptr(const int* idx, bool createMissing, size_t* hashval)
@@ -5117,7 +5197,7 @@ uchar* SparseMat::ptr(const int* idx, bool createMissing, size_t* hashval)
         nidx = elem->next;
     }
 
-    return createMissing ? newNode(idx, h) : 0;
+    return createMissing ? newNode(idx, h) : NULL;
 }
 
 void SparseMat::erase(int i0, int i1, size_t* hashval)
@@ -5191,13 +5271,13 @@ void SparseMat::resizeHashTab(size_t newsize)
     if((newsize & (newsize-1)) != 0)
         newsize = (size_t)1 << cvCeil(std::log((double)newsize)/CV_LOG2);
 
-    size_t i, hsize = hdr->hashtab.size();
+    size_t hsize = hdr->hashtab.size();
     std::vector<size_t> _newh(newsize);
     size_t* newh = &_newh[0];
-    for( i = 0; i < newsize; i++ )
+    for( size_t i = 0; i < newsize; i++ )
         newh[i] = 0;
     uchar* pool = &hdr->pool[0];
-    for( i = 0; i < hsize; i++ )
+    for( size_t i = 0; i < hsize; i++ )
     {
         size_t nidx = hdr->hashtab[i];
         while( nidx )
@@ -5326,6 +5406,8 @@ SparseMatConstIterator& SparseMatConstIterator::operator ++()
 
 double norm( const SparseMat& src, int normType )
 {
+    CV_INSTRUMENT_REGION()
+
     SparseMatConstIterator it = src.begin();
 
     size_t i, N = src.nzcount();
@@ -5375,6 +5457,8 @@ double norm( const SparseMat& src, int normType )
 
 void minMaxLoc( const SparseMat& src, double* _minval, double* _maxval, int* _minidx, int* _maxidx )
 {
+    CV_INSTRUMENT_REGION()
+
     SparseMatConstIterator it = src.begin();
     size_t i, N = src.nzcount(), d = src.hdr ? src.hdr->dims : 0;
     int type = src.type();
@@ -5438,6 +5522,8 @@ void minMaxLoc( const SparseMat& src, double* _minval, double* _maxval, int* _mi
 
 void normalize( const SparseMat& src, SparseMat& dst, double a, int norm_type )
 {
+    CV_INSTRUMENT_REGION()
+
     double scale = 1;
     if( norm_type == CV_L2 || norm_type == CV_L1 || norm_type == CV_C )
     {
@@ -5505,6 +5591,16 @@ Rect RotatedRect::boundingRect() const
     return r;
 }
 
+
+Rect_<float> RotatedRect::boundingRect2f() const
+{
+    Point2f pt[4];
+    points(pt);
+    Rect_<float> r(Point_<float>(min(min(min(pt[0].x, pt[1].x), pt[2].x), pt[3].x), min(min(min(pt[0].y, pt[1].y), pt[2].y), pt[3].y)),
+                   Point_<float>(max(max(max(pt[0].x, pt[1].x), pt[2].x), pt[3].x), max(max(max(pt[0].y, pt[1].y), pt[2].y), pt[3].y)));
+    return r;
+}
+
 }
 
 // glue
diff --git a/modules/core/src/matrix_decomp.cpp b/modules/core/src/matrix_decomp.cpp
index 3fe9eca..66c584a 100644
--- a/modules/core/src/matrix_decomp.cpp
+++ b/modules/core/src/matrix_decomp.cpp
@@ -89,8 +89,6 @@ LUImpl(_Tp* A, size_t astep, int m, _Tp* b, size_t bstep, int n, _Tp eps)
                 for( k = 0; k < n; k++ )
                     b[j*bstep + k] += alpha*b[i*bstep + k];
         }
-
-        A[i*astep + i] = -d;
     }
 
     if( b )
@@ -101,7 +99,7 @@ LUImpl(_Tp* A, size_t astep, int m, _Tp* b, size_t bstep, int n, _Tp eps)
                 _Tp s = b[i*bstep + j];
                 for( k = i+1; k < m; k++ )
                     s -= A[i*astep + k]*b[k*bstep + j];
-                b[i*bstep + j] = s*A[i*astep + i];
+                b[i*bstep + j] = s/A[i*astep + i];
             }
     }
 
@@ -111,13 +109,23 @@ LUImpl(_Tp* A, size_t astep, int m, _Tp* b, size_t bstep, int n, _Tp eps)
 
 int LU32f(float* A, size_t astep, int m, float* b, size_t bstep, int n)
 {
-    return LUImpl(A, astep, m, b, bstep, n, FLT_EPSILON*10);
+    CV_INSTRUMENT_REGION()
+
+    int output;
+    CALL_HAL_RET(LU32f, cv_hal_LU32f, output, A, astep, m, b, bstep, n)
+    output = LUImpl(A, astep, m, b, bstep, n, FLT_EPSILON*10);
+    return output;
 }
 
 
 int LU64f(double* A, size_t astep, int m, double* b, size_t bstep, int n)
 {
-    return LUImpl(A, astep, m, b, bstep, n, DBL_EPSILON*100);
+    CV_INSTRUMENT_REGION()
+
+    int output;
+    CALL_HAL_RET(LU64f, cv_hal_LU64f, output, A, astep, m, b, bstep, n)
+    output = LUImpl(A, astep, m, b, bstep, n, DBL_EPSILON*100);
+    return output;
 }
 
 template<typename _Tp> static inline bool
@@ -149,8 +157,12 @@ CholImpl(_Tp* A, size_t astep, int m, _Tp* b, size_t bstep, int n)
         L[i*astep + i] = (_Tp)(1./std::sqrt(s));
     }
 
-    if( !b )
+    if (!b)
+    {
+        for( i = 0; i < m; i++ )
+             L[i*astep + i]=1/L[i*astep + i];
         return true;
+   }
 
     // LLt x = b
     // 1: L y = b
@@ -189,21 +201,153 @@ CholImpl(_Tp* A, size_t astep, int m, _Tp* b, size_t bstep, int n)
             b[i*bstep + j] = (_Tp)(s*L[i*astep + i]);
         }
     }
+    for( i = 0; i < m; i++ )
+            L[i*astep + i]=1/L[i*astep + i];
 
     return true;
 }
 
-
 bool Cholesky32f(float* A, size_t astep, int m, float* b, size_t bstep, int n)
 {
+    CV_INSTRUMENT_REGION()
+
+    bool output;
+    CALL_HAL_RET(Cholesky32f, cv_hal_Cholesky32f, output, A, astep, m, b, bstep, n)
     return CholImpl(A, astep, m, b, bstep, n);
 }
 
 bool Cholesky64f(double* A, size_t astep, int m, double* b, size_t bstep, int n)
 {
+    CV_INSTRUMENT_REGION()
+
+    bool output;
+    CALL_HAL_RET(Cholesky64f, cv_hal_Cholesky64f, output, A, astep, m, b, bstep, n)
     return CholImpl(A, astep, m, b, bstep, n);
 }
 
+template<typename _Tp> inline static int
+sign(_Tp x)
+{
+    if (x >= (_Tp)0)
+        return 1;
+    else
+        return -1;
+}
+
+template<typename _Tp> static inline int
+QRImpl(_Tp* A, size_t astep, int m, int n, int k, _Tp* b, size_t bstep, _Tp* hFactors, _Tp eps)
+{
+    astep /= sizeof(_Tp);
+    bstep /= sizeof(_Tp);
+
+    cv::AutoBuffer<_Tp> buffer;
+    size_t buf_size = m ? m + n : hFactors != NULL;
+    buffer.allocate(buf_size);
+    _Tp* vl = buffer;
+    if (hFactors == NULL)
+        hFactors = vl + m;
+
+    for (int l = 0; l < n; l++)
+    {
+        //generate vl
+        int vlSize = m - l;
+        _Tp vlNorm = (_Tp)0;
+        for (int i = 0; i < vlSize; i++)
+        {
+            vl[i] = A[(l + i)*astep + l];
+            vlNorm += vl[i] * vl[i];
+        }
+        _Tp tmpV = vl[0];
+        vl[0] = vl[0] + sign(vl[0])*std::sqrt(vlNorm);
+        vlNorm = std::sqrt(vlNorm + vl[0] * vl[0] - tmpV*tmpV);
+        for (int i = 0; i < vlSize; i++)
+        {
+            vl[i] /= vlNorm;
+        }
+        //multiply A_l*vl
+        for (int j = l; j < n; j++)
+        {
+            _Tp v_lA = (_Tp)0;
+            for (int i = l; i < m; i++)
+            {
+                v_lA += vl[i - l] * A[i*astep + j];
+            }
+
+            for (int i = l; i < m; i++)
+            {
+                A[i*astep + j] -= 2 * vl[i - l] * v_lA;
+            }
+        }
+
+        //save vl and factors
+        hFactors[l] = vl[0] * vl[0];
+        for (int i = 1; i < vlSize; i++)
+        {
+            A[(l + i)*astep + l] = vl[i] / vl[0];
+        }
+    }
+
+    if (b)
+    {
+        //generate new rhs
+        for (int l = 0; l < n; l++)
+        {
+            //unpack vl
+            vl[0] = (_Tp)1;
+            for (int j = 1; j < m - l; j++)
+            {
+              vl[j] = A[(j + l)*astep + l];
+            }
+
+            //h_l*x
+            for (int j = 0; j < k; j++)
+            {
+                _Tp v_lB = (_Tp)0;
+                for (int i = l; i < m; i++)
+                  v_lB += vl[i - l] * b[i*bstep + j];
+
+                for (int i = l; i < m; i++)
+                    b[i*bstep + j] -= 2 * vl[i - l] * v_lB * hFactors[l];
+            }
+        }
+        //do back substitution
+        for (int i = n - 1; i >= 0; i--)
+        {
+            for (int j = n - 1; j > i; j--)
+            {
+                for (int p = 0; p < k; p++)
+                    b[i*bstep + p] -= b[j*bstep + p] * A[i*astep + j];
+            }
+            if (std::abs(A[i*astep + i]) < eps)
+                return 0;
+            for (int p = 0; p < k; p++)
+                b[i*bstep + p] /= A[i*astep + i];
+        }
+    }
+
+    return 1;
+}
+
+int QR32f(float* A, size_t astep, int m, int n, int k, float* b, size_t bstep, float* hFactors)
+{
+    CV_INSTRUMENT_REGION()
+
+    int output;
+    CALL_HAL_RET(QR32f, cv_hal_QR32f, output, A, astep, m, n, k, b, bstep, hFactors);
+    output = QRImpl(A, astep, m, n, k, b, bstep, hFactors, FLT_EPSILON * 10);
+    return output;
+}
+
+int QR64f(double* A, size_t astep, int m, int n, int k, double* b, size_t bstep, double* hFactors)
+{
+    CV_INSTRUMENT_REGION()
+
+    int output;
+    CALL_HAL_RET(QR64f, cv_hal_QR64f, output, A, astep, m, n, k, b, bstep, hFactors)
+    output = QRImpl(A, astep, m, n, k, b, bstep, hFactors, DBL_EPSILON * 100);
+    return output;
+}
+
 //=============================================================================
 // for compatibility with 3.0
 
diff --git a/modules/core/src/ocl.cpp b/modules/core/src/ocl.cpp
index eed4ee5..60ecc69 100644
--- a/modules/core/src/ocl.cpp
+++ b/modules/core/src/ocl.cpp
@@ -45,6 +45,9 @@
 #include <string>
 #include <sstream>
 #include <iostream> // std::cerr
+#if !(defined _MSC_VER) || (defined _MSC_VER && _MSC_VER > 1700)
+#include <inttypes.h>
+#endif
 
 #define CV_OPENCL_ALWAYS_SHOW_BUILD_LOG 0
 #define CV_OPENCL_SHOW_RUN_ERRORS       0
@@ -684,10 +687,13 @@ typedef struct _cl_buffer_region {
 
 #define CL_CALLBACK CV_STDCALL
 
-static volatile bool g_haveOpenCL = false;
+
+#ifdef HAVE_OPENCL
 static const char* oclFuncToCheck = "clEnqueueReadBufferRect";
+static volatile bool g_haveOpenCL = false;
+#endif
 
-#if defined(__APPLE__)
+#if defined(__APPLE__) && defined(HAVE_OPENCL)
 #include <dlfcn.h>
 
 static void* initOpenCLAndLoad(const char* funcname)
@@ -716,7 +722,7 @@ static void* initOpenCLAndLoad(const char* funcname)
     return funcname && handle ? dlsym(handle, funcname) : 0;
 }
 
-#elif defined WIN32 || defined _WIN32
+#elif (defined WIN32 || defined _WIN32) && defined(HAVE_OPENCL)
 
 #ifndef _WIN32_WINNT           // This is needed for the declaration of TryEnterCriticalSection in winbase.h with Visual Studio 2005 (and older?)
   #define _WIN32_WINNT 0x0400  // http://msdn.microsoft.com/en-us/library/ms686857(VS.85).aspx
@@ -751,7 +757,7 @@ static void* initOpenCLAndLoad(const char* funcname)
     return funcname ? (void*)GetProcAddress(handle, funcname) : 0;
 }
 
-#elif defined(__linux)
+#elif defined(__linux) && defined(HAVE_OPENCL)
 
 #include <dlfcn.h>
 #include <stdio.h>
@@ -3166,6 +3172,9 @@ struct Kernel::Impl
     {
         cl_program ph = (cl_program)prog.ptr();
         cl_int retval = 0;
+#ifdef ENABLE_INSTRUMENTATION
+        name = kname;
+#endif
         handle = ph != 0 ?
             clCreateKernel(ph, kname, &retval) : 0;
         CV_OclDbgAssert(retval == CL_SUCCESS);
@@ -3218,6 +3227,9 @@ struct Kernel::Impl
 
     IMPLEMENT_REFCOUNTABLE();
 
+#ifdef ENABLE_INSTRUMENTATION
+    cv::String name;
+#endif
     cl_kernel handle;
     cl_event e;
     enum { MAX_ARRS = 16 };
@@ -3438,6 +3450,8 @@ int Kernel::set(int i, const KernelArg& arg)
 bool Kernel::run(int dims, size_t _globalsize[], size_t _localsize[],
                  bool sync, const Queue& q)
 {
+    CV_INSTRUMENT_REGION_OPENCL_RUN(p->name.c_str());
+
     if(!p || !p->handle || p->e != 0)
         return false;
 
@@ -3549,6 +3563,7 @@ struct Program::Impl
     Impl(const ProgramSource& _src,
          const String& _buildflags, String& errmsg)
     {
+        CV_INSTRUMENT_REGION_OPENCL_COMPILE(cv::format("Compile: %" PRIx64 " options: %s", _src.hash(), _buildflags.c_str()).c_str());
         refcount = 1;
         const Context& ctx = Context::getDefault();
         src = _src;
@@ -6058,6 +6073,18 @@ void* Image2D::ptr() const
     return p ? p->handle : 0;
 }
 
+bool internal::isOpenCLForced()
+{
+    static bool initialized = false;
+    static bool value = false;
+    if (!initialized)
+    {
+        value = getBoolParameter("OPENCV_OPENCL_FORCE", false);
+        initialized = true;
+    }
+    return value;
+}
+
 bool internal::isPerformanceCheckBypassed()
 {
     static bool initialized = false;
diff --git a/modules/core/src/opencl/runtime/autogenerated/opencl_clamdblas_impl.hpp b/modules/core/src/opencl/runtime/autogenerated/opencl_clamdblas_impl.hpp
index 8ff3cec..9c7e4d1 100644
--- a/modules/core/src/opencl/runtime/autogenerated/opencl_clamdblas_impl.hpp
+++ b/modules/core/src/opencl/runtime/autogenerated/opencl_clamdblas_impl.hpp
@@ -182,891 +182,997 @@ enum OPENCLAMDBLAS_FN_ID {
 
 namespace {
 // generated by parser_clamdblas.py
-template <int ID, typename _R>
-struct openclamdblas_fn0
-{
-    typedef _R (*FN)();
-    static _R switch_fn()
-    { return ((FN)openclamdblas_check_fn(ID))(); }
-};
-
-template <int ID, typename _R, typename _T1>
-struct openclamdblas_fn1
-{
-    typedef _R (*FN)(_T1);
-    static _R switch_fn(_T1 p1)
-    { return ((FN)openclamdblas_check_fn(ID))(p1); }
-};
-
-template <int ID, typename _R, typename _T1, typename _T2>
-struct openclamdblas_fn2
-{
-    typedef _R (*FN)(_T1, _T2);
-    static _R switch_fn(_T1 p1, _T2 p2)
-    { return ((FN)openclamdblas_check_fn(ID))(p1, p2); }
-};
-
-template <int ID, typename _R, typename _T1, typename _T2, typename _T3>
-struct openclamdblas_fn3
-{
-    typedef _R (*FN)(_T1, _T2, _T3);
-    static _R switch_fn(_T1 p1, _T2 p2, _T3 p3)
-    { return ((FN)openclamdblas_check_fn(ID))(p1, p2, p3); }
-};
-
-template <int ID, typename _R, typename _T1, typename _T2, typename _T3, typename _T4>
-struct openclamdblas_fn4
-{
-    typedef _R (*FN)(_T1, _T2, _T3, _T4);
-    static _R switch_fn(_T1 p1, _T2 p2, _T3 p3, _T4 p4)
-    { return ((FN)openclamdblas_check_fn(ID))(p1, p2, p3, p4); }
-};
-
-template <int ID, typename _R, typename _T1, typename _T2, typename _T3, typename _T4, typename _T5>
-struct openclamdblas_fn5
-{
-    typedef _R (*FN)(_T1, _T2, _T3, _T4, _T5);
-    static _R switch_fn(_T1 p1, _T2 p2, _T3 p3, _T4 p4, _T5 p5)
-    { return ((FN)openclamdblas_check_fn(ID))(p1, p2, p3, p4, p5); }
-};
-
-template <int ID, typename _R, typename _T1, typename _T2, typename _T3, typename _T4, typename _T5, typename _T6>
-struct openclamdblas_fn6
-{
-    typedef _R (*FN)(_T1, _T2, _T3, _T4, _T5, _T6);
-    static _R switch_fn(_T1 p1, _T2 p2, _T3 p3, _T4 p4, _T5 p5, _T6 p6)
-    { return ((FN)openclamdblas_check_fn(ID))(p1, p2, p3, p4, p5, p6); }
-};
-
-template <int ID, typename _R, typename _T1, typename _T2, typename _T3, typename _T4, typename _T5, typename _T6, typename _T7>
-struct openclamdblas_fn7
-{
-    typedef _R (*FN)(_T1, _T2, _T3, _T4, _T5, _T6, _T7);
-    static _R switch_fn(_T1 p1, _T2 p2, _T3 p3, _T4 p4, _T5 p5, _T6 p6, _T7 p7)
-    { return ((FN)openclamdblas_check_fn(ID))(p1, p2, p3, p4, p5, p6, p7); }
-};
-
-template <int ID, typename _R, typename _T1, typename _T2, typename _T3, typename _T4, typename _T5, typename _T6, typename _T7, typename _T8>
-struct openclamdblas_fn8
-{
-    typedef _R (*FN)(_T1, _T2, _T3, _T4, _T5, _T6, _T7, _T8);
-    static _R switch_fn(_T1 p1, _T2 p2, _T3 p3, _T4 p4, _T5 p5, _T6 p6, _T7 p7, _T8 p8)
-    { return ((FN)openclamdblas_check_fn(ID))(p1, p2, p3, p4, p5, p6, p7, p8); }
-};
-
-template <int ID, typename _R, typename _T1, typename _T2, typename _T3, typename _T4, typename _T5, typename _T6, typename _T7, typename _T8, typename _T9>
-struct openclamdblas_fn9
-{
-    typedef _R (*FN)(_T1, _T2, _T3, _T4, _T5, _T6, _T7, _T8, _T9);
-    static _R switch_fn(_T1 p1, _T2 p2, _T3 p3, _T4 p4, _T5 p5, _T6 p6, _T7 p7, _T8 p8, _T9 p9)
-    { return ((FN)openclamdblas_check_fn(ID))(p1, p2, p3, p4, p5, p6, p7, p8, p9); }
-};
-
-template <int ID, typename _R, typename _T1, typename _T2, typename _T3, typename _T4, typename _T5, typename _T6, typename _T7, typename _T8, typename _T9, typename _T10>
-struct openclamdblas_fn10
-{
-    typedef _R (*FN)(_T1, _T2, _T3, _T4, _T5, _T6, _T7, _T8, _T9, _T10);
-    static _R switch_fn(_T1 p1, _T2 p2, _T3 p3, _T4 p4, _T5 p5, _T6 p6, _T7 p7, _T8 p8, _T9 p9, _T10 p10)
-    { return ((FN)openclamdblas_check_fn(ID))(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10); }
-};
-
-template <int ID, typename _R, typename _T1, typename _T2, typename _T3, typename _T4, typename _T5, typename _T6, typename _T7, typename _T8, typename _T9, typename _T10, typename _T11>
-struct openclamdblas_fn11
-{
-    typedef _R (*FN)(_T1, _T2, _T3, _T4, _T5, _T6, _T7, _T8, _T9, _T10, _T11);
-    static _R switch_fn(_T1 p1, _T2 p2, _T3 p3, _T4 p4, _T5 p5, _T6 p6, _T7 p7, _T8 p8, _T9 p9, _T10 p10, _T11 p11)
-    { return ((FN)openclamdblas_check_fn(ID))(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11); }
-};
-
-template <int ID, typename _R, typename _T1, typename _T2, typename _T3, typename _T4, typename _T5, typename _T6, typename _T7, typename _T8, typename _T9, typename _T10, typename _T11, typename _T12>
-struct openclamdblas_fn12
-{
-    typedef _R (*FN)(_T1, _T2, _T3, _T4, _T5, _T6, _T7, _T8, _T9, _T10, _T11, _T12);
-    static _R switch_fn(_T1 p1, _T2 p2, _T3 p3, _T4 p4, _T5 p5, _T6 p6, _T7 p7, _T8 p8, _T9 p9, _T10 p10, _T11 p11, _T12 p12)
-    { return ((FN)openclamdblas_check_fn(ID))(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12); }
-};
-
-template <int ID, typename _R, typename _T1, typename _T2, typename _T3, typename _T4, typename _T5, typename _T6, typename _T7, typename _T8, typename _T9, typename _T10, typename _T11, typename _T12, typename _T13>
-struct openclamdblas_fn13
-{
-    typedef _R (*FN)(_T1, _T2, _T3, _T4, _T5, _T6, _T7, _T8, _T9, _T10, _T11, _T12, _T13);
-    static _R switch_fn(_T1 p1, _T2 p2, _T3 p3, _T4 p4, _T5 p5, _T6 p6, _T7 p7, _T8 p8, _T9 p9, _T10 p10, _T11 p11, _T12 p12, _T13 p13)
-    { return ((FN)openclamdblas_check_fn(ID))(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13); }
-};
-
-template <int ID, typename _R, typename _T1, typename _T2, typename _T3, typename _T4, typename _T5, typename _T6, typename _T7, typename _T8, typename _T9, typename _T10, typename _T11, typename _T12, typename _T13, typename _T14>
-struct openclamdblas_fn14
-{
-    typedef _R (*FN)(_T1, _T2, _T3, _T4, _T5, _T6, _T7, _T8, _T9, _T10, _T11, _T12, _T13, _T14);
-    static _R switch_fn(_T1 p1, _T2 p2, _T3 p3, _T4 p4, _T5 p5, _T6 p6, _T7 p7, _T8 p8, _T9 p9, _T10 p10, _T11 p11, _T12 p12, _T13 p13, _T14 p14)
-    { return ((FN)openclamdblas_check_fn(ID))(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14); }
-};
-
-template <int ID, typename _R, typename _T1, typename _T2, typename _T3, typename _T4, typename _T5, typename _T6, typename _T7, typename _T8, typename _T9, typename _T10, typename _T11, typename _T12, typename _T13, typename _T14, typename _T15>
-struct openclamdblas_fn15
-{
-    typedef _R (*FN)(_T1, _T2, _T3, _T4, _T5, _T6, _T7, _T8, _T9, _T10, _T11, _T12, _T13, _T14, _T15);
-    static _R switch_fn(_T1 p1, _T2 p2, _T3 p3, _T4 p4, _T5 p5, _T6 p6, _T7 p7, _T8 p8, _T9 p9, _T10 p10, _T11 p11, _T12 p12, _T13 p13, _T14 p14, _T15 p15)
-    { return ((FN)openclamdblas_check_fn(ID))(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15); }
-};
-
-template <int ID, typename _R, typename _T1, typename _T2, typename _T3, typename _T4, typename _T5, typename _T6, typename _T7, typename _T8, typename _T9, typename _T10, typename _T11, typename _T12, typename _T13, typename _T14, typename _T15, typename _T16>
-struct openclamdblas_fn16
-{
-    typedef _R (*FN)(_T1, _T2, _T3, _T4, _T5, _T6, _T7, _T8, _T9, _T10, _T11, _T12, _T13, _T14, _T15, _T16);
-    static _R switch_fn(_T1 p1, _T2 p2, _T3 p3, _T4 p4, _T5 p5, _T6 p6, _T7 p7, _T8 p8, _T9 p9, _T10 p10, _T11 p11, _T12 p12, _T13 p13, _T14 p14, _T15 p15, _T16 p16)
-    { return ((FN)openclamdblas_check_fn(ID))(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16); }
-};
-
-template <int ID, typename _R, typename _T1, typename _T2, typename _T3, typename _T4, typename _T5, typename _T6, typename _T7, typename _T8, typename _T9, typename _T10, typename _T11, typename _T12, typename _T13, typename _T14, typename _T15, typename _T16, typename _T17>
-struct openclamdblas_fn17
-{
-    typedef _R (*FN)(_T1, _T2, _T3, _T4, _T5, _T6, _T7, _T8, _T9, _T10, _T11, _T12, _T13, _T14, _T15, _T16, _T17);
-    static _R switch_fn(_T1 p1, _T2 p2, _T3 p3, _T4 p4, _T5 p5, _T6 p6, _T7 p7, _T8 p8, _T9 p9, _T10 p10, _T11 p11, _T12 p12, _T13 p13, _T14 p14, _T15 p15, _T16 p16, _T17 p17)
-    { return ((FN)openclamdblas_check_fn(ID))(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17); }
-};
-
-template <int ID, typename _R, typename _T1, typename _T2, typename _T3, typename _T4, typename _T5, typename _T6, typename _T7, typename _T8, typename _T9, typename _T10, typename _T11, typename _T12, typename _T13, typename _T14, typename _T15, typename _T16, typename _T17, typename _T18>
-struct openclamdblas_fn18
-{
-    typedef _R (*FN)(_T1, _T2, _T3, _T4, _T5, _T6, _T7, _T8, _T9, _T10, _T11, _T12, _T13, _T14, _T15, _T16, _T17, _T18);
-    static _R switch_fn(_T1 p1, _T2 p2, _T3 p3, _T4 p4, _T5 p5, _T6 p6, _T7 p7, _T8 p8, _T9 p9, _T10 p10, _T11 p11, _T12 p12, _T13 p13, _T14 p14, _T15 p15, _T16 p16, _T17 p17, _T18 p18)
-    { return ((FN)openclamdblas_check_fn(ID))(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18); }
-};
-
-template <int ID, typename _R, typename _T1, typename _T2, typename _T3, typename _T4, typename _T5, typename _T6, typename _T7, typename _T8, typename _T9, typename _T10, typename _T11, typename _T12, typename _T13, typename _T14, typename _T15, typename _T16, typename _T17, typename _T18, typename _T19>
-struct openclamdblas_fn19
-{
-    typedef _R (*FN)(_T1, _T2, _T3, _T4, _T5, _T6, _T7, _T8, _T9, _T10, _T11, _T12, _T13, _T14, _T15, _T16, _T17, _T18, _T19);
-    static _R switch_fn(_T1 p1, _T2 p2, _T3 p3, _T4 p4, _T5 p5, _T6 p6, _T7 p7, _T8 p8, _T9 p9, _T10 p10, _T11 p11, _T12 p12, _T13 p13, _T14 p14, _T15 p15, _T16 p16, _T17 p17, _T18 p18, _T19 p19)
-    { return ((FN)openclamdblas_check_fn(ID))(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19); }
-};
-
-template <int ID, typename _R, typename _T1, typename _T2, typename _T3, typename _T4, typename _T5, typename _T6, typename _T7, typename _T8, typename _T9, typename _T10, typename _T11, typename _T12, typename _T13, typename _T14, typename _T15, typename _T16, typename _T17, typename _T18, typename _T19, typename _T20>
-struct openclamdblas_fn20
-{
-    typedef _R (*FN)(_T1, _T2, _T3, _T4, _T5, _T6, _T7, _T8, _T9, _T10, _T11, _T12, _T13, _T14, _T15, _T16, _T17, _T18, _T19, _T20);
-    static _R switch_fn(_T1 p1, _T2 p2, _T3 p3, _T4 p4, _T5 p5, _T6 p6, _T7 p7, _T8 p8, _T9 p9, _T10 p10, _T11 p11, _T12 p12, _T13 p13, _T14 p14, _T15 p15, _T16 p16, _T17 p17, _T18 p18, _T19 p19, _T20 p20)
-    { return ((FN)openclamdblas_check_fn(ID))(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20); }
-};
-
-template <int ID, typename _R, typename _T1, typename _T2, typename _T3, typename _T4, typename _T5, typename _T6, typename _T7, typename _T8, typename _T9, typename _T10, typename _T11, typename _T12, typename _T13, typename _T14, typename _T15, typename _T16, typename _T17, typename _T18, typename _T19, typename _T20, typename _T21>
-struct openclamdblas_fn21
-{
-    typedef _R (*FN)(_T1, _T2, _T3, _T4, _T5, _T6, _T7, _T8, _T9, _T10, _T11, _T12, _T13, _T14, _T15, _T16, _T17, _T18, _T19, _T20, _T21);
-    static _R switch_fn(_T1 p1, _T2 p2, _T3 p3, _T4 p4, _T5 p5, _T6 p6, _T7 p7, _T8 p8, _T9 p9, _T10 p10, _T11 p11, _T12 p12, _T13 p13, _T14 p14, _T15 p15, _T16 p16, _T17 p17, _T18 p18, _T19 p19, _T20 p20, _T21 p21)
-    { return ((FN)openclamdblas_check_fn(ID))(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, p21); }
-};
-
-template <int ID, typename _R, typename _T1, typename _T2, typename _T3, typename _T4, typename _T5, typename _T6, typename _T7, typename _T8, typename _T9, typename _T10, typename _T11, typename _T12, typename _T13, typename _T14, typename _T15, typename _T16, typename _T17, typename _T18, typename _T19, typename _T20, typename _T21, typename _T22>
-struct openclamdblas_fn22
-{
-    typedef _R (*FN)(_T1, _T2, _T3, _T4, _T5, _T6, _T7, _T8, _T9, _T10, _T11, _T12, _T13, _T14, _T15, _T16, _T17, _T18, _T19, _T20, _T21, _T22);
-    static _R switch_fn(_T1 p1, _T2 p2, _T3 p3, _T4 p4, _T5 p5, _T6 p6, _T7 p7, _T8 p8, _T9 p9, _T10 p10, _T11 p11, _T12 p12, _T13 p13, _T14 p14, _T15 p15, _T16 p16, _T17 p17, _T18 p18, _T19 p19, _T20 p20, _T21 p21, _T22 p22)
-    { return ((FN)openclamdblas_check_fn(ID))(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, p21, p22); }
-};
+#define openclamdblas_fn0(ID, _R, decl_args) \
+    typedef _R (*ID##FN)decl_args; \
+    static _R ID##_switch_fn decl_args \
+    { return ((ID##FN)openclamdblas_check_fn(ID))(); } \
+
+#define openclamdblas_fn1(ID, _R, decl_args) \
+    typedef _R (*ID##FN)decl_args; \
+    static _R ID##_switch_fn decl_args \
+    { return ((ID##FN)openclamdblas_check_fn(ID))(p1); } \
+
+#define openclamdblas_fn2(ID, _R, decl_args) \
+    typedef _R (*ID##FN)decl_args; \
+    static _R ID##_switch_fn decl_args \
+    { return ((ID##FN)openclamdblas_check_fn(ID))(p1, p2); } \
+
+#define openclamdblas_fn3(ID, _R, decl_args) \
+    typedef _R (*ID##FN)decl_args; \
+    static _R ID##_switch_fn decl_args \
+    { return ((ID##FN)openclamdblas_check_fn(ID))(p1, p2, p3); } \
+
+#define openclamdblas_fn4(ID, _R, decl_args) \
+    typedef _R (*ID##FN)decl_args; \
+    static _R ID##_switch_fn decl_args \
+    { return ((ID##FN)openclamdblas_check_fn(ID))(p1, p2, p3, p4); } \
+
+#define openclamdblas_fn5(ID, _R, decl_args) \
+    typedef _R (*ID##FN)decl_args; \
+    static _R ID##_switch_fn decl_args \
+    { return ((ID##FN)openclamdblas_check_fn(ID))(p1, p2, p3, p4, p5); } \
+
+#define openclamdblas_fn6(ID, _R, decl_args) \
+    typedef _R (*ID##FN)decl_args; \
+    static _R ID##_switch_fn decl_args \
+    { return ((ID##FN)openclamdblas_check_fn(ID))(p1, p2, p3, p4, p5, p6); } \
+
+#define openclamdblas_fn7(ID, _R, decl_args) \
+    typedef _R (*ID##FN)decl_args; \
+    static _R ID##_switch_fn decl_args \
+    { return ((ID##FN)openclamdblas_check_fn(ID))(p1, p2, p3, p4, p5, p6, p7); } \
+
+#define openclamdblas_fn8(ID, _R, decl_args) \
+    typedef _R (*ID##FN)decl_args; \
+    static _R ID##_switch_fn decl_args \
+    { return ((ID##FN)openclamdblas_check_fn(ID))(p1, p2, p3, p4, p5, p6, p7, p8); } \
+
+#define openclamdblas_fn9(ID, _R, decl_args) \
+    typedef _R (*ID##FN)decl_args; \
+    static _R ID##_switch_fn decl_args \
+    { return ((ID##FN)openclamdblas_check_fn(ID))(p1, p2, p3, p4, p5, p6, p7, p8, p9); } \
+
+#define openclamdblas_fn10(ID, _R, decl_args) \
+    typedef _R (*ID##FN)decl_args; \
+    static _R ID##_switch_fn decl_args \
+    { return ((ID##FN)openclamdblas_check_fn(ID))(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10); } \
+
+#define openclamdblas_fn11(ID, _R, decl_args) \
+    typedef _R (*ID##FN)decl_args; \
+    static _R ID##_switch_fn decl_args \
+    { return ((ID##FN)openclamdblas_check_fn(ID))(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11); } \
+
+#define openclamdblas_fn12(ID, _R, decl_args) \
+    typedef _R (*ID##FN)decl_args; \
+    static _R ID##_switch_fn decl_args \
+    { return ((ID##FN)openclamdblas_check_fn(ID))(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12); } \
+
+#define openclamdblas_fn13(ID, _R, decl_args) \
+    typedef _R (*ID##FN)decl_args; \
+    static _R ID##_switch_fn decl_args \
+    { return ((ID##FN)openclamdblas_check_fn(ID))(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13); } \
+
+#define openclamdblas_fn14(ID, _R, decl_args) \
+    typedef _R (*ID##FN)decl_args; \
+    static _R ID##_switch_fn decl_args \
+    { return ((ID##FN)openclamdblas_check_fn(ID))(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14); } \
+
+#define openclamdblas_fn15(ID, _R, decl_args) \
+    typedef _R (*ID##FN)decl_args; \
+    static _R ID##_switch_fn decl_args \
+    { return ((ID##FN)openclamdblas_check_fn(ID))(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15); } \
+
+#define openclamdblas_fn16(ID, _R, decl_args) \
+    typedef _R (*ID##FN)decl_args; \
+    static _R ID##_switch_fn decl_args \
+    { return ((ID##FN)openclamdblas_check_fn(ID))(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16); } \
+
+#define openclamdblas_fn17(ID, _R, decl_args) \
+    typedef _R (*ID##FN)decl_args; \
+    static _R ID##_switch_fn decl_args \
+    { return ((ID##FN)openclamdblas_check_fn(ID))(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17); } \
+
+#define openclamdblas_fn18(ID, _R, decl_args) \
+    typedef _R (*ID##FN)decl_args; \
+    static _R ID##_switch_fn decl_args \
+    { return ((ID##FN)openclamdblas_check_fn(ID))(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18); } \
+
+#define openclamdblas_fn19(ID, _R, decl_args) \
+    typedef _R (*ID##FN)decl_args; \
+    static _R ID##_switch_fn decl_args \
+    { return ((ID##FN)openclamdblas_check_fn(ID))(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19); } \
+
+#define openclamdblas_fn20(ID, _R, decl_args) \
+    typedef _R (*ID##FN)decl_args; \
+    static _R ID##_switch_fn decl_args \
+    { return ((ID##FN)openclamdblas_check_fn(ID))(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20); } \
+
+#define openclamdblas_fn21(ID, _R, decl_args) \
+    typedef _R (*ID##FN)decl_args; \
+    static _R ID##_switch_fn decl_args \
+    { return ((ID##FN)openclamdblas_check_fn(ID))(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, p21); } \
+
+#define openclamdblas_fn22(ID, _R, decl_args) \
+    typedef _R (*ID##FN)decl_args; \
+    static _R ID##_switch_fn decl_args \
+    { return ((ID##FN)openclamdblas_check_fn(ID))(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, p21, p22); } \
 
 }
 
 // generated by parser_clamdblas.py
+//openclamdblas_fn4(OPENCLAMDBLAS_FN_clAmdBlasAddScratchImage, cl_ulong, (cl_context p1, size_t p2, size_t p3, clAmdBlasStatus* p4))
 //cl_ulong (*clAmdBlasAddScratchImage)(cl_context, size_t, size_t, clAmdBlasStatus*) =
-//        openclamdblas_fn4<OPENCLAMDBLAS_FN_clAmdBlasAddScratchImage, cl_ulong, cl_context, size_t, size_t, clAmdBlasStatus*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasAddScratchImage_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasAddScratchImage_definition = { "clAmdBlasAddScratchImage", (void**)&clAmdBlasAddScratchImage};
 
+//openclamdblas_fn13(OPENCLAMDBLAS_FN_clAmdBlasCaxpy, clAmdBlasStatus, (size_t p1, cl_float2 p2, const cl_mem p3, size_t p4, int p5, cl_mem p6, size_t p7, int p8, cl_uint p9, cl_command_queue* p10, cl_uint p11, const cl_event* p12, cl_event* p13))
 //clAmdBlasStatus (*clAmdBlasCaxpy)(size_t, cl_float2, const cl_mem, size_t, int, cl_mem, size_t, int, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn13<OPENCLAMDBLAS_FN_clAmdBlasCaxpy, clAmdBlasStatus, size_t, cl_float2, const cl_mem, size_t, int, cl_mem, size_t, int, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasCaxpy_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasCaxpy_definition = { "clAmdBlasCaxpy", (void**)&clAmdBlasCaxpy};
 
+//openclamdblas_fn12(OPENCLAMDBLAS_FN_clAmdBlasCcopy, clAmdBlasStatus, (size_t p1, const cl_mem p2, size_t p3, int p4, cl_mem p5, size_t p6, int p7, cl_uint p8, cl_command_queue* p9, cl_uint p10, const cl_event* p11, cl_event* p12))
 //clAmdBlasStatus (*clAmdBlasCcopy)(size_t, const cl_mem, size_t, int, cl_mem, size_t, int, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn12<OPENCLAMDBLAS_FN_clAmdBlasCcopy, clAmdBlasStatus, size_t, const cl_mem, size_t, int, cl_mem, size_t, int, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasCcopy_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasCcopy_definition = { "clAmdBlasCcopy", (void**)&clAmdBlasCcopy};
 
+//openclamdblas_fn15(OPENCLAMDBLAS_FN_clAmdBlasCdotc, clAmdBlasStatus, (size_t p1, cl_mem p2, size_t p3, const cl_mem p4, size_t p5, int p6, const cl_mem p7, size_t p8, int p9, cl_mem p10, cl_uint p11, cl_command_queue* p12, cl_uint p13, const cl_event* p14, cl_event* p15))
 //clAmdBlasStatus (*clAmdBlasCdotc)(size_t, cl_mem, size_t, const cl_mem, size_t, int, const cl_mem, size_t, int, cl_mem, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn15<OPENCLAMDBLAS_FN_clAmdBlasCdotc, clAmdBlasStatus, size_t, cl_mem, size_t, const cl_mem, size_t, int, const cl_mem, size_t, int, cl_mem, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasCdotc_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasCdotc_definition = { "clAmdBlasCdotc", (void**)&clAmdBlasCdotc};
 
+//openclamdblas_fn15(OPENCLAMDBLAS_FN_clAmdBlasCdotu, clAmdBlasStatus, (size_t p1, cl_mem p2, size_t p3, const cl_mem p4, size_t p5, int p6, const cl_mem p7, size_t p8, int p9, cl_mem p10, cl_uint p11, cl_command_queue* p12, cl_uint p13, const cl_event* p14, cl_event* p15))
 //clAmdBlasStatus (*clAmdBlasCdotu)(size_t, cl_mem, size_t, const cl_mem, size_t, int, const cl_mem, size_t, int, cl_mem, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn15<OPENCLAMDBLAS_FN_clAmdBlasCdotu, clAmdBlasStatus, size_t, cl_mem, size_t, const cl_mem, size_t, int, const cl_mem, size_t, int, cl_mem, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasCdotu_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasCdotu_definition = { "clAmdBlasCdotu", (void**)&clAmdBlasCdotu};
 
+//openclamdblas_fn22(OPENCLAMDBLAS_FN_clAmdBlasCgbmv, clAmdBlasStatus, (clAmdBlasOrder p1, clAmdBlasTranspose p2, size_t p3, size_t p4, size_t p5, size_t p6, cl_float2 p7, const cl_mem p8, size_t p9, size_t p10, const cl_mem p11, size_t p12, int p13, cl_float2 p14, cl_mem p15, size_t p16, int p17, cl_uint p18, cl_command_queue* p19, cl_uint p20, const cl_event* p21, cl_event* p22))
 //clAmdBlasStatus (*clAmdBlasCgbmv)(clAmdBlasOrder, clAmdBlasTranspose, size_t, size_t, size_t, size_t, cl_float2, const cl_mem, size_t, size_t, const cl_mem, size_t, int, cl_float2, cl_mem, size_t, int, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn22<OPENCLAMDBLAS_FN_clAmdBlasCgbmv, clAmdBlasStatus, clAmdBlasOrder, clAmdBlasTranspose, size_t, size_t, size_t, size_t, cl_float2, const cl_mem, size_t, size_t, const cl_mem, size_t, int, cl_float2, cl_mem, size_t, int, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasCgbmv_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasCgbmv_definition = { "clAmdBlasCgbmv", (void**)&clAmdBlasCgbmv};
 
+//openclamdblas_fn19(OPENCLAMDBLAS_FN_clAmdBlasCgemm, clAmdBlasStatus, (clAmdBlasOrder p1, clAmdBlasTranspose p2, clAmdBlasTranspose p3, size_t p4, size_t p5, size_t p6, FloatComplex p7, const cl_mem p8, size_t p9, const cl_mem p10, size_t p11, FloatComplex p12, cl_mem p13, size_t p14, cl_uint p15, cl_command_queue* p16, cl_uint p17, const cl_event* p18, cl_event* p19))
 //clAmdBlasStatus (*clAmdBlasCgemm)(clAmdBlasOrder, clAmdBlasTranspose, clAmdBlasTranspose, size_t, size_t, size_t, FloatComplex, const cl_mem, size_t, const cl_mem, size_t, FloatComplex, cl_mem, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn19<OPENCLAMDBLAS_FN_clAmdBlasCgemm, clAmdBlasStatus, clAmdBlasOrder, clAmdBlasTranspose, clAmdBlasTranspose, size_t, size_t, size_t, FloatComplex, const cl_mem, size_t, const cl_mem, size_t, FloatComplex, cl_mem, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasCgemm_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasCgemm_definition = { "clAmdBlasCgemm", (void**)&clAmdBlasCgemm};
 
+openclamdblas_fn22(OPENCLAMDBLAS_FN_clAmdBlasCgemmEx, clAmdBlasStatus, (clAmdBlasOrder p1, clAmdBlasTranspose p2, clAmdBlasTranspose p3, size_t p4, size_t p5, size_t p6, FloatComplex p7, const cl_mem p8, size_t p9, size_t p10, const cl_mem p11, size_t p12, size_t p13, FloatComplex p14, cl_mem p15, size_t p16, size_t p17, cl_uint p18, cl_command_queue* p19, cl_uint p20, const cl_event* p21, cl_event* p22))
 clAmdBlasStatus (*clAmdBlasCgemmEx)(clAmdBlasOrder, clAmdBlasTranspose, clAmdBlasTranspose, size_t, size_t, size_t, FloatComplex, const cl_mem, size_t, size_t, const cl_mem, size_t, size_t, FloatComplex, cl_mem, size_t, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-        openclamdblas_fn22<OPENCLAMDBLAS_FN_clAmdBlasCgemmEx, clAmdBlasStatus, clAmdBlasOrder, clAmdBlasTranspose, clAmdBlasTranspose, size_t, size_t, size_t, FloatComplex, const cl_mem, size_t, size_t, const cl_mem, size_t, size_t, FloatComplex, cl_mem, size_t, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+        OPENCLAMDBLAS_FN_clAmdBlasCgemmEx_switch_fn;
 static const struct DynamicFnEntry clAmdBlasCgemmEx_definition = { "clAmdBlasCgemmEx", (void**)&clAmdBlasCgemmEx};
 
+//openclamdblas_fn19(OPENCLAMDBLAS_FN_clAmdBlasCgemv, clAmdBlasStatus, (clAmdBlasOrder p1, clAmdBlasTranspose p2, size_t p3, size_t p4, FloatComplex p5, const cl_mem p6, size_t p7, const cl_mem p8, size_t p9, int p10, FloatComplex p11, cl_mem p12, size_t p13, int p14, cl_uint p15, cl_command_queue* p16, cl_uint p17, const cl_event* p18, cl_event* p19))
 //clAmdBlasStatus (*clAmdBlasCgemv)(clAmdBlasOrder, clAmdBlasTranspose, size_t, size_t, FloatComplex, const cl_mem, size_t, const cl_mem, size_t, int, FloatComplex, cl_mem, size_t, int, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn19<OPENCLAMDBLAS_FN_clAmdBlasCgemv, clAmdBlasStatus, clAmdBlasOrder, clAmdBlasTranspose, size_t, size_t, FloatComplex, const cl_mem, size_t, const cl_mem, size_t, int, FloatComplex, cl_mem, size_t, int, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasCgemv_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasCgemv_definition = { "clAmdBlasCgemv", (void**)&clAmdBlasCgemv};
 
+//openclamdblas_fn20(OPENCLAMDBLAS_FN_clAmdBlasCgemvEx, clAmdBlasStatus, (clAmdBlasOrder p1, clAmdBlasTranspose p2, size_t p3, size_t p4, FloatComplex p5, const cl_mem p6, size_t p7, size_t p8, const cl_mem p9, size_t p10, int p11, FloatComplex p12, cl_mem p13, size_t p14, int p15, cl_uint p16, cl_command_queue* p17, cl_uint p18, const cl_event* p19, cl_event* p20))
 //clAmdBlasStatus (*clAmdBlasCgemvEx)(clAmdBlasOrder, clAmdBlasTranspose, size_t, size_t, FloatComplex, const cl_mem, size_t, size_t, const cl_mem, size_t, int, FloatComplex, cl_mem, size_t, int, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn20<OPENCLAMDBLAS_FN_clAmdBlasCgemvEx, clAmdBlasStatus, clAmdBlasOrder, clAmdBlasTranspose, size_t, size_t, FloatComplex, const cl_mem, size_t, size_t, const cl_mem, size_t, int, FloatComplex, cl_mem, size_t, int, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasCgemvEx_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasCgemvEx_definition = { "clAmdBlasCgemvEx", (void**)&clAmdBlasCgemvEx};
 
+//openclamdblas_fn18(OPENCLAMDBLAS_FN_clAmdBlasCgerc, clAmdBlasStatus, (clAmdBlasOrder p1, size_t p2, size_t p3, cl_float2 p4, const cl_mem p5, size_t p6, int p7, const cl_mem p8, size_t p9, int p10, cl_mem p11, size_t p12, size_t p13, cl_uint p14, cl_command_queue* p15, cl_uint p16, const cl_event* p17, cl_event* p18))
 //clAmdBlasStatus (*clAmdBlasCgerc)(clAmdBlasOrder, size_t, size_t, cl_float2, const cl_mem, size_t, int, const cl_mem, size_t, int, cl_mem, size_t, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn18<OPENCLAMDBLAS_FN_clAmdBlasCgerc, clAmdBlasStatus, clAmdBlasOrder, size_t, size_t, cl_float2, const cl_mem, size_t, int, const cl_mem, size_t, int, cl_mem, size_t, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasCgerc_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasCgerc_definition = { "clAmdBlasCgerc", (void**)&clAmdBlasCgerc};
 
+//openclamdblas_fn18(OPENCLAMDBLAS_FN_clAmdBlasCgeru, clAmdBlasStatus, (clAmdBlasOrder p1, size_t p2, size_t p3, cl_float2 p4, const cl_mem p5, size_t p6, int p7, const cl_mem p8, size_t p9, int p10, cl_mem p11, size_t p12, size_t p13, cl_uint p14, cl_command_queue* p15, cl_uint p16, const cl_event* p17, cl_event* p18))
 //clAmdBlasStatus (*clAmdBlasCgeru)(clAmdBlasOrder, size_t, size_t, cl_float2, const cl_mem, size_t, int, const cl_mem, size_t, int, cl_mem, size_t, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn18<OPENCLAMDBLAS_FN_clAmdBlasCgeru, clAmdBlasStatus, clAmdBlasOrder, size_t, size_t, cl_float2, const cl_mem, size_t, int, const cl_mem, size_t, int, cl_mem, size_t, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasCgeru_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasCgeru_definition = { "clAmdBlasCgeru", (void**)&clAmdBlasCgeru};
 
+//openclamdblas_fn20(OPENCLAMDBLAS_FN_clAmdBlasChbmv, clAmdBlasStatus, (clAmdBlasOrder p1, clAmdBlasUplo p2, size_t p3, size_t p4, cl_float2 p5, const cl_mem p6, size_t p7, size_t p8, const cl_mem p9, size_t p10, int p11, cl_float2 p12, cl_mem p13, size_t p14, int p15, cl_uint p16, cl_command_queue* p17, cl_uint p18, const cl_event* p19, cl_event* p20))
 //clAmdBlasStatus (*clAmdBlasChbmv)(clAmdBlasOrder, clAmdBlasUplo, size_t, size_t, cl_float2, const cl_mem, size_t, size_t, const cl_mem, size_t, int, cl_float2, cl_mem, size_t, int, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn20<OPENCLAMDBLAS_FN_clAmdBlasChbmv, clAmdBlasStatus, clAmdBlasOrder, clAmdBlasUplo, size_t, size_t, cl_float2, const cl_mem, size_t, size_t, const cl_mem, size_t, int, cl_float2, cl_mem, size_t, int, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasChbmv_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasChbmv_definition = { "clAmdBlasChbmv", (void**)&clAmdBlasChbmv};
 
+//openclamdblas_fn21(OPENCLAMDBLAS_FN_clAmdBlasChemm, clAmdBlasStatus, (clAmdBlasOrder p1, clAmdBlasSide p2, clAmdBlasUplo p3, size_t p4, size_t p5, cl_float2 p6, const cl_mem p7, size_t p8, size_t p9, const cl_mem p10, size_t p11, size_t p12, cl_float2 p13, cl_mem p14, size_t p15, size_t p16, cl_uint p17, cl_command_queue* p18, cl_uint p19, const cl_event* p20, cl_event* p21))
 //clAmdBlasStatus (*clAmdBlasChemm)(clAmdBlasOrder, clAmdBlasSide, clAmdBlasUplo, size_t, size_t, cl_float2, const cl_mem, size_t, size_t, const cl_mem, size_t, size_t, cl_float2, cl_mem, size_t, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn21<OPENCLAMDBLAS_FN_clAmdBlasChemm, clAmdBlasStatus, clAmdBlasOrder, clAmdBlasSide, clAmdBlasUplo, size_t, size_t, cl_float2, const cl_mem, size_t, size_t, const cl_mem, size_t, size_t, cl_float2, cl_mem, size_t, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasChemm_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasChemm_definition = { "clAmdBlasChemm", (void**)&clAmdBlasChemm};
 
+//openclamdblas_fn19(OPENCLAMDBLAS_FN_clAmdBlasChemv, clAmdBlasStatus, (clAmdBlasOrder p1, clAmdBlasUplo p2, size_t p3, FloatComplex p4, const cl_mem p5, size_t p6, size_t p7, const cl_mem p8, size_t p9, int p10, FloatComplex p11, cl_mem p12, size_t p13, int p14, cl_uint p15, cl_command_queue* p16, cl_uint p17, const cl_event* p18, cl_event* p19))
 //clAmdBlasStatus (*clAmdBlasChemv)(clAmdBlasOrder, clAmdBlasUplo, size_t, FloatComplex, const cl_mem, size_t, size_t, const cl_mem, size_t, int, FloatComplex, cl_mem, size_t, int, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn19<OPENCLAMDBLAS_FN_clAmdBlasChemv, clAmdBlasStatus, clAmdBlasOrder, clAmdBlasUplo, size_t, FloatComplex, const cl_mem, size_t, size_t, const cl_mem, size_t, int, FloatComplex, cl_mem, size_t, int, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasChemv_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasChemv_definition = { "clAmdBlasChemv", (void**)&clAmdBlasChemv};
 
+//openclamdblas_fn15(OPENCLAMDBLAS_FN_clAmdBlasCher, clAmdBlasStatus, (clAmdBlasOrder p1, clAmdBlasUplo p2, size_t p3, cl_float p4, const cl_mem p5, size_t p6, int p7, cl_mem p8, size_t p9, size_t p10, cl_uint p11, cl_command_queue* p12, cl_uint p13, const cl_event* p14, cl_event* p15))
 //clAmdBlasStatus (*clAmdBlasCher)(clAmdBlasOrder, clAmdBlasUplo, size_t, cl_float, const cl_mem, size_t, int, cl_mem, size_t, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn15<OPENCLAMDBLAS_FN_clAmdBlasCher, clAmdBlasStatus, clAmdBlasOrder, clAmdBlasUplo, size_t, cl_float, const cl_mem, size_t, int, cl_mem, size_t, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasCher_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasCher_definition = { "clAmdBlasCher", (void**)&clAmdBlasCher};
 
+//openclamdblas_fn18(OPENCLAMDBLAS_FN_clAmdBlasCher2, clAmdBlasStatus, (clAmdBlasOrder p1, clAmdBlasUplo p2, size_t p3, cl_float2 p4, const cl_mem p5, size_t p6, int p7, const cl_mem p8, size_t p9, int p10, cl_mem p11, size_t p12, size_t p13, cl_uint p14, cl_command_queue* p15, cl_uint p16, const cl_event* p17, cl_event* p18))
 //clAmdBlasStatus (*clAmdBlasCher2)(clAmdBlasOrder, clAmdBlasUplo, size_t, cl_float2, const cl_mem, size_t, int, const cl_mem, size_t, int, cl_mem, size_t, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn18<OPENCLAMDBLAS_FN_clAmdBlasCher2, clAmdBlasStatus, clAmdBlasOrder, clAmdBlasUplo, size_t, cl_float2, const cl_mem, size_t, int, const cl_mem, size_t, int, cl_mem, size_t, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasCher2_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasCher2_definition = { "clAmdBlasCher2", (void**)&clAmdBlasCher2};
 
+//openclamdblas_fn21(OPENCLAMDBLAS_FN_clAmdBlasCher2k, clAmdBlasStatus, (clAmdBlasOrder p1, clAmdBlasUplo p2, clAmdBlasTranspose p3, size_t p4, size_t p5, FloatComplex p6, const cl_mem p7, size_t p8, size_t p9, const cl_mem p10, size_t p11, size_t p12, cl_float p13, cl_mem p14, size_t p15, size_t p16, cl_uint p17, cl_command_queue* p18, cl_uint p19, const cl_event* p20, cl_event* p21))
 //clAmdBlasStatus (*clAmdBlasCher2k)(clAmdBlasOrder, clAmdBlasUplo, clAmdBlasTranspose, size_t, size_t, FloatComplex, const cl_mem, size_t, size_t, const cl_mem, size_t, size_t, cl_float, cl_mem, size_t, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn21<OPENCLAMDBLAS_FN_clAmdBlasCher2k, clAmdBlasStatus, clAmdBlasOrder, clAmdBlasUplo, clAmdBlasTranspose, size_t, size_t, FloatComplex, const cl_mem, size_t, size_t, const cl_mem, size_t, size_t, cl_float, cl_mem, size_t, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasCher2k_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasCher2k_definition = { "clAmdBlasCher2k", (void**)&clAmdBlasCher2k};
 
+//openclamdblas_fn18(OPENCLAMDBLAS_FN_clAmdBlasCherk, clAmdBlasStatus, (clAmdBlasOrder p1, clAmdBlasUplo p2, clAmdBlasTranspose p3, size_t p4, size_t p5, float p6, const cl_mem p7, size_t p8, size_t p9, float p10, cl_mem p11, size_t p12, size_t p13, cl_uint p14, cl_command_queue* p15, cl_uint p16, const cl_event* p17, cl_event* p18))
 //clAmdBlasStatus (*clAmdBlasCherk)(clAmdBlasOrder, clAmdBlasUplo, clAmdBlasTranspose, size_t, size_t, float, const cl_mem, size_t, size_t, float, cl_mem, size_t, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn18<OPENCLAMDBLAS_FN_clAmdBlasCherk, clAmdBlasStatus, clAmdBlasOrder, clAmdBlasUplo, clAmdBlasTranspose, size_t, size_t, float, const cl_mem, size_t, size_t, float, cl_mem, size_t, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasCherk_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasCherk_definition = { "clAmdBlasCherk", (void**)&clAmdBlasCherk};
 
+//openclamdblas_fn18(OPENCLAMDBLAS_FN_clAmdBlasChpmv, clAmdBlasStatus, (clAmdBlasOrder p1, clAmdBlasUplo p2, size_t p3, cl_float2 p4, const cl_mem p5, size_t p6, const cl_mem p7, size_t p8, int p9, cl_float2 p10, cl_mem p11, size_t p12, int p13, cl_uint p14, cl_command_queue* p15, cl_uint p16, const cl_event* p17, cl_event* p18))
 //clAmdBlasStatus (*clAmdBlasChpmv)(clAmdBlasOrder, clAmdBlasUplo, size_t, cl_float2, const cl_mem, size_t, const cl_mem, size_t, int, cl_float2, cl_mem, size_t, int, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn18<OPENCLAMDBLAS_FN_clAmdBlasChpmv, clAmdBlasStatus, clAmdBlasOrder, clAmdBlasUplo, size_t, cl_float2, const cl_mem, size_t, const cl_mem, size_t, int, cl_float2, cl_mem, size_t, int, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasChpmv_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasChpmv_definition = { "clAmdBlasChpmv", (void**)&clAmdBlasChpmv};
 
+//openclamdblas_fn14(OPENCLAMDBLAS_FN_clAmdBlasChpr, clAmdBlasStatus, (clAmdBlasOrder p1, clAmdBlasUplo p2, size_t p3, cl_float p4, const cl_mem p5, size_t p6, int p7, cl_mem p8, size_t p9, cl_uint p10, cl_command_queue* p11, cl_uint p12, const cl_event* p13, cl_event* p14))
 //clAmdBlasStatus (*clAmdBlasChpr)(clAmdBlasOrder, clAmdBlasUplo, size_t, cl_float, const cl_mem, size_t, int, cl_mem, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn14<OPENCLAMDBLAS_FN_clAmdBlasChpr, clAmdBlasStatus, clAmdBlasOrder, clAmdBlasUplo, size_t, cl_float, const cl_mem, size_t, int, cl_mem, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasChpr_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasChpr_definition = { "clAmdBlasChpr", (void**)&clAmdBlasChpr};
 
+//openclamdblas_fn17(OPENCLAMDBLAS_FN_clAmdBlasChpr2, clAmdBlasStatus, (clAmdBlasOrder p1, clAmdBlasUplo p2, size_t p3, cl_float2 p4, const cl_mem p5, size_t p6, int p7, const cl_mem p8, size_t p9, int p10, cl_mem p11, size_t p12, cl_uint p13, cl_command_queue* p14, cl_uint p15, const cl_event* p16, cl_event* p17))
 //clAmdBlasStatus (*clAmdBlasChpr2)(clAmdBlasOrder, clAmdBlasUplo, size_t, cl_float2, const cl_mem, size_t, int, const cl_mem, size_t, int, cl_mem, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn17<OPENCLAMDBLAS_FN_clAmdBlasChpr2, clAmdBlasStatus, clAmdBlasOrder, clAmdBlasUplo, size_t, cl_float2, const cl_mem, size_t, int, const cl_mem, size_t, int, cl_mem, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasChpr2_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasChpr2_definition = { "clAmdBlasChpr2", (void**)&clAmdBlasChpr2};
 
+//openclamdblas_fn13(OPENCLAMDBLAS_FN_clAmdBlasCrotg, clAmdBlasStatus, (cl_mem p1, size_t p2, cl_mem p3, size_t p4, cl_mem p5, size_t p6, cl_mem p7, size_t p8, cl_uint p9, cl_command_queue* p10, cl_uint p11, const cl_event* p12, cl_event* p13))
 //clAmdBlasStatus (*clAmdBlasCrotg)(cl_mem, size_t, cl_mem, size_t, cl_mem, size_t, cl_mem, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn13<OPENCLAMDBLAS_FN_clAmdBlasCrotg, clAmdBlasStatus, cl_mem, size_t, cl_mem, size_t, cl_mem, size_t, cl_mem, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasCrotg_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasCrotg_definition = { "clAmdBlasCrotg", (void**)&clAmdBlasCrotg};
 
+//openclamdblas_fn10(OPENCLAMDBLAS_FN_clAmdBlasCscal, clAmdBlasStatus, (size_t p1, cl_float2 p2, cl_mem p3, size_t p4, int p5, cl_uint p6, cl_command_queue* p7, cl_uint p8, const cl_event* p9, cl_event* p10))
 //clAmdBlasStatus (*clAmdBlasCscal)(size_t, cl_float2, cl_mem, size_t, int, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn10<OPENCLAMDBLAS_FN_clAmdBlasCscal, clAmdBlasStatus, size_t, cl_float2, cl_mem, size_t, int, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasCscal_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasCscal_definition = { "clAmdBlasCscal", (void**)&clAmdBlasCscal};
 
+//openclamdblas_fn14(OPENCLAMDBLAS_FN_clAmdBlasCsrot, clAmdBlasStatus, (size_t p1, cl_mem p2, size_t p3, int p4, cl_mem p5, size_t p6, int p7, cl_float p8, cl_float p9, cl_uint p10, cl_command_queue* p11, cl_uint p12, const cl_event* p13, cl_event* p14))
 //clAmdBlasStatus (*clAmdBlasCsrot)(size_t, cl_mem, size_t, int, cl_mem, size_t, int, cl_float, cl_float, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn14<OPENCLAMDBLAS_FN_clAmdBlasCsrot, clAmdBlasStatus, size_t, cl_mem, size_t, int, cl_mem, size_t, int, cl_float, cl_float, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasCsrot_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasCsrot_definition = { "clAmdBlasCsrot", (void**)&clAmdBlasCsrot};
 
+//openclamdblas_fn10(OPENCLAMDBLAS_FN_clAmdBlasCsscal, clAmdBlasStatus, (size_t p1, cl_float p2, cl_mem p3, size_t p4, int p5, cl_uint p6, cl_command_queue* p7, cl_uint p8, const cl_event* p9, cl_event* p10))
 //clAmdBlasStatus (*clAmdBlasCsscal)(size_t, cl_float, cl_mem, size_t, int, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn10<OPENCLAMDBLAS_FN_clAmdBlasCsscal, clAmdBlasStatus, size_t, cl_float, cl_mem, size_t, int, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasCsscal_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasCsscal_definition = { "clAmdBlasCsscal", (void**)&clAmdBlasCsscal};
 
+//openclamdblas_fn12(OPENCLAMDBLAS_FN_clAmdBlasCswap, clAmdBlasStatus, (size_t p1, cl_mem p2, size_t p3, int p4, cl_mem p5, size_t p6, int p7, cl_uint p8, cl_command_queue* p9, cl_uint p10, const cl_event* p11, cl_event* p12))
 //clAmdBlasStatus (*clAmdBlasCswap)(size_t, cl_mem, size_t, int, cl_mem, size_t, int, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn12<OPENCLAMDBLAS_FN_clAmdBlasCswap, clAmdBlasStatus, size_t, cl_mem, size_t, int, cl_mem, size_t, int, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasCswap_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasCswap_definition = { "clAmdBlasCswap", (void**)&clAmdBlasCswap};
 
+//openclamdblas_fn21(OPENCLAMDBLAS_FN_clAmdBlasCsymm, clAmdBlasStatus, (clAmdBlasOrder p1, clAmdBlasSide p2, clAmdBlasUplo p3, size_t p4, size_t p5, cl_float2 p6, const cl_mem p7, size_t p8, size_t p9, const cl_mem p10, size_t p11, size_t p12, cl_float2 p13, cl_mem p14, size_t p15, size_t p16, cl_uint p17, cl_command_queue* p18, cl_uint p19, const cl_event* p20, cl_event* p21))
 //clAmdBlasStatus (*clAmdBlasCsymm)(clAmdBlasOrder, clAmdBlasSide, clAmdBlasUplo, size_t, size_t, cl_float2, const cl_mem, size_t, size_t, const cl_mem, size_t, size_t, cl_float2, cl_mem, size_t, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn21<OPENCLAMDBLAS_FN_clAmdBlasCsymm, clAmdBlasStatus, clAmdBlasOrder, clAmdBlasSide, clAmdBlasUplo, size_t, size_t, cl_float2, const cl_mem, size_t, size_t, const cl_mem, size_t, size_t, cl_float2, cl_mem, size_t, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasCsymm_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasCsymm_definition = { "clAmdBlasCsymm", (void**)&clAmdBlasCsymm};
 
+//openclamdblas_fn18(OPENCLAMDBLAS_FN_clAmdBlasCsyr2k, clAmdBlasStatus, (clAmdBlasOrder p1, clAmdBlasUplo p2, clAmdBlasTranspose p3, size_t p4, size_t p5, FloatComplex p6, const cl_mem p7, size_t p8, const cl_mem p9, size_t p10, FloatComplex p11, cl_mem p12, size_t p13, cl_uint p14, cl_command_queue* p15, cl_uint p16, const cl_event* p17, cl_event* p18))
 //clAmdBlasStatus (*clAmdBlasCsyr2k)(clAmdBlasOrder, clAmdBlasUplo, clAmdBlasTranspose, size_t, size_t, FloatComplex, const cl_mem, size_t, const cl_mem, size_t, FloatComplex, cl_mem, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn18<OPENCLAMDBLAS_FN_clAmdBlasCsyr2k, clAmdBlasStatus, clAmdBlasOrder, clAmdBlasUplo, clAmdBlasTranspose, size_t, size_t, FloatComplex, const cl_mem, size_t, const cl_mem, size_t, FloatComplex, cl_mem, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasCsyr2k_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasCsyr2k_definition = { "clAmdBlasCsyr2k", (void**)&clAmdBlasCsyr2k};
 
+//openclamdblas_fn21(OPENCLAMDBLAS_FN_clAmdBlasCsyr2kEx, clAmdBlasStatus, (clAmdBlasOrder p1, clAmdBlasUplo p2, clAmdBlasTranspose p3, size_t p4, size_t p5, FloatComplex p6, const cl_mem p7, size_t p8, size_t p9, const cl_mem p10, size_t p11, size_t p12, FloatComplex p13, cl_mem p14, size_t p15, size_t p16, cl_uint p17, cl_command_queue* p18, cl_uint p19, const cl_event* p20, cl_event* p21))
 //clAmdBlasStatus (*clAmdBlasCsyr2kEx)(clAmdBlasOrder, clAmdBlasUplo, clAmdBlasTranspose, size_t, size_t, FloatComplex, const cl_mem, size_t, size_t, const cl_mem, size_t, size_t, FloatComplex, cl_mem, size_t, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn21<OPENCLAMDBLAS_FN_clAmdBlasCsyr2kEx, clAmdBlasStatus, clAmdBlasOrder, clAmdBlasUplo, clAmdBlasTranspose, size_t, size_t, FloatComplex, const cl_mem, size_t, size_t, const cl_mem, size_t, size_t, FloatComplex, cl_mem, size_t, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasCsyr2kEx_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasCsyr2kEx_definition = { "clAmdBlasCsyr2kEx", (void**)&clAmdBlasCsyr2kEx};
 
+//openclamdblas_fn16(OPENCLAMDBLAS_FN_clAmdBlasCsyrk, clAmdBlasStatus, (clAmdBlasOrder p1, clAmdBlasUplo p2, clAmdBlasTranspose p3, size_t p4, size_t p5, FloatComplex p6, const cl_mem p7, size_t p8, FloatComplex p9, cl_mem p10, size_t p11, cl_uint p12, cl_command_queue* p13, cl_uint p14, const cl_event* p15, cl_event* p16))
 //clAmdBlasStatus (*clAmdBlasCsyrk)(clAmdBlasOrder, clAmdBlasUplo, clAmdBlasTranspose, size_t, size_t, FloatComplex, const cl_mem, size_t, FloatComplex, cl_mem, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn16<OPENCLAMDBLAS_FN_clAmdBlasCsyrk, clAmdBlasStatus, clAmdBlasOrder, clAmdBlasUplo, clAmdBlasTranspose, size_t, size_t, FloatComplex, const cl_mem, size_t, FloatComplex, cl_mem, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasCsyrk_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasCsyrk_definition = { "clAmdBlasCsyrk", (void**)&clAmdBlasCsyrk};
 
+//openclamdblas_fn18(OPENCLAMDBLAS_FN_clAmdBlasCsyrkEx, clAmdBlasStatus, (clAmdBlasOrder p1, clAmdBlasUplo p2, clAmdBlasTranspose p3, size_t p4, size_t p5, FloatComplex p6, const cl_mem p7, size_t p8, size_t p9, FloatComplex p10, cl_mem p11, size_t p12, size_t p13, cl_uint p14, cl_command_queue* p15, cl_uint p16, const cl_event* p17, cl_event* p18))
 //clAmdBlasStatus (*clAmdBlasCsyrkEx)(clAmdBlasOrder, clAmdBlasUplo, clAmdBlasTranspose, size_t, size_t, FloatComplex, const cl_mem, size_t, size_t, FloatComplex, cl_mem, size_t, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn18<OPENCLAMDBLAS_FN_clAmdBlasCsyrkEx, clAmdBlasStatus, clAmdBlasOrder, clAmdBlasUplo, clAmdBlasTranspose, size_t, size_t, FloatComplex, const cl_mem, size_t, size_t, FloatComplex, cl_mem, size_t, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasCsyrkEx_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasCsyrkEx_definition = { "clAmdBlasCsyrkEx", (void**)&clAmdBlasCsyrkEx};
 
+//openclamdblas_fn18(OPENCLAMDBLAS_FN_clAmdBlasCtbmv, clAmdBlasStatus, (clAmdBlasOrder p1, clAmdBlasUplo p2, clAmdBlasTranspose p3, clAmdBlasDiag p4, size_t p5, size_t p6, const cl_mem p7, size_t p8, size_t p9, cl_mem p10, size_t p11, int p12, cl_mem p13, cl_uint p14, cl_command_queue* p15, cl_uint p16, const cl_event* p17, cl_event* p18))
 //clAmdBlasStatus (*clAmdBlasCtbmv)(clAmdBlasOrder, clAmdBlasUplo, clAmdBlasTranspose, clAmdBlasDiag, size_t, size_t, const cl_mem, size_t, size_t, cl_mem, size_t, int, cl_mem, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn18<OPENCLAMDBLAS_FN_clAmdBlasCtbmv, clAmdBlasStatus, clAmdBlasOrder, clAmdBlasUplo, clAmdBlasTranspose, clAmdBlasDiag, size_t, size_t, const cl_mem, size_t, size_t, cl_mem, size_t, int, cl_mem, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasCtbmv_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasCtbmv_definition = { "clAmdBlasCtbmv", (void**)&clAmdBlasCtbmv};
 
+//openclamdblas_fn17(OPENCLAMDBLAS_FN_clAmdBlasCtbsv, clAmdBlasStatus, (clAmdBlasOrder p1, clAmdBlasUplo p2, clAmdBlasTranspose p3, clAmdBlasDiag p4, size_t p5, size_t p6, const cl_mem p7, size_t p8, size_t p9, cl_mem p10, size_t p11, int p12, cl_uint p13, cl_command_queue* p14, cl_uint p15, const cl_event* p16, cl_event* p17))
 //clAmdBlasStatus (*clAmdBlasCtbsv)(clAmdBlasOrder, clAmdBlasUplo, clAmdBlasTranspose, clAmdBlasDiag, size_t, size_t, const cl_mem, size_t, size_t, cl_mem, size_t, int, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn17<OPENCLAMDBLAS_FN_clAmdBlasCtbsv, clAmdBlasStatus, clAmdBlasOrder, clAmdBlasUplo, clAmdBlasTranspose, clAmdBlasDiag, size_t, size_t, const cl_mem, size_t, size_t, cl_mem, size_t, int, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasCtbsv_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasCtbsv_definition = { "clAmdBlasCtbsv", (void**)&clAmdBlasCtbsv};
 
+//openclamdblas_fn16(OPENCLAMDBLAS_FN_clAmdBlasCtpmv, clAmdBlasStatus, (clAmdBlasOrder p1, clAmdBlasUplo p2, clAmdBlasTranspose p3, clAmdBlasDiag p4, size_t p5, const cl_mem p6, size_t p7, cl_mem p8, size_t p9, int p10, cl_mem p11, cl_uint p12, cl_command_queue* p13, cl_uint p14, const cl_event* p15, cl_event* p16))
 //clAmdBlasStatus (*clAmdBlasCtpmv)(clAmdBlasOrder, clAmdBlasUplo, clAmdBlasTranspose, clAmdBlasDiag, size_t, const cl_mem, size_t, cl_mem, size_t, int, cl_mem, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn16<OPENCLAMDBLAS_FN_clAmdBlasCtpmv, clAmdBlasStatus, clAmdBlasOrder, clAmdBlasUplo, clAmdBlasTranspose, clAmdBlasDiag, size_t, const cl_mem, size_t, cl_mem, size_t, int, cl_mem, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasCtpmv_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasCtpmv_definition = { "clAmdBlasCtpmv", (void**)&clAmdBlasCtpmv};
 
+//openclamdblas_fn15(OPENCLAMDBLAS_FN_clAmdBlasCtpsv, clAmdBlasStatus, (clAmdBlasOrder p1, clAmdBlasUplo p2, clAmdBlasTranspose p3, clAmdBlasDiag p4, size_t p5, const cl_mem p6, size_t p7, cl_mem p8, size_t p9, int p10, cl_uint p11, cl_command_queue* p12, cl_uint p13, const cl_event* p14, cl_event* p15))
 //clAmdBlasStatus (*clAmdBlasCtpsv)(clAmdBlasOrder, clAmdBlasUplo, clAmdBlasTranspose, clAmdBlasDiag, size_t, const cl_mem, size_t, cl_mem, size_t, int, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn15<OPENCLAMDBLAS_FN_clAmdBlasCtpsv, clAmdBlasStatus, clAmdBlasOrder, clAmdBlasUplo, clAmdBlasTranspose, clAmdBlasDiag, size_t, const cl_mem, size_t, cl_mem, size_t, int, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasCtpsv_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasCtpsv_definition = { "clAmdBlasCtpsv", (void**)&clAmdBlasCtpsv};
 
+//openclamdblas_fn17(OPENCLAMDBLAS_FN_clAmdBlasCtrmm, clAmdBlasStatus, (clAmdBlasOrder p1, clAmdBlasSide p2, clAmdBlasUplo p3, clAmdBlasTranspose p4, clAmdBlasDiag p5, size_t p6, size_t p7, FloatComplex p8, const cl_mem p9, size_t p10, cl_mem p11, size_t p12, cl_uint p13, cl_command_queue* p14, cl_uint p15, const cl_event* p16, cl_event* p17))
 //clAmdBlasStatus (*clAmdBlasCtrmm)(clAmdBlasOrder, clAmdBlasSide, clAmdBlasUplo, clAmdBlasTranspose, clAmdBlasDiag, size_t, size_t, FloatComplex, const cl_mem, size_t, cl_mem, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn17<OPENCLAMDBLAS_FN_clAmdBlasCtrmm, clAmdBlasStatus, clAmdBlasOrder, clAmdBlasSide, clAmdBlasUplo, clAmdBlasTranspose, clAmdBlasDiag, size_t, size_t, FloatComplex, const cl_mem, size_t, cl_mem, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasCtrmm_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasCtrmm_definition = { "clAmdBlasCtrmm", (void**)&clAmdBlasCtrmm};
 
+//openclamdblas_fn19(OPENCLAMDBLAS_FN_clAmdBlasCtrmmEx, clAmdBlasStatus, (clAmdBlasOrder p1, clAmdBlasSide p2, clAmdBlasUplo p3, clAmdBlasTranspose p4, clAmdBlasDiag p5, size_t p6, size_t p7, FloatComplex p8, const cl_mem p9, size_t p10, size_t p11, cl_mem p12, size_t p13, size_t p14, cl_uint p15, cl_command_queue* p16, cl_uint p17, const cl_event* p18, cl_event* p19))
 //clAmdBlasStatus (*clAmdBlasCtrmmEx)(clAmdBlasOrder, clAmdBlasSide, clAmdBlasUplo, clAmdBlasTranspose, clAmdBlasDiag, size_t, size_t, FloatComplex, const cl_mem, size_t, size_t, cl_mem, size_t, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn19<OPENCLAMDBLAS_FN_clAmdBlasCtrmmEx, clAmdBlasStatus, clAmdBlasOrder, clAmdBlasSide, clAmdBlasUplo, clAmdBlasTranspose, clAmdBlasDiag, size_t, size_t, FloatComplex, const cl_mem, size_t, size_t, cl_mem, size_t, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasCtrmmEx_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasCtrmmEx_definition = { "clAmdBlasCtrmmEx", (void**)&clAmdBlasCtrmmEx};
 
+//openclamdblas_fn17(OPENCLAMDBLAS_FN_clAmdBlasCtrmv, clAmdBlasStatus, (clAmdBlasOrder p1, clAmdBlasUplo p2, clAmdBlasTranspose p3, clAmdBlasDiag p4, size_t p5, const cl_mem p6, size_t p7, size_t p8, cl_mem p9, size_t p10, int p11, cl_mem p12, cl_uint p13, cl_command_queue* p14, cl_uint p15, const cl_event* p16, cl_event* p17))
 //clAmdBlasStatus (*clAmdBlasCtrmv)(clAmdBlasOrder, clAmdBlasUplo, clAmdBlasTranspose, clAmdBlasDiag, size_t, const cl_mem, size_t, size_t, cl_mem, size_t, int, cl_mem, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn17<OPENCLAMDBLAS_FN_clAmdBlasCtrmv, clAmdBlasStatus, clAmdBlasOrder, clAmdBlasUplo, clAmdBlasTranspose, clAmdBlasDiag, size_t, const cl_mem, size_t, size_t, cl_mem, size_t, int, cl_mem, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasCtrmv_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasCtrmv_definition = { "clAmdBlasCtrmv", (void**)&clAmdBlasCtrmv};
 
+//openclamdblas_fn17(OPENCLAMDBLAS_FN_clAmdBlasCtrsm, clAmdBlasStatus, (clAmdBlasOrder p1, clAmdBlasSide p2, clAmdBlasUplo p3, clAmdBlasTranspose p4, clAmdBlasDiag p5, size_t p6, size_t p7, FloatComplex p8, const cl_mem p9, size_t p10, cl_mem p11, size_t p12, cl_uint p13, cl_command_queue* p14, cl_uint p15, const cl_event* p16, cl_event* p17))
 //clAmdBlasStatus (*clAmdBlasCtrsm)(clAmdBlasOrder, clAmdBlasSide, clAmdBlasUplo, clAmdBlasTranspose, clAmdBlasDiag, size_t, size_t, FloatComplex, const cl_mem, size_t, cl_mem, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn17<OPENCLAMDBLAS_FN_clAmdBlasCtrsm, clAmdBlasStatus, clAmdBlasOrder, clAmdBlasSide, clAmdBlasUplo, clAmdBlasTranspose, clAmdBlasDiag, size_t, size_t, FloatComplex, const cl_mem, size_t, cl_mem, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasCtrsm_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasCtrsm_definition = { "clAmdBlasCtrsm", (void**)&clAmdBlasCtrsm};
 
+//openclamdblas_fn19(OPENCLAMDBLAS_FN_clAmdBlasCtrsmEx, clAmdBlasStatus, (clAmdBlasOrder p1, clAmdBlasSide p2, clAmdBlasUplo p3, clAmdBlasTranspose p4, clAmdBlasDiag p5, size_t p6, size_t p7, FloatComplex p8, const cl_mem p9, size_t p10, size_t p11, cl_mem p12, size_t p13, size_t p14, cl_uint p15, cl_command_queue* p16, cl_uint p17, const cl_event* p18, cl_event* p19))
 //clAmdBlasStatus (*clAmdBlasCtrsmEx)(clAmdBlasOrder, clAmdBlasSide, clAmdBlasUplo, clAmdBlasTranspose, clAmdBlasDiag, size_t, size_t, FloatComplex, const cl_mem, size_t, size_t, cl_mem, size_t, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn19<OPENCLAMDBLAS_FN_clAmdBlasCtrsmEx, clAmdBlasStatus, clAmdBlasOrder, clAmdBlasSide, clAmdBlasUplo, clAmdBlasTranspose, clAmdBlasDiag, size_t, size_t, FloatComplex, const cl_mem, size_t, size_t, cl_mem, size_t, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasCtrsmEx_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasCtrsmEx_definition = { "clAmdBlasCtrsmEx", (void**)&clAmdBlasCtrsmEx};
 
+//openclamdblas_fn16(OPENCLAMDBLAS_FN_clAmdBlasCtrsv, clAmdBlasStatus, (clAmdBlasOrder p1, clAmdBlasUplo p2, clAmdBlasTranspose p3, clAmdBlasDiag p4, size_t p5, const cl_mem p6, size_t p7, size_t p8, cl_mem p9, size_t p10, int p11, cl_uint p12, cl_command_queue* p13, cl_uint p14, const cl_event* p15, cl_event* p16))
 //clAmdBlasStatus (*clAmdBlasCtrsv)(clAmdBlasOrder, clAmdBlasUplo, clAmdBlasTranspose, clAmdBlasDiag, size_t, const cl_mem, size_t, size_t, cl_mem, size_t, int, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn16<OPENCLAMDBLAS_FN_clAmdBlasCtrsv, clAmdBlasStatus, clAmdBlasOrder, clAmdBlasUplo, clAmdBlasTranspose, clAmdBlasDiag, size_t, const cl_mem, size_t, size_t, cl_mem, size_t, int, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasCtrsv_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasCtrsv_definition = { "clAmdBlasCtrsv", (void**)&clAmdBlasCtrsv};
 
+//openclamdblas_fn12(OPENCLAMDBLAS_FN_clAmdBlasDasum, clAmdBlasStatus, (size_t p1, cl_mem p2, size_t p3, const cl_mem p4, size_t p5, int p6, cl_mem p7, cl_uint p8, cl_command_queue* p9, cl_uint p10, const cl_event* p11, cl_event* p12))
 //clAmdBlasStatus (*clAmdBlasDasum)(size_t, cl_mem, size_t, const cl_mem, size_t, int, cl_mem, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn12<OPENCLAMDBLAS_FN_clAmdBlasDasum, clAmdBlasStatus, size_t, cl_mem, size_t, const cl_mem, size_t, int, cl_mem, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasDasum_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasDasum_definition = { "clAmdBlasDasum", (void**)&clAmdBlasDasum};
 
+//openclamdblas_fn13(OPENCLAMDBLAS_FN_clAmdBlasDaxpy, clAmdBlasStatus, (size_t p1, cl_double p2, const cl_mem p3, size_t p4, int p5, cl_mem p6, size_t p7, int p8, cl_uint p9, cl_command_queue* p10, cl_uint p11, const cl_event* p12, cl_event* p13))
 //clAmdBlasStatus (*clAmdBlasDaxpy)(size_t, cl_double, const cl_mem, size_t, int, cl_mem, size_t, int, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn13<OPENCLAMDBLAS_FN_clAmdBlasDaxpy, clAmdBlasStatus, size_t, cl_double, const cl_mem, size_t, int, cl_mem, size_t, int, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasDaxpy_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasDaxpy_definition = { "clAmdBlasDaxpy", (void**)&clAmdBlasDaxpy};
 
+//openclamdblas_fn12(OPENCLAMDBLAS_FN_clAmdBlasDcopy, clAmdBlasStatus, (size_t p1, const cl_mem p2, size_t p3, int p4, cl_mem p5, size_t p6, int p7, cl_uint p8, cl_command_queue* p9, cl_uint p10, const cl_event* p11, cl_event* p12))
 //clAmdBlasStatus (*clAmdBlasDcopy)(size_t, const cl_mem, size_t, int, cl_mem, size_t, int, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn12<OPENCLAMDBLAS_FN_clAmdBlasDcopy, clAmdBlasStatus, size_t, const cl_mem, size_t, int, cl_mem, size_t, int, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasDcopy_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasDcopy_definition = { "clAmdBlasDcopy", (void**)&clAmdBlasDcopy};
 
+//openclamdblas_fn15(OPENCLAMDBLAS_FN_clAmdBlasDdot, clAmdBlasStatus, (size_t p1, cl_mem p2, size_t p3, const cl_mem p4, size_t p5, int p6, const cl_mem p7, size_t p8, int p9, cl_mem p10, cl_uint p11, cl_command_queue* p12, cl_uint p13, const cl_event* p14, cl_event* p15))
 //clAmdBlasStatus (*clAmdBlasDdot)(size_t, cl_mem, size_t, const cl_mem, size_t, int, const cl_mem, size_t, int, cl_mem, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn15<OPENCLAMDBLAS_FN_clAmdBlasDdot, clAmdBlasStatus, size_t, cl_mem, size_t, const cl_mem, size_t, int, const cl_mem, size_t, int, cl_mem, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasDdot_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasDdot_definition = { "clAmdBlasDdot", (void**)&clAmdBlasDdot};
 
+//openclamdblas_fn22(OPENCLAMDBLAS_FN_clAmdBlasDgbmv, clAmdBlasStatus, (clAmdBlasOrder p1, clAmdBlasTranspose p2, size_t p3, size_t p4, size_t p5, size_t p6, cl_double p7, const cl_mem p8, size_t p9, size_t p10, const cl_mem p11, size_t p12, int p13, cl_double p14, cl_mem p15, size_t p16, int p17, cl_uint p18, cl_command_queue* p19, cl_uint p20, const cl_event* p21, cl_event* p22))
 //clAmdBlasStatus (*clAmdBlasDgbmv)(clAmdBlasOrder, clAmdBlasTranspose, size_t, size_t, size_t, size_t, cl_double, const cl_mem, size_t, size_t, const cl_mem, size_t, int, cl_double, cl_mem, size_t, int, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn22<OPENCLAMDBLAS_FN_clAmdBlasDgbmv, clAmdBlasStatus, clAmdBlasOrder, clAmdBlasTranspose, size_t, size_t, size_t, size_t, cl_double, const cl_mem, size_t, size_t, const cl_mem, size_t, int, cl_double, cl_mem, size_t, int, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasDgbmv_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasDgbmv_definition = { "clAmdBlasDgbmv", (void**)&clAmdBlasDgbmv};
 
+//openclamdblas_fn19(OPENCLAMDBLAS_FN_clAmdBlasDgemm, clAmdBlasStatus, (clAmdBlasOrder p1, clAmdBlasTranspose p2, clAmdBlasTranspose p3, size_t p4, size_t p5, size_t p6, cl_double p7, const cl_mem p8, size_t p9, const cl_mem p10, size_t p11, cl_double p12, cl_mem p13, size_t p14, cl_uint p15, cl_command_queue* p16, cl_uint p17, const cl_event* p18, cl_event* p19))
 //clAmdBlasStatus (*clAmdBlasDgemm)(clAmdBlasOrder, clAmdBlasTranspose, clAmdBlasTranspose, size_t, size_t, size_t, cl_double, const cl_mem, size_t, const cl_mem, size_t, cl_double, cl_mem, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn19<OPENCLAMDBLAS_FN_clAmdBlasDgemm, clAmdBlasStatus, clAmdBlasOrder, clAmdBlasTranspose, clAmdBlasTranspose, size_t, size_t, size_t, cl_double, const cl_mem, size_t, const cl_mem, size_t, cl_double, cl_mem, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasDgemm_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasDgemm_definition = { "clAmdBlasDgemm", (void**)&clAmdBlasDgemm};
 
+openclamdblas_fn22(OPENCLAMDBLAS_FN_clAmdBlasDgemmEx, clAmdBlasStatus, (clAmdBlasOrder p1, clAmdBlasTranspose p2, clAmdBlasTranspose p3, size_t p4, size_t p5, size_t p6, cl_double p7, const cl_mem p8, size_t p9, size_t p10, const cl_mem p11, size_t p12, size_t p13, cl_double p14, cl_mem p15, size_t p16, size_t p17, cl_uint p18, cl_command_queue* p19, cl_uint p20, const cl_event* p21, cl_event* p22))
 clAmdBlasStatus (*clAmdBlasDgemmEx)(clAmdBlasOrder, clAmdBlasTranspose, clAmdBlasTranspose, size_t, size_t, size_t, cl_double, const cl_mem, size_t, size_t, const cl_mem, size_t, size_t, cl_double, cl_mem, size_t, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-        openclamdblas_fn22<OPENCLAMDBLAS_FN_clAmdBlasDgemmEx, clAmdBlasStatus, clAmdBlasOrder, clAmdBlasTranspose, clAmdBlasTranspose, size_t, size_t, size_t, cl_double, const cl_mem, size_t, size_t, const cl_mem, size_t, size_t, cl_double, cl_mem, size_t, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+        OPENCLAMDBLAS_FN_clAmdBlasDgemmEx_switch_fn;
 static const struct DynamicFnEntry clAmdBlasDgemmEx_definition = { "clAmdBlasDgemmEx", (void**)&clAmdBlasDgemmEx};
 
+//openclamdblas_fn19(OPENCLAMDBLAS_FN_clAmdBlasDgemv, clAmdBlasStatus, (clAmdBlasOrder p1, clAmdBlasTranspose p2, size_t p3, size_t p4, cl_double p5, const cl_mem p6, size_t p7, const cl_mem p8, size_t p9, int p10, cl_double p11, cl_mem p12, size_t p13, int p14, cl_uint p15, cl_command_queue* p16, cl_uint p17, const cl_event* p18, cl_event* p19))
 //clAmdBlasStatus (*clAmdBlasDgemv)(clAmdBlasOrder, clAmdBlasTranspose, size_t, size_t, cl_double, const cl_mem, size_t, const cl_mem, size_t, int, cl_double, cl_mem, size_t, int, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn19<OPENCLAMDBLAS_FN_clAmdBlasDgemv, clAmdBlasStatus, clAmdBlasOrder, clAmdBlasTranspose, size_t, size_t, cl_double, const cl_mem, size_t, const cl_mem, size_t, int, cl_double, cl_mem, size_t, int, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasDgemv_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasDgemv_definition = { "clAmdBlasDgemv", (void**)&clAmdBlasDgemv};
 
+//openclamdblas_fn20(OPENCLAMDBLAS_FN_clAmdBlasDgemvEx, clAmdBlasStatus, (clAmdBlasOrder p1, clAmdBlasTranspose p2, size_t p3, size_t p4, cl_double p5, const cl_mem p6, size_t p7, size_t p8, const cl_mem p9, size_t p10, int p11, cl_double p12, cl_mem p13, size_t p14, int p15, cl_uint p16, cl_command_queue* p17, cl_uint p18, const cl_event* p19, cl_event* p20))
 //clAmdBlasStatus (*clAmdBlasDgemvEx)(clAmdBlasOrder, clAmdBlasTranspose, size_t, size_t, cl_double, const cl_mem, size_t, size_t, const cl_mem, size_t, int, cl_double, cl_mem, size_t, int, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn20<OPENCLAMDBLAS_FN_clAmdBlasDgemvEx, clAmdBlasStatus, clAmdBlasOrder, clAmdBlasTranspose, size_t, size_t, cl_double, const cl_mem, size_t, size_t, const cl_mem, size_t, int, cl_double, cl_mem, size_t, int, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasDgemvEx_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasDgemvEx_definition = { "clAmdBlasDgemvEx", (void**)&clAmdBlasDgemvEx};
 
+//openclamdblas_fn18(OPENCLAMDBLAS_FN_clAmdBlasDger, clAmdBlasStatus, (clAmdBlasOrder p1, size_t p2, size_t p3, cl_double p4, const cl_mem p5, size_t p6, int p7, const cl_mem p8, size_t p9, int p10, cl_mem p11, size_t p12, size_t p13, cl_uint p14, cl_command_queue* p15, cl_uint p16, const cl_event* p17, cl_event* p18))
 //clAmdBlasStatus (*clAmdBlasDger)(clAmdBlasOrder, size_t, size_t, cl_double, const cl_mem, size_t, int, const cl_mem, size_t, int, cl_mem, size_t, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn18<OPENCLAMDBLAS_FN_clAmdBlasDger, clAmdBlasStatus, clAmdBlasOrder, size_t, size_t, cl_double, const cl_mem, size_t, int, const cl_mem, size_t, int, cl_mem, size_t, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasDger_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasDger_definition = { "clAmdBlasDger", (void**)&clAmdBlasDger};
 
+//openclamdblas_fn12(OPENCLAMDBLAS_FN_clAmdBlasDnrm2, clAmdBlasStatus, (size_t p1, cl_mem p2, size_t p3, const cl_mem p4, size_t p5, int p6, cl_mem p7, cl_uint p8, cl_command_queue* p9, cl_uint p10, const cl_event* p11, cl_event* p12))
 //clAmdBlasStatus (*clAmdBlasDnrm2)(size_t, cl_mem, size_t, const cl_mem, size_t, int, cl_mem, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn12<OPENCLAMDBLAS_FN_clAmdBlasDnrm2, clAmdBlasStatus, size_t, cl_mem, size_t, const cl_mem, size_t, int, cl_mem, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasDnrm2_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasDnrm2_definition = { "clAmdBlasDnrm2", (void**)&clAmdBlasDnrm2};
 
+//openclamdblas_fn14(OPENCLAMDBLAS_FN_clAmdBlasDrot, clAmdBlasStatus, (size_t p1, cl_mem p2, size_t p3, int p4, cl_mem p5, size_t p6, int p7, cl_double p8, cl_double p9, cl_uint p10, cl_command_queue* p11, cl_uint p12, const cl_event* p13, cl_event* p14))
 //clAmdBlasStatus (*clAmdBlasDrot)(size_t, cl_mem, size_t, int, cl_mem, size_t, int, cl_double, cl_double, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn14<OPENCLAMDBLAS_FN_clAmdBlasDrot, clAmdBlasStatus, size_t, cl_mem, size_t, int, cl_mem, size_t, int, cl_double, cl_double, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasDrot_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasDrot_definition = { "clAmdBlasDrot", (void**)&clAmdBlasDrot};
 
+//openclamdblas_fn13(OPENCLAMDBLAS_FN_clAmdBlasDrotg, clAmdBlasStatus, (cl_mem p1, size_t p2, cl_mem p3, size_t p4, cl_mem p5, size_t p6, cl_mem p7, size_t p8, cl_uint p9, cl_command_queue* p10, cl_uint p11, const cl_event* p12, cl_event* p13))
 //clAmdBlasStatus (*clAmdBlasDrotg)(cl_mem, size_t, cl_mem, size_t, cl_mem, size_t, cl_mem, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn13<OPENCLAMDBLAS_FN_clAmdBlasDrotg, clAmdBlasStatus, cl_mem, size_t, cl_mem, size_t, cl_mem, size_t, cl_mem, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasDrotg_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasDrotg_definition = { "clAmdBlasDrotg", (void**)&clAmdBlasDrotg};
 
+//openclamdblas_fn14(OPENCLAMDBLAS_FN_clAmdBlasDrotm, clAmdBlasStatus, (size_t p1, cl_mem p2, size_t p3, int p4, cl_mem p5, size_t p6, int p7, const cl_mem p8, size_t p9, cl_uint p10, cl_command_queue* p11, cl_uint p12, const cl_event* p13, cl_event* p14))
 //clAmdBlasStatus (*clAmdBlasDrotm)(size_t, cl_mem, size_t, int, cl_mem, size_t, int, const cl_mem, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn14<OPENCLAMDBLAS_FN_clAmdBlasDrotm, clAmdBlasStatus, size_t, cl_mem, size_t, int, cl_mem, size_t, int, const cl_mem, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasDrotm_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasDrotm_definition = { "clAmdBlasDrotm", (void**)&clAmdBlasDrotm};
 
+//openclamdblas_fn15(OPENCLAMDBLAS_FN_clAmdBlasDrotmg, clAmdBlasStatus, (cl_mem p1, size_t p2, cl_mem p3, size_t p4, cl_mem p5, size_t p6, const cl_mem p7, size_t p8, cl_mem p9, size_t p10, cl_uint p11, cl_command_queue* p12, cl_uint p13, const cl_event* p14, cl_event* p15))
 //clAmdBlasStatus (*clAmdBlasDrotmg)(cl_mem, size_t, cl_mem, size_t, cl_mem, size_t, const cl_mem, size_t, cl_mem, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn15<OPENCLAMDBLAS_FN_clAmdBlasDrotmg, clAmdBlasStatus, cl_mem, size_t, cl_mem, size_t, cl_mem, size_t, const cl_mem, size_t, cl_mem, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasDrotmg_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasDrotmg_definition = { "clAmdBlasDrotmg", (void**)&clAmdBlasDrotmg};
 
+//openclamdblas_fn20(OPENCLAMDBLAS_FN_clAmdBlasDsbmv, clAmdBlasStatus, (clAmdBlasOrder p1, clAmdBlasUplo p2, size_t p3, size_t p4, cl_double p5, const cl_mem p6, size_t p7, size_t p8, const cl_mem p9, size_t p10, int p11, cl_double p12, cl_mem p13, size_t p14, int p15, cl_uint p16, cl_command_queue* p17, cl_uint p18, const cl_event* p19, cl_event* p20))
 //clAmdBlasStatus (*clAmdBlasDsbmv)(clAmdBlasOrder, clAmdBlasUplo, size_t, size_t, cl_double, const cl_mem, size_t, size_t, const cl_mem, size_t, int, cl_double, cl_mem, size_t, int, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn20<OPENCLAMDBLAS_FN_clAmdBlasDsbmv, clAmdBlasStatus, clAmdBlasOrder, clAmdBlasUplo, size_t, size_t, cl_double, const cl_mem, size_t, size_t, const cl_mem, size_t, int, cl_double, cl_mem, size_t, int, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasDsbmv_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasDsbmv_definition = { "clAmdBlasDsbmv", (void**)&clAmdBlasDsbmv};
 
+//openclamdblas_fn10(OPENCLAMDBLAS_FN_clAmdBlasDscal, clAmdBlasStatus, (size_t p1, cl_double p2, cl_mem p3, size_t p4, int p5, cl_uint p6, cl_command_queue* p7, cl_uint p8, const cl_event* p9, cl_event* p10))
 //clAmdBlasStatus (*clAmdBlasDscal)(size_t, cl_double, cl_mem, size_t, int, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn10<OPENCLAMDBLAS_FN_clAmdBlasDscal, clAmdBlasStatus, size_t, cl_double, cl_mem, size_t, int, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasDscal_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasDscal_definition = { "clAmdBlasDscal", (void**)&clAmdBlasDscal};
 
+//openclamdblas_fn18(OPENCLAMDBLAS_FN_clAmdBlasDspmv, clAmdBlasStatus, (clAmdBlasOrder p1, clAmdBlasUplo p2, size_t p3, cl_double p4, const cl_mem p5, size_t p6, const cl_mem p7, size_t p8, int p9, cl_double p10, cl_mem p11, size_t p12, int p13, cl_uint p14, cl_command_queue* p15, cl_uint p16, const cl_event* p17, cl_event* p18))
 //clAmdBlasStatus (*clAmdBlasDspmv)(clAmdBlasOrder, clAmdBlasUplo, size_t, cl_double, const cl_mem, size_t, const cl_mem, size_t, int, cl_double, cl_mem, size_t, int, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn18<OPENCLAMDBLAS_FN_clAmdBlasDspmv, clAmdBlasStatus, clAmdBlasOrder, clAmdBlasUplo, size_t, cl_double, const cl_mem, size_t, const cl_mem, size_t, int, cl_double, cl_mem, size_t, int, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasDspmv_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasDspmv_definition = { "clAmdBlasDspmv", (void**)&clAmdBlasDspmv};
 
+//openclamdblas_fn14(OPENCLAMDBLAS_FN_clAmdBlasDspr, clAmdBlasStatus, (clAmdBlasOrder p1, clAmdBlasUplo p2, size_t p3, cl_double p4, const cl_mem p5, size_t p6, int p7, cl_mem p8, size_t p9, cl_uint p10, cl_command_queue* p11, cl_uint p12, const cl_event* p13, cl_event* p14))
 //clAmdBlasStatus (*clAmdBlasDspr)(clAmdBlasOrder, clAmdBlasUplo, size_t, cl_double, const cl_mem, size_t, int, cl_mem, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn14<OPENCLAMDBLAS_FN_clAmdBlasDspr, clAmdBlasStatus, clAmdBlasOrder, clAmdBlasUplo, size_t, cl_double, const cl_mem, size_t, int, cl_mem, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasDspr_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasDspr_definition = { "clAmdBlasDspr", (void**)&clAmdBlasDspr};
 
+//openclamdblas_fn17(OPENCLAMDBLAS_FN_clAmdBlasDspr2, clAmdBlasStatus, (clAmdBlasOrder p1, clAmdBlasUplo p2, size_t p3, cl_double p4, const cl_mem p5, size_t p6, int p7, const cl_mem p8, size_t p9, int p10, cl_mem p11, size_t p12, cl_uint p13, cl_command_queue* p14, cl_uint p15, const cl_event* p16, cl_event* p17))
 //clAmdBlasStatus (*clAmdBlasDspr2)(clAmdBlasOrder, clAmdBlasUplo, size_t, cl_double, const cl_mem, size_t, int, const cl_mem, size_t, int, cl_mem, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn17<OPENCLAMDBLAS_FN_clAmdBlasDspr2, clAmdBlasStatus, clAmdBlasOrder, clAmdBlasUplo, size_t, cl_double, const cl_mem, size_t, int, const cl_mem, size_t, int, cl_mem, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasDspr2_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasDspr2_definition = { "clAmdBlasDspr2", (void**)&clAmdBlasDspr2};
 
+//openclamdblas_fn12(OPENCLAMDBLAS_FN_clAmdBlasDswap, clAmdBlasStatus, (size_t p1, cl_mem p2, size_t p3, int p4, cl_mem p5, size_t p6, int p7, cl_uint p8, cl_command_queue* p9, cl_uint p10, const cl_event* p11, cl_event* p12))
 //clAmdBlasStatus (*clAmdBlasDswap)(size_t, cl_mem, size_t, int, cl_mem, size_t, int, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn12<OPENCLAMDBLAS_FN_clAmdBlasDswap, clAmdBlasStatus, size_t, cl_mem, size_t, int, cl_mem, size_t, int, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasDswap_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasDswap_definition = { "clAmdBlasDswap", (void**)&clAmdBlasDswap};
 
+//openclamdblas_fn21(OPENCLAMDBLAS_FN_clAmdBlasDsymm, clAmdBlasStatus, (clAmdBlasOrder p1, clAmdBlasSide p2, clAmdBlasUplo p3, size_t p4, size_t p5, cl_double p6, const cl_mem p7, size_t p8, size_t p9, const cl_mem p10, size_t p11, size_t p12, cl_double p13, cl_mem p14, size_t p15, size_t p16, cl_uint p17, cl_command_queue* p18, cl_uint p19, const cl_event* p20, cl_event* p21))
 //clAmdBlasStatus (*clAmdBlasDsymm)(clAmdBlasOrder, clAmdBlasSide, clAmdBlasUplo, size_t, size_t, cl_double, const cl_mem, size_t, size_t, const cl_mem, size_t, size_t, cl_double, cl_mem, size_t, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn21<OPENCLAMDBLAS_FN_clAmdBlasDsymm, clAmdBlasStatus, clAmdBlasOrder, clAmdBlasSide, clAmdBlasUplo, size_t, size_t, cl_double, const cl_mem, size_t, size_t, const cl_mem, size_t, size_t, cl_double, cl_mem, size_t, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasDsymm_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasDsymm_definition = { "clAmdBlasDsymm", (void**)&clAmdBlasDsymm};
 
+//openclamdblas_fn18(OPENCLAMDBLAS_FN_clAmdBlasDsymv, clAmdBlasStatus, (clAmdBlasOrder p1, clAmdBlasUplo p2, size_t p3, cl_double p4, const cl_mem p5, size_t p6, const cl_mem p7, size_t p8, int p9, cl_double p10, cl_mem p11, size_t p12, int p13, cl_uint p14, cl_command_queue* p15, cl_uint p16, const cl_event* p17, cl_event* p18))
 //clAmdBlasStatus (*clAmdBlasDsymv)(clAmdBlasOrder, clAmdBlasUplo, size_t, cl_double, const cl_mem, size_t, const cl_mem, size_t, int, cl_double, cl_mem, size_t, int, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn18<OPENCLAMDBLAS_FN_clAmdBlasDsymv, clAmdBlasStatus, clAmdBlasOrder, clAmdBlasUplo, size_t, cl_double, const cl_mem, size_t, const cl_mem, size_t, int, cl_double, cl_mem, size_t, int, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasDsymv_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasDsymv_definition = { "clAmdBlasDsymv", (void**)&clAmdBlasDsymv};
 
+//openclamdblas_fn19(OPENCLAMDBLAS_FN_clAmdBlasDsymvEx, clAmdBlasStatus, (clAmdBlasOrder p1, clAmdBlasUplo p2, size_t p3, cl_double p4, const cl_mem p5, size_t p6, size_t p7, const cl_mem p8, size_t p9, int p10, cl_double p11, cl_mem p12, size_t p13, int p14, cl_uint p15, cl_command_queue* p16, cl_uint p17, const cl_event* p18, cl_event* p19))
 //clAmdBlasStatus (*clAmdBlasDsymvEx)(clAmdBlasOrder, clAmdBlasUplo, size_t, cl_double, const cl_mem, size_t, size_t, const cl_mem, size_t, int, cl_double, cl_mem, size_t, int, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn19<OPENCLAMDBLAS_FN_clAmdBlasDsymvEx, clAmdBlasStatus, clAmdBlasOrder, clAmdBlasUplo, size_t, cl_double, const cl_mem, size_t, size_t, const cl_mem, size_t, int, cl_double, cl_mem, size_t, int, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasDsymvEx_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasDsymvEx_definition = { "clAmdBlasDsymvEx", (void**)&clAmdBlasDsymvEx};
 
+//openclamdblas_fn15(OPENCLAMDBLAS_FN_clAmdBlasDsyr, clAmdBlasStatus, (clAmdBlasOrder p1, clAmdBlasUplo p2, size_t p3, cl_double p4, const cl_mem p5, size_t p6, int p7, cl_mem p8, size_t p9, size_t p10, cl_uint p11, cl_command_queue* p12, cl_uint p13, const cl_event* p14, cl_event* p15))
 //clAmdBlasStatus (*clAmdBlasDsyr)(clAmdBlasOrder, clAmdBlasUplo, size_t, cl_double, const cl_mem, size_t, int, cl_mem, size_t, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn15<OPENCLAMDBLAS_FN_clAmdBlasDsyr, clAmdBlasStatus, clAmdBlasOrder, clAmdBlasUplo, size_t, cl_double, const cl_mem, size_t, int, cl_mem, size_t, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasDsyr_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasDsyr_definition = { "clAmdBlasDsyr", (void**)&clAmdBlasDsyr};
 
+//openclamdblas_fn18(OPENCLAMDBLAS_FN_clAmdBlasDsyr2, clAmdBlasStatus, (clAmdBlasOrder p1, clAmdBlasUplo p2, size_t p3, cl_double p4, const cl_mem p5, size_t p6, int p7, const cl_mem p8, size_t p9, int p10, cl_mem p11, size_t p12, size_t p13, cl_uint p14, cl_command_queue* p15, cl_uint p16, const cl_event* p17, cl_event* p18))
 //clAmdBlasStatus (*clAmdBlasDsyr2)(clAmdBlasOrder, clAmdBlasUplo, size_t, cl_double, const cl_mem, size_t, int, const cl_mem, size_t, int, cl_mem, size_t, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn18<OPENCLAMDBLAS_FN_clAmdBlasDsyr2, clAmdBlasStatus, clAmdBlasOrder, clAmdBlasUplo, size_t, cl_double, const cl_mem, size_t, int, const cl_mem, size_t, int, cl_mem, size_t, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasDsyr2_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasDsyr2_definition = { "clAmdBlasDsyr2", (void**)&clAmdBlasDsyr2};
 
+//openclamdblas_fn18(OPENCLAMDBLAS_FN_clAmdBlasDsyr2k, clAmdBlasStatus, (clAmdBlasOrder p1, clAmdBlasUplo p2, clAmdBlasTranspose p3, size_t p4, size_t p5, cl_double p6, const cl_mem p7, size_t p8, const cl_mem p9, size_t p10, cl_double p11, cl_mem p12, size_t p13, cl_uint p14, cl_command_queue* p15, cl_uint p16, const cl_event* p17, cl_event* p18))
 //clAmdBlasStatus (*clAmdBlasDsyr2k)(clAmdBlasOrder, clAmdBlasUplo, clAmdBlasTranspose, size_t, size_t, cl_double, const cl_mem, size_t, const cl_mem, size_t, cl_double, cl_mem, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn18<OPENCLAMDBLAS_FN_clAmdBlasDsyr2k, clAmdBlasStatus, clAmdBlasOrder, clAmdBlasUplo, clAmdBlasTranspose, size_t, size_t, cl_double, const cl_mem, size_t, const cl_mem, size_t, cl_double, cl_mem, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasDsyr2k_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasDsyr2k_definition = { "clAmdBlasDsyr2k", (void**)&clAmdBlasDsyr2k};
 
+//openclamdblas_fn21(OPENCLAMDBLAS_FN_clAmdBlasDsyr2kEx, clAmdBlasStatus, (clAmdBlasOrder p1, clAmdBlasUplo p2, clAmdBlasTranspose p3, size_t p4, size_t p5, cl_double p6, const cl_mem p7, size_t p8, size_t p9, const cl_mem p10, size_t p11, size_t p12, cl_double p13, cl_mem p14, size_t p15, size_t p16, cl_uint p17, cl_command_queue* p18, cl_uint p19, const cl_event* p20, cl_event* p21))
 //clAmdBlasStatus (*clAmdBlasDsyr2kEx)(clAmdBlasOrder, clAmdBlasUplo, clAmdBlasTranspose, size_t, size_t, cl_double, const cl_mem, size_t, size_t, const cl_mem, size_t, size_t, cl_double, cl_mem, size_t, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn21<OPENCLAMDBLAS_FN_clAmdBlasDsyr2kEx, clAmdBlasStatus, clAmdBlasOrder, clAmdBlasUplo, clAmdBlasTranspose, size_t, size_t, cl_double, const cl_mem, size_t, size_t, const cl_mem, size_t, size_t, cl_double, cl_mem, size_t, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasDsyr2kEx_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasDsyr2kEx_definition = { "clAmdBlasDsyr2kEx", (void**)&clAmdBlasDsyr2kEx};
 
+//openclamdblas_fn16(OPENCLAMDBLAS_FN_clAmdBlasDsyrk, clAmdBlasStatus, (clAmdBlasOrder p1, clAmdBlasUplo p2, clAmdBlasTranspose p3, size_t p4, size_t p5, cl_double p6, const cl_mem p7, size_t p8, cl_double p9, cl_mem p10, size_t p11, cl_uint p12, cl_command_queue* p13, cl_uint p14, const cl_event* p15, cl_event* p16))
 //clAmdBlasStatus (*clAmdBlasDsyrk)(clAmdBlasOrder, clAmdBlasUplo, clAmdBlasTranspose, size_t, size_t, cl_double, const cl_mem, size_t, cl_double, cl_mem, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn16<OPENCLAMDBLAS_FN_clAmdBlasDsyrk, clAmdBlasStatus, clAmdBlasOrder, clAmdBlasUplo, clAmdBlasTranspose, size_t, size_t, cl_double, const cl_mem, size_t, cl_double, cl_mem, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasDsyrk_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasDsyrk_definition = { "clAmdBlasDsyrk", (void**)&clAmdBlasDsyrk};
 
+//openclamdblas_fn18(OPENCLAMDBLAS_FN_clAmdBlasDsyrkEx, clAmdBlasStatus, (clAmdBlasOrder p1, clAmdBlasUplo p2, clAmdBlasTranspose p3, size_t p4, size_t p5, cl_double p6, const cl_mem p7, size_t p8, size_t p9, cl_double p10, cl_mem p11, size_t p12, size_t p13, cl_uint p14, cl_command_queue* p15, cl_uint p16, const cl_event* p17, cl_event* p18))
 //clAmdBlasStatus (*clAmdBlasDsyrkEx)(clAmdBlasOrder, clAmdBlasUplo, clAmdBlasTranspose, size_t, size_t, cl_double, const cl_mem, size_t, size_t, cl_double, cl_mem, size_t, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn18<OPENCLAMDBLAS_FN_clAmdBlasDsyrkEx, clAmdBlasStatus, clAmdBlasOrder, clAmdBlasUplo, clAmdBlasTranspose, size_t, size_t, cl_double, const cl_mem, size_t, size_t, cl_double, cl_mem, size_t, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasDsyrkEx_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasDsyrkEx_definition = { "clAmdBlasDsyrkEx", (void**)&clAmdBlasDsyrkEx};
 
+//openclamdblas_fn18(OPENCLAMDBLAS_FN_clAmdBlasDtbmv, clAmdBlasStatus, (clAmdBlasOrder p1, clAmdBlasUplo p2, clAmdBlasTranspose p3, clAmdBlasDiag p4, size_t p5, size_t p6, const cl_mem p7, size_t p8, size_t p9, cl_mem p10, size_t p11, int p12, cl_mem p13, cl_uint p14, cl_command_queue* p15, cl_uint p16, const cl_event* p17, cl_event* p18))
 //clAmdBlasStatus (*clAmdBlasDtbmv)(clAmdBlasOrder, clAmdBlasUplo, clAmdBlasTranspose, clAmdBlasDiag, size_t, size_t, const cl_mem, size_t, size_t, cl_mem, size_t, int, cl_mem, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn18<OPENCLAMDBLAS_FN_clAmdBlasDtbmv, clAmdBlasStatus, clAmdBlasOrder, clAmdBlasUplo, clAmdBlasTranspose, clAmdBlasDiag, size_t, size_t, const cl_mem, size_t, size_t, cl_mem, size_t, int, cl_mem, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasDtbmv_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasDtbmv_definition = { "clAmdBlasDtbmv", (void**)&clAmdBlasDtbmv};
 
+//openclamdblas_fn17(OPENCLAMDBLAS_FN_clAmdBlasDtbsv, clAmdBlasStatus, (clAmdBlasOrder p1, clAmdBlasUplo p2, clAmdBlasTranspose p3, clAmdBlasDiag p4, size_t p5, size_t p6, const cl_mem p7, size_t p8, size_t p9, cl_mem p10, size_t p11, int p12, cl_uint p13, cl_command_queue* p14, cl_uint p15, const cl_event* p16, cl_event* p17))
 //clAmdBlasStatus (*clAmdBlasDtbsv)(clAmdBlasOrder, clAmdBlasUplo, clAmdBlasTranspose, clAmdBlasDiag, size_t, size_t, const cl_mem, size_t, size_t, cl_mem, size_t, int, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn17<OPENCLAMDBLAS_FN_clAmdBlasDtbsv, clAmdBlasStatus, clAmdBlasOrder, clAmdBlasUplo, clAmdBlasTranspose, clAmdBlasDiag, size_t, size_t, const cl_mem, size_t, size_t, cl_mem, size_t, int, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasDtbsv_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasDtbsv_definition = { "clAmdBlasDtbsv", (void**)&clAmdBlasDtbsv};
 
+//openclamdblas_fn16(OPENCLAMDBLAS_FN_clAmdBlasDtpmv, clAmdBlasStatus, (clAmdBlasOrder p1, clAmdBlasUplo p2, clAmdBlasTranspose p3, clAmdBlasDiag p4, size_t p5, const cl_mem p6, size_t p7, cl_mem p8, size_t p9, int p10, cl_mem p11, cl_uint p12, cl_command_queue* p13, cl_uint p14, const cl_event* p15, cl_event* p16))
 //clAmdBlasStatus (*clAmdBlasDtpmv)(clAmdBlasOrder, clAmdBlasUplo, clAmdBlasTranspose, clAmdBlasDiag, size_t, const cl_mem, size_t, cl_mem, size_t, int, cl_mem, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn16<OPENCLAMDBLAS_FN_clAmdBlasDtpmv, clAmdBlasStatus, clAmdBlasOrder, clAmdBlasUplo, clAmdBlasTranspose, clAmdBlasDiag, size_t, const cl_mem, size_t, cl_mem, size_t, int, cl_mem, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasDtpmv_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasDtpmv_definition = { "clAmdBlasDtpmv", (void**)&clAmdBlasDtpmv};
 
+//openclamdblas_fn15(OPENCLAMDBLAS_FN_clAmdBlasDtpsv, clAmdBlasStatus, (clAmdBlasOrder p1, clAmdBlasUplo p2, clAmdBlasTranspose p3, clAmdBlasDiag p4, size_t p5, const cl_mem p6, size_t p7, cl_mem p8, size_t p9, int p10, cl_uint p11, cl_command_queue* p12, cl_uint p13, const cl_event* p14, cl_event* p15))
 //clAmdBlasStatus (*clAmdBlasDtpsv)(clAmdBlasOrder, clAmdBlasUplo, clAmdBlasTranspose, clAmdBlasDiag, size_t, const cl_mem, size_t, cl_mem, size_t, int, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn15<OPENCLAMDBLAS_FN_clAmdBlasDtpsv, clAmdBlasStatus, clAmdBlasOrder, clAmdBlasUplo, clAmdBlasTranspose, clAmdBlasDiag, size_t, const cl_mem, size_t, cl_mem, size_t, int, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasDtpsv_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasDtpsv_definition = { "clAmdBlasDtpsv", (void**)&clAmdBlasDtpsv};
 
+//openclamdblas_fn17(OPENCLAMDBLAS_FN_clAmdBlasDtrmm, clAmdBlasStatus, (clAmdBlasOrder p1, clAmdBlasSide p2, clAmdBlasUplo p3, clAmdBlasTranspose p4, clAmdBlasDiag p5, size_t p6, size_t p7, cl_double p8, const cl_mem p9, size_t p10, cl_mem p11, size_t p12, cl_uint p13, cl_command_queue* p14, cl_uint p15, const cl_event* p16, cl_event* p17))
 //clAmdBlasStatus (*clAmdBlasDtrmm)(clAmdBlasOrder, clAmdBlasSide, clAmdBlasUplo, clAmdBlasTranspose, clAmdBlasDiag, size_t, size_t, cl_double, const cl_mem, size_t, cl_mem, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn17<OPENCLAMDBLAS_FN_clAmdBlasDtrmm, clAmdBlasStatus, clAmdBlasOrder, clAmdBlasSide, clAmdBlasUplo, clAmdBlasTranspose, clAmdBlasDiag, size_t, size_t, cl_double, const cl_mem, size_t, cl_mem, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasDtrmm_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasDtrmm_definition = { "clAmdBlasDtrmm", (void**)&clAmdBlasDtrmm};
 
+//openclamdblas_fn19(OPENCLAMDBLAS_FN_clAmdBlasDtrmmEx, clAmdBlasStatus, (clAmdBlasOrder p1, clAmdBlasSide p2, clAmdBlasUplo p3, clAmdBlasTranspose p4, clAmdBlasDiag p5, size_t p6, size_t p7, cl_double p8, const cl_mem p9, size_t p10, size_t p11, cl_mem p12, size_t p13, size_t p14, cl_uint p15, cl_command_queue* p16, cl_uint p17, const cl_event* p18, cl_event* p19))
 //clAmdBlasStatus (*clAmdBlasDtrmmEx)(clAmdBlasOrder, clAmdBlasSide, clAmdBlasUplo, clAmdBlasTranspose, clAmdBlasDiag, size_t, size_t, cl_double, const cl_mem, size_t, size_t, cl_mem, size_t, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn19<OPENCLAMDBLAS_FN_clAmdBlasDtrmmEx, clAmdBlasStatus, clAmdBlasOrder, clAmdBlasSide, clAmdBlasUplo, clAmdBlasTranspose, clAmdBlasDiag, size_t, size_t, cl_double, const cl_mem, size_t, size_t, cl_mem, size_t, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasDtrmmEx_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasDtrmmEx_definition = { "clAmdBlasDtrmmEx", (void**)&clAmdBlasDtrmmEx};
 
+//openclamdblas_fn17(OPENCLAMDBLAS_FN_clAmdBlasDtrmv, clAmdBlasStatus, (clAmdBlasOrder p1, clAmdBlasUplo p2, clAmdBlasTranspose p3, clAmdBlasDiag p4, size_t p5, const cl_mem p6, size_t p7, size_t p8, cl_mem p9, size_t p10, int p11, cl_mem p12, cl_uint p13, cl_command_queue* p14, cl_uint p15, const cl_event* p16, cl_event* p17))
 //clAmdBlasStatus (*clAmdBlasDtrmv)(clAmdBlasOrder, clAmdBlasUplo, clAmdBlasTranspose, clAmdBlasDiag, size_t, const cl_mem, size_t, size_t, cl_mem, size_t, int, cl_mem, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn17<OPENCLAMDBLAS_FN_clAmdBlasDtrmv, clAmdBlasStatus, clAmdBlasOrder, clAmdBlasUplo, clAmdBlasTranspose, clAmdBlasDiag, size_t, const cl_mem, size_t, size_t, cl_mem, size_t, int, cl_mem, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasDtrmv_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasDtrmv_definition = { "clAmdBlasDtrmv", (void**)&clAmdBlasDtrmv};
 
+//openclamdblas_fn17(OPENCLAMDBLAS_FN_clAmdBlasDtrsm, clAmdBlasStatus, (clAmdBlasOrder p1, clAmdBlasSide p2, clAmdBlasUplo p3, clAmdBlasTranspose p4, clAmdBlasDiag p5, size_t p6, size_t p7, cl_double p8, const cl_mem p9, size_t p10, cl_mem p11, size_t p12, cl_uint p13, cl_command_queue* p14, cl_uint p15, const cl_event* p16, cl_event* p17))
 //clAmdBlasStatus (*clAmdBlasDtrsm)(clAmdBlasOrder, clAmdBlasSide, clAmdBlasUplo, clAmdBlasTranspose, clAmdBlasDiag, size_t, size_t, cl_double, const cl_mem, size_t, cl_mem, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn17<OPENCLAMDBLAS_FN_clAmdBlasDtrsm, clAmdBlasStatus, clAmdBlasOrder, clAmdBlasSide, clAmdBlasUplo, clAmdBlasTranspose, clAmdBlasDiag, size_t, size_t, cl_double, const cl_mem, size_t, cl_mem, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasDtrsm_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasDtrsm_definition = { "clAmdBlasDtrsm", (void**)&clAmdBlasDtrsm};
 
+//openclamdblas_fn19(OPENCLAMDBLAS_FN_clAmdBlasDtrsmEx, clAmdBlasStatus, (clAmdBlasOrder p1, clAmdBlasSide p2, clAmdBlasUplo p3, clAmdBlasTranspose p4, clAmdBlasDiag p5, size_t p6, size_t p7, cl_double p8, const cl_mem p9, size_t p10, size_t p11, cl_mem p12, size_t p13, size_t p14, cl_uint p15, cl_command_queue* p16, cl_uint p17, const cl_event* p18, cl_event* p19))
 //clAmdBlasStatus (*clAmdBlasDtrsmEx)(clAmdBlasOrder, clAmdBlasSide, clAmdBlasUplo, clAmdBlasTranspose, clAmdBlasDiag, size_t, size_t, cl_double, const cl_mem, size_t, size_t, cl_mem, size_t, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn19<OPENCLAMDBLAS_FN_clAmdBlasDtrsmEx, clAmdBlasStatus, clAmdBlasOrder, clAmdBlasSide, clAmdBlasUplo, clAmdBlasTranspose, clAmdBlasDiag, size_t, size_t, cl_double, const cl_mem, size_t, size_t, cl_mem, size_t, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasDtrsmEx_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasDtrsmEx_definition = { "clAmdBlasDtrsmEx", (void**)&clAmdBlasDtrsmEx};
 
+//openclamdblas_fn16(OPENCLAMDBLAS_FN_clAmdBlasDtrsv, clAmdBlasStatus, (clAmdBlasOrder p1, clAmdBlasUplo p2, clAmdBlasTranspose p3, clAmdBlasDiag p4, size_t p5, const cl_mem p6, size_t p7, size_t p8, cl_mem p9, size_t p10, int p11, cl_uint p12, cl_command_queue* p13, cl_uint p14, const cl_event* p15, cl_event* p16))
 //clAmdBlasStatus (*clAmdBlasDtrsv)(clAmdBlasOrder, clAmdBlasUplo, clAmdBlasTranspose, clAmdBlasDiag, size_t, const cl_mem, size_t, size_t, cl_mem, size_t, int, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn16<OPENCLAMDBLAS_FN_clAmdBlasDtrsv, clAmdBlasStatus, clAmdBlasOrder, clAmdBlasUplo, clAmdBlasTranspose, clAmdBlasDiag, size_t, const cl_mem, size_t, size_t, cl_mem, size_t, int, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasDtrsv_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasDtrsv_definition = { "clAmdBlasDtrsv", (void**)&clAmdBlasDtrsv};
 
+//openclamdblas_fn12(OPENCLAMDBLAS_FN_clAmdBlasDzasum, clAmdBlasStatus, (size_t p1, cl_mem p2, size_t p3, const cl_mem p4, size_t p5, int p6, cl_mem p7, cl_uint p8, cl_command_queue* p9, cl_uint p10, const cl_event* p11, cl_event* p12))
 //clAmdBlasStatus (*clAmdBlasDzasum)(size_t, cl_mem, size_t, const cl_mem, size_t, int, cl_mem, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn12<OPENCLAMDBLAS_FN_clAmdBlasDzasum, clAmdBlasStatus, size_t, cl_mem, size_t, const cl_mem, size_t, int, cl_mem, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasDzasum_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasDzasum_definition = { "clAmdBlasDzasum", (void**)&clAmdBlasDzasum};
 
+//openclamdblas_fn12(OPENCLAMDBLAS_FN_clAmdBlasDznrm2, clAmdBlasStatus, (size_t p1, cl_mem p2, size_t p3, const cl_mem p4, size_t p5, int p6, cl_mem p7, cl_uint p8, cl_command_queue* p9, cl_uint p10, const cl_event* p11, cl_event* p12))
 //clAmdBlasStatus (*clAmdBlasDznrm2)(size_t, cl_mem, size_t, const cl_mem, size_t, int, cl_mem, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn12<OPENCLAMDBLAS_FN_clAmdBlasDznrm2, clAmdBlasStatus, size_t, cl_mem, size_t, const cl_mem, size_t, int, cl_mem, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasDznrm2_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasDznrm2_definition = { "clAmdBlasDznrm2", (void**)&clAmdBlasDznrm2};
 
+//openclamdblas_fn3(OPENCLAMDBLAS_FN_clAmdBlasGetVersion, clAmdBlasStatus, (cl_uint* p1, cl_uint* p2, cl_uint* p3))
 //clAmdBlasStatus (*clAmdBlasGetVersion)(cl_uint*, cl_uint*, cl_uint*) =
-//        openclamdblas_fn3<OPENCLAMDBLAS_FN_clAmdBlasGetVersion, clAmdBlasStatus, cl_uint*, cl_uint*, cl_uint*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasGetVersion_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasGetVersion_definition = { "clAmdBlasGetVersion", (void**)&clAmdBlasGetVersion};
 
+//openclamdblas_fn1(OPENCLAMDBLAS_FN_clAmdBlasRemoveScratchImage, clAmdBlasStatus, (cl_ulong p1))
 //clAmdBlasStatus (*clAmdBlasRemoveScratchImage)(cl_ulong) =
-//        openclamdblas_fn1<OPENCLAMDBLAS_FN_clAmdBlasRemoveScratchImage, clAmdBlasStatus, cl_ulong>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasRemoveScratchImage_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasRemoveScratchImage_definition = { "clAmdBlasRemoveScratchImage", (void**)&clAmdBlasRemoveScratchImage};
 
+//openclamdblas_fn12(OPENCLAMDBLAS_FN_clAmdBlasSasum, clAmdBlasStatus, (size_t p1, cl_mem p2, size_t p3, const cl_mem p4, size_t p5, int p6, cl_mem p7, cl_uint p8, cl_command_queue* p9, cl_uint p10, const cl_event* p11, cl_event* p12))
 //clAmdBlasStatus (*clAmdBlasSasum)(size_t, cl_mem, size_t, const cl_mem, size_t, int, cl_mem, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn12<OPENCLAMDBLAS_FN_clAmdBlasSasum, clAmdBlasStatus, size_t, cl_mem, size_t, const cl_mem, size_t, int, cl_mem, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasSasum_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasSasum_definition = { "clAmdBlasSasum", (void**)&clAmdBlasSasum};
 
+//openclamdblas_fn13(OPENCLAMDBLAS_FN_clAmdBlasSaxpy, clAmdBlasStatus, (size_t p1, cl_float p2, const cl_mem p3, size_t p4, int p5, cl_mem p6, size_t p7, int p8, cl_uint p9, cl_command_queue* p10, cl_uint p11, const cl_event* p12, cl_event* p13))
 //clAmdBlasStatus (*clAmdBlasSaxpy)(size_t, cl_float, const cl_mem, size_t, int, cl_mem, size_t, int, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn13<OPENCLAMDBLAS_FN_clAmdBlasSaxpy, clAmdBlasStatus, size_t, cl_float, const cl_mem, size_t, int, cl_mem, size_t, int, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasSaxpy_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasSaxpy_definition = { "clAmdBlasSaxpy", (void**)&clAmdBlasSaxpy};
 
+//openclamdblas_fn12(OPENCLAMDBLAS_FN_clAmdBlasScasum, clAmdBlasStatus, (size_t p1, cl_mem p2, size_t p3, const cl_mem p4, size_t p5, int p6, cl_mem p7, cl_uint p8, cl_command_queue* p9, cl_uint p10, const cl_event* p11, cl_event* p12))
 //clAmdBlasStatus (*clAmdBlasScasum)(size_t, cl_mem, size_t, const cl_mem, size_t, int, cl_mem, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn12<OPENCLAMDBLAS_FN_clAmdBlasScasum, clAmdBlasStatus, size_t, cl_mem, size_t, const cl_mem, size_t, int, cl_mem, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasScasum_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasScasum_definition = { "clAmdBlasScasum", (void**)&clAmdBlasScasum};
 
+//openclamdblas_fn12(OPENCLAMDBLAS_FN_clAmdBlasScnrm2, clAmdBlasStatus, (size_t p1, cl_mem p2, size_t p3, const cl_mem p4, size_t p5, int p6, cl_mem p7, cl_uint p8, cl_command_queue* p9, cl_uint p10, const cl_event* p11, cl_event* p12))
 //clAmdBlasStatus (*clAmdBlasScnrm2)(size_t, cl_mem, size_t, const cl_mem, size_t, int, cl_mem, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn12<OPENCLAMDBLAS_FN_clAmdBlasScnrm2, clAmdBlasStatus, size_t, cl_mem, size_t, const cl_mem, size_t, int, cl_mem, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasScnrm2_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasScnrm2_definition = { "clAmdBlasScnrm2", (void**)&clAmdBlasScnrm2};
 
+//openclamdblas_fn12(OPENCLAMDBLAS_FN_clAmdBlasScopy, clAmdBlasStatus, (size_t p1, const cl_mem p2, size_t p3, int p4, cl_mem p5, size_t p6, int p7, cl_uint p8, cl_command_queue* p9, cl_uint p10, const cl_event* p11, cl_event* p12))
 //clAmdBlasStatus (*clAmdBlasScopy)(size_t, const cl_mem, size_t, int, cl_mem, size_t, int, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn12<OPENCLAMDBLAS_FN_clAmdBlasScopy, clAmdBlasStatus, size_t, const cl_mem, size_t, int, cl_mem, size_t, int, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasScopy_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasScopy_definition = { "clAmdBlasScopy", (void**)&clAmdBlasScopy};
 
+//openclamdblas_fn15(OPENCLAMDBLAS_FN_clAmdBlasSdot, clAmdBlasStatus, (size_t p1, cl_mem p2, size_t p3, const cl_mem p4, size_t p5, int p6, const cl_mem p7, size_t p8, int p9, cl_mem p10, cl_uint p11, cl_command_queue* p12, cl_uint p13, const cl_event* p14, cl_event* p15))
 //clAmdBlasStatus (*clAmdBlasSdot)(size_t, cl_mem, size_t, const cl_mem, size_t, int, const cl_mem, size_t, int, cl_mem, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn15<OPENCLAMDBLAS_FN_clAmdBlasSdot, clAmdBlasStatus, size_t, cl_mem, size_t, const cl_mem, size_t, int, const cl_mem, size_t, int, cl_mem, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasSdot_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasSdot_definition = { "clAmdBlasSdot", (void**)&clAmdBlasSdot};
 
+openclamdblas_fn0(OPENCLAMDBLAS_FN_clAmdBlasSetup, clAmdBlasStatus, ())
 clAmdBlasStatus (*clAmdBlasSetup)() =
-        openclamdblas_fn0<OPENCLAMDBLAS_FN_clAmdBlasSetup, clAmdBlasStatus>::switch_fn;
+        OPENCLAMDBLAS_FN_clAmdBlasSetup_switch_fn;
 static const struct DynamicFnEntry clAmdBlasSetup_definition = { "clAmdBlasSetup", (void**)&clAmdBlasSetup};
 
+//openclamdblas_fn22(OPENCLAMDBLAS_FN_clAmdBlasSgbmv, clAmdBlasStatus, (clAmdBlasOrder p1, clAmdBlasTranspose p2, size_t p3, size_t p4, size_t p5, size_t p6, cl_float p7, const cl_mem p8, size_t p9, size_t p10, const cl_mem p11, size_t p12, int p13, cl_float p14, cl_mem p15, size_t p16, int p17, cl_uint p18, cl_command_queue* p19, cl_uint p20, const cl_event* p21, cl_event* p22))
 //clAmdBlasStatus (*clAmdBlasSgbmv)(clAmdBlasOrder, clAmdBlasTranspose, size_t, size_t, size_t, size_t, cl_float, const cl_mem, size_t, size_t, const cl_mem, size_t, int, cl_float, cl_mem, size_t, int, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn22<OPENCLAMDBLAS_FN_clAmdBlasSgbmv, clAmdBlasStatus, clAmdBlasOrder, clAmdBlasTranspose, size_t, size_t, size_t, size_t, cl_float, const cl_mem, size_t, size_t, const cl_mem, size_t, int, cl_float, cl_mem, size_t, int, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasSgbmv_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasSgbmv_definition = { "clAmdBlasSgbmv", (void**)&clAmdBlasSgbmv};
 
+//openclamdblas_fn19(OPENCLAMDBLAS_FN_clAmdBlasSgemm, clAmdBlasStatus, (clAmdBlasOrder p1, clAmdBlasTranspose p2, clAmdBlasTranspose p3, size_t p4, size_t p5, size_t p6, cl_float p7, const cl_mem p8, size_t p9, const cl_mem p10, size_t p11, cl_float p12, cl_mem p13, size_t p14, cl_uint p15, cl_command_queue* p16, cl_uint p17, const cl_event* p18, cl_event* p19))
 //clAmdBlasStatus (*clAmdBlasSgemm)(clAmdBlasOrder, clAmdBlasTranspose, clAmdBlasTranspose, size_t, size_t, size_t, cl_float, const cl_mem, size_t, const cl_mem, size_t, cl_float, cl_mem, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn19<OPENCLAMDBLAS_FN_clAmdBlasSgemm, clAmdBlasStatus, clAmdBlasOrder, clAmdBlasTranspose, clAmdBlasTranspose, size_t, size_t, size_t, cl_float, const cl_mem, size_t, const cl_mem, size_t, cl_float, cl_mem, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasSgemm_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasSgemm_definition = { "clAmdBlasSgemm", (void**)&clAmdBlasSgemm};
 
+openclamdblas_fn22(OPENCLAMDBLAS_FN_clAmdBlasSgemmEx, clAmdBlasStatus, (clAmdBlasOrder p1, clAmdBlasTranspose p2, clAmdBlasTranspose p3, size_t p4, size_t p5, size_t p6, cl_float p7, const cl_mem p8, size_t p9, size_t p10, const cl_mem p11, size_t p12, size_t p13, cl_float p14, cl_mem p15, size_t p16, size_t p17, cl_uint p18, cl_command_queue* p19, cl_uint p20, const cl_event* p21, cl_event* p22))
 clAmdBlasStatus (*clAmdBlasSgemmEx)(clAmdBlasOrder, clAmdBlasTranspose, clAmdBlasTranspose, size_t, size_t, size_t, cl_float, const cl_mem, size_t, size_t, const cl_mem, size_t, size_t, cl_float, cl_mem, size_t, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-        openclamdblas_fn22<OPENCLAMDBLAS_FN_clAmdBlasSgemmEx, clAmdBlasStatus, clAmdBlasOrder, clAmdBlasTranspose, clAmdBlasTranspose, size_t, size_t, size_t, cl_float, const cl_mem, size_t, size_t, const cl_mem, size_t, size_t, cl_float, cl_mem, size_t, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+        OPENCLAMDBLAS_FN_clAmdBlasSgemmEx_switch_fn;
 static const struct DynamicFnEntry clAmdBlasSgemmEx_definition = { "clAmdBlasSgemmEx", (void**)&clAmdBlasSgemmEx};
 
+//openclamdblas_fn19(OPENCLAMDBLAS_FN_clAmdBlasSgemv, clAmdBlasStatus, (clAmdBlasOrder p1, clAmdBlasTranspose p2, size_t p3, size_t p4, cl_float p5, const cl_mem p6, size_t p7, const cl_mem p8, size_t p9, int p10, cl_float p11, cl_mem p12, size_t p13, int p14, cl_uint p15, cl_command_queue* p16, cl_uint p17, const cl_event* p18, cl_event* p19))
 //clAmdBlasStatus (*clAmdBlasSgemv)(clAmdBlasOrder, clAmdBlasTranspose, size_t, size_t, cl_float, const cl_mem, size_t, const cl_mem, size_t, int, cl_float, cl_mem, size_t, int, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn19<OPENCLAMDBLAS_FN_clAmdBlasSgemv, clAmdBlasStatus, clAmdBlasOrder, clAmdBlasTranspose, size_t, size_t, cl_float, const cl_mem, size_t, const cl_mem, size_t, int, cl_float, cl_mem, size_t, int, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasSgemv_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasSgemv_definition = { "clAmdBlasSgemv", (void**)&clAmdBlasSgemv};
 
+//openclamdblas_fn20(OPENCLAMDBLAS_FN_clAmdBlasSgemvEx, clAmdBlasStatus, (clAmdBlasOrder p1, clAmdBlasTranspose p2, size_t p3, size_t p4, cl_float p5, const cl_mem p6, size_t p7, size_t p8, const cl_mem p9, size_t p10, int p11, cl_float p12, cl_mem p13, size_t p14, int p15, cl_uint p16, cl_command_queue* p17, cl_uint p18, const cl_event* p19, cl_event* p20))
 //clAmdBlasStatus (*clAmdBlasSgemvEx)(clAmdBlasOrder, clAmdBlasTranspose, size_t, size_t, cl_float, const cl_mem, size_t, size_t, const cl_mem, size_t, int, cl_float, cl_mem, size_t, int, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn20<OPENCLAMDBLAS_FN_clAmdBlasSgemvEx, clAmdBlasStatus, clAmdBlasOrder, clAmdBlasTranspose, size_t, size_t, cl_float, const cl_mem, size_t, size_t, const cl_mem, size_t, int, cl_float, cl_mem, size_t, int, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasSgemvEx_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasSgemvEx_definition = { "clAmdBlasSgemvEx", (void**)&clAmdBlasSgemvEx};
 
+//openclamdblas_fn18(OPENCLAMDBLAS_FN_clAmdBlasSger, clAmdBlasStatus, (clAmdBlasOrder p1, size_t p2, size_t p3, cl_float p4, const cl_mem p5, size_t p6, int p7, const cl_mem p8, size_t p9, int p10, cl_mem p11, size_t p12, size_t p13, cl_uint p14, cl_command_queue* p15, cl_uint p16, const cl_event* p17, cl_event* p18))
 //clAmdBlasStatus (*clAmdBlasSger)(clAmdBlasOrder, size_t, size_t, cl_float, const cl_mem, size_t, int, const cl_mem, size_t, int, cl_mem, size_t, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn18<OPENCLAMDBLAS_FN_clAmdBlasSger, clAmdBlasStatus, clAmdBlasOrder, size_t, size_t, cl_float, const cl_mem, size_t, int, const cl_mem, size_t, int, cl_mem, size_t, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasSger_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasSger_definition = { "clAmdBlasSger", (void**)&clAmdBlasSger};
 
+//openclamdblas_fn12(OPENCLAMDBLAS_FN_clAmdBlasSnrm2, clAmdBlasStatus, (size_t p1, cl_mem p2, size_t p3, const cl_mem p4, size_t p5, int p6, cl_mem p7, cl_uint p8, cl_command_queue* p9, cl_uint p10, const cl_event* p11, cl_event* p12))
 //clAmdBlasStatus (*clAmdBlasSnrm2)(size_t, cl_mem, size_t, const cl_mem, size_t, int, cl_mem, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn12<OPENCLAMDBLAS_FN_clAmdBlasSnrm2, clAmdBlasStatus, size_t, cl_mem, size_t, const cl_mem, size_t, int, cl_mem, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasSnrm2_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasSnrm2_definition = { "clAmdBlasSnrm2", (void**)&clAmdBlasSnrm2};
 
+//openclamdblas_fn14(OPENCLAMDBLAS_FN_clAmdBlasSrot, clAmdBlasStatus, (size_t p1, cl_mem p2, size_t p3, int p4, cl_mem p5, size_t p6, int p7, cl_float p8, cl_float p9, cl_uint p10, cl_command_queue* p11, cl_uint p12, const cl_event* p13, cl_event* p14))
 //clAmdBlasStatus (*clAmdBlasSrot)(size_t, cl_mem, size_t, int, cl_mem, size_t, int, cl_float, cl_float, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn14<OPENCLAMDBLAS_FN_clAmdBlasSrot, clAmdBlasStatus, size_t, cl_mem, size_t, int, cl_mem, size_t, int, cl_float, cl_float, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasSrot_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasSrot_definition = { "clAmdBlasSrot", (void**)&clAmdBlasSrot};
 
+//openclamdblas_fn13(OPENCLAMDBLAS_FN_clAmdBlasSrotg, clAmdBlasStatus, (cl_mem p1, size_t p2, cl_mem p3, size_t p4, cl_mem p5, size_t p6, cl_mem p7, size_t p8, cl_uint p9, cl_command_queue* p10, cl_uint p11, const cl_event* p12, cl_event* p13))
 //clAmdBlasStatus (*clAmdBlasSrotg)(cl_mem, size_t, cl_mem, size_t, cl_mem, size_t, cl_mem, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn13<OPENCLAMDBLAS_FN_clAmdBlasSrotg, clAmdBlasStatus, cl_mem, size_t, cl_mem, size_t, cl_mem, size_t, cl_mem, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasSrotg_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasSrotg_definition = { "clAmdBlasSrotg", (void**)&clAmdBlasSrotg};
 
+//openclamdblas_fn14(OPENCLAMDBLAS_FN_clAmdBlasSrotm, clAmdBlasStatus, (size_t p1, cl_mem p2, size_t p3, int p4, cl_mem p5, size_t p6, int p7, const cl_mem p8, size_t p9, cl_uint p10, cl_command_queue* p11, cl_uint p12, const cl_event* p13, cl_event* p14))
 //clAmdBlasStatus (*clAmdBlasSrotm)(size_t, cl_mem, size_t, int, cl_mem, size_t, int, const cl_mem, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn14<OPENCLAMDBLAS_FN_clAmdBlasSrotm, clAmdBlasStatus, size_t, cl_mem, size_t, int, cl_mem, size_t, int, const cl_mem, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasSrotm_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasSrotm_definition = { "clAmdBlasSrotm", (void**)&clAmdBlasSrotm};
 
+//openclamdblas_fn15(OPENCLAMDBLAS_FN_clAmdBlasSrotmg, clAmdBlasStatus, (cl_mem p1, size_t p2, cl_mem p3, size_t p4, cl_mem p5, size_t p6, const cl_mem p7, size_t p8, cl_mem p9, size_t p10, cl_uint p11, cl_command_queue* p12, cl_uint p13, const cl_event* p14, cl_event* p15))
 //clAmdBlasStatus (*clAmdBlasSrotmg)(cl_mem, size_t, cl_mem, size_t, cl_mem, size_t, const cl_mem, size_t, cl_mem, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn15<OPENCLAMDBLAS_FN_clAmdBlasSrotmg, clAmdBlasStatus, cl_mem, size_t, cl_mem, size_t, cl_mem, size_t, const cl_mem, size_t, cl_mem, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasSrotmg_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasSrotmg_definition = { "clAmdBlasSrotmg", (void**)&clAmdBlasSrotmg};
 
+//openclamdblas_fn20(OPENCLAMDBLAS_FN_clAmdBlasSsbmv, clAmdBlasStatus, (clAmdBlasOrder p1, clAmdBlasUplo p2, size_t p3, size_t p4, cl_float p5, const cl_mem p6, size_t p7, size_t p8, const cl_mem p9, size_t p10, int p11, cl_float p12, cl_mem p13, size_t p14, int p15, cl_uint p16, cl_command_queue* p17, cl_uint p18, const cl_event* p19, cl_event* p20))
 //clAmdBlasStatus (*clAmdBlasSsbmv)(clAmdBlasOrder, clAmdBlasUplo, size_t, size_t, cl_float, const cl_mem, size_t, size_t, const cl_mem, size_t, int, cl_float, cl_mem, size_t, int, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn20<OPENCLAMDBLAS_FN_clAmdBlasSsbmv, clAmdBlasStatus, clAmdBlasOrder, clAmdBlasUplo, size_t, size_t, cl_float, const cl_mem, size_t, size_t, const cl_mem, size_t, int, cl_float, cl_mem, size_t, int, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasSsbmv_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasSsbmv_definition = { "clAmdBlasSsbmv", (void**)&clAmdBlasSsbmv};
 
+//openclamdblas_fn10(OPENCLAMDBLAS_FN_clAmdBlasSscal, clAmdBlasStatus, (size_t p1, cl_float p2, cl_mem p3, size_t p4, int p5, cl_uint p6, cl_command_queue* p7, cl_uint p8, const cl_event* p9, cl_event* p10))
 //clAmdBlasStatus (*clAmdBlasSscal)(size_t, cl_float, cl_mem, size_t, int, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn10<OPENCLAMDBLAS_FN_clAmdBlasSscal, clAmdBlasStatus, size_t, cl_float, cl_mem, size_t, int, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasSscal_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasSscal_definition = { "clAmdBlasSscal", (void**)&clAmdBlasSscal};
 
+//openclamdblas_fn18(OPENCLAMDBLAS_FN_clAmdBlasSspmv, clAmdBlasStatus, (clAmdBlasOrder p1, clAmdBlasUplo p2, size_t p3, cl_float p4, const cl_mem p5, size_t p6, const cl_mem p7, size_t p8, int p9, cl_float p10, cl_mem p11, size_t p12, int p13, cl_uint p14, cl_command_queue* p15, cl_uint p16, const cl_event* p17, cl_event* p18))
 //clAmdBlasStatus (*clAmdBlasSspmv)(clAmdBlasOrder, clAmdBlasUplo, size_t, cl_float, const cl_mem, size_t, const cl_mem, size_t, int, cl_float, cl_mem, size_t, int, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn18<OPENCLAMDBLAS_FN_clAmdBlasSspmv, clAmdBlasStatus, clAmdBlasOrder, clAmdBlasUplo, size_t, cl_float, const cl_mem, size_t, const cl_mem, size_t, int, cl_float, cl_mem, size_t, int, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasSspmv_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasSspmv_definition = { "clAmdBlasSspmv", (void**)&clAmdBlasSspmv};
 
+//openclamdblas_fn14(OPENCLAMDBLAS_FN_clAmdBlasSspr, clAmdBlasStatus, (clAmdBlasOrder p1, clAmdBlasUplo p2, size_t p3, cl_float p4, const cl_mem p5, size_t p6, int p7, cl_mem p8, size_t p9, cl_uint p10, cl_command_queue* p11, cl_uint p12, const cl_event* p13, cl_event* p14))
 //clAmdBlasStatus (*clAmdBlasSspr)(clAmdBlasOrder, clAmdBlasUplo, size_t, cl_float, const cl_mem, size_t, int, cl_mem, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn14<OPENCLAMDBLAS_FN_clAmdBlasSspr, clAmdBlasStatus, clAmdBlasOrder, clAmdBlasUplo, size_t, cl_float, const cl_mem, size_t, int, cl_mem, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasSspr_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasSspr_definition = { "clAmdBlasSspr", (void**)&clAmdBlasSspr};
 
+//openclamdblas_fn17(OPENCLAMDBLAS_FN_clAmdBlasSspr2, clAmdBlasStatus, (clAmdBlasOrder p1, clAmdBlasUplo p2, size_t p3, cl_float p4, const cl_mem p5, size_t p6, int p7, const cl_mem p8, size_t p9, int p10, cl_mem p11, size_t p12, cl_uint p13, cl_command_queue* p14, cl_uint p15, const cl_event* p16, cl_event* p17))
 //clAmdBlasStatus (*clAmdBlasSspr2)(clAmdBlasOrder, clAmdBlasUplo, size_t, cl_float, const cl_mem, size_t, int, const cl_mem, size_t, int, cl_mem, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn17<OPENCLAMDBLAS_FN_clAmdBlasSspr2, clAmdBlasStatus, clAmdBlasOrder, clAmdBlasUplo, size_t, cl_float, const cl_mem, size_t, int, const cl_mem, size_t, int, cl_mem, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasSspr2_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasSspr2_definition = { "clAmdBlasSspr2", (void**)&clAmdBlasSspr2};
 
+//openclamdblas_fn12(OPENCLAMDBLAS_FN_clAmdBlasSswap, clAmdBlasStatus, (size_t p1, cl_mem p2, size_t p3, int p4, cl_mem p5, size_t p6, int p7, cl_uint p8, cl_command_queue* p9, cl_uint p10, const cl_event* p11, cl_event* p12))
 //clAmdBlasStatus (*clAmdBlasSswap)(size_t, cl_mem, size_t, int, cl_mem, size_t, int, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn12<OPENCLAMDBLAS_FN_clAmdBlasSswap, clAmdBlasStatus, size_t, cl_mem, size_t, int, cl_mem, size_t, int, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasSswap_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasSswap_definition = { "clAmdBlasSswap", (void**)&clAmdBlasSswap};
 
+//openclamdblas_fn21(OPENCLAMDBLAS_FN_clAmdBlasSsymm, clAmdBlasStatus, (clAmdBlasOrder p1, clAmdBlasSide p2, clAmdBlasUplo p3, size_t p4, size_t p5, cl_float p6, const cl_mem p7, size_t p8, size_t p9, const cl_mem p10, size_t p11, size_t p12, cl_float p13, cl_mem p14, size_t p15, size_t p16, cl_uint p17, cl_command_queue* p18, cl_uint p19, const cl_event* p20, cl_event* p21))
 //clAmdBlasStatus (*clAmdBlasSsymm)(clAmdBlasOrder, clAmdBlasSide, clAmdBlasUplo, size_t, size_t, cl_float, const cl_mem, size_t, size_t, const cl_mem, size_t, size_t, cl_float, cl_mem, size_t, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn21<OPENCLAMDBLAS_FN_clAmdBlasSsymm, clAmdBlasStatus, clAmdBlasOrder, clAmdBlasSide, clAmdBlasUplo, size_t, size_t, cl_float, const cl_mem, size_t, size_t, const cl_mem, size_t, size_t, cl_float, cl_mem, size_t, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasSsymm_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasSsymm_definition = { "clAmdBlasSsymm", (void**)&clAmdBlasSsymm};
 
+//openclamdblas_fn18(OPENCLAMDBLAS_FN_clAmdBlasSsymv, clAmdBlasStatus, (clAmdBlasOrder p1, clAmdBlasUplo p2, size_t p3, cl_float p4, const cl_mem p5, size_t p6, const cl_mem p7, size_t p8, int p9, cl_float p10, cl_mem p11, size_t p12, int p13, cl_uint p14, cl_command_queue* p15, cl_uint p16, const cl_event* p17, cl_event* p18))
 //clAmdBlasStatus (*clAmdBlasSsymv)(clAmdBlasOrder, clAmdBlasUplo, size_t, cl_float, const cl_mem, size_t, const cl_mem, size_t, int, cl_float, cl_mem, size_t, int, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn18<OPENCLAMDBLAS_FN_clAmdBlasSsymv, clAmdBlasStatus, clAmdBlasOrder, clAmdBlasUplo, size_t, cl_float, const cl_mem, size_t, const cl_mem, size_t, int, cl_float, cl_mem, size_t, int, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasSsymv_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasSsymv_definition = { "clAmdBlasSsymv", (void**)&clAmdBlasSsymv};
 
+//openclamdblas_fn19(OPENCLAMDBLAS_FN_clAmdBlasSsymvEx, clAmdBlasStatus, (clAmdBlasOrder p1, clAmdBlasUplo p2, size_t p3, cl_float p4, const cl_mem p5, size_t p6, size_t p7, const cl_mem p8, size_t p9, int p10, cl_float p11, cl_mem p12, size_t p13, int p14, cl_uint p15, cl_command_queue* p16, cl_uint p17, const cl_event* p18, cl_event* p19))
 //clAmdBlasStatus (*clAmdBlasSsymvEx)(clAmdBlasOrder, clAmdBlasUplo, size_t, cl_float, const cl_mem, size_t, size_t, const cl_mem, size_t, int, cl_float, cl_mem, size_t, int, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn19<OPENCLAMDBLAS_FN_clAmdBlasSsymvEx, clAmdBlasStatus, clAmdBlasOrder, clAmdBlasUplo, size_t, cl_float, const cl_mem, size_t, size_t, const cl_mem, size_t, int, cl_float, cl_mem, size_t, int, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasSsymvEx_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasSsymvEx_definition = { "clAmdBlasSsymvEx", (void**)&clAmdBlasSsymvEx};
 
+//openclamdblas_fn15(OPENCLAMDBLAS_FN_clAmdBlasSsyr, clAmdBlasStatus, (clAmdBlasOrder p1, clAmdBlasUplo p2, size_t p3, cl_float p4, const cl_mem p5, size_t p6, int p7, cl_mem p8, size_t p9, size_t p10, cl_uint p11, cl_command_queue* p12, cl_uint p13, const cl_event* p14, cl_event* p15))
 //clAmdBlasStatus (*clAmdBlasSsyr)(clAmdBlasOrder, clAmdBlasUplo, size_t, cl_float, const cl_mem, size_t, int, cl_mem, size_t, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn15<OPENCLAMDBLAS_FN_clAmdBlasSsyr, clAmdBlasStatus, clAmdBlasOrder, clAmdBlasUplo, size_t, cl_float, const cl_mem, size_t, int, cl_mem, size_t, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasSsyr_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasSsyr_definition = { "clAmdBlasSsyr", (void**)&clAmdBlasSsyr};
 
+//openclamdblas_fn18(OPENCLAMDBLAS_FN_clAmdBlasSsyr2, clAmdBlasStatus, (clAmdBlasOrder p1, clAmdBlasUplo p2, size_t p3, cl_float p4, const cl_mem p5, size_t p6, int p7, const cl_mem p8, size_t p9, int p10, cl_mem p11, size_t p12, size_t p13, cl_uint p14, cl_command_queue* p15, cl_uint p16, const cl_event* p17, cl_event* p18))
 //clAmdBlasStatus (*clAmdBlasSsyr2)(clAmdBlasOrder, clAmdBlasUplo, size_t, cl_float, const cl_mem, size_t, int, const cl_mem, size_t, int, cl_mem, size_t, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn18<OPENCLAMDBLAS_FN_clAmdBlasSsyr2, clAmdBlasStatus, clAmdBlasOrder, clAmdBlasUplo, size_t, cl_float, const cl_mem, size_t, int, const cl_mem, size_t, int, cl_mem, size_t, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasSsyr2_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasSsyr2_definition = { "clAmdBlasSsyr2", (void**)&clAmdBlasSsyr2};
 
+//openclamdblas_fn18(OPENCLAMDBLAS_FN_clAmdBlasSsyr2k, clAmdBlasStatus, (clAmdBlasOrder p1, clAmdBlasUplo p2, clAmdBlasTranspose p3, size_t p4, size_t p5, cl_float p6, const cl_mem p7, size_t p8, const cl_mem p9, size_t p10, cl_float p11, cl_mem p12, size_t p13, cl_uint p14, cl_command_queue* p15, cl_uint p16, const cl_event* p17, cl_event* p18))
 //clAmdBlasStatus (*clAmdBlasSsyr2k)(clAmdBlasOrder, clAmdBlasUplo, clAmdBlasTranspose, size_t, size_t, cl_float, const cl_mem, size_t, const cl_mem, size_t, cl_float, cl_mem, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn18<OPENCLAMDBLAS_FN_clAmdBlasSsyr2k, clAmdBlasStatus, clAmdBlasOrder, clAmdBlasUplo, clAmdBlasTranspose, size_t, size_t, cl_float, const cl_mem, size_t, const cl_mem, size_t, cl_float, cl_mem, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasSsyr2k_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasSsyr2k_definition = { "clAmdBlasSsyr2k", (void**)&clAmdBlasSsyr2k};
 
+//openclamdblas_fn21(OPENCLAMDBLAS_FN_clAmdBlasSsyr2kEx, clAmdBlasStatus, (clAmdBlasOrder p1, clAmdBlasUplo p2, clAmdBlasTranspose p3, size_t p4, size_t p5, cl_float p6, const cl_mem p7, size_t p8, size_t p9, const cl_mem p10, size_t p11, size_t p12, cl_float p13, cl_mem p14, size_t p15, size_t p16, cl_uint p17, cl_command_queue* p18, cl_uint p19, const cl_event* p20, cl_event* p21))
 //clAmdBlasStatus (*clAmdBlasSsyr2kEx)(clAmdBlasOrder, clAmdBlasUplo, clAmdBlasTranspose, size_t, size_t, cl_float, const cl_mem, size_t, size_t, const cl_mem, size_t, size_t, cl_float, cl_mem, size_t, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn21<OPENCLAMDBLAS_FN_clAmdBlasSsyr2kEx, clAmdBlasStatus, clAmdBlasOrder, clAmdBlasUplo, clAmdBlasTranspose, size_t, size_t, cl_float, const cl_mem, size_t, size_t, const cl_mem, size_t, size_t, cl_float, cl_mem, size_t, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasSsyr2kEx_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasSsyr2kEx_definition = { "clAmdBlasSsyr2kEx", (void**)&clAmdBlasSsyr2kEx};
 
+//openclamdblas_fn16(OPENCLAMDBLAS_FN_clAmdBlasSsyrk, clAmdBlasStatus, (clAmdBlasOrder p1, clAmdBlasUplo p2, clAmdBlasTranspose p3, size_t p4, size_t p5, cl_float p6, const cl_mem p7, size_t p8, cl_float p9, cl_mem p10, size_t p11, cl_uint p12, cl_command_queue* p13, cl_uint p14, const cl_event* p15, cl_event* p16))
 //clAmdBlasStatus (*clAmdBlasSsyrk)(clAmdBlasOrder, clAmdBlasUplo, clAmdBlasTranspose, size_t, size_t, cl_float, const cl_mem, size_t, cl_float, cl_mem, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn16<OPENCLAMDBLAS_FN_clAmdBlasSsyrk, clAmdBlasStatus, clAmdBlasOrder, clAmdBlasUplo, clAmdBlasTranspose, size_t, size_t, cl_float, const cl_mem, size_t, cl_float, cl_mem, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasSsyrk_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasSsyrk_definition = { "clAmdBlasSsyrk", (void**)&clAmdBlasSsyrk};
 
+//openclamdblas_fn18(OPENCLAMDBLAS_FN_clAmdBlasSsyrkEx, clAmdBlasStatus, (clAmdBlasOrder p1, clAmdBlasUplo p2, clAmdBlasTranspose p3, size_t p4, size_t p5, cl_float p6, const cl_mem p7, size_t p8, size_t p9, cl_float p10, cl_mem p11, size_t p12, size_t p13, cl_uint p14, cl_command_queue* p15, cl_uint p16, const cl_event* p17, cl_event* p18))
 //clAmdBlasStatus (*clAmdBlasSsyrkEx)(clAmdBlasOrder, clAmdBlasUplo, clAmdBlasTranspose, size_t, size_t, cl_float, const cl_mem, size_t, size_t, cl_float, cl_mem, size_t, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn18<OPENCLAMDBLAS_FN_clAmdBlasSsyrkEx, clAmdBlasStatus, clAmdBlasOrder, clAmdBlasUplo, clAmdBlasTranspose, size_t, size_t, cl_float, const cl_mem, size_t, size_t, cl_float, cl_mem, size_t, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasSsyrkEx_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasSsyrkEx_definition = { "clAmdBlasSsyrkEx", (void**)&clAmdBlasSsyrkEx};
 
+//openclamdblas_fn18(OPENCLAMDBLAS_FN_clAmdBlasStbmv, clAmdBlasStatus, (clAmdBlasOrder p1, clAmdBlasUplo p2, clAmdBlasTranspose p3, clAmdBlasDiag p4, size_t p5, size_t p6, const cl_mem p7, size_t p8, size_t p9, cl_mem p10, size_t p11, int p12, cl_mem p13, cl_uint p14, cl_command_queue* p15, cl_uint p16, const cl_event* p17, cl_event* p18))
 //clAmdBlasStatus (*clAmdBlasStbmv)(clAmdBlasOrder, clAmdBlasUplo, clAmdBlasTranspose, clAmdBlasDiag, size_t, size_t, const cl_mem, size_t, size_t, cl_mem, size_t, int, cl_mem, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn18<OPENCLAMDBLAS_FN_clAmdBlasStbmv, clAmdBlasStatus, clAmdBlasOrder, clAmdBlasUplo, clAmdBlasTranspose, clAmdBlasDiag, size_t, size_t, const cl_mem, size_t, size_t, cl_mem, size_t, int, cl_mem, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasStbmv_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasStbmv_definition = { "clAmdBlasStbmv", (void**)&clAmdBlasStbmv};
 
+//openclamdblas_fn17(OPENCLAMDBLAS_FN_clAmdBlasStbsv, clAmdBlasStatus, (clAmdBlasOrder p1, clAmdBlasUplo p2, clAmdBlasTranspose p3, clAmdBlasDiag p4, size_t p5, size_t p6, const cl_mem p7, size_t p8, size_t p9, cl_mem p10, size_t p11, int p12, cl_uint p13, cl_command_queue* p14, cl_uint p15, const cl_event* p16, cl_event* p17))
 //clAmdBlasStatus (*clAmdBlasStbsv)(clAmdBlasOrder, clAmdBlasUplo, clAmdBlasTranspose, clAmdBlasDiag, size_t, size_t, const cl_mem, size_t, size_t, cl_mem, size_t, int, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn17<OPENCLAMDBLAS_FN_clAmdBlasStbsv, clAmdBlasStatus, clAmdBlasOrder, clAmdBlasUplo, clAmdBlasTranspose, clAmdBlasDiag, size_t, size_t, const cl_mem, size_t, size_t, cl_mem, size_t, int, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasStbsv_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasStbsv_definition = { "clAmdBlasStbsv", (void**)&clAmdBlasStbsv};
 
+//openclamdblas_fn16(OPENCLAMDBLAS_FN_clAmdBlasStpmv, clAmdBlasStatus, (clAmdBlasOrder p1, clAmdBlasUplo p2, clAmdBlasTranspose p3, clAmdBlasDiag p4, size_t p5, const cl_mem p6, size_t p7, cl_mem p8, size_t p9, int p10, cl_mem p11, cl_uint p12, cl_command_queue* p13, cl_uint p14, const cl_event* p15, cl_event* p16))
 //clAmdBlasStatus (*clAmdBlasStpmv)(clAmdBlasOrder, clAmdBlasUplo, clAmdBlasTranspose, clAmdBlasDiag, size_t, const cl_mem, size_t, cl_mem, size_t, int, cl_mem, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn16<OPENCLAMDBLAS_FN_clAmdBlasStpmv, clAmdBlasStatus, clAmdBlasOrder, clAmdBlasUplo, clAmdBlasTranspose, clAmdBlasDiag, size_t, const cl_mem, size_t, cl_mem, size_t, int, cl_mem, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasStpmv_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasStpmv_definition = { "clAmdBlasStpmv", (void**)&clAmdBlasStpmv};
 
+//openclamdblas_fn15(OPENCLAMDBLAS_FN_clAmdBlasStpsv, clAmdBlasStatus, (clAmdBlasOrder p1, clAmdBlasUplo p2, clAmdBlasTranspose p3, clAmdBlasDiag p4, size_t p5, const cl_mem p6, size_t p7, cl_mem p8, size_t p9, int p10, cl_uint p11, cl_command_queue* p12, cl_uint p13, const cl_event* p14, cl_event* p15))
 //clAmdBlasStatus (*clAmdBlasStpsv)(clAmdBlasOrder, clAmdBlasUplo, clAmdBlasTranspose, clAmdBlasDiag, size_t, const cl_mem, size_t, cl_mem, size_t, int, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn15<OPENCLAMDBLAS_FN_clAmdBlasStpsv, clAmdBlasStatus, clAmdBlasOrder, clAmdBlasUplo, clAmdBlasTranspose, clAmdBlasDiag, size_t, const cl_mem, size_t, cl_mem, size_t, int, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasStpsv_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasStpsv_definition = { "clAmdBlasStpsv", (void**)&clAmdBlasStpsv};
 
+//openclamdblas_fn17(OPENCLAMDBLAS_FN_clAmdBlasStrmm, clAmdBlasStatus, (clAmdBlasOrder p1, clAmdBlasSide p2, clAmdBlasUplo p3, clAmdBlasTranspose p4, clAmdBlasDiag p5, size_t p6, size_t p7, cl_float p8, const cl_mem p9, size_t p10, cl_mem p11, size_t p12, cl_uint p13, cl_command_queue* p14, cl_uint p15, const cl_event* p16, cl_event* p17))
 //clAmdBlasStatus (*clAmdBlasStrmm)(clAmdBlasOrder, clAmdBlasSide, clAmdBlasUplo, clAmdBlasTranspose, clAmdBlasDiag, size_t, size_t, cl_float, const cl_mem, size_t, cl_mem, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn17<OPENCLAMDBLAS_FN_clAmdBlasStrmm, clAmdBlasStatus, clAmdBlasOrder, clAmdBlasSide, clAmdBlasUplo, clAmdBlasTranspose, clAmdBlasDiag, size_t, size_t, cl_float, const cl_mem, size_t, cl_mem, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasStrmm_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasStrmm_definition = { "clAmdBlasStrmm", (void**)&clAmdBlasStrmm};
 
+//openclamdblas_fn19(OPENCLAMDBLAS_FN_clAmdBlasStrmmEx, clAmdBlasStatus, (clAmdBlasOrder p1, clAmdBlasSide p2, clAmdBlasUplo p3, clAmdBlasTranspose p4, clAmdBlasDiag p5, size_t p6, size_t p7, cl_float p8, const cl_mem p9, size_t p10, size_t p11, cl_mem p12, size_t p13, size_t p14, cl_uint p15, cl_command_queue* p16, cl_uint p17, const cl_event* p18, cl_event* p19))
 //clAmdBlasStatus (*clAmdBlasStrmmEx)(clAmdBlasOrder, clAmdBlasSide, clAmdBlasUplo, clAmdBlasTranspose, clAmdBlasDiag, size_t, size_t, cl_float, const cl_mem, size_t, size_t, cl_mem, size_t, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn19<OPENCLAMDBLAS_FN_clAmdBlasStrmmEx, clAmdBlasStatus, clAmdBlasOrder, clAmdBlasSide, clAmdBlasUplo, clAmdBlasTranspose, clAmdBlasDiag, size_t, size_t, cl_float, const cl_mem, size_t, size_t, cl_mem, size_t, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasStrmmEx_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasStrmmEx_definition = { "clAmdBlasStrmmEx", (void**)&clAmdBlasStrmmEx};
 
+//openclamdblas_fn17(OPENCLAMDBLAS_FN_clAmdBlasStrmv, clAmdBlasStatus, (clAmdBlasOrder p1, clAmdBlasUplo p2, clAmdBlasTranspose p3, clAmdBlasDiag p4, size_t p5, const cl_mem p6, size_t p7, size_t p8, cl_mem p9, size_t p10, int p11, cl_mem p12, cl_uint p13, cl_command_queue* p14, cl_uint p15, const cl_event* p16, cl_event* p17))
 //clAmdBlasStatus (*clAmdBlasStrmv)(clAmdBlasOrder, clAmdBlasUplo, clAmdBlasTranspose, clAmdBlasDiag, size_t, const cl_mem, size_t, size_t, cl_mem, size_t, int, cl_mem, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn17<OPENCLAMDBLAS_FN_clAmdBlasStrmv, clAmdBlasStatus, clAmdBlasOrder, clAmdBlasUplo, clAmdBlasTranspose, clAmdBlasDiag, size_t, const cl_mem, size_t, size_t, cl_mem, size_t, int, cl_mem, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasStrmv_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasStrmv_definition = { "clAmdBlasStrmv", (void**)&clAmdBlasStrmv};
 
+//openclamdblas_fn17(OPENCLAMDBLAS_FN_clAmdBlasStrsm, clAmdBlasStatus, (clAmdBlasOrder p1, clAmdBlasSide p2, clAmdBlasUplo p3, clAmdBlasTranspose p4, clAmdBlasDiag p5, size_t p6, size_t p7, cl_float p8, const cl_mem p9, size_t p10, cl_mem p11, size_t p12, cl_uint p13, cl_command_queue* p14, cl_uint p15, const cl_event* p16, cl_event* p17))
 //clAmdBlasStatus (*clAmdBlasStrsm)(clAmdBlasOrder, clAmdBlasSide, clAmdBlasUplo, clAmdBlasTranspose, clAmdBlasDiag, size_t, size_t, cl_float, const cl_mem, size_t, cl_mem, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn17<OPENCLAMDBLAS_FN_clAmdBlasStrsm, clAmdBlasStatus, clAmdBlasOrder, clAmdBlasSide, clAmdBlasUplo, clAmdBlasTranspose, clAmdBlasDiag, size_t, size_t, cl_float, const cl_mem, size_t, cl_mem, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasStrsm_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasStrsm_definition = { "clAmdBlasStrsm", (void**)&clAmdBlasStrsm};
 
+//openclamdblas_fn19(OPENCLAMDBLAS_FN_clAmdBlasStrsmEx, clAmdBlasStatus, (clAmdBlasOrder p1, clAmdBlasSide p2, clAmdBlasUplo p3, clAmdBlasTranspose p4, clAmdBlasDiag p5, size_t p6, size_t p7, cl_float p8, const cl_mem p9, size_t p10, size_t p11, cl_mem p12, size_t p13, size_t p14, cl_uint p15, cl_command_queue* p16, cl_uint p17, const cl_event* p18, cl_event* p19))
 //clAmdBlasStatus (*clAmdBlasStrsmEx)(clAmdBlasOrder, clAmdBlasSide, clAmdBlasUplo, clAmdBlasTranspose, clAmdBlasDiag, size_t, size_t, cl_float, const cl_mem, size_t, size_t, cl_mem, size_t, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn19<OPENCLAMDBLAS_FN_clAmdBlasStrsmEx, clAmdBlasStatus, clAmdBlasOrder, clAmdBlasSide, clAmdBlasUplo, clAmdBlasTranspose, clAmdBlasDiag, size_t, size_t, cl_float, const cl_mem, size_t, size_t, cl_mem, size_t, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasStrsmEx_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasStrsmEx_definition = { "clAmdBlasStrsmEx", (void**)&clAmdBlasStrsmEx};
 
+//openclamdblas_fn16(OPENCLAMDBLAS_FN_clAmdBlasStrsv, clAmdBlasStatus, (clAmdBlasOrder p1, clAmdBlasUplo p2, clAmdBlasTranspose p3, clAmdBlasDiag p4, size_t p5, const cl_mem p6, size_t p7, size_t p8, cl_mem p9, size_t p10, int p11, cl_uint p12, cl_command_queue* p13, cl_uint p14, const cl_event* p15, cl_event* p16))
 //clAmdBlasStatus (*clAmdBlasStrsv)(clAmdBlasOrder, clAmdBlasUplo, clAmdBlasTranspose, clAmdBlasDiag, size_t, const cl_mem, size_t, size_t, cl_mem, size_t, int, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn16<OPENCLAMDBLAS_FN_clAmdBlasStrsv, clAmdBlasStatus, clAmdBlasOrder, clAmdBlasUplo, clAmdBlasTranspose, clAmdBlasDiag, size_t, const cl_mem, size_t, size_t, cl_mem, size_t, int, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasStrsv_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasStrsv_definition = { "clAmdBlasStrsv", (void**)&clAmdBlasStrsv};
 
+openclamdblas_fn0(OPENCLAMDBLAS_FN_clAmdBlasTeardown, void, ())
 void (*clAmdBlasTeardown)() =
-        openclamdblas_fn0<OPENCLAMDBLAS_FN_clAmdBlasTeardown, void>::switch_fn;
+        OPENCLAMDBLAS_FN_clAmdBlasTeardown_switch_fn;
 static const struct DynamicFnEntry clAmdBlasTeardown_definition = { "clAmdBlasTeardown", (void**)&clAmdBlasTeardown};
 
+//openclamdblas_fn13(OPENCLAMDBLAS_FN_clAmdBlasZaxpy, clAmdBlasStatus, (size_t p1, cl_double2 p2, const cl_mem p3, size_t p4, int p5, cl_mem p6, size_t p7, int p8, cl_uint p9, cl_command_queue* p10, cl_uint p11, const cl_event* p12, cl_event* p13))
 //clAmdBlasStatus (*clAmdBlasZaxpy)(size_t, cl_double2, const cl_mem, size_t, int, cl_mem, size_t, int, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn13<OPENCLAMDBLAS_FN_clAmdBlasZaxpy, clAmdBlasStatus, size_t, cl_double2, const cl_mem, size_t, int, cl_mem, size_t, int, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasZaxpy_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasZaxpy_definition = { "clAmdBlasZaxpy", (void**)&clAmdBlasZaxpy};
 
+//openclamdblas_fn12(OPENCLAMDBLAS_FN_clAmdBlasZcopy, clAmdBlasStatus, (size_t p1, const cl_mem p2, size_t p3, int p4, cl_mem p5, size_t p6, int p7, cl_uint p8, cl_command_queue* p9, cl_uint p10, const cl_event* p11, cl_event* p12))
 //clAmdBlasStatus (*clAmdBlasZcopy)(size_t, const cl_mem, size_t, int, cl_mem, size_t, int, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn12<OPENCLAMDBLAS_FN_clAmdBlasZcopy, clAmdBlasStatus, size_t, const cl_mem, size_t, int, cl_mem, size_t, int, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasZcopy_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasZcopy_definition = { "clAmdBlasZcopy", (void**)&clAmdBlasZcopy};
 
+//openclamdblas_fn15(OPENCLAMDBLAS_FN_clAmdBlasZdotc, clAmdBlasStatus, (size_t p1, cl_mem p2, size_t p3, const cl_mem p4, size_t p5, int p6, const cl_mem p7, size_t p8, int p9, cl_mem p10, cl_uint p11, cl_command_queue* p12, cl_uint p13, const cl_event* p14, cl_event* p15))
 //clAmdBlasStatus (*clAmdBlasZdotc)(size_t, cl_mem, size_t, const cl_mem, size_t, int, const cl_mem, size_t, int, cl_mem, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn15<OPENCLAMDBLAS_FN_clAmdBlasZdotc, clAmdBlasStatus, size_t, cl_mem, size_t, const cl_mem, size_t, int, const cl_mem, size_t, int, cl_mem, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasZdotc_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasZdotc_definition = { "clAmdBlasZdotc", (void**)&clAmdBlasZdotc};
 
+//openclamdblas_fn15(OPENCLAMDBLAS_FN_clAmdBlasZdotu, clAmdBlasStatus, (size_t p1, cl_mem p2, size_t p3, const cl_mem p4, size_t p5, int p6, const cl_mem p7, size_t p8, int p9, cl_mem p10, cl_uint p11, cl_command_queue* p12, cl_uint p13, const cl_event* p14, cl_event* p15))
 //clAmdBlasStatus (*clAmdBlasZdotu)(size_t, cl_mem, size_t, const cl_mem, size_t, int, const cl_mem, size_t, int, cl_mem, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn15<OPENCLAMDBLAS_FN_clAmdBlasZdotu, clAmdBlasStatus, size_t, cl_mem, size_t, const cl_mem, size_t, int, const cl_mem, size_t, int, cl_mem, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasZdotu_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasZdotu_definition = { "clAmdBlasZdotu", (void**)&clAmdBlasZdotu};
 
+//openclamdblas_fn14(OPENCLAMDBLAS_FN_clAmdBlasZdrot, clAmdBlasStatus, (size_t p1, cl_mem p2, size_t p3, int p4, cl_mem p5, size_t p6, int p7, cl_double p8, cl_double p9, cl_uint p10, cl_command_queue* p11, cl_uint p12, const cl_event* p13, cl_event* p14))
 //clAmdBlasStatus (*clAmdBlasZdrot)(size_t, cl_mem, size_t, int, cl_mem, size_t, int, cl_double, cl_double, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn14<OPENCLAMDBLAS_FN_clAmdBlasZdrot, clAmdBlasStatus, size_t, cl_mem, size_t, int, cl_mem, size_t, int, cl_double, cl_double, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasZdrot_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasZdrot_definition = { "clAmdBlasZdrot", (void**)&clAmdBlasZdrot};
 
+//openclamdblas_fn10(OPENCLAMDBLAS_FN_clAmdBlasZdscal, clAmdBlasStatus, (size_t p1, cl_double p2, cl_mem p3, size_t p4, int p5, cl_uint p6, cl_command_queue* p7, cl_uint p8, const cl_event* p9, cl_event* p10))
 //clAmdBlasStatus (*clAmdBlasZdscal)(size_t, cl_double, cl_mem, size_t, int, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn10<OPENCLAMDBLAS_FN_clAmdBlasZdscal, clAmdBlasStatus, size_t, cl_double, cl_mem, size_t, int, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasZdscal_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasZdscal_definition = { "clAmdBlasZdscal", (void**)&clAmdBlasZdscal};
 
+//openclamdblas_fn22(OPENCLAMDBLAS_FN_clAmdBlasZgbmv, clAmdBlasStatus, (clAmdBlasOrder p1, clAmdBlasTranspose p2, size_t p3, size_t p4, size_t p5, size_t p6, cl_double2 p7, const cl_mem p8, size_t p9, size_t p10, const cl_mem p11, size_t p12, int p13, cl_double2 p14, cl_mem p15, size_t p16, int p17, cl_uint p18, cl_command_queue* p19, cl_uint p20, const cl_event* p21, cl_event* p22))
 //clAmdBlasStatus (*clAmdBlasZgbmv)(clAmdBlasOrder, clAmdBlasTranspose, size_t, size_t, size_t, size_t, cl_double2, const cl_mem, size_t, size_t, const cl_mem, size_t, int, cl_double2, cl_mem, size_t, int, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn22<OPENCLAMDBLAS_FN_clAmdBlasZgbmv, clAmdBlasStatus, clAmdBlasOrder, clAmdBlasTranspose, size_t, size_t, size_t, size_t, cl_double2, const cl_mem, size_t, size_t, const cl_mem, size_t, int, cl_double2, cl_mem, size_t, int, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasZgbmv_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasZgbmv_definition = { "clAmdBlasZgbmv", (void**)&clAmdBlasZgbmv};
 
+//openclamdblas_fn19(OPENCLAMDBLAS_FN_clAmdBlasZgemm, clAmdBlasStatus, (clAmdBlasOrder p1, clAmdBlasTranspose p2, clAmdBlasTranspose p3, size_t p4, size_t p5, size_t p6, DoubleComplex p7, const cl_mem p8, size_t p9, const cl_mem p10, size_t p11, DoubleComplex p12, cl_mem p13, size_t p14, cl_uint p15, cl_command_queue* p16, cl_uint p17, const cl_event* p18, cl_event* p19))
 //clAmdBlasStatus (*clAmdBlasZgemm)(clAmdBlasOrder, clAmdBlasTranspose, clAmdBlasTranspose, size_t, size_t, size_t, DoubleComplex, const cl_mem, size_t, const cl_mem, size_t, DoubleComplex, cl_mem, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn19<OPENCLAMDBLAS_FN_clAmdBlasZgemm, clAmdBlasStatus, clAmdBlasOrder, clAmdBlasTranspose, clAmdBlasTranspose, size_t, size_t, size_t, DoubleComplex, const cl_mem, size_t, const cl_mem, size_t, DoubleComplex, cl_mem, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasZgemm_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasZgemm_definition = { "clAmdBlasZgemm", (void**)&clAmdBlasZgemm};
 
+openclamdblas_fn22(OPENCLAMDBLAS_FN_clAmdBlasZgemmEx, clAmdBlasStatus, (clAmdBlasOrder p1, clAmdBlasTranspose p2, clAmdBlasTranspose p3, size_t p4, size_t p5, size_t p6, DoubleComplex p7, const cl_mem p8, size_t p9, size_t p10, const cl_mem p11, size_t p12, size_t p13, DoubleComplex p14, cl_mem p15, size_t p16, size_t p17, cl_uint p18, cl_command_queue* p19, cl_uint p20, const cl_event* p21, cl_event* p22))
 clAmdBlasStatus (*clAmdBlasZgemmEx)(clAmdBlasOrder, clAmdBlasTranspose, clAmdBlasTranspose, size_t, size_t, size_t, DoubleComplex, const cl_mem, size_t, size_t, const cl_mem, size_t, size_t, DoubleComplex, cl_mem, size_t, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-        openclamdblas_fn22<OPENCLAMDBLAS_FN_clAmdBlasZgemmEx, clAmdBlasStatus, clAmdBlasOrder, clAmdBlasTranspose, clAmdBlasTranspose, size_t, size_t, size_t, DoubleComplex, const cl_mem, size_t, size_t, const cl_mem, size_t, size_t, DoubleComplex, cl_mem, size_t, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+        OPENCLAMDBLAS_FN_clAmdBlasZgemmEx_switch_fn;
 static const struct DynamicFnEntry clAmdBlasZgemmEx_definition = { "clAmdBlasZgemmEx", (void**)&clAmdBlasZgemmEx};
 
+//openclamdblas_fn19(OPENCLAMDBLAS_FN_clAmdBlasZgemv, clAmdBlasStatus, (clAmdBlasOrder p1, clAmdBlasTranspose p2, size_t p3, size_t p4, DoubleComplex p5, const cl_mem p6, size_t p7, const cl_mem p8, size_t p9, int p10, DoubleComplex p11, cl_mem p12, size_t p13, int p14, cl_uint p15, cl_command_queue* p16, cl_uint p17, const cl_event* p18, cl_event* p19))
 //clAmdBlasStatus (*clAmdBlasZgemv)(clAmdBlasOrder, clAmdBlasTranspose, size_t, size_t, DoubleComplex, const cl_mem, size_t, const cl_mem, size_t, int, DoubleComplex, cl_mem, size_t, int, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn19<OPENCLAMDBLAS_FN_clAmdBlasZgemv, clAmdBlasStatus, clAmdBlasOrder, clAmdBlasTranspose, size_t, size_t, DoubleComplex, const cl_mem, size_t, const cl_mem, size_t, int, DoubleComplex, cl_mem, size_t, int, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasZgemv_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasZgemv_definition = { "clAmdBlasZgemv", (void**)&clAmdBlasZgemv};
 
+//openclamdblas_fn20(OPENCLAMDBLAS_FN_clAmdBlasZgemvEx, clAmdBlasStatus, (clAmdBlasOrder p1, clAmdBlasTranspose p2, size_t p3, size_t p4, DoubleComplex p5, const cl_mem p6, size_t p7, size_t p8, const cl_mem p9, size_t p10, int p11, DoubleComplex p12, cl_mem p13, size_t p14, int p15, cl_uint p16, cl_command_queue* p17, cl_uint p18, const cl_event* p19, cl_event* p20))
 //clAmdBlasStatus (*clAmdBlasZgemvEx)(clAmdBlasOrder, clAmdBlasTranspose, size_t, size_t, DoubleComplex, const cl_mem, size_t, size_t, const cl_mem, size_t, int, DoubleComplex, cl_mem, size_t, int, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn20<OPENCLAMDBLAS_FN_clAmdBlasZgemvEx, clAmdBlasStatus, clAmdBlasOrder, clAmdBlasTranspose, size_t, size_t, DoubleComplex, const cl_mem, size_t, size_t, const cl_mem, size_t, int, DoubleComplex, cl_mem, size_t, int, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasZgemvEx_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasZgemvEx_definition = { "clAmdBlasZgemvEx", (void**)&clAmdBlasZgemvEx};
 
+//openclamdblas_fn18(OPENCLAMDBLAS_FN_clAmdBlasZgerc, clAmdBlasStatus, (clAmdBlasOrder p1, size_t p2, size_t p3, cl_double2 p4, const cl_mem p5, size_t p6, int p7, const cl_mem p8, size_t p9, int p10, cl_mem p11, size_t p12, size_t p13, cl_uint p14, cl_command_queue* p15, cl_uint p16, const cl_event* p17, cl_event* p18))
 //clAmdBlasStatus (*clAmdBlasZgerc)(clAmdBlasOrder, size_t, size_t, cl_double2, const cl_mem, size_t, int, const cl_mem, size_t, int, cl_mem, size_t, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn18<OPENCLAMDBLAS_FN_clAmdBlasZgerc, clAmdBlasStatus, clAmdBlasOrder, size_t, size_t, cl_double2, const cl_mem, size_t, int, const cl_mem, size_t, int, cl_mem, size_t, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasZgerc_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasZgerc_definition = { "clAmdBlasZgerc", (void**)&clAmdBlasZgerc};
 
+//openclamdblas_fn18(OPENCLAMDBLAS_FN_clAmdBlasZgeru, clAmdBlasStatus, (clAmdBlasOrder p1, size_t p2, size_t p3, cl_double2 p4, const cl_mem p5, size_t p6, int p7, const cl_mem p8, size_t p9, int p10, cl_mem p11, size_t p12, size_t p13, cl_uint p14, cl_command_queue* p15, cl_uint p16, const cl_event* p17, cl_event* p18))
 //clAmdBlasStatus (*clAmdBlasZgeru)(clAmdBlasOrder, size_t, size_t, cl_double2, const cl_mem, size_t, int, const cl_mem, size_t, int, cl_mem, size_t, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn18<OPENCLAMDBLAS_FN_clAmdBlasZgeru, clAmdBlasStatus, clAmdBlasOrder, size_t, size_t, cl_double2, const cl_mem, size_t, int, const cl_mem, size_t, int, cl_mem, size_t, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasZgeru_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasZgeru_definition = { "clAmdBlasZgeru", (void**)&clAmdBlasZgeru};
 
+//openclamdblas_fn20(OPENCLAMDBLAS_FN_clAmdBlasZhbmv, clAmdBlasStatus, (clAmdBlasOrder p1, clAmdBlasUplo p2, size_t p3, size_t p4, cl_double2 p5, const cl_mem p6, size_t p7, size_t p8, const cl_mem p9, size_t p10, int p11, cl_double2 p12, cl_mem p13, size_t p14, int p15, cl_uint p16, cl_command_queue* p17, cl_uint p18, const cl_event* p19, cl_event* p20))
 //clAmdBlasStatus (*clAmdBlasZhbmv)(clAmdBlasOrder, clAmdBlasUplo, size_t, size_t, cl_double2, const cl_mem, size_t, size_t, const cl_mem, size_t, int, cl_double2, cl_mem, size_t, int, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn20<OPENCLAMDBLAS_FN_clAmdBlasZhbmv, clAmdBlasStatus, clAmdBlasOrder, clAmdBlasUplo, size_t, size_t, cl_double2, const cl_mem, size_t, size_t, const cl_mem, size_t, int, cl_double2, cl_mem, size_t, int, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasZhbmv_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasZhbmv_definition = { "clAmdBlasZhbmv", (void**)&clAmdBlasZhbmv};
 
+//openclamdblas_fn21(OPENCLAMDBLAS_FN_clAmdBlasZhemm, clAmdBlasStatus, (clAmdBlasOrder p1, clAmdBlasSide p2, clAmdBlasUplo p3, size_t p4, size_t p5, cl_double2 p6, const cl_mem p7, size_t p8, size_t p9, const cl_mem p10, size_t p11, size_t p12, cl_double2 p13, cl_mem p14, size_t p15, size_t p16, cl_uint p17, cl_command_queue* p18, cl_uint p19, const cl_event* p20, cl_event* p21))
 //clAmdBlasStatus (*clAmdBlasZhemm)(clAmdBlasOrder, clAmdBlasSide, clAmdBlasUplo, size_t, size_t, cl_double2, const cl_mem, size_t, size_t, const cl_mem, size_t, size_t, cl_double2, cl_mem, size_t, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn21<OPENCLAMDBLAS_FN_clAmdBlasZhemm, clAmdBlasStatus, clAmdBlasOrder, clAmdBlasSide, clAmdBlasUplo, size_t, size_t, cl_double2, const cl_mem, size_t, size_t, const cl_mem, size_t, size_t, cl_double2, cl_mem, size_t, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasZhemm_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasZhemm_definition = { "clAmdBlasZhemm", (void**)&clAmdBlasZhemm};
 
+//openclamdblas_fn19(OPENCLAMDBLAS_FN_clAmdBlasZhemv, clAmdBlasStatus, (clAmdBlasOrder p1, clAmdBlasUplo p2, size_t p3, DoubleComplex p4, const cl_mem p5, size_t p6, size_t p7, const cl_mem p8, size_t p9, int p10, DoubleComplex p11, cl_mem p12, size_t p13, int p14, cl_uint p15, cl_command_queue* p16, cl_uint p17, const cl_event* p18, cl_event* p19))
 //clAmdBlasStatus (*clAmdBlasZhemv)(clAmdBlasOrder, clAmdBlasUplo, size_t, DoubleComplex, const cl_mem, size_t, size_t, const cl_mem, size_t, int, DoubleComplex, cl_mem, size_t, int, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn19<OPENCLAMDBLAS_FN_clAmdBlasZhemv, clAmdBlasStatus, clAmdBlasOrder, clAmdBlasUplo, size_t, DoubleComplex, const cl_mem, size_t, size_t, const cl_mem, size_t, int, DoubleComplex, cl_mem, size_t, int, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasZhemv_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasZhemv_definition = { "clAmdBlasZhemv", (void**)&clAmdBlasZhemv};
 
+//openclamdblas_fn15(OPENCLAMDBLAS_FN_clAmdBlasZher, clAmdBlasStatus, (clAmdBlasOrder p1, clAmdBlasUplo p2, size_t p3, cl_double p4, const cl_mem p5, size_t p6, int p7, cl_mem p8, size_t p9, size_t p10, cl_uint p11, cl_command_queue* p12, cl_uint p13, const cl_event* p14, cl_event* p15))
 //clAmdBlasStatus (*clAmdBlasZher)(clAmdBlasOrder, clAmdBlasUplo, size_t, cl_double, const cl_mem, size_t, int, cl_mem, size_t, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn15<OPENCLAMDBLAS_FN_clAmdBlasZher, clAmdBlasStatus, clAmdBlasOrder, clAmdBlasUplo, size_t, cl_double, const cl_mem, size_t, int, cl_mem, size_t, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasZher_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasZher_definition = { "clAmdBlasZher", (void**)&clAmdBlasZher};
 
+//openclamdblas_fn18(OPENCLAMDBLAS_FN_clAmdBlasZher2, clAmdBlasStatus, (clAmdBlasOrder p1, clAmdBlasUplo p2, size_t p3, cl_double2 p4, const cl_mem p5, size_t p6, int p7, const cl_mem p8, size_t p9, int p10, cl_mem p11, size_t p12, size_t p13, cl_uint p14, cl_command_queue* p15, cl_uint p16, const cl_event* p17, cl_event* p18))
 //clAmdBlasStatus (*clAmdBlasZher2)(clAmdBlasOrder, clAmdBlasUplo, size_t, cl_double2, const cl_mem, size_t, int, const cl_mem, size_t, int, cl_mem, size_t, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn18<OPENCLAMDBLAS_FN_clAmdBlasZher2, clAmdBlasStatus, clAmdBlasOrder, clAmdBlasUplo, size_t, cl_double2, const cl_mem, size_t, int, const cl_mem, size_t, int, cl_mem, size_t, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasZher2_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasZher2_definition = { "clAmdBlasZher2", (void**)&clAmdBlasZher2};
 
+//openclamdblas_fn21(OPENCLAMDBLAS_FN_clAmdBlasZher2k, clAmdBlasStatus, (clAmdBlasOrder p1, clAmdBlasUplo p2, clAmdBlasTranspose p3, size_t p4, size_t p5, DoubleComplex p6, const cl_mem p7, size_t p8, size_t p9, const cl_mem p10, size_t p11, size_t p12, cl_double p13, cl_mem p14, size_t p15, size_t p16, cl_uint p17, cl_command_queue* p18, cl_uint p19, const cl_event* p20, cl_event* p21))
 //clAmdBlasStatus (*clAmdBlasZher2k)(clAmdBlasOrder, clAmdBlasUplo, clAmdBlasTranspose, size_t, size_t, DoubleComplex, const cl_mem, size_t, size_t, const cl_mem, size_t, size_t, cl_double, cl_mem, size_t, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn21<OPENCLAMDBLAS_FN_clAmdBlasZher2k, clAmdBlasStatus, clAmdBlasOrder, clAmdBlasUplo, clAmdBlasTranspose, size_t, size_t, DoubleComplex, const cl_mem, size_t, size_t, const cl_mem, size_t, size_t, cl_double, cl_mem, size_t, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasZher2k_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasZher2k_definition = { "clAmdBlasZher2k", (void**)&clAmdBlasZher2k};
 
+//openclamdblas_fn18(OPENCLAMDBLAS_FN_clAmdBlasZherk, clAmdBlasStatus, (clAmdBlasOrder p1, clAmdBlasUplo p2, clAmdBlasTranspose p3, size_t p4, size_t p5, double p6, const cl_mem p7, size_t p8, size_t p9, double p10, cl_mem p11, size_t p12, size_t p13, cl_uint p14, cl_command_queue* p15, cl_uint p16, const cl_event* p17, cl_event* p18))
 //clAmdBlasStatus (*clAmdBlasZherk)(clAmdBlasOrder, clAmdBlasUplo, clAmdBlasTranspose, size_t, size_t, double, const cl_mem, size_t, size_t, double, cl_mem, size_t, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn18<OPENCLAMDBLAS_FN_clAmdBlasZherk, clAmdBlasStatus, clAmdBlasOrder, clAmdBlasUplo, clAmdBlasTranspose, size_t, size_t, double, const cl_mem, size_t, size_t, double, cl_mem, size_t, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasZherk_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasZherk_definition = { "clAmdBlasZherk", (void**)&clAmdBlasZherk};
 
+//openclamdblas_fn18(OPENCLAMDBLAS_FN_clAmdBlasZhpmv, clAmdBlasStatus, (clAmdBlasOrder p1, clAmdBlasUplo p2, size_t p3, cl_double2 p4, const cl_mem p5, size_t p6, const cl_mem p7, size_t p8, int p9, cl_double2 p10, cl_mem p11, size_t p12, int p13, cl_uint p14, cl_command_queue* p15, cl_uint p16, const cl_event* p17, cl_event* p18))
 //clAmdBlasStatus (*clAmdBlasZhpmv)(clAmdBlasOrder, clAmdBlasUplo, size_t, cl_double2, const cl_mem, size_t, const cl_mem, size_t, int, cl_double2, cl_mem, size_t, int, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn18<OPENCLAMDBLAS_FN_clAmdBlasZhpmv, clAmdBlasStatus, clAmdBlasOrder, clAmdBlasUplo, size_t, cl_double2, const cl_mem, size_t, const cl_mem, size_t, int, cl_double2, cl_mem, size_t, int, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasZhpmv_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasZhpmv_definition = { "clAmdBlasZhpmv", (void**)&clAmdBlasZhpmv};
 
+//openclamdblas_fn14(OPENCLAMDBLAS_FN_clAmdBlasZhpr, clAmdBlasStatus, (clAmdBlasOrder p1, clAmdBlasUplo p2, size_t p3, cl_double p4, const cl_mem p5, size_t p6, int p7, cl_mem p8, size_t p9, cl_uint p10, cl_command_queue* p11, cl_uint p12, const cl_event* p13, cl_event* p14))
 //clAmdBlasStatus (*clAmdBlasZhpr)(clAmdBlasOrder, clAmdBlasUplo, size_t, cl_double, const cl_mem, size_t, int, cl_mem, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn14<OPENCLAMDBLAS_FN_clAmdBlasZhpr, clAmdBlasStatus, clAmdBlasOrder, clAmdBlasUplo, size_t, cl_double, const cl_mem, size_t, int, cl_mem, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasZhpr_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasZhpr_definition = { "clAmdBlasZhpr", (void**)&clAmdBlasZhpr};
 
+//openclamdblas_fn17(OPENCLAMDBLAS_FN_clAmdBlasZhpr2, clAmdBlasStatus, (clAmdBlasOrder p1, clAmdBlasUplo p2, size_t p3, cl_double2 p4, const cl_mem p5, size_t p6, int p7, const cl_mem p8, size_t p9, int p10, cl_mem p11, size_t p12, cl_uint p13, cl_command_queue* p14, cl_uint p15, const cl_event* p16, cl_event* p17))
 //clAmdBlasStatus (*clAmdBlasZhpr2)(clAmdBlasOrder, clAmdBlasUplo, size_t, cl_double2, const cl_mem, size_t, int, const cl_mem, size_t, int, cl_mem, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn17<OPENCLAMDBLAS_FN_clAmdBlasZhpr2, clAmdBlasStatus, clAmdBlasOrder, clAmdBlasUplo, size_t, cl_double2, const cl_mem, size_t, int, const cl_mem, size_t, int, cl_mem, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasZhpr2_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasZhpr2_definition = { "clAmdBlasZhpr2", (void**)&clAmdBlasZhpr2};
 
+//openclamdblas_fn13(OPENCLAMDBLAS_FN_clAmdBlasZrotg, clAmdBlasStatus, (cl_mem p1, size_t p2, cl_mem p3, size_t p4, cl_mem p5, size_t p6, cl_mem p7, size_t p8, cl_uint p9, cl_command_queue* p10, cl_uint p11, const cl_event* p12, cl_event* p13))
 //clAmdBlasStatus (*clAmdBlasZrotg)(cl_mem, size_t, cl_mem, size_t, cl_mem, size_t, cl_mem, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn13<OPENCLAMDBLAS_FN_clAmdBlasZrotg, clAmdBlasStatus, cl_mem, size_t, cl_mem, size_t, cl_mem, size_t, cl_mem, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasZrotg_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasZrotg_definition = { "clAmdBlasZrotg", (void**)&clAmdBlasZrotg};
 
+//openclamdblas_fn10(OPENCLAMDBLAS_FN_clAmdBlasZscal, clAmdBlasStatus, (size_t p1, cl_double2 p2, cl_mem p3, size_t p4, int p5, cl_uint p6, cl_command_queue* p7, cl_uint p8, const cl_event* p9, cl_event* p10))
 //clAmdBlasStatus (*clAmdBlasZscal)(size_t, cl_double2, cl_mem, size_t, int, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn10<OPENCLAMDBLAS_FN_clAmdBlasZscal, clAmdBlasStatus, size_t, cl_double2, cl_mem, size_t, int, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasZscal_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasZscal_definition = { "clAmdBlasZscal", (void**)&clAmdBlasZscal};
 
+//openclamdblas_fn12(OPENCLAMDBLAS_FN_clAmdBlasZswap, clAmdBlasStatus, (size_t p1, cl_mem p2, size_t p3, int p4, cl_mem p5, size_t p6, int p7, cl_uint p8, cl_command_queue* p9, cl_uint p10, const cl_event* p11, cl_event* p12))
 //clAmdBlasStatus (*clAmdBlasZswap)(size_t, cl_mem, size_t, int, cl_mem, size_t, int, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn12<OPENCLAMDBLAS_FN_clAmdBlasZswap, clAmdBlasStatus, size_t, cl_mem, size_t, int, cl_mem, size_t, int, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasZswap_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasZswap_definition = { "clAmdBlasZswap", (void**)&clAmdBlasZswap};
 
+//openclamdblas_fn21(OPENCLAMDBLAS_FN_clAmdBlasZsymm, clAmdBlasStatus, (clAmdBlasOrder p1, clAmdBlasSide p2, clAmdBlasUplo p3, size_t p4, size_t p5, cl_double2 p6, const cl_mem p7, size_t p8, size_t p9, const cl_mem p10, size_t p11, size_t p12, cl_double2 p13, cl_mem p14, size_t p15, size_t p16, cl_uint p17, cl_command_queue* p18, cl_uint p19, const cl_event* p20, cl_event* p21))
 //clAmdBlasStatus (*clAmdBlasZsymm)(clAmdBlasOrder, clAmdBlasSide, clAmdBlasUplo, size_t, size_t, cl_double2, const cl_mem, size_t, size_t, const cl_mem, size_t, size_t, cl_double2, cl_mem, size_t, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn21<OPENCLAMDBLAS_FN_clAmdBlasZsymm, clAmdBlasStatus, clAmdBlasOrder, clAmdBlasSide, clAmdBlasUplo, size_t, size_t, cl_double2, const cl_mem, size_t, size_t, const cl_mem, size_t, size_t, cl_double2, cl_mem, size_t, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasZsymm_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasZsymm_definition = { "clAmdBlasZsymm", (void**)&clAmdBlasZsymm};
 
+//openclamdblas_fn18(OPENCLAMDBLAS_FN_clAmdBlasZsyr2k, clAmdBlasStatus, (clAmdBlasOrder p1, clAmdBlasUplo p2, clAmdBlasTranspose p3, size_t p4, size_t p5, DoubleComplex p6, const cl_mem p7, size_t p8, const cl_mem p9, size_t p10, DoubleComplex p11, cl_mem p12, size_t p13, cl_uint p14, cl_command_queue* p15, cl_uint p16, const cl_event* p17, cl_event* p18))
 //clAmdBlasStatus (*clAmdBlasZsyr2k)(clAmdBlasOrder, clAmdBlasUplo, clAmdBlasTranspose, size_t, size_t, DoubleComplex, const cl_mem, size_t, const cl_mem, size_t, DoubleComplex, cl_mem, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn18<OPENCLAMDBLAS_FN_clAmdBlasZsyr2k, clAmdBlasStatus, clAmdBlasOrder, clAmdBlasUplo, clAmdBlasTranspose, size_t, size_t, DoubleComplex, const cl_mem, size_t, const cl_mem, size_t, DoubleComplex, cl_mem, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasZsyr2k_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasZsyr2k_definition = { "clAmdBlasZsyr2k", (void**)&clAmdBlasZsyr2k};
 
+//openclamdblas_fn21(OPENCLAMDBLAS_FN_clAmdBlasZsyr2kEx, clAmdBlasStatus, (clAmdBlasOrder p1, clAmdBlasUplo p2, clAmdBlasTranspose p3, size_t p4, size_t p5, DoubleComplex p6, const cl_mem p7, size_t p8, size_t p9, const cl_mem p10, size_t p11, size_t p12, DoubleComplex p13, cl_mem p14, size_t p15, size_t p16, cl_uint p17, cl_command_queue* p18, cl_uint p19, const cl_event* p20, cl_event* p21))
 //clAmdBlasStatus (*clAmdBlasZsyr2kEx)(clAmdBlasOrder, clAmdBlasUplo, clAmdBlasTranspose, size_t, size_t, DoubleComplex, const cl_mem, size_t, size_t, const cl_mem, size_t, size_t, DoubleComplex, cl_mem, size_t, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn21<OPENCLAMDBLAS_FN_clAmdBlasZsyr2kEx, clAmdBlasStatus, clAmdBlasOrder, clAmdBlasUplo, clAmdBlasTranspose, size_t, size_t, DoubleComplex, const cl_mem, size_t, size_t, const cl_mem, size_t, size_t, DoubleComplex, cl_mem, size_t, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasZsyr2kEx_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasZsyr2kEx_definition = { "clAmdBlasZsyr2kEx", (void**)&clAmdBlasZsyr2kEx};
 
+//openclamdblas_fn16(OPENCLAMDBLAS_FN_clAmdBlasZsyrk, clAmdBlasStatus, (clAmdBlasOrder p1, clAmdBlasUplo p2, clAmdBlasTranspose p3, size_t p4, size_t p5, DoubleComplex p6, const cl_mem p7, size_t p8, DoubleComplex p9, cl_mem p10, size_t p11, cl_uint p12, cl_command_queue* p13, cl_uint p14, const cl_event* p15, cl_event* p16))
 //clAmdBlasStatus (*clAmdBlasZsyrk)(clAmdBlasOrder, clAmdBlasUplo, clAmdBlasTranspose, size_t, size_t, DoubleComplex, const cl_mem, size_t, DoubleComplex, cl_mem, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn16<OPENCLAMDBLAS_FN_clAmdBlasZsyrk, clAmdBlasStatus, clAmdBlasOrder, clAmdBlasUplo, clAmdBlasTranspose, size_t, size_t, DoubleComplex, const cl_mem, size_t, DoubleComplex, cl_mem, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasZsyrk_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasZsyrk_definition = { "clAmdBlasZsyrk", (void**)&clAmdBlasZsyrk};
 
+//openclamdblas_fn18(OPENCLAMDBLAS_FN_clAmdBlasZsyrkEx, clAmdBlasStatus, (clAmdBlasOrder p1, clAmdBlasUplo p2, clAmdBlasTranspose p3, size_t p4, size_t p5, DoubleComplex p6, const cl_mem p7, size_t p8, size_t p9, DoubleComplex p10, cl_mem p11, size_t p12, size_t p13, cl_uint p14, cl_command_queue* p15, cl_uint p16, const cl_event* p17, cl_event* p18))
 //clAmdBlasStatus (*clAmdBlasZsyrkEx)(clAmdBlasOrder, clAmdBlasUplo, clAmdBlasTranspose, size_t, size_t, DoubleComplex, const cl_mem, size_t, size_t, DoubleComplex, cl_mem, size_t, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn18<OPENCLAMDBLAS_FN_clAmdBlasZsyrkEx, clAmdBlasStatus, clAmdBlasOrder, clAmdBlasUplo, clAmdBlasTranspose, size_t, size_t, DoubleComplex, const cl_mem, size_t, size_t, DoubleComplex, cl_mem, size_t, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasZsyrkEx_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasZsyrkEx_definition = { "clAmdBlasZsyrkEx", (void**)&clAmdBlasZsyrkEx};
 
+//openclamdblas_fn18(OPENCLAMDBLAS_FN_clAmdBlasZtbmv, clAmdBlasStatus, (clAmdBlasOrder p1, clAmdBlasUplo p2, clAmdBlasTranspose p3, clAmdBlasDiag p4, size_t p5, size_t p6, const cl_mem p7, size_t p8, size_t p9, cl_mem p10, size_t p11, int p12, cl_mem p13, cl_uint p14, cl_command_queue* p15, cl_uint p16, const cl_event* p17, cl_event* p18))
 //clAmdBlasStatus (*clAmdBlasZtbmv)(clAmdBlasOrder, clAmdBlasUplo, clAmdBlasTranspose, clAmdBlasDiag, size_t, size_t, const cl_mem, size_t, size_t, cl_mem, size_t, int, cl_mem, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn18<OPENCLAMDBLAS_FN_clAmdBlasZtbmv, clAmdBlasStatus, clAmdBlasOrder, clAmdBlasUplo, clAmdBlasTranspose, clAmdBlasDiag, size_t, size_t, const cl_mem, size_t, size_t, cl_mem, size_t, int, cl_mem, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasZtbmv_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasZtbmv_definition = { "clAmdBlasZtbmv", (void**)&clAmdBlasZtbmv};
 
+//openclamdblas_fn17(OPENCLAMDBLAS_FN_clAmdBlasZtbsv, clAmdBlasStatus, (clAmdBlasOrder p1, clAmdBlasUplo p2, clAmdBlasTranspose p3, clAmdBlasDiag p4, size_t p5, size_t p6, const cl_mem p7, size_t p8, size_t p9, cl_mem p10, size_t p11, int p12, cl_uint p13, cl_command_queue* p14, cl_uint p15, const cl_event* p16, cl_event* p17))
 //clAmdBlasStatus (*clAmdBlasZtbsv)(clAmdBlasOrder, clAmdBlasUplo, clAmdBlasTranspose, clAmdBlasDiag, size_t, size_t, const cl_mem, size_t, size_t, cl_mem, size_t, int, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn17<OPENCLAMDBLAS_FN_clAmdBlasZtbsv, clAmdBlasStatus, clAmdBlasOrder, clAmdBlasUplo, clAmdBlasTranspose, clAmdBlasDiag, size_t, size_t, const cl_mem, size_t, size_t, cl_mem, size_t, int, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasZtbsv_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasZtbsv_definition = { "clAmdBlasZtbsv", (void**)&clAmdBlasZtbsv};
 
+//openclamdblas_fn16(OPENCLAMDBLAS_FN_clAmdBlasZtpmv, clAmdBlasStatus, (clAmdBlasOrder p1, clAmdBlasUplo p2, clAmdBlasTranspose p3, clAmdBlasDiag p4, size_t p5, const cl_mem p6, size_t p7, cl_mem p8, size_t p9, int p10, cl_mem p11, cl_uint p12, cl_command_queue* p13, cl_uint p14, const cl_event* p15, cl_event* p16))
 //clAmdBlasStatus (*clAmdBlasZtpmv)(clAmdBlasOrder, clAmdBlasUplo, clAmdBlasTranspose, clAmdBlasDiag, size_t, const cl_mem, size_t, cl_mem, size_t, int, cl_mem, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn16<OPENCLAMDBLAS_FN_clAmdBlasZtpmv, clAmdBlasStatus, clAmdBlasOrder, clAmdBlasUplo, clAmdBlasTranspose, clAmdBlasDiag, size_t, const cl_mem, size_t, cl_mem, size_t, int, cl_mem, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasZtpmv_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasZtpmv_definition = { "clAmdBlasZtpmv", (void**)&clAmdBlasZtpmv};
 
+//openclamdblas_fn15(OPENCLAMDBLAS_FN_clAmdBlasZtpsv, clAmdBlasStatus, (clAmdBlasOrder p1, clAmdBlasUplo p2, clAmdBlasTranspose p3, clAmdBlasDiag p4, size_t p5, const cl_mem p6, size_t p7, cl_mem p8, size_t p9, int p10, cl_uint p11, cl_command_queue* p12, cl_uint p13, const cl_event* p14, cl_event* p15))
 //clAmdBlasStatus (*clAmdBlasZtpsv)(clAmdBlasOrder, clAmdBlasUplo, clAmdBlasTranspose, clAmdBlasDiag, size_t, const cl_mem, size_t, cl_mem, size_t, int, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn15<OPENCLAMDBLAS_FN_clAmdBlasZtpsv, clAmdBlasStatus, clAmdBlasOrder, clAmdBlasUplo, clAmdBlasTranspose, clAmdBlasDiag, size_t, const cl_mem, size_t, cl_mem, size_t, int, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasZtpsv_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasZtpsv_definition = { "clAmdBlasZtpsv", (void**)&clAmdBlasZtpsv};
 
+//openclamdblas_fn17(OPENCLAMDBLAS_FN_clAmdBlasZtrmm, clAmdBlasStatus, (clAmdBlasOrder p1, clAmdBlasSide p2, clAmdBlasUplo p3, clAmdBlasTranspose p4, clAmdBlasDiag p5, size_t p6, size_t p7, DoubleComplex p8, const cl_mem p9, size_t p10, cl_mem p11, size_t p12, cl_uint p13, cl_command_queue* p14, cl_uint p15, const cl_event* p16, cl_event* p17))
 //clAmdBlasStatus (*clAmdBlasZtrmm)(clAmdBlasOrder, clAmdBlasSide, clAmdBlasUplo, clAmdBlasTranspose, clAmdBlasDiag, size_t, size_t, DoubleComplex, const cl_mem, size_t, cl_mem, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn17<OPENCLAMDBLAS_FN_clAmdBlasZtrmm, clAmdBlasStatus, clAmdBlasOrder, clAmdBlasSide, clAmdBlasUplo, clAmdBlasTranspose, clAmdBlasDiag, size_t, size_t, DoubleComplex, const cl_mem, size_t, cl_mem, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasZtrmm_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasZtrmm_definition = { "clAmdBlasZtrmm", (void**)&clAmdBlasZtrmm};
 
+//openclamdblas_fn19(OPENCLAMDBLAS_FN_clAmdBlasZtrmmEx, clAmdBlasStatus, (clAmdBlasOrder p1, clAmdBlasSide p2, clAmdBlasUplo p3, clAmdBlasTranspose p4, clAmdBlasDiag p5, size_t p6, size_t p7, DoubleComplex p8, const cl_mem p9, size_t p10, size_t p11, cl_mem p12, size_t p13, size_t p14, cl_uint p15, cl_command_queue* p16, cl_uint p17, const cl_event* p18, cl_event* p19))
 //clAmdBlasStatus (*clAmdBlasZtrmmEx)(clAmdBlasOrder, clAmdBlasSide, clAmdBlasUplo, clAmdBlasTranspose, clAmdBlasDiag, size_t, size_t, DoubleComplex, const cl_mem, size_t, size_t, cl_mem, size_t, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn19<OPENCLAMDBLAS_FN_clAmdBlasZtrmmEx, clAmdBlasStatus, clAmdBlasOrder, clAmdBlasSide, clAmdBlasUplo, clAmdBlasTranspose, clAmdBlasDiag, size_t, size_t, DoubleComplex, const cl_mem, size_t, size_t, cl_mem, size_t, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasZtrmmEx_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasZtrmmEx_definition = { "clAmdBlasZtrmmEx", (void**)&clAmdBlasZtrmmEx};
 
+//openclamdblas_fn17(OPENCLAMDBLAS_FN_clAmdBlasZtrmv, clAmdBlasStatus, (clAmdBlasOrder p1, clAmdBlasUplo p2, clAmdBlasTranspose p3, clAmdBlasDiag p4, size_t p5, const cl_mem p6, size_t p7, size_t p8, cl_mem p9, size_t p10, int p11, cl_mem p12, cl_uint p13, cl_command_queue* p14, cl_uint p15, const cl_event* p16, cl_event* p17))
 //clAmdBlasStatus (*clAmdBlasZtrmv)(clAmdBlasOrder, clAmdBlasUplo, clAmdBlasTranspose, clAmdBlasDiag, size_t, const cl_mem, size_t, size_t, cl_mem, size_t, int, cl_mem, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn17<OPENCLAMDBLAS_FN_clAmdBlasZtrmv, clAmdBlasStatus, clAmdBlasOrder, clAmdBlasUplo, clAmdBlasTranspose, clAmdBlasDiag, size_t, const cl_mem, size_t, size_t, cl_mem, size_t, int, cl_mem, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasZtrmv_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasZtrmv_definition = { "clAmdBlasZtrmv", (void**)&clAmdBlasZtrmv};
 
+//openclamdblas_fn17(OPENCLAMDBLAS_FN_clAmdBlasZtrsm, clAmdBlasStatus, (clAmdBlasOrder p1, clAmdBlasSide p2, clAmdBlasUplo p3, clAmdBlasTranspose p4, clAmdBlasDiag p5, size_t p6, size_t p7, DoubleComplex p8, const cl_mem p9, size_t p10, cl_mem p11, size_t p12, cl_uint p13, cl_command_queue* p14, cl_uint p15, const cl_event* p16, cl_event* p17))
 //clAmdBlasStatus (*clAmdBlasZtrsm)(clAmdBlasOrder, clAmdBlasSide, clAmdBlasUplo, clAmdBlasTranspose, clAmdBlasDiag, size_t, size_t, DoubleComplex, const cl_mem, size_t, cl_mem, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn17<OPENCLAMDBLAS_FN_clAmdBlasZtrsm, clAmdBlasStatus, clAmdBlasOrder, clAmdBlasSide, clAmdBlasUplo, clAmdBlasTranspose, clAmdBlasDiag, size_t, size_t, DoubleComplex, const cl_mem, size_t, cl_mem, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasZtrsm_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasZtrsm_definition = { "clAmdBlasZtrsm", (void**)&clAmdBlasZtrsm};
 
+//openclamdblas_fn19(OPENCLAMDBLAS_FN_clAmdBlasZtrsmEx, clAmdBlasStatus, (clAmdBlasOrder p1, clAmdBlasSide p2, clAmdBlasUplo p3, clAmdBlasTranspose p4, clAmdBlasDiag p5, size_t p6, size_t p7, DoubleComplex p8, const cl_mem p9, size_t p10, size_t p11, cl_mem p12, size_t p13, size_t p14, cl_uint p15, cl_command_queue* p16, cl_uint p17, const cl_event* p18, cl_event* p19))
 //clAmdBlasStatus (*clAmdBlasZtrsmEx)(clAmdBlasOrder, clAmdBlasSide, clAmdBlasUplo, clAmdBlasTranspose, clAmdBlasDiag, size_t, size_t, DoubleComplex, const cl_mem, size_t, size_t, cl_mem, size_t, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn19<OPENCLAMDBLAS_FN_clAmdBlasZtrsmEx, clAmdBlasStatus, clAmdBlasOrder, clAmdBlasSide, clAmdBlasUplo, clAmdBlasTranspose, clAmdBlasDiag, size_t, size_t, DoubleComplex, const cl_mem, size_t, size_t, cl_mem, size_t, size_t, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasZtrsmEx_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasZtrsmEx_definition = { "clAmdBlasZtrsmEx", (void**)&clAmdBlasZtrsmEx};
 
+//openclamdblas_fn16(OPENCLAMDBLAS_FN_clAmdBlasZtrsv, clAmdBlasStatus, (clAmdBlasOrder p1, clAmdBlasUplo p2, clAmdBlasTranspose p3, clAmdBlasDiag p4, size_t p5, const cl_mem p6, size_t p7, size_t p8, cl_mem p9, size_t p10, int p11, cl_uint p12, cl_command_queue* p13, cl_uint p14, const cl_event* p15, cl_event* p16))
 //clAmdBlasStatus (*clAmdBlasZtrsv)(clAmdBlasOrder, clAmdBlasUplo, clAmdBlasTranspose, clAmdBlasDiag, size_t, const cl_mem, size_t, size_t, cl_mem, size_t, int, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn16<OPENCLAMDBLAS_FN_clAmdBlasZtrsv, clAmdBlasStatus, clAmdBlasOrder, clAmdBlasUplo, clAmdBlasTranspose, clAmdBlasDiag, size_t, const cl_mem, size_t, size_t, cl_mem, size_t, int, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasZtrsv_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasZtrsv_definition = { "clAmdBlasZtrsv", (void**)&clAmdBlasZtrsv};
 
+//openclamdblas_fn12(OPENCLAMDBLAS_FN_clAmdBlasiCamax, clAmdBlasStatus, (size_t p1, cl_mem p2, size_t p3, const cl_mem p4, size_t p5, int p6, cl_mem p7, cl_uint p8, cl_command_queue* p9, cl_uint p10, const cl_event* p11, cl_event* p12))
 //clAmdBlasStatus (*clAmdBlasiCamax)(size_t, cl_mem, size_t, const cl_mem, size_t, int, cl_mem, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn12<OPENCLAMDBLAS_FN_clAmdBlasiCamax, clAmdBlasStatus, size_t, cl_mem, size_t, const cl_mem, size_t, int, cl_mem, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasiCamax_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasiCamax_definition = { "clAmdBlasiCamax", (void**)&clAmdBlasiCamax};
 
+//openclamdblas_fn12(OPENCLAMDBLAS_FN_clAmdBlasiDamax, clAmdBlasStatus, (size_t p1, cl_mem p2, size_t p3, const cl_mem p4, size_t p5, int p6, cl_mem p7, cl_uint p8, cl_command_queue* p9, cl_uint p10, const cl_event* p11, cl_event* p12))
 //clAmdBlasStatus (*clAmdBlasiDamax)(size_t, cl_mem, size_t, const cl_mem, size_t, int, cl_mem, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn12<OPENCLAMDBLAS_FN_clAmdBlasiDamax, clAmdBlasStatus, size_t, cl_mem, size_t, const cl_mem, size_t, int, cl_mem, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasiDamax_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasiDamax_definition = { "clAmdBlasiDamax", (void**)&clAmdBlasiDamax};
 
+//openclamdblas_fn12(OPENCLAMDBLAS_FN_clAmdBlasiSamax, clAmdBlasStatus, (size_t p1, cl_mem p2, size_t p3, const cl_mem p4, size_t p5, int p6, cl_mem p7, cl_uint p8, cl_command_queue* p9, cl_uint p10, const cl_event* p11, cl_event* p12))
 //clAmdBlasStatus (*clAmdBlasiSamax)(size_t, cl_mem, size_t, const cl_mem, size_t, int, cl_mem, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn12<OPENCLAMDBLAS_FN_clAmdBlasiSamax, clAmdBlasStatus, size_t, cl_mem, size_t, const cl_mem, size_t, int, cl_mem, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasiSamax_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasiSamax_definition = { "clAmdBlasiSamax", (void**)&clAmdBlasiSamax};
 
+//openclamdblas_fn12(OPENCLAMDBLAS_FN_clAmdBlasiZamax, clAmdBlasStatus, (size_t p1, cl_mem p2, size_t p3, const cl_mem p4, size_t p5, int p6, cl_mem p7, cl_uint p8, cl_command_queue* p9, cl_uint p10, const cl_event* p11, cl_event* p12))
 //clAmdBlasStatus (*clAmdBlasiZamax)(size_t, cl_mem, size_t, const cl_mem, size_t, int, cl_mem, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*) =
-//        openclamdblas_fn12<OPENCLAMDBLAS_FN_clAmdBlasiZamax, clAmdBlasStatus, size_t, cl_mem, size_t, const cl_mem, size_t, int, cl_mem, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+//        OPENCLAMDBLAS_FN_clAmdBlasiZamax_switch_fn;
 //static const struct DynamicFnEntry clAmdBlasiZamax_definition = { "clAmdBlasiZamax", (void**)&clAmdBlasiZamax};
 
 
diff --git a/modules/core/src/opencl/runtime/autogenerated/opencl_clamdfft_impl.hpp b/modules/core/src/opencl/runtime/autogenerated/opencl_clamdfft_impl.hpp
index fd36adf..6653210 100644
--- a/modules/core/src/opencl/runtime/autogenerated/opencl_clamdfft_impl.hpp
+++ b/modules/core/src/opencl/runtime/autogenerated/opencl_clamdfft_impl.hpp
@@ -39,319 +39,282 @@ enum OPENCLAMDFFT_FN_ID {
 
 namespace {
 // generated by parser_clamdfft.py
-template <int ID, typename _R>
-struct openclamdfft_fn0
-{
-    typedef _R (*FN)();
-    static _R switch_fn()
-    { return ((FN)openclamdfft_check_fn(ID))(); }
-};
-
-template <int ID, typename _R, typename _T1>
-struct openclamdfft_fn1
-{
-    typedef _R (*FN)(_T1);
-    static _R switch_fn(_T1 p1)
-    { return ((FN)openclamdfft_check_fn(ID))(p1); }
-};
-
-template <int ID, typename _R, typename _T1, typename _T2>
-struct openclamdfft_fn2
-{
-    typedef _R (*FN)(_T1, _T2);
-    static _R switch_fn(_T1 p1, _T2 p2)
-    { return ((FN)openclamdfft_check_fn(ID))(p1, p2); }
-};
-
-template <int ID, typename _R, typename _T1, typename _T2, typename _T3>
-struct openclamdfft_fn3
-{
-    typedef _R (*FN)(_T1, _T2, _T3);
-    static _R switch_fn(_T1 p1, _T2 p2, _T3 p3)
-    { return ((FN)openclamdfft_check_fn(ID))(p1, p2, p3); }
-};
-
-template <int ID, typename _R, typename _T1, typename _T2, typename _T3, typename _T4>
-struct openclamdfft_fn4
-{
-    typedef _R (*FN)(_T1, _T2, _T3, _T4);
-    static _R switch_fn(_T1 p1, _T2 p2, _T3 p3, _T4 p4)
-    { return ((FN)openclamdfft_check_fn(ID))(p1, p2, p3, p4); }
-};
-
-template <int ID, typename _R, typename _T1, typename _T2, typename _T3, typename _T4, typename _T5>
-struct openclamdfft_fn5
-{
-    typedef _R (*FN)(_T1, _T2, _T3, _T4, _T5);
-    static _R switch_fn(_T1 p1, _T2 p2, _T3 p3, _T4 p4, _T5 p5)
-    { return ((FN)openclamdfft_check_fn(ID))(p1, p2, p3, p4, p5); }
-};
-
-template <int ID, typename _R, typename _T1, typename _T2, typename _T3, typename _T4, typename _T5, typename _T6>
-struct openclamdfft_fn6
-{
-    typedef _R (*FN)(_T1, _T2, _T3, _T4, _T5, _T6);
-    static _R switch_fn(_T1 p1, _T2 p2, _T3 p3, _T4 p4, _T5 p5, _T6 p6)
-    { return ((FN)openclamdfft_check_fn(ID))(p1, p2, p3, p4, p5, p6); }
-};
-
-template <int ID, typename _R, typename _T1, typename _T2, typename _T3, typename _T4, typename _T5, typename _T6, typename _T7>
-struct openclamdfft_fn7
-{
-    typedef _R (*FN)(_T1, _T2, _T3, _T4, _T5, _T6, _T7);
-    static _R switch_fn(_T1 p1, _T2 p2, _T3 p3, _T4 p4, _T5 p5, _T6 p6, _T7 p7)
-    { return ((FN)openclamdfft_check_fn(ID))(p1, p2, p3, p4, p5, p6, p7); }
-};
-
-template <int ID, typename _R, typename _T1, typename _T2, typename _T3, typename _T4, typename _T5, typename _T6, typename _T7, typename _T8>
-struct openclamdfft_fn8
-{
-    typedef _R (*FN)(_T1, _T2, _T3, _T4, _T5, _T6, _T7, _T8);
-    static _R switch_fn(_T1 p1, _T2 p2, _T3 p3, _T4 p4, _T5 p5, _T6 p6, _T7 p7, _T8 p8)
-    { return ((FN)openclamdfft_check_fn(ID))(p1, p2, p3, p4, p5, p6, p7, p8); }
-};
-
-template <int ID, typename _R, typename _T1, typename _T2, typename _T3, typename _T4, typename _T5, typename _T6, typename _T7, typename _T8, typename _T9>
-struct openclamdfft_fn9
-{
-    typedef _R (*FN)(_T1, _T2, _T3, _T4, _T5, _T6, _T7, _T8, _T9);
-    static _R switch_fn(_T1 p1, _T2 p2, _T3 p3, _T4 p4, _T5 p5, _T6 p6, _T7 p7, _T8 p8, _T9 p9)
-    { return ((FN)openclamdfft_check_fn(ID))(p1, p2, p3, p4, p5, p6, p7, p8, p9); }
-};
-
-template <int ID, typename _R, typename _T1, typename _T2, typename _T3, typename _T4, typename _T5, typename _T6, typename _T7, typename _T8, typename _T9, typename _T10>
-struct openclamdfft_fn10
-{
-    typedef _R (*FN)(_T1, _T2, _T3, _T4, _T5, _T6, _T7, _T8, _T9, _T10);
-    static _R switch_fn(_T1 p1, _T2 p2, _T3 p3, _T4 p4, _T5 p5, _T6 p6, _T7 p7, _T8 p8, _T9 p9, _T10 p10)
-    { return ((FN)openclamdfft_check_fn(ID))(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10); }
-};
-
-template <int ID, typename _R, typename _T1, typename _T2, typename _T3, typename _T4, typename _T5, typename _T6, typename _T7, typename _T8, typename _T9, typename _T10, typename _T11>
-struct openclamdfft_fn11
-{
-    typedef _R (*FN)(_T1, _T2, _T3, _T4, _T5, _T6, _T7, _T8, _T9, _T10, _T11);
-    static _R switch_fn(_T1 p1, _T2 p2, _T3 p3, _T4 p4, _T5 p5, _T6 p6, _T7 p7, _T8 p8, _T9 p9, _T10 p10, _T11 p11)
-    { return ((FN)openclamdfft_check_fn(ID))(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11); }
-};
-
-template <int ID, typename _R, typename _T1, typename _T2, typename _T3, typename _T4, typename _T5, typename _T6, typename _T7, typename _T8, typename _T9, typename _T10, typename _T11, typename _T12>
-struct openclamdfft_fn12
-{
-    typedef _R (*FN)(_T1, _T2, _T3, _T4, _T5, _T6, _T7, _T8, _T9, _T10, _T11, _T12);
-    static _R switch_fn(_T1 p1, _T2 p2, _T3 p3, _T4 p4, _T5 p5, _T6 p6, _T7 p7, _T8 p8, _T9 p9, _T10 p10, _T11 p11, _T12 p12)
-    { return ((FN)openclamdfft_check_fn(ID))(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12); }
-};
-
-template <int ID, typename _R, typename _T1, typename _T2, typename _T3, typename _T4, typename _T5, typename _T6, typename _T7, typename _T8, typename _T9, typename _T10, typename _T11, typename _T12, typename _T13>
-struct openclamdfft_fn13
-{
-    typedef _R (*FN)(_T1, _T2, _T3, _T4, _T5, _T6, _T7, _T8, _T9, _T10, _T11, _T12, _T13);
-    static _R switch_fn(_T1 p1, _T2 p2, _T3 p3, _T4 p4, _T5 p5, _T6 p6, _T7 p7, _T8 p8, _T9 p9, _T10 p10, _T11 p11, _T12 p12, _T13 p13)
-    { return ((FN)openclamdfft_check_fn(ID))(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13); }
-};
-
-template <int ID, typename _R, typename _T1, typename _T2, typename _T3, typename _T4, typename _T5, typename _T6, typename _T7, typename _T8, typename _T9, typename _T10, typename _T11, typename _T12, typename _T13, typename _T14>
-struct openclamdfft_fn14
-{
-    typedef _R (*FN)(_T1, _T2, _T3, _T4, _T5, _T6, _T7, _T8, _T9, _T10, _T11, _T12, _T13, _T14);
-    static _R switch_fn(_T1 p1, _T2 p2, _T3 p3, _T4 p4, _T5 p5, _T6 p6, _T7 p7, _T8 p8, _T9 p9, _T10 p10, _T11 p11, _T12 p12, _T13 p13, _T14 p14)
-    { return ((FN)openclamdfft_check_fn(ID))(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14); }
-};
-
-template <int ID, typename _R, typename _T1, typename _T2, typename _T3, typename _T4, typename _T5, typename _T6, typename _T7, typename _T8, typename _T9, typename _T10, typename _T11, typename _T12, typename _T13, typename _T14, typename _T15>
-struct openclamdfft_fn15
-{
-    typedef _R (*FN)(_T1, _T2, _T3, _T4, _T5, _T6, _T7, _T8, _T9, _T10, _T11, _T12, _T13, _T14, _T15);
-    static _R switch_fn(_T1 p1, _T2 p2, _T3 p3, _T4 p4, _T5 p5, _T6 p6, _T7 p7, _T8 p8, _T9 p9, _T10 p10, _T11 p11, _T12 p12, _T13 p13, _T14 p14, _T15 p15)
-    { return ((FN)openclamdfft_check_fn(ID))(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15); }
-};
-
-template <int ID, typename _R, typename _T1, typename _T2, typename _T3, typename _T4, typename _T5, typename _T6, typename _T7, typename _T8, typename _T9, typename _T10, typename _T11, typename _T12, typename _T13, typename _T14, typename _T15, typename _T16>
-struct openclamdfft_fn16
-{
-    typedef _R (*FN)(_T1, _T2, _T3, _T4, _T5, _T6, _T7, _T8, _T9, _T10, _T11, _T12, _T13, _T14, _T15, _T16);
-    static _R switch_fn(_T1 p1, _T2 p2, _T3 p3, _T4 p4, _T5 p5, _T6 p6, _T7 p7, _T8 p8, _T9 p9, _T10 p10, _T11 p11, _T12 p12, _T13 p13, _T14 p14, _T15 p15, _T16 p16)
-    { return ((FN)openclamdfft_check_fn(ID))(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16); }
-};
-
-template <int ID, typename _R, typename _T1, typename _T2, typename _T3, typename _T4, typename _T5, typename _T6, typename _T7, typename _T8, typename _T9, typename _T10, typename _T11, typename _T12, typename _T13, typename _T14, typename _T15, typename _T16, typename _T17>
-struct openclamdfft_fn17
-{
-    typedef _R (*FN)(_T1, _T2, _T3, _T4, _T5, _T6, _T7, _T8, _T9, _T10, _T11, _T12, _T13, _T14, _T15, _T16, _T17);
-    static _R switch_fn(_T1 p1, _T2 p2, _T3 p3, _T4 p4, _T5 p5, _T6 p6, _T7 p7, _T8 p8, _T9 p9, _T10 p10, _T11 p11, _T12 p12, _T13 p13, _T14 p14, _T15 p15, _T16 p16, _T17 p17)
-    { return ((FN)openclamdfft_check_fn(ID))(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17); }
-};
-
-template <int ID, typename _R, typename _T1, typename _T2, typename _T3, typename _T4, typename _T5, typename _T6, typename _T7, typename _T8, typename _T9, typename _T10, typename _T11, typename _T12, typename _T13, typename _T14, typename _T15, typename _T16, typename _T17, typename _T18>
-struct openclamdfft_fn18
-{
-    typedef _R (*FN)(_T1, _T2, _T3, _T4, _T5, _T6, _T7, _T8, _T9, _T10, _T11, _T12, _T13, _T14, _T15, _T16, _T17, _T18);
-    static _R switch_fn(_T1 p1, _T2 p2, _T3 p3, _T4 p4, _T5 p5, _T6 p6, _T7 p7, _T8 p8, _T9 p9, _T10 p10, _T11 p11, _T12 p12, _T13 p13, _T14 p14, _T15 p15, _T16 p16, _T17 p17, _T18 p18)
-    { return ((FN)openclamdfft_check_fn(ID))(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18); }
-};
-
-template <int ID, typename _R, typename _T1, typename _T2, typename _T3, typename _T4, typename _T5, typename _T6, typename _T7, typename _T8, typename _T9, typename _T10, typename _T11, typename _T12, typename _T13, typename _T14, typename _T15, typename _T16, typename _T17, typename _T18, typename _T19>
-struct openclamdfft_fn19
-{
-    typedef _R (*FN)(_T1, _T2, _T3, _T4, _T5, _T6, _T7, _T8, _T9, _T10, _T11, _T12, _T13, _T14, _T15, _T16, _T17, _T18, _T19);
-    static _R switch_fn(_T1 p1, _T2 p2, _T3 p3, _T4 p4, _T5 p5, _T6 p6, _T7 p7, _T8 p8, _T9 p9, _T10 p10, _T11 p11, _T12 p12, _T13 p13, _T14 p14, _T15 p15, _T16 p16, _T17 p17, _T18 p18, _T19 p19)
-    { return ((FN)openclamdfft_check_fn(ID))(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19); }
-};
-
-template <int ID, typename _R, typename _T1, typename _T2, typename _T3, typename _T4, typename _T5, typename _T6, typename _T7, typename _T8, typename _T9, typename _T10, typename _T11, typename _T12, typename _T13, typename _T14, typename _T15, typename _T16, typename _T17, typename _T18, typename _T19, typename _T20>
-struct openclamdfft_fn20
-{
-    typedef _R (*FN)(_T1, _T2, _T3, _T4, _T5, _T6, _T7, _T8, _T9, _T10, _T11, _T12, _T13, _T14, _T15, _T16, _T17, _T18, _T19, _T20);
-    static _R switch_fn(_T1 p1, _T2 p2, _T3 p3, _T4 p4, _T5 p5, _T6 p6, _T7 p7, _T8 p8, _T9 p9, _T10 p10, _T11 p11, _T12 p12, _T13 p13, _T14 p14, _T15 p15, _T16 p16, _T17 p17, _T18 p18, _T19 p19, _T20 p20)
-    { return ((FN)openclamdfft_check_fn(ID))(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20); }
-};
-
-template <int ID, typename _R, typename _T1, typename _T2, typename _T3, typename _T4, typename _T5, typename _T6, typename _T7, typename _T8, typename _T9, typename _T10, typename _T11, typename _T12, typename _T13, typename _T14, typename _T15, typename _T16, typename _T17, typename _T18, typename _T19, typename _T20, typename _T21>
-struct openclamdfft_fn21
-{
-    typedef _R (*FN)(_T1, _T2, _T3, _T4, _T5, _T6, _T7, _T8, _T9, _T10, _T11, _T12, _T13, _T14, _T15, _T16, _T17, _T18, _T19, _T20, _T21);
-    static _R switch_fn(_T1 p1, _T2 p2, _T3 p3, _T4 p4, _T5 p5, _T6 p6, _T7 p7, _T8 p8, _T9 p9, _T10 p10, _T11 p11, _T12 p12, _T13 p13, _T14 p14, _T15 p15, _T16 p16, _T17 p17, _T18 p18, _T19 p19, _T20 p20, _T21 p21)
-    { return ((FN)openclamdfft_check_fn(ID))(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, p21); }
-};
-
-template <int ID, typename _R, typename _T1, typename _T2, typename _T3, typename _T4, typename _T5, typename _T6, typename _T7, typename _T8, typename _T9, typename _T10, typename _T11, typename _T12, typename _T13, typename _T14, typename _T15, typename _T16, typename _T17, typename _T18, typename _T19, typename _T20, typename _T21, typename _T22>
-struct openclamdfft_fn22
-{
-    typedef _R (*FN)(_T1, _T2, _T3, _T4, _T5, _T6, _T7, _T8, _T9, _T10, _T11, _T12, _T13, _T14, _T15, _T16, _T17, _T18, _T19, _T20, _T21, _T22);
-    static _R switch_fn(_T1 p1, _T2 p2, _T3 p3, _T4 p4, _T5 p5, _T6 p6, _T7 p7, _T8 p8, _T9 p9, _T10 p10, _T11 p11, _T12 p12, _T13 p13, _T14 p14, _T15 p15, _T16 p16, _T17 p17, _T18 p18, _T19 p19, _T20 p20, _T21 p21, _T22 p22)
-    { return ((FN)openclamdfft_check_fn(ID))(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, p21, p22); }
-};
+#define openclamdfft_fn0(ID, _R, decl_args) \
+    typedef _R (*ID##FN)decl_args; \
+    static _R ID##_switch_fn decl_args \
+    { return ((ID##FN)openclamdfft_check_fn(ID))(); } \
+
+#define openclamdfft_fn1(ID, _R, decl_args) \
+    typedef _R (*ID##FN)decl_args; \
+    static _R ID##_switch_fn decl_args \
+    { return ((ID##FN)openclamdfft_check_fn(ID))(p1); } \
+
+#define openclamdfft_fn2(ID, _R, decl_args) \
+    typedef _R (*ID##FN)decl_args; \
+    static _R ID##_switch_fn decl_args \
+    { return ((ID##FN)openclamdfft_check_fn(ID))(p1, p2); } \
+
+#define openclamdfft_fn3(ID, _R, decl_args) \
+    typedef _R (*ID##FN)decl_args; \
+    static _R ID##_switch_fn decl_args \
+    { return ((ID##FN)openclamdfft_check_fn(ID))(p1, p2, p3); } \
+
+#define openclamdfft_fn4(ID, _R, decl_args) \
+    typedef _R (*ID##FN)decl_args; \
+    static _R ID##_switch_fn decl_args \
+    { return ((ID##FN)openclamdfft_check_fn(ID))(p1, p2, p3, p4); } \
+
+#define openclamdfft_fn5(ID, _R, decl_args) \
+    typedef _R (*ID##FN)decl_args; \
+    static _R ID##_switch_fn decl_args \
+    { return ((ID##FN)openclamdfft_check_fn(ID))(p1, p2, p3, p4, p5); } \
+
+#define openclamdfft_fn6(ID, _R, decl_args) \
+    typedef _R (*ID##FN)decl_args; \
+    static _R ID##_switch_fn decl_args \
+    { return ((ID##FN)openclamdfft_check_fn(ID))(p1, p2, p3, p4, p5, p6); } \
+
+#define openclamdfft_fn7(ID, _R, decl_args) \
+    typedef _R (*ID##FN)decl_args; \
+    static _R ID##_switch_fn decl_args \
+    { return ((ID##FN)openclamdfft_check_fn(ID))(p1, p2, p3, p4, p5, p6, p7); } \
+
+#define openclamdfft_fn8(ID, _R, decl_args) \
+    typedef _R (*ID##FN)decl_args; \
+    static _R ID##_switch_fn decl_args \
+    { return ((ID##FN)openclamdfft_check_fn(ID))(p1, p2, p3, p4, p5, p6, p7, p8); } \
+
+#define openclamdfft_fn9(ID, _R, decl_args) \
+    typedef _R (*ID##FN)decl_args; \
+    static _R ID##_switch_fn decl_args \
+    { return ((ID##FN)openclamdfft_check_fn(ID))(p1, p2, p3, p4, p5, p6, p7, p8, p9); } \
+
+#define openclamdfft_fn10(ID, _R, decl_args) \
+    typedef _R (*ID##FN)decl_args; \
+    static _R ID##_switch_fn decl_args \
+    { return ((ID##FN)openclamdfft_check_fn(ID))(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10); } \
+
+#define openclamdfft_fn11(ID, _R, decl_args) \
+    typedef _R (*ID##FN)decl_args; \
+    static _R ID##_switch_fn decl_args \
+    { return ((ID##FN)openclamdfft_check_fn(ID))(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11); } \
+
+#define openclamdfft_fn12(ID, _R, decl_args) \
+    typedef _R (*ID##FN)decl_args; \
+    static _R ID##_switch_fn decl_args \
+    { return ((ID##FN)openclamdfft_check_fn(ID))(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12); } \
+
+#define openclamdfft_fn13(ID, _R, decl_args) \
+    typedef _R (*ID##FN)decl_args; \
+    static _R ID##_switch_fn decl_args \
+    { return ((ID##FN)openclamdfft_check_fn(ID))(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13); } \
+
+#define openclamdfft_fn14(ID, _R, decl_args) \
+    typedef _R (*ID##FN)decl_args; \
+    static _R ID##_switch_fn decl_args \
+    { return ((ID##FN)openclamdfft_check_fn(ID))(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14); } \
+
+#define openclamdfft_fn15(ID, _R, decl_args) \
+    typedef _R (*ID##FN)decl_args; \
+    static _R ID##_switch_fn decl_args \
+    { return ((ID##FN)openclamdfft_check_fn(ID))(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15); } \
+
+#define openclamdfft_fn16(ID, _R, decl_args) \
+    typedef _R (*ID##FN)decl_args; \
+    static _R ID##_switch_fn decl_args \
+    { return ((ID##FN)openclamdfft_check_fn(ID))(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16); } \
+
+#define openclamdfft_fn17(ID, _R, decl_args) \
+    typedef _R (*ID##FN)decl_args; \
+    static _R ID##_switch_fn decl_args \
+    { return ((ID##FN)openclamdfft_check_fn(ID))(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17); } \
+
+#define openclamdfft_fn18(ID, _R, decl_args) \
+    typedef _R (*ID##FN)decl_args; \
+    static _R ID##_switch_fn decl_args \
+    { return ((ID##FN)openclamdfft_check_fn(ID))(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18); } \
+
+#define openclamdfft_fn19(ID, _R, decl_args) \
+    typedef _R (*ID##FN)decl_args; \
+    static _R ID##_switch_fn decl_args \
+    { return ((ID##FN)openclamdfft_check_fn(ID))(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19); } \
+
+#define openclamdfft_fn20(ID, _R, decl_args) \
+    typedef _R (*ID##FN)decl_args; \
+    static _R ID##_switch_fn decl_args \
+    { return ((ID##FN)openclamdfft_check_fn(ID))(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20); } \
+
+#define openclamdfft_fn21(ID, _R, decl_args) \
+    typedef _R (*ID##FN)decl_args; \
+    static _R ID##_switch_fn decl_args \
+    { return ((ID##FN)openclamdfft_check_fn(ID))(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, p21); } \
+
+#define openclamdfft_fn22(ID, _R, decl_args) \
+    typedef _R (*ID##FN)decl_args; \
+    static _R ID##_switch_fn decl_args \
+    { return ((ID##FN)openclamdfft_check_fn(ID))(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, p21, p22); } \
 
 }
 
 // generated by parser_clamdfft.py
+openclamdfft_fn5(OPENCLAMDFFT_FN_clAmdFftBakePlan, clAmdFftStatus, (clAmdFftPlanHandle p1, cl_uint p2, cl_command_queue* p3, void (CL_CALLBACK*p4) (clAmdFftPlanHandle plHandle, void* user_data), void* p5))
 clAmdFftStatus (*clAmdFftBakePlan)(clAmdFftPlanHandle, cl_uint, cl_command_queue*, void (CL_CALLBACK*) (clAmdFftPlanHandle plHandle, void* user_data), void*) =
-        openclamdfft_fn5<OPENCLAMDFFT_FN_clAmdFftBakePlan, clAmdFftStatus, clAmdFftPlanHandle, cl_uint, cl_command_queue*, void (CL_CALLBACK*) (clAmdFftPlanHandle plHandle, void* user_data), void*>::switch_fn;
+        OPENCLAMDFFT_FN_clAmdFftBakePlan_switch_fn;
 static const struct DynamicFnEntry clAmdFftBakePlan_definition = { "clAmdFftBakePlan", (void**)&clAmdFftBakePlan};
 
+//openclamdfft_fn3(OPENCLAMDFFT_FN_clAmdFftCopyPlan, clAmdFftStatus, (clAmdFftPlanHandle* p1, cl_context p2, clAmdFftPlanHandle p3))
 //clAmdFftStatus (*clAmdFftCopyPlan)(clAmdFftPlanHandle*, cl_context, clAmdFftPlanHandle) =
-//        openclamdfft_fn3<OPENCLAMDFFT_FN_clAmdFftCopyPlan, clAmdFftStatus, clAmdFftPlanHandle*, cl_context, clAmdFftPlanHandle>::switch_fn;
+//        OPENCLAMDFFT_FN_clAmdFftCopyPlan_switch_fn;
 //static const struct DynamicFnEntry clAmdFftCopyPlan_definition = { "clAmdFftCopyPlan", (void**)&clAmdFftCopyPlan};
 
+openclamdfft_fn4(OPENCLAMDFFT_FN_clAmdFftCreateDefaultPlan, clAmdFftStatus, (clAmdFftPlanHandle* p1, cl_context p2, const clAmdFftDim p3, const size_t* p4))
 clAmdFftStatus (*clAmdFftCreateDefaultPlan)(clAmdFftPlanHandle*, cl_context, const clAmdFftDim, const size_t*) =
-        openclamdfft_fn4<OPENCLAMDFFT_FN_clAmdFftCreateDefaultPlan, clAmdFftStatus, clAmdFftPlanHandle*, cl_context, const clAmdFftDim, const size_t*>::switch_fn;
+        OPENCLAMDFFT_FN_clAmdFftCreateDefaultPlan_switch_fn;
 static const struct DynamicFnEntry clAmdFftCreateDefaultPlan_definition = { "clAmdFftCreateDefaultPlan", (void**)&clAmdFftCreateDefaultPlan};
 
+openclamdfft_fn1(OPENCLAMDFFT_FN_clAmdFftDestroyPlan, clAmdFftStatus, (clAmdFftPlanHandle* p1))
 clAmdFftStatus (*clAmdFftDestroyPlan)(clAmdFftPlanHandle*) =
-        openclamdfft_fn1<OPENCLAMDFFT_FN_clAmdFftDestroyPlan, clAmdFftStatus, clAmdFftPlanHandle*>::switch_fn;
+        OPENCLAMDFFT_FN_clAmdFftDestroyPlan_switch_fn;
 static const struct DynamicFnEntry clAmdFftDestroyPlan_definition = { "clAmdFftDestroyPlan", (void**)&clAmdFftDestroyPlan};
 
+openclamdfft_fn10(OPENCLAMDFFT_FN_clAmdFftEnqueueTransform, clAmdFftStatus, (clAmdFftPlanHandle p1, clAmdFftDirection p2, cl_uint p3, cl_command_queue* p4, cl_uint p5, const cl_event* p6, cl_event* p7, cl_mem* p8, cl_mem* p9, cl_mem p10))
 clAmdFftStatus (*clAmdFftEnqueueTransform)(clAmdFftPlanHandle, clAmdFftDirection, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*, cl_mem*, cl_mem*, cl_mem) =
-        openclamdfft_fn10<OPENCLAMDFFT_FN_clAmdFftEnqueueTransform, clAmdFftStatus, clAmdFftPlanHandle, clAmdFftDirection, cl_uint, cl_command_queue*, cl_uint, const cl_event*, cl_event*, cl_mem*, cl_mem*, cl_mem>::switch_fn;
+        OPENCLAMDFFT_FN_clAmdFftEnqueueTransform_switch_fn;
 static const struct DynamicFnEntry clAmdFftEnqueueTransform_definition = { "clAmdFftEnqueueTransform", (void**)&clAmdFftEnqueueTransform};
 
+//openclamdfft_fn3(OPENCLAMDFFT_FN_clAmdFftGetLayout, clAmdFftStatus, (const clAmdFftPlanHandle p1, clAmdFftLayout* p2, clAmdFftLayout* p3))
 //clAmdFftStatus (*clAmdFftGetLayout)(const clAmdFftPlanHandle, clAmdFftLayout*, clAmdFftLayout*) =
-//        openclamdfft_fn3<OPENCLAMDFFT_FN_clAmdFftGetLayout, clAmdFftStatus, const clAmdFftPlanHandle, clAmdFftLayout*, clAmdFftLayout*>::switch_fn;
+//        OPENCLAMDFFT_FN_clAmdFftGetLayout_switch_fn;
 //static const struct DynamicFnEntry clAmdFftGetLayout_definition = { "clAmdFftGetLayout", (void**)&clAmdFftGetLayout};
 
+//openclamdfft_fn2(OPENCLAMDFFT_FN_clAmdFftGetPlanBatchSize, clAmdFftStatus, (const clAmdFftPlanHandle p1, size_t* p2))
 //clAmdFftStatus (*clAmdFftGetPlanBatchSize)(const clAmdFftPlanHandle, size_t*) =
-//        openclamdfft_fn2<OPENCLAMDFFT_FN_clAmdFftGetPlanBatchSize, clAmdFftStatus, const clAmdFftPlanHandle, size_t*>::switch_fn;
+//        OPENCLAMDFFT_FN_clAmdFftGetPlanBatchSize_switch_fn;
 //static const struct DynamicFnEntry clAmdFftGetPlanBatchSize_definition = { "clAmdFftGetPlanBatchSize", (void**)&clAmdFftGetPlanBatchSize};
 
+//openclamdfft_fn2(OPENCLAMDFFT_FN_clAmdFftGetPlanContext, clAmdFftStatus, (const clAmdFftPlanHandle p1, cl_context* p2))
 //clAmdFftStatus (*clAmdFftGetPlanContext)(const clAmdFftPlanHandle, cl_context*) =
-//        openclamdfft_fn2<OPENCLAMDFFT_FN_clAmdFftGetPlanContext, clAmdFftStatus, const clAmdFftPlanHandle, cl_context*>::switch_fn;
+//        OPENCLAMDFFT_FN_clAmdFftGetPlanContext_switch_fn;
 //static const struct DynamicFnEntry clAmdFftGetPlanContext_definition = { "clAmdFftGetPlanContext", (void**)&clAmdFftGetPlanContext};
 
+//openclamdfft_fn3(OPENCLAMDFFT_FN_clAmdFftGetPlanDim, clAmdFftStatus, (const clAmdFftPlanHandle p1, clAmdFftDim* p2, cl_uint* p3))
 //clAmdFftStatus (*clAmdFftGetPlanDim)(const clAmdFftPlanHandle, clAmdFftDim*, cl_uint*) =
-//        openclamdfft_fn3<OPENCLAMDFFT_FN_clAmdFftGetPlanDim, clAmdFftStatus, const clAmdFftPlanHandle, clAmdFftDim*, cl_uint*>::switch_fn;
+//        OPENCLAMDFFT_FN_clAmdFftGetPlanDim_switch_fn;
 //static const struct DynamicFnEntry clAmdFftGetPlanDim_definition = { "clAmdFftGetPlanDim", (void**)&clAmdFftGetPlanDim};
 
+//openclamdfft_fn3(OPENCLAMDFFT_FN_clAmdFftGetPlanDistance, clAmdFftStatus, (const clAmdFftPlanHandle p1, size_t* p2, size_t* p3))
 //clAmdFftStatus (*clAmdFftGetPlanDistance)(const clAmdFftPlanHandle, size_t*, size_t*) =
-//        openclamdfft_fn3<OPENCLAMDFFT_FN_clAmdFftGetPlanDistance, clAmdFftStatus, const clAmdFftPlanHandle, size_t*, size_t*>::switch_fn;
+//        OPENCLAMDFFT_FN_clAmdFftGetPlanDistance_switch_fn;
 //static const struct DynamicFnEntry clAmdFftGetPlanDistance_definition = { "clAmdFftGetPlanDistance", (void**)&clAmdFftGetPlanDistance};
 
+//openclamdfft_fn3(OPENCLAMDFFT_FN_clAmdFftGetPlanInStride, clAmdFftStatus, (const clAmdFftPlanHandle p1, const clAmdFftDim p2, size_t* p3))
 //clAmdFftStatus (*clAmdFftGetPlanInStride)(const clAmdFftPlanHandle, const clAmdFftDim, size_t*) =
-//        openclamdfft_fn3<OPENCLAMDFFT_FN_clAmdFftGetPlanInStride, clAmdFftStatus, const clAmdFftPlanHandle, const clAmdFftDim, size_t*>::switch_fn;
+//        OPENCLAMDFFT_FN_clAmdFftGetPlanInStride_switch_fn;
 //static const struct DynamicFnEntry clAmdFftGetPlanInStride_definition = { "clAmdFftGetPlanInStride", (void**)&clAmdFftGetPlanInStride};
 
+//openclamdfft_fn3(OPENCLAMDFFT_FN_clAmdFftGetPlanLength, clAmdFftStatus, (const clAmdFftPlanHandle p1, const clAmdFftDim p2, size_t* p3))
 //clAmdFftStatus (*clAmdFftGetPlanLength)(const clAmdFftPlanHandle, const clAmdFftDim, size_t*) =
-//        openclamdfft_fn3<OPENCLAMDFFT_FN_clAmdFftGetPlanLength, clAmdFftStatus, const clAmdFftPlanHandle, const clAmdFftDim, size_t*>::switch_fn;
+//        OPENCLAMDFFT_FN_clAmdFftGetPlanLength_switch_fn;
 //static const struct DynamicFnEntry clAmdFftGetPlanLength_definition = { "clAmdFftGetPlanLength", (void**)&clAmdFftGetPlanLength};
 
+//openclamdfft_fn3(OPENCLAMDFFT_FN_clAmdFftGetPlanOutStride, clAmdFftStatus, (const clAmdFftPlanHandle p1, const clAmdFftDim p2, size_t* p3))
 //clAmdFftStatus (*clAmdFftGetPlanOutStride)(const clAmdFftPlanHandle, const clAmdFftDim, size_t*) =
-//        openclamdfft_fn3<OPENCLAMDFFT_FN_clAmdFftGetPlanOutStride, clAmdFftStatus, const clAmdFftPlanHandle, const clAmdFftDim, size_t*>::switch_fn;
+//        OPENCLAMDFFT_FN_clAmdFftGetPlanOutStride_switch_fn;
 //static const struct DynamicFnEntry clAmdFftGetPlanOutStride_definition = { "clAmdFftGetPlanOutStride", (void**)&clAmdFftGetPlanOutStride};
 
+//openclamdfft_fn2(OPENCLAMDFFT_FN_clAmdFftGetPlanPrecision, clAmdFftStatus, (const clAmdFftPlanHandle p1, clAmdFftPrecision* p2))
 //clAmdFftStatus (*clAmdFftGetPlanPrecision)(const clAmdFftPlanHandle, clAmdFftPrecision*) =
-//        openclamdfft_fn2<OPENCLAMDFFT_FN_clAmdFftGetPlanPrecision, clAmdFftStatus, const clAmdFftPlanHandle, clAmdFftPrecision*>::switch_fn;
+//        OPENCLAMDFFT_FN_clAmdFftGetPlanPrecision_switch_fn;
 //static const struct DynamicFnEntry clAmdFftGetPlanPrecision_definition = { "clAmdFftGetPlanPrecision", (void**)&clAmdFftGetPlanPrecision};
 
+//openclamdfft_fn3(OPENCLAMDFFT_FN_clAmdFftGetPlanScale, clAmdFftStatus, (const clAmdFftPlanHandle p1, clAmdFftDirection p2, cl_float* p3))
 //clAmdFftStatus (*clAmdFftGetPlanScale)(const clAmdFftPlanHandle, clAmdFftDirection, cl_float*) =
-//        openclamdfft_fn3<OPENCLAMDFFT_FN_clAmdFftGetPlanScale, clAmdFftStatus, const clAmdFftPlanHandle, clAmdFftDirection, cl_float*>::switch_fn;
+//        OPENCLAMDFFT_FN_clAmdFftGetPlanScale_switch_fn;
 //static const struct DynamicFnEntry clAmdFftGetPlanScale_definition = { "clAmdFftGetPlanScale", (void**)&clAmdFftGetPlanScale};
 
+//openclamdfft_fn2(OPENCLAMDFFT_FN_clAmdFftGetPlanTransposeResult, clAmdFftStatus, (const clAmdFftPlanHandle p1, clAmdFftResultTransposed* p2))
 //clAmdFftStatus (*clAmdFftGetPlanTransposeResult)(const clAmdFftPlanHandle, clAmdFftResultTransposed*) =
-//        openclamdfft_fn2<OPENCLAMDFFT_FN_clAmdFftGetPlanTransposeResult, clAmdFftStatus, const clAmdFftPlanHandle, clAmdFftResultTransposed*>::switch_fn;
+//        OPENCLAMDFFT_FN_clAmdFftGetPlanTransposeResult_switch_fn;
 //static const struct DynamicFnEntry clAmdFftGetPlanTransposeResult_definition = { "clAmdFftGetPlanTransposeResult", (void**)&clAmdFftGetPlanTransposeResult};
 
+//openclamdfft_fn2(OPENCLAMDFFT_FN_clAmdFftGetResultLocation, clAmdFftStatus, (const clAmdFftPlanHandle p1, clAmdFftResultLocation* p2))
 //clAmdFftStatus (*clAmdFftGetResultLocation)(const clAmdFftPlanHandle, clAmdFftResultLocation*) =
-//        openclamdfft_fn2<OPENCLAMDFFT_FN_clAmdFftGetResultLocation, clAmdFftStatus, const clAmdFftPlanHandle, clAmdFftResultLocation*>::switch_fn;
+//        OPENCLAMDFFT_FN_clAmdFftGetResultLocation_switch_fn;
 //static const struct DynamicFnEntry clAmdFftGetResultLocation_definition = { "clAmdFftGetResultLocation", (void**)&clAmdFftGetResultLocation};
 
+openclamdfft_fn2(OPENCLAMDFFT_FN_clAmdFftGetTmpBufSize, clAmdFftStatus, (const clAmdFftPlanHandle p1, size_t* p2))
 clAmdFftStatus (*clAmdFftGetTmpBufSize)(const clAmdFftPlanHandle, size_t*) =
-        openclamdfft_fn2<OPENCLAMDFFT_FN_clAmdFftGetTmpBufSize, clAmdFftStatus, const clAmdFftPlanHandle, size_t*>::switch_fn;
+        OPENCLAMDFFT_FN_clAmdFftGetTmpBufSize_switch_fn;
 static const struct DynamicFnEntry clAmdFftGetTmpBufSize_definition = { "clAmdFftGetTmpBufSize", (void**)&clAmdFftGetTmpBufSize};
 
+openclamdfft_fn3(OPENCLAMDFFT_FN_clAmdFftGetVersion, clAmdFftStatus, (cl_uint* p1, cl_uint* p2, cl_uint* p3))
 clAmdFftStatus (*clAmdFftGetVersion)(cl_uint*, cl_uint*, cl_uint*) =
-        openclamdfft_fn3<OPENCLAMDFFT_FN_clAmdFftGetVersion, clAmdFftStatus, cl_uint*, cl_uint*, cl_uint*>::switch_fn;
+        OPENCLAMDFFT_FN_clAmdFftGetVersion_switch_fn;
 static const struct DynamicFnEntry clAmdFftGetVersion_definition = { "clAmdFftGetVersion", (void**)&clAmdFftGetVersion};
 
+openclamdfft_fn3(OPENCLAMDFFT_FN_clAmdFftSetLayout, clAmdFftStatus, (clAmdFftPlanHandle p1, clAmdFftLayout p2, clAmdFftLayout p3))
 clAmdFftStatus (*clAmdFftSetLayout)(clAmdFftPlanHandle, clAmdFftLayout, clAmdFftLayout) =
-        openclamdfft_fn3<OPENCLAMDFFT_FN_clAmdFftSetLayout, clAmdFftStatus, clAmdFftPlanHandle, clAmdFftLayout, clAmdFftLayout>::switch_fn;
+        OPENCLAMDFFT_FN_clAmdFftSetLayout_switch_fn;
 static const struct DynamicFnEntry clAmdFftSetLayout_definition = { "clAmdFftSetLayout", (void**)&clAmdFftSetLayout};
 
+openclamdfft_fn2(OPENCLAMDFFT_FN_clAmdFftSetPlanBatchSize, clAmdFftStatus, (clAmdFftPlanHandle p1, size_t p2))
 clAmdFftStatus (*clAmdFftSetPlanBatchSize)(clAmdFftPlanHandle, size_t) =
-        openclamdfft_fn2<OPENCLAMDFFT_FN_clAmdFftSetPlanBatchSize, clAmdFftStatus, clAmdFftPlanHandle, size_t>::switch_fn;
+        OPENCLAMDFFT_FN_clAmdFftSetPlanBatchSize_switch_fn;
 static const struct DynamicFnEntry clAmdFftSetPlanBatchSize_definition = { "clAmdFftSetPlanBatchSize", (void**)&clAmdFftSetPlanBatchSize};
 
+//openclamdfft_fn2(OPENCLAMDFFT_FN_clAmdFftSetPlanDim, clAmdFftStatus, (clAmdFftPlanHandle p1, const clAmdFftDim p2))
 //clAmdFftStatus (*clAmdFftSetPlanDim)(clAmdFftPlanHandle, const clAmdFftDim) =
-//        openclamdfft_fn2<OPENCLAMDFFT_FN_clAmdFftSetPlanDim, clAmdFftStatus, clAmdFftPlanHandle, const clAmdFftDim>::switch_fn;
+//        OPENCLAMDFFT_FN_clAmdFftSetPlanDim_switch_fn;
 //static const struct DynamicFnEntry clAmdFftSetPlanDim_definition = { "clAmdFftSetPlanDim", (void**)&clAmdFftSetPlanDim};
 
+openclamdfft_fn3(OPENCLAMDFFT_FN_clAmdFftSetPlanDistance, clAmdFftStatus, (clAmdFftPlanHandle p1, size_t p2, size_t p3))
 clAmdFftStatus (*clAmdFftSetPlanDistance)(clAmdFftPlanHandle, size_t, size_t) =
-        openclamdfft_fn3<OPENCLAMDFFT_FN_clAmdFftSetPlanDistance, clAmdFftStatus, clAmdFftPlanHandle, size_t, size_t>::switch_fn;
+        OPENCLAMDFFT_FN_clAmdFftSetPlanDistance_switch_fn;
 static const struct DynamicFnEntry clAmdFftSetPlanDistance_definition = { "clAmdFftSetPlanDistance", (void**)&clAmdFftSetPlanDistance};
 
+openclamdfft_fn3(OPENCLAMDFFT_FN_clAmdFftSetPlanInStride, clAmdFftStatus, (clAmdFftPlanHandle p1, const clAmdFftDim p2, size_t* p3))
 clAmdFftStatus (*clAmdFftSetPlanInStride)(clAmdFftPlanHandle, const clAmdFftDim, size_t*) =
-        openclamdfft_fn3<OPENCLAMDFFT_FN_clAmdFftSetPlanInStride, clAmdFftStatus, clAmdFftPlanHandle, const clAmdFftDim, size_t*>::switch_fn;
+        OPENCLAMDFFT_FN_clAmdFftSetPlanInStride_switch_fn;
 static const struct DynamicFnEntry clAmdFftSetPlanInStride_definition = { "clAmdFftSetPlanInStride", (void**)&clAmdFftSetPlanInStride};
 
+//openclamdfft_fn3(OPENCLAMDFFT_FN_clAmdFftSetPlanLength, clAmdFftStatus, (clAmdFftPlanHandle p1, const clAmdFftDim p2, const size_t* p3))
 //clAmdFftStatus (*clAmdFftSetPlanLength)(clAmdFftPlanHandle, const clAmdFftDim, const size_t*) =
-//        openclamdfft_fn3<OPENCLAMDFFT_FN_clAmdFftSetPlanLength, clAmdFftStatus, clAmdFftPlanHandle, const clAmdFftDim, const size_t*>::switch_fn;
+//        OPENCLAMDFFT_FN_clAmdFftSetPlanLength_switch_fn;
 //static const struct DynamicFnEntry clAmdFftSetPlanLength_definition = { "clAmdFftSetPlanLength", (void**)&clAmdFftSetPlanLength};
 
+openclamdfft_fn3(OPENCLAMDFFT_FN_clAmdFftSetPlanOutStride, clAmdFftStatus, (clAmdFftPlanHandle p1, const clAmdFftDim p2, size_t* p3))
 clAmdFftStatus (*clAmdFftSetPlanOutStride)(clAmdFftPlanHandle, const clAmdFftDim, size_t*) =
-        openclamdfft_fn3<OPENCLAMDFFT_FN_clAmdFftSetPlanOutStride, clAmdFftStatus, clAmdFftPlanHandle, const clAmdFftDim, size_t*>::switch_fn;
+        OPENCLAMDFFT_FN_clAmdFftSetPlanOutStride_switch_fn;
 static const struct DynamicFnEntry clAmdFftSetPlanOutStride_definition = { "clAmdFftSetPlanOutStride", (void**)&clAmdFftSetPlanOutStride};
 
+openclamdfft_fn2(OPENCLAMDFFT_FN_clAmdFftSetPlanPrecision, clAmdFftStatus, (clAmdFftPlanHandle p1, clAmdFftPrecision p2))
 clAmdFftStatus (*clAmdFftSetPlanPrecision)(clAmdFftPlanHandle, clAmdFftPrecision) =
-        openclamdfft_fn2<OPENCLAMDFFT_FN_clAmdFftSetPlanPrecision, clAmdFftStatus, clAmdFftPlanHandle, clAmdFftPrecision>::switch_fn;
+        OPENCLAMDFFT_FN_clAmdFftSetPlanPrecision_switch_fn;
 static const struct DynamicFnEntry clAmdFftSetPlanPrecision_definition = { "clAmdFftSetPlanPrecision", (void**)&clAmdFftSetPlanPrecision};
 
+openclamdfft_fn3(OPENCLAMDFFT_FN_clAmdFftSetPlanScale, clAmdFftStatus, (clAmdFftPlanHandle p1, clAmdFftDirection p2, cl_float p3))
 clAmdFftStatus (*clAmdFftSetPlanScale)(clAmdFftPlanHandle, clAmdFftDirection, cl_float) =
-        openclamdfft_fn3<OPENCLAMDFFT_FN_clAmdFftSetPlanScale, clAmdFftStatus, clAmdFftPlanHandle, clAmdFftDirection, cl_float>::switch_fn;
+        OPENCLAMDFFT_FN_clAmdFftSetPlanScale_switch_fn;
 static const struct DynamicFnEntry clAmdFftSetPlanScale_definition = { "clAmdFftSetPlanScale", (void**)&clAmdFftSetPlanScale};
 
+//openclamdfft_fn2(OPENCLAMDFFT_FN_clAmdFftSetPlanTransposeResult, clAmdFftStatus, (clAmdFftPlanHandle p1, clAmdFftResultTransposed p2))
 //clAmdFftStatus (*clAmdFftSetPlanTransposeResult)(clAmdFftPlanHandle, clAmdFftResultTransposed) =
-//        openclamdfft_fn2<OPENCLAMDFFT_FN_clAmdFftSetPlanTransposeResult, clAmdFftStatus, clAmdFftPlanHandle, clAmdFftResultTransposed>::switch_fn;
+//        OPENCLAMDFFT_FN_clAmdFftSetPlanTransposeResult_switch_fn;
 //static const struct DynamicFnEntry clAmdFftSetPlanTransposeResult_definition = { "clAmdFftSetPlanTransposeResult", (void**)&clAmdFftSetPlanTransposeResult};
 
+openclamdfft_fn2(OPENCLAMDFFT_FN_clAmdFftSetResultLocation, clAmdFftStatus, (clAmdFftPlanHandle p1, clAmdFftResultLocation p2))
 clAmdFftStatus (*clAmdFftSetResultLocation)(clAmdFftPlanHandle, clAmdFftResultLocation) =
-        openclamdfft_fn2<OPENCLAMDFFT_FN_clAmdFftSetResultLocation, clAmdFftStatus, clAmdFftPlanHandle, clAmdFftResultLocation>::switch_fn;
+        OPENCLAMDFFT_FN_clAmdFftSetResultLocation_switch_fn;
 static const struct DynamicFnEntry clAmdFftSetResultLocation_definition = { "clAmdFftSetResultLocation", (void**)&clAmdFftSetResultLocation};
 
+openclamdfft_fn1(OPENCLAMDFFT_FN_clAmdFftSetup, clAmdFftStatus, (const clAmdFftSetupData* p1))
 clAmdFftStatus (*clAmdFftSetup)(const clAmdFftSetupData*) =
-        openclamdfft_fn1<OPENCLAMDFFT_FN_clAmdFftSetup, clAmdFftStatus, const clAmdFftSetupData*>::switch_fn;
+        OPENCLAMDFFT_FN_clAmdFftSetup_switch_fn;
 static const struct DynamicFnEntry clAmdFftSetup_definition = { "clAmdFftSetup", (void**)&clAmdFftSetup};
 
+openclamdfft_fn0(OPENCLAMDFFT_FN_clAmdFftTeardown, clAmdFftStatus, ())
 clAmdFftStatus (*clAmdFftTeardown)() =
-        openclamdfft_fn0<OPENCLAMDFFT_FN_clAmdFftTeardown, clAmdFftStatus>::switch_fn;
+        OPENCLAMDFFT_FN_clAmdFftTeardown_switch_fn;
 static const struct DynamicFnEntry clAmdFftTeardown_definition = { "clAmdFftTeardown", (void**)&clAmdFftTeardown};
 
 
diff --git a/modules/core/src/opencl/runtime/autogenerated/opencl_core_impl.hpp b/modules/core/src/opencl/runtime/autogenerated/opencl_core_impl.hpp
index 913b523..e761260 100644
--- a/modules/core/src/opencl/runtime/autogenerated/opencl_core_impl.hpp
+++ b/modules/core/src/opencl/runtime/autogenerated/opencl_core_impl.hpp
@@ -95,479 +95,522 @@ enum OPENCL_FN_ID {
 
 namespace {
 // generated by parser_cl.py
-template <int ID, typename _R>
-struct opencl_fn0
-{
-    typedef _R (CL_API_CALL*FN)();
-    static _R CL_API_CALL switch_fn()
-    { return ((FN)opencl_check_fn(ID))(); }
-};
-
-template <int ID, typename _R, typename _T1>
-struct opencl_fn1
-{
-    typedef _R (CL_API_CALL*FN)(_T1);
-    static _R CL_API_CALL switch_fn(_T1 p1)
-    { return ((FN)opencl_check_fn(ID))(p1); }
-};
-
-template <int ID, typename _R, typename _T1, typename _T2>
-struct opencl_fn2
-{
-    typedef _R (CL_API_CALL*FN)(_T1, _T2);
-    static _R CL_API_CALL switch_fn(_T1 p1, _T2 p2)
-    { return ((FN)opencl_check_fn(ID))(p1, p2); }
-};
-
-template <int ID, typename _R, typename _T1, typename _T2, typename _T3>
-struct opencl_fn3
-{
-    typedef _R (CL_API_CALL*FN)(_T1, _T2, _T3);
-    static _R CL_API_CALL switch_fn(_T1 p1, _T2 p2, _T3 p3)
-    { return ((FN)opencl_check_fn(ID))(p1, p2, p3); }
-};
-
-template <int ID, typename _R, typename _T1, typename _T2, typename _T3, typename _T4>
-struct opencl_fn4
-{
-    typedef _R (CL_API_CALL*FN)(_T1, _T2, _T3, _T4);
-    static _R CL_API_CALL switch_fn(_T1 p1, _T2 p2, _T3 p3, _T4 p4)
-    { return ((FN)opencl_check_fn(ID))(p1, p2, p3, p4); }
-};
-
-template <int ID, typename _R, typename _T1, typename _T2, typename _T3, typename _T4, typename _T5>
-struct opencl_fn5
-{
-    typedef _R (CL_API_CALL*FN)(_T1, _T2, _T3, _T4, _T5);
-    static _R CL_API_CALL switch_fn(_T1 p1, _T2 p2, _T3 p3, _T4 p4, _T5 p5)
-    { return ((FN)opencl_check_fn(ID))(p1, p2, p3, p4, p5); }
-};
-
-template <int ID, typename _R, typename _T1, typename _T2, typename _T3, typename _T4, typename _T5, typename _T6>
-struct opencl_fn6
-{
-    typedef _R (CL_API_CALL*FN)(_T1, _T2, _T3, _T4, _T5, _T6);
-    static _R CL_API_CALL switch_fn(_T1 p1, _T2 p2, _T3 p3, _T4 p4, _T5 p5, _T6 p6)
-    { return ((FN)opencl_check_fn(ID))(p1, p2, p3, p4, p5, p6); }
-};
-
-template <int ID, typename _R, typename _T1, typename _T2, typename _T3, typename _T4, typename _T5, typename _T6, typename _T7>
-struct opencl_fn7
-{
-    typedef _R (CL_API_CALL*FN)(_T1, _T2, _T3, _T4, _T5, _T6, _T7);
-    static _R CL_API_CALL switch_fn(_T1 p1, _T2 p2, _T3 p3, _T4 p4, _T5 p5, _T6 p6, _T7 p7)
-    { return ((FN)opencl_check_fn(ID))(p1, p2, p3, p4, p5, p6, p7); }
-};
-
-template <int ID, typename _R, typename _T1, typename _T2, typename _T3, typename _T4, typename _T5, typename _T6, typename _T7, typename _T8>
-struct opencl_fn8
-{
-    typedef _R (CL_API_CALL*FN)(_T1, _T2, _T3, _T4, _T5, _T6, _T7, _T8);
-    static _R CL_API_CALL switch_fn(_T1 p1, _T2 p2, _T3 p3, _T4 p4, _T5 p5, _T6 p6, _T7 p7, _T8 p8)
-    { return ((FN)opencl_check_fn(ID))(p1, p2, p3, p4, p5, p6, p7, p8); }
-};
-
-template <int ID, typename _R, typename _T1, typename _T2, typename _T3, typename _T4, typename _T5, typename _T6, typename _T7, typename _T8, typename _T9>
-struct opencl_fn9
-{
-    typedef _R (CL_API_CALL*FN)(_T1, _T2, _T3, _T4, _T5, _T6, _T7, _T8, _T9);
-    static _R CL_API_CALL switch_fn(_T1 p1, _T2 p2, _T3 p3, _T4 p4, _T5 p5, _T6 p6, _T7 p7, _T8 p8, _T9 p9)
-    { return ((FN)opencl_check_fn(ID))(p1, p2, p3, p4, p5, p6, p7, p8, p9); }
-};
-
-template <int ID, typename _R, typename _T1, typename _T2, typename _T3, typename _T4, typename _T5, typename _T6, typename _T7, typename _T8, typename _T9, typename _T10>
-struct opencl_fn10
-{
-    typedef _R (CL_API_CALL*FN)(_T1, _T2, _T3, _T4, _T5, _T6, _T7, _T8, _T9, _T10);
-    static _R CL_API_CALL switch_fn(_T1 p1, _T2 p2, _T3 p3, _T4 p4, _T5 p5, _T6 p6, _T7 p7, _T8 p8, _T9 p9, _T10 p10)
-    { return ((FN)opencl_check_fn(ID))(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10); }
-};
-
-template <int ID, typename _R, typename _T1, typename _T2, typename _T3, typename _T4, typename _T5, typename _T6, typename _T7, typename _T8, typename _T9, typename _T10, typename _T11>
-struct opencl_fn11
-{
-    typedef _R (CL_API_CALL*FN)(_T1, _T2, _T3, _T4, _T5, _T6, _T7, _T8, _T9, _T10, _T11);
-    static _R CL_API_CALL switch_fn(_T1 p1, _T2 p2, _T3 p3, _T4 p4, _T5 p5, _T6 p6, _T7 p7, _T8 p8, _T9 p9, _T10 p10, _T11 p11)
-    { return ((FN)opencl_check_fn(ID))(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11); }
-};
-
-template <int ID, typename _R, typename _T1, typename _T2, typename _T3, typename _T4, typename _T5, typename _T6, typename _T7, typename _T8, typename _T9, typename _T10, typename _T11, typename _T12>
-struct opencl_fn12
-{
-    typedef _R (CL_API_CALL*FN)(_T1, _T2, _T3, _T4, _T5, _T6, _T7, _T8, _T9, _T10, _T11, _T12);
-    static _R CL_API_CALL switch_fn(_T1 p1, _T2 p2, _T3 p3, _T4 p4, _T5 p5, _T6 p6, _T7 p7, _T8 p8, _T9 p9, _T10 p10, _T11 p11, _T12 p12)
-    { return ((FN)opencl_check_fn(ID))(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12); }
-};
-
-template <int ID, typename _R, typename _T1, typename _T2, typename _T3, typename _T4, typename _T5, typename _T6, typename _T7, typename _T8, typename _T9, typename _T10, typename _T11, typename _T12, typename _T13>
-struct opencl_fn13
-{
-    typedef _R (CL_API_CALL*FN)(_T1, _T2, _T3, _T4, _T5, _T6, _T7, _T8, _T9, _T10, _T11, _T12, _T13);
-    static _R CL_API_CALL switch_fn(_T1 p1, _T2 p2, _T3 p3, _T4 p4, _T5 p5, _T6 p6, _T7 p7, _T8 p8, _T9 p9, _T10 p10, _T11 p11, _T12 p12, _T13 p13)
-    { return ((FN)opencl_check_fn(ID))(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13); }
-};
-
-template <int ID, typename _R, typename _T1, typename _T2, typename _T3, typename _T4, typename _T5, typename _T6, typename _T7, typename _T8, typename _T9, typename _T10, typename _T11, typename _T12, typename _T13, typename _T14>
-struct opencl_fn14
-{
-    typedef _R (CL_API_CALL*FN)(_T1, _T2, _T3, _T4, _T5, _T6, _T7, _T8, _T9, _T10, _T11, _T12, _T13, _T14);
-    static _R CL_API_CALL switch_fn(_T1 p1, _T2 p2, _T3 p3, _T4 p4, _T5 p5, _T6 p6, _T7 p7, _T8 p8, _T9 p9, _T10 p10, _T11 p11, _T12 p12, _T13 p13, _T14 p14)
-    { return ((FN)opencl_check_fn(ID))(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14); }
-};
+#define opencl_fn0(ID, _R, decl_args) \
+    typedef _R (CL_API_CALL*ID##FN)decl_args; \
+    static _R CL_API_CALL ID##_switch_fn decl_args \
+    { return ((ID##FN)opencl_check_fn(ID))(); } \
+
+#define opencl_fn1(ID, _R, decl_args) \
+    typedef _R (CL_API_CALL*ID##FN)decl_args; \
+    static _R CL_API_CALL ID##_switch_fn decl_args \
+    { return ((ID##FN)opencl_check_fn(ID))(p1); } \
+
+#define opencl_fn2(ID, _R, decl_args) \
+    typedef _R (CL_API_CALL*ID##FN)decl_args; \
+    static _R CL_API_CALL ID##_switch_fn decl_args \
+    { return ((ID##FN)opencl_check_fn(ID))(p1, p2); } \
+
+#define opencl_fn3(ID, _R, decl_args) \
+    typedef _R (CL_API_CALL*ID##FN)decl_args; \
+    static _R CL_API_CALL ID##_switch_fn decl_args \
+    { return ((ID##FN)opencl_check_fn(ID))(p1, p2, p3); } \
+
+#define opencl_fn4(ID, _R, decl_args) \
+    typedef _R (CL_API_CALL*ID##FN)decl_args; \
+    static _R CL_API_CALL ID##_switch_fn decl_args \
+    { return ((ID##FN)opencl_check_fn(ID))(p1, p2, p3, p4); } \
+
+#define opencl_fn5(ID, _R, decl_args) \
+    typedef _R (CL_API_CALL*ID##FN)decl_args; \
+    static _R CL_API_CALL ID##_switch_fn decl_args \
+    { return ((ID##FN)opencl_check_fn(ID))(p1, p2, p3, p4, p5); } \
+
+#define opencl_fn6(ID, _R, decl_args) \
+    typedef _R (CL_API_CALL*ID##FN)decl_args; \
+    static _R CL_API_CALL ID##_switch_fn decl_args \
+    { return ((ID##FN)opencl_check_fn(ID))(p1, p2, p3, p4, p5, p6); } \
+
+#define opencl_fn7(ID, _R, decl_args) \
+    typedef _R (CL_API_CALL*ID##FN)decl_args; \
+    static _R CL_API_CALL ID##_switch_fn decl_args \
+    { return ((ID##FN)opencl_check_fn(ID))(p1, p2, p3, p4, p5, p6, p7); } \
+
+#define opencl_fn8(ID, _R, decl_args) \
+    typedef _R (CL_API_CALL*ID##FN)decl_args; \
+    static _R CL_API_CALL ID##_switch_fn decl_args \
+    { return ((ID##FN)opencl_check_fn(ID))(p1, p2, p3, p4, p5, p6, p7, p8); } \
+
+#define opencl_fn9(ID, _R, decl_args) \
+    typedef _R (CL_API_CALL*ID##FN)decl_args; \
+    static _R CL_API_CALL ID##_switch_fn decl_args \
+    { return ((ID##FN)opencl_check_fn(ID))(p1, p2, p3, p4, p5, p6, p7, p8, p9); } \
+
+#define opencl_fn10(ID, _R, decl_args) \
+    typedef _R (CL_API_CALL*ID##FN)decl_args; \
+    static _R CL_API_CALL ID##_switch_fn decl_args \
+    { return ((ID##FN)opencl_check_fn(ID))(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10); } \
+
+#define opencl_fn11(ID, _R, decl_args) \
+    typedef _R (CL_API_CALL*ID##FN)decl_args; \
+    static _R CL_API_CALL ID##_switch_fn decl_args \
+    { return ((ID##FN)opencl_check_fn(ID))(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11); } \
+
+#define opencl_fn12(ID, _R, decl_args) \
+    typedef _R (CL_API_CALL*ID##FN)decl_args; \
+    static _R CL_API_CALL ID##_switch_fn decl_args \
+    { return ((ID##FN)opencl_check_fn(ID))(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12); } \
+
+#define opencl_fn13(ID, _R, decl_args) \
+    typedef _R (CL_API_CALL*ID##FN)decl_args; \
+    static _R CL_API_CALL ID##_switch_fn decl_args \
+    { return ((ID##FN)opencl_check_fn(ID))(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13); } \
+
+#define opencl_fn14(ID, _R, decl_args) \
+    typedef _R (CL_API_CALL*ID##FN)decl_args; \
+    static _R CL_API_CALL ID##_switch_fn decl_args \
+    { return ((ID##FN)opencl_check_fn(ID))(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14); } \
 
 } // anonymous namespace
 
 // generated by parser_cl.py
+opencl_fn6(OPENCL_FN_clBuildProgram, cl_int, (cl_program p1, cl_uint p2, const cl_device_id* p3, const char* p4, void (CL_CALLBACK*p5) (cl_program, void*), void* p6))
 cl_int (CL_API_CALL*clBuildProgram)(cl_program, cl_uint, const cl_device_id*, const char*, void (CL_CALLBACK*) (cl_program, void*), void*) =
-        opencl_fn6<OPENCL_FN_clBuildProgram, cl_int, cl_program, cl_uint, const cl_device_id*, const char*, void (CL_CALLBACK*) (cl_program, void*), void*>::switch_fn;
+        OPENCL_FN_clBuildProgram_switch_fn;
 static const struct DynamicFnEntry clBuildProgram_definition = { "clBuildProgram", (void**)&clBuildProgram};
 
+opencl_fn9(OPENCL_FN_clCompileProgram, cl_int, (cl_program p1, cl_uint p2, const cl_device_id* p3, const char* p4, cl_uint p5, const cl_program* p6, const char** p7, void (CL_CALLBACK*p8) (cl_program, void*), void* p9))
 cl_int (CL_API_CALL*clCompileProgram)(cl_program, cl_uint, const cl_device_id*, const char*, cl_uint, const cl_program*, const char**, void (CL_CALLBACK*) (cl_program, void*), void*) =
-        opencl_fn9<OPENCL_FN_clCompileProgram, cl_int, cl_program, cl_uint, const cl_device_id*, const char*, cl_uint, const cl_program*, const char**, void (CL_CALLBACK*) (cl_program, void*), void*>::switch_fn;
+        OPENCL_FN_clCompileProgram_switch_fn;
 static const struct DynamicFnEntry clCompileProgram_definition = { "clCompileProgram", (void**)&clCompileProgram};
 
+opencl_fn5(OPENCL_FN_clCreateBuffer, cl_mem, (cl_context p1, cl_mem_flags p2, size_t p3, void* p4, cl_int* p5))
 cl_mem (CL_API_CALL*clCreateBuffer)(cl_context, cl_mem_flags, size_t, void*, cl_int*) =
-        opencl_fn5<OPENCL_FN_clCreateBuffer, cl_mem, cl_context, cl_mem_flags, size_t, void*, cl_int*>::switch_fn;
+        OPENCL_FN_clCreateBuffer_switch_fn;
 static const struct DynamicFnEntry clCreateBuffer_definition = { "clCreateBuffer", (void**)&clCreateBuffer};
 
+opencl_fn4(OPENCL_FN_clCreateCommandQueue, cl_command_queue, (cl_context p1, cl_device_id p2, cl_command_queue_properties p3, cl_int* p4))
 cl_command_queue (CL_API_CALL*clCreateCommandQueue)(cl_context, cl_device_id, cl_command_queue_properties, cl_int*) =
-        opencl_fn4<OPENCL_FN_clCreateCommandQueue, cl_command_queue, cl_context, cl_device_id, cl_command_queue_properties, cl_int*>::switch_fn;
+        OPENCL_FN_clCreateCommandQueue_switch_fn;
 static const struct DynamicFnEntry clCreateCommandQueue_definition = { "clCreateCommandQueue", (void**)&clCreateCommandQueue};
 
+opencl_fn6(OPENCL_FN_clCreateContext, cl_context, (const cl_context_properties* p1, cl_uint p2, const cl_device_id* p3, void (CL_CALLBACK*p4) (const char*, const void*, size_t, void*), void* p5, cl_int* p6))
 cl_context (CL_API_CALL*clCreateContext)(const cl_context_properties*, cl_uint, const cl_device_id*, void (CL_CALLBACK*) (const char*, const void*, size_t, void*), void*, cl_int*) =
-        opencl_fn6<OPENCL_FN_clCreateContext, cl_context, const cl_context_properties*, cl_uint, const cl_device_id*, void (CL_CALLBACK*) (const char*, const void*, size_t, void*), void*, cl_int*>::switch_fn;
+        OPENCL_FN_clCreateContext_switch_fn;
 static const struct DynamicFnEntry clCreateContext_definition = { "clCreateContext", (void**)&clCreateContext};
 
+opencl_fn5(OPENCL_FN_clCreateContextFromType, cl_context, (const cl_context_properties* p1, cl_device_type p2, void (CL_CALLBACK*p3) (const char*, const void*, size_t, void*), void* p4, cl_int* p5))
 cl_context (CL_API_CALL*clCreateContextFromType)(const cl_context_properties*, cl_device_type, void (CL_CALLBACK*) (const char*, const void*, size_t, void*), void*, cl_int*) =
-        opencl_fn5<OPENCL_FN_clCreateContextFromType, cl_context, const cl_context_properties*, cl_device_type, void (CL_CALLBACK*) (const char*, const void*, size_t, void*), void*, cl_int*>::switch_fn;
+        OPENCL_FN_clCreateContextFromType_switch_fn;
 static const struct DynamicFnEntry clCreateContextFromType_definition = { "clCreateContextFromType", (void**)&clCreateContextFromType};
 
+opencl_fn6(OPENCL_FN_clCreateImage, cl_mem, (cl_context p1, cl_mem_flags p2, const cl_image_format* p3, const cl_image_desc* p4, void* p5, cl_int* p6))
 cl_mem (CL_API_CALL*clCreateImage)(cl_context, cl_mem_flags, const cl_image_format*, const cl_image_desc*, void*, cl_int*) =
-        opencl_fn6<OPENCL_FN_clCreateImage, cl_mem, cl_context, cl_mem_flags, const cl_image_format*, const cl_image_desc*, void*, cl_int*>::switch_fn;
+        OPENCL_FN_clCreateImage_switch_fn;
 static const struct DynamicFnEntry clCreateImage_definition = { "clCreateImage", (void**)&clCreateImage};
 
+opencl_fn8(OPENCL_FN_clCreateImage2D, cl_mem, (cl_context p1, cl_mem_flags p2, const cl_image_format* p3, size_t p4, size_t p5, size_t p6, void* p7, cl_int* p8))
 cl_mem (CL_API_CALL*clCreateImage2D)(cl_context, cl_mem_flags, const cl_image_format*, size_t, size_t, size_t, void*, cl_int*) =
-        opencl_fn8<OPENCL_FN_clCreateImage2D, cl_mem, cl_context, cl_mem_flags, const cl_image_format*, size_t, size_t, size_t, void*, cl_int*>::switch_fn;
+        OPENCL_FN_clCreateImage2D_switch_fn;
 static const struct DynamicFnEntry clCreateImage2D_definition = { "clCreateImage2D", (void**)&clCreateImage2D};
 
+opencl_fn10(OPENCL_FN_clCreateImage3D, cl_mem, (cl_context p1, cl_mem_flags p2, const cl_image_format* p3, size_t p4, size_t p5, size_t p6, size_t p7, size_t p8, void* p9, cl_int* p10))
 cl_mem (CL_API_CALL*clCreateImage3D)(cl_context, cl_mem_flags, const cl_image_format*, size_t, size_t, size_t, size_t, size_t, void*, cl_int*) =
-        opencl_fn10<OPENCL_FN_clCreateImage3D, cl_mem, cl_context, cl_mem_flags, const cl_image_format*, size_t, size_t, size_t, size_t, size_t, void*, cl_int*>::switch_fn;
+        OPENCL_FN_clCreateImage3D_switch_fn;
 static const struct DynamicFnEntry clCreateImage3D_definition = { "clCreateImage3D", (void**)&clCreateImage3D};
 
+opencl_fn3(OPENCL_FN_clCreateKernel, cl_kernel, (cl_program p1, const char* p2, cl_int* p3))
 cl_kernel (CL_API_CALL*clCreateKernel)(cl_program, const char*, cl_int*) =
-        opencl_fn3<OPENCL_FN_clCreateKernel, cl_kernel, cl_program, const char*, cl_int*>::switch_fn;
+        OPENCL_FN_clCreateKernel_switch_fn;
 static const struct DynamicFnEntry clCreateKernel_definition = { "clCreateKernel", (void**)&clCreateKernel};
 
+opencl_fn4(OPENCL_FN_clCreateKernelsInProgram, cl_int, (cl_program p1, cl_uint p2, cl_kernel* p3, cl_uint* p4))
 cl_int (CL_API_CALL*clCreateKernelsInProgram)(cl_program, cl_uint, cl_kernel*, cl_uint*) =
-        opencl_fn4<OPENCL_FN_clCreateKernelsInProgram, cl_int, cl_program, cl_uint, cl_kernel*, cl_uint*>::switch_fn;
+        OPENCL_FN_clCreateKernelsInProgram_switch_fn;
 static const struct DynamicFnEntry clCreateKernelsInProgram_definition = { "clCreateKernelsInProgram", (void**)&clCreateKernelsInProgram};
 
+opencl_fn7(OPENCL_FN_clCreateProgramWithBinary, cl_program, (cl_context p1, cl_uint p2, const cl_device_id* p3, const size_t* p4, const unsigned char** p5, cl_int* p6, cl_int* p7))
 cl_program (CL_API_CALL*clCreateProgramWithBinary)(cl_context, cl_uint, const cl_device_id*, const size_t*, const unsigned char**, cl_int*, cl_int*) =
-        opencl_fn7<OPENCL_FN_clCreateProgramWithBinary, cl_program, cl_context, cl_uint, const cl_device_id*, const size_t*, const unsigned char**, cl_int*, cl_int*>::switch_fn;
+        OPENCL_FN_clCreateProgramWithBinary_switch_fn;
 static const struct DynamicFnEntry clCreateProgramWithBinary_definition = { "clCreateProgramWithBinary", (void**)&clCreateProgramWithBinary};
 
+opencl_fn5(OPENCL_FN_clCreateProgramWithBuiltInKernels, cl_program, (cl_context p1, cl_uint p2, const cl_device_id* p3, const char* p4, cl_int* p5))
 cl_program (CL_API_CALL*clCreateProgramWithBuiltInKernels)(cl_context, cl_uint, const cl_device_id*, const char*, cl_int*) =
-        opencl_fn5<OPENCL_FN_clCreateProgramWithBuiltInKernels, cl_program, cl_context, cl_uint, const cl_device_id*, const char*, cl_int*>::switch_fn;
+        OPENCL_FN_clCreateProgramWithBuiltInKernels_switch_fn;
 static const struct DynamicFnEntry clCreateProgramWithBuiltInKernels_definition = { "clCreateProgramWithBuiltInKernels", (void**)&clCreateProgramWithBuiltInKernels};
 
+opencl_fn5(OPENCL_FN_clCreateProgramWithSource, cl_program, (cl_context p1, cl_uint p2, const char** p3, const size_t* p4, cl_int* p5))
 cl_program (CL_API_CALL*clCreateProgramWithSource)(cl_context, cl_uint, const char**, const size_t*, cl_int*) =
-        opencl_fn5<OPENCL_FN_clCreateProgramWithSource, cl_program, cl_context, cl_uint, const char**, const size_t*, cl_int*>::switch_fn;
+        OPENCL_FN_clCreateProgramWithSource_switch_fn;
 static const struct DynamicFnEntry clCreateProgramWithSource_definition = { "clCreateProgramWithSource", (void**)&clCreateProgramWithSource};
 
+opencl_fn5(OPENCL_FN_clCreateSampler, cl_sampler, (cl_context p1, cl_bool p2, cl_addressing_mode p3, cl_filter_mode p4, cl_int* p5))
 cl_sampler (CL_API_CALL*clCreateSampler)(cl_context, cl_bool, cl_addressing_mode, cl_filter_mode, cl_int*) =
-        opencl_fn5<OPENCL_FN_clCreateSampler, cl_sampler, cl_context, cl_bool, cl_addressing_mode, cl_filter_mode, cl_int*>::switch_fn;
+        OPENCL_FN_clCreateSampler_switch_fn;
 static const struct DynamicFnEntry clCreateSampler_definition = { "clCreateSampler", (void**)&clCreateSampler};
 
+opencl_fn5(OPENCL_FN_clCreateSubBuffer, cl_mem, (cl_mem p1, cl_mem_flags p2, cl_buffer_create_type p3, const void* p4, cl_int* p5))
 cl_mem (CL_API_CALL*clCreateSubBuffer)(cl_mem, cl_mem_flags, cl_buffer_create_type, const void*, cl_int*) =
-        opencl_fn5<OPENCL_FN_clCreateSubBuffer, cl_mem, cl_mem, cl_mem_flags, cl_buffer_create_type, const void*, cl_int*>::switch_fn;
+        OPENCL_FN_clCreateSubBuffer_switch_fn;
 static const struct DynamicFnEntry clCreateSubBuffer_definition = { "clCreateSubBuffer", (void**)&clCreateSubBuffer};
 
+opencl_fn5(OPENCL_FN_clCreateSubDevices, cl_int, (cl_device_id p1, const cl_device_partition_property* p2, cl_uint p3, cl_device_id* p4, cl_uint* p5))
 cl_int (CL_API_CALL*clCreateSubDevices)(cl_device_id, const cl_device_partition_property*, cl_uint, cl_device_id*, cl_uint*) =
-        opencl_fn5<OPENCL_FN_clCreateSubDevices, cl_int, cl_device_id, const cl_device_partition_property*, cl_uint, cl_device_id*, cl_uint*>::switch_fn;
+        OPENCL_FN_clCreateSubDevices_switch_fn;
 static const struct DynamicFnEntry clCreateSubDevices_definition = { "clCreateSubDevices", (void**)&clCreateSubDevices};
 
+opencl_fn2(OPENCL_FN_clCreateUserEvent, cl_event, (cl_context p1, cl_int* p2))
 cl_event (CL_API_CALL*clCreateUserEvent)(cl_context, cl_int*) =
-        opencl_fn2<OPENCL_FN_clCreateUserEvent, cl_event, cl_context, cl_int*>::switch_fn;
+        OPENCL_FN_clCreateUserEvent_switch_fn;
 static const struct DynamicFnEntry clCreateUserEvent_definition = { "clCreateUserEvent", (void**)&clCreateUserEvent};
 
+opencl_fn1(OPENCL_FN_clEnqueueBarrier, cl_int, (cl_command_queue p1))
 cl_int (CL_API_CALL*clEnqueueBarrier)(cl_command_queue) =
-        opencl_fn1<OPENCL_FN_clEnqueueBarrier, cl_int, cl_command_queue>::switch_fn;
+        OPENCL_FN_clEnqueueBarrier_switch_fn;
 static const struct DynamicFnEntry clEnqueueBarrier_definition = { "clEnqueueBarrier", (void**)&clEnqueueBarrier};
 
+opencl_fn4(OPENCL_FN_clEnqueueBarrierWithWaitList, cl_int, (cl_command_queue p1, cl_uint p2, const cl_event* p3, cl_event* p4))
 cl_int (CL_API_CALL*clEnqueueBarrierWithWaitList)(cl_command_queue, cl_uint, const cl_event*, cl_event*) =
-        opencl_fn4<OPENCL_FN_clEnqueueBarrierWithWaitList, cl_int, cl_command_queue, cl_uint, const cl_event*, cl_event*>::switch_fn;
+        OPENCL_FN_clEnqueueBarrierWithWaitList_switch_fn;
 static const struct DynamicFnEntry clEnqueueBarrierWithWaitList_definition = { "clEnqueueBarrierWithWaitList", (void**)&clEnqueueBarrierWithWaitList};
 
+opencl_fn9(OPENCL_FN_clEnqueueCopyBuffer, cl_int, (cl_command_queue p1, cl_mem p2, cl_mem p3, size_t p4, size_t p5, size_t p6, cl_uint p7, const cl_event* p8, cl_event* p9))
 cl_int (CL_API_CALL*clEnqueueCopyBuffer)(cl_command_queue, cl_mem, cl_mem, size_t, size_t, size_t, cl_uint, const cl_event*, cl_event*) =
-        opencl_fn9<OPENCL_FN_clEnqueueCopyBuffer, cl_int, cl_command_queue, cl_mem, cl_mem, size_t, size_t, size_t, cl_uint, const cl_event*, cl_event*>::switch_fn;
+        OPENCL_FN_clEnqueueCopyBuffer_switch_fn;
 static const struct DynamicFnEntry clEnqueueCopyBuffer_definition = { "clEnqueueCopyBuffer", (void**)&clEnqueueCopyBuffer};
 
+opencl_fn13(OPENCL_FN_clEnqueueCopyBufferRect, cl_int, (cl_command_queue p1, cl_mem p2, cl_mem p3, const size_t* p4, const size_t* p5, const size_t* p6, size_t p7, size_t p8, size_t p9, size_t p10, cl_uint p11, const cl_event* p12, cl_event* p13))
 cl_int (CL_API_CALL*clEnqueueCopyBufferRect)(cl_command_queue, cl_mem, cl_mem, const size_t*, const size_t*, const size_t*, size_t, size_t, size_t, size_t, cl_uint, const cl_event*, cl_event*) =
-        opencl_fn13<OPENCL_FN_clEnqueueCopyBufferRect, cl_int, cl_command_queue, cl_mem, cl_mem, const size_t*, const size_t*, const size_t*, size_t, size_t, size_t, size_t, cl_uint, const cl_event*, cl_event*>::switch_fn;
+        OPENCL_FN_clEnqueueCopyBufferRect_switch_fn;
 static const struct DynamicFnEntry clEnqueueCopyBufferRect_definition = { "clEnqueueCopyBufferRect", (void**)&clEnqueueCopyBufferRect};
 
+opencl_fn9(OPENCL_FN_clEnqueueCopyBufferToImage, cl_int, (cl_command_queue p1, cl_mem p2, cl_mem p3, size_t p4, const size_t* p5, const size_t* p6, cl_uint p7, const cl_event* p8, cl_event* p9))
 cl_int (CL_API_CALL*clEnqueueCopyBufferToImage)(cl_command_queue, cl_mem, cl_mem, size_t, const size_t*, const size_t*, cl_uint, const cl_event*, cl_event*) =
-        opencl_fn9<OPENCL_FN_clEnqueueCopyBufferToImage, cl_int, cl_command_queue, cl_mem, cl_mem, size_t, const size_t*, const size_t*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+        OPENCL_FN_clEnqueueCopyBufferToImage_switch_fn;
 static const struct DynamicFnEntry clEnqueueCopyBufferToImage_definition = { "clEnqueueCopyBufferToImage", (void**)&clEnqueueCopyBufferToImage};
 
+opencl_fn9(OPENCL_FN_clEnqueueCopyImage, cl_int, (cl_command_queue p1, cl_mem p2, cl_mem p3, const size_t* p4, const size_t* p5, const size_t* p6, cl_uint p7, const cl_event* p8, cl_event* p9))
 cl_int (CL_API_CALL*clEnqueueCopyImage)(cl_command_queue, cl_mem, cl_mem, const size_t*, const size_t*, const size_t*, cl_uint, const cl_event*, cl_event*) =
-        opencl_fn9<OPENCL_FN_clEnqueueCopyImage, cl_int, cl_command_queue, cl_mem, cl_mem, const size_t*, const size_t*, const size_t*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+        OPENCL_FN_clEnqueueCopyImage_switch_fn;
 static const struct DynamicFnEntry clEnqueueCopyImage_definition = { "clEnqueueCopyImage", (void**)&clEnqueueCopyImage};
 
+opencl_fn9(OPENCL_FN_clEnqueueCopyImageToBuffer, cl_int, (cl_command_queue p1, cl_mem p2, cl_mem p3, const size_t* p4, const size_t* p5, size_t p6, cl_uint p7, const cl_event* p8, cl_event* p9))
 cl_int (CL_API_CALL*clEnqueueCopyImageToBuffer)(cl_command_queue, cl_mem, cl_mem, const size_t*, const size_t*, size_t, cl_uint, const cl_event*, cl_event*) =
-        opencl_fn9<OPENCL_FN_clEnqueueCopyImageToBuffer, cl_int, cl_command_queue, cl_mem, cl_mem, const size_t*, const size_t*, size_t, cl_uint, const cl_event*, cl_event*>::switch_fn;
+        OPENCL_FN_clEnqueueCopyImageToBuffer_switch_fn;
 static const struct DynamicFnEntry clEnqueueCopyImageToBuffer_definition = { "clEnqueueCopyImageToBuffer", (void**)&clEnqueueCopyImageToBuffer};
 
+opencl_fn9(OPENCL_FN_clEnqueueFillBuffer, cl_int, (cl_command_queue p1, cl_mem p2, const void* p3, size_t p4, size_t p5, size_t p6, cl_uint p7, const cl_event* p8, cl_event* p9))
 cl_int (CL_API_CALL*clEnqueueFillBuffer)(cl_command_queue, cl_mem, const void*, size_t, size_t, size_t, cl_uint, const cl_event*, cl_event*) =
-        opencl_fn9<OPENCL_FN_clEnqueueFillBuffer, cl_int, cl_command_queue, cl_mem, const void*, size_t, size_t, size_t, cl_uint, const cl_event*, cl_event*>::switch_fn;
+        OPENCL_FN_clEnqueueFillBuffer_switch_fn;
 static const struct DynamicFnEntry clEnqueueFillBuffer_definition = { "clEnqueueFillBuffer", (void**)&clEnqueueFillBuffer};
 
+opencl_fn8(OPENCL_FN_clEnqueueFillImage, cl_int, (cl_command_queue p1, cl_mem p2, const void* p3, const size_t* p4, const size_t* p5, cl_uint p6, const cl_event* p7, cl_event* p8))
 cl_int (CL_API_CALL*clEnqueueFillImage)(cl_command_queue, cl_mem, const void*, const size_t*, const size_t*, cl_uint, const cl_event*, cl_event*) =
-        opencl_fn8<OPENCL_FN_clEnqueueFillImage, cl_int, cl_command_queue, cl_mem, const void*, const size_t*, const size_t*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+        OPENCL_FN_clEnqueueFillImage_switch_fn;
 static const struct DynamicFnEntry clEnqueueFillImage_definition = { "clEnqueueFillImage", (void**)&clEnqueueFillImage};
 
+opencl_fn10(OPENCL_FN_clEnqueueMapBuffer, void*, (cl_command_queue p1, cl_mem p2, cl_bool p3, cl_map_flags p4, size_t p5, size_t p6, cl_uint p7, const cl_event* p8, cl_event* p9, cl_int* p10))
 void* (CL_API_CALL*clEnqueueMapBuffer)(cl_command_queue, cl_mem, cl_bool, cl_map_flags, size_t, size_t, cl_uint, const cl_event*, cl_event*, cl_int*) =
-        opencl_fn10<OPENCL_FN_clEnqueueMapBuffer, void*, cl_command_queue, cl_mem, cl_bool, cl_map_flags, size_t, size_t, cl_uint, const cl_event*, cl_event*, cl_int*>::switch_fn;
+        OPENCL_FN_clEnqueueMapBuffer_switch_fn;
 static const struct DynamicFnEntry clEnqueueMapBuffer_definition = { "clEnqueueMapBuffer", (void**)&clEnqueueMapBuffer};
 
+opencl_fn12(OPENCL_FN_clEnqueueMapImage, void*, (cl_command_queue p1, cl_mem p2, cl_bool p3, cl_map_flags p4, const size_t* p5, const size_t* p6, size_t* p7, size_t* p8, cl_uint p9, const cl_event* p10, cl_event* p11, cl_int* p12))
 void* (CL_API_CALL*clEnqueueMapImage)(cl_command_queue, cl_mem, cl_bool, cl_map_flags, const size_t*, const size_t*, size_t*, size_t*, cl_uint, const cl_event*, cl_event*, cl_int*) =
-        opencl_fn12<OPENCL_FN_clEnqueueMapImage, void*, cl_command_queue, cl_mem, cl_bool, cl_map_flags, const size_t*, const size_t*, size_t*, size_t*, cl_uint, const cl_event*, cl_event*, cl_int*>::switch_fn;
+        OPENCL_FN_clEnqueueMapImage_switch_fn;
 static const struct DynamicFnEntry clEnqueueMapImage_definition = { "clEnqueueMapImage", (void**)&clEnqueueMapImage};
 
+opencl_fn2(OPENCL_FN_clEnqueueMarker, cl_int, (cl_command_queue p1, cl_event* p2))
 cl_int (CL_API_CALL*clEnqueueMarker)(cl_command_queue, cl_event*) =
-        opencl_fn2<OPENCL_FN_clEnqueueMarker, cl_int, cl_command_queue, cl_event*>::switch_fn;
+        OPENCL_FN_clEnqueueMarker_switch_fn;
 static const struct DynamicFnEntry clEnqueueMarker_definition = { "clEnqueueMarker", (void**)&clEnqueueMarker};
 
+opencl_fn4(OPENCL_FN_clEnqueueMarkerWithWaitList, cl_int, (cl_command_queue p1, cl_uint p2, const cl_event* p3, cl_event* p4))
 cl_int (CL_API_CALL*clEnqueueMarkerWithWaitList)(cl_command_queue, cl_uint, const cl_event*, cl_event*) =
-        opencl_fn4<OPENCL_FN_clEnqueueMarkerWithWaitList, cl_int, cl_command_queue, cl_uint, const cl_event*, cl_event*>::switch_fn;
+        OPENCL_FN_clEnqueueMarkerWithWaitList_switch_fn;
 static const struct DynamicFnEntry clEnqueueMarkerWithWaitList_definition = { "clEnqueueMarkerWithWaitList", (void**)&clEnqueueMarkerWithWaitList};
 
+opencl_fn7(OPENCL_FN_clEnqueueMigrateMemObjects, cl_int, (cl_command_queue p1, cl_uint p2, const cl_mem* p3, cl_mem_migration_flags p4, cl_uint p5, const cl_event* p6, cl_event* p7))
 cl_int (CL_API_CALL*clEnqueueMigrateMemObjects)(cl_command_queue, cl_uint, const cl_mem*, cl_mem_migration_flags, cl_uint, const cl_event*, cl_event*) =
-        opencl_fn7<OPENCL_FN_clEnqueueMigrateMemObjects, cl_int, cl_command_queue, cl_uint, const cl_mem*, cl_mem_migration_flags, cl_uint, const cl_event*, cl_event*>::switch_fn;
+        OPENCL_FN_clEnqueueMigrateMemObjects_switch_fn;
 static const struct DynamicFnEntry clEnqueueMigrateMemObjects_definition = { "clEnqueueMigrateMemObjects", (void**)&clEnqueueMigrateMemObjects};
 
+opencl_fn9(OPENCL_FN_clEnqueueNDRangeKernel, cl_int, (cl_command_queue p1, cl_kernel p2, cl_uint p3, const size_t* p4, const size_t* p5, const size_t* p6, cl_uint p7, const cl_event* p8, cl_event* p9))
 cl_int (CL_API_CALL*clEnqueueNDRangeKernel)(cl_command_queue, cl_kernel, cl_uint, const size_t*, const size_t*, const size_t*, cl_uint, const cl_event*, cl_event*) =
-        opencl_fn9<OPENCL_FN_clEnqueueNDRangeKernel, cl_int, cl_command_queue, cl_kernel, cl_uint, const size_t*, const size_t*, const size_t*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+        OPENCL_FN_clEnqueueNDRangeKernel_switch_fn;
 static const struct DynamicFnEntry clEnqueueNDRangeKernel_definition = { "clEnqueueNDRangeKernel", (void**)&clEnqueueNDRangeKernel};
 
+opencl_fn10(OPENCL_FN_clEnqueueNativeKernel, cl_int, (cl_command_queue p1, void (CL_CALLBACK*p2) (void*), void* p3, size_t p4, cl_uint p5, const cl_mem* p6, const void** p7, cl_uint p8, const cl_event* p9, cl_event* p10))
 cl_int (CL_API_CALL*clEnqueueNativeKernel)(cl_command_queue, void (CL_CALLBACK*) (void*), void*, size_t, cl_uint, const cl_mem*, const void**, cl_uint, const cl_event*, cl_event*) =
-        opencl_fn10<OPENCL_FN_clEnqueueNativeKernel, cl_int, cl_command_queue, void (CL_CALLBACK*) (void*), void*, size_t, cl_uint, const cl_mem*, const void**, cl_uint, const cl_event*, cl_event*>::switch_fn;
+        OPENCL_FN_clEnqueueNativeKernel_switch_fn;
 static const struct DynamicFnEntry clEnqueueNativeKernel_definition = { "clEnqueueNativeKernel", (void**)&clEnqueueNativeKernel};
 
+opencl_fn9(OPENCL_FN_clEnqueueReadBuffer, cl_int, (cl_command_queue p1, cl_mem p2, cl_bool p3, size_t p4, size_t p5, void* p6, cl_uint p7, const cl_event* p8, cl_event* p9))
 cl_int (CL_API_CALL*clEnqueueReadBuffer)(cl_command_queue, cl_mem, cl_bool, size_t, size_t, void*, cl_uint, const cl_event*, cl_event*) =
-        opencl_fn9<OPENCL_FN_clEnqueueReadBuffer, cl_int, cl_command_queue, cl_mem, cl_bool, size_t, size_t, void*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+        OPENCL_FN_clEnqueueReadBuffer_switch_fn;
 static const struct DynamicFnEntry clEnqueueReadBuffer_definition = { "clEnqueueReadBuffer", (void**)&clEnqueueReadBuffer};
 
+opencl_fn14(OPENCL_FN_clEnqueueReadBufferRect, cl_int, (cl_command_queue p1, cl_mem p2, cl_bool p3, const size_t* p4, const size_t* p5, const size_t* p6, size_t p7, size_t p8, size_t p9, size_t p10, void* p11, cl_uint p12, const cl_event* p13, cl_event* p14))
 cl_int (CL_API_CALL*clEnqueueReadBufferRect)(cl_command_queue, cl_mem, cl_bool, const size_t*, const size_t*, const size_t*, size_t, size_t, size_t, size_t, void*, cl_uint, const cl_event*, cl_event*) =
-        opencl_fn14<OPENCL_FN_clEnqueueReadBufferRect, cl_int, cl_command_queue, cl_mem, cl_bool, const size_t*, const size_t*, const size_t*, size_t, size_t, size_t, size_t, void*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+        OPENCL_FN_clEnqueueReadBufferRect_switch_fn;
 static const struct DynamicFnEntry clEnqueueReadBufferRect_definition = { "clEnqueueReadBufferRect", (void**)&clEnqueueReadBufferRect};
 
+opencl_fn11(OPENCL_FN_clEnqueueReadImage, cl_int, (cl_command_queue p1, cl_mem p2, cl_bool p3, const size_t* p4, const size_t* p5, size_t p6, size_t p7, void* p8, cl_uint p9, const cl_event* p10, cl_event* p11))
 cl_int (CL_API_CALL*clEnqueueReadImage)(cl_command_queue, cl_mem, cl_bool, const size_t*, const size_t*, size_t, size_t, void*, cl_uint, const cl_event*, cl_event*) =
-        opencl_fn11<OPENCL_FN_clEnqueueReadImage, cl_int, cl_command_queue, cl_mem, cl_bool, const size_t*, const size_t*, size_t, size_t, void*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+        OPENCL_FN_clEnqueueReadImage_switch_fn;
 static const struct DynamicFnEntry clEnqueueReadImage_definition = { "clEnqueueReadImage", (void**)&clEnqueueReadImage};
 
+opencl_fn5(OPENCL_FN_clEnqueueTask, cl_int, (cl_command_queue p1, cl_kernel p2, cl_uint p3, const cl_event* p4, cl_event* p5))
 cl_int (CL_API_CALL*clEnqueueTask)(cl_command_queue, cl_kernel, cl_uint, const cl_event*, cl_event*) =
-        opencl_fn5<OPENCL_FN_clEnqueueTask, cl_int, cl_command_queue, cl_kernel, cl_uint, const cl_event*, cl_event*>::switch_fn;
+        OPENCL_FN_clEnqueueTask_switch_fn;
 static const struct DynamicFnEntry clEnqueueTask_definition = { "clEnqueueTask", (void**)&clEnqueueTask};
 
+opencl_fn6(OPENCL_FN_clEnqueueUnmapMemObject, cl_int, (cl_command_queue p1, cl_mem p2, void* p3, cl_uint p4, const cl_event* p5, cl_event* p6))
 cl_int (CL_API_CALL*clEnqueueUnmapMemObject)(cl_command_queue, cl_mem, void*, cl_uint, const cl_event*, cl_event*) =
-        opencl_fn6<OPENCL_FN_clEnqueueUnmapMemObject, cl_int, cl_command_queue, cl_mem, void*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+        OPENCL_FN_clEnqueueUnmapMemObject_switch_fn;
 static const struct DynamicFnEntry clEnqueueUnmapMemObject_definition = { "clEnqueueUnmapMemObject", (void**)&clEnqueueUnmapMemObject};
 
+opencl_fn3(OPENCL_FN_clEnqueueWaitForEvents, cl_int, (cl_command_queue p1, cl_uint p2, const cl_event* p3))
 cl_int (CL_API_CALL*clEnqueueWaitForEvents)(cl_command_queue, cl_uint, const cl_event*) =
-        opencl_fn3<OPENCL_FN_clEnqueueWaitForEvents, cl_int, cl_command_queue, cl_uint, const cl_event*>::switch_fn;
+        OPENCL_FN_clEnqueueWaitForEvents_switch_fn;
 static const struct DynamicFnEntry clEnqueueWaitForEvents_definition = { "clEnqueueWaitForEvents", (void**)&clEnqueueWaitForEvents};
 
+opencl_fn9(OPENCL_FN_clEnqueueWriteBuffer, cl_int, (cl_command_queue p1, cl_mem p2, cl_bool p3, size_t p4, size_t p5, const void* p6, cl_uint p7, const cl_event* p8, cl_event* p9))
 cl_int (CL_API_CALL*clEnqueueWriteBuffer)(cl_command_queue, cl_mem, cl_bool, size_t, size_t, const void*, cl_uint, const cl_event*, cl_event*) =
-        opencl_fn9<OPENCL_FN_clEnqueueWriteBuffer, cl_int, cl_command_queue, cl_mem, cl_bool, size_t, size_t, const void*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+        OPENCL_FN_clEnqueueWriteBuffer_switch_fn;
 static const struct DynamicFnEntry clEnqueueWriteBuffer_definition = { "clEnqueueWriteBuffer", (void**)&clEnqueueWriteBuffer};
 
+opencl_fn14(OPENCL_FN_clEnqueueWriteBufferRect, cl_int, (cl_command_queue p1, cl_mem p2, cl_bool p3, const size_t* p4, const size_t* p5, const size_t* p6, size_t p7, size_t p8, size_t p9, size_t p10, const void* p11, cl_uint p12, const cl_event* p13, cl_event* p14))
 cl_int (CL_API_CALL*clEnqueueWriteBufferRect)(cl_command_queue, cl_mem, cl_bool, const size_t*, const size_t*, const size_t*, size_t, size_t, size_t, size_t, const void*, cl_uint, const cl_event*, cl_event*) =
-        opencl_fn14<OPENCL_FN_clEnqueueWriteBufferRect, cl_int, cl_command_queue, cl_mem, cl_bool, const size_t*, const size_t*, const size_t*, size_t, size_t, size_t, size_t, const void*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+        OPENCL_FN_clEnqueueWriteBufferRect_switch_fn;
 static const struct DynamicFnEntry clEnqueueWriteBufferRect_definition = { "clEnqueueWriteBufferRect", (void**)&clEnqueueWriteBufferRect};
 
+opencl_fn11(OPENCL_FN_clEnqueueWriteImage, cl_int, (cl_command_queue p1, cl_mem p2, cl_bool p3, const size_t* p4, const size_t* p5, size_t p6, size_t p7, const void* p8, cl_uint p9, const cl_event* p10, cl_event* p11))
 cl_int (CL_API_CALL*clEnqueueWriteImage)(cl_command_queue, cl_mem, cl_bool, const size_t*, const size_t*, size_t, size_t, const void*, cl_uint, const cl_event*, cl_event*) =
-        opencl_fn11<OPENCL_FN_clEnqueueWriteImage, cl_int, cl_command_queue, cl_mem, cl_bool, const size_t*, const size_t*, size_t, size_t, const void*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+        OPENCL_FN_clEnqueueWriteImage_switch_fn;
 static const struct DynamicFnEntry clEnqueueWriteImage_definition = { "clEnqueueWriteImage", (void**)&clEnqueueWriteImage};
 
+opencl_fn1(OPENCL_FN_clFinish, cl_int, (cl_command_queue p1))
 cl_int (CL_API_CALL*clFinish)(cl_command_queue) =
-        opencl_fn1<OPENCL_FN_clFinish, cl_int, cl_command_queue>::switch_fn;
+        OPENCL_FN_clFinish_switch_fn;
 static const struct DynamicFnEntry clFinish_definition = { "clFinish", (void**)&clFinish};
 
+opencl_fn1(OPENCL_FN_clFlush, cl_int, (cl_command_queue p1))
 cl_int (CL_API_CALL*clFlush)(cl_command_queue) =
-        opencl_fn1<OPENCL_FN_clFlush, cl_int, cl_command_queue>::switch_fn;
+        OPENCL_FN_clFlush_switch_fn;
 static const struct DynamicFnEntry clFlush_definition = { "clFlush", (void**)&clFlush};
 
+opencl_fn5(OPENCL_FN_clGetCommandQueueInfo, cl_int, (cl_command_queue p1, cl_command_queue_info p2, size_t p3, void* p4, size_t* p5))
 cl_int (CL_API_CALL*clGetCommandQueueInfo)(cl_command_queue, cl_command_queue_info, size_t, void*, size_t*) =
-        opencl_fn5<OPENCL_FN_clGetCommandQueueInfo, cl_int, cl_command_queue, cl_command_queue_info, size_t, void*, size_t*>::switch_fn;
+        OPENCL_FN_clGetCommandQueueInfo_switch_fn;
 static const struct DynamicFnEntry clGetCommandQueueInfo_definition = { "clGetCommandQueueInfo", (void**)&clGetCommandQueueInfo};
 
+opencl_fn5(OPENCL_FN_clGetContextInfo, cl_int, (cl_context p1, cl_context_info p2, size_t p3, void* p4, size_t* p5))
 cl_int (CL_API_CALL*clGetContextInfo)(cl_context, cl_context_info, size_t, void*, size_t*) =
-        opencl_fn5<OPENCL_FN_clGetContextInfo, cl_int, cl_context, cl_context_info, size_t, void*, size_t*>::switch_fn;
+        OPENCL_FN_clGetContextInfo_switch_fn;
 static const struct DynamicFnEntry clGetContextInfo_definition = { "clGetContextInfo", (void**)&clGetContextInfo};
 
+opencl_fn5(OPENCL_FN_clGetDeviceIDs, cl_int, (cl_platform_id p1, cl_device_type p2, cl_uint p3, cl_device_id* p4, cl_uint* p5))
 cl_int (CL_API_CALL*clGetDeviceIDs)(cl_platform_id, cl_device_type, cl_uint, cl_device_id*, cl_uint*) =
-        opencl_fn5<OPENCL_FN_clGetDeviceIDs, cl_int, cl_platform_id, cl_device_type, cl_uint, cl_device_id*, cl_uint*>::switch_fn;
+        OPENCL_FN_clGetDeviceIDs_switch_fn;
 static const struct DynamicFnEntry clGetDeviceIDs_definition = { "clGetDeviceIDs", (void**)&clGetDeviceIDs};
 
+opencl_fn5(OPENCL_FN_clGetDeviceInfo, cl_int, (cl_device_id p1, cl_device_info p2, size_t p3, void* p4, size_t* p5))
 cl_int (CL_API_CALL*clGetDeviceInfo)(cl_device_id, cl_device_info, size_t, void*, size_t*) =
-        opencl_fn5<OPENCL_FN_clGetDeviceInfo, cl_int, cl_device_id, cl_device_info, size_t, void*, size_t*>::switch_fn;
+        OPENCL_FN_clGetDeviceInfo_switch_fn;
 static const struct DynamicFnEntry clGetDeviceInfo_definition = { "clGetDeviceInfo", (void**)&clGetDeviceInfo};
 
+opencl_fn5(OPENCL_FN_clGetEventInfo, cl_int, (cl_event p1, cl_event_info p2, size_t p3, void* p4, size_t* p5))
 cl_int (CL_API_CALL*clGetEventInfo)(cl_event, cl_event_info, size_t, void*, size_t*) =
-        opencl_fn5<OPENCL_FN_clGetEventInfo, cl_int, cl_event, cl_event_info, size_t, void*, size_t*>::switch_fn;
+        OPENCL_FN_clGetEventInfo_switch_fn;
 static const struct DynamicFnEntry clGetEventInfo_definition = { "clGetEventInfo", (void**)&clGetEventInfo};
 
+opencl_fn5(OPENCL_FN_clGetEventProfilingInfo, cl_int, (cl_event p1, cl_profiling_info p2, size_t p3, void* p4, size_t* p5))
 cl_int (CL_API_CALL*clGetEventProfilingInfo)(cl_event, cl_profiling_info, size_t, void*, size_t*) =
-        opencl_fn5<OPENCL_FN_clGetEventProfilingInfo, cl_int, cl_event, cl_profiling_info, size_t, void*, size_t*>::switch_fn;
+        OPENCL_FN_clGetEventProfilingInfo_switch_fn;
 static const struct DynamicFnEntry clGetEventProfilingInfo_definition = { "clGetEventProfilingInfo", (void**)&clGetEventProfilingInfo};
 
+opencl_fn1(OPENCL_FN_clGetExtensionFunctionAddress, void*, (const char* p1))
 void* (CL_API_CALL*clGetExtensionFunctionAddress)(const char*) =
-        opencl_fn1<OPENCL_FN_clGetExtensionFunctionAddress, void*, const char*>::switch_fn;
+        OPENCL_FN_clGetExtensionFunctionAddress_switch_fn;
 static const struct DynamicFnEntry clGetExtensionFunctionAddress_definition = { "clGetExtensionFunctionAddress", (void**)&clGetExtensionFunctionAddress};
 
+opencl_fn2(OPENCL_FN_clGetExtensionFunctionAddressForPlatform, void*, (cl_platform_id p1, const char* p2))
 void* (CL_API_CALL*clGetExtensionFunctionAddressForPlatform)(cl_platform_id, const char*) =
-        opencl_fn2<OPENCL_FN_clGetExtensionFunctionAddressForPlatform, void*, cl_platform_id, const char*>::switch_fn;
+        OPENCL_FN_clGetExtensionFunctionAddressForPlatform_switch_fn;
 static const struct DynamicFnEntry clGetExtensionFunctionAddressForPlatform_definition = { "clGetExtensionFunctionAddressForPlatform", (void**)&clGetExtensionFunctionAddressForPlatform};
 
+opencl_fn5(OPENCL_FN_clGetImageInfo, cl_int, (cl_mem p1, cl_image_info p2, size_t p3, void* p4, size_t* p5))
 cl_int (CL_API_CALL*clGetImageInfo)(cl_mem, cl_image_info, size_t, void*, size_t*) =
-        opencl_fn5<OPENCL_FN_clGetImageInfo, cl_int, cl_mem, cl_image_info, size_t, void*, size_t*>::switch_fn;
+        OPENCL_FN_clGetImageInfo_switch_fn;
 static const struct DynamicFnEntry clGetImageInfo_definition = { "clGetImageInfo", (void**)&clGetImageInfo};
 
+opencl_fn6(OPENCL_FN_clGetKernelArgInfo, cl_int, (cl_kernel p1, cl_uint p2, cl_kernel_arg_info p3, size_t p4, void* p5, size_t* p6))
 cl_int (CL_API_CALL*clGetKernelArgInfo)(cl_kernel, cl_uint, cl_kernel_arg_info, size_t, void*, size_t*) =
-        opencl_fn6<OPENCL_FN_clGetKernelArgInfo, cl_int, cl_kernel, cl_uint, cl_kernel_arg_info, size_t, void*, size_t*>::switch_fn;
+        OPENCL_FN_clGetKernelArgInfo_switch_fn;
 static const struct DynamicFnEntry clGetKernelArgInfo_definition = { "clGetKernelArgInfo", (void**)&clGetKernelArgInfo};
 
+opencl_fn5(OPENCL_FN_clGetKernelInfo, cl_int, (cl_kernel p1, cl_kernel_info p2, size_t p3, void* p4, size_t* p5))
 cl_int (CL_API_CALL*clGetKernelInfo)(cl_kernel, cl_kernel_info, size_t, void*, size_t*) =
-        opencl_fn5<OPENCL_FN_clGetKernelInfo, cl_int, cl_kernel, cl_kernel_info, size_t, void*, size_t*>::switch_fn;
+        OPENCL_FN_clGetKernelInfo_switch_fn;
 static const struct DynamicFnEntry clGetKernelInfo_definition = { "clGetKernelInfo", (void**)&clGetKernelInfo};
 
+opencl_fn6(OPENCL_FN_clGetKernelWorkGroupInfo, cl_int, (cl_kernel p1, cl_device_id p2, cl_kernel_work_group_info p3, size_t p4, void* p5, size_t* p6))
 cl_int (CL_API_CALL*clGetKernelWorkGroupInfo)(cl_kernel, cl_device_id, cl_kernel_work_group_info, size_t, void*, size_t*) =
-        opencl_fn6<OPENCL_FN_clGetKernelWorkGroupInfo, cl_int, cl_kernel, cl_device_id, cl_kernel_work_group_info, size_t, void*, size_t*>::switch_fn;
+        OPENCL_FN_clGetKernelWorkGroupInfo_switch_fn;
 static const struct DynamicFnEntry clGetKernelWorkGroupInfo_definition = { "clGetKernelWorkGroupInfo", (void**)&clGetKernelWorkGroupInfo};
 
+opencl_fn5(OPENCL_FN_clGetMemObjectInfo, cl_int, (cl_mem p1, cl_mem_info p2, size_t p3, void* p4, size_t* p5))
 cl_int (CL_API_CALL*clGetMemObjectInfo)(cl_mem, cl_mem_info, size_t, void*, size_t*) =
-        opencl_fn5<OPENCL_FN_clGetMemObjectInfo, cl_int, cl_mem, cl_mem_info, size_t, void*, size_t*>::switch_fn;
+        OPENCL_FN_clGetMemObjectInfo_switch_fn;
 static const struct DynamicFnEntry clGetMemObjectInfo_definition = { "clGetMemObjectInfo", (void**)&clGetMemObjectInfo};
 
+opencl_fn3(OPENCL_FN_clGetPlatformIDs, cl_int, (cl_uint p1, cl_platform_id* p2, cl_uint* p3))
 cl_int (CL_API_CALL*clGetPlatformIDs)(cl_uint, cl_platform_id*, cl_uint*) =
-        opencl_fn3<OPENCL_FN_clGetPlatformIDs, cl_int, cl_uint, cl_platform_id*, cl_uint*>::switch_fn;
+        OPENCL_FN_clGetPlatformIDs_switch_fn;
 static const struct DynamicFnEntry clGetPlatformIDs_definition = { "clGetPlatformIDs", (void**)&clGetPlatformIDs};
 
+opencl_fn5(OPENCL_FN_clGetPlatformInfo, cl_int, (cl_platform_id p1, cl_platform_info p2, size_t p3, void* p4, size_t* p5))
 cl_int (CL_API_CALL*clGetPlatformInfo)(cl_platform_id, cl_platform_info, size_t, void*, size_t*) =
-        opencl_fn5<OPENCL_FN_clGetPlatformInfo, cl_int, cl_platform_id, cl_platform_info, size_t, void*, size_t*>::switch_fn;
+        OPENCL_FN_clGetPlatformInfo_switch_fn;
 static const struct DynamicFnEntry clGetPlatformInfo_definition = { "clGetPlatformInfo", (void**)&clGetPlatformInfo};
 
+opencl_fn6(OPENCL_FN_clGetProgramBuildInfo, cl_int, (cl_program p1, cl_device_id p2, cl_program_build_info p3, size_t p4, void* p5, size_t* p6))
 cl_int (CL_API_CALL*clGetProgramBuildInfo)(cl_program, cl_device_id, cl_program_build_info, size_t, void*, size_t*) =
-        opencl_fn6<OPENCL_FN_clGetProgramBuildInfo, cl_int, cl_program, cl_device_id, cl_program_build_info, size_t, void*, size_t*>::switch_fn;
+        OPENCL_FN_clGetProgramBuildInfo_switch_fn;
 static const struct DynamicFnEntry clGetProgramBuildInfo_definition = { "clGetProgramBuildInfo", (void**)&clGetProgramBuildInfo};
 
+opencl_fn5(OPENCL_FN_clGetProgramInfo, cl_int, (cl_program p1, cl_program_info p2, size_t p3, void* p4, size_t* p5))
 cl_int (CL_API_CALL*clGetProgramInfo)(cl_program, cl_program_info, size_t, void*, size_t*) =
-        opencl_fn5<OPENCL_FN_clGetProgramInfo, cl_int, cl_program, cl_program_info, size_t, void*, size_t*>::switch_fn;
+        OPENCL_FN_clGetProgramInfo_switch_fn;
 static const struct DynamicFnEntry clGetProgramInfo_definition = { "clGetProgramInfo", (void**)&clGetProgramInfo};
 
+opencl_fn5(OPENCL_FN_clGetSamplerInfo, cl_int, (cl_sampler p1, cl_sampler_info p2, size_t p3, void* p4, size_t* p5))
 cl_int (CL_API_CALL*clGetSamplerInfo)(cl_sampler, cl_sampler_info, size_t, void*, size_t*) =
-        opencl_fn5<OPENCL_FN_clGetSamplerInfo, cl_int, cl_sampler, cl_sampler_info, size_t, void*, size_t*>::switch_fn;
+        OPENCL_FN_clGetSamplerInfo_switch_fn;
 static const struct DynamicFnEntry clGetSamplerInfo_definition = { "clGetSamplerInfo", (void**)&clGetSamplerInfo};
 
+opencl_fn6(OPENCL_FN_clGetSupportedImageFormats, cl_int, (cl_context p1, cl_mem_flags p2, cl_mem_object_type p3, cl_uint p4, cl_image_format* p5, cl_uint* p6))
 cl_int (CL_API_CALL*clGetSupportedImageFormats)(cl_context, cl_mem_flags, cl_mem_object_type, cl_uint, cl_image_format*, cl_uint*) =
-        opencl_fn6<OPENCL_FN_clGetSupportedImageFormats, cl_int, cl_context, cl_mem_flags, cl_mem_object_type, cl_uint, cl_image_format*, cl_uint*>::switch_fn;
+        OPENCL_FN_clGetSupportedImageFormats_switch_fn;
 static const struct DynamicFnEntry clGetSupportedImageFormats_definition = { "clGetSupportedImageFormats", (void**)&clGetSupportedImageFormats};
 
+opencl_fn9(OPENCL_FN_clLinkProgram, cl_program, (cl_context p1, cl_uint p2, const cl_device_id* p3, const char* p4, cl_uint p5, const cl_program* p6, void (CL_CALLBACK*p7) (cl_program, void*), void* p8, cl_int* p9))
 cl_program (CL_API_CALL*clLinkProgram)(cl_context, cl_uint, const cl_device_id*, const char*, cl_uint, const cl_program*, void (CL_CALLBACK*) (cl_program, void*), void*, cl_int*) =
-        opencl_fn9<OPENCL_FN_clLinkProgram, cl_program, cl_context, cl_uint, const cl_device_id*, const char*, cl_uint, const cl_program*, void (CL_CALLBACK*) (cl_program, void*), void*, cl_int*>::switch_fn;
+        OPENCL_FN_clLinkProgram_switch_fn;
 static const struct DynamicFnEntry clLinkProgram_definition = { "clLinkProgram", (void**)&clLinkProgram};
 
+opencl_fn1(OPENCL_FN_clReleaseCommandQueue, cl_int, (cl_command_queue p1))
 cl_int (CL_API_CALL*clReleaseCommandQueue)(cl_command_queue) =
-        opencl_fn1<OPENCL_FN_clReleaseCommandQueue, cl_int, cl_command_queue>::switch_fn;
+        OPENCL_FN_clReleaseCommandQueue_switch_fn;
 static const struct DynamicFnEntry clReleaseCommandQueue_definition = { "clReleaseCommandQueue", (void**)&clReleaseCommandQueue};
 
+opencl_fn1(OPENCL_FN_clReleaseContext, cl_int, (cl_context p1))
 cl_int (CL_API_CALL*clReleaseContext)(cl_context) =
-        opencl_fn1<OPENCL_FN_clReleaseContext, cl_int, cl_context>::switch_fn;
+        OPENCL_FN_clReleaseContext_switch_fn;
 static const struct DynamicFnEntry clReleaseContext_definition = { "clReleaseContext", (void**)&clReleaseContext};
 
+opencl_fn1(OPENCL_FN_clReleaseDevice, cl_int, (cl_device_id p1))
 cl_int (CL_API_CALL*clReleaseDevice)(cl_device_id) =
-        opencl_fn1<OPENCL_FN_clReleaseDevice, cl_int, cl_device_id>::switch_fn;
+        OPENCL_FN_clReleaseDevice_switch_fn;
 static const struct DynamicFnEntry clReleaseDevice_definition = { "clReleaseDevice", (void**)&clReleaseDevice};
 
+opencl_fn1(OPENCL_FN_clReleaseEvent, cl_int, (cl_event p1))
 cl_int (CL_API_CALL*clReleaseEvent)(cl_event) =
-        opencl_fn1<OPENCL_FN_clReleaseEvent, cl_int, cl_event>::switch_fn;
+        OPENCL_FN_clReleaseEvent_switch_fn;
 static const struct DynamicFnEntry clReleaseEvent_definition = { "clReleaseEvent", (void**)&clReleaseEvent};
 
+opencl_fn1(OPENCL_FN_clReleaseKernel, cl_int, (cl_kernel p1))
 cl_int (CL_API_CALL*clReleaseKernel)(cl_kernel) =
-        opencl_fn1<OPENCL_FN_clReleaseKernel, cl_int, cl_kernel>::switch_fn;
+        OPENCL_FN_clReleaseKernel_switch_fn;
 static const struct DynamicFnEntry clReleaseKernel_definition = { "clReleaseKernel", (void**)&clReleaseKernel};
 
+opencl_fn1(OPENCL_FN_clReleaseMemObject, cl_int, (cl_mem p1))
 cl_int (CL_API_CALL*clReleaseMemObject)(cl_mem) =
-        opencl_fn1<OPENCL_FN_clReleaseMemObject, cl_int, cl_mem>::switch_fn;
+        OPENCL_FN_clReleaseMemObject_switch_fn;
 static const struct DynamicFnEntry clReleaseMemObject_definition = { "clReleaseMemObject", (void**)&clReleaseMemObject};
 
+opencl_fn1(OPENCL_FN_clReleaseProgram, cl_int, (cl_program p1))
 cl_int (CL_API_CALL*clReleaseProgram)(cl_program) =
-        opencl_fn1<OPENCL_FN_clReleaseProgram, cl_int, cl_program>::switch_fn;
+        OPENCL_FN_clReleaseProgram_switch_fn;
 static const struct DynamicFnEntry clReleaseProgram_definition = { "clReleaseProgram", (void**)&clReleaseProgram};
 
+opencl_fn1(OPENCL_FN_clReleaseSampler, cl_int, (cl_sampler p1))
 cl_int (CL_API_CALL*clReleaseSampler)(cl_sampler) =
-        opencl_fn1<OPENCL_FN_clReleaseSampler, cl_int, cl_sampler>::switch_fn;
+        OPENCL_FN_clReleaseSampler_switch_fn;
 static const struct DynamicFnEntry clReleaseSampler_definition = { "clReleaseSampler", (void**)&clReleaseSampler};
 
+opencl_fn1(OPENCL_FN_clRetainCommandQueue, cl_int, (cl_command_queue p1))
 cl_int (CL_API_CALL*clRetainCommandQueue)(cl_command_queue) =
-        opencl_fn1<OPENCL_FN_clRetainCommandQueue, cl_int, cl_command_queue>::switch_fn;
+        OPENCL_FN_clRetainCommandQueue_switch_fn;
 static const struct DynamicFnEntry clRetainCommandQueue_definition = { "clRetainCommandQueue", (void**)&clRetainCommandQueue};
 
+opencl_fn1(OPENCL_FN_clRetainContext, cl_int, (cl_context p1))
 cl_int (CL_API_CALL*clRetainContext)(cl_context) =
-        opencl_fn1<OPENCL_FN_clRetainContext, cl_int, cl_context>::switch_fn;
+        OPENCL_FN_clRetainContext_switch_fn;
 static const struct DynamicFnEntry clRetainContext_definition = { "clRetainContext", (void**)&clRetainContext};
 
+opencl_fn1(OPENCL_FN_clRetainDevice, cl_int, (cl_device_id p1))
 cl_int (CL_API_CALL*clRetainDevice)(cl_device_id) =
-        opencl_fn1<OPENCL_FN_clRetainDevice, cl_int, cl_device_id>::switch_fn;
+        OPENCL_FN_clRetainDevice_switch_fn;
 static const struct DynamicFnEntry clRetainDevice_definition = { "clRetainDevice", (void**)&clRetainDevice};
 
+opencl_fn1(OPENCL_FN_clRetainEvent, cl_int, (cl_event p1))
 cl_int (CL_API_CALL*clRetainEvent)(cl_event) =
-        opencl_fn1<OPENCL_FN_clRetainEvent, cl_int, cl_event>::switch_fn;
+        OPENCL_FN_clRetainEvent_switch_fn;
 static const struct DynamicFnEntry clRetainEvent_definition = { "clRetainEvent", (void**)&clRetainEvent};
 
+opencl_fn1(OPENCL_FN_clRetainKernel, cl_int, (cl_kernel p1))
 cl_int (CL_API_CALL*clRetainKernel)(cl_kernel) =
-        opencl_fn1<OPENCL_FN_clRetainKernel, cl_int, cl_kernel>::switch_fn;
+        OPENCL_FN_clRetainKernel_switch_fn;
 static const struct DynamicFnEntry clRetainKernel_definition = { "clRetainKernel", (void**)&clRetainKernel};
 
+opencl_fn1(OPENCL_FN_clRetainMemObject, cl_int, (cl_mem p1))
 cl_int (CL_API_CALL*clRetainMemObject)(cl_mem) =
-        opencl_fn1<OPENCL_FN_clRetainMemObject, cl_int, cl_mem>::switch_fn;
+        OPENCL_FN_clRetainMemObject_switch_fn;
 static const struct DynamicFnEntry clRetainMemObject_definition = { "clRetainMemObject", (void**)&clRetainMemObject};
 
+opencl_fn1(OPENCL_FN_clRetainProgram, cl_int, (cl_program p1))
 cl_int (CL_API_CALL*clRetainProgram)(cl_program) =
-        opencl_fn1<OPENCL_FN_clRetainProgram, cl_int, cl_program>::switch_fn;
+        OPENCL_FN_clRetainProgram_switch_fn;
 static const struct DynamicFnEntry clRetainProgram_definition = { "clRetainProgram", (void**)&clRetainProgram};
 
+opencl_fn1(OPENCL_FN_clRetainSampler, cl_int, (cl_sampler p1))
 cl_int (CL_API_CALL*clRetainSampler)(cl_sampler) =
-        opencl_fn1<OPENCL_FN_clRetainSampler, cl_int, cl_sampler>::switch_fn;
+        OPENCL_FN_clRetainSampler_switch_fn;
 static const struct DynamicFnEntry clRetainSampler_definition = { "clRetainSampler", (void**)&clRetainSampler};
 
+opencl_fn4(OPENCL_FN_clSetEventCallback, cl_int, (cl_event p1, cl_int p2, void (CL_CALLBACK*p3) (cl_event, cl_int, void*), void* p4))
 cl_int (CL_API_CALL*clSetEventCallback)(cl_event, cl_int, void (CL_CALLBACK*) (cl_event, cl_int, void*), void*) =
-        opencl_fn4<OPENCL_FN_clSetEventCallback, cl_int, cl_event, cl_int, void (CL_CALLBACK*) (cl_event, cl_int, void*), void*>::switch_fn;
+        OPENCL_FN_clSetEventCallback_switch_fn;
 static const struct DynamicFnEntry clSetEventCallback_definition = { "clSetEventCallback", (void**)&clSetEventCallback};
 
+opencl_fn4(OPENCL_FN_clSetKernelArg, cl_int, (cl_kernel p1, cl_uint p2, size_t p3, const void* p4))
 cl_int (CL_API_CALL*clSetKernelArg)(cl_kernel, cl_uint, size_t, const void*) =
-        opencl_fn4<OPENCL_FN_clSetKernelArg, cl_int, cl_kernel, cl_uint, size_t, const void*>::switch_fn;
+        OPENCL_FN_clSetKernelArg_switch_fn;
 static const struct DynamicFnEntry clSetKernelArg_definition = { "clSetKernelArg", (void**)&clSetKernelArg};
 
+opencl_fn3(OPENCL_FN_clSetMemObjectDestructorCallback, cl_int, (cl_mem p1, void (CL_CALLBACK*p2) (cl_mem, void*), void* p3))
 cl_int (CL_API_CALL*clSetMemObjectDestructorCallback)(cl_mem, void (CL_CALLBACK*) (cl_mem, void*), void*) =
-        opencl_fn3<OPENCL_FN_clSetMemObjectDestructorCallback, cl_int, cl_mem, void (CL_CALLBACK*) (cl_mem, void*), void*>::switch_fn;
+        OPENCL_FN_clSetMemObjectDestructorCallback_switch_fn;
 static const struct DynamicFnEntry clSetMemObjectDestructorCallback_definition = { "clSetMemObjectDestructorCallback", (void**)&clSetMemObjectDestructorCallback};
 
+opencl_fn2(OPENCL_FN_clSetUserEventStatus, cl_int, (cl_event p1, cl_int p2))
 cl_int (CL_API_CALL*clSetUserEventStatus)(cl_event, cl_int) =
-        opencl_fn2<OPENCL_FN_clSetUserEventStatus, cl_int, cl_event, cl_int>::switch_fn;
+        OPENCL_FN_clSetUserEventStatus_switch_fn;
 static const struct DynamicFnEntry clSetUserEventStatus_definition = { "clSetUserEventStatus", (void**)&clSetUserEventStatus};
 
+opencl_fn0(OPENCL_FN_clUnloadCompiler, cl_int, ())
 cl_int (CL_API_CALL*clUnloadCompiler)() =
-        opencl_fn0<OPENCL_FN_clUnloadCompiler, cl_int>::switch_fn;
+        OPENCL_FN_clUnloadCompiler_switch_fn;
 static const struct DynamicFnEntry clUnloadCompiler_definition = { "clUnloadCompiler", (void**)&clUnloadCompiler};
 
+opencl_fn1(OPENCL_FN_clUnloadPlatformCompiler, cl_int, (cl_platform_id p1))
 cl_int (CL_API_CALL*clUnloadPlatformCompiler)(cl_platform_id) =
-        opencl_fn1<OPENCL_FN_clUnloadPlatformCompiler, cl_int, cl_platform_id>::switch_fn;
+        OPENCL_FN_clUnloadPlatformCompiler_switch_fn;
 static const struct DynamicFnEntry clUnloadPlatformCompiler_definition = { "clUnloadPlatformCompiler", (void**)&clUnloadPlatformCompiler};
 
+opencl_fn2(OPENCL_FN_clWaitForEvents, cl_int, (cl_uint p1, const cl_event* p2))
 cl_int (CL_API_CALL*clWaitForEvents)(cl_uint, const cl_event*) =
-        opencl_fn2<OPENCL_FN_clWaitForEvents, cl_int, cl_uint, const cl_event*>::switch_fn;
+        OPENCL_FN_clWaitForEvents_switch_fn;
 static const struct DynamicFnEntry clWaitForEvents_definition = { "clWaitForEvents", (void**)&clWaitForEvents};
 
 
diff --git a/modules/core/src/opencl/runtime/autogenerated/opencl_gl_impl.hpp b/modules/core/src/opencl/runtime/autogenerated/opencl_gl_impl.hpp
index 6d97180..506f5b8 100644
--- a/modules/core/src/opencl/runtime/autogenerated/opencl_gl_impl.hpp
+++ b/modules/core/src/opencl/runtime/autogenerated/opencl_gl_impl.hpp
@@ -17,167 +17,134 @@ enum OPENCL_GL_FN_ID {
 
 namespace {
 // generated by parser_cl.py
-template <int ID, typename _R>
-struct opencl_gl_fn0
-{
-    typedef _R (CL_API_CALL*FN)();
-    static _R CL_API_CALL switch_fn()
-    { return ((FN)opencl_gl_check_fn(ID))(); }
-};
-
-template <int ID, typename _R, typename _T1>
-struct opencl_gl_fn1
-{
-    typedef _R (CL_API_CALL*FN)(_T1);
-    static _R CL_API_CALL switch_fn(_T1 p1)
-    { return ((FN)opencl_gl_check_fn(ID))(p1); }
-};
-
-template <int ID, typename _R, typename _T1, typename _T2>
-struct opencl_gl_fn2
-{
-    typedef _R (CL_API_CALL*FN)(_T1, _T2);
-    static _R CL_API_CALL switch_fn(_T1 p1, _T2 p2)
-    { return ((FN)opencl_gl_check_fn(ID))(p1, p2); }
-};
-
-template <int ID, typename _R, typename _T1, typename _T2, typename _T3>
-struct opencl_gl_fn3
-{
-    typedef _R (CL_API_CALL*FN)(_T1, _T2, _T3);
-    static _R CL_API_CALL switch_fn(_T1 p1, _T2 p2, _T3 p3)
-    { return ((FN)opencl_gl_check_fn(ID))(p1, p2, p3); }
-};
-
-template <int ID, typename _R, typename _T1, typename _T2, typename _T3, typename _T4>
-struct opencl_gl_fn4
-{
-    typedef _R (CL_API_CALL*FN)(_T1, _T2, _T3, _T4);
-    static _R CL_API_CALL switch_fn(_T1 p1, _T2 p2, _T3 p3, _T4 p4)
-    { return ((FN)opencl_gl_check_fn(ID))(p1, p2, p3, p4); }
-};
-
-template <int ID, typename _R, typename _T1, typename _T2, typename _T3, typename _T4, typename _T5>
-struct opencl_gl_fn5
-{
-    typedef _R (CL_API_CALL*FN)(_T1, _T2, _T3, _T4, _T5);
-    static _R CL_API_CALL switch_fn(_T1 p1, _T2 p2, _T3 p3, _T4 p4, _T5 p5)
-    { return ((FN)opencl_gl_check_fn(ID))(p1, p2, p3, p4, p5); }
-};
-
-template <int ID, typename _R, typename _T1, typename _T2, typename _T3, typename _T4, typename _T5, typename _T6>
-struct opencl_gl_fn6
-{
-    typedef _R (CL_API_CALL*FN)(_T1, _T2, _T3, _T4, _T5, _T6);
-    static _R CL_API_CALL switch_fn(_T1 p1, _T2 p2, _T3 p3, _T4 p4, _T5 p5, _T6 p6)
-    { return ((FN)opencl_gl_check_fn(ID))(p1, p2, p3, p4, p5, p6); }
-};
-
-template <int ID, typename _R, typename _T1, typename _T2, typename _T3, typename _T4, typename _T5, typename _T6, typename _T7>
-struct opencl_gl_fn7
-{
-    typedef _R (CL_API_CALL*FN)(_T1, _T2, _T3, _T4, _T5, _T6, _T7);
-    static _R CL_API_CALL switch_fn(_T1 p1, _T2 p2, _T3 p3, _T4 p4, _T5 p5, _T6 p6, _T7 p7)
-    { return ((FN)opencl_gl_check_fn(ID))(p1, p2, p3, p4, p5, p6, p7); }
-};
-
-template <int ID, typename _R, typename _T1, typename _T2, typename _T3, typename _T4, typename _T5, typename _T6, typename _T7, typename _T8>
-struct opencl_gl_fn8
-{
-    typedef _R (CL_API_CALL*FN)(_T1, _T2, _T3, _T4, _T5, _T6, _T7, _T8);
-    static _R CL_API_CALL switch_fn(_T1 p1, _T2 p2, _T3 p3, _T4 p4, _T5 p5, _T6 p6, _T7 p7, _T8 p8)
-    { return ((FN)opencl_gl_check_fn(ID))(p1, p2, p3, p4, p5, p6, p7, p8); }
-};
-
-template <int ID, typename _R, typename _T1, typename _T2, typename _T3, typename _T4, typename _T5, typename _T6, typename _T7, typename _T8, typename _T9>
-struct opencl_gl_fn9
-{
-    typedef _R (CL_API_CALL*FN)(_T1, _T2, _T3, _T4, _T5, _T6, _T7, _T8, _T9);
-    static _R CL_API_CALL switch_fn(_T1 p1, _T2 p2, _T3 p3, _T4 p4, _T5 p5, _T6 p6, _T7 p7, _T8 p8, _T9 p9)
-    { return ((FN)opencl_gl_check_fn(ID))(p1, p2, p3, p4, p5, p6, p7, p8, p9); }
-};
-
-template <int ID, typename _R, typename _T1, typename _T2, typename _T3, typename _T4, typename _T5, typename _T6, typename _T7, typename _T8, typename _T9, typename _T10>
-struct opencl_gl_fn10
-{
-    typedef _R (CL_API_CALL*FN)(_T1, _T2, _T3, _T4, _T5, _T6, _T7, _T8, _T9, _T10);
-    static _R CL_API_CALL switch_fn(_T1 p1, _T2 p2, _T3 p3, _T4 p4, _T5 p5, _T6 p6, _T7 p7, _T8 p8, _T9 p9, _T10 p10)
-    { return ((FN)opencl_gl_check_fn(ID))(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10); }
-};
-
-template <int ID, typename _R, typename _T1, typename _T2, typename _T3, typename _T4, typename _T5, typename _T6, typename _T7, typename _T8, typename _T9, typename _T10, typename _T11>
-struct opencl_gl_fn11
-{
-    typedef _R (CL_API_CALL*FN)(_T1, _T2, _T3, _T4, _T5, _T6, _T7, _T8, _T9, _T10, _T11);
-    static _R CL_API_CALL switch_fn(_T1 p1, _T2 p2, _T3 p3, _T4 p4, _T5 p5, _T6 p6, _T7 p7, _T8 p8, _T9 p9, _T10 p10, _T11 p11)
-    { return ((FN)opencl_gl_check_fn(ID))(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11); }
-};
-
-template <int ID, typename _R, typename _T1, typename _T2, typename _T3, typename _T4, typename _T5, typename _T6, typename _T7, typename _T8, typename _T9, typename _T10, typename _T11, typename _T12>
-struct opencl_gl_fn12
-{
-    typedef _R (CL_API_CALL*FN)(_T1, _T2, _T3, _T4, _T5, _T6, _T7, _T8, _T9, _T10, _T11, _T12);
-    static _R CL_API_CALL switch_fn(_T1 p1, _T2 p2, _T3 p3, _T4 p4, _T5 p5, _T6 p6, _T7 p7, _T8 p8, _T9 p9, _T10 p10, _T11 p11, _T12 p12)
-    { return ((FN)opencl_gl_check_fn(ID))(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12); }
-};
-
-template <int ID, typename _R, typename _T1, typename _T2, typename _T3, typename _T4, typename _T5, typename _T6, typename _T7, typename _T8, typename _T9, typename _T10, typename _T11, typename _T12, typename _T13>
-struct opencl_gl_fn13
-{
-    typedef _R (CL_API_CALL*FN)(_T1, _T2, _T3, _T4, _T5, _T6, _T7, _T8, _T9, _T10, _T11, _T12, _T13);
-    static _R CL_API_CALL switch_fn(_T1 p1, _T2 p2, _T3 p3, _T4 p4, _T5 p5, _T6 p6, _T7 p7, _T8 p8, _T9 p9, _T10 p10, _T11 p11, _T12 p12, _T13 p13)
-    { return ((FN)opencl_gl_check_fn(ID))(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13); }
-};
-
-template <int ID, typename _R, typename _T1, typename _T2, typename _T3, typename _T4, typename _T5, typename _T6, typename _T7, typename _T8, typename _T9, typename _T10, typename _T11, typename _T12, typename _T13, typename _T14>
-struct opencl_gl_fn14
-{
-    typedef _R (CL_API_CALL*FN)(_T1, _T2, _T3, _T4, _T5, _T6, _T7, _T8, _T9, _T10, _T11, _T12, _T13, _T14);
-    static _R CL_API_CALL switch_fn(_T1 p1, _T2 p2, _T3 p3, _T4 p4, _T5 p5, _T6 p6, _T7 p7, _T8 p8, _T9 p9, _T10 p10, _T11 p11, _T12 p12, _T13 p13, _T14 p14)
-    { return ((FN)opencl_gl_check_fn(ID))(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14); }
-};
+#define opencl_gl_fn0(ID, _R, decl_args) \
+    typedef _R (CL_API_CALL*ID##FN)decl_args; \
+    static _R CL_API_CALL ID##_switch_fn decl_args \
+    { return ((ID##FN)opencl_gl_check_fn(ID))(); } \
+
+#define opencl_gl_fn1(ID, _R, decl_args) \
+    typedef _R (CL_API_CALL*ID##FN)decl_args; \
+    static _R CL_API_CALL ID##_switch_fn decl_args \
+    { return ((ID##FN)opencl_gl_check_fn(ID))(p1); } \
+
+#define opencl_gl_fn2(ID, _R, decl_args) \
+    typedef _R (CL_API_CALL*ID##FN)decl_args; \
+    static _R CL_API_CALL ID##_switch_fn decl_args \
+    { return ((ID##FN)opencl_gl_check_fn(ID))(p1, p2); } \
+
+#define opencl_gl_fn3(ID, _R, decl_args) \
+    typedef _R (CL_API_CALL*ID##FN)decl_args; \
+    static _R CL_API_CALL ID##_switch_fn decl_args \
+    { return ((ID##FN)opencl_gl_check_fn(ID))(p1, p2, p3); } \
+
+#define opencl_gl_fn4(ID, _R, decl_args) \
+    typedef _R (CL_API_CALL*ID##FN)decl_args; \
+    static _R CL_API_CALL ID##_switch_fn decl_args \
+    { return ((ID##FN)opencl_gl_check_fn(ID))(p1, p2, p3, p4); } \
+
+#define opencl_gl_fn5(ID, _R, decl_args) \
+    typedef _R (CL_API_CALL*ID##FN)decl_args; \
+    static _R CL_API_CALL ID##_switch_fn decl_args \
+    { return ((ID##FN)opencl_gl_check_fn(ID))(p1, p2, p3, p4, p5); } \
+
+#define opencl_gl_fn6(ID, _R, decl_args) \
+    typedef _R (CL_API_CALL*ID##FN)decl_args; \
+    static _R CL_API_CALL ID##_switch_fn decl_args \
+    { return ((ID##FN)opencl_gl_check_fn(ID))(p1, p2, p3, p4, p5, p6); } \
+
+#define opencl_gl_fn7(ID, _R, decl_args) \
+    typedef _R (CL_API_CALL*ID##FN)decl_args; \
+    static _R CL_API_CALL ID##_switch_fn decl_args \
+    { return ((ID##FN)opencl_gl_check_fn(ID))(p1, p2, p3, p4, p5, p6, p7); } \
+
+#define opencl_gl_fn8(ID, _R, decl_args) \
+    typedef _R (CL_API_CALL*ID##FN)decl_args; \
+    static _R CL_API_CALL ID##_switch_fn decl_args \
+    { return ((ID##FN)opencl_gl_check_fn(ID))(p1, p2, p3, p4, p5, p6, p7, p8); } \
+
+#define opencl_gl_fn9(ID, _R, decl_args) \
+    typedef _R (CL_API_CALL*ID##FN)decl_args; \
+    static _R CL_API_CALL ID##_switch_fn decl_args \
+    { return ((ID##FN)opencl_gl_check_fn(ID))(p1, p2, p3, p4, p5, p6, p7, p8, p9); } \
+
+#define opencl_gl_fn10(ID, _R, decl_args) \
+    typedef _R (CL_API_CALL*ID##FN)decl_args; \
+    static _R CL_API_CALL ID##_switch_fn decl_args \
+    { return ((ID##FN)opencl_gl_check_fn(ID))(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10); } \
+
+#define opencl_gl_fn11(ID, _R, decl_args) \
+    typedef _R (CL_API_CALL*ID##FN)decl_args; \
+    static _R CL_API_CALL ID##_switch_fn decl_args \
+    { return ((ID##FN)opencl_gl_check_fn(ID))(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11); } \
+
+#define opencl_gl_fn12(ID, _R, decl_args) \
+    typedef _R (CL_API_CALL*ID##FN)decl_args; \
+    static _R CL_API_CALL ID##_switch_fn decl_args \
+    { return ((ID##FN)opencl_gl_check_fn(ID))(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12); } \
+
+#define opencl_gl_fn13(ID, _R, decl_args) \
+    typedef _R (CL_API_CALL*ID##FN)decl_args; \
+    static _R CL_API_CALL ID##_switch_fn decl_args \
+    { return ((ID##FN)opencl_gl_check_fn(ID))(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13); } \
+
+#define opencl_gl_fn14(ID, _R, decl_args) \
+    typedef _R (CL_API_CALL*ID##FN)decl_args; \
+    static _R CL_API_CALL ID##_switch_fn decl_args \
+    { return ((ID##FN)opencl_gl_check_fn(ID))(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14); } \
 
 } // anonymous namespace
 
+#ifdef cl_khr_gl_sharing
+
 // generated by parser_cl.py
+opencl_gl_fn4(OPENCL_GL_FN_clCreateFromGLBuffer, cl_mem, (cl_context p1, cl_mem_flags p2, cl_GLuint p3, int* p4))
 cl_mem (CL_API_CALL*clCreateFromGLBuffer)(cl_context, cl_mem_flags, cl_GLuint, int*) =
-        opencl_gl_fn4<OPENCL_GL_FN_clCreateFromGLBuffer, cl_mem, cl_context, cl_mem_flags, cl_GLuint, int*>::switch_fn;
+        OPENCL_GL_FN_clCreateFromGLBuffer_switch_fn;
 static const struct DynamicFnEntry clCreateFromGLBuffer_definition = { "clCreateFromGLBuffer", (void**)&clCreateFromGLBuffer};
 
+opencl_gl_fn4(OPENCL_GL_FN_clCreateFromGLRenderbuffer, cl_mem, (cl_context p1, cl_mem_flags p2, cl_GLuint p3, cl_int* p4))
 cl_mem (CL_API_CALL*clCreateFromGLRenderbuffer)(cl_context, cl_mem_flags, cl_GLuint, cl_int*) =
-        opencl_gl_fn4<OPENCL_GL_FN_clCreateFromGLRenderbuffer, cl_mem, cl_context, cl_mem_flags, cl_GLuint, cl_int*>::switch_fn;
+        OPENCL_GL_FN_clCreateFromGLRenderbuffer_switch_fn;
 static const struct DynamicFnEntry clCreateFromGLRenderbuffer_definition = { "clCreateFromGLRenderbuffer", (void**)&clCreateFromGLRenderbuffer};
 
+opencl_gl_fn6(OPENCL_GL_FN_clCreateFromGLTexture, cl_mem, (cl_context p1, cl_mem_flags p2, cl_GLenum p3, cl_GLint p4, cl_GLuint p5, cl_int* p6))
 cl_mem (CL_API_CALL*clCreateFromGLTexture)(cl_context, cl_mem_flags, cl_GLenum, cl_GLint, cl_GLuint, cl_int*) =
-        opencl_gl_fn6<OPENCL_GL_FN_clCreateFromGLTexture, cl_mem, cl_context, cl_mem_flags, cl_GLenum, cl_GLint, cl_GLuint, cl_int*>::switch_fn;
+        OPENCL_GL_FN_clCreateFromGLTexture_switch_fn;
 static const struct DynamicFnEntry clCreateFromGLTexture_definition = { "clCreateFromGLTexture", (void**)&clCreateFromGLTexture};
 
+opencl_gl_fn6(OPENCL_GL_FN_clCreateFromGLTexture2D, cl_mem, (cl_context p1, cl_mem_flags p2, cl_GLenum p3, cl_GLint p4, cl_GLuint p5, cl_int* p6))
 cl_mem (CL_API_CALL*clCreateFromGLTexture2D)(cl_context, cl_mem_flags, cl_GLenum, cl_GLint, cl_GLuint, cl_int*) =
-        opencl_gl_fn6<OPENCL_GL_FN_clCreateFromGLTexture2D, cl_mem, cl_context, cl_mem_flags, cl_GLenum, cl_GLint, cl_GLuint, cl_int*>::switch_fn;
+        OPENCL_GL_FN_clCreateFromGLTexture2D_switch_fn;
 static const struct DynamicFnEntry clCreateFromGLTexture2D_definition = { "clCreateFromGLTexture2D", (void**)&clCreateFromGLTexture2D};
 
+opencl_gl_fn6(OPENCL_GL_FN_clCreateFromGLTexture3D, cl_mem, (cl_context p1, cl_mem_flags p2, cl_GLenum p3, cl_GLint p4, cl_GLuint p5, cl_int* p6))
 cl_mem (CL_API_CALL*clCreateFromGLTexture3D)(cl_context, cl_mem_flags, cl_GLenum, cl_GLint, cl_GLuint, cl_int*) =
-        opencl_gl_fn6<OPENCL_GL_FN_clCreateFromGLTexture3D, cl_mem, cl_context, cl_mem_flags, cl_GLenum, cl_GLint, cl_GLuint, cl_int*>::switch_fn;
+        OPENCL_GL_FN_clCreateFromGLTexture3D_switch_fn;
 static const struct DynamicFnEntry clCreateFromGLTexture3D_definition = { "clCreateFromGLTexture3D", (void**)&clCreateFromGLTexture3D};
 
+opencl_gl_fn6(OPENCL_GL_FN_clEnqueueAcquireGLObjects, cl_int, (cl_command_queue p1, cl_uint p2, const cl_mem* p3, cl_uint p4, const cl_event* p5, cl_event* p6))
 cl_int (CL_API_CALL*clEnqueueAcquireGLObjects)(cl_command_queue, cl_uint, const cl_mem*, cl_uint, const cl_event*, cl_event*) =
-        opencl_gl_fn6<OPENCL_GL_FN_clEnqueueAcquireGLObjects, cl_int, cl_command_queue, cl_uint, const cl_mem*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+        OPENCL_GL_FN_clEnqueueAcquireGLObjects_switch_fn;
 static const struct DynamicFnEntry clEnqueueAcquireGLObjects_definition = { "clEnqueueAcquireGLObjects", (void**)&clEnqueueAcquireGLObjects};
 
+opencl_gl_fn6(OPENCL_GL_FN_clEnqueueReleaseGLObjects, cl_int, (cl_command_queue p1, cl_uint p2, const cl_mem* p3, cl_uint p4, const cl_event* p5, cl_event* p6))
 cl_int (CL_API_CALL*clEnqueueReleaseGLObjects)(cl_command_queue, cl_uint, const cl_mem*, cl_uint, const cl_event*, cl_event*) =
-        opencl_gl_fn6<OPENCL_GL_FN_clEnqueueReleaseGLObjects, cl_int, cl_command_queue, cl_uint, const cl_mem*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+        OPENCL_GL_FN_clEnqueueReleaseGLObjects_switch_fn;
 static const struct DynamicFnEntry clEnqueueReleaseGLObjects_definition = { "clEnqueueReleaseGLObjects", (void**)&clEnqueueReleaseGLObjects};
 
+opencl_gl_fn5(OPENCL_GL_FN_clGetGLContextInfoKHR, cl_int, (const cl_context_properties* p1, cl_gl_context_info p2, size_t p3, void* p4, size_t* p5))
 cl_int (CL_API_CALL*clGetGLContextInfoKHR)(const cl_context_properties*, cl_gl_context_info, size_t, void*, size_t*) =
-        opencl_gl_fn5<OPENCL_GL_FN_clGetGLContextInfoKHR, cl_int, const cl_context_properties*, cl_gl_context_info, size_t, void*, size_t*>::switch_fn;
+        OPENCL_GL_FN_clGetGLContextInfoKHR_switch_fn;
 static const struct DynamicFnEntry clGetGLContextInfoKHR_definition = { "clGetGLContextInfoKHR", (void**)&clGetGLContextInfoKHR};
 
+opencl_gl_fn3(OPENCL_GL_FN_clGetGLObjectInfo, cl_int, (cl_mem p1, cl_gl_object_type* p2, cl_GLuint* p3))
 cl_int (CL_API_CALL*clGetGLObjectInfo)(cl_mem, cl_gl_object_type*, cl_GLuint*) =
-        opencl_gl_fn3<OPENCL_GL_FN_clGetGLObjectInfo, cl_int, cl_mem, cl_gl_object_type*, cl_GLuint*>::switch_fn;
+        OPENCL_GL_FN_clGetGLObjectInfo_switch_fn;
 static const struct DynamicFnEntry clGetGLObjectInfo_definition = { "clGetGLObjectInfo", (void**)&clGetGLObjectInfo};
 
+opencl_gl_fn5(OPENCL_GL_FN_clGetGLTextureInfo, cl_int, (cl_mem p1, cl_gl_texture_info p2, size_t p3, void* p4, size_t* p5))
 cl_int (CL_API_CALL*clGetGLTextureInfo)(cl_mem, cl_gl_texture_info, size_t, void*, size_t*) =
-        opencl_gl_fn5<OPENCL_GL_FN_clGetGLTextureInfo, cl_int, cl_mem, cl_gl_texture_info, size_t, void*, size_t*>::switch_fn;
+        OPENCL_GL_FN_clGetGLTextureInfo_switch_fn;
 static const struct DynamicFnEntry clGetGLTextureInfo_definition = { "clGetGLTextureInfo", (void**)&clGetGLTextureInfo};
 
 
@@ -196,3 +163,5 @@ static const struct DynamicFnEntry* opencl_gl_fn_list[] = {
 };
 
 // number of enabled functions: 10
+
+#endif // cl_khr_gl_sharing
diff --git a/modules/core/src/opencl/runtime/generator/common.py b/modules/core/src/opencl/runtime/generator/common.py
index 80c5452..d9064fa 100644
--- a/modules/core/src/opencl/runtime/generator/common.py
+++ b/modules/core/src/opencl/runtime/generator/common.py
@@ -136,16 +136,30 @@ def generateFilterNames(fns):
         print '%s%s' % ('' if fn.has_key('enabled') else '//', fn['name'])
     print '#total %d' % len(fns)
 
+callback_check = re.compile(r'([^\(]*\(.*)(\* *)(\).*\(.*\))')
+
+def getTypeWithParam(t, p):
+    if callback_check.match(t):
+        return callback_check.sub(r'\1 *' + p + r'\3', t)
+    return t + ' ' + p
+
 @outputToString
 def generateStructDefinitions(fns, lprefix='opencl_fn', enumprefix='OPENCL_FN'):
     print '// generated by %s' % os.path.basename(sys.argv[0])
     first = True
     for fn in fns:
         commentStr = '' if fn.has_key('enabled') else '//'
-        print commentStr + ('%s%s (%s *%s)(%s) =\n%s        %s%d<%s_%s, %s%s>::switch_fn;' % \
+        decl_args = []
+        for (i, t) in enumerate(fn['params']):
+            decl_args.append(getTypeWithParam(t, 'p%d' % (i+1)))
+        decl_args_str = '(' + (', '.join(decl_args)) + ')'
+        print '%s%s%d(%s_%s, %s, %s)' % \
+             (commentStr, lprefix, len(fn['params']), enumprefix, fn['name'], \
+             ' '.join(fn['ret']), decl_args_str)
+        print commentStr + ('%s%s (%s *%s)(%s) =\n%s        %s_%s_switch_fn;' % \
             ((' '.join(fn['modifiers'] + ' ') if len(fn['modifiers']) > 0 else ''),
              ' '.join(fn['ret']), ' '.join(fn['calling']), fn['name'], ', '.join(fn['params']), \
-             commentStr, lprefix, len(fn['params']), enumprefix, fn['name'], ' '.join(fn['ret']), ('' if len(fn['params']) == 0 else ', ' + ', '.join(fn['params']))))
+             commentStr, enumprefix, fn['name']))
         print commentStr + ('static const struct DynamicFnEntry %s_definition = { "%s", (void**)&%s};' % (fn['name'], fn['name'], fn['name']))
         print
         first = False
@@ -200,22 +214,12 @@ def generateFnDeclaration(fns):
 def generateTemplates(sz, lprefix, switch_name, calling_convention=''):
     print '// generated by %s' % os.path.basename(sys.argv[0])
     for sz in range(sz):
-        template_params = ['int ID', 'typename _R']
-        types = []
-        types_with_params = []
-        params = []
-        for i in range(1, sz + 1):
-            template_params.append('typename _T%d' % i)
-            types.append('_T%d' % i)
-            types_with_params.append('_T%d p%d' % (i, i))
-            params.append('p%d' % i)
-        print 'template <%s>' % ', '.join(template_params)
-        print 'struct %s%d' % (lprefix, sz)
-        print '{'
-        print '    typedef _R (%s *FN)(%s);' % (calling_convention, ', '.join(types))
-        print '    static _R %s switch_fn(%s)' % (calling_convention, ', '.join(types_with_params))
-        print '    { return ((FN)%s(ID))(%s); }' % (switch_name, ', '.join(params))
-        print '};'
+        template_params = ['ID', '_R', 'decl_args']
+        params = ['p%d' % (i + 1) for i in range(0, sz)]
+        print '#define %s%d(%s) \\' % (lprefix, sz, ', '.join(template_params))
+        print '    typedef _R (%s *ID##FN)decl_args; \\' % (calling_convention)
+        print '    static _R %s ID##_switch_fn decl_args \\' % (calling_convention)
+        print '    { return ((ID##FN)%s(ID))(%s); } \\' % (switch_name, ', '.join(params))
         print ''
 
 @outputToString
@@ -254,6 +258,6 @@ def ProcessTemplate(inputFile, ctx, noteLine='//\n// AUTOGENERATED, DO NOT EDIT\
             assert line[-1] == '@'
             name = line[1:-1]
             assert ctx.has_key(name), name
-            line = ctx[name]
-        print line,
+            line = ctx[name] + ('\n' if len(ctx[name]) > 0 and ctx[name][-1] != '\n' else '')
+        sys.stdout.write(line)
     f.close()
diff --git a/modules/core/src/opencl/runtime/generator/generate.sh b/modules/core/src/opencl/runtime/generator/generate.sh
old mode 100644
new mode 100755
diff --git a/modules/core/src/opencl/runtime/generator/template/opencl_clamdblas.hpp.in b/modules/core/src/opencl/runtime/generator/template/opencl_clamdblas.hpp.in
index 251c085..5b48f51 100644
--- a/modules/core/src/opencl/runtime/generator/template/opencl_clamdblas.hpp.in
+++ b/modules/core/src/opencl/runtime/generator/template/opencl_clamdblas.hpp.in
@@ -1,4 +1,4 @@
-#ifndef __OPENCV_CORE_OCL_RUNTIME_CLAMDBLAS_HPP__
+#ifndef OPENCV_CORE_OCL_RUNTIME_CLAMDBLAS_HPP
 #error "Invalid usage"
 #endif
 
diff --git a/modules/core/src/opencl/runtime/generator/template/opencl_clamdfft.hpp.in b/modules/core/src/opencl/runtime/generator/template/opencl_clamdfft.hpp.in
index 8633580..4e8a563 100644
--- a/modules/core/src/opencl/runtime/generator/template/opencl_clamdfft.hpp.in
+++ b/modules/core/src/opencl/runtime/generator/template/opencl_clamdfft.hpp.in
@@ -1,4 +1,4 @@
-#ifndef __OPENCV_CORE_OCL_RUNTIME_CLAMDFFT_HPP__
+#ifndef OPENCV_CORE_OCL_RUNTIME_CLAMDFFT_HPP
 #error "Invalid usage"
 #endif
 
diff --git a/modules/core/src/opencl/runtime/generator/template/opencl_core.hpp.in b/modules/core/src/opencl/runtime/generator/template/opencl_core.hpp.in
index 4196622..db9eb80 100644
--- a/modules/core/src/opencl/runtime/generator/template/opencl_core.hpp.in
+++ b/modules/core/src/opencl/runtime/generator/template/opencl_core.hpp.in
@@ -1,14 +1,10 @@
-#ifndef __OPENCV_CORE_OCL_RUNTIME_OPENCL_CORE_HPP__
+#ifndef OPENCV_CORE_OCL_RUNTIME_OPENCL_CORE_HPP
 #error "Invalid usage"
 #endif
 
 @CL_REMAP_ORIGIN@
 
-#if defined __APPLE__
-#include <OpenCL/cl.h>
-#else
 #include <CL/cl.h>
-#endif
 
 @CL_REMAP_DYNAMIC@
 
diff --git a/modules/core/src/opencl/runtime/generator/template/opencl_core_wrappers.hpp.in b/modules/core/src/opencl/runtime/generator/template/opencl_core_wrappers.hpp.in
index 847e67f..1c2cb68 100644
--- a/modules/core/src/opencl/runtime/generator/template/opencl_core_wrappers.hpp.in
+++ b/modules/core/src/opencl/runtime/generator/template/opencl_core_wrappers.hpp.in
@@ -1,4 +1,4 @@
-#ifndef __OPENCV_CORE_OCL_RUNTIME_OPENCL_WRAPPERS_HPP__
+#ifndef OPENCV_CORE_OCL_RUNTIME_OPENCL_WRAPPERS_HPP
 #error "Invalid usage"
 #endif
 
diff --git a/modules/core/src/opencl/runtime/generator/template/opencl_gl.hpp.in b/modules/core/src/opencl/runtime/generator/template/opencl_gl.hpp.in
index 24434d2..d9de9f6 100644
--- a/modules/core/src/opencl/runtime/generator/template/opencl_gl.hpp.in
+++ b/modules/core/src/opencl/runtime/generator/template/opencl_gl.hpp.in
@@ -1,15 +1,15 @@
-#ifndef __OPENCV_CORE_OCL_RUNTIME_OPENCL_GL_HPP__
+#ifndef OPENCV_CORE_OCL_RUNTIME_OPENCL_GL_HPP
 #error "Invalid usage"
 #endif
 
 @CL_REMAP_ORIGIN@
 
-#if defined __APPLE__
-#include <OpenCL/cl_gl.h>
-#else
 #include <CL/cl_gl.h>
-#endif
 
 @CL_REMAP_DYNAMIC@
 
+#ifdef cl_khr_gl_sharing
+
 @CL_FN_DECLARATIONS@
+
+#endif // cl_khr_gl_sharing
diff --git a/modules/core/src/opencl/runtime/generator/template/opencl_gl_impl.hpp.in b/modules/core/src/opencl/runtime/generator/template/opencl_gl_impl.hpp.in
index 1458601..cba1278 100644
--- a/modules/core/src/opencl/runtime/generator/template/opencl_gl_impl.hpp.in
+++ b/modules/core/src/opencl/runtime/generator/template/opencl_gl_impl.hpp.in
@@ -4,8 +4,12 @@ namespace {
 @CL_FN_SWITCH@
 } // anonymous namespace
 
+#ifdef cl_khr_gl_sharing
+
 @CL_FN_ENTRY_DEFINITIONS@
 
 @CL_FN_ENTRY_LIST@
 
 @CL_NUMBER_OF_ENABLED_FUNCTIONS@
+
+#endif // cl_khr_gl_sharing
diff --git a/modules/core/src/opencl/runtime/generator/template/opencl_gl_wrappers.hpp.in b/modules/core/src/opencl/runtime/generator/template/opencl_gl_wrappers.hpp.in
index 0aeefb4..c5b7554 100644
--- a/modules/core/src/opencl/runtime/generator/template/opencl_gl_wrappers.hpp.in
+++ b/modules/core/src/opencl/runtime/generator/template/opencl_gl_wrappers.hpp.in
@@ -1,5 +1,9 @@
-#ifndef __OPENCV_CORE_OCL_RUNTIME_OPENCL_GL_WRAPPERS_HPP__
+#ifndef OPENCV_CORE_OCL_RUNTIME_OPENCL_GL_WRAPPERS_HPP
 #error "Invalid usage"
 #endif
 
+#ifdef cl_khr_gl_sharing
+
 @CL_FN_INLINE_WRAPPERS@
+
+#endif // cl_khr_gl_sharing
diff --git a/modules/core/src/opencl/runtime/opencl_core.cpp b/modules/core/src/opencl/runtime/opencl_core.cpp
index 971c077..dc3d0a4 100644
--- a/modules/core/src/opencl/runtime/opencl_core.cpp
+++ b/modules/core/src/opencl/runtime/opencl_core.cpp
@@ -58,11 +58,11 @@ static void* AppleCLGetProcAddress(const char* name)
 {
     static bool initialized = false;
     static void* handle = NULL;
-    if (!handle)
+    if (!handle && !initialized)
     {
-        if(!initialized)
+        cv::AutoLock lock(cv::getInitializationMutex());
+        if (!initialized)
         {
-            initialized = true;
             const char* path = "/System/Library/Frameworks/OpenCL.framework/Versions/Current/OpenCL";
             const char* envPath = getenv("OPENCV_OPENCL_RUNTIME");
             if (envPath)
@@ -78,10 +78,11 @@ static void* AppleCLGetProcAddress(const char* name)
                 fprintf(stderr, ERROR_MSG_INVALID_VERSION);
                 handle = NULL;
             }
+            initialized = true;
         }
-        if (!handle)
-            return NULL;
     }
+    if (!handle)
+        return NULL;
     return dlsym(handle, name);
 }
 #define CV_CL_GET_PROC_ADDRESS(name) AppleCLGetProcAddress(name)
@@ -94,11 +95,11 @@ static void* WinGetProcAddress(const char* name)
 {
     static bool initialized = false;
     static HMODULE handle = NULL;
-    if (!handle)
+    if (!handle && !initialized)
     {
-        if(!initialized)
+        cv::AutoLock lock(cv::getInitializationMutex());
+        if (!initialized)
         {
-            initialized = true;
             handle = GetModuleHandleA("OpenCL.dll");
             if (!handle)
             {
@@ -118,10 +119,11 @@ static void* WinGetProcAddress(const char* name)
                     handle = NULL;
                 }
             }
+            initialized = true;
         }
-        if (!handle)
-            return NULL;
     }
+    if (!handle)
+        return NULL;
     return (void*)GetProcAddress(handle, name);
 }
 #define CV_CL_GET_PROC_ADDRESS(name) WinGetProcAddress(name)
@@ -135,11 +137,11 @@ static void* GetProcAddress(const char* name)
 {
     static bool initialized = false;
     static void* handle = NULL;
-    if (!handle)
+    if (!handle && !initialized)
     {
-        if(!initialized)
+        cv::AutoLock lock(cv::getInitializationMutex());
+        if (!initialized)
         {
-            initialized = true;
             const char* path = "libOpenCL.so";
             const char* envPath = getenv("OPENCV_OPENCL_RUNTIME");
             if (envPath)
@@ -155,10 +157,11 @@ static void* GetProcAddress(const char* name)
                 fprintf(stderr, ERROR_MSG_INVALID_VERSION);
                 handle = NULL;
             }
+            initialized = true;
         }
-        if (!handle)
-            return NULL;
     }
+    if (!handle)
+        return NULL;
     return dlsym(handle, name);
 }
 #define CV_CL_GET_PROC_ADDRESS(name) GetProcAddress(name)
@@ -203,32 +206,33 @@ enum OPENCL_FN_SVM_ID
     OPENCL_FN_clEnqueueSVMUnmap,
 };
 
+opencl_fn4(OPENCL_FN_clSVMAlloc, void*, (cl_context p1, cl_svm_mem_flags p2, size_t p3, unsigned int p4))
 void* (CL_API_CALL *clSVMAlloc)(cl_context context, cl_svm_mem_flags flags, size_t size, unsigned int alignment) =
-        opencl_fn4<OPENCL_FN_clSVMAlloc, void*, cl_context, cl_svm_mem_flags, size_t, unsigned int>::switch_fn;
+        OPENCL_FN_clSVMAlloc_switch_fn;
 static const struct DynamicFnEntry _clSVMAlloc_definition = { "clSVMAlloc", (void**)&clSVMAlloc};
+opencl_fn2(OPENCL_FN_clSVMFree, void, (cl_context p1, void* p2))
 void (CL_API_CALL *clSVMFree)(cl_context context, void* svm_pointer) =
-        opencl_fn2<OPENCL_FN_clSVMFree, void, cl_context, void*>::switch_fn;
+        OPENCL_FN_clSVMFree_switch_fn;
 static const struct DynamicFnEntry _clSVMFree_definition = { "clSVMFree", (void**)&clSVMFree};
+opencl_fn3(OPENCL_FN_clSetKernelArgSVMPointer, cl_int, (cl_kernel p1, cl_uint p2, const void* p3))
 cl_int (CL_API_CALL *clSetKernelArgSVMPointer)(cl_kernel kernel, cl_uint arg_index, const void* arg_value) =
-        opencl_fn3<OPENCL_FN_clSetKernelArgSVMPointer, cl_int, cl_kernel, cl_uint, const void*>::switch_fn;
+        OPENCL_FN_clSetKernelArgSVMPointer_switch_fn;
 static const struct DynamicFnEntry _clSetKernelArgSVMPointer_definition = { "clSetKernelArgSVMPointer", (void**)&clSetKernelArgSVMPointer};
-//void* (CL_API_CALL *clSetKernelExecInfo)(cl_kernel kernel, cl_kernel_exec_info param_name, size_t param_value_size, const void* param_value) =
-//        opencl_fn4<OPENCL_FN_clSetKernelExecInfo, void*, cl_kernel, cl_kernel_exec_info, size_t, const void*>::switch_fn;
-//static const struct DynamicFnEntry _clSetKernelExecInfo_definition = { "clSetKernelExecInfo", (void**)&clSetKernelExecInfo};
-//cl_int (CL_API_CALL *clEnqueueSVMFree)(...) =
-//        opencl_fn8<OPENCL_FN_clEnqueueSVMFree, cl_int, ...>::switch_fn;
-//static const struct DynamicFnEntry _clEnqueueSVMFree_definition = { "clEnqueueSVMFree", (void**)&clEnqueueSVMFree};
+opencl_fn8(OPENCL_FN_clEnqueueSVMMemcpy, cl_int, (cl_command_queue p1, cl_bool p2, void* p3, const void* p4, size_t p5, cl_uint p6, const cl_event* p7, cl_event* p8))
 cl_int (CL_API_CALL *clEnqueueSVMMemcpy)(cl_command_queue command_queue, cl_bool blocking_copy, void* dst_ptr, const void* src_ptr, size_t size, cl_uint num_events_in_wait_list, const cl_event* event_wait_list, cl_event* event) =
-        opencl_fn8<OPENCL_FN_clEnqueueSVMMemcpy, cl_int, cl_command_queue, cl_bool, void*, const void*, size_t, cl_uint, const cl_event*, cl_event*>::switch_fn;
+        OPENCL_FN_clEnqueueSVMMemcpy_switch_fn;
 static const struct DynamicFnEntry _clEnqueueSVMMemcpy_definition = { "clEnqueueSVMMemcpy", (void**)&clEnqueueSVMMemcpy};
+opencl_fn8(OPENCL_FN_clEnqueueSVMMemFill, cl_int, (cl_command_queue p1, void* p2, const void* p3, size_t p4, size_t p5, cl_uint p6, const cl_event* p7, cl_event* p8))
 cl_int (CL_API_CALL *clEnqueueSVMMemFill)(cl_command_queue command_queue, void* svm_ptr, const void* pattern, size_t pattern_size, size_t size, cl_uint num_events_in_wait_list, const cl_event* event_wait_list, cl_event* event) =
-        opencl_fn8<OPENCL_FN_clEnqueueSVMMemFill, cl_int, cl_command_queue, void*, const void*, size_t, size_t, cl_uint, const cl_event*, cl_event*>::switch_fn;
+        OPENCL_FN_clEnqueueSVMMemFill_switch_fn;
 static const struct DynamicFnEntry _clEnqueueSVMMemFill_definition = { "clEnqueueSVMMemFill", (void**)&clEnqueueSVMMemFill};
+opencl_fn8(OPENCL_FN_clEnqueueSVMMap, cl_int, (cl_command_queue p1, cl_bool p2, cl_map_flags p3, void* p4, size_t p5, cl_uint p6, const cl_event* p7, cl_event* p8))
 cl_int (CL_API_CALL *clEnqueueSVMMap)(cl_command_queue command_queue, cl_bool blocking_map, cl_map_flags map_flags, void* svm_ptr, size_t size, cl_uint num_events_in_wait_list, const cl_event* event_wait_list, cl_event* event) =
-        opencl_fn8<OPENCL_FN_clEnqueueSVMMap, cl_int, cl_command_queue, cl_bool, cl_map_flags, void*, size_t, cl_uint, const cl_event*, cl_event*>::switch_fn;
+        OPENCL_FN_clEnqueueSVMMap_switch_fn;
 static const struct DynamicFnEntry _clEnqueueSVMMap_definition = { "clEnqueueSVMMap", (void**)&clEnqueueSVMMap};
+opencl_fn5(OPENCL_FN_clEnqueueSVMUnmap, cl_int, (cl_command_queue p1, void* p2, cl_uint p3, const cl_event* p4, cl_event* p5))
 cl_int (CL_API_CALL *clEnqueueSVMUnmap)(cl_command_queue command_queue, void* svm_ptr, cl_uint num_events_in_wait_list, const cl_event* event_wait_list, cl_event* event) =
-        opencl_fn5<OPENCL_FN_clEnqueueSVMUnmap, cl_int, cl_command_queue, void*, cl_uint, const cl_event*, cl_event*>::switch_fn;
+        OPENCL_FN_clEnqueueSVMUnmap_switch_fn;
 static const struct DynamicFnEntry _clEnqueueSVMUnmap_definition = { "clEnqueueSVMUnmap", (void**)&clEnqueueSVMUnmap};
 
 static const struct DynamicFnEntry* opencl_svm_fn_list[] = {
@@ -283,6 +287,8 @@ static void* opencl_check_fn(int ID)
 
 #include "opencv2/core/opencl/runtime/opencl_gl.hpp"
 
+#ifdef cl_khr_gl_sharing
+
 static void* opencl_gl_check_fn(int ID);
 
 #include "autogenerated/opencl_gl_impl.hpp"
@@ -303,6 +309,8 @@ static void* opencl_gl_check_fn(int ID)
     return func;
 }
 
+#endif // cl_khr_gl_sharing
+
 #endif // HAVE_OPENGL
 
 #endif
diff --git a/modules/core/src/opengl.cpp b/modules/core/src/opengl.cpp
index 3bbc0f8..f3d106f 100644
--- a/modules/core/src/opengl.cpp
+++ b/modules/core/src/opengl.cpp
@@ -1580,6 +1580,11 @@ void cv::ogl::render(const ogl::Arrays& arr, InputArray indices, int mode, Scala
 
 #ifdef HAVE_OPENCL
 #  include "opencv2/core/opencl/runtime/opencl_gl.hpp"
+#  ifdef cl_khr_gl_sharing
+#    define HAVE_OPENCL_OPENGL_SHARING
+#  else
+#    define NO_OPENCL_SHARING_ERROR CV_ErrorNoReturn(cv::Error::StsBadFunc, "OpenCV was build without OpenCL/OpenGL sharing support")
+#  endif
 #else // HAVE_OPENCL
 #  define NO_OPENCL_SUPPORT_ERROR CV_ErrorNoReturn(cv::Error::StsBadFunc, "OpenCV was build without OpenCL support")
 #endif // HAVE_OPENCL
@@ -1602,6 +1607,8 @@ Context& initializeContextFromGL()
     NO_OPENGL_SUPPORT_ERROR;
 #elif !defined(HAVE_OPENCL)
     NO_OPENCL_SUPPORT_ERROR;
+#elif !defined(HAVE_OPENCL_OPENGL_SHARING)
+    NO_OPENCL_SHARING_ERROR;
 #else
     cl_uint numPlatforms;
     cl_int status = clGetPlatformIDs(0, NULL, &numPlatforms);
@@ -1701,6 +1708,8 @@ void convertToGLTexture2D(InputArray src, Texture2D& texture)
     NO_OPENGL_SUPPORT_ERROR;
 #elif !defined(HAVE_OPENCL)
     NO_OPENCL_SUPPORT_ERROR;
+#elif !defined(HAVE_OPENCL_OPENGL_SHARING)
+    NO_OPENCL_SHARING_ERROR;
 #else
     Size srcSize = src.size();
     CV_Assert(srcSize.width == (int)texture.cols() && srcSize.height == (int)texture.rows());
@@ -1753,6 +1762,8 @@ void convertFromGLTexture2D(const Texture2D& texture, OutputArray dst)
     NO_OPENGL_SUPPORT_ERROR;
 #elif !defined(HAVE_OPENCL)
     NO_OPENCL_SUPPORT_ERROR;
+#elif !defined(HAVE_OPENCL_OPENGL_SHARING)
+    NO_OPENCL_SHARING_ERROR;
 #else
     // check texture format
     const int dtype = CV_8UC4;
@@ -1812,6 +1823,8 @@ UMat mapGLBuffer(const Buffer& buffer, int accessFlags)
     NO_OPENGL_SUPPORT_ERROR;
 #elif !defined(HAVE_OPENCL)
     NO_OPENCL_SUPPORT_ERROR;
+#elif !defined(HAVE_OPENCL_OPENGL_SHARING)
+    NO_OPENCL_SHARING_ERROR;
 #else
     using namespace cv::ocl;
     Context& ctx = Context::getDefault();
@@ -1862,6 +1875,8 @@ void unmapGLBuffer(UMat& u)
     NO_OPENGL_SUPPORT_ERROR;
 #elif !defined(HAVE_OPENCL)
     NO_OPENCL_SUPPORT_ERROR;
+#elif !defined(HAVE_OPENCL_OPENGL_SHARING)
+    NO_OPENCL_SHARING_ERROR;
 #else
     using namespace cv::ocl;
     cl_command_queue clQueue = (cl_command_queue)Queue::getDefault().ptr();
diff --git a/modules/core/src/ovx.cpp b/modules/core/src/ovx.cpp
new file mode 100644
index 0000000..a53f553
--- /dev/null
+++ b/modules/core/src/ovx.cpp
@@ -0,0 +1,72 @@
+// This file is part of OpenCV project.
+// It is subject to the license terms in the LICENSE file found in the top-level directory
+// of this distribution and at http://opencv.org/license.html.
+
+// Copyright (C) 2016, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+
+// OpenVX related functions
+
+#include "precomp.hpp"
+#include "opencv2/core/ovx.hpp"
+#include "opencv2/core/openvx/ovx_defs.hpp"
+
+namespace cv
+{
+
+bool haveOpenVX()
+{
+#ifdef HAVE_OPENVX
+    static int g_haveOpenVX = -1;
+    if(g_haveOpenVX < 0)
+    {
+        try
+        {
+        ivx::Context context = ivx::Context::create();
+        vx_uint16 vComp = ivx::compiledWithVersion();
+        vx_uint16 vCurr = context.version();
+        g_haveOpenVX =
+                VX_VERSION_MAJOR(vComp) == VX_VERSION_MAJOR(vCurr) &&
+                VX_VERSION_MINOR(vComp) == VX_VERSION_MINOR(vCurr)
+                ? 1 : 0;
+        }
+        catch(const ivx::WrapperError&)
+        { g_haveOpenVX = 0; }
+        catch(const ivx::RuntimeError&)
+        { g_haveOpenVX = 0; }
+    }
+    return g_haveOpenVX == 1;
+#else
+    return false;
+#endif
+}
+
+bool useOpenVX()
+{
+#ifdef HAVE_OPENVX
+    CoreTLSData* data = getCoreTlsData().get();
+    if( data->useOpenVX < 0 )
+    {
+        // enabled (if available) by default
+        data->useOpenVX = haveOpenVX() ? 1 : 0;
+    }
+    return data->useOpenVX > 0;
+#else
+    return false;
+#endif
+}
+
+void setUseOpenVX(bool flag)
+{
+#ifdef HAVE_OPENVX
+    if( haveOpenVX() )
+    {
+        CoreTLSData* data = getCoreTlsData().get();
+        data->useOpenVX = flag ? 1 : 0;
+    }
+#else
+    CV_Assert(!flag && "OpenVX support isn't enabled at compile time");
+#endif
+}
+
+} // namespace cv
diff --git a/modules/core/src/parallel.cpp b/modules/core/src/parallel.cpp
index b805ab4..71ac94e 100644
--- a/modules/core/src/parallel.cpp
+++ b/modules/core/src/parallel.cpp
@@ -84,37 +84,30 @@
 */
 
 #if defined HAVE_TBB
+    #include "tbb/tbb.h"
+    #include "tbb/task.h"
     #include "tbb/tbb_stddef.h"
-    #if TBB_VERSION_MAJOR*100 + TBB_VERSION_MINOR >= 202
-        #include "tbb/tbb.h"
-        #include "tbb/task.h"
-        #if TBB_INTERFACE_VERSION >= 6100
-            #include "tbb/task_arena.h"
-        #endif
-        #undef min
-        #undef max
-    #else
-        #undef HAVE_TBB
-    #endif // end TBB version
-#endif
-
-#ifndef HAVE_TBB
-    #if defined HAVE_CSTRIPES
-        #include "C=.h"
-        #undef shared
-    #elif defined HAVE_OPENMP
-        #include <omp.h>
-    #elif defined HAVE_GCD
-        #include <dispatch/dispatch.h>
-        #include <pthread.h>
-    #elif defined WINRT && _MSC_VER < 1900
-        #include <ppltasks.h>
-    #elif defined HAVE_CONCURRENCY
-        #include <ppl.h>
+    #if TBB_INTERFACE_VERSION >= 8000
+        #include "tbb/task_arena.h"
     #endif
+    #undef min
+    #undef max
+#elif defined HAVE_CSTRIPES
+    #include "C=.h"
+    #undef shared
+#elif defined HAVE_OPENMP
+    #include <omp.h>
+#elif defined HAVE_GCD
+    #include <dispatch/dispatch.h>
+    #include <pthread.h>
+#elif defined WINRT && _MSC_VER < 1900
+    #include <ppltasks.h>
+#elif defined HAVE_CONCURRENCY
+    #include <ppl.h>
 #endif
 
-#if defined HAVE_TBB && TBB_VERSION_MAJOR*100 + TBB_VERSION_MINOR >= 202
+
+#if defined HAVE_TBB
 #  define CV_PARALLEL_FRAMEWORK "tbb"
 #elif defined HAVE_CSTRIPES
 #  define CV_PARALLEL_FRAMEWORK "cstripes"
@@ -144,18 +137,64 @@ namespace cv
 namespace
 {
 #ifdef CV_PARALLEL_FRAMEWORK
-    class ParallelLoopBodyWrapper
+#ifdef ENABLE_INSTRUMENTATION
+    static void SyncNodes(cv::instr::InstrNode *pNode)
+    {
+        std::vector<cv::instr::NodeDataTls*> data;
+        pNode->m_payload.m_tls.gather(data);
+
+        uint64 ticksMax = 0;
+        int    threads  = 0;
+        for(size_t i = 0; i < data.size(); i++)
+        {
+            if(data[i] && data[i]->m_ticksTotal)
+            {
+                ticksMax = MAX(ticksMax, data[i]->m_ticksTotal);
+                pNode->m_payload.m_ticksTotal -= data[i]->m_ticksTotal;
+                data[i]->m_ticksTotal = 0;
+                threads++;
+            }
+        }
+        pNode->m_payload.m_ticksTotal += ticksMax;
+        pNode->m_payload.m_threads = MAX(pNode->m_payload.m_threads, threads);
+
+        for(size_t i = 0; i < pNode->m_childs.size(); i++)
+            SyncNodes(pNode->m_childs[i]);
+    }
+#endif
+
+    class ParallelLoopBodyWrapper : public cv::ParallelLoopBody
     {
     public:
         ParallelLoopBodyWrapper(const cv::ParallelLoopBody& _body, const cv::Range& _r, double _nstripes)
         {
+
             body = &_body;
             wholeRange = _r;
             double len = wholeRange.end - wholeRange.start;
             nstripes = cvRound(_nstripes <= 0 ? len : MIN(MAX(_nstripes, 1.), len));
+
+#ifdef ENABLE_INSTRUMENTATION
+            pThreadRoot = cv::instr::getInstrumentTLSStruct().pCurrentNode;
+#endif
         }
+#ifdef ENABLE_INSTRUMENTATION
+        ~ParallelLoopBodyWrapper()
+        {
+            for(size_t i = 0; i < pThreadRoot->m_childs.size(); i++)
+                SyncNodes(pThreadRoot->m_childs[i]);
+        }
+#endif
         void operator()(const cv::Range& sr) const
         {
+#ifdef ENABLE_INSTRUMENTATION
+            {
+                cv::instr::InstrTLSStruct *pInstrTLS = &cv::instr::getInstrumentTLSStruct();
+                pInstrTLS->pCurrentNode = pThreadRoot; // Initialize TLS node for thread
+            }
+#endif
+            CV_INSTRUMENT_REGION()
+
             cv::Range r;
             r.start = (int)(wholeRange.start +
                             ((uint64)sr.start*(wholeRange.end - wholeRange.start) + nstripes/2)/nstripes);
@@ -169,6 +208,9 @@ namespace
         const cv::ParallelLoopBody* body;
         cv::Range wholeRange;
         int nstripes;
+#ifdef ENABLE_INSTRUMENTATION
+        cv::instr::InstrNode *pThreadRoot;
+#endif
     };
 
 #if defined HAVE_TBB
@@ -252,6 +294,10 @@ static SchedPtr pplScheduler;
 
 void cv::parallel_for_(const cv::Range& range, const cv::ParallelLoopBody& body, double nstripes)
 {
+    CV_INSTRUMENT_REGION_MT_FORK()
+    if (range.empty())
+        return;
+
 #ifdef CV_PARALLEL_FRAMEWORK
 
     if(numThreads != 0)
@@ -309,7 +355,7 @@ void cv::parallel_for_(const cv::Range& range, const cv::ParallelLoopBody& body,
 
 #elif defined HAVE_PTHREADS_PF
 
-        parallel_for_pthreads(range, body, nstripes);
+        parallel_for_pthreads(pbody.stripeRange(), pbody, pbody.stripeRange().size());
 
 #else
 
@@ -438,8 +484,10 @@ void cv::setNumThreads( int threads )
 int cv::getThreadNum(void)
 {
 #if defined HAVE_TBB
-    #if TBB_INTERFACE_VERSION >= 6100 && defined TBB_PREVIEW_TASK_ARENA && TBB_PREVIEW_TASK_ARENA
-        return tbb::task_arena::current_slot();
+    #if TBB_INTERFACE_VERSION >= 9100
+        return tbb::this_task_arena::current_thread_index();
+    #elif TBB_INTERFACE_VERSION >= 8000
+        return tbb::task_arena::current_thread_index();
     #else
         return 0;
     #endif
@@ -504,7 +552,7 @@ int cv::getNumberOfCPUs(void)
 {
 #if defined WIN32 || defined _WIN32
     SYSTEM_INFO sysinfo;
-#if defined(_M_ARM) || defined(_M_X64) || defined(WINRT)
+#if (defined(_M_ARM) || defined(_M_X64) || defined(WINRT)) && _WIN32_WINNT >= 0x501
     GetNativeSystemInfo( &sysinfo );
 #else
     GetSystemInfo( &sysinfo );
diff --git a/modules/core/src/pca.cpp b/modules/core/src/pca.cpp
index 85ba443..0fa4700 100644
--- a/modules/core/src/pca.cpp
+++ b/modules/core/src/pca.cpp
@@ -158,15 +158,14 @@ void PCA::write(FileStorage& fs ) const
     fs << "mean" << mean;
 }
 
-void PCA::read(const FileNode& fs)
+void PCA::read(const FileNode& fn)
 {
-    CV_Assert( !fs.empty() );
-    String name = (String)fs["name"];
-    CV_Assert( name == "PCA" );
+    CV_Assert( !fn.empty() );
+    CV_Assert( (String)fn["name"] == "PCA" );
 
-    cv::read(fs["vectors"], eigenvectors);
-    cv::read(fs["values"], eigenvalues);
-    cv::read(fs["mean"], mean);
+    cv::read(fn["vectors"], eigenvectors);
+    cv::read(fn["values"], eigenvalues);
+    cv::read(fn["mean"], mean);
 }
 
 template <typename T>
@@ -352,6 +351,8 @@ Mat PCA::backProject(InputArray data) const
 void cv::PCACompute(InputArray data, InputOutputArray mean,
                     OutputArray eigenvectors, int maxComponents)
 {
+    CV_INSTRUMENT_REGION()
+
     PCA pca;
     pca(data, mean, 0, maxComponents);
     pca.mean.copyTo(mean);
@@ -361,6 +362,8 @@ void cv::PCACompute(InputArray data, InputOutputArray mean,
 void cv::PCACompute(InputArray data, InputOutputArray mean,
                     OutputArray eigenvectors, double retainedVariance)
 {
+    CV_INSTRUMENT_REGION()
+
     PCA pca;
     pca(data, mean, 0, retainedVariance);
     pca.mean.copyTo(mean);
@@ -370,6 +373,8 @@ void cv::PCACompute(InputArray data, InputOutputArray mean,
 void cv::PCAProject(InputArray data, InputArray mean,
                     InputArray eigenvectors, OutputArray result)
 {
+    CV_INSTRUMENT_REGION()
+
     PCA pca;
     pca.mean = mean.getMat();
     pca.eigenvectors = eigenvectors.getMat();
@@ -379,6 +384,8 @@ void cv::PCAProject(InputArray data, InputArray mean,
 void cv::PCABackProject(InputArray data, InputArray mean,
                     InputArray eigenvectors, OutputArray result)
 {
+    CV_INSTRUMENT_REGION()
+
     PCA pca;
     pca.mean = mean.getMat();
     pca.eigenvectors = eigenvectors.getMat();
diff --git a/modules/core/src/persistence.cpp b/modules/core/src/persistence.cpp
index 9c7b0f2..ccdb135 100644
--- a/modules/core/src/persistence.cpp
+++ b/modules/core/src/persistence.cpp
@@ -44,6 +44,8 @@
 
 #include <ctype.h>
 #include <deque>
+#include <sstream>
+#include <string>
 #include <iterator>
 
 #define USE_ZLIB 1
@@ -94,6 +96,15 @@ static inline bool cv_isspace(char c)
     return (9 <= c && c <= 13) || c == ' ';
 }
 
+static inline char* cv_skip_BOM(char* ptr)
+{
+    if((uchar)ptr[0] == 0xef && (uchar)ptr[1] == 0xbb && (uchar)ptr[2] == 0xbf) //UTF-8 BOM
+    {
+      return ptr + 3;
+    }
+    return ptr;
+}
+
 static char* icv_itoa( int _val, char* buffer, int /*radix*/ )
 {
     const int radix = 10;
@@ -115,6 +126,25 @@ static char* icv_itoa( int _val, char* buffer, int /*radix*/ )
     return ptr;
 }
 
+static inline bool cv_strcasecmp(const char * s1, const char * s2)
+{
+    if ( s1 == 0 && s2 == 0 )
+        return true;
+    else if ( s1 == 0 || s2 == 0 )
+        return false;
+
+    size_t len1 = strlen(s1);
+    size_t len2 = strlen(s2);
+    if ( len1 != len2 )
+        return false;
+
+    for ( size_t i = 0U; i < len1; i++ )
+        if ( tolower( static_cast<int>(s1[i]) ) != tolower( static_cast<int>(s2[i]) ) )
+            return false;
+
+    return true;
+}
+
 cv::String cv::FileStorage::getDefaultObjectName(const cv::String& _filename)
 {
     static const char* stubname = "unnamed";
@@ -181,6 +211,21 @@ typedef struct CvXMLStackRecord
 }
 CvXMLStackRecord;
 
+namespace base64
+{
+    class Base64Writer;
+
+    namespace fs
+    {
+        enum State
+        {
+            Uncertain,
+            NotUse,
+            InUse,
+        };
+    }
+}
+
 #define CV_XML_OPENING_TAG 1
 #define CV_XML_CLOSING_TAG 2
 #define CV_XML_EMPTY_TAG 3
@@ -238,10 +283,116 @@ typedef struct CvFileStorage
     size_t strbufsize, strbufpos;
     std::deque<char>* outbuf;
 
+    base64::Base64Writer * base64_writer;
+    bool is_default_using_base64;
+    base64::fs::State state_of_writing_base64;  /**< used in WriteRawData only */
+
+    bool is_write_struct_delayed;
+    char* delayed_struct_key;
+    int   delayed_struct_flags;
+    char* delayed_type_name;
+
     bool is_opened;
 }
 CvFileStorage;
 
+namespace base64
+{
+    static const size_t HEADER_SIZE         = 24U;
+    static const size_t ENCODED_HEADER_SIZE = 32U;
+
+    /* base64 */
+
+    typedef uchar uint8_t;
+
+    extern uint8_t const base64_padding;
+    extern uint8_t const base64_mapping[65];
+    extern uint8_t const base64_demapping[127];
+
+    size_t base64_encode(uint8_t const * src, uint8_t * dst, size_t off,      size_t cnt);
+    size_t base64_encode(   char const * src,    char * dst, size_t off = 0U, size_t cnt = 0U);
+
+    size_t base64_decode(uint8_t const * src, uint8_t * dst, size_t off,      size_t cnt);
+    size_t base64_decode(   char const * src,    char * dst, size_t off = 0U, size_t cnt = 0U);
+
+    bool   base64_valid (uint8_t const * src, size_t off,      size_t cnt);
+    bool   base64_valid (   char const * src, size_t off = 0U, size_t cnt = 0U);
+
+    size_t base64_encode_buffer_size(size_t cnt, bool is_end_with_zero = true);
+
+    size_t base64_decode_buffer_size(size_t cnt, bool is_end_with_zero = true);
+    size_t base64_decode_buffer_size(size_t cnt, char  const * src, bool is_end_with_zero = true);
+    size_t base64_decode_buffer_size(size_t cnt, uchar const * src, bool is_end_with_zero = true);
+
+    /* binary */
+
+    template<typename _uint_t>      inline size_t to_binary(_uint_t       val, uchar * cur);
+    template<>                      inline size_t to_binary(double        val, uchar * cur);
+    template<>                      inline size_t to_binary(float         val, uchar * cur);
+    template<typename _primitive_t> inline size_t to_binary(uchar const * val, uchar * cur);
+
+    template<typename _uint_t>      inline size_t binary_to(uchar const * cur, _uint_t & val);
+    template<>                      inline size_t binary_to(uchar const * cur, double  & val);
+    template<>                      inline size_t binary_to(uchar const * cur, float   & val);
+    template<typename _primitive_t> inline size_t binary_to(uchar const * cur, uchar   * val);
+
+    class RawDataToBinaryConvertor;
+
+    class BinaryToCvSeqConvertor;
+
+    /* class */
+
+    class Base64ContextParser
+    {
+    public:
+        explicit Base64ContextParser(uchar * buffer, size_t size);
+        ~Base64ContextParser();
+        Base64ContextParser & read(const uchar * beg, const uchar * end);
+        bool flush();
+    private:
+        static const size_t BUFFER_LEN = 120U;
+        uchar * dst_cur;
+        uchar * dst_end;
+        std::vector<uchar> base64_buffer;
+        uchar * src_beg;
+        uchar * src_cur;
+        uchar * src_end;
+        std::vector<uchar> binary_buffer;
+    };
+
+    class Base64ContextEmitter;
+
+    class Base64Writer
+    {
+    public:
+        Base64Writer(::CvFileStorage * fs);
+        ~Base64Writer();
+        void write(const void* _data, size_t len, const char* dt);
+        template<typename _to_binary_convertor_t> void write(_to_binary_convertor_t & convertor, const char* dt);
+
+    private:
+        void check_dt(const char* dt);
+
+    private:
+
+        Base64ContextEmitter * emitter;
+        std::string data_type_string;
+    };
+
+    /* other */
+
+    std::string make_base64_header(const char * dt);
+
+    bool read_base64_header(std::vector<char> const & header, std::string & dt);
+
+    void make_seq(void * binary_data, int elem_cnt, const char * dt, CvSeq & seq);
+
+    /* sample */
+
+    void cvWriteRawDataBase64(::CvFileStorage* fs, const void* _data, int len, const char* dt);
+}
+
+
 static void icvPuts( CvFileStorage* fs, const char* str )
 {
     if( fs->outbuf )
@@ -498,8 +649,7 @@ icvFSFlush( CvFileStorage* fs )
 
     if( fs->space != indent )
     {
-        if( fs->space < indent )
-            memset( fs->buffer_start + fs->space, ' ', indent - fs->space );
+        memset( fs->buffer_start, ' ', indent );
         fs->space = indent;
     }
 
@@ -530,6 +680,8 @@ icvClose( CvFileStorage* fs, cv::String* out )
             icvFSFlush(fs);
             if( fs->fmt == CV_STORAGE_FORMAT_XML )
                 icvPuts( fs, "</opencv_storage>\n" );
+            else if ( fs->fmt == CV_STORAGE_FORMAT_JSON )
+                icvPuts( fs, "}\n" );
         }
 
         icvCloseFile(fs);
@@ -560,8 +712,10 @@ cvReleaseFileStorage( CvFileStorage** p_fs )
         cvFree( &fs->buffer_start );
         cvReleaseMemStorage( &fs->memstorage );
 
-        if( fs->outbuf )
-            delete fs->outbuf;
+        delete fs->outbuf;
+        delete fs->base64_writer;
+        delete[] fs->delayed_struct_key;
+        delete[] fs->delayed_type_name;
 
         memset( fs, 0, sizeof(*fs) );
         cvFree( &fs );
@@ -941,6 +1095,185 @@ static double icv_strtod( CvFileStorage* fs, char* ptr, char** endptr )
     return fval;
 }
 
+// this function will convert "aa?bb&cc&dd" to {"aa", "bb", "cc", "dd"}
+static std::vector<std::string> analyze_file_name( std::string const & file_name )
+{
+    static const char not_file_name       = '\n';
+    static const char parameter_begin     = '?';
+    static const char parameter_separator = '&';
+    std::vector<std::string> result;
+
+    if ( file_name.find(not_file_name, 0U) != std::string::npos )
+        return result;
+
+    size_t beg = file_name.find_last_of(parameter_begin);
+    size_t end = file_name.size();
+    result.push_back(file_name.substr(0U, beg));
+
+    if ( beg != std::string::npos )
+    {
+        beg ++;
+        for ( size_t param_beg = beg, param_end = beg;
+              param_end < end;
+              param_beg = param_end + 1U )
+        {
+            param_end = file_name.find_first_of( parameter_separator, param_beg );
+            if ( (param_end == std::string::npos || param_end != param_beg) && param_beg + 1U < end )
+            {
+                result.push_back( file_name.substr( param_beg, param_end - param_beg ) );
+            }
+        }
+    }
+
+    return result;
+}
+
+static bool is_param_exist( const std::vector<std::string> & params, const std::string & param )
+{
+    if ( params.size() < 2U )
+        return false;
+
+    return std::find(params.begin(), params.end(), param) != params.end();
+}
+
+static void switch_to_Base64_state( CvFileStorage* fs, base64::fs::State state )
+{
+    const char * err_unkonwn_state = "Unexpected error, unable to determine the Base64 state.";
+    const char * err_unable_to_switch = "Unexpected error, unable to switch to this state.";
+
+    /* like a finite state machine */
+    switch (fs->state_of_writing_base64)
+    {
+    case base64::fs::Uncertain:
+        switch (state)
+        {
+        case base64::fs::InUse:
+            CV_DbgAssert( fs->base64_writer == 0 );
+            fs->base64_writer = new base64::Base64Writer( fs );
+            break;
+        case base64::fs::Uncertain:
+            break;
+        case base64::fs::NotUse:
+            break;
+        default:
+            CV_Error( CV_StsError, err_unkonwn_state );
+            break;
+        }
+        break;
+    case base64::fs::InUse:
+        switch (state)
+        {
+        case base64::fs::InUse:
+        case base64::fs::NotUse:
+            CV_Error( CV_StsError, err_unable_to_switch );
+            break;
+        case base64::fs::Uncertain:
+            delete fs->base64_writer;
+            fs->base64_writer = 0;
+            break;
+        default:
+            CV_Error( CV_StsError, err_unkonwn_state );
+            break;
+        }
+        break;
+    case base64::fs::NotUse:
+        switch (state)
+        {
+        case base64::fs::InUse:
+        case base64::fs::NotUse:
+            CV_Error( CV_StsError, err_unable_to_switch );
+            break;
+        case base64::fs::Uncertain:
+            break;
+        default:
+            CV_Error( CV_StsError, err_unkonwn_state );
+            break;
+        }
+        break;
+    default:
+        CV_Error( CV_StsError, err_unkonwn_state );
+        break;
+    }
+
+    fs->state_of_writing_base64 = state;
+}
+
+
+static void check_if_write_struct_is_delayed( CvFileStorage* fs, bool change_type_to_base64 = false )
+{
+    if ( fs->is_write_struct_delayed )
+    {
+        /* save data to prevent recursive call errors */
+        std::string struct_key;
+        std::string type_name;
+        int struct_flags = fs->delayed_struct_flags;
+
+        if ( fs->delayed_struct_key != 0 && *fs->delayed_struct_key != '\0' )
+        {
+            struct_key.assign(fs->delayed_struct_key);
+        }
+        if ( fs->delayed_type_name != 0 && *fs->delayed_type_name != '\0' )
+        {
+            type_name.assign(fs->delayed_type_name);
+        }
+
+        /* reset */
+        delete[] fs->delayed_struct_key;
+        delete[] fs->delayed_type_name;
+        fs->delayed_struct_key   = 0;
+        fs->delayed_struct_flags = 0;
+        fs->delayed_type_name    = 0;
+
+        fs->is_write_struct_delayed = false;
+
+        /* call */
+        if ( change_type_to_base64 )
+        {
+            fs->start_write_struct( fs, struct_key.c_str(), struct_flags, "binary");
+            if ( fs->state_of_writing_base64 != base64::fs::Uncertain )
+                switch_to_Base64_state( fs, base64::fs::Uncertain );
+            switch_to_Base64_state( fs, base64::fs::InUse );
+        }
+        else
+        {
+            fs->start_write_struct( fs, struct_key.c_str(), struct_flags, type_name.c_str());
+            if ( fs->state_of_writing_base64 != base64::fs::Uncertain )
+                switch_to_Base64_state( fs, base64::fs::Uncertain );
+            switch_to_Base64_state( fs, base64::fs::NotUse );
+        }
+    }
+}
+
+
+static void make_write_struct_delayed(
+    CvFileStorage* fs,
+    const char* key,
+    int struct_flags,
+    const char* type_name )
+{
+    CV_Assert( fs->is_write_struct_delayed == false );
+    CV_DbgAssert( fs->delayed_struct_key   == 0 );
+    CV_DbgAssert( fs->delayed_struct_flags == 0 );
+    CV_DbgAssert( fs->delayed_type_name    == 0 );
+
+    fs->delayed_struct_flags = struct_flags;
+
+    if ( key != 0 )
+    {
+        fs->delayed_struct_key = new char[strlen(key) + 1U];
+        strcpy(fs->delayed_struct_key, key);
+    }
+
+    if ( type_name != 0 )
+    {
+        fs->delayed_type_name = new char[strlen(type_name) + 1U];
+        strcpy(fs->delayed_type_name, type_name);
+    }
+
+    fs->is_write_struct_delayed = true;
+}
+
+static const size_t PARSER_BASE64_BUFFER_SIZE = 1024U * 1024U / 8U;
 
 /****************************************************************************************\
 *                                       YAML Parser                                      *
@@ -995,6 +1328,99 @@ icvYMLSkipSpaces( CvFileStorage* fs, char* ptr, int min_indent, int max_comment_
 }
 
 
+static void icvYMLGetMultilineStringContent(CvFileStorage* fs,
+    char* ptr, int indent, char* &beg, char* &end)
+{
+    ptr = icvYMLSkipSpaces(fs, ptr, 0, INT_MAX);
+    beg = ptr;
+    end = ptr;
+    if (fs->dummy_eof)
+        return ; /* end of file */
+
+    if (ptr - fs->buffer_start != indent)
+        return ; /* end of string */
+
+    /* find end */
+    while(cv_isprint(*ptr)) /* no check for base64 string */
+        ++ ptr;
+    if (*ptr == '\0')
+        CV_PARSE_ERROR("Unexpected end of line");
+
+    end = ptr;
+}
+
+static int icvCalcStructSize( const char* dt, int initial_size );
+
+static char* icvYMLParseBase64(CvFileStorage* fs, char* ptr, int indent, CvFileNode * node)
+{
+    char * beg = 0;
+    char * end = 0;
+
+    icvYMLGetMultilineStringContent(fs, ptr, indent, beg, end);
+    if (beg >= end)
+        return end; // CV_PARSE_ERROR("Empty Binary Data");
+
+    /* calc (decoded) total_byte_size from header */
+    std::string dt;
+    {
+        if (end - beg < static_cast<int>(base64::ENCODED_HEADER_SIZE))
+            CV_PARSE_ERROR("Unrecognized Base64 header");
+
+        std::vector<char> header(base64::HEADER_SIZE + 1, ' ');
+        base64::base64_decode(beg, header.data(), 0U, base64::ENCODED_HEADER_SIZE);
+        if ( !base64::read_base64_header(header, dt) || dt.empty() )
+            CV_PARSE_ERROR("Invalid `dt` in Base64 header");
+
+        beg += base64::ENCODED_HEADER_SIZE;
+    }
+
+    /* get all Base64 data */
+    std::string base64_buffer;
+    base64_buffer.reserve( PARSER_BASE64_BUFFER_SIZE );
+    while( beg < end )
+    {
+        base64_buffer.append( beg, end );
+        beg = end;
+        icvYMLGetMultilineStringContent( fs, beg, indent, beg, end );
+    }
+    if ( !base64::base64_valid(base64_buffer.data(), 0U, base64_buffer.size()) )
+        CV_PARSE_ERROR( "Invalid Base64 data." );
+
+    /* buffer for decoded data(exclude header) */
+    std::vector<uchar> binary_buffer( base64::base64_decode_buffer_size(base64_buffer.size()) );
+    int total_byte_size = static_cast<int>(
+        base64::base64_decode_buffer_size( base64_buffer.size(), base64_buffer.data(), false )
+        );
+    {
+        base64::Base64ContextParser parser(binary_buffer.data(), binary_buffer.size() );
+        const uchar * buffer_beg = reinterpret_cast<const uchar *>( base64_buffer.data() );
+        const uchar * buffer_end = buffer_beg + base64_buffer.size();
+        parser.read( buffer_beg, buffer_end );
+        parser.flush();
+    }
+
+    /* save as CvSeq */
+    int elem_size = ::icvCalcStructSize(dt.c_str(), 0);
+    if (total_byte_size % elem_size != 0)
+        CV_PARSE_ERROR("Byte size not match elememt size");
+    int elem_cnt = total_byte_size / elem_size;
+
+    node->tag = CV_NODE_NONE;
+    int struct_flags = CV_NODE_FLOW | CV_NODE_SEQ;
+    /* after icvFSCreateCollection, node->tag == struct_flags */
+    icvFSCreateCollection(fs, struct_flags, node);
+    base64::make_seq(binary_buffer.data(), elem_cnt, dt.c_str(), *node->data.seq);
+
+    if (fs->dummy_eof) {
+        /* end of file */
+        return fs->buffer_start;
+    } else {
+        /* end of line */
+        return end;
+    }
+}
+
+
 static char*
 icvYMLParseKey( CvFileStorage* fs, char* ptr,
                 CvFileNode* map_node, CvFileNode** value_placeholder )
@@ -1038,6 +1464,7 @@ icvYMLParseValue( CvFileStorage* fs, char* ptr, CvFileNode* node,
     int is_parent_flow = CV_NODE_IS_FLOW(parent_flags);
     int value_type = CV_NODE_NONE;
     int len;
+    bool is_binary_string = false;
 
     memset( node, 0, sizeof(*node) );
 
@@ -1074,6 +1501,27 @@ icvYMLParseValue( CvFileStorage* fs, char* ptr, CvFileNode* node,
             if( memcmp( ptr, "float", 5 ) == 0 )
                 value_type = CV_NODE_REAL;
         }
+        else if (len == 6 && CV_NODE_IS_USER(value_type))
+        {
+            if( memcmp( ptr, "binary", 6 ) == 0 ) {
+                value_type = CV_NODE_SEQ;
+                is_binary_string = true;
+
+                /* for ignore '|' */
+
+                /**** operation with endptr ****/
+                *endptr = d;
+
+                do {
+                    d = *++endptr;
+                    if (d == '|')
+                        break;
+                } while (d == ' ');
+
+                d = *++endptr;
+                *endptr = '\0';
+            }
+        }
         else if( CV_NODE_IS_USER(value_type) )
         {
             node->info = cvFindType( ptr );
@@ -1088,7 +1536,7 @@ icvYMLParseValue( CvFileStorage* fs, char* ptr, CvFileNode* node,
 
         if( !CV_NODE_IS_USER(value_type) )
         {
-            if( value_type == CV_NODE_STRING && c != '\'' && c != '\"' )
+            if (value_type == CV_NODE_STRING && c != '\'' && c != '\"')
                 goto force_string;
             if( value_type == CV_NODE_INT )
                 goto force_int;
@@ -1097,7 +1545,13 @@ icvYMLParseValue( CvFileStorage* fs, char* ptr, CvFileNode* node,
         }
     }
 
-    if( cv_isdigit(c) ||
+    if (is_binary_string)
+    {
+        /* for base64 string */
+        int indent = static_cast<int>(ptr - fs->buffer_start);
+        ptr = icvYMLParseBase64(fs, ptr, indent, node);
+    }
+    else if( cv_isdigit(c) ||
         ((c == '-' || c == '+') && (cv_isdigit(d) || d == '.')) ||
         (c == '.' && cv_isalnum(d))) // a number
     {
@@ -1355,8 +1809,9 @@ icvYMLParse( CvFileStorage* fs )
 
             if( *ptr == '%' )
             {
-                if( memcmp( ptr, "%YAML:", 6 ) == 0 &&
-                    memcmp( ptr, "%YAML:1.", 8 ) != 0 )
+                if( memcmp( ptr, "%YAML", 5 ) == 0 &&
+                    memcmp( ptr, "%YAML:1.", 8 ) != 0 &&
+                    memcmp( ptr, "%YAML 1.", 8 ) != 0)
                     CV_PARSE_ERROR( "Unsupported YAML version (it must be 1.x)" );
                 *ptr = '\0';
             }
@@ -1413,6 +1868,16 @@ icvYMLParse( CvFileStorage* fs )
 static void
 icvYMLWrite( CvFileStorage* fs, const char* key, const char* data )
 {
+    check_if_write_struct_is_delayed( fs );
+    if ( fs->state_of_writing_base64 == base64::fs::Uncertain )
+    {
+        switch_to_Base64_state( fs, base64::fs::NotUse );
+    }
+    else if ( fs->state_of_writing_base64 == base64::fs::InUse )
+    {
+        CV_Error( CV_StsError, "At present, output Base64 data only." );
+    }
+
     int i, keylen = 0;
     int datalen = 0;
     int struct_flags;
@@ -1516,12 +1981,22 @@ icvYMLStartWriteStruct( CvFileStorage* fs, const char* key, int struct_flags,
     char buf[CV_FS_MAX_LEN + 1024];
     const char* data = 0;
 
+    if ( type_name && *type_name == '\0' )
+        type_name = 0;
+
     struct_flags = (struct_flags & (CV_NODE_TYPE_MASK|CV_NODE_FLOW)) | CV_NODE_EMPTY;
     if( !CV_NODE_IS_COLLECTION(struct_flags))
         CV_Error( CV_StsBadArg,
         "Some collection type - CV_NODE_SEQ or CV_NODE_MAP, must be specified" );
 
-    if( CV_NODE_IS_FLOW(struct_flags) )
+    if (type_name && memcmp(type_name, "binary", 6) == 0)
+    {
+        /* reset struct flag. in order not to print ']' */
+        struct_flags = CV_NODE_SEQ;
+        sprintf(buf, "!!binary |");
+        data = buf;
+    }
+    else if( CV_NODE_IS_FLOW(struct_flags))
     {
         char c = CV_NODE_IS_MAP(struct_flags) ? '{' : '[';
         struct_flags |= CV_NODE_FLOW;
@@ -1637,7 +2112,7 @@ icvYMLWriteString( CvFileStorage* fs, const char* key,
 
     if( quote || len == 0 || str[0] != str[len-1] || (str[0] != '\"' && str[0] != '\'') )
     {
-        int need_quote = quote || len == 0;
+        int need_quote = quote || len == 0 || str[0] == ' ';
         data = buf;
         *data++ = '\"';
         for( i = 0; i < len; i++ )
@@ -1813,6 +2288,98 @@ icvXMLSkipSpaces( CvFileStorage* fs, char* ptr, int mode )
 }
 
 
+static void icvXMLGetMultilineStringContent(CvFileStorage* fs,
+    char* ptr, char* &beg, char* &end)
+{
+    ptr = icvXMLSkipSpaces(fs, ptr, CV_XML_INSIDE_TAG);
+    beg = ptr;
+    end = ptr;
+    if ( fs->dummy_eof )
+        return ; /* end of file */
+
+    if ( *beg == '<' )
+        return; /* end of string */
+
+    /* find end */
+    while( cv_isprint(*ptr) ) /* no check for base64 string */
+        ++ ptr;
+    if ( *ptr == '\0' )
+        CV_PARSE_ERROR( "Unexpected end of line" );
+
+    end = ptr;
+}
+
+
+static char* icvXMLParseBase64(CvFileStorage* fs, char* ptr, CvFileNode * node)
+{
+    char * beg = 0;
+    char * end = 0;
+
+    icvXMLGetMultilineStringContent(fs, ptr, beg, end);
+    if (beg >= end)
+        return end; // CV_PARSE_ERROR("Empty Binary Data");
+
+    /* calc (decoded) total_byte_size from header */
+    std::string dt;
+    {
+        if (end - beg < static_cast<int>(base64::ENCODED_HEADER_SIZE))
+            CV_PARSE_ERROR("Unrecognized Base64 header");
+
+        std::vector<char> header(base64::HEADER_SIZE + 1, ' ');
+        base64::base64_decode(beg, header.data(), 0U, base64::ENCODED_HEADER_SIZE);
+        if ( !base64::read_base64_header(header, dt) || dt.empty() )
+            CV_PARSE_ERROR("Invalid `dt` in Base64 header");
+
+        beg += base64::ENCODED_HEADER_SIZE;
+    }
+
+    /* get all Base64 data */
+    std::string base64_buffer; // not an efficient way.
+    base64_buffer.reserve( PARSER_BASE64_BUFFER_SIZE );
+    while( beg < end )
+    {
+        base64_buffer.append( beg, end );
+        beg = end;
+        icvXMLGetMultilineStringContent( fs, beg, beg, end );
+    }
+    if ( !base64::base64_valid(base64_buffer.data(), 0U, base64_buffer.size()) )
+        CV_PARSE_ERROR( "Invalid Base64 data." );
+
+    /* alloc buffer for all decoded data(include header) */
+    std::vector<uchar> binary_buffer( base64::base64_decode_buffer_size(base64_buffer.size()) );
+    int total_byte_size = static_cast<int>(
+        base64::base64_decode_buffer_size( base64_buffer.size(), base64_buffer.data(), false )
+        );
+    {
+        base64::Base64ContextParser parser(binary_buffer.data(), binary_buffer.size() );
+        const uchar * buffer_beg = reinterpret_cast<const uchar *>( base64_buffer.data() );
+        const uchar * buffer_end = buffer_beg + base64_buffer.size();
+        parser.read( buffer_beg, buffer_end );
+        parser.flush();
+    }
+
+    /* save as CvSeq */
+    int elem_size = ::icvCalcStructSize(dt.c_str(), 0);
+    if (total_byte_size % elem_size != 0)
+        CV_PARSE_ERROR("data size not matches elememt size");
+    int elem_cnt = total_byte_size / elem_size;
+
+    node->tag = CV_NODE_NONE;
+    int struct_flags = CV_NODE_SEQ;
+    /* after icvFSCreateCollection, node->tag == struct_flags */
+    icvFSCreateCollection(fs, struct_flags, node);
+    base64::make_seq(binary_buffer.data(), elem_cnt, dt.c_str(), *node->data.seq);
+
+    if (fs->dummy_eof) {
+        /* end of file */
+        return fs->buffer_start;
+    } else {
+        /* end of line */
+        return end;
+    }
+}
+
+
 static char*
 icvXMLParseTag( CvFileStorage* fs, char* ptr, CvStringHashNode** _tag,
                 CvAttrList** _list, int* _tag_type );
@@ -1864,6 +2431,9 @@ icvXMLParseValue( CvFileStorage* fs, char* ptr, CvFileNode* node,
 
             assert( tag_type == CV_XML_OPENING_TAG );
 
+            /* for base64 string */
+            bool is_binary_string = false;
+
             type_name = list ? cvAttrValue( list, "type_id" ) : 0;
             if( type_name )
             {
@@ -1873,6 +2443,11 @@ icvXMLParseValue( CvFileStorage* fs, char* ptr, CvFileNode* node,
                     elem_type = CV_NODE_MAP;
                 else if( strcmp( type_name, "seq" ) == 0 )
                     elem_type = CV_NODE_SEQ;
+                else if (strcmp(type_name, "binary") == 0)
+                {
+                    elem_type = CV_NODE_NONE;
+                    is_binary_string = true;
+                }
                 else
                 {
                     info = cvFindType( type_name );
@@ -1895,7 +2470,14 @@ icvXMLParseValue( CvFileStorage* fs, char* ptr, CvFileNode* node,
             else
                 elem = cvGetFileNode( fs, node, key, 1 );
 
-            ptr = icvXMLParseValue( fs, ptr, elem, elem_type);
+            if (!is_binary_string)
+                ptr = icvXMLParseValue( fs, ptr, elem, elem_type);
+            else {
+                /* for base64 string */
+                ptr = icvXMLParseBase64( fs, ptr, elem);
+                ptr = icvXMLSkipSpaces( fs, ptr, 0 );
+            }
+
             if( !is_noname )
                 elem->tag |= CV_NODE_NAMED;
             is_simple &= !CV_NODE_IS_COLLECTION(elem->tag);
@@ -2367,6 +2949,9 @@ icvXMLStartWriteStruct( CvFileStorage* fs, const char* key, int struct_flags,
         CV_Error( CV_StsBadArg,
         "Some collection type: CV_NODE_SEQ or CV_NODE_MAP must be specified" );
 
+    if ( type_name && *type_name == '\0' )
+        type_name = 0;
+
     if( type_name )
     {
         attr[idx++] = "type_id";
@@ -2441,6 +3026,16 @@ icvXMLStartNextStream( CvFileStorage* fs )
 static void
 icvXMLWriteScalar( CvFileStorage* fs, const char* key, const char* data, int len )
 {
+    check_if_write_struct_is_delayed( fs );
+    if ( fs->state_of_writing_base64 == base64::fs::Uncertain )
+    {
+        switch_to_Base64_state( fs, base64::fs::NotUse );
+    }
+    else if ( fs->state_of_writing_base64 == base64::fs::InUse )
+    {
+        CV_Error( CV_StsError, "Currently only Base64 data is allowed." );
+    }
+
     if( CV_NODE_IS_MAP(fs->struct_flags) ||
         (!CV_NODE_IS_COLLECTION(fs->struct_flags) && key) )
     {
@@ -2644,3021 +3239,5043 @@ icvXMLWriteComment( CvFileStorage* fs, const char* comment, int eol_comment )
 
 
 /****************************************************************************************\
-*                              Common High-Level Functions                               *
+*                                       JSON Parser                                      *
 \****************************************************************************************/
 
-CV_IMPL CvFileStorage*
-cvOpenFileStorage( const char* filename, CvMemStorage* dststorage, int flags, const char* encoding )
+static char*
+icvJSONSkipSpaces( CvFileStorage* fs, char* ptr )
 {
-    CvFileStorage* fs = 0;
-    int default_block_size = 1 << 18;
-    bool append = (flags & 3) == CV_STORAGE_APPEND;
-    bool mem = (flags & CV_STORAGE_MEMORY) != 0;
-    bool write_mode = (flags & 3) != 0;
-    bool isGZ = false;
-    size_t fnamelen = 0;
-
-    if( !filename || filename[0] == '\0' )
-    {
-        if( !write_mode )
-            CV_Error( CV_StsNullPtr, mem ? "NULL or empty filename" : "NULL or empty buffer" );
-        mem = true;
-    }
-    else
-        fnamelen = strlen(filename);
-
-    if( mem && append )
-        CV_Error( CV_StsBadFlag, "CV_STORAGE_APPEND and CV_STORAGE_MEMORY are not currently compatible" );
+    bool is_eof = false;
+    bool is_completed = false;
 
-    fs = (CvFileStorage*)cvAlloc( sizeof(*fs) );
-    memset( fs, 0, sizeof(*fs));
-
-    fs->memstorage = cvCreateMemStorage( default_block_size );
-    fs->dststorage = dststorage ? dststorage : fs->memstorage;
-
-    fs->flags = CV_FILE_STORAGE;
-    fs->write_mode = write_mode;
-
-    if( !mem )
+    while ( is_eof == false && is_completed == false )
     {
-        fs->filename = (char*)cvMemStorageAlloc( fs->memstorage, fnamelen+1 );
-        strcpy( fs->filename, filename );
+        switch ( *ptr )
+        {
+        /* comment */
+        case '/' : {
+            ptr++;
+            if ( *ptr == '\0' )
+            {
+                ptr = icvGets( fs, fs->buffer_start, static_cast<int>(fs->buffer_end - fs->buffer_start) );
+                if ( !ptr ) { is_eof = true; break; }
+            }
 
-        char* dot_pos = strrchr(fs->filename, '.');
-        char compression = '\0';
-
-        if( dot_pos && dot_pos[1] == 'g' && dot_pos[2] == 'z' &&
-            (dot_pos[3] == '\0' || (cv_isdigit(dot_pos[3]) && dot_pos[4] == '\0')) )
-        {
-            if( append )
+            if ( *ptr == '/' )
             {
-                cvReleaseFileStorage( &fs );
-                CV_Error(CV_StsNotImplemented, "Appending data to compressed file is not implemented" );
+                while ( *ptr != '\n' && *ptr != '\r' )
+                {
+                    if ( *ptr == '\0' )
+                    {
+                        ptr = icvGets( fs, fs->buffer_start, static_cast<int>(fs->buffer_end - fs->buffer_start) );
+                        if ( !ptr ) { is_eof = true; break; }
+                    }
+                    else
+                    {
+                        ptr++;
+                    }
+                }
             }
-            isGZ = true;
-            compression = dot_pos[3];
-            if( compression )
-                dot_pos[3] = '\0', fnamelen--;
+            else if ( *ptr == '*' )
+            {
+                ptr++;
+                for (;;)
+                {
+                    if ( *ptr == '\0' )
+                    {
+                        ptr = icvGets( fs, fs->buffer_start, static_cast<int>(fs->buffer_end - fs->buffer_start) );
+                        if ( !ptr ) { is_eof = true; break; }
+                    }
+                    else if ( *ptr == '*' )
+                    {
+                        ptr++;
+                        if ( *ptr == '\0' )
+                        {
+                            ptr = icvGets( fs, fs->buffer_start, static_cast<int>(fs->buffer_end - fs->buffer_start) );
+                            if ( !ptr ) { is_eof = true; break; }
+                        }
+                        if ( *ptr == '/' )
+                        {
+                            ptr++;
+                            break;
+                        }
+                    }
+                    else
+                    {
+                        ptr++;
+                    }
+                }
+            }
+            else
+            {
+                CV_PARSE_ERROR( "Not supported escape character" );
+            }
+        } break;
+        /* whitespace */
+        case '\t':
+        case ' ' : {
+            ptr++;
+        } break;
+        /* newline || end mark */
+        case '\0':
+        case '\n':
+        case '\r': {
+            ptr = icvGets( fs, fs->buffer_start, static_cast<int>(fs->buffer_end - fs->buffer_start) );
+            if ( !ptr ) { is_eof = true; break; }
+        } break;
+        /* other character */
+        default: {
+            if ( !cv_isprint(*ptr) )
+                CV_PARSE_ERROR( "Invalid character in the stream" );
+            is_completed = true;
+        } break;
         }
+    }
 
-        if( !isGZ )
-        {
-            fs->file = fopen(fs->filename, !fs->write_mode ? "rt" : !append ? "wt" : "a+t" );
-            if( !fs->file )
-                goto _exit_;
-        }
-        else
-        {
-            #if USE_ZLIB
-            char mode[] = { fs->write_mode ? 'w' : 'r', 'b', compression ? compression : '3', '\0' };
-            fs->gzfile = gzopen(fs->filename, mode);
-            if( !fs->gzfile )
-                goto _exit_;
-            #else
-            cvReleaseFileStorage( &fs );
-            CV_Error(CV_StsNotImplemented, "There is no compressed file storage support in this configuration");
-            #endif
-        }
+    if ( is_eof )
+    {
+        ptr = fs->buffer_start;
+        *ptr = '\0';
+        fs->dummy_eof = 1;
+    }
+    else if ( !is_completed )
+    {
+        /* should not be executed */
+        ptr = 0;
+        fs->dummy_eof = 1;
+        CV_PARSE_ERROR( "Abort at parse time" );
     }
+    return ptr;
+}
 
-    fs->roots = 0;
-    fs->struct_indent = 0;
-    fs->struct_flags = 0;
-    fs->wrap_margin = 71;
 
-    if( fs->write_mode )
+static char* icvJSONParseKey( CvFileStorage* fs, char* ptr, CvFileNode* map, CvFileNode** value_placeholder )
+{
+    if( *ptr != '"' )
+        CV_PARSE_ERROR( "Key must start with \'\"\'" );
+
+    char * beg = ptr + 1;
+    char * end = beg;
+
+    do ++ptr;
+    while( cv_isprint(*ptr) && *ptr != '"' );
+
+    if( *ptr != '"' )
+        CV_PARSE_ERROR( "Key must end with \'\"\'" );
+
+    end = ptr;
+    ptr++;
+    ptr = icvJSONSkipSpaces( fs, ptr );
+    if ( ptr == 0 || fs->dummy_eof )
+        return 0;
+
+    if( *ptr != ':' )
+        CV_PARSE_ERROR( "Missing \':\' between key and value" );
+
+    /* [beg, end) */
+    if( end <= beg )
+        CV_PARSE_ERROR( "Key is empty" );
+
+    if ( end - beg == 7u && memcmp(beg, "type_id", 7u) == 0 )
     {
-        int fmt = flags & CV_STORAGE_FORMAT_MASK;
+        *value_placeholder = 0;
+    }
+    else
+    {
+        CvStringHashNode* str_hash_node = cvGetHashedKey( fs, beg, static_cast<int>(end - beg), 1 );
+        *value_placeholder = cvGetFileNode( fs, map, str_hash_node, 1 );
+    }
 
-        if( mem )
-            fs->outbuf = new std::deque<char>;
+    ptr++;
+    return ptr;
+}
 
-        if( fmt == CV_STORAGE_FORMAT_AUTO && filename )
-        {
-            const char* dot_pos = filename + fnamelen - (isGZ ? 7 : 4);
-            fs->fmt = (dot_pos >= filename && (memcmp( dot_pos, ".xml", 4) == 0 ||
-                    memcmp(dot_pos, ".XML", 4) == 0 || memcmp(dot_pos, ".Xml", 4) == 0)) ?
-                CV_STORAGE_FORMAT_XML : CV_STORAGE_FORMAT_YAML;
-        }
-        else
-            fs->fmt = fmt != CV_STORAGE_FORMAT_AUTO ? fmt : CV_STORAGE_FORMAT_XML;
+static char* icvJSONParseValue( CvFileStorage* fs, char* ptr, CvFileNode* node )
+{
+    ptr = icvJSONSkipSpaces( fs, ptr );
+    if ( ptr == 0 || fs->dummy_eof )
+        CV_PARSE_ERROR( "Unexpected End-Of-File" );
 
-        // we use factor=6 for XML (the longest characters (' and ") are encoded with 6 bytes (' and ")
-        // and factor=4 for YAML ( as we use 4 bytes for non ASCII characters (e.g. \xAB))
-        int buf_size = CV_FS_MAX_LEN*(fs->fmt == CV_STORAGE_FORMAT_XML ? 6 : 4) + 1024;
+    memset( node, 0, sizeof(*node) );
 
-        if( append )
-            fseek( fs->file, 0, SEEK_END );
+    if ( *ptr == '"' )
+    {   /* must be string or Base64 string */
+        ptr++;
+        char * beg = ptr;
+        size_t len = 0u;
+        for ( ; (cv_isalnum(*ptr) || *ptr == '$' ) && len <= 9u; ptr++ )
+            len++;
 
-        fs->write_stack = cvCreateSeq( 0, sizeof(CvSeq), fs->fmt == CV_STORAGE_FORMAT_XML ?
-                sizeof(CvXMLStackRecord) : sizeof(int), fs->memstorage );
-        fs->is_first = 1;
-        fs->struct_indent = 0;
-        fs->struct_flags = CV_NODE_EMPTY;
-        fs->buffer_start = fs->buffer = (char*)cvAlloc( buf_size + 1024 );
-        fs->buffer_end = fs->buffer_start + buf_size;
-        if( fs->fmt == CV_STORAGE_FORMAT_XML )
-        {
-            size_t file_size = fs->file ? (size_t)ftell( fs->file ) : (size_t)0;
-            fs->strstorage = cvCreateChildMemStorage( fs->memstorage );
-            if( !append || file_size == 0 )
+        if ( len >= 8u && memcmp( beg, "$base64$", 8u ) == 0 )
+        {   /**************** Base64 string ****************/
+            ptr = beg += 8;
+
+            std::string base64_buffer;
+            base64_buffer.reserve( PARSER_BASE64_BUFFER_SIZE );
+
+            bool is_matching = false;
+            while ( !is_matching )
             {
-                if( encoding )
+                switch ( *ptr )
                 {
-                    if( strcmp( encoding, "UTF-16" ) == 0 ||
-                        strcmp( encoding, "utf-16" ) == 0 ||
-                        strcmp( encoding, "Utf-16" ) == 0 )
+                case '\0':
+                {
+                    base64_buffer.append( beg, ptr );
+
+                    ptr = icvGets( fs, fs->buffer_start, static_cast<int>(fs->buffer_end - fs->buffer_start) );
+                    if ( !ptr )
+                        CV_PARSE_ERROR( "'\"' - right-quote of string is missing" );
+
+                    beg = ptr;
+                    break;
+                }
+                case '\"':
+                {
+                    base64_buffer.append( beg, ptr );
+                    beg = ptr;
+                    is_matching = true;
+                    break;
+                }
+                case '\n':
+                case '\r':
+                {
+                    CV_PARSE_ERROR( "'\"' - right-quote of string is missing" );
+                    break;
+                }
+                default:
+                {
+                    ptr++;
+                    break;
+                }
+                }
+            }
+
+            if ( *ptr != '\"' )
+                CV_PARSE_ERROR( "'\"' - right-quote of string is missing" );
+            else
+                ptr++;
+
+            if ( base64_buffer.size() >= base64::ENCODED_HEADER_SIZE )
+            {
+                const char * base64_beg = base64_buffer.data();
+                const char * base64_end = base64_beg + base64_buffer.size();
+
+                /* get dt from header */
+                std::string dt;
+                {
+                    std::vector<char> header(base64::HEADER_SIZE + 1, ' ');
+                    base64::base64_decode(base64_beg, header.data(), 0U, base64::ENCODED_HEADER_SIZE);
+                    if ( !base64::read_base64_header(header, dt) || dt.empty() )
+                        CV_PARSE_ERROR("Invalid `dt` in Base64 header");
+                }
+
+                /* set base64_beg to beginning of base64 data */
+                base64_beg = &base64_buffer.at( base64::ENCODED_HEADER_SIZE );
+
+                if ( base64_buffer.size() > base64::ENCODED_HEADER_SIZE )
+                {
+                    if ( !base64::base64_valid( base64_beg, 0U, base64_end - base64_beg ) )
+                        CV_PARSE_ERROR( "Invalid Base64 data." );
+
+                    /* buffer for decoded data(exclude header) */
+                    std::vector<uchar> binary_buffer( base64::base64_decode_buffer_size(base64_end - base64_beg) );
+                    int total_byte_size = static_cast<int>(
+                        base64::base64_decode_buffer_size( base64_end - base64_beg, base64_beg, false )
+                        );
                     {
-                        cvReleaseFileStorage( &fs );
-                        CV_Error( CV_StsBadArg, "UTF-16 XML encoding is not supported! Use 8-bit encoding\n");
+                        base64::Base64ContextParser parser(binary_buffer.data(), binary_buffer.size() );
+                        const uchar * binary_beg = reinterpret_cast<const uchar *>( base64_beg );
+                        const uchar * binary_end = binary_beg + (base64_end - base64_beg);
+                        parser.read( binary_beg, binary_end );
+                        parser.flush();
                     }
 
-                    CV_Assert( strlen(encoding) < 1000 );
-                    char buf[1100];
-                    sprintf(buf, "<?xml version=\"1.0\" encoding=\"%s\"?>\n", encoding);
-                    icvPuts( fs, buf );
+                    /* save as CvSeq */
+                    int elem_size = ::icvCalcStructSize(dt.c_str(), 0);
+                    if (total_byte_size % elem_size != 0)
+                        CV_PARSE_ERROR("Byte size not match elememt size");
+                    int elem_cnt = total_byte_size / elem_size;
+
+                    /* after icvFSCreateCollection, node->tag == struct_flags */
+                    icvFSCreateCollection(fs, CV_NODE_FLOW | CV_NODE_SEQ, node);
+                    base64::make_seq(binary_buffer.data(), elem_cnt, dt.c_str(), *node->data.seq);
                 }
                 else
-                    icvPuts( fs, "<?xml version=\"1.0\"?>\n" );
-                icvPuts( fs, "<opencv_storage>\n" );
+                {
+                    /* empty */
+                    icvFSCreateCollection(fs, CV_NODE_FLOW | CV_NODE_SEQ, node);
+                }
+            }
+            else if ( base64_buffer.empty() )
+            {
+                /* empty */
+                icvFSCreateCollection(fs, CV_NODE_FLOW | CV_NODE_SEQ, node);
             }
             else
             {
-                int xml_buf_size = 1 << 10;
-                char substr[] = "</opencv_storage>";
-                int last_occurence = -1;
-                xml_buf_size = MIN(xml_buf_size, int(file_size));
-                fseek( fs->file, -xml_buf_size, SEEK_END );
-                char* xml_buf = (char*)cvAlloc( xml_buf_size+2 );
-                // find the last occurence of </opencv_storage>
-                for(;;)
+                CV_PARSE_ERROR("Unrecognized Base64 header");
+            }
+        }
+        else
+        {   /**************** normal string ****************/
+            std::string string_buffer;
+            string_buffer.reserve( PARSER_BASE64_BUFFER_SIZE );
+
+            ptr = beg;
+            bool is_matching = false;
+            while ( !is_matching )
+            {
+                switch ( *ptr )
                 {
-                    int line_offset = (int)ftell( fs->file );
-                    char* ptr0 = icvGets( fs, xml_buf, xml_buf_size ), *ptr;
-                    if( !ptr0 )
-                        break;
-                    ptr = ptr0;
-                    for(;;)
+                case '\\':
+                {
+                    string_buffer.append( beg, ptr );
+                    ptr++;
+                    switch ( *ptr )
                     {
-                        ptr = strstr( ptr, substr );
-                        if( !ptr )
-                            break;
-                        last_occurence = line_offset + (int)(ptr - ptr0);
-                        ptr += strlen(substr);
+                    case '\\':
+                    case '\"':
+                    case '\'': { string_buffer.append( 1u, *ptr ); break; }
+                    case 'n' : { string_buffer.append( 1u, '\n' ); break; }
+                    case 'r' : { string_buffer.append( 1u, '\r' ); break; }
+                    case 't' : { string_buffer.append( 1u, '\t' ); break; }
+                    case 'b' : { string_buffer.append( 1u, '\b' ); break; }
+                    case 'f' : { string_buffer.append( 1u, '\f' ); break; }
+                    case 'u' : { CV_PARSE_ERROR( "'\\uXXXX' currently not supported" ); }
+                    default  : { CV_PARSE_ERROR( "Invalid escape character" ); }
+                        break;
                     }
+                    ptr++;
+                    beg = ptr;
+                    break;
                 }
-                cvFree( &xml_buf );
-                if( last_occurence < 0 )
+                case '\0':
                 {
-                    cvReleaseFileStorage( &fs );
-                    CV_Error( CV_StsError, "Could not find </opencv_storage> in the end of file.\n" );
+                    string_buffer.append( beg, ptr );
+
+                    ptr = icvGets( fs, fs->buffer_start, static_cast<int>(fs->buffer_end - fs->buffer_start) );
+                    if ( !ptr )
+                        CV_PARSE_ERROR( "'\"' - right-quote of string is missing" );
+
+                    beg = ptr;
+                    break;
+                }
+                case '\"':
+                {
+                    string_buffer.append( beg, ptr );
+                    beg = ptr;
+                    is_matching = true;
+                    break;
+                }
+                case '\n':
+                case '\r':
+                {
+                    CV_PARSE_ERROR( "'\"' - right-quote of string is missing" );
+                    break;
+                }
+                default:
+                {
+                    ptr++;
+                    break;
+                }
                 }
-                icvCloseFile( fs );
-                fs->file = fopen( fs->filename, "r+t" );
-                fseek( fs->file, last_occurence, SEEK_SET );
-                // replace the last "</opencv_storage>" with " <!-- resumed -->", which has the same length
-                icvPuts( fs, " <!-- resumed -->" );
-                fseek( fs->file, 0, SEEK_END );
-                icvPuts( fs, "\n" );
             }
-            fs->start_write_struct = icvXMLStartWriteStruct;
-            fs->end_write_struct = icvXMLEndWriteStruct;
-            fs->write_int = icvXMLWriteInt;
-            fs->write_real = icvXMLWriteReal;
-            fs->write_string = icvXMLWriteString;
-            fs->write_comment = icvXMLWriteComment;
-            fs->start_next_stream = icvXMLStartNextStream;
+
+            if ( *ptr != '\"' )
+                CV_PARSE_ERROR( "'\"' - right-quote of string is missing" );
+            else
+                ptr++;
+
+            node->data.str = cvMemStorageAllocString
+            (
+                fs->memstorage,
+                string_buffer.c_str(),
+                static_cast<int>(string_buffer.size())
+            );
+            node->tag = CV_NODE_STRING;
+        }
+    }
+    else if ( cv_isdigit(*ptr) || *ptr == '-' || *ptr == '+' || *ptr == '.' )
+    {    /**************** number ****************/
+        char * beg = ptr;
+        if ( *ptr == '+' || *ptr == '-' )
+            ptr++;
+        while( cv_isdigit(*ptr) )
+            ptr++;
+        if (*ptr == '.' || *ptr == 'e')
+        {
+            node->data.f = icv_strtod( fs, beg, &ptr );
+            node->tag = CV_NODE_REAL;
         }
         else
         {
-            if( !append )
-                icvPuts( fs, "%YAML:1.0\n" );
-            else
-                icvPuts( fs, "...\n---\n" );
-            fs->start_write_struct = icvYMLStartWriteStruct;
-            fs->end_write_struct = icvYMLEndWriteStruct;
-            fs->write_int = icvYMLWriteInt;
-            fs->write_real = icvYMLWriteReal;
-            fs->write_string = icvYMLWriteString;
-            fs->write_comment = icvYMLWriteComment;
-            fs->start_next_stream = icvYMLStartNextStream;
+            node->data.i = static_cast<int>(strtol( beg, &ptr, 0 ));
+            node->tag = CV_NODE_INT;
         }
+
+        if ( beg >= ptr )
+            CV_PARSE_ERROR( "Invalid numeric value (inconsistent explicit type specification?)" );
     }
     else
-    {
-        if( mem )
+    {    /**************** other data ****************/
+        const char * beg = ptr;
+        size_t len = 0u;
+        for ( ; cv_isalpha(*ptr) && len <= 6u; ptr++ )
+            len++;
+
+        if ( len >= 4u && memcmp( beg, "null", 4u ) == 0 )
         {
-            fs->strbuf = filename;
-            fs->strbufsize = fnamelen;
+            CV_PARSE_ERROR( "Value 'null' is not supported by this parser" );
         }
-
-        size_t buf_size = 1 << 20;
-        const char* yaml_signature = "%YAML:";
-        char buf[16];
-        icvGets( fs, buf, sizeof(buf)-2 );
-        fs->fmt = strncmp( buf, yaml_signature, strlen(yaml_signature) ) == 0 ?
-            CV_STORAGE_FORMAT_YAML : CV_STORAGE_FORMAT_XML;
-
-        if( !isGZ )
+        else if ( len >= 4u && memcmp( beg, "true", 4u ) == 0 )
         {
-            if( !mem )
-            {
-                fseek( fs->file, 0, SEEK_END );
-                buf_size = ftell( fs->file );
-            }
-            else
-                buf_size = fs->strbufsize;
-            buf_size = MIN( buf_size, (size_t)(1 << 20) );
-            buf_size = MAX( buf_size, (size_t)(CV_FS_MAX_LEN*2 + 1024) );
-        }
-        icvRewind(fs);
-
-        fs->str_hash = cvCreateMap( 0, sizeof(CvStringHash),
-                        sizeof(CvStringHashNode), fs->memstorage, 256 );
-
-        fs->roots = cvCreateSeq( 0, sizeof(CvSeq),
-                        sizeof(CvFileNode), fs->memstorage );
-
-        fs->buffer = fs->buffer_start = (char*)cvAlloc( buf_size + 256 );
-        fs->buffer_end = fs->buffer_start + buf_size;
-        fs->buffer[0] = '\n';
-        fs->buffer[1] = '\0';
-
-        //mode = cvGetErrMode();
-        //cvSetErrMode( CV_ErrModeSilent );
-        try
-        {
-            if( fs->fmt == CV_STORAGE_FORMAT_XML )
-                icvXMLParse( fs );
-            else
-                icvYMLParse( fs );
-        }
-        catch (...)
-        {
-            cvReleaseFileStorage( &fs );
-            throw;
+            node->data.i = 1;
+            node->tag = CV_NODE_INT;
         }
-        //cvSetErrMode( mode );
-
-        // release resources that we do not need anymore
-        cvFree( &fs->buffer_start );
-        fs->buffer = fs->buffer_end = 0;
-    }
-    fs->is_opened = true;
-
-_exit_:
-    if( fs )
-    {
-        if( cvGetErrStatus() < 0 || (!fs->file && !fs->gzfile && !fs->outbuf && !fs->strbuf) )
+        else if ( len >= 5u && memcmp( beg, "false", 5u ) == 0 )
         {
-            cvReleaseFileStorage( &fs );
+            node->data.i = 0;
+            node->tag = CV_NODE_INT;
         }
-        else if( !fs->write_mode )
+        else
         {
-            icvCloseFile(fs);
-            // we close the file since it's not needed anymore. But icvCloseFile() resets is_opened,
-            // which may be misleading. Since we restore the value of is_opened.
-            fs->is_opened = true;
+            CV_PARSE_ERROR( "Unrecognized value" );
         }
+        ptr++;
     }
 
-    return  fs;
-}
-
-
-CV_IMPL void
-cvStartWriteStruct( CvFileStorage* fs, const char* key, int struct_flags,
-                    const char* type_name, CvAttrList /*attributes*/ )
-{
-    CV_CHECK_OUTPUT_FILE_STORAGE(fs);
-    fs->start_write_struct( fs, key, struct_flags, type_name );
-}
-
-
-CV_IMPL void
-cvEndWriteStruct( CvFileStorage* fs )
-{
-    CV_CHECK_OUTPUT_FILE_STORAGE(fs);
-    fs->end_write_struct( fs );
-}
-
-
-CV_IMPL void
-cvWriteInt( CvFileStorage* fs, const char* key, int value )
-{
-    CV_CHECK_OUTPUT_FILE_STORAGE(fs);
-    fs->write_int( fs, key, value );
+    return ptr;
 }
 
+static char* icvJSONParseSeq( CvFileStorage* fs, char* ptr, CvFileNode* node );
+static char* icvJSONParseMap( CvFileStorage* fs, char* ptr, CvFileNode* node );
 
-CV_IMPL void
-cvWriteReal( CvFileStorage* fs, const char* key, double value )
+static char* icvJSONParseSeq( CvFileStorage* fs, char* ptr, CvFileNode* node )
 {
-    CV_CHECK_OUTPUT_FILE_STORAGE(fs);
-    fs->write_real( fs, key, value );
-}
-
+    if ( *ptr != '[' )
+        CV_PARSE_ERROR( "'[' - left-brace of seq is missing" );
+    else
+        ptr++;
 
-CV_IMPL void
-cvWriteString( CvFileStorage* fs, const char* key, const char* value, int quote )
-{
-    CV_CHECK_OUTPUT_FILE_STORAGE(fs);
-    fs->write_string( fs, key, value, quote );
-}
+    memset( node, 0, sizeof(*node) );
+    icvFSCreateCollection( fs, CV_NODE_SEQ, node );
 
+    for (;;)
+    {
+        ptr = icvJSONSkipSpaces( fs, ptr );
+        if ( ptr == 0 || fs->dummy_eof )
+            break;
 
-CV_IMPL void
-cvWriteComment( CvFileStorage* fs, const char* comment, int eol_comment )
-{
-    CV_CHECK_OUTPUT_FILE_STORAGE(fs);
-    fs->write_comment( fs, comment, eol_comment );
-}
+        if ( *ptr != ']' )
+        {
+            CvFileNode* child = (CvFileNode*)cvSeqPush( node->data.seq, 0 );
 
+            if ( *ptr == '[' )
+                ptr = icvJSONParseSeq( fs, ptr, child );
+            else if ( *ptr == '{' )
+                ptr = icvJSONParseMap( fs, ptr, child );
+            else
+                ptr = icvJSONParseValue( fs, ptr, child );
+        }
 
-CV_IMPL void
-cvStartNextStream( CvFileStorage* fs )
-{
-    CV_CHECK_OUTPUT_FILE_STORAGE(fs);
-    fs->start_next_stream( fs );
-}
+        ptr = icvJSONSkipSpaces( fs, ptr );
+        if ( ptr == 0 || fs->dummy_eof )
+            break;
 
+        if ( *ptr == ',' )
+            ptr++;
+        else if ( *ptr == ']' )
+            break;
+        else
+            CV_PARSE_ERROR( "Unexpected character" );
+    }
 
-static const char icvTypeSymbol[] = "ucwsifdr";
-#define CV_FS_MAX_FMT_PAIRS  128
+    if ( *ptr != ']' )
+        CV_PARSE_ERROR( "']' - right-brace of seq is missing" );
+    else
+        ptr++;
 
-static char*
-icvEncodeFormat( int elem_type, char* dt )
-{
-    sprintf( dt, "%d%c", CV_MAT_CN(elem_type), icvTypeSymbol[CV_MAT_DEPTH(elem_type)] );
-    return dt + ( dt[2] == '\0' && dt[0] == '1' );
+    return ptr;
 }
 
-static int
-icvDecodeFormat( const char* dt, int* fmt_pairs, int max_len )
+static char* icvJSONParseMap( CvFileStorage* fs, char* ptr, CvFileNode* node )
 {
-    int fmt_pair_count = 0;
-    int i = 0, k = 0, len = dt ? (int)strlen(dt) : 0;
-
-    if( !dt || !len )
-        return 0;
+    if ( *ptr != '{' )
+        CV_PARSE_ERROR( "'{' - left-brace of map is missing" );
+    else
+        ptr++;
 
-    assert( fmt_pairs != 0 && max_len > 0 );
-    fmt_pairs[0] = 0;
-    max_len *= 2;
+    memset( node, 0, sizeof(*node) );
+    icvFSCreateCollection( fs, CV_NODE_MAP, node );
 
-    for( ; k < len; k++ )
+    for ( ;; )
     {
-        char c = dt[k];
+        ptr = icvJSONSkipSpaces( fs, ptr );
+        if ( ptr == 0 || fs->dummy_eof )
+            break;
 
-        if( cv_isdigit(c) )
+        if ( *ptr == '"' )
         {
-            int count = c - '0';
-            if( cv_isdigit(dt[k+1]) )
-            {
-                char* endptr = 0;
-                count = (int)strtol( dt+k, &endptr, 10 );
-                k = (int)(endptr - dt) - 1;
-            }
-
-            if( count <= 0 )
-                CV_Error( CV_StsBadArg, "Invalid data type specification" );
+            CvFileNode* child = 0;
+            ptr = icvJSONParseKey( fs, ptr, node, &child );
+            ptr = icvJSONSkipSpaces( fs, ptr );
+            if ( ptr == 0 || fs->dummy_eof )
+                break;
 
-            fmt_pairs[i] = count;
-        }
-        else
-        {
-            const char* pos = strchr( icvTypeSymbol, c );
-            if( !pos )
-                CV_Error( CV_StsBadArg, "Invalid data type specification" );
-            if( fmt_pairs[i] == 0 )
-                fmt_pairs[i] = 1;
-            fmt_pairs[i+1] = (int)(pos - icvTypeSymbol);
-            if( i > 0 && fmt_pairs[i+1] == fmt_pairs[i-1] )
-                fmt_pairs[i-2] += fmt_pairs[i];
+            if ( child == 0 )
+            {   /* type_id */
+                CvFileNode tmp;
+                ptr = icvJSONParseValue( fs, ptr, &tmp );
+                if ( CV_NODE_IS_STRING(tmp.tag) )
+                {
+                    node->info = cvFindType( tmp.data.str.ptr );
+                    if ( node->info )
+                        node->tag |= CV_NODE_USER;
+                    // delete tmp.data.str
+                }
+                else
+                {
+                    CV_PARSE_ERROR( "\"type_id\" should be of type string" );
+                }
+            }
             else
-            {
-                i += 2;
-                if( i >= max_len )
-                    CV_Error( CV_StsBadArg, "Too long data type specification" );
+            {   /* normal */
+                if ( *ptr == '[' )
+                    ptr = icvJSONParseSeq( fs, ptr, child );
+                else if ( *ptr == '{' )
+                    ptr = icvJSONParseMap( fs, ptr, child );
+                else
+                    ptr = icvJSONParseValue( fs, ptr, child );
             }
-            fmt_pairs[i] = 0;
         }
+
+        ptr = icvJSONSkipSpaces( fs, ptr );
+        if ( ptr == 0 || fs->dummy_eof )
+            break;
+
+        if ( *ptr == ',' )
+            ptr++;
+        else if ( *ptr == '}' )
+            break;
+        else
+            CV_PARSE_ERROR( "Unexpected character" );
     }
 
-    fmt_pair_count = i/2;
-    return fmt_pair_count;
+    if ( *ptr != '}' )
+        CV_PARSE_ERROR( "'}' - right-brace of map is missing" );
+    else
+        ptr++;
+
+    return ptr;
 }
 
 
-static int
-icvCalcElemSize( const char* dt, int initial_size )
+static void
+icvJSONParse( CvFileStorage* fs )
 {
-    int size = 0;
-    int fmt_pairs[CV_FS_MAX_FMT_PAIRS], i, fmt_pair_count;
-    int comp_size;
+    char* ptr = fs->buffer_start;
+    ptr = icvJSONSkipSpaces( fs, ptr );
+    if ( ptr == 0 || fs->dummy_eof )
+        return;
 
-    fmt_pair_count = icvDecodeFormat( dt, fmt_pairs, CV_FS_MAX_FMT_PAIRS );
-    fmt_pair_count *= 2;
-    for( i = 0, size = initial_size; i < fmt_pair_count; i += 2 )
+    if ( *ptr == '{' )
     {
-        comp_size = CV_ELEM_SIZE(fmt_pairs[i+1]);
-        size = cvAlign( size, comp_size );
-        size += comp_size * fmt_pairs[i];
+        CvFileNode* root_node = (CvFileNode*)cvSeqPush( fs->roots, 0 );
+        ptr = icvJSONParseMap( fs, ptr, root_node );
     }
-    if( initial_size == 0 )
+    else if ( *ptr == '[' )
     {
-        comp_size = CV_ELEM_SIZE(fmt_pairs[1]);
-        size = cvAlign( size, comp_size );
+        CvFileNode* root_node = (CvFileNode*)cvSeqPush( fs->roots, 0 );
+        ptr = icvJSONParseSeq( fs, ptr, root_node );
     }
-    return size;
+    else
+    {
+        CV_PARSE_ERROR( "left-brace of top level is missing" );
+    }
+
+    if ( fs->dummy_eof != 0 )
+        CV_PARSE_ERROR( "Unexpected End-Of-File" );
 }
 
 
-static int
-icvDecodeSimpleFormat( const char* dt )
+/****************************************************************************************\
+*                                       JSON Emitter                                     *
+\****************************************************************************************/
+
+static void
+icvJSONWrite( CvFileStorage* fs, const char* key, const char* data )
 {
-    int elem_type = -1;
-    int fmt_pairs[CV_FS_MAX_FMT_PAIRS], fmt_pair_count;
+    /* check write_struct */
 
-    fmt_pair_count = icvDecodeFormat( dt, fmt_pairs, CV_FS_MAX_FMT_PAIRS );
-    if( fmt_pair_count != 1 || fmt_pairs[0] > 4 )
-        CV_Error( CV_StsError, "Too complex format for the matrix" );
+    check_if_write_struct_is_delayed( fs );
+    if ( fs->state_of_writing_base64 == base64::fs::Uncertain )
+    {
+        switch_to_Base64_state( fs, base64::fs::NotUse );
+    }
+    else if ( fs->state_of_writing_base64 == base64::fs::InUse )
+    {
+        CV_Error( CV_StsError, "At present, output Base64 data only." );
+    }
 
-    elem_type = CV_MAKETYPE( fmt_pairs[1], fmt_pairs[0] );
+    /* check parameters */
 
-    return elem_type;
-}
+    size_t key_len = 0u;
+    if( key && *key == '\0' )
+        key = 0;
+    if ( key )
+    {
+        key_len = strlen(key);
+        if ( key_len == 0u )
+            CV_Error( CV_StsBadArg, "The key is an empty" );
+        else if ( static_cast<int>(key_len) > CV_FS_MAX_LEN )
+            CV_Error( CV_StsBadArg, "The key is too long" );
+    }
 
+    size_t data_len = 0u;
+    if ( data )
+        data_len = strlen(data);
 
-CV_IMPL void
-cvWriteRawData( CvFileStorage* fs, const void* _data, int len, const char* dt )
-{
-    const char* data0 = (const char*)_data;
-    int offset = 0;
-    int fmt_pairs[CV_FS_MAX_FMT_PAIRS*2], k, fmt_pair_count;
-    char buf[256] = "";
+    int struct_flags = fs->struct_flags;
+    if( CV_NODE_IS_COLLECTION(struct_flags) )
+    {
+        if ( (CV_NODE_IS_MAP(struct_flags) ^ (key != 0)) )
+            CV_Error( CV_StsBadArg, "An attempt to add element without a key to a map, "
+                                    "or add element with key to sequence" );
+    } else {
+        fs->is_first = 0;
+        struct_flags = CV_NODE_EMPTY | (key ? CV_NODE_MAP : CV_NODE_SEQ);
+    }
 
-    CV_CHECK_OUTPUT_FILE_STORAGE( fs );
+    /* start to write */
 
-    if( len < 0 )
-        CV_Error( CV_StsOutOfRange, "Negative number of elements" );
+    char* ptr = 0;
 
-    fmt_pair_count = icvDecodeFormat( dt, fmt_pairs, CV_FS_MAX_FMT_PAIRS );
-
-    if( !len )
-        return;
-
-    if( !data0 )
-        CV_Error( CV_StsNullPtr, "Null data pointer" );
-
-    if( fmt_pair_count == 1 )
+    if( CV_NODE_IS_FLOW(struct_flags) )
     {
-        fmt_pairs[0] *= len;
-        len = 1;
+        int new_offset;
+        ptr = fs->buffer;
+        if( !CV_NODE_IS_EMPTY(struct_flags) )
+            *ptr++ = ',';
+        new_offset = static_cast<int>(ptr - fs->buffer_start + key_len + data_len);
+        if( new_offset > fs->wrap_margin && new_offset - fs->struct_indent > 10 )
+        {
+            fs->buffer = ptr;
+            ptr = icvFSFlush(fs);
+        }
+        else
+            *ptr++ = ' ';
     }
-
-    for(;len--;)
+    else
     {
-        for( k = 0; k < fmt_pair_count; k++ )
+        if ( !CV_NODE_IS_EMPTY(struct_flags) )
         {
-            int i, count = fmt_pairs[k*2];
-            int elem_type = fmt_pairs[k*2+1];
-            int elem_size = CV_ELEM_SIZE(elem_type);
-            const char* data, *ptr;
+            ptr = fs->buffer;
+            *ptr++ = ',';
+            *ptr++ = '\n';
+            *ptr++ = '\0';
+            ::icvPuts( fs, fs->buffer_start );
+            ptr = fs->buffer = fs->buffer_start;
+        }
+        ptr = icvFSFlush(fs);
+    }
 
-            offset = cvAlign( offset, elem_size );
-            data = data0 + offset;
+    if( key )
+    {
+        if( !cv_isalpha(key[0]) && key[0] != '_' )
+            CV_Error( CV_StsBadArg, "Key must start with a letter or _" );
 
-            for( i = 0; i < count; i++ )
-            {
-                switch( elem_type )
-                {
-                case CV_8U:
-                    ptr = icv_itoa( *(uchar*)data, buf, 10 );
-                    data++;
-                    break;
-                case CV_8S:
-                    ptr = icv_itoa( *(char*)data, buf, 10 );
-                    data++;
-                    break;
-                case CV_16U:
-                    ptr = icv_itoa( *(ushort*)data, buf, 10 );
-                    data += sizeof(ushort);
-                    break;
-                case CV_16S:
-                    ptr = icv_itoa( *(short*)data, buf, 10 );
-                    data += sizeof(short);
-                    break;
-                case CV_32S:
-                    ptr = icv_itoa( *(int*)data, buf, 10 );
-                    data += sizeof(int);
-                    break;
-                case CV_32F:
-                    ptr = icvFloatToString( buf, *(float*)data );
-                    data += sizeof(float);
-                    break;
-                case CV_64F:
-                    ptr = icvDoubleToString( buf, *(double*)data );
-                    data += sizeof(double);
-                    break;
-                case CV_USRTYPE1: /* reference */
-                    ptr = icv_itoa( (int)*(size_t*)data, buf, 10 );
-                    data += sizeof(size_t);
-                    break;
-                default:
-                    assert(0);
-                    return;
-                }
+        ptr = icvFSResizeWriteBuffer( fs, ptr, static_cast<int>(key_len) );
+        *ptr++ = '\"';
 
-                if( fs->fmt == CV_STORAGE_FORMAT_XML )
-                {
-                    int buf_len = (int)strlen(ptr);
-                    icvXMLWriteScalar( fs, 0, ptr, buf_len );
-                }
-                else
-                    icvYMLWrite( fs, 0, ptr );
-            }
+        for( size_t i = 0u; i < key_len; i++ )
+        {
+            char c = key[i];
 
-            offset = (int)(data - data0);
+            ptr[i] = c;
+            if( !cv_isalnum(c) && c != '-' && c != '_' && c != ' ' )
+                CV_Error( CV_StsBadArg, "Key names may only contain alphanumeric characters [a-zA-Z0-9], '-', '_' and ' '" );
         }
+
+        ptr += key_len;
+        *ptr++ = '\"';
+        *ptr++ = ':';
+        *ptr++ = ' ';
+    }
+
+    if( data )
+    {
+        ptr = icvFSResizeWriteBuffer( fs, ptr, static_cast<int>(data_len) );
+        memcpy( ptr, data, data_len );
+        ptr += data_len;
     }
+
+    fs->buffer = ptr;
+    fs->struct_flags = struct_flags & ~CV_NODE_EMPTY;
 }
 
 
-CV_IMPL void
-cvStartReadRawData( const CvFileStorage* fs, const CvFileNode* src, CvSeqReader* reader )
+static void
+icvJSONStartWriteStruct( CvFileStorage* fs, const char* key, int struct_flags,
+                        const char* type_name CV_DEFAULT(0))
 {
-    int node_type;
-    CV_CHECK_FILE_STORAGE( fs );
+    int parent_flags;
+    char data[CV_FS_MAX_LEN + 1024];
 
-    if( !src || !reader )
-        CV_Error( CV_StsNullPtr, "Null pointer to source file node or reader" );
+    struct_flags = (struct_flags & (CV_NODE_TYPE_MASK|CV_NODE_FLOW)) | CV_NODE_EMPTY;
+    if( !CV_NODE_IS_COLLECTION(struct_flags))
+        CV_Error( CV_StsBadArg,
+        "Some collection type - CV_NODE_SEQ or CV_NODE_MAP, must be specified" );
 
-    node_type = CV_NODE_TYPE(src->tag);
-    if( node_type == CV_NODE_INT || node_type == CV_NODE_REAL )
+    if ( type_name && *type_name == '\0' )
+        type_name = 0;
+
+    bool has_type_id = false;
+    bool is_real_collection = true;
+    if (type_name && memcmp(type_name, "binary", 6) == 0)
     {
-        // emulate reading from 1-element sequence
-        reader->ptr = (schar*)src;
-        reader->block_max = reader->ptr + sizeof(*src)*2;
-        reader->block_min = reader->ptr;
-        reader->seq = 0;
+        struct_flags = CV_NODE_STR;
+        data[0] = '\0';
+        is_real_collection = false;
     }
-    else if( node_type == CV_NODE_SEQ )
+    else if( type_name )
     {
-        cvStartReadSeq( src->data.seq, reader, 0 );
+        has_type_id = true;
     }
-    else if( node_type == CV_NODE_NONE )
+
+    if ( is_real_collection )
     {
-        memset( reader, 0, sizeof(*reader) );
+        char c = CV_NODE_IS_MAP(struct_flags) ? '{' : '[';
+        data[0] = c;
+        data[1] = '\0';
     }
-    else
-        CV_Error( CV_StsBadArg, "The file node should be a numerical scalar or a sequence" );
+
+    icvJSONWrite( fs, key, data );
+
+    parent_flags = fs->struct_flags;
+    cvSeqPush( fs->write_stack, &parent_flags );
+    fs->struct_flags = struct_flags;
+    fs->struct_indent += 4;
+
+    if ( has_type_id )
+        fs->write_string( fs, "type_id", type_name, 1 );
 }
 
 
-CV_IMPL void
-cvReadRawDataSlice( const CvFileStorage* fs, CvSeqReader* reader,
-                    int len, void* _data, const char* dt )
+static void
+icvJSONEndWriteStruct( CvFileStorage* fs )
 {
-    char* data0 = (char*)_data;
-    int fmt_pairs[CV_FS_MAX_FMT_PAIRS*2], k = 0, fmt_pair_count;
-    int i = 0, offset = 0, count = 0;
+    if( fs->write_stack->total == 0 )
+        CV_Error( CV_StsError, "EndWriteStruct w/o matching StartWriteStruct" );
 
-    CV_CHECK_FILE_STORAGE( fs );
+    int parent_flags = 0;
+    int struct_flags = fs->struct_flags;
+    cvSeqPop( fs->write_stack, &parent_flags );
+    fs->struct_indent -= 4;
+    fs->struct_flags = parent_flags & ~CV_NODE_EMPTY;
+    assert( fs->struct_indent >= 0 );
 
-    if( !reader || !data0 )
-        CV_Error( CV_StsNullPtr, "Null pointer to reader or destination array" );
+    if ( CV_NODE_IS_COLLECTION(struct_flags) )
+    {
+        if ( !CV_NODE_IS_FLOW(struct_flags) )
+        {
+            if ( fs->buffer <= fs->buffer_start + fs->space )
+            {
+                /* some bad code for base64_writer... */
+                *fs->buffer++ = '\n';
+                *fs->buffer++ = '\0';
+                icvPuts( fs, fs->buffer_start );
+                fs->buffer = fs->buffer_start;
+            }
+            icvFSFlush(fs);
+        }
 
-    if( !reader->seq && len != 1 )
-        CV_Error( CV_StsBadSize, "The readed sequence is a scalar, thus len must be 1" );
+        char* ptr = fs->buffer;
+        if( ptr > fs->buffer_start + fs->struct_indent && !CV_NODE_IS_EMPTY(struct_flags) )
+            *ptr++ = ' ';
+        *ptr++ = CV_NODE_IS_MAP(struct_flags) ? '}' : ']';
+        fs->buffer = ptr;
+    }
+}
 
-    fmt_pair_count = icvDecodeFormat( dt, fmt_pairs, CV_FS_MAX_FMT_PAIRS );
 
-    for(;;)
+static void
+icvJSONStartNextStream( CvFileStorage* fs )
+{
+    if( !fs->is_first )
     {
-        for( k = 0; k < fmt_pair_count; k++ )
-        {
-            int elem_type = fmt_pairs[k*2+1];
-            int elem_size = CV_ELEM_SIZE(elem_type);
-            char* data;
+        while( fs->write_stack->total > 0 )
+            icvJSONEndWriteStruct(fs);
 
-            count = fmt_pairs[k*2];
-            offset = cvAlign( offset, elem_size );
-            data = data0 + offset;
+        fs->struct_indent = 4;
+        icvFSFlush(fs);
+        fs->buffer = fs->buffer_start;
+    }
+}
 
-            for( i = 0; i < count; i++ )
-            {
-                CvFileNode* node = (CvFileNode*)reader->ptr;
-                if( CV_NODE_IS_INT(node->tag) )
-                {
-                    int ival = node->data.i;
 
-                    switch( elem_type )
-                    {
-                    case CV_8U:
-                        *(uchar*)data = cv::saturate_cast<uchar>(ival);
-                        data++;
-                        break;
-                    case CV_8S:
-                        *(char*)data = cv::saturate_cast<schar>(ival);
-                        data++;
-                        break;
-                    case CV_16U:
-                        *(ushort*)data = cv::saturate_cast<ushort>(ival);
-                        data += sizeof(ushort);
-                        break;
-                    case CV_16S:
-                        *(short*)data = cv::saturate_cast<short>(ival);
-                        data += sizeof(short);
-                        break;
-                    case CV_32S:
-                        *(int*)data = ival;
-                        data += sizeof(int);
-                        break;
-                    case CV_32F:
-                        *(float*)data = (float)ival;
-                        data += sizeof(float);
-                        break;
-                    case CV_64F:
-                        *(double*)data = (double)ival;
-                        data += sizeof(double);
-                        break;
-                    case CV_USRTYPE1: /* reference */
-                        *(size_t*)data = ival;
-                        data += sizeof(size_t);
-                        break;
-                    default:
-                        assert(0);
-                        return;
-                    }
-                }
-                else if( CV_NODE_IS_REAL(node->tag) )
-                {
-                    double fval = node->data.f;
-                    int ival;
-
-                    switch( elem_type )
-                    {
-                    case CV_8U:
-                        ival = cvRound(fval);
-                        *(uchar*)data = cv::saturate_cast<uchar>(ival);
-                        data++;
-                        break;
-                    case CV_8S:
-                        ival = cvRound(fval);
-                        *(char*)data = cv::saturate_cast<schar>(ival);
-                        data++;
-                        break;
-                    case CV_16U:
-                        ival = cvRound(fval);
-                        *(ushort*)data = cv::saturate_cast<ushort>(ival);
-                        data += sizeof(ushort);
-                        break;
-                    case CV_16S:
-                        ival = cvRound(fval);
-                        *(short*)data = cv::saturate_cast<short>(ival);
-                        data += sizeof(short);
-                        break;
-                    case CV_32S:
-                        ival = cvRound(fval);
-                        *(int*)data = ival;
-                        data += sizeof(int);
-                        break;
-                    case CV_32F:
-                        *(float*)data = (float)fval;
-                        data += sizeof(float);
-                        break;
-                    case CV_64F:
-                        *(double*)data = fval;
-                        data += sizeof(double);
-                        break;
-                    case CV_USRTYPE1: /* reference */
-                        ival = cvRound(fval);
-                        *(size_t*)data = ival;
-                        data += sizeof(size_t);
-                        break;
-                    default:
-                        assert(0);
-                        return;
-                    }
-                }
-                else
-                    CV_Error( CV_StsError,
-                    "The sequence element is not a numerical scalar" );
-
-                CV_NEXT_SEQ_ELEM( sizeof(CvFileNode), *reader );
-                if( !--len )
-                    goto end_loop;
-            }
-
-            offset = (int)(data - data0);
-        }
-    }
-
-end_loop:
-    if( i != count - 1 || k != fmt_pair_count - 1 )
-        CV_Error( CV_StsBadSize,
-        "The sequence slice does not fit an integer number of records" );
-
-    if( !reader->seq )
-        reader->ptr -= sizeof(CvFileNode);
-}
+static void
+icvJSONWriteInt( CvFileStorage* fs, const char* key, int value )
+{
+    char buf[128];
+    icvJSONWrite( fs, key, icv_itoa( value, buf, 10 ));
+}
 
 
-CV_IMPL void
-cvReadRawData( const CvFileStorage* fs, const CvFileNode* src,
-               void* data, const char* dt )
+static void
+icvJSONWriteReal( CvFileStorage* fs, const char* key, double value )
 {
-    CvSeqReader reader;
-
-    if( !src || !data )
-        CV_Error( CV_StsNullPtr, "Null pointers to source file node or destination array" );
-
-    cvStartReadRawData( fs, src, &reader );
-    cvReadRawDataSlice( fs, &reader, CV_NODE_IS_SEQ(src->tag) ?
-                        src->data.seq->total : 1, data, dt );
+    char buf[128];
+    icvJSONWrite( fs, key, icvDoubleToString( buf, value ));
 }
 
 
 static void
-icvWriteFileNode( CvFileStorage* fs, const char* name, const CvFileNode* node );
-
-static void
-icvWriteCollection( CvFileStorage* fs, const CvFileNode* node )
+icvJSONWriteString( CvFileStorage* fs, const char* key,
+                   const char* str, int quote CV_DEFAULT(0))
 {
-    int i, total = node->data.seq->total;
-    int elem_size = node->data.seq->elem_size;
-    int is_map = CV_NODE_IS_MAP(node->tag);
-    CvSeqReader reader;
+    char buf[CV_FS_MAX_LEN*4+16];
+    char* data = (char*)str;
+    int i, len;
 
-    cvStartReadSeq( node->data.seq, &reader, 0 );
+    if( !str )
+        CV_Error( CV_StsNullPtr, "Null string pointer" );
 
-    for( i = 0; i < total; i++ )
+    len = (int)strlen(str);
+    if( len > CV_FS_MAX_LEN )
+        CV_Error( CV_StsBadArg, "The written string is too long" );
+
+    if( quote || len == 0 || str[0] != str[len-1] || (str[0] != '\"' && str[0] != '\'') )
     {
-        CvFileMapNode* elem = (CvFileMapNode*)reader.ptr;
-        if( !is_map || CV_IS_SET_ELEM(elem) )
+        int need_quote = 1;
+        data = buf;
+        *data++ = '\"';
+        for( i = 0; i < len; i++ )
         {
-            const char* name = is_map ? elem->key->str.ptr : 0;
-            icvWriteFileNode( fs, name, &elem->value );
+            char c = str[i];
+
+            switch ( c )
+            {
+            case '\\':
+            case '\"':
+            case '\'': { *data++ = '\\'; *data++ = c;   break; }
+            case '\n': { *data++ = '\\'; *data++ = 'n'; break; }
+            case '\r': { *data++ = '\\'; *data++ = 'r'; break; }
+            case '\t': { *data++ = '\\'; *data++ = 't'; break; }
+            case '\b': { *data++ = '\\'; *data++ = 'b'; break; }
+            case '\f': { *data++ = '\\'; *data++ = 'f'; break; }
+            default  : { *data++ = c; }
+                break;
+            }
         }
-        CV_NEXT_SEQ_ELEM( elem_size, reader );
-    }
-}
 
-static void
-icvWriteFileNode( CvFileStorage* fs, const char* name, const CvFileNode* node )
-{
-    switch( CV_NODE_TYPE(node->tag) )
-    {
-    case CV_NODE_INT:
-        fs->write_int( fs, name, node->data.i );
-        break;
-    case CV_NODE_REAL:
-        fs->write_real( fs, name, node->data.f );
-        break;
-    case CV_NODE_STR:
-        fs->write_string( fs, name, node->data.str.ptr, 0 );
-        break;
-    case CV_NODE_SEQ:
-    case CV_NODE_MAP:
-        fs->start_write_struct( fs, name, CV_NODE_TYPE(node->tag) +
-                (CV_NODE_SEQ_IS_SIMPLE(node->data.seq) ? CV_NODE_FLOW : 0),
-                node->info ? node->info->type_name : 0 );
-        icvWriteCollection( fs, node );
-        fs->end_write_struct( fs );
-        break;
-    case CV_NODE_NONE:
-        fs->start_write_struct( fs, name, CV_NODE_SEQ, 0 );
-        fs->end_write_struct( fs );
-        break;
-    default:
-        CV_Error( CV_StsBadFlag, "Unknown type of file node" );
+        *data++ = '\"';
+        *data++ = '\0';
+        data = buf + !need_quote;
     }
+
+    icvJSONWrite( fs, key, data );
 }
 
 
-CV_IMPL void
-cvWriteFileNode( CvFileStorage* fs, const char* new_node_name,
-                 const CvFileNode* node, int embed )
+static void
+icvJSONWriteComment( CvFileStorage* fs, const char* comment, int eol_comment )
 {
-    CvFileStorage* dst = 0;
-    CV_CHECK_OUTPUT_FILE_STORAGE(fs);
+    if( !comment )
+        CV_Error( CV_StsNullPtr, "Null comment" );
 
-    if( !node )
-        return;
+    int         len = static_cast<int>(strlen(comment));
+    char*       ptr = fs->buffer;
+    const char* eol = strchr(comment, '\n');
+    bool  multiline = eol != 0;
 
-    if( CV_NODE_IS_COLLECTION(node->tag) && embed )
-    {
-        icvWriteCollection( fs, node );
-    }
+    if( !eol_comment || multiline || fs->buffer_end - ptr < len || ptr == fs->buffer_start )
+        ptr = icvFSFlush( fs );
     else
+        *ptr++ = ' ';
+
+    while( comment )
     {
-        icvWriteFileNode( fs, new_node_name, node );
+        *ptr++ = '/';
+        *ptr++ = '/';
+        *ptr++ = ' ';
+        if( eol )
+        {
+            ptr = icvFSResizeWriteBuffer( fs, ptr, (int)(eol - comment) + 1 );
+            memcpy( ptr, comment, eol - comment + 1 );
+            fs->buffer = ptr + (eol - comment);
+            comment = eol + 1;
+            eol = strchr( comment, '\n' );
+        }
+        else
+        {
+            len = (int)strlen(comment);
+            ptr = icvFSResizeWriteBuffer( fs, ptr, len );
+            memcpy( ptr, comment, len );
+            fs->buffer = ptr + len;
+            comment = 0;
+        }
+        ptr = icvFSFlush( fs );
     }
-    /*
-    int i, stream_count;
-    stream_count = fs->roots->total;
-    for( i = 0; i < stream_count; i++ )
-    {
-        CvFileNode* node = (CvFileNode*)cvGetSeqElem( fs->roots, i, 0 );
-        icvDumpCollection( dst, node );
-        if( i < stream_count - 1 )
-            dst->start_next_stream( dst );
-    }*/
-    cvReleaseFileStorage( &dst );
 }
 
 
-CV_IMPL const char*
-cvGetFileNodeName( const CvFileNode* file_node )
-{
-    return file_node && CV_NODE_HAS_NAME(file_node->tag) ?
-        ((CvFileMapNode*)file_node)->key->str.ptr : 0;
-}
-
 /****************************************************************************************\
-*                          Reading/Writing etc. for standard types                       *
+*                              Common High-Level Functions                               *
 \****************************************************************************************/
 
-/*#define CV_TYPE_NAME_MAT "opencv-matrix"
-#define CV_TYPE_NAME_MATND "opencv-nd-matrix"
-#define CV_TYPE_NAME_SPARSE_MAT "opencv-sparse-matrix"
-#define CV_TYPE_NAME_IMAGE "opencv-image"
-#define CV_TYPE_NAME_SEQ "opencv-sequence"
-#define CV_TYPE_NAME_SEQ_TREE "opencv-sequence-tree"
-#define CV_TYPE_NAME_GRAPH "opencv-graph"*/
-
-/******************************* CvMat ******************************/
-
-static int
-icvIsMat( const void* ptr )
-{
-    return CV_IS_MAT_HDR_Z(ptr);
-}
-
-static void
-icvWriteMat( CvFileStorage* fs, const char* name,
-             const void* struct_ptr, CvAttrList /*attr*/ )
+CV_IMPL CvFileStorage*
+cvOpenFileStorage( const char* query, CvMemStorage* dststorage, int flags, const char* encoding )
 {
-    const CvMat* mat = (const CvMat*)struct_ptr;
-    char dt[16];
-    CvSize size;
-    int y;
+    CvFileStorage* fs = 0;
+    int default_block_size = 1 << 18;
+    bool append = (flags & 3) == CV_STORAGE_APPEND;
+    bool mem = (flags & CV_STORAGE_MEMORY) != 0;
+    bool write_mode = (flags & 3) != 0;
+    bool write_base64 = (write_mode || append) && (flags & CV_STORAGE_BASE64) != 0;
+    bool isGZ = false;
+    size_t fnamelen = 0;
+    const char * filename = query;
 
-    assert( CV_IS_MAT_HDR_Z(mat) );
+    std::vector<std::string> params;
+    if ( !mem )
+    {
+        params = analyze_file_name( query );
+        if ( !params.empty() )
+            filename = params.begin()->c_str();
 
-    cvStartWriteStruct( fs, name, CV_NODE_MAP, CV_TYPE_NAME_MAT );
-    cvWriteInt( fs, "rows", mat->rows );
-    cvWriteInt( fs, "cols", mat->cols );
-    cvWriteString( fs, "dt", icvEncodeFormat( CV_MAT_TYPE(mat->type), dt ), 0 );
-    cvStartWriteStruct( fs, "data", CV_NODE_SEQ + CV_NODE_FLOW );
+        if ( write_base64 == false && is_param_exist( params, "base64" ) )
+            write_base64 = (write_mode || append);
+    }
 
-    size = cvGetSize(mat);
-    if( size.height > 0 && size.width > 0 && mat->data.ptr )
+    if( !filename || filename[0] == '\0' )
     {
-        if( CV_IS_MAT_CONT(mat->type) )
-        {
-            size.width *= size.height;
-            size.height = 1;
-        }
-
-        for( y = 0; y < size.height; y++ )
-            cvWriteRawData( fs, mat->data.ptr + (size_t)y*mat->step, size.width, dt );
+        if( !write_mode )
+            CV_Error( CV_StsNullPtr, mem ? "NULL or empty filename" : "NULL or empty buffer" );
+        mem = true;
     }
-    cvEndWriteStruct( fs );
-    cvEndWriteStruct( fs );
-}
+    else
+        fnamelen = strlen(filename);
 
+    if( mem && append )
+        CV_Error( CV_StsBadFlag, "CV_STORAGE_APPEND and CV_STORAGE_MEMORY are not currently compatible" );
 
-static int
-icvFileNodeSeqLen( CvFileNode* node )
-{
-    return CV_NODE_IS_COLLECTION(node->tag) ? node->data.seq->total :
-           CV_NODE_TYPE(node->tag) != CV_NODE_NONE;
-}
+    fs = (CvFileStorage*)cvAlloc( sizeof(*fs) );
+    memset( fs, 0, sizeof(*fs));
 
+    fs->memstorage = cvCreateMemStorage( default_block_size );
+    fs->dststorage = dststorage ? dststorage : fs->memstorage;
 
-static void*
+    fs->flags = CV_FILE_STORAGE;
+    fs->write_mode = write_mode;
+
+    if( !mem )
+    {
+        fs->filename = (char*)cvMemStorageAlloc( fs->memstorage, fnamelen+1 );
+        strcpy( fs->filename, filename );
+
+        char* dot_pos = strrchr(fs->filename, '.');
+        char compression = '\0';
+
+        if( dot_pos && dot_pos[1] == 'g' && dot_pos[2] == 'z' &&
+            (dot_pos[3] == '\0' || (cv_isdigit(dot_pos[3]) && dot_pos[4] == '\0')) )
+        {
+            if( append )
+            {
+                cvReleaseFileStorage( &fs );
+                CV_Error(CV_StsNotImplemented, "Appending data to compressed file is not implemented" );
+            }
+            isGZ = true;
+            compression = dot_pos[3];
+            if( compression )
+                dot_pos[3] = '\0', fnamelen--;
+        }
+
+        if( !isGZ )
+        {
+            fs->file = fopen(fs->filename, !fs->write_mode ? "rt" : !append ? "wt" : "a+t" );
+            if( !fs->file )
+                goto _exit_;
+        }
+        else
+        {
+            #if USE_ZLIB
+            char mode[] = { fs->write_mode ? 'w' : 'r', 'b', compression ? compression : '3', '\0' };
+            fs->gzfile = gzopen(fs->filename, mode);
+            if( !fs->gzfile )
+                goto _exit_;
+            #else
+            cvReleaseFileStorage( &fs );
+            CV_Error(CV_StsNotImplemented, "There is no compressed file storage support in this configuration");
+            #endif
+        }
+    }
+
+    fs->roots = 0;
+    fs->struct_indent = 0;
+    fs->struct_flags = 0;
+    fs->wrap_margin = 71;
+
+    if( fs->write_mode )
+    {
+        int fmt = flags & CV_STORAGE_FORMAT_MASK;
+
+        if( mem )
+            fs->outbuf = new std::deque<char>;
+
+        if( fmt == CV_STORAGE_FORMAT_AUTO && filename )
+        {
+            const char* dot_pos = strrchr( filename, '.' );
+            fs->fmt
+                = cv_strcasecmp( dot_pos, ".xml" )
+                ? CV_STORAGE_FORMAT_XML
+                : cv_strcasecmp( dot_pos, ".json" )
+                ? CV_STORAGE_FORMAT_JSON
+                : CV_STORAGE_FORMAT_YAML
+                ;
+        }
+        else if ( fmt != CV_STORAGE_FORMAT_AUTO )
+        {
+            fs->fmt = fmt;
+        }
+        else
+        {
+            fs->fmt = CV_STORAGE_FORMAT_XML;
+        }
+
+        // we use factor=6 for XML (the longest characters (' and ") are encoded with 6 bytes (' and ")
+        // and factor=4 for YAML ( as we use 4 bytes for non ASCII characters (e.g. \xAB))
+        int buf_size = CV_FS_MAX_LEN*(fs->fmt == CV_STORAGE_FORMAT_XML ? 6 : 4) + 1024;
+
+        if( append )
+            fseek( fs->file, 0, SEEK_END );
+
+        fs->write_stack = cvCreateSeq( 0, sizeof(CvSeq), fs->fmt == CV_STORAGE_FORMAT_XML ?
+                sizeof(CvXMLStackRecord) : sizeof(int), fs->memstorage );
+        fs->is_first = 1;
+        fs->struct_indent = 0;
+        fs->struct_flags = CV_NODE_EMPTY;
+        fs->buffer_start = fs->buffer = (char*)cvAlloc( buf_size + 1024 );
+        fs->buffer_end = fs->buffer_start + buf_size;
+
+        fs->base64_writer           = 0;
+        fs->is_default_using_base64 = write_base64;
+        fs->state_of_writing_base64 = base64::fs::Uncertain;
+
+        fs->is_write_struct_delayed = false;
+        fs->delayed_struct_key      = 0;
+        fs->delayed_struct_flags    = 0;
+        fs->delayed_type_name       = 0;
+
+        if( fs->fmt == CV_STORAGE_FORMAT_XML )
+        {
+            size_t file_size = fs->file ? (size_t)ftell( fs->file ) : (size_t)0;
+            fs->strstorage = cvCreateChildMemStorage( fs->memstorage );
+            if( !append || file_size == 0 )
+            {
+                if( encoding )
+                {
+                    if( strcmp( encoding, "UTF-16" ) == 0 ||
+                        strcmp( encoding, "utf-16" ) == 0 ||
+                        strcmp( encoding, "Utf-16" ) == 0 )
+                    {
+                        cvReleaseFileStorage( &fs );
+                        CV_Error( CV_StsBadArg, "UTF-16 XML encoding is not supported! Use 8-bit encoding\n");
+                    }
+
+                    CV_Assert( strlen(encoding) < 1000 );
+                    char buf[1100];
+                    sprintf(buf, "<?xml version=\"1.0\" encoding=\"%s\"?>\n", encoding);
+                    icvPuts( fs, buf );
+                }
+                else
+                    icvPuts( fs, "<?xml version=\"1.0\"?>\n" );
+                icvPuts( fs, "<opencv_storage>\n" );
+            }
+            else
+            {
+                int xml_buf_size = 1 << 10;
+                char substr[] = "</opencv_storage>";
+                int last_occurence = -1;
+                xml_buf_size = MIN(xml_buf_size, int(file_size));
+                fseek( fs->file, -xml_buf_size, SEEK_END );
+                char* xml_buf = (char*)cvAlloc( xml_buf_size+2 );
+                // find the last occurence of </opencv_storage>
+                for(;;)
+                {
+                    int line_offset = (int)ftell( fs->file );
+                    char* ptr0 = icvGets( fs, xml_buf, xml_buf_size ), *ptr;
+                    if( !ptr0 )
+                        break;
+                    ptr = ptr0;
+                    for(;;)
+                    {
+                        ptr = strstr( ptr, substr );
+                        if( !ptr )
+                            break;
+                        last_occurence = line_offset + (int)(ptr - ptr0);
+                        ptr += strlen(substr);
+                    }
+                }
+                cvFree( &xml_buf );
+                if( last_occurence < 0 )
+                {
+                    cvReleaseFileStorage( &fs );
+                    CV_Error( CV_StsError, "Could not find </opencv_storage> in the end of file.\n" );
+                }
+                icvCloseFile( fs );
+                fs->file = fopen( fs->filename, "r+t" );
+                fseek( fs->file, last_occurence, SEEK_SET );
+                // replace the last "</opencv_storage>" with " <!-- resumed -->", which has the same length
+                icvPuts( fs, " <!-- resumed -->" );
+                fseek( fs->file, 0, SEEK_END );
+                icvPuts( fs, "\n" );
+            }
+            fs->start_write_struct = icvXMLStartWriteStruct;
+            fs->end_write_struct = icvXMLEndWriteStruct;
+            fs->write_int = icvXMLWriteInt;
+            fs->write_real = icvXMLWriteReal;
+            fs->write_string = icvXMLWriteString;
+            fs->write_comment = icvXMLWriteComment;
+            fs->start_next_stream = icvXMLStartNextStream;
+        }
+        else if( fs->fmt == CV_STORAGE_FORMAT_YAML )
+        {
+            if( !append )
+                icvPuts( fs, "%YAML:1.0\n---\n" );
+            else
+                icvPuts( fs, "...\n---\n" );
+            fs->start_write_struct = icvYMLStartWriteStruct;
+            fs->end_write_struct = icvYMLEndWriteStruct;
+            fs->write_int = icvYMLWriteInt;
+            fs->write_real = icvYMLWriteReal;
+            fs->write_string = icvYMLWriteString;
+            fs->write_comment = icvYMLWriteComment;
+            fs->start_next_stream = icvYMLStartNextStream;
+        }
+        else
+        {
+            if( !append )
+                icvPuts( fs, "{\n" );
+            else
+            {
+                bool valid = false;
+                long roffset = 0;
+                for ( ;
+                      fseek( fs->file, roffset, SEEK_END ) == 0;
+                      roffset -= 1 )
+                {
+                    const char end_mark = '}';
+                    if ( fgetc( fs->file ) == end_mark )
+                    {
+                        fseek( fs->file, roffset, SEEK_END );
+                        valid = true;
+                        break;
+                    }
+                }
+
+                if ( valid )
+                {
+                    icvCloseFile( fs );
+                    fs->file = fopen( fs->filename, "r+t" );
+                    fseek( fs->file, roffset, SEEK_END );
+                    fputs( ",", fs->file );
+                }
+                else
+                {
+                    CV_Error( CV_StsError, "Could not find '}' in the end of file.\n" );
+                }
+            }
+            fs->struct_indent = 4;
+            fs->start_write_struct = icvJSONStartWriteStruct;
+            fs->end_write_struct = icvJSONEndWriteStruct;
+            fs->write_int = icvJSONWriteInt;
+            fs->write_real = icvJSONWriteReal;
+            fs->write_string = icvJSONWriteString;
+            fs->write_comment = icvJSONWriteComment;
+            fs->start_next_stream = icvJSONStartNextStream;
+        }
+    }
+    else
+    {
+        if( mem )
+        {
+            fs->strbuf = filename;
+            fs->strbufsize = fnamelen;
+        }
+
+        size_t buf_size = 1 << 20;
+        const char* yaml_signature = "%YAML";
+        const char* json_signature = "{";
+        const char* xml_signature  = "<?xml";
+        char buf[16];
+        icvGets( fs, buf, sizeof(buf)-2 );
+        char* bufPtr = cv_skip_BOM(buf);
+        size_t bufOffset = bufPtr - buf;
+
+        if(strncmp( bufPtr, yaml_signature, strlen(yaml_signature) ) == 0)
+            fs->fmt = CV_STORAGE_FORMAT_YAML;
+        else if(strncmp( bufPtr, json_signature, strlen(json_signature) ) == 0)
+            fs->fmt = CV_STORAGE_FORMAT_JSON;
+        else if(strncmp( bufPtr, xml_signature, strlen(xml_signature) ) == 0)
+            fs->fmt = CV_STORAGE_FORMAT_XML;
+        else if(fs->strbufsize  == bufOffset)
+            CV_Error(CV_BADARG_ERR, "Input file is empty");
+        else
+            CV_Error(CV_BADARG_ERR, "Unsupported file storage format");
+
+        if( !isGZ )
+        {
+            if( !mem )
+            {
+                fseek( fs->file, 0, SEEK_END );
+                buf_size = ftell( fs->file );
+            }
+            else
+                buf_size = fs->strbufsize;
+            buf_size = MIN( buf_size, (size_t)(1 << 20) );
+            buf_size = MAX( buf_size, (size_t)(CV_FS_MAX_LEN*2 + 1024) );
+        }
+        icvRewind(fs);
+        fs->strbufpos = bufOffset;
+
+        fs->str_hash = cvCreateMap( 0, sizeof(CvStringHash),
+                        sizeof(CvStringHashNode), fs->memstorage, 256 );
+
+        fs->roots = cvCreateSeq( 0, sizeof(CvSeq),
+                        sizeof(CvFileNode), fs->memstorage );
+
+        fs->buffer = fs->buffer_start = (char*)cvAlloc( buf_size + 256 );
+        fs->buffer_end = fs->buffer_start + buf_size;
+        fs->buffer[0] = '\n';
+        fs->buffer[1] = '\0';
+
+        //mode = cvGetErrMode();
+        //cvSetErrMode( CV_ErrModeSilent );
+        try
+        {
+            switch (fs->fmt)
+            {
+            case CV_STORAGE_FORMAT_XML : { icvXMLParse ( fs ); break; }
+            case CV_STORAGE_FORMAT_YAML: { icvYMLParse ( fs ); break; }
+            case CV_STORAGE_FORMAT_JSON: { icvJSONParse( fs ); break; }
+            default: break;
+            }
+        }
+        catch (...)
+        {
+            cvReleaseFileStorage( &fs );
+            throw;
+        }
+        //cvSetErrMode( mode );
+
+        // release resources that we do not need anymore
+        cvFree( &fs->buffer_start );
+        fs->buffer = fs->buffer_end = 0;
+    }
+    fs->is_opened = true;
+
+_exit_:
+    if( fs )
+    {
+        if( cvGetErrStatus() < 0 || (!fs->file && !fs->gzfile && !fs->outbuf && !fs->strbuf) )
+        {
+            cvReleaseFileStorage( &fs );
+        }
+        else if( !fs->write_mode )
+        {
+            icvCloseFile(fs);
+            // we close the file since it's not needed anymore. But icvCloseFile() resets is_opened,
+            // which may be misleading. Since we restore the value of is_opened.
+            fs->is_opened = true;
+        }
+    }
+
+    return  fs;
+}
+
+
+CV_IMPL void
+cvStartWriteStruct( CvFileStorage* fs, const char* key, int struct_flags,
+                    const char* type_name, CvAttrList /*attributes*/ )
+{
+    CV_CHECK_OUTPUT_FILE_STORAGE(fs);
+    check_if_write_struct_is_delayed( fs );
+    if ( fs->state_of_writing_base64 == base64::fs::NotUse )
+        switch_to_Base64_state( fs, base64::fs::Uncertain );
+
+    if ( fs->state_of_writing_base64 == base64::fs::Uncertain
+        &&
+        CV_NODE_IS_SEQ(struct_flags)
+        &&
+        fs->is_default_using_base64
+        &&
+        type_name == 0
+       )
+    {
+        /* Uncertain whether output Base64 data */
+        make_write_struct_delayed( fs, key, struct_flags, type_name );
+    }
+    else if ( type_name && memcmp(type_name, "binary", 6) == 0 )
+    {
+        /* Must output Base64 data */
+        if ( !CV_NODE_IS_SEQ(struct_flags) )
+            CV_Error( CV_StsBadArg, "must set 'struct_flags |= CV_NODE_SEQ' if using Base64.");
+        else if ( fs->state_of_writing_base64 != base64::fs::Uncertain )
+            CV_Error( CV_StsError, "function \'cvStartWriteStruct\' calls cannot be nested if using Base64.");
+
+        fs->start_write_struct( fs, key, struct_flags, type_name );
+
+        if ( fs->state_of_writing_base64 != base64::fs::Uncertain )
+            switch_to_Base64_state( fs, base64::fs::Uncertain );
+        switch_to_Base64_state( fs, base64::fs::InUse );
+    }
+    else
+    {
+        /* Won't output Base64 data */
+        if ( fs->state_of_writing_base64 == base64::fs::InUse )
+            CV_Error( CV_StsError, "At the end of the output Base64, `cvEndWriteStruct` is needed.");
+
+        fs->start_write_struct( fs, key, struct_flags, type_name );
+
+        if ( fs->state_of_writing_base64 != base64::fs::Uncertain )
+            switch_to_Base64_state( fs, base64::fs::Uncertain );
+        switch_to_Base64_state( fs, base64::fs::NotUse );
+    }
+}
+
+
+CV_IMPL void
+cvEndWriteStruct( CvFileStorage* fs )
+{
+    CV_CHECK_OUTPUT_FILE_STORAGE(fs);
+    check_if_write_struct_is_delayed( fs );
+
+    if ( fs->state_of_writing_base64 != base64::fs::Uncertain )
+        switch_to_Base64_state( fs, base64::fs::Uncertain );
+
+    fs->end_write_struct( fs );
+}
+
+
+CV_IMPL void
+cvWriteInt( CvFileStorage* fs, const char* key, int value )
+{
+    CV_CHECK_OUTPUT_FILE_STORAGE(fs);
+    fs->write_int( fs, key, value );
+}
+
+
+CV_IMPL void
+cvWriteReal( CvFileStorage* fs, const char* key, double value )
+{
+    CV_CHECK_OUTPUT_FILE_STORAGE(fs);
+    fs->write_real( fs, key, value );
+}
+
+
+CV_IMPL void
+cvWriteString( CvFileStorage* fs, const char* key, const char* value, int quote )
+{
+    CV_CHECK_OUTPUT_FILE_STORAGE(fs);
+    fs->write_string( fs, key, value, quote );
+}
+
+
+CV_IMPL void
+cvWriteComment( CvFileStorage* fs, const char* comment, int eol_comment )
+{
+    CV_CHECK_OUTPUT_FILE_STORAGE(fs);
+    fs->write_comment( fs, comment, eol_comment );
+}
+
+
+CV_IMPL void
+cvStartNextStream( CvFileStorage* fs )
+{
+    CV_CHECK_OUTPUT_FILE_STORAGE(fs);
+    fs->start_next_stream( fs );
+}
+
+
+static const char icvTypeSymbol[] = "ucwsifdr";
+#define CV_FS_MAX_FMT_PAIRS  128
+
+static char*
+icvEncodeFormat( int elem_type, char* dt )
+{
+    sprintf( dt, "%d%c", CV_MAT_CN(elem_type), icvTypeSymbol[CV_MAT_DEPTH(elem_type)] );
+    return dt + ( dt[2] == '\0' && dt[0] == '1' );
+}
+
+static int
+icvDecodeFormat( const char* dt, int* fmt_pairs, int max_len )
+{
+    int fmt_pair_count = 0;
+    int i = 0, k = 0, len = dt ? (int)strlen(dt) : 0;
+
+    if( !dt || !len )
+        return 0;
+
+    assert( fmt_pairs != 0 && max_len > 0 );
+    fmt_pairs[0] = 0;
+    max_len *= 2;
+
+    for( ; k < len; k++ )
+    {
+        char c = dt[k];
+
+        if( cv_isdigit(c) )
+        {
+            int count = c - '0';
+            if( cv_isdigit(dt[k+1]) )
+            {
+                char* endptr = 0;
+                count = (int)strtol( dt+k, &endptr, 10 );
+                k = (int)(endptr - dt) - 1;
+            }
+
+            if( count <= 0 )
+                CV_Error( CV_StsBadArg, "Invalid data type specification" );
+
+            fmt_pairs[i] = count;
+        }
+        else
+        {
+            const char* pos = strchr( icvTypeSymbol, c );
+            if( !pos )
+                CV_Error( CV_StsBadArg, "Invalid data type specification" );
+            if( fmt_pairs[i] == 0 )
+                fmt_pairs[i] = 1;
+            fmt_pairs[i+1] = (int)(pos - icvTypeSymbol);
+            if( i > 0 && fmt_pairs[i+1] == fmt_pairs[i-1] )
+                fmt_pairs[i-2] += fmt_pairs[i];
+            else
+            {
+                i += 2;
+                if( i >= max_len )
+                    CV_Error( CV_StsBadArg, "Too long data type specification" );
+            }
+            fmt_pairs[i] = 0;
+        }
+    }
+
+    fmt_pair_count = i/2;
+    return fmt_pair_count;
+}
+
+
+static int
+icvCalcElemSize( const char* dt, int initial_size )
+{
+    int size = 0;
+    int fmt_pairs[CV_FS_MAX_FMT_PAIRS], i, fmt_pair_count;
+    int comp_size;
+
+    fmt_pair_count = icvDecodeFormat( dt, fmt_pairs, CV_FS_MAX_FMT_PAIRS );
+    fmt_pair_count *= 2;
+    for( i = 0, size = initial_size; i < fmt_pair_count; i += 2 )
+    {
+        comp_size = CV_ELEM_SIZE(fmt_pairs[i+1]);
+        size = cvAlign( size, comp_size );
+        size += comp_size * fmt_pairs[i];
+    }
+    if( initial_size == 0 )
+    {
+        comp_size = CV_ELEM_SIZE(fmt_pairs[1]);
+        size = cvAlign( size, comp_size );
+    }
+    return size;
+}
+
+
+static int
+icvCalcStructSize( const char* dt, int initial_size )
+{
+    int size = icvCalcElemSize( dt, initial_size );
+    size_t elem_max_size = 0;
+    for ( const char * type = dt; *type != '\0'; type++ ) {
+        switch ( *type )
+        {
+        case 'u': { elem_max_size = std::max( elem_max_size, sizeof(uchar ) ); break; }
+        case 'c': { elem_max_size = std::max( elem_max_size, sizeof(schar ) ); break; }
+        case 'w': { elem_max_size = std::max( elem_max_size, sizeof(ushort) ); break; }
+        case 's': { elem_max_size = std::max( elem_max_size, sizeof(short ) ); break; }
+        case 'i': { elem_max_size = std::max( elem_max_size, sizeof(int   ) ); break; }
+        case 'f': { elem_max_size = std::max( elem_max_size, sizeof(float ) ); break; }
+        case 'd': { elem_max_size = std::max( elem_max_size, sizeof(double) ); break; }
+        default: break;
+        }
+    }
+    size = cvAlign( size, static_cast<int>(elem_max_size) );
+    return size;
+}
+
+
+static int
+icvDecodeSimpleFormat( const char* dt )
+{
+    int elem_type = -1;
+    int fmt_pairs[CV_FS_MAX_FMT_PAIRS], fmt_pair_count;
+
+    fmt_pair_count = icvDecodeFormat( dt, fmt_pairs, CV_FS_MAX_FMT_PAIRS );
+    if( fmt_pair_count != 1 || fmt_pairs[0] > 4 )
+        CV_Error( CV_StsError, "Too complex format for the matrix" );
+
+    elem_type = CV_MAKETYPE( fmt_pairs[1], fmt_pairs[0] );
+
+    return elem_type;
+}
+
+
+CV_IMPL void
+cvWriteRawData( CvFileStorage* fs, const void* _data, int len, const char* dt )
+{
+    if (fs->is_default_using_base64 ||
+        fs->state_of_writing_base64 == base64::fs::InUse )
+    {
+        base64::cvWriteRawDataBase64( fs, _data, len, dt );
+        return;
+    }
+    else if ( fs->state_of_writing_base64 == base64::fs::Uncertain )
+    {
+        switch_to_Base64_state( fs, base64::fs::NotUse );
+    }
+
+    const char* data0 = (const char*)_data;
+    int offset = 0;
+    int fmt_pairs[CV_FS_MAX_FMT_PAIRS*2], k, fmt_pair_count;
+    char buf[256] = "";
+
+    CV_CHECK_OUTPUT_FILE_STORAGE( fs );
+
+    if( len < 0 )
+        CV_Error( CV_StsOutOfRange, "Negative number of elements" );
+
+    fmt_pair_count = icvDecodeFormat( dt, fmt_pairs, CV_FS_MAX_FMT_PAIRS );
+
+    if( !len )
+        return;
+
+    if( !data0 )
+        CV_Error( CV_StsNullPtr, "Null data pointer" );
+
+    if( fmt_pair_count == 1 )
+    {
+        fmt_pairs[0] *= len;
+        len = 1;
+    }
+
+    for(;len--;)
+    {
+        for( k = 0; k < fmt_pair_count; k++ )
+        {
+            int i, count = fmt_pairs[k*2];
+            int elem_type = fmt_pairs[k*2+1];
+            int elem_size = CV_ELEM_SIZE(elem_type);
+            const char* data, *ptr;
+
+            offset = cvAlign( offset, elem_size );
+            data = data0 + offset;
+
+            for( i = 0; i < count; i++ )
+            {
+                switch( elem_type )
+                {
+                case CV_8U:
+                    ptr = icv_itoa( *(uchar*)data, buf, 10 );
+                    data++;
+                    break;
+                case CV_8S:
+                    ptr = icv_itoa( *(char*)data, buf, 10 );
+                    data++;
+                    break;
+                case CV_16U:
+                    ptr = icv_itoa( *(ushort*)data, buf, 10 );
+                    data += sizeof(ushort);
+                    break;
+                case CV_16S:
+                    ptr = icv_itoa( *(short*)data, buf, 10 );
+                    data += sizeof(short);
+                    break;
+                case CV_32S:
+                    ptr = icv_itoa( *(int*)data, buf, 10 );
+                    data += sizeof(int);
+                    break;
+                case CV_32F:
+                    ptr = icvFloatToString( buf, *(float*)data );
+                    data += sizeof(float);
+                    break;
+                case CV_64F:
+                    ptr = icvDoubleToString( buf, *(double*)data );
+                    data += sizeof(double);
+                    break;
+                case CV_USRTYPE1: /* reference */
+                    ptr = icv_itoa( (int)*(size_t*)data, buf, 10 );
+                    data += sizeof(size_t);
+                    break;
+                default:
+                    CV_Error( CV_StsUnsupportedFormat, "Unsupported type" );
+                    return;
+                }
+
+                if( fs->fmt == CV_STORAGE_FORMAT_XML )
+                {
+                    int buf_len = (int)strlen(ptr);
+                    icvXMLWriteScalar( fs, 0, ptr, buf_len );
+                }
+                else if ( fs->fmt == CV_STORAGE_FORMAT_YAML )
+                {
+                    icvYMLWrite( fs, 0, ptr );
+                }
+                else
+                {
+                    icvJSONWrite( fs, 0, ptr );
+                }
+            }
+
+            offset = (int)(data - data0);
+        }
+    }
+}
+
+
+CV_IMPL void
+cvStartReadRawData( const CvFileStorage* fs, const CvFileNode* src, CvSeqReader* reader )
+{
+    int node_type;
+    CV_CHECK_FILE_STORAGE( fs );
+
+    if( !src || !reader )
+        CV_Error( CV_StsNullPtr, "Null pointer to source file node or reader" );
+
+    node_type = CV_NODE_TYPE(src->tag);
+    if( node_type == CV_NODE_INT || node_type == CV_NODE_REAL )
+    {
+        // emulate reading from 1-element sequence
+        reader->ptr = (schar*)src;
+        reader->block_max = reader->ptr + sizeof(*src)*2;
+        reader->block_min = reader->ptr;
+        reader->seq = 0;
+    }
+    else if( node_type == CV_NODE_SEQ )
+    {
+        cvStartReadSeq( src->data.seq, reader, 0 );
+    }
+    else if( node_type == CV_NODE_NONE )
+    {
+        memset( reader, 0, sizeof(*reader) );
+    }
+    else
+        CV_Error( CV_StsBadArg, "The file node should be a numerical scalar or a sequence" );
+}
+
+
+CV_IMPL void
+cvReadRawDataSlice( const CvFileStorage* fs, CvSeqReader* reader,
+                    int len, void* _data, const char* dt )
+{
+    char* data0 = (char*)_data;
+    int fmt_pairs[CV_FS_MAX_FMT_PAIRS*2], k = 0, fmt_pair_count;
+    int i = 0, offset = 0, count = 0;
+
+    CV_CHECK_FILE_STORAGE( fs );
+
+    if( !reader || !data0 )
+        CV_Error( CV_StsNullPtr, "Null pointer to reader or destination array" );
+
+    if( !reader->seq && len != 1 )
+        CV_Error( CV_StsBadSize, "The readed sequence is a scalar, thus len must be 1" );
+
+    fmt_pair_count = icvDecodeFormat( dt, fmt_pairs, CV_FS_MAX_FMT_PAIRS );
+
+    for(;;)
+    {
+        for( k = 0; k < fmt_pair_count; k++ )
+        {
+            int elem_type = fmt_pairs[k*2+1];
+            int elem_size = CV_ELEM_SIZE(elem_type);
+            char* data;
+
+            count = fmt_pairs[k*2];
+            offset = cvAlign( offset, elem_size );
+            data = data0 + offset;
+
+            for( i = 0; i < count; i++ )
+            {
+                CvFileNode* node = (CvFileNode*)reader->ptr;
+                if( CV_NODE_IS_INT(node->tag) )
+                {
+                    int ival = node->data.i;
+
+                    switch( elem_type )
+                    {
+                    case CV_8U:
+                        *(uchar*)data = cv::saturate_cast<uchar>(ival);
+                        data++;
+                        break;
+                    case CV_8S:
+                        *(char*)data = cv::saturate_cast<schar>(ival);
+                        data++;
+                        break;
+                    case CV_16U:
+                        *(ushort*)data = cv::saturate_cast<ushort>(ival);
+                        data += sizeof(ushort);
+                        break;
+                    case CV_16S:
+                        *(short*)data = cv::saturate_cast<short>(ival);
+                        data += sizeof(short);
+                        break;
+                    case CV_32S:
+                        *(int*)data = ival;
+                        data += sizeof(int);
+                        break;
+                    case CV_32F:
+                        *(float*)data = (float)ival;
+                        data += sizeof(float);
+                        break;
+                    case CV_64F:
+                        *(double*)data = (double)ival;
+                        data += sizeof(double);
+                        break;
+                    case CV_USRTYPE1: /* reference */
+                        *(size_t*)data = ival;
+                        data += sizeof(size_t);
+                        break;
+                    default:
+                        CV_Error( CV_StsUnsupportedFormat, "Unsupported type" );
+                        return;
+                    }
+                }
+                else if( CV_NODE_IS_REAL(node->tag) )
+                {
+                    double fval = node->data.f;
+                    int ival;
+
+                    switch( elem_type )
+                    {
+                    case CV_8U:
+                        ival = cvRound(fval);
+                        *(uchar*)data = cv::saturate_cast<uchar>(ival);
+                        data++;
+                        break;
+                    case CV_8S:
+                        ival = cvRound(fval);
+                        *(char*)data = cv::saturate_cast<schar>(ival);
+                        data++;
+                        break;
+                    case CV_16U:
+                        ival = cvRound(fval);
+                        *(ushort*)data = cv::saturate_cast<ushort>(ival);
+                        data += sizeof(ushort);
+                        break;
+                    case CV_16S:
+                        ival = cvRound(fval);
+                        *(short*)data = cv::saturate_cast<short>(ival);
+                        data += sizeof(short);
+                        break;
+                    case CV_32S:
+                        ival = cvRound(fval);
+                        *(int*)data = ival;
+                        data += sizeof(int);
+                        break;
+                    case CV_32F:
+                        *(float*)data = (float)fval;
+                        data += sizeof(float);
+                        break;
+                    case CV_64F:
+                        *(double*)data = fval;
+                        data += sizeof(double);
+                        break;
+                    case CV_USRTYPE1: /* reference */
+                        ival = cvRound(fval);
+                        *(size_t*)data = ival;
+                        data += sizeof(size_t);
+                        break;
+                    default:
+                        CV_Error( CV_StsUnsupportedFormat, "Unsupported type" );
+                        return;
+                    }
+                }
+                else
+                    CV_Error( CV_StsError,
+                    "The sequence element is not a numerical scalar" );
+
+                CV_NEXT_SEQ_ELEM( sizeof(CvFileNode), *reader );
+                if( !--len )
+                    goto end_loop;
+            }
+
+            offset = (int)(data - data0);
+        }
+    }
+
+end_loop:
+    if( i != count - 1 || k != fmt_pair_count - 1 )
+        CV_Error( CV_StsBadSize,
+        "The sequence slice does not fit an integer number of records" );
+
+    if( !reader->seq )
+        reader->ptr -= sizeof(CvFileNode);
+}
+
+
+CV_IMPL void
+cvReadRawData( const CvFileStorage* fs, const CvFileNode* src,
+               void* data, const char* dt )
+{
+    CvSeqReader reader;
+
+    if( !src || !data )
+        CV_Error( CV_StsNullPtr, "Null pointers to source file node or destination array" );
+
+    cvStartReadRawData( fs, src, &reader );
+    cvReadRawDataSlice( fs, &reader, CV_NODE_IS_SEQ(src->tag) ?
+                        src->data.seq->total : 1, data, dt );
+}
+
+
+static void
+icvWriteFileNode( CvFileStorage* fs, const char* name, const CvFileNode* node );
+
+static void
+icvWriteCollection( CvFileStorage* fs, const CvFileNode* node )
+{
+    int i, total = node->data.seq->total;
+    int elem_size = node->data.seq->elem_size;
+    int is_map = CV_NODE_IS_MAP(node->tag);
+    CvSeqReader reader;
+
+    cvStartReadSeq( node->data.seq, &reader, 0 );
+
+    for( i = 0; i < total; i++ )
+    {
+        CvFileMapNode* elem = (CvFileMapNode*)reader.ptr;
+        if( !is_map || CV_IS_SET_ELEM(elem) )
+        {
+            const char* name = is_map ? elem->key->str.ptr : 0;
+            icvWriteFileNode( fs, name, &elem->value );
+        }
+        CV_NEXT_SEQ_ELEM( elem_size, reader );
+    }
+}
+
+static void
+icvWriteFileNode( CvFileStorage* fs, const char* name, const CvFileNode* node )
+{
+    switch( CV_NODE_TYPE(node->tag) )
+    {
+    case CV_NODE_INT:
+        fs->write_int( fs, name, node->data.i );
+        break;
+    case CV_NODE_REAL:
+        fs->write_real( fs, name, node->data.f );
+        break;
+    case CV_NODE_STR:
+        fs->write_string( fs, name, node->data.str.ptr, 0 );
+        break;
+    case CV_NODE_SEQ:
+    case CV_NODE_MAP:
+        cvStartWriteStruct( fs, name, CV_NODE_TYPE(node->tag) +
+                (CV_NODE_SEQ_IS_SIMPLE(node->data.seq) ? CV_NODE_FLOW : 0),
+                node->info ? node->info->type_name : 0 );
+        icvWriteCollection( fs, node );
+        cvEndWriteStruct( fs );
+        break;
+    case CV_NODE_NONE:
+        cvStartWriteStruct( fs, name, CV_NODE_SEQ, 0 );
+        cvEndWriteStruct( fs );
+        break;
+    default:
+        CV_Error( CV_StsBadFlag, "Unknown type of file node" );
+    }
+}
+
+
+CV_IMPL void
+cvWriteFileNode( CvFileStorage* fs, const char* new_node_name,
+                 const CvFileNode* node, int embed )
+{
+    CvFileStorage* dst = 0;
+    CV_CHECK_OUTPUT_FILE_STORAGE(fs);
+
+    if( !node )
+        return;
+
+    if( CV_NODE_IS_COLLECTION(node->tag) && embed )
+    {
+        icvWriteCollection( fs, node );
+    }
+    else
+    {
+        icvWriteFileNode( fs, new_node_name, node );
+    }
+    /*
+    int i, stream_count;
+    stream_count = fs->roots->total;
+    for( i = 0; i < stream_count; i++ )
+    {
+        CvFileNode* node = (CvFileNode*)cvGetSeqElem( fs->roots, i, 0 );
+        icvDumpCollection( dst, node );
+        if( i < stream_count - 1 )
+            dst->start_next_stream( dst );
+    }*/
+    cvReleaseFileStorage( &dst );
+}
+
+
+CV_IMPL const char*
+cvGetFileNodeName( const CvFileNode* file_node )
+{
+    return file_node && CV_NODE_HAS_NAME(file_node->tag) ?
+        ((CvFileMapNode*)file_node)->key->str.ptr : 0;
+}
+
+/****************************************************************************************\
+*                          Reading/Writing etc. for standard types                       *
+\****************************************************************************************/
+
+/*#define CV_TYPE_NAME_MAT "opencv-matrix"
+#define CV_TYPE_NAME_MATND "opencv-nd-matrix"
+#define CV_TYPE_NAME_SPARSE_MAT "opencv-sparse-matrix"
+#define CV_TYPE_NAME_IMAGE "opencv-image"
+#define CV_TYPE_NAME_SEQ "opencv-sequence"
+#define CV_TYPE_NAME_SEQ_TREE "opencv-sequence-tree"
+#define CV_TYPE_NAME_GRAPH "opencv-graph"*/
+
+/******************************* CvMat ******************************/
+
+static int
+icvIsMat( const void* ptr )
+{
+    return CV_IS_MAT_HDR_Z(ptr);
+}
+
+static void
+icvWriteMat( CvFileStorage* fs, const char* name,
+             const void* struct_ptr, CvAttrList /*attr*/ )
+{
+    const CvMat* mat = (const CvMat*)struct_ptr;
+    char dt[16];
+    CvSize size;
+    int y;
+
+    assert( CV_IS_MAT_HDR_Z(mat) );
+
+    cvStartWriteStruct( fs, name, CV_NODE_MAP, CV_TYPE_NAME_MAT );
+    cvWriteInt( fs, "rows", mat->rows );
+    cvWriteInt( fs, "cols", mat->cols );
+    cvWriteString( fs, "dt", icvEncodeFormat( CV_MAT_TYPE(mat->type), dt ), 0 );
+    cvStartWriteStruct( fs, "data", CV_NODE_SEQ + CV_NODE_FLOW );
+
+    size = cvGetSize(mat);
+    if( size.height > 0 && size.width > 0 && mat->data.ptr )
+    {
+        if( CV_IS_MAT_CONT(mat->type) )
+        {
+            size.width *= size.height;
+            size.height = 1;
+        }
+
+        for( y = 0; y < size.height; y++ )
+            cvWriteRawData( fs, mat->data.ptr + (size_t)y*mat->step, size.width, dt );
+    }
+    cvEndWriteStruct( fs );
+    cvEndWriteStruct( fs );
+}
+
+
+static int
+icvFileNodeSeqLen( CvFileNode* node )
+{
+    return CV_NODE_IS_COLLECTION(node->tag) ? node->data.seq->total :
+        CV_NODE_TYPE(node->tag) != CV_NODE_NONE;
+}
+
+
+static void*
 icvReadMat( CvFileStorage* fs, CvFileNode* node )
 {
     void* ptr = 0;
-    CvMat* mat;
+    CvMat* mat;
+    const char* dt;
+    CvFileNode* data;
+    int rows, cols, elem_type;
+
+    rows = cvReadIntByName( fs, node, "rows", -1 );
+    cols = cvReadIntByName( fs, node, "cols", -1 );
+    dt = cvReadStringByName( fs, node, "dt", 0 );
+
+    if( rows < 0 || cols < 0 || !dt )
+        CV_Error( CV_StsError, "Some of essential matrix attributes are absent" );
+
+    elem_type = icvDecodeSimpleFormat( dt );
+
+    data = cvGetFileNodeByName( fs, node, "data" );
+    if( !data )
+        CV_Error( CV_StsError, "The matrix data is not found in file storage" );
+
+    int nelems = icvFileNodeSeqLen( data );
+    if( nelems > 0 && nelems != rows*cols*CV_MAT_CN(elem_type) )
+        CV_Error( CV_StsUnmatchedSizes,
+                 "The matrix size does not match to the number of stored elements" );
+
+    if( nelems > 0 )
+    {
+        mat = cvCreateMat( rows, cols, elem_type );
+        cvReadRawData( fs, data, mat->data.ptr, dt );
+    }
+    else
+        mat = cvCreateMatHeader( rows, cols, elem_type );
+
+    ptr = mat;
+    return ptr;
+}
+
+
+/******************************* CvMatND ******************************/
+
+static int
+icvIsMatND( const void* ptr )
+{
+    return CV_IS_MATND_HDR(ptr);
+}
+
+
+static void
+icvWriteMatND( CvFileStorage* fs, const char* name,
+               const void* struct_ptr, CvAttrList /*attr*/ )
+{
+    CvMatND* mat = (CvMatND*)struct_ptr;
+    CvMatND stub;
+    CvNArrayIterator iterator;
+    int dims, sizes[CV_MAX_DIM];
+    char dt[16];
+
+    assert( CV_IS_MATND_HDR(mat) );
+
+    cvStartWriteStruct( fs, name, CV_NODE_MAP, CV_TYPE_NAME_MATND );
+    dims = cvGetDims( mat, sizes );
+    cvStartWriteStruct( fs, "sizes", CV_NODE_SEQ + CV_NODE_FLOW );
+    cvWriteRawData( fs, sizes, dims, "i" );
+    cvEndWriteStruct( fs );
+    cvWriteString( fs, "dt", icvEncodeFormat( cvGetElemType(mat), dt ), 0 );
+    cvStartWriteStruct( fs, "data", CV_NODE_SEQ + CV_NODE_FLOW );
+
+    if( mat->dim[0].size > 0 && mat->data.ptr )
+    {
+        cvInitNArrayIterator( 1, (CvArr**)&mat, 0, &stub, &iterator );
+
+        do
+            cvWriteRawData( fs, iterator.ptr[0], iterator.size.width, dt );
+        while( cvNextNArraySlice( &iterator ));
+    }
+    cvEndWriteStruct( fs );
+    cvEndWriteStruct( fs );
+}
+
+
+static void*
+icvReadMatND( CvFileStorage* fs, CvFileNode* node )
+{
+    void* ptr = 0;
+    CvMatND* mat;
+    const char* dt;
+    CvFileNode* data;
+    CvFileNode* sizes_node;
+    int sizes[CV_MAX_DIM], dims, elem_type;
+    int i, total_size;
+
+    sizes_node = cvGetFileNodeByName( fs, node, "sizes" );
+    dt = cvReadStringByName( fs, node, "dt", 0 );
+
+    if( !sizes_node || !dt )
+        CV_Error( CV_StsError, "Some of essential matrix attributes are absent" );
+
+    dims = CV_NODE_IS_SEQ(sizes_node->tag) ? sizes_node->data.seq->total :
+           CV_NODE_IS_INT(sizes_node->tag) ? 1 : -1;
+
+    if( dims <= 0 || dims > CV_MAX_DIM )
+        CV_Error( CV_StsParseError, "Could not determine the matrix dimensionality" );
+
+    cvReadRawData( fs, sizes_node, sizes, "i" );
+    elem_type = icvDecodeSimpleFormat( dt );
+
+    data = cvGetFileNodeByName( fs, node, "data" );
+    if( !data )
+        CV_Error( CV_StsError, "The matrix data is not found in file storage" );
+
+
+
+    for( total_size = CV_MAT_CN(elem_type), i = 0; i < dims; i++ )
+        total_size *= sizes[i];
+
+    int nelems = icvFileNodeSeqLen( data );
+
+    if( nelems > 0 && nelems != total_size )
+        CV_Error( CV_StsUnmatchedSizes,
+                 "The matrix size does not match to the number of stored elements" );
+
+    if( nelems > 0 )
+    {
+        mat = cvCreateMatND( dims, sizes, elem_type );
+        cvReadRawData( fs, data, mat->data.ptr, dt );
+    }
+    else
+        mat = cvCreateMatNDHeader( dims, sizes, elem_type );
+
+    ptr = mat;
+    return ptr;
+}
+
+
+/******************************* CvSparseMat ******************************/
+
+static int
+icvIsSparseMat( const void* ptr )
+{
+    return CV_IS_SPARSE_MAT(ptr);
+}
+
+
+static int
+icvSortIdxCmpFunc( const void* _a, const void* _b, void* userdata )
+{
+    int i, dims = *(int*)userdata;
+    const int* a = *(const int**)_a;
+    const int* b = *(const int**)_b;
+
+    for( i = 0; i < dims; i++ )
+    {
+        int delta = a[i] - b[i];
+        if( delta )
+            return delta;
+    }
+
+    return 0;
+}
+
+
+static void
+icvWriteSparseMat( CvFileStorage* fs, const char* name,
+                   const void* struct_ptr, CvAttrList /*attr*/ )
+{
+    CvMemStorage* memstorage = 0;
+    const CvSparseMat* mat = (const CvSparseMat*)struct_ptr;
+    CvSparseMatIterator iterator;
+    CvSparseNode* node;
+    CvSeq* elements;
+    CvSeqReader reader;
+    int i, dims;
+    int *prev_idx = 0;
+    char dt[16];
+
+    assert( CV_IS_SPARSE_MAT(mat) );
+
+    memstorage = cvCreateMemStorage();
+
+    cvStartWriteStruct( fs, name, CV_NODE_MAP, CV_TYPE_NAME_SPARSE_MAT );
+    dims = cvGetDims( mat, 0 );
+
+    cvStartWriteStruct( fs, "sizes", CV_NODE_SEQ + CV_NODE_FLOW );
+    cvWriteRawData( fs, mat->size, dims, "i" );
+    cvEndWriteStruct( fs );
+    cvWriteString( fs, "dt", icvEncodeFormat( CV_MAT_TYPE(mat->type), dt ), 0 );
+    cvStartWriteStruct( fs, "data", CV_NODE_SEQ + CV_NODE_FLOW );
+
+    elements = cvCreateSeq( CV_SEQ_ELTYPE_PTR, sizeof(CvSeq), sizeof(int*), memstorage );
+
+    node = cvInitSparseMatIterator( mat, &iterator );
+    while( node )
+    {
+        int* idx = CV_NODE_IDX( mat, node );
+        cvSeqPush( elements, &idx );
+        node = cvGetNextSparseNode( &iterator );
+    }
+
+    cvSeqSort( elements, icvSortIdxCmpFunc, &dims );
+    cvStartReadSeq( elements, &reader, 0 );
+
+    for( i = 0; i < elements->total; i++ )
+    {
+        int* idx;
+        void* val;
+        int k = 0;
+
+        CV_READ_SEQ_ELEM( idx, reader );
+        if( i > 0 )
+        {
+            for( ; idx[k] == prev_idx[k]; k++ )
+                assert( k < dims );
+            if( k < dims - 1 )
+                fs->write_int( fs, 0, k - dims + 1 );
+        }
+        for( ; k < dims; k++ )
+            fs->write_int( fs, 0, idx[k] );
+        prev_idx = idx;
+
+        node = (CvSparseNode*)((uchar*)idx - mat->idxoffset );
+        val = CV_NODE_VAL( mat, node );
+
+        cvWriteRawData( fs, val, 1, dt );
+    }
+
+    cvEndWriteStruct( fs );
+    cvEndWriteStruct( fs );
+    cvReleaseMemStorage( &memstorage );
+}
+
+
+static void*
+icvReadSparseMat( CvFileStorage* fs, CvFileNode* node )
+{
+    void* ptr = 0;
+    CvSparseMat* mat;
+    const char* dt;
+    CvFileNode* data;
+    CvFileNode* sizes_node;
+    CvSeqReader reader;
+    CvSeq* elements;
+    int sizes[CV_MAX_DIM_HEAP], dims, elem_type, cn;
+    int i;
+
+    sizes_node = cvGetFileNodeByName( fs, node, "sizes" );
+    dt = cvReadStringByName( fs, node, "dt", 0 );
+
+    if( !sizes_node || !dt )
+        CV_Error( CV_StsError, "Some of essential matrix attributes are absent" );
+
+    dims = CV_NODE_IS_SEQ(sizes_node->tag) ? sizes_node->data.seq->total :
+           CV_NODE_IS_INT(sizes_node->tag) ? 1 : -1;
+
+    if( dims <= 0 || dims > CV_MAX_DIM_HEAP )
+        CV_Error( CV_StsParseError, "Could not determine sparse matrix dimensionality" );
+
+    cvReadRawData( fs, sizes_node, sizes, "i" );
+    elem_type = icvDecodeSimpleFormat( dt );
+
+    data = cvGetFileNodeByName( fs, node, "data" );
+    if( !data || !CV_NODE_IS_SEQ(data->tag) )
+        CV_Error( CV_StsError, "The matrix data is not found in file storage" );
+
+    mat = cvCreateSparseMat( dims, sizes, elem_type );
+
+    cn = CV_MAT_CN(elem_type);
+    int idx[CV_MAX_DIM_HEAP];
+    elements = data->data.seq;
+    cvStartReadRawData( fs, data, &reader );
+
+    for( i = 0; i < elements->total; )
+    {
+        CvFileNode* elem = (CvFileNode*)reader.ptr;
+        uchar* val;
+        int k;
+        if( !CV_NODE_IS_INT(elem->tag ))
+            CV_Error( CV_StsParseError, "Sparse matrix data is corrupted" );
+        k = elem->data.i;
+        if( i > 0 && k >= 0 )
+            idx[dims-1] = k;
+        else
+        {
+            if( i > 0 )
+                k = dims + k - 1;
+            else
+                idx[0] = k, k = 1;
+            for( ; k < dims; k++ )
+            {
+                CV_NEXT_SEQ_ELEM( elements->elem_size, reader );
+                i++;
+                elem = (CvFileNode*)reader.ptr;
+                if( !CV_NODE_IS_INT(elem->tag ) || elem->data.i < 0 )
+                    CV_Error( CV_StsParseError, "Sparse matrix data is corrupted" );
+                idx[k] = elem->data.i;
+            }
+        }
+        CV_NEXT_SEQ_ELEM( elements->elem_size, reader );
+        i++;
+        val = cvPtrND( mat, idx, 0, 1, 0 );
+        cvReadRawDataSlice( fs, &reader, cn, val, dt );
+        i += cn;
+    }
+
+    ptr = mat;
+    return ptr;
+}
+
+
+/******************************* IplImage ******************************/
+
+static int
+icvIsImage( const void* ptr )
+{
+    return CV_IS_IMAGE_HDR(ptr);
+}
+
+static void
+icvWriteImage( CvFileStorage* fs, const char* name,
+               const void* struct_ptr, CvAttrList /*attr*/ )
+{
+    const IplImage* image = (const IplImage*)struct_ptr;
+    char dt_buf[16], *dt;
+    CvSize size;
+    int y, depth;
+
+    assert( CV_IS_IMAGE(image) );
+
+    if( image->dataOrder == IPL_DATA_ORDER_PLANE )
+        CV_Error( CV_StsUnsupportedFormat,
+        "Images with planar data layout are not supported" );
+
+    cvStartWriteStruct( fs, name, CV_NODE_MAP, CV_TYPE_NAME_IMAGE );
+    cvWriteInt( fs, "width", image->width );
+    cvWriteInt( fs, "height", image->height );
+    cvWriteString( fs, "origin", image->origin == IPL_ORIGIN_TL
+                   ? "top-left" : "bottom-left", 0 );
+    cvWriteString( fs, "layout", image->dataOrder == IPL_DATA_ORDER_PLANE
+                   ? "planar" : "interleaved", 0 );
+    if( image->roi )
+    {
+        cvStartWriteStruct( fs, "roi", CV_NODE_MAP + CV_NODE_FLOW );
+        cvWriteInt( fs, "x", image->roi->xOffset );
+        cvWriteInt( fs, "y", image->roi->yOffset );
+        cvWriteInt( fs, "width", image->roi->width );
+        cvWriteInt( fs, "height", image->roi->height );
+        cvWriteInt( fs, "coi", image->roi->coi );
+        cvEndWriteStruct( fs );
+    }
+
+    depth = IPL2CV_DEPTH(image->depth);
+    sprintf( dt_buf, "%d%c", image->nChannels, icvTypeSymbol[depth] );
+    dt = dt_buf + (dt_buf[2] == '\0' && dt_buf[0] == '1');
+    cvWriteString( fs, "dt", dt, 0 );
+
+    size = cvSize(image->width, image->height);
+    if( size.width*image->nChannels*CV_ELEM_SIZE(depth) == image->widthStep )
+    {
+        size.width *= size.height;
+        size.height = 1;
+    }
+
+    cvStartWriteStruct( fs, "data", CV_NODE_SEQ + CV_NODE_FLOW );
+    for( y = 0; y < size.height; y++ )
+        cvWriteRawData( fs, image->imageData + y*image->widthStep, size.width, dt );
+    cvEndWriteStruct( fs );
+    cvEndWriteStruct( fs );
+}
+
+
+static void*
+icvReadImage( CvFileStorage* fs, CvFileNode* node )
+{
+    void* ptr = 0;
+    IplImage* image;
+    const char* dt;
+    CvFileNode* data;
+    CvFileNode* roi_node;
+    CvSeqReader reader;
+    CvRect roi;
+    int y, width, height, elem_type, coi, depth;
+    const char* origin, *data_order;
+
+    width = cvReadIntByName( fs, node, "width", 0 );
+    height = cvReadIntByName( fs, node, "height", 0 );
+    dt = cvReadStringByName( fs, node, "dt", 0 );
+    origin = cvReadStringByName( fs, node, "origin", 0 );
+
+    if( width == 0 || height == 0 || dt == 0 || origin == 0 )
+        CV_Error( CV_StsError, "Some of essential image attributes are absent" );
+
+    elem_type = icvDecodeSimpleFormat( dt );
+    data_order = cvReadStringByName( fs, node, "layout", "interleaved" );
+    if( strcmp( data_order, "interleaved" ) != 0 )
+        CV_Error( CV_StsError, "Only interleaved images can be read" );
+
+    data = cvGetFileNodeByName( fs, node, "data" );
+    if( !data )
+        CV_Error( CV_StsError, "The image data is not found in file storage" );
+
+    if( icvFileNodeSeqLen( data ) != width*height*CV_MAT_CN(elem_type) )
+        CV_Error( CV_StsUnmatchedSizes,
+        "The matrix size does not match to the number of stored elements" );
+
+    depth = cvIplDepth(elem_type);
+    image = cvCreateImage( cvSize(width,height), depth, CV_MAT_CN(elem_type) );
+
+    roi_node = cvGetFileNodeByName( fs, node, "roi" );
+    if( roi_node )
+    {
+        roi.x = cvReadIntByName( fs, roi_node, "x", 0 );
+        roi.y = cvReadIntByName( fs, roi_node, "y", 0 );
+        roi.width = cvReadIntByName( fs, roi_node, "width", 0 );
+        roi.height = cvReadIntByName( fs, roi_node, "height", 0 );
+        coi = cvReadIntByName( fs, roi_node, "coi", 0 );
+
+        cvSetImageROI( image, roi );
+        cvSetImageCOI( image, coi );
+    }
+
+    if( width*CV_ELEM_SIZE(elem_type) == image->widthStep )
+    {
+        width *= height;
+        height = 1;
+    }
+
+    width *= CV_MAT_CN(elem_type);
+    cvStartReadRawData( fs, data, &reader );
+    for( y = 0; y < height; y++ )
+    {
+        cvReadRawDataSlice( fs, &reader, width,
+            image->imageData + y*image->widthStep, dt );
+    }
+
+    ptr = image;
+    return ptr;
+}
+
+
+/******************************* CvSeq ******************************/
+
+static int
+icvIsSeq( const void* ptr )
+{
+    return CV_IS_SEQ(ptr);
+}
+
+
+static void
+icvReleaseSeq( void** ptr )
+{
+    if( !ptr )
+        CV_Error( CV_StsNullPtr, "NULL double pointer" );
+    *ptr = 0; // it's impossible now to release seq, so just clear the pointer
+}
+
+
+static void*
+icvCloneSeq( const void* ptr )
+{
+    return cvSeqSlice( (CvSeq*)ptr, CV_WHOLE_SEQ,
+                       0 /* use the same storage as for the original sequence */, 1 );
+}
+
+
+static void
+icvWriteHeaderData( CvFileStorage* fs, const CvSeq* seq,
+                    CvAttrList* attr, int initial_header_size )
+{
+    char header_dt_buf[128];
+    const char* header_dt = cvAttrValue( attr, "header_dt" );
+
+    if( header_dt )
+    {
+        int dt_header_size;
+        dt_header_size = icvCalcElemSize( header_dt, initial_header_size );
+        if( dt_header_size > seq->header_size )
+            CV_Error( CV_StsUnmatchedSizes,
+            "The size of header calculated from \"header_dt\" is greater than header_size" );
+    }
+    else if( seq->header_size > initial_header_size )
+    {
+        if( CV_IS_SEQ(seq) && CV_IS_SEQ_POINT_SET(seq) &&
+            seq->header_size == sizeof(CvPoint2DSeq) &&
+            seq->elem_size == sizeof(int)*2 )
+        {
+            CvPoint2DSeq* point_seq = (CvPoint2DSeq*)seq;
+
+            cvStartWriteStruct( fs, "rect", CV_NODE_MAP + CV_NODE_FLOW );
+            cvWriteInt( fs, "x", point_seq->rect.x );
+            cvWriteInt( fs, "y", point_seq->rect.y );
+            cvWriteInt( fs, "width", point_seq->rect.width );
+            cvWriteInt( fs, "height", point_seq->rect.height );
+            cvEndWriteStruct( fs );
+            cvWriteInt( fs, "color", point_seq->color );
+        }
+        else if( CV_IS_SEQ(seq) && CV_IS_SEQ_CHAIN(seq) &&
+                 CV_MAT_TYPE(seq->flags) == CV_8UC1 )
+        {
+            CvChain* chain = (CvChain*)seq;
+
+            cvStartWriteStruct( fs, "origin", CV_NODE_MAP + CV_NODE_FLOW );
+            cvWriteInt( fs, "x", chain->origin.x );
+            cvWriteInt( fs, "y", chain->origin.y );
+            cvEndWriteStruct( fs );
+        }
+        else
+        {
+            unsigned extra_size = seq->header_size - initial_header_size;
+            // a heuristic to provide nice defaults for sequences of int's & float's
+            if( extra_size % sizeof(int) == 0 )
+                sprintf( header_dt_buf, "%ui", (unsigned)(extra_size/sizeof(int)) );
+            else
+                sprintf( header_dt_buf, "%uu", extra_size );
+            header_dt = header_dt_buf;
+        }
+    }
+
+    if( header_dt )
+    {
+        cvWriteString( fs, "header_dt", header_dt, 0 );
+        cvStartWriteStruct( fs, "header_user_data", CV_NODE_SEQ + CV_NODE_FLOW );
+        cvWriteRawData( fs, (uchar*)seq + sizeof(CvSeq), 1, header_dt );
+        cvEndWriteStruct( fs );
+    }
+}
+
+
+static char*
+icvGetFormat( const CvSeq* seq, const char* dt_key, CvAttrList* attr,
+              int initial_elem_size, char* dt_buf )
+{
+    char* dt = 0;
+    dt = (char*)cvAttrValue( attr, dt_key );
+
+    if( dt )
+    {
+        int dt_elem_size;
+        dt_elem_size = icvCalcElemSize( dt, initial_elem_size );
+        if( dt_elem_size != seq->elem_size )
+            CV_Error( CV_StsUnmatchedSizes,
+            "The size of element calculated from \"dt\" and "
+            "the elem_size do not match" );
+    }
+    else if( CV_MAT_TYPE(seq->flags) != 0 || seq->elem_size == 1 )
+    {
+        if( CV_ELEM_SIZE(seq->flags) != seq->elem_size )
+            CV_Error( CV_StsUnmatchedSizes,
+            "Size of sequence element (elem_size) is inconsistent with seq->flags" );
+        dt = icvEncodeFormat( CV_MAT_TYPE(seq->flags), dt_buf );
+    }
+    else if( seq->elem_size > initial_elem_size )
+    {
+        unsigned extra_elem_size = seq->elem_size - initial_elem_size;
+        // a heuristic to provide nice defaults for sequences of int's & float's
+        if( extra_elem_size % sizeof(int) == 0 )
+            sprintf( dt_buf, "%ui", (unsigned)(extra_elem_size/sizeof(int)) );
+        else
+            sprintf( dt_buf, "%uu", extra_elem_size );
+        dt = dt_buf;
+    }
+
+    return dt;
+}
+
+
+static void
+icvWriteSeq( CvFileStorage* fs, const char* name,
+             const void* struct_ptr,
+             CvAttrList attr, int level )
+{
+    const CvSeq* seq = (CvSeq*)struct_ptr;
+    CvSeqBlock* block;
+    char buf[128];
+    char dt_buf[128], *dt;
+
+    assert( CV_IS_SEQ( seq ));
+    cvStartWriteStruct( fs, name, CV_NODE_MAP, CV_TYPE_NAME_SEQ );
+
+    if( level >= 0 )
+        cvWriteInt( fs, "level", level );
+
+    dt = icvGetFormat( seq, "dt", &attr, 0, dt_buf );
+
+    strcpy(buf, "");
+    if( CV_IS_SEQ_CLOSED(seq) )
+        strcat(buf, " closed");
+    if( CV_IS_SEQ_HOLE(seq) )
+        strcat(buf, " hole");
+    if( CV_IS_SEQ_CURVE(seq) )
+        strcat(buf, " curve");
+    if( CV_SEQ_ELTYPE(seq) == 0 && seq->elem_size != 1 )
+        strcat(buf, " untyped");
+
+    cvWriteString( fs, "flags", buf + (buf[0] ? 1 : 0), 1 );
+
+    cvWriteInt( fs, "count", seq->total );
+
+    cvWriteString( fs, "dt", dt, 0 );
+
+    icvWriteHeaderData( fs, seq, &attr, sizeof(CvSeq) );
+    cvStartWriteStruct( fs, "data", CV_NODE_SEQ + CV_NODE_FLOW );
+
+    for( block = seq->first; block; block = block->next )
+    {
+        cvWriteRawData( fs, block->data, block->count, dt );
+        if( block == seq->first->prev )
+            break;
+    }
+    cvEndWriteStruct( fs );
+    cvEndWriteStruct( fs );
+}
+
+
+static void
+icvWriteSeqTree( CvFileStorage* fs, const char* name,
+                 const void* struct_ptr, CvAttrList attr )
+{
+    const CvSeq* seq = (CvSeq*)struct_ptr;
+    const char* recursive_value = cvAttrValue( &attr, "recursive" );
+    int is_recursive = recursive_value &&
+                       strcmp(recursive_value,"0") != 0 &&
+                       strcmp(recursive_value,"false") != 0 &&
+                       strcmp(recursive_value,"False") != 0 &&
+                       strcmp(recursive_value,"FALSE") != 0;
+
+    assert( CV_IS_SEQ( seq ));
+
+    if( !is_recursive )
+    {
+        icvWriteSeq( fs, name, seq, attr, -1 );
+    }
+    else
+    {
+        CvTreeNodeIterator tree_iterator;
+
+        cvStartWriteStruct( fs, name, CV_NODE_MAP, CV_TYPE_NAME_SEQ_TREE );
+        cvStartWriteStruct( fs, "sequences", CV_NODE_SEQ );
+        cvInitTreeNodeIterator( &tree_iterator, seq, INT_MAX );
+
+        for(;;)
+        {
+            if( !tree_iterator.node )
+                break;
+            icvWriteSeq( fs, 0, tree_iterator.node, attr, tree_iterator.level );
+            cvNextTreeNode( &tree_iterator );
+        }
+
+        cvEndWriteStruct( fs );
+        cvEndWriteStruct( fs );
+    }
+}
+
+
+static void*
+icvReadSeq( CvFileStorage* fs, CvFileNode* node )
+{
+    void* ptr = 0;
+    CvSeq* seq;
+    CvSeqBlock* block;
+    CvFileNode *data, *header_node, *rect_node, *origin_node;
+    CvSeqReader reader;
+    int total, flags;
+    int elem_size, header_size = sizeof(CvSeq);
+    int fmt_pairs[CV_FS_MAX_FMT_PAIRS], i, fmt_pair_count;
+    int items_per_elem = 0;
+    const char* flags_str;
+    const char* header_dt;
     const char* dt;
-    CvFileNode* data;
-    int rows, cols, elem_type;
+    char* endptr = 0;
 
-    rows = cvReadIntByName( fs, node, "rows", -1 );
-    cols = cvReadIntByName( fs, node, "cols", -1 );
+    flags_str = cvReadStringByName( fs, node, "flags", 0 );
+    total = cvReadIntByName( fs, node, "count", -1 );
     dt = cvReadStringByName( fs, node, "dt", 0 );
 
-    if( rows < 0 || cols < 0 || !dt )
-        CV_Error( CV_StsError, "Some of essential matrix attributes are absent" );
+    if( !flags_str || total == -1 || !dt )
+        CV_Error( CV_StsError, "Some of essential sequence attributes are absent" );
+
+    flags = CV_SEQ_MAGIC_VAL;
+
+    if( cv_isdigit(flags_str[0]) )
+    {
+        const int OLD_SEQ_ELTYPE_BITS = 9;
+        const int OLD_SEQ_ELTYPE_MASK = (1 << OLD_SEQ_ELTYPE_BITS) - 1;
+        const int OLD_SEQ_KIND_BITS = 3;
+        const int OLD_SEQ_KIND_MASK = ((1 << OLD_SEQ_KIND_BITS) - 1) << OLD_SEQ_ELTYPE_BITS;
+        const int OLD_SEQ_KIND_CURVE = 1 << OLD_SEQ_ELTYPE_BITS;
+        const int OLD_SEQ_FLAG_SHIFT = OLD_SEQ_KIND_BITS + OLD_SEQ_ELTYPE_BITS;
+        const int OLD_SEQ_FLAG_CLOSED = 1 << OLD_SEQ_FLAG_SHIFT;
+        const int OLD_SEQ_FLAG_HOLE = 8 << OLD_SEQ_FLAG_SHIFT;
+
+        int flags0 = (int)strtol( flags_str, &endptr, 16 );
+        if( endptr == flags_str || (flags0 & CV_MAGIC_MASK) != CV_SEQ_MAGIC_VAL )
+            CV_Error( CV_StsError, "The sequence flags are invalid" );
+        if( (flags0 & OLD_SEQ_KIND_MASK) == OLD_SEQ_KIND_CURVE )
+            flags |= CV_SEQ_KIND_CURVE;
+        if( flags0 & OLD_SEQ_FLAG_CLOSED )
+            flags |= CV_SEQ_FLAG_CLOSED;
+        if( flags0 & OLD_SEQ_FLAG_HOLE )
+            flags |= CV_SEQ_FLAG_HOLE;
+        flags |= flags0 & OLD_SEQ_ELTYPE_MASK;
+    }
+    else
+    {
+        if( strstr(flags_str, "curve") )
+            flags |= CV_SEQ_KIND_CURVE;
+        if( strstr(flags_str, "closed") )
+            flags |= CV_SEQ_FLAG_CLOSED;
+        if( strstr(flags_str, "hole") )
+            flags |= CV_SEQ_FLAG_HOLE;
+        if( !strstr(flags_str, "untyped") )
+        {
+            try
+            {
+                flags |= icvDecodeSimpleFormat(dt);
+            }
+            catch(...)
+            {
+            }
+        }
+    }
+
+    header_dt = cvReadStringByName( fs, node, "header_dt", 0 );
+    header_node = cvGetFileNodeByName( fs, node, "header_user_data" );
+
+    if( (header_dt != 0) ^ (header_node != 0) )
+        CV_Error( CV_StsError,
+        "One of \"header_dt\" and \"header_user_data\" is there, while the other is not" );
+
+    rect_node = cvGetFileNodeByName( fs, node, "rect" );
+    origin_node = cvGetFileNodeByName( fs, node, "origin" );
+
+    if( (header_node != 0) + (rect_node != 0) + (origin_node != 0) > 1 )
+        CV_Error( CV_StsError, "Only one of \"header_user_data\", \"rect\" and \"origin\" tags may occur" );
+
+    if( header_dt )
+    {
+        header_size = icvCalcElemSize( header_dt, header_size );
+    }
+    else if( rect_node )
+        header_size = sizeof(CvPoint2DSeq);
+    else if( origin_node )
+        header_size = sizeof(CvChain);
+
+    elem_size = icvCalcElemSize( dt, 0 );
+    seq = cvCreateSeq( flags, header_size, elem_size, fs->dststorage );
+
+    if( header_node )
+    {
+        cvReadRawData( fs, header_node, (char*)seq + sizeof(CvSeq), header_dt );
+    }
+    else if( rect_node )
+    {
+        CvPoint2DSeq* point_seq = (CvPoint2DSeq*)seq;
+        point_seq->rect.x = cvReadIntByName( fs, rect_node, "x", 0 );
+        point_seq->rect.y = cvReadIntByName( fs, rect_node, "y", 0 );
+        point_seq->rect.width = cvReadIntByName( fs, rect_node, "width", 0 );
+        point_seq->rect.height = cvReadIntByName( fs, rect_node, "height", 0 );
+        point_seq->color = cvReadIntByName( fs, node, "color", 0 );
+    }
+    else if( origin_node )
+    {
+        CvChain* chain = (CvChain*)seq;
+        chain->origin.x = cvReadIntByName( fs, origin_node, "x", 0 );
+        chain->origin.y = cvReadIntByName( fs, origin_node, "y", 0 );
+    }
 
-    elem_type = icvDecodeSimpleFormat( dt );
+    cvSeqPushMulti( seq, 0, total, 0 );
+    fmt_pair_count = icvDecodeFormat( dt, fmt_pairs, CV_FS_MAX_FMT_PAIRS );
+    fmt_pair_count *= 2;
+    for( i = 0; i < fmt_pair_count; i += 2 )
+        items_per_elem += fmt_pairs[i];
 
     data = cvGetFileNodeByName( fs, node, "data" );
     if( !data )
-        CV_Error( CV_StsError, "The matrix data is not found in file storage" );
+        CV_Error( CV_StsError, "The image data is not found in file storage" );
 
-    int nelems = icvFileNodeSeqLen( data );
-    if( nelems > 0 && nelems != rows*cols*CV_MAT_CN(elem_type) )
-        CV_Error( CV_StsUnmatchedSizes,
-                 "The matrix size does not match to the number of stored elements" );
+    if( icvFileNodeSeqLen( data ) != total*items_per_elem )
+        CV_Error( CV_StsError, "The number of stored elements does not match to \"count\"" );
 
-    if( nelems > 0 )
+    cvStartReadRawData( fs, data, &reader );
+    for( block = seq->first; block; block = block->next )
     {
-        mat = cvCreateMat( rows, cols, elem_type );
-        cvReadRawData( fs, data, mat->data.ptr, dt );
+        int delta = block->count*items_per_elem;
+        cvReadRawDataSlice( fs, &reader, delta, block->data, dt );
+        if( block == seq->first->prev )
+            break;
     }
-    else if( rows == 0 && cols == 0 )
-        mat = cvCreateMatHeader( 0, 1, elem_type );
-    else
-        mat = cvCreateMatHeader( rows, cols, elem_type );
 
-    ptr = mat;
+    ptr = seq;
     return ptr;
 }
 
 
-/******************************* CvMatND ******************************/
+static void*
+icvReadSeqTree( CvFileStorage* fs, CvFileNode* node )
+{
+    void* ptr = 0;
+    CvFileNode *sequences_node = cvGetFileNodeByName( fs, node, "sequences" );
+    CvSeq* sequences;
+    CvSeq* root = 0;
+    CvSeq* parent = 0;
+    CvSeq* prev_seq = 0;
+    CvSeqReader reader;
+    int i, total;
+    int prev_level = 0;
+
+    if( !sequences_node || !CV_NODE_IS_SEQ(sequences_node->tag) )
+        CV_Error( CV_StsParseError,
+        "opencv-sequence-tree instance should contain a field \"sequences\" that should be a sequence" );
+
+    sequences = sequences_node->data.seq;
+    total = sequences->total;
+
+    cvStartReadSeq( sequences, &reader, 0 );
+    for( i = 0; i < total; i++ )
+    {
+        CvFileNode* elem = (CvFileNode*)reader.ptr;
+        CvSeq* seq;
+        int level;
+        seq = (CvSeq*)cvRead( fs, elem );
+        level = cvReadIntByName( fs, elem, "level", -1 );
+        if( level < 0 )
+            CV_Error( CV_StsParseError, "All the sequence tree nodes should contain \"level\" field" );
+        if( !root )
+            root = seq;
+        if( level > prev_level )
+        {
+            assert( level == prev_level + 1 );
+            parent = prev_seq;
+            prev_seq = 0;
+            if( parent )
+                parent->v_next = seq;
+        }
+        else if( level < prev_level )
+        {
+            for( ; prev_level > level; prev_level-- )
+                prev_seq = prev_seq->v_prev;
+            parent = prev_seq->v_prev;
+        }
+        seq->h_prev = prev_seq;
+        if( prev_seq )
+            prev_seq->h_next = seq;
+        seq->v_prev = parent;
+        prev_seq = seq;
+        prev_level = level;
+        CV_NEXT_SEQ_ELEM( sequences->elem_size, reader );
+    }
+
+    ptr = root;
+    return ptr;
+}
+
+/******************************* CvGraph ******************************/
 
 static int
-icvIsMatND( const void* ptr )
+icvIsGraph( const void* ptr )
 {
-    return CV_IS_MATND_HDR(ptr);
+    return CV_IS_GRAPH(ptr);
 }
 
 
 static void
-icvWriteMatND( CvFileStorage* fs, const char* name,
-               const void* struct_ptr, CvAttrList /*attr*/ )
+icvReleaseGraph( void** ptr )
 {
-    CvMatND* mat = (CvMatND*)struct_ptr;
-    CvMatND stub;
-    CvNArrayIterator iterator;
-    int dims, sizes[CV_MAX_DIM];
-    char dt[16];
-
-    assert( CV_IS_MATND_HDR(mat) );
+    if( !ptr )
+        CV_Error( CV_StsNullPtr, "NULL double pointer" );
 
-    cvStartWriteStruct( fs, name, CV_NODE_MAP, CV_TYPE_NAME_MATND );
-    dims = cvGetDims( mat, sizes );
-    cvStartWriteStruct( fs, "sizes", CV_NODE_SEQ + CV_NODE_FLOW );
-    cvWriteRawData( fs, sizes, dims, "i" );
-    cvEndWriteStruct( fs );
-    cvWriteString( fs, "dt", icvEncodeFormat( cvGetElemType(mat), dt ), 0 );
-    cvStartWriteStruct( fs, "data", CV_NODE_SEQ + CV_NODE_FLOW );
+    *ptr = 0; // it's impossible now to release graph, so just clear the pointer
+}
 
-    if( mat->dim[0].size > 0 && mat->data.ptr )
-    {
-        cvInitNArrayIterator( 1, (CvArr**)&mat, 0, &stub, &iterator );
 
-        do
-            cvWriteRawData( fs, iterator.ptr[0], iterator.size.width, dt );
-        while( cvNextNArraySlice( &iterator ));
-    }
-    cvEndWriteStruct( fs );
-    cvEndWriteStruct( fs );
+static void*
+icvCloneGraph( const void* ptr )
+{
+    return cvCloneGraph( (const CvGraph*)ptr, 0 );
 }
 
 
-static void*
-icvReadMatND( CvFileStorage* fs, CvFileNode* node )
+static void
+icvWriteGraph( CvFileStorage* fs, const char* name,
+               const void* struct_ptr, CvAttrList attr )
 {
-    void* ptr = 0;
-    CvMatND* mat;
-    const char* dt;
-    CvFileNode* data;
-    CvFileNode* sizes_node;
-    int sizes[CV_MAX_DIM], dims, elem_type;
-    int i, total_size;
+    int* flag_buf = 0;
+    char* write_buf = 0;
+    const CvGraph* graph = (const CvGraph*)struct_ptr;
+    CvSeqReader reader;
+    char buf[128];
+    int i, k, vtx_count, edge_count;
+    char vtx_dt_buf[128], *vtx_dt;
+    char edge_dt_buf[128], *edge_dt;
+    int write_buf_size;
 
-    sizes_node = cvGetFileNodeByName( fs, node, "sizes" );
-    dt = cvReadStringByName( fs, node, "dt", 0 );
+    assert( CV_IS_GRAPH(graph) );
+    vtx_count = cvGraphGetVtxCount( graph );
+    edge_count = cvGraphGetEdgeCount( graph );
+    flag_buf = (int*)cvAlloc( vtx_count*sizeof(flag_buf[0]));
 
-    if( !sizes_node || !dt )
-        CV_Error( CV_StsError, "Some of essential matrix attributes are absent" );
+    // count vertices
+    cvStartReadSeq( (CvSeq*)graph, &reader );
+    for( i = 0, k = 0; i < graph->total; i++ )
+    {
+        if( CV_IS_SET_ELEM( reader.ptr ))
+        {
+            CvGraphVtx* vtx = (CvGraphVtx*)reader.ptr;
+            flag_buf[k] = vtx->flags;
+            vtx->flags = k++;
+        }
+        CV_NEXT_SEQ_ELEM( graph->elem_size, reader );
+    }
 
-    dims = CV_NODE_IS_SEQ(sizes_node->tag) ? sizes_node->data.seq->total :
-           CV_NODE_IS_INT(sizes_node->tag) ? 1 : -1;
+    // write header
+    cvStartWriteStruct( fs, name, CV_NODE_MAP, CV_TYPE_NAME_GRAPH );
 
-    if( dims <= 0 || dims > CV_MAX_DIM )
-        CV_Error( CV_StsParseError, "Could not determine the matrix dimensionality" );
+    cvWriteString(fs, "flags", CV_IS_GRAPH_ORIENTED(graph) ? "oriented" : "", 1);
 
-    cvReadRawData( fs, sizes_node, sizes, "i" );
-    elem_type = icvDecodeSimpleFormat( dt );
+    cvWriteInt( fs, "vertex_count", vtx_count );
+    vtx_dt = icvGetFormat( (CvSeq*)graph, "vertex_dt",
+                    &attr, sizeof(CvGraphVtx), vtx_dt_buf );
+    if( vtx_dt )
+        cvWriteString( fs, "vertex_dt", vtx_dt, 0 );
 
-    data = cvGetFileNodeByName( fs, node, "data" );
-    if( !data )
-        CV_Error( CV_StsError, "The matrix data is not found in file storage" );
+    cvWriteInt( fs, "edge_count", edge_count );
+    edge_dt = icvGetFormat( (CvSeq*)graph->edges, "edge_dt",
+                                &attr, sizeof(CvGraphEdge), buf );
+    sprintf( edge_dt_buf, "2if%s", edge_dt ? edge_dt : "" );
+    edge_dt = edge_dt_buf;
+    cvWriteString( fs, "edge_dt", edge_dt, 0 );
 
+    icvWriteHeaderData( fs, (CvSeq*)graph, &attr, sizeof(CvGraph) );
 
+    write_buf_size = MAX( 3*graph->elem_size, 1 << 16 );
+    write_buf_size = MAX( 3*graph->edges->elem_size, write_buf_size );
+    write_buf = (char*)cvAlloc( write_buf_size );
 
-    for( total_size = CV_MAT_CN(elem_type), i = 0; i < dims; i++ )
-        total_size *= sizes[i];
+    // as vertices and edges are written in similar way,
+    // do it as a parametrized 2-iteration loop
+    for( k = 0; k < 2; k++ )
+    {
+        const char* dt = k == 0 ? vtx_dt : edge_dt;
+        if( dt )
+        {
+            CvSet* data = k == 0 ? (CvSet*)graph : graph->edges;
+            int elem_size = data->elem_size;
+            int write_elem_size = icvCalcElemSize( dt, 0 );
+            char* src_ptr = write_buf;
+            int write_max = write_buf_size / write_elem_size, write_count = 0;
+
+            // alignment of user part of the edge data following 2if
+            int edge_user_align = sizeof(float);
+
+            if( k == 1 )
+            {
+                int fmt_pairs[CV_FS_MAX_FMT_PAIRS], fmt_pair_count;
+                fmt_pair_count = icvDecodeFormat( dt, fmt_pairs, CV_FS_MAX_FMT_PAIRS );
+                if( fmt_pair_count > 2 && CV_ELEM_SIZE(fmt_pairs[2*2+1]) >= (int)sizeof(double))
+                    edge_user_align = sizeof(double);
+            }
+
+            cvStartWriteStruct( fs, k == 0 ? "vertices" : "edges",
+                                CV_NODE_SEQ + CV_NODE_FLOW );
+            cvStartReadSeq( (CvSeq*)data, &reader );
+            for( i = 0; i < data->total; i++ )
+            {
+                if( CV_IS_SET_ELEM( reader.ptr ))
+                {
+                    if( k == 0 ) // vertices
+                        memcpy( src_ptr, reader.ptr + sizeof(CvGraphVtx), write_elem_size );
+                    else
+                    {
+                        CvGraphEdge* edge = (CvGraphEdge*)reader.ptr;
+                        src_ptr = (char*)cvAlignPtr( src_ptr, sizeof(int) );
+                        ((int*)src_ptr)[0] = edge->vtx[0]->flags;
+                        ((int*)src_ptr)[1] = edge->vtx[1]->flags;
+                        *(float*)(src_ptr + sizeof(int)*2) = edge->weight;
+                        if( elem_size > (int)sizeof(CvGraphEdge) )
+                        {
+                            char* src_ptr2 = (char*)cvAlignPtr( src_ptr + 2*sizeof(int)
+                                                + sizeof(float), edge_user_align );
+                            memcpy( src_ptr2, edge + 1, elem_size - sizeof(CvGraphEdge) );
+                        }
+                    }
+                    src_ptr += write_elem_size;
+                    if( ++write_count >= write_max )
+                    {
+                        cvWriteRawData( fs, write_buf, write_count, dt );
+                        write_count = 0;
+                        src_ptr = write_buf;
+                    }
+                }
+                CV_NEXT_SEQ_ELEM( data->elem_size, reader );
+            }
 
-    int nelems = icvFileNodeSeqLen( data );
+            if( write_count > 0 )
+                cvWriteRawData( fs, write_buf, write_count, dt );
+            cvEndWriteStruct( fs );
+        }
+    }
 
-    if( nelems > 0 && nelems != total_size )
-        CV_Error( CV_StsUnmatchedSizes,
-                 "The matrix size does not match to the number of stored elements" );
+    cvEndWriteStruct( fs );
 
-    if( nelems > 0 )
+    // final stage. restore the graph flags
+    cvStartReadSeq( (CvSeq*)graph, &reader );
+    vtx_count = 0;
+    for( i = 0; i < graph->total; i++ )
     {
-        mat = cvCreateMatND( dims, sizes, elem_type );
-        cvReadRawData( fs, data, mat->data.ptr, dt );
+        if( CV_IS_SET_ELEM( reader.ptr ))
+            ((CvGraphVtx*)reader.ptr)->flags = flag_buf[vtx_count++];
+        CV_NEXT_SEQ_ELEM( graph->elem_size, reader );
     }
-    else
-        mat = cvCreateMatNDHeader( dims, sizes, elem_type );
 
-    ptr = mat;
-    return ptr;
-}
-
-
-/******************************* CvSparseMat ******************************/
-
-static int
-icvIsSparseMat( const void* ptr )
-{
-    return CV_IS_SPARSE_MAT(ptr);
+    cvFree( &write_buf );
+    cvFree( &flag_buf );
 }
 
 
-static int
-icvSortIdxCmpFunc( const void* _a, const void* _b, void* userdata )
+static void*
+icvReadGraph( CvFileStorage* fs, CvFileNode* node )
 {
-    int i, dims = *(int*)userdata;
-    const int* a = *(const int**)_a;
-    const int* b = *(const int**)_b;
-
-    for( i = 0; i < dims; i++ )
-    {
-        int delta = a[i] - b[i];
-        if( delta )
-            return delta;
-    }
+    void* ptr = 0;
+    char* read_buf = 0;
+    CvGraphVtx** vtx_buf = 0;
+    CvGraph* graph;
+    CvFileNode *header_node, *vtx_node, *edge_node;
+    int flags, vtx_count, edge_count;
+    int vtx_size = sizeof(CvGraphVtx), edge_size, header_size = sizeof(CvGraph);
+    int src_vtx_size = 0, src_edge_size;
+    int fmt_pairs[CV_FS_MAX_FMT_PAIRS], fmt_pair_count;
+    int vtx_items_per_elem = 0, edge_items_per_elem = 0;
+    int edge_user_align = sizeof(float);
+    int read_buf_size;
+    int i, k;
+    const char* flags_str;
+    const char* header_dt;
+    const char* vtx_dt;
+    const char* edge_dt;
+    char* endptr = 0;
 
-    return 0;
-}
+    flags_str = cvReadStringByName( fs, node, "flags", 0 );
+    vtx_dt = cvReadStringByName( fs, node, "vertex_dt", 0 );
+    edge_dt = cvReadStringByName( fs, node, "edge_dt", 0 );
+    vtx_count = cvReadIntByName( fs, node, "vertex_count", -1 );
+    edge_count = cvReadIntByName( fs, node, "edge_count", -1 );
 
+    if( !flags_str || vtx_count == -1 || edge_count == -1 || !edge_dt )
+        CV_Error( CV_StsError, "Some of essential graph attributes are absent" );
 
-static void
-icvWriteSparseMat( CvFileStorage* fs, const char* name,
-                   const void* struct_ptr, CvAttrList /*attr*/ )
-{
-    CvMemStorage* memstorage = 0;
-    const CvSparseMat* mat = (const CvSparseMat*)struct_ptr;
-    CvSparseMatIterator iterator;
-    CvSparseNode* node;
-    CvSeq* elements;
-    CvSeqReader reader;
-    int i, dims;
-    int *prev_idx = 0;
-    char dt[16];
+    flags = CV_SET_MAGIC_VAL + CV_GRAPH;
 
-    assert( CV_IS_SPARSE_MAT(mat) );
+    if( isxdigit(flags_str[0]) )
+    {
+        const int OLD_SEQ_ELTYPE_BITS = 9;
+        const int OLD_SEQ_KIND_BITS = 3;
+        const int OLD_SEQ_FLAG_SHIFT = OLD_SEQ_KIND_BITS + OLD_SEQ_ELTYPE_BITS;
+        const int OLD_GRAPH_FLAG_ORIENTED = 1 << OLD_SEQ_FLAG_SHIFT;
 
-    memstorage = cvCreateMemStorage();
+        int flags0 = (int)strtol( flags_str, &endptr, 16 );
+        if( endptr == flags_str || (flags0 & CV_MAGIC_MASK) != CV_SET_MAGIC_VAL )
+            CV_Error( CV_StsError, "The sequence flags are invalid" );
+        if( flags0 & OLD_GRAPH_FLAG_ORIENTED )
+            flags |= CV_GRAPH_FLAG_ORIENTED;
+    }
+    else
+    {
+        if( strstr(flags_str, "oriented") )
+            flags |= CV_GRAPH_FLAG_ORIENTED;
+    }
 
-    cvStartWriteStruct( fs, name, CV_NODE_MAP, CV_TYPE_NAME_SPARSE_MAT );
-    dims = cvGetDims( mat, 0 );
+    header_dt = cvReadStringByName( fs, node, "header_dt", 0 );
+    header_node = cvGetFileNodeByName( fs, node, "header_user_data" );
 
-    cvStartWriteStruct( fs, "sizes", CV_NODE_SEQ + CV_NODE_FLOW );
-    cvWriteRawData( fs, mat->size, dims, "i" );
-    cvEndWriteStruct( fs );
-    cvWriteString( fs, "dt", icvEncodeFormat( CV_MAT_TYPE(mat->type), dt ), 0 );
-    cvStartWriteStruct( fs, "data", CV_NODE_SEQ + CV_NODE_FLOW );
+    if( (header_dt != 0) ^ (header_node != 0) )
+        CV_Error( CV_StsError,
+        "One of \"header_dt\" and \"header_user_data\" is there, while the other is not" );
 
-    elements = cvCreateSeq( CV_SEQ_ELTYPE_PTR, sizeof(CvSeq), sizeof(int*), memstorage );
+    if( header_dt )
+        header_size = icvCalcElemSize( header_dt, header_size );
 
-    node = cvInitSparseMatIterator( mat, &iterator );
-    while( node )
+    if( vtx_dt )
     {
-        int* idx = CV_NODE_IDX( mat, node );
-        cvSeqPush( elements, &idx );
-        node = cvGetNextSparseNode( &iterator );
+        src_vtx_size = icvCalcElemSize( vtx_dt, 0 );
+        vtx_size = icvCalcElemSize( vtx_dt, vtx_size );
+        fmt_pair_count = icvDecodeFormat( edge_dt,
+                            fmt_pairs, CV_FS_MAX_FMT_PAIRS );
+        fmt_pair_count *= 2;
+        for( i = 0; i < fmt_pair_count; i += 2 )
+            vtx_items_per_elem += fmt_pairs[i];
     }
 
-    cvSeqSort( elements, icvSortIdxCmpFunc, &dims );
-    cvStartReadSeq( elements, &reader, 0 );
-
-    for( i = 0; i < elements->total; i++ )
     {
-        int* idx;
-        void* val;
-        int k = 0;
+        char dst_edge_dt_buf[128];
+        const char* dst_edge_dt = 0;
 
-        CV_READ_SEQ_ELEM( idx, reader );
-        if( i > 0 )
+        fmt_pair_count = icvDecodeFormat( edge_dt,
+                            fmt_pairs, CV_FS_MAX_FMT_PAIRS );
+        if( fmt_pair_count < 2 ||
+            fmt_pairs[0] != 2 || fmt_pairs[1] != CV_32S ||
+            fmt_pairs[2] < 1 || fmt_pairs[3] != CV_32F )
+            CV_Error( CV_StsBadArg,
+            "Graph edges should start with 2 integers and a float" );
+
+        // alignment of user part of the edge data following 2if
+        if( fmt_pair_count > 2 && CV_ELEM_SIZE(fmt_pairs[5]) >= (int)sizeof(double))
+            edge_user_align = sizeof(double);
+
+        fmt_pair_count *= 2;
+        for( i = 0; i < fmt_pair_count; i += 2 )
+            edge_items_per_elem += fmt_pairs[i];
+
+        if( edge_dt[2] == 'f' || (edge_dt[2] == '1' && edge_dt[3] == 'f') )
+            dst_edge_dt = edge_dt + 3 + cv_isdigit(edge_dt[2]);
+        else
         {
-            for( ; idx[k] == prev_idx[k]; k++ )
-                assert( k < dims );
-            if( k < dims - 1 )
-                fs->write_int( fs, 0, k - dims + 1 );
+            int val = (int)strtol( edge_dt + 2, &endptr, 10 );
+            sprintf( dst_edge_dt_buf, "%df%s", val-1, endptr );
+            dst_edge_dt = dst_edge_dt_buf;
         }
-        for( ; k < dims; k++ )
-            fs->write_int( fs, 0, idx[k] );
-        prev_idx = idx;
-
-        node = (CvSparseNode*)((uchar*)idx - mat->idxoffset );
-        val = CV_NODE_VAL( mat, node );
 
-        cvWriteRawData( fs, val, 1, dt );
+        edge_size = icvCalcElemSize( dst_edge_dt, sizeof(CvGraphEdge) );
+        src_edge_size = icvCalcElemSize( edge_dt, 0 );
     }
 
-    cvEndWriteStruct( fs );
-    cvEndWriteStruct( fs );
-    cvReleaseMemStorage( &memstorage );
-}
-
+    graph = cvCreateGraph( flags, header_size, vtx_size, edge_size, fs->dststorage );
 
-static void*
-icvReadSparseMat( CvFileStorage* fs, CvFileNode* node )
-{
-    void* ptr = 0;
-    CvSparseMat* mat;
-    const char* dt;
-    CvFileNode* data;
-    CvFileNode* sizes_node;
-    CvSeqReader reader;
-    CvSeq* elements;
-    int sizes[CV_MAX_DIM_HEAP], dims, elem_type, cn;
-    int i;
+    if( header_node )
+        cvReadRawData( fs, header_node, (char*)graph + sizeof(CvGraph), header_dt );
 
-    sizes_node = cvGetFileNodeByName( fs, node, "sizes" );
-    dt = cvReadStringByName( fs, node, "dt", 0 );
+    read_buf_size = MAX( src_vtx_size*3, 1 << 16 );
+    read_buf_size = MAX( src_edge_size*3, read_buf_size );
+    read_buf = (char*)cvAlloc( read_buf_size );
+    vtx_buf = (CvGraphVtx**)cvAlloc( vtx_count * sizeof(vtx_buf[0]) );
 
-    if( !sizes_node || !dt )
-        CV_Error( CV_StsError, "Some of essential matrix attributes are absent" );
+    vtx_node = cvGetFileNodeByName( fs, node, "vertices" );
+    edge_node = cvGetFileNodeByName( fs, node, "edges" );
+    if( !edge_node )
+        CV_Error( CV_StsBadArg, "No edges data" );
+    if( vtx_dt && !vtx_node )
+        CV_Error( CV_StsBadArg, "No vertices data" );
 
-    dims = CV_NODE_IS_SEQ(sizes_node->tag) ? sizes_node->data.seq->total :
-           CV_NODE_IS_INT(sizes_node->tag) ? 1 : -1;
+    // as vertices and edges are read in similar way,
+    // do it as a parametrized 2-iteration loop
+    for( k = 0; k < 2; k++ )
+    {
+        const char* dt = k == 0 ? vtx_dt : edge_dt;
+        int elem_size = k == 0 ? vtx_size : edge_size;
+        int src_elem_size = k == 0 ? src_vtx_size : src_edge_size;
+        int items_per_elem = k == 0 ? vtx_items_per_elem : edge_items_per_elem;
+        int elem_count = k == 0 ? vtx_count : edge_count;
+        char* dst_ptr = read_buf;
+        int read_max = read_buf_size /MAX(src_elem_size, 1), read_count = 0;
+        CvSeqReader reader;
+        if(dt)
+            cvStartReadRawData( fs, k == 0 ? vtx_node : edge_node, &reader );
 
-    if( dims <= 0 || dims > CV_MAX_DIM_HEAP )
-        CV_Error( CV_StsParseError, "Could not determine sparse matrix dimensionality" );
+        for( i = 0; i < elem_count; i++ )
+        {
+            if( read_count == 0 && dt )
+            {
+                int count = MIN( elem_count - i, read_max )*items_per_elem;
+                cvReadRawDataSlice( fs, &reader, count, read_buf, dt );
+                read_count = count;
+                dst_ptr = read_buf;
+            }
 
-    cvReadRawData( fs, sizes_node, sizes, "i" );
-    elem_type = icvDecodeSimpleFormat( dt );
+            if( k == 0 )
+            {
+                CvGraphVtx* vtx;
+                cvGraphAddVtx( graph, 0, &vtx );
+                vtx_buf[i] = vtx;
+                if( dt )
+                    memcpy( vtx + 1, dst_ptr, src_elem_size );
+            }
+            else
+            {
+                CvGraphEdge* edge = 0;
+                int vtx1 = ((int*)dst_ptr)[0];
+                int vtx2 = ((int*)dst_ptr)[1];
+                int result;
 
-    data = cvGetFileNodeByName( fs, node, "data" );
-    if( !data || !CV_NODE_IS_SEQ(data->tag) )
-        CV_Error( CV_StsError, "The matrix data is not found in file storage" );
+                if( (unsigned)vtx1 >= (unsigned)vtx_count ||
+                    (unsigned)vtx2 >= (unsigned)vtx_count )
+                    CV_Error( CV_StsOutOfRange,
+                    "Some of stored vertex indices are out of range" );
 
-    mat = cvCreateSparseMat( dims, sizes, elem_type );
+                result = cvGraphAddEdgeByPtr( graph,
+                    vtx_buf[vtx1], vtx_buf[vtx2], 0, &edge );
 
-    cn = CV_MAT_CN(elem_type);
-    int idx[CV_MAX_DIM_HEAP];
-    elements = data->data.seq;
-    cvStartReadRawData( fs, data, &reader );
+                if( result == 0 )
+                    CV_Error( CV_StsBadArg, "Duplicated edge has occured" );
 
-    for( i = 0; i < elements->total; )
-    {
-        CvFileNode* elem = (CvFileNode*)reader.ptr;
-        uchar* val;
-        int k;
-        if( !CV_NODE_IS_INT(elem->tag ))
-            CV_Error( CV_StsParseError, "Sparse matrix data is corrupted" );
-        k = elem->data.i;
-        if( i > 0 && k >= 0 )
-            idx[dims-1] = k;
-        else
-        {
-            if( i > 0 )
-                k = dims + k - 1;
-            else
-                idx[0] = k, k = 1;
-            for( ; k < dims; k++ )
-            {
-                CV_NEXT_SEQ_ELEM( elements->elem_size, reader );
-                i++;
-                elem = (CvFileNode*)reader.ptr;
-                if( !CV_NODE_IS_INT(elem->tag ) || elem->data.i < 0 )
-                    CV_Error( CV_StsParseError, "Sparse matrix data is corrupted" );
-                idx[k] = elem->data.i;
+                edge->weight = *(float*)(dst_ptr + sizeof(int)*2);
+                if( elem_size > (int)sizeof(CvGraphEdge) )
+                {
+                    char* dst_ptr2 = (char*)cvAlignPtr( dst_ptr + sizeof(int)*2 +
+                                                sizeof(float), edge_user_align );
+                    memcpy( edge + 1, dst_ptr2, elem_size - sizeof(CvGraphEdge) );
+                }
             }
+
+            dst_ptr += src_elem_size;
+            read_count--;
         }
-        CV_NEXT_SEQ_ELEM( elements->elem_size, reader );
-        i++;
-        val = cvPtrND( mat, idx, 0, 1, 0 );
-        cvReadRawDataSlice( fs, &reader, cn, val, dt );
-        i += cn;
     }
 
-    ptr = mat;
+    ptr = graph;
+    cvFree( &read_buf );
+    cvFree( &vtx_buf );
+
     return ptr;
 }
 
+/****************************************************************************************\
+*                                    RTTI Functions                                      *
+\****************************************************************************************/
 
-/******************************* IplImage ******************************/
+CvTypeInfo *CvType::first = 0, *CvType::last = 0;
 
-static int
-icvIsImage( const void* ptr )
+CvType::CvType( const char* type_name,
+                CvIsInstanceFunc is_instance, CvReleaseFunc release,
+                CvReadFunc read, CvWriteFunc write, CvCloneFunc clone )
 {
-    return CV_IS_IMAGE_HDR(ptr);
+    CvTypeInfo _info;
+    _info.flags = 0;
+    _info.header_size = sizeof(_info);
+    _info.type_name = type_name;
+    _info.prev = _info.next = 0;
+    _info.is_instance = is_instance;
+    _info.release = release;
+    _info.clone = clone;
+    _info.read = read;
+    _info.write = write;
+
+    cvRegisterType( &_info );
+    info = first;
 }
 
-static void
-icvWriteImage( CvFileStorage* fs, const char* name,
-               const void* struct_ptr, CvAttrList /*attr*/ )
+
+CvType::~CvType()
 {
-    const IplImage* image = (const IplImage*)struct_ptr;
-    char dt_buf[16], *dt;
-    CvSize size;
-    int y, depth;
+    cvUnregisterType( info->type_name );
+}
 
-    assert( CV_IS_IMAGE(image) );
 
-    if( image->dataOrder == IPL_DATA_ORDER_PLANE )
-        CV_Error( CV_StsUnsupportedFormat,
-        "Images with planar data layout are not supported" );
+CvType seq_type( CV_TYPE_NAME_SEQ, icvIsSeq, icvReleaseSeq, icvReadSeq,
+                 icvWriteSeqTree /* this is the entry point for
+                 writing a single sequence too */, icvCloneSeq );
 
-    cvStartWriteStruct( fs, name, CV_NODE_MAP, CV_TYPE_NAME_IMAGE );
-    cvWriteInt( fs, "width", image->width );
-    cvWriteInt( fs, "height", image->height );
-    cvWriteString( fs, "origin", image->origin == IPL_ORIGIN_TL
-                   ? "top-left" : "bottom-left", 0 );
-    cvWriteString( fs, "layout", image->dataOrder == IPL_DATA_ORDER_PLANE
-                   ? "planar" : "interleaved", 0 );
-    if( image->roi )
-    {
-        cvStartWriteStruct( fs, "roi", CV_NODE_MAP + CV_NODE_FLOW );
-        cvWriteInt( fs, "x", image->roi->xOffset );
-        cvWriteInt( fs, "y", image->roi->yOffset );
-        cvWriteInt( fs, "width", image->roi->width );
-        cvWriteInt( fs, "height", image->roi->height );
-        cvWriteInt( fs, "coi", image->roi->coi );
-        cvEndWriteStruct( fs );
-    }
+CvType seq_tree_type( CV_TYPE_NAME_SEQ_TREE, icvIsSeq, icvReleaseSeq,
+                      icvReadSeqTree, icvWriteSeqTree, icvCloneSeq );
 
-    depth = IPL2CV_DEPTH(image->depth);
-    sprintf( dt_buf, "%d%c", image->nChannels, icvTypeSymbol[depth] );
-    dt = dt_buf + (dt_buf[2] == '\0' && dt_buf[0] == '1');
-    cvWriteString( fs, "dt", dt, 0 );
+CvType seq_graph_type( CV_TYPE_NAME_GRAPH, icvIsGraph, icvReleaseGraph,
+                       icvReadGraph, icvWriteGraph, icvCloneGraph );
 
-    size = cvSize(image->width, image->height);
-    if( size.width*image->nChannels*CV_ELEM_SIZE(depth) == image->widthStep )
-    {
-        size.width *= size.height;
-        size.height = 1;
-    }
+CvType sparse_mat_type( CV_TYPE_NAME_SPARSE_MAT, icvIsSparseMat,
+                        (CvReleaseFunc)cvReleaseSparseMat, icvReadSparseMat,
+                        icvWriteSparseMat, (CvCloneFunc)cvCloneSparseMat );
 
-    cvStartWriteStruct( fs, "data", CV_NODE_SEQ + CV_NODE_FLOW );
-    for( y = 0; y < size.height; y++ )
-        cvWriteRawData( fs, image->imageData + y*image->widthStep, size.width, dt );
-    cvEndWriteStruct( fs );
-    cvEndWriteStruct( fs );
-}
+CvType image_type( CV_TYPE_NAME_IMAGE, icvIsImage, (CvReleaseFunc)cvReleaseImage,
+                   icvReadImage, icvWriteImage, (CvCloneFunc)cvCloneImage );
 
+CvType mat_type( CV_TYPE_NAME_MAT, icvIsMat, (CvReleaseFunc)cvReleaseMat,
+                 icvReadMat, icvWriteMat, (CvCloneFunc)cvCloneMat );
 
-static void*
-icvReadImage( CvFileStorage* fs, CvFileNode* node )
-{
-    void* ptr = 0;
-    IplImage* image;
-    const char* dt;
-    CvFileNode* data;
-    CvFileNode* roi_node;
-    CvSeqReader reader;
-    CvRect roi;
-    int y, width, height, elem_type, coi, depth;
-    const char* origin, *data_order;
+CvType matnd_type( CV_TYPE_NAME_MATND, icvIsMatND, (CvReleaseFunc)cvReleaseMatND,
+                   icvReadMatND, icvWriteMatND, (CvCloneFunc)cvCloneMatND );
 
-    width = cvReadIntByName( fs, node, "width", 0 );
-    height = cvReadIntByName( fs, node, "height", 0 );
-    dt = cvReadStringByName( fs, node, "dt", 0 );
-    origin = cvReadStringByName( fs, node, "origin", 0 );
+CV_IMPL  void
+cvRegisterType( const CvTypeInfo* _info )
+{
+    CvTypeInfo* info = 0;
+    int i, len;
+    char c;
 
-    if( width == 0 || height == 0 || dt == 0 || origin == 0 )
-        CV_Error( CV_StsError, "Some of essential image attributes are absent" );
+    //if( !CvType::first )
+    //    icvCreateStandardTypes();
 
-    elem_type = icvDecodeSimpleFormat( dt );
-    data_order = cvReadStringByName( fs, node, "layout", "interleaved" );
-    if( strcmp( data_order, "interleaved" ) != 0 )
-        CV_Error( CV_StsError, "Only interleaved images can be read" );
+    if( !_info || _info->header_size != sizeof(CvTypeInfo) )
+        CV_Error( CV_StsBadSize, "Invalid type info" );
 
-    data = cvGetFileNodeByName( fs, node, "data" );
-    if( !data )
-        CV_Error( CV_StsError, "The image data is not found in file storage" );
+    if( !_info->is_instance || !_info->release ||
+        !_info->read || !_info->write )
+        CV_Error( CV_StsNullPtr,
+        "Some of required function pointers "
+        "(is_instance, release, read or write) are NULL");
 
-    if( icvFileNodeSeqLen( data ) != width*height*CV_MAT_CN(elem_type) )
-        CV_Error( CV_StsUnmatchedSizes,
-        "The matrix size does not match to the number of stored elements" );
+    c = _info->type_name[0];
+    if( !cv_isalpha(c) && c != '_' )
+        CV_Error( CV_StsBadArg, "Type name should start with a letter or _" );
 
-    depth = cvIplDepth(elem_type);
-    image = cvCreateImage( cvSize(width,height), depth, CV_MAT_CN(elem_type) );
+    len = (int)strlen(_info->type_name);
 
-    roi_node = cvGetFileNodeByName( fs, node, "roi" );
-    if( roi_node )
+    for( i = 0; i < len; i++ )
     {
-        roi.x = cvReadIntByName( fs, roi_node, "x", 0 );
-        roi.y = cvReadIntByName( fs, roi_node, "y", 0 );
-        roi.width = cvReadIntByName( fs, roi_node, "width", 0 );
-        roi.height = cvReadIntByName( fs, roi_node, "height", 0 );
-        coi = cvReadIntByName( fs, roi_node, "coi", 0 );
-
-        cvSetImageROI( image, roi );
-        cvSetImageCOI( image, coi );
+        c = _info->type_name[i];
+        if( !cv_isalnum(c) && c != '-' && c != '_' )
+            CV_Error( CV_StsBadArg,
+            "Type name should contain only letters, digits, - and _" );
     }
 
-    if( width*CV_ELEM_SIZE(elem_type) == image->widthStep )
-    {
-        width *= height;
-        height = 1;
-    }
+    info = (CvTypeInfo*)cvAlloc( sizeof(*info) + len + 1 );
 
-    width *= CV_MAT_CN(elem_type);
-    cvStartReadRawData( fs, data, &reader );
-    for( y = 0; y < height; y++ )
-    {
-        cvReadRawDataSlice( fs, &reader, width,
-            image->imageData + y*image->widthStep, dt );
-    }
+    *info = *_info;
+    info->type_name = (char*)(info + 1);
+    memcpy( (char*)info->type_name, _info->type_name, len + 1 );
 
-    ptr = image;
-    return ptr;
+    info->flags = 0;
+    info->next = CvType::first;
+    info->prev = 0;
+    if( CvType::first )
+        CvType::first->prev = info;
+    else
+        CvType::last = info;
+    CvType::first = info;
 }
 
 
-/******************************* CvSeq ******************************/
-
-static int
-icvIsSeq( const void* ptr )
+CV_IMPL void
+cvUnregisterType( const char* type_name )
 {
-    return CV_IS_SEQ(ptr);
-}
+    CvTypeInfo* info;
 
+    info = cvFindType( type_name );
+    if( info )
+    {
+        if( info->prev )
+            info->prev->next = info->next;
+        else
+            CvType::first = info->next;
 
-static void
-icvReleaseSeq( void** ptr )
-{
-    if( !ptr )
-        CV_Error( CV_StsNullPtr, "NULL double pointer" );
-    *ptr = 0; // it's impossible now to release seq, so just clear the pointer
-}
+        if( info->next )
+            info->next->prev = info->prev;
+        else
+            CvType::last = info->prev;
 
+        if( !CvType::first || !CvType::last )
+            CvType::first = CvType::last = 0;
 
-static void*
-icvCloneSeq( const void* ptr )
-{
-    return cvSeqSlice( (CvSeq*)ptr, CV_WHOLE_SEQ,
-                       0 /* use the same storage as for the original sequence */, 1 );
+        cvFree( &info );
+    }
 }
 
 
-static void
-icvWriteHeaderData( CvFileStorage* fs, const CvSeq* seq,
-                    CvAttrList* attr, int initial_header_size )
+CV_IMPL CvTypeInfo*
+cvFirstType( void )
 {
-    char header_dt_buf[128];
-    const char* header_dt = cvAttrValue( attr, "header_dt" );
+    return CvType::first;
+}
 
-    if( header_dt )
-    {
-        int dt_header_size;
-        dt_header_size = icvCalcElemSize( header_dt, initial_header_size );
-        if( dt_header_size > seq->header_size )
-            CV_Error( CV_StsUnmatchedSizes,
-            "The size of header calculated from \"header_dt\" is greater than header_size" );
-    }
-    else if( seq->header_size > initial_header_size )
-    {
-        if( CV_IS_SEQ(seq) && CV_IS_SEQ_POINT_SET(seq) &&
-            seq->header_size == sizeof(CvPoint2DSeq) &&
-            seq->elem_size == sizeof(int)*2 )
-        {
-            CvPoint2DSeq* point_seq = (CvPoint2DSeq*)seq;
 
-            cvStartWriteStruct( fs, "rect", CV_NODE_MAP + CV_NODE_FLOW );
-            cvWriteInt( fs, "x", point_seq->rect.x );
-            cvWriteInt( fs, "y", point_seq->rect.y );
-            cvWriteInt( fs, "width", point_seq->rect.width );
-            cvWriteInt( fs, "height", point_seq->rect.height );
-            cvEndWriteStruct( fs );
-            cvWriteInt( fs, "color", point_seq->color );
-        }
-        else if( CV_IS_SEQ(seq) && CV_IS_SEQ_CHAIN(seq) &&
-                 CV_MAT_TYPE(seq->flags) == CV_8UC1 )
-        {
-            CvChain* chain = (CvChain*)seq;
+CV_IMPL CvTypeInfo*
+cvFindType( const char* type_name )
+{
+    CvTypeInfo* info = 0;
 
-            cvStartWriteStruct( fs, "origin", CV_NODE_MAP + CV_NODE_FLOW );
-            cvWriteInt( fs, "x", chain->origin.x );
-            cvWriteInt( fs, "y", chain->origin.y );
-            cvEndWriteStruct( fs );
-        }
-        else
-        {
-            unsigned extra_size = seq->header_size - initial_header_size;
-            // a heuristic to provide nice defaults for sequences of int's & float's
-            if( extra_size % sizeof(int) == 0 )
-                sprintf( header_dt_buf, "%ui", (unsigned)(extra_size/sizeof(int)) );
-            else
-                sprintf( header_dt_buf, "%uu", extra_size );
-            header_dt = header_dt_buf;
-        }
-    }
+    if (type_name)
+      for( info = CvType::first; info != 0; info = info->next )
+        if( strcmp( info->type_name, type_name ) == 0 )
+      break;
 
-    if( header_dt )
-    {
-        cvWriteString( fs, "header_dt", header_dt, 0 );
-        cvStartWriteStruct( fs, "header_user_data", CV_NODE_SEQ + CV_NODE_FLOW );
-        cvWriteRawData( fs, (uchar*)seq + sizeof(CvSeq), 1, header_dt );
-        cvEndWriteStruct( fs );
-    }
+    return info;
 }
 
 
-static char*
-icvGetFormat( const CvSeq* seq, const char* dt_key, CvAttrList* attr,
-              int initial_elem_size, char* dt_buf )
+CV_IMPL CvTypeInfo*
+cvTypeOf( const void* struct_ptr )
 {
-    char* dt = 0;
-    dt = (char*)cvAttrValue( attr, dt_key );
+    CvTypeInfo* info = 0;
 
-    if( dt )
-    {
-        int dt_elem_size;
-        dt_elem_size = icvCalcElemSize( dt, initial_elem_size );
-        if( dt_elem_size != seq->elem_size )
-            CV_Error( CV_StsUnmatchedSizes,
-            "The size of element calculated from \"dt\" and "
-            "the elem_size do not match" );
-    }
-    else if( CV_MAT_TYPE(seq->flags) != 0 || seq->elem_size == 1 )
-    {
-        if( CV_ELEM_SIZE(seq->flags) != seq->elem_size )
-            CV_Error( CV_StsUnmatchedSizes,
-            "Size of sequence element (elem_size) is inconsistent with seq->flags" );
-        dt = icvEncodeFormat( CV_MAT_TYPE(seq->flags), dt_buf );
-    }
-    else if( seq->elem_size > initial_elem_size )
+    if( struct_ptr )
     {
-        unsigned extra_elem_size = seq->elem_size - initial_elem_size;
-        // a heuristic to provide nice defaults for sequences of int's & float's
-        if( extra_elem_size % sizeof(int) == 0 )
-            sprintf( dt_buf, "%ui", (unsigned)(extra_elem_size/sizeof(int)) );
-        else
-            sprintf( dt_buf, "%uu", extra_elem_size );
-        dt = dt_buf;
+        for( info = CvType::first; info != 0; info = info->next )
+            if( info->is_instance( struct_ptr ))
+                break;
     }
 
-    return dt;
+    return info;
 }
 
 
-static void
-icvWriteSeq( CvFileStorage* fs, const char* name,
-             const void* struct_ptr,
-             CvAttrList attr, int level )
+/* universal functions */
+CV_IMPL void
+cvRelease( void** struct_ptr )
 {
-    const CvSeq* seq = (CvSeq*)struct_ptr;
-    CvSeqBlock* block;
-    char buf[128];
-    char dt_buf[128], *dt;
-
-    assert( CV_IS_SEQ( seq ));
-    cvStartWriteStruct( fs, name, CV_NODE_MAP, CV_TYPE_NAME_SEQ );
+    CvTypeInfo* info;
 
-    if( level >= 0 )
-        cvWriteInt( fs, "level", level );
+    if( !struct_ptr )
+        CV_Error( CV_StsNullPtr, "NULL double pointer" );
 
-    dt = icvGetFormat( seq, "dt", &attr, 0, dt_buf );
+    if( *struct_ptr )
+    {
+        info = cvTypeOf( *struct_ptr );
+        if( !info )
+            CV_Error( CV_StsError, "Unknown object type" );
+        if( !info->release )
+            CV_Error( CV_StsError, "release function pointer is NULL" );
 
-    strcpy(buf, "");
-    if( CV_IS_SEQ_CLOSED(seq) )
-        strcat(buf, " closed");
-    if( CV_IS_SEQ_HOLE(seq) )
-        strcat(buf, " hole");
-    if( CV_IS_SEQ_CURVE(seq) )
-        strcat(buf, " curve");
-    if( CV_SEQ_ELTYPE(seq) == 0 && seq->elem_size != 1 )
-        strcat(buf, " untyped");
+        info->release( struct_ptr );
+        *struct_ptr = 0;
+    }
+}
 
-    cvWriteString( fs, "flags", buf + (buf[0] ? 1 : 0), 1 );
 
-    cvWriteInt( fs, "count", seq->total );
+void* cvClone( const void* struct_ptr )
+{
+    void* struct_copy = 0;
+    CvTypeInfo* info;
 
-    cvWriteString( fs, "dt", dt, 0 );
+    if( !struct_ptr )
+        CV_Error( CV_StsNullPtr, "NULL structure pointer" );
 
-    icvWriteHeaderData( fs, seq, &attr, sizeof(CvSeq) );
-    cvStartWriteStruct( fs, "data", CV_NODE_SEQ + CV_NODE_FLOW );
+    info = cvTypeOf( struct_ptr );
+    if( !info )
+        CV_Error( CV_StsError, "Unknown object type" );
+    if( !info->clone )
+        CV_Error( CV_StsError, "clone function pointer is NULL" );
 
-    for( block = seq->first; block; block = block->next )
-    {
-        cvWriteRawData( fs, block->data, block->count, dt );
-        if( block == seq->first->prev )
-            break;
-    }
-    cvEndWriteStruct( fs );
-    cvEndWriteStruct( fs );
+    struct_copy = info->clone( struct_ptr );
+    return struct_copy;
 }
 
 
-static void
-icvWriteSeqTree( CvFileStorage* fs, const char* name,
-                 const void* struct_ptr, CvAttrList attr )
+/* reads matrix, image, sequence, graph etc. */
+CV_IMPL void*
+cvRead( CvFileStorage* fs, CvFileNode* node, CvAttrList* list )
 {
-    const CvSeq* seq = (CvSeq*)struct_ptr;
-    const char* recursive_value = cvAttrValue( &attr, "recursive" );
-    int is_recursive = recursive_value &&
-                       strcmp(recursive_value,"0") != 0 &&
-                       strcmp(recursive_value,"false") != 0 &&
-                       strcmp(recursive_value,"False") != 0 &&
-                       strcmp(recursive_value,"FALSE") != 0;
-
-    assert( CV_IS_SEQ( seq ));
+    void* obj = 0;
+    CV_CHECK_FILE_STORAGE( fs );
 
-    if( !is_recursive )
-    {
-        icvWriteSeq( fs, name, seq, attr, -1 );
-    }
-    else
-    {
-        CvTreeNodeIterator tree_iterator;
+    if( !node )
+        return 0;
 
-        cvStartWriteStruct( fs, name, CV_NODE_MAP, CV_TYPE_NAME_SEQ_TREE );
-        cvStartWriteStruct( fs, "sequences", CV_NODE_SEQ );
-        cvInitTreeNodeIterator( &tree_iterator, seq, INT_MAX );
+    if( !CV_NODE_IS_USER(node->tag) || !node->info )
+        CV_Error( CV_StsError, "The node does not represent a user object (unknown type?)" );
 
-        for(;;)
-        {
-            if( !tree_iterator.node )
-                break;
-            icvWriteSeq( fs, 0, tree_iterator.node, attr, tree_iterator.level );
-            cvNextTreeNode( &tree_iterator );
-        }
+    obj = node->info->read( fs, node );
+    if( list )
+        *list = cvAttrList(0,0);
 
-        cvEndWriteStruct( fs );
-        cvEndWriteStruct( fs );
-    }
+    return obj;
 }
 
 
-static void*
-icvReadSeq( CvFileStorage* fs, CvFileNode* node )
+/* writes matrix, image, sequence, graph etc. */
+CV_IMPL void
+cvWrite( CvFileStorage* fs, const char* name,
+         const void* ptr, CvAttrList attributes )
 {
-    void* ptr = 0;
-    CvSeq* seq;
-    CvSeqBlock* block;
-    CvFileNode *data, *header_node, *rect_node, *origin_node;
-    CvSeqReader reader;
-    int total, flags;
-    int elem_size, header_size = sizeof(CvSeq);
-    int fmt_pairs[CV_FS_MAX_FMT_PAIRS], i, fmt_pair_count;
-    int items_per_elem = 0;
-    const char* flags_str;
-    const char* header_dt;
-    const char* dt;
-    char* endptr = 0;
+    CvTypeInfo* info;
 
-    flags_str = cvReadStringByName( fs, node, "flags", 0 );
-    total = cvReadIntByName( fs, node, "count", -1 );
-    dt = cvReadStringByName( fs, node, "dt", 0 );
+    CV_CHECK_OUTPUT_FILE_STORAGE( fs );
 
-    if( !flags_str || total == -1 || !dt )
-        CV_Error( CV_StsError, "Some of essential sequence attributes are absent" );
+    if( !ptr )
+        CV_Error( CV_StsNullPtr, "Null pointer to the written object" );
 
-    flags = CV_SEQ_MAGIC_VAL;
+    info = cvTypeOf( ptr );
+    if( !info )
+        CV_Error( CV_StsBadArg, "Unknown object" );
 
-    if( cv_isdigit(flags_str[0]) )
-    {
-        const int OLD_SEQ_ELTYPE_BITS = 9;
-        const int OLD_SEQ_ELTYPE_MASK = (1 << OLD_SEQ_ELTYPE_BITS) - 1;
-        const int OLD_SEQ_KIND_BITS = 3;
-        const int OLD_SEQ_KIND_MASK = ((1 << OLD_SEQ_KIND_BITS) - 1) << OLD_SEQ_ELTYPE_BITS;
-        const int OLD_SEQ_KIND_CURVE = 1 << OLD_SEQ_ELTYPE_BITS;
-        const int OLD_SEQ_FLAG_SHIFT = OLD_SEQ_KIND_BITS + OLD_SEQ_ELTYPE_BITS;
-        const int OLD_SEQ_FLAG_CLOSED = 1 << OLD_SEQ_FLAG_SHIFT;
-        const int OLD_SEQ_FLAG_HOLE = 8 << OLD_SEQ_FLAG_SHIFT;
+    if( !info->write )
+        CV_Error( CV_StsBadArg, "The object does not have write function" );
 
-        int flags0 = (int)strtol( flags_str, &endptr, 16 );
-        if( endptr == flags_str || (flags0 & CV_MAGIC_MASK) != CV_SEQ_MAGIC_VAL )
-            CV_Error( CV_StsError, "The sequence flags are invalid" );
-        if( (flags0 & OLD_SEQ_KIND_MASK) == OLD_SEQ_KIND_CURVE )
-            flags |= CV_SEQ_KIND_CURVE;
-        if( flags0 & OLD_SEQ_FLAG_CLOSED )
-            flags |= CV_SEQ_FLAG_CLOSED;
-        if( flags0 & OLD_SEQ_FLAG_HOLE )
-            flags |= CV_SEQ_FLAG_HOLE;
-        flags |= flags0 & OLD_SEQ_ELTYPE_MASK;
-    }
-    else
-    {
-        if( strstr(flags_str, "curve") )
-            flags |= CV_SEQ_KIND_CURVE;
-        if( strstr(flags_str, "closed") )
-            flags |= CV_SEQ_FLAG_CLOSED;
-        if( strstr(flags_str, "hole") )
-            flags |= CV_SEQ_FLAG_HOLE;
-        if( !strstr(flags_str, "untyped") )
-        {
-            try
-            {
-                flags |= icvDecodeSimpleFormat(dt);
-            }
-            catch(...)
-            {
-            }
-        }
-    }
+    info->write( fs, name, ptr, attributes );
+}
 
-    header_dt = cvReadStringByName( fs, node, "header_dt", 0 );
-    header_node = cvGetFileNodeByName( fs, node, "header_user_data" );
 
-    if( (header_dt != 0) ^ (header_node != 0) )
-        CV_Error( CV_StsError,
-        "One of \"header_dt\" and \"header_user_data\" is there, while the other is not" );
+/* simple API for reading/writing data */
+CV_IMPL void
+cvSave( const char* filename, const void* struct_ptr,
+        const char* _name, const char* comment, CvAttrList attributes )
+{
+    CvFileStorage* fs = 0;
 
-    rect_node = cvGetFileNodeByName( fs, node, "rect" );
-    origin_node = cvGetFileNodeByName( fs, node, "origin" );
+    if( !struct_ptr )
+        CV_Error( CV_StsNullPtr, "NULL object pointer" );
 
-    if( (header_node != 0) + (rect_node != 0) + (origin_node != 0) > 1 )
-        CV_Error( CV_StsError, "Only one of \"header_user_data\", \"rect\" and \"origin\" tags may occur" );
+    fs = cvOpenFileStorage( filename, 0, CV_STORAGE_WRITE );
+    if( !fs )
+        CV_Error( CV_StsError, "Could not open the file storage. Check the path and permissions" );
 
-    if( header_dt )
-    {
-        header_size = icvCalcElemSize( header_dt, header_size );
-    }
-    else if( rect_node )
-        header_size = sizeof(CvPoint2DSeq);
-    else if( origin_node )
-        header_size = sizeof(CvChain);
+    cv::String name = _name ? cv::String(_name) : cv::FileStorage::getDefaultObjectName(filename);
 
-    elem_size = icvCalcElemSize( dt, 0 );
-    seq = cvCreateSeq( flags, header_size, elem_size, fs->dststorage );
+    if( comment )
+        cvWriteComment( fs, comment, 0 );
+    cvWrite( fs, name.c_str(), struct_ptr, attributes );
+    cvReleaseFileStorage( &fs );
+}
 
-    if( header_node )
-    {
-        cvReadRawData( fs, header_node, (char*)seq + sizeof(CvSeq), header_dt );
-    }
-    else if( rect_node )
+CV_IMPL void*
+cvLoad( const char* filename, CvMemStorage* memstorage,
+        const char* name, const char** _real_name )
+{
+    void* ptr = 0;
+    const char* real_name = 0;
+    cv::FileStorage fs(cvOpenFileStorage(filename, memstorage, CV_STORAGE_READ));
+
+    CvFileNode* node = 0;
+
+    if( !fs.isOpened() )
+        return 0;
+
+    if( name )
     {
-        CvPoint2DSeq* point_seq = (CvPoint2DSeq*)seq;
-        point_seq->rect.x = cvReadIntByName( fs, rect_node, "x", 0 );
-        point_seq->rect.y = cvReadIntByName( fs, rect_node, "y", 0 );
-        point_seq->rect.width = cvReadIntByName( fs, rect_node, "width", 0 );
-        point_seq->rect.height = cvReadIntByName( fs, rect_node, "height", 0 );
-        point_seq->color = cvReadIntByName( fs, node, "color", 0 );
+        node = cvGetFileNodeByName( *fs, 0, name );
     }
-    else if( origin_node )
+    else
     {
-        CvChain* chain = (CvChain*)seq;
-        chain->origin.x = cvReadIntByName( fs, origin_node, "x", 0 );
-        chain->origin.y = cvReadIntByName( fs, origin_node, "y", 0 );
-    }
+        int i, k;
+        for( k = 0; k < (*fs)->roots->total; k++ )
+        {
+            CvSeq* seq;
+            CvSeqReader reader;
 
-    cvSeqPushMulti( seq, 0, total, 0 );
-    fmt_pair_count = icvDecodeFormat( dt, fmt_pairs, CV_FS_MAX_FMT_PAIRS );
-    fmt_pair_count *= 2;
-    for( i = 0; i < fmt_pair_count; i += 2 )
-        items_per_elem += fmt_pairs[i];
+            node = (CvFileNode*)cvGetSeqElem( (*fs)->roots, k );
+            if( !CV_NODE_IS_MAP( node->tag ))
+                return 0;
+            seq = node->data.seq;
+            node = 0;
 
-    data = cvGetFileNodeByName( fs, node, "data" );
-    if( !data )
-        CV_Error( CV_StsError, "The image data is not found in file storage" );
+            cvStartReadSeq( seq, &reader, 0 );
 
-    if( icvFileNodeSeqLen( data ) != total*items_per_elem )
-        CV_Error( CV_StsError, "The number of stored elements does not match to \"count\"" );
+            // find the first element in the map
+            for( i = 0; i < seq->total; i++ )
+            {
+                if( CV_IS_SET_ELEM( reader.ptr ))
+                {
+                    node = (CvFileNode*)reader.ptr;
+                    goto stop_search;
+                }
+                CV_NEXT_SEQ_ELEM( seq->elem_size, reader );
+            }
+        }
 
-    cvStartReadRawData( fs, data, &reader );
-    for( block = seq->first; block; block = block->next )
-    {
-        int delta = block->count*items_per_elem;
-        cvReadRawDataSlice( fs, &reader, delta, block->data, dt );
-        if( block == seq->first->prev )
-            break;
+stop_search:
+        ;
     }
 
-    ptr = seq;
-    return ptr;
-}
-
+    if( !node )
+        CV_Error( CV_StsObjectNotFound, "Could not find the/an object in file storage" );
 
-static void*
-icvReadSeqTree( CvFileStorage* fs, CvFileNode* node )
-{
-    void* ptr = 0;
-    CvFileNode *sequences_node = cvGetFileNodeByName( fs, node, "sequences" );
-    CvSeq* sequences;
-    CvSeq* root = 0;
-    CvSeq* parent = 0;
-    CvSeq* prev_seq = 0;
-    CvSeqReader reader;
-    int i, total;
-    int prev_level = 0;
+    real_name = cvGetFileNodeName( node );
+    ptr = cvRead( *fs, node, 0 );
 
-    if( !sequences_node || !CV_NODE_IS_SEQ(sequences_node->tag) )
-        CV_Error( CV_StsParseError,
-        "opencv-sequence-tree instance should contain a field \"sequences\" that should be a sequence" );
+    // sanity check
+    if( !memstorage && (CV_IS_SEQ( ptr ) || CV_IS_SET( ptr )) )
+        CV_Error( CV_StsNullPtr,
+        "NULL memory storage is passed - the loaded dynamic structure can not be stored" );
 
-    sequences = sequences_node->data.seq;
-    total = sequences->total;
+    if( cvGetErrStatus() < 0 )
+    {
+        cvRelease( (void**)&ptr );
+        real_name = 0;
+    }
 
-    cvStartReadSeq( sequences, &reader, 0 );
-    for( i = 0; i < total; i++ )
+    if( _real_name)
     {
-        CvFileNode* elem = (CvFileNode*)reader.ptr;
-        CvSeq* seq;
-        int level;
-        seq = (CvSeq*)cvRead( fs, elem );
-        level = cvReadIntByName( fs, elem, "level", -1 );
-        if( level < 0 )
-            CV_Error( CV_StsParseError, "All the sequence tree nodes should contain \"level\" field" );
-        if( !root )
-            root = seq;
-        if( level > prev_level )
-        {
-            assert( level == prev_level + 1 );
-            parent = prev_seq;
-            prev_seq = 0;
-            if( parent )
-                parent->v_next = seq;
-        }
-        else if( level < prev_level )
-        {
-            for( ; prev_level > level; prev_level-- )
-                prev_seq = prev_seq->v_prev;
-            parent = prev_seq->v_prev;
-        }
-        seq->h_prev = prev_seq;
-        if( prev_seq )
-            prev_seq->h_next = seq;
-        seq->v_prev = parent;
-        prev_seq = seq;
-        prev_level = level;
-        CV_NEXT_SEQ_ELEM( sequences->elem_size, reader );
+    if (real_name)
+    {
+        *_real_name = (const char*)cvAlloc(strlen(real_name));
+            memcpy((void*)*_real_name, real_name, strlen(real_name));
+    } else {
+        *_real_name = 0;
+    }
     }
 
-    ptr = root;
     return ptr;
 }
 
-/******************************* CvGraph ******************************/
-
-static int
-icvIsGraph( const void* ptr )
-{
-    return CV_IS_GRAPH(ptr);
-}
 
+///////////////////////// new C++ interface for CvFileStorage ///////////////////////////
 
-static void
-icvReleaseGraph( void** ptr )
+namespace cv
 {
-    if( !ptr )
-        CV_Error( CV_StsNullPtr, "NULL double pointer" );
 
-    *ptr = 0; // it's impossible now to release graph, so just clear the pointer
+static void getElemSize( const String& fmt, size_t& elemSize, size_t& cn )
+{
+    const char* dt = fmt.c_str();
+    cn = 1;
+    if( cv_isdigit(dt[0]) )
+    {
+        cn = dt[0] - '0';
+        dt++;
+    }
+    char c = dt[0];
+    elemSize = cn*(c == 'u' || c == 'c' ? sizeof(uchar) : c == 'w' || c == 's' ? sizeof(ushort) :
+        c == 'i' ? sizeof(int) : c == 'f' ? sizeof(float) : c == 'd' ? sizeof(double) :
+        c == 'r' ? sizeof(void*) : (size_t)0);
 }
 
-
-static void*
-icvCloneGraph( const void* ptr )
+FileStorage::FileStorage()
 {
-    return cvCloneGraph( (const CvGraph*)ptr, 0 );
+    state = UNDEFINED;
 }
 
+FileStorage::FileStorage(const String& filename, int flags, const String& encoding)
+{
+    state = UNDEFINED;
+    open( filename, flags, encoding );
+}
 
-static void
-icvWriteGraph( CvFileStorage* fs, const char* name,
-               const void* struct_ptr, CvAttrList attr )
+FileStorage::FileStorage(CvFileStorage* _fs, bool owning)
 {
-    int* flag_buf = 0;
-    char* write_buf = 0;
-    const CvGraph* graph = (const CvGraph*)struct_ptr;
-    CvSeqReader reader;
-    char buf[128];
-    int i, k, vtx_count, edge_count;
-    char vtx_dt_buf[128], *vtx_dt;
-    char edge_dt_buf[128], *edge_dt;
-    int write_buf_size;
+    if (owning) fs.reset(_fs);
+    else fs = Ptr<CvFileStorage>(Ptr<CvFileStorage>(), _fs);
 
-    assert( CV_IS_GRAPH(graph) );
-    vtx_count = cvGraphGetVtxCount( graph );
-    edge_count = cvGraphGetEdgeCount( graph );
-    flag_buf = (int*)cvAlloc( vtx_count*sizeof(flag_buf[0]));
+    state = _fs ? NAME_EXPECTED + INSIDE_MAP : UNDEFINED;
+}
 
-    // count vertices
-    cvStartReadSeq( (CvSeq*)graph, &reader );
-    for( i = 0, k = 0; i < graph->total; i++ )
+FileStorage::~FileStorage()
+{
+    while( structs.size() > 0 )
     {
-        if( CV_IS_SET_ELEM( reader.ptr ))
-        {
-            CvGraphVtx* vtx = (CvGraphVtx*)reader.ptr;
-            flag_buf[k] = vtx->flags;
-            vtx->flags = k++;
-        }
-        CV_NEXT_SEQ_ELEM( graph->elem_size, reader );
+        cvEndWriteStruct(fs);
+        structs.pop_back();
     }
+}
 
-    // write header
-    cvStartWriteStruct( fs, name, CV_NODE_MAP, CV_TYPE_NAME_GRAPH );
-
-    cvWriteString(fs, "flags", CV_IS_GRAPH_ORIENTED(graph) ? "oriented" : "", 1);
+bool FileStorage::open(const String& filename, int flags, const String& encoding)
+{
+    CV_INSTRUMENT_REGION()
 
-    cvWriteInt( fs, "vertex_count", vtx_count );
-    vtx_dt = icvGetFormat( (CvSeq*)graph, "vertex_dt",
-                    &attr, sizeof(CvGraphVtx), vtx_dt_buf );
-    if( vtx_dt )
-        cvWriteString( fs, "vertex_dt", vtx_dt, 0 );
+    release();
+    fs.reset(cvOpenFileStorage( filename.c_str(), 0, flags,
+                                !encoding.empty() ? encoding.c_str() : 0));
+    bool ok = isOpened();
+    state = ok ? NAME_EXPECTED + INSIDE_MAP : UNDEFINED;
+    return ok;
+}
 
-    cvWriteInt( fs, "edge_count", edge_count );
-    edge_dt = icvGetFormat( (CvSeq*)graph->edges, "edge_dt",
-                                &attr, sizeof(CvGraphEdge), buf );
-    sprintf( edge_dt_buf, "2if%s", edge_dt ? edge_dt : "" );
-    edge_dt = edge_dt_buf;
-    cvWriteString( fs, "edge_dt", edge_dt, 0 );
+bool FileStorage::isOpened() const
+{
+    return fs && fs->is_opened;
+}
 
-    icvWriteHeaderData( fs, (CvSeq*)graph, &attr, sizeof(CvGraph) );
+void FileStorage::release()
+{
+    fs.release();
+    structs.clear();
+    state = UNDEFINED;
+}
 
-    write_buf_size = MAX( 3*graph->elem_size, 1 << 16 );
-    write_buf_size = MAX( 3*graph->edges->elem_size, write_buf_size );
-    write_buf = (char*)cvAlloc( write_buf_size );
+String FileStorage::releaseAndGetString()
+{
+    String buf;
+    if( fs && fs->outbuf )
+        icvClose(fs, &buf);
 
-    // as vertices and edges are written in similar way,
-    // do it as a parametrized 2-iteration loop
-    for( k = 0; k < 2; k++ )
-    {
-        const char* dt = k == 0 ? vtx_dt : edge_dt;
-        if( dt )
-        {
-            CvSet* data = k == 0 ? (CvSet*)graph : graph->edges;
-            int elem_size = data->elem_size;
-            int write_elem_size = icvCalcElemSize( dt, 0 );
-            char* src_ptr = write_buf;
-            int write_max = write_buf_size / write_elem_size, write_count = 0;
+    release();
+    return buf;
+}
 
-            // alignment of user part of the edge data following 2if
-            int edge_user_align = sizeof(float);
+FileNode FileStorage::root(int streamidx) const
+{
+    return isOpened() ? FileNode(fs, cvGetRootFileNode(fs, streamidx)) : FileNode();
+}
 
-            if( k == 1 )
-            {
-                int fmt_pairs[CV_FS_MAX_FMT_PAIRS], fmt_pair_count;
-                fmt_pair_count = icvDecodeFormat( dt, fmt_pairs, CV_FS_MAX_FMT_PAIRS );
-                if( fmt_pair_count > 2 && CV_ELEM_SIZE(fmt_pairs[2*2+1]) >= (int)sizeof(double))
-                    edge_user_align = sizeof(double);
-            }
+FileStorage& operator << (FileStorage& fs, const String& str)
+{
+    CV_INSTRUMENT_REGION()
 
-            cvStartWriteStruct( fs, k == 0 ? "vertices" : "edges",
-                                CV_NODE_SEQ + CV_NODE_FLOW );
-            cvStartReadSeq( (CvSeq*)data, &reader );
-            for( i = 0; i < data->total; i++ )
+    enum { NAME_EXPECTED = FileStorage::NAME_EXPECTED,
+        VALUE_EXPECTED = FileStorage::VALUE_EXPECTED,
+        INSIDE_MAP = FileStorage::INSIDE_MAP };
+    const char* _str = str.c_str();
+    if( !fs.isOpened() || !_str )
+        return fs;
+    if( *_str == '}' || *_str == ']' )
+    {
+        if( fs.structs.empty() )
+            CV_Error_( CV_StsError, ("Extra closing '%c'", *_str) );
+        if( (*_str == ']' ? '[' : '{') != fs.structs.back() )
+            CV_Error_( CV_StsError,
+            ("The closing '%c' does not match the opening '%c'", *_str, fs.structs.back()));
+        fs.structs.pop_back();
+        fs.state = fs.structs.empty() || fs.structs.back() == '{' ?
+            INSIDE_MAP + NAME_EXPECTED : VALUE_EXPECTED;
+        cvEndWriteStruct( *fs );
+        fs.elname = String();
+    }
+    else if( fs.state == NAME_EXPECTED + INSIDE_MAP )
+    {
+        if (!cv_isalpha(*_str) && *_str != '_')
+            CV_Error_( CV_StsError, ("Incorrect element name %s", _str) );
+        fs.elname = str;
+        fs.state = VALUE_EXPECTED + INSIDE_MAP;
+    }
+    else if( (fs.state & 3) == VALUE_EXPECTED )
+    {
+        if( *_str == '{' || *_str == '[' )
+        {
+            fs.structs.push_back(*_str);
+            int flags = *_str++ == '{' ? CV_NODE_MAP : CV_NODE_SEQ;
+            fs.state = flags == CV_NODE_MAP ? INSIDE_MAP +
+                NAME_EXPECTED : VALUE_EXPECTED;
+            if( *_str == ':' )
             {
-                if( CV_IS_SET_ELEM( reader.ptr ))
-                {
-                    if( k == 0 ) // vertices
-                        memcpy( src_ptr, reader.ptr + sizeof(CvGraphVtx), write_elem_size );
-                    else
-                    {
-                        CvGraphEdge* edge = (CvGraphEdge*)reader.ptr;
-                        src_ptr = (char*)cvAlignPtr( src_ptr, sizeof(int) );
-                        ((int*)src_ptr)[0] = edge->vtx[0]->flags;
-                        ((int*)src_ptr)[1] = edge->vtx[1]->flags;
-                        *(float*)(src_ptr + sizeof(int)*2) = edge->weight;
-                        if( elem_size > (int)sizeof(CvGraphEdge) )
-                        {
-                            char* src_ptr2 = (char*)cvAlignPtr( src_ptr + 2*sizeof(int)
-                                                + sizeof(float), edge_user_align );
-                            memcpy( src_ptr2, edge + 1, elem_size - sizeof(CvGraphEdge) );
-                        }
-                    }
-                    src_ptr += write_elem_size;
-                    if( ++write_count >= write_max )
-                    {
-                        cvWriteRawData( fs, write_buf, write_count, dt );
-                        write_count = 0;
-                        src_ptr = write_buf;
-                    }
-                }
-                CV_NEXT_SEQ_ELEM( data->elem_size, reader );
+                flags |= CV_NODE_FLOW;
+                _str++;
             }
-
-            if( write_count > 0 )
-                cvWriteRawData( fs, write_buf, write_count, dt );
-            cvEndWriteStruct( fs );
+            cvStartWriteStruct( *fs, fs.elname.size() > 0 ? fs.elname.c_str() : 0,
+                flags, *_str ? _str : 0 );
+            fs.elname = String();
+        }
+        else
+        {
+            write( fs, fs.elname, (_str[0] == '\\' && (_str[1] == '{' || _str[1] == '}' ||
+                _str[1] == '[' || _str[1] == ']')) ? String(_str+1) : str );
+            if( fs.state == INSIDE_MAP + VALUE_EXPECTED )
+                fs.state = INSIDE_MAP + NAME_EXPECTED;
         }
     }
+    else
+        CV_Error( CV_StsError, "Invalid fs.state" );
+    return fs;
+}
 
-    cvEndWriteStruct( fs );
-
-    // final stage. restore the graph flags
-    cvStartReadSeq( (CvSeq*)graph, &reader );
-    vtx_count = 0;
-    for( i = 0; i < graph->total; i++ )
-    {
-        if( CV_IS_SET_ELEM( reader.ptr ))
-            ((CvGraphVtx*)reader.ptr)->flags = flag_buf[vtx_count++];
-        CV_NEXT_SEQ_ELEM( graph->elem_size, reader );
-    }
 
-    cvFree( &write_buf );
-    cvFree( &flag_buf );
+void FileStorage::writeRaw( const String& fmt, const uchar* vec, size_t len )
+{
+    if( !isOpened() )
+        return;
+    size_t elemSize, cn;
+    getElemSize( fmt, elemSize, cn );
+    CV_Assert( len % elemSize == 0 );
+    cvWriteRawData( fs, vec, (int)(len/elemSize), fmt.c_str());
 }
 
 
-static void*
-icvReadGraph( CvFileStorage* fs, CvFileNode* node )
+void FileStorage::writeObj( const String& name, const void* obj )
 {
-    void* ptr = 0;
-    char* read_buf = 0;
-    CvGraphVtx** vtx_buf = 0;
-    CvGraph* graph;
-    CvFileNode *header_node, *vtx_node, *edge_node;
-    int flags, vtx_count, edge_count;
-    int vtx_size = sizeof(CvGraphVtx), edge_size, header_size = sizeof(CvGraph);
-    int src_vtx_size = 0, src_edge_size;
-    int fmt_pairs[CV_FS_MAX_FMT_PAIRS], fmt_pair_count;
-    int vtx_items_per_elem = 0, edge_items_per_elem = 0;
-    int edge_user_align = sizeof(float);
-    int read_buf_size;
-    int i, k;
-    const char* flags_str;
-    const char* header_dt;
-    const char* vtx_dt;
-    const char* edge_dt;
-    char* endptr = 0;
-
-    flags_str = cvReadStringByName( fs, node, "flags", 0 );
-    vtx_dt = cvReadStringByName( fs, node, "vertex_dt", 0 );
-    edge_dt = cvReadStringByName( fs, node, "edge_dt", 0 );
-    vtx_count = cvReadIntByName( fs, node, "vertex_count", -1 );
-    edge_count = cvReadIntByName( fs, node, "edge_count", -1 );
+    if( !isOpened() )
+        return;
+    cvWrite( fs, name.size() > 0 ? name.c_str() : 0, obj );
+}
 
-    if( !flags_str || vtx_count == -1 || edge_count == -1 || !edge_dt )
-        CV_Error( CV_StsError, "Some of essential graph attributes are absent" );
+void FileStorage::write( const String& name, double val )
+{
+    *this << name << val;
+}
 
-    flags = CV_SET_MAGIC_VAL + CV_GRAPH;
+void FileStorage::write( const String& name, const String& val )
+{
+    *this << name << val;
+}
 
-    if( isxdigit(flags_str[0]) )
-    {
-        const int OLD_SEQ_ELTYPE_BITS = 9;
-        const int OLD_SEQ_KIND_BITS = 3;
-        const int OLD_SEQ_FLAG_SHIFT = OLD_SEQ_KIND_BITS + OLD_SEQ_ELTYPE_BITS;
-        const int OLD_GRAPH_FLAG_ORIENTED = 1 << OLD_SEQ_FLAG_SHIFT;
+void FileStorage::write( const String& name, InputArray val )
+{
+    *this << name << val.getMat();
+}
 
-        int flags0 = (int)strtol( flags_str, &endptr, 16 );
-        if( endptr == flags_str || (flags0 & CV_MAGIC_MASK) != CV_SET_MAGIC_VAL )
-            CV_Error( CV_StsError, "The sequence flags are invalid" );
-        if( flags0 & OLD_GRAPH_FLAG_ORIENTED )
-            flags |= CV_GRAPH_FLAG_ORIENTED;
-    }
-    else
-    {
-        if( strstr(flags_str, "oriented") )
-            flags |= CV_GRAPH_FLAG_ORIENTED;
-    }
+void FileStorage::writeComment( const String& comment, bool append )
+{
+    cvWriteComment(fs, comment.c_str(), append ? 1 : 0);
+}
 
-    header_dt = cvReadStringByName( fs, node, "header_dt", 0 );
-    header_node = cvGetFileNodeByName( fs, node, "header_user_data" );
+FileNode FileStorage::operator[](const String& nodename) const
+{
+    return FileNode(fs, cvGetFileNodeByName(fs, 0, nodename.c_str()));
+}
 
-    if( (header_dt != 0) ^ (header_node != 0) )
-        CV_Error( CV_StsError,
-        "One of \"header_dt\" and \"header_user_data\" is there, while the other is not" );
+FileNode FileStorage::operator[](const char* nodename) const
+{
+    return FileNode(fs, cvGetFileNodeByName(fs, 0, nodename));
+}
 
-    if( header_dt )
-        header_size = icvCalcElemSize( header_dt, header_size );
+FileNode FileNode::operator[](const String& nodename) const
+{
+    return FileNode(fs, cvGetFileNodeByName(fs, node, nodename.c_str()));
+}
 
-    if( vtx_dt )
-    {
-        src_vtx_size = icvCalcElemSize( vtx_dt, 0 );
-        vtx_size = icvCalcElemSize( vtx_dt, vtx_size );
-        fmt_pair_count = icvDecodeFormat( edge_dt,
-                            fmt_pairs, CV_FS_MAX_FMT_PAIRS );
-        fmt_pair_count *= 2;
-        for( i = 0; i < fmt_pair_count; i += 2 )
-            vtx_items_per_elem += fmt_pairs[i];
-    }
+FileNode FileNode::operator[](const char* nodename) const
+{
+    return FileNode(fs, cvGetFileNodeByName(fs, node, nodename));
+}
 
-    {
-        char dst_edge_dt_buf[128];
-        const char* dst_edge_dt = 0;
+FileNode FileNode::operator[](int i) const
+{
+    return isSeq() ? FileNode(fs, (CvFileNode*)cvGetSeqElem(node->data.seq, i)) :
+        i == 0 ? *this : FileNode();
+}
 
-        fmt_pair_count = icvDecodeFormat( edge_dt,
-                            fmt_pairs, CV_FS_MAX_FMT_PAIRS );
-        if( fmt_pair_count < 2 ||
-            fmt_pairs[0] != 2 || fmt_pairs[1] != CV_32S ||
-            fmt_pairs[2] < 1 || fmt_pairs[3] != CV_32F )
-            CV_Error( CV_StsBadArg,
-            "Graph edges should start with 2 integers and a float" );
+String FileNode::name() const
+{
+    const char* str;
+    return !node || (str = cvGetFileNodeName(node)) == 0 ? String() : String(str);
+}
 
-        // alignment of user part of the edge data following 2if
-        if( fmt_pair_count > 2 && CV_ELEM_SIZE(fmt_pairs[5]) >= (int)sizeof(double))
-            edge_user_align = sizeof(double);
+void* FileNode::readObj() const
+{
+    if( !fs || !node )
+        return 0;
+    return cvRead( (CvFileStorage*)fs, (CvFileNode*)node );
+}
 
-        fmt_pair_count *= 2;
-        for( i = 0; i < fmt_pair_count; i += 2 )
-            edge_items_per_elem += fmt_pairs[i];
+FileNodeIterator::FileNodeIterator()
+{
+    fs = 0;
+    container = 0;
+    reader.ptr = 0;
+    remaining = 0;
+}
 
-        if( edge_dt[2] == 'f' || (edge_dt[2] == '1' && edge_dt[3] == 'f') )
-            dst_edge_dt = edge_dt + 3 + cv_isdigit(edge_dt[2]);
+FileNodeIterator::FileNodeIterator(const CvFileStorage* _fs,
+                                   const CvFileNode* _node, size_t _ofs)
+{
+    if( _fs && _node && CV_NODE_TYPE(_node->tag) != CV_NODE_NONE )
+    {
+        int node_type = _node->tag & FileNode::TYPE_MASK;
+        fs = _fs;
+        container = _node;
+        if( !(_node->tag & FileNode::USER) && (node_type == FileNode::SEQ || node_type == FileNode::MAP) )
+        {
+            cvStartReadSeq( _node->data.seq, (CvSeqReader*)&reader );
+            remaining = FileNode(_fs, _node).size();
+        }
         else
         {
-            int val = (int)strtol( edge_dt + 2, &endptr, 10 );
-            sprintf( dst_edge_dt_buf, "%df%s", val-1, endptr );
-            dst_edge_dt = dst_edge_dt_buf;
+            reader.ptr = (schar*)_node;
+            reader.seq = 0;
+            remaining = 1;
         }
-
-        edge_size = icvCalcElemSize( dst_edge_dt, sizeof(CvGraphEdge) );
-        src_edge_size = icvCalcElemSize( edge_dt, 0 );
+        (*this) += (int)_ofs;
     }
+    else
+    {
+        fs = 0;
+        container = 0;
+        reader.ptr = 0;
+        remaining = 0;
+    }
+}
 
-    graph = cvCreateGraph( flags, header_size, vtx_size, edge_size, fs->dststorage );
-
-    if( header_node )
-        cvReadRawData( fs, header_node, (char*)graph + sizeof(CvGraph), header_dt );
-
-    read_buf_size = MAX( src_vtx_size*3, 1 << 16 );
-    read_buf_size = MAX( src_edge_size*3, read_buf_size );
-    read_buf = (char*)cvAlloc( read_buf_size );
-    vtx_buf = (CvGraphVtx**)cvAlloc( vtx_count * sizeof(vtx_buf[0]) );
-
-    vtx_node = cvGetFileNodeByName( fs, node, "vertices" );
-    edge_node = cvGetFileNodeByName( fs, node, "edges" );
-    if( !edge_node )
-        CV_Error( CV_StsBadArg, "No edges data" );
-    if( vtx_dt && !vtx_node )
-        CV_Error( CV_StsBadArg, "No vertices data" );
+FileNodeIterator::FileNodeIterator(const FileNodeIterator& it)
+{
+    fs = it.fs;
+    container = it.container;
+    reader = it.reader;
+    remaining = it.remaining;
+}
 
-    // as vertices and edges are read in similar way,
-    // do it as a parametrized 2-iteration loop
-    for( k = 0; k < 2; k++ )
+FileNodeIterator& FileNodeIterator::operator ++()
+{
+    if( remaining > 0 )
     {
-        const char* dt = k == 0 ? vtx_dt : edge_dt;
-        int elem_size = k == 0 ? vtx_size : edge_size;
-        int src_elem_size = k == 0 ? src_vtx_size : src_edge_size;
-        int items_per_elem = k == 0 ? vtx_items_per_elem : edge_items_per_elem;
-        int elem_count = k == 0 ? vtx_count : edge_count;
-        char* dst_ptr = read_buf;
-        int read_max = read_buf_size /MAX(src_elem_size, 1), read_count = 0;
-        CvSeqReader reader;
-        if(dt)
-            cvStartReadRawData( fs, k == 0 ? vtx_node : edge_node, &reader );
-
-        for( i = 0; i < elem_count; i++ )
+        if( reader.seq )
         {
-            if( read_count == 0 && dt )
-            {
-                int count = MIN( elem_count - i, read_max )*items_per_elem;
-                cvReadRawDataSlice( fs, &reader, count, read_buf, dt );
-                read_count = count;
-                dst_ptr = read_buf;
-            }
-
-            if( k == 0 )
+            if( ((reader).ptr += (((CvSeq*)reader.seq)->elem_size)) >= (reader).block_max )
             {
-                CvGraphVtx* vtx;
-                cvGraphAddVtx( graph, 0, &vtx );
-                vtx_buf[i] = vtx;
-                if( dt )
-                    memcpy( vtx + 1, dst_ptr, src_elem_size );
+                cvChangeSeqBlock( (CvSeqReader*)&(reader), 1 );
             }
-            else
-            {
-                CvGraphEdge* edge = 0;
-                int vtx1 = ((int*)dst_ptr)[0];
-                int vtx2 = ((int*)dst_ptr)[1];
-                int result;
-
-                if( (unsigned)vtx1 >= (unsigned)vtx_count ||
-                    (unsigned)vtx2 >= (unsigned)vtx_count )
-                    CV_Error( CV_StsOutOfRange,
-                    "Some of stored vertex indices are out of range" );
-
-                result = cvGraphAddEdgeByPtr( graph,
-                    vtx_buf[vtx1], vtx_buf[vtx2], 0, &edge );
-
-                if( result == 0 )
-                    CV_Error( CV_StsBadArg, "Duplicated edge has occured" );
+        }
+        remaining--;
+    }
+    return *this;
+}
 
-                edge->weight = *(float*)(dst_ptr + sizeof(int)*2);
-                if( elem_size > (int)sizeof(CvGraphEdge) )
-                {
-                    char* dst_ptr2 = (char*)cvAlignPtr( dst_ptr + sizeof(int)*2 +
-                                                sizeof(float), edge_user_align );
-                    memcpy( edge + 1, dst_ptr2, elem_size - sizeof(CvGraphEdge) );
-                }
-            }
+FileNodeIterator FileNodeIterator::operator ++(int)
+{
+    FileNodeIterator it = *this;
+    ++(*this);
+    return it;
+}
 
-            dst_ptr += src_elem_size;
-            read_count--;
+FileNodeIterator& FileNodeIterator::operator --()
+{
+    if( remaining < FileNode(fs, container).size() )
+    {
+        if( reader.seq )
+        {
+            if( ((reader).ptr -= (((CvSeq*)reader.seq)->elem_size)) < (reader).block_min )
+            {
+                cvChangeSeqBlock( (CvSeqReader*)&(reader), -1 );
+            }
         }
+        remaining++;
     }
-
-    ptr = graph;
-    cvFree( &read_buf );
-    cvFree( &vtx_buf );
-
-    return ptr;
+    return *this;
 }
 
-/****************************************************************************************\
-*                                    RTTI Functions                                      *
-\****************************************************************************************/
-
-CvTypeInfo *CvType::first = 0, *CvType::last = 0;
-
-CvType::CvType( const char* type_name,
-                CvIsInstanceFunc is_instance, CvReleaseFunc release,
-                CvReadFunc read, CvWriteFunc write, CvCloneFunc clone )
+FileNodeIterator FileNodeIterator::operator --(int)
 {
-    CvTypeInfo _info;
-    _info.flags = 0;
-    _info.header_size = sizeof(_info);
-    _info.type_name = type_name;
-    _info.prev = _info.next = 0;
-    _info.is_instance = is_instance;
-    _info.release = release;
-    _info.clone = clone;
-    _info.read = read;
-    _info.write = write;
-
-    cvRegisterType( &_info );
-    info = first;
+    FileNodeIterator it = *this;
+    --(*this);
+    return it;
 }
 
-
-CvType::~CvType()
+FileNodeIterator& FileNodeIterator::operator += (int ofs)
 {
-    cvUnregisterType( info->type_name );
+    if( ofs == 0 )
+        return *this;
+    if( ofs > 0 )
+        ofs = std::min(ofs, (int)remaining);
+    else
+    {
+        size_t count = FileNode(fs, container).size();
+        ofs = (int)(remaining - std::min(remaining - ofs, count));
+    }
+    remaining -= ofs;
+    if( reader.seq )
+        cvSetSeqReaderPos( (CvSeqReader*)&reader, ofs, 1 );
+    return *this;
 }
 
+FileNodeIterator& FileNodeIterator::operator -= (int ofs)
+{
+    return operator += (-ofs);
+}
 
-CvType seq_type( CV_TYPE_NAME_SEQ, icvIsSeq, icvReleaseSeq, icvReadSeq,
-                 icvWriteSeqTree /* this is the entry point for
-                 writing a single sequence too */, icvCloneSeq );
 
-CvType seq_tree_type( CV_TYPE_NAME_SEQ_TREE, icvIsSeq, icvReleaseSeq,
-                      icvReadSeqTree, icvWriteSeqTree, icvCloneSeq );
+FileNodeIterator& FileNodeIterator::readRaw( const String& fmt, uchar* vec, size_t maxCount )
+{
+    if( fs && container && remaining > 0 )
+    {
+        size_t elem_size, cn;
+        getElemSize( fmt, elem_size, cn );
+        CV_Assert( elem_size > 0 );
+        size_t count = std::min(remaining, maxCount);
 
-CvType seq_graph_type( CV_TYPE_NAME_GRAPH, icvIsGraph, icvReleaseGraph,
-                       icvReadGraph, icvWriteGraph, icvCloneGraph );
+        if( reader.seq )
+        {
+            cvReadRawDataSlice( fs, (CvSeqReader*)&reader, (int)count, vec, fmt.c_str() );
+            remaining -= count*cn;
+        }
+        else
+        {
+            cvReadRawData( fs, container, vec, fmt.c_str() );
+            remaining = 0;
+        }
+    }
+    return *this;
+}
 
-CvType sparse_mat_type( CV_TYPE_NAME_SPARSE_MAT, icvIsSparseMat,
-                        (CvReleaseFunc)cvReleaseSparseMat, icvReadSparseMat,
-                        icvWriteSparseMat, (CvCloneFunc)cvCloneSparseMat );
 
-CvType image_type( CV_TYPE_NAME_IMAGE, icvIsImage, (CvReleaseFunc)cvReleaseImage,
-                   icvReadImage, icvWriteImage, (CvCloneFunc)cvCloneImage );
+void write( FileStorage& fs, const String& name, int value )
+{ cvWriteInt( *fs, name.size() ? name.c_str() : 0, value ); }
 
-CvType mat_type( CV_TYPE_NAME_MAT, icvIsMat, (CvReleaseFunc)cvReleaseMat,
-                 icvReadMat, icvWriteMat, (CvCloneFunc)cvCloneMat );
+void write( FileStorage& fs, const String& name, float value )
+{ cvWriteReal( *fs, name.size() ? name.c_str() : 0, value ); }
 
-CvType matnd_type( CV_TYPE_NAME_MATND, icvIsMatND, (CvReleaseFunc)cvReleaseMatND,
-                   icvReadMatND, icvWriteMatND, (CvCloneFunc)cvCloneMatND );
+void write( FileStorage& fs, const String& name, double value )
+{ cvWriteReal( *fs, name.size() ? name.c_str() : 0, value ); }
 
-CV_IMPL  void
-cvRegisterType( const CvTypeInfo* _info )
-{
-    CvTypeInfo* info = 0;
-    int i, len;
-    char c;
+void write( FileStorage& fs, const String& name, const String& value )
+{ cvWriteString( *fs, name.size() ? name.c_str() : 0, value.c_str() ); }
 
-    //if( !CvType::first )
-    //    icvCreateStandardTypes();
+void writeScalar(FileStorage& fs, int value )
+{ cvWriteInt( *fs, 0, value ); }
 
-    if( !_info || _info->header_size != sizeof(CvTypeInfo) )
-        CV_Error( CV_StsBadSize, "Invalid type info" );
+void writeScalar(FileStorage& fs, float value )
+{ cvWriteReal( *fs, 0, value ); }
 
-    if( !_info->is_instance || !_info->release ||
-        !_info->read || !_info->write )
-        CV_Error( CV_StsNullPtr,
-        "Some of required function pointers "
-        "(is_instance, release, read or write) are NULL");
+void writeScalar(FileStorage& fs, double value )
+{ cvWriteReal( *fs, 0, value ); }
 
-    c = _info->type_name[0];
-    if( !cv_isalpha(c) && c != '_' )
-        CV_Error( CV_StsBadArg, "Type name should start with a letter or _" );
+void writeScalar(FileStorage& fs, const String& value )
+{ cvWriteString( *fs, 0, value.c_str() ); }
 
-    len = (int)strlen(_info->type_name);
 
-    for( i = 0; i < len; i++ )
+void write( FileStorage& fs, const String& name, const Mat& value )
+{
+    if( value.dims <= 2 )
     {
-        c = _info->type_name[i];
-        if( !cv_isalnum(c) && c != '-' && c != '_' )
-            CV_Error( CV_StsBadArg,
-            "Type name should contain only letters, digits, - and _" );
+        CvMat mat = value;
+        cvWrite( *fs, name.size() ? name.c_str() : 0, &mat );
     }
-
-    info = (CvTypeInfo*)cvAlloc( sizeof(*info) + len + 1 );
-
-    *info = *_info;
-    info->type_name = (char*)(info + 1);
-    memcpy( (char*)info->type_name, _info->type_name, len + 1 );
-
-    info->flags = 0;
-    info->next = CvType::first;
-    info->prev = 0;
-    if( CvType::first )
-        CvType::first->prev = info;
     else
-        CvType::last = info;
-    CvType::first = info;
+    {
+        CvMatND mat = value;
+        cvWrite( *fs, name.size() ? name.c_str() : 0, &mat );
+    }
 }
 
-
-CV_IMPL void
-cvUnregisterType( const char* type_name )
+// TODO: the 4 functions below need to be implemented more efficiently
+void write( FileStorage& fs, const String& name, const SparseMat& value )
 {
-    CvTypeInfo* info;
+    Ptr<CvSparseMat> mat(cvCreateSparseMat(value));
+    cvWrite( *fs, name.size() ? name.c_str() : 0, mat );
+}
 
-    info = cvFindType( type_name );
-    if( info )
+
+internal::WriteStructContext::WriteStructContext(FileStorage& _fs,
+    const String& name, int flags, const String& typeName) : fs(&_fs)
+{
+    cvStartWriteStruct(**fs, !name.empty() ? name.c_str() : 0, flags,
+                       !typeName.empty() ? typeName.c_str() : 0);
+    fs->elname = String();
+    if ((flags & FileNode::TYPE_MASK) == FileNode::SEQ)
     {
-        if( info->prev )
-            info->prev->next = info->next;
-        else
-            CvType::first = info->next;
+        fs->state = FileStorage::VALUE_EXPECTED;
+        fs->structs.push_back('[');
+    }
+    else
+    {
+        fs->state = FileStorage::NAME_EXPECTED + FileStorage::INSIDE_MAP;
+        fs->structs.push_back('{');
+    }
+}
 
-        if( info->next )
-            info->next->prev = info->prev;
-        else
-            CvType::last = info->prev;
+internal::WriteStructContext::~WriteStructContext()
+{
+    cvEndWriteStruct(**fs);
+    fs->structs.pop_back();
+    fs->state = fs->structs.empty() || fs->structs.back() == '{' ?
+        FileStorage::NAME_EXPECTED + FileStorage::INSIDE_MAP :
+        FileStorage::VALUE_EXPECTED;
+    fs->elname = String();
+}
 
-        if( !CvType::first || !CvType::last )
-            CvType::first = CvType::last = 0;
 
-        cvFree( &info );
+void read( const FileNode& node, Mat& mat, const Mat& default_mat )
+{
+    if( node.empty() )
+    {
+        default_mat.copyTo(mat);
+        return;
+    }
+    void* obj = cvRead((CvFileStorage*)node.fs, (CvFileNode*)*node);
+    if(CV_IS_MAT_HDR_Z(obj))
+    {
+        cvarrToMat(obj).copyTo(mat);
+        cvReleaseMat((CvMat**)&obj);
+    }
+    else if(CV_IS_MATND_HDR(obj))
+    {
+        cvarrToMat(obj).copyTo(mat);
+        cvReleaseMatND((CvMatND**)&obj);
+    }
+    else
+    {
+        cvRelease(&obj);
+        CV_Error(CV_StsBadArg, "Unknown array type");
     }
 }
 
-
-CV_IMPL CvTypeInfo*
-cvFirstType( void )
+void read( const FileNode& node, SparseMat& mat, const SparseMat& default_mat )
 {
-    return CvType::first;
+    if( node.empty() )
+    {
+        default_mat.copyTo(mat);
+        return;
+    }
+    Ptr<CvSparseMat> m((CvSparseMat*)cvRead((CvFileStorage*)node.fs, (CvFileNode*)*node));
+    CV_Assert(CV_IS_SPARSE_MAT(m));
+    m->copyToSparseMat(mat);
 }
 
-
-CV_IMPL CvTypeInfo*
-cvFindType( const char* type_name )
+void write(FileStorage& fs, const String& objname, const std::vector<KeyPoint>& keypoints)
 {
-    CvTypeInfo* info = 0;
-
-    if (type_name)
-      for( info = CvType::first; info != 0; info = info->next )
-        if( strcmp( info->type_name, type_name ) == 0 )
-      break;
+    cv::internal::WriteStructContext ws(fs, objname, CV_NODE_SEQ + CV_NODE_FLOW);
 
-    return info;
+    int i, npoints = (int)keypoints.size();
+    for( i = 0; i < npoints; i++ )
+    {
+        const KeyPoint& kpt = keypoints[i];
+        cv::write(fs, kpt.pt.x);
+        cv::write(fs, kpt.pt.y);
+        cv::write(fs, kpt.size);
+        cv::write(fs, kpt.angle);
+        cv::write(fs, kpt.response);
+        cv::write(fs, kpt.octave);
+        cv::write(fs, kpt.class_id);
+    }
 }
 
 
-CV_IMPL CvTypeInfo*
-cvTypeOf( const void* struct_ptr )
+void read(const FileNode& node, std::vector<KeyPoint>& keypoints)
 {
-    CvTypeInfo* info = 0;
-
-    if( struct_ptr )
+    keypoints.resize(0);
+    FileNodeIterator it = node.begin(), it_end = node.end();
+    for( ; it != it_end; )
     {
-        for( info = CvType::first; info != 0; info = info->next )
-            if( info->is_instance( struct_ptr ))
-                break;
+        KeyPoint kpt;
+        it >> kpt.pt.x >> kpt.pt.y >> kpt.size >> kpt.angle >> kpt.response >> kpt.octave >> kpt.class_id;
+        keypoints.push_back(kpt);
     }
-
-    return info;
 }
 
 
-/* universal functions */
-CV_IMPL void
-cvRelease( void** struct_ptr )
+void write(FileStorage& fs, const String& objname, const std::vector<DMatch>& matches)
 {
-    CvTypeInfo* info;
-
-    if( !struct_ptr )
-        CV_Error( CV_StsNullPtr, "NULL double pointer" );
+    cv::internal::WriteStructContext ws(fs, objname, CV_NODE_SEQ + CV_NODE_FLOW);
 
-    if( *struct_ptr )
+    int i, n = (int)matches.size();
+    for( i = 0; i < n; i++ )
     {
-        info = cvTypeOf( *struct_ptr );
-        if( !info )
-            CV_Error( CV_StsError, "Unknown object type" );
-        if( !info->release )
-            CV_Error( CV_StsError, "release function pointer is NULL" );
-
-        info->release( struct_ptr );
-        *struct_ptr = 0;
+        const DMatch& m = matches[i];
+        cv::write(fs, m.queryIdx);
+        cv::write(fs, m.trainIdx);
+        cv::write(fs, m.imgIdx);
+        cv::write(fs, m.distance);
     }
 }
 
-
-void* cvClone( const void* struct_ptr )
+void read(const FileNode& node, std::vector<DMatch>& matches)
 {
-    void* struct_copy = 0;
-    CvTypeInfo* info;
+    matches.resize(0);
+    FileNodeIterator it = node.begin(), it_end = node.end();
+    for( ; it != it_end; )
+    {
+        DMatch m;
+        it >> m.queryIdx >> m.trainIdx >> m.imgIdx >> m.distance;
+        matches.push_back(m);
+    }
+}
 
-    if( !struct_ptr )
-        CV_Error( CV_StsNullPtr, "NULL structure pointer" );
 
-    info = cvTypeOf( struct_ptr );
-    if( !info )
-        CV_Error( CV_StsError, "Unknown object type" );
-    if( !info->clone )
-        CV_Error( CV_StsError, "clone function pointer is NULL" );
+int FileNode::type() const { return !node ? NONE : (node->tag & TYPE_MASK); }
+bool FileNode::isNamed() const { return !node ? false : (node->tag & NAMED) != 0; }
 
-    struct_copy = info->clone( struct_ptr );
-    return struct_copy;
+size_t FileNode::size() const
+{
+    int t = type();
+    return t == MAP ? (size_t)((CvSet*)node->data.map)->active_count :
+        t == SEQ ? (size_t)node->data.seq->total : (size_t)!isNone();
 }
 
-
-/* reads matrix, image, sequence, graph etc. */
-CV_IMPL void*
-cvRead( CvFileStorage* fs, CvFileNode* node, CvAttrList* list )
+void read(const FileNode& node, int& value, int default_value)
 {
-    void* obj = 0;
-    CV_CHECK_FILE_STORAGE( fs );
-
-    if( !node )
-        return 0;
-
-    if( !CV_NODE_IS_USER(node->tag) || !node->info )
-        CV_Error( CV_StsError, "The node does not represent a user object (unknown type?)" );
-
-    obj = node->info->read( fs, node );
-    if( list )
-        *list = cvAttrList(0,0);
-
-    return obj;
+    value = !node.node ? default_value :
+    CV_NODE_IS_INT(node.node->tag) ? node.node->data.i :
+    CV_NODE_IS_REAL(node.node->tag) ? cvRound(node.node->data.f) : 0x7fffffff;
 }
 
-
-/* writes matrix, image, sequence, graph etc. */
-CV_IMPL void
-cvWrite( CvFileStorage* fs, const char* name,
-         const void* ptr, CvAttrList attributes )
+void read(const FileNode& node, float& value, float default_value)
 {
-    CvTypeInfo* info;
-
-    CV_CHECK_OUTPUT_FILE_STORAGE( fs );
-
-    if( !ptr )
-        CV_Error( CV_StsNullPtr, "Null pointer to the written object" );
-
-    info = cvTypeOf( ptr );
-    if( !info )
-        CV_Error( CV_StsBadArg, "Unknown object" );
-
-    if( !info->write )
-        CV_Error( CV_StsBadArg, "The object does not have write function" );
-
-    info->write( fs, name, ptr, attributes );
+    value = !node.node ? default_value :
+        CV_NODE_IS_INT(node.node->tag) ? (float)node.node->data.i :
+        CV_NODE_IS_REAL(node.node->tag) ? (float)node.node->data.f : 1e30f;
 }
 
-
-/* simple API for reading/writing data */
-CV_IMPL void
-cvSave( const char* filename, const void* struct_ptr,
-        const char* _name, const char* comment, CvAttrList attributes )
+void read(const FileNode& node, double& value, double default_value)
 {
-    CvFileStorage* fs = 0;
-
-    if( !struct_ptr )
-        CV_Error( CV_StsNullPtr, "NULL object pointer" );
-
-    fs = cvOpenFileStorage( filename, 0, CV_STORAGE_WRITE );
-    if( !fs )
-        CV_Error( CV_StsError, "Could not open the file storage. Check the path and permissions" );
-
-    cv::String name = _name ? cv::String(_name) : cv::FileStorage::getDefaultObjectName(filename);
-
-    if( comment )
-        cvWriteComment( fs, comment, 0 );
-    cvWrite( fs, name.c_str(), struct_ptr, attributes );
-    cvReleaseFileStorage( &fs );
+    value = !node.node ? default_value :
+        CV_NODE_IS_INT(node.node->tag) ? (double)node.node->data.i :
+        CV_NODE_IS_REAL(node.node->tag) ? node.node->data.f : 1e300;
 }
 
-CV_IMPL void*
-cvLoad( const char* filename, CvMemStorage* memstorage,
-        const char* name, const char** _real_name )
+void read(const FileNode& node, String& value, const String& default_value)
 {
-    void* ptr = 0;
-    const char* real_name = 0;
-    cv::FileStorage fs(cvOpenFileStorage(filename, memstorage, CV_STORAGE_READ));
-
-    CvFileNode* node = 0;
-
-    if( !fs.isOpened() )
-        return 0;
-
-    if( name )
-    {
-        node = cvGetFileNodeByName( *fs, 0, name );
-    }
-    else
-    {
-        int i, k;
-        for( k = 0; k < (*fs)->roots->total; k++ )
-        {
-            CvSeq* seq;
-            CvSeqReader reader;
+    value = !node.node ? default_value : CV_NODE_IS_STRING(node.node->tag) ? String(node.node->data.str.ptr) : String();
+}
 
-            node = (CvFileNode*)cvGetSeqElem( (*fs)->roots, k );
-            if( !CV_NODE_IS_MAP( node->tag ))
-                return 0;
-            seq = node->data.seq;
-            node = 0;
+}
 
-            cvStartReadSeq( seq, &reader, 0 );
 
-            // find the first element in the map
-            for( i = 0; i < seq->total; i++ )
-            {
-                if( CV_IS_SET_ELEM( reader.ptr ))
-                {
-                    node = (CvFileNode*)reader.ptr;
-                    goto stop_search;
-                }
-                CV_NEXT_SEQ_ELEM( seq->elem_size, reader );
-            }
-        }
 
-stop_search:
-        ;
-    }
 
-    if( !node )
-        CV_Error( CV_StsObjectNotFound, "Could not find the/an object in file storage" );
 
-    real_name = cvGetFileNodeName( node );
-    ptr = cvRead( *fs, node, 0 );
 
-    // sanity check
-    if( !memstorage && (CV_IS_SEQ( ptr ) || CV_IS_SET( ptr )) )
-        CV_Error( CV_StsNullPtr,
-        "NULL memory storage is passed - the loaded dynamic structure can not be stored" );
 
-    if( cvGetErrStatus() < 0 )
-    {
-        cvRelease( (void**)&ptr );
-        real_name = 0;
-    }
 
-    if( _real_name)
-    {
-    if (real_name)
-    {
-        *_real_name = (const char*)cvAlloc(strlen(real_name));
-            memcpy((void*)*_real_name, real_name, strlen(real_name));
-    } else {
-        *_real_name = 0;
-    }
-    }
 
-    return ptr;
-}
+/****************************************************************************
+ * Newly added for Base64
+ *
+ *
+ ***************************************************************************/
 
 
-///////////////////////// new C++ interface for CvFileStorage ///////////////////////////
+/****************************************************************************
+ * constant
+ ***************************************************************************/
 
-namespace cv
-{
+#if CHAR_BIT != 8
+#error "`char` should be 8 bit."
+#endif
 
-static void getElemSize( const String& fmt, size_t& elemSize, size_t& cn )
-{
-    const char* dt = fmt.c_str();
-    cn = 1;
-    if( cv_isdigit(dt[0]) )
-    {
-        cn = dt[0] - '0';
-        dt++;
-    }
-    char c = dt[0];
-    elemSize = cn*(c == 'u' || c == 'c' ? sizeof(uchar) : c == 'w' || c == 's' ? sizeof(ushort) :
-        c == 'i' ? sizeof(int) : c == 'f' ? sizeof(float) : c == 'd' ? sizeof(double) :
-        c == 'r' ? sizeof(void*) : (size_t)0);
-}
+base64::uint8_t const base64::base64_mapping[] =
+    "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+    "abcdefghijklmnopqrstuvwxyz"
+    "0123456789+/";
+
+base64::uint8_t const base64::base64_padding = '=';
+
+base64::uint8_t const base64::base64_demapping[] = {
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0, 62,  0,  0,  0, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61,  0,  0,
+    0,  0,  0,  0,  0,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,
+    15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,  0,  0,  0,  0,  0,  0, 26, 27, 28,
+    29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
+    49, 50, 51,  0,  0,  0,  0,
+};
+
+/*    `base64_demapping` above is generated in this way:
+ *    `````````````````````````````````````````````````````````````````````
+ *  std::string mapping((const char *)base64_mapping);
+ *    for (auto ch = 0; ch < 127; ch++) {
+ *        auto i = mapping.find(ch);
+ *        printf("%3u, ", (i != std::string::npos ? i : 0));
+ *    }
+ *    putchar('\n');
+ *    `````````````````````````````````````````````````````````````````````
+ */
+
+/****************************************************************************
+ * function
+ ***************************************************************************/
+
+size_t base64::base64_encode(uint8_t const * src, uint8_t * dst, size_t off, size_t cnt)
+{
+    if (!src || !dst || !cnt)
+        return 0;
 
-FileStorage::FileStorage()
-{
-    state = UNDEFINED;
-}
+    /* initialize beginning and end */
+    uint8_t       * dst_beg = dst;
+    uint8_t       * dst_cur = dst_beg;
+
+    uint8_t const * src_beg = src + off;
+    uint8_t const * src_cur = src_beg;
+    uint8_t const * src_end = src_cur + cnt / 3U * 3U;
+
+    /* integer multiples part */
+    while (src_cur < src_end) {
+        uint8_t _2 = *src_cur++;
+        uint8_t _1 = *src_cur++;
+        uint8_t _0 = *src_cur++;
+        *dst_cur++ = base64_mapping[ _2          >> 2U];
+        *dst_cur++ = base64_mapping[(_1 & 0xF0U) >> 4U | (_2 & 0x03U) << 4U];
+        *dst_cur++ = base64_mapping[(_0 & 0xC0U) >> 6U | (_1 & 0x0FU) << 2U];
+        *dst_cur++ = base64_mapping[ _0 & 0x3FU];
+    }
+
+    /* remainder part */
+    size_t rst = src_beg + cnt - src_cur;
+    if (rst == 1U) {
+        uint8_t _2 = *src_cur++;
+        *dst_cur++ = base64_mapping[ _2          >> 2U];
+        *dst_cur++ = base64_mapping[(_2 & 0x03U) << 4U];
+    } else if (rst == 2U) {
+        uint8_t _2 = *src_cur++;
+        uint8_t _1 = *src_cur++;
+        *dst_cur++ = base64_mapping[ _2          >> 2U];
+        *dst_cur++ = base64_mapping[(_2 & 0x03U) << 4U | (_1 & 0xF0U) >> 4U];
+        *dst_cur++ = base64_mapping[(_1 & 0x0FU) << 2U];
+    }
+
+    /* padding */
+    switch (rst)
+    {
+    case 1U: *dst_cur++ = base64_padding;
+    case 2U: *dst_cur++ = base64_padding;
+    default: *dst_cur   = 0;
+        break;
+    }
 
-FileStorage::FileStorage(const String& filename, int flags, const String& encoding)
-{
-    state = UNDEFINED;
-    open( filename, flags, encoding );
+    return static_cast<size_t>(dst_cur - dst_beg);
 }
 
-FileStorage::FileStorage(CvFileStorage* _fs, bool owning)
+size_t base64::base64_encode(char const * src, char * dst, size_t off, size_t cnt)
 {
-    if (owning) fs.reset(_fs);
-    else fs = Ptr<CvFileStorage>(Ptr<CvFileStorage>(), _fs);
+    if (cnt == 0U)
+        cnt = std::strlen(src);
 
-    state = _fs ? NAME_EXPECTED + INSIDE_MAP : UNDEFINED;
+    return base64_encode
+    (
+        reinterpret_cast<uint8_t const *>(src),
+        reinterpret_cast<uint8_t       *>(dst),
+        off,
+        cnt
+    );
 }
 
-FileStorage::~FileStorage()
+size_t base64::base64_decode(uint8_t const * src, uint8_t * dst, size_t off, size_t cnt)
 {
-    while( structs.size() > 0 )
-    {
-        cvEndWriteStruct(fs);
-        structs.pop_back();
+    /* check parameters */
+    if (!src || !dst || !cnt)
+        return 0U;
+    if (cnt & 0x3U)
+        return 0U;
+
+    /* initialize beginning and end */
+    uint8_t       * dst_beg = dst;
+    uint8_t       * dst_cur = dst_beg;
+
+    uint8_t const * src_beg = src + off;
+    uint8_t const * src_cur = src_beg;
+    uint8_t const * src_end = src_cur + cnt;
+
+    /* start decoding */
+    while (src_cur < src_end) {
+        uint8_t d50 = base64_demapping[*src_cur++];
+        uint8_t c50 = base64_demapping[*src_cur++];
+        uint8_t b50 = base64_demapping[*src_cur++];
+        uint8_t a50 = base64_demapping[*src_cur++];
+
+        uint8_t b10 = b50 & 0x03U;
+        uint8_t b52 = b50 & 0x3CU;
+        uint8_t c30 = c50 & 0x0FU;
+        uint8_t c54 = c50 & 0x30U;
+
+        *dst_cur++ = (d50 << 2U) | (c54 >> 4U);
+        *dst_cur++ = (c30 << 4U) | (b52 >> 2U);
+        *dst_cur++ = (b10 << 6U) | (a50 >> 0U);
     }
-}
 
-bool FileStorage::open(const String& filename, int flags, const String& encoding)
-{
-    release();
-    fs.reset(cvOpenFileStorage( filename.c_str(), 0, flags,
-                                !encoding.empty() ? encoding.c_str() : 0));
-    bool ok = isOpened();
-    state = ok ? NAME_EXPECTED + INSIDE_MAP : UNDEFINED;
-    return ok;
+    *dst_cur = 0;
+    return size_t(dst_cur - dst_beg);
 }
 
-bool FileStorage::isOpened() const
+size_t base64::base64_decode(char const * src, char * dst, size_t off, size_t cnt)
 {
-    return fs && fs->is_opened;
+    if (cnt == 0U)
+        cnt = std::strlen(src);
+
+    return base64_decode
+    (
+        reinterpret_cast<uint8_t const *>(src),
+        reinterpret_cast<uint8_t       *>(dst),
+        off,
+        cnt
+    );
 }
 
-void FileStorage::release()
+bool base64::base64_valid(uint8_t const * src, size_t off, size_t cnt)
 {
-    fs.release();
-    structs.clear();
-    state = UNDEFINED;
+    /* check parameters */
+    if (src == 0 || src + off == 0)
+        return false;
+    if (cnt == 0U)
+        cnt = std::strlen(reinterpret_cast<char const *>(src));
+    if (cnt == 0U)
+        return false;
+    if (cnt & 0x3U)
+        return false;
+
+    /* initialize beginning and end */
+    uint8_t const * beg = src + off;
+    uint8_t const * end = beg + cnt;
+
+    /* skip padding */
+    if (*(end - 1U) == base64_padding) {
+        end--;
+        if (*(end - 1U) == base64_padding)
+            end--;
+    }
+
+    /* find illegal characters */
+    for (uint8_t const * iter = beg; iter < end; iter++)
+        if (*iter > 126U || (!base64_demapping[(uint8_t)*iter] && *iter != base64_mapping[0]))
+            return false;
+
+    return true;
 }
 
-String FileStorage::releaseAndGetString()
+bool base64::base64_valid(char const * src, size_t off, size_t cnt)
 {
-    String buf;
-    if( fs && fs->outbuf )
-        icvClose(fs, &buf);
+    if (cnt == 0U)
+        cnt = std::strlen(src);
 
-    release();
-    return buf;
+    return base64_valid(reinterpret_cast<uint8_t const *>(src), off, cnt);
 }
 
-FileNode FileStorage::root(int streamidx) const
+size_t base64::base64_encode_buffer_size(size_t cnt, bool is_end_with_zero)
 {
-    return isOpened() ? FileNode(fs, cvGetRootFileNode(fs, streamidx)) : FileNode();
+    size_t additional = static_cast<size_t>(is_end_with_zero == true);
+    return (cnt + 2U) / 3U * 4U + additional;
 }
 
-FileStorage& operator << (FileStorage& fs, const String& str)
+size_t base64::base64_decode_buffer_size(size_t cnt, bool is_end_with_zero)
 {
-    enum { NAME_EXPECTED = FileStorage::NAME_EXPECTED,
-        VALUE_EXPECTED = FileStorage::VALUE_EXPECTED,
-        INSIDE_MAP = FileStorage::INSIDE_MAP };
-    const char* _str = str.c_str();
-    if( !fs.isOpened() || !_str )
-        return fs;
-    if( *_str == '}' || *_str == ']' )
-    {
-        if( fs.structs.empty() )
-            CV_Error_( CV_StsError, ("Extra closing '%c'", *_str) );
-        if( (*_str == ']' ? '[' : '{') != fs.structs.back() )
-            CV_Error_( CV_StsError,
-            ("The closing '%c' does not match the opening '%c'", *_str, fs.structs.back()));
-        fs.structs.pop_back();
-        fs.state = fs.structs.empty() || fs.structs.back() == '{' ?
-            INSIDE_MAP + NAME_EXPECTED : VALUE_EXPECTED;
-        cvEndWriteStruct( *fs );
-        fs.elname = String();
-    }
-    else if( fs.state == NAME_EXPECTED + INSIDE_MAP )
-    {
-        if( !cv_isalpha(*_str) )
-            CV_Error_( CV_StsError, ("Incorrect element name %s", _str) );
-        fs.elname = str;
-        fs.state = VALUE_EXPECTED + INSIDE_MAP;
-    }
-    else if( (fs.state & 3) == VALUE_EXPECTED )
-    {
-        if( *_str == '{' || *_str == '[' )
-        {
-            fs.structs.push_back(*_str);
-            int flags = *_str++ == '{' ? CV_NODE_MAP : CV_NODE_SEQ;
-            fs.state = flags == CV_NODE_MAP ? INSIDE_MAP +
-                NAME_EXPECTED : VALUE_EXPECTED;
-            if( *_str == ':' )
-            {
-                flags |= CV_NODE_FLOW;
-                _str++;
-            }
-            cvStartWriteStruct( *fs, fs.elname.size() > 0 ? fs.elname.c_str() : 0,
-                flags, *_str ? _str : 0 );
-            fs.elname = String();
-        }
-        else
-        {
-            write( fs, fs.elname, (_str[0] == '\\' && (_str[1] == '{' || _str[1] == '}' ||
-                _str[1] == '[' || _str[1] == ']')) ? String(_str+1) : str );
-            if( fs.state == INSIDE_MAP + VALUE_EXPECTED )
-                fs.state = INSIDE_MAP + NAME_EXPECTED;
-        }
-    }
-    else
-        CV_Error( CV_StsError, "Invalid fs.state" );
-    return fs;
+    size_t additional = static_cast<size_t>(is_end_with_zero == true);
+    return cnt / 4U * 3U + additional;
 }
 
-
-void FileStorage::writeRaw( const String& fmt, const uchar* vec, size_t len )
+size_t base64::base64_decode_buffer_size(size_t cnt, char  const * src, bool is_end_with_zero)
 {
-    if( !isOpened() )
-        return;
-    size_t elemSize, cn;
-    getElemSize( fmt, elemSize, cn );
-    CV_Assert( len % elemSize == 0 );
-    cvWriteRawData( fs, vec, (int)(len/elemSize), fmt.c_str());
+    return base64_decode_buffer_size(cnt, reinterpret_cast<uchar const *>(src), is_end_with_zero);
 }
 
-
-void FileStorage::writeObj( const String& name, const void* obj )
+size_t base64::base64_decode_buffer_size(size_t cnt, uchar const * src, bool is_end_with_zero)
 {
-    if( !isOpened() )
-        return;
-    cvWrite( fs, name.size() > 0 ? name.c_str() : 0, obj );
+    size_t padding_cnt = 0U;
+    for (uchar const * ptr = src + cnt - 1U; *ptr == base64_padding; ptr--)
+        padding_cnt ++;
+    return base64_decode_buffer_size(cnt, is_end_with_zero) - padding_cnt;
 }
 
+/****************************************************************************
+ * to_binary && binary_to
+ ***************************************************************************/
 
-FileNode FileStorage::operator[](const String& nodename) const
+template<typename _uint_t> inline size_t base64::
+to_binary(_uint_t val, uchar * cur)
 {
-    return FileNode(fs, cvGetFileNodeByName(fs, 0, nodename.c_str()));
+    size_t delta = CHAR_BIT;
+    size_t cnt = sizeof(_uint_t);
+    while (cnt --> static_cast<size_t>(0U)) {
+        *cur++ = static_cast<uchar>(val);
+        val >>= delta;
+    }
+    return sizeof(_uint_t);
 }
 
-FileNode FileStorage::operator[](const char* nodename) const
+template<> inline size_t base64::to_binary(double val, uchar * cur)
 {
-    return FileNode(fs, cvGetFileNodeByName(fs, 0, nodename));
+    Cv64suf bit64;
+    bit64.f = val;
+    return to_binary(bit64.u, cur);
 }
 
-FileNode FileNode::operator[](const String& nodename) const
+template<> inline size_t base64::to_binary(float val, uchar * cur)
 {
-    return FileNode(fs, cvGetFileNodeByName(fs, node, nodename.c_str()));
+    Cv32suf bit32;
+    bit32.f = val;
+    return to_binary(bit32.u, cur);
 }
 
-FileNode FileNode::operator[](const char* nodename) const
+template<typename _primitive_t> inline size_t base64::
+to_binary(uchar const * val, uchar * cur)
 {
-    return FileNode(fs, cvGetFileNodeByName(fs, node, nodename));
+    return to_binary<_primitive_t>(*reinterpret_cast<_primitive_t const *>(val), cur);
 }
 
-FileNode FileNode::operator[](int i) const
+
+template<typename _uint_t> inline size_t base64::
+binary_to(uchar const * cur, _uint_t & val)
 {
-    return isSeq() ? FileNode(fs, (CvFileNode*)cvGetSeqElem(node->data.seq, i)) :
-        i == 0 ? *this : FileNode();
+    val = static_cast<_uint_t>(0);
+    for (size_t i = static_cast<size_t>(0U); i < sizeof(_uint_t); i++)
+        val |= (static_cast<_uint_t>(*cur++) << (i * CHAR_BIT));
+    return sizeof(_uint_t);
 }
 
-String FileNode::name() const
+template<> inline size_t base64::binary_to(uchar const * cur, double & val)
 {
-    const char* str;
-    return !node || (str = cvGetFileNodeName(node)) == 0 ? String() : String(str);
+    Cv64suf bit64;
+    binary_to(cur, bit64.u);
+    val = bit64.f;
+    return sizeof(val);
 }
 
-void* FileNode::readObj() const
+template<> inline size_t base64::binary_to(uchar const * cur, float & val)
 {
-    if( !fs || !node )
-        return 0;
-    return cvRead( (CvFileStorage*)fs, (CvFileNode*)node );
+    Cv32suf bit32;
+    binary_to(cur, bit32.u);
+    val = bit32.f;
+    return sizeof(val);
 }
 
-FileNodeIterator::FileNodeIterator()
+template<typename _primitive_t> inline size_t base64::
+binary_to(uchar const * cur, uchar * val)
 {
-    fs = 0;
-    container = 0;
-    reader.ptr = 0;
-    remaining = 0;
+    return binary_to<_primitive_t>(cur, *reinterpret_cast<_primitive_t *>(val));
 }
 
-FileNodeIterator::FileNodeIterator(const CvFileStorage* _fs,
-                                   const CvFileNode* _node, size_t _ofs)
+/****************************************************************************
+ * others
+ ***************************************************************************/
+
+std::string base64::make_base64_header(const char * dt)
 {
-    if( _fs && _node && CV_NODE_TYPE(_node->tag) != CV_NODE_NONE )
-    {
-        int node_type = _node->tag & FileNode::TYPE_MASK;
-        fs = _fs;
-        container = _node;
-        if( !(_node->tag & FileNode::USER) && (node_type == FileNode::SEQ || node_type == FileNode::MAP) )
-        {
-            cvStartReadSeq( _node->data.seq, (CvSeqReader*)&reader );
-            remaining = FileNode(_fs, _node).size();
-        }
-        else
-        {
-            reader.ptr = (schar*)_node;
-            reader.seq = 0;
-            remaining = 1;
-        }
-        (*this) += (int)_ofs;
-    }
-    else
-    {
-        fs = 0;
-        container = 0;
-        reader.ptr = 0;
-        remaining = 0;
-    }
+    std::ostringstream oss;
+    oss << dt   << ' ';
+    std::string buffer(oss.str());
+    CV_Assert(buffer.size() < HEADER_SIZE);
+
+    buffer.reserve(HEADER_SIZE);
+    while (buffer.size() < HEADER_SIZE)
+        buffer += ' ';
+
+    return buffer;
 }
 
-FileNodeIterator::FileNodeIterator(const FileNodeIterator& it)
+bool base64::read_base64_header(std::vector<char> const & header, std::string & dt)
 {
-    fs = it.fs;
-    container = it.container;
-    reader = it.reader;
-    remaining = it.remaining;
+    std::istringstream iss(header.data());
+    return static_cast<bool>(iss >> dt);
 }
 
-FileNodeIterator& FileNodeIterator::operator ++()
+/****************************************************************************
+ * Parser
+ ***************************************************************************/
+
+base64::Base64ContextParser::Base64ContextParser(uchar * buffer, size_t size)
+    : dst_cur(buffer)
+    , dst_end(buffer + size)
+    , base64_buffer(BUFFER_LEN)
+    , src_beg(0)
+    , src_cur(0)
+    , src_end(0)
+    , binary_buffer(base64_encode_buffer_size(BUFFER_LEN))
 {
-    if( remaining > 0 )
-    {
-        if( reader.seq )
-        {
-            if( ((reader).ptr += (((CvSeq*)reader.seq)->elem_size)) >= (reader).block_max )
-            {
-                cvChangeSeqBlock( (CvSeqReader*)&(reader), 1 );
-            }
-        }
-        remaining--;
-    }
-    return *this;
+    src_beg = binary_buffer.data();
+    src_cur = src_beg;
+    src_end = src_beg + BUFFER_LEN;
 }
 
-FileNodeIterator FileNodeIterator::operator ++(int)
+base64::Base64ContextParser::~Base64ContextParser()
 {
-    FileNodeIterator it = *this;
-    ++(*this);
-    return it;
+    /* encode the rest binary data to base64 buffer */
+    if (src_cur != src_beg)
+        flush();
 }
 
-FileNodeIterator& FileNodeIterator::operator --()
+base64::Base64ContextParser & base64::Base64ContextParser::
+read(const uchar * beg, const uchar * end)
 {
-    if( remaining < FileNode(fs, container).size() )
-    {
-        if( reader.seq )
-        {
-            if( ((reader).ptr -= (((CvSeq*)reader.seq)->elem_size)) < (reader).block_min )
-            {
-                cvChangeSeqBlock( (CvSeqReader*)&(reader), -1 );
-            }
+    if (beg >= end)
+        return *this;
+
+    while (beg < end) {
+        /* collect binary data and copy to binary buffer */
+        size_t len = std::min(end - beg, src_end - src_cur);
+        std::memcpy(src_cur, beg, len);
+        beg     += len;
+        src_cur += len;
+
+        if (src_cur >= src_end) {
+            /* binary buffer is full. */
+            /* decode it send result to dst */
+
+            CV_Assert(flush());    /* check for base64_valid */
         }
-        remaining++;
     }
+
     return *this;
 }
 
-FileNodeIterator FileNodeIterator::operator --(int)
+bool base64::Base64ContextParser::flush()
 {
-    FileNodeIterator it = *this;
-    --(*this);
-    return it;
-}
+    if ( !base64_valid(src_beg, 0U, src_cur - src_beg) )
+        return false;
 
-FileNodeIterator& FileNodeIterator::operator += (int ofs)
-{
-    if( ofs == 0 )
-        return *this;
-    if( ofs > 0 )
-        ofs = std::min(ofs, (int)remaining);
-    else
-    {
-        size_t count = FileNode(fs, container).size();
-        ofs = (int)(remaining - std::min(remaining - ofs, count));
+    if ( src_cur == src_beg )
+        return true;
+
+    uchar * buffer = binary_buffer.data();
+    size_t len = base64_decode(src_beg, buffer, 0U, src_cur - src_beg);
+    src_cur = src_beg;
+
+    /* unexpected error */
+    CV_Assert(len != 0);
+
+    /* buffer is full */
+    CV_Assert(dst_cur + len < dst_end);
+
+    if (dst_cur + len < dst_end) {
+        /* send data to dst */
+        std::memcpy(dst_cur, buffer, len);
+        dst_cur += len;
     }
-    remaining -= ofs;
-    if( reader.seq )
-        cvSetSeqReaderPos( (CvSeqReader*)&reader, ofs, 1 );
-    return *this;
-}
 
-FileNodeIterator& FileNodeIterator::operator -= (int ofs)
-{
-    return operator += (-ofs);
+    return true;
 }
 
+/****************************************************************************
+ * Emitter
+ ***************************************************************************/
 
-FileNodeIterator& FileNodeIterator::readRaw( const String& fmt, uchar* vec, size_t maxCount )
+/* A decorator for CvFileStorage
+ * - no copyable
+ * - not safe for now
+ * - move constructor may be needed if C++11
+ */
+class base64::Base64ContextEmitter
 {
-    if( fs && container && remaining > 0 )
+public:
+    explicit Base64ContextEmitter(CvFileStorage * fs)
+        : file_storage(fs)
+        , binary_buffer(BUFFER_LEN)
+        , base64_buffer(base64_encode_buffer_size(BUFFER_LEN))
+        , src_beg(0)
+        , src_cur(0)
+        , src_end(0)
     {
-        size_t elem_size, cn;
-        getElemSize( fmt, elem_size, cn );
-        CV_Assert( elem_size > 0 );
-        size_t count = std::min(remaining, maxCount);
+        src_beg = binary_buffer.data();
+        src_end = src_beg + BUFFER_LEN;
+        src_cur = src_beg;
+
+        CV_CHECK_OUTPUT_FILE_STORAGE(fs);
+
+        if ( fs->fmt == CV_STORAGE_FORMAT_JSON )
+        {
+            /* clean and break buffer */
+            *fs->buffer++ = '\0';
+            ::icvPuts( fs, fs->buffer_start );
+            fs->buffer = fs->buffer_start;
+            memset( file_storage->buffer_start, 0, static_cast<int>(file_storage->space) );
+            ::icvPuts( fs, "\"$base64$" );
+        }
+        else
+        {
+            ::icvFSFlush(file_storage);
+        }
+    }
+
+    ~Base64ContextEmitter()
+    {
+        /* cleaning */
+        if (src_cur != src_beg)
+            flush();    /* encode the rest binary data to base64 buffer */
 
-        if( reader.seq )
+        if ( file_storage->fmt == CV_STORAGE_FORMAT_JSON )
         {
-            cvReadRawDataSlice( fs, (CvSeqReader*)&reader, (int)count, vec, fmt.c_str() );
-            remaining -= count*cn;
+            /* clean and break buffer  */
+            ::icvPuts(file_storage, "\"");
+            file_storage->buffer = file_storage->buffer_start;
+            ::icvFSFlush( file_storage );
+            memset( file_storage->buffer_start, 0, static_cast<int>(file_storage->space) );
+            file_storage->buffer = file_storage->buffer_start;
         }
-        else
-        {
-            cvReadRawData( fs, container, vec, fmt.c_str() );
-            remaining = 0;
+    }
+
+    Base64ContextEmitter & write(const uchar * beg, const uchar * end)
+    {
+        if (beg >= end)
+            return *this;
+
+        while (beg < end) {
+            /* collect binary data and copy to binary buffer */
+            size_t len = std::min(end - beg, src_end - src_cur);
+           std::memcpy(src_cur, beg, len);
+            beg     += len;
+            src_cur += len;
+
+            if (src_cur >= src_end) {
+                /* binary buffer is full. */
+                /* encode it to base64 and send result to fs */
+                flush();
+            }
         }
+
+        return *this;
     }
-    return *this;
-}
 
+    /*
+     * a convertor must provide :
+     * - `operator >> (uchar * & dst)` for writting current binary data to `dst` and moving to next data.
+     * - `operator bool` for checking if current loaction is valid and not the end.
+     */
+    template<typename _to_binary_convertor_t> inline
+    Base64ContextEmitter & write(_to_binary_convertor_t & convertor)
+    {
+        static const size_t BUFFER_MAX_LEN = 1024U;
+
+        std::vector<uchar> buffer(BUFFER_MAX_LEN);
+        uchar * beg = buffer.data();
+        uchar * end = beg;
+
+        while (convertor) {
+            convertor >> end;
+            write(beg, end);
+            end = beg;
+        }
 
-void write( FileStorage& fs, const String& name, int value )
-{ cvWriteInt( *fs, name.size() ? name.c_str() : 0, value ); }
+        return *this;
+    }
 
-void write( FileStorage& fs, const String& name, float value )
-{ cvWriteReal( *fs, name.size() ? name.c_str() : 0, value ); }
+    bool flush()
+    {
+        /* controll line width, so on. */
+        size_t len = base64_encode(src_beg, base64_buffer.data(), 0U, src_cur - src_beg);
+        if (len == 0U)
+            return false;
 
-void write( FileStorage& fs, const String& name, double value )
-{ cvWriteReal( *fs, name.size() ? name.c_str() : 0, value ); }
+        src_cur = src_beg;
+        {
+            if ( file_storage->fmt == CV_STORAGE_FORMAT_JSON )
+            {
+                ::icvPuts(file_storage, (const char*)base64_buffer.data());
+            }
+            else
+            {
+                const char newline[] = "\n";
+                char space[80];
+                int ident = file_storage->struct_indent;
+                memset(space, ' ', static_cast<int>(ident));
+                space[ident] = '\0';
+
+                ::icvPuts(file_storage, space);
+                ::icvPuts(file_storage, (const char*)base64_buffer.data());
+                ::icvPuts(file_storage, newline);
+                ::icvFSFlush(file_storage);
+            }
 
-void write( FileStorage& fs, const String& name, const String& value )
-{ cvWriteString( *fs, name.size() ? name.c_str() : 0, value.c_str() ); }
+        }
 
-void writeScalar(FileStorage& fs, int value )
-{ cvWriteInt( *fs, 0, value ); }
+        return true;
+    }
 
-void writeScalar(FileStorage& fs, float value )
-{ cvWriteReal( *fs, 0, value ); }
+private:
+    /* because of Base64, we must keep its length a multiple of 3 */
+    static const size_t BUFFER_LEN = 48U;
+    // static_assert(BUFFER_LEN % 3 == 0, "BUFFER_LEN is invalid");
 
-void writeScalar(FileStorage& fs, double value )
-{ cvWriteReal( *fs, 0, value ); }
+private:
+    CvFileStorage * file_storage;
 
-void writeScalar(FileStorage& fs, const String& value )
-{ cvWriteString( *fs, 0, value.c_str() ); }
+    std::vector<uchar> binary_buffer;
+    std::vector<uchar> base64_buffer;
+    uchar * src_beg;
+    uchar * src_cur;
+    uchar * src_end;
+};
 
 
-void write( FileStorage& fs, const String& name, const Mat& value )
+class base64::RawDataToBinaryConvertor
 {
-    if( value.dims <= 2 )
+public:
+
+    RawDataToBinaryConvertor(const void* src, int len, const char* dt)
+        : beg(reinterpret_cast<const uchar *>(src))
+        , cur(0)
+        , end(0)
     {
-        CvMat mat = value;
-        cvWrite( *fs, name.size() ? name.c_str() : 0, &mat );
+        CV_Assert(src);
+        CV_Assert(dt);
+        CV_Assert(len > 0);
+
+        /* calc step and to_binary_funcs */
+        make_to_binary_funcs(dt);
+
+        end = beg;
+        cur = beg;
+
+        step = ::icvCalcStructSize(dt, 0);
+        end = beg + step * static_cast<size_t>(len);
     }
-    else
+
+    inline RawDataToBinaryConvertor & operator >>(uchar * & dst)
     {
-        CvMatND mat = value;
-        cvWrite( *fs, name.size() ? name.c_str() : 0, &mat );
-    }
-}
+        CV_DbgAssert(*this);
 
-// TODO: the 4 functions below need to be implemented more efficiently
-void write( FileStorage& fs, const String& name, const SparseMat& value )
-{
-    Ptr<CvSparseMat> mat(cvCreateSparseMat(value));
-    cvWrite( *fs, name.size() ? name.c_str() : 0, mat );
-}
+        for (size_t i = 0U, n = to_binary_funcs.size(); i < n; i++) {
+            elem_to_binary_t & pack = to_binary_funcs[i];
+            pack.func(cur + pack.offset, dst + pack.offset);
+        }
+        cur += step;
+        dst += step;
 
+        return *this;
+    }
 
-internal::WriteStructContext::WriteStructContext(FileStorage& _fs,
-    const String& name, int flags, const String& typeName) : fs(&_fs)
-{
-    cvStartWriteStruct(**fs, !name.empty() ? name.c_str() : 0, flags,
-                       !typeName.empty() ? typeName.c_str() : 0);
-    fs->elname = String();
-    if ((flags & FileNode::TYPE_MASK) == FileNode::SEQ)
+    inline operator bool() const
     {
-        fs->state = FileStorage::VALUE_EXPECTED;
-        fs->structs.push_back('[');
+        return cur < end;
     }
-    else
+
+private:
+    typedef size_t(*to_binary_t)(const uchar *, uchar *);
+    struct elem_to_binary_t
     {
-        fs->state = FileStorage::NAME_EXPECTED + FileStorage::INSIDE_MAP;
-        fs->structs.push_back('{');
+        size_t      offset;
+        to_binary_t func;
+    };
+
+private:
+    void make_to_binary_funcs(const char* dt)
+    {
+        size_t cnt = 0;
+        size_t offset = 0;
+        char type = '\0';
+
+        std::istringstream iss(dt);
+        while (!iss.eof()) {
+            if (!(iss >> cnt)) {
+                iss.clear();
+                cnt = 1;
+            }
+            CV_Assert(cnt > 0U);
+            if (!(iss >> type))
+                break;
+
+            while (cnt-- > 0)
+            {
+                elem_to_binary_t pack;
+
+                size_t size = 0;
+                switch (type)
+                {
+                case 'u':
+                case 'c':
+                    size = sizeof(uchar);
+                    pack.func = to_binary<uchar>;
+                    break;
+                case 'w':
+                case 's':
+                    size = sizeof(ushort);
+                    pack.func = to_binary<ushort>;
+                    break;
+                case 'i':
+                    size = sizeof(uint);
+                    pack.func = to_binary<uint>;
+                    break;
+                case 'f':
+                    size = sizeof(float);
+                    pack.func = to_binary<float>;
+                    break;
+                case 'd':
+                    size = sizeof(double);
+                    pack.func = to_binary<double>;
+                    break;
+                case 'r':
+                default: { CV_Assert(!"type not support"); break; }
+                };
+
+                offset = static_cast<size_t>(cvAlign(static_cast<int>(offset), static_cast<int>(size)));
+                pack.offset = offset;
+                offset += size;
+
+                to_binary_funcs.push_back(pack);
+            }
+        }
+
+        CV_Assert(iss.eof());
     }
-}
 
-internal::WriteStructContext::~WriteStructContext()
-{
-    cvEndWriteStruct(**fs);
-    fs->structs.pop_back();
-    fs->state = fs->structs.empty() || fs->structs.back() == '{' ?
-        FileStorage::NAME_EXPECTED + FileStorage::INSIDE_MAP :
-        FileStorage::VALUE_EXPECTED;
-    fs->elname = String();
-}
+private:
+    const uchar * beg;
+    const uchar * cur;
+    const uchar * end;
 
+    size_t step;
+    std::vector<elem_to_binary_t> to_binary_funcs;
+};
 
-void read( const FileNode& node, Mat& mat, const Mat& default_mat )
+class base64::BinaryToCvSeqConvertor
 {
-    if( node.empty() )
+public:
+    BinaryToCvSeqConvertor(const void* src, int len, const char* dt)
+        : cur(reinterpret_cast<const uchar *>(src))
+        , beg(reinterpret_cast<const uchar *>(src))
+        , end(reinterpret_cast<const uchar *>(src))
     {
-        default_mat.copyTo(mat);
-        return;
+        CV_Assert(src);
+        CV_Assert(dt);
+        CV_Assert(len >= 0);
+
+        /* calc binary_to_funcs */
+        make_funcs(dt);
+        functor_iter = binary_to_funcs.begin();
+
+        step = ::icvCalcStructSize(dt, 0);
+        end = beg + step * static_cast<size_t>(len);
     }
-    void* obj = cvRead((CvFileStorage*)node.fs, (CvFileNode*)*node);
-    if(CV_IS_MAT_HDR_Z(obj))
+
+    inline BinaryToCvSeqConvertor & operator >> (CvFileNode & dst)
     {
-        cvarrToMat(obj).copyTo(mat);
-        cvReleaseMat((CvMat**)&obj);
+        CV_DbgAssert(*this);
+
+        /* get current data */
+        union
+        {
+            uchar mem[sizeof(double)];
+            uchar  u;
+            char   b;
+            ushort w;
+            short  s;
+            int    i;
+            float  f;
+            double d;
+        } buffer; /* for GCC -Wstrict-aliasing */
+        std::memset(buffer.mem, 0, sizeof(buffer));
+        functor_iter->func(cur + functor_iter->offset, buffer.mem);
+
+        /* set node::data */
+        switch (functor_iter->cv_type)
+        {
+        case CV_8U : { dst.data.i = cv::saturate_cast<int>   (buffer.u); break;}
+        case CV_8S : { dst.data.i = cv::saturate_cast<int>   (buffer.b); break;}
+        case CV_16U: { dst.data.i = cv::saturate_cast<int>   (buffer.w); break;}
+        case CV_16S: { dst.data.i = cv::saturate_cast<int>   (buffer.s); break;}
+        case CV_32S: { dst.data.i = cv::saturate_cast<int>   (buffer.i); break;}
+        case CV_32F: { dst.data.f = cv::saturate_cast<double>(buffer.f); break;}
+        case CV_64F: { dst.data.f = cv::saturate_cast<double>(buffer.d); break;}
+        default: break;
+        }
+
+        /* set node::tag */
+        switch (functor_iter->cv_type)
+        {
+        case CV_8U :
+        case CV_8S :
+        case CV_16U:
+        case CV_16S:
+        case CV_32S: { dst.tag = CV_NODE_INT; /*std::printf("%i,", dst.data.i);*/ break; }
+        case CV_32F:
+        case CV_64F: { dst.tag = CV_NODE_REAL; /*std::printf("%.1f,", dst.data.f);*/ break; }
+        default: break;
+        }
+
+        /* check if end */
+        if (++functor_iter == binary_to_funcs.end()) {
+            functor_iter = binary_to_funcs.begin();
+            cur += step;
+        }
+
+        return *this;
     }
-    else if(CV_IS_MATND_HDR(obj))
+
+    inline operator bool() const
     {
-        cvarrToMat(obj).copyTo(mat);
-        cvReleaseMatND((CvMatND**)&obj);
+        return cur < end;
     }
-    else
+
+private:
+    typedef size_t(*binary_to_t)(uchar const *, uchar *);
+    struct binary_to_filenode_t
     {
-        cvRelease(&obj);
-        CV_Error(CV_StsBadArg, "Unknown array type");
-    }
-}
+        size_t      cv_type;
+        size_t      offset;
+        binary_to_t func;
+    };
 
-void read( const FileNode& node, SparseMat& mat, const SparseMat& default_mat )
-{
-    if( node.empty() )
+private:
+    void make_funcs(const char* dt)
     {
-        default_mat.copyTo(mat);
-        return;
-    }
-    Ptr<CvSparseMat> m((CvSparseMat*)cvRead((CvFileStorage*)node.fs, (CvFileNode*)*node));
-    CV_Assert(CV_IS_SPARSE_MAT(m));
-    m->copyToSparseMat(mat);
-}
+        size_t cnt = 0;
+        char type = '\0';
+        size_t offset = 0;
 
-void write(FileStorage& fs, const String& objname, const std::vector<KeyPoint>& keypoints)
-{
-    cv::internal::WriteStructContext ws(fs, objname, CV_NODE_SEQ + CV_NODE_FLOW);
+        std::istringstream iss(dt);
+        while (!iss.eof()) {
+            if (!(iss >> cnt)) {
+                iss.clear();
+                cnt = 1;
+            }
+            CV_Assert(cnt > 0U);
+            if (!(iss >> type))
+                break;
 
-    int i, npoints = (int)keypoints.size();
-    for( i = 0; i < npoints; i++ )
-    {
-        const KeyPoint& kpt = keypoints[i];
-        cv::write(fs, kpt.pt.x);
-        cv::write(fs, kpt.pt.y);
-        cv::write(fs, kpt.size);
-        cv::write(fs, kpt.angle);
-        cv::write(fs, kpt.response);
-        cv::write(fs, kpt.octave);
-        cv::write(fs, kpt.class_id);
-    }
-}
+            while (cnt-- > 0)
+            {
+                binary_to_filenode_t pack;
+
+                /* set func and offset */
+                size_t size = 0;
+                switch (type)
+                {
+                case 'u':
+                case 'c':
+                    size      = sizeof(uchar);
+                    pack.func = binary_to<uchar>;
+                    break;
+                case 'w':
+                case 's':
+                    size      = sizeof(ushort);
+                    pack.func = binary_to<ushort>;
+                    break;
+                case 'i':
+                    size      = sizeof(uint);
+                    pack.func = binary_to<uint>;
+                    break;
+                case 'f':
+                    size      = sizeof(float);
+                    pack.func = binary_to<float>;
+                    break;
+                case 'd':
+                    size      = sizeof(double);
+                    pack.func = binary_to<double>;
+                    break;
+                case 'r':
+                default:  { CV_Assert(!"type not support"); break; }
+                }; // need a better way for outputting error.
 
+                offset = static_cast<size_t>(cvAlign(static_cast<int>(offset), static_cast<int>(size)));
+                pack.offset = offset;
+                offset += size;
 
-void read(const FileNode& node, std::vector<KeyPoint>& keypoints)
-{
-    keypoints.resize(0);
-    FileNodeIterator it = node.begin(), it_end = node.end();
-    for( ; it != it_end; )
-    {
-        KeyPoint kpt;
-        it >> kpt.pt.x >> kpt.pt.y >> kpt.size >> kpt.angle >> kpt.response >> kpt.octave >> kpt.class_id;
-        keypoints.push_back(kpt);
+                /* set type */
+                switch (type)
+                {
+                case 'u': { pack.cv_type = CV_8U ; break; }
+                case 'c': { pack.cv_type = CV_8S ; break; }
+                case 'w': { pack.cv_type = CV_16U; break; }
+                case 's': { pack.cv_type = CV_16S; break; }
+                case 'i': { pack.cv_type = CV_32S; break; }
+                case 'f': { pack.cv_type = CV_32F; break; }
+                case 'd': { pack.cv_type = CV_64F; break; }
+                case 'r':
+                default:  { CV_Assert(!"type is not support"); break; }
+                } // need a better way for outputting error.
+
+                binary_to_funcs.push_back(pack);
+            }
+        }
+
+        CV_Assert(iss.eof());
+        CV_Assert(binary_to_funcs.size());
     }
-}
 
+private:
 
-void write(FileStorage& fs, const String& objname, const std::vector<DMatch>& matches)
-{
-    cv::internal::WriteStructContext ws(fs, objname, CV_NODE_SEQ + CV_NODE_FLOW);
+    const uchar * cur;
+    const uchar * beg;
+    const uchar * end;
 
-    int i, n = (int)matches.size();
-    for( i = 0; i < n; i++ )
-    {
-        const DMatch& m = matches[i];
-        cv::write(fs, m.queryIdx);
-        cv::write(fs, m.trainIdx);
-        cv::write(fs, m.imgIdx);
-        cv::write(fs, m.distance);
-    }
-}
+    size_t step;
+    std::vector<binary_to_filenode_t> binary_to_funcs;
+    std::vector<binary_to_filenode_t>::iterator functor_iter;
+};
 
-void read(const FileNode& node, std::vector<DMatch>& matches)
+
+
+/****************************************************************************
+ * Wapper
+ ***************************************************************************/
+
+
+base64::Base64Writer::Base64Writer(::CvFileStorage * fs)
+    : emitter(new Base64ContextEmitter(fs))
+    , data_type_string()
 {
-    matches.resize(0);
-    FileNodeIterator it = node.begin(), it_end = node.end();
-    for( ; it != it_end; )
-    {
-        DMatch m;
-        it >> m.queryIdx >> m.trainIdx >> m.imgIdx >> m.distance;
-        matches.push_back(m);
-    }
+    CV_CHECK_OUTPUT_FILE_STORAGE(fs);
 }
 
+void base64::Base64Writer::write(const void* _data, size_t len, const char* dt)
+{
+    check_dt(dt);
 
-int FileNode::type() const { return !node ? NONE : (node->tag & TYPE_MASK); }
-bool FileNode::isNamed() const { return !node ? false : (node->tag & NAMED) != 0; }
+    RawDataToBinaryConvertor convertor(
+        _data, static_cast<int>(len), data_type_string.c_str()
+    );
+    emitter->write(convertor);
+}
 
-size_t FileNode::size() const
+template<typename _to_binary_convertor_t> inline
+void base64::Base64Writer::write(_to_binary_convertor_t & convertor, const char* dt)
 {
-    int t = type();
-    return t == MAP ? (size_t)((CvSet*)node->data.map)->active_count :
-        t == SEQ ? (size_t)node->data.seq->total : (size_t)!isNone();
+    check_dt(dt);
+    emitter->write(convertor);
 }
 
-void read(const FileNode& node, int& value, int default_value)
+base64::Base64Writer::~Base64Writer()
 {
-    value = !node.node ? default_value :
-    CV_NODE_IS_INT(node.node->tag) ? node.node->data.i :
-    CV_NODE_IS_REAL(node.node->tag) ? cvRound(node.node->data.f) : 0x7fffffff;
+    delete emitter;
 }
 
-void read(const FileNode& node, float& value, float default_value)
+void base64::Base64Writer::check_dt(const char* dt)
 {
-    value = !node.node ? default_value :
-        CV_NODE_IS_INT(node.node->tag) ? (float)node.node->data.i :
-        CV_NODE_IS_REAL(node.node->tag) ? (float)node.node->data.f : 1e30f;
+    if ( dt == 0 )
+        CV_Error( CV_StsBadArg, "Invalid \'dt\'." );
+    else if (data_type_string.empty()) {
+        data_type_string = dt;
+
+        /* output header */
+        std::string buffer = make_base64_header(dt);
+        const uchar * beg = reinterpret_cast<const uchar *>(buffer.data());
+        const uchar * end = beg + buffer.size();
+
+        emitter->write(beg, end);
+    } else if ( data_type_string != dt )
+        CV_Error( CV_StsBadArg, "\'dt\' does not match." );
 }
 
-void read(const FileNode& node, double& value, double default_value)
+
+void base64::make_seq(void * binary, int elem_cnt, const char * dt, ::CvSeq & seq)
 {
-    value = !node.node ? default_value :
-        CV_NODE_IS_INT(node.node->tag) ? (double)node.node->data.i :
-        CV_NODE_IS_REAL(node.node->tag) ? node.node->data.f : 1e300;
+    ::CvFileNode node;
+    node.info = 0;
+    BinaryToCvSeqConvertor convertor(binary, elem_cnt, dt);
+    while (convertor) {
+        convertor >> node;
+        cvSeqPush(&seq, &node);
+    }
 }
 
-void read(const FileNode& node, String& value, const String& default_value)
+void base64::cvWriteRawDataBase64(::CvFileStorage* fs, const void* _data, int len, const char* dt)
 {
-    value = !node.node ? default_value : CV_NODE_IS_STRING(node.node->tag) ? String(node.node->data.str.ptr) : String();
+    CV_Assert(fs);
+    CV_CHECK_OUTPUT_FILE_STORAGE(fs);
+
+    check_if_write_struct_is_delayed( fs, true );
+
+    if ( fs->state_of_writing_base64 == base64::fs::Uncertain )
+    {
+        switch_to_Base64_state( fs, base64::fs::InUse );
+    }
+    else if ( fs->state_of_writing_base64 != base64::fs::InUse )
+    {
+        CV_Error( CV_StsError, "Base64 should not be used at present." );
+    }
+
+    fs->base64_writer->write(_data, len, dt);
 }
 
+/****************************************************************************
+ * Interface
+ ***************************************************************************/
+
+CV_IMPL void cvWriteRawDataBase64(::CvFileStorage* fs, const void* _data, int len, const char* dt)
+{
+    ::base64::cvWriteRawDataBase64(fs, _data, len, dt);
 }
 
 /* End of file. */
diff --git a/modules/core/src/precomp.hpp b/modules/core/src/precomp.hpp
index f699ede..be30664 100644
--- a/modules/core/src/precomp.hpp
+++ b/modules/core/src/precomp.hpp
@@ -135,6 +135,7 @@ typedef void (*BinaryFuncC)(const uchar* src1, size_t step1,
                        uchar* dst, size_t step, int width, int height,
                        void*);
 
+BinaryFunc getConvertFuncFp16(int ddepth);
 BinaryFunc getConvertFunc(int sdepth, int ddepth);
 BinaryFunc getCopyMaskFunc(size_t esz);
 
@@ -261,11 +262,13 @@ struct CoreTLSData
         device(0), useOpenCL(-1),
 //#endif
         useIPP(-1)
-    {
 #ifdef HAVE_TEGRA_OPTIMIZATION
-        useTegra = -1;
+        ,useTegra(-1)
 #endif
-    }
+#ifdef HAVE_OPENVX
+        ,useOpenVX(-1)
+#endif
+    {}
 
     RNG rng;
 //#ifdef HAVE_OPENCL
@@ -277,6 +280,9 @@ struct CoreTLSData
 #ifdef HAVE_TEGRA_OPTIMIZATION
     int useTegra; // 1 - use, 0 - do not use, -1 - auto/not initialized
 #endif
+#ifdef HAVE_OPENVX
+    int useOpenVX; // 1 - use, 0 - do not use, -1 - auto/not initialized
+#endif
 };
 
 TLSData<CoreTLSData>& getCoreTlsData();
diff --git a/modules/core/src/rand.cpp b/modules/core/src/rand.cpp
index 9d95243..094cde9 100644
--- a/modules/core/src/rand.cpp
+++ b/modules/core/src/rand.cpp
@@ -239,6 +239,17 @@ static void randf_32f( float* arr, int len, uint64* state, const Vec2f* p, bool
         __m128 p1 = _mm_unpackhi_ps(q01l, q01h);
 
         _mm_storeu_ps(arr + i, _mm_add_ps(_mm_mul_ps(_mm_loadu_ps(f), p0), p1));
+#elif defined __ARM_NEON && defined __aarch64__
+        // handwritten NEON is required not for performance but for numerical stability!
+        // 64bit gcc tends to use fmadd instead of separate multiply and add
+        // use volatile to ensure to separate the multiply and add
+        float32x4x2_t q = vld2q_f32((const float*)(p + i));
+
+        float32x4_t p0 = q.val[0];
+        float32x4_t p1 = q.val[1];
+
+        volatile float32x4_t v0 = vmulq_f32(vld1q_f32(f), p0);
+        vst1q_f32(arr+i, vaddq_f32(v0, p1));
 #else
         arr[i+0] = f[0]*p[i+0][0] + p[i+0][1];
         arr[i+1] = f[1]*p[i+1][0] + p[i+1][1];
@@ -255,6 +266,11 @@ static void randf_32f( float* arr, int len, uint64* state, const Vec2f* p, bool
                 _mm_mul_ss(_mm_set_ss((float)(int)temp), _mm_set_ss(p[i][0])),
                 _mm_set_ss(p[i][1]))
                 );
+#elif defined __ARM_NEON && defined __aarch64__
+        float32x2_t t = vadd_f32(vmul_f32(
+                vdup_n_f32((float)(int)temp), vdup_n_f32(p[i][0])),
+                vdup_n_f32(p[i][1]));
+        arr[i] = vget_lane_f32(t, 0);
 #else
         arr[i] = (int)temp*p[i][0] + p[i][1];
 #endif
@@ -624,7 +640,7 @@ void RNG::fill( InputOutputArray _mat, int disttype,
         int ptype = depth == CV_64F ? CV_64F : CV_32F;
         int esz = (int)CV_ELEM_SIZE(ptype);
 
-        if( _param1.isContinuous() && _param1.type() == ptype )
+        if( _param1.isContinuous() && _param1.type() == ptype && n1 >= cn)
             mean = _param1.ptr();
         else
         {
@@ -637,18 +653,18 @@ void RNG::fill( InputOutputArray _mat, int disttype,
             for( j = n1*esz; j < cn*esz; j++ )
                 mean[j] = mean[j - n1*esz];
 
-        if( _param2.isContinuous() && _param2.type() == ptype )
+        if( _param2.isContinuous() && _param2.type() == ptype && n2 >= cn)
             stddev = _param2.ptr();
         else
         {
-            Mat tmp(_param2.size(), ptype, parambuf + cn);
+            Mat tmp(_param2.size(), ptype, parambuf + MAX(n1, cn));
             _param2.convertTo(tmp, ptype);
-            stddev = (uchar*)(parambuf + cn);
+            stddev = (uchar*)(parambuf + MAX(n1, cn));
         }
 
-        if( n1 < cn )
-            for( j = n1*esz; j < cn*esz; j++ )
-                stddev[j] = stddev[j - n1*esz];
+        if( n2 < cn )
+            for( j = n2*esz; j < cn*esz; j++ )
+                stddev[j] = stddev[j - n2*esz];
 
         stdmtx = _param2.rows == cn && _param2.cols == cn;
         scaleFunc = randnScaleTab[depth];
@@ -734,13 +750,23 @@ cv::RNG& cv::theRNG()
     return getCoreTlsData().get()->rng;
 }
 
+void cv::setRNGSeed(int seed)
+{
+    theRNG() = RNG(static_cast<uint64>(seed));
+}
+
+
 void cv::randu(InputOutputArray dst, InputArray low, InputArray high)
 {
+    CV_INSTRUMENT_REGION()
+
     theRNG().fill(dst, RNG::UNIFORM, low, high);
 }
 
 void cv::randn(InputOutputArray dst, InputArray mean, InputArray stddev)
 {
+    CV_INSTRUMENT_REGION()
+
     theRNG().fill(dst, RNG::NORMAL, mean, stddev);
 }
 
@@ -787,6 +813,8 @@ typedef void (*RandShuffleFunc)( Mat& dst, RNG& rng, double iterFactor );
 
 void cv::randShuffle( InputOutputArray _dst, double iterFactor, RNG* _rng )
 {
+    CV_INSTRUMENT_REGION()
+
     RandShuffleFunc tab[] =
     {
         0,
diff --git a/modules/core/src/stat.cpp b/modules/core/src/stat.cpp
index e352575..5cdae20 100644
--- a/modules/core/src/stat.cpp
+++ b/modules/core/src/stat.cpp
@@ -47,6 +47,8 @@
 
 #include "opencl_kernels_core.hpp"
 
+#include "opencv2/core/openvx/ovx_defs.hpp"
+
 namespace cv
 {
 
@@ -757,38 +759,36 @@ struct SumSqr_SIMD<uchar, int, int>
 
         int x = 0;
         __m128i v_zero = _mm_setzero_si128(), v_sum = v_zero, v_sqsum = v_zero;
+        const int len_16 = len & ~15;
 
-        for ( ; x <= len - 16; x += 16)
+        for ( ; x <= len_16 - 16; )
         {
-            __m128i v_src = _mm_loadu_si128((const __m128i *)(src0 + x));
-            __m128i v_half = _mm_unpacklo_epi8(v_src, v_zero);
-
-            __m128i v_mullo = _mm_mullo_epi16(v_half, v_half);
-            __m128i v_mulhi = _mm_mulhi_epi16(v_half, v_half);
-            v_sum = _mm_add_epi32(v_sum, _mm_unpacklo_epi16(v_half, v_zero));
-            v_sum = _mm_add_epi32(v_sum, _mm_unpackhi_epi16(v_half, v_zero));
-            v_sqsum = _mm_add_epi32(v_sqsum, _mm_unpacklo_epi16(v_mullo, v_mulhi));
-            v_sqsum = _mm_add_epi32(v_sqsum, _mm_unpackhi_epi16(v_mullo, v_mulhi));
-
-            v_half = _mm_unpackhi_epi8(v_src, v_zero);
-            v_mullo = _mm_mullo_epi16(v_half, v_half);
-            v_mulhi = _mm_mulhi_epi16(v_half, v_half);
-            v_sum = _mm_add_epi32(v_sum, _mm_unpacklo_epi16(v_half, v_zero));
-            v_sum = _mm_add_epi32(v_sum, _mm_unpackhi_epi16(v_half, v_zero));
-            v_sqsum = _mm_add_epi32(v_sqsum, _mm_unpacklo_epi16(v_mullo, v_mulhi));
-            v_sqsum = _mm_add_epi32(v_sqsum, _mm_unpackhi_epi16(v_mullo, v_mulhi));
+            const int len_tmp = min(x + 2048, len_16);
+            __m128i v_sum_tmp = v_zero;
+            for ( ; x <= len_tmp - 16; x += 16)
+            {
+                __m128i v_src = _mm_loadu_si128((const __m128i *)(src0 + x));
+                __m128i v_half_0 = _mm_unpacklo_epi8(v_src, v_zero);
+                __m128i v_half_1 = _mm_unpackhi_epi8(v_src, v_zero);
+                v_sum_tmp = _mm_add_epi16(v_sum_tmp, _mm_add_epi16(v_half_0, v_half_1));
+                __m128i v_half_2 = _mm_unpacklo_epi16(v_half_0, v_half_1);
+                __m128i v_half_3 = _mm_unpackhi_epi16(v_half_0, v_half_1);
+                v_sqsum = _mm_add_epi32(v_sqsum, _mm_madd_epi16(v_half_2, v_half_2));
+                v_sqsum = _mm_add_epi32(v_sqsum, _mm_madd_epi16(v_half_3, v_half_3));
+            }
+            v_sum = _mm_add_epi32(v_sum, _mm_unpacklo_epi16(v_sum_tmp, v_zero));
+            v_sum = _mm_add_epi32(v_sum, _mm_unpackhi_epi16(v_sum_tmp, v_zero));
         }
 
         for ( ; x <= len - 8; x += 8)
         {
             __m128i v_src = _mm_unpacklo_epi8(_mm_loadl_epi64((__m128i const *)(src0 + x)), v_zero);
+            __m128i v_half_0 = _mm_unpackhi_epi64(v_src, v_src);
+            __m128i v_sum_tmp = _mm_add_epi16(v_src, v_half_0);
+            __m128i v_half_1 = _mm_unpacklo_epi16(v_src, v_half_0);
 
-            __m128i v_mullo = _mm_mullo_epi16(v_src, v_src);
-            __m128i v_mulhi = _mm_mulhi_epi16(v_src, v_src);
-            v_sum = _mm_add_epi32(v_sum, _mm_unpacklo_epi16(v_src, v_zero));
-            v_sum = _mm_add_epi32(v_sum, _mm_unpackhi_epi16(v_src, v_zero));
-            v_sqsum = _mm_add_epi32(v_sqsum, _mm_unpacklo_epi16(v_mullo, v_mulhi));
-            v_sqsum = _mm_add_epi32(v_sqsum, _mm_unpackhi_epi16(v_mullo, v_mulhi));
+            v_sum = _mm_add_epi32(v_sum, _mm_unpacklo_epi16(v_sum_tmp, v_zero));
+            v_sqsum = _mm_add_epi32(v_sqsum, _mm_madd_epi16(v_half_1, v_half_1));
         }
 
         int CV_DECL_ALIGNED(16) ar[8];
@@ -816,38 +816,36 @@ struct SumSqr_SIMD<schar, int, int>
 
         int x = 0;
         __m128i v_zero = _mm_setzero_si128(), v_sum = v_zero, v_sqsum = v_zero;
+        const int len_16 = len & ~15;
 
-        for ( ; x <= len - 16; x += 16)
+        for ( ; x <= len_16 - 16; )
         {
-            __m128i v_src = _mm_loadu_si128((const __m128i *)(src0 + x));
-            __m128i v_half = _mm_srai_epi16(_mm_unpacklo_epi8(v_zero, v_src), 8);
-
-            __m128i v_mullo = _mm_mullo_epi16(v_half, v_half);
-            __m128i v_mulhi = _mm_mulhi_epi16(v_half, v_half);
-            v_sum = _mm_add_epi32(v_sum, _mm_srai_epi32(_mm_unpacklo_epi16(v_zero, v_half), 16));
-            v_sum = _mm_add_epi32(v_sum, _mm_srai_epi32(_mm_unpackhi_epi16(v_zero, v_half), 16));
-            v_sqsum = _mm_add_epi32(v_sqsum, _mm_unpacklo_epi16(v_mullo, v_mulhi));
-            v_sqsum = _mm_add_epi32(v_sqsum, _mm_unpackhi_epi16(v_mullo, v_mulhi));
-
-            v_half = _mm_srai_epi16(_mm_unpackhi_epi8(v_zero, v_src), 8);
-            v_mullo = _mm_mullo_epi16(v_half, v_half);
-            v_mulhi = _mm_mulhi_epi16(v_half, v_half);
-            v_sum = _mm_add_epi32(v_sum, _mm_srai_epi32(_mm_unpacklo_epi16(v_zero, v_half), 16));
-            v_sum = _mm_add_epi32(v_sum, _mm_srai_epi32(_mm_unpackhi_epi16(v_zero, v_half), 16));
-            v_sqsum = _mm_add_epi32(v_sqsum, _mm_unpacklo_epi16(v_mullo, v_mulhi));
-            v_sqsum = _mm_add_epi32(v_sqsum, _mm_unpackhi_epi16(v_mullo, v_mulhi));
+            const int len_tmp = min(x + 2048, len_16);
+            __m128i v_sum_tmp = v_zero;
+            for ( ; x <= len_tmp - 16; x += 16)
+            {
+                __m128i v_src = _mm_loadu_si128((const __m128i *)(src0 + x));
+                __m128i v_half_0 = _mm_srai_epi16(_mm_unpacklo_epi8(v_zero, v_src), 8);
+                __m128i v_half_1 = _mm_srai_epi16(_mm_unpackhi_epi8(v_zero, v_src), 8);
+                v_sum_tmp = _mm_add_epi16(v_sum_tmp, _mm_add_epi16(v_half_0, v_half_1));
+                __m128i v_half_2 = _mm_unpacklo_epi16(v_half_0, v_half_1);
+                __m128i v_half_3 = _mm_unpackhi_epi16(v_half_0, v_half_1);
+                v_sqsum = _mm_add_epi32(v_sqsum, _mm_madd_epi16(v_half_2, v_half_2));
+                v_sqsum = _mm_add_epi32(v_sqsum, _mm_madd_epi16(v_half_3, v_half_3));
+            }
+            v_sum = _mm_add_epi32(v_sum, _mm_srai_epi32(_mm_unpacklo_epi16(v_zero, v_sum_tmp), 16));
+            v_sum = _mm_add_epi32(v_sum, _mm_srai_epi32(_mm_unpackhi_epi16(v_zero, v_sum_tmp), 16));
         }
 
         for ( ; x <= len - 8; x += 8)
         {
             __m128i v_src = _mm_srai_epi16(_mm_unpacklo_epi8(v_zero, _mm_loadl_epi64((__m128i const *)(src0 + x))), 8);
+            __m128i v_half_0 = _mm_unpackhi_epi64(v_src, v_src);
+            __m128i v_sum_tmp = _mm_add_epi16(v_src, v_half_0);
+            __m128i v_half_1 = _mm_unpacklo_epi16(v_src, v_half_0);
 
-            __m128i v_mullo = _mm_mullo_epi16(v_src, v_src);
-            __m128i v_mulhi = _mm_mulhi_epi16(v_src, v_src);
-            v_sum = _mm_add_epi32(v_sum, _mm_srai_epi32(_mm_unpacklo_epi16(v_zero, v_src), 16));
-            v_sum = _mm_add_epi32(v_sum, _mm_srai_epi32(_mm_unpackhi_epi16(v_zero, v_src), 16));
-            v_sqsum = _mm_add_epi32(v_sqsum, _mm_unpacklo_epi16(v_mullo, v_mulhi));
-            v_sqsum = _mm_add_epi32(v_sqsum, _mm_unpackhi_epi16(v_mullo, v_mulhi));
+            v_sum = _mm_add_epi32(v_sum, _mm_srai_epi32(_mm_unpacklo_epi16(v_zero, v_sum_tmp), 16));
+            v_sqsum = _mm_add_epi32(v_sqsum, _mm_madd_epi16(v_half_1, v_half_1));
         }
 
         int CV_DECL_ALIGNED(16) ar[8];
@@ -1141,6 +1139,8 @@ static bool ocl_sum( InputArray _src, Scalar & res, int sum_op, InputArray _mask
 #ifdef HAVE_IPP
 static bool ipp_sum(Mat &src, Scalar &_res)
 {
+    CV_INSTRUMENT_REGION_IPP()
+
 #if IPP_VERSION_X100 >= 700
     int cn = src.channels();
     size_t total_size = src.total();
@@ -1151,12 +1151,12 @@ static bool ipp_sum(Mat &src, Scalar &_res)
         int type = src.type();
         typedef IppStatus (CV_STDCALL* ippiSumFuncHint)(const void*, int, IppiSize, double *, IppHintAlgorithm);
         typedef IppStatus (CV_STDCALL* ippiSumFuncNoHint)(const void*, int, IppiSize, double *);
-        ippiSumFuncHint ippFuncHint =
+        ippiSumFuncHint ippiSumHint =
             type == CV_32FC1 ? (ippiSumFuncHint)ippiSum_32f_C1R :
             type == CV_32FC3 ? (ippiSumFuncHint)ippiSum_32f_C3R :
             type == CV_32FC4 ? (ippiSumFuncHint)ippiSum_32f_C4R :
             0;
-        ippiSumFuncNoHint ippFuncNoHint =
+        ippiSumFuncNoHint ippiSum =
             type == CV_8UC1 ? (ippiSumFuncNoHint)ippiSum_8u_C1R :
             type == CV_8UC3 ? (ippiSumFuncNoHint)ippiSum_8u_C3R :
             type == CV_8UC4 ? (ippiSumFuncNoHint)ippiSum_8u_C4R :
@@ -1167,12 +1167,13 @@ static bool ipp_sum(Mat &src, Scalar &_res)
             type == CV_16SC3 ? (ippiSumFuncNoHint)ippiSum_16s_C3R :
             type == CV_16SC4 ? (ippiSumFuncNoHint)ippiSum_16s_C4R :
             0;
-        CV_Assert(!ippFuncHint || !ippFuncNoHint);
-        if( ippFuncHint || ippFuncNoHint )
+        CV_Assert(!ippiSumHint || !ippiSum);
+        if( ippiSumHint || ippiSum )
         {
             Ipp64f res[4];
-            IppStatus ret = ippFuncHint ? ippFuncHint(src.ptr(), (int)src.step[0], sz, res, ippAlgHintAccurate) :
-                            ippFuncNoHint(src.ptr(), (int)src.step[0], sz, res);
+            IppStatus ret = ippiSumHint ?
+                            CV_INSTRUMENT_FUN_IPP(ippiSumHint, src.ptr(), (int)src.step[0], sz, res, ippAlgHintAccurate) :
+                            CV_INSTRUMENT_FUN_IPP(ippiSum, src.ptr(), (int)src.step[0], sz, res);
             if( ret >= 0 )
             {
                 for( int i = 0; i < cn; i++ )
@@ -1192,6 +1193,8 @@ static bool ipp_sum(Mat &src, Scalar &_res)
 
 cv::Scalar cv::sum( InputArray _src )
 {
+    CV_INSTRUMENT_REGION()
+
 #if defined HAVE_OPENCL || defined HAVE_IPP
     Scalar _res;
 #endif
@@ -1303,7 +1306,8 @@ namespace cv {
 
 static bool ipp_countNonZero( Mat &src, int &res )
 {
-#if !defined HAVE_IPP_ICV_ONLY
+    CV_INSTRUMENT_REGION_IPP()
+
     Ipp32s count = 0;
     IppStatus status = ippStsNoErr;
 
@@ -1318,18 +1322,15 @@ static bool ipp_countNonZero( Mat &src, int &res )
     }
 
     if (depth == CV_8U)
-        status = ippiCountInRange_8u_C1R((const Ipp8u *)src.data, srcstep, roiSize, &count, 0, 0);
+        status = CV_INSTRUMENT_FUN_IPP(ippiCountInRange_8u_C1R, (const Ipp8u *)src.data, srcstep, roiSize, &count, 0, 0);
     else if (depth == CV_32F)
-        status = ippiCountInRange_32f_C1R((const Ipp32f *)src.data, srcstep, roiSize, &count, 0, 0);
+        status = CV_INSTRUMENT_FUN_IPP(ippiCountInRange_32f_C1R, (const Ipp32f *)src.data, srcstep, roiSize, &count, 0, 0);
 
     if (status >= 0)
     {
         res = ((Ipp32s)src.total() - count);
         return true;
     }
-#else
-    CV_UNUSED(src); CV_UNUSED(res);
-#endif
     return false;
 }
 }
@@ -1338,6 +1339,8 @@ static bool ipp_countNonZero( Mat &src, int &res )
 
 int cv::countNonZero( InputArray _src )
 {
+    CV_INSTRUMENT_REGION()
+
     int type = _src.type(), cn = CV_MAT_CN(type);
     CV_Assert( cn == 1 );
 
@@ -1373,6 +1376,8 @@ namespace cv
 {
 static bool ipp_mean( Mat &src, Mat &mask, Scalar &ret )
 {
+    CV_INSTRUMENT_REGION_IPP()
+
 #if IPP_VERSION_X100 >= 700
     size_t total_size = src.total();
     int rows = src.size[0], cols = rows ? (int)(total_size/rows) : 0;
@@ -1383,32 +1388,32 @@ static bool ipp_mean( Mat &src, Mat &mask, Scalar &ret )
         if( !mask.empty() )
         {
             typedef IppStatus (CV_STDCALL* ippiMaskMeanFuncC1)(const void *, int, const void *, int, IppiSize, Ipp64f *);
-            ippiMaskMeanFuncC1 ippFuncC1 =
+            ippiMaskMeanFuncC1 ippiMean_C1MR =
             type == CV_8UC1 ? (ippiMaskMeanFuncC1)ippiMean_8u_C1MR :
             type == CV_16UC1 ? (ippiMaskMeanFuncC1)ippiMean_16u_C1MR :
             type == CV_32FC1 ? (ippiMaskMeanFuncC1)ippiMean_32f_C1MR :
             0;
-            if( ippFuncC1 )
+            if( ippiMean_C1MR )
             {
                 Ipp64f res;
-                if( ippFuncC1(src.ptr(), (int)src.step[0], mask.ptr(), (int)mask.step[0], sz, &res) >= 0 )
+                if( CV_INSTRUMENT_FUN_IPP(ippiMean_C1MR, src.ptr(), (int)src.step[0], mask.ptr(), (int)mask.step[0], sz, &res) >= 0 )
                 {
                     ret = Scalar(res);
                     return true;
                 }
             }
             typedef IppStatus (CV_STDCALL* ippiMaskMeanFuncC3)(const void *, int, const void *, int, IppiSize, int, Ipp64f *);
-            ippiMaskMeanFuncC3 ippFuncC3 =
+            ippiMaskMeanFuncC3 ippiMean_C3MR =
             type == CV_8UC3 ? (ippiMaskMeanFuncC3)ippiMean_8u_C3CMR :
             type == CV_16UC3 ? (ippiMaskMeanFuncC3)ippiMean_16u_C3CMR :
             type == CV_32FC3 ? (ippiMaskMeanFuncC3)ippiMean_32f_C3CMR :
             0;
-            if( ippFuncC3 )
+            if( ippiMean_C3MR )
             {
                 Ipp64f res1, res2, res3;
-                if( ippFuncC3(src.ptr(), (int)src.step[0], mask.ptr(), (int)mask.step[0], sz, 1, &res1) >= 0 &&
-                    ippFuncC3(src.ptr(), (int)src.step[0], mask.ptr(), (int)mask.step[0], sz, 2, &res2) >= 0 &&
-                    ippFuncC3(src.ptr(), (int)src.step[0], mask.ptr(), (int)mask.step[0], sz, 3, &res3) >= 0 )
+                if( CV_INSTRUMENT_FUN_IPP(ippiMean_C3MR, src.ptr(), (int)src.step[0], mask.ptr(), (int)mask.step[0], sz, 1, &res1) >= 0 &&
+                    CV_INSTRUMENT_FUN_IPP(ippiMean_C3MR, src.ptr(), (int)src.step[0], mask.ptr(), (int)mask.step[0], sz, 2, &res2) >= 0 &&
+                    CV_INSTRUMENT_FUN_IPP(ippiMean_C3MR, src.ptr(), (int)src.step[0], mask.ptr(), (int)mask.step[0], sz, 3, &res3) >= 0 )
                 {
                     ret = Scalar(res1, res2, res3);
                     return true;
@@ -1419,12 +1424,12 @@ static bool ipp_mean( Mat &src, Mat &mask, Scalar &ret )
         {
             typedef IppStatus (CV_STDCALL* ippiMeanFuncHint)(const void*, int, IppiSize, double *, IppHintAlgorithm);
             typedef IppStatus (CV_STDCALL* ippiMeanFuncNoHint)(const void*, int, IppiSize, double *);
-            ippiMeanFuncHint ippFuncHint =
+            ippiMeanFuncHint ippiMeanHint =
                 type == CV_32FC1 ? (ippiMeanFuncHint)ippiMean_32f_C1R :
                 type == CV_32FC3 ? (ippiMeanFuncHint)ippiMean_32f_C3R :
                 type == CV_32FC4 ? (ippiMeanFuncHint)ippiMean_32f_C4R :
                 0;
-            ippiMeanFuncNoHint ippFuncNoHint =
+            ippiMeanFuncNoHint ippiMean =
                 type == CV_8UC1 ? (ippiMeanFuncNoHint)ippiMean_8u_C1R :
                 type == CV_8UC3 ? (ippiMeanFuncNoHint)ippiMean_8u_C3R :
                 type == CV_8UC4 ? (ippiMeanFuncNoHint)ippiMean_8u_C4R :
@@ -1436,12 +1441,12 @@ static bool ipp_mean( Mat &src, Mat &mask, Scalar &ret )
                 type == CV_16SC4 ? (ippiMeanFuncNoHint)ippiMean_16s_C4R :
                 0;
             // Make sure only zero or one version of the function pointer is valid
-            CV_Assert(!ippFuncHint || !ippFuncNoHint);
-            if( ippFuncHint || ippFuncNoHint )
+            CV_Assert(!ippiMeanHint || !ippiMean);
+            if( ippiMeanHint || ippiMean )
             {
                 Ipp64f res[4];
-                IppStatus status = ippFuncHint ? ippFuncHint(src.ptr(), (int)src.step[0], sz, res, ippAlgHintAccurate) :
-                                ippFuncNoHint(src.ptr(), (int)src.step[0], sz, res);
+                IppStatus status = ippiMeanHint ? CV_INSTRUMENT_FUN_IPP(ippiMeanHint, src.ptr(), (int)src.step[0], sz, res, ippAlgHintAccurate) :
+                                CV_INSTRUMENT_FUN_IPP(ippiMean, src.ptr(), (int)src.step[0], sz, res);
                 if( status >= 0 )
                 {
                     for( int i = 0; i < src.channels(); i++ )
@@ -1461,6 +1466,8 @@ static bool ipp_mean( Mat &src, Mat &mask, Scalar &ret )
 
 cv::Scalar cv::mean( InputArray _src, InputArray _mask )
 {
+    CV_INSTRUMENT_REGION()
+
     Mat src = _src.getMat(), mask = _mask.getMat();
     CV_Assert( mask.empty() || mask.type() == CV_8U );
 
@@ -1526,6 +1533,8 @@ namespace cv {
 
 static bool ocl_meanStdDev( InputArray _src, OutputArray _mean, OutputArray _sdv, InputArray _mask )
 {
+    CV_INSTRUMENT_REGION_OPENCL()
+
     bool haveMask = _mask.kind() != _InputArray::NONE;
     int nz = haveMask ? -1 : (int)_src.total();
     Scalar mean, stddev;
@@ -1589,7 +1598,8 @@ static bool ocl_meanStdDev( InputArray _src, OutputArray _mean, OutputArray _sdv
             k.args(srcarg, src.cols, (int)src.total(), groups, dbarg);
 
         size_t globalsize = groups * wgs;
-        if (!k.run(1, &globalsize, &wgs, false))
+
+        if(!k.run(1, &globalsize, &wgs, false))
             return false;
 
         typedef Scalar (* part_sum)(Mat m);
@@ -1640,11 +1650,80 @@ static bool ocl_meanStdDev( InputArray _src, OutputArray _mean, OutputArray _sdv
 
 #endif
 
+#ifdef HAVE_OPENVX
+namespace cv
+{
+    static bool openvx_meanStdDev(Mat& src, OutputArray _mean, OutputArray _sdv, Mat& mask)
+    {
+        size_t total_size = src.total();
+        int rows = src.size[0], cols = rows ? (int)(total_size / rows) : 0;
+        if (src.type() != CV_8UC1|| !mask.empty() ||
+               (src.dims != 2 && !(src.isContinuous() && cols > 0 && (size_t)rows*cols == total_size))
+           )
+        return false;
+
+        try
+        {
+            ivx::Context ctx = ivx::Context::create();
+#ifndef VX_VERSION_1_1
+            if (ctx.vendorID() == VX_ID_KHRONOS)
+                return false; // Do not use OpenVX meanStdDev estimation for sample 1.0.1 implementation due to lack of accuracy
+#endif
+
+            ivx::Image
+                ia = ivx::Image::createFromHandle(ctx, VX_DF_IMAGE_U8,
+                    ivx::Image::createAddressing(cols, rows, 1, (vx_int32)(src.step[0])), src.ptr());
+
+            vx_float32 mean_temp, stddev_temp;
+            ivx::IVX_CHECK_STATUS(vxuMeanStdDev(ctx, ia, &mean_temp, &stddev_temp));
+
+            if (_mean.needed())
+            {
+                if (!_mean.fixedSize())
+                    _mean.create(1, 1, CV_64F, -1, true);
+                Mat mean = _mean.getMat();
+                CV_Assert(mean.type() == CV_64F && mean.isContinuous() &&
+                    (mean.cols == 1 || mean.rows == 1) && mean.total() >= 1);
+                double *pmean = mean.ptr<double>();
+                pmean[0] = mean_temp;
+                for (int c = 1; c < (int)mean.total(); c++)
+                    pmean[c] = 0;
+            }
+
+            if (_sdv.needed())
+            {
+                if (!_sdv.fixedSize())
+                    _sdv.create(1, 1, CV_64F, -1, true);
+                Mat stddev = _sdv.getMat();
+                CV_Assert(stddev.type() == CV_64F && stddev.isContinuous() &&
+                    (stddev.cols == 1 || stddev.rows == 1) && stddev.total() >= 1);
+                double *pstddev = stddev.ptr<double>();
+                pstddev[0] = stddev_temp;
+                for (int c = 1; c < (int)stddev.total(); c++)
+                    pstddev[c] = 0;
+            }
+        }
+        catch (ivx::RuntimeError & e)
+        {
+            VX_DbgThrow(e.what());
+        }
+        catch (ivx::WrapperError & e)
+        {
+            VX_DbgThrow(e.what());
+        }
+
+        return true;
+    }
+}
+#endif
+
 #ifdef HAVE_IPP
 namespace cv
 {
 static bool ipp_meanStdDev(Mat& src, OutputArray _mean, OutputArray _sdv, Mat& mask)
 {
+    CV_INSTRUMENT_REGION_IPP()
+
 #if IPP_VERSION_X100 >= 700
     int cn = src.channels();
     size_t total_size = src.total();
@@ -1683,29 +1762,29 @@ static bool ipp_meanStdDev(Mat& src, OutputArray _mean, OutputArray _sdv, Mat& m
         if( !mask.empty() )
         {
             typedef IppStatus (CV_STDCALL* ippiMaskMeanStdDevFuncC1)(const void *, int, const void *, int, IppiSize, Ipp64f *, Ipp64f *);
-            ippiMaskMeanStdDevFuncC1 ippFuncC1 =
+            ippiMaskMeanStdDevFuncC1 ippiMean_StdDev_C1MR =
             type == CV_8UC1 ? (ippiMaskMeanStdDevFuncC1)ippiMean_StdDev_8u_C1MR :
             type == CV_16UC1 ? (ippiMaskMeanStdDevFuncC1)ippiMean_StdDev_16u_C1MR :
             type == CV_32FC1 ? (ippiMaskMeanStdDevFuncC1)ippiMean_StdDev_32f_C1MR :
             0;
-            if( ippFuncC1 )
+            if( ippiMean_StdDev_C1MR )
             {
-                if( ippFuncC1(src.ptr(), (int)src.step[0], mask.ptr(), (int)mask.step[0], sz, pmean, pstddev) >= 0 )
+                if( CV_INSTRUMENT_FUN_IPP(ippiMean_StdDev_C1MR, src.ptr(), (int)src.step[0], mask.ptr(), (int)mask.step[0], sz, pmean, pstddev) >= 0 )
                 {
                     return true;
                 }
             }
             typedef IppStatus (CV_STDCALL* ippiMaskMeanStdDevFuncC3)(const void *, int, const void *, int, IppiSize, int, Ipp64f *, Ipp64f *);
-            ippiMaskMeanStdDevFuncC3 ippFuncC3 =
+            ippiMaskMeanStdDevFuncC3 ippiMean_StdDev_C3CMR =
             type == CV_8UC3 ? (ippiMaskMeanStdDevFuncC3)ippiMean_StdDev_8u_C3CMR :
             type == CV_16UC3 ? (ippiMaskMeanStdDevFuncC3)ippiMean_StdDev_16u_C3CMR :
             type == CV_32FC3 ? (ippiMaskMeanStdDevFuncC3)ippiMean_StdDev_32f_C3CMR :
             0;
-            if( ippFuncC3 )
+            if( ippiMean_StdDev_C3CMR )
             {
-                if( ippFuncC3(src.ptr(), (int)src.step[0], mask.ptr(), (int)mask.step[0], sz, 1, &pmean[0], &pstddev[0]) >= 0 &&
-                    ippFuncC3(src.ptr(), (int)src.step[0], mask.ptr(), (int)mask.step[0], sz, 2, &pmean[1], &pstddev[1]) >= 0 &&
-                    ippFuncC3(src.ptr(), (int)src.step[0], mask.ptr(), (int)mask.step[0], sz, 3, &pmean[2], &pstddev[2]) >= 0 )
+                if( CV_INSTRUMENT_FUN_IPP(ippiMean_StdDev_C3CMR, src.ptr(), (int)src.step[0], mask.ptr(), (int)mask.step[0], sz, 1, &pmean[0], &pstddev[0]) >= 0 &&
+                    CV_INSTRUMENT_FUN_IPP(ippiMean_StdDev_C3CMR, src.ptr(), (int)src.step[0], mask.ptr(), (int)mask.step[0], sz, 2, &pmean[1], &pstddev[1]) >= 0 &&
+                    CV_INSTRUMENT_FUN_IPP(ippiMean_StdDev_C3CMR, src.ptr(), (int)src.step[0], mask.ptr(), (int)mask.step[0], sz, 3, &pmean[2], &pstddev[2]) >= 0 )
                 {
                     return true;
                 }
@@ -1714,31 +1793,31 @@ static bool ipp_meanStdDev(Mat& src, OutputArray _mean, OutputArray _sdv, Mat& m
         else
         {
             typedef IppStatus (CV_STDCALL* ippiMeanStdDevFuncC1)(const void *, int, IppiSize, Ipp64f *, Ipp64f *);
-            ippiMeanStdDevFuncC1 ippFuncC1 =
+            ippiMeanStdDevFuncC1 ippiMean_StdDev_C1R =
             type == CV_8UC1 ? (ippiMeanStdDevFuncC1)ippiMean_StdDev_8u_C1R :
             type == CV_16UC1 ? (ippiMeanStdDevFuncC1)ippiMean_StdDev_16u_C1R :
 #if (IPP_VERSION_X100 >= 810)
             type == CV_32FC1 ? (ippiMeanStdDevFuncC1)ippiMean_StdDev_32f_C1R ://Aug 2013: bug in IPP 7.1, 8.0
 #endif
             0;
-            if( ippFuncC1 )
+            if( ippiMean_StdDev_C1R )
             {
-                if( ippFuncC1(src.ptr(), (int)src.step[0], sz, pmean, pstddev) >= 0 )
+                if( CV_INSTRUMENT_FUN_IPP(ippiMean_StdDev_C1R, src.ptr(), (int)src.step[0], sz, pmean, pstddev) >= 0 )
                 {
                     return true;
                 }
             }
             typedef IppStatus (CV_STDCALL* ippiMeanStdDevFuncC3)(const void *, int, IppiSize, int, Ipp64f *, Ipp64f *);
-            ippiMeanStdDevFuncC3 ippFuncC3 =
+            ippiMeanStdDevFuncC3 ippiMean_StdDev_C3CR =
             type == CV_8UC3 ? (ippiMeanStdDevFuncC3)ippiMean_StdDev_8u_C3CR :
             type == CV_16UC3 ? (ippiMeanStdDevFuncC3)ippiMean_StdDev_16u_C3CR :
             type == CV_32FC3 ? (ippiMeanStdDevFuncC3)ippiMean_StdDev_32f_C3CR :
             0;
-            if( ippFuncC3 )
+            if( ippiMean_StdDev_C3CR )
             {
-                if( ippFuncC3(src.ptr(), (int)src.step[0], sz, 1, &pmean[0], &pstddev[0]) >= 0 &&
-                    ippFuncC3(src.ptr(), (int)src.step[0], sz, 2, &pmean[1], &pstddev[1]) >= 0 &&
-                    ippFuncC3(src.ptr(), (int)src.step[0], sz, 3, &pmean[2], &pstddev[2]) >= 0 )
+                if( CV_INSTRUMENT_FUN_IPP(ippiMean_StdDev_C3CR, src.ptr(), (int)src.step[0], sz, 1, &pmean[0], &pstddev[0]) >= 0 &&
+                    CV_INSTRUMENT_FUN_IPP(ippiMean_StdDev_C3CR, src.ptr(), (int)src.step[0], sz, 2, &pmean[1], &pstddev[1]) >= 0 &&
+                    CV_INSTRUMENT_FUN_IPP(ippiMean_StdDev_C3CR, src.ptr(), (int)src.step[0], sz, 3, &pmean[2], &pstddev[2]) >= 0 )
                 {
                     return true;
                 }
@@ -1755,12 +1834,17 @@ static bool ipp_meanStdDev(Mat& src, OutputArray _mean, OutputArray _sdv, Mat& m
 
 void cv::meanStdDev( InputArray _src, OutputArray _mean, OutputArray _sdv, InputArray _mask )
 {
+    CV_INSTRUMENT_REGION()
+
     CV_OCL_RUN(OCL_PERFORMANCE_CHECK(_src.isUMat()) && _src.dims() <= 2,
                ocl_meanStdDev(_src, _mean, _sdv, _mask))
 
     Mat src = _src.getMat(), mask = _mask.getMat();
     CV_Assert( mask.empty() || mask.type() == CV_8UC1 );
 
+    CV_OVX_RUN(true,
+               openvx_meanStdDev(src, _mean, _sdv, mask))
+
     CV_IPP_RUN(IPP_VERSION_X100 >= 700, ipp_meanStdDev(src, _mean, _sdv, mask));
 
     int k, cn = src.channels(), depth = src.depth();
@@ -2214,9 +2298,84 @@ static bool ocl_minMaxIdx( InputArray _src, double* minVal, double* maxVal, int*
 
 #endif
 
+#ifdef HAVE_OPENVX
+static bool openvx_minMaxIdx(Mat &src, double* minVal, double* maxVal, int* minIdx, int* maxIdx, Mat &mask)
+{
+    int stype = src.type();
+    size_t total_size = src.total();
+    int rows = src.size[0], cols = rows ? (int)(total_size / rows) : 0;
+    if ((stype != CV_8UC1 && stype != CV_16SC1) || !mask.empty() ||
+        (src.dims != 2 && !(src.isContinuous() && cols > 0 && (size_t)rows*cols == total_size))
+        )
+        return false;
+
+    try
+    {
+        ivx::Context ctx = ivx::Context::create();
+        ivx::Image
+            ia = ivx::Image::createFromHandle(ctx, stype == CV_8UC1 ? VX_DF_IMAGE_U8 : VX_DF_IMAGE_S16,
+                ivx::Image::createAddressing(cols, rows, stype == CV_8UC1 ? 1 : 2, (vx_int32)(src.step[0])), src.ptr());
+
+        ivx::Scalar vxMinVal = ivx::Scalar::create(ctx, stype == CV_8UC1 ? VX_TYPE_UINT8 : VX_TYPE_INT16, 0);
+        ivx::Scalar vxMaxVal = ivx::Scalar::create(ctx, stype == CV_8UC1 ? VX_TYPE_UINT8 : VX_TYPE_INT16, 0);
+        ivx::Array vxMinInd, vxMaxInd;
+        ivx::Scalar vxMinCount, vxMaxCount;
+        if (minIdx)
+        {
+            vxMinInd = ivx::Array::create(ctx, VX_TYPE_COORDINATES2D, 1);
+            vxMinCount = ivx::Scalar::create(ctx, VX_TYPE_UINT32, 0);
+        }
+        if (maxIdx)
+        {
+            vxMaxInd = ivx::Array::create(ctx, VX_TYPE_COORDINATES2D, 1);
+            vxMaxCount = ivx::Scalar::create(ctx, VX_TYPE_UINT32, 0);
+        }
+
+        ivx::IVX_CHECK_STATUS(vxuMinMaxLoc(ctx, ia, vxMinVal, vxMaxVal, vxMinInd, vxMaxInd, vxMinCount, vxMaxCount));
+
+        if (minVal)
+        {
+            *minVal = stype == CV_8UC1 ? vxMinVal.getValue<vx_uint8>() : vxMinVal.getValue<vx_int16>();
+        }
+        if (maxVal)
+        {
+            *maxVal = stype == CV_8UC1 ? vxMaxVal.getValue<vx_uint8>() : vxMaxVal.getValue<vx_int16>();
+        }
+        if (minIdx)
+        {
+            if(vxMinCount.getValue<vx_uint32>()<1) throw ivx::RuntimeError(VX_ERROR_INVALID_VALUE, std::string(__func__) + "(): minimum value location not found");
+            vx_coordinates2d_t loc;
+            vxMinInd.copyRangeTo(0, 1, &loc);
+            size_t minidx = loc.y * cols + loc.x + 1;
+            ofs2idx(src, minidx, minIdx);
+        }
+        if (maxIdx)
+        {
+            if (vxMaxCount.getValue<vx_uint32>()<1) throw ivx::RuntimeError(VX_ERROR_INVALID_VALUE, std::string(__func__) + "(): maximum value location not found");
+            vx_coordinates2d_t loc;
+            vxMaxInd.copyRangeTo(0, 1, &loc);
+            size_t maxidx = loc.y * cols + loc.x + 1;
+            ofs2idx(src, maxidx, maxIdx);
+        }
+    }
+    catch (ivx::RuntimeError & e)
+    {
+        VX_DbgThrow(e.what());
+    }
+    catch (ivx::WrapperError & e)
+    {
+        VX_DbgThrow(e.what());
+    }
+
+    return true;
+}
+#endif
+
 #ifdef HAVE_IPP
 static bool ipp_minMaxIdx( Mat &src, double* minVal, double* maxVal, int* minIdx, int* maxIdx, Mat &mask)
 {
+    CV_INSTRUMENT_REGION_IPP()
+
 #if IPP_VERSION_X100 >= 700
     int type = src.type(), depth = CV_MAT_DEPTH(type), cn = CV_MAT_CN(type);
     size_t total_size = src.total();
@@ -2231,7 +2390,7 @@ static bool ipp_minMaxIdx( Mat &src, double* minVal, double* maxVal, int* minIdx
                                                                         IppiSize, Ipp32f *, Ipp32f *, IppiPoint *, IppiPoint *);
 
             CV_SUPPRESS_DEPRECATED_START
-            ippiMaskMinMaxIndxFuncC1 ippFuncC1 =
+            ippiMaskMinMaxIndxFuncC1 ippiMinMaxIndx_C1MR =
                 type == CV_8UC1 ? (ippiMaskMinMaxIndxFuncC1)ippiMinMaxIndx_8u_C1MR :
 #if IPP_VERSION_X100 < 900
                 type == CV_8SC1 ? (ippiMaskMinMaxIndxFuncC1)ippiMinMaxIndx_8s_C1MR :
@@ -2240,11 +2399,11 @@ static bool ipp_minMaxIdx( Mat &src, double* minVal, double* maxVal, int* minIdx
                 type == CV_32FC1 ? (ippiMaskMinMaxIndxFuncC1)ippiMinMaxIndx_32f_C1MR : 0;
             CV_SUPPRESS_DEPRECATED_END
 
-            if( ippFuncC1 )
+            if( ippiMinMaxIndx_C1MR )
             {
                 Ipp32f min, max;
                 IppiPoint minp, maxp;
-                if( ippFuncC1(src.ptr(), (int)src.step[0], mask.ptr(), (int)mask.step[0], sz, &min, &max, &minp, &maxp) >= 0 )
+                if( CV_INSTRUMENT_FUN_IPP(ippiMinMaxIndx_C1MR, src.ptr(), (int)src.step[0], mask.ptr(), (int)mask.step[0], sz, &min, &max, &minp, &maxp) >= 0 )
                 {
                     if( minVal )
                         *minVal = (double)min;
@@ -2271,7 +2430,7 @@ static bool ipp_minMaxIdx( Mat &src, double* minVal, double* maxVal, int* minIdx
             typedef IppStatus (CV_STDCALL* ippiMinMaxIndxFuncC1)(const void *, int, IppiSize, Ipp32f *, Ipp32f *, IppiPoint *, IppiPoint *);
 
             CV_SUPPRESS_DEPRECATED_START
-            ippiMinMaxIndxFuncC1 ippFuncC1 =
+            ippiMinMaxIndxFuncC1 ippiMinMaxIndx_C1R =
 #if IPP_VERSION_X100 != 900 // bug in 9.0.0 avx2 optimization
                 depth == CV_8U ? (ippiMinMaxIndxFuncC1)ippiMinMaxIndx_8u_C1R :
 #endif
@@ -2279,17 +2438,19 @@ static bool ipp_minMaxIdx( Mat &src, double* minVal, double* maxVal, int* minIdx
                 depth == CV_8S ? (ippiMinMaxIndxFuncC1)ippiMinMaxIndx_8s_C1R :
 #endif
                 depth == CV_16U ? (ippiMinMaxIndxFuncC1)ippiMinMaxIndx_16u_C1R :
-#if !((defined _MSC_VER && defined _M_IX86) || defined __i386__)
+#if IPP_DISABLE_BLOCK && !((defined _MSC_VER && defined _M_IX86) || defined __i386__)
+                // See bug #4955: the function fails with SEGFAULT when the source matrix contains NANs
+                // IPPICV version is 9.0.1.
                 depth == CV_32F ? (ippiMinMaxIndxFuncC1)ippiMinMaxIndx_32f_C1R :
 #endif
                 0;
             CV_SUPPRESS_DEPRECATED_END
 
-            if( ippFuncC1 )
+            if( ippiMinMaxIndx_C1R )
             {
                 Ipp32f min, max;
                 IppiPoint minp, maxp;
-                if( ippFuncC1(src.ptr(), (int)src.step[0], sz, &min, &max, &minp, &maxp) >= 0 )
+                if( CV_INSTRUMENT_FUN_IPP(ippiMinMaxIndx_C1R, src.ptr(), (int)src.step[0], sz, &min, &max, &minp, &maxp) >= 0 )
                 {
                     if( minVal )
                         *minVal = (double)min;
@@ -2323,6 +2484,8 @@ void cv::minMaxIdx(InputArray _src, double* minVal,
                    double* maxVal, int* minIdx, int* maxIdx,
                    InputArray _mask)
 {
+    CV_INSTRUMENT_REGION()
+
     int type = _src.type(), depth = CV_MAT_DEPTH(type), cn = CV_MAT_CN(type);
     CV_Assert( (cn == 1 && (_mask.empty() || _mask.type() == CV_8U)) ||
         (cn > 1 && _mask.empty() && !minIdx && !maxIdx) );
@@ -2331,6 +2494,10 @@ void cv::minMaxIdx(InputArray _src, double* minVal,
                ocl_minMaxIdx(_src, minVal, maxVal, minIdx, maxIdx, _mask))
 
     Mat src = _src.getMat(), mask = _mask.getMat();
+
+    CV_OVX_RUN(true,
+               openvx_minMaxIdx(src, minVal, maxVal, minIdx, maxIdx, mask))
+
     CV_IPP_RUN(IPP_VERSION_X100 >= 700, ipp_minMaxIdx(src, minVal, maxVal, minIdx, maxIdx, mask))
 
     MinMaxIdxFunc func = getMinmaxTab(depth);
@@ -2385,6 +2552,8 @@ void cv::minMaxIdx(InputArray _src, double* minVal,
 void cv::minMaxLoc( InputArray _img, double* minVal, double* maxVal,
                     Point* minLoc, Point* maxLoc, InputArray mask )
 {
+    CV_INSTRUMENT_REGION()
+
     CV_Assert(_img.dims() <= 2);
 
     minMaxIdx(_img, minVal, maxVal, (int*)minLoc, (int*)maxLoc, mask);
@@ -2664,6 +2833,8 @@ static bool ocl_norm( InputArray _src, int normType, InputArray _mask, double &
 #ifdef HAVE_IPP
 static bool ipp_norm(Mat &src, int normType, Mat &mask, double &result)
 {
+    CV_INSTRUMENT_REGION_IPP()
+
 #if IPP_VERSION_X100 >= 700
     int cn = src.channels();
     size_t total_size = src.total();
@@ -2679,7 +2850,7 @@ static bool ipp_norm(Mat &src, int normType, Mat &mask, double &result)
         if( !mask.empty() )
         {
             typedef IppStatus (CV_STDCALL* ippiMaskNormFuncC1)(const void *, int, const void *, int, IppiSize, Ipp64f *);
-            ippiMaskNormFuncC1 ippFuncC1 =
+            ippiMaskNormFuncC1 ippiNorm_C1MR =
                 normType == NORM_INF ?
                 (type == CV_8UC1 ? (ippiMaskNormFuncC1)ippiNorm_Inf_8u_C1MR :
 #if IPP_VERSION_X100 < 900
@@ -2704,10 +2875,10 @@ static bool ipp_norm(Mat &src, int normType, Mat &mask, double &result)
                 type == CV_16UC1 ? (ippiMaskNormFuncC1)ippiNorm_L2_16u_C1MR :
                 type == CV_32FC1 ? (ippiMaskNormFuncC1)ippiNorm_L2_32f_C1MR :
                 0) : 0;
-            if( ippFuncC1 )
+            if( ippiNorm_C1MR )
             {
                 Ipp64f norm;
-                if( ippFuncC1(src.ptr(), (int)src.step[0], mask.ptr(), (int)mask.step[0], sz, &norm) >= 0 )
+                if( CV_INSTRUMENT_FUN_IPP(ippiNorm_C1MR, src.ptr(), (int)src.step[0], mask.ptr(), (int)mask.step[0], sz, &norm) >= 0 )
                 {
                     result = (normType == NORM_L2SQR ? (double)(norm * norm) : (double)norm);
                     return true;
@@ -2715,31 +2886,37 @@ static bool ipp_norm(Mat &src, int normType, Mat &mask, double &result)
             }
 #if IPP_DISABLE_BLOCK
             typedef IppStatus (CV_STDCALL* ippiMaskNormFuncC3)(const void *, int, const void *, int, IppiSize, int, Ipp64f *);
-            ippiMaskNormFuncC3 ippFuncC3 =
+            ippiMaskNormFuncC3 ippiNorm_C3CMR =
                 normType == NORM_INF ?
                 (type == CV_8UC3 ? (ippiMaskNormFuncC3)ippiNorm_Inf_8u_C3CMR :
+#if IPP_VERSION_X100 < 900
                 type == CV_8SC3 ? (ippiMaskNormFuncC3)ippiNorm_Inf_8s_C3CMR :
+#endif
                 type == CV_16UC3 ? (ippiMaskNormFuncC3)ippiNorm_Inf_16u_C3CMR :
                 type == CV_32FC3 ? (ippiMaskNormFuncC3)ippiNorm_Inf_32f_C3CMR :
                 0) :
             normType == NORM_L1 ?
                 (type == CV_8UC3 ? (ippiMaskNormFuncC3)ippiNorm_L1_8u_C3CMR :
+#if IPP_VERSION_X100 < 900
                 type == CV_8SC3 ? (ippiMaskNormFuncC3)ippiNorm_L1_8s_C3CMR :
+#endif
                 type == CV_16UC3 ? (ippiMaskNormFuncC3)ippiNorm_L1_16u_C3CMR :
                 type == CV_32FC3 ? (ippiMaskNormFuncC3)ippiNorm_L1_32f_C3CMR :
                 0) :
             normType == NORM_L2 || normType == NORM_L2SQR ?
                 (type == CV_8UC3 ? (ippiMaskNormFuncC3)ippiNorm_L2_8u_C3CMR :
+#if IPP_VERSION_X100 < 900
                 type == CV_8SC3 ? (ippiMaskNormFuncC3)ippiNorm_L2_8s_C3CMR :
+#endif
                 type == CV_16UC3 ? (ippiMaskNormFuncC3)ippiNorm_L2_16u_C3CMR :
                 type == CV_32FC3 ? (ippiMaskNormFuncC3)ippiNorm_L2_32f_C3CMR :
                 0) : 0;
-            if( ippFuncC3 )
+            if( ippiNorm_C3CMR )
             {
                 Ipp64f norm1, norm2, norm3;
-                if( ippFuncC3(src.data, (int)src.step[0], mask.data, (int)mask.step[0], sz, 1, &norm1) >= 0 &&
-                    ippFuncC3(src.data, (int)src.step[0], mask.data, (int)mask.step[0], sz, 2, &norm2) >= 0 &&
-                    ippFuncC3(src.data, (int)src.step[0], mask.data, (int)mask.step[0], sz, 3, &norm3) >= 0)
+                if( CV_INSTRUMENT_FUN_IPP(ippiNorm_C3CMR, (src.data, (int)src.step[0], mask.data, (int)mask.step[0], sz, 1, &norm1)) >= 0 &&
+                    CV_INSTRUMENT_FUN_IPP(ippiNorm_C3CMR, (src.data, (int)src.step[0], mask.data, (int)mask.step[0], sz, 2, &norm2)) >= 0 &&
+                    CV_INSTRUMENT_FUN_IPP(ippiNorm_C3CMR, (src.data, (int)src.step[0], mask.data, (int)mask.step[0], sz, 3, &norm3)) >= 0)
                 {
                     Ipp64f norm =
                         normType == NORM_INF ? std::max(std::max(norm1, norm2), norm3) :
@@ -2756,7 +2933,7 @@ static bool ipp_norm(Mat &src, int normType, Mat &mask, double &result)
         {
             typedef IppStatus (CV_STDCALL* ippiNormFuncHint)(const void *, int, IppiSize, Ipp64f *, IppHintAlgorithm hint);
             typedef IppStatus (CV_STDCALL* ippiNormFuncNoHint)(const void *, int, IppiSize, Ipp64f *);
-            ippiNormFuncHint ippFuncHint =
+            ippiNormFuncHint ippiNormHint =
                 normType == NORM_L1 ?
                 (type == CV_32FC1 ? (ippiNormFuncHint)ippiNorm_L1_32f_C1R :
                 type == CV_32FC3 ? (ippiNormFuncHint)ippiNorm_L1_32f_C3R :
@@ -2767,7 +2944,7 @@ static bool ipp_norm(Mat &src, int normType, Mat &mask, double &result)
                 type == CV_32FC3 ? (ippiNormFuncHint)ippiNorm_L2_32f_C3R :
                 type == CV_32FC4 ? (ippiNormFuncHint)ippiNorm_L2_32f_C4R :
                 0) : 0;
-            ippiNormFuncNoHint ippFuncNoHint =
+            ippiNormFuncNoHint ippiNorm =
                 normType == NORM_INF ?
                 (type == CV_8UC1 ? (ippiNormFuncNoHint)ippiNorm_Inf_8u_C1R :
                 type == CV_8UC3 ? (ippiNormFuncNoHint)ippiNorm_Inf_8u_C3R :
@@ -2807,12 +2984,12 @@ static bool ipp_norm(Mat &src, int normType, Mat &mask, double &result)
                 type == CV_16SC4 ? (ippiNormFuncNoHint)ippiNorm_L2_16s_C4R :
                 0) : 0;
             // Make sure only zero or one version of the function pointer is valid
-            CV_Assert(!ippFuncHint || !ippFuncNoHint);
-            if( ippFuncHint || ippFuncNoHint )
+            CV_Assert(!ippiNormHint || !ippiNorm);
+            if( ippiNormHint || ippiNorm )
             {
                 Ipp64f norm_array[4];
-                IppStatus ret = ippFuncHint ? ippFuncHint(src.ptr(), (int)src.step[0], sz, norm_array, ippAlgHintAccurate) :
-                                ippFuncNoHint(src.ptr(), (int)src.step[0], sz, norm_array);
+                IppStatus ret = ippiNormHint ? CV_INSTRUMENT_FUN_IPP(ippiNormHint, src.ptr(), (int)src.step[0], sz, norm_array, ippAlgHintAccurate) :
+                                CV_INSTRUMENT_FUN_IPP(ippiNorm, src.ptr(), (int)src.step[0], sz, norm_array);
                 if( ret >= 0 )
                 {
                     Ipp64f norm = (normType == NORM_L2 || normType == NORM_L2SQR) ? norm_array[0] * norm_array[0] : norm_array[0];
@@ -2840,6 +3017,8 @@ static bool ipp_norm(Mat &src, int normType, Mat &mask, double &result)
 
 double cv::norm( InputArray _src, int normType, InputArray _mask )
 {
+    CV_INSTRUMENT_REGION()
+
     normType &= NORM_TYPE_MASK;
     CV_Assert( normType == NORM_INF || normType == NORM_L1 ||
                normType == NORM_L2 || normType == NORM_L2SQR ||
@@ -3060,6 +3239,8 @@ namespace cv
 {
 static bool ipp_norm(InputArray _src1, InputArray _src2, int normType, InputArray _mask, double &result)
 {
+    CV_INSTRUMENT_REGION_IPP()
+
 #if IPP_VERSION_X100 >= 700
     Mat src1 = _src1.getMat(), src2 = _src2.getMat(), mask = _mask.getMat();
 
@@ -3080,7 +3261,7 @@ static bool ipp_norm(InputArray _src1, InputArray _src2, int normType, InputArra
             if( !mask.empty() )
             {
                 typedef IppStatus (CV_STDCALL* ippiMaskNormRelFuncC1)(const void *, int, const void *, int, const void *, int, IppiSize, Ipp64f *);
-                ippiMaskNormRelFuncC1 ippFuncC1 =
+                ippiMaskNormRelFuncC1 ippiNormDiff_C1MR =
                     normType == NORM_INF ?
                     (type == CV_8UC1 ? (ippiMaskNormRelFuncC1)ippiNormRel_Inf_8u_C1MR :
 #if IPP_VERSION_X100 < 900
@@ -3109,10 +3290,10 @@ static bool ipp_norm(InputArray _src1, InputArray _src2, int normType, InputArra
                     type == CV_16UC1 ? (ippiMaskNormRelFuncC1)ippiNormRel_L2_16u_C1MR :
                     type == CV_32FC1 ? (ippiMaskNormRelFuncC1)ippiNormRel_L2_32f_C1MR :
                     0) : 0;
-                if( ippFuncC1 )
+                if( ippiNormDiff_C1MR )
                 {
                     Ipp64f norm;
-                    if( ippFuncC1(src1.ptr(), (int)src1.step[0], src2.ptr(), (int)src2.step[0], mask.ptr(), (int)mask.step[0], sz, &norm) >= 0 )
+                    if( CV_INSTRUMENT_FUN_IPP(ippiNormDiff_C1MR, src1.ptr(), (int)src1.step[0], src2.ptr(), (int)src2.step[0], mask.ptr(), (int)mask.step[0], sz, &norm) >= 0 )
                     {
                         result = (normType == NORM_L2SQR ? (double)(norm * norm) : (double)norm);
                         return true;
@@ -3123,7 +3304,7 @@ static bool ipp_norm(InputArray _src1, InputArray _src2, int normType, InputArra
             {
                 typedef IppStatus (CV_STDCALL* ippiNormRelFuncNoHint)(const void *, int, const void *, int, IppiSize, Ipp64f *);
                 typedef IppStatus (CV_STDCALL* ippiNormRelFuncHint)(const void *, int, const void *, int, IppiSize, Ipp64f *, IppHintAlgorithm hint);
-                ippiNormRelFuncNoHint ippFuncNoHint =
+                ippiNormRelFuncNoHint ippiNormDiff =
                     normType == NORM_INF ?
                     (type == CV_8UC1 ? (ippiNormRelFuncNoHint)ippiNormRel_Inf_8u_C1R :
                     type == CV_16UC1 ? (ippiNormRelFuncNoHint)ippiNormRel_Inf_16u_C1R :
@@ -3140,26 +3321,26 @@ static bool ipp_norm(InputArray _src1, InputArray _src2, int normType, InputArra
                     type == CV_16UC1 ? (ippiNormRelFuncNoHint)ippiNormRel_L2_16u_C1R :
                     type == CV_16SC1 ? (ippiNormRelFuncNoHint)ippiNormRel_L2_16s_C1R :
                     0) : 0;
-                ippiNormRelFuncHint ippFuncHint =
+                ippiNormRelFuncHint ippiNormDiffHint =
                     normType == NORM_L1 ?
                     (type == CV_32FC1 ? (ippiNormRelFuncHint)ippiNormRel_L1_32f_C1R :
                     0) :
                     normType == NORM_L2 || normType == NORM_L2SQR ?
                     (type == CV_32FC1 ? (ippiNormRelFuncHint)ippiNormRel_L2_32f_C1R :
                     0) : 0;
-                if (ippFuncNoHint)
+                if (ippiNormDiff)
                 {
                     Ipp64f norm;
-                    if( ippFuncNoHint(src1.ptr(), (int)src1.step[0], src2.ptr(), (int)src2.step[0], sz, &norm) >= 0 )
+                    if( CV_INSTRUMENT_FUN_IPP(ippiNormDiff, src1.ptr(), (int)src1.step[0], src2.ptr(), (int)src2.step[0], sz, &norm) >= 0 )
                     {
                         result = (double)norm;
                         return true;
                     }
                 }
-                if (ippFuncHint)
+                if (ippiNormDiffHint)
                 {
                     Ipp64f norm;
-                    if( ippFuncHint(src1.ptr(), (int)src1.step[0], src2.ptr(), (int)src2.step[0], sz, &norm, ippAlgHintAccurate) >= 0 )
+                    if( CV_INSTRUMENT_FUN_IPP(ippiNormDiffHint, src1.ptr(), (int)src1.step[0], src2.ptr(), (int)src2.step[0], sz, &norm, ippAlgHintAccurate) >= 0 )
                     {
                         result = (double)norm;
                         return true;
@@ -3187,7 +3368,7 @@ static bool ipp_norm(InputArray _src1, InputArray _src2, int normType, InputArra
         if( !mask.empty() )
         {
             typedef IppStatus (CV_STDCALL* ippiMaskNormDiffFuncC1)(const void *, int, const void *, int, const void *, int, IppiSize, Ipp64f *);
-            ippiMaskNormDiffFuncC1 ippFuncC1 =
+            ippiMaskNormDiffFuncC1 ippiNormDiff_C1MR =
                 normType == NORM_INF ?
                 (type == CV_8UC1 ? (ippiMaskNormDiffFuncC1)ippiNormDiff_Inf_8u_C1MR :
 #if IPP_VERSION_X100 < 900
@@ -3214,10 +3395,10 @@ static bool ipp_norm(InputArray _src1, InputArray _src2, int normType, InputArra
                 type == CV_16UC1 ? (ippiMaskNormDiffFuncC1)ippiNormDiff_L2_16u_C1MR :
                 type == CV_32FC1 ? (ippiMaskNormDiffFuncC1)ippiNormDiff_L2_32f_C1MR :
                 0) : 0;
-            if( ippFuncC1 )
+            if( ippiNormDiff_C1MR )
             {
                 Ipp64f norm;
-                if( ippFuncC1(src1.ptr(), (int)src1.step[0], src2.ptr(), (int)src2.step[0], mask.ptr(), (int)mask.step[0], sz, &norm) >= 0 )
+                if( CV_INSTRUMENT_FUN_IPP(ippiNormDiff_C1MR, src1.ptr(), (int)src1.step[0], src2.ptr(), (int)src2.step[0], mask.ptr(), (int)mask.step[0], sz, &norm) >= 0 )
                 {
                     result = (normType == NORM_L2SQR ? (double)(norm * norm) : (double)norm);
                     return true;
@@ -3225,7 +3406,7 @@ static bool ipp_norm(InputArray _src1, InputArray _src2, int normType, InputArra
             }
 #ifndef __APPLE__
             typedef IppStatus (CV_STDCALL* ippiMaskNormDiffFuncC3)(const void *, int, const void *, int, const void *, int, IppiSize, int, Ipp64f *);
-            ippiMaskNormDiffFuncC3 ippFuncC3 =
+            ippiMaskNormDiffFuncC3 ippiNormDiff_C3CMR =
                 normType == NORM_INF ?
                 (type == CV_8UC3 ? (ippiMaskNormDiffFuncC3)ippiNormDiff_Inf_8u_C3CMR :
 #if IPP_VERSION_X100 < 900
@@ -3250,12 +3431,12 @@ static bool ipp_norm(InputArray _src1, InputArray _src2, int normType, InputArra
                 type == CV_16UC3 ? (ippiMaskNormDiffFuncC3)ippiNormDiff_L2_16u_C3CMR :
                 type == CV_32FC3 ? (ippiMaskNormDiffFuncC3)ippiNormDiff_L2_32f_C3CMR :
                 0) : 0;
-            if( ippFuncC3 )
+            if( ippiNormDiff_C3CMR )
             {
                 Ipp64f norm1, norm2, norm3;
-                if( ippFuncC3(src1.data, (int)src1.step[0], src2.data, (int)src2.step[0], mask.data, (int)mask.step[0], sz, 1, &norm1) >= 0 &&
-                    ippFuncC3(src1.data, (int)src1.step[0], src2.data, (int)src2.step[0], mask.data, (int)mask.step[0], sz, 2, &norm2) >= 0 &&
-                    ippFuncC3(src1.data, (int)src1.step[0], src2.data, (int)src2.step[0], mask.data, (int)mask.step[0], sz, 3, &norm3) >= 0)
+                if( CV_INSTRUMENT_FUN_IPP(ippiNormDiff_C3CMR, src1.data, (int)src1.step[0], src2.data, (int)src2.step[0], mask.data, (int)mask.step[0], sz, 1, &norm1) >= 0 &&
+                    CV_INSTRUMENT_FUN_IPP(ippiNormDiff_C3CMR, src1.data, (int)src1.step[0], src2.data, (int)src2.step[0], mask.data, (int)mask.step[0], sz, 2, &norm2) >= 0 &&
+                    CV_INSTRUMENT_FUN_IPP(ippiNormDiff_C3CMR, src1.data, (int)src1.step[0], src2.data, (int)src2.step[0], mask.data, (int)mask.step[0], sz, 3, &norm3) >= 0)
                 {
                     Ipp64f norm =
                         normType == NORM_INF ? std::max(std::max(norm1, norm2), norm3) :
@@ -3272,7 +3453,7 @@ static bool ipp_norm(InputArray _src1, InputArray _src2, int normType, InputArra
         {
             typedef IppStatus (CV_STDCALL* ippiNormDiffFuncHint)(const void *, int, const void *, int, IppiSize, Ipp64f *, IppHintAlgorithm hint);
             typedef IppStatus (CV_STDCALL* ippiNormDiffFuncNoHint)(const void *, int, const void *, int, IppiSize, Ipp64f *);
-            ippiNormDiffFuncHint ippFuncHint =
+            ippiNormDiffFuncHint ippiNormDiffHint =
                 normType == NORM_L1 ?
                 (type == CV_32FC1 ? (ippiNormDiffFuncHint)ippiNormDiff_L1_32f_C1R :
                 type == CV_32FC3 ? (ippiNormDiffFuncHint)ippiNormDiff_L1_32f_C3R :
@@ -3283,7 +3464,7 @@ static bool ipp_norm(InputArray _src1, InputArray _src2, int normType, InputArra
                 type == CV_32FC3 ? (ippiNormDiffFuncHint)ippiNormDiff_L2_32f_C3R :
                 type == CV_32FC4 ? (ippiNormDiffFuncHint)ippiNormDiff_L2_32f_C4R :
                 0) : 0;
-            ippiNormDiffFuncNoHint ippFuncNoHint =
+            ippiNormDiffFuncNoHint ippiNormDiff =
                 normType == NORM_INF ?
                 (type == CV_8UC1 ? (ippiNormDiffFuncNoHint)ippiNormDiff_Inf_8u_C1R :
                 type == CV_8UC3 ? (ippiNormDiffFuncNoHint)ippiNormDiff_Inf_8u_C3R :
@@ -3325,12 +3506,12 @@ static bool ipp_norm(InputArray _src1, InputArray _src2, int normType, InputArra
                 type == CV_16SC4 ? (ippiNormDiffFuncNoHint)ippiNormDiff_L2_16s_C4R :
                 0) : 0;
             // Make sure only zero or one version of the function pointer is valid
-            CV_Assert(!ippFuncHint || !ippFuncNoHint);
-            if( ippFuncHint || ippFuncNoHint )
+            CV_Assert(!ippiNormDiffHint || !ippiNormDiff);
+            if( ippiNormDiffHint || ippiNormDiff )
             {
                 Ipp64f norm_array[4];
-                IppStatus ret = ippFuncHint ? ippFuncHint(src1.ptr(), (int)src1.step[0], src2.ptr(), (int)src2.step[0], sz, norm_array, ippAlgHintAccurate) :
-                                ippFuncNoHint(src1.ptr(), (int)src1.step[0], src2.ptr(), (int)src2.step[0], sz, norm_array);
+                IppStatus ret = ippiNormDiffHint ? CV_INSTRUMENT_FUN_IPP(ippiNormDiffHint, src1.ptr(), (int)src1.step[0], src2.ptr(), (int)src2.step[0], sz, norm_array, ippAlgHintAccurate) :
+                                CV_INSTRUMENT_FUN_IPP(ippiNormDiff, src1.ptr(), (int)src1.step[0], src2.ptr(), (int)src2.step[0], sz, norm_array);
                 if( ret >= 0 )
                 {
                     Ipp64f norm = (normType == NORM_L2 || normType == NORM_L2SQR) ? norm_array[0] * norm_array[0] : norm_array[0];
@@ -3359,6 +3540,8 @@ static bool ipp_norm(InputArray _src1, InputArray _src2, int normType, InputArra
 
 double cv::norm( InputArray _src1, InputArray _src2, int normType, InputArray _mask )
 {
+    CV_INSTRUMENT_REGION()
+
     CV_Assert( _src1.sameSize(_src2) && _src1.type() == _src2.type() );
 
 #if defined HAVE_OPENCL || defined HAVE_IPP
@@ -3743,6 +3926,8 @@ void cv::batchDistance( InputArray _src1, InputArray _src2,
                         int normType, int K, InputArray _mask,
                         int update, bool crosscheck )
 {
+    CV_INSTRUMENT_REGION()
+
     Mat src1 = _src1.getMat(), src2 = _src2.getMat(), mask = _mask.getMat();
     int type = src1.type();
     CV_Assert( type == src2.type() && src1.cols == src2.cols &&
@@ -3852,6 +4037,8 @@ void cv::batchDistance( InputArray _src1, InputArray _src2,
 
 void cv::findNonZero( InputArray _src, OutputArray _idx )
 {
+    CV_INSTRUMENT_REGION()
+
     Mat src = _src.getMat();
     CV_Assert( src.type() == CV_8UC1 );
     int n = countNonZero(src);
@@ -3878,6 +4065,8 @@ void cv::findNonZero( InputArray _src, OutputArray _idx )
 
 double cv::PSNR(InputArray _src1, InputArray _src2)
 {
+    CV_INSTRUMENT_REGION()
+
     CV_Assert( _src1.depth() == CV_8U );
     double diff = std::sqrt(norm(_src1, _src2, NORM_L2SQR)/(_src1.total()*_src1.channels()));
     return 20*log10(255./(diff+DBL_EPSILON));
@@ -4035,6 +4224,16 @@ static const uchar popCountTable4[] =
     1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2
 };
 
+#if CV_AVX2
+static inline int _mm256_extract_epi32_(__m256i reg, const int i)
+{
+    CV_DECL_ALIGNED(32) int reg_data[8];
+    CV_DbgAssert(0 <= i && i < 8);
+    _mm256_store_si256((__m256i*)reg_data, reg);
+    return reg_data[i];
+}
+#endif
+
 int normHamming(const uchar* a, int n)
 {
     int i = 0;
@@ -4053,6 +4252,27 @@ int normHamming(const uchar* a, int n)
         result = vgetq_lane_s32 (vreinterpretq_s32_u64(bitSet2),0);
         result += vgetq_lane_s32 (vreinterpretq_s32_u64(bitSet2),2);
     }
+#elif CV_AVX2
+    {
+        __m256i _r0 = _mm256_setzero_si256();
+        __m256i _0 = _mm256_setzero_si256();
+        __m256i _popcnt_table = _mm256_setr_epi8(0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
+                                                 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4);
+        __m256i _popcnt_mask = _mm256_set1_epi8(0x0F);
+
+        for(; i <= n - 32; i+= 32)
+        {
+            __m256i _a0 = _mm256_loadu_si256((const __m256i*)(a + i));
+
+            __m256i _popc0 = _mm256_shuffle_epi8(_popcnt_table, _mm256_and_si256(_a0, _popcnt_mask));
+            __m256i _popc1 = _mm256_shuffle_epi8(_popcnt_table,
+                             _mm256_and_si256(_mm256_srli_epi16(_a0, 4), _popcnt_mask));
+
+            _r0 = _mm256_add_epi32(_r0, _mm256_sad_epu8(_0, _mm256_add_epi8(_popc0, _popc1)));
+        }
+        _r0 = _mm256_add_epi32(_r0, _mm256_shuffle_epi32(_r0, 2));
+        result = _mm256_extract_epi32_(_mm256_add_epi32(_r0, _mm256_permute2x128_si256(_r0, _r0, 1)), 0);
+    }
 #endif
         for( ; i <= n - 4; i += 4 )
             result += popCountTable[a[i]] + popCountTable[a[i+1]] +
@@ -4082,6 +4302,30 @@ int normHamming(const uchar* a, const uchar* b, int n)
         result = vgetq_lane_s32 (vreinterpretq_s32_u64(bitSet2),0);
         result += vgetq_lane_s32 (vreinterpretq_s32_u64(bitSet2),2);
     }
+#elif CV_AVX2
+    {
+        __m256i _r0 = _mm256_setzero_si256();
+        __m256i _0 = _mm256_setzero_si256();
+        __m256i _popcnt_table = _mm256_setr_epi8(0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
+                                                 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4);
+        __m256i _popcnt_mask = _mm256_set1_epi8(0x0F);
+
+        for(; i <= n - 32; i+= 32)
+        {
+            __m256i _a0 = _mm256_loadu_si256((const __m256i*)(a + i));
+            __m256i _b0 = _mm256_loadu_si256((const __m256i*)(b + i));
+
+            __m256i _xor = _mm256_xor_si256(_a0, _b0);
+
+            __m256i _popc0 = _mm256_shuffle_epi8(_popcnt_table, _mm256_and_si256(_xor, _popcnt_mask));
+            __m256i _popc1 = _mm256_shuffle_epi8(_popcnt_table,
+                             _mm256_and_si256(_mm256_srli_epi16(_xor, 4), _popcnt_mask));
+
+            _r0 = _mm256_add_epi32(_r0, _mm256_sad_epu8(_0, _mm256_add_epi8(_popc0, _popc1)));
+        }
+        _r0 = _mm256_add_epi32(_r0, _mm256_shuffle_epi32(_r0, 2));
+        result = _mm256_extract_epi32_(_mm256_add_epi32(_r0, _mm256_permute2x128_si256(_r0, _r0, 1)), 0);
+    }
 #endif
         for( ; i <= n - 4; i += 4 )
             result += popCountTable[a[i] ^ b[i]] + popCountTable[a[i+1] ^ b[i+1]] +
diff --git a/modules/core/src/system.cpp b/modules/core/src/system.cpp
index 5fbb453..3c8f39d 100644
--- a/modules/core/src/system.cpp
+++ b/modules/core/src/system.cpp
@@ -198,7 +198,7 @@ std::wstring GetTempFileNameWinRT(std::wstring prefix)
 
 #include <stdarg.h>
 
-#if defined __linux__ || defined __APPLE__ || defined __EMSCRIPTEN__
+#if defined __linux__ || defined __APPLE__ || defined __EMSCRIPTEN__ || defined __FreeBSD__
 #include <unistd.h>
 #include <stdio.h>
 #include <sys/types.h>
@@ -291,6 +291,7 @@ struct HWFeatures
             f.have[CV_CPU_SSE4_2] = (cpuid_data[2] & (1<<20)) != 0;
             f.have[CV_CPU_POPCNT] = (cpuid_data[2] & (1<<23)) != 0;
             f.have[CV_CPU_AVX]    = (((cpuid_data[2] & (1<<28)) != 0)&&((cpuid_data[2] & (1<<27)) != 0));//OS uses XSAVE_XRSTORE and CPU support AVX
+            f.have[CV_CPU_FP16]   = (cpuid_data[2] & (1<<29)) != 0;
 
             // make the second call to the cpuid command in order to get
             // information about extended features like AVX2
@@ -338,7 +339,8 @@ struct HWFeatures
     #if defined ANDROID || defined __linux__
     #ifdef __aarch64__
         f.have[CV_CPU_NEON] = true;
-    #else
+        f.have[CV_CPU_FP16] = true;
+    #elif defined __arm__
         int cpufile = open("/proc/self/auxv", O_RDONLY);
 
         if (cpufile >= 0)
@@ -351,6 +353,7 @@ struct HWFeatures
                 if (auxv.a_type == AT_HWCAP)
                 {
                     f.have[CV_CPU_NEON] = (auxv.a_un.a_val & 4096) != 0;
+                    f.have[CV_CPU_FP16] = (auxv.a_un.a_val & 2) != 0;
                     break;
                 }
             }
@@ -358,9 +361,14 @@ struct HWFeatures
             close(cpufile);
         }
     #endif
-    #elif (defined __clang__ || defined __APPLE__) && (defined __ARM_NEON__ || (defined __ARM_NEON && defined __aarch64__))
+    #elif (defined __clang__ || defined __APPLE__)
+    #if (defined __ARM_NEON__ || (defined __ARM_NEON && defined __aarch64__))
         f.have[CV_CPU_NEON] = true;
     #endif
+    #if (defined __ARM_FP  && (((__ARM_FP & 0x2) != 0) && defined __ARM_NEON__))
+        f.have[CV_CPU_FP16] = true;
+    #endif
+    #endif
 
         return f;
     }
@@ -613,7 +621,7 @@ String tempfile( const char* suffix )
     return fname;
 }
 
-static CvErrorCallback customErrorCallback = 0;
+static ErrorCallback customErrorCallback = 0;
 static void* customErrorCallbackData = 0;
 static bool breakOnError = false;
 
@@ -658,13 +666,13 @@ void error(int _code, const String& _err, const char* _func, const char* _file,
     error(cv::Exception(_code, _err, _func, _file, _line));
 }
 
-CvErrorCallback
-redirectError( CvErrorCallback errCallback, void* userdata, void** prevUserdata)
+ErrorCallback
+redirectError( ErrorCallback errCallback, void* userdata, void** prevUserdata)
 {
     if( prevUserdata )
         *prevUserdata = customErrorCallbackData;
 
-    CvErrorCallback prevCallback = customErrorCallback;
+    ErrorCallback prevCallback = customErrorCallback;
 
     customErrorCallback     = errCallback;
     customErrorCallbackData = userdata;
@@ -1085,11 +1093,14 @@ public:
 
         for(size_t i = 0; i < threads.size(); i++)
         {
-            std::vector<void*>& thread_slots = threads[i]->slots;
-            if (thread_slots.size() > slotIdx && thread_slots[slotIdx])
+            if(threads[i])
             {
-                dataVec.push_back(thread_slots[slotIdx]);
-                threads[i]->slots[slotIdx] = 0;
+                std::vector<void*>& thread_slots = threads[i]->slots;
+                if (thread_slots.size() > slotIdx && thread_slots[slotIdx])
+                {
+                    dataVec.push_back(thread_slots[slotIdx]);
+                    threads[i]->slots[slotIdx] = 0;
+                }
             }
         }
 
@@ -1116,9 +1127,12 @@ public:
 
         for(size_t i = 0; i < threads.size(); i++)
         {
-            std::vector<void*>& thread_slots = threads[i]->slots;
-            if (thread_slots.size() > slotIdx && thread_slots[slotIdx])
-                dataVec.push_back(thread_slots[slotIdx]);
+            if(threads[i])
+            {
+                std::vector<void*>& thread_slots = threads[i]->slots;
+                if (thread_slots.size() > slotIdx && thread_slots[slotIdx])
+                    dataVec.push_back(thread_slots[slotIdx]);
+            }
         }
     }
 
@@ -1286,13 +1300,219 @@ void setUseCollection(bool flag)
 }
 #endif
 
+namespace instr
+{
+bool useInstrumentation()
+{
+#ifdef ENABLE_INSTRUMENTATION
+    return getInstrumentStruct().useInstr;
+#else
+    return false;
+#endif
+}
+
+void setUseInstrumentation(bool flag)
+{
+#ifdef ENABLE_INSTRUMENTATION
+    getInstrumentStruct().useInstr = flag;
+#else
+    CV_UNUSED(flag);
+#endif
+}
+
+InstrNode* getTrace()
+{
+#ifdef ENABLE_INSTRUMENTATION
+    return &getInstrumentStruct().rootNode;
+#else
+    return NULL;
+#endif
+}
+
+void resetTrace()
+{
+#ifdef ENABLE_INSTRUMENTATION
+    getInstrumentStruct().rootNode.removeChilds();
+    getInstrumentTLSStruct().pCurrentNode = &getInstrumentStruct().rootNode;
+#endif
+}
+
+void setFlags(FLAGS modeFlags)
+{
+#ifdef ENABLE_INSTRUMENTATION
+    getInstrumentStruct().flags = modeFlags;
+#else
+    CV_UNUSED(modeFlags);
+#endif
+}
+FLAGS getFlags()
+{
+#ifdef ENABLE_INSTRUMENTATION
+    return (FLAGS)getInstrumentStruct().flags;
+#else
+    return (FLAGS)0;
+#endif
+}
+
+NodeData::NodeData(const char* funName, const char* fileName, int lineNum, void* retAddress, bool alwaysExpand, cv::instr::TYPE instrType, cv::instr::IMPL implType)
+{
+    m_funName       = funName;
+    m_instrType     = instrType;
+    m_implType      = implType;
+    m_fileName      = fileName;
+    m_lineNum       = lineNum;
+    m_retAddress    = retAddress;
+    m_alwaysExpand  = alwaysExpand;
+
+    m_threads    = 1;
+    m_counter    = 0;
+    m_ticksTotal = 0;
+
+    m_funError  = false;
+}
+NodeData::NodeData(NodeData &ref)
+{
+    *this = ref;
+}
+NodeData& NodeData::operator=(const NodeData &right)
+{
+    this->m_funName      = right.m_funName;
+    this->m_instrType    = right.m_instrType;
+    this->m_implType     = right.m_implType;
+    this->m_fileName     = right.m_fileName;
+    this->m_lineNum      = right.m_lineNum;
+    this->m_retAddress   = right.m_retAddress;
+    this->m_alwaysExpand = right.m_alwaysExpand;
+
+    this->m_threads     = right.m_threads;
+    this->m_counter     = right.m_counter;
+    this->m_ticksTotal  = right.m_ticksTotal;
+
+    this->m_funError    = right.m_funError;
+
+    return *this;
+}
+NodeData::~NodeData()
+{
+}
+bool operator==(const NodeData& left, const NodeData& right)
+{
+    if(left.m_lineNum == right.m_lineNum && left.m_funName == right.m_funName && left.m_fileName == right.m_fileName)
+    {
+        if(left.m_retAddress == right.m_retAddress || !(cv::instr::getFlags()&cv::instr::FLAGS_EXPAND_SAME_NAMES || left.m_alwaysExpand))
+            return true;
+    }
+    return false;
+}
+
+#ifdef ENABLE_INSTRUMENTATION
+InstrStruct& getInstrumentStruct()
+{
+    static InstrStruct instr;
+    return instr;
+}
+
+InstrTLSStruct& getInstrumentTLSStruct()
+{
+    return *getInstrumentStruct().tlsStruct.get();
+}
+
+InstrNode* getCurrentNode()
+{
+    return getInstrumentTLSStruct().pCurrentNode;
+}
+
+IntrumentationRegion::IntrumentationRegion(const char* funName, const char* fileName, int lineNum, void *retAddress, bool alwaysExpand, TYPE instrType, IMPL implType)
+{
+    m_disabled    = false;
+    m_regionTicks = 0;
+
+    InstrStruct *pStruct = &getInstrumentStruct();
+    if(pStruct->useInstr)
+    {
+        InstrTLSStruct *pTLS = &getInstrumentTLSStruct();
+
+        // Disable in case of failure
+        if(!pTLS->pCurrentNode)
+        {
+            m_disabled = true;
+            return;
+        }
+
+        int depth = pTLS->pCurrentNode->getDepth();
+        if(pStruct->maxDepth && pStruct->maxDepth <= depth)
+        {
+            m_disabled = true;
+            return;
+        }
+
+        NodeData payload(funName, fileName, lineNum, retAddress, alwaysExpand, instrType, implType);
+        Node<NodeData>* pChild = NULL;
+
+        if(pStruct->flags&FLAGS_MAPPING)
+        {
+            // Critical section
+            cv::AutoLock guard(pStruct->mutexCreate); // Guard from concurrent child creation
+            pChild = pTLS->pCurrentNode->findChild(payload);
+            if(!pChild)
+            {
+                pChild = new Node<NodeData>(payload);
+                pTLS->pCurrentNode->addChild(pChild);
+            }
+        }
+        else
+        {
+            pChild = pTLS->pCurrentNode->findChild(payload);
+            if(!pChild)
+            {
+                m_disabled = true;
+                return;
+            }
+        }
+        pTLS->pCurrentNode = pChild;
+
+        m_regionTicks = getTickCount();
+    }
+}
+
+IntrumentationRegion::~IntrumentationRegion()
+{
+    InstrStruct *pStruct = &getInstrumentStruct();
+    if(pStruct->useInstr)
+    {
+        if(!m_disabled)
+        {
+            InstrTLSStruct *pTLS = &getInstrumentTLSStruct();
+
+            if (pTLS->pCurrentNode->m_payload.m_implType == cv::instr::IMPL_OPENCL &&
+                (pTLS->pCurrentNode->m_payload.m_instrType == cv::instr::TYPE_FUN ||
+                    pTLS->pCurrentNode->m_payload.m_instrType == cv::instr::TYPE_WRAPPER))
+            {
+                cv::ocl::finish(); // TODO Support "async" OpenCL instrumentation
+            }
+
+            uint64 ticks = (getTickCount() - m_regionTicks);
+            {
+                cv::AutoLock guard(pStruct->mutexCount); // Concurrent ticks accumulation
+                pTLS->pCurrentNode->m_payload.m_counter++;
+                pTLS->pCurrentNode->m_payload.m_ticksTotal += ticks;
+                pTLS->pCurrentNode->m_payload.m_tls.get()->m_ticksTotal += ticks;
+            }
+
+            pTLS->pCurrentNode = pTLS->pCurrentNode->m_pParent;
+        }
+    }
+}
+#endif
+}
+
 namespace ipp
 {
 
-struct IPPInitSingelton
+struct IPPInitSingleton
 {
 public:
-    IPPInitSingelton()
+    IPPInitSingleton()
     {
         useIPP      = true;
         ippStatus   = 0;
@@ -1346,15 +1566,15 @@ public:
     int         ippFeatures;
 };
 
-static IPPInitSingelton& getIPPSingelton()
+static IPPInitSingleton& getIPPSingleton()
 {
-    CV_SINGLETON_LAZY_INIT_REF(IPPInitSingelton, new IPPInitSingelton())
+    CV_SINGLETON_LAZY_INIT_REF(IPPInitSingleton, new IPPInitSingleton())
 }
 
 int getIppFeatures()
 {
 #ifdef HAVE_IPP
-    return getIPPSingelton().ippFeatures;
+    return getIPPSingleton().ippFeatures;
 #else
     return 0;
 #endif
@@ -1362,20 +1582,20 @@ int getIppFeatures()
 
 void setIppStatus(int status, const char * const _funcname, const char * const _filename, int _line)
 {
-    getIPPSingelton().ippStatus = status;
-    getIPPSingelton().funcname = _funcname;
-    getIPPSingelton().filename = _filename;
-    getIPPSingelton().linen = _line;
+    getIPPSingleton().ippStatus = status;
+    getIPPSingleton().funcname = _funcname;
+    getIPPSingleton().filename = _filename;
+    getIPPSingleton().linen = _line;
 }
 
 int getIppStatus()
 {
-    return getIPPSingelton().ippStatus;
+    return getIPPSingleton().ippStatus;
 }
 
 String getIppErrorLocation()
 {
-    return format("%s:%d %s", getIPPSingelton().filename ? getIPPSingelton().filename : "", getIPPSingelton().linen, getIPPSingelton().funcname ? getIPPSingelton().funcname : "");
+    return format("%s:%d %s", getIPPSingleton().filename ? getIPPSingleton().filename : "", getIPPSingleton().linen, getIPPSingleton().funcname ? getIPPSingleton().funcname : "");
 }
 
 bool useIPP()
@@ -1384,7 +1604,7 @@ bool useIPP()
     CoreTLSData* data = getCoreTlsData().get();
     if(data->useIPP < 0)
     {
-        data->useIPP = getIPPSingelton().useIPP;
+        data->useIPP = getIPPSingleton().useIPP;
     }
     return (data->useIPP > 0);
 #else
@@ -1396,7 +1616,7 @@ void setUseIPP(bool flag)
 {
     CoreTLSData* data = getCoreTlsData().get();
 #ifdef HAVE_IPP
-    data->useIPP = flag;
+    data->useIPP = (getIPPSingleton().useIPP)?flag:false;
 #else
     (void)flag;
     data->useIPP = false;
diff --git a/modules/core/src/types.cpp b/modules/core/src/types.cpp
index 89e0042..6cd47b6 100644
--- a/modules/core/src/types.cpp
+++ b/modules/core/src/types.cpp
@@ -63,6 +63,8 @@ size_t KeyPoint::hash() const
 void KeyPoint::convert(const std::vector<KeyPoint>& keypoints, std::vector<Point2f>& points2f,
                        const std::vector<int>& keypointIndexes)
 {
+    CV_INSTRUMENT_REGION()
+
     if( keypointIndexes.empty() )
     {
         points2f.resize( keypoints.size() );
@@ -89,6 +91,8 @@ void KeyPoint::convert(const std::vector<KeyPoint>& keypoints, std::vector<Point
 void KeyPoint::convert( const std::vector<Point2f>& points2f, std::vector<KeyPoint>& keypoints,
                         float size, float response, int octave, int class_id )
 {
+    CV_INSTRUMENT_REGION()
+
     keypoints.resize(points2f.size());
     for( size_t i = 0; i < points2f.size(); i++ )
         keypoints[i] = KeyPoint(points2f[i], size, -1, response, octave, class_id);
diff --git a/modules/core/src/umatrix.cpp b/modules/core/src/umatrix.cpp
index 98d6b8c..5874be8 100644
--- a/modules/core/src/umatrix.cpp
+++ b/modules/core/src/umatrix.cpp
@@ -345,6 +345,14 @@ void UMat::create(int d, const int* _sizes, int _type, UMatUsageFlags _usageFlag
             return;
     }
 
+    int _sizes_backup[CV_MAX_DIM]; // #5991
+    if (_sizes == (this->size.p))
+    {
+        for(i = 0; i < d; i++ )
+            _sizes_backup[i] = _sizes[i];
+        _sizes = _sizes_backup;
+    }
+
     release();
     if( d == 0 )
         return;
@@ -378,6 +386,11 @@ void UMat::create(int d, const int* _sizes, int _type, UMatUsageFlags _usageFlag
     addref();
 }
 
+void UMat::create(const std::vector<int>& _sizes, int _type, UMatUsageFlags _usageFlags)
+{
+    create((int)_sizes.size(), _sizes.data(), _type, _usageFlags);
+}
+
 void UMat::copySize(const UMat& m)
 {
     setSize(*this, m.dims, 0, 0);
@@ -499,6 +512,31 @@ UMat::UMat(const UMat& m, const Range* ranges)
     updateContinuityFlag(*this);
 }
 
+UMat::UMat(const UMat& m, const std::vector<Range>& ranges)
+    : flags(MAGIC_VAL), dims(0), rows(0), cols(0), allocator(0), usageFlags(USAGE_DEFAULT), u(0), offset(0), size(&rows)
+{
+    int i, d = m.dims;
+
+    CV_Assert((int)ranges.size() == d);
+    for (i = 0; i < d; i++)
+    {
+        Range r = ranges[i];
+        CV_Assert(r == Range::all() || (0 <= r.start && r.start < r.end && r.end <= m.size[i]));
+    }
+    *this = m;
+    for (i = 0; i < d; i++)
+    {
+        Range r = ranges[i];
+        if (r != Range::all() && r != Range(0, size.p[i]))
+        {
+            size.p[i] = r.end - r.start;
+            offset += r.start*step.p[i];
+            flags |= SUBMATRIX_FLAG;
+        }
+    }
+    updateContinuityFlag(*this);
+}
+
 UMat UMat::diag(int d) const
 {
     CV_Assert( dims <= 2 );
@@ -765,6 +803,8 @@ void UMat::ndoffset(size_t* ofs) const
 
 void UMat::copyTo(OutputArray _dst) const
 {
+    CV_INSTRUMENT_REGION()
+
     int dtype = _dst.type();
     if( _dst.fixedType() && dtype != type() )
     {
@@ -808,6 +848,8 @@ void UMat::copyTo(OutputArray _dst) const
 
 void UMat::copyTo(OutputArray _dst, InputArray _mask) const
 {
+    CV_INSTRUMENT_REGION()
+
     if( _mask.empty() )
     {
         copyTo(_dst);
@@ -855,6 +897,8 @@ void UMat::copyTo(OutputArray _dst, InputArray _mask) const
 
 void UMat::convertTo(OutputArray _dst, int _type, double alpha, double beta) const
 {
+    CV_INSTRUMENT_REGION()
+
     bool noScale = std::fabs(alpha - 1) < DBL_EPSILON && std::fabs(beta) < DBL_EPSILON;
     int stype = type(), cn = CV_MAT_CN(stype);
 
@@ -916,6 +960,8 @@ void UMat::convertTo(OutputArray _dst, int _type, double alpha, double beta) con
 
 UMat& UMat::setTo(InputArray _value, InputArray _mask)
 {
+    CV_INSTRUMENT_REGION()
+
     bool haveMask = !_mask.empty();
 #ifdef HAVE_OPENCL
     int tp = type(), cn = CV_MAT_CN(tp), d = CV_MAT_DEPTH(tp);
@@ -1054,6 +1100,8 @@ static bool ocl_dot( InputArray _src1, InputArray _src2, double & res )
 
 double UMat::dot(InputArray m) const
 {
+    CV_INSTRUMENT_REGION()
+
     CV_Assert(m.sameSize(*this) && m.type() == type());
 
 #ifdef HAVE_OPENCL
diff --git a/modules/core/test/ocl/test_arithm.cpp b/modules/core/test/ocl/test_arithm.cpp
index f1efe9b..435cbf6 100644
--- a/modules/core/test/ocl/test_arithm.cpp
+++ b/modules/core/test/ocl/test_arithm.cpp
@@ -134,7 +134,7 @@ PARAM_TEST_CASE(ArithmTestBase, MatDepth, Channels, bool)
         use_roi = GET_PARAM(2);
     }
 
-    virtual void generateTestData(bool with_val_in_range = false)
+    void generateTestData(bool with_val_in_range = false)
     {
         const int type = CV_MAKE_TYPE(depth, cn);
 
@@ -897,7 +897,7 @@ struct RepeatTestCase :
 {
     int nx, ny;
 
-    virtual void generateTestData()
+    void generateTestData()
     {
         const int type = CV_MAKE_TYPE(depth, cn);
 
@@ -1495,7 +1495,7 @@ PARAM_TEST_CASE(InRange, MatDepth, Channels, bool /*Scalar or not*/, bool /*Roi*
         use_roi = GET_PARAM(3);
     }
 
-    virtual void generateTestData()
+    void generateTestData()
     {
         const int type = CV_MAKE_TYPE(depth, cn);
 
@@ -1574,7 +1574,7 @@ PARAM_TEST_CASE(ConvertScaleAbs, MatDepth, Channels, bool)
         use_roi = GET_PARAM(2);
     }
 
-    virtual void generateTestData()
+    void generateTestData()
     {
         const int stype = CV_MAKE_TYPE(depth, cn);
         const int dtype = CV_MAKE_TYPE(CV_8U, cn);
@@ -1647,7 +1647,7 @@ PARAM_TEST_CASE(PatchNaNs, Channels, bool)
         use_roi = GET_PARAM(1);
     }
 
-    virtual void generateTestData()
+    void generateTestData()
     {
         const int type = CV_MAKE_TYPE(CV_32F, cn);
 
@@ -1727,7 +1727,7 @@ PARAM_TEST_CASE(Reduce, std::pair<MatDepth, MatDepth>, Channels, int, bool)
         use_roi = GET_PARAM(3);
     }
 
-    virtual void generateTestData()
+    void generateTestData()
     {
         const int stype = CV_MAKE_TYPE(sdepth, cn);
         dtype = CV_MAKE_TYPE(ddepth, cn);
@@ -1885,6 +1885,22 @@ OCL_INSTANTIATE_TEST_CASE_P(Arithm, ReduceMin, Combine(testing::Values(std::make
                                                        OCL_ALL_CHANNELS, testing::Values(0, 1), Bool()));
 
 
+// T-API BUG (haveOpenCL() is false): modules/core/src/matrix.cpp:212: error: (-215) u->refcount == 0 in function deallocate
+OCL_TEST(Normalize, DISABLED_regression_5876_inplace_change_type)
+{
+    double initial_values[] = {1, 2, 5, 4, 3};
+    float result_values[] = {0, 0.25, 1, 0.75, 0.5};
+    Mat m(Size(5, 1), CV_64FC1, initial_values);
+    Mat result(Size(5, 1), CV_32FC1, result_values);
+
+    UMat um; m.copyTo(um);
+    UMat uresult; result.copyTo(uresult);
+
+    OCL_ON(normalize(um, um, 1, 0, NORM_MINMAX, CV_32F));
+
+    EXPECT_EQ(0, cvtest::norm(um, uresult, NORM_INF));
+}
+
 } } // namespace cvtest::ocl
 
 #endif // HAVE_OPENCL
diff --git a/modules/core/test/ocl/test_matrix_operation.cpp b/modules/core/test/ocl/test_matrix_operation.cpp
index c32aa5a..0a0c628 100644
--- a/modules/core/test/ocl/test_matrix_operation.cpp
+++ b/modules/core/test/ocl/test_matrix_operation.cpp
@@ -71,7 +71,7 @@ PARAM_TEST_CASE(ConvertTo, MatDepth, MatDepth, Channels, bool)
         use_roi = GET_PARAM(3);
     }
 
-    virtual void generateTestData()
+    void generateTestData()
     {
         Size roiSize = randomSize(1, MAX_VALUE);
         Border srcBorder = randomBorder(0, use_roi ? MAX_VALUE : 0);
diff --git a/modules/core/test/test_arithm.cpp b/modules/core/test/test_arithm.cpp
index 0471ffc..a23cee9 100644
--- a/modules/core/test/test_arithm.cpp
+++ b/modules/core/test/test_arithm.cpp
@@ -1,4 +1,5 @@
 #include "test_precomp.hpp"
+#include <cmath>
 
 using namespace cv;
 using namespace std;
@@ -737,6 +738,62 @@ struct ConvertScaleOp : public BaseElemWiseOp
     int ddepth;
 };
 
+struct ConvertScaleFp16Op : public BaseElemWiseOp
+{
+    ConvertScaleFp16Op() : BaseElemWiseOp(1, FIX_BETA+REAL_GAMMA, 1, 1, Scalar::all(0)), nextRange(0) { }
+    void op(const vector<Mat>& src, Mat& dst, const Mat&)
+    {
+        Mat m;
+        convertFp16(src[0], m);
+        convertFp16(m, dst);
+    }
+    void refop(const vector<Mat>& src, Mat& dst, const Mat&)
+    {
+        cvtest::copy(src[0], dst);
+    }
+    int getRandomType(RNG&)
+    {
+        // 0: FP32 -> FP16 -> FP32
+        // 1: FP16 -> FP32 -> FP16
+        int srctype = (nextRange & 1) == 0 ? CV_32F : CV_16S;
+        return srctype;
+    }
+    void getValueRange(int, double& minval, double& maxval)
+    {
+        // 0: FP32 -> FP16 -> FP32
+        // 1: FP16 -> FP32 -> FP16
+        if( (nextRange & 1) == 0 )
+        {
+            // largest integer number that fp16 can express exactly
+            maxval = 2048.f;
+            minval = -maxval;
+        }
+        else
+        {
+            // 0: positive number range
+            // 1: negative number range
+            if( (nextRange & 2) == 0 )
+            {
+                minval = 0;      // 0x0000 +0
+                maxval = 31744;  // 0x7C00 +Inf
+            }
+            else
+            {
+                minval = -32768; // 0x8000 -0
+                maxval = -1024;  // 0xFC00 -Inf
+            }
+        }
+    }
+    double getMaxErr(int)
+    {
+        return 0.5f;
+    }
+    void generateScalars(int, RNG& rng)
+    {
+        nextRange = rng.next();
+    }
+    int nextRange;
+};
 
 struct ConvertScaleAbsOp : public BaseElemWiseOp
 {
@@ -1371,6 +1428,7 @@ INSTANTIATE_TEST_CASE_P(Core_Copy, ElemWiseTest, ::testing::Values(ElemWiseOpPtr
 INSTANTIATE_TEST_CASE_P(Core_Set, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::SetOp)));
 INSTANTIATE_TEST_CASE_P(Core_SetZero, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::SetZeroOp)));
 INSTANTIATE_TEST_CASE_P(Core_ConvertScale, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::ConvertScaleOp)));
+INSTANTIATE_TEST_CASE_P(Core_ConvertScaleFp16, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::ConvertScaleFp16Op)));
 INSTANTIATE_TEST_CASE_P(Core_ConvertScaleAbs, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::ConvertScaleAbsOp)));
 
 INSTANTIATE_TEST_CASE_P(Core_Add, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::AddOp)));
@@ -1423,35 +1481,26 @@ INSTANTIATE_TEST_CASE_P(Core_MinMaxLoc, ElemWiseTest, ::testing::Values(ElemWise
 INSTANTIATE_TEST_CASE_P(Core_CartToPolarToCart, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::CartToPolarToCartOp)));
 
 
-class CV_ArithmMaskTest : public cvtest::BaseTest
+TEST(Core_ArithmMask, uninitialized)
 {
-public:
-    CV_ArithmMaskTest() {}
-    ~CV_ArithmMaskTest() {}
-protected:
-    void run(int)
-    {
-        try
-        {
             RNG& rng = theRNG();
             const int MAX_DIM=3;
             int sizes[MAX_DIM];
             for( int iter = 0; iter < 100; iter++ )
             {
-                //ts->printf(cvtest::TS::LOG, ".");
-
-                ts->update_context(this, iter, true);
-                int k, dims = rng.uniform(1, MAX_DIM+1), p = 1;
+                int dims = rng.uniform(1, MAX_DIM+1);
                 int depth = rng.uniform(CV_8U, CV_64F+1);
                 int cn = rng.uniform(1, 6);
                 int type = CV_MAKETYPE(depth, cn);
-                int op = rng.uniform(0, 5);
+                int op = rng.uniform(0, depth < CV_32F ? 5 : 2); // don't run binary operations between floating-point values
                 int depth1 = op <= 1 ? CV_64F : depth;
-                for( k = 0; k < dims; k++ )
+                for (int k = 0; k < MAX_DIM; k++)
                 {
-                    sizes[k] = rng.uniform(1, 30);
-                    p *= sizes[k];
+                    sizes[k] = k < dims ? rng.uniform(1, 30) : 0;
                 }
+                SCOPED_TRACE(cv::format("iter=%d dims=%d depth=%d cn=%d type=%d op=%d depth1=%d dims=[%d; %d; %d]",
+                                         iter,   dims,   depth,   cn,   type,   op,   depth1, sizes[0], sizes[1], sizes[2]));
+
                 Mat a(dims, sizes, type), a1;
                 Mat b(dims, sizes, type), b1;
                 Mat mask(dims, sizes, CV_8U);
@@ -1500,7 +1549,7 @@ protected:
                 }
                 Mat d1;
                 d.convertTo(d1, depth);
-                CV_Assert( cvtest::norm(c, d1, CV_C) <= DBL_EPSILON );
+                EXPECT_LE(cvtest::norm(c, d1, CV_C), DBL_EPSILON);
             }
 
             Mat_<uchar> tmpSrc(100,100);
@@ -1510,15 +1559,7 @@ protected:
             Mat_<uchar> tmpDst(100,100);
             tmpDst = 2;
             tmpSrc.copyTo(tmpDst,tmpMask);
-        }
-        catch(...)
-        {
-           ts->set_failed_test_info(cvtest::TS::FAIL_MISMATCH);
-        }
-    }
-};
-
-TEST(Core_ArithmMask, uninitialized) { CV_ArithmMaskTest test; test.safe_run(); }
+}
 
 TEST(Multiply, FloatingPointRounding)
 {
@@ -1833,3 +1874,41 @@ TEST(MinMaxLoc, Mat_IntMax_Without_Mask)
     ASSERT_EQ(Point(0, 0), minLoc);
     ASSERT_EQ(Point(0, 0), maxLoc);
 }
+
+TEST(Normalize, regression_5876_inplace_change_type)
+{
+    double initial_values[] = {1, 2, 5, 4, 3};
+    float result_values[] = {0, 0.25, 1, 0.75, 0.5};
+    Mat m(Size(5, 1), CV_64FC1, initial_values);
+    Mat result(Size(5, 1), CV_32FC1, result_values);
+
+    normalize(m, m, 1, 0, NORM_MINMAX, CV_32F);
+    EXPECT_EQ(0, cvtest::norm(m, result, NORM_INF));
+}
+
+TEST(MinMaxLoc, regression_4955_nans)
+{
+    cv::Mat one_mat(2, 2, CV_32F, cv::Scalar(1));
+    cv::minMaxLoc(one_mat, NULL, NULL, NULL, NULL);
+
+    cv::Mat nan_mat(2, 2, CV_32F, cv::Scalar(std::numeric_limits<float>::quiet_NaN()));
+    cv::minMaxLoc(nan_mat, NULL, NULL, NULL, NULL);
+}
+
+TEST(Subtract, scalarc1_matc3)
+{
+    int scalar = 255;
+    cv::Mat srcImage(5, 5, CV_8UC3, cv::Scalar::all(5)), destImage;
+    cv::subtract(scalar, srcImage, destImage);
+
+    ASSERT_EQ(0, cv::norm(cv::Mat(5, 5, CV_8UC3, cv::Scalar::all(250)), destImage, cv::NORM_INF));
+}
+
+TEST(Subtract, scalarc4_matc4)
+{
+    cv::Scalar sc(255, 255, 255, 255);
+    cv::Mat srcImage(5, 5, CV_8UC4, cv::Scalar::all(5)), destImage;
+    cv::subtract(sc, srcImage, destImage);
+
+    ASSERT_EQ(0, cv::norm(cv::Mat(5, 5, CV_8UC4, cv::Scalar::all(250)), destImage, cv::NORM_INF));
+}
diff --git a/modules/core/test/test_ds.cpp b/modules/core/test/test_ds.cpp
index def3fe2..b97b9d8 100644
--- a/modules/core/test/test_ds.cpp
+++ b/modules/core/test/test_ds.cpp
@@ -56,7 +56,7 @@ static void cvTsSimpleSeqShiftAndCopy( CvTsSimpleSeq* seq, int from_idx, int to_
                 (seq->count - from_idx)*elem_size );
     }
     seq->count += to_idx - from_idx;
-    if( elem && to_idx > from_idx )
+    if( elem )
         memcpy( seq->array + from_idx*elem_size, elem, (to_idx - from_idx)*elem_size );
 }
 
diff --git a/modules/core/test/test_dxt.cpp b/modules/core/test/test_dxt.cpp
index ad75e52..98ab8c2 100644
--- a/modules/core/test/test_dxt.cpp
+++ b/modules/core/test/test_dxt.cpp
@@ -419,9 +419,6 @@ static void fixCCS( Mat& mat, int cols, int flags )
     }
 }
 
-#if defined _MSC_VER &&  _MSC_VER >= 1700
-#pragma optimize("", off)
-#endif
 static void mulComplex( const Mat& src1, const Mat& src2, Mat& dst, int flags )
 {
     dst.create(src1.rows, src1.cols, src1.type());
@@ -430,12 +427,27 @@ static void mulComplex( const Mat& src1, const Mat& src2, Mat& dst, int flags )
     CV_Assert( src1.size == src2.size && src1.type() == src2.type() &&
               (src1.type() == CV_32FC2 || src1.type() == CV_64FC2) );
 
+    const Mat* src1_ = &src1;
+    Mat src1_tmp;
+    if (dst.data == src1.data)
+    {
+        src1_tmp = src1.clone();
+        src1_ = &src1_tmp;
+    }
+    const Mat* src2_ = &src2;
+    Mat src2_tmp;
+    if (dst.data == src2.data)
+    {
+        src2_tmp = src2.clone();
+        src2_ = &src2_tmp;
+    }
+
     for( i = 0; i < dst.rows; i++ )
     {
         if( depth == CV_32F )
         {
-            const float* a = src1.ptr<float>(i);
-            const float* b = src2.ptr<float>(i);
+            const float* a = src1_->ptr<float>(i);
+            const float* b = src2_->ptr<float>(i);
             float* c = dst.ptr<float>(i);
 
             if( !(flags & CV_DXT_MUL_CONJ) )
@@ -459,8 +471,8 @@ static void mulComplex( const Mat& src1, const Mat& src2, Mat& dst, int flags )
         }
         else
         {
-            const double* a = src1.ptr<double>(i);
-            const double* b = src2.ptr<double>(i);
+            const double* a = src1_->ptr<double>(i);
+            const double* b = src2_->ptr<double>(i);
             double* c = dst.ptr<double>(i);
 
             if( !(flags & CV_DXT_MUL_CONJ) )
@@ -484,9 +496,6 @@ static void mulComplex( const Mat& src1, const Mat& src2, Mat& dst, int flags )
         }
     }
 }
-#if defined _MSC_VER &&  _MSC_VER >= 1700
-#pragma optimize("", on)
-#endif
 
 }
 
@@ -778,6 +787,7 @@ public:
 protected:
     void run_func();
     void prepare_to_validation( int test_case_idx );
+    double get_success_error_level( int test_case_idx, int i, int j );
 };
 
 
@@ -785,6 +795,19 @@ CxCore_MulSpectrumsTest::CxCore_MulSpectrumsTest() : CxCore_DXTBaseTest( true, t
 {
 }
 
+double CxCore_MulSpectrumsTest::get_success_error_level( int test_case_idx, int i, int j )
+{
+    (void)test_case_idx;
+    CV_Assert(i == OUTPUT);
+    CV_Assert(j == 0);
+    int elem_depth = CV_MAT_DEPTH(cvGetElemType(test_array[i][j]));
+    CV_Assert(elem_depth == CV_32F || elem_depth == CV_64F);
+
+    element_wise_relative_error = false;
+    double maxInputValue = 1000; // ArrayTest::get_minmax_bounds
+    double err = 8 * maxInputValue;  // result = A*B + C*D
+    return (elem_depth == CV_32F ? FLT_EPSILON : DBL_EPSILON) * err;
+}
 
 void CxCore_MulSpectrumsTest::run_func()
 {
@@ -887,3 +910,79 @@ TEST(Core_DFT, complex_output2)
         }
     }
 }
+
+class Core_DXTReverseTest : public cvtest::BaseTest
+{
+public:
+    enum Mode
+    {
+        ModeDFT,
+        ModeDCT
+    };
+    Core_DXTReverseTest(Mode m) : mode(m) {}
+private:
+    Mode mode;
+protected:
+    void run(int)
+    {
+        for (int i = 0; i < 3; ++i)
+        {
+            if (mode == ModeDCT && i != 0)
+                continue;
+            int flags = 0;
+            int flags_inv = DFT_INVERSE | DFT_SCALE;
+            int cn_in = 0;
+            int cn_out = 0;
+            switch (i)
+            {
+                case 0: cn_in = 1; cn_out = 1; break;
+                case 1: cn_in = 1; cn_out = 2; flags |= DFT_COMPLEX_OUTPUT; flags_inv |= DFT_REAL_OUTPUT; break;
+                case 2: cn_in = 2; cn_out = 2; break;
+            };
+            for (int j = 0; j < 100; ++j)
+            {
+                RNG& rng = ts->get_rng();
+                int type = rng.uniform(0, 2) ? CV_64F : CV_32F;
+                int m = rng.uniform(1, 10);
+                int n = rng.uniform(1, 10);
+                if (mode == ModeDCT)
+                {
+                    m *= 2;
+                    n *= 2;
+                }
+                Mat one(m, n, CV_MAKETYPE(type, cn_in));
+                cvtest::randUni(rng, one, Scalar::all(-1.), Scalar::all(1.));
+                Mat out;
+                Mat two;
+                if (mode == ModeDFT)
+                {
+                    cv::dft(one, out, flags);
+                    cv::dft(out, two, flags_inv);
+                }
+                else if (mode == ModeDCT)
+                {
+                    cv::dct(one, out, flags);
+                    cv::dct(out, two, flags_inv);
+                }
+                if (out.channels() != cn_out || two.channels() != cn_in || cvtest::norm(one, two, NORM_INF) > 1e-5)
+                {
+                    cout << "Test #" << j + 1 << " - "
+                        << "elements: " << m << " x " << n << ", "
+                        << "channels: "
+                        << one.channels() << " (" << cn_in << ")" << " -> "
+                        << out.channels() << " (" << cn_out << ")" << " -> "
+                        << two.channels() << " (" << cn_in << ")"
+                        << endl;
+                    cout << "signal:\n" << one << endl << endl;
+                    cout << "spectrum:\n" << out << endl << endl;
+                    cout << "inverse:\n" << two << endl << endl;
+                    ts->set_failed_test_info(cvtest::TS::FAIL_INVALID_OUTPUT);
+                    break;
+                }
+            }
+        }
+    }
+};
+
+TEST(Core_DFT, reverse) { Core_DXTReverseTest test(Core_DXTReverseTest::ModeDFT); test.safe_run(); }
+TEST(Core_DCT, reverse) { Core_DXTReverseTest test(Core_DXTReverseTest::ModeDCT); test.safe_run(); }
diff --git a/modules/core/test/test_eigen.cpp b/modules/core/test/test_eigen.cpp
index 7a11925..6a9e99e 100644
--- a/modules/core/test/test_eigen.cpp
+++ b/modules/core/test/test_eigen.cpp
@@ -56,7 +56,7 @@ using namespace std;
 
 #define MESSAGE_ERROR_COUNT "Matrix of eigen values must have the same rows as source matrix and 1 column."
 #define MESSAGE_ERROR_SIZE "Source matrix and matrix of eigen vectors must have the same sizes."
-#define MESSAGE_ERROR_DIFF_1 "Accurasy of eigen values computing less than required."
+#define MESSAGE_ERROR_DIFF_1 "Accuracy of eigen values computing less than required."
 #define MESSAGE_ERROR_DIFF_2 "Accuracy of eigen vectors computing less than required."
 #define MESSAGE_ERROR_ORTHO "Matrix of eigen vectors is not orthogonal."
 #define MESSAGE_ERROR_ORDER "Eigen values are not sorted in ascending order."
diff --git a/modules/core/test/test_hal_core.cpp b/modules/core/test/test_hal_core.cpp
index dfd0867..ab85659 100644
--- a/modules/core/test/test_hal_core.cpp
+++ b/modules/core/test/test_hal_core.cpp
@@ -120,15 +120,20 @@ TEST(Core_HAL, mathfuncs)
     }
 }
 
+namespace {
+
 enum
 {
     HAL_LU = 0,
     HAL_CHOL = 1
 };
 
-TEST(Core_HAL, mat_decomp)
+typedef testing::TestWithParam<int> HAL;
+
+TEST_P(HAL, mat_decomp)
 {
-    for( int hcase = 0; hcase < 16; hcase++ )
+    int hcase = GetParam();
+    SCOPED_TRACE(cv::format("hcase=%d", hcase));
     {
         int depth = hcase % 2 == 0 ? CV_32F : CV_64F;
         int size = (hcase / 2) % 4;
@@ -137,7 +142,7 @@ TEST(Core_HAL, mat_decomp)
         double eps = depth == CV_32F ? 1e-5 : 1e-10;
 
         if( size == 3 )
-            continue;
+            return; // TODO ???
 
         Mat a0(size, size, depth), a(size, size, depth), b(size, 1, depth), x(size, 1, depth), x0(size, 1, depth);
         randu(a0, -1, 1);
@@ -175,14 +180,19 @@ TEST(Core_HAL, mat_decomp)
             min_hal_t = std::min(min_hal_t, t);
 
             t = (double)getTickCount();
-            solve(a0, b, x0, (nfunc == HAL_LU ? DECOMP_LU : DECOMP_CHOLESKY));
+            bool solveStatus = solve(a0, b, x0, (nfunc == HAL_LU ? DECOMP_LU : DECOMP_CHOLESKY));
             t = (double)getTickCount() - t;
+            EXPECT_TRUE(solveStatus);
             min_ocv_t = std::min(min_ocv_t, t);
         }
         //std::cout << "x: " << Mat(x.t()) << std::endl;
         //std::cout << "x0: " << Mat(x0.t()) << std::endl;
 
-        EXPECT_LE(norm(x, x0, NORM_INF | NORM_RELATIVE), eps);
+        EXPECT_LE(norm(x, x0, NORM_INF | NORM_RELATIVE), eps)
+            << "x:  " << Mat(x.t())
+            << "\nx0: " << Mat(x0.t())
+            << "\na0: " << a0
+            << "\nb: " << b;
 
         double freq = getTickFrequency();
         printf("%s (%d x %d, %s): hal time=%.2fusec, ocv time=%.2fusec\n",
@@ -192,3 +202,7 @@ TEST(Core_HAL, mat_decomp)
                min_hal_t*1e6/freq, min_ocv_t*1e6/freq);
     }
 }
+
+INSTANTIATE_TEST_CASE_P(Core, HAL, testing::Range(0, 16));
+
+} // namespace
diff --git a/modules/core/test/test_intrin.cpp b/modules/core/test/test_intrin.cpp
index 681fe3f..66b2083 100644
--- a/modules/core/test/test_intrin.cpp
+++ b/modules/core/test/test_intrin.cpp
@@ -1,12 +1,32 @@
+#include "test_precomp.hpp"
 #include "test_intrin_utils.hpp"
 #include <climits>
 
 using namespace cv;
 
+namespace cvtest { namespace hal {
+
+template<typename T> static inline void EXPECT_COMPARE_EQ_(const T a, const T b);
+template<> inline void EXPECT_COMPARE_EQ_<float>(const float a, const float b)
+{
+    EXPECT_FLOAT_EQ( a, b );
+}
+
+template<> inline void EXPECT_COMPARE_EQ_<double>(const double a, const double b)
+{
+    EXPECT_DOUBLE_EQ( a, b );
+}
+
 template<typename R> struct TheTest
 {
     typedef typename R::lane_type LaneType;
 
+    template <typename T1, typename T2>
+    static inline void EXPECT_COMPARE_EQ(const T1 a, const T2 b)
+    {
+        EXPECT_COMPARE_EQ_<LaneType>((LaneType)a, (LaneType)b);
+    }
+
     TheTest & test_loadstore()
     {
         AlignedData<R> data;
@@ -50,8 +70,8 @@ template<typename R> struct TheTest
         EXPECT_EQ(d, res);
 
         // zero, all
-        Data<R> resZ = RegTrait<R>::zero();
-        Data<R> resV = RegTrait<R>::all(8);
+        Data<R> resZ = V_RegTrait128<LaneType>::zero();
+        Data<R> resV = V_RegTrait128<LaneType>::all(8);
         for (int i = 0; i < R::nlanes; ++i)
         {
             EXPECT_EQ((LaneType)0, resZ[i]);
@@ -113,10 +133,36 @@ template<typename R> struct TheTest
         return *this;
     }
 
+    // float32x4 only
+    TheTest & test_interleave_2channel()
+    {
+        Data<R> data1, data2;
+        data2 += 20;
+
+        R a = data1, b = data2;
+
+        LaneType buf2[R::nlanes * 2];
+
+        v_store_interleave(buf2, a, b);
+
+        Data<R> z(0);
+        a = b = z;
+
+        v_load_deinterleave(buf2, a, b);
+
+        for (int i = 0; i < R::nlanes; ++i)
+        {
+            EXPECT_EQ(data1, Data<R>(a));
+            EXPECT_EQ(data2, Data<R>(b));
+        }
+
+        return *this;
+    }
+
     // v_expand and v_load_expand
     TheTest & test_expand()
     {
-        typedef typename RegTrait<R>::w_reg Rx2;
+        typedef typename V_RegTrait128<LaneType>::w_reg Rx2;
         Data<R> dataA;
         R a = dataA;
 
@@ -139,7 +185,7 @@ template<typename R> struct TheTest
 
     TheTest & test_expand_q()
     {
-        typedef typename RegTrait<R>::q_reg Rx4;
+        typedef typename V_RegTrait128<LaneType>::q_reg Rx4;
         Data<R> data;
         Data<Rx4> out = v_load_expand_q(data.d);
         const int n = Rx4::nlanes;
@@ -213,7 +259,7 @@ template<typename R> struct TheTest
 
     TheTest & test_mul_expand()
     {
-        typedef typename RegTrait<R>::w_reg Rx2;
+        typedef typename V_RegTrait128<LaneType>::w_reg Rx2;
         Data<R> dataA, dataB(2);
         R a = dataA, b = dataB;
         Rx2 c, d;
@@ -231,6 +277,24 @@ template<typename R> struct TheTest
         return *this;
     }
 
+    TheTest & test_abs()
+    {
+        typedef typename V_RegTrait128<LaneType>::u_reg Ru;
+        typedef typename Ru::lane_type u_type;
+        Data<R> dataA, dataB(10);
+        R a = dataA, b = dataB;
+        a = a - b;
+
+        Data<Ru> resC = v_abs(a);
+
+        for (int i = 0; i < Ru::nlanes; ++i)
+        {
+            EXPECT_EQ((u_type)std::abs(dataA[i] - dataB[i]), resC[i]);
+        }
+
+        return *this;
+    }
+
     template <int s>
     TheTest & test_shift()
     {
@@ -276,7 +340,7 @@ template<typename R> struct TheTest
 
     TheTest & test_dot_prod()
     {
-        typedef typename RegTrait<R>::w_reg Rx2;
+        typedef typename V_RegTrait128<LaneType>::w_reg Rx2;
         Data<R> dataA, dataB(2);
         R a = dataA, b = dataB;
 
@@ -316,9 +380,9 @@ template<typename R> struct TheTest
         Data<R> resB = v_sqrt(a), resC = v_invsqrt(a), resE = v_abs(d);
         for (int i = 0; i < R::nlanes; ++i)
         {
-            EXPECT_FLOAT_EQ((float)std::sqrt(dataA[i]), (float)resB[i]);
-            EXPECT_FLOAT_EQ(1/(float)std::sqrt(dataA[i]), (float)resC[i]);
-            EXPECT_FLOAT_EQ((float)abs(dataA[i]), (float)resE[i]);
+            EXPECT_COMPARE_EQ((float)std::sqrt(dataA[i]), (float)resB[i]);
+            EXPECT_COMPARE_EQ(1/(float)std::sqrt(dataA[i]), (float)resC[i]);
+            EXPECT_COMPARE_EQ((float)abs(dataA[i]), (float)resE[i]);
         }
 
         return *this;
@@ -342,7 +406,7 @@ template<typename R> struct TheTest
 
     TheTest & test_absdiff()
     {
-        typedef typename RegTrait<R>::u_reg Ru;
+        typedef typename V_RegTrait128<LaneType>::u_reg Ru;
         typedef typename Ru::lane_type u_type;
         Data<R> dataA(std::numeric_limits<LaneType>::max()),
                 dataB(std::numeric_limits<LaneType>::min());
@@ -385,7 +449,7 @@ template<typename R> struct TheTest
         R a = dataA;
         EXPECT_EQ((LaneType)1, v_reduce_min(a));
         EXPECT_EQ((LaneType)R::nlanes, v_reduce_max(a));
-        EXPECT_EQ((LaneType)(1 + R::nlanes)*2, v_reduce_sum(a));
+        EXPECT_EQ((LaneType)((1 + R::nlanes)*R::nlanes/2), v_reduce_sum(a));
         return *this;
     }
 
@@ -426,7 +490,7 @@ template<typename R> struct TheTest
     template <int s>
     TheTest & test_pack()
     {
-        typedef typename RegTrait<R>::w_reg Rx2;
+        typedef typename V_RegTrait128<LaneType>::w_reg Rx2;
         typedef typename Rx2::lane_type w_type;
         Data<Rx2> dataA, dataB;
         dataA += std::numeric_limits<LaneType>::is_signed ? -10 : 10;
@@ -461,8 +525,8 @@ template<typename R> struct TheTest
     template <int s>
     TheTest & test_pack_u()
     {
-        typedef typename RegTrait<R>::w_reg Rx2;
-        typedef typename RegTrait<Rx2>::int_reg Ri2;
+        typedef typename V_TypeTraits<LaneType>::w_type LaneType_w;
+        typedef typename V_RegTrait128<LaneType_w>::int_reg Ri2;
         typedef typename Ri2::lane_type w_type;
 
         Data<Ri2> dataA, dataB;
@@ -553,7 +617,7 @@ template<typename R> struct TheTest
 
     TheTest & test_float_math()
     {
-        typedef typename RegTrait<R>::int_reg Ri;
+        typedef typename V_RegTrait128<LaneType>::int_reg Ri;
         Data<R> data1, data2, data3;
         data1 *= 1.1;
         data2 += 10;
@@ -575,9 +639,9 @@ template<typename R> struct TheTest
             EXPECT_EQ(cvFloor(data1[i]), resD[i]);
             EXPECT_EQ(cvCeil(data1[i]), resE[i]);
 
-            EXPECT_DOUBLE_EQ(std::sqrt(data1[i]*data1[i] + data2[i]*data2[i]), resF[i]);
-            EXPECT_DOUBLE_EQ(data1[i]*data1[i] + data2[i]*data2[i], resG[i]);
-            EXPECT_DOUBLE_EQ(data1[i]*data2[i] + data3[i], resH[i]);
+            EXPECT_COMPARE_EQ(std::sqrt(data1[i]*data1[i] + data2[i]*data2[i]), resF[i]);
+            EXPECT_COMPARE_EQ(data1[i]*data1[i] + data2[i]*data2[i], resG[i]);
+            EXPECT_COMPARE_EQ(data1[i]*data2[i] + data3[i], resH[i]);
         }
 
         return *this;
@@ -607,12 +671,18 @@ template<typename R> struct TheTest
         dataA *= 1.1;
         R a = dataA;
         Rt b = v_cvt_f64(a);
+        Rt c = v_cvt_f64_high(a);
         Data<Rt> resB = b;
+        Data<Rt> resC = c;
         int n = std::min<int>(Rt::nlanes, R::nlanes);
         for (int i = 0; i < n; ++i)
         {
             EXPECT_EQ((typename Rt::lane_type)dataA[i], resB[i]);
         }
+        for (int i = 0; i < n; ++i)
+        {
+            EXPECT_EQ((typename Rt::lane_type)dataA[i+n], resC[i]);
+        }
 #endif
         return *this;
     }
@@ -659,6 +729,57 @@ template<typename R> struct TheTest
         return *this;
     }
 
+    TheTest & test_loadstore_fp16()
+    {
+#if CV_FP16
+        AlignedData<R> data;
+        AlignedData<R> out;
+
+        if(checkHardwareSupport(CV_CPU_FP16))
+        {
+            // check if addresses are aligned and unaligned respectively
+            EXPECT_EQ((size_t)0, (size_t)&data.a.d % 16);
+            EXPECT_NE((size_t)0, (size_t)&data.u.d % 16);
+            EXPECT_EQ((size_t)0, (size_t)&out.a.d % 16);
+            EXPECT_NE((size_t)0, (size_t)&out.u.d % 16);
+
+            // check some initialization methods
+            R r1 = data.u;
+            R r2 = v_load_f16(data.a.d);
+            R r3(r2);
+            EXPECT_EQ(data.u[0], r1.get0());
+            EXPECT_EQ(data.a[0], r2.get0());
+            EXPECT_EQ(data.a[0], r3.get0());
+
+            // check some store methods
+            out.a.clear();
+            v_store_f16(out.a.d, r1);
+            EXPECT_EQ(data.a, out.a);
+        }
+
+        return *this;
+#endif
+    }
+
+    TheTest & test_float_cvt_fp16()
+    {
+#if CV_FP16
+        AlignedData<v_float32x4> data;
+
+        if(checkHardwareSupport(CV_CPU_FP16))
+        {
+            // check conversion
+            v_float32x4 r1 = v_load(data.a.d);
+            v_float16x4 r2 = v_cvt_f16(r1);
+            v_float32x4 r3 = v_cvt_f32(r2);
+            EXPECT_EQ(0x3c00, r2.get0());
+            EXPECT_EQ(r3.get0(), r1.get0());
+        }
+
+        return *this;
+#endif
+    }
+
 };
 
 
@@ -696,6 +817,7 @@ TEST(hal_intrin, int8x16) {
         .test_logic()
         .test_min_max()
         .test_absdiff()
+        .test_abs()
         .test_mask()
         .test_pack<1>().test_pack<2>().test_pack<3>().test_pack<8>()
         .test_unpack()
@@ -720,6 +842,7 @@ TEST(hal_intrin, uint16x8) {
         .test_logic()
         .test_min_max()
         .test_absdiff()
+        .test_reduce()
         .test_mask()
         .test_pack<1>().test_pack<2>().test_pack<7>().test_pack<16>()
         .test_pack_u<1>().test_pack_u<2>().test_pack_u<7>().test_pack_u<16>()
@@ -744,6 +867,8 @@ TEST(hal_intrin, int16x8) {
         .test_logic()
         .test_min_max()
         .test_absdiff()
+        .test_abs()
+        .test_reduce()
         .test_mask()
         .test_pack<1>().test_pack<2>().test_pack<7>().test_pack<16>()
         .test_unpack()
@@ -783,6 +908,7 @@ TEST(hal_intrin, int32x4) {
         .test_expand()
         .test_addsub()
         .test_mul()
+        .test_abs()
         .test_cmp()
         .test_shift<1>().test_shift<8>()
         .test_logic()
@@ -827,6 +953,7 @@ TEST(hal_intrin, float32x4) {
     TheTest<v_float32x4>()
         .test_loadstore()
         .test_interleave()
+        .test_interleave_2channel()
         .test_addsub()
         .test_mul()
         .test_div()
@@ -862,3 +989,16 @@ TEST(hal_intrin, float64x2) {
         ;
 }
 #endif
+
+#if CV_FP16
+TEST(hal_intrin, float16x4) {
+    TheTest<v_float16x4>()
+        .test_loadstore_fp16()
+        .test_float_cvt_fp16()
+        ;
+}
+#endif
+
+};
+
+};
diff --git a/modules/core/test/test_intrin_utils.hpp b/modules/core/test/test_intrin_utils.hpp
index a0eab56..1f8a78d 100644
--- a/modules/core/test/test_intrin_utils.hpp
+++ b/modules/core/test/test_intrin_utils.hpp
@@ -155,80 +155,4 @@ template <typename R> std::ostream & operator<<(std::ostream & out, const Data<R
     return out;
 }
 
-//==================================================================================================
-
-template <typename R> struct RegTrait;
-
-template <> struct RegTrait<cv::v_uint8x16> {
-    typedef cv::v_uint16x8 w_reg;
-    typedef cv::v_uint32x4 q_reg;
-    typedef cv::v_uint8x16 u_reg;
-    static cv::v_uint8x16 zero() { return cv::v_setzero_u8(); }
-    static cv::v_uint8x16 all(uchar val) { return cv::v_setall_u8(val); }
-};
-template <> struct RegTrait<cv::v_int8x16> {
-    typedef cv::v_int16x8 w_reg;
-    typedef cv::v_int32x4 q_reg;
-    typedef cv::v_uint8x16 u_reg;
-    static cv::v_int8x16 zero() { return cv::v_setzero_s8(); }
-    static cv::v_int8x16 all(schar val) { return cv::v_setall_s8(val); }
-};
-
-template <> struct RegTrait<cv::v_uint16x8> {
-    typedef cv::v_uint32x4 w_reg;
-    typedef cv::v_int16x8 int_reg;
-    typedef cv::v_uint16x8 u_reg;
-    static cv::v_uint16x8 zero() { return cv::v_setzero_u16(); }
-    static cv::v_uint16x8 all(ushort val) { return cv::v_setall_u16(val); }
-};
-
-template <> struct RegTrait<cv::v_int16x8> {
-    typedef cv::v_int32x4 w_reg;
-    typedef cv::v_uint16x8 u_reg;
-    static cv::v_int16x8 zero() { return cv::v_setzero_s16(); }
-    static cv::v_int16x8 all(short val) { return cv::v_setall_s16(val); }
-};
-
-template <> struct RegTrait<cv::v_uint32x4> {
-    typedef cv::v_uint64x2 w_reg;
-    typedef cv::v_int32x4 int_reg;
-    typedef cv::v_uint32x4 u_reg;
-    static cv::v_uint32x4 zero() { return cv::v_setzero_u32(); }
-    static cv::v_uint32x4 all(unsigned val) { return cv::v_setall_u32(val); }
-};
-
-template <> struct RegTrait<cv::v_int32x4> {
-    typedef cv::v_int64x2 w_reg;
-    typedef cv::v_uint32x4 u_reg;
-    static cv::v_int32x4 zero() { return cv::v_setzero_s32(); }
-    static cv::v_int32x4 all(int val) { return cv::v_setall_s32(val); }
-};
-
-template <> struct RegTrait<cv::v_uint64x2> {
-    static cv::v_uint64x2 zero() { return cv::v_setzero_u64(); }
-    static cv::v_uint64x2 all(uint64 val) { return cv::v_setall_u64(val); }
-};
-
-template <> struct RegTrait<cv::v_int64x2> {
-    static cv::v_int64x2 zero() { return cv::v_setzero_s64(); }
-    static cv::v_int64x2 all(int64 val) { return cv::v_setall_s64(val); }
-};
-
-template <> struct RegTrait<cv::v_float32x4> {
-    typedef cv::v_int32x4 int_reg;
-    typedef cv::v_float32x4 u_reg;
-    static cv::v_float32x4 zero() { return cv::v_setzero_f32(); }
-    static cv::v_float32x4 all(float val) { return cv::v_setall_f32(val); }
-};
-
-#if CV_SIMD128_64F
-template <> struct RegTrait<cv::v_float64x2> {
-    typedef cv::v_int32x4 int_reg;
-    typedef cv::v_float64x2 u_reg;
-    static cv::v_float64x2 zero() { return cv::v_setzero_f64(); }
-    static cv::v_float64x2 all(double val) { return cv::v_setall_f64(val); }
-};
-
-#endif
-
 #endif
diff --git a/modules/core/test/test_io.cpp b/modules/core/test/test_io.cpp
index 0c401f8..eb02a7b 100644
--- a/modules/core/test/test_io.cpp
+++ b/modules/core/test/test_io.cpp
@@ -91,9 +91,10 @@ protected:
             {-1000000, 1000000}, {-10, 10}, {-10, 10}};
         RNG& rng = ts->get_rng();
         RNG rng0;
-        test_case_count = 4;
         int progress = 0;
         MemStorage storage(cvCreateMemStorage(0));
+        const char * suffixs[3] = {".yml", ".xml", ".json" };
+        test_case_count = 6;
 
         for( int idx = 0; idx < test_case_count; idx++ )
         {
@@ -102,8 +103,8 @@ protected:
 
             cvClearMemStorage(storage);
 
-            bool mem = (idx % 4) >= 2;
-            string filename = tempfile(idx % 2 ? ".yml" : ".xml");
+            bool mem = (idx % test_case_count) >= (test_case_count >> 1);
+            string filename = tempfile(suffixs[idx % (test_case_count >> 1)]);
 
             FileStorage fs(filename, FileStorage::WRITE + (mem ? FileStorage::MEMORY : 0));
 
@@ -430,82 +431,91 @@ public:
 protected:
     void run(int)
     {
-        try
-        {
-            string fname = cv::tempfile(".xml");
-            vector<int> mi, mi2, mi3, mi4;
-            vector<Mat> mv, mv2, mv3, mv4;
-            vector<UserDefinedType> vudt, vudt2, vudt3, vudt4;
-            Mat m(10, 9, CV_32F);
-            Mat empty;
-            UserDefinedType udt = { 8, 3.3f };
-            randu(m, 0, 1);
-            mi3.push_back(5);
-            mv3.push_back(m);
-            vudt3.push_back(udt);
-            Point_<float> p1(1.1f, 2.2f), op1;
-            Point3i p2(3, 4, 5), op2;
-            Size s1(6, 7), os1;
-            Complex<int> c1(9, 10), oc1;
-            Rect r1(11, 12, 13, 14), or1;
-            Vec<int, 5> v1(15, 16, 17, 18, 19), ov1;
-            Scalar sc1(20.0, 21.1, 22.2, 23.3), osc1;
-            Range g1(7, 8), og1;
-
-            FileStorage fs(fname, FileStorage::WRITE);
-            fs << "mi" << mi;
-            fs << "mv" << mv;
-            fs << "mi3" << mi3;
-            fs << "mv3" << mv3;
-            fs << "vudt" << vudt;
-            fs << "vudt3" << vudt3;
-            fs << "empty" << empty;
-            fs << "p1" << p1;
-            fs << "p2" << p2;
-            fs << "s1" << s1;
-            fs << "c1" << c1;
-            fs << "r1" << r1;
-            fs << "v1" << v1;
-            fs << "sc1" << sc1;
-            fs << "g1" << g1;
-            fs.release();
+        const char * suffix[3] = {
+            ".yml",
+            ".xml",
+            ".json"
+        };
 
-            fs.open(fname, FileStorage::READ);
-            fs["mi"] >> mi2;
-            fs["mv"] >> mv2;
-            fs["mi3"] >> mi4;
-            fs["mv3"] >> mv4;
-            fs["vudt"] >> vudt2;
-            fs["vudt3"] >> vudt4;
-            fs["empty"] >> empty;
-            fs["p1"] >> op1;
-            fs["p2"] >> op2;
-            fs["s1"] >> os1;
-            fs["c1"] >> oc1;
-            fs["r1"] >> or1;
-            fs["v1"] >> ov1;
-            fs["sc1"] >> osc1;
-            fs["g1"] >> og1;
-            CV_Assert( mi2.empty() );
-            CV_Assert( mv2.empty() );
-            CV_Assert( cvtest::norm(Mat(mi3), Mat(mi4), CV_C) == 0 );
-            CV_Assert( mv4.size() == 1 );
-            double n = cvtest::norm(mv3[0], mv4[0], CV_C);
-            CV_Assert( vudt2.empty() );
-            CV_Assert( vudt3 == vudt4 );
-            CV_Assert( n == 0 );
-            CV_Assert( op1 == p1 );
-            CV_Assert( op2 == p2 );
-            CV_Assert( os1 == s1 );
-            CV_Assert( oc1 == c1 );
-            CV_Assert( or1 == r1 );
-            CV_Assert( ov1 == v1 );
-            CV_Assert( osc1 == sc1 );
-            CV_Assert( og1 == g1 );
-        }
-        catch(...)
+        for ( size_t i = 0u; i < 3u; i++ )
         {
-            ts->set_failed_test_info(cvtest::TS::FAIL_MISMATCH);
+            try
+            {
+                string fname = cv::tempfile(suffix[i]);
+                vector<int> mi, mi2, mi3, mi4;
+                vector<Mat> mv, mv2, mv3, mv4;
+                vector<UserDefinedType> vudt, vudt2, vudt3, vudt4;
+                Mat m(10, 9, CV_32F);
+                Mat empty;
+                UserDefinedType udt = { 8, 3.3f };
+                randu(m, 0, 1);
+                mi3.push_back(5);
+                mv3.push_back(m);
+                vudt3.push_back(udt);
+                Point_<float> p1(1.1f, 2.2f), op1;
+                Point3i p2(3, 4, 5), op2;
+                Size s1(6, 7), os1;
+                Complex<int> c1(9, 10), oc1;
+                Rect r1(11, 12, 13, 14), or1;
+                Vec<int, 5> v1(15, 16, 17, 18, 19), ov1;
+                Scalar sc1(20.0, 21.1, 22.2, 23.3), osc1;
+                Range g1(7, 8), og1;
+
+                FileStorage fs(fname, FileStorage::WRITE);
+                fs << "mi" << mi;
+                fs << "mv" << mv;
+                fs << "mi3" << mi3;
+                fs << "mv3" << mv3;
+                fs << "vudt" << vudt;
+                fs << "vudt3" << vudt3;
+                fs << "empty" << empty;
+                fs << "p1" << p1;
+                fs << "p2" << p2;
+                fs << "s1" << s1;
+                fs << "c1" << c1;
+                fs << "r1" << r1;
+                fs << "v1" << v1;
+                fs << "sc1" << sc1;
+                fs << "g1" << g1;
+                fs.release();
+
+                fs.open(fname, FileStorage::READ);
+                fs["mi"] >> mi2;
+                fs["mv"] >> mv2;
+                fs["mi3"] >> mi4;
+                fs["mv3"] >> mv4;
+                fs["vudt"] >> vudt2;
+                fs["vudt3"] >> vudt4;
+                fs["empty"] >> empty;
+                fs["p1"] >> op1;
+                fs["p2"] >> op2;
+                fs["s1"] >> os1;
+                fs["c1"] >> oc1;
+                fs["r1"] >> or1;
+                fs["v1"] >> ov1;
+                fs["sc1"] >> osc1;
+                fs["g1"] >> og1;
+                CV_Assert( mi2.empty() );
+                CV_Assert( mv2.empty() );
+                CV_Assert( cvtest::norm(Mat(mi3), Mat(mi4), CV_C) == 0 );
+                CV_Assert( mv4.size() == 1 );
+                double n = cvtest::norm(mv3[0], mv4[0], CV_C);
+                CV_Assert( vudt2.empty() );
+                CV_Assert( vudt3 == vudt4 );
+                CV_Assert( n == 0 );
+                CV_Assert( op1 == p1 );
+                CV_Assert( op2 == p2 );
+                CV_Assert( os1 == s1 );
+                CV_Assert( oc1 == c1 );
+                CV_Assert( or1 == r1 );
+                CV_Assert( ov1 == v1 );
+                CV_Assert( osc1 == sc1 );
+                CV_Assert( og1 == g1 );
+            }
+            catch(...)
+            {
+                ts->set_failed_test_info(cvtest::TS::FAIL_MISMATCH);
+            }
         }
     }
 };
@@ -566,3 +576,423 @@ TEST(Core_InputOutput, FileStorage)
     sprintf(arr, "sprintf is hell %d", 666);
     EXPECT_NO_THROW(f << arr);
 }
+
+TEST(Core_InputOutput, FileStorageKey)
+{
+    cv::FileStorage f("dummy.yml", cv::FileStorage::WRITE | cv::FileStorage::MEMORY);
+
+    EXPECT_NO_THROW(f << "key1" << "value1");
+    EXPECT_NO_THROW(f << "_key2" << "value2");
+    EXPECT_NO_THROW(f << "key_3" << "value3");
+    const std::string expected = "%YAML:1.0\n---\nkey1: value1\n_key2: value2\nkey_3: value3\n";
+    ASSERT_STREQ(f.releaseAndGetString().c_str(), expected.c_str());
+}
+
+TEST(Core_InputOutput, FileStorageSpaces)
+{
+    cv::FileStorage f("dummy.yml", cv::FileStorage::WRITE | cv::FileStorage::MEMORY);
+    const int valueCount = 5;
+    std::string values[5] = { "", " ", " ", "  a", " some string" };
+    for (size_t i = 0; i < valueCount; i++) {
+        EXPECT_NO_THROW(f << cv::format("key%d", i) << values[i]);
+    }
+    cv::FileStorage f2(f.releaseAndGetString(), cv::FileStorage::READ | cv::FileStorage::MEMORY);
+    std::string valuesRead[valueCount];
+    for (size_t i = 0; i < valueCount; i++) {
+        EXPECT_NO_THROW(f2[cv::format("key%d", i)] >> valuesRead[i]);
+        ASSERT_STREQ(values[i].c_str(), valuesRead[i].c_str());
+    }
+}
+
+struct data_t
+{
+    typedef uchar  u;
+    typedef char   b;
+    typedef ushort w;
+    typedef short  s;
+    typedef int    i;
+    typedef float  f;
+    typedef double d;
+
+    u u1   ;u u2   ;                i i1                           ;
+    i i2                           ;i i3                           ;
+    d d1                                                           ;
+    d d2                                                           ;
+    i i4                           ;
+
+    static inline const char * signature() { return "2u3i2di"; }
+};
+
+TEST(Core_InputOutput, filestorage_base64_basic)
+{
+    char const * filenames[] = {
+        "core_io_base64_basic_test.yml",
+        "core_io_base64_basic_test.xml",
+        "core_io_base64_basic_test.json",
+        0
+    };
+
+    for (char const ** ptr = filenames; *ptr; ptr++)
+    {
+        char const * name = *ptr;
+
+        std::vector<data_t> rawdata;
+
+        cv::Mat _em_out, _em_in;
+        cv::Mat _2d_out, _2d_in;
+        cv::Mat _nd_out, _nd_in;
+        cv::Mat _rd_out(64, 64, CV_64FC1), _rd_in;
+
+        bool no_type_id = true;
+
+        {   /* init */
+
+            /* a normal mat */
+            _2d_out = cv::Mat(100, 100, CV_8UC3, cvScalar(1U, 2U, 127U));
+            for (int i = 0; i < _2d_out.rows; ++i)
+                for (int j = 0; j < _2d_out.cols; ++j)
+                    _2d_out.at<cv::Vec3b>(i, j)[1] = (i + j) % 256;
+
+            /* a 4d mat */
+            const int Size[] = {4, 4, 4, 4};
+            cv::Mat _4d(4, Size, CV_64FC4, cvScalar(0.888, 0.111, 0.666, 0.444));
+            const cv::Range ranges[] = {
+                cv::Range(0, 2),
+                cv::Range(0, 2),
+                cv::Range(1, 2),
+                cv::Range(0, 2) };
+            _nd_out = _4d(ranges);
+
+            /* a random mat */
+            cv::randu(_rd_out, cv::Scalar(0.0), cv::Scalar(1.0));
+
+            /* raw data */
+            for (int i = 0; i < 1000; i++) {
+                data_t tmp;
+                tmp.u1 = 1;
+                tmp.u2 = 2;
+                tmp.i1 = 1;
+                tmp.i2 = 2;
+                tmp.i3 = 3;
+                tmp.d1 = 0.1;
+                tmp.d2 = 0.2;
+                tmp.i4 = i;
+                rawdata.push_back(tmp);
+            }
+        }
+
+        {   /* write */
+            cv::FileStorage fs(name, cv::FileStorage::WRITE_BASE64);
+            fs << "normal_2d_mat" << _2d_out;
+            fs << "normal_nd_mat" << _nd_out;
+            fs << "empty_2d_mat"  << _em_out;
+            fs << "random_mat"    << _rd_out;
+
+            cvStartWriteStruct( *fs, "rawdata", CV_NODE_SEQ | CV_NODE_FLOW, "binary" );
+            for (int i = 0; i < 10; i++)
+                cvWriteRawDataBase64(*fs, rawdata.data() + i * 100, 100, data_t::signature());
+            cvEndWriteStruct( *fs );
+
+            fs.release();
+        }
+
+        {   /* read */
+            cv::FileStorage fs(name, cv::FileStorage::READ);
+
+            /* mat */
+            fs["empty_2d_mat"]  >> _em_in;
+            fs["normal_2d_mat"] >> _2d_in;
+            fs["normal_nd_mat"] >> _nd_in;
+            fs["random_mat"]    >> _rd_in;
+
+            if ( !fs["empty_2d_mat"]["type_id"].empty() ||
+                !fs["normal_2d_mat"]["type_id"].empty() ||
+                !fs["normal_nd_mat"]["type_id"].empty() ||
+                !fs[   "random_mat"]["type_id"].empty() )
+                no_type_id = false;
+
+            /* raw data */
+            std::vector<data_t>(1000).swap(rawdata);
+            cvReadRawData(*fs, fs["rawdata"].node, rawdata.data(), data_t::signature());
+
+            fs.release();
+        }
+
+        for (int i = 0; i < 1000; i++) {
+            // TODO: Solve this bug in `cvReadRawData`
+            //EXPECT_EQ(rawdata[i].u1, 1);
+            //EXPECT_EQ(rawdata[i].u2, 2);
+            //EXPECT_EQ(rawdata[i].i1, 1);
+            //EXPECT_EQ(rawdata[i].i2, 2);
+            //EXPECT_EQ(rawdata[i].i3, 3);
+            //EXPECT_EQ(rawdata[i].d1, 0.1);
+            //EXPECT_EQ(rawdata[i].d2, 0.2);
+            //EXPECT_EQ(rawdata[i].i4, i);
+        }
+
+        EXPECT_TRUE(no_type_id);
+
+        EXPECT_EQ(_em_in.rows   , _em_out.rows);
+        EXPECT_EQ(_em_in.cols   , _em_out.cols);
+        EXPECT_EQ(_em_in.depth(), _em_out.depth());
+        EXPECT_TRUE(_em_in.empty());
+
+        EXPECT_EQ(_2d_in.rows   , _2d_out.rows);
+        EXPECT_EQ(_2d_in.cols   , _2d_out.cols);
+        EXPECT_EQ(_2d_in.dims   , _2d_out.dims);
+        EXPECT_EQ(_2d_in.depth(), _2d_out.depth());
+        for(int i = 0; i < _2d_out.rows; ++i)
+            for (int j = 0; j < _2d_out.cols; ++j)
+                EXPECT_EQ(_2d_in.at<cv::Vec3b>(i, j), _2d_out.at<cv::Vec3b>(i, j));
+
+        EXPECT_EQ(_nd_in.rows   , _nd_out.rows);
+        EXPECT_EQ(_nd_in.cols   , _nd_out.cols);
+        EXPECT_EQ(_nd_in.dims   , _nd_out.dims);
+        EXPECT_EQ(_nd_in.depth(), _nd_out.depth());
+        EXPECT_EQ(cv::countNonZero(cv::mean(_nd_in != _nd_out)), 0);
+
+        EXPECT_EQ(_rd_in.rows   , _rd_out.rows);
+        EXPECT_EQ(_rd_in.cols   , _rd_out.cols);
+        EXPECT_EQ(_rd_in.dims   , _rd_out.dims);
+        EXPECT_EQ(_rd_in.depth(), _rd_out.depth());
+        EXPECT_EQ(cv::countNonZero(cv::mean(_rd_in != _rd_out)), 0);
+
+        remove(name);
+    }
+}
+
+TEST(Core_InputOutput, filestorage_base64_valid_call)
+{
+    char const * filenames[] = {
+        "core_io_base64_other_test.yml",
+        "core_io_base64_other_test.xml",
+        "core_io_base64_other_test.json",
+        "core_io_base64_other_test.yml?base64",
+        "core_io_base64_other_test.xml?base64",
+        "core_io_base64_other_test.json?base64",
+        0
+    };
+    char const * real_name[] = {
+        "core_io_base64_other_test.yml",
+        "core_io_base64_other_test.xml",
+        "core_io_base64_other_test.json",
+        "core_io_base64_other_test.yml",
+        "core_io_base64_other_test.xml",
+        "core_io_base64_other_test.json",
+        0
+    };
+
+    std::vector<int> rawdata(10, static_cast<int>(0x00010203));
+    cv::String str_out = "test_string";
+
+    for (char const ** ptr = filenames; *ptr; ptr++)
+    {
+        char const * name = *ptr;
+
+        EXPECT_NO_THROW(
+        {
+            cv::FileStorage fs(name, cv::FileStorage::WRITE_BASE64);
+
+            cvStartWriteStruct(*fs, "manydata", CV_NODE_SEQ);
+            cvStartWriteStruct(*fs, 0, CV_NODE_SEQ | CV_NODE_FLOW);
+            for (int i = 0; i < 10; i++)
+                cvWriteRawData(*fs, rawdata.data(), static_cast<int>(rawdata.size()), "i");
+            cvEndWriteStruct(*fs);
+            cvWriteString(*fs, 0, str_out.c_str(), 1);
+            cvEndWriteStruct(*fs);
+
+            fs.release();
+        });
+
+        {
+            cv::FileStorage fs(name, cv::FileStorage::READ);
+            std::vector<int> data_in(rawdata.size());
+            fs["manydata"][0].readRaw("i", (uchar *)data_in.data(), data_in.size());
+            EXPECT_TRUE(fs["manydata"][0].isSeq());
+            EXPECT_TRUE(std::equal(rawdata.begin(), rawdata.end(), data_in.begin()));
+            cv::String str_in;
+            fs["manydata"][1] >> str_in;
+            EXPECT_TRUE(fs["manydata"][1].isString());
+            EXPECT_EQ(str_in, str_out);
+            fs.release();
+        }
+
+        EXPECT_NO_THROW(
+        {
+            cv::FileStorage fs(name, cv::FileStorage::WRITE);
+
+            cvStartWriteStruct(*fs, "manydata", CV_NODE_SEQ);
+            cvWriteString(*fs, 0, str_out.c_str(), 1);
+            cvStartWriteStruct(*fs, 0, CV_NODE_SEQ | CV_NODE_FLOW, "binary");
+            for (int i = 0; i < 10; i++)
+                cvWriteRawData(*fs, rawdata.data(), static_cast<int>(rawdata.size()), "i");
+            cvEndWriteStruct(*fs);
+            cvEndWriteStruct(*fs);
+
+            fs.release();
+        });
+
+        {
+            cv::FileStorage fs(name, cv::FileStorage::READ);
+            cv::String str_in;
+            fs["manydata"][0] >> str_in;
+            EXPECT_TRUE(fs["manydata"][0].isString());
+            EXPECT_EQ(str_in, str_out);
+            std::vector<int> data_in(rawdata.size());
+            fs["manydata"][1].readRaw("i", (uchar *)data_in.data(), data_in.size());
+            EXPECT_TRUE(fs["manydata"][1].isSeq());
+            EXPECT_TRUE(std::equal(rawdata.begin(), rawdata.end(), data_in.begin()));
+            fs.release();
+        }
+
+        remove(real_name[ptr - filenames]);
+    }
+}
+
+TEST(Core_InputOutput, filestorage_base64_invalid_call)
+{
+    char const * filenames[] = {
+        "core_io_base64_other_test.yml",
+        "core_io_base64_other_test.xml",
+        "core_io_base64_other_test.json",
+        0
+    };
+
+    for (char const ** ptr = filenames; *ptr; ptr++)
+    {
+        char const * name = *ptr;
+
+        EXPECT_ANY_THROW({
+            cv::FileStorage fs(name, cv::FileStorage::WRITE);
+            cvStartWriteStruct(*fs, "rawdata", CV_NODE_SEQ, "binary");
+            cvStartWriteStruct(*fs, 0, CV_NODE_SEQ | CV_NODE_FLOW);
+        });
+
+        EXPECT_ANY_THROW({
+            cv::FileStorage fs(name, cv::FileStorage::WRITE);
+            cvStartWriteStruct(*fs, "rawdata", CV_NODE_SEQ);
+            cvStartWriteStruct(*fs, 0, CV_NODE_SEQ | CV_NODE_FLOW);
+            cvWriteRawDataBase64(*fs, name, 1, "u");
+        });
+
+        remove(name);
+    }
+}
+
+TEST(Core_InputOutput, filestorage_yml_vec2i)
+{
+    const std::string file_name = "vec2i.yml";
+    cv::Vec2i vec(2, 1), ovec;
+
+    /* write */
+    {
+        cv::FileStorage fs(file_name, cv::FileStorage::WRITE);
+        fs << "prms0" << "{" << "vec0" << vec << "}";
+        fs.release();
+    }
+
+    /* read */
+    {
+        cv::FileStorage fs(file_name, cv::FileStorage::READ);
+        fs["prms0"]["vec0"] >> ovec;
+        fs.release();
+    }
+
+    EXPECT_EQ(vec(0), ovec(0));
+    EXPECT_EQ(vec(1), ovec(1));
+
+    remove(file_name.c_str());
+}
+
+TEST(Core_InputOutput, filestorage_json_comment)
+{
+    String mem_str =
+        "{ /* comment */\n"
+        "  \"key\": \"value\"\n"
+        "  /************\n"
+        "   * multiline comment\n"
+        "   ************/\n"
+        "  // 233\n"
+        "  // \n"
+        "}\n"
+        ;
+
+    String str;
+
+    EXPECT_NO_THROW(
+    {
+        cv::FileStorage fs(mem_str, cv::FileStorage::READ | cv::FileStorage::MEMORY);
+        fs["key"] >> str;
+        fs.release();
+    });
+
+    EXPECT_EQ(str, String("value"));
+}
+
+TEST(Core_InputOutput, filestorage_utf8_bom)
+{
+    EXPECT_NO_THROW(
+    {
+        String content ="\xEF\xBB\xBF<?xml version=\"1.0\"?>\n<opencv_storage>\n</opencv_storage>\n";
+        cv::FileStorage fs(content, cv::FileStorage::READ | cv::FileStorage::MEMORY);
+        fs.release();
+    });
+    EXPECT_NO_THROW(
+    {
+        String content ="\xEF\xBB\xBF%YAML:1.0\n";
+        cv::FileStorage fs(content, cv::FileStorage::READ | cv::FileStorage::MEMORY);
+        fs.release();
+    });
+    EXPECT_NO_THROW(
+    {
+        String content ="\xEF\xBB\xBF{\n}\n";
+        cv::FileStorage fs(content, cv::FileStorage::READ | cv::FileStorage::MEMORY);
+        fs.release();
+    });
+}
+
+TEST(Core_InputOutput, filestorage_vec_vec_io)
+{
+    std::vector<std::vector<Mat> > outputMats(3);
+    for(size_t i = 0; i < outputMats.size(); i++)
+    {
+        outputMats[i].resize(i+1);
+        for(size_t j = 0; j < outputMats[i].size(); j++)
+        {
+            outputMats[i][j] = Mat::eye((int)i + 1, (int)i + 1, CV_8U);
+        }
+    }
+
+    String fileName = "vec_test.";
+
+    std::vector<String> formats;
+    formats.push_back("xml");
+    formats.push_back("yml");
+    formats.push_back("json");
+
+    for(size_t i = 0; i < formats.size(); i++)
+    {
+        FileStorage writer(fileName + formats[i], FileStorage::WRITE);
+        writer << "vecVecMat" << outputMats;
+        writer.release();
+
+        FileStorage reader(fileName + formats[i], FileStorage::READ);
+        std::vector<std::vector<Mat> > testMats;
+        reader["vecVecMat"] >> testMats;
+
+        ASSERT_EQ(testMats.size(), testMats.size());
+
+        for(size_t j = 0; j < testMats.size(); j++)
+        {
+            ASSERT_EQ(testMats[j].size(), outputMats[j].size());
+
+            for(size_t k = 0; k < testMats[j].size(); k++)
+            {
+                ASSERT_TRUE(norm(outputMats[j][k] - testMats[j][k], NORM_INF) == 0);
+            }
+        }
+
+        reader.release();
+        remove((fileName + formats[i]).c_str());
+    }
+}
diff --git a/modules/core/test/test_ippasync.cpp b/modules/core/test/test_ippasync.cpp
index bd37ffa..5ba9f60 100644
--- a/modules/core/test/test_ippasync.cpp
+++ b/modules/core/test/test_ippasync.cpp
@@ -32,7 +32,7 @@ PARAM_TEST_CASE(IPPAsync, MatDepth, Channels, hppAccelType)
         accelType = GET_PARAM(2);
     }
 
-    virtual void generateTestData()
+    void generateTestData()
     {
         Size matrix_Size = randomSize(2, 100);
         const double upValue = 100;
@@ -102,7 +102,7 @@ PARAM_TEST_CASE(IPPAsyncShared, Channels, hppAccelType)
         type=CV_MAKE_TYPE(CV_8U, GET_PARAM(0));
     }
 
-    virtual void generateTestData()
+    void generateTestData()
     {
         Size matrix_Size = randomSize(2, 100);
         hpp32u pitch, size;
diff --git a/modules/core/test/test_mat.cpp b/modules/core/test/test_mat.cpp
index 2344df2..9a379f4 100644
--- a/modules/core/test/test_mat.cpp
+++ b/modules/core/test/test_mat.cpp
@@ -1392,7 +1392,7 @@ TEST(Core_SparseMat, footprint)
 }
 
 
-// Can't fix without duty hacks or broken user code (PR #4159)
+// Can't fix without dirty hacks or broken user code (PR #4159)
 TEST(Core_Mat_vector, DISABLED_OutputArray_create_getMat)
 {
     cv::Mat_<uchar> src_base(5, 1);
@@ -1420,7 +1420,7 @@ TEST(Core_Mat_vector, copyTo_roi_column)
 
     Mat src_full(src_base);
     Mat src(src_full.col(0));
-#if 0 // Can't fix without duty hacks or broken user code (PR #4159)
+#if 0 // Can't fix without dirty hacks or broken user code (PR #4159)
     OutputArray _dst(dst1);
     {
         _dst.create(src.rows, src.cols, src.type());
@@ -1472,3 +1472,102 @@ TEST(Core_Mat_vector, copyTo_roi_row)
     EXPECT_EQ(4, (int)dst2[3]);
     EXPECT_EQ(5, (int)dst2[4]);
 }
+
+TEST(Mat, regression_5991)
+{
+    int sz[] = {2,3,2};
+    Mat mat(3, sz, CV_32F, Scalar(1));
+    ASSERT_NO_THROW(mat.convertTo(mat, CV_8U));
+    EXPECT_EQ(sz[0], mat.size[0]);
+    EXPECT_EQ(sz[1], mat.size[1]);
+    EXPECT_EQ(sz[2], mat.size[2]);
+    EXPECT_EQ(0, cvtest::norm(mat, Mat(3, sz, CV_8U, Scalar(1)), NORM_INF));
+}
+
+#ifdef OPENCV_TEST_BIGDATA
+TEST(Mat, regression_6696_BigData_8Gb)
+{
+    int width = 60000;
+    int height = 10000;
+
+    Mat destImageBGR = Mat(height, width, CV_8UC3, Scalar(1, 2, 3, 0));
+    Mat destImageA = Mat(height, width, CV_8UC1, Scalar::all(4));
+
+    vector<Mat> planes;
+    split(destImageBGR, planes);
+    planes.push_back(destImageA);
+    merge(planes, destImageBGR);
+
+    EXPECT_EQ(1, destImageBGR.at<Vec4b>(0)[0]);
+    EXPECT_EQ(2, destImageBGR.at<Vec4b>(0)[1]);
+    EXPECT_EQ(3, destImageBGR.at<Vec4b>(0)[2]);
+    EXPECT_EQ(4, destImageBGR.at<Vec4b>(0)[3]);
+
+    EXPECT_EQ(1, destImageBGR.at<Vec4b>(height-1, width-1)[0]);
+    EXPECT_EQ(2, destImageBGR.at<Vec4b>(height-1, width-1)[1]);
+    EXPECT_EQ(3, destImageBGR.at<Vec4b>(height-1, width-1)[2]);
+    EXPECT_EQ(4, destImageBGR.at<Vec4b>(height-1, width-1)[3]);
+}
+#endif
+
+TEST(Reduce, regression_should_fail_bug_4594)
+{
+    cv::Mat src = cv::Mat::eye(4, 4, CV_8U);
+    std::vector<int> dst;
+
+    EXPECT_THROW(cv::reduce(src, dst, 0, CV_REDUCE_MIN, CV_32S), cv::Exception);
+    EXPECT_THROW(cv::reduce(src, dst, 0, CV_REDUCE_MAX, CV_32S), cv::Exception);
+    EXPECT_NO_THROW(cv::reduce(src, dst, 0, CV_REDUCE_SUM, CV_32S));
+    EXPECT_NO_THROW(cv::reduce(src, dst, 0, CV_REDUCE_AVG, CV_32S));
+}
+
+TEST(Mat, push_back_vector)
+{
+    cv::Mat result(1, 5, CV_32FC1);
+
+    std::vector<float> vec1(result.cols + 1);
+    std::vector<int> vec2(result.cols);
+
+    EXPECT_THROW(result.push_back(vec1), cv::Exception);
+    EXPECT_THROW(result.push_back(vec2), cv::Exception);
+
+    vec1.resize(result.cols);
+
+    for (int i = 0; i < 5; ++i)
+        result.push_back(cv::Mat(vec1).reshape(1, 1));
+
+    ASSERT_EQ(6, result.rows);
+}
+
+TEST(Mat, regression_5917_clone_empty)
+{
+    Mat cloned;
+    Mat_<Point2f> source(5, 0);
+
+    ASSERT_NO_THROW(cloned = source.clone());
+}
+
+TEST(Mat, regression_7873_mat_vector_initialize)
+{
+    std::vector<int> dims;
+    dims.push_back(12);
+    dims.push_back(3);
+    dims.push_back(2);
+    Mat multi_mat(dims, CV_32FC1, cv::Scalar(0));
+
+    ASSERT_EQ(3, multi_mat.dims);
+    ASSERT_EQ(12, multi_mat.size[0]);
+    ASSERT_EQ(3, multi_mat.size[1]);
+    ASSERT_EQ(2, multi_mat.size[2]);
+
+    std::vector<Range> ranges;
+    ranges.push_back(Range(1, 2));
+    ranges.push_back(Range::all());
+    ranges.push_back(Range::all());
+    Mat sub_mat = multi_mat(ranges);
+
+    ASSERT_EQ(3, sub_mat.dims);
+    ASSERT_EQ(1, sub_mat.size[0]);
+    ASSERT_EQ(3, sub_mat.size[1]);
+    ASSERT_EQ(2, sub_mat.size[2]);
+}
diff --git a/modules/core/test/test_math.cpp b/modules/core/test/test_math.cpp
index 65e3861..3870d31 100644
--- a/modules/core/test/test_math.cpp
+++ b/modules/core/test/test_math.cpp
@@ -2384,7 +2384,7 @@ TEST(Core_SolvePoly, regression_5599)
         double prec;
         prec = cv::solvePoly(coefs, r);
         EXPECT_LE(prec, 1e-6);
-        EXPECT_EQ(4, r.total());
+        EXPECT_EQ(4u, r.total());
         //std::cout << "Preciseness = " << prec << std::endl;
         //std::cout << "roots:\n" << r << "\n" << std::endl;
         ASSERT_EQ(CV_32FC2, r.type());
@@ -2400,7 +2400,7 @@ TEST(Core_SolvePoly, regression_5599)
         double prec;
         prec = cv::solvePoly(coefs, r);
         EXPECT_LE(prec, 1e-6);
-        EXPECT_EQ(2, r.total());
+        EXPECT_EQ(2u, r.total());
         //std::cout << "Preciseness = " << prec << std::endl;
         //std::cout << "roots:\n" << r << "\n" << std::endl;
         ASSERT_EQ(CV_32FC2, r.type());
@@ -2411,8 +2411,9 @@ TEST(Core_SolvePoly, regression_5599)
 
 class Core_PhaseTest : public cvtest::BaseTest
 {
+    int t;
 public:
-    Core_PhaseTest() {}
+    Core_PhaseTest(int t_) : t(t_) {}
     ~Core_PhaseTest() {}
 protected:
     virtual void run(int)
@@ -2421,9 +2422,9 @@ protected:
         const int axisCount = 8;
         const int dim = theRNG().uniform(1,10);
         const float scale = theRNG().uniform(1.f, 100.f);
-        Mat x(axisCount + 1, dim, CV_32FC1),
-            y(axisCount + 1, dim, CV_32FC1);
-        Mat anglesInDegrees(axisCount + 1, dim, CV_32FC1);
+        Mat x(axisCount + 1, dim, t),
+            y(axisCount + 1, dim, t);
+        Mat anglesInDegrees(axisCount + 1, dim, t);
 
         // fill the data
         x.row(0).setTo(Scalar(0));
@@ -2696,8 +2697,8 @@ TEST(Core_SVD, accuracy) { Core_SVDTest test; test.safe_run(); }
 TEST(Core_SVBkSb, accuracy) { Core_SVBkSbTest test; test.safe_run(); }
 TEST(Core_Trace, accuracy) { Core_TraceTest test; test.safe_run(); }
 TEST(Core_SolvePoly, accuracy) { Core_SolvePolyTest test; test.safe_run(); }
-TEST(Core_Phase, accuracy) { Core_PhaseTest test; test.safe_run(); }
-
+TEST(Core_Phase, accuracy32f) { Core_PhaseTest test(CV_32FC1); test.safe_run(); }
+TEST(Core_Phase, accuracy64f) { Core_PhaseTest test(CV_64FC1); test.safe_run(); }
 
 TEST(Core_SVD, flt)
 {
@@ -2976,4 +2977,68 @@ TEST(Core_Pow, special)
     }
 }
 
+TEST(Core_Cholesky, accuracy64f)
+{
+    const int n = 5;
+    Mat A(n, n, CV_64F), refA;
+    Mat mean(1, 1, CV_64F);
+    *mean.ptr<double>() = 10.0;
+    Mat dev(1, 1, CV_64F);
+    *dev.ptr<double>() = 10.0;
+    RNG rng(10);
+    rng.fill(A, RNG::NORMAL, mean, dev);
+    A = A*A.t();
+    A.copyTo(refA);
+    Cholesky(A.ptr<double>(), A.step, n, NULL, 0, 0);
+
+   for (int i = 0; i < A.rows; i++)
+       for (int j = i + 1; j < A.cols; j++)
+           A.at<double>(i, j) = 0.0;
+   EXPECT_LE(norm(refA, A*A.t(), CV_RELATIVE_L2), FLT_EPSILON);
+}
+
+TEST(Core_QR_Solver, accuracy64f)
+{
+    int m = 20, n = 18;
+    Mat A(m, m, CV_64F);
+    Mat B(m, n, CV_64F);
+    Mat mean(1, 1, CV_64F);
+    *mean.ptr<double>() = 10.0;
+    Mat dev(1, 1, CV_64F);
+    *dev.ptr<double>() = 10.0;
+    RNG rng(10);
+    rng.fill(A, RNG::NORMAL, mean, dev);
+    rng.fill(B, RNG::NORMAL, mean, dev);
+    A = A*A.t();
+    Mat solutionQR;
+
+    //solve system with square matrix
+    solve(A, B, solutionQR, DECOMP_QR);
+    EXPECT_LE(norm(A*solutionQR, B, CV_RELATIVE_L2), FLT_EPSILON);
+
+    A = Mat(m, n, CV_64F);
+    B = Mat(m, n, CV_64F);
+    rng.fill(A, RNG::NORMAL, mean, dev);
+    rng.fill(B, RNG::NORMAL, mean, dev);
+
+    //solve normal system
+    solve(A, B, solutionQR, DECOMP_QR | DECOMP_NORMAL);
+    EXPECT_LE(norm(A.t()*(A*solutionQR), A.t()*B, CV_RELATIVE_L2), FLT_EPSILON);
+
+    //solve overdeterminated system as a least squares problem
+    Mat solutionSVD;
+    solve(A, B, solutionQR, DECOMP_QR);
+    solve(A, B, solutionSVD, DECOMP_SVD);
+    EXPECT_LE(norm(solutionQR, solutionSVD, CV_RELATIVE_L2), FLT_EPSILON);
+
+    //solve system with singular matrix
+    A = Mat(10, 10, CV_64F);
+    B = Mat(10, 1, CV_64F);
+    rng.fill(A, RNG::NORMAL, mean, dev);
+    rng.fill(B, RNG::NORMAL, mean, dev);
+    for (int i = 0; i < A.cols; i++)
+      A.at<double>(0, i) = A.at<double>(1, i);
+    ASSERT_FALSE(solve(A, B, solutionQR, DECOMP_QR));
+}
+
 /* End of file. */
diff --git a/modules/core/test/test_rand.cpp b/modules/core/test/test_rand.cpp
index fc6c75a..63b9094 100644
--- a/modules/core/test/test_rand.cpp
+++ b/modules/core/test/test_rand.cpp
@@ -365,3 +365,20 @@ TEST(Core_RNG_MT19937, regression)
         ASSERT_EQ(expected[i], actual[i]);
     }
 }
+
+
+TEST(Core_Rand, Regression_Stack_Corruption)
+{
+    int bufsz = 128; //enough for 14 doubles
+    AutoBuffer<uchar> buffer(bufsz);
+    size_t offset = 0;
+    cv::Mat_<cv::Point2d> x(2, 3, (cv::Point2d*)(buffer+offset)); offset += x.total()*x.elemSize();
+    double& param1 = *(double*)(buffer+offset); offset += sizeof(double);
+    double& param2 = *(double*)(buffer+offset); offset += sizeof(double);
+    param1 = -9; param2 = 2;
+
+    cv::theRNG().fill(x, cv::RNG::NORMAL, param1, param2);
+
+    ASSERT_EQ(param1, -9);
+    ASSERT_EQ(param2,  2);
+}
diff --git a/modules/core/test/test_umat.cpp b/modules/core/test/test_umat.cpp
index a8641d0..9e9835f 100644
--- a/modules/core/test/test_umat.cpp
+++ b/modules/core/test/test_umat.cpp
@@ -1035,7 +1035,7 @@ TEST(UMat, synchronization_map_unmap)
     };
     try
     {
-        UMat u(1000, 1000, CV_32FC1);
+        UMat u(1000, 1000, CV_32FC1, Scalar::all(0));
         parallel_for_(cv::Range(0, 2), TestParallelLoopBody(u));
     }
     catch (const cv::Exception& e)
@@ -1056,7 +1056,7 @@ TEST(UMat, async_unmap)
     {
         try
         {
-            Mat m = Mat(1000, 1000, CV_8UC1);
+            Mat m = Mat(1000, 1000, CV_8UC1, Scalar::all(0));
             UMat u = m.getUMat(ACCESS_READ);
             UMat dst;
             add(u, Scalar::all(0), dst); // start async operation
@@ -1101,7 +1101,7 @@ TEST(UMat, unmap_in_class)
     };
     try
     {
-        Mat m = Mat(1000, 1000, CV_8UC1);
+        Mat m = Mat(1000, 1000, CV_8UC1, Scalar::all(0));
         Logic l;
         l.processData(m);
         UMat result = l.getResult();
@@ -1127,7 +1127,7 @@ TEST(UMat, map_unmap_counting)
         return;
     }
     std::cout << "Host memory: " << cv::ocl::Device::getDefault().hostUnifiedMemory() << std::endl;
-    Mat m(Size(10, 10), CV_8UC1);
+    Mat m(Size(10, 10), CV_8UC1, Scalar::all(0));
     UMat um = m.getUMat(ACCESS_RW);
     {
         Mat d1 = um.getMat(ACCESS_RW);
@@ -1156,7 +1156,7 @@ OCL_TEST(UMat, DISABLED_OCL_ThreadSafe_CleanupCallback_1_VeryLongTest)
         const int type = CV_8UC1;
         const int dtype = CV_16UC1;
 
-        Mat src(srcSize, type);
+        Mat src(srcSize, type, Scalar::all(0));
         Mat dst_ref(srcSize, dtype);
 
         // Generate reference data as additional check
@@ -1198,7 +1198,7 @@ OCL_TEST(UMat, DISABLED_OCL_ThreadSafe_CleanupCallback_2_VeryLongTest)
         // Use multiple iterations to increase chance of data race catching
         for(int k = 0; k < 10000; k++)
         {
-            Mat src(srcSize, type); // Declare src inside loop now to catch its destruction on stack
+            Mat src(srcSize, type, Scalar::all(0)); // Declare src inside loop now to catch its destruction on stack
             {
                 UMat tmpUMat = src.getUMat(ACCESS_RW);
                 tmpUMat.convertTo(dst, dtype);
@@ -1216,7 +1216,7 @@ TEST(UMat, DISABLED_Test_same_behaviour_read_and_read)
     bool exceptionDetected = false;
     try
     {
-        UMat u(Size(10, 10), CV_8UC1);
+        UMat u(Size(10, 10), CV_8UC1, Scalar::all(0));
         Mat m = u.getMat(ACCESS_READ);
         UMat dst;
         add(u, Scalar::all(1), dst);
@@ -1234,7 +1234,7 @@ TEST(UMat, DISABLED_Test_same_behaviour_read_and_write)
     bool exceptionDetected = false;
     try
     {
-        UMat u(Size(10, 10), CV_8UC1);
+        UMat u(Size(10, 10), CV_8UC1, Scalar::all(0));
         Mat m = u.getMat(ACCESS_READ);
         add(u, Scalar::all(1), u);
     }
@@ -1250,7 +1250,7 @@ TEST(UMat, DISABLED_Test_same_behaviour_write_and_read)
     bool exceptionDetected = false;
     try
     {
-        UMat u(Size(10, 10), CV_8UC1);
+        UMat u(Size(10, 10), CV_8UC1, Scalar::all(0));
         Mat m = u.getMat(ACCESS_WRITE);
         UMat dst;
         add(u, Scalar::all(1), dst);
@@ -1267,7 +1267,7 @@ TEST(UMat, DISABLED_Test_same_behaviour_write_and_write)
     bool exceptionDetected = false;
     try
     {
-        UMat u(Size(10, 10), CV_8UC1);
+        UMat u(Size(10, 10), CV_8UC1, Scalar::all(0));
         Mat m = u.getMat(ACCESS_WRITE);
         add(u, Scalar::all(1), u);
     }
@@ -1304,20 +1304,18 @@ TEST(UMat, testTempObjects_UMat)
     ASSERT_EQ(0, countNonZero(uDiff));
 }
 
-// Disabled due to failure in VS 2015:
-//  C++11 is enabled by default ==>
-//  destructors have implicit 'noexcept(true)' specifier ==>
-//  throwing exception from destructor is not handled correctly
-#if defined(_MSC_VER) && _MSC_VER >= 1900 /* MSVC 14 */
-TEST(UMat, DISABLED_testTempObjects_Mat)
-#else
 TEST(UMat, testTempObjects_Mat)
-#endif
 {
     Mat m(10, 10, CV_8UC1, Scalar(1));
     {
         Mat m2;
-        ASSERT_ANY_THROW(m2 = m.getUMat(ACCESS_RW).getMat(ACCESS_RW));
+        ASSERT_ANY_THROW({
+          // Below is unwrapped version of this invalid expression:
+          // m2 = m.getUMat(ACCESS_RW).getMat(ACCESS_RW)
+          UMat u = m.getUMat(ACCESS_RW);
+          m2 = u.getMat(ACCESS_RW);
+          u.release();
+        });
     }
 }
 
@@ -1343,4 +1341,15 @@ TEST(UMat, testWrongLifetime_Mat)
     }
 }
 
+TEST(UMat, DISABLED_regression_5991)
+{
+    int sz[] = {2,3,2};
+    UMat mat(3, sz, CV_32F, Scalar(1));
+    ASSERT_NO_THROW(mat.convertTo(mat, CV_8U));
+    EXPECT_EQ(sz[0], mat.size[0]);
+    EXPECT_EQ(sz[1], mat.size[1]);
+    EXPECT_EQ(sz[2], mat.size[2]);
+    EXPECT_EQ(0, cvtest::norm(mat.getMat(ACCESS_READ), Mat(3, sz, CV_8U, Scalar(1)), NORM_INF));
+}
+
 } } // namespace cvtest::ocl
diff --git a/modules/core/test/test_utils.cpp b/modules/core/test/test_utils.cpp
index 18b0a5a..8ff76af 100644
--- a/modules/core/test/test_utils.cpp
+++ b/modules/core/test/test_utils.cpp
@@ -27,6 +27,7 @@ TEST(CommandLineParser, testFailure)
     parser.get<bool>("h");
     EXPECT_FALSE(parser.check());
 }
+
 TEST(CommandLineParser, testHas_noValues)
 {
     const char* argv[] = {"<bin>", "-h", "--info"};
@@ -218,4 +219,17 @@ TEST(CommandLineParser, positional_regression_5074_equal_sign)
     EXPECT_TRUE(parser.check());
 }
 
+
+TEST(AutoBuffer, allocate_test)
+{
+    AutoBuffer<int, 5> abuf(2);
+    EXPECT_EQ(2u, abuf.size());
+
+    abuf.allocate(4);
+    EXPECT_EQ(4u, abuf.size());
+
+    abuf.allocate(6);
+    EXPECT_EQ(6u, abuf.size());
+}
+
 } // namespace
diff --git a/modules/cudaarithm/include/opencv2/cudaarithm.hpp b/modules/cudaarithm/include/opencv2/cudaarithm.hpp
index d377a70..f2ee845 100644
--- a/modules/cudaarithm/include/opencv2/cudaarithm.hpp
+++ b/modules/cudaarithm/include/opencv2/cudaarithm.hpp
@@ -40,8 +40,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_CUDAARITHM_HPP__
-#define __OPENCV_CUDAARITHM_HPP__
+#ifndef OPENCV_CUDAARITHM_HPP
+#define OPENCV_CUDAARITHM_HPP
 
 #ifndef __cplusplus
 #  error cudaarithm.hpp header must be compiled as C++
@@ -77,7 +77,7 @@ namespace cv { namespace cuda {
 @param dst Destination matrix that has the same size and number of channels as the input array(s).
 The depth is defined by dtype or src1 depth.
 @param mask Optional operation mask, 8-bit single channel array, that specifies elements of the
-destination array to be changed.
+destination array to be changed. The mask can be used only with single channel images.
 @param dtype Optional depth of the output array.
 @param stream Stream for the asynchronous version.
 
@@ -92,7 +92,7 @@ CV_EXPORTS void add(InputArray src1, InputArray src2, OutputArray dst, InputArra
 @param dst Destination matrix that has the same size and number of channels as the input array(s).
 The depth is defined by dtype or src1 depth.
 @param mask Optional operation mask, 8-bit single channel array, that specifies elements of the
-destination array to be changed.
+destination array to be changed. The mask can be used only with single channel images.
 @param dtype Optional depth of the output array.
 @param stream Stream for the asynchronous version.
 
@@ -226,7 +226,8 @@ CV_EXPORTS void compare(InputArray src1, InputArray src2, OutputArray dst, int c
 
 @param src Source matrix.
 @param dst Destination matrix with the same size and type as src .
- at param mask Optional operation mask. 8-bit single channel image.
+ at param mask Optional operation mask, 8-bit single channel array, that specifies elements of the
+destination array to be changed. The mask can be used only with single channel images.
 @param stream Stream for the asynchronous version.
  */
 CV_EXPORTS void bitwise_not(InputArray src, OutputArray dst, InputArray mask = noArray(), Stream& stream = Stream::Null());
@@ -236,7 +237,8 @@ CV_EXPORTS void bitwise_not(InputArray src, OutputArray dst, InputArray mask = n
 @param src1 First source matrix or scalar.
 @param src2 Second source matrix or scalar.
 @param dst Destination matrix that has the same size and type as the input array(s).
- at param mask Optional operation mask. 8-bit single channel image.
+ at param mask Optional operation mask, 8-bit single channel array, that specifies elements of the
+destination array to be changed. The mask can be used only with single channel images.
 @param stream Stream for the asynchronous version.
  */
 CV_EXPORTS void bitwise_or(InputArray src1, InputArray src2, OutputArray dst, InputArray mask = noArray(), Stream& stream = Stream::Null());
@@ -246,7 +248,8 @@ CV_EXPORTS void bitwise_or(InputArray src1, InputArray src2, OutputArray dst, In
 @param src1 First source matrix or scalar.
 @param src2 Second source matrix or scalar.
 @param dst Destination matrix that has the same size and type as the input array(s).
- at param mask Optional operation mask. 8-bit single channel image.
+ at param mask Optional operation mask, 8-bit single channel array, that specifies elements of the
+destination array to be changed. The mask can be used only with single channel images.
 @param stream Stream for the asynchronous version.
  */
 CV_EXPORTS void bitwise_and(InputArray src1, InputArray src2, OutputArray dst, InputArray mask = noArray(), Stream& stream = Stream::Null());
@@ -256,7 +259,8 @@ CV_EXPORTS void bitwise_and(InputArray src1, InputArray src2, OutputArray dst, I
 @param src1 First source matrix or scalar.
 @param src2 Second source matrix or scalar.
 @param dst Destination matrix that has the same size and type as the input array(s).
- at param mask Optional operation mask. 8-bit single channel image.
+ at param mask Optional operation mask, 8-bit single channel array, that specifies elements of the
+destination array to be changed. The mask can be used only with single channel images.
 @param stream Stream for the asynchronous version.
  */
 CV_EXPORTS void bitwise_xor(InputArray src1, InputArray src2, OutputArray dst, InputArray mask = noArray(), Stream& stream = Stream::Null());
@@ -841,4 +845,4 @@ CV_EXPORTS Ptr<Convolution> createConvolution(Size user_block_size = Size());
 
 }} // namespace cv { namespace cuda {
 
-#endif /* __OPENCV_CUDAARITHM_HPP__ */
+#endif /* OPENCV_CUDAARITHM_HPP */
diff --git a/modules/cudaarithm/perf/perf_arithm.cpp b/modules/cudaarithm/perf/perf_arithm.cpp
index c58397b..02cff85 100644
--- a/modules/cudaarithm/perf/perf_arithm.cpp
+++ b/modules/cudaarithm/perf/perf_arithm.cpp
@@ -46,6 +46,8 @@ using namespace std;
 using namespace testing;
 using namespace perf;
 
+namespace { // workaround conflict with DftFlags
+
 //////////////////////////////////////////////////////////////////////
 // GEMM
 
@@ -252,3 +254,5 @@ PERF_TEST_P(Sz_KernelSz_Ccorr, Convolve,
         CPU_SANITY_CHECK(dst);
     }
 }
+
+} // namespace
diff --git a/modules/cudaarithm/perf/perf_reductions.cpp b/modules/cudaarithm/perf/perf_reductions.cpp
index 78699c0..54c5147 100644
--- a/modules/cudaarithm/perf/perf_reductions.cpp
+++ b/modules/cudaarithm/perf/perf_reductions.cpp
@@ -368,6 +368,8 @@ PERF_TEST_P(Sz_Depth_Cn_Code_Dim, Reduce,
 
         TEST_CYCLE() cv::cuda::reduce(d_src, dst, dim, reduceOp, CV_32F);
 
+        dst = dst.reshape(dst.channels(), 1);
+
         CUDA_SANITY_CHECK(dst);
     }
     else
diff --git a/modules/cudaarithm/src/cuda/reduce.cu b/modules/cudaarithm/src/cuda/reduce.cu
index 5fb9028..3f907c7 100644
--- a/modules/cudaarithm/src/cuda/reduce.cu
+++ b/modules/cudaarithm/src/cuda/reduce.cu
@@ -137,7 +137,7 @@ void cv::cuda::reduce(InputArray _src, OutputArray _dst, int dim, int reduceOp,
     if (dtype < 0)
         dtype = src.depth();
 
-    GpuMat dst = getOutputMat(_dst, 1, dim == 0 ? src.cols : src.rows, CV_MAKE_TYPE(CV_MAT_DEPTH(dtype), src.channels()), stream);
+    GpuMat dst = getOutputMat(_dst, dim == 0 ? 1 : src.rows, dim == 0 ? src.cols : 1, CV_MAKE_TYPE(CV_MAT_DEPTH(dtype), src.channels()), stream);
 
     if (dim == 0)
     {
diff --git a/modules/cudaarithm/src/cuda/threshold.cu b/modules/cudaarithm/src/cuda/threshold.cu
index a5b8f07..1249fee 100644
--- a/modules/cudaarithm/src/cuda/threshold.cu
+++ b/modules/cudaarithm/src/cuda/threshold.cu
@@ -101,10 +101,12 @@ double cv::cuda::threshold(InputArray _src, OutputArray _dst, double thresh, dou
 
     const int depth = src.depth();
 
-    CV_Assert( src.channels() == 1 && depth <= CV_64F );
+    CV_Assert( depth <= CV_64F );
     CV_Assert( type <= 4 /*THRESH_TOZERO_INV*/ );
 
     GpuMat dst = getOutputMat(_dst, src.size(), src.type(), stream);
+    src = src.reshape(1);
+    dst = dst.reshape(1);
 
     if (depth == CV_32F && type == 2 /*THRESH_TRUNC*/)
     {
diff --git a/modules/cudaarithm/test/test_arithm.cpp b/modules/cudaarithm/test/test_arithm.cpp
index 0ee4e34..257f523 100644
--- a/modules/cudaarithm/test/test_arithm.cpp
+++ b/modules/cudaarithm/test/test_arithm.cpp
@@ -46,6 +46,8 @@
 
 using namespace cvtest;
 
+namespace {
+
 //////////////////////////////////////////////////////////////////////////////
 // GEMM
 
@@ -401,4 +403,6 @@ INSTANTIATE_TEST_CASE_P(CUDA_Arithm, Convolve, testing::Combine(
 
 #endif // HAVE_CUBLAS
 
+} // namespace
+
 #endif // HAVE_CUDA
diff --git a/modules/cudaarithm/test/test_core.cpp b/modules/cudaarithm/test/test_core.cpp
index f67854e..cd918ba 100644
--- a/modules/cudaarithm/test/test_core.cpp
+++ b/modules/cudaarithm/test/test_core.cpp
@@ -46,6 +46,8 @@
 
 using namespace cvtest;
 
+namespace {
+
 ////////////////////////////////////////////////////////////////////////////////
 // Merge
 
@@ -416,4 +418,6 @@ INSTANTIATE_TEST_CASE_P(CUDA_Arithm, CopyMakeBorder, testing::Combine(
     ALL_BORDER_TYPES,
     WHOLE_SUBMAT));
 
+} //namespace
+
 #endif // HAVE_CUDA
diff --git a/modules/cudaarithm/test/test_element_operations.cpp b/modules/cudaarithm/test/test_element_operations.cpp
index a4a16ea..b3a2243 100644
--- a/modules/cudaarithm/test/test_element_operations.cpp
+++ b/modules/cudaarithm/test/test_element_operations.cpp
@@ -2532,11 +2532,12 @@ INSTANTIATE_TEST_CASE_P(CUDA_Arithm, AddWeighted, testing::Combine(
 CV_ENUM(ThreshOp, cv::THRESH_BINARY, cv::THRESH_BINARY_INV, cv::THRESH_TRUNC, cv::THRESH_TOZERO, cv::THRESH_TOZERO_INV)
 #define ALL_THRESH_OPS testing::Values(ThreshOp(cv::THRESH_BINARY), ThreshOp(cv::THRESH_BINARY_INV), ThreshOp(cv::THRESH_TRUNC), ThreshOp(cv::THRESH_TOZERO), ThreshOp(cv::THRESH_TOZERO_INV))
 
-PARAM_TEST_CASE(Threshold, cv::cuda::DeviceInfo, cv::Size, MatType, ThreshOp, UseRoi)
+PARAM_TEST_CASE(Threshold, cv::cuda::DeviceInfo, cv::Size, MatType, Channels, ThreshOp, UseRoi)
 {
     cv::cuda::DeviceInfo devInfo;
     cv::Size size;
     int type;
+    int channel;
     int threshOp;
     bool useRoi;
 
@@ -2545,8 +2546,9 @@ PARAM_TEST_CASE(Threshold, cv::cuda::DeviceInfo, cv::Size, MatType, ThreshOp, Us
         devInfo = GET_PARAM(0);
         size = GET_PARAM(1);
         type = GET_PARAM(2);
-        threshOp = GET_PARAM(3);
-        useRoi = GET_PARAM(4);
+        channel = GET_PARAM(3);
+        threshOp = GET_PARAM(4);
+        useRoi = GET_PARAM(5);
 
         cv::cuda::setDevice(devInfo.deviceID());
     }
@@ -2554,7 +2556,7 @@ PARAM_TEST_CASE(Threshold, cv::cuda::DeviceInfo, cv::Size, MatType, ThreshOp, Us
 
 CUDA_TEST_P(Threshold, Accuracy)
 {
-    cv::Mat src = randomMat(size, type);
+    cv::Mat src = randomMat(size, CV_MAKE_TYPE(type, channel));
     double maxVal = randomDouble(20.0, 127.0);
     double thresh = randomDouble(0.0, maxVal);
 
@@ -2570,7 +2572,8 @@ CUDA_TEST_P(Threshold, Accuracy)
 INSTANTIATE_TEST_CASE_P(CUDA_Arithm, Threshold, testing::Combine(
     ALL_DEVICES,
     DIFFERENT_SIZES,
-    testing::Values(MatType(CV_8UC1), MatType(CV_16SC1), MatType(CV_32FC1)),
+    testing::Values(MatDepth(CV_8U), MatDepth(CV_16S), MatDepth(CV_32F)),
+    ALL_CHANNELS,
     ALL_THRESH_OPS,
     WHOLE_SUBMAT));
 
diff --git a/modules/cudaarithm/test/test_reductions.cpp b/modules/cudaarithm/test/test_reductions.cpp
index a0ff0df..48abdfe 100644
--- a/modules/cudaarithm/test/test_reductions.cpp
+++ b/modules/cudaarithm/test/test_reductions.cpp
@@ -877,14 +877,11 @@ CUDA_TEST_P(Reduce, Cols)
 {
     cv::Mat src = randomMat(size, type);
 
-    cv::cuda::GpuMat dst = createMat(cv::Size(src.rows, 1), dst_type, useRoi);
+    cv::cuda::GpuMat dst;
     cv::cuda::reduce(loadMat(src, useRoi), dst, 1, reduceOp, dst_depth);
 
     cv::Mat dst_gold;
     cv::reduce(src, dst_gold, 1, reduceOp, dst_depth);
-    dst_gold.cols = dst_gold.rows;
-    dst_gold.rows = 1;
-    dst_gold.step = dst_gold.cols * dst_gold.elemSize();
 
     EXPECT_MAT_NEAR(dst_gold, dst, dst_depth < CV_32F ? 0.0 : 0.02);
 }
diff --git a/modules/cudabgsegm/include/opencv2/cudabgsegm.hpp b/modules/cudabgsegm/include/opencv2/cudabgsegm.hpp
index 32ea7c1..6149a5c 100644
--- a/modules/cudabgsegm/include/opencv2/cudabgsegm.hpp
+++ b/modules/cudabgsegm/include/opencv2/cudabgsegm.hpp
@@ -40,8 +40,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_CUDABGSEGM_HPP__
-#define __OPENCV_CUDABGSEGM_HPP__
+#ifndef OPENCV_CUDABGSEGM_HPP
+#define OPENCV_CUDABGSEGM_HPP
 
 #ifndef __cplusplus
 #  error cudabgsegm.hpp header must be compiled as C++
@@ -151,4 +151,4 @@ CV_EXPORTS Ptr<cuda::BackgroundSubtractorMOG2>
 
 }} // namespace cv { namespace cuda {
 
-#endif /* __OPENCV_CUDABGSEGM_HPP__ */
+#endif /* OPENCV_CUDABGSEGM_HPP */
diff --git a/modules/cudabgsegm/perf/perf_precomp.hpp b/modules/cudabgsegm/perf/perf_precomp.hpp
index e52fe92..4a230f2 100644
--- a/modules/cudabgsegm/perf/perf_precomp.hpp
+++ b/modules/cudabgsegm/perf/perf_precomp.hpp
@@ -48,8 +48,8 @@
 #  endif
 #endif
 
-#ifndef __OPENCV_PERF_PRECOMP_HPP__
-#define __OPENCV_PERF_PRECOMP_HPP__
+#ifndef OPENCV_PERF_PRECOMP_HPP
+#define OPENCV_PERF_PRECOMP_HPP
 
 #include "opencv2/ts.hpp"
 #include "opencv2/ts/cuda_perf.hpp"
diff --git a/modules/cudabgsegm/src/precomp.hpp b/modules/cudabgsegm/src/precomp.hpp
index e8d627e..12429c2 100644
--- a/modules/cudabgsegm/src/precomp.hpp
+++ b/modules/cudabgsegm/src/precomp.hpp
@@ -40,8 +40,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_PRECOMP_H__
-#define __OPENCV_PRECOMP_H__
+#ifndef OPENCV_PRECOMP_H
+#define OPENCV_PRECOMP_H
 
 #include <limits>
 
@@ -51,4 +51,4 @@
 
 #include "opencv2/opencv_modules.hpp"
 
-#endif /* __OPENCV_PRECOMP_H__ */
+#endif /* OPENCV_PRECOMP_H */
diff --git a/modules/cudabgsegm/test/test_precomp.hpp b/modules/cudabgsegm/test/test_precomp.hpp
index 4d21dfc..5067465 100644
--- a/modules/cudabgsegm/test/test_precomp.hpp
+++ b/modules/cudabgsegm/test/test_precomp.hpp
@@ -48,8 +48,8 @@
 #  endif
 #endif
 
-#ifndef __OPENCV_TEST_PRECOMP_HPP__
-#define __OPENCV_TEST_PRECOMP_HPP__
+#ifndef OPENCV_TEST_PRECOMP_HPP
+#define OPENCV_TEST_PRECOMP_HPP
 
 #include <fstream>
 
diff --git a/modules/cudacodec/CMakeLists.txt b/modules/cudacodec/CMakeLists.txt
index f2e955b..6aecd26 100644
--- a/modules/cudacodec/CMakeLists.txt
+++ b/modules/cudacodec/CMakeLists.txt
@@ -15,7 +15,9 @@ set(extra_libs "")
 
 if(HAVE_NVCUVID)
   list(APPEND extra_libs ${CUDA_CUDA_LIBRARY} ${CUDA_nvcuvid_LIBRARY})
+endif()
 
+if(HAVE_NVCUVENC)
   if(WIN32)
     list(APPEND extra_libs ${CUDA_nvcuvenc_LIBRARY})
   endif()
diff --git a/modules/cudacodec/include/opencv2/cudacodec.hpp b/modules/cudacodec/include/opencv2/cudacodec.hpp
index 610ecf6..a379edc 100644
--- a/modules/cudacodec/include/opencv2/cudacodec.hpp
+++ b/modules/cudacodec/include/opencv2/cudacodec.hpp
@@ -41,8 +41,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_CUDACODEC_HPP__
-#define __OPENCV_CUDACODEC_HPP__
+#ifndef OPENCV_CUDACODEC_HPP
+#define OPENCV_CUDACODEC_HPP
 
 #ifndef __cplusplus
 #  error cudacodec.hpp header must be compiled as C++
@@ -339,4 +339,4 @@ CV_EXPORTS Ptr<VideoReader> createVideoReader(const Ptr<RawVideoSource>& source)
 
 }} // namespace cv { namespace cudacodec {
 
-#endif /* __OPENCV_CUDACODEC_HPP__ */
+#endif /* OPENCV_CUDACODEC_HPP */
diff --git a/modules/cudacodec/perf/perf_precomp.hpp b/modules/cudacodec/perf/perf_precomp.hpp
index 593c84d..def2462 100644
--- a/modules/cudacodec/perf/perf_precomp.hpp
+++ b/modules/cudacodec/perf/perf_precomp.hpp
@@ -48,8 +48,8 @@
 #  endif
 #endif
 
-#ifndef __OPENCV_PERF_PRECOMP_HPP__
-#define __OPENCV_PERF_PRECOMP_HPP__
+#ifndef OPENCV_PERF_PRECOMP_HPP
+#define OPENCV_PERF_PRECOMP_HPP
 
 #include "opencv2/ts.hpp"
 #include "opencv2/ts/cuda_perf.hpp"
diff --git a/modules/cudacodec/src/precomp.hpp b/modules/cudacodec/src/precomp.hpp
index 80257a0..0abd7b0 100644
--- a/modules/cudacodec/src/precomp.hpp
+++ b/modules/cudacodec/src/precomp.hpp
@@ -41,8 +41,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_PRECOMP_H__
-#define __OPENCV_PRECOMP_H__
+#ifndef OPENCV_PRECOMP_H
+#define OPENCV_PRECOMP_H
 
 #include <cstdlib>
 #include <cstring>
@@ -61,7 +61,9 @@
     #ifdef WIN32
         #define NOMINMAX
         #include <windows.h>
-        #include <NVEncoderAPI.h>
+        #ifdef HAVE_NVCUVENC
+            #include <NVEncoderAPI.h>
+        #endif
     #else
         #include <pthread.h>
         #include <unistd.h>
@@ -78,4 +80,4 @@
     #include "../src/cap_ffmpeg_api.hpp"
 #endif
 
-#endif /* __OPENCV_PRECOMP_H__ */
+#endif /* OPENCV_PRECOMP_H */
diff --git a/modules/cudacodec/src/video_writer.cpp b/modules/cudacodec/src/video_writer.cpp
index 6faa9d3..f6b9fc7 100644
--- a/modules/cudacodec/src/video_writer.cpp
+++ b/modules/cudacodec/src/video_writer.cpp
@@ -47,7 +47,7 @@ using namespace cv;
 using namespace cv::cuda;
 using namespace cv::cudacodec;
 
-#if !defined(HAVE_NVCUVID) || !defined(WIN32)
+#if !defined(HAVE_NVCUVENC) || !defined(WIN32)
 
 cv::cudacodec::EncoderParams::EncoderParams() { throw_no_cuda(); }
 cv::cudacodec::EncoderParams::EncoderParams(const String&) { throw_no_cuda(); }
@@ -60,7 +60,7 @@ Ptr<VideoWriter> cv::cudacodec::createVideoWriter(const String&, Size, double, c
 Ptr<VideoWriter> cv::cudacodec::createVideoWriter(const Ptr<EncoderCallBack>&, Size, double, SurfaceFormat) { throw_no_cuda(); return Ptr<VideoWriter>(); }
 Ptr<VideoWriter> cv::cudacodec::createVideoWriter(const Ptr<EncoderCallBack>&, Size, double, const EncoderParams&, SurfaceFormat) { throw_no_cuda(); return Ptr<VideoWriter>(); }
 
-#else // !defined HAVE_CUDA || !defined WIN32
+#else // !defined HAVE_NVCUVENC || !defined WIN32
 
 void RGB_to_YV12(const GpuMat& src, GpuMat& dst);
 
@@ -913,4 +913,4 @@ Ptr<VideoWriter> cv::cudacodec::createVideoWriter(const Ptr<EncoderCallBack>& en
     return makePtr<VideoWriterImpl>(encoderCallback, frameSize, fps, params, format);
 }
 
-#endif // !defined HAVE_CUDA || !defined WIN32
+#endif // !defined HAVE_NVCUVENC || !defined WIN32
diff --git a/modules/cudacodec/test/test_precomp.hpp b/modules/cudacodec/test/test_precomp.hpp
index 5c5a142..a8fb713 100644
--- a/modules/cudacodec/test/test_precomp.hpp
+++ b/modules/cudacodec/test/test_precomp.hpp
@@ -48,8 +48,8 @@
 #  endif
 #endif
 
-#ifndef __OPENCV_TEST_PRECOMP_HPP__
-#define __OPENCV_TEST_PRECOMP_HPP__
+#ifndef OPENCV_TEST_PRECOMP_HPP
+#define OPENCV_TEST_PRECOMP_HPP
 
 #include "opencv2/ts.hpp"
 #include "opencv2/ts/cuda_test.hpp"
diff --git a/modules/cudafeatures2d/include/opencv2/cudafeatures2d.hpp b/modules/cudafeatures2d/include/opencv2/cudafeatures2d.hpp
index 1d7f4e4..27a0ddd 100644
--- a/modules/cudafeatures2d/include/opencv2/cudafeatures2d.hpp
+++ b/modules/cudafeatures2d/include/opencv2/cudafeatures2d.hpp
@@ -40,8 +40,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_CUDAFEATURES2D_HPP__
-#define __OPENCV_CUDAFEATURES2D_HPP__
+#ifndef OPENCV_CUDAFEATURES2D_HPP
+#define OPENCV_CUDAFEATURES2D_HPP
 
 #ifndef __cplusplus
 #  error cudafeatures2d.hpp header must be compiled as C++
@@ -486,4 +486,4 @@ public:
 
 }} // namespace cv { namespace cuda {
 
-#endif /* __OPENCV_CUDAFEATURES2D_HPP__ */
+#endif /* OPENCV_CUDAFEATURES2D_HPP */
diff --git a/modules/cudafeatures2d/src/cuda/orb.cu b/modules/cudafeatures2d/src/cuda/orb.cu
index 2e4f2e0..182ca4f 100644
--- a/modules/cudafeatures2d/src/cuda/orb.cu
+++ b/modules/cudafeatures2d/src/cuda/orb.cu
@@ -44,11 +44,14 @@
 
 #include <thrust/device_ptr.h>
 #include <thrust/sort.h>
+#include <thrust/system/cuda/execution_policy.h>
+#include <thrust/version.h>
+
 
 #include "opencv2/core/cuda/common.hpp"
 #include "opencv2/core/cuda/reduce.hpp"
 #include "opencv2/core/cuda/functional.hpp"
-
+#include "opencv2/core/cuda/utility.hpp"
 namespace cv { namespace cuda { namespace device
 {
     namespace orb
@@ -56,13 +59,32 @@ namespace cv { namespace cuda { namespace device
         ////////////////////////////////////////////////////////////////////////////////////////////////////////
         // cull
 
-        int cull_gpu(int* loc, float* response, int size, int n_points)
+        int cull_gpu(int* loc, float* response, int size, int n_points, cudaStream_t stream)
         {
             thrust::device_ptr<int> loc_ptr(loc);
             thrust::device_ptr<float> response_ptr(response);
-
+#if THRUST_VERSION >= 100800
+#if THRUST_VERSION >= 100802
+            if (stream)
+            {
+                thrust::sort_by_key(thrust::cuda::par(ThrustAllocator::getAllocator()).on(stream), response_ptr, response_ptr + size, loc_ptr, thrust::greater<float>());
+            }
+            else
+            {
+                thrust::sort_by_key(thrust::cuda::par(ThrustAllocator::getAllocator()), response_ptr, response_ptr + size, loc_ptr, thrust::greater<float>());
+            }
+#else
+            if(stream)
+            {
+                thrust::sort_by_key(thrust::cuda::par.on(stream), response_ptr, response_ptr + size, loc_ptr, thrust::greater<float>());
+            }else
+            {
+                thrust::sort_by_key(response_ptr, response_ptr + size, loc_ptr, thrust::greater<float>());
+            }
+#endif
+#else
             thrust::sort_by_key(response_ptr, response_ptr + size, loc_ptr, thrust::greater<float>());
-
+#endif
             return n_points;
         }
 
diff --git a/modules/cudafeatures2d/src/fast.cpp b/modules/cudafeatures2d/src/fast.cpp
index 2095ef7..ce44b3a 100644
--- a/modules/cudafeatures2d/src/fast.cpp
+++ b/modules/cudafeatures2d/src/fast.cpp
@@ -104,7 +104,7 @@ namespace
         }
 
         BufferPool pool(Stream::Null());
-        GpuMat d_keypoints = pool.getBuffer(ROWS_COUNT, max_npoints_, CV_16SC2);
+        GpuMat d_keypoints = pool.getBuffer(ROWS_COUNT, max_npoints_, CV_32FC1);
 
         detectAsync(_image, d_keypoints, _mask, Stream::Null());
         convert(d_keypoints, keypoints);
diff --git a/modules/cudafeatures2d/src/orb.cpp b/modules/cudafeatures2d/src/orb.cpp
index 6bfdd5a..41a431d 100644
--- a/modules/cudafeatures2d/src/orb.cpp
+++ b/modules/cudafeatures2d/src/orb.cpp
@@ -55,7 +55,7 @@ namespace cv { namespace cuda { namespace device
 {
     namespace orb
     {
-        int cull_gpu(int* loc, float* response, int size, int n_points);
+        int cull_gpu(int* loc, float* response, int size, int n_points, cudaStream_t stream);
 
         void HarrisResponses_gpu(PtrStepSzb img, const short2* loc, float* response, const int npoints, int blockSize, float harris_k, cudaStream_t stream);
 
@@ -401,10 +401,10 @@ namespace
         bool blurForDescriptor_;
 
     private:
-        void buildScalePyramids(InputArray _image, InputArray _mask);
-        void computeKeyPointsPyramid();
-        void computeDescriptors(OutputArray _descriptors);
-        void mergeKeyPoints(OutputArray _keypoints);
+        void buildScalePyramids(InputArray _image, InputArray _mask, Stream& stream);
+        void computeKeyPointsPyramid(Stream& stream);
+        void computeDescriptors(OutputArray _descriptors, Stream& stream);
+        void mergeKeyPoints(OutputArray _keypoints, Stream& stream);
 
     private:
         Ptr<cv::cuda::FastFeatureDetector> fastDetector_;
@@ -570,33 +570,95 @@ namespace
         blurFilter_ = cuda::createGaussianFilter(CV_8UC1, -1, Size(7, 7), 2, 2, BORDER_REFLECT_101);
     }
 
+    static float getScale(float scaleFactor, int firstLevel, int level)
+    {
+        return pow(scaleFactor, level - firstLevel);
+    }
+
     void ORB_Impl::detectAndCompute(InputArray _image, InputArray _mask, std::vector<KeyPoint>& keypoints, OutputArray _descriptors, bool useProvidedKeypoints)
     {
-        CV_Assert( useProvidedKeypoints == false );
+        using namespace cv::cuda::device::orb;
+        if (useProvidedKeypoints)
+        {
+            d_keypoints_.release();
+            keyPointsPyr_.clear();
 
-        detectAndComputeAsync(_image, _mask, d_keypoints_, _descriptors, false, Stream::Null());
-        convert(d_keypoints_, keypoints);
+            int j, level, nkeypoints = (int)keypoints.size();
+            nLevels_ = 0;
+            for( j = 0; j < nkeypoints; j++ )
+            {
+                level = keypoints[j].octave;
+                CV_Assert(level >= 0);
+                nLevels_ = std::max(nLevels_, level);
+            }
+            nLevels_ ++;
+            std::vector<std::vector<KeyPoint> > oKeypoints(nLevels_);
+            for( j = 0; j < nkeypoints; j++ )
+            {
+                level = keypoints[j].octave;
+                oKeypoints[level].push_back(keypoints[j]);
+            }
+            if (!keypoints.empty())
+            {
+                keyPointsPyr_.resize(nLevels_);
+                keyPointsCount_.resize(nLevels_);
+                int t;
+                for(t = 0; t < nLevels_; t++) {
+                    const std::vector<KeyPoint>& ks = oKeypoints[t];
+                    if (!ks.empty()){
+
+                        Mat h_keypoints(ROWS_COUNT, static_cast<int>(ks.size()), CV_32FC1);
+
+                        float sf = getScale(scaleFactor_, firstLevel_, t);
+                        float locScale = t != firstLevel_ ? sf : 1.0f;
+                        float scale = 1.f/locScale;
+
+                        short2* x_loc_row = h_keypoints.ptr<short2>(0);
+                        float* x_kp_hessian = h_keypoints.ptr<float>(1);
+                        float* x_kp_dir = h_keypoints.ptr<float>(2);
+
+                        for (size_t i = 0, size = ks.size(); i < size; ++i)
+                        {
+                            const KeyPoint& kp = ks[i];
+                            x_kp_hessian[i] = kp.response;
+                            x_loc_row[i].x = cvRound(kp.pt.x * scale);
+                            x_loc_row[i].y = cvRound(kp.pt.y * scale);
+                            x_kp_dir[i] = kp.angle;
+
+                        }
+
+                        keyPointsPyr_[t].upload(h_keypoints.rowRange(0,3));
+                        keyPointsCount_[t] = h_keypoints.cols;
+                    }
+                }
+            }
+        }
+
+        detectAndComputeAsync(_image, _mask, d_keypoints_, _descriptors, useProvidedKeypoints, Stream::Null());
+
+        if (!useProvidedKeypoints) {
+            convert(d_keypoints_, keypoints);
+        }
     }
 
     void ORB_Impl::detectAndComputeAsync(InputArray _image, InputArray _mask, OutputArray _keypoints, OutputArray _descriptors, bool useProvidedKeypoints, Stream& stream)
     {
-        CV_Assert( useProvidedKeypoints == false );
-
-        buildScalePyramids(_image, _mask);
-        computeKeyPointsPyramid();
+        buildScalePyramids(_image, _mask, stream);
+        if (!useProvidedKeypoints)
+        {
+           computeKeyPointsPyramid(stream);
+        }
         if (_descriptors.needed())
         {
-            computeDescriptors(_descriptors);
+            computeDescriptors(_descriptors, stream);
+        }
+        if (!useProvidedKeypoints)
+        {
+            mergeKeyPoints(_keypoints, stream);
         }
-        mergeKeyPoints(_keypoints);
-    }
-
-    static float getScale(float scaleFactor, int firstLevel, int level)
-    {
-        return pow(scaleFactor, level - firstLevel);
     }
 
-    void ORB_Impl::buildScalePyramids(InputArray _image, InputArray _mask)
+    void ORB_Impl::buildScalePyramids(InputArray _image, InputArray _mask, Stream& stream)
     {
         const GpuMat image = _image.getGpuMat();
         const GpuMat mask = _mask.getGpuMat();
@@ -622,42 +684,42 @@ namespace
             {
                 if (level < firstLevel_)
                 {
-                    cuda::resize(image, imagePyr_[level], sz, 0, 0, INTER_LINEAR);
+                    cuda::resize(image, imagePyr_[level], sz, 0, 0, INTER_LINEAR, stream);
 
                     if (!mask.empty())
-                        cuda::resize(mask, maskPyr_[level], sz, 0, 0, INTER_LINEAR);
+                        cuda::resize(mask, maskPyr_[level], sz, 0, 0, INTER_LINEAR, stream);
                 }
                 else
                 {
-                    cuda::resize(imagePyr_[level - 1], imagePyr_[level], sz, 0, 0, INTER_LINEAR);
+                    cuda::resize(imagePyr_[level - 1], imagePyr_[level], sz, 0, 0, INTER_LINEAR, stream);
 
                     if (!mask.empty())
                     {
-                        cuda::resize(maskPyr_[level - 1], maskPyr_[level], sz, 0, 0, INTER_LINEAR);
-                        cuda::threshold(maskPyr_[level], maskPyr_[level], 254, 0, THRESH_TOZERO);
+                        cuda::resize(maskPyr_[level - 1], maskPyr_[level], sz, 0, 0, INTER_LINEAR, stream);
+                        cuda::threshold(maskPyr_[level], maskPyr_[level], 254, 0, THRESH_TOZERO, stream);
                     }
                 }
             }
             else
             {
-                image.copyTo(imagePyr_[level]);
+                image.copyTo(imagePyr_[level], stream);
 
                 if (!mask.empty())
-                    mask.copyTo(maskPyr_[level]);
+                    mask.copyTo(maskPyr_[level], stream);
             }
 
             // Filter keypoints by image border
             ensureSizeIsEnough(sz, CV_8UC1, buf_);
-            buf_.setTo(Scalar::all(0));
+            buf_.setTo(Scalar::all(0), stream);
             Rect inner(edgeThreshold_, edgeThreshold_, sz.width - 2 * edgeThreshold_, sz.height - 2 * edgeThreshold_);
-            buf_(inner).setTo(Scalar::all(255));
+            buf_(inner).setTo(Scalar::all(255), stream);
 
-            cuda::bitwise_and(maskPyr_[level], buf_, maskPyr_[level]);
+            cuda::bitwise_and(maskPyr_[level], buf_, maskPyr_[level], cv::noArray(), stream);
         }
     }
 
     // takes keypoints and culls them by the response
-    static void cull(GpuMat& keypoints, int& count, int n_points)
+    static void cull(GpuMat& keypoints, int& count, int n_points, Stream& stream)
     {
         using namespace cv::cuda::device::orb;
 
@@ -670,11 +732,11 @@ namespace
                 return;
             }
 
-            count = cull_gpu(keypoints.ptr<int>(cuda::FastFeatureDetector::LOCATION_ROW), keypoints.ptr<float>(cuda::FastFeatureDetector::RESPONSE_ROW), count, n_points);
+            count = cull_gpu(keypoints.ptr<int>(cuda::FastFeatureDetector::LOCATION_ROW), keypoints.ptr<float>(cuda::FastFeatureDetector::RESPONSE_ROW), count, n_points, StreamAccessor::getStream(stream));
         }
     }
 
-    void ORB_Impl::computeKeyPointsPyramid()
+    void ORB_Impl::computeKeyPointsPyramid(Stream& stream)
     {
         using namespace cv::cuda::device::orb;
 
@@ -690,7 +752,7 @@ namespace
             fastDetector_->setMaxNumPoints(0.05 * imagePyr_[level].size().area());
 
             GpuMat fastKpRange;
-            fastDetector_->detectAsync(imagePyr_[level], fastKpRange, maskPyr_[level], Stream::Null());
+            fastDetector_->detectAsync(imagePyr_[level], fastKpRange, maskPyr_[level], stream);
 
             keyPointsCount_[level] = fastKpRange.cols;
 
@@ -698,28 +760,28 @@ namespace
                 continue;
 
             ensureSizeIsEnough(3, keyPointsCount_[level], fastKpRange.type(), keyPointsPyr_[level]);
-            fastKpRange.copyTo(keyPointsPyr_[level].rowRange(0, 2));
+            fastKpRange.copyTo(keyPointsPyr_[level].rowRange(0, 2), stream);
 
             const int n_features = static_cast<int>(n_features_per_level_[level]);
 
             if (scoreType_ == ORB::HARRIS_SCORE)
             {
                 // Keep more points than necessary as FAST does not give amazing corners
-                cull(keyPointsPyr_[level], keyPointsCount_[level], 2 * n_features);
+                cull(keyPointsPyr_[level], keyPointsCount_[level], 2 * n_features, stream);
 
                 // Compute the Harris cornerness (better scoring than FAST)
-                HarrisResponses_gpu(imagePyr_[level], keyPointsPyr_[level].ptr<short2>(0), keyPointsPyr_[level].ptr<float>(1), keyPointsCount_[level], 7, HARRIS_K, 0);
+                HarrisResponses_gpu(imagePyr_[level], keyPointsPyr_[level].ptr<short2>(0), keyPointsPyr_[level].ptr<float>(1), keyPointsCount_[level], 7, HARRIS_K, StreamAccessor::getStream(stream));
             }
 
             //cull to the final desired level, using the new Harris scores or the original FAST scores.
-            cull(keyPointsPyr_[level], keyPointsCount_[level], n_features);
+            cull(keyPointsPyr_[level], keyPointsCount_[level], n_features, stream);
 
             // Compute orientation
-            IC_Angle_gpu(imagePyr_[level], keyPointsPyr_[level].ptr<short2>(0), keyPointsPyr_[level].ptr<float>(2), keyPointsCount_[level], half_patch_size, 0);
+            IC_Angle_gpu(imagePyr_[level], keyPointsPyr_[level].ptr<short2>(0), keyPointsPyr_[level].ptr<float>(2), keyPointsCount_[level], half_patch_size, StreamAccessor::getStream(stream));
         }
     }
 
-    void ORB_Impl::computeDescriptors(OutputArray _descriptors)
+    void ORB_Impl::computeDescriptors(OutputArray _descriptors, Stream& stream)
     {
         using namespace cv::cuda::device::orb;
 
@@ -750,17 +812,17 @@ namespace
             {
                 // preprocess the resized image
                 ensureSizeIsEnough(imagePyr_[level].size(), imagePyr_[level].type(), buf_);
-                blurFilter_->apply(imagePyr_[level], buf_);
+                blurFilter_->apply(imagePyr_[level], buf_, stream);
             }
 
             computeOrbDescriptor_gpu(blurForDescriptor_ ? buf_ : imagePyr_[level], keyPointsPyr_[level].ptr<short2>(0), keyPointsPyr_[level].ptr<float>(2),
-                keyPointsCount_[level], pattern_.ptr<int>(0), pattern_.ptr<int>(1), descRange, descriptorSize(), WTA_K_, 0);
+                keyPointsCount_[level], pattern_.ptr<int>(0), pattern_.ptr<int>(1), descRange, descriptorSize(), WTA_K_, StreamAccessor::getStream(stream));
 
             offset += keyPointsCount_[level];
         }
     }
 
-    void ORB_Impl::mergeKeyPoints(OutputArray _keypoints)
+    void ORB_Impl::mergeKeyPoints(OutputArray _keypoints, Stream& stream)
     {
         using namespace cv::cuda::device::orb;
 
@@ -791,13 +853,13 @@ namespace
 
             float locScale = level != firstLevel_ ? sf : 1.0f;
 
-            mergeLocation_gpu(keyPointsPyr_[level].ptr<short2>(0), keyPointsRange.ptr<float>(0), keyPointsRange.ptr<float>(1), keyPointsCount_[level], locScale, 0);
+            mergeLocation_gpu(keyPointsPyr_[level].ptr<short2>(0), keyPointsRange.ptr<float>(0), keyPointsRange.ptr<float>(1), keyPointsCount_[level], locScale, StreamAccessor::getStream(stream));
 
             GpuMat range = keyPointsRange.rowRange(2, 4);
-            keyPointsPyr_[level](Range(1, 3), Range(0, keyPointsCount_[level])).copyTo(range);
+            keyPointsPyr_[level](Range(1, 3), Range(0, keyPointsCount_[level])).copyTo(range, stream);
 
-            keyPointsRange.row(4).setTo(Scalar::all(level));
-            keyPointsRange.row(5).setTo(Scalar::all(patchSize_ * sf));
+            keyPointsRange.row(4).setTo(Scalar::all(level), stream);
+            keyPointsRange.row(5).setTo(Scalar::all(patchSize_ * sf), stream);
 
             offset += keyPointsCount_[level];
         }
diff --git a/modules/cudafeatures2d/test/test_features2d.cpp b/modules/cudafeatures2d/test/test_features2d.cpp
index 3046a60..7fccd9e 100644
--- a/modules/cudafeatures2d/test/test_features2d.cpp
+++ b/modules/cudafeatures2d/test/test_features2d.cpp
@@ -55,6 +55,8 @@ namespace
     IMPLEMENT_PARAM_CLASS(FAST_NonmaxSuppression, bool)
 }
 
+namespace {
+
 PARAM_TEST_CASE(FAST, cv::cuda::DeviceInfo, FAST_Threshold, FAST_NonmaxSuppression)
 {
     cv::cuda::DeviceInfo devInfo;
@@ -708,4 +710,6 @@ INSTANTIATE_TEST_CASE_P(CUDA_Features2D, BruteForceMatcher, testing::Combine(
     testing::Values(DescriptorSize(57), DescriptorSize(64), DescriptorSize(83), DescriptorSize(128), DescriptorSize(179), DescriptorSize(256), DescriptorSize(304)),
     testing::Values(UseMask(false), UseMask(true))));
 
+} // namespace
+
 #endif // HAVE_CUDA
diff --git a/modules/cudafilters/include/opencv2/cudafilters.hpp b/modules/cudafilters/include/opencv2/cudafilters.hpp
index 9e86cc3..1e25e56 100644
--- a/modules/cudafilters/include/opencv2/cudafilters.hpp
+++ b/modules/cudafilters/include/opencv2/cudafilters.hpp
@@ -40,8 +40,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_CUDAFILTERS_HPP__
-#define __OPENCV_CUDAFILTERS_HPP__
+#ifndef OPENCV_CUDAFILTERS_HPP
+#define OPENCV_CUDAFILTERS_HPP
 
 #ifndef __cplusplus
 #  error cudafilters.hpp header must be compiled as C++
@@ -89,7 +89,7 @@ public:
 
 /** @brief Creates a normalized 2D box filter.
 
- at param srcType Input image type. Only CV_8UC1 and CV_8UC4 are supported for now.
+ at param srcType Input image type. Only CV_8UC1, CV_8UC4 and CV_32FC1 are supported for now.
 @param dstType Output image type. Only the same type as src is supported for now.
 @param ksize Kernel size.
 @param anchor Anchor point. The default value Point(-1, -1) means that the anchor is at the kernel
@@ -250,7 +250,7 @@ CV_EXPORTS Ptr<Filter> createGaussianFilter(int srcType, int dstType, Size ksize
 -   **MORPH_GRADIENT** morphological gradient
 -   **MORPH_TOPHAT** "top hat"
 -   **MORPH_BLACKHAT** "black hat"
- at param srcType Input/output image type. Only CV_8UC1 and CV_8UC4 are supported.
+ at param srcType Input/output image type. Only CV_8UC1, CV_8UC4, CV_32FC1 and CV_32FC4 are supported.
 @param kernel 2D 8-bit structuring element for the morphological operation.
 @param anchor Anchor position within the structuring element. Negative values mean that the anchor
 is at the center.
@@ -314,6 +314,18 @@ CV_EXPORTS Ptr<Filter> createColumnSumFilter(int srcType, int dstType, int ksize
 
 //! @}
 
+///////////////////////////// Median Filtering //////////////////////////////
+
+/** @brief Performs median filtering for each point of the source image.
+
+ at param srcType type of of source image. Only CV_8UC1 images are supported for now.
+ at param windowSize Size of the kernerl used for the filtering. Uses a (windowSize x windowSize) filter.
+ at param partition Specifies the parallel granularity of the workload. This parameter should be used GPU experts when optimizing performance.
+
+Outputs an image that has been filtered using median-filtering formulation.
+ */
+CV_EXPORTS Ptr<Filter> createMedianFilter(int srcType, int windowSize, int partition=128);
+
 }} // namespace cv { namespace cuda {
 
-#endif /* __OPENCV_CUDAFILTERS_HPP__ */
+#endif /* OPENCV_CUDAFILTERS_HPP */
diff --git a/modules/cudafilters/perf/perf_filters.cpp b/modules/cudafilters/perf/perf_filters.cpp
index e6bb200..cac7e8e 100644
--- a/modules/cudafilters/perf/perf_filters.cpp
+++ b/modules/cudafilters/perf/perf_filters.cpp
@@ -53,7 +53,7 @@ DEF_PARAM_TEST(Sz_Type_KernelSz, cv::Size, MatType, int);
 
 PERF_TEST_P(Sz_Type_KernelSz, Blur,
             Combine(CUDA_TYPICAL_MAT_SIZES,
-                    Values(CV_8UC1, CV_8UC4),
+                    Values(CV_8UC1, CV_8UC4, CV_32FC1),
                     Values(3, 5, 7)))
 {
     declare.time(20.0);
@@ -375,3 +375,43 @@ PERF_TEST_P(Sz_Type_Op, MorphologyEx, Combine(CUDA_TYPICAL_MAT_SIZES, Values(CV_
         CPU_SANITY_CHECK(dst);
     }
 }
+//////////////////////////////////////////////////////////////////////
+// MedianFilter
+//////////////////////////////////////////////////////////////////////
+// Median
+
+DEF_PARAM_TEST(Sz_KernelSz, cv::Size, int);
+
+//PERF_TEST_P(Sz_Type_KernelSz, Median, Combine(CUDA_TYPICAL_MAT_SIZES, Values(CV_8UC1,CV_8UC1), Values(3, 5, 7, 9, 11, 13, 15)))
+PERF_TEST_P(Sz_KernelSz, Median, Combine(CUDA_TYPICAL_MAT_SIZES, Values(3, 5, 7, 9, 11, 13, 15)))
+{
+    declare.time(20.0);
+
+    const cv::Size size = GET_PARAM(0);
+    // const int type = GET_PARAM(1);
+    const int type = CV_8UC1;
+    const int kernel = GET_PARAM(1);
+
+    cv::Mat src(size, type);
+    declare.in(src, WARMUP_RNG);
+
+    if (PERF_RUN_CUDA())
+    {
+        const cv::cuda::GpuMat d_src(src);
+        cv::cuda::GpuMat dst;
+
+        cv::Ptr<cv::cuda::Filter> median = cv::cuda::createMedianFilter(d_src.type(), kernel);
+
+        TEST_CYCLE() median->apply(d_src, dst);
+
+        SANITY_CHECK_NOTHING();
+    }
+    else
+    {
+        cv::Mat dst;
+
+        TEST_CYCLE() cv::medianBlur(src,dst,kernel);
+
+        SANITY_CHECK_NOTHING();
+    }
+}
\ No newline at end of file
diff --git a/modules/cudafilters/src/cuda/median_filter.cu b/modules/cudafilters/src/cuda/median_filter.cu
new file mode 100644
index 0000000..f66b429
--- /dev/null
+++ b/modules/cudafilters/src/cuda/median_filter.cu
@@ -0,0 +1,348 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+//  By downloading, copying, installing or using the software you agree to this license.
+//  If you do not agree to this license, do not download, install,
+//  copy or use the software.
+//
+//
+//                           License Agreement
+//                For Open Source Computer Vision Library
+//
+// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
+// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+//   * Redistribution's of source code must retain the above copyright notice,
+//     this list of conditions and the following disclaimer.
+//
+//   * Redistribution's in binary form must reproduce the above copyright notice,
+//     this list of conditions and the following disclaimer in the documentation
+//     and/or other materials provided with the distribution.
+//
+//   * The name of the copyright holders may not be used to endorse or promote products
+//     derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#if !defined CUDA_DISABLER
+
+#include "precomp.hpp"
+
+using namespace cv;
+using namespace cv::cuda;
+
+#include "opencv2/core/cuda/common.hpp"
+#include "opencv2/core/cuda/vec_traits.hpp"
+#include "opencv2/core/cuda/vec_math.hpp"
+#include "opencv2/core/cuda/saturate_cast.hpp"
+#include "opencv2/core/cuda/border_interpolate.hpp"
+
+namespace cv { namespace cuda { namespace device
+{
+    // // namespace imgproc
+    // {
+
+        __device__ void histogramAddAndSub8(int* H, const int * hist_colAdd,const int * hist_colSub){
+            int tx = threadIdx.x;
+            if (tx<8){
+                H[tx]+=hist_colAdd[tx]-hist_colSub[tx];
+            }
+        }
+
+        __device__ void histogramMultipleAdd8(int* H, const int * hist_col,int histCount){
+            int tx = threadIdx.x;
+            if (tx<8){
+                int temp=H[tx];
+                for(int i=0; i<histCount; i++)
+                    temp+=hist_col[(i<<3)+tx];
+                H[tx]=temp;
+            }
+        }
+
+        __device__ void histogramClear8(int* H){
+            int tx = threadIdx.x;
+            if (tx<8){
+                H[tx]=0;
+            }
+        }
+
+        __device__ void histogramAdd8(int* H, const int * hist_col){
+            int tx = threadIdx.x;
+            if (tx<8){
+                H[tx]+=hist_col[tx];
+            }
+        }
+
+        __device__ void histogramSub8(int* H, const int * hist_col){
+            int tx = threadIdx.x;
+            if (tx<8){
+                H[tx]-=hist_col[tx];
+            }
+        }
+
+
+        __device__ void histogramAdd32(int* H, const int * hist_col){
+            int tx = threadIdx.x;
+            if (tx<32){
+                H[tx]+=hist_col[tx];
+            }
+        }
+
+        __device__ void histogramAddAndSub32(int* H, const int * hist_colAdd,const int * hist_colSub){
+            int tx = threadIdx.x;
+            if (tx<32){
+                H[tx]+=hist_colAdd[tx]-hist_colSub[tx];
+            }
+        }
+
+
+        __device__ void histogramClear32(int* H){
+            int tx = threadIdx.x;
+            if (tx<32){
+                H[tx]=0;
+            }
+        }
+
+        __device__ void lucClear8(int* luc){
+            int tx = threadIdx.x;
+            if (tx<8)
+                luc[tx]=0;
+        }
+
+        __device__ void histogramMedianPar8LookupOnly(int* H,int* Hscan, const int medPos,int* retval, int* countAtMed){
+            int tx=threadIdx.x;
+            *retval=*countAtMed=0;
+            if(tx<8){
+                Hscan[tx]=H[tx];
+            }
+            __syncthreads();
+            if(tx<8){
+                if(tx>=1 )
+                  Hscan[tx]+=Hscan[tx-1];
+                if(tx>=2)
+                  Hscan[tx]+=Hscan[tx-2];
+                if(tx>=4)
+                  Hscan[tx]+=Hscan[tx-4];
+            }
+            __syncthreads();
+
+            if(tx<7){
+                if(Hscan[tx+1] > medPos && Hscan[tx] < medPos){
+                    *retval=tx+1;
+                    *countAtMed=Hscan[tx];
+                }
+                else if(Hscan[tx]==medPos){
+                  if(Hscan[tx+1]>medPos){
+                     *retval=tx+1;
+                     *countAtMed=Hscan[tx];
+                  }
+                }
+            }
+        }
+
+        __device__ void histogramMedianPar32LookupOnly(int* H,int* Hscan, const int medPos,int* retval, int* countAtMed){
+            int tx=threadIdx.x;
+            *retval=*countAtMed=0;
+            if(tx<32){
+                Hscan[tx]=H[tx];
+            }
+            __syncthreads();
+            if(tx<32){
+                if(tx>=1)
+                  Hscan[tx]+=Hscan[tx-1];
+                if(tx>=2)
+                  Hscan[tx]+=Hscan[tx-2];
+                if(tx>=4)
+                  Hscan[tx]+=Hscan[tx-4];
+                if(tx>=8)
+                  Hscan[tx]+=Hscan[tx-8];
+                if(tx>=16)
+                  Hscan[tx]+=Hscan[tx-16];
+            }
+            __syncthreads();
+            if(tx<31){
+                if(Hscan[tx+1] > medPos && Hscan[tx] < medPos){
+                    *retval=tx+1;
+                    *countAtMed=Hscan[tx];
+                }
+                else if(Hscan[tx]==medPos){
+                  if(Hscan[tx+1]>medPos){
+                      *retval=tx+1;
+                      *countAtMed=Hscan[tx];
+                  }
+                }
+            }
+         }
+
+    __global__ void cuMedianFilterMultiBlock(PtrStepSzb src, PtrStepSzb  dest, PtrStepSzi histPar, PtrStepSzi coarseHistGrid,int r, int medPos_)
+    {
+        __shared__ int HCoarse[8];
+        __shared__ int HCoarseScan[32];
+        __shared__ int HFine[8][32];
+
+        __shared__ int luc[8];
+
+        __shared__ int firstBin,countAtMed, retval;
+
+        int rows = src.rows, cols=src.cols;
+
+        int extraRowThread=rows%gridDim.x;
+        int doExtraRow=blockIdx.x<extraRowThread;
+        int startRow=0, stopRow=0;
+        int rowsPerBlock= rows/gridDim.x+doExtraRow;
+
+
+        // The following code partitions the work to the blocks. Some blocks will do one row more
+        // than other blocks. This code is responsible for doing that balancing
+        if(doExtraRow){
+            startRow=rowsPerBlock*blockIdx.x;
+            stopRow=::min(rows, startRow+rowsPerBlock);
+        }
+        else{
+            startRow=(rowsPerBlock+1)*extraRowThread+(rowsPerBlock)*(blockIdx.x-extraRowThread);
+            stopRow=::min(rows, startRow+rowsPerBlock);
+        }
+
+        int* hist= histPar.data+cols*256*blockIdx.x;
+        int* histCoarse=coarseHistGrid.data +cols*8*blockIdx.x;
+
+        if (blockIdx.x==(gridDim.x-1))
+            stopRow=rows;
+        __syncthreads();
+        int initNeeded=0, initVal, initStartRow, initStopRow;
+
+        if(blockIdx.x==0){
+            initNeeded=1; initVal=r+2; initStartRow=1;  initStopRow=r;
+        }
+        else if (startRow<(r+2)){
+            initNeeded=1; initVal=r+2-startRow; initStartRow=1; initStopRow=r+startRow;
+        }
+        else{
+            initNeeded=0; initVal=0; initStartRow=startRow-(r+1);   initStopRow=r+startRow;
+        }
+       __syncthreads();
+
+
+        // In the original algorithm an initialization phase was required as part of the window was outside the
+        // image. In this parallel version, the initializtion is required for all thread blocks that part
+        // of the median filter is outside the window.
+        // For all threads in the block the same code will be executed.
+        if (initNeeded){
+            for (int j=threadIdx.x; j<(cols); j+=blockDim.x){
+                hist[j*256+src.ptr(0)[j]]=initVal;
+                histCoarse[j*8+(src.ptr(0)[j]>>5)]=initVal;
+            }
+        }
+        __syncthreads();
+
+        // Fot all remaining rows in the median filter, add the values to the the histogram
+        for (int j=threadIdx.x; j<cols; j+=blockDim.x){
+            for(int i=initStartRow; i<initStopRow; i++){
+                    int pos=::min(i,rows-1);
+                    hist[j*256+src.ptr(pos)[j]]++;
+                    histCoarse[j*8+(src.ptr(pos)[j]>>5)]++;
+                }
+        }
+        __syncthreads();
+         // Going through all the rows that the block is responsible for.
+         int inc=blockDim.x*256;
+         int incCoarse=blockDim.x*8;
+         for(int i=startRow; i< stopRow; i++){
+             // For every new row that is started the global histogram for the entire window is restarted.
+
+             histogramClear8(HCoarse);
+             lucClear8(luc);
+             // Computing some necessary indices
+             int possub=::max(0,i-r-1),posadd=::min(rows-1,i+r);
+             int histPos=threadIdx.x*256;
+             int histCoarsePos=threadIdx.x*8;
+             // Going through all the elements of a specific row. Foeach histogram, a value is taken out and
+             // one value is added.
+             for (int j=threadIdx.x; j<cols; j+=blockDim.x){
+                hist[histPos+ src.ptr(possub)[j] ]--;
+                hist[histPos+ src.ptr(posadd)[j] ]++;
+                histCoarse[histCoarsePos+ (src.ptr(possub)[j]>>5) ]--;
+                histCoarse[histCoarsePos+ (src.ptr(posadd)[j]>>5) ]++;
+
+                histPos+=inc;
+                histCoarsePos+=incCoarse;
+             }
+            __syncthreads();
+
+            histogramMultipleAdd8(HCoarse,histCoarse, 2*r+1);
+//            __syncthreads();
+            int cols_m_1=cols-1;
+
+             for(int j=r;j<cols-r;j++){
+                int possub=::max(j-r,0);
+                int posadd=::min(j+1+r,cols_m_1);
+                int medPos=medPos_;
+                __syncthreads();
+
+                histogramMedianPar8LookupOnly(HCoarse,HCoarseScan,medPos, &firstBin,&countAtMed);
+                __syncthreads();
+
+                if ( luc[firstBin] <= (j-r))
+                {
+                    histogramClear32(HFine[firstBin]);
+                    for ( luc[firstBin] = j-r; luc[firstBin] < ::min(j+r+1,cols); luc[firstBin]++ ){
+                        histogramAdd32(HFine[firstBin], hist+(luc[firstBin]*256+(firstBin<<5) ) );
+                    }
+                }
+                else{
+                    for ( ; luc[firstBin] < (j+r+1);luc[firstBin]++ ) {
+                        histogramAddAndSub32(HFine[firstBin],
+                        hist+(::min(luc[firstBin],cols_m_1)*256+(firstBin<<5) ),
+                        hist+(::max(luc[firstBin]-2*r-1,0)*256+(firstBin<<5) ) );
+                        __syncthreads();
+
+                    }
+                }
+                __syncthreads();
+
+                int leftOver=medPos-countAtMed;
+                if(leftOver>=0){
+                    histogramMedianPar32LookupOnly(HFine[firstBin],HCoarseScan,leftOver,&retval,&countAtMed);
+                }
+                else retval=0;
+                __syncthreads();
+
+                if (threadIdx.x==0){
+                    dest.ptr(i)[j]=(firstBin<<5) + retval;
+                }
+                histogramAddAndSub8(HCoarse, histCoarse+(int)(posadd<<3),histCoarse+(int)(possub<<3));
+
+                __syncthreads();
+            }
+             __syncthreads();
+        }
+    }
+
+    void medianFiltering_gpu(const PtrStepSzb src, PtrStepSzb dst, PtrStepSzi devHist, PtrStepSzi devCoarseHist,int kernel, int partitions,cudaStream_t stream){
+        int medPos=2*kernel*kernel+2*kernel;
+        dim3 gridDim; gridDim.x=partitions;
+        dim3 blockDim; blockDim.x=32;
+        cuMedianFilterMultiBlock<<<gridDim,blockDim,0, stream>>>(src, dst, devHist,devCoarseHist, kernel, medPos);
+        if (!stream)
+            cudaSafeCall( cudaDeviceSynchronize() );
+    }
+
+}}}
+
+#endif
diff --git a/modules/cudafilters/src/filtering.cpp b/modules/cudafilters/src/filtering.cpp
index ed72a3a..21efde0 100644
--- a/modules/cudafilters/src/filtering.cpp
+++ b/modules/cudafilters/src/filtering.cpp
@@ -69,6 +69,8 @@ Ptr<Filter> cv::cuda::createBoxMinFilter(int, Size, Point, int, Scalar) { throw_
 Ptr<Filter> cv::cuda::createRowSumFilter(int, int, int, int, int, Scalar) { throw_no_cuda(); return Ptr<Filter>(); }
 Ptr<Filter> cv::cuda::createColumnSumFilter(int, int, int, int, int, Scalar) { throw_no_cuda(); return Ptr<Filter>(); }
 
+Ptr<Filter> cv::cuda::createMedianFilter(int srcType, int _windowSize, int _partitions){ throw_no_cuda(); return Ptr<Filter>();}
+
 #else
 
 namespace
@@ -101,13 +103,14 @@ namespace
         void apply(InputArray src, OutputArray dst, Stream& stream = Stream::Null());
 
     private:
-        typedef NppStatus (*nppFilterBox_t)(const Npp8u* pSrc, Npp32s nSrcStep, Npp8u* pDst, Npp32s nDstStep,
+        typedef NppStatus (*nppFilterBox8U_t)(const Npp8u* pSrc, Npp32s nSrcStep, Npp8u* pDst, Npp32s nDstStep,
+                                            NppiSize oSizeROI, NppiSize oMaskSize, NppiPoint oAnchor);
+        typedef NppStatus (*nppFilterBox32F_t)(const Npp32f* pSrc, Npp32s nSrcStep, Npp32f* pDst, Npp32s nDstStep,
                                             NppiSize oSizeROI, NppiSize oMaskSize, NppiPoint oAnchor);
 
         Size ksize_;
         Point anchor_;
         int type_;
-        nppFilterBox_t func_;
         int borderMode_;
         Scalar borderVal_;
         GpuMat srcBorder_;
@@ -116,14 +119,10 @@ namespace
     NPPBoxFilter::NPPBoxFilter(int srcType, int dstType, Size ksize, Point anchor, int borderMode, Scalar borderVal) :
         ksize_(ksize), anchor_(anchor), type_(srcType), borderMode_(borderMode), borderVal_(borderVal)
     {
-        static const nppFilterBox_t funcs[] = {0, nppiFilterBox_8u_C1R, 0, 0, nppiFilterBox_8u_C4R};
-
-        CV_Assert( srcType == CV_8UC1 || srcType == CV_8UC4 );
+        CV_Assert( srcType == CV_8UC1 || srcType == CV_8UC4 || srcType == CV_32FC1);
         CV_Assert( dstType == srcType );
 
         normalizeAnchor(anchor_, ksize);
-
-        func_ = funcs[CV_MAT_CN(srcType)];
     }
 
     void NPPBoxFilter::apply(InputArray _src, OutputArray _dst, Stream& _stream)
@@ -153,10 +152,30 @@ namespace
         oAnchor.x = anchor_.x;
         oAnchor.y = anchor_.y;
 
-        nppSafeCall( func_(srcRoi.ptr<Npp8u>(), static_cast<int>(srcRoi.step),
-                           dst.ptr<Npp8u>(), static_cast<int>(dst.step),
-                           oSizeROI, oMaskSize, oAnchor) );
+        const int depth = CV_MAT_DEPTH(type_);
+        const int cn = CV_MAT_CN(type_);
 
+        switch (depth)
+        {
+        case CV_8U:
+        {
+            static const nppFilterBox8U_t funcs8U[] = { 0, nppiFilterBox_8u_C1R, 0, 0, nppiFilterBox_8u_C4R };
+            const nppFilterBox8U_t func8U = funcs8U[cn];
+            nppSafeCall(func8U(srcRoi.ptr<Npp8u>(), static_cast<int>(srcRoi.step),
+                dst.ptr<Npp8u>(), static_cast<int>(dst.step),
+                oSizeROI, oMaskSize, oAnchor));
+        }
+            break;
+        case CV_32F:
+        {
+            static const nppFilterBox32F_t funcs32F[] = { 0, nppiFilterBox_32f_C1R, 0, 0, 0 };
+            const nppFilterBox32F_t func32F = funcs32F[cn];
+            nppSafeCall(func32F(srcRoi.ptr<Npp32f>(), static_cast<int>(srcRoi.step),
+                dst.ptr<Npp32f>(), static_cast<int>(dst.step),
+                oSizeROI, oMaskSize, oAnchor));
+        }
+            break;
+        }
         if (stream == 0)
             cudaSafeCall( cudaDeviceSynchronize() );
     }
@@ -506,14 +525,17 @@ namespace
         void apply(InputArray src, OutputArray dst, Stream& stream = Stream::Null());
 
     private:
-        typedef NppStatus (*nppMorfFilter_t)(const Npp8u* pSrc, Npp32s nSrcStep, Npp8u* pDst, Npp32s nDstStep, NppiSize oSizeROI,
-                                             const Npp8u* pMask, NppiSize oMaskSize, NppiPoint oAnchor);
+        typedef NppStatus (*nppMorfFilter8u_t)(const Npp8u* pSrc, Npp32s nSrcStep, Npp8u* pDst, Npp32s nDstStep, NppiSize oSizeROI,
+                                               const Npp8u* pMask, NppiSize oMaskSize, NppiPoint oAnchor);
+        typedef NppStatus (*nppMorfFilter32f_t)(const Npp32f* pSrc, Npp32s nSrcStep, Npp32f* pDst, Npp32s nDstStep, NppiSize oSizeROI,
+                                                const Npp8u* pMask, NppiSize oMaskSize, NppiPoint oAnchor);
 
         int type_;
         GpuMat kernel_;
         Point anchor_;
         int iters_;
-        nppMorfFilter_t func_;
+        nppMorfFilter8u_t func8u_;
+        nppMorfFilter32f_t func32f_;
 
         GpuMat srcBorder_;
         GpuMat buf_;
@@ -522,14 +544,19 @@ namespace
     MorphologyFilter::MorphologyFilter(int op, int srcType, InputArray _kernel, Point anchor, int iterations) :
         type_(srcType), anchor_(anchor), iters_(iterations)
     {
-        static const nppMorfFilter_t funcs[2][5] =
+        static const nppMorfFilter8u_t funcs8u[2][5] =
         {
             {0, nppiErode_8u_C1R, 0, 0, nppiErode_8u_C4R },
             {0, nppiDilate_8u_C1R, 0, 0, nppiDilate_8u_C4R }
         };
+        static const nppMorfFilter32f_t funcs32f[2][5] =
+        {
+            {0, nppiErode_32f_C1R, 0, 0, nppiErode_32f_C4R },
+            {0, nppiDilate_32f_C1R, 0, 0, nppiDilate_32f_C4R }
+        };
 
         CV_Assert( op == MORPH_ERODE || op == MORPH_DILATE );
-        CV_Assert( srcType == CV_8UC1 || srcType == CV_8UC4 );
+        CV_Assert( srcType == CV_8UC1 || srcType == CV_8UC4 || srcType == CV_32FC1 || srcType == CV_32FC4 );
 
         Mat kernel = _kernel.getMat();
         Size ksize = !kernel.empty() ? _kernel.size() : Size(3, 3);
@@ -560,7 +587,14 @@ namespace
         kernel_ = cuda::createContinuous(kernel.size(), CV_8UC1);
         kernel_.upload(kernel8U);
 
-        func_ = funcs[op][CV_MAT_CN(srcType)];
+        if(srcType == CV_8UC1 || srcType == CV_8UC4)
+        {
+            func8u_ = funcs8u[op][CV_MAT_CN(srcType)];
+        }
+        else if(srcType == CV_32FC1 || srcType == CV_32FC4)
+        {
+            func32f_ = funcs32f[op][CV_MAT_CN(srcType)];
+        }
     }
 
     void MorphologyFilter::apply(InputArray _src, OutputArray _dst, Stream& _stream)
@@ -599,15 +633,31 @@ namespace
         oAnchor.x = anchor_.x;
         oAnchor.y = anchor_.y;
 
-        nppSafeCall( func_(srcRoi.ptr<Npp8u>(), static_cast<int>(srcRoi.step), dst.ptr<Npp8u>(), static_cast<int>(dst.step),
-                           oSizeROI, kernel_.ptr<Npp8u>(), oMaskSize, oAnchor) );
+        if (type_ == CV_8UC1 || type_ == CV_8UC4)
+        {
+            nppSafeCall( func8u_(srcRoi.ptr<Npp8u>(), static_cast<int>(srcRoi.step), dst.ptr<Npp8u>(), static_cast<int>(dst.step),
+                                 oSizeROI, kernel_.ptr<Npp8u>(), oMaskSize, oAnchor) );
 
-        for(int i = 1; i < iters_; ++i)
+            for(int i = 1; i < iters_; ++i)
+            {
+                dst.copyTo(bufRoi, _stream);
+
+                nppSafeCall( func8u_(bufRoi.ptr<Npp8u>(), static_cast<int>(bufRoi.step), dst.ptr<Npp8u>(), static_cast<int>(dst.step),
+                                     oSizeROI, kernel_.ptr<Npp8u>(), oMaskSize, oAnchor) );
+            }
+        }
+        else if (type_ == CV_32FC1 || type_ == CV_32FC4)
         {
-            dst.copyTo(bufRoi, _stream);
+            nppSafeCall( func32f_(srcRoi.ptr<Npp32f>(), static_cast<int>(srcRoi.step), dst.ptr<Npp32f>(), static_cast<int>(dst.step),
+                                  oSizeROI, kernel_.ptr<Npp8u>(), oMaskSize, oAnchor) );
 
-            nppSafeCall( func_(bufRoi.ptr<Npp8u>(), static_cast<int>(bufRoi.step), dst.ptr<Npp8u>(), static_cast<int>(dst.step),
-                               oSizeROI, kernel_.ptr<Npp8u>(), oMaskSize, oAnchor) );
+            for(int i = 1; i < iters_; ++i)
+            {
+                dst.copyTo(bufRoi, _stream);
+
+                nppSafeCall( func32f_(bufRoi.ptr<Npp32f>(), static_cast<int>(bufRoi.step), dst.ptr<Npp32f>(), static_cast<int>(dst.step),
+                                      oSizeROI, kernel_.ptr<Npp8u>(), oMaskSize, oAnchor) );
+            }
         }
 
         if (stream == 0)
@@ -995,4 +1045,74 @@ Ptr<Filter> cv::cuda::createColumnSumFilter(int srcType, int dstType, int ksize,
     return makePtr<NppColumnSumFilter>(srcType, dstType, ksize, anchor, borderMode, borderVal);
 }
 
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Median Filter
+
+
+
+namespace cv { namespace cuda { namespace device
+{
+    void medianFiltering_gpu(const PtrStepSzb src, PtrStepSzb dst, PtrStepSzi devHist,
+        PtrStepSzi devCoarseHist,int kernel, int partitions, cudaStream_t stream);
+}}}
+
+namespace
+{
+    class MedianFilter : public Filter
+    {
+    public:
+        MedianFilter(int srcType, int _windowSize, int _partitions=128);
+
+        void apply(InputArray src, OutputArray dst, Stream& stream = Stream::Null());
+
+    private:
+        int windowSize;
+        int partitions;
+    };
+
+    MedianFilter::MedianFilter(int srcType, int _windowSize, int _partitions) :
+        windowSize(_windowSize),partitions(_partitions)
+    {
+        CV_Assert( srcType == CV_8UC1 );
+        CV_Assert(windowSize>=3);
+        CV_Assert(_partitions>=1);
+
+    }
+
+    void MedianFilter::apply(InputArray _src, OutputArray _dst, Stream& _stream)
+    {
+        using namespace cv::cuda::device;
+
+        GpuMat src = _src.getGpuMat();
+         _dst.create(src.rows, src.cols, src.type());
+        GpuMat dst = _dst.getGpuMat();
+
+        if (partitions>src.rows)
+            partitions=src.rows/2;
+
+        // Kernel needs to be half window size
+        int kernel=windowSize/2;
+
+        CV_Assert(kernel < src.rows);
+        CV_Assert(kernel < src.cols);
+
+        // Note - these are hardcoded in the actual GPU kernel. Do not change these values.
+        int histSize=256, histCoarseSize=8;
+
+        BufferPool pool(_stream);
+        GpuMat devHist = pool.getBuffer(1, src.cols*histSize*partitions,CV_32SC1);
+        GpuMat devCoarseHist = pool.getBuffer(1,src.cols*histCoarseSize*partitions,CV_32SC1);
+
+        devHist.setTo(0, _stream);
+        devCoarseHist.setTo(0, _stream);
+
+        medianFiltering_gpu(src,dst,devHist, devCoarseHist,kernel,partitions,StreamAccessor::getStream(_stream));
+    }
+}
+
+Ptr<Filter> cv::cuda::createMedianFilter(int srcType, int _windowSize, int _partitions)
+{
+    return makePtr<MedianFilter>(srcType, _windowSize,_partitions);
+}
+
 #endif
diff --git a/modules/cudafilters/test/test_filters.cpp b/modules/cudafilters/test/test_filters.cpp
index 97661b0..25c2fb9 100644
--- a/modules/cudafilters/test/test_filters.cpp
+++ b/modules/cudafilters/test/test_filters.cpp
@@ -53,6 +53,7 @@ namespace
     IMPLEMENT_PARAM_CLASS(Deriv_X, int)
     IMPLEMENT_PARAM_CLASS(Deriv_Y, int)
     IMPLEMENT_PARAM_CLASS(Iterations, int)
+    IMPLEMENT_PARAM_CLASS(KernelSize, int)
 
     cv::Mat getInnerROI(cv::InputArray m_, cv::Size ksize)
     {
@@ -60,13 +61,10 @@ namespace
         cv::Rect roi(ksize.width, ksize.height, m.cols - 2 * ksize.width, m.rows - 2 * ksize.height);
         return m(roi);
     }
-
-    cv::Mat getInnerROI(cv::InputArray m, int ksize)
-    {
-        return getInnerROI(m, cv::Size(ksize, ksize));
-    }
 }
 
+namespace {
+
 /////////////////////////////////////////////////////////////////////////////////////////////////
 // Blur
 
@@ -112,7 +110,7 @@ CUDA_TEST_P(Blur, Accuracy)
 INSTANTIATE_TEST_CASE_P(CUDA_Filters, Blur, testing::Combine(
     ALL_DEVICES,
     DIFFERENT_SIZES,
-    testing::Values(MatType(CV_8UC1), MatType(CV_8UC4)),
+    testing::Values(MatType(CV_8UC1), MatType(CV_8UC4), MatType(CV_32FC1)),
     testing::Values(KSize(cv::Size(3, 3)), KSize(cv::Size(5, 5)), KSize(cv::Size(7, 7))),
     testing::Values(Anchor(cv::Point(-1, -1)), Anchor(cv::Point(0, 0)), Anchor(cv::Point(2, 2))),
     testing::Values(BorderType(cv::BORDER_REFLECT101), BorderType(cv::BORDER_REPLICATE), BorderType(cv::BORDER_CONSTANT), BorderType(cv::BORDER_REFLECT)),
@@ -647,4 +645,66 @@ INSTANTIATE_TEST_CASE_P(CUDA_Filters, MorphEx, testing::Combine(
     testing::Values(Iterations(1), Iterations(2), Iterations(3)),
     WHOLE_SUBMAT));
 
+/////////////////////////////////////////////////////////////////////////////////////////////////
+// Median
+
+
+PARAM_TEST_CASE(Median, cv::cuda::DeviceInfo, cv::Size, MatDepth,  KernelSize, UseRoi)
+{
+    cv::cuda::DeviceInfo devInfo;
+    cv::Size size;
+    int type;
+    int kernel;
+    bool useRoi;
+
+    virtual void SetUp()
+    {
+        devInfo = GET_PARAM(0);
+        size = GET_PARAM(1);
+        type = GET_PARAM(2);
+        kernel = GET_PARAM(3);
+        useRoi = GET_PARAM(4);
+
+        cv::cuda::setDevice(devInfo.deviceID());
+    }
+};
+
+
+
+CUDA_TEST_P(Median, Accuracy)
+{
+    cv::Mat src = randomMat(size, type);
+
+    cv::Ptr<cv::cuda::Filter> median = cv::cuda::createMedianFilter(src.type(), kernel);
+
+    cv::cuda::GpuMat dst = createMat(size, type, useRoi);
+    median->apply(loadMat(src, useRoi), dst);
+
+    cv::Mat dst_gold;
+    cv::medianBlur(src,dst_gold,kernel);
+
+    cv::Rect rect(kernel+1,0,src.cols-(2*kernel+1),src.rows);
+    cv::Mat dst_gold_no_border = dst_gold(rect);
+    cv::cuda::GpuMat dst_no_border = cv::cuda::GpuMat(dst, rect);
+
+    EXPECT_MAT_NEAR(dst_gold_no_border, dst_no_border, 1);
+
+}
+
+INSTANTIATE_TEST_CASE_P(CUDA_Filters, Median, testing::Combine(
+    ALL_DEVICES,
+    DIFFERENT_SIZES,
+    testing::Values(MatDepth(CV_8U)),
+    testing::Values(KernelSize(3),
+                    KernelSize(5),
+                    KernelSize(7),
+                    KernelSize(9),
+                    KernelSize(11),
+                    KernelSize(13),
+                    KernelSize(15)),
+    WHOLE_SUBMAT)
+    );
+
+} //namespace
+
 #endif // HAVE_CUDA
diff --git a/modules/cudaimgproc/include/opencv2/cudaimgproc.hpp b/modules/cudaimgproc/include/opencv2/cudaimgproc.hpp
index d84ae24..dc876b7 100644
--- a/modules/cudaimgproc/include/opencv2/cudaimgproc.hpp
+++ b/modules/cudaimgproc/include/opencv2/cudaimgproc.hpp
@@ -40,8 +40,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_CUDAIMGPROC_HPP__
-#define __OPENCV_CUDAIMGPROC_HPP__
+#ifndef OPENCV_CUDAIMGPROC_HPP
+#define OPENCV_CUDAIMGPROC_HPP
 
 #ifndef __cplusplus
 #  error cudaimgproc.hpp header must be compiled as C++
@@ -588,6 +588,7 @@ CV_EXPORTS Ptr<CornersDetector> createGoodFeaturesToTrackDetector(int srcType, i
 
 //! @} cudaimgproc_feature
 
+
 ///////////////////////////// Mean Shift //////////////////////////////
 
 /** @brief Performs mean-shift filtering for each point of the source image.
@@ -725,4 +726,4 @@ CV_EXPORTS void blendLinear(InputArray img1, InputArray img2, InputArray weights
 
 }} // namespace cv { namespace cuda {
 
-#endif /* __OPENCV_CUDAIMGPROC_HPP__ */
+#endif /* OPENCV_CUDAIMGPROC_HPP */
diff --git a/modules/cudaimgproc/src/canny.cpp b/modules/cudaimgproc/src/canny.cpp
index 1e52bd2..75e53cf 100644
--- a/modules/cudaimgproc/src/canny.cpp
+++ b/modules/cudaimgproc/src/canny.cpp
@@ -93,6 +93,7 @@ namespace
 
         void write(FileStorage& fs) const
         {
+            writeFormat(fs);
             fs << "name" << "Canny_CUDA"
             << "low_thresh" << low_thresh_
             << "high_thresh" << high_thresh_
diff --git a/modules/cudaimgproc/src/cuda/gftt.cu b/modules/cudaimgproc/src/cuda/gftt.cu
index 029df41..ab8713f 100644
--- a/modules/cudaimgproc/src/cuda/gftt.cu
+++ b/modules/cudaimgproc/src/cuda/gftt.cu
@@ -47,7 +47,7 @@
 
 #include "opencv2/core/cuda/common.hpp"
 #include "opencv2/core/cuda/utility.hpp"
-
+#include <thrust/execution_policy.h>
 namespace cv { namespace cuda { namespace device
 {
     namespace gfft
@@ -91,12 +91,12 @@ namespace cv { namespace cuda { namespace device
             }
         }
 
-        int findCorners_gpu(PtrStepSzf eig, float threshold, PtrStepSzb mask, float2* corners, int max_count)
+        int findCorners_gpu(PtrStepSzf eig, float threshold, PtrStepSzb mask, float2* corners, int max_count, cudaStream_t stream)
         {
             void* counter_ptr;
             cudaSafeCall( cudaGetSymbolAddress(&counter_ptr, g_counter) );
 
-            cudaSafeCall( cudaMemset(counter_ptr, 0, sizeof(int)) );
+            cudaSafeCall( cudaMemsetAsync(counter_ptr, 0, sizeof(int), stream) );
 
             bindTexture(&eigTex, eig);
 
@@ -104,17 +104,18 @@ namespace cv { namespace cuda { namespace device
             dim3 grid(divUp(eig.cols, block.x), divUp(eig.rows, block.y));
 
             if (mask.data)
-                findCorners<<<grid, block>>>(threshold, SingleMask(mask), corners, max_count, eig.rows, eig.cols);
+                findCorners<<<grid, block, 0, stream>>>(threshold, SingleMask(mask), corners, max_count, eig.rows, eig.cols);
             else
-                findCorners<<<grid, block>>>(threshold, WithOutMask(), corners, max_count, eig.rows, eig.cols);
+                findCorners<<<grid, block, 0, stream>>>(threshold, WithOutMask(), corners, max_count, eig.rows, eig.cols);
 
             cudaSafeCall( cudaGetLastError() );
 
-            cudaSafeCall( cudaDeviceSynchronize() );
-
             int count;
-            cudaSafeCall( cudaMemcpy(&count, counter_ptr, sizeof(int), cudaMemcpyDeviceToHost) );
-
+            cudaSafeCall( cudaMemcpyAsync(&count, counter_ptr, sizeof(int), cudaMemcpyDeviceToHost, stream) );
+            if (stream)
+                cudaSafeCall(cudaStreamSynchronize(stream));
+            else
+                cudaSafeCall( cudaDeviceSynchronize() );
             return std::min(count, max_count);
         }
 
@@ -128,13 +129,19 @@ namespace cv { namespace cuda { namespace device
         };
 
 
-        void sortCorners_gpu(PtrStepSzf eig, float2* corners, int count)
+        void sortCorners_gpu(PtrStepSzf eig, float2* corners, int count, cudaStream_t stream)
         {
             bindTexture(&eigTex, eig);
 
             thrust::device_ptr<float2> ptr(corners);
-
+#if THRUST_VERSION >= 100802
+            if (stream)
+                thrust::sort(thrust::cuda::par(ThrustAllocator::getAllocator()).on(stream), ptr, ptr + count, EigGreater());
+            else
+                thrust::sort(thrust::cuda::par(ThrustAllocator::getAllocator()), ptr, ptr + count, EigGreater());
+#else
             thrust::sort(ptr, ptr + count, EigGreater());
+#endif
         }
     } // namespace optical_flow
 }}}
diff --git a/modules/cudaimgproc/src/generalized_hough.cpp b/modules/cudaimgproc/src/generalized_hough.cpp
index 9810bed..75b90af 100644
--- a/modules/cudaimgproc/src/generalized_hough.cpp
+++ b/modules/cudaimgproc/src/generalized_hough.cpp
@@ -684,28 +684,6 @@ namespace
         std::vector<int> h_buf_;
     };
 
-    double toRad(double a)
-    {
-        return a * CV_PI / 180.0;
-    }
-
-    double clampAngle(double a)
-    {
-        double res = a;
-
-        while (res > 360.0)
-            res -= 360.0;
-        while (res < 0)
-            res += 360.0;
-
-        return res;
-    }
-
-    bool angleEq(double a, double b, double eps = 1.0)
-    {
-        return (fabs(clampAngle(a - b)) <= eps);
-    }
-
     GeneralizedHoughGuilImpl::GeneralizedHoughGuilImpl()
     {
         maxBufferSize_ = 1000;
diff --git a/modules/cudaimgproc/src/gftt.cpp b/modules/cudaimgproc/src/gftt.cpp
index 73221c4..bf5d01b 100644
--- a/modules/cudaimgproc/src/gftt.cpp
+++ b/modules/cudaimgproc/src/gftt.cpp
@@ -55,8 +55,8 @@ namespace cv { namespace cuda { namespace device
 {
     namespace gfft
     {
-        int findCorners_gpu(PtrStepSzf eig, float threshold, PtrStepSzb mask, float2* corners, int max_count);
-        void sortCorners_gpu(PtrStepSzf eig, float2* corners, int count);
+        int findCorners_gpu(PtrStepSzf eig, float threshold, PtrStepSzb mask, float2* corners, int max_count, cudaStream_t stream);
+        void sortCorners_gpu(PtrStepSzf eig, float2* corners, int count, cudaStream_t stream);
     }
 }}}
 
@@ -97,9 +97,6 @@ namespace
 
     void GoodFeaturesToTrackDetector::detect(InputArray _image, OutputArray _corners, InputArray _mask, Stream& stream)
     {
-        // TODO : implement async version
-        (void) stream;
-
         using namespace cv::cuda::device::gfft;
 
         GpuMat image = _image.getGpuMat();
@@ -108,14 +105,14 @@ namespace
         CV_Assert( mask.empty() || (mask.type() == CV_8UC1 && mask.size() == image.size()) );
 
         ensureSizeIsEnough(image.size(), CV_32FC1, eig_);
-        cornerCriteria_->compute(image, eig_);
+        cornerCriteria_->compute(image, eig_, stream);
 
         double maxVal = 0;
         cuda::minMax(eig_, 0, &maxVal);
-
+        cudaStream_t stream_ = StreamAccessor::getStream(stream);
         ensureSizeIsEnough(1, std::max(1000, static_cast<int>(image.size().area() * 0.05)), CV_32FC2, tmpCorners_);
 
-        int total = findCorners_gpu(eig_, static_cast<float>(maxVal * qualityLevel_), mask, tmpCorners_.ptr<float2>(), tmpCorners_.cols);
+        int total = findCorners_gpu(eig_, static_cast<float>(maxVal * qualityLevel_), mask, tmpCorners_.ptr<float2>(), tmpCorners_.cols, stream_);
 
         if (total == 0)
         {
@@ -123,18 +120,18 @@ namespace
             return;
         }
 
-        sortCorners_gpu(eig_, tmpCorners_.ptr<float2>(), total);
+        sortCorners_gpu(eig_, tmpCorners_.ptr<float2>(), total, stream_);
 
         if (minDistance_ < 1)
         {
-            tmpCorners_.colRange(0, maxCorners_ > 0 ? std::min(maxCorners_, total) : total).copyTo(_corners);
+            tmpCorners_.colRange(0, maxCorners_ > 0 ? std::min(maxCorners_, total) : total).copyTo(_corners, stream);
         }
         else
         {
             std::vector<Point2f> tmp(total);
             Mat tmpMat(1, total, CV_32FC2, (void*)&tmp[0]);
-            tmpCorners_.colRange(0, total).download(tmpMat);
-
+            tmpCorners_.colRange(0, total).download(tmpMat, stream);
+            stream.waitForCompletion();
             std::vector<Point2f> tmp2;
             tmp2.reserve(total);
 
@@ -203,7 +200,7 @@ namespace
             _corners.create(1, static_cast<int>(tmp2.size()), CV_32FC2);
             GpuMat corners = _corners.getGpuMat();
 
-            corners.upload(Mat(1, static_cast<int>(tmp2.size()), CV_32FC2, &tmp2[0]));
+            corners.upload(Mat(1, static_cast<int>(tmp2.size()), CV_32FC2, &tmp2[0]), stream);
         }
     }
 }
diff --git a/modules/cudaimgproc/src/hough_circles.cpp b/modules/cudaimgproc/src/hough_circles.cpp
index 6bdaf16..b706967 100644
--- a/modules/cudaimgproc/src/hough_circles.cpp
+++ b/modules/cudaimgproc/src/hough_circles.cpp
@@ -99,6 +99,7 @@ namespace
 
         void write(FileStorage& fs) const
         {
+            writeFormat(fs);
             fs << "name" << "HoughCirclesDetector_CUDA"
             << "dp" << dp_
             << "minDist" << minDist_
diff --git a/modules/cudaimgproc/src/hough_lines.cpp b/modules/cudaimgproc/src/hough_lines.cpp
index 7b9c082..db45fb6 100644
--- a/modules/cudaimgproc/src/hough_lines.cpp
+++ b/modules/cudaimgproc/src/hough_lines.cpp
@@ -95,6 +95,7 @@ namespace
 
         void write(FileStorage& fs) const
         {
+            writeFormat(fs);
             fs << "name" << "HoughLinesDetector_CUDA"
             << "rho" << rho_
             << "theta" << theta_
diff --git a/modules/cudaimgproc/src/hough_segments.cpp b/modules/cudaimgproc/src/hough_segments.cpp
index e3e34ec..edd3006 100644
--- a/modules/cudaimgproc/src/hough_segments.cpp
+++ b/modules/cudaimgproc/src/hough_segments.cpp
@@ -98,6 +98,7 @@ namespace
 
         void write(FileStorage& fs) const
         {
+            writeFormat(fs);
             fs << "name" << "PHoughLinesDetector_CUDA"
             << "rho" << rho_
             << "theta" << theta_
diff --git a/modules/cudaimgproc/test/test_canny.cpp b/modules/cudaimgproc/test/test_canny.cpp
index adb5c0d..e9baae2 100644
--- a/modules/cudaimgproc/test/test_canny.cpp
+++ b/modules/cudaimgproc/test/test_canny.cpp
@@ -55,6 +55,8 @@ namespace
     IMPLEMENT_PARAM_CLASS(L2gradient, bool)
 }
 
+namespace {
+
 PARAM_TEST_CASE(Canny, cv::cuda::DeviceInfo, AppertureSize, L2gradient, UseRoi)
 {
     cv::cuda::DeviceInfo devInfo;
@@ -98,4 +100,6 @@ INSTANTIATE_TEST_CASE_P(CUDA_ImgProc, Canny, testing::Combine(
     testing::Values(L2gradient(false), L2gradient(true)),
     WHOLE_SUBMAT));
 
+} // namespace
+
 #endif // HAVE_CUDA
diff --git a/modules/cudaimgproc/test/test_histogram.cpp b/modules/cudaimgproc/test/test_histogram.cpp
index 5ff5963..3d32173 100644
--- a/modules/cudaimgproc/test/test_histogram.cpp
+++ b/modules/cudaimgproc/test/test_histogram.cpp
@@ -46,6 +46,8 @@
 
 using namespace cvtest;
 
+namespace {
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////////
 // HistEven
 
@@ -212,4 +214,6 @@ INSTANTIATE_TEST_CASE_P(CUDA_ImgProc, CLAHE, testing::Combine(
     DIFFERENT_SIZES,
     testing::Values(0.0, 40.0)));
 
+} // namespace
+
 #endif // HAVE_CUDA
diff --git a/modules/cudaimgproc/test/test_hough.cpp b/modules/cudaimgproc/test/test_hough.cpp
index 5e55abe..fd69521 100644
--- a/modules/cudaimgproc/test/test_hough.cpp
+++ b/modules/cudaimgproc/test/test_hough.cpp
@@ -46,6 +46,8 @@
 
 using namespace cvtest;
 
+namespace {
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////////
 // HoughLines
 
@@ -256,4 +258,6 @@ INSTANTIATE_TEST_CASE_P(CUDA_ImgProc, GeneralizedHough, testing::Combine(
     ALL_DEVICES,
     WHOLE_SUBMAT));
 
+} // namespace
+
 #endif // HAVE_CUDA
diff --git a/modules/cudalegacy/include/opencv2/cudalegacy.hpp b/modules/cudalegacy/include/opencv2/cudalegacy.hpp
index c27a116..ace8548 100644
--- a/modules/cudalegacy/include/opencv2/cudalegacy.hpp
+++ b/modules/cudalegacy/include/opencv2/cudalegacy.hpp
@@ -40,8 +40,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_CUDALEGACY_HPP__
-#define __OPENCV_CUDALEGACY_HPP__
+#ifndef OPENCV_CUDALEGACY_HPP
+#define OPENCV_CUDALEGACY_HPP
 
 #include "opencv2/core/cuda.hpp"
 #include "opencv2/cudalegacy/NCV.hpp"
@@ -287,4 +287,4 @@ CV_EXPORTS void solvePnPRansac(const Mat& object, const Mat& image, const Mat& c
 
 }}
 
-#endif /* __OPENCV_CUDALEGACY_HPP__ */
+#endif /* OPENCV_CUDALEGACY_HPP */
diff --git a/modules/cudalegacy/include/opencv2/cudalegacy/private.hpp b/modules/cudalegacy/include/opencv2/cudalegacy/private.hpp
index 7217480..79f9e63 100644
--- a/modules/cudalegacy/include/opencv2/cudalegacy/private.hpp
+++ b/modules/cudalegacy/include/opencv2/cudalegacy/private.hpp
@@ -41,8 +41,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_CORE_CUDALEGACY_PRIVATE_HPP__
-#define __OPENCV_CORE_CUDALEGACY_PRIVATE_HPP__
+#ifndef OPENCV_CORE_CUDALEGACY_PRIVATE_HPP
+#define OPENCV_CORE_CUDALEGACY_PRIVATE_HPP
 
 #ifndef __OPENCV_BUILD
 #  error this is a private header which should not be used from outside of the OpenCV library
@@ -93,4 +93,4 @@ namespace cv { namespace cuda
 
 //! @endcond
 
-#endif // __OPENCV_CORE_CUDALEGACY_PRIVATE_HPP__
+#endif // OPENCV_CORE_CUDALEGACY_PRIVATE_HPP
diff --git a/modules/cudalegacy/src/graphcuts.cpp b/modules/cudalegacy/src/graphcuts.cpp
index eb08c3c..1a1eb85 100644
--- a/modules/cudalegacy/src/graphcuts.cpp
+++ b/modules/cudalegacy/src/graphcuts.cpp
@@ -42,7 +42,8 @@
 
 #include "precomp.hpp"
 
-#if !defined (HAVE_CUDA) || defined (CUDA_DISABLER)
+// GraphCut has been removed in NPP 8.0
+#if !defined (HAVE_CUDA) || defined (CUDA_DISABLER) || (CUDART_VERSION >= 8000)
 
 void cv::cuda::graphcut(GpuMat&, GpuMat&, GpuMat&, GpuMat&, GpuMat&, GpuMat&, GpuMat&, Stream&) { throw_no_cuda(); }
 void cv::cuda::graphcut(GpuMat&, GpuMat&, GpuMat&, GpuMat&, GpuMat&, GpuMat&, GpuMat&, GpuMat&, GpuMat&, GpuMat&, GpuMat&, Stream&) { throw_no_cuda(); }
diff --git a/modules/cudalegacy/test/NCVTest.hpp b/modules/cudalegacy/test/NCVTest.hpp
index 2c7b5f9..23b1fee 100644
--- a/modules/cudalegacy/test/NCVTest.hpp
+++ b/modules/cudalegacy/test/NCVTest.hpp
@@ -214,12 +214,12 @@ private:
         stream << "====================================================" << std::endl << std::endl;
         stream << "Test initialization report: " << std::endl;
         for (std::map<std::string,std::string>::iterator it=report.statsText.begin();
-             it != report.statsText.end(); it++)
+             it != report.statsText.end(); ++it)
         {
             stream << it->first << "=" << it->second << std::endl;
         }
         for (std::map<std::string,Ncv32u>::iterator it=report.statsNums.begin();
-            it != report.statsNums.end(); it++)
+            it != report.statsNums.end(); ++it)
         {
             stream << it->first << "=" << it->second << std::endl;
         }
diff --git a/modules/cudalegacy/test/TestHaarCascadeApplication.cpp b/modules/cudalegacy/test/TestHaarCascadeApplication.cpp
index b7c389e..adc3dff 100644
--- a/modules/cudalegacy/test/TestHaarCascadeApplication.cpp
+++ b/modules/cudalegacy/test/TestHaarCascadeApplication.cpp
@@ -52,7 +52,7 @@ namespace
         ~FpuControl();
 
     private:
-    #if defined(__GNUC__) && !defined(__APPLE__) && !defined(__arm__) && !defined(__aarch64__)
+    #if defined(__GNUC__) && !defined(__APPLE__) && !defined(__arm__) && !defined(__aarch64__) && !defined(__powerpc64__)
         fpu_control_t fpu_oldcw, fpu_cw;
     #elif defined(_WIN32) && !defined(_WIN64)
         unsigned int fpu_oldcw, fpu_cw;
@@ -61,7 +61,7 @@ namespace
 
     FpuControl::FpuControl()
     {
-    #if defined(__GNUC__) && !defined(__APPLE__) && !defined(__arm__) && !defined(__aarch64__)
+    #if defined(__GNUC__) && !defined(__APPLE__) && !defined(__arm__) && !defined(__aarch64__) && !defined(__powerpc64__)
         _FPU_GETCW(fpu_oldcw);
         fpu_cw = (fpu_oldcw & ~_FPU_EXTENDED & ~_FPU_DOUBLE & ~_FPU_SINGLE) | _FPU_SINGLE;
         _FPU_SETCW(fpu_cw);
@@ -74,7 +74,7 @@ namespace
 
     FpuControl::~FpuControl()
     {
-    #if defined(__GNUC__) && !defined(__APPLE__) && !defined(__arm__) && !defined(__aarch64__)
+    #if defined(__GNUC__) && !defined(__APPLE__) && !defined(__arm__) && !defined(__aarch64__) && !defined(__powerpc64__)
         _FPU_SETCW(fpu_oldcw);
     #elif defined(_WIN32) && !defined(_WIN64)
         _controlfp_s(&fpu_cw, fpu_oldcw, _MCW_PC);
diff --git a/modules/cudalegacy/test/test_precomp.hpp b/modules/cudalegacy/test/test_precomp.hpp
index 41314da..5e0e9ee 100644
--- a/modules/cudalegacy/test/test_precomp.hpp
+++ b/modules/cudalegacy/test/test_precomp.hpp
@@ -51,7 +51,7 @@
 #ifndef __OPENCV_TEST_PRECOMP_HPP__
 #define __OPENCV_TEST_PRECOMP_HPP__
 
-#if defined(__GNUC__) && !defined(__APPLE__) && !defined(__arm__) && !defined(__aarch64__)
+#if defined(__GNUC__) && !defined(__APPLE__) && !defined(__arm__) && !defined(__aarch64__) && !defined(__powerpc64__)
     #include <fpu_control.h>
 #endif
 
diff --git a/modules/cudaobjdetect/include/opencv2/cudaobjdetect.hpp b/modules/cudaobjdetect/include/opencv2/cudaobjdetect.hpp
index f29ed53..7c07428 100644
--- a/modules/cudaobjdetect/include/opencv2/cudaobjdetect.hpp
+++ b/modules/cudaobjdetect/include/opencv2/cudaobjdetect.hpp
@@ -40,8 +40,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_CUDAOBJDETECT_HPP__
-#define __OPENCV_CUDAOBJDETECT_HPP__
+#ifndef OPENCV_CUDAOBJDETECT_HPP
+#define OPENCV_CUDAOBJDETECT_HPP
 
 #ifndef __cplusplus
 #  error cudaobjdetect.hpp header must be compiled as C++
@@ -285,4 +285,4 @@ public:
 
 }} // namespace cv { namespace cuda {
 
-#endif /* __OPENCV_CUDAOBJDETECT_HPP__ */
+#endif /* OPENCV_CUDAOBJDETECT_HPP */
diff --git a/modules/cudaobjdetect/test/test_objdetect.cpp b/modules/cudaobjdetect/test/test_objdetect.cpp
index 25c3efd..fcb566e 100644
--- a/modules/cudaobjdetect/test/test_objdetect.cpp
+++ b/modules/cudaobjdetect/test/test_objdetect.cpp
@@ -46,6 +46,8 @@
 
 using namespace cvtest;
 
+namespace {
+
 //#define DUMP
 
 struct HOG : testing::TestWithParam<cv::cuda::DeviceInfo>
@@ -558,4 +560,6 @@ CUDA_TEST_P(LBP_classify, Accuracy)
 INSTANTIATE_TEST_CASE_P(CUDA_ObjDetect, LBP_classify,
                         testing::Combine(ALL_DEVICES, testing::Values<int>(0)));
 
+} // namespace
+
 #endif // HAVE_CUDA
diff --git a/modules/cudaoptflow/include/opencv2/cudaoptflow.hpp b/modules/cudaoptflow/include/opencv2/cudaoptflow.hpp
index 6ea7559..576164b 100644
--- a/modules/cudaoptflow/include/opencv2/cudaoptflow.hpp
+++ b/modules/cudaoptflow/include/opencv2/cudaoptflow.hpp
@@ -40,8 +40,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_CUDAOPTFLOW_HPP__
-#define __OPENCV_CUDAOPTFLOW_HPP__
+#ifndef OPENCV_CUDAOPTFLOW_HPP
+#define OPENCV_CUDAOPTFLOW_HPP
 
 #ifndef __cplusplus
 #  error cudaoptflow.hpp header must be compiled as C++
@@ -346,4 +346,4 @@ public:
 
 }} // namespace cv { namespace cuda {
 
-#endif /* __OPENCV_CUDAOPTFLOW_HPP__ */
+#endif /* OPENCV_CUDAOPTFLOW_HPP */
diff --git a/modules/cudaoptflow/perf/perf_optflow.cpp b/modules/cudaoptflow/perf/perf_optflow.cpp
index 57994b7..d2992c3 100644
--- a/modules/cudaoptflow/perf/perf_optflow.cpp
+++ b/modules/cudaoptflow/perf/perf_optflow.cpp
@@ -116,10 +116,10 @@ PERF_TEST_P(ImagePair_Gray_NPts_WinSz_Levels_Iters, PyrLKOpticalFlowSparse,
     const int levels = GET_PARAM(4);
     const int iters = GET_PARAM(5);
 
-    const cv::Mat frame0 = readImage(imagePair.first, useGray ? cv::IMREAD_GRAYSCALE : cv::IMREAD_COLOR);
+    cv::Mat frame0 = readImage(imagePair.first, useGray ? cv::IMREAD_GRAYSCALE : cv::IMREAD_COLOR);
     ASSERT_FALSE(frame0.empty());
 
-    const cv::Mat frame1 = readImage(imagePair.second, useGray ? cv::IMREAD_GRAYSCALE : cv::IMREAD_COLOR);
+    cv::Mat frame1 = readImage(imagePair.second, useGray ? cv::IMREAD_GRAYSCALE : cv::IMREAD_COLOR);
     ASSERT_FALSE(frame1.empty());
 
     cv::Mat gray_frame;
@@ -131,6 +131,14 @@ PERF_TEST_P(ImagePair_Gray_NPts_WinSz_Levels_Iters, PyrLKOpticalFlowSparse,
     cv::Mat pts;
     cv::goodFeaturesToTrack(gray_frame, pts, points, 0.01, 0.0);
 
+    frame0.convertTo(frame0, CV_32F);
+    frame1.convertTo(frame1, CV_32F);
+    if(!useGray)
+    {
+        cv::cvtColor(frame0, frame0, cv::COLOR_BGR2BGRA);
+        cv::cvtColor(frame1, frame1, cv::COLOR_BGR2BGRA);
+    }
+
     if (PERF_RUN_CUDA())
     {
         const cv::cuda::GpuMat d_pts(pts.reshape(2, 1));
@@ -318,4 +326,4 @@ PERF_TEST_P(ImagePair, OpticalFlowDual_TVL1,
 
         CPU_SANITY_CHECK(flow);
     }
-}
+}
\ No newline at end of file
diff --git a/modules/cudaoptflow/src/cuda/pyrlk.cu b/modules/cudaoptflow/src/cuda/pyrlk.cu
index 7693551..2f28650 100644
--- a/modules/cudaoptflow/src/cuda/pyrlk.cu
+++ b/modules/cudaoptflow/src/cuda/pyrlk.cu
@@ -48,6 +48,8 @@
 #include "opencv2/core/cuda/limits.hpp"
 #include "opencv2/core/cuda/vec_math.hpp"
 #include "opencv2/core/cuda/reduce.hpp"
+#include "opencv2/core/cuda/filters.hpp"
+#include "opencv2/core/cuda/border_interpolate.hpp"
 
 using namespace cv::cuda;
 using namespace cv::cuda::device;
@@ -60,53 +62,240 @@ namespace pyrlk
     __constant__ int c_halfWin_y;
     __constant__ int c_iters;
 
+    texture<uchar, cudaTextureType2D, cudaReadModeNormalizedFloat> tex_I8U(false, cudaFilterModeLinear, cudaAddressModeClamp);
+    texture<uchar4, cudaTextureType2D, cudaReadModeNormalizedFloat> tex_I8UC4(false, cudaFilterModeLinear, cudaAddressModeClamp);
+
+    texture<ushort4, cudaTextureType2D, cudaReadModeNormalizedFloat> tex_I16UC4(false, cudaFilterModeLinear, cudaAddressModeClamp);
+
+
     texture<float, cudaTextureType2D, cudaReadModeElementType> tex_If(false, cudaFilterModeLinear, cudaAddressModeClamp);
     texture<float4, cudaTextureType2D, cudaReadModeElementType> tex_If4(false, cudaFilterModeLinear, cudaAddressModeClamp);
+
     texture<uchar, cudaTextureType2D, cudaReadModeElementType> tex_Ib(false, cudaFilterModePoint, cudaAddressModeClamp);
 
+    texture<uchar, cudaTextureType2D, cudaReadModeNormalizedFloat> tex_J8U(false, cudaFilterModeLinear, cudaAddressModeClamp);
+    texture<uchar4, cudaTextureType2D, cudaReadModeNormalizedFloat> tex_J8UC4(false, cudaFilterModeLinear, cudaAddressModeClamp);
+
+    texture<ushort4, cudaTextureType2D, cudaReadModeNormalizedFloat> tex_J16UC4(false, cudaFilterModeLinear, cudaAddressModeClamp);
+
+
     texture<float, cudaTextureType2D, cudaReadModeElementType> tex_Jf(false, cudaFilterModeLinear, cudaAddressModeClamp);
     texture<float4, cudaTextureType2D, cudaReadModeElementType> tex_Jf4(false, cudaFilterModeLinear, cudaAddressModeClamp);
 
-    template <int cn> struct Tex_I;
-    template <> struct Tex_I<1>
+
+    template <int cn, typename T> struct Tex_I
+    {
+        static __host__ __forceinline__ void bindTexture_(PtrStepSz<typename TypeVec<T, cn>::vec_type> I)
+        {
+            (void)I;
+        }
+    };
+
+    template <> struct Tex_I<1, uchar>
+    {
+        static __device__ __forceinline__ float read(float x, float y)
+        {
+            return tex2D(tex_I8U, x, y);
+        }
+        static __host__ __forceinline__ void bindTexture_(PtrStepSz<uchar>& I)
+        {
+            bindTexture(&tex_I8U, I);
+        }
+    };
+    template <> struct Tex_I<1, ushort>
+    {
+        static __device__ __forceinline__ float read(float x, float y)
+        {
+            return 0.0;
+        }
+        static __host__ __forceinline__ void bindTexture_(PtrStepSz<ushort>& I)
+        {
+            (void)I;
+        }
+    };
+    template <> struct Tex_I<1, int>
+    {
+        static __device__ __forceinline__ float read(float x, float y)
+        {
+            return 0.0;
+        }
+        static __host__ __forceinline__ void bindTexture_(PtrStepSz<int>& I)
+        {
+            (void)I;
+        }
+    };
+    template <> struct Tex_I<1, float>
     {
         static __device__ __forceinline__ float read(float x, float y)
         {
             return tex2D(tex_If, x, y);
         }
+        static __host__ __forceinline__ void bindTexture_(PtrStepSz<float>& I)
+        {
+            bindTexture(&tex_If, I);
+        }
+    };
+    // ****************** 3 channel specializations ************************
+    template <> struct Tex_I<3, uchar>
+    {
+        static __device__ __forceinline__ float3 read(float x, float y)
+        {
+            return make_float3(0,0,0);
+        }
+        static __host__ __forceinline__ void bindTexture_(PtrStepSz<uchar3> I)
+        {
+            (void)I;
+        }
+    };
+    template <> struct Tex_I<3, ushort>
+    {
+        static __device__ __forceinline__ float3 read(float x, float y)
+        {
+            return make_float3(0, 0, 0);
+        }
+        static __host__ __forceinline__ void bindTexture_(PtrStepSz<ushort3> I)
+        {
+            (void)I;
+        }
+    };
+    template <> struct Tex_I<3, int>
+    {
+        static __device__ __forceinline__ float3 read(float x, float y)
+        {
+            return make_float3(0, 0, 0);
+        }
+        static __host__ __forceinline__ void bindTexture_(PtrStepSz<int3> I)
+        {
+            (void)I;
+        }
+    };
+    template <> struct Tex_I<3, float>
+    {
+        static __device__ __forceinline__ float3 read(float x, float y)
+        {
+            return make_float3(0, 0, 0);
+        }
+        static __host__ __forceinline__ void bindTexture_(PtrStepSz<float3> I)
+        {
+            (void)I;
+        }
+    };
+    // ****************** 4 channel specializations ************************
+
+    template <> struct Tex_I<4, uchar>
+    {
+        static __device__ __forceinline__ float4 read(float x, float y)
+        {
+            return tex2D(tex_I8UC4, x, y);
+        }
+        static __host__ __forceinline__ void bindTexture_(PtrStepSz<uchar4>& I)
+        {
+            bindTexture(&tex_I8UC4, I);
+        }
     };
-    template <> struct Tex_I<4>
+    template <> struct Tex_I<4, ushort>
+    {
+        static __device__ __forceinline__ float4 read(float x, float y)
+        {
+            return tex2D(tex_I16UC4, x, y);
+        }
+        static __host__ __forceinline__ void bindTexture_(PtrStepSz<ushort4>& I)
+        {
+            bindTexture(&tex_I16UC4, I);
+        }
+    };
+    template <> struct Tex_I<4, float>
     {
         static __device__ __forceinline__ float4 read(float x, float y)
         {
             return tex2D(tex_If4, x, y);
         }
+        static __host__ __forceinline__ void bindTexture_(PtrStepSz<float4>& I)
+        {
+            bindTexture(&tex_If4, I);
+        }
     };
-
-    template <int cn> struct Tex_J;
-    template <> struct Tex_J<1>
+    // ************* J  ***************
+    template <int cn, typename T> struct Tex_J
+    {
+        static __host__ __forceinline__ void bindTexture_(PtrStepSz<typename TypeVec<T,cn>::vec_type>& J)
+        {
+            (void)J;
+        }
+    };
+    template <> struct Tex_J<1, uchar>
+    {
+        static __device__ __forceinline__ float read(float x, float y)
+        {
+            return tex2D(tex_J8U, x, y);
+        }
+        static __host__ __forceinline__ void bindTexture_(PtrStepSz<uchar>& J)
+        {
+            bindTexture(&tex_J8U, J);
+        }
+    };
+    template <> struct Tex_J<1, float>
     {
         static __device__ __forceinline__ float read(float x, float y)
         {
             return tex2D(tex_Jf, x, y);
         }
+        static __host__ __forceinline__ void bindTexture_(PtrStepSz<float>& J)
+        {
+            bindTexture(&tex_Jf, J);
+        }
     };
-    template <> struct Tex_J<4>
+    // ************* 4 channel specializations ***************
+    template <> struct Tex_J<4, uchar>
+    {
+        static __device__ __forceinline__ float4 read(float x, float y)
+        {
+            return tex2D(tex_J8UC4, x, y);
+        }
+        static __host__ __forceinline__ void bindTexture_(PtrStepSz<uchar4>& J)
+        {
+            bindTexture(&tex_J8UC4, J);
+        }
+    };
+    template <> struct Tex_J<4, ushort>
+    {
+        static __device__ __forceinline__ float4 read(float x, float y)
+        {
+            return tex2D(tex_J16UC4, x, y);
+        }
+        static __host__ __forceinline__ void bindTexture_(PtrStepSz<ushort4>& J)
+        {
+            bindTexture(&tex_J16UC4, J);
+        }
+    };
+    template <> struct Tex_J<4, float>
     {
         static __device__ __forceinline__ float4 read(float x, float y)
         {
             return tex2D(tex_Jf4, x, y);
         }
+        static __host__ __forceinline__ void bindTexture_(PtrStepSz<float4>& J)
+        {
+            bindTexture(&tex_Jf4, J);
+        }
     };
 
-    __device__ __forceinline__ void accum(float& dst, float val)
+    __device__ __forceinline__ void accum(float& dst, const float& val)
     {
         dst += val;
     }
-    __device__ __forceinline__ void accum(float& dst, const float4& val)
+    __device__ __forceinline__ void accum(float& dst, const float2& val)
+    {
+        dst += val.x + val.y;
+    }
+    __device__ __forceinline__ void accum(float& dst, const float3& val)
     {
         dst += val.x + val.y + val.z;
     }
+    __device__ __forceinline__ void accum(float& dst, const float4& val)
+    {
+        dst += val.x + val.y + val.z + val.w;
+    }
 
     __device__ __forceinline__ float abs_(float a)
     {
@@ -116,8 +305,64 @@ namespace pyrlk
     {
         return abs(a);
     }
+    __device__ __forceinline__ float2 abs_(const float2& a)
+    {
+        return abs(a);
+    }
+    __device__ __forceinline__ float3 abs_(const float3& a)
+    {
+        return abs(a);
+    }
+
+
+    template<typename T> __device__ __forceinline__ typename TypeVec<float, 1>::vec_type ToFloat(const typename TypeVec<T, 1>::vec_type& other)
+    {
+        return other;
+    }
+    template<typename T> __device__ __forceinline__  typename TypeVec<float, 2>::vec_type ToFloat(const typename TypeVec<T, 2>::vec_type& other)
+    {
+        typename TypeVec<float, 2>::vec_type ret;
+        ret.x = other.x;
+        ret.y = other.y;
+        return ret;
+    }
+    template<typename T> __device__ __forceinline__  typename TypeVec<float, 3>::vec_type ToFloat(const typename TypeVec<T, 3>::vec_type& other)
+    {
+        typename TypeVec<float, 3>::vec_type ret;
+        ret.x = other.x;
+        ret.y = other.y;
+        ret.z = other.z;
+        return ret;
+    }
+    template<typename T> __device__ __forceinline__  typename TypeVec<float, 4>::vec_type ToFloat(const typename TypeVec<T, 4>::vec_type& other)
+    {
+        typename TypeVec<float, 4>::vec_type ret;
+        ret.x = other.x;
+        ret.y = other.y;
+        ret.z = other.z;
+        ret.w = other.w;
+        return ret;
+    }
 
-    template <int cn, int PATCH_X, int PATCH_Y, bool calcErr>
+    template <typename T>
+    struct DenormalizationFactor
+    {
+        static __device__ __forceinline__ float factor()
+        {
+            return 1.0f;
+        }
+    };
+
+    template <>
+    struct DenormalizationFactor<uchar>
+    {
+        static __device__ __forceinline__ float factor()
+        {
+            return 255.0f;
+        }
+    };
+
+    template <int cn, int PATCH_X, int PATCH_Y, bool calcErr, typename T>
     __global__ void sparseKernel(const float2* prevPts, float2* nextPts, uchar* status, float* err, const int level, const int rows, const int cols)
     {
     #if __CUDA_ARCH__ <= 110
@@ -166,15 +411,15 @@ namespace pyrlk
                 float x = prevPt.x + xBase + 0.5f;
                 float y = prevPt.y + yBase + 0.5f;
 
-                I_patch[i][j] = Tex_I<cn>::read(x, y);
+                I_patch[i][j] = Tex_I<cn, T>::read(x, y);
 
                 // Sharr Deriv
 
-                work_type dIdx = 3.0f * Tex_I<cn>::read(x+1, y-1) + 10.0f * Tex_I<cn>::read(x+1, y) + 3.0f * Tex_I<cn>::read(x+1, y+1) -
-                                 (3.0f * Tex_I<cn>::read(x-1, y-1) + 10.0f * Tex_I<cn>::read(x-1, y) + 3.0f * Tex_I<cn>::read(x-1, y+1));
+                work_type dIdx = 3.0f * Tex_I<cn,T>::read(x+1, y-1) + 10.0f * Tex_I<cn, T>::read(x+1, y) + 3.0f * Tex_I<cn,T>::read(x+1, y+1) -
+                                 (3.0f * Tex_I<cn,T>::read(x-1, y-1) + 10.0f * Tex_I<cn, T>::read(x-1, y) + 3.0f * Tex_I<cn,T>::read(x-1, y+1));
 
-                work_type dIdy = 3.0f * Tex_I<cn>::read(x-1, y+1) + 10.0f * Tex_I<cn>::read(x, y+1) + 3.0f * Tex_I<cn>::read(x+1, y+1) -
-                                (3.0f * Tex_I<cn>::read(x-1, y-1) + 10.0f * Tex_I<cn>::read(x, y-1) + 3.0f * Tex_I<cn>::read(x+1, y-1));
+                work_type dIdy = 3.0f * Tex_I<cn,T>::read(x-1, y+1) + 10.0f * Tex_I<cn, T>::read(x, y+1) + 3.0f * Tex_I<cn,T>::read(x+1, y+1) -
+                                (3.0f * Tex_I<cn,T>::read(x-1, y-1) + 10.0f * Tex_I<cn, T>::read(x, y-1) + 3.0f * Tex_I<cn,T>::read(x+1, y-1));
 
                 dIdx_patch[i][j] = dIdx;
                 dIdy_patch[i][j] = dIdy;
@@ -243,7 +488,7 @@ namespace pyrlk
                 for (int x = threadIdx.x, j = 0; x < c_winSize_x; x += blockDim.x, ++j)
                 {
                     work_type I_val = I_patch[i][j];
-                    work_type J_val = Tex_J<cn>::read(nextPt.x + x + 0.5f, nextPt.y + y + 0.5f);
+                    work_type J_val = Tex_J<cn, T>::read(nextPt.x + x + 0.5f, nextPt.y + y + 0.5f);
 
                     work_type diff = (J_val - I_val) * 32.0f;
 
@@ -286,7 +531,7 @@ namespace pyrlk
                 for (int x = threadIdx.x, j = 0; x < c_winSize_x; x += blockDim.x, ++j)
                 {
                     work_type I_val = I_patch[i][j];
-                    work_type J_val = Tex_J<cn>::read(nextPt.x + x + 0.5f, nextPt.y + y + 0.5f);
+                    work_type J_val = Tex_J<cn, T>::read(nextPt.x + x + 0.5f, nextPt.y + y + 0.5f);
 
                     work_type diff = J_val - I_val;
 
@@ -305,26 +550,356 @@ namespace pyrlk
             nextPts[blockIdx.x] = nextPt;
 
             if (calcErr)
-                err[blockIdx.x] = static_cast<float>(errval) / (cn * c_winSize_x * c_winSize_y);
+                err[blockIdx.x] = static_cast<float>(errval) / (::min(cn, 3) * c_winSize_x * c_winSize_y) * DenormalizationFactor<T>::factor();
         }
     }
 
-    template <int cn, int PATCH_X, int PATCH_Y>
-    void sparse_caller(int rows, int cols, const float2* prevPts, float2* nextPts, uchar* status, float* err, int ptcount,
-                       int level, dim3 block, cudaStream_t stream)
+    // Kernel, uses non texture fetches
+    template <int PATCH_X, int PATCH_Y, bool calcErr, int cn, typename T, typename Ptr2D>
+    __global__ void sparseKernel_(Ptr2D I, Ptr2D J, const float2* prevPts, float2* nextPts, uchar* status, float* err, const int level, const int rows, const int cols)
     {
-        dim3 grid(ptcount);
+#if __CUDA_ARCH__ <= 110
+        const int BLOCK_SIZE = 128;
+#else
+        const int BLOCK_SIZE = 256;
+#endif
 
-        if (level == 0 && err)
-            sparseKernel<cn, PATCH_X, PATCH_Y, true><<<grid, block>>>(prevPts, nextPts, status, err, level, rows, cols);
-        else
-            sparseKernel<cn, PATCH_X, PATCH_Y, false><<<grid, block>>>(prevPts, nextPts, status, err, level, rows, cols);
+        __shared__ float smem1[BLOCK_SIZE];
+        __shared__ float smem2[BLOCK_SIZE];
+        __shared__ float smem3[BLOCK_SIZE];
 
-        cudaSafeCall( cudaGetLastError() );
+        const unsigned int tid = threadIdx.y * blockDim.x + threadIdx.x;
+
+        float2 prevPt = prevPts[blockIdx.x];
+        prevPt.x *= (1.0f / (1 << level));
+        prevPt.y *= (1.0f / (1 << level));
+
+        if (prevPt.x < 0 || prevPt.x >= cols || prevPt.y < 0 || prevPt.y >= rows)
+        {
+            if (tid == 0 && level == 0)
+                status[blockIdx.x] = 0;
+
+            return;
+        }
+
+        prevPt.x -= c_halfWin_x;
+        prevPt.y -= c_halfWin_y;
+
+        // extract the patch from the first image, compute covariation matrix of derivatives
+
+        float A11 = 0;
+        float A12 = 0;
+        float A22 = 0;
+
+        typedef typename TypeVec<float, cn>::vec_type work_type;
+
+        work_type I_patch[PATCH_Y][PATCH_X];
+        work_type dIdx_patch[PATCH_Y][PATCH_X];
+        work_type dIdy_patch[PATCH_Y][PATCH_X];
+
+        for (int yBase = threadIdx.y, i = 0; yBase < c_winSize_y; yBase += blockDim.y, ++i)
+        {
+            for (int xBase = threadIdx.x, j = 0; xBase < c_winSize_x; xBase += blockDim.x, ++j)
+            {
+                float x = prevPt.x + xBase + 0.5f;
+                float y = prevPt.y + yBase + 0.5f;
+
+                I_patch[i][j] = ToFloat<T>(I(y, x));
+
+                // Sharr Deriv
+
+                work_type dIdx = 3.0f * I(y - 1, x + 1) + 10.0f * I(y, x + 1) + 3.0f * I(y + 1, x + 1) -
+                    (3.0f * I(y - 1, x - 1) + 10.0f * I(y, x - 1) + 3.0f * I(y + 1 , x - 1));
+
+                work_type dIdy = 3.0f * I(y + 1, x - 1) + 10.0f * I(y + 1, x) + 3.0f * I(y+1, x + 1) -
+                    (3.0f * I(y - 1, x - 1) + 10.0f * I(y-1, x) + 3.0f * I(y - 1, x + 1));
+
+                dIdx_patch[i][j] = dIdx;
+                dIdy_patch[i][j] = dIdy;
+
+                accum(A11, dIdx * dIdx);
+                accum(A12, dIdx * dIdy);
+                accum(A22, dIdy * dIdy);
+            }
+        }
+
+        reduce<BLOCK_SIZE>(smem_tuple(smem1, smem2, smem3), thrust::tie(A11, A12, A22), tid, thrust::make_tuple(plus<float>(), plus<float>(), plus<float>()));
+
+#if __CUDA_ARCH__ >= 300
+        if (tid == 0)
+        {
+            smem1[0] = A11;
+            smem2[0] = A12;
+            smem3[0] = A22;
+        }
+#endif
+
+        __syncthreads();
+
+        A11 = smem1[0];
+        A12 = smem2[0];
+        A22 = smem3[0];
+
+        float D = A11 * A22 - A12 * A12;
+
+        if (D < numeric_limits<float>::epsilon())
+        {
+            if (tid == 0 && level == 0)
+                status[blockIdx.x] = 0;
+
+            return;
+        }
+
+        D = 1.f / D;
+
+        A11 *= D;
+        A12 *= D;
+        A22 *= D;
+
+        float2 nextPt = nextPts[blockIdx.x];
+        nextPt.x *= 2.f;
+        nextPt.y *= 2.f;
+
+        nextPt.x -= c_halfWin_x;
+        nextPt.y -= c_halfWin_y;
+
+        for (int k = 0; k < c_iters; ++k)
+        {
+            if (nextPt.x < -c_halfWin_x || nextPt.x >= cols || nextPt.y < -c_halfWin_y || nextPt.y >= rows)
+            {
+                if (tid == 0 && level == 0)
+                    status[blockIdx.x] = 0;
+
+                return;
+            }
+
+            float b1 = 0;
+            float b2 = 0;
+
+            for (int y = threadIdx.y, i = 0; y < c_winSize_y; y += blockDim.y, ++i)
+            {
+                for (int x = threadIdx.x, j = 0; x < c_winSize_x; x += blockDim.x, ++j)
+                {
+                    work_type I_val = I_patch[i][j];
+                    work_type J_val = ToFloat<T>(J(nextPt.y + y + 0.5f, nextPt.x + x + 0.5f));
+
+                    work_type diff = (J_val - I_val) * 32.0f;
+
+                    accum(b1, diff * dIdx_patch[i][j]);
+                    accum(b2, diff * dIdy_patch[i][j]);
+                }
+            }
+
+            reduce<BLOCK_SIZE>(smem_tuple(smem1, smem2), thrust::tie(b1, b2), tid, thrust::make_tuple(plus<float>(), plus<float>()));
+
+#if __CUDA_ARCH__ >= 300
+            if (tid == 0)
+            {
+                smem1[0] = b1;
+                smem2[0] = b2;
+            }
+#endif
+
+            __syncthreads();
+
+            b1 = smem1[0];
+            b2 = smem2[0];
+
+            float2 delta;
+            delta.x = A12 * b2 - A22 * b1;
+            delta.y = A12 * b1 - A11 * b2;
+
+            nextPt.x += delta.x;
+            nextPt.y += delta.y;
+
+            if (::fabs(delta.x) < 0.01f && ::fabs(delta.y) < 0.01f)
+                break;
+        }
+
+        float errval = 0;
+        if (calcErr)
+        {
+            for (int y = threadIdx.y, i = 0; y < c_winSize_y; y += blockDim.y, ++i)
+            {
+                for (int x = threadIdx.x, j = 0; x < c_winSize_x; x += blockDim.x, ++j)
+                {
+                    work_type I_val = I_patch[i][j];
+                    work_type J_val = ToFloat<T>(J(nextPt.y + y + 0.5f, nextPt.x + x + 0.5f));
+
+                    work_type diff = J_val - I_val;
+
+                    accum(errval, abs_(diff));
+                }
+            }
+
+            reduce<BLOCK_SIZE>(smem1, errval, tid, plus<float>());
+        }
+
+        if (tid == 0)
+        {
+            nextPt.x += c_halfWin_x;
+            nextPt.y += c_halfWin_y;
+
+            nextPts[blockIdx.x] = nextPt;
+
+            if (calcErr)
+                err[blockIdx.x] = static_cast<float>(errval) / (::min(cn, 3)*c_winSize_x * c_winSize_y);
+        }
+    } // __global__ void sparseKernel_
+
+
+    template <int cn, int PATCH_X, int PATCH_Y, typename T> class sparse_caller
+    {
+    public:
+        static void call(PtrStepSz<typename TypeVec<T, cn>::vec_type> I, PtrStepSz<typename TypeVec<T, cn>::vec_type> J, int rows, int cols, const float2* prevPts, float2* nextPts, uchar* status, float* err, int ptcount,
+            int level, dim3 block, cudaStream_t stream)
+        {
+            dim3 grid(ptcount);
+            (void)I;
+            (void)J;
+            if (level == 0 && err)
+                sparseKernel<cn, PATCH_X, PATCH_Y, true, T> <<<grid, block, 0, stream >>>(prevPts, nextPts, status, err, level, rows, cols);
+            else
+                sparseKernel<cn, PATCH_X, PATCH_Y, false, T> <<<grid, block, 0, stream >>>(prevPts, nextPts, status, err, level, rows, cols);
+
+            cudaSafeCall(cudaGetLastError());
+
+            if (stream == 0)
+                cudaSafeCall(cudaDeviceSynchronize());
+        }
+    };
+    // Specialization to use non texture path because for some reason the texture path keeps failing accuracy tests
+    template<int PATCH_X, int PATCH_Y> class sparse_caller<1, PATCH_X, PATCH_Y, unsigned short>
+    {
+    public:
+        typedef typename TypeVec<unsigned short, 1>::vec_type work_type;
+        typedef PtrStepSz<work_type> Ptr2D;
+        typedef BrdConstant<work_type> BrdType;
+        typedef BorderReader<Ptr2D, BrdType> Reader;
+        typedef LinearFilter<Reader> Filter;
+        static void call(Ptr2D I, Ptr2D J, int rows, int cols, const float2* prevPts, float2* nextPts, uchar* status, float* err, int ptcount,
+            int level, dim3 block, cudaStream_t stream)
+        {
+            dim3 grid(ptcount);
+            if (level == 0 && err)
+            {
+                sparseKernel_<PATCH_X, PATCH_Y, true, 1, unsigned short> <<<grid, block, 0, stream >>>(
+                    Filter(Reader(I, BrdType(rows, cols))),
+                    Filter(Reader(J, BrdType(rows, cols))),
+                    prevPts, nextPts, status, err, level, rows, cols);
+            }
+            else
+            {
+                sparseKernel_<PATCH_X, PATCH_Y, false, 1, unsigned short> <<<grid, block, 0, stream >>>(
+                    Filter(Reader(I, BrdType(rows, cols))),
+                    Filter(Reader(J, BrdType(rows, cols))),
+                    prevPts, nextPts, status, err, level, rows, cols);
+            }
+            cudaSafeCall(cudaGetLastError());
+
+            if (stream == 0)
+                cudaSafeCall(cudaDeviceSynchronize());
+        }
+    };
+    // Specialization for int because the texture path keeps failing
+    template<int PATCH_X, int PATCH_Y> class sparse_caller<1, PATCH_X, PATCH_Y, int>
+    {
+    public:
+        typedef typename TypeVec<int, 1>::vec_type work_type;
+        typedef PtrStepSz<work_type> Ptr2D;
+        typedef BrdConstant<work_type> BrdType;
+        typedef BorderReader<Ptr2D, BrdType> Reader;
+        typedef LinearFilter<Reader> Filter;
+        static void call(Ptr2D I, Ptr2D J, int rows, int cols, const float2* prevPts, float2* nextPts, uchar* status, float* err, int ptcount,
+            int level, dim3 block, cudaStream_t stream)
+        {
+            dim3 grid(ptcount);
+            if (level == 0 && err)
+            {
+                sparseKernel_<PATCH_X, PATCH_Y, true, 1, int> <<<grid, block, 0, stream >>>(
+                    Filter(Reader(I, BrdType(rows, cols))),
+                    Filter(Reader(J, BrdType(rows, cols))),
+                    prevPts, nextPts, status, err, level, rows, cols);
+            }
+            else
+            {
+                sparseKernel_<PATCH_X, PATCH_Y, false, 1, int> <<<grid, block, 0, stream >>>(
+                    Filter(Reader(I, BrdType(rows, cols))),
+                    Filter(Reader(J, BrdType(rows, cols))),
+                    prevPts, nextPts, status, err, level, rows, cols);
+            }
+            cudaSafeCall(cudaGetLastError());
+
+            if (stream == 0)
+                cudaSafeCall(cudaDeviceSynchronize());
+        }
+    };
+    template<int PATCH_X, int PATCH_Y> class sparse_caller<4, PATCH_X, PATCH_Y, int>
+    {
+    public:
+        typedef typename TypeVec<int, 4>::vec_type work_type;
+        typedef PtrStepSz<work_type> Ptr2D;
+        typedef BrdConstant<work_type> BrdType;
+        typedef BorderReader<Ptr2D, BrdType> Reader;
+        typedef LinearFilter<Reader> Filter;
+        static void call(Ptr2D I, Ptr2D J, int rows, int cols, const float2* prevPts, float2* nextPts, uchar* status, float* err, int ptcount,
+            int level, dim3 block, cudaStream_t stream)
+        {
+            dim3 grid(ptcount);
+            if (level == 0 && err)
+            {
+                sparseKernel_<PATCH_X, PATCH_Y, true, 4, int> <<<grid, block, 0, stream >>>(
+                    Filter(Reader(I, BrdType(rows, cols))),
+                    Filter(Reader(J, BrdType(rows, cols))),
+                    prevPts, nextPts, status, err, level, rows, cols);
+            }
+            else
+            {
+                sparseKernel_<PATCH_X, PATCH_Y, false, 4, int> <<<grid, block, 0, stream >>>(
+                    Filter(Reader(I, BrdType(rows, cols))),
+                    Filter(Reader(J, BrdType(rows, cols))),
+                    prevPts, nextPts, status, err, level, rows, cols);
+            }
+            cudaSafeCall(cudaGetLastError());
+
+            if (stream == 0)
+                cudaSafeCall(cudaDeviceSynchronize());
+        }
+    };
+    using namespace cv::cuda::device;
+    template <int PATCH_X, int PATCH_Y, typename T> class sparse_caller<3, PATCH_X, PATCH_Y, T>
+    {
+    public:
+        typedef typename TypeVec<T, 3>::vec_type work_type;
+        typedef PtrStepSz<work_type> Ptr2D;
+        typedef BrdConstant<work_type> BrdType;
+        typedef BorderReader<Ptr2D, BrdType> Reader;
+        typedef LinearFilter<Reader> Filter;
+        static void call(Ptr2D I, Ptr2D J, int rows, int cols, const float2* prevPts, float2* nextPts, uchar* status, float* err, int ptcount,
+            int level, dim3 block, cudaStream_t stream)
+        {
+            dim3 grid(ptcount);
+            if (level == 0 && err)
+            {
+                sparseKernel_<PATCH_X, PATCH_Y, true, 3, T> <<<grid, block, 0, stream >>>(
+                    Filter(Reader(I, BrdType(rows, cols))),
+                    Filter(Reader(J, BrdType(rows, cols))),
+                    prevPts, nextPts, status, err, level, rows, cols);
+            }
+            else
+            {
+                sparseKernel_<PATCH_X, PATCH_Y, false, 3, T> <<<grid, block, 0, stream >>>(
+                    Filter(Reader(I, BrdType(rows, cols))),
+                    Filter(Reader(J, BrdType(rows, cols))),
+                    prevPts, nextPts, status, err, level, rows, cols);
+            }
+            cudaSafeCall(cudaGetLastError());
+
+            if (stream == 0)
+                cudaSafeCall(cudaDeviceSynchronize());
+        }
+    };
 
-        if (stream == 0)
-            cudaSafeCall( cudaDeviceSynchronize() );
-    }
 
     template <bool calcErr>
     __global__ void denseKernel(PtrStepf u, PtrStepf v, const PtrStepf prevU, const PtrStepf prevV, PtrStepf err, const int rows, const int cols)
@@ -484,77 +1059,72 @@ namespace pyrlk
         cudaSafeCall( cudaMemcpyToSymbolAsync(c_iters, &iters, sizeof(int), 0, cudaMemcpyHostToDevice, stream) );
     }
 
-    void sparse1(PtrStepSzf I, PtrStepSzf J, const float2* prevPts, float2* nextPts, uchar* status, float* err, int ptcount,
-                 int level, dim3 block, dim3 patch, cudaStream_t stream)
+    template<typename T, int cn> struct pyrLK_caller
     {
-        typedef void (*func_t)(int rows, int cols, const float2* prevPts, float2* nextPts, uchar* status, float* err, int ptcount,
-                               int level, dim3 block, cudaStream_t stream);
-
-        static const func_t funcs[5][5] =
+        static void sparse(PtrStepSz<typename TypeVec<T, cn>::vec_type> I, PtrStepSz<typename TypeVec<T, cn>::vec_type> J, const float2* prevPts, float2* nextPts, uchar* status, float* err, int ptcount,
+            int level, dim3 block, dim3 patch, cudaStream_t stream)
         {
-            {sparse_caller<1, 1, 1>, sparse_caller<1, 2, 1>, sparse_caller<1, 3, 1>, sparse_caller<1, 4, 1>, sparse_caller<1, 5, 1>},
-            {sparse_caller<1, 1, 2>, sparse_caller<1, 2, 2>, sparse_caller<1, 3, 2>, sparse_caller<1, 4, 2>, sparse_caller<1, 5, 2>},
-            {sparse_caller<1, 1, 3>, sparse_caller<1, 2, 3>, sparse_caller<1, 3, 3>, sparse_caller<1, 4, 3>, sparse_caller<1, 5, 3>},
-            {sparse_caller<1, 1, 4>, sparse_caller<1, 2, 4>, sparse_caller<1, 3, 4>, sparse_caller<1, 4, 4>, sparse_caller<1, 5, 4>},
-            {sparse_caller<1, 1, 5>, sparse_caller<1, 2, 5>, sparse_caller<1, 3, 5>, sparse_caller<1, 4, 5>, sparse_caller<1, 5, 5>}
-        };
-
-        bindTexture(&tex_If, I);
-        bindTexture(&tex_Jf, J);
-
-        funcs[patch.y - 1][patch.x - 1](I.rows, I.cols, prevPts, nextPts, status, err, ptcount,
-            level, block, stream);
-    }
-
-    void sparse4(PtrStepSz<float4> I, PtrStepSz<float4> J, const float2* prevPts, float2* nextPts, uchar* status, float* err, int ptcount,
-                 int level, dim3 block, dim3 patch, cudaStream_t stream)
-    {
-        typedef void (*func_t)(int rows, int cols, const float2* prevPts, float2* nextPts, uchar* status, float* err, int ptcount,
-                               int level, dim3 block, cudaStream_t stream);
+            typedef void(*func_t)(PtrStepSz<typename TypeVec<T, cn>::vec_type> I, PtrStepSz<typename TypeVec<T, cn>::vec_type> J,
+                int rows, int cols, const float2* prevPts, float2* nextPts, uchar* status, float* err, int ptcount,
+                int level, dim3 block, cudaStream_t stream);
 
-        static const func_t funcs[5][5] =
+            static const func_t funcs[5][5] =
+            {
+                { sparse_caller<cn, 1, 1,T>::call, sparse_caller<cn, 2, 1,T>::call, sparse_caller<cn, 3, 1,T>::call, sparse_caller<cn, 4, 1,T>::call, sparse_caller<cn, 5, 1,T>::call },
+                { sparse_caller<cn, 1, 2,T>::call, sparse_caller<cn, 2, 2,T>::call, sparse_caller<cn, 3, 2,T>::call, sparse_caller<cn, 4, 2,T>::call, sparse_caller<cn, 5, 2,T>::call },
+                { sparse_caller<cn, 1, 3,T>::call, sparse_caller<cn, 2, 3,T>::call, sparse_caller<cn, 3, 3,T>::call, sparse_caller<cn, 4, 3,T>::call, sparse_caller<cn, 5, 3,T>::call },
+                { sparse_caller<cn, 1, 4,T>::call, sparse_caller<cn, 2, 4,T>::call, sparse_caller<cn, 3, 4,T>::call, sparse_caller<cn, 4, 4,T>::call, sparse_caller<cn, 5, 4,T>::call },
+                { sparse_caller<cn, 1, 5,T>::call, sparse_caller<cn, 2, 5,T>::call, sparse_caller<cn, 3, 5,T>::call, sparse_caller<cn, 4, 5,T>::call, sparse_caller<cn, 5, 5,T>::call }
+            };
+
+            Tex_I<cn, T>::bindTexture_(I);
+            Tex_J<cn, T>::bindTexture_(J);
+
+            funcs[patch.y - 1][patch.x - 1](I, J, I.rows, I.cols, prevPts, nextPts, status, err, ptcount,
+                level, block, stream);
+        }
+        static void dense(PtrStepSzb I, PtrStepSz<T> J, PtrStepSzf u, PtrStepSzf v, PtrStepSzf prevU, PtrStepSzf prevV, PtrStepSzf err, int2 winSize, cudaStream_t stream)
         {
-            {sparse_caller<4, 1, 1>, sparse_caller<4, 2, 1>, sparse_caller<4, 3, 1>, sparse_caller<4, 4, 1>, sparse_caller<4, 5, 1>},
-            {sparse_caller<4, 1, 2>, sparse_caller<4, 2, 2>, sparse_caller<4, 3, 2>, sparse_caller<4, 4, 2>, sparse_caller<4, 5, 2>},
-            {sparse_caller<4, 1, 3>, sparse_caller<4, 2, 3>, sparse_caller<4, 3, 3>, sparse_caller<4, 4, 3>, sparse_caller<4, 5, 3>},
-            {sparse_caller<4, 1, 4>, sparse_caller<4, 2, 4>, sparse_caller<4, 3, 4>, sparse_caller<4, 4, 4>, sparse_caller<4, 5, 4>},
-            {sparse_caller<4, 1, 5>, sparse_caller<4, 2, 5>, sparse_caller<4, 3, 5>, sparse_caller<4, 4, 5>, sparse_caller<4, 5, 5>}
-        };
-
-        bindTexture(&tex_If4, I);
-        bindTexture(&tex_Jf4, J);
+            dim3 block(16, 16);
+            dim3 grid(divUp(I.cols, block.x), divUp(I.rows, block.y));
+            Tex_I<1, uchar>::bindTexture_(I);
+            Tex_J<1, T>::bindTexture_(J);
 
-        funcs[patch.y - 1][patch.x - 1](I.rows, I.cols, prevPts, nextPts, status, err, ptcount,
-            level, block, stream);
-    }
+            int2 halfWin = make_int2((winSize.x - 1) / 2, (winSize.y - 1) / 2);
+            const int patchWidth = block.x + 2 * halfWin.x;
+            const int patchHeight = block.y + 2 * halfWin.y;
+            size_t smem_size = 3 * patchWidth * patchHeight * sizeof(int);
 
-    void dense(PtrStepSzb I, PtrStepSzf J, PtrStepSzf u, PtrStepSzf v, PtrStepSzf prevU, PtrStepSzf prevV, PtrStepSzf err, int2 winSize, cudaStream_t stream)
-    {
-        dim3 block(16, 16);
-        dim3 grid(divUp(I.cols, block.x), divUp(I.rows, block.y));
+            if (err.data)
+            {
+                denseKernel<true> << <grid, block, smem_size, stream >> >(u, v, prevU, prevV, err, I.rows, I.cols);
+                cudaSafeCall(cudaGetLastError());
+            }
+            else
+            {
+                denseKernel<false> << <grid, block, smem_size, stream >> >(u, v, prevU, prevV, PtrStepf(), I.rows, I.cols);
+                cudaSafeCall(cudaGetLastError());
+            }
 
-        bindTexture(&tex_Ib, I);
-        bindTexture(&tex_Jf, J);
+            if (stream == 0)
+                cudaSafeCall(cudaDeviceSynchronize());
+        }
+    };
 
-        int2 halfWin = make_int2((winSize.x - 1) / 2, (winSize.y - 1) / 2);
-        const int patchWidth  = block.x + 2 * halfWin.x;
-        const int patchHeight = block.y + 2 * halfWin.y;
-        size_t smem_size = 3 * patchWidth * patchHeight * sizeof(int);
+    template class pyrLK_caller<unsigned char,1>;
+    template class pyrLK_caller<unsigned short,1>;
+    template class pyrLK_caller<int,1>;
+    template class pyrLK_caller<float,1>;
 
-        if (err.data)
-        {
-            denseKernel<true><<<grid, block, smem_size, stream>>>(u, v, prevU, prevV, err, I.rows, I.cols);
-            cudaSafeCall( cudaGetLastError() );
-        }
-        else
-        {
-            denseKernel<false><<<grid, block, smem_size, stream>>>(u, v, prevU, prevV, PtrStepf(), I.rows, I.cols);
-            cudaSafeCall( cudaGetLastError() );
-        }
+    template class pyrLK_caller<unsigned char, 3>;
+    template class pyrLK_caller<unsigned short, 3>;
+    template class pyrLK_caller<int, 3>;
+    template class pyrLK_caller<float, 3>;
 
-        if (stream == 0)
-            cudaSafeCall( cudaDeviceSynchronize() );
-    }
+    template class pyrLK_caller<unsigned char, 4>;
+    template class pyrLK_caller<unsigned short, 4>;
+    template class pyrLK_caller<int, 4>;
+    template class pyrLK_caller<float, 4>;
 }
 
 #endif /* CUDA_DISABLER */
diff --git a/modules/cudaoptflow/src/farneback.cpp b/modules/cudaoptflow/src/farneback.cpp
index fb62df6..43032b4 100644
--- a/modules/cudaoptflow/src/farneback.cpp
+++ b/modules/cudaoptflow/src/farneback.cpp
@@ -93,7 +93,7 @@ namespace cv { namespace cuda { namespace device { namespace optflow_farneback
 
 namespace
 {
-    class FarnebackOpticalFlowImpl : public FarnebackOpticalFlow
+    class FarnebackOpticalFlowImpl : public cv::cuda::FarnebackOpticalFlow
     {
     public:
         FarnebackOpticalFlowImpl(int numLevels, double pyrScale, bool fastPyramids, int winSize,
@@ -459,7 +459,7 @@ namespace
     }
 }
 
-Ptr<FarnebackOpticalFlow> cv::cuda::FarnebackOpticalFlow::create(int numLevels, double pyrScale, bool fastPyramids, int winSize,
+Ptr<cv::cuda::FarnebackOpticalFlow> cv::cuda::FarnebackOpticalFlow::create(int numLevels, double pyrScale, bool fastPyramids, int winSize,
                                                                  int numIters, int polyN, double polySigma, int flags)
 {
     return makePtr<FarnebackOpticalFlowImpl>(numLevels, pyrScale, fastPyramids, winSize,
diff --git a/modules/cudaoptflow/src/precomp.hpp b/modules/cudaoptflow/src/precomp.hpp
index 3c818dd..d5ac493 100644
--- a/modules/cudaoptflow/src/precomp.hpp
+++ b/modules/cudaoptflow/src/precomp.hpp
@@ -52,7 +52,7 @@
 #include "opencv2/video.hpp"
 
 #include "opencv2/core/private.cuda.hpp"
-
+#include "opencv2/core/cuda/vec_traits.hpp"
 #include "opencv2/opencv_modules.hpp"
 
 #ifdef HAVE_OPENCV_CUDALEGACY
diff --git a/modules/cudaoptflow/src/pyrlk.cpp b/modules/cudaoptflow/src/pyrlk.cpp
index 9d7db0a..c7f7060 100644
--- a/modules/cudaoptflow/src/pyrlk.cpp
+++ b/modules/cudaoptflow/src/pyrlk.cpp
@@ -47,23 +47,29 @@ using namespace cv::cuda;
 
 #if !defined (HAVE_CUDA) || defined (CUDA_DISABLER)
 
-Ptr<SparsePyrLKOpticalFlow> cv::cuda::SparsePyrLKOpticalFlow::create(Size, int, int, bool) { throw_no_cuda(); return Ptr<SparsePyrLKOpticalFlow>(); }
+Ptr<cv::cuda::SparsePyrLKOpticalFlow> cv::cuda::SparsePyrLKOpticalFlow::create(Size, int, int, bool) { throw_no_cuda(); return Ptr<SparsePyrLKOpticalFlow>(); }
 
-Ptr<DensePyrLKOpticalFlow> cv::cuda::DensePyrLKOpticalFlow::create(Size, int, int, bool) { throw_no_cuda(); return Ptr<DensePyrLKOpticalFlow>(); }
+Ptr<cv::cuda::DensePyrLKOpticalFlow> cv::cuda::DensePyrLKOpticalFlow::create(Size, int, int, bool) { throw_no_cuda(); return Ptr<DensePyrLKOpticalFlow>(); }
 
 #else /* !defined (HAVE_CUDA) */
 
 namespace pyrlk
 {
     void loadConstants(int2 winSize, int iters, cudaStream_t stream);
+    template<typename T, int cn> struct pyrLK_caller
+    {
+        static void sparse(PtrStepSz<typename device::TypeVec<T, cn>::vec_type> I, PtrStepSz<typename device::TypeVec<T, cn>::vec_type> J, const float2* prevPts, float2* nextPts, uchar* status, float* err, int ptcount,
+            int level, dim3 block, dim3 patch, cudaStream_t stream);
 
-    void sparse1(PtrStepSzf I, PtrStepSzf J, const float2* prevPts, float2* nextPts, uchar* status, float* err, int ptcount,
-                 int level, dim3 block, dim3 patch, cudaStream_t stream);
-    void sparse4(PtrStepSz<float4> I, PtrStepSz<float4> J, const float2* prevPts, float2* nextPts, uchar* status, float* err, int ptcount,
-                 int level, dim3 block, dim3 patch, cudaStream_t stream);
+        static void dense(PtrStepSzb I, PtrStepSzf J, PtrStepSzf u, PtrStepSzf v, PtrStepSzf prevU, PtrStepSzf prevV,
+            PtrStepSzf err, int2 winSize, cudaStream_t stream);
+    };
 
-    void dense(PtrStepSzb I, PtrStepSzf J, PtrStepSzf u, PtrStepSzf v, PtrStepSzf prevU, PtrStepSzf prevV,
-               PtrStepSzf err, int2 winSize, cudaStream_t stream);
+    template<typename T, int cn> void dispatcher(GpuMat I, GpuMat J, const float2* prevPts, float2* nextPts, uchar* status, float* err, int ptcount,
+        int level, dim3 block, dim3 patch, cudaStream_t stream)
+    {
+        pyrLK_caller<T, cn>::sparse(I, J, prevPts, nextPts, status, err, ptcount, level, block, patch, stream);
+    }
 }
 
 namespace
@@ -76,6 +82,9 @@ namespace
         void sparse(const GpuMat& prevImg, const GpuMat& nextImg, const GpuMat& prevPts, GpuMat& nextPts,
             GpuMat& status, GpuMat* err, Stream& stream);
 
+        void sparse(std::vector<GpuMat>& prevPyr, std::vector<GpuMat>& nextPyr, const GpuMat& prevPts, GpuMat& nextPts,
+            GpuMat& status, GpuMat* err, Stream& stream);
+
         void dense(const GpuMat& prevImg, const GpuMat& nextImg, GpuMat& u, GpuMat& v, Stream& stream);
 
     protected:
@@ -83,8 +92,9 @@ namespace
         int maxLevel_;
         int iters_;
         bool useInitialFlow_;
-
+        void buildImagePyramid(const GpuMat& prevImg, std::vector<GpuMat>& prevPyr, const GpuMat& nextImg, std::vector<GpuMat>& nextPyr, Stream stream);
     private:
+        friend class SparsePyrLKOpticalFlowImpl;
         std::vector<GpuMat> prevPyr_;
         std::vector<GpuMat> nextPyr_;
     };
@@ -113,28 +123,34 @@ namespace
         block.z = patch.z = 1;
     }
 
-    void PyrLKOpticalFlowBase::sparse(const GpuMat& prevImg, const GpuMat& nextImg, const GpuMat& prevPts, GpuMat& nextPts, GpuMat& status, GpuMat* err, Stream& stream)
+    void PyrLKOpticalFlowBase::buildImagePyramid(const GpuMat& prevImg, std::vector<GpuMat>& prevPyr, const GpuMat& nextImg, std::vector<GpuMat>& nextPyr, Stream stream)
     {
-        if (prevPts.empty())
-        {
-            nextPts.release();
-            status.release();
-            if (err) err->release();
-            return;
-        }
+        prevPyr.resize(maxLevel_ + 1);
+        nextPyr.resize(maxLevel_ + 1);
 
-        dim3 block, patch;
-        calcPatchSize(winSize_, block, patch);
+        int cn = prevImg.channels();
 
-        CV_Assert( prevImg.channels() == 1 || prevImg.channels() == 3 || prevImg.channels() == 4 );
-        CV_Assert( prevImg.size() == nextImg.size() && prevImg.type() == nextImg.type() );
-        CV_Assert( maxLevel_ >= 0 );
-        CV_Assert( winSize_.width > 2 && winSize_.height > 2 );
-        CV_Assert( patch.x > 0 && patch.x < 6 && patch.y > 0 && patch.y < 6 );
-        CV_Assert( prevPts.rows == 1 && prevPts.type() == CV_32FC2 );
+        CV_Assert(cn == 1 || cn == 3 || cn == 4);
+
+        prevPyr[0] = prevImg;
+        nextPyr[0] = nextImg;
 
+        for (int level = 1; level <= maxLevel_; ++level)
+        {
+            cuda::pyrDown(prevPyr[level - 1], prevPyr[level], stream);
+            cuda::pyrDown(nextPyr[level - 1], nextPyr[level], stream);
+        }
+    }
+    void PyrLKOpticalFlowBase::sparse(std::vector<GpuMat>& prevPyr, std::vector<GpuMat>& nextPyr, const GpuMat& prevPts, GpuMat& nextPts,
+        GpuMat& status, GpuMat* err, Stream& stream)
+    {
+        CV_Assert(prevPyr.size() && nextPyr.size() && "Pyramid needs to at least contain the original matrix as the first element");
+        CV_Assert(prevPyr[0].size() == nextPyr[0].size());
+        CV_Assert(prevPts.rows == 1 && prevPts.type() == CV_32FC2);
+        CV_Assert(maxLevel_ >= 0);
+        CV_Assert(winSize_.width > 2 && winSize_.height > 2);
         if (useInitialFlow_)
-            CV_Assert( nextPts.size() == prevPts.size() && nextPts.type() == prevPts.type() );
+            CV_Assert(nextPts.size() == prevPts.size() && nextPts.type() == prevPts.type());
         else
             ensureSizeIsEnough(1, prevPts.cols, prevPts.type(), nextPts);
 
@@ -142,66 +158,70 @@ namespace
         GpuMat temp2 = nextPts.reshape(1);
         cuda::multiply(temp1, Scalar::all(1.0 / (1 << maxLevel_) / 2.0), temp2, 1, -1, stream);
 
+
         ensureSizeIsEnough(1, prevPts.cols, CV_8UC1, status);
         status.setTo(Scalar::all(1), stream);
 
         if (err)
             ensureSizeIsEnough(1, prevPts.cols, CV_32FC1, *err);
 
-        // build the image pyramids.
+        if (prevPyr.size() != size_t(maxLevel_ + 1) || nextPyr.size() != size_t(maxLevel_ + 1))
+        {
+            buildImagePyramid(prevPyr[0], prevPyr, nextPyr[0], nextPyr, stream);
+        }
 
-        BufferPool pool(stream);
+        dim3 block, patch;
+        calcPatchSize(winSize_, block, patch);
+        CV_Assert(patch.x > 0 && patch.x < 6 && patch.y > 0 && patch.y < 6);
+        pyrlk::loadConstants(make_int2(winSize_.width, winSize_.height), iters_, StreamAccessor::getStream(stream));
 
-        prevPyr_.resize(maxLevel_ + 1);
-        nextPyr_.resize(maxLevel_ + 1);
+        const int cn = prevPyr[0].channels();
+        const int type = prevPyr[0].depth();
 
-        int cn = prevImg.channels();
+        typedef void(*func_t)(GpuMat I, GpuMat J, const float2* prevPts, float2* nextPts, uchar* status, float* err, int ptcount,
+            int level, dim3 block, dim3 patch, cudaStream_t stream);
 
-        if (cn == 1 || cn == 4)
+        // Current int datatype is disabled due to pyrDown not implementing it
+        // while ushort does work, it has significantly worse performance, and thus doesn't pass accuracy tests.
+        static const func_t funcs[6][4] =
         {
-            prevImg.convertTo(prevPyr_[0], CV_32F, stream);
-            nextImg.convertTo(nextPyr_[0], CV_32F, stream);
-        }
-        else
-        {
-            GpuMat buf = pool.getBuffer(prevImg.size(), CV_MAKE_TYPE(prevImg.depth(), 4));
-
-            cuda::cvtColor(prevImg, buf, COLOR_BGR2BGRA, 0, stream);
-            buf.convertTo(prevPyr_[0], CV_32F, stream);
+          {   pyrlk::dispatcher<uchar, 1>     , /*pyrlk::dispatcher<uchar, 2>*/ 0, pyrlk::dispatcher<uchar, 3>     ,   pyrlk::dispatcher<uchar, 4>    },
+          { /*pyrlk::dispatcher<char, 1>*/   0, /*pyrlk::dispatcher<char, 2>*/  0, /*pyrlk::dispatcher<char, 3>*/  0, /*pyrlk::dispatcher<char, 4>*/ 0 },
+          { pyrlk::dispatcher<ushort, 1>      , /*pyrlk::dispatcher<ushort, 2>*/0, pyrlk::dispatcher<ushort, 3>     ,   pyrlk::dispatcher<ushort, 4>   },
+          { /*pyrlk::dispatcher<short, 1>*/  0, /*pyrlk::dispatcher<short, 2>*/ 0, /*pyrlk::dispatcher<short, 3>*/ 0, /*pyrlk::dispatcher<short, 4>*/0 },
+          {   pyrlk::dispatcher<int, 1>       , /*pyrlk::dispatcher<int, 2>*/   0, pyrlk::dispatcher<int, 3>        ,   pyrlk::dispatcher<int, 4>      },
+          {   pyrlk::dispatcher<float, 1>     , /*pyrlk::dispatcher<float, 2>*/ 0, pyrlk::dispatcher<float, 3>      ,   pyrlk::dispatcher<float, 4>    }
+        };
 
-            cuda::cvtColor(nextImg, buf, COLOR_BGR2BGRA, 0, stream);
-            buf.convertTo(nextPyr_[0], CV_32F, stream);
+        func_t func = funcs[type][cn-1];
+        CV_Assert(func != NULL && "Datatype not implemented");
+        for (int level = maxLevel_; level >= 0; level--)
+        {
+            func(prevPyr[level], nextPyr[level],
+                prevPts.ptr<float2>(), nextPts.ptr<float2>(),
+                status.ptr(), level == 0 && err ? err->ptr<float>() : 0,
+                prevPts.cols, level, block, patch,
+                StreamAccessor::getStream(stream));
         }
+    }
 
-        for (int level = 1; level <= maxLevel_; ++level)
+    void PyrLKOpticalFlowBase::sparse(const GpuMat& prevImg, const GpuMat& nextImg, const GpuMat& prevPts, GpuMat& nextPts, GpuMat& status, GpuMat* err, Stream& stream)
+    {
+        if (prevPts.empty())
         {
-            cuda::pyrDown(prevPyr_[level - 1], prevPyr_[level], stream);
-            cuda::pyrDown(nextPyr_[level - 1], nextPyr_[level], stream);
+            nextPts.release();
+            status.release();
+            if (err) err->release();
+            return;
         }
+        CV_Assert( prevImg.channels() == 1 || prevImg.channels() == 3 || prevImg.channels() == 4 );
+        CV_Assert( prevImg.size() == nextImg.size() && prevImg.type() == nextImg.type() );
 
-        pyrlk::loadConstants(make_int2(winSize_.width, winSize_.height), iters_, StreamAccessor::getStream(stream));
+        // build the image pyramids.
+        buildImagePyramid(prevImg, prevPyr_, nextImg, nextPyr_, stream);
+
+        sparse(prevPyr_, nextPyr_, prevPts, nextPts, status, err, stream);
 
-        for (int level = maxLevel_; level >= 0; level--)
-        {
-            if (cn == 1)
-            {
-                pyrlk::sparse1(prevPyr_[level], nextPyr_[level],
-                               prevPts.ptr<float2>(), nextPts.ptr<float2>(),
-                               status.ptr(),
-                               level == 0 && err ? err->ptr<float>() : 0, prevPts.cols,
-                               level, block, patch,
-                               StreamAccessor::getStream(stream));
-            }
-            else
-            {
-                pyrlk::sparse4(prevPyr_[level], nextPyr_[level],
-                               prevPts.ptr<float2>(), nextPts.ptr<float2>(),
-                               status.ptr(),
-                               level == 0 && err ? err->ptr<float>() : 0, prevPts.cols,
-                               level, block, patch,
-                               StreamAccessor::getStream(stream));
-            }
-        }
     }
 
     void PyrLKOpticalFlowBase::dense(const GpuMat& prevImg, const GpuMat& nextImg, GpuMat& u, GpuMat& v, Stream& stream)
@@ -250,7 +270,7 @@ namespace
         {
             int idx2 = (idx + 1) & 1;
 
-            pyrlk::dense(prevPyr_[level], nextPyr_[level],
+            pyrlk::pyrLK_caller<float,1>::dense(prevPyr_[level], nextPyr_[level],
                          uPyr[idx], vPyr[idx], uPyr[idx2], vPyr[idx2],
                          PtrStepSzf(), winSize2i,
                          StreamAccessor::getStream(stream));
@@ -263,7 +283,7 @@ namespace
         vPyr[idx].copyTo(v, stream);
     }
 
-    class SparsePyrLKOpticalFlowImpl : public SparsePyrLKOpticalFlow, private PyrLKOpticalFlowBase
+    class SparsePyrLKOpticalFlowImpl : public cv::cuda::SparsePyrLKOpticalFlow, private PyrLKOpticalFlowBase
     {
     public:
         SparsePyrLKOpticalFlowImpl(Size winSize, int maxLevel, int iters, bool useInitialFlow) :
@@ -289,14 +309,23 @@ namespace
                           OutputArray _err,
                           Stream& stream)
         {
-            const GpuMat prevImg = _prevImg.getGpuMat();
-            const GpuMat nextImg = _nextImg.getGpuMat();
             const GpuMat prevPts = _prevPts.getGpuMat();
             GpuMat& nextPts = _nextPts.getGpuMatRef();
             GpuMat& status = _status.getGpuMatRef();
             GpuMat* err = _err.needed() ? &(_err.getGpuMatRef()) : NULL;
-
-            sparse(prevImg, nextImg, prevPts, nextPts, status, err, stream);
+            if (_prevImg.kind() == _InputArray::STD_VECTOR_CUDA_GPU_MAT && _prevImg.kind() == _InputArray::STD_VECTOR_CUDA_GPU_MAT)
+            {
+                std::vector<GpuMat> prevPyr, nextPyr;
+                _prevImg.getGpuMatVector(prevPyr);
+                _nextImg.getGpuMatVector(nextPyr);
+                sparse(prevPyr, nextPyr, prevPts, nextPts, status, err, stream);
+            }
+            else
+            {
+                const GpuMat prevImg = _prevImg.getGpuMat();
+                const GpuMat nextImg = _nextImg.getGpuMat();
+                sparse(prevImg, nextImg, prevPts, nextPts, status, err, stream);
+            }
         }
     };
 
@@ -337,12 +366,12 @@ namespace
     };
 }
 
-Ptr<SparsePyrLKOpticalFlow> cv::cuda::SparsePyrLKOpticalFlow::create(Size winSize, int maxLevel, int iters, bool useInitialFlow)
+Ptr<cv::cuda::SparsePyrLKOpticalFlow> cv::cuda::SparsePyrLKOpticalFlow::create(Size winSize, int maxLevel, int iters, bool useInitialFlow)
 {
     return makePtr<SparsePyrLKOpticalFlowImpl>(winSize, maxLevel, iters, useInitialFlow);
 }
 
-Ptr<DensePyrLKOpticalFlow> cv::cuda::DensePyrLKOpticalFlow::create(Size winSize, int maxLevel, int iters, bool useInitialFlow)
+Ptr<cv::cuda::DensePyrLKOpticalFlow> cv::cuda::DensePyrLKOpticalFlow::create(Size winSize, int maxLevel, int iters, bool useInitialFlow)
 {
     return makePtr<DensePyrLKOpticalFlowImpl>(winSize, maxLevel, iters, useInitialFlow);
 }
diff --git a/modules/cudaoptflow/test/test_optflow.cpp b/modules/cudaoptflow/test/test_optflow.cpp
index 63bc461..fe910d2 100644
--- a/modules/cudaoptflow/test/test_optflow.cpp
+++ b/modules/cudaoptflow/test/test_optflow.cpp
@@ -46,6 +46,8 @@
 
 using namespace cvtest;
 
+namespace {
+
 //////////////////////////////////////////////////////
 // BroxOpticalFlow
 
@@ -167,33 +169,34 @@ INSTANTIATE_TEST_CASE_P(CUDA_OptFlow, BroxOpticalFlow, ALL_DEVICES);
 
 namespace
 {
-    IMPLEMENT_PARAM_CLASS(UseGray, bool)
+    IMPLEMENT_PARAM_CLASS(Chan, int)
+    IMPLEMENT_PARAM_CLASS(DataType, int)
 }
 
-PARAM_TEST_CASE(PyrLKOpticalFlow, cv::cuda::DeviceInfo, UseGray)
+PARAM_TEST_CASE(PyrLKOpticalFlow, cv::cuda::DeviceInfo, Chan, DataType)
 {
     cv::cuda::DeviceInfo devInfo;
-    bool useGray;
-
+    int channels;
+    int dataType;
     virtual void SetUp()
     {
         devInfo = GET_PARAM(0);
-        useGray = GET_PARAM(1);
-
+        channels = GET_PARAM(1);
+        dataType = GET_PARAM(2);
         cv::cuda::setDevice(devInfo.deviceID());
     }
 };
 
 CUDA_TEST_P(PyrLKOpticalFlow, Sparse)
 {
-    cv::Mat frame0 = readImage("opticalflow/frame0.png", useGray ? cv::IMREAD_GRAYSCALE : cv::IMREAD_COLOR);
+    cv::Mat frame0 = readImage("opticalflow/frame0.png", channels == 1 ? cv::IMREAD_GRAYSCALE : cv::IMREAD_COLOR);
     ASSERT_FALSE(frame0.empty());
 
-    cv::Mat frame1 = readImage("opticalflow/frame1.png", useGray ? cv::IMREAD_GRAYSCALE : cv::IMREAD_COLOR);
+    cv::Mat frame1 = readImage("opticalflow/frame1.png", channels == 1 ? cv::IMREAD_GRAYSCALE : cv::IMREAD_COLOR);
     ASSERT_FALSE(frame1.empty());
 
     cv::Mat gray_frame;
-    if (useGray)
+    if (channels == 1)
         gray_frame = frame0;
     else
         cv::cvtColor(frame0, gray_frame, cv::COLOR_BGR2GRAY);
@@ -208,22 +211,32 @@ CUDA_TEST_P(PyrLKOpticalFlow, Sparse)
     cv::Ptr<cv::cuda::SparsePyrLKOpticalFlow> pyrLK =
             cv::cuda::SparsePyrLKOpticalFlow::create();
 
+    std::vector<cv::Point2f> nextPts_gold;
+    std::vector<unsigned char> status_gold;
+    cv::calcOpticalFlowPyrLK(frame0, frame1, pts, nextPts_gold, status_gold, cv::noArray());
+
+
     cv::cuda::GpuMat d_nextPts;
     cv::cuda::GpuMat d_status;
-    pyrLK->calc(loadMat(frame0), loadMat(frame1), d_pts, d_nextPts, d_status);
+    cv::Mat converted0, converted1;
+    if(channels == 4)
+    {
+        cv::cvtColor(frame0, frame0, cv::COLOR_BGR2BGRA);
+        cv::cvtColor(frame1, frame1, cv::COLOR_BGR2BGRA);
+    }
+    frame0.convertTo(converted0, dataType);
+    frame1.convertTo(converted1, dataType);
+
+    pyrLK->calc(loadMat(converted0), loadMat(converted1), d_pts, d_nextPts, d_status);
 
     std::vector<cv::Point2f> nextPts(d_nextPts.cols);
-    cv::Mat nextPts_mat(1, d_nextPts.cols, CV_32FC2, (void*) &nextPts[0]);
+    cv::Mat nextPts_mat(1, d_nextPts.cols, CV_32FC2, (void*)&nextPts[0]);
     d_nextPts.download(nextPts_mat);
 
     std::vector<unsigned char> status(d_status.cols);
-    cv::Mat status_mat(1, d_status.cols, CV_8UC1, (void*) &status[0]);
+    cv::Mat status_mat(1, d_status.cols, CV_8UC1, (void*)&status[0]);
     d_status.download(status_mat);
 
-    std::vector<cv::Point2f> nextPts_gold;
-    std::vector<unsigned char> status_gold;
-    cv::calcOpticalFlowPyrLK(frame0, frame1, pts, nextPts_gold, status_gold, cv::noArray());
-
     ASSERT_EQ(nextPts_gold.size(), nextPts.size());
     ASSERT_EQ(status_gold.size(), status.size());
 
@@ -251,11 +264,16 @@ CUDA_TEST_P(PyrLKOpticalFlow, Sparse)
     double bad_ratio = static_cast<double>(mistmatch) / nextPts.size();
 
     ASSERT_LE(bad_ratio, 0.01);
+
+
 }
 
 INSTANTIATE_TEST_CASE_P(CUDA_OptFlow, PyrLKOpticalFlow, testing::Combine(
     ALL_DEVICES,
-    testing::Values(UseGray(true), UseGray(false))));
+    testing::Values(Chan(1), Chan(3), Chan(4)),
+    testing::Values(DataType(CV_8U), DataType(CV_16U), DataType(CV_32S), DataType(CV_32F))));
+
+
 
 //////////////////////////////////////////////////////
 // FarnebackOpticalFlow
@@ -385,4 +403,6 @@ INSTANTIATE_TEST_CASE_P(CUDA_OptFlow, OpticalFlowDual_TVL1, testing::Combine(
     ALL_DEVICES,
     testing::Values(Gamma(0.0), Gamma(1.0))));
 
+} // namespace
+
 #endif // HAVE_CUDA
diff --git a/modules/cudastereo/include/opencv2/cudastereo.hpp b/modules/cudastereo/include/opencv2/cudastereo.hpp
index c734f5c..c9afd47 100644
--- a/modules/cudastereo/include/opencv2/cudastereo.hpp
+++ b/modules/cudastereo/include/opencv2/cudastereo.hpp
@@ -40,8 +40,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_CUDASTEREO_HPP__
-#define __OPENCV_CUDASTEREO_HPP__
+#ifndef OPENCV_CUDASTEREO_HPP
+#define OPENCV_CUDASTEREO_HPP
 
 #ifndef __cplusplus
 #  error cudastereo.hpp header must be compiled as C++
@@ -330,4 +330,4 @@ CV_EXPORTS void drawColorDisp(InputArray src_disp, OutputArray dst_disp, int ndi
 
 }} // namespace cv { namespace cuda {
 
-#endif /* __OPENCV_CUDASTEREO_HPP__ */
+#endif /* OPENCV_CUDASTEREO_HPP */
diff --git a/modules/cudastereo/test/test_stereo.cpp b/modules/cudastereo/test/test_stereo.cpp
index bc9aa37..de801cf 100644
--- a/modules/cudastereo/test/test_stereo.cpp
+++ b/modules/cudastereo/test/test_stereo.cpp
@@ -46,6 +46,8 @@
 
 using namespace cvtest;
 
+namespace {
+
 //////////////////////////////////////////////////////////////////////////
 // StereoBM
 
@@ -209,4 +211,6 @@ INSTANTIATE_TEST_CASE_P(CUDA_Stereo, ReprojectImageTo3D, testing::Combine(
     testing::Values(MatDepth(CV_8U), MatDepth(CV_16S)),
     WHOLE_SUBMAT));
 
+} // namespace
+
 #endif // HAVE_CUDA
diff --git a/modules/cudawarping/include/opencv2/cudawarping.hpp b/modules/cudawarping/include/opencv2/cudawarping.hpp
index 66c41cc..ca2357a 100644
--- a/modules/cudawarping/include/opencv2/cudawarping.hpp
+++ b/modules/cudawarping/include/opencv2/cudawarping.hpp
@@ -40,8 +40,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_CUDAWARPING_HPP__
-#define __OPENCV_CUDAWARPING_HPP__
+#ifndef OPENCV_CUDAWARPING_HPP
+#define OPENCV_CUDAWARPING_HPP
 
 #ifndef __cplusplus
 #  error cudawarping.hpp header must be compiled as C++
@@ -213,4 +213,4 @@ CV_EXPORTS void pyrUp(InputArray src, OutputArray dst, Stream& stream = Stream::
 
 }} // namespace cv { namespace cuda {
 
-#endif /* __OPENCV_CUDAWARPING_HPP__ */
+#endif /* OPENCV_CUDAWARPING_HPP */
diff --git a/modules/cudawarping/src/cuda/pyr_down.cu b/modules/cudawarping/src/cuda/pyr_down.cu
index 3207d65..03e791d 100644
--- a/modules/cudawarping/src/cuda/pyr_down.cu
+++ b/modules/cudawarping/src/cuda/pyr_down.cu
@@ -212,10 +212,10 @@ namespace cv { namespace cuda { namespace device
         template void pyrDown_gpu<short3>(PtrStepSzb src, PtrStepSzb dst, cudaStream_t stream);
         template void pyrDown_gpu<short4>(PtrStepSzb src, PtrStepSzb dst, cudaStream_t stream);
 
-        //template void pyrDown_gpu<int>(PtrStepSzb src, PtrStepSzb dst, cudaStream_t stream);
+        template void pyrDown_gpu<int>(PtrStepSzb src, PtrStepSzb dst, cudaStream_t stream);
         //template void pyrDown_gpu<int2>(PtrStepSzb src, PtrStepSzb dst, cudaStream_t stream);
-        //template void pyrDown_gpu<int3>(PtrStepSzb src, PtrStepSzb dst, cudaStream_t stream);
-        //template void pyrDown_gpu<int4>(PtrStepSzb src, PtrStepSzb dst, cudaStream_t stream);
+        template void pyrDown_gpu<int3>(PtrStepSzb src, PtrStepSzb dst, cudaStream_t stream);
+        template void pyrDown_gpu<int4>(PtrStepSzb src, PtrStepSzb dst, cudaStream_t stream);
 
         template void pyrDown_gpu<float>(PtrStepSzb src, PtrStepSzb dst, cudaStream_t stream);
         //template void pyrDown_gpu<float2>(PtrStepSzb src, PtrStepSzb dst, cudaStream_t stream);
@@ -225,4 +225,4 @@ namespace cv { namespace cuda { namespace device
 }}} // namespace cv { namespace cuda { namespace cudev
 
 
-#endif /* CUDA_DISABLER */
+#endif /* CUDA_DISABLER */
\ No newline at end of file
diff --git a/modules/cudawarping/src/pyramids.cpp b/modules/cudawarping/src/pyramids.cpp
index 0cb0f5d..817a167 100644
--- a/modules/cudawarping/src/pyramids.cpp
+++ b/modules/cudawarping/src/pyramids.cpp
@@ -74,7 +74,7 @@ void cv::cuda::pyrDown(InputArray _src, OutputArray _dst, Stream& stream)
         {0 /*pyrDown_gpu<schar>*/, 0 /*pyrDown_gpu<schar2>*/ , 0 /*pyrDown_gpu<schar3>*/, 0 /*pyrDown_gpu<schar4>*/},
         {pyrDown_gpu<ushort>     , 0 /*pyrDown_gpu<ushort2>*/, pyrDown_gpu<ushort3>     , pyrDown_gpu<ushort4>     },
         {pyrDown_gpu<short>      , 0 /*pyrDown_gpu<short2>*/ , pyrDown_gpu<short3>      , pyrDown_gpu<short4>      },
-        {0 /*pyrDown_gpu<int>*/  , 0 /*pyrDown_gpu<int2>*/   , 0 /*pyrDown_gpu<int3>*/  , 0 /*pyrDown_gpu<int4>*/  },
+        {pyrDown_gpu<int>        , 0 /*pyrDown_gpu<int2>*/   , pyrDown_gpu<int3>        , pyrDown_gpu<int4>        },
         {pyrDown_gpu<float>      , 0 /*pyrDown_gpu<float2>*/ , pyrDown_gpu<float3>      , pyrDown_gpu<float4>      }
     };
 
@@ -131,4 +131,4 @@ void cv::cuda::pyrUp(InputArray _src, OutputArray _dst, Stream& stream)
     func(src, dst, StreamAccessor::getStream(stream));
 }
 
-#endif
+#endif
\ No newline at end of file
diff --git a/modules/cudev/CMakeLists.txt b/modules/cudev/CMakeLists.txt
index 2575729..e27186c5 100644
--- a/modules/cudev/CMakeLists.txt
+++ b/modules/cudev/CMakeLists.txt
@@ -10,13 +10,16 @@ ocv_add_module(cudev)
 
 ocv_module_include_directories(opencv_core opencv_hal)
 
-file(GLOB_RECURSE lib_hdrs "include/opencv2/*.hpp")
-file(GLOB         lib_srcs "src/*.cpp")
+file(GLOB_RECURSE lib_hdrs "${CMAKE_CURRENT_LIST_DIR}/include/opencv2/${name}/*.hpp")
+file(GLOB         lib_srcs "${CMAKE_CURRENT_LIST_DIR}/src/*.cpp")
 
-ocv_set_module_sources(HEADERS ${lib_hdrs} SOURCES ${lib_srcs})
+source_group("Include" FILES ${lib_hdrs})
+source_group("Src" FILES ${lib_srcs})
+
+ocv_glob_module_sources(HEADERS ${lib_hdrs} SOURCES ${lib_srcs})
 
 ocv_create_module()
 
-if(BUILD_TESTS)
+if(BUILD_TESTS AND NOT BUILD_opencv_world)
   add_subdirectory(test)
 endif()
diff --git a/modules/cudev/include/opencv2/cudev.hpp b/modules/cudev/include/opencv2/cudev.hpp
index 565efa1..1f435c2 100644
--- a/modules/cudev/include/opencv2/cudev.hpp
+++ b/modules/cudev/include/opencv2/cudev.hpp
@@ -43,8 +43,8 @@
 
 #pragma once
 
-#ifndef __OPENCV_CUDEV_HPP__
-#define __OPENCV_CUDEV_HPP__
+#ifndef OPENCV_CUDEV_HPP
+#define OPENCV_CUDEV_HPP
 
 #include "cudev/common.hpp"
 
diff --git a/modules/cudev/include/opencv2/cudev/block/block.hpp b/modules/cudev/include/opencv2/cudev/block/block.hpp
index e8d59bb..7c502aa 100644
--- a/modules/cudev/include/opencv2/cudev/block/block.hpp
+++ b/modules/cudev/include/opencv2/cudev/block/block.hpp
@@ -43,8 +43,8 @@
 
 #pragma once
 
-#ifndef __OPENCV_CUDEV_BLOCK_BLOCK_HPP__
-#define __OPENCV_CUDEV_BLOCK_BLOCK_HPP__
+#ifndef OPENCV_CUDEV_BLOCK_BLOCK_HPP
+#define OPENCV_CUDEV_BLOCK_BLOCK_HPP
 
 #include "../common.hpp"
 
diff --git a/modules/cudev/include/opencv2/cudev/block/detail/reduce.hpp b/modules/cudev/include/opencv2/cudev/block/detail/reduce.hpp
index 02803b0..ca10772 100644
--- a/modules/cudev/include/opencv2/cudev/block/detail/reduce.hpp
+++ b/modules/cudev/include/opencv2/cudev/block/detail/reduce.hpp
@@ -43,8 +43,8 @@
 
 #pragma once
 
-#ifndef __OPENCV_CUDEV_BLOCK_REDUCE_DETAIL_HPP__
-#define __OPENCV_CUDEV_BLOCK_REDUCE_DETAIL_HPP__
+#ifndef OPENCV_CUDEV_BLOCK_REDUCE_DETAIL_HPP
+#define OPENCV_CUDEV_BLOCK_REDUCE_DETAIL_HPP
 
 #include "../../common.hpp"
 #include "../../util/tuple.hpp"
diff --git a/modules/cudev/include/opencv2/cudev/block/detail/reduce_key_val.hpp b/modules/cudev/include/opencv2/cudev/block/detail/reduce_key_val.hpp
index edbe8a5..4af834a 100644
--- a/modules/cudev/include/opencv2/cudev/block/detail/reduce_key_val.hpp
+++ b/modules/cudev/include/opencv2/cudev/block/detail/reduce_key_val.hpp
@@ -43,8 +43,8 @@
 
 #pragma once
 
-#ifndef __OPENCV_CUDEV_BLOCK_REDUCE_KEY_VAL_DETAIL_HPP__
-#define __OPENCV_CUDEV_BLOCK_REDUCE_KEY_VAL_DETAIL_HPP__
+#ifndef OPENCV_CUDEV_BLOCK_REDUCE_KEY_VAL_DETAIL_HPP
+#define OPENCV_CUDEV_BLOCK_REDUCE_KEY_VAL_DETAIL_HPP
 
 #include "../../common.hpp"
 #include "../../util/tuple.hpp"
diff --git a/modules/cudev/include/opencv2/cudev/block/dynamic_smem.hpp b/modules/cudev/include/opencv2/cudev/block/dynamic_smem.hpp
index e52f829..610de30 100644
--- a/modules/cudev/include/opencv2/cudev/block/dynamic_smem.hpp
+++ b/modules/cudev/include/opencv2/cudev/block/dynamic_smem.hpp
@@ -43,8 +43,8 @@
 
 #pragma once
 
-#ifndef __OPENCV_CUDEV_BLOCK_DYNAMIC_SMEM_HPP__
-#define __OPENCV_CUDEV_BLOCK_DYNAMIC_SMEM_HPP__
+#ifndef OPENCV_CUDEV_BLOCK_DYNAMIC_SMEM_HPP
+#define OPENCV_CUDEV_BLOCK_DYNAMIC_SMEM_HPP
 
 #include "../common.hpp"
 
diff --git a/modules/cudev/include/opencv2/cudev/block/reduce.hpp b/modules/cudev/include/opencv2/cudev/block/reduce.hpp
index 74c8fca..06f59a1 100644
--- a/modules/cudev/include/opencv2/cudev/block/reduce.hpp
+++ b/modules/cudev/include/opencv2/cudev/block/reduce.hpp
@@ -43,8 +43,8 @@
 
 #pragma once
 
-#ifndef __OPENCV_CUDEV_BLOCK_REDUCE_HPP__
-#define __OPENCV_CUDEV_BLOCK_REDUCE_HPP__
+#ifndef OPENCV_CUDEV_BLOCK_REDUCE_HPP
+#define OPENCV_CUDEV_BLOCK_REDUCE_HPP
 
 #include "../common.hpp"
 #include "../util/tuple.hpp"
diff --git a/modules/cudev/include/opencv2/cudev/block/scan.hpp b/modules/cudev/include/opencv2/cudev/block/scan.hpp
index 3369cff..cd75a3e 100644
--- a/modules/cudev/include/opencv2/cudev/block/scan.hpp
+++ b/modules/cudev/include/opencv2/cudev/block/scan.hpp
@@ -43,8 +43,8 @@
 
 #pragma once
 
-#ifndef __OPENCV_CUDEV_BLOCK_SCAN_HPP__
-#define __OPENCV_CUDEV_BLOCK_SCAN_HPP__
+#ifndef OPENCV_CUDEV_BLOCK_SCAN_HPP
+#define OPENCV_CUDEV_BLOCK_SCAN_HPP
 
 #include "../common.hpp"
 #include "../warp/scan.hpp"
diff --git a/modules/cudev/include/opencv2/cudev/block/vec_distance.hpp b/modules/cudev/include/opencv2/cudev/block/vec_distance.hpp
index 767d32a..3dc3875 100644
--- a/modules/cudev/include/opencv2/cudev/block/vec_distance.hpp
+++ b/modules/cudev/include/opencv2/cudev/block/vec_distance.hpp
@@ -43,8 +43,8 @@
 
 #pragma once
 
-#ifndef __OPENCV_CUDEV_BLOCK_VEC_DISTANCE_HPP__
-#define __OPENCV_CUDEV_BLOCK_VEC_DISTANCE_HPP__
+#ifndef OPENCV_CUDEV_BLOCK_VEC_DISTANCE_HPP
+#define OPENCV_CUDEV_BLOCK_VEC_DISTANCE_HPP
 
 #include "../common.hpp"
 #include "../functional/functional.hpp"
diff --git a/modules/cudev/include/opencv2/cudev/common.hpp b/modules/cudev/include/opencv2/cudev/common.hpp
index f475e20..b4439f5 100644
--- a/modules/cudev/include/opencv2/cudev/common.hpp
+++ b/modules/cudev/include/opencv2/cudev/common.hpp
@@ -43,8 +43,8 @@
 
 #pragma once
 
-#ifndef __OPENCV_CUDEV_COMMON_HPP__
-#define __OPENCV_CUDEV_COMMON_HPP__
+#ifndef OPENCV_CUDEV_COMMON_HPP
+#define OPENCV_CUDEV_COMMON_HPP
 
 #include <cuda_runtime.h>
 #include "opencv2/core/cuda.hpp"
diff --git a/modules/cudev/include/opencv2/cudev/expr/binary_func.hpp b/modules/cudev/include/opencv2/cudev/expr/binary_func.hpp
index 2777a1e..3e5c009 100644
--- a/modules/cudev/include/opencv2/cudev/expr/binary_func.hpp
+++ b/modules/cudev/include/opencv2/cudev/expr/binary_func.hpp
@@ -43,8 +43,8 @@
 
 #pragma once
 
-#ifndef __OPENCV_CUDEV_EXPR_BINARY_FUNC_HPP__
-#define __OPENCV_CUDEV_EXPR_BINARY_FUNC_HPP__
+#ifndef OPENCV_CUDEV_EXPR_BINARY_FUNC_HPP
+#define OPENCV_CUDEV_EXPR_BINARY_FUNC_HPP
 
 #include "../common.hpp"
 #include "../util/type_traits.hpp"
diff --git a/modules/cudev/include/opencv2/cudev/expr/binary_op.hpp b/modules/cudev/include/opencv2/cudev/expr/binary_op.hpp
index 7533946..e3c9ebb 100644
--- a/modules/cudev/include/opencv2/cudev/expr/binary_op.hpp
+++ b/modules/cudev/include/opencv2/cudev/expr/binary_op.hpp
@@ -43,8 +43,8 @@
 
 #pragma once
 
-#ifndef __OPENCV_CUDEV_EXPR_BINARY_OP_HPP__
-#define __OPENCV_CUDEV_EXPR_BINARY_OP_HPP__
+#ifndef OPENCV_CUDEV_EXPR_BINARY_OP_HPP
+#define OPENCV_CUDEV_EXPR_BINARY_OP_HPP
 
 #include "../common.hpp"
 #include "../util/type_traits.hpp"
diff --git a/modules/cudev/include/opencv2/cudev/expr/color.hpp b/modules/cudev/include/opencv2/cudev/expr/color.hpp
index f53de78..ca487a2 100644
--- a/modules/cudev/include/opencv2/cudev/expr/color.hpp
+++ b/modules/cudev/include/opencv2/cudev/expr/color.hpp
@@ -43,8 +43,8 @@
 
 #pragma once
 
-#ifndef __OPENCV_CUDEV_EXPR_COLOR_HPP__
-#define __OPENCV_CUDEV_EXPR_COLOR_HPP__
+#ifndef OPENCV_CUDEV_EXPR_COLOR_HPP
+#define OPENCV_CUDEV_EXPR_COLOR_HPP
 
 #include "../common.hpp"
 #include "../ptr2d/traits.hpp"
diff --git a/modules/cudev/include/opencv2/cudev/expr/deriv.hpp b/modules/cudev/include/opencv2/cudev/expr/deriv.hpp
index da51cc7..d1b0615 100644
--- a/modules/cudev/include/opencv2/cudev/expr/deriv.hpp
+++ b/modules/cudev/include/opencv2/cudev/expr/deriv.hpp
@@ -43,8 +43,8 @@
 
 #pragma once
 
-#ifndef __OPENCV_CUDEV_EXPR_DERIV_HPP__
-#define __OPENCV_CUDEV_EXPR_DERIV_HPP__
+#ifndef OPENCV_CUDEV_EXPR_DERIV_HPP
+#define OPENCV_CUDEV_EXPR_DERIV_HPP
 
 #include "../common.hpp"
 #include "../ptr2d/traits.hpp"
diff --git a/modules/cudev/include/opencv2/cudev/expr/expr.hpp b/modules/cudev/include/opencv2/cudev/expr/expr.hpp
index cdc8612..5f4a491 100644
--- a/modules/cudev/include/opencv2/cudev/expr/expr.hpp
+++ b/modules/cudev/include/opencv2/cudev/expr/expr.hpp
@@ -43,8 +43,8 @@
 
 #pragma once
 
-#ifndef __OPENCV_CUDEV_EXPR_EXPR_HPP__
-#define __OPENCV_CUDEV_EXPR_EXPR_HPP__
+#ifndef OPENCV_CUDEV_EXPR_EXPR_HPP
+#define OPENCV_CUDEV_EXPR_EXPR_HPP
 
 #include "../common.hpp"
 #include "../ptr2d/traits.hpp"
diff --git a/modules/cudev/include/opencv2/cudev/expr/per_element_func.hpp b/modules/cudev/include/opencv2/cudev/expr/per_element_func.hpp
index d7ecd3b..9eac333 100644
--- a/modules/cudev/include/opencv2/cudev/expr/per_element_func.hpp
+++ b/modules/cudev/include/opencv2/cudev/expr/per_element_func.hpp
@@ -43,8 +43,8 @@
 
 #pragma once
 
-#ifndef __OPENCV_CUDEV_EXPR_PER_ELEMENT_FUNC_HPP__
-#define __OPENCV_CUDEV_EXPR_PER_ELEMENT_FUNC_HPP__
+#ifndef OPENCV_CUDEV_EXPR_PER_ELEMENT_FUNC_HPP
+#define OPENCV_CUDEV_EXPR_PER_ELEMENT_FUNC_HPP
 
 #include "../common.hpp"
 #include "../util/type_traits.hpp"
diff --git a/modules/cudev/include/opencv2/cudev/expr/reduction.hpp b/modules/cudev/include/opencv2/cudev/expr/reduction.hpp
index 598fb4f..aa772d0 100644
--- a/modules/cudev/include/opencv2/cudev/expr/reduction.hpp
+++ b/modules/cudev/include/opencv2/cudev/expr/reduction.hpp
@@ -43,8 +43,8 @@
 
 #pragma once
 
-#ifndef __OPENCV_CUDEV_EXPR_REDUCTION_HPP__
-#define __OPENCV_CUDEV_EXPR_REDUCTION_HPP__
+#ifndef OPENCV_CUDEV_EXPR_REDUCTION_HPP
+#define OPENCV_CUDEV_EXPR_REDUCTION_HPP
 
 #include "../common.hpp"
 #include "../grid/reduce.hpp"
diff --git a/modules/cudev/include/opencv2/cudev/expr/unary_func.hpp b/modules/cudev/include/opencv2/cudev/expr/unary_func.hpp
index b19cec8..567e15c 100644
--- a/modules/cudev/include/opencv2/cudev/expr/unary_func.hpp
+++ b/modules/cudev/include/opencv2/cudev/expr/unary_func.hpp
@@ -43,8 +43,8 @@
 
 #pragma once
 
-#ifndef __OPENCV_CUDEV_EXPR_UNARY_FUNC_HPP__
-#define __OPENCV_CUDEV_EXPR_UNARY_FUNC_HPP__
+#ifndef OPENCV_CUDEV_EXPR_UNARY_FUNC_HPP
+#define OPENCV_CUDEV_EXPR_UNARY_FUNC_HPP
 
 #include "../common.hpp"
 #include "../ptr2d/traits.hpp"
diff --git a/modules/cudev/include/opencv2/cudev/expr/unary_op.hpp b/modules/cudev/include/opencv2/cudev/expr/unary_op.hpp
index c5fabe4..4e067fe 100644
--- a/modules/cudev/include/opencv2/cudev/expr/unary_op.hpp
+++ b/modules/cudev/include/opencv2/cudev/expr/unary_op.hpp
@@ -43,8 +43,8 @@
 
 #pragma once
 
-#ifndef __OPENCV_CUDEV_EXPR_UNARY_OP_HPP__
-#define __OPENCV_CUDEV_EXPR_UNARY_OP_HPP__
+#ifndef OPENCV_CUDEV_EXPR_UNARY_OP_HPP
+#define OPENCV_CUDEV_EXPR_UNARY_OP_HPP
 
 #include "../common.hpp"
 #include "../ptr2d/traits.hpp"
diff --git a/modules/cudev/include/opencv2/cudev/expr/warping.hpp b/modules/cudev/include/opencv2/cudev/expr/warping.hpp
index e1f78b9..ca04b4d 100644
--- a/modules/cudev/include/opencv2/cudev/expr/warping.hpp
+++ b/modules/cudev/include/opencv2/cudev/expr/warping.hpp
@@ -43,8 +43,8 @@
 
 #pragma once
 
-#ifndef __OPENCV_CUDEV_EXPR_WARPING_HPP__
-#define __OPENCV_CUDEV_EXPR_WARPING_HPP__
+#ifndef OPENCV_CUDEV_EXPR_WARPING_HPP
+#define OPENCV_CUDEV_EXPR_WARPING_HPP
 
 #include "../common.hpp"
 #include "../ptr2d/traits.hpp"
diff --git a/modules/cudev/include/opencv2/cudev/functional/color_cvt.hpp b/modules/cudev/include/opencv2/cudev/functional/color_cvt.hpp
index 5134d04..2681030 100644
--- a/modules/cudev/include/opencv2/cudev/functional/color_cvt.hpp
+++ b/modules/cudev/include/opencv2/cudev/functional/color_cvt.hpp
@@ -43,8 +43,8 @@
 
 #pragma once
 
-#ifndef __OPENCV_CUDEV_FUNCTIONAL_COLOR_CVT_HPP__
-#define __OPENCV_CUDEV_FUNCTIONAL_COLOR_CVT_HPP__
+#ifndef OPENCV_CUDEV_FUNCTIONAL_COLOR_CVT_HPP
+#define OPENCV_CUDEV_FUNCTIONAL_COLOR_CVT_HPP
 
 #include "../common.hpp"
 #include "detail/color_cvt.hpp"
diff --git a/modules/cudev/include/opencv2/cudev/functional/detail/color_cvt.hpp b/modules/cudev/include/opencv2/cudev/functional/detail/color_cvt.hpp
index 49d1d2c..5947214 100644
--- a/modules/cudev/include/opencv2/cudev/functional/detail/color_cvt.hpp
+++ b/modules/cudev/include/opencv2/cudev/functional/detail/color_cvt.hpp
@@ -43,8 +43,8 @@
 
 #pragma once
 
-#ifndef __OPENCV_CUDEV_FUNCTIONAL_COLOR_CVT_DETAIL_HPP__
-#define __OPENCV_CUDEV_FUNCTIONAL_COLOR_CVT_DETAIL_HPP__
+#ifndef OPENCV_CUDEV_FUNCTIONAL_COLOR_CVT_DETAIL_HPP
+#define OPENCV_CUDEV_FUNCTIONAL_COLOR_CVT_DETAIL_HPP
 
 #include "../../common.hpp"
 #include "../../util/vec_traits.hpp"
diff --git a/modules/cudev/include/opencv2/cudev/functional/functional.hpp b/modules/cudev/include/opencv2/cudev/functional/functional.hpp
index 125b66f..f6569cf 100644
--- a/modules/cudev/include/opencv2/cudev/functional/functional.hpp
+++ b/modules/cudev/include/opencv2/cudev/functional/functional.hpp
@@ -43,8 +43,8 @@
 
 #pragma once
 
-#ifndef __OPENCV_CUDEV_FUNCTIONAL_FUNCTIONAL_HPP__
-#define __OPENCV_CUDEV_FUNCTIONAL_FUNCTIONAL_HPP__
+#ifndef OPENCV_CUDEV_FUNCTIONAL_FUNCTIONAL_HPP
+#define OPENCV_CUDEV_FUNCTIONAL_FUNCTIONAL_HPP
 
 #include "../common.hpp"
 #include "../util/saturate_cast.hpp"
@@ -668,6 +668,27 @@ template <typename T, typename D> struct saturate_cast_func : unary_function<T,
     }
 };
 
+// Convert Fp16 dummy
+template <typename T, typename D> struct saturate_cast_fp16_func;
+
+// Convert Fp16 from Fp32
+template <> struct saturate_cast_fp16_func<float, short> : unary_function<float, short>
+{
+    __device__ __forceinline__ short operator ()(float v) const
+    {
+        return cast_fp16<float, short>(v);
+    }
+};
+
+// Convert Fp16 to Fp32
+template <> struct saturate_cast_fp16_func<short, float> : unary_function<short, float>
+{
+    __device__ __forceinline__ float operator ()(short v) const
+    {
+        return cast_fp16<short, float>(v);
+    }
+};
+
 // Threshold Functors
 
 template <typename T> struct ThreshBinaryFunc : unary_function<T, T>
diff --git a/modules/cudev/include/opencv2/cudev/functional/tuple_adapter.hpp b/modules/cudev/include/opencv2/cudev/functional/tuple_adapter.hpp
index ff075dc..1533181 100644
--- a/modules/cudev/include/opencv2/cudev/functional/tuple_adapter.hpp
+++ b/modules/cudev/include/opencv2/cudev/functional/tuple_adapter.hpp
@@ -43,8 +43,8 @@
 
 #pragma once
 
-#ifndef __OPENCV_CUDEV_FUNCTIONAL_TUPLE_ADAPTER_HPP__
-#define __OPENCV_CUDEV_FUNCTIONAL_TUPLE_ADAPTER_HPP__
+#ifndef OPENCV_CUDEV_FUNCTIONAL_TUPLE_ADAPTER_HPP
+#define OPENCV_CUDEV_FUNCTIONAL_TUPLE_ADAPTER_HPP
 
 #include "../common.hpp"
 #include "../util/tuple.hpp"
diff --git a/modules/cudev/include/opencv2/cudev/grid/copy.hpp b/modules/cudev/include/opencv2/cudev/grid/copy.hpp
index 1d30f99..cbaca84 100644
--- a/modules/cudev/include/opencv2/cudev/grid/copy.hpp
+++ b/modules/cudev/include/opencv2/cudev/grid/copy.hpp
@@ -43,8 +43,8 @@
 
 #pragma once
 
-#ifndef __OPENCV_CUDEV_GRID_COPY_HPP__
-#define __OPENCV_CUDEV_GRID_COPY_HPP__
+#ifndef OPENCV_CUDEV_GRID_COPY_HPP
+#define OPENCV_CUDEV_GRID_COPY_HPP
 
 #include "../common.hpp"
 #include "../util/tuple.hpp"
diff --git a/modules/cudev/include/opencv2/cudev/grid/detail/copy.hpp b/modules/cudev/include/opencv2/cudev/grid/detail/copy.hpp
index 707b842..b6fce94 100644
--- a/modules/cudev/include/opencv2/cudev/grid/detail/copy.hpp
+++ b/modules/cudev/include/opencv2/cudev/grid/detail/copy.hpp
@@ -43,8 +43,8 @@
 
 #pragma once
 
-#ifndef __OPENCV_CUDEV_GRID_COPY_DETAIL_HPP__
-#define __OPENCV_CUDEV_GRID_COPY_DETAIL_HPP__
+#ifndef OPENCV_CUDEV_GRID_COPY_DETAIL_HPP
+#define OPENCV_CUDEV_GRID_COPY_DETAIL_HPP
 
 #include "../../common.hpp"
 #include "../../util/tuple.hpp"
diff --git a/modules/cudev/include/opencv2/cudev/grid/detail/histogram.hpp b/modules/cudev/include/opencv2/cudev/grid/detail/histogram.hpp
index a27955d..8b6164e 100644
--- a/modules/cudev/include/opencv2/cudev/grid/detail/histogram.hpp
+++ b/modules/cudev/include/opencv2/cudev/grid/detail/histogram.hpp
@@ -43,8 +43,8 @@
 
 #pragma once
 
-#ifndef __OPENCV_CUDEV_GRID_HISTOGRAM_DETAIL_HPP__
-#define __OPENCV_CUDEV_GRID_HISTOGRAM_DETAIL_HPP__
+#ifndef OPENCV_CUDEV_GRID_HISTOGRAM_DETAIL_HPP
+#define OPENCV_CUDEV_GRID_HISTOGRAM_DETAIL_HPP
 
 #include "../../common.hpp"
 #include "../../util/atomic.hpp"
diff --git a/modules/cudev/include/opencv2/cudev/grid/detail/integral.hpp b/modules/cudev/include/opencv2/cudev/grid/detail/integral.hpp
index 7af5265..0475ebd 100644
--- a/modules/cudev/include/opencv2/cudev/grid/detail/integral.hpp
+++ b/modules/cudev/include/opencv2/cudev/grid/detail/integral.hpp
@@ -43,8 +43,8 @@
 
 #pragma once
 
-#ifndef __OPENCV_CUDEV_GRID_INTEGRAL_DETAIL_HPP__
-#define __OPENCV_CUDEV_GRID_INTEGRAL_DETAIL_HPP__
+#ifndef OPENCV_CUDEV_GRID_INTEGRAL_DETAIL_HPP
+#define OPENCV_CUDEV_GRID_INTEGRAL_DETAIL_HPP
 
 #include "../../common.hpp"
 #include "../../warp/shuffle.hpp"
diff --git a/modules/cudev/include/opencv2/cudev/grid/detail/minmaxloc.hpp b/modules/cudev/include/opencv2/cudev/grid/detail/minmaxloc.hpp
index eb34d7f..9e4f348 100644
--- a/modules/cudev/include/opencv2/cudev/grid/detail/minmaxloc.hpp
+++ b/modules/cudev/include/opencv2/cudev/grid/detail/minmaxloc.hpp
@@ -43,8 +43,8 @@
 
 #pragma once
 
-#ifndef __OPENCV_CUDEV_GRID_MINMAXLOC_DETAIL_HPP__
-#define __OPENCV_CUDEV_GRID_MINMAXLOC_DETAIL_HPP__
+#ifndef OPENCV_CUDEV_GRID_MINMAXLOC_DETAIL_HPP
+#define OPENCV_CUDEV_GRID_MINMAXLOC_DETAIL_HPP
 
 #include "../../common.hpp"
 #include "../../util/vec_traits.hpp"
diff --git a/modules/cudev/include/opencv2/cudev/grid/detail/pyr_down.hpp b/modules/cudev/include/opencv2/cudev/grid/detail/pyr_down.hpp
index b14792c..51cdf1b 100644
--- a/modules/cudev/include/opencv2/cudev/grid/detail/pyr_down.hpp
+++ b/modules/cudev/include/opencv2/cudev/grid/detail/pyr_down.hpp
@@ -43,8 +43,8 @@
 
 #pragma once
 
-#ifndef __OPENCV_CUDEV_GRID_PYR_DOWN_DETAIL_HPP__
-#define __OPENCV_CUDEV_GRID_PYR_DOWN_DETAIL_HPP__
+#ifndef OPENCV_CUDEV_GRID_PYR_DOWN_DETAIL_HPP
+#define OPENCV_CUDEV_GRID_PYR_DOWN_DETAIL_HPP
 
 #include "../../common.hpp"
 #include "../../util/vec_traits.hpp"
diff --git a/modules/cudev/include/opencv2/cudev/grid/detail/pyr_up.hpp b/modules/cudev/include/opencv2/cudev/grid/detail/pyr_up.hpp
index 16c8b20..b5543ae 100644
--- a/modules/cudev/include/opencv2/cudev/grid/detail/pyr_up.hpp
+++ b/modules/cudev/include/opencv2/cudev/grid/detail/pyr_up.hpp
@@ -43,8 +43,8 @@
 
 #pragma once
 
-#ifndef __OPENCV_CUDEV_GRID_PYR_UP_DETAIL_HPP__
-#define __OPENCV_CUDEV_GRID_PYR_UP_DETAIL_HPP__
+#ifndef OPENCV_CUDEV_GRID_PYR_UP_DETAIL_HPP
+#define OPENCV_CUDEV_GRID_PYR_UP_DETAIL_HPP
 
 #include "../../common.hpp"
 #include "../../util/vec_traits.hpp"
diff --git a/modules/cudev/include/opencv2/cudev/grid/detail/reduce.hpp b/modules/cudev/include/opencv2/cudev/grid/detail/reduce.hpp
index 7ccdd05..2c8dfb3 100644
--- a/modules/cudev/include/opencv2/cudev/grid/detail/reduce.hpp
+++ b/modules/cudev/include/opencv2/cudev/grid/detail/reduce.hpp
@@ -43,8 +43,8 @@
 
 #pragma once
 
-#ifndef __OPENCV_CUDEV_GRID_REDUCE_DETAIL_HPP__
-#define __OPENCV_CUDEV_GRID_REDUCE_DETAIL_HPP__
+#ifndef OPENCV_CUDEV_GRID_REDUCE_DETAIL_HPP
+#define OPENCV_CUDEV_GRID_REDUCE_DETAIL_HPP
 
 #include "../../common.hpp"
 #include "../../util/tuple.hpp"
diff --git a/modules/cudev/include/opencv2/cudev/grid/detail/reduce_to_column.hpp b/modules/cudev/include/opencv2/cudev/grid/detail/reduce_to_column.hpp
index c485294..e1c8a3b 100644
--- a/modules/cudev/include/opencv2/cudev/grid/detail/reduce_to_column.hpp
+++ b/modules/cudev/include/opencv2/cudev/grid/detail/reduce_to_column.hpp
@@ -43,8 +43,8 @@
 
 #pragma once
 
-#ifndef __OPENCV_CUDEV_GRID_REDUCE_TO_COLUMN_DETAIL_HPP__
-#define __OPENCV_CUDEV_GRID_REDUCE_TO_COLUMN_DETAIL_HPP__
+#ifndef OPENCV_CUDEV_GRID_REDUCE_TO_COLUMN_DETAIL_HPP
+#define OPENCV_CUDEV_GRID_REDUCE_TO_COLUMN_DETAIL_HPP
 
 #include "../../common.hpp"
 #include "../../util/saturate_cast.hpp"
diff --git a/modules/cudev/include/opencv2/cudev/grid/detail/reduce_to_row.hpp b/modules/cudev/include/opencv2/cudev/grid/detail/reduce_to_row.hpp
index 154004f..8d3c7e4 100644
--- a/modules/cudev/include/opencv2/cudev/grid/detail/reduce_to_row.hpp
+++ b/modules/cudev/include/opencv2/cudev/grid/detail/reduce_to_row.hpp
@@ -43,8 +43,8 @@
 
 #pragma once
 
-#ifndef __OPENCV_CUDEV_GRID_REDUCE_TO_ROW_DETAIL_HPP__
-#define __OPENCV_CUDEV_GRID_REDUCE_TO_ROW_DETAIL_HPP__
+#ifndef OPENCV_CUDEV_GRID_REDUCE_TO_ROW_DETAIL_HPP
+#define OPENCV_CUDEV_GRID_REDUCE_TO_ROW_DETAIL_HPP
 
 #include "../../common.hpp"
 #include "../../util/saturate_cast.hpp"
diff --git a/modules/cudev/include/opencv2/cudev/grid/detail/split_merge.hpp b/modules/cudev/include/opencv2/cudev/grid/detail/split_merge.hpp
index 0bd76ac..3f51206 100644
--- a/modules/cudev/include/opencv2/cudev/grid/detail/split_merge.hpp
+++ b/modules/cudev/include/opencv2/cudev/grid/detail/split_merge.hpp
@@ -43,8 +43,8 @@
 
 #pragma once
 
-#ifndef __OPENCV_CUDEV_GRID_SPLIT_MERGE_DETAIL_HPP__
-#define __OPENCV_CUDEV_GRID_SPLIT_MERGE_DETAIL_HPP__
+#ifndef OPENCV_CUDEV_GRID_SPLIT_MERGE_DETAIL_HPP
+#define OPENCV_CUDEV_GRID_SPLIT_MERGE_DETAIL_HPP
 
 #include "../../common.hpp"
 #include "../../util/saturate_cast.hpp"
diff --git a/modules/cudev/include/opencv2/cudev/grid/detail/transform.hpp b/modules/cudev/include/opencv2/cudev/grid/detail/transform.hpp
index d135853..dd39fe9 100644
--- a/modules/cudev/include/opencv2/cudev/grid/detail/transform.hpp
+++ b/modules/cudev/include/opencv2/cudev/grid/detail/transform.hpp
@@ -43,8 +43,8 @@
 
 #pragma once
 
-#ifndef __OPENCV_CUDEV_GRID_TRANSFORM_DETAIL_HPP__
-#define __OPENCV_CUDEV_GRID_TRANSFORM_DETAIL_HPP__
+#ifndef OPENCV_CUDEV_GRID_TRANSFORM_DETAIL_HPP
+#define OPENCV_CUDEV_GRID_TRANSFORM_DETAIL_HPP
 
 #include "../../common.hpp"
 #include "../../util/tuple.hpp"
diff --git a/modules/cudev/include/opencv2/cudev/grid/detail/transpose.hpp b/modules/cudev/include/opencv2/cudev/grid/detail/transpose.hpp
index 83ee96b..1236d4b 100644
--- a/modules/cudev/include/opencv2/cudev/grid/detail/transpose.hpp
+++ b/modules/cudev/include/opencv2/cudev/grid/detail/transpose.hpp
@@ -43,8 +43,8 @@
 
 #pragma once
 
-#ifndef __OPENCV_CUDEV_GRID_TRANSPOSE_DETAIL_HPP__
-#define __OPENCV_CUDEV_GRID_TRANSPOSE_DETAIL_HPP__
+#ifndef OPENCV_CUDEV_GRID_TRANSPOSE_DETAIL_HPP
+#define OPENCV_CUDEV_GRID_TRANSPOSE_DETAIL_HPP
 
 #include "../../common.hpp"
 #include "../../util/saturate_cast.hpp"
diff --git a/modules/cudev/include/opencv2/cudev/grid/histogram.hpp b/modules/cudev/include/opencv2/cudev/grid/histogram.hpp
index 154f737..1ceee9f 100644
--- a/modules/cudev/include/opencv2/cudev/grid/histogram.hpp
+++ b/modules/cudev/include/opencv2/cudev/grid/histogram.hpp
@@ -43,8 +43,8 @@
 
 #pragma once
 
-#ifndef __OPENCV_CUDEV_GRID_HISTOGRAM_HPP__
-#define __OPENCV_CUDEV_GRID_HISTOGRAM_HPP__
+#ifndef OPENCV_CUDEV_GRID_HISTOGRAM_HPP
+#define OPENCV_CUDEV_GRID_HISTOGRAM_HPP
 
 #include "../common.hpp"
 #include "../ptr2d/traits.hpp"
diff --git a/modules/cudev/include/opencv2/cudev/grid/integral.hpp b/modules/cudev/include/opencv2/cudev/grid/integral.hpp
index 6312f44..3e680b1 100644
--- a/modules/cudev/include/opencv2/cudev/grid/integral.hpp
+++ b/modules/cudev/include/opencv2/cudev/grid/integral.hpp
@@ -43,8 +43,8 @@
 
 #pragma once
 
-#ifndef __OPENCV_CUDEV_GRID_INTEGRAL_HPP__
-#define __OPENCV_CUDEV_GRID_INTEGRAL_HPP__
+#ifndef OPENCV_CUDEV_GRID_INTEGRAL_HPP
+#define OPENCV_CUDEV_GRID_INTEGRAL_HPP
 
 #include "../common.hpp"
 #include "../ptr2d/traits.hpp"
diff --git a/modules/cudev/include/opencv2/cudev/grid/pyramids.hpp b/modules/cudev/include/opencv2/cudev/grid/pyramids.hpp
index 22eafe6..6482657 100644
--- a/modules/cudev/include/opencv2/cudev/grid/pyramids.hpp
+++ b/modules/cudev/include/opencv2/cudev/grid/pyramids.hpp
@@ -43,8 +43,8 @@
 
 #pragma once
 
-#ifndef __OPENCV_CUDEV_GRID_PYRAMIDS_HPP__
-#define __OPENCV_CUDEV_GRID_PYRAMIDS_HPP__
+#ifndef OPENCV_CUDEV_GRID_PYRAMIDS_HPP
+#define OPENCV_CUDEV_GRID_PYRAMIDS_HPP
 
 #include "../common.hpp"
 #include "../ptr2d/traits.hpp"
diff --git a/modules/cudev/include/opencv2/cudev/grid/reduce.hpp b/modules/cudev/include/opencv2/cudev/grid/reduce.hpp
index 4551bc8..e9e42b2 100644
--- a/modules/cudev/include/opencv2/cudev/grid/reduce.hpp
+++ b/modules/cudev/include/opencv2/cudev/grid/reduce.hpp
@@ -43,8 +43,8 @@
 
 #pragma once
 
-#ifndef __OPENCV_CUDEV_GRID_REDUCE_HPP__
-#define __OPENCV_CUDEV_GRID_REDUCE_HPP__
+#ifndef OPENCV_CUDEV_GRID_REDUCE_HPP
+#define OPENCV_CUDEV_GRID_REDUCE_HPP
 
 #include <limits>
 #include "../common.hpp"
diff --git a/modules/cudev/include/opencv2/cudev/grid/reduce_to_vec.hpp b/modules/cudev/include/opencv2/cudev/grid/reduce_to_vec.hpp
index 595ee8b..5955cee 100644
--- a/modules/cudev/include/opencv2/cudev/grid/reduce_to_vec.hpp
+++ b/modules/cudev/include/opencv2/cudev/grid/reduce_to_vec.hpp
@@ -43,8 +43,8 @@
 
 #pragma once
 
-#ifndef __OPENCV_CUDEV_GRID_REDUCE_TO_VEC_HPP__
-#define __OPENCV_CUDEV_GRID_REDUCE_TO_VEC_HPP__
+#ifndef OPENCV_CUDEV_GRID_REDUCE_TO_VEC_HPP
+#define OPENCV_CUDEV_GRID_REDUCE_TO_VEC_HPP
 
 #include "../common.hpp"
 #include "../util/vec_traits.hpp"
@@ -182,7 +182,7 @@ __host__ void gridReduceToColumn_(const SrcPtr& src, GpuMat_<ResType>& dst, cons
 
     CV_Assert( getRows(mask) == rows && getCols(mask) == cols );
 
-    dst.create(1, rows);
+    cuda::createContinuous(rows, 1, dst.type(), dst);
 
     grid_reduce_to_vec_detail::reduceToColumn<Reductor, Policy>(shrinkPtr(src),
                                                                 dst[0],
@@ -197,7 +197,7 @@ __host__ void gridReduceToColumn_(const SrcPtr& src, GpuMat_<ResType>& dst, Stre
     const int rows = getRows(src);
     const int cols = getCols(src);
 
-    dst.create(1, rows);
+    cuda::createContinuous(rows, 1, dst.type(), dst);
 
     grid_reduce_to_vec_detail::reduceToColumn<Reductor, Policy>(shrinkPtr(src),
                                                                 dst[0],
diff --git a/modules/cudev/include/opencv2/cudev/grid/split_merge.hpp b/modules/cudev/include/opencv2/cudev/grid/split_merge.hpp
index 1a71347..5c92a81 100644
--- a/modules/cudev/include/opencv2/cudev/grid/split_merge.hpp
+++ b/modules/cudev/include/opencv2/cudev/grid/split_merge.hpp
@@ -43,8 +43,8 @@
 
 #pragma once
 
-#ifndef __OPENCV_CUDEV_GRID_SPLIT_MERGE_HPP__
-#define __OPENCV_CUDEV_GRID_SPLIT_MERGE_HPP__
+#ifndef OPENCV_CUDEV_GRID_SPLIT_MERGE_HPP
+#define OPENCV_CUDEV_GRID_SPLIT_MERGE_HPP
 
 #include "../common.hpp"
 #include "../util/tuple.hpp"
diff --git a/modules/cudev/include/opencv2/cudev/grid/transform.hpp b/modules/cudev/include/opencv2/cudev/grid/transform.hpp
index 2f16f7d..4f7d191 100644
--- a/modules/cudev/include/opencv2/cudev/grid/transform.hpp
+++ b/modules/cudev/include/opencv2/cudev/grid/transform.hpp
@@ -43,8 +43,8 @@
 
 #pragma once
 
-#ifndef __OPENCV_CUDEV_GRID_TRANSFORM_HPP__
-#define __OPENCV_CUDEV_GRID_TRANSFORM_HPP__
+#ifndef OPENCV_CUDEV_GRID_TRANSFORM_HPP
+#define OPENCV_CUDEV_GRID_TRANSFORM_HPP
 
 #include "../common.hpp"
 #include "../util/tuple.hpp"
diff --git a/modules/cudev/include/opencv2/cudev/grid/transpose.hpp b/modules/cudev/include/opencv2/cudev/grid/transpose.hpp
index 0d7a195..72ab726 100644
--- a/modules/cudev/include/opencv2/cudev/grid/transpose.hpp
+++ b/modules/cudev/include/opencv2/cudev/grid/transpose.hpp
@@ -43,8 +43,8 @@
 
 #pragma once
 
-#ifndef __OPENCV_CUDEV_GRID_TRANSPOSE_HPP__
-#define __OPENCV_CUDEV_GRID_TRANSPOSE_HPP__
+#ifndef OPENCV_CUDEV_GRID_TRANSPOSE_HPP
+#define OPENCV_CUDEV_GRID_TRANSPOSE_HPP
 
 #include "../common.hpp"
 #include "../ptr2d/traits.hpp"
diff --git a/modules/cudev/include/opencv2/cudev/ptr2d/constant.hpp b/modules/cudev/include/opencv2/cudev/ptr2d/constant.hpp
index b3c5f5f..eb96290 100644
--- a/modules/cudev/include/opencv2/cudev/ptr2d/constant.hpp
+++ b/modules/cudev/include/opencv2/cudev/ptr2d/constant.hpp
@@ -43,8 +43,8 @@
 
 #pragma once
 
-#ifndef __OPENCV_CUDEV_PTR2D_CONSTANT_HPP__
-#define __OPENCV_CUDEV_PTR2D_CONSTANT_HPP__
+#ifndef OPENCV_CUDEV_PTR2D_CONSTANT_HPP
+#define OPENCV_CUDEV_PTR2D_CONSTANT_HPP
 
 #include "../common.hpp"
 #include "traits.hpp"
diff --git a/modules/cudev/include/opencv2/cudev/ptr2d/deriv.hpp b/modules/cudev/include/opencv2/cudev/ptr2d/deriv.hpp
index 9508817..fe30d3e 100644
--- a/modules/cudev/include/opencv2/cudev/ptr2d/deriv.hpp
+++ b/modules/cudev/include/opencv2/cudev/ptr2d/deriv.hpp
@@ -43,8 +43,8 @@
 
 #pragma once
 
-#ifndef __OPENCV_CUDEV_PTR2D_DERIV_HPP__
-#define __OPENCV_CUDEV_PTR2D_DERIV_HPP__
+#ifndef OPENCV_CUDEV_PTR2D_DERIV_HPP
+#define OPENCV_CUDEV_PTR2D_DERIV_HPP
 
 #include "../common.hpp"
 #include "../grid/copy.hpp"
diff --git a/modules/cudev/include/opencv2/cudev/ptr2d/detail/gpumat.hpp b/modules/cudev/include/opencv2/cudev/ptr2d/detail/gpumat.hpp
index 665840e..968d78e 100644
--- a/modules/cudev/include/opencv2/cudev/ptr2d/detail/gpumat.hpp
+++ b/modules/cudev/include/opencv2/cudev/ptr2d/detail/gpumat.hpp
@@ -43,8 +43,8 @@
 
 #pragma once
 
-#ifndef __OPENCV_CUDEV_PTR2D_GPUMAT_DETAIL_HPP__
-#define __OPENCV_CUDEV_PTR2D_GPUMAT_DETAIL_HPP__
+#ifndef OPENCV_CUDEV_PTR2D_GPUMAT_DETAIL_HPP
+#define OPENCV_CUDEV_PTR2D_GPUMAT_DETAIL_HPP
 
 #include "../gpumat.hpp"
 
diff --git a/modules/cudev/include/opencv2/cudev/ptr2d/extrapolation.hpp b/modules/cudev/include/opencv2/cudev/ptr2d/extrapolation.hpp
index e06058f..14bb305 100644
--- a/modules/cudev/include/opencv2/cudev/ptr2d/extrapolation.hpp
+++ b/modules/cudev/include/opencv2/cudev/ptr2d/extrapolation.hpp
@@ -43,8 +43,8 @@
 
 #pragma once
 
-#ifndef __OPENCV_CUDEV_PTR2D_EXTRAPOLATION_HPP__
-#define __OPENCV_CUDEV_PTR2D_EXTRAPOLATION_HPP__
+#ifndef OPENCV_CUDEV_PTR2D_EXTRAPOLATION_HPP
+#define OPENCV_CUDEV_PTR2D_EXTRAPOLATION_HPP
 
 #include "../common.hpp"
 #include "../util/vec_traits.hpp"
diff --git a/modules/cudev/include/opencv2/cudev/ptr2d/glob.hpp b/modules/cudev/include/opencv2/cudev/ptr2d/glob.hpp
index 4296dd4..2024a7e 100644
--- a/modules/cudev/include/opencv2/cudev/ptr2d/glob.hpp
+++ b/modules/cudev/include/opencv2/cudev/ptr2d/glob.hpp
@@ -43,8 +43,8 @@
 
 #pragma once
 
-#ifndef __OPENCV_CUDEV_PTR2D_GLOB_HPP__
-#define __OPENCV_CUDEV_PTR2D_GLOB_HPP__
+#ifndef OPENCV_CUDEV_PTR2D_GLOB_HPP
+#define OPENCV_CUDEV_PTR2D_GLOB_HPP
 
 #include "../common.hpp"
 #include "traits.hpp"
diff --git a/modules/cudev/include/opencv2/cudev/ptr2d/gpumat.hpp b/modules/cudev/include/opencv2/cudev/ptr2d/gpumat.hpp
index 983652c..eac4fb6 100644
--- a/modules/cudev/include/opencv2/cudev/ptr2d/gpumat.hpp
+++ b/modules/cudev/include/opencv2/cudev/ptr2d/gpumat.hpp
@@ -43,8 +43,8 @@
 
 #pragma once
 
-#ifndef __OPENCV_CUDEV_PTR2D_GPUMAT_HPP__
-#define __OPENCV_CUDEV_PTR2D_GPUMAT_HPP__
+#ifndef OPENCV_CUDEV_PTR2D_GPUMAT_HPP
+#define OPENCV_CUDEV_PTR2D_GPUMAT_HPP
 
 #include "../common.hpp"
 #include "../util/vec_traits.hpp"
diff --git a/modules/cudev/include/opencv2/cudev/ptr2d/interpolation.hpp b/modules/cudev/include/opencv2/cudev/ptr2d/interpolation.hpp
index 256d4fd..c416140 100644
--- a/modules/cudev/include/opencv2/cudev/ptr2d/interpolation.hpp
+++ b/modules/cudev/include/opencv2/cudev/ptr2d/interpolation.hpp
@@ -43,8 +43,8 @@
 
 #pragma once
 
-#ifndef __OPENCV_CUDEV_PTR2D_INTERPOLATION_HPP__
-#define __OPENCV_CUDEV_PTR2D_INTERPOLATION_HPP__
+#ifndef OPENCV_CUDEV_PTR2D_INTERPOLATION_HPP
+#define OPENCV_CUDEV_PTR2D_INTERPOLATION_HPP
 
 #include "../common.hpp"
 #include "../util/vec_traits.hpp"
diff --git a/modules/cudev/include/opencv2/cudev/ptr2d/lut.hpp b/modules/cudev/include/opencv2/cudev/ptr2d/lut.hpp
index 26a3725..221732c 100644
--- a/modules/cudev/include/opencv2/cudev/ptr2d/lut.hpp
+++ b/modules/cudev/include/opencv2/cudev/ptr2d/lut.hpp
@@ -43,8 +43,8 @@
 
 #pragma once
 
-#ifndef __OPENCV_CUDEV_PTR2D_LUT_HPP__
-#define __OPENCV_CUDEV_PTR2D_LUT_HPP__
+#ifndef OPENCV_CUDEV_PTR2D_LUT_HPP
+#define OPENCV_CUDEV_PTR2D_LUT_HPP
 
 #include "../common.hpp"
 #include "../util/vec_traits.hpp"
diff --git a/modules/cudev/include/opencv2/cudev/ptr2d/mask.hpp b/modules/cudev/include/opencv2/cudev/ptr2d/mask.hpp
index bbd2f1a..46f518c 100644
--- a/modules/cudev/include/opencv2/cudev/ptr2d/mask.hpp
+++ b/modules/cudev/include/opencv2/cudev/ptr2d/mask.hpp
@@ -43,8 +43,8 @@
 
 #pragma once
 
-#ifndef __OPENCV_CUDEV_PTR2D_MASK_HPP__
-#define __OPENCV_CUDEV_PTR2D_MASK_HPP__
+#ifndef OPENCV_CUDEV_PTR2D_MASK_HPP
+#define OPENCV_CUDEV_PTR2D_MASK_HPP
 
 #include "../common.hpp"
 #include "traits.hpp"
diff --git a/modules/cudev/include/opencv2/cudev/ptr2d/remap.hpp b/modules/cudev/include/opencv2/cudev/ptr2d/remap.hpp
index 9d8745f..cb21da4 100644
--- a/modules/cudev/include/opencv2/cudev/ptr2d/remap.hpp
+++ b/modules/cudev/include/opencv2/cudev/ptr2d/remap.hpp
@@ -43,8 +43,8 @@
 
 #pragma once
 
-#ifndef __OPENCV_CUDEV_PTR2D_REMAP_HPP__
-#define __OPENCV_CUDEV_PTR2D_REMAP_HPP__
+#ifndef OPENCV_CUDEV_PTR2D_REMAP_HPP
+#define OPENCV_CUDEV_PTR2D_REMAP_HPP
 
 #include "opencv2/core/base.hpp"
 #include "../common.hpp"
diff --git a/modules/cudev/include/opencv2/cudev/ptr2d/resize.hpp b/modules/cudev/include/opencv2/cudev/ptr2d/resize.hpp
index 63ae7eb..d026b70 100644
--- a/modules/cudev/include/opencv2/cudev/ptr2d/resize.hpp
+++ b/modules/cudev/include/opencv2/cudev/ptr2d/resize.hpp
@@ -43,8 +43,8 @@
 
 #pragma once
 
-#ifndef __OPENCV_CUDEV_PTR2D_RESIZE_HPP__
-#define __OPENCV_CUDEV_PTR2D_RESIZE_HPP__
+#ifndef OPENCV_CUDEV_PTR2D_RESIZE_HPP
+#define OPENCV_CUDEV_PTR2D_RESIZE_HPP
 
 #include "opencv2/core/base.hpp"
 #include "../common.hpp"
diff --git a/modules/cudev/include/opencv2/cudev/ptr2d/texture.hpp b/modules/cudev/include/opencv2/cudev/ptr2d/texture.hpp
index 6fa83e6..a209d00 100644
--- a/modules/cudev/include/opencv2/cudev/ptr2d/texture.hpp
+++ b/modules/cudev/include/opencv2/cudev/ptr2d/texture.hpp
@@ -43,8 +43,8 @@
 
 #pragma once
 
-#ifndef __OPENCV_CUDEV_PTR2D_TEXTURE_HPP__
-#define __OPENCV_CUDEV_PTR2D_TEXTURE_HPP__
+#ifndef OPENCV_CUDEV_PTR2D_TEXTURE_HPP
+#define OPENCV_CUDEV_PTR2D_TEXTURE_HPP
 
 #include <cstring>
 #include "../common.hpp"
diff --git a/modules/cudev/include/opencv2/cudev/ptr2d/traits.hpp b/modules/cudev/include/opencv2/cudev/ptr2d/traits.hpp
index f1552ca..f0d1cad 100644
--- a/modules/cudev/include/opencv2/cudev/ptr2d/traits.hpp
+++ b/modules/cudev/include/opencv2/cudev/ptr2d/traits.hpp
@@ -43,8 +43,8 @@
 
 #pragma once
 
-#ifndef __OPENCV_CUDEV_PTR2D_TRAITS_HPP__
-#define __OPENCV_CUDEV_PTR2D_TRAITS_HPP__
+#ifndef OPENCV_CUDEV_PTR2D_TRAITS_HPP
+#define OPENCV_CUDEV_PTR2D_TRAITS_HPP
 
 #include "../common.hpp"
 
diff --git a/modules/cudev/include/opencv2/cudev/ptr2d/transform.hpp b/modules/cudev/include/opencv2/cudev/ptr2d/transform.hpp
index b6edb91..21d5075 100644
--- a/modules/cudev/include/opencv2/cudev/ptr2d/transform.hpp
+++ b/modules/cudev/include/opencv2/cudev/ptr2d/transform.hpp
@@ -43,8 +43,8 @@
 
 #pragma once
 
-#ifndef __OPENCV_CUDEV_PTR2D_TRANSFORM_HPP__
-#define __OPENCV_CUDEV_PTR2D_TRANSFORM_HPP__
+#ifndef OPENCV_CUDEV_PTR2D_TRANSFORM_HPP
+#define OPENCV_CUDEV_PTR2D_TRANSFORM_HPP
 
 #include "../common.hpp"
 #include "../grid/copy.hpp"
diff --git a/modules/cudev/include/opencv2/cudev/ptr2d/warping.hpp b/modules/cudev/include/opencv2/cudev/ptr2d/warping.hpp
index c9d0083..02df07f 100644
--- a/modules/cudev/include/opencv2/cudev/ptr2d/warping.hpp
+++ b/modules/cudev/include/opencv2/cudev/ptr2d/warping.hpp
@@ -43,8 +43,8 @@
 
 #pragma once
 
-#ifndef __OPENCV_CUDEV_PTR2D_WARPING_HPP__
-#define __OPENCV_CUDEV_PTR2D_WARPING_HPP__
+#ifndef OPENCV_CUDEV_PTR2D_WARPING_HPP
+#define OPENCV_CUDEV_PTR2D_WARPING_HPP
 
 #include "../common.hpp"
 #include "traits.hpp"
diff --git a/modules/cudev/include/opencv2/cudev/ptr2d/zip.hpp b/modules/cudev/include/opencv2/cudev/ptr2d/zip.hpp
index 3688482..e68f4cf 100644
--- a/modules/cudev/include/opencv2/cudev/ptr2d/zip.hpp
+++ b/modules/cudev/include/opencv2/cudev/ptr2d/zip.hpp
@@ -43,8 +43,8 @@
 
 #pragma once
 
-#ifndef __OPENCV_CUDEV_PTR2D_ZIP_HPP__
-#define __OPENCV_CUDEV_PTR2D_ZIP_HPP__
+#ifndef OPENCV_CUDEV_PTR2D_ZIP_HPP
+#define OPENCV_CUDEV_PTR2D_ZIP_HPP
 
 #include "../common.hpp"
 #include "../util/tuple.hpp"
diff --git a/modules/cudev/include/opencv2/cudev/util/atomic.hpp b/modules/cudev/include/opencv2/cudev/util/atomic.hpp
index a88cd99..b05fff9 100644
--- a/modules/cudev/include/opencv2/cudev/util/atomic.hpp
+++ b/modules/cudev/include/opencv2/cudev/util/atomic.hpp
@@ -43,8 +43,8 @@
 
 #pragma once
 
-#ifndef __OPENCV_CUDEV_UTIL_ATOMIC_HPP__
-#define __OPENCV_CUDEV_UTIL_ATOMIC_HPP__
+#ifndef OPENCV_CUDEV_UTIL_ATOMIC_HPP
+#define OPENCV_CUDEV_UTIL_ATOMIC_HPP
 
 #include "../common.hpp"
 
diff --git a/modules/cudev/include/opencv2/cudev/util/detail/tuple.hpp b/modules/cudev/include/opencv2/cudev/util/detail/tuple.hpp
index 2fc8494..2483061 100644
--- a/modules/cudev/include/opencv2/cudev/util/detail/tuple.hpp
+++ b/modules/cudev/include/opencv2/cudev/util/detail/tuple.hpp
@@ -43,8 +43,8 @@
 
 #pragma once
 
-#ifndef __OPENCV_CUDEV_UTIL_TUPLE_DETAIL_HPP__
-#define __OPENCV_CUDEV_UTIL_TUPLE_DETAIL_HPP__
+#ifndef OPENCV_CUDEV_UTIL_TUPLE_DETAIL_HPP
+#define OPENCV_CUDEV_UTIL_TUPLE_DETAIL_HPP
 
 #include <thrust/tuple.h>
 
diff --git a/modules/cudev/include/opencv2/cudev/util/detail/type_traits.hpp b/modules/cudev/include/opencv2/cudev/util/detail/type_traits.hpp
index d711642..91e4736 100644
--- a/modules/cudev/include/opencv2/cudev/util/detail/type_traits.hpp
+++ b/modules/cudev/include/opencv2/cudev/util/detail/type_traits.hpp
@@ -43,8 +43,8 @@
 
 #pragma once
 
-#ifndef __OPENCV_CUDEV_UTIL_TYPE_TRAITS_DETAIL_HPP__
-#define __OPENCV_CUDEV_UTIL_TYPE_TRAITS_DETAIL_HPP__
+#ifndef OPENCV_CUDEV_UTIL_TYPE_TRAITS_DETAIL_HPP
+#define OPENCV_CUDEV_UTIL_TYPE_TRAITS_DETAIL_HPP
 
 #include "../../common.hpp"
 
diff --git a/modules/cudev/include/opencv2/cudev/util/limits.hpp b/modules/cudev/include/opencv2/cudev/util/limits.hpp
index 71e7faa..753fd91 100644
--- a/modules/cudev/include/opencv2/cudev/util/limits.hpp
+++ b/modules/cudev/include/opencv2/cudev/util/limits.hpp
@@ -43,8 +43,8 @@
 
 #pragma once
 
-#ifndef __OPENCV_CUDEV_UTIL_LIMITS_HPP__
-#define __OPENCV_CUDEV_UTIL_LIMITS_HPP__
+#ifndef OPENCV_CUDEV_UTIL_LIMITS_HPP
+#define OPENCV_CUDEV_UTIL_LIMITS_HPP
 
 #include <limits.h>
 #include <float.h>
diff --git a/modules/cudev/include/opencv2/cudev/util/saturate_cast.hpp b/modules/cudev/include/opencv2/cudev/util/saturate_cast.hpp
index 3176542..ec9804c 100644
--- a/modules/cudev/include/opencv2/cudev/util/saturate_cast.hpp
+++ b/modules/cudev/include/opencv2/cudev/util/saturate_cast.hpp
@@ -43,8 +43,8 @@
 
 #pragma once
 
-#ifndef __OPENCV_CUDEV_UTIL_SATURATE_CAST_HPP__
-#define __OPENCV_CUDEV_UTIL_SATURATE_CAST_HPP__
+#ifndef OPENCV_CUDEV_UTIL_SATURATE_CAST_HPP
+#define OPENCV_CUDEV_UTIL_SATURATE_CAST_HPP
 
 #include "../common.hpp"
 
@@ -270,6 +270,17 @@ template <> __device__ __forceinline__ uint saturate_cast<uint>(double v)
 #endif
 }
 
+template <typename T, typename D> __device__ __forceinline__ D cast_fp16(T v);
+
+template <> __device__ __forceinline__ float cast_fp16<short, float>(short v)
+{
+    return __half2float(v);
+}
+
+template <> __device__ __forceinline__ short cast_fp16<float, short>(float v)
+{
+    return (short)__float2half_rn(v);
+}
 //! @}
 
 }}
diff --git a/modules/cudev/include/opencv2/cudev/util/simd_functions.hpp b/modules/cudev/include/opencv2/cudev/util/simd_functions.hpp
index 2dd6f12..ed6efa6 100644
--- a/modules/cudev/include/opencv2/cudev/util/simd_functions.hpp
+++ b/modules/cudev/include/opencv2/cudev/util/simd_functions.hpp
@@ -73,8 +73,8 @@
 
 #pragma once
 
-#ifndef __OPENCV_CUDEV_UTIL_SIMD_FUNCTIONS_HPP__
-#define __OPENCV_CUDEV_UTIL_SIMD_FUNCTIONS_HPP__
+#ifndef OPENCV_CUDEV_UTIL_SIMD_FUNCTIONS_HPP
+#define OPENCV_CUDEV_UTIL_SIMD_FUNCTIONS_HPP
 
 #include "../common.hpp"
 
diff --git a/modules/cudev/include/opencv2/cudev/util/tuple.hpp b/modules/cudev/include/opencv2/cudev/util/tuple.hpp
index 70d0424..b28bb4d 100644
--- a/modules/cudev/include/opencv2/cudev/util/tuple.hpp
+++ b/modules/cudev/include/opencv2/cudev/util/tuple.hpp
@@ -43,8 +43,8 @@
 
 #pragma once
 
-#ifndef __OPENCV_CUDEV_UTIL_TUPLE_HPP__
-#define __OPENCV_CUDEV_UTIL_TUPLE_HPP__
+#ifndef OPENCV_CUDEV_UTIL_TUPLE_HPP
+#define OPENCV_CUDEV_UTIL_TUPLE_HPP
 
 #include "../common.hpp"
 #include "detail/tuple.hpp"
diff --git a/modules/cudev/include/opencv2/cudev/util/type_traits.hpp b/modules/cudev/include/opencv2/cudev/util/type_traits.hpp
index acd1d3b..cad1f00 100644
--- a/modules/cudev/include/opencv2/cudev/util/type_traits.hpp
+++ b/modules/cudev/include/opencv2/cudev/util/type_traits.hpp
@@ -43,8 +43,8 @@
 
 #pragma once
 
-#ifndef __OPENCV_CUDEV_UTIL_TYPE_TRAITS_HPP__
-#define __OPENCV_CUDEV_UTIL_TYPE_TRAITS_HPP__
+#ifndef OPENCV_CUDEV_UTIL_TYPE_TRAITS_HPP
+#define OPENCV_CUDEV_UTIL_TYPE_TRAITS_HPP
 
 #include "../common.hpp"
 #include "vec_traits.hpp"
diff --git a/modules/cudev/include/opencv2/cudev/util/vec_math.hpp b/modules/cudev/include/opencv2/cudev/util/vec_math.hpp
index 82fa06e..f6d8d2c 100644
--- a/modules/cudev/include/opencv2/cudev/util/vec_math.hpp
+++ b/modules/cudev/include/opencv2/cudev/util/vec_math.hpp
@@ -43,8 +43,8 @@
 
 #pragma once
 
-#ifndef __OPENCV_CUDEV_UTIL_VEC_MATH_HPP__
-#define __OPENCV_CUDEV_UTIL_VEC_MATH_HPP__
+#ifndef OPENCV_CUDEV_UTIL_VEC_MATH_HPP
+#define OPENCV_CUDEV_UTIL_VEC_MATH_HPP
 
 #include "vec_traits.hpp"
 #include "saturate_cast.hpp"
diff --git a/modules/cudev/include/opencv2/cudev/util/vec_traits.hpp b/modules/cudev/include/opencv2/cudev/util/vec_traits.hpp
index 9bb5678..bff3744 100644
--- a/modules/cudev/include/opencv2/cudev/util/vec_traits.hpp
+++ b/modules/cudev/include/opencv2/cudev/util/vec_traits.hpp
@@ -43,8 +43,8 @@
 
 #pragma once
 
-#ifndef __OPENCV_CUDEV_UTIL_VEC_TRAITS_HPP__
-#define __OPENCV_CUDEV_UTIL_VEC_TRAITS_HPP__
+#ifndef OPENCV_CUDEV_UTIL_VEC_TRAITS_HPP
+#define OPENCV_CUDEV_UTIL_VEC_TRAITS_HPP
 
 #include "../common.hpp"
 
diff --git a/modules/cudev/include/opencv2/cudev/warp/detail/reduce.hpp b/modules/cudev/include/opencv2/cudev/warp/detail/reduce.hpp
index 7f9faf9..2848889 100644
--- a/modules/cudev/include/opencv2/cudev/warp/detail/reduce.hpp
+++ b/modules/cudev/include/opencv2/cudev/warp/detail/reduce.hpp
@@ -43,8 +43,8 @@
 
 #pragma once
 
-#ifndef __OPENCV_CUDEV_WARP_REDUCE_DETAIL_HPP__
-#define __OPENCV_CUDEV_WARP_REDUCE_DETAIL_HPP__
+#ifndef OPENCV_CUDEV_WARP_REDUCE_DETAIL_HPP
+#define OPENCV_CUDEV_WARP_REDUCE_DETAIL_HPP
 
 #include "../../common.hpp"
 #include "../../util/tuple.hpp"
diff --git a/modules/cudev/include/opencv2/cudev/warp/detail/reduce_key_val.hpp b/modules/cudev/include/opencv2/cudev/warp/detail/reduce_key_val.hpp
index 7701795..c6deb3a 100644
--- a/modules/cudev/include/opencv2/cudev/warp/detail/reduce_key_val.hpp
+++ b/modules/cudev/include/opencv2/cudev/warp/detail/reduce_key_val.hpp
@@ -43,8 +43,8 @@
 
 #pragma once
 
-#ifndef __OPENCV_CUDEV_WARP_REDUCE_KEY_VAL_DETAIL_HPP__
-#define __OPENCV_CUDEV_WARP_REDUCE_KEY_VAL_DETAIL_HPP__
+#ifndef OPENCV_CUDEV_WARP_REDUCE_KEY_VAL_DETAIL_HPP
+#define OPENCV_CUDEV_WARP_REDUCE_KEY_VAL_DETAIL_HPP
 
 #include "../../common.hpp"
 #include "../../util/tuple.hpp"
diff --git a/modules/cudev/include/opencv2/cudev/warp/reduce.hpp b/modules/cudev/include/opencv2/cudev/warp/reduce.hpp
index f3919c2..4682603 100644
--- a/modules/cudev/include/opencv2/cudev/warp/reduce.hpp
+++ b/modules/cudev/include/opencv2/cudev/warp/reduce.hpp
@@ -43,8 +43,8 @@
 
 #pragma once
 
-#ifndef __OPENCV_CUDEV_WARP_REDUCE_HPP__
-#define __OPENCV_CUDEV_WARP_REDUCE_HPP__
+#ifndef OPENCV_CUDEV_WARP_REDUCE_HPP
+#define OPENCV_CUDEV_WARP_REDUCE_HPP
 
 #include "../common.hpp"
 #include "../util/tuple.hpp"
diff --git a/modules/cudev/include/opencv2/cudev/warp/scan.hpp b/modules/cudev/include/opencv2/cudev/warp/scan.hpp
index a440298..f76376e 100644
--- a/modules/cudev/include/opencv2/cudev/warp/scan.hpp
+++ b/modules/cudev/include/opencv2/cudev/warp/scan.hpp
@@ -43,8 +43,8 @@
 
 #pragma once
 
-#ifndef __OPENCV_CUDEV_WARP_SCAN_HPP__
-#define __OPENCV_CUDEV_WARP_SCAN_HPP__
+#ifndef OPENCV_CUDEV_WARP_SCAN_HPP
+#define OPENCV_CUDEV_WARP_SCAN_HPP
 
 #include "../common.hpp"
 #include "warp.hpp"
diff --git a/modules/cudev/include/opencv2/cudev/warp/shuffle.hpp b/modules/cudev/include/opencv2/cudev/warp/shuffle.hpp
index 97af069..94e5879 100644
--- a/modules/cudev/include/opencv2/cudev/warp/shuffle.hpp
+++ b/modules/cudev/include/opencv2/cudev/warp/shuffle.hpp
@@ -43,8 +43,8 @@
 
 #pragma once
 
-#ifndef __OPENCV_CUDEV_WARP_SHUFFLE_HPP__
-#define __OPENCV_CUDEV_WARP_SHUFFLE_HPP__
+#ifndef OPENCV_CUDEV_WARP_SHUFFLE_HPP
+#define OPENCV_CUDEV_WARP_SHUFFLE_HPP
 
 #include "../common.hpp"
 #include "../util/vec_traits.hpp"
diff --git a/modules/cudev/include/opencv2/cudev/warp/warp.hpp b/modules/cudev/include/opencv2/cudev/warp/warp.hpp
index 61caea2..6860ccf 100644
--- a/modules/cudev/include/opencv2/cudev/warp/warp.hpp
+++ b/modules/cudev/include/opencv2/cudev/warp/warp.hpp
@@ -43,8 +43,8 @@
 
 #pragma once
 
-#ifndef __OPENCV_CUDEV_WARP_WARP_HPP__
-#define __OPENCV_CUDEV_WARP_WARP_HPP__
+#ifndef OPENCV_CUDEV_WARP_WARP_HPP
+#define OPENCV_CUDEV_WARP_WARP_HPP
 
 #include "../common.hpp"
 
diff --git a/modules/cudev/test/CMakeLists.txt b/modules/cudev/test/CMakeLists.txt
index a7bd632..d348fdc 100644
--- a/modules/cudev/test/CMakeLists.txt
+++ b/modules/cudev/test/CMakeLists.txt
@@ -13,20 +13,7 @@ if(OCV_DEPENDENCIES_FOUND)
   source_group("Include" FILES ${test_hdrs})
   set(OPENCV_TEST_${the_module}_SOURCES ${test_srcs} ${test_hdrs})
 
-  foreach(var CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_RELEASE CMAKE_CXX_FLAGS_DEBUG)
-    # we remove /EHa as it generates warnings under windows
-    string(REPLACE "/EHa" "" ${var} "${${var}}")
-
-    # we remove -ggdb3 flag as it leads to preprocessor errors when compiling CUDA files (CUDA 4.1)
-    string(REPLACE "-ggdb3" "" ${var} "${${var}}")
-
-    # we remove -Wsign-promo as it generates warnings under linux
-    string(REPLACE "-Wsign-promo" "" ${var} "${${var}}")
-
-    # we remove -fvisibility-inlines-hidden because it's used for C++ compiler
-    # but NVCC uses C compiler by default
-    string(REPLACE "-fvisibility-inlines-hidden" "" ${var} "${${var}}")
-  endforeach()
+  ocv_cuda_filter_options()
 
   CUDA_ADD_EXECUTABLE(${the_target} ${OPENCV_TEST_${the_module}_SOURCES})
   ocv_target_link_libraries(${the_target} ${test_deps} ${OPENCV_LINKER_LIBS} ${CUDA_LIBRARIES})
diff --git a/modules/cudev/test/test_cvt.cu b/modules/cudev/test/test_cvt.cu
index b1c3d10..c659525 100644
--- a/modules/cudev/test/test_cvt.cu
+++ b/modules/cudev/test/test_cvt.cu
@@ -49,6 +49,7 @@ using namespace cv::cudev;
 using namespace cvtest;
 
 typedef ::testing::Types<uchar, ushort, short, int, float> AllTypes;
+typedef ::testing::Types<short, float> Fp16Types;
 
 ////////////////////////////////////////////////////////////////////////////////
 // CvtTest
@@ -75,9 +76,75 @@ public:
     }
 };
 
+// dummy class
+template <typename T>
+class CvFp16Test : public ::testing::Test
+{
+public:
+    void test_gpumat()
+    {
+    }
+};
+
+template <>
+class CvFp16Test <short> : public ::testing::Test
+{
+public:
+    void test_gpumat()
+    {
+        const Size size = randomSize(100, 400);
+        const int type = DataType<float>::type;
+
+        Mat src = randomMat(size, type), dst, ref;
+
+        GpuMat_<float> g_src(src);
+        GpuMat g_dst;
+
+        // Fp32 -> Fp16
+        cuda::convertFp16(g_src, g_dst);
+        cv::convertFp16(src, dst);
+        // Fp16 -> Fp32
+        cuda::convertFp16(g_dst.clone(), g_dst);
+        cv::convertFp16(dst, ref);
+
+        g_dst.download(dst);
+        EXPECT_MAT_NEAR(dst, ref, 0.0);
+    }
+};
+
+template <>
+class CvFp16Test <float> : public ::testing::Test
+{
+public:
+    void test_gpumat()
+    {
+        const Size size = randomSize(100, 400);
+        const int type = DataType<float>::type;
+
+        Mat src = randomMat(size, type), dst, ref;
+
+        GpuMat_<float> g_src(src);
+        GpuMat g_dst;
+
+        // Fp32 -> Fp16
+        cuda::convertFp16(g_src, g_dst);
+        cv::convertFp16(src, ref);
+
+        g_dst.download(dst);
+        EXPECT_MAT_NEAR(dst, ref, 0.0);
+    }
+};
+
 TYPED_TEST_CASE(CvtTest, AllTypes);
 
 TYPED_TEST(CvtTest, GpuMat)
 {
     CvtTest<TypeParam>::test_gpumat();
 }
+
+TYPED_TEST_CASE(CvFp16Test, Fp16Types);
+
+TYPED_TEST(CvFp16Test, GpuMat)
+{
+    CvFp16Test<TypeParam>::test_gpumat();
+}
diff --git a/modules/cudev/test/test_reduction.cu b/modules/cudev/test/test_reduction.cu
index c376059..03c78de 100644
--- a/modules/cudev/test/test_reduction.cu
+++ b/modules/cudev/test/test_reduction.cu
@@ -228,9 +228,6 @@ TEST(ReduceToColumn, Sum)
 
     Mat dst_gold;
     cv::reduce(src, dst_gold, 1, REDUCE_SUM, CV_32S);
-    dst_gold.cols = dst_gold.rows;
-    dst_gold.rows = 1;
-    dst_gold.step = dst_gold.cols * dst_gold.elemSize();
 
     EXPECT_MAT_NEAR(dst_gold, dst, 0.0);
 }
@@ -247,9 +244,6 @@ TEST(ReduceToColumn, Avg)
 
     Mat dst_gold;
     cv::reduce(src, dst_gold, 1, REDUCE_AVG, CV_32F);
-    dst_gold.cols = dst_gold.rows;
-    dst_gold.rows = 1;
-    dst_gold.step = dst_gold.cols * dst_gold.elemSize();
 
     EXPECT_MAT_NEAR(dst_gold, dst, 1e-4);
 }
@@ -266,9 +260,6 @@ TEST(ReduceToColumn, Min)
 
     Mat dst_gold;
     cv::reduce(src, dst_gold, 1, REDUCE_MIN);
-    dst_gold.cols = dst_gold.rows;
-    dst_gold.rows = 1;
-    dst_gold.step = dst_gold.cols * dst_gold.elemSize();
 
     EXPECT_MAT_NEAR(dst_gold, dst, 0.0);
 }
@@ -285,9 +276,6 @@ TEST(ReduceToColumn, Max)
 
     Mat dst_gold;
     cv::reduce(src, dst_gold, 1, REDUCE_MAX);
-    dst_gold.cols = dst_gold.rows;
-    dst_gold.rows = 1;
-    dst_gold.step = dst_gold.cols * dst_gold.elemSize();
 
     EXPECT_MAT_NEAR(dst_gold, dst, 0.0);
 }
diff --git a/modules/features2d/doc/agast.txt b/modules/features2d/doc/agast.txt
index 974446f..737b041 100644
--- a/modules/features2d/doc/agast.txt
+++ b/modules/features2d/doc/agast.txt
@@ -65,24 +65,24 @@ static void AGAST_5_8(InputArray _img, std::vector<KeyPoint>& keypoints, int thr
     int xsize = img.cols;
     int ysize = img.rows;
     size_t nExpectedCorners = keypoints.capacity();
-    register int x, y;
-    register int xsizeB = xsize - 2;
-    register int ysizeB = ysize - 1;
-    register int width;
+    int x, y;
+    int xsizeB = xsize - 2;
+    int ysizeB = ysize - 1;
+    int width;
 
     keypoints.resize(0);
 
     int pixel_5_8_[16];
     makeAgastOffsets(pixel_5_8_, (int)img.step, AgastFeatureDetector::AGAST_5_8);
 
-    register short offset0 = (short) pixel_5_8_[0];
-    register short offset1 = (short) pixel_5_8_[1];
-    register short offset2 = (short) pixel_5_8_[2];
-    register short offset3 = (short) pixel_5_8_[3];
-    register short offset4 = (short) pixel_5_8_[4];
-    register short offset5 = (short) pixel_5_8_[5];
-    register short offset6 = (short) pixel_5_8_[6];
-    register short offset7 = (short) pixel_5_8_[7];
+    short offset0 = (short) pixel_5_8_[0];
+    short offset1 = (short) pixel_5_8_[1];
+    short offset2 = (short) pixel_5_8_[2];
+    short offset3 = (short) pixel_5_8_[3];
+    short offset4 = (short) pixel_5_8_[4];
+    short offset5 = (short) pixel_5_8_[5];
+    short offset6 = (short) pixel_5_8_[6];
+    short offset7 = (short) pixel_5_8_[7];
 
     width = xsize;
 
@@ -98,9 +98,9 @@ static void AGAST_5_8(InputArray _img, std::vector<KeyPoint>& keypoints, int thr
                 break;
             else
             {
-                register const unsigned char* const ptr = img.ptr() + y*width + x;
-                register const int cb = *ptr + threshold;
-                register const int c_b = *ptr - threshold;
+                const unsigned char* const ptr = img.ptr() + y*width + x;
+                const int cb = *ptr + threshold;
+                const int c_b = *ptr - threshold;
                 if(ptr[offset0] > cb)
                   if(ptr[offset2] > cb)
                     if(ptr[offset3] > cb)
@@ -435,9 +435,9 @@ static void AGAST_5_8(InputArray _img, std::vector<KeyPoint>& keypoints, int thr
                 break;
             else
             {
-                register const unsigned char* const ptr = img.ptr() + y*width + x;
-                register const int cb = *ptr + threshold;
-                register const int c_b = *ptr - threshold;
+                const unsigned char* const ptr = img.ptr() + y*width + x;
+                const int cb = *ptr + threshold;
+                const int c_b = *ptr - threshold;
                 if(ptr[offset0] > cb)
                   if(ptr[offset2] > cb)
                     if(ptr[offset3] > cb)
@@ -827,28 +827,28 @@ static void AGAST_7_12d(InputArray _img, std::vector<KeyPoint>& keypoints, int t
     int xsize = img.cols;
     int ysize = img.rows;
     size_t nExpectedCorners = keypoints.capacity();
-    register int x, y;
-    register int xsizeB = xsize - 4;
-    register int ysizeB = ysize - 3;
-    register int width;
+    int x, y;
+    int xsizeB = xsize - 4;
+    int ysizeB = ysize - 3;
+    int width;
 
     keypoints.resize(0);
 
     int pixel_7_12d_[16];
     makeAgastOffsets(pixel_7_12d_, (int)img.step, AgastFeatureDetector::AGAST_7_12d);
 
-    register short offset0 = (short) pixel_7_12d_[0];
-    register short offset1 = (short) pixel_7_12d_[1];
-    register short offset2 = (short) pixel_7_12d_[2];
-    register short offset3 = (short) pixel_7_12d_[3];
-    register short offset4 = (short) pixel_7_12d_[4];
-    register short offset5 = (short) pixel_7_12d_[5];
-    register short offset6 = (short) pixel_7_12d_[6];
-    register short offset7 = (short) pixel_7_12d_[7];
-    register short offset8 = (short) pixel_7_12d_[8];
-    register short offset9 = (short) pixel_7_12d_[9];
-    register short offset10 = (short) pixel_7_12d_[10];
-    register short offset11 = (short) pixel_7_12d_[11];
+    short offset0 = (short) pixel_7_12d_[0];
+    short offset1 = (short) pixel_7_12d_[1];
+    short offset2 = (short) pixel_7_12d_[2];
+    short offset3 = (short) pixel_7_12d_[3];
+    short offset4 = (short) pixel_7_12d_[4];
+    short offset5 = (short) pixel_7_12d_[5];
+    short offset6 = (short) pixel_7_12d_[6];
+    short offset7 = (short) pixel_7_12d_[7];
+    short offset8 = (short) pixel_7_12d_[8];
+    short offset9 = (short) pixel_7_12d_[9];
+    short offset10 = (short) pixel_7_12d_[10];
+    short offset11 = (short) pixel_7_12d_[11];
 
     width = xsize;
 
@@ -864,9 +864,9 @@ static void AGAST_7_12d(InputArray _img, std::vector<KeyPoint>& keypoints, int t
                 break;
             else
             {
-                register const unsigned char* const ptr = img.ptr() + y*width + x;
-                register const int cb = *ptr + threshold;
-                register const int c_b = *ptr - threshold;
+                const unsigned char* const ptr = img.ptr() + y*width + x;
+                const int cb = *ptr + threshold;
+                const int c_b = *ptr - threshold;
                 if(ptr[offset0] > cb)
                   if(ptr[offset5] > cb)
                     if(ptr[offset2] > cb)
@@ -2047,9 +2047,9 @@ static void AGAST_7_12d(InputArray _img, std::vector<KeyPoint>& keypoints, int t
                 break;
             else
             {
-                register const unsigned char* const ptr = img.ptr() + y*width + x;
-                register const int cb = *ptr + threshold;
-                register const int c_b = *ptr - threshold;
+                const unsigned char* const ptr = img.ptr() + y*width + x;
+                const int cb = *ptr + threshold;
+                const int c_b = *ptr - threshold;
                 if(ptr[offset0] > cb)
                   if(ptr[offset5] > cb)
                     if(ptr[offset2] > cb)
@@ -3273,28 +3273,28 @@ static void AGAST_7_12s(InputArray _img, std::vector<KeyPoint>& keypoints, int t
     int xsize = img.cols;
     int ysize = img.rows;
     size_t nExpectedCorners = keypoints.capacity();
-    register int x, y;
-    register int xsizeB=xsize - 3; //2, +1 due to faster test x>xsizeB
-    register int ysizeB=ysize - 2;
-    register int width;
+    int x, y;
+    int xsizeB=xsize - 3; //2, +1 due to faster test x>xsizeB
+    int ysizeB=ysize - 2;
+    int width;
 
     keypoints.resize(0);
 
     int pixel_7_12s_[16];
     makeAgastOffsets(pixel_7_12s_, (int)img.step, AgastFeatureDetector::AGAST_7_12s);
 
-    register short offset0 = (short) pixel_7_12s_[0];
-    register short offset1 = (short) pixel_7_12s_[1];
-    register short offset2 = (short) pixel_7_12s_[2];
-    register short offset3 = (short) pixel_7_12s_[3];
-    register short offset4 = (short) pixel_7_12s_[4];
-    register short offset5 = (short) pixel_7_12s_[5];
-    register short offset6 = (short) pixel_7_12s_[6];
-    register short offset7 = (short) pixel_7_12s_[7];
-    register short offset8 = (short) pixel_7_12s_[8];
-    register short offset9 = (short) pixel_7_12s_[9];
-    register short offset10 = (short) pixel_7_12s_[10];
-    register short offset11 = (short) pixel_7_12s_[11];
+    short offset0 = (short) pixel_7_12s_[0];
+    short offset1 = (short) pixel_7_12s_[1];
+    short offset2 = (short) pixel_7_12s_[2];
+    short offset3 = (short) pixel_7_12s_[3];
+    short offset4 = (short) pixel_7_12s_[4];
+    short offset5 = (short) pixel_7_12s_[5];
+    short offset6 = (short) pixel_7_12s_[6];
+    short offset7 = (short) pixel_7_12s_[7];
+    short offset8 = (short) pixel_7_12s_[8];
+    short offset9 = (short) pixel_7_12s_[9];
+    short offset10 = (short) pixel_7_12s_[10];
+    short offset11 = (short) pixel_7_12s_[11];
 
     width = xsize;
 
@@ -3310,9 +3310,9 @@ static void AGAST_7_12s(InputArray _img, std::vector<KeyPoint>& keypoints, int t
                 break;
             else
             {
-                register const unsigned char* const ptr = img.ptr() + y*width + x;
-                register const int cb = *ptr + threshold;
-                register const int c_b = *ptr - threshold;
+                const unsigned char* const ptr = img.ptr() + y*width + x;
+                const int cb = *ptr + threshold;
+                const int c_b = *ptr - threshold;
                 if(ptr[offset0] > cb)
                   if(ptr[offset2] > cb)
                     if(ptr[offset5] > cb)
@@ -4349,9 +4349,9 @@ static void AGAST_7_12s(InputArray _img, std::vector<KeyPoint>& keypoints, int t
                 break;
             else
             {
-                register const unsigned char* const ptr = img.ptr() + y*width + x;
-                register const int cb = *ptr + threshold;
-                register const int c_b = *ptr - threshold;
+                const unsigned char* const ptr = img.ptr() + y*width + x;
+                const int cb = *ptr + threshold;
+                const int c_b = *ptr - threshold;
                 if(ptr[offset0] > cb)
                   if(ptr[offset2] > cb)
                     if(ptr[offset5] > cb)
@@ -5356,32 +5356,32 @@ static void OAST_9_16(InputArray _img, std::vector<KeyPoint>& keypoints, int thr
     int xsize = img.cols;
     int ysize = img.rows;
     size_t nExpectedCorners = keypoints.capacity();
-    register int x, y;
-    register int xsizeB=xsize - 4;
-    register int ysizeB=ysize - 3;
-    register int width;
+    int x, y;
+    int xsizeB=xsize - 4;
+    int ysizeB=ysize - 3;
+    int width;
 
     keypoints.resize(0);
 
     int pixel_9_16_[16];
     makeAgastOffsets(pixel_9_16_, (int)img.step, AgastFeatureDetector::OAST_9_16);
 
-    register short offset0 = (short) pixel_9_16_[0];
-    register short offset1 = (short) pixel_9_16_[1];
-    register short offset2 = (short) pixel_9_16_[2];
-    register short offset3 = (short) pixel_9_16_[3];
-    register short offset4 = (short) pixel_9_16_[4];
-    register short offset5 = (short) pixel_9_16_[5];
-    register short offset6 = (short) pixel_9_16_[6];
-    register short offset7 = (short) pixel_9_16_[7];
-    register short offset8 = (short) pixel_9_16_[8];
-    register short offset9 = (short) pixel_9_16_[9];
-    register short offset10 = (short) pixel_9_16_[10];
-    register short offset11 = (short) pixel_9_16_[11];
-    register short offset12 = (short) pixel_9_16_[12];
-    register short offset13 = (short) pixel_9_16_[13];
-    register short offset14 = (short) pixel_9_16_[14];
-    register short offset15 = (short) pixel_9_16_[15];
+    short offset0 = (short) pixel_9_16_[0];
+    short offset1 = (short) pixel_9_16_[1];
+    short offset2 = (short) pixel_9_16_[2];
+    short offset3 = (short) pixel_9_16_[3];
+    short offset4 = (short) pixel_9_16_[4];
+    short offset5 = (short) pixel_9_16_[5];
+    short offset6 = (short) pixel_9_16_[6];
+    short offset7 = (short) pixel_9_16_[7];
+    short offset8 = (short) pixel_9_16_[8];
+    short offset9 = (short) pixel_9_16_[9];
+    short offset10 = (short) pixel_9_16_[10];
+    short offset11 = (short) pixel_9_16_[11];
+    short offset12 = (short) pixel_9_16_[12];
+    short offset13 = (short) pixel_9_16_[13];
+    short offset14 = (short) pixel_9_16_[14];
+    short offset15 = (short) pixel_9_16_[15];
 
     width = xsize;
 
@@ -5395,9 +5395,9 @@ static void OAST_9_16(InputArray _img, std::vector<KeyPoint>& keypoints, int thr
                 break;
             else
             {
-                register const unsigned char* const ptr = img.ptr() + y*width + x;
-                register const int cb = *ptr + threshold;
-                register const int c_b = *ptr - threshold;
+                const unsigned char* const ptr = img.ptr() + y*width + x;
+                const int cb = *ptr + threshold;
+                const int c_b = *ptr - threshold;
                 if(ptr[offset0] > cb)
                   if(ptr[offset2] > cb)
                     if(ptr[offset4] > cb)
diff --git a/modules/features2d/doc/agast_score.txt b/modules/features2d/doc/agast_score.txt
index baca9b0..3c0b347 100644
--- a/modules/features2d/doc/agast_score.txt
+++ b/modules/features2d/doc/agast_score.txt
@@ -97,27 +97,27 @@ int agast_cornerScore<AgastFeatureDetector::OAST_9_16>(const uchar* ptr, const i
     int bmax = 255;
     int b_test = (bmax + bmin) / 2;
 
-    register short offset0 = (short) pixel[0];
-    register short offset1 = (short) pixel[1];
-    register short offset2 = (short) pixel[2];
-    register short offset3 = (short) pixel[3];
-    register short offset4 = (short) pixel[4];
-    register short offset5 = (short) pixel[5];
-    register short offset6 = (short) pixel[6];
-    register short offset7 = (short) pixel[7];
-    register short offset8 = (short) pixel[8];
-    register short offset9 = (short) pixel[9];
-    register short offset10 = (short) pixel[10];
-    register short offset11 = (short) pixel[11];
-    register short offset12 = (short) pixel[12];
-    register short offset13 = (short) pixel[13];
-    register short offset14 = (short) pixel[14];
-    register short offset15 = (short) pixel[15];
+    short offset0 = (short) pixel[0];
+    short offset1 = (short) pixel[1];
+    short offset2 = (short) pixel[2];
+    short offset3 = (short) pixel[3];
+    short offset4 = (short) pixel[4];
+    short offset5 = (short) pixel[5];
+    short offset6 = (short) pixel[6];
+    short offset7 = (short) pixel[7];
+    short offset8 = (short) pixel[8];
+    short offset9 = (short) pixel[9];
+    short offset10 = (short) pixel[10];
+    short offset11 = (short) pixel[11];
+    short offset12 = (short) pixel[12];
+    short offset13 = (short) pixel[13];
+    short offset14 = (short) pixel[14];
+    short offset15 = (short) pixel[15];
 
     while(true)
     {
-        register const int cb = *ptr + b_test;
-        register const int c_b = *ptr - b_test;
+        const int cb = *ptr + b_test;
+        const int c_b = *ptr - b_test;
         if(ptr[offset0] > cb)
           if(ptr[offset2] > cb)
             if(ptr[offset4] > cb)
@@ -2196,23 +2196,23 @@ int agast_cornerScore<AgastFeatureDetector::AGAST_7_12d>(const uchar* ptr, const
     int bmax = 255;
     int b_test = (bmax + bmin)/2;
 
-    register short offset0 = (short) pixel[0];
-    register short offset1 = (short) pixel[1];
-    register short offset2 = (short) pixel[2];
-    register short offset3 = (short) pixel[3];
-    register short offset4 = (short) pixel[4];
-    register short offset5 = (short) pixel[5];
-    register short offset6 = (short) pixel[6];
-    register short offset7 = (short) pixel[7];
-    register short offset8 = (short) pixel[8];
-    register short offset9 = (short) pixel[9];
-    register short offset10 = (short) pixel[10];
-    register short offset11 = (short) pixel[11];
+    short offset0 = (short) pixel[0];
+    short offset1 = (short) pixel[1];
+    short offset2 = (short) pixel[2];
+    short offset3 = (short) pixel[3];
+    short offset4 = (short) pixel[4];
+    short offset5 = (short) pixel[5];
+    short offset6 = (short) pixel[6];
+    short offset7 = (short) pixel[7];
+    short offset8 = (short) pixel[8];
+    short offset9 = (short) pixel[9];
+    short offset10 = (short) pixel[10];
+    short offset11 = (short) pixel[11];
 
     while(true)
     {
-        register const int cb = *ptr + b_test;
-        register const int c_b = *ptr - b_test;
+        const int cb = *ptr + b_test;
+        const int c_b = *ptr - b_test;
         if(ptr[offset0] > cb)
           if(ptr[offset5] > cb)
             if(ptr[offset2] > cb)
@@ -3409,23 +3409,23 @@ int agast_cornerScore<AgastFeatureDetector::AGAST_7_12s>(const uchar* ptr, const
     int bmax = 255;
     int b_test = (bmax + bmin)/2;
 
-    register short offset0 = (short) pixel[0];
-    register short offset1 = (short) pixel[1];
-    register short offset2 = (short) pixel[2];
-    register short offset3 = (short) pixel[3];
-    register short offset4 = (short) pixel[4];
-    register short offset5 = (short) pixel[5];
-    register short offset6 = (short) pixel[6];
-    register short offset7 = (short) pixel[7];
-    register short offset8 = (short) pixel[8];
-    register short offset9 = (short) pixel[9];
-    register short offset10 = (short) pixel[10];
-    register short offset11 = (short) pixel[11];
+    short offset0 = (short) pixel[0];
+    short offset1 = (short) pixel[1];
+    short offset2 = (short) pixel[2];
+    short offset3 = (short) pixel[3];
+    short offset4 = (short) pixel[4];
+    short offset5 = (short) pixel[5];
+    short offset6 = (short) pixel[6];
+    short offset7 = (short) pixel[7];
+    short offset8 = (short) pixel[8];
+    short offset9 = (short) pixel[9];
+    short offset10 = (short) pixel[10];
+    short offset11 = (short) pixel[11];
 
     while(true)
     {
-        register const int cb = *ptr + b_test;
-        register const int c_b = *ptr - b_test;
+        const int cb = *ptr + b_test;
+        const int c_b = *ptr - b_test;
         if(ptr[offset0] > cb)
           if(ptr[offset5] > cb)
             if(ptr[offset2] < c_b)
@@ -9044,19 +9044,19 @@ int agast_cornerScore<AgastFeatureDetector::AGAST_5_8>(const uchar* ptr, const i
     int bmax = 255;
     int b_test = (bmax + bmin)/2;
 
-    register short offset0 = (short) pixel[0];
-    register short offset1 = (short) pixel[1];
-    register short offset2 = (short) pixel[2];
-    register short offset3 = (short) pixel[3];
-    register short offset4 = (short) pixel[4];
-    register short offset5 = (short) pixel[5];
-    register short offset6 = (short) pixel[6];
-    register short offset7 = (short) pixel[7];
+    short offset0 = (short) pixel[0];
+    short offset1 = (short) pixel[1];
+    short offset2 = (short) pixel[2];
+    short offset3 = (short) pixel[3];
+    short offset4 = (short) pixel[4];
+    short offset5 = (short) pixel[5];
+    short offset6 = (short) pixel[6];
+    short offset7 = (short) pixel[7];
 
     while(true)
     {
-        register const int cb = *ptr + b_test;
-        register const int c_b = *ptr - b_test;
+        const int cb = *ptr + b_test;
+        const int c_b = *ptr - b_test;
         if(ptr[offset0] > cb)
           if(ptr[offset2] > cb)
             if(ptr[offset3] > cb)
diff --git a/modules/features2d/include/opencv2/features2d.hpp b/modules/features2d/include/opencv2/features2d.hpp
index 692d3d9..70fe409 100644
--- a/modules/features2d/include/opencv2/features2d.hpp
+++ b/modules/features2d/include/opencv2/features2d.hpp
@@ -40,8 +40,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_FEATURES_2D_HPP__
-#define __OPENCV_FEATURES_2D_HPP__
+#ifndef OPENCV_FEATURES_2D_HPP
+#define OPENCV_FEATURES_2D_HPP
 
 #include "opencv2/core.hpp"
 #include "opencv2/flann/miniflann.hpp"
@@ -153,8 +153,8 @@ public:
     @param masks Masks for each input image specifying where to look for keypoints (optional).
     masks[i] is a mask for images[i].
     */
-    virtual void detect( InputArrayOfArrays images,
-                         std::vector<std::vector<KeyPoint> >& keypoints,
+    CV_WRAP virtual void detect( InputArrayOfArrays images,
+                         CV_OUT std::vector<std::vector<KeyPoint> >& keypoints,
                          InputArrayOfArrays masks=noArray() );
 
     /** @brief Computes the descriptors for a set of keypoints detected in an image (first variant) or image set
@@ -182,8 +182,8 @@ public:
     descriptors computed for a keypoints[i]. Row j is the keypoints (or keypoints[i]) is the
     descriptor for keypoint j-th keypoint.
     */
-    virtual void compute( InputArrayOfArrays images,
-                          std::vector<std::vector<KeyPoint> >& keypoints,
+    CV_WRAP virtual void compute( InputArrayOfArrays images,
+                          CV_OUT CV_IN_OUT std::vector<std::vector<KeyPoint> >& keypoints,
                           OutputArrayOfArrays descriptors );
 
     /** Detects keypoints and computes the descriptors */
@@ -196,6 +196,14 @@ public:
     CV_WRAP virtual int descriptorType() const;
     CV_WRAP virtual int defaultNorm() const;
 
+    CV_WRAP void write( const String& fileName ) const;
+
+    CV_WRAP void read( const String& fileName );
+
+    virtual void write( FileStorage&) const;
+
+    virtual void read( const FileNode&);
+
     //! Return true if detector object is empty
     CV_WRAP virtual bool empty() const;
 };
@@ -355,13 +363,13 @@ public:
 
     /** @brief Detect %MSER regions
 
-    @param image input image (8UC1, 8UC3 or 8UC4)
+    @param image input image (8UC1, 8UC3 or 8UC4, must be greater or equal than 3x3)
     @param msers resulting list of point sets
     @param bboxes resulting bounding boxes
     */
     CV_WRAP virtual void detectRegions( InputArray image,
                                         CV_OUT std::vector<std::vector<Point> >& msers,
-                                        std::vector<Rect>& bboxes ) = 0;
+                                        CV_OUT std::vector<Rect>& bboxes ) = 0;
 
     CV_WRAP virtual void setDelta(int delta) = 0;
     CV_WRAP virtual int getDelta() const = 0;
@@ -771,6 +779,15 @@ an image set.
 class CV_EXPORTS_W DescriptorMatcher : public Algorithm
 {
 public:
+   enum
+    {
+        FLANNBASED            = 1,
+        BRUTEFORCE            = 2,
+        BRUTEFORCE_L1         = 3,
+        BRUTEFORCE_HAMMING    = 4,
+        BRUTEFORCE_HAMMINGLUT = 5,
+        BRUTEFORCE_SL2        = 6
+    };
     virtual ~DescriptorMatcher();
 
     /** @brief Adds descriptors to train a CPU(trainDescCollectionis) or GPU(utrainDescCollectionis) descriptor
@@ -868,8 +885,8 @@ public:
     query descriptor and the training descriptor is equal or smaller than maxDistance. Found matches are
     returned in the distance increasing order.
      */
-    void radiusMatch( InputArray queryDescriptors, InputArray trainDescriptors,
-                      std::vector<std::vector<DMatch> >& matches, float maxDistance,
+    CV_WRAP void radiusMatch( InputArray queryDescriptors, InputArray trainDescriptors,
+                      CV_OUT std::vector<std::vector<DMatch> >& matches, float maxDistance,
                       InputArray mask=noArray(), bool compactResult=false ) const;
 
     /** @overload
@@ -906,9 +923,21 @@ public:
     false, the matches vector has the same size as queryDescriptors rows. If compactResult is true,
     the matches vector does not contain matches for fully masked-out query descriptors.
     */
-    void radiusMatch( InputArray queryDescriptors, std::vector<std::vector<DMatch> >& matches, float maxDistance,
+    CV_WRAP void radiusMatch( InputArray queryDescriptors, CV_OUT std::vector<std::vector<DMatch> >& matches, float maxDistance,
                       InputArrayOfArrays masks=noArray(), bool compactResult=false );
 
+
+    CV_WRAP void write( const String& fileName ) const
+    {
+        FileStorage fs(fileName, FileStorage::WRITE);
+        write(fs);
+    }
+
+    CV_WRAP void read( const String& fileName )
+    {
+        FileStorage fs(fileName, FileStorage::READ);
+        read(fs.root());
+    }
     // Reads matcher object from a file node
     virtual void read( const FileNode& );
     // Writes matcher object to a file storage
@@ -920,7 +949,7 @@ public:
     that is, copies both parameters and train data. If emptyTrainData is true, the method creates an
     object copy with the current parameters but with empty train data.
      */
-    virtual Ptr<DescriptorMatcher> clone( bool emptyTrainData=false ) const = 0;
+    CV_WRAP virtual Ptr<DescriptorMatcher> clone( bool emptyTrainData=false ) const = 0;
 
     /** @brief Creates a descriptor matcher of a given type with the default parameters (using default
     constructor).
@@ -934,6 +963,9 @@ public:
     -   `FlannBased`
      */
     CV_WRAP static Ptr<DescriptorMatcher> create( const String& descriptorMatcherType );
+
+    CV_WRAP static Ptr<DescriptorMatcher> create( int matcherType );
+
 protected:
     /**
      * Class to work with descriptors from several images as with one merged matrix.
@@ -990,8 +1022,17 @@ sets.
 class CV_EXPORTS_W BFMatcher : public DescriptorMatcher
 {
 public:
-    /** @brief Brute-force matcher constructor.
+    /** @brief Brute-force matcher constructor (obsolete). Please use BFMatcher.create()
+     *
+     *
+    */
+    CV_WRAP BFMatcher( int normType=NORM_L2, bool crossCheck=false );
+
+    virtual ~BFMatcher() {}
+
+    virtual bool isMaskSupported() const { return true; }
 
+    /* @brief Brute-force matcher create method.
     @param normType One of NORM_L1, NORM_L2, NORM_HAMMING, NORM_HAMMING2. L1 and L2 norms are
     preferable choices for SIFT and SURF descriptors, NORM_HAMMING should be used with ORB, BRISK and
     BRIEF, NORM_HAMMING2 should be used with ORB when WTA_K==3 or 4 (see ORB::ORB constructor
@@ -1003,10 +1044,7 @@ public:
     pairs. Such technique usually produces best results with minimal number of outliers when there are
     enough matches. This is alternative to the ratio test, used by D. Lowe in SIFT paper.
      */
-    CV_WRAP BFMatcher( int normType=NORM_L2, bool crossCheck=false );
-    virtual ~BFMatcher() {}
-
-    virtual bool isMaskSupported() const { return true; }
+    CV_WRAP static Ptr<BFMatcher> create( int normType=NORM_L2, bool crossCheck=false ) ;
 
     virtual Ptr<DescriptorMatcher> clone( bool emptyTrainData=false ) const;
 protected:
@@ -1022,7 +1060,7 @@ protected:
 
 /** @brief Flann-based descriptor matcher.
 
-This matcher trains flann::Index_ on a train descriptor collection and calls its nearest search
+This matcher trains cv::flann::Index on a train descriptor collection and calls its nearest search
 methods to find the best matches. So, this matcher may be faster when matching a large train
 collection than the brute force matcher. FlannBasedMatcher does not support masking permissible
 matches of descriptor sets because flann::Index does not support this. :
@@ -1044,6 +1082,8 @@ public:
     virtual void train();
     virtual bool isMaskSupported() const;
 
+    CV_WRAP static Ptr<FlannBasedMatcher> create();
+
     virtual Ptr<DescriptorMatcher> clone( bool emptyTrainData=false ) const;
 protected:
     static void convertToDMatches( const DescriptorCollection& descriptors,
diff --git a/modules/features2d/misc/java/filelist b/modules/features2d/misc/java/filelist
index d4ff5ec..0430b54 100644
--- a/modules/features2d/misc/java/filelist
+++ b/modules/features2d/misc/java/filelist
@@ -1 +1,2 @@
 misc/java/src/cpp/features2d_manual.hpp
+include/opencv2/features2d.hpp
diff --git a/modules/features2d/misc/java/filelist_common b/modules/features2d/misc/java/filelist_common
new file mode 100644
index 0000000..7831d45
--- /dev/null
+++ b/modules/features2d/misc/java/filelist_common
@@ -0,0 +1 @@
+misc/java/src/cpp/features2d_converters.hpp
diff --git a/modules/features2d/misc/java/src/cpp/features2d_converters.hpp b/modules/features2d/misc/java/src/cpp/features2d_converters.hpp
index ca90f23..3744115 100644
--- a/modules/features2d/misc/java/src/cpp/features2d_converters.hpp
+++ b/modules/features2d/misc/java/src/cpp/features2d_converters.hpp
@@ -3,8 +3,7 @@
 
 #include "opencv2/opencv_modules.hpp"
 #include "opencv2/core.hpp"
-
-#include "features2d_manual.hpp"
+#include "opencv2/features2d.hpp"
 
 void Mat_to_vector_KeyPoint(cv::Mat& mat, std::vector<cv::KeyPoint>& v_kp);
 void vector_KeyPoint_to_Mat(std::vector<cv::KeyPoint>& v_kp, cv::Mat& mat);
diff --git a/modules/features2d/misc/java/src/cpp/features2d_manual.hpp b/modules/features2d/misc/java/src/cpp/features2d_manual.hpp
index abd6623..6d72bd9 100644
--- a/modules/features2d/misc/java/src/cpp/features2d_manual.hpp
+++ b/modules/features2d/misc/java/src/cpp/features2d_manual.hpp
@@ -89,7 +89,7 @@ public:
 
     //supported: FAST STAR SIFT SURF ORB MSER GFTT HARRIS BRISK AKAZE Grid(XXXX) Pyramid(XXXX) Dynamic(XXXX)
     //not supported: SimpleBlob, Dense
-    CV_WRAP static javaFeatureDetector* create( int detectorType )
+    CV_WRAP static Ptr<javaFeatureDetector> create( int detectorType )
     {
         //String name;
         if (detectorType > DYNAMICDETECTOR)
@@ -156,7 +156,7 @@ public:
             break;
         }
 
-        return new javaFeatureDetector(fd);
+        return makePtr<javaFeatureDetector>(fd);
     }
 
     CV_WRAP void write( const String& fileName ) const
@@ -171,125 +171,12 @@ public:
         wrapped->read(fs.root());
     }
 
-private:
     javaFeatureDetector(Ptr<FeatureDetector> _wrapped) : wrapped(_wrapped)
     {}
 
-    Ptr<FeatureDetector> wrapped;
-};
-
-class CV_EXPORTS_AS(DescriptorMatcher) javaDescriptorMatcher
-{
-public:
-    CV_WRAP bool isMaskSupported() const
-    { return wrapped->isMaskSupported(); }
-
-    CV_WRAP void add( const std::vector<Mat>& descriptors )
-    { return wrapped->add(descriptors); }
-
-    CV_WRAP const std::vector<Mat>& getTrainDescriptors() const
-    { return wrapped->getTrainDescriptors(); }
-
-    CV_WRAP void clear()
-    { return wrapped->clear(); }
-
-    CV_WRAP bool empty() const
-    { return wrapped->empty(); }
-
-    CV_WRAP void train()
-    { return wrapped->train(); }
-
-    CV_WRAP void match( const Mat& queryDescriptors, const Mat& trainDescriptors,
-                CV_OUT std::vector<DMatch>& matches, const Mat& mask=Mat() ) const
-    { return wrapped->match(queryDescriptors, trainDescriptors, matches, mask); }
-
-    CV_WRAP void knnMatch( const Mat& queryDescriptors, const Mat& trainDescriptors,
-                   CV_OUT std::vector<std::vector<DMatch> >& matches, int k,
-                   const Mat& mask=Mat(), bool compactResult=false ) const
-    { return wrapped->knnMatch(queryDescriptors, trainDescriptors, matches, k, mask, compactResult); }
-
-    CV_WRAP void radiusMatch( const Mat& queryDescriptors, const Mat& trainDescriptors,
-                      CV_OUT std::vector<std::vector<DMatch> >& matches, float maxDistance,
-                      const Mat& mask=Mat(), bool compactResult=false ) const
-    { return wrapped->radiusMatch(queryDescriptors, trainDescriptors, matches, maxDistance, mask, compactResult); }
-
-    CV_WRAP void match( const Mat& queryDescriptors, CV_OUT std::vector<DMatch>& matches,
-                const std::vector<Mat>& masks=std::vector<Mat>() )
-    { return wrapped->match(queryDescriptors, matches, masks); }
-
-    CV_WRAP void knnMatch( const Mat& queryDescriptors, CV_OUT std::vector<std::vector<DMatch> >& matches, int k,
-           const std::vector<Mat>& masks=std::vector<Mat>(), bool compactResult=false )
-    { return wrapped->knnMatch(queryDescriptors, matches, k, masks, compactResult); }
-
-    CV_WRAP void radiusMatch( const Mat& queryDescriptors, CV_OUT std::vector<std::vector<DMatch> >& matches, float maxDistance,
-                   const std::vector<Mat>& masks=std::vector<Mat>(), bool compactResult=false )
-    { return wrapped->radiusMatch(queryDescriptors, matches, maxDistance, masks, compactResult); }
-
-    enum
-    {
-        FLANNBASED            = 1,
-        BRUTEFORCE            = 2,
-        BRUTEFORCE_L1         = 3,
-        BRUTEFORCE_HAMMING    = 4,
-        BRUTEFORCE_HAMMINGLUT = 5,
-        BRUTEFORCE_SL2        = 6
-    };
-
-    CV_WRAP_AS(clone) javaDescriptorMatcher* jclone( bool emptyTrainData=false ) const
-    {
-        return new javaDescriptorMatcher(wrapped->clone(emptyTrainData));
-    }
-
-    //supported: FlannBased, BruteForce, BruteForce-L1, BruteForce-Hamming, BruteForce-HammingLUT
-    CV_WRAP static javaDescriptorMatcher* create( int matcherType )
-    {
-        String name;
-
-        switch(matcherType)
-        {
-        case FLANNBASED:
-            name = "FlannBased";
-            break;
-        case BRUTEFORCE:
-            name = "BruteForce";
-            break;
-        case BRUTEFORCE_L1:
-            name = "BruteForce-L1";
-            break;
-        case BRUTEFORCE_HAMMING:
-            name = "BruteForce-Hamming";
-            break;
-        case BRUTEFORCE_HAMMINGLUT:
-            name = "BruteForce-HammingLUT";
-            break;
-        case BRUTEFORCE_SL2:
-            name = "BruteForce-SL2";
-            break;
-        default:
-            CV_Error( Error::StsBadArg, "Specified descriptor matcher type is not supported." );
-            break;
-        }
-
-        return new javaDescriptorMatcher(DescriptorMatcher::create(name));
-    }
-
-    CV_WRAP void write( const String& fileName ) const
-    {
-        FileStorage fs(fileName, FileStorage::WRITE);
-        wrapped->write(fs);
-    }
-
-    CV_WRAP void read( const String& fileName )
-    {
-        FileStorage fs(fileName, FileStorage::READ);
-        wrapped->read(fs.root());
-    }
-
 private:
-    javaDescriptorMatcher(Ptr<DescriptorMatcher> _wrapped) : wrapped(_wrapped)
-    {}
 
-    Ptr<DescriptorMatcher> wrapped;
+    Ptr<FeatureDetector> wrapped;
 };
 
 class CV_EXPORTS_AS(DescriptorExtractor) javaDescriptorExtractor
@@ -336,7 +223,7 @@ public:
 
     //supported SIFT, SURF, ORB, BRIEF, BRISK, FREAK, AKAZE, Opponent(XXXX)
     //not supported: Calonder
-    CV_WRAP static javaDescriptorExtractor* create( int extractorType )
+    CV_WRAP static Ptr<javaDescriptorExtractor> create( int extractorType )
     {
         //String name;
 
@@ -375,7 +262,7 @@ public:
             break;
         }
 
-        return new javaDescriptorExtractor(de);
+        return makePtr<javaDescriptorExtractor>(de);
     }
 
     CV_WRAP void write( const String& fileName ) const
@@ -390,10 +277,11 @@ public:
         wrapped->read(fs.root());
     }
 
-private:
     javaDescriptorExtractor(Ptr<DescriptorExtractor> _wrapped) : wrapped(_wrapped)
     {}
 
+private:
+
     Ptr<DescriptorExtractor> wrapped;
 };
 
@@ -408,17 +296,6 @@ enum
                                   // orientation will be drawn.
 };
 
-// Draw keypoints.
-CV_EXPORTS_W void drawKeypoints( const Mat& image, const std::vector<KeyPoint>& keypoints, Mat& outImage,
-                               const Scalar& color=Scalar::all(-1), int flags=0 );
-
-// Draws matches of keypints from two images on output image.
-CV_EXPORTS_W void drawMatches( const Mat& img1, const std::vector<KeyPoint>& keypoints1,
-                             const Mat& img2, const std::vector<KeyPoint>& keypoints2,
-                             const std::vector<DMatch>& matches1to2, Mat& outImg,
-                             const Scalar& matchColor=Scalar::all(-1), const Scalar& singlePointColor=Scalar::all(-1),
-                             const std::vector<char>& matchesMask=std::vector<char>(), int flags=0 );
-
 CV_EXPORTS_AS(drawMatches2) void drawMatches( const Mat& img1, const std::vector<KeyPoint>& keypoints1,
                              const Mat& img2, const std::vector<KeyPoint>& keypoints2,
                              const std::vector<std::vector<DMatch> >& matches1to2, Mat& outImg,
diff --git a/modules/features2d/misc/java/test/BRIEFDescriptorExtractorTest.java b/modules/features2d/misc/java/test/BRIEFDescriptorExtractorTest.java
index 9f10e25..2c6e543 100644
--- a/modules/features2d/misc/java/test/BRIEFDescriptorExtractorTest.java
+++ b/modules/features2d/misc/java/test/BRIEFDescriptorExtractorTest.java
@@ -1,20 +1,19 @@
 package org.opencv.test.features2d;
 
-import org.opencv.core.Core;
 import org.opencv.core.CvType;
 import org.opencv.core.Mat;
 import org.opencv.core.MatOfKeyPoint;
 import org.opencv.core.Point;
 import org.opencv.core.Scalar;
-import org.opencv.features2d.DescriptorExtractor;
 import org.opencv.core.KeyPoint;
 import org.opencv.test.OpenCVTestCase;
 import org.opencv.test.OpenCVTestRunner;
 import org.opencv.imgproc.Imgproc;
+import org.opencv.features2d.Feature2D;
 
 public class BRIEFDescriptorExtractorTest extends OpenCVTestCase {
 
-    DescriptorExtractor extractor;
+    Feature2D extractor;
     int matSize;
 
     private Mat getTestImg() {
@@ -28,7 +27,7 @@ public class BRIEFDescriptorExtractorTest extends OpenCVTestCase {
     @Override
     protected void setUp() throws Exception {
         super.setUp();
-        extractor = DescriptorExtractor.create(DescriptorExtractor.BRIEF);
+        extractor = createClassInstance(XFEATURES2D+"BriefDescriptorExtractor", DEFAULT_FACTORY, null, null);
         matSize = 100;
     }
 
@@ -69,12 +68,13 @@ public class BRIEFDescriptorExtractorTest extends OpenCVTestCase {
     }
 
     public void testEmpty() {
-        assertFalse(extractor.empty());
+//        assertFalse(extractor.empty());
+        fail("Not yet implemented"); // BRIEF does not override empty() method
     }
 
     public void testRead() {
         String filename = OpenCVTestRunner.getTempFileName("yml");
-        writeFile(filename, "%YAML:1.0\ndescriptorSize: 64\n");
+        writeFile(filename, "%YAML:1.0\n---\ndescriptorSize: 64\n");
 
         extractor.read(filename);
 
@@ -95,7 +95,7 @@ public class BRIEFDescriptorExtractorTest extends OpenCVTestCase {
 
         extractor.write(filename);
 
-        String truth = "%YAML:1.0\ndescriptorSize: 32\n";
+        String truth = "%YAML:1.0\n---\ndescriptorSize: 32\n";
         assertEquals(truth, readFile(filename));
     }
 
diff --git a/modules/features2d/misc/java/test/BruteForceDescriptorMatcherTest.java b/modules/features2d/misc/java/test/BruteForceDescriptorMatcherTest.java
index a6152ee..ebdc04f 100644
--- a/modules/features2d/misc/java/test/BruteForceDescriptorMatcherTest.java
+++ b/modules/features2d/misc/java/test/BruteForceDescriptorMatcherTest.java
@@ -4,7 +4,6 @@ import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
 
-import org.opencv.core.Core;
 import org.opencv.core.CvType;
 import org.opencv.core.Mat;
 import org.opencv.core.MatOfDMatch;
@@ -12,13 +11,12 @@ import org.opencv.core.MatOfKeyPoint;
 import org.opencv.core.Point;
 import org.opencv.core.Scalar;
 import org.opencv.core.DMatch;
-import org.opencv.features2d.DescriptorExtractor;
 import org.opencv.features2d.DescriptorMatcher;
-import org.opencv.features2d.FeatureDetector;
 import org.opencv.core.KeyPoint;
 import org.opencv.test.OpenCVTestCase;
 import org.opencv.test.OpenCVTestRunner;
 import org.opencv.imgproc.Imgproc;
+import org.opencv.features2d.Feature2D;
 
 public class BruteForceDescriptorMatcherTest extends OpenCVTestCase {
 
@@ -39,12 +37,13 @@ public class BruteForceDescriptorMatcherTest extends OpenCVTestCase {
         MatOfKeyPoint keypoints = new MatOfKeyPoint();
         Mat descriptors = new Mat();
 
-        FeatureDetector detector = FeatureDetector.create(FeatureDetector.SURF);
-        DescriptorExtractor extractor = DescriptorExtractor.create(DescriptorExtractor.SURF);
+        Feature2D detector = createClassInstance(XFEATURES2D+"SURF", DEFAULT_FACTORY, null, null);
+        Feature2D extractor = createClassInstance(XFEATURES2D+"SURF", DEFAULT_FACTORY, null, null);
 
-        String filename = OpenCVTestRunner.getTempFileName("yml");
-        writeFile(filename, "%YAML:1.0\nhessianThreshold: 8000.\noctaves: 3\noctaveLayers: 4\nupright: 0\n");
-        detector.read(filename);
+        setProperty(detector, "hessianThreshold", "double", 8000);
+        setProperty(detector, "nOctaves", "int", 3);
+        setProperty(detector, "nOctaveLayers", "int", 4);
+        setProperty(detector, "upright", "boolean", false);
 
         detector.detect(img, keypoints);
         extractor.compute(img, keypoints, descriptors);
@@ -65,7 +64,7 @@ public class BruteForceDescriptorMatcherTest extends OpenCVTestCase {
         MatOfKeyPoint keypoints = new MatOfKeyPoint(new KeyPoint(50, 50, 16, 0, 20000, 1, -1), new KeyPoint(42, 42, 16, 160, 10000, 1, -1));
         Mat descriptors = new Mat();
 
-        DescriptorExtractor extractor = DescriptorExtractor.create(DescriptorExtractor.SURF);
+        Feature2D extractor = createClassInstance(XFEATURES2D+"SURF", DEFAULT_FACTORY, null, null);
 
         extractor.compute(img, keypoints, descriptors);
 
@@ -273,7 +272,7 @@ public class BruteForceDescriptorMatcherTest extends OpenCVTestCase {
 
     public void testRead() {
         String filename = OpenCVTestRunner.getTempFileName("yml");
-        writeFile(filename, "%YAML:1.0\n");
+        writeFile(filename, "%YAML:1.0\n---\n");
 
         matcher.read(filename);
         assertTrue(true);// BruteforceMatcher has no settings
@@ -288,7 +287,7 @@ public class BruteForceDescriptorMatcherTest extends OpenCVTestCase {
 
         matcher.write(filename);
 
-        String truth = "%YAML:1.0\n";
+        String truth = "%YAML:1.0\n---\n";
         assertEquals(truth, readFile(filename));
     }
 
diff --git a/modules/features2d/misc/java/test/BruteForceHammingDescriptorMatcherTest.java b/modules/features2d/misc/java/test/BruteForceHammingDescriptorMatcherTest.java
index c038f4a..6bcc3ea 100644
--- a/modules/features2d/misc/java/test/BruteForceHammingDescriptorMatcherTest.java
+++ b/modules/features2d/misc/java/test/BruteForceHammingDescriptorMatcherTest.java
@@ -4,7 +4,6 @@ import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
 
-import org.opencv.core.Core;
 import org.opencv.core.CvType;
 import org.opencv.core.Mat;
 import org.opencv.core.MatOfDMatch;
@@ -12,12 +11,12 @@ import org.opencv.core.MatOfKeyPoint;
 import org.opencv.core.Point;
 import org.opencv.core.Scalar;
 import org.opencv.core.DMatch;
-import org.opencv.features2d.DescriptorExtractor;
 import org.opencv.features2d.DescriptorMatcher;
 import org.opencv.features2d.FeatureDetector;
 import org.opencv.test.OpenCVTestCase;
 import org.opencv.test.OpenCVTestRunner;
 import org.opencv.imgproc.Imgproc;
+import org.opencv.features2d.Feature2D;
 
 public class BruteForceHammingDescriptorMatcherTest extends OpenCVTestCase {
 
@@ -48,7 +47,7 @@ public class BruteForceHammingDescriptorMatcherTest extends OpenCVTestCase {
         Mat descriptors = new Mat();
 
         FeatureDetector detector = FeatureDetector.create(FeatureDetector.FAST);
-        DescriptorExtractor extractor = DescriptorExtractor.create(DescriptorExtractor.BRIEF);
+        Feature2D extractor = createClassInstance(XFEATURES2D+"BriefDescriptorExtractor", DEFAULT_FACTORY, null, null);
 
         detector.detect(img, keypoints);
         extractor.compute(img, keypoints, descriptors);
@@ -212,7 +211,7 @@ public class BruteForceHammingDescriptorMatcherTest extends OpenCVTestCase {
 
         matcher.radiusMatch(query, train, matches, 50.f);
 
-        assertEquals(matches.size(), 4);
+        assertEquals(4, matches.size());
         assertTrue(matches.get(0).empty());
         assertMatEqual(matches.get(1), new MatOfDMatch(truth[1]), EPS);
         assertMatEqual(matches.get(2), new MatOfDMatch(truth[2]), EPS);
@@ -241,7 +240,7 @@ public class BruteForceHammingDescriptorMatcherTest extends OpenCVTestCase {
 
     public void testRead() {
         String filename = OpenCVTestRunner.getTempFileName("yml");
-        writeFile(filename, "%YAML:1.0\n");
+        writeFile(filename, "%YAML:1.0\n---\n");
 
         matcher.read(filename);
         assertTrue(true);// BruteforceMatcher has no settings
@@ -256,7 +255,7 @@ public class BruteForceHammingDescriptorMatcherTest extends OpenCVTestCase {
 
         matcher.write(filename);
 
-        String truth = "%YAML:1.0\n";
+        String truth = "%YAML:1.0\n---\n";
         assertEquals(truth, readFile(filename));
     }
 
diff --git a/modules/features2d/misc/java/test/BruteForceHammingLUTDescriptorMatcherTest.java b/modules/features2d/misc/java/test/BruteForceHammingLUTDescriptorMatcherTest.java
index 9e2ce83..67ceb0b 100644
--- a/modules/features2d/misc/java/test/BruteForceHammingLUTDescriptorMatcherTest.java
+++ b/modules/features2d/misc/java/test/BruteForceHammingLUTDescriptorMatcherTest.java
@@ -3,7 +3,6 @@ package org.opencv.test.features2d;
 import java.util.Arrays;
 import java.util.List;
 
-import org.opencv.core.Core;
 import org.opencv.core.CvType;
 import org.opencv.core.Mat;
 import org.opencv.core.MatOfDMatch;
@@ -11,12 +10,12 @@ import org.opencv.core.MatOfKeyPoint;
 import org.opencv.core.Point;
 import org.opencv.core.Scalar;
 import org.opencv.core.DMatch;
-import org.opencv.features2d.DescriptorExtractor;
 import org.opencv.features2d.DescriptorMatcher;
 import org.opencv.features2d.FeatureDetector;
 import org.opencv.test.OpenCVTestCase;
 import org.opencv.test.OpenCVTestRunner;
 import org.opencv.imgproc.Imgproc;
+import org.opencv.features2d.Feature2D;
 
 public class BruteForceHammingLUTDescriptorMatcherTest extends OpenCVTestCase {
 
@@ -47,7 +46,7 @@ public class BruteForceHammingLUTDescriptorMatcherTest extends OpenCVTestCase {
         Mat descriptors = new Mat();
 
         FeatureDetector detector = FeatureDetector.create(FeatureDetector.FAST);
-        DescriptorExtractor extractor = DescriptorExtractor.create(DescriptorExtractor.BRIEF);
+        Feature2D extractor = createClassInstance(XFEATURES2D+"BriefDescriptorExtractor", DEFAULT_FACTORY, null, null);
 
         detector.detect(img, keypoints);
         extractor.compute(img, keypoints, descriptors);
@@ -236,7 +235,7 @@ public class BruteForceHammingLUTDescriptorMatcherTest extends OpenCVTestCase {
 
     public void testRead() {
         String filename = OpenCVTestRunner.getTempFileName("yml");
-        writeFile(filename, "%YAML:1.0\n");
+        writeFile(filename, "%YAML:1.0\n---\n");
 
         matcher.read(filename);
         assertTrue(true);// BruteforceMatcher has no settings
@@ -251,7 +250,7 @@ public class BruteForceHammingLUTDescriptorMatcherTest extends OpenCVTestCase {
 
         matcher.write(filename);
 
-        String truth = "%YAML:1.0\n";
+        String truth = "%YAML:1.0\n---\n";
         assertEquals(truth, readFile(filename));
     }
 
diff --git a/modules/features2d/misc/java/test/BruteForceL1DescriptorMatcherTest.java b/modules/features2d/misc/java/test/BruteForceL1DescriptorMatcherTest.java
index e15d070..9115d40 100644
--- a/modules/features2d/misc/java/test/BruteForceL1DescriptorMatcherTest.java
+++ b/modules/features2d/misc/java/test/BruteForceL1DescriptorMatcherTest.java
@@ -3,7 +3,6 @@ package org.opencv.test.features2d;
 import java.util.Arrays;
 import java.util.List;
 
-import org.opencv.core.Core;
 import org.opencv.core.CvType;
 import org.opencv.core.Mat;
 import org.opencv.core.MatOfDMatch;
@@ -11,13 +10,12 @@ import org.opencv.core.MatOfKeyPoint;
 import org.opencv.core.Point;
 import org.opencv.core.Scalar;
 import org.opencv.core.DMatch;
-import org.opencv.features2d.DescriptorExtractor;
 import org.opencv.features2d.DescriptorMatcher;
-import org.opencv.features2d.FeatureDetector;
 import org.opencv.core.KeyPoint;
 import org.opencv.test.OpenCVTestCase;
 import org.opencv.test.OpenCVTestRunner;
 import org.opencv.imgproc.Imgproc;
+import org.opencv.features2d.Feature2D;
 
 public class BruteForceL1DescriptorMatcherTest extends OpenCVTestCase {
 
@@ -38,13 +36,14 @@ public class BruteForceL1DescriptorMatcherTest extends OpenCVTestCase {
         MatOfKeyPoint keypoints = new MatOfKeyPoint();
         Mat descriptors = new Mat();
 
-        FeatureDetector detector = FeatureDetector.create(FeatureDetector.SURF);
-        DescriptorExtractor extractor = DescriptorExtractor.create(DescriptorExtractor.SURF);
+        Feature2D detector = createClassInstance(XFEATURES2D+"SURF", DEFAULT_FACTORY, null, null);
+        Feature2D extractor = createClassInstance(XFEATURES2D+"SURF", DEFAULT_FACTORY, null, null);
 
-        String filename = OpenCVTestRunner.getTempFileName("yml");
-        //writeFile(filename, "%YAML:1.0\nhessianThreshold: 8000.\noctaves: 3\noctaveLayers: 4\nupright: 0\n");
-        writeFile(filename, "%YAML:1.0\nname: \"Feature2D.SURF\"\nextended: 1\nhessianThreshold: 8000.\nnOctaveLayers: 2\nnOctaves: 3\nupright: 0\n");
-        detector.read(filename);
+        setProperty(detector, "extended", "boolean", true);
+        setProperty(detector, "hessianThreshold", "double", 8000);
+        setProperty(detector, "nOctaveLayers", "int", 2);
+        setProperty(detector, "nOctaves", "int", 3);
+        setProperty(detector, "upright", "boolean", false);
 
         detector.detect(img, keypoints);
         extractor.compute(img, keypoints, descriptors);
@@ -65,7 +64,7 @@ public class BruteForceL1DescriptorMatcherTest extends OpenCVTestCase {
         MatOfKeyPoint keypoints = new MatOfKeyPoint(new KeyPoint(50, 50, 16, 0, 20000, 1, -1), new KeyPoint(42, 42, 16, 160, 10000, 1, -1));
         Mat descriptors = new Mat();
 
-        DescriptorExtractor extractor = DescriptorExtractor.create(DescriptorExtractor.SURF);
+        Feature2D extractor = createClassInstance(XFEATURES2D+"SURF", DEFAULT_FACTORY, null, null);
 
         extractor.compute(img, keypoints, descriptors);
 
@@ -247,7 +246,7 @@ public class BruteForceL1DescriptorMatcherTest extends OpenCVTestCase {
 
     public void testRead() {
         String filename = OpenCVTestRunner.getTempFileName("yml");
-        writeFile(filename, "%YAML:1.0\n");
+        writeFile(filename, "%YAML:1.0\n---\n");
 
         matcher.read(filename);
         assertTrue(true);// BruteforceMatcher has no settings
@@ -262,7 +261,7 @@ public class BruteForceL1DescriptorMatcherTest extends OpenCVTestCase {
 
         matcher.write(filename);
 
-        String truth = "%YAML:1.0\n";
+        String truth = "%YAML:1.0\n---\n";
         assertEquals(truth, readFile(filename));
     }
 
diff --git a/modules/features2d/misc/java/test/BruteForceSL2DescriptorMatcherTest.java b/modules/features2d/misc/java/test/BruteForceSL2DescriptorMatcherTest.java
index 9074676..ec87dfa 100644
--- a/modules/features2d/misc/java/test/BruteForceSL2DescriptorMatcherTest.java
+++ b/modules/features2d/misc/java/test/BruteForceSL2DescriptorMatcherTest.java
@@ -3,7 +3,6 @@ package org.opencv.test.features2d;
 import java.util.Arrays;
 import java.util.List;
 
-import org.opencv.core.Core;
 import org.opencv.core.CvType;
 import org.opencv.core.Mat;
 import org.opencv.core.MatOfDMatch;
@@ -11,13 +10,12 @@ import org.opencv.core.MatOfKeyPoint;
 import org.opencv.core.Point;
 import org.opencv.core.Scalar;
 import org.opencv.core.DMatch;
-import org.opencv.features2d.DescriptorExtractor;
 import org.opencv.features2d.DescriptorMatcher;
-import org.opencv.features2d.FeatureDetector;
 import org.opencv.core.KeyPoint;
 import org.opencv.test.OpenCVTestCase;
 import org.opencv.test.OpenCVTestRunner;
 import org.opencv.imgproc.Imgproc;
+import org.opencv.features2d.Feature2D;
 
 public class BruteForceSL2DescriptorMatcherTest extends OpenCVTestCase {
 
@@ -44,12 +42,13 @@ public class BruteForceSL2DescriptorMatcherTest extends OpenCVTestCase {
         MatOfKeyPoint keypoints = new MatOfKeyPoint();
         Mat descriptors = new Mat();
 
-        FeatureDetector detector = FeatureDetector.create(FeatureDetector.SURF);
-        DescriptorExtractor extractor = DescriptorExtractor.create(DescriptorExtractor.SURF);
+        Feature2D detector = createClassInstance(XFEATURES2D+"SURF", DEFAULT_FACTORY, null, null);
+        Feature2D extractor = createClassInstance(XFEATURES2D+"SURF", DEFAULT_FACTORY, null, null);
 
-        String filename = OpenCVTestRunner.getTempFileName("yml");
-        writeFile(filename, "%YAML:1.0\nhessianThreshold: 8000.\noctaves: 3\noctaveLayers: 4\nupright: 0\n");
-        detector.read(filename);
+        setProperty(detector, "hessianThreshold", "double", 8000);
+        setProperty(detector, "nOctaves", "int", 3);
+        setProperty(detector, "nOctaveLayers", "int", 4);
+        setProperty(detector, "upright", "boolean", false);
 
         detector.detect(img, keypoints);
         extractor.compute(img, keypoints, descriptors);
@@ -70,7 +69,7 @@ public class BruteForceSL2DescriptorMatcherTest extends OpenCVTestCase {
         MatOfKeyPoint keypoints = new MatOfKeyPoint(new KeyPoint(50, 50, 16, 0, 20000, 1, -1), new KeyPoint(42, 42, 16, 160, 10000, 1, -1));
         Mat descriptors = new Mat();
 
-        DescriptorExtractor extractor = DescriptorExtractor.create(DescriptorExtractor.SURF);
+        Feature2D extractor = createClassInstance(XFEATURES2D+"SURF", DEFAULT_FACTORY, null, null);
 
         extractor.compute(img, keypoints, descriptors);
 
@@ -259,7 +258,7 @@ public class BruteForceSL2DescriptorMatcherTest extends OpenCVTestCase {
 
     public void testRead() {
         String filename = OpenCVTestRunner.getTempFileName("yml");
-        writeFile(filename, "%YAML:1.0\n");
+        writeFile(filename, "%YAML:1.0\n---\n");
 
         matcher.read(filename);
         assertTrue(true);// BruteforceMatcher has no settings
@@ -274,7 +273,7 @@ public class BruteForceSL2DescriptorMatcherTest extends OpenCVTestCase {
 
         matcher.write(filename);
 
-        String truth = "%YAML:1.0\n";
+        String truth = "%YAML:1.0\n---\n";
         assertEquals(truth, readFile(filename));
     }
 
diff --git a/modules/features2d/misc/java/test/DynamicDENSEFeatureDetectorTest.java b/modules/features2d/misc/java/test/DynamicDENSEFeatureDetectorTest.java
deleted file mode 100644
index 75042ab..0000000
--- a/modules/features2d/misc/java/test/DynamicDENSEFeatureDetectorTest.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package org.opencv.test.features2d;
-
-import org.opencv.test.OpenCVTestCase;
-
-public class DynamicDENSEFeatureDetectorTest extends OpenCVTestCase {
-
-    public void testCreate() {
-        fail("Not yet implemented");
-    }
-
-    public void testDetectListOfMatListOfListOfKeyPoint() {
-        fail("Not yet implemented");
-    }
-
-    public void testDetectListOfMatListOfListOfKeyPointListOfMat() {
-        fail("Not yet implemented");
-    }
-
-    public void testDetectMatListOfKeyPoint() {
-        fail("Not yet implemented");
-    }
-
-    public void testDetectMatListOfKeyPointMat() {
-        fail("Not yet implemented");
-    }
-
-    public void testEmpty() {
-        fail("Not yet implemented");
-    }
-
-    public void testRead() {
-        fail("Not yet implemented");
-    }
-
-    public void testWrite() {
-        fail("Not yet implemented");
-    }
-
-}
diff --git a/modules/features2d/misc/java/test/DynamicFASTFeatureDetectorTest.java b/modules/features2d/misc/java/test/DynamicFASTFeatureDetectorTest.java
deleted file mode 100644
index 5313e27..0000000
--- a/modules/features2d/misc/java/test/DynamicFASTFeatureDetectorTest.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package org.opencv.test.features2d;
-
-import org.opencv.test.OpenCVTestCase;
-
-public class DynamicFASTFeatureDetectorTest extends OpenCVTestCase {
-
-    public void testCreate() {
-        fail("Not yet implemented");
-    }
-
-    public void testDetectListOfMatListOfListOfKeyPoint() {
-        fail("Not yet implemented");
-    }
-
-    public void testDetectListOfMatListOfListOfKeyPointListOfMat() {
-        fail("Not yet implemented");
-    }
-
-    public void testDetectMatListOfKeyPoint() {
-        fail("Not yet implemented");
-    }
-
-    public void testDetectMatListOfKeyPointMat() {
-        fail("Not yet implemented");
-    }
-
-    public void testEmpty() {
-        fail("Not yet implemented");
-    }
-
-    public void testRead() {
-        fail("Not yet implemented");
-    }
-
-    public void testWrite() {
-        fail("Not yet implemented");
-    }
-
-}
diff --git a/modules/features2d/misc/java/test/DynamicGFTTFeatureDetectorTest.java b/modules/features2d/misc/java/test/DynamicGFTTFeatureDetectorTest.java
deleted file mode 100644
index d2410f0..0000000
--- a/modules/features2d/misc/java/test/DynamicGFTTFeatureDetectorTest.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package org.opencv.test.features2d;
-
-import org.opencv.test.OpenCVTestCase;
-
-public class DynamicGFTTFeatureDetectorTest extends OpenCVTestCase {
-
-    public void testCreate() {
-        fail("Not yet implemented");
-    }
-
-    public void testDetectListOfMatListOfListOfKeyPoint() {
-        fail("Not yet implemented");
-    }
-
-    public void testDetectListOfMatListOfListOfKeyPointListOfMat() {
-        fail("Not yet implemented");
-    }
-
-    public void testDetectMatListOfKeyPoint() {
-        fail("Not yet implemented");
-    }
-
-    public void testDetectMatListOfKeyPointMat() {
-        fail("Not yet implemented");
-    }
-
-    public void testEmpty() {
-        fail("Not yet implemented");
-    }
-
-    public void testRead() {
-        fail("Not yet implemented");
-    }
-
-    public void testWrite() {
-        fail("Not yet implemented");
-    }
-
-}
diff --git a/modules/features2d/misc/java/test/DynamicHARRISFeatureDetectorTest.java b/modules/features2d/misc/java/test/DynamicHARRISFeatureDetectorTest.java
deleted file mode 100644
index c1162c6..0000000
--- a/modules/features2d/misc/java/test/DynamicHARRISFeatureDetectorTest.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package org.opencv.test.features2d;
-
-import org.opencv.test.OpenCVTestCase;
-
-public class DynamicHARRISFeatureDetectorTest extends OpenCVTestCase {
-
-    public void testCreate() {
-        fail("Not yet implemented");
-    }
-
-    public void testDetectListOfMatListOfListOfKeyPoint() {
-        fail("Not yet implemented");
-    }
-
-    public void testDetectListOfMatListOfListOfKeyPointListOfMat() {
-        fail("Not yet implemented");
-    }
-
-    public void testDetectMatListOfKeyPoint() {
-        fail("Not yet implemented");
-    }
-
-    public void testDetectMatListOfKeyPointMat() {
-        fail("Not yet implemented");
-    }
-
-    public void testEmpty() {
-        fail("Not yet implemented");
-    }
-
-    public void testRead() {
-        fail("Not yet implemented");
-    }
-
-    public void testWrite() {
-        fail("Not yet implemented");
-    }
-
-}
diff --git a/modules/features2d/misc/java/test/DynamicMSERFeatureDetectorTest.java b/modules/features2d/misc/java/test/DynamicMSERFeatureDetectorTest.java
deleted file mode 100644
index a3dd244..0000000
--- a/modules/features2d/misc/java/test/DynamicMSERFeatureDetectorTest.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package org.opencv.test.features2d;
-
-import org.opencv.test.OpenCVTestCase;
-
-public class DynamicMSERFeatureDetectorTest extends OpenCVTestCase {
-
-    public void testCreate() {
-        fail("Not yet implemented");
-    }
-
-    public void testDetectListOfMatListOfListOfKeyPoint() {
-        fail("Not yet implemented");
-    }
-
-    public void testDetectListOfMatListOfListOfKeyPointListOfMat() {
-        fail("Not yet implemented");
-    }
-
-    public void testDetectMatListOfKeyPoint() {
-        fail("Not yet implemented");
-    }
-
-    public void testDetectMatListOfKeyPointMat() {
-        fail("Not yet implemented");
-    }
-
-    public void testEmpty() {
-        fail("Not yet implemented");
-    }
-
-    public void testRead() {
-        fail("Not yet implemented");
-    }
-
-    public void testWrite() {
-        fail("Not yet implemented");
-    }
-
-}
diff --git a/modules/features2d/misc/java/test/DynamicORBFeatureDetectorTest.java b/modules/features2d/misc/java/test/DynamicORBFeatureDetectorTest.java
deleted file mode 100644
index 69889bc..0000000
--- a/modules/features2d/misc/java/test/DynamicORBFeatureDetectorTest.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package org.opencv.test.features2d;
-
-import org.opencv.test.OpenCVTestCase;
-
-public class DynamicORBFeatureDetectorTest extends OpenCVTestCase {
-
-    public void testCreate() {
-        fail("Not yet implemented");
-    }
-
-    public void testDetectListOfMatListOfListOfKeyPoint() {
-        fail("Not yet implemented");
-    }
-
-    public void testDetectListOfMatListOfListOfKeyPointListOfMat() {
-        fail("Not yet implemented");
-    }
-
-    public void testDetectMatListOfKeyPoint() {
-        fail("Not yet implemented");
-    }
-
-    public void testDetectMatListOfKeyPointMat() {
-        fail("Not yet implemented");
-    }
-
-    public void testEmpty() {
-        fail("Not yet implemented");
-    }
-
-    public void testRead() {
-        fail("Not yet implemented");
-    }
-
-    public void testWrite() {
-        fail("Not yet implemented");
-    }
-
-}
diff --git a/modules/features2d/misc/java/test/DynamicSIFTFeatureDetectorTest.java b/modules/features2d/misc/java/test/DynamicSIFTFeatureDetectorTest.java
deleted file mode 100644
index 6152c1c..0000000
--- a/modules/features2d/misc/java/test/DynamicSIFTFeatureDetectorTest.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package org.opencv.test.features2d;
-
-import org.opencv.test.OpenCVTestCase;
-
-public class DynamicSIFTFeatureDetectorTest extends OpenCVTestCase {
-
-    public void testCreate() {
-        fail("Not yet implemented");
-    }
-
-    public void testDetectListOfMatListOfListOfKeyPoint() {
-        fail("Not yet implemented");
-    }
-
-    public void testDetectListOfMatListOfListOfKeyPointListOfMat() {
-        fail("Not yet implemented");
-    }
-
-    public void testDetectMatListOfKeyPoint() {
-        fail("Not yet implemented");
-    }
-
-    public void testDetectMatListOfKeyPointMat() {
-        fail("Not yet implemented");
-    }
-
-    public void testEmpty() {
-        fail("Not yet implemented");
-    }
-
-    public void testRead() {
-        fail("Not yet implemented");
-    }
-
-    public void testWrite() {
-        fail("Not yet implemented");
-    }
-
-}
diff --git a/modules/features2d/misc/java/test/DynamicSIMPLEBLOBFeatureDetectorTest.java b/modules/features2d/misc/java/test/DynamicSIMPLEBLOBFeatureDetectorTest.java
deleted file mode 100644
index 57c46b1..0000000
--- a/modules/features2d/misc/java/test/DynamicSIMPLEBLOBFeatureDetectorTest.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package org.opencv.test.features2d;
-
-import org.opencv.test.OpenCVTestCase;
-
-public class DynamicSIMPLEBLOBFeatureDetectorTest extends OpenCVTestCase {
-
-    public void testCreate() {
-        fail("Not yet implemented");
-    }
-
-    public void testDetectListOfMatListOfListOfKeyPoint() {
-        fail("Not yet implemented");
-    }
-
-    public void testDetectListOfMatListOfListOfKeyPointListOfMat() {
-        fail("Not yet implemented");
-    }
-
-    public void testDetectMatListOfKeyPoint() {
-        fail("Not yet implemented");
-    }
-
-    public void testDetectMatListOfKeyPointMat() {
-        fail("Not yet implemented");
-    }
-
-    public void testEmpty() {
-        fail("Not yet implemented");
-    }
-
-    public void testRead() {
-        fail("Not yet implemented");
-    }
-
-    public void testWrite() {
-        fail("Not yet implemented");
-    }
-
-}
diff --git a/modules/features2d/misc/java/test/DynamicSTARFeatureDetectorTest.java b/modules/features2d/misc/java/test/DynamicSTARFeatureDetectorTest.java
deleted file mode 100644
index 6ca04fe..0000000
--- a/modules/features2d/misc/java/test/DynamicSTARFeatureDetectorTest.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package org.opencv.test.features2d;
-
-import org.opencv.test.OpenCVTestCase;
-
-public class DynamicSTARFeatureDetectorTest extends OpenCVTestCase {
-
-    public void testCreate() {
-        fail("Not yet implemented");
-    }
-
-    public void testDetectListOfMatListOfListOfKeyPoint() {
-        fail("Not yet implemented");
-    }
-
-    public void testDetectListOfMatListOfListOfKeyPointListOfMat() {
-        fail("Not yet implemented");
-    }
-
-    public void testDetectMatListOfKeyPoint() {
-        fail("Not yet implemented");
-    }
-
-    public void testDetectMatListOfKeyPointMat() {
-        fail("Not yet implemented");
-    }
-
-    public void testEmpty() {
-        fail("Not yet implemented");
-    }
-
-    public void testRead() {
-        fail("Not yet implemented");
-    }
-
-    public void testWrite() {
-        fail("Not yet implemented");
-    }
-
-}
diff --git a/modules/features2d/misc/java/test/DynamicSURFFeatureDetectorTest.java b/modules/features2d/misc/java/test/DynamicSURFFeatureDetectorTest.java
deleted file mode 100644
index e3f4c66..0000000
--- a/modules/features2d/misc/java/test/DynamicSURFFeatureDetectorTest.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package org.opencv.test.features2d;
-
-import org.opencv.test.OpenCVTestCase;
-
-public class DynamicSURFFeatureDetectorTest extends OpenCVTestCase {
-
-    public void testCreate() {
-        fail("Not yet implemented");
-    }
-
-    public void testDetectListOfMatListOfListOfKeyPoint() {
-        fail("Not yet implemented");
-    }
-
-    public void testDetectListOfMatListOfListOfKeyPointListOfMat() {
-        fail("Not yet implemented");
-    }
-
-    public void testDetectMatListOfKeyPoint() {
-        fail("Not yet implemented");
-    }
-
-    public void testDetectMatListOfKeyPointMat() {
-        fail("Not yet implemented");
-    }
-
-    public void testEmpty() {
-        fail("Not yet implemented");
-    }
-
-    public void testRead() {
-        fail("Not yet implemented");
-    }
-
-    public void testWrite() {
-        fail("Not yet implemented");
-    }
-
-}
diff --git a/modules/features2d/misc/java/test/FASTFeatureDetectorTest.java b/modules/features2d/misc/java/test/FASTFeatureDetectorTest.java
index 0afe7eb..091f4a7 100644
--- a/modules/features2d/misc/java/test/FASTFeatureDetectorTest.java
+++ b/modules/features2d/misc/java/test/FASTFeatureDetectorTest.java
@@ -76,20 +76,21 @@ public class FASTFeatureDetectorTest extends OpenCVTestCase {
     }
 
     public void testEmpty() {
-        assertFalse(detector.empty());
+//        assertFalse(detector.empty());
+        fail("Not yet implemented"); //FAST does not override empty() method
     }
 
     public void testRead() {
         String filename = OpenCVTestRunner.getTempFileName("yml");
 
-        writeFile(filename, "%YAML:1.0\nthreshold: 130\nnonmaxSuppression: 1\n");
+        writeFile(filename, "%YAML:1.0\n---\nthreshold: 130\nnonmaxSuppression: 1\n");
         detector.read(filename);
 
         MatOfKeyPoint keypoints1 = new MatOfKeyPoint();
 
         detector.detect(grayChess, keypoints1);
 
-        writeFile(filename, "%YAML:1.0\nthreshold: 150\nnonmaxSuppression: 1\n");
+        writeFile(filename, "%YAML:1.0\n---\nthreshold: 150\nnonmaxSuppression: 1\n");
         detector.read(filename);
 
         MatOfKeyPoint keypoints2 = new MatOfKeyPoint();
@@ -126,7 +127,8 @@ public class FASTFeatureDetectorTest extends OpenCVTestCase {
 
         detector.write(filename);
 
-        String truth = "<?xml version=\"1.0\"?>\n<opencv_storage>\n<name>Feature2D.FAST</name>\n<nonmaxSuppression>1</nonmaxSuppression>\n<threshold>10</threshold>\n<type>2</type>\n</opencv_storage>\n";
+//        String truth = "<?xml version=\"1.0\"?>\n<opencv_storage>\n<name>Feature2D.FAST</name>\n<nonmaxSuppression>1</nonmaxSuppression>\n<threshold>10</threshold>\n<type>2</type>\n</opencv_storage>\n";
+        String truth = "<?xml version=\"1.0\"?>\n<opencv_storage>\n</opencv_storage>\n";
         String data = readFile(filename);
         //Log.d("qqq", "\"" + data + "\"");
         assertEquals(truth, data);
@@ -137,7 +139,8 @@ public class FASTFeatureDetectorTest extends OpenCVTestCase {
 
         detector.write(filename);
 
-        String truth = "%YAML:1.0\nname: \"Feature2D.FAST\"\nnonmaxSuppression: 1\nthreshold: 10\ntype: 2\n";
+//        String truth = "%YAML:1.0\n---\nname: \"Feature2D.FAST\"\nnonmaxSuppression: 1\nthreshold: 10\ntype: 2\n";
+        String truth = "%YAML:1.0\n---\n";
         String data = readFile(filename);
 
         //Log.d("qqq", "\"" + data + "\"");
diff --git a/modules/features2d/misc/java/test/Features2dTest.java b/modules/features2d/misc/java/test/Features2dTest.java
index b9e8983..20bfd75 100644
--- a/modules/features2d/misc/java/test/Features2dTest.java
+++ b/modules/features2d/misc/java/test/Features2dTest.java
@@ -13,14 +13,13 @@ import org.opencv.core.MatOfPoint2f;
 import org.opencv.core.Point;
 import org.opencv.core.Range;
 import org.opencv.core.DMatch;
-import org.opencv.features2d.DescriptorExtractor;
 import org.opencv.features2d.DescriptorMatcher;
-import org.opencv.features2d.FeatureDetector;
 import org.opencv.features2d.Features2d;
 import org.opencv.core.KeyPoint;
 import org.opencv.imgcodecs.Imgcodecs;
 import org.opencv.test.OpenCVTestCase;
 import org.opencv.test.OpenCVTestRunner;
+import org.opencv.features2d.Feature2D;
 
 public class Features2dTest extends OpenCVTestCase {
 
@@ -78,11 +77,11 @@ public class Features2dTest extends OpenCVTestCase {
 
     public void testPTOD()
     {
-        String detectorCfg = "%YAML:1.0\nhessianThreshold: 4000.\noctaves: 3\noctaveLayers: 4\nupright: 0\n";
-        String extractorCfg = "%YAML:1.0\nnOctaves: 4\nnOctaveLayers: 2\nextended: 0\nupright: 0\n";
+        String detectorCfg = "%YAML:1.0\n---\nhessianThreshold: 4000.\noctaves: 3\noctaveLayers: 4\nupright: 0\n";
+        String extractorCfg = "%YAML:1.0\n---\nnOctaves: 4\nnOctaveLayers: 2\nextended: 0\nupright: 0\n";
 
-        FeatureDetector detector = FeatureDetector.create(FeatureDetector.SURF);
-        DescriptorExtractor extractor = DescriptorExtractor.create(DescriptorExtractor.SURF);
+        Feature2D detector = createClassInstance(XFEATURES2D+"SURF", DEFAULT_FACTORY, null, null);
+        Feature2D extractor = createClassInstance(XFEATURES2D+"SURF", DEFAULT_FACTORY, null, null);
         DescriptorMatcher matcher = DescriptorMatcher.create(DescriptorMatcher.BRUTEFORCE);
 
         String detectorCfgFile = OpenCVTestRunner.getTempFileName("yml");
diff --git a/modules/features2d/misc/java/test/FernGenericDescriptorMatcherTest.java b/modules/features2d/misc/java/test/FernGenericDescriptorMatcherTest.java
deleted file mode 100644
index 841abb5..0000000
--- a/modules/features2d/misc/java/test/FernGenericDescriptorMatcherTest.java
+++ /dev/null
@@ -1,127 +0,0 @@
-package org.opencv.test.features2d;
-
-import org.opencv.test.OpenCVTestCase;
-
-public class FernGenericDescriptorMatcherTest extends OpenCVTestCase {
-
-    public void testAdd() {
-        fail("Not yet implemented");
-    }
-
-    public void testClassifyMatListOfKeyPointMatListOfKeyPoint() {
-        fail("Not yet implemented");
-    }
-
-    public void testClassifyMatListOfKeyPoint() {
-        fail("Not yet implemented");
-    }
-
-    public void testClear() {
-        fail("Not yet implemented");
-    }
-
-    public void testCloneBoolean() {
-        fail("Not yet implemented");
-    }
-
-    public void testClone() {
-        fail("Not yet implemented");
-    }
-
-    public void testCreate() {
-        fail("Not yet implemented");
-    }
-
-    public void testEmpty() {
-        fail("Not yet implemented");
-    }
-
-    public void testGetTrainImages() {
-        fail("Not yet implemented");
-    }
-
-    public void testGetTrainKeypoints() {
-        fail("Not yet implemented");
-    }
-
-    public void testIsMaskSupported() {
-        fail("Not yet implemented");
-    }
-
-    public void testKnnMatchMatListOfKeyPointMatListOfKeyPointListOfListOfDMatchIntMatBoolean() {
-        fail("Not yet implemented");
-    }
-
-    public void testKnnMatchMatListOfKeyPointMatListOfKeyPointListOfListOfDMatchIntMat() {
-        fail("Not yet implemented");
-    }
-
-    public void testKnnMatchMatListOfKeyPointMatListOfKeyPointListOfListOfDMatchInt() {
-        fail("Not yet implemented");
-    }
-
-    public void testKnnMatchMatListOfKeyPointListOfListOfDMatchIntListOfMatBoolean() {
-        fail("Not yet implemented");
-    }
-
-    public void testKnnMatchMatListOfKeyPointListOfListOfDMatchIntListOfMat() {
-        fail("Not yet implemented");
-    }
-
-    public void testKnnMatchMatListOfKeyPointListOfListOfDMatchInt() {
-        fail("Not yet implemented");
-    }
-
-    public void testMatchMatListOfKeyPointMatListOfKeyPointListOfDMatchMat() {
-        fail("Not yet implemented");
-    }
-
-    public void testMatchMatListOfKeyPointMatListOfKeyPointListOfDMatch() {
-        fail("Not yet implemented");
-    }
-
-    public void testMatchMatListOfKeyPointListOfDMatchListOfMat() {
-        fail("Not yet implemented");
-    }
-
-    public void testMatchMatListOfKeyPointListOfDMatch() {
-        fail("Not yet implemented");
-    }
-
-    public void testRadiusMatchMatListOfKeyPointMatListOfKeyPointListOfListOfDMatchFloatMatBoolean() {
-        fail("Not yet implemented");
-    }
-
-    public void testRadiusMatchMatListOfKeyPointMatListOfKeyPointListOfListOfDMatchFloatMat() {
-        fail("Not yet implemented");
-    }
-
-    public void testRadiusMatchMatListOfKeyPointMatListOfKeyPointListOfListOfDMatchFloat() {
-        fail("Not yet implemented");
-    }
-
-    public void testRadiusMatchMatListOfKeyPointListOfListOfDMatchFloatListOfMatBoolean() {
-        fail("Not yet implemented");
-    }
-
-    public void testRadiusMatchMatListOfKeyPointListOfListOfDMatchFloatListOfMat() {
-        fail("Not yet implemented");
-    }
-
-    public void testRadiusMatchMatListOfKeyPointListOfListOfDMatchFloat() {
-        fail("Not yet implemented");
-    }
-
-    public void testRead() {
-        fail("Not yet implemented");
-    }
-
-    public void testTrain() {
-        fail("Not yet implemented");
-    }
-
-    public void testWrite() {
-        fail("Not yet implemented");
-    }
-
-}
diff --git a/modules/features2d/misc/java/test/FlannBasedDescriptorMatcherTest.java b/modules/features2d/misc/java/test/FlannBasedDescriptorMatcherTest.java
index 3bdfa89..2385246 100644
--- a/modules/features2d/misc/java/test/FlannBasedDescriptorMatcherTest.java
+++ b/modules/features2d/misc/java/test/FlannBasedDescriptorMatcherTest.java
@@ -3,7 +3,6 @@ package org.opencv.test.features2d;
 import java.util.Arrays;
 import java.util.List;
 
-import org.opencv.core.Core;
 import org.opencv.core.CvException;
 import org.opencv.core.CvType;
 import org.opencv.core.Mat;
@@ -12,18 +11,18 @@ import org.opencv.core.MatOfKeyPoint;
 import org.opencv.core.Point;
 import org.opencv.core.Scalar;
 import org.opencv.core.DMatch;
-import org.opencv.features2d.DescriptorExtractor;
 import org.opencv.features2d.DescriptorMatcher;
-import org.opencv.features2d.FeatureDetector;
 import org.opencv.core.KeyPoint;
 import org.opencv.test.OpenCVTestCase;
 import org.opencv.test.OpenCVTestRunner;
 import org.opencv.imgproc.Imgproc;
+import org.opencv.features2d.Feature2D;
 
 public class FlannBasedDescriptorMatcherTest extends OpenCVTestCase {
 
     static final String xmlParamsDefault = "<?xml version=\"1.0\"?>\n"
             + "<opencv_storage>\n"
+            + "<format>3</format>\n"
             + "<indexParams>\n"
             + "  <_>\n"
             + "    <name>algorithm</name>\n"
@@ -47,7 +46,8 @@ public class FlannBasedDescriptorMatcherTest extends OpenCVTestCase {
             + "    <type>15</type>\n"
             + "    <value>1</value></_></searchParams>\n"
             + "</opencv_storage>\n";
-    static final String ymlParamsDefault = "%YAML:1.0\n"
+    static final String ymlParamsDefault = "%YAML:1.0\n---\n"
+            + "format: 3\n"
             + "indexParams:\n"
             + "   -\n"
             + "      name: algorithm\n"
@@ -70,7 +70,8 @@ public class FlannBasedDescriptorMatcherTest extends OpenCVTestCase {
             + "      name: sorted\n"
             + "      type: 15\n"
             + "      value: 1\n";
-    static final String ymlParamsModified = "%YAML:1.0\n"
+    static final String ymlParamsModified = "%YAML:1.0\n---\n"
+            + "format: 3\n"
             + "indexParams:\n"
             + "   -\n"
             + "      name: algorithm\n"
@@ -113,12 +114,12 @@ public class FlannBasedDescriptorMatcherTest extends OpenCVTestCase {
         MatOfKeyPoint keypoints = new MatOfKeyPoint();
         Mat descriptors = new Mat();
 
-        FeatureDetector detector = FeatureDetector.create(FeatureDetector.SURF);
-        DescriptorExtractor extractor = DescriptorExtractor.create(DescriptorExtractor.SURF);
+        Feature2D detector = createClassInstance(XFEATURES2D+"SURF", DEFAULT_FACTORY, null, null);
+        Feature2D extractor = createClassInstance(XFEATURES2D+"SURF", DEFAULT_FACTORY, null, null);
 
-        String filename = OpenCVTestRunner.getTempFileName("yml");
-        writeFile(filename, "%YAML:1.0\nhessianThreshold: 8000.\noctaves: 3\noctaveLayers: 4\nupright: 0\n");
-        detector.read(filename);
+        setProperty(detector, "hessianThreshold", "double", 8000);
+        setProperty(detector, "nOctaves", "int", 3);
+        setProperty(detector, "upright", "boolean", false);
 
         detector.detect(img, keypoints);
         extractor.compute(img, keypoints, descriptors);
@@ -139,7 +140,7 @@ public class FlannBasedDescriptorMatcherTest extends OpenCVTestCase {
         MatOfKeyPoint keypoints = new MatOfKeyPoint(new KeyPoint(50, 50, 16, 0, 20000, 1, -1), new KeyPoint(42, 42, 16, 160, 10000, 1, -1));
         Mat descriptors = new Mat();
 
-        DescriptorExtractor extractor = DescriptorExtractor.create(DescriptorExtractor.SURF);
+        Feature2D extractor = createClassInstance(XFEATURES2D+"SURF", DEFAULT_FACTORY, null, null);
 
         extractor.compute(img, keypoints, descriptors);
 
diff --git a/modules/features2d/misc/java/test/GridDENSEFeatureDetectorTest.java b/modules/features2d/misc/java/test/GridDENSEFeatureDetectorTest.java
deleted file mode 100644
index 8f68e4a..0000000
--- a/modules/features2d/misc/java/test/GridDENSEFeatureDetectorTest.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package org.opencv.test.features2d;
-
-import org.opencv.test.OpenCVTestCase;
-
-public class GridDENSEFeatureDetectorTest extends OpenCVTestCase {
-
-    public void testCreate() {
-        fail("Not yet implemented");
-    }
-
-    public void testDetectListOfMatListOfListOfKeyPoint() {
-        fail("Not yet implemented");
-    }
-
-    public void testDetectListOfMatListOfListOfKeyPointListOfMat() {
-        fail("Not yet implemented");
-    }
-
-    public void testDetectMatListOfKeyPoint() {
-        fail("Not yet implemented");
-    }
-
-    public void testDetectMatListOfKeyPointMat() {
-        fail("Not yet implemented");
-    }
-
-    public void testEmpty() {
-        fail("Not yet implemented");
-    }
-
-    public void testRead() {
-        fail("Not yet implemented");
-    }
-
-    public void testWrite() {
-        fail("Not yet implemented");
-    }
-
-}
diff --git a/modules/features2d/misc/java/test/GridFASTFeatureDetectorTest.java b/modules/features2d/misc/java/test/GridFASTFeatureDetectorTest.java
deleted file mode 100644
index c72601a..0000000
--- a/modules/features2d/misc/java/test/GridFASTFeatureDetectorTest.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package org.opencv.test.features2d;
-
-import org.opencv.test.OpenCVTestCase;
-
-public class GridFASTFeatureDetectorTest extends OpenCVTestCase {
-
-    public void testCreate() {
-        fail("Not yet implemented");
-    }
-
-    public void testDetectListOfMatListOfListOfKeyPoint() {
-        fail("Not yet implemented");
-    }
-
-    public void testDetectListOfMatListOfListOfKeyPointListOfMat() {
-        fail("Not yet implemented");
-    }
-
-    public void testDetectMatListOfKeyPoint() {
-        fail("Not yet implemented");
-    }
-
-    public void testDetectMatListOfKeyPointMat() {
-        fail("Not yet implemented");
-    }
-
-    public void testEmpty() {
-        fail("Not yet implemented");
-    }
-
-    public void testRead() {
-        fail("Not yet implemented");
-    }
-
-    public void testWrite() {
-        fail("Not yet implemented");
-    }
-
-}
diff --git a/modules/features2d/misc/java/test/GridGFTTFeatureDetectorTest.java b/modules/features2d/misc/java/test/GridGFTTFeatureDetectorTest.java
deleted file mode 100644
index 828e639..0000000
--- a/modules/features2d/misc/java/test/GridGFTTFeatureDetectorTest.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package org.opencv.test.features2d;
-
-import org.opencv.test.OpenCVTestCase;
-
-public class GridGFTTFeatureDetectorTest extends OpenCVTestCase {
-
-    public void testCreate() {
-        fail("Not yet implemented");
-    }
-
-    public void testDetectListOfMatListOfListOfKeyPoint() {
-        fail("Not yet implemented");
-    }
-
-    public void testDetectListOfMatListOfListOfKeyPointListOfMat() {
-        fail("Not yet implemented");
-    }
-
-    public void testDetectMatListOfKeyPoint() {
-        fail("Not yet implemented");
-    }
-
-    public void testDetectMatListOfKeyPointMat() {
-        fail("Not yet implemented");
-    }
-
-    public void testEmpty() {
-        fail("Not yet implemented");
-    }
-
-    public void testRead() {
-        fail("Not yet implemented");
-    }
-
-    public void testWrite() {
-        fail("Not yet implemented");
-    }
-
-}
diff --git a/modules/features2d/misc/java/test/GridHARRISFeatureDetectorTest.java b/modules/features2d/misc/java/test/GridHARRISFeatureDetectorTest.java
deleted file mode 100644
index 0e84cca..0000000
--- a/modules/features2d/misc/java/test/GridHARRISFeatureDetectorTest.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package org.opencv.test.features2d;
-
-import org.opencv.test.OpenCVTestCase;
-
-public class GridHARRISFeatureDetectorTest extends OpenCVTestCase {
-
-    public void testCreate() {
-        fail("Not yet implemented");
-    }
-
-    public void testDetectListOfMatListOfListOfKeyPoint() {
-        fail("Not yet implemented");
-    }
-
-    public void testDetectListOfMatListOfListOfKeyPointListOfMat() {
-        fail("Not yet implemented");
-    }
-
-    public void testDetectMatListOfKeyPoint() {
-        fail("Not yet implemented");
-    }
-
-    public void testDetectMatListOfKeyPointMat() {
-        fail("Not yet implemented");
-    }
-
-    public void testEmpty() {
-        fail("Not yet implemented");
-    }
-
-    public void testRead() {
-        fail("Not yet implemented");
-    }
-
-    public void testWrite() {
-        fail("Not yet implemented");
-    }
-
-}
diff --git a/modules/features2d/misc/java/test/GridMSERFeatureDetectorTest.java b/modules/features2d/misc/java/test/GridMSERFeatureDetectorTest.java
deleted file mode 100644
index 95fb73d..0000000
--- a/modules/features2d/misc/java/test/GridMSERFeatureDetectorTest.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package org.opencv.test.features2d;
-
-import org.opencv.test.OpenCVTestCase;
-
-public class GridMSERFeatureDetectorTest extends OpenCVTestCase {
-
-    public void testCreate() {
-        fail("Not yet implemented");
-    }
-
-    public void testDetectListOfMatListOfListOfKeyPoint() {
-        fail("Not yet implemented");
-    }
-
-    public void testDetectListOfMatListOfListOfKeyPointListOfMat() {
-        fail("Not yet implemented");
-    }
-
-    public void testDetectMatListOfKeyPoint() {
-        fail("Not yet implemented");
-    }
-
-    public void testDetectMatListOfKeyPointMat() {
-        fail("Not yet implemented");
-    }
-
-    public void testEmpty() {
-        fail("Not yet implemented");
-    }
-
-    public void testRead() {
-        fail("Not yet implemented");
-    }
-
-    public void testWrite() {
-        fail("Not yet implemented");
-    }
-
-}
diff --git a/modules/features2d/misc/java/test/GridORBFeatureDetectorTest.java b/modules/features2d/misc/java/test/GridORBFeatureDetectorTest.java
deleted file mode 100644
index 0d62c36..0000000
--- a/modules/features2d/misc/java/test/GridORBFeatureDetectorTest.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package org.opencv.test.features2d;
-
-import org.opencv.test.OpenCVTestCase;
-
-public class GridORBFeatureDetectorTest extends OpenCVTestCase {
-
-    public void testCreate() {
-        fail("Not yet implemented");
-    }
-
-    public void testDetectListOfMatListOfListOfKeyPoint() {
-        fail("Not yet implemented");
-    }
-
-    public void testDetectListOfMatListOfListOfKeyPointListOfMat() {
-        fail("Not yet implemented");
-    }
-
-    public void testDetectMatListOfKeyPoint() {
-        fail("Not yet implemented");
-    }
-
-    public void testDetectMatListOfKeyPointMat() {
-        fail("Not yet implemented");
-    }
-
-    public void testEmpty() {
-        fail("Not yet implemented");
-    }
-
-    public void testRead() {
-        fail("Not yet implemented");
-    }
-
-    public void testWrite() {
-        fail("Not yet implemented");
-    }
-
-}
diff --git a/modules/features2d/misc/java/test/GridSIFTFeatureDetectorTest.java b/modules/features2d/misc/java/test/GridSIFTFeatureDetectorTest.java
deleted file mode 100644
index fd5b12c..0000000
--- a/modules/features2d/misc/java/test/GridSIFTFeatureDetectorTest.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package org.opencv.test.features2d;
-
-import org.opencv.test.OpenCVTestCase;
-
-public class GridSIFTFeatureDetectorTest extends OpenCVTestCase {
-
-    public void testCreate() {
-        fail("Not yet implemented");
-    }
-
-    public void testDetectListOfMatListOfListOfKeyPoint() {
-        fail("Not yet implemented");
-    }
-
-    public void testDetectListOfMatListOfListOfKeyPointListOfMat() {
-        fail("Not yet implemented");
-    }
-
-    public void testDetectMatListOfKeyPoint() {
-        fail("Not yet implemented");
-    }
-
-    public void testDetectMatListOfKeyPointMat() {
-        fail("Not yet implemented");
-    }
-
-    public void testEmpty() {
-        fail("Not yet implemented");
-    }
-
-    public void testRead() {
-        fail("Not yet implemented");
-    }
-
-    public void testWrite() {
-        fail("Not yet implemented");
-    }
-
-}
diff --git a/modules/features2d/misc/java/test/GridSIMPLEBLOBFeatureDetectorTest.java b/modules/features2d/misc/java/test/GridSIMPLEBLOBFeatureDetectorTest.java
deleted file mode 100644
index 1e0f537..0000000
--- a/modules/features2d/misc/java/test/GridSIMPLEBLOBFeatureDetectorTest.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package org.opencv.test.features2d;
-
-import org.opencv.test.OpenCVTestCase;
-
-public class GridSIMPLEBLOBFeatureDetectorTest extends OpenCVTestCase {
-
-    public void testCreate() {
-        fail("Not yet implemented");
-    }
-
-    public void testDetectListOfMatListOfListOfKeyPoint() {
-        fail("Not yet implemented");
-    }
-
-    public void testDetectListOfMatListOfListOfKeyPointListOfMat() {
-        fail("Not yet implemented");
-    }
-
-    public void testDetectMatListOfKeyPoint() {
-        fail("Not yet implemented");
-    }
-
-    public void testDetectMatListOfKeyPointMat() {
-        fail("Not yet implemented");
-    }
-
-    public void testEmpty() {
-        fail("Not yet implemented");
-    }
-
-    public void testRead() {
-        fail("Not yet implemented");
-    }
-
-    public void testWrite() {
-        fail("Not yet implemented");
-    }
-
-}
diff --git a/modules/features2d/misc/java/test/GridSTARFeatureDetectorTest.java b/modules/features2d/misc/java/test/GridSTARFeatureDetectorTest.java
deleted file mode 100644
index c22d234..0000000
--- a/modules/features2d/misc/java/test/GridSTARFeatureDetectorTest.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package org.opencv.test.features2d;
-
-import org.opencv.test.OpenCVTestCase;
-
-public class GridSTARFeatureDetectorTest extends OpenCVTestCase {
-
-    public void testCreate() {
-        fail("Not yet implemented");
-    }
-
-    public void testDetectListOfMatListOfListOfKeyPoint() {
-        fail("Not yet implemented");
-    }
-
-    public void testDetectListOfMatListOfListOfKeyPointListOfMat() {
-        fail("Not yet implemented");
-    }
-
-    public void testDetectMatListOfKeyPoint() {
-        fail("Not yet implemented");
-    }
-
-    public void testDetectMatListOfKeyPointMat() {
-        fail("Not yet implemented");
-    }
-
-    public void testEmpty() {
-        fail("Not yet implemented");
-    }
-
-    public void testRead() {
-        fail("Not yet implemented");
-    }
-
-    public void testWrite() {
-        fail("Not yet implemented");
-    }
-
-}
diff --git a/modules/features2d/misc/java/test/GridSURFFeatureDetectorTest.java b/modules/features2d/misc/java/test/GridSURFFeatureDetectorTest.java
deleted file mode 100644
index d93df1b..0000000
--- a/modules/features2d/misc/java/test/GridSURFFeatureDetectorTest.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package org.opencv.test.features2d;
-
-import org.opencv.test.OpenCVTestCase;
-
-public class GridSURFFeatureDetectorTest extends OpenCVTestCase {
-
-    public void testCreate() {
-        fail("Not yet implemented");
-    }
-
-    public void testDetectListOfMatListOfListOfKeyPoint() {
-        fail("Not yet implemented");
-    }
-
-    public void testDetectListOfMatListOfListOfKeyPointListOfMat() {
-        fail("Not yet implemented");
-    }
-
-    public void testDetectMatListOfKeyPoint() {
-        fail("Not yet implemented");
-    }
-
-    public void testDetectMatListOfKeyPointMat() {
-        fail("Not yet implemented");
-    }
-
-    public void testEmpty() {
-        fail("Not yet implemented");
-    }
-
-    public void testRead() {
-        fail("Not yet implemented");
-    }
-
-    public void testWrite() {
-        fail("Not yet implemented");
-    }
-
-}
diff --git a/modules/features2d/misc/java/test/ORBDescriptorExtractorTest.java b/modules/features2d/misc/java/test/ORBDescriptorExtractorTest.java
index 5869d67..1009e1b 100644
--- a/modules/features2d/misc/java/test/ORBDescriptorExtractorTest.java
+++ b/modules/features2d/misc/java/test/ORBDescriptorExtractorTest.java
@@ -8,13 +8,14 @@ import org.opencv.core.Point;
 import org.opencv.core.Scalar;
 import org.opencv.features2d.DescriptorExtractor;
 import org.opencv.core.KeyPoint;
+import org.opencv.features2d.ORB;
 import org.opencv.test.OpenCVTestCase;
 import org.opencv.test.OpenCVTestRunner;
 import org.opencv.imgproc.Imgproc;
 
 public class ORBDescriptorExtractorTest extends OpenCVTestCase {
 
-    DescriptorExtractor extractor;
+    ORB extractor;
     int matSize;
 
     public static void assertDescriptorsClose(Mat expected, Mat actual, int allowedDistance) {
@@ -33,7 +34,7 @@ public class ORBDescriptorExtractorTest extends OpenCVTestCase {
     @Override
     protected void setUp() throws Exception {
         super.setUp();
-        extractor = DescriptorExtractor.create(DescriptorExtractor.ORB);
+        extractor = ORB.create();
         matSize = 100;
     }
 
@@ -71,7 +72,8 @@ public class ORBDescriptorExtractorTest extends OpenCVTestCase {
     }
 
     public void testEmpty() {
-        assertFalse(extractor.empty());
+//        assertFalse(extractor.empty());
+        fail("Not yet implemented"); // ORB does not override empty() method
     }
 
     public void testRead() {
@@ -80,9 +82,10 @@ public class ORBDescriptorExtractorTest extends OpenCVTestCase {
         Mat img = getTestImg();
         Mat descriptors = new Mat();
 
-        String filename = OpenCVTestRunner.getTempFileName("yml");
-        writeFile(filename, "%YAML:1.0\nscaleFactor: 1.1\nnLevels: 3\nfirstLevel: 0\nedgeThreshold: 31\npatchSize: 31\n");
-        extractor.read(filename);
+//        String filename = OpenCVTestRunner.getTempFileName("yml");
+//        writeFile(filename, "%YAML:1.0\n---\nscaleFactor: 1.1\nnLevels: 3\nfirstLevel: 0\nedgeThreshold: 31\npatchSize: 31\n");
+//        extractor.read(filename);
+        extractor = ORB.create(500, 1.1f, 3, 31, 0, 2, ORB.HARRIS_SCORE, 31, 20);
 
         extractor.compute(img, keypoints, descriptors);
 
@@ -100,7 +103,8 @@ public class ORBDescriptorExtractorTest extends OpenCVTestCase {
 
         extractor.write(filename);
 
-        String truth = "<?xml version=\"1.0\"?>\n<opencv_storage>\n<name>Feature2D.ORB</name>\n<WTA_K>2</WTA_K>\n<edgeThreshold>31</edgeThreshold>\n<firstLevel>0</firstLevel>\n<nFeatures>500</nFeatures>\n<nLevels>8</nLevels>\n<patchSize>31</patchSize>\n<scaleFactor>1.2000000476837158e+00</scaleFactor>\n<scoreType>0</scoreType>\n</opencv_storage>\n";
+//        String truth = "<?xml version=\"1.0\"?>\n<opencv_storage>\n<name>Feature2D.ORB</name>\n<WTA_K>2</WTA_K>\n<edgeThreshold>31</edgeThreshold>\n<firstLevel>0</firstLevel>\n<nFeatures>500</nFeatures>\n<nLevels>8</nLevels>\n<patchSize>31</patchSize>\n<scaleFactor>1.2000000476837158e+00</scaleFactor>\n<scoreType>0</scoreType>\n</opencv_storage>\n";
+        String truth = "<?xml version=\"1.0\"?>\n<opencv_storage>\n</opencv_storage>\n";
         String actual = readFile(filename);
         actual = actual.replaceAll("e\\+000", "e+00"); // NOTE: workaround for different platforms double representation
         assertEquals(truth, actual);
@@ -111,7 +115,8 @@ public class ORBDescriptorExtractorTest extends OpenCVTestCase {
 
         extractor.write(filename);
 
-        String truth = "%YAML:1.0\nname: \"Feature2D.ORB\"\nWTA_K: 2\nedgeThreshold: 31\nfirstLevel: 0\nnFeatures: 500\nnLevels: 8\npatchSize: 31\nscaleFactor: 1.2000000476837158e+00\nscoreType: 0\n";
+//        String truth = "%YAML:1.0\n---\nname: \"Feature2D.ORB\"\nWTA_K: 2\nedgeThreshold: 31\nfirstLevel: 0\nnFeatures: 500\nnLevels: 8\npatchSize: 31\nscaleFactor: 1.2000000476837158e+00\nscoreType: 0\n";
+        String truth = "%YAML:1.0\n---\n";
         String actual = readFile(filename);
         actual = actual.replaceAll("e\\+000", "e+00"); // NOTE: workaround for different platforms double representation
         assertEquals(truth, actual);
diff --git a/modules/features2d/misc/java/test/OneWayGenericDescriptorMatcherTest.java b/modules/features2d/misc/java/test/OneWayGenericDescriptorMatcherTest.java
deleted file mode 100644
index 1d66957..0000000
--- a/modules/features2d/misc/java/test/OneWayGenericDescriptorMatcherTest.java
+++ /dev/null
@@ -1,127 +0,0 @@
-package org.opencv.test.features2d;
-
-import org.opencv.test.OpenCVTestCase;
-
-public class OneWayGenericDescriptorMatcherTest extends OpenCVTestCase {
-
-    public void testAdd() {
-        fail("Not yet implemented");
-    }
-
-    public void testClassifyMatListOfKeyPointMatListOfKeyPoint() {
-        fail("Not yet implemented");
-    }
-
-    public void testClassifyMatListOfKeyPoint() {
-        fail("Not yet implemented");
-    }
-
-    public void testClear() {
-        fail("Not yet implemented");
-    }
-
-    public void testCloneBoolean() {
-        fail("Not yet implemented");
-    }
-
-    public void testClone() {
-        fail("Not yet implemented");
-    }
-
-    public void testCreate() {
-        fail("Not yet implemented");
-    }
-
-    public void testEmpty() {
-        fail("Not yet implemented");
-    }
-
-    public void testGetTrainImages() {
-        fail("Not yet implemented");
-    }
-
-    public void testGetTrainKeypoints() {
-        fail("Not yet implemented");
-    }
-
-    public void testIsMaskSupported() {
-        fail("Not yet implemented");
-    }
-
-    public void testKnnMatchMatListOfKeyPointMatListOfKeyPointListOfListOfDMatchIntMatBoolean() {
-        fail("Not yet implemented");
-    }
-
-    public void testKnnMatchMatListOfKeyPointMatListOfKeyPointListOfListOfDMatchIntMat() {
-        fail("Not yet implemented");
-    }
-
-    public void testKnnMatchMatListOfKeyPointMatListOfKeyPointListOfListOfDMatchInt() {
-        fail("Not yet implemented");
-    }
-
-    public void testKnnMatchMatListOfKeyPointListOfListOfDMatchIntListOfMatBoolean() {
-        fail("Not yet implemented");
-    }
-
-    public void testKnnMatchMatListOfKeyPointListOfListOfDMatchIntListOfMat() {
-        fail("Not yet implemented");
-    }
-
-    public void testKnnMatchMatListOfKeyPointListOfListOfDMatchInt() {
-        fail("Not yet implemented");
-    }
-
-    public void testMatchMatListOfKeyPointMatListOfKeyPointListOfDMatchMat() {
-        fail("Not yet implemented");
-    }
-
-    public void testMatchMatListOfKeyPointMatListOfKeyPointListOfDMatch() {
-        fail("Not yet implemented");
-    }
-
-    public void testMatchMatListOfKeyPointListOfDMatchListOfMat() {
-        fail("Not yet implemented");
-    }
-
-    public void testMatchMatListOfKeyPointListOfDMatch() {
-        fail("Not yet implemented");
-    }
-
-    public void testRadiusMatchMatListOfKeyPointMatListOfKeyPointListOfListOfDMatchFloatMatBoolean() {
-        fail("Not yet implemented");
-    }
-
-    public void testRadiusMatchMatListOfKeyPointMatListOfKeyPointListOfListOfDMatchFloatMat() {
-        fail("Not yet implemented");
-    }
-
-    public void testRadiusMatchMatListOfKeyPointMatListOfKeyPointListOfListOfDMatchFloat() {
-        fail("Not yet implemented");
-    }
-
-    public void testRadiusMatchMatListOfKeyPointListOfListOfDMatchFloatListOfMatBoolean() {
-        fail("Not yet implemented");
-    }
-
-    public void testRadiusMatchMatListOfKeyPointListOfListOfDMatchFloatListOfMat() {
-        fail("Not yet implemented");
-    }
-
-    public void testRadiusMatchMatListOfKeyPointListOfListOfDMatchFloat() {
-        fail("Not yet implemented");
-    }
-
-    public void testRead() {
-        fail("Not yet implemented");
-    }
-
-    public void testTrain() {
-        fail("Not yet implemented");
-    }
-
-    public void testWrite() {
-        fail("Not yet implemented");
-    }
-
-}
diff --git a/modules/features2d/misc/java/test/OpponentBRIEFDescriptorExtractorTest.java b/modules/features2d/misc/java/test/OpponentBRIEFDescriptorExtractorTest.java
deleted file mode 100644
index 7007da8..0000000
--- a/modules/features2d/misc/java/test/OpponentBRIEFDescriptorExtractorTest.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package org.opencv.test.features2d;
-
-import org.opencv.test.OpenCVTestCase;
-
-public class OpponentBRIEFDescriptorExtractorTest extends OpenCVTestCase {
-
-    public void testComputeListOfMatListOfListOfKeyPointListOfMat() {
-        fail("Not yet implemented");
-    }
-
-    public void testComputeMatListOfKeyPointMat() {
-        fail("Not yet implemented");
-    }
-
-    public void testCreate() {
-        fail("Not yet implemented");
-    }
-
-    public void testDescriptorSize() {
-        fail("Not yet implemented");
-    }
-
-    public void testDescriptorType() {
-        fail("Not yet implemented");
-    }
-
-    public void testEmpty() {
-        fail("Not yet implemented");
-    }
-
-    public void testRead() {
-        fail("Not yet implemented");
-    }
-
-    public void testWrite() {
-        fail("Not yet implemented");
-    }
-
-}
diff --git a/modules/features2d/misc/java/test/OpponentORBDescriptorExtractorTest.java b/modules/features2d/misc/java/test/OpponentORBDescriptorExtractorTest.java
deleted file mode 100644
index ee63e37..0000000
--- a/modules/features2d/misc/java/test/OpponentORBDescriptorExtractorTest.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package org.opencv.test.features2d;
-
-import org.opencv.test.OpenCVTestCase;
-
-public class OpponentORBDescriptorExtractorTest extends OpenCVTestCase {
-
-    public void testComputeListOfMatListOfListOfKeyPointListOfMat() {
-        fail("Not yet implemented");
-    }
-
-    public void testComputeMatListOfKeyPointMat() {
-        fail("Not yet implemented");
-    }
-
-    public void testCreate() {
-        fail("Not yet implemented");
-    }
-
-    public void testDescriptorSize() {
-        fail("Not yet implemented");
-    }
-
-    public void testDescriptorType() {
-        fail("Not yet implemented");
-    }
-
-    public void testEmpty() {
-        fail("Not yet implemented");
-    }
-
-    public void testRead() {
-        fail("Not yet implemented");
-    }
-
-    public void testWrite() {
-        fail("Not yet implemented");
-    }
-
-}
diff --git a/modules/features2d/misc/java/test/OpponentSIFTDescriptorExtractorTest.java b/modules/features2d/misc/java/test/OpponentSIFTDescriptorExtractorTest.java
deleted file mode 100644
index 2429582..0000000
--- a/modules/features2d/misc/java/test/OpponentSIFTDescriptorExtractorTest.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package org.opencv.test.features2d;
-
-import org.opencv.test.OpenCVTestCase;
-
-public class OpponentSIFTDescriptorExtractorTest extends OpenCVTestCase {
-
-    public void testComputeListOfMatListOfListOfKeyPointListOfMat() {
-        fail("Not yet implemented");
-    }
-
-    public void testComputeMatListOfKeyPointMat() {
-        fail("Not yet implemented");
-    }
-
-    public void testCreate() {
-        fail("Not yet implemented");
-    }
-
-    public void testDescriptorSize() {
-        fail("Not yet implemented");
-    }
-
-    public void testDescriptorType() {
-        fail("Not yet implemented");
-    }
-
-    public void testEmpty() {
-        fail("Not yet implemented");
-    }
-
-    public void testRead() {
-        fail("Not yet implemented");
-    }
-
-    public void testWrite() {
-        fail("Not yet implemented");
-    }
-
-}
diff --git a/modules/features2d/misc/java/test/OpponentSURFDescriptorExtractorTest.java b/modules/features2d/misc/java/test/OpponentSURFDescriptorExtractorTest.java
deleted file mode 100644
index cbfcd2d..0000000
--- a/modules/features2d/misc/java/test/OpponentSURFDescriptorExtractorTest.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package org.opencv.test.features2d;
-
-import org.opencv.test.OpenCVTestCase;
-
-public class OpponentSURFDescriptorExtractorTest extends OpenCVTestCase {
-
-    public void testComputeListOfMatListOfListOfKeyPointListOfMat() {
-        fail("Not yet implemented");
-    }
-
-    public void testComputeMatListOfKeyPointMat() {
-        fail("Not yet implemented");
-    }
-
-    public void testCreate() {
-        fail("Not yet implemented");
-    }
-
-    public void testDescriptorSize() {
-        fail("Not yet implemented");
-    }
-
-    public void testDescriptorType() {
-        fail("Not yet implemented");
-    }
-
-    public void testEmpty() {
-        fail("Not yet implemented");
-    }
-
-    public void testRead() {
-        fail("Not yet implemented");
-    }
-
-    public void testWrite() {
-        fail("Not yet implemented");
-    }
-
-}
diff --git a/modules/features2d/misc/java/test/PyramidDENSEFeatureDetectorTest.java b/modules/features2d/misc/java/test/PyramidDENSEFeatureDetectorTest.java
deleted file mode 100644
index 31be53a..0000000
--- a/modules/features2d/misc/java/test/PyramidDENSEFeatureDetectorTest.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package org.opencv.test.features2d;
-
-import org.opencv.test.OpenCVTestCase;
-
-public class PyramidDENSEFeatureDetectorTest extends OpenCVTestCase {
-
-    public void testCreate() {
-        fail("Not yet implemented");
-    }
-
-    public void testDetectListOfMatListOfListOfKeyPoint() {
-        fail("Not yet implemented");
-    }
-
-    public void testDetectListOfMatListOfListOfKeyPointListOfMat() {
-        fail("Not yet implemented");
-    }
-
-    public void testDetectMatListOfKeyPoint() {
-        fail("Not yet implemented");
-    }
-
-    public void testDetectMatListOfKeyPointMat() {
-        fail("Not yet implemented");
-    }
-
-    public void testEmpty() {
-        fail("Not yet implemented");
-    }
-
-    public void testRead() {
-        fail("Not yet implemented");
-    }
-
-    public void testWrite() {
-        fail("Not yet implemented");
-    }
-
-}
diff --git a/modules/features2d/misc/java/test/PyramidFASTFeatureDetectorTest.java b/modules/features2d/misc/java/test/PyramidFASTFeatureDetectorTest.java
deleted file mode 100644
index 90447f1..0000000
--- a/modules/features2d/misc/java/test/PyramidFASTFeatureDetectorTest.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package org.opencv.test.features2d;
-
-import org.opencv.test.OpenCVTestCase;
-
-public class PyramidFASTFeatureDetectorTest extends OpenCVTestCase {
-
-    public void testCreate() {
-        fail("Not yet implemented");
-    }
-
-    public void testDetectListOfMatListOfListOfKeyPoint() {
-        fail("Not yet implemented");
-    }
-
-    public void testDetectListOfMatListOfListOfKeyPointListOfMat() {
-        fail("Not yet implemented");
-    }
-
-    public void testDetectMatListOfKeyPoint() {
-        fail("Not yet implemented");
-    }
-
-    public void testDetectMatListOfKeyPointMat() {
-        fail("Not yet implemented");
-    }
-
-    public void testEmpty() {
-        fail("Not yet implemented");
-    }
-
-    public void testRead() {
-        fail("Not yet implemented");
-    }
-
-    public void testWrite() {
-        fail("Not yet implemented");
-    }
-
-}
diff --git a/modules/features2d/misc/java/test/PyramidGFTTFeatureDetectorTest.java b/modules/features2d/misc/java/test/PyramidGFTTFeatureDetectorTest.java
deleted file mode 100644
index d660f34..0000000
--- a/modules/features2d/misc/java/test/PyramidGFTTFeatureDetectorTest.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package org.opencv.test.features2d;
-
-import org.opencv.test.OpenCVTestCase;
-
-public class PyramidGFTTFeatureDetectorTest extends OpenCVTestCase {
-
-    public void testCreate() {
-        fail("Not yet implemented");
-    }
-
-    public void testDetectListOfMatListOfListOfKeyPoint() {
-        fail("Not yet implemented");
-    }
-
-    public void testDetectListOfMatListOfListOfKeyPointListOfMat() {
-        fail("Not yet implemented");
-    }
-
-    public void testDetectMatListOfKeyPoint() {
-        fail("Not yet implemented");
-    }
-
-    public void testDetectMatListOfKeyPointMat() {
-        fail("Not yet implemented");
-    }
-
-    public void testEmpty() {
-        fail("Not yet implemented");
-    }
-
-    public void testRead() {
-        fail("Not yet implemented");
-    }
-
-    public void testWrite() {
-        fail("Not yet implemented");
-    }
-
-}
diff --git a/modules/features2d/misc/java/test/PyramidHARRISFeatureDetectorTest.java b/modules/features2d/misc/java/test/PyramidHARRISFeatureDetectorTest.java
deleted file mode 100644
index 92f534b..0000000
--- a/modules/features2d/misc/java/test/PyramidHARRISFeatureDetectorTest.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package org.opencv.test.features2d;
-
-import org.opencv.test.OpenCVTestCase;
-
-public class PyramidHARRISFeatureDetectorTest extends OpenCVTestCase {
-
-    public void testCreate() {
-        fail("Not yet implemented");
-    }
-
-    public void testDetectListOfMatListOfListOfKeyPoint() {
-        fail("Not yet implemented");
-    }
-
-    public void testDetectListOfMatListOfListOfKeyPointListOfMat() {
-        fail("Not yet implemented");
-    }
-
-    public void testDetectMatListOfKeyPoint() {
-        fail("Not yet implemented");
-    }
-
-    public void testDetectMatListOfKeyPointMat() {
-        fail("Not yet implemented");
-    }
-
-    public void testEmpty() {
-        fail("Not yet implemented");
-    }
-
-    public void testRead() {
-        fail("Not yet implemented");
-    }
-
-    public void testWrite() {
-        fail("Not yet implemented");
-    }
-
-}
diff --git a/modules/features2d/misc/java/test/PyramidMSERFeatureDetectorTest.java b/modules/features2d/misc/java/test/PyramidMSERFeatureDetectorTest.java
deleted file mode 100644
index 865c30d..0000000
--- a/modules/features2d/misc/java/test/PyramidMSERFeatureDetectorTest.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package org.opencv.test.features2d;
-
-import org.opencv.test.OpenCVTestCase;
-
-public class PyramidMSERFeatureDetectorTest extends OpenCVTestCase {
-
-    public void testCreate() {
-        fail("Not yet implemented");
-    }
-
-    public void testDetectListOfMatListOfListOfKeyPoint() {
-        fail("Not yet implemented");
-    }
-
-    public void testDetectListOfMatListOfListOfKeyPointListOfMat() {
-        fail("Not yet implemented");
-    }
-
-    public void testDetectMatListOfKeyPoint() {
-        fail("Not yet implemented");
-    }
-
-    public void testDetectMatListOfKeyPointMat() {
-        fail("Not yet implemented");
-    }
-
-    public void testEmpty() {
-        fail("Not yet implemented");
-    }
-
-    public void testRead() {
-        fail("Not yet implemented");
-    }
-
-    public void testWrite() {
-        fail("Not yet implemented");
-    }
-
-}
diff --git a/modules/features2d/misc/java/test/PyramidORBFeatureDetectorTest.java b/modules/features2d/misc/java/test/PyramidORBFeatureDetectorTest.java
deleted file mode 100644
index 71ca5e0..0000000
--- a/modules/features2d/misc/java/test/PyramidORBFeatureDetectorTest.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package org.opencv.test.features2d;
-
-import org.opencv.test.OpenCVTestCase;
-
-public class PyramidORBFeatureDetectorTest extends OpenCVTestCase {
-
-    public void testCreate() {
-        fail("Not yet implemented");
-    }
-
-    public void testDetectListOfMatListOfListOfKeyPoint() {
-        fail("Not yet implemented");
-    }
-
-    public void testDetectListOfMatListOfListOfKeyPointListOfMat() {
-        fail("Not yet implemented");
-    }
-
-    public void testDetectMatListOfKeyPoint() {
-        fail("Not yet implemented");
-    }
-
-    public void testDetectMatListOfKeyPointMat() {
-        fail("Not yet implemented");
-    }
-
-    public void testEmpty() {
-        fail("Not yet implemented");
-    }
-
-    public void testRead() {
-        fail("Not yet implemented");
-    }
-
-    public void testWrite() {
-        fail("Not yet implemented");
-    }
-
-}
diff --git a/modules/features2d/misc/java/test/PyramidSIFTFeatureDetectorTest.java b/modules/features2d/misc/java/test/PyramidSIFTFeatureDetectorTest.java
deleted file mode 100644
index 6327c00..0000000
--- a/modules/features2d/misc/java/test/PyramidSIFTFeatureDetectorTest.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package org.opencv.test.features2d;
-
-import org.opencv.test.OpenCVTestCase;
-
-public class PyramidSIFTFeatureDetectorTest extends OpenCVTestCase {
-
-    public void testCreate() {
-        fail("Not yet implemented");
-    }
-
-    public void testDetectListOfMatListOfListOfKeyPoint() {
-        fail("Not yet implemented");
-    }
-
-    public void testDetectListOfMatListOfListOfKeyPointListOfMat() {
-        fail("Not yet implemented");
-    }
-
-    public void testDetectMatListOfKeyPoint() {
-        fail("Not yet implemented");
-    }
-
-    public void testDetectMatListOfKeyPointMat() {
-        fail("Not yet implemented");
-    }
-
-    public void testEmpty() {
-        fail("Not yet implemented");
-    }
-
-    public void testRead() {
-        fail("Not yet implemented");
-    }
-
-    public void testWrite() {
-        fail("Not yet implemented");
-    }
-
-}
diff --git a/modules/features2d/misc/java/test/PyramidSIMPLEBLOBFeatureDetectorTest.java b/modules/features2d/misc/java/test/PyramidSIMPLEBLOBFeatureDetectorTest.java
deleted file mode 100644
index 94a0ba6..0000000
--- a/modules/features2d/misc/java/test/PyramidSIMPLEBLOBFeatureDetectorTest.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package org.opencv.test.features2d;
-
-import org.opencv.test.OpenCVTestCase;
-
-public class PyramidSIMPLEBLOBFeatureDetectorTest extends OpenCVTestCase {
-
-    public void testCreate() {
-        fail("Not yet implemented");
-    }
-
-    public void testDetectListOfMatListOfListOfKeyPoint() {
-        fail("Not yet implemented");
-    }
-
-    public void testDetectListOfMatListOfListOfKeyPointListOfMat() {
-        fail("Not yet implemented");
-    }
-
-    public void testDetectMatListOfKeyPoint() {
-        fail("Not yet implemented");
-    }
-
-    public void testDetectMatListOfKeyPointMat() {
-        fail("Not yet implemented");
-    }
-
-    public void testEmpty() {
-        fail("Not yet implemented");
-    }
-
-    public void testRead() {
-        fail("Not yet implemented");
-    }
-
-    public void testWrite() {
-        fail("Not yet implemented");
-    }
-
-}
diff --git a/modules/features2d/misc/java/test/PyramidSTARFeatureDetectorTest.java b/modules/features2d/misc/java/test/PyramidSTARFeatureDetectorTest.java
deleted file mode 100644
index 6adc93e..0000000
--- a/modules/features2d/misc/java/test/PyramidSTARFeatureDetectorTest.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package org.opencv.test.features2d;
-
-import org.opencv.test.OpenCVTestCase;
-
-public class PyramidSTARFeatureDetectorTest extends OpenCVTestCase {
-
-    public void testCreate() {
-        fail("Not yet implemented");
-    }
-
-    public void testDetectListOfMatListOfListOfKeyPoint() {
-        fail("Not yet implemented");
-    }
-
-    public void testDetectListOfMatListOfListOfKeyPointListOfMat() {
-        fail("Not yet implemented");
-    }
-
-    public void testDetectMatListOfKeyPoint() {
-        fail("Not yet implemented");
-    }
-
-    public void testDetectMatListOfKeyPointMat() {
-        fail("Not yet implemented");
-    }
-
-    public void testEmpty() {
-        fail("Not yet implemented");
-    }
-
-    public void testRead() {
-        fail("Not yet implemented");
-    }
-
-    public void testWrite() {
-        fail("Not yet implemented");
-    }
-
-}
diff --git a/modules/features2d/misc/java/test/PyramidSURFFeatureDetectorTest.java b/modules/features2d/misc/java/test/PyramidSURFFeatureDetectorTest.java
deleted file mode 100644
index 0e7b341..0000000
--- a/modules/features2d/misc/java/test/PyramidSURFFeatureDetectorTest.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package org.opencv.test.features2d;
-
-import org.opencv.test.OpenCVTestCase;
-
-public class PyramidSURFFeatureDetectorTest extends OpenCVTestCase {
-
-    public void testCreate() {
-        fail("Not yet implemented");
-    }
-
-    public void testDetectListOfMatListOfListOfKeyPoint() {
-        fail("Not yet implemented");
-    }
-
-    public void testDetectListOfMatListOfListOfKeyPointListOfMat() {
-        fail("Not yet implemented");
-    }
-
-    public void testDetectMatListOfKeyPoint() {
-        fail("Not yet implemented");
-    }
-
-    public void testDetectMatListOfKeyPointMat() {
-        fail("Not yet implemented");
-    }
-
-    public void testEmpty() {
-        fail("Not yet implemented");
-    }
-
-    public void testRead() {
-        fail("Not yet implemented");
-    }
-
-    public void testWrite() {
-        fail("Not yet implemented");
-    }
-
-}
diff --git a/modules/features2d/misc/java/test/SIFTDescriptorExtractorTest.java b/modules/features2d/misc/java/test/SIFTDescriptorExtractorTest.java
index 33c5d45..2c1ac7c 100644
--- a/modules/features2d/misc/java/test/SIFTDescriptorExtractorTest.java
+++ b/modules/features2d/misc/java/test/SIFTDescriptorExtractorTest.java
@@ -1,20 +1,19 @@
 package org.opencv.test.features2d;
 
-import org.opencv.core.Core;
 import org.opencv.core.CvType;
 import org.opencv.core.Mat;
 import org.opencv.core.MatOfKeyPoint;
 import org.opencv.core.Point;
 import org.opencv.core.Scalar;
-import org.opencv.features2d.DescriptorExtractor;
 import org.opencv.core.KeyPoint;
 import org.opencv.test.OpenCVTestCase;
 import org.opencv.test.OpenCVTestRunner;
 import org.opencv.imgproc.Imgproc;
+import org.opencv.features2d.Feature2D;
 
 public class SIFTDescriptorExtractorTest extends OpenCVTestCase {
 
-    DescriptorExtractor extractor;
+    Feature2D extractor;
     KeyPoint keypoint;
     int matSize;
     Mat truth;
@@ -30,7 +29,7 @@ public class SIFTDescriptorExtractorTest extends OpenCVTestCase {
     @Override
     protected void setUp() throws Exception {
         super.setUp();
-        extractor = DescriptorExtractor.create(DescriptorExtractor.SIFT);
+        extractor = createClassInstance(XFEATURES2D+"SIFT", DEFAULT_FACTORY, null, null);
         keypoint = new KeyPoint(55.775577545166016f, 44.224422454833984f, 16, 9.754629f, 8617.863f, 1, -1);
         matSize = 100;
         truth = new Mat(1, 128, CvType.CV_32FC1) {
@@ -75,7 +74,8 @@ public class SIFTDescriptorExtractorTest extends OpenCVTestCase {
     }
 
     public void testEmpty() {
-        assertFalse(extractor.empty());
+//        assertFalse(extractor.empty());
+        fail("Not yet implemented"); //SIFT does not override empty() method
     }
 
     public void testRead() {
@@ -87,7 +87,8 @@ public class SIFTDescriptorExtractorTest extends OpenCVTestCase {
 
         extractor.write(filename);
 
-        String truth = "<?xml version=\"1.0\"?>\n<opencv_storage>\n<name>Feature2D.SIFT</name>\n<contrastThreshold>4.0000000000000001e-02</contrastThreshold>\n<edgeThreshold>10.</edgeThreshold>\n<nFeatures>0</nFeatures>\n<nOctaveLayers>3</nOctaveLayers>\n<sigma>1.6000000000000001e+00</sigma>\n</opencv_storage>\n";
+//        String truth = "<?xml version=\"1.0\"?>\n<opencv_storage>\n<name>Feature2D.SIFT</name>\n<contrastThreshold>4.0000000000000001e-02</contrastThreshold>\n<edgeThreshold>10.</edgeThreshold>\n<nFeatures>0</nFeatures>\n<nOctaveLayers>3</nOctaveLayers>\n<sigma>1.6000000000000001e+00</sigma>\n</opencv_storage>\n";
+        String truth = "<?xml version=\"1.0\"?>\n<opencv_storage>\n</opencv_storage>\n";
         String actual = readFile(filename);
         actual = actual.replaceAll("e([+-])0(\\d\\d)", "e$1$2"); // NOTE: workaround for different platforms double representation
         assertEquals(truth, actual);
@@ -98,7 +99,8 @@ public class SIFTDescriptorExtractorTest extends OpenCVTestCase {
 
         extractor.write(filename);
 
-        String truth = "%YAML:1.0\nname: \"Feature2D.SIFT\"\ncontrastThreshold: 4.0000000000000001e-02\nedgeThreshold: 10.\nnFeatures: 0\nnOctaveLayers: 3\nsigma: 1.6000000000000001e+00\n";
+//        String truth = "%YAML:1.0\n---\nname: \"Feature2D.SIFT\"\ncontrastThreshold: 4.0000000000000001e-02\nedgeThreshold: 10.\nnFeatures: 0\nnOctaveLayers: 3\nsigma: 1.6000000000000001e+00\n";
+        String truth = "%YAML:1.0\n---\n";
         String actual = readFile(filename);
         actual = actual.replaceAll("e([+-])0(\\d\\d)", "e$1$2"); // NOTE: workaround for different platforms double representation
         assertEquals(truth, actual);
diff --git a/modules/features2d/misc/java/test/STARFeatureDetectorTest.java b/modules/features2d/misc/java/test/STARFeatureDetectorTest.java
index 282f043..3270842 100644
--- a/modules/features2d/misc/java/test/STARFeatureDetectorTest.java
+++ b/modules/features2d/misc/java/test/STARFeatureDetectorTest.java
@@ -2,21 +2,20 @@ package org.opencv.test.features2d;
 
 import java.util.Arrays;
 
-import org.opencv.core.Core;
 import org.opencv.core.CvType;
 import org.opencv.core.Mat;
 import org.opencv.core.MatOfKeyPoint;
 import org.opencv.core.Point;
 import org.opencv.core.Scalar;
-import org.opencv.features2d.FeatureDetector;
 import org.opencv.core.KeyPoint;
 import org.opencv.test.OpenCVTestCase;
 import org.opencv.test.OpenCVTestRunner;
 import org.opencv.imgproc.Imgproc;
+import org.opencv.features2d.Feature2D;
 
 public class STARFeatureDetectorTest extends OpenCVTestCase {
 
-    FeatureDetector detector;
+    Feature2D detector;
     int matSize;
     KeyPoint[] truth;
 
@@ -44,7 +43,7 @@ public class STARFeatureDetectorTest extends OpenCVTestCase {
 
     protected void setUp() throws Exception {
         super.setUp();
-        detector = FeatureDetector.create(FeatureDetector.STAR);
+        detector = createClassInstance(XFEATURES2D+"StarDetector", DEFAULT_FACTORY, null, null);
         matSize = 200;
         truth = new KeyPoint[] {
                 new KeyPoint( 95,  80, 22, -1, 31.5957f, 0, -1),
@@ -91,7 +90,8 @@ public class STARFeatureDetectorTest extends OpenCVTestCase {
     }
 
     public void testEmpty() {
-        assertFalse(detector.empty());
+//        assertFalse(detector.empty());
+        fail("Not yet implemented");
     }
 
     public void testRead() {
@@ -101,7 +101,7 @@ public class STARFeatureDetectorTest extends OpenCVTestCase {
         detector.detect(img, keypoints1);
 
         String filename = OpenCVTestRunner.getTempFileName("yml");
-        writeFile(filename, "%YAML:1.0\nmaxSize: 45\nresponseThreshold: 150\nlineThresholdProjected: 10\nlineThresholdBinarized: 8\nsuppressNonmaxSize: 5\n");
+        writeFile(filename, "%YAML:1.0\n---\nmaxSize: 45\nresponseThreshold: 150\nlineThresholdProjected: 10\nlineThresholdBinarized: 8\nsuppressNonmaxSize: 5\n");
         detector.read(filename);
 
         MatOfKeyPoint keypoints2 = new MatOfKeyPoint();
@@ -115,7 +115,8 @@ public class STARFeatureDetectorTest extends OpenCVTestCase {
 
         detector.write(filename);
 
-        String truth = "<?xml version=\"1.0\"?>\n<opencv_storage>\n<name>Feature2D.STAR</name>\n<lineThresholdBinarized>8</lineThresholdBinarized>\n<lineThresholdProjected>10</lineThresholdProjected>\n<maxSize>45</maxSize>\n<responseThreshold>30</responseThreshold>\n<suppressNonmaxSize>5</suppressNonmaxSize>\n</opencv_storage>\n";
+//        String truth = "<?xml version=\"1.0\"?>\n<opencv_storage>\n<name>Feature2D.STAR</name>\n<lineThresholdBinarized>8</lineThresholdBinarized>\n<lineThresholdProjected>10</lineThresholdProjected>\n<maxSize>45</maxSize>\n<responseThreshold>30</responseThreshold>\n<suppressNonmaxSize>5</suppressNonmaxSize>\n</opencv_storage>\n";
+        String truth = "<?xml version=\"1.0\"?>\n<opencv_storage>\n</opencv_storage>\n";
         assertEquals(truth, readFile(filename));
     }
 
@@ -124,7 +125,8 @@ public class STARFeatureDetectorTest extends OpenCVTestCase {
 
         detector.write(filename);
 
-        String truth = "%YAML:1.0\nname: \"Feature2D.STAR\"\nlineThresholdBinarized: 8\nlineThresholdProjected: 10\nmaxSize: 45\nresponseThreshold: 30\nsuppressNonmaxSize: 5\n";
+//        String truth = "%YAML:1.0\n---\nname: \"Feature2D.STAR\"\nlineThresholdBinarized: 8\nlineThresholdProjected: 10\nmaxSize: 45\nresponseThreshold: 30\nsuppressNonmaxSize: 5\n";
+        String truth = "%YAML:1.0\n---\n";
         assertEquals(truth, readFile(filename));
     }
 
diff --git a/modules/features2d/misc/java/test/SURFDescriptorExtractorTest.java b/modules/features2d/misc/java/test/SURFDescriptorExtractorTest.java
index 8973592..35131ee 100644
--- a/modules/features2d/misc/java/test/SURFDescriptorExtractorTest.java
+++ b/modules/features2d/misc/java/test/SURFDescriptorExtractorTest.java
@@ -1,20 +1,19 @@
 package org.opencv.test.features2d;
 
-import org.opencv.core.Core;
 import org.opencv.core.CvType;
 import org.opencv.core.Mat;
 import org.opencv.core.MatOfKeyPoint;
 import org.opencv.core.Point;
 import org.opencv.core.Scalar;
-import org.opencv.features2d.DescriptorExtractor;
 import org.opencv.core.KeyPoint;
 import org.opencv.test.OpenCVTestCase;
 import org.opencv.test.OpenCVTestRunner;
 import org.opencv.imgproc.Imgproc;
+import org.opencv.features2d.Feature2D;
 
 public class SURFDescriptorExtractorTest extends OpenCVTestCase {
 
-    DescriptorExtractor extractor;
+    Feature2D extractor;
     int matSize;
 
     private Mat getTestImg() {
@@ -29,10 +28,9 @@ public class SURFDescriptorExtractorTest extends OpenCVTestCase {
     protected void setUp() throws Exception {
         super.setUp();
 
-        extractor = DescriptorExtractor.create(DescriptorExtractor.SURF);
-        String filename = OpenCVTestRunner.getTempFileName("yml");
-        writeFile(filename, "%YAML:1.0\nextended: 1\nhessianThreshold: 100.\nnOctaveLayers: 2\nnOctaves: 4\nupright: 0");
-        extractor.read(filename);
+        Class[] cParams = {double.class, int.class, int.class, boolean.class, boolean.class};
+        Object[] oValues = {100, 2, 4, true, false};
+        extractor = createClassInstance(XFEATURES2D+"SURF", DEFAULT_FACTORY, cParams, oValues);
 
         matSize = 100;
     }
@@ -85,12 +83,13 @@ public class SURFDescriptorExtractorTest extends OpenCVTestCase {
     }
 
     public void testEmpty() {
-        assertFalse(extractor.empty());
+//        assertFalse(extractor.empty());
+        fail("Not yet implemented");
     }
 
     public void testRead() {
         String filename = OpenCVTestRunner.getTempFileName("yml");
-        writeFile(filename, "%YAML:1.0\nnOctaves: 4\nnOctaveLayers: 2\nextended: 1\nupright: 0\n");
+        writeFile(filename, "%YAML:1.0\n---\nnOctaves: 4\nnOctaveLayers: 2\nextended: 1\nupright: 0\n");
 
         extractor.read(filename);
 
@@ -102,7 +101,8 @@ public class SURFDescriptorExtractorTest extends OpenCVTestCase {
 
         extractor.write(filename);
 
-        String truth = "<?xml version=\"1.0\"?>\n<opencv_storage>\n<name>Feature2D.SURF</name>\n<extended>1</extended>\n<hessianThreshold>100.</hessianThreshold>\n<nOctaveLayers>2</nOctaveLayers>\n<nOctaves>4</nOctaves>\n<upright>0</upright>\n</opencv_storage>\n";
+//        String truth = "<?xml version=\"1.0\"?>\n<opencv_storage>\n<name>Feature2D.SURF</name>\n<extended>1</extended>\n<hessianThreshold>100.</hessianThreshold>\n<nOctaveLayers>2</nOctaveLayers>\n<nOctaves>4</nOctaves>\n<upright>0</upright>\n</opencv_storage>\n";
+        String truth = "<?xml version=\"1.0\"?>\n<opencv_storage>\n</opencv_storage>\n";
         assertEquals(truth, readFile(filename));
     }
 
@@ -111,7 +111,8 @@ public class SURFDescriptorExtractorTest extends OpenCVTestCase {
 
         extractor.write(filename);
 
-        String truth = "%YAML:1.0\nname: \"Feature2D.SURF\"\nextended: 1\nhessianThreshold: 100.\nnOctaveLayers: 2\nnOctaves: 4\nupright: 0\n";
+//        String truth = "%YAML:1.0\n---\nname: \"Feature2D.SURF\"\nextended: 1\nhessianThreshold: 100.\nnOctaveLayers: 2\nnOctaves: 4\nupright: 0\n";
+        String truth = "%YAML:1.0\n---\n";
         assertEquals(truth, readFile(filename));
     }
 
diff --git a/modules/features2d/misc/java/test/SURFFeatureDetectorTest.java b/modules/features2d/misc/java/test/SURFFeatureDetectorTest.java
index 75d1dab..f15426c 100644
--- a/modules/features2d/misc/java/test/SURFFeatureDetectorTest.java
+++ b/modules/features2d/misc/java/test/SURFFeatureDetectorTest.java
@@ -6,21 +6,20 @@ import java.util.Collections;
 import java.util.Comparator;
 import java.util.List;
 
-import org.opencv.core.Core;
 import org.opencv.core.CvType;
 import org.opencv.core.Mat;
 import org.opencv.core.MatOfKeyPoint;
 import org.opencv.core.Point;
 import org.opencv.core.Scalar;
-import org.opencv.features2d.FeatureDetector;
 import org.opencv.core.KeyPoint;
 import org.opencv.test.OpenCVTestCase;
 import org.opencv.test.OpenCVTestRunner;
 import org.opencv.imgproc.Imgproc;
+import org.opencv.features2d.Feature2D;
 
 public class SURFFeatureDetectorTest extends OpenCVTestCase {
 
-    FeatureDetector detector;
+    Feature2D detector;
     int matSize;
     KeyPoint[] truth;
 
@@ -54,7 +53,7 @@ public class SURFFeatureDetectorTest extends OpenCVTestCase {
     @Override
     protected void setUp() throws Exception {
         super.setUp();
-        detector = FeatureDetector.create(FeatureDetector.SURF);
+        detector = createClassInstance(XFEATURES2D+"SURF", DEFAULT_FACTORY, null, null);
         matSize = 100;
         truth = new KeyPoint[] {
                 new KeyPoint(55.775578f, 55.775578f, 16, 80.245735f, 8617.8633f, 0, -1),
@@ -69,9 +68,11 @@ public class SURFFeatureDetectorTest extends OpenCVTestCase {
     }
 
     public void testDetectListOfMatListOfListOfKeyPoint() {
-        String filename = OpenCVTestRunner.getTempFileName("yml");
-        writeFile(filename, "%YAML:1.0\nhessianThreshold: 8000.\noctaves: 3\noctaveLayers: 4\nupright: 0\n");
-        detector.read(filename);
+
+        setProperty(detector, "hessianThreshold", "double", 8000);
+        setProperty(detector, "nOctaves", "int", 3);
+        setProperty(detector, "nOctaveLayers", "int", 4);
+        setProperty(detector, "upright", "boolean", false);
 
         List<MatOfKeyPoint> keypoints = new ArrayList<MatOfKeyPoint>();
         Mat cross = getTestImg();
@@ -96,9 +97,11 @@ public class SURFFeatureDetectorTest extends OpenCVTestCase {
     }
 
     public void testDetectMatListOfKeyPoint() {
-        String filename = OpenCVTestRunner.getTempFileName("yml");
-        writeFile(filename, "%YAML:1.0\nhessianThreshold: 8000.\noctaves: 3\noctaveLayers: 4\nupright: 0\n");
-        detector.read(filename);
+
+        setProperty(detector, "hessianThreshold", "double", 8000);
+        setProperty(detector, "nOctaves", "int", 3);
+        setProperty(detector, "nOctaveLayers", "int", 4);
+        setProperty(detector, "upright", "boolean", false);
 
         MatOfKeyPoint keypoints = new MatOfKeyPoint();
         Mat cross = getTestImg();
@@ -111,9 +114,11 @@ public class SURFFeatureDetectorTest extends OpenCVTestCase {
     }
 
     public void testDetectMatListOfKeyPointMat() {
-        String filename = OpenCVTestRunner.getTempFileName("yml");
-        writeFile(filename, "%YAML:1.0\nhessianThreshold: 8000.\noctaves: 3\noctaveLayers: 4\nupright: 0\n");
-        detector.read(filename);
+
+        setProperty(detector, "hessianThreshold", "double", 8000);
+        setProperty(detector, "nOctaves", "int", 3);
+        setProperty(detector, "nOctaveLayers", "int", 4);
+        setProperty(detector, "upright", "boolean", false);
 
         Mat img = getTestImg();
         Mat mask = getMaskImg();
@@ -127,7 +132,8 @@ public class SURFFeatureDetectorTest extends OpenCVTestCase {
     }
 
     public void testEmpty() {
-        assertFalse(detector.empty());
+//        assertFalse(detector.empty());
+        fail("Not yet implemented");
     }
 
     public void testRead() {
@@ -137,7 +143,7 @@ public class SURFFeatureDetectorTest extends OpenCVTestCase {
         detector.detect(cross, keypoints1);
 
         String filename = OpenCVTestRunner.getTempFileName("yml");
-        writeFile(filename, "%YAML:1.0\nhessianThreshold: 8000.\noctaves: 3\noctaveLayers: 4\nupright: 0\n");
+        writeFile(filename, "%YAML:1.0\n---\nhessianThreshold: 8000.\noctaves: 3\noctaveLayers: 4\nupright: 0\n");
         detector.read(filename);
 
         MatOfKeyPoint keypoints2 = new MatOfKeyPoint();
@@ -151,7 +157,8 @@ public class SURFFeatureDetectorTest extends OpenCVTestCase {
 
         detector.write(filename);
 
-        String truth = "<?xml version=\"1.0\"?>\n<opencv_storage>\n<name>Feature2D.SURF</name>\n<extended>0</extended>\n<hessianThreshold>100.</hessianThreshold>\n<nOctaveLayers>3</nOctaveLayers>\n<nOctaves>4</nOctaves>\n<upright>0</upright>\n</opencv_storage>\n";
+//        String truth = "<?xml version=\"1.0\"?>\n<opencv_storage>\n<name>Feature2D.SURF</name>\n<extended>0</extended>\n<hessianThreshold>100.</hessianThreshold>\n<nOctaveLayers>3</nOctaveLayers>\n<nOctaves>4</nOctaves>\n<upright>0</upright>\n</opencv_storage>\n";
+        String truth = "<?xml version=\"1.0\"?>\n<opencv_storage>\n</opencv_storage>\n";
         assertEquals(truth, readFile(filename));
     }
 
@@ -160,7 +167,8 @@ public class SURFFeatureDetectorTest extends OpenCVTestCase {
 
         detector.write(filename);
 
-        String truth = "%YAML:1.0\nname: \"Feature2D.SURF\"\nextended: 0\nhessianThreshold: 100.\nnOctaveLayers: 3\nnOctaves: 4\nupright: 0\n";
+//        String truth = "%YAML:1.0\n---\nname: \"Feature2D.SURF\"\nextended: 0\nhessianThreshold: 100.\nnOctaveLayers: 3\nnOctaves: 4\nupright: 0\n";
+        String truth = "%YAML:1.0\n---\n";
         assertEquals(truth, readFile(filename));
     }
 
diff --git a/modules/features2d/misc/python/pyopencv_features2d.hpp b/modules/features2d/misc/python/pyopencv_features2d.hpp
new file mode 100644
index 0000000..b865e36
--- /dev/null
+++ b/modules/features2d/misc/python/pyopencv_features2d.hpp
@@ -0,0 +1,3 @@
+#ifdef HAVE_OPENCV_FEATURES2D
+typedef SimpleBlobDetector::Params SimpleBlobDetector_Params;
+#endif
\ No newline at end of file
diff --git a/modules/features2d/perf/opencl/perf_orb.cpp b/modules/features2d/perf/opencl/perf_orb.cpp
index a7d96f1..5d9aa2f 100644
--- a/modules/features2d/perf/opencl/perf_orb.cpp
+++ b/modules/features2d/perf/opencl/perf_orb.cpp
@@ -27,8 +27,8 @@ OCL_PERF_TEST_P(ORBFixture, ORB_Detect, ORB_IMAGES)
 
     OCL_TEST_CYCLE() detector->detect(frame, points, mask);
 
-    std::sort(points.begin(), points.end(), comparators::KeypointGreater());
-    SANITY_CHECK_KEYPOINTS(points, 1e-5);
+    EXPECT_GT(points.size(), 20u);
+    SANITY_CHECK_NOTHING();
 }
 
 OCL_PERF_TEST_P(ORBFixture, ORB_Extract, ORB_IMAGES)
@@ -47,13 +47,14 @@ OCL_PERF_TEST_P(ORBFixture, ORB_Extract, ORB_IMAGES)
     Ptr<ORB> detector = ORB::create(1500, 1.3f, 1);
     vector<KeyPoint> points;
     detector->detect(frame, points, mask);
-    std::sort(points.begin(), points.end(), comparators::KeypointGreater());
+    EXPECT_GT(points.size(), 20u);
 
     UMat descriptors;
 
     OCL_TEST_CYCLE() detector->compute(frame, points, descriptors);
 
-    SANITY_CHECK(descriptors);
+    EXPECT_EQ((size_t)descriptors.rows, points.size());
+    SANITY_CHECK_NOTHING();
 }
 
 OCL_PERF_TEST_P(ORBFixture, ORB_Full, ORB_IMAGES)
@@ -61,12 +62,6 @@ OCL_PERF_TEST_P(ORBFixture, ORB_Full, ORB_IMAGES)
     string filename = getDataPath(GetParam());
     Mat mframe = imread(filename, IMREAD_GRAYSCALE);
 
-    double desc_eps = 1e-6;
-#ifdef ANDROID
-    if (cv::ocl::Device::getDefault().isNVidia())
-        desc_eps = 2;
-#endif
-
     if (mframe.empty())
         FAIL() << "Unable to load source image " << filename;
 
@@ -81,9 +76,9 @@ OCL_PERF_TEST_P(ORBFixture, ORB_Full, ORB_IMAGES)
 
     OCL_TEST_CYCLE() detector->detectAndCompute(frame, mask, points, descriptors, false);
 
-    ::perf::sort(points, descriptors);
-    SANITY_CHECK_KEYPOINTS(points, 1e-5);
-    SANITY_CHECK(descriptors, desc_eps);
+    EXPECT_GT(points.size(), 20u);
+    EXPECT_EQ((size_t)descriptors.rows, points.size());
+    SANITY_CHECK_NOTHING();
 }
 
 } // ocl
diff --git a/modules/features2d/perf/perf_orb.cpp b/modules/features2d/perf/perf_orb.cpp
index 96cfc3e..0397125 100644
--- a/modules/features2d/perf/perf_orb.cpp
+++ b/modules/features2d/perf/perf_orb.cpp
@@ -27,8 +27,9 @@ PERF_TEST_P(orb, detect, testing::Values(ORB_IMAGES))
 
     TEST_CYCLE() detector->detect(frame, points, mask);
 
-    sort(points.begin(), points.end(), comparators::KeypointGreater());
-    SANITY_CHECK_KEYPOINTS(points, 1e-5);
+    EXPECT_GT(points.size(), 20u);
+
+    SANITY_CHECK_NOTHING();
 }
 
 PERF_TEST_P(orb, extract, testing::Values(ORB_IMAGES))
@@ -45,13 +46,15 @@ PERF_TEST_P(orb, extract, testing::Values(ORB_IMAGES))
     Ptr<ORB> detector = ORB::create(1500, 1.3f, 1);
     vector<KeyPoint> points;
     detector->detect(frame, points, mask);
-    sort(points.begin(), points.end(), comparators::KeypointGreater());
+
+    EXPECT_GT(points.size(), 20u);
 
     Mat descriptors;
 
     TEST_CYCLE() detector->compute(frame, points, descriptors);
 
-    SANITY_CHECK(descriptors);
+    EXPECT_EQ((size_t)descriptors.rows, points.size());
+    SANITY_CHECK_NOTHING();
 }
 
 PERF_TEST_P(orb, full, testing::Values(ORB_IMAGES))
@@ -71,7 +74,7 @@ PERF_TEST_P(orb, full, testing::Values(ORB_IMAGES))
 
     TEST_CYCLE() detector->detectAndCompute(frame, mask, points, descriptors, false);
 
-    perf::sort(points, descriptors);
-    SANITY_CHECK_KEYPOINTS(points, 1e-5);
-    SANITY_CHECK(descriptors);
+    EXPECT_GT(points.size(), 20u);
+    EXPECT_EQ((size_t)descriptors.rows, points.size());
+    SANITY_CHECK_NOTHING();
 }
diff --git a/modules/features2d/src/agast.cpp b/modules/features2d/src/agast.cpp
index b8db008..a0481f9 100644
--- a/modules/features2d/src/agast.cpp
+++ b/modules/features2d/src/agast.cpp
@@ -67,24 +67,24 @@ static void AGAST_5_8(InputArray _img, std::vector<KeyPoint>& keypoints, int thr
     int xsize = img.cols;
     int ysize = img.rows;
     size_t nExpectedCorners = keypoints.capacity();
-    register int x, y;
-    register int xsizeB = xsize - 2;
-    register int ysizeB = ysize - 1;
-    register int width;
+    int x, y;
+    int xsizeB = xsize - 2;
+    int ysizeB = ysize - 1;
+    int width;
 
     keypoints.resize(0);
 
     int pixel_5_8_[16];
     makeAgastOffsets(pixel_5_8_, (int)img.step, AgastFeatureDetector::AGAST_5_8);
 
-    register short offset0 = (short) pixel_5_8_[0];
-    register short offset1 = (short) pixel_5_8_[1];
-    register short offset2 = (short) pixel_5_8_[2];
-    register short offset3 = (short) pixel_5_8_[3];
-    register short offset4 = (short) pixel_5_8_[4];
-    register short offset5 = (short) pixel_5_8_[5];
-    register short offset6 = (short) pixel_5_8_[6];
-    register short offset7 = (short) pixel_5_8_[7];
+    short offset0 = (short) pixel_5_8_[0];
+    short offset1 = (short) pixel_5_8_[1];
+    short offset2 = (short) pixel_5_8_[2];
+    short offset3 = (short) pixel_5_8_[3];
+    short offset4 = (short) pixel_5_8_[4];
+    short offset5 = (short) pixel_5_8_[5];
+    short offset6 = (short) pixel_5_8_[6];
+    short offset7 = (short) pixel_5_8_[7];
 
     width = xsize;
 
@@ -100,9 +100,9 @@ static void AGAST_5_8(InputArray _img, std::vector<KeyPoint>& keypoints, int thr
                 break;
             else
             {
-                register const unsigned char* const ptr = img.ptr() + y*width + x;
-                register const int cb = *ptr + threshold;
-                register const int c_b = *ptr - threshold;
+                const unsigned char* const ptr = img.ptr() + y*width + x;
+                const int cb = *ptr + threshold;
+                const int c_b = *ptr - threshold;
                 if(ptr[offset0] > cb)
                   if(ptr[offset2] > cb)
                     if(ptr[offset3] > cb)
@@ -437,9 +437,9 @@ static void AGAST_5_8(InputArray _img, std::vector<KeyPoint>& keypoints, int thr
                 break;
             else
             {
-                register const unsigned char* const ptr = img.ptr() + y*width + x;
-                register const int cb = *ptr + threshold;
-                register const int c_b = *ptr - threshold;
+                const unsigned char* const ptr = img.ptr() + y*width + x;
+                const int cb = *ptr + threshold;
+                const int c_b = *ptr - threshold;
                 if(ptr[offset0] > cb)
                   if(ptr[offset2] > cb)
                     if(ptr[offset3] > cb)
@@ -793,7 +793,7 @@ static void AGAST_5_8(InputArray _img, std::vector<KeyPoint>& keypoints, int thr
                     keypoints.reserve(nExpectedCorners);
                 }
             }
-            keypoints.push_back(KeyPoint(Point2f((float)x, (float)y), 1.0f));
+            keypoints.push_back(KeyPoint(Point2f((float)x, (float)y), 7.0f));
             total++;
             goto homogeneous;
             success_structured:
@@ -810,7 +810,7 @@ static void AGAST_5_8(InputArray _img, std::vector<KeyPoint>& keypoints, int thr
                     keypoints.reserve(nExpectedCorners);
                 }
             }
-            keypoints.push_back(KeyPoint(Point2f((float)x, (float)y), 1.0f));
+            keypoints.push_back(KeyPoint(Point2f((float)x, (float)y), 7.0f));
             total++;
             goto structured;
         }
@@ -829,28 +829,28 @@ static void AGAST_7_12d(InputArray _img, std::vector<KeyPoint>& keypoints, int t
     int xsize = img.cols;
     int ysize = img.rows;
     size_t nExpectedCorners = keypoints.capacity();
-    register int x, y;
-    register int xsizeB = xsize - 4;
-    register int ysizeB = ysize - 3;
-    register int width;
+    int x, y;
+    int xsizeB = xsize - 4;
+    int ysizeB = ysize - 3;
+    int width;
 
     keypoints.resize(0);
 
     int pixel_7_12d_[16];
     makeAgastOffsets(pixel_7_12d_, (int)img.step, AgastFeatureDetector::AGAST_7_12d);
 
-    register short offset0 = (short) pixel_7_12d_[0];
-    register short offset1 = (short) pixel_7_12d_[1];
-    register short offset2 = (short) pixel_7_12d_[2];
-    register short offset3 = (short) pixel_7_12d_[3];
-    register short offset4 = (short) pixel_7_12d_[4];
-    register short offset5 = (short) pixel_7_12d_[5];
-    register short offset6 = (short) pixel_7_12d_[6];
-    register short offset7 = (short) pixel_7_12d_[7];
-    register short offset8 = (short) pixel_7_12d_[8];
-    register short offset9 = (short) pixel_7_12d_[9];
-    register short offset10 = (short) pixel_7_12d_[10];
-    register short offset11 = (short) pixel_7_12d_[11];
+    short offset0 = (short) pixel_7_12d_[0];
+    short offset1 = (short) pixel_7_12d_[1];
+    short offset2 = (short) pixel_7_12d_[2];
+    short offset3 = (short) pixel_7_12d_[3];
+    short offset4 = (short) pixel_7_12d_[4];
+    short offset5 = (short) pixel_7_12d_[5];
+    short offset6 = (short) pixel_7_12d_[6];
+    short offset7 = (short) pixel_7_12d_[7];
+    short offset8 = (short) pixel_7_12d_[8];
+    short offset9 = (short) pixel_7_12d_[9];
+    short offset10 = (short) pixel_7_12d_[10];
+    short offset11 = (short) pixel_7_12d_[11];
 
     width = xsize;
 
@@ -866,9 +866,9 @@ static void AGAST_7_12d(InputArray _img, std::vector<KeyPoint>& keypoints, int t
                 break;
             else
             {
-                register const unsigned char* const ptr = img.ptr() + y*width + x;
-                register const int cb = *ptr + threshold;
-                register const int c_b = *ptr - threshold;
+                const unsigned char* const ptr = img.ptr() + y*width + x;
+                const int cb = *ptr + threshold;
+                const int c_b = *ptr - threshold;
                 if(ptr[offset0] > cb)
                   if(ptr[offset5] > cb)
                     if(ptr[offset2] > cb)
@@ -2048,9 +2048,9 @@ static void AGAST_7_12d(InputArray _img, std::vector<KeyPoint>& keypoints, int t
                 break;
             else
             {
-                register const unsigned char* const ptr = img.ptr() + y*width + x;
-                register const int cb = *ptr + threshold;
-                register const int c_b = *ptr - threshold;
+                const unsigned char* const ptr = img.ptr() + y*width + x;
+                const int cb = *ptr + threshold;
+                const int c_b = *ptr - threshold;
                 if(ptr[offset0] > cb)
                   if(ptr[offset5] > cb)
                     if(ptr[offset2] > cb)
@@ -3237,7 +3237,7 @@ static void AGAST_7_12d(InputArray _img, std::vector<KeyPoint>& keypoints, int t
                     keypoints.reserve(nExpectedCorners);
                 }
             }
-            keypoints.push_back(KeyPoint(Point2f((float)x, (float)y), 1.0f));
+            keypoints.push_back(KeyPoint(Point2f((float)x, (float)y), 7.0f));
             total++;
             goto homogeneous;
           success_structured:
@@ -3254,7 +3254,7 @@ static void AGAST_7_12d(InputArray _img, std::vector<KeyPoint>& keypoints, int t
                     keypoints.reserve(nExpectedCorners);
                 }
             }
-            keypoints.push_back(KeyPoint(Point2f((float)x, (float)y), 1.0f));
+            keypoints.push_back(KeyPoint(Point2f((float)x, (float)y), 7.0f));
             total++;
             goto structured;
         }
@@ -3274,28 +3274,28 @@ static void AGAST_7_12s(InputArray _img, std::vector<KeyPoint>& keypoints, int t
     int xsize = img.cols;
     int ysize = img.rows;
     size_t nExpectedCorners = keypoints.capacity();
-    register int x, y;
-    register int xsizeB=xsize - 3; //2, +1 due to faster test x>xsizeB
-    register int ysizeB=ysize - 2;
-    register int width;
+    int x, y;
+    int xsizeB=xsize - 3; //2, +1 due to faster test x>xsizeB
+    int ysizeB=ysize - 2;
+    int width;
 
     keypoints.resize(0);
 
     int pixel_7_12s_[16];
     makeAgastOffsets(pixel_7_12s_, (int)img.step, AgastFeatureDetector::AGAST_7_12s);
 
-    register short offset0 = (short) pixel_7_12s_[0];
-    register short offset1 = (short) pixel_7_12s_[1];
-    register short offset2 = (short) pixel_7_12s_[2];
-    register short offset3 = (short) pixel_7_12s_[3];
-    register short offset4 = (short) pixel_7_12s_[4];
-    register short offset5 = (short) pixel_7_12s_[5];
-    register short offset6 = (short) pixel_7_12s_[6];
-    register short offset7 = (short) pixel_7_12s_[7];
-    register short offset8 = (short) pixel_7_12s_[8];
-    register short offset9 = (short) pixel_7_12s_[9];
-    register short offset10 = (short) pixel_7_12s_[10];
-    register short offset11 = (short) pixel_7_12s_[11];
+    short offset0 = (short) pixel_7_12s_[0];
+    short offset1 = (short) pixel_7_12s_[1];
+    short offset2 = (short) pixel_7_12s_[2];
+    short offset3 = (short) pixel_7_12s_[3];
+    short offset4 = (short) pixel_7_12s_[4];
+    short offset5 = (short) pixel_7_12s_[5];
+    short offset6 = (short) pixel_7_12s_[6];
+    short offset7 = (short) pixel_7_12s_[7];
+    short offset8 = (short) pixel_7_12s_[8];
+    short offset9 = (short) pixel_7_12s_[9];
+    short offset10 = (short) pixel_7_12s_[10];
+    short offset11 = (short) pixel_7_12s_[11];
 
     width = xsize;
 
@@ -3311,9 +3311,9 @@ static void AGAST_7_12s(InputArray _img, std::vector<KeyPoint>& keypoints, int t
                 break;
             else
             {
-                register const unsigned char* const ptr = img.ptr() + y*width + x;
-                register const int cb = *ptr + threshold;
-                register const int c_b = *ptr - threshold;
+                const unsigned char* const ptr = img.ptr() + y*width + x;
+                const int cb = *ptr + threshold;
+                const int c_b = *ptr - threshold;
                 if(ptr[offset0] > cb)
                   if(ptr[offset2] > cb)
                     if(ptr[offset5] > cb)
@@ -4349,9 +4349,9 @@ static void AGAST_7_12s(InputArray _img, std::vector<KeyPoint>& keypoints, int t
                 break;
             else
             {
-                register const unsigned char* const ptr = img.ptr() + y*width + x;
-                register const int cb = *ptr + threshold;
-                register const int c_b = *ptr - threshold;
+                const unsigned char* const ptr = img.ptr() + y*width + x;
+                const int cb = *ptr + threshold;
+                const int c_b = *ptr - threshold;
                 if(ptr[offset0] > cb)
                   if(ptr[offset2] > cb)
                     if(ptr[offset5] > cb)
@@ -5319,7 +5319,7 @@ static void AGAST_7_12s(InputArray _img, std::vector<KeyPoint>& keypoints, int t
                     keypoints.reserve(nExpectedCorners);
                 }
             }
-            keypoints.push_back(KeyPoint(Point2f((float)x, (float)y), 1.0f));
+            keypoints.push_back(KeyPoint(Point2f((float)x, (float)y), 7.0f));
             total++;
             goto homogeneous;
           success_structured:
@@ -5336,7 +5336,7 @@ static void AGAST_7_12s(InputArray _img, std::vector<KeyPoint>& keypoints, int t
                     keypoints.reserve(nExpectedCorners);
                 }
             }
-            keypoints.push_back(KeyPoint(Point2f((float)x, (float)y), 1.0f));
+            keypoints.push_back(KeyPoint(Point2f((float)x, (float)y), 7.0f));
             total++;
             goto structured;
         }
@@ -5355,32 +5355,32 @@ static void OAST_9_16(InputArray _img, std::vector<KeyPoint>& keypoints, int thr
     int xsize = img.cols;
     int ysize = img.rows;
     size_t nExpectedCorners = keypoints.capacity();
-    register int x, y;
-    register int xsizeB=xsize - 4;
-    register int ysizeB=ysize - 3;
-    register int width;
+    int x, y;
+    int xsizeB=xsize - 4;
+    int ysizeB=ysize - 3;
+    int width;
 
     keypoints.resize(0);
 
     int pixel_9_16_[16];
     makeAgastOffsets(pixel_9_16_, (int)img.step, AgastFeatureDetector::OAST_9_16);
 
-    register short offset0 = (short) pixel_9_16_[0];
-    register short offset1 = (short) pixel_9_16_[1];
-    register short offset2 = (short) pixel_9_16_[2];
-    register short offset3 = (short) pixel_9_16_[3];
-    register short offset4 = (short) pixel_9_16_[4];
-    register short offset5 = (short) pixel_9_16_[5];
-    register short offset6 = (short) pixel_9_16_[6];
-    register short offset7 = (short) pixel_9_16_[7];
-    register short offset8 = (short) pixel_9_16_[8];
-    register short offset9 = (short) pixel_9_16_[9];
-    register short offset10 = (short) pixel_9_16_[10];
-    register short offset11 = (short) pixel_9_16_[11];
-    register short offset12 = (short) pixel_9_16_[12];
-    register short offset13 = (short) pixel_9_16_[13];
-    register short offset14 = (short) pixel_9_16_[14];
-    register short offset15 = (short) pixel_9_16_[15];
+    short offset0 = (short) pixel_9_16_[0];
+    short offset1 = (short) pixel_9_16_[1];
+    short offset2 = (short) pixel_9_16_[2];
+    short offset3 = (short) pixel_9_16_[3];
+    short offset4 = (short) pixel_9_16_[4];
+    short offset5 = (short) pixel_9_16_[5];
+    short offset6 = (short) pixel_9_16_[6];
+    short offset7 = (short) pixel_9_16_[7];
+    short offset8 = (short) pixel_9_16_[8];
+    short offset9 = (short) pixel_9_16_[9];
+    short offset10 = (short) pixel_9_16_[10];
+    short offset11 = (short) pixel_9_16_[11];
+    short offset12 = (short) pixel_9_16_[12];
+    short offset13 = (short) pixel_9_16_[13];
+    short offset14 = (short) pixel_9_16_[14];
+    short offset15 = (short) pixel_9_16_[15];
 
     width = xsize;
 
@@ -5394,9 +5394,9 @@ static void OAST_9_16(InputArray _img, std::vector<KeyPoint>& keypoints, int thr
                 break;
             else
             {
-                register const unsigned char* const ptr = img.ptr() + y*width + x;
-                register const int cb = *ptr + threshold;
-                register const int c_b = *ptr - threshold;
+                const unsigned char* const ptr = img.ptr() + y*width + x;
+                const int cb = *ptr + threshold;
+                const int c_b = *ptr - threshold;
                 if(ptr[offset0] > cb)
                   if(ptr[offset2] > cb)
                     if(ptr[offset4] > cb)
@@ -7440,7 +7440,7 @@ static void OAST_9_16(InputArray _img, std::vector<KeyPoint>& keypoints, int thr
                     keypoints.reserve(nExpectedCorners);
                 }
             }
-            keypoints.push_back(KeyPoint(Point2f((float)x, (float)y), 1.0f));
+            keypoints.push_back(KeyPoint(Point2f((float)x, (float)y), 7.0f));
             total++;
         }
     }
@@ -7817,10 +7817,10 @@ static void AGAST_ALL(InputArray _img, std::vector<KeyPoint>& keypoints, int thr
     int xsize = img.cols;
     int ysize = img.rows;
     size_t nExpectedCorners = keypoints.capacity();
-    register int x, y;
-    register int xsizeB = xsize - (agastbase + 2);
-    register int ysizeB = ysize - (agastbase + 1);
-    register int width;
+    int x, y;
+    int xsizeB = xsize - (agastbase + 2);
+    int ysizeB = ysize - (agastbase + 1);
+    int width;
 
     keypoints.resize(0);
 
@@ -7841,7 +7841,7 @@ static void AGAST_ALL(InputArray _img, std::vector<KeyPoint>& keypoints, int thr
                 break;
             else
             {
-                register const unsigned char* const ptr = img.ptr() + y*width + x;
+                const unsigned char* const ptr = img.ptr() + y*width + x;
                 result = agast_tree_search(table_struct1, pixel, ptr, threshold);
                 switch (result)
                 {
@@ -7863,7 +7863,7 @@ static void AGAST_ALL(InputArray _img, std::vector<KeyPoint>& keypoints, int thr
                 break;
             else
             {
-                register const unsigned char* const ptr = img.ptr() + y*width + x;
+                const unsigned char* const ptr = img.ptr() + y*width + x;
                 result = agast_tree_search(table_struct2, pixel, ptr, threshold);
                 switch (result)
                 {
@@ -7892,7 +7892,7 @@ static void AGAST_ALL(InputArray _img, std::vector<KeyPoint>& keypoints, int thr
                     keypoints.reserve(nExpectedCorners);
                 }
             }
-            keypoints.push_back(KeyPoint(Point2f((float)x, (float)y), 1.0f));
+            keypoints.push_back(KeyPoint(Point2f((float)x, (float)y), 7.0f));
             total++;
             goto homogeneous;
             success_structured:
@@ -7909,7 +7909,7 @@ static void AGAST_ALL(InputArray _img, std::vector<KeyPoint>& keypoints, int thr
                     keypoints.reserve(nExpectedCorners);
                 }
             }
-            keypoints.push_back(KeyPoint(Point2f((float)x, (float)y), 1.0f));
+            keypoints.push_back(KeyPoint(Point2f((float)x, (float)y), 7.0f));
             total++;
             goto structured;
         }
@@ -7940,6 +7940,8 @@ static void OAST_9_16(InputArray _img, std::vector<KeyPoint>& keypoints, int thr
 
 void AGAST(InputArray _img, std::vector<KeyPoint>& keypoints, int threshold, bool nonmax_suppression)
 {
+    CV_INSTRUMENT_REGION()
+
     AGAST(_img, keypoints, threshold, nonmax_suppression, AgastFeatureDetector::OAST_9_16);
 }
 
@@ -7952,6 +7954,8 @@ public:
 
     void detect( InputArray _image, std::vector<KeyPoint>& keypoints, InputArray _mask )
     {
+        CV_INSTRUMENT_REGION()
+
         Mat mask = _mask.getMat(), grayImage;
         UMat ugrayImage;
         _InputArray gray = _image;
@@ -7961,6 +7965,7 @@ public:
             cvtColor( _image, ogray, COLOR_BGR2GRAY );
             gray = ogray;
         }
+        keypoints.clear();
         AGAST( gray, keypoints, threshold, nonmaxSuppression, type );
         KeyPointsFilter::runByPixelsMask( keypoints, mask );
     }
@@ -8006,6 +8011,7 @@ Ptr<AgastFeatureDetector> AgastFeatureDetector::create( int threshold, bool nonm
 
 void AGAST(InputArray _img, std::vector<KeyPoint>& keypoints, int threshold, bool nonmax_suppression, int type)
 {
+    CV_INSTRUMENT_REGION()
 
     std::vector<KeyPoint> kpts;
 
@@ -8032,7 +8038,7 @@ void AGAST(InputArray _img, std::vector<KeyPoint>& keypoints, int threshold, boo
     makeAgastOffsets(pixel_, (int)img.step, type);
 
     std::vector<KeyPoint>::iterator kpt;
-    for(kpt = kpts.begin(); kpt != kpts.end(); kpt++)
+    for(kpt = kpts.begin(); kpt != kpts.end(); ++kpt)
     {
         switch(type) {
           case AgastFeatureDetector::AGAST_5_8:
@@ -8096,19 +8102,19 @@ void AGAST(InputArray _img, std::vector<KeyPoint>& keypoints, int threshold, boo
                     && (kpts[lastRowCorner_ind].pt.y == lastRow) )
                     lastRowCorner_ind++;
 
-                    if( (kpts[lastRowCorner_ind].pt.x == currCorner->pt.x)
-                     && (lastRowCorner_ind != curr_idx) )
-                    {
-                        size_t w = lastRowCorner_ind;
-                        // find the maximum in this block
-                        while(nmsFlags[w] != -1)
-                            w = nmsFlags[w];
+                if( (kpts[lastRowCorner_ind].pt.x == currCorner->pt.x)
+                 && (lastRowCorner_ind != curr_idx) )
+                {
+                    size_t w = lastRowCorner_ind;
+                    // find the maximum in this block
+                    while(nmsFlags[w] != -1)
+                        w = nmsFlags[w];
 
-                        if(kpts[curr_idx].response < kpts[w].response)
-                            nmsFlags[curr_idx] = (int)w;
-                        else
-                            nmsFlags[w] = (int)curr_idx;
-                    }
+                    if(kpts[curr_idx].response < kpts[w].response)
+                        nmsFlags[curr_idx] = (int)w;
+                    else
+                        nmsFlags[w] = (int)curr_idx;
+                }
             }
 
             // check left
@@ -8148,7 +8154,7 @@ void AGAST(InputArray _img, std::vector<KeyPoint>& keypoints, int threshold, boo
                     }
                 }
             }
-            currCorner++;
+            ++currCorner;
         }
 
         // collecting maximum corners
diff --git a/modules/features2d/src/agast_score.cpp b/modules/features2d/src/agast_score.cpp
index 9a8163b..ad9b448 100644
--- a/modules/features2d/src/agast_score.cpp
+++ b/modules/features2d/src/agast_score.cpp
@@ -98,27 +98,27 @@ int agast_cornerScore<AgastFeatureDetector::OAST_9_16>(const uchar* ptr, const i
     int bmax = 255;
     int b_test = (bmax + bmin) / 2;
 
-    register short offset0 = (short) pixel[0];
-    register short offset1 = (short) pixel[1];
-    register short offset2 = (short) pixel[2];
-    register short offset3 = (short) pixel[3];
-    register short offset4 = (short) pixel[4];
-    register short offset5 = (short) pixel[5];
-    register short offset6 = (short) pixel[6];
-    register short offset7 = (short) pixel[7];
-    register short offset8 = (short) pixel[8];
-    register short offset9 = (short) pixel[9];
-    register short offset10 = (short) pixel[10];
-    register short offset11 = (short) pixel[11];
-    register short offset12 = (short) pixel[12];
-    register short offset13 = (short) pixel[13];
-    register short offset14 = (short) pixel[14];
-    register short offset15 = (short) pixel[15];
+    short offset0 = (short) pixel[0];
+    short offset1 = (short) pixel[1];
+    short offset2 = (short) pixel[2];
+    short offset3 = (short) pixel[3];
+    short offset4 = (short) pixel[4];
+    short offset5 = (short) pixel[5];
+    short offset6 = (short) pixel[6];
+    short offset7 = (short) pixel[7];
+    short offset8 = (short) pixel[8];
+    short offset9 = (short) pixel[9];
+    short offset10 = (short) pixel[10];
+    short offset11 = (short) pixel[11];
+    short offset12 = (short) pixel[12];
+    short offset13 = (short) pixel[13];
+    short offset14 = (short) pixel[14];
+    short offset15 = (short) pixel[15];
 
     while(true)
     {
-        register const int cb = *ptr + b_test;
-        register const int c_b = *ptr - b_test;
+        const int cb = *ptr + b_test;
+        const int c_b = *ptr - b_test;
         if(ptr[offset0] > cb)
           if(ptr[offset2] > cb)
             if(ptr[offset4] > cb)
@@ -2173,23 +2173,23 @@ int agast_cornerScore<AgastFeatureDetector::AGAST_7_12d>(const uchar* ptr, const
     int bmax = 255;
     int b_test = (bmax + bmin)/2;
 
-    register short offset0 = (short) pixel[0];
-    register short offset1 = (short) pixel[1];
-    register short offset2 = (short) pixel[2];
-    register short offset3 = (short) pixel[3];
-    register short offset4 = (short) pixel[4];
-    register short offset5 = (short) pixel[5];
-    register short offset6 = (short) pixel[6];
-    register short offset7 = (short) pixel[7];
-    register short offset8 = (short) pixel[8];
-    register short offset9 = (short) pixel[9];
-    register short offset10 = (short) pixel[10];
-    register short offset11 = (short) pixel[11];
+    short offset0 = (short) pixel[0];
+    short offset1 = (short) pixel[1];
+    short offset2 = (short) pixel[2];
+    short offset3 = (short) pixel[3];
+    short offset4 = (short) pixel[4];
+    short offset5 = (short) pixel[5];
+    short offset6 = (short) pixel[6];
+    short offset7 = (short) pixel[7];
+    short offset8 = (short) pixel[8];
+    short offset9 = (short) pixel[9];
+    short offset10 = (short) pixel[10];
+    short offset11 = (short) pixel[11];
 
     while(true)
     {
-        register const int cb = *ptr + b_test;
-        register const int c_b = *ptr - b_test;
+        const int cb = *ptr + b_test;
+        const int c_b = *ptr - b_test;
         if(ptr[offset0] > cb)
           if(ptr[offset5] > cb)
             if(ptr[offset2] > cb)
@@ -3385,23 +3385,23 @@ int agast_cornerScore<AgastFeatureDetector::AGAST_7_12s>(const uchar* ptr, const
     int bmax = 255;
     int b_test = (bmax + bmin)/2;
 
-    register short offset0 = (short) pixel[0];
-    register short offset1 = (short) pixel[1];
-    register short offset2 = (short) pixel[2];
-    register short offset3 = (short) pixel[3];
-    register short offset4 = (short) pixel[4];
-    register short offset5 = (short) pixel[5];
-    register short offset6 = (short) pixel[6];
-    register short offset7 = (short) pixel[7];
-    register short offset8 = (short) pixel[8];
-    register short offset9 = (short) pixel[9];
-    register short offset10 = (short) pixel[10];
-    register short offset11 = (short) pixel[11];
+    short offset0 = (short) pixel[0];
+    short offset1 = (short) pixel[1];
+    short offset2 = (short) pixel[2];
+    short offset3 = (short) pixel[3];
+    short offset4 = (short) pixel[4];
+    short offset5 = (short) pixel[5];
+    short offset6 = (short) pixel[6];
+    short offset7 = (short) pixel[7];
+    short offset8 = (short) pixel[8];
+    short offset9 = (short) pixel[9];
+    short offset10 = (short) pixel[10];
+    short offset11 = (short) pixel[11];
 
     while(true)
     {
-        register const int cb = *ptr + b_test;
-        register const int c_b = *ptr - b_test;
+        const int cb = *ptr + b_test;
+        const int c_b = *ptr - b_test;
         if(ptr[offset0] > cb)
           if(ptr[offset5] > cb)
             if(ptr[offset2] < c_b)
@@ -9019,19 +9019,19 @@ int agast_cornerScore<AgastFeatureDetector::AGAST_5_8>(const uchar* ptr, const i
     int bmax = 255;
     int b_test = (bmax + bmin)/2;
 
-    register short offset0 = (short) pixel[0];
-    register short offset1 = (short) pixel[1];
-    register short offset2 = (short) pixel[2];
-    register short offset3 = (short) pixel[3];
-    register short offset4 = (short) pixel[4];
-    register short offset5 = (short) pixel[5];
-    register short offset6 = (short) pixel[6];
-    register short offset7 = (short) pixel[7];
+    short offset0 = (short) pixel[0];
+    short offset1 = (short) pixel[1];
+    short offset2 = (short) pixel[2];
+    short offset3 = (short) pixel[3];
+    short offset4 = (short) pixel[4];
+    short offset5 = (short) pixel[5];
+    short offset6 = (short) pixel[6];
+    short offset7 = (short) pixel[7];
 
     while(true)
     {
-        register const int cb = *ptr + b_test;
-        register const int c_b = *ptr - b_test;
+        const int cb = *ptr + b_test;
+        const int c_b = *ptr - b_test;
         if(ptr[offset0] > cb)
           if(ptr[offset2] > cb)
             if(ptr[offset3] > cb)
@@ -9377,11 +9377,11 @@ int agast_cornerScore<AgastFeatureDetector::AGAST_5_8>(const uchar* ptr, const i
 
 int agast_tree_search(const uint32_t table_struct32[], int pixel_[], const unsigned char* const ptr, int threshold)
 {
-    register const int cb = *ptr + threshold;
-    register const int c_b = *ptr - threshold;
-    register int index;
-    register int offset;
-    register int cmpresult;
+    const int cb = *ptr + threshold;
+    const int c_b = *ptr - threshold;
+    int index;
+    int offset;
+    int cmpresult;
     index = 0;
     while ((table_struct32[index]>>16)!=0)
     {
diff --git a/modules/features2d/src/akaze.cpp b/modules/features2d/src/akaze.cpp
index bfe91af..2297194 100644
--- a/modules/features2d/src/akaze.cpp
+++ b/modules/features2d/src/akaze.cpp
@@ -167,6 +167,8 @@ namespace cv
                               OutputArray descriptors,
                               bool useProvidedKeypoints)
         {
+            CV_INSTRUMENT_REGION()
+
             Mat img = image.getMat();
             if (img.channels() > 1)
                 cvtColor(image, img, COLOR_BGR2GRAY);
@@ -198,6 +200,8 @@ namespace cv
             if (!useProvidedKeypoints)
             {
                 impl.Feature_Detection(keypoints);
+                if( !descriptors.needed() )
+                    impl.Compute_Keypoints_Orientation(keypoints);
             }
 
             if (!mask.empty())
@@ -217,6 +221,7 @@ namespace cv
 
         void write(FileStorage& fs) const
         {
+            writeFormat(fs);
             fs << "descriptor" << descriptor;
             fs << "descriptor_channels" << descriptor_channels;
             fs << "descriptor_size" << descriptor_size;
diff --git a/modules/features2d/src/bagofwords.cpp b/modules/features2d/src/bagofwords.cpp
index 0d6d2f4..31fb19d 100644
--- a/modules/features2d/src/bagofwords.cpp
+++ b/modules/features2d/src/bagofwords.cpp
@@ -89,13 +89,11 @@ BOWKMeansTrainer::BOWKMeansTrainer( int _clusterCount, const TermCriteria& _term
 
 Mat BOWKMeansTrainer::cluster() const
 {
-    CV_Assert( !descriptors.empty() );
+    CV_INSTRUMENT_REGION()
 
-    int descCount = 0;
-    for( size_t i = 0; i < descriptors.size(); i++ )
-        descCount += descriptors[i].rows;
+    CV_Assert( !descriptors.empty() );
 
-    Mat mergedDescriptors( descCount, descriptors[0].cols, descriptors[0].type() );
+    Mat mergedDescriptors( descriptorsCount(), descriptors[0].cols, descriptors[0].type() );
     for( size_t i = 0, start = 0; i < descriptors.size(); i++ )
     {
         Mat submut = mergedDescriptors.rowRange((int)start, (int)(start + descriptors[i].rows));
@@ -110,6 +108,8 @@ BOWKMeansTrainer::~BOWKMeansTrainer()
 
 Mat BOWKMeansTrainer::cluster( const Mat& _descriptors ) const
 {
+    CV_INSTRUMENT_REGION()
+
     Mat labels, vocabulary;
     kmeans( _descriptors, clusterCount, labels, termcrit, attempts, flags, vocabulary );
     return vocabulary;
@@ -143,6 +143,8 @@ const Mat& BOWImgDescriptorExtractor::getVocabulary() const
 void BOWImgDescriptorExtractor::compute( InputArray image, std::vector<KeyPoint>& keypoints, OutputArray imgDescriptor,
                                          std::vector<std::vector<int> >* pointIdxsOfClusters, Mat* descriptors )
 {
+    CV_INSTRUMENT_REGION()
+
     imgDescriptor.release();
 
     if( keypoints.empty() )
@@ -172,6 +174,8 @@ int BOWImgDescriptorExtractor::descriptorType() const
 
 void BOWImgDescriptorExtractor::compute( InputArray keypointDescriptors, OutputArray _imgDescriptor, std::vector<std::vector<int> >* pointIdxsOfClusters )
 {
+    CV_INSTRUMENT_REGION()
+
     CV_Assert( !vocabulary.empty() );
 
     int clusterCount = descriptorSize(); // = vocabulary.rows
diff --git a/modules/features2d/src/blobdetector.cpp b/modules/features2d/src/blobdetector.cpp
index aa8593a..ac55341 100644
--- a/modules/features2d/src/blobdetector.cpp
+++ b/modules/features2d/src/blobdetector.cpp
@@ -184,11 +184,14 @@ void SimpleBlobDetectorImpl::read( const cv::FileNode& fn )
 
 void SimpleBlobDetectorImpl::write( cv::FileStorage& fs ) const
 {
+    writeFormat(fs);
     params.write(fs);
 }
 
 void SimpleBlobDetectorImpl::findBlobs(InputArray _image, InputArray _binaryImage, std::vector<Center> &centers) const
 {
+    CV_INSTRUMENT_REGION()
+
     Mat image = _image.getMat(), binaryImage = _binaryImage.getMat();
     (void)image;
     centers.clear();
@@ -303,6 +306,8 @@ void SimpleBlobDetectorImpl::findBlobs(InputArray _image, InputArray _binaryImag
 
 void SimpleBlobDetectorImpl::detect(InputArray image, std::vector<cv::KeyPoint>& keypoints, InputArray)
 {
+    CV_INSTRUMENT_REGION()
+
     //TODO: support mask
     keypoints.clear();
     Mat grayscaleImage;
diff --git a/modules/features2d/src/brisk.cpp b/modules/features2d/src/brisk.cpp
index 3e80c5d..d6e88a1 100644
--- a/modules/features2d/src/brisk.cpp
+++ b/modules/features2d/src/brisk.cpp
@@ -2046,13 +2046,13 @@ BriskScaleSpace::subpixel2D(const int s_0_0, const int s_0_1, const int s_0_2, c
     if (max1 > max2)
     {
       delta_x = delta_x1;
-      delta_y = delta_x1;
+      delta_y = delta_y1;
       return max1;
     }
     else
     {
       delta_x = delta_x2;
-      delta_y = delta_x2;
+      delta_y = delta_y2;
       return max2;
     }
   }
diff --git a/modules/features2d/src/draw.cpp b/modules/features2d/src/draw.cpp
index 63410e7..357662f 100644
--- a/modules/features2d/src/draw.cpp
+++ b/modules/features2d/src/draw.cpp
@@ -91,6 +91,8 @@ static inline void _drawKeypoint( InputOutputArray img, const KeyPoint& p, const
 void drawKeypoints( InputArray image, const std::vector<KeyPoint>& keypoints, InputOutputArray outImage,
                     const Scalar& _color, int flags )
 {
+    CV_INSTRUMENT_REGION()
+
     if( !(flags & DrawMatchesFlags::DRAW_OVER_OUTIMG) )
     {
         if( image.type() == CV_8UC3 )
diff --git a/modules/features2d/src/evaluation.cpp b/modules/features2d/src/evaluation.cpp
index 3863203..5ea8821 100644
--- a/modules/features2d/src/evaluation.cpp
+++ b/modules/features2d/src/evaluation.cpp
@@ -179,6 +179,8 @@ void EllipticKeyPoint::calcProjection( const Mat_<double>& H, EllipticKeyPoint&
 
 void EllipticKeyPoint::convert( const std::vector<KeyPoint>& src, std::vector<EllipticKeyPoint>& dst )
 {
+    CV_INSTRUMENT_REGION()
+
     if( !src.empty() )
     {
         dst.resize(src.size());
@@ -194,6 +196,8 @@ void EllipticKeyPoint::convert( const std::vector<KeyPoint>& src, std::vector<El
 
 void EllipticKeyPoint::convert( const std::vector<EllipticKeyPoint>& src, std::vector<KeyPoint>& dst )
 {
+    CV_INSTRUMENT_REGION()
+
     if( !src.empty() )
     {
         dst.resize(src.size());
@@ -456,6 +460,8 @@ void cv::evaluateFeatureDetector( const Mat& img1, const Mat& img2, const Mat& H
                               float& repeatability, int& correspCount,
                               const Ptr<FeatureDetector>& _fdetector )
 {
+    CV_INSTRUMENT_REGION()
+
     Ptr<FeatureDetector> fdetector(_fdetector);
     std::vector<KeyPoint> *keypoints1, *keypoints2, buf1, buf2;
     keypoints1 = _keypoints1 != 0 ? _keypoints1 : &buf1;
@@ -492,6 +498,8 @@ void cv::computeRecallPrecisionCurve( const std::vector<std::vector<DMatch> >& m
                                       const std::vector<std::vector<uchar> >& correctMatches1to2Mask,
                                       std::vector<Point2f>& recallPrecisionCurve )
 {
+    CV_INSTRUMENT_REGION()
+
     CV_Assert( matches1to2.size() == correctMatches1to2Mask.size() );
 
     std::vector<DMatchForEvaluation> allMatches;
@@ -526,6 +534,8 @@ void cv::computeRecallPrecisionCurve( const std::vector<std::vector<DMatch> >& m
 
 float cv::getRecall( const std::vector<Point2f>& recallPrecisionCurve, float l_precision )
 {
+    CV_INSTRUMENT_REGION()
+
     int nearestPointIndex = getNearestPoint( recallPrecisionCurve, l_precision );
 
     float recall = -1.f;
@@ -538,6 +548,8 @@ float cv::getRecall( const std::vector<Point2f>& recallPrecisionCurve, float l_p
 
 int cv::getNearestPoint( const std::vector<Point2f>& recallPrecisionCurve, float l_precision )
 {
+    CV_INSTRUMENT_REGION()
+
     int nearestPointIndex = -1;
 
     if( l_precision >= 0 && l_precision <= 1 )
diff --git a/modules/features2d/src/fast.cpp b/modules/features2d/src/fast.cpp
index 42dacb5..e731ded 100644
--- a/modules/features2d/src/fast.cpp
+++ b/modules/features2d/src/fast.cpp
@@ -45,6 +45,7 @@ The references are:
 #include "fast_score.hpp"
 #include "opencl_kernels_features2d.hpp"
 
+#include "opencv2/core/openvx/ovx_defs.hpp"
 #if defined _MSC_VER
 # pragma warning( disable : 4127)
 #endif
@@ -329,8 +330,71 @@ static bool ocl_FAST( InputArray _img, std::vector<KeyPoint>& keypoints,
 }
 #endif
 
+
+#ifdef HAVE_OPENVX
+static bool openvx_FAST(InputArray _img, std::vector<KeyPoint>& keypoints,
+                        int _threshold, bool nonmaxSuppression, int type)
+{
+    using namespace ivx;
+
+    // Nonmax suppression is done differently in OpenCV than in OpenVX
+    // 9/16 is the only supported mode in OpenVX
+    if(nonmaxSuppression || type != FastFeatureDetector::TYPE_9_16)
+        return false;
+
+    Mat imgMat = _img.getMat();
+    if(imgMat.empty() || imgMat.type() != CV_8UC1)
+        return false;
+
+    try
+    {
+        Context context = Context::create();
+        Image img = Image::createFromHandle(context, Image::matTypeToFormat(imgMat.type()),
+                                            Image::createAddressing(imgMat), (void*)imgMat.data);
+        ivx::Scalar threshold = ivx::Scalar::create<VX_TYPE_FLOAT32>(context, _threshold);
+        vx_size capacity = imgMat.cols * imgMat.rows;
+        Array corners = Array::create(context, VX_TYPE_KEYPOINT, capacity);
+
+        ivx::Scalar numCorners = ivx::Scalar::create<VX_TYPE_SIZE>(context, 0);
+
+        IVX_CHECK_STATUS(vxuFastCorners(context, img, threshold, (vx_bool)nonmaxSuppression, corners, numCorners));
+
+        size_t nPoints = numCorners.getValue<vx_size>();
+        keypoints.clear(); keypoints.reserve(nPoints);
+        std::vector<vx_keypoint_t> vxCorners;
+        corners.copyTo(vxCorners);
+        for(size_t i = 0; i < nPoints; i++)
+        {
+            vx_keypoint_t kp = vxCorners[i];
+            //if nonmaxSuppression is false, kp.strength is undefined
+            keypoints.push_back(KeyPoint((float)kp.x, (float)kp.y, 7.f, -1, kp.strength));
+        }
+
+#ifdef VX_VERSION_1_1
+        //we should take user memory back before release
+        //(it's not done automatically according to standard)
+        img.swapHandle();
+#endif
+    }
+    catch (RuntimeError & e)
+    {
+        VX_DbgThrow(e.what());
+    }
+    catch (WrapperError & e)
+    {
+        VX_DbgThrow(e.what());
+    }
+
+    return true;
+}
+
+#endif
+
+
 void FAST(InputArray _img, std::vector<KeyPoint>& keypoints, int threshold, bool nonmax_suppression, int type)
 {
+    CV_INSTRUMENT_REGION()
+
 #ifdef HAVE_OPENCL
   if( ocl::useOpenCL() && _img.isUMat() && type == FastFeatureDetector::TYPE_9_16 &&
       ocl_FAST(_img, keypoints, threshold, nonmax_suppression, 10000))
@@ -340,6 +404,9 @@ void FAST(InputArray _img, std::vector<KeyPoint>& keypoints, int threshold, bool
   }
 #endif
 
+    CV_OVX_RUN(true,
+               openvx_FAST(_img, keypoints, threshold, nonmax_suppression, type))
+
   switch(type) {
     case FastFeatureDetector::TYPE_5_8:
       FAST_t<8>(_img, keypoints, threshold, nonmax_suppression);
@@ -360,6 +427,8 @@ void FAST(InputArray _img, std::vector<KeyPoint>& keypoints, int threshold, bool
 
 void FAST(InputArray _img, std::vector<KeyPoint>& keypoints, int threshold, bool nonmax_suppression)
 {
+    CV_INSTRUMENT_REGION()
+
     FAST(_img, keypoints, threshold, nonmax_suppression, FastFeatureDetector::TYPE_9_16);
 }
 
@@ -373,6 +442,8 @@ public:
 
     void detect( InputArray _image, std::vector<KeyPoint>& keypoints, InputArray _mask )
     {
+        CV_INSTRUMENT_REGION()
+
         Mat mask = _mask.getMat(), grayImage;
         UMat ugrayImage;
         _InputArray gray = _image;
diff --git a/modules/features2d/src/feature2d.cpp b/modules/features2d/src/feature2d.cpp
index 93b650b..06a7f4c 100644
--- a/modules/features2d/src/feature2d.cpp
+++ b/modules/features2d/src/feature2d.cpp
@@ -60,6 +60,8 @@ void Feature2D::detect( InputArray image,
                         std::vector<KeyPoint>& keypoints,
                         InputArray mask )
 {
+    CV_INSTRUMENT_REGION()
+
     if( image.empty() )
     {
         keypoints.clear();
@@ -73,6 +75,8 @@ void Feature2D::detect( InputArrayOfArrays _images,
                         std::vector<std::vector<KeyPoint> >& keypoints,
                         InputArrayOfArrays _masks )
 {
+    CV_INSTRUMENT_REGION()
+
     vector<Mat> images, masks;
 
     _images.getMatVector(images);
@@ -102,6 +106,8 @@ void Feature2D::compute( InputArray image,
                          std::vector<KeyPoint>& keypoints,
                          OutputArray descriptors )
 {
+    CV_INSTRUMENT_REGION()
+
     if( image.empty() )
     {
         descriptors.release();
@@ -114,6 +120,8 @@ void Feature2D::compute( InputArrayOfArrays _images,
                          std::vector<std::vector<KeyPoint> >& keypoints,
                          OutputArrayOfArrays _descriptors )
 {
+    CV_INSTRUMENT_REGION()
+
     if( !_descriptors.needed() )
         return;
 
@@ -141,9 +149,31 @@ void Feature2D::detectAndCompute( InputArray, InputArray,
                                   OutputArray,
                                   bool )
 {
+    CV_INSTRUMENT_REGION()
+
     CV_Error(Error::StsNotImplemented, "");
 }
 
+void Feature2D::write( const String& fileName ) const
+{
+    FileStorage fs(fileName, FileStorage::WRITE);
+    write(fs);
+}
+
+void Feature2D::read( const String& fileName )
+{
+    FileStorage fs(fileName, FileStorage::READ);
+    read(fs.root());
+}
+
+void Feature2D::write( FileStorage&) const
+{
+}
+
+void Feature2D::read( const FileNode&)
+{
+}
+
 int Feature2D::descriptorSize() const
 {
     return 0;
diff --git a/modules/features2d/src/gftt.cpp b/modules/features2d/src/gftt.cpp
index 17e2692..c61c96f 100644
--- a/modules/features2d/src/gftt.cpp
+++ b/modules/features2d/src/gftt.cpp
@@ -75,6 +75,8 @@ public:
 
     void detect( InputArray _image, std::vector<KeyPoint>& keypoints, InputArray _mask )
     {
+        CV_INSTRUMENT_REGION()
+
         std::vector<Point2f> corners;
 
         if (_image.isUMat())
diff --git a/modules/features2d/src/kaze.cpp b/modules/features2d/src/kaze.cpp
index 0174907..63b48c3 100644
--- a/modules/features2d/src/kaze.cpp
+++ b/modules/features2d/src/kaze.cpp
@@ -110,6 +110,8 @@ namespace cv
                               OutputArray descriptors,
                               bool useProvidedKeypoints)
         {
+            CV_INSTRUMENT_REGION()
+
             cv::Mat img = image.getMat();
             if (img.channels() > 1)
                 cvtColor(image, img, COLOR_BGR2GRAY);
@@ -159,6 +161,7 @@ namespace cv
 
         void write(FileStorage& fs) const
         {
+            writeFormat(fs);
             fs << "extended" << (int)extended;
             fs << "upright" << (int)upright;
             fs << "threshold" << threshold;
diff --git a/modules/features2d/src/kaze/AKAZEFeatures.cpp b/modules/features2d/src/kaze/AKAZEFeatures.cpp
index 6f1b610..77a68a5 100644
--- a/modules/features2d/src/kaze/AKAZEFeatures.cpp
+++ b/modules/features2d/src/kaze/AKAZEFeatures.cpp
@@ -342,14 +342,14 @@ void AKAZEFeatures::Find_Scale_Space_Extrema(std::vector<KeyPoint>& kpts)
 
             if (is_out == false) {
               if (is_repeated == false) {
-                point.pt.x *= ratio;
-                point.pt.y *= ratio;
+                point.pt.x = (float)(point.pt.x*ratio + .5*(ratio-1.0));
+                point.pt.y = (float)(point.pt.y*ratio + .5*(ratio-1.0));
                 kpts_aux.push_back(point);
                 npoints++;
               }
               else {
-                point.pt.x *= ratio;
-                point.pt.y *= ratio;
+                point.pt.x = (float)(point.pt.x*ratio + .5*(ratio-1.0));
+                point.pt.y = (float)(point.pt.y*ratio + .5*(ratio-1.0));
                 kpts_aux[id_repeated] = point;
               }
             } // if is_out
@@ -439,8 +439,8 @@ void AKAZEFeatures::Do_Subpixel_Refinement(std::vector<KeyPoint>& kpts)
         kpts[i].pt.x = x + dst(0);
       kpts[i].pt.y = y + dst(1);
       int power = fastpow(2, evolution_[kpts[i].class_id].octave);
-      kpts[i].pt.x *= power;
-      kpts[i].pt.y *= power;
+      kpts[i].pt.x = (float)(kpts[i].pt.x*power + .5*(power-1));
+      kpts[i].pt.y = (float)(kpts[i].pt.y*power + .5*(power-1));
       kpts[i].angle = 0.0;
 
       // In OpenCV the size of a keypoint its the diameter
@@ -812,7 +812,7 @@ void AKAZEFeatures::Compute_Main_Orientation(KeyPoint& kpt, const std::vector<TE
       }
     }
   }
-  hal::fastAtan2(resY, resX, Ang, ang_size, false);
+  hal::fastAtan32f(resY, resX, Ang, ang_size, false);
   // Loop slides pi/3 window around feature point
   for (ang1 = 0; ang1 < (float)(2.0 * CV_PI); ang1 += 0.15f) {
     ang2 = (ang1 + (float)(CV_PI / 3.0) >(float)(2.0*CV_PI) ? ang1 - (float)(5.0*CV_PI / 3.0) : ang1 + (float)(CV_PI / 3.0));
@@ -846,6 +846,17 @@ void AKAZEFeatures::Compute_Main_Orientation(KeyPoint& kpt, const std::vector<TE
 
 /* ************************************************************************* */
 /**
+ * @brief This method computes the main orientation for a given keypoints
+ * @param kpts Input keypoints
+ */
+void AKAZEFeatures::Compute_Keypoints_Orientation(std::vector<KeyPoint>& kpts) const
+{
+     for(size_t i = 0; i < kpts.size(); i++)
+         Compute_Main_Orientation(kpts[i], evolution_);
+}
+
+/* ************************************************************************* */
+/**
  * @brief This method computes the upright descriptor (not rotation invariant) of
  * the provided keypoint
  * @param kpt Input keypoint
diff --git a/modules/features2d/src/kaze/AKAZEFeatures.h b/modules/features2d/src/kaze/AKAZEFeatures.h
index 14800bc..16a858f 100644
--- a/modules/features2d/src/kaze/AKAZEFeatures.h
+++ b/modules/features2d/src/kaze/AKAZEFeatures.h
@@ -54,6 +54,7 @@ public:
   /// Feature description methods
   void Compute_Descriptors(std::vector<cv::KeyPoint>& kpts, cv::Mat& desc);
   static void Compute_Main_Orientation(cv::KeyPoint& kpt, const std::vector<TEvolution>& evolution_);
+  void Compute_Keypoints_Orientation(std::vector<cv::KeyPoint>& kpts) const;
 };
 
 /* ************************************************************************* */
diff --git a/modules/features2d/src/matchers.cpp b/modules/features2d/src/matchers.cpp
index fad73a2..4e9a7b4 100644
--- a/modules/features2d/src/matchers.cpp
+++ b/modules/features2d/src/matchers.cpp
@@ -517,30 +517,32 @@ DescriptorMatcher::~DescriptorMatcher()
 
 void DescriptorMatcher::add( InputArrayOfArrays _descriptors )
 {
-    if(_descriptors.isUMatVector())
+    if( _descriptors.isUMatVector() )
     {
         std::vector<UMat> descriptors;
-        _descriptors.getUMatVector(descriptors);
+        _descriptors.getUMatVector( descriptors );
         utrainDescCollection.insert( utrainDescCollection.end(), descriptors.begin(), descriptors.end() );
     }
-    else if(_descriptors.isUMat())
+    else if( _descriptors.isUMat() )
     {
         std::vector<UMat> descriptors = std::vector<UMat>(1, _descriptors.getUMat());
         utrainDescCollection.insert( utrainDescCollection.end(), descriptors.begin(), descriptors.end() );
     }
-    else if(_descriptors.isMatVector())
+    else if( _descriptors.isMatVector() )
     {
         std::vector<Mat> descriptors;
         _descriptors.getMatVector(descriptors);
         trainDescCollection.insert( trainDescCollection.end(), descriptors.begin(), descriptors.end() );
     }
-    else if(_descriptors.isMat())
+    else if( _descriptors.isMat() )
     {
         std::vector<Mat> descriptors = std::vector<Mat>(1, _descriptors.getMat());
         trainDescCollection.insert( trainDescCollection.end(), descriptors.begin(), descriptors.end() );
     }
     else
+    {
         CV_Assert( _descriptors.isUMat() || _descriptors.isUMatVector() || _descriptors.isMat() || _descriptors.isMatVector() );
+    }
 }
 
 const std::vector<Mat>& DescriptorMatcher::getTrainDescriptors() const
@@ -565,6 +567,8 @@ void DescriptorMatcher::train()
 void DescriptorMatcher::match( InputArray queryDescriptors, InputArray trainDescriptors,
                               std::vector<DMatch>& matches, InputArray mask ) const
 {
+    CV_INSTRUMENT_REGION()
+
     Ptr<DescriptorMatcher> tempMatcher = clone(true);
     tempMatcher->add(trainDescriptors);
     tempMatcher->match( queryDescriptors, matches, std::vector<Mat>(1, mask.getMat()) );
@@ -574,6 +578,8 @@ void DescriptorMatcher::knnMatch( InputArray queryDescriptors, InputArray trainD
                                   std::vector<std::vector<DMatch> >& matches, int knn,
                                   InputArray mask, bool compactResult ) const
 {
+    CV_INSTRUMENT_REGION()
+
     Ptr<DescriptorMatcher> tempMatcher = clone(true);
     tempMatcher->add(trainDescriptors);
     tempMatcher->knnMatch( queryDescriptors, matches, knn, std::vector<Mat>(1, mask.getMat()), compactResult );
@@ -583,6 +589,8 @@ void DescriptorMatcher::radiusMatch( InputArray queryDescriptors, InputArray tra
                                      std::vector<std::vector<DMatch> >& matches, float maxDistance, InputArray mask,
                                      bool compactResult ) const
 {
+    CV_INSTRUMENT_REGION()
+
     Ptr<DescriptorMatcher> tempMatcher = clone(true);
     tempMatcher->add(trainDescriptors);
     tempMatcher->radiusMatch( queryDescriptors, matches, maxDistance, std::vector<Mat>(1, mask.getMat()), compactResult );
@@ -590,6 +598,8 @@ void DescriptorMatcher::radiusMatch( InputArray queryDescriptors, InputArray tra
 
 void DescriptorMatcher::match( InputArray queryDescriptors, std::vector<DMatch>& matches, InputArrayOfArrays masks )
 {
+    CV_INSTRUMENT_REGION()
+
     std::vector<std::vector<DMatch> > knnMatches;
     knnMatch( queryDescriptors, knnMatches, 1, masks, true /*compactResult*/ );
     convertMatches( knnMatches, matches );
@@ -611,8 +621,7 @@ void DescriptorMatcher::checkMasks( InputArrayOfArrays _masks, int queryDescript
             {
                 int rows = trainDescCollection[i].empty() ? utrainDescCollection[i].rows : trainDescCollection[i].rows;
                     CV_Assert( masks[i].rows == queryDescriptorsCount &&
-                        (masks[i].cols == rows || masks[i].cols == rows) &&
-                        masks[i].type() == CV_8UC1 );
+                        masks[i].cols == rows && masks[i].type() == CV_8UC1);
             }
         }
     }
@@ -621,6 +630,8 @@ void DescriptorMatcher::checkMasks( InputArrayOfArrays _masks, int queryDescript
 void DescriptorMatcher::knnMatch( InputArray queryDescriptors, std::vector<std::vector<DMatch> >& matches, int knn,
                                   InputArrayOfArrays masks, bool compactResult )
 {
+    CV_INSTRUMENT_REGION()
+
     if( empty() || queryDescriptors.empty() )
         return;
 
@@ -635,6 +646,8 @@ void DescriptorMatcher::knnMatch( InputArray queryDescriptors, std::vector<std::
 void DescriptorMatcher::radiusMatch( InputArray queryDescriptors, std::vector<std::vector<DMatch> >& matches, float maxDistance,
                                      InputArrayOfArrays masks, bool compactResult )
 {
+    CV_INSTRUMENT_REGION()
+
     matches.clear();
     if( empty() || queryDescriptors.empty() )
         return;
@@ -683,6 +696,11 @@ BFMatcher::BFMatcher( int _normType, bool _crossCheck )
     crossCheck = _crossCheck;
 }
 
+Ptr<BFMatcher> BFMatcher::create(int _normType, bool _crossCheck )
+{
+    return makePtr<BFMatcher>(_normType, _crossCheck);
+}
+
 Ptr<DescriptorMatcher> BFMatcher::clone( bool emptyTrainData ) const
 {
     Ptr<BFMatcher> matcher = makePtr<BFMatcher>(normType, crossCheck);
@@ -1018,6 +1036,41 @@ Ptr<DescriptorMatcher> DescriptorMatcher::create( const String& descriptorMatche
     return dm;
 }
 
+Ptr<DescriptorMatcher> DescriptorMatcher::create(int matcherType)
+{
+
+
+    String name;
+
+    switch(matcherType)
+    {
+    case FLANNBASED:
+        name = "FlannBased";
+        break;
+    case BRUTEFORCE:
+        name = "BruteForce";
+        break;
+    case BRUTEFORCE_L1:
+        name = "BruteForce-L1";
+        break;
+    case BRUTEFORCE_HAMMING:
+        name = "BruteForce-Hamming";
+        break;
+    case BRUTEFORCE_HAMMINGLUT:
+        name = "BruteForce-HammingLUT";
+        break;
+    case BRUTEFORCE_SL2:
+        name = "BruteForce-SL2";
+        break;
+    default:
+        CV_Error( Error::StsBadArg, "Specified descriptor matcher type is not supported." );
+        break;
+    }
+
+    return DescriptorMatcher::create(name);
+
+}
+
 
 /*
  * Flann based matcher
@@ -1029,15 +1082,45 @@ FlannBasedMatcher::FlannBasedMatcher( const Ptr<flann::IndexParams>& _indexParam
     CV_Assert( _searchParams );
 }
 
+Ptr<FlannBasedMatcher> FlannBasedMatcher::create()
+{
+    return makePtr<FlannBasedMatcher>();
+}
+
 void FlannBasedMatcher::add( InputArrayOfArrays _descriptors )
 {
     DescriptorMatcher::add( _descriptors );
-    std::vector<UMat> descriptors;
-    _descriptors.getUMatVector(descriptors);
 
-    for( size_t i = 0; i < descriptors.size(); i++ )
+    if( _descriptors.isUMatVector() )
+    {
+        std::vector<UMat> descriptors;
+        _descriptors.getUMatVector( descriptors );
+
+        for( size_t i = 0; i < descriptors.size(); i++ )
+        {
+            addedDescCount += descriptors[i].rows;
+        }
+    }
+    else if( _descriptors.isUMat() )
     {
-        addedDescCount += descriptors[i].rows;
+        addedDescCount += _descriptors.getUMat().rows;
+    }
+    else if( _descriptors.isMatVector() )
+    {
+        std::vector<Mat> descriptors;
+        _descriptors.getMatVector(descriptors);
+        for( size_t i = 0; i < descriptors.size(); i++ )
+        {
+            addedDescCount += descriptors[i].rows;
+        }
+    }
+    else if( _descriptors.isMat() )
+    {
+        addedDescCount += _descriptors.getMat().rows;
+    }
+    else
+    {
+        CV_Assert( _descriptors.isUMat() || _descriptors.isUMatVector() || _descriptors.isMat() || _descriptors.isMatVector() );
     }
 }
 
@@ -1053,6 +1136,8 @@ void FlannBasedMatcher::clear()
 
 void FlannBasedMatcher::train()
 {
+    CV_INSTRUMENT_REGION()
+
     if( !flannIndex || mergedDescriptors.size() < addedDescCount )
     {
         // FIXIT: Workaround for 'utrainDescCollection' issue (PR #2142)
@@ -1152,6 +1237,7 @@ void FlannBasedMatcher::read( const FileNode& fn)
 
 void FlannBasedMatcher::write( FileStorage& fs) const
 {
+     writeFormat(fs);
      fs << "indexParams" << "[";
 
      if (indexParams)
@@ -1304,6 +1390,8 @@ void FlannBasedMatcher::convertToDMatches( const DescriptorCollection& collectio
 void FlannBasedMatcher::knnMatchImpl( InputArray _queryDescriptors, std::vector<std::vector<DMatch> >& matches, int knn,
                                      InputArrayOfArrays /*masks*/, bool /*compactResult*/ )
 {
+    CV_INSTRUMENT_REGION()
+
     Mat queryDescriptors = _queryDescriptors.getMat();
     Mat indices( queryDescriptors.rows, knn, CV_32SC1 );
     Mat dists( queryDescriptors.rows, knn, CV_32FC1);
@@ -1315,6 +1403,8 @@ void FlannBasedMatcher::knnMatchImpl( InputArray _queryDescriptors, std::vector<
 void FlannBasedMatcher::radiusMatchImpl( InputArray _queryDescriptors, std::vector<std::vector<DMatch> >& matches, float maxDistance,
                                          InputArrayOfArrays /*masks*/, bool /*compactResult*/ )
 {
+    CV_INSTRUMENT_REGION()
+
     Mat queryDescriptors = _queryDescriptors.getMat();
     const int count = mergedDescriptors.size(); // TODO do count as param?
     Mat indices( queryDescriptors.rows, count, CV_32SC1, Scalar::all(-1) );
@@ -1329,5 +1419,4 @@ void FlannBasedMatcher::radiusMatchImpl( InputArray _queryDescriptors, std::vect
 
     convertToDMatches( mergedDescriptors, indices, dists, matches );
 }
-
 }
diff --git a/modules/features2d/src/mser.cpp b/modules/features2d/src/mser.cpp
index 1143add..f16a0d2 100644
--- a/modules/features2d/src/mser.cpp
+++ b/modules/features2d/src/mser.cpp
@@ -211,7 +211,7 @@ public:
                         return;
                 }
             }
-            if( parent_ && parent_->var >= 0.f && var >= parent_->var )
+            if( var > 0.f && parent_ && parent_->var >= 0.f && var >= parent_->var )
                 return;
             int xmin = INT_MAX, ymin = INT_MAX, xmax = INT_MIN, ymax = INT_MIN, j = 0;
             wp.msers->push_back(vector<Point>());
@@ -270,12 +270,20 @@ public:
             if( !history || (history->size != size && size > 0 &&
                 (gray_level != history->val || force)))
             {
-                CompHistory* h = hptr++;
-                h->parent_ = 0;
-                h->child_ = history;
-                h->next_ = 0;
-                if( history )
-                    history->parent_ = h;
+                CompHistory* h;
+
+                if (history && gray_level == history->val)
+                    h = history;
+                else
+                {
+                    h = hptr++;
+                    h->parent_ = 0;
+                    h->child_ = history;
+                    h->next_ = 0;
+                    if (history)
+                        history->parent_ = h;
+                }
+
                 h->val = gray_level;
                 h->size = size;
                 h->head = head;
@@ -283,7 +291,7 @@ public:
                 history = h;
                 h->var = FLT_MAX;
                 h->checked = true;
-                if( h->size >= wp.p.minArea )
+                if (h->size >= wp.p.minArea)
                 {
                     h->var = -1.f;
                     h->checked = false;
@@ -291,7 +299,7 @@ public:
                 }
             }
             gray_level = new_gray_level;
-            if( update && history )
+            if( update && history && gray_level != history->val )
                 history->updateTree(wp, 0, 0, final);
         }
 
@@ -299,14 +307,13 @@ public:
         void merge( ConnectedComp* comp1, ConnectedComp* comp2,
                     CompHistory*& hptr, WParams& wp )
         {
-            comp1->growHistory( hptr, wp, -1, false );
-            comp2->growHistory( hptr, wp, -1, false );
-
             if( comp1->size < comp2->size )
                 std::swap(comp1, comp2);
 
             if( comp2->size == 0 )
             {
+                // only grow comp1's history
+                comp1->growHistory(hptr, wp, -1, false);
                 gray_level = comp1->gray_level;
                 head = comp1->head;
                 tail = comp1->tail;
@@ -315,21 +322,35 @@ public:
                 return;
             }
 
-            CompHistory* h1 = comp1->history;
-            CompHistory* h2 = comp2->history;
+            comp1->growHistory( hptr, wp, -1, false );
+            comp2->growHistory( hptr, wp, -1, false );
+
+            if (comp1->gray_level < comp2->gray_level)
+                std::swap(comp1, comp2);
 
-            gray_level = std::max(comp1->gray_level, comp2->gray_level);
+            gray_level = comp1->gray_level;
             history = comp1->history;
             wp.pix0[comp1->tail].setNext(comp2->head);
 
             head = comp1->head;
             tail = comp2->tail;
             size = comp1->size + comp2->size;
-            bool keep_2nd = h2->size > wp.p.minArea;
-            growHistory( hptr, wp, -1, false, keep_2nd );
-            if( keep_2nd )
+
+            CompHistory *h1 = history->child_;
+            CompHistory *h2 = comp2->history;
+            if (h2->size > wp.p.minArea)
             {
-                h1->next_ = h2;
+                // the child_'s size should be the large one
+                if (h1 && h1->size > h2->size)
+                {
+                    h2->next_ = h1->next_;
+                    h1->next_ = h2;
+                }
+                else
+                {
+                    history->child_ = h2;
+                    h2->next_ = h1;
+                }
                 h2->parent_ = history;
             }
         }
@@ -390,7 +411,7 @@ public:
             int step = cols;
             for( i = 1; i < rows-1; i++ )
             {
-                Pixel* pptr = &pixbuf[i*step + 1];
+                Pixel* pptr = &pixbuf[i*step];
                 for( j = 1; j < cols-1; j++ )
                 {
                     pptr[j].val = 0;
@@ -1019,14 +1040,15 @@ extractMSER_8uC3( const Mat& src,
 
 void MSER_Impl::detectRegions( InputArray _src, vector<vector<Point> >& msers, vector<Rect>& bboxes )
 {
+    CV_INSTRUMENT_REGION()
+
     Mat src = _src.getMat();
-    size_t npix = src.total();
 
     msers.clear();
     bboxes.clear();
 
-    if( npix == 0 )
-        return;
+    if( src.rows < 3 || src.cols < 3 )
+        CV_Error(Error::StsBadArg, "Input image is too small. Expected at least 3x3");
 
     Size size = src.size();
 
@@ -1056,6 +1078,8 @@ void MSER_Impl::detectRegions( InputArray _src, vector<vector<Point> >& msers, v
 
 void MSER_Impl::detect( InputArray _image, vector<KeyPoint>& keypoints, InputArray _mask )
 {
+    CV_INSTRUMENT_REGION()
+
     vector<Rect> bboxes;
     vector<vector<Point> > msers;
     Mat mask = _mask.getMat();
diff --git a/modules/features2d/src/orb.cpp b/modules/features2d/src/orb.cpp
index 7775b84..9db9fd8 100644
--- a/modules/features2d/src/orb.cpp
+++ b/modules/features2d/src/orb.cpp
@@ -957,6 +957,8 @@ void ORB_Impl::detectAndCompute( InputArray _image, InputArray _mask,
                                  std::vector<KeyPoint>& keypoints,
                                  OutputArray _descriptors, bool useProvidedKeypoints )
 {
+    CV_INSTRUMENT_REGION()
+
     CV_Assert(patchSize >= 2);
 
     bool do_keypoints = !useProvidedKeypoints;
@@ -968,9 +970,11 @@ void ORB_Impl::detectAndCompute( InputArray _image, InputArray _mask,
     //ROI handling
     const int HARRIS_BLOCK_SIZE = 9;
     int halfPatchSize = patchSize / 2;
-    int border = std::max(edgeThreshold, std::max(halfPatchSize, HARRIS_BLOCK_SIZE/2))+1;
+    // sqrt(2.0) is for handling patch rotation
+    int descPatchSize = cvCeil(halfPatchSize*sqrt(2.0));
+    int border = std::max(edgeThreshold, std::max(descPatchSize, HARRIS_BLOCK_SIZE/2))+1;
 
-    bool useOCL = ocl::useOpenCL();
+    bool useOCL = ocl::useOpenCL() && OCL_FORCE_CHECK(_image.isUMat() || _descriptors.isUMat());
 
     Mat image = _image.getMat(), mask = _mask.getMat();
     if( image.type() != CV_8UC1 )
diff --git a/modules/features2d/test/test_detectors_regression.cpp b/modules/features2d/test/test_detectors_regression.cpp
index a235065..9b6d489 100644
--- a/modules/features2d/test/test_detectors_regression.cpp
+++ b/modules/features2d/test/test_detectors_regression.cpp
@@ -301,3 +301,23 @@ TEST( Features2d_Detector_AKAZE, regression )
     CV_FeatureDetectorTest test( "detector-akaze", AKAZE::create() );
     test.safe_run();
 }
+
+TEST( Features2d_Detector_AKAZE, detect_and_compute_split )
+{
+    Mat testImg(100, 100, CV_8U);
+    RNG rng(101);
+    rng.fill(testImg, RNG::UNIFORM, Scalar(0), Scalar(255), true);
+
+    Ptr<Feature2D> ext = AKAZE::create(AKAZE::DESCRIPTOR_MLDB, 0, 3, 0.001f, 1, 1, KAZE::DIFF_PM_G2);
+    vector<KeyPoint> detAndCompKps;
+    Mat desc;
+    ext->detectAndCompute(testImg, noArray(), detAndCompKps, desc);
+
+    vector<KeyPoint> detKps;
+    ext->detect(testImg, detKps);
+
+    ASSERT_EQ(detKps.size(), detAndCompKps.size());
+
+    for(size_t i = 0; i < detKps.size(); i++)
+        ASSERT_EQ(detKps[i].hash(), detAndCompKps[i].hash());
+}
diff --git a/modules/features2d/test/test_mser.cpp b/modules/features2d/test/test_mser.cpp
index 89b8ddb..a52c3c3 100644
--- a/modules/features2d/test/test_mser.cpp
+++ b/modules/features2d/test/test_mser.cpp
@@ -132,7 +132,7 @@ TEST(Features2d_MSER, cases)
             GaussianBlur(src, src, Size(5, 5), 1.5, 1.5);
 
         int minRegs = use_big_image ? 7 : 2;
-        int maxRegs = use_big_image ? 1000 : 15;
+        int maxRegs = use_big_image ? 1000 : 20;
         if( binarize && (thresh == 0 || thresh == 255) )
             minRegs = maxRegs = 0;
 
diff --git a/modules/features2d/test/test_orb.cpp b/modules/features2d/test/test_orb.cpp
index c02ea01..5394f75 100644
--- a/modules/features2d/test/test_orb.cpp
+++ b/modules/features2d/test/test_orb.cpp
@@ -90,3 +90,36 @@ TEST(Features2D_ORB, _1996)
 
     ASSERT_EQ(0, roiViolations);
 }
+
+TEST(Features2D_ORB, crash)
+{
+    cv::Mat image = cv::Mat::zeros(cv::Size(1920, 1080), CV_8UC3);
+
+    int nfeatures = 8000;
+    float orbScaleFactor = 1.2f;
+    int nlevels = 18;
+    int edgeThreshold = 4;
+    int firstLevel = 0;
+    int WTA_K = 2;
+    int scoreType = cv::ORB::HARRIS_SCORE;
+    int patchSize = 47;
+    int fastThreshold = 20;
+
+    Ptr<ORB> orb = cv::ORB::create(nfeatures, orbScaleFactor, nlevels, edgeThreshold, firstLevel, WTA_K, scoreType, patchSize, fastThreshold);
+
+    std::vector<cv::KeyPoint> keypoints;
+    cv::Mat descriptors;
+
+    cv::KeyPoint kp;
+    kp.pt.x = 443;
+    kp.pt.y = 5;
+    kp.size = 47;
+    kp.angle = 53.4580612f;
+    kp.response = 0.0000470733867f;
+    kp.octave = 0;
+    kp.class_id = -1;
+
+    keypoints.push_back(kp);
+
+    ASSERT_NO_THROW(orb->compute(image, keypoints, descriptors));
+}
diff --git a/modules/features2d/test/test_rotation_and_scale_invariance.cpp b/modules/features2d/test/test_rotation_and_scale_invariance.cpp
index 93ded0b..072adc4 100644
--- a/modules/features2d/test/test_rotation_and_scale_invariance.cpp
+++ b/modules/features2d/test/test_rotation_and_scale_invariance.cpp
@@ -47,7 +47,7 @@ using namespace cv;
 const string IMAGE_TSUKUBA = "/features2d/tsukuba.png";
 const string IMAGE_BIKES = "/detectors_descriptors_evaluation/images_datasets/bikes/img1.png";
 
-#define SHOW_DEBUG_LOG 0
+#define SHOW_DEBUG_LOG 1
 
 static
 Mat generateHomography(float angle)
@@ -63,7 +63,7 @@ Mat generateHomography(float angle)
 }
 
 static
-Mat rotateImage(const Mat& srcImage, float angle, Mat& dstImage, Mat& dstMask)
+Mat rotateImage(const Mat& srcImage, const Mat& srcMask, float angle, Mat& dstImage, Mat& dstMask)
 {
     // angle - rotation around Oz in degrees
     float diag = std::sqrt(static_cast<float>(srcImage.cols * srcImage.cols + srcImage.rows * srcImage.rows));
@@ -75,8 +75,6 @@ Mat rotateImage(const Mat& srcImage, float angle, Mat& dstImage, Mat& dstMask)
     RDShift.at<float>(1,2) = diag/2;
     Size sz(cvRound(diag), cvRound(diag));
 
-    Mat srcMask(srcImage.size(), CV_8UC1, Scalar(255));
-
     Mat H = RDShift * generateHomography(angle) * LUShift;
     warpPerspective(srcImage, dstImage, H, sz);
     warpPerspective(srcMask, dstMask, H, sz);
@@ -212,16 +210,22 @@ protected:
             ts->set_failed_test_info(cvtest::TS::FAIL_INVALID_TEST_DATA);
             return;
         }
+        std::cout << "Image: " << image0.size() << std::endl;
+
+        const int borderSize = 16;
+        Mat mask0(image0.size(), CV_8UC1, Scalar(0));
+        mask0(Rect(borderSize, borderSize, mask0.cols - 2*borderSize, mask0.rows - 2*borderSize)).setTo(Scalar(255));
 
         vector<KeyPoint> keypoints0;
-        featureDetector->detect(image0, keypoints0);
+        featureDetector->detect(image0, keypoints0, mask0);
+        std::cout << "Intial keypoints: " << keypoints0.size() << std::endl;
         if(keypoints0.size() < 15)
             CV_Error(Error::StsAssert, "Detector gives too few points in a test image\n");
 
         const int maxAngle = 360, angleStep = 15;
         for(int angle = 0; angle < maxAngle; angle += angleStep)
         {
-            Mat H = rotateImage(image0, static_cast<float>(angle), image1, mask1);
+            Mat H = rotateImage(image0, mask0, static_cast<float>(angle), image1, mask1);
 
             vector<KeyPoint> keypoints1;
             featureDetector->detect(image1, keypoints1, mask1);
@@ -264,10 +268,9 @@ protected:
             float keyPointMatchesRatio = static_cast<float>(keyPointMatchesCount) / keypoints0.size();
             if(keyPointMatchesRatio < minKeyPointMatchesRatio)
             {
-                ts->printf(cvtest::TS::LOG, "Incorrect keyPointMatchesRatio: curr = %f, min = %f.\n",
-                           keyPointMatchesRatio, minKeyPointMatchesRatio);
+                ts->printf(cvtest::TS::LOG, "Angle: %f: Incorrect keyPointMatchesRatio: curr = %f, min = %f (matched=%d total=%d - %d).\n",
+                           (float)angle, keyPointMatchesRatio, minKeyPointMatchesRatio, (int)keyPointMatchesCount, (int)keypoints0.size(), (int)keypoints1.size());
                 ts->set_failed_test_info(cvtest::TS::FAIL_BAD_ACCURACY);
-                return;
             }
 
             if(keyPointMatchesCount)
@@ -275,15 +278,18 @@ protected:
                 float angleInliersRatio = static_cast<float>(angleInliersCount) / keyPointMatchesCount;
                 if(angleInliersRatio < minAngleInliersRatio)
                 {
-                    ts->printf(cvtest::TS::LOG, "Incorrect angleInliersRatio: curr = %f, min = %f.\n",
-                               angleInliersRatio, minAngleInliersRatio);
+                    ts->printf(cvtest::TS::LOG, "Angle: %f: Incorrect angleInliersRatio: curr = %f, min = %f.\n",
+                               (float)angle, angleInliersRatio, minAngleInliersRatio);
                     ts->set_failed_test_info(cvtest::TS::FAIL_BAD_ACCURACY);
-                    return;
                 }
             }
 #if SHOW_DEBUG_LOG
-            std::cout << "keyPointMatchesRatio - " << keyPointMatchesRatio
-                << " - angleInliersRatio " << static_cast<float>(angleInliersCount) / keyPointMatchesCount << std::endl;
+            std::cout
+                << "angle = " << angle
+                << ", keypoints = " << keypoints1.size()
+                << ", keyPointMatchesRatio = " << keyPointMatchesRatio
+                << ", angleInliersRatio = " << (keyPointMatchesCount ? (static_cast<float>(angleInliersCount) / keyPointMatchesCount) : 0)
+                << std::endl;
 #endif
         }
         ts->set_failed_test_info( cvtest::TS::OK );
@@ -324,10 +330,16 @@ protected:
             ts->set_failed_test_info(cvtest::TS::FAIL_INVALID_TEST_DATA);
             return;
         }
+        std::cout << "Image: " << image0.size() << std::endl;
+
+        const int borderSize = 16;
+        Mat mask0(image0.size(), CV_8UC1, Scalar(0));
+        mask0(Rect(borderSize, borderSize, mask0.cols - 2*borderSize, mask0.rows - 2*borderSize)).setTo(Scalar(255));
 
         vector<KeyPoint> keypoints0;
         Mat descriptors0;
-        featureDetector->detect(image0, keypoints0);
+        featureDetector->detect(image0, keypoints0, mask0);
+        std::cout << "Intial keypoints: " << keypoints0.size() << std::endl;
         if(keypoints0.size() < 15)
             CV_Error(Error::StsAssert, "Detector gives too few points in a test image\n");
         descriptorExtractor->compute(image0, keypoints0, descriptors0);
@@ -338,7 +350,7 @@ protected:
         const int maxAngle = 360, angleStep = 15;
         for(int angle = 0; angle < maxAngle; angle += angleStep)
         {
-            Mat H = rotateImage(image0, static_cast<float>(angle), image1, mask1);
+            Mat H = rotateImage(image0, mask0, static_cast<float>(angle), image1, mask1);
 
             vector<KeyPoint> keypoints1;
             rotateKeyPoints(keypoints0, H, static_cast<float>(angle), keypoints1);
@@ -369,7 +381,11 @@ protected:
                 return;
             }
 #if SHOW_DEBUG_LOG
-            std::cout << "descInliersRatio " << static_cast<float>(descInliersCount) / keypoints0.size() << std::endl;
+            std::cout
+                << "angle = " << angle
+                << ", keypoints = " << keypoints1.size()
+                << ", descInliersRatio = " << static_cast<float>(descInliersCount) / keypoints0.size()
+                << std::endl;
 #endif
         }
         ts->set_failed_test_info( cvtest::TS::OK );
@@ -485,8 +501,11 @@ protected:
                 }
             }
 #if SHOW_DEBUG_LOG
-            std::cout << "keyPointMatchesRatio - " << keyPointMatchesRatio
-                << " - scaleInliersRatio " << static_cast<float>(scaleInliersCount) / keyPointMatchesCount << std::endl;
+            std::cout
+                << "scale = " << scale
+                << ", keyPointMatchesRatio = " << keyPointMatchesRatio
+                << ", scaleInliersRatio = " << (keyPointMatchesCount ? static_cast<float>(scaleInliersCount) / keyPointMatchesCount : 0)
+                << std::endl;
 #endif
         }
         ts->set_failed_test_info( cvtest::TS::OK );
@@ -573,7 +592,10 @@ protected:
                 return;
             }
 #if SHOW_DEBUG_LOG
-            std::cout << "descInliersRatio " << static_cast<float>(descInliersCount) / keypoints0.size() << std::endl;
+            std::cout
+                << "scale = " << scale
+                << ", descInliersRatio = " << static_cast<float>(descInliersCount) / keypoints0.size()
+                << std::endl;
 #endif
         }
         ts->set_failed_test_info( cvtest::TS::OK );
@@ -595,7 +617,7 @@ protected:
 TEST(Features2d_RotationInvariance_Detector_BRISK, regression)
 {
     DetectorRotationInvarianceTest test(BRISK::create(),
-                                        0.32f,
+                                        0.45f,
                                         0.76f);
     test.safe_run();
 }
@@ -603,7 +625,7 @@ TEST(Features2d_RotationInvariance_Detector_BRISK, regression)
 TEST(Features2d_RotationInvariance_Detector_ORB, regression)
 {
     DetectorRotationInvarianceTest test(ORB::create(),
-                                        0.47f,
+                                        0.5f,
                                         0.76f);
     test.safe_run();
 }
@@ -657,13 +679,11 @@ TEST(Features2d_ScaleInvariance_Detector_AKAZE, regression)
     test.safe_run();
 }
 
-//TEST(Features2d_ScaleInvariance_Detector_ORB, regression)
-//{
-//    DetectorScaleInvarianceTest test(Algorithm::create<FeatureDetector>("Feature2D.ORB"),
-//                                     0.22f,
-//                                     0.83f);
-//    test.safe_run();
-//}
+TEST(Features2d_ScaleInvariance_Detector_ORB, regression)
+{
+    DetectorScaleInvarianceTest test(ORB::create(), 0.08f, 0.49f);
+    test.safe_run();
+}
 
 /*
  * Descriptor's scale invariance check
diff --git a/modules/flann/include/opencv2/flann.hpp b/modules/flann/include/opencv2/flann.hpp
index 4f92d57..19a98f1 100644
--- a/modules/flann/include/opencv2/flann.hpp
+++ b/modules/flann/include/opencv2/flann.hpp
@@ -40,8 +40,8 @@
 //
 //M*/
 
-#ifndef _OPENCV_FLANN_HPP_
-#define _OPENCV_FLANN_HPP_
+#ifndef OPENCV_FLANN_HPP
+#define OPENCV_FLANN_HPP
 
 #include "opencv2/core.hpp"
 #include "opencv2/flann/miniflann.hpp"
@@ -338,164 +338,134 @@ int GenericIndex<Distance>::radiusSearch(const Mat& query, Mat& indices, Mat& di
  * @deprecated Use GenericIndex class instead
  */
 template <typename T>
-class
-#ifndef _MSC_VER
- FLANN_DEPRECATED
-#endif
- Index_ {
+class Index_
+{
 public:
-        typedef typename L2<T>::ElementType ElementType;
-        typedef typename L2<T>::ResultType DistanceType;
-
-    Index_(const Mat& features, const ::cvflann::IndexParams& params);
-
-    ~Index_();
+    typedef typename L2<T>::ElementType ElementType;
+    typedef typename L2<T>::ResultType DistanceType;
 
-    void knnSearch(const std::vector<ElementType>& query, std::vector<int>& indices, std::vector<DistanceType>& dists, int knn, const ::cvflann::SearchParams& params);
-    void knnSearch(const Mat& queries, Mat& indices, Mat& dists, int knn, const ::cvflann::SearchParams& params);
-
-    int radiusSearch(const std::vector<ElementType>& query, std::vector<int>& indices, std::vector<DistanceType>& dists, DistanceType radius, const ::cvflann::SearchParams& params);
-    int radiusSearch(const Mat& query, Mat& indices, Mat& dists, DistanceType radius, const ::cvflann::SearchParams& params);
-
-    void save(String filename)
-        {
-            if (nnIndex_L1) nnIndex_L1->save(filename);
-            if (nnIndex_L2) nnIndex_L2->save(filename);
-        }
-
-    int veclen() const
+    FLANN_DEPRECATED Index_(const Mat& dataset, const ::cvflann::IndexParams& params)
     {
-            if (nnIndex_L1) return nnIndex_L1->veclen();
-            if (nnIndex_L2) return nnIndex_L2->veclen();
-        }
+        printf("[WARNING] The cv::flann::Index_<T> class is deperecated, use cv::flann::GenericIndex<Distance> instead\n");
 
-    int size() const
-    {
-            if (nnIndex_L1) return nnIndex_L1->size();
-            if (nnIndex_L2) return nnIndex_L2->size();
-        }
-
-        ::cvflann::IndexParams getParameters()
-        {
-            if (nnIndex_L1) return nnIndex_L1->getParameters();
-            if (nnIndex_L2) return nnIndex_L2->getParameters();
+        CV_Assert(dataset.type() == CvType<ElementType>::type());
+        CV_Assert(dataset.isContinuous());
+        ::cvflann::Matrix<ElementType> m_dataset((ElementType*)dataset.ptr<ElementType>(0), dataset.rows, dataset.cols);
 
+        if ( ::cvflann::flann_distance_type() == cvflann::FLANN_DIST_L2 ) {
+            nnIndex_L1 = NULL;
+            nnIndex_L2 = new ::cvflann::Index< L2<ElementType> >(m_dataset, params);
         }
-
-        FLANN_DEPRECATED const ::cvflann::IndexParams* getIndexParameters()
-        {
-            if (nnIndex_L1) return nnIndex_L1->getIndexParameters();
-            if (nnIndex_L2) return nnIndex_L2->getIndexParameters();
+        else if ( ::cvflann::flann_distance_type() == cvflann::FLANN_DIST_L1 ) {
+            nnIndex_L1 = new ::cvflann::Index< L1<ElementType> >(m_dataset, params);
+            nnIndex_L2 = NULL;
         }
+        else {
+            printf("[ERROR] cv::flann::Index_<T> only provides backwards compatibility for the L1 and L2 distances. "
+                   "For other distance types you must use cv::flann::GenericIndex<Distance>\n");
+            CV_Assert(0);
+        }
+        if (nnIndex_L1) nnIndex_L1->buildIndex();
+        if (nnIndex_L2) nnIndex_L2->buildIndex();
+    }
+    FLANN_DEPRECATED ~Index_()
+    {
+        if (nnIndex_L1) delete nnIndex_L1;
+        if (nnIndex_L2) delete nnIndex_L2;
+    }
 
-private:
-        // providing backwards compatibility for L2 and L1 distances (most common)
-        ::cvflann::Index< L2<ElementType> >* nnIndex_L2;
-        ::cvflann::Index< L1<ElementType> >* nnIndex_L1;
-};
-
-#ifdef _MSC_VER
-template <typename T>
-class FLANN_DEPRECATED Index_;
-#endif
+    FLANN_DEPRECATED void knnSearch(const std::vector<ElementType>& query, std::vector<int>& indices, std::vector<DistanceType>& dists, int knn, const ::cvflann::SearchParams& searchParams)
+    {
+        ::cvflann::Matrix<ElementType> m_query((ElementType*)&query[0], 1, query.size());
+        ::cvflann::Matrix<int> m_indices(&indices[0], 1, indices.size());
+        ::cvflann::Matrix<DistanceType> m_dists(&dists[0], 1, dists.size());
 
-//! @cond IGNORED
+        if (nnIndex_L1) nnIndex_L1->knnSearch(m_query,m_indices,m_dists,knn,searchParams);
+        if (nnIndex_L2) nnIndex_L2->knnSearch(m_query,m_indices,m_dists,knn,searchParams);
+    }
+    FLANN_DEPRECATED void knnSearch(const Mat& queries, Mat& indices, Mat& dists, int knn, const ::cvflann::SearchParams& searchParams)
+    {
+        CV_Assert(queries.type() == CvType<ElementType>::type());
+        CV_Assert(queries.isContinuous());
+        ::cvflann::Matrix<ElementType> m_queries((ElementType*)queries.ptr<ElementType>(0), queries.rows, queries.cols);
 
-template <typename T>
-Index_<T>::Index_(const Mat& dataset, const ::cvflann::IndexParams& params)
-{
-    printf("[WARNING] The cv::flann::Index_<T> class is deperecated, use cv::flann::GenericIndex<Distance> instead\n");
+        CV_Assert(indices.type() == CV_32S);
+        CV_Assert(indices.isContinuous());
+        ::cvflann::Matrix<int> m_indices((int*)indices.ptr<int>(0), indices.rows, indices.cols);
 
-    CV_Assert(dataset.type() == CvType<ElementType>::type());
-    CV_Assert(dataset.isContinuous());
-    ::cvflann::Matrix<ElementType> m_dataset((ElementType*)dataset.ptr<ElementType>(0), dataset.rows, dataset.cols);
+        CV_Assert(dists.type() == CvType<DistanceType>::type());
+        CV_Assert(dists.isContinuous());
+        ::cvflann::Matrix<DistanceType> m_dists((DistanceType*)dists.ptr<DistanceType>(0), dists.rows, dists.cols);
 
-    if ( ::cvflann::flann_distance_type() == cvflann::FLANN_DIST_L2 ) {
-        nnIndex_L1 = NULL;
-        nnIndex_L2 = new ::cvflann::Index< L2<ElementType> >(m_dataset, params);
-    }
-    else if ( ::cvflann::flann_distance_type() == cvflann::FLANN_DIST_L1 ) {
-        nnIndex_L1 = new ::cvflann::Index< L1<ElementType> >(m_dataset, params);
-        nnIndex_L2 = NULL;
+        if (nnIndex_L1) nnIndex_L1->knnSearch(m_queries,m_indices,m_dists,knn, searchParams);
+        if (nnIndex_L2) nnIndex_L2->knnSearch(m_queries,m_indices,m_dists,knn, searchParams);
     }
-    else {
-        printf("[ERROR] cv::flann::Index_<T> only provides backwards compatibility for the L1 and L2 distances. "
-        "For other distance types you must use cv::flann::GenericIndex<Distance>\n");
-        CV_Assert(0);
-    }
-    if (nnIndex_L1) nnIndex_L1->buildIndex();
-    if (nnIndex_L2) nnIndex_L2->buildIndex();
-}
-
-template <typename T>
-Index_<T>::~Index_()
-{
-    if (nnIndex_L1) delete nnIndex_L1;
-    if (nnIndex_L2) delete nnIndex_L2;
-}
 
-template <typename T>
-void Index_<T>::knnSearch(const std::vector<ElementType>& query, std::vector<int>& indices, std::vector<DistanceType>& dists, int knn, const ::cvflann::SearchParams& searchParams)
-{
-    ::cvflann::Matrix<ElementType> m_query((ElementType*)&query[0], 1, query.size());
-    ::cvflann::Matrix<int> m_indices(&indices[0], 1, indices.size());
-    ::cvflann::Matrix<DistanceType> m_dists(&dists[0], 1, dists.size());
+    FLANN_DEPRECATED int radiusSearch(const std::vector<ElementType>& query, std::vector<int>& indices, std::vector<DistanceType>& dists, DistanceType radius, const ::cvflann::SearchParams& searchParams)
+    {
+        ::cvflann::Matrix<ElementType> m_query((ElementType*)&query[0], 1, query.size());
+        ::cvflann::Matrix<int> m_indices(&indices[0], 1, indices.size());
+        ::cvflann::Matrix<DistanceType> m_dists(&dists[0], 1, dists.size());
 
-    if (nnIndex_L1) nnIndex_L1->knnSearch(m_query,m_indices,m_dists,knn,searchParams);
-    if (nnIndex_L2) nnIndex_L2->knnSearch(m_query,m_indices,m_dists,knn,searchParams);
-}
+        if (nnIndex_L1) return nnIndex_L1->radiusSearch(m_query,m_indices,m_dists,radius,searchParams);
+        if (nnIndex_L2) return nnIndex_L2->radiusSearch(m_query,m_indices,m_dists,radius,searchParams);
+    }
 
+    FLANN_DEPRECATED int radiusSearch(const Mat& query, Mat& indices, Mat& dists, DistanceType radius, const ::cvflann::SearchParams& searchParams)
+    {
+        CV_Assert(query.type() == CvType<ElementType>::type());
+        CV_Assert(query.isContinuous());
+        ::cvflann::Matrix<ElementType> m_query((ElementType*)query.ptr<ElementType>(0), query.rows, query.cols);
 
-template <typename T>
-void Index_<T>::knnSearch(const Mat& queries, Mat& indices, Mat& dists, int knn, const ::cvflann::SearchParams& searchParams)
-{
-    CV_Assert(queries.type() == CvType<ElementType>::type());
-    CV_Assert(queries.isContinuous());
-    ::cvflann::Matrix<ElementType> m_queries((ElementType*)queries.ptr<ElementType>(0), queries.rows, queries.cols);
+        CV_Assert(indices.type() == CV_32S);
+        CV_Assert(indices.isContinuous());
+        ::cvflann::Matrix<int> m_indices((int*)indices.ptr<int>(0), indices.rows, indices.cols);
 
-    CV_Assert(indices.type() == CV_32S);
-    CV_Assert(indices.isContinuous());
-    ::cvflann::Matrix<int> m_indices((int*)indices.ptr<int>(0), indices.rows, indices.cols);
+        CV_Assert(dists.type() == CvType<DistanceType>::type());
+        CV_Assert(dists.isContinuous());
+        ::cvflann::Matrix<DistanceType> m_dists((DistanceType*)dists.ptr<DistanceType>(0), dists.rows, dists.cols);
 
-    CV_Assert(dists.type() == CvType<DistanceType>::type());
-    CV_Assert(dists.isContinuous());
-    ::cvflann::Matrix<DistanceType> m_dists((DistanceType*)dists.ptr<DistanceType>(0), dists.rows, dists.cols);
+        if (nnIndex_L1) return nnIndex_L1->radiusSearch(m_query,m_indices,m_dists,radius,searchParams);
+        if (nnIndex_L2) return nnIndex_L2->radiusSearch(m_query,m_indices,m_dists,radius,searchParams);
+    }
 
-    if (nnIndex_L1) nnIndex_L1->knnSearch(m_queries,m_indices,m_dists,knn, searchParams);
-    if (nnIndex_L2) nnIndex_L2->knnSearch(m_queries,m_indices,m_dists,knn, searchParams);
-}
+    FLANN_DEPRECATED void save(String filename)
+    {
+        if (nnIndex_L1) nnIndex_L1->save(filename);
+        if (nnIndex_L2) nnIndex_L2->save(filename);
+    }
 
-template <typename T>
-int Index_<T>::radiusSearch(const std::vector<ElementType>& query, std::vector<int>& indices, std::vector<DistanceType>& dists, DistanceType radius, const ::cvflann::SearchParams& searchParams)
-{
-    ::cvflann::Matrix<ElementType> m_query((ElementType*)&query[0], 1, query.size());
-    ::cvflann::Matrix<int> m_indices(&indices[0], 1, indices.size());
-    ::cvflann::Matrix<DistanceType> m_dists(&dists[0], 1, dists.size());
+    FLANN_DEPRECATED int veclen() const
+    {
+        if (nnIndex_L1) return nnIndex_L1->veclen();
+        if (nnIndex_L2) return nnIndex_L2->veclen();
+    }
 
-    if (nnIndex_L1) return nnIndex_L1->radiusSearch(m_query,m_indices,m_dists,radius,searchParams);
-    if (nnIndex_L2) return nnIndex_L2->radiusSearch(m_query,m_indices,m_dists,radius,searchParams);
-}
+    FLANN_DEPRECATED int size() const
+    {
+        if (nnIndex_L1) return nnIndex_L1->size();
+        if (nnIndex_L2) return nnIndex_L2->size();
+    }
 
-template <typename T>
-int Index_<T>::radiusSearch(const Mat& query, Mat& indices, Mat& dists, DistanceType radius, const ::cvflann::SearchParams& searchParams)
-{
-    CV_Assert(query.type() == CvType<ElementType>::type());
-    CV_Assert(query.isContinuous());
-    ::cvflann::Matrix<ElementType> m_query((ElementType*)query.ptr<ElementType>(0), query.rows, query.cols);
+    FLANN_DEPRECATED ::cvflann::IndexParams getParameters()
+    {
+        if (nnIndex_L1) return nnIndex_L1->getParameters();
+        if (nnIndex_L2) return nnIndex_L2->getParameters();
 
-    CV_Assert(indices.type() == CV_32S);
-    CV_Assert(indices.isContinuous());
-    ::cvflann::Matrix<int> m_indices((int*)indices.ptr<int>(0), indices.rows, indices.cols);
+    }
 
-    CV_Assert(dists.type() == CvType<DistanceType>::type());
-    CV_Assert(dists.isContinuous());
-    ::cvflann::Matrix<DistanceType> m_dists((DistanceType*)dists.ptr<DistanceType>(0), dists.rows, dists.cols);
+    FLANN_DEPRECATED const ::cvflann::IndexParams* getIndexParameters()
+    {
+        if (nnIndex_L1) return nnIndex_L1->getIndexParameters();
+        if (nnIndex_L2) return nnIndex_L2->getIndexParameters();
+    }
 
-    if (nnIndex_L1) return nnIndex_L1->radiusSearch(m_query,m_indices,m_dists,radius,searchParams);
-    if (nnIndex_L2) return nnIndex_L2->radiusSearch(m_query,m_indices,m_dists,radius,searchParams);
-}
+private:
+    // providing backwards compatibility for L2 and L1 distances (most common)
+    ::cvflann::Index< L2<ElementType> >* nnIndex_L2;
+    ::cvflann::Index< L1<ElementType> >* nnIndex_L1;
+};
 
-//! @endcond
 
 /** @brief Clusters features using hierarchical k-means algorithm.
 
diff --git a/modules/flann/include/opencv2/flann/any.h b/modules/flann/include/opencv2/flann/any.h
index 8c2edaa..bfe06c8 100644
--- a/modules/flann/include/opencv2/flann/any.h
+++ b/modules/flann/include/opencv2/flann/any.h
@@ -79,7 +79,8 @@ struct big_any_policy : typed_base_any_policy<T>
 {
     virtual void static_delete(void** x)
     {
-        if (* x) delete (* reinterpret_cast<T**>(x)); *x = NULL;
+        if (* x) delete (* reinterpret_cast<T**>(x));
+        *x = NULL;
     }
     virtual void copy_from_value(void const* src, void** dest)
     {
diff --git a/modules/flann/include/opencv2/flann/kmeans_index.h b/modules/flann/include/opencv2/flann/kmeans_index.h
index 226fc71..98ad0c8 100644
--- a/modules/flann/include/opencv2/flann/kmeans_index.h
+++ b/modules/flann/include/opencv2/flann/kmeans_index.h
@@ -874,6 +874,8 @@ private:
             computeClustering(node->childs[c],indices+start, end-start, branching, level+1);
             start=end;
         }
+
+        delete[] centers;
     }
 
 
diff --git a/modules/flann/include/opencv2/flann/lsh_table.h b/modules/flann/include/opencv2/flann/lsh_table.h
index 582dcdb..8ef2bd3 100644
--- a/modules/flann/include/opencv2/flann/lsh_table.h
+++ b/modules/flann/include/opencv2/flann/lsh_table.h
@@ -265,7 +265,7 @@ private:
     {
         const size_t key_size_lower_bound = 1;
         //a value (size_t(1) << key_size) must fit the size_t type so key_size has to be strictly less than size of size_t
-        const size_t key_size_upper_bound = std::min(sizeof(BucketKey) * CHAR_BIT + 1, sizeof(size_t) * CHAR_BIT);
+        const size_t key_size_upper_bound = (std::min)(sizeof(BucketKey) * CHAR_BIT + 1, sizeof(size_t) * CHAR_BIT);
         if (key_size < key_size_lower_bound || key_size >= key_size_upper_bound)
         {
             CV_Error(cv::Error::StsBadArg, cv::format("Invalid key_size (=%d). Valid values for your system are %d <= key_size < %d.", (int)key_size, (int)key_size_lower_bound, (int)key_size_upper_bound));
diff --git a/modules/flann/include/opencv2/flann/miniflann.hpp b/modules/flann/include/opencv2/flann/miniflann.hpp
index 02fa236..5d25f5e 100644
--- a/modules/flann/include/opencv2/flann/miniflann.hpp
+++ b/modules/flann/include/opencv2/flann/miniflann.hpp
@@ -40,8 +40,8 @@
 //
 //M*/
 
-#ifndef _OPENCV_MINIFLANN_HPP_
-#define _OPENCV_MINIFLANN_HPP_
+#ifndef OPENCV_MINIFLANN_HPP
+#define OPENCV_MINIFLANN_HPP
 
 #include "opencv2/core.hpp"
 #include "opencv2/flann/defines.h"
diff --git a/modules/flann/misc/python/pyopencv_flann.hpp b/modules/flann/misc/python/pyopencv_flann.hpp
new file mode 100644
index 0000000..a9da8d0
--- /dev/null
+++ b/modules/flann/misc/python/pyopencv_flann.hpp
@@ -0,0 +1,79 @@
+#ifdef HAVE_OPENCV_FLANN
+typedef cvflann::flann_distance_t cvflann_flann_distance_t;
+typedef cvflann::flann_algorithm_t cvflann_flann_algorithm_t;
+
+template<>
+PyObject* pyopencv_from(const cvflann_flann_algorithm_t& value)
+{
+    return PyInt_FromLong(int(value));
+}
+
+template<>
+PyObject* pyopencv_from(const cvflann_flann_distance_t& value)
+{
+    return PyInt_FromLong(int(value));
+}
+
+template<>
+bool pyopencv_to(PyObject *o, cv::flann::IndexParams& p, const char *name)
+{
+    (void)name;
+    bool ok = true;
+    PyObject* key = NULL;
+    PyObject* item = NULL;
+    Py_ssize_t pos = 0;
+
+    if(PyDict_Check(o)) {
+        while(PyDict_Next(o, &pos, &key, &item)) {
+            if( !PyString_Check(key) ) {
+                ok = false;
+                break;
+            }
+
+            String k = PyString_AsString(key);
+            if( PyString_Check(item) )
+            {
+                const char* value = PyString_AsString(item);
+                p.setString(k, value);
+            }
+            else if( !!PyBool_Check(item) )
+                p.setBool(k, item == Py_True);
+            else if( PyInt_Check(item) )
+            {
+                int value = (int)PyInt_AsLong(item);
+                if( strcmp(k.c_str(), "algorithm") == 0 )
+                    p.setAlgorithm(value);
+                else
+                    p.setInt(k, value);
+            }
+            else if( PyFloat_Check(item) )
+            {
+                double value = PyFloat_AsDouble(item);
+                p.setDouble(k, value);
+            }
+            else
+            {
+                ok = false;
+                break;
+            }
+        }
+    }
+
+    return ok && !PyErr_Occurred();
+}
+
+template<>
+bool pyopencv_to(PyObject* obj, cv::flann::SearchParams & value, const char * name)
+{
+    return pyopencv_to<cv::flann::IndexParams>(obj, value, name);
+}
+
+template<>
+bool pyopencv_to(PyObject *o, cvflann::flann_distance_t& dist, const char *name)
+{
+    int d = (int)dist;
+    bool ok = pyopencv_to(o, d, name);
+    dist = (cvflann::flann_distance_t)d;
+    return ok;
+}
+#endif
\ No newline at end of file
diff --git a/modules/flann/src/miniflann.cpp b/modules/flann/src/miniflann.cpp
index 7d81438..8aca73c 100644
--- a/modules/flann/src/miniflann.cpp
+++ b/modules/flann/src/miniflann.cpp
@@ -318,7 +318,19 @@ buildIndex_(void*& index, const Mat& data, const IndexParams& params, const Dist
 
     ::cvflann::Matrix<ElementType> dataset((ElementType*)data.data, data.rows, data.cols);
     IndexType* _index = new IndexType(dataset, get_params(params), dist);
-    _index->buildIndex();
+
+    try
+    {
+        _index->buildIndex();
+    }
+    catch (...)
+    {
+        delete _index;
+        _index = NULL;
+
+        throw;
+    }
+
     index = _index;
 }
 
@@ -353,6 +365,8 @@ Index::Index(InputArray _data, const IndexParams& params, flann_distance_t _dist
 
 void Index::build(InputArray _data, const IndexParams& params, flann_distance_t _distType)
 {
+    CV_INSTRUMENT_REGION()
+
     release();
     algo = getParam<flann_algorithm_t>(params, "algorithm", FLANN_INDEX_LINEAR);
     if( algo == FLANN_INDEX_SAVED )
@@ -421,6 +435,8 @@ Index::~Index()
 
 void Index::release()
 {
+    CV_INSTRUMENT_REGION()
+
     if( !index )
         return;
 
@@ -551,6 +567,8 @@ static void createIndicesDists(OutputArray _indices, OutputArray _dists,
 void Index::knnSearch(InputArray _query, OutputArray _indices,
                OutputArray _dists, int knn, const SearchParams& params)
 {
+    CV_INSTRUMENT_REGION()
+
     Mat query = _query.getMat(), indices, dists;
     int dtype = distType == FLANN_DIST_HAMMING ? CV_32S : CV_32F;
 
@@ -593,6 +611,8 @@ int Index::radiusSearch(InputArray _query, OutputArray _indices,
                         OutputArray _dists, double radius, int maxResults,
                         const SearchParams& params)
 {
+    CV_INSTRUMENT_REGION()
+
     Mat query = _query.getMat(), indices, dists;
     int dtype = distType == FLANN_DIST_HAMMING ? CV_32S : CV_32F;
     CV_Assert( maxResults > 0 );
@@ -656,6 +676,8 @@ template<typename Distance> void saveIndex(const Index* index0, const void* inde
 
 void Index::save(const String& filename) const
 {
+    CV_INSTRUMENT_REGION()
+
     FILE* fout = fopen(filename.c_str(), "wb");
     if (fout == NULL)
         CV_Error_( Error::StsError, ("Can not open file %s for writing FLANN index\n", filename.c_str()) );
diff --git a/modules/flann/src/precomp.hpp b/modules/flann/src/precomp.hpp
index 1c41542..bcd8889 100644
--- a/modules/flann/src/precomp.hpp
+++ b/modules/flann/src/precomp.hpp
@@ -1,5 +1,5 @@
-#ifndef _OPENCV_FLANN_PRECOMP_HPP_
-#define _OPENCV_FLANN_PRECOMP_HPP_
+#ifndef OPENCV_FLANN_PRECOMP_HPP
+#define OPENCV_FLANN_PRECOMP_HPP
 
 #include <cstdio>
 #include <cstdarg>
diff --git a/modules/flann/test/test_precomp.hpp b/modules/flann/test/test_precomp.hpp
index cbee895..4a19d2a 100644
--- a/modules/flann/test/test_precomp.hpp
+++ b/modules/flann/test/test_precomp.hpp
@@ -6,8 +6,8 @@
 #  endif
 #endif
 
-#ifndef __OPENCV_TEST_PRECOMP_HPP__
-#define __OPENCV_TEST_PRECOMP_HPP__
+#ifndef OPENCV_TEST_PRECOMP_HPP
+#define OPENCV_TEST_PRECOMP_HPP
 
 #include "opencv2/ts.hpp"
 #include "opencv2/flann.hpp"
diff --git a/modules/highgui/CMakeLists.txt b/modules/highgui/CMakeLists.txt
index 9d1745e..eb56177 100644
--- a/modules/highgui/CMakeLists.txt
+++ b/modules/highgui/CMakeLists.txt
@@ -1,5 +1,5 @@
 set(the_description "High-level GUI and Media I/O")
-ocv_add_module(highgui opencv_imgproc opencv_imgcodecs opencv_videoio WRAP python)
+ocv_add_module(highgui opencv_imgproc OPTIONAL opencv_imgcodecs opencv_videoio WRAP python)
 
 # ----------------------------------------------------------------------------
 #  CMake file for highgui. See root CMakeLists.txt
@@ -7,7 +7,7 @@ ocv_add_module(highgui opencv_imgproc opencv_imgcodecs opencv_videoio WRAP pytho
 #   Jose Luis Blanco, 2008
 # ----------------------------------------------------------------------------
 
-if(WINRT_8_1)
+if(DEFINED WINRT AND NOT DEFINED ENABLE_WINRT_MODE_NATIVE)
   set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /ZW")
 endif()
 
diff --git a/modules/highgui/include/opencv2/highgui.hpp b/modules/highgui/include/opencv2/highgui.hpp
index 41bd8af..16ef8c4 100644
--- a/modules/highgui/include/opencv2/highgui.hpp
+++ b/modules/highgui/include/opencv2/highgui.hpp
@@ -40,12 +40,16 @@
 //
 //M*/
 
-#ifndef __OPENCV_HIGHGUI_HPP__
-#define __OPENCV_HIGHGUI_HPP__
+#ifndef OPENCV_HIGHGUI_HPP
+#define OPENCV_HIGHGUI_HPP
 
 #include "opencv2/core.hpp"
+#ifdef HAVE_OPENCV_IMGCODECS
 #include "opencv2/imgcodecs.hpp"
+#endif
+#ifdef HAVE_OPENCV_VIDEOIO
 #include "opencv2/videoio.hpp"
+#endif
 
 /**
 @defgroup highgui High-level GUI
@@ -182,15 +186,18 @@ enum WindowFlags {
 
        WINDOW_FULLSCREEN = 1,          //!< change the window to fullscreen.
        WINDOW_FREERATIO  = 0x00000100, //!< the image expends as much as it can (no ratio constraint).
-       WINDOW_KEEPRATIO  = 0x00000000  //!< the ratio of the image is respected.
-     };
+       WINDOW_KEEPRATIO  = 0x00000000, //!< the ratio of the image is respected.
+       WINDOW_GUI_EXPANDED=0x00000000, //!< status bar and tool bar
+       WINDOW_GUI_NORMAL = 0x00000010, //!< old fashious way
+    };
 
 //! Flags for cv::setWindowProperty / cv::getWindowProperty
 enum WindowPropertyFlags {
        WND_PROP_FULLSCREEN   = 0, //!< fullscreen property    (can be WINDOW_NORMAL or WINDOW_FULLSCREEN).
        WND_PROP_AUTOSIZE     = 1, //!< autosize property      (can be WINDOW_NORMAL or WINDOW_AUTOSIZE).
        WND_PROP_ASPECT_RATIO = 2, //!< window's aspect ration (can be set to WINDOW_FREERATIO or WINDOW_KEEPRATIO).
-       WND_PROP_OPENGL       = 3  //!< opengl support.
+       WND_PROP_OPENGL       = 3, //!< opengl support.
+       WND_PROP_VISIBLE      = 4  //!< checks whether the window exists and is visible
      };
 
 //! Mouse Events see cv::MouseCallback
@@ -237,9 +244,10 @@ enum QtFontStyles {
 
 //! Qt "button" type
 enum QtButtonTypes {
-       QT_PUSH_BUTTON = 0, //!< Push button.
-       QT_CHECKBOX    = 1, //!< Checkbox button.
-       QT_RADIOBOX    = 2  //!< Radiobox button.
+       QT_PUSH_BUTTON   = 0,    //!< Push button.
+       QT_CHECKBOX      = 1,    //!< Checkbox button.
+       QT_RADIOBOX      = 2,    //!< Radiobox button.
+       QT_NEW_BUTTONBAR = 1024  //!< Button should create a new buttonbar
      };
 
 /** @brief Callback function for mouse events. see cv::setMouseCallback
@@ -287,9 +295,9 @@ Qt backend supports additional flags:
      displayed image (see imshow ), and you cannot change the window size manually.
  -   **WINDOW_FREERATIO or WINDOW_KEEPRATIO:** WINDOW_FREERATIO adjusts the image
      with no respect to its ratio, whereas WINDOW_KEEPRATIO keeps the image ratio.
- -   **CV_GUI_NORMAL or CV_GUI_EXPANDED:** CV_GUI_NORMAL is the old way to draw the window
-     without statusbar and toolbar, whereas CV_GUI_EXPANDED is a new enhanced GUI.
-By default, flags == WINDOW_AUTOSIZE | WINDOW_KEEPRATIO | CV_GUI_EXPANDED
+ -   **WINDOW_GUI_NORMAL or WINDOW_GUI_EXPANDED:** WINDOW_GUI_NORMAL is the old way to draw the window
+     without statusbar and toolbar, whereas WINDOW_GUI_EXPANDED is a new enhanced GUI.
+By default, flags == WINDOW_AUTOSIZE | WINDOW_KEEPRATIO | WINDOW_GUI_EXPANDED
 
 @param winname Name of the window in the window caption that may be used as a window identifier.
 @param flags Flags of the window. The supported flags are: (cv::WindowFlags)
@@ -312,6 +320,15 @@ CV_EXPORTS_W void destroyAllWindows();
 
 CV_EXPORTS_W int startWindowThread();
 
+/** @brief Similar to #waitKey, but returns full key code.
+
+ at note
+
+Key code is implementation specific and depends on used backend: QT/GTK/Win32/etc
+
+*/
+CV_EXPORTS_W int waitKeyEx(int delay = 0);
+
 /** @brief Waits for a pressed key.
 
 The function waitKey waits for a key event infinitely (when \f$\texttt{delay}\leq 0\f$ ) or for delay
@@ -423,7 +440,7 @@ CV_EXPORTS_W double getWindowProperty(const String& winname, int prop_id);
 
 @param winname Name of the window.
 @param onMouse Mouse callback. See OpenCV samples, such as
-<https://github.com/Itseez/opencv/tree/master/samples/cpp/ffilldemo.cpp>, on how to specify and
+<https://github.com/opencv/opencv/tree/master/samples/cpp/ffilldemo.cpp>, on how to specify and
 use the callback.
 @param userdata The optional parameter passed to the callback.
  */
@@ -663,6 +680,23 @@ The function addText draws *text* on the image *img* using a specific font *font
  */
 CV_EXPORTS void addText( const Mat& img, const String& text, Point org, const QtFont& font);
 
+/** @brief Draws a text on the image.
+
+ at param img 8-bit 3-channel image where the text should be drawn.
+ at param text Text to write on an image.
+ at param org Point(x,y) where the text should start on an image.
+ at param nameFont Name of the font. The name should match the name of a system font (such as
+*Times*). If the font is not found, a default one is used.
+ at param pointSize Size of the font. If not specified, equal zero or negative, the point size of the
+font is set to a system-dependent default value. Generally, this is 12 points.
+ at param color Color of the font in BGRA where A = 255 is fully transparent.
+ at param weight Font weight. Available operation flags are : cv::QtFontWeights You can also specify a positive integer for better control.
+ at param style Font style. Available operation flags are : cv::QtFontStyles
+ at param spacing Spacing between characters. It can be negative or positive.
+ */
+CV_EXPORTS_W void addText(const Mat& img, const String& text, Point org, const String& nameFont, int pointSize = -1, Scalar color = Scalar::all(0),
+        int weight = QT_FONT_NORMAL, int style = QT_STYLE_NORMAL, int spacing = 0);
+
 /** @brief Displays a text on a window image as an overlay for a specified duration.
 
 The function displayOverlay displays useful information/tips on top of the window for a certain
@@ -675,7 +709,7 @@ after the specified delay the original content of the window is restored.
 function is called before the previous overlay text timed out, the timer is restarted and the text
 is updated. If this value is zero, the text never disappears.
  */
-CV_EXPORTS void displayOverlay(const String& winname, const String& text, int delayms = 0);
+CV_EXPORTS_W void displayOverlay(const String& winname, const String& text, int delayms = 0);
 
 /** @brief Displays a text on the window statusbar during the specified period of time.
 
@@ -689,7 +723,7 @@ created with the CV_GUI_EXPANDED flags).
 the previous text timed out, the timer is restarted and the text is updated. If this value is
 zero, the text never disappears.
  */
-CV_EXPORTS void displayStatusBar(const String& winname, const String& text, int delayms = 0);
+CV_EXPORTS_W void displayStatusBar(const String& winname, const String& text, int delayms = 0);
 
 /** @brief Saves parameters of the specified window.
 
@@ -717,7 +751,8 @@ CV_EXPORTS  void stopLoop();
 
 The function createButton attaches a button to the control panel. Each button is added to a
 buttonbar to the right of the last button. A new buttonbar is created if nothing was attached to the
-control panel before, or if the last element attached to the control panel was a trackbar.
+control panel before, or if the last element attached to the control panel was a trackbar or if the
+QT_NEW_BUTTONBAR flag is added to the type.
 
 See below various examples of the cv::createButton function call: :
 @code
@@ -726,6 +761,7 @@ See below various examples of the cv::createButton function call: :
     createButton("button3",callbackButton,&value);
     createButton("button5",callbackButton1,NULL,QT_RADIOBOX);
     createButton("button6",callbackButton2,NULL,QT_PUSH_BUTTON,1);
+    createButton("button6",callbackButton2,NULL,QT_PUSH_BUTTON|QT_NEW_BUTTONBAR);// create a push button in a new row
 @endcode
 
 @param  bar_name Name of the button.
diff --git a/modules/highgui/include/opencv2/highgui/highgui_c.h b/modules/highgui/include/opencv2/highgui/highgui_c.h
index 47fdb84..71c08ca 100644
--- a/modules/highgui/include/opencv2/highgui/highgui_c.h
+++ b/modules/highgui/include/opencv2/highgui/highgui_c.h
@@ -39,13 +39,17 @@
 //
 //M*/
 
-#ifndef __OPENCV_HIGHGUI_H__
-#define __OPENCV_HIGHGUI_H__
+#ifndef OPENCV_HIGHGUI_H
+#define OPENCV_HIGHGUI_H
 
 #include "opencv2/core/core_c.h"
 #include "opencv2/imgproc/imgproc_c.h"
+#ifdef HAVE_OPENCV_IMGCODECS
 #include "opencv2/imgcodecs/imgcodecs_c.h"
+#endif
+#ifdef HAVE_OPENCV_VIDEOIO
 #include "opencv2/videoio/videoio_c.h"
+#endif
 
 #ifdef __cplusplus
 extern "C" {
@@ -107,6 +111,7 @@ enum
     CV_WND_PROP_AUTOSIZE   = 1, //to change/get window's autosize property
     CV_WND_PROP_ASPECTRATIO= 2, //to change/get window's aspectratio property
     CV_WND_PROP_OPENGL     = 3, //to change/get window's opengl support
+    CV_WND_PROP_VISIBLE    = 4,
 
     //These 2 flags are used by cvNamedWindow and cvSet/GetWindowProperty
     CV_WINDOW_NORMAL       = 0x00000000, //the user can resize the window (no constraint)  / also use to switch a fullscreen window to a normal size
diff --git a/modules/highgui/src/precomp.hpp b/modules/highgui/src/precomp.hpp
index 796af39..d9e7ad8 100644
--- a/modules/highgui/src/precomp.hpp
+++ b/modules/highgui/src/precomp.hpp
@@ -47,12 +47,14 @@
 #include "opencv2/core/utility.hpp"
 #include "opencv2/core/private.hpp"
 
-#include "opencv2/imgcodecs.hpp"
-
 #include "opencv2/imgproc/imgproc_c.h"
-#include "opencv2/imgcodecs/imgcodecs_c.h"
 #include "opencv2/highgui/highgui_c.h"
 
+#ifdef HAVE_OPENCV_IMGCODECS
+#include "opencv2/imgcodecs.hpp"
+#include "opencv2/imgcodecs/imgcodecs_c.h"
+#endif
+
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
@@ -61,14 +63,6 @@
 #include <assert.h>
 
 #if defined WIN32 || defined WINCE
-    #if !defined _WIN32_WINNT
-        #ifdef HAVE_MSMF
-            #define _WIN32_WINNT 0x0600 // Windows Vista
-        #else
-            #define _WIN32_WINNT 0x0500 // Windows 2000
-        #endif
-    #endif
-
     #include <windows.h>
     #undef small
     #undef min
@@ -129,6 +123,7 @@ double cvGetRatioWindow_QT(const char* name);
 void cvSetRatioWindow_QT(const char* name,double prop_value);
 
 double cvGetOpenGlProp_QT(const char* name);
+double cvGetPropVisible_QT(const char* name);
 #endif
 
 #endif /* __HIGHGUI_H_ */
diff --git a/modules/highgui/src/window.cpp b/modules/highgui/src/window.cpp
index c879c41..9306f8e 100644
--- a/modules/highgui/src/window.cpp
+++ b/modules/highgui/src/window.cpp
@@ -153,6 +153,14 @@ CV_IMPL double cvGetWindowProperty(const char* name, int prop_id)
         #endif
     break;
 
+    case CV_WND_PROP_VISIBLE:
+        #if defined (HAVE_QT)
+            return cvGetPropVisible_QT(name);
+        #else
+            return -1;
+        #endif
+    break;
+
     default:
         return -1;
     }
@@ -193,11 +201,26 @@ double cv::getWindowProperty(const String& winname, int prop_id)
     return cvGetWindowProperty(winname.c_str(), prop_id);
 }
 
-int cv::waitKey(int delay)
+int cv::waitKeyEx(int delay)
 {
     return cvWaitKey(delay);
 }
 
+int cv::waitKey(int delay)
+{
+    int code = waitKeyEx(delay);
+#ifndef HAVE_WINRT
+    static int use_legacy = -1;
+    if (use_legacy < 0)
+    {
+        use_legacy = getenv("OPENCV_LEGACY_WAITKEY") != NULL ? 1 : 0;
+    }
+    if (use_legacy > 0)
+        return code;
+#endif
+    return code & 0xff;
+}
+
 int cv::createTrackbar(const String& trackbarName, const String& winName,
                    int* value, int count, TrackbarCallback callback,
                    void* userdata)
@@ -391,9 +414,9 @@ CV_IMPL void cvUpdateWindow(const char*)
 
 #if defined (HAVE_QT)
 
-cv::QtFont cv::fontQt(const String& nameFont, int pointSize, Scalar color, int weight,  int style, int /*spacing*/)
+cv::QtFont cv::fontQt(const String& nameFont, int pointSize, Scalar color, int weight, int style, int spacing)
 {
-    CvFont f = cvFontQt(nameFont.c_str(), pointSize,color,weight, style);
+    CvFont f = cvFontQt(nameFont.c_str(), pointSize,color,weight, style, spacing);
     void* pf = &f; // to suppress strict-aliasing
     return *(cv::QtFont*)pf;
 }
@@ -404,6 +427,14 @@ void cv::addText( const Mat& img, const String& text, Point org, const QtFont& f
     cvAddText( &_img, text.c_str(), org, (CvFont*)&font);
 }
 
+void cv::addText( const Mat& img, const String& text, Point org, const String& nameFont,
+        int pointSize, Scalar color, int weight, int style, int spacing)
+{
+    CvFont f = cvFontQt(nameFont.c_str(), pointSize,color,weight, style, spacing);
+    CvMat _img = img;
+    cvAddText( &_img, text.c_str(), org, &f);
+}
+
 void cv::displayStatusBar(const String& name,  const String& text, int delayms)
 {
     cvDisplayStatusBar(name.c_str(),text.c_str(), delayms);
@@ -441,51 +472,58 @@ int cv::createButton(const String& button_name, ButtonCallback on_change, void*
 
 #else
 
+static const char* NO_QT_ERR_MSG = "The library is compiled without QT support";
+
 cv::QtFont cv::fontQt(const String&, int, Scalar, int,  int, int)
 {
-    CV_Error(CV_StsNotImplemented, "The library is compiled without QT support");
+    CV_Error(CV_StsNotImplemented, NO_QT_ERR_MSG);
     return QtFont();
 }
 
 void cv::addText( const Mat&, const String&, Point, const QtFont&)
 {
-    CV_Error(CV_StsNotImplemented, "The library is compiled without QT support");
+    CV_Error(CV_StsNotImplemented, NO_QT_ERR_MSG);
+}
+
+void cv::addText(const Mat&, const String&, Point, const String&, int, Scalar, int, int, int)
+{
+    CV_Error(CV_StsNotImplemented, NO_QT_ERR_MSG);
 }
 
 void cv::displayStatusBar(const String&,  const String&, int)
 {
-    CV_Error(CV_StsNotImplemented, "The library is compiled without QT support");
+    CV_Error(CV_StsNotImplemented, NO_QT_ERR_MSG);
 }
 
 void cv::displayOverlay(const String&,  const String&, int )
 {
-    CV_Error(CV_StsNotImplemented, "The library is compiled without QT support");
+    CV_Error(CV_StsNotImplemented, NO_QT_ERR_MSG);
 }
 
 int cv::startLoop(int (*)(int argc, char *argv[]), int , char**)
 {
-    CV_Error(CV_StsNotImplemented, "The library is compiled without QT support");
+    CV_Error(CV_StsNotImplemented, NO_QT_ERR_MSG);
     return 0;
 }
 
 void cv::stopLoop()
 {
-    CV_Error(CV_StsNotImplemented, "The library is compiled without QT support");
+    CV_Error(CV_StsNotImplemented, NO_QT_ERR_MSG);
 }
 
 void cv::saveWindowParameters(const String&)
 {
-    CV_Error(CV_StsNotImplemented, "The library is compiled without QT support");
+    CV_Error(CV_StsNotImplemented, NO_QT_ERR_MSG);
 }
 
 void cv::loadWindowParameters(const String&)
 {
-    CV_Error(CV_StsNotImplemented, "The library is compiled without QT support");
+    CV_Error(CV_StsNotImplemented, NO_QT_ERR_MSG);
 }
 
 int cv::createButton(const String&, ButtonCallback, void*, int , bool )
 {
-    CV_Error(CV_StsNotImplemented, "The library is compiled without QT support");
+    CV_Error(CV_StsNotImplemented, NO_QT_ERR_MSG);
     return 0;
 }
 
diff --git a/modules/highgui/src/window_QT.cpp b/modules/highgui/src/window_QT.cpp
index 925bc22..4cfce66 100644
--- a/modules/highgui/src/window_QT.cpp
+++ b/modules/highgui/src/window_QT.cpp
@@ -55,7 +55,7 @@
 #endif
 
 #ifdef HAVE_QT_OPENGL
-    #ifdef Q_WS_X11
+    #if defined Q_WS_X11 /* Qt4 */ || defined Q_OS_LINUX /* Qt5 */
         #include <GL/glx.h>
     #endif
 #endif
@@ -138,6 +138,20 @@ double cvGetRatioWindow_QT(const char* name)
     return result;
 }
 
+double cvGetPropVisible_QT(const char* name) {
+    if (!guiMainThread)
+        CV_Error( CV_StsNullPtr, "NULL guiReceiver (please create a window)" );
+
+    double result = 0;
+
+    QMetaObject::invokeMethod(guiMainThread,
+        "getWindowVisible",
+        autoBlockingConnection(),
+        Q_RETURN_ARG(double, result),
+        Q_ARG(QString, QString(name)));
+
+    return result;
+}
 
 void cvSetRatioWindow_QT(const char* name,double prop_value)
 {
@@ -843,7 +857,7 @@ void GuiReceiver::putText(void* arr, QString text, QPoint org, void* arg2)
         //cvScalar(blue_component, green_component, red_component[, alpha_component])
         //Qt map non-transparent to 0xFF and transparent to 0
         //OpenCV scalar is the reverse, so 255-font->color.val[3]
-        qp.setPen(QColor(font->color.val[2], font->color.val[1], font->color.val[0], 255 - font->color.val[3]));
+        qp.setPen(QColor(font->color.val[0], font->color.val[1], font->color.val[2], 255 - font->color.val[3]));
         qp.setFont(f);
     }
     qp.drawText(org, text);
@@ -903,6 +917,16 @@ double GuiReceiver::getPropWindow(QString name)
     return (double) w->getPropWindow();
 }
 
+double GuiReceiver::getWindowVisible(QString name)
+{
+    QPointer<CvWindow> w = icvFindWindowByName(name);
+
+    if (!w)
+        return 0;
+
+    return (double) w->isVisible();
+}
+
 
 void GuiReceiver::setPropWindow(QString name, double arg2)
 {
@@ -1139,13 +1163,18 @@ void GuiReceiver::addButton(QString button_name, int button_type, int initial_bu
     {
         CvBar* lastbar = (CvBar*) global_control_panel->myLayout->itemAt(global_control_panel->myLayout->count() - 1);
 
-        if (lastbar->type == type_CvTrackbar) //if last bar is a trackbar, create a new buttonbar, else, attach to the current bar
+        // if last bar is a trackbar or the user requests a new buttonbar, create a new buttonbar
+        // else, attach to the current bar
+        if (lastbar->type == type_CvTrackbar || cv::QT_NEW_BUTTONBAR & button_type)
             b = CvWindow::createButtonBar(button_name); //the bar has the name of the first button attached to it
         else
             b = (CvButtonbar*) lastbar;
 
     }
 
+    // unset buttonbar flag
+    button_type = button_type & ~cv::QT_NEW_BUTTONBAR;
+
     b->addButton(button_name, (CvButtonCallback) on_change, userdata, button_type, initial_button_state);
 }
 
@@ -2296,10 +2325,89 @@ void CvWindow::icvSaveTrackbars(QSettings* settings)
 
 
 //////////////////////////////////////////////////////
+// OCVViewPort
+
+OCVViewPort::OCVViewPort()
+{
+    mouseCallback = 0;
+    mouseData = 0;
+}
+
+void OCVViewPort::setMouseCallBack(CvMouseCallback callback, void* param)
+{
+    mouseCallback = callback;
+    mouseData = param;
+}
+
+void OCVViewPort::icvmouseEvent(QMouseEvent* evnt, type_mouse_event category)
+{
+    int cv_event = -1, flags = 0;
+
+    icvmouseHandler(evnt, category, cv_event, flags);
+    icvmouseProcessing(QPointF(evnt->pos()), cv_event, flags);
+}
+
+void OCVViewPort::icvmouseHandler(QMouseEvent* evnt, type_mouse_event category, int& cv_event, int& flags)
+{
+    Qt::KeyboardModifiers modifiers = evnt->modifiers();
+    Qt::MouseButtons buttons = evnt->buttons();
+
+    // This line gives excess flags flushing, with it you cannot predefine flags value.
+    // icvmouseHandler called with flags == 0 where it really need.
+    //flags = 0;
+    if(modifiers & Qt::ShiftModifier)
+        flags |= CV_EVENT_FLAG_SHIFTKEY;
+    if(modifiers & Qt::ControlModifier)
+        flags |= CV_EVENT_FLAG_CTRLKEY;
+    if(modifiers & Qt::AltModifier)
+        flags |= CV_EVENT_FLAG_ALTKEY;
+
+    if(buttons & Qt::LeftButton)
+        flags |= CV_EVENT_FLAG_LBUTTON;
+    if(buttons & Qt::RightButton)
+        flags |= CV_EVENT_FLAG_RBUTTON;
+    if(buttons & Qt::MidButton)
+        flags |= CV_EVENT_FLAG_MBUTTON;
+
+    if (cv_event == -1) {
+        if (category == mouse_wheel) {
+            QWheelEvent *we = (QWheelEvent *) evnt;
+            cv_event = ((we->orientation() == Qt::Vertical) ? CV_EVENT_MOUSEWHEEL : CV_EVENT_MOUSEHWHEEL);
+            flags |= (we->delta() & 0xffff)<<16;
+            return;
+        }
+        switch(evnt->button())
+        {
+        case Qt::LeftButton:
+            cv_event = tableMouseButtons[category][0];
+            flags |= CV_EVENT_FLAG_LBUTTON;
+            break;
+        case Qt::RightButton:
+            cv_event = tableMouseButtons[category][1];
+            flags |= CV_EVENT_FLAG_RBUTTON;
+            break;
+        case Qt::MidButton:
+            cv_event = tableMouseButtons[category][2];
+            flags |= CV_EVENT_FLAG_MBUTTON;
+            break;
+        default:
+            cv_event = CV_EVENT_MOUSEMOVE;
+        }
+    }
+}
+
+void OCVViewPort::icvmouseProcessing(QPointF pt, int cv_event, int flags)
+{
+    if (mouseCallback)
+        mouseCallback(cv_event, pt.x(), pt.y(), flags, mouseData);
+}
+
+
+//////////////////////////////////////////////////////
 // DefaultViewPort
 
 
-DefaultViewPort::DefaultViewPort(CvWindow* arg, int arg2) : QGraphicsView(arg), image2Draw_mat(0)
+DefaultViewPort::DefaultViewPort(CvWindow* arg, int arg2) : QGraphicsView(arg), OCVViewPort(), image2Draw_mat(0)
 {
     centralWidget = arg;
     param_keepRatio = arg2;
@@ -2315,12 +2423,10 @@ DefaultViewPort::DefaultViewPort(CvWindow* arg, int arg2) : QGraphicsView(arg),
     connect(timerDisplay, SIGNAL(timeout()), this, SLOT(stopDisplayInfo()));
 
     drawInfo = false;
+    mouseCoordinate  = QPoint(-1, -1);
     positionGrabbing = QPointF(0, 0);
-    positionCorners = QRect(0, 0, size().width(), size().height());
+    positionCorners  = QRect(0, 0, size().width(), size().height());
 
-    on_mouse = 0;
-    on_mouse_param = 0;
-    mouseCoordinate = QPoint(-1, -1);
 
     //no border
     setStyleSheet( "QGraphicsView { border-style: none; }" );
@@ -2348,13 +2454,6 @@ QWidget* DefaultViewPort::getWidget()
 }
 
 
-void DefaultViewPort::setMouseCallBack(CvMouseCallback m, void* param)
-{
-    on_mouse = m;
-
-    on_mouse_param = param;
-}
-
 void DefaultViewPort::writeSettings(QSettings& settings)
 {
     settings.setValue("matrix_view.m11", param_matrixWorld.m11());
@@ -2629,19 +2728,18 @@ void DefaultViewPort::resizeEvent(QResizeEvent* evnt)
 
 void DefaultViewPort::wheelEvent(QWheelEvent* evnt)
 {
+    icvmouseEvent((QMouseEvent *)evnt, mouse_wheel);
+
     scaleView(evnt->delta() / 240.0, evnt->pos());
     viewport()->update();
+
+    QWidget::wheelEvent(evnt);
 }
 
 
 void DefaultViewPort::mousePressEvent(QMouseEvent* evnt)
 {
-    int cv_event = -1, flags = 0;
-    QPoint pt = evnt->pos();
-
-    //icvmouseHandler: pass parameters for cv_event, flags
-    icvmouseHandler(evnt, mouse_down, cv_event, flags);
-    icvmouseProcessing(QPointF(pt), cv_event, flags);
+    icvmouseEvent(evnt, mouse_down);
 
     if (param_matrixWorld.m11()>1)
     {
@@ -2655,12 +2753,7 @@ void DefaultViewPort::mousePressEvent(QMouseEvent* evnt)
 
 void DefaultViewPort::mouseReleaseEvent(QMouseEvent* evnt)
 {
-    int cv_event = -1, flags = 0;
-    QPoint pt = evnt->pos();
-
-    //icvmouseHandler: pass parameters for cv_event, flags
-    icvmouseHandler(evnt, mouse_up, cv_event, flags);
-    icvmouseProcessing(QPointF(pt), cv_event, flags);
+    icvmouseEvent(evnt, mouse_up);
 
     if (param_matrixWorld.m11()>1)
         setCursor(Qt::OpenHandCursor);
@@ -2671,30 +2764,20 @@ void DefaultViewPort::mouseReleaseEvent(QMouseEvent* evnt)
 
 void DefaultViewPort::mouseDoubleClickEvent(QMouseEvent* evnt)
 {
-    int cv_event = -1, flags = 0;
-    QPoint pt = evnt->pos();
-
-    //icvmouseHandler: pass parameters for cv_event, flags
-    icvmouseHandler(evnt, mouse_dbclick, cv_event, flags);
-    icvmouseProcessing(QPointF(pt), cv_event, flags);
-
+    icvmouseEvent(evnt, mouse_dbclick);
     QWidget::mouseDoubleClickEvent(evnt);
 }
 
 
 void DefaultViewPort::mouseMoveEvent(QMouseEvent* evnt)
 {
-    int cv_event = CV_EVENT_MOUSEMOVE, flags = 0;
-    QPoint pt = evnt->pos();
-
-    //icvmouseHandler: pass parameters for cv_event, flags
-    icvmouseHandler(evnt, mouse_move, cv_event, flags);
-    icvmouseProcessing(QPointF(pt), cv_event, flags);
+    icvmouseEvent(evnt, mouse_move);
 
     if (param_matrixWorld.m11() > 1 && evnt->buttons() == Qt::LeftButton)
     {
+        QPoint pt = evnt->pos();
         QPointF dxy = (pt - positionGrabbing)/param_matrixWorld.m11();
-        positionGrabbing = evnt->pos();
+        positionGrabbing = pt;
         moveView(dxy);
     }
 
@@ -2841,45 +2924,6 @@ void DefaultViewPort::scaleView(qreal factor,QPointF center)
 }
 
 
-//up, down, dclick, move
-void DefaultViewPort::icvmouseHandler(QMouseEvent *evnt, type_mouse_event category, int &cv_event, int &flags)
-{
-    Qt::KeyboardModifiers modifiers = evnt->modifiers();
-    Qt::MouseButtons buttons = evnt->buttons();
-
-    flags = 0;
-    if(modifiers & Qt::ShiftModifier)
-        flags |= CV_EVENT_FLAG_SHIFTKEY;
-    if(modifiers & Qt::ControlModifier)
-        flags |= CV_EVENT_FLAG_CTRLKEY;
-    if(modifiers & Qt::AltModifier)
-        flags |= CV_EVENT_FLAG_ALTKEY;
-
-    if(buttons & Qt::LeftButton)
-        flags |= CV_EVENT_FLAG_LBUTTON;
-    if(buttons & Qt::RightButton)
-        flags |= CV_EVENT_FLAG_RBUTTON;
-    if(buttons & Qt::MidButton)
-        flags |= CV_EVENT_FLAG_MBUTTON;
-
-    cv_event = CV_EVENT_MOUSEMOVE;
-    switch(evnt->button())
-    {
-    case Qt::LeftButton:
-        cv_event = tableMouseButtons[category][0];
-        flags |= CV_EVENT_FLAG_LBUTTON;
-        break;
-    case Qt::RightButton:
-        cv_event = tableMouseButtons[category][1];
-        flags |= CV_EVENT_FLAG_RBUTTON;
-        break;
-    case Qt::MidButton:
-        cv_event = tableMouseButtons[category][2];
-        flags |= CV_EVENT_FLAG_MBUTTON;
-        break;
-    default:;
-    }
-}
 
 
 void DefaultViewPort::icvmouseProcessing(QPointF pt, int cv_event, int flags)
@@ -2891,9 +2935,7 @@ void DefaultViewPort::icvmouseProcessing(QPointF pt, int cv_event, int flags)
     mouseCoordinate.rx()=floor(pfx/ratioX);
     mouseCoordinate.ry()=floor(pfy/ratioY);
 
-    if (on_mouse)
-        on_mouse( cv_event, mouseCoordinate.x(),
-            mouseCoordinate.y(), flags, on_mouse_param );
+    OCVViewPort::icvmouseProcessing(QPointF(mouseCoordinate), cv_event, flags);
 }
 
 
@@ -3098,11 +3140,8 @@ void DefaultViewPort::setSize(QSize /*size_*/)
 
 #ifdef HAVE_QT_OPENGL
 
-OpenGlViewPort::OpenGlViewPort(QWidget* _parent) : QGLWidget(_parent), size(-1, -1)
+OpenGlViewPort::OpenGlViewPort(QWidget* _parent) : QGLWidget(_parent), OCVViewPort(), size(-1, -1)
 {
-    mouseCallback = 0;
-    mouseData = 0;
-
     glDrawCallback = 0;
     glDrawData = 0;
 }
@@ -3116,11 +3155,6 @@ QWidget* OpenGlViewPort::getWidget()
     return this;
 }
 
-void OpenGlViewPort::setMouseCallBack(CvMouseCallback callback, void* param)
-{
-    mouseCallback = callback;
-    mouseData = param;
-}
 
 void OpenGlViewPort::writeSettings(QSettings& /*settings*/)
 {
@@ -3181,104 +3215,37 @@ void OpenGlViewPort::paintGL()
         glDrawCallback(glDrawData);
 }
 
-void OpenGlViewPort::mousePressEvent(QMouseEvent* evnt)
-{
-    int cv_event = -1, flags = 0;
-    QPoint pt = evnt->pos();
 
-    icvmouseHandler(evnt, mouse_down, cv_event, flags);
-    icvmouseProcessing(QPointF(pt), cv_event, flags);
+void OpenGlViewPort::wheelEvent(QWheelEvent* evnt)
+{
+    icvmouseEvent((QMouseEvent *)evnt, mouse_wheel);
+    QGLWidget::wheelEvent(evnt);
+}
 
+void OpenGlViewPort::mousePressEvent(QMouseEvent* evnt)
+{
+    icvmouseEvent(evnt, mouse_down);
     QGLWidget::mousePressEvent(evnt);
 }
 
-
 void OpenGlViewPort::mouseReleaseEvent(QMouseEvent* evnt)
 {
-    int cv_event = -1, flags = 0;
-    QPoint pt = evnt->pos();
-
-    icvmouseHandler(evnt, mouse_up, cv_event, flags);
-    icvmouseProcessing(QPointF(pt), cv_event, flags);
-
+    icvmouseEvent(evnt, mouse_up);
     QGLWidget::mouseReleaseEvent(evnt);
 }
 
-
 void OpenGlViewPort::mouseDoubleClickEvent(QMouseEvent* evnt)
 {
-    int cv_event = -1, flags = 0;
-    QPoint pt = evnt->pos();
-
-    icvmouseHandler(evnt, mouse_dbclick, cv_event, flags);
-    icvmouseProcessing(QPointF(pt), cv_event, flags);
-
+    icvmouseEvent(evnt, mouse_dbclick);
     QGLWidget::mouseDoubleClickEvent(evnt);
 }
 
-
 void OpenGlViewPort::mouseMoveEvent(QMouseEvent* evnt)
 {
-    int cv_event = CV_EVENT_MOUSEMOVE, flags = 0;
-    QPoint pt = evnt->pos();
-
-    //icvmouseHandler: pass parameters for cv_event, flags
-    icvmouseHandler(evnt, mouse_move, cv_event, flags);
-    icvmouseProcessing(QPointF(pt), cv_event, flags);
-
+    icvmouseEvent(evnt, mouse_move);
     QGLWidget::mouseMoveEvent(evnt);
 }
 
-void OpenGlViewPort::icvmouseHandler(QMouseEvent* evnt, type_mouse_event category, int& cv_event, int& flags)
-{
-    Qt::KeyboardModifiers modifiers = evnt->modifiers();
-    Qt::MouseButtons buttons = evnt->buttons();
-
-    flags = 0;
-    if (modifiers & Qt::ShiftModifier)
-        flags |= CV_EVENT_FLAG_SHIFTKEY;
-    if (modifiers & Qt::ControlModifier)
-        flags |= CV_EVENT_FLAG_CTRLKEY;
-    if (modifiers & Qt::AltModifier)
-        flags |= CV_EVENT_FLAG_ALTKEY;
-
-    if (buttons & Qt::LeftButton)
-        flags |= CV_EVENT_FLAG_LBUTTON;
-    if (buttons & Qt::RightButton)
-        flags |= CV_EVENT_FLAG_RBUTTON;
-    if (buttons & Qt::MidButton)
-        flags |= CV_EVENT_FLAG_MBUTTON;
-
-    cv_event = CV_EVENT_MOUSEMOVE;
-    switch (evnt->button())
-    {
-    case Qt::LeftButton:
-        cv_event = tableMouseButtons[category][0];
-        flags |= CV_EVENT_FLAG_LBUTTON;
-        break;
-
-    case Qt::RightButton:
-        cv_event = tableMouseButtons[category][1];
-        flags |= CV_EVENT_FLAG_RBUTTON;
-        break;
-
-    case Qt::MidButton:
-        cv_event = tableMouseButtons[category][2];
-        flags |= CV_EVENT_FLAG_MBUTTON;
-        break;
-
-    default:
-        ;
-    }
-}
-
-
-void OpenGlViewPort::icvmouseProcessing(QPointF pt, int cv_event, int flags)
-{
-    if (mouseCallback)
-        mouseCallback(cv_event, pt.x(), pt.y(), flags, mouseData);
-}
-
 
 QSize OpenGlViewPort::sizeHint() const
 {
diff --git a/modules/highgui/src/window_QT.h b/modules/highgui/src/window_QT.h
index c0769dc..b08d713 100644
--- a/modules/highgui/src/window_QT.h
+++ b/modules/highgui/src/window_QT.h
@@ -132,6 +132,7 @@ public slots:
     double getPropWindow(QString name);
     void setPropWindow(QString name, double flags );
     void setWindowTitle(QString name, QString title);
+    double getWindowVisible(QString name);
     double getRatioWindow(QString name);
     void setRatioWindow(QString name, double arg2 );
     void saveWindowParameters(QString name);
@@ -366,12 +367,13 @@ private slots:
 };
 
 
-enum type_mouse_event { mouse_up = 0, mouse_down = 1, mouse_dbclick = 2, mouse_move = 3 };
+enum type_mouse_event { mouse_up = 0, mouse_down = 1, mouse_dbclick = 2, mouse_move = 3, mouse_wheel = 4 };
 static const int tableMouseButtons[][3]={
     {CV_EVENT_LBUTTONUP, CV_EVENT_RBUTTONUP, CV_EVENT_MBUTTONUP},               //mouse_up
     {CV_EVENT_LBUTTONDOWN, CV_EVENT_RBUTTONDOWN, CV_EVENT_MBUTTONDOWN},         //mouse_down
     {CV_EVENT_LBUTTONDBLCLK, CV_EVENT_RBUTTONDBLCLK, CV_EVENT_MBUTTONDBLCLK},   //mouse_dbclick
-    {CV_EVENT_MOUSEMOVE, CV_EVENT_MOUSEMOVE, CV_EVENT_MOUSEMOVE}                //mouse_move
+    {CV_EVENT_MOUSEMOVE, CV_EVENT_MOUSEMOVE, CV_EVENT_MOUSEMOVE},               //mouse_move
+    {0, 0, 0}                                                                   //mouse_wheel, to prevent exceptions in code
 };
 
 
@@ -402,10 +404,26 @@ public:
 };
 
 
+class OCVViewPort : public ViewPort
+{
+public:
+    explicit OCVViewPort();
+    ~OCVViewPort() {};
+    void setMouseCallBack(CvMouseCallback callback, void* param);
+
+protected:
+    void icvmouseEvent(QMouseEvent* event, type_mouse_event category);
+    void icvmouseHandler(QMouseEvent* event, type_mouse_event category, int& cv_event, int& flags);
+    virtual void icvmouseProcessing(QPointF pt, int cv_event, int flags);
+
+    CvMouseCallback mouseCallback;
+    void* mouseData;
+};
+
 
 #ifdef HAVE_QT_OPENGL
 
-class OpenGlViewPort : public QGLWidget, public ViewPort
+class OpenGlViewPort : public QGLWidget, public OCVViewPort
 {
 public:
     explicit OpenGlViewPort(QWidget* parent);
@@ -413,8 +431,6 @@ public:
 
     QWidget* getWidget();
 
-    void setMouseCallBack(CvMouseCallback callback, void* param);
-
     void writeSettings(QSettings& settings);
     void readSettings(QSettings& settings);
 
@@ -436,6 +452,7 @@ protected:
     void resizeGL(int w, int h);
     void paintGL();
 
+    void wheelEvent(QWheelEvent* event);
     void mouseMoveEvent(QMouseEvent* event);
     void mousePressEvent(QMouseEvent* event);
     void mouseReleaseEvent(QMouseEvent* event);
@@ -446,20 +463,14 @@ protected:
 private:
     QSize size;
 
-    CvMouseCallback mouseCallback;
-    void* mouseData;
-
     CvOpenGlDrawCallback glDrawCallback;
     void* glDrawData;
-
-    void icvmouseHandler(QMouseEvent* event, type_mouse_event category, int& cv_event, int& flags);
-    void icvmouseProcessing(QPointF pt, int cv_event, int flags);
 };
 
 #endif // HAVE_QT_OPENGL
 
 
-class DefaultViewPort : public QGraphicsView, public ViewPort
+class DefaultViewPort : public QGraphicsView, public OCVViewPort
 {
     Q_OBJECT
 
@@ -469,8 +480,6 @@ public:
 
     QWidget* getWidget();
 
-    void setMouseCallBack(CvMouseCallback callback, void* param);
-
     void writeSettings(QSettings& settings);
     void readSettings(QSettings& settings);
 
@@ -508,6 +517,7 @@ protected:
     void contextMenuEvent(QContextMenuEvent* event);
     void resizeEvent(QResizeEvent* event);
     void paintEvent(QPaintEvent* paintEventInfo);
+
     void wheelEvent(QWheelEvent* event);
     void mouseMoveEvent(QMouseEvent* event);
     void mousePressEvent(QMouseEvent* event);
@@ -524,17 +534,13 @@ private:
     QImage image2Draw_qt;
     int nbChannelOriginImage;
 
-    //for mouse callback
-    CvMouseCallback on_mouse;
-    void* on_mouse_param;
-
 
     void scaleView(qreal scaleFactor, QPointF center);
     void moveView(QPointF delta);
 
-    QPoint mouseCoordinate;
+    QPoint  mouseCoordinate;
     QPointF positionGrabbing;
-    QRect  positionCorners;
+    QRect   positionCorners;
     QTransform matrixWorld_inv;
     float ratioX, ratioY;
 
@@ -553,7 +559,7 @@ private:
     void draw2D(QPainter *painter);
     void drawStatusBar();
     void controlImagePosition();
-    void icvmouseHandler(QMouseEvent *event, type_mouse_event category, int &cv_event, int &flags);
+
     void icvmouseProcessing(QPointF pt, int cv_event, int flags);
 
 private slots:
diff --git a/modules/highgui/src/window_cocoa.mm b/modules/highgui/src/window_cocoa.mm
index 4ab1e36..a1befc3 100644
--- a/modules/highgui/src/window_cocoa.mm
+++ b/modules/highgui/src/window_cocoa.mm
@@ -82,42 +82,26 @@ static NSAutoreleasePool *pool = nil;
 static NSMutableDictionary *windows = nil;
 static bool wasInitialized = false;
 
- at interface CVView : NSView {
-    NSImage *image;
-}
- at property(retain) NSImage *image;
+ at interface CVView : NSView
+ at property(strong) NSImage *image;
 - (void)setImageData:(CvArr *)arr;
 @end
 
- at interface CVSlider : NSView {
-    NSSlider *slider;
-    NSTextField *name;
-    int *value;
-    void *userData;
-    CvTrackbarCallback callback;
-    CvTrackbarCallback2 callback2;
-}
- at property(retain) NSSlider *slider;
- at property(retain) NSTextField *name;
+ at interface CVSlider : NSView
+ at property(strong) NSSlider *slider;
+ at property(strong) NSTextField *name;
 @property(assign) int *value;
 @property(assign) void *userData;
 @property(assign) CvTrackbarCallback callback;
 @property(assign) CvTrackbarCallback2 callback2;
 @end
 
- at interface CVWindow : NSWindow {
-    NSMutableDictionary *sliders;
-    CvMouseCallback mouseCallback;
-    void *mouseParam;
-    BOOL autosize;
-    BOOL firstContent;
-    int status;
-}
+ at interface CVWindow : NSWindow
 @property(assign) CvMouseCallback mouseCallback;
 @property(assign) void *mouseParam;
 @property(assign) BOOL autosize;
 @property(assign) BOOL firstContent;
- at property(retain) NSMutableDictionary *sliders;
+ at property(strong) NSMutableDictionary *sliders;
 @property(readwrite) int status;
 - (CVView *)contentView;
 - (void)cvSendMouseEvent:(NSEvent *)event type:(int)type flags:(int)flags;
@@ -230,8 +214,10 @@ CV_IMPL void cvShowImage( const char* name, const CvArr* arr)
             //Set new view size considering sliders (reserve height and min width)
             NSRect vrectNew = vrectOld;
             int slider_height = 0;
-            for(NSString *key in [window sliders]) {
-                slider_height += [[[window sliders] valueForKey:key] frame].size.height;
+            if ([window respondsToSelector:@selector(sliders)]) {
+                for(NSString *key in [window sliders]) {
+                    slider_height += [[[window sliders] valueForKey:key] frame].size.height;
+                }
             }
             vrectNew.size.height = [[[window contentView] image] size].height + slider_height;
             vrectNew.size.width = std::max<int>([[[window contentView] image] size].width, MIN_SLIDER_WIDTH);
@@ -331,9 +317,12 @@ CV_IMPL int cvCreateTrackbar2(const char* trackbar_name,
     NSAutoreleasePool* localpool = [[NSAutoreleasePool alloc] init];
     int res = cvCreateTrackbar(trackbar_name, window_name, val, count, NULL);
     if(res) {
-        CVSlider *slider = [[cvGetWindow(window_name) sliders] valueForKey:[NSString stringWithFormat:@"%s", trackbar_name]];
-        [slider setCallback2:on_notify2];
-        [slider setUserData:userdata];
+        CVWindow *window = cvGetWindow(window_name);
+        if (window && [window respondsToSelector:@selector(sliders)]) {
+            CVSlider *slider = [[window sliders] valueForKey:[NSString stringWithFormat:@"%s", trackbar_name]];
+            [slider setCallback2:on_notify2];
+            [slider setUserData:userdata];
+        }
     }
     [localpool drain];
     return res;
@@ -383,7 +372,7 @@ cvSetMouseCallback( const char* name, CvMouseCallback function, void* info)
     localpool4 = [[NSAutoreleasePool alloc] init];
 
     window = cvGetWindow(window_name);
-    if(window) {
+    if(window && [window respondsToSelector:@selector(sliders)]) {
         CVSlider *slider = [[window sliders] valueForKey:[NSString stringWithFormat:@"%s", trackbar_name]];
         if(slider) {
             pos = [[slider slider] intValue];
@@ -414,7 +403,7 @@ CV_IMPL void cvSetTrackbarPos(const char* trackbar_name, const char* window_name
     localpool5 = [[NSAutoreleasePool alloc] init];
 
     window = cvGetWindow(window_name);
-    if(window) {
+    if(window && [window respondsToSelector:@selector(sliders)]) {
         slider = [[window sliders] valueForKey:[NSString stringWithFormat:@"%s", trackbar_name]];
         if(slider) {
             [[slider slider] setIntValue:pos];
@@ -442,7 +431,7 @@ CV_IMPL void cvSetTrackbarMax(const char* trackbar_name, const char* window_name
     localpool5 = [[NSAutoreleasePool alloc] init];
 
     window = cvGetWindow(window_name);
-    if(window) {
+    if(window && [window respondsToSelector:@selector(sliders)]) {
         slider = [[window sliders] valueForKey:[NSString stringWithFormat:@"%s", trackbar_name]];
         if(slider) {
             if(maxval >= 0) {
@@ -473,7 +462,7 @@ CV_IMPL void cvSetTrackbarMin(const char* trackbar_name, const char* window_name
     localpool5 = [[NSAutoreleasePool alloc] init];
 
     window = cvGetWindow(window_name);
-    if(window) {
+    if(window && [window respondsToSelector:@selector(sliders)]) {
         slider = [[window sliders] valueForKey:[NSString stringWithFormat:@"%s", trackbar_name]];
         if(slider) {
             if(minval >= 0) {
@@ -709,9 +698,11 @@ void cv::setWindowTitle(const String& winname, const String& title)
     double viewHeight = [self contentView].frame.size.height;
     double viewWidth = [self contentView].frame.size.width;
     CVWindow *window = (CVWindow *)[[self contentView] window];
-    for(NSString *key in [window sliders]) {
-        NSSlider *slider = [[window sliders] valueForKey:key];
-        viewHeight = std::min(viewHeight, (double)([slider frame].origin.y));
+    if ([window respondsToSelector:@selector(sliders)]) {
+        for(NSString *key in [window sliders]) {
+            NSSlider *slider = [[window sliders] valueForKey:key];
+            viewHeight = std::min(viewHeight, (double)([slider frame].origin.y));
+        }
     }
     viewHeight -= TOP_BORDER;
     mp.y = viewHeight - mp.y;
@@ -929,13 +920,15 @@ void cv::setWindowTitle(const String& winname, const String& title)
     int height = size.height;
 
     CVWindow *cvwindow = (CVWindow *)[self window];
-    for(NSString *key in [cvwindow sliders]) {
-        NSSlider *slider = [[cvwindow sliders] valueForKey:key];
-        NSRect r = [slider frame];
-        r.origin.y = height - r.size.height;
-        r.size.width = [[cvwindow contentView] frame].size.width;
-        [slider setFrame:r];
-        height -= r.size.height;
+    if ([cvwindow respondsToSelector:@selector(sliders)]) {
+        for(NSString *key in [cvwindow sliders]) {
+            NSSlider *slider = [[cvwindow sliders] valueForKey:key];
+            NSRect r = [slider frame];
+            r.origin.y = height - r.size.height;
+            r.size.width = [[cvwindow contentView] frame].size.width;
+            [slider setFrame:r];
+            height -= r.size.height;
+        }
     }
     [localpool drain];
 }
diff --git a/modules/highgui/src/window_gtk.cpp b/modules/highgui/src/window_gtk.cpp
index c722165..6e4da8b 100644
--- a/modules/highgui/src/window_gtk.cpp
+++ b/modules/highgui/src/window_gtk.cpp
@@ -52,8 +52,11 @@
 #include <stdio.h>
 
 #if (GTK_MAJOR_VERSION == 3)
-  #define GTK_VERSION3
+  #define GTK_VERSION3 1
 #endif //GTK_MAJOR_VERSION >= 3
+#if (GTK_MAJOR_VERSION > 3 || (GTK_MAJOR_VERSION == 3 && GTK_MINOR_VERSION >= 4))
+  #define GTK_VERSION3_4 1
+#endif
 
 #ifdef HAVE_OPENGL
     #include <gtk/gtkgl.h>
@@ -61,6 +64,13 @@
     #include <GL/glu.h>
 #endif
 
+#ifndef BIT_ALLIN
+    #define BIT_ALLIN(x,y) ( ((x)&(y)) == (y) )
+#endif
+#ifndef BIT_MAP
+    #define BIT_MAP(x,y,z) ( ((x)&(y)) ? (z) : 0 )
+#endif
+
 // TODO Fix the initial window size when flags=0.  Right now the initial window is by default
 // 320x240 size.  A better default would be actual size of the image.  Problem
 // is determining desired window size with trackbars while still allowing resizing.
@@ -485,7 +495,7 @@ GType cvImageWidget_get_type (void){
           (GClassInitFunc) cvImageWidget_class_init,
           sizeof(CvImageWidget),
           (GInstanceInitFunc) cvImageWidget_init,
-          (GTypeFlags)NULL
+          (GTypeFlags)0
           );
     }
 
@@ -609,9 +619,13 @@ CV_IMPL int cvStartWindowThread(){
     // conditional that indicates a key has been pressed
     cond_have_key = g_cond_new();
 
+#if !GLIB_CHECK_VERSION(2, 32, 0)
     // this is the window update thread
     window_thread = g_thread_create((GThreadFunc) icvWindowThreadLoop,
                     NULL, TRUE, NULL);
+#else
+    window_thread = g_thread_new("OpenCV window update", (GThreadFunc)icvWindowThreadLoop, NULL);
+#endif
     }
     thread_started = window_thread!=NULL;
     return thread_started;
@@ -1006,6 +1020,7 @@ CV_IMPL int cvNamedWindow( const char* name, int flags )
 
     CvWindow* window;
     int len;
+    int b_nautosize;
 
     cvInitSystem(1,(char**)&name);
     if( !name )
@@ -1066,6 +1081,8 @@ CV_IMPL int cvNamedWindow( const char* name, int flags )
                         G_CALLBACK(icvOnMouse), window );
     g_signal_connect( window->widget, "motion-notify-event",
                         G_CALLBACK(icvOnMouse), window );
+    g_signal_connect( window->widget, "scroll-event",
+                        G_CALLBACK(icvOnMouse), window );
     g_signal_connect( window->frame, "delete-event",
                         G_CALLBACK(icvOnClose), window );
 #if defined(GTK_VERSION3)
@@ -1076,7 +1093,12 @@ CV_IMPL int cvNamedWindow( const char* name, int flags )
                         G_CALLBACK(cvImageWidget_expose), window );
 #endif //GTK_VERSION3
 
-    gtk_widget_add_events (window->widget, GDK_BUTTON_RELEASE_MASK | GDK_BUTTON_PRESS_MASK | GDK_POINTER_MOTION_MASK) ;
+
+#if defined(GTK_VERSION3_4)
+    gtk_widget_add_events (window->widget, GDK_BUTTON_RELEASE_MASK | GDK_BUTTON_PRESS_MASK | GDK_POINTER_MOTION_MASK | GDK_SCROLL_MASK | GDK_SMOOTH_SCROLL_MASK) ;
+#else
+    gtk_widget_add_events (window->widget, GDK_BUTTON_RELEASE_MASK | GDK_BUTTON_PRESS_MASK | GDK_POINTER_MOTION_MASK | GDK_SCROLL_MASK) ;
+#endif //GTK_VERSION3_4
 
     gtk_widget_show( window->frame );
     gtk_window_set_title( GTK_WINDOW(window->frame), name );
@@ -1085,11 +1107,11 @@ CV_IMPL int cvNamedWindow( const char* name, int flags )
         hg_windows->prev = window;
     hg_windows = window;
 
-    gtk_window_set_resizable( GTK_WINDOW(window->frame), (flags & CV_WINDOW_AUTOSIZE) == 0 );
-
+    b_nautosize = ((flags & CV_WINDOW_AUTOSIZE) == 0);
+    gtk_window_set_resizable( GTK_WINDOW(window->frame), b_nautosize );
 
     // allow window to be resized
-    if( (flags & CV_WINDOW_AUTOSIZE)==0 ){
+    if( b_nautosize ){
         GdkGeometry geometry;
         geometry.min_width = 50;
         geometry.min_height = 50;
@@ -1216,13 +1238,33 @@ static void icvDeleteWindow( CvWindow* window )
     }
 
     cvFree( &window );
+
+    // if last window...
+    if( hg_windows == 0 )
+    {
 #ifdef HAVE_GTHREAD
-    // if last window, send key press signal
-    // to jump out of any waiting cvWaitKey's
-    if(hg_windows==0 && thread_started){
-        g_cond_broadcast(cond_have_key);
-    }
+        if( thread_started )
+        {
+            // send key press signal to jump out of any waiting cvWaitKey's
+            g_cond_broadcast( cond_have_key );
+        }
+        else
+        {
 #endif
+            // Some GTK+ modules (like the Unity module) use GDBusConnection,
+            // which has a habit of postponing cleanup by performing it via
+            // idle sources added to the main loop. Since this was the last window,
+            // we can assume that no event processing is going to happen in the
+            // nearest future, so we should force that cleanup (by handling all pending
+            // events) while we still have the chance.
+            // This is not needed if thread_started is true, because the background
+            // thread will process events continuously.
+            while( gtk_events_pending() )
+                gtk_main_iteration();
+#ifdef HAVE_GTHREAD
+        }
+#endif
+    }
 }
 
 
@@ -1797,7 +1839,7 @@ static gboolean icvOnKeyPress(GtkWidget* widget, GdkEventKey* event, gpointer us
 {
     int code = 0;
 
-    if ( (event->state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK && (event->keyval == GDK_s || event->keyval == GDK_S))
+    if ( BIT_ALLIN(event->state, GDK_CONTROL_MASK) && (event->keyval == GDK_s || event->keyval == GDK_S))
     {
         try
         {
@@ -1881,7 +1923,7 @@ static gboolean icvOnMouse( GtkWidget *widget, GdkEvent *event, gpointer user_da
     CvWindow* window = (CvWindow*)user_data;
     CvPoint2D32f pt32f(-1., -1.);
     CvPoint pt(-1,-1);
-    int cv_event = -1, state = 0;
+    int cv_event = -1, state = 0, flags = 0;
     CvImageWidget * image_widget = CV_IMAGE_WIDGET( widget );
 
     if( window->signature != CV_WINDOW_MAGIC_VAL ||
@@ -1927,12 +1969,40 @@ static gboolean icvOnMouse( GtkWidget *widget, GdkEvent *event, gpointer user_da
         }
         state = event_button->state;
     }
+    else if( event->type == GDK_SCROLL )
+    {
+#if defined(GTK_VERSION3_4)
+        // NOTE: in current implementation doesn't possible to put into callback function delta_x and delta_y separetely
+        double delta = (event->scroll.delta_x + event->scroll.delta_y);
+        cv_event   = (event->scroll.delta_y!=0) ? CV_EVENT_MOUSEHWHEEL : CV_EVENT_MOUSEWHEEL;
+#else
+        cv_event = CV_EVENT_MOUSEWHEEL;
+#endif //GTK_VERSION3_4
+
+        state    = event->scroll.state;
+
+        switch(event->scroll.direction) {
+#if defined(GTK_VERSION3_4)
+        case GDK_SCROLL_SMOOTH: flags |= (((int)delta << 16));
+            break;
+#endif //GTK_VERSION3_4
+        case GDK_SCROLL_LEFT:  cv_event = CV_EVENT_MOUSEHWHEEL;
+        case GDK_SCROLL_UP:    flags |= ~0xffff;
+            break;
+        case GDK_SCROLL_RIGHT: cv_event = CV_EVENT_MOUSEHWHEEL;
+        case GDK_SCROLL_DOWN:  flags |= (((int)1 << 16));
+            break;
+        default: ;
+        };
+    }
 
-    if( cv_event >= 0 ){
+    if( cv_event >= 0 )
+    {
         // scale point if image is scaled
         if( (image_widget->flags & CV_WINDOW_AUTOSIZE)==0 &&
              image_widget->original_image &&
-             image_widget->scaled_image ){
+             image_widget->scaled_image )
+        {
             // image origin is not necessarily at (0,0)
 #if defined (GTK_VERSION3)
             int x0 = (gtk_widget_get_allocated_width(widget) - image_widget->scaled_image->cols)/2;
@@ -1946,25 +2016,27 @@ static gboolean icvOnMouse( GtkWidget *widget, GdkEvent *event, gpointer user_da
             pt.y = cvFloor( ((pt32f.y-y0)*image_widget->original_image->rows)/
                                             image_widget->scaled_image->rows );
         }
-        else{
+        else
+        {
             pt = cvPointFrom32f( pt32f );
         }
 
 //        if((unsigned)pt.x < (unsigned)(image_widget->original_image->width) &&
 //           (unsigned)pt.y < (unsigned)(image_widget->original_image->height) )
         {
-            int flags = (state & GDK_SHIFT_MASK ? CV_EVENT_FLAG_SHIFTKEY : 0) |
-                (state & GDK_CONTROL_MASK ? CV_EVENT_FLAG_CTRLKEY : 0) |
-                (state & (GDK_MOD1_MASK|GDK_MOD2_MASK) ? CV_EVENT_FLAG_ALTKEY : 0) |
-                (state & GDK_BUTTON1_MASK ? CV_EVENT_FLAG_LBUTTON : 0) |
-                (state & GDK_BUTTON2_MASK ? CV_EVENT_FLAG_MBUTTON : 0) |
-                (state & GDK_BUTTON3_MASK ? CV_EVENT_FLAG_RBUTTON : 0);
+            flags |= BIT_MAP(state, GDK_SHIFT_MASK,   CV_EVENT_FLAG_SHIFTKEY) |
+                BIT_MAP(state, GDK_CONTROL_MASK, CV_EVENT_FLAG_CTRLKEY)  |
+                BIT_MAP(state, GDK_MOD1_MASK,    CV_EVENT_FLAG_ALTKEY)   |
+                BIT_MAP(state, GDK_MOD2_MASK,    CV_EVENT_FLAG_ALTKEY)   |
+                BIT_MAP(state, GDK_BUTTON1_MASK, CV_EVENT_FLAG_LBUTTON)  |
+                BIT_MAP(state, GDK_BUTTON2_MASK, CV_EVENT_FLAG_MBUTTON)  |
+                BIT_MAP(state, GDK_BUTTON3_MASK, CV_EVENT_FLAG_RBUTTON);
             window->on_mouse( cv_event, pt.x, pt.y, flags, window->on_mouse_param );
         }
     }
 
-        return FALSE;
-    }
+    return FALSE;
+}
 
 
 static gboolean icvAlarm( gpointer user_data )
diff --git a/modules/highgui/test/test_precomp.hpp b/modules/highgui/test/test_precomp.hpp
index e4d7797..40945ac 100644
--- a/modules/highgui/test/test_precomp.hpp
+++ b/modules/highgui/test/test_precomp.hpp
@@ -6,16 +6,4 @@
 #  endif
 #endif
 
-#ifndef __OPENCV_TEST_PRECOMP_HPP__
-#define __OPENCV_TEST_PRECOMP_HPP__
-
-#include <iostream>
 #include "opencv2/ts.hpp"
-//#include "opencv2/imgproc.hpp"
-//#include "opencv2/imgcodecs.hpp"
-//#include "opencv2/highgui.hpp"
-//#include "opencv2/imgproc/imgproc_c.h"
-
-//#include "opencv2/core/private.hpp"
-
-#endif
diff --git a/modules/imgcodecs/CMakeLists.txt b/modules/imgcodecs/CMakeLists.txt
index 8b8c577..7800640 100644
--- a/modules/imgcodecs/CMakeLists.txt
+++ b/modules/imgcodecs/CMakeLists.txt
@@ -35,6 +35,11 @@ if(HAVE_PNG)
   list(APPEND GRFMT_LIBS ${PNG_LIBRARIES})
 endif()
 
+if(HAVE_GDCM)
+  ocv_include_directories(${GDCM_INCLUDE_DIRS})
+  list(APPEND GRFMT_LIBS ${GDCM_LIBRARIES})
+endif()
+
 if(HAVE_TIFF)
   ocv_include_directories(${TIFF_INCLUDE_DIR})
   list(APPEND GRFMT_LIBS ${TIFF_LIBRARIES})
@@ -57,12 +62,13 @@ endif()
 
 file(GLOB grfmt_hdrs ${CMAKE_CURRENT_LIST_DIR}/src/grfmt*.hpp)
 file(GLOB grfmt_srcs ${CMAKE_CURRENT_LIST_DIR}/src/grfmt*.cpp)
+
 list(APPEND grfmt_hdrs ${CMAKE_CURRENT_LIST_DIR}/src/bitstrm.hpp)
 list(APPEND grfmt_srcs ${CMAKE_CURRENT_LIST_DIR}/src/bitstrm.cpp)
 list(APPEND grfmt_hdrs ${CMAKE_CURRENT_LIST_DIR}/src/rgbe.hpp)
 list(APPEND grfmt_srcs ${CMAKE_CURRENT_LIST_DIR}/src/rgbe.cpp)
-list(APPEND grfmt_hdrs ${CMAKE_CURRENT_LIST_DIR}/src/jpeg_exif.hpp)
-list(APPEND grfmt_srcs ${CMAKE_CURRENT_LIST_DIR}/src/jpeg_exif.cpp)
+list(APPEND grfmt_hdrs ${CMAKE_CURRENT_LIST_DIR}/src/exif.hpp)
+list(APPEND grfmt_srcs ${CMAKE_CURRENT_LIST_DIR}/src/exif.cpp)
 
 source_group("Src\\grfmts" FILES ${grfmt_hdrs} ${grfmt_srcs})
 
@@ -84,7 +90,7 @@ file(GLOB imgcodecs_ext_hdrs
 
 if(IOS)
   list(APPEND imgcodecs_srcs ${CMAKE_CURRENT_LIST_DIR}/src/ios_conversions.mm)
-  list(APPEND IMGCODECS_LIBRARIES "-framework Accelerate" "-framework CoreGraphics" "-framework CoreImage" "-framework QuartzCore" "-framework AssetsLibrary")
+  list(APPEND IMGCODECS_LIBRARIES "-framework Accelerate" "-framework CoreGraphics" "-framework QuartzCore" "-framework AssetsLibrary")
 endif()
 
 if(UNIX)
diff --git a/modules/imgcodecs/include/opencv2/imgcodecs.hpp b/modules/imgcodecs/include/opencv2/imgcodecs.hpp
index ac0fd24..6359de6 100644
--- a/modules/imgcodecs/include/opencv2/imgcodecs.hpp
+++ b/modules/imgcodecs/include/opencv2/imgcodecs.hpp
@@ -40,8 +40,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_IMGCODECS_HPP__
-#define __OPENCV_IMGCODECS_HPP__
+#ifndef OPENCV_IMGCODECS_HPP
+#define OPENCV_IMGCODECS_HPP
 
 #include "opencv2/core.hpp"
 
@@ -73,7 +73,8 @@ enum ImreadModes {
        IMREAD_REDUCED_GRAYSCALE_4  = 32, //!< If set, always convert image to the single channel grayscale image and the image size reduced 1/4.
        IMREAD_REDUCED_COLOR_4      = 33, //!< If set, always convert image to the 3 channel BGR color image and the image size reduced 1/4.
        IMREAD_REDUCED_GRAYSCALE_8  = 64, //!< If set, always convert image to the single channel grayscale image and the image size reduced 1/8.
-       IMREAD_REDUCED_COLOR_8      = 65  //!< If set, always convert image to the 3 channel BGR color image and the image size reduced 1/8.
+       IMREAD_REDUCED_COLOR_8      = 65, //!< If set, always convert image to the 3 channel BGR color image and the image size reduced 1/8.
+       IMREAD_IGNORE_ORIENTATION   = 128 //!< If set, do not rotate the image according to EXIF's orientation flag.
      };
 
 //! Imwrite flags
@@ -84,11 +85,12 @@ enum ImwriteFlags {
        IMWRITE_JPEG_RST_INTERVAL   = 4,  //!< JPEG restart interval, 0 - 65535, default is 0 - no restart.
        IMWRITE_JPEG_LUMA_QUALITY   = 5,  //!< Separate luma quality level, 0 - 100, default is 0 - don't use.
        IMWRITE_JPEG_CHROMA_QUALITY = 6,  //!< Separate chroma quality level, 0 - 100, default is 0 - don't use.
-       IMWRITE_PNG_COMPRESSION     = 16, //!< For PNG, it can be the compression level from 0 to 9. A higher value means a smaller size and longer compression time. Default value is 3.
+       IMWRITE_PNG_COMPRESSION     = 16, //!< For PNG, it can be the compression level from 0 to 9. A higher value means a smaller size and longer compression time. Default value is 3. Also strategy is changed to IMWRITE_PNG_STRATEGY_DEFAULT (Z_DEFAULT_STRATEGY).
        IMWRITE_PNG_STRATEGY        = 17, //!< One of cv::ImwritePNGFlags, default is IMWRITE_PNG_STRATEGY_DEFAULT.
        IMWRITE_PNG_BILEVEL         = 18, //!< Binary level PNG, 0 or 1, default is 0.
        IMWRITE_PXM_BINARY          = 32, //!< For PPM, PGM, or PBM, it can be a binary format flag, 0 or 1. Default value is 1.
-       IMWRITE_WEBP_QUALITY        = 64  //!< For WEBP, it can be a quality from 1 to 100 (the higher is the better). By default (without any parameter) and for quality above 100 the lossless compression is used.
+       IMWRITE_WEBP_QUALITY        = 64, //!< For WEBP, it can be a quality from 1 to 100 (the higher is the better). By default (without any parameter) and for quality above 100 the lossless compression is used.
+       IMWRITE_PAM_TUPLETYPE       = 128,//!< For PAM, sets the TUPLETYPE field to the corresponding string value that is defined for the format
      };
 
 //! Imwrite PNG specific flags used to tune the compression algorithm.
@@ -107,6 +109,16 @@ enum ImwritePNGFlags {
        IMWRITE_PNG_STRATEGY_FIXED        = 4  //!< Using this value prevents the use of dynamic Huffman codes, allowing for a simpler decoder for special applications.
      };
 
+//! Imwrite PAM specific tupletype flags used to define the 'TUPETYPE' field of a PAM file.
+enum ImwritePAMFlags {
+       IMWRITE_PAM_FORMAT_NULL = 0,
+       IMWRITE_PAM_FORMAT_BLACKANDWHITE = 1,
+       IMWRITE_PAM_FORMAT_GRAYSCALE = 2,
+       IMWRITE_PAM_FORMAT_GRAYSCALE_ALPHA = 3,
+       IMWRITE_PAM_FORMAT_RGB = 4,
+       IMWRITE_PAM_FORMAT_RGB_ALPHA = 5,
+     };
+
 /** @brief Loads an image from a file.
 
 @anchor imread
@@ -146,6 +158,8 @@ Currently, the following file formats are supported:
     then [GDAL](http://www.gdal.org) driver will be used in order to decode the image by supporting
     the following formats: [Raster](http://www.gdal.org/formats_list.html),
     [Vector](http://www.gdal.org/ogr_formats.html).
+-   If EXIF information are embedded in the image file, the EXIF orientation will be taken into account
+    and thus the image will be rotated accordingly except if the flag @ref IMREAD_IGNORE_ORIENTATION is passed.
 @param filename Name of file to be loaded.
 @param flags Flag that can take values of cv::ImreadModes
 */
@@ -264,4 +278,4 @@ CV_EXPORTS_W bool imencode( const String& ext, InputArray img,
 
 } // cv
 
-#endif //__OPENCV_IMGCODECS_HPP__
+#endif //OPENCV_IMGCODECS_HPP
diff --git a/modules/imgcodecs/include/opencv2/imgcodecs/imgcodecs_c.h b/modules/imgcodecs/include/opencv2/imgcodecs/imgcodecs_c.h
index ad793cc..3130710 100644
--- a/modules/imgcodecs/include/opencv2/imgcodecs/imgcodecs_c.h
+++ b/modules/imgcodecs/include/opencv2/imgcodecs/imgcodecs_c.h
@@ -39,8 +39,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_IMGCODECS_H__
-#define __OPENCV_IMGCODECS_H__
+#ifndef OPENCV_IMGCODECS_H
+#define OPENCV_IMGCODECS_H
 
 #include "opencv2/core/core_c.h"
 
@@ -63,7 +63,9 @@ enum
 /* any depth, ? */
     CV_LOAD_IMAGE_ANYDEPTH   =2,
 /* ?, any color */
-    CV_LOAD_IMAGE_ANYCOLOR   =4
+    CV_LOAD_IMAGE_ANYCOLOR   =4,
+/* ?, no rotate */
+    CV_LOAD_IMAGE_IGNORE_ORIENTATION  =128
 };
 
 /* load image from file
@@ -92,9 +94,18 @@ enum
     CV_IMWRITE_PNG_STRATEGY_RLE =3,
     CV_IMWRITE_PNG_STRATEGY_FIXED =4,
     CV_IMWRITE_PXM_BINARY =32,
-    CV_IMWRITE_WEBP_QUALITY =64
+    CV_IMWRITE_WEBP_QUALITY =64,
+    CV_IMWRITE_PAM_TUPLETYPE = 128,
+    CV_IMWRITE_PAM_FORMAT_NULL = 0,
+    CV_IMWRITE_PAM_FORMAT_BLACKANDWHITE = 1,
+    CV_IMWRITE_PAM_FORMAT_GRAYSCALE = 2,
+    CV_IMWRITE_PAM_FORMAT_GRAYSCALE_ALPHA = 3,
+    CV_IMWRITE_PAM_FORMAT_RGB = 4,
+    CV_IMWRITE_PAM_FORMAT_RGB_ALPHA = 5,
 };
 
+
+
 /* save image to file */
 CVAPI(int) cvSaveImage( const char* filename, const CvArr* image,
                         const int* params CV_DEFAULT(0) );
@@ -134,4 +145,4 @@ CVAPI(int) cvHaveImageWriter(const char* filename);
 }
 #endif
 
-#endif // __OPENCV_IMGCODECS_H__
+#endif // OPENCV_IMGCODECS_H
diff --git a/modules/imgcodecs/src/exif.cpp b/modules/imgcodecs/src/exif.cpp
new file mode 100644
index 0000000..8a4f3f4
--- /dev/null
+++ b/modules/imgcodecs/src/exif.cpp
@@ -0,0 +1,625 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+//  By downloading, copying, installing or using the software you agree to this license.
+//  If you do not agree to this license, do not download, install,
+//  copy or use the software.
+//
+//
+//                           License Agreement
+//                For Open Source Computer Vision Library
+//
+// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
+// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+//   * Redistribution's of source code must retain the above copyright notice,
+//     this list of conditions and the following disclaimer.
+//
+//   * Redistribution's in binary form must reproduce the above copyright notice,
+//     this list of conditions and the following disclaimer in the documentation
+//     and/or other materials provided with the distribution.
+//
+//   * The name of the copyright holders may not be used to endorse or promote products
+//     derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "exif.hpp"
+
+namespace {
+
+    class ExifParsingError {
+    };
+}
+
+
+namespace cv
+{
+
+ExifEntry_t::ExifEntry_t() :
+    field_float(0), field_double(0), field_u32(0), field_s32(0),
+    tag(INVALID_TAG), field_u16(0), field_s16(0), field_u8(0), field_s8(0)
+{
+}
+
+/**
+ * @brief ExifReader constructor
+ */
+ExifReader::ExifReader(std::string filename) : m_filename(filename), m_format(NONE)
+{
+}
+
+/**
+ * @brief ExifReader destructor
+ */
+ExifReader::~ExifReader()
+{
+}
+
+/**
+ * @brief Parsing the file and prepare (internally) exif directory structure
+ * @return  true if parsing was successful and exif information exists in JpegReader object
+ *          false in case of unsuccessful parsing
+ */
+bool ExifReader::parse()
+{
+    try {
+        m_exif = getExif();
+        if( !m_exif.empty() )
+        {
+            return true;
+        }
+        return false;
+    } catch (ExifParsingError&) {
+        return false;
+    }
+}
+
+
+/**
+ *  @brief Get tag value by tag number
+ *
+ *  @param [in] tag The tag number
+ *
+ *  @return ExifEntru_t structure. Caller has to know what tag it calls in order to extract proper field from the structure ExifEntry_t
+ *
+ */
+ExifEntry_t ExifReader::getTag(const ExifTagName tag)
+{
+    ExifEntry_t entry;
+    std::map<int, ExifEntry_t>::iterator it = m_exif.find(tag);
+
+    if( it != m_exif.end() )
+    {
+        entry = it->second;
+    }
+    return entry;
+}
+
+
+/**
+ * @brief Get exif directory structure contained in file (if any)
+ *          This is internal function and is not exposed to client
+ *
+ *  @return Map where key is tag number and value is ExifEntry_t structure
+ */
+std::map<int, ExifEntry_t > ExifReader::getExif()
+{
+    const size_t markerSize = 2;
+    const size_t offsetToTiffHeader = 6; //bytes from Exif size field to the first TIFF header
+    unsigned char appMarker[markerSize];
+    m_exif.erase( m_exif.begin(), m_exif.end() );
+
+    size_t count;
+
+    if (m_filename.size() == 0)
+    {
+        return m_exif;
+    }
+
+    FILE* f = fopen( m_filename.c_str(), "rb" );
+
+    if( !f )
+    {
+        return m_exif; //Until this moment the map is empty
+    }
+
+    bool exifFound = false, stopSearch = false;
+    while( ( !feof( f ) ) && !exifFound && !stopSearch )
+    {
+        count = fread( appMarker, sizeof(unsigned char), markerSize, f );
+        if( count < markerSize )
+        {
+            break;
+        }
+        unsigned char marker = appMarker[1];
+        size_t bytesToSkip;
+        size_t exifSize;
+        switch( marker )
+        {
+            //For all the markers just skip bytes in file pointed by followed two bytes (field size)
+            case SOF0: case SOF2: case DHT: case DQT: case DRI: case SOS:
+            case RST0: case RST1: case RST2: case RST3: case RST4: case RST5: case RST6: case RST7:
+            case APP0: case APP2: case APP3: case APP4: case APP5: case APP6: case APP7: case APP8:
+            case APP9: case APP10: case APP11: case APP12: case APP13: case APP14: case APP15:
+            case COM:
+                bytesToSkip = getFieldSize( f );
+                if (bytesToSkip < markerSize) {
+                    fclose(f);
+                    throw ExifParsingError();
+                }
+                fseek( f, static_cast<long>( bytesToSkip - markerSize ), SEEK_CUR );
+                break;
+
+            //SOI and EOI don't have the size field after the marker
+            case SOI: case EOI:
+                break;
+
+            case APP1: //actual Exif Marker
+                exifSize = getFieldSize(f);
+                if (exifSize <= offsetToTiffHeader) {
+                    fclose(f);
+                    throw ExifParsingError();
+                }
+                m_data.resize( exifSize - offsetToTiffHeader );
+                fseek(f, static_cast<long>( offsetToTiffHeader ), SEEK_CUR);
+                count = fread( &m_data[0], sizeof( unsigned char ), exifSize - offsetToTiffHeader, f );
+                exifFound = true;
+                break;
+
+            default: //No other markers are expected according to standard. May be a signal of error
+                stopSearch = true;
+                break;
+        }
+    }
+
+    fclose(f);
+
+    if( !exifFound )
+    {
+        return m_exif;
+    }
+
+    parseExif();
+
+    return m_exif;
+}
+
+/**
+ * @brief Get the size of exif field (required to properly ready whole exif from the file)
+ *          This is internal function and is not exposed to client
+ *
+ *  @return size of exif field in the file
+ */
+size_t ExifReader::getFieldSize (FILE* f) const
+{
+    unsigned char fieldSize[2];
+    size_t count = fread ( fieldSize, sizeof( char ), 2, f );
+    if (count < 2)
+    {
+        return 0;
+    }
+    return ( fieldSize[0] << 8 ) + fieldSize[1];
+}
+
+/**
+ * @brief Filling m_exif member with exif directory elements
+ *          This is internal function and is not exposed to client
+ *
+ *  @return The function doesn't return any value. In case of unsiccessful parsing
+ *      the m_exif member is not filled up
+ */
+void ExifReader::parseExif()
+{
+    m_format = getFormat();
+
+    if( !checkTagMark() )
+    {
+        return;
+    }
+
+    uint32_t offset = getStartOffset();
+
+    size_t numEntry = getNumDirEntry();
+
+    offset += 2; //go to start of tag fields
+
+    for( size_t entry = 0; entry < numEntry; entry++ )
+    {
+        ExifEntry_t exifEntry = parseExifEntry( offset );
+        m_exif.insert( std::make_pair( exifEntry.tag, exifEntry ) );
+        offset += tiffFieldSize;
+    }
+}
+
+/**
+ * @brief Get endianness of exif information
+ *          This is internal function and is not exposed to client
+ *
+ * @return INTEL, MOTO or NONE
+ */
+Endianess_t ExifReader::getFormat() const
+{
+    if (m_data.size() < 1)
+        return NONE;
+
+    if( m_data.size() > 1 && m_data[0] != m_data[1] )
+    {
+        return NONE;
+    }
+
+    if( m_data[0] == 'I' )
+    {
+        return INTEL;
+    }
+
+    if( m_data[0] == 'M' )
+    {
+        return MOTO;
+    }
+
+    return NONE;
+}
+
+/**
+ * @brief Checking whether Tag Mark (0x002A) correspond to one contained in the Jpeg file
+ *          This is internal function and is not exposed to client
+ *
+ * @return true if tag mark equals 0x002A, false otherwise
+ */
+bool ExifReader::checkTagMark() const
+{
+    uint16_t tagMark = getU16( 2 );
+
+    if( tagMark != tagMarkRequired )
+    {
+        return false;
+    }
+    return true;
+}
+
+/**
+ * @brief The utility function for extracting actual offset exif IFD0 info is started from
+ *          This is internal function and is not exposed to client
+ *
+ * @return offset of IFD0 field
+ */
+uint32_t ExifReader::getStartOffset() const
+{
+    return getU32( 4 );
+}
+
+/**
+ * @brief Get the number of Directory Entries in Jpeg file
+ *
+ * @return The number of directory entries
+ */
+size_t ExifReader::getNumDirEntry() const
+{
+    return getU16( offsetNumDir );
+}
+
+/**
+ * @brief Parsing particular entry in exif directory
+ *          This is internal function and is not exposed to client
+ *
+ *      Entries are divided into 12-bytes blocks each
+ *      Each block corresponds the following structure:
+ *
+ *      +------+-------------+-------------------+------------------------+
+ *      | Type | Data format | Num of components | Data or offset to data |
+ *      +======+=============+===================+========================+
+ *      | TTTT | ffff        | NNNNNNNN          | DDDDDDDD               |
+ *      +------+-------------+-------------------+------------------------+
+ *
+ *      Details can be found here: http://www.media.mit.edu/pia/Research/deepview/exif.html
+ *
+ * @param [in] offset Offset to entry in bytes inside raw exif data
+ * @return ExifEntry_t structure which corresponds to particular entry
+ *
+ */
+ExifEntry_t ExifReader::parseExifEntry(const size_t offset)
+{
+    ExifEntry_t entry;
+    uint16_t tagNum = getExifTag( offset );
+    entry.tag = tagNum;
+
+    switch( tagNum )
+    {
+        case IMAGE_DESCRIPTION:
+            entry.field_str = getString( offset );
+            break;
+        case MAKE:
+            entry.field_str = getString( offset );
+            break;
+        case MODEL:
+            entry.field_str = getString( offset );
+            break;
+        case ORIENTATION:
+            entry.field_u16 = getOrientation( offset );
+            break;
+        case XRESOLUTION:
+            entry.field_u_rational = getResolution( offset );
+            break;
+        case YRESOLUTION:
+            entry.field_u_rational = getResolution( offset );
+            break;
+        case RESOLUTION_UNIT:
+            entry.field_u16 = getResolutionUnit( offset );
+            break;
+        case SOFTWARE:
+            entry.field_str = getString( offset );
+            break;
+        case DATE_TIME:
+            entry.field_str = getString( offset );
+            break;
+        case WHITE_POINT:
+            entry.field_u_rational = getWhitePoint( offset );
+            break;
+        case PRIMARY_CHROMATICIES:
+            entry.field_u_rational = getPrimaryChromaticies( offset );
+            break;
+        case Y_CB_CR_COEFFICIENTS:
+            entry.field_u_rational = getYCbCrCoeffs( offset );
+            break;
+        case Y_CB_CR_POSITIONING:
+            entry.field_u16 = getYCbCrPos( offset );
+            break;
+        case REFERENCE_BLACK_WHITE:
+            entry.field_u_rational = getRefBW( offset );
+            break;
+        case COPYRIGHT:
+            entry.field_str = getString( offset );
+            break;
+        case EXIF_OFFSET:
+            break;
+        default:
+            entry.tag = INVALID_TAG;
+            break;
+    }
+    return entry;
+}
+
+/**
+ * @brief Get tag number from raw exif data
+ *          This is internal function and is not exposed to client
+ * @param [in] offset Offset to entry in bytes inside raw exif data
+ * @return tag number
+ */
+uint16_t ExifReader::getExifTag(const size_t offset) const
+{
+    return getU16( offset );
+}
+
+/**
+ * @brief Get string information from raw exif data
+ *          This is internal function and is not exposed to client
+ * @param [in] offset Offset to entry in bytes inside raw exif data
+ * @return string value
+ */
+std::string ExifReader::getString(const size_t offset) const
+{
+    size_t size = getU32( offset + 4 );
+    size_t dataOffset = 8; // position of data in the field
+    if( size > maxDataSize )
+    {
+        dataOffset = getU32( offset + 8 );
+    }
+    if (dataOffset > m_data.size() || dataOffset + size > m_data.size()) {
+        throw ExifParsingError();
+    }
+    std::vector<uint8_t>::const_iterator it = m_data.begin() + dataOffset;
+    std::string result( it, it + size ); //copy vector content into result
+
+    return result;
+}
+
+/**
+ * @brief Get unsigned short data from raw exif data
+ *          This is internal function and is not exposed to client
+ * @param [in] offset Offset to entry in bytes inside raw exif data
+ * @return Unsigned short data
+ */
+uint16_t ExifReader::getU16(const size_t offset) const
+{
+    if (offset + 1 >= m_data.size())
+        throw ExifParsingError();
+
+    if( m_format == INTEL )
+    {
+        return m_data[offset] + ( m_data[offset + 1] << 8 );
+    }
+    return ( m_data[offset] << 8 ) + m_data[offset + 1];
+}
+
+/**
+ * @brief Get unsigned 32-bit data from raw exif data
+ *          This is internal function and is not exposed to client
+ * @param [in] offset Offset to entry in bytes inside raw exif data
+ * @return Unsigned 32-bit data
+ */
+uint32_t ExifReader::getU32(const size_t offset) const
+{
+    if (offset + 3 >= m_data.size())
+        throw ExifParsingError();
+
+    if( m_format == INTEL )
+    {
+        return m_data[offset] +
+                ( m_data[offset + 1] << 8 ) +
+                ( m_data[offset + 2] << 16 ) +
+                ( m_data[offset + 3] << 24 );
+    }
+
+    return ( m_data[offset] << 24 ) +
+            ( m_data[offset + 1] << 16 ) +
+            ( m_data[offset + 2] << 8 ) +
+            m_data[offset + 3];
+}
+
+/**
+ * @brief Get unsigned rational data from raw exif data
+ *          This is internal function and is not exposed to client
+ * @param [in] offset Offset to entry in bytes inside raw exif data
+ * @return Unsigned rational data
+ *
+ * "rational" means a fractional value, it contains 2 signed/unsigned long integer value,
+ *  and the first represents the numerator, the second, the denominator.
+ */
+u_rational_t ExifReader::getURational(const size_t offset) const
+{
+    u_rational_t result;
+    uint32_t numerator = getU32( offset );
+    uint32_t denominator = getU32( offset + 4 );
+
+    return std::make_pair( numerator, denominator );
+
+}
+
+/**
+ * @brief Get orientation information from raw exif data
+ *          This is internal function and is not exposed to client
+ * @param [in] offset Offset to entry in bytes inside raw exif data
+ * @return orientation number
+ */
+uint16_t ExifReader::getOrientation(const size_t offset) const
+{
+    return getU16( offset + 8 );
+}
+
+/**
+ * @brief Get resolution information from raw exif data
+ *          This is internal function and is not exposed to client
+ * @param [in] offset Offset to entry in bytes inside raw exif data
+ * @return resolution value
+ */
+std::vector<u_rational_t> ExifReader::getResolution(const size_t offset) const
+{
+    std::vector<u_rational_t> result;
+    uint32_t rationalOffset = getU32( offset + 8 );
+    result.push_back( getURational( rationalOffset ) );
+
+    return result;
+}
+
+/**
+ * @brief Get resolution unit from raw exif data
+ *          This is internal function and is not exposed to client
+ * @param [in] offset Offset to entry in bytes inside raw exif data
+ * @return resolution unit value
+ */
+uint16_t ExifReader::getResolutionUnit(const size_t offset) const
+{
+    return getU16( offset + 8 );
+}
+
+/**
+ * @brief Get White Point information from raw exif data
+ *          This is internal function and is not exposed to client
+ * @param [in] offset Offset to entry in bytes inside raw exif data
+ * @return White Point value
+ *
+ * If the image uses CIE Standard Illumination D65(known as international
+ * standard of 'daylight'), the values are '3127/10000,3290/10000'.
+ */
+std::vector<u_rational_t> ExifReader::getWhitePoint(const size_t offset) const
+{
+    std::vector<u_rational_t> result;
+    uint32_t rationalOffset = getU32( offset + 8 );
+    result.push_back( getURational( rationalOffset ) );
+    result.push_back( getURational( rationalOffset + 8 ) );
+
+    return result;
+}
+
+/**
+ * @brief Get Primary Chromaticies information from raw exif data
+ *          This is internal function and is not exposed to client
+ * @param [in] offset Offset to entry in bytes inside raw exif data
+ * @return vector with primary chromaticies values
+ *
+ */
+std::vector<u_rational_t> ExifReader::getPrimaryChromaticies(const size_t offset) const
+{
+    std::vector<u_rational_t> result;
+    uint32_t rationalOffset = getU32( offset + 8 );
+    for( size_t i = 0; i < primaryChromaticiesComponents; i++ )
+    {
+        result.push_back( getURational( rationalOffset ) );
+        rationalOffset += 8;
+    }
+    return result;
+}
+
+/**
+ * @brief Get YCbCr Coefficients information from raw exif data
+ *          This is internal function and is not exposed to client
+ * @param [in] offset Offset to entry in bytes inside raw exif data
+ * @return vector with YCbCr coefficients values
+ *
+ */
+std::vector<u_rational_t> ExifReader::getYCbCrCoeffs(const size_t offset) const
+{
+    std::vector<u_rational_t> result;
+    uint32_t rationalOffset = getU32( offset + 8 );
+    for( size_t i = 0; i < ycbcrCoeffs; i++ )
+    {
+        result.push_back( getURational( rationalOffset ) );
+        rationalOffset += 8;
+    }
+    return result;
+}
+
+/**
+ * @brief Get YCbCr Positioning information from raw exif data
+ *          This is internal function and is not exposed to client
+ * @param [in] offset Offset to entry in bytes inside raw exif data
+ * @return vector with YCbCr positioning value
+ *
+ */
+uint16_t ExifReader::getYCbCrPos(const size_t offset) const
+{
+    return getU16( offset + 8 );
+}
+
+/**
+ * @brief Get Reference Black&White point information from raw exif data
+ *          This is internal function and is not exposed to client
+ * @param [in] offset Offset to entry in bytes inside raw exif data
+ * @return vector with reference BW points
+ *
+ * In case of YCbCr format, first 2 show black/white of Y, next 2 are Cb,
+ * last 2 are Cr. In case of RGB format, first 2 show black/white of R,
+ * next 2 are G, last 2 are B.
+ *
+ */
+std::vector<u_rational_t> ExifReader::getRefBW(const size_t offset) const
+{
+    const size_t rationalFieldSize = 8;
+    std::vector<u_rational_t> result;
+    uint32_t rationalOffset = getU32( offset + rationalFieldSize );
+    for( size_t i = 0; i < refBWComponents; i++ )
+    {
+        result.push_back( getURational( rationalOffset ) );
+        rationalOffset += rationalFieldSize;
+    }
+    return result;
+}
+
+} //namespace cv
diff --git a/modules/imgcodecs/src/exif.hpp b/modules/imgcodecs/src/exif.hpp
new file mode 100644
index 0000000..43c2857
--- /dev/null
+++ b/modules/imgcodecs/src/exif.hpp
@@ -0,0 +1,253 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+//  By downloading, copying, installing or using the software you agree to this license.
+//  If you do not agree to this license, do not download, install,
+//  copy or use the software.
+//
+//
+//                           License Agreement
+//                For Open Source Computer Vision Library
+//
+// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
+// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+//   * Redistribution's of source code must retain the above copyright notice,
+//     this list of conditions and the following disclaimer.
+//
+//   * Redistribution's in binary form must reproduce the above copyright notice,
+//     this list of conditions and the following disclaimer in the documentation
+//     and/or other materials provided with the distribution.
+//
+//   * The name of the copyright holders may not be used to endorse or promote products
+//     derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+
+#ifndef _OPENCV_EXIF_HPP_
+#define _OPENCV_EXIF_HPP_
+
+#include <cstdio>
+#include <map>
+#include <utility>
+#include <algorithm>
+#include <stdint.h>
+#include <string>
+#include <vector>
+
+namespace cv
+{
+/**
+ * @brief Jpeg markers that can encounter in Jpeg file
+ */
+enum AppMarkerTypes
+{
+    SOI   = 0xD8, SOF0  = 0xC0, SOF2  = 0xC2, DHT   = 0xC4,
+    DQT   = 0xDB, DRI   = 0xDD, SOS   = 0xDA,
+
+    RST0  = 0xD0, RST1  = 0xD1, RST2  = 0xD2, RST3  = 0xD3,
+    RST4  = 0xD4, RST5  = 0xD5, RST6  = 0xD6, RST7  = 0xD7,
+
+    APP0  = 0xE0, APP1  = 0xE1, APP2  = 0xE2, APP3  = 0xE3,
+    APP4  = 0xE4, APP5  = 0xE5, APP6  = 0xE6, APP7  = 0xE7,
+    APP8  = 0xE8, APP9  = 0xE9, APP10 = 0xEA, APP11 = 0xEB,
+    APP12 = 0xEC, APP13 = 0xED, APP14 = 0xEE, APP15 = 0xEF,
+
+    COM   = 0xFE, EOI   = 0xD9
+};
+
+/**
+ * @brief Base Exif tags used by IFD0 (main image)
+ */
+enum ExifTagName
+{
+    IMAGE_DESCRIPTION       = 0x010E,   ///< Image Description: ASCII string
+    MAKE                    = 0x010F,   ///< Description of manufacturer: ASCII string
+    MODEL                   = 0x0110,   ///< Description of camera model: ASCII string
+    ORIENTATION             = 0x0112,   ///< Orientation of the image: unsigned short
+    XRESOLUTION             = 0x011A,   ///< Resolution of the image across X axis: unsigned rational
+    YRESOLUTION             = 0x011B,   ///< Resolution of the image across Y axis: unsigned rational
+    RESOLUTION_UNIT         = 0x0128,   ///< Resolution units. '1' no-unit, '2' inch, '3' centimeter
+    SOFTWARE                = 0x0131,   ///< Shows firmware(internal software of digicam) version number
+    DATE_TIME               = 0x0132,   ///< Date/Time of image was last modified
+    WHITE_POINT             = 0x013E,   ///< Chromaticity of white point of the image
+    PRIMARY_CHROMATICIES    = 0x013F,   ///< Chromaticity of the primaries of the image
+    Y_CB_CR_COEFFICIENTS    = 0x0211,   ///< constant to translate an image from YCbCr to RGB format
+    Y_CB_CR_POSITIONING     = 0x0213,   ///< Chroma sample point of subsampling pixel array
+    REFERENCE_BLACK_WHITE   = 0x0214,   ///< Reference value of black point/white point
+    COPYRIGHT               = 0x8298,   ///< Copyright information
+    EXIF_OFFSET             = 0x8769,   ///< Offset to Exif Sub IFD
+    INVALID_TAG             = 0xFFFF    ///< Shows that the tag was not recognized
+};
+
+enum Endianess_t
+{
+    INTEL = 0x49,
+    MOTO = 0x4D,
+    NONE = 0x00
+};
+
+typedef std::pair<uint32_t, uint32_t> u_rational_t;
+
+/**
+ * @brief Entry which contains possible values for different exif tags
+ */
+struct ExifEntry_t
+{
+    ExifEntry_t();
+
+    std::vector<u_rational_t> field_u_rational; ///< vector of rational fields
+    std::string field_str;                      ///< any kind of textual information
+
+    float  field_float;                         ///< Currently is not used
+    double field_double;                        ///< Currently is not used
+
+    uint32_t field_u32;                         ///< Unsigned 32-bit value
+    int32_t  field_s32;                         ///< Signed 32-bit value
+
+    uint16_t tag;                               ///< Tag number
+
+    uint16_t field_u16;                         ///< Unsigned 16-bit value
+    int16_t  field_s16;                         ///< Signed 16-bit value
+    uint8_t  field_u8;                          ///< Unsigned 8-bit value
+    int8_t   field_s8;                          ///< Signed 8-bit value
+};
+
+/**
+ * @brief Picture orientation which may be taken from EXIF
+ *      Orientation usually matters when the picture is taken by
+ *      smartphone or other camera with orientation sensor support
+ *      Corresponds to EXIF 2.3 Specification
+ */
+enum ImageOrientation
+{
+    IMAGE_ORIENTATION_TL = 1, ///< Horizontal (normal)
+    IMAGE_ORIENTATION_TR = 2, ///< Mirrored horizontal
+    IMAGE_ORIENTATION_BR = 3, ///< Rotate 180
+    IMAGE_ORIENTATION_BL = 4, ///< Mirrored vertical
+    IMAGE_ORIENTATION_LT = 5, ///< Mirrored horizontal & rotate 270 CW
+    IMAGE_ORIENTATION_RT = 6, ///< Rotate 90 CW
+    IMAGE_ORIENTATION_RB = 7, ///< Mirrored horizontal & rotate 90 CW
+    IMAGE_ORIENTATION_LB = 8  ///< Rotate 270 CW
+};
+
+/**
+ * @brief Reading exif information from Jpeg file
+ *
+ * Usage example for getting the orientation of the image:
+ *
+ *      @code
+ *      ExifReader reader(fileName);
+ *      if( reader.parse() )
+ *      {
+ *          int orientation = reader.getTag(Orientation).field_u16;
+ *      }
+ *      @endcode
+ *
+ */
+class ExifReader
+{
+public:
+    /**
+     * @brief ExifReader constructor. Constructs an object of exif reader
+     *
+     * @param [in]filename The name of file to look exif info in
+     */
+    explicit ExifReader( std::string filename );
+    ~ExifReader();
+
+
+    /**
+     * @brief Parse the file with exif info
+     *
+     * @return true if parsing was successful and exif information exists in JpegReader object
+     */
+    bool parse();
+
+    /**
+     * @brief Get tag info by tag number
+     *
+     * @param [in] tag The tag number
+     * @return ExifEntru_t structure. Caller has to know what tag it calls in order to extract proper field from the structure ExifEntry_t
+     */
+    ExifEntry_t getTag( const ExifTagName tag );
+
+private:
+    std::string m_filename;
+    std::vector<unsigned char> m_data;
+    std::map<int, ExifEntry_t > m_exif;
+    Endianess_t m_format;
+
+    void parseExif();
+    bool checkTagMark() const;
+
+    size_t getFieldSize ( FILE* f ) const;
+    size_t getNumDirEntry() const;
+    uint32_t getStartOffset() const;
+    uint16_t getExifTag( const size_t offset ) const;
+    uint16_t getU16( const size_t offset ) const;
+    uint32_t getU32( const size_t offset ) const;
+    uint16_t getOrientation( const size_t offset ) const;
+    uint16_t getResolutionUnit( const size_t offset ) const;
+    uint16_t getYCbCrPos( const size_t offset ) const;
+
+    Endianess_t getFormat() const;
+
+    ExifEntry_t parseExifEntry( const size_t offset );
+
+    u_rational_t getURational( const size_t offset ) const;
+
+    std::map<int, ExifEntry_t > getExif();
+    std::string getString( const size_t offset ) const;
+    std::vector<u_rational_t> getResolution( const size_t offset ) const;
+    std::vector<u_rational_t> getWhitePoint( const size_t offset ) const;
+    std::vector<u_rational_t> getPrimaryChromaticies( const size_t offset ) const;
+    std::vector<u_rational_t> getYCbCrCoeffs( const size_t offset ) const;
+    std::vector<u_rational_t> getRefBW( const size_t offset ) const;
+
+private:
+    static const uint16_t tagMarkRequired = 0x2A;
+
+    //offset to the _number-of-directory-entry_ field
+    static const size_t offsetNumDir = 8;
+
+    //max size of data in tag.
+    //'DDDDDDDD' contains the value of that Tag. If its size is over 4bytes,
+    //'DDDDDDDD' contains the offset to data stored address.
+    static const size_t maxDataSize = 4;
+
+    //bytes per tag field
+    static const size_t tiffFieldSize = 12;
+
+    //number of primary chromaticies components
+    static const size_t primaryChromaticiesComponents = 6;
+
+    //number of YCbCr coefficients in field
+    static const size_t ycbcrCoeffs = 3;
+
+    //number of Reference Black&White components
+    static const size_t refBWComponents = 6;
+};
+
+
+
+}
+
+#endif /* _OPENCV_EXIF_HPP_ */
diff --git a/modules/imgcodecs/src/grfmt_gdal.cpp b/modules/imgcodecs/src/grfmt_gdal.cpp
index 1094b91..8865ae4 100644
--- a/modules/imgcodecs/src/grfmt_gdal.cpp
+++ b/modules/imgcodecs/src/grfmt_gdal.cpp
@@ -559,7 +559,7 @@ bool GdalDecoder::checkSignature( const String& signature )const{
 
 
     // look for NITF
-    std::string str = signature.c_str();
+    std::string str(signature);
     if( str.substr(0,4).find("NITF") != std::string::npos ){
         return true;
     }
diff --git a/modules/imgcodecs/src/grfmt_gdcm.cpp b/modules/imgcodecs/src/grfmt_gdcm.cpp
new file mode 100644
index 0000000..a1d9e9d
--- /dev/null
+++ b/modules/imgcodecs/src/grfmt_gdcm.cpp
@@ -0,0 +1,197 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+//  By downloading, copying, installing or using the software you agree to this license.
+//  If you do not agree to this license, do not download, install,
+//  copy or use the software.
+//
+//
+//                           License Agreement
+//                For Open Source Computer Vision Library
+//
+// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
+// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+//   * Redistribution's of source code must retain the above copyright notice,
+//     this list of conditions and the following disclaimer.
+//
+//   * Redistribution's in binary form must reproduce the above copyright notice,
+//     this list of conditions and the following disclaimer in the documentation
+//     and/or other materials provided with the distribution.
+//
+//   * The name of the copyright holders may not be used to endorse or promote products
+//     derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "precomp.hpp"
+#include "grfmt_gdcm.hpp"
+
+#ifdef HAVE_GDCM
+
+//#define DBG(...) printf(__VA_ARGS__)
+#define DBG(...)
+
+#include <gdcmImageReader.h>
+
+static const size_t preamble_skip = 128;
+static const size_t magic_len = 4;
+
+inline cv::String getMagic()
+{
+    return cv::String("\x44\x49\x43\x4D", 4);
+}
+
+namespace cv
+{
+
+/************************ DICOM decoder *****************************/
+
+DICOMDecoder::DICOMDecoder()
+{
+    // DICOM preamble is 128 bytes (can have any value, defaults to 0) + 4 bytes magic number (DICM)
+    m_signature = String(preamble_skip, (char)'\x0') + getMagic();
+    m_buf_supported = false;
+}
+
+bool DICOMDecoder::checkSignature( const String& signature ) const
+{
+    if (signature.size() >= preamble_skip + magic_len)
+    {
+        if (signature.substr(preamble_skip, magic_len) == getMagic())
+        {
+            return true;
+        }
+    }
+    DBG("GDCM | Signature does not match\n");
+    return false;
+}
+
+ImageDecoder DICOMDecoder::newDecoder() const
+{
+    return makePtr<DICOMDecoder>();
+}
+
+bool  DICOMDecoder::readHeader()
+{
+    gdcm::ImageReader csImageReader;
+    csImageReader.SetFileName(m_filename.c_str());
+    if(!csImageReader.Read())
+    {
+        DBG("GDCM | Failed to open DICOM file\n");
+        return(false);
+    }
+
+    const gdcm::Image &csImage = csImageReader.GetImage();
+    bool bOK = true;
+    switch (csImage.GetPhotometricInterpretation().GetType())
+    {
+        case gdcm::PhotometricInterpretation::MONOCHROME1:
+        case gdcm::PhotometricInterpretation::MONOCHROME2:
+        {
+            switch (csImage.GetPixelFormat().GetScalarType())
+            {
+                case gdcm::PixelFormat::INT8: m_type = CV_8SC1; break;
+                case gdcm::PixelFormat::UINT8: m_type = CV_8UC1; break;
+                case gdcm::PixelFormat::INT16: m_type = CV_16SC1; break;
+                case gdcm::PixelFormat::UINT16: m_type = CV_16UC1; break;
+                case gdcm::PixelFormat::INT32: m_type = CV_32SC1; break;
+                case gdcm::PixelFormat::FLOAT32: m_type = CV_32FC1; break;
+                case gdcm::PixelFormat::FLOAT64: m_type = CV_64FC1; break;
+                default: bOK = false; DBG("GDCM | Monochrome scalar type not supported\n"); break;
+            }
+            break;
+        }
+
+        case gdcm::PhotometricInterpretation::RGB:
+        {
+            switch (csImage.GetPixelFormat().GetScalarType())
+            {
+                case gdcm::PixelFormat::UINT8: m_type = CV_8UC3; break;
+                default: bOK = false; DBG("GDCM | RGB scalar type not supported\n"); break;
+            }
+            break;
+        }
+
+        default:
+        {
+            bOK = false;
+            DBG("GDCM | PI not supported: %s\n", csImage.GetPhotometricInterpretation().GetString());
+            break;
+        }
+    }
+
+    if(bOK)
+    {
+        unsigned int ndim = csImage.GetNumberOfDimensions();
+        if (ndim != 2)
+        {
+            DBG("GDCM | Invalid dimensions number: %d\n", ndim);
+            bOK = false;
+        }
+    }
+    if (bOK)
+    {
+        const unsigned int *piDimension = csImage.GetDimensions();
+        m_height = piDimension[0];
+        m_width = piDimension[1];
+        if( ( m_width <=0 )  || ( m_height <=0 ) )
+        {
+            DBG("GDCM | Invalid dimensions: %d x %d\n", piDimension[0], piDimension[1]);
+            bOK = false;
+        }
+    }
+
+    return(bOK);
+}
+
+
+bool  DICOMDecoder::readData( Mat& csImage )
+{
+    csImage.create(m_width,m_height,m_type);
+
+    gdcm::ImageReader csImageReader;
+    csImageReader.SetFileName(m_filename.c_str());
+    if(!csImageReader.Read())
+    {
+        DBG("GDCM | Failed to Read\n");
+        return false;
+    }
+
+    const gdcm::Image &img = csImageReader.GetImage();
+
+    unsigned long len = img.GetBufferLength();
+    if (len > csImage.elemSize() * csImage.total())
+    {
+        DBG("GDCM | Buffer is bigger than Mat: %ld > %ld * %ld\n", len, csImage.elemSize(), csImage.total());
+        return false;
+    }
+
+    if (!img.GetBuffer((char*)csImage.ptr()))
+    {
+        DBG("GDCM | Failed to GetBuffer\n");
+        return false;
+    }
+    DBG("GDCM | Read OK\n");
+    return true;
+}
+
+}
+
+#endif // HAVE_GDCM
\ No newline at end of file
diff --git a/modules/imgcodecs/src/grfmt_gdcm.hpp b/modules/imgcodecs/src/grfmt_gdcm.hpp
new file mode 100644
index 0000000..d8dc60f
--- /dev/null
+++ b/modules/imgcodecs/src/grfmt_gdcm.hpp
@@ -0,0 +1,70 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+//  By downloading, copying, installing or using the software you agree to this license.
+//  If you do not agree to this license, do not download, install,
+//  copy or use the software.
+//
+//
+//                           License Agreement
+//                For Open Source Computer Vision Library
+//
+// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
+// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+//   * Redistribution's of source code must retain the above copyright notice,
+//     this list of conditions and the following disclaimer.
+//
+//   * Redistribution's in binary form must reproduce the above copyright notice,
+//     this list of conditions and the following disclaimer in the documentation
+//     and/or other materials provided with the distribution.
+//
+//   * The name of the copyright holders may not be used to endorse or promote products
+//     derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#ifndef _GDCM_DICOM_H_
+#define _GDCM_DICOM_H_
+
+#include "cvconfig.h"
+
+#ifdef HAVE_GDCM
+
+#include "grfmt_base.hpp"
+
+namespace cv
+{
+
+// DICOM image reader using GDCM
+class DICOMDecoder : public BaseImageDecoder
+{
+public:
+    DICOMDecoder();
+    bool  readData( Mat& img );
+    bool  readHeader();
+    ImageDecoder newDecoder() const;
+    virtual bool checkSignature( const String& signature ) const;
+};
+
+}
+
+#endif // HAVE_GDCM
+
+#endif/*_GDCM_DICOM_H_*/
diff --git a/modules/imgcodecs/src/grfmt_jpeg.cpp b/modules/imgcodecs/src/grfmt_jpeg.cpp
index 8a2900a1..1f5f1e8 100644
--- a/modules/imgcodecs/src/grfmt_jpeg.cpp
+++ b/modules/imgcodecs/src/grfmt_jpeg.cpp
@@ -41,7 +41,6 @@
 
 #include "precomp.hpp"
 #include "grfmt_jpeg.hpp"
-#include "jpeg_exif.hpp"
 
 #ifdef HAVE_JPEG
 
@@ -178,7 +177,6 @@ JpegDecoder::JpegDecoder()
     m_state = 0;
     m_f = 0;
     m_buf_supported = true;
-    m_orientation = JPEG_ORIENTATION_TL;
 }
 
 
@@ -255,68 +253,12 @@ bool  JpegDecoder::readHeader()
         }
     }
 
-    m_orientation = getOrientation();
-
     if( !result )
         close();
 
     return result;
 }
 
-int JpegDecoder::getOrientation()
-{
-    int orientation = JPEG_ORIENTATION_TL;
-
-    ExifReader reader( m_filename );
-    if( reader.parse() )
-    {
-        ExifEntry_t entry = reader.getTag( ORIENTATION );
-        if (entry.tag != INVALID_TAG)
-        {
-            orientation = entry.field_u16; //orientation is unsigned short, so check field_u16
-        }
-    }
-
-    return orientation;
-}
-
-void JpegDecoder::setOrientation(Mat& img)
-{
-    switch( m_orientation )
-    {
-        case    JPEG_ORIENTATION_TL: //0th row == visual top, 0th column == visual left-hand side
-            //do nothing, the image already has proper orientation
-            break;
-        case    JPEG_ORIENTATION_TR: //0th row == visual top, 0th column == visual right-hand side
-            flip(img, img, 1); //flip horizontally
-            break;
-        case    JPEG_ORIENTATION_BR: //0th row == visual bottom, 0th column == visual right-hand side
-            flip(img, img, -1);//flip both horizontally and vertically
-            break;
-        case    JPEG_ORIENTATION_BL: //0th row == visual bottom, 0th column == visual left-hand side
-            flip(img, img, 0); //flip vertically
-            break;
-        case    JPEG_ORIENTATION_LT: //0th row == visual left-hand side, 0th column == visual top
-            transpose(img, img);
-            break;
-        case    JPEG_ORIENTATION_RT: //0th row == visual right-hand side, 0th column == visual top
-            transpose(img, img);
-            flip(img, img, 1); //flip horizontally
-            break;
-        case    JPEG_ORIENTATION_RB: //0th row == visual right-hand side, 0th column == visual bottom
-            transpose(img, img);
-            flip(img, img, -1); //flip both horizontally and vertically
-            break;
-        case    JPEG_ORIENTATION_LB: //0th row == visual left-hand side, 0th column == visual bottom
-            transpose(img, img);
-            flip(img, img, 0); //flip vertically
-            break;
-        default:
-            //by default the image read has normal (JPEG_ORIENTATION_TL) orientation
-            break;
-    }
-}
-
 /***************************************************************************
  * following code is for supporting MJPEG image files
  * based on a message of Laurent Pinchart on the video4linux mailing list
@@ -533,7 +475,6 @@ bool  JpegDecoder::readData( Mat& img )
 
             result = true;
             jpeg_finish_decompress( cinfo );
-            setOrientation( img );
         }
     }
 
diff --git a/modules/imgcodecs/src/grfmt_jpeg.hpp b/modules/imgcodecs/src/grfmt_jpeg.hpp
index d0a0991..8455b19 100644
--- a/modules/imgcodecs/src/grfmt_jpeg.hpp
+++ b/modules/imgcodecs/src/grfmt_jpeg.hpp
@@ -70,12 +70,6 @@ protected:
 
     FILE* m_f;
     void* m_state;
-
-private:
-    //Support for handling exif orientation tag in Jpeg file
-    int m_orientation;
-    int getOrientation();
-    void setOrientation(Mat& img);
 };
 
 
diff --git a/modules/imgcodecs/src/grfmt_jpeg2000.cpp b/modules/imgcodecs/src/grfmt_jpeg2000.cpp
index e499c58..24aa457 100644
--- a/modules/imgcodecs/src/grfmt_jpeg2000.cpp
+++ b/modules/imgcodecs/src/grfmt_jpeg2000.cpp
@@ -525,7 +525,7 @@ bool  Jpeg2KEncoder::writeComponent16u( void *__img, const Mat& _img )
 
     for( int y = 0; y < h; y++ )
     {
-        const uchar* data = _img.ptr(y);
+        const ushort* data = _img.ptr<ushort>(y);
         for( int i = 0; i < ncmpts; i++ )
         {
             for( int x = 0; x < w; x++)
diff --git a/modules/imgcodecs/src/grfmt_pam.cpp b/modules/imgcodecs/src/grfmt_pam.cpp
new file mode 100644
index 0000000..ac7198a
--- /dev/null
+++ b/modules/imgcodecs/src/grfmt_pam.cpp
@@ -0,0 +1,719 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+//  By downloading, copying, installing or using the software you agree to this license.
+//  If you do not agree to this license, do not download, install,
+//  copy or use the software.
+//
+//
+//                            License Agreement
+//                 For Open Source Computer Vision Library
+//                         (3-clause BSD License)
+//
+//  Copyright (C) 2000-2016, Intel Corporation, all rights reserved.
+//  Copyright (C) 2009-2011, Willow Garage Inc., all rights reserved.
+//  Copyright (C) 2009-2016, NVIDIA Corporation, all rights reserved.
+//  Copyright (C) 2010-2013, Advanced Micro Devices, Inc., all rights reserved.
+//  Copyright (C) 2015-2016, OpenCV Foundation, all rights reserved.
+//  Copyright (C) 2015-2016, Itseez Inc., all rights reserved.
+//  Third party copyrights are property of their respective owners.
+//
+//  Redistribution and use in source and binary forms, with or without modification,
+//  are permitted provided that the following conditions are met:
+//
+//    * Redistributions of source code must retain the above copyright notice,
+//      this list of conditions and the following disclaimer.
+//
+//    * Redistributions in binary form must reproduce the above copyright notice,
+//      this list of conditions and the following disclaimer in the documentation
+//      and/or other materials provided with the distribution.
+//
+//    * Neither the names of the copyright holders nor the names of the contributors
+//      may be used to endorse or promote products derived from this software
+//      without specific prior written permission.
+//
+//  This software is provided by the copyright holders and contributors "as is" and
+//  any express or implied warranties, including, but not limited to, the implied
+//  warranties of merchantability and fitness for a particular purpose are disclaimed.
+//  In no event shall copyright holders or contributors be liable for any direct,
+//  indirect, incidental, special, exemplary, or consequential damages
+//  (including, but not limited to, procurement of substitute goods or services;
+//  loss of use, data, or profits; or business interruption) however caused
+//  and on any theory of liability, whether in contract, strict liability,
+//  or tort (including negligence or otherwise) arising in any way out of
+//  the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+
+#include <cerrno>
+
+#include "precomp.hpp"
+#include "utils.hpp"
+#include "grfmt_pam.hpp"
+
+/* the PAM related fields */
+#define MAX_PAM_HEADER_IDENITFIER_LENGTH 8
+#define MAX_PAM_HEADER_VALUE_LENGTH 255
+
+/* PAM header fileds */
+typedef enum {
+    PAM_HEADER_NONE,
+    PAM_HEADER_COMMENT,
+    PAM_HEADER_ENDHDR,
+    PAM_HEADER_HEIGHT,
+    PAM_HEADER_WIDTH,
+    PAM_HEADER_DEPTH,
+    PAM_HEADER_MAXVAL,
+    PAM_HEADER_TUPLTYPE,
+} PamHeaderFieldType;
+
+struct pam_header_field {
+    PamHeaderFieldType type;
+    char identifier[MAX_PAM_HEADER_IDENITFIER_LENGTH+1];
+};
+
+const static struct pam_header_field fields[] = {
+    {PAM_HEADER_ENDHDR,   "ENDHDR"},
+    {PAM_HEADER_HEIGHT,   "HEIGHT"},
+    {PAM_HEADER_WIDTH,    "WIDTH"},
+    {PAM_HEADER_DEPTH,    "DEPTH"},
+    {PAM_HEADER_MAXVAL,   "MAXVAL"},
+    {PAM_HEADER_TUPLTYPE, "TUPLTYPE"},
+};
+#define PAM_FIELDS_NO (sizeof (fields) / sizeof ((fields)[0]))
+
+typedef bool (*cvtFunc) (void *src, void *target, int width, int target_channels,
+    int target_depth);
+
+struct channel_layout {
+    uint rchan, gchan, bchan, graychan;
+};
+
+struct pam_format {
+    uint fmt;
+    char name[MAX_PAM_HEADER_VALUE_LENGTH+1];
+    cvtFunc cvt_func;
+    /* the channel layout that should be used when
+     * imread_ creates a 3 channel or 1 channel image
+     * used when no conversion function is available
+     */
+    struct channel_layout layout;
+};
+
+static bool rgb_convert (void *src, void *target, int width, int target_channels,
+    int target_depth);
+
+const static struct pam_format formats[] = {
+    {CV_IMWRITE_PAM_FORMAT_NULL, "", NULL, {0, 0, 0, 0} },
+    {CV_IMWRITE_PAM_FORMAT_BLACKANDWHITE, "BLACKANDWHITE", NULL, {0, 0, 0, 0} },
+    {CV_IMWRITE_PAM_FORMAT_GRAYSCALE, "GRAYSCALE", NULL, {0, 0, 0, 0} },
+    {CV_IMWRITE_PAM_FORMAT_GRAYSCALE_ALPHA, "GRAYSCALE_ALPHA", NULL, {0, 0, 0, 0} },
+    {CV_IMWRITE_PAM_FORMAT_RGB, "RGB", rgb_convert, {0, 1, 2, 0} },
+    {CV_IMWRITE_PAM_FORMAT_RGB_ALPHA, "RGB_ALPHA", NULL, {0, 1, 2, 0} },
+};
+#define PAM_FORMATS_NO (sizeof (fields) / sizeof ((fields)[0]))
+
+/*
+ * conversion functions
+ */
+
+static bool
+rgb_convert (void *src, void *target, int width, int target_channels, int target_depth)
+{
+    bool ret = false;
+    if (target_channels == 3) {
+        switch (target_depth) {
+            case CV_8U:
+                icvCvt_RGB2BGR_8u_C3R( (uchar*) src, 0, (uchar*) target, 0,
+                    cvSize(width,1) );
+                ret = true;
+                break;
+            case CV_16U:
+                icvCvt_RGB2BGR_16u_C3R( (ushort *)src, 0, (ushort *)target, 0,
+                    cvSize(width,1) );
+                ret = true;
+                break;
+            default:
+                break;
+        }
+    } else if (target_channels == 1) {
+        switch (target_depth) {
+            case CV_8U:
+                icvCvt_BGR2Gray_8u_C3C1R( (uchar*) src, 0, (uchar*) target, 0,
+                    cvSize(width,1), 2 );
+                ret = true;
+                break;
+            case CV_16U:
+                icvCvt_BGRA2Gray_16u_CnC1R( (ushort *)src, 0, (ushort *)target, 0,
+                    cvSize(width,1), 3, 2 );
+                ret = true;
+                break;
+            default:
+                break;
+        }
+    }
+    return ret;
+}
+
+/*
+ * copy functions used as a fall back for undefined formats
+ * or simpler conversion options
+ */
+
+static void
+basic_conversion (void *src, const struct channel_layout *layout, int src_sampe_size,
+    int src_width, void *target, int target_channels, int target_depth)
+{
+    switch (target_depth) {
+        case CV_8U:
+        {
+            uchar *d = (uchar *)target, *s = (uchar *)src,
+                *end = ((uchar *)src) + src_width;
+            switch (target_channels) {
+                case 1:
+                    for( ; s < end; d += 3, s += src_sampe_size )
+                        d[0] = d[1] = d[2] = s[layout->graychan];
+                    break;
+                case 3:
+                    for( ; s < end; d += 3, s += src_sampe_size ) {
+                        d[0] = s[layout->bchan];
+                        d[1] = s[layout->gchan];
+                        d[2] = s[layout->rchan];
+                    }
+                    break;
+                default:
+                    assert (0);
+            }
+            break;
+        }
+        case CV_16U:
+        {
+            ushort *d = (ushort *)target, *s = (ushort *)src,
+                *end = ((ushort *)src) + src_width;
+            switch (target_channels) {
+                case 1:
+                    for( ; s < end; d += 3, s += src_sampe_size )
+                        d[0] = d[1] = d[2] = s[layout->graychan];
+                    break;
+                case 3:
+                    for( ; s < end; d += 3, s += src_sampe_size ) {
+                        d[0] = s[layout->bchan];
+                        d[1] = s[layout->gchan];
+                        d[2] = s[layout->rchan];
+                    }
+                    break;
+                default:
+                    assert (0);
+            }
+            break;
+        }
+        default:
+            assert (0);
+    }
+}
+
+
+static bool ReadPAMHeaderLine (cv::RLByteStream& strm,
+                PamHeaderFieldType &fieldtype,
+                char value[MAX_PAM_HEADER_VALUE_LENGTH+1])
+{
+    int code, pos;
+    bool ident_found = false;
+    uint i;
+    char ident[MAX_PAM_HEADER_IDENITFIER_LENGTH+1] = { 0 };
+
+    do {
+        code = strm.getByte();
+    } while ( isspace(code) );
+
+    if (code == '#') {
+        /* we are in a comment, eat characters until linebreak */
+        do
+        {
+            code = strm.getByte();
+        } while( code != '\n' && code != '\r' );
+        fieldtype = PAM_HEADER_COMMENT;
+        return true;
+    } else if (code == '\n' || code == '\r' ) {
+        fieldtype = PAM_HEADER_NONE;
+        return true;
+    }
+
+    /* nul-ify buffers before writing to them */
+    memset (ident, '\0', sizeof(char) * MAX_PAM_HEADER_IDENITFIER_LENGTH);
+    for (i=0; i<MAX_PAM_HEADER_IDENITFIER_LENGTH; i++) {
+        if (!isspace(code))
+            ident[i] = (char) code;
+        else
+            break;
+        code = strm.getByte();
+    }
+
+    /* we may have filled the buffer and still have data */
+    if (!isspace(code))
+        return false;
+
+    for (i=0; i<PAM_FIELDS_NO; i++) {
+        if (strncmp(fields[i].identifier, ident, MAX_PAM_HEADER_IDENITFIER_LENGTH+1) == 0) {
+            fieldtype = fields[i].type;
+            ident_found = true;
+        }
+    }
+
+    if (!ident_found)
+        return false;
+
+    memset (value, '\0', sizeof(char) * MAX_PAM_HEADER_VALUE_LENGTH);
+    /* we may have an identifier that has no value */
+    if (code == '\n' || code == '\r')
+        return true;
+
+    do {
+        code = strm.getByte();
+    } while ( isspace(code) );
+
+
+
+    /* read identifier value */
+    for (i=0; i<MAX_PAM_HEADER_VALUE_LENGTH; i++) {
+        if (code != '\n' && code != '\r') {
+            value[i] = (char) code;
+        } else if (code != '\n' || code != '\r')
+            break;
+        code = strm.getByte();
+    }
+    pos = i;
+
+    /* should be terminated */
+    if (code != '\n' && code != '\r')
+        return false;
+
+    /* remove trailing white spaces */
+    while (pos >= 0 && isspace(value[pos]))
+        value[pos--] = '\0';
+
+    return true;
+}
+
+static bool ParseNumber (char *str, int *retval)
+{
+  char *endptr;
+  long lval = strtol (str, &endptr, 0);
+
+  if ((errno == ERANGE && (lval == LONG_MAX || lval == LONG_MIN))
+        || (errno != 0 && lval == 0)) {
+    return false;
+  }
+  if (endptr == str) {
+    return false;
+  }
+
+  *retval = (int) lval;
+
+  return true;
+}
+
+namespace cv
+{
+
+PAMDecoder::PAMDecoder()
+{
+    m_offset = -1;
+    m_buf_supported = true;
+    bit_mode = false;
+    selected_fmt = CV_IMWRITE_PAM_FORMAT_NULL;
+}
+
+
+PAMDecoder::~PAMDecoder()
+{
+    m_strm.close();
+}
+
+size_t PAMDecoder::signatureLength() const
+{
+    return 3;
+}
+
+bool PAMDecoder::checkSignature( const String& signature ) const
+{
+    return signature.size() >= 3 && signature[0] == 'P' &&
+           signature[1] == '7' &&
+           isspace(signature[2]);
+}
+
+ImageDecoder PAMDecoder::newDecoder() const
+{
+    return makePtr<PAMDecoder>();
+}
+
+struct parsed_fields
+{
+    bool endhdr, height, width, depth, maxval;
+};
+
+#define HEADER_READ_CORRECT(pf) (pf.endhdr && pf.height && pf.width \
+    && pf.depth && pf.maxval)
+
+
+bool  PAMDecoder::readHeader()
+{
+    PamHeaderFieldType fieldtype = PAM_HEADER_NONE;
+    char value[MAX_PAM_HEADER_VALUE_LENGTH+1];
+    int byte;
+    struct parsed_fields flds;
+    if( !m_buf.empty() )
+    {
+        if( !m_strm.open(m_buf) )
+            return false;
+    }
+    else if( !m_strm.open( m_filename ))
+        return false;
+    try
+    {
+        byte = m_strm.getByte();
+        if( byte != 'P' )
+            throw RBS_BAD_HEADER;
+
+        byte = m_strm.getByte();
+        if (byte != '7')
+            throw RBS_BAD_HEADER;
+
+        byte = m_strm.getByte();
+        if (byte != '\n' && byte != '\r')
+            throw RBS_BAD_HEADER;
+
+        uint i;
+        memset (&flds, 0x00, sizeof (struct parsed_fields));
+        do {
+            if (!ReadPAMHeaderLine(m_strm, fieldtype, value))
+                throw RBS_BAD_HEADER;
+            switch (fieldtype) {
+                case PAM_HEADER_NONE:
+                case PAM_HEADER_COMMENT:
+                    continue;
+                case PAM_HEADER_ENDHDR:
+                    flds.endhdr = true;
+                    break;
+                case PAM_HEADER_HEIGHT:
+                    if (flds.height)
+                        throw RBS_BAD_HEADER;
+                    if (!ParseNumber (value, &m_height))
+                        throw RBS_BAD_HEADER;
+                    flds.height = true;
+                    break;
+                case PAM_HEADER_WIDTH:
+                    if (flds.width)
+                        throw RBS_BAD_HEADER;
+                    if (!ParseNumber (value, &m_width))
+                        throw RBS_BAD_HEADER;
+                    flds.width = true;
+                    break;
+                case PAM_HEADER_DEPTH:
+                    if (flds.depth)
+                        throw RBS_BAD_HEADER;
+                    if (!ParseNumber (value, &m_channels))
+                        throw RBS_BAD_HEADER;
+                    flds.depth = true;
+                    break;
+                case PAM_HEADER_MAXVAL:
+                    if (flds.maxval)
+                        throw RBS_BAD_HEADER;
+                    if (!ParseNumber (value, &m_maxval))
+                        throw RBS_BAD_HEADER;
+                    if ( m_maxval > 65535 )
+                        throw RBS_BAD_HEADER;
+                    if ( m_maxval > 255 ) {
+                        m_sampledepth = CV_16U;
+                    }
+                    else
+                        m_sampledepth = CV_8U;
+                    if (m_maxval == 1)
+                        bit_mode = true;
+                    flds.maxval = true;
+                    break;
+                case PAM_HEADER_TUPLTYPE:
+                    for (i=0; i<PAM_FORMATS_NO; i++) {
+                        if (strncmp(formats[i].name,
+                                value, MAX_PAM_HEADER_VALUE_LENGTH+1) == 0) {
+                            selected_fmt = formats[i].fmt;
+                        }
+                    }
+                    break;
+                default:
+                    throw RBS_BAD_HEADER;
+            }
+        } while (fieldtype != PAM_HEADER_ENDHDR);
+
+        if (HEADER_READ_CORRECT(flds)) {
+            if (selected_fmt == CV_IMWRITE_PAM_FORMAT_NULL) {
+                if (m_channels == 1 && m_maxval == 1)
+                    selected_fmt = CV_IMWRITE_PAM_FORMAT_BLACKANDWHITE;
+                else if (m_channels == 1 && m_maxval < 256)
+                    selected_fmt = CV_IMWRITE_PAM_FORMAT_GRAYSCALE;
+                else if (m_channels == 3 && m_maxval < 256)
+                    selected_fmt = CV_IMWRITE_PAM_FORMAT_RGB;
+            }
+            m_type = CV_MAKETYPE(m_sampledepth, m_channels);
+            m_offset = m_strm.getPos();
+
+            return true;
+        }
+    } catch(...)
+    {
+    }
+
+    m_offset = -1;
+    m_width = m_height = -1;
+    m_strm.close();
+    return false;
+}
+
+
+bool  PAMDecoder::readData( Mat& img )
+{
+    uchar* data = img.ptr();
+    int target_channels = img.channels();
+    int imp_stride = (int)img.step;
+    int sample_depth = CV_ELEM_SIZE1(m_type);
+    int src_elems_per_row = m_width*m_channels;
+    int src_stride = src_elems_per_row*sample_depth;
+    int x, y;
+    bool res = false, funcout;
+    PaletteEntry palette[256];
+    const struct pam_format *fmt = NULL;
+    struct channel_layout layout;
+
+    /* setting buffer to max data size so scaling up is possible */
+    AutoBuffer<uchar> _src(src_elems_per_row * 2);
+    uchar* src = _src;
+    AutoBuffer<uchar> _gray_palette;
+    uchar* gray_palette = _gray_palette;
+
+    if( m_offset < 0 || !m_strm.isOpened())
+        return false;
+
+    if (selected_fmt != CV_IMWRITE_PAM_FORMAT_NULL)
+        fmt = &formats[selected_fmt];
+    else {
+        /* default layout handling */
+        if (m_channels >= 3) {
+            layout.bchan = 0;
+            layout.gchan = 1;
+            layout.rchan = 2;
+        } else
+            layout.bchan = layout.gchan = layout.rchan = 0;
+        layout.graychan = 0;
+    }
+
+    try
+    {
+        m_strm.setPos( m_offset );
+
+        /* the case where data fits the opencv matrix */
+        if (m_sampledepth == img.depth() && target_channels == m_channels && !bit_mode) {
+            /* special case for 16bit images with wrong endianess */
+            if (m_sampledepth == CV_16U && !isBigEndian())
+            {
+                for (y = 0; y < m_height; y++, data += imp_stride )
+                {
+                    m_strm.getBytes( src, src_stride );
+                    for( x = 0; x < src_elems_per_row; x++ )
+                    {
+                        uchar v = src[x * 2];
+                        data[x * 2] = src[x * 2 + 1];
+                        data[x * 2 + 1] = v;
+                    }
+                }
+            }
+            else {
+                m_strm.getBytes( data, src_stride * m_height );
+            }
+
+        }
+        else {
+            /* black and white mode */
+            if (bit_mode) {
+                if( target_channels == 1 )
+                {
+                    _gray_palette.allocate(2);
+                    gray_palette = _gray_palette;
+                    gray_palette[0] = 0;
+                    gray_palette[1] = 255;
+                    for( y = 0; y < m_height; y++, data += imp_stride )
+                    {
+                        m_strm.getBytes( src, src_stride );
+                        FillGrayRow1( data, src, m_width, gray_palette );
+                    }
+                } else if ( target_channels == 3 )
+                {
+                    FillGrayPalette( palette, 1 , false );
+                    for( y = 0; y < m_height; y++, data += imp_stride )
+                    {
+                        m_strm.getBytes( src, src_stride );
+                        FillColorRow1( data, src, m_width, palette );
+                    }
+                }
+            } else {
+                for (y = 0; y < m_height; y++, data += imp_stride )
+                {
+                    m_strm.getBytes( src, src_stride );
+
+                    /* endianess correction */
+                    if( m_sampledepth == CV_16U && !isBigEndian() )
+                    {
+                        for( x = 0; x < src_elems_per_row; x++ )
+                        {
+                            uchar v = src[x * 2];
+                            src[x * 2] = src[x * 2 + 1];
+                            src[x * 2 + 1] = v;
+                        }
+                    }
+
+                    /* scale down */
+                    if( img.depth() == CV_8U && m_sampledepth == CV_16U )
+                    {
+                        for( x = 0; x < src_elems_per_row; x++ )
+                        {
+                            int v = ((ushort *)src)[x];
+                            src[x] = (uchar)(v >> 8);
+                        }
+                    }
+
+                    /* if we are only scaling up/down then we can then copy the data */
+                    if (target_channels == m_channels) {
+                        memcpy (data, src, imp_stride);
+                    }
+                    /* perform correct conversion based on format */
+                    else if (fmt) {
+                        funcout = false;
+                        if (fmt->cvt_func)
+                            funcout = fmt->cvt_func (src, data, m_width, target_channels,
+                                img.depth());
+                        /* fall back to default if there is no conversion function or it
+                         * can't handle the specified characteristics
+                         */
+                        if (!funcout)
+                            basic_conversion (src, &fmt->layout, m_channels,
+                                m_width, data, target_channels, img.depth());
+
+                    /* default to selecting the first available channels */
+                    } else {
+                        basic_conversion (src, &layout, m_channels,
+                            m_width, data, target_channels, img.depth());
+                    }
+                }
+            }
+        }
+
+        res = true;
+    } catch(...)
+    {
+    }
+
+    return res;
+}
+
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+PAMEncoder::PAMEncoder()
+{
+    m_description = "Portable arbitrary format (*.pam)";
+    m_buf_supported = true;
+}
+
+
+PAMEncoder::~PAMEncoder()
+{
+}
+
+
+ImageEncoder PAMEncoder::newEncoder() const
+{
+    return makePtr<PAMEncoder>();
+}
+
+
+bool PAMEncoder::isFormatSupported( int depth ) const
+{
+    return depth == CV_8U || depth == CV_16U;
+}
+
+
+bool PAMEncoder::write( const Mat& img, const std::vector<int>& params )
+{
+
+    WLByteStream strm;
+
+    int width = img.cols, height = img.rows;
+    int stride = width*(int)img.elemSize();
+    const uchar* data = img.ptr();
+    const struct pam_format *fmt = NULL;
+    int x, y, tmp, bufsize = 256;
+
+    /* parse save file type */
+    for( size_t i = 0; i < params.size(); i += 2 )
+        if( params[i] == CV_IMWRITE_PAM_TUPLETYPE ) {
+            if ( params[i+1] > CV_IMWRITE_PAM_FORMAT_NULL &&
+                 params[i+1] < (int) PAM_FORMATS_NO)
+                fmt = &formats[params[i+1]];
+        }
+
+    if( m_buf )
+    {
+        if( !strm.open(*m_buf) )
+            return false;
+        m_buf->reserve( alignSize(256 + stride*height, 256));
+    }
+    else if( !strm.open(m_filename) )
+        return false;
+
+    tmp = width * (int)img.elemSize();
+
+    if (bufsize < tmp)
+        bufsize = tmp;
+
+    AutoBuffer<char> _buffer(bufsize);
+    char* buffer = _buffer;
+
+    /* write header */
+    tmp = 0;
+    tmp += sprintf( buffer, "P7\n");
+    tmp += sprintf( buffer + tmp, "WIDTH %d\n", width);
+    tmp += sprintf( buffer + tmp, "HEIGHT %d\n", height);
+    tmp += sprintf( buffer + tmp, "DEPTH %d\n", img.channels());
+    tmp += sprintf( buffer + tmp, "MAXVAL %d\n", (1 << img.elemSize1()*8) - 1);
+    if (fmt)
+        tmp += sprintf( buffer + tmp, "TUPLTYPE %s\n", fmt->name );
+    tmp += sprintf( buffer + tmp, "ENDHDR\n" );
+
+    strm.putBytes( buffer, (int)strlen(buffer) );
+    /* write data */
+    if (img.depth() == CV_8U)
+        strm.putBytes( data, stride*height );
+    else if (img.depth() == CV_16U) {
+        /* fix endianess */
+        if (!isBigEndian()) {
+            for( y = 0; y < height; y++ ) {
+                memcpy( buffer, img.ptr(y), stride );
+                for( x = 0; x < stride; x += 2 )
+                {
+                    uchar v = buffer[x];
+                    buffer[x] = buffer[x + 1];
+                    buffer[x + 1] = v;
+                }
+                strm.putBytes( buffer, stride );
+            }
+        } else
+            strm.putBytes( data, stride*height );
+    } else
+        assert (0);
+
+    strm.close();
+    return true;
+}
+
+}
diff --git a/modules/imgcodecs/src/grfmt_pam.hpp b/modules/imgcodecs/src/grfmt_pam.hpp
new file mode 100644
index 0000000..8b3b1f1
--- /dev/null
+++ b/modules/imgcodecs/src/grfmt_pam.hpp
@@ -0,0 +1,99 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+//  By downloading, copying, installing or using the software you agree to this license.
+//  If you do not agree to this license, do not download, install,
+//  copy or use the software.
+//
+//
+//                            License Agreement
+//                 For Open Source Computer Vision Library
+//                         (3-clause BSD License)
+//
+//  Copyright (C) 2000-2016, Intel Corporation, all rights reserved.
+//  Copyright (C) 2009-2011, Willow Garage Inc., all rights reserved.
+//  Copyright (C) 2009-2016, NVIDIA Corporation, all rights reserved.
+//  Copyright (C) 2010-2013, Advanced Micro Devices, Inc., all rights reserved.
+//  Copyright (C) 2015-2016, OpenCV Foundation, all rights reserved.
+//  Copyright (C) 2015-2016, Itseez Inc., all rights reserved.
+//  Third party copyrights are property of their respective owners.
+//
+//  Redistribution and use in source and binary forms, with or without modification,
+//  are permitted provided that the following conditions are met:
+//
+//    * Redistributions of source code must retain the above copyright notice,
+//      this list of conditions and the following disclaimer.
+//
+//    * Redistributions in binary form must reproduce the above copyright notice,
+//      this list of conditions and the following disclaimer in the documentation
+//      and/or other materials provided with the distribution.
+//
+//    * Neither the names of the copyright holders nor the names of the contributors
+//      may be used to endorse or promote products derived from this software
+//      without specific prior written permission.
+//
+//  This software is provided by the copyright holders and contributors "as is" and
+//  any express or implied warranties, including, but not limited to, the implied
+//  warranties of merchantability and fitness for a particular purpose are disclaimed.
+//  In no event shall copyright holders or contributors be liable for any direct,
+//  indirect, incidental, special, exemplary, or consequential damages
+//  (including, but not limited to, procurement of substitute goods or services;
+//  loss of use, data, or profits; or business interruption) however caused
+//  and on any theory of liability, whether in contract, strict liability,
+//  or tort (including negligence or otherwise) arising in any way out of
+//  the use of this software, even if advised of the possibility of such damage.
+//
+//
+//M*/
+
+//Based on "imgcodecs/src/grfmt_pxm.hpp"
+//Written by Dimitrios Katsaros <patcherwork at gmail.com>
+
+#ifndef _OPENCV_PAM_HPP_
+#define _OPENCV_PAM_HPP_
+
+#include "grfmt_base.hpp"
+#include "bitstrm.hpp"
+
+namespace cv
+{
+
+class PAMDecoder : public BaseImageDecoder
+{
+public:
+
+    PAMDecoder();
+    virtual ~PAMDecoder();
+
+    bool  readData( Mat& img );
+    bool  readHeader();
+
+    size_t signatureLength() const;
+    bool checkSignature( const String& signature ) const;
+    ImageDecoder newDecoder() const;
+
+protected:
+
+    RLByteStream    m_strm;
+    int m_maxval, m_channels, m_sampledepth, m_offset,
+        selected_fmt;
+    bool bit_mode;
+};
+
+
+class PAMEncoder : public BaseImageEncoder
+{
+public:
+    PAMEncoder();
+    virtual ~PAMEncoder();
+
+    bool  isFormatSupported( int depth ) const;
+    bool  write( const Mat& img, const std::vector<int>& params );
+
+    ImageEncoder newEncoder() const;
+};
+
+}
+
+#endif /* _OPENCV_PAM_HPP_ */
\ No newline at end of file
diff --git a/modules/imgcodecs/src/grfmt_png.cpp b/modules/imgcodecs/src/grfmt_png.cpp
index 2f4a62b..c8ff244 100644
--- a/modules/imgcodecs/src/grfmt_png.cpp
+++ b/modules/imgcodecs/src/grfmt_png.cpp
@@ -190,16 +190,14 @@ bool  PngDecoder::readHeader()
                         switch(color_type)
                         {
                             case PNG_COLOR_TYPE_RGB:
-                                m_type = CV_8UC3;
-                                break;
                             case PNG_COLOR_TYPE_PALETTE:
-                                png_get_tRNS( png_ptr, info_ptr, &trans, &num_trans, &trans_values);
-                                //Check if there is a transparency value in the palette
-                                if ( num_trans > 0 )
+                                png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, &trans_values);
+                                if( num_trans > 0 )
                                     m_type = CV_8UC4;
                                 else
                                     m_type = CV_8UC3;
                                 break;
+                            case PNG_COLOR_TYPE_GRAY_ALPHA:
                             case PNG_COLOR_TYPE_RGB_ALPHA:
                                 m_type = CV_8UC4;
                                 break;
@@ -228,8 +226,6 @@ bool  PngDecoder::readData( Mat& img )
     AutoBuffer<uchar*> _buffer(m_height);
     uchar** buffer = _buffer;
     int color = img.channels() > 1;
-    uchar* data = img.ptr();
-    int step = (int)img.step;
 
     if( m_png_ptr && m_info_ptr && m_end_info && m_width && m_height )
     {
@@ -257,12 +253,13 @@ bool  PngDecoder::readData( Mat& img )
                  * stripping alpha..  18.11.2004 Axel Walthelm
                  */
                  png_set_strip_alpha( png_ptr );
-            }
+            } else
+                png_set_tRNS_to_alpha( png_ptr );
 
             if( m_color_type == PNG_COLOR_TYPE_PALETTE )
                 png_set_palette_to_rgb( png_ptr );
 
-            if( m_color_type == PNG_COLOR_TYPE_GRAY && m_bit_depth < 8 )
+            if( (m_color_type & PNG_COLOR_MASK_COLOR) == 0 && m_bit_depth < 8 )
 #if (PNG_LIBPNG_VER_MAJOR*10000 + PNG_LIBPNG_VER_MINOR*100 + PNG_LIBPNG_VER_RELEASE >= 10209) || \
     (PNG_LIBPNG_VER_MAJOR == 1 && PNG_LIBPNG_VER_MINOR == 0 && PNG_LIBPNG_VER_RELEASE >= 18)
                 png_set_expand_gray_1_2_4_to_8( png_ptr );
@@ -270,7 +267,7 @@ bool  PngDecoder::readData( Mat& img )
                 png_set_gray_1_2_4_to_8( png_ptr );
 #endif
 
-            if( CV_MAT_CN(m_type) > 1 && color )
+            if( (m_color_type & PNG_COLOR_MASK_COLOR) && color )
                 png_set_bgr( png_ptr ); // convert RGB to BGR
             else if( color )
                 png_set_gray_to_rgb( png_ptr ); // Gray->RGB
@@ -281,7 +278,7 @@ bool  PngDecoder::readData( Mat& img )
             png_read_update_info( png_ptr, info_ptr );
 
             for( y = 0; y < m_height; y++ )
-                buffer[y] = data + y*step;
+                buffer[y] = img.data + y*img.step;
 
             png_read_image( png_ptr, buffer );
             png_read_end( png_ptr, end_info );
@@ -372,22 +369,23 @@ bool  PngEncoder::write( const Mat& img, const std::vector<int>& params )
                 }
 
                 int compression_level = -1; // Invalid value to allow setting 0-9 as valid
-                int compression_strategy = Z_RLE; // Default strategy
+                int compression_strategy = IMWRITE_PNG_STRATEGY_RLE; // Default strategy
                 bool isBilevel = false;
 
                 for( size_t i = 0; i < params.size(); i += 2 )
                 {
-                    if( params[i] == CV_IMWRITE_PNG_COMPRESSION )
+                    if( params[i] == IMWRITE_PNG_COMPRESSION )
                     {
+                        compression_strategy = IMWRITE_PNG_STRATEGY_DEFAULT; // Default strategy
                         compression_level = params[i+1];
                         compression_level = MIN(MAX(compression_level, 0), Z_BEST_COMPRESSION);
                     }
-                    if( params[i] == CV_IMWRITE_PNG_STRATEGY )
+                    if( params[i] == IMWRITE_PNG_STRATEGY )
                     {
                         compression_strategy = params[i+1];
                         compression_strategy = MIN(MAX(compression_strategy, 0), Z_FIXED);
                     }
-                    if( params[i] == CV_IMWRITE_PNG_BILEVEL )
+                    if( params[i] == IMWRITE_PNG_BILEVEL )
                     {
                         isBilevel = params[i+1] != 0;
                     }
diff --git a/modules/imgcodecs/src/grfmt_pxm.cpp b/modules/imgcodecs/src/grfmt_pxm.cpp
index 7f29909..8afd7b1 100644
--- a/modules/imgcodecs/src/grfmt_pxm.cpp
+++ b/modules/imgcodecs/src/grfmt_pxm.cpp
@@ -190,7 +190,6 @@ bool  PxMDecoder::readData( Mat& img )
 {
     int color = img.channels() > 1;
     uchar* data = img.ptr();
-    int step = (int)img.step;
     PaletteEntry palette[256];
     bool   result = false;
     int  bit_depth = CV_ELEM_SIZE1(m_type)*8;
@@ -229,7 +228,7 @@ bool  PxMDecoder::readData( Mat& img )
         case 1:
             if( !m_binary )
             {
-                for( y = 0; y < m_height; y++, data += step )
+                for( y = 0; y < m_height; y++, data += img.step )
                 {
                     for( x = 0; x < m_width; x++ )
                         src[x] = ReadNumber( m_strm, 1 ) != 0;
@@ -242,7 +241,7 @@ bool  PxMDecoder::readData( Mat& img )
             }
             else
             {
-                for( y = 0; y < m_height; y++, data += step )
+                for( y = 0; y < m_height; y++, data += img.step )
                 {
                     m_strm.getBytes( src, src_pitch );
 
@@ -258,7 +257,7 @@ bool  PxMDecoder::readData( Mat& img )
         ////////////////////////// 8 BPP /////////////////////////
         case 8:
         case 24:
-            for( y = 0; y < m_height; y++, data += step )
+            for( y = 0; y < m_height; y++, data += img.step )
             {
                 if( !m_binary )
                 {
@@ -310,7 +309,7 @@ bool  PxMDecoder::readData( Mat& img )
                         }
                     }
                     else
-                        memcpy( data, src, m_width*(bit_depth/8) );
+                        memcpy( data, src, CV_ELEM_SIZE1(m_type)*m_width);
                 }
                 else
                 {
diff --git a/modules/imgcodecs/src/grfmts.hpp b/modules/imgcodecs/src/grfmts.hpp
index c9e3153..10bd882 100644
--- a/modules/imgcodecs/src/grfmts.hpp
+++ b/modules/imgcodecs/src/grfmts.hpp
@@ -54,5 +54,7 @@
 #include "grfmt_webp.hpp"
 #include "grfmt_hdr.hpp"
 #include "grfmt_gdal.hpp"
+#include "grfmt_gdcm.hpp"
+#include "grfmt_pam.hpp"
 
 #endif/*_GRFMTS_H_*/
diff --git a/modules/imgcodecs/src/ios_conversions.mm b/modules/imgcodecs/src/ios_conversions.mm
index 8f2b4e8..eed867a 100644
--- a/modules/imgcodecs/src/ios_conversions.mm
+++ b/modules/imgcodecs/src/ios_conversions.mm
@@ -100,12 +100,14 @@ void UIImageToMat(const UIImage* image,
     CGFloat cols = image.size.width, rows = image.size.height;
     CGContextRef contextRef;
     CGBitmapInfo bitmapInfo = kCGImageAlphaPremultipliedLast;
-    if (CGColorSpaceGetModel(colorSpace) == 0)
+    if (CGColorSpaceGetModel(colorSpace) == kCGColorSpaceModelMonochrome)
     {
         m.create(rows, cols, CV_8UC1); // 8 bits per component, 1 channel
         bitmapInfo = kCGImageAlphaNone;
         if (!alphaExist)
             bitmapInfo = kCGImageAlphaNone;
+        else
+            m = cv::Scalar(0);
         contextRef = CGBitmapContextCreate(m.data, m.cols, m.rows, 8,
                                            m.step[0], colorSpace,
                                            bitmapInfo);
@@ -116,6 +118,8 @@ void UIImageToMat(const UIImage* image,
         if (!alphaExist)
             bitmapInfo = kCGImageAlphaNoneSkipLast |
                                 kCGBitmapByteOrderDefault;
+        else
+            m = cv::Scalar(0);
         contextRef = CGBitmapContextCreate(m.data, m.cols, m.rows, 8,
                                            m.step[0], colorSpace,
                                            bitmapInfo);
diff --git a/modules/imgcodecs/src/jpeg_exif.cpp b/modules/imgcodecs/src/jpeg_exif.cpp
deleted file mode 100644
index 103e72d..0000000
--- a/modules/imgcodecs/src/jpeg_exif.cpp
+++ /dev/null
@@ -1,611 +0,0 @@
-/*M///////////////////////////////////////////////////////////////////////////////////////
-//
-//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
-//
-//  By downloading, copying, installing or using the software you agree to this license.
-//  If you do not agree to this license, do not download, install,
-//  copy or use the software.
-//
-//
-//                           License Agreement
-//                For Open Source Computer Vision Library
-//
-// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
-// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
-// Third party copyrights are property of their respective owners.
-//
-// Redistribution and use in source and binary forms, with or without modification,
-// are permitted provided that the following conditions are met:
-//
-//   * Redistribution's of source code must retain the above copyright notice,
-//     this list of conditions and the following disclaimer.
-//
-//   * Redistribution's in binary form must reproduce the above copyright notice,
-//     this list of conditions and the following disclaimer in the documentation
-//     and/or other materials provided with the distribution.
-//
-//   * The name of the copyright holders may not be used to endorse or promote products
-//     derived from this software without specific prior written permission.
-//
-// This software is provided by the copyright holders and contributors "as is" and
-// any express or implied warranties, including, but not limited to, the implied
-// warranties of merchantability and fitness for a particular purpose are disclaimed.
-// In no event shall the Intel Corporation or contributors be liable for any direct,
-// indirect, incidental, special, exemplary, or consequential damages
-// (including, but not limited to, procurement of substitute goods or services;
-// loss of use, data, or profits; or business interruption) however caused
-// and on any theory of liability, whether in contract, strict liability,
-// or tort (including negligence or otherwise) arising in any way out of
-// the use of this software, even if advised of the possibility of such damage.
-//
-//M*/
-
-#include "jpeg_exif.hpp"
-
-namespace {
-
-    class ExifParsingError {
-    };
-}
-
-
-namespace cv
-{
-
-ExifEntry_t::ExifEntry_t() :
-    field_float(0), field_double(0), field_u32(0), field_s32(0),
-    tag(INVALID_TAG), field_u16(0), field_s16(0), field_u8(0), field_s8(0)
-{
-}
-
-/**
- * @brief ExifReader constructor
- */
-ExifReader::ExifReader(std::string filename) : m_filename(filename), m_format(NONE)
-{
-}
-
-/**
- * @brief ExifReader destructor
- */
-ExifReader::~ExifReader()
-{
-}
-
-/**
- * @brief Parsing the jpeg file and prepare (internally) exif directory structure
- * @return  true if parsing was successful and exif information exists in JpegReader object
- *          false in case of unsuccessful parsing
- */
-bool ExifReader::parse()
-{
-    try {
-        m_exif = getExif();
-        if( !m_exif.empty() )
-        {
-            return true;
-        }
-        return false;
-    } catch (ExifParsingError&) {
-        return false;
-    }
-}
-
-
-/**
- *  @brief Get tag value by tag number
- *
- *  @param [in] tag The tag number
- *
- *  @return ExifEntru_t structure. Caller has to know what tag it calls in order to extract proper field from the structure ExifEntry_t
- *
- */
-ExifEntry_t ExifReader::getTag(const ExifTagName tag)
-{
-    ExifEntry_t entry;
-    std::map<int, ExifEntry_t>::iterator it = m_exif.find(tag);
-
-    if( it != m_exif.end() )
-    {
-        entry = it->second;
-    }
-    return entry;
-}
-
-
-/**
- * @brief Get exif directory structure contained in jpeg file (if any)
- *          This is internal function and is not exposed to client
- *
- *  @return Map where key is tag number and value is ExifEntry_t structure
- */
-std::map<int, ExifEntry_t > ExifReader::getExif()
-{
-    const size_t markerSize = 2;
-    const size_t offsetToTiffHeader = 6; //bytes from Exif size field to the first TIFF header
-    unsigned char appMarker[markerSize];
-    m_exif.erase( m_exif.begin(), m_exif.end() );
-
-    size_t count;
-
-    FILE* f = fopen( m_filename.c_str(), "rb" );
-
-    if( !f )
-    {
-        return m_exif; //Until this moment the map is empty
-    }
-
-    bool exifFound = false;
-    while( ( !feof( f ) ) && !exifFound )
-    {
-        count = fread( appMarker, sizeof(unsigned char), markerSize, f );
-        if( count < markerSize )
-        {
-            break;
-        }
-        unsigned char marker = appMarker[1];
-        size_t bytesToSkip;
-        size_t exifSize;
-        switch( marker )
-        {
-            //For all the markers just skip bytes in file pointed by followed two bytes (field size)
-            case SOF0: case SOF2: case DHT: case DQT: case DRI: case SOS:
-            case RST0: case RST1: case RST2: case RST3: case RST4: case RST5: case RST6: case RST7:
-            case APP0: case APP2: case APP3: case APP4: case APP5: case APP6: case APP7: case APP8:
-            case APP9: case APP10: case APP11: case APP12: case APP13: case APP14: case APP15:
-            case COM:
-                bytesToSkip = getFieldSize( f );
-                fseek( f, static_cast<long>( bytesToSkip - markerSize ), SEEK_CUR );
-                break;
-
-            //SOI and EOI don't have the size field after the marker
-            case SOI: case EOI:
-                break;
-
-            case APP1: //actual Exif Marker
-                exifSize = getFieldSize(f);
-                if (exifSize <= offsetToTiffHeader) {
-                    throw ExifParsingError();
-                }
-                m_data.resize( exifSize - offsetToTiffHeader );
-                fseek(f, static_cast<long>( offsetToTiffHeader ), SEEK_CUR);
-                count = fread( &m_data[0], sizeof( unsigned char ), exifSize - offsetToTiffHeader, f );
-                exifFound = true;
-                break;
-
-            default: //No other markers are expected according to standard. May be a signal of error
-                break;
-        }
-    }
-
-    fclose(f);
-
-    if( !exifFound )
-    {
-        return m_exif;
-    }
-
-    parseExif();
-
-    return m_exif;
-}
-
-/**
- * @brief Get the size of exif field (required to properly ready whole exif from the file)
- *          This is internal function and is not exposed to client
- *
- *  @return size of exif field in the file
- */
-size_t ExifReader::getFieldSize (FILE* f) const
-{
-    unsigned char fieldSize[2];
-    size_t count = fread ( fieldSize, sizeof( char ), 2, f );
-    if (count < 2)
-    {
-        return 0;
-    }
-    return ( fieldSize[0] << 8 ) + fieldSize[1];
-}
-
-/**
- * @brief Filling m_exif member with exif directory elements
- *          This is internal function and is not exposed to client
- *
- *  @return The function doesn't return any value. In case of unsiccessful parsing
- *      the m_exif member is not filled up
- */
-void ExifReader::parseExif()
-{
-    m_format = getFormat();
-
-    if( !checkTagMark() )
-    {
-        return;
-    }
-
-    uint32_t offset = getStartOffset();
-
-    size_t numEntry = getNumDirEntry();
-
-    offset += 2; //go to start of tag fields
-
-    for( size_t entry = 0; entry < numEntry; entry++ )
-    {
-        ExifEntry_t exifEntry = parseExifEntry( offset );
-        m_exif.insert( std::make_pair( exifEntry.tag, exifEntry ) );
-        offset += tiffFieldSize;
-    }
-}
-
-/**
- * @brief Get endianness of exif information
- *          This is internal function and is not exposed to client
- *
- * @return INTEL, MOTO or NONE
- */
-Endianess_t ExifReader::getFormat() const
-{
-    if( m_data[0] != m_data[1] )
-    {
-        return NONE;
-    }
-
-    if( m_data[0] == 'I' )
-    {
-        return INTEL;
-    }
-
-    if( m_data[0] == 'M' )
-    {
-        return MOTO;
-    }
-
-    return NONE;
-}
-
-/**
- * @brief Checking whether Tag Mark (0x002A) correspond to one contained in the Jpeg file
- *          This is internal function and is not exposed to client
- *
- * @return true if tag mark equals 0x002A, false otherwise
- */
-bool ExifReader::checkTagMark() const
-{
-    uint16_t tagMark = getU16( 2 );
-
-    if( tagMark != tagMarkRequired )
-    {
-        return false;
-    }
-    return true;
-}
-
-/**
- * @brief The utility function for extracting actual offset exif IFD0 info is started from
- *          This is internal function and is not exposed to client
- *
- * @return offset of IFD0 field
- */
-uint32_t ExifReader::getStartOffset() const
-{
-    return getU32( 4 );
-}
-
-/**
- * @brief Get the number of Directory Entries in Jpeg file
- *
- * @return The number of directory entries
- */
-size_t ExifReader::getNumDirEntry() const
-{
-    return getU16( offsetNumDir );
-}
-
-/**
- * @brief Parsing particular entry in exif directory
- *          This is internal function and is not exposed to client
- *
- *      Entries are divided into 12-bytes blocks each
- *      Each block corresponds the following structure:
- *
- *      +------+-------------+-------------------+------------------------+
- *      | Type | Data format | Num of components | Data or offset to data |
- *      +======+=============+===================+========================+
- *      | TTTT | ffff        | NNNNNNNN          | DDDDDDDD               |
- *      +------+-------------+-------------------+------------------------+
- *
- *      Details can be found here: http://www.media.mit.edu/pia/Research/deepview/exif.html
- *
- * @param [in] offset Offset to entry in bytes inside raw exif data
- * @return ExifEntry_t structure which corresponds to particular entry
- *
- */
-ExifEntry_t ExifReader::parseExifEntry(const size_t offset)
-{
-    ExifEntry_t entry;
-    uint16_t tagNum = getExifTag( offset );
-    entry.tag = tagNum;
-
-    switch( tagNum )
-    {
-        case IMAGE_DESCRIPTION:
-            entry.field_str = getString( offset );
-            break;
-        case MAKE:
-            entry.field_str = getString( offset );
-            break;
-        case MODEL:
-            entry.field_str = getString( offset );
-            break;
-        case ORIENTATION:
-            entry.field_u16 = getOrientation( offset );
-            break;
-        case XRESOLUTION:
-            entry.field_u_rational = getResolution( offset );
-            break;
-        case YRESOLUTION:
-            entry.field_u_rational = getResolution( offset );
-            break;
-        case RESOLUTION_UNIT:
-            entry.field_u16 = getResolutionUnit( offset );
-            break;
-        case SOFTWARE:
-            entry.field_str = getString( offset );
-            break;
-        case DATE_TIME:
-            entry.field_str = getString( offset );
-            break;
-        case WHITE_POINT:
-            entry.field_u_rational = getWhitePoint( offset );
-            break;
-        case PRIMARY_CHROMATICIES:
-            entry.field_u_rational = getPrimaryChromaticies( offset );
-            break;
-        case Y_CB_CR_COEFFICIENTS:
-            entry.field_u_rational = getYCbCrCoeffs( offset );
-            break;
-        case Y_CB_CR_POSITIONING:
-            entry.field_u16 = getYCbCrPos( offset );
-            break;
-        case REFERENCE_BLACK_WHITE:
-            entry.field_u_rational = getRefBW( offset );
-            break;
-        case COPYRIGHT:
-            entry.field_str = getString( offset );
-            break;
-        case EXIF_OFFSET:
-            break;
-        default:
-            entry.tag = INVALID_TAG;
-            break;
-    }
-    return entry;
-}
-
-/**
- * @brief Get tag number from raw exif data
- *          This is internal function and is not exposed to client
- * @param [in] offset Offset to entry in bytes inside raw exif data
- * @return tag number
- */
-uint16_t ExifReader::getExifTag(const size_t offset) const
-{
-    return getU16( offset );
-}
-
-/**
- * @brief Get string information from raw exif data
- *          This is internal function and is not exposed to client
- * @param [in] offset Offset to entry in bytes inside raw exif data
- * @return string value
- */
-std::string ExifReader::getString(const size_t offset) const
-{
-    size_t size = getU32( offset + 4 );
-    size_t dataOffset = 8; // position of data in the field
-    if( size > maxDataSize )
-    {
-        dataOffset = getU32( offset + 8 );
-    }
-    if (dataOffset > m_data.size() || dataOffset + size > m_data.size()) {
-        throw ExifParsingError();
-    }
-    std::vector<uint8_t>::const_iterator it = m_data.begin() + dataOffset;
-    std::string result( it, it + size ); //copy vector content into result
-
-    return result;
-}
-
-/**
- * @brief Get unsigned short data from raw exif data
- *          This is internal function and is not exposed to client
- * @param [in] offset Offset to entry in bytes inside raw exif data
- * @return Unsigned short data
- */
-uint16_t ExifReader::getU16(const size_t offset) const
-{
-    if (offset + 1 >= m_data.size())
-        throw ExifParsingError();
-
-    if( m_format == INTEL )
-    {
-        return m_data[offset] + ( m_data[offset + 1] << 8 );
-    }
-    return ( m_data[offset] << 8 ) + m_data[offset + 1];
-}
-
-/**
- * @brief Get unsigned 32-bit data from raw exif data
- *          This is internal function and is not exposed to client
- * @param [in] offset Offset to entry in bytes inside raw exif data
- * @return Unsigned 32-bit data
- */
-uint32_t ExifReader::getU32(const size_t offset) const
-{
-    if (offset + 3 >= m_data.size())
-        throw ExifParsingError();
-
-    if( m_format == INTEL )
-    {
-        return m_data[offset] +
-                ( m_data[offset + 1] << 8 ) +
-                ( m_data[offset + 2] << 16 ) +
-                ( m_data[offset + 3] << 24 );
-    }
-
-    return ( m_data[offset] << 24 ) +
-            ( m_data[offset + 1] << 16 ) +
-            ( m_data[offset + 2] << 8 ) +
-            m_data[offset + 3];
-}
-
-/**
- * @brief Get unsigned rational data from raw exif data
- *          This is internal function and is not exposed to client
- * @param [in] offset Offset to entry in bytes inside raw exif data
- * @return Unsigned rational data
- *
- * "rational" means a fractional value, it contains 2 signed/unsigned long integer value,
- *  and the first represents the numerator, the second, the denominator.
- */
-u_rational_t ExifReader::getURational(const size_t offset) const
-{
-    u_rational_t result;
-    uint32_t numerator = getU32( offset );
-    uint32_t denominator = getU32( offset + 4 );
-
-    return std::make_pair( numerator, denominator );
-
-}
-
-/**
- * @brief Get orientation information from raw exif data
- *          This is internal function and is not exposed to client
- * @param [in] offset Offset to entry in bytes inside raw exif data
- * @return orientation number
- */
-uint16_t ExifReader::getOrientation(const size_t offset) const
-{
-    return getU16( offset + 8 );
-}
-
-/**
- * @brief Get resolution information from raw exif data
- *          This is internal function and is not exposed to client
- * @param [in] offset Offset to entry in bytes inside raw exif data
- * @return resolution value
- */
-std::vector<u_rational_t> ExifReader::getResolution(const size_t offset) const
-{
-    std::vector<u_rational_t> result;
-    uint32_t rationalOffset = getU32( offset + 8 );
-    result.push_back( getURational( rationalOffset ) );
-
-    return result;
-}
-
-/**
- * @brief Get resolution unit from raw exif data
- *          This is internal function and is not exposed to client
- * @param [in] offset Offset to entry in bytes inside raw exif data
- * @return resolution unit value
- */
-uint16_t ExifReader::getResolutionUnit(const size_t offset) const
-{
-    return getU16( offset + 8 );
-}
-
-/**
- * @brief Get White Point information from raw exif data
- *          This is internal function and is not exposed to client
- * @param [in] offset Offset to entry in bytes inside raw exif data
- * @return White Point value
- *
- * If the image uses CIE Standard Illumination D65(known as international
- * standard of 'daylight'), the values are '3127/10000,3290/10000'.
- */
-std::vector<u_rational_t> ExifReader::getWhitePoint(const size_t offset) const
-{
-    std::vector<u_rational_t> result;
-    uint32_t rationalOffset = getU32( offset + 8 );
-    result.push_back( getURational( rationalOffset ) );
-    result.push_back( getURational( rationalOffset + 8 ) );
-
-    return result;
-}
-
-/**
- * @brief Get Primary Chromaticies information from raw exif data
- *          This is internal function and is not exposed to client
- * @param [in] offset Offset to entry in bytes inside raw exif data
- * @return vector with primary chromaticies values
- *
- */
-std::vector<u_rational_t> ExifReader::getPrimaryChromaticies(const size_t offset) const
-{
-    std::vector<u_rational_t> result;
-    uint32_t rationalOffset = getU32( offset + 8 );
-    for( size_t i = 0; i < primaryChromaticiesComponents; i++ )
-    {
-        result.push_back( getURational( rationalOffset ) );
-        rationalOffset += 8;
-    }
-    return result;
-}
-
-/**
- * @brief Get YCbCr Coefficients information from raw exif data
- *          This is internal function and is not exposed to client
- * @param [in] offset Offset to entry in bytes inside raw exif data
- * @return vector with YCbCr coefficients values
- *
- */
-std::vector<u_rational_t> ExifReader::getYCbCrCoeffs(const size_t offset) const
-{
-    std::vector<u_rational_t> result;
-    uint32_t rationalOffset = getU32( offset + 8 );
-    for( size_t i = 0; i < ycbcrCoeffs; i++ )
-    {
-        result.push_back( getURational( rationalOffset ) );
-        rationalOffset += 8;
-    }
-    return result;
-}
-
-/**
- * @brief Get YCbCr Positioning information from raw exif data
- *          This is internal function and is not exposed to client
- * @param [in] offset Offset to entry in bytes inside raw exif data
- * @return vector with YCbCr positioning value
- *
- */
-uint16_t ExifReader::getYCbCrPos(const size_t offset) const
-{
-    return getU16( offset + 8 );
-}
-
-/**
- * @brief Get Reference Black&White point information from raw exif data
- *          This is internal function and is not exposed to client
- * @param [in] offset Offset to entry in bytes inside raw exif data
- * @return vector with reference BW points
- *
- * In case of YCbCr format, first 2 show black/white of Y, next 2 are Cb,
- * last 2 are Cr. In case of RGB format, first 2 show black/white of R,
- * next 2 are G, last 2 are B.
- *
- */
-std::vector<u_rational_t> ExifReader::getRefBW(const size_t offset) const
-{
-    const size_t rationalFieldSize = 8;
-    std::vector<u_rational_t> result;
-    uint32_t rationalOffset = getU32( offset + rationalFieldSize );
-    for( size_t i = 0; i < refBWComponents; i++ )
-    {
-        result.push_back( getURational( rationalOffset ) );
-        rationalOffset += rationalFieldSize;
-    }
-    return result;
-}
-
-} //namespace cv
diff --git a/modules/imgcodecs/src/jpeg_exif.hpp b/modules/imgcodecs/src/jpeg_exif.hpp
deleted file mode 100644
index c8502c5..0000000
--- a/modules/imgcodecs/src/jpeg_exif.hpp
+++ /dev/null
@@ -1,253 +0,0 @@
-/*M///////////////////////////////////////////////////////////////////////////////////////
-//
-//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
-//
-//  By downloading, copying, installing or using the software you agree to this license.
-//  If you do not agree to this license, do not download, install,
-//  copy or use the software.
-//
-//
-//                           License Agreement
-//                For Open Source Computer Vision Library
-//
-// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
-// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
-// Third party copyrights are property of their respective owners.
-//
-// Redistribution and use in source and binary forms, with or without modification,
-// are permitted provided that the following conditions are met:
-//
-//   * Redistribution's of source code must retain the above copyright notice,
-//     this list of conditions and the following disclaimer.
-//
-//   * Redistribution's in binary form must reproduce the above copyright notice,
-//     this list of conditions and the following disclaimer in the documentation
-//     and/or other materials provided with the distribution.
-//
-//   * The name of the copyright holders may not be used to endorse or promote products
-//     derived from this software without specific prior written permission.
-//
-// This software is provided by the copyright holders and contributors "as is" and
-// any express or implied warranties, including, but not limited to, the implied
-// warranties of merchantability and fitness for a particular purpose are disclaimed.
-// In no event shall the Intel Corporation or contributors be liable for any direct,
-// indirect, incidental, special, exemplary, or consequential damages
-// (including, but not limited to, procurement of substitute goods or services;
-// loss of use, data, or profits; or business interruption) however caused
-// and on any theory of liability, whether in contract, strict liability,
-// or tort (including negligence or otherwise) arising in any way out of
-// the use of this software, even if advised of the possibility of such damage.
-//
-//M*/
-
-
-#ifndef _OPENCV_JPEG_EXIF_HPP_
-#define _OPENCV_JPEG_EXIF_HPP_
-
-#include <cstdio>
-#include <map>
-#include <utility>
-#include <algorithm>
-#include <stdint.h>
-#include <string>
-#include <vector>
-
-namespace cv
-{
-/**
- * @brief Jpeg markers that can encounter in Jpeg file
- */
-enum AppMarkerTypes
-{
-    SOI   = 0xD8, SOF0  = 0xC0, SOF2  = 0xC2, DHT   = 0xC4,
-    DQT   = 0xDB, DRI   = 0xDD, SOS   = 0xDA,
-
-    RST0  = 0xD0, RST1  = 0xD1, RST2  = 0xD2, RST3  = 0xD3,
-    RST4  = 0xD4, RST5  = 0xD5, RST6  = 0xD6, RST7  = 0xD7,
-
-    APP0  = 0xE0, APP1  = 0xE1, APP2  = 0xE2, APP3  = 0xE3,
-    APP4  = 0xE4, APP5  = 0xE5, APP6  = 0xE6, APP7  = 0xE7,
-    APP8  = 0xE8, APP9  = 0xE9, APP10 = 0xEA, APP11 = 0xEB,
-    APP12 = 0xEC, APP13 = 0xED, APP14 = 0xEE, APP15 = 0xEF,
-
-    COM   = 0xFE, EOI   = 0xD9
-};
-
-/**
- * @brief Base Exif tags used by IFD0 (main image)
- */
-enum ExifTagName
-{
-    IMAGE_DESCRIPTION       = 0x010E,   ///< Image Description: ASCII string
-    MAKE                    = 0x010F,   ///< Description of manufacturer: ASCII string
-    MODEL                   = 0x0110,   ///< Description of camera model: ASCII string
-    ORIENTATION             = 0x0112,   ///< Orientation of the image: unsigned short
-    XRESOLUTION             = 0x011A,   ///< Resolution of the image across X axis: unsigned rational
-    YRESOLUTION             = 0x011B,   ///< Resolution of the image across Y axis: unsigned rational
-    RESOLUTION_UNIT         = 0x0128,   ///< Resolution units. '1' no-unit, '2' inch, '3' centimeter
-    SOFTWARE                = 0x0131,   ///< Shows firmware(internal software of digicam) version number
-    DATE_TIME               = 0x0132,   ///< Date/Time of image was last modified
-    WHITE_POINT             = 0x013E,   ///< Chromaticity of white point of the image
-    PRIMARY_CHROMATICIES    = 0x013F,   ///< Chromaticity of the primaries of the image
-    Y_CB_CR_COEFFICIENTS    = 0x0211,   ///< constant to translate an image from YCbCr to RGB format
-    Y_CB_CR_POSITIONING     = 0x0213,   ///< Chroma sample point of subsampling pixel array
-    REFERENCE_BLACK_WHITE   = 0x0214,   ///< Reference value of black point/white point
-    COPYRIGHT               = 0x8298,   ///< Copyright information
-    EXIF_OFFSET             = 0x8769,   ///< Offset to Exif Sub IFD
-    INVALID_TAG             = 0xFFFF    ///< Shows that the tag was not recognized
-};
-
-enum Endianess_t
-{
-    INTEL = 0x49,
-    MOTO = 0x4D,
-    NONE = 0x00
-};
-
-typedef std::pair<uint32_t, uint32_t> u_rational_t;
-
-/**
- * @brief Entry which contains possible values for different exif tags
- */
-struct ExifEntry_t
-{
-    ExifEntry_t();
-
-    std::vector<u_rational_t> field_u_rational; ///< vector of rational fields
-    std::string field_str;                      ///< any kind of textual information
-
-    float  field_float;                         ///< Currently is not used
-    double field_double;                        ///< Currently is not used
-
-    uint32_t field_u32;                         ///< Unsigned 32-bit value
-    int32_t  field_s32;                         ///< Signed 32-bit value
-
-    uint16_t tag;                               ///< Tag number
-
-    uint16_t field_u16;                         ///< Unsigned 16-bit value
-    int16_t  field_s16;                         ///< Signed 16-bit value
-    uint8_t  field_u8;                          ///< Unsigned 8-bit value
-    int8_t   field_s8;                          ///< Signed 8-bit value
-};
-
-/**
- * @brief Picture orientation which may be taken from JPEG's EXIF
- *      Orientation usually matters when the picture is taken by
- *      smartphone or other camera with orientation sensor support
- *      Corresponds to EXIF 2.3 Specification
- */
-enum JpegOrientation
-{
-    JPEG_ORIENTATION_TL = 1, ///< 0th row == visual top, 0th column == visual left-hand side
-    JPEG_ORIENTATION_TR = 2, ///< 0th row == visual top, 0th column == visual right-hand side
-    JPEG_ORIENTATION_BR = 3, ///< 0th row == visual bottom, 0th column == visual right-hand side
-    JPEG_ORIENTATION_BL = 4, ///< 0th row == visual bottom, 0th column == visual left-hand side
-    JPEG_ORIENTATION_LT = 5, ///< 0th row == visual left-hand side, 0th column == visual top
-    JPEG_ORIENTATION_RT = 6, ///< 0th row == visual right-hand side, 0th column == visual top
-    JPEG_ORIENTATION_RB = 7, ///< 0th row == visual right-hand side, 0th column == visual bottom
-    JPEG_ORIENTATION_LB = 8  ///< 0th row == visual left-hand side, 0th column == visual bottom
-};
-
-/**
- * @brief Reading exif information from Jpeg file
- *
- * Usage example for getting the orientation of the image:
- *
- *      @code
- *      ExifReader reader(fileName);
- *      if( reader.parse() )
- *      {
- *          int orientation = reader.getTag(Orientation).field_u16;
- *      }
- *      @endcode
- *
- */
-class ExifReader
-{
-public:
-    /**
-     * @brief ExifReader constructor. Constructs an object of exif reader
-     *
-     * @param [in]filename The name of file to look exif info in
-     */
-    explicit ExifReader( std::string filename );
-    ~ExifReader();
-
-
-    /**
-     * @brief Parse the file with exif info
-     *
-     * @return true if parsing was successful and exif information exists in JpegReader object
-     */
-    bool parse();
-
-    /**
-     * @brief Get tag info by tag number
-     *
-     * @param [in] tag The tag number
-     * @return ExifEntru_t structure. Caller has to know what tag it calls in order to extract proper field from the structure ExifEntry_t
-     */
-    ExifEntry_t getTag( const ExifTagName tag );
-
-private:
-    std::string m_filename;
-    std::vector<unsigned char> m_data;
-    std::map<int, ExifEntry_t > m_exif;
-    Endianess_t m_format;
-
-    void parseExif();
-    bool checkTagMark() const;
-
-    size_t getFieldSize ( FILE* f ) const;
-    size_t getNumDirEntry() const;
-    uint32_t getStartOffset() const;
-    uint16_t getExifTag( const size_t offset ) const;
-    uint16_t getU16( const size_t offset ) const;
-    uint32_t getU32( const size_t offset ) const;
-    uint16_t getOrientation( const size_t offset ) const;
-    uint16_t getResolutionUnit( const size_t offset ) const;
-    uint16_t getYCbCrPos( const size_t offset ) const;
-
-    Endianess_t getFormat() const;
-
-    ExifEntry_t parseExifEntry( const size_t offset );
-
-    u_rational_t getURational( const size_t offset ) const;
-
-    std::map<int, ExifEntry_t > getExif();
-    std::string getString( const size_t offset ) const;
-    std::vector<u_rational_t> getResolution( const size_t offset ) const;
-    std::vector<u_rational_t> getWhitePoint( const size_t offset ) const;
-    std::vector<u_rational_t> getPrimaryChromaticies( const size_t offset ) const;
-    std::vector<u_rational_t> getYCbCrCoeffs( const size_t offset ) const;
-    std::vector<u_rational_t> getRefBW( const size_t offset ) const;
-
-private:
-    static const uint16_t tagMarkRequired = 0x2A;
-
-    //offset to the _number-of-directory-entry_ field
-    static const size_t offsetNumDir = 8;
-
-    //max size of data in tag.
-    //'DDDDDDDD' contains the value of that Tag. If its size is over 4bytes,
-    //'DDDDDDDD' contains the offset to data stored address.
-    static const size_t maxDataSize = 4;
-
-    //bytes per tag field
-    static const size_t tiffFieldSize = 12;
-
-    //number of primary chromaticies components
-    static const size_t primaryChromaticiesComponents = 6;
-
-    //number of YCbCr coefficients in field
-    static const size_t ycbcrCoeffs = 3;
-
-    //number of Reference Black&White components
-    static const size_t refBWComponents = 6;
-};
-
-
-
-}
-
-#endif /* JPEG_EXIF_HPP_ */
diff --git a/modules/imgcodecs/src/loadsave.cpp b/modules/imgcodecs/src/loadsave.cpp
index 70a31c3..493ccab 100644
--- a/modules/imgcodecs/src/loadsave.cpp
+++ b/modules/imgcodecs/src/loadsave.cpp
@@ -45,6 +45,8 @@
 
 #include "precomp.hpp"
 #include "grfmts.hpp"
+#include "utils.hpp"
+#include "exif.hpp"
 #undef min
 #undef max
 #include <iostream>
@@ -93,6 +95,9 @@ struct ImageCodecInitializer
         decoders.push_back( makePtr<PngDecoder>() );
         encoders.push_back( makePtr<PngEncoder>() );
     #endif
+    #ifdef HAVE_GDCM
+        decoders.push_back( makePtr<DICOMDecoder>() );
+    #endif
     #ifdef HAVE_JASPER
         decoders.push_back( makePtr<Jpeg2KDecoder>() );
         encoders.push_back( makePtr<Jpeg2KEncoder>() );
@@ -106,6 +111,8 @@ struct ImageCodecInitializer
         /// Attach the GDAL Decoder
         decoders.push_back( makePtr<GdalDecoder>() );
     #endif/*HAVE_GDAL*/
+        decoders.push_back( makePtr<PAMDecoder>() );
+        encoders.push_back( makePtr<PAMEncoder>() );
     }
 
     std::vector<ImageDecoder> decoders;
@@ -222,8 +229,61 @@ static ImageEncoder findEncoder( const String& _ext )
     return ImageEncoder();
 }
 
+
 enum { LOAD_CVMAT=0, LOAD_IMAGE=1, LOAD_MAT=2 };
 
+static void ApplyExifOrientation(const String& filename, Mat& img)
+{
+    int orientation = IMAGE_ORIENTATION_TL;
+
+    if (filename.size() > 0)
+    {
+        ExifReader reader( filename );
+        if( reader.parse() )
+        {
+            ExifEntry_t entry = reader.getTag( ORIENTATION );
+            if (entry.tag != INVALID_TAG)
+            {
+                orientation = entry.field_u16; //orientation is unsigned short, so check field_u16
+            }
+        }
+    }
+
+    switch( orientation )
+    {
+        case    IMAGE_ORIENTATION_TL: //0th row == visual top, 0th column == visual left-hand side
+            //do nothing, the image already has proper orientation
+            break;
+        case    IMAGE_ORIENTATION_TR: //0th row == visual top, 0th column == visual right-hand side
+            flip(img, img, 1); //flip horizontally
+            break;
+        case    IMAGE_ORIENTATION_BR: //0th row == visual bottom, 0th column == visual right-hand side
+            flip(img, img, -1);//flip both horizontally and vertically
+            break;
+        case    IMAGE_ORIENTATION_BL: //0th row == visual bottom, 0th column == visual left-hand side
+            flip(img, img, 0); //flip vertically
+            break;
+        case    IMAGE_ORIENTATION_LT: //0th row == visual left-hand side, 0th column == visual top
+            transpose(img, img);
+            break;
+        case    IMAGE_ORIENTATION_RT: //0th row == visual right-hand side, 0th column == visual top
+            transpose(img, img);
+            flip(img, img, 1); //flip horizontally
+            break;
+        case    IMAGE_ORIENTATION_RB: //0th row == visual right-hand side, 0th column == visual bottom
+            transpose(img, img);
+            flip(img, img, -1); //flip both horizontally and vertically
+            break;
+        case    IMAGE_ORIENTATION_LB: //0th row == visual left-hand side, 0th column == visual bottom
+            transpose(img, img);
+            flip(img, img, 0); //flip vertically
+            break;
+        default:
+            //by default the image read has normal (JPEG_ORIENTATION_TL) orientation
+            break;
+    }
+}
+
 /**
  * Read an image into memory and return the information
  *
@@ -398,6 +458,12 @@ imreadmulti_(const String& filename, int flags, std::vector<Mat>& mats)
         Mat mat(decoder->height(), decoder->width(), type);
         if (!decoder->readData(mat))
         {
+            // optionally rotate the data if EXIF' orientation flag says so
+            if( (flags & IMREAD_IGNORE_ORIENTATION) == 0 && flags != IMREAD_UNCHANGED )
+            {
+                ApplyExifOrientation(filename, mat);
+            }
+
             break;
         }
 
@@ -427,6 +493,12 @@ Mat imread( const String& filename, int flags )
     /// load the data
     imread_( filename, flags, LOAD_MAT, &img );
 
+    /// optionally rotate the data if EXIF' orientation flag says so
+    if( (flags & IMREAD_IGNORE_ORIENTATION) == 0 && flags != IMREAD_UNCHANGED )
+    {
+        ApplyExifOrientation(filename, img);
+    }
+
     /// return a reference to the data
     return img;
 }
@@ -511,8 +583,14 @@ imdecode_( const Mat& buf, int flags, int hdrtype, Mat* mat=0 )
 
     if( !decoder->readHeader() )
     {
-        if( !filename.empty() )
-            remove(filename.c_str());
+        decoder.release();
+        if ( !filename.empty() )
+        {
+            if ( remove(filename.c_str()) != 0 )
+            {
+                CV_Error( CV_StsError, "unable to remove temporary file" );
+            }
+        }
         return 0;
     }
 
@@ -553,8 +631,14 @@ imdecode_( const Mat& buf, int flags, int hdrtype, Mat* mat=0 )
     }
 
     bool code = decoder->readData( *data );
-    if( !filename.empty() )
-        remove(filename.c_str());
+    decoder.release();
+    if ( !filename.empty() )
+    {
+        if ( remove(filename.c_str()) != 0 )
+        {
+            CV_Error( CV_StsError, "unable to remove temporary file" );
+        }
+    }
 
     if( !code )
     {
diff --git a/modules/imgcodecs/src/precomp.hpp b/modules/imgcodecs/src/precomp.hpp
index 101f015..6a16ca8 100644
--- a/modules/imgcodecs/src/precomp.hpp
+++ b/modules/imgcodecs/src/precomp.hpp
@@ -59,14 +59,6 @@
 #include <assert.h>
 
 #if defined WIN32 || defined WINCE
-    #if !defined _WIN32_WINNT
-        #ifdef HAVE_MSMF
-            #define _WIN32_WINNT 0x0600 // Windows Vista
-        #else
-            #define _WIN32_WINNT 0x0500 // Windows 2000
-        #endif
-    #endif
-
     #include <windows.h>
     #undef small
     #undef min
diff --git a/modules/imgcodecs/src/rgbe.cpp b/modules/imgcodecs/src/rgbe.cpp
index 3400849..1e51cfb 100644
--- a/modules/imgcodecs/src/rgbe.cpp
+++ b/modules/imgcodecs/src/rgbe.cpp
@@ -43,9 +43,7 @@
 #include "precomp.hpp"
 #include "rgbe.hpp"
 #include <math.h>
-#if !defined(__APPLE__)
-#include <malloc.h>
-#endif
+#include <stdlib.h>
 #include <string.h>
 #include <ctype.h>
 
diff --git a/modules/imgcodecs/test/test_drawing.cpp b/modules/imgcodecs/test/test_drawing.cpp
deleted file mode 100644
index d6d7682..0000000
--- a/modules/imgcodecs/test/test_drawing.cpp
+++ /dev/null
@@ -1,528 +0,0 @@
-/*M///////////////////////////////////////////////////////////////////////////////////////
-//
-//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
-//
-//  By downloading, copying, installing or using the software you agree to this license.
-//  If you do not agree to this license, do not download, install,
-//  copy or use the software.
-//
-//
-//                          License Agreement
-//                For Open Source Computer Vision Library
-//
-// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
-// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
-// Third party copyrights are property of their respective owners.
-//
-// Redistribution and use in source and binary forms, with or without modification,
-// are permitted provided that the following conditions are met:
-//
-//   * Redistribution's of source code must retain the above copyright notice,
-//     this list of conditions and the following disclaimer.
-//
-//   * Redistribution's in binary form must reproduce the above copyright notice,
-//     this list of conditions and the following disclaimer in the documentation
-//     and/or other materials provided with the distribution.
-//
-//   * The name of the copyright holders may not be used to endorse or promote products
-//     derived from this software without specific prior written permission.
-//
-// This software is provided by the copyright holders and contributors "as is" and
-// any express or implied warranties, including, but not limited to, the implied
-// warranties of merchantability and fitness for a particular purpose are disclaimed.
-// In no event shall the Intel Corporation or contributors be liable for any direct,
-// indirect, incidental, special, exemplary, or consequential damages
-// (including, but not limited to, procurement of substitute goods or services;
-// loss of use, data, or profits; or business interruption) however caused
-// and on any theory of liability, whether in contract, strict liability,
-// or tort (including negligence or otherwise) arising in any way out of
-// the use of this software, even if advised of the possibility of such damage.
-//
-//M*/
-
-#include "test_precomp.hpp"
-
-using namespace std;
-using namespace cv;
-
-//#define DRAW_TEST_IMAGE
-
-class CV_DrawingTest : public cvtest::BaseTest
-{
-public:
-    CV_DrawingTest(){}
-protected:
-    void run( int );
-    virtual void draw( Mat& img ) = 0;
-    virtual int checkLineIterator( Mat& img) = 0;
-};
-
-void CV_DrawingTest::run( int )
-{
-    Mat testImg, valImg;
-    const string fname = "drawing/image.png";
-    string path = ts->get_data_path(), filename;
-    filename = path + fname;
-
-    draw( testImg );
-
-    valImg = imread( filename );
-    if( valImg.empty() )
-    {
-        imwrite( filename, testImg );
-        //ts->printf( ts->LOG, "test image can not be read");
-        //ts->set_failed_test_info(cvtest::TS::FAIL_INVALID_TEST_DATA);
-    }
-    else
-    {
-        // image should match exactly
-        float err = (float)cvtest::norm( testImg, valImg, NORM_L1 );
-        float Eps = 1;
-        if( err > Eps)
-        {
-            ts->printf( ts->LOG, "NORM_L1 between testImg and valImg is equal %f (larger than %f)\n", err, Eps );
-            ts->set_failed_test_info(cvtest::TS::FAIL_BAD_ACCURACY);
-        }
-        else
-        {
-            ts->set_failed_test_info(checkLineIterator( testImg ));
-        }
-    }
-    ts->set_failed_test_info(cvtest::TS::OK);
-}
-
-class CV_DrawingTest_CPP : public CV_DrawingTest
-{
-public:
-    CV_DrawingTest_CPP() {}
-protected:
-    virtual void draw( Mat& img );
-    virtual int checkLineIterator( Mat& img);
-};
-
-void CV_DrawingTest_CPP::draw( Mat& img )
-{
-    Size imgSize( 600, 400 );
-    img.create( imgSize, CV_8UC3 );
-
-    vector<Point> polyline(4);
-    polyline[0] = Point(0, 0);
-    polyline[1] = Point(imgSize.width, 0);
-    polyline[2] = Point(imgSize.width, imgSize.height);
-    polyline[3] = Point(0, imgSize.height);
-    const Point* pts = &polyline[0];
-    int n = (int)polyline.size();
-    fillPoly( img, &pts, &n, 1, Scalar::all(255) );
-
-    Point p1(1,1), p2(3,3);
-    if( clipLine(Rect(0,0,imgSize.width,imgSize.height), p1, p2) && clipLine(imgSize, p1, p2) )
-        circle( img, Point(300,100), 40, Scalar(0,0,255), 3 ); // draw
-
-    p2 = Point(3,imgSize.height+1000);
-    if( clipLine(Rect(0,0,imgSize.width,imgSize.height), p1, p2) && clipLine(imgSize, p1, p2) )
-        circle( img, Point(500,300), 50, cvColorToScalar(255,CV_8UC3), 5, 8, 1 ); // draw
-
-    p1 = Point(imgSize.width,1), p2 = Point(imgSize.width,3);
-    if( clipLine(Rect(0,0,imgSize.width,imgSize.height), p1, p2) && clipLine(imgSize, p1, p2) )
-        circle( img, Point(390,100), 10, Scalar(0,0,255), 3 ); // not draw
-
-    p1 = Point(imgSize.width-1,1), p2 = Point(imgSize.width,3);
-    if( clipLine(Rect(0,0,imgSize.width,imgSize.height), p1, p2) && clipLine(imgSize, p1, p2) )
-        ellipse( img, Point(390,100), Size(20,30), 60, 0, 220.0, Scalar(0,200,0), 4 ); //draw
-
-    ellipse( img, RotatedRect(Point(100,200),Size(200,100),160), Scalar(200,200,255), 5 );
-
-    polyline.clear();
-    ellipse2Poly( Point(430,180), Size(100,150), 30, 0, 150, 20, polyline );
-    pts = &polyline[0];
-    n = (int)polyline.size();
-    polylines( img, &pts, &n, 1, false, Scalar(0,0,150), 4, CV_AA );
-    n = 0;
-    for( vector<Point>::const_iterator it = polyline.begin(); n < (int)polyline.size()-1; ++it, n++ )
-    {
-        line( img, *it, *(it+1), Scalar(50,250,100));
-    }
-
-    polyline.clear();
-    ellipse2Poly( Point(500,300), Size(50,80), 0, 0, 180, 10, polyline );
-    pts = &polyline[0];
-    n = (int)polyline.size();
-    polylines( img, &pts, &n, 1, true, Scalar(100,200,100), 20 );
-    fillConvexPoly( img, pts, n, Scalar(0, 80, 0) );
-
-    polyline.resize(8);
-    // external rectengular
-    polyline[0] = Point(0, 0);
-    polyline[1] = Point(80, 0);
-    polyline[2] = Point(80, 80);
-    polyline[3] = Point(0, 80);
-    // internal rectangular
-    polyline[4] = Point(20, 20);
-    polyline[5] = Point(60, 20);
-    polyline[6] = Point(60, 60);
-    polyline[7] = Point(20, 60);
-    const Point* ppts[] = {&polyline[0], &polyline[0]+4};
-    int pn[] = {4, 4};
-    fillPoly( img, ppts, pn, 2, Scalar(100, 100, 0), 8, 0, Point(500, 20) );
-
-    rectangle( img, Point(0, 300), Point(50, 398), Scalar(0,0,255) );
-
-    string text1 = "OpenCV";
-    int baseline = 0, thickness = 3, fontFace = FONT_HERSHEY_SCRIPT_SIMPLEX;
-    float fontScale = 2;
-    Size textSize = getTextSize( text1, fontFace, fontScale, thickness, &baseline);
-    baseline += thickness;
-    Point textOrg((img.cols - textSize.width)/2, (img.rows + textSize.height)/2);
-    rectangle(img, textOrg + Point(0, baseline), textOrg + Point(textSize.width, -textSize.height), Scalar(0,0,255));
-    line(img, textOrg + Point(0, thickness), textOrg + Point(textSize.width, thickness), Scalar(0, 0, 255));
-    putText(img, text1, textOrg, fontFace, fontScale, Scalar(150,0,150), thickness, 8);
-
-    string text2 = "abcdefghijklmnopqrstuvwxyz1234567890";
-    Scalar color(200,0,0);
-    fontScale = 0.5, thickness = 1;
-    int dist = 5;
-
-    textSize = getTextSize( text2, FONT_HERSHEY_SIMPLEX, fontScale, thickness, &baseline);
-    textOrg = Point(5,5)+Point(0,textSize.height+dist);
-    putText(img, text2, textOrg, FONT_HERSHEY_SIMPLEX, fontScale, color, thickness, CV_AA);
-
-    fontScale = 1;
-    textSize = getTextSize( text2, FONT_HERSHEY_PLAIN, fontScale, thickness, &baseline);
-    textOrg += Point(0,textSize.height+dist);
-    putText(img, text2, textOrg, FONT_HERSHEY_PLAIN, fontScale, color, thickness, CV_AA);
-
-    fontScale = 0.5;
-    textSize = getTextSize( text2, FONT_HERSHEY_DUPLEX, fontScale, thickness, &baseline);
-    textOrg += Point(0,textSize.height+dist);
-    putText(img, text2, textOrg, FONT_HERSHEY_DUPLEX, fontScale, color, thickness, CV_AA);
-
-    textSize = getTextSize( text2, FONT_HERSHEY_COMPLEX, fontScale, thickness, &baseline);
-    textOrg += Point(0,textSize.height+dist);
-    putText(img, text2, textOrg, FONT_HERSHEY_COMPLEX, fontScale, color, thickness, CV_AA);
-
-    textSize = getTextSize( text2, FONT_HERSHEY_TRIPLEX, fontScale, thickness, &baseline);
-    textOrg += Point(0,textSize.height+dist);
-    putText(img, text2, textOrg, FONT_HERSHEY_TRIPLEX, fontScale, color, thickness, CV_AA);
-
-    fontScale = 1;
-    textSize = getTextSize( text2, FONT_HERSHEY_COMPLEX_SMALL, fontScale, thickness, &baseline);
-    textOrg += Point(0,180) + Point(0,textSize.height+dist);
-    putText(img, text2, textOrg, FONT_HERSHEY_COMPLEX_SMALL, fontScale, color, thickness, CV_AA);
-
-    textSize = getTextSize( text2, FONT_HERSHEY_SCRIPT_SIMPLEX, fontScale, thickness, &baseline);
-    textOrg += Point(0,textSize.height+dist);
-    putText(img, text2, textOrg, FONT_HERSHEY_SCRIPT_SIMPLEX, fontScale, color, thickness, CV_AA);
-
-    textSize = getTextSize( text2, FONT_HERSHEY_SCRIPT_COMPLEX, fontScale, thickness, &baseline);
-    textOrg += Point(0,textSize.height+dist);
-    putText(img, text2, textOrg, FONT_HERSHEY_SCRIPT_COMPLEX, fontScale, color, thickness, CV_AA);
-
-    dist = 15, fontScale = 0.5;
-    textSize = getTextSize( text2, FONT_ITALIC, fontScale, thickness, &baseline);
-    textOrg += Point(0,textSize.height+dist);
-    putText(img, text2, textOrg, FONT_ITALIC, fontScale, color, thickness, CV_AA);
-}
-
-int CV_DrawingTest_CPP::checkLineIterator( Mat& img )
-{
-    LineIterator it( img, Point(0,300), Point(1000, 300) );
-    for(int i = 0; i < it.count; ++it, i++ )
-    {
-        Vec3b v = (Vec3b)(*(*it)) - img.at<Vec3b>(300,i);
-        float err = (float)cvtest::norm( v, NORM_L2 );
-        if( err != 0 )
-        {
-            ts->printf( ts->LOG, "LineIterator works incorrect" );
-            ts->set_failed_test_info(cvtest::TS::FAIL_INVALID_OUTPUT);
-        }
-    }
-    ts->set_failed_test_info(cvtest::TS::OK);
-    return 0;
-}
-
-class CV_DrawingTest_C : public CV_DrawingTest
-{
-public:
-    CV_DrawingTest_C() {}
-protected:
-    virtual void draw( Mat& img );
-    virtual int checkLineIterator( Mat& img);
-};
-
-void CV_DrawingTest_C::draw( Mat& _img )
-{
-    CvSize imgSize = cvSize(600, 400);
-    _img.create( imgSize, CV_8UC3 );
-    CvMat img = _img;
-
-    vector<CvPoint> polyline(4);
-    polyline[0] = cvPoint(0, 0);
-    polyline[1] = cvPoint(imgSize.width, 0);
-    polyline[2] = cvPoint(imgSize.width, imgSize.height);
-    polyline[3] = cvPoint(0, imgSize.height);
-    CvPoint* pts = &polyline[0];
-    int n = (int)polyline.size();
-    int actualSize = 0;
-    cvFillPoly( &img, &pts, &n, 1, cvScalar(255,255,255) );
-
-    CvPoint p1 = cvPoint(1,1), p2 = cvPoint(3,3);
-    if( cvClipLine(imgSize, &p1, &p2) )
-        cvCircle( &img, cvPoint(300,100), 40, cvScalar(0,0,255), 3 ); // draw
-
-    p1 = cvPoint(1,1), p2 = cvPoint(3,imgSize.height+1000);
-    if( cvClipLine(imgSize, &p1, &p2) )
-        cvCircle( &img, cvPoint(500,300), 50, cvScalar(255,0,0), 5, 8, 1 ); // draw
-
-    p1 = cvPoint(imgSize.width,1), p2 = cvPoint(imgSize.width,3);
-    if( cvClipLine(imgSize, &p1, &p2) )
-        cvCircle( &img, cvPoint(390,100), 10, cvScalar(0,0,255), 3 ); // not draw
-
-    p1 = Point(imgSize.width-1,1), p2 = Point(imgSize.width,3);
-    if( cvClipLine(imgSize, &p1, &p2) )
-        cvEllipse( &img, cvPoint(390,100), cvSize(20,30), 60, 0, 220.0, cvScalar(0,200,0), 4 ); //draw
-
-    CvBox2D box;
-    box.center.x = 100;
-    box.center.y = 200;
-    box.size.width = 200;
-    box.size.height = 100;
-    box.angle = 160;
-    cvEllipseBox( &img, box, Scalar(200,200,255), 5 );
-
-    polyline.resize(9);
-    pts = &polyline[0];
-    n = (int)polyline.size();
-    actualSize = cvEllipse2Poly( cvPoint(430,180), cvSize(100,150), 30, 0, 150, &polyline[0], 20 );
-    CV_Assert(actualSize == n);
-    cvPolyLine( &img, &pts, &n, 1, false, cvScalar(0,0,150), 4, CV_AA );
-    n = 0;
-    for( vector<CvPoint>::const_iterator it = polyline.begin(); n < (int)polyline.size()-1; ++it, n++ )
-    {
-        cvLine( &img, *it, *(it+1), cvScalar(50,250,100) );
-    }
-
-    polyline.resize(19);
-    pts = &polyline[0];
-    n = (int)polyline.size();
-    actualSize = cvEllipse2Poly( cvPoint(500,300), cvSize(50,80), 0, 0, 180, &polyline[0], 10 );
-    CV_Assert(actualSize == n);
-    cvPolyLine( &img, &pts, &n, 1, true, Scalar(100,200,100), 20 );
-    cvFillConvexPoly( &img, pts, n, cvScalar(0, 80, 0) );
-
-    polyline.resize(8);
-    // external rectengular
-    polyline[0] = cvPoint(500, 20);
-    polyline[1] = cvPoint(580, 20);
-    polyline[2] = cvPoint(580, 100);
-    polyline[3] = cvPoint(500, 100);
-    // internal rectangular
-    polyline[4] = cvPoint(520, 40);
-    polyline[5] = cvPoint(560, 40);
-    polyline[6] = cvPoint(560, 80);
-    polyline[7] = cvPoint(520, 80);
-    CvPoint* ppts[] = {&polyline[0], &polyline[0]+4};
-    int pn[] = {4, 4};
-    cvFillPoly( &img, ppts, pn, 2, cvScalar(100, 100, 0), 8, 0 );
-
-    cvRectangle( &img, cvPoint(0, 300), cvPoint(50, 398), cvScalar(0,0,255) );
-
-    string text1 = "OpenCV";
-    CvFont font;
-    cvInitFont( &font, FONT_HERSHEY_SCRIPT_SIMPLEX, 2, 2, 0, 3 );
-    int baseline = 0;
-    CvSize textSize;
-    cvGetTextSize( text1.c_str(), &font, &textSize, &baseline );
-    baseline += font.thickness;
-    CvPoint textOrg = cvPoint((imgSize.width - textSize.width)/2, (imgSize.height + textSize.height)/2);
-    cvRectangle( &img, cvPoint( textOrg.x, textOrg.y + baseline),
-                 cvPoint(textOrg.x + textSize.width, textOrg.y - textSize.height), cvScalar(0,0,255));
-    cvLine( &img, cvPoint(textOrg.x, textOrg.y + font.thickness),
-            cvPoint(textOrg.x + textSize.width, textOrg.y + font.thickness), cvScalar(0, 0, 255));
-    cvPutText( &img, text1.c_str(), textOrg, &font, cvScalar(150,0,150) );
-
-    int dist = 5;
-    string text2 = "abcdefghijklmnopqrstuvwxyz1234567890";
-    CvScalar color = cvScalar(200,0,0);
-    cvInitFont( &font, FONT_HERSHEY_SIMPLEX, 0.5, 0.5, 0, 1, CV_AA );
-    cvGetTextSize( text2.c_str(), &font, &textSize, &baseline );
-    textOrg = cvPoint(5, 5+textSize.height+dist);
-    cvPutText(&img, text2.c_str(), textOrg, &font, color );
-
-    cvInitFont( &font, FONT_HERSHEY_PLAIN, 1, 1, 0, 1, CV_AA );
-    cvGetTextSize( text2.c_str(), &font, &textSize, &baseline );
-    textOrg = cvPoint(textOrg.x,textOrg.y+textSize.height+dist);
-    cvPutText(&img, text2.c_str(), textOrg, &font, color );
-
-    cvInitFont( &font, FONT_HERSHEY_DUPLEX, 0.5, 0.5, 0, 1, CV_AA );
-    cvGetTextSize( text2.c_str(), &font, &textSize, &baseline );
-    textOrg = cvPoint(textOrg.x,textOrg.y+textSize.height+dist);
-    cvPutText(&img, text2.c_str(), textOrg, &font, color );
-
-    cvInitFont( &font, FONT_HERSHEY_COMPLEX, 0.5, 0.5, 0, 1, CV_AA );
-    cvGetTextSize( text2.c_str(), &font, &textSize, &baseline );
-    textOrg = cvPoint(textOrg.x,textOrg.y+textSize.height+dist);
-    cvPutText(&img, text2.c_str(), textOrg, &font, color );
-
-    cvInitFont( &font, FONT_HERSHEY_TRIPLEX, 0.5, 0.5, 0, 1, CV_AA );
-    cvGetTextSize( text2.c_str(), &font, &textSize, &baseline );
-    textOrg = cvPoint(textOrg.x,textOrg.y+textSize.height+dist);
-    cvPutText(&img, text2.c_str(), textOrg, &font, color );
-
-    cvInitFont( &font, FONT_HERSHEY_COMPLEX_SMALL, 1, 1, 0, 1, CV_AA );
-    cvGetTextSize( text2.c_str(), &font, &textSize, &baseline );
-    textOrg = cvPoint(textOrg.x,textOrg.y+textSize.height+dist + 180);
-    cvPutText(&img, text2.c_str(), textOrg, &font, color );
-
-    cvInitFont( &font, FONT_HERSHEY_SCRIPT_SIMPLEX, 1, 1, 0, 1, CV_AA );
-    cvGetTextSize( text2.c_str(), &font, &textSize, &baseline );
-    textOrg = cvPoint(textOrg.x,textOrg.y+textSize.height+dist);
-    cvPutText(&img, text2.c_str(), textOrg, &font, color );
-
-    cvInitFont( &font, FONT_HERSHEY_SCRIPT_COMPLEX, 1, 1, 0, 1, CV_AA );
-    cvGetTextSize( text2.c_str(), &font, &textSize, &baseline );
-    textOrg = cvPoint(textOrg.x,textOrg.y+textSize.height+dist);
-    cvPutText(&img, text2.c_str(), textOrg, &font, color );
-
-    dist = 15;
-    cvInitFont( &font, FONT_ITALIC, 0.5, 0.5, 0, 1, CV_AA );
-    cvGetTextSize( text2.c_str(), &font, &textSize, &baseline );
-    textOrg = cvPoint(textOrg.x,textOrg.y+textSize.height+dist);
-    cvPutText(&img, text2.c_str(), textOrg, &font, color );
-}
-
-int CV_DrawingTest_C::checkLineIterator( Mat& _img )
-{
-    CvLineIterator it;
-    CvMat img = _img;
-    int count = cvInitLineIterator( &img, cvPoint(0,300), cvPoint(1000, 300), &it );
-    for(int i = 0; i < count; i++ )
-    {
-        Vec3b v = (Vec3b)(*(it.ptr)) - _img.at<Vec3b>(300,i);
-        float err = (float)cvtest::norm( v, NORM_L2 );
-        if( err != 0 )
-        {
-            ts->printf( ts->LOG, "CvLineIterator works incorrect" );
-            ts->set_failed_test_info(cvtest::TS::FAIL_INVALID_OUTPUT);
-        }
-        CV_NEXT_LINE_POINT(it);
-    }
-    ts->set_failed_test_info(cvtest::TS::OK);
-    return 0;
-}
-
-#ifdef HAVE_JPEG
-TEST(Imgcodecs_Drawing,    cpp_regression) { CV_DrawingTest_CPP test; test.safe_run(); }
-TEST(Imgcodecs_Drawing,      c_regression) { CV_DrawingTest_C   test; test.safe_run(); }
-#endif
-
-class CV_FillConvexPolyTest : public cvtest::BaseTest
-{
-public:
-    CV_FillConvexPolyTest() {}
-    ~CV_FillConvexPolyTest() {}
-protected:
-    void run(int)
-    {
-        vector<Point> line1;
-        vector<Point> line2;
-
-        line1.push_back(Point(1, 1));
-        line1.push_back(Point(5, 1));
-        line1.push_back(Point(5, 8));
-        line1.push_back(Point(1, 8));
-
-        line2.push_back(Point(2, 2));
-        line2.push_back(Point(10, 2));
-        line2.push_back(Point(10, 16));
-        line2.push_back(Point(2, 16));
-
-        Mat gray0(10,10,CV_8U, Scalar(0));
-        fillConvexPoly(gray0, line1, Scalar(255), 8, 0);
-        int nz1 = countNonZero(gray0);
-
-        fillConvexPoly(gray0, line2, Scalar(0), 8, 1);
-        int nz2 = countNonZero(gray0)/255;
-
-        CV_Assert( nz1 == 40 && nz2 == 0 );
-    }
-};
-
-TEST(Imgcodecs_Drawing, fillconvexpoly_clipping) { CV_FillConvexPolyTest test; test.safe_run(); }
-
-class CV_DrawingTest_UTF8 : public cvtest::BaseTest
-{
-public:
-    CV_DrawingTest_UTF8() {}
-    ~CV_DrawingTest_UTF8() {}
-protected:
-    void run(int)
-    {
-        vector<string> lines;
-        lines.push_back("abcdefghijklmnopqrstuvwxyz1234567890");
-        // cyrillic letters small
-        lines.push_back("\xD0\xB0\xD0\xB1\xD0\xB2\xD0\xB3\xD0\xB4\xD0\xB5\xD1\x91\xD0\xB6\xD0\xB7"
-                        "\xD0\xB8\xD0\xB9\xD0\xBA\xD0\xBB\xD0\xBC\xD0\xBD\xD0\xBE\xD0\xBF\xD1\x80"
-                        "\xD1\x81\xD1\x82\xD1\x83\xD1\x84\xD1\x85\xD1\x86\xD1\x87\xD1\x88\xD1\x89"
-                        "\xD1\x8A\xD1\x8B\xD1\x8C\xD1\x8D\xD1\x8E\xD1\x8F");
-        // cyrillic letters capital
-        lines.push_back("\xD0\x90\xD0\x91\xD0\x92\xD0\x93\xD0\x94\xD0\x95\xD0\x81\xD0\x96\xD0\x97"
-                        "\xD0\x98\xD0\x99\xD0\x9A\xD0\x9B\xD0\x9C\xD0\x9D\xD0\x9E\xD0\x9F\xD0\xA0"
-                        "\xD0\xA1\xD0\xA2\xD0\xA3\xD0\xA4\xD0\xA5\xD0\xA6\xD0\xA7\xD0\xA8\xD0\xA9"
-                        "\xD0\xAA\xD0\xAB\xD0\xAC\xD0\xAD\xD0\xAE\xD0\xAF");
-        // bounds
-        lines.push_back("-\xD0\x80-\xD0\x8E-\xD0\x8F-");
-        lines.push_back("-\xD1\x90-\xD1\x91-\xD1\xBF-");
-        // bad utf8
-        lines.push_back("-\x81-\x82-\x83-");
-        lines.push_back("--\xF0--");
-        lines.push_back("-\xF0");
-
-        vector<int> fonts;
-        fonts.push_back(FONT_HERSHEY_SIMPLEX);
-        fonts.push_back(FONT_HERSHEY_PLAIN);
-        fonts.push_back(FONT_HERSHEY_DUPLEX);
-        fonts.push_back(FONT_HERSHEY_COMPLEX);
-        fonts.push_back(FONT_HERSHEY_TRIPLEX);
-        fonts.push_back(FONT_HERSHEY_COMPLEX_SMALL);
-        fonts.push_back(FONT_HERSHEY_SCRIPT_SIMPLEX);
-        fonts.push_back(FONT_HERSHEY_SCRIPT_COMPLEX);
-
-        vector<Mat> results;
-        Size bigSize(0, 0);
-        for (vector<int>::const_iterator font = fonts.begin(); font != fonts.end(); ++font)
-        {
-            for (int italic = 0; italic <= FONT_ITALIC; italic += FONT_ITALIC)
-            {
-                for (vector<string>::const_iterator line = lines.begin(); line != lines.end(); ++line)
-                {
-                    const float fontScale = 1;
-                    const int thickness = 1;
-                    const Scalar color(20,20,20);
-                    int baseline = 0;
-
-                    Size textSize = getTextSize(*line, *font | italic, fontScale, thickness, &baseline);
-                    Point textOrg(0, textSize.height + 2);
-                    Mat img(textSize + Size(0, baseline), CV_8UC3, Scalar(255, 255, 255));
-                    putText(img, *line, textOrg, *font | italic, fontScale, color, thickness, CV_AA);
-
-                    results.push_back(img);
-                    bigSize.width = max(bigSize.width, img.size().width);
-                    bigSize.height += img.size().height + 1;
-                }
-            }
-        }
-
-        int shift = 0;
-        Mat result(bigSize, CV_8UC3, Scalar(100, 100, 100));
-        for (vector<Mat>::const_iterator img = results.begin(); img != results.end(); ++img)
-        {
-            Rect roi(Point(0, shift), img->size());
-            Mat sub(result, roi);
-            img->copyTo(sub);
-            shift += img->size().height + 1;
-        }
-        imwrite("/tmp/all_fonts.png", result);
-    }
-};
-
-TEST(Highgui_Drawing, utf8_support) { CV_DrawingTest_UTF8 test; test.safe_run(); }
diff --git a/modules/imgcodecs/test/test_grfmt.cpp b/modules/imgcodecs/test/test_grfmt.cpp
index f305ca1..faca3d7 100644
--- a/modules/imgcodecs/test/test_grfmt.cpp
+++ b/modules/imgcodecs/test/test_grfmt.cpp
@@ -44,6 +44,7 @@
 
 #include <fstream>
 #include <sstream>
+#include <iostream>
 
 using namespace cv;
 using namespace std;
@@ -93,6 +94,12 @@ TEST(Imgcodecs_imread, regression)
 #ifdef HAVE_JASPER
         "Rome.jp2",
 #endif
+#ifdef HAVE_GDCM
+        "int16-mono1.dcm",
+        "uint8-mono2.dcm",
+        "uint16-mono2.dcm",
+        "uint8-rgb.dcm",
+#endif
         "color_palette_alpha.png",
         "multipage.tif",
         "rle.hdr",
@@ -111,9 +118,10 @@ TEST(Imgcodecs_imread, regression)
         ASSERT_TRUE(imread_compare(path, IMREAD_COLOR));
         ASSERT_TRUE(imread_compare(path, IMREAD_ANYDEPTH));
         ASSERT_TRUE(imread_compare(path, IMREAD_ANYCOLOR));
-        if (path.substr(path.length() - 3) != "hdr")
+        const string ext = path.substr( path.length() - 3 );
+        if ( ext != "hdr" && ext != "dcm" )
         {
-            // GDAL does not support hdr
+            // GDAL does not support hdr nor dcm
             ASSERT_TRUE(imread_compare(path, IMREAD_LOAD_GDAL));
         }
     }
@@ -308,6 +316,7 @@ string ext_from_int(int ext)
 #ifdef HAVE_TIFF
     if (ext == 3) return ".tiff";
 #endif
+    if (ext == 4) return ".pam";
     return "";
 }
 
@@ -323,7 +332,7 @@ public:
 
             for (int k = 1; k <= 5; ++k)
             {
-                for (int ext = 0; ext < 4; ++ext) // 0 - png, 1 - bmp, 2 - pgm, 3 - tiff
+                for (int ext = 0; ext < 5; ++ext) // 0 - png, 1 - bmp, 2 - pgm, 3 - tiff
                 {
                     if(ext_from_int(ext).empty())
                         continue;
@@ -890,6 +899,19 @@ TEST(Imgcodecs_Tiff, decode_multipage)
     CV_GrfmtReadTifMultiPage test; test.safe_run();
 }
 
+TEST(Imgcodecs_Tiff, imdecode_no_exception_temporary_file_removed)
+{
+    cvtest::TS& ts = *cvtest::TS::ptr();
+    string input = string(ts.get_data_path()) + "../cv/shared/lena.png";
+    cv::Mat img = cv::imread(input);
+    ASSERT_FALSE(img.empty());
+
+    std::vector<uchar> buf;
+    EXPECT_NO_THROW(cv::imencode(".tiff", img, buf));
+
+    EXPECT_NO_THROW(cv::imdecode(buf, IMREAD_UNCHANGED));
+}
+
 #endif
 
 #ifdef HAVE_WEBP
@@ -1017,3 +1039,27 @@ TEST(Imgcodecs_Hdr, regression)
         ASSERT_FALSE(max > DBL_EPSILON);
     }
 }
+
+TEST(Imgcodecs_Pam, readwrite)
+{
+    string folder = string(cvtest::TS::ptr()->get_data_path()) + "readwrite/";
+    string filepath = folder + "lena.pam";
+
+    cv::Mat img = cv::imread(filepath);
+    ASSERT_FALSE(img.empty());
+
+    std::vector<int> params;
+    params.push_back(IMWRITE_PAM_TUPLETYPE);
+    params.push_back(IMWRITE_PAM_FORMAT_RGB);
+
+    string writefile = cv::tempfile(".pam");
+    EXPECT_NO_THROW(cv::imwrite(writefile, img, params));
+    cv::Mat reread = cv::imread(writefile);
+
+    string writefile_no_param = cv::tempfile(".pam");
+    EXPECT_NO_THROW(cv::imwrite(writefile_no_param, img));
+    cv::Mat reread_no_param = cv::imread(writefile_no_param);
+
+    EXPECT_EQ(0, cvtest::norm(reread, reread_no_param, NORM_INF));
+    EXPECT_EQ(0, cvtest::norm(img, reread, NORM_INF));
+}
diff --git a/modules/imgproc/doc/colors.markdown b/modules/imgproc/doc/colors.markdown
index c372d28..52152c9 100644
--- a/modules/imgproc/doc/colors.markdown
+++ b/modules/imgproc/doc/colors.markdown
@@ -123,7 +123,7 @@ In case of 8-bit and 16-bit images, R, G, and B are converted to the floating-po
 scaled to fit 0 to 1 range.
 
 \f[\vecthree{X}{Y}{Z} \leftarrow \vecthreethree{0.412453}{0.357580}{0.180423}{0.212671}{0.715160}{0.072169}{0.019334}{0.119193}{0.950227} \cdot \vecthree{R}{G}{B}\f]
-\f[L  \leftarrow \fork{116 Y^{1/3}}{for \(Y>0.008856\)}{903.3 Y}{for \(Y\leq 0.008856\)}\f]
+\f[L  \leftarrow \fork{116*Y^{1/3} - 16}{for \(Y>0.008856\)}{903.3 Y}{for \(Y\leq 0.008856\)}\f]
 \f[u'  \leftarrow 4*X/(X + 15*Y + 3 Z)\f]
 \f[v'  \leftarrow 9*Y/(X + 15*Y + 3 Z)\f]
 \f[u  \leftarrow 13*L*(u' - u_n)  \quad \text{where} \quad u_n=0.19793943\f]
diff --git a/modules/imgproc/doc/pics/delaunay_voronoi.png b/modules/imgproc/doc/pics/delaunay_voronoi.png
new file mode 100644
index 0000000..ca09c7b
Binary files /dev/null and b/modules/imgproc/doc/pics/delaunay_voronoi.png differ
diff --git a/modules/imgproc/doc/pics/polar_remap_doc.png b/modules/imgproc/doc/pics/polar_remap_doc.png
new file mode 100644
index 0000000..e3e4105
Binary files /dev/null and b/modules/imgproc/doc/pics/polar_remap_doc.png differ
diff --git a/modules/imgproc/doc/pics/polar_remap_doc.svg b/modules/imgproc/doc/pics/polar_remap_doc.svg
new file mode 100644
index 0000000..5442215
--- /dev/null
+++ b/modules/imgproc/doc/pics/polar_remap_doc.svg
@@ -0,0 +1,3776 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:xlink="http://www.w3.org/1999/xlink"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   id="svg2"
+   sodipodi:docname="polar_remap_doc.svg"
+   inkscape:export-filename=".\polar_remap_doc.png"
+   viewBox="-240000 0 0 400"
+   sodipodi:version="0.32"
+   inkscape:export-xdpi="90"
+   version="1.0"
+   inkscape:output_extension="org.inkscape.output.svg.inkscape"
+   inkscape:export-ydpi="90"
+   inkscape:version="0.91 r13725"
+   width="1280"
+   height="1000">
+  <defs
+     id="defs4">
+    <pattern
+       inkscape:isstock="true"
+       inkscape:stockid="Checkerboard"
+       id="Checkerboard"
+       patternTransform="translate(0,0) scale(10,10)"
+       height="2"
+       width="2"
+       patternUnits="userSpaceOnUse"
+       inkscape:collect="always">
+      <rect
+         id="rect9960"
+         height="1"
+         width="1"
+         y="0"
+         x="0"
+         style="fill:black;stroke:none" />
+      <rect
+         id="rect9962"
+         height="1"
+         width="1"
+         y="1"
+         x="1"
+         style="fill:black;stroke:none" />
+    </pattern>
+    <marker
+       inkscape:stockid="Arrow1Lend"
+       orient="auto"
+       refY="0.0"
+       refX="0.0"
+       id="Arrow1Lend"
+       style="overflow:visible;"
+       inkscape:isstock="true">
+      <path
+         id="path8405"
+         d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
+         style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1"
+         transform="scale(0.8) rotate(180) translate(12.5,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker20913"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         inkscape:connector-curvature="0"
+         id="path20915"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
+         transform="matrix(-0.8,0,0,-0.8,-10,0)" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker15424"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow1Lend"
+       inkscape:collect="always">
+      <path
+         transform="matrix(-0.8,0,0,-0.8,-10,0)"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
+         id="path15426"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker11066"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow1Lend"
+       inkscape:collect="always">
+      <path
+         transform="matrix(-0.8,0,0,-0.8,-10,0)"
+         style="fill:#0000ff;fill-opacity:1;fill-rule:evenodd;stroke:#0000ff;stroke-width:1pt;stroke-opacity:1"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
+         id="path11068"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker12808"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow1Lend">
+      <path
+         transform="matrix(-0.8,0,0,-0.8,-10,0)"
+         style="fill:#ff00ff;fill-opacity:1;fill-rule:evenodd;stroke:#ff00ff;stroke-width:1pt;stroke-opacity:1"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
+         id="path12810"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker12450"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow1Lend">
+      <path
+         transform="matrix(-0.8,0,0,-0.8,-10,0)"
+         style="fill:#ffff00;fill-opacity:1;fill-rule:evenodd;stroke:#ffff00;stroke-width:1pt;stroke-opacity:1"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
+         id="path12452"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Lstart"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker12092"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         id="path12094"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
+         style="fill:#ff00ff;fill-opacity:1;fill-rule:evenodd;stroke:#ff00ff;stroke-width:1pt;stroke-opacity:1"
+         transform="matrix(0.8,0,0,0.8,10,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Lstart"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker11752"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         id="path11754"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
+         style="fill:#ffff00;fill-opacity:1;fill-rule:evenodd;stroke:#ffff00;stroke-width:1pt;stroke-opacity:1"
+         transform="matrix(0.8,0,0,0.8,10,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker10065"
+       style="overflow:visible"
+       inkscape:isstock="true"
+       inkscape:collect="always">
+      <path
+         inkscape:connector-curvature="0"
+         id="path10067"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
+         transform="matrix(-0.8,0,0,-0.8,-10,0)" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker9767"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow1Lstart"
+       inkscape:collect="always">
+      <path
+         inkscape:connector-curvature="0"
+         transform="matrix(0.8,0,0,0.8,10,0)"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
+         id="path9769" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker5176"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         inkscape:connector-curvature="0"
+         id="path5178"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
+         transform="matrix(-0.8,0,0,-0.8,-10,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker4914"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         inkscape:connector-curvature="0"
+         id="path4916"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
+         transform="matrix(-0.8,0,0,-0.8,-10,0)" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker11655"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow1Lend"
+       inkscape:collect="always">
+      <path
+         transform="matrix(-0.8,0,0,-0.8,-10,0)"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
+         id="path11657"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker11223"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow1Lend">
+      <path
+         transform="matrix(-0.8,0,0,-0.8,-10,0)"
+         style="fill:#ff00ff;fill-opacity:1;fill-rule:evenodd;stroke:#ff00ff;stroke-width:1pt;stroke-opacity:1"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
+         id="path11225"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="StopL"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker10956"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         id="path10574"
+         d="M 0,5.65 0,-5.65"
+         style="fill:#ffff00;fill-opacity:1;fill-rule:evenodd;stroke:#ffff00;stroke-width:1pt;stroke-opacity:1"
+         transform="scale(0.8,0.8)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker10166"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow1Lend">
+      <path
+         transform="matrix(-0.8,0,0,-0.8,-10,0)"
+         style="fill:#ffff00;fill-opacity:1;fill-rule:evenodd;stroke:#ffff00;stroke-width:1pt;stroke-opacity:1"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
+         id="path10168"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker7969"
+       style="overflow:visible"
+       inkscape:isstock="true"
+       inkscape:collect="always">
+      <path
+         inkscape:connector-curvature="0"
+         id="path7971"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
+         style="fill:#ffff00;fill-opacity:1;fill-rule:evenodd;stroke:#ffff00;stroke-width:1pt;stroke-opacity:1"
+         transform="matrix(-0.8,0,0,-0.8,-10,0)" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker7752"
+       style="overflow:visible"
+       inkscape:isstock="true"
+       inkscape:collect="always">
+      <path
+         inkscape:connector-curvature="0"
+         id="path7754"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
+         style="fill:#ff00ff;fill-opacity:1;fill-rule:evenodd;stroke:#ff00ff;stroke-width:1pt;stroke-opacity:1"
+         transform="matrix(-0.8,0,0,-0.8,-10,0)" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker7511"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow1Lstart">
+      <path
+         inkscape:connector-curvature="0"
+         transform="matrix(0.8,0,0,0.8,10,0)"
+         style="fill:#ffff00;fill-opacity:1;fill-rule:evenodd;stroke:#ffff00;stroke-width:1pt;stroke-opacity:1"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
+         id="path7513" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker7501"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow1Lstart">
+      <path
+         inkscape:connector-curvature="0"
+         transform="matrix(0.8,0,0,0.8,10,0)"
+         style="fill:#ff00ff;fill-opacity:1;fill-rule:evenodd;stroke:#ff00ff;stroke-width:1pt;stroke-opacity:1"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
+         id="path7503" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Lstart"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker6597"
+       style="overflow:visible"
+       inkscape:isstock="true"
+       inkscape:collect="always">
+      <path
+         id="path6599"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
+         transform="matrix(0.8,0,0,0.8,10,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker9222"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow1Lstart"
+       inkscape:collect="always">
+      <path
+         inkscape:connector-curvature="0"
+         transform="matrix(0.8,0,0,0.8,10,0)"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
+         id="path9224" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker9089"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow1Lend"
+       inkscape:collect="always">
+      <path
+         transform="matrix(-0.8,0,0,-0.8,-10,0)"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
+         id="path9091"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Lstart"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker6337-2"
+       style="overflow:visible"
+       inkscape:isstock="true">
+      <path
+         id="path6339-7"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
+         transform="matrix(0.8,0,0,0.8,10,0)"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker7260-0-4"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow1Lend">
+      <path
+         transform="matrix(-0.8,0,0,-0.8,-10,0)"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
+         id="path7262-2-0"
+         inkscape:connector-curvature="0" />
+    </marker>
+    <marker
+       inkscape:isstock="true"
+       style="overflow:visible"
+       id="marker9767-4"
+       refX="0"
+       refY="0"
+       orient="auto"
+       inkscape:stockid="Arrow1Lstart"
+       inkscape:collect="always">
+      <path
+         inkscape:connector-curvature="0"
+         transform="matrix(0.8,0,0,0.8,10,0)"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
+         id="path9769-6" />
+    </marker>
+    <marker
+       inkscape:stockid="Arrow1Lend"
+       orient="auto"
+       refY="0"
+       refX="0"
+       id="marker10065-7"
+       style="overflow:visible"
+       inkscape:isstock="true"
+       inkscape:collect="always">
+      <path
+         inkscape:connector-curvature="0"
+         id="path10067-8"
+         d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z"
+         style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1"
+         transform="matrix(-0.8,0,0,-0.8,-10,0)" />
+    </marker>
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     bordercolor="#666666"
+     inkscape:pageshadow="2"
+     guidetolerance="10"
+     pagecolor="#ffffff"
+     gridtolerance="10000"
+     inkscape:zoom="0.881"
+     objecttolerance="10"
+     showgrid="true"
+     borderopacity="1.0"
+     inkscape:current-layer="layer1"
+     inkscape:cx="640"
+     inkscape:cy="454.59705"
+     showguides="true"
+     inkscape:guide-bbox="true"
+     inkscape:pageopacity="0.0"
+     inkscape:document-units="px"
+     inkscape:window-width="1920"
+     inkscape:window-height="1058"
+     inkscape:window-x="-8"
+     inkscape:window-y="-8"
+     inkscape:window-maximized="1"
+     inkscape:snap-smooth-nodes="true"
+     inkscape:snap-object-midpoints="true"
+     fit-margin-top="0"
+     fit-margin-left="0"
+     fit-margin-right="0"
+     fit-margin-bottom="0"
+     inkscape:snap-bbox="true"
+     inkscape:object-nodes="true"
+     inkscape:snap-bbox-edge-midpoints="true"
+     inkscape:snap-midpoints="true"
+     inkscape:object-paths="true"
+     inkscape:snap-center="true"
+     inkscape:snap-page="true"
+     inkscape:snap-bbox-midpoints="true"
+     inkscape:snap-nodes="true"
+     inkscape:snap-intersection-paths="true"
+     inkscape:bbox-paths="true"
+     inkscape:bbox-nodes="true"
+     inkscape:snap-global="true">
+    <inkscape:grid
+       type="xygrid"
+       id="grid8396"
+       snapvisiblegridlinesonly="false"
+       enabled="false" />
+  </sodipodi:namedview>
+  <g
+     id="layer1"
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     transform="translate(-1145.2897,280.70953)"
+     style="display:inline">
+    <image
+       y="249.2905"
+       x="1814.2898"
+       id="image25280"
+       xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAlgAAAG4CAIAAAAWqA6UAAAgAElEQVR4AezBXcz3+UHX+ffn8/n9
+74dOt0ilLWVBiQ9rcfmz4cBkXXEN2ZNN7IEQtKVG0gfbmeJCAEUpBg48MCSatAnRRA+MBxx4BvHA
+I0FDQtSEwNBOBfeBp7RdBnsNpZ1p5364vp/98r3zv/a6nbmn99XOU4ff66Xj8YxXDamAVMBmkgrY
+ZZGYpAI2k1S7gMQkFbCZpAJ2JSapgI1UwC4gIRWwKzHZlZik2gUk7AISdtntXhqHw7h+/fzmzbvX
+r5/fvHn3xo3z69fPr18/PxzG4XB+7do4HMbhMLZtsNv9ofT63/7t//UHf9C3b/N8fpD//SP5n/kx
+rkrH4xmvGlIBqYDNJBWwyyIxSQVsJql2AYlJKmAzSQXsSkxSARupgF1AQipgV2KyC0hItQtI2AUk
+7PJgLbsvWStei1oe0rb15s27N2/evXHj/ObNuzdv3r1+/fz69fPDYRwO59eujcNhHA5j2wa73Q7u
+3u13fMcvcdkB/j5XpePxjFcNqYBUwGaSCthlkZikAjaTVLuAxCQVsJmkAlJtJqmAzSRVKmAjFbCR
+CkgFbKTaTFKlAjZSeXVrxVe4lpeG+GJaXiItX9S29ebNuzdu3H3d6+7evHn3xo3zmzfvXr9+fjiM
+w+H82rVxOIzDYWzbYLd7LdIYvnPn8MwzvnMHOL927fZXfVVtHuDOnX7nd/4Sl12DH+WqdDye8aoh
+FZAK2ExSWSQmu4BUwGaSCkjYBaQCNpNUQKrNJBWwmaRKBWykAjaTVKmAhF1Awq7EJNUuX55WfKVp
+ebGJF9TyUmi5IvEcLQ8jKZckg/sl5ZKkybh58/z69fMbN+5ev37+utfdvXHj7rVrY9vGto1tG4dD
+t21s22C3e235737rt771H//j13/yk4yBjUSr9u7Nm5/8S3/piUcf5fk8/fT5d3/341z2Rvh+rkrH
+4xmvhJbnsgtIBWwmqSwSk11AKmAzSQUk7AJSAZtJKiDVZpIKSEx2JSapdgGJya7EJNUuIGFXYpJq
+F2jFq17Li0q8oJYXV8tViOdoeRhJuSQZ3C8plyTlkqRckgxOknJJUk6SwUlSFrs3bpxfv35+OIxr
+185v3Lh77drYtpF020bSpMlIym73GpJbt/6397xnXL/+f373d5998zfffsMbxrbVHteuff3P/uz/
+9JM/+f/8lb/ya+9+N8/xuc/dff/7n3jmmXMuvBUe5ap0PJ7xEmt5SHYBqYDNJJVFYrILSAVsJqmA
+xGRXKiAx2QUkJrtSAYnJrsQk1S4gMUm1maTaTFKl2kxSJV5+LS8S8YJaXkQtVyHu1/IwknJJMrhf
+Ui5JyiVJOUkGlyTlJCknyeAkKSdJOUnKSTJYkrIk5SQpiz0kDodx7dr5to1t6+Fwvm1NRlK7dm3s
+2mW3ew15w6//+v/yoQ994tu//YnHHuOS7Qtf+Lqf//lv/mf/7Dff/vb//N738hx37owPfvA/P/nk
+LS58LTzGVel4POPF1vKlsQtIBWzukQpITHYBqYDEZBeQmOxKBSQmu4DEZFdikgpItZmkAjZSAak2
+k1SbSarEJNWuxIul5cUgHqzlRdTy0MT9Wr6opNwvGVySlEuScklSTpLBJUk5ScpJMjhJyklSTpKy
+JIOTpCxJWZKy2IMlKUtSlmSwJGVJCiRl2bZh1+62DbvbVrsSdqVKSEAldrvXlPZbfvInv+Hnfm4k
+tc9v3hzbdnjmmTz7bO3f+fN//pd/+Icr8XweffSJT33qFhfeAD8A5kp0PJ7xImn5MtkFpAIS99gF
+JCa7gFRAYrILSEx2pYKkAlIBm0mqzSQVkGozSQUk7AISUgG7EpNdiUmqXYmH1PJlEw/Q8mJpeWji
+fi1fVFIuSQaXJOWSpFySlJNkcElSTpJykgxOknKSlCUpJ8lgScqSlJOkLPZgScqSlCUZQFKWpCxJ
+gWSwJAWSsiQDSAokZUkKJEPCLrvdHzKHZ5752v/4H28++eT5zZt3Xve6p7/+6z/7J//k3Rs3eEHf
+8R2/dPduuRD4Ma5Kx+MZX56WF4tdQCogcY9dQGKyC0gFJCa7gMQkFbCRCkgFbCapNi12AYnJrlRA
+wi4gIRWwkQpItZmkSkx2WVq+bOIBWl4ULQ9H3K/li0rKJcngkqRckpSTpFySDE6ScpKUk2RwkpST
+pCxJOUkGS1KWpCxJWezBkpQlKUsyWJKyJAWSsiQDSMqSFEgGS1IgKZAUSAaQlN1u9+L57Gfv/vW/
+/itc9hb4IFel4/GML1XLi8suIJVFYrILSExSAZtJKmAXkJikAjaTVInJLiAVkLALSEx2pQISUgEb
+qYDNJFWqTYtdiUkqVyMeoOXL1/JwxP1aXlhSLkkGlyTlkqScJOWSZHCSlJOknCSDk6QsSTlJypIM
+lqScJGVJymIPlqQsSYFksCRlSQokZUkGS1IgKZAMlqRAUiApkAwgKbvd7mX36KNPfOpTt7jwZvhe
+rkrH4xlX1/JSsAtIZZGY7AISk1TAZpIK2AUkJqmAxGRXYrILSAUk7AISk1S7gMQk1abFrsRkVyog
+YVdiksrzEw/Q8mVqeTjifi0vLCmXJINLknKSlEuScpIMTpJykpSTZHCSlCUpJ0lZksGSlJOkLElZ
+7MGSFEjKkgyWpCxJgaQsyQCSAklZkgEkBZKyJAWSASRlt9u9yvzVv/rLzz47uLDB3wdxJToez7ii
+lpeIXUDiHqmAXUBikgrYTFIBqYDNJBWQmOwCElIBu4DEZFdikiox2QWkSkx2JSapNpNUqYCNVP6A
+eD4tX6aWhyDu1/LCknJJMjhJyiVJOUnKJcngJCknSVmSwUlSlqScJGVJBktSTpKyJGWxB5CUJSlL
+MliSAklZkgLJYEkKJAWSwZIUSAokBZIBJGW3233l+P3fv/u+933s1q3Bha+DD3BVOh7PeGgtLymp
+LDaTVMAuIDFJBWwmqYBUwGaSCkhMdgEJqYBdQGKSajNJBSTsAlIlJrsSk1SbSarEJNXmQsuXo+Xh
+iEtaXlhSTpLBJUk5ScolSTlJBidJOUnKkgxOknKSlCUpSzJYkrIkZUnKYg+WpCxJWZIBJGVJCiRl
+SQaQlCUpkAwgKZCUJSmQDCApu93uNeFv/s0nnnzyFhcCPwrhSnQ8nvFwWl5qUllsJqmA3RabSSpg
+M0kFpAISk11AYrILSExSbSapgFSbSSogIRWwmaTabWVXKiBhV2KSKvEla/lixP1aXkBSLkkGJ0m5
+JCknSTlJBidJOUnKkgxOkrIk5SQpSzJYkrIkZUnKYg+WpEBSlmSwJAWSsiQFksGSFEgKJANIypIU
+SAokA0jKbrd77frc587f9a7Hueyt8ChXpePxjIfQ8vKQCthMUgGpgM0klcWmxS4gIRWwC0hMUgGb
+SSpgIxWQmKTaBSQmqTaTVInJrlSQVKmAjVSJh9TyEMQlLS8gKZckg5OkXJKUk6ScJIOTpCxJOUkG
+S1JOkrIkZUkGS1KWpCxJWezBkpQlKZAMlqRAUpakQDJYkgJJgWQASVmSAkmBZABJ2e12f/i8+90f
+PTu7wwXBj4G5Eh2PZzyElpeHVMBmkgpIBWzukQpITHYBiUkqYCMVkArYTFIBCbuAxCTVbiu7gFSb
+SarEJNVmkioVJNUuIPG8Wh6CuKTlBSTlJBlckpSTpJwk5SQZnCRlScpJMliScpKUJSlLMliSsiRl
+ScpiD5akQFKWZABJWZICSVmSASQFkrIkA0gKJAWSAskAkrLb7Xbwuc/d/Z7v+ejdu+XC18EHuCod
+j2d8MS0vG6mAzSQVkMofkF1AKiAx2QUkJqmAzSRVKsguIBWQmOxKTFIBCbuAxCTVLiAhFZCwC0hI
+lZjsctLyxYhLWl5AUk6SwSVJOUnKSVJOksGSlJOkLMngJClLUpakLMlgScqSlCUpiz1YkgJJWZLB
+khRICiRlSQaQFEjKkgwgKZAUSAokA0jKbrfbPZ+W7/mej37mM3e48Aj8MFel4/GMF9TycpIK2ExS
+WSQmu4BUQGKyC0hMUgGbFruAhF1AKiAxSQVspAISk12JSarEZFcqICEVsJEKSEjlixCXtDxIUi5J
+BidJOUnKSVJOksGSlJOkLMngJClLUpakLMlgScqSlCUpiz2ApCxJWZIBJGVJCiQFksGSFEgKJANI
+CiQFkgLJAJKy2+12D+fznz//4Ac//tRTd7jwRvg/wFyJjsczXlDLy0kqYDO12AUkJruAVJBUwC4g
+MUkFJCa7gMQk1S4gMUkFJOwCEpNdiUkqIGG3xUYqIFVisishlechLml5kKScJINLknKSlCUpJ8ng
+JClLUk6SwZKUJSlLUpZksCRlScqSlMUeQFKWpCzJAJICSVmSAskAkrIkBZIBJAWSAkmBZABJ2e12
+uy/JF75w/o53PN7y//vv4f1clY7HMx6s5WUmFZC4xy4gMUkFbCapgF1AYpIKSEx2AYlJKmBXYpIK
+SEx2JSapgI1UQEIqYCMVkJAKSNgFpPIHxCUtD5KUk2RwSVKWpJwk5SQZnCRlScqSDE6SsiRlScqS
+DJakLEmBpCz2YEkKJGVJBpCUJSmQFEgGS1IgKZAMICmQFEgKJANIym63271I3v3uj56d3eHCG+CH
+uCodj2c8WMvLTCqLxGQXkJikAjaTVBapgM0kVWKyC0hMUgGJya5UQGKyC0hIBSTsAhKTVInJrsQk
+VcJui82FlgdJykkyOEnKSVKWpJwkg5OkLElZksFJUpakLElZksGSFEjKkpTFHkBSlqRAMliSAklZ
+kgLJAJICSYFksCQFkgJJgWQASdntdrsX2507feyxJ373d29zYYMfBXMlOh7PeICWV4RUQGKyC0hM
+UllsJqmAVMCmxS4gMdmVmKQCEpNdQEIqIDHZlQpITFJtJqkSk1SbSarEJFXiQZJykgxOknKSlJOk
+LMngJClLUk6SwZKUJSlLUpZksCQFkrIkZbEHkJQlKZAMlqRAUiApSzKApEBSIBlAUiApkBRIBpCU
+3W63e4l97nN33/Oej926Nbjw1fB9YK5Ex+MZD9DyipAKSEx2AYl7pAI2k1RAKkgqYBeQmKQCNpNU
+ickuIDFJlZjstthIBaSCpNoFJKQCEnZb2ZUq8d9IykkyOEnKSVKWpJwkgyUpJ0lZksGSlCUpS1KW
+ZLAkZUkKJGWxB5CUJSmQDJakQFIgKUsygKRAUiAZQFIgKZAUSAaQlN1ut3sZ3bo1/tpfe3yMcuGt
+8ChXpePxjAdoeUVIBSQmuywSk1TAZpIKSExSAZtJKiAVkJjsAhJSAZtJKiAhFbBpsSsxSZWY7EoF
+JCQmuxKTVCApJ8ngJCknSVmScpIMlqQsSTlJBktSlqQsSYFksCRlScqSFLAHS1IgKUsygKRAUpak
+QDKApEBSIBlAUiApkBRIBpCU3W63e+W8852PP/PMORe+Fh7jqnQ8nvF8Wl4pUgGJe+wCEpNUwKbF
+LiAxSQVsJqmAVEBisgtITFIBCbuAxCRVYrILSEgFJKQCNlIBCanA4TAk7kkGJ0k5ScqSlJNksCRl
+ScqSDJakLElZkrIkgyUpS1IgKYs9gKQsSYFkAElZkgJJgWQASVmSAskAkgJJgaRAMpKy2+12rwIt
+73rX408/fc6Fr4XHuCodj2c8n5ZXilQWickuIDFJZZGY7AISk1TApsUuIBWQsAtITFIBicmuxCQV
+kJAK2EgFJCapEpNdiWRI2JVIBktSTpKyJOUkGSxJWZKyJIMlKUtSlqQsyWBJCiRlScpiDyApkJQl
+GUBSIClLUiAZQFIgKZAMICmQFEgKJANIym63273KvPvdHz07u8OFN8Hf4qp0PJ7xfFpeKVL5A5IK
+2AUk7pEKSEx2AYlJKiAx2QUkJqmA3VZ2pQISk1TARiogMUmVmOxKTFIlktoFpG5b7QJSk7Ik5SQp
+SzJYkrIk5SQZLEmBpCxJWZLBkhRIypIUsAdLUiApSzKApEBSIClLMoCkQFIgGUBSICmQFEgGkJTd
+brd7tXrPez726U/f5sIb4fu5Kh2PZzxHyytLYpIK2AVabCapgMRkF5CYpAISk11AYpIKSEx2W2yk
+AlJBUgG7EpNUQMJmkrptA5Cwa9euRDIk7AJJWZJykgyWpCxJWZLBkpQlKUtSIBksSVmSAklZ7AEk
+BZKyJANICiQFkrIkA0gKJAWSASQFkgJJgWQkZbfb7V71zs/7vvc9cXZ2mwtvgQ9yVToez3iOlldK
+y2QzSWWRCthMUgGJyW7LZDNJBSQmu4CEVEBikgrYTFIBCamAzSRVYpIKbNuQmA6HIRWQOBwGIHXb
+CtgFkrIkgyUpS1KWZLAkZUnKkpQlGUBSlqRAUhZ7AElZkgLJAJICSVmSAskAkgJJgWQASYGkQFIg
+GUnZ7Xa7rxzn533f+z52dnaHC2+BD3JVOh7PeI6WV0TLPTb3SAWkAjaTVBaJSSpgM0kFJCapgM0k
+FZCYpNpMUgGJSapNi11AYtsGIDWphF1g24bEtG3DLiBxOAyWZLAkZUnKkgyWpCxJgaQsyWBJCiRl
+SQrYgyUpkBRIBpCUJSmQFEgGkBRICiQDSAokBZICyQCSstvtdl+B3vvej/3X/3qbC2+BD3JVOh7P
+eI6Wl1/LBZt7pAJSQXZZpIKkAlIBm0kqIDFJBWxa7AISk1TApsWuxCQVkLBrV2LatmEXkEgq1a5d
+uxJJ7UoFDofBkpQlKUsygKQsSVmSsiQDSMqSFEjKYg8gKZCUJRlAUiApkBRIBpAUSAokA0gKJAWS
+AskAkrLb7XavqKeeuvOGN2zAtomr+xt/46Of+cwdLrwFHgNxJToez3iOlpdZy3/DZpIKSNxjF5CY
+pAJSAZt7pAISk1RAwi4gMUkFJCa7LTZSgW0rINWuXYlp24bNtG0DkHo4DEDicBiAVLtJWZICyWBJ
+ypKUJSmQDJakQFKWpIA9WJICSYFkAElZkgJJgWQASYGkQDKApEDSpEAygKTsdrvdq8C//bdn//Sf
+/taf/tOP/PiP/6lHHgknt2+P//AfPvNf/ssz73//N0g8yPl53/GOx2/dGlx4PfwQmCvR8XjG/Vpe
+Zi3PZTNJZZGY7LbY3CMVkApITHYBiUkqIDHZBSQmqRKTVMDGrlRg2yoVsGvXRmpSqTZJpdq1axew
+2bZhNylLMliSsiRlSQokgyUpkJQlKWAPIClLUiAZQFIgKZAUSAaQFEgKJANICiQFkgLJAJKy2+12
+rxr/4B/8348//tkf+7E/9a3f+gbgp37qUz/3c2c/8RP/w5vffP1f/ItP/Ot//eQ//Id/5s/+2dfz
+AOfnfcc7Hr91a3DhBvwIV6Xj8Yz7tbycWp6XzdRiF5CYpLLYtNgFpIKkAnZb2QWkgqQCdlvZBaSC
+pALbNgAJqUklpm0bUoFtK2B32wZgIzWpVLtJ7W7bAGySwZKUJSmQlCUZLEmBpEBSFnsASYGkLMkA
+kgJJgaRAMoCkQFIgGUBSICmQNBlAUna73e7V5wd+4Fd/+7ef/dt/+xv/wl/46pa/+3d/7Td+4wsf
+/vA3fcM33PiX//KTP/MzT/7ET/yZt73tER7g7t2+852P37o1uPBH4fu4Kh2PZ9yv5WXT8gIkJruA
+xD1SAYnJLiBxj1RAYrILSExSAYlJqs0k1a5dIClgNylgF9i2AUhs2wDsbtsAbLZtAHa3bQCHw7AL
+JGVJCiRlSQZLUiApkJTFHkBSICmQDJakQFIgKZAMICmQFEgGkDQpkBRIBpCU3W63e7X6hV/4vQ9/
++De3TW972yOPP/5ZSYna/vE//rpf//XPv+Ut1/7JP/kft008wDPPnH/v9378qafucOEt8BiIK9Hx
+eMb9Wl4eLS9MYrLLIjFJBSTusQtITFIBickuIDFJBSQmqcC2FZBq167EtG0DkEgq1a5dm2nbhl1g
+24bNtG0DsLttAzgchl0gKUtSIBksSYGkQFIWewBJgaRAMoCkLEmBpEAygKRAUiAZSYGkQFIgGUBS
+drvd7lXv93//7r/6V5/65CdvPf303fe+9+vf9Kbr/+bf/O7v/M6tb/mWN/zlv/wmXtAYfd/7nvj0
+p29z4RH4IQhXouPxjPu1vAxaviiJe+wCEpNUFonJLiAxSQUk7rHbYjNJBSSkJpWYkgHYtWszJcNm
+2rYBSE0q1SapVLtJpQKHw7CZtm3YTWoXSAokgyUpkBRIymIPICmQFEgGkJQlKZAUSAaQFEiaDCAp
+kBRICiQjKbvdbvfa9Y3f+I1tb9++fffuXeCf//P/99lnx/n5ePrp2//pP33y0898nr/HVel4PON+
+LS+1lockMdkFJO6RCkhMdlsmm0kqIDFJBWxa7AJJAbt2JSapSaXa2JUKbFsBu9s2AKlJbbZtAHbt
+2rWbVOrhMACbw2EAyWBJCiRlSQrYA0gKJAWSwZIUSAokBZIBJAWSJgNICiQFkgLJSMput9u9pt24
+cePbvu3bbN++fRto+fznuXnz8Oyz50899fkPfehnf+YXfo0PgrkSHY9n3K/lJdXy8CQmuy2TzSSV
+RWKSCthMUgGJSSogcc+2DYlp2wYgYdcukAzAxq5diWRITNs2ALvbVsDutg3gcBiA3W0bwOEw7AKH
+wwCSsiQFkgL2AJKyJAWSASQFkgJJgWQASYGkyQCSAkmBpEAykrLb7XZfsX7xF3//E5949hd/8bPb
+Bkjim77pkb/4F9/41rde5wXdvj0effTjn/70bS4c4ENgrkTH4xn3a3lJtTw8iXukAjb3SAUkJqmA
+zT1SAYlJKiBh1y6QFLBrV2LatgFI3bYCdu3aBbatUpPaBbZt2EzbNoDDYUgFDodhN6ldu0mBpEBS
+wB4sSYGkQDKApEBSICmQDCApkBRIRlIgKZAUSAaQlN1ut/vK9Ku/+syHP/wbTz55+5FH8vrX561v
+vS7xiU/c+r3fu93y5/7cH/nQh/4ED9b2Xe/6laefPufCG+H7uSodj2dc0vKSarkqiUkqi80kFZC4
+Rypg02IXkJik2kgF7NqVmLZtABJ27QLbNoBtKyDVrl0bu3aBbRt27doFDofatWvXblK7h8MADofB
+khSwB5AUSAokA0gKJAWSAskAkgJJgWQASZMCSYFkAEnZ7Xa7r1h37vTHf/z/+uQnn/2RH/kT3/RN
+r5e47Kd/+smf+qlPffjDb/tjf+wmD3D79vjAB544O7vDhdfB3wFzJToez7ik5aXTcnWSyiIVsJmk
+skhMUgGJe2wmqXYlpmQAdm2kAts2AImkUoFtK2A3GYDdpBJJpdpNKjWpXRt72BwOAzgcBmD3cBjA
+4TAAewBJgaQsyQCSAkmBpEAykgJJgWQASYGkSYFkAEnZ7Xa7r3wf+chv/rt/99R3fudbvv3b3/g1
+X3NN0q1b54eDf/qnn/z3//6pu3fHP/pHb3vTm67xAOfnfec7f+XZZ8+58DXwt0BciY7HMy5peem0
+XJEAqSxSAZuWyS5IKovEJBWwmZIBSNiVCti1mZIB2LVrI9WuzbRtA9i2Adi1a7NtA7Br1+7hMACp
+Se0eDgPYtpEU2LaRYA8gKZAUSAaQFEgKJAWSASQFkgLJSAokBZICyUjKbrfbvYZ85CO/+fM//1TL
+NEZbpm3T29/+5re//c1vfvM1HuwLXzj/wAc+/pnP3OHCTfh7XJWOxzMuaXmJtFyROJEKSOUPSCpg
+c49UQGKSypIUsGtXYkoGYGNXKrBtA7CxKzWpxLRtA7C7bQPYtgLbNgC7h8MAtm0Adg+HAWzbsJvU
+7uEwgMNhAElZkgEkBZImBZIBJAWSAskAkiYFkgLJAJKy2+12r0XPPHP+7LPnh4MfeSR37vTGDfNw
+3v3uj56d3eHCH4XvhXAlOh7PuKTlpdBydeJEKovEJJXFpsUui8Qk1a7EtG0DkLALSLVrMyUD2LYC
+du3aBZLatWsX2LYBHA4DkDgcBrBtAzgchl27doHDYdhNavdwGMDhMIBkAEmBpEBSIBlAUiBpMoCk
+QFIgaTKApOx2u93ufl/4wvljj338qafucOGr4AdAXImOxzMuaXkptFyRuJ9UQOIeqYBNy2QXkJiS
+wZIUsCvVZkoGYGNXalKJadsGsG0DkEgqFTgcBrBtA9i2YTNt2wAOh2HXrt2kdg+HAdg9HAZwOAy7
+yQCSAkmBpMkAkgJJgWQASZMCSYFkJGW32+12D/DOdz7+zDPnXLgBP8JV6Xg845KWF13LFYnnkMoi
+MUllkZjssiQFpNqVmJLBsm0FkgHY2LULJAW2bQB27drYtQts27Br165dm+lwGHbt2k1q93AYwOEw
+gMPh3CYZdg+HASQFkgLJAJICSZMBJAWSAkmTASRlt9vtdg9w+/Z4//ufeOqpO1z4avg+MFei4/GM
+S1pedC1XIZ6jZbILSNwjFZC4x65Um0mqXSApINXGrl2pgI1dYNsGkBSwa9euXRu7du3atZtUalK7
+NvawSWo3GTaHwwAOh3O7Se0mtXs4DCApkAwgaVIgGUBSIGlSIBlAUna73W73YC3f9V2/fPv24MIb
+4fu5Kh2PZ1zS8uJquSJxv5Z77LJITFJZJKZksCQF7NpIBexK2LULJAXs2rVrV2LatgFs2wC2rYBd
+u3aT2rVrd9sGYDepTTLsHg4D2LYBHA4jqd2kh8MADoeRDCApkBRIBpA0KZAUSEZSdrvdbvcQvuu7
+fvnWrcGF18HfAfP/sQe/Mb/fd13Hn+/X6/O52nU9bde129wITtzGAv4QxUTBoES8Y7KIUZeOJgIb
+y4BtjD8qKoruBpFoMJEbGkkwIdyALZoYMCZ4A9BwS0xY13Zq3MBNRv+4/trTnbU95/rzefnN5+R3
+5TqZvc51nXNmW/p9PM6lNpstJyTcWgnnUXyZhGNSgCquqgqTHaAqElUBpEgs7AHYYWptAFVIkSJF
+CtBaAHsArQ1Awk5V7EiRIqW1AfQ+AClS7LQ2gN4H0PuQYqf3AeztDSn2kGIHsGMPwA5gB7BjD8AO
+q9VqtTqDo6N87/c+ut3uc+xO+BEw51KbzasIY4EAACAASURBVJYTEm6hhPMovkzCSVISFhJXVUWi
+KoCUKhb2ACSqAkiRUoUUKYAdQIoUoLUBtBagtQFUxY6EFClSpLQ2gN4H0NoAeh9A70OKHSl2pPQ+
+gN4H0PuRHTu9D8AegB3Ajh3AHoAdVqvVanVm3/mdn/zSlw459jr4CBTnUpvNlp2EWyvhPIprJXy5
+qjBJLKoisbAHUIUUoCoSVQFaG4BEVYDWBmAHkCIFaC1AawOQIkWKFAkpUlobQO8DaG0AvQ+g9yFF
+ih0pdqTY6X0AvR9JsbO3N4DejwA7dgA7gD3ssFqtVqtz+o7v+O0xwrF74IegOJfabLbsJNxaCWdW
+fJmEL1cVJolFVSQW9gCqkALYYbIH0FqAqkgBWgtQFSlSpEhIkQK0NoDWBtBagNYG0PsAWhtA7wNo
+bQC9Dyl2pNiR0vsA9vaOpNjpfQB7e0dA78MOYAewhx1Wq9VqdU5HR3nwwU8+//wRx14Df4fzqs1m
+y07CLZRwHsW1El5MVZjsABJVAaRUsbAHICEFqIoUiapIkQJISKmKFClSJBatDaC1AbQ2gNYC9D6A
+1gbQ+wBaG0DvA+h9SLEjxY6U3o/sSLFjp/dhDzu9D8COPQA7rFar1er8Dg/z3d/98Be/eMixDn+f
+86rNZstOwi2UcGbFl0k4RVUkqgJIqWIhpYqFPQApEgt7ABJVAVobQGsBpFQFaG0ArQVobQCtDaC1
+AfQeoLUBtDaA3gfQ+wBaG3ak2JHS+xHQ+7BjR4qd3o/s2JFiZ2/vCLDDarVarW7I/n7e+96Hv/jF
+Q441+AecV202W3YSbpWE8yiulXC6qkgs7MFkh8kOYA8mO0BrAaoiBWhtAK0FqIoUoLUArQ2gtQG0
+NoDeA7Q2gNYG0PsAWhtA7wPofUix0/sAej8Ceh92pOztDaD3Izt2ej8C9vYGq9VqtbpRBwf53u99
+5JlnDjhm+AnOqzabLTsJt0rCmRXXSriuqkgsqiKlioWUqkgspFRFoiqAFAkpVZECSJGQUhUpUoDW
+ArQ2gNYG0NoAeg/Q2gB6H0BrA+h9AL0PoLXR+wB6PwJ6H8De3uh9AL0fAXt7Y29vAL0fAXZYrVar
+1Q05PMx73/vwxYuHHDP8BOdVm82WnYRbJeHMimslnK4qTHaY7AD2YGotQFUkFvYApEgs7AFIkZBS
+FSlSpEhIAaRIkSJFip3WArQ2gN4H0NoAeh9A7wPofUjDTu8D6H3YkWLHHr0PO3bsSMMOYIfVarVa
+nd/+fr7nez556dIRx/bgxzmv2my27CTcEglnVlwr4bqqwiRRFSlVLKRURWIhpSoSVQFaG0x2gNYG
+0FoAKVUBWhtAawGkSJEixY4UKRJSeh9AawPofQC9D6C1YUcadqTs7Q0pdqTYsUfvw44dO4A07AB2
+WK1Wq9U5HR3lPe956PLlwbHXwt/mvGqz2bKTcEsknFlxrYTTVYVJYlEVKYAdJjuAlKpIVAWQIkWi
+KlKA1gJIkQLYA2gtQGsDkCJFih0pUiSkSOl9AL0PoLUB9D6k2JGGHSl7ewPofUix0/sRsLc3ADt2
+AGkAduywWq1Wq3P6K3/lt4+OwrG74YehOJfabLbsJNwSCWdTXCvhuqoCSFxVFSlVLKRUBWgtTHYA
+ewBSJBb2AKRISJFSFaC1AbQWoLUBSJEixY4UCSlS7LQ2gN4H0PsAWht2pGFHip3eB9D7sGOP3gdg
+B7BjB5AGYMcOq9VqtTqPBx/85KVLhxx7HfwgiHOpzWbLTsLNSziz4loJp6sKk8SiKkx2AClVASSk
+VEVCClAVKYAdoLUBSEipihQpQGsBWhtAawOQIsWOFAkpUnofQGsD6H0AvQ8pdqRhR0rvA9jbG1Ls
+2JEGYMcOYAewIw3ADmCH1Wq1Wp3B4WHe975HnnnmgGN3w0fAnEttNlt2Em5ewtkU10q4rqoAEldV
+BZACVCEFsANIqQrQWoCqSJFY2ANoLUz2AFobgBQJKVKkSJEixY4UCSlSpPQ+gN4HIEWKnd4H0PtR
+7wPofQC9Dzt2AGkAdgA7dgA7gDTsAHZYrVarr6TLl1tro7XBK9xf/+ufuHJlcOxO+FEQ51KbzZad
+hJuXcDbFtRJOVxUmiUVVmKQAVUgBqiIhpSoSC3swtRagKlKkSEgB7AG0NgAJKVKkSAFaG1LsSEiR
+IsWOFClS7EjpfQC9D6D3Iyl27PQ+ADt2AGkAdgA7gB07gDQAO3ZYrVarr4xLl/Z+8zf/0N7e+LZv
++/3WBq9kf+2vfWJ/f3DsbvgRzqs2my07CTcv4WyKayWcriqAxFVVAaQwVbGwByAhBbADVEWKFMAO
+IEWKhJSqAK0NQEKKFClSpEgBWhsSdqRIkQL0PqRIsSNFSu8D6H3YQ4qd3gdgB7AD2AGkYQewA9gB
+7EgDsAPYYbVarW61z33uwq/8yh/5s3/28W/8xqek8Ip15cp4//sfvXjxgGOvgx8EcS612WzZSbhJ
+CWdTXCvhdFVhklhUhUkKUMVCClAViYU9ADuAFClVLKRIAVoLUBUpUqRISJEiRYoUoLUBtBYpdqQA
+rQ2g9yHFjpTeB9D7AHo/kmJHih3ADmAHsANIA7AD2LED2AGkAdixw2q1Wt1SDz/8+l/4hXd++MOP
+vPWtX+QV7j3veei55444djv8Xc6rNpstOwk3KeFsimslnK4qgMRVVQGkMFWxkAJURaIqgBSJhT0A
+O4AUKVIAO4AUKVIkpACtDSlSpACtBWhtAFJ6H0DvA2htSLEjRYodKb0PoPcjwA5gB7AD2AHsANKw
+A9gB7AB2pAHYAeywWq1Wt0LCJz9538c+9o6PfOSTb37zc7ySvfDC+P7vf/Tppw84dhf8CBTnUpvN
+lp2Em5RwNsUJCaerCpPEoipMUoAqFlKYqgLYAaRIVAVobQBVSJEipYpFawOQIkVi0doAWhuAlNYG
+0FoAKVLstDaA3ocUoPcBtDbsSLHT+wCkAdgB7AB2ADuAHUAagB3Ajh3ADiANwI4dVqvV6qZdvuyH
+H77vkUde/x3f8bv33XeZl4ennz744hcPW6v77uuHh9x5pzmb7/quh5955oBjr4cfgMa51GazZSfh
+JiWcQXGthNNVBZC4qiqAFKYqFlKAqgASi6pIAewAUqRUsWhtAFWRkCJFCtBapACtDaC1AUhpLYAU
+KVLsSGltAFJ6H0DvQ4odKb0PJjuANAA7gB3ADmAHsANIww5gB7AD2AGkYQeww2q1Wt2EK1f8i7/4
+tRcuXHnXuz53++2HvNT+4T/89KOPXhqDxdFRqljY9T3f85Z3vesNdvHiXnjh6AMf+NTFiwccuwN+
+jPOqzWbLTsJNSjiD4loJp6gKk8SiKkxSgCoWUpiqAkgsqiKlikVrA6hCihTAHoCEFClAawOowk5V
+WhuAFDtV2JEiRYoUO1KkSJHS+wB6H1KA3gdgB7ADSAOwA9gB7AB2ADuANAA7gB3ADmBHGoAdwA6r
+1Wp1Qw4P9XM/93UXLhw88MD/bC28pP7ZP/tfv/mbzzzwwB/6S3/pvqr6rd969md/9n//hb/w+oRf
+//Xt299+x0c/+vbbbxcv4ugoDzzw0JUrg2Ovhw9DcS612WzZSbgZCWdTnJBwuqoAEldVBZDCVMVC
+ClAVQOKqqgB2AClSqli0NoCqSJFYtDakAHYAKVKkAK0NCSlSgN6HFClSpNiRIkWKFDtSeh+AHSY7
+gB1AGoAdwA5gB7AD2AGkAdgB7NgB7ADSAOzYYbVarc7v8mX/23/7tjvuOPyrf/V3eEnt74+f+IlP
+P/74lX/0j972R//oHcCnP/38T/7kZ+65p/3Mz3zdz/7s//6P/3H70z/9tV/zNXfwIvb3xwc+8Oh2
+e8Cx2+DvgDiX2my27CTcjIQzKK6VcLqqABKLqjBJAapYSGGqCiCxqAogBbADSKlCCiClKhKL1gZQ
+FTtVtDYAKVKkAK1FCtDaAHofUoDWhhQ7UiSkIaX3wWQHsAPYAewwSQOwA9gB7AB2ADuANAA7dgA7
+gB1AGoAdO6xWq9V5PP74Hb/6q3/4ne+8+Kf+1JO9D146Cf/lv1z8mZ/57PPPj7vvbgcH4/LlYdc/
+/sdf+5a33PbTP/2/Hnnk0sc+9o2tFS8i4Tu/86Hnnjvi2P3wIc6rNpstOwk3I+EMimslnKIqTBKL
+qgBSmKpYSAGqAkhcVRVAClCFFClAFVKkAHakAPYAJKRIAVobUoDWAkhpbQCtDUBKawOQ6H0AvQ8p
+0rBZSAOww2QHsAPYAaQB2AHsMNkB7AB2pAHYAewAdgA7gDTsAHZYrVavVoeHam0Ah4dqbSRUkbCo
+YoySMkZJYfrCF17zUz/1Te9+92e++Zuf4GUg4Td+Y/vZz75w5cr4Y3/swp/+03fv7Ql46ql9qe69
+t/Pi9vfHBz7w6HZ7wLEOfw/EudRms2Un4WYknEFxQsLpqgJIXFUVQApQxVVSgKoAEouqAFKAKhZS
+ADuAFClVAVoLUBUpElKkSAFaG0AVvQ+gKnakVMWOFAkpUnofgJTeB2CHSRqAHcAOkx3ADiANwA5g
+B7AD2AHsANIA7AB2ADuAHUAadgA7rFarV5lf+7Wvuny5Pf74ayH33nvlc5+78Ja3PPfss3utjQsX
+9p9++vY3vvGFJ5644557rjz77G2vfe3Ba15z+Du/c/dTT92+tzf+zJ954sknX3P//Zcff/yON7/5
+uaefvv2ee648++xtd9115eLF297whheefPI1b3rT85cu7X3zNz/xVV/1JV4Gbr/99m/91m+VtL+/
+DyR86Uu5445+cHD0zDOXf/zHf+3f/Kf/xg+AOJfabLbsJNyMhDMoTkg4XVUAiUVVmKQAVSykAFVh
+klhUBZACVLGQAlRFQgpQldYCVEWKFKC1AFVpbQASUqRIkSIFaG1ILHofUqRIkWJHih0mO4A0mOwA
+dgA7THYAaQB2ADuAHcAOYAeQBmAHsAPYAewA0gDs2GG1Wr1qXLx422c+c/dttx0l7O/73nsvb7e3
+3333/uGhDg501137Fy/edv/9ly9e3Ov9qPdxeKjLl9tv/MZb3vrWS29727NvetNz2+3tr33t4ZUr
+unDh4Etf6nfdtX/pUt/bG0dHtbc3Dg50xx2Hr3vdlarw8vDVX/3VwP7+/tH0L/7F7x8cMEaef/7g
+v/7Xx556/nl+jPOqzWbLTsINSziD4loJp6gKk8SiKoAUpioWUoCqABKLqgBSgCoWUoCqABILewAS
+UqoCtDYkFlWRIgVoLVKA1oYUoLUBtBYpQO9DCtDakALYAeww2QGkwWQHsAPYYbIDSAOwA9gB7AB2
+ADuANAA7gB3ADmAHkAZgxw6r1Wr1//LYY6/9+Mff/m3f9vnN5unWBi+1ixcPP/7xx3/7t5/dbg/G
+QKL3GiMPPvjmv/yX31jFKcbI+9736Ha7z7E74UdBnEttNlt2Em5YwhkU10o4RVUAiauqAkgBqlhI
+YaoKILGoCiAFqGIhBagKILGoihSJqgCtDaAKO1WRIkVi0dqoCtD7AKrofQBSWhuAlNYGIMUOkx3A
+DpMdQBpMdgA7gB0mO4A0ADuAHcAOYIfJDiANwI4dwA5gB5AGYAeww2q1Wp1wcKCf+qlv+pZveeLb
+v/3zVeEl9e/+3ZM///Ofv+ee/if+xF3f8A0XqrjtNt12m/79v/8/n/rUl+6+u//Lf/l1e3viRTz3
+3NEHP/ipp58+4Nib4PugOJfabLZMCTcj4QyKExJOVxVAYlEVJilAFQspQFUAiauqAkgBqlhIAaoi
+sagKILGwByDFDiAFaG0AVbQ2ACmtDUBCihQpdqoixY4UCWkw2QHsMNlhsgNIg8kOYAeww2QHkAZg
+B7DDZAewA9gBpAHYAewAduwA0gDsAHZYrVar6ZlnbvsP/+GtUh588H/ykkrygz/43y9ePPjJn3zH
+W9/6Gq718Y8//rGPPf5P/snXvuMdr+VFHB7mPe956MqVwbF74SOcV202W6aEm5FwBsUJCaeoCpPE
+oiqAFKYqFlKAqgASi6oAUoAqFlKAqgASi6oAEouqVMVOFYvWRlWA1gJIkSJFCtBapACtDSlAa0MK
+0HuYpMFkh8kOYIfJDiANJjuAHSY7gB1AGkx2ADuAHcAOYAeQBmAHsAPYAewA0gDs2GG1Wr3qXbrU
+f/mXv+bChYNv//bfu/POA15Sv/RLj3/844/deWf783/+3m/4hruOjsYTT+x/9rMvfPrTzz3xxJV7
+7+3/+l9veHGHh3nwwYdeeGFw7Hb4u5xXbTZbpoSbkXA9xbUSTlEVQOKqqgBSgCoWUpiqAkgsqgJI
+AapYSAGqAkhUBZBYVAWoCtBapABVkSIhRYoUoCqtBZDS2gCktDYAid4Hkx0maTDZYbID2GGywyQN
+wA6THcAOYIdJGoAdwA5gB7AD2GGSBmAHsGMHsANIA7AD2GG1Wr2K/dIvvWOMeve7P7O3d8RL7Xd/
+9/l/9a9+7/d+74X9/diMwYUL7Y//8Qt/8S/e9/Vff2cVpzg6ygMPPHTlyuDYnfCjIM6lNpstU8LN
+SLie4loJp6gKILGoCpMUoIqFFKAqgMSiKoAUoIqFFKAqgMSiKoDEoipAVSQWVbFTFYlFawOoSmsD
+kKiKHSlVsSNRFTtSADtMdpikwWSHyQ6THcAOkzQAO0x2ADtMdgBpAHaY7AB2ADuAHUAagB3ADmAH
+sANIA7AD2GG1Wr3KHBzot37rjb/+61/1N//mJ+6445CXmYQqzu67vuvhZ5454Ngb4PtBnEttNlum
+hBuWcAbFCQmnqAqTxKIqgBSmKhZSgKoAEouqAFKAKhZSgKoAEouqABJVAaoCSCyqIgVoLUBVpEiR
+UoWdqkgBWhsSi9aGFMAOO3aY7DBJA7DDZIfJDpMdQBpMdgA7THYAO0zSAOwAdgA7THYAO4A0ADuA
+HcAOYAeQhh3ADqvV6lUj4ROfuP8//+c3v+tdn3v72y/yCvf+9z/65JNXOPYG+CDnVZvNlinhhiWc
+QXFCwimqwiSxqAogBajiKilAVQCJRVUAKUAVCylAVQCJqgASi6oAVZFYVAWQAlQhRYqUKhatDSlA
+VXoPUJXeB1AVO+zYYbLDZIdJGkx2mOww2QHsMEmDyQ5gh8kOYAeQBpMdwA5gB7AD2GGSBmAHsAPY
+AexIA7AD2GG1Wr0K/I//8bpf/dWvfte7Pvu2tz3LK9x73/vIU0/tc+x++BDnVZvNlinhhiWcQXFC
+wimqAkhcVRVAClDFQgpQFUDiqqoAUoAqpABVASQWVQEkFlWpCiCxqAogpYqFlKoArQWQUhU7VZFY
+tDakVMUOO3aY7DDZYbLDjjQAO0x2mOww2WGSBmCHyQ5gh8kOIA3ADpMdwA5gB7ADSIPJDmAHsAPY
+kQZgB7DDarX6g2uM+qf/9E/+uT/32Ld8y+O8kh0d5f3vf/Spp/Y59gb4IOdVm82WKeGGJZxBcULC
+KaoCSCyqwiQFqGIhBagKILGoCiAFqGIhBagKILGoCiBRFaAqgERVAClAFVKAqgASVQFaGxKLqvQ+
+gKq0Ntixw2SHHTtMdpjsMEmDyQ6THSY7THYAaTDZYbID2GGyA0gDsMNkB7AD2AHsMEkDsAPYAewA
+dgBpAHbssFqt/sB54YX2xBN3XLnid77zGV7h3ve+R77whX2OvQ5+iPOqzWbLlHDDEq6nuFbCKaoC
+SCyqAkhhqmIhBagKILGoCiAFqGIhBagKIFEVQGJRFaAqEouqAFKqWEgBqiKxqIoUoIrWBiClKnYk
+rpIGkx127DDZYccOkx0maTDZYbLDZIfJDiANJjtMdgA7THYAaTDZAewAdgA7THYAaQB2ADuAHcAO
+IA3ADmCH1Wq1epl5//sfffLJKxy7Dz7MedVms2VKuGEJ11NcK+HFVIVJYlEVQApQxVVSgKoAEouq
+AFKAKhZSqgJILKoCSCyqUhVAYlEVQEoVCylVASSqAkipYiGlKkBrQ+IqO+xIg8kOO3aY7LBjh8kO
+kzSY7DDZYbLDZIdJGoAdJjuAHSY7gDSY7AB2mOwAdgA7gDQAO4AdwA5gB5AGYAeww2q1Wr08PPjg
+Q5cuHXHsjfADnFdtNlumhBuWcD3FCQmnqAogcVVVAClAFQspQFUAiUVVAClAFQspQFUAiUVVAImq
+AFUBJBZVkQJUIQWoCiBRFUBKFQspVQEkqgLYYccOkzTYscOOHSY77NhhssMkDSY7THaY7DDZYZIG
+kx3ADpMdwA6TNAA7THYAO4AdJjuANAA7gB3ADmAHkAZgB7DDarVavXTe856HnnvuiGNvhB/gvGqz
+2TIl3LCE6ylOSDhFVQCJq6oCSAGqWEgBqgJILKoCSAGqWEgBqgJILKoisagKUBVAoiqAFKAKKUBV
+JBZVkQJUIQWoisSiKuzY4QQ7TNJgxw47dtixw2SHyQ470mCyw2SHyQ6THUAaTHaY7DDZAewwSQOw
+A9hhsgPYAewwSQOwA9gB7AB2AGkAdgA7rFar1f9H+/vjgQceOjwMx+6HD3FetdlsmRJuWML1FCck
+nKIqgMSiKkxSgCoWUoCqABKLqgBSgCoWUoCqABJVASQWVQGqIrGoCiClioWUqgASi6pIAaqQUhVA
+oiq8CDvs2GFHGuzYYbLDjh0mO+zYYZIGkx0mO0x2mOwwSYPJDpMdwA6THUAaTHYAO0x2ADuAHSZp
+AHYAO4AdwA4gDcAOYIfVarX6Cnv++aPv/u6HL18eHLsbPgLmXGqz2TIl3LCE6ylOSDhFVQCJRVUA
+KUxVLKQAVQEkFlUBpABVLKRUBZBYVAWQWFSlKoDEoipSgCoWUqoCSFQFkFLFQkpVAImqcD122LHD
+jjTYscOOHXbsMNlhxw6TNJjsMNlhssNkh0kaTHaY7AB2mOwwSQOww2QHsAPYYbIDSAOwA9gB7AB2
+AGkAdgA7rFar1VfAwUE+/OFPPfbYFY4Z/j6Ic6nNZsuUcGMSzqA4IeHFVIVJYlEVQApQxUIKU1UA
+iUVVAClVLKQAVQEkFlUBJKoCVAWQWFRFClCFFKAqEouqAFKqkAJURWJRFc7DDjt22JEGO3bYscOO
+HSY77NhhkgaTHSY77NhhsgNIg8kOkx0mO4AdJmkw2QHsAHaY7AB2AGkw2QHsAHYAO4A0ADuAHVar
+1eoWee97H3nqqX2O3Ql/i/OqzWbLlHBjEq6nuFbCi6kKk8SiKoAUoIqFFKAqgMSiKoAUoIqFFKAq
+gMSiKhKLqgBVASSqAkgBqpACVEViURUpQBVSgKpILKrCDbHDCXbYkQY7dtixw44dJjvs2GGSBjt2
+mOww2WGywyQNJjtMdgA7THaYpAHYYbID2GGyA9gBpAHYYbID2AHsANIA7AB2WK1WqxtycJB3v/sT
+R0fh2P3wIc6rNpstU8KNSbie4loJL6YqgMRVVQGkAFUspABVASQWVQGkAFUspABVASSqAkgsqgJU
+RWJRFUBKFQspVQEkFlWRAlQhpSqARFW4ReywY4cdabBjhx077Nhhxw47dpikwWSHHTtMdpjsMEmD
+yQ6THcAOkx0maQB2mOwAdpjsAHYAaTDZAewAdgA7gDQAO4AdVqvV6mwuXx4f/OCnvvCFfY5dgB8G
+cw4///O12WyZEm5MwvUUJyScoiqAxFVVAaQAVSykAFUBJBZVAaQAVSykAFUBJKoCSCyqAlRFYlEV
+KUAVCylVASSqAkipYiGlKoBEVfgKsMMJdtiRBjt22LHDjh127LBjh0kaTHbYscNkh8kOkzSY7DDZ
+YbID2GGSBpMdwA6THcAOkx1AGoAdwA6THcAOIA3ADmCH1Wq1ehF/4288fPHiAcdug7/H+Xz0o7XZ
+bJkSbkzC9RQnJJyiKoDEoipMUoAqFlKAqgASi6oAUoAqFlKAqkgsqgJILKpSFUBiURUpQBULKVUB
+JKoCSKliIaUqEouq8JVnhxPssCMNduywY4cdO+zYYccOkzTYscNkhx07THaYpMFkh8kOYIfJDpM0
+mOwAdpjsAHaY7ADSAOwAdpjsAHYAaQB2ADusVqsVvPDC0YMPfvLwMBx7A3yQc/j85/m5n6vNZsuU
+cGMSrqc4IeEUVQEkFlUBpDBVsZACVAWQWFQFkAJUIQWoCiCxqAogURWgKoBEVQApQBVSgKpILKoi
+BahCClAViUVVeCnYYccOJ0iDHTvs2GHHDjt22LHDJA127DDZYccOkx0maTDZYbLDZIfJDiANJjtM
+dgA7THYAO4A0mOwAdgA7gB1AGkx2ADusVqtXn+/7vkcfe+wKxwr+AZiz+uf/nIsXa7PZMiXcmITr
+KU5IOEVVAIlFVQApQBVXSQGqAkgsqgJIqWIhBagKILGoCiBRFaAqgERVAClAFVKAqkgsqiIFqEIK
+UBWJqvDyYIcT7HCCNNixw44dduywY4cdO+xIg8kOO3aY7DDZYUcaTHaY7DDZAewwSYPJDmCHyQ5g
+h8kOIA0mO4AdwA5gh0kagB3ADqvV6g+u558/euCBhzjpfvgQ5/DRjwK12WyZEm5MwvUUJyScoiqA
+xKIqgBSgioUUpqoAElUBpABVLKQAVQEkFlWRWFQFqAogURVAShULKUBVJBZVkQJUIaUqgERVeBmz
+wwl22JEGJ9hhxw47/r/swV3M5vlh1vfvdV33PfMswS9xzcZrxXFBYCylt6wWpQpIBY56BAdgbbw4
+Itg4eO1tFSLXEXmjHYUTKzKIEyQLEDIowAEHgMRBgqpgKWqUSo29iTdq8UsVRGTWxg+79u44Oy/P
+7+pfv9F/uKftM8/MY6+zmfw/n5RVUlZJWdmDVVKmpExJWSVlsgdTUqakTEmZkjLZA0jKlJQpKZCU
+KSlgDyApU1IgKZAUsAeQlCkpm83mkfDBDz73H/7DDe4K/CSEB/LKK3zsY4AOh1OmlstpuYg40nIf
+UgGbhVTALiCxsAtIBWwWUgG7gMTCLiAVsFlItVlIBaTaLKQCdiUWdqUCNlIBuxILu1IBG6n8bpOU
+I0k5Yg9WSTmSlFVSVklZJWVlD6akildgIwAAIABJREFUrJIyJWWVlMkeTEmZkjIlZUrKZA+mpEBS
+pqRAUqakgD2YkgJJgaRMSQF7AEmBpGw2m989rl8/e9/7fv2VVwZ3PQ7P8KB+/uf5lV8BdDicMrVc
+TstFxJGW80hlsllIBewCEgu7gFTAZiEVsAtILOwCUgEbqYDNQiog1WYhFbArsbArFbCRCtiVWNiV
+CthI5VGRlCNJOWIPjiRllZQjSVklZZWUlT2YkrJKypSUVVImezAlZUrKlJQpKZM9mJIyJQWSMiUF
+kjLZA0jKlBRICiQF7MGUFEjKZrN5jXnqqWevXz/jLsNfB/FArl1j0uFwytRyOS0XEUdaziOVyWYh
+FbALSCzsAlIBm4VUwC4gsbALSAVspAI2C6lSAZuFVLuAxMKuVMBGKmBXYmFXqs1CKr8HJOVeSTli
+D1ZJOZKUVVJWSTmSlMkerJKySsqUlFVSJnswJWVKypSUKSmTPZiSMiVlSgokZUoK2IMpKZAUSMqU
+FLAHkBRIymaz+bZ7+unnvvSlG9z1B+B/4EFdu8akw+GUqeVyWi4ijrScRyqTzUIqYBeQWNgFpAI2
+C6mAXUBiYReQarOQCtgspEoFbBZS7QISdgGpgI1UwK6EXUCqzUIqG0jKkaQcsQdHknIkKaukHEnK
+KikrezAlZZWUVVKmpKzswZSUKSlTUqakTPZgSsqUFEjKlJQpKWAPIClTUiApU1LAHkBSICmbzeZb
+5xvfOHvPe57l2JvgR3hQ164x6XA4ZWq5nJaLiCMt55EK2NwhFbALSCzsAlIBm4VUwC4gsbALSLVZ
+SAVsFlKlAjYLqXYBCbuAVJuFVLuAhF1Aqs1CKpsHk5R7JeWIPTiSlFVSjiRllZRVUlb2YJWUVVJW
+SZmSsrIHU1KmpExJmZIy2YMpKVNSpqRAUqakTPYAkgJJmZICSQF7MCWVsMtms3kAP/ADz/72b59x
+7H8BcbHnn+cTn2DS4XDK1HI5LRcRR1rOIxWwuUMqYBeQWNgFpAI2C6mAXUBiYVcqYLOQCtgspEoF
+bBZS7QISdgGpNgupdgEJu4BUm4VUNq+CpBxJyhF7cCQpR5JyJCmrpBxJysoerJIyJWWVlFVSJnsw
+JWWVlCkpU1ImezAlZUoKJGVKypQMm91u2LWbVGpSCakSElCJzebRsPvt337il3/5pbe97cV3vAPY
+3bjxB//lv3zsy1/+xhNPfPn7vu+l7/keJO7r6aef+9KXbnDX6+FHwVzsU5/iU59i0uFwytRyOS0X
+EUdaziMVsLlDKmAXkFjYBaQCNgupgF1AYmFXKmCzkArYSAWkAjZSAbuAhF1Aqs1Cql1Awi4g1UYq
+m9eMpNwrKUfswZGkHEnKkaSsknIkKSt7sErKKimrpExJWdmDKSlTUlZJpe523e/PdrvudmO/H0mT
+kdSuXRu7dtlsHgnf+3f/7tt/4Ree/dEfff6P//HD3/k73/2Lv3h2cqIxaH3r1vPf//2/+hM/wflu
+3eozz/zG88/f4K7vgg/zQD75SX7zN5l0OJwytVxOy0XEkZbzSAVs7pAK2AUkFnYBqYDNQipgF5BY
+2JUK2CykAjZSAamAjVTALiBhF5Bqs5BqF5CwC0i1kcrmEZKUeyXliD04kpQjSTmSlCNJWSXliD1Y
+JWVKevXq2ZUrY7cbJye3r1wZu93Y78duN5ImTZqMpGw2j4Tv/+mf/i+ee+5f/9zPnZye/rc/8zPX
+3/KWX/3Jn7z1Hd8B/KF/8S/e8U/+yf/xUz/11Xe9i3Ncv372wz/82ZdfPuOux+EZHsjHPsYrrzDp
+cDhlarmclouIIy3nkQrYLKQy2QUkFnYBqYDNQipgF5BY2JUK2CykAjZSAamAjVTALiBhF5Bqs5Bq
+F5CwC0i1kcpmc5Gk3CspR+zBvZImPTk5u3Ll7OTk7OTk9snJ2dWrZ1eujGTs92O3G/t9d7ux2w02
+m0fCW3/pl/7rv/k3X3nzm7/w7nf/0X/8j0fyf/2lv/TCO9958p/+0x/9uZ97wxe/+Et/62+9/La3
+cY7r18+eeupZjn0n/FUeyLVrrHQ4nDK1XE7LRcSRlvNIBWwWUpnsAhILu4BUwGYhFbALSNgFpAI2
+C6mAjVRAKmAjFbALSNgFpNospNoFJOwCUm2kstm8Ona7npzcPjk5e+yx2ycnt09Ozk5Ozq5ePdvv
+x35/tt93vz/b78d+P9hsHhVv/Nzn/puf/dmT01Pfvs1CKmC//La3ffqjH33p7W/nfDdvjne/+zMc
+uwo/wQO5do2VDodTppbLabmIONJyHqmAzUIqk11AYmEXkArYLKQCdgEJu4BUwGYhFbCRCkgFbKQC
+dgEJu4BUm4VUu4CEXUCqjVQ2m1fHbteTk9snJ2ePPXb75OT2ycnZycnZ1atn+/3Y78+uXBn7/djv
+x2432GweORpjf/36SG4/9hgSD+bP/tlf5f/lGg/k2jVWOhxOmVoup+Ui4kjLeaQCNgupTHYBiYVd
+QCpgs5AK2AUk7AJSAZuFVMBGKiAVsJEK2AUk7AJSbRZS7QISdqUCNlLZbF4du11PTm4/9tjtk5Oz
+k5Pbjz12dvXq2dWrZ/v92O/PrlwZ+/3Y78duN9hsfk963b/7d//dRz7imzf5//Nj/Pcf509wjQdy
+7RorHQ6nTC2X03IRcaTlPFIBm4VUJruAxMIuIBWwWUgF7AISdgGpgM1CKmAjFZAK2EgF7AISdgGp
+NgupdgEJu4BUG6lsNq+O3a4nJ7dPTs4ee+z2ycntk5Ozk5Ozq1fP9vux359duTL2+7Hfj91usNk8
+cnLr1u769e52N3/f78PmAdy82Xe/+9McO4Ef54Fcu8ZKh8MpU8vltFxEHGk5j1TAZiGVyS4gsbAL
+SAVsFlIBu4CEXUAqYLOQCthIBaQCNlIBu4CEXUCqzUKqXUDCLiDVRiqbzatjt+vJye2Tk7PHHrt9
+cnL75OTs5OTs6tWz/X7s92f7fff7s/1+7PeDzeaR4Fu33vkP/+F3/5t/c+Wll2iRmCp944knPv3R
+j37tD/9hznfrVv/8n/80x67CT/BArl1jpcPhlKnlclouIo60nEcqYLOQymQXkFjYBaQCNgupgF1A
+YmFXKmCzkArYSAWkAjZSAbuAhF1Aqs1Cql1Awi4g1UYqm835knKvpNzLHhxJypT05OTsscduX716
+duXK2cnJ2dWrZ1evniXd7cZuN/b77nZjtxtsNo+Ed/6jf/SH/vk/f/Ed7/g/P/CBF/7IH0EC8sor
+b/jiF9/xT//pd/7bf/u/ffzjX3/72znH9etnTz31LMe+E/4qD+TaNVY6HE6ZWi6n5SLiSMt5pAI2
+d0gF7AISC7uAVMBmIRWwC0gs7EoFbBZSARupgFTARipgF5CwC0i1WUi1C0jYBaTaSGXzSEjKvZJy
+xB7cKylHknIkKaukHEnKyh6skrJKane/H1eujCtXzq5cObtyZex248qVkYykSZORNCmbzSPhT/y1
+v/bGL3zhf/0H/+DmG97Avf6rT3ziu3/xF//3n/mZF975Ts7x0ku3/8pfee769TPuegKe5oF87GO8
+8gqTDodTppbLabmIONJyHqmAzR1SAbuAxMIuIBWwWUgF7AISC7tSAZuFVMBGKiAVsJEK2AUk7AJS
+bRZS7QISdgGpNlLZvAYk5V5JOWIP7pWUI0lZJeVIUlZJWdmDI0mZkrJKyiopkz1YJWVKypSUSeqV
+KyMZu12vXDlLmnS3G3bt2rWxa5fN5pHwxs9//vv+xt+48vWvX3/rW2++/vX7l18++epXaXPzJvC5
+9773C08+yflu3eqHP/wbX/7yDe56C3yIB/LJT/Kbv8mkw+GUqeVyWi4ijrScRypgc4dUwC4gsbAL
+SAVsFlIBu4DEwq5UwGYhFbBZSJUK2Cyk2gUk7AJSbRZS7QISdgGpNgupbL6lknIkKfeyB0eSciQp
+q6QcScoqKSt7sErKKimrpExJWdmDKSmrpExJmZIy2YMpKVNSpqRAUqakUJvdbthNho3UpBJSJaQC
+EpvNI2N//fobP//5P/CZz7z5058GXnnzm1/6nu85fde7Tr/3e8+uXuUiTz/93Je+dIO7Xg8/CuZi
+n/oUn/oUkw6HU6aWy2m5iDjSch6pgM0dUgG7gMTCLiAVsFlIBewCEgu7gFSbhVTAZiFVKmCzkGoX
+kLALSLVZSLULSNgFpNospLK5SFLulZQj9uBIUo4kZZWUI0lZJWVlD1ZJWSVllZQpKSt7MCVlSsqU
+lCkpkz2YkjIlZUrKlBRIymQPIClTUiApkJTJHkBSICmbzebB/Lk/9+nbt8tdhv+ZB/L883ziE0w6
+HE6ZWi6n5SLiSMt5pDLZLKQCdgGJhV1AKmCzkArYBSQWdgGpNgupgM1CqlTAZiHVLiBhF5AK2EgF
+7ErYBaTaLKTye1tS7pWUI/bgSFJWSTmSlFVSVklZ2YNVUlZJWSVlSspkD1ZJmZIyJWVKymQPpqRM
+SYGkTEmZkgL2YEoKJAWSMiUF7AEkBZKy2Wy+pb7+9ds/+IO/xrHvgg/zoK5dY9LhcMrUcjktFxFH
+Ws4jlclmIRWwC0gs7AJSAZuFVMAuILGwC0gFbKQCNgupUgGbhVS7gMTCrlTARipgV2JhV6rNQiqP
+uqQcScoRe3AkKaukHEnKKimrpKzswSopq6RMSVklZbIHU1KmpExJmZIy2YMpKVNSpqRAUqakgD2Y
+kgJJmZICSQF7AEmZkrLZbL7tnn76uS996QZ3PQ7P8KCuXWPS4XDK1HI5LRcRR1rOI5XJZiEVsAtI
+LOwCUgGbhVTALiCxsAtIBWykAjYLqYBUm4VUwK7Ewq5UwEYqYFdiYVcqYCOVR0JSjiTliD1YJeVI
+UlZJWSVllZSVPVglZZWUKSmrpEz2YErKlJQpKVNSJnswJWVKCiRlSgokZbIHkJQpKZAUSMpkDyAp
+kJTNZvPa8+STn3nllcFdO/gpEA/k2jUmHQ6nTC2X03IRcaTlPqQCNgupgF1AYmEXkArYLKQCdgGJ
+hV1AKmCzkGqzkApItVlIBexKLOxKBWykAnYlFnalAjZS+d0jKfdKysoeHEnKKilHkrJKyiopK3sw
+JWWVlCkpq6RM9mBKypSUKSlTUiZ7MCUFkjIlZUoKJGWyB5AUSMqUFEgK2ANICiRls9n8rvLSS7ff
+//7P3rgxuOut8EEe1M//PL/yK4AOh1OmlstpuYg40nIfUgGbhVTALiCxsMskFbCRCtgFJBZ2AamA
+zUKqzUIqIBWwkQrYlVjYBaTaLKTaBSTsSgVspPKalJQjSTliD44kZZWUVVJWSVklZWUPpqSskjIl
+ZZWUyR5MSZmSMiVlSspkDyApU1KmpEBSpqSAPZiSAkmBpEBSJnsASYGkbDabR8UP//BzX/7yDe4K
+/CSEB/LKK3zsY4AOh1OmlstpuYg40nIfUgGbhVTALiBxh11AKmCzkArYlVjYBaQCNgupgI1UQCpg
+IxWwC0jYBaTaLKTaBSTsAlJtpPIakJQjSVnZgyNJWSVllZRVUlZJWdmDKSmrpExJmZKysgdTUqak
+TEmBpEz2YErKlBRIypQUSMpkDyApkBRIypQUsAeQFEjKZrN5pL300tl73/ssx56Ap3kI164BOhxO
+mVoup+Ui4kjLfUgFbBZSAbtMEgu7gFTAZiEVsAtI2AWkAjYLqYCNVEAqYCMVsAtI2AWk2iyk2gUk
+7AJSbRZS+fZKypGkrOzBkaSskrJKyiopq6RM9mCVlCkpq6RMSZnswZSUKSlTUqakgD2YkjIlBZIy
+JQWSMtkDSAokBZIyJQXsASQFkrLZbH5Pev/7P/vVr97kLsFfB/Og/vbf5sUXdTicMrVcTstFxJGW
++5AK2CykMtkFJBZ2AamAzUIqYBeQWNgFpNospAI2C6lSAZuFVLuAxMKuVMBGKmBXYmFXqs1CKq+y
+pKyScsQerJKySsoqKaukrJIy2YNVUqakTElZJWWyB1NSpqRMSYGkTPZgSgokZUoKJGVKCtgDSMqU
+FEgKJAXsASQFkrLZbDbTyy/f/ot/8ddv3y53vRU+yEP4rd/i7/99HQ6nTC2X03IRcaTlPqQCNndI
+BewCEgu7gFTAZiEVsAtILOwCUgEbqYDNQiog1WYh1S4gsbArFbCRCtiVWNiVCthI5VstKaukHLEH
+q6SskrJKyiopU1JW9mBKyiopU1KmpEz2YErKlJQpKVNSwB5MSYGkTEmBpExJAXsASZmSAkmBpIA9
+gKRAUjabzeYcLT/0Q7/24ou3uev3w0d5ONeu6XA4ZWq5nJaLiHu1nEcqYHOHVMAuILGwC0gFbBZS
+AbuAxMIuIBWwkQrYLKQCUm0WUgG7Egu7UgGbhVS7gIRdqYCNVL5pSTmSlJU9WCVllZRVUlZJmZKy
+sgdTUlZJmZIyJWWyB1NSpqRAUqakTPYAkjIlBZIyJQWSMtkDSAokBZICSZnsASQFkrLZbDYP5hvf
+OPvQh37jhRducdcb4UfAPIRPflKHwylTy+W0XETcq+U8UplsFlIBu4DEwi4gFbBZSAXsAhILu4BU
+wGYh1WYhFZAK2EgF7AISdgGpNgupdgEJu4BUm4VUHl5SVkk5Yg9WSVklZZWUKSmrpEz2YJWUKSlT
+UqakTPZgSsqUlCkpkJTJHkBSpqRAUqakQFLAHkxJgaRAUiApYA8gKZCUzWazuawbN8aTT36m5T97
+Ap7mYelwOGVquZyWByCOtJxHKpPNQipgF5BY2GWSCtgspAJ2JRZ2AamAzUIqYCMVkArYLKTaBSTs
+AlJtFlIBuxJ2Aak2C6k8mKSsknLEHqySskrKlJRVUqakrOzBlJQpKaukTEkBezAlZUrKlJQpKWAP
+pqRAUqakQFIgKZM9gKRAUiApkBSwB5AUSMpms9l867zvfZ89Pb3JXa+D/4mHpcPhlKnl0louIo60
+3IdUwGYhFbDLJLGwC0gFbBZSAbuAxMKuVMBmIRWwWUiVCtgspNoFJBZ2pQI2UgG7Egu7UgEbqdxX
+UlZJWdmDVVJWSZmSskrKlJSVPZiSMiVlSsqUlMkeTEmZkjIlBZIy2QNIypQUSMqUFEgK2ANICiRl
+SgokBewBJAWSstlsNq+CmzfHBz/43OnpLe66Aj8O5qHocDhlarm0louIIy33IRWwWUhlsgtILOwC
+UgGbhVTALiCxsAtIBWykAjYLqYBUm4VUwK7Ewq5UwGYh1S4gYVcqYCOV/4+krJKysgerpKySskrK
+lJRVUiZ7MCVlSsqUlCkpkz2YkjIlBZIyJWWyB5CUKSmQFEjKlBSwB5AUSAokBZIC9gCSAknZbDab
+V9/Xvnb7Ax/47I0bg7veBP8jmIeiw+GUqeXSWi4ijrTch1TA5g6pgF1AYmEXkArYLKQCdgGJhV1A
+KmCzkGqzkApIBWykAnYBCbuAVJuFVLuAhF1Aqs1CKlNSVklZ2YNVUlZJmZKySsqUlMkerJIyJWVK
+ypSUyR5AUqakTEmBpEz2AJIyJQWSAkmZkgL2AJICSYGkQFLAHkBSICmbzWbz7XXz5njyyc+MwX/2
+ODzDw9LhcMrUcmktFxFHWu5DKmBzh1TALiCxsAtIBWwWUgG7gMTCLiAVsFlIBWykAlIBm4VUu4CE
+XUAqYCMVsCuxsCsVsNntBqukrOzBKimrpExJWSVlSspkD6akTEmZkjIlZbIHU1IgKVNSpqSAPZiS
+AkmBpExJgaSAPYCkQFIgKZAUsAeQFEjKZrPZ/I566qlnr18/4663wId4WDocTplaLq3lIuJeLeeR
+ymSzkArYBSTusAtIBWwWUgG7gMTCrlTAZiEVsFlIlQrYLKQCdiUWdqUCNlIBuxILu7vdAKTaJGVl
+D1ZJWSVlSsoqKVNSJnswJWVKypSUKSmTPYCkTEmZkgJJmewBJAWSMiUFkgJJAXswJQWSAkmBpIA9
+gKRAUjabzeY1oOW973325ZfPuOst8CEelg6HU6aWS2u5iLhXy31IBWwWUgG7TBILu4BUwGYhFbAL
+SCzsAlIBG6mAzUIqINVmIRWwK7GwC0i1WUi1C+x2lQrY3e0GYLOwB1NSVkmZkrJKypSUyR5MSZmS
+MiVlSspkDyApU1IgKVNSwB5MSYGkQFKmpEBSwB5AUiApkBRICtgDSAokZbPZbF57fuiHfv2FF25x
+1+PwDA9Lh8MpU8ultTwAcaTlPqQCNgupTHYBiYVdQCpgs5AK2AUkFnYBqYDNQipgIxWQCthIBewC
+EnYBqYDNbjcAqTb2sLEL7HZDKlNSpqSskjIlZUrKZA+mpExJmZIyJWWyB5CUKSmQlCkpYA+mpEBS
+ICmQlCkpYA8gKZAUSAokBewBJAWSstlsNq9hf/kvf/Y//seb3PU4PMPD0uFwytRyaS0PQBxpuQ+p
+gM0dUgG7gMTCLiAVsLlDKmAXkLALSAVsFlIBm4VUqYDNQipgV2JhV2pSiYXd3W4AUm2SSrW72w1W
+SZmSMiVlSsrKHkxJgaRMSZmSMtkDSMqUFEjKlBSwB1NSICmQFEjKlBSwB5AUSAokBZIC9gCSAknZ
+bDabV9/Nm+Of/bPnP/e5b3zkI//lG96w40jL2Vl3O3G+s7O+//2ffeGFW9z1ODzDw9LhcMrUcmkt
+D0AcabkPqUw2C6mAXUDiDruAVMBmIRWwC0gs7AJSARupgM1CKiDVZiEVsAtI7HYDsCuRDAm7du3a
+LHa7YRfY7QarpExJmZIy2YMpKVNSpqRAUiZ7MCUFkjIlBZIy2QNICiQFkjIlBZIC9gCSAkmBpEBS
+wB5AUiApm81m8230wgu3fvqnP/fCC7c//vF3vvWtVznyC7/w1U984t+/5z1veeqpJzjf+97366en
+t7jrCXiah6XD4ZSp5dJaHoA40nIfUplsFlIBu0wSC7uAVMBmIRWwC0gs7AJSAZuFVMBGKiAVsFlI
+tWvXZiF1txuA3d2ugFS7SaXaJJVqNylTUlZJmezBlBRIypSUKSlgD6akTEmBpEBSJnsASYGkTEmB
+pEBSwB5AUiApkBRICtgDSAokZbPZbH4nfOEL37h27fNf+9rt3U5AIuAtb7kK3Lgxnn/+xp/8k2/6
+sR/7g5zvAx/47Fe+cpO7HodneFg6HE6ZWr4ZLRcR92q5D6mAzUIqk11AYmEXkArYLKQCdgGJhV1A
+KmCzkArYLKQCUm0Wu90ApNrYtQvsdkMqYLPbDcDubjcAm91uAHaTMiVlsgdTUqakTEmBpEz2YEoK
+JGVKCiQF7MGUFEgKJAWSAkkBewBJgaRAUiApYA8gKZCUzWaz+R31y7/84s/+7P/9rne97qmn3vq6
+1+2++MXrX/nKjVu3+vzzN37rt27cuDH+9J9+05NPvoXz/eAP/trXv36bux6HD4N4KDocTplavhkt
+FxH3arkPqYDNHVIBu4DEwi6TVMBmIRWwC0gs7AJSARupgM1CKiA1qYRdIBmAzW43ALvAbjckFvv9
+kArs90MqsN8Pm0VSJnswJWVKCiRlSspkDyApU1IgKVNSwB5AUiApU1IgKZAUsAeQFEgKJAWSAvZI
+CiRls9lsXhs+97nrf+/v/fs/82ce/1N/6k08vLOz/sAPfObmzXLX7y8fEeah6HA4ZWr5ZrQ8AHGk
+5T6kMtkspAJ2mSQWdgGpgM1CKmAXkFjYBaQCNgupgM0iGXYBCbt2pSaVWNjd7QZg166NXbt27dq1
+azepzcIeTEmZkgJJmZIy2QNICiRlSgokZbIHkBRICiQFkgJJAXsASYGkQFIgKWAPICmQlM1ms3mE
+nJ31Pe959saNwV0n8OM8LB0Op0wt34yWByCOtNyfVMBmIZXJLiCxsAtIBWzukArYBSQWdgGpNgup
+gI1dqcBuNyQWdu3aBXa7SgV2u2EX2O0K2N3vByB1vx+A3d1uMCVlSgokZUoK2IMpKZCUKSmQFLAH
+U1IgKZAUSAokBewBJAWSAkmBpIA9gKRJ2Ww2m0fRrVv9C3/h2Rs3Bne9CX6Eh6XD4ZRVy6W1PABx
+r5b7kArY3CEVsAtILOwySQVsFlIBu4DEwi4gFbBZJAOwkWrXLrDbFZC62w3Axq5dqUntArvdsFns
+dsMusN8PqcB+P5iSAkmZkgL2YEoKJGVKCiQF7AEkZUoKJAWSAkkBewBJgaRAUiCpPYCkQFI2m83m
+Nexf/auv3LzZP/bHXv/2tz/GkRdfvP3Vr9584omr3/Ed4XzXr599+MO/8cILt7jru+BDIB6KDodT
+Vi2X1vIAxL1a7kMqk81CKmCXSWJhF5AK2CykAnYBiYVdQCpgY1cqsNsVkGrXro1dqYBduzZ27dq1
+a9cusNvVblK7du3atZv0/2EP/oJ9v+u73j/fr9fns/OHP6FJWsBG7Jn2FDnya6teUnV0ZMaZOqMD
+g0nrHyKBShpAYICprb2QC0cvZIq2Tr3QG3vhTMfhot54UUfpGZ3j2JJCOMUDpWArFchK2AnZ2Xut
+9Xu/ztfvmrXc23Rv9iIhQPp9PAA7rOwAUrOyA9hhZQewA0gN2GFlB7AD2AHsAFIDdgA7gB07gNSA
+HcAOm81m860t4b3v/c3PfObSLbfox37slT/yI991yy1idXycN73pY3/0j77ogx/8/jmL69jv88AD
+jxwcHHLmRfBeMOdSu90BpxKejYSbUFwl4caqAkgsqsJKClDFQgpQFVYSi6oAUoAqFlIAO4AUKVWR
+WNgNSJGQAozRVQHGCCBljAak2KmKhN0SYzQgZc4GpNgB7LCSGrAD2GFlB7ADSA3YYWUHsAPYAewA
+UgN2ADt2ADuA1IAdwA6bzWbz7eD4OO9736d+53cu/8k/ecev/drFO+4YP/dz/9ftt5vVz/zMpz/9
+6ad+9mdf84pX3MJVXvWqVwH7/f549U//6ReuXAnkypX9f/yPv/Po05d4P+dVu90BpxKejYSbUFwl
+4caqAkicqAogBajihBSgKoDEoiqAFKCKhRQpVSzGaKAqElIAuwGJMRqQIkUKMEakAGM0IGWMBqSM
+EWDOlgLM2VLssJIasMPKDmCy+zKmAAAgAElEQVQHsANIzcoOYAewA9gB7ABSA3YAO3YAO4DUgB3A
+DpvNZvPt4/Cwf+qn/utv//blf/yPX/PlLx/+y3/5hd/6rUvf9323P/DAHz466g996Lel+tmffc1L
+Xzo4ddttt/3wD/9wVR0dHQHdeeopbr11HB/3xYtX3vOef/vL/89/5e0gzqV2uwNOJTwbCTehuFbC
+DVSFlcSiKoAUVlUspABVASROVAWQAtgBpAB2AClVkZAipSrAGAGkSJEiRYrEYoyWIkUKMGdXBZiz
+JeyWkCK1jdSs7AB2ADuAHVZSA3YAO4AdwA5gB5AasAPYAezYAaQG7AB22Gw2m283h4f9D//hZz/2
+sSf+2T977Xd+54WEf/NvvvRLv/Q/Ll48ruLOO+c73vFH/sSfeCnXd3jYb3/7J7/85UPOXIC/A8W5
+1G53wKmEZyPhJhTXSrixqgASi6qwkgJUsZDCqiqAxKIqgJQqpAB2ACmA3YCEFCnAGA1UMUYDYzQg
+RYqEFClSgDlbihQpUuxIGaOBOVsKYAewA9hhZQeQGrAD2AHsAHYAO4DUgB3ADmDHDiA1YAeww2az
+2XzbevLJ/cWLR/fccyvX2u9jF19Lkvvu+41Ll/acuQveyXnVbnfAqYRnI+HmFFdJuLGqABInqgJI
+YVXFQgpQFUDiRFWkVLEYo4EqpEgB7AYkpEiRIqWKxRgNSJEiZYwAUuxIkSJFypwNSJEiZc4G5mwp
+gB3ADmAHkBqwA9gB7AB2ADuA1IAdwA5gB7AjNWAHsMNms9n8wXZ42G972yOPPXbEmVvhAyDOpXa7
+A04lPEsJN6G4VsINVIWVxKIqrKQAVSyksKoKILGwG6hCihTADiBFSlWAMQJIkSIFGCPAGF0VYM4G
+qrAjZYwGpNiRMkYDc7YUYM6WYkeKHcAOK6kBO4AdwA5gB7ADSG0HsAPYAewAUtsB7LDZbDYvOAlH
+R314mNtuUxVS8bUcH+dHf/Thy5ebMy+HBzmv2u0OOJXwLCXchOJaCTdWFUDiRFUAKayqWEgBqgJI
+VAWQIlEVYIwGqpAiBbADSJEiRYqEFClSgDEaGKMlFmM0MGcDUsZoYM6WYkeKFDtS5mzADiA1YAew
+A9gB7AB2AKkBO4AdO4AdQGrAjh02m83mheXy5f75n//85z739O/+7uWE7lQxhl7yEr/5zff82T97
+J9f31FP7H//xR5544pgzt8JPcl612x1wKuFZSrg5xVUSbqwqrCQWVWElBahiIYVVVSSqAowRoCpS
+pAB2AClSqpAiBRijAQkpUqRIAcZoKRJSgDEamLOlAHO2FCl2pEiZs4E52w4gNWAHsAPYAewAdqQG
+7AB2ADuAHakBO4AdNpvN5oXl4sXj97znNy9ePHr96+/+3u+9/Qd+4CV3333hqaf2Tzxx/NGPPvav
+//UX3/a2P/wX/sLdXN/993/84OCIM3fDg2DOpXa7A04lPEsJN6e4VsKNVQWQOFEVQAqrKhZSqiKx
+qIoUQKIqUgA7wBgNSJGoCjBGA1IkpEiRIkWKFCkSizEamLOlSLEjRYoUO1LmbGDOlmK3FDuAHcAO
+YAewA0gN2AHs2AHsAFIDduyw2Ww2L0S/8isHv/AL/+1HfuS77r//u7nWww8/8ff+3mde//q7f+In
+XsV1XLq0f/vbP/n440eceRm8m/Oq3e6AUwnPUsLNKa6VcGNVYSWxqAorKUAVC7tZSUipCmAHGKOB
+KqQAUqRILOwGxmhAYowGxmhAihQpUiSk2JEiRYodKXM2IGXOBuZsYM69FDtS7AB2ADuAHakBO4Ad
+wA5gR2rADmCHzWazeYE6ODh63/s+9ZWvHP3QD73k5S+/9dKl/eXL+yefPP7sZ58+POxXv/pFH/zg
+/3nhgri+e+99+NKlPWduhZ/kvGq3O+BUwrOXcHOKayXcWFUAiRNVAaSwqkJKVYAxwsoOYDcgRaIq
+wBgNSEipihQpwBgBxmhAihQpUqTMGUCKFCl2pIzRwJwNzNlS7EiZcw9cuNBS7AB2ADuA1IAdwI4d
+wA4gNWDHDpvNZvMHwK/+6uMf+cgXL148unBBt93m7/7uW+68c77hDa+4447BDR0d9dve9sjBwRFn
+7oB3gTmX2u0OOJXw7CXcnOJaCTdWFVYSi6qwkgLYYWUHkFIVCSlVAaRILOwGpEhIqYoUYIwGxggg
+RYoUKVLmbGCMAFKk2BmjgTkbmLOl2JFit5Q5G5iz7dgB7ABSA3bsAHYAO1IDdgA7bDabzeaGEt74
+xo8dHTVn7oJ3cl612x1wKuHZS7g5xbUSvqaqABInqgJIqWIhpSoSC7sBCSmA3YBEVaRIkVhIqQow
+RgNjBBijASljNDBnA2MEGKMBKXM2MGcDYzQwZ9uR2s6cDczZwJxtx47UgB3ADmDHDiA1YMcOm81m
+s7k5b3jDrx8dhTMvgvdBcS612x1wKuHZS7hpxbUSbqwqrCQWVQGkVLGwm9UYAaoiIaUqgBSJqgBj
+NDBGgKpIkSJFQooUYIwGxmhgzgbGCDBnSwHGaGDOBuZsKXaktiNlzrZjZ84G5twDdgA7dgA7gNR2
+ADtsNpvN5uYcH+etb/3EwcERZ14K7wZxLrXbHXAq4TmRcHOKayV8TVUBJE7YDVQhBaiKhBSgKhJV
+kQKMEVZ2A2MEkCKlKlKkSEgBxmhgjAbmbGCMAGM0MGdLAeZsYM4Gxug598CcDVy40FLsSLlwYQ/M
+2XYAO4AdQGo7gB02m81mc9O6+Wt/7TeefPKYM3fBO6A4l9rtDjiV8JxIuGnFtRJurCqsJKoCSKlC
+ClAViYXdgB1WYzQgURUpUiQWUqRURYoUicUYDYzRwJwNjNHAGAHmbClS7EiRYkfKnA3MuQfmbDtS
+7EixM+fejh07gB2pATuAHTabzWZzTn/pL/1aN//Ly+BvQ3EutdsdcCrhOZFw04prJXxNVWFlB7DD
+ym5AQgpQFYmqSJECSFRFihRgjAB2A1KkAGMEGKOBMRqYs4ExAozRdqRIkWJHih0pUubcA3M2cOFC
+S7EzZwNz7u3YsWNHasCOHTabzWZzfsfH+dEfffjy5ebM7fABzqt2uwNOJTxXEm5aca2EG6sKIFEV
+QEoVUqoCSEgB7ABVkQKMEaAqUoAxAtgNjNGAFAkpUoAxGhijgTkjRYoUO1KkSLEjxY4UKXbm3ANz
+NjBnz9nAhQt7YM6+cKGBOfeAHTtsNpvN5utyfJz77//4xYvHnJnw05xX7XYHnEp4riTctOJaCV+T
+HVZ2A1VIAeywshuQqAowRgApVZEiBRgjQFWkSJGQIkWKFClSpNhIkSJFih0pUqTYkWJHipQ5G5hz
+b0eKHTtzNjDn3o6dCxcamHNvh81ms9l8vQ4P+/77P/Hkk8ecGfB3Oa/a7Q44lfBcSTiP4loJN1AV
+QKIqUoAqpABVSKmKFECiKlIkFlWRIkWKhBSgKlKkSEiRIkWKFClSbKRIkSJFih0pUuxIkWJHip05
+W2o7UuzYkXLhQkttx86cbbcdO2w2m83m63V0lL/5Nz9+8eIxZwb8Xc6rdrsDTiU8hxJuWvEMCddT
+FUCiKoAdVnZY2Q2MEaAqUgA7gBQpwBgB7AakSJGQIkWKFClSpABzRooUKVLsSJFiR4oUO1LszNlS
+25Fix46UOdtuO3M2cOFC2w3YYbPZbDZfl+Pj3H//xy9ePOaM4Wc4r9rtDjiV8BxKOI/iWgm/r6qw
+kqgKIFEVKUAVUqoisZBSFWCMAHYDUiQWdgNjNDBGWI3RwBgNjNHAGAHmbGCMlmJHihQpdqTYkTJn
+A3M2MOfejpQLFxqYsy9c2ANzNmDHbsAOm81mszm/w8N+85s//tWv7jlzAX6K86rd7oBTCc+thJtW
+PEPCM1UFkDhhh5XdgB1WdoCqSJEisaiKFCkSVQHGaECKhBQpwBgNjNHAGAHGaGDOBsZoKXakSLEj
+RYodKXM2MGcDFy7s52xgzrZjtxQ7dgA7gN122Gw2m805HR/nvvsevnKlOfMieD/nVbvdAacSnlsJ
+51FcK+F/IyVhIbGoCiBRFSlVLKRUBbDDaowG7ABSpAB2AClSpEhIkSIFGKOBMQKM0cAYDczZwBgt
+xY4UO1Kk2JmzgTkbmLOl2C3lwoW2I8VuwI4dwA5gtx02m81mc05/+S//+n4fztwB74biXGq3O+Aq
+Cc+hhPMoniHhjBQgQeJEVQA7rOwAVZECSFRFCmAHkCIFsAOM0YAUKRJSqmKnKsCcAcZoYIwGxmhg
+zgbGaCl2pNiRMmcDczYwZ0uxY0dqO3O2HcBuwA5gxw5gN2CHzWaz2dy0++57+Kmn9pz5DngniHOp
+3e6AqyQ8txLOo3iGhBNSWFWxqAqrKqRUBZCoCjBGgKpIAewAUqRUsRijgTEaqMJOVaRIkSKxGKOB
+ORsYo4ExGpizpQBzNjBGA3O2FDtS7MzZduxImXMP2AHs2A3YAewAduwG7LDZbDabm3B0lLe85eNf
++coxZ14G7wJxLrXbHXCVhOdWwjkV10pYSGFVxYmqAFWcsBuQqIoUQKIqgB1gjAaqIrGQIkWKlCoW
+YzQwRgNjBJAyRgNzNjBGA2M0IGXOAHPugTlbQmo7UuzM2cCcLcWO3YAdwA5gN2DHDmAHsNsOm81m
+s7kJb3jDrx8dhTMvhveCOJfa7Q64SsJzLuE8imdIkMKqikVVWFWxkALYYWU3UIWUqgASUqRUBRgj
+gBQpVUiRAozRwBgBpEiRIkXKGA3M2YCE1BJzNjBnA3O2FLulzNnAnA3M2YAdwG7Ajh3AbsAOYMcO
+YDdgh81ms3mh2+8jVRVfnze+8WOHh82Zl8G7Oa/a7Q64SsJzLuGcimtVhVUVJ6oCVHFCClCFlKoA
+UqpY2A1ISKmKFInFGA1UIUWKFCnAGAHGaECKFClSpIwRQIodKVKkzNnAnC3FjhS7JebcA3M2YAew
+A9gN2AHs2A3YAewAduwG7LDZbDYvXN38+I8/8sQTR7/wC6+9887JVb7whSuPPXb02te+mOu7cqUf
+eOATFy8ec+YueAjEudRud8BVEr4REs6puEpVWFWxqAoriQQpQBUn7AaqkCIFsMPKbkBCSlXsVLEY
+o4ExGqhijAak2KmKHSlSJKRIkWJHyhgNzNnAnC0FmLOl2JFiN2AHsAPYsRuwA9gB7Abs2AHsAHbb
+YbPZbF6gvvKVo3e+8zereMtb7nn1q180Rl24oFtv1Rj10Y8+/uEPf+7HfuwP/ZW/8gqu7777Hn7q
+qT1nbocPcF612x1wlYRvhITzK1ZVYVUVKKAqgMSiKqyqWFQFsMNqjAaqkFIVYIwAVZEiRUIKMEYD
+VUiRIkWKFCkSdlexmLOlSJFiR8oYDUixI2XOBuZsKXYAuwE7gB3ADmA3YAewYzdgB7AD2LEbsMNm
+s9m84DzyyFf//t//rSefPL5wQcfHDSTYlVDFfp83vvEVb37zd3MdTz+9f/vbP/nYY0eceSm8B4pz
+qd3ugKskfIMknFOxqgqrqgBVnJBYVAWo4kRVAImqSAHsAFWRIrGwG5AiRWJhNzBGAClSpABjNDBG
+pEiRAszZUqRIAeZsKVKkzNnAnC3FDmCHld2AHcCOHcBuwA5gB7AbsGMHsAPYDdhhs9lsXkB+5VcO
+fu7nPv9n/syd73739xwedjdj1PFxHn308EtfOnz66f33fd/tL3/5LVzf3/gbH3/88SPO3AU/AeZc
+arc74CoJ3zgJ51RAVYCqsJJIkAJUcaKKRVUAiRN2A1VIqQowRoCqSJECjBGgKlIkFmN0VexIAcYI
+MEZLAcZoYM6uCjBnA3O2hNR2JKS2kRqwA9gB7AbsAHYAO4DdgB3ADmC3HcAOYAew2w6bzWbzQvF7
+v3dFqitX+lWvupXze+qp/d/6W49cvHjMmdvhA5xX7XYHXCXhGyfhvKo4URVA4kRVgCoWVWFVxUIK
+VFUAO0BVpEgB7ABSpFSxGKMBKRJSALsBKWMEGKMBKWM0MGcDEmM0MGcDc7YUYM6WYgeQGrAD2GFl
+N2AHsAPYAey2A9gB7AbsAHbsAHYDdthsNps/8Pb73Hvvw1euNGfuhndwXrXbHXCVhG+ohHOpYlEV
+VhKLqrCqYlEVQGJRFVZVLKoiURVAipQqFmM0UIUUKcAYXYWdqgBjNCAxRgNSpEiRIkXCjpQxGpAy
+ZwNzthQ7rOwAUgN2ADuA3YAdwA5gB7AbsAPYAewG7NgB7AB2A3bYbDabP8COjvLAA594/PEjztwG
+7wdxLrXbHXCthG+ohJtUxYmqABInqgJUsagKK4lFVYAqFlUBqliM0UAVUqQAdgApUqoCjBFAyhgN
+VGGnKnakVGG3xGKMlmKnKlLsSJmzASl2ADuAHUBqVnYAO4DdgB3ADmAHsBuwA9gB7LYD2AHsAHYD
+dthsNptvT//qX/3eRz/62Pd//4ve/e7vSfjUp776xS8e3nPPrXZdvtyQ17zmxVxfwn33PXzp0p4z
+d8M7OK/a7Q64VsI3VMJNquKElASJRVVYVbGoCiCxqAqrKhZVAapYSJFSxWKMBqqQIqUqUiQWYzRQ
+hd1VSJEiBRgjUoAxGpizpQBjtBQ7UiTsBuywsgPYAaQG7LCyA9gN2AHsAHYAuwE7gB27ATuAHcAO
+YLcdNpvN5tvNU0/tP/jBz3z600/94i/+4O23G/h3/+7gn/yTz88piaef7ttu07/4F7vbbzfXcXjY
+b3vbI489dsSZW+AnoTiX2u0OuFbCN1rCzahiIYVVFYuqAFWckJIgsagKUMWiKoDEoipAFVKkAHaA
+qgBjNCAhpSoSUqQAY3RVgDkDjNFSgDEakDJGA3O2xGLOBuxmZQeww8oOIDVgB7AD2M3KDmAHsAPY
+DdgB7NgN2AHsAHYAu+2w2Ww23z4ee+zop3/6//vSlw7/+T9/7cteNoHPfvbp97//N//0n77zXe/6
+ngcffOToKB/60GvuuGNw6rbbbnvd615n++joCNjv8/TTue22eXTUTzxx5b3v/bcf+b8/xYMgzqV2
+uwOulfA8SLixKk5IAao4URWgioUUoIoTVQGqWEgBqlhUBahiURU7VSzslgKMEaAqUiQWY3RVgDEa
+kBijASljNCBht0RV7EiZs1nZAexmZQewA9hhJTVgB7AD2A3YYWUHsAPYDdgB7NgN2AHsAHYAu+2w
+2Ww23w66+dCHfvujH33sB37gpT/4gy+R6hd/8b8nPPTQq17/+rsfeuj/vXx5/6EPveaOOwZXueee
+e6rq6Ojo+Pi4uz/84d89OopUTz99/J//839/9NIlPsB51W53wLUSnh8JN1DFCSlAFYuqsKpiIQWo
+YlEVoIqFFKCKRVWAKhZVASSkVAUYo4EqFmN0FYsxGpAyRoCq2JFSFTsSVbEjBRijpczZrOywsgPY
+zcoOYAeww0pqwA5gB7AbsMPKDmAHsBuwA9gB7LYD2AHsAHYDdthsNptvbZcu7T/ykS/+p//0lS98
+4XJVvfKVt9x77yv/1J/6DuBXf/XxO++cr3nNi6TiOvb7vOUtn3jssSPOvBjeC+Jcarc74FoJz5uE
+65FIkMKqikVVgCoWUlhVsagKUMVCClDFoipAFQspCRKLqkiRUoUUKYAdQEpV7FSxGKOlAGO0xGKM
+lgKM0VLsSAHssLID2GFlNys7gB3ADiupATuAHcBuVnYAO4AdwG7ADmAHsBuwYwewA9gN2GGz2Wy+
+5XVHKs7pq1/dP/TQJx977IgzL4cHOa/a7Q64VsLzKeGZJE5UBajiRFUAiUVVgKoAVZyQkpQUoCpQ
+VQGkJCWlKkAVi6rYqWJRlTECVMVOVYAxIgUYoyUWVRmjASlzNjBGSyzsZmWHlR3ADiu7WdkB7AB2
+WEkN2AHssLIbsAPYAewAdgN2ADuA3YAdwA5gx27ADpvNZvOCc3ycN73pY8fH4cyd8C7Oq3a7A66V
+8DxL+N9InKgKUMVCCpAgsagKUBVAIkEKUMWiKkAVCylAFYuqAFUsqgJI2A1ISKmKFGCMAFUZowGJ
+MRqQIkWKRFXsSLHDym5WdljZYWUHsJuVHcAOKzuA1IAdVnYAuwE7gB3ADmA3YAewA9gN2AHsAHYA
+uwE7bDabzbeY7ly6tO/mk5/86qOPHt5zz60Jf/yPv7SKGzs+zr33fuzwMJy5FX6S86rd7oBnSHie
+JVxNYlEVVlUspABVgaoKq6oAEouqAFUsqgJUsZACVLGoShULKUAVi6oAY6QqwBgNVCFFikRV7FQF
+mLOrWMzZVZEC2GFlB7CblR1WdljZAexmZQeww8oOIDUrO4AdwG7ADis7gB3AbsAOYAewG7AD2LED
+2A3YYbPZbL41PPLIk//oH33u8ccP93tuu03Hx9xyS12+3MfHecUrbvkH/+DVd901uY79Pm9608eO
+jsKZO+BvgziX2u0OeIaE51/CGYlFVYCq8D+VFKAqQBWLqgASJ6oCVLGoCiCRIKWKRVUAiUVVgCqq
+AlSxkCKlCilSpFSxGKMBKWM0UMWcDVRFwm5WdljZYWU3YIeVHVZ2WNkN2GFlB7DDSmrADmCHld2A
+HcAOYAewG7AD2AHsBuwAdgA7gN2AHTabzeab5+GHn/zgBz/zvd97+733vuKHfuilY1RCFYvPf/7p
+97znU3/uz9310EOvquJ6/vpf/42vfOWYM98FD0JxLrXbHfAMCd8UCQuJE1UBqgJInKgKUMWiKoDE
+oipAFQspCRKLqgBVLKoCSCyqUsWiKoBEVYAqFmN0VYAxAkipip0qpEiRUsVizmZlNys7rOywspuV
+HVZ2ADus7GZlB7DDyg4gNSs7gB3AbsAOKzuAHcBuwA5gB7AbsAPYAewAdgN22Gw2m+fdf/gPj334
+w5973eu+473v/T+qOLHf56tf3f/SL/2PX/7lL/75P3/XO9/5PVzfAw984ktfOuTMd8JDnFftdgc8
+Q8I3S4LEiaoAVQEkFlVhVcVCSoLEoipAFQspQBWLqgBVLKoisagKUMWiKhKLqgBVVAWQkLoKKXaq
+UsVizq4KMEaksLLDym5WdljZYWU3Kzus7LCyw8puwA4rO4AdVlIDdljZAewG7AB2WNkB7AbsAHYA
+uwE7gB3ADmC3HTabzeZ5dOVK//zP/7d//+8P5lQVc+rKlYbs93nJS8Z9973yL/7F7+L69vu89a2P
+PProIWdeDg9yXrXbHfAMCd9EVYGqCispQBWLqgBVLKSwqmJRFaCKhRSgikVVqlhIAapYVAWoShUL
+KUAVVQGqWEhUBRijq1hIGaOBKsZoQApgh5UdTtnNyg4rO6zsZmWHlR1WdgC7WdlhZQeww0pqwA5g
+h5XdgB3ADmCHld2AHcAOYDdgB7AD2AHstsNms9k8Xy5f7s9//un/8l8u3nXXlOqVr7zlj/2xF0vF
+17Lf561vfeTRRw8583J4kPOq3e6A30/CN0tVgCoWUlhVsagKUMVCClDFoipAFQspQFWgqgJIAapY
+VAWooiqAxKIqVSyqAlQhBaiiKkAVdqRUpQo7UqoC2GFlh1N2WNnNyg4rO5yym5UdwA4rO6zsZmUH
+sMPKDiA1KzuAHVZ2A3YAO4AdVnYDdgA7gN2AHcAOYAewG7DDZrPZfKt64IFPfOlLh5x5Gbyb86rd
+7oDfT8I3RVVYVbGQAlRxoipAFQspQBWLqgASi6oAVQGqWEgBqqgKUMVCClBFVYAqFlWRWFQFqKIq
+QBVSgCrGaEBKFXazssMpO6zscMpuVnZY2WFlNys7rOywssPKblZ2ADus7LCSGrAD2GFlN2AHsMPK
+DmA3YAewA9gN2AHsAHYAuwE7bDabzbeYt7zlE1/+8iFn7oR3cV612x3w+0n4pqgKqyoWUoAqFlVh
+JZEgBahiURVAYlEVoCpAFVKAKhZVASQSpFSxqApQhRSgikVVqlhURWJRlSoWVZGwu4oTdnPKDqfs
+sLLDKbtZ2WFlh5XdrOywssPKDiu7WdlhZQeww0pqwA4rO4DdgB1WdgA7gN2AHVZ2ALsBO4AdwA5g
+tx02m83mW0DCX/2rv/Hkk8eceTk8yHnVbnfAdSQ8/6oCVHFCClDFoiqAxKIqrKpYVAWQWFSlKoBE
+ghSgikVVAImqAFUsqiKxqApQRVWAKqQAValiUYUUoIqqsLLDKbs5ZYdTdljZ4ZTdrOywssMpu1nZ
+YWWHlR3AblZ2WNlhZQeQmpUdwA4ruwE7gB1WdgC7ATuAHcBuwA5gB7AD2A3YYbPZbL557r334UuX
+9px5Bbyd86rd7oDrSHj+VQWo4oQU/n/24C3W9/Qw6/v3eZ619mHqxNjxMQ1OrQgKCn/JkJ58gQqq
+iIpAKALHY3xhEkdxbE9IUylqCSWhCCGQLKJKiDtQhCKUG5QbhCKEKqRGLuLCzNiOLdpSFBwfIk9W
+087Je8+s9T599e75bf+3x3vPXp49B49/nw9ITFIBm0kqIBWQmOwCEpNUwGaSCkhMdiUmqYDEZFdi
+kioVkJjsSkxSJSa7EpNUiW+QlE0y2CRlk5QlKZtksCRlk5QlGSxJWZKyJGVJBktSlqRAUhZ7AElZ
+kgLJYEkKJAWSsiQDSAokBZIBJAWSAkmBZABJ2e12u1fQc8+N97//sfPzctvb4ONclg6HM+6i5ZUn
+FZCY7LJITFIBm0kqIBWwmaQCEpNdQGKSCkjYBSQmqYCEXUAqICEVsJEKSEgFbKQCElIBibtJyiYZ
+bJKyScomKUsy2CRlScomGSxJWZKyJGVJBktSIClLUhZ7AElZkgLJYEkKJAWSsiQDSAokBZIBJAWS
+AkmBZABJ2e12u5fZU09d/PiPf+bGjcFtb4afBnMpOhzOuLuWV5hUQGKyC0jcIhWwmaQCUgGbSSog
+MdkFJKQCEpNdQCogYReQmKRKTHYlJqmAhF1AQiogYVfiWMvdJGWTDDZJ2SRlScomGWySsiRlSQab
+pCxJWZKyJIMlKZCUJSmLPYCkLEmBZLAkBZKyJAWSASQFkgLJYEkKJAWSAskAkrLb7XYP2s2b4+Mf
+/9xXv/ostwX+JzCXomHbS7oAACAASURBVMPhjLtreSVJZZGY7AISk92WyWaSCtgFJCapgMRkV2KS
+CtgFJCapEpNdQEIqYDNJlZik2kxSJSapdlvZlcrzxJGWu0nKJhkcScqSlE1SNslgk5QlKUsy2CRl
+ScqSlCUZLElZkgJJWezBkhRIypIMIClLUiApkAyWpEBSIBlAUiApkBRIBpCU3W63e0A+/OHPPv74
+s9z2Bvg5LkuHwxn31PKKkcpiM0kFJCa7gFRAYrLLIiEVkJjsAhKT3Ra7gIRUQGKyC0jYBSSkAhKT
+XYlJqlRAwq7EJJVvQhxpuZukbJLBkaRskrIkZZMMNklZkrJJBktSlqQsSVmSwZKUJSlLUhZ7AElZ
+krIkA0gKJGVJCiQDSMqSFEgGkBRICiQFkgEkZbfb7b4lzz3XH/3RRy8uym1vg49zWToczrinlleM
+VMDmFqmAxGQXkApITHYBiUkqYDNJBSQmu4BUiUkqYDNJlZjsAhJSAQm7gFSJSarNJFViksqLEEda
+7iYpR5LBJimbpGySskkGS1I2SVmSwSYpS1KWpCzJYEnKkpQlKYs9gKQsSVmSASRlSQokBZLBkhRI
+CiQDSAokBZICyQCSstvtdvfnmWcufvqnP//4489y25vgL4O5FB0OZ7yYlleGVMDmFqmAVMBmkgpI
+THYBiUkqYDNJBaSC7EoFJCa7gIRUQGKyKxUkFbArMUmVmOxKTFIl7HKk5cWIIy33kJRNMjiSlE1S
+NknZJIMlKZukLMlgk5QlKUtSlmSwJGVJypKUxR4sSYGkLMlgSQokBZKyJANICiRlSQaQFEgKJAWS
+ASRlt9vt7uJDH/rM7/3ec9x2Hf4HEJeiw+GM+9DyCpAK2ExSWaQCNpNUQGKyC0hMUgGbSSogFbCR
+CkhMdgEJqYDdVnalAjZSAQmpgI1UQKrEZFfiblrugzjScg9J2SSDI0nZJGWTlE0y2CRlScomGSxJ
+2SRlScqSDJakLElZkrLYgyUpkJQlGUBSlqRAUpZkAEmBpCzJAJICSYGkQDKApOx2ux187WsXH/zg
+p8/Py21vhUe4LB0OZ9yHlleAVMBmkgpIZbGZpAI2k1RAYpIK2AUkJqk2k1TAZpIqFSQVsCsxSQVs
+pAISdgGpEpNUm0mqxH1quQ/iSMs9JOVIMtgk5UhSNknZJINNUpakbJLBkpRNUpakLMlgScqSlCUp
+iz1YkrIkBZLBkhRIypIUSAZLUiApkAwgKUtSICmQDCApu93uO89HPvKbX/nKTY79AoRL0eFwxv1p
+eblJBWwmqYBdoMVmkgrYTFIBqYDEZBeQsAtITFIBm0mqVMBmkioxSbWZpAJ2JSapEpNdCamAxLes
+5cWIO7XcQ1KOJINNUo4kZZOUTTLYJGWTlCUZbJKyJGWTlCUZLElZkrIkZbEHS1IgKUsyWJICSVmS
+AslgSQokBZIBJGVJCiQFkgEkZbfbvX4988zFww8/xrG3wce5LB0OZ9y3lpeVVMBmkgrYBSRukQrY
+TFIBqYCNVEBisgtITFIBuxKTVMBGKiAx2ZUKSNgFJKQCNlIBCamAzW0tL0XL/RFHWu4tKZtkcCQp
+m6QcScomGWySsknKkgw2SdkkZUnKkgyWpCxJWZKy2IMlKUtSlmQASVmSAklZkgEkZUkKJANICiRl
+SQokA0jKbrd7XfjoRz/3pS/d4LbAz8MJl6LD4YxLank52GWRmKQCdgGJSSpgc4tUqYDNJBWQmOwC
+EpNUwK7EZBeQkApITHalAhJ2AQm7LTZSAak2Unme+GZaXqKW+yDu1HJvSTmSDDZJOZKUTVKOJINN
+UjZJWZLBJilLUjZJWZLBkpRNUpakLPYAkrIkZUkGS1IgKUtSIBksSYGkQDJYkgJJgaRAMoCk7Ha7
+bx9PP33xYz/2mRs3Bre9HT7GZelwOOPyWh44uyxSAYnJLiAxSQVsJqmAXUBikgpITHYBicmuVEBi
+sgtISAXsSkxSARupgIRdQKrEZFdCKncl7qLlJWq5P+JOLfeWlCPJ4EhSNkk5kpRNMtgkZZOUTTLY
+JGVJyiYpSzJYkrJJypKUxR4sSYGkLMlgScqSFEjKkgwgKZCUJRlAUiApS1IgGUBSdrvdg/aGL37R
+zz771O///eP0lMv74Ac//eST59xm+AUQl6LD4YxvVcsDZJdFKiAx2QUkJrstNpNUwC4gMUkFbCap
+gMRkVyogMdmVmOwCUiUmqTaTVMBGqlTARiogIZVLE3fR8tK13B9xp5Z7S8qRZHAkKUeSsknKkWSw
+ScomKZtksEnKkpRNUpZksCRlk5QlKYs9WJKyJAWSwZKUJSmQlCUZLEmBpEAyWJICSYGkQDKApOx2
+u0u68sQT7/mlX3rz5z//v3/iE098//dz5C2PPfaf/uN//H994ANf/aEf4i4uLvrII5//0pducNtb
+4REuS4fDGS9NywNhl0UqIDHZBSQmu4BUQGKyC0hMUgGbSSog1WaSCti02JWY7AJSJSa7EpNUuyCp
+UgEbqYCEXTYtL5m4i5YHouX+iDu1vKikHEkGR5JyJCmbpBxJBpukbJKySQabpGySsiRlkwyWpCxJ
+WZKy2IMlKUtSlmSwJGVJCiRlSQaQlCUpkAyWpEBSICmQDCApu93uyHd94Qv/xd/4G6dPPfX//cAP
+PPV93/e1t771a295yzPvfOf59etvffTRP/zLv/xbf/bPfu4nf5K7+NrXxvvf/yjH3gT/HZelw+GM
+B6TlpbALSGWRmOwCEpNdQCogMdkFJCa7gFSQVECqzSQVsJmkSgVsJqk2LXYlJql2AQm7gIRUwK7E
+fWp5ycRdtDwoLfdN3KnlRSXlSDI4kpQjSTmSlE0yOJKUTVI2yWCTlE1SlqRsksGSlCUpm6Qs9mBJ
+ypKUJRlAUpakLEmBZLAkBZKyJANICiRlSQokQ8Iuu913gLd8+tP/2d/6WxdXr15cu6bzc5+f++JC
+5+c+P/f5eeH/+NCH/t373sfdPfzwY888c8Gxvw7iUnQ4nPGgtXwL7AJSWWwmqYDEZBeQCkhMdgGJ
+yS4gFZCwC0hMdgEJqYBUwEYqYDNJlQrYSAVspAISUgG7Eg9Ky4Mg7q7lAWq5b+JOLS8qKXdKBkeS
+ciQpR5KySQZHkrJJyiYZbJKyScomKUsy2CRlScqSlMUeLElZkrIkgyUpS1IgKcvJybBr9/R0SD05
+qV2pNlIlJKASu93rwzs/+cn3/NIv/d9/4S/8nx/8IN+Sj370c1/60g1u+274WTCXosPhjJdZy/2w
+C0hlsZmkAhKTXUAqYDNJBSQmu4BUQMIuIDHZBaRKTHYBCamAXUBCKmAjFbCRCki1kQpIvPJaHhBx
+Ty0PUMtliDu13I+kHEkGd0rKkaQcScomGRxJyiYpm2SwScomKZukbJLBkpQlKZukLPawe3LSq1cv
+knFy0itXLpImI6lduzZ27bLb7eC55/rII5/7ylductvb4ONclg6HM14NLd/ALiCVxWaSCkhMdgGp
+gM0kFZCY7AJSARupgFTAZpIqMdkFJKQCdiUmu4CEVMCuxGRXQipgF2jFa17LAyXuqeXBarkM8QIt
+9yMpR5LBnZJyJClHknIkGWySciQpm2SwScpi96GHzk9Px5UrF6en49q18ytXxsnJODlpMpImTUZS
+drsdPPXUxY//+Gdu3Bjc9lZ4hMvS4XDGa4NUQCqLzSQVkJjsAlIBm0kqIDHZBaQCNlIBqYDNJNVm
+kgpItZmk2kxSAak2LXYl7AISUgG7vDSt+HbT8qCJe2p5ObRckniBlvuRlCPJ4E5JOZI0GdevX1y7
+dn716sW1a+cPPXR+9erFlSvj5GScno6Tk3FyMk5PR1J2ux08/fTFBz7wGMd+H/wsl6XD4YzXBqmA
+VMDmFqmAXUBikgrYTFIBu4DEJNVmkgpIBWwmqTaTVECqzSTVZpIKSLWZpNpIBaTaTFJ5bWvFt7mW
+l4d4MS0vk5YXdeXKuHr14qGHzq9dO79+/fyhh86vXz8/PR2np+P09OLKlXF6Ok5Px8nJYLd7XXjo
+K1/5z//m33zDl7+sMWp/4Yd/+PE/9sf+8C//si4uvva2tz36cz93481v5u6ee65//s//G45dhZ/n
+snQ4nPHaIBWQCtjcIhWwC0hMUgGbSSpgF5CYpNpMUgG7gMQk1WaSCtiVmKTaBSTsAhKTVLsSk12J
+yS5317L7lrXi9ajlPl25Mq5evbh+/fz69fNr1y6uXz+/fv389HScno7T04srV8bp6Tg9HScng93u
+25+fe+6P/t2/+/Z//a//w5/5M1/8k3/yrZ/61A/82q/l5s3ffc97nnj3u9/1z/95bt78X//hP3z2
+jW/k7n7kR/7NxUU59tdBXIoOhzNeG6QCUgGbW6QCdgGJSSpgM0kF7AISk1SbSSpgF5CYpNpMUgG7
+EpNUu4CEXUBCKmBXYrIrMdllt3t5nJ6Oq1cvrl8/v379/OrVi2vXLq5fP79y5eLkpKenF1eujNPT
+cXo6Tk4Gu923v9Onn37vz//8G377t3/9n/yTJqdPPfVf/uIvPvTVr/5vf+/v3XjTm/7QP/pH7/6n
+//Rf/e2//f/+gT/A5g1f+MJ//TM/o4sLvpn/nv/2f+G/4n/msnQ4nPEqK4vEJBWwuUUqYBeQmOwC
+EpNUwC4gMdmVCkhMdgGJya5UQGKyKzHZlQrYSAWkAjZSbSapUgGb3Tclle9IEg/K6em4evXi2rXz
+69cvrly5uH79/Nq1i9PTcXo6Tk8vrlwZp6fj9HScnAx2u29/urj4wX/wD77/13/9iXe/+5l3vOPa
+44+/8d//+9rPvvGN5w899B998YsX1679i1/5lXFywl20/Lk/9ymOGX6Ry9LhcMaDUV4aiUkqYHOL
+VMAuIDHZBSQmqYBdQGKyKxWQmOwCEpNdqYDEZFdisisVsJmkSgVs7EoFJOwCEq8Mqbx+SbzqpPJy
+kris09OLq1fHtWvnV66Ma9fOr127uHbt4vR0nJ6O09OLK1fG6ek4PR0nJ4Pd7nUhN2/+J//sn/3B
+X/3V2sCn/spfOfsjf+QP/cqvfPdv/dZX3vveL/zwDzfh7i4u+JEf+RTHTuCvcVk6HM64tPIykJik
+sthMUgG7gMRkF5CYpAJ2AYnJLiDVZpIK2AUkpAI2k1S7gIRUwGaSaheQsCsVkLALSHwDqbwuSLxa
+pPLykLik8s1I3I+k3Mkud0rKkaRs7HH16rh+/fzKlXHlysXVqxenp+Pq1YuTk56cjJOTcXo6Tk5G
+Una7HTz99MUHPvAYx34f/CyXpcPhjPtSXmYSk1QWm0kqYBeQmOwCUgGbSSogMdkFpNpMUgG7gIRU
+wGaSaheQkCohFbCRCkjYBaTaSAXs8loi8aqQyoMmcUnlBSTuR1LuZJc7JeVIUo7Y5UgyOGKXTVKO
+JGVjl01Su6en4+RkXL16cXLS09Nx9epF0mQkTZqMpEnZ7Xbw5JPnH/7wZ2/cGNz2dvgYl6XD4Yx7
+Ka8Uickui1RAYrILSEx2AamAzSQVkJjsAlJtJqmAXUDCLiAVkLALSEx2pQI2UgEJu4BdqRKTXV42
+Eq8kqTxoEpdRXkDiRSXlTna5U1KOJOWIXY4kg41djiRlk5SNXTZJ2SRlY5clKRu7LElZksFyclK7
+Jyfj9HQkTXpyMuzaTWpXwq5ddrvXkWtnZ9/7G7/xlsceu/7449cff1xj/D8/+INf/BN/4nff856b
+b3oTd/fcc/34xz/3O79zk9veDh/jsnQ4nHFX5RUkMdllkQpITHYBickuIBWwmaQCdgGJSarNJBWw
+C0jYBaQCEnYBu4CEVMBGKmBXYrIrFZCwyyVJvDKk8kBJXEZ5AYkXlZQ72eVIUo4k5YhdjiSDjV2O
+JGWTlI1dNklZkrKxyyYpi12WpCzJYGOXJSlLUsAuS1IWuyxJgdPTIdUmGRLJkJCQKiEVkNjtXjcO
+f//vf9+//Je+uKh943u+5+m3v/3mm9+cmzff+uijwCc/8Ykn3/Uu7u5jH/vcF794g9u+G34WzKXo
+cDjjmyuvLInJLotUQGKyC0hMdgGpgM0kFbALSExSARupgF1AYrIrFbCZpNoFJKQCNlIlpEpMdqUC
+NlK5k8QrQCoPjsR9Ky8g8aKScsQuR5JyJClH7HIkGWzsciQpm6Rs7LIkZZOUjV2WpGzssiRlSQaL
+XZakLElZ7LIkBeyyJAWSstgFksGSFLALJGWxK2GX3e47wzs/+ck/+olP/Paf+lO/+dGPNuHIlSee
++G9+4ie+/Mf/+Kd/5me4u/e979GbNwe3GX4BxKXocDjjmyivOIlb7AJSAZtJKmAzSQWkAjaTVMAu
+IDHZBaTaTFIBicmuVMBmkmoXkLALSLWZpEpMdu0CEnZ5eUjlQZC4b+UFJO4tKXeyy5GkHEnKEbts
+ksERu2ySsknKxi5LUjZJ2dhlScpil01SlmSw2GVJypIUsMuSlMUukJQlKWCXJRlAUha7QFLALpCU
+3W53p7d8+tM/9Hf+ztfe9rZ/+6EPPfmudz37Xd91ce3alSeffMcnP/kDv/ZrDz3++G9+5CP/4U//
+ae7iqacu/uJffIxjb4OPc1k6HM74RuXVIHGLXUAqYDNJBWwmqYBUwGaSCtgFJCa7gFTARipgF5Cw
+C0hMUu0CEnYBqYCNVLuAhF1Awi4vgVQeBIn7U15A4t6ScsQuR5JyJClH7LJJBkfssknKJikbuyxJ
+2SRlscsmKYtdlqQsyWCxy5KUJSmLXSApi12WpEBSFrtAMoCkLHaBpIBdICm73e5b8r2/8Rt/8Fd/
+9aEvf1mgMWhrP/eGN/zOe9/77973vmfe8Q7u7uKijzzy+S996Qa3vRUe4bJ0OJzxjcqrQeIWu4BU
+wGaSCthMUgG7gMQkFbALSEx2AamAjVTALiAx2ZWY7EoFbCapUgEbqRJSbSapUm3uh1QeBIn7U+4k
+cW9JOWKXI0k5kpSNXY4kg41dNknZJGVjlyUpm6QsdtkkZbHLkpQlGSx2WZKyJAXssiRlsQskZUkK
+2AWSwZIUsAskZbELJGW3271scuMG0sXVq1zSww8/9swzF9wW+GsgLkWHwxl3KK8SiVvsAlIBm0kq
+YBeQuMWuxCQVsAvYTFIBqYDNJNUuIDHZlQrYTFJtJql2Aak2k1SbSapdiReSyksjcX/KnSTuLSlH
+7HIkKZukHLHLJhls7LJJyiYpG7ssSdkkZbHLJimLXZakLMlgscuSFEjKYpclKWCXJSmQlMUukAwg
+KYtdIClgF0jKbrf7tvLEE+c/8ROfvXFjcNt/DD/JZelwOOMO5dUjMdkFpAI2k1QWu4DEZBeQCthI
+BWwmqYBUCYnJrlRAYrIrVUJikmoXkLAL2JWYpNoFJOwCdnlpJO5DuZPEvSXliF02STmSlI1djiSD
+jV02SVmSsrHLJilLUha7bJKy2GVJypIMFrtAUpakLHaBpCx2gaQsSQG7LMkAkgJ2gaQsdoGk7Ha7
+14uPfOQ3v/KVm9wW+KsQLkWHwxlfV15VEhJSAamAzS1SAbuAxGQXkArYTFIBuxKTXUBisgtItZmk
+AnYlJql2AZtJql1AQqqEVBupgF0uQ+I+lDtJ3ENSjtjlSFI2STlil00y2Nhlk5QlKRu7LEnZJGWx
+y5KUxS5LUpZksNhlScqSFLDLkhSwy5IUSMpiF0gGkBSwy5IUsAskZbfbva4988zFww8/xrG3w8e4
+LB0OZ3xdeVXZTFIBqYDNLVIBu4DEZBeQCthMUgG7gIRdQAJqM0m1maQCdqUCNpNUm0mqXUCqzSTV
+LiBhl3uSuA/liMQ9JOWIXY4kZZOUjV02yWBjl01SNklZ7LJJypKUxS6bpCx2WZICyWCxy5KUJSlg
+lyUpYJclKZCUxS6QDCApYJclKWAXSMput/uO9OEPf/bxx5/lNsEvgLkUHQ5nfF15VdlMUgGpLDaT
+VMAuIDHZBaQCNpNUwC4gMdmVCthMUgG7EpNdQKrNJNUuIGEXsCsx2ZUKSNjlThL3oRyRuIekHLHL
+JilHkrKxyyYZbOyyJGWTlMUum6QsSVnssiRlscuSlCUZLHZZkgJJWeyyJAXsAklZkgJ2gWSwJAXs
+AkkBu0BSdrvdbnnyyfMPfegz5+fltnfCT3FZOhzO+LryqrKZpLLYBSQmqYBdwGaSCkgFbCapElIB
+icmuVMBmkgrYlZjsAnYlJqmAXZtJql1Awi4g1UYqIPFiyhGJe0jKEbtskrJJysYum2SwscsmKUtS
+NnZZkrJJymKXJSmLXZakQDJY7LIkZUkK2GVJCtgFkrIkBewCyWBJCtgFkgJ2gaTsdrvdXbT8pb/0
+md/7vee47Tr8j1yWDoczvq68qmwmqSx2AYlJKmAXsJmkAlIBm8kuIBWQkJAK2JWYpAJ2ARupgF1A
+wi4g1WaSaheQsAvYlQrY3EU5InEPSdnYZZOUI0nZ2GWTDBa7bJKyJGVjlyUpS1IWu2ySAnZZkrIk
+g8UuS1IgKYtdICmLXSApkJTFLpAMIClgF0gK2AWSstvtdvft6acvHnnkc2dnz3Hbm+Avg7kUHQ5n
+PK+82uyySEx2AQmozSQVsJmkstiVmOwCUgGbSSpgF5BqM0kFbKASdgEJu4BdQKrEZNcuIGFXKmBz
+pByRuJukHLHLJimbpGzsskkGG7ssSdkkZbHLkpRNUha7LElZ7AJJWZLBYpclKZCUxS6QFLDLkhRI
+CthlSQaQFLALJAXsAknZ7Xa7b9XNm+P97390DL7ue+EjXJYOhzOeV15tdlkkJruAVMDmFqmAXUBi
+sgtIQG0mqTaTVMAuIBWwkQrYBSTsAnYBCbuAVJtJql3ARiog1S5HJO4hKRu7bJKyScrGLptksLHL
+kpQlKRu7LElZkrLYZUnKYpclKUsyALssSYGkLHaBpCx2gaRAUha7QDKApIBdIClgF0jKbrfbPTg/
+9mOfOTt7jtveAD/HZelwOON55TXALiAx2QWksthMUgG7gMRkF5AK2ExSAbsSk13ALiAxSbUL2ExS
+7QISdgGpgF2bSaoNVMKuVEDibpKyscsmKZukbOyySQYbuyxJWZKyscuSlCUpi12WpCx2WZICyWCx
+CyRlSQrYZUkK2GVJCiQF7ALJAJICdoGkgF0gKbvdbvfyuHlzfPSjn/vd332W207gr4K5FB0OZzyv
+vAbYBSQmuyxSAZtJKmAXkJjsAlIBm0kqYBeQkJBqF5CY7AJSbSapgF2Jya5dQKrNJNUuIGEXsMsL
+JGVjl01SNknZ2GVJBhu7LEnZJGWxy5KUJSmLXZakLHaBpCzJYLELJGVJCthlSQrYBZKyJAXsAskA
+kgJ2gaSAXSApu91u9/J74onzD3/4szdvDm77HngEzKXocDjjeeU1wC4gcYtdQCpgM0kF7AISk11A
+KmAzSQXsAjaTVMCuxGQXkArYlZjs2gUkJrtSARupElLtAjZS2SRlY5dNUjZJWeyySQaLXTZJWZKy
+2GVJypKUxS5LUha7LEmBZLDYBZKyJAXssiQF7AJJWZICdoFkAEkBu0BSwC6QlN1ut3tlPfvs+NEf
+fWyMcts74KNclg6HM55XXgPsAhK32AWkAjaTVMAui4SEVEAqYGMXkArYQCUmu4CEXUAqYNdmkgrY
+lZjsSpWQajPZlQrYSE3Kxi6bpCxJ2dhlkwwWu2ySsiRlscuSlCUpi12WpIBdlqQsyQDssiQFkrLY
+BZICdlmSAkkBu0AygKSAXSApYBdIym63272qHn74sWeeueC2d8JPcVk6HM54XnkNsMsiMdkFpAI2
+t0gF7AI2k1RAqoTEZBeQaheQmOwCUgEbu4BUwEYqYBewKzHZlSohYRc4ORkSk127bJKyScpil00y
+WOyyJGWTlMUuS1KWpCx2gaQsdlmSAslgsQskZUkK2AWSstgFkgJJAbtAMoCkLHaTAnaBpOx2u91r
+Q8sHP/jYU09dcNs74ae4LB0OZzyvvAbYZZGY7AJ2WSQm/f/swVusr2dh3evfGOP9fAZzzq4DqCSh
+kKB/1aqNRCXa3NCbpJWi0gisqBxNOIRAzkDITtOqbSqkSm1FkHrZu+amN5W6pS0q5aJI2a1KHGw2
+xSRRE0jSYk8fYry8WHPOd/Rb39qesrfjxZrY5uB8z6NKSAVsVlIBu4DEyi4gFbAL2EgFpEpIrOxK
+BWxWUu0CdgEbqYDdpIBdu3ZtpAJJeUxSNnZ5TDLZ2GWTlMckZWOXTVI2SQG7bJKyscsmKZBMNnaB
+pEBSNnaBpIBdNkmBpIBdIJlAUsAukBSwCyRlt9vtvv284x2fve++Y868FH6S89LhcMT/p3wbkJAK
+SKzssrELSKzsAlIBG6jEyi4gFbBZSZWQCtispAJ2JaA2K6k2UJuVVLuAjVS7dgGJZZlSAZsxJpuk
+PMYum2SysctjkrJJysYum6RskgJ22SRlY5dNUiCZbOwCSYGkbOwCSQG7QFI2SQG7QDKBpIBdIClg
+F0jKbrfbPZtaJL5hd9xx1//6X5c48wL4ac5Lh8MRl5VvNYkrpAISUgGJlV1AKmCzksrGLiCxsgtI
+BWxWdqUCNiupgF1Aqs3KLiDVZmUXkDpGAaljTMDGrl27UoFlKRu7PCaZbOyyScomKRu7bJKyScrG
+LpCUjV02SYFksrELJAWSsrELJAXsAkmBpGzsAskEkgJ2gaR2gaTsdrvdN8Wc/df/+g8++9mH/8bf
+eMG73/0KHudrX5vA9debp3Z62ne/++57773Eme+C93FeOhyOuKx8S0mckcrGLiCxsgtIZWOzkgrY
+BSRWdgG7gMTKLiAVsLELSAWkSkjYBewCEmNMQCowRu0CUscoYHeMCdi1scsmmWzs8pikbJKysQsk
+ZZOUjV02SQG7bJICyWRjF0jKJilgF0gK2AWSskkK2AWSCSQF7AJJ7QJJ2e12u2+uCxdOP/zhL3z5
+yxcl/vbffsn73vdKHvOpTx39+q//wV//67d+7GPfy1M4Pe0dd9x9332XOPNd8D7OS4fDEZeVbx2J
+x5PKxi4gsbLLUNawZQAAIABJREFURipgs5IK2AUkVnYBu4DEyi4gVUIqYLOSaheQkJBq167Eyu4Y
+E5BYjTHtAmPULiB1jAnYJJONXTZJ2SRlY5dNUjZJ2dgFkrKxCyRlk0zALpukQFLALpCUjV0gKZAU
+sAskE0gK2AWSAnaTstvtdt8iX/nKpZ/92c/feGNe//oX/Mf/eO+LX7x89KPf+6pX3Qg8/PDJ+9//
+uVe+8sZf/dXvWxbzFN71rru+8pVLnHkp/CTnpcPhiMvKt4jEk0kF7AISV9gFpAI2K7uAVDY2K6mA
+XUBiZdcuIBWwWUkF7NqskgnYBZLaBeyOUUBqUqk2qzGmXWCMaRewyyYpm6Rs7LJJCiRlY5dNUsAu
+m6RAMtnYBZICSdnYBZICdoGkQFLALpBMIClgF0gK2AWSstvtdt9S//2/P/Kxj93zmtfc/I/+0au/
+9KVHP/zhL5yc9Md//LbXv/4Fd9/91X/zb/7wh37oRR/60F+UeCpvfetnH3jgmDMvhfeDOBcdDkdc
+Vr4VJP5MUgG7bCRWdgGpgM0VdgGpgM1KKmAXkJAqsbILSLVZ2QWkAmMUkDrGBCRWY0y7wBi1C4wx
+Aak2SaXaHWOyScomKRu7QFI2SdnYBZKysQskZZNMwC6bpEBSwC6QFLDLJimQFLALJBNICthNCtgF
+krLb7XbfHn7ndx7+xCf+4K/9tVvf855XSDz00Mm/+3d/8qlP3XdyUonXvvaWj3zke57//MFTOD3t
+W95y58WLkzPPLx8S4Vx0OBxxWfmmk3gqUtnYBSRWdtlIlZBY2QWkAjZQiZVdwC4gsbILSJWQWNm1
+K9XGrlTA7hgFpCaVarMaY9oFxpiAzRjTLjDGZJOUjV0gKZukbOwCSdnYBZKySSZgF0jKJilgF0gK
+2AWSAkkBu0AygaSAXSApYBdIym63230nuHhx3nCD+XpOT/uWt9x58eLkzA3wEc5Lh8MRl5VvLomr
+kMrGLiBxhV3ALiCxsgtIZWMXkJCQCtgFJFZ27QISdu0CUu3aSLVrFxijgF2pdm3s2rVr166NXbt2
+7SZlYxdIyiYpG7tAUjZ2gaRAMtnYBZICSQG7bJICdoGkQFLALpBMIClgF0hqF0jKbrfbPRednPTH
+fuy3T07KmRfChzgvHQ5HXFa+iSS+LqmAXTYSK7uAXUDiCruAVMAuYLOSCtgFJKRKrOxKtVmNMaUC
+YxSQCoxRu8AYE5C6LAWkjjEBu8tSQOqyTMCuXSApm6Rs7AJJ2dgFkgLJZGMXSAokBewCSdnYBZIC
+SQG7QDKTAnaBpIBdICm73W733PXVr55+4AOfOzo65szL4P2clw6HIy4r3ywS10KqxEoqICEhlY1d
+QGJlF5AK2AVsVlIBu4BdQMKuVMDGrl0gKWB3jAlI2LVr165dYIzaBcaYdoExCtgdY9pNyiYpG7tA
+UjZ2gaRAMtnYBZICSQG7QFLALpukQFK7QDKBpIBdIClgF0jKbrfbfdv79V//w09/+oGPfex7X/e6
+W3ice++99Cu/8sXXv/4Fb33rd0s8lTn7rnfdfd99lzhzE/wchHPR4XDEZeWbQuIa2WUjFbC5Qipg
+F5CA2lxhF5AK2KykSkgF7ErYBZICdseYgMRqjAnYtSth165dYIzaBcaYdu3aBZalUoFlmXaTsrEL
+JGVjF0gKJJONXSApkBSwCyQF7AJJgaSAXSCZQFLALpAUsJuU3W63+87xS790z+c///CP/dhf+Kt/
+9fkve9n1Dz988sgjp7feOm64IR/4wOde9KLl137tNbfeOnicV7ziFW1PNycnJ5/4xB9dvDhtnZzM
+T3/6S/dduMAvcl46HI64rDz7JM7FLiCVjc1KKmCXjVTAZmUXkArYrOwCUu1KrOzalViNMQG7diVW
+Y0y7wBgFpI4xARu7du3atZvUro09bewmtWuXTVLALpCUTTIBu0BSIClgF0jKxi6QNClgF0gmkBSw
+CyQF7CZlt9vtvqPMyT/8h1+8884/HUNAi0RbSS02N92Uj3/8tbfddj2PufHGG9/whjfYPj4+Bubs
+hQu94Ybl5GT+6Z9+7YMf/L/+w2/dw/vAnIsOhyMuK88+iXOxy0YqYAOVuMIuIFVCYmWXjVTALmAj
+1S6QFLBrV2Jld4wJSNi1C4xRwO4YExhjAhLLMgGpSe2OMQG7y1JgjGkXSArYZZMUSCZgF0gKJGVj
+F0gK2AWSAkkBu8kEkgJ2gaSA3aTsdrvdd6DT037847//X//rQ//sn73mNa+5+fS0EomAOSsJkLiK
+S5fme9/7uXvvvcSZBX4JxLnocDjisvIskzgvu2ykAnbZSKzsAnbZSKzsAnYBqUBSwK6NVGCMCUjY
+tQuMUUCqXbs2du0CY0zA7hgFxpiA3TEmsCzTLjBG7Sa1C9gFkgLJBOyySQokBewCSQG7QFIgKWAX
+SGZSwC6QFLALJGW32+2+Y33qU0f33nvpb/2tF373d9/A+bW9/fbfeeSRU868CD7IeelwOOKy8myS
++IbUZiWVjV1A4gq7gF1AYmWXjV2pNiupdm1WyQTs2kgFxpiATTIBu3Zt7Nq1a9cuMEaBMaZdYFmm
+Xbt2bZJpM8YEkrJJJmAXSAokBewCSQG7QFIgKWAXSCaQ1C6QFLALJGW32+3+fDs+nu96190PPHDM
+mRvhF8Cciw6HIy4rzyaJ8ytgc4VUwC4bCQmpgF02ElIlVskEbFbJBGyk2gXGKCDVrl0bu0AyAbs2
+du3atWvXro1du0nt2rVr127SMSZgd1kKJBOwCyQFkgJ2gaSAXSApkBSwCyQTSArYBZLaBZKy2+12
+Ozg97e23/86jj55y5sXwU5yXDocjLivPGonzK4+xWUllYxewWUllYxewC0jYBaTaSAXGKCDVrl0g
+KWDXrs1qjAlIHaPAGBOwa9fuGAXsJrU7xgTs2rW7LBNYlmnXblLALpAUSArYBZICdoGkQFLAbjKB
+pIBdIClgNym73W733DJn77vv+Dd+40/+6I8u/u7vXuCy3nTT+L7vu+mOO15+22038NQuXDh9z3vu
+fvDBE87cAB/hvHQ4HHFZedZInFN5HJsrpAJ22dispAJ22diVsAskBaTatVklE7BrIxUYYwI2du3a
+lQqMUcCuXbtjTMAmqd0xJjDGBOwuywSWZdq1a3dZJpAUSArYBZICdoGkQFLALpBMIKldIClgF0jK
+brfbPbecnPSjH/3CF7944ZZb8upX33zbbde/5jW33HJLvvzli//lvzx4zz2PvP3tL//hH34pT+2t
+b/3sAw8cc+bF8H4I56LD4YjLyrND4pzKE9lcIRWQkArYQCVWElKBpIBdqYCNXanAGAWk2rVZJROw
+a9fGrl0gmcAYtQuMMYFlmYDNGBMYYwLLMu3atQssy7Sb1O6yTCApYBdICtgFkgJJAbvJBJICdoGk
+doGk7Ha73XPR3Xc//Gu/9vuve90tH/nI99jicS5dmu9+910vf/mN//gfvzoRf5ZHHz19z3s+98AD
+x5x5PvwMiHPR4XDEZeVZIHF+5UlsrrALSGVjF7BZSbULSNiVCoxRQKrNyq5Uu8AYBZIJ2LWxC4wx
+pSZIBcaYwLJMYIzaBcaYwLJMu3btJrW7LBMYYyYFlmUCdoGkdoGkQFLALpBMIKldIClgF0jKbrfb
+PUc98MDxT//054+P+3f+zsv+8l9+3s035/77j7/whUfuvffSb/7mUaL3vveVb3zji3lqb37znRcu
+nHLmJvhFzkuHwxGXlWeBxDmVJ5GQuMIuG6mAXTY2Uu0CSdkkBexKtVklE7BrY1eqXWCMAmNMwK5d
+G7t2gTEmMMa0sWsXGGMCyzLt2k06xgSWZQLLMu0mtZsUsAskBZICdpMJJAXsAkntAknZ7Xa7Pwf+
+yT/5vc985iFgTsbQ9df7Va+68Xu+56Z3vvPlXNWlS/Pd7777/vuPOfMi+EkI56LD4YjLyjNN4pzK
+k0hcIXGFXUAqICEVSArYlVjZlWqzSiabMQpItWtjVyowxgTGKGDXrl0bu8AYExhj2rVrY9cusCzT
+rl27Se0uywSWZdq1m9RuUrtA0qSAXSCZQFLAblLALpCU3W63+3OmZSVxjdr+/b9/56VLkzMvgg9y
+XjocjrisPNMkzqk8icQVElfYZWMXkCqxsmtXYpVMNmMUkGpjF0gmYGMXSCYwRgG7du3atbFr165d
+u3bt2ti1m9SuXbtJ7Y4xgWWZwLJMu0mXZdpNCiQF7ALJBJLaBZICdpOy2+12u2vzpjd95tKlcuZm
++HkQ56LD4YjLyjNN4jzKk0g8ngQUsFnZZWMXGGOySQpItbELSLVZJRMYo4BdqXbt2qzGmMAYExij
+gF27du3atWtj1+6yTGCMCSzLBJZl2rWb1G7SMSZw3XXTblLAbjKBpIBdIKldICm73W63uzbHx73j
+jrvuv/+YM7fCh8Cciw6HIy4rzyiJ8yhPIvH/IwEFbK6wK1ViZdcukBSQarNKJmBjF0gmYGNXql27
+wBgFxpjAGAXs2rVr165duzZ27SYdYwLLMoExZlK7dpPaXZYJLMsElmUuywSSCSQF7CYF7AJJ2e12
+u901m5Pbb7/zwoVTzrwIfgrEuehwOOKy8oySOI/yJBJPJhWQkFglk01SwK7EKpmAjVTAro1dqXYB
+G7tS7QJjFBhjAmNMwMauXbt27dq1a2PX7rJMYIwJLMsElmXatZvUbtJlmcCyzGWZwLKcAkntAkkB
+u0nZ7Xa73fn96I9+5vS0nHkhfBDEuehwOOKy8syROI/yJBJPxS4gIRWwK7GyK9VmZVeqjVRgjAJS
+7QJjFEgmYNdmNcYExpiAXRu7du3atWvXro3dZZnAGBNYlgmMMYFlmXaT2k26LNNuUrvLMoHrrju1
+CyQF7CZlt9vtdud3etrbb7/z0UcnZ26CX+S8dDgccVl55kicR3kiiauwC0hIBexKrJLJZowCSdkk
+E7CRatcuMEYBqXZt7Nq1C9i1ayM1qV27du3a2B1jAssygTEmsCwTWJZp1+6yTGBZJrAsM6ndZZnJ
+tJs0qV0gKbvdbrf7hpyc9O1v/+xDD51wZsAvc146HI64rDxzJK5ZeRKJq7MrsZJqV8IuINVmZVeq
+jVS7gI1Uu3YBG7tS7drYBcaYwBgTSAosywTs2h2jwBgTWJYJjDGBZZnAGBNYlrksExhjAssygWWZ
+1103gWWZ9ky6LBNIym632+2+UcfHfcc7PvvQQyecGfDLnJcOhyMuK88QifMoTyTxdSVlk0w2SQEJ
+u0AyARupwBgFpNoFxiiQTMCuzWqMCSQTGKPAGBNYlgmMMYExCowxgWWZwBgTWJYJjDGT2l2WCSzL
+BJZl2k26LBNYltPrrpvAskx2u91u9zQcH8+3ve2uhx8+4cyAX+a8dDgccVl5hkhcs/IkElcnFbCR
+CtiVWNmVsCsVsGuzSiZgIxUYYwJJAbt2gTEKJBMYo8AYExhjAmNMYFkKjDGBMSawLBMYYwLLMu0m
+tWt3WSawLDOp3aR2r7tu2k2m3aRJ2e12u9036uSk73jHXQ8+eMyZwP/JeelwOOKy8gyRuGbliSS+
+LqlskgI2UoGkgF2pgI1dqXYBCbt27QISdu3atbErFRhjAmMUGGMCY0xgjALLMoExJjDGBJZlAmPM
+pHbtJrWb1O6yzKR2k9pdlpk0qT2BpEnZ7Xa73Tfk+Hi+7W13PfzwCWeug1/ivHQ4HEF5hkhcs/Ik
+ElcnlY3NSqqNVLuAhF0gKZtkAkkBu3aBpIBduzZ2pdq1C9i1sWvXrt0xCowxgWWZwBgTWJYJjDGB
+ZZl27Sa1a3dZJrAsM6nd666bwLJMIKk9gaRJ2e12u935nZ72LW+58+LFyZlb4Oc5Lx0OR1CeIRLX
+rDyRxNclFbC5IimbZAISdgGpNlLt2qyk2gWSAmNMwK7NKpnAGBOwsWvXrl27NnbtjjGBZZnAGBNY
+lgmMMW2SaZNMm2U5BZZlAssy7SZdlgkkBZLaE0gKJGW32+125/SjP/qZ09Ny5vnwMyDORYfDEZRn
+iMS1KU8icXVS2dispAI2UgG7EqtkAjZSgTEKSLVrF5Cwa9cukBQYYwJjFLBr165duzZ27dodYwLL
+MgG7dm2SaTPGTGo3qd1lmcCynNpNajdpUiApkBSwZ1IgKbvdbre7Zi23337nI4+ccubF8AEQ56LD
+4QjKM0HimpUnkvi6pAI2V0gFJOwCUm2kAnZtVskEkrIZYwISdu3alViNMYExCowxAalJpSa1sWvX
+rt0xJmA3qY1du8sygWWZwBgzqd1lmcCynCbYE0gKJE0KJAXsmRRIym632+2uzaVL853vvOuhh044
+8wL4IJhz0eFwBOWZIHHNyhNJXJ1UNjYrqWwkVslkkxSwsSvVLiBh1y6QFBhjAhJ27QJjTGCMAskE
+7Nq1SSo1qV27du3atUlq167dZZnAskxgWaZdu0mXZQJJ7QkkBZICSZMC9gSSJmW32+121+bv/b3P
+HB+XM7fAz4I5Fx0OR1CeCRLXpjyRxNclFbC5QiogcYVdqTYrqTarZAJJAbt2JVZ27QJJgTEmYNeu
+RFKpwBjTxq5du3aT2gXGmDZ27Sa1O8YElmUCyzLtJrW7LBNICiQF7AkkTQokBZLaE0gKJGW32+3+
+HHj44ZMLF05f8ILl+uvN+b3pTb996dLkzAvgpzkvHQ5HUJ4JEtemPJHE1UllY7OSykZiZZdNUkCq
+jVQgKWDXLpAUsGtXKjBGgTEmIGHXrl27wBgFxph27doFxiiwLNOuXbtJ7Y4xgWWZdpPaTWo3KZAU
+SArYE0gKJE0KJAXsCSRNym632z3X/eqv/u5/+28P3XxzPv7x17zylTfymHvuuXDPPV/9oR968fOe
+F57C174277jjrgcfPOHMi+ADYM5Fh8MRlKdN4pqVJ5K4OqmAzRVSAYkr7AISdqWySQrYlbBrVyow
+RgGpdm1WyQTGKGDXrl27NqsxJjDGtAuMUWCMCSzLtGvXLrAs067dpGNMYFkmkBRICiQFktoTSAok
+BZICSe0JJAWSstvtds9RFy/OX/mVL37hC48si1b/9J+++i/9pZvZfPnLFz/84S+88IXLJz7xAzy1
+N7/5zgsXTjlzE/wi56XD4QjK0yZxbcoTSVydVDY2K6lsJFZ22UiskglIrMaYbJICUu3a2JUKjFFA
+ql2b1RgTGGNKrMaYwLJMQGpSmzEmMMYElmXaBcaYdpPaJNPuGBNICiQFkgJJgaSAPYGkQNKkQFLA
+nkDSpOx2u91z0Ve+cumjH/3CGPrQh/7iP//nv/fggydve9t3/8iPvOyGGwy885133XRT/sW/eO31
+15s/y6OPnr7vfZ87OjrmzPPhZ0Cciw6HIyhPm8S1KU8kcXVSAZsrpAISV9gFJFZS2SQF7NqVWCUT
+sLErFRijQDIBuzZ2gTEmkBSwO8YExpiATVKpyzIBqUntjjGBZZk2Se0uy2RjTyApkBRICiQFktoT
+SAokBZICSe0JJAWSstvtds8tX/rSxZ/7uc+/5CXXffKTr7tw4fQ3fuN//vt//z/H0A//8EvvueeR
+3/u9Cz/+47e96U3/B0/tbW/77P33H3PmJfA+COeiw+EIytMmcW3K40hcnVQ2NiupbCRWdtlIrKQC
+NqtkAhJ2Aal2bVbJBGzsSgXGmBJJpQJjFLBr1+4YE7Cxa9euXbt27S5LgTEmYHdZJrAsE0gK2BNI
+CiQFkgJJgaSAPYGkQNKkQFLAnkDSpOx2u91zyJ/8ydd+//cvPPjgyY/8yEvZPPTQyb/8l//jvvsu
+3XJL3vrWl3//99/MU/vqV0/f8567//RPTzhzE/wi56XD4QjK0yZxDcoTSVydVMDmCqmAxBV2AYmV
+VDY2K6l2JVbJBGzsSgXGKCDVrl0gKWDXrs0YE5CaVCqwLJWa1C4wxrSxp82yTMDuGBNYlgkkBZKy
+sSeQFEgKJAWSAkkBeyYFkgJJgaSAPZMCSdntdrsdnJz09tvvvHhxcual8JOclw6HIyhPj8S1KU8k
+cXVSAZsrpAISK7tsJFZSAZuVVECqzUqqXZtVMgG7NlLt2pVYjTEBuzZSgTGmXbs2qzGmXWCMCSxL
+7QJjTLtJpS7LZJMUSAokBewJJAWSAkmBpEBSwJ5AUiApkBRIak8gKZCU3W63+/Pt+Lh33HHX/fcf
+c+ZG+AUw56LD4QjK0yNxbcrjSFydVDY2K6lsJFZ2AYmVVDY2K6mAVCApYNdGKmDXrsRqjAlI2LUr
+NamEXbvAGNNmNcYE7I4xgTEK2B1jAssy7dq1CyQFkgJJ2SQF7AkkBZICSYGkQFLAnkBSICmQNClg
+TyApkJTdbrf7Dnfhwunb3/7ZG2/MP/gHt73xjS/hmrW8+c2//eijkzMvgQ9wXjocjqA8PRLXoDyR
+xNVJBWyukApIrOyykVhJBWxWUgGpbCTs2gUk7NqVsCsVGKOAXbtSgTFqFxhjAhJJpS7LBCSWZQJS
+l2UCY0zAZlkmYE82SYGkQFIgKRt7AkmBpEBSICmQFLAnkBRICiRNCtgTSAokZbfb7b5j3X//8R13
+3PW85405OT3tD/7grT/xE6+4+ebw9Vy6NH/iJ+4+OjrmzHXwURDnosPhCMrTI3ENyhNJXIVUNjYr
+qWwkVnYBiSukAjYrqYBUQGJlF0gKSE0qsUomYGPXrlS7NqsxJiB1jAJ27dq1sWvXrl27Y0zAZlkm
+kJSNPYGkbJICSYGkgD3ZJAWSAkmBpEBSwJ5AUiBpUiApYE8gKZCU3W63+w70x3/8tZ/6qf/3B3/w
+1p//+Vd9+tMP/Nt/++X77jv+m3/zRX/3777sta+9mce58cYb3/CGN0g6OTlpO2cvXOCGG5bj49MH
+H7z4sz/7f/+H/+cLvBfMuehwOILy9Ehcg/JEElchlY3NSiogcYVdQGIlFbC5QiogFZBY2QUk7EoF
+xqhUwMauVGCMCdgkE7Cxp43UpFKBZalUYFmm1KQ2UpPaBZICSdnYE0gKJGWTFEgK2BNIyiYpkBRI
+CiQF7AkkBZImBZIC9gSSAknZ7Xa77xCf/OQf/qf/dHTjjX7kkVNbbZ/3vHFy0uPj+eij8+ab86/+
+1fd/13ddz+O84hWvkHRycnJ6enpycvLJT/7xo4+e2nr00ZPf+q0v3/foBX6B89LhcATl6ZG4BuVx
+JK5OKmBzhVRAYmWXjcRKKmCzkgpIBSRWdgGJlVRgjAJS7dqskmkXGKOAVGCMSgXGmIDNGBOwO8YE
+xpg2qzGmXSApkJRNUsCebJICSdkkBZIC9gSSskkKJAWSAkkBewJJgaRA0qSAPYGkQFJ2u93u295v
+/ub9d9/91YcfPvnMZx666aa88Y0vvvXW5YUvXB555AR46Uuv/yt/5XmJeAqnp33Xu+4+OrrEmVvh
+Q2DORYfDEZSnQeLalMeRuAqpbGxWUtlIrOwCEiupbGxWUgGpgMTKLiCxkgrY2JVqF0gKSE0qYdeu
+xGqMaRcYo4DdMSYgdVkKSF2WCUhNyiYpkJRNUsCebJICSdkkBZIC9gSSskkKJAWSAkkBewJJgaRA
+UiCpPYGkQFJ2u93u297Fi/M//+cHbrvt+h/4gVs4j69+9fS97737oYdOOPMX4D2clw6HIyhPg8Q1
+KE8kcRVS2dispAISV9gFJFZSAZuVVEAqILGyC0ispAI2K6nAGBOQSCZgsxpjAhJjTEBqUgm7SaXa
+2NNGalK7NvZkk5RNUiApm6SAPdkkBZKySQokBezJJimQFEj6v9mDu5jd84Os99/ruu77WfOUMnYo
+fdlAEKgoFO/4FmAbjXqwJdsDIlEca2vU0gJlhtJN3IkbUrIXCoZGSfaJ4kGjPdB4YEJ84cTExIm6
+ERSZ0hZqNpGUvTsUaJ8pnc6aWTPref7X/uW38l+5l7LeHhgYpv/PB0gKJAXsBUgKJAWSAkkBewGS
+JmWz2WxeiW7c6KOPPnl+Xm75AvguHpQOhzMovwES96HcTuIupAI2N0kFJAa7TBKDVMBmkApIBSQG
+u4DEIBWwGaRKBXa7AlKB3a6A1N2ugF2pdm2G3W6RCuz3lQrsdotdYL8vk70wJWVKCiRlSspkL0BS
+IClTUiApk70ASYGkQFIgKZAUsBcgKZAUSAokBewFSAokZbPZbF7GPvnJF198cfnCLzz59KdvvPGN
+V7iXi4s++ugHX3xx4ZZT+Bs8KB0OZ1B+AyTuQzkicXdSAZtBKpPEYBeQGKQy2QxSAamAxGAXkBik
+2gxSAamAzZAsNoNUuzZSk0oFJHa7BbC72xWwu9stgMR+vzAlZbIXpqRMSYGkTEmZ7AVIypQUSMqU
+FLAXICmQlCkpkBRICtgLkBRICiQFkgL2khRIymaz2bxsXLt28c/+2SeeeOLpp5++IWHr4qKJgC/7
+stPv+Z43vf71J9zB+XkfffTJGzfKLb8L3gPmgehwOIPyGyBxH8oRibuQymQzSAUkbrILSAxSAZtB
+KiAVkBjsAhKDVMBmkApItRmkAhJJpUoMu90CSN3tCtiVmlTCblKpNnbtAkmZkjLZC1NSpqRMSYGk
+TPbClBRIypQUSArYC1NSICmQFEgKJAXsBUgKJAWSAkkBewGSAknZbDab31YXF/3zf/6nE/+ZP/O6
+b/qmNzz0kHc7Xbnia9cunn32/D3v+eib3/zq7/u+32NzJ297288888w5t7wevgPEA9HhcAblN0Di
+PpQjEnchFbC5SSogMdhlkhikAjaDVEAqIDHYBSQGqYDNIFUqYDNIBSTsAkkBu1Lt2khNKtVm2O0W
+iWG/X6QCSZmSskrKZC9MSYGkTEmZkgL2wpSUKSmQFEjKZC9AUiApU1IgKZAUsBcgKZAUSAokBewF
+SAokZbPZbH47/MIvPPfe9/7861538sM//FW7nVgtCx/+8DM//MMf+7IvO33ve990cmLu4B3v+PCv
+/uqL3PIG+A4elA6HMyi/ARL3Um4ncRdSAZubpAISg11AYpDKZDNIBaQCEoNdQEIqYDNIBaQCNoNU
+icEuICFM3hr6AAAgAElEQVQ1qVSJYbdbAJvdbgGk2ti1KzUpq6RMSZmSMtkLU1KmpExJgaRM9sKU
+FEjKlBRIymQvQFIgKZCUKSmQFLAXICmQFEgKJAXsBUgKJGWz2Wx+C11c9O///f/33/ybT732tScS
+v/t3n/78z19L9JnPnLe87nUn73vf7/uCL9hzBxcX/ZZv+fDTT9/gljfCu3hQOhzOoFyWxH0ot5O4
+C6mAzSCVSWKwC0gMUgGbQSogFZAY7AISg1TAZpAKSLUZpAISg12JQarNkCyAXYmkUqUC+32lArvd
+wiopU1KmpExJWdkLU1IgKVNSpqRM9gIkZUoKJGVKCtgLU1IgKZAUSMqUFLAXICmQFEgKJAXsBUgK
+JGWz2Wx+S7Q89dT1n/u5Z//Df3j64Yf3v/ZrN9785lf/8T/+yGtes//8z99J3MXFRd/5zo986lMv
+csvr4TEelA6HMyiXJXEfyhGJu5DKZDNIBSRusgtIDFIBm0EqIBWQGOwCEoNUwGaQKhWwGaQCEnYB
+iUGqzSBValIJqcBut9gMUne7hVVSpqSskjIlZUrKZC9MSZmSMiVlSspkL0BSpqRAUqakgL0wJQWS
+AkmBpExJAXsBkgJJgaRAUsBegKRAUjabzeZl7B3v+PCv/uqL3PIF8F08KB0OZ1AuS+I+lCMSdyGV
+yWaQCkgMdpkkBqmAzSAVkApIDHYBiUGqzSAVkArYDFIlBruAhFTARiogVWKwu9sVkCo1qc1N9sKU
+lFVSpqSskjIlZbIXpqRMSZmSMiVlshcgKVNSIClTUsBemJICSYGkTEmBpIC9AEmBpEBSIClgL0BS
+ICmbzWbz8vP2t3/4U596kVteC+/mQelwOINyWRL3oRyRuAupgM1NUgGJwS4gMUhlshmkAlIBCbuA
+xCAVsBmkAlJtBqmAxGBXYpBqM0gFpEoMdiWG3W6RajMkZWUvrJKySsqUlFVSpqRM9sKUlCkpU1Km
+pEz2AiRlSsqUFEjKZC9AUiApU1IgKZAUsBempEBSICmQFLAXICmQlM1ms3kZaHnb237ms58955Y3
+wHfwoHQ4nEG5LIn7UI5I3IVUwGaQyiQx2AUkBqmAzSAVkApIDHYBiUEqYDNIlQrYDFIBCbuAxCDV
+ZpAqFZCwC0hIBWykJmWVlJW9sErKKilTUlZJmZIy2QtTUqakTEmZkjLZC1NSIClTUqakgL0wJQWS
+AkmZkgJJAXsBkgJJgaRAUsBegKRAUjabzea31Vve8sFr1y645Y3wLh6UDoczKJclcS/ldhJ3IRWw
+GaQCEjfZBSQGqYDNIBWQCkgMdgGJQSpgIxWQCtgMUiUGu4CEVMBGKiBVYrArMUi1GaSySsoqKSt7
+YZWUVVKmpKySMiVlshdWSZmSMiVlSspkL0BSpqRMSYGkTPYCJGVKCiQFkjIlBewFSAokBZICSQF7
+AZICSdlsNpvfWjdu9C/8hScvLsotr4fHeFA6HM6gXJbEvZTbSdyJVCabQSogMdhlkhikAjaDVEAq
+IDHYBSSkAjaDVEAqYCMVkBjsSgxSARupgFSJwa7EINVmkMr/ICmrpKzshVVSVklZJWVKyiopk70w
+JWVKypSUKSmTvTAlZUoKJGVKymQvQFKmpEBSIClTUsBegKRAUiApkBSwFyApkJTNZrN56T377MXb
+3/6h69cXbnktPA7mgehwOINyWRL3Uo5I3IVUJptBKiAx2AUkbpIK2AxSAamAxGBXYpAK2AxSAak2
+g1RAwi4gMUi1GaRKBSTsAhJSARup3EtSVklZ2QurpKySMiVllZQpKSt7YUrKlJQpKVNSJnthSsqU
+lCkpkJTJXoCkTEmBpExJgaSAvQBJgaRMSYGkgL0ASYGkbDabzUvg+vXlXe/6yNnZDW7ZwfeCeSA6
+HM6gXJbEvZQjEnchFbC5SSogMdgFJAapgM0gFZAKSAx2AYlBKmAzSJUK2AxSAQm7gIRUwGaQKhWQ
+sAtISAVspHLfkrJKyhF7YZWUVVKmpKySMiVlZS9MSZmSskrKlBSwF6akTEmZkjIlBeyFKSmQlCkp
+kBRIymQvQFIgKZAUSArYC5AUSMpms9n85nn72z/8qU+9yC2vhv+dB6XD4QzKZUncSzkicRdSAZub
+pAISg11AYpAK2AxSAamAxGAXkBikAjZSAamAzSBVYrALSEgFbKQCUiUGuxKDVJtBKpeSlFVSjtgL
+q6SskrJKypSUVVIme2GVlCkpU1KmpEz2wpSUKSlTUiApk70ASZmSAkmZkgJJAXthSgokBZICSQF7
+AZICSdlsNpvLunGj3/zNTy5LueX18BgPSofDGZTLkriXckTiLqQCNoNUJonBLiAxSAVsBqmAVEBi
+sAtIDFJtBqmAVMBGKiAx2JUYpAI2UgGpEoNdiUGqjVR+MyTlSFJW9sIqKaukrJKySsqUlJW9MCVl
+lZQpKVNSJnthSsqUFEjKlJTJXoCkTEmBpExJgaRM9gIkBZICSYGkTPYCJAWSstlsNvfn2rWLxx//
+2bOzG9zyCLwbzAN4//t1OJxBuSyJeylHJO5CKmAzSAUkbrILSAxSAZtBKiAVkBjsAhJSAZtBKiAV
+sJEKSAx2JQapNoNUqYCEXUBCKmAjlZdAUlZJOWIvrJKySsoqKaukTElZ2QtTUlZJmZIyJWWyF6ak
+TEmZkjIlBeyFKSmQlCkpkJQpKWAvQFKmpEBSIClgL0BSICmbzWZzBy1/9a9+6NOfvsEtp/A3eDBX
+r+pwOINyWRL3Uo5I3IVUwGaQCkjcZBeQGKQCNoNUQCogMdiVGKQCNoNUQKrNIBWQsAtIDFJtBqlS
+AQm7gIRUwEYqL72krJJyxF5YJWWVlFVSVklZJWWyF1ZJmZIyJWWVlMlemJIyJWVKCiRlshempEBS
+pqRAUqakgL0ASZmSAkmBpIC9AEmBpGw2m830/PPLo48+ybHXweM8gI99jA98QIfDGZRLkbgP5YjE
+nUhlshmkAhKDXSaJQSpgM0gFpAISdgGJQSpgM0iVCtgMUgEJu4CEVMBmkCoVkLALSEi1GaTyWy4p
+R5KysheOJGWVlFVSVklZJWWyF1ZJmZKySsqUlMlemJIyJWVKypQUsBempExJgaRMSYGkTPYCJAWS
+AkmZkgL2AiQFkrLZbD4nfeu3fuSXf/kFjn0fhPv1d/8uzz6rw+EMyqVI3IdyROJOpDLZDFIBicEu
+IDFIBWwGqYBUQGKwC0gMUgGbQapUwGaQKjHYBSSkAjZSAakSg12JQarNIJWXgaQcScrKXjiSlFVS
+VklZJWWVlJW9MCVllZQpKVNSVvbClJQpKVNSICmTvTAlZUoKJGVKCiRlshcgKZAUSMqUFLAXICmQ
+lM1m84r27LMXf+kvfZBjXwzfygO4ehXQ4XAG5VIk7qXcTuJOpDLZDFIBicEuIDFIBWwGqYBUQGKw
+C0gMUgEbqYBUwGaQKjHYlRikAjZSAakSg12JQaqNVF6uknIkKUfshSNJWSVllZRVUlZJWdkLU1JW
+SZmSskrKZC9MSZmSMiVlSspkL0BSpqRMSYGkTEkBe2FKCiQFkgJJmewFSAokZbPZvFK8610/+9RT
+17kl8D2w475cv84P/RCgw+EMyqVI3Eu5ncSdSAVsbpIKSAx2AYlBKmAzSAWkAhKDXUBikArYSAWk
+AjZSAYnBrsQgFbCRCkiVGOxKSAVspPI7SlJul5SVvXAkKaukHEnKKimrpKzshSkpq6RMSVklZbIX
+pqRMSZmSMiVlshempEBSpqRMSYGkTPYCJAWSMiUFkgL2AiQFkrLZbH5HuXbt4q/9tQ9dv75wyxvg
+O7hfP/Zj/NRPAToczqBcisS9lCMSdyEVsLlJKiAx2AUkBqmAzSAVkApIDHYBiUGqzSAVkArYSAUk
+BrsSg1SbQapUQMIuICEVsJHKK0VSjiTliL2wSsqRpKySskrKKikre2GVlFVSpqSskjLZC1NSpqRM
+SZmSMtkLU1KmpEBSpqRAUiZ7AZIyJQWSAkmZ7AVICiRls9m8BF77oQ+94T/9p0/+4T/8yT/0h5B4
+QG9968989rPn3GJ4L5j7cvUqkw6HMyiXInEv5YjEXUgFbG6SCkgMdgGJQSpgM0gFpAISg11AYpBq
+M0gFpAI2UgEJu4DEINVmkCoVkLALSEgFbKTyOSApR5JyxF44kpRVUo4kZZWUVVJW9sIqKaukTElZ
+JWWyF6akTEmZkjIlZbIXpqRMSZmSAkmZkgL2wpQUSMqUFEgK2AuQlCkpm83mAeni4vAjP/Kl//pf
+X5yc/D9ve9svfNM31Wb6wief/Lq/9bee/uqv/okf/EHu4OKijz/+c089dZ1bXgePc7+uXmXS4XAG
+5VIk7qUckbgLqYDNIJVJYrALSAxSAZtBKiAVkBjsAhJSAZtBKiDVZpAKSNgFJAapNoNUqYCEXUBC
+KmAjlc95SbldUo7YC0eSskrKkaSskrJKyspeWCVllZRVUqakTPbCKilTUqakTEmZ7IUpKVNSIClT
+UqakgL0wJQWSAkmZkgL2AiQFkrLZbG6XF1/8E9/5nfvnnnv+C7/w83/xF3/1a7/2yb/+1y+uXAF2
+zz//Jx977MWHH/6//87fWU5O+PU8//zFo49+kGOPwHu4X1evMulwOINyKRL3Uo5I3IVUwGaQyiQx
+2AUkBqmAzSAVkApIDHYBCamAzSAVkGozSAUk7AISg1SbQapUQMIuICHVZpDK5j4k5XZJOWIvHEnK
+kaSsknIkKaukrOyFVVJWSVklZUrKyl6YkjIlZUrKlJTJXpiSMiVlSsqUFEjKZC9AUqakQFIgKZO9
+AEmBpGw2nxt2zz//DW972zNf8RU/8Tf/5hf9+3//1f/wH56/6lUfeve7P/UH/sD+uef+l7/yV577
+oi964u/9Pe7sLW/54LVrFxz7P0Hc28c/zvvfz6TD4QzKpUjcSzkicRdSAZtBKpPEYBeQGKQCNoNU
+QCogMdiVGKQCNoNUQKrNIBWQsAtISAVsBqlSAQm7EoNUm0Eqm99sSTmSlNvZC0eSciQpq6QcScoq
+KSt7YZWUVVJWSZmSsrIXpqSskjIlZUrKZC9MSZmSMiUFkjIlhdrd7Wp3t1sk7NqVkCohFZDYbF4Z
+9teufcNb3/orX//1P/W93wtc+fSnv+77v//hj32M6fxVr/qPP/iDz3z5l3Nn3/ZtH/nEJ17glkfg
+3WDu7YkneOIJJh0OZ1AuReJeyhGJu5AK2AxSAYmb7AISg1TAZpAKSAUkBrsSg1TAZpAqFbAZpAIS
+dgEJqYCNVECqxGBXYpBqM0hl8zKQlNsl5Yi9cLukHEnKKilHkrJKyspeOJKUKSmrpKySMtkLq6RM
+SZmSMkk9OVl2uyXpycnFbtdkSWrXblIJu3bZbF4ZWp+fV+pux2r3/PNXnn56/+yzz37pl56fnnJn
+N2708cd/9hOfeIFb3gjv4r584AN87GNMOhzOoFyKxL2UIxJ3IRWwGaQCEjfZBSQGqYDNIBWQCkjY
+BSQGqYDNIFUqYDNIlRjsAhJSARupgFSJwa7EINVmkMrmFSEpt0vKEXvhdkk5kpQjSVkl5UhSVvbC
+KimrpHZPTi72+z700Pl+v+z3y36/7PdLsiRNmixJk7LZbODZZy/e/vYPXb++cMvr4HHuyw/8AOfn
+TDoczqBcisS9lCMSdyEVsBmkAhI32QUkBqmAzSAVkApI2AUkBqmAzSBVKmAzSJUY7AISUgEbqYBU
+icGuxCDVZpDKZnNnSbldUm5nLxxJyrTfLycny6tedePkZHnooYsrVy5OTi6uXLnY7brbLbvdstst
++/2SlM1mA9euXbzlLR/k2CPwHu7L1ausdDicQbkUiXspRyTuQipgM0gFJG6yC0gMUgGbQSogFZCw
+C0gMUgGbQapUwGaQKjHYBSSkAjZSAakSg12JQarNIJXN5qWx3y9Xrlycnp6fnp5fuXJxenpxenq+
+3y/7/bLfX5ycLPv9st8vu93CZvOKoPNzkkr8D778X/7LL/m3//ZDjz32ma/8Su7gxo3+uT/30xx7
+CP4P7svVq6x0OJxBuRSJeylHJO5CKmAzSAUkbrILSAxSAZtBKiAVkLALSAxSAZtBqlTAZpAqMdgF
+JKQCNlIBqRKDXYlBqs0glc3mpbHfL1euXJyenp+enl+5cnF6enF6en5ycrHbdb+/ODlZ9vtlv192
+u4XN5hWg/b3/9J9+xT//5//fn/7Tn/hjf+zZL/mSFx9+mNVX/6N/9KYf/dEff9/7nn7zm7mzb/zG
+/8J/5yr35epVVjoczqBcisS9lCMSdyEVsBmkAhI32QUkBqmAzSAVkApI2AUkBqmAzSBVKmAzSJUY
+7AISUgEbqYBUicGuxCDVZpDKZvPS2O+X09PzK1cuTk/Pr1y5OD29OD09Pzm52O2631+cnCz7/bLf
+L7vdwmbzivDIf/2vX/zEE6//z//59OmnC9df+9pf+fqvP/v9v/+Tf+SP/N5/8k/e9KM/+uPve9/T
+b34zq8//xV/8E+95jy4u+PV8N//r/8X/zFXuy9WrrHQ4nEG5FIl7KUck7kIqYDNIBSRusgtIDFIB
+m0EqIBWQsAtIDFIBm0GqVMBmkCox2AUkpAI2UgGpEoNdiUGqzSCVzealsd8vV65cnJ6en56eX7ly
+cXp6cXp6fnJysdt1v784OVn2+2W/X3a7hc3mlaQ9eeaZz/vEJ97wkz/55f/qX2lZfH5+sd/nxRd/
+/H3ve/rNb+bOvvEb/wv/navcl6tXWelwOINyKRL3Uo5I3IVUwGaQCkjcZBeQGKQCNoNUQCogYReQ
+GKQCNoNUqYDNIFVisAtISAVspAJSJQa7EoNUm0Eqm81LY79frly5OD09Pz09v3Ll4vT04vT0fL9f
+9vtlv784OVn2+2W/X3a7hc3mFe3kM5/5in/xLx756Ed/7p3v/Myb3sQdLEv/7J/9aY5dge/hvly9
+ykqHwxmUS5G4l3JE4i6kAjaDVEDiJruAxCAVsBmkAlIBCbuAxCAVsBmkSgVsBqkSg11AQipgIxWQ
+KjHYlRik2gxS2WzuJSm3S8oRe+F2Sff75eRkeeih85OT5VWvOr9y5eLk5OLkZNntlv1+2e2W3W7Z
+75ekbDYbuHbt4i1v+SDHXgP/G/fl6lVWOhzOoFyKxL2UIxJ3IRWwGaQCEjfZBSQGqYDNIBWQCkjY
+BSQGqYDNIFUqYDNIlRjsAhJSARupgFSJwa7EINVmkMrmFSQpt0vKEXvhSFKOJOVIUo4kZZWUI/bC
+KilT0oceOt/ve3JyceXKxX6/7PfLbrfsdkvSpEmTJSmbzQaeeeb8He/48PXrC7e8Ab6D+/IDP8D5
+OZMOhzMolyJxL+WIxF1IBWwGqYDETXYBiUEqYDNIBaQCEoNdiUEqYDNIlQrYDFIBCbuAhFTARiog
+VWKwKzFItRmksnnZSMrtknLEXjiSlCNJOZKUVVKOJGVlL6ySskrKKilTUlb2wpSUKSmrpFJ3u56c
+XCTd7ZaTkyVZ7Ca1m1TCrl02m1eSZfmCj370jT/xE7/rv/23K08/jf3013zNr3zt1/7aV37lC488
+wp3duNHHHvvZX/7lF7jlf4Jv57584AN87GNMOhzOoFyKxL2UIxJ3IRWwGaQySQx2AYlBKmAzSAWk
+AhKDXYlBKmAzSAWk2gxSAQm7gIRUwGaQKhWQsCsxSLUZpLJ5aSTlSFKO2AtHknIkKUeSskrKkaSs
+7IVVUqakrJKySspkL0xJWSVlSsqUlMlemJIyJQWSMiVlSha7u13t2k1q166EVAkJqMRm84rxxf/u
+333NP/gH+2vXlpOTF17zmhceeeTFhx/ePffca37+5yt98Lu/+5f/6B/lzr792z/yS7/0Arc8Au8G
+c29PPMETTzDpcDiDcikS91KOSNyFVMBmkMokMdgFJAapgM0gFZAKSAx2AQmpgM0gFZBqM0gFJOwC
+EoNUm0GqVEDCLiAh1WaQyua+JeV2STliLxxJyiopR5KySsoqKSt7YZWUVVJWSZmSsrIXpqRMSZmS
+MiVlshempExJmZICSZmSMtkLkBRIypQUSArYC1NSCbtsNp8DTj/5yT/5nd/53Bvf+ON/+2+ff97n
+caz9hr/8l198+OEnfuRHuLNv/uYnX3hh4RbD94G4t49/nPe/n0mHwxmUS5G4l3JE4i6kAjaDVCaJ
+wS4gMUgFbAapgFRAYrALSEgFbAapgFSbQSogYReQGKTaDFKlAhJ2AQmpgI1UNlNSjiTliL1wJClH
+krJKypGkrJKyshempKySskrKlJSVvTAlZUrKlJQpKZO9MCVlSgokZUrKlBSwFyApU1IgKVNSwF6A
+pEBSNpvNkc976qmv+/7vX3a7j37Lt3z6q77qxqtfzfTqj3/89/3jf/yGn/zJp/7Un/rQd31XJX49
+n/3s+Vvf+jMcez08xv26epVJh8MZlEuRuJdyROIupAI2N0kFJAa7gMQgFbAZpAJSAYnBLiAxSLUZ
+pAJSARupgIRdQGKQajNIlQpI2AUkpAI2UvnckJTbJeWIvbBKypGkrJKySsqRpEz2wiopq6RMSVkl
+ZbIXpqRMSZmSMiVlshempExJmZICSZmSAvbClBRICiRlSgrYC5AUSMpms3lwr3vyya95//s/75d+
+iVbLAlRCevZLvuRn3/nOT/3BP8idXVz08cd/7qmnrnPL6+Bx7tfVq0w6HM6gXIrEvZQjEnchFbC5
+SSogMdgFJAapgM0gFZAKSAx2AYlBqs0gFZAK2EgFJAa7EoNUm0GqVEDCLiAhFbCRyitIUo4k5Yi9
+cCQpq6QcScoqKaukrOyFKSmrpExJWSVlshempExJmZIyJWWyF6akTEmBpExJgaRM9gIkZUoKJAWS
+AvbClBRIymazeWnsn322Se39s89enJycv+pVTbgPf/EvfvC55y64JfBeEPfl6lUmHQ5nUC5F4l7K
+7STuRCpgc5NUQGKwC0gMUgGbQSogFZAY7AISg1TARiogFbCRCkgMdiUGqYCNVECqxGBXQipgI5Xf
+gZJyJClH7IVVUo4kZZWUVVJWSVnZC1NSVkmZkrJKymQvTEmZkjIlZUrKZC9MSYGkTEmBpExJAXth
+SgokBZIyJQXsBUgKJGWz2fzO8cwz5+94x4evX1+45YvhW7lfP/Zj/NRPAToczqBcisS9lNtJ3IlU
+JptBKiAx2AUkBqmAzSAVkApIDHYBiUEqYCMVkArYDFIlBrsSg1TARiogVWKwKzFItZHKy1tSjiRl
+ZS8cScoqKaukrJKySsrKXlglZUrKlJRVUiZ7YUrKlJQpKVNSJnsBkjIlZUoKJGVKCtgLkJQpKZAU
+SArYC5CUKSmbzeYV4du+7SOf+MQL3BL4Xgj35fp1fuiHAB0OZ1AuReI+lCMSdyKVyWaQCkgMdgGJ
+QSpgM0gFpAISg11AYpAK2AxSpQI2g1SJwS4gIRWwkQpIlRjsSgxSbQapvDwk5UhSjtgLq6SskrJK
+yiopq6Ss7IUpKaukTEmZkrKyF6akTEmZkgJJmeyFKSmQlCkpkJQpKWAvTEmBpEBSICmTvQBJgaRs
+NptXruefv3j00Q9y7PXwGA/g6lVAh8MZlEuRuA/liMSdSGWyGaQCEoNdJolBKmAzSAWkAhJ2AYlB
+KmAzSJUK2AxSAQm7gIRUwGaQKhWQsAtISLUZpPLbJCmrpByxF1ZJWSVllZRVUlZJmeyFVVKmpKyS
+MiVlshempExJmZL+/+zBbcz36UHW+e9xHOdv2imlLQ5YQBTkqV2z/2QjJmrkJYkmvFFsLS1Ioc9Q
+CjQwbOlCUm2CGpsYXhhj4gtjjCSuvvKl2WBifAiJMLRTtoXVBWW7Q5mrM7Tz0PvhOo/9zXnnunLf
+O8w99zUzhVJ+nw9LUsCeLElZkgJJWZICSQF7siQFkgJJgaSAPVmSAkk5HA5/9LzznQ8/8sg1Lgl+
+GsK9+shHeOIJnU5nUF4oiedTbiNxF1IBm51UQOIWu4DETipgs5MKSAUkdnYldlIBm51UQKrNTiog
+YReQ2Em12UmVCkjYBSSkAjZS+X2RlNsk5YI9uZCUC0m5kJQLSbmQlMWeXEjKkpQLSVmSstiTJSlL
+UiApS1IWe7IkBZKyJAWSsiQF7AkkBZKyJAWSAvYEkgJJORwOB/jc526+5S2/wu2+Bt7NFfzGb/BP
+/6lOpzMoL5TE8ym3kbgLqYDNTiogcYtdQGInFbDZSQWkAhI7u4CEVMBmJxWQCthIBSR2diV2Um12
+UqUCEnYBCamAjVS+MJJym6RcsCcXknIhKReSciEpF5Ky2JMlKReSsiRlScpiT5akLElZkgJJWezJ
+khRIypIUSMqSFLAnkBRIypIUSArYE0gKJOVwOByew9/8m7/y+OM3ufRy+ABX86EP6XQ6g/JCSTyf
+chuJu5AK2Oykskjs7AISO6mAzU4qIBWQ2NkFJHZSbXZSAamAjVRAYmdXYicVsJEKSJXY2ZXYSbWR
+yksnKReScsGeXEjKhaRcSMqFpFxIymJPlqRcSMqSlCUpiz1ZkrIkBZKyJGWxJ5CUJSmQlCUpkBSw
+J0tSICmQFEgK2BNICiTlcDgc7s2TT57/8A//6qOPXufSV8D7wFzBP/knOp3OoLxQEs+n3EbiLqQC
+NrdIBSR2dgGJnVTAZicVkApI7OwCEjupgI1UQCpgs5MqsbMLSEgFbKQCUiV2diV2Um12UnmhknKb
+pFywJxeSciEpF5KyJOVCUhZ7ciEpS1KWpCxJWezJkpQlKZCUJSmLPYGkLEmBpCxJgaSAPYGkLEmB
+pEBSwJ5AUiAph8Ph8IJcuzbf9KaHzs/Lpa+Fd3FVOp3OoLxQEs+n3EbiLqQCNrdIBSR2dgGJnVTA
+ZicVkApI7OwCEjupgM1OqlTAZicVkLALSEgFbHZSpQISdgEJqYCNVK4oKReScsGeXEjKhaRcSMqS
+lAtJWezJkpQlKReSsiQF7MmSlCUpS1IgKYs9WZICSYGkLEmBpIA9WZICSYGkQFLAnkBSICmHw+Hw
+EnOijH0AACAASURBVPn+7//o2dkNLr0SfoKr0ul0BuWFkng+5TYSdyGVxWYnFZDY2QUkbpEK2Oyk
+AlIBiZ1diZ1UwGYnFZBqs5MKSNgFJHZSbXZSpQISdgEJqYCNVO5BUi4k5YI9uZCUC0m5kJQlKReS
+stiTJSlLUpakLElZ7MmSlCUpkJQlKYs9gaQsSYGkQFKWpIA9gaRAUiApkBSwJ5AUSMrhcDh8AVy7
+Nn/wBz/+O79znUuB/w3Mleh0OoPyQkk8n3IniecilcVmJxWQ2NllkdhJBWx2UgGpgMTOLiAhFbDZ
+SQWkAjZSAYmdXYmdVMBGKiBVYmdXYifVZieV55CUC0m5YE8uJGVJyoWkLEm5kJTFnixJWZKyJGVJ
+ymJPlqQsSYGkLEkBe7IkBZKyJAWSAklZ7AkkBZICSYGkgD2BpEBSDofD4Qvss5+9+ba3fezatcml
+B+C9YK5Ep9MZlBdK4vmUO0nchVTAZicVkLjFLiCxkwrY7KQCUgGJnV1AYicVsJEKSAVsdlIldnYB
+CamAjVRAqsTOrsROqs1OKrdJym2SstiTC0m5kJQLSVmSsiTlgj1ZkrIkZUnKkhSwJ0tSlqQsSYGk
+LPYEkgJJWZICSYGkLPYEkgJJgaRAUsCeQFIgKYfD4fD76Pr1+cY3PjRnufTV8B6uSqfTGZQXSuIe
+lNtI3IVUwGYnlUViZxeQ2EkFbHZSAamAxM4uILGTCtjspEoFbHZSAQm7gMROqs1OqlRAwi4gIRWw
+kcqSlAtJWezJhaRcSMqSlAtJWZKy2JMlKUtSlqQsSVnsyZIUSMqSFEjKYk8gKUtSICmQlCUpYE8g
+KZAUSAokBewJJAWScjgcDn9wvvu7H3ryyXMufTW8h6vS6XQG5YWSuAflNhJ3IRWwuUUqILGzC0js
+pLLY7KQCUgEJu4DETipgs5MKSLXZSQUkdnYldlJtdlIBqRI7uxI7qTZjTC4k5YI9WZJyISlLUi4k
+ZUnKYk+WpCxJWZKyJGWxJ5CUJSmQlCUpYE+WpEBSlqRAUiApYE8gKZAUSAokBewJJAWScjgcDl8E
+Wt7yloeeeOKcS18D7+aqdDqdQXmhJO5BuY3EXUhlsdlJBSR2dlkkdlIBm51UQCogsbMLSOyk2uyk
+AlIBm51UiZ1dQEIqYCMVkCqxsyuRVKpUYNvKBXuyJOVCUpakXEjKkpTFnixJWZKyJGVJCtiTJSlL
+UiApS1LAnixJgaRAUiApS1LAnkBSICmQFEgK2BNICiTlcDgcvsi8/e0f+/Snr3Ppq+C9XJVOpzMo
+L5TEPSi3kbgLqSw2O6mAxC12AYmdVMBmJxWQCkjs7AISO6mAzU6qVMBmJxWQsAtI7KTa7KRKBSTG
+mICN1KRSbezJhaQsSbmQlCUpS1IWe7IkZUnKkpQlKWBPlqQsSYGkLEkBewJJWZICSYGkQFIWewJJ
+gaRAUiApYE8gaVIOh8Phi9jb3/6xT3/6OpdeDe/nqnQ6nUF5oSTuQbmTxF1IBWx2UlkkdnYBiZ1U
+wGYnFZAKSOzsAhI7qYDNTiog1WYnFZDY2ZXYSbXZSbVrV2I3xpQK2IwxAalJuZCUJSlLUpakXLAn
+kJQlKUtSlqQs9gSSsiQFkrIkBewJJGVJCiQFkgJJAXuyJAWSAkmBpPYEkgJJORwOh98X/+7ffeYf
+/sPf/IZvuP9v/+1vvf9+c5vz8ybiuZ2f913vevjTn77OpT8OP8RV6XQ6g/IiSDyfcieJu5AK2Nwi
+FZDY2QUkdlJZbHZSAamAxM4uICEVsNlJBaQCNjupEju7gIRUYIwpsbNr10YqMMa02Y0xpQJJuZCU
+JSlLUhZ7siRlScqSFEjKYk+WpEBSlqRAUsCeLEmBpEBSICmQlMWeQFIgKZAUSGpPICmQlMPhcPh9
+9LnP3fzAB37t7Oz6Rz7y+q/7upe3/Of//Pic/Ut/6Ssee+zGT/zEJx544L4Pf/hbXvYy83s5P+/b
+3/6xs7MbXHoA3sdV6XQ6g/IiSNyDchuJu5AK2NwiFZDY2WWR2EkFbHZSAamAxM4uILGTCtjspEoF
+bHZSAQm7gIRdu1KBMSoVGGPa7KSOUcDuGJMlKReSsiRlsSeQlCUpS1KWpIA9WZICSVmSAklZ7Akk
+BZICSVmSAkkBewJJgaRAUiApYM+kQFIOh8PhD8Jv/dbnP/CBT7761eMjH3n9/ffn8cdvvuc9D7/2
+tS/7uZ/7n+bkXe96+GUv09/7e69/5SvDc3jHOz722799nUuvhR/kqnQ6nUF5ESTuQbmNxF1IZbHZ
+SQUkbrELSOykAjY7qYBUQGJnF5DYSQVsdlIBqTY7qYDEbowpsbNrV6qNXbtSgTFqFxhj2uzGmCxJ
+WZKy2JMlKUtSlqRAUhZ7AklZkgJJWZIC9gSSsiQFkgJJgaSAPYGkQFIgKZAUsCeQFEjK4XA4/IH6
+G3/joWvXzv/yX/6qP//nX/Nv/+2j/+k/PX7ffTz44Ddduzb/wT/4v//CX3jNgw9+o8Rz+b7v++hj
+j93g0lfCe0FciU6nMygvgsQ9KLeRuDupgM1OKovEzi4gsZPKYrOTCkgFJHZ2AYmdVJudVEAqYLOT
+OkYBqcAYlQqMMQEJu3btSiS1KzWphN2kLElZ7MmSlCUpkJQlKYs9gaQsSYGkQFIWewJJgaRAUiAp
+kJTFnkBSIGlSIClgTyApkJTD4XD44vDEE+f/7J/91i/+4u8+/vjNr/3al33nd/7xf/NvPv3II9cS
+fd3Xvexnfuabv/Ir7+M5nJ/3TW966Nq1yaVXlR8V4Up0Op1BeREk7kG5k8RdSAVsbpEKSOzsskjs
+pAI2O6mAVEBiZxeQ2EkFbHZSpQI2u2QCNnal2ti1KxUYo4DUMSZgM8YE7I4xAZukLPZkScqSFEjK
+khSwJ0tSIClLUiApYE+WpEBSICmQFEgK2BNICiQFkgJJAXsCSZNyOBwOfxicnzcRz+f8vG9+80NP
+Pz259DL4Ka5Kp9MZlBdB4h6UO0nchVQWm51UQOIWu4DETipgs5MKSAUkdnYBiZ1UwGYnFZCaVEKq
+XZud1KQSdu1KBcaoXWCMabMbY0oFtm3a7OzJkhRIypKUJSlgT5akQFIgKUtSwJ5AUiApS1IgKZAU
+sCeQFEgKJE0K2BNICiTlcDgcvuTcvNk3vvGXb94sl14N7+eqdDqdQXkRJO5NuY3EXUhlsdlJZZHY
+2QUkdlJZbHZSAamAxM4uILGTCtjskmkXkLArFRijdoGkgN0xJiCR1K7UpFJtkkq1m1QqkJQlKZCU
+JSlgT5akQFIgKUtSwJ5AUiApkBRIypIUsCeQNCmQFEgK2BNICiTlcDgcvlg9+uj1s7Mbjz1249u+
+7dXbJm4zJ20T8dyeeur8B3/w45/5zA0ufTW8h6vS6XQG5cWRuAflNhJ3JxWwuUUqILGzyyKxkwrY
+7KQCUgGJnV1AYicVsLErFRijgNQxJiCxG2MCEmNMwK5dG7t27Y4xAZsxJmB3jMmSFEjKkhSwJ0tS
+ICmQlCUpYE8gKZAUSAokBZIC9gSSAkmBpEBSwJ5A0qQcDofDF71/+S8f+ef//P/5nu/52je96WuA
+69f72c/efOCBTeLBBz/5m7/51L/4F//LGOI5zNl3vevjv/3b17j05fBjEK5Ep9MZlBdH4h6UO0nc
+hVQWm51UQOIWu4DETipgc4tUQCogsbMLSOySCdhItWuzSyZg166NVLs2uzGmVGCMCdiMMQG7Y0xg
+2yoV2LYJJGVJCtiTJSmQFEjKkhSwJ5AUSAokBZICSQF7AkmBpEBSIClgTyBpUg6Hw+EPg5s3++M/
+/olPferzf+fvvO6bv/kVwE/91Cd/4zee/lt/61u+9Vu/7F/9q0d+/uc/9ff//uu/8RtfwW3+5J/8
+k5KuX79+8+bNOec/+kefevrpCTzxxI3/8l8+9egTT/EBrkqn0xmUF0fiHpQ7SdyFVBabnVQWiZ1d
+QOIWqYDNTiogFZDY2QUk7EoFxigg1a7NbowpFRijgNSkUm3s2gXGmDa7MaZdYIxpY08bu0mBpCz2
+BJICSVmSAkkBewJJgaRAUiApkBSwJ5AUSAokBZIC9kwKJOVwOBz+8Gj50Id+/Zd+6bPf+71/4o1v
+fC3wwz/8q5/61LXv+Z6v/a7veu3P/ux//fjHn/jQh7759a9/JRfuv//+b//2b7d948aNPoMnn+wr
+XrFdu3b++OOf/+AH/4///Rd+lR8CcyU6nc6gvDgS96DcSeLupAI2t0gFJHZ2WSR2UgGbnVRAKovE
+bowJSOzGmBK7ZAI2du0CyQRsxpiA1KQSuzGm3aQSdpNKtZtUalKbbZss9gSSsiQFkgJJAXsCSYGk
+LEmBpEBSewJJgaRAUiApYM+kQFIOh8PhD6FPfvLJn/u53/gf/+PzYwiQ+KZvesWv//pTc/a++/yd
+3/lVP/ADX8dzu359vvvdDz/66A0uDfggmCvR6XQG5cWRuDflNhJ3J5XFZieVRWJnF5DYSWWx2UkF
+pAISdu0CSQG7QFJAalKJ3RhTalKJ3RgTsDtGAalJ7Y4xARu7dseYgN1tm8AYkyUpkBRICiRlsSeQ
+FEgKJAWSAkkBewJJkwJJgaSAPYGkSTkcDoc/zObkv//3p8/ObrzqVXnta1/2qleNlmvXJvDyl5u7
+avuWt/zKE0+cc+mPwY9wVTqdzqC8OBL3ptxJ4u6kAja3SAUkdnZZJHZSAZudVEAqYCMVGKOAVLt2
+gaR2gaSAXbt2gaSA3TEmMEYBu2NMYIwJ2GzbBMaYdoExpt2kQFKWpEBSwJ5AUiApkBRICiQF7Akk
+BZImBZIC9gSSJuVwOBz+aLt+fb7jHQ8/9tgNLt0PD4K5Ep1OZ1BeNIl7UO4kcXdSAZtbpAISt9gF
+JHZSWWx2UoGkgFS7NrtkAnZtpAJjTEDCrl1gjEpNKhUYYwLbVqnAtk1gjGmzG2PaTWp3jAnYTQok
+BZIC9gSSAkmBpEBSIClgTyApkBRICiS1J5AUSMrhcDh8Kbpxo9sm7s35eb/7ux/6/Ocnl74CfpSr
+0ul0BuVFk7g35TYSdyeVxWYnlUViZ5dFYicVsNlJtSuxsysVGKOAVLs2u2QCY0yJ3RgTsLFr165d
+qUltdmNMYIxp165dm6R27drdtgls22RJCtgTSAokBZICSYGkgD2TAkmBpEBSwJ5JgaQcDofDl5Cb
+N/sf/+Njv/ALn/nEJ564fr03bkxb992nL//y7Y1v/Oq/8le+kuf29NPz3e9++LHHbnDp5fABrkqn
+0xmUF03i3pQ7SdydVMDmFqmAxC12AYmdVBYbqXaBpIBUuza7ZAJjFJBq1y4wRgGpSSXs2rVr165d
+m90Y025SqUnt2tjTZtsmsG3TblLAnkBSICmQFEgKJAXsCSQFkiYFkgL2BJIm5XA4HL603LjRD37w
+k//tvz39ute94k//6Vf8uT/36q//+vuvXTv/3d89/8VffPxf/+tHvuM7vvJ97/t6nttb3/rRz3zm
+BpcegB+CcCU6nc6gvGgS96bcSeLupLLY7KSySOzsskjspAJJAbt2AQm7Uu3a7JIJ2NiVCoxRYIwJ
+2E0KjDEBu0mlJrWRmtSuXbvbNoExpl1g2wps27mNPYGkQFIgKZAUSArYMymQFEgKJLUnkBRIyuFw
+OHzJ+eQnn/zwh/+v17/+lT/1U9+YiNs8+uj1Bx/8xAMP3Pd3/+7rxhC/l6efPn/Pez7+mc/c4NKr
+4P0grkSn0xmUF03inpU7SdydVMDmFqmAxC12AYmdVLuAhF27EnaBZAI2dqUCYxSQatfGrl1gjAmM
+UUBqUrtjTGCMAnbt2t22CYwxgW2bdu0mHWMC2zaBpEBSICmQFLAnkBRImhRICtgTSJqUw+Fw+BL1
+5JPnP/uz//Xhhz/3F//ia173ulfevDkfffTGtWvz13/9yUceuf5lX5YHH/zG0+mVPLc3v/mhJ544
+59Ir4Ce5Kp1OZ1BeChL3ptxJ4u6kstjspLJI7OyySNiVCiQFkrKMMQGpNnaBZAJjFJCaVGI3xgTG
+mMAYBeyOMYExJjBGAbvbNoExJrBt065du9s2gW2bwLZNICmQFEgK2DMpkBRICiS1J5AUSMrhcDh8
+qfsP/+Gxn//5//fs7MYY3HefH3jgvgce2L7jOx74tm97NXd1/fp85zsf/sxnbnDpNfA+CFei0+kM
+yktB4t6UO0k8L6mAzS1SAYlb7AJJWZICyQQk7NoFkrKMMYGkgF27du1K7MaYwBjTZjfGBMaYwLZN
+YIxpsxtjAts27dq1m9Tutk1g26bdpEDSpIA9gaRAUiBpUsCeQNKkHA6Hw+Gu2r7hDQ9dvz659Br4
+Ma5Kp9MZlJeCxD0rd5K4O6ksNjupLBI7u1IBG6k2u2QCdiV2Y0xAwq5duxK7MSYwxgQkkkq1axcY
+o8AYE9i2CYwx7dq1SWoXGGPaTWo36bZNu3aTbtsEkgL2BJICSZMCSQF7JgWScjgcDod78IY3/PK1
+a5NLXwY/DuZKdDqdQXkpSNyzcieJ5yUVsLlFKiCxsysVSMoyRoFkAhJ2Abt2JezaBZICY0zAro1d
+u1KTSgW2rcAYExhj2rVrN6mNXbvbNoFtm8AYM6ldu0nt3nffBOwJJE0KJAWS2hNICiTlcDgcDvfg
+/LzveMfDjz56nUuvhh+BcCU6nc6gvEQk7k15Fom7k8pis5PKkpQlKSDVrs1Oql0bqcAYE5CwC4wx
+gaSAXbs2du3atQuMMYExCowx7dq1m9SuXZtk2owxgW2bwLZNu0ntbts5sG0zKZAUSJoUsCeQNCmH
+w+FwuIo3vemhp54659JXwI+AuBKdTmdQXiIS96zcSeJ5SQVsbpFqs5NqV2JnVyqQFBijLMkEkgJ2
+7dq12Um1a9eujV27wBgTGKPAGNOuXbtJ7dq1m9TuGAW2bQLbNu0m0yaZ2zbtJrWbFEiaFLAnkDQp
+h8PhcLiiv/pXf+n8vFx6DfwoiCvR6XQG5SUicc/Ks0jcnVQWm1uSAslkSQpItdklE7CRahewK2HX
+rl2bXTKBMSZg12Y3xgTGmDZ27dq1m9SuXbtJ7dq1u20T2LYJjDG3bQLbNoFtm0mTbtsEkgL2TAok
+5XA4HA5XdH7eN7/5oaefnly6H/5Xrkqn0xnPKC8RiXtW7iTxvKSy2Ei12Um1K2EXkGqzSyZgV2I3
+xgTsSuzGmMAYBZIJjDEBG7t27dq1a2PXblK7du3aTWrX7rZNYIwJbNtManfbJrBtE9i2uW0TuO++
+CdgzKZCUw+FwOFzdjRt961s/+rnP3eTSgJ/mqnQ6nfGM8hKRuGflWSTuTipLUpakLEmBZLKMUSCZ
+LEmBMSYgYRcYYwJjFJBq166NXbt27dq1a5PUrl27du0mtWvX7rbNpHbtJrWbdNum3aR2k27bTKbd
+pEBSDofD4fCC3LzZ7//+j/7u797k0oCf5qp0Op3xjPISkbiKcieJ5yXVZifVLiBhV2JnV6pdm51U
+uzZS7QJ2baTatWuzs2tXql0bu3bt2k0qNamNXbt27Sa1a9du0jFmUrt2k9pNum3TblK7SbftPGlS
+u0k5HA6Hwwt140bf9raPPv74TS4Ffoar0ul0xjPKS0finpVnkXheSQGpdoGkLEkBu1KBpIBdm10y
+Abs2dqUCYxSwa9eu1KQSdu0mtWvXro1du3aT2rVrN+kYE9i2aTepXbvbNoFtm0mTbtsEtu08qd2k
+HA6Hw+GFunmzP/ADH3v88RtcCvwMV6XT6YxnlJeOxFWUO0ncnV2JnVS7Eju7UgEbu1JtdlLtAkmB
+MSZgYxdIJjBGgTEmYNeujdSkdu3atWtj167dpHbt2k1qd9smMMZManfbJrBtE9i2uW0T2LbzpEnt
+Akk5HA6Hwwty40bf+taPfu5zN7l0H3yQq9LpdMYzyktH4irKs0g8F7ssdlmSAnalAjZ2pdrspNq1
+kWoXsGtjVyowRoExJjDGBOza2LVr165du3Zt7NpNateu3aRjTGDbJrBt027SbZvAtk27Se0mc9sm
+kBSwm5TD4XA4XN35ed/85oeefnpy6RXwk1yVTqcznlFeUhJXUZ5F4vckVWInIdUuIGEXSArYlQok
+Beza7JIJ2LWxK9UuYGPXrl27doExCowxgTGmXbs2du0mtWvX7rZNYNsmMMYEtm0mtZt026bdpHaT
+mdQukBSwm5TD4XA4XN1f+2u/dPNmufQqeD+IK9HpdMYzyktK4irKs0g8m1QWm1uSCUjYBexK2JVq
+s5NqFxijQDIBG7tAMgG7Nnbt2rVrsxtjAmNMYIxp18au3aR27dpNOsYEtm0C2zbtJrWb1O62zaR2
+kwkkBewmBewCSTkcDofDPWv53u/9lc9+9iaX/hi8D8SV6HQ64xnlpSZxFeVZJP5/pAI2t9gFpErY
+tQskZUkK2JVqs7Mr1a7NLpnAGBOwsWvXrl0bu8AYExhjAmNMG7t2k9q1a3fbJrBtExhjJrWb1K7d
+++6bwLZNwG4ygaSAXSCpXSAph8PhcLg3N270bW/72OOP3+DSq+DHwFyJTqcznlFeahJXVJ5F4pLE
+UpudXRa7gF27gIRdqcAYZUkK2JVq18YukExgjAJ27dq1a2PXLjDGBMaYwBi1azcpMMYEtm3atWs3
+qd1tm8C2zW2bwLZNIClgF0gmkNQukBSwm5TD4XA43Js3vOGXr12bXPoy+HEwV6LT6YxnlJeaxBWV
+Z5G4JLGzyyJVQiogYRdIypJMwMauVGCMAlLtAmMUkGrXro1dYIwJjFG7wBgTGGMCY0xgjNoFtm0C
+Y0xg26Zdu0m3bQJjTGDbZlK7QNKkgF0gmUBSwG5SwC6QlMPhcPgj4Iknzh955NoY+oZvuJ+r++t/
+/ZevX59c+gr4Ua5Kp9MZzyhfABJXVJ5FYidxi11AKotdwEYqYFfCLpAUsCsVsLErFRijQDIBu3Zt
+7NoFxpjAGAXsjjGBMSYwRgG7Y0xg2yYwxkxq125Su9s2gW2bdpMCdoGkQFLAbjKBpIBdIKldICmH
+w+Hwpe4nf/ITv/ZrT33Xd732+77vT3Cbz39+/vt//5k/+2df/cADG8/h2rX5znc+/NhjN7j0ALwX
+zJXodDrjGeULQOLqyrNISOzsskgF7LLY7JIJSNgFpNrYBZICdqXaBcYokEzAro1dYIwJjFFAalKp
+Se2OUcCuXbvbNoExJrBt067dpGNMIOm2TcAukNQukBRICtgFkgkktQskBewCSTkcDocvUb/zO9ff
++95f/VN/6uUf/vC33H9/5uyb3/wrf+bPvPKDH/ymp546f//7/89t0z/+x/8zz+1Nb3roqafOufRy
++ABXpdPpjGeULwyJKyrPYnOLVAmpLHYBCYmdVLsSu2QCNnalAjZ2gWQCNnalAmNMYIwCdpMJjFHA
+rl27Se3a2P9fe3D38nl+mHX8fV3X9zczG9OkqcmmFrEl1gjir9jS0gMpiB6KByLmQWvpQ9h1E1uf
+alOL0UIteiL4BwjSMw9EkIonBVH0QBHJJtmotdInNGke7t2a7O7szD2/7+VnPrvfO/ck2cnc7e7O
+JP2+XrVr1+7hsALLsgJ2D4cVOBxWu0ntJgXsAkkBu0BSIClgN1mBpIBdIKldICm73W73jehXf/XF
+n/3Z//3449f+4T98940b/vVfv/mTP/k//8Sf+KYPf/gPJ3r/+5/+9m9/7Od//t2Hg/hqXnppffLJ
+Z5599pwLb4G/CeJKdDyecVd53UhcUbmXzSCVyS5gM1VisAvYlRjsSrUZkhWwsSsVWJYCUu3aBZal
+wLKsgFS7Nnbt2rVrFzgcateuXbt27Sa1eziswLKsdpPaTQokBewCSQG7QFIgKWAXSFYgqV0gKWAX
+SMput9t9Yzmd+pGP/Mp//+/Pv+lNedvblk996tbp1GXxH//jb3722fNPf/qlH//x7/hTf+pbeHU/
+9EMff+65cy68HZ6CcCU6Hs+4q7xuJK6ubGxeJhWwy2QzSGWyC9gFkgJSbaQCy1KmZAXs2kgFlmW1
+GZZlBaTatbFrF1iW1a5dm+FwWO3atQssy2o3qd3DYQWWZU0K2AWSAkkBu0BSwC6QFEgK2E1WIClg
+F0gK2E3KbrfbfWNZ1/7mb770S7/0+XXtd3/3W7/ne97ysY994Rd/8bM3buR97/sD3/Edj/HqXnjh
+9MQTz3zhC3e48Cb4Ka5Kx+MZd5XXk8TVlcnmZVIBu4CExCAVsAtISAUk7EoFbKTaBZICdu3aDMkK
+LEsBu3al2rWxCyzLCizLahdYlgKHw2oXWJbVrt2kdu3aTWqTrIBdICmQFLALJAXsAkmBpIBdIFmB
+pIBdIKldICm73W63g9Op73vfx1566cSFd8AHQVyJjscz7iqvJ4nfkQI2g1Qmu4DEYJfJLiAx2AXs
+SrUZpNq1GZIVsGsjFViWFbCxKxVYlhVYltoFlmUF7C5LgWVZAbuHwwosy2oXOBxWG3u1ScqUrIBd
+ICmQFLALJAXsAkmBpIBdIFmBpHaBpIBdICm73W73e9v5+frEE898/vPnXHgM/g6YK9HxeMZd5XUm
+8Ttgl0kqYJdJYrAL2AUkXmYXsAtItZEKLEsBqXbtAkkBu3ZtpNq1CyxLAbvLsgJ27dosywrYtWv3
+cFgBu8tS4HBY7QJ2gaRAsgJ2mZICSQG7QFLALpAUSArYBZI1KWAXSArYBZKy2+12X8+++MU7//7f
+P/sf/sOzd+400fXrfuGFO3/+z3/ru9/9+77t265zXy3vfe9Hb95cufB2+GtclY7HM+4qrz+Jq7IL
+SGWyC0i8zC5gF5AY7AJSAbuAjVTAblLArl2Jwa5du0BSwO6yFLBr165duxJJ7UpNateuXbtJbZZl
+BewmBewyJQWSFbALJAWSMtkFkgJ2gaRAUsBusgJJAbtAUsBuUna73e7r07/6V7/1L//lb92+3ccf
+v/bWtx7e/ObcuOH/8T+ef/750+3b65/5M2//0If+EK/u9u31iSc+eXZ2mwvX4O+CuBIdj2fcUzEN
+MwAAFvRJREFUVV5/EldlF5AK2EyVGOwCUplsBruAVMAGajMkKyAxLMsKSNi1CyzLKjEsywrYtbEr
+NalUYFlqF1iWFTgcVrvAsqw2w+Gw2rXLlBSwCyRlSlbALpAUSArYBZIy2QWSJgXsAskKJAXsAkkB
+u0nZ7Xa7rys3b54+8pFf+bVfu/nP//nxLW9ZuNc//ae//p//82///b//nX/sj72ZzY0bN37gB35A
+0vn5ee/ixRd57LHDSy+dnn32xZ/6qV/6xf/yv/irYK5Ex+MZd5U3hMSDs8skFbAZpDLZBaQCNoNd
+QCqTzWAXkAoktQskBezatQtI2LVr167EsCwrYHdZCthdlhVYlhWwezgUkHo4rMDhsDLZBZIy2QWS
+AsnKZBdICiQF7AJJAbtAUiApYBdIViApYBdICthNym63232dWFf+yT/5tf/4H5/9s3/28e/6rm/6
+vu9763PPnQM3b64f/egXfuEX/s873nHt537u3Y8/fo1L3vWud925c+d0Ot25c+d0Ov2zf/aZmzdP
+p9N669bpP/2n3/z8Sy/yk1yVjscz7ipvFIkHZBeQymQzSAXsMklAbQapElIBm0EqYBewCyQFpALL
+UsBuUsCuXbtAUrvAsqyA3WUpYHdZVsCuXRu7du0eDitTUia7QFImu0BSIFmZ7AJJgaSAXSApYJcp
+KZDULpCsQFLALpAUsAskZbfb7R55L754+rf/9nP/7t+d/dZv3T4/X21JSFy75u///rf+4A9+2+OP
+X+fVnU79kR/5xHPPnXPhzfC3wFyJjscz7ipvIIkHIRWwC0gMElIBu4DEYJdJKmAXsBmkAnYBu4CE
+Xak2w7KsgFQbu1KBZSlg165dqUltpCaVajepjdSkdu3aBZIyJWWyCyRlsgskBZKVyS6QFEgK2AWS
+MtkFkgJJAbtAsiYF7AJJAbtAUna73e7rwe3bK2Dr5s3Tm96URDyAF144PfXUJ5977pwL3wpPgrgS
+HY9n3FXeWBL3J5XJLiAx2GWyC0gMdgGpgF1AQkIqYBeQGOwCdoGkgF0gWW2GZAXsLksBu0Cy2gzL
+stoFlmW1GZZltQscDiuTXSApU1Imu0BSJrtAUiBZmewCSYGkgF2mpIBdICmQFLALJCuQFLALJLUL
+JGW32+2+EZ2f9/3vf/rWrZULb4O/zlXpeDzjrvKGk7gPqYBdJonBLiBVYpAY7AJSAbuAxGAXsAtI
+DHYBuxKDXbtSgWUpINWuXZthWVapgM2yrIDdZVkBG7t27S7LypSUyS6QlCkpk10gKZNdIClTsgJ2
+gaRMSQG7QFLALpAUSArYBZIVSArYBZICdoGk7Ha73aOn5datVeKXf/mFZ589f8c7rp2f97u+65ts
+7u906nvf+/StWysXHoMPc1U6Hs+4qzwMEq9GKmAXkHiZXUAqYDPYBaQy2QxSAbuAXYnBLiAVsBns
+AlKXpYBUu3YBiWVZAbvLUsCuXbtSgcOhUoHDYZUKJGVKymQXSMqUlMkukJTJLpCUKVkBu0xJgaSA
+XSApYJcpKZAUsAskK5AUsJsUsAskZbfb7R4Zn/3s7X/0j371N37jxTt3ejh4XXs46Py8p1Pf8pbl
+H//jP/oH/+ANXsXp1Pe856O3b5cL3wR/E8yV6Hg8467ykEh8JalMdgGJwS6TVMBmsAtIBWwGqYBd
+QGKwC9gFpAI2g1S7gI1dqXaBpIBdu3ZthmVZpQI2y7ICdpdlBezaZUrKlJTJLlNSICmTXaakgF2m
+pECyMtkFkgJJmewCSQG7QFIgKWAXSFYgKWAXSArYBZKy2+12D9X//b8v/e2//T/f9rbDe97zB/7k
+n/zma9e8rrUFnJ2dP/nkM9/7vW/98IffJfFq/spf+fhv//Y5Fx6Hp0BciY7HM+4qD4/El5HKZBeQ
+GOwCUplsBqkSUgGJwS5gF5AY7AJ2Aak2g1TALmAjFViWFZCwa9cuILEsK2B3WQrYlZpUqk2yMtll
+SsqUlMkuU1KmpEx2gaRMdoGkTMkK2GVKCiQF7AJJmewCSYGkgF0gWYGkgF0gKWA3KbvdbveQfOxj
+X/j5n//V7/zON/3cz/2RREwtL754+jf/5rP/4l98+vu//5t/+qffxav70R/9xOc+d5sLj8MHuSod
+j2fcVR4qicukAnaZJAa7gFTAZpDKZBeQGOwCdgEJu4BUwAZqM0gF7EoMdgG7EnbtAlKXpYBdqUkl
+7CaVahdYljIlK5NdNkmZkjLZBZIyJWWyy5QUsMuUFEhWJrtAUqakgF0gKWAXSMqUFLALJCuQFLAL
+JLULJGW32+3eWOvaX/iFT/3rf/2ZRBJvfnO++MU7ks7P18cey5/+09/yxBN/iFd3OvXHfuyZs7Pb
+XHgnPMVV6Xg8467ysElckArYBSReZheQCtgMUgG7gMRgF5AK2Ax2AamAzSDVLiAVsBnsSgVsBrtS
+7dpITSrVZliW1S4g9XAok102ycpklykpU1Imu0xJmZIy2QWSMtllSgokK5NdICmQlMkukBSwCyQF
+kjLZBZIVSArYBZLaBZKy2+12b6A7d/rLv/zCf/2v/+/tbz/cvLl++7ff+N7vfavu4v5Op37gA898
+/vO3ufBOeIqr0vF4xivKI0BCKpPEYBewyyQBtRmkAnYBicEuIBWwGewCUgEbqYBdQCpgIxWwC9hI
+lZBqMySrXUAiqV2pNvZqMyRlY5cpWZnssknKlJTJLlNSpqSAXaakTHaZkgLJymQXSAokZbILJAXs
+AkmZkgJ2gWQFkgJ2gaSAXSApu91u9wj70R/9xOc+d5sL3wI/wVXpeDzjFeXRYJdJYrAL2AUkXmYX
+kArYDFIBu4AE1GaQahewGaQCdgEJu4BUwEaqhFS7gM0g1a5dCbvAsqw2UoGkbJIy2WWTrEx2mZKy
+ScpklykpU1LALlNSJrtMSYFkZbILJAWSMtkFkgJ2mZICSQG7QLICSQG7QFLALpCU3W63e/T82I99
+4rOfvc2F3w8/zlXpeDzjFeXRYBeQeJldQKqExCAVsAvYDFIBqRISg11AKmAXkJCQCki1GewCUm0G
+qYBdu4CEXcCuxGB3WVZAwq5dNknZJGWyyyZZmewyJWWTlMkuU1KmpEx2gaRMdpmSAsnKZBdIypQU
+sAskZbILJAWSAnaBZAWSMtlNCtgFkrLb7XaPhpa//Jc/9sUv3uHCO+EprkrH4xmvKI8Gu4DEYJdJ
+KmAzSAXsAhISUgGpgM1gF5AK2AUk7AISUJtBql3AZpBqF5CwC9iVCtjYBaTaDMuysrHLJilTUjZ2
+2SQrk102SZmSMtllSsqUlMkuU1LALlNSpmQF7DIlBZIy2QWSAnaZkgJJAbtAsgJJAbtAUsAukJTd
+brd7qN73vqdfeOHEhW+Fv8pV6Xg84xXl0WAXkBjsAlKZbAapgF1AYrALSAVsBqkSUgEbqYBdQGKw
+KxWwC0jYBewCEnYBqTaDXamAXRupbJKyscsmKZukTHbZJCuTXTZJmZIy2WVKypSUyS5TUia7TEmB
+ZGWyCyRlSgrYZUoK2AWSMiUF7ALJCiQF7AJJAbtAUna73e6Ndfv2+p73PH06lQvvhKe4Kh2PZ7yi
+PBrsAhKDXUAqYPMyqYBdQGKwC0gFbAapdgEJCamAXUDCLiAVsJEK2AUk7AJ2pQI2UgG7ElIl7PIV
+krKxyyYpm6Rs7DIlKxu7TEnZJGWyy5SUKSmTXaakTHaBpEzJymQXSMqUFLDLlBSwCyRlSgrYBZIV
+SArYBZICdoGk7Ha73evv+edPP/zDH791a+XCN8NPgLkSHY9nvKI8AuwySQx2AamAzSAVsMskMdgF
+pNoMUgG7gMRgF7ArMUgF7AI2UgG7EoNdQKpdwEYqYFfCLiBV4tUkZWOXTVI2SdnYZZOsbOwyJWVK
+ysYuU1KmpEx2mZIy2WVKCiQrk10gKVNSwC5TUsAuU1IgKWAXSFYgKWAXSArYBZKy2+12r4/z8z71
+1Cc/85lbXFjgZ8BciY7HM15RHgF2AYmX2QWkAjaDVMAuIDHYBSSgNoNUwGaQCtiVCtgMUgG7EoNd
+wK7EYFcqYCMVsGszSJUqIZWNxH0kZWOXTVI2SdnYZZOsbOwyJWVKysYuU1KmpEx2mZIy2WVKypSs
+gF2mpEBSJrtAUia7QFIgKZNdIFmBpIBdIClgF0jKbrfbvXZ++Ic/fnZ2zoU3w09yVToez3hFeQTY
+BSReZheQCtgMUgGbQSpgF5AY7AJSAZtBql1AKmAzSLWBSgx2JQa7gF2pgIRdwK7EYFeqzSXlEolX
+k5RL7LJJyiYpG7tskpWNXaakbJIy2WVKyiYpk12mpEx2gaRMycpklykpkJTJLpAUsMuUFEgK2GVK
+ViApYBdICtgFkrLb7Xa/U+fn/Yt/8aOnU7nwTniKq9LxeMaXlIfNBiox2GWSGKRKSAVsBqmAVAmJ
+wS4gFbCRCtgFJAapElJtBqmAXYnBrlTARipgV2KwaxeQavMqyiUS95GUjV02SbkkKRu7bJKVyS6b
+pExJ2dhlSsqUlMkum6SAXaakTMnKZJcpKZCUyS6QlMkukBRIymQXSFYgKWAXSArYBZKy2+12D+zm
+zfWDH/zk5z9/mwtvgx8HcyU6Hs/4kvKw2QxSAbuAxMukAnYBm0EqIBWwGewCUiUGu4BUCYlBql1A
+QkKqXUBikGoXsJEK2JUY7Eq1GaRKfC3lEon7SMoldtkkZZOUjV02ycrGLpukTEnZ2GVKyiYpk12m
+pEx2mZICycpklykpU1LALlNSwC6QlCkpYBdIVqakgF0gKWAXSMput9u9uh/6oY8/99w5Fx6DD3NV
+Oh7P+JLysNkMUgGpgM0glckuIDHYBaQCNoNUu4DEYBeQCthIBewCEnYBqYCNVMCuxGDXLiBhF5Aq
+ISGVSyQeQLlE4j6ScoldNkm5JCkbu2ySlY1dpqRskjLZZZOUKSmTXaakTHaZkjIlK5NdpqRAUia7
+TEkBu0BSpqSAXSBZmZICdoGkgF0gKbvdbjfdvHn6S3/pY3fulAuPwwe5Kh2PZ3xJedhsBqmAVMBm
+kArYZZIY7AJSbQapgF1AYrALSAVspAI2g1S7gFTARipgIxWwKxWwkSohVcIu9yXxAMolEveRlEvs
+cklSNknZ2GWTrGzssknKJimTXTZJmZIy2WWTlMkuU1IgWZnsMiVlSgrYZUoK2GVKCiRlsgskK5AU
+sMuUFLALJGW32/2e9IEPPPOZz9ziguDvQbgSHY9nfEl5qCQkBqmAVMBmkArYBSQGu4BUwGaQCtgF
+JAa7gIRdQCpgIxWwC0hIBewCNlIBuxKDXak2g1S7XIXEAyj3kriPpFxil0uSsknKJXbZJCsbu2yS
+MiVlY5cpKZukTHaZkjLZZUrKlKxMdpmSMiUF7DIlBewyJQWSMtkFkhVICthlSgrYBZKy2+2+ob34
+4um9732ay94JT3FVOh7PuEd5eCReZheQCtgMUgG7gMRgF5AK2AxSAZtBKmBXYrALSAUk7AJ2AQmp
+gF2Jwa5dQEIqYFdisGuX3x2JB1DuJXF/SbnELpukXJKUjV0uSVY2dtkkZUrKxi6bpExJmeyyScpk
+lykpU7Iy2QWSMiVlsgskZbILJGVKCthlSlYgKWAXSMpkF0jKbrf7RvHEE898+tO3uBD4GQhXouPx
+jHuUh0disMskFbAZpAJ2AYnBLiAxSAXsAjaDVECqzSAVsAtI2AWk2gxSARupgF2pgI1UwEYqYFfi
+y0jld0fiwZR7SdxfUi6xyyVJ2STlErtskpWNXTZJ2SRlY5cpKZukTHbZJGWyy5SUKVmZ7DIlBZIy
+2WVKCthlSgokZbILJCuQlMkukBSwCyRlt9t9XXn++dOP/MjHX3pp5cLj8EGuSsfjGV+uPCQSg10m
+qYDNIBWwgUoMdgGJQSpgF5AY7EoFbAapgF2JwS4gYReQCthIBaTaDHalAjZSpQI2X5NUXgsSD6bc
+S+L+knKJXS5JyiVJ2djlkmRlY5dNUjZJ2dhlSsomKZNdNkmZ7DIlZUpWJrtMSZmSAnaZkjLZBZIy
+JQXsAsnKlBSwCyRlsgskZbfbPXre976nX3jhxAWXjwhxJToez/hy5SGRGOwySQVsBqmAzSAVkArY
+DFIBu4DEYFcqYDNIBexKDHYBCamAXYnBrlTAZpBqV2KwKzHY5XdKKq8FiQdTvoLE/SXlErtckpRL
+knKJXTbJyiV22SRlk5SNXaakbJIy2WWTlMkuU1KmZGWyy5SUKSmTXSApk12mpEBSJrtAsgJJmewC
+SQG7QFJ2u93D8OSTz3zqU7e48A74EFel4/GMr6I8DBKDXUAqk80gFbAZpAJSAZtBKmAXkLALSAVs
+BqkSg11AKmAjFbArMdiVCthIBSTsAnYlBru8DqTyWpB4YOUrSNxfUu5ll0uScklSLrHLJlm5xC6b
+pGySsrHLlJRNUjZ2mZIy2WWTlClZmewyJWVKCthlSspkF0jKlBSwy5SsQFImu0BSwC6QlN1u95p6
+8cXTe9/7NJd9C/wEV6Xj8YyvrrzhJAa7gFQmicEuICEhFZAK2AxSAbsSg1TAZpAK2JUY7AJSbQap
+gF2JQarNYFcqIGEXkGojlXtJvAGk8tqReGDlK0h8TUm5xC6XJOWSpFxil0uSlY1dLknKJikbu0xJ
+2SRlY5cpKRu7TEmZkpXJLlNSpqRMdpmSAnaZkgJJmewCycqUFLALJGWyK2GX3W73YN7znqdv3jzx
+JeUfCHElOh7PeFXljSUx2AWkMkkMdgGJwS4gFbAZpAJ2JQapgM0gFbArMdgFpEoMdgG7EoNUm0Gq
+XUDCLiBVwi5XJPHGkMprSuIqyleQ+JqSci+7XJKUS5JyiV0uSVY2drkkKZukbOyyScqUlI1dNkmZ
+7DIlZUpWNnaZkjIlBewyJWWyy5QUWJbVrk2ySiSrhIRUCamAxG63e9mTTz7zqU/d4sJb4G+AuRId
+j2fcT3kDSQx2AamAxMvsAhKDXUAqYDNIBSTsAlIBm0EqYFdisAtIlRjsSgx2Aak2g1SJwa5dqYCE
+XV43Em8kqbzWJK6ifAWJrykp97LLvZJySVIuscslycrGLpckZZOUjV02SdkkZWOXKSkbu0xJmZKV
+KWnSZL12bU1q93BY7dpNalfCrl12ux2cn/dDH/rkpz99iwvvhKe4Kh2PZzyQ8vqTGKQCNoNUJruA
+xGAXkArYDFIlBruAVMBmkGoXkBikAjZSAbsSg11Aqs0gVWKwK9VmkGqXR4nEQyGV15rEFZWvIPEg
+knIvu9wrKZck5RK7XJKsXGKXTVIuScrGLpukdpdlPRzWa9fWw2E9HNbr109JkzVp0mRNmpTdbgcv
+vHD6wAc+8fzzJy48Dh/kqnQ8nnFl5fUhMUgFbAapTHYBicEuIDFIBexKDHYBqYDNINUuIDFIBWyk
+AnYlBqmAjVTArsRgV6rEYFfiy0jlG4LEwyKV14fEFZWvRuJBJOVedrlXUi5JysZer19fb9y4c/36
+ejicrl9fr107Xb9+WpYm67Ksh8O6LF2Wld1uB88/f3r/+5/msrfBX+eqdDye8doov2sSg1TAZpAK
+2GWSGOwCEoNUu4DEYBeQCkgMdiUGu4BUQMIuIGEXkGozSAWk2tgFpEoMdiXeGFL5xiXx0Enl9SRx
+Vcuy3rhxunbtdOPG6caNO9evrzdu3Ll2bT0c1sPhdO3aejish8O6LCu73Q5u317/wl/4KJfdgJ/m
+qnQ8nvGQlY3EIBWwGaQCdpkkBruAxCDVLiAx2AWkAhKDXYnBLiBVYrALSNgFpNoMUgGpNlIBG6mA
+VJvdVyWV35MkXivJ+thjpxs37ly/frpx4/TYY3euXz9du7YeDuvhcLp2bT0c1sNhXZaV3W43/bk/
+99+4R/lZcUX/H1DtXYSCVHdAAAAAAElFTkSuQmCC
+"
+       preserveAspectRatio="none"
+       height="440"
+       width="600" />
+    <image
+       y="249.2905"
+       x="1155.2897"
+       id="image25269"
+       xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAlgAAAG4CAIAAAAWqA6UAAAgAElEQVR4AezB2ZMdV34n9u/Jk3lu
+ZmXetfZC7VXYK8lik2KzR4vblh1qzziiGWPPkOMJGZwYR1h+9F8yr9Yb+NacsOyWJkYhTTiiNy4A
+WCxcAAXwslAAakdt99bdby7nnJ/Z7GhFaySNuwtNFsV7Ph8WhlUAvp+WSlGhEOPLxzkND/dGR7uF
+QpzNpkGQMAbDMIxvGCtNc8+e5Z48yT97ln/yJP/kCVMKX5UTDNzD2AomyhgrY6yCIVgAAyaBbwEv
+o2+Ntduv7e8vHxzYWgOouy4LwyoA309LpahQiInwX0bE8Jsjwt+wbRoZ6Y6M9EqlKJtNgyBhDIZh
+GMavIoLWpBStrbV/9KPqj39cwwvigAVMAiHwEmCjP105OfnfVlbeKZd/PDv7p6+99leLiywMqwB8
+Py2Vonw+xi8RMfwDiPB3MHyBCH8vIvwN26bR0e7oaLdUirLZNAgSxmAYhvHbRMSIADApGRGILCkZ
+kZWm+ByRJSW+wKQEY2RZjIgsS9s2MaYdRzsO2TZZFjEGxnAepKQ0pWfPuj/5Se0nP6l1OgovggMc
+GAZCIAR89KexdvtPVlZulMubhcK7y8s3l5dZGFYB+H5aKkX5fAyAiOFvI8IvMQBE+M8Q4VcwAET4
+Bc4JAOcaAOcEQAg1PBwND3fz+SQI0oGBlDEYhmH8ZogYEVPKrVYztVqwt1d4/Dj/5IloNOxez44i
+EIEIACMiAIzhFxjDLzCGX0XEiPA3iACoTCb1fel5vZGRaHCwfeFCc36+fvGi9Dwwhi9Zt6uaTXl4
+mNy5U799u3F4GONFZIABIA9cBi4Bg+hb75TLN8rl2Xr9T1977ebyMgvDKgDfT4vFKJ9P8CuI8EuM
+CH+DCL/EABDhc5wTAM415wSAc+KcAHCuOSfOCQDnmnNiDKVSVCpFvp+6rnJdyRgMwzB+TUxrplSm
+Xh9///2xW7f85895FPE4Vq4rXTcpFFozM82ZmSSXS/L5JJtVmYwcGNCOQ7ZNjBHnZFlgjBgDYyAC
+Y8QYGAMRWRZxDkA0m5l63d/fHyqXh+/edatVphRTKsnn42KxOTd39NprR6+9Jj0PX5pORx0exgcH
+8cOH7QcP2s+edfEiMkARKAKTwBwwgb71xu7ujXL5nXL5h1eu/Olrr7EwrBIhCNJiMcrnE3yBCF9g
+AIjwC0T4AiPCL3BOnGvOiXPinDjXADgnzolzzTlxTpwT5xoA58Q5cU6c62w2CYLU86TjaNvWjMEw
+DOPXxOM4U6+LRmPwwYPhu3cLjx+DiBF1R0frly41Fhbak5Ot6em4WMRvjmltpamVJE6n41ar3slJ
+sVIprK8Hu7uWlEypJJvtjo93JiaqS0u169c74+P40ihFm5u9Z896GxudJ0+6T5/2kkTjRYwA48AE
+MAaMAi761jvl8o1yeazdfnd5mYVhlQi+nxaLcaEQAyDCFxgRfoEIX2BE4Jw415wT58Q5ca45J86J
+c805cU6cE+eac+KcOCfL0pwT58S5FkJzTpxr11WZjHIcbVlkWQTDMIzfCBEA7+Sk8NlnhceP/b09
+f39/4PCQaW0pRYyRZZFl4XNEYIwsizgnyyLOybJgWWRZIGJaM6WY1kwpppSlFNMaRPgFxogxMEaW
+RZZ1euXKySuv1K5di4vFuFBQQuDLd3gYr642791rHR7Gx8dJoyHxIgJgAbgElIAsEKBvzdbr75TL
+N8rlytAQC8MqEXw/LRbjQiEmwhcYET5HhC8wInBOnGvOSQjNueacOCfOtRCac+Jcc05CaMvSnBPn
+xLkWQnNOnGvOSQjFOXFOnJNta8siGIZh/FbZvZ7TbjutllurZU5PnXabJ4klpRICjBEAxsi2iTGy
+LLIs4ly6rnYc6XnK85JsVnmedF2ybW3bZFn4Gvjgg9Mf/ai6utrUGloTEc7IAhgwA7xMeAk/xxj6
+TyGK3imXb5TLAP70tdduLi+zMKwSwffTYjEuFGIiAIwInyMCwIjwOSEU5ySE5lxzTkIozkkIzbnm
+nITQlqWF0JxrzkkIzbkWQnOuOSchNOeac4JhGIbxa+t01OlpeniYfPJJY2Wl8fx5jBeRAfJAAZgF
+5oBx9K2xdvudcvlGuVx33T997TUWhlUi+H5aLMb5fAwwInyOCAAjAuckhOKchFCckxCKcxJCC6E4
+J8dRnJMQinMSQguhOCchFOckhOKcYBiGYZzV1lbvs886T550Nzd7m5u9blfhRQwC08A0MAiUgAB9
+qxBFf7KycqNcrrsuC8MqEXw/LRTiQiEGGBGIADAicE5CKCE051oILYQSQnOuhdCOo4TQnGshtBBK
+CM25FkILoTgnGIZhGL8NP/vZ6U9+UltbayUJSamJcEYWYAGzQAiEAAMY+tN3NzdvlMvvlMv/52uv
+vbu8zMKwSgTfTwuFuFCIiRgAIhAxzkkIJYQWQgmhhNCckxBKCO04SgglhBZCCaGFUEJoIRQMwzCM
+35J2Wx0fJwcH8b17zQcP2tvbPbwIDowAo8A4cAGYACz0rSsnJzfK5XfK5fLYGAvDKhF8Py0U4kIh
+IQIRAEYEz5NCaCGUEEoILYQSQjuOEkILoYTQnieFUEJoIRQMwzCM37aDg7hcbq2uNp8/j2q1tNmU
+eEHXgGvALCAAB2DoQ9/d3LxRLr9TLt9cXn53eZmFYZUIvp8WCnE+nwAgAhETQgmhhVCeJ4XQQigh
+tOtKIZQQWgjleVIILYTinGAYhmH8tnU6qtGQz5/Hd+7UP/64cXyc4EUIoAQMAheAaWAS/elStfr7
+W1v/zbNne7nc7cnJW5OTLAyrRPD9tFCI8/mECACzLBJCeZ4UQnueFEIJoV1XCqE8TwmhPE8KoYVQ
+MAzDML40u7vR6mpzZaVxdJTU62mno/AiGHAVWALmARvgAEMfcqV8p1y+US4Xoujd5WUWhlUi+H6a
+zyeFQkwEIiaE8jwlhPI8KYT2POm6UgjleUoI5XnS8yTnBMMwDONL0+mo09P06ChZWWncvdvc3Y3w
+IixgFBgFJoBxYBQQ6E/vlMs3yuXZev3d5eWby8ssDKtE8P00n08KhZiIEcHzpOdJz5NCaM+Tris9
+T3qeEkJ5nvQ8yTnBMAzD+JI1m/L27cZHH51ubvY6HdXrKSKcBQM4IIAR4BpwDfABhj5kaz3S6Vw7
+Pn71+fORdvtZscjCsEoE30/z+SSXSxiDZZHnSc+Tnic9T3qecl3pedLzpOdJz5OcEwzDMIwvWRzr
+ra3es2e99fXOkyfdzc2eUoQXkQcuAovACDAAuOhb393cvFEuv1Mu31xeZmFYJYLvp7lcks8nAIRQ
+QZB6nvQ85XnSdaXnSc+Tnic9TwmhYBiGYXzJiBDHutdTGxvdDz44vXWr3u0qIpydAwwDo8A4MAGM
+ATb601i7/U65/NbaGoB3l5dZGFaJ4HmyUIjz+QSA58kgSD1Pep70/dTzpOcpz5NBkAqhYBiGYXxV
+6vV0ZaV561Z9Z6fXaMhuVxHhjBzABYrAVeAKUETf+u7m5ltra++Uyz+8cuXd5WUWhlUieJ4sFOJc
+LrFt8jwZBKnnySBIXVcGQep5MghSz5MwDMMwvipK0bNnvcePO5VKZ2cn2tnpRZHGmTGAA5eB68Ac
+4AAcYOhDb6+t3SiX39jdvbm8/O7yMgvDKhE8T+bzST4fZzLK81QQJEGQep7y/SQIUs+TQZByTjAM
+wzC+Ku22qlaT58/jcrl5715rdzfCC8oBF4HLwBDgAR76kFDqXzx69L+Uy5eq1XeXl28uL7MwrBLB
+82Q+n+Ryie+nnieDIA2C1PfTIEg9TwZB6nkShmEYxleFCGmq41hXKp333z/9+ONGuy2J8EJGgXFg
+GhgFisAA+lA2jt96+PDfrq4Woui9paWby8ssDKtE8DyZzyfZbBIEaRCkQZAGQer7aRCkQZAEQco5
+wTAMw/hqpSndulV///3aw4ftKNJpqrXGGdnAEDACTAITwCjgoA9lpPxXa2s3yuXZev0HS0vvLi+z
+MKwSwfNkLpfkckk+nwRBms/Hvp8GQRoEaRCknidhGIZhfLWIcHyc3LlTv3OnsbXVa7dVkmicWQYo
+AMPAJDANTKBvvVmp3CiXv7excXN5+b2lJRaGVSJ4nsxmk1IpzueTIEjy+cT30yBI8/k4CFLOCYZh
+GMZXbnc3Kpeb5XJzby8+PU07HYUzE0AOKAILwDQwgb61fHBwo1x+e22tPDb23tISC8MqETxPZrPJ
+8HCUz8dBkObzie+n+XwcBGkQpDAMwzDOw/Z2b22t/eBBa2cnOj5Oul2FMxOAD5SAeWAeGEffcqV8
+p1x+a23tysnJzeVlFoZVIniezGbToaHe4GAUBGk+n+RycRCk+XwihIJhGIZxHp4+7VUq7XK5tb8f
+nZwknY7CmWWAHDAEzAIzwBj6Uz6OXzo8fG1/PxfH64ODH0xNsTCsEiGTUfl8MjraHRyMgiDN5eJ8
+Psnn4yBIOScYhmEY5+Hp0+6nn3bu3Wvu7ETVatLraZyZAArACDANXADGAI4+5Eq5cHr6B1tbU43G
+QRD8xeXLLAyrRMhkVD6fjI52BwejfD7O5ZJ8Psnn4yBIYRiGYZyT3d1oba19925zfz+qVtNWS+LM
+OFAExoEpYBwYAjz0pzcrlbfW1t5eW/vB0tJ7S0ssDKtEyGRULpeMj3eGh3v5fJLLJfl8XCrFQigY
+hmF8DShFjYZMEu04Vi5nMwbLAhGIwBg4Z/gm2t+P7t9vffJJc3u7d3oqez2FFzEETAELwCiQAzLo
+W29WKm+trb29tnZzeZmFYZUImYzK5ZLJyfbwcC+fT3K5uFSK8/mYc4JhGMZ5IEK9nj571nvwoL2+
+3t7djVotyRgYY55nXbrkLy/nLl/2BwdFLmc7DsNviAjttqzV0lotjSJ9epqenKRSaqUok7Hm5weu
+XQuKRYcxnAsiaE3Nprx7t/nTn55WKu0k0VISEc4uABaBq8AEkAEcgKHfWEQTrdbre3uvPH/ecN2/
+XlhgYVglQiajstlkaqo9NtbN55NiMcrn43w+gWEYxjnp9dS9e61yubm21q7Vkm5XM4ZSyZmZ8V56
+KXvlSjAz43oex98Wx/r4ONnaitbXOxsbnc8+6whh+T7PZKzr14NXXsn9zu/kGQP7OXyOCM2m/OlP
+a7du1dfXO1qT1jQwwOfmBq5dC65cCS5ccItFWwgLXy0iaE1K0epq8/33Tz/+uJGmWkoiwhkxQAAz
+wGXgEuADFvrT8sHBW2trb6+tHQTBe0tLLAyrRMhkVDabzMy0xse7uVxcKsX5fBwEKQzDMM5Jt6vu
+3Gncvl1fW2tFkU4SzTkbHBTj45mLFweuXw/m5wcKBQe/gggnJ8nGRvfhw9bDh+2Dg7jTUZbFhGCu
+y8Mw+M53it/+dsFxGL5AhM8dHSUffni6utp89qwbx1pK4pzNznpXrwavvpqbnHTzecdxGL5aRFCK
+Wi25sdG9c6d+/37r+fOYCGcnAB8oABeBeWAMfUso9bs7O9/Z2dGM/XRmhoVhlQiZjMrlktnZ1uho
+t1iMSqWoVIqFUDAMwzgnUtLRUXJ0FO/txY8fdzY2uoeHsdakFHHOMhlLKWSzfGhIZLN2kuijo+T5
+8wgAYwwAEYjAObMsEEFKsiwwBsbY8LCTzzu2zY6Pk1otVYqI8DkiYozlcvbsrPfqq7nLl4PZWc91
+LZyTXk8fHcVPn/YePGg9ftzZ3Y2kJJwZA4aASWAWGAMKQAb96bX9/X99//7ba2uVoaE/v3KFhWGV
+CI6jC4V4drY1MdEuFuNSKSqVIs4JhmEY540ISaIBpCk9etTa3Y27Xdluq93dqFZLs1l7YMBijElJ
+rZbM5+2pKW9qyp2YcGdm3GzW7vXU6alMEt3rqfX17tZWTykSgsWxbrcVY8jl7PFx98KFzOysd+GC
+i6+TnZ3o0aP23bvNnZ1etZp2OgpnxoAMsABcB2YAB7ABC/3m23t7b62t/e8ff/zDK1feW1r64ZUr
+LAyrRHAcXSpFs7PNCxc6xWJUKsWlUgTDMAzjxQwMDLhfcBxHSqmUsizLcRzGmPoCEXHOGWNSyjiO
+Hcexv6C1jqIoTdX2ttzZSfb2ooOD3slJ13F4segCrNWKe73Utq2BAcd17SiS+/utQsH1PMe2LSn1
+4WH72bO6lLrXk71eCg4IYBi4CswCo4CF/jTWbr+9tvbP1tcTzm8uL7MwrBLBcXSpFM3MtGZmWsVi
+VCpF+XwCwzAM46w4567rZrPZwhey2SwAKSVjzLZtxphSSkoJgHMuhJBfICLGmOM4lmVFUZymWmvG
+ObMsq1aLu900k7EHBz3LYsfH3U4nAZDPu2NjweFhu9GIGYMQPJfLaE0//vHmBx/sfPLJ/tOnp/V6
+lKYaQ8AUsAiMAgHgog/5SRIeHb1ZqXxnZ+fDqan3lpZYGFaJ4Dh6cDCanW1OTbWHhnqlUhQEKQzD
+ML5+ej29s9M7OUnbbRlFmghK0elpenqaNpsyirQQludZvZ5qtSSAbNZxHGZZrN2WvZ6+cCGTzdpE
+lMvZY2OZiYmM1shm7clJ17aZlMQ5YwxfB1LSzk5vfb17715zezs6Pk66XYWzYQADODADXAfmgADg
+AEO/caX81vPn393cdKX86czM/zs/z8KwSgTH0YOD0dxcY2amPTTUK5Uiz5MwDMM4J0TQmtKUqtXk
+2bPeZ591trZ6x8dJrZZGkSYixphlgXPGOQsC7rqWUtCapKRCwfZ927ZZqyV7PZXL2UJYnLNuV1Wr
+KedMCNbpqHo9JQLnTEpiDESwLIyPu8PDYmwsMzvrLSwMLC4O4PwQEYBbt+qrq82PP2602yqONc6M
+A1lgApgBLgDDQAb9aeno6H9YX/eTZGVi4v2ZGRaGVSLYth4Z6c3MNOfmmsPDvVIpFkLBMAzjnCSJ
+PjpKHj/urq42Pvusc3KSAPB9XiyKqSn3pZeyV674w8OCc2bbjHOGM9Gaul3daMgnT7oPHjQfPmwf
+Hyda43P5vP366/nf/d3ipUu+bTPOGb5yaaprtXRzs7e62qxU2js7UZoSzoYBFmADs8Bl4AogAA4w
+9BsvTf+7p0//zd2739vY+OGVK39+5QoLwyoRbFuPjPTm5xtzc81SKRoe7nFOMAzDOCdK0dFRsrXV
+W1/vPH7c3duLTk4SgFkWLItduxa88kp2dtZzXZ7JWMPDwnFYHGshrIEBDqDbVYzhc7bNOGenp6lS
+5HmcMfR6+vnz6PnzuNmUrZY6PZW1WtJoyFotabeVZbGBAWt83L10yX/55ezUlDs46Hgex3nQmk5O
+0vv3W7dv1x88aKUpSam1xhk5QBYYBeaBSaAEZNCHRjqdf7Kz88f37o10On927doPr1xhYVjVGo5D
+w8PdubnmwkJjeLg3PNyDYRjG10O9nq6vd5896z5/Hnc66vg42d7uAWCMaU34glJkWYwxEIEIRMQY
+PkeEX7AsBoB+DrbNtAZj4Jzl8/aFC+74eGZ0NDMx4RaLdi5nBwH3PG7bDOcqinS9nh4cJHfu1B88
+aG1vR1oTXoQLzACLwCJQRN9aOjr6oydPhjqdu+Pj//76dRaGVa3hODQ62pmfby4sNIaHe6VSBMMw
+jK8xrYkIlsUANBopYyyX442G7HaVbVueZxFBa5KSbNsqFGylKI41AMexHIfhH4laLXn0qLOy0lhf
+79Rqaa+ntSacDQMKwAXgEjAKZAEPYOhP//Tx4zd2d1uZzH+an2dhWNUajkOjo53FxcbiYn14uJfP
+JzAMwzDOVRTpVks+fx7dutV4+LC9uxslicbZMMAGPCAHXAfmgGGAoz+5Ur5ZqfzRxsZMo/GDpSUW
+hlWtwTlNTHTm5pqXLp2OjXWDIIVhGIZx3jodtbraWF1t3r3bbDSklIQX4QKzwCJwEfABG/1prN1+
+s1L5o42NNyuVm8vLLAyrWoNzmpjoLC42Ll06HRvrep6EYRiGca7SlOr19OnT7spKc329vb8fR5HG
+mVlAFpgA5oEZIA8IgKEPjbfb369UXt3fPwiC/+vaNRaGVa3BOU1Otmdnm9ev14aHe54nYRiGYZwr
+IrTb8sGD9upqY22tvbcX4UVwIAuMAgvANDAE2OhPY+32m5XK9yuVN3Z3/913vsPCsKo1OKeJic7i
+Yv3atdPR0a4QCoZhGMZ5OzpKPvus88knjZWVRrerlILWhLOxAQFMAJeARSAPWABDH8rF8f/84MFi
+rfakWPyPly6xMKxqDc5pYqIzP99YWqpNTLQ5JxiGYRjnSimq1dKNje7du82HD9vVatLpKLyIAJgE
+FoEZIAAygIX+9L2NjT/a2Hhjd/dHc3MsDKtaw7IwNdVaWGhcvVqbmmrDMAzD+BqoVtPHjzuffNK4
+f7+1vx/jRVhAFhgCFoAZYBBw0bfe2N39w2fPYs7/w+XLLAyrWsOycOFCe2Gh8dJLJxMTHRiGYRhf
+A9VqWqm0V1YaH35YjyJNP4czcgAPGAIWgTlgEBDoQ1zr1/f2/uXDh4O93kdTU3929SoLw6rWsCxM
+TbUWFhrXrtUmJ9swDMMwzpvWdHKSVirtlZXG/futVktJSVoTzoABHHCAQeA6MAsMAgJ9aLrR+MOn
+T/9kZWW60firxcW/XlxkYVjVGpzT5GR7YaFx7VptcrINwzAM47xJSa2WfPKke/t2/dGj9tFREsea
+CGfBAAZYwBhwHZgBRgGO/pSR8lsHB//80aPX9/b+anGRhWFVa1gWJifbi4v1a9dqk5NtGIZhGOeK
+CFJSkuj19e4HH9Qqlc7+fpymGmfDAAZYwBywCMwCIwBDf8oo9cbOzjvlciGK/vLiRRaGVa1hWZie
+bs3PN65dq01OtmEYhmGcKyIoRWlKjx61V1Yaa2ut7e1Ia8KZMYABs8AVYAoYRz/LR9GNe/eycXxr
+cpKFYVVrWBYmJ9sXL9aXlqrj4x0YhmEY54oIWlOaUqXSvnWr/vBh+/nzOI41zowBDJgGLgFzwBjA
+0J8yUr6xu/v22tpYu/2XFy+yMKxqDc7pwoXOxYv1q1drk5NtGIZhGOctTanZlJVKe2Wl8emnnWo1
+iWNNhLNggAVw4AJwGZgBRgCO/pSR8lsHB//80aPf297+i8uXWRhWtYZlYXq6tbDQuHq1NjnZhmEY
+hnHetKbj4+TTTzsrK/X791vttlKKtMZZMMAGBDAIXAemgSHAQR+abjT+8OnTP1lZmW40/mpx8a8X
+F1kYVrWGZWFysj0/31haqk5OtmEYhmF8DdRqaaXSWVlpfPjhaa+n6edwRg7gASXgCjADDAICfSij
+1Lf29//lw4eDvd5HU1N/cekSC8Oq1rAsTE+3FhYaV6/WJifbMAzDML4GarX08eNOudy6e7e5txfh
+RXAgC4wAc8AMUAJc9K03dnf/26dPu47zZ9eusTCsag3LwvR0a3a2ubRUHR/vcE4wDMMwzpVSdHSU
+rK937t1rPnrUPj2V3a7CmTEgC0wBi8AM4AMCYOhP39vY+KONjTd2d380N8fCsKo1OKcLFzqLi/Vr
+12ojI10hNAyjL6WppZQFgHPtOBqGca4OD5NPP22Xy82VlUa3q5QirXFGNpABLgAXgUUgB1gAQx/K
+xfH/9OjR5ZOT7ULhP1y6xMKwqjU4p6mp9uxsc2mpOjLSFULDMPqJ1ixJeKvl7O4G29vZbtf2PBmG
+1dHR7sCAtCyCYZyHTkc9etS+f7+1utrc3u7hRXDABwaBeWAOGAEE+tNYu/1mpfL9SuWN3d1/953v
+sDCsag3O6cKFzuJi/fLl09HRnutKGEY/kdKq18XmZu7Ro1KjIfL5ZHGxMTfXGBqKbFszBsP46iWJ
+rtXSJ0+6KyuNx4+7BwdxHGucmQXkgXHgMnAByAEOwNCHxtvt71cqr+7vHwTB/331KgvDqtbgnC5c
+6MzPN65erQ0NRb6fwjD6zPZ29tGj4p07o72eHYbVV145nplpZTKKc4JhnJNOR62sNFZXm+Vys9mU
+UhJehANcBC4CC8AAYKM/jbXb39vY+H6l8malcnN5mYVhVWs4jh4d7S4uNi5dOh0ainK5BIbRN4ig
+NTs8HFhZGVlfL7TbIgxPXnnleGamxTnBMM5JFOl2Wz5/Ht+6VX/woLW3FyeJxtkwwAZcIAdcB+aA
+EYCjb71ZqXy/Uhlrt/+fq1dZGFa1huPosbHuwkJjYaE+NBQVizEMo2/EMW82xcmJ++mnpZMT13XV
+5cunMzOtUikWQsH4WlKKpCTGQITT09S2rSDgJydJt6uEsIKAx7FOEg1gYICXSo6U1OtpxjAwwDMZ
+C/9InJwkDx+279ypr693m00ZRVprwtkwoABMABeBMSAHeABDf/qnjx+/sbvbymT+0/w8C8Oq1nAc
+PTbWXVhozM01Bwd7Q0MRDKNvxDHf3Q0+/bS0tlbK5ZLp6db167WRkd7AgGSMYJy3Wi19+LBdqbS3
+t6M01Y2GPDqKifA5pYgxRgStybIYY/ic1kSEX2VZ4JwBUApEZFmMiBgD56xQcGZnvdlZb3bWW1z0
+czlbCMu2GWM4d1GkG4304CBZXW3cvdvc2oq0JrwIF5gDFoEFoID+xLV++fDwv97cHOp07o6P//vr
+11kYVrWG4+iRke7iYmN+vjk42CsWY84JhtEfpLSePs3dvz+0ujqsNfv9399/+eWT0dGubWvGYJwL
+KenwMN7aiiqV9tOn3d3dqFZLGWO2zRyHXb+effXV3OXLfhBwzlkQ2FpTr6dtmwlhMYbd3ahS6Tx8
+2Nrejo6PE60JgGWxxcWBS5f8wUEninSno6rV9PAwrlaTVkulqdaafJ8PDYm5uYGXX86GYdb3eSZj
+cc5wHpSiajW9d695+3bj/v2WlFop0hpn5ABZYBhYAKaAEpBBHxrpdP7Jzs4f37s30un8x0uXfrC0
+xMKwqjUcR4+NdWdnm3NzzaGhqFCIhNAwjD6gFEtTq1ZzV1ZGdnaynY6ztFS9erU2NdW2bQ3jnMSx
+PjxM1tc7q6uN9fVOrZYC8H1eKonpaffll56uv1wAACAASURBVHNLS8HQkLAsWBbDryACY/jc48fd
+tbXWw4ftw8O4Wk07HSmElc3yqSn3W9/KX70azMx4QlidjtrdjR48aD561H72rNdqKSKyLJbP26+/
+Xvi93yvOzw84DuOcMYavWJpSrZZubXU/+aRZqbR3dqI0JZwNAyyAA7PAJeAqkAEswEK/cbT+7x8/
+/jd3775ZqfxgaenPr1xhYVjVGkLo4eHe/Hxjero1NBQVi7HrShhGH0hT6+TE3d7Obmzku10nn08W
+Fhqzs80gSDMZBeOcEEEpiiK1vx8/fNh++LC9vx/V67LbVUoRY2CMWRYsi3HOslnuOFa3q9JUaw3G
+kKakNSlFjMGymG2z0dHM0lL28mV/bm6gULAHBjhjVK/L4+Nka6tXqXQ2NroHBzEAxuA47PXXC9/+
+duF3fidvWbAsxhi+ekQgwocfnn78cWN1tdHt6iTRODMbyAMXgBngAlACBPrTxVrtf3z0yE+SlYmJ
+92dmWBhWtYYQeni4NzfXmJlpFYtxsRj7fgrDOD9KMSLGGHFO+IKUFgDb1vglpRjnBIAIRIwxYgy/
+oDUDYFmEX9KaMUaM4T9DhJMT79Gj0gcfjEWRffny6dJSbW6u6fsp5wTj64QIn+t21cZGZ28vPj1N
+Wy3JGHNdK4p0r6dsm+Xz9sAAHxjg2aw9MpIRgvk+Hx4W+PtoTdVqmiTatlku59g2Oz1NbZsxBsex
+PM/inOH8SEm7u9GjR+3791vb271aLe10FM6GAQzgwAxwHZgDAoADDP3GT5KXDw+/u7npSnlrcvIv
+L15kYVjVGkLowcHewkJjcrJdLMbFYpzLJTCM8/Dpp8WtrWyn47iuimN+fOwpxTxPep4UQjebolZz
+c7kkn49tm6KIV6suEUZGepmMShKrXs8A8DyVyyVKsaMjz7a1EHpgQNq2PjoaiGMrl0tzucS2dasl
+Gg3Rbjtas16P7+5mbVuPj3emp1sjI70o4vV6xra158lMRjNGp6duFPFcLg4CaVnUbju9ns05ZbOJ
+betu10kSy7a1ENp1ZRTZjUZGCOX7aSajAKrVXKUs308HBiQR6/U4ANdVk5Pt+flmNpvA+AbhnLuu
+m81mS6VSPp/PZrNEJKVkjDmOwxiTUiqliMi2bSGElDJNU3zBcRzOeRTFaaoA63OMsWo16nbTTIaX
+SgOcs2q11+ulAPL5zPCwf3jYabVizhnnVi6XkVL/7GfbH364Uy4frK9Xa7VekigMAhPARWAcCAAP
+fchPkvDo6M1K5b/a3Pzx7OyfX7nCwrCqNYTQw8O96enm5GS7WIyLxbhYjGEY56RadU9O3Ho9ozXL
+ZtNsNmk0RBTZlkWOo4Mg1Zq1Wo7WzPdT11VSWnHMk8RyHF0qxUlitduOlBZj8P00n0/qddHr2ZZF
+QqggSJWy2m1HKeb7kjFqNsXJibexkW80hOfJ+fnm4GCUzaaca99PBwej09NMt2sDzLZ1EKRKsU7H
+IcLAgBRCac26XSdJLCFUoRBzTo1GJk0tIuZ56dBQVK9nej2bc21Z5HmKc2o0hNZsYEDatrZt7XnS
+sgAQYzDOjAiM4VdpTZbFcK5833ddN5PJ2LYtpdRaM8YcxwGQpqnWmjHGObcsS0oZx7HjOJxzy7K0
+1nEcp6ne3Ew3N6P9/Xh/v1OrRa5rFwouEVqtOE21EHxgwBGCN5vx3l5raMjzfeE4llL64KCzuVlP
+UxVFsteT4EAGGAEuAfPAKMDQn8ba7bfX1v7Z+nrC+c3lZRaGVa0hhB4cjGZnmxMTnUIhKhbjYjHm
+nGAYfeDwcODx4/z9+0NEGBnpvfTSyYULnUxGOY6G8TWgNZJEE0FKevSovbcXdbuq0ZDb272jo8R1
+rTjWzaYEoDU5jsUYtIaURATGAJBlMfyS61qWxRhDmuo0pcFBZ3ram531ZmcHLlzITE66jDHLwtfE
+9nb06FF7dbW5u9ur1dJOR+FsGMCADLAIXAemAQewAYZ+8+29vbfW1v6Pjz76wdLSe0tLP7xyhYVh
+VWsmhBocjGZnm6Oj3WIxLhbjQiESQsMwvtGIQMSUYmtrg7dvj66tDV67Vnv55ZPl5RPPk5ZFMM5P
+kujt7Whrq7e11dve7u3uRsfHCefsc47DMhlLKfg+n552i0WHc5bN8rGxTCZjxbHWGo7Dslk7m7Vb
+LdntqiTRlsV8n3OOajU9OIiPj5Pd3ahaTbWmNKUk0UoRwLJZPjXlvfxy9vJl/+JFPwg4zkmvpw4P
+k2fPeg8etB4/7uzuRlISzowBQ8AkMA+MAgVAoD+9tr//r+/ff3ttbbNQeG9piYVhVWvmurJUiiYn
+2xMTnVwuKRbjXC7x/RSG8U0npdVqOdWq+9lnxY2N/MmJ++qrxy+9dDI/34Rxfoio3VYffli/c6f+
+2WedNNVKkevy6Wn30qXg2rVgetotlRwhLLwAIjCGVkveudO4fbt+/35LSlKKHMean/euXQtefjk3
+MZHJ520hLHzlpKR2W21sdG/frt+/3zw4iLXG2QlgAMgDl4AFYAx9Syj1uzs739nZ0Yz9dGaGhWFV
+a+a6slCIp6ZaY2PdXC4pFuNcLsnlEhhGH2i1nN3d4LPPisfHnm3riYnO3FxzZKRXKMQwzk+a0v5+
+tL7e+eST5tZW7/g4lpIYY5wz22aOwzIZa3Q0MzaWGR4WpZKTy9mcs3Zb9nracZjnccdhlsVOTpJe
+T2tNUlK7Lff3Y85Zt6tOT1OlqNfT3a7SGlqTZWFggAthDQ+L11/Pv/56YWrKxTkhgtYkJa2uNj/8
+8HRlpZEkJKXWGmfEgAwwDVwBLgIBwNCflg8O3lpbe3tt7SAI3ltaYmFY1Zq5riwU4qmp1vBwL5dL
+isU4l0tyuYRzgmH0gf19//79wXv3hjinxcXGK68cj493OdecE4yvByLa3Ozt7EQ7O9HeXry11dvf
+jyyLOQ6zLFgWAxDHWmvQz0EIy7KYlJoIv5DN2pyzdlsOD4vBQTEwwPN5u1h0ikWnWHRGRsTgoGNZ
+cBzLthnOGxGIqNmUd+82P/qo/uBBK461lESEs/OAy8BVYALIAA7A0G8soolW6w+2tq4eHzdc968X
+FlgYVrVmrisLhfjChfbQUC+XS4rFOJdLcrlECA3D+EYjgpRWHPO9Pf/jj0crlWKxGH/rW8fLy8e5
+XMI5wfhHhQhEYAyM4W8QgTH8Y/T8eby21lpdbW5u9k5P005H4UUMAZPARWAYyAMZ9K03K5W31tbe
+Xlv7wdISC8Oq1sx1ZaEQT062BgejIJC5XJLLJblc4vspDOObjgjNpjg8HHj2LLe7GzSbzshI7+WX
+T+bmWr6fwjDOz95e9OmnnZWVxv5+dHKStloSZ8aBIjAKTAMTwBDgoT99b2PjRrn89traD5aW3lta
+YmFY1Zq5riwWo/Hx7uBg5PtpLpfkckkul+RyCQyjDxDh8HDg0aPS3bvDQqjJyfbVq7XBwTifT4RQ
+MIxz8vRp97PPOvfutXZ3o+PjpNtVODMHyAEjwBQwBYwDNvpQRqnFWu0PtrbmTk93c7m/uHyZhWFV
+a+a6sliMRkZ6g4NRLpf4fprLJb6f5nKJEBqG0R+2trIrK6MPHgzm8/FLL1VfffUon08YIxjGOXn2
+rPfZZ51795q7u9HJSdJuK5xZBsgBQ8AMMA1MoD/l4/ilw8PX9vdzcfxgZGRlYoKFYVVr5nlpoRCP
+jPQKhTiXS3w/9f00n099P/X9FIbRB5KERxHvdJxOx+l0bMfR+XwyNNTLZBQM45xsb0eVSrtcbu3s
+9I6Pk05H4cwE4AElYAGYAy6gb7lSvlMuv7W2duXk5ObyMgvDqtbM89JCIR4e7uVySS6X+H4aBNL3
+01wu8f2Uc4JhGIbxldvfjyuV9t27rZ2d3tFR0mpJnJkDZIEiMA/MAJPoW8sHBzfK5bfX1spjY+8t
+LbEwrGrNPC8tFOJSKcrlklwuCQLp+6nvp76fBoF0XQnDMAzjK3d8nJTLzQ8+ON3c7LXbKo41ziwD
+5IEhYAqYAcYAC/3pzUrlrbW1NyuVm8vL7y0tsTCsas08Ly2V4kIhyuWSIJC+n7qu9P00CKTvp76f
+ck4wDMMwvlppSrdu1X/2s9qjR+0o0mmqtcYZ2UAJGAWmgHFgDHDQhzJS/qu1tRvl8pWTk5vLy+8u
+L7MwrGrNPC8tleJCIfL9NAik60rfT4NA+n7q+6nnKdeVMAzDML4qRJCSkkSvr3fef//0zp1Gs5lq
+jRcyDIwBU8AYMAQMoA9llPrje/f+7erqWLv97vLyzeVlFoZVrZnnpaVSXCpFmYzy/dR1ZRBI15W+
+nwaBdF3p+ynnBMMwDOOr0uvpZlPW6+lHH9U/+aSxudnDC8oCc8ACMApkAR99SCj1Lx49+l8/+WS2
+Xn93efnm8jILw6rWzPPSUikulSLb1r6fep5yXen7qecp309dVwaBdF0JwzAM46uiNe3sRE+f9tbX
+O8+edZ8963W7CmfGAAu4BFwH5giCwQYY+tDba2s3yuU3NjZuAu8CLAyrWjPPS0uluFSKGCPfTz1P
+ua70POX7qetKz1O+n7quFELDMAzD+KrU6+nqavP27frWVtRsynZbEuGMHCADFIBrwBWghP61u4ty
+GeUypATAwrCqNfO8tFSKS6WIMXJd6XnKdaXnKdeVnqdcV3qecl3p+ynnBMMwDOPLJyXFsX76tPuz
+n51+8MFpu63o53BGNlAESsAEMANMAjb6ztoaymVsbOBXsDCsas18Py0U4lIpYoyE0I6jPE+5rvQ8
+5brSdaXnKdeVnqdcV3JOMAzDML5kSaL39uKdnd76erdSaW9sdJUivIgsMAMsAqNADvDRL6REuYxy
+Gbu7+DtYGFa1Zr6fFotRqRQB4JwcR3mecl3pecpxlOcp15Wep1xXCqFdV3JOMAzDML5kzaa8c6fx
+0Uenm5u9Tkd1u4oIZ8QBGxgGloDrQAAwfPNJiXIZ5TJ2d/EPYGFY1Zr5flosRqVShC8IoV1XCqFd
+V3qechzlecpxlOcp15VCaNeVnBMMwzCML00U6VZLVqvp7dv1O3ca29s9vAgLGASGgAlgErgACHzD
+lcsol7G5if8iFoZVrZnvp8ViVCpF+ALn5DjK85QQ2nWlENp1pRDacZTnKcdRnqccRwmhYRiGYXxp
+jo6S+/ebn3zSfP48Pj5Omk2JF8GAi8A1YB7IAA5g4ZtpYwPlMtbW8GtgYVjVmvl+WixGpVKEXxJC
+O44SQruuFEILoV1XCqEdRwmhXVcKoYXQjqM4JxiGYRi/bb2e7nTk4WHy4Yent2/XDw8TvAgHyAMF
+YBKYA2bwzVSvo1xGuYx6Hb8eFoZVrZnvp8ViVCpF+CXOyXGUEFoI7ThKCC2EdhwlhHYcJYT2POU4
+SgjtOEoIDcMwDOO37fAwuX+/WS639vejk5OkXpd4QVeAq8AM4AICsPCNUqmgXEalgt8EC8Oq1sz3
+02IxKpUi/ArOyXGUEFoI7ThKCC2EdhzFOQmhHUcJoYXQjqOE0I6jhNAwDMMwfkt6PXV6KqvVdGWl
+sbra2Nzs4UVwoASUgElgCpgGLHxztNsol1Eu4+QEvyEWhlWtme+nxWJUKkX42zgnx1FCaCE05+Q4
+SgjtOIpzEkI7juKchNBCaMdRnJMQ2nEU5wTDMAzjt+H9909/9rPTtbVWHOsk0UQ4IwYwYAZ4CXgJ
+YAADGL4JDg5QLqNcRhThN8fCsKo18/20WIxKpQh/B+fkOIpzEkJzTo6jhNCck+MozkkIzTk5jhJC
+c06OozgnITTn5DiKc4JhGIZxVpubvSdPuuvrnWfPeltbvW5X4UUMAlPANDAIDAIBvgl2d7GygnIZ
+Z8XCsKo18/20WIxKpQh/H86Jc7IsLYTmnITQlqU5JyE05+Q4inPinBxHcU5CaM6Jc3IcxTkJoS1L
+c06cEwzDMIxfWxTpdluenKS3btVv3arv7UV4EQ4QAAGwAFwELuCbYHcXKysol/ECWBhWtWa+nxaL
+UakU4R/GOXFOlqWF0JwT58Q5OY7inDgnzsmytBCac+KcLEsLoTknzolzsiwthOacOCfL0kJoGIZh
+GL+Gjz6q//SntXK5lSQ6TTURXsgM8DLwMsAABjD8I3ZwgHIZ5TKiCC+AhWFVa+b7abEYlUoR/v9w
+TpyTZWnOiXPinDgnzsmyNOfEOXFOnJNlac6Jc+KcOCfHUZwT58Q5cU6ZjBRCO462LLIsgmEYxt/H
+kpIp5bTbA8+fe8fHltbKcbQQcmBAum4aBEkuJ32fGMOvYFozrS2lBg4OvKMjt1rN1OtOs2lJCYAY
+00Jox1Gum3qeHBhI8vkkl0uz2dT35cCA5hyM4evh8DD+/9iD1+Y6jvxO0L/MrMpThapT5wIcEAAB
+EAR4Edksid2t1vbInrE9jvH0rMfty26MNBETq/bGxjpiYz/U7qudl/sF7Am51ZJIgeQhCRIACRIg
+LiRB4ADnXrfM/C9bHXZ42pftBiRCEvJ5bt/u3rvXffky39vLOx2F4wiABeASMAqUgRDfYv0+mk0s
+LqLdxvGwOG4Zw4KgqNXSej3Fb0MIEoI4N0KQECQECUEAhCDOjRAkBAlBQhDnBoAQJAQ5jgnDIgiU
+5ynXNY5jGINlWdavcfv92vJydW2tvLkZbm2FOzvEGHE+mJx89e67rbffTuv1rFYrwpArxbSurK2d
++eKL8Zs3nSRxh0Oe5wAYkXFdLSUYY0oxIrxGhH+Aac2MISGM6yrf783Ndc6f75071z1/vj8zQ5zj
+hBhDm5vps2fJ+vpwZWXw+PEwzw2OowGMA1PAJDAFePgWW1pCs4m1NRwbi+OWMSwIilotrddTHJUQ
+BEAI4twAEIKEICEIgBAkBAHg3AhBjKFWy2q1LAiKUkl7nmIMlmVZvyZaXx+9f3/0wYORly/93V13
+OCTOwdjLH/9451//6/133jGuS65bOjgIt7fLGxuVtbXq2pq/t0eMgbHDK1f2r18/uHo1q1azalWX
+SvinlA4PR3Z3w52d2vJybXnZ398HEYD2xYuta9c6Fy4kZ84Mz5zRpRLeuOFQt1rF3l52/36/2eyu
+rQ1xHBKoABVgBrgAnMW32P4+FhfRbCJNcWwsjlvGsCAoarW0Xk/xVROCAAhBADg3AFyXxsaSsbE0
+ivIgKIKgYAyWZVm/hivFiyLY3p769NPJTz4pHR5ypZgxWkpdKuVRNDxzJhkbG0xNJY0GIxq9d69x
+547sdrnWIMorlTyKhhMT/ZmZzvx8EYZFGCrfx2uM8Sxz0tQdDEZevChvbY28fOnv7Xn7+0xrcF6U
+y3vXr+9fv96bmclqtaxaxUkYDnWvp3d3sxs32jdudHZ3MxxHCfCBELgKXAZG8S22soLFRayt4avA
+4rhlDAuColZL6/UUXz/HoUYjaTSSWi2NoiIMc8ZgWZb1L/MODrxWK9zeri0vV1dX3X5fZBnXmivF
+i4IZAyL8cxjDlwh/hzEwBsaIMQBZrTacmBicPdubne3Mzw/PnNGep3yfOMfJKQqT57S+Pvzbvz38
++OOD4VDjOATgAA3gGhADAb6t0hTNJppNvHyJrwKL45YxLAiK0dGkWs3w9XMcajSSRiOp19NyuQjD
+nDFYlmUdFxEjYlpzrZnWzBgYA8aIcxLCCEFCgHMCwBi+Pe7f7/31X7f++q9b+EpMA9eB64CDb6t2
+G80mmk202/gqsDhuGcOCoBgdTarVDF8/x6FGI2k0kno9LZeLMMwZg2VZ1ncMz/PK+nr09Gllba3y
+9Gm0vs60xpuyj5G7mFjEVBMTTUysYAy/Mg1cB97Ft9j+PppNNJvo9/FVYHHcMoYFQTE6mlSrGb5+
+jkONRtJoJPV6Wi4XYZgzBsuyrONgRDCGGcO05koxrRkRM4Y4JyGIcyMECUFCEGNgDN94RFCKlDJL
+S/2PPz74+OMDHAcDBCCAaSAGrgEOvq3abTSbaDbRbuOrwOK4ZQwLgqJWS+v1FF8/x6FGI2k0klot
+jaIiDHPGYFmW9U9iWnOleFHUHz6sP3xYefTIHQzcwcAZDkWec6WYMXiNCL+GMfwaIrzGGAFgDK8x
+RoyBsTyK0tHR4Zkz3fn59oULw4kJFQRFEBDnODlFQUVB6+vDjz8++Pjjg+FQ4zgE4AAN4BoQAwG+
+rdIUzSaaTbx8ia8Ci+OWMSwIilotrddTfNWEICEIAOcGgBDEOcbHh/V6VqlkIyMqCArGYFmW9Wv8
+V6+CFy/Czc36w4f15WW332daA1C+n0dRMj7enZ/vz8wk4+NprVaUy7pU0lIS5/jnMWOcJOF57gwG
+7nDo9nrB7u7Iy5fB8+f+3t7Iy5dMazBWhOH+O++04rh37lxaq6WjozgJw6Hu9dTubn7jRvvGjc7u
+bobjKAE+EAJXgcvAKL7FVlawuIi1NXwVWBy3jGFBUNRqab2e4qiEICEIAOdGCAIgBAlBQhAAIYhz
+A0AIchwTRUWtlgVB4XmqVNKMwbIs69dU1tbG7t4dvX/f39vz9vedNCUhjOPsvvfei/ffP7h2TUtp
+pCTOcQwjL19W1taijY1ofb28sVHqdokxMHZ4+fL+9evtixfTsbF0dFRLiTduMNC7u9mLF9nDh/37
+9/vr60McRwmoATVgGjgPTOFbbH8fi4toNpGmODYWxy1jWBAUtVpar6f4jQlBQhDnBoAQJAQJQUKQ
+EMS5EYIACEFCkBDEuRGChCAhiDEKwyIIlOcp1zWOYxiDZVnWr+FKuf2+MxhU19ZG790bffBAJImT
+JKIoQARAl0rK87TnKd/XUoJzEDFjuFIAeFHwPOdFwYuCa82VIsaIMQYwY0DEjGHGgAhfUkGQVSrJ
++HjnwoXOwsJgaiqt1fIoAmM4IVrTxkaysZE8fZo8ejR4+nSY5wbHMQ5MAlPABHAG8PAttrSEZhNr
+azg2FsctY1gQFLVaWq+n+P8jBAlBnBshSAgSgoQgIYhzIwQJQVIazo0QJAQJQUIQ50YIEoKEICFI
+CCqVlJTGdQ3nxDnBsizrX0YEwEkS2es5w6GTJE6SOMNhqdMptduy03G73VK77aQpLwoQEefEOTmO
+cV3julpKXSppz1OepzyvKJdVEOTlch5FeRSpICiCQEsJzokxfJPs7ma3b3fv3eu9fJnt7eWdjsJx
+BMACcAkYBcpAiG+xfh/NJhYX0W7jeFgct4xhQVDUamm9nuKfJwS5rhaChCAhSAhyXS0ECUFCkOtq
+IUgIEoKEINfVQpAQJAS5rhaChCAhSAhyXS0EwbIsy/oN/OIXh//tv7Vu3+4aQ8aACEfEAAbMAe8A
+7+C74OVLNJtoNpGmOAYWxy1jWBAUtVpar6f4pwhBQpDraiFISiMEcW6kNEKQ62ohSAiS0nBupDRC
+kBDkuloIktIIQZwbKQ0sy7Ks38ZgoA8Pi1ev8sXFzuJi58WLDMdRAipAFZgDzgOT+C7Y3sbiIppN
+HAOL45YxLAiKWi2t11P8I0KQ62opjRAkpeHcSGmEINfVUhohyHW1ECSlEYJcV0tphCDX1UKQEATL
+sizrqJ49S9bWho8eDTY2ko2NZDjUOI5RYBaYBUaBOhDiu2B7G4uLaDZxVCyOW8awIChqtbReT/Hf
+k9JwbqQ0UhrX1UKQlMZ1tZRGCHJdLaWR0ghBrqulNK6rhSAhCJZlWdZX4ec/P/j448OlpV6ek1KG
+CEfEAQ7MATEQAwxg+I54+RLNJppNpCl+eyyOW8awIChqtbReT/EPCEGuq6U0UhrX1VIaKY3raimN
+62opjZRGCHJdLaVxXS2lgWVZlvUV6ff13l7+6lV25073/v3e5maK4xDAODAOnAWmgCmA47uj30ez
+iWYT+/v4LbE4bhnDgqCo1dJ6PcXfEYJcV0tppDSuq6U0UhrPU1Ia19VSGimN62opjetqKQ0sy7Ks
+r9rLl1mz2bt9u/viRXpwUHS7Csd0FbgKzAEScAGG75SVFTSbWFnBb4PFccsYFgRFrZbW6yn+jpTG
+85SUxnW1lMbzlJRGSuO62ve162opjZTG8xQsy7Ksr0G/r7td9fx5dvNme3Gxs7eX4zgkUAdGgWlg
+BpjGd1O7jWYTzSbabfxmWBy3jGFBUNRqab2e4ktCkOcpKY3nKSmNlMbzlJTG85SUxvOUlMZ1tZQG
+lmVZ1tfm5cvs1q3uZ58d7u8X7XYxGGgcBwOuANeAecABBMDw3bS2hmYTS0v4DbA4bhnDgqCo1dJ6
+PcWXpDSep3xfu672fe262ve15ykpjecpKY3nKSEIlmVZ1tdmMNCHh8WrV/niYufOne72dorj4MA4
+MAlMApPAGUDiO67ZRLOJjQ38i1gct4xhQVDUamm9ngIQgjxPSWk8T/m+9jzl+9p1te9rz1O+r11X
+C0GwLMuyvk5E6HbVzZvtzz5rb2wkg4FOEk2EI3IBCYwDV4ErQAAwfPcphWYTzSa2t/HPYHHcMoYF
+QVGtZvV6yhhJaTxP+b72POV5yve15ykpjecp39eep4QgWJZlWV+zNDUbG8O1teHjx8OnT4ebm6kx
+hOOoAgvAFaABeEAJp4VSaDbRbGJ7G/8Ii+OWMcz3i3o9q9dTxsjzlO9rz1O+rz1P+b4OgsLzlO9r
+z1NCECzLsqyvGRHy3CSJWVsbfvLJwWeftYdDjeNwgTGgAZwFzgITgINTZ2kJzSbW1vAPsDhuGcN8
+v6jXs3o9dRzjecr3teepICh8X3ueCkPlecrzlJQGlmVZ1pvSbheLi90bN9qbm2m3qwYDRYQjkkAJ
+qAFXgctADafX9jaaTTSbUAoAi+OWMcz3i3o9q9dTxzFBUPi+DoLC81QQFL6vg6Dwfe15CpZlWdab
+ojWtrQ2Xl/urq4Pt7fTFiyzLDI6MAwK4DFwFzgMuIACGU+jfrq//L3fv/mRp6f9R6v8GWBy3jGG+
+X9TrWb2elko6CIogKHxfB0HheSoMVRAUnqeEIFiWZVlvSq+n9vbyFy/yZrN7/35vZyfFMVWAS8Bb
+QB0YAUo4zX7w4sVPV1dnOh0Wxy1jNKmGDwAAIABJREFUmO8X9XpWraZBUIShCoLC81QYqiAogqAI
+gkJKA8uyLOtNIUJRmCwzq6uDTz45vHmz0+spHNM4MAXMAuNAHRjBqTWaJP/D9vZ7Ozuu1iyOW8Yw
+3y/q9axaTaMoD0MVBEUQFEFQhKEKgiIICliWZVlvXFHQ55+3f/7zg4cP+2lqisIYgyNygDpwBpgB
+JoEJwMXpJLWe7XR+9Pz5pVZr6LosjlvGMN8vqtWs0UiiKA+CIgxVEBRBUARBEUW5lAaWZVnWm0WE
+vb38zp3up58ebmwkg4HOMoMjKwEVoAHMALPABMBxOoV5vnBw8P7W1kS/vxcELI5bxjDfL6rVrNFI
+arUsCIogKMJQRVEeBEUQFEIQLMuyrDduczO5e7d340b71au801HDocaRSaAC1IDzwDlgCqfWSFFc
+3t//na2t84eHW5UKi+OWMcz3i2o1Gx9PqtUsivIgKKIoD0MVRbnnKViWZVknYXMzWV0d3L7d3dlJ
+d3fz4VDjyEpABIwBc8AsMIlTy1PqZ83mB0tLb+3v/1/Xr7M4bhnDPE/Vaunk5LBazaIoD4IiivIo
+yoOgkNLAsizrhGhNaWoGA729na6tDR49GgBMCDYc6kZDvvVW8MMfVnyfl0pcCIYjIcKvMIbXtCZ8
+iTHGOU7W48eD+/f7d+92d3fzg4MiSTSOrAREQAM4B8wAUzjNrr98+cHS0s+azZWxMRbHLWOY56la
+LZ2cHI6OplGUR1EeBEUU5VGUw7Is6+QMh/rwUO3spHfv9paWeltbCRFeGxuT169HP/hBNDVVKped
+KHIch+FLxhAAzhl+A0QwhprN3t/+7cGnnx4aAyJwjkrFaTTkhQvBtWvhW28F1aqLk/D06XB5uX/3
+bu/582xvLx8ONY5MAjVgCpgBJoFxQOA0+8na2kfN5odLSyyOW8Ywz1PVajY93RsdTaMoj6K8Uimi
+KPc8BcuyrBOiFO3t5dvb6crK4NGjwfr6cDDQxpAx+BXGwDljDK9xzoigNXGO1xyHSck5R5YZY/Ba
+EIgwdBhDmpo8N0JgbKw0MsKNwf5+fnBQGENKkdbEGITgQrCLF0f+8A9Hf/SjSrnsMIY3b2cnXV4e
+LC52nj9P9/eLXk/hyARQB84As8AkMAb4OJ3GhsMf7ez8dHVVcf7p7CyL45YxzPNUtZrNzPQajSSK
+8ijKoyiPolxKA8uyrBPS66mtrfThw/7y8mBrK9nfzxmD43Ap2TvvRL/7u7XLl4ODgyJNDQAhWBQ5
+/b7e38/S1AjBhGCco9NRh4dFnptSibsuzzJzeFgkiQZQKnGlqNdT/b7WGr7PGWPDoR4OtTFUKvF3
+3im/+2710qUR3xeM4c3b3k7v3u3dutV59izpdlWaGhzHGDALLAANoAKUcGr92crKB0tLHy4t/ddr
+11gct4xhnqeq1WxmptdoJLVaFkV5FOVRlAtBsCzLOiG9njo8VAcHxYMHvcePB4OBrlbdMBTVqnv1
+anjxYlCtOviOIoIx1OmoW7c6n3/eXlrq5TlpTUQ4Op/wFsNVYAqQgAMwnFo/WVv7YGnpw6UlFsct
+Y5jnqWo1m5vrNhpJrZZFUR5FeRTlsCzLsk4CEYwhY2hxsfOLX7Rv3uwoZZQiIhwRB1zgHHAZuASE
+AMPpJLW+cHDwe8+exbu7G9Uqi+OWMczzVL2eTk/3p6YGtVoWRXmtlnmegmVZlnVClKJuV62vJzdu
+tO/e7b58mRmDo5NAAETAZWAemMBpVk3TD5eWPlhaemt/n8VxyxgmpR4dTefmulNTg2o1rVSKajWV
+0sCyLOuEEOHgoHjyZPjoUV9rvBYEIoqcsTFZLjuex2s1NwwFfnvGUFFQlhkiGEO9nsoyUyrxWs0V
+gmlNQeBwjhOXJPrly3xjI7l/v/fo0WBnJ1WKcGQMGAXOAvPAJFABSji16kny3s7OD58/B2MsjlvG
+QErTaCRzc92pqX4U5bVaVqtlQhAsy7JOAhGSRC8udj/77HBpqZ9lOs9Ja8KXOGdSMsZQqTjvvVeN
+4/L5876U3PeF53H8BohgDG1tpZ98cvjFF53NzYQIROR54uzZ0uysf/FicOHCyNmzXhgKnJzNzfTB
+g96tW93nz9ODg2Iw0DgyBpSAC8BV4BzgAg7AcWr91a1bF1qtZ9Uqi+OWMZDSNBrJ7Gx3erpfq2W1
+WlarZbAsyzoJxsAYKgq6caP9+eft27c7WgMggEnJ6nV57pyf5+bwsNjeTrUmrckYKpcdKbnjsOvX
+ox/8IHr77TLnjHNIyfHPMIa2ttLl5cGdO93t7XRvL09TXSrxctkZHy99//vRD34QXbw4gqNijI2M
+jHieVyqVHMdRShljOOeO4wAoisIYwzkXQnDOi6LI89xxHCEE55yIsizTGs+e5c+eZTs76fb2oNfL
+R0bcKCopZTqdLMtUqSSCQEopOp10e7s3NuYHgXRdrpTZ3R1sbLSLQqepShIFAUigAVwCFoAzAMfp
+VE3Tn66u/uWdO2/t7//Xa9dYHLeMgZSm0UjOn+9MT/drtaxWy6Ioh2VZ1kkwhoqChkO9vNz/7LP2
+rVudNDUAGMPMjH/lSvDDH1ZmZrxKxS2V+PZ2urra39hIOx21t5e9eJH1+4oIxqBU4lLyUonPzHgX
+L45cuhSGoTCGpORElOeUJHp9PVlZ6W9vp+12kaYGYCMj/Nw5/513yu+8E01MlMplx3UZfntCCN/3
+y+VyrVarVCrlcpmIiqJgjLmuyxjTWiulADiOI6VUShVFQUScc9d1GeNpmua5JuJC8NcODtJuN/M8
+Z2xsRAjeag2zTGlNlYo3Ph68ejXodjPOmePwSqWklPmbv1n/5JPNL754vrHR7vWyojAYA6aBy0AD
+CAEPp9lcu/2fl5auvnrF4rhlDKQ0jUZy4UJ7erpfq2VjY6nnKViWZZ0EImSZ6XbV+vpwcbHz4EF/
+dzcnAkDVqvvee5Xvfz+6eDEIAiElZwy/QoTXGEOS6IcPB1tbyatXeb+vd3bS7e3UGNKalCLOGWP4
+e0KwUom7LnNdPjVVungxmJvzz53zx8Zc3xc4UUrR8+fp6urg7t3es2fJ/n7e72scDQM4IIBzwPeA
+80AIcIDhdKqm6b9dX/8v9+5Nd7ssjlvGQEpz5sxwbq57/ny3VstGRxMpDSzLsk6UMTQYaCG467KD
+g0Ipcl02OuoKwfBbMoaIIAQjgtaELzkOwzcYEQH47LP2F190Fhc7w6HJc4MjE0AZmATOATPAKODh
+dGJEs53O72xt/dGTJ51SicVxyxi4rpmYGM7Pd86d642NpaOjiRAEy7Is6+QUBR0cFE+eDO/e7S4v
+97e306IgHA0DOOACc8BbwCVAAgJgOJ1crX/44sUfrq+nQrA4bhkD1zUTE8P5+c78fHd0NBkbS2FZ
+lvXtQYRfYQyvZZlhjAHgHETIMs0YGxnhAIqCOGcAGAPnDH+HMXzTaE37+/n9+72bNzv37vXy3GhN
+xuCIXKAGTAJzwBRQAyROs/d2dn66ulrOMhbHLWPgumZiYriw0FlYaI+NpbVaBsuyrG+YNDWbm8nm
+Zrqzk756lff7Ost0ltFgoA4PFRFpTcYQYwx/hwjGEGMQggEwhgAwxgBwDoAB8H0uJTMGtZp76VIw
+N+ePjclKxWk0ZL3u4oQQIUl0q5Xv7GR37nSXlnrb25kxhOPwgFngAnABqOM0C/L8dzc3P7p79wcv
+XrA4bhkD1zUTE8OFhc6lS4djY2kU5bAsyzppxpBStLmZ3rvXW17ub2wkBwcFEQFgjHGO6WlvdtZr
+NErVquN5AoDnsdFR2WhIrakoiAiex2s1N89Nv68ZQ7nsDIc6ywxj6HZVr6c6HXVwUGxvp48fD169
+yolAhCAQCwsjV66E77xTbjRkuey4LsMb12rlDx70Fxe7jx4N2u0iSYwxhKNhQA2YAS4DDSAEPIDh
+dPKVurq39yerq+/t7LA4bhkD1zWTk8P5+c6lS4djY2kU5bAsyzpRxsAYWlkZ/OIXh81m5+CgMAZE
+CEMxNzdy/Xr53XcrExMlIRhjOI5ORz1/nj55Mlxa6j96NGi3CyIwBiHYD35QuX49iuNwfFxKyfEG
+ESFNTbernj9PP/20vbzcf/48LQrC0TDABUaACnAFmAPGAY5T6988e/aXd+782cpKc2KCxXHLGAhB
+Z88OLlxoX758ODaWBkEBy7Ksb4aVlf6dO91bt7qtVpEkOk0NEYRgQiAIxMREKYocIvi+CEPh+0Jr
+Gg71cKgZY77P89y020W3q8LQ4Rz9vtrby/t9LQTjnClFeW44Z0KAMcY5zp71pqe9+fmRa9fK09Ml
+1+VCMMZwIgYDfetWZ3Gxe/9+r90ulCIchwtcAC4AC0AZEDidHGMWDg//4+rq/3nzZnNigsVxyxgI
+QTMz/fn5ztWrB2NjqecpWJZlffPs7ua7u1mamsFAv3iRbW+ne3t5URDnGAy0UqQ1uS5zHEaEJNGO
+w8LQYQzttvJ9Pj4ux8ak53GtwTnGx+XUlHf+vF8qcWPAGHyfS8nxzaAUtdvF2trwzp3uw4f9ly+z
+NDU4Mg6UgQngIjADVIASwHA6CWO+t7f3F8vLY8Mhi+OWMRCCZmb68/Odq1cPxseHUhpYlmVZJ4oI
+nY568KB35053aam/s5PiOBwgAs4AC8AsUANcnE6eUu/t7HywtPR/fPHF//vWWyyOW8ZACDp7dnDh
+Qvvq1YPJyYEQBMuyLOuk7e5mDx/2Fxc7d+70kkRrTUQ4IgeQwDRwCZgHKgAHGE6noCjeff78Py0t
+jQ8GLI5bxoBzzM72FhY61661JicHsCzLsk6a1rS/Xzx+PLhzp/vwYf/wsBgMNI6MASFwFrgAzAEh
+UAIYTqf41as/X17+yzt3UsdhcdwyBpxjdra3sNC5cuVgeroPy7Is6xvg4KB4/HjQbPZu3+4+f57i
+OAQQARPAeWAGqAMlnFquMRdbrf+wtva/Ly6yOG4ZA84xO9tbWOhcuXIwPd2HZVmW9Q3QahUPH/Zv
+3Gh/9tlhURARjs4FRoAGcBGYBUYBidPs/a2tv1herqQpi+OWMRCCZmb6Cwuda9dak5MDWJZlWSfN
+GNrdzVdXB1980W42u0litCZjcBQMEIALjANXgHPAGODiNPuPjx69+/z5bhCwOG4ZAyHo7NnBxYvt
+K1cOpqf7sCzLsk6aUtTvq9XVwa1bnXv3egcHRZoaIhwFAxjAgbPAZeA8MA4InHIXDg7+fGWFxXHL
+GHCO2dnewkLn2rXW5OQAlmVZ1okiQlGYPDcPH/Zv3Og8fNjf3c2KgnA0DGAAB2aBt4BZ4AzAcMr9
+3rNnf7S2xuK4ZQyEoJmZ/vx8J45bk5MDWJZlWSeKCEpRUdDDh/0bN9rLy/2trdQYwtEwgAEMmAPe
+AmaBMzjlJvv9P1hf/1/v3GFx3DIGQtD0dH9hoXP16sH0dB+WZVnWiSKC1qQUra0NP/nk4MGD/s5O
+WhSEI2MAA+aAS8AccAZgOOXe39r640ePWBy3jIEQND3dX1joxHFrcnIAy7Is66QVBXW7xaNHw88/
+b6+uDvb38zw3RDgKBnCAA2eBy8A54AwgcMotHB7+xfIyi+OWMeAcMzO9hYXO1asH09N9WJZlWSfN
+GHr1Kn/4cLC42L53rzccaqWICEfBAAeQwBhwFTgHjAIuTrOJfv/PVlb+/doai+OWMeAcMzO9hYXO
+tWutqakBLMuyrG+Avb18ebl/5073s8/aSWLol3BELjACjAILwDwwCkicZn+wsfE/PXxYSVMWxy1j
+IARNT/cXFjrXrrWmpgawLMuyvgEOD4vV1cGdO91793rb2ymOQwAhcAY4D5wD6oCHU8sx5mKr9R/W
+1n7WbLI4bhkDIWhqanDhQvvq1cOpqb4QBMuyLOtEKUX7+/njx8PFxc7qar/VKtLU4MgYUAZmgcvA
+NDACSIDhNJvudn+6usriuGUMhKDp6f78fOfatYNGI5FSw7IsyzppL15kjx4Nbt7s3LnTTRKtNRHh
+iBzAA6aAt4DzQARwgOF0CvP87d3d/3z//kS/z+K4ZQyEoOnp/vx898qVg0Yj8X0Fy7KsbxKliDEI
+wYhABMbAGL7z+n398GH/9u3OvXu9ra0UxyGAABgDLgKzwDjg4pQ7Mxj8zw8fsjhuGQPHocnJwYUL
+nUuXDicmhr6vYFmW9Q1AhKIwq6uDL77ofPppu99XWpPWVK26ly8Hb79dvnIlnJwsOQ4TguG3Zwxp
+jTw3m5tpmuogEETo97WUbHRUTk2VcHLy3BwcFE+fDhcXO6urg93dPMsMjowDEXAWuADMABHgAgyn
+1tu7u//j48eTvR6L45YxcF2anBzMzXUvXTqcmBiGYQHLsqxvAK3p8ePBrVvdxcVOq1UkiS4KYgyj
+o/LixZGrV8MocoggJYsip1p1SyU+GGhjqFx2oshJEq01HIcFgeAcr2WZcRzuuswYIgJjGA7Nykr/
+3r3evXvd7e1UKbxWrTrj46VLl4I4Lp8/74+OukIwvHGdjmo2u7dvd5vNbrerlCIchwdcAC4A54EA
+cHDKeUr9+coKi+OWMXBdOnNmcOFC58KFdqORVCo5LMuyvgG2t9OHD/u3b3c3N5N2Ww0G2hjCl4Rg
+nDPG8BpjMIa0JsYYAPolcM4A0C/hNc4ZYyCC1sQ5YwyM4TUhGBG0JgDGEBE4B+esVGL/6l/V3n23
+cu1aOQiE4zC8QURIU9Pvqxcvshs32ktL/e3tNM8NjoYBDuABVeAKcB4YBwROufd2dv7oyRMWxy1j
+4Lp05sxgfr67sNBpNJJ6PYVlWdZJa7eLjY3kwYP+8nJ/ZydrtwsiRJEzOVl6660gjsuzs/74uMSX
+iFAUBoDjMM5ZkmgiCMEYw2uDgVaKXJeVy06vp3o9DYBzOA7vdlWvp4gQRYIIBwfFYKC1ppERce6c
+f/Zsif0STsSrV9nSUv+LLzpPngw7HZWm2hgcEQOqwBRwEZgAIsADOE4nT6kre3t/8ujR27u7LI5b
+xsB1aXx8OD/fOX++22gkjUYCy7Ksb4BORx0eFkpRqcRHRsTBQaEU+T4XgkWRE0UOY/hOIkKa6oOD
+YmsrvXOn++BBf2srNYZwHB5wHrgALABVnGYjRfH+1tZ/uXfvT1dWWBy3iOC6ptFI5uc758936/W0
+0UiEIFiWZVknR2va3c0fPOjduNG5d6+nlFGKiHBELhABZ4DzwDRQB0o4zf7Ns2d/vrz8ZysrLI5b
+RHBd02gk5851z5/vNhpJvZ5JqWFZlmWdHKWo1So2N5Nbt7oPHvR2drKiMDgaBnBAAHPAFeAiUAIE
+wHFqeUr92crKn66ssDhuEcF1zehourDQmZnpj40l9Xrq+wqWZVknxxhkmfnss8PPP2+vrvbLZccY
+tNvFyIiYnvbOnCldu1a+cGFkfFwKwfAlIhhDRNjfzw8PCyIQ4eCgyHPj+3xkRFQqTrer0tRwzmo1
+VwiWJLooiHNWLotKxW218jw3rsvHx2Wl4uBEEaEo6ObN9ueft5vNbpKYPDc4MgeoApPAHHAWqAEl
+nE6caKrX+4P19T9cX98bGWFx3CKC65pGI5md7c3M9MfGkno9DcMClmVZJ0FrGg71/n6xujq4e7e7
+tjY8OMiJ8NroqPvjH1fffbd6+XLgukwIhv8eEYrC7O7mDx/279zpbmwknY5KUw2AMcY5OGf4kuOw
+NNWMMWPIGBARACEYY1hYGLl+Pfr93x+NIuF5wnEYY3jzlKLNzWR1dXj3bndrK93fz4dDjaNhAAcE
+MAdcBc4DIcABhtNpNEl+Z3PzrxYXr+7tsThuEcF1Tb2ezs11Z2f7tVpar6eVSg7LsqyTkOem3VYv
+XmT37/cePOivrw+zzABgDPPzI++/X/3hDyujo67nCcdh+EeUon5ft1r5ysrg7t3u6uqg11MAGGNz
+c/73vx/96EeVs2dLnicch21sJDdvthcXOzs72XCojUEYivn5kWvXwrffjsbHZRQ5rsvw2xNC+L4f
+hmHtS0EQMMaUUowxx3EYY/pLADjnUkr1JQCMMcdxOOdpmhWFARj/0v5+kiRKSjE66gvB9veTPNdE
+FEWlRiN49WowGORCcMfhUSSTRP3N36x/9tn2rVvPnz49bLfTQhmMAjPABeAMUAZKOM3mDw//04MH
+HywtsThuEaFU0tVqNjfXPXt2UKul9XpWr6ewLMs6CUQgQlGYJ0+Gi4udpaX+wUHe7ao0NZyzMBRj
+Y7JedxsN2WhIAKUSL5cdAJ2OOjgo+n21tZU+fjwwBvRLcF3mOGxkRLz/fu299yrXr0f4kta0sjJY
+WurfutXZ3c26XWUMKhVnYqJ06dLI229HCwv+6KjEMfi+73melNJxHK21MUYI4TgOgKIojDGccyEE
+51wplWWZ67pCCMYYEWVZliRqa0utr6ebm8Pnz4e9Xu55brksiXB4mAyHRRjKMJSuK7JM7ez06nWv
+XC65rsgytb8/XF9v57nOMpUkCgIoAQ3gCjAPNACG00xq/XsbGz/e2WFx3CJCqaSjKJ+b601N9Wu1
+rF5P6/VUCIJlWdbJIUKem+FQHx4Wz59n29vJ/n7RauWdjhoOTa+n0tTQL0EIJgQrCpKS+b4QgoWh
+mJ72JidLlYozPi7n5kbGxyX+kSQxOzvp7m4GwPeF73Nj4DhMSu55vFZzPY/j5GxsJMvL/du3u9vb
+aatVJInG0TCAASPAeeB7wCzgAg7AcDp5Sn24tPSnKys/WVtjcdwiQqmkq9Xs3Lne+HhSq6X1elqv
+Z1JqWJZlfYMZA4DYL+HvEYExfAcMh3p3N9/YSO7f7z1+PNjeTpUiHJkAxoApYA6YBKqAxCn3+xsb
+HywtsThuEaFU0uVyfu5cb3JyGEVZvZ5VKlkYFrAsy7JOiFLU7+snT4Y3brTv3u2+fJkZg6MrASNA
+BFwCFoAJnGbCmAuHh//uyZN/v7bG4rhFhFJJl8v5zEx/YmJYqeS1WlqpZJVKDsuyrG8eIhAR50wp
+ynOjNaWpMQYjI6LVyl+9yrPMSMk4Z4zh4KAYDrWUPAhEEAgASaKVgpRsdFSOjbljY5IIf48xfBMQ
+wRhSim7f7v785weLi52iIK2JCEfEAAmcAy4Dl4AA4Djlfry9/cHSEovjFhFKJR1F+cxMf2wsqVTy
+KMrq9axSyYQgWJZlnShj0OkUw6Hu9/Xycv/Bg/7GRpLnJkl0nhsARPgVY8A5OGcAXJdzDqXIGABE
+BN8XnKMoTFEQACK8Zgzol8AYhGBS8pERMTFReued8uXLwcREqVJxfF8whjeMCMZQq1Xcvt399NPD
+lZV+UZDWRISjC4ELwBVgCigBLsBwal1qtf5kdfV/u32bxXGLCKWSrlTyycnB2FhSqeRRlFcqWb2e
+SalhWZZ1Qrpdtbub7+ykjx4N1taG6+sJETHGXJddvDgyPz9Sq7n1ujsxURobk47DSiXOGIwhx2Gc
+M3yJCK8xhn+ICIzhV5Sidrt4+nS4sjK4f7+3tZWmqWEMIyPie98r//jHlTguR5HjupxzvGHPn6f3
+7vVu3uxsb6ftdpEkBscxBpwDFoAGEAElnHKeUh8uLbE4bhHB81QUFWfODEdH00oli6K8UskrlSwM
+C1iWZZ2QJNFPngzv3u01m92XL7PhUHPOymWnVnMvXRp5993q22+XHYcxht+EMSAiAMbAcRiA7e30
+8LBIU/3sWbq01FtdHWhNRUEAXJeVSvzy5eD992s/+lElihychM3NZGVlcOdOd2cn3dvL+32NI+PA
+KDAOTANngTNACafcz5rND5aWWBy3iOD7qlwuzpwZjo6mYVhEUVap5JVKFoaFEATLsqwTohTlOQ2H
++v793r17vfX1pN0uej1VFIYInEMI9prWxBiEYEKwUolzzrLMADCGlCIicA6tiTEQ4TUiGEOcM8bw
+2siI4JwZQ3FcXlgYGR+Xo6Pu1JRXr7s4Uevrw5WVQbPZ295O9veL4VDjyCRQBcaAWWAWOAMInGbx
+q1d//OjRXy0usjhuEcH3VblcNBpJvZ6GYVGp5FGUhWFRqeRSaliWZX1jGENaQyliDFrTwUH+8mW+
+t5cPBqooyHG453Ep2WtJoonwWhQ5jYZ0XaY1cc58n4+MiHLZcV2uNTkOcxyGb6T19eHDh/2lpf72
+dvrqVT4cahyZBKpADVgAZoBJnGajw+G/2dz86cpKmOcsjltE8H1VLueNRlqpZGFYVCp5EBSVShaG
+RRgWsCzLsk7C1lb64EF/aan37Fmyt5cPBhpHJoERoAYsAAvAJKy5dvvDpSUWxy0i+L6qVPJqNatU
+8jDMK5U8CIowLCqVLAwLIQiWZVnWG/f8eXr/fu/evd7mZtpqFb2ewpFJIACqwAIwD0zB+sna2kfN
+JovjFhF8X1UqebmcVyp5GBaVShYERRgWYViEYeH7CpZlWdabRYRWK//ii84XX3Q2NpJuV+W5IcIR
+SaAK1IE5YAY4i1POU+pnzeZHzSaL4xYRfF9VKnmlko+MFGFYhGERhkUQFGFYhGEehoUQBMuyLOvN
+Kgr6+c8PPv+8/eBBP8tMURhjcEQOUAfOAGeBaeAM4OI0m2u3f9ZsfrC0xOK4RQTfV5VKXqlkIyPK
+91UYFmFYBEERhoXvqzAsfF/BsizLelOIoBTluXn0aPDJJ4e/+MXhcKiJcCxjwARwFpgCGsAITrO3
+9vc/ajY/XFpicdwiwshIEUVFpZKVStr3dRjmYVj4vg6CPAwL31dhWAhBsCzLst6U4VB3Omp3N795
+s33vXu/ZswTHVAXmgfPAOFAGRnCavbW//+HS0kfNJovjFhFGRopKJY+i3HHI91UYFr6vwrDwPBWG
+he+rMCx8X8GyLMt6U4qCtreTJ0+Gq6uDp0+TZ8+SLDM4MgZw4CLwPWAekIADMJxaE/3+h0tLHzWb
+LI5bRAiColLJoygH4PsqDAvfV76vgqDwfeX72vdVGBZSaliWZVlvyv5+fv9+/8aN9uZm0m6rXk/h
+yBygBIwBl4ArQB3Wh0tLHzWWzQbjAAAgAElEQVSbLI5bRAiColLJK5WMiEmpw7DwfeX72veV5ynf
+V76vfF/5vpZSw7Isy/qaEUFrynPz9Gny858ffPLJYb+v6ZdwRA5QA0aBs8A5YApwcMr9eHv7o2aT
+xXGLCEFQVCp5pZIBjHPyfeX7yveV7yvf156nfF/5vvJ95ftKCIJlWZb1NUtT8+JFurmZPno0WF0d
+rK0NtSYcRwTMAxeBBhACIzjlPKU+XFpicdwiQhAUlUperWZEjAi+r3xf+b6S0vi+8jzl+8r3tZTa
+95XvKyEIlmVZ1tes11NffNH5/PP2xkbS7arhUBPhiBzAASaA7wHfA3yA4dTiRLOdzvdfvHhnd5fF
+cYsIQVBUKnm1mhGBiEmpfV9LqX1fSWl8X3meklL7vpZS+77yfSUEwbIsy/rapKnp99XeXv755+0b
+Nzo7OymOgwGjwCgwCcwCZ4ESTrO5dvtnzeZHzSaL4xYRgqCoVrNKJScCwDgnKbXvKymN7ysptZTG
+85SU2ve1lNr3lZRGSg3Lsizra/PiRXb/fu/u3d7z5+neXt7pKBzTFeB7wCxQAlyA4zS7/vLlR80m
+i+MWEYKgqFazSiUHQAQiJqWW0kipfV9JaaTUUhrPU1JqKY2U2veVlEZKLQTBsizL+qolie739e5u
+9tln7Rs32ru7OY7DBWpADZgB5oBpnGau1n/8+PGHS0ujwyGL4xYRgqCoVrNqNScCEQBGBN9XUhop
+tZRaSiOlltK4rpbSSKmlNL6vpNRSGik1LMuyrK/aq1f5/fu9u3d7Ozvpq1d5u13gmC4DbwFzgAeU
+AI7T7GfN5kfNJovjFhGCoKjX0yjKiRgAIhAxIUhKLaWRUkuppTRCkJRaSuO6WkotpZFSS2mk1FIa
+KTUsy7Ksr8hwqNttdXhYLC52bt3qrq8PcRwOUAPqwBRwDpgFOKyfrK2xOG4RIQiKej2NohxgRCAC
+wIggBEmppTRCGCmNlFpKI4SR0riultIIYaQ0UmopjRBGSiOlFoJgWZb1FWFaO2nKs8xJEidNRZoa
+1zWOo31f+b7yPHIcEoIYw3fRxx8ffPLJ4erqIE1NlmljcEQMYMAs8DYQAxzgAMOp5Sn1s2bzo2aT
+xXGLCEFQ1OtpFOUAI8JrRAAYEYQgKbUQJKUWgqTUQpCURkotBLmuFoKk1EKQlEZKLQRJqYUgKbUQ
+BMuyrGPgSo28fBm8eFHe2KitrtYfPGBaAyiC4ODatYNr17rnzqVjY8nYGI5EZJnb68ler7a6Wn/w
+IHjxgjgnxrLR0d7MTO/cucHkZNJoFGGIk7C+PnzyZPj06fDp02RjIxkMNI6jDswAM0ADGAMCWD/e
+3mZx3CJCuZxXq1mlkhMBYER4jQgAI8JrUmohSEojhBGCpNRCkJRGCCMESWk4N1IaIYwQJKURwkhp
+hDBCkJRGCCMEwbIs67fk7++PvHgR7vx/7MHpb13XmSfq37vWXnvvc/aZeShSpMRJoyXvxHaGLlS6
+UClcFJAG6gLVBTSQ+6WdLxf9N/aUBGU7lq2BRxJtURIlUhwkiuQhz3z2sNZ6r0q+KaRSSXVClUUl
+XM+z0/j669rqanB0RMzErINAF4u6UNBRpMNQF4vW89jzdKFgPc+EofU863kmDK3nmTC0SlnPM2Fo
+Pc8qxUQgYimZiIWobGxMffHFZKsl01RmGay1nmeV2vv+95//1V/tff/7IGIh8HYliR2NTLudf/75
+0SefHO3upngTPlAEisBF4DJwDs6PNzY+brUojtvMKJezWi2tVjNmvEbMeIUZrxEzpGQprZTs+1ZK
+KyVLyVJa37dSspRWSvZ9K4SVkqVkKa3vWylZSisl+76RkqVkKdnzrBAMx3Gcf5M3GpV2doq7u7XH
+j2sPH1bW1wEQs1XKKMVSgpmlBBGYyVowEwBmshbMYCYAzGQtmAkAM1kLZgDEDGayFswAiBnMeM16
+HnveYGbm4MMP9z/8cHzmTFap5FGEk3DjRueTTw6Xl/tZZvPcWos3sgR8B7gOCEAAhFPrL7a3P261
+ftZqURy3mVEuZ7VaWq1mAJjxGjHjG8x4jZghJUtppWQpWUqW0krJUrKUVkqWkqVkKa2ULCVLyUJY
+KVlKltL6vpWSPc+GofF9o5QVgoVgOI7j/C7R7m7xxYvy5mZ9dbWxsuKNRiCynteO44MPPugvLIyb
+zXGzyVLiz9Tz5+n9+/179/q7u+nubtrrabyJCrAEXAAmgApQgvOTtTWK4zYzyuWsVkur1QyvMeM1
+AsCMbzDjNWLGN6RkKa2ULCVLyVJaAFKylCyllZKlZClZSgtASpaSpWQpbbmclct5GGqlrOdZIjiO
+4zi/xVre2ko2NsZPn44ePRo+ejTKMos3cQY4A0wDM8BZoIBT7urBwcetFsVxG0CplNVqabWa4Tcw
+49eIGf+MGb9GAJjxipQMQEorJQOQkqVkAFJaKVlKBiCllZKF4EYjqdfTKMoLBR0EhgiO4zjObxkO
+zeFh3m5n9+71b97sbmyM8SZ8oAJUgAVgCTgH52et1setFsVxG0CplNXrabWaAmAm/EvM+DUCwIzf
+wozfQACY8Q0pGYCUFoCUDMD3zeRkMjk5qtXSKNLFYk4Ex3Ec57eMRmY4NC9fpp9+enTjRqfdzvEm
+fKAIVIArwBWgiVPu6sHBx63Wz1otiuM2gFIpq9fTajXFrzETfg9m/CuE15jxOzHjn3keT02NpqeH
+9XpaLuelUkYEx3Gc34E56HQK+/uFvb3m/fv1Bw+i58/BTNYSM5iJGa8wg4iJQMRCgGg0Obn/0UcH
+3/mOKRREnqvhsLq2Vn/0yO92yVowMxFZC8D6vpVSFwpZrZaVy50rVw6vXx83myyl9TycHGYYw1rz
+06ej//W/2r/85WGeW7wJCUhgEoiBD4EAp9yPNzb+261bf7+6SnHcBlAqZfV6WqulzPi3MRP+eMz4
+Z57H09PDM2fGtVpaLuflcgbHcZx/yRuPy5ub0fZ29enT+oMH5WfPiBnMeamUTE6OJycH58/3z58f
+T05apaznqeEwbLeDw8Pq06fljY3w6Ii0FlqDmZhZCF0s6kIhq1TGk5PjyUkmApEaDIovXxb299Vw
+6I3HIstYCBaie+nSyx/8YO+HP8yjKC+VjO/j5KysDH7xi/bPf962FvxP8EZmge8C3wMIIIBwav10
+ZeXjVuuD3V2K4zaAUimr19NaLcW3T0qemhpNTo5rtbRczsvlDI7jOP9SeHjYWFmZWFkpb24Wd3fD
+dpuFYKLO5cs7f/M3W3/7tywEiJgIv0FmWXVtrbq2Vl1bK29ulp89A8CeN56Y2P/oo/2PPhrOzmbl
+cl4q4TWRZWo4VIPB5PLymVu36qurxAzm0fR059KlztWrg9nZwblzaa2GP57I8+qTJ+X19er6evXJ
+k9qjR3iLDlC8jZkWpluYvoWZNTTwjQXgA+ADOO/v7X3/+fOFTofiuA2gVMrq9bRWS/F7EDH+SET4
+naS0Z86MJyeTajUtl/NyOYPjOM6/JPI8PDwMOp3aw4dTX35Zf/CAmMlaq1ReKOhiMS+V8lLJFApg
+ZilFnss0lUkSdDpBpyOyDEQMgAivEDERiEwQ6GLRKgUiAKS1Nx7LJBF5LowBM3ueVerwvfde/Mf/
++OJHP7JSspQsBE4CM5ixstL/3/+7/fOft/GGCCDgHPBd4Htwfrqy8nGr9cHuLsVxG+BSKa/X01ot
+xWtEjN+FCL8PEeP3IMJv8jw7MZFMTo6r1axczkuljAiO4zi/k9BapKkwpvL0aeXZs9L2dmlrq/zs
+mdAaREyEbzCTtWRtb2FhODMzmJs7vHq1t7Skw5AAkefRzk704kX04kVhf98/OpJ5DiIAebGYlcuj
+qanh7OxwdjaPorxUskrhHWAtjOH19fF//+/7v/jFYZ5bvAkBCKAJfBf4EAhxyv14Y+O/3br196ur
+FMdtgEulvNFIqtWMiPEbiPBbiBj/EhF+AwMgwjekZABCMAApGYCULISdmEhrtbRazYpFXSzmRHAc
+x3F+y2hkRiOzt5f94z8e3rjRabdzvAkfKAAV4ApwFWjilLt6cPBxq/WzVoviuA1wuZzX60mtluLX
+iPDPiBi/gQivMQAifENKFoIBSMlSshAMQEorBAOQkqVkAEKwUrZSyUqlPIp0GOogMERwHMdxfstg
+YA4Osv397P79/p07vWfPxngTPlADqsACsADMwvlZq/Vxq0Vx3Aa4XM7r9aRWSwEQ4Z8RMV4jwq8x
+EV6RkoVgKVlKBiAES2mFYClZShaCpWQAUrIQLCULwVKylFZKDkMTRXkQGKWs51kiOI7j/IGE1jJJ
+vPE4ODoK222/1ws6naDTUf2+Gg7VcCjyXGQZAJHnMs9Fnossk1kGIgas75swNEGQ1mppvZ7Wakm9
+ntVqSb2uoyiPorxUyioVEwQ4acbw5mayvj56+nS8tjZ8/HiUZRZvYgqYAqaBs8BZIMQpd/Xg4ONW
+i+K4DXC5nNfrSa2WEuEbRIzXiPAaE+EVKVkIlpKlZCFYSisES8lSslJWShaCpWQhWEqW0grBUrKU
+LARLyUKwlBwExveN57EQLATDcRzn9/PG49LmZvXJk/KzZ6WtrejFCy9JZJqSMSACEQvBQjARWctC
+WKWsUtb3TRCYIDBKsedZz7NKWc+zngciACLLZJap4VD1+36vpwYDAsBsldJBoAuFve9/f++HP+wu
+LZkgMEEAIrx1z5+nKyv9+/f7L16ku7tpt6vxJirAIrAETABVoAznJ2trFMdtgMvlvF5ParWUCK8Q
+MV4jAsBEeEVKVspKyUKwlFYpKyULwVKylKyUFYKlZCmtUlZKFoKlZCHY960QLKWVkpWyQrCUDMdx
+nP8TNRhU1tcrGxvVtbXqkyfR9jaIIET/3Ln9733v5Q9+kExMZJWKCUO8ATLGSxKZps1796Zu3Dhz
++zYxgzmt1zuXLnUuXeotLAzOnx9PTuIkfP5555e/PFxe7mlttWZmHBMBBFwAvgNcBwggnGZ/sb39
+cav1s1aL4rgNcLmc1+tJvZ4CIGK8RgSAiSAlC8G+b4VgpYyULCUrZaVkpawQLCUrZaRkpayULAT7
+vhWCfd8IwVKyUhaO4zh/vPKzZ7XHj6tPnpQ3NspbW2owYCFYiKOrV3sXLgxmZ7NqNY8iXSxaz9Nh
+yJ5nPc96HgvBUrIQEIKJhDFkjNBaZJk3Hhdevgw6nfDwMNrZKezthYeHfq+nBgMABOggSCYnx81m
++/33D69f7168yEKwEHi7hkPT6+n9/ezLL7uff360t5fhTYRAGagAi8ASMAPnxxsbH7daFMdtgKMo
+n5hI6vUUABEDIALARFDKSslKWSmtUlZKVsoqZaVkpayUVikrJStllbJSslJGSlbKCsFSMhzHcf49
+FA4Oao8eVZ88Kezvh+12eHAg09QbDmWeM/5/BIAZADHjFWb8FiImYiFYCOv7xvd1FKX1elqrjc6c
+GZ85Mzx7dtxs5pWKLhatlCDCiVpfHz99OnryZLS+PlpfHw+HBm+iAZwHzgOTQBOI4PzF9jbFcRvg
+UimfmEhqtZSIARABYCIoZaVkpaxSxvetEOz7VimrlJXSKmWVskpZKVkp6/tGKSsES8lwHMf5lpG1
+ZAxZS8YIY5jIKmWCAH9efvGLw08+OVxdHWaZzTLLjGMiQADzwHeAGCCAAMKpFWr9s1br41aL4rgN
+cKmUT0wktVpKxEQAmAhKWSlZKauU8X2rlFXKKmV93yhllbJKWd+3ShkpWSmrlIXjOI7z72QwMAcH
+2cFBtrzcu3u3/+zZGG9CAU1gEjgLnANmAQHnJ2trFMdtgEulvNFIGo0EABGIWEpWyipllTK+b5Wy
+YWiUskoZ37dKWaWsUtb3jVJWKQvHcRzn39vLl9ndu73l5d6LF+nBQdbtaryhq8A1YB4IgAAgnGY/
+a7U+brUojtsAl0p5o5E0GgkRACaCUjYMjVLG961SNgyNUlYpE4ZGKev7VikThkYpC8dxHOdbMBqZ
+wcC8eJHeuNH58svO3l6GN6GABtAAzgPzwCycVz7Y3aU4bgNcKuWNRtJoJEQgYik5DI1SJgyNUjYM
+jVJWKROGRikbhsb3TRAYKRmO4zjOt2ZnJ2m1+nfudF++zNrtbDAweBMEXAeuA/OAAjyAcJp9sLv7
+catFcdwGuFTKG42k0UiIQMRhaJSyYaiVsmFowtAoZcLQKGXD0IShVspKyXAcx3G+NYOB6Xb17m56
+82b3zp3uixcp3oQAJoFp4CwwA0wDPk6zhU7nZ63Wx60WxXEb4FIpbzSSRiMhYs/jMDRBoH3fhqEJ
+AhOG2vdtEJgwNGGow9DAcRzH+ZYxo9/XN292b9zorK+P+n0zHhtmHJMHKGAauA5cB0KA4Fw9OKA4
+bgNcKuWNRjIxkRCxUjYMTRjqMDRhaMJQh6EJAhOGJgy1UlZKhuM4jvMtG4/Nzk66vj56/Hi0tjZ8
++nRsDONNVICLwBWgCURAiFMu1PqnKysUx22AS6W80UgmJhIiDkMThjoMTRiaIDBRlIehCUMThjoI
+jJQMx3Ec51vGjCyzSWKfPBl9+unRr351NBoZZhyfAiaAM8AscA6YAjyccn+xvf1xq0Vx3Aa4VMob
+jaReT3zfhqEJAh1FOgxNGOowNMWiDkMdhkYpC8dxHOdtOTjI7t7tf/llZ3Mz6XTywcDg2BTgA03g
+CvAeUIfzDw8e/L+3b1MctwEulfJ6PZmYSILAhKEJQx1FOghMFOVhaIpFHYY6DA0cx3GctyXPeXNz
+vLY2evRo+PTpaGsrSVOLYyNAAFeAa8ASQxE8gHBqTQ0G/8/KysetFsVxG+BSKa/Xk4mJJAhMFOXF
+og5DE0V5sajD0ERRHgRGSobjOI7ztgyH5vAwf/EiuXWrt7LS39pK8IZqwEXgAtAEykCI00xZOzUY
+fLi7S3HcBjiK8kYjmZhIikVdLOZRpItFHYY6inSxqKMoV8rCcRzHeVuYoTUniX38ePjJJ0effXaY
+JJYZb+QMMAucA6aACaCA06yg9eV2+y+3tiiO2wBHUd5oJM1mUirlxWIeRbpY1FGUF4s6ivJiUcNx
+HMd56/KcP/nk8MaNzldfDdLU5rm1FsfkARPAFDADnAfOAAqnWZTn8cuXf7O+TnHcBjiK8omJpNkc
+l8t5FOXFoo6ivFjU5XIeRblSFo7jOM7bxYz9/ezWre6XX3Y2Nsb9vskyi2MLgBowAcwD54EZnHLS
+2u8/f/53jx5RHLcBjqJ8YiJpNse1Wlos6ijS5XJWLOooyotFLSXDcRzHeet2dpJWq9dq9Z8/Tw4P
+88HA4NgCoAQ0gEVgCZiGE+/t/ecHDyiO2wBHUV6vJ9PTo1otjSJdLOpKJSsWdbmchaGB4zjOO4AZ
+rxDh9NjaSh48GNy719/aGr98mQ2HBsemgAioApeAC8BZOAudzk9XViiO2wBHUV6vJ7Ozw3I5q1Ty
+cjkrFnW5nEdRrpSF4zjOCWGG1qw1P3w4+OUvD5eXe8xQiqxFFMlKxavV1PXrpfffL83PF/DHs5a1
+ZmYIQZ5HRNCarWUAQpDnEU7Uxsb4q6/6X3892NpKXr7MRiODY/OBKjABLAJzwFk4r/x4Y4PiuA1w
+FOWNRjI9PWo0knI5L5ezKNLlclYu53Acxzk5WWbHY9vp5J9+enT7dndjY8yMbzCDmYUgIUCEubnC
+wkJhZiacmQnPnQvm5gr4g92507t9u3vnTm8w0OOxzTLreaSUmJsr/OVf1v7qr+rNpo+TsLExXl0d
+LC/3dnbS/f1sNDI4Nh+oApPAHDAHnAE8OK9QHLcBjqK80UhmZ4eNRlIu5+VyVi7n5XIWhgaO4zgn
+xBgeDMzRUf7o0XB5uff114N+XzODCOfPF7773fJHH1XX10erq4OHD4d5zmlqs8wKQVJiaiqI4/KV
+K6WpKb9S8c6c8YNA4HdhxnhsBgOzsTG+caPz9df9/f0MICFoZiaI49JHH1XPnQsrFS8MBd6ura1k
+dXXQavV2dtKXL9PBwODYJNAApoBzwAwwBQQ45X6ytvZf796lOG4DXCzqiYnx+fODRiMpl/NKJSuX
+83I5U8rCcRznhIzH9uAg295Ovvpq8PDhYGNjbAwDUEp8+GHlRz+qf/BB2feFUpTn3Ono0cjs7aUr
+K4Nbt7r7+5kxbAwTkRCQki5fji5cKMzMhLWaV6upatXTmgGylnd20sePh8+ejZ8/Tw4P8yxjIVAs
+ysuXo+99rxLH5clJPwyFEIS368WLdGWlf+NGd2tr3Ono8djgTUwAC8AFoAlUgBCnXKj1T1dWKI7b
+ABeLutFI5ub6k5Pjcjkvl7NyOa/VUjiO45ycfl/v7mbPno3v3etvbIzHYxMEgoiCgD76qPof/kN1
+fr4gBAmBf+3oKO90dJLYzc3xw4fDlZW+1pymdjQyRGAGM4jADGtZSpKSfF+Uy7Ja9WZnw6tXSxcv
+FhsNVSxK3xdEeMuYwYzDw3x5ufv5550HDwZparVmZhxfxLhIuArMACGgAAGH4rgNcLGom83x+fP9
+ZjOp1dJyOa/V0mJRw3Ec588FM14hAjOYYS1nmfU88n2Bdw8zrGVr+fbt3mefHd282c0y1toy45gE
+oIA54ApwBSgBhFPu0uHh36+uUhy3AS4WdbM5np/vTU4m1WpaLue1WhqGBo7jOM4JMYb7ffPkyejm
+zW6r1XvxIrEWx+cDEVACrgJLwFk4r0wPBhTHbYCLRd1sjufne1NT41otLZfzWi1VysJxHMc5IaOR
+2dvLtreT+/f7q6vDzc2x1oxjk8AEMA0sAjNADQhwyi10Ov/X06cUx22Ai0XdbI4XFnpnz45qtbRc
+zqvVVEqG4zjOCclzfvx4eO/e4OHDwXhsul3d7eqZmeDCheLly9H8fOHMGb9S8fDHsxZZZsdjs7OT
+Li93W63+YKClpPHYhqF4//1SHJcXF4u1mlcsSikJJ2dzc/zo0Wh5uffs2fjgIBsODY6NgAKwCFwH
+5gAf8ACBU6sxHn+wu/t3jx5RHLcBLhZ1szleWOidPTuq1dJGIymXcziO45ycPOd79/q/+tXR8nJv
+PDZZZq3lSkU1Gmpy0r9ypXTlSnT+fHhwkCWJFQKeJ6pVz1rudLTWtlTyfJ+05vHY5jn7Pk1M+MZw
+v6/znIlQLMpaTf2P/7F/505vY2OcplZrZkazqWZmgosXo2vXSouLhWbTx3ERUbFYDF6TUmqtrbVC
+CM/zmDnLMgBCCM/zhBBa6zRNlVKe5xERMydJkqZ2Z8dsbCTPng23t4fjsQ5DVSr51nK7PcoyUyr5
+pZIvpRgOs52dfqMRlsuBUjJN9cHBaH29k2UmTfV4rCEAH5gCrgJLwCQgcMpNDwY/XVmhOG4DXCjo
+qanRwkLv7NlRrZZOTCTFoobjOM5JYIa1bAy+/npw48bRjRudwcBozcYwACIIQURghrUsBAmBbzCD
+GcwgAhFeISJ+DQAziEhKMOMVZljL9E9AhFesBRGUEtPTweJi4bvfLS8uFs+eDcJQ4I8npSwWi6VS
+qVar1ev1KIqY2RgjhPA8j4i01tZaAFJKpZQxJssyes3zPCHEaDQ2hpmFlOKVg4PxYJAFgddsFj2P
+2u3xaJQDqFbDM2eivb3hcJgRQSlZqQRJon/+8/VPPtm8ffv5+nqn309zbdEAzgMXgTNABQhxygVa
+x3t7FMdtIg5DPTU1Wlzszc4Oa7W00UjC0MBxHOeEaM1ZZnd2khs3Ojdvdre3U4ABlMvee++V3n+/
+dOVKqV73ymUvCAQzmGEtM0MpYoa1zAwiSEkAmGEMA/A8wmvMsJalJADM+AYRvmEtAxCCcKK05p2d
+5NGj4b17/c3N5OXLdDg0OB4CCJDAPHAdWARKgAQIp9xHL15QHLeJOAz11NRocbE3N9evVrOJiUQp
+C8dxnJPDjCyzKyuD1dXB/n4WRbJS8cJQzs0VKhUZRbJU8goFISXhzxQza823bvVu3Oi0Wr3BwGSZ
+xbFJoApMAovAeWACCHHK1ZLkHx48oDhuE3EY6qmp0eJib26u32ikjUYiJcNxHMc5OXnOh4fZ06fj
+u3f7X33V39lJ8pxxPAQIwAPmgPeBi4APSEDg1BLMFw8Pf7K2RnHcJuIw1GfPDufn+wsLvYmJtNFI
+4DiO8+eIGUT4k2At7+1lX301uHmze/duL8tYa2stjskDqsAZYAmYBSaAAKfcbL//440NiuM2EQeB
+mZkZLC31FhZ6jUZaq6VwHMd5x1jLWcZpatPUAuj19Obm+Nmz8dZW8vx5GkXS8yjPudvNez3NDM8j
+pUSeW2tZCAJgDGvNRHilVPK0tnnO09NBraaUonLZu3w5uny5WK8rKSkMRaEgcUKYkSSm09HPnyfL
+y7379/sbG4m1jDcRAvPAReAC0IDzyvt7exTHbSIOAjM9Pbx4sXvhQrfRSMrlHI7jOO+GbldvbycP
+Hw5v3eo+fjy0FtaytbCWg0D4vhAC1rKUtLBQOHMmKJWktchzDkMxNeUXi9IY1pqFoGJRlMve/n42
+GBghkGX88mX64kVqLbLMHh1l3a7Ga8WiXFwsvP9++b33Ss2mX6l4YSjw1u3tpSsrg1u3uk+ejDud
+PEmstYzjIaAGzAKXgCmgAhQAwil3pd2mOG4TcRDomZnh0lLvwoXu5OS4WNRwHMd5B2xvJysr/eXl
+3s5OenSUj0ZGCJqa8q9eLf3gB9Xr10uFglSK8AaYoTUfHGQrK/2bN7tPngxHI5vnlgizs4Vr10rf
+/351cbFQLntSEhHeDmakqR0MzNZW8sUXna+/7u/spFlmcTwEKCAEasBVYBE4A0g4P1lbozhuE3EQ
+6JmZ4dJS79KlzsREUixqOI7jvAOM4cePh3fu9Fqt3t5eNhyaNLW+L4JAeB6Vy97775fPnQuiyGPm
+Wk01Gmo4NMZwuewFgdjfz7LMCkFK0XBojo7yvb1Ma5YSSWI7nXx7O3n5MrOWrYW1zAylKAjk5KQ6
+f75w+XLxwoVodjaoVJZBwbcAACAASURBVDwpCW9dr6dbrd6dO727d/tHR7kxjDcRABeBC8ASUAYk
+TrnAmP/0+DHFcZuIg0DPzAyXlnpXrx41GkkYGjiO47x71tfHDx4M1tZGR0e5MXxwkO3upgCCQKSp
+BcCMV5jxCjMDJCUJgVekJKUoz9kYFoJmZoJm0w9D4Xnk+zQ9Hc7MBBcvFptNH++GPOduN3/yZLS8
+3Pvqq8HLl+l4bHFsAigDs8AFYBaoAQFAOM08a3+0uUlx3CZi3zezs4OLF7uXL3cmJ8dKWTiO4/wJ
+0pqlJCJYy8ZACEhJzPgGEf6EMHOvpx88GN661b1/v//8eYo3IYEycAa4AMwBk4CHUy7U+idraxTH
+bSL2fXP+fH9hoX/t2uHk5FhKhuM4jnPSXrxIHz4cfvFFZ3m5l6bWGGbGMXlAAMwC7wHzQBUQAOGU
+++HODsVxm4h938zODi5e7L733tHU1AiO4zjOSTOGDw7ytbXh7dvd1dVhu52PRgbHRkAJmAWuAOeB
+EhAAhFPu6sEBxXGbiH3fzM4OlpZ6168fTk2N4DiO47wDDg/zhw+HrVbv7t3+zk6CNyGBMjANLAHn
+gAYQwgmMoThuE7FSZm6uv7TUe++9o6mpERzHcZx3wP5+9tVXg+Xl3q9+dZRl/BqOyQciYBK4CMwB
+DcDHKVdJ079+9oziuE3ESplz5wZLS73r1w+npkZwHMdxTpq1vLeXPX48vHmzu7zcG42s1mwt4xgI
+kIAPTAJXgXlgElA4zXxjvvPy5X/56iuK4zYRK2Xm5vpLS7333juamhrBcRzHOWlac6+nHz8e3r7d
+W1npHxzkSWKYcRwEECCAc8AlYBGYAiSc+nhMcdwmYqXM3Fx/YaF/7drh9PQIjuM4zolihtasNT94
+MPjss6MHD4a7u0meM46HAAIIWACuAnPAGYDgTA6HFMdtIg4CPTMzvHixe/364eTkGI7jOM6JshbG
+2Dznr78efP555+HD4dZWYi3jeAggQACLwGVgAZiE8w2K4zYRK2Xm5voLC/1r1w6np0dwHMdxThQz
+jGFjeHV1+MUXnfv3+8+fp1lmcWwECGAOuALMA9MAwTnb71Mct4lYKXPu3ODixe7Vq0fT0yM4juM4
+Jy3PudfTq6uD27e7KyuDo6M8TS0zjoMAAQjgPHAFmAcmAQmnPh5THLeJWClz7txgaal37drh9PQI
+juM4zkmzll++zB4+HN661V1e7o3H1hi2lnEMBHiAD0wBV4E5oAl4OM1Crd/f2/svX31FcdwmYqXM
+3Nxgaal79erR9PQIjuM4zjvg4CBbXR3eutX97LOjLOPXcEwKKABN4CIwDzSBAKdcJU3/+tkziuM2
+EStlzp0bLC72rl07PHt2BMdxHOcd0OnkDx8OW63+3bu9ra0Eb0ICVeAssAjMAg0ggBMYQ3HcJmKl
+zLlzgwsXulevHp09O4LjOI5z0rTmvb3swYPBnTu9R4+GnU6eJBbHRkAZmAcuAeeBIuADhFPu6sEB
+xXGbiJUys7PDpaXutWtHZ86MpGQ4juM4J+3Fi3R1dfjFF5179/rjsTGGmXFMHhAAs8BVYAGoAgIg
+nHI/3NmhOG4TsVJmdnZ48WLn0qXumTMj37dwHMd5lySJzXNrDI9GJs+5VPLqdU9rZoYQpBThz1G3
+qx88GNy61b13r//iRYo3IYEy0AQuAXPAJODhlAu1/snaGsVxm4h938zMDBcXe1evHjWbSRhqOI7j
+vBus5Rcv0pWVwe3b3c3NpNvNRyNrLQsBIpIS5bL33e+Wr1wpXb0azc6GQSDwh7EWWWaHQ5Mkdnc3
+7fW0EBiPjTEoFMTcXGF6OmBmKSkIhJSEtyvL7NFR/vjxaHm59/XXg/39LE0tjk0CFWAGuAzMAFVA
+AYTTzLP2R5ubFMdtIvZ9MzMzvHChe+FCt9lMoiiH4zjOO4AZe3vZ+vr4wYPB6upgdzftdrW1LAQR
+QUpiBhGIwAwiTE4Gi4uFa9dK16+X5uYKRCDCv81adDr506ej+/f7q6vD3d2039fWggj1uvroo8r3
+vle9fLk4MeHjrev19K1b3eXl3v37/W5Xa814EyFwEbgILAIlQOKUC4z5T48fUxy3idj3zczMcHGx
+t7TUbTaTSiWD4zjOO6Df1y9fZg8fDu/d66+vjw4OMmsRRWJiwp+fL3zwQWVy0reWnzwZPXgwePJk
+NB7bLLNaM4CJCTU9HZw7Fy4uFs+fLzSbqlSSYSiVIvwre3vp6urw5s3uw4fDwUAnibWWm01/aan4
+wx/Wrl6NJiZUEEgh8HYwI03tYGB2d9N//MfDhw+H29tJllkcDwEKCIEqcA2YB6YACecna2sUx20i
+9n0zPT1aWOhdutRpNpNKJYPjOM5JS1Pb75vNzfGdO72vvx7s7CRJYnxfFIvy7Nnge9+rfu97laWl
+Il5jRprawUC32/mLF+nTp6PNzWR3N+108tHI0D8BEV45ezY4fz5sNn1rcXiYHR3lzMhzPjrSg4Fm
+ZgClklxYKFy+XLp6NZqaChoNFUUSb93eXray0r99u7e2Nup08iSx1jKOh4A6cA64BEwBZSAECKfc
+lXab4rhNxGGop6ZGi4u9hYVes5nU6ykcx3HeAb2e3tvLBgOdplZrTlObptYYhKGYny8sLRWkJPyf
+7O6mT5+Onz0bb26OBwPjeaS1HY/t4WE+GJgzZ/xyWVrLxaK8erV08WJUq3lBICoVr1LxcEKYMRqZ
+g4NsaytZXu6trg62t1NrGW+iAMwDF4ELQB3OK+/v7VEct4lsGJqpqdH8fH9hoT8xMW42EziO4zgn
+yhh++TL7+uvBl1927t3rZRkbw9bimBRQA84C88As0AB8nHKz/f6PNzYojttENgzN5OR4aal77tyw
+2UwmJsZSMhzHcZyTk+d8dJRvbIxv3+4+eDDc3k7y3OJ4CBCABywC7wEXgACQgMCpJZgvHh7+3w8f
+Uhy3iWwYmqmp0dxcf25uUK+nExNj37dwHMd5J2nNo5G5fbt761b39u1esSiDQGSZNYat5enpYH6+
+cOVKtLBQvHixiD9ZzNCav/ii8/nnR3fv9kcjk+eMY/OAKnAWWATOATUgwClXS5J/ePCA4rhNZMPQ
+NJvjxcXe7OywXk+bzSQMNRzHcd49zMgyu7ub3rrVvX27+/Dh0Fq8IiUVizIIhBDQmvOcx2OTZVYp
+EQSiUJDFoqhUvMXF4uxsMDMTzs6GExMK7zCteWsrefRoeOdOd2cn3d/PRiOD4yFAABK4AFwBLgIF
+QACEU+4vtrcpjttENgxNszleWOifPTus19N6Pa1UMjiO47x7mKE1r6+Pv/ii8+mnR+12Zi0DqNfV
+/HzhvfdKV65EMzNhve5JSf2+3tlJt7fHW1vJ06ejly/TNLVZxnnOWjMz6nWvXvebTdVs+tPTQb2u
+6nWvWvXKZa9c9jyPcFxSymKxWCqV6vV6rVYrlUrMnOe5EMLzPCKy1uZ5DsDzPN/3tdZ5njOzEMLz
+PCFkkiRZZgDxipSi3U4Gg6xQ8Or1gueJg4NRmhpjbLUaTk1Fu7uD4TADoJSs1cIsM//zfz79/POt
+L77YefasOxikubZoAPPAZaAJlIEAp1ygdby3R3HcJrKFgqnXk/n5/tmzw3o9rdfTej2F4zjOyTGG
+V1eHKyuDhw+HvV5+dKQ7nTwMhe+LPLcAjEGeW2vZWjBDCAhBpZKUkrTmwUADCALh+4IIWvN4bD2P
+fF/kuSUCM4xhrdlathbfIEIQiCiS9br6wQ+qP/xh7eLFIo6LiIrFYhiGQRBIKc1rQgilFDNrra21
+QggppRAiz/MsyzzPk1IKIay1WZalqd3YyHd20s3N8c7OcDzWQeCVywHAR0fjJDHFolcs+lLSYJBt
+b/cbjbBcDpQSWWZ2dwdbW70sM0mik0RDAgHQBN4DLgCTAOGUW+h0/n51leK4TWQLBTMxkZw/3z97
+dlipZPV6Wq+nUjIcx3FOCDOGQ7OxMVpdHXa7ejg0zKjVPN8Xw6HZ3U339rJ+X4/HJk0tM3yfwlBO
+TKj5+UK5LIWgKJL1upKShkOTplYIqlY9KSlNbZpaKVEsyiAQWvN4bAFEkSwWpTEsBDGjVJKzs0G5
+7OHkrK+PV1b6d+/2nz9P2u18NDI4HgIIKAKXgKvAPOABEiCcWo3x+IPd3b979IjiuE1kCwVTrydz
+c/3p6XGtllSrea2W+L6F4zjOu8daHo/tYGAODrJOJ+90tDHs+2J6Omg0VLEoKhXP9wX+xA2HZnc3
+3dgYf/XV4NGj4c5OojXj2CTQBM4BC8A0UAV8nHJz3e7fPnlCcdwmsoWCqdeTc+eGU1Ojej2tVLJ6
+PQ1DDcdxHOckMMMY7vX0+vr4iy86rVbv5cvUWhxfAERADbgILAHTcF6ZHgwojttEtlAwlUo6Pz9o
+Nsf1elqpZJVKVqlkcBzH+VOQ5/yK74sksVlmreUss0EgSyXZ6eTDodGaPY+iyKtWvX5fp6kFICWV
+SrJQkHj3MMNaNoZv3ep+9lnn5s1unltjmBnHJAAfmAeuAJeAEkA45S4dHv796irFcZvIFgqmVkvP
+nRs0Gkm9nlYqWaWSVSqZlAzHcZx3Q5rap09H+/tZp6N3dpLHj4fdrmbGeGzS1DLDGAZARPgnzAxm
+SElEeIUZ/E8gBBHhFWYwg5mFIM8jz6NCQZbLcmoquHw5WlwszMwE1aoqFIQQhLeLGdbywUF2+3bv
+xo3O6uogy9haZsbxlYCLwHvADBAACiA4FMdtIlss6mo1O3du0GgklUpWqWSVSlapZL5v4TiOc0KY
+wczWYnm599lnh7/85SEzmPFKEAghqFSS16+XZ2aCUslrNNTcXFgoyDy3vi98X3ge+T5ZC63Z84gI
+RCQErOUksdaCCJ5HQtBoZLa3x/fu9VdWBpub4+HQAPB9MT9fuHat9MEHlXPnwkrFU4rwdm1vJ7dv
+d2/d6u7spL2eTlOLN9EEFoCLwARQAQKccqHWP11ZoThuE9liUVer2dmzw0YjqVSySiWrVvNKJQtD
+DcdxnBOS53x4mG1tJQ8fDldXBxsb49HIEkEIunw5+tGP6n/913WlhJQQgvAHYwYRXjGGrUWW2Z2d
+pN3ONzfH6+vj9fXR4WFOREJgdjaM4/JHH1VmZoJSyQtDgbdrczNZXR20Wr2dnWRvLxsMDI7NA+rA
+FHAeOAucAUKccj9ZW/uvd+9SHLeJbLGoq9XszJnRxERaqWSVShZFeaWSVSoZHMdxTo61sJazzN6/
+32+1+mtrw4ODvNfTeW4BKCWiSAaB8H0BcJZxv6/rdVWreYWCzDLb7epuNyeiKJJCUJbZfl+nqWUG
+QERgZmtBhFeEoGJRBoGo170PP6zEcXlmJggCUShIzyOchPX18erqYHm59/x5ur+fjUYGx+YDdeAM
+sADMAGcACecViuM2kS0WdbWaTU+PKpWsUsmiKK9Uskoli6Lc9y0cx3HeAcywlrPMjkZ2MNBpapPE
+Hh7mw6E5PMwODrJ+Xx8c5FJSreaFoVSK0tQOh0ZKqlS8el2FoQDgeVQue7OzYa3mWYtiUfq+UIoK
+BSEEMYMI74j19fHKSv/rrwebm8nBQTYaGRxbAFSAJrAInAfOwnnlJ2trFMdtIlss6lotbTaTSiWr
+VLIoyiuVrFTSlUoWhhqO4zjOSVhfHz96NLx3r7+5Od7fz4ZDg2NTQAmoAZeBBeAsnIVO56crKxTH
+bSJbLOpaLa3X03o9jaI8ivJSSVcqWRTlUZRLyXAcx3HeumfPxl9/Pbh5s/vyZdpu58OhwbH5QAmo
+AUvAEjADJ97b+88PHlAct4lssahrtbReTyuVLIryUklHUR5FeRTllUrm+xaO4zjO28WMg4Ps1q3u
+5593treTXk+nqcWx+UANqAMLwHngHE4535gPX7z4u0ePKI7bRLZU0pVKWqtlpVJWKukoyqMoj6K8
+VNJRlEdRDsdxHOety3P+7LOjGzc6X301GI9NnrO1jOPxgAYwBcwA54EzgI/TrJjn33n58m/W1ymO
+20S2VNKVSlqrZYVCXirpKMrDUJdKOoryKMqjKPd9C8dxHOdtYYbWnOf20aPhp58effLJ0XhsmPFG
+msBZYBY4C0wCRZxmBa0vt9t/ubVFcdwmsqWSrlTSWi0LAhNFeRTlhYKJojwMdamkoygPQy0lw3Ec
+x3lbhkPT6+mXL9Mvv+zeu9d/9myMN1QDLgAXgCZQBgo4zTxrpweDD3d3KY7bRLZU0tVqWq1mnmej
+KC8UTBTlYaijKC8UTBTlhYIJQw3HcRznbclz+/TpeG1t9OjRcGNjvL2dZJnFsREggMvANeACoAAP
+IJxegwFaLaysUBy3iWyppKvVtFZLpeQw1IWCCUMdRXmhYMJQl0o6DHUYat+3cBzHcd6Wg4Pszp3e
+nTu9zc3x0ZEeDDSOTQE+MAFcBy4BDZxeGxtotdBq4TWK4zaRLZV0tZrWaimAMNSFgglDXSiYMNSF
+gomiPAx1oWDCUEvJcBzHcb5lzDCGs8w+fDj8/PPOp58eDYfaWhyfB9SBCWAWmAfOAQKnzsoKWi2s
+reE3UBy3iWyppKvVtFZLAfi+DUNdKJgw1GGoCwUThtr3bRjqQsGEoZaS4TiO43zLxmOztZVsbiaP
+Hw8fPx4+fTo2hvEmKsBF4DLQBCKggNNCa7RaaLWwvY1/heK4TWRLJV2tprVaCkBKDkPt+zYMdaFg
+wlAXCkYpUyiYMNSFglHKSMlwHMdxvk3M6Pf1zZvdL77orK+P+309GhlmHJMHKOAscA24BhQAwp+/
+JEGrhVYLu7v4PSiO20S2VNLValqrpXjN920Y6kLBKGUKBaOUKRRMGGrft2Gofd+GoZaS4TiO43xr
+ksQOBmZ/P/v886Mvv+zu7CR4EwRMAE1gGpgDZoEAf+ZaLbRa2NjAv4niuE1kSyVdraa1WorXpOQw
+1L5vw1D7vvV9G4ba920Yat+3Yah93yplfN/CcRzH+dY8f57eu9drtXq7u9n+ftbrabyha8A1YB7w
+AQUI/HlaW0OrhZUV/AEojttEtlTS1Wpaq6X4Nd+3Yah93yplfN+GofZ96/tWKVMoGKWM71vft2Go
+4TiO43wLhkPT6+nnz9MvvujcutXd38/wJgKgATSBc8B5YAZ/ng4O0Gqh1cJggD8MxXGbyJZKul5P
+KpUMvyYlK2V83/q+Vcr4vvV9G4ba961Sxvet71uljO9bpYzvWziO4zj/3vb2svv3+3fv9re3k/39
+rNPJ8YauAO8Ds0ABCACBPysrK2i1sLaGPwbFcZvIlst5rZZWKhl+g5SslPF96/tWKeP71vetUsb3
+rVLG963vWylZqf+PPXh9jvPK7wP/Pec8t+6n++mnG2igQYAgLrxApB6GI41lj+3YcWWTTHYTXzZJ
+SVtbqbE3qcqb/aPycl/u21R5xmPrQkoEyQYJkCAIggBIgCCARt+7n8s557eUpmZrxvZkLEAiKOF8
+PspxtG0rx9EwDMMwviGDgWq1ZLOZLS6279xpP3s2xElYQBmoAOeAC8A0wPH90euhXsfiIlotfE0s
+ihqM6WIxC8MkCFL8OsfRnGvH0Y6jbVsJQY6jbVs5jhaCbFs5jnYcLQTZtnIcbdtKCBKCYBiG8Q1h
+WjOluFKl9fXyo0fFra3M97XjZIVCUiqlYTgcHY2r1bRYJMbAGL5f/vZvjz75pPn4cT+OVZJorXFM
+DGDANHAdiAAOcIDh+2BvD4uLqNchJb4+FkUNxnSxmIVhEgQp/gEhyLaV42ghyHE059pxtBBk28px
+tBBk20oIchwtBNm2chwtBNm2EoKEIBiGYZwEEZeSZ1mwuXnu44+nfvYzkSTQmhERY+CcOCfOtRDt
+S5eaCwvNhYVBrTYcHdWOQ4yBMfxP8TS1+32716t9/vnY7dul9XVGBEDbtnLdpFR6+Yd/uPejH3Wn
+p3Eanj0bbmwMnj4dbGwMnz7tx7HGSYwAU8AFYBQYAXx8H2xuol5HvY7jYlHUYEwXi1kYJkGQ4h8j
+BAlBtq2EIMfRQhDn2nG0EGTbSggSghxHc64dRwtBQpBtKyHIcbQQxLl2HA3DMIyvj0vJpPQajXMf
+f3zu44/93V2mNdN6MD4eV6vSde3BwOr3rcHAimMRx8QYOI/L5c78/NG1a72pqf65c3GlQpyTEPgN
+RJpag4HTbtdu3Rr/4ovi5ibTmhH1a7Xu9HR3Zqa5sNC+eDENArxBcawHA9VopDdvtv7u75qvXiU4
+CQfIA3ngIvAOMIHvg81N1Ouo13ECLIoajOliMQvDJAhS/GZCkG0rIUgIEoKEINtWQpAQJATZthKC
+hCAhSAiybSUECUFCkG0rIUgIEoKEINtWQhAMwzB+G6Y1zzIu5dji4sQnn4zducO0ZlonYdg9f743
+Pd1cWGhdujQYH7cHA7vTCZ88GXnwIHzyxO717F6PZxleY2w4Nta5cKEzNzeo1fq1WlIuS9+XnofX
+GGNKiTRlSo3evz/xySfjn3/OtGZEynWTcjkplQ7ee2///fdbly/jNNy61frZzxorK900pTTVWuNE
+5oDrwDWAAxxg+A578QL1Oup1SIkTYFHU4FwXClkYJkGQ4rcRgoQgzrUQJAQJQUKQEMS5FoKEIMfR
+nGshSAgSgoQgzrUQJAQJQUKQENp1leNo29acE+cEwzCMfwyXkmdZfm9v6mc/O/d3f+e2WniNsc7M
+TO/8+c7sbOvy5aN33iEh8CuYUiJNrTgOHz8OV1eLW1v5/f3c4SFPUwaACK8RgTEAxBjDV4jwGpFy
+XZnPy3z+4Ac/OHjvvfbcnPI85XnEGN643d3kwYPugwfd3d14fz9ttyVOIgDmgHlgBCgBPr7DWi3U
+66jX0WrhZFgUNTjXhUIWhkkQpPgnE4KEIM41ACFICBKChCAhiHMtBAEQgoQgIYhzLQQJQUIQY1Qo
+ZL4vPU/atrYszRgMwzB+I60ZESMCEb5CjIExMEaMgTH80zClGBHPMp6mIk15moos41nGlNJCkGUp
+15W5nHYc6XkkBE6b1rS1FW9vDzc2hmtr/bW1fppqnMQYMAbUgHPAFODgO6xeR72OzU2cGIuiBue6
+UMjCMAmCFMclBAlBADjXQhAAIUgIEoIACEGcawBCkG3rIEjDMPX9zPOk6yrGYBiGYfw9g4FqNLKj
+o/T+/e7t2+1nz4Y4CQcIgBC4AMwCU/gO29tDvY56HXGME2NR1OBcFwpZGCZBkOKbJgQJQQA41wCE
+ICGoWh2OjsZBkObzMp/PGINhGIbx9wwGqt9X+/vpxx8f3brVajQynIQL5IAAWACuAiG+w5aXUa9j
+fR3fBBZFDc51oZCFYRIEKb59lkXV6nB8fBCGSbGYFYspDMMw/iEiAExrpjUjIs5JCGIM3xwupdXr
+Ob1e6enTyvJyZXVVWxaAuFzuT052p6f7584NJibiSgVvHBGUIilpY2Pw13/d+PnPj7JM4yQsQABV
+4F3gB4CL76o4Rr2OxUUcHuKbwKKowbkuFLIwTIIgxbfPsmh8fFCtDsMwKRazYjGFYRjGr2Nacyl5
+lo3W61M//enYnTskBFlWWiwOq9V4dHRYrQ5HRtJSSebzaRBIz1Ouq1xXO45yHOIcjOG3EUlid7tO
+pzOysjJ2+3a4tsazjEs5HBtrzc+3L17szM11Z2biSgWn58GD7k9/2vjpTxv4RkwBN4Af4jus1cLi
+Iup19Hr4JrAoanCuC4UsDJMgSPHtsywaHx9Uq8MwTIrFrFhMYRiG8fcQMSJo7e/tFZ4/91++tPp9
+ezCwu1231XKbTWswsAcDkSRgDADh1yjXzYrFtFBIS6U0DNNiUebzMp9Pi8W0VEpLpbRYzAoFAHav
+Z/d6I/fvV+/dC9fWRJYxKYdjY83Ll9sXL3YvXOjOzMSVCr4+nqbh+nqwsRE8e1ba2Citr+MN2kNh
+CbU6anXUFnFuHRX8wgxwA7iB77DDQ9TrWFxEHOObwKKowbkuFLIwTIIgxbfPsmh8fFCtDsMwKRaz
+YjGFYRjG10XEiJhSIklEkog45lKKOLb7fbvfd1st9+jI39vzGg3v8NDpdPALRFwpaI1fYIw4JyFA
+BCJGxLRmRIPx8db8fPvixc7cXHdmJq5UcHoePOj+9KeNn/60gW/EFHAD+CG+w1otLC6iXkevh28C
+i6IG57pQyMIwCYIU3z7Lomp1OD4+CMOkWMyKxRSGYRhvFk9TkSR2v587OMi/epXb3/eOjrzDQxCJ
+LMt8vzs93ZuaGtRqg1otKZdxGrQmrbGxMfgf/+Pwb/7mKMs0TsICBFAF3gV+ALj4ropj1OtYXMTh
+Ib4JLIoanOtCIQvDJAhSfNOEIABCEADONQDH0SMj8djYsFhMfV/m8xljMAzDMP6ewUANBurVq/Tj
+j49u3Wo1GhlOwgVyQBFYAK4BIb7DlpdRr2N9Hd8EFkUNznWhkIVhEgQpjksIAiAEca4BCEFCkBAE
+QAgSggBwroUgISgMkzBMfT/zPOm6ijEYhmEYf0+vpw4OkoODdHm5d/duZ2triJNwgBAoA+eBWWAS
+32F7e6jXUa8jjnFiLIoanOtCIQvDJAhSfB1CkBDEuRaChCAhSAgCIARxroUgIUgIEoI41wCEICHI
+snShkPm+9Dxp29qyNGMwDMP4GogYkdXv2/2+0+067bZ7dOR2OtZw6HQ61nBoDQYijkWSiCThWUaM
+caVAREIo15W5nPK8pFTKisUkDNNiMQsC6XnK82Q+n/l+GgTKcfAaYzg9StHm5nBra7ixMVxf7z95
+MkhTjZMYB2pADagBk4CD77B6HfU6NjdxYiyKGpzrQiELwyQIUvw2QpAQxLkWgoQgIUgIEoI410KQ
+ECQECUGcayFICBKChCDbVkKQECQECaFdVzmOtm3NOXFOMAzD+M24lHavZ3e7xe3tcG0tXFvzGg23
+3RZJAiL8AufEGAmhOde2TZalbVt6nrYssm1tWdqyyLK0EMQ5IwKRSFOr37f7fSuOreGQJwkDQKQt
+S7muct2ja9caWoo3qgAAIABJREFU16515uaScjmuVEgIvHG7u8nycvfBg+7OTrK/n7TbEicRAHPA
+HDAClIACvsNaLdTrqNfRauFkWBQ1GNPFYhaGSRCk+M2EICGIc+04WggSgoQg21ZCkBAkBHGuHUcL
+QUIQ59pxtBAkBAlBnGvH0UKQEMS5dhwNwzCM34ZLafd6drc7+uDB2OJiZWWFKcW0zgqF4dhYf2Li
+MIqaV6/2JifBGI6NiOFLlQcPzn3ySe3mTZEkIk21bSelUhqG+++9t//DH7YuX8Zp+Oyz1l//9eHy
+ck9KLSUR4ZgYwIB54DpwDWAAw3fbixeo11GvQ0qcAIuiBmO6WMzCMAmCFP8YIUgI4lw7jhaCHEdz
+roUgx9FCkG0rIUgIsm0lBDmOFoKEINtWQpDjaM61ECQEwTAM42tym83c4aG/s1NZWamsrHiNBiMC
+UffChd7U1LBW609M9CcmpO8r15WuS7atbJuEwG/Gs8waDu1u1+71co1G7uCg8Px5cXvb39nhUvIs
+A6AtS1vW0dWr+7/zO4fXr2eFgsznSQi8Qf2+6nTk/n56+3b75s3m/n6Kk/CAIhAAs8AlYBzfB5ub
+qNdRr+MEWBQ1GNPFYhaGSRCk+AeEINtWQpDjaCHItpXjaCHItpUQ5DhaCLJt5ThaCLJtJQQ5jhaC
+bFsJQTAMw/gmuM1mcXu7uL3tv3xZePEit78v4tju97mURMTwS0QAGBEBDF8hAmMAiDG8xhiIwBhe
+I9K2rTxP5nLDarVfq/UnJwe1Wnd6Og3DLJ8nIXCqnj0bbmwMnj4dbGwMnj4dxLHGSYwAU8AFYBQY
+AXx8H2xuol5HvY7jYlHUYEwXi1kYJkGQ4tcJQbatHEc7jhaCbFs5jrZtJQQ5jrZtJQQ5jnYcbdtK
+CHIcbdtKCIJhGMa3jCnFpWRK8SxjWhPn4Fx6HgnBlGJKcSm5UkwpEAEgzkkIYowsi4TQnINz4hxv
+t7/5m6OPPz5aXe0nic4yTYRjYgAHLgARcB1gAAMYvg/29rC4iHodUuLrY1HUYEwXi1kYJkGQ4lcI
+QbatHEc7jrZt5TjacbRtKyHIcbRtK8fRjqNtWzmOtm3lOBqGYRjGN6TXk4eH2cFBeu9e5/797tbW
+ECdhA6NAFZgApoBJgOP7o9dDvY7FRbRa+JpYFDUY04WCLJfjIEjxS0KQbSvH0Y6jbVs5jnYcbdvK
+cbRtK8fRuZyybeU42raV42gYhmEY37RXr5Klpe69e52XL5PDw7TdljihBeA6MAW4gAMwfK8sL6Ne
+x/o6vg4WRQ3GdKEgS6UkDBP8kuNo21aOoz1POo52HO150nG0bSvH0Z4nHUc7jrZtJQTBMAzD+KYN
+h3owkHt76c2bzVu3Wq9epTgJBygBITANzADn8f10eIh6HfU6ej3807AoajCmCwVZKiVhmOArQpBt
+q1xOOY72POk42vOk42jbVrmcsm2VyynbVo6jYRiGYXxrdneT+/c7S0vdly+Tg4O005E4CQa8A1wF
+pgEXsAGO76f1ddTrWF7GPwGLogZjulCQpVIShgm+4jja86TjaM+TuZyybZXLKdtWuZzyPOk42vOk
+EATDMAzjW9Pvq1Yre/kyWVxs37nT2dtLcBIcGAPGgQngHFADHHzP1euo17G5if8pFkUNxnShIEul
+JAwTAEKQbatcTnmezOWUbatcTnmezOWU50nH0Z4nhSAYhmEY37JuV37xRfvmzeazZ8NeTw2HigjH
+JAALqAHvAteAHMDw/RfHqNdRr2NvD78Bi6IGY7pQkKVSEoYJAMfRtq1yOeV5MpdTnic9T+ZyyvNk
+Lqc8TwpBMAzDML5lw6F68SLe3o7X1vpPngw2NgZKEU4iAOaBS8AoUARyOCukRL2Oeh0vXuAfYFHU
+YEwXCrJUSsIwAeB5MpdTnidzOeV5MpdTnidzOeV50vczIQiGYRjGt4wIaarjWK+u9r74on3zZqvf
+V/QlHJMNjABjwCQwBUwAHGfO8jLqdayv41ewKGowpgsFWSolYZgA8P0sl1OeJ3M55fuZ58lcTvl+
+5nnScTQMwzCMN+XwML1zp3P3bnt7O261sl5P4dhswAVGgXeAy0AZZ9fmJup11Ov4CouiBmO6UJCl
+UlIqpZalfT/L5ZTnSd/Pcjnl+5nnyUJBep6EYRiG8aZkGW1vDzc2Bmtr/Y2N4dbWMEk0jo0BHLgM
+XAPmAAcQAMPZ1euhXsfyMouiBmO6UJBBkIRh6rrK9zPPk4WC9Dzp+1mhID1P+n4mBMEwDMN4U3o9
+1Wxme3vJ7dvt5eXu8+cxTigE5oE5oAoUgRzOsoXDw4+Wl39Sr7MoajCmCwUZBEkYprlcVihIz5O+
+nxUK0vcz389yOeV5EoZhGMabQgQpdRzrtbX+J580P/20GceaCCcyBkwCU8A4MAp4OMsWDg9/Uq9/
+tLzMoqjBmC4UZBAkYZgWCmmhIH0/8zzp+1mhIH0/8/1MCIJhGIbxZmUZffLJ0a1brZWVXhzrLNNa
+45gsYAQYByaBKWAMsHGWzbRaf1mvf7i8zKKowZjO52UYJkGQBkEaBGmhIH0/8/3M97NCQXqehGEY
+hvFmEeHwML19u/3pp82dnbjbVWmqcWwuEAIjwAXgPHAOZ1wYxx8tL/+kXmdR1GBM5/MyDJNyOQmC
+NAhS388KBen7WRCkvp8JQTAMwzDeuOfP40ePevfudXZ24oODtNdTODYXKAAjwAwwC0zA+PH6+k/q
+dRZFDcZ0Pi/DMBkdjYMgDYLU9zPfz0qlzPcz389gGIbx1iDCa4zhF4jAGL6vNjeHjx/3l5d7m5uD
+g4O031c4NhvwgBJwBZgHzsGYabU+Wl5mUdRgTOfzslRKq9VhuZwEQer7WRCkvp8FQeo4GoZhGKft
+8DB9+LD38GFvezt++TJptTIhWJbRyIh940bw7ruFubl8terkcoJznIRSRITXOAfnDKdqa2v46FF/
+ZaW7uTk8OEj7fYVjc4EAqADzwHlgAmfZeL//+8+f/6eVFQAsihqM6Xxelkrp2NhgZCTx/SwI0iBI
+gyANghSGYRinJ451tysbjezmzda9e53nz4cAGEOpZF++7L/3Xml2Nlet2qWSzTl+FRGazezly2R/
+P/U8zhiSRDOGXE74vggCq1ZzLYvhK72earWynZ1kaamzvNx98SJmDJyzatW5cSP4wQ+C8+dzxaLI
+5wVjeJOePRs+fty7d6/74sXw8DAbDBSOzQaKwCgwA0wDNcDCWfbP9vb+7fr6f1tcZFHUYEzn87JU
+Sicm+pVKXCjIIEiDIA2C1PczGIZhnBIpqdORe3vJ2lp/ZaX35Em/25VEeO3SpfwHH4R/8Adl3xee
+J2yb4ZeIQETNplxZ6X7xRfvhw16vJ5OEHIeVSvboqH3jRnDjRrCw4OOXiKA1bW/Hn37aXFxs7+7G
+WkNrKpftubnc1avFK1f8iQk3DG3G8CZtbw9XV/v1emdnJ9nfT3o9hWOzgDIwDkwB54BxwMUZ95f1
++ofLyyyKGozpfF6WSunERL9SiYMgLZeTIEiDIHUcDcMwjNO2tNT99NPmz39+JCVpTUqREOCc+b64
+dq04MeHmciKfF9WqbVm80UgPD9OnT4cvXgwbjSzLiDEwBs4Z5yCi3/md0tWrxbExh3Pm+yKXE41G
+trMTP3s22NgYvHqVJIlmjHkev3TJv369eP16cXzcLRSEEAxv1suXydJS586dzvPncbOZDQYKJ1EG
+zgMXgTEgBDyccZ6UHy0vsyhqMKZzORWGydRUr1KJgyAtl5MgSIMgFYJgGIbxdohjvbbW39mJj46y
+g4P02bNBpyOJWByrJNEAiJDLCcdhQjDP46WSVSrZ5865k5NepWJvbAwePuzdv9+1bU5Ew6HGV7Qm
+IZhlMSGY53HfFxMT7sJCYX4+Pz7uhqGVywnG8IYRgQjNZnb3bvvWrdbDh70k0VISEY7PJ1xkWADO
+AR5gAxxn1tWDg3/75Ml/vXuXRVGDMZ3LqSBIpqb64+ODIEjL5SQI0iBIYRiG8V2gNRFBCIZ/MiIo
+RQAsi+HtQwStSWu6c6fz2WfN27fbaUpSaq1xTAxwgGngCnAZKAIMZ9zvvXjx4fIyi6IGYzqXU+Vy
+PDXVHx8fBEFaLidBkPp+BsMwDOM0EEEp6vXk06eDL75oLy11X76MtcbxOYAHlIBLwEXgHM4yofXF
+ZvNfPX36b9bXWRQ1GNO5nCqX4+npbrUal8tJuZyEYew4GoZhGKdHShoMVK+nskxLSVlGSaLjWKUp
+uS6vVp3RUce2meMwzhmOhQhEeI0xMIbXlCIhGN4Cw6E6PMy2t4crK71Hj3pbW8MsIxybACrAFHAB
+qAFlwMUZ9y82Nz9cXmZR1GBM53KqXI7Pn+9NTAzCMC6Xk3I5EYJgGIZxSpSinZ1kdbW3vNx7+nRw
+cJDGscrnxeioMzOTu3q1cP16cWrKwz+gNbQmrcE50lQniSaC54lcjuMrjOEXOh25vj5YXu6tr/f3
+9pJmM0sSbdssnxeXL/u/+7vhD39YqlRsnJ7nz+O1tf6DB91nz4b7+0mvp3BsDMgBc8AVYAZwAQvg
+OJs8KT9aXv6z1dUfr6+zKGowpnM5VS7HFy50Jyb65XJSLiflcgLDMIzTQASlKI71vXudTz5pLi11
+lCKtwTnGx91Ll/I/+EFpdjZXrTqex/HrpKSNjcHKSu/zz1s7O3G/r5RCEFjVqjM7m7txo3jxoj8x
+4eIrRBgM1MFB+uzZsF7vrK31X71KGAPnzHX5Bx+U/vAPK9evFzkH+xKOwfd9z/Nc1xVCqK9wzm3b
+JiIppdaa/5KUMkkS6yucc6VUmqbDodzelru72fb28MWLXrudOI5VKrmcs3Y7SVOVy1m5nC0E7/fT
+nZ1upeIFgWvbIknk3l7v+fNOmqo4lnEswQEHqALvAPNAFeA4yxyl/peNjfdfvmRR1GBMe56qVOK5
+uc7ERL9cTsrlJAhSGIZhnBIiENHycu/mzebNm61eTyoFpSgM7VrNnZry5ubyFy/mL1zIuS4jAucM
+ABEdHmZ37rQfPOg+ezZsNrMk0UqRZTHft4LAWljw3323ePVqoVKxGYMQbH19sLbWX1vrr6/39/ZS
+pci2WRBYlYp9+bJ/40awsOAXixa+PiFELpcrFAqVSiUMw0KhQERSSsaYbduMMaWUlBKAEMJxHCll
+lmUAGGOWZQkh4jiRUgOcMcY5PzwcDofS86ww9CyLHR4O4lgRURC44+P+3l6/10sZg22LUslNU/Xz
+n29+/vnO3bsvnzxpNJtxmimUgSngIlADAsDDWTbfbP6nlZUPl5dZFDUY056nRkeH09O96eluuZyU
+y4nvZzAMwzhVg4FqNLKDg3RvL3nypP/06WBvL1WKpKTXhGAAiMAY/n9KEeeMMTAGxpjn8bExx7J4
+lulORzYaKeeMCESgL4FzxjmEYJwDYNPT3vR07p13/CtX/PPnc4zhFElJL17ET57079/vbm0N9/fT
+fl/heBjAAA7MAVeAi4APCIDhbBoZDv/V06f/eWlprtlkUdRgTHueGh0dzs52Jif7o6NxuZx4noRh
+GMZbgwhEYAxHR9lgoLJMd7sqy7TriqOjNE21ZbGJCXd01AHAObNtZtvc8zi+ojUB4JylqU5TUoqE
+YPm8AEgpKEWMwXU53iZEJCXdudO+ebO9tNTp9VSSaBybAAKgBswA54EK4OFs4kTnut0/efbsXz57
+dpDPsyhqMKY9T1Wrw5mZzvR0b3Q0DsPYcTQMwzCM05NlutHItrfj27fbq6u9nZ0kyzSOhwEcEMA8
+cAW4BLgABzjOLE/KP19d/XB5mUVRgzHteapaHc7OdmZmuiMjw3I5EYJgGIbx3aQUCcHwFSJkmQbg
+OByAUsS+hNcYw9tMa9rfT1dWel980Vpa6qQpKUVa45gsoAiMArPANFAFXJxlf7S19RePHv356iqL
+ogZj5HlyfHwwO9uZnu6NjAxHR2MYhmG8ZbSmdlseHWVHR1mvpzqdrNHIGo10by/Z2hoKwThnRNAa
+WaY5ZwCISCkCwBgDQATGwDlesyxGBK3h+8JxuNZUqdjz8/nJSS8IrDC0Jia88XEHp4QISaI7Hbm3
+l9y501la6jx7NtSacBIucAG4CFwEKjjL8ln2+8+f/5e7d3+8vs6iqMEYOY6q1QYzM525ufboaFwu
+JzAMw3g7HB1lGxuDR4/69+93nj0bEuEXiFAqiZERx/eF43AhWLlsVavOxIRXKllxrJUi1+VBYJXL
+dhzrblcKgXLZHgxUv685x3Co223Z66leT+7sDB896r18mRCBCJ7Hq1VnZib3zjuFubn8xIRbLtt4
+4w4O0pWV7u3b7adPh61WNhxqrQnHw4ASMAlcAmpACfAAhrPJk/Kdg4N/v7Z2/dUrFkUNxshxVK02
+mJ9vz821R0fjIEhhGIbxFnj5Mllb69frnWfPhoeHab+vGEOt5l65UrhxI7hyxQ9Dy/M4TiBN9WCg
+9/eT1dV+vd7Z3h4OBipJ6LVazb182X/vveDq1UKpZFsWYwxvBhHiWPd68uXL5LPPmg8f9nZ2kjTV
+OB4GWIAHlIFrwDQwBgiccX+0tfVHW1ssihqMkeOoc+f6s7OdS5dao6Ox72cwDMN4C2hNu7vJkyf9
+9fXB8+fx3l5ydJSlqeYcnLMgsGZnc6WSLQSzLDYyYgeBlaY6y0hrEoK91uvJTkcBsG1GhGYz292N
+BwPlulxrJInudCQRiEhrKEWFgjUyYk9OenNzufl5v1ZzwtDO5wXnePM6HXn3buf+/e69e51WK5OS
+cBIuMA9cAmaBAmDhjPOk/IvVVRZFDcbIcVSt1p+f71y61BofH3qehGEYxtvn1avk6Cjr91W7LV+9
+Sra24t3dOMuIMXS7UikighCMMbymNThHLieUonZbWhar1dxcTnCOONZhaNVq7tSUF4aW63Lb5sWi
+VS7bYWjh7ZBl1Gplm5vDxcX2o0e9ly+TONY4Ng4UgQngEjAFlAAXYDizbuzt/Xh9faLbZVHUYIxs
+W01O9mdnOwsLzbGxgeNoGIZhfAcRgTF8PxBRr6cePuzdvdup1zu7uwlOQgBFYBS4BJwHxgALZ9x4
+v/8fHz5kUdRgjGxbTU725+baV682R0aGjqNhGIZhnLa9veTx4/6dO+179zr9vlKKtMYxWYALnAMW
+gFmgBHCA4WwqpOn7L1/+x5WVWq/HoqjBGNm2mprqzc52rlxpTUz0hSAYhmEYp0opajSyJ0/6Dx50
+Hz7s7+8n/b7CsTHAB84D88A0UAQ8gOEsm+p0/vTxYxZFDcbIttXUVG92tnP16tHExACGYRjGW+Do
+KFtd7dXrnaWl7u5ugpMQQBGoAbPAeWAEcHFmWVq/c3j4v62t/dW9eyyKGoyRbaupqd7sbOfataNa
+bQDDMAzjLXB4mD561Lt3r/PZZ63hUNOXcEw2kAdGgCvANDACODizLK3/+fb2f3j4sBTHLIoajJFl
+6fPnu3NznStXmpOTfRiGYRinTWs6PMxWV3uLi+3797vdrpKStCYcAwM4YAMV4F3gAlAFHJxlM63W
+j9fX/836OouiBmNk22pqqnfxYnthoVmrDWAYhmGcNimp25Wrq/3FxfbDh73DwzRJNBGOgwEM4MAU
+cAWYBmqAwBl38ejoL1ZXWRQ1GCPbVlNTvbm5ztWrR7XaAIZhGMapIoJSlGW0utq7dau1vNx9+TLJ
+MsLxMIABHJgBLgMzQBVgOON+//nz//XJExZFDcbIttXUVO/ixfbCQrNWG8AwDMM4VURQiqSkhw97
+n3/eevSot7UVa004NgZwYBa4BFwAajjjJjudP97a+r/u3WNR1GCMLEufP9+dm+tcvXpUqw1gGIZh
+nCoiKEVS0uPH/U8/ba6u9nZ3kyTRODYGcGAauAxcACYAhjPuj7e2/vX6OouiBmNk22p6ujs317l8
+uXXuXB+GYRjGaZOSms1sfX1w5077wYPu0VGWJJoIx8EABghgErgCzAJVQOCMu3h09BerqyyKGoyR
+baupqd7cXOfataPx8QEMwzCM06Y17e+na2v9xcX23bud4VBLSVoTjoEBAnCAKvAOcAEYBWycZf9u
+be2Hu7uvfJ9FUYMxsm01NdWbm+tcu3Y0Pj6AYRiG8RZoNrNHj/qLi61PPmmmKWlNRDgmC8gBVeAi
+cAEYBVycZf98e/vPVlfLwyGLogZjZFn6/Pnu3FxnYaF57lwfhmEYxlug2czW1weLi+3797svXsQ4
+CQEUgXFgHpgCKoCHM8vW+lKj8aePH//VvXssihqMkeOoycne3Fzn2rWj8fEBDMMwjNOmFO3vp2tr
+/Tt3Oo8e9dptORwqHBsDisAUcAm4APiAAzCcTf9sb+/PHj/+q3v3YstiUdRgjBxHTU725uY6CwvN
+8fGBEATDMAzjtO3vp48e9e7c6SwutuNYKUVa45gswAEmgcvAPFACOMBwNhXS9P2XL//P+/fLwyGL
+ogZj5DhqcrI3N9dZWGhWq0Pb1jAMw3ibSElJotNUd7tqMFCex8PQbrUyIvi+GBtz8H3U6cjV1f7i
+Yvv+/e7OToyTEEABqAKzwCxQBWycTZ6UH+zs/Oelpf969+7/u7DAoqjBGNm2mprqzc11FhaalUrs
+eQqGYRhvjSdP+ktL3Xv3Oru7ca+n0lQLwcLQHhlxajXn6tXCpUv+7GxOCIZj0ZoajazTkYOBOjxM
+tYbr8okJt1y2lSIhWKEgHIfjzUoS3Wpla2v9e/c6q6v9/f00STSOjQMlYBKYB6aAEmADDGeT0Pra
+wcH//uhReThkUdRgjGxbTU725+fbly61RkbifF7CMAzjtBFBSnr8uH/rVuvWrVanI7UmreH74sKF
+3LVrhfffDyYmXM8Tts3wK4hARDs7yeeft+7caa+vD6SkkRHbcfi1a8Xr14sLC34QWJbFhGBEiGPd
+aKRbW8Olpe7Dh72dnZgIjCEIrOvXi++/X7pyxZ+YcPHG9fvq9u323bvt+/e7rZZUinASHjAHXATm
+gQIgcDZZWr9zcPCvnz79v7/4ol6rsShqMEauK8+d68/Ndebn29XqMJ+XMAzDeAvs76cbG4MHD7ob
+G4OXL5N2WxKhXLanpryFBf/GjWBy0gtDC7+OCM+eDT/7rHn3bufFi1gpUoqEwNSU9+67xR/9KBwb
+c4tF4XmCMbxGhFevkrt3OzdvttbX+1KSUsQYm5z0Ll/2f/jD0vx8rlSybJszhjcmSXS/r168iG/d
+aq2sdF+8SNJU43gYYAEeEADXgFlgDBA4myyt/+XGxkfLy3++ulqv1VgUNRgj11W1Wv/ixfb8fLtS
+iYvFDIZhGG+Hfl/t7SWPH/cXF9srKz2tSSnSGkqR43DHYZwzIgiBILC0Rrst41gRQWtiX4JSxBg4
+Z68BKBREGFpBYBEhjnWSaCJIqTsdORwqzhnnrFi0Ll3y3323cP16sVy283lh2wxv3OFhurLSW1zs
+rK312+1sONRaE46HAWVgCrgEjANFwAMYzqaclFcPDv7948cf7OywKGowRq6rarX+3Fxnbq5dqSRh
+mMAwDOMtozUNBnowUIOBAjAYqJ2deG8vaTazXk8VCpbn8STRRDQ15U1P54LAsm1eKlmFguj3Vacj
+m80sSfThYbq3lx4cpIeH6XCoKhUnnxcAbJtdvJi/dCk/NuYKwXI5nssJnBIiDIfq6Ch78SK+c6f9
+8GH/xYtYa8JJ5IEZ4CIwC5Rxlvlp+ofb2z9ZWnrv5UsWRQ3GyHXVuXO9Cxe6MzOdkZGkUolhGIZh
+nCql6PAwW1rqLC6279/vpikppbXGMdlAANSAOeAcUAFcnGUf7Oz8h4cPPSlZFDUYI9dVtVp/drYz
+Pd2tVJJKJRaCYBiGYZyeLKNmM9vYGCwtdR496m9vD7OMcDwM4IAFXACuAAuAAwiA42yylfrjra3f
+3dmJhWBR1GCMPE+Ojw8uXOjOzHRKpXRkJLZtDcMwjLfGcKiUAufY3h7u7CS9noxjfXCQbm0NXVdw
+jjTVcazTVDsOd10uJTWb2WCgzp1zfd8SAkmiWy05MmLXam6t5gaBVSgIAPm8CAJrZMQplSy8TYhA
+hE8/bd6+3bp7tzMYqCwjHJsFlIBzwCxwDqgADs4mTnS+3f6D58//3draQT7PoqjBGHmerFaH8/Pt
+ycl+GCaVSux5CoZhGKeq0Ujv3++urvafP4+7XXl4mA4GSgjGGGybOw5XijhntZqTywkAWUZCMM/j
+jsOyjLpdKQQLQ0sI1u3Ko6Os0Uh933IcrhT1+6rfV5xDKdCXYFlsfNydnvYWFgpXrviXLuU5Zzg9
+UtL2dvzoUW9pqbOzkxwcpMOhwvEwgAMCuAC8C8wABYADDGfT6GDwR1tb/+Xu3epgwKKoAVAuJ8fH
+B9PT3cnJfhgmIyNxPi9hGIZxGpSiONa9nnz4sHf7dntpqTscKgCMsUuX8u+/X3r//WB83HVdLgRj
+DMemNY6O0s3N4epqf2mps7ubxLHmHL4vKhV7fj7/wQfhwoJfLFr4+oQQnucVi8VyuVwqlYrFotZa
+KcU5tyyLMSalVEoBsCzLcRwpZZqmRMQ5t22bcz4YxFJqrZll8deOjpJuN/E8e3Q0LwQ7OBi02zFj
+rFz2JiaKr1712u2EiBxHlEoeEf3t3279/Oebd+7sbm62Op0kyzRGgAvAJaAKFAAPZ9lMq/V/LC9f
+39tjUdQAKJeT1epwZqYzMTEIw6RSiYvFDIZhGKeBCERQilZX+4uL7ZWV7tFR1u3KJNGuy6tVZ3o6
+V6061aozOuoQkW1z3xdBYFWrjmWxdltKSZbFcjluWUwp6nSkUsjluJTU7ao01a1W1mxmnY5sNrOt
+reHjx32toTUxhnLZrladyUnvyhX/nXcKMzM5HBdjLJ/P53I513Udx0nTVCnFObcsC4CUUmvNGBNC
+MMaklEmS2LbtOI4QQms9HA6lpK2t7PnzdHc33tsbtlqx44gw9IjQ6SRJIi2L5/O264puN93d7YRh
+Lp+3LYv6u+//AAAPCUlEQVRLqV+96j171pJSD4dyOMwgABcYBxaAC8A4wHA2hXH8p48f/9W9ewuH
+h//Pu++yKGoAlMvJanU4M9OZmBiEYVIsZqVSIgTBMAzj9BAhy/RgoI+Oslevkp2d+OAgPTxMOx3Z
+7apORyaJJgJAWoMIWhPnjHO8pjWICABjYIzhlxiDEEwIBsC2ebEoPI+HoT0/n794MT8yYnueqFRs
+3xd4C2xvD5eXe3futHd2klYr6/cVjocBDHCBi8A1YBqwAQFwnFn/7c6di43GVhiyKGoAlM/LSiW+
+cKEzMTEIw6RYzMIwsW0NwzCMt5iUpDVxzoQAY0wp6vUUERyHOw57TUqdppox5rrcthkApYgxsC/h
+LTccqr29dHNz+OBBd22tv7MTS0k4NgZUgUlgDqgBJcDBmVUZDj/Y2fm9Fy8yIVgUNQDK5+Xo6PDC
+hU61GpdKSbGYhWHieQqGYRjGKZGSOh25vj5YXGzX651XrxKtcXwOkAeKwAIwB0zgLAvj+KPl5Q+X
+lxcOD1kUNQDK5+Xo6PD8+e7oaByGSbGYhWGSz0sYhmG8fYjwGmNQiqQkIiSJVop8XxwdZc1mlqaa
+Mea6nHMcHWX9vgIQBJbrctvmnY7UmiyLBYE1MeEGgaU1iPAaY2AMjOHUEUFrUooWF9uffdb64ou2
+lFpKIsIxccABLgBXgMuADzCcTa6U883mH29tRa9ebYYhi6IGQPm8rFTiqanu+PiwWMyKxbRYzMIw
+gWEYxlsgSbRS1Oup+/e7q6u958/j4VC127LfV0TQmrTGa1oT5+CcARCCMQaliAivEcF1OWPIMnoN
+ABGIQAT6EhgDY8y2meOwctl+993itWuFqSlvdNQpFATnDG8WEbSmdlvevdv++OPmo0e9LCOliAjH
+VwAuAe8AE4AL2ADDmfXj9fUPl5c/Wl5mUdQAKJ+XlUo8NdUdHY2LxSwI0mIxKxZT29YwDMM4JWmq
+Ox15dJStrPRWVrqrq/0sI60JwOSkV6u55bI9MeFOTXm1mmvbrFCwOIfWZNvcshi+QgQiYl/CLxCB
+CJzjF7Sm4VBvbg4fPerV693NzUG/rxiD6/LZ2fyNG8UbN4LJSS+X45wzvFm7u/H9+93btzvb28NW
+K4tjjZMYBaaBeWAMCAAXZ9afr65+uLz80fLyf79xg0VRA6B8Xo6MDCcn+5VKXCxmxWJaLGbFYup5
+CoZhGKckSfTLl8mTJ/2Vld7GxmB/P80ysm3mefzyZf9HPyp/8EHJdbkQjDH8VkT4Ba1JCAbg8DDt
+95VS9ORJ/+HD3pMngzjW3a5MEs2+hLm5/J/8SeX3f79cLtuMgTG8YTs78fJy7969zu5ufHiYdbsS
+xyaAMjABTAHngFEgh7NprN9/f3f3Tx8/lpx/Nj3NoqgBUD4vR0aGtdqgUomLxaxYTH1fFotpsZjB
+MAzj9BBBKUpTvbraf/iw9+RJ/9WrpNmUcay1Js6ZEGCMaU0AhGBCIJcTQjApiQhZptOUOIcQTCki
+AhGISGsQEfsSiOA43LLw2sxM7tw5b3TUnpjwrlzxazUXp+rZs+GjR72lpe6LF/HhYToYKBybDYTA
+ODANTAI1QOAs+/H6+k/q9Y+Wl1kUNQDy/axcjicmBqVSEgRZsZjm87JYzHw/s20NwzCMtwYRiKA1
+AVCKdneTw8N0fz9tNjOliDG4Lvc8AVCWUZpqKSkIrGrVLRREHGshkM+LXI6Pjjquy9OUHIfZNgfA
+GN42z54NHj3q37/f3dmJDw7Sfl/h2FwgAEaBC8AMUMNZdmNv78Pl5b+s11dHR1kUNQDy/axcjmu1
+QRgmvi/zeRkEaT4vi8XU8xQMwzCM07C9PVxZ6d2/393ZiV+9SgcDhWNzAB8oAxeBOaCGM8uT8i/r
+9Q+XlxcOD//7jRssihoA+X5WLidjY4MwTPJ56fuyWEzzeen7WT4vhSAYhmEYb9zOTry01F1a6u7s
+xEdHWbcrcWw2UARCYB6YASZxZuWz7Mrh4R88fz7bbD4vlVgUNQDy/axcTsbGBsVi5vtZPi99P8vn
+ZbGY+X5m2xqGYRjGm0WEw8N0cbH9xRftzc1htyuTROPYXCAARoHzwAxwDmdWIU0vNRq/9+JFrdc7
+8H0WRQ2AfD+rVOJKJQ6CLJ/PfF/m89L3s3xe+n6Wz0sYhmEYb1yW0a1brU8+OVpZ6cWxzjKtNY7J
+AkaAMWAKOAfUABtnU07K2Wbz9168ON/pDGybRVEDIN/PKpW4Uol9X+bzme/LfF56nvR9mc9L389s
+W8MwDMN4U4ggJSWJfvKk/8knzVu3Wt2uJMKJVIEacB6oASOAjzNrZDj8g+3t916+tJViUdQAyPez
+SiUeGYldV/l+ls9Lz1O+n+Xz0vOU72euq4QgGIZhGG/KYKCazWxvL7l7t1Ovd7e3hzihIjAPXAZG
+gQKQx1n2ey9e/Hh9/Xy7zaKoAZDvZ5VKPDISu67yPOV50vel6yrfzzxP5fPS86TnKRiGYRhvitb0
+7NlwfX2wttbf3Bw+fx4PhwrHxgAOXAauAvMEm8ECGP6/9uCmOYrrCgPwe+6Z03NL3YKZHkjkDz4q
+OA52aKcXWmTpRRap/IFsUpnZxT8p7NAm2WaZDVUpjMuyDOaCWaQQxoLC2MIaaxDDTM9033tCRNlF
+iF0VI8hm7vMsoN/cuvWHa9d+e/PmX8+cWStLKoohoGla53mV51WSBGt9u92kaWOtt7ax1i8tNdY2
+1nqRgCiKouj/ZTSqL1/e29gY3blTjUb1o0deFc9JgDbQAd4G3gK6WFind3Z+t7n5R+euraz8pSio
+KIaAZlnd7VZ5XjGrtd7axlpvrW+3fZrW1nprvbVNu+2ZFVEURdFLpgrvdTYLt25N3n9/94MPdsdj
+r/+G59QCusAR4BXgOPA60MJiWhmPB879/vp1AGtlSUUxBDTL6jyvut2KWUWCtd7axlpvrbe2sda3
+295ab20jEpgVURRF0Us2m4W7d6vbt6c3bkw2Nx999tnEe8VBHAJOAT8DfgpkwBIW1rtbW33nBs6d
+K0sqiiGgWVbneZXnFZG2Wmqtb7ebJAnW+nbbW9skSWi3vbXe2sZajyiKoujl29trNjYerK/vfv75
+dDz206lXxXNqAQIcBX4JvA1kAGFh2aYZONd3rlNVVBRDQLOszvMqzysiEKm1XiRY24gEa721XsRb
+60WCtd7aRiQwK6IoiqKXpqrCeNwMh/X6+ujjjx/cvj3FQRggB44CrwDHgNeABItp4FzfuZOj0VpZ
+nitLKoohoFlW53mV5xURiJRZrfUi3lovEqz1IkHEW+tFgrU+SXy77ZkVURRF0Utz797s2rW9K1f2
+vvpqvrMz39trcBAEvAm8DZwCBBDAYAHZphk413euU1VrZUlFMQQ0y+o8r/K8IgKgRBAJ1noRnyRB
+JFjrRYKIt9aLhCQJIt5aLxIQRVEUvQSTiR+P/ZdfztbXRxsbo/v35zgIAbpADrwOHAeOY5HZphk4
+13euU1VUFENAs6zO8yrPKwBEIFJmFQkiQcQnSRAJ1nqRIOKTJIgEkSASksSLBJGAKIqi6EXb3p5f
+vbrn3N69e7OdnfmDBw0O6DTwFnACsEACGCygd7e2+s4NnDtXlmtlSUUxBDTL6m63yvMZkRIBUCKI
+BGYVCSI+SYJIEAkiIUm8SBAJIiFJgohnVpEgEhBFURS9INOp391tdnbmly/vffLJg62tKQ6CgRw4
+ArwKHAeOAQYL6/TOTt+5gXNuZYWKYgholtXdbpXnMyIFQARAiSASmFUkiPgkCcZokgSRIBKYg0gQ
+CSKBWUVCkniRYIwyK6IoiqIX4eLF3YsXd69ff1hVYT4PqnhOBJDiBPAOoQAMQABhAb27tdV3buDc
+n1dX18qSimIIaJrWeT7L8woAkQIgAqBEEAnMKhKYg0hgVpEgEphVJDAHkcCsIkEkMKuIZ1aRYIwy
+K6IoiqLntbU1vXHj0c2bk62t6e3b08nE4yB6wDHgBJADPSDDwupU1XuXLvWdG1lLRTEENE3rPJ/l
+eQWASLGPCIASgVmN0SQJxqiIZ1ZmFQnMKhKMUWYV8cwqEpjVGE2SYIwmiTdGmVUkIIqiKPoxqio8
+fNgMh/X6+mh9ffTFFxUOQoAMyIBTwM+B17CwVsbjgXN950bWnl1dpaIYApqmdZ7Put2KCI8RKfYR
+AVAiPMasIoFZjVHmIBKY1RhlVmYVCcYoszIHkcCsxiizGqNJEoxR5sCsIsEYZVZEURRF/4MPPxxd
+uPDNlSsPmybM50EVB6A4AbxD+BVgAAIIi6ZTVQPn+s4BOLu6eq4sqSiGgKZp3e3O8rwiwhNEin1E
+2KdEeIxZjVFmZVZjlDkYo8zKrCKBWY1RZjVGmZU5GKPMyqzGKLMao8zabvsk8a2WGqPGKKIoiqLv
+s709v3LlwdWrD7e3519/PRuNGhxEBpwC3gRyYBnIsLBOjkYD5/rO/fPIESqKIaBpWvd6VaczA0CE
+7xAp9hHhW0qEx5jVGGVWZgVgjDIHY5RZmdUYZVYAzGqMMqsxyqzMgVmt9UtLjbWNSGi1AhGiKIqi
+Z4Sgd+5Ud+5MNzcnm5uPNjcn83nAQRwFfgK8CrwKvAJYLKyBc33nVsbjtbKkohgCmqZ1r1d1OjN8
+iwjfIVI8hQj7FAARnmBWYxQAszKrMQqAORijAJiVWQEYo62WHjo0X16ep2ljbdNueyJEURRFz5hM
+/HBY378/+/TT8dWrezdvTnAQCXAYOAwcA94AXsPC+vXdu33nBs797fTps6urVBRDQNO06fWmhw/P
+iRRPIcIziBT/iQhPUQBEeIJZARijAJgVALMaE3q9WaczO3RonqbN0lJNhCiKougZk4nf2/Pb27ON
+jdFHHz3Y3p7hINrAEnAYeBP4BdDDwho413fu5Gh0dnX1XFlSUQwBTdMmz6tOZ4Z9RIrvQ4QfQqT4
+AUR4WqsVer2q16u63dnycp1lcyJEURRFz6hrnc/DrVvTCxe+uXDhm8nE4yBaQAs4CpwBzgApFtPK
+ePzepUt957Y6nbWyPFeWVBRDAGla53nV6czwA4gUPxIRvhdzOHq0OnJk2u3OlpfrLJsTIYqiKPpv
+qnr9+vj8+eH580O8AIrXgZJQAi0sptM7O3+6dGng3D9Onjy7uvr3N974FwUliUp8E0kQAAAAAElF
+TkSuQmCC
+"
+       preserveAspectRatio="none"
+       height="440"
+       width="600" />
+    <use
+       x="0"
+       y="0"
+       xlink:href="#polar_remap_src"
+       id="use4927"
+       transform="translate(659.00006,-1.2939453e-6)"
+       width="100%"
+       height="100%" />
+    <path
+       style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#0000ff;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker-end:url(#marker11066)"
+       d="m 2075.7211,-60.709552 195.9396,0 0,0"
+       id="path4352-5"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:none;fill-opacity:1;stroke:#ffff00;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker-start:url(#marker10956);marker-end:url(#marker10166)"
+       id="path5297"
+       sodipodi:type="arc"
+       sodipodi:cx="2052.2896"
+       sodipodi:cy="-60.709564"
+       sodipodi:rx="89.723862"
+       sodipodi:ry="80.153481"
+       sodipodi:start="0"
+       sodipodi:end="1.0471976"
+       d="M 2142.0134,-60.709564 A 89.723862,80.153481 0 0 1 2097.1515,8.7053881"
+       sodipodi:open="true" />
+    <path
+       style="fill:none;fill-rule:evenodd;stroke:#ff00ff;stroke-width:0.99999988px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#marker11223)"
+       d="m 2054.2975,-60.708232 49.9936,86.598216"
+       id="path4279"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cc" />
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-weight:normal;font-size:10px;line-height:125%;font-family:sans-serif;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;"
+       id="text5222"
+       sodipodi:linespacing="125%"
+       transform="translate(-2,-2)"
+       x="1.3096769e-006"
+       y="0"><textPath
+         xlink:href="#path4277"
+         startOffset="50%"
+         id="textPath5236"
+         style="font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:15px;font-family:serif;-inkscape-font-specification:'serif Italic';text-align:center;text-anchor:middle;fill:#000000;">maxRadius</textPath></text>
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-weight:normal;font-size:10px;line-height:0%;font-family:sans-serif;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#ffff00;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       id="text5267"
+       sodipodi:linespacing="0%"
+       y="-21.652691"
+       x="2161.561"><tspan
+         style="font-size:15px;-inkscape-font-specification:'serif Italic';font-family:serif;font-weight:normal;font-style:italic;font-stretch:normal;font-variant:normal"
+         id="tspan4872">angle</tspan><tspan
+         style="-inkscape-font-specification:'serif Italic';font-family:serif;font-weight:normal;font-style:italic;font-stretch:normal;font-variant:normal;font-size:15px"
+         id="tspan4874">°</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10px;line-height:125%;font-family:serif;-inkscape-font-specification:serif;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#ff00ff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;"
+       id="text5322"
+       sodipodi:linespacing="125%"
+       transform="translate(-10,10)"><textPath
+         xlink:href="#path4279"
+         startOffset="50%"
+         id="textPath4864"
+         style="font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:15px;font-family:serif;-inkscape-font-specification:'serif Italic';fill:#ff00ff;">magnitude </textPath></text>
+    <path
+       style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#Arrow1Lend);stroke-miterlimit:4;stroke-dasharray:none"
+       d="M 2054.2806,-60.700192 2208.1961,-227.89023"
+       id="path4277"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cc"
+       inkscape:transform-center-x="-77.328882"
+       inkscape:transform-center-y="-83.926236" />
+    <path
+       style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#marker6597);marker-end:url(#marker11655)"
+       d="m 2055.3089,-83.560619 48.2906,0"
+       id="path8626"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#marker9222);marker-end:url(#marker9089)"
+       d="m 2025.6066,-59.71359 0,85.560965"
+       id="path8628"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:0.99999998, 2.99999997;stroke-dashoffset:0;stroke-opacity:1"
+       d="m 2104.7011,-91.628465 0,142.297108"
+       id="path9373"
+       inkscape:connector-curvature="0" />
+    <path
+       style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:1.00000004, 3.00000012;stroke-dashoffset:0;stroke-opacity:1"
+       d="m 2014.2525,26.966205 109.6793,0"
+       id="path9375"
+       inkscape:connector-curvature="0" />
+    <text
+       xml:space="preserve"
+       style="font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10px;line-height:125%;font-family:serif;-inkscape-font-specification:'serif Italic';text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       id="text10553"
+       sodipodi:linespacing="125%"
+       y="2"
+       transform="translate(0,4)"><textPath
+         xlink:href="#path8626"
+         startOffset="50%"
+         id="textPath10573"><tspan
+   id="tspan10555"
+   style="font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:15px;font-family:serif;-inkscape-font-specification:'serif Italic'"
+   dy="10">dx</tspan></textPath></text>
+    <text
+       xml:space="preserve"
+       style="font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10px;line-height:125%;font-family:serif;-inkscape-font-specification:'serif Italic';text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       id="text10557"
+       sodipodi:linespacing="125%"
+       x="2"
+       transform="translate(4,0)"><textPath
+         xlink:href="#path8628"
+         startOffset="50%"
+         id="textPath10600"><tspan
+   id="tspan10559"
+   style="font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:15px;font-family:serif;-inkscape-font-specification:'serif Italic'"
+   dy="-3">dy</tspan></textPath></text>
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-weight:normal;font-size:17.4700737px;line-height:125%;font-family:sans-serif;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="2005.4854"
+       y="-102.5746"
+       id="text12420"
+       sodipodi:linespacing="125%"
+       transform="scale(1.001713,0.99828992)"><tspan
+         sodipodi:role="line"
+         id="tspan12422"
+         x="2005.4854"
+         y="-102.5746"
+         style="font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:15px;font-family:serif;-inkscape-font-specification:'serif Italic';fill:#000000;fill-opacity:1">center</tspan><tspan
+         sodipodi:role="line"
+         x="2005.4854"
+         y="-83.8246"
+         style="font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:15px;font-family:serif;-inkscape-font-specification:'serif Italic';fill:#000000;fill-opacity:1"
+         id="tspan11403">C(x<tspan
+   style="font-size:15px;baseline-shift:sub;fill:#000000"
+   id="tspan14204">c</tspan> , y<tspan
+   style="font-size:15px;baseline-shift:sub;fill:#000000"
+   id="tspan14202">c</tspan>)</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-weight:normal;font-size:17.4700737px;line-height:125%;font-family:sans-serif;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#0000ff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="2142.4895"
+       y="42.887527"
+       id="text12420-7"
+       sodipodi:linespacing="125%"
+       transform="scale(1.001713,0.99828992)"><tspan
+         sodipodi:role="line"
+         x="2142.4895"
+         y="42.887527"
+         id="tspan12424-9"
+         style="font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:15px;font-family:serif;-inkscape-font-specification:'serif Italic';fill:#0000ff;fill-opacity:1">A(x<tspan
+   style="font-size:64.99999762%;baseline-shift:sub"
+   id="tspan25243">A</tspan> , y<tspan
+   style="font-size:64.99999762%;baseline-shift:sub"
+   id="tspan25241">A</tspan>)</tspan></text>
+    <path
+       style="display:inline;opacity:1;fill:url(#Checkerboard);fill-opacity:1.0;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+       d="m 1814.2898,-280.70953 0,440 173.1368,0 A 230,230 0 0 1 1843.4344,31.157655 230,230 0 0 1 1962.4226,-271.565 a 230,230 0 0 1 25.3516,-9.14453 l -173.4844,0 z m 306.8594,0 a 230,230 0 0 1 143.9981,128.13281 230,230 0 0 1 -118.9903,302.72461 230,230 0 0 1 -25.3515,9.14258 l 293.4863,0 0,-440 -293.1426,0 z"
+       id="rect9164-5"
+       inkscape:connector-curvature="0" />
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-weight:normal;font-size:17.5px;line-height:125%;font-family:sans-serif;text-align:center;letter-spacing:5px;word-spacing:0px;text-anchor:middle;display:inline;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;"
+       id="text23583"
+       sodipodi:linespacing="125%"><textPath
+         xlink:href="#path5214"
+         startOffset="50%"
+         id="textPath8771"
+         dy="-5"
+         style="-inkscape-font-specification:'serif Italic';font-family:serif;font-weight:normal;font-style:italic;font-stretch:normal;font-variant:normal;stroke:#ffffff;stroke-opacity:1;">BOUNDING CIRCLE</textPath></text>
+    <g
+       style="display:inline"
+       id="g12095"
+       transform="translate(599.73005,-127.36705)">
+      <path
+         inkscape:connector-curvature="0"
+         id="path12562"
+         d="m 1439.5597,66.657525 30,0"
+         style="display:inline;fill:none;fill-rule:evenodd;stroke:#0000ff;stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1" />
+      <path
+         inkscape:connector-curvature="0"
+         id="path12564"
+         d="m 1454.5597,51.708765 0,29.8975"
+         style="display:inline;fill:none;fill-rule:evenodd;stroke:#0000ff;stroke-width:0.99999988px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1" />
+    </g>
+    <rect
+       style="display:inline;opacity:1;fill:#aaccff;fill-opacity:1;stroke:none;stroke-width:2;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+       id="rect5347"
+       width="600"
+       height="30"
+       x="876.90057"
+       y="-220.60022"
+       transform="translate(278.38913,379.89069)" />
+    <text
+       transform="translate(278.38913,379.89069)"
+       xml:space="preserve"
+       style="font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:20px;line-height:125%;font-family:serif;-inkscape-font-specification:'serif Italic';text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;display:inline;fill:#0000ff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="1177.0618"
+       y="-200.22424"
+       id="text10597-7-0"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan10599-7-1"
+         x="1177.0618"
+         y="-200.22424">a) Source Image</tspan></text>
+    <path
+       transform="translate(278.38913,379.89069)"
+       style="display:inline;fill:#000000;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999988px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#marker9767);marker-end:url(#marker10065)"
+       d="m 876.90056,-146.6002 600.00004,0"
+       id="path4277-3"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cc" />
+    <text
+       xml:space="preserve"
+       style="font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:17.5px;line-height:125%;font-family:serif;-inkscape-font-specification:'serif Italic';text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       id="text6291"
+       sodipodi:linespacing="125%"
+       y="-2"
+       transform="translate(0,-4)"><textPath
+         xlink:href="#path4277-3"
+         startOffset="50%"
+         id="textPath8906">ρ: 0 .. Kx * maxRadius = src.cols</textPath></text>
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-weight:normal;font-size:17.4700737px;line-height:125%;font-family:sans-serif;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;display:inline;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="1863.2867"
+       y="268.28613"
+       id="text12420-4-5"
+       sodipodi:linespacing="125%"
+       transform="scale(1.001713,0.99828992)"><tspan
+         sodipodi:role="line"
+         id="tspan12422-9-8"
+         x="1863.2867"
+         y="268.28613"
+         style="font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:15px;font-family:serif;-inkscape-font-specification:'serif Italic';fill:#ffffff;fill-opacity:1">center</tspan><tspan
+         sodipodi:role="line"
+         x="1863.2867"
+         y="287.03613"
+         id="tspan12424-3-8"
+         style="font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:15px;font-family:serif;-inkscape-font-specification:'serif Italic';fill:#ffffff;fill-opacity:1">C(0,0)</tspan></text>
+    <circle
+       transform="translate(278.38913,379.89069)"
+       style="display:inline;fill:#ffff00;fill-opacity:1;stroke:#ff0000;stroke-width:6;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+       id="path7812-0-0"
+       cx="1546.2402"
+       cy="-120.53497"
+       r="10" />
+    <circle
+       transform="translate(278.38913,379.89069)"
+       style="display:inline;fill:#ffff00;fill-opacity:1;stroke:#ff0000;stroke-width:6;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+       id="path7812-0-5"
+       cx="887.51678"
+       cy="-120.30492"
+       r="10" />
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-weight:normal;font-size:17.4700737px;line-height:125%;font-family:sans-serif;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="1206.5698"
+       y="268.28613"
+       id="text12420-4"
+       sodipodi:linespacing="125%"
+       transform="scale(1.001713,0.99828992)"><tspan
+         sodipodi:role="line"
+         id="tspan12422-9"
+         x="1206.5698"
+         y="268.28613"
+         style="font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:15px;font-family:serif;-inkscape-font-specification:'serif Italic';fill:#000000;fill-opacity:1">center</tspan><tspan
+         sodipodi:role="line"
+         x="1206.5698"
+         y="287.03613"
+         id="tspan12424-3"
+         style="font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:15px;font-family:serif;-inkscape-font-specification:'serif Italic';fill:#000000;fill-opacity:1">C(0,0)</tspan></text>
+    <path
+       style="display:inline;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#ff00ff;stroke-width:0.99999982px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#marker7501);marker-end:url(#marker7752)"
+       d="m 1157.0852,382.50133 257.3365,0"
+       id="path8626-1"
+       inkscape:connector-curvature="0" />
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-weight:normal;font-size:17.5px;line-height:125%;font-family:sans-serif;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;display:inline;fill:#ff00ff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;"
+       id="text11539"
+       sodipodi:linespacing="125%"
+       transform="translate(0,16)"><textPath
+         xlink:href="#path8626-1"
+         startOffset="50%"
+         id="textPath9453"
+         style="font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:serif;-inkscape-font-specification:'serif Italic';fill:#ff00ff;">ρ<tspan
+   style="font-size:64.99999762%;baseline-shift:sub;fill:#ff00ff;"
+   id="tspan25221">A</tspan> = Kx * magnitude </textPath></text>
+    <path
+       style="display:inline;fill:none;fill-rule:evenodd;stroke:#ffff00;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#marker7511);marker-end:url(#marker7969)"
+       d="m 1504.072,251.11052 0,69.70375"
+       id="path8628-4"
+       inkscape:connector-curvature="0" />
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-weight:normal;font-size:17.5px;line-height:125%;font-family:sans-serif;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;display:inline;fill:#ffff00;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       id="text11543"
+       sodipodi:linespacing="125%"
+       x="1490.2782"
+       y="290.78436"><tspan
+         style="font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:serif;-inkscape-font-specification:'serif Italic';text-align:end;text-anchor:end;fill:#ffff00"
+         id="tspan9727">ϕ<tspan
+   style="font-size:64.99999762%;baseline-shift:sub"
+   id="tspan25219">A</tspan> = Ky * angle°</tspan></text>
+    <path
+       style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:1.00000005, 3.00000014;stroke-dashoffset:0;stroke-opacity:1"
+       d="m 1416.2587,318.74619 0,75"
+       id="path9373-1"
+       inkscape:connector-curvature="0" />
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-weight:normal;font-size:17.4700737px;line-height:125%;font-family:sans-serif;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;display:inline;fill:#0000ff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="1366.0044"
+       y="345.78555"
+       id="text12420-7-4"
+       sodipodi:linespacing="125%"
+       transform="scale(1.001713,0.99828992)"><tspan
+         sodipodi:role="line"
+         x="1366.0044"
+         y="345.78555"
+         id="tspan12424-9-8"
+         style="font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:15px;font-family:serif;-inkscape-font-specification:'serif Italic';fill:#0000ff;fill-opacity:1">A(ρ<tspan
+   style="font-size:65%;baseline-shift:sub"
+   id="tspan25257">A</tspan> , ϕ<tspan
+   style="font-size:65%;baseline-shift:sub"
+   id="tspan25259">A</tspan>)</tspan></text>
+    <text
+       transform="translate(278.38913,379.89069)"
+       xml:space="preserve"
+       style="font-style:normal;font-weight:normal;font-size:17.5px;line-height:125%;font-family:sans-serif;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="1116.5338"
+       y="181.09943"
+       id="text4900"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan4902"
+         x="1116.5338"
+         y="181.09943"
+         style="font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:serif;-inkscape-font-specification:'serif Italic'">if 2 * maxRadius > min(srcSize)</tspan><tspan
+         sodipodi:role="line"
+         x="1116.5338"
+         y="202.97443"
+         id="tspan10807"
+         style="font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:serif;-inkscape-font-specification:'serif Italic'">CV_WARP_FILL_OUTLIERS</tspan></text>
+    <path
+       transform="translate(278.38913,379.89069)"
+       style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#marker5176)"
+       d="M 1201.2307,185.77462 C 1400.7343,186.636 1419.6861,151.18814 1460.3598,6.6245405"
+       id="path4904"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cc" />
+    <path
+       transform="translate(278.38913,379.89069)"
+       style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#marker4914)"
+       d="m 1201.2307,185.77462 c 175.8754,2.61724 131.5946,-18.72509 240.5838,11.16238"
+       id="path4906"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cc" />
+    <text
+       transform="translate(278.38913,379.89069)"
+       xml:space="preserve"
+       style="font-style:normal;font-weight:normal;font-size:17.5px;line-height:125%;font-family:sans-serif;text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="1720.7256"
+       y="57.31295"
+       id="text9677-6"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan9679-5"
+         x="1720.7256"
+         y="57.31295"
+         style="font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:serif;-inkscape-font-specification:'serif Italic';text-align:start;text-anchor:start;fill:#000000;stroke:none">M = src.cols / log<tspan
+   style="font-size:64.99999762%;text-align:start;baseline-shift:sub;text-anchor:start;fill:#000000;stroke:none"
+   id="tspan13237">e</tspan>(maxRadius)</tspan><tspan
+         sodipodi:role="line"
+         x="1720.7256"
+         y="79.18795"
+         style="font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:serif;-inkscape-font-specification:'serif Italic';text-align:start;text-anchor:start;fill:#000000;stroke:none"
+         id="tspan9683-0">Ky = src.rows / 360.0</tspan></text>
+    <path
+       style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:1, 3.00000004;stroke-dashoffset:0;stroke-opacity:1"
+       d="m 1470.2799,322.6235 52.0123,0"
+       id="path9375-8"
+       inkscape:connector-curvature="0" />
+    <text
+       transform="translate(278.38913,379.89069)"
+       xml:space="preserve"
+       style="font-style:normal;font-weight:normal;font-size:17.5px;line-height:125%;font-family:sans-serif;text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="972.77118"
+       y="268.11703"
+       id="text9677-2"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         x="972.77118"
+         y="268.11703"
+         style="font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:serif;-inkscape-font-specification:'serif Italic';text-align:start;text-anchor:start"
+         id="tspan9683-00">Blue cross in the center</tspan></text>
+    <path
+       transform="translate(278.38913,379.89069)"
+       style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       d="m 918.15536,298.24776 c 39.4386,-1.11634 11.6785,-37.06858 39.8288,-37.04069"
+       id="path15847"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cc" />
+    <path
+       transform="translate(278.38913,379.89069)"
+       style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       d="m 923.20346,-19.136999 c 40.2902,-7.6239 -1.9824,287.799669 34.7565,279.338899"
+       id="path15843-9"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cc" />
+    <text
+       transform="translate(278.38913,379.89069)"
+       xml:space="preserve"
+       style="font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:17.5px;line-height:125%;font-family:serif;-inkscape-font-specification:'serif Italic';text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="1875.3696"
+       y="151.86354"
+       id="text4900-6"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan4902-5"
+         x="1875.3696"
+         y="151.86354">if 2 * maxRadius > min(srcSize)</tspan><tspan
+         sodipodi:role="line"
+         x="1875.3696"
+         y="173.73854"
+         id="tspan10807-5">CV_WARP_FILL_OUTLIERS</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-weight:normal;font-size:17.5px;line-height:125%;font-family:sans-serif;text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="1965.1147"
+       y="631.5249"
+       id="text9677-2-7"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         x="1965.1147"
+         y="631.5249"
+         style="font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:serif;-inkscape-font-specification:'serif Italic';text-align:start;text-anchor:start"
+         id="tspan9683-00-3">Blue cross in the center</tspan></text>
+    <path
+       style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       d="m 1921.4596,661.65562 c 39.4386,-1.11634 11.6785,-37.06858 39.8288,-37.04069"
+       id="path15847-0"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cc" />
+    <path
+       style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       d="m 1926.5077,364.51819 c 40.2902,-7.07218 -1.9824,266.97246 34.7565,259.12397"
+       id="path15843-9-1"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cc" />
+    <rect
+       transform="translate(278.38913,379.89069)"
+       style="display:inline;opacity:1;fill:#aaccff;fill-opacity:1;stroke:none;stroke-width:2;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+       id="rect5347-0"
+       width="600"
+       height="30"
+       x="876.90057"
+       y="309.39981" />
+    <text
+       transform="translate(278.38913,379.89069)"
+       xml:space="preserve"
+       style="font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:20px;line-height:125%;font-family:serif;-inkscape-font-specification:'serif Italic';text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;display:inline;fill:#0000ff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="1177.0618"
+       y="329.77579"
+       id="text10597-7-0-4"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan10599-7-1-7"
+         x="1177.0618"
+         y="329.77579">c) linearPolar Result Image</tspan></text>
+    <rect
+       transform="translate(278.38913,379.89069)"
+       style="display:inline;opacity:1;fill:#aaccff;fill-opacity:1;stroke:none;stroke-width:2;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+       id="rect5347-7"
+       width="600"
+       height="30"
+       x="1535.9006"
+       y="309.39981" />
+    <text
+       transform="translate(278.38913,379.89069)"
+       xml:space="preserve"
+       style="font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:20px;line-height:125%;font-family:serif;-inkscape-font-specification:'serif Italic';text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;display:inline;fill:#0000ff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="1836.0618"
+       y="329.77579"
+       id="text10597-7-0-0"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan10599-7-1-2"
+         x="1836.0618"
+         y="329.77579">d) logPolar Result Image</tspan></text>
+    <path
+       style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999982px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#marker20913)"
+       d="m 2272.8428,536.87859 c 102.331,0.78706 105.3305,-23.81673 132.9146,-163.69246"
+       id="path4904-3"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cc" />
+    <path
+       style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#marker15424)"
+       d="m 2272.4917,538.063 c 90.5396,4.43657 77.1679,-15.5098 133.2749,35.15337"
+       id="path4906-7"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cc" />
+    <path
+       style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       d="m 1926.5319,474.29256 c 31.4326,-6.82905 4.5593,151.82542 34.7565,150.35839"
+       id="path15843-2"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cc" />
+    <path
+       style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       d="m 1929.4254,566.70008 c 26.9994,-6.04182 8.1996,54.30051 31.863,57.92501"
+       id="path15845-5"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cc" />
+    <path
+       style="display:inline;fill:none;fill-rule:evenodd;stroke:#ffff00;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#marker11752);marker-end:url(#marker12450)"
+       d="m 2307.6529,250.84529 0,69.96898"
+       id="path8628-4-0"
+       inkscape:connector-curvature="0" />
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-weight:normal;font-size:17.5px;line-height:125%;font-family:sans-serif;text-align:end;letter-spacing:0px;word-spacing:0px;text-anchor:end;display:inline;fill:#ffff00;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       id="text11543-1"
+       sodipodi:linespacing="125%"
+       x="2301.5044"
+       y="290.78436"><tspan
+         style="font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:serif;-inkscape-font-specification:'serif Italic';text-align:end;text-anchor:end;fill:#ffff00"
+         id="tspan9727-1">ϕ<tspan
+   style="font-size:64.99999762%;baseline-shift:sub"
+   id="tspan25233">A</tspan> = Ky * angle°</tspan></text>
+    <path
+       style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:1.00000002, 3.00000006;stroke-dashoffset:0;stroke-opacity:1"
+       d="m 2323.5966,318.86057 0,75"
+       id="path9373-1-2"
+       inkscape:connector-curvature="0" />
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-weight:normal;font-size:17.4700737px;line-height:125%;font-family:sans-serif;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;display:inline;fill:#0000ff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="2273.3022"
+       y="345.78555"
+       id="text12420-7-4-1"
+       sodipodi:linespacing="125%"
+       transform="scale(1.001713,0.99828992)"><tspan
+         sodipodi:role="line"
+         x="2273.3022"
+         y="345.78555"
+         id="tspan12424-9-8-9"
+         style="font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:15px;font-family:serif;-inkscape-font-specification:'serif Italic';fill:#0000ff;fill-opacity:1">A(ρ<tspan
+   style="font-size:64.99999762%;baseline-shift:sub"
+   id="tspan25237">A </tspan>, ϕ<tspan
+   style="font-size:64.99999762%;baseline-shift:sub"
+   id="tspan25235">A</tspan>)</tspan></text>
+    <path
+       transform="translate(278.38913,379.89069)"
+       style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       d="m 923.22766,91.795358 c 31.4326,-7.694425 4.5593,171.064642 34.7565,169.411712"
+       id="path15843"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cc" />
+    <path
+       transform="translate(278.38913,379.89069)"
+       style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       d="m 926.12116,201.06575 c 26.9994,-6.273 8.1996,56.37814 31.863,60.14132"
+       id="path15845"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cc" />
+    <text
+       transform="translate(278.38913,379.89069)"
+       xml:space="preserve"
+       style="font-style:normal;font-weight:normal;font-size:17.5px;line-height:125%;font-family:sans-serif;text-align:start;letter-spacing:0px;word-spacing:0px;text-anchor:start;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="972.38251"
+       y="57.31295"
+       id="text9677"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan9679"
+         x="972.38251"
+         y="57.31295"
+         style="font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:serif;-inkscape-font-specification:'serif Italic';text-align:start;text-anchor:start">Kx = src.cols / maxRadius</tspan><tspan
+         sodipodi:role="line"
+         x="972.38251"
+         y="79.18795"
+         style="font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:serif;-inkscape-font-specification:'serif Italic';text-align:start;text-anchor:start"
+         id="tspan9683">Ky = src.rows / 360.0</tspan></text>
+    <path
+       transform="translate(278.38913,379.89069)"
+       style="display:inline;fill:#000000;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999988px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#marker9767-4);marker-end:url(#marker10065-7)"
+       d="m 1537.7207,-146.6002 600.0001,0"
+       id="path4277-3-73"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cc" />
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-weight:normal;font-size:17.5px;line-height:125%;font-family:sans-serif;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       id="text22329"
+       sodipodi:linespacing="125%"
+       y="-2"
+       transform="translate(0,-4)"><textPath
+         xlink:href="#path4277-3-73"
+         startOffset="50%"
+         id="textPath9292"><tspan
+   style="font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:serif;-inkscape-font-specification:'serif Italic'"
+   id="tspan22331">ρ: 0 .. M * log<tspan
+   style="font-size:64.99999762%;baseline-shift:sub"
+   id="tspan22755">e</tspan>(maxRadius) = src.cols</tspan></textPath></text>
+    <path
+       transform="translate(278.38913,379.89069)"
+       style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999976;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-start:url(#marker6337-2);marker-end:url(#marker7260-0-4)"
+       d="m 1511.9006,309.3998 0,-440"
+       id="path4277-3-9"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cc" />
+    <text
+       xml:space="preserve"
+       style="font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:17.5px;line-height:125%;font-family:serif;-inkscape-font-specification:'serif Italic';text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       id="text6291-1"
+       sodipodi:linespacing="125%"
+       transform="translate(-4,0)"><textPath
+         xlink:href="#path4277-3-9"
+         startOffset="50%"
+         id="textPath9479">ϕ: 0 ..  Ky * 360 = src.rows</textPath></text>
+    <path
+       style="display:inline;fill:none;fill-rule:evenodd;stroke:#ff00ff;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#marker12092);marker-end:url(#marker12808)"
+       d="m 1816.1098,382.50168 504.579,0"
+       id="path10984"
+       inkscape:connector-curvature="0" />
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-weight:normal;font-size:17.5px;line-height:125%;font-family:sans-serif;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;display:inline;fill:#ff00ff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;"
+       id="text11543-1-5"
+       sodipodi:linespacing="125%"
+       transform="translate(0,18)"><textPath
+         xlink:href="#path10984"
+         startOffset="50%"
+         id="textPath9401"><tspan
+   id="tspan9727-1-1"
+   style="font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:serif;-inkscape-font-specification:'serif Italic';fill:#ff00ff;stroke:none;">ρ<tspan
+   style="font-size:64.99999762%;baseline-shift:sub;fill:#ff00ff;"
+   id="tspan25239">A</tspan> = M * log<tspan
+   style="font-size:64.99999762%;baseline-shift:sub;fill:#ff00ff;"
+   id="tspan13235">e</tspan>(magnitude )</tspan></textPath></text>
+    <g
+       transform="translate(-15.999847,-520.00001)"
+       style="display:inline"
+       id="polar_remap_src"
+       inkscape:label="#polar_remap_src"
+       inkscape:export-filename=".\polar_remap_src.png"
+       inkscape:export-xdpi="90"
+       inkscape:export-ydpi="90">
+      <rect
+         inkscape:export-ydpi="90"
+         inkscape:export-xdpi="90"
+         y="239.29048"
+         x="1171.2896"
+         height="440"
+         width="600"
+         id="rect4188-0"
+         style="display:inline;fill:#008080;fill-opacity:1;stroke:none;stroke-width:0.99999994;stroke-miterlimit:4;stroke-dasharray:1, 1;stroke-dashoffset:0;stroke-opacity:1" />
+      <circle
+         transform="matrix(-0.89340311,0.44925593,-0.44925593,-0.89340311,0,0)"
+         r="190"
+         cy="-1044.3617"
+         cx="-1054.5115"
+         id="path6960-7"
+         style="display:inline;fill:#b3b3b3;fill-opacity:1;stroke:#000080;stroke-width:10;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+      <g
+         transform="matrix(0.99860139,0,0,0.99931219,1.9737346,0.47152877)"
+         id="g5553">
+        <path
+           transform="translate(278.38897,379.89069)"
+           style="display:inline;fill:none;fill-rule:evenodd;stroke:#ff0000;stroke-width:3.0031333;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+           d="m 1132.9007,-113.38845 0,16.011329"
+           id="path14287-5-4"
+           inkscape:connector-curvature="0" />
+        <path
+           transform="translate(278.38897,379.89069)"
+           style="display:inline;fill:none;fill-rule:evenodd;stroke:#ffffff;stroke-width:3.0031333;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+           d="m 1036.5159,-87.580589 8.0085,13.861288"
+           id="path14287-5-6"
+           inkscape:connector-curvature="0" />
+        <path
+           transform="translate(278.38897,379.89069)"
+           style="display:inline;fill:none;fill-rule:evenodd;stroke:#ffffff;stroke-width:3.0031333;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+           d="m 965.9573,-17.072217 13.86132,7.9971585"
+           id="path14287-5-3"
+           inkscape:connector-curvature="0" />
+        <path
+           transform="translate(278.38897,379.89069)"
+           style="display:inline;fill:none;fill-rule:evenodd;stroke:#ff0000;stroke-width:3.0031333;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+           d="m 940.13108,79.244016 16,0"
+           id="path14287-5-63"
+           inkscape:connector-curvature="0" />
+        <path
+           transform="translate(278.38897,379.89069)"
+           style="display:inline;fill:none;fill-rule:evenodd;stroke:#ffffff;stroke-width:3.0031333;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+           d="m 965.95732,175.56031 13.8613,-7.99716"
+           id="path14287-5-2"
+           inkscape:connector-curvature="0" />
+        <path
+           transform="translate(278.38897,379.89069)"
+           style="display:inline;fill:none;fill-rule:evenodd;stroke:#ffffff;stroke-width:3.0031333;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+           d="m 1036.5159,246.06868 8.0085,-13.86129"
+           id="path14287-5-46"
+           inkscape:connector-curvature="0" />
+        <path
+           transform="translate(278.38897,379.89069)"
+           style="display:inline;fill:none;fill-rule:evenodd;stroke:#ff0000;stroke-width:3.0031333;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+           d="m 1132.9007,271.87654 0,-16.01133"
+           id="path14287-5-7"
+           inkscape:connector-curvature="0" />
+        <path
+           transform="translate(278.38897,379.89069)"
+           style="display:inline;fill:none;fill-rule:evenodd;stroke:#ffffff;stroke-width:3.0031333;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+           d="m 1229.2855,246.0687 -8.0086,-13.86131"
+           id="path14287-5-25"
+           inkscape:connector-curvature="0" />
+        <path
+           transform="translate(278.38897,379.89069)"
+           style="display:inline;fill:none;fill-rule:evenodd;stroke:#ffffff;stroke-width:3.0031333;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+           d="m 1299.844,175.56029 -13.8613,-7.99714"
+           id="path14287-5-9"
+           inkscape:connector-curvature="0" />
+        <path
+           transform="translate(278.38897,379.89069)"
+           style="display:inline;fill:none;fill-rule:evenodd;stroke:#ff0000;stroke-width:3.0031333;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+           d="m 1325.6703,79.244056 -16,0"
+           id="path14287-5-66"
+           inkscape:connector-curvature="0" />
+        <path
+           transform="translate(278.38897,379.89069)"
+           style="display:inline;fill:none;fill-rule:evenodd;stroke:#ffffff;stroke-width:3.0031333;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+           d="m 1299.844,-17.072197 -13.8613,7.9971385"
+           id="path14287-5-8"
+           inkscape:connector-curvature="0" />
+        <path
+           transform="translate(278.38897,379.89069)"
+           style="display:inline;fill:none;fill-rule:evenodd;stroke:#ffffff;stroke-width:3.0031333;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+           d="m 1229.2855,-87.580589 -8.0086,13.861288"
+           id="path14287-5-467"
+           inkscape:connector-curvature="0" />
+      </g>
+      <text
+         transform="matrix(0.99964615,0,0,1.000354,278.38897,379.89069)"
+         sodipodi:linespacing="125%"
+         id="text12623-7"
+         y="-72.976212"
+         x="1133.2386"
+         style="font-style:normal;font-weight:normal;font-size:20.00708008px;line-height:125%;font-family:sans-serif;text-align:center;letter-spacing:4.00141573px;word-spacing:0px;text-anchor:middle;display:inline;fill:#ff0000;fill-opacity:1;stroke:#ff0000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+         xml:space="preserve"><tspan
+           y="-72.976212"
+           x="1135.2394"
+           id="tspan12625-0"
+           sodipodi:role="line">270</tspan></text>
+      <text
+         transform="matrix(0.86571853,-0.50017773,0.49982381,0.86633153,278.38897,379.89069)"
+         sodipodi:linespacing="125%"
+         id="text12627-1"
+         y="483.06329"
+         x="941.79602"
+         style="font-style:normal;font-weight:normal;font-size:20.00708008px;line-height:125%;font-family:sans-serif;text-align:center;letter-spacing:4.00141573px;word-spacing:0px;text-anchor:middle;display:inline;fill:#000080;fill-opacity:1;stroke:#000080;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+         xml:space="preserve"><tspan
+           y="483.06329"
+           x="943.79675"
+           id="tspan12629-38"
+           sodipodi:role="line">240</tspan></text>
+      <text
+         transform="matrix(0.49982243,-0.86633233,0.86571933,0.50017635,278.38897,379.89069)"
+         sodipodi:linespacing="125%"
+         id="text12631-8"
+         y="868.88483"
+         x="497.98352"
+         style="font-style:normal;font-weight:normal;font-size:20.00708008px;line-height:125%;font-family:sans-serif;text-align:center;letter-spacing:4.00141573px;word-spacing:0px;text-anchor:middle;display:inline;fill:#000080;fill-opacity:1;stroke:#000080;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+         xml:space="preserve"><tspan
+           y="868.88483"
+           x="499.98422"
+           id="tspan12633-3"
+           sodipodi:role="line">210</tspan></text>
+      <text
+         transform="matrix(1.9463829e-7,-1.000354,0.99964615,1.9477611e-7,278.38897,379.89069)"
+         sodipodi:linespacing="125%"
+         id="text12635-5"
+         y="981.11011"
+         x="-79.645622"
+         style="font-style:normal;font-weight:normal;font-size:20.00708008px;line-height:125%;font-family:sans-serif;text-align:center;letter-spacing:4.00141573px;word-spacing:0px;text-anchor:middle;display:inline;fill:#ff0000;fill-opacity:1;stroke:#ff0000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+         xml:space="preserve"><tspan
+           y="981.11011"
+           x="-77.644913"
+           id="tspan12637-21"
+           sodipodi:role="line">180</tspan></text>
+      <text
+         transform="matrix(-0.4998225,-0.86633229,0.86571929,-0.50017642,278.38897,379.89069)"
+         sodipodi:linespacing="125%"
+         id="text12639-8"
+         y="789.66895"
+         x="-635.68311"
+         style="font-style:normal;font-weight:normal;font-size:20.00708008px;line-height:125%;font-family:sans-serif;text-align:center;letter-spacing:4.00141573px;word-spacing:0px;text-anchor:middle;display:inline;fill:#000080;fill-opacity:1;stroke:#000080;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+         xml:space="preserve"><tspan
+           y="789.66895"
+           x="-633.68237"
+           id="tspan12641-2"
+           sodipodi:role="line">150</tspan></text>
+      <text
+         transform="matrix(-0.86571858,-0.50017765,0.49982373,-0.86633158,278.38897,379.89069)"
+         sodipodi:linespacing="125%"
+         id="text12643-3"
+         y="345.85715"
+         x="-1021.5056"
+         style="font-style:normal;font-weight:normal;font-size:20.00708008px;line-height:125%;font-family:sans-serif;text-align:center;letter-spacing:4.00141573px;word-spacing:0px;text-anchor:middle;display:inline;fill:#000080;fill-opacity:1;stroke:#000080;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+         xml:space="preserve"><tspan
+           y="345.85715"
+           x="-1019.5049"
+           id="tspan12645-4"
+           sodipodi:role="line">120</tspan></text>
+      <text
+         transform="matrix(-0.99964615,0,0,-1.000354,278.38897,379.89069)"
+         sodipodi:linespacing="125%"
+         id="text12647-9"
+         y="-231.40747"
+         x="-1133.2625"
+         style="font-style:normal;font-weight:normal;font-size:20.00708008px;line-height:125%;font-family:sans-serif;text-align:center;letter-spacing:4.00141573px;word-spacing:0px;text-anchor:middle;display:inline;fill:#ff0000;fill-opacity:1;stroke:#ff0000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+         xml:space="preserve"><tspan
+           y="-231.40747"
+           x="-1131.2617"
+           id="tspan12649-9"
+           sodipodi:role="line">90</tspan></text>
+      <text
+         transform="matrix(-0.86571858,0.50017765,-0.49982373,-0.86633158,278.38897,379.89069)"
+         sodipodi:linespacing="125%"
+         id="text12651-8"
+         y="-787.44611"
+         x="-941.88885"
+         style="font-style:normal;font-weight:normal;font-size:20.00708008px;line-height:125%;font-family:sans-serif;text-align:center;letter-spacing:4.00141573px;word-spacing:0px;text-anchor:middle;display:inline;fill:#000080;fill-opacity:1;stroke:#000080;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+         xml:space="preserve"><tspan
+           y="-787.44611"
+           x="-939.88812"
+           id="tspan12653-4"
+           sodipodi:role="line">60</tspan></text>
+      <text
+         transform="matrix(-0.4998225,0.86633229,-0.86571929,-0.50017642,278.38897,379.89069)"
+         sodipodi:linespacing="125%"
+         id="text12655-1"
+         y="-1173.2679"
+         x="-498.13989"
+         style="font-style:normal;font-weight:normal;font-size:20.00708008px;line-height:125%;font-family:sans-serif;text-align:center;letter-spacing:4.00141573px;word-spacing:0px;text-anchor:middle;display:inline;fill:#000080;fill-opacity:1;stroke:#000080;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+         xml:space="preserve"><tspan
+           y="-1173.2679"
+           x="-496.13919"
+           id="tspan12657-8"
+           sodipodi:role="line">30</tspan></text>
+      <text
+         transform="matrix(0.49982232,0.86633239,-0.86571939,0.50017624,278.38897,379.89069)"
+         sodipodi:linespacing="125%"
+         id="text12623-3-8"
+         y="-1094.0522"
+         x="635.16028"
+         style="font-style:normal;font-weight:normal;font-size:20.00708008px;line-height:125%;font-family:sans-serif;text-align:center;letter-spacing:4.00141573px;word-spacing:0px;text-anchor:middle;display:inline;fill:#000080;fill-opacity:1;stroke:#000080;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+         xml:space="preserve"><tspan
+           y="-1094.0522"
+           x="637.16101"
+           id="tspan12625-3-3"
+           sodipodi:role="line">300</tspan></text>
+      <text
+         transform="matrix(0.86571859,0.50017762,-0.4998237,0.8663316,278.38897,379.89069)"
+         sodipodi:linespacing="125%"
+         id="text12627-5-9"
+         y="-650.23999"
+         x="1020.9829"
+         style="font-style:normal;font-weight:normal;font-size:20.00708008px;line-height:125%;font-family:sans-serif;text-align:center;letter-spacing:4.00141573px;word-spacing:0px;text-anchor:middle;display:inline;fill:#000080;fill-opacity:1;stroke:#000080;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+         xml:space="preserve"><tspan
+           y="-650.23999"
+           x="1022.9836"
+           id="tspan12629-3-6"
+           sodipodi:role="line">330</tspan></text>
+      <text
+         transform="matrix(-5.2231723e-4,-1.0003066,-0.99969344,1.6860649e-4,0,0)"
+         sodipodi:linespacing="125%"
+         id="text12659-6-5"
+         y="-1567.0344"
+         x="-470.15445"
+         style="font-style:normal;font-weight:normal;font-size:20.00708008px;line-height:125%;font-family:sans-serif;text-align:center;letter-spacing:4.00141573px;word-spacing:0px;text-anchor:middle;display:inline;fill:#ff0000;fill-opacity:1;stroke:#ff0000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+         xml:space="preserve"><tspan
+           y="-1567.0344"
+           x="-468.15375"
+           id="tspan12661-5-2"
+           sodipodi:role="line">0</tspan></text>
+      <g
+         transform="matrix(1.0004736,0,0,1.0004782,-0.66817142,-0.21820955)"
+         id="g5567">
+        <path
+           style="display:inline;fill:none;fill-rule:evenodd;stroke:#0000ff;stroke-width:0.99952435px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1"
+           d="m 1396.2964,459.29047 29.9858,0"
+           id="path12562-9"
+           inkscape:connector-curvature="0" />
+        <path
+           style="display:inline;fill:none;fill-rule:evenodd;stroke:#0000ff;stroke-width:0.99952435px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1"
+           d="m 1411.2896,444.2962 0,29.98566"
+           id="path12564-3"
+           inkscape:connector-curvature="0" />
+      </g>
+      <g
+         transform="matrix(0.5,0.8660254,-0.8660254,0.5,1153.4021,-905.96716)"
+         id="g5567-2"
+         style="display:inline;fill:none;stroke:#0000ff">
+        <path
+           style="display:inline;fill:none;fill-rule:evenodd;stroke:#0000ff;stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1"
+           d="m 1396.2964,459.29047 29.9858,0"
+           id="path12562-8"
+           inkscape:connector-curvature="0" />
+        <path
+           style="display:inline;fill:none;fill-rule:evenodd;stroke:#0000ff;stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1"
+           d="m 1411.2896,444.2962 0,29.98566"
+           id="path12564-5"
+           inkscape:connector-curvature="0" />
+      </g>
+    </g>
+    <path
+       style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:1, 3.00000004;stroke-dashoffset:0;stroke-opacity:1"
+       d="m 2287.8127,322.85414 52.0123,0"
+       id="path9375-8-0"
+       inkscape:connector-curvature="0" />
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-weight:normal;font-size:17.5px;line-height:125%;font-family:sans-serif;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="1164.5468"
+       y="-392.44144"
+       id="text5769"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan5771"
+         x="1164.5468"
+         y="-392.44144"
+         style="text-align:start;text-anchor:start">Size: W:600 H:440 px</tspan><tspan
+         sodipodi:role="line"
+         x="1164.5468"
+         y="-370.56644"
+         style="text-align:start;text-anchor:start"
+         id="tspan5779">Center = x:240, y:220</tspan><tspan
+         sodipodi:role="line"
+         x="1164.5468"
+         y="-348.69144"
+         style="text-align:start;text-anchor:start"
+         id="tspan5777">magnitude=100px</tspan><tspan
+         sodipodi:role="line"
+         x="1164.5468"
+         y="-326.81644"
+         id="tspan5773"
+         style="text-align:start;text-anchor:start">angle = 60deg</tspan><tspan
+         sodipodi:role="line"
+         x="1164.5468"
+         y="-304.94144"
+         id="tspan5775"
+         style="text-align:start;text-anchor:start">maxRadius= 230px</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-weight:normal;font-size:17.5px;line-height:125%;font-family:sans-serif;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="1403.5974"
+       y="-392.44144"
+       id="text5783"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan5785"
+         x="1403.5974"
+         y="-392.44144"
+         style="text-align:start;text-anchor:start">Kx = 600px / 230px = 2.609 => rho =  260.869px</tspan><tspan
+         sodipodi:role="line"
+         x="1403.5974"
+         y="-370.56644"
+         style="text-align:start;text-anchor:start"
+         id="tspan5787">Ky = 440px / 360deg = 1.222 pix/deg = phi = 73.333px</tspan><tspan
+         sodipodi:role="line"
+         x="1403.5974"
+         y="-348.69144"
+         style="text-align:start;text-anchor:start"
+         id="tspan5801">M = 600px / ln(230px) = 110.33 pn/ln(px) => rho = 508.103px</tspan></text>
+    <circle
+       style="display:inline;opacity:1;fill:none;fill-opacity:1;stroke:#ff0000;stroke-width:2;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+       id="path5214"
+       cx="-1804.0728"
+       cy="-305.4054"
+       transform="matrix(-0.9167673,0.39942172,-0.39942171,-0.91676731,278.38913,379.89069)"
+       r="230" />
+    <rect
+       style="display:inline;opacity:1;fill:#aaccff;fill-opacity:1;stroke:none;stroke-width:2;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+       id="rect5347-06"
+       width="600"
+       height="30"
+       x="1535.9006"
+       y="-220.60022"
+       transform="translate(278.38913,379.89069)" />
+    <text
+       transform="translate(278.38913,379.89069)"
+       xml:space="preserve"
+       style="font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:20px;line-height:125%;font-family:serif;-inkscape-font-specification:'serif Italic';text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;display:inline;fill:#0000ff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;"
+       x="1836.0618"
+       y="-200.08264"
+       id="text10597-7-0-1"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan10599-7-1-1"
+         x="1836.0618"
+         y="-200.08264">b) Params References</tspan></text>
+  </g>
+  <metadata
+     id="metadata74">
+    <rdf:RDF>
+      <cc:Work>
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <cc:license
+           rdf:resource="http://creativecommons.org/publicdomain/zero/1.0/" />
+        <dc:publisher>
+          <cc:Agent
+             rdf:about="http://openclipart.org/">
+            <dc:title>OpenCV</dc:title>
+          </cc:Agent>
+        </dc:publisher>
+        <dc:title></dc:title>
+        <dc:date>2016-08-08</dc:date>
+        <dc:description />
+        <dc:source />
+        <dc:creator>
+          <cc:Agent>
+            <dc:title>PkLab.net</dc:title>
+          </cc:Agent>
+        </dc:creator>
+        <dc:subject>
+          <rdf:Bag>
+            <rdf:li>linearPolar</rdf:li>
+            <rdf:li>logPolar</rdf:li>
+            <rdf:li>image processing</rdf:li>
+            <rdf:li>OpenCV</rdf:li>
+          </rdf:Bag>
+        </dc:subject>
+      </cc:Work>
+      <cc:License
+         rdf:about="http://creativecommons.org/publicdomain/zero/1.0/">
+        <cc:permits
+           rdf:resource="http://creativecommons.org/ns#Reproduction" />
+        <cc:permits
+           rdf:resource="http://creativecommons.org/ns#Distribution" />
+        <cc:permits
+           rdf:resource="http://creativecommons.org/ns#DerivativeWorks" />
+      </cc:License>
+    </rdf:RDF>
+  </metadata>
+</svg>
diff --git a/modules/imgproc/include/opencv2/imgproc.hpp b/modules/imgproc/include/opencv2/imgproc.hpp
index 717dcf5..007a238 100644
--- a/modules/imgproc/include/opencv2/imgproc.hpp
+++ b/modules/imgproc/include/opencv2/imgproc.hpp
@@ -40,8 +40,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_IMGPROC_HPP__
-#define __OPENCV_IMGPROC_HPP__
+#ifndef OPENCV_IMGPROC_HPP
+#define OPENCV_IMGPROC_HPP
 
 #include "opencv2/core.hpp"
 
@@ -194,12 +194,30 @@ int main(int argc, const char *argv[])
 
 @see cv::ColormapTypes
 
+    @defgroup imgproc_subdiv2d Planar Subdivision
+
+The Subdiv2D class described in this section is used to perform various planar subdivision on
+a set of 2D points (represented as vector of Point2f). OpenCV subdivides a plane into triangles
+using the Delaunay’s algorithm, which corresponds to the dual graph of the Voronoi diagram.
+In the figure below, the Delaunay’s triangulation is marked with black lines and the Voronoi
+diagram with red lines.
+
+![Delaunay triangulation (black) and Voronoi (red)](pics/delaunay_voronoi.png)
+
+The subdivisions can be used for the 3D piece-wise transformation of a plane, morphing, fast
+location of points on the plane, building special graphs (such as NNG,RNG), and so forth.
+
     @defgroup imgproc_hist Histograms
     @defgroup imgproc_shape Structural Analysis and Shape Descriptors
     @defgroup imgproc_motion Motion Analysis and Object Tracking
     @defgroup imgproc_feature Feature Detection
     @defgroup imgproc_object Object Detection
     @defgroup imgproc_c C API
+    @defgroup imgproc_hal Hardware Acceleration Layer
+    @{
+        @defgroup imgproc_hal_functions Functions
+        @defgroup imgproc_hal_interface Interface
+    @}
   @}
 */
 
@@ -228,7 +246,7 @@ enum MorphTypes{
     MORPH_BLACKHAT = 6, //!< "black hat"
                         //!< \f[\texttt{dst} = \mathrm{blackhat} ( \texttt{src} , \texttt{element} )= \mathrm{close} ( \texttt{src} , \texttt{element} )- \texttt{src}\f]
     MORPH_HITMISS  = 7  //!< "hit and miss"
-                        //!<   .- Only supported for CV_8UC1 binary images. Tutorial can be found in [this page](http://opencv-code.com/tutorials/hit-or-miss-transform-in-opencv/)
+                        //!<   .- Only supported for CV_8UC1 binary images. Tutorial can be found in [this page](https://web.archive.org/web/20160316070407/http://opencv-code.com/tutorials/hit-or-miss-transform-in-opencv/)
 };
 
 //! shape of the structuring element
@@ -266,9 +284,9 @@ enum InterpolationFlags{
     WARP_FILL_OUTLIERS   = 8,
     /** flag, inverse transformation
 
-    For example, polar transforms:
-    - flag is __not__ set: \f$dst( \phi , \rho ) = src(x,y)\f$
-    - flag is set: \f$dst(x,y) = src( \phi , \rho )\f$
+    For example, @ref cv::linearPolar or @ref cv::logPolar transforms:
+    - flag is __not__ set: \f$dst( \rho , \phi ) = src(x,y)\f$
+    - flag is set: \f$dst(x,y) = src( \rho , \phi )\f$
     */
     WARP_INVERSE_MAP     = 16
 };
@@ -395,6 +413,13 @@ enum ConnectedComponentsTypes {
     CC_STAT_MAX    = 5
 };
 
+//! connected components algorithm
+enum ConnectedComponentsAlgorithmsTypes {
+    CCL_WU      = 0,  //!< SAUF algorithm for 8-way connectivity, SAUF algorithm for 4-way connectivity
+    CCL_DEFAULT = -1, //!< BBDT algortihm for 8-way connectivity, SAUF algorithm for 4-way connectivity
+    CCL_GRANA   = 1   //!< BBDT algorithm for 8-way connectivity, SAUF algorithm for 4-way connectivity
+};
+
 //! mode of the contour retrieval algorithm
 enum RetrievalModes {
     /** retrieves only the extreme outer contours. It sets `hierarchy[i][2]=hierarchy[i][3]=-1` for
@@ -874,16 +899,21 @@ public:
 };
 
 
+//! @addtogroup imgproc_subdiv2d
+//! @{
+
 class CV_EXPORTS_W Subdiv2D
 {
 public:
-    enum { PTLOC_ERROR        = -2,
-           PTLOC_OUTSIDE_RECT = -1,
-           PTLOC_INSIDE       = 0,
-           PTLOC_VERTEX       = 1,
-           PTLOC_ON_EDGE      = 2
+    /** Subdiv2D point location cases */
+    enum { PTLOC_ERROR        = -2, //!< Point location error
+           PTLOC_OUTSIDE_RECT = -1, //!< Point outside the subdivision bounding rect
+           PTLOC_INSIDE       = 0, //!< Point inside some facet
+           PTLOC_VERTEX       = 1, //!< Point coincides with one of the subdivision vertices
+           PTLOC_ON_EDGE      = 2  //!< Point on some edge
          };
 
+    /** Subdiv2D edge type navigation (see: getEdge()) */
     enum { NEXT_AROUND_ORG   = 0x00,
            NEXT_AROUND_DST   = 0x22,
            PREV_AROUND_ORG   = 0x11,
@@ -894,27 +924,190 @@ public:
            PREV_AROUND_RIGHT = 0x02
          };
 
+    /** creates an empty Subdiv2D object.
+    To create a new empty Delaunay subdivision you need to use the initDelaunay() function.
+     */
     CV_WRAP Subdiv2D();
+
+    /** @overload
+
+    @param rect – Rectangle that includes all of the 2D points that are to be added to the subdivision.
+
+    The function creates an empty Delaunay subdivision where 2D points can be added using the function
+    insert() . All of the points to be added must be within the specified rectangle, otherwise a runtime
+    error is raised.
+     */
     CV_WRAP Subdiv2D(Rect rect);
+
+    /** @brief Creates a new empty Delaunay subdivision
+
+    @param rect – Rectangle that includes all of the 2D points that are to be added to the subdivision.
+
+     */
     CV_WRAP void initDelaunay(Rect rect);
 
+    /** @brief Insert a single point into a Delaunay triangulation.
+
+    @param pt – Point to insert.
+
+    The function inserts a single point into a subdivision and modifies the subdivision topology
+    appropriately. If a point with the same coordinates exists already, no new point is added.
+    @returns the ID of the point.
+
+    @note If the point is outside of the triangulation specified rect a runtime error is raised.
+     */
     CV_WRAP int insert(Point2f pt);
+
+    /** @brief Insert multiple points into a Delaunay triangulation.
+
+    @param ptvec – Points to insert.
+
+    The function inserts a vector of points into a subdivision and modifies the subdivision topology
+    appropriately.
+     */
     CV_WRAP void insert(const std::vector<Point2f>& ptvec);
+
+    /** @brief Returns the location of a point within a Delaunay triangulation.
+
+    @param pt – Point to locate.
+    @param edge – Output edge that the point belongs to or is located to the right of it.
+    @param vertex – Optional output vertex the input point coincides with.
+
+    The function locates the input point within the subdivision and gives one of the triangle edges
+    or vertices.
+
+    @returns an integer which specify one of the following five cases for point location:
+    -  The point falls into some facet. The function returns PTLOC_INSIDE and edge will contain one of
+       edges of the facet.
+    -  The point falls onto the edge. The function returns PTLOC_ON_EDGE and edge will contain this edge.
+    -  The point coincides with one of the subdivision vertices. The function returns PTLOC_VERTEX and
+       vertex will contain a pointer to the vertex.
+    -  The point is outside the subdivision reference rectangle. The function returns PTLOC_OUTSIDE_RECT
+       and no pointers are filled.
+    -  One of input arguments is invalid. A runtime error is raised or, if silent or “parent” error
+       processing mode is selected, CV_PTLOC_ERROR is returnd.
+     */
     CV_WRAP int locate(Point2f pt, CV_OUT int& edge, CV_OUT int& vertex);
 
+    /** @brief Finds the subdivision vertex closest to the given point.
+
+    @param pt – Input point.
+    @param nearestPt – Output subdivision vertex point.
+
+    The function is another function that locates the input point within the subdivision. It finds the
+    subdivision vertex that is the closest to the input point. It is not necessarily one of vertices
+    of the facet containing the input point, though the facet (located using locate() ) is used as a
+    starting point.
+
+    @returns vertex ID.
+     */
     CV_WRAP int findNearest(Point2f pt, CV_OUT Point2f* nearestPt = 0);
+
+    /** @brief Returns a list of all edges.
+
+    @param edgeList – Output vector.
+
+    The function gives each edge as a 4 numbers vector, where each two are one of the edge
+    vertices. i.e. org_x = v[0], org_y = v[1], dst_x = v[2], dst_y = v[3].
+     */
     CV_WRAP void getEdgeList(CV_OUT std::vector<Vec4f>& edgeList) const;
+
+    /** @brief Returns a list of the leading edge ID connected to each triangle.
+
+    @param leadingEdgeList – Output vector.
+
+    The function gives one edge ID for each triangle.
+     */
+    CV_WRAP void getLeadingEdgeList(CV_OUT std::vector<int>& leadingEdgeList) const;
+
+    /** @brief Returns a list of all triangles.
+
+    @param triangleList – Output vector.
+
+    The function gives each triangle as a 6 numbers vector, where each two are one of the triangle
+    vertices. i.e. p1_x = v[0], p1_y = v[1], p2_x = v[2], p2_y = v[3], p3_x = v[4], p3_y = v[5].
+     */
     CV_WRAP void getTriangleList(CV_OUT std::vector<Vec6f>& triangleList) const;
+
+    /** @brief Returns a list of all Voroni facets.
+
+    @param idx – Vector of vertices IDs to consider. For all vertices you can pass empty vector.
+    @param facetList – Output vector of the Voroni facets.
+    @param facetCenters – Output vector of the Voroni facets center points.
+
+     */
     CV_WRAP void getVoronoiFacetList(const std::vector<int>& idx, CV_OUT std::vector<std::vector<Point2f> >& facetList,
                                      CV_OUT std::vector<Point2f>& facetCenters);
 
+    /** @brief Returns vertex location from vertex ID.
+
+    @param vertex – vertex ID.
+    @param firstEdge – Optional. The first edge ID which is connected to the vertex.
+    @returns vertex (x,y)
+
+     */
     CV_WRAP Point2f getVertex(int vertex, CV_OUT int* firstEdge = 0) const;
 
+    /** @brief Returns one of the edges related to the given edge.
+
+    @param edge – Subdivision edge ID.
+    @param nextEdgeType - Parameter specifying which of the related edges to return.
+    The following values are possible:
+    -   NEXT_AROUND_ORG next around the edge origin ( eOnext on the picture below if e is the input edge)
+    -   NEXT_AROUND_DST next around the edge vertex ( eDnext )
+    -   PREV_AROUND_ORG previous around the edge origin (reversed eRnext )
+    -   PREV_AROUND_DST previous around the edge destination (reversed eLnext )
+    -   NEXT_AROUND_LEFT next around the left facet ( eLnext )
+    -   NEXT_AROUND_RIGHT next around the right facet ( eRnext )
+    -   PREV_AROUND_LEFT previous around the left facet (reversed eOnext )
+    -   PREV_AROUND_RIGHT previous around the right facet (reversed eDnext )
+
+    ![sample output](pics/quadedge.png)
+
+    @returns edge ID related to the input edge.
+     */
     CV_WRAP int getEdge( int edge, int nextEdgeType ) const;
+
+    /** @brief Returns next edge around the edge origin.
+
+    @param edge – Subdivision edge ID.
+
+    @returns an integer which is next edge ID around the edge origin: eOnext on the
+    picture above if e is the input edge).
+     */
     CV_WRAP int nextEdge(int edge) const;
+
+    /** @brief Returns another edge of the same quad-edge.
+
+    @param edge – Subdivision edge ID.
+    @param rotate - Parameter specifying which of the edges of the same quad-edge as the input
+    one to return. The following values are possible:
+    -   0 - the input edge ( e on the picture below if e is the input edge)
+    -   1 - the rotated edge ( eRot )
+    -   2 - the reversed edge (reversed e (in green))
+    -   3 - the reversed rotated edge (reversed eRot (in green))
+
+    @returns one of the edges ID of the same quad-edge as the input edge.
+     */
     CV_WRAP int rotateEdge(int edge, int rotate) const;
     CV_WRAP int symEdge(int edge) const;
+
+    /** @brief Returns the edge origin.
+
+    @param edge – Subdivision edge ID.
+    @param orgpt – Output vertex location.
+
+    @returns vertex ID.
+     */
     CV_WRAP int edgeOrg(int edge, CV_OUT Point2f* orgpt = 0) const;
+
+    /** @brief Returns the edge destination.
+
+    @param edge – Subdivision edge ID.
+    @param dstpt – Output vertex location.
+
+    @returns vertex ID.
+     */
     CV_WRAP int edgeDst(int edge, CV_OUT Point2f* dstpt = 0) const;
 
 protected:
@@ -953,17 +1146,23 @@ protected:
         int pt[4];
     };
 
+    //! All of the vertices
     std::vector<Vertex> vtx;
+    //! All of the edges
     std::vector<QuadEdge> qedges;
     int freeQEdge;
     int freePoint;
     bool validGeometry;
 
     int recentEdge;
+    //! Top left corner of the bounding rect
     Point2f topLeft;
+    //! Bottom right corner of the bounding rect
     Point2f bottomRight;
 };
 
+//! @} imgproc_subdiv2d
+
 //! @addtogroup imgproc_feature
 //! @{
 
@@ -1130,6 +1329,8 @@ The function smoothes an image using the median filter with the \f$\texttt{ksize
 \texttt{ksize}\f$ aperture. Each channel of a multi-channel image is processed independently.
 In-place operation is supported.
 
+ at note The median filter uses BORDER_REPLICATE internally to cope with border pixels, see cv::BorderTypes
+
 @param src input 1-, 3-, or 4-channel image; when ksize is 3 or 5, the image depth should be
 CV_8U, CV_16U, or CV_32F, for larger aperture sizes, it can only be CV_8U.
 @param dst destination array of the same size and type as src.
@@ -1480,6 +1681,19 @@ CV_EXPORTS_W void Canny( InputArray image, OutputArray edges,
                          double threshold1, double threshold2,
                          int apertureSize = 3, bool L2gradient = false );
 
+/** \overload
+
+Finds edges in an image using the Canny algorithm with custom image gradient.
+
+ at param dx 16-bit x derivative of input image (CV_16SC1 or CV_16SC3).
+ at param dy 16-bit y derivative of input image (same type as dx).
+ at param edges,threshold1,threshold2,L2gradient See cv::Canny
+ */
+CV_EXPORTS_W void Canny( InputArray dx, InputArray dy,
+                         OutputArray edges,
+                         double threshold1, double threshold2,
+                         bool L2gradient = false );
+
 /** @brief Calculates the minimal eigenvalue of gradient matrices for corner detection.
 
 The function is similar to cornerEigenValsAndVecs but it calculates and stores only the minimal
@@ -1644,7 +1858,8 @@ with qualityLevel=B .
 @param image Input 8-bit or floating-point 32-bit, single-channel image.
 @param corners Output vector of detected corners.
 @param maxCorners Maximum number of corners to return. If there are more corners than are found,
-the strongest of them is returned.
+the strongest of them is returned. `maxCorners <= 0` implies that no limit on the maximum is set
+and all detected corners are returned.
 @param qualityLevel Parameter characterizing the minimal accepted quality of image corners. The
 parameter value is multiplied by the best corner quality measure, which is the minimal eigenvalue
 (see cornerMinEigenVal ) or the Harris function response (see cornerHarris ). The corners with the
@@ -2079,6 +2294,8 @@ not supported by this function.
 borderMode=BORDER_TRANSPARENT, it means that the pixels in the destination image that
 corresponds to the "outliers" in the source image are not modified by the function.
 @param borderValue Value used in case of a constant border. By default, it is 0.
+ at note
+Due to current implementaion limitations the size of an input and output images should be less than 32767x32767.
  */
 CV_EXPORTS_W void remap( InputArray src, OutputArray dst,
                          InputArray map1, InputArray map2,
@@ -2091,13 +2308,13 @@ The function converts a pair of maps for remap from one representation to anothe
 options ( (map1.type(), map2.type()) \f$\rightarrow\f$ (dstmap1.type(), dstmap2.type()) ) are
 supported:
 
-- \f$\texttt{(CV\_32FC1, CV\_32FC1)} \rightarrow \texttt{(CV\_16SC2, CV\_16UC1)}\f$. This is the
+- \f$\texttt{(CV_32FC1, CV_32FC1)} \rightarrow \texttt{(CV_16SC2, CV_16UC1)}\f$. This is the
 most frequently used conversion operation, in which the original floating-point maps (see remap )
 are converted to a more compact and much faster fixed-point representation. The first output array
 contains the rounded coordinates and the second array (created only when nninterpolation=false )
 contains indices in the interpolation tables.
 
-- \f$\texttt{(CV\_32FC2)} \rightarrow \texttt{(CV\_16SC2, CV\_16UC1)}\f$. The same as above but
+- \f$\texttt{(CV_32FC2)} \rightarrow \texttt{(CV_16SC2, CV_16UC1)}\f$. The same as above but
 the original maps are stored in one 2-channel matrix.
 
 - Reverse conversion. Obviously, the reconstructed floating-point maps will not be exactly the same
@@ -2147,7 +2364,7 @@ CV_EXPORTS Mat getPerspectiveTransform( const Point2f src[], const Point2f dst[]
 
 The function calculates the \f$2 \times 3\f$ matrix of an affine transform so that:
 
-\f[\begin{bmatrix} x'_i \\ y'_i \end{bmatrix} = \texttt{map\_matrix} \cdot \begin{bmatrix} x_i \\ y_i \\ 1 \end{bmatrix}\f]
+\f[\begin{bmatrix} x'_i \\ y'_i \end{bmatrix} = \texttt{map_matrix} \cdot \begin{bmatrix} x_i \\ y_i \\ 1 \end{bmatrix}\f]
 
 where
 
@@ -2177,7 +2394,7 @@ CV_EXPORTS_W void invertAffineTransform( InputArray M, OutputArray iM );
 
 The function calculates the \f$3 \times 3\f$ matrix of a perspective transform so that:
 
-\f[\begin{bmatrix} t_i x'_i \\ t_i y'_i \\ t_i \end{bmatrix} = \texttt{map\_matrix} \cdot \begin{bmatrix} x_i \\ y_i \\ 1 \end{bmatrix}\f]
+\f[\begin{bmatrix} t_i x'_i \\ t_i y'_i \\ t_i \end{bmatrix} = \texttt{map_matrix} \cdot \begin{bmatrix} x_i \\ y_i \\ 1 \end{bmatrix}\f]
 
 where
 
@@ -2220,41 +2437,78 @@ CV_EXPORTS_W void getRectSubPix( InputArray image, Size patchSize,
 An example using the cv::linearPolar and cv::logPolar operations
 */
 
-/** @brief Remaps an image to log-polar space.
+/** @brief Remaps an image to semilog-polar coordinates space.
+
+Transform the source image using the following transformation (See @ref polar_remaps_reference_image "Polar remaps reference image"):
+\f[\begin{array}{l}
+  dst( \rho , \phi ) = src(x,y) \\
+  dst.size() \leftarrow src.size()
+\end{array}\f]
 
-transforms the source image using the following transformation:
-\f[dst( \phi , \rho ) = src(x,y)\f]
 where
-\f[\rho = M  \cdot \log{\sqrt{x^2 + y^2}} , \phi =atan(y/x)\f]
+\f[\begin{array}{l}
+  I = (dx,dy) = (x - center.x,y - center.y) \\
+  \rho = M \cdot log_e(\texttt{magnitude} (I)) ,\\
+  \phi = Ky \cdot \texttt{angle} (I)_{0..360 deg} \\
+\end{array}\f]
 
-The function emulates the human "foveal" vision and can be used for fast scale and
-rotation-invariant template matching, for object tracking and so forth. The function can not operate
-in-place.
+and
+\f[\begin{array}{l}
+  M = src.cols / log_e(maxRadius) \\
+  Ky = src.rows / 360 \\
+\end{array}\f]
 
+The function emulates the human "foveal" vision and can be used for fast scale and
+rotation-invariant template matching, for object tracking and so forth.
 @param src Source image
- at param dst Destination image
+ at param dst Destination image. It will have same size and type as src.
 @param center The transformation center; where the output precision is maximal
- at param M Magnitude scale parameter.
+ at param M Magnitude scale parameter. It determines the radius of the bounding circle to transform too.
 @param flags A combination of interpolation methods, see cv::InterpolationFlags
- */
+
+ at note
+-   The function can not operate in-place.
+-   To calculate magnitude and angle in degrees @ref cv::cartToPolar is used internally thus angles are measured from 0 to 360 with accuracy about 0.3 degrees.
+*/
 CV_EXPORTS_W void logPolar( InputArray src, OutputArray dst,
                             Point2f center, double M, int flags );
 
-/** @brief Remaps an image to polar space.
+/** @brief Remaps an image to polar coordinates space.
+
+ at anchor polar_remaps_reference_image
+![Polar remaps reference](pics/polar_remap_doc.png)
+
+Transform the source image using the following transformation:
+\f[\begin{array}{l}
+  dst( \rho , \phi ) = src(x,y) \\
+  dst.size() \leftarrow src.size()
+\end{array}\f]
 
-transforms the source image using the following transformation:
-\f[dst( \phi , \rho ) = src(x,y)\f]
 where
-\f[\rho = (src.width/maxRadius)  \cdot \sqrt{x^2 + y^2} , \phi =atan(y/x)\f]
+\f[\begin{array}{l}
+  I = (dx,dy) = (x - center.x,y - center.y) \\
+  \rho = Kx \cdot \texttt{magnitude} (I) ,\\
+  \phi = Ky \cdot \texttt{angle} (I)_{0..360 deg}
+\end{array}\f]
+
+and
+\f[\begin{array}{l}
+  Kx = src.cols / maxRadius \\
+  Ky = src.rows / 360
+\end{array}\f]
 
-The function can not operate in-place.
 
 @param src Source image
- at param dst Destination image
+ at param dst Destination image. It will have same size and type as src.
 @param center The transformation center;
- at param maxRadius Inverse magnitude scale parameter
+ at param maxRadius The radius of the bounding circle to transform. It determines the inverse magnitude scale parameter too.
 @param flags A combination of interpolation methods, see cv::InterpolationFlags
- */
+
+ at note
+-   The function can not operate in-place.
+-   To calculate magnitude and angle in degrees @ref cv::cartToPolar is used internally thus angles are measured from 0 to 360 with accuracy about 0.3 degrees.
+
+*/
 CV_EXPORTS_W void linearPolar( InputArray src, OutputArray dst,
                                Point2f center, double maxRadius, int flags );
 
@@ -2272,7 +2526,7 @@ CV_EXPORTS_AS(integral2) void integral( InputArray src, OutputArray sum,
 
 /** @brief Calculates the integral of an image.
 
-The functions calculate one or more integral images for the source image as follows:
+The function calculates one or more integral images for the source image as follows:
 
 \f[\texttt{sum} (X,Y) =  \sum _{x<X,y<Y}  \texttt{image} (x,y)\f]
 
@@ -2711,20 +2965,23 @@ The function is similar to cv::undistort and cv::initUndistortRectifyMap but it
 sparse set of points instead of a raster image. Also the function performs a reverse transformation
 to projectPoints. In case of a 3D object, it does not reconstruct its 3D coordinates, but for a
 planar object, it does, up to a translation vector, if the proper R is specified.
- at code
-    // (u,v) is the input point, (u', v') is the output point
-    // camera_matrix=[fx 0 cx; 0 fy cy; 0 0 1]
-    // P=[fx' 0 cx' tx; 0 fy' cy' ty; 0 0 1 tz]
-    x" = (u - cx)/fx
-    y" = (v - cy)/fy
-    (x',y') = undistort(x",y",dist_coeffs)
-    [X,Y,W]T = R*[x' y' 1]T
-    x = X/W, y = Y/W
-    // only performed if P=[fx' 0 cx' [tx]; 0 fy' cy' [ty]; 0 0 1 [tz]] is specified
-    u' = x*fx' + cx'
-    v' = y*fy' + cy',
- at endcode
-where cv::undistort is an approximate iterative algorithm that estimates the normalized original
+
+For each observed point coordinate \f$(u, v)\f$ the function computes:
+\f[
+\begin{array}{l}
+x^{"}  \leftarrow (u - c_x)/f_x  \\
+y^{"}  \leftarrow (v - c_y)/f_y  \\
+(x',y') = undistort(x^{"},y^{"}, \texttt{distCoeffs}) \\
+{[X\,Y\,W]} ^T  \leftarrow R*[x' \, y' \, 1]^T  \\
+x  \leftarrow X/W  \\
+y  \leftarrow Y/W  \\
+\text{only performed if P is specified:} \\
+u'  \leftarrow x {f'}_x + {c'}_x  \\
+v'  \leftarrow y {f'}_y + {c'}_y
+\end{array}
+\f]
+
+where *undistort* is an approximate iterative algorithm that estimates the normalized original
 point coordinates out of the normalized distorted point coordinates ("normalized" means that the
 coordinates do not depend on the camera matrix).
 
@@ -2739,7 +2996,7 @@ transformation. If matrix P is identity or omitted, dst will contain normalized
 of 4, 5, 8, 12 or 14 elements. If the vector is NULL/empty, the zero distortion coefficients are assumed.
 @param R Rectification transformation in the object space (3x3 matrix). R1 or R2 computed by
 cv::stereoRectify can be passed here. If the matrix is empty, the identity transformation is used.
- at param P New camera matrix (3x3) or new projection matrix (3x4). P1 or P2 computed by
+ at param P New camera matrix (3x3) or new projection matrix (3x4) \f$\begin{bmatrix} {f'}_x & 0 & {c'}_x & t_x \\ 0 & {f'}_y & {c'}_y & t_y \\ 0 & 0 & 1 & t_z \end{bmatrix}\f$. P1 or P2 computed by
 cv::stereoRectify can be passed here. If the matrix is empty, the identity new camera matrix is used.
  */
 CV_EXPORTS_W void undistortPoints( InputArray src, OutputArray dst,
@@ -2757,7 +3014,7 @@ An example for creating histograms of an image
 
 /** @brief Calculates a histogram of a set of arrays.
 
-The functions calcHist calculate the histogram of one or more arrays. The elements of a tuple used
+The function cv::calcHist calculates the histogram of one or more arrays. The elements of a tuple used
 to increment a histogram bin are taken from the corresponding input arrays at the same location. The
 sample below shows how to compute a 2D Hue-Saturation histogram for a color image. :
 @code
@@ -2818,7 +3075,7 @@ sample below shows how to compute a 2D Hue-Saturation histogram for a color imag
     }
 @endcode
 
- at param images Source arrays. They all should have the same depth, CV_8U or CV_32F , and the same
+ at param images Source arrays. They all should have the same depth, CV_8U, CV_16U or CV_32F , and the same
 size. Each of them can have an arbitrary number of channels.
 @param nimages Number of source images.
 @param channels List of the dims channels used to compute the histogram. The first array channels
@@ -2869,7 +3126,7 @@ CV_EXPORTS_W void calcHist( InputArrayOfArrays images,
 
 /** @brief Calculates the back projection of a histogram.
 
-The functions calcBackProject calculate the back project of the histogram. That is, similarly to
+The function cv::calcBackProject calculates the back project of the histogram. That is, similarly to
 cv::calcHist , at each location (x, y) the function collects the values from the selected channels
 in the input images and finds the corresponding histogram bin. But instead of incrementing it, the
 function reads the bin value, scales it by scale , and stores in backProject(x,y) . In terms of
@@ -2890,7 +3147,7 @@ component.
 
 This is an approximate algorithm of the CamShift color object tracker.
 
- at param images Source arrays. They all should have the same depth, CV_8U or CV_32F , and the same
+ at param images Source arrays. They all should have the same depth, CV_8U, CV_16U or CV_32F , and the same
 size. Each of them can have an arbitrary number of channels.
 @param nimages Number of source images.
 @param channels The list of channels used to compute the back projection. The number of channels
@@ -2900,7 +3157,7 @@ images[0].channels() + images[1].channels()-1, and so on.
 @param hist Input histogram that can be dense or sparse.
 @param backProject Destination back projection array that is a single-channel array of the same
 size and depth as images[0] .
- at param ranges Array of arrays of the histogram bin boundaries in each dimension. See calcHist .
+ at param ranges Array of arrays of the histogram bin boundaries in each dimension. See cv::calcHist .
 @param scale Optional scale factor for the output back projection.
 @param uniform Flag indicating whether the histogram is uniform or not (see above).
 
@@ -2925,7 +3182,7 @@ CV_EXPORTS_W void calcBackProject( InputArrayOfArrays images, const std::vector<
 
 /** @brief Compares two histograms.
 
-The function compare two dense or two sparse histograms using the specified method.
+The function cv::compareHist compares two dense or two sparse histograms using the specified method.
 
 The function returns \f$d(H_1, H_2)\f$ .
 
@@ -2973,10 +3230,12 @@ same object.
 
 @param signature1 First signature, a \f$\texttt{size1}\times \texttt{dims}+1\f$ floating-point matrix.
 Each row stores the point weight followed by the point coordinates. The matrix is allowed to have
-a single column (weights only) if the user-defined cost matrix is used.
+a single column (weights only) if the user-defined cost matrix is used. The weights must be
+non-negative and have at least one non-zero value.
 @param signature2 Second signature of the same format as signature1 , though the number of rows
 may be different. The total weights may be different. In this case an extra "dummy" point is added
-to either signature1 or signature2 .
+to either signature1 or signature2. The weights must be non-negative and have at least one non-zero
+value.
 @param distType Used metric. See cv::DistanceTypes.
 @param cost User-defined \f$\texttt{size1}\times \texttt{size2}\f$ cost matrix. Also, if a cost matrix
 is used, lower boundary lowerBound cannot be calculated because it needs a metric function.
@@ -3111,7 +3370,7 @@ An example on using the distance transform\
 
 /** @brief Calculates the distance to the closest zero pixel for each pixel of the source image.
 
-The functions distanceTransform calculate the approximate or precise distance from every binary
+The function cv::distanceTransform calculates the approximate or precise distance from every binary
 image pixel to the nearest zero pixel. For zero image pixels, the distance will obviously be zero.
 
 When maskSize == DIST_MASK_PRECISE and distanceType == DIST_L2 , the function runs the
@@ -3195,7 +3454,7 @@ CV_EXPORTS int floodFill( InputOutputArray image,
 
 /** @brief Fills a connected component with the given color.
 
-The functions floodFill fill a connected component starting from the seed point with the specified
+The function cv::floodFill fills a connected component starting from the seed point with the specified
 color. The connectivity is determined by the color/brightness closeness of the neighbor pixels. The
 pixel at \f$(x,y)\f$ is considered to belong to the repainted domain if:
 
@@ -3330,6 +3589,9 @@ results are returned in the structure cv::Moments.
 used for images only.
 @returns moments.
 
+ at note Only applicable to contour moments calculations from Python bindings: Note that the numpy
+type for the input array should be either np.int32 or np.float32.
+
 @sa  contourArea, arcLength
  */
 CV_EXPORTS_W Moments moments( InputArray array, bool binaryImage = false );
@@ -3411,16 +3673,56 @@ CV_EXPORTS_W void matchTemplate( InputArray image, InputArray templ,
 image with 4 or 8 way connectivity - returns N, the total number of labels [0, N-1] where 0
 represents the background label. ltype specifies the output label image type, an important
 consideration based on the total number of labels or alternatively the total number of pixels in
-the source image.
+the source image. ccltype specifies the connected components labeling algorithm to use, currently
+Grana's (BBDT) and Wu's (SAUF) algorithms are supported, see the cv::ConnectedComponentsAlgorithmsTypes
+for details. Note that SAUF algorithm forces a row major ordering of labels while BBDT does not.
 
 @param image the 8-bit single-channel image to be labeled
 @param labels destination labeled image
 @param connectivity 8 or 4 for 8-way or 4-way connectivity respectively
 @param ltype output image label type. Currently CV_32S and CV_16U are supported.
- */
+ at param ccltype connected components algorithm type (see the cv::ConnectedComponentsAlgorithmsTypes).
+*/
+CV_EXPORTS_AS(connectedComponentsWithAlgorithm) int connectedComponents(InputArray image, OutputArray labels,
+                                                                        int connectivity, int ltype, int ccltype);
+
+
+/** @overload
+
+ at param image the 8-bit single-channel image to be labeled
+ at param labels destination labeled image
+ at param connectivity 8 or 4 for 8-way or 4-way connectivity respectively
+ at param ltype output image label type. Currently CV_32S and CV_16U are supported.
+*/
 CV_EXPORTS_W int connectedComponents(InputArray image, OutputArray labels,
                                      int connectivity = 8, int ltype = CV_32S);
 
+
+/** @brief computes the connected components labeled image of boolean image and also produces a statistics output for each label
+
+image with 4 or 8 way connectivity - returns N, the total number of labels [0, N-1] where 0
+represents the background label. ltype specifies the output label image type, an important
+consideration based on the total number of labels or alternatively the total number of pixels in
+the source image. ccltype specifies the connected components labeling algorithm to use, currently
+Grana's (BBDT) and Wu's (SAUF) algorithms are supported, see the cv::ConnectedComponentsAlgorithmsTypes
+for details. Note that SAUF algorithm forces a row major ordering of labels while BBDT does not.
+
+
+ at param image the 8-bit single-channel image to be labeled
+ at param labels destination labeled image
+ at param stats statistics output for each label, including the background label, see below for
+available statistics. Statistics are accessed via stats(label, COLUMN) where COLUMN is one of
+cv::ConnectedComponentsTypes. The data type is CV_32S.
+ at param centroids centroid output for each label, including the background label. Centroids are
+accessed via centroids(label, 0) for x and centroids(label, 1) for y. The data type CV_64F.
+ at param connectivity 8 or 4 for 8-way or 4-way connectivity respectively
+ at param ltype output image label type. Currently CV_32S and CV_16U are supported.
+ at param ccltype connected components algorithm type (see the cv::ConnectedComponentsAlgorithmsTypes).
+*/
+CV_EXPORTS_AS(connectedComponentsWithStatsWithAlgorithm) int connectedComponentsWithStats(InputArray image, OutputArray labels,
+                                                                                          OutputArray stats, OutputArray centroids,
+                                                                                          int connectivity, int ltype, int ccltype);
+
 /** @overload
 @param image the 8-bit single-channel image to be labeled
 @param labels destination labeled image
@@ -3440,21 +3742,17 @@ CV_EXPORTS_W int connectedComponentsWithStats(InputArray image, OutputArray labe
 /** @brief Finds contours in a binary image.
 
 The function retrieves contours from the binary image using the algorithm @cite Suzuki85 . The contours
-are a useful tool for shape analysis and object detection and recognition. See squares.c in the
+are a useful tool for shape analysis and object detection and recognition. See squares.cpp in the
 OpenCV sample directory.
 
- at note Source image is modified by this function. Also, the function does not take into account
-1-pixel border of the image (it's filled with 0's and used for neighbor analysis in the algorithm),
-therefore the contours touching the image border will be clipped.
-
 @param image Source, an 8-bit single-channel image. Non-zero pixels are treated as 1's. Zero
-pixels remain 0's, so the image is treated as binary . You can use compare , inRange , threshold ,
-adaptiveThreshold , Canny , and others to create a binary image out of a grayscale or color one.
-The function modifies the image while extracting the contours. If mode equals to RETR_CCOMP
-or RETR_FLOODFILL, the input can also be a 32-bit integer image of labels (CV_32SC1).
- at param contours Detected contours. Each contour is stored as a vector of points.
- at param hierarchy Optional output vector, containing information about the image topology. It has
-as many elements as the number of contours. For each i-th contour contours[i] , the elements
+pixels remain 0's, so the image is treated as binary . You can use cv::compare, cv::inRange, cv::threshold ,
+cv::adaptiveThreshold, cv::Canny, and others to create a binary image out of a grayscale or color one.
+If mode equals to cv::RETR_CCOMP or cv::RETR_FLOODFILL, the input can also be a 32-bit integer image of labels (CV_32SC1).
+ at param contours Detected contours. Each contour is stored as a vector of points (e.g.
+std::vector<std::vector<cv::Point> >).
+ at param hierarchy Optional output vector (e.g. std::vector<cv::Vec4i>), containing information about the image topology. It has
+as many elements as the number of contours. For each i-th contour contours[i], the elements
 hierarchy[i][0] , hiearchy[i][1] , hiearchy[i][2] , and hiearchy[i][3] are set to 0-based indices
 in contours of the next and previous contours at the same hierarchical level, the first child
 contour and the parent contour, respectively. If for the contour i there are no next, previous,
@@ -3475,7 +3773,7 @@ CV_EXPORTS void findContours( InputOutputArray image, OutputArrayOfArrays contou
 
 /** @brief Approximates a polygonal curve(s) with the specified precision.
 
-The functions approxPolyDP approximate a curve or a polygon with another curve/polygon with less
+The function cv::approxPolyDP approximates a curve or a polygon with another curve/polygon with less
 vertices so that the distance between them is less or equal to the specified precision. It uses the
 Douglas-Peucker algorithm <http://en.wikipedia.org/wiki/Ramer-Douglas-Peucker_algorithm>
 
@@ -3617,7 +3915,7 @@ An example using the convexHull functionality
 
 /** @brief Finds the convex hull of a point set.
 
-The functions find the convex hull of a 2D point set using the Sklansky's algorithm @cite Sklansky82
+The function cv::convexHull finds the convex hull of a 2D point set using the Sklansky's algorithm @cite Sklansky82
 that has *O(N logN)* complexity in the current implementation. See the OpenCV sample convexhull.cpp
 that demonstrates the usage of different function variants.
 
@@ -3632,8 +3930,8 @@ to the right, and its Y axis pointing upwards.
 @param returnPoints Operation flag. In case of a matrix, when the flag is true, the function
 returns convex hull points. Otherwise, it returns indices of the convex hull points. When the
 output array is std::vector, the flag is ignored, and the output depends on the type of the
-vector: std::vector\<int\> implies returnPoints=true, std::vector\<Point\> implies
-returnPoints=false.
+vector: std::vector\<int\> implies returnPoints=false, std::vector\<Point\> implies
+returnPoints=true.
  */
 CV_EXPORTS_W void convexHull( InputArray points, OutputArray hull,
                               bool clockwise = false, bool returnPoints = true );
@@ -3796,7 +4094,7 @@ enum ColormapTypes
 
 /** @brief Applies a GNU Octave/MATLAB equivalent colormap on a given image.
 
- at param src The source image, grayscale or colored does not matter.
+ at param src The source image, grayscale or colored of type CV_8UC1 or CV_8UC3.
 @param dst The result is the colormapped source image. Note: Mat::create is called on dst.
 @param colormap The colormap to apply, see cv::ColormapTypes
  */
@@ -3886,7 +4184,7 @@ CV_EXPORTS_W void circle(InputOutputArray img, Point center, int radius,
 
 /** @brief Draws a simple or thick elliptic arc or fills an ellipse sector.
 
-The functions ellipse with less parameters draw an ellipse outline, a filled ellipse, an elliptic
+The function cv::ellipse with less parameters draws an ellipse outline, a filled ellipse, an elliptic
 arc, or a filled ellipse sector. A piecewise-linear curve is used to approximate the elliptic arc
 boundary. If you need more control of the ellipse rendering, you can retrieve the curve using
 ellipse2Poly and then render it with polylines or fill it with fillPoly . If you use the first
@@ -3947,8 +4245,8 @@ marker types are supported, see cv::MarkerTypes for more information.
 
 @param img Image.
 @param position The point where the crosshair is positioned.
- at param markerType The specific type of marker you want to use, see cv::MarkerTypes
 @param color Line color.
+ at param markerType The specific type of marker you want to use, see cv::MarkerTypes
 @param thickness Line thickness.
 @param line_type Type of the line, see cv::LineTypes
 @param markerSize The length of the marker axis [default = 20 pixels]
@@ -4107,9 +4405,9 @@ CV_EXPORTS_W void drawContours( InputOutputArray image, InputArrayOfArrays conto
 
 /** @brief Clips the line against the image rectangle.
 
-The functions clipLine calculate a part of the line segment that is entirely within the specified
-rectangle. They return false if the line segment is completely outside the rectangle. Otherwise,
-they return true .
+The function cv::clipLine calculates a part of the line segment that is entirely within the specified
+rectangle. it returns false if the line segment is completely outside the rectangle. Otherwise,
+it returns true .
 @param imgSize Image size. The image rectangle is Rect(0, 0, imgSize.width, imgSize.height) .
 @param pt1 First line point.
 @param pt2 Second line point.
@@ -4117,6 +4415,13 @@ they return true .
 CV_EXPORTS bool clipLine(Size imgSize, CV_IN_OUT Point& pt1, CV_IN_OUT Point& pt2);
 
 /** @overload
+ at param imgSize Image size. The image rectangle is Rect(0, 0, imgSize.width, imgSize.height) .
+ at param pt1 First line point.
+ at param pt2 Second line point.
+*/
+CV_EXPORTS bool clipLine(Size2l imgSize, CV_IN_OUT Point2l& pt1, CV_IN_OUT Point2l& pt2);
+
+/** @overload
 @param imgRect Image rectangle.
 @param pt1 First line point.
 @param pt2 Second line point.
@@ -4141,6 +4446,20 @@ CV_EXPORTS_W void ellipse2Poly( Point center, Size axes, int angle,
                                 int arcStart, int arcEnd, int delta,
                                 CV_OUT std::vector<Point>& pts );
 
+/** @overload
+ at param center Center of the arc.
+ at param axes Half of the size of the ellipse main axes. See the ellipse for details.
+ at param angle Rotation angle of the ellipse in degrees. See the ellipse for details.
+ at param arcStart Starting angle of the elliptic arc in degrees.
+ at param arcEnd Ending angle of the elliptic arc in degrees.
+ at param delta Angle between the subsequent polyline vertices. It defines the approximation
+accuracy.
+ at param pts Output vector of polyline vertices.
+*/
+CV_EXPORTS void ellipse2Poly(Point2d center, Size2d axes, int angle,
+                             int arcStart, int arcEnd, int delta,
+                             CV_OUT std::vector<Point2d>& pts);
+
 /** @brief Draws a text string.
 
 The function putText renders the specified text string in the image. Symbols that cannot be rendered
diff --git a/modules/imgproc/include/opencv2/imgproc/detail/distortion_model.hpp b/modules/imgproc/include/opencv2/imgproc/detail/distortion_model.hpp
index ca29304..a9c3dde 100644
--- a/modules/imgproc/include/opencv2/imgproc/detail/distortion_model.hpp
+++ b/modules/imgproc/include/opencv2/imgproc/detail/distortion_model.hpp
@@ -40,8 +40,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_IMGPROC_DETAIL_DISTORTION_MODEL_HPP__
-#define __OPENCV_IMGPROC_DETAIL_DISTORTION_MODEL_HPP__
+#ifndef OPENCV_IMGPROC_DETAIL_DISTORTION_MODEL_HPP
+#define OPENCV_IMGPROC_DETAIL_DISTORTION_MODEL_HPP
 
 //! @cond IGNORED
 
@@ -120,4 +120,4 @@ void computeTiltProjectionMatrix(FLOAT tauX,
 
 //! @endcond
 
-#endif // __OPENCV_IMGPROC_DETAIL_DISTORTION_MODEL_HPP__
+#endif // OPENCV_IMGPROC_DETAIL_DISTORTION_MODEL_HPP
diff --git a/modules/imgproc/include/opencv2/imgproc/hal/hal.hpp b/modules/imgproc/include/opencv2/imgproc/hal/hal.hpp
new file mode 100644
index 0000000..fc6b9d8
--- /dev/null
+++ b/modules/imgproc/include/opencv2/imgproc/hal/hal.hpp
@@ -0,0 +1,189 @@
+#ifndef CV_IMGPROC_HAL_HPP
+#define CV_IMGPROC_HAL_HPP
+
+#include "opencv2/core/cvdef.h"
+#include "opencv2/core/cvstd.hpp"
+#include "opencv2/core/hal/interface.h"
+
+namespace cv { namespace hal {
+
+//! @addtogroup imgproc_hal_functions
+//! @{
+
+struct CV_EXPORTS Filter2D
+{
+    static Ptr<hal::Filter2D> create(uchar * kernel_data, size_t kernel_step, int kernel_type,
+                                     int kernel_width, int kernel_height,
+                                     int max_width, int max_height,
+                                     int stype, int dtype,
+                                     int borderType, double delta,
+                                     int anchor_x, int anchor_y,
+                                     bool isSubmatrix, bool isInplace);
+    virtual void apply(uchar * src_data, size_t src_step,
+                       uchar * dst_data, size_t dst_step,
+                       int width, int height,
+                       int full_width, int full_height,
+                       int offset_x, int offset_y) = 0;
+    virtual ~Filter2D() {}
+};
+
+struct CV_EXPORTS SepFilter2D
+{
+    static Ptr<hal::SepFilter2D> create(int stype, int dtype, int ktype,
+                                        uchar * kernelx_data, int kernelx_len,
+                                        uchar * kernely_data, int kernely_len,
+                                        int anchor_x, int anchor_y,
+                                        double delta, int borderType);
+    virtual void apply(uchar * src_data, size_t src_step,
+                       uchar * dst_data, size_t dst_step,
+                       int width, int height,
+                       int full_width, int full_height,
+                       int offset_x, int offset_y) = 0;
+    virtual ~SepFilter2D() {}
+};
+
+
+struct  CV_EXPORTS Morph
+{
+    static Ptr<Morph> create(int op, int src_type, int dst_type, int max_width, int max_height,
+                                    int kernel_type, uchar * kernel_data, size_t kernel_step,
+                                    int kernel_width, int kernel_height,
+                                    int anchor_x, int anchor_y,
+                                    int borderType, const double borderValue[4],
+                                    int iterations, bool isSubmatrix, bool allowInplace);
+    virtual void apply(uchar * src_data, size_t src_step, uchar * dst_data, size_t dst_step, int width, int height,
+                       int roi_width, int roi_height, int roi_x, int roi_y,
+                       int roi_width2, int roi_height2, int roi_x2, int roi_y2) = 0;
+    virtual ~Morph() {}
+};
+
+
+CV_EXPORTS void resize(int src_type,
+                       const uchar * src_data, size_t src_step, int src_width, int src_height,
+                       uchar * dst_data, size_t dst_step, int dst_width, int dst_height,
+                       double inv_scale_x, double inv_scale_y, int interpolation);
+
+CV_EXPORTS void warpAffine(int src_type,
+                           const uchar * src_data, size_t src_step, int src_width, int src_height,
+                           uchar * dst_data, size_t dst_step, int dst_width, int dst_height,
+                           const double M[6], int interpolation, int borderType, const double borderValue[4]);
+
+CV_EXPORTS void warpPerspectve(int src_type,
+                               const uchar * src_data, size_t src_step, int src_width, int src_height,
+                               uchar * dst_data, size_t dst_step, int dst_width, int dst_height,
+                               const double M[9], int interpolation, int borderType, const double borderValue[4]);
+
+CV_EXPORTS void cvtBGRtoBGR(const uchar * src_data, size_t src_step,
+                            uchar * dst_data, size_t dst_step,
+                            int width, int height,
+                            int depth, int scn, int dcn, bool swapBlue);
+
+CV_EXPORTS void cvtBGRtoBGR5x5(const uchar * src_data, size_t src_step,
+                               uchar * dst_data, size_t dst_step,
+                               int width, int height,
+                               int scn, bool swapBlue, int greenBits);
+
+CV_EXPORTS void cvtBGR5x5toBGR(const uchar * src_data, size_t src_step,
+                               uchar * dst_data, size_t dst_step,
+                               int width, int height,
+                               int dcn, bool swapBlue, int greenBits);
+
+CV_EXPORTS void cvtBGRtoGray(const uchar * src_data, size_t src_step,
+                             uchar * dst_data, size_t dst_step,
+                             int width, int height,
+                             int depth, int scn, bool swapBlue);
+
+CV_EXPORTS void cvtGraytoBGR(const uchar * src_data, size_t src_step,
+                             uchar * dst_data, size_t dst_step,
+                             int width, int height,
+                             int depth, int dcn);
+
+CV_EXPORTS void cvtBGR5x5toGray(const uchar * src_data, size_t src_step,
+                                uchar * dst_data, size_t dst_step,
+                                int width, int height,
+                                int greenBits);
+
+CV_EXPORTS void cvtGraytoBGR5x5(const uchar * src_data, size_t src_step,
+                                uchar * dst_data, size_t dst_step,
+                                int width, int height,
+                                int greenBits);
+CV_EXPORTS void cvtBGRtoYUV(const uchar * src_data, size_t src_step,
+                            uchar * dst_data, size_t dst_step,
+                            int width, int height,
+                            int depth, int scn, bool swapBlue, bool isCbCr);
+
+CV_EXPORTS void cvtYUVtoBGR(const uchar * src_data, size_t src_step,
+                            uchar * dst_data, size_t dst_step,
+                            int width, int height,
+                            int depth, int dcn, bool swapBlue, bool isCbCr);
+
+CV_EXPORTS void cvtBGRtoXYZ(const uchar * src_data, size_t src_step,
+                            uchar * dst_data, size_t dst_step,
+                            int width, int height,
+                            int depth, int scn, bool swapBlue);
+
+CV_EXPORTS void cvtXYZtoBGR(const uchar * src_data, size_t src_step,
+                            uchar * dst_data, size_t dst_step,
+                            int width, int height,
+                            int depth, int dcn, bool swapBlue);
+
+CV_EXPORTS void cvtBGRtoHSV(const uchar * src_data, size_t src_step,
+                            uchar * dst_data, size_t dst_step,
+                            int width, int height,
+                            int depth, int scn, bool swapBlue, bool isFullRange, bool isHSV);
+
+CV_EXPORTS void cvtHSVtoBGR(const uchar * src_data, size_t src_step,
+                            uchar * dst_data, size_t dst_step,
+                            int width, int height,
+                            int depth, int dcn, bool swapBlue, bool isFullRange, bool isHSV);
+
+CV_EXPORTS void cvtBGRtoLab(const uchar * src_data, size_t src_step,
+                            uchar * dst_data, size_t dst_step,
+                            int width, int height,
+                            int depth, int scn, bool swapBlue, bool isLab, bool srgb);
+
+CV_EXPORTS void cvtLabtoBGR(const uchar * src_data, size_t src_step,
+                            uchar * dst_data, size_t dst_step,
+                            int width, int height,
+                            int depth, int dcn, bool swapBlue, bool isLab, bool srgb);
+
+CV_EXPORTS void cvtTwoPlaneYUVtoBGR(const uchar * src_data, size_t src_step,
+                                    uchar * dst_data, size_t dst_step,
+                                    int dst_width, int dst_height,
+                                    int dcn, bool swapBlue, int uIdx);
+
+CV_EXPORTS void cvtThreePlaneYUVtoBGR(const uchar * src_data, size_t src_step,
+                                      uchar * dst_data, size_t dst_step,
+                                      int dst_width, int dst_height,
+                                      int dcn, bool swapBlue, int uIdx);
+
+CV_EXPORTS void cvtBGRtoThreePlaneYUV(const uchar * src_data, size_t src_step,
+                                      uchar * dst_data, size_t dst_step,
+                                      int width, int height,
+                                      int scn, bool swapBlue, int uIdx);
+
+CV_EXPORTS void cvtOnePlaneYUVtoBGR(const uchar * src_data, size_t src_step,
+                                    uchar * dst_data, size_t dst_step,
+                                    int width, int height,
+                                    int dcn, bool swapBlue, int uIdx, int ycn);
+
+CV_EXPORTS void cvtRGBAtoMultipliedRGBA(const uchar * src_data, size_t src_step,
+                                        uchar * dst_data, size_t dst_step,
+                                        int width, int height);
+
+CV_EXPORTS void cvtMultipliedRGBAtoRGBA(const uchar * src_data, size_t src_step,
+                                        uchar * dst_data, size_t dst_step,
+                                        int width, int height);
+
+CV_EXPORTS void integral(int depth, int sdepth, int sqdepth,
+                         const uchar* src, size_t srcstep,
+                         uchar* sum, size_t sumstep,
+                         uchar* sqsum, size_t sqsumstep,
+                         uchar* tilted, size_t tstep,
+                         int width, int height, int cn);
+
+//! @}
+
+}}
+
+#endif // CV_IMGPROC_HAL_HPP
diff --git a/modules/imgproc/include/opencv2/imgproc/hal/interface.h b/modules/imgproc/include/opencv2/imgproc/hal/interface.h
new file mode 100644
index 0000000..9d2a3e5
--- /dev/null
+++ b/modules/imgproc/include/opencv2/imgproc/hal/interface.h
@@ -0,0 +1,26 @@
+#ifndef OPENCV_IMGPROC_HAL_INTERFACE_H
+#define OPENCV_IMGPROC_HAL_INTERFACE_H
+
+//! @addtogroup imgproc_hal_interface
+//! @{
+
+//! @name Interpolation modes
+//! @sa cv::InterpolationFlags
+//! @{
+#define CV_HAL_INTER_NEAREST 0
+#define CV_HAL_INTER_LINEAR 1
+#define CV_HAL_INTER_CUBIC 2
+#define CV_HAL_INTER_AREA 3
+#define CV_HAL_INTER_LANCZOS4 4
+//! @}
+
+//! @name Morphology operations
+//! @sa cv::MorphTypes
+//! @{
+#define MORPH_ERODE 0
+#define MORPH_DILATE 1
+//! @}
+
+//! @}
+
+#endif
diff --git a/modules/imgproc/include/opencv2/imgproc/imgproc_c.h b/modules/imgproc/include/opencv2/imgproc/imgproc_c.h
index 87518d7..d11db4b 100644
--- a/modules/imgproc/include/opencv2/imgproc/imgproc_c.h
+++ b/modules/imgproc/include/opencv2/imgproc/imgproc_c.h
@@ -40,8 +40,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_IMGPROC_IMGPROC_C_H__
-#define __OPENCV_IMGPROC_IMGPROC_C_H__
+#ifndef OPENCV_IMGPROC_IMGPROC_C_H
+#define OPENCV_IMGPROC_IMGPROC_C_H
 
 #include "opencv2/imgproc/types_c.h"
 
diff --git a/modules/imgproc/include/opencv2/imgproc/types_c.h b/modules/imgproc/include/opencv2/imgproc/types_c.h
index 5ecb460..eacba02 100644
--- a/modules/imgproc/include/opencv2/imgproc/types_c.h
+++ b/modules/imgproc/include/opencv2/imgproc/types_c.h
@@ -40,8 +40,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_IMGPROC_TYPES_C_H__
-#define __OPENCV_IMGPROC_TYPES_C_H__
+#ifndef OPENCV_IMGPROC_TYPES_C_H
+#define OPENCV_IMGPROC_TYPES_C_H
 
 #include "opencv2/core/core_c.h"
 
diff --git a/modules/imgproc/misc/java/src/java/imgproc+Moments.java b/modules/imgproc/misc/java/src/java/imgproc+Moments.java
index 431b025..2eeebc9 100644
--- a/modules/imgproc/misc/java/src/java/imgproc+Moments.java
+++ b/modules/imgproc/misc/java/src/java/imgproc+Moments.java
@@ -67,16 +67,16 @@ public class Moments {
 
     public void set(double[] vals) {
         if (vals != null) {
-            m00 = vals.length > 0 ? (int) vals[0] : 0;
-            m10 = vals.length > 1 ? (int) vals[1] : 0;
-            m01 = vals.length > 2 ? (int) vals[2] : 0;
-            m20 = vals.length > 3 ? (int) vals[3] : 0;
-            m11 = vals.length > 4 ? (int) vals[4] : 0;
-            m02 = vals.length > 5 ? (int) vals[5] : 0;
-            m30 = vals.length > 6 ? (int) vals[6] : 0;
-            m21 = vals.length > 7 ? (int) vals[7] : 0;
-            m12 = vals.length > 8 ? (int) vals[8] : 0;
-            m03 = vals.length > 9 ? (int) vals[9] : 0;
+            m00 = vals.length > 0 ? vals[0] : 0;
+            m10 = vals.length > 1 ? vals[1] : 0;
+            m01 = vals.length > 2 ? vals[2] : 0;
+            m20 = vals.length > 3 ? vals[3] : 0;
+            m11 = vals.length > 4 ? vals[4] : 0;
+            m02 = vals.length > 5 ? vals[5] : 0;
+            m30 = vals.length > 6 ? vals[6] : 0;
+            m21 = vals.length > 7 ? vals[7] : 0;
+            m12 = vals.length > 8 ? vals[8] : 0;
+            m03 = vals.length > 9 ? vals[9] : 0;
             this.completeState();
         } else {
             m00 = 0;
diff --git a/modules/imgproc/misc/java/test/ImgprocTest.java b/modules/imgproc/misc/java/test/ImgprocTest.java
index 0b06152..8a5ce2b 100644
--- a/modules/imgproc/misc/java/test/ImgprocTest.java
+++ b/modules/imgproc/misc/java/test/ImgprocTest.java
@@ -359,7 +359,7 @@ public class ImgprocTest extends OpenCVTestCase {
 
         double distance = Imgproc.compareHist(H1, H2, Imgproc.CV_COMP_CORREL);
 
-        assertEquals(1., distance);
+        assertEquals(1., distance, EPS);
     }
 
     public void testContourAreaMat() {
@@ -368,7 +368,7 @@ public class ImgprocTest extends OpenCVTestCase {
 
         double area = Imgproc.contourArea(contour);
 
-        assertEquals(45., area);
+        assertEquals(45., area, EPS);
     }
 
     public void testContourAreaMatBoolean() {
@@ -377,7 +377,7 @@ public class ImgprocTest extends OpenCVTestCase {
 
         double area = Imgproc.contourArea(contour, true);
 
-        assertEquals(45., area);
+        assertEquals(45., area, EPS);
         // TODO_: write better test
     }
 
@@ -1116,7 +1116,7 @@ public class ImgprocTest extends OpenCVTestCase {
 
         Imgproc.HoughLinesP(img, lines, 1, 3.1415926/180, 100);
 
-        assertEquals(2, lines.cols());
+        assertEquals(2, lines.rows());
 
         /*
         Log.d("HoughLinesP", "lines=" + lines);
@@ -1407,14 +1407,14 @@ public class ImgprocTest extends OpenCVTestCase {
     }
 
     public void testMinEnclosingCircle() {
-        MatOfPoint2f points = new MatOfPoint2f(new Point(0, 0), new Point(-1, 0), new Point(0, -1), new Point(1, 0), new Point(0, 1));
+        MatOfPoint2f points = new MatOfPoint2f(new Point(0, 0), new Point(-100, 0), new Point(0, -100), new Point(100, 0), new Point(0, 100));
         Point actualCenter = new Point();
         float[] radius = new float[1];
 
         Imgproc.minEnclosingCircle(points, actualCenter, radius);
 
         assertEquals(new Point(0, 0), actualCenter);
-        assertEquals(1.03f, radius[0], EPS);
+        assertEquals(100.0f, radius[0], 1.0);
     }
 
     public void testMomentsMat() {
diff --git a/modules/imgproc/perf/opencl/perf_imgproc.cpp b/modules/imgproc/perf/opencl/perf_imgproc.cpp
index f441bd9..6d9b1a0 100644
--- a/modules/imgproc/perf/opencl/perf_imgproc.cpp
+++ b/modules/imgproc/perf/opencl/perf_imgproc.cpp
@@ -299,33 +299,30 @@ OCL_PERF_TEST_P(CLAHEFixture, CLAHE, OCL_TEST_SIZES)
 
 ///////////// Canny ////////////////////////
 
-typedef tuple<int, bool> CannyParams;
+typedef tuple<Size, int, bool> CannyParams;
 typedef TestBaseWithParam<CannyParams> CannyFixture;
 
-OCL_PERF_TEST_P(CannyFixture, Canny, ::testing::Combine(OCL_PERF_ENUM(3, 5), Bool()))
+OCL_PERF_TEST_P(CannyFixture, Canny, ::testing::Combine(OCL_TEST_SIZES, OCL_PERF_ENUM(3, 5), Bool()))
 {
-    const CannyParams params = GetParam();
-    int apertureSize = get<0>(params);
-    bool L2Grad = get<1>(params);
+    const CannyParams& params = GetParam();
+    cv::Size imgSize = get<0>(params);
+    int apertureSize = get<1>(params);
+    bool L2Grad = get<2>(params);
 
     Mat _img = imread(getDataPath("gpu/stereobm/aloe-L.png"), cv::IMREAD_GRAYSCALE);
     ASSERT_TRUE(!_img.empty()) << "can't open aloe-L.png";
 
     UMat img;
-    _img.copyTo(img);
+    cv::resize(_img, img, imgSize);
     UMat edges(img.size(), CV_8UC1);
 
-    declare.in(img, WARMUP_RNG).out(edges);
+    declare.in(img).out(edges);
 
     OCL_TEST_CYCLE() cv::Canny(img, edges, 50.0, 100.0, apertureSize, L2Grad);
 
-    if (apertureSize == 3)
-        SANITY_CHECK(edges);
-    else
-        SANITY_CHECK_NOTHING();
+    SANITY_CHECK_NOTHING();
 }
 
-
 } } // namespace cvtest::ocl
 
 #endif // HAVE_OPENCL
diff --git a/modules/imgproc/perf/perf_blur.cpp b/modules/imgproc/perf/perf_blur.cpp
index 58a0c7c..2a284dc 100644
--- a/modules/imgproc/perf/perf_blur.cpp
+++ b/modules/imgproc/perf/perf_blur.cpp
@@ -100,9 +100,7 @@ PERF_TEST_P(Size_MatType_BorderType, blur16x16,
     BorderType btype = get<2>(GetParam());
     double eps = 1e-3;
 
-#if CV_NEON
     eps = CV_MAT_DEPTH(type) <= CV_32S ? 1 : eps;
-#endif
 
     Mat src(size, type);
     Mat dst(size, type);
diff --git a/modules/imgproc/perf/perf_houghLines.cpp b/modules/imgproc/perf/perf_houghLines.cpp
index 6dfaa56..96575ec 100644
--- a/modules/imgproc/perf/perf_houghLines.cpp
+++ b/modules/imgproc/perf/perf_houghLines.cpp
@@ -8,7 +8,7 @@ using namespace perf;
 using std::tr1::make_tuple;
 using std::tr1::get;
 
-typedef std::tr1::tuple<string, double, double, int> Image_RhoStep_ThetaStep_Threshold_t;
+typedef std::tr1::tuple<string, double, double, double> Image_RhoStep_ThetaStep_Threshold_t;
 typedef perf::TestBaseWithParam<Image_RhoStep_ThetaStep_Threshold_t> Image_RhoStep_ThetaStep_Threshold;
 
 PERF_TEST_P(Image_RhoStep_ThetaStep_Threshold, HoughLines,
@@ -16,30 +16,58 @@ PERF_TEST_P(Image_RhoStep_ThetaStep_Threshold, HoughLines,
                 testing::Values( "cv/shared/pic5.png", "stitching/a1.png" ),
                 testing::Values( 1, 10 ),
                 testing::Values( 0.01, 0.1 ),
-                testing::Values( 300, 500 )
+                testing::Values( 0.5, 1.1 )
                 )
             )
 {
     string filename = getDataPath(get<0>(GetParam()));
     double rhoStep = get<1>(GetParam());
     double thetaStep = get<2>(GetParam());
-    int threshold = get<3>(GetParam());
+    double threshold_ratio = get<3>(GetParam());
 
     Mat image = imread(filename, IMREAD_GRAYSCALE);
     if (image.empty())
         FAIL() << "Unable to load source image" << filename;
 
-    Canny(image, image, 0, 0);
+    Canny(image, image, 32, 128);
 
-    Mat lines;
+    // add some syntetic lines:
+    line(image, Point(0, 0), Point(image.cols, image.rows), Scalar::all(255), 3);
+    line(image, Point(image.cols, 0), Point(image.cols/2, image.rows), Scalar::all(255), 3);
+
+    vector<Vec2f> lines;
     declare.time(60);
 
+    int threshold = (int)(std::min(image.cols, image.rows) * threshold_ratio);
+
     TEST_CYCLE() HoughLines(image, lines, rhoStep, thetaStep, threshold);
 
-    transpose(lines, lines);
-#if (0 && defined(HAVE_IPP) && !defined(HAVE_IPP_ICV_ONLY) && IPP_VERSION_X100 >= 810)
-    SANITY_CHECK_NOTHING();
-#else
-    SANITY_CHECK(lines);
+    printf("%dx%d: %d lines\n", image.cols, image.rows, (int)lines.size());
+
+    if (threshold_ratio < 1.0)
+    {
+        EXPECT_GE(lines.size(), 2u);
+    }
+
+    EXPECT_LT(lines.size(), 3000u);
+
+#if 0
+    cv::cvtColor(image,image,cv::COLOR_GRAY2BGR);
+    for( size_t i = 0; i < lines.size(); i++ )
+    {
+        float rho = lines[i][0], theta = lines[i][1];
+        Point pt1, pt2;
+        double a = cos(theta), b = sin(theta);
+        double x0 = a*rho, y0 = b*rho;
+        pt1.x = cvRound(x0 + 1000*(-b));
+        pt1.y = cvRound(y0 + 1000*(a));
+        pt2.x = cvRound(x0 - 1000*(-b));
+        pt2.y = cvRound(y0 - 1000*(a));
+        line(image, pt1, pt2, Scalar(0,0,255), 1, cv::LINE_AA);
+    }
+    cv::imshow("result", image);
+    cv::waitKey();
 #endif
+
+    SANITY_CHECK_NOTHING();
 }
diff --git a/modules/imgproc/perf/perf_threshold.cpp b/modules/imgproc/perf/perf_threshold.cpp
index 9ccafd6..846f1a0 100644
--- a/modules/imgproc/perf/perf_threshold.cpp
+++ b/modules/imgproc/perf/perf_threshold.cpp
@@ -14,7 +14,7 @@ typedef perf::TestBaseWithParam<Size_MatType_ThreshType_t> Size_MatType_ThreshTy
 PERF_TEST_P(Size_MatType_ThreshType, threshold,
             testing::Combine(
                 testing::Values(TYPICAL_MAT_SIZES),
-                testing::Values(CV_8UC1, CV_16SC1),
+                testing::Values(CV_8UC1, CV_16SC1, CV_32FC1, CV_64FC1),
                 ThreshType::all()
                 )
             )
diff --git a/modules/imgproc/src/accum.cpp b/modules/imgproc/src/accum.cpp
index c7cbc40..8c457e3 100644
--- a/modules/imgproc/src/accum.cpp
+++ b/modules/imgproc/src/accum.cpp
@@ -43,48 +43,671 @@
 
 #include "precomp.hpp"
 #include "opencl_kernels_imgproc.hpp"
+#include "opencv2/core/hal/intrin.hpp"
+
+#include "opencv2/core/openvx/ovx_defs.hpp"
 
 namespace cv
 {
 
-template <typename T, typename AT>
-struct Acc_SIMD
+template <typename T, typename AT>
+struct Acc_SIMD
+{
+    int operator() (const T *, AT *, const uchar *, int, int) const
+    {
+        return 0;
+    }
+};
+
+template <typename T, typename AT>
+struct AccSqr_SIMD
+{
+    int operator() (const T *, AT *, const uchar *, int, int) const
+    {
+        return 0;
+    }
+};
+
+template <typename T, typename AT>
+struct AccProd_SIMD
+{
+    int operator() (const T *, const T *, AT *, const uchar *, int, int) const
+    {
+        return 0;
+    }
+};
+
+template <typename T, typename AT>
+struct AccW_SIMD
+{
+    int operator() (const T *, AT *, const uchar *, int, int, AT) const
+    {
+        return 0;
+    }
+};
+
+#if CV_AVX
+template <>
+struct Acc_SIMD<float, float>
+{
+    int operator() (const float * src, float * dst, const uchar * mask, int len, int cn) const
+    {
+        int x = 0;
+        if (!mask)
+        {
+            len *= cn;
+            for ( ; x <= len - 8 ; x += 8)
+            {
+                __m256 v_src = _mm256_loadu_ps(src + x);
+                __m256 v_dst = _mm256_loadu_ps(dst + x);
+                v_dst = _mm256_add_ps(v_src, v_dst);
+                _mm256_storeu_ps(dst + x, v_dst);
+            }
+        }
+        return x;
+    }
+};
+
+template <>
+struct Acc_SIMD<float, double>
+{
+    int operator() (const float * src, double * dst, const uchar * mask, int len, int cn) const
+    {
+        int x = 0;
+        if (!mask)
+        {
+            len *= cn;
+            for ( ; x <= len - 8 ; x += 8)
+            {
+                __m256 v_src = _mm256_loadu_ps(src + x);
+                __m256d v_src0 = _mm256_cvtps_pd(_mm256_extractf128_ps(v_src,0));
+                __m256d v_src1 = _mm256_cvtps_pd(_mm256_extractf128_ps(v_src,1));
+                __m256d v_dst0 = _mm256_loadu_pd(dst + x);
+                __m256d v_dst1 = _mm256_loadu_pd(dst + x + 4);
+                v_dst0 = _mm256_add_pd(v_src0, v_dst0);
+                v_dst1 = _mm256_add_pd(v_src1, v_dst1);
+                _mm256_storeu_pd(dst + x, v_dst0);
+                _mm256_storeu_pd(dst + x + 4, v_dst1);
+            }
+        }
+        return x;
+    }
+};
+
+template <>
+struct Acc_SIMD<double, double>
+{
+    int operator() (const double * src, double * dst, const uchar * mask, int len, int cn) const
+    {
+        int x = 0;
+
+        if (!mask)
+        {
+            len *= cn;
+            for ( ; x <= len - 4; x += 4)
+            {
+                __m256d v_src = _mm256_loadu_pd(src + x);
+                __m256d v_dst = _mm256_loadu_pd(dst + x);
+
+                v_dst = _mm256_add_pd(v_dst, v_src);
+                _mm256_storeu_pd(dst + x, v_dst);
+            }
+        }
+        return x;
+    }
+};
+
+template <>
+struct AccSqr_SIMD<float, float>
+{
+    int operator() (const float * src, float * dst, const uchar * mask, int len, int cn) const
+    {
+        int x = 0;
+        if (!mask)
+        {
+            len *= cn;
+            for ( ; x <= len - 8 ; x += 8)
+            {
+                __m256 v_src = _mm256_loadu_ps(src + x);
+                __m256 v_dst = _mm256_loadu_ps(dst + x);
+
+                v_src = _mm256_mul_ps(v_src, v_src);
+                v_dst = _mm256_add_ps(v_src, v_dst);
+                _mm256_storeu_ps(dst + x, v_dst);
+            }
+        }
+        return x;
+    }
+};
+
+template <>
+struct AccSqr_SIMD<float, double>
+{
+    int operator() (const float * src, double * dst, const uchar * mask, int len, int cn) const
+    {
+        int x = 0;
+        if (!mask)
+        {
+            len *= cn;
+            for ( ; x <= len - 8 ; x += 8)
+            {
+                __m256 v_src = _mm256_loadu_ps(src + x);
+                __m256d v_src0 = _mm256_cvtps_pd(_mm256_extractf128_ps(v_src,0));
+                __m256d v_src1 = _mm256_cvtps_pd(_mm256_extractf128_ps(v_src,1));
+                __m256d v_dst0 = _mm256_loadu_pd(dst + x);
+                __m256d v_dst1 = _mm256_loadu_pd(dst + x + 4);
+
+                v_src0 = _mm256_mul_pd(v_src0, v_src0);
+                v_src1 = _mm256_mul_pd(v_src1, v_src1);
+                v_dst0 = _mm256_add_pd(v_src0, v_dst0);
+                v_dst1 = _mm256_add_pd(v_src1, v_dst1);
+                _mm256_storeu_pd(dst + x, v_dst0);
+                _mm256_storeu_pd(dst + x + 4, v_dst1);
+            }
+        }
+        return x;
+    }
+};
+
+template <>
+struct AccSqr_SIMD<double, double>
+{
+    int operator() (const double * src, double * dst, const uchar * mask, int len, int cn) const
+    {
+        int x = 0;
+
+        if (!mask)
+        {
+            len *= cn;
+            for ( ; x <= len - 4; x += 4)
+            {
+                __m256d v_src = _mm256_loadu_pd(src + x);
+                __m256d v_dst = _mm256_loadu_pd(dst + x);
+
+                v_src = _mm256_mul_pd(v_src, v_src);
+                v_dst = _mm256_add_pd(v_dst, v_src);
+                _mm256_storeu_pd(dst + x, v_dst);
+            }
+        }
+        return x;
+    }
+};
+
+template <>
+struct AccProd_SIMD<float, float>
+{
+    int operator() (const float * src1, const float * src2, float * dst, const uchar * mask, int len, int cn) const
+    {
+        int x = 0;
+
+        if (!mask)
+        {
+            len *= cn;
+            for ( ; x <= len - 8; x += 8)
+            {
+                __m256 v_src0 = _mm256_loadu_ps(src1 + x);
+                __m256 v_src1 = _mm256_loadu_ps(src2 + x);
+                __m256 v_dst = _mm256_loadu_ps(dst + x);
+                __m256 v_src = _mm256_mul_ps(v_src0, v_src1);
+
+                v_dst = _mm256_add_ps(v_src, v_dst);
+                _mm256_storeu_ps(dst + x, v_dst);
+            }
+        }
+
+        return x;
+    }
+};
+
+template <>
+struct AccProd_SIMD<float, double>
+{
+    int operator() (const float * src1, const float * src2, double * dst, const uchar * mask, int len, int cn) const
+    {
+        int x = 0;
+
+        if (!mask)
+        {
+            len *= cn;
+            for ( ; x <= len - 8; x += 8)
+            {
+                __m256 v_1src = _mm256_loadu_ps(src1 + x);
+                __m256 v_2src = _mm256_loadu_ps(src2 + x);
+                __m256d v_src00 = _mm256_cvtps_pd(_mm256_extractf128_ps(v_1src,0));
+                __m256d v_src01 = _mm256_cvtps_pd(_mm256_extractf128_ps(v_1src,1));
+                __m256d v_src10 = _mm256_cvtps_pd(_mm256_extractf128_ps(v_2src,0));
+                __m256d v_src11 = _mm256_cvtps_pd(_mm256_extractf128_ps(v_2src,1));
+                __m256d v_dst0 = _mm256_loadu_pd(dst + x);
+                __m256d v_dst1 = _mm256_loadu_pd(dst + x + 4);
+
+                __m256d v_src0 = _mm256_mul_pd(v_src00, v_src10);
+                __m256d v_src1 = _mm256_mul_pd(v_src01, v_src11);
+                v_dst0 = _mm256_add_pd(v_src0, v_dst0);
+                v_dst1 = _mm256_add_pd(v_src1, v_dst1);
+                _mm256_storeu_pd(dst + x, v_dst0);
+                _mm256_storeu_pd(dst + x + 4, v_dst1);
+            }
+        }
+        return x;
+    }
+};
+
+template <>
+struct AccProd_SIMD<double, double>
+{
+    int operator() (const double * src1, const double * src2, double * dst, const uchar * mask, int len, int cn) const
+    {
+        int x = 0;
+
+        if (!mask)
+        {
+            len *= cn;
+            for ( ; x <= len - 4; x += 4)
+            {
+                __m256d v_src0 = _mm256_loadu_pd(src1 + x);
+                __m256d v_src1 = _mm256_loadu_pd(src2 + x);
+                __m256d v_dst = _mm256_loadu_pd(dst + x);
+
+                v_src0 = _mm256_mul_pd(v_src0, v_src1);
+                v_dst = _mm256_add_pd(v_dst, v_src0);
+                _mm256_storeu_pd(dst + x, v_dst);
+            }
+        }
+        return x;
+    }
+};
+
+template <>
+struct AccW_SIMD<float, float>
+{
+    int operator() (const float * src, float * dst, const uchar * mask, int len, int cn, float alpha) const
+    {
+        int x = 0;
+        __m256 v_alpha = _mm256_set1_ps(alpha);
+        __m256 v_beta = _mm256_set1_ps(1.0f - alpha);
+
+        if (!mask)
+        {
+            len *= cn;
+            for ( ; x <= len - 16; x += 16)
+            {
+                _mm256_storeu_ps(dst + x, _mm256_add_ps(_mm256_mul_ps(_mm256_loadu_ps(dst + x), v_beta), _mm256_mul_ps(_mm256_loadu_ps(src + x), v_alpha)));
+                _mm256_storeu_ps(dst + x + 8, _mm256_add_ps(_mm256_mul_ps(_mm256_loadu_ps(dst + x + 8), v_beta), _mm256_mul_ps(_mm256_loadu_ps(src + x + 8), v_alpha)));
+            }
+        }
+
+        return x;
+    }
+};
+
+template <>
+struct AccW_SIMD<float, double>
+{
+    int operator() (const float * src, double * dst, const uchar * mask, int len, int cn, double alpha) const
+    {
+        int x = 0;
+        __m256d v_alpha = _mm256_set1_pd(alpha);
+        __m256d v_beta = _mm256_set1_pd(1.0f - alpha);
+
+        if (!mask)
+        {
+            len *= cn;
+            for ( ; x <= len - 16; x += 16)
+            {
+                __m256 v_src0 = _mm256_loadu_ps(src + x);
+                __m256 v_src1 = _mm256_loadu_ps(src + x + 8);
+                __m256d v_src00 = _mm256_cvtps_pd(_mm256_extractf128_ps(v_src0,0));
+                __m256d v_src01 = _mm256_cvtps_pd(_mm256_extractf128_ps(v_src0,1));
+                __m256d v_src10 = _mm256_cvtps_pd(_mm256_extractf128_ps(v_src1,0));
+                __m256d v_src11 = _mm256_cvtps_pd(_mm256_extractf128_ps(v_src1,1));
+
+                _mm256_storeu_pd(dst + x, _mm256_add_pd(_mm256_mul_pd(_mm256_loadu_pd(dst + x), v_beta), _mm256_mul_pd(v_src00, v_alpha)));
+                _mm256_storeu_pd(dst + x + 4, _mm256_add_pd(_mm256_mul_pd(_mm256_loadu_pd(dst + x + 4), v_beta), _mm256_mul_pd(v_src01, v_alpha)));
+                _mm256_storeu_pd(dst + x + 8, _mm256_add_pd(_mm256_mul_pd(_mm256_loadu_pd(dst + x + 8), v_beta), _mm256_mul_pd(v_src10, v_alpha)));
+                _mm256_storeu_pd(dst + x + 12, _mm256_add_pd(_mm256_mul_pd(_mm256_loadu_pd(dst + x + 12), v_beta), _mm256_mul_pd(v_src11, v_alpha)));
+            }
+        }
+
+        return x;
+    }
+};
+
+template <>
+struct AccW_SIMD<double, double>
+{
+    int operator() (const double * src, double * dst, const uchar * mask, int len, int cn, double alpha) const
+    {
+        int x = 0;
+        __m256d v_alpha = _mm256_set1_pd(alpha);
+        __m256d v_beta = _mm256_set1_pd(1.0f - alpha);
+
+        if (!mask)
+        {
+            len *= cn;
+            for ( ; x <= len - 8; x += 8)
+            {
+                __m256d v_src0 = _mm256_loadu_pd(src + x);
+                __m256d v_src1 = _mm256_loadu_pd(src + x + 4);
+
+                _mm256_storeu_pd(dst + x, _mm256_add_pd(_mm256_mul_pd(_mm256_loadu_pd(dst + x), v_beta), _mm256_mul_pd(v_src0, v_alpha)));
+                _mm256_storeu_pd(dst + x + 4, _mm256_add_pd(_mm256_mul_pd(_mm256_loadu_pd(dst + x + 4), v_beta), _mm256_mul_pd(v_src1, v_alpha)));
+            }
+        }
+
+        return x;
+    }
+};
+#elif CV_SIMD128
+template <>
+struct Acc_SIMD<float, float>
+{
+    int operator() (const float * src, float * dst, const uchar * mask, int len, int cn) const
+    {
+        int x = 0;
+
+        if (!mask)
+        {
+            len *= cn;
+            for ( ; x <= len - 8; x += 8)
+            {
+                v_store(dst + x, v_load(dst + x) + v_load(src + x));
+                v_store(dst + x + 4, v_load(dst + x + 4) + v_load(src + x + 4));
+            }
+        }
+
+        return x;
+    }
+};
+
+#if CV_SIMD128_64F
+template <>
+struct Acc_SIMD<float, double>
+{
+    int operator() (const float * src, double * dst, const uchar * mask, int len, int cn) const
+    {
+        int x = 0;
+
+        if (!mask)
+        {
+            len *= cn;
+            for ( ; x <= len - 4; x += 4)
+            {
+                v_float32x4 v_src = v_load(src + x);
+                v_float64x2 v_src0 = v_cvt_f64(v_src);
+                v_float64x2 v_src1 = v_cvt_f64_high(v_src);
+
+                v_store(dst + x, v_load(dst + x) + v_src0);
+                v_store(dst + x + 2, v_load(dst + x + 2) + v_src1);
+            }
+        }
+        return x;
+    }
+};
+
+template <>
+struct Acc_SIMD<double, double>
+{
+    int operator() (const double * src, double * dst, const uchar * mask, int len, int cn) const
+    {
+        int x = 0;
+
+        if (!mask)
+        {
+            len *= cn;
+            for ( ; x <= len - 4; x += 4)
+            {
+                v_float64x2 v_src0 = v_load(src + x);
+                v_float64x2 v_src1 = v_load(src + x + 2);
+
+                v_store(dst + x, v_load(dst + x) + v_src0);
+                v_store(dst + x + 2, v_load(dst + x + 2) + v_src1);
+            }
+        }
+        return x;
+    }
+};
+#endif //CV_SIMD128_64F
+
+template <>
+struct AccSqr_SIMD<float, float>
+{
+    int operator() (const float * src, float * dst, const uchar * mask, int len, int cn) const
+    {
+        int x = 0;
+
+        if (!mask)
+        {
+            len *= cn;
+            for ( ; x <= len - 8; x += 8)
+            {
+                v_float32x4 v_src0 = v_load(src + x);
+                v_float32x4 v_src1 = v_load(src + x + 4);
+                v_src0 = v_src0 * v_src0;
+                v_src1 = v_src1 * v_src1;
+
+                v_store(dst + x, v_load(dst + x) + v_src0);
+                v_store(dst + x + 4, v_load(dst + x + 4) + v_src1);
+            }
+        }
+
+        return x;
+    }
+};
+
+#if CV_SIMD128_64F
+template <>
+struct AccSqr_SIMD<float, double>
+{
+    int operator() (const float * src, double * dst, const uchar * mask, int len, int cn) const
+    {
+        int x = 0;
+
+        if (!mask)
+        {
+            len *= cn;
+            for ( ; x <= len - 4; x += 4)
+            {
+                v_float32x4 v_src = v_load(src + x);
+                v_float64x2 v_src0 = v_cvt_f64(v_src);
+                v_float64x2 v_src1 = v_cvt_f64_high(v_src);
+                v_src0 = v_src0 * v_src0;
+                v_src1 = v_src1 * v_src1;
+
+                v_store(dst + x, v_load(dst + x) + v_src0);
+                v_store(dst + x + 2, v_load(dst + x + 2) + v_src1);
+            }
+        }
+        return x;
+    }
+};
+
+template <>
+struct AccSqr_SIMD<double, double>
+{
+    int operator() (const double * src, double * dst, const uchar * mask, int len, int cn) const
+    {
+        int x = 0;
+
+        if (!mask)
+        {
+            len *= cn;
+            for ( ; x <= len - 4; x += 4)
+            {
+                v_float64x2 v_src0 = v_load(src + x);
+                v_float64x2 v_src1 = v_load(src + x + 2);
+                v_src0 = v_src0 * v_src0;
+                v_src1 = v_src1 * v_src1;
+
+                v_store(dst + x, v_load(dst + x) + v_src0);
+                v_store(dst + x + 2, v_load(dst + x + 2) + v_src1);
+            }
+        }
+        return x;
+    }
+};
+#endif //CV_SIMD128_64F
+
+template <>
+struct AccProd_SIMD<float, float>
+{
+    int operator() (const float * src1, const float * src2, float * dst, const uchar * mask, int len, int cn) const
+    {
+        int x = 0;
+
+        if (!mask)
+        {
+            len *= cn;
+            for ( ; x <= len - 8; x += 8)
+            {
+                v_store(dst + x, v_load(dst + x) + v_load(src1 + x) * v_load(src2 + x));
+                v_store(dst + x + 4, v_load(dst + x + 4) + v_load(src1 + x + 4) * v_load(src2 + x + 4));
+            }
+        }
+
+        return x;
+    }
+};
+
+#if CV_SIMD128_64F
+template <>
+struct AccProd_SIMD<float, double>
 {
-    int operator() (const T *, AT *, const uchar *, int, int) const
+    int operator() (const float * src1, const float * src2, double * dst, const uchar * mask, int len, int cn) const
     {
-        return 0;
+        int x = 0;
+
+        if (!mask)
+        {
+            len *= cn;
+            for ( ; x <= len - 4; x += 4)
+            {
+                v_float32x4 v_1src  = v_load(src1 + x);
+                v_float32x4 v_2src  = v_load(src2 + x);
+
+                v_float64x2 v_1src0 = v_cvt_f64(v_1src);
+                v_float64x2 v_1src1 = v_cvt_f64_high(v_1src);
+                v_float64x2 v_2src0 = v_cvt_f64(v_2src);
+                v_float64x2 v_2src1 = v_cvt_f64_high(v_2src);
+
+                v_store(dst + x, v_load(dst + x) + (v_1src0 * v_2src0));
+                v_store(dst + x + 2, v_load(dst + x + 2) + (v_1src1 * v_2src1));
+            }
+        }
+        return x;
     }
 };
 
-template <typename T, typename AT>
-struct AccSqr_SIMD
+template <>
+struct AccProd_SIMD<double, double>
 {
-    int operator() (const T *, AT *, const uchar *, int, int) const
+    int operator() (const double * src1, const double * src2, double * dst, const uchar * mask, int len, int cn) const
     {
-        return 0;
+        int x = 0;
+
+        if (!mask)
+        {
+            len *= cn;
+            for ( ; x <= len - 4; x += 4)
+            {
+                v_float64x2 v_src00 = v_load(src1 + x);
+                v_float64x2 v_src01 = v_load(src1 + x + 2);
+                v_float64x2 v_src10 = v_load(src2 + x);
+                v_float64x2 v_src11 = v_load(src2 + x + 2);
+
+                v_store(dst + x, v_load(dst + x) + (v_src00 * v_src10));
+                v_store(dst + x + 2, v_load(dst + x + 2) + (v_src01 * v_src11));
+            }
+        }
+        return x;
     }
 };
+#endif //CV_SIMD128_64F
 
-template <typename T, typename AT>
-struct AccProd_SIMD
+template <>
+struct AccW_SIMD<float, float>
 {
-    int operator() (const T *, const T *, AT *, const uchar *, int, int) const
+    int operator() (const float * src, float * dst, const uchar * mask, int len, int cn, float alpha) const
     {
-        return 0;
+        int x = 0;
+        v_float32x4 v_alpha = v_setall_f32(alpha);
+        v_float32x4 v_beta = v_setall_f32(1.0f - alpha);
+
+        if (!mask)
+        {
+            len *= cn;
+            for ( ; x <= len - 8; x += 8)
+            {
+                v_store(dst + x, ((v_load(dst + x) * v_beta) + (v_load(src + x) * v_alpha)));
+                v_store(dst + x + 4, ((v_load(dst + x + 4) * v_beta) + (v_load(src + x + 4) * v_alpha)));
+            }
+        }
+
+        return x;
     }
 };
 
-template <typename T, typename AT>
-struct AccW_SIMD
+#if CV_SIMD128_64F
+template <>
+struct AccW_SIMD<float, double>
 {
-    int operator() (const T *, AT *, const uchar *, int, int, AT) const
+    int operator() (const float * src, double * dst, const uchar * mask, int len, int cn, double alpha) const
     {
-        return 0;
+        int x = 0;
+        v_float64x2 v_alpha = v_setall_f64(alpha);
+        v_float64x2 v_beta = v_setall_f64(1.0f - alpha);
+
+        if (!mask)
+        {
+            len *= cn;
+            for ( ; x <= len - 8; x += 8)
+            {
+                v_float32x4 v_src0 = v_load(src + x);
+                v_float32x4 v_src1 = v_load(src + x + 4);
+                v_float64x2 v_src00 = v_cvt_f64(v_src0);
+                v_float64x2 v_src01 = v_cvt_f64_high(v_src0);
+                v_float64x2 v_src10 = v_cvt_f64(v_src1);
+                v_float64x2 v_src11 = v_cvt_f64_high(v_src1);
+
+                v_store(dst + x, ((v_load(dst + x) * v_beta) + (v_src00 * v_alpha)));
+                v_store(dst + x + 2, ((v_load(dst + x + 2) * v_beta) + (v_src01 * v_alpha)));
+                v_store(dst + x + 4, ((v_load(dst + x + 4) * v_beta) + (v_src10 * v_alpha)));
+                v_store(dst + x + 6, ((v_load(dst + x + 6) * v_beta) + (v_src11 * v_alpha)));
+            }
+        }
+
+        return x;
     }
 };
 
-#if CV_NEON
+template <>
+struct AccW_SIMD<double, double>
+{
+    int operator() (const double * src, double * dst, const uchar * mask, int len, int cn, double alpha) const
+    {
+        int x = 0;
+        v_float64x2 v_alpha = v_setall_f64(alpha);
+        v_float64x2 v_beta = v_setall_f64(1.0f - alpha);
+
+        if (!mask)
+        {
+            len *= cn;
+            for ( ; x <= len - 4; x += 4)
+            {
+                v_float64x2 v_src0 = v_load(src + x);
+                v_float64x2 v_src1 = v_load(src + x + 2);
+
+                v_store(dst + x, ((v_load(dst + x) * v_beta) + (v_src0 * v_alpha)));
+                v_store(dst + x + 2, ((v_load(dst + x + 2) * v_beta) + (v_src1 * v_alpha)));
+            }
+        }
+
+        return x;
+    }
+};
+#endif //CV_SIMD128_64F
+#endif //CV_SIMD128
 
+#if CV_SIMD128
 template <>
 struct Acc_SIMD<uchar, float>
 {
@@ -97,28 +720,41 @@ struct Acc_SIMD<uchar, float>
             len *= cn;
             for ( ; x <= len - 16; x += 16)
             {
-                uint8x16_t v_src = vld1q_u8(src + x);
-                uint16x8_t v_src0 = vmovl_u8(vget_low_u8(v_src)), v_src1 = vmovl_u8(vget_high_u8(v_src));
-
-                vst1q_f32(dst + x, vaddq_f32(vld1q_f32(dst + x), vcvtq_f32_u32(vmovl_u16(vget_low_u16(v_src0)))));
-                vst1q_f32(dst + x + 4, vaddq_f32(vld1q_f32(dst + x + 4), vcvtq_f32_u32(vmovl_u16(vget_high_u16(v_src0)))));
-                vst1q_f32(dst + x + 8, vaddq_f32(vld1q_f32(dst + x + 8), vcvtq_f32_u32(vmovl_u16(vget_low_u16(v_src1)))));
-                vst1q_f32(dst + x + 12, vaddq_f32(vld1q_f32(dst + x + 12), vcvtq_f32_u32(vmovl_u16(vget_high_u16(v_src1)))));
+                v_uint8x16 v_src  = v_load(src + x);
+                v_uint16x8 v_src0, v_src1;
+                v_expand(v_src, v_src0, v_src1);
+
+                v_uint32x4 v_src00, v_src01, v_src10, v_src11;
+                v_expand(v_src0, v_src00, v_src01);
+                v_expand(v_src1, v_src10, v_src11);
+
+                v_store(dst + x, v_load(dst + x) + v_cvt_f32(v_reinterpret_as_s32(v_src00)));
+                v_store(dst + x + 4, v_load(dst + x + 4) + v_cvt_f32(v_reinterpret_as_s32(v_src01)));
+                v_store(dst + x + 8, v_load(dst + x + 8) + v_cvt_f32(v_reinterpret_as_s32(v_src10)));
+                v_store(dst + x + 12, v_load(dst + x + 12) + v_cvt_f32(v_reinterpret_as_s32(v_src11)));
             }
         }
         else if (cn == 1)
         {
-            uint8x16_t v_255 = vdupq_n_u8(255), v_0 = vdupq_n_u8(0);
+            v_uint8x16 v_0 = v_setall_u8(0);
 
             for ( ; x <= len - 16; x += 16)
             {
-                uint8x16_t v_src = vandq_u8(vld1q_u8(src + x), veorq_u8(v_255, vceqq_u8(vld1q_u8(mask + x), v_0)));
-                uint16x8_t v_src0 = vmovl_u8(vget_low_u8(v_src)), v_src1 = vmovl_u8(vget_high_u8(v_src));
-
-                vst1q_f32(dst + x, vaddq_f32(vld1q_f32(dst + x), vcvtq_f32_u32(vmovl_u16(vget_low_u16(v_src0)))));
-                vst1q_f32(dst + x + 4, vaddq_f32(vld1q_f32(dst + x + 4), vcvtq_f32_u32(vmovl_u16(vget_high_u16(v_src0)))));
-                vst1q_f32(dst + x + 8, vaddq_f32(vld1q_f32(dst + x + 8), vcvtq_f32_u32(vmovl_u16(vget_low_u16(v_src1)))));
-                vst1q_f32(dst + x + 12, vaddq_f32(vld1q_f32(dst + x + 12), vcvtq_f32_u32(vmovl_u16(vget_high_u16(v_src1)))));
+                v_uint8x16 v_mask = v_load(mask + x);
+                v_mask = ~(v_0 == v_mask);
+                v_uint8x16 v_src = v_load(src + x);
+                v_src = v_src & v_mask;
+                v_uint16x8 v_src0, v_src1;
+                v_expand(v_src, v_src0, v_src1);
+
+                v_uint32x4 v_src00, v_src01, v_src10, v_src11;
+                v_expand(v_src0, v_src00, v_src01);
+                v_expand(v_src1, v_src10, v_src11);
+
+                v_store(dst + x, v_load(dst + x) + v_cvt_f32(v_reinterpret_as_s32(v_src00)));
+                v_store(dst + x + 4, v_load(dst + x + 4) + v_cvt_f32(v_reinterpret_as_s32(v_src01)));
+                v_store(dst + x + 8, v_load(dst + x + 8) + v_cvt_f32(v_reinterpret_as_s32(v_src10)));
+                v_store(dst + x + 12, v_load(dst + x + 12) + v_cvt_f32(v_reinterpret_as_s32(v_src11)));
             }
         }
 
@@ -132,17 +768,17 @@ struct Acc_SIMD<ushort, float>
     int operator() (const ushort * src, float * dst, const uchar * mask, int len, int cn) const
     {
         int x = 0;
-
         if (!mask)
         {
             len *= cn;
             for ( ; x <= len - 8; x += 8)
             {
-                uint16x8_t v_src = vld1q_u16(src + x);
-                uint32x4_t v_src0 = vmovl_u16(vget_low_u16(v_src)), v_src1 = vmovl_u16(vget_high_u16(v_src));
+                v_uint16x8 v_src = v_load(src + x);
+                v_uint32x4 v_src0, v_src1;
+                v_expand(v_src, v_src0, v_src1);
 
-                vst1q_f32(dst + x, vaddq_f32(vld1q_f32(dst + x), vcvtq_f32_u32(v_src0)));
-                vst1q_f32(dst + x + 4, vaddq_f32(vld1q_f32(dst + x + 4), vcvtq_f32_u32(v_src1)));
+                v_store(dst + x, v_load(dst + x) + v_cvt_f32(v_reinterpret_as_s32(v_src0)));
+                v_store(dst + x + 4, v_load(dst + x + 4) + v_cvt_f32(v_reinterpret_as_s32(v_src1)));
             }
         }
 
@@ -150,26 +786,109 @@ struct Acc_SIMD<ushort, float>
     }
 };
 
+#if CV_SIMD128_64F
 template <>
-struct Acc_SIMD<float, float>
+struct Acc_SIMD<uchar, double>
 {
-    int operator() (const float * src, float * dst, const uchar * mask, int len, int cn) const
+    int operator() (const uchar * src, double * dst, const uchar * mask, int len, int cn) const
     {
         int x = 0;
 
         if (!mask)
         {
             len *= cn;
-            for ( ; x <= len - 8; x += 8)
+            for ( ; x <= len - 16; x += 16)
             {
-                vst1q_f32(dst + x, vaddq_f32(vld1q_f32(dst + x), vld1q_f32(src + x)));
-                vst1q_f32(dst + x + 4, vaddq_f32(vld1q_f32(dst + x + 4), vld1q_f32(src + x + 4)));
+                v_uint8x16 v_src  = v_load(src + x);
+                v_uint16x8 v_int0, v_int1;
+                v_expand(v_src, v_int0, v_int1);
+
+                v_uint32x4 v_int00, v_int01, v_int10, v_int11;
+                v_expand(v_int0, v_int00, v_int01);
+                v_expand(v_int1, v_int10, v_int11);
+
+                v_float64x2 v_src0 = v_cvt_f64(v_reinterpret_as_s32(v_int00));
+                v_float64x2 v_src1 = v_cvt_f64_high(v_reinterpret_as_s32(v_int00));
+                v_float64x2 v_src2 = v_cvt_f64(v_reinterpret_as_s32(v_int01));
+                v_float64x2 v_src3 = v_cvt_f64_high(v_reinterpret_as_s32(v_int01));
+                v_float64x2 v_src4 = v_cvt_f64(v_reinterpret_as_s32(v_int10));
+                v_float64x2 v_src5 = v_cvt_f64_high(v_reinterpret_as_s32(v_int10));
+                v_float64x2 v_src6 = v_cvt_f64(v_reinterpret_as_s32(v_int11));
+                v_float64x2 v_src7 = v_cvt_f64_high(v_reinterpret_as_s32(v_int11));
+
+                v_float64x2 v_dst0 = v_load(dst + x);
+                v_float64x2 v_dst1 = v_load(dst + x + 2);
+                v_float64x2 v_dst2 = v_load(dst + x + 4);
+                v_float64x2 v_dst3 = v_load(dst + x + 6);
+                v_float64x2 v_dst4 = v_load(dst + x + 8);
+                v_float64x2 v_dst5 = v_load(dst + x + 10);
+                v_float64x2 v_dst6 = v_load(dst + x + 12);
+                v_float64x2 v_dst7 = v_load(dst + x + 14);
+
+                v_dst0 = v_dst0 + v_src0;
+                v_dst1 = v_dst1 + v_src1;
+                v_dst2 = v_dst2 + v_src2;
+                v_dst3 = v_dst3 + v_src3;
+                v_dst4 = v_dst4 + v_src4;
+                v_dst5 = v_dst5 + v_src5;
+                v_dst6 = v_dst6 + v_src6;
+                v_dst7 = v_dst7 + v_src7;
+
+                v_store(dst + x, v_dst0);
+                v_store(dst + x + 2, v_dst1);
+                v_store(dst + x + 4, v_dst2);
+                v_store(dst + x + 6, v_dst3);
+                v_store(dst + x + 8, v_dst4);
+                v_store(dst + x + 10, v_dst5);
+                v_store(dst + x + 12, v_dst6);
+                v_store(dst + x + 14, v_dst7);
             }
         }
+        return x;
+    }
+};
+
+template <>
+struct Acc_SIMD<ushort, double>
+{
+    int operator() (const ushort * src, double * dst, const uchar * mask, int len, int cn) const
+    {
+        int x = 0;
 
+        if (!mask)
+        {
+            len *= cn;
+            for ( ; x <= len - 8; x += 8)
+            {
+                v_uint16x8 v_src  = v_load(src + x);
+                v_uint32x4 v_int0, v_int1;
+                v_expand(v_src, v_int0, v_int1);
+
+                v_float64x2 v_src0 = v_cvt_f64(v_reinterpret_as_s32(v_int0));
+                v_float64x2 v_src1 = v_cvt_f64_high(v_reinterpret_as_s32(v_int0));
+                v_float64x2 v_src2 = v_cvt_f64(v_reinterpret_as_s32(v_int1));
+                v_float64x2 v_src3 = v_cvt_f64_high(v_reinterpret_as_s32(v_int1));
+
+                v_float64x2 v_dst0 = v_load(dst + x);
+                v_float64x2 v_dst1 = v_load(dst + x + 2);
+                v_float64x2 v_dst2 = v_load(dst + x + 4);
+                v_float64x2 v_dst3 = v_load(dst + x + 6);
+
+                v_dst0 = v_dst0 + v_src0;
+                v_dst1 = v_dst1 + v_src1;
+                v_dst2 = v_dst2 + v_src2;
+                v_dst3 = v_dst3 + v_src3;
+
+                v_store(dst + x, v_dst0);
+                v_store(dst + x + 2, v_dst1);
+                v_store(dst + x + 4, v_dst2);
+                v_store(dst + x + 6, v_dst3);
+            }
+        }
         return x;
     }
 };
+#endif
 
 template <>
 struct AccSqr_SIMD<uchar, float>
@@ -183,30 +902,44 @@ struct AccSqr_SIMD<uchar, float>
             len *= cn;
             for ( ; x <= len - 16; x += 16)
             {
-                uint8x16_t v_src = vld1q_u8(src + x);
-                uint8x8_t v_src_0 = vget_low_u8(v_src), v_src_1 = vget_high_u8(v_src);
-                uint16x8_t v_src0 = vmull_u8(v_src_0, v_src_0), v_src1 = vmull_u8(v_src_1, v_src_1);
-
-                vst1q_f32(dst + x, vaddq_f32(vld1q_f32(dst + x), vcvtq_f32_u32(vmovl_u16(vget_low_u16(v_src0)))));
-                vst1q_f32(dst + x + 4, vaddq_f32(vld1q_f32(dst + x + 4), vcvtq_f32_u32(vmovl_u16(vget_high_u16(v_src0)))));
-                vst1q_f32(dst + x + 8, vaddq_f32(vld1q_f32(dst + x + 8), vcvtq_f32_u32(vmovl_u16(vget_low_u16(v_src1)))));
-                vst1q_f32(dst + x + 12, vaddq_f32(vld1q_f32(dst + x + 12), vcvtq_f32_u32(vmovl_u16(vget_high_u16(v_src1)))));
+                v_uint8x16 v_src  = v_load(src + x);
+                v_uint16x8 v_src0, v_src1;
+                v_expand(v_src, v_src0, v_src1);
+                v_src0 = v_src0 * v_src0;
+                v_src1 = v_src1 * v_src1;
+
+                v_uint32x4 v_src00, v_src01, v_src10, v_src11;
+                v_expand(v_src0, v_src00, v_src01);
+                v_expand(v_src1, v_src10, v_src11);
+
+                v_store(dst + x, v_load(dst + x) + v_cvt_f32(v_reinterpret_as_s32(v_src00)));
+                v_store(dst + x + 4, v_load(dst + x + 4) + v_cvt_f32(v_reinterpret_as_s32(v_src01)));
+                v_store(dst + x + 8, v_load(dst + x + 8) + v_cvt_f32(v_reinterpret_as_s32(v_src10)));
+                v_store(dst + x + 12, v_load(dst + x + 12) + v_cvt_f32(v_reinterpret_as_s32(v_src11)));
             }
         }
         else if (cn == 1)
         {
-            uint8x16_t v_255 = vdupq_n_u8(255), v_0 = vdupq_n_u8(0);
-
+            v_uint8x16 v_0 = v_setall_u8(0);
             for ( ; x <= len - 16; x += 16)
             {
-                uint8x16_t v_src = vandq_u8(vld1q_u8(src + x), veorq_u8(v_255, vceqq_u8(vld1q_u8(mask + x), v_0)));
-                uint8x8_t v_src_0 = vget_low_u8(v_src), v_src_1 = vget_high_u8(v_src);
-                uint16x8_t v_src0 = vmull_u8(v_src_0, v_src_0), v_src1 = vmull_u8(v_src_1, v_src_1);
-
-                vst1q_f32(dst + x, vaddq_f32(vld1q_f32(dst + x), vcvtq_f32_u32(vmovl_u16(vget_low_u16(v_src0)))));
-                vst1q_f32(dst + x + 4, vaddq_f32(vld1q_f32(dst + x + 4), vcvtq_f32_u32(vmovl_u16(vget_high_u16(v_src0)))));
-                vst1q_f32(dst + x + 8, vaddq_f32(vld1q_f32(dst + x + 8), vcvtq_f32_u32(vmovl_u16(vget_low_u16(v_src1)))));
-                vst1q_f32(dst + x + 12, vaddq_f32(vld1q_f32(dst + x + 12), vcvtq_f32_u32(vmovl_u16(vget_high_u16(v_src1)))));
+                v_uint8x16 v_mask = v_load(mask + x);
+                v_mask = ~(v_0 == v_mask);
+                v_uint8x16 v_src = v_load(src + x);
+                v_src = v_src & v_mask;
+                v_uint16x8 v_src0, v_src1;
+                v_expand(v_src, v_src0, v_src1);
+                v_src0 = v_src0 * v_src0;
+                v_src1 = v_src1 * v_src1;
+
+                v_uint32x4 v_src00, v_src01, v_src10, v_src11;
+                v_expand(v_src0, v_src00, v_src01);
+                v_expand(v_src1, v_src10, v_src11);
+
+                v_store(dst + x, v_load(dst + x) + v_cvt_f32(v_reinterpret_as_s32(v_src00)));
+                v_store(dst + x + 4, v_load(dst + x + 4) + v_cvt_f32(v_reinterpret_as_s32(v_src01)));
+                v_store(dst + x + 8, v_load(dst + x + 8) + v_cvt_f32(v_reinterpret_as_s32(v_src10)));
+                v_store(dst + x + 12, v_load(dst + x + 12) + v_cvt_f32(v_reinterpret_as_s32(v_src11)));
             }
         }
 
@@ -226,41 +959,78 @@ struct AccSqr_SIMD<ushort, float>
             len *= cn;
             for ( ; x <= len - 8; x += 8)
             {
-                uint16x8_t v_src = vld1q_u16(src + x);
-                uint16x4_t v_src_0 = vget_low_u16(v_src), v_src_1 = vget_high_u16(v_src);
-                uint32x4_t v_src0 = vmull_u16(v_src_0, v_src_0), v_src1 = vmull_u16(v_src_1, v_src_1);
-
-                vst1q_f32(dst + x, vaddq_f32(vld1q_f32(dst + x), vcvtq_f32_u32(v_src0)));
-                vst1q_f32(dst + x + 4, vaddq_f32(vld1q_f32(dst + x + 4), vcvtq_f32_u32(v_src1)));
+                v_uint16x8 v_src = v_load(src + x);
+                v_uint32x4 v_src0, v_src1;
+                v_expand(v_src, v_src0, v_src1);
+
+                v_float32x4 v_float0, v_float1;
+                v_float0 = v_cvt_f32(v_reinterpret_as_s32(v_src0));
+                v_float1 = v_cvt_f32(v_reinterpret_as_s32(v_src1));
+                v_float0 = v_float0 * v_float0;
+                v_float1 = v_float1 * v_float1;
+
+                v_store(dst + x, v_load(dst + x) + v_float0);
+                v_store(dst + x + 4, v_load(dst + x + 4) + v_float1);
             }
         }
-        else if (cn == 1)
-        {
-            uint8x8_t v_255 = vdup_n_u8(255), v_0 = vdup_n_u8(0);
 
-            for ( ; x <= len - 8; x += 8)
-            {
-                uint8x8_t v_mask_src = veor_u8(v_255, vceq_u8(vld1_u8(mask + x), v_0));
-                uint8x8x2_t v_mask_zp = vzip_u8(v_mask_src, v_mask_src);
-                uint16x8_t v_mask = vreinterpretq_u16_u8(vcombine_u8(v_mask_zp.val[0], v_mask_zp.val[1])),
-                           v_src = vandq_u16(vld1q_u16(src + x), v_mask);
+        return x;
+    }
+};
 
-                uint16x4_t v_src_0 = vget_low_u16(v_src), v_src_1 = vget_high_u16(v_src);
-                uint32x4_t v_src0 = vmull_u16(v_src_0, v_src_0), v_src1 = vmull_u16(v_src_1, v_src_1);
+#if CV_SIMD128_64F
+template <>
+struct AccSqr_SIMD<uchar, double>
+{
+    int operator() (const uchar * src, double * dst, const uchar * mask, int len, int cn) const
+    {
+        int x = 0;
 
-                vst1q_f32(dst + x, vaddq_f32(vld1q_f32(dst + x), vcvtq_f32_u32(v_src0)));
-                vst1q_f32(dst + x + 4, vaddq_f32(vld1q_f32(dst + x + 4), vcvtq_f32_u32(v_src1)));
+        if (!mask)
+        {
+            len *= cn;
+            for ( ; x <= len - 8; x += 8)
+            {
+                v_uint8x16 v_src = v_load(src + x);
+                v_uint16x8 v_int, dummy;
+                v_expand(v_src, v_int, dummy);
+
+                v_uint32x4 v_int0, v_int1;
+                v_expand(v_int, v_int0, v_int1);
+
+                v_float64x2 v_src0 = v_cvt_f64(v_reinterpret_as_s32(v_int0));
+                v_float64x2 v_src1 = v_cvt_f64_high(v_reinterpret_as_s32(v_int0));
+                v_float64x2 v_src2 = v_cvt_f64(v_reinterpret_as_s32(v_int1));
+                v_float64x2 v_src3 = v_cvt_f64_high(v_reinterpret_as_s32(v_int1));
+                v_src0 = v_src0 * v_src0;
+                v_src1 = v_src1 * v_src1;
+                v_src2 = v_src2 * v_src2;
+                v_src3 = v_src3 * v_src3;
+
+                v_float64x2 v_dst0 = v_load(dst + x);
+                v_float64x2 v_dst1 = v_load(dst + x + 2);
+                v_float64x2 v_dst2 = v_load(dst + x + 4);
+                v_float64x2 v_dst3 = v_load(dst + x + 6);
+
+                v_dst0 += v_src0;
+                v_dst1 += v_src1;
+                v_dst2 += v_src2;
+                v_dst3 += v_src3;
+
+                v_store(dst + x, v_dst0);
+                v_store(dst + x + 2, v_dst1);
+                v_store(dst + x + 4, v_dst2);
+                v_store(dst + x + 6, v_dst3);
             }
         }
-
         return x;
     }
 };
 
 template <>
-struct AccSqr_SIMD<float, float>
+struct AccSqr_SIMD<ushort, double>
 {
-    int operator() (const float * src, float * dst, const uchar * mask, int len, int cn) const
+    int operator() (const ushort * src, double * dst, const uchar * mask, int len, int cn) const
     {
         int x = 0;
 
@@ -269,17 +1039,42 @@ struct AccSqr_SIMD<float, float>
             len *= cn;
             for ( ; x <= len - 8; x += 8)
             {
-                float32x4_t v_src = vld1q_f32(src + x);
-                vst1q_f32(dst + x, vmlaq_f32(vld1q_f32(dst + x), v_src, v_src));
-
-                v_src = vld1q_f32(src + x + 4);
-                vst1q_f32(dst + x + 4, vmlaq_f32(vld1q_f32(dst + x + 4), v_src, v_src));
+                v_uint16x8 v_src  = v_load(src + x);
+                v_uint32x4 v_int_0, v_int_1;
+                v_expand(v_src, v_int_0, v_int_1);
+
+                v_int32x4 v_int0 = v_reinterpret_as_s32(v_int_0);
+                v_int32x4 v_int1 = v_reinterpret_as_s32(v_int_1);
+
+                v_float64x2 v_src0 = v_cvt_f64(v_int0);
+                v_float64x2 v_src1 = v_cvt_f64_high(v_int0);
+                v_float64x2 v_src2 = v_cvt_f64(v_int1);
+                v_float64x2 v_src3 = v_cvt_f64_high(v_int1);
+                v_src0 = v_src0 * v_src0;
+                v_src1 = v_src1 * v_src1;
+                v_src2 = v_src2 * v_src2;
+                v_src3 = v_src3 * v_src3;
+
+                v_float64x2 v_dst0 = v_load(dst + x);
+                v_float64x2 v_dst1 = v_load(dst + x + 2);
+                v_float64x2 v_dst2 = v_load(dst + x + 4);
+                v_float64x2 v_dst3 = v_load(dst + x + 6);
+
+                v_dst0 += v_src0;
+                v_dst1 += v_src1;
+                v_dst2 += v_src2;
+                v_dst3 += v_src3;
+
+                v_store(dst + x, v_dst0);
+                v_store(dst + x + 2, v_dst1);
+                v_store(dst + x + 4, v_dst2);
+                v_store(dst + x + 6, v_dst3);
             }
         }
-
         return x;
     }
 };
+#endif
 
 template <>
 struct AccProd_SIMD<uchar, float>
@@ -288,36 +1083,60 @@ struct AccProd_SIMD<uchar, float>
     {
         int x = 0;
 
+        len *= cn;
         if (!mask)
         {
-            len *= cn;
             for ( ; x <= len - 16; x += 16)
             {
-                uint8x16_t v_1src = vld1q_u8(src1 + x), v_2src = vld1q_u8(src2 + x);
-                uint16x8_t v_src0 = vmull_u8(vget_low_u8(v_1src), vget_low_u8(v_2src)),
-                           v_src1 = vmull_u8(vget_high_u8(v_1src), vget_high_u8(v_2src));
-
-                vst1q_f32(dst + x, vaddq_f32(vld1q_f32(dst + x), vcvtq_f32_u32(vmovl_u16(vget_low_u16(v_src0)))));
-                vst1q_f32(dst + x + 4, vaddq_f32(vld1q_f32(dst + x + 4), vcvtq_f32_u32(vmovl_u16(vget_high_u16(v_src0)))));
-                vst1q_f32(dst + x + 8, vaddq_f32(vld1q_f32(dst + x + 8), vcvtq_f32_u32(vmovl_u16(vget_low_u16(v_src1)))));
-                vst1q_f32(dst + x + 12, vaddq_f32(vld1q_f32(dst + x + 12), vcvtq_f32_u32(vmovl_u16(vget_high_u16(v_src1)))));
+                v_uint8x16 v_1src = v_load(src1 + x);
+                v_uint8x16 v_2src = v_load(src2 + x);
+
+                v_uint16x8 v_1src0, v_1src1, v_2src0, v_2src1;
+                v_expand(v_1src, v_1src0, v_1src1);
+                v_expand(v_2src, v_2src0, v_2src1);
+
+                v_uint16x8 v_src0, v_src1;
+                v_src0 = v_1src0 * v_2src0;
+                v_src1 = v_1src1 * v_2src1;
+
+                v_uint32x4 v_src00, v_src01, v_src10, v_src11;
+                v_expand(v_src0, v_src00, v_src01);
+                v_expand(v_src1, v_src10, v_src11);
+
+                v_store(dst + x, v_load(dst + x) + v_cvt_f32(v_reinterpret_as_s32(v_src00)));
+                v_store(dst + x + 4, v_load(dst + x + 4) + v_cvt_f32(v_reinterpret_as_s32(v_src01)));
+                v_store(dst + x + 8, v_load(dst + x + 8) + v_cvt_f32(v_reinterpret_as_s32(v_src10)));
+                v_store(dst + x + 12, v_load(dst + x + 12) + v_cvt_f32(v_reinterpret_as_s32(v_src11)));
             }
         }
         else if (cn == 1)
         {
-            uint8x16_t v_255 = vdupq_n_u8(255), v_0 = vdupq_n_u8(0);
+            v_uint8x16 v_0 = v_setzero_u8();
 
             for ( ; x <= len - 16; x += 16)
             {
-                uint8x16_t v_mask = veorq_u8(v_255, vceqq_u8(vld1q_u8(mask + x), v_0));
-                uint8x16_t v_1src = vandq_u8(vld1q_u8(src1 + x), v_mask), v_2src = vandq_u8(vld1q_u8(src2 + x), v_mask);
-                uint16x8_t v_src0 = vmull_u8(vget_low_u8(v_1src), vget_low_u8(v_2src)),
-                           v_src1 = vmull_u8(vget_high_u8(v_1src), vget_high_u8(v_2src));
-
-                vst1q_f32(dst + x, vaddq_f32(vld1q_f32(dst + x), vcvtq_f32_u32(vmovl_u16(vget_low_u16(v_src0)))));
-                vst1q_f32(dst + x + 4, vaddq_f32(vld1q_f32(dst + x + 4), vcvtq_f32_u32(vmovl_u16(vget_high_u16(v_src0)))));
-                vst1q_f32(dst + x + 8, vaddq_f32(vld1q_f32(dst + x + 8), vcvtq_f32_u32(vmovl_u16(vget_low_u16(v_src1)))));
-                vst1q_f32(dst + x + 12, vaddq_f32(vld1q_f32(dst + x + 12), vcvtq_f32_u32(vmovl_u16(vget_high_u16(v_src1)))));
+                v_uint8x16 v_mask = v_load(mask + x);
+                v_mask = ~(v_0 == v_mask);
+
+                v_uint8x16 v_1src = v_load(src1 + x) & v_mask;
+                v_uint8x16 v_2src = v_load(src2 + x) & v_mask;
+
+                v_uint16x8 v_1src0, v_1src1, v_2src0, v_2src1;
+                v_expand(v_1src, v_1src0, v_1src1);
+                v_expand(v_2src, v_2src0, v_2src1);
+
+                v_uint16x8 v_src0, v_src1;
+                v_src0 = v_1src0 * v_2src0;
+                v_src1 = v_1src1 * v_2src1;
+
+                v_uint32x4 v_src00, v_src01, v_src10, v_src11;
+                v_expand(v_src0, v_src00, v_src01);
+                v_expand(v_src1, v_src10, v_src11);
+
+                v_store(dst + x, v_load(dst + x) + v_cvt_f32(v_reinterpret_as_s32(v_src00)));
+                v_store(dst + x + 4, v_load(dst + x + 4) + v_cvt_f32(v_reinterpret_as_s32(v_src01)));
+                v_store(dst + x + 8, v_load(dst + x + 8) + v_cvt_f32(v_reinterpret_as_s32(v_src10)));
+                v_store(dst + x + 12, v_load(dst + x + 12) + v_cvt_f32(v_reinterpret_as_s32(v_src11)));
             }
         }
 
@@ -337,31 +1156,53 @@ struct AccProd_SIMD<ushort, float>
             len *= cn;
             for ( ; x <= len - 8; x += 8)
             {
-                uint16x8_t v_1src = vld1q_u16(src1 + x), v_2src = vld1q_u16(src2 + x);
-                uint32x4_t v_src0 = vmull_u16(vget_low_u16(v_1src), vget_low_u16(v_2src)),
-                           v_src1 = vmull_u16(vget_high_u16(v_1src), vget_high_u16(v_2src));
+                v_uint16x8 v_1src = v_load(src1 + x);
+                v_uint16x8 v_2src = v_load(src2 + x);
+
+                v_uint32x4 v_1src0, v_1src1, v_2src0, v_2src1;
+                v_expand(v_1src, v_1src0, v_1src1);
+                v_expand(v_2src, v_2src0, v_2src1);
+
+                v_float32x4 v_1float0 = v_cvt_f32(v_reinterpret_as_s32(v_1src0));
+                v_float32x4 v_1float1 = v_cvt_f32(v_reinterpret_as_s32(v_1src1));
+                v_float32x4 v_2float0 = v_cvt_f32(v_reinterpret_as_s32(v_2src0));
+                v_float32x4 v_2float1 = v_cvt_f32(v_reinterpret_as_s32(v_2src1));
 
-                vst1q_f32(dst + x, vaddq_f32(vld1q_f32(dst + x), vcvtq_f32_u32(v_src0)));
-                vst1q_f32(dst + x + 4, vaddq_f32(vld1q_f32(dst + x + 4), vcvtq_f32_u32(v_src1)));
+                v_float32x4 v_src0 = v_1float0 * v_2float0;
+                v_float32x4 v_src1 = v_1float1 * v_2float1;
+
+                v_store(dst + x, v_load(dst + x) + v_src0);
+                v_store(dst + x + 4, v_load(dst + x + 4) + v_src1);
             }
         }
         else if (cn == 1)
         {
-            uint8x8_t v_255 = vdup_n_u8(255), v_0 = vdup_n_u8(0);
+            v_uint16x8 v_0 = v_setzero_u16();
 
             for ( ; x <= len - 8; x += 8)
             {
-                uint8x8_t v_mask_src = veor_u8(v_255, vceq_u8(vld1_u8(mask + x), v_0));
-                uint8x8x2_t v_mask_zp = vzip_u8(v_mask_src, v_mask_src);
-                uint16x8_t v_mask = vreinterpretq_u16_u8(vcombine_u8(v_mask_zp.val[0], v_mask_zp.val[1])),
-                           v_1src = vandq_u16(vld1q_u16(src1 + x), v_mask),
-                           v_2src = vandq_u16(vld1q_u16(src2 + x), v_mask);
+                v_uint8x16 v_mask = v_load_halves(mask + x, mask + x);
+                v_uint16x8 v_mask0, v_mask1;
+                v_expand(v_mask, v_mask0, v_mask1);
+                v_mask0 = ~(v_0 == v_mask0);
+
+                v_uint16x8 v_1src = v_load(src1 + x) & v_mask0;
+                v_uint16x8 v_2src = v_load(src2 + x) & v_mask0;
+
+                v_uint32x4 v_1src0, v_1src1, v_2src0, v_2src1;
+                v_expand(v_1src, v_1src0, v_1src1);
+                v_expand(v_2src, v_2src0, v_2src1);
+
+                v_float32x4 v_1float0 = v_cvt_f32(v_reinterpret_as_s32(v_1src0));
+                v_float32x4 v_1float1 = v_cvt_f32(v_reinterpret_as_s32(v_1src1));
+                v_float32x4 v_2float0 = v_cvt_f32(v_reinterpret_as_s32(v_2src0));
+                v_float32x4 v_2float1 = v_cvt_f32(v_reinterpret_as_s32(v_2src1));
 
-                uint32x4_t v_src0 = vmull_u16(vget_low_u16(v_1src), vget_low_u16(v_2src)),
-                           v_src1 = vmull_u16(vget_high_u16(v_1src), vget_high_u16(v_2src));
+                v_float32x4 v_src0 = v_1float0 * v_2float0;
+                v_float32x4 v_src1 = v_1float1 * v_2float1;
 
-                vst1q_f32(dst + x, vaddq_f32(vld1q_f32(dst + x), vcvtq_f32_u32(v_src0)));
-                vst1q_f32(dst + x + 4, vaddq_f32(vld1q_f32(dst + x + 4), vcvtq_f32_u32(v_src1)));
+                v_store(dst + x, v_load(dst + x) + v_src0);
+                v_store(dst + x + 4, v_load(dst + x + 4) + v_src1);
             }
         }
 
@@ -369,10 +1210,11 @@ struct AccProd_SIMD<ushort, float>
     }
 };
 
+#if CV_SIMD128_64F
 template <>
-struct AccProd_SIMD<float, float>
+struct AccProd_SIMD<uchar, double>
 {
-    int operator() (const float * src1, const float * src2, float * dst, const uchar * mask, int len, int cn) const
+    int operator() (const uchar * src1, const uchar * src2, double * dst, const uchar * mask, int len, int cn) const
     {
         int x = 0;
 
@@ -381,14 +1223,96 @@ struct AccProd_SIMD<float, float>
             len *= cn;
             for ( ; x <= len - 8; x += 8)
             {
-                vst1q_f32(dst + x, vmlaq_f32(vld1q_f32(dst + x), vld1q_f32(src1 + x), vld1q_f32(src2 + x)));
-                vst1q_f32(dst + x + 4, vmlaq_f32(vld1q_f32(dst + x + 4), vld1q_f32(src1 + x + 4), vld1q_f32(src2 + x + 4)));
+                v_uint8x16 v_1src  = v_load(src1 + x);
+                v_uint8x16 v_2src  = v_load(src2 + x);
+
+                v_uint16x8 v_1int, v_2int, dummy;
+                v_expand(v_1src, v_1int, dummy);
+                v_expand(v_2src, v_2int, dummy);
+
+                v_uint32x4 v_1int_0, v_1int_1, v_2int_0, v_2int_1;
+                v_expand(v_1int, v_1int_0, v_1int_1);
+                v_expand(v_2int, v_2int_0, v_2int_1);
+
+                v_int32x4 v_1int0 = v_reinterpret_as_s32(v_1int_0);
+                v_int32x4 v_1int1 = v_reinterpret_as_s32(v_1int_1);
+                v_int32x4 v_2int0 = v_reinterpret_as_s32(v_2int_0);
+                v_int32x4 v_2int1 = v_reinterpret_as_s32(v_2int_1);
+
+                v_float64x2 v_src0 = v_cvt_f64(v_1int0) * v_cvt_f64(v_2int0);
+                v_float64x2 v_src1 = v_cvt_f64_high(v_1int0) * v_cvt_f64_high(v_2int0);
+                v_float64x2 v_src2 = v_cvt_f64(v_1int1) * v_cvt_f64(v_2int1);
+                v_float64x2 v_src3 = v_cvt_f64_high(v_1int1) * v_cvt_f64_high(v_2int1);
+
+                v_float64x2 v_dst0 = v_load(dst + x);
+                v_float64x2 v_dst1 = v_load(dst + x + 2);
+                v_float64x2 v_dst2 = v_load(dst + x + 4);
+                v_float64x2 v_dst3 = v_load(dst + x + 6);
+
+                v_dst0 += v_src0;
+                v_dst1 += v_src1;
+                v_dst2 += v_src2;
+                v_dst3 += v_src3;
+
+                v_store(dst + x, v_dst0);
+                v_store(dst + x + 2, v_dst1);
+                v_store(dst + x + 4, v_dst2);
+                v_store(dst + x + 6, v_dst3);
             }
         }
+        return x;
+    }
+};
+
+template <>
+struct AccProd_SIMD<ushort, double>
+{
+    int operator() (const ushort * src1, const ushort * src2, double * dst, const uchar * mask, int len, int cn) const
+    {
+        int x = 0;
 
+        if (!mask)
+        {
+            len *= cn;
+            for ( ; x <= len - 8; x += 8)
+            {
+                v_uint16x8 v_1src  = v_load(src1 + x);
+                v_uint16x8 v_2src  = v_load(src2 + x);
+
+                v_uint32x4 v_1int_0, v_1int_1, v_2int_0, v_2int_1;
+                v_expand(v_1src, v_1int_0, v_1int_1);
+                v_expand(v_2src, v_2int_0, v_2int_1);
+
+                v_int32x4 v_1int0 = v_reinterpret_as_s32(v_1int_0);
+                v_int32x4 v_1int1 = v_reinterpret_as_s32(v_1int_1);
+                v_int32x4 v_2int0 = v_reinterpret_as_s32(v_2int_0);
+                v_int32x4 v_2int1 = v_reinterpret_as_s32(v_2int_1);
+
+                v_float64x2 v_src0 = v_cvt_f64(v_1int0) * v_cvt_f64(v_2int0);
+                v_float64x2 v_src1 = v_cvt_f64_high(v_1int0) * v_cvt_f64_high(v_2int0);
+                v_float64x2 v_src2 = v_cvt_f64(v_1int1) * v_cvt_f64(v_2int1);
+                v_float64x2 v_src3 = v_cvt_f64_high(v_1int1) * v_cvt_f64_high(v_2int1);
+
+                v_float64x2 v_dst0 = v_load(dst + x);
+                v_float64x2 v_dst1 = v_load(dst + x + 2);
+                v_float64x2 v_dst2 = v_load(dst + x + 4);
+                v_float64x2 v_dst3 = v_load(dst + x + 6);
+
+                v_dst0 = v_dst0 + v_src0;
+                v_dst1 = v_dst1 + v_src1;
+                v_dst2 = v_dst2 + v_src2;
+                v_dst3 = v_dst3 + v_src3;
+
+                v_store(dst + x, v_dst0);
+                v_store(dst + x + 2, v_dst1);
+                v_store(dst + x + 4, v_dst2);
+                v_store(dst + x + 6, v_dst3);
+            }
+        }
         return x;
     }
 };
+#endif
 
 template <>
 struct AccW_SIMD<uchar, float>
@@ -396,24 +1320,37 @@ struct AccW_SIMD<uchar, float>
     int operator() (const uchar * src, float * dst, const uchar * mask, int len, int cn, float alpha) const
     {
         int x = 0;
-        float32x4_t v_alpha = vdupq_n_f32(alpha), v_beta = vdupq_n_f32(1.0f - alpha);
+        v_float32x4 v_alpha = v_setall_f32(alpha);
+        v_float32x4 v_beta = v_setall_f32(1.0f - alpha);
 
         if (!mask)
         {
             len *= cn;
             for ( ; x <= len - 16; x += 16)
             {
-                uint8x16_t v_src = vld1q_u8(src + x);
-                uint16x8_t v_src0 = vmovl_u8(vget_low_u8(v_src)), v_src1 = vmovl_u8(vget_high_u8(v_src));
-
-                vst1q_f32(dst + x, vmlaq_f32(vmulq_f32(vld1q_f32(dst + x), v_beta),
-                                             vcvtq_f32_u32(vmovl_u16(vget_low_u16(v_src0))), v_alpha));
-                vst1q_f32(dst + x + 4, vmlaq_f32(vmulq_f32(vld1q_f32(dst + x + 4), v_beta),
-                                             vcvtq_f32_u32(vmovl_u16(vget_high_u16(v_src0))), v_alpha));
-                vst1q_f32(dst + x + 8, vmlaq_f32(vmulq_f32(vld1q_f32(dst + x + 8), v_beta),
-                                                 vcvtq_f32_u32(vmovl_u16(vget_low_u16(v_src1))), v_alpha));
-                vst1q_f32(dst + x + 12, vmlaq_f32(vmulq_f32(vld1q_f32(dst + x + 12), v_beta),
-                                                  vcvtq_f32_u32(vmovl_u16(vget_high_u16(v_src1))), v_alpha));
+                v_uint8x16 v_src = v_load(src + x);
+
+                v_uint16x8 v_src0, v_src1;
+                v_expand(v_src, v_src0, v_src1);
+
+                v_uint32x4 v_src00, v_src01, v_src10, v_src11;
+                v_expand(v_src0, v_src00, v_src01);
+                v_expand(v_src1, v_src10, v_src11);
+
+                v_float32x4 v_dst00 = v_load(dst + x);
+                v_float32x4 v_dst01 = v_load(dst + x + 4);
+                v_float32x4 v_dst10 = v_load(dst + x + 8);
+                v_float32x4 v_dst11 = v_load(dst + x + 12);
+
+                v_dst00 = (v_dst00 * v_beta) + (v_cvt_f32(v_reinterpret_as_s32(v_src00)) * v_alpha);
+                v_dst01 = (v_dst01 * v_beta) + (v_cvt_f32(v_reinterpret_as_s32(v_src01)) * v_alpha);
+                v_dst10 = (v_dst10 * v_beta) + (v_cvt_f32(v_reinterpret_as_s32(v_src10)) * v_alpha);
+                v_dst11 = (v_dst11 * v_beta) + (v_cvt_f32(v_reinterpret_as_s32(v_src11)) * v_alpha);
+
+                v_store(dst + x, v_dst00);
+                v_store(dst + x + 4, v_dst01);
+                v_store(dst + x + 8, v_dst10);
+                v_store(dst + x + 12, v_dst11);
             }
         }
 
@@ -427,18 +1364,28 @@ struct AccW_SIMD<ushort, float>
     int operator() (const ushort * src, float * dst, const uchar * mask, int len, int cn, float alpha) const
     {
         int x = 0;
-        float32x4_t v_alpha = vdupq_n_f32(alpha), v_beta = vdupq_n_f32(1.0f - alpha);
+        v_float32x4 v_alpha = v_setall_f32(alpha);
+        v_float32x4 v_beta = v_setall_f32(1.0f - alpha);
 
         if (!mask)
         {
             len *= cn;
             for ( ; x <= len - 8; x += 8)
             {
-                uint16x8_t v_src = vld1q_u16(src + x);
-                uint32x4_t v_src0 = vmovl_u16(vget_low_u16(v_src)), v_src1 = vmovl_u16(vget_high_u16(v_src));
+                v_uint16x8 v_src = v_load(src + x);
+                v_uint32x4 v_int0, v_int1;
+                v_expand(v_src, v_int0, v_int1);
+
+                v_float32x4 v_src0 = v_cvt_f32(v_reinterpret_as_s32(v_int0));
+                v_float32x4 v_src1 = v_cvt_f32(v_reinterpret_as_s32(v_int1));
+                v_src0 = v_src0 * v_alpha;
+                v_src1 = v_src1 * v_alpha;
 
-                vst1q_f32(dst + x, vmlaq_f32(vmulq_f32(vld1q_f32(dst + x), v_beta), vcvtq_f32_u32(v_src0), v_alpha));
-                vst1q_f32(dst + x + 4, vmlaq_f32(vmulq_f32(vld1q_f32(dst + x + 4), v_beta), vcvtq_f32_u32(v_src1), v_alpha));
+                v_float32x4 v_dst0 = v_load(dst + x) * v_beta;
+                v_float32x4 v_dst1 = v_load(dst + x + 4) * v_beta;
+
+                v_store(dst + x, v_dst0 + v_src0);
+                v_store(dst + x + 4, v_dst1 + v_src1);
             }
         }
 
@@ -446,21 +1393,50 @@ struct AccW_SIMD<ushort, float>
     }
 };
 
+#if CV_SIMD128_64F
 template <>
-struct AccW_SIMD<float, float>
+struct AccW_SIMD<uchar, double>
 {
-    int operator() (const float * src, float * dst, const uchar * mask, int len, int cn, float alpha) const
+    int operator() (const uchar * src, double * dst, const uchar * mask, int len, int cn, double alpha) const
     {
         int x = 0;
-        float32x4_t v_alpha = vdupq_n_f32(alpha), v_beta = vdupq_n_f32(1.0f - alpha);
+        v_float64x2 v_alpha = v_setall_f64(alpha);
+        v_float64x2 v_beta = v_setall_f64(1.0f - alpha);
 
         if (!mask)
         {
             len *= cn;
             for ( ; x <= len - 8; x += 8)
             {
-                vst1q_f32(dst + x, vmlaq_f32(vmulq_f32(vld1q_f32(dst + x), v_beta), vld1q_f32(src + x), v_alpha));
-                vst1q_f32(dst + x + 4, vmlaq_f32(vmulq_f32(vld1q_f32(dst + x + 4), v_beta), vld1q_f32(src + x + 4), v_alpha));
+                v_uint8x16 v_src = v_load(src + x);
+                v_uint16x8 v_int, dummy;
+                v_expand(v_src, v_int, dummy);
+
+                v_uint32x4 v_int_0, v_int_1;
+                v_expand(v_int, v_int_0, v_int_1);
+
+                v_int32x4 v_int0 = v_reinterpret_as_s32(v_int_0);
+                v_int32x4 v_int1 = v_reinterpret_as_s32(v_int_1);
+
+                v_float64x2 v_src0 = v_cvt_f64(v_int0);
+                v_float64x2 v_src1 = v_cvt_f64_high(v_int0);
+                v_float64x2 v_src2 = v_cvt_f64(v_int1);
+                v_float64x2 v_src3 = v_cvt_f64_high(v_int1);
+
+                v_float64x2 v_dst0 = v_load(dst + x);
+                v_float64x2 v_dst1 = v_load(dst + x + 2);
+                v_float64x2 v_dst2 = v_load(dst + x + 4);
+                v_float64x2 v_dst3 = v_load(dst + x + 6);
+
+                v_dst0 = (v_dst0 * v_beta) + (v_src0 * v_alpha);
+                v_dst1 = (v_dst1 * v_beta) + (v_src1 * v_alpha);
+                v_dst2 = (v_dst2 * v_beta) + (v_src2 * v_alpha);
+                v_dst3 = (v_dst3 * v_beta) + (v_src3 * v_alpha);
+
+                v_store(dst + x, v_dst0);
+                v_store(dst + x + 2, v_dst1);
+                v_store(dst + x + 4, v_dst2);
+                v_store(dst + x + 6, v_dst3);
             }
         }
 
@@ -468,7 +1444,54 @@ struct AccW_SIMD<float, float>
     }
 };
 
-#endif
+template <>
+struct AccW_SIMD<ushort, double>
+{
+    int operator() (const ushort * src, double * dst, const uchar * mask, int len, int cn, double alpha) const
+    {
+        int x = 0;
+        v_float64x2 v_alpha = v_setall_f64(alpha);
+        v_float64x2 v_beta = v_setall_f64(1.0f - alpha);
+
+        if (!mask)
+        {
+            len *= cn;
+            for ( ; x <= len - 8; x += 8)
+            {
+                v_uint16x8 v_src = v_load(src + x);
+                v_uint32x4 v_int_0, v_int_1;
+                v_expand(v_src, v_int_0, v_int_1);
+
+                v_int32x4 v_int0 = v_reinterpret_as_s32(v_int_0);
+                v_int32x4 v_int1 = v_reinterpret_as_s32(v_int_1);
+
+                v_float64x2 v_src00 = v_cvt_f64(v_int0);
+                v_float64x2 v_src01 = v_cvt_f64_high(v_int0);
+                v_float64x2 v_src10 = v_cvt_f64(v_int1);
+                v_float64x2 v_src11 = v_cvt_f64_high(v_int1);
+
+                v_float64x2 v_dst00 = v_load(dst + x);
+                v_float64x2 v_dst01 = v_load(dst + x + 2);
+                v_float64x2 v_dst10 = v_load(dst + x + 4);
+                v_float64x2 v_dst11 = v_load(dst + x + 6);
+
+                v_dst00 = (v_dst00 * v_beta) + (v_src00 * v_alpha);
+                v_dst01 = (v_dst01 * v_beta) + (v_src01 * v_alpha);
+                v_dst10 = (v_dst10 * v_beta) + (v_src10 * v_alpha);
+                v_dst11 = (v_dst11 * v_beta) + (v_src11 * v_alpha);
+
+                v_store(dst + x, v_dst00);
+                v_store(dst + x + 2, v_dst01);
+                v_store(dst + x + 4, v_dst10);
+                v_store(dst + x + 6, v_dst11);
+            }
+        }
+
+        return x;
+    }
+};
+#endif //CV_SIMD128_64F
+#endif //CV_SIMD128
 
 template<typename T, typename AT> void
 acc_( const T* src, AT* dst, const uchar* mask, int len, int cn )
@@ -848,6 +1871,8 @@ namespace cv
 {
 static bool ipp_accumulate(InputArray _src, InputOutputArray _dst, InputArray _mask)
 {
+    CV_INSTRUMENT_REGION_IPP()
+
     int stype = _src.type(), sdepth = CV_MAT_DEPTH(stype), scn = CV_MAT_CN(stype);
     int dtype = _dst.type(), ddepth = CV_MAT_DEPTH(dtype);
 
@@ -855,28 +1880,28 @@ static bool ipp_accumulate(InputArray _src, InputOutputArray _dst, InputArray _m
 
     if (src.dims <= 2 || (src.isContinuous() && dst.isContinuous() && (mask.empty() || mask.isContinuous())))
     {
-        typedef IppStatus (CV_STDCALL * ippiAdd)(const void * pSrc, int srcStep, Ipp32f * pSrcDst, int srcdstStep, IppiSize roiSize);
-        typedef IppStatus (CV_STDCALL * ippiAddMask)(const void * pSrc, int srcStep, const Ipp8u * pMask, int maskStep, Ipp32f * pSrcDst,
+        typedef IppStatus (CV_STDCALL * IppiAdd)(const void * pSrc, int srcStep, Ipp32f * pSrcDst, int srcdstStep, IppiSize roiSize);
+        typedef IppStatus (CV_STDCALL * IppiAddMask)(const void * pSrc, int srcStep, const Ipp8u * pMask, int maskStep, Ipp32f * pSrcDst,
                                                     int srcDstStep, IppiSize roiSize);
-        ippiAdd ippFunc = 0;
-        ippiAddMask ippFuncMask = 0;
+        IppiAdd ippiAdd_I = 0;
+        IppiAddMask ippiAdd_IM = 0;
 
         if (mask.empty())
         {
             CV_SUPPRESS_DEPRECATED_START
-            ippFunc = sdepth == CV_8U && ddepth == CV_32F ? (ippiAdd)ippiAdd_8u32f_C1IR :
-                sdepth == CV_16U && ddepth == CV_32F ? (ippiAdd)ippiAdd_16u32f_C1IR :
-                sdepth == CV_32F && ddepth == CV_32F ? (ippiAdd)ippiAdd_32f_C1IR : 0;
+            ippiAdd_I = sdepth == CV_8U && ddepth == CV_32F ? (IppiAdd)ippiAdd_8u32f_C1IR :
+                sdepth == CV_16U && ddepth == CV_32F ? (IppiAdd)ippiAdd_16u32f_C1IR :
+                sdepth == CV_32F && ddepth == CV_32F ? (IppiAdd)ippiAdd_32f_C1IR : 0;
             CV_SUPPRESS_DEPRECATED_END
         }
         else if (scn == 1)
         {
-            ippFuncMask = sdepth == CV_8U && ddepth == CV_32F ? (ippiAddMask)ippiAdd_8u32f_C1IMR :
-                sdepth == CV_16U && ddepth == CV_32F ? (ippiAddMask)ippiAdd_16u32f_C1IMR :
-                sdepth == CV_32F && ddepth == CV_32F ? (ippiAddMask)ippiAdd_32f_C1IMR : 0;
+            ippiAdd_IM = sdepth == CV_8U && ddepth == CV_32F ? (IppiAddMask)ippiAdd_8u32f_C1IMR :
+                sdepth == CV_16U && ddepth == CV_32F ? (IppiAddMask)ippiAdd_16u32f_C1IMR :
+                sdepth == CV_32F && ddepth == CV_32F ? (IppiAddMask)ippiAdd_32f_C1IMR : 0;
         }
 
-        if (ippFunc || ippFuncMask)
+        if (ippiAdd_I || ippiAdd_IM)
         {
             IppStatus status = ippStsErr;
 
@@ -892,11 +1917,11 @@ static bool ipp_accumulate(InputArray _src, InputOutputArray _dst, InputArray _m
             }
             size.width *= scn;
 
-            if (ippFunc)
-                status = ippFunc(src.ptr(), srcstep, dst.ptr<Ipp32f>(), dststep, ippiSize(size.width, size.height));
-            else if(ippFuncMask)
-                status = ippFuncMask(src.ptr(), srcstep, mask.ptr<Ipp8u>(), maskstep,
-                                        dst.ptr<Ipp32f>(), dststep, ippiSize(size.width, size.height));
+            if (ippiAdd_I)
+                status = CV_INSTRUMENT_FUN_IPP(ippiAdd_I, src.ptr(), srcstep, dst.ptr<Ipp32f>(), dststep, ippiSize(size.width, size.height));
+            else if (ippiAdd_IM)
+                status = CV_INSTRUMENT_FUN_IPP(ippiAdd_IM, src.ptr(), srcstep, mask.ptr<Ipp8u>(), maskstep,
+                    dst.ptr<Ipp32f>(), dststep, ippiSize(size.width, size.height));
 
             if (status >= 0)
                 return true;
@@ -907,8 +1932,79 @@ static bool ipp_accumulate(InputArray _src, InputOutputArray _dst, InputArray _m
 }
 #endif
 
+#ifdef HAVE_OPENVX
+namespace cv
+{
+enum
+{
+    VX_ACCUMULATE_OP = 0,
+    VX_ACCUMULATE_SQUARE_OP = 1,
+    VX_ACCUMULATE_WEIGHTED_OP = 2
+};
+
+static bool openvx_accumulate(InputArray _src, InputOutputArray _dst, InputArray _mask, double _weight, int opType)
+{
+    Mat srcMat = _src.getMat(), dstMat = _dst.getMat();
+    if(!_mask.empty() ||
+       (opType == VX_ACCUMULATE_WEIGHTED_OP && dstMat.type() != CV_8UC1  ) ||
+       (opType != VX_ACCUMULATE_WEIGHTED_OP && dstMat.type() != CV_16SC1 ) ||
+       srcMat.type() != CV_8UC1)
+    {
+        return false;
+    }
+    //TODO: handle different number of channels (channel extract && channel combine)
+    //TODO: handle mask (threshold mask to 0xff && bitwise AND with src)
+    //(both things can be done by creating a graph)
+
+    try
+    {
+        ivx::Context context = ivx::Context::create();
+        ivx::Image srcImage = ivx::Image::createFromHandle(context, ivx::Image::matTypeToFormat(srcMat.type()),
+                                                           ivx::Image::createAddressing(srcMat), srcMat.data);
+        ivx::Image dstImage = ivx::Image::createFromHandle(context, ivx::Image::matTypeToFormat(dstMat.type()),
+                                                           ivx::Image::createAddressing(dstMat), dstMat.data);
+        ivx::Scalar shift = ivx::Scalar::create<VX_TYPE_UINT32>(context, 0);
+        ivx::Scalar alpha = ivx::Scalar::create<VX_TYPE_FLOAT32>(context, _weight);
+
+        switch (opType)
+        {
+        case VX_ACCUMULATE_OP:
+            ivx::IVX_CHECK_STATUS(vxuAccumulateImage(context, srcImage, dstImage));
+            break;
+        case VX_ACCUMULATE_SQUARE_OP:
+            ivx::IVX_CHECK_STATUS(vxuAccumulateSquareImage(context, srcImage, shift, dstImage));
+            break;
+        case VX_ACCUMULATE_WEIGHTED_OP:
+            ivx::IVX_CHECK_STATUS(vxuAccumulateWeightedImage(context, srcImage, alpha, dstImage));
+            break;
+        default:
+            break;
+        }
+
+#ifdef VX_VERSION_1_1
+        //we should take user memory back before release
+        //(it's not done automatically according to standard)
+        srcImage.swapHandle(); dstImage.swapHandle();
+#endif
+    }
+    catch (ivx::RuntimeError & e)
+    {
+        VX_DbgThrow(e.what());
+    }
+    catch (ivx::WrapperError & e)
+    {
+        VX_DbgThrow(e.what());
+    }
+
+    return true;
+}
+}
+#endif
+
 void cv::accumulate( InputArray _src, InputOutputArray _dst, InputArray _mask )
 {
+    CV_INSTRUMENT_REGION()
+
     int stype = _src.type(), sdepth = CV_MAT_DEPTH(stype), scn = CV_MAT_CN(stype);
     int dtype = _dst.type(), ddepth = CV_MAT_DEPTH(dtype), dcn = CV_MAT_CN(dtype);
 
@@ -921,6 +2017,9 @@ void cv::accumulate( InputArray _src, InputOutputArray _dst, InputArray _mask )
     CV_IPP_RUN((_src.dims() <= 2 || (_src.isContinuous() && _dst.isContinuous() && (_mask.empty() || _mask.isContinuous()))),
         ipp_accumulate(_src, _dst, _mask));
 
+    CV_OVX_RUN(_src.dims() <= 2,
+               openvx_accumulate(_src, _dst, _mask, 0.0, VX_ACCUMULATE_OP))
+
     Mat src = _src.getMat(), dst = _dst.getMat(), mask = _mask.getMat();
 
 
@@ -942,6 +2041,8 @@ namespace cv
 {
 static bool ipp_accumulate_square(InputArray _src, InputOutputArray _dst, InputArray _mask)
 {
+    CV_INSTRUMENT_REGION_IPP()
+
     int stype = _src.type(), sdepth = CV_MAT_DEPTH(stype), scn = CV_MAT_CN(stype);
     int dtype = _dst.type(), ddepth = CV_MAT_DEPTH(dtype);
 
@@ -952,23 +2053,23 @@ static bool ipp_accumulate_square(InputArray _src, InputOutputArray _dst, InputA
         typedef IppStatus (CV_STDCALL * ippiAddSquare)(const void * pSrc, int srcStep, Ipp32f * pSrcDst, int srcdstStep, IppiSize roiSize);
         typedef IppStatus (CV_STDCALL * ippiAddSquareMask)(const void * pSrc, int srcStep, const Ipp8u * pMask, int maskStep, Ipp32f * pSrcDst,
                                                             int srcDstStep, IppiSize roiSize);
-        ippiAddSquare ippFunc = 0;
-        ippiAddSquareMask ippFuncMask = 0;
+        ippiAddSquare ippiAddSquare_I = 0;
+        ippiAddSquareMask ippiAddSquare_IM = 0;
 
         if (mask.empty())
         {
-            ippFunc = sdepth == CV_8U && ddepth == CV_32F ? (ippiAddSquare)ippiAddSquare_8u32f_C1IR :
+            ippiAddSquare_I = sdepth == CV_8U && ddepth == CV_32F ? (ippiAddSquare)ippiAddSquare_8u32f_C1IR :
                 sdepth == CV_16U && ddepth == CV_32F ? (ippiAddSquare)ippiAddSquare_16u32f_C1IR :
                 sdepth == CV_32F && ddepth == CV_32F ? (ippiAddSquare)ippiAddSquare_32f_C1IR : 0;
         }
         else if (scn == 1)
         {
-            ippFuncMask = sdepth == CV_8U && ddepth == CV_32F ? (ippiAddSquareMask)ippiAddSquare_8u32f_C1IMR :
+            ippiAddSquare_IM = sdepth == CV_8U && ddepth == CV_32F ? (ippiAddSquareMask)ippiAddSquare_8u32f_C1IMR :
                 sdepth == CV_16U && ddepth == CV_32F ? (ippiAddSquareMask)ippiAddSquare_16u32f_C1IMR :
                 sdepth == CV_32F && ddepth == CV_32F ? (ippiAddSquareMask)ippiAddSquare_32f_C1IMR : 0;
         }
 
-        if (ippFunc || ippFuncMask)
+        if (ippiAddSquare_I || ippiAddSquare_IM)
         {
             IppStatus status = ippStsErr;
 
@@ -984,11 +2085,11 @@ static bool ipp_accumulate_square(InputArray _src, InputOutputArray _dst, InputA
             }
             size.width *= scn;
 
-            if (ippFunc)
-                status = ippFunc(src.ptr(), srcstep, dst.ptr<Ipp32f>(), dststep, ippiSize(size.width, size.height));
-            else if(ippFuncMask)
-                status = ippFuncMask(src.ptr(), srcstep, mask.ptr<Ipp8u>(), maskstep,
-                                        dst.ptr<Ipp32f>(), dststep, ippiSize(size.width, size.height));
+            if (ippiAddSquare_I)
+                status = CV_INSTRUMENT_FUN_IPP(ippiAddSquare_I, src.ptr(), srcstep, dst.ptr<Ipp32f>(), dststep, ippiSize(size.width, size.height));
+            else if (ippiAddSquare_IM)
+                status = CV_INSTRUMENT_FUN_IPP(ippiAddSquare_IM, src.ptr(), srcstep, mask.ptr<Ipp8u>(), maskstep,
+                    dst.ptr<Ipp32f>(), dststep, ippiSize(size.width, size.height));
 
             if (status >= 0)
                 return true;
@@ -1001,6 +2102,8 @@ static bool ipp_accumulate_square(InputArray _src, InputOutputArray _dst, InputA
 
 void cv::accumulateSquare( InputArray _src, InputOutputArray _dst, InputArray _mask )
 {
+    CV_INSTRUMENT_REGION()
+
     int stype = _src.type(), sdepth = CV_MAT_DEPTH(stype), scn = CV_MAT_CN(stype);
     int dtype = _dst.type(), ddepth = CV_MAT_DEPTH(dtype), dcn = CV_MAT_CN(dtype);
 
@@ -1013,6 +2116,9 @@ void cv::accumulateSquare( InputArray _src, InputOutputArray _dst, InputArray _m
     CV_IPP_RUN((_src.dims() <= 2 || (_src.isContinuous() && _dst.isContinuous() && (_mask.empty() || _mask.isContinuous()))),
         ipp_accumulate_square(_src, _dst, _mask));
 
+    CV_OVX_RUN(_src.dims() <= 2,
+               openvx_accumulate(_src, _dst, _mask, 0.0, VX_ACCUMULATE_SQUARE_OP))
+
     Mat src = _src.getMat(), dst = _dst.getMat(), mask = _mask.getMat();
 
     int fidx = getAccTabIdx(sdepth, ddepth);
@@ -1034,6 +2140,8 @@ namespace cv
 static bool ipp_accumulate_product(InputArray _src1, InputArray _src2,
                             InputOutputArray _dst, InputArray _mask)
 {
+    CV_INSTRUMENT_REGION_IPP()
+
     int stype = _src1.type(), sdepth = CV_MAT_DEPTH(stype), scn = CV_MAT_CN(stype);
     int dtype = _dst.type(), ddepth = CV_MAT_DEPTH(dtype);
 
@@ -1045,23 +2153,23 @@ static bool ipp_accumulate_product(InputArray _src1, InputArray _src2,
                                                         int src2Step, Ipp32f * pSrcDst, int srcDstStep, IppiSize roiSize);
         typedef IppStatus (CV_STDCALL * ippiAddProductMask)(const void * pSrc1, int src1Step, const void * pSrc2, int src2Step,
                                                             const Ipp8u * pMask, int maskStep, Ipp32f * pSrcDst, int srcDstStep, IppiSize roiSize);
-        ippiAddProduct ippFunc = 0;
-        ippiAddProductMask ippFuncMask = 0;
+        ippiAddProduct ippiAddProduct_I = 0;
+        ippiAddProductMask ippiAddProduct_IM = 0;
 
         if (mask.empty())
         {
-            ippFunc = sdepth == CV_8U && ddepth == CV_32F ? (ippiAddProduct)ippiAddProduct_8u32f_C1IR :
+            ippiAddProduct_I = sdepth == CV_8U && ddepth == CV_32F ? (ippiAddProduct)ippiAddProduct_8u32f_C1IR :
                 sdepth == CV_16U && ddepth == CV_32F ? (ippiAddProduct)ippiAddProduct_16u32f_C1IR :
                 sdepth == CV_32F && ddepth == CV_32F ? (ippiAddProduct)ippiAddProduct_32f_C1IR : 0;
         }
         else if (scn == 1)
         {
-            ippFuncMask = sdepth == CV_8U && ddepth == CV_32F ? (ippiAddProductMask)ippiAddProduct_8u32f_C1IMR :
+            ippiAddProduct_IM = sdepth == CV_8U && ddepth == CV_32F ? (ippiAddProductMask)ippiAddProduct_8u32f_C1IMR :
                 sdepth == CV_16U && ddepth == CV_32F ? (ippiAddProductMask)ippiAddProduct_16u32f_C1IMR :
                 sdepth == CV_32F && ddepth == CV_32F ? (ippiAddProductMask)ippiAddProduct_32f_C1IMR : 0;
         }
 
-        if (ippFunc || ippFuncMask)
+        if (ippiAddProduct_I || ippiAddProduct_IM)
         {
             IppStatus status = ippStsErr;
 
@@ -1078,12 +2186,12 @@ static bool ipp_accumulate_product(InputArray _src1, InputArray _src2,
             }
             size.width *= scn;
 
-            if (ippFunc)
-                status = ippFunc(src1.ptr(), src1step, src2.ptr(), src2step, dst.ptr<Ipp32f>(),
-                                    dststep, ippiSize(size.width, size.height));
-            else if(ippFuncMask)
-                status = ippFuncMask(src1.ptr(), src1step, src2.ptr(), src2step, mask.ptr<Ipp8u>(), maskstep,
-                                        dst.ptr<Ipp32f>(), dststep, ippiSize(size.width, size.height));
+            if (ippiAddProduct_I)
+                status = CV_INSTRUMENT_FUN_IPP(ippiAddProduct_I, src1.ptr(), src1step, src2.ptr(), src2step, dst.ptr<Ipp32f>(),
+                    dststep, ippiSize(size.width, size.height));
+            else if (ippiAddProduct_IM)
+                status = CV_INSTRUMENT_FUN_IPP(ippiAddProduct_IM, src1.ptr(), src1step, src2.ptr(), src2step, mask.ptr<Ipp8u>(), maskstep,
+                    dst.ptr<Ipp32f>(), dststep, ippiSize(size.width, size.height));
 
             if (status >= 0)
                 return true;
@@ -1099,6 +2207,8 @@ static bool ipp_accumulate_product(InputArray _src1, InputArray _src2,
 void cv::accumulateProduct( InputArray _src1, InputArray _src2,
                             InputOutputArray _dst, InputArray _mask )
 {
+    CV_INSTRUMENT_REGION()
+
     int stype = _src1.type(), sdepth = CV_MAT_DEPTH(stype), scn = CV_MAT_CN(stype);
     int dtype = _dst.type(), ddepth = CV_MAT_DEPTH(dtype), dcn = CV_MAT_CN(dtype);
 
@@ -1133,6 +2243,8 @@ namespace cv
 static bool ipp_accumulate_weighted( InputArray _src, InputOutputArray _dst,
                              double alpha, InputArray _mask )
 {
+    CV_INSTRUMENT_REGION_IPP()
+
     int stype = _src.type(), sdepth = CV_MAT_DEPTH(stype), scn = CV_MAT_CN(stype);
     int dtype = _dst.type(), ddepth = CV_MAT_DEPTH(dtype);
 
@@ -1145,23 +2257,23 @@ static bool ipp_accumulate_weighted( InputArray _src, InputOutputArray _dst,
         typedef IppStatus (CV_STDCALL * ippiAddWeightedMask)(const void * pSrc, int srcStep, const Ipp8u * pMask,
                                                                 int maskStep, Ipp32f * pSrcDst,
                                                                 int srcDstStep, IppiSize roiSize, Ipp32f alpha);
-        ippiAddWeighted ippFunc = 0;
-        ippiAddWeightedMask ippFuncMask = 0;
+        ippiAddWeighted ippiAddWeighted_I = 0;
+        ippiAddWeightedMask ippiAddWeighted_IM = 0;
 
         if (mask.empty())
         {
-            ippFunc = sdepth == CV_8U && ddepth == CV_32F ? (ippiAddWeighted)ippiAddWeighted_8u32f_C1IR :
+            ippiAddWeighted_I = sdepth == CV_8U && ddepth == CV_32F ? (ippiAddWeighted)ippiAddWeighted_8u32f_C1IR :
                 sdepth == CV_16U && ddepth == CV_32F ? (ippiAddWeighted)ippiAddWeighted_16u32f_C1IR :
                 sdepth == CV_32F && ddepth == CV_32F ? (ippiAddWeighted)ippiAddWeighted_32f_C1IR : 0;
         }
         else if (scn == 1)
         {
-            ippFuncMask = sdepth == CV_8U && ddepth == CV_32F ? (ippiAddWeightedMask)ippiAddWeighted_8u32f_C1IMR :
+            ippiAddWeighted_IM = sdepth == CV_8U && ddepth == CV_32F ? (ippiAddWeightedMask)ippiAddWeighted_8u32f_C1IMR :
                 sdepth == CV_16U && ddepth == CV_32F ? (ippiAddWeightedMask)ippiAddWeighted_16u32f_C1IMR :
                 sdepth == CV_32F && ddepth == CV_32F ? (ippiAddWeightedMask)ippiAddWeighted_32f_C1IMR : 0;
         }
 
-        if (ippFunc || ippFuncMask)
+        if (ippiAddWeighted_I || ippiAddWeighted_IM)
         {
             IppStatus status = ippStsErr;
 
@@ -1177,11 +2289,11 @@ static bool ipp_accumulate_weighted( InputArray _src, InputOutputArray _dst,
             }
             size.width *= scn;
 
-            if (ippFunc)
-                status = ippFunc(src.ptr(), srcstep, dst.ptr<Ipp32f>(), dststep, ippiSize(size.width, size.height), (Ipp32f)alpha);
-            else if(ippFuncMask)
-                status = ippFuncMask(src.ptr(), srcstep, mask.ptr<Ipp8u>(), maskstep,
-                                        dst.ptr<Ipp32f>(), dststep, ippiSize(size.width, size.height), (Ipp32f)alpha);
+            if (ippiAddWeighted_I)
+                status = CV_INSTRUMENT_FUN_IPP(ippiAddWeighted_I, src.ptr(), srcstep, dst.ptr<Ipp32f>(), dststep, ippiSize(size.width, size.height), (Ipp32f)alpha);
+            else if (ippiAddWeighted_IM)
+                status = CV_INSTRUMENT_FUN_IPP(ippiAddWeighted_IM, src.ptr(), srcstep, mask.ptr<Ipp8u>(), maskstep,
+                    dst.ptr<Ipp32f>(), dststep, ippiSize(size.width, size.height), (Ipp32f)alpha);
 
             if (status >= 0)
                 return true;
@@ -1195,6 +2307,8 @@ static bool ipp_accumulate_weighted( InputArray _src, InputOutputArray _dst,
 void cv::accumulateWeighted( InputArray _src, InputOutputArray _dst,
                              double alpha, InputArray _mask )
 {
+    CV_INSTRUMENT_REGION()
+
     int stype = _src.type(), sdepth = CV_MAT_DEPTH(stype), scn = CV_MAT_CN(stype);
     int dtype = _dst.type(), ddepth = CV_MAT_DEPTH(dtype), dcn = CV_MAT_CN(dtype);
 
@@ -1206,6 +2320,8 @@ void cv::accumulateWeighted( InputArray _src, InputOutputArray _dst,
 
     CV_IPP_RUN((_src.dims() <= 2 || (_src.isContinuous() && _dst.isContinuous() && _mask.isContinuous())), ipp_accumulate_weighted(_src, _dst, alpha, _mask));
 
+    CV_OVX_RUN(_src.dims() <= 2,
+               openvx_accumulate(_src, _dst, _mask, alpha, VX_ACCUMULATE_WEIGHTED_OP))
 
     Mat src = _src.getMat(), dst = _dst.getMat(), mask = _mask.getMat();
 
diff --git a/modules/imgproc/src/approx.cpp b/modules/imgproc/src/approx.cpp
index 54b5dd0..ec0db30 100644
--- a/modules/imgproc/src/approx.cpp
+++ b/modules/imgproc/src/approx.cpp
@@ -674,6 +674,8 @@ approxPolyDP_( const Point_<T>* src_contour, int count0, Point_<T>* dst_contour,
 void cv::approxPolyDP( InputArray _curve, OutputArray _approxCurve,
                       double epsilon, bool closed )
 {
+    CV_INSTRUMENT_REGION()
+
     Mat curve = _curve.getMat();
     int npoints = curve.checkVector(2), depth = curve.depth();
     CV_Assert( npoints >= 0 && (depth == CV_32S || depth == CV_32F));
diff --git a/modules/imgproc/src/blend.cpp b/modules/imgproc/src/blend.cpp
index 2393f26..17e31aa 100644
--- a/modules/imgproc/src/blend.cpp
+++ b/modules/imgproc/src/blend.cpp
@@ -121,6 +121,8 @@ static bool ocl_blendLinear( InputArray _src1, InputArray _src2, InputArray _wei
 
 void cv::blendLinear( InputArray _src1, InputArray _src2, InputArray _weights1, InputArray _weights2, OutputArray _dst )
 {
+    CV_INSTRUMENT_REGION()
+
     int type = _src1.type(), depth = CV_MAT_DEPTH(type);
     Size size = _src1.size();
 
diff --git a/modules/imgproc/src/canny.cpp b/modules/imgproc/src/canny.cpp
index 22ed547..cdc4e7a 100644
--- a/modules/imgproc/src/canny.cpp
+++ b/modules/imgproc/src/canny.cpp
@@ -42,6 +42,14 @@
 
 #include "precomp.hpp"
 #include "opencl_kernels_imgproc.hpp"
+#include "opencv2/core/hal/intrin.hpp"
+#include <queue>
+
+#include "opencv2/core/openvx/ovx_defs.hpp"
+
+#ifdef _MSC_VER
+#pragma warning( disable: 4127 ) // conditional expression is constant
+#endif
 
 
 #if defined (HAVE_IPP) && (IPP_VERSION_X100 >= 700)
@@ -53,53 +61,78 @@
 
 namespace cv
 {
+
+static void CannyImpl(Mat& dx_, Mat& dy_, Mat& _dst, double low_thresh, double high_thresh, bool L2gradient);
+
+
 #ifdef HAVE_IPP
-static bool ippCanny(const Mat& _src, Mat& _dst, float low,  float high)
+template <bool useCustomDeriv>
+static bool ippCanny(const Mat& _src, const Mat& dx_, const Mat& dy_, Mat& _dst, float low, float high)
 {
+    CV_INSTRUMENT_REGION_IPP()
+
 #if USE_IPP_CANNY
+    if (!useCustomDeriv && _src.isSubmatrix())
+        return false; // IPP Sobel doesn't support transparent ROI border
+
     int size = 0, size1 = 0;
     IppiSize roi = { _src.cols, _src.rows };
 
-#if IPP_VERSION_X100 < 900
-    if (ippiFilterSobelNegVertGetBufferSize_8u16s_C1R(roi, ippMskSize3x3, &size) < 0)
-        return false;
-    if (ippiFilterSobelHorizGetBufferSize_8u16s_C1R(roi, ippMskSize3x3, &size1) < 0)
+    if (ippiCannyGetSize(roi, &size) < 0)
         return false;
+
+    if (!useCustomDeriv)
+    {
+#if IPP_VERSION_X100 < 900
+        if (ippiFilterSobelNegVertGetBufferSize_8u16s_C1R(roi, ippMskSize3x3, &size1) < 0)
+            return false;
+        size = std::max(size, size1);
+        if (ippiFilterSobelHorizGetBufferSize_8u16s_C1R(roi, ippMskSize3x3, &size1) < 0)
+            return false;
 #else
-    if (ippiFilterSobelNegVertBorderGetBufferSize(roi, ippMskSize3x3, ipp8u, ipp16s, 1, &size) < 0)
-        return false;
-    if (ippiFilterSobelHorizBorderGetBufferSize(roi, ippMskSize3x3, ipp8u, ipp16s, 1, &size1) < 0)
-        return false;
+        if (ippiFilterSobelNegVertBorderGetBufferSize(roi, ippMskSize3x3, ipp8u, ipp16s, 1, &size1) < 0)
+            return false;
+        size = std::max(size, size1);
+        if (ippiFilterSobelHorizBorderGetBufferSize(roi, ippMskSize3x3, ipp8u, ipp16s, 1, &size1) < 0)
+            return false;
 #endif
-
-    size = std::max(size, size1);
-
-    if (ippiCannyGetSize(roi, &size1) < 0)
-        return false;
-    size = std::max(size, size1);
+        size = std::max(size, size1);
+    }
 
     AutoBuffer<uchar> buf(size + 64);
     uchar* buffer = alignPtr((uchar*)buf, 32);
 
-    Mat _dx(_src.rows, _src.cols, CV_16S);
-    if( ippiFilterSobelNegVertBorder_8u16s_C1R(_src.ptr(), (int)_src.step,
-                    _dx.ptr<short>(), (int)_dx.step, roi,
-                    ippMskSize3x3, ippBorderRepl, 0, buffer) < 0 )
-        return false;
+    Mat dx, dy;
+    if (!useCustomDeriv)
+    {
+        Mat _dx(_src.rows, _src.cols, CV_16S);
+        if( CV_INSTRUMENT_FUN_IPP(ippiFilterSobelNegVertBorder_8u16s_C1R, _src.ptr(), (int)_src.step,
+                        _dx.ptr<short>(), (int)_dx.step, roi,
+                        ippMskSize3x3, ippBorderRepl, 0, buffer) < 0 )
+            return false;
 
-    Mat _dy(_src.rows, _src.cols, CV_16S);
-    if( ippiFilterSobelHorizBorder_8u16s_C1R(_src.ptr(), (int)_src.step,
-                    _dy.ptr<short>(), (int)_dy.step, roi,
-                    ippMskSize3x3, ippBorderRepl, 0, buffer) < 0 )
-        return false;
+        Mat _dy(_src.rows, _src.cols, CV_16S);
+        if( CV_INSTRUMENT_FUN_IPP(ippiFilterSobelHorizBorder_8u16s_C1R, _src.ptr(), (int)_src.step,
+                        _dy.ptr<short>(), (int)_dy.step, roi,
+                        ippMskSize3x3, ippBorderRepl, 0, buffer) < 0 )
+            return false;
 
-    if( ippiCanny_16s8u_C1R(_dx.ptr<short>(), (int)_dx.step,
-                               _dy.ptr<short>(), (int)_dy.step,
+        swap(dx, _dx);
+        swap(dy, _dy);
+    }
+    else
+    {
+        dx = dx_;
+        dy = dy_;
+    }
+
+    if( CV_INSTRUMENT_FUN_IPP(ippiCanny_16s8u_C1R, dx.ptr<short>(), (int)dx.step,
+                               dy.ptr<short>(), (int)dy.step,
                               _dst.ptr(), (int)_dst.step, roi, low, high, buffer) < 0 )
         return false;
     return true;
 #else
-    CV_UNUSED(_src); CV_UNUSED(_dst); CV_UNUSED(low); CV_UNUSED(high);
+    CV_UNUSED(_src); CV_UNUSED(dx_); CV_UNUSED(dy_); CV_UNUSED(_dst); CV_UNUSED(low); CV_UNUSED(high);
     return false;
 #endif
 }
@@ -107,9 +140,12 @@ static bool ippCanny(const Mat& _src, Mat& _dst, float low,  float high)
 
 #ifdef HAVE_OPENCL
 
-static bool ocl_Canny(InputArray _src, OutputArray _dst, float low_thresh, float high_thresh,
+template <bool useCustomDeriv>
+static bool ocl_Canny(InputArray _src, const UMat& dx_, const UMat& dy_, OutputArray _dst, float low_thresh, float high_thresh,
                       int aperture_size, bool L2gradient, int cn, const Size & size)
 {
+    CV_INSTRUMENT_REGION_OPENCL()
+
     UMat map;
 
     const ocl::Device &dev = ocl::Device::getDefault();
@@ -140,7 +176,8 @@ static bool ocl_Canny(InputArray _src, OutputArray _dst, float low_thresh, float
     }
     int low = cvFloor(low_thresh), high = cvFloor(high_thresh);
 
-    if (aperture_size == 3 && !_src.isSubmatrix())
+    if (!useCustomDeriv &&
+        aperture_size == 3 && !_src.isSubmatrix())
     {
         /*
             stage1_with_sobel:
@@ -181,8 +218,16 @@ static bool ocl_Canny(InputArray _src, OutputArray _dst, float low_thresh, float
                 Double thresholding
         */
         UMat dx, dy;
-        Sobel(_src, dx, CV_16S, 1, 0, aperture_size, 1, 0, BORDER_REPLICATE);
-        Sobel(_src, dy, CV_16S, 0, 1, aperture_size, 1, 0, BORDER_REPLICATE);
+        if (!useCustomDeriv)
+        {
+            Sobel(_src, dx, CV_16S, 1, 0, aperture_size, 1, 0, BORDER_REPLICATE);
+            Sobel(_src, dy, CV_16S, 0, 1, aperture_size, 1, 0, BORDER_REPLICATE);
+        }
+        else
+        {
+            dx = dx_;
+            dy = dy_;
+        }
 
         ocl::Kernel without_sobel("stage1_without_sobel", ocl::imgproc::canny_oclsrc,
                                     format("-D WITHOUT_SOBEL -D cn=%d -D GRP_SIZEX=%d -D GRP_SIZEY=%d%s",
@@ -242,40 +287,43 @@ static bool ocl_Canny(InputArray _src, OutputArray _dst, float low_thresh, float
 
 #endif
 
-#ifdef HAVE_TBB
-
-// Queue with peaks that will processed serially.
-static tbb::concurrent_queue<uchar*> borderPeaks;
-
-class tbbCanny
+class parallelCanny : public ParallelLoopBody
 {
+
 public:
-    tbbCanny(const Range _boundaries, const Mat& _src, uchar* _map, int _low,
-            int _high, int _aperture_size, bool _L2gradient)
-        : boundaries(_boundaries), src(_src), map(_map), low(_low), high(_high),
-          aperture_size(_aperture_size), L2gradient(_L2gradient)
-    {}
-
-    // This parallel version of Canny algorithm splits the src image in threadsNumber horizontal slices.
-    // The first row of each slice contains the last row of the previous slice and
-    // the last row of each slice contains the first row of the next slice
-    // so that each slice is independent and no mutexes are required.
-    void operator()() const
+    parallelCanny(const Mat& _src, uchar* _map, int _low, int _high, int _aperture_size, bool _L2gradient, std::queue<uchar*> *borderPeaksParallel) :
+        src(_src), map(_map), low(_low), high(_high), aperture_size(_aperture_size), L2gradient(_L2gradient), _borderPeaksParallel(borderPeaksParallel)
     {
-#if CV_SSE2
-        bool haveSSE2 = checkHardwareSupport(CV_CPU_SSE2);
+    }
+
+    ~parallelCanny()
+    {
+    }
+
+    parallelCanny& operator=(const parallelCanny&) { return *this; }
+
+    void operator()(const Range &boundaries) const
+    {
+#if CV_SIMD128
+        bool haveSIMD = hasSIMD128();
 #endif
 
         const int type = src.type(), cn = CV_MAT_CN(type);
 
         Mat dx, dy;
+        std::queue<uchar*> borderPeaksLocal;
 
         ptrdiff_t mapstep = src.cols + 2;
 
         // In sobel transform we calculate ksize2 extra lines for the first and last rows of each slice
         // because IPPDerivSobel expects only isolated ROIs, in contrast with the opencv version which
         // uses the pixels outside of the ROI to form a border.
-        uchar ksize2 = aperture_size / 2;
+        int ksize2 = aperture_size / 2;
+        // If Scharr filter: aperture_size is 3 and ksize2 is 1
+        if(aperture_size == -1)
+        {
+            ksize2 = 1;
+        }
 
         if (boundaries.start == 0 && boundaries.end == src.rows)
         {
@@ -366,33 +414,28 @@ public:
             if (!L2gradient)
             {
                 int j = 0, width = src.cols * cn;
-#if CV_SSE2
-                if (haveSSE2)
+#if CV_SIMD128
+                if (haveSIMD)
                 {
-                    __m128i v_zero = _mm_setzero_si128();
                     for ( ; j <= width - 8; j += 8)
                     {
-                        __m128i v_dx = _mm_loadu_si128((const __m128i *)(_dx + j));
-                        __m128i v_dy = _mm_loadu_si128((const __m128i *)(_dy + j));
-                        v_dx = _mm_max_epi16(v_dx, _mm_sub_epi16(v_zero, v_dx));
-                        v_dy = _mm_max_epi16(v_dy, _mm_sub_epi16(v_zero, v_dy));
+                        v_int16x8 v_dx = v_load((const short *)(_dx + j));
+                        v_int16x8 v_dy = v_load((const short *)(_dy + j));
+
+                        v_dx = v_reinterpret_as_s16(v_abs(v_dx));
+                        v_dy = v_reinterpret_as_s16(v_abs(v_dy));
 
-                        __m128i v_norm = _mm_add_epi32(_mm_unpacklo_epi16(v_dx, v_zero), _mm_unpacklo_epi16(v_dy, v_zero));
-                        _mm_storeu_si128((__m128i *)(_norm + j), v_norm);
+                        v_int32x4 v_dx_ml;
+                        v_int32x4 v_dy_ml;
+                        v_int32x4 v_dx_mh;
+                        v_int32x4 v_dy_mh;
+                        v_expand(v_dx, v_dx_ml, v_dx_mh);
+                        v_expand(v_dy, v_dy_ml, v_dy_mh);
 
-                        v_norm = _mm_add_epi32(_mm_unpackhi_epi16(v_dx, v_zero), _mm_unpackhi_epi16(v_dy, v_zero));
-                        _mm_storeu_si128((__m128i *)(_norm + j + 4), v_norm);
+                        v_store((int *)(_norm + j), v_dx_ml + v_dy_ml);
+                        v_store((int *)(_norm + j + 4), v_dx_mh + v_dy_mh);
                     }
                 }
-#elif CV_NEON
-                for ( ; j <= width - 8; j += 8)
-                {
-                    int16x8_t v_dx = vld1q_s16(_dx + j), v_dy = vld1q_s16(_dy + j);
-                    vst1q_s32(_norm + j, vaddq_s32(vabsq_s32(vmovl_s16(vget_low_s16(v_dx))),
-                                                   vabsq_s32(vmovl_s16(vget_low_s16(v_dy)))));
-                    vst1q_s32(_norm + j + 4, vaddq_s32(vabsq_s32(vmovl_s16(vget_high_s16(v_dx))),
-                                                       vabsq_s32(vmovl_s16(vget_high_s16(v_dy)))));
-                }
 #endif
                 for ( ; j < width; ++j)
                     _norm[j] = std::abs(int(_dx[j])) + std::abs(int(_dy[j]));
@@ -400,36 +443,23 @@ public:
             else
             {
                 int j = 0, width = src.cols * cn;
-#if CV_SSE2
-                if (haveSSE2)
+#if CV_SIMD128
+                if (haveSIMD)
                 {
-                    for ( ; j <= width - 8; j += 8)
+                   for ( ; j <= width - 8; j += 8)
                     {
-                        __m128i v_dx = _mm_loadu_si128((const __m128i *)(_dx + j));
-                        __m128i v_dy = _mm_loadu_si128((const __m128i *)(_dy + j));
+                        v_int16x8 v_dx = v_load((const short*)(_dx + j));
+                        v_int16x8 v_dy = v_load((const short*)(_dy + j));
 
-                        __m128i v_dx_ml = _mm_mullo_epi16(v_dx, v_dx), v_dx_mh = _mm_mulhi_epi16(v_dx, v_dx);
-                        __m128i v_dy_ml = _mm_mullo_epi16(v_dy, v_dy), v_dy_mh = _mm_mulhi_epi16(v_dy, v_dy);
+                        v_int32x4 v_dxp_low, v_dxp_high;
+                        v_int32x4 v_dyp_low, v_dyp_high;
+                        v_expand(v_dx, v_dxp_low, v_dxp_high);
+                        v_expand(v_dy, v_dyp_low, v_dyp_high);
 
-                        __m128i v_norm = _mm_add_epi32(_mm_unpacklo_epi16(v_dx_ml, v_dx_mh), _mm_unpacklo_epi16(v_dy_ml, v_dy_mh));
-                        _mm_storeu_si128((__m128i *)(_norm + j), v_norm);
-
-                        v_norm = _mm_add_epi32(_mm_unpackhi_epi16(v_dx_ml, v_dx_mh), _mm_unpackhi_epi16(v_dy_ml, v_dy_mh));
-                        _mm_storeu_si128((__m128i *)(_norm + j + 4), v_norm);
+                        v_store((int *)(_norm + j), v_dxp_low*v_dxp_low+v_dyp_low*v_dyp_low);
+                        v_store((int *)(_norm + j + 4), v_dxp_high*v_dxp_high+v_dyp_high*v_dyp_high);
                     }
                 }
-#elif CV_NEON
-                for ( ; j <= width - 8; j += 8)
-                {
-                    int16x8_t v_dx = vld1q_s16(_dx + j), v_dy = vld1q_s16(_dy + j);
-                    int16x4_t v_dxp = vget_low_s16(v_dx), v_dyp = vget_low_s16(v_dy);
-                    int32x4_t v_dst = vmlal_s16(vmull_s16(v_dxp, v_dxp), v_dyp, v_dyp);
-                    vst1q_s32(_norm + j, v_dst);
-
-                    v_dxp = vget_high_s16(v_dx), v_dyp = vget_high_s16(v_dy);
-                    v_dst = vmlal_s16(vmull_s16(v_dxp, v_dxp), v_dyp, v_dyp);
-                    vst1q_s32(_norm + j + 4, v_dst);
-                }
 #endif
                 for ( ; j < width; ++j)
                     _norm[j] = int(_dx[j])*_dx[j] + int(_dy[j])*_dy[j];
@@ -476,13 +506,93 @@ public:
 #define CANNY_PUSH(d)    *(d) = uchar(2), *stack_top++ = (d)
 #define CANNY_POP(d)     (d) = *--stack_top
 
-            int prev_flag = 0;
-            bool canny_push = false;
-            for (int j = 0; j < src.cols; j++)
+#define CANNY_SHIFT 15
+            const int TG22 = (int)(0.4142135623730950488016887242097*(1 << CANNY_SHIFT) + 0.5);
+
+            int prev_flag = 0, j = 0;
+#if CV_SIMD128
+            if (haveSIMD)
             {
-                #define CANNY_SHIFT 15
-                const int TG22 = (int)(0.4142135623730950488016887242097*(1<<CANNY_SHIFT) + 0.5);
+                v_int32x4 v_low = v_setall_s32(low);
+                v_int8x16 v_one = v_setall_s8(1);
+
+                for (; j <= src.cols - 16; j += 16)
+                {
+                    v_int32x4 v_m1 = v_load((const int*)(_mag + j));
+                    v_int32x4 v_m2 = v_load((const int*)(_mag + j + 4));
+                    v_int32x4 v_m3 = v_load((const int*)(_mag + j + 8));
+                    v_int32x4 v_m4 = v_load((const int*)(_mag + j + 12));
+
+                    v_store((signed char*)(_map + j), v_one);
+
+                    v_int32x4 v_cmp1 = v_m1 > v_low;
+                    v_int32x4 v_cmp2 = v_m2 > v_low;
+                    v_int32x4 v_cmp3 = v_m3 > v_low;
+                    v_int32x4 v_cmp4 = v_m4 > v_low;
+
+                    v_int16x8 v_cmp80 = v_pack(v_cmp1, v_cmp2);
+                    v_int16x8 v_cmp81 = v_pack(v_cmp3, v_cmp4);
+
+                    v_int8x16 v_cmp = v_pack(v_cmp80, v_cmp81);
+                    unsigned int mask = v_signmask(v_cmp);
+
+                    if (mask)
+                    {
+                        int m, k = j;
 
+                        for (; mask; ++k, mask >>= 1)
+                        {
+                            if (mask & 0x00000001)
+                            {
+                                m = _mag[k];
+                                int xs = _x[k];
+                                int ys = _y[k];
+                                int x = std::abs(xs);
+                                int y = std::abs(ys) << CANNY_SHIFT;
+
+                                int tg22x = x * TG22;
+
+                                if (y < tg22x)
+                                {
+                                    if (m > _mag[k - 1] && m >= _mag[k + 1]) goto _canny_push_sse;
+                                }
+                                else
+                                {
+                                    int tg67x = tg22x + (x << (CANNY_SHIFT + 1));
+                                    if (y > tg67x)
+                                    {
+                                        if (m > _mag[k + magstep2] && m >= _mag[k + magstep1]) goto _canny_push_sse;
+                                    } else
+                                    {
+                                        int s = (xs ^ ys) < 0 ? -1 : 1;
+                                        if (m > _mag[k + magstep2 - s] && m > _mag[k + magstep1 + s]) goto _canny_push_sse;
+                                    }
+                                }
+                            }
+
+                            prev_flag = 0;
+                            continue;
+
+_canny_push_sse:
+                            // _map[k-mapstep] is short-circuited at the start because previous thread is
+                            // responsible for initializing it.
+                            if (m > high && !prev_flag  && (i <= boundaries.start + 1 || _map[k - mapstep] != 2))
+                            {
+                                CANNY_PUSH(_map + k);
+                                prev_flag = 1;
+                            } else
+                                _map[k] = 0;
+
+                        }
+
+                        if (prev_flag && ((k < j+16) || (k < src.cols && _mag[k] <= high)))
+                            prev_flag = 0;
+                    }
+                }
+            }
+#endif
+            for (; j < src.cols; j++)
+            {
                 int m = _mag[j];
 
                 if (m > low)
@@ -496,42 +606,37 @@ public:
 
                     if (y < tg22x)
                     {
-                        if (m > _mag[j-1] && m >= _mag[j+1]) canny_push = true;
+                        if (m > _mag[j-1] && m >= _mag[j+1]) goto _canny_push;
                     }
                     else
                     {
                         int tg67x = tg22x + (x << (CANNY_SHIFT+1));
                         if (y > tg67x)
                         {
-                            if (m > _mag[j+magstep2] && m >= _mag[j+magstep1]) canny_push = true;
+                            if (m > _mag[j+magstep2] && m >= _mag[j+magstep1]) goto _canny_push;
                         }
                         else
                         {
                             int s = (xs ^ ys) < 0 ? -1 : 1;
-                            if (m > _mag[j+magstep2-s] && m > _mag[j+magstep1+s]) canny_push = true;
+                            if (m > _mag[j+magstep2-s] && m > _mag[j+magstep1+s]) goto _canny_push;
                         }
                     }
                 }
-                if (!canny_push)
+
+                prev_flag = 0;
+                _map[j] = uchar(1);
+                continue;
+
+_canny_push:
+                // _map[j-mapstep] is short-circuited at the start because previous thread is
+                // responsible for initializing it.
+                if (!prev_flag && m > high && (i <= boundaries.start+1 || _map[j-mapstep] != 2) )
                 {
-                    prev_flag = 0;
-                    _map[j] = uchar(1);
-                    continue;
+                    CANNY_PUSH(_map + j);
+                    prev_flag = 1;
                 }
                 else
-                {
-                    // _map[j-mapstep] is short-circuited at the start because previous thread is
-                    // responsible for initializing it.
-                    if (!prev_flag && m > high && (i <= boundaries.start+1 || _map[j-mapstep] != 2) )
-                    {
-                        CANNY_PUSH(_map + j);
-                        prev_flag = 1;
-                    }
-                    else
-                        _map[j] = 0;
-
-                    canny_push = false;
-                }
+                    _map[j] = 0;
             }
 
             // scroll the ring buffer
@@ -560,7 +665,7 @@ public:
             // slice in a queue to be serially processed later.
             if ( (m < map + (boundaries.start + 2) * mapstep) || (m >= map + boundaries.end * mapstep) )
             {
-                borderPeaks.push(m);
+                borderPeaksLocal.push(m);
                 continue;
             }
 
@@ -573,26 +678,167 @@ public:
             if (!m[mapstep])    CANNY_PUSH(m + mapstep);
             if (!m[mapstep+1])  CANNY_PUSH(m + mapstep + 1);
         }
+
+        AutoLock lock(mutex);
+        while (!borderPeaksLocal.empty()) {
+            _borderPeaksParallel->push(borderPeaksLocal.front());
+            borderPeaksLocal.pop();
+        }
     }
 
 private:
-    const Range boundaries;
     const Mat& src;
     uchar* map;
-    int low;
-    int high;
-    int aperture_size;
+    int low, high, aperture_size;
     bool L2gradient;
+    std::queue<uchar*> *_borderPeaksParallel;
+    mutable Mutex mutex;
 };
 
+class finalPass : public ParallelLoopBody
+{
+
+public:
+    finalPass(uchar *_map, Mat &_dst, ptrdiff_t _mapstep) :
+        map(_map), dst(_dst), mapstep(_mapstep) {}
+
+    ~finalPass() {}
+
+    finalPass& operator=(const finalPass&) {return *this;}
+
+    void operator()(const Range &boundaries) const
+    {
+        // the final pass, form the final image
+        const uchar* pmap = map + mapstep + 1 + (ptrdiff_t)(mapstep * boundaries.start);
+        uchar* pdst = dst.ptr() + (ptrdiff_t)(dst.step * boundaries.start);
+
+#if CV_SIMD128
+        bool haveSIMD = hasSIMD128();
 #endif
 
-} // namespace cv
+        for (int i = boundaries.start; i < boundaries.end; i++, pmap += mapstep, pdst += dst.step)
+        {
+            int j = 0;
+#if CV_SIMD128
+            if(haveSIMD) {
+                const v_int8x16 v_zero = v_setzero_s8();
+
+                for(; j <= dst.cols - 32; j += 32) {
+                    v_uint8x16 v_pmap1 = v_load((const unsigned char*)(pmap + j));
+                    v_uint8x16 v_pmap2 = v_load((const unsigned char*)(pmap + j + 16));
+
+                    v_uint16x8 v_pmaplo1;
+                    v_uint16x8 v_pmaphi1;
+                    v_uint16x8 v_pmaplo2;
+                    v_uint16x8 v_pmaphi2;
+                    v_expand(v_pmap1, v_pmaplo1, v_pmaphi1);
+                    v_expand(v_pmap2, v_pmaplo2, v_pmaphi2);
+
+                    v_pmaplo1 = v_pmaplo1 >> 1;
+                    v_pmaphi1 = v_pmaphi1 >> 1;
+                    v_pmaplo2 = v_pmaplo2 >> 1;
+                    v_pmaphi2 = v_pmaphi2 >> 1;
+
+                    v_pmap1 = v_pack(v_pmaplo1, v_pmaphi1);
+                    v_pmap2 = v_pack(v_pmaplo2, v_pmaphi2);
+
+                    v_pmap1 = v_reinterpret_as_u8(v_zero - v_reinterpret_as_s8(v_pmap1));
+                    v_pmap2 = v_reinterpret_as_u8(v_zero - v_reinterpret_as_s8(v_pmap2));
+
+                    v_store((pdst + j), v_pmap1);
+                    v_store((pdst + j + 16), v_pmap2);
+                }
+
+                for(; j <= dst.cols - 16; j += 16) {
+                    v_uint8x16 v_pmap = v_load((const unsigned char*)(pmap + j));
+
+                    v_uint16x8 v_pmaplo;
+                    v_uint16x8 v_pmaphi;
+                    v_expand(v_pmap, v_pmaplo, v_pmaphi);
 
-void cv::Canny( InputArray _src, OutputArray _dst,
+                    v_pmaplo = v_pmaplo >> 1;
+                    v_pmaphi = v_pmaphi >> 1;
+
+                    v_pmap = v_pack(v_pmaplo, v_pmaphi);
+                    v_pmap = v_reinterpret_as_u8(v_zero - v_reinterpret_as_s8(v_pmap));
+
+                    v_store((pdst + j), v_pmap);
+                }
+            }
+#endif
+            for (; j < dst.cols; j++)
+                pdst[j] = (uchar)-(pmap[j] >> 1);
+        }
+    }
+
+private:
+    uchar *map;
+    Mat &dst;
+    ptrdiff_t mapstep;
+};
+
+#ifdef HAVE_OPENVX
+static bool openvx_canny(const Mat& src, Mat& dst, int loVal, int hiVal, int kSize, bool useL2)
+{
+    using namespace ivx;
+
+    Context context = Context::create();
+    try
+    {
+    Image _src = Image::createFromHandle(
+                context,
+                Image::matTypeToFormat(src.type()),
+                Image::createAddressing(src),
+                src.data );
+    Image _dst = Image::createFromHandle(
+                context,
+                Image::matTypeToFormat(dst.type()),
+                Image::createAddressing(dst),
+                dst.data );
+    Threshold threshold = Threshold::createRange(context, VX_TYPE_UINT8, saturate_cast<uchar>(loVal), saturate_cast<uchar>(hiVal));
+
+#if 0
+    // the code below is disabled because vxuCannyEdgeDetector()
+    // ignores context attribute VX_CONTEXT_IMMEDIATE_BORDER
+
+    // FIXME: may fail in multithread case
+    border_t prevBorder = context.immediateBorder();
+    context.setImmediateBorder(VX_BORDER_REPLICATE);
+    IVX_CHECK_STATUS( vxuCannyEdgeDetector(context, _src, threshold, kSize, (useL2 ? VX_NORM_L2 : VX_NORM_L1), _dst) );
+    context.setImmediateBorder(prevBorder);
+#else
+    // alternative code without vxuCannyEdgeDetector()
+    Graph graph = Graph::create(context);
+    ivx::Node node = ivx::Node(vxCannyEdgeDetectorNode(graph, _src, threshold, kSize, (useL2 ? VX_NORM_L2 : VX_NORM_L1), _dst) );
+    node.setBorder(VX_BORDER_REPLICATE);
+    graph.verify();
+    graph.process();
+#endif
+
+#ifdef VX_VERSION_1_1
+    _src.swapHandle();
+    _dst.swapHandle();
+#endif
+    }
+    catch(const WrapperError& e)
+    {
+        VX_DbgThrow(e.what());
+    }
+    catch(const RuntimeError& e)
+    {
+        VX_DbgThrow(e.what());
+    }
+
+    return true;
+}
+#endif // HAVE_OPENVX
+
+void Canny( InputArray _src, OutputArray _dst,
                 double low_thresh, double high_thresh,
                 int aperture_size, bool L2gradient )
 {
+    CV_INSTRUMENT_REGION()
+
     const int type = _src.type(), depth = CV_MAT_DEPTH(type), cn = CV_MAT_CN(type);
     const Size size = _src.size();
 
@@ -607,24 +853,36 @@ void cv::Canny( InputArray _src, OutputArray _dst,
     }
 
     if ((aperture_size & 1) == 0 || (aperture_size != -1 && (aperture_size < 3 || aperture_size > 7)))
-        CV_Error(CV_StsBadFlag, "Aperture size should be odd");
+        CV_Error(CV_StsBadFlag, "Aperture size should be odd between 3 and 7");
 
     if (low_thresh > high_thresh)
         std::swap(low_thresh, high_thresh);
 
     CV_OCL_RUN(_dst.isUMat() && (cn == 1 || cn == 3),
-               ocl_Canny(_src, _dst, (float)low_thresh, (float)high_thresh, aperture_size, L2gradient, cn, size))
+               ocl_Canny<false>(_src, UMat(), UMat(), _dst, (float)low_thresh, (float)high_thresh, aperture_size, L2gradient, cn, size))
 
     Mat src = _src.getMat(), dst = _dst.getMat();
 
+    CV_OVX_RUN(
+        false && /* disabling due to accuracy issues */
+            src.type() == CV_8UC1 &&
+            !src.isSubmatrix() &&
+            src.cols >= aperture_size &&
+            src.rows >= aperture_size,
+        openvx_canny(
+            src,
+            dst,
+            cvFloor(low_thresh),
+            cvFloor(high_thresh),
+            aperture_size,
+            L2gradient ) )
+
 #ifdef HAVE_TEGRA_OPTIMIZATION
     if (tegra::useTegra() && tegra::canny(src, dst, low_thresh, high_thresh, aperture_size, L2gradient))
         return;
 #endif
 
-    CV_IPP_RUN(USE_IPP_CANNY && (aperture_size == 3 && !L2gradient && 1 == cn), ippCanny(src, dst, (float)low_thresh, (float)high_thresh))
-
-#ifdef HAVE_TBB
+    CV_IPP_RUN(USE_IPP_CANNY && (aperture_size == 3 && !L2gradient && 1 == cn), ippCanny<false>(src, Mat(), Mat(), dst, (float)low_thresh, (float)high_thresh))
 
 if (L2gradient)
 {
@@ -637,44 +895,49 @@ if (L2gradient)
 int low = cvFloor(low_thresh);
 int high = cvFloor(high_thresh);
 
-ptrdiff_t mapstep = src.cols + 2;
-AutoBuffer<uchar> buffer((src.cols+2)*(src.rows+2));
+    ptrdiff_t mapstep = src.cols + 2;
+    AutoBuffer<uchar> buffer((src.cols+2)*(src.rows+2) + cn * mapstep * 3 * sizeof(int));
 
-uchar* map = (uchar*)buffer;
-memset(map, 1, mapstep);
-memset(map + mapstep*(src.rows + 1), 1, mapstep);
+    int* mag_buf[3];
+    mag_buf[0] = (int*)(uchar*)buffer;
+    mag_buf[1] = mag_buf[0] + mapstep*cn;
+    mag_buf[2] = mag_buf[1] + mapstep*cn;
+    memset(mag_buf[0], 0, /* cn* */mapstep*sizeof(int));
 
-int threadsNumber = tbb::task_scheduler_init::default_num_threads();
-int grainSize = src.rows / threadsNumber;
+    uchar *map = (uchar*)(mag_buf[2] + mapstep*cn);
+    memset(map, 1, mapstep);
+    memset(map + mapstep*(src.rows + 1), 1, mapstep);
 
-// Make a fallback for pictures with too few rows.
-uchar ksize2 = aperture_size / 2;
-int minGrainSize = 1 + ksize2;
-int maxGrainSize = src.rows - 2 - 2*ksize2;
-if ( !( minGrainSize <= grainSize && grainSize <= maxGrainSize ) )
-{
-    threadsNumber = 1;
-    grainSize = src.rows;
-}
+    // Minimum number of threads should be 1, maximum should not exceed number of CPU's, because of overhead
+    int numOfThreads = std::max(1, std::min(getNumThreads(), getNumberOfCPUs()));
 
-tbb::task_group g;
+    // Make a fallback for pictures with too few rows.
+    int grainSize = src.rows / numOfThreads;
+    int ksize2 = aperture_size / 2;
+    // If Scharr filter: aperture size is 3, ksize2 is 1
+    if(aperture_size == -1)
+    {
+        ksize2 = 1;
+    }
 
-for (int i = 0; i < threadsNumber; ++i)
-{
-    if (i < threadsNumber - 1)
-        g.run(tbbCanny(Range(i * grainSize, (i + 1) * grainSize), src, map, low, high, aperture_size, L2gradient));
-    else
-        g.run(tbbCanny(Range(i * grainSize, src.rows), src, map, low, high, aperture_size, L2gradient));
-}
+    int minGrainSize = 2 * (ksize2 + 1);
+    if (grainSize < minGrainSize)
+    {
+        numOfThreads = std::max(1, src.rows / minGrainSize);
+    }
 
-g.wait();
+    std::queue<uchar*> borderPeaksParallel;
 
-#define CANNY_PUSH_SERIAL(d)    *(d) = uchar(2), borderPeaks.push(d)
+    parallel_for_(Range(0, src.rows), parallelCanny(src, map, low, high, aperture_size, L2gradient, &borderPeaksParallel), numOfThreads);
 
-// now track the edges (hysteresis thresholding)
-uchar* m;
-while (borderPeaks.try_pop(m))
-{
+#define CANNY_PUSH_SERIAL(d)    *(d) = uchar(2), borderPeaksParallel.push(d)
+
+    // now track the edges (hysteresis thresholding)
+    uchar* m;
+    while (!borderPeaksParallel.empty())
+    {
+        m = borderPeaksParallel.front();
+        borderPeaksParallel.pop();
     if (!m[-1])         CANNY_PUSH_SERIAL(m - 1);
     if (!m[1])          CANNY_PUSH_SERIAL(m + 1);
     if (!m[-mapstep-1]) CANNY_PUSH_SERIAL(m - mapstep - 1);
@@ -685,13 +948,48 @@ while (borderPeaks.try_pop(m))
     if (!m[mapstep+1])  CANNY_PUSH_SERIAL(m + mapstep + 1);
 }
 
-#else
+    parallel_for_(Range(0, dst.rows), finalPass(map, dst, mapstep), dst.total()/(double)(1<<16));
+}
+
+void Canny( InputArray _dx, InputArray _dy, OutputArray _dst,
+                double low_thresh, double high_thresh,
+                bool L2gradient )
+{
+    CV_Assert(_dx.dims() == 2);
+    CV_Assert(_dx.type() == CV_16SC1 || _dx.type() == CV_16SC3);
+    CV_Assert(_dy.type() == _dx.type());
+    CV_Assert(_dx.sameSize(_dy));
 
-    Mat dx(src.rows, src.cols, CV_16SC(cn));
-    Mat dy(src.rows, src.cols, CV_16SC(cn));
+    if (low_thresh > high_thresh)
+        std::swap(low_thresh, high_thresh);
 
-    Sobel(src, dx, CV_16S, 1, 0, aperture_size, 1, 0, BORDER_REPLICATE);
-    Sobel(src, dy, CV_16S, 0, 1, aperture_size, 1, 0, BORDER_REPLICATE);
+    const int cn = _dx.channels();
+    const Size size = _dx.size();
+
+    CV_OCL_RUN(_dst.isUMat(),
+               ocl_Canny<true>(UMat(), _dx.getUMat(), _dy.getUMat(), _dst, (float)low_thresh, (float)high_thresh, 0, L2gradient, cn, size))
+
+    _dst.create(size, CV_8U);
+    Mat dst = _dst.getMat();
+
+    Mat dx = _dx.getMat();
+    Mat dy = _dy.getMat();
+
+    CV_IPP_RUN(USE_IPP_CANNY && (!L2gradient && 1 == cn), ippCanny<true>(Mat(), dx, dy, dst, (float)low_thresh, (float)high_thresh))
+
+    if (cn > 1)
+    {
+        dx = dx.clone();
+        dy = dy.clone();
+    }
+    CannyImpl(dx, dy, dst, low_thresh, high_thresh, L2gradient);
+}
+
+static void CannyImpl(Mat& dx, Mat& dy, Mat& dst,
+    double low_thresh, double high_thresh, bool L2gradient)
+{
+    const int cn = dx.channels();
+    const int cols = dx.cols, rows = dx.rows;
 
     if (L2gradient)
     {
@@ -704,8 +1002,8 @@ while (borderPeaks.try_pop(m))
     int low = cvFloor(low_thresh);
     int high = cvFloor(high_thresh);
 
-    ptrdiff_t mapstep = src.cols + 2;
-    AutoBuffer<uchar> buffer((src.cols+2)*(src.rows+2) + cn * mapstep * 3 * sizeof(int));
+    ptrdiff_t mapstep = cols + 2;
+    AutoBuffer<uchar> buffer((cols+2)*(rows+2) + cn * mapstep * 3 * sizeof(int));
 
     int* mag_buf[3];
     mag_buf[0] = (int*)(uchar*)buffer;
@@ -715,9 +1013,9 @@ while (borderPeaks.try_pop(m))
 
     uchar* map = (uchar*)(mag_buf[2] + mapstep*cn);
     memset(map, 1, mapstep);
-    memset(map + mapstep*(src.rows + 1), 1, mapstep);
+    memset(map + mapstep*(rows + 1), 1, mapstep);
 
-    int maxsize = std::max(1 << 10, src.cols * src.rows / 10);
+    int maxsize = std::max(1 << 10, cols * rows / 10);
     std::vector<uchar*> stack(maxsize);
     uchar **stack_top = &stack[0];
     uchar **stack_bottom = &stack[0];
@@ -737,8 +1035,8 @@ while (borderPeaks.try_pop(m))
     #define CANNY_PUSH(d)    *(d) = uchar(2), *stack_top++ = (d)
     #define CANNY_POP(d)     (d) = *--stack_top
 
-#if CV_SSE2
-    bool haveSSE2 = checkHardwareSupport(CV_CPU_SSE2);
+#if CV_SIMD128
+    bool haveSIMD = hasSIMD128();
 #endif
 
     // calculate magnitude and angle of gradient, perform non-maxima suppression.
@@ -746,81 +1044,63 @@ while (borderPeaks.try_pop(m))
     //   0 - the pixel might belong to an edge
     //   1 - the pixel can not belong to an edge
     //   2 - the pixel does belong to an edge
-    for (int i = 0; i <= src.rows; i++)
+    for (int i = 0; i <= rows; i++)
     {
         int* _norm = mag_buf[(i > 0) + 1] + 1;
-        if (i < src.rows)
+        if (i < rows)
         {
             short* _dx = dx.ptr<short>(i);
             short* _dy = dy.ptr<short>(i);
 
             if (!L2gradient)
             {
-                int j = 0, width = src.cols * cn;
-#if CV_SSE2
-                if (haveSSE2)
+                int j = 0, width = cols * cn;
+#if CV_SIMD128
+                if (haveSIMD)
                 {
-                    __m128i v_zero = _mm_setzero_si128();
                     for ( ; j <= width - 8; j += 8)
                     {
-                        __m128i v_dx = _mm_loadu_si128((const __m128i *)(_dx + j));
-                        __m128i v_dy = _mm_loadu_si128((const __m128i *)(_dy + j));
-                        v_dx = _mm_max_epi16(v_dx, _mm_sub_epi16(v_zero, v_dx));
-                        v_dy = _mm_max_epi16(v_dy, _mm_sub_epi16(v_zero, v_dy));
+                        v_int16x8 v_dx = v_load((const short*)(_dx + j));
+                        v_int16x8 v_dy = v_load((const short*)(_dy + j));
 
-                        __m128i v_norm = _mm_add_epi32(_mm_unpacklo_epi16(v_dx, v_zero), _mm_unpacklo_epi16(v_dy, v_zero));
-                        _mm_storeu_si128((__m128i *)(_norm + j), v_norm);
+                        v_int32x4 v_dx0, v_dx1, v_dy0, v_dy1;
+                        v_expand(v_dx, v_dx0, v_dx1);
+                        v_expand(v_dy, v_dy0, v_dy1);
 
-                        v_norm = _mm_add_epi32(_mm_unpackhi_epi16(v_dx, v_zero), _mm_unpackhi_epi16(v_dy, v_zero));
-                        _mm_storeu_si128((__m128i *)(_norm + j + 4), v_norm);
+                        v_dx0 = v_reinterpret_as_s32(v_abs(v_dx0));
+                        v_dx1 = v_reinterpret_as_s32(v_abs(v_dx1));
+                        v_dy0 = v_reinterpret_as_s32(v_abs(v_dy0));
+                        v_dy1 = v_reinterpret_as_s32(v_abs(v_dy1));
+
+                        v_store(_norm + j, v_dx0 + v_dy0);
+                        v_store(_norm + j + 4, v_dx1 + v_dy1);
                     }
                 }
-#elif CV_NEON
-                for ( ; j <= width - 8; j += 8)
-                {
-                    int16x8_t v_dx = vld1q_s16(_dx + j), v_dy = vld1q_s16(_dy + j);
-                    vst1q_s32(_norm + j, vaddq_s32(vabsq_s32(vmovl_s16(vget_low_s16(v_dx))),
-                                                   vabsq_s32(vmovl_s16(vget_low_s16(v_dy)))));
-                    vst1q_s32(_norm + j + 4, vaddq_s32(vabsq_s32(vmovl_s16(vget_high_s16(v_dx))),
-                                                       vabsq_s32(vmovl_s16(vget_high_s16(v_dy)))));
-                }
 #endif
                 for ( ; j < width; ++j)
                     _norm[j] = std::abs(int(_dx[j])) + std::abs(int(_dy[j]));
             }
             else
             {
-                int j = 0, width = src.cols * cn;
-#if CV_SSE2
-                if (haveSSE2)
+                int j = 0, width = cols * cn;
+#if CV_SIMD128
+                if (haveSIMD)
                 {
                     for ( ; j <= width - 8; j += 8)
                     {
-                        __m128i v_dx = _mm_loadu_si128((const __m128i *)(_dx + j));
-                        __m128i v_dy = _mm_loadu_si128((const __m128i *)(_dy + j));
+                        v_int16x8 v_dx = v_load((const short*)(_dx + j));
+                        v_int16x8 v_dy = v_load((const short*)(_dy + j));
 
-                        __m128i v_dx_ml = _mm_mullo_epi16(v_dx, v_dx), v_dx_mh = _mm_mulhi_epi16(v_dx, v_dx);
-                        __m128i v_dy_ml = _mm_mullo_epi16(v_dy, v_dy), v_dy_mh = _mm_mulhi_epi16(v_dy, v_dy);
+                        v_int16x8 v_dx_dy0, v_dx_dy1;
+                        v_zip(v_dx, v_dy, v_dx_dy0, v_dx_dy1);
 
-                        __m128i v_norm = _mm_add_epi32(_mm_unpacklo_epi16(v_dx_ml, v_dx_mh), _mm_unpacklo_epi16(v_dy_ml, v_dy_mh));
-                        _mm_storeu_si128((__m128i *)(_norm + j), v_norm);
+                        v_int32x4 v_dst0 = v_dotprod(v_dx_dy0, v_dx_dy0);
+                        v_int32x4 v_dst1 = v_dotprod(v_dx_dy1, v_dx_dy1);
 
-                        v_norm = _mm_add_epi32(_mm_unpackhi_epi16(v_dx_ml, v_dx_mh), _mm_unpackhi_epi16(v_dy_ml, v_dy_mh));
-                        _mm_storeu_si128((__m128i *)(_norm + j + 4), v_norm);
+                        v_store(_norm + j, v_dst0);
+                        v_store(_norm + j + 4, v_dst1);
                     }
                 }
-#elif CV_NEON
-                for ( ; j <= width - 8; j += 8)
-                {
-                    int16x8_t v_dx = vld1q_s16(_dx + j), v_dy = vld1q_s16(_dy + j);
-                    int16x4_t v_dxp = vget_low_s16(v_dx), v_dyp = vget_low_s16(v_dy);
-                    int32x4_t v_dst = vmlal_s16(vmull_s16(v_dxp, v_dxp), v_dyp, v_dyp);
-                    vst1q_s32(_norm + j, v_dst);
-
-                    v_dxp = vget_high_s16(v_dx), v_dyp = vget_high_s16(v_dy);
-                    v_dst = vmlal_s16(vmull_s16(v_dxp, v_dxp), v_dyp, v_dyp);
-                    vst1q_s32(_norm + j + 4, v_dst);
-                }
 #endif
                 for ( ; j < width; ++j)
                     _norm[j] = int(_dx[j])*_dx[j] + int(_dy[j])*_dy[j];
@@ -828,7 +1108,7 @@ while (borderPeaks.try_pop(m))
 
             if (cn > 1)
             {
-                for(int j = 0, jn = 0; j < src.cols; ++j, jn += cn)
+                for(int j = 0, jn = 0; j < cols; ++j, jn += cn)
                 {
                     int maxIdx = jn;
                     for(int k = 1; k < cn; ++k)
@@ -838,7 +1118,7 @@ while (borderPeaks.try_pop(m))
                     _dy[j] = _dy[maxIdx];
                 }
             }
-            _norm[-1] = _norm[src.cols] = 0;
+            _norm[-1] = _norm[cols] = 0;
         }
         else
             memset(_norm-1, 0, /* cn* */mapstep*sizeof(int));
@@ -849,7 +1129,7 @@ while (borderPeaks.try_pop(m))
             continue;
 
         uchar* _map = map + mapstep*i + 1;
-        _map[-1] = _map[src.cols] = 1;
+        _map[-1] = _map[cols] = 1;
 
         int* _mag = mag_buf[1] + 1; // take the central row
         ptrdiff_t magstep1 = mag_buf[2] - mag_buf[1];
@@ -858,21 +1138,102 @@ while (borderPeaks.try_pop(m))
         const short* _x = dx.ptr<short>(i-1);
         const short* _y = dy.ptr<short>(i-1);
 
-        if ((stack_top - stack_bottom) + src.cols > maxsize)
+        if ((stack_top - stack_bottom) + cols > maxsize)
         {
             int sz = (int)(stack_top - stack_bottom);
-            maxsize = std::max(maxsize * 3/2, sz + src.cols);
+            maxsize = std::max(maxsize * 3/2, sz + cols);
             stack.resize(maxsize);
             stack_bottom = &stack[0];
             stack_top = stack_bottom + sz;
         }
 
-        int prev_flag = 0;
-        for (int j = 0; j < src.cols; j++)
+#define CANNY_SHIFT 15
+        const int TG22 = (int)(0.4142135623730950488016887242097*(1<<CANNY_SHIFT) + 0.5);
+
+        int prev_flag = 0, j = 0;
+#if CV_SIMD128
+        if (haveSIMD)
         {
-            #define CANNY_SHIFT 15
-            const int TG22 = (int)(0.4142135623730950488016887242097*(1<<CANNY_SHIFT) + 0.5);
+            v_int32x4 v_low = v_setall_s32(low);
+            v_int8x16 v_one = v_setall_s8(1);
+
+            for (; j <= cols - 16; j += 16)
+            {
+                v_int32x4 v_m1 = v_load((const int*)(_mag + j));
+                v_int32x4 v_m2 = v_load((const int*)(_mag + j + 4));
+                v_int32x4 v_m3 = v_load((const int*)(_mag + j + 8));
+                v_int32x4 v_m4 = v_load((const int*)(_mag + j + 12));
 
+                v_store((signed char*)(_map + j), v_one);
+
+                v_int32x4 v_cmp1 = v_m1 > v_low;
+                v_int32x4 v_cmp2 = v_m2 > v_low;
+                v_int32x4 v_cmp3 = v_m3 > v_low;
+                v_int32x4 v_cmp4 = v_m4 > v_low;
+
+                v_int16x8 v_cmp80 = v_pack(v_cmp1, v_cmp2);
+                v_int16x8 v_cmp81 = v_pack(v_cmp3, v_cmp4);
+
+                v_int8x16 v_cmp = v_pack(v_cmp80, v_cmp81);
+                unsigned int mask = v_signmask(v_cmp);
+
+                if (mask)
+                {
+                    int m, k = j;
+
+                    for (; mask; ++k, mask >>= 1)
+                    {
+                        if (mask & 0x00000001)
+                        {
+                            m = _mag[k];
+                            int xs = _x[k];
+                            int ys = _y[k];
+                            int x = std::abs(xs);
+                            int y = std::abs(ys) << CANNY_SHIFT;
+
+                            int tg22x = x * TG22;
+
+                            if (y < tg22x)
+                            {
+                                if (m > _mag[k - 1] && m >= _mag[k + 1]) goto ocv_canny_push_sse;
+                            }
+                            else
+                            {
+                                int tg67x = tg22x + (x << (CANNY_SHIFT + 1));
+                                if (y > tg67x)
+                                {
+                                    if (m > _mag[k + magstep2] && m >= _mag[k + magstep1]) goto ocv_canny_push_sse;
+                                } else
+                                {
+                                    int s = (xs ^ ys) < 0 ? -1 : 1;
+                                    if (m > _mag[k + magstep2 - s] && m > _mag[k + magstep1 + s]) goto ocv_canny_push_sse;
+                                }
+                            }
+                        }
+
+                        prev_flag = 0;
+                        continue;
+
+ocv_canny_push_sse:
+                        // _map[k-mapstep] is short-circuited at the start because previous thread is
+                        // responsible for initializing it.
+                        if (!prev_flag && m > high && _map[k-mapstep] != 2)
+                        {
+                            CANNY_PUSH(_map + k);
+                            prev_flag = 1;
+                        } else
+                            _map[k] = 0;
+
+                    }
+
+                    if (prev_flag && ((k < j+16) || (k < cols && _mag[k] <= high)))
+                        prev_flag = 0;
+                }
+            }
+        }
+#endif
+        for (; j < cols; j++)
+        {
             int m = _mag[j];
 
             if (m > low)
@@ -947,18 +1308,11 @@ __ocv_canny_push:
         if (!m[mapstep+1])  CANNY_PUSH(m + mapstep + 1);
     }
 
-#endif
-
-    // the final pass, form the final image
-    const uchar* pmap = map + mapstep + 1;
-    uchar* pdst = dst.ptr();
-    for (int i = 0; i < src.rows; i++, pmap += mapstep, pdst += dst.step)
-    {
-        for (int j = 0; j < src.cols; j++)
-            pdst[j] = (uchar)-(pmap[j] >> 1);
-    }
+    parallel_for_(Range(0, dst.rows), finalPass(map, dst, mapstep), dst.total()/(double)(1<<16));
 }
 
+} // namespace cv
+
 void cvCanny( const CvArr* image, CvArr* edges, double threshold1,
               double threshold2, int aperture_size )
 {
diff --git a/modules/imgproc/src/clahe.cpp b/modules/imgproc/src/clahe.cpp
index fcd6c21..1bec038 100644
--- a/modules/imgproc/src/clahe.cpp
+++ b/modules/imgproc/src/clahe.cpp
@@ -212,8 +212,12 @@ namespace
                 for (int i = 0; i < histSize; ++i)
                     tileHist[i] += redistBatch;
 
-                for (int i = 0; i < residual; ++i)
-                    tileHist[i]++;
+                if (residual != 0)
+                {
+                    int residualStep = MAX(histSize / residual, 1);
+                    for (int i = 0; i < histSize && residual > 0; i += residualStep, residual--)
+                        tileHist[i]++;
+                }
             }
 
             // calc Lut
@@ -227,7 +231,7 @@ namespace
         }
     }
 
-    template <class T>
+    template <class T, int shift>
     class CLAHE_Interpolation_Body : public cv::ParallelLoopBody
     {
     public:
@@ -277,8 +281,8 @@ namespace
         float * xa_p, * xa1_p;
     };
 
-    template <class T>
-    void CLAHE_Interpolation_Body<T>::operator ()(const cv::Range& range) const
+    template <class T, int shift>
+    void CLAHE_Interpolation_Body<T, shift>::operator ()(const cv::Range& range) const
     {
         float inv_th = 1.0f / tileSize_.height;
 
@@ -302,7 +306,7 @@ namespace
 
             for (int x = 0; x < src_.cols; ++x)
             {
-                int srcVal = srcRow[x];
+                int srcVal = srcRow[x] >> shift;
 
                 int ind1 = ind1_p[x] + srcVal;
                 int ind2 = ind2_p[x] + srcVal;
@@ -310,7 +314,7 @@ namespace
                 float res = (lutPlane1[ind1] * xa1_p[x] + lutPlane1[ind2] * xa_p[x]) * ya1 +
                             (lutPlane2[ind1] * xa1_p[x] + lutPlane2[ind2] * xa_p[x]) * ya;
 
-                dstRow[x] = cv::saturate_cast<T>(res);
+                dstRow[x] = cv::saturate_cast<T>(res) << shift;
             }
         }
     }
@@ -351,13 +355,15 @@ namespace
 
     void CLAHE_Impl::apply(cv::InputArray _src, cv::OutputArray _dst)
     {
+        CV_INSTRUMENT_REGION()
+
         CV_Assert( _src.type() == CV_8UC1 || _src.type() == CV_16UC1 );
 
 #ifdef HAVE_OPENCL
         bool useOpenCL = cv::ocl::useOpenCL() && _src.isUMat() && _src.dims()<=2 && _src.type() == CV_8UC1;
 #endif
 
-        int histSize = _src.type() == CV_8UC1 ? 256 : 4096;
+        int histSize = _src.type() == CV_8UC1 ? 256 : 65536;
 
         cv::Size tileSize;
         cv::_InputArray _srcForLut;
@@ -414,7 +420,7 @@ namespace
         if (_src.type() == CV_8UC1)
             calcLutBody = cv::makePtr<CLAHE_CalcLut_Body<uchar, 256, 0> >(srcForLut, lut_, tileSize, tilesX_, clipLimit, lutScale);
         else if (_src.type() == CV_16UC1)
-            calcLutBody = cv::makePtr<CLAHE_CalcLut_Body<ushort, 4096, 4> >(srcForLut, lut_, tileSize, tilesX_, clipLimit, lutScale);
+            calcLutBody = cv::makePtr<CLAHE_CalcLut_Body<ushort, 65536, 0> >(srcForLut, lut_, tileSize, tilesX_, clipLimit, lutScale);
         else
             CV_Error( CV_StsBadArg, "Unsupported type" );
 
@@ -422,9 +428,9 @@ namespace
 
         cv::Ptr<cv::ParallelLoopBody> interpolationBody;
         if (_src.type() == CV_8UC1)
-            interpolationBody = cv::makePtr<CLAHE_Interpolation_Body<uchar> >(src, dst, lut_, tileSize, tilesX_, tilesY_);
+            interpolationBody = cv::makePtr<CLAHE_Interpolation_Body<uchar, 0> >(src, dst, lut_, tileSize, tilesX_, tilesY_);
         else if (_src.type() == CV_16UC1)
-            interpolationBody = cv::makePtr<CLAHE_Interpolation_Body<ushort> >(src, dst, lut_, tileSize, tilesX_, tilesY_);
+            interpolationBody = cv::makePtr<CLAHE_Interpolation_Body<ushort, 0> >(src, dst, lut_, tileSize, tilesX_, tilesY_);
 
         cv::parallel_for_(cv::Range(0, src.rows), *interpolationBody);
     }
diff --git a/modules/imgproc/src/color.cpp b/modules/imgproc/src/color.cpp
index 95197ec..b571e1e 100644
--- a/modules/imgproc/src/color.cpp
+++ b/modules/imgproc/src/color.cpp
@@ -93,6 +93,7 @@
 #include "precomp.hpp"
 #include "opencl_kernels_imgproc.hpp"
 #include <limits>
+#include "hal_replacement.hpp"
 
 #define  CV_DESCALE(x,n)     (((x) + (1 << ((n)-1))) >> (n))
 
@@ -104,6 +105,39 @@
 
 namespace cv
 {
+//constants for conversion from/to RGB and Gray, YUV, YCrCb according to BT.601
+const float B2YF = 0.114f;
+const float G2YF = 0.587f;
+const float R2YF = 0.299f;
+//to YCbCr
+const float YCBF = 0.564f; // == 1/2/(1-B2YF)
+const float YCRF = 0.713f; // == 1/2/(1-R2YF)
+const int YCBI = 9241;  // == YCBF*16384
+const int YCRI = 11682; // == YCRF*16384
+//to YUV
+const float B2UF = 0.492f;
+const float R2VF = 0.877f;
+const int B2UI = 8061;  // == B2UF*16384
+const int R2VI = 14369; // == R2VF*16384
+//from YUV
+const float U2BF = 2.032f;
+const float U2GF = -0.395f;
+const float V2GF = -0.581f;
+const float V2RF = 1.140f;
+const int U2BI = 33292;
+const int U2GI = -6472;
+const int V2GI = -9519;
+const int V2RI = 18678;
+//from YCrCb
+const float CB2BF = 1.773f;
+const float CB2GF = -0.344f;
+const float CR2GF = -0.714f;
+const float CR2RF = 1.403f;
+const int CB2BI = 29049;
+const int CB2GI = -5636;
+const int CR2GI = -11698;
+const int CR2RI = 22987;
+
 
 // computes cubic spline coefficients for a function: (xi=i, yi=f[i]), i=0..n
 template<typename _Tp> static void splineBuild(const _Tp* f, int n, _Tp* tab)
@@ -140,6 +174,64 @@ template<typename _Tp> static inline _Tp splineInterpolate(_Tp x, const _Tp* tab
     return ((tab[3]*x + tab[2])*x + tab[1])*x + tab[0];
 }
 
+#if CV_NEON
+template<typename _Tp> static inline void splineInterpolate(float32x4_t& v_x, const _Tp* tab, int n)
+{
+    int32x4_t v_ix = vcvtq_s32_f32(vminq_f32(vmaxq_f32(v_x, vdupq_n_f32(0)), vdupq_n_f32(n - 1)));
+    v_x = vsubq_f32(v_x, vcvtq_f32_s32(v_ix));
+    v_ix = vshlq_n_s32(v_ix, 2);
+
+    int CV_DECL_ALIGNED(16) ix[4];
+    vst1q_s32(ix, v_ix);
+
+    float32x4_t v_tab0 = vld1q_f32(tab + ix[0]);
+    float32x4_t v_tab1 = vld1q_f32(tab + ix[1]);
+    float32x4_t v_tab2 = vld1q_f32(tab + ix[2]);
+    float32x4_t v_tab3 = vld1q_f32(tab + ix[3]);
+
+    float32x4x2_t v01 = vtrnq_f32(v_tab0, v_tab1);
+    float32x4x2_t v23 = vtrnq_f32(v_tab2, v_tab3);
+
+    v_tab0 = vcombine_f32(vget_low_f32(v01.val[0]), vget_low_f32(v23.val[0]));
+    v_tab1 = vcombine_f32(vget_low_f32(v01.val[1]), vget_low_f32(v23.val[1]));
+    v_tab2 = vcombine_f32(vget_high_f32(v01.val[0]), vget_high_f32(v23.val[0]));
+    v_tab3 = vcombine_f32(vget_high_f32(v01.val[1]), vget_high_f32(v23.val[1]));
+
+    v_x = vmlaq_f32(v_tab0, vmlaq_f32(v_tab1, vmlaq_f32(v_tab2, v_tab3, v_x), v_x), v_x);
+}
+#elif CV_SSE2
+template<typename _Tp> static inline void splineInterpolate(__m128& v_x, const _Tp* tab, int n)
+{
+    __m128i v_ix = _mm_cvttps_epi32(_mm_min_ps(_mm_max_ps(v_x, _mm_setzero_ps()), _mm_set1_ps(float(n - 1))));
+    v_x = _mm_sub_ps(v_x, _mm_cvtepi32_ps(v_ix));
+    v_ix = _mm_slli_epi32(v_ix, 2);
+
+    int CV_DECL_ALIGNED(16) ix[4];
+    _mm_store_si128((__m128i *)ix, v_ix);
+
+    __m128 v_tab0 = _mm_loadu_ps(tab + ix[0]);
+    __m128 v_tab1 = _mm_loadu_ps(tab + ix[1]);
+    __m128 v_tab2 = _mm_loadu_ps(tab + ix[2]);
+    __m128 v_tab3 = _mm_loadu_ps(tab + ix[3]);
+
+    __m128 v_tmp0 = _mm_unpacklo_ps(v_tab0, v_tab1);
+    __m128 v_tmp1 = _mm_unpacklo_ps(v_tab2, v_tab3);
+    __m128 v_tmp2 = _mm_unpackhi_ps(v_tab0, v_tab1);
+    __m128 v_tmp3 = _mm_unpackhi_ps(v_tab2, v_tab3);
+
+    v_tab0 = _mm_shuffle_ps(v_tmp0, v_tmp1, 0x44);
+    v_tab2 = _mm_shuffle_ps(v_tmp2, v_tmp3, 0x44);
+    v_tab1 = _mm_shuffle_ps(v_tmp0, v_tmp1, 0xee);
+    v_tab3 = _mm_shuffle_ps(v_tmp2, v_tmp3, 0xee);
+
+    __m128 v_l = _mm_mul_ps(v_x, v_tab3);
+    v_l = _mm_add_ps(v_l, v_tab2);
+    v_l = _mm_mul_ps(v_l, v_x);
+    v_l = _mm_add_ps(v_l, v_tab1);
+    v_l = _mm_mul_ps(v_l, v_x);
+    v_x = _mm_add_ps(v_l, v_tab0);
+}
+#endif
 
 template<typename _Tp> struct ColorChannel
 {
@@ -171,32 +263,38 @@ class CvtColorLoop_Invoker : public ParallelLoopBody
     typedef typename Cvt::channel_type _Tp;
 public:
 
-    CvtColorLoop_Invoker(const Mat& _src, Mat& _dst, const Cvt& _cvt) :
-        ParallelLoopBody(), src(_src), dst(_dst), cvt(_cvt)
+    CvtColorLoop_Invoker(const uchar * src_data_, size_t src_step_, uchar * dst_data_, size_t dst_step_, int width_, const Cvt& _cvt) :
+        ParallelLoopBody(), src_data(src_data_), src_step(src_step_), dst_data(dst_data_), dst_step(dst_step_),
+        width(width_), cvt(_cvt)
     {
     }
 
     virtual void operator()(const Range& range) const
     {
-        const uchar* yS = src.ptr<uchar>(range.start);
-        uchar* yD = dst.ptr<uchar>(range.start);
+        const uchar* yS = src_data + static_cast<size_t>(range.start) * src_step;
+        uchar* yD = dst_data + static_cast<size_t>(range.start) * dst_step;
 
-        for( int i = range.start; i < range.end; ++i, yS += src.step, yD += dst.step )
-            cvt((const _Tp*)yS, (_Tp*)yD, src.cols);
+        for( int i = range.start; i < range.end; ++i, yS += src_step, yD += dst_step )
+            cvt(reinterpret_cast<const _Tp*>(yS), reinterpret_cast<_Tp*>(yD), width);
     }
 
 private:
-    const Mat& src;
-    Mat& dst;
+    const uchar * src_data;
+    size_t src_step;
+    uchar * dst_data;
+    size_t dst_step;
+    int width;
     const Cvt& cvt;
 
     const CvtColorLoop_Invoker& operator= (const CvtColorLoop_Invoker&);
 };
 
 template <typename Cvt>
-void CvtColorLoop(const Mat& src, Mat& dst, const Cvt& cvt)
+void CvtColorLoop(const uchar * src_data, size_t src_step, uchar * dst_data, size_t dst_step, int width, int height, const Cvt& cvt)
 {
-    parallel_for_(Range(0, src.rows), CvtColorLoop_Invoker<Cvt>(src, dst, cvt), src.total()/(double)(1<<16) );
+    parallel_for_(Range(0, height),
+                  CvtColorLoop_Invoker<Cvt>(src_data, src_step, dst_data, dst_step, width, cvt),
+                  (width * height) / static_cast<double>(1<<16));
 }
 
 #if defined (HAVE_IPP) && (IPP_VERSION_X100 >= 700)
@@ -211,17 +309,17 @@ class CvtColorIPPLoop_Invoker :
 {
 public:
 
-    CvtColorIPPLoop_Invoker(const Mat& _src, Mat& _dst, const Cvt& _cvt, bool *_ok) :
-        ParallelLoopBody(), src(_src), dst(_dst), cvt(_cvt), ok(_ok)
+    CvtColorIPPLoop_Invoker(const uchar * src_data_, size_t src_step_, uchar * dst_data_, size_t dst_step_, int width_, const Cvt& _cvt, bool *_ok) :
+        ParallelLoopBody(), src_data(src_data_), src_step(src_step_), dst_data(dst_data_), dst_step(dst_step_), width(width_), cvt(_cvt), ok(_ok)
     {
         *ok = true;
     }
 
     virtual void operator()(const Range& range) const
     {
-        const void *yS = src.ptr<uchar>(range.start);
-        void *yD = dst.ptr<uchar>(range.start);
-        if( !cvt(yS, (int)src.step[0], yD, (int)dst.step[0], src.cols, range.end - range.start) )
+        const void *yS = src_data + src_step * range.start;
+        void *yD = dst_data + dst_step * range.start;
+        if( !cvt(yS, static_cast<int>(src_step), yD, static_cast<int>(dst_step), width, range.end - range.start) )
             *ok = false;
         else
         {
@@ -230,8 +328,11 @@ public:
     }
 
 private:
-    const Mat& src;
-    Mat& dst;
+    const uchar * src_data;
+    size_t src_step;
+    uchar * dst_data;
+    size_t dst_step;
+    int width;
     const Cvt& cvt;
     bool *ok;
 
@@ -239,25 +340,28 @@ private:
 };
 
 template <typename Cvt>
-bool CvtColorIPPLoop(const Mat& src, Mat& dst, const Cvt& cvt)
+bool CvtColorIPPLoop(const uchar * src_data, size_t src_step, uchar * dst_data, size_t dst_step, int width, int height, const Cvt& cvt)
 {
     bool ok;
-    parallel_for_(Range(0, src.rows), CvtColorIPPLoop_Invoker<Cvt>(src, dst, cvt, &ok), src.total()/(double)(1<<16) );
+    parallel_for_(Range(0, height), CvtColorIPPLoop_Invoker<Cvt>(src_data, src_step, dst_data, dst_step, width, cvt, &ok), (width * height)/(double)(1<<16) );
     return ok;
 }
 
 template <typename Cvt>
-bool CvtColorIPPLoopCopy(Mat& src, Mat& dst, const Cvt& cvt)
+bool CvtColorIPPLoopCopy(const uchar * src_data, size_t src_step, int src_type, uchar * dst_data, size_t dst_step, int width, int height, const Cvt& cvt)
 {
     Mat temp;
-    Mat &source = src;
-    if( src.data == dst.data )
+    Mat src(Size(width, height), src_type, const_cast<uchar*>(src_data), src_step);
+    Mat source = src;
+    if( src_data == dst_data )
     {
         src.copyTo(temp);
         source = temp;
     }
     bool ok;
-    parallel_for_(Range(0, source.rows), CvtColorIPPLoop_Invoker<Cvt>(source, dst, cvt, &ok),
+    parallel_for_(Range(0, source.rows),
+                  CvtColorIPPLoop_Invoker<Cvt>(source.data, source.step, dst_data, dst_step,
+                                               source.cols, cvt, &ok),
                   source.total()/(double)(1<<16) );
     return ok;
 }
@@ -265,19 +369,19 @@ bool CvtColorIPPLoopCopy(Mat& src, Mat& dst, const Cvt& cvt)
 static IppStatus CV_STDCALL ippiSwapChannels_8u_C3C4Rf(const Ipp8u* pSrc, int srcStep, Ipp8u* pDst, int dstStep,
          IppiSize roiSize, const int *dstOrder)
 {
-    return ippiSwapChannels_8u_C3C4R(pSrc, srcStep, pDst, dstStep, roiSize, dstOrder, MAX_IPP8u);
+    return CV_INSTRUMENT_FUN_IPP(ippiSwapChannels_8u_C3C4R, pSrc, srcStep, pDst, dstStep, roiSize, dstOrder, MAX_IPP8u);
 }
 
 static IppStatus CV_STDCALL ippiSwapChannels_16u_C3C4Rf(const Ipp16u* pSrc, int srcStep, Ipp16u* pDst, int dstStep,
          IppiSize roiSize, const int *dstOrder)
 {
-    return ippiSwapChannels_16u_C3C4R(pSrc, srcStep, pDst, dstStep, roiSize, dstOrder, MAX_IPP16u);
+    return CV_INSTRUMENT_FUN_IPP(ippiSwapChannels_16u_C3C4R, pSrc, srcStep, pDst, dstStep, roiSize, dstOrder, MAX_IPP16u);
 }
 
 static IppStatus CV_STDCALL ippiSwapChannels_32f_C3C4Rf(const Ipp32f* pSrc, int srcStep, Ipp32f* pDst, int dstStep,
          IppiSize roiSize, const int *dstOrder)
 {
-    return ippiSwapChannels_32f_C3C4R(pSrc, srcStep, pDst, dstStep, roiSize, dstOrder, MAX_IPP32f);
+    return CV_INSTRUMENT_FUN_IPP(ippiSwapChannels_32f_C3C4R, pSrc, srcStep, pDst, dstStep, roiSize, dstOrder, MAX_IPP32f);
 }
 
 static ippiReorderFunc ippiSwapChannelsC3C4RTab[] =
@@ -354,11 +458,13 @@ static ippiGeneralFunc ippiXYZ2RGBTab[] =
     0, (ippiGeneralFunc)ippiXYZToRGB_32f_C3R, 0, 0
 };
 
+#if IPP_DISABLE_BLOCK
 static ippiGeneralFunc ippiRGB2HSVTab[] =
 {
     (ippiGeneralFunc)ippiRGBToHSV_8u_C3R, 0, (ippiGeneralFunc)ippiRGBToHSV_16u_C3R, 0,
     0, 0, 0, 0
 };
+#endif
 
 static ippiGeneralFunc ippiHSV2RGBTab[] =
 {
@@ -378,7 +484,7 @@ static ippiGeneralFunc ippiHLS2RGBTab[] =
     0, (ippiGeneralFunc)ippiHLSToRGB_32f_C3R, 0, 0
 };
 
-#if !defined(HAVE_IPP_ICV_ONLY) && IPP_DISABLE_BLOCK
+#if IPP_DISABLE_BLOCK
 static ippiGeneralFunc ippiRGBToLUVTab[] =
 {
     (ippiGeneralFunc)ippiRGBToLUV_8u_C3R, 0, (ippiGeneralFunc)ippiRGBToLUV_16u_C3R, 0,
@@ -394,18 +500,18 @@ static ippiGeneralFunc ippiLUVToRGBTab[] =
 
 struct IPPGeneralFunctor
 {
-    IPPGeneralFunctor(ippiGeneralFunc _func) : func(_func){}
+    IPPGeneralFunctor(ippiGeneralFunc _func) : ippiColorConvertGeneral(_func){}
     bool operator()(const void *src, int srcStep, void *dst, int dstStep, int cols, int rows) const
     {
-        return func ? func(src, srcStep, dst, dstStep, ippiSize(cols, rows)) >= 0 : false;
+        return ippiColorConvertGeneral ? CV_INSTRUMENT_FUN_IPP(ippiColorConvertGeneral, src, srcStep, dst, dstStep, ippiSize(cols, rows)) >= 0 : false;
     }
 private:
-    ippiGeneralFunc func;
+    ippiGeneralFunc ippiColorConvertGeneral;
 };
 
 struct IPPReorderFunctor
 {
-    IPPReorderFunctor(ippiReorderFunc _func, int _order0, int _order1, int _order2) : func(_func)
+    IPPReorderFunctor(ippiReorderFunc _func, int _order0, int _order1, int _order2) : ippiColorConvertReorder(_func)
     {
         order[0] = _order0;
         order[1] = _order1;
@@ -414,79 +520,79 @@ struct IPPReorderFunctor
     }
     bool operator()(const void *src, int srcStep, void *dst, int dstStep, int cols, int rows) const
     {
-        return func ? func(src, srcStep, dst, dstStep, ippiSize(cols, rows), order) >= 0 : false;
+        return ippiColorConvertReorder ? CV_INSTRUMENT_FUN_IPP(ippiColorConvertReorder, src, srcStep, dst, dstStep, ippiSize(cols, rows), order) >= 0 : false;
     }
 private:
-    ippiReorderFunc func;
+    ippiReorderFunc ippiColorConvertReorder;
     int order[4];
 };
 
 struct IPPColor2GrayFunctor
 {
     IPPColor2GrayFunctor(ippiColor2GrayFunc _func) :
-        func(_func)
+        ippiColorToGray(_func)
     {
-        coeffs[0] = 0.114f;
-        coeffs[1] = 0.587f;
-        coeffs[2] = 0.299f;
+        coeffs[0] = B2YF;
+        coeffs[1] = G2YF;
+        coeffs[2] = R2YF;
     }
     bool operator()(const void *src, int srcStep, void *dst, int dstStep, int cols, int rows) const
     {
-        return func ? func(src, srcStep, dst, dstStep, ippiSize(cols, rows), coeffs) >= 0 : false;
+        return ippiColorToGray ? CV_INSTRUMENT_FUN_IPP(ippiColorToGray, src, srcStep, dst, dstStep, ippiSize(cols, rows), coeffs) >= 0 : false;
     }
 private:
-    ippiColor2GrayFunc func;
+    ippiColor2GrayFunc ippiColorToGray;
     Ipp32f coeffs[3];
 };
 
 struct IPPGray2BGRFunctor
 {
     IPPGray2BGRFunctor(ippiGeneralFunc _func) :
-        func(_func)
+        ippiGrayToBGR(_func)
     {
     }
 
     bool operator()(const void *src, int srcStep, void *dst, int dstStep, int cols, int rows) const
     {
-        if (func == 0)
+        if (ippiGrayToBGR == 0)
             return false;
 
         const void* srcarray[3] = { src, src, src };
-        return func(srcarray, srcStep, dst, dstStep, ippiSize(cols, rows)) >= 0;
+        return CV_INSTRUMENT_FUN_IPP(ippiGrayToBGR, srcarray, srcStep, dst, dstStep, ippiSize(cols, rows)) >= 0;
     }
 private:
-    ippiGeneralFunc func;
+    ippiGeneralFunc ippiGrayToBGR;
 };
 
 struct IPPGray2BGRAFunctor
 {
     IPPGray2BGRAFunctor(ippiGeneralFunc _func1, ippiReorderFunc _func2, int _depth) :
-        func1(_func1), func2(_func2), depth(_depth)
+        ippiColorConvertGeneral(_func1), ippiColorConvertReorder(_func2), depth(_depth)
     {
     }
 
     bool operator()(const void *src, int srcStep, void *dst, int dstStep, int cols, int rows) const
     {
-        if (func1 == 0 || func2 == 0)
+        if (ippiColorConvertGeneral == 0 || ippiColorConvertReorder == 0)
             return false;
 
         const void* srcarray[3] = { src, src, src };
         Mat temp(rows, cols, CV_MAKETYPE(depth, 3));
-        if(func1(srcarray, srcStep, temp.ptr(), (int)temp.step[0], ippiSize(cols, rows)) < 0)
+        if(CV_INSTRUMENT_FUN_IPP(ippiColorConvertGeneral, srcarray, srcStep, temp.ptr(), (int)temp.step[0], ippiSize(cols, rows)) < 0)
             return false;
         int order[4] = {0, 1, 2, 3};
-        return func2(temp.ptr(), (int)temp.step[0], dst, dstStep, ippiSize(cols, rows), order) >= 0;
+        return CV_INSTRUMENT_FUN_IPP(ippiColorConvertReorder, temp.ptr(), (int)temp.step[0], dst, dstStep, ippiSize(cols, rows), order) >= 0;
     }
 private:
-    ippiGeneralFunc func1;
-    ippiReorderFunc func2;
+    ippiGeneralFunc ippiColorConvertGeneral;
+    ippiReorderFunc ippiColorConvertReorder;
     int depth;
 };
 
 struct IPPReorderGeneralFunctor
 {
     IPPReorderGeneralFunctor(ippiReorderFunc _func1, ippiGeneralFunc _func2, int _order0, int _order1, int _order2, int _depth) :
-        func1(_func1), func2(_func2), depth(_depth)
+        ippiColorConvertReorder(_func1), ippiColorConvertGeneral(_func2), depth(_depth)
     {
         order[0] = _order0;
         order[1] = _order1;
@@ -495,18 +601,18 @@ struct IPPReorderGeneralFunctor
     }
     bool operator()(const void *src, int srcStep, void *dst, int dstStep, int cols, int rows) const
     {
-        if (func1 == 0 || func2 == 0)
+        if (ippiColorConvertReorder == 0 || ippiColorConvertGeneral == 0)
             return false;
 
         Mat temp;
         temp.create(rows, cols, CV_MAKETYPE(depth, 3));
-        if(func1(src, srcStep, temp.ptr(), (int)temp.step[0], ippiSize(cols, rows), order) < 0)
+        if(CV_INSTRUMENT_FUN_IPP(ippiColorConvertReorder, src, srcStep, temp.ptr(), (int)temp.step[0], ippiSize(cols, rows), order) < 0)
             return false;
-        return func2(temp.ptr(), (int)temp.step[0], dst, dstStep, ippiSize(cols, rows)) >= 0;
+        return CV_INSTRUMENT_FUN_IPP(ippiColorConvertGeneral, temp.ptr(), (int)temp.step[0], dst, dstStep, ippiSize(cols, rows)) >= 0;
     }
 private:
-    ippiReorderFunc func1;
-    ippiGeneralFunc func2;
+    ippiReorderFunc ippiColorConvertReorder;
+    ippiGeneralFunc ippiColorConvertGeneral;
     int order[4];
     int depth;
 };
@@ -514,7 +620,7 @@ private:
 struct IPPGeneralReorderFunctor
 {
     IPPGeneralReorderFunctor(ippiGeneralFunc _func1, ippiReorderFunc _func2, int _order0, int _order1, int _order2, int _depth) :
-        func1(_func1), func2(_func2), depth(_depth)
+        ippiColorConvertGeneral(_func1), ippiColorConvertReorder(_func2), depth(_depth)
     {
         order[0] = _order0;
         order[1] = _order1;
@@ -523,18 +629,18 @@ struct IPPGeneralReorderFunctor
     }
     bool operator()(const void *src, int srcStep, void *dst, int dstStep, int cols, int rows) const
     {
-        if (func1 == 0 || func2 == 0)
+        if (ippiColorConvertGeneral == 0 || ippiColorConvertReorder == 0)
             return false;
 
         Mat temp;
         temp.create(rows, cols, CV_MAKETYPE(depth, 3));
-        if(func1(src, srcStep, temp.ptr(), (int)temp.step[0], ippiSize(cols, rows)) < 0)
+        if(CV_INSTRUMENT_FUN_IPP(ippiColorConvertGeneral, src, srcStep, temp.ptr(), (int)temp.step[0], ippiSize(cols, rows)) < 0)
             return false;
-        return func2(temp.ptr(), (int)temp.step[0], dst, dstStep, ippiSize(cols, rows), order) >= 0;
+        return CV_INSTRUMENT_FUN_IPP(ippiColorConvertReorder, temp.ptr(), (int)temp.step[0], dst, dstStep, ippiSize(cols, rows), order) >= 0;
     }
 private:
-    ippiGeneralFunc func1;
-    ippiReorderFunc func2;
+    ippiGeneralFunc ippiColorConvertGeneral;
+    ippiReorderFunc ippiColorConvertReorder;
     int order[4];
     int depth;
 };
@@ -1070,9 +1176,9 @@ enum
 {
     yuv_shift = 14,
     xyz_shift = 12,
-    R2Y = 4899,
-    G2Y = 9617,
-    B2Y = 1868,
+    R2Y = 4899, // == R2YF*16384
+    G2Y = 9617, // == G2YF*16384
+    B2Y = 1868, // == B2YF*16384
     BLOCK_SIZE = 256
 };
 
@@ -1092,12 +1198,13 @@ struct RGB5x52Gray
         v_fc = vdupq_n_u16(0xfc);
         #elif CV_SSE2
         haveSIMD = checkHardwareSupport(CV_CPU_SSE2);
-        v_b2y = _mm_set1_epi16(B2Y);
-        v_g2y = _mm_set1_epi16(G2Y);
-        v_r2y = _mm_set1_epi16(R2Y);
-        v_delta = _mm_set1_epi32(1 << (yuv_shift - 1));
-        v_f8 = _mm_set1_epi16(0xf8);
-        v_fc = _mm_set1_epi16(0xfc);
+        const __m128i v_b2y = _mm_set1_epi16(B2Y);
+        const __m128i v_g2y = _mm_set1_epi16(G2Y);
+        v_bg2y = _mm_unpacklo_epi16(v_b2y, v_g2y);
+        const __m128i v_r2y = _mm_set1_epi16(R2Y);
+        const __m128i v_one = _mm_set1_epi16(1);
+        v_rd2y = _mm_unpacklo_epi16(v_r2y, v_one);
+        v_delta = _mm_slli_epi16(v_one, yuv_shift - 1);
         #endif
     }
 
@@ -1126,37 +1233,30 @@ struct RGB5x52Gray
             #elif CV_SSE2
             if (haveSIMD)
             {
-                __m128i v_zero = _mm_setzero_si128();
-
                 for ( ; i <= n - 8; i += 8)
                 {
                     __m128i v_src = _mm_loadu_si128((__m128i const *)((ushort *)src + i));
-                    __m128i v_t0 = _mm_and_si128(_mm_slli_epi16(v_src, 3), v_f8),
-                            v_t1 = _mm_and_si128(_mm_srli_epi16(v_src, 3), v_fc),
-                            v_t2 = _mm_and_si128(_mm_srli_epi16(v_src, 8), v_f8);
-
-                    __m128i v_mullo_b = _mm_mullo_epi16(v_t0, v_b2y);
-                    __m128i v_mullo_g = _mm_mullo_epi16(v_t1, v_g2y);
-                    __m128i v_mullo_r = _mm_mullo_epi16(v_t2, v_r2y);
-                    __m128i v_mulhi_b = _mm_mulhi_epi16(v_t0, v_b2y);
-                    __m128i v_mulhi_g = _mm_mulhi_epi16(v_t1, v_g2y);
-                    __m128i v_mulhi_r = _mm_mulhi_epi16(v_t2, v_r2y);
-
-                    __m128i v_dst0 = _mm_add_epi32(_mm_unpacklo_epi16(v_mullo_b, v_mulhi_b),
-                                                   _mm_unpacklo_epi16(v_mullo_g, v_mulhi_g));
-                    v_dst0 = _mm_add_epi32(_mm_add_epi32(v_dst0, v_delta),
-                                           _mm_unpacklo_epi16(v_mullo_r, v_mulhi_r));
-
-                    __m128i v_dst1 = _mm_add_epi32(_mm_unpackhi_epi16(v_mullo_b, v_mulhi_b),
-                                                   _mm_unpackhi_epi16(v_mullo_g, v_mulhi_g));
-                    v_dst1 = _mm_add_epi32(_mm_add_epi32(v_dst1, v_delta),
-                                           _mm_unpackhi_epi16(v_mullo_r, v_mulhi_r));
-
-                    v_dst0 = _mm_srli_epi32(v_dst0, yuv_shift);
-                    v_dst1 = _mm_srli_epi32(v_dst1, yuv_shift);
-
-                    __m128i v_dst = _mm_packs_epi32(v_dst0, v_dst1);
-                    _mm_storel_epi64((__m128i *)(dst + i), _mm_packus_epi16(v_dst, v_zero));
+                    __m128i v_b = _mm_srli_epi16(_mm_slli_epi16(v_src, 11), 8),
+                            v_g = _mm_srli_epi16(_mm_slli_epi16(_mm_srli_epi16(v_src, 5), 10),8),
+                            v_r = _mm_slli_epi16(_mm_srli_epi16(v_src, 11), 3);
+
+                    __m128i v_bg_lo = _mm_unpacklo_epi16(v_b, v_g);
+                    __m128i v_rd_lo = _mm_unpacklo_epi16(v_r, v_delta);
+                    __m128i v_bg_hi = _mm_unpackhi_epi16(v_b, v_g);
+                    __m128i v_rd_hi = _mm_unpackhi_epi16(v_r, v_delta);
+                    v_bg_lo = _mm_madd_epi16(v_bg_lo, v_bg2y);
+                    v_rd_lo = _mm_madd_epi16(v_rd_lo, v_rd2y);
+                    v_bg_hi = _mm_madd_epi16(v_bg_hi, v_bg2y);
+                    v_rd_hi = _mm_madd_epi16(v_rd_hi, v_rd2y);
+
+                    __m128i v_bgr_lo = _mm_add_epi32(v_bg_lo, v_rd_lo);
+                    __m128i v_bgr_hi = _mm_add_epi32(v_bg_hi, v_rd_hi);
+                    v_bgr_lo = _mm_srli_epi32(v_bgr_lo, yuv_shift);
+                    v_bgr_hi = _mm_srli_epi32(v_bgr_hi, yuv_shift);
+
+                    __m128i v_dst = _mm_packs_epi32(v_bgr_lo, v_bgr_hi);
+                    v_dst = _mm_packus_epi16(v_dst, v_dst);
+                    _mm_storel_epi64((__m128i *)(dst + i), v_dst);
                 }
             }
             #endif
@@ -1190,37 +1290,30 @@ struct RGB5x52Gray
             #elif CV_SSE2
             if (haveSIMD)
             {
-                __m128i v_zero = _mm_setzero_si128();
-
                 for ( ; i <= n - 8; i += 8)
                 {
                     __m128i v_src = _mm_loadu_si128((__m128i const *)((ushort *)src + i));
-                    __m128i v_t0 = _mm_and_si128(_mm_slli_epi16(v_src, 3), v_f8),
-                            v_t1 = _mm_and_si128(_mm_srli_epi16(v_src, 2), v_f8),
-                            v_t2 = _mm_and_si128(_mm_srli_epi16(v_src, 7), v_f8);
-
-                    __m128i v_mullo_b = _mm_mullo_epi16(v_t0, v_b2y);
-                    __m128i v_mullo_g = _mm_mullo_epi16(v_t1, v_g2y);
-                    __m128i v_mullo_r = _mm_mullo_epi16(v_t2, v_r2y);
-                    __m128i v_mulhi_b = _mm_mulhi_epi16(v_t0, v_b2y);
-                    __m128i v_mulhi_g = _mm_mulhi_epi16(v_t1, v_g2y);
-                    __m128i v_mulhi_r = _mm_mulhi_epi16(v_t2, v_r2y);
-
-                    __m128i v_dst0 = _mm_add_epi32(_mm_unpacklo_epi16(v_mullo_b, v_mulhi_b),
-                                                   _mm_unpacklo_epi16(v_mullo_g, v_mulhi_g));
-                    v_dst0 = _mm_add_epi32(_mm_add_epi32(v_dst0, v_delta),
-                                           _mm_unpacklo_epi16(v_mullo_r, v_mulhi_r));
-
-                    __m128i v_dst1 = _mm_add_epi32(_mm_unpackhi_epi16(v_mullo_b, v_mulhi_b),
-                                                   _mm_unpackhi_epi16(v_mullo_g, v_mulhi_g));
-                    v_dst1 = _mm_add_epi32(_mm_add_epi32(v_dst1, v_delta),
-                                           _mm_unpackhi_epi16(v_mullo_r, v_mulhi_r));
-
-                    v_dst0 = _mm_srli_epi32(v_dst0, yuv_shift);
-                    v_dst1 = _mm_srli_epi32(v_dst1, yuv_shift);
-
-                    __m128i v_dst = _mm_packs_epi32(v_dst0, v_dst1);
-                    _mm_storel_epi64((__m128i *)(dst + i), _mm_packus_epi16(v_dst, v_zero));
+                    __m128i v_b = _mm_srli_epi16(_mm_slli_epi16(v_src, 11), 8),
+                            v_g = _mm_srli_epi16(_mm_slli_epi16(_mm_srli_epi16(v_src, 5), 11),8),
+                            v_r = _mm_srli_epi16(_mm_slli_epi16(_mm_srli_epi16(v_src, 10), 11),8);
+
+                    __m128i v_bg_lo = _mm_unpacklo_epi16(v_b, v_g);
+                    __m128i v_rd_lo = _mm_unpacklo_epi16(v_r, v_delta);
+                    __m128i v_bg_hi = _mm_unpackhi_epi16(v_b, v_g);
+                    __m128i v_rd_hi = _mm_unpackhi_epi16(v_r, v_delta);
+                    v_bg_lo = _mm_madd_epi16(v_bg_lo, v_bg2y);
+                    v_rd_lo = _mm_madd_epi16(v_rd_lo, v_rd2y);
+                    v_bg_hi = _mm_madd_epi16(v_bg_hi, v_bg2y);
+                    v_rd_hi = _mm_madd_epi16(v_rd_hi, v_rd2y);
+
+                    __m128i v_bgr_lo = _mm_add_epi32(v_bg_lo, v_rd_lo);
+                    __m128i v_bgr_hi = _mm_add_epi32(v_bg_hi, v_rd_hi);
+                    v_bgr_lo = _mm_srli_epi32(v_bgr_lo, yuv_shift);
+                    v_bgr_hi = _mm_srli_epi32(v_bgr_hi, yuv_shift);
+
+                    __m128i v_dst = _mm_packs_epi32(v_bgr_lo, v_bgr_hi);
+                    v_dst = _mm_packus_epi16(v_dst, v_dst);
+                    _mm_storel_epi64((__m128i *)(dst + i), v_dst);
                 }
             }
             #endif
@@ -1241,9 +1334,8 @@ struct RGB5x52Gray
     uint16x8_t v_f8, v_fc;
     #elif CV_SSE2
     bool haveSIMD;
-    __m128i v_b2y, v_g2y, v_r2y;
+    __m128i v_bg2y, v_rd2y;
     __m128i v_delta;
-    __m128i v_f8, v_fc;
     #endif
 };
 
@@ -1254,7 +1346,7 @@ template<typename _Tp> struct RGB2Gray
 
     RGB2Gray(int _srccn, int blueIdx, const float* _coeffs) : srccn(_srccn)
     {
-        static const float coeffs0[] = { 0.299f, 0.587f, 0.114f };
+        static const float coeffs0[] = { R2YF, G2YF, B2YF };
         memcpy( coeffs, _coeffs ? _coeffs : coeffs0, 3*sizeof(coeffs[0]) );
         if(blueIdx == 0)
             std::swap(coeffs[0], coeffs[2]);
@@ -1401,7 +1493,7 @@ struct RGB2Gray<float>
 
     RGB2Gray(int _srccn, int blueIdx, const float* _coeffs) : srccn(_srccn)
     {
-        static const float coeffs0[] = { 0.299f, 0.587f, 0.114f };
+        static const float coeffs0[] = { R2YF, G2YF, B2YF };
         memcpy( coeffs, _coeffs ? _coeffs : coeffs0, 3*sizeof(coeffs[0]) );
         if(blueIdx == 0)
             std::swap(coeffs[0], coeffs[2]);
@@ -1477,36 +1569,47 @@ struct RGB2Gray<ushort>
         if( blueIdx == 0 )
             std::swap(coeffs[0], coeffs[2]);
 
-        v_cb = _mm_set1_epi16((short)coeffs[0]);
-        v_cg = _mm_set1_epi16((short)coeffs[1]);
-        v_cr = _mm_set1_epi16((short)coeffs[2]);
         v_delta = _mm_set1_epi32(1 << (yuv_shift - 1));
+        v_zero = _mm_setzero_si128();
 
         haveSIMD = checkHardwareSupport(CV_CPU_SSE4_1);
     }
 
     // 16s x 8
-    void process(__m128i v_b, __m128i v_g, __m128i v_r,
+    void process(__m128i* v_rgb, __m128i* v_coeffs,
                  __m128i & v_gray) const
     {
-        __m128i v_mullo_r = _mm_mullo_epi16(v_r, v_cr);
-        __m128i v_mullo_g = _mm_mullo_epi16(v_g, v_cg);
-        __m128i v_mullo_b = _mm_mullo_epi16(v_b, v_cb);
-        __m128i v_mulhi_r = _mm_mulhi_epu16(v_r, v_cr);
-        __m128i v_mulhi_g = _mm_mulhi_epu16(v_g, v_cg);
-        __m128i v_mulhi_b = _mm_mulhi_epu16(v_b, v_cb);
+        __m128i v_rgb_hi[4];
+        v_rgb_hi[0] = _mm_cmplt_epi16(v_rgb[0], v_zero);
+        v_rgb_hi[1] = _mm_cmplt_epi16(v_rgb[1], v_zero);
+        v_rgb_hi[2] = _mm_cmplt_epi16(v_rgb[2], v_zero);
+        v_rgb_hi[3] = _mm_cmplt_epi16(v_rgb[3], v_zero);
+
+        v_rgb_hi[0] = _mm_and_si128(v_rgb_hi[0], v_coeffs[1]);
+        v_rgb_hi[1] = _mm_and_si128(v_rgb_hi[1], v_coeffs[1]);
+        v_rgb_hi[2] = _mm_and_si128(v_rgb_hi[2], v_coeffs[1]);
+        v_rgb_hi[3] = _mm_and_si128(v_rgb_hi[3], v_coeffs[1]);
+
+        v_rgb_hi[0] = _mm_hadd_epi16(v_rgb_hi[0], v_rgb_hi[1]);
+        v_rgb_hi[2] = _mm_hadd_epi16(v_rgb_hi[2], v_rgb_hi[3]);
+        v_rgb_hi[0] = _mm_hadd_epi16(v_rgb_hi[0], v_rgb_hi[2]);
+
+        v_rgb[0] = _mm_madd_epi16(v_rgb[0], v_coeffs[0]);
+        v_rgb[1] = _mm_madd_epi16(v_rgb[1], v_coeffs[0]);
+        v_rgb[2] = _mm_madd_epi16(v_rgb[2], v_coeffs[0]);
+        v_rgb[3] = _mm_madd_epi16(v_rgb[3], v_coeffs[0]);
+
+        v_rgb[0] = _mm_hadd_epi32(v_rgb[0], v_rgb[1]);
+        v_rgb[2] = _mm_hadd_epi32(v_rgb[2], v_rgb[3]);
 
-        __m128i v_gray0 = _mm_add_epi32(_mm_unpacklo_epi16(v_mullo_r, v_mulhi_r),
-                                        _mm_unpacklo_epi16(v_mullo_g, v_mulhi_g));
-        v_gray0 = _mm_add_epi32(_mm_unpacklo_epi16(v_mullo_b, v_mulhi_b), v_gray0);
-        v_gray0 = _mm_srli_epi32(_mm_add_epi32(v_gray0, v_delta), yuv_shift);
+        v_rgb[0] = _mm_add_epi32(v_rgb[0], v_delta);
+        v_rgb[2] = _mm_add_epi32(v_rgb[2], v_delta);
 
-        __m128i v_gray1 = _mm_add_epi32(_mm_unpackhi_epi16(v_mullo_r, v_mulhi_r),
-                                        _mm_unpackhi_epi16(v_mullo_g, v_mulhi_g));
-        v_gray1 = _mm_add_epi32(_mm_unpackhi_epi16(v_mullo_b, v_mulhi_b), v_gray1);
-        v_gray1 = _mm_srli_epi32(_mm_add_epi32(v_gray1, v_delta), yuv_shift);
+        v_rgb[0] = _mm_srai_epi32(v_rgb[0], yuv_shift);
+        v_rgb[2] = _mm_srai_epi32(v_rgb[2], yuv_shift);
 
-        v_gray = _mm_packus_epi32(v_gray0, v_gray1);
+        v_gray = _mm_packs_epi32(v_rgb[0], v_rgb[2]);
+        v_gray = _mm_add_epi16(v_gray, v_rgb_hi[0]);
     }
 
     void operator()(const ushort* src, ushort* dst, int n) const
@@ -1515,54 +1618,49 @@ struct RGB2Gray<ushort>
 
         if (scn == 3 && haveSIMD)
         {
-            for ( ; i <= n - 16; i += 16, src += scn * 16)
-            {
-                __m128i v_r0 = _mm_loadu_si128((__m128i const *)(src));
-                __m128i v_r1 = _mm_loadu_si128((__m128i const *)(src + 8));
-                __m128i v_g0 = _mm_loadu_si128((__m128i const *)(src + 16));
-                __m128i v_g1 = _mm_loadu_si128((__m128i const *)(src + 24));
-                __m128i v_b0 = _mm_loadu_si128((__m128i const *)(src + 32));
-                __m128i v_b1 = _mm_loadu_si128((__m128i const *)(src + 40));
+            __m128i v_coeffs[2];
+            v_coeffs[0] = _mm_set_epi16(0, (short)coeffs[2], (short)coeffs[1], (short)coeffs[0], (short)coeffs[2], (short)coeffs[1], (short)coeffs[0], 0);
+            v_coeffs[1] = _mm_slli_epi16(v_coeffs[0], 2);
 
-                _mm_deinterleave_epi16(v_r0, v_r1, v_g0, v_g1, v_b0, v_b1);
+            for ( ; i <= n - 8; i += 8, src += scn * 8)
+            {
+                __m128i v_src[3];
+                v_src[0] = _mm_loadu_si128((__m128i const *)(src));
+                v_src[1] = _mm_loadu_si128((__m128i const *)(src + 8));
+                v_src[2] = _mm_loadu_si128((__m128i const *)(src + 16));
 
-                __m128i v_gray0;
-                process(v_r0, v_g0, v_b0,
-                        v_gray0);
+                __m128i v_rgb[4];
+                v_rgb[0] = _mm_slli_si128(v_src[0], 2);
+                v_rgb[1] = _mm_alignr_epi8(v_src[1], v_src[0], 10);
+                v_rgb[2] = _mm_alignr_epi8(v_src[2], v_src[1], 6);
+                v_rgb[3] = _mm_srli_si128(v_src[2], 2);
 
-                __m128i v_gray1;
-                process(v_r1, v_g1, v_b1,
-                        v_gray1);
+                __m128i v_gray;
+                process(v_rgb, v_coeffs,
+                        v_gray);
 
-                _mm_storeu_si128((__m128i *)(dst + i), v_gray0);
-                _mm_storeu_si128((__m128i *)(dst + i + 8), v_gray1);
+                _mm_storeu_si128((__m128i *)(dst + i), v_gray);
             }
         }
         else if (scn == 4 && haveSIMD)
         {
-            for ( ; i <= n - 16; i += 16, src += scn * 16)
-            {
-                __m128i v_r0 = _mm_loadu_si128((__m128i const *)(src));
-                __m128i v_r1 = _mm_loadu_si128((__m128i const *)(src + 8));
-                __m128i v_g0 = _mm_loadu_si128((__m128i const *)(src + 16));
-                __m128i v_g1 = _mm_loadu_si128((__m128i const *)(src + 24));
-                __m128i v_b0 = _mm_loadu_si128((__m128i const *)(src + 32));
-                __m128i v_b1 = _mm_loadu_si128((__m128i const *)(src + 40));
-                __m128i v_a0 = _mm_loadu_si128((__m128i const *)(src + 48));
-                __m128i v_a1 = _mm_loadu_si128((__m128i const *)(src + 56));
+            __m128i v_coeffs[2];
+            v_coeffs[0] = _mm_set_epi16(0, (short)coeffs[2], (short)coeffs[1], (short)coeffs[0], 0, (short)coeffs[2], (short)coeffs[1], (short)coeffs[0]);
+            v_coeffs[1] = _mm_slli_epi16(v_coeffs[0], 2);
 
-                _mm_deinterleave_epi16(v_r0, v_r1, v_g0, v_g1, v_b0, v_b1, v_a0, v_a1);
-
-                __m128i v_gray0;
-                process(v_r0, v_g0, v_b0,
-                        v_gray0);
+            for ( ; i <= n - 8; i += 8, src += scn * 8)
+            {
+                __m128i v_rgb[4];
+                v_rgb[0] = _mm_loadu_si128((__m128i const *)(src));
+                v_rgb[1] = _mm_loadu_si128((__m128i const *)(src + 8));
+                v_rgb[2] = _mm_loadu_si128((__m128i const *)(src + 16));
+                v_rgb[3] = _mm_loadu_si128((__m128i const *)(src + 24));
 
-                __m128i v_gray1;
-                process(v_r1, v_g1, v_b1,
-                        v_gray1);
+                __m128i v_gray;
+                process(v_rgb, v_coeffs,
+                        v_gray);
 
-                _mm_storeu_si128((__m128i *)(dst + i), v_gray0);
-                _mm_storeu_si128((__m128i *)(dst + i + 8), v_gray1);
+                _mm_storeu_si128((__m128i *)(dst + i), v_gray);
             }
         }
 
@@ -1571,8 +1669,8 @@ struct RGB2Gray<ushort>
     }
 
     int srccn, coeffs[3];
-    __m128i v_cb, v_cg, v_cr;
     __m128i v_delta;
+    __m128i v_zero;
     bool haveSIMD;
 };
 
@@ -1585,7 +1683,7 @@ struct RGB2Gray<float>
 
     RGB2Gray(int _srccn, int blueIdx, const float* _coeffs) : srccn(_srccn)
     {
-        static const float coeffs0[] = { 0.299f, 0.587f, 0.114f };
+        static const float coeffs0[] = { R2YF, G2YF, B2YF };
         memcpy( coeffs, _coeffs ? _coeffs : coeffs0, 3*sizeof(coeffs[0]) );
         if(blueIdx == 0)
             std::swap(coeffs[0], coeffs[2]);
@@ -1707,16 +1805,18 @@ template<typename _Tp> struct RGB2YCrCb_f
 {
     typedef _Tp channel_type;
 
-    RGB2YCrCb_f(int _srccn, int _blueIdx, const float* _coeffs) : srccn(_srccn), blueIdx(_blueIdx)
+    RGB2YCrCb_f(int _srccn, int _blueIdx, bool _isCrCb) : srccn(_srccn), blueIdx(_blueIdx), isCrCb(_isCrCb)
     {
-        static const float coeffs0[] = {0.299f, 0.587f, 0.114f, 0.713f, 0.564f};
-        memcpy(coeffs, _coeffs ? _coeffs : coeffs0, 5*sizeof(coeffs[0]));
+        static const float coeffs_crb[] = { R2YF, G2YF, B2YF, YCRF, YCBF };
+        static const float coeffs_yuv[] = { R2YF, G2YF, B2YF, R2VF, B2UF };
+        memcpy(coeffs, isCrCb ? coeffs_crb : coeffs_yuv, 5*sizeof(coeffs[0]));
         if(blueIdx==0) std::swap(coeffs[0], coeffs[2]);
     }
 
     void operator()(const _Tp* src, _Tp* dst, int n) const
     {
         int scn = srccn, bidx = blueIdx;
+        int yuvOrder = !isCrCb; //1 if YUV, 0 if YCrCb
         const _Tp delta = ColorChannel<_Tp>::half();
         float C0 = coeffs[0], C1 = coeffs[1], C2 = coeffs[2], C3 = coeffs[3], C4 = coeffs[4];
         n *= 3;
@@ -1725,10 +1825,11 @@ template<typename _Tp> struct RGB2YCrCb_f
             _Tp Y = saturate_cast<_Tp>(src[0]*C0 + src[1]*C1 + src[2]*C2);
             _Tp Cr = saturate_cast<_Tp>((src[bidx^2] - Y)*C3 + delta);
             _Tp Cb = saturate_cast<_Tp>((src[bidx] - Y)*C4 + delta);
-            dst[i] = Y; dst[i+1] = Cr; dst[i+2] = Cb;
+            dst[i] = Y; dst[i+1+yuvOrder] = Cr; dst[i+2-yuvOrder] = Cb;
         }
     }
     int srccn, blueIdx;
+    bool isCrCb;
     float coeffs[5];
 };
 
@@ -1739,11 +1840,12 @@ struct RGB2YCrCb_f<float>
 {
     typedef float channel_type;
 
-    RGB2YCrCb_f(int _srccn, int _blueIdx, const float* _coeffs) :
-        srccn(_srccn), blueIdx(_blueIdx)
+    RGB2YCrCb_f(int _srccn, int _blueIdx, bool _isCrCb) :
+        srccn(_srccn), blueIdx(_blueIdx), isCrCb(_isCrCb)
     {
-        static const float coeffs0[] = {0.299f, 0.587f, 0.114f, 0.713f, 0.564f};
-        memcpy(coeffs, _coeffs ? _coeffs : coeffs0, 5*sizeof(coeffs[0]));
+        static const float coeffs_crb[] = { R2YF, G2YF, B2YF, YCRF, YCBF };
+        static const float coeffs_yuv[] = { R2YF, G2YF, B2YF, R2VF, B2UF };
+        memcpy(coeffs, isCrCb ? coeffs_crb : coeffs_yuv, 5*sizeof(coeffs[0]));
         if(blueIdx==0)
             std::swap(coeffs[0], coeffs[2]);
 
@@ -1758,6 +1860,7 @@ struct RGB2YCrCb_f<float>
     void operator()(const float * src, float * dst, int n) const
     {
         int scn = srccn, bidx = blueIdx, i = 0;
+        int yuvOrder = !isCrCb; //1 if YUV, 0 if YCrCb
         const float delta = ColorChannel<float>::half();
         float C0 = coeffs[0], C1 = coeffs[1], C2 = coeffs[2], C3 = coeffs[3], C4 = coeffs[4];
         n *= 3;
@@ -1767,8 +1870,8 @@ struct RGB2YCrCb_f<float>
             {
                 float32x4x3_t v_src = vld3q_f32(src), v_dst;
                 v_dst.val[0] = vmlaq_f32(vmlaq_f32(vmulq_f32(v_src.val[0], v_c0), v_src.val[1], v_c1), v_src.val[2], v_c2);
-                v_dst.val[1] = vmlaq_f32(v_delta, vsubq_f32(v_src.val[bidx^2], v_dst.val[0]), v_c3);
-                v_dst.val[2] = vmlaq_f32(v_delta, vsubq_f32(v_src.val[bidx], v_dst.val[0]), v_c4);
+                v_dst.val[1+yuvOrder] = vmlaq_f32(v_delta, vsubq_f32(v_src.val[bidx^2], v_dst.val[0]), v_c3);
+                v_dst.val[2-yuvOrder] = vmlaq_f32(v_delta, vsubq_f32(v_src.val[bidx], v_dst.val[0]), v_c4);
 
                 vst3q_f32(dst + i, v_dst);
             }
@@ -1778,8 +1881,8 @@ struct RGB2YCrCb_f<float>
                 float32x4x4_t v_src = vld4q_f32(src);
                 float32x4x3_t v_dst;
                 v_dst.val[0] = vmlaq_f32(vmlaq_f32(vmulq_f32(v_src.val[0], v_c0), v_src.val[1], v_c1), v_src.val[2], v_c2);
-                v_dst.val[1] = vmlaq_f32(v_delta, vsubq_f32(v_src.val[bidx^2], v_dst.val[0]), v_c3);
-                v_dst.val[2] = vmlaq_f32(v_delta, vsubq_f32(v_src.val[bidx], v_dst.val[0]), v_c4);
+                v_dst.val[1+yuvOrder] = vmlaq_f32(v_delta, vsubq_f32(v_src.val[bidx^2], v_dst.val[0]), v_c3);
+                v_dst.val[2-yuvOrder] = vmlaq_f32(v_delta, vsubq_f32(v_src.val[bidx], v_dst.val[0]), v_c4);
 
                 vst3q_f32(dst + i, v_dst);
             }
@@ -1789,10 +1892,11 @@ struct RGB2YCrCb_f<float>
             float Y = src[0]*C0 + src[1]*C1 + src[2]*C2;
             float Cr = (src[bidx^2] - Y)*C3 + delta;
             float Cb = (src[bidx] - Y)*C4 + delta;
-            dst[i] = Y; dst[i+1] = Cr; dst[i+2] = Cb;
+            dst[i] = Y; dst[i+1+yuvOrder] = Cr; dst[i+2-yuvOrder] = Cb;
         }
     }
     int srccn, blueIdx;
+    bool isCrCb;
     float coeffs[5];
     float32x4_t v_c0, v_c1, v_c2, v_c3, v_c4, v_delta;
 };
@@ -1804,11 +1908,12 @@ struct RGB2YCrCb_f<float>
 {
     typedef float channel_type;
 
-    RGB2YCrCb_f(int _srccn, int _blueIdx, const float* _coeffs) :
-        srccn(_srccn), blueIdx(_blueIdx)
+    RGB2YCrCb_f(int _srccn, int _blueIdx, bool _isCrCb) :
+        srccn(_srccn), blueIdx(_blueIdx), isCrCb(_isCrCb)
     {
-        static const float coeffs0[] = {0.299f, 0.587f, 0.114f, 0.713f, 0.564f};
-        memcpy(coeffs, _coeffs ? _coeffs : coeffs0, 5*sizeof(coeffs[0]));
+        static const float coeffs_crb[] = { R2YF, G2YF, B2YF, YCRF, YCBF };
+        static const float coeffs_yuv[] = { R2YF, G2YF, B2YF, R2VF, B2UF };
+        memcpy(coeffs, isCrCb ? coeffs_crb : coeffs_yuv, 5*sizeof(coeffs[0]));
         if (blueIdx==0)
             std::swap(coeffs[0], coeffs[2]);
 
@@ -1836,6 +1941,7 @@ struct RGB2YCrCb_f<float>
     void operator()(const float * src, float * dst, int n) const
     {
         int scn = srccn, bidx = blueIdx, i = 0;
+        int yuvOrder = !isCrCb; //1 if YUV, 0 if YCrCb
         const float delta = ColorChannel<float>::half();
         float C0 = coeffs[0], C1 = coeffs[1], C2 = coeffs[2], C3 = coeffs[3], C4 = coeffs[4];
         n *= 3;
@@ -1869,14 +1975,19 @@ struct RGB2YCrCb_f<float>
                 process(v_r1, v_g1, v_b1,
                         v_y1, v_cr1, v_cb1);
 
-                _mm_interleave_ps(v_y0, v_y1, v_cr0, v_cr1, v_cb0, v_cb1);
+                if(isCrCb)
+                    _mm_interleave_ps(v_y0, v_y1, v_cr0, v_cr1, v_cb0, v_cb1);
+                else //YUV
+                {
+                    _mm_interleave_ps(v_y0, v_y1, v_cb0, v_cb1, v_cr0, v_cr1);
+                }
 
                 _mm_storeu_ps(dst + i, v_y0);
                 _mm_storeu_ps(dst + i + 4, v_y1);
-                _mm_storeu_ps(dst + i + 8, v_cr0);
-                _mm_storeu_ps(dst + i + 12, v_cr1);
-                _mm_storeu_ps(dst + i + 16, v_cb0);
-                _mm_storeu_ps(dst + i + 20, v_cb1);
+                _mm_storeu_ps(dst + i + 8  + yuvOrder*8, v_cr0);
+                _mm_storeu_ps(dst + i + 12 + yuvOrder*8, v_cr1);
+                _mm_storeu_ps(dst + i + 16 - yuvOrder*8, v_cb0);
+                _mm_storeu_ps(dst + i + 20 - yuvOrder*8, v_cb1);
             }
         }
 
@@ -1885,10 +1996,11 @@ struct RGB2YCrCb_f<float>
             float Y = src[0]*C0 + src[1]*C1 + src[2]*C2;
             float Cr = (src[bidx^2] - Y)*C3 + delta;
             float Cb = (src[bidx] - Y)*C4 + delta;
-            dst[i] = Y; dst[i+1] = Cr; dst[i+2] = Cb;
+            dst[i] = Y; dst[i+1+yuvOrder] = Cr; dst[i+2-yuvOrder] = Cb;
         }
     }
     int srccn, blueIdx;
+    bool isCrCb;
     float coeffs[5];
     __m128 v_c0, v_c1, v_c2, v_c3, v_c4, v_delta;
     bool haveSIMD;
@@ -1900,16 +2012,18 @@ template<typename _Tp> struct RGB2YCrCb_i
 {
     typedef _Tp channel_type;
 
-    RGB2YCrCb_i(int _srccn, int _blueIdx, const int* _coeffs)
-        : srccn(_srccn), blueIdx(_blueIdx)
+    RGB2YCrCb_i(int _srccn, int _blueIdx, bool _isCrCb)
+        : srccn(_srccn), blueIdx(_blueIdx), isCrCb(_isCrCb)
     {
-        static const int coeffs0[] = {R2Y, G2Y, B2Y, 11682, 9241};
-        memcpy(coeffs, _coeffs ? _coeffs : coeffs0, 5*sizeof(coeffs[0]));
+        static const int coeffs_crb[] = { R2Y, G2Y, B2Y, YCRI, YCBI };
+        static const int coeffs_yuv[] = { R2Y, G2Y, B2Y, R2VI, B2UI };
+        memcpy(coeffs, isCrCb ? coeffs_crb : coeffs_yuv, 5*sizeof(coeffs[0]));
         if(blueIdx==0) std::swap(coeffs[0], coeffs[2]);
     }
     void operator()(const _Tp* src, _Tp* dst, int n) const
     {
         int scn = srccn, bidx = blueIdx;
+        int yuvOrder = !isCrCb; //1 if YUV, 0 if YCrCb
         int C0 = coeffs[0], C1 = coeffs[1], C2 = coeffs[2], C3 = coeffs[3], C4 = coeffs[4];
         int delta = ColorChannel<_Tp>::half()*(1 << yuv_shift);
         n *= 3;
@@ -1919,11 +2033,12 @@ template<typename _Tp> struct RGB2YCrCb_i
             int Cr = CV_DESCALE((src[bidx^2] - Y)*C3 + delta, yuv_shift);
             int Cb = CV_DESCALE((src[bidx] - Y)*C4 + delta, yuv_shift);
             dst[i] = saturate_cast<_Tp>(Y);
-            dst[i+1] = saturate_cast<_Tp>(Cr);
-            dst[i+2] = saturate_cast<_Tp>(Cb);
+            dst[i+1+yuvOrder] = saturate_cast<_Tp>(Cr);
+            dst[i+2-yuvOrder] = saturate_cast<_Tp>(Cb);
         }
     }
     int srccn, blueIdx;
+    bool isCrCb;
     int coeffs[5];
 };
 
@@ -1934,11 +2049,12 @@ struct RGB2YCrCb_i<uchar>
 {
     typedef uchar channel_type;
 
-    RGB2YCrCb_i(int _srccn, int _blueIdx, const int* _coeffs)
-        : srccn(_srccn), blueIdx(_blueIdx)
+    RGB2YCrCb_i(int _srccn, int _blueIdx, bool _isCrCb)
+        : srccn(_srccn), blueIdx(_blueIdx), isCrCb(_isCrCb)
     {
-        static const int coeffs0[] = {R2Y, G2Y, B2Y, 11682, 9241};
-        memcpy(coeffs, _coeffs ? _coeffs : coeffs0, 5*sizeof(coeffs[0]));
+        static const int coeffs_crb[] = { R2Y, G2Y, B2Y, YCRI, YCBI };
+        static const int coeffs_yuv[] = { R2Y, G2Y, B2Y, R2VI, B2UI };
+        memcpy(coeffs, isCrCb ? coeffs_crb : coeffs_yuv, 5*sizeof(coeffs[0]));
         if (blueIdx==0)
             std::swap(coeffs[0], coeffs[2]);
 
@@ -1954,6 +2070,7 @@ struct RGB2YCrCb_i<uchar>
     void operator()(const uchar * src, uchar * dst, int n) const
     {
         int scn = srccn, bidx = blueIdx, i = 0;
+        int yuvOrder = !isCrCb; //1 if YUV, 0 if YCrCb
         int C0 = coeffs[0], C1 = coeffs[1], C2 = coeffs[2], C3 = coeffs[3], C4 = coeffs[4];
         int delta = ColorChannel<uchar>::half()*(1 << yuv_shift);
         n *= 3;
@@ -2002,8 +2119,8 @@ struct RGB2YCrCb_i<uchar>
             v_Cb1 = vshrq_n_s32(vaddq_s32(v_Cb1, v_delta2), yuv_shift);
 
             v_dst.val[0] = vqmovun_s16(vcombine_s16(vqmovn_s32(v_Y0), vqmovn_s32(v_Y1)));
-            v_dst.val[1] = vqmovun_s16(vcombine_s16(vqmovn_s32(v_Cr0), vqmovn_s32(v_Cr1)));
-            v_dst.val[2] = vqmovun_s16(vcombine_s16(vqmovn_s32(v_Cb0), vqmovn_s32(v_Cb1)));
+            v_dst.val[1+yuvOrder] = vqmovun_s16(vcombine_s16(vqmovn_s32(v_Cr0), vqmovn_s32(v_Cr1)));
+            v_dst.val[2-yuvOrder] = vqmovun_s16(vcombine_s16(vqmovn_s32(v_Cb0), vqmovn_s32(v_Cb1)));
 
             vst3_u8(dst + i, v_dst);
         }
@@ -2014,11 +2131,12 @@ struct RGB2YCrCb_i<uchar>
             int Cr = CV_DESCALE((src[bidx^2] - Y)*C3 + delta, yuv_shift);
             int Cb = CV_DESCALE((src[bidx] - Y)*C4 + delta, yuv_shift);
             dst[i] = saturate_cast<uchar>(Y);
-            dst[i+1] = saturate_cast<uchar>(Cr);
-            dst[i+2] = saturate_cast<uchar>(Cb);
+            dst[i+1+yuvOrder] = saturate_cast<uchar>(Cr);
+            dst[i+2-yuvOrder] = saturate_cast<uchar>(Cb);
         }
     }
     int srccn, blueIdx, coeffs[5];
+    bool isCrCb;
     int16x4_t v_c0, v_c1, v_c2;
     int32x4_t v_c3, v_c4, v_delta, v_delta2;
 };
@@ -2028,11 +2146,12 @@ struct RGB2YCrCb_i<ushort>
 {
     typedef ushort channel_type;
 
-    RGB2YCrCb_i(int _srccn, int _blueIdx, const int* _coeffs)
-        : srccn(_srccn), blueIdx(_blueIdx)
+    RGB2YCrCb_i(int _srccn, int _blueIdx, bool _isCrCb)
+        : srccn(_srccn), blueIdx(_blueIdx), isCrCb(_isCrCb)
     {
-        static const int coeffs0[] = {R2Y, G2Y, B2Y, 11682, 9241};
-        memcpy(coeffs, _coeffs ? _coeffs : coeffs0, 5*sizeof(coeffs[0]));
+        static const int coeffs_crb[] = { R2Y, G2Y, B2Y, YCRI, YCBI };
+        static const int coeffs_yuv[] = { R2Y, G2Y, B2Y, R2VI, B2UI };
+        memcpy(coeffs, isCrCb ? coeffs_crb : coeffs_yuv, 5*sizeof(coeffs[0]));
         if (blueIdx==0)
             std::swap(coeffs[0], coeffs[2]);
 
@@ -2048,6 +2167,7 @@ struct RGB2YCrCb_i<ushort>
     void operator()(const ushort * src, ushort * dst, int n) const
     {
         int scn = srccn, bidx = blueIdx, i = 0;
+        int yuvOrder = !isCrCb; //1 if YUV, 0 if YCrCb
         int C0 = coeffs[0], C1 = coeffs[1], C2 = coeffs[2], C3 = coeffs[3], C4 = coeffs[4];
         int delta = ColorChannel<ushort>::half()*(1 << yuv_shift);
         n *= 3;
@@ -2090,8 +2210,8 @@ struct RGB2YCrCb_i<ushort>
             v_Cb1 = vshrq_n_s32(vaddq_s32(v_Cb1, v_delta2), yuv_shift);
 
             v_dst.val[0] = vcombine_u16(vqmovun_s32(v_Y0), vqmovun_s32(v_Y1));
-            v_dst.val[1] = vcombine_u16(vqmovun_s32(v_Cr0), vqmovun_s32(v_Cr1));
-            v_dst.val[2] = vcombine_u16(vqmovun_s32(v_Cb0), vqmovun_s32(v_Cb1));
+            v_dst.val[1+yuvOrder] = vcombine_u16(vqmovun_s32(v_Cr0), vqmovun_s32(v_Cr1));
+            v_dst.val[2-yuvOrder] = vcombine_u16(vqmovun_s32(v_Cb0), vqmovun_s32(v_Cb1));
 
             vst3q_u16(dst + i, v_dst);
         }
@@ -2124,8 +2244,8 @@ struct RGB2YCrCb_i<ushort>
             v_Cb = vshrq_n_s32(vaddq_s32(v_Cb, v_delta2), yuv_shift);
 
             v_dst.val[0] = vqmovun_s32(v_Y);
-            v_dst.val[1] = vqmovun_s32(v_Cr);
-            v_dst.val[2] = vqmovun_s32(v_Cb);
+            v_dst.val[1+yuvOrder] = vqmovun_s32(v_Cr);
+            v_dst.val[2-yuvOrder] = vqmovun_s32(v_Cb);
 
             vst3_u16(dst + i, v_dst);
         }
@@ -2136,11 +2256,12 @@ struct RGB2YCrCb_i<ushort>
             int Cr = CV_DESCALE((src[bidx^2] - Y)*C3 + delta, yuv_shift);
             int Cb = CV_DESCALE((src[bidx] - Y)*C4 + delta, yuv_shift);
             dst[i] = saturate_cast<ushort>(Y);
-            dst[i+1] = saturate_cast<ushort>(Cr);
-            dst[i+2] = saturate_cast<ushort>(Cb);
+            dst[i+1+yuvOrder] = saturate_cast<ushort>(Cr);
+            dst[i+2-yuvOrder] = saturate_cast<ushort>(Cb);
         }
     }
     int srccn, blueIdx, coeffs[5];
+    bool isCrCb;
     int32x4_t v_c0, v_c1, v_c2, v_c3, v_c4, v_delta, v_delta2;
 };
 
@@ -2151,130 +2272,145 @@ struct RGB2YCrCb_i<uchar>
 {
     typedef uchar channel_type;
 
-    RGB2YCrCb_i(int _srccn, int _blueIdx, const int* _coeffs)
-        : srccn(_srccn), blueIdx(_blueIdx)
+    RGB2YCrCb_i(int _srccn, int _blueIdx, bool _isCrCb)
+        : srccn(_srccn), blueIdx(_blueIdx), isCrCb(_isCrCb)
     {
-        static const int coeffs0[] = {R2Y, G2Y, B2Y, 11682, 9241};
-        memcpy(coeffs, _coeffs ? _coeffs : coeffs0, 5*sizeof(coeffs[0]));
+        static const int coeffs_crb[] = { R2Y, G2Y, B2Y, YCRI, YCBI };
+        static const int coeffs_yuv[] = { R2Y, G2Y, B2Y, R2VI, B2UI };
+        memcpy(coeffs, isCrCb ? coeffs_crb : coeffs_yuv, 5*sizeof(coeffs[0]));
         if (blueIdx==0)
             std::swap(coeffs[0], coeffs[2]);
 
-        v_c0 = _mm_set1_epi32(coeffs[0]);
-        v_c1 = _mm_set1_epi32(coeffs[1]);
-        v_c2 = _mm_set1_epi32(coeffs[2]);
-        v_c3 = _mm_set1_epi32(coeffs[3]);
-        v_c4 = _mm_set1_epi32(coeffs[4]);
-        v_delta2 = _mm_set1_epi32(1 << (yuv_shift - 1));
-        v_delta = _mm_set1_epi32(ColorChannel<uchar>::half()*(1 << yuv_shift));
-        v_delta = _mm_add_epi32(v_delta, v_delta2);
-        v_zero = _mm_setzero_si128();
-
+        short delta = 1 << (yuv_shift - 1);
+        v_delta_16 = _mm_set1_epi16(delta);
+        v_delta_32 = _mm_set1_epi32(delta);
+        short delta2 = 1 + ColorChannel<uchar>::half() * 2;
+        v_coeff = _mm_set_epi16(delta2, (short)coeffs[4], delta2, (short)coeffs[3], delta2, (short)coeffs[4], delta2, (short)coeffs[3]);
+        if(isCrCb)
+            v_shuffle2 = _mm_set_epi8(0x0, 0x0, 0x0, 0x0, 0xf, 0xe, 0xc, 0xb, 0xa, 0x8, 0x7, 0x6, 0x4, 0x3, 0x2, 0x0);
+        else //if YUV
+            v_shuffle2 = _mm_set_epi8(0x0, 0x0, 0x0, 0x0, 0xe, 0xf, 0xc, 0xa, 0xb, 0x8, 0x6, 0x7, 0x4, 0x2, 0x3, 0x0);
         haveSIMD = checkHardwareSupport(CV_CPU_SSE4_1);
     }
 
     // 16u x 8
-    void process(__m128i v_r, __m128i v_g, __m128i v_b,
-                 __m128i & v_y, __m128i & v_cr, __m128i & v_cb) const
-    {
-        __m128i v_r_p = _mm_unpacklo_epi16(v_r, v_zero);
-        __m128i v_g_p = _mm_unpacklo_epi16(v_g, v_zero);
-        __m128i v_b_p = _mm_unpacklo_epi16(v_b, v_zero);
-
-        __m128i v_y0 = _mm_add_epi32(_mm_mullo_epi32(v_r_p, v_c0),
-                       _mm_add_epi32(_mm_mullo_epi32(v_g_p, v_c1),
-                                     _mm_mullo_epi32(v_b_p, v_c2)));
-        v_y0 = _mm_srli_epi32(_mm_add_epi32(v_delta2, v_y0), yuv_shift);
-
-        __m128i v_cr0 = _mm_mullo_epi32(_mm_sub_epi32(blueIdx == 2 ? v_r_p : v_b_p, v_y0), v_c3);
-        __m128i v_cb0 = _mm_mullo_epi32(_mm_sub_epi32(blueIdx == 0 ? v_r_p : v_b_p, v_y0), v_c4);
-        v_cr0 = _mm_srai_epi32(_mm_add_epi32(v_delta, v_cr0), yuv_shift);
-        v_cb0 = _mm_srai_epi32(_mm_add_epi32(v_delta, v_cb0), yuv_shift);
-
-        v_r_p = _mm_unpackhi_epi16(v_r, v_zero);
-        v_g_p = _mm_unpackhi_epi16(v_g, v_zero);
-        v_b_p = _mm_unpackhi_epi16(v_b, v_zero);
-
-        __m128i v_y1 = _mm_add_epi32(_mm_mullo_epi32(v_r_p, v_c0),
-                       _mm_add_epi32(_mm_mullo_epi32(v_g_p, v_c1),
-                                     _mm_mullo_epi32(v_b_p, v_c2)));
-        v_y1 = _mm_srli_epi32(_mm_add_epi32(v_delta2, v_y1), yuv_shift);
-
-        __m128i v_cr1 = _mm_mullo_epi32(_mm_sub_epi32(blueIdx == 2 ? v_r_p : v_b_p, v_y1), v_c3);
-        __m128i v_cb1 = _mm_mullo_epi32(_mm_sub_epi32(blueIdx == 0 ? v_r_p : v_b_p, v_y1), v_c4);
-        v_cr1 = _mm_srai_epi32(_mm_add_epi32(v_delta, v_cr1), yuv_shift);
-        v_cb1 = _mm_srai_epi32(_mm_add_epi32(v_delta, v_cb1), yuv_shift);
-
-        v_y = _mm_packs_epi32(v_y0, v_y1);
-        v_cr = _mm_packs_epi32(v_cr0, v_cr1);
-        v_cb = _mm_packs_epi32(v_cb0, v_cb1);
+    void process(__m128i* v_rgb, __m128i & v_crgb,
+                 __m128i* v_rb, uchar * dst) const
+    {
+        v_rgb[0] = _mm_madd_epi16(v_rgb[0], v_crgb);
+        v_rgb[1] = _mm_madd_epi16(v_rgb[1], v_crgb);
+        v_rgb[2] = _mm_madd_epi16(v_rgb[2], v_crgb);
+        v_rgb[3] = _mm_madd_epi16(v_rgb[3], v_crgb);
+        v_rgb[0] = _mm_hadd_epi32(v_rgb[0], v_rgb[1]);
+        v_rgb[2] = _mm_hadd_epi32(v_rgb[2], v_rgb[3]);
+        v_rgb[0] = _mm_add_epi32(v_rgb[0], v_delta_32);
+        v_rgb[2] = _mm_add_epi32(v_rgb[2], v_delta_32);
+        v_rgb[0] = _mm_srai_epi32(v_rgb[0], yuv_shift);
+        v_rgb[2] = _mm_srai_epi32(v_rgb[2], yuv_shift);
+        __m128i v_y = _mm_packs_epi32(v_rgb[0], v_rgb[2]);
+
+        v_rb[0] = _mm_cvtepu8_epi16(v_rb[0]);
+        v_rb[1] = _mm_cvtepu8_epi16(v_rb[1]);
+        v_rb[0] = _mm_sub_epi16(v_rb[0], _mm_unpacklo_epi16(v_y, v_y));
+        v_rb[1] = _mm_sub_epi16(v_rb[1], _mm_unpackhi_epi16(v_y, v_y));
+        v_rgb[0] = _mm_unpacklo_epi16(v_rb[0], v_delta_16);
+        v_rgb[1] = _mm_unpackhi_epi16(v_rb[0], v_delta_16);
+        v_rgb[2] = _mm_unpacklo_epi16(v_rb[1], v_delta_16);
+        v_rgb[3] = _mm_unpackhi_epi16(v_rb[1], v_delta_16);
+        v_rgb[0] = _mm_madd_epi16(v_rgb[0], v_coeff);
+        v_rgb[1] = _mm_madd_epi16(v_rgb[1], v_coeff);
+        v_rgb[2] = _mm_madd_epi16(v_rgb[2], v_coeff);
+        v_rgb[3] = _mm_madd_epi16(v_rgb[3], v_coeff);
+        v_rgb[0] = _mm_srai_epi32(v_rgb[0], yuv_shift);
+        v_rgb[1] = _mm_srai_epi32(v_rgb[1], yuv_shift);
+        v_rgb[2] = _mm_srai_epi32(v_rgb[2], yuv_shift);
+        v_rgb[3] = _mm_srai_epi32(v_rgb[3], yuv_shift);
+        v_rgb[0] = _mm_packs_epi32(v_rgb[0], v_rgb[1]);
+        v_rgb[2] = _mm_packs_epi32(v_rgb[2], v_rgb[3]);
+        v_rgb[0] = _mm_packus_epi16(v_rgb[0], v_rgb[2]);
+
+        v_rb[0] = _mm_unpacklo_epi16(v_y, v_rgb[0]);
+        v_rb[1] = _mm_unpackhi_epi16(v_y, v_rgb[0]);
+
+        v_rb[0] = _mm_shuffle_epi8(v_rb[0], v_shuffle2);
+        v_rb[1] = _mm_shuffle_epi8(v_rb[1], v_shuffle2);
+        v_rb[1] = _mm_alignr_epi8(v_rb[1], _mm_slli_si128(v_rb[0], 4), 12);
+
+        _mm_storel_epi64((__m128i *)(dst), v_rb[0]);
+        _mm_storeu_si128((__m128i *)(dst + 8), v_rb[1]);
     }
 
     void operator()(const uchar * src, uchar * dst, int n) const
     {
         int scn = srccn, bidx = blueIdx, i = 0;
+        int yuvOrder = !isCrCb; //1 if YUV, 0 if YCrCb
         int C0 = coeffs[0], C1 = coeffs[1], C2 = coeffs[2], C3 = coeffs[3], C4 = coeffs[4];
         int delta = ColorChannel<uchar>::half()*(1 << yuv_shift);
         n *= 3;
 
         if (haveSIMD)
         {
-            for ( ; i <= n - 96; i += 96, src += scn * 32)
+            __m128i v_shuffle;
+            __m128i v_crgb;
+            if (scn == 4)
             {
-                __m128i v_r0 = _mm_loadu_si128((__m128i const *)(src));
-                __m128i v_r1 = _mm_loadu_si128((__m128i const *)(src + 16));
-                __m128i v_g0 = _mm_loadu_si128((__m128i const *)(src + 32));
-                __m128i v_g1 = _mm_loadu_si128((__m128i const *)(src + 48));
-                __m128i v_b0 = _mm_loadu_si128((__m128i const *)(src + 64));
-                __m128i v_b1 = _mm_loadu_si128((__m128i const *)(src + 80));
-
-                if (scn == 4)
+                if (bidx == 0)
                 {
-                    __m128i v_a0 = _mm_loadu_si128((__m128i const *)(src + 96));
-                    __m128i v_a1 = _mm_loadu_si128((__m128i const *)(src + 112));
-                    _mm_deinterleave_epi8(v_r0, v_r1, v_g0, v_g1,
-                                          v_b0, v_b1, v_a0, v_a1);
+                    v_shuffle = _mm_set_epi8(0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc, 0xe, 0x8, 0xa, 0x4, 0x6, 0x0, 0x2);
                 }
                 else
-                    _mm_deinterleave_epi8(v_r0, v_r1, v_g0, v_g1, v_b0, v_b1);
-
-                __m128i v_y0 = v_zero, v_cr0 = v_zero, v_cb0 = v_zero;
-                process(_mm_unpacklo_epi8(v_r0, v_zero),
-                        _mm_unpacklo_epi8(v_g0, v_zero),
-                        _mm_unpacklo_epi8(v_b0, v_zero),
-                        v_y0, v_cr0, v_cb0);
-
-                __m128i v_y1 = v_zero, v_cr1 = v_zero, v_cb1 = v_zero;
-                process(_mm_unpackhi_epi8(v_r0, v_zero),
-                        _mm_unpackhi_epi8(v_g0, v_zero),
-                        _mm_unpackhi_epi8(v_b0, v_zero),
-                        v_y1, v_cr1, v_cb1);
+                {
+                    v_shuffle = _mm_set_epi8(0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xe, 0xc, 0xa, 0x8, 0x6, 0x4, 0x2, 0x0);
+                }
+                v_crgb = _mm_set_epi16(0, (short)C2, (short)C1, (short)C0, 0, (short)C2, (short)C1, (short)C0);
+                for ( ; i <= n - 24; i += 24, src += scn * 8)
+                {
+                    __m128i v_src[2];
+                    v_src[0] = _mm_loadu_si128((__m128i const *)(src));
+                    v_src[1] = _mm_loadu_si128((__m128i const *)(src + 16));
 
-                __m128i v_y_0 = _mm_packus_epi16(v_y0, v_y1);
-                __m128i v_cr_0 = _mm_packus_epi16(v_cr0, v_cr1);
-                __m128i v_cb_0 = _mm_packus_epi16(v_cb0, v_cb1);
+                    __m128i v_rgb[4];
+                    v_rgb[0] = _mm_cvtepu8_epi16(v_src[0]);
+                    v_rgb[1] = _mm_cvtepu8_epi16(_mm_srli_si128(v_src[0], 8));
+                    v_rgb[2] = _mm_cvtepu8_epi16(v_src[1]);
+                    v_rgb[3] = _mm_cvtepu8_epi16(_mm_srli_si128(v_src[1], 8));
 
-                process(_mm_unpacklo_epi8(v_r1, v_zero),
-                        _mm_unpacklo_epi8(v_g1, v_zero),
-                        _mm_unpacklo_epi8(v_b1, v_zero),
-                        v_y0, v_cr0, v_cb0);
+                    __m128i v_rb[2];
+                    v_rb[0] = _mm_shuffle_epi8(v_src[0], v_shuffle);
+                    v_rb[1] = _mm_shuffle_epi8(v_src[1], v_shuffle);
 
-                process(_mm_unpackhi_epi8(v_r1, v_zero),
-                        _mm_unpackhi_epi8(v_g1, v_zero),
-                        _mm_unpackhi_epi8(v_b1, v_zero),
-                        v_y1, v_cr1, v_cb1);
+                    process(v_rgb, v_crgb, v_rb, dst + i);
+                }
+            }
+            else
+            {
+                if (bidx == 0)
+                {
+                    v_shuffle = _mm_set_epi8(0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9, 0xb, 0x6, 0x8, 0x3, 0x5, 0x0, 0x2);
+                }
+                else
+                {
+                    v_shuffle = _mm_set_epi8(0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xb, 0x9, 0x8, 0x6, 0x5, 0x3, 0x2, 0x0);
+                }
+                v_crgb = _mm_set_epi16(0, (short)C2, (short)C1, (short)C0, (short)C2, (short)C1, (short)C0, 0);
+                for ( ; i <= n - 24; i += 24, src += scn * 8)
+                {
+                    __m128i v_src[2];
+                    v_src[0] = _mm_loadu_si128((__m128i const *)(src));
+                    v_src[1] = _mm_loadl_epi64((__m128i const *)(src + 16));
 
-                __m128i v_y_1 = _mm_packus_epi16(v_y0, v_y1);
-                __m128i v_cr_1 = _mm_packus_epi16(v_cr0, v_cr1);
-                __m128i v_cb_1 = _mm_packus_epi16(v_cb0, v_cb1);
+                    __m128i v_rgb[4];
+                    v_rgb[0] = _mm_cvtepu8_epi16(_mm_slli_si128(v_src[0], 1));
+                    v_rgb[1] = _mm_cvtepu8_epi16(_mm_srli_si128(v_src[0], 5));
+                    v_rgb[2] = _mm_cvtepu8_epi16(_mm_alignr_epi8(v_src[1], v_src[0], 11));
+                    v_rgb[3] = _mm_cvtepu8_epi16(_mm_srli_si128(v_src[1], 1));
 
-                _mm_interleave_epi8(v_y_0, v_y_1, v_cr_0, v_cr_1, v_cb_0, v_cb_1);
+                    __m128i v_rb[2];
+                    v_rb[0] = _mm_shuffle_epi8(v_src[0], v_shuffle);
+                    v_rb[1] = _mm_shuffle_epi8(_mm_alignr_epi8(v_src[1], v_src[0], 12), v_shuffle);
 
-                _mm_storeu_si128((__m128i *)(dst + i), v_y_0);
-                _mm_storeu_si128((__m128i *)(dst + i + 16), v_y_1);
-                _mm_storeu_si128((__m128i *)(dst + i + 32), v_cr_0);
-                _mm_storeu_si128((__m128i *)(dst + i + 48), v_cr_1);
-                _mm_storeu_si128((__m128i *)(dst + i + 64), v_cb_0);
-                _mm_storeu_si128((__m128i *)(dst + i + 80), v_cb_1);
+                    process(v_rgb, v_crgb, v_rb, dst + i);
+                }
             }
         }
 
@@ -2284,15 +2420,16 @@ struct RGB2YCrCb_i<uchar>
             int Cr = CV_DESCALE((src[bidx^2] - Y)*C3 + delta, yuv_shift);
             int Cb = CV_DESCALE((src[bidx] - Y)*C4 + delta, yuv_shift);
             dst[i] = saturate_cast<uchar>(Y);
-            dst[i+1] = saturate_cast<uchar>(Cr);
-            dst[i+2] = saturate_cast<uchar>(Cb);
+            dst[i+1+yuvOrder] = saturate_cast<uchar>(Cr);
+            dst[i+2-yuvOrder] = saturate_cast<uchar>(Cb);
         }
     }
 
+    __m128i v_delta_16, v_delta_32;
+    __m128i v_coeff;
+    __m128i v_shuffle2;
     int srccn, blueIdx, coeffs[5];
-    __m128i v_c0, v_c1, v_c2;
-    __m128i v_c3, v_c4, v_delta, v_delta2;
-    __m128i v_zero;
+    bool isCrCb;
     bool haveSIMD;
 };
 
@@ -2301,11 +2438,12 @@ struct RGB2YCrCb_i<ushort>
 {
     typedef ushort channel_type;
 
-    RGB2YCrCb_i(int _srccn, int _blueIdx, const int* _coeffs)
-        : srccn(_srccn), blueIdx(_blueIdx)
+    RGB2YCrCb_i(int _srccn, int _blueIdx, bool _isCrCb)
+        : srccn(_srccn), blueIdx(_blueIdx), isCrCb(_isCrCb)
     {
-        static const int coeffs0[] = {R2Y, G2Y, B2Y, 11682, 9241};
-        memcpy(coeffs, _coeffs ? _coeffs : coeffs0, 5*sizeof(coeffs[0]));
+        static const int coeffs_crb[] = { R2Y, G2Y, B2Y, YCRI, YCBI };
+        static const int coeffs_yuv[] = { R2Y, G2Y, B2Y, R2VI, B2UI };
+        memcpy(coeffs, isCrCb ? coeffs_crb : coeffs_yuv, 5*sizeof(coeffs[0]));
         if (blueIdx==0)
             std::swap(coeffs[0], coeffs[2]);
 
@@ -2362,6 +2500,7 @@ struct RGB2YCrCb_i<ushort>
     void operator()(const ushort * src, ushort * dst, int n) const
     {
         int scn = srccn, bidx = blueIdx, i = 0;
+        int yuvOrder = !isCrCb; //1 if YUV, 0 if YCrCb
         int C0 = coeffs[0], C1 = coeffs[1], C2 = coeffs[2], C3 = coeffs[3], C4 = coeffs[4];
         int delta = ColorChannel<ushort>::half()*(1 << yuv_shift);
         n *= 3;
@@ -2396,14 +2535,17 @@ struct RGB2YCrCb_i<ushort>
                 process(v_r1, v_g1, v_b1,
                         v_y1, v_cr1, v_cb1);
 
-                _mm_interleave_epi16(v_y0, v_y1, v_cr0, v_cr1, v_cb0, v_cb1);
+                if(isCrCb)
+                    _mm_interleave_epi16(v_y0, v_y1, v_cr0, v_cr1, v_cb0, v_cb1);
+                else //YUV
+                    _mm_interleave_epi16(v_y0, v_y1, v_cb0, v_cb1, v_cr0, v_cr1);
 
                 _mm_storeu_si128((__m128i *)(dst + i), v_y0);
                 _mm_storeu_si128((__m128i *)(dst + i + 8), v_y1);
-                _mm_storeu_si128((__m128i *)(dst + i + 16), v_cr0);
-                _mm_storeu_si128((__m128i *)(dst + i + 24), v_cr1);
-                _mm_storeu_si128((__m128i *)(dst + i + 32), v_cb0);
-                _mm_storeu_si128((__m128i *)(dst + i + 40), v_cb1);
+                _mm_storeu_si128((__m128i *)(dst + i + 16 + yuvOrder*16), v_cr0);
+                _mm_storeu_si128((__m128i *)(dst + i + 24 + yuvOrder*16), v_cr1);
+                _mm_storeu_si128((__m128i *)(dst + i + 32 - yuvOrder*16), v_cb0);
+                _mm_storeu_si128((__m128i *)(dst + i + 40 - yuvOrder*16), v_cb1);
             }
         }
 
@@ -2413,12 +2555,13 @@ struct RGB2YCrCb_i<ushort>
             int Cr = CV_DESCALE((src[bidx^2] - Y)*C3 + delta, yuv_shift);
             int Cb = CV_DESCALE((src[bidx] - Y)*C4 + delta, yuv_shift);
             dst[i] = saturate_cast<ushort>(Y);
-            dst[i+1] = saturate_cast<ushort>(Cr);
-            dst[i+2] = saturate_cast<ushort>(Cb);
+            dst[i+1+yuvOrder] = saturate_cast<ushort>(Cr);
+            dst[i+2-yuvOrder] = saturate_cast<ushort>(Cb);
         }
     }
 
     int srccn, blueIdx, coeffs[5];
+    bool isCrCb;
     __m128i v_c0, v_c1, v_c2;
     __m128i v_c3, v_c4, v_delta, v_delta2;
     __m128i v_zero;
@@ -2431,23 +2574,25 @@ template<typename _Tp> struct YCrCb2RGB_f
 {
     typedef _Tp channel_type;
 
-    YCrCb2RGB_f(int _dstcn, int _blueIdx, const float* _coeffs)
-        : dstcn(_dstcn), blueIdx(_blueIdx)
+    YCrCb2RGB_f(int _dstcn, int _blueIdx, bool _isCrCb)
+        : dstcn(_dstcn), blueIdx(_blueIdx), isCrCb(_isCrCb)
     {
-        static const float coeffs0[] = {1.403f, -0.714f, -0.344f, 1.773f};
-        memcpy(coeffs, _coeffs ? _coeffs : coeffs0, 4*sizeof(coeffs[0]));
+        static const float coeffs_cbr[] = {CR2RF, CR2GF, CB2GF, CB2BF};
+        static const float coeffs_yuv[] = { V2RF,  V2GF,  U2GF,  U2BF};
+        memcpy(coeffs, isCrCb ? coeffs_cbr : coeffs_yuv, 4*sizeof(coeffs[0]));
     }
     void operator()(const _Tp* src, _Tp* dst, int n) const
     {
         int dcn = dstcn, bidx = blueIdx;
+        int yuvOrder = !isCrCb; //1 if YUV, 0 if YCrCb
         const _Tp delta = ColorChannel<_Tp>::half(), alpha = ColorChannel<_Tp>::max();
         float C0 = coeffs[0], C1 = coeffs[1], C2 = coeffs[2], C3 = coeffs[3];
         n *= 3;
         for(int i = 0; i < n; i += 3, dst += dcn)
         {
             _Tp Y = src[i];
-            _Tp Cr = src[i+1];
-            _Tp Cb = src[i+2];
+            _Tp Cr = src[i+1+yuvOrder];
+            _Tp Cb = src[i+2-yuvOrder];
 
             _Tp b = saturate_cast<_Tp>(Y + (Cb - delta)*C3);
             _Tp g = saturate_cast<_Tp>(Y + (Cb - delta)*C2 + (Cr - delta)*C1);
@@ -2459,6 +2604,7 @@ template<typename _Tp> struct YCrCb2RGB_f
         }
     }
     int dstcn, blueIdx;
+    bool isCrCb;
     float coeffs[4];
 };
 
@@ -2469,11 +2615,12 @@ struct YCrCb2RGB_f<float>
 {
     typedef float channel_type;
 
-    YCrCb2RGB_f(int _dstcn, int _blueIdx, const float* _coeffs)
-        : dstcn(_dstcn), blueIdx(_blueIdx)
+    YCrCb2RGB_f(int _dstcn, int _blueIdx, bool _isCrCb)
+        : dstcn(_dstcn), blueIdx(_blueIdx), isCrCb(_isCrCb)
     {
-        static const float coeffs0[] = {1.403f, -0.714f, -0.344f, 1.773f};
-        memcpy(coeffs, _coeffs ? _coeffs : coeffs0, 4*sizeof(coeffs[0]));
+        static const float coeffs_cbr[] = {CR2RF, CR2GF, CB2GF, CB2BF};
+        static const float coeffs_yuv[] = { V2RF,  V2GF,  U2GF,  U2BF};
+        memcpy(coeffs, isCrCb ? coeffs_cbr : coeffs_yuv, 4*sizeof(coeffs[0]));
 
         v_c0 = vdupq_n_f32(coeffs[0]);
         v_c1 = vdupq_n_f32(coeffs[1]);
@@ -2486,6 +2633,7 @@ struct YCrCb2RGB_f<float>
     void operator()(const float* src, float* dst, int n) const
     {
         int dcn = dstcn, bidx = blueIdx, i = 0;
+        int yuvOrder = !isCrCb; //1 if YUV, 0 if YCrCb
         const float delta = ColorChannel<float>::half(), alpha = ColorChannel<float>::max();
         float C0 = coeffs[0], C1 = coeffs[1], C2 = coeffs[2], C3 = coeffs[3];
         n *= 3;
@@ -2494,7 +2642,7 @@ struct YCrCb2RGB_f<float>
             for ( ; i <= n - 12; i += 12, dst += 12)
             {
                 float32x4x3_t v_src = vld3q_f32(src + i), v_dst;
-                float32x4_t v_Y = v_src.val[0], v_Cr = v_src.val[1], v_Cb = v_src.val[2];
+                float32x4_t v_Y = v_src.val[0], v_Cr = v_src.val[1+yuvOrder], v_Cb = v_src.val[2-yuvOrder];
 
                 v_dst.val[bidx] = vmlaq_f32(v_Y, vsubq_f32(v_Cb, v_delta), v_c3);
                 v_dst.val[1] = vaddq_f32(vmlaq_f32(vmulq_f32(vsubq_f32(v_Cb, v_delta), v_c2), vsubq_f32(v_Cr, v_delta), v_c1), v_Y);
@@ -2507,7 +2655,7 @@ struct YCrCb2RGB_f<float>
             {
                 float32x4x3_t v_src = vld3q_f32(src + i);
                 float32x4x4_t v_dst;
-                float32x4_t v_Y = v_src.val[0], v_Cr = v_src.val[1], v_Cb = v_src.val[2];
+                float32x4_t v_Y = v_src.val[0], v_Cr = v_src.val[1+yuvOrder], v_Cb = v_src.val[2-yuvOrder];
 
                 v_dst.val[bidx] = vmlaq_f32(v_Y, vsubq_f32(v_Cb, v_delta), v_c3);
                 v_dst.val[1] = vaddq_f32(vmlaq_f32(vmulq_f32(vsubq_f32(v_Cb, v_delta), v_c2), vsubq_f32(v_Cr, v_delta), v_c1), v_Y);
@@ -2519,7 +2667,7 @@ struct YCrCb2RGB_f<float>
 
         for ( ; i < n; i += 3, dst += dcn)
         {
-            float Y = src[i], Cr = src[i+1], Cb = src[i+2];
+            float Y = src[i], Cr = src[i+1+yuvOrder], Cb = src[i+2-yuvOrder];
 
             float b = Y + (Cb - delta)*C3;
             float g = Y + (Cb - delta)*C2 + (Cr - delta)*C1;
@@ -2531,6 +2679,7 @@ struct YCrCb2RGB_f<float>
         }
     }
     int dstcn, blueIdx;
+    bool isCrCb;
     float coeffs[4];
     float32x4_t v_c0, v_c1, v_c2, v_c3, v_alpha, v_delta;
 };
@@ -2542,11 +2691,12 @@ struct YCrCb2RGB_f<float>
 {
     typedef float channel_type;
 
-    YCrCb2RGB_f(int _dstcn, int _blueIdx, const float* _coeffs)
-        : dstcn(_dstcn), blueIdx(_blueIdx)
+    YCrCb2RGB_f(int _dstcn, int _blueIdx, bool _isCrCb)
+        : dstcn(_dstcn), blueIdx(_blueIdx), isCrCb(_isCrCb)
     {
-        static const float coeffs0[] = {1.403f, -0.714f, -0.344f, 1.773f};
-        memcpy(coeffs, _coeffs ? _coeffs : coeffs0, 4*sizeof(coeffs[0]));
+        static const float coeffs_cbr[] = {CR2RF, CR2GF, CB2GF, CB2BF};
+        static const float coeffs_yuv[] = { V2RF,  V2GF,  U2GF,  U2BF};
+        memcpy(coeffs, isCrCb ? coeffs_cbr : coeffs_yuv, 4*sizeof(coeffs[0]));
 
         v_c0 = _mm_set1_ps(coeffs[0]);
         v_c1 = _mm_set1_ps(coeffs[1]);
@@ -2564,6 +2714,9 @@ struct YCrCb2RGB_f<float>
         v_cb = _mm_sub_ps(v_cb, v_delta);
         v_cr = _mm_sub_ps(v_cr, v_delta);
 
+        if (!isCrCb)
+            std::swap(v_cb, v_cr);
+
         v_b = _mm_mul_ps(v_cb, v_c3);
         v_g = _mm_add_ps(_mm_mul_ps(v_cb, v_c2), _mm_mul_ps(v_cr, v_c1));
         v_r = _mm_mul_ps(v_cr, v_c0);
@@ -2579,6 +2732,7 @@ struct YCrCb2RGB_f<float>
     void operator()(const float* src, float* dst, int n) const
     {
         int dcn = dstcn, bidx = blueIdx, i = 0;
+        int yuvOrder = !isCrCb; //1 if YUV, 0 if YCrCb
         const float delta = ColorChannel<float>::half(), alpha = ColorChannel<float>::max();
         float C0 = coeffs[0], C1 = coeffs[1], C2 = coeffs[2], C3 = coeffs[3];
         n *= 3;
@@ -2629,7 +2783,7 @@ struct YCrCb2RGB_f<float>
 
         for ( ; i < n; i += 3, dst += dcn)
         {
-            float Y = src[i], Cr = src[i+1], Cb = src[i+2];
+            float Y = src[i], Cr = src[i+1+yuvOrder], Cb = src[i+2-yuvOrder];
 
             float b = Y + (Cb - delta)*C3;
             float g = Y + (Cb - delta)*C2 + (Cr - delta)*C1;
@@ -2641,6 +2795,7 @@ struct YCrCb2RGB_f<float>
         }
     }
     int dstcn, blueIdx;
+    bool isCrCb;
     float coeffs[4];
 
     __m128 v_c0, v_c1, v_c2, v_c3, v_alpha, v_delta;
@@ -2653,24 +2808,26 @@ template<typename _Tp> struct YCrCb2RGB_i
 {
     typedef _Tp channel_type;
 
-    YCrCb2RGB_i(int _dstcn, int _blueIdx, const int* _coeffs)
-        : dstcn(_dstcn), blueIdx(_blueIdx)
+    YCrCb2RGB_i(int _dstcn, int _blueIdx, bool _isCrCb)
+        : dstcn(_dstcn), blueIdx(_blueIdx), isCrCb(_isCrCb)
     {
-        static const int coeffs0[] = {22987, -11698, -5636, 29049};
-        memcpy(coeffs, _coeffs ? _coeffs : coeffs0, 4*sizeof(coeffs[0]));
+        static const int coeffs_crb[] = { CR2RI, CR2GI, CB2GI, CB2BI};
+        static const int coeffs_yuv[] = {  V2RI,  V2GI,  U2GI, U2BI };
+        memcpy(coeffs, isCrCb ? coeffs_crb : coeffs_yuv, 4*sizeof(coeffs[0]));
     }
 
     void operator()(const _Tp* src, _Tp* dst, int n) const
     {
         int dcn = dstcn, bidx = blueIdx;
+        int yuvOrder = !isCrCb; //1 if YUV, 0 if YCrCb
         const _Tp delta = ColorChannel<_Tp>::half(), alpha = ColorChannel<_Tp>::max();
         int C0 = coeffs[0], C1 = coeffs[1], C2 = coeffs[2], C3 = coeffs[3];
         n *= 3;
         for(int i = 0; i < n; i += 3, dst += dcn)
         {
             _Tp Y = src[i];
-            _Tp Cr = src[i+1];
-            _Tp Cb = src[i+2];
+            _Tp Cr = src[i+1+yuvOrder];
+            _Tp Cb = src[i+2-yuvOrder];
 
             int b = Y + CV_DESCALE((Cb - delta)*C3, yuv_shift);
             int g = Y + CV_DESCALE((Cb - delta)*C2 + (Cr - delta)*C1, yuv_shift);
@@ -2684,6 +2841,7 @@ template<typename _Tp> struct YCrCb2RGB_i
         }
     }
     int dstcn, blueIdx;
+    bool isCrCb;
     int coeffs[4];
 };
 
@@ -2694,11 +2852,12 @@ struct YCrCb2RGB_i<uchar>
 {
     typedef uchar channel_type;
 
-    YCrCb2RGB_i(int _dstcn, int _blueIdx, const int* _coeffs)
-        : dstcn(_dstcn), blueIdx(_blueIdx)
+    YCrCb2RGB_i(int _dstcn, int _blueIdx, bool _isCrCb)
+        : dstcn(_dstcn), blueIdx(_blueIdx), isCrCb(_isCrCb)
     {
-        static const int coeffs0[] = {22987, -11698, -5636, 29049};
-        memcpy(coeffs, _coeffs ? _coeffs : coeffs0, 4*sizeof(coeffs[0]));
+        static const int coeffs_crb[] = { CR2RI, CR2GI, CB2GI, CB2BI};
+        static const int coeffs_yuv[] = {  V2RI,  V2GI,  U2GI, U2BI };
+        memcpy(coeffs, isCrCb ? coeffs_crb : coeffs_yuv, 4*sizeof(coeffs[0]));
 
         v_c0 = vdupq_n_s32(coeffs[0]);
         v_c1 = vdupq_n_s32(coeffs[1]);
@@ -2712,6 +2871,7 @@ struct YCrCb2RGB_i<uchar>
     void operator()(const uchar* src, uchar* dst, int n) const
     {
         int dcn = dstcn, bidx = blueIdx, i = 0;
+        int yuvOrder = !isCrCb; //1 if YUV, 0 if YCrCb
         const uchar delta = ColorChannel<uchar>::half(), alpha = ColorChannel<uchar>::max();
         int C0 = coeffs[0], C1 = coeffs[1], C2 = coeffs[2], C3 = coeffs[3];
         n *= 3;
@@ -2725,8 +2885,8 @@ struct YCrCb2RGB_i<uchar>
             v_src16.val[2] = vreinterpretq_s16_u16(vmovl_u8(v_src.val[2]));
 
             int16x4_t v_Y = vget_low_s16(v_src16.val[0]),
-                      v_Cr = vget_low_s16(v_src16.val[1]),
-                      v_Cb = vget_low_s16(v_src16.val[2]);
+                      v_Cr = vget_low_s16(v_src16.val[1+yuvOrder]),
+                      v_Cb = vget_low_s16(v_src16.val[2-yuvOrder]);
 
             int32x4_t v_b0 = vmulq_s32(v_c3, vsubl_s16(v_Cb, v_delta));
             v_b0 = vaddw_s16(vshrq_n_s32(vaddq_s32(v_b0, v_delta2), yuv_shift), v_Y);
@@ -2736,8 +2896,8 @@ struct YCrCb2RGB_i<uchar>
             v_r0 = vaddw_s16(vshrq_n_s32(vaddq_s32(v_r0, v_delta2), yuv_shift), v_Y);
 
             v_Y = vget_high_s16(v_src16.val[0]);
-            v_Cr = vget_high_s16(v_src16.val[1]);
-            v_Cb = vget_high_s16(v_src16.val[2]);
+            v_Cr = vget_high_s16(v_src16.val[1+yuvOrder]);
+            v_Cb = vget_high_s16(v_src16.val[2-yuvOrder]);
 
             int32x4_t v_b1 = vmulq_s32(v_c3, vsubl_s16(v_Cb, v_delta));
             v_b1 = vaddw_s16(vshrq_n_s32(vaddq_s32(v_b1, v_delta2), yuv_shift), v_Y);
@@ -2772,8 +2932,8 @@ struct YCrCb2RGB_i<uchar>
         for ( ; i < n; i += 3, dst += dcn)
         {
             uchar Y = src[i];
-            uchar Cr = src[i+1];
-            uchar Cb = src[i+2];
+            uchar Cr = src[i+1+yuvOrder];
+            uchar Cb = src[i+2-yuvOrder];
 
             int b = Y + CV_DESCALE((Cb - delta)*C3, yuv_shift);
             int g = Y + CV_DESCALE((Cb - delta)*C2 + (Cr - delta)*C1, yuv_shift);
@@ -2787,6 +2947,7 @@ struct YCrCb2RGB_i<uchar>
         }
     }
     int dstcn, blueIdx;
+    bool isCrCb;
     int coeffs[4];
 
     int32x4_t v_c0, v_c1, v_c2, v_c3, v_delta2;
@@ -2799,11 +2960,12 @@ struct YCrCb2RGB_i<ushort>
 {
     typedef ushort channel_type;
 
-    YCrCb2RGB_i(int _dstcn, int _blueIdx, const int* _coeffs)
-        : dstcn(_dstcn), blueIdx(_blueIdx)
+    YCrCb2RGB_i(int _dstcn, int _blueIdx, bool _isCrCb)
+        : dstcn(_dstcn), blueIdx(_blueIdx), isCrCb(_isCrCb)
     {
-        static const int coeffs0[] = {22987, -11698, -5636, 29049};
-        memcpy(coeffs, _coeffs ? _coeffs : coeffs0, 4*sizeof(coeffs[0]));
+        static const int coeffs_crb[] = { CR2RI, CR2GI, CB2GI, CB2BI};
+        static const int coeffs_yuv[] = {  V2RI,  V2GI,  U2GI, U2BI };
+        memcpy(coeffs, isCrCb ? coeffs_crb : coeffs_yuv, 4*sizeof(coeffs[0]));
 
         v_c0 = vdupq_n_s32(coeffs[0]);
         v_c1 = vdupq_n_s32(coeffs[1]);
@@ -2818,6 +2980,7 @@ struct YCrCb2RGB_i<ushort>
     void operator()(const ushort* src, ushort* dst, int n) const
     {
         int dcn = dstcn, bidx = blueIdx, i = 0;
+        int yuvOrder = !isCrCb; //1 if YUV, 0 if YCrCb
         const ushort delta = ColorChannel<ushort>::half(), alpha = ColorChannel<ushort>::max();
         int C0 = coeffs[0], C1 = coeffs[1], C2 = coeffs[2], C3 = coeffs[3];
         n *= 3;
@@ -2827,8 +2990,8 @@ struct YCrCb2RGB_i<ushort>
             uint16x8x3_t v_src = vld3q_u16(src + i);
 
             int32x4_t v_Y = vreinterpretq_s32_u32(vmovl_u16(vget_low_u16(v_src.val[0]))),
-                      v_Cr = vreinterpretq_s32_u32(vmovl_u16(vget_low_u16(v_src.val[1]))),
-                      v_Cb = vreinterpretq_s32_u32(vmovl_u16(vget_low_u16(v_src.val[2])));
+                      v_Cr = vreinterpretq_s32_u32(vmovl_u16(vget_low_u16(v_src.val[1+yuvOrder]))),
+                      v_Cb = vreinterpretq_s32_u32(vmovl_u16(vget_low_u16(v_src.val[2-yuvOrder])));
 
             int32x4_t v_b0 = vmulq_s32(v_c3, vsubq_s32(v_Cb, v_delta));
             v_b0 = vaddq_s32(vshrq_n_s32(vaddq_s32(v_b0, v_delta2), yuv_shift), v_Y);
@@ -2838,8 +3001,8 @@ struct YCrCb2RGB_i<ushort>
             v_r0 = vaddq_s32(vshrq_n_s32(vaddq_s32(v_r0, v_delta2), yuv_shift), v_Y);
 
             v_Y = vreinterpretq_s32_u32(vmovl_u16(vget_high_u16(v_src.val[0]))),
-            v_Cr = vreinterpretq_s32_u32(vmovl_u16(vget_high_u16(v_src.val[1]))),
-            v_Cb = vreinterpretq_s32_u32(vmovl_u16(vget_high_u16(v_src.val[2])));
+            v_Cr = vreinterpretq_s32_u32(vmovl_u16(vget_high_u16(v_src.val[1+yuvOrder]))),
+            v_Cb = vreinterpretq_s32_u32(vmovl_u16(vget_high_u16(v_src.val[2-yuvOrder])));
 
             int32x4_t v_b1 = vmulq_s32(v_c3, vsubq_s32(v_Cb, v_delta));
             v_b1 = vaddq_s32(vshrq_n_s32(vaddq_s32(v_b1, v_delta2), yuv_shift), v_Y);
@@ -2876,8 +3039,8 @@ struct YCrCb2RGB_i<ushort>
             uint16x4x3_t v_src = vld3_u16(src + i);
 
             int32x4_t v_Y = vreinterpretq_s32_u32(vmovl_u16(v_src.val[0])),
-                      v_Cr = vreinterpretq_s32_u32(vmovl_u16(v_src.val[1])),
-                      v_Cb = vreinterpretq_s32_u32(vmovl_u16(v_src.val[2]));
+                      v_Cr = vreinterpretq_s32_u32(vmovl_u16(v_src.val[1+yuvOrder])),
+                      v_Cb = vreinterpretq_s32_u32(vmovl_u16(v_src.val[2-yuvOrder]));
 
             int32x4_t v_b = vmulq_s32(v_c3, vsubq_s32(v_Cb, v_delta));
             v_b = vaddq_s32(vshrq_n_s32(vaddq_s32(v_b, v_delta2), yuv_shift), v_Y);
@@ -2912,8 +3075,8 @@ struct YCrCb2RGB_i<ushort>
         for ( ; i < n; i += 3, dst += dcn)
         {
             ushort Y = src[i];
-            ushort Cr = src[i+1];
-            ushort Cb = src[i+2];
+            ushort Cr = src[i+1+yuvOrder];
+            ushort Cb = src[i+2-yuvOrder];
 
             int b = Y + CV_DESCALE((Cb - delta)*C3, yuv_shift);
             int g = Y + CV_DESCALE((Cb - delta)*C2 + (Cr - delta)*C1, yuv_shift);
@@ -2927,6 +3090,7 @@ struct YCrCb2RGB_i<ushort>
         }
     }
     int dstcn, blueIdx;
+    bool isCrCb;
     int coeffs[4];
 
     int32x4_t v_c0, v_c1, v_c2, v_c3, v_delta2, v_delta;
@@ -2941,11 +3105,12 @@ struct YCrCb2RGB_i<uchar>
 {
     typedef uchar channel_type;
 
-    YCrCb2RGB_i(int _dstcn, int _blueIdx, const int* _coeffs)
-        : dstcn(_dstcn), blueIdx(_blueIdx)
+    YCrCb2RGB_i(int _dstcn, int _blueIdx, bool _isCrCb)
+        : dstcn(_dstcn), blueIdx(_blueIdx), isCrCb(_isCrCb)
     {
-        static const int coeffs0[] = {22987, -11698, -5636, 29049};
-        memcpy(coeffs, _coeffs ? _coeffs : coeffs0, 4*sizeof(coeffs[0]));
+        static const int coeffs_crb[] = { CR2RI, CR2GI, CB2GI, CB2BI};
+        static const int coeffs_yuv[] = {  V2RI,  V2GI,  U2GI, U2BI };
+        memcpy(coeffs, isCrCb ? coeffs_crb : coeffs_yuv, 4*sizeof(coeffs[0]));
 
         v_c0 = _mm_set1_epi16((short)coeffs[0]);
         v_c1 = _mm_set1_epi16((short)coeffs[1]);
@@ -2958,10 +3123,78 @@ struct YCrCb2RGB_i<uchar>
         uchar alpha = ColorChannel<uchar>::max();
         v_alpha = _mm_set1_epi8(*(char *)&alpha);
 
-        useSSE = coeffs[0] <= std::numeric_limits<short>::max();
+        // when using YUV, one of coefficients is bigger than std::numeric_limits<short>::max(),
+        //which is not appropriate for SSE
+        useSSE = isCrCb;
         haveSIMD = checkHardwareSupport(CV_CPU_SSE2);
     }
 
+#if CV_SSE4_1
+    // 16s x 8
+    void process(__m128i* v_src, __m128i* v_shuffle,
+                 __m128i* v_coeffs) const
+    {
+        __m128i v_ycrcb[3];
+        v_ycrcb[0] = _mm_shuffle_epi8(v_src[0], v_shuffle[0]);
+        v_ycrcb[1] = _mm_shuffle_epi8(_mm_alignr_epi8(v_src[1], v_src[0], 8), v_shuffle[0]);
+        v_ycrcb[2] = _mm_shuffle_epi8(v_src[1], v_shuffle[0]);
+
+        __m128i v_y[3];
+        v_y[1] = _mm_shuffle_epi8(v_src[0], v_shuffle[1]);
+        v_y[2] = _mm_srli_si128(_mm_shuffle_epi8(_mm_alignr_epi8(v_src[1], v_src[0], 15), v_shuffle[1]), 1);
+        v_y[0] = _mm_unpacklo_epi8(v_y[1], v_zero);
+        v_y[1] = _mm_unpackhi_epi8(v_y[1], v_zero);
+        v_y[2] = _mm_unpacklo_epi8(v_y[2], v_zero);
+
+        __m128i v_rgb[6];
+        v_rgb[0] = _mm_unpacklo_epi8(v_ycrcb[0], v_zero);
+        v_rgb[1] = _mm_unpackhi_epi8(v_ycrcb[0], v_zero);
+        v_rgb[2] = _mm_unpacklo_epi8(v_ycrcb[1], v_zero);
+        v_rgb[3] = _mm_unpackhi_epi8(v_ycrcb[1], v_zero);
+        v_rgb[4] = _mm_unpacklo_epi8(v_ycrcb[2], v_zero);
+        v_rgb[5] = _mm_unpackhi_epi8(v_ycrcb[2], v_zero);
+
+        v_rgb[0] = _mm_sub_epi16(v_rgb[0], v_delta);
+        v_rgb[1] = _mm_sub_epi16(v_rgb[1], v_delta);
+        v_rgb[2] = _mm_sub_epi16(v_rgb[2], v_delta);
+        v_rgb[3] = _mm_sub_epi16(v_rgb[3], v_delta);
+        v_rgb[4] = _mm_sub_epi16(v_rgb[4], v_delta);
+        v_rgb[5] = _mm_sub_epi16(v_rgb[5], v_delta);
+
+        v_rgb[0] = _mm_madd_epi16(v_rgb[0], v_coeffs[0]);
+        v_rgb[1] = _mm_madd_epi16(v_rgb[1], v_coeffs[1]);
+        v_rgb[2] = _mm_madd_epi16(v_rgb[2], v_coeffs[2]);
+        v_rgb[3] = _mm_madd_epi16(v_rgb[3], v_coeffs[0]);
+        v_rgb[4] = _mm_madd_epi16(v_rgb[4], v_coeffs[1]);
+        v_rgb[5] = _mm_madd_epi16(v_rgb[5], v_coeffs[2]);
+
+        v_rgb[0] = _mm_add_epi32(v_rgb[0], v_delta2);
+        v_rgb[1] = _mm_add_epi32(v_rgb[1], v_delta2);
+        v_rgb[2] = _mm_add_epi32(v_rgb[2], v_delta2);
+        v_rgb[3] = _mm_add_epi32(v_rgb[3], v_delta2);
+        v_rgb[4] = _mm_add_epi32(v_rgb[4], v_delta2);
+        v_rgb[5] = _mm_add_epi32(v_rgb[5], v_delta2);
+
+        v_rgb[0] = _mm_srai_epi32(v_rgb[0], yuv_shift);
+        v_rgb[1] = _mm_srai_epi32(v_rgb[1], yuv_shift);
+        v_rgb[2] = _mm_srai_epi32(v_rgb[2], yuv_shift);
+        v_rgb[3] = _mm_srai_epi32(v_rgb[3], yuv_shift);
+        v_rgb[4] = _mm_srai_epi32(v_rgb[4], yuv_shift);
+        v_rgb[5] = _mm_srai_epi32(v_rgb[5], yuv_shift);
+
+        v_rgb[0] = _mm_packs_epi32(v_rgb[0], v_rgb[1]);
+        v_rgb[2] = _mm_packs_epi32(v_rgb[2], v_rgb[3]);
+        v_rgb[4] = _mm_packs_epi32(v_rgb[4], v_rgb[5]);
+
+        v_rgb[0] = _mm_add_epi16(v_rgb[0], v_y[0]);
+        v_rgb[2] = _mm_add_epi16(v_rgb[2], v_y[1]);
+        v_rgb[4] = _mm_add_epi16(v_rgb[4], v_y[2]);
+
+        v_src[0] = _mm_packus_epi16(v_rgb[0], v_rgb[2]);
+        v_src[1] = _mm_packus_epi16(v_rgb[4], v_rgb[4]);
+    }
+#endif // CV_SSE4_1
+
     // 16s x 8
     void process(__m128i v_y, __m128i v_cr, __m128i v_cb,
                  __m128i & v_r, __m128i & v_g, __m128i & v_b) const
@@ -3011,10 +3244,96 @@ struct YCrCb2RGB_i<uchar>
     void operator()(const uchar* src, uchar* dst, int n) const
     {
         int dcn = dstcn, bidx = blueIdx, i = 0;
+        int yuvOrder = !isCrCb; //1 if YUV, 0 if YCrCb
         const uchar delta = ColorChannel<uchar>::half(), alpha = ColorChannel<uchar>::max();
         int C0 = coeffs[0], C1 = coeffs[1], C2 = coeffs[2], C3 = coeffs[3];
         n *= 3;
 
+#if CV_SSE4_1
+        if (checkHardwareSupport(CV_CPU_SSE4_1) && useSSE)
+        {
+            __m128i v_shuffle[2];
+            v_shuffle[0] = _mm_set_epi8(0x8, 0x7, 0x7, 0x6, 0x6, 0x5, 0x5, 0x4, 0x4, 0x3, 0x3, 0x2, 0x2, 0x1, 0x1, 0x0);
+            v_shuffle[1] = _mm_set_epi8(0xf, 0xc, 0xc, 0xc, 0x9, 0x9, 0x9, 0x6, 0x6, 0x6, 0x3, 0x3, 0x3, 0x0, 0x0, 0x0);
+            __m128i v_coeffs[3];
+            v_coeffs[0] = _mm_set_epi16((short)C0, 0, 0, (short)C3, (short)C2, (short)C1, (short)C0, 0);
+            v_coeffs[1] = _mm_set_epi16((short)C2, (short)C1, (short)C0, 0, 0, (short)C3, (short)C2, (short)C1);
+            v_coeffs[2] = _mm_set_epi16(0, (short)C3, (short)C2, (short)C1, (short)C0, 0, 0, (short)C3);
+
+            if (dcn == 3)
+            {
+                if (bidx == 0)
+                {
+                    __m128i v_shuffle_dst = _mm_set_epi8(0xf, 0xc, 0xd, 0xe, 0x9, 0xa, 0xb, 0x6, 0x7, 0x8, 0x3, 0x4, 0x5, 0x0, 0x1, 0x2);
+                    for ( ; i <= n - 24; i += 24, dst += dcn * 8)
+                    {
+                        __m128i v_src[2];
+                        v_src[0] = _mm_loadu_si128((__m128i const *)(src + i));
+                        v_src[1] = _mm_loadl_epi64((__m128i const *)(src + i + 16));
+
+                        process(v_src, v_shuffle, v_coeffs);
+
+                        __m128i v_dst[2];
+                        v_dst[0] = _mm_shuffle_epi8(v_src[0], v_shuffle_dst);
+                        v_dst[1] = _mm_shuffle_epi8(_mm_alignr_epi8(v_src[1], v_src[0], 15), v_shuffle_dst);
+
+                        _mm_storeu_si128((__m128i *)(dst), _mm_alignr_epi8(v_dst[1], _mm_slli_si128(v_dst[0], 1), 1));
+                        _mm_storel_epi64((__m128i *)(dst + 16), _mm_srli_si128(v_dst[1], 1));
+                    }
+                }
+                else
+                {
+                    for ( ; i <= n - 24; i += 24, dst += dcn * 8)
+                    {
+                        __m128i v_src[2];
+                        v_src[0] = _mm_loadu_si128((__m128i const *)(src + i));
+                        v_src[1] = _mm_loadl_epi64((__m128i const *)(src + i + 16));
+
+                        process(v_src, v_shuffle, v_coeffs);
+
+                        _mm_storeu_si128((__m128i *)(dst), v_src[0]);
+                        _mm_storel_epi64((__m128i *)(dst + 16), v_src[1]);
+                    }
+                }
+            }
+            else
+            {
+                if (bidx == 0)
+                {
+                    __m128i v_shuffle_dst = _mm_set_epi8(0x0, 0xa, 0xb, 0xc, 0x0, 0x7, 0x8, 0x9, 0x0, 0x4, 0x5, 0x6, 0x0, 0x1, 0x2, 0x3);
+
+                    for ( ; i <= n - 24; i += 24, dst += dcn * 8)
+                    {
+                        __m128i v_src[2];
+                        v_src[0] = _mm_loadu_si128((__m128i const *)(src + i));
+                        v_src[1] = _mm_loadl_epi64((__m128i const *)(src + i + 16));
+
+                        process(v_src, v_shuffle, v_coeffs);
+
+                        _mm_storeu_si128((__m128i *)(dst), _mm_shuffle_epi8(_mm_alignr_epi8(v_src[0], v_alpha, 15), v_shuffle_dst));
+                        _mm_storeu_si128((__m128i *)(dst + 16), _mm_shuffle_epi8(_mm_alignr_epi8(_mm_alignr_epi8(v_src[1], v_src[0], 12), v_alpha, 15), v_shuffle_dst));
+                    }
+                }
+                else
+                {
+                    __m128i v_shuffle_dst = _mm_set_epi8(0x0, 0xc, 0xb, 0xa, 0x0, 0x9, 0x8, 0x7, 0x0, 0x6, 0x5, 0x4, 0x0, 0x3, 0x2, 0x1);
+
+                    for ( ; i <= n - 24; i += 24, dst += dcn * 8)
+                    {
+                        __m128i v_src[2];
+                        v_src[0] = _mm_loadu_si128((__m128i const *)(src + i));
+                        v_src[1] = _mm_loadl_epi64((__m128i const *)(src + i + 16));
+
+                        process(v_src, v_shuffle, v_coeffs);
+
+                        _mm_storeu_si128((__m128i *)(dst), _mm_shuffle_epi8(_mm_alignr_epi8(v_src[0], v_alpha, 15), v_shuffle_dst));
+                        _mm_storeu_si128((__m128i *)(dst + 16), _mm_shuffle_epi8(_mm_alignr_epi8(_mm_alignr_epi8(v_src[1], v_src[0], 12), v_alpha, 15), v_shuffle_dst));
+                    }
+                }
+            }
+        }
+        else
+#endif // CV_SSE4_1
         if (haveSIMD && useSSE)
         {
             for ( ; i <= n - 96; i += 96, dst += dcn * 32)
@@ -3090,8 +3409,8 @@ struct YCrCb2RGB_i<uchar>
         for ( ; i < n; i += 3, dst += dcn)
         {
             uchar Y = src[i];
-            uchar Cr = src[i+1];
-            uchar Cb = src[i+2];
+            uchar Cr = src[i+1+yuvOrder];
+            uchar Cb = src[i+2-yuvOrder];
 
             int b = Y + CV_DESCALE((Cb - delta)*C3, yuv_shift);
             int g = Y + CV_DESCALE((Cb - delta)*C2 + (Cr - delta)*C1, yuv_shift);
@@ -3106,6 +3425,7 @@ struct YCrCb2RGB_i<uchar>
     }
     int dstcn, blueIdx;
     int coeffs[4];
+    bool isCrCb;
     bool useSSE, haveSIMD;
 
     __m128i v_c0, v_c1, v_c2, v_c3, v_delta2;
@@ -4240,16 +4560,161 @@ struct HSV2RGB_f
     typedef float channel_type;
 
     HSV2RGB_f(int _dstcn, int _blueIdx, float _hrange)
-    : dstcn(_dstcn), blueIdx(_blueIdx), hscale(6.f/_hrange) {}
+    : dstcn(_dstcn), blueIdx(_blueIdx), hscale(6.f/_hrange) {
+        #if CV_SSE2
+        haveSIMD = checkHardwareSupport(CV_CPU_SSE2);
+        #endif
+    }
+
+    #if CV_SSE2
+    void process(__m128& v_h0, __m128& v_h1, __m128& v_s0,
+                 __m128& v_s1, __m128& v_v0, __m128& v_v1) const
+    {
+        v_h0 = _mm_mul_ps(v_h0, _mm_set1_ps(hscale));
+        v_h1 = _mm_mul_ps(v_h1, _mm_set1_ps(hscale));
+
+        __m128 v_pre_sector0 = _mm_cvtepi32_ps(_mm_cvttps_epi32(v_h0));
+        __m128 v_pre_sector1 = _mm_cvtepi32_ps(_mm_cvttps_epi32(v_h1));
+
+        v_h0 = _mm_sub_ps(v_h0, v_pre_sector0);
+        v_h1 = _mm_sub_ps(v_h1, v_pre_sector1);
+
+        __m128 v_tab00 = v_v0;
+        __m128 v_tab01 = v_v1;
+        __m128 v_tab10 = _mm_mul_ps(v_v0, _mm_sub_ps(_mm_set1_ps(1.0f), v_s0));
+        __m128 v_tab11 = _mm_mul_ps(v_v1, _mm_sub_ps(_mm_set1_ps(1.0f), v_s1));
+        __m128 v_tab20 = _mm_mul_ps(v_v0, _mm_sub_ps(_mm_set1_ps(1.0f), _mm_mul_ps(v_s0, v_h0)));
+        __m128 v_tab21 = _mm_mul_ps(v_v1, _mm_sub_ps(_mm_set1_ps(1.0f), _mm_mul_ps(v_s1, v_h1)));
+        __m128 v_tab30 = _mm_mul_ps(v_v0, _mm_sub_ps(_mm_set1_ps(1.0f), _mm_mul_ps(v_s0, _mm_sub_ps(_mm_set1_ps(1.0f), v_h0))));
+        __m128 v_tab31 = _mm_mul_ps(v_v1, _mm_sub_ps(_mm_set1_ps(1.0f), _mm_mul_ps(v_s1, _mm_sub_ps(_mm_set1_ps(1.0f), v_h1))));
+
+        __m128 v_sector0 = _mm_div_ps(v_pre_sector0, _mm_set1_ps(6.0f));
+        __m128 v_sector1 = _mm_div_ps(v_pre_sector1, _mm_set1_ps(6.0f));
+        v_sector0 = _mm_cvtepi32_ps(_mm_cvttps_epi32(v_sector0));
+        v_sector1 = _mm_cvtepi32_ps(_mm_cvttps_epi32(v_sector1));
+        v_sector0 = _mm_mul_ps(v_sector0, _mm_set1_ps(6.0f));
+        v_sector1 = _mm_mul_ps(v_sector1, _mm_set1_ps(6.0f));
+        v_sector0 = _mm_sub_ps(v_pre_sector0, v_sector0);
+        v_sector1 = _mm_sub_ps(v_pre_sector1, v_sector1);
+
+        v_h0 = _mm_and_ps(v_tab10, _mm_cmplt_ps(v_sector0, _mm_set1_ps(2.0f)));
+        v_h1 = _mm_and_ps(v_tab11, _mm_cmplt_ps(v_sector1, _mm_set1_ps(2.0f)));
+        v_h0 = _mm_or_ps(v_h0, _mm_and_ps(v_tab30, _mm_cmpeq_ps(v_sector0, _mm_set1_ps(2.0f))));
+        v_h1 = _mm_or_ps(v_h1, _mm_and_ps(v_tab31, _mm_cmpeq_ps(v_sector1, _mm_set1_ps(2.0f))));
+        v_h0 = _mm_or_ps(v_h0, _mm_and_ps(v_tab00, _mm_cmpeq_ps(v_sector0, _mm_set1_ps(3.0f))));
+        v_h1 = _mm_or_ps(v_h1, _mm_and_ps(v_tab01, _mm_cmpeq_ps(v_sector1, _mm_set1_ps(3.0f))));
+        v_h0 = _mm_or_ps(v_h0, _mm_and_ps(v_tab00, _mm_cmpeq_ps(v_sector0, _mm_set1_ps(4.0f))));
+        v_h1 = _mm_or_ps(v_h1, _mm_and_ps(v_tab01, _mm_cmpeq_ps(v_sector1, _mm_set1_ps(4.0f))));
+        v_h0 = _mm_or_ps(v_h0, _mm_and_ps(v_tab20, _mm_cmpgt_ps(v_sector0, _mm_set1_ps(4.0f))));
+        v_h1 = _mm_or_ps(v_h1, _mm_and_ps(v_tab21, _mm_cmpgt_ps(v_sector1, _mm_set1_ps(4.0f))));
+        v_s0 = _mm_and_ps(v_tab30, _mm_cmplt_ps(v_sector0, _mm_set1_ps(1.0f)));
+        v_s1 = _mm_and_ps(v_tab31, _mm_cmplt_ps(v_sector1, _mm_set1_ps(1.0f)));
+        v_s0 = _mm_or_ps(v_s0, _mm_and_ps(v_tab00, _mm_cmpeq_ps(v_sector0, _mm_set1_ps(1.0f))));
+        v_s1 = _mm_or_ps(v_s1, _mm_and_ps(v_tab01, _mm_cmpeq_ps(v_sector1, _mm_set1_ps(1.0f))));
+        v_s0 = _mm_or_ps(v_s0, _mm_and_ps(v_tab00, _mm_cmpeq_ps(v_sector0, _mm_set1_ps(2.0f))));
+        v_s1 = _mm_or_ps(v_s1, _mm_and_ps(v_tab01, _mm_cmpeq_ps(v_sector1, _mm_set1_ps(2.0f))));
+        v_s0 = _mm_or_ps(v_s0, _mm_and_ps(v_tab20, _mm_cmpeq_ps(v_sector0, _mm_set1_ps(3.0f))));
+        v_s1 = _mm_or_ps(v_s1, _mm_and_ps(v_tab21, _mm_cmpeq_ps(v_sector1, _mm_set1_ps(3.0f))));
+        v_s0 = _mm_or_ps(v_s0, _mm_and_ps(v_tab10, _mm_cmpgt_ps(v_sector0, _mm_set1_ps(3.0f))));
+        v_s1 = _mm_or_ps(v_s1, _mm_and_ps(v_tab11, _mm_cmpgt_ps(v_sector1, _mm_set1_ps(3.0f))));
+        v_v0 = _mm_and_ps(v_tab00, _mm_cmplt_ps(v_sector0, _mm_set1_ps(1.0f)));
+        v_v1 = _mm_and_ps(v_tab01, _mm_cmplt_ps(v_sector1, _mm_set1_ps(1.0f)));
+        v_v0 = _mm_or_ps(v_v0, _mm_and_ps(v_tab20, _mm_cmpeq_ps(v_sector0, _mm_set1_ps(1.0f))));
+        v_v1 = _mm_or_ps(v_v1, _mm_and_ps(v_tab21, _mm_cmpeq_ps(v_sector1, _mm_set1_ps(1.0f))));
+        v_v0 = _mm_or_ps(v_v0, _mm_and_ps(v_tab10, _mm_cmpeq_ps(v_sector0, _mm_set1_ps(2.0f))));
+        v_v1 = _mm_or_ps(v_v1, _mm_and_ps(v_tab11, _mm_cmpeq_ps(v_sector1, _mm_set1_ps(2.0f))));
+        v_v0 = _mm_or_ps(v_v0, _mm_and_ps(v_tab10, _mm_cmpeq_ps(v_sector0, _mm_set1_ps(3.0f))));
+        v_v1 = _mm_or_ps(v_v1, _mm_and_ps(v_tab11, _mm_cmpeq_ps(v_sector1, _mm_set1_ps(3.0f))));
+        v_v0 = _mm_or_ps(v_v0, _mm_and_ps(v_tab30, _mm_cmpeq_ps(v_sector0, _mm_set1_ps(4.0f))));
+        v_v1 = _mm_or_ps(v_v1, _mm_and_ps(v_tab31, _mm_cmpeq_ps(v_sector1, _mm_set1_ps(4.0f))));
+        v_v0 = _mm_or_ps(v_v0, _mm_and_ps(v_tab00, _mm_cmpgt_ps(v_sector0, _mm_set1_ps(4.0f))));
+        v_v1 = _mm_or_ps(v_v1, _mm_and_ps(v_tab01, _mm_cmpgt_ps(v_sector1, _mm_set1_ps(4.0f))));
+    }
+    #endif
 
     void operator()(const float* src, float* dst, int n) const
     {
-        int i, bidx = blueIdx, dcn = dstcn;
+        int i = 0, bidx = blueIdx, dcn = dstcn;
         float _hscale = hscale;
         float alpha = ColorChannel<float>::max();
         n *= 3;
 
-        for( i = 0; i < n; i += 3, dst += dcn )
+        #if CV_SSE2
+        if (haveSIMD)
+        {
+            for( ; i <= n - 24; i += 24, dst += dcn * 8 )
+            {
+                __m128 v_h0 = _mm_loadu_ps(src + i +  0);
+                __m128 v_h1 = _mm_loadu_ps(src + i +  4);
+                __m128 v_s0 = _mm_loadu_ps(src + i +  8);
+                __m128 v_s1 = _mm_loadu_ps(src + i + 12);
+                __m128 v_v0 = _mm_loadu_ps(src + i + 16);
+                __m128 v_v1 = _mm_loadu_ps(src + i + 20);
+
+                _mm_deinterleave_ps(v_h0, v_h1, v_s0, v_s1, v_v0, v_v1);
+
+                process(v_h0, v_h1, v_s0, v_s1, v_v0, v_v1);
+
+                if (dcn == 3)
+                {
+                    if (bidx)
+                    {
+                        _mm_interleave_ps(v_v0, v_v1, v_s0, v_s1, v_h0, v_h1);
+
+                        _mm_storeu_ps(dst +  0, v_v0);
+                        _mm_storeu_ps(dst +  4, v_v1);
+                        _mm_storeu_ps(dst +  8, v_s0);
+                        _mm_storeu_ps(dst + 12, v_s1);
+                        _mm_storeu_ps(dst + 16, v_h0);
+                        _mm_storeu_ps(dst + 20, v_h1);
+                    }
+                    else
+                    {
+                        _mm_interleave_ps(v_h0, v_h1, v_s0, v_s1, v_v0, v_v1);
+
+                        _mm_storeu_ps(dst +  0, v_h0);
+                        _mm_storeu_ps(dst +  4, v_h1);
+                        _mm_storeu_ps(dst +  8, v_s0);
+                        _mm_storeu_ps(dst + 12, v_s1);
+                        _mm_storeu_ps(dst + 16, v_v0);
+                        _mm_storeu_ps(dst + 20, v_v1);
+                    }
+                }
+                else
+                {
+                    __m128 v_a0 = _mm_set1_ps(alpha);
+                    __m128 v_a1 = _mm_set1_ps(alpha);
+                    if (bidx)
+                    {
+                        _mm_interleave_ps(v_v0, v_v1, v_s0, v_s1, v_h0, v_h1, v_a0, v_a1);
+
+                        _mm_storeu_ps(dst +  0, v_v0);
+                        _mm_storeu_ps(dst +  4, v_v1);
+                        _mm_storeu_ps(dst +  8, v_s0);
+                        _mm_storeu_ps(dst + 12, v_s1);
+                        _mm_storeu_ps(dst + 16, v_h0);
+                        _mm_storeu_ps(dst + 20, v_h1);
+                        _mm_storeu_ps(dst + 24, v_a0);
+                        _mm_storeu_ps(dst + 28, v_a1);
+                    }
+                    else
+                    {
+                        _mm_interleave_ps(v_h0, v_h1, v_s0, v_s1, v_v0, v_v1, v_a0, v_a1);
+
+                        _mm_storeu_ps(dst +  0, v_h0);
+                        _mm_storeu_ps(dst +  4, v_h1);
+                        _mm_storeu_ps(dst +  8, v_s0);
+                        _mm_storeu_ps(dst + 12, v_s1);
+                        _mm_storeu_ps(dst + 16, v_v0);
+                        _mm_storeu_ps(dst + 20, v_v1);
+                        _mm_storeu_ps(dst + 24, v_a0);
+                        _mm_storeu_ps(dst + 28, v_a1);
+                    }
+                }
+            }
+        }
+        #endif
+        for( ; i < n; i += 3, dst += dcn )
         {
             float h = src[i], s = src[i+1], v = src[i+2];
             float b, g, r;
@@ -4295,6 +4760,9 @@ struct HSV2RGB_f
 
     int dstcn, blueIdx;
     float hscale;
+    #if CV_SSE2
+    bool haveSIMD;
+    #endif
 };
 
 
@@ -4310,16 +4778,16 @@ struct HSV2RGB_b
         v_scale = vdupq_n_f32(255.f);
         v_alpha = vdup_n_u8(ColorChannel<uchar>::max());
         #elif CV_SSE2
-        v_scale_inv = _mm_set1_ps(1.f/255.f);
         v_scale = _mm_set1_ps(255.0f);
+        v_alpha = _mm_set1_ps(ColorChannel<uchar>::max());
         v_zero = _mm_setzero_si128();
         haveSIMD = checkHardwareSupport(CV_CPU_SSE2);
         #endif
     }
 
     #if CV_SSE2
-    // 16s x 8
     void process(__m128i v_r, __m128i v_g, __m128i v_b,
+                 const __m128& v_coeffs_,
                  float * buf) const
     {
         __m128 v_r0 = _mm_cvtepi32_ps(_mm_unpacklo_epi16(v_r, v_zero));
@@ -4330,13 +4798,20 @@ struct HSV2RGB_b
         __m128 v_g1 = _mm_cvtepi32_ps(_mm_unpackhi_epi16(v_g, v_zero));
         __m128 v_b1 = _mm_cvtepi32_ps(_mm_unpackhi_epi16(v_b, v_zero));
 
-        v_g0 = _mm_mul_ps(v_g0, v_scale_inv);
-        v_b0 = _mm_mul_ps(v_b0, v_scale_inv);
+        __m128 v_coeffs = v_coeffs_;
+
+        v_r0 = _mm_mul_ps(v_r0, v_coeffs);
+        v_g1 = _mm_mul_ps(v_g1, v_coeffs);
+
+        v_coeffs = _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(v_coeffs), 0x49));
+
+        v_r1 = _mm_mul_ps(v_r1, v_coeffs);
+        v_b0 = _mm_mul_ps(v_b0, v_coeffs);
 
-        v_g1 = _mm_mul_ps(v_g1, v_scale_inv);
-        v_b1 = _mm_mul_ps(v_b1, v_scale_inv);
+        v_coeffs = _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(v_coeffs), 0x49));
 
-        _mm_interleave_ps(v_r0, v_r1, v_g0, v_g1, v_b0, v_b1);
+        v_g0 = _mm_mul_ps(v_g0, v_coeffs);
+        v_b1 = _mm_mul_ps(v_b1, v_coeffs);
 
         _mm_store_ps(buf, v_r0);
         _mm_store_ps(buf + 4, v_r1);
@@ -4352,6 +4827,9 @@ struct HSV2RGB_b
         int i, j, dcn = dstcn;
         uchar alpha = ColorChannel<uchar>::max();
         float CV_DECL_ALIGNED(16) buf[3*BLOCK_SIZE];
+        #if CV_SSE2
+        __m128 v_coeffs = _mm_set_ps(1.f, 1.f/255.f, 1.f/255.f, 1.f);
+        #endif
 
         for( i = 0; i < n; i += BLOCK_SIZE, src += BLOCK_SIZE*3 )
         {
@@ -4380,36 +4858,16 @@ struct HSV2RGB_b
             #elif CV_SSE2
             if (haveSIMD)
             {
-                for ( ; j <= (dn - 32) * 3; j += 96)
+                for ( ; j <= (dn - 8) * 3; j += 24)
                 {
-                    __m128i v_r0 = _mm_loadu_si128((__m128i const *)(src + j));
-                    __m128i v_r1 = _mm_loadu_si128((__m128i const *)(src + j + 16));
-                    __m128i v_g0 = _mm_loadu_si128((__m128i const *)(src + j + 32));
-                    __m128i v_g1 = _mm_loadu_si128((__m128i const *)(src + j + 48));
-                    __m128i v_b0 = _mm_loadu_si128((__m128i const *)(src + j + 64));
-                    __m128i v_b1 = _mm_loadu_si128((__m128i const *)(src + j + 80));
-
-                    _mm_deinterleave_epi8(v_r0, v_r1, v_g0, v_g1, v_b0, v_b1);
-
-                    process(_mm_unpacklo_epi8(v_r0, v_zero),
-                            _mm_unpacklo_epi8(v_g0, v_zero),
-                            _mm_unpacklo_epi8(v_b0, v_zero),
-                            buf + j);
-
-                    process(_mm_unpackhi_epi8(v_r0, v_zero),
-                            _mm_unpackhi_epi8(v_g0, v_zero),
-                            _mm_unpackhi_epi8(v_b0, v_zero),
-                            buf + j + 24);
-
-                    process(_mm_unpacklo_epi8(v_r1, v_zero),
-                            _mm_unpacklo_epi8(v_g1, v_zero),
-                            _mm_unpacklo_epi8(v_b1, v_zero),
-                            buf + j + 48);
+                    __m128i v_src0 = _mm_loadu_si128((__m128i const *)(src + j));
+                    __m128i v_src1 = _mm_loadl_epi64((__m128i const *)(src + j + 16));
 
-                    process(_mm_unpackhi_epi8(v_r1, v_zero),
-                            _mm_unpackhi_epi8(v_g1, v_zero),
-                            _mm_unpackhi_epi8(v_b1, v_zero),
-                            buf + j + 72);
+                    process(_mm_unpacklo_epi8(v_src0, v_zero),
+                            _mm_unpackhi_epi8(v_src0, v_zero),
+                            _mm_unpacklo_epi8(v_src1, v_zero),
+                            v_coeffs,
+                            buf + j);
                 }
             }
             #endif
@@ -4474,6 +4932,32 @@ struct HSV2RGB_b
                 if (jr)
                     dst -= jr, j -= jr;
             }
+            else if (dcn == 4 && haveSIMD)
+            {
+                for ( ; j <= (dn * 3 - 12); j += 12, dst += 16)
+                {
+                    __m128 v_buf0 = _mm_mul_ps(_mm_load_ps(buf + j), v_scale);
+                    __m128 v_buf1 = _mm_mul_ps(_mm_load_ps(buf + j + 4), v_scale);
+                    __m128 v_buf2 = _mm_mul_ps(_mm_load_ps(buf + j + 8), v_scale);
+
+                    __m128 v_ba0 = _mm_unpackhi_ps(v_buf0, v_alpha);
+                    __m128 v_ba1 = _mm_unpacklo_ps(v_buf2, v_alpha);
+
+                    __m128i v_src0 = _mm_cvtps_epi32(_mm_shuffle_ps(v_buf0, v_ba0, 0x44));
+                    __m128i v_src1 = _mm_shuffle_epi32(_mm_cvtps_epi32(_mm_shuffle_ps(v_ba0, v_buf1, 0x4e)), 0x78);
+                    __m128i v_src2 = _mm_cvtps_epi32(_mm_shuffle_ps(v_buf1, v_ba1, 0x4e));
+                    __m128i v_src3 = _mm_shuffle_epi32(_mm_cvtps_epi32(_mm_shuffle_ps(v_ba1, v_buf2, 0xee)), 0x78);
+
+                    __m128i v_dst0 = _mm_packs_epi32(v_src0, v_src1);
+                    __m128i v_dst1 = _mm_packs_epi32(v_src2, v_src3);
+
+                    _mm_storeu_si128((__m128i *)dst, _mm_packus_epi16(v_dst0, v_dst1));
+                }
+
+                int jr = j % 3;
+                if (jr)
+                    dst -= jr, j -= jr;
+            }
             #endif
 
             for( ; j < dn*3; j += 3, dst += dcn )
@@ -4493,7 +4977,8 @@ struct HSV2RGB_b
     float32x4_t v_scale, v_scale_inv;
     uint8x8_t v_alpha;
     #elif CV_SSE2
-    __m128 v_scale_inv, v_scale;
+    __m128 v_scale;
+    __m128 v_alpha;
     __m128i v_zero;
     bool haveSIMD;
     #endif
@@ -4507,15 +4992,119 @@ struct RGB2HLS_f
     typedef float channel_type;
 
     RGB2HLS_f(int _srccn, int _blueIdx, float _hrange)
-    : srccn(_srccn), blueIdx(_blueIdx), hrange(_hrange) {}
+    : srccn(_srccn), blueIdx(_blueIdx), hscale(_hrange/360.f) {
+        #if CV_SSE2
+        haveSIMD = checkHardwareSupport(CV_CPU_SSE2);
+        #endif
+    }
+
+    #if CV_SSE2
+    void process(__m128& v_b0, __m128& v_b1, __m128& v_g0,
+                 __m128& v_g1, __m128& v_r0, __m128& v_r1) const
+    {
+        __m128 v_max0 = _mm_max_ps(_mm_max_ps(v_b0, v_g0), v_r0);
+        __m128 v_max1 = _mm_max_ps(_mm_max_ps(v_b1, v_g1), v_r1);
+        __m128 v_min0 = _mm_min_ps(_mm_min_ps(v_b0, v_g0), v_r0);
+        __m128 v_min1 = _mm_min_ps(_mm_min_ps(v_b1, v_g1), v_r1);
+        __m128 v_diff0 = _mm_sub_ps(v_max0, v_min0);
+        __m128 v_diff1 = _mm_sub_ps(v_max1, v_min1);
+        __m128 v_sum0 = _mm_add_ps(v_max0, v_min0);
+        __m128 v_sum1 = _mm_add_ps(v_max1, v_min1);
+        __m128 v_l0 = _mm_mul_ps(v_sum0, _mm_set1_ps(0.5f));
+        __m128 v_l1 = _mm_mul_ps(v_sum1, _mm_set1_ps(0.5f));
+
+        __m128 v_gel0 = _mm_cmpge_ps(v_l0, _mm_set1_ps(0.5f));
+        __m128 v_gel1 = _mm_cmpge_ps(v_l1, _mm_set1_ps(0.5f));
+        __m128 v_s0 = _mm_and_ps(v_gel0, _mm_sub_ps(_mm_set1_ps(2.0f), v_sum0));
+        __m128 v_s1 = _mm_and_ps(v_gel1, _mm_sub_ps(_mm_set1_ps(2.0f), v_sum1));
+        v_s0 = _mm_or_ps(v_s0, _mm_andnot_ps(v_gel0, v_sum0));
+        v_s1 = _mm_or_ps(v_s1, _mm_andnot_ps(v_gel1, v_sum1));
+        v_s0 = _mm_div_ps(v_diff0, v_s0);
+        v_s1 = _mm_div_ps(v_diff1, v_s1);
+
+        __m128 v_gteps0 = _mm_cmpgt_ps(v_diff0, _mm_set1_ps(FLT_EPSILON));
+        __m128 v_gteps1 = _mm_cmpgt_ps(v_diff1, _mm_set1_ps(FLT_EPSILON));
+
+        v_diff0 = _mm_div_ps(_mm_set1_ps(60.f), v_diff0);
+        v_diff1 = _mm_div_ps(_mm_set1_ps(60.f), v_diff1);
+
+        __m128 v_eqr0 = _mm_cmpeq_ps(v_max0, v_r0);
+        __m128 v_eqr1 = _mm_cmpeq_ps(v_max1, v_r1);
+        __m128 v_h0 = _mm_and_ps(v_eqr0, _mm_mul_ps(_mm_sub_ps(v_g0, v_b0), v_diff0));
+        __m128 v_h1 = _mm_and_ps(v_eqr1, _mm_mul_ps(_mm_sub_ps(v_g1, v_b1), v_diff1));
+        __m128 v_eqg0 = _mm_cmpeq_ps(v_max0, v_g0);
+        __m128 v_eqg1 = _mm_cmpeq_ps(v_max1, v_g1);
+        v_h0 = _mm_or_ps(v_h0, _mm_and_ps(_mm_andnot_ps(v_eqr0, v_eqg0), _mm_add_ps(_mm_mul_ps(_mm_sub_ps(v_b0, v_r0), v_diff0), _mm_set1_ps(120.f))));
+        v_h1 = _mm_or_ps(v_h1, _mm_and_ps(_mm_andnot_ps(v_eqr1, v_eqg1), _mm_add_ps(_mm_mul_ps(_mm_sub_ps(v_b1, v_r1), v_diff1), _mm_set1_ps(120.f))));
+        v_h0 = _mm_or_ps(v_h0, _mm_andnot_ps(_mm_or_ps(v_eqr0, v_eqg0), _mm_add_ps(_mm_mul_ps(_mm_sub_ps(v_r0, v_g0), v_diff0), _mm_set1_ps(240.f))));
+        v_h1 = _mm_or_ps(v_h1, _mm_andnot_ps(_mm_or_ps(v_eqr1, v_eqg1), _mm_add_ps(_mm_mul_ps(_mm_sub_ps(v_r1, v_g1), v_diff1), _mm_set1_ps(240.f))));
+        v_h0 = _mm_add_ps(v_h0, _mm_and_ps(_mm_cmplt_ps(v_h0, _mm_setzero_ps()), _mm_set1_ps(360.f)));
+        v_h1 = _mm_add_ps(v_h1, _mm_and_ps(_mm_cmplt_ps(v_h1, _mm_setzero_ps()), _mm_set1_ps(360.f)));
+        v_h0 = _mm_mul_ps(v_h0, _mm_set1_ps(hscale));
+        v_h1 = _mm_mul_ps(v_h1, _mm_set1_ps(hscale));
+
+        v_b0 = _mm_and_ps(v_gteps0, v_h0);
+        v_b1 = _mm_and_ps(v_gteps1, v_h1);
+        v_g0 = v_l0;
+        v_g1 = v_l1;
+        v_r0 = _mm_and_ps(v_gteps0, v_s0);
+        v_r1 = _mm_and_ps(v_gteps1, v_s1);
+    }
+    #endif
 
     void operator()(const float* src, float* dst, int n) const
     {
-        int i, bidx = blueIdx, scn = srccn;
-        float hscale = hrange*(1.f/360.f);
+        int i = 0, bidx = blueIdx, scn = srccn;
         n *= 3;
 
-        for( i = 0; i < n; i += 3, src += scn )
+        #if CV_SSE2
+        if (haveSIMD)
+        {
+            for( ; i <= n - 24; i += 24, src += scn * 8 )
+            {
+                __m128 v_b0 = _mm_loadu_ps(src +  0);
+                __m128 v_b1 = _mm_loadu_ps(src +  4);
+                __m128 v_g0 = _mm_loadu_ps(src +  8);
+                __m128 v_g1 = _mm_loadu_ps(src + 12);
+                __m128 v_r0 = _mm_loadu_ps(src + 16);
+                __m128 v_r1 = _mm_loadu_ps(src + 20);
+
+                if (scn == 3)
+                {
+                    _mm_deinterleave_ps(v_b0, v_b1, v_g0, v_g1, v_r0, v_r1);
+                }
+                else
+                {
+                    __m128 v_a0 = _mm_loadu_ps(src + 24);
+                    __m128 v_a1 = _mm_loadu_ps(src + 28);
+                    _mm_deinterleave_ps(v_b0, v_b1, v_g0, v_g1, v_r0, v_r1, v_a0, v_a1);
+                }
+
+                if (bidx)
+                {
+                    __m128 v_tmp0 = v_b0;
+                    __m128 v_tmp1 = v_b1;
+                    v_b0 = v_r0;
+                    v_b1 = v_r1;
+                    v_r0 = v_tmp0;
+                    v_r1 = v_tmp1;
+                }
+
+                process(v_b0, v_b1, v_g0, v_g1, v_r0, v_r1);
+
+                _mm_interleave_ps(v_b0, v_b1, v_g0, v_g1, v_r0, v_r1);
+
+                _mm_storeu_ps(dst + i +  0, v_b0);
+                _mm_storeu_ps(dst + i +  4, v_b1);
+                _mm_storeu_ps(dst + i +  8, v_g0);
+                _mm_storeu_ps(dst + i + 12, v_g1);
+                _mm_storeu_ps(dst + i + 16, v_r0);
+                _mm_storeu_ps(dst + i + 20, v_r1);
+            }
+        }
+        #endif
+
+        for( ; i < n; i += 3, src += scn )
         {
             float b = src[bidx], g = src[1], r = src[bidx^2];
             float h = 0.f, s = 0.f, l;
@@ -4552,7 +5141,10 @@ struct RGB2HLS_f
     }
 
     int srccn, blueIdx;
-    float hrange;
+    float hscale;
+    #if CV_SSE2
+    bool haveSIMD;
+    #endif
 };
 
 
@@ -4569,7 +5161,6 @@ struct RGB2HLS_b
         v_alpha = vdup_n_u8(ColorChannel<uchar>::max());
         #elif CV_SSE2
         v_scale_inv = _mm_set1_ps(1.f/255.f);
-        v_scale = _mm_set1_ps(255.f);
         v_zero = _mm_setzero_si128();
         haveSIMD = checkHardwareSupport(CV_CPU_SSE2);
         #endif
@@ -4577,25 +5168,25 @@ struct RGB2HLS_b
 
     #if CV_SSE2
     void process(const float * buf,
-                 __m128i & v_h, __m128i & v_l, __m128i & v_s) const
+                 __m128 & v_coeffs, uchar * dst) const
     {
-        __m128 v_h0f = _mm_load_ps(buf);
-        __m128 v_h1f = _mm_load_ps(buf + 4);
-        __m128 v_l0f = _mm_load_ps(buf + 8);
-        __m128 v_l1f = _mm_load_ps(buf + 12);
-        __m128 v_s0f = _mm_load_ps(buf + 16);
-        __m128 v_s1f = _mm_load_ps(buf + 20);
+        __m128 v_l0f = _mm_load_ps(buf);
+        __m128 v_l1f = _mm_load_ps(buf + 4);
+        __m128 v_u0f = _mm_load_ps(buf + 8);
+        __m128 v_u1f = _mm_load_ps(buf + 12);
 
-        _mm_deinterleave_ps(v_h0f, v_h1f, v_l0f, v_l1f, v_s0f, v_s1f);
+        v_l0f = _mm_mul_ps(v_l0f, v_coeffs);
+        v_u1f = _mm_mul_ps(v_u1f, v_coeffs);
+        v_coeffs = _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(v_coeffs), 0x92));
+        v_u0f = _mm_mul_ps(v_u0f, v_coeffs);
+        v_coeffs = _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(v_coeffs), 0x92));
+        v_l1f = _mm_mul_ps(v_l1f, v_coeffs);
 
-        v_l0f = _mm_mul_ps(v_l0f, v_scale);
-        v_l1f = _mm_mul_ps(v_l1f, v_scale);
-        v_s0f = _mm_mul_ps(v_s0f, v_scale);
-        v_s1f = _mm_mul_ps(v_s1f, v_scale);
+        __m128i v_l = _mm_packs_epi32(_mm_cvtps_epi32(v_l0f), _mm_cvtps_epi32(v_l1f));
+        __m128i v_u = _mm_packs_epi32(_mm_cvtps_epi32(v_u0f), _mm_cvtps_epi32(v_u1f));
+        __m128i v_l0 = _mm_packus_epi16(v_l, v_u);
 
-        v_h = _mm_packs_epi32(_mm_cvtps_epi32(v_h0f), _mm_cvtps_epi32(v_h1f));
-        v_l = _mm_packs_epi32(_mm_cvtps_epi32(v_l0f), _mm_cvtps_epi32(v_l1f));
-        v_s = _mm_packs_epi32(_mm_cvtps_epi32(v_s0f), _mm_cvtps_epi32(v_s1f));
+        _mm_storeu_si128((__m128i *)(dst), v_l0);
     }
     #endif
 
@@ -4603,6 +5194,9 @@ struct RGB2HLS_b
     {
         int i, j, scn = srccn;
         float CV_DECL_ALIGNED(16) buf[3*BLOCK_SIZE];
+        #if CV_SSE2
+        __m128 v_coeffs = _mm_set_ps(1.f, 255.f, 255.f, 1.f);
+        #endif
 
         for( i = 0; i < n; i += BLOCK_SIZE, dst += BLOCK_SIZE*3 )
         {
@@ -4660,6 +5254,26 @@ struct RGB2HLS_b
                 if (jr)
                     src -= jr, j -= jr;
             }
+            else if (scn == 4 && haveSIMD)
+            {
+                for ( ; j <= (dn * 3 - 12); j += 12, src += 16)
+                {
+                    __m128i v_src = _mm_loadu_si128((__m128i const *)src);
+
+                    __m128i v_src_lo = _mm_unpacklo_epi8(v_src, v_zero);
+                    __m128i v_src_hi = _mm_unpackhi_epi8(v_src, v_zero);
+                    _mm_storeu_ps(buf + j, _mm_mul_ps(_mm_cvtepi32_ps(_mm_unpacklo_epi16(v_src_lo, v_zero)), v_scale_inv));
+                    _mm_storeu_ps(buf + j + 3, _mm_mul_ps(_mm_cvtepi32_ps(_mm_unpackhi_epi16(v_src_lo, v_zero)), v_scale_inv));
+                    _mm_storeu_ps(buf + j + 6, _mm_mul_ps(_mm_cvtepi32_ps(_mm_unpacklo_epi16(v_src_hi, v_zero)), v_scale_inv));
+                    float tmp = buf[j + 8];
+                    _mm_storeu_ps(buf + j + 8, _mm_mul_ps(_mm_cvtepi32_ps(_mm_shuffle_epi32(_mm_unpackhi_epi16(v_src_hi, v_zero), 0x90)), v_scale_inv));
+                    buf[j + 8] = tmp;
+                }
+
+                int jr = j % 3;
+                if (jr)
+                    src -= jr, j -= jr;
+            }
             #endif
             for( ; j < dn*3; j += 3, src += scn )
             {
@@ -4687,38 +5301,16 @@ struct RGB2HLS_b
             #elif CV_SSE2
             if (haveSIMD)
             {
-                for ( ; j <= (dn - 32) * 3; j += 96)
+                for ( ; j <= (dn - 16) * 3; j += 48)
                 {
-                    __m128i v_h_0, v_l_0, v_s_0;
                     process(buf + j,
-                            v_h_0, v_l_0, v_s_0);
-
-                    __m128i v_h_1, v_l_1, v_s_1;
-                    process(buf + j + 24,
-                            v_h_1, v_l_1, v_s_1);
-
-                    __m128i v_h0 = _mm_packus_epi16(v_h_0, v_h_1);
-                    __m128i v_l0 = _mm_packus_epi16(v_l_0, v_l_1);
-                    __m128i v_s0 = _mm_packus_epi16(v_s_0, v_s_1);
+                            v_coeffs, dst + j);
 
-                    process(buf + j + 48,
-                            v_h_0, v_l_0, v_s_0);
+                    process(buf + j + 16,
+                            v_coeffs, dst + j + 16);
 
-                    process(buf + j + 72,
-                            v_h_1, v_l_1, v_s_1);
-
-                    __m128i v_h1 = _mm_packus_epi16(v_h_0, v_h_1);
-                    __m128i v_l1 = _mm_packus_epi16(v_l_0, v_l_1);
-                    __m128i v_s1 = _mm_packus_epi16(v_s_0, v_s_1);
-
-                    _mm_interleave_epi8(v_h0, v_h1, v_l0, v_l1, v_s0, v_s1);
-
-                    _mm_storeu_si128((__m128i *)(dst + j), v_h0);
-                    _mm_storeu_si128((__m128i *)(dst + j + 16), v_h1);
-                    _mm_storeu_si128((__m128i *)(dst + j + 32), v_l0);
-                    _mm_storeu_si128((__m128i *)(dst + j + 48), v_l1);
-                    _mm_storeu_si128((__m128i *)(dst + j + 64), v_s0);
-                    _mm_storeu_si128((__m128i *)(dst + j + 80), v_s1);
+                    process(buf + j + 32,
+                            v_coeffs, dst + j + 32);
                 }
             }
             #endif
@@ -4737,7 +5329,7 @@ struct RGB2HLS_b
     float32x4_t v_scale, v_scale_inv;
     uint8x8_t v_alpha;
     #elif CV_SSE2
-    __m128 v_scale, v_scale_inv;
+    __m128 v_scale_inv;
     __m128i v_zero;
     bool haveSIMD;
     #endif
@@ -4749,16 +5341,169 @@ struct HLS2RGB_f
     typedef float channel_type;
 
     HLS2RGB_f(int _dstcn, int _blueIdx, float _hrange)
-    : dstcn(_dstcn), blueIdx(_blueIdx), hscale(6.f/_hrange) {}
+    : dstcn(_dstcn), blueIdx(_blueIdx), hscale(6.f/_hrange) {
+        #if CV_SSE2
+        haveSIMD = checkHardwareSupport(CV_CPU_SSE2);
+        #endif
+    }
+
+    #if CV_SSE2
+    void process(__m128& v_h0, __m128& v_h1, __m128& v_l0,
+                 __m128& v_l1, __m128& v_s0, __m128& v_s1) const
+    {
+        __m128 v_lel0 = _mm_cmple_ps(v_l0, _mm_set1_ps(0.5f));
+        __m128 v_lel1 = _mm_cmple_ps(v_l1, _mm_set1_ps(0.5f));
+        __m128 v_p20 = _mm_andnot_ps(v_lel0, _mm_sub_ps(_mm_add_ps(v_l0, v_s0), _mm_mul_ps(v_l0, v_s0)));
+        __m128 v_p21 = _mm_andnot_ps(v_lel1, _mm_sub_ps(_mm_add_ps(v_l1, v_s1), _mm_mul_ps(v_l1, v_s1)));
+        v_p20 = _mm_or_ps(v_p20, _mm_and_ps(v_lel0, _mm_mul_ps(v_l0, _mm_add_ps(_mm_set1_ps(1.0f), v_s0))));
+        v_p21 = _mm_or_ps(v_p21, _mm_and_ps(v_lel1, _mm_mul_ps(v_l1, _mm_add_ps(_mm_set1_ps(1.0f), v_s1))));
+
+        __m128 v_p10 = _mm_sub_ps(_mm_mul_ps(_mm_set1_ps(2.0f), v_l0), v_p20);
+        __m128 v_p11 = _mm_sub_ps(_mm_mul_ps(_mm_set1_ps(2.0f), v_l1), v_p21);
+
+        v_h0 = _mm_mul_ps(v_h0, _mm_set1_ps(hscale));
+        v_h1 = _mm_mul_ps(v_h1, _mm_set1_ps(hscale));
+
+        __m128 v_pre_sector0 = _mm_cvtepi32_ps(_mm_cvttps_epi32(v_h0));
+        __m128 v_pre_sector1 = _mm_cvtepi32_ps(_mm_cvttps_epi32(v_h1));
+
+        v_h0 = _mm_sub_ps(v_h0, v_pre_sector0);
+        v_h1 = _mm_sub_ps(v_h1, v_pre_sector1);
+
+        __m128 v_p2_p10 = _mm_sub_ps(v_p20, v_p10);
+        __m128 v_p2_p11 = _mm_sub_ps(v_p21, v_p11);
+        __m128 v_tab20 = _mm_add_ps(v_p10, _mm_mul_ps(v_p2_p10, _mm_sub_ps(_mm_set1_ps(1.0f), v_h0)));
+        __m128 v_tab21 = _mm_add_ps(v_p11, _mm_mul_ps(v_p2_p11, _mm_sub_ps(_mm_set1_ps(1.0f), v_h1)));
+        __m128 v_tab30 = _mm_add_ps(v_p10, _mm_mul_ps(v_p2_p10, v_h0));
+        __m128 v_tab31 = _mm_add_ps(v_p11, _mm_mul_ps(v_p2_p11, v_h1));
+
+        __m128 v_sector0 = _mm_div_ps(v_pre_sector0, _mm_set1_ps(6.0f));
+        __m128 v_sector1 = _mm_div_ps(v_pre_sector1, _mm_set1_ps(6.0f));
+        v_sector0 = _mm_cvtepi32_ps(_mm_cvttps_epi32(v_sector0));
+        v_sector1 = _mm_cvtepi32_ps(_mm_cvttps_epi32(v_sector1));
+        v_sector0 = _mm_mul_ps(v_sector0, _mm_set1_ps(6.0f));
+        v_sector1 = _mm_mul_ps(v_sector1, _mm_set1_ps(6.0f));
+        v_sector0 = _mm_sub_ps(v_pre_sector0, v_sector0);
+        v_sector1 = _mm_sub_ps(v_pre_sector1, v_sector1);
+
+        v_h0 = _mm_and_ps(v_p10, _mm_cmplt_ps(v_sector0, _mm_set1_ps(2.0f)));
+        v_h1 = _mm_and_ps(v_p11, _mm_cmplt_ps(v_sector1, _mm_set1_ps(2.0f)));
+        v_h0 = _mm_or_ps(v_h0, _mm_and_ps(v_tab30, _mm_cmpeq_ps(v_sector0, _mm_set1_ps(2.0f))));
+        v_h1 = _mm_or_ps(v_h1, _mm_and_ps(v_tab31, _mm_cmpeq_ps(v_sector1, _mm_set1_ps(2.0f))));
+        v_h0 = _mm_or_ps(v_h0, _mm_and_ps(v_p20, _mm_cmpeq_ps(v_sector0, _mm_set1_ps(3.0f))));
+        v_h1 = _mm_or_ps(v_h1, _mm_and_ps(v_p21, _mm_cmpeq_ps(v_sector1, _mm_set1_ps(3.0f))));
+        v_h0 = _mm_or_ps(v_h0, _mm_and_ps(v_p20, _mm_cmpeq_ps(v_sector0, _mm_set1_ps(4.0f))));
+        v_h1 = _mm_or_ps(v_h1, _mm_and_ps(v_p21, _mm_cmpeq_ps(v_sector1, _mm_set1_ps(4.0f))));
+        v_h0 = _mm_or_ps(v_h0, _mm_and_ps(v_tab20, _mm_cmpgt_ps(v_sector0, _mm_set1_ps(4.0f))));
+        v_h1 = _mm_or_ps(v_h1, _mm_and_ps(v_tab21, _mm_cmpgt_ps(v_sector1, _mm_set1_ps(4.0f))));
+        v_l0 = _mm_and_ps(v_tab30, _mm_cmplt_ps(v_sector0, _mm_set1_ps(1.0f)));
+        v_l1 = _mm_and_ps(v_tab31, _mm_cmplt_ps(v_sector1, _mm_set1_ps(1.0f)));
+        v_l0 = _mm_or_ps(v_l0, _mm_and_ps(v_p20, _mm_cmpeq_ps(v_sector0, _mm_set1_ps(1.0f))));
+        v_l1 = _mm_or_ps(v_l1, _mm_and_ps(v_p21, _mm_cmpeq_ps(v_sector1, _mm_set1_ps(1.0f))));
+        v_l0 = _mm_or_ps(v_l0, _mm_and_ps(v_p20, _mm_cmpeq_ps(v_sector0, _mm_set1_ps(2.0f))));
+        v_l1 = _mm_or_ps(v_l1, _mm_and_ps(v_p21, _mm_cmpeq_ps(v_sector1, _mm_set1_ps(2.0f))));
+        v_l0 = _mm_or_ps(v_l0, _mm_and_ps(v_tab20, _mm_cmpeq_ps(v_sector0, _mm_set1_ps(3.0f))));
+        v_l1 = _mm_or_ps(v_l1, _mm_and_ps(v_tab21, _mm_cmpeq_ps(v_sector1, _mm_set1_ps(3.0f))));
+        v_l0 = _mm_or_ps(v_l0, _mm_and_ps(v_p10, _mm_cmpgt_ps(v_sector0, _mm_set1_ps(3.0f))));
+        v_l1 = _mm_or_ps(v_l1, _mm_and_ps(v_p11, _mm_cmpgt_ps(v_sector1, _mm_set1_ps(3.0f))));
+        v_s0 = _mm_and_ps(v_p20, _mm_cmplt_ps(v_sector0, _mm_set1_ps(1.0f)));
+        v_s1 = _mm_and_ps(v_p21, _mm_cmplt_ps(v_sector1, _mm_set1_ps(1.0f)));
+        v_s0 = _mm_or_ps(v_s0, _mm_and_ps(v_tab20, _mm_cmpeq_ps(v_sector0, _mm_set1_ps(1.0f))));
+        v_s1 = _mm_or_ps(v_s1, _mm_and_ps(v_tab21, _mm_cmpeq_ps(v_sector1, _mm_set1_ps(1.0f))));
+        v_s0 = _mm_or_ps(v_s0, _mm_and_ps(v_p10, _mm_cmpeq_ps(v_sector0, _mm_set1_ps(2.0f))));
+        v_s1 = _mm_or_ps(v_s1, _mm_and_ps(v_p11, _mm_cmpeq_ps(v_sector1, _mm_set1_ps(2.0f))));
+        v_s0 = _mm_or_ps(v_s0, _mm_and_ps(v_p10, _mm_cmpeq_ps(v_sector0, _mm_set1_ps(3.0f))));
+        v_s1 = _mm_or_ps(v_s1, _mm_and_ps(v_p11, _mm_cmpeq_ps(v_sector1, _mm_set1_ps(3.0f))));
+        v_s0 = _mm_or_ps(v_s0, _mm_and_ps(v_tab30, _mm_cmpeq_ps(v_sector0, _mm_set1_ps(4.0f))));
+        v_s1 = _mm_or_ps(v_s1, _mm_and_ps(v_tab31, _mm_cmpeq_ps(v_sector1, _mm_set1_ps(4.0f))));
+        v_s0 = _mm_or_ps(v_s0, _mm_and_ps(v_p20, _mm_cmpgt_ps(v_sector0, _mm_set1_ps(4.0f))));
+        v_s1 = _mm_or_ps(v_s1, _mm_and_ps(v_p21, _mm_cmpgt_ps(v_sector1, _mm_set1_ps(4.0f))));
+    }
+    #endif
 
     void operator()(const float* src, float* dst, int n) const
     {
-        int i, bidx = blueIdx, dcn = dstcn;
+        int i = 0, bidx = blueIdx, dcn = dstcn;
         float _hscale = hscale;
         float alpha = ColorChannel<float>::max();
         n *= 3;
 
-        for( i = 0; i < n; i += 3, dst += dcn )
+        #if CV_SSE2
+        if (haveSIMD)
+        {
+            for( ; i <= n - 24; i += 24, dst += dcn * 8 )
+            {
+                __m128 v_h0 = _mm_loadu_ps(src + i +  0);
+                __m128 v_h1 = _mm_loadu_ps(src + i +  4);
+                __m128 v_l0 = _mm_loadu_ps(src + i +  8);
+                __m128 v_l1 = _mm_loadu_ps(src + i + 12);
+                __m128 v_s0 = _mm_loadu_ps(src + i + 16);
+                __m128 v_s1 = _mm_loadu_ps(src + i + 20);
+
+                _mm_deinterleave_ps(v_h0, v_h1, v_l0, v_l1, v_s0, v_s1);
+
+                process(v_h0, v_h1, v_l0, v_l1, v_s0, v_s1);
+
+                if (dcn == 3)
+                {
+                    if (bidx)
+                    {
+                        _mm_interleave_ps(v_s0, v_s1, v_l0, v_l1, v_h0, v_h1);
+
+                        _mm_storeu_ps(dst +  0, v_s0);
+                        _mm_storeu_ps(dst +  4, v_s1);
+                        _mm_storeu_ps(dst +  8, v_l0);
+                        _mm_storeu_ps(dst + 12, v_l1);
+                        _mm_storeu_ps(dst + 16, v_h0);
+                        _mm_storeu_ps(dst + 20, v_h1);
+                    }
+                    else
+                    {
+                        _mm_interleave_ps(v_h0, v_h1, v_l0, v_l1, v_s0, v_s1);
+
+                        _mm_storeu_ps(dst +  0, v_h0);
+                        _mm_storeu_ps(dst +  4, v_h1);
+                        _mm_storeu_ps(dst +  8, v_l0);
+                        _mm_storeu_ps(dst + 12, v_l1);
+                        _mm_storeu_ps(dst + 16, v_s0);
+                        _mm_storeu_ps(dst + 20, v_s1);
+                    }
+                }
+                else
+                {
+                    __m128 v_a0 = _mm_set1_ps(alpha);
+                    __m128 v_a1 = _mm_set1_ps(alpha);
+                    if (bidx)
+                    {
+                        _mm_interleave_ps(v_s0, v_s1, v_l0, v_l1, v_h0, v_h1, v_a0, v_a1);
+
+                        _mm_storeu_ps(dst +  0, v_s0);
+                        _mm_storeu_ps(dst +  4, v_s1);
+                        _mm_storeu_ps(dst +  8, v_l0);
+                        _mm_storeu_ps(dst + 12, v_l1);
+                        _mm_storeu_ps(dst + 16, v_h0);
+                        _mm_storeu_ps(dst + 20, v_h1);
+                        _mm_storeu_ps(dst + 24, v_a0);
+                        _mm_storeu_ps(dst + 28, v_a1);
+                    }
+                    else
+                    {
+                        _mm_interleave_ps(v_h0, v_h1, v_l0, v_l1, v_s0, v_s1, v_a0, v_a1);
+
+                        _mm_storeu_ps(dst +  0, v_h0);
+                        _mm_storeu_ps(dst +  4, v_h1);
+                        _mm_storeu_ps(dst +  8, v_l0);
+                        _mm_storeu_ps(dst + 12, v_l1);
+                        _mm_storeu_ps(dst + 16, v_s0);
+                        _mm_storeu_ps(dst + 20, v_s1);
+                        _mm_storeu_ps(dst + 24, v_a0);
+                        _mm_storeu_ps(dst + 28, v_a1);
+                    }
+                }
+            }
+        }
+        #endif
+        for( ; i < n; i += 3, dst += dcn )
         {
             float h = src[i], l = src[i+1], s = src[i+2];
             float b, g, r;
@@ -4805,6 +5550,9 @@ struct HLS2RGB_f
 
     int dstcn, blueIdx;
     float hscale;
+    #if CV_SSE2
+    bool haveSIMD;
+    #endif
 };
 
 
@@ -4820,16 +5568,16 @@ struct HLS2RGB_b
         v_scale = vdupq_n_f32(255.f);
         v_alpha = vdup_n_u8(ColorChannel<uchar>::max());
         #elif CV_SSE2
-        v_scale_inv = _mm_set1_ps(1.f/255.f);
         v_scale = _mm_set1_ps(255.f);
+        v_alpha = _mm_set1_ps(ColorChannel<uchar>::max());
         v_zero = _mm_setzero_si128();
         haveSIMD = checkHardwareSupport(CV_CPU_SSE2);
         #endif
     }
 
     #if CV_SSE2
-    // 16s x 8
     void process(__m128i v_r, __m128i v_g, __m128i v_b,
+                 const __m128& v_coeffs_,
                  float * buf) const
     {
         __m128 v_r0 = _mm_cvtepi32_ps(_mm_unpacklo_epi16(v_r, v_zero));
@@ -4840,13 +5588,20 @@ struct HLS2RGB_b
         __m128 v_g1 = _mm_cvtepi32_ps(_mm_unpackhi_epi16(v_g, v_zero));
         __m128 v_b1 = _mm_cvtepi32_ps(_mm_unpackhi_epi16(v_b, v_zero));
 
-        v_g0 = _mm_mul_ps(v_g0, v_scale_inv);
-        v_b0 = _mm_mul_ps(v_b0, v_scale_inv);
+        __m128 v_coeffs = v_coeffs_;
+
+        v_r0 = _mm_mul_ps(v_r0, v_coeffs);
+        v_g1 = _mm_mul_ps(v_g1, v_coeffs);
+
+        v_coeffs = _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(v_coeffs), 0x49));
 
-        v_g1 = _mm_mul_ps(v_g1, v_scale_inv);
-        v_b1 = _mm_mul_ps(v_b1, v_scale_inv);
+        v_r1 = _mm_mul_ps(v_r1, v_coeffs);
+        v_b0 = _mm_mul_ps(v_b0, v_coeffs);
 
-        _mm_interleave_ps(v_r0, v_r1, v_g0, v_g1, v_b0, v_b1);
+        v_coeffs = _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(v_coeffs), 0x49));
+
+        v_g0 = _mm_mul_ps(v_g0, v_coeffs);
+        v_b1 = _mm_mul_ps(v_b1, v_coeffs);
 
         _mm_store_ps(buf, v_r0);
         _mm_store_ps(buf + 4, v_r1);
@@ -4862,6 +5617,9 @@ struct HLS2RGB_b
         int i, j, dcn = dstcn;
         uchar alpha = ColorChannel<uchar>::max();
         float CV_DECL_ALIGNED(16) buf[3*BLOCK_SIZE];
+        #if CV_SSE2
+        __m128 v_coeffs = _mm_set_ps(1.f, 1.f/255.f, 1.f/255.f, 1.f);
+        #endif
 
         for( i = 0; i < n; i += BLOCK_SIZE, src += BLOCK_SIZE*3 )
         {
@@ -4890,36 +5648,16 @@ struct HLS2RGB_b
             #elif CV_SSE2
             if (haveSIMD)
             {
-                for ( ; j <= (dn - 32) * 3; j += 96)
+                for ( ; j <= (dn - 8) * 3; j += 24)
                 {
-                    __m128i v_r0 = _mm_loadu_si128((__m128i const *)(src + j));
-                    __m128i v_r1 = _mm_loadu_si128((__m128i const *)(src + j + 16));
-                    __m128i v_g0 = _mm_loadu_si128((__m128i const *)(src + j + 32));
-                    __m128i v_g1 = _mm_loadu_si128((__m128i const *)(src + j + 48));
-                    __m128i v_b0 = _mm_loadu_si128((__m128i const *)(src + j + 64));
-                    __m128i v_b1 = _mm_loadu_si128((__m128i const *)(src + j + 80));
-
-                    _mm_deinterleave_epi8(v_r0, v_r1, v_g0, v_g1, v_b0, v_b1);
-
-                    process(_mm_unpacklo_epi8(v_r0, v_zero),
-                            _mm_unpacklo_epi8(v_g0, v_zero),
-                            _mm_unpacklo_epi8(v_b0, v_zero),
-                            buf + j);
-
-                    process(_mm_unpackhi_epi8(v_r0, v_zero),
-                            _mm_unpackhi_epi8(v_g0, v_zero),
-                            _mm_unpackhi_epi8(v_b0, v_zero),
-                            buf + j + 24);
+                    __m128i v_src0 = _mm_loadu_si128((__m128i const *)(src + j));
+                    __m128i v_src1 = _mm_loadl_epi64((__m128i const *)(src + j + 16));
 
-                    process(_mm_unpacklo_epi8(v_r1, v_zero),
-                            _mm_unpacklo_epi8(v_g1, v_zero),
-                            _mm_unpacklo_epi8(v_b1, v_zero),
-                            buf + j + 48);
-
-                    process(_mm_unpackhi_epi8(v_r1, v_zero),
-                            _mm_unpackhi_epi8(v_g1, v_zero),
-                            _mm_unpackhi_epi8(v_b1, v_zero),
-                            buf + j + 72);
+                    process(_mm_unpacklo_epi8(v_src0, v_zero),
+                            _mm_unpackhi_epi8(v_src0, v_zero),
+                            _mm_unpacklo_epi8(v_src1, v_zero),
+                            v_coeffs,
+                            buf + j);
                 }
             }
             #endif
@@ -4983,6 +5721,32 @@ struct HLS2RGB_b
                 if (jr)
                     dst -= jr, j -= jr;
             }
+            else if (dcn == 4 && haveSIMD)
+            {
+                for ( ; j <= (dn * 3 - 12); j += 12, dst += 16)
+                {
+                    __m128 v_buf0 = _mm_mul_ps(_mm_load_ps(buf + j), v_scale);
+                    __m128 v_buf1 = _mm_mul_ps(_mm_load_ps(buf + j + 4), v_scale);
+                    __m128 v_buf2 = _mm_mul_ps(_mm_load_ps(buf + j + 8), v_scale);
+
+                    __m128 v_ba0 = _mm_unpackhi_ps(v_buf0, v_alpha);
+                    __m128 v_ba1 = _mm_unpacklo_ps(v_buf2, v_alpha);
+
+                    __m128i v_src0 = _mm_cvtps_epi32(_mm_shuffle_ps(v_buf0, v_ba0, 0x44));
+                    __m128i v_src1 = _mm_shuffle_epi32(_mm_cvtps_epi32(_mm_shuffle_ps(v_ba0, v_buf1, 0x4e)), 0x78);
+                    __m128i v_src2 = _mm_cvtps_epi32(_mm_shuffle_ps(v_buf1, v_ba1, 0x4e));
+                    __m128i v_src3 = _mm_shuffle_epi32(_mm_cvtps_epi32(_mm_shuffle_ps(v_ba1, v_buf2, 0xee)), 0x78);
+
+                    __m128i v_dst0 = _mm_packs_epi32(v_src0, v_src1);
+                    __m128i v_dst1 = _mm_packs_epi32(v_src2, v_src3);
+
+                    _mm_storeu_si128((__m128i *)dst, _mm_packus_epi16(v_dst0, v_dst1));
+                }
+
+                int jr = j % 3;
+                if (jr)
+                    dst -= jr, j -= jr;
+            }
             #endif
 
             for( ; j < dn*3; j += 3, dst += dcn )
@@ -5002,7 +5766,8 @@ struct HLS2RGB_b
     float32x4_t v_scale, v_scale_inv;
     uint8x8_t v_alpha;
     #elif CV_SSE2
-    __m128 v_scale, v_scale_inv;
+    __m128 v_scale;
+    __m128 v_alpha;
     __m128i v_zero;
     bool haveSIMD;
     #endif
@@ -5237,11 +6002,106 @@ struct Lab2RGB_f
             coeffs[i+3] = _coeffs[i+3]*_whitept[i];
             coeffs[i+blueIdx*3] = _coeffs[i+6]*_whitept[i];
         }
+
+        lThresh = 0.008856f * 903.3f;
+        fThresh = 7.787f * 0.008856f + 16.0f / 116.0f;
+        #if CV_SSE2
+        haveSIMD = checkHardwareSupport(CV_CPU_SSE2);
+        #endif
+    }
+
+    #if CV_SSE2
+    void process(__m128& v_li0, __m128& v_li1, __m128& v_ai0,
+                 __m128& v_ai1, __m128& v_bi0, __m128& v_bi1) const
+    {
+        __m128 v_y00 = _mm_mul_ps(v_li0, _mm_set1_ps(1.0f/903.3f));
+        __m128 v_y01 = _mm_mul_ps(v_li1, _mm_set1_ps(1.0f/903.3f));
+        __m128 v_fy00 = _mm_add_ps(_mm_mul_ps(_mm_set1_ps(7.787f), v_y00), _mm_set1_ps(16.0f/116.0f));
+        __m128 v_fy01 = _mm_add_ps(_mm_mul_ps(_mm_set1_ps(7.787f), v_y01), _mm_set1_ps(16.0f/116.0f));
+
+        __m128 v_fy10 = _mm_mul_ps(_mm_add_ps(v_li0, _mm_set1_ps(16.0f)), _mm_set1_ps(1.0f/116.0f));
+        __m128 v_fy11 = _mm_mul_ps(_mm_add_ps(v_li1, _mm_set1_ps(16.0f)), _mm_set1_ps(1.0f/116.0f));
+        __m128 v_y10 = _mm_mul_ps(_mm_mul_ps(v_fy10, v_fy10), v_fy10);
+        __m128 v_y11 = _mm_mul_ps(_mm_mul_ps(v_fy11, v_fy11), v_fy11);
+
+        __m128 v_cmpli0 = _mm_cmple_ps(v_li0, _mm_set1_ps(lThresh));
+        __m128 v_cmpli1 = _mm_cmple_ps(v_li1, _mm_set1_ps(lThresh));
+        v_y00 = _mm_and_ps(v_cmpli0, v_y00);
+        v_y01 = _mm_and_ps(v_cmpli1, v_y01);
+        v_fy00 = _mm_and_ps(v_cmpli0, v_fy00);
+        v_fy01 = _mm_and_ps(v_cmpli1, v_fy01);
+        v_y10 = _mm_andnot_ps(v_cmpli0, v_y10);
+        v_y11 = _mm_andnot_ps(v_cmpli1, v_y11);
+        v_fy10 = _mm_andnot_ps(v_cmpli0, v_fy10);
+        v_fy11 = _mm_andnot_ps(v_cmpli1, v_fy11);
+        __m128 v_y0 = _mm_or_ps(v_y00, v_y10);
+        __m128 v_y1 = _mm_or_ps(v_y01, v_y11);
+        __m128 v_fy0 = _mm_or_ps(v_fy00, v_fy10);
+        __m128 v_fy1 = _mm_or_ps(v_fy01, v_fy11);
+
+        __m128 v_fxz00 = _mm_add_ps(v_fy0, _mm_mul_ps(v_ai0, _mm_set1_ps(0.002f)));
+        __m128 v_fxz01 = _mm_add_ps(v_fy1, _mm_mul_ps(v_ai1, _mm_set1_ps(0.002f)));
+        __m128 v_fxz10 = _mm_sub_ps(v_fy0, _mm_mul_ps(v_bi0, _mm_set1_ps(0.005f)));
+        __m128 v_fxz11 = _mm_sub_ps(v_fy1, _mm_mul_ps(v_bi1, _mm_set1_ps(0.005f)));
+
+        __m128 v_fxz000 = _mm_mul_ps(_mm_sub_ps(v_fxz00, _mm_set1_ps(16.0f/116.0f)), _mm_set1_ps(1.0f/7.787f));
+        __m128 v_fxz001 = _mm_mul_ps(_mm_sub_ps(v_fxz01, _mm_set1_ps(16.0f/116.0f)), _mm_set1_ps(1.0f/7.787f));
+        __m128 v_fxz010 = _mm_mul_ps(_mm_sub_ps(v_fxz10, _mm_set1_ps(16.0f/116.0f)), _mm_set1_ps(1.0f/7.787f));
+        __m128 v_fxz011 = _mm_mul_ps(_mm_sub_ps(v_fxz11, _mm_set1_ps(16.0f/116.0f)), _mm_set1_ps(1.0f/7.787f));
+
+        __m128 v_fxz100 = _mm_mul_ps(_mm_mul_ps(v_fxz00, v_fxz00), v_fxz00);
+        __m128 v_fxz101 = _mm_mul_ps(_mm_mul_ps(v_fxz01, v_fxz01), v_fxz01);
+        __m128 v_fxz110 = _mm_mul_ps(_mm_mul_ps(v_fxz10, v_fxz10), v_fxz10);
+        __m128 v_fxz111 = _mm_mul_ps(_mm_mul_ps(v_fxz11, v_fxz11), v_fxz11);
+
+        __m128 v_cmpfxz00 = _mm_cmple_ps(v_fxz00, _mm_set1_ps(fThresh));
+        __m128 v_cmpfxz01 = _mm_cmple_ps(v_fxz01, _mm_set1_ps(fThresh));
+        __m128 v_cmpfxz10 = _mm_cmple_ps(v_fxz10, _mm_set1_ps(fThresh));
+        __m128 v_cmpfxz11 = _mm_cmple_ps(v_fxz11, _mm_set1_ps(fThresh));
+        v_fxz000 = _mm_and_ps(v_cmpfxz00, v_fxz000);
+        v_fxz001 = _mm_and_ps(v_cmpfxz01, v_fxz001);
+        v_fxz010 = _mm_and_ps(v_cmpfxz10, v_fxz010);
+        v_fxz011 = _mm_and_ps(v_cmpfxz11, v_fxz011);
+        v_fxz100 = _mm_andnot_ps(v_cmpfxz00, v_fxz100);
+        v_fxz101 = _mm_andnot_ps(v_cmpfxz01, v_fxz101);
+        v_fxz110 = _mm_andnot_ps(v_cmpfxz10, v_fxz110);
+        v_fxz111 = _mm_andnot_ps(v_cmpfxz11, v_fxz111);
+        __m128 v_x0 = _mm_or_ps(v_fxz000, v_fxz100);
+        __m128 v_x1 = _mm_or_ps(v_fxz001, v_fxz101);
+        __m128 v_z0 = _mm_or_ps(v_fxz010, v_fxz110);
+        __m128 v_z1 = _mm_or_ps(v_fxz011, v_fxz111);
+
+        __m128 v_ro0 = _mm_mul_ps(_mm_set1_ps(coeffs[0]), v_x0);
+        __m128 v_ro1 = _mm_mul_ps(_mm_set1_ps(coeffs[0]), v_x1);
+        __m128 v_go0 = _mm_mul_ps(_mm_set1_ps(coeffs[3]), v_x0);
+        __m128 v_go1 = _mm_mul_ps(_mm_set1_ps(coeffs[3]), v_x1);
+        __m128 v_bo0 = _mm_mul_ps(_mm_set1_ps(coeffs[6]), v_x0);
+        __m128 v_bo1 = _mm_mul_ps(_mm_set1_ps(coeffs[6]), v_x1);
+        v_ro0 = _mm_add_ps(v_ro0, _mm_mul_ps(_mm_set1_ps(coeffs[1]), v_y0));
+        v_ro1 = _mm_add_ps(v_ro1, _mm_mul_ps(_mm_set1_ps(coeffs[1]), v_y1));
+        v_go0 = _mm_add_ps(v_go0, _mm_mul_ps(_mm_set1_ps(coeffs[4]), v_y0));
+        v_go1 = _mm_add_ps(v_go1, _mm_mul_ps(_mm_set1_ps(coeffs[4]), v_y1));
+        v_bo0 = _mm_add_ps(v_bo0, _mm_mul_ps(_mm_set1_ps(coeffs[7]), v_y0));
+        v_bo1 = _mm_add_ps(v_bo1, _mm_mul_ps(_mm_set1_ps(coeffs[7]), v_y1));
+        v_ro0 = _mm_add_ps(v_ro0, _mm_mul_ps(_mm_set1_ps(coeffs[2]), v_z0));
+        v_ro1 = _mm_add_ps(v_ro1, _mm_mul_ps(_mm_set1_ps(coeffs[2]), v_z1));
+        v_go0 = _mm_add_ps(v_go0, _mm_mul_ps(_mm_set1_ps(coeffs[5]), v_z0));
+        v_go1 = _mm_add_ps(v_go1, _mm_mul_ps(_mm_set1_ps(coeffs[5]), v_z1));
+        v_bo0 = _mm_add_ps(v_bo0, _mm_mul_ps(_mm_set1_ps(coeffs[8]), v_z0));
+        v_bo1 = _mm_add_ps(v_bo1, _mm_mul_ps(_mm_set1_ps(coeffs[8]), v_z1));
+
+        v_li0 = _mm_min_ps(_mm_max_ps(v_ro0, _mm_setzero_ps()), _mm_set1_ps(1.0f));
+        v_li1 = _mm_min_ps(_mm_max_ps(v_ro1, _mm_setzero_ps()), _mm_set1_ps(1.0f));
+        v_ai0 = _mm_min_ps(_mm_max_ps(v_go0, _mm_setzero_ps()), _mm_set1_ps(1.0f));
+        v_ai1 = _mm_min_ps(_mm_max_ps(v_go1, _mm_setzero_ps()), _mm_set1_ps(1.0f));
+        v_bi0 = _mm_min_ps(_mm_max_ps(v_bo0, _mm_setzero_ps()), _mm_set1_ps(1.0f));
+        v_bi1 = _mm_min_ps(_mm_max_ps(v_bo1, _mm_setzero_ps()), _mm_set1_ps(1.0f));
     }
+    #endif
 
     void operator()(const float* src, float* dst, int n) const
     {
-        int i, dcn = dstcn;
+        int i = 0, dcn = dstcn;
         const float* gammaTab = srgb ? sRGBInvGammaTab : 0;
         float gscale = GammaTabScale;
         float C0 = coeffs[0], C1 = coeffs[1], C2 = coeffs[2],
@@ -5250,9 +6110,70 @@ struct Lab2RGB_f
         float alpha = ColorChannel<float>::max();
         n *= 3;
 
-        static const float lThresh = 0.008856f * 903.3f;
-        static const float fThresh = 7.787f * 0.008856f + 16.0f / 116.0f;
-        for (i = 0; i < n; i += 3, dst += dcn)
+        #if CV_SSE2
+        if (haveSIMD)
+        {
+            for (; i <= n - 24; i += 24, dst += dcn * 8)
+            {
+                __m128 v_li0 = _mm_loadu_ps(src + i +  0);
+                __m128 v_li1 = _mm_loadu_ps(src + i +  4);
+                __m128 v_ai0 = _mm_loadu_ps(src + i +  8);
+                __m128 v_ai1 = _mm_loadu_ps(src + i + 12);
+                __m128 v_bi0 = _mm_loadu_ps(src + i + 16);
+                __m128 v_bi1 = _mm_loadu_ps(src + i + 20);
+
+                _mm_deinterleave_ps(v_li0, v_li1, v_ai0, v_ai1, v_bi0, v_bi1);
+
+                process(v_li0, v_li1, v_ai0, v_ai1, v_bi0, v_bi1);
+
+                if (gammaTab)
+                {
+                    __m128 v_gscale = _mm_set1_ps(gscale);
+                    v_li0 = _mm_mul_ps(v_li0, v_gscale);
+                    v_li1 = _mm_mul_ps(v_li1, v_gscale);
+                    v_ai0 = _mm_mul_ps(v_ai0, v_gscale);
+                    v_ai1 = _mm_mul_ps(v_ai1, v_gscale);
+                    v_bi0 = _mm_mul_ps(v_bi0, v_gscale);
+                    v_bi1 = _mm_mul_ps(v_bi1, v_gscale);
+
+                    splineInterpolate(v_li0, gammaTab, GAMMA_TAB_SIZE);
+                    splineInterpolate(v_li1, gammaTab, GAMMA_TAB_SIZE);
+                    splineInterpolate(v_ai0, gammaTab, GAMMA_TAB_SIZE);
+                    splineInterpolate(v_ai1, gammaTab, GAMMA_TAB_SIZE);
+                    splineInterpolate(v_bi0, gammaTab, GAMMA_TAB_SIZE);
+                    splineInterpolate(v_bi1, gammaTab, GAMMA_TAB_SIZE);
+                }
+
+                if( dcn == 4 )
+                {
+                    __m128 v_a0 = _mm_set1_ps(alpha);
+                    __m128 v_a1 = _mm_set1_ps(alpha);
+                    _mm_interleave_ps(v_li0, v_li1, v_ai0, v_ai1, v_bi0, v_bi1, v_a0, v_a1);
+
+                    _mm_storeu_ps(dst +  0, v_li0);
+                    _mm_storeu_ps(dst +  4, v_li1);
+                    _mm_storeu_ps(dst +  8, v_ai0);
+                    _mm_storeu_ps(dst + 12, v_ai1);
+                    _mm_storeu_ps(dst + 16, v_bi0);
+                    _mm_storeu_ps(dst + 20, v_bi1);
+                    _mm_storeu_ps(dst + 24, v_a0);
+                    _mm_storeu_ps(dst + 28, v_a1);
+                }
+                else
+                {
+                    _mm_interleave_ps(v_li0, v_li1, v_ai0, v_ai1, v_bi0, v_bi1);
+
+                    _mm_storeu_ps(dst +  0, v_li0);
+                    _mm_storeu_ps(dst +  4, v_li1);
+                    _mm_storeu_ps(dst +  8, v_ai0);
+                    _mm_storeu_ps(dst + 12, v_ai1);
+                    _mm_storeu_ps(dst + 16, v_bi0);
+                    _mm_storeu_ps(dst + 20, v_bi1);
+                }
+            }
+        }
+        #endif
+        for (; i < n; i += 3, dst += dcn)
         {
             float li = src[i];
             float ai = src[i + 1];
@@ -5303,6 +6224,11 @@ struct Lab2RGB_f
     int dstcn;
     float coeffs[9];
     bool srgb;
+    float lThresh;
+    float fThresh;
+    #if CV_SSE2
+    bool haveSIMD;
+    #endif
 };
 
 #undef clip
@@ -5321,9 +6247,8 @@ struct Lab2RGB_b
         v_alpha = vdup_n_u8(ColorChannel<uchar>::max());
         v_128 = vdupq_n_f32(128.0f);
         #elif CV_SSE2
-        v_scale_inv = _mm_set1_ps(100.f/255.f);
         v_scale = _mm_set1_ps(255.f);
-        v_128 = _mm_set1_ps(128.0f);
+        v_alpha = _mm_set1_ps(ColorChannel<uchar>::max());
         v_zero = _mm_setzero_si128();
         haveSIMD = checkHardwareSupport(CV_CPU_SSE2);
         #endif
@@ -5332,6 +6257,7 @@ struct Lab2RGB_b
     #if CV_SSE2
     // 16s x 8
     void process(__m128i v_r, __m128i v_g, __m128i v_b,
+                 const __m128& v_coeffs_, const __m128& v_res_,
                  float * buf) const
     {
         __m128 v_r0 = _mm_cvtepi32_ps(_mm_unpacklo_epi16(v_r, v_zero));
@@ -5342,15 +6268,23 @@ struct Lab2RGB_b
         __m128 v_g1 = _mm_cvtepi32_ps(_mm_unpackhi_epi16(v_g, v_zero));
         __m128 v_b1 = _mm_cvtepi32_ps(_mm_unpackhi_epi16(v_b, v_zero));
 
-        v_r0 = _mm_mul_ps(v_r0, v_scale_inv);
-        v_r1 = _mm_mul_ps(v_r1, v_scale_inv);
+        __m128 v_coeffs = v_coeffs_;
+        __m128 v_res = v_res_;
+
+        v_r0 = _mm_sub_ps(_mm_mul_ps(v_r0, v_coeffs), v_res);
+        v_g1 = _mm_sub_ps(_mm_mul_ps(v_g1, v_coeffs), v_res);
+
+        v_coeffs = _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(v_coeffs), 0x49));
+        v_res = _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(v_res), 0x49));
 
-        v_g0 = _mm_sub_ps(v_g0, v_128);
-        v_g1 = _mm_sub_ps(v_g1, v_128);
-        v_b0 = _mm_sub_ps(v_b0, v_128);
-        v_b1 = _mm_sub_ps(v_b1, v_128);
+        v_r1 = _mm_sub_ps(_mm_mul_ps(v_r1, v_coeffs), v_res);
+        v_b0 = _mm_sub_ps(_mm_mul_ps(v_b0, v_coeffs), v_res);
 
-        _mm_interleave_ps(v_r0, v_r1, v_g0, v_g1, v_b0, v_b1);
+        v_coeffs = _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(v_coeffs), 0x49));
+        v_res = _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(v_res), 0x49));
+
+        v_g0 = _mm_sub_ps(_mm_mul_ps(v_g0, v_coeffs), v_res);
+        v_b1 = _mm_sub_ps(_mm_mul_ps(v_b1, v_coeffs), v_res);
 
         _mm_store_ps(buf, v_r0);
         _mm_store_ps(buf + 4, v_r1);
@@ -5366,6 +6300,10 @@ struct Lab2RGB_b
         int i, j, dcn = dstcn;
         uchar alpha = ColorChannel<uchar>::max();
         float CV_DECL_ALIGNED(16) buf[3*BLOCK_SIZE];
+        #if CV_SSE2
+        __m128 v_coeffs = _mm_set_ps(100.f/255.f, 1.f, 1.f, 100.f/255.f);
+        __m128 v_res = _mm_set_ps(0.f, 128.f, 128.f, 0.f);
+        #endif
 
         for( i = 0; i < n; i += BLOCK_SIZE, src += BLOCK_SIZE*3 )
         {
@@ -5394,36 +6332,16 @@ struct Lab2RGB_b
             #elif CV_SSE2
             if (haveSIMD)
             {
-                for ( ; j <= (dn - 32) * 3; j += 96)
+                for ( ; j <= (dn - 8) * 3; j += 24)
                 {
-                    __m128i v_r0 = _mm_loadu_si128((__m128i const *)(src + j));
-                    __m128i v_r1 = _mm_loadu_si128((__m128i const *)(src + j + 16));
-                    __m128i v_g0 = _mm_loadu_si128((__m128i const *)(src + j + 32));
-                    __m128i v_g1 = _mm_loadu_si128((__m128i const *)(src + j + 48));
-                    __m128i v_b0 = _mm_loadu_si128((__m128i const *)(src + j + 64));
-                    __m128i v_b1 = _mm_loadu_si128((__m128i const *)(src + j + 80));
-
-                    _mm_deinterleave_epi8(v_r0, v_r1, v_g0, v_g1, v_b0, v_b1);
-
-                    process(_mm_unpacklo_epi8(v_r0, v_zero),
-                            _mm_unpacklo_epi8(v_g0, v_zero),
-                            _mm_unpacklo_epi8(v_b0, v_zero),
-                            buf + j);
-
-                    process(_mm_unpackhi_epi8(v_r0, v_zero),
-                            _mm_unpackhi_epi8(v_g0, v_zero),
-                            _mm_unpackhi_epi8(v_b0, v_zero),
-                            buf + j + 24);
+                    __m128i v_src0 = _mm_loadu_si128((__m128i const *)(src + j));
+                    __m128i v_src1 = _mm_loadl_epi64((__m128i const *)(src + j + 16));
 
-                    process(_mm_unpacklo_epi8(v_r1, v_zero),
-                            _mm_unpacklo_epi8(v_g1, v_zero),
-                            _mm_unpacklo_epi8(v_b1, v_zero),
-                            buf + j + 48);
-
-                    process(_mm_unpackhi_epi8(v_r1, v_zero),
-                            _mm_unpackhi_epi8(v_g1, v_zero),
-                            _mm_unpackhi_epi8(v_b1, v_zero),
-                            buf + j + 72);
+                    process(_mm_unpacklo_epi8(v_src0, v_zero),
+                            _mm_unpackhi_epi8(v_src0, v_zero),
+                            _mm_unpacklo_epi8(v_src1, v_zero),
+                            v_coeffs, v_res,
+                            buf + j);
                 }
             }
             #endif
@@ -5488,6 +6406,32 @@ struct Lab2RGB_b
                 if (jr)
                     dst -= jr, j -= jr;
             }
+            else if (dcn == 4 && haveSIMD)
+            {
+                for ( ; j <= (dn * 3 - 12); j += 12, dst += 16)
+                {
+                    __m128 v_buf0 = _mm_mul_ps(_mm_load_ps(buf + j), v_scale);
+                    __m128 v_buf1 = _mm_mul_ps(_mm_load_ps(buf + j + 4), v_scale);
+                    __m128 v_buf2 = _mm_mul_ps(_mm_load_ps(buf + j + 8), v_scale);
+
+                    __m128 v_ba0 = _mm_unpackhi_ps(v_buf0, v_alpha);
+                    __m128 v_ba1 = _mm_unpacklo_ps(v_buf2, v_alpha);
+
+                    __m128i v_src0 = _mm_cvtps_epi32(_mm_shuffle_ps(v_buf0, v_ba0, 0x44));
+                    __m128i v_src1 = _mm_shuffle_epi32(_mm_cvtps_epi32(_mm_shuffle_ps(v_ba0, v_buf1, 0x4e)), 0x78);
+                    __m128i v_src2 = _mm_cvtps_epi32(_mm_shuffle_ps(v_buf1, v_ba1, 0x4e));
+                    __m128i v_src3 = _mm_shuffle_epi32(_mm_cvtps_epi32(_mm_shuffle_ps(v_ba1, v_buf2, 0xee)), 0x78);
+
+                    __m128i v_dst0 = _mm_packs_epi32(v_src0, v_src1);
+                    __m128i v_dst1 = _mm_packs_epi32(v_src2, v_src3);
+
+                    _mm_storeu_si128((__m128i *)dst, _mm_packus_epi16(v_dst0, v_dst1));
+                }
+
+                int jr = j % 3;
+                if (jr)
+                    dst -= jr, j -= jr;
+            }
             #endif
 
             for( ; j < dn*3; j += 3, dst += dcn )
@@ -5508,7 +6452,8 @@ struct Lab2RGB_b
     float32x4_t v_scale, v_scale_inv, v_128;
     uint8x8_t v_alpha;
     #elif CV_SSE2
-    __m128 v_scale, v_scale_inv, v_128;
+    __m128 v_scale;
+    __m128 v_alpha;
     __m128i v_zero;
     bool haveSIMD;
     #endif
@@ -5543,24 +6488,212 @@ struct RGB2Luv_f
         }
 
         float d = 1.f/(whitept[0] + whitept[1]*15 + whitept[2]*3);
-        un = 4*whitept[0]*d;
-        vn = 9*whitept[1]*d;
+        un = 4*whitept[0]*d*13;
+        vn = 9*whitept[1]*d*13;
+
+        #if CV_SSE2
+        haveSIMD = checkHardwareSupport(CV_CPU_SSE2);
+        #endif
 
         CV_Assert(whitept[1] == 1.f);
     }
 
+    #if CV_NEON
+    void process(float32x4x3_t& v_src) const
+    {
+        float32x4_t v_x = vmlaq_f32(vmlaq_f32(vmulq_f32(v_src.val[0], vdupq_n_f32(coeffs[0])), v_src.val[1], vdupq_n_f32(coeffs[1])), v_src.val[2], vdupq_n_f32(coeffs[2]));
+        float32x4_t v_y = vmlaq_f32(vmlaq_f32(vmulq_f32(v_src.val[0], vdupq_n_f32(coeffs[3])), v_src.val[1], vdupq_n_f32(coeffs[4])), v_src.val[2], vdupq_n_f32(coeffs[5]));
+        float32x4_t v_z = vmlaq_f32(vmlaq_f32(vmulq_f32(v_src.val[0], vdupq_n_f32(coeffs[6])), v_src.val[1], vdupq_n_f32(coeffs[7])), v_src.val[2], vdupq_n_f32(coeffs[8]));
+
+        v_src.val[0] = vmulq_f32(v_y, vdupq_n_f32(LabCbrtTabScale));
+        splineInterpolate(v_src.val[0], LabCbrtTab, LAB_CBRT_TAB_SIZE);
+
+        v_src.val[0] = vmlaq_f32(vdupq_n_f32(-16.f), v_src.val[0], vdupq_n_f32(116.f));
+
+        float32x4_t v_div = vmaxq_f32(vmlaq_f32(vmlaq_f32(v_x, vdupq_n_f32(15.f), v_y), vdupq_n_f32(3.f), v_z), vdupq_n_f32(FLT_EPSILON));
+        float32x4_t v_reciprocal = vrecpeq_f32(v_div);
+        v_reciprocal = vmulq_f32(vrecpsq_f32(v_div, v_reciprocal), v_reciprocal);
+        v_reciprocal = vmulq_f32(vrecpsq_f32(v_div, v_reciprocal), v_reciprocal);
+        float32x4_t v_d = vmulq_f32(vdupq_n_f32(52.f), v_reciprocal);
+
+        v_src.val[1] = vmulq_f32(v_src.val[0], vmlaq_f32(vdupq_n_f32(-un), v_x, v_d));
+        v_src.val[2] = vmulq_f32(v_src.val[0], vmlaq_f32(vdupq_n_f32(-vn), vmulq_f32(vdupq_n_f32(2.25f), v_y), v_d));
+    }
+    #elif CV_SSE2
+    void process(__m128& v_r0, __m128& v_r1, __m128& v_g0,
+                 __m128& v_g1, __m128& v_b0, __m128& v_b1) const
+    {
+        __m128 v_x0 = _mm_mul_ps(v_r0, _mm_set1_ps(coeffs[0]));
+        __m128 v_x1 = _mm_mul_ps(v_r1, _mm_set1_ps(coeffs[0]));
+        __m128 v_y0 = _mm_mul_ps(v_r0, _mm_set1_ps(coeffs[3]));
+        __m128 v_y1 = _mm_mul_ps(v_r1, _mm_set1_ps(coeffs[3]));
+        __m128 v_z0 = _mm_mul_ps(v_r0, _mm_set1_ps(coeffs[6]));
+        __m128 v_z1 = _mm_mul_ps(v_r1, _mm_set1_ps(coeffs[6]));
+
+        v_x0 = _mm_add_ps(v_x0, _mm_mul_ps(v_g0, _mm_set1_ps(coeffs[1])));
+        v_x1 = _mm_add_ps(v_x1, _mm_mul_ps(v_g1, _mm_set1_ps(coeffs[1])));
+        v_y0 = _mm_add_ps(v_y0, _mm_mul_ps(v_g0, _mm_set1_ps(coeffs[4])));
+        v_y1 = _mm_add_ps(v_y1, _mm_mul_ps(v_g1, _mm_set1_ps(coeffs[4])));
+        v_z0 = _mm_add_ps(v_z0, _mm_mul_ps(v_g0, _mm_set1_ps(coeffs[7])));
+        v_z1 = _mm_add_ps(v_z1, _mm_mul_ps(v_g1, _mm_set1_ps(coeffs[7])));
+
+        v_x0 = _mm_add_ps(v_x0, _mm_mul_ps(v_b0, _mm_set1_ps(coeffs[2])));
+        v_x1 = _mm_add_ps(v_x1, _mm_mul_ps(v_b1, _mm_set1_ps(coeffs[2])));
+        v_y0 = _mm_add_ps(v_y0, _mm_mul_ps(v_b0, _mm_set1_ps(coeffs[5])));
+        v_y1 = _mm_add_ps(v_y1, _mm_mul_ps(v_b1, _mm_set1_ps(coeffs[5])));
+        v_z0 = _mm_add_ps(v_z0, _mm_mul_ps(v_b0, _mm_set1_ps(coeffs[8])));
+        v_z1 = _mm_add_ps(v_z1, _mm_mul_ps(v_b1, _mm_set1_ps(coeffs[8])));
+
+        __m128 v_l0 = _mm_mul_ps(v_y0, _mm_set1_ps(LabCbrtTabScale));
+        __m128 v_l1 = _mm_mul_ps(v_y1, _mm_set1_ps(LabCbrtTabScale));
+        splineInterpolate(v_l0, LabCbrtTab, LAB_CBRT_TAB_SIZE);
+        splineInterpolate(v_l1, LabCbrtTab, LAB_CBRT_TAB_SIZE);
+
+        v_l0 = _mm_mul_ps(v_l0, _mm_set1_ps(116.0f));
+        v_l1 = _mm_mul_ps(v_l1, _mm_set1_ps(116.0f));
+        v_r0 = _mm_sub_ps(v_l0, _mm_set1_ps(16.0f));
+        v_r1 = _mm_sub_ps(v_l1, _mm_set1_ps(16.0f));
+
+        v_z0 = _mm_mul_ps(v_z0, _mm_set1_ps(3.0f));
+        v_z1 = _mm_mul_ps(v_z1, _mm_set1_ps(3.0f));
+        v_z0 = _mm_add_ps(v_z0, v_x0);
+        v_z1 = _mm_add_ps(v_z1, v_x1);
+        v_z0 = _mm_add_ps(v_z0, _mm_mul_ps(v_y0, _mm_set1_ps(15.0f)));
+        v_z1 = _mm_add_ps(v_z1, _mm_mul_ps(v_y1, _mm_set1_ps(15.0f)));
+        v_z0 = _mm_max_ps(v_z0, _mm_set1_ps(FLT_EPSILON));
+        v_z1 = _mm_max_ps(v_z1, _mm_set1_ps(FLT_EPSILON));
+        __m128 v_d0 = _mm_div_ps(_mm_set1_ps(52.0f), v_z0);
+        __m128 v_d1 = _mm_div_ps(_mm_set1_ps(52.0f), v_z1);
+
+        v_x0 = _mm_mul_ps(v_x0, v_d0);
+        v_x1 = _mm_mul_ps(v_x1, v_d1);
+        v_x0 = _mm_sub_ps(v_x0, _mm_set1_ps(un));
+        v_x1 = _mm_sub_ps(v_x1, _mm_set1_ps(un));
+        v_g0 = _mm_mul_ps(v_x0, v_r0);
+        v_g1 = _mm_mul_ps(v_x1, v_r1);
+
+        v_y0 = _mm_mul_ps(v_y0, v_d0);
+        v_y1 = _mm_mul_ps(v_y1, v_d1);
+        v_y0 = _mm_mul_ps(v_y0, _mm_set1_ps(2.25f));
+        v_y1 = _mm_mul_ps(v_y1, _mm_set1_ps(2.25f));
+        v_y0 = _mm_sub_ps(v_y0, _mm_set1_ps(vn));
+        v_y1 = _mm_sub_ps(v_y1, _mm_set1_ps(vn));
+        v_b0 = _mm_mul_ps(v_y0, v_r0);
+        v_b1 = _mm_mul_ps(v_y1, v_r1);
+    }
+    #endif
+
     void operator()(const float* src, float* dst, int n) const
     {
-        int i, scn = srccn;
+        int i = 0, scn = srccn;
         float gscale = GammaTabScale;
         const float* gammaTab = srgb ? sRGBGammaTab : 0;
         float C0 = coeffs[0], C1 = coeffs[1], C2 = coeffs[2],
               C3 = coeffs[3], C4 = coeffs[4], C5 = coeffs[5],
               C6 = coeffs[6], C7 = coeffs[7], C8 = coeffs[8];
-        float _un = 13*un, _vn = 13*vn;
         n *= 3;
 
-        for( i = 0; i < n; i += 3, src += scn )
+        #if CV_NEON
+        if (scn == 3)
+        {
+            for( ; i <= n - 12; i += 12, src += scn * 4 )
+            {
+                float32x4x3_t v_src = vld3q_f32(src);
+                if( gammaTab )
+                {
+                    v_src.val[0] = vmulq_f32(v_src.val[0], vdupq_n_f32(gscale));
+                    v_src.val[1] = vmulq_f32(v_src.val[1], vdupq_n_f32(gscale));
+                    v_src.val[2] = vmulq_f32(v_src.val[2], vdupq_n_f32(gscale));
+                    splineInterpolate(v_src.val[0], gammaTab, GAMMA_TAB_SIZE);
+                    splineInterpolate(v_src.val[1], gammaTab, GAMMA_TAB_SIZE);
+                    splineInterpolate(v_src.val[2], gammaTab, GAMMA_TAB_SIZE);
+                }
+
+                process(v_src);
+
+                vst3q_f32(dst + i, v_src);
+            }
+        }
+        else
+        {
+            for( ; i <= n - 12; i += 12, src += scn * 4 )
+            {
+                float32x4x4_t v_src = vld4q_f32(src);
+                if( gammaTab )
+                {
+                    v_src.val[0] = vmulq_f32(v_src.val[0], vdupq_n_f32(gscale));
+                    v_src.val[1] = vmulq_f32(v_src.val[1], vdupq_n_f32(gscale));
+                    v_src.val[2] = vmulq_f32(v_src.val[2], vdupq_n_f32(gscale));
+                    splineInterpolate(v_src.val[0], gammaTab, GAMMA_TAB_SIZE);
+                    splineInterpolate(v_src.val[1], gammaTab, GAMMA_TAB_SIZE);
+                    splineInterpolate(v_src.val[2], gammaTab, GAMMA_TAB_SIZE);
+                }
+
+                float32x4x3_t v_dst;
+                v_dst.val[0] = v_src.val[0];
+                v_dst.val[1] = v_src.val[1];
+                v_dst.val[2] = v_src.val[2];
+                process(v_dst);
+
+                vst3q_f32(dst + i, v_dst);
+            }
+        }
+        #elif CV_SSE2
+        if (haveSIMD)
+        {
+            for( ; i <= n - 24; i += 24, src += scn * 8 )
+            {
+                __m128 v_r0 = _mm_loadu_ps(src +  0);
+                __m128 v_r1 = _mm_loadu_ps(src +  4);
+                __m128 v_g0 = _mm_loadu_ps(src +  8);
+                __m128 v_g1 = _mm_loadu_ps(src + 12);
+                __m128 v_b0 = _mm_loadu_ps(src + 16);
+                __m128 v_b1 = _mm_loadu_ps(src + 20);
+
+                if (scn == 3)
+                {
+                    _mm_deinterleave_ps(v_r0, v_r1, v_g0, v_g1, v_b0, v_b1);
+                }
+                else
+                {
+                    __m128 v_a0 = _mm_loadu_ps(src + 24);
+                    __m128 v_a1 = _mm_loadu_ps(src + 28);
+
+                    _mm_deinterleave_ps(v_r0, v_r1, v_g0, v_g1, v_b0, v_b1, v_a0, v_a1);
+                }
+
+                if ( gammaTab )
+                {
+                    __m128 v_gscale = _mm_set1_ps(gscale);
+                    v_r0 = _mm_mul_ps(v_r0, v_gscale);
+                    v_r1 = _mm_mul_ps(v_r1, v_gscale);
+                    v_g0 = _mm_mul_ps(v_g0, v_gscale);
+                    v_g1 = _mm_mul_ps(v_g1, v_gscale);
+                    v_b0 = _mm_mul_ps(v_b0, v_gscale);
+                    v_b1 = _mm_mul_ps(v_b1, v_gscale);
+
+                    splineInterpolate(v_r0, gammaTab, GAMMA_TAB_SIZE);
+                    splineInterpolate(v_r1, gammaTab, GAMMA_TAB_SIZE);
+                    splineInterpolate(v_g0, gammaTab, GAMMA_TAB_SIZE);
+                    splineInterpolate(v_g1, gammaTab, GAMMA_TAB_SIZE);
+                    splineInterpolate(v_b0, gammaTab, GAMMA_TAB_SIZE);
+                    splineInterpolate(v_b1, gammaTab, GAMMA_TAB_SIZE);
+                }
+
+                process(v_r0, v_r1, v_g0, v_g1, v_b0, v_b1);
+
+                _mm_interleave_ps(v_r0, v_r1, v_g0, v_g1, v_b0, v_b1);
+
+                _mm_storeu_ps(dst + i +  0, v_r0);
+                _mm_storeu_ps(dst + i +  4, v_r1);
+                _mm_storeu_ps(dst + i +  8, v_g0);
+                _mm_storeu_ps(dst + i + 12, v_g1);
+                _mm_storeu_ps(dst + i + 16, v_b0);
+                _mm_storeu_ps(dst + i + 20, v_b1);
+            }
+        }
+        #endif
+        for( ; i < n; i += 3, src += scn )
         {
             float R = src[0], G = src[1], B = src[2];
             if( gammaTab )
@@ -5578,8 +6711,8 @@ struct RGB2Luv_f
             L = 116.f*L - 16.f;
 
             float d = (4*13) / std::max(X + 15 * Y + 3 * Z, FLT_EPSILON);
-            float u = L*(X*d - _un);
-            float v = L*((9*0.25f)*Y*d - _vn);
+            float u = L*(X*d - un);
+            float v = L*((9*0.25f)*Y*d - vn);
 
             dst[i] = L; dst[i+1] = u; dst[i+2] = v;
         }
@@ -5588,6 +6721,9 @@ struct RGB2Luv_f
     int srccn;
     float coeffs[9], un, vn;
     bool srgb;
+    #if CV_SSE2
+    bool haveSIMD;
+    #endif
 };
 
 
@@ -5614,13 +6750,77 @@ struct Luv2RGB_f
         float d = 1.f/(whitept[0] + whitept[1]*15 + whitept[2]*3);
         un = 4*whitept[0]*d;
         vn = 9*whitept[1]*d;
+        #if CV_SSE2
+        haveSIMD = checkHardwareSupport(CV_CPU_SSE2);
+        #endif
 
         CV_Assert(whitept[1] == 1.f);
     }
 
+    #if CV_SSE2
+    void process(__m128& v_l0, __m128& v_l1, __m128& v_u0,
+                 __m128& v_u1, __m128& v_v0, __m128& v_v1) const
+    {
+        __m128 v_y0 = _mm_mul_ps(_mm_add_ps(v_l0, _mm_set1_ps(16.0f)), _mm_set1_ps(1.f/116.f));
+        __m128 v_y1 = _mm_mul_ps(_mm_add_ps(v_l1, _mm_set1_ps(16.0f)), _mm_set1_ps(1.f/116.f));
+        v_y0 = _mm_mul_ps(_mm_mul_ps(v_y0, v_y0), v_y0);
+        v_y1 = _mm_mul_ps(_mm_mul_ps(v_y1, v_y1), v_y1);
+        __m128 v_d0 = _mm_div_ps(_mm_set1_ps(1.f/13.f), v_l0);
+        __m128 v_d1 = _mm_div_ps(_mm_set1_ps(1.f/13.f), v_l1);
+        v_u0 = _mm_mul_ps(_mm_add_ps(_mm_mul_ps(v_u0, v_d0), _mm_set1_ps(un)), _mm_set1_ps(3.f));
+        v_u1 = _mm_mul_ps(_mm_add_ps(_mm_mul_ps(v_u1, v_d1), _mm_set1_ps(un)), _mm_set1_ps(3.f));
+        v_v0 = _mm_add_ps(_mm_mul_ps(v_v0, v_d0), _mm_set1_ps(vn));
+        v_v1 = _mm_add_ps(_mm_mul_ps(v_v1, v_d1), _mm_set1_ps(vn));
+        __m128 v_iv0 = _mm_div_ps(_mm_set1_ps(0.25f), v_v0);
+        __m128 v_iv1 = _mm_div_ps(_mm_set1_ps(0.25f), v_v1);
+        __m128 v_x0 = _mm_mul_ps(_mm_mul_ps(_mm_set1_ps(3.f), v_u0), v_iv0);
+        __m128 v_x1 = _mm_mul_ps(_mm_mul_ps(_mm_set1_ps(3.f), v_u1), v_iv1);
+        __m128 v_z0 = _mm_mul_ps(_mm_sub_ps(_mm_sub_ps(_mm_set1_ps(12.f), v_u0), _mm_mul_ps(_mm_set1_ps(20.f), v_v0)), v_iv0);
+        __m128 v_z1 = _mm_mul_ps(_mm_sub_ps(_mm_sub_ps(_mm_set1_ps(12.f), v_u1), _mm_mul_ps(_mm_set1_ps(20.f), v_v1)), v_iv1);
+
+        v_l0 = _mm_mul_ps(v_x0, _mm_set1_ps(coeffs[0]));
+        v_l1 = _mm_mul_ps(v_x1, _mm_set1_ps(coeffs[0]));
+        v_u0 = _mm_mul_ps(v_x0, _mm_set1_ps(coeffs[3]));
+        v_u1 = _mm_mul_ps(v_x1, _mm_set1_ps(coeffs[3]));
+        v_v0 = _mm_mul_ps(v_x0, _mm_set1_ps(coeffs[6]));
+        v_v1 = _mm_mul_ps(v_x1, _mm_set1_ps(coeffs[6]));
+        v_l0 = _mm_add_ps(v_l0, _mm_set1_ps(coeffs[1]));
+        v_l1 = _mm_add_ps(v_l1, _mm_set1_ps(coeffs[1]));
+        v_u0 = _mm_add_ps(v_u0, _mm_set1_ps(coeffs[4]));
+        v_u1 = _mm_add_ps(v_u1, _mm_set1_ps(coeffs[4]));
+        v_v0 = _mm_add_ps(v_v0, _mm_set1_ps(coeffs[7]));
+        v_v1 = _mm_add_ps(v_v1, _mm_set1_ps(coeffs[7]));
+        v_l0 = _mm_add_ps(v_l0, _mm_mul_ps(v_z0, _mm_set1_ps(coeffs[2])));
+        v_l1 = _mm_add_ps(v_l1, _mm_mul_ps(v_z1, _mm_set1_ps(coeffs[2])));
+        v_u0 = _mm_add_ps(v_u0, _mm_mul_ps(v_z0, _mm_set1_ps(coeffs[5])));
+        v_u1 = _mm_add_ps(v_u1, _mm_mul_ps(v_z1, _mm_set1_ps(coeffs[5])));
+        v_v0 = _mm_add_ps(v_v0, _mm_mul_ps(v_z0, _mm_set1_ps(coeffs[8])));
+        v_v1 = _mm_add_ps(v_v1, _mm_mul_ps(v_z1, _mm_set1_ps(coeffs[8])));
+        v_l0 = _mm_mul_ps(v_l0, v_y0);
+        v_l1 = _mm_mul_ps(v_l1, v_y1);
+        v_u0 = _mm_mul_ps(v_u0, v_y0);
+        v_u1 = _mm_mul_ps(v_u1, v_y1);
+        v_v0 = _mm_mul_ps(v_v0, v_y0);
+        v_v1 = _mm_mul_ps(v_v1, v_y1);
+
+        v_l0 = _mm_max_ps(v_l0, _mm_setzero_ps());
+        v_l1 = _mm_max_ps(v_l1, _mm_setzero_ps());
+        v_u0 = _mm_max_ps(v_u0, _mm_setzero_ps());
+        v_u1 = _mm_max_ps(v_u1, _mm_setzero_ps());
+        v_v0 = _mm_max_ps(v_v0, _mm_setzero_ps());
+        v_v1 = _mm_max_ps(v_v1, _mm_setzero_ps());
+        v_l0 = _mm_min_ps(v_l0, _mm_set1_ps(1.f));
+        v_l1 = _mm_min_ps(v_l1, _mm_set1_ps(1.f));
+        v_u0 = _mm_min_ps(v_u0, _mm_set1_ps(1.f));
+        v_u1 = _mm_min_ps(v_u1, _mm_set1_ps(1.f));
+        v_v0 = _mm_min_ps(v_v0, _mm_set1_ps(1.f));
+        v_v1 = _mm_min_ps(v_v1, _mm_set1_ps(1.f));
+    }
+    #endif
+
     void operator()(const float* src, float* dst, int n) const
     {
-        int i, dcn = dstcn;
+        int i = 0, dcn = dstcn;
         const float* gammaTab = srgb ? sRGBInvGammaTab : 0;
         float gscale = GammaTabScale;
         float C0 = coeffs[0], C1 = coeffs[1], C2 = coeffs[2],
@@ -5630,7 +6830,69 @@ struct Luv2RGB_f
         float _un = un, _vn = vn;
         n *= 3;
 
-        for( i = 0; i < n; i += 3, dst += dcn )
+        #if CV_SSE2
+        if (haveSIMD)
+        {
+            for( ; i <= n - 24; i += 24, dst += dcn * 8 )
+            {
+                __m128 v_l0 = _mm_loadu_ps(src + i +  0);
+                __m128 v_l1 = _mm_loadu_ps(src + i +  4);
+                __m128 v_u0 = _mm_loadu_ps(src + i +  8);
+                __m128 v_u1 = _mm_loadu_ps(src + i + 12);
+                __m128 v_v0 = _mm_loadu_ps(src + i + 16);
+                __m128 v_v1 = _mm_loadu_ps(src + i + 20);
+
+                _mm_deinterleave_ps(v_l0, v_l1, v_u0, v_u1, v_v0, v_v1);
+
+                process(v_l0, v_l1, v_u0, v_u1, v_v0, v_v1);
+
+                if( gammaTab )
+                {
+                    __m128 v_gscale = _mm_set1_ps(gscale);
+                    v_l0 = _mm_mul_ps(v_l0, v_gscale);
+                    v_l1 = _mm_mul_ps(v_l1, v_gscale);
+                    v_u0 = _mm_mul_ps(v_u0, v_gscale);
+                    v_u1 = _mm_mul_ps(v_u1, v_gscale);
+                    v_v0 = _mm_mul_ps(v_v0, v_gscale);
+                    v_v1 = _mm_mul_ps(v_v1, v_gscale);
+                    splineInterpolate(v_l0, gammaTab, GAMMA_TAB_SIZE);
+                    splineInterpolate(v_l1, gammaTab, GAMMA_TAB_SIZE);
+                    splineInterpolate(v_u0, gammaTab, GAMMA_TAB_SIZE);
+                    splineInterpolate(v_u1, gammaTab, GAMMA_TAB_SIZE);
+                    splineInterpolate(v_v0, gammaTab, GAMMA_TAB_SIZE);
+                    splineInterpolate(v_v1, gammaTab, GAMMA_TAB_SIZE);
+                }
+
+                if( dcn == 4 )
+                {
+                    __m128 v_a0 = _mm_set1_ps(alpha);
+                    __m128 v_a1 = _mm_set1_ps(alpha);
+                    _mm_interleave_ps(v_l0, v_l1, v_u0, v_u1, v_v0, v_v1, v_a0, v_a1);
+
+                    _mm_storeu_ps(dst +  0, v_l0);
+                    _mm_storeu_ps(dst +  4, v_l1);
+                    _mm_storeu_ps(dst +  8, v_u0);
+                    _mm_storeu_ps(dst + 12, v_u1);
+                    _mm_storeu_ps(dst + 16, v_v0);
+                    _mm_storeu_ps(dst + 20, v_v1);
+                    _mm_storeu_ps(dst + 24, v_a0);
+                    _mm_storeu_ps(dst + 28, v_a1);
+                }
+                else
+                {
+                    _mm_interleave_ps(v_l0, v_l1, v_u0, v_u1, v_v0, v_v1);
+
+                    _mm_storeu_ps(dst +  0, v_l0);
+                    _mm_storeu_ps(dst +  4, v_l1);
+                    _mm_storeu_ps(dst +  8, v_u0);
+                    _mm_storeu_ps(dst + 12, v_u1);
+                    _mm_storeu_ps(dst + 16, v_v0);
+                    _mm_storeu_ps(dst + 20, v_v1);
+                }
+            }
+        }
+        #endif
+        for( ; i < n; i += 3, dst += dcn )
         {
             float L = src[i], u = src[i+1], v = src[i+2], d, X, Y, Z;
             Y = (L + 16.f) * (1.f/116.f);
@@ -5666,6 +6928,9 @@ struct Luv2RGB_f
     int dstcn;
     float coeffs[9], un, vn;
     bool srgb;
+    #if CV_SSE2
+    bool haveSIMD;
+    #endif
 };
 
 
@@ -5688,38 +6953,33 @@ struct RGB2Luv_b
         #elif CV_SSE2
         v_zero = _mm_setzero_si128();
         v_scale_inv = _mm_set1_ps(1.f/255.f);
-        v_scale = _mm_set1_ps(2.55f);
-        v_coeff1 = _mm_set1_ps(0.72033898305084743f);
-        v_coeff2 = _mm_set1_ps(96.525423728813564f);
-        v_coeff3 = _mm_set1_ps(0.9732824427480916f);
-        v_coeff4 = _mm_set1_ps(136.259541984732824f);
         haveSIMD = checkHardwareSupport(CV_CPU_SSE2);
         #endif
     }
 
     #if CV_SSE2
     void process(const float * buf,
-                 __m128i & v_l, __m128i & v_u, __m128i & v_v) const
+                 __m128 & v_coeffs, __m128 & v_res, uchar * dst) const
     {
         __m128 v_l0f = _mm_load_ps(buf);
         __m128 v_l1f = _mm_load_ps(buf + 4);
         __m128 v_u0f = _mm_load_ps(buf + 8);
         __m128 v_u1f = _mm_load_ps(buf + 12);
-        __m128 v_v0f = _mm_load_ps(buf + 16);
-        __m128 v_v1f = _mm_load_ps(buf + 20);
 
-        _mm_deinterleave_ps(v_l0f, v_l1f, v_u0f, v_u1f, v_v0f, v_v1f);
+        v_l0f = _mm_add_ps(_mm_mul_ps(v_l0f, v_coeffs), v_res);
+        v_u1f = _mm_add_ps(_mm_mul_ps(v_u1f, v_coeffs), v_res);
+        v_coeffs = _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(v_coeffs), 0x92));
+        v_res = _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(v_res), 0x92));
+        v_u0f = _mm_add_ps(_mm_mul_ps(v_u0f, v_coeffs), v_res);
+        v_coeffs = _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(v_coeffs), 0x92));
+        v_res = _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(v_res), 0x92));
+        v_l1f = _mm_add_ps(_mm_mul_ps(v_l1f, v_coeffs), v_res);
 
-        v_l0f = _mm_mul_ps(v_l0f, v_scale);
-        v_l1f = _mm_mul_ps(v_l1f, v_scale);
-        v_u0f = _mm_add_ps(_mm_mul_ps(v_u0f, v_coeff1), v_coeff2);
-        v_u1f = _mm_add_ps(_mm_mul_ps(v_u1f, v_coeff1), v_coeff2);
-        v_v0f = _mm_add_ps(_mm_mul_ps(v_v0f, v_coeff3), v_coeff4);
-        v_v1f = _mm_add_ps(_mm_mul_ps(v_v1f, v_coeff3), v_coeff4);
+        __m128i v_l = _mm_packs_epi32(_mm_cvtps_epi32(v_l0f), _mm_cvtps_epi32(v_l1f));
+        __m128i v_u = _mm_packs_epi32(_mm_cvtps_epi32(v_u0f), _mm_cvtps_epi32(v_u1f));
+        __m128i v_l0 = _mm_packus_epi16(v_l, v_u);
 
-        v_l = _mm_packs_epi32(_mm_cvtps_epi32(v_l0f), _mm_cvtps_epi32(v_l1f));
-        v_u = _mm_packs_epi32(_mm_cvtps_epi32(v_u0f), _mm_cvtps_epi32(v_u1f));
-        v_v = _mm_packs_epi32(_mm_cvtps_epi32(v_v0f), _mm_cvtps_epi32(v_v1f));
+        _mm_storeu_si128((__m128i *)(dst), v_l0);
     }
     #endif
 
@@ -5728,6 +6988,11 @@ struct RGB2Luv_b
         int i, j, scn = srccn;
         float CV_DECL_ALIGNED(16) buf[3*BLOCK_SIZE];
 
+        #if CV_SSE2
+        __m128 v_coeffs = _mm_set_ps(2.55f, 0.9732824427480916f, 0.72033898305084743f, 2.55f);
+        __m128 v_res = _mm_set_ps(0.f, 136.259541984732824f, 96.525423728813564f, 0.f);
+        #endif
+
         for( i = 0; i < n; i += BLOCK_SIZE, dst += BLOCK_SIZE*3 )
         {
             int dn = std::min(n - i, (int)BLOCK_SIZE);
@@ -5784,6 +7049,26 @@ struct RGB2Luv_b
                 if (jr)
                     src -= jr, j -= jr;
             }
+            else if (scn == 4 && haveSIMD)
+            {
+                for ( ; j <= (dn * 3 - 12); j += 12, src += 16)
+                {
+                    __m128i v_src = _mm_loadu_si128((__m128i const *)src);
+
+                    __m128i v_src_lo = _mm_unpacklo_epi8(v_src, v_zero);
+                    __m128i v_src_hi = _mm_unpackhi_epi8(v_src, v_zero);
+                    _mm_storeu_ps(buf + j, _mm_mul_ps(_mm_cvtepi32_ps(_mm_unpacklo_epi16(v_src_lo, v_zero)), v_scale_inv));
+                    _mm_storeu_ps(buf + j + 3, _mm_mul_ps(_mm_cvtepi32_ps(_mm_unpackhi_epi16(v_src_lo, v_zero)), v_scale_inv));
+                    _mm_storeu_ps(buf + j + 6, _mm_mul_ps(_mm_cvtepi32_ps(_mm_unpacklo_epi16(v_src_hi, v_zero)), v_scale_inv));
+                    float tmp = buf[j + 8];
+                    _mm_storeu_ps(buf + j + 8, _mm_mul_ps(_mm_cvtepi32_ps(_mm_shuffle_epi32(_mm_unpackhi_epi16(v_src_hi, v_zero), 0x90)), v_scale_inv));
+                    buf[j + 8] = tmp;
+                }
+
+                int jr = j % 3;
+                if (jr)
+                    src -= jr, j -= jr;
+            }
             #endif
             for( ; j < dn*3; j += 3, src += scn )
             {
@@ -5812,38 +7097,16 @@ struct RGB2Luv_b
             #elif CV_SSE2
             if (haveSIMD)
             {
-                for ( ; j <= (dn - 32) * 3; j += 96)
+                for ( ; j <= (dn - 16) * 3; j += 48)
                 {
-                    __m128i v_l_0, v_u_0, v_v_0;
                     process(buf + j,
-                            v_l_0, v_u_0, v_v_0);
-
-                    __m128i v_l_1, v_u_1, v_v_1;
-                    process(buf + j + 24,
-                            v_l_1, v_u_1, v_v_1);
-
-                    __m128i v_l0 = _mm_packus_epi16(v_l_0, v_l_1);
-                    __m128i v_u0 = _mm_packus_epi16(v_u_0, v_u_1);
-                    __m128i v_v0 = _mm_packus_epi16(v_v_0, v_v_1);
-
-                    process(buf + j + 48,
-                            v_l_0, v_u_0, v_v_0);
+                            v_coeffs, v_res, dst + j);
 
-                    process(buf + j + 72,
-                            v_l_1, v_u_1, v_v_1);
+                    process(buf + j + 16,
+                            v_coeffs, v_res, dst + j + 16);
 
-                    __m128i v_l1 = _mm_packus_epi16(v_l_0, v_l_1);
-                    __m128i v_u1 = _mm_packus_epi16(v_u_0, v_u_1);
-                    __m128i v_v1 = _mm_packus_epi16(v_v_0, v_v_1);
-
-                    _mm_interleave_epi8(v_l0, v_l1, v_u0, v_u1, v_v0, v_v1);
-
-                    _mm_storeu_si128((__m128i *)(dst + j), v_l0);
-                    _mm_storeu_si128((__m128i *)(dst + j + 16), v_l1);
-                    _mm_storeu_si128((__m128i *)(dst + j + 32), v_u0);
-                    _mm_storeu_si128((__m128i *)(dst + j + 48), v_u1);
-                    _mm_storeu_si128((__m128i *)(dst + j + 64), v_v0);
-                    _mm_storeu_si128((__m128i *)(dst + j + 80), v_v1);
+                    process(buf + j + 32,
+                            v_coeffs, v_res, dst + j + 32);
                 }
             }
             #endif
@@ -5864,7 +7127,7 @@ struct RGB2Luv_b
     float32x4_t v_scale, v_scale_inv, v_coeff1, v_coeff2, v_coeff3, v_coeff4;
     uint8x8_t v_alpha;
     #elif CV_SSE2
-    __m128 v_scale, v_scale_inv, v_coeff1, v_coeff2, v_coeff3, v_coeff4;
+    __m128 v_scale_inv;
     __m128i v_zero;
     bool haveSIMD;
     #endif
@@ -5888,13 +7151,9 @@ struct Luv2RGB_b
         v_scale = vdupq_n_f32(255.f);
         v_alpha = vdup_n_u8(ColorChannel<uchar>::max());
         #elif CV_SSE2
-        v_scale_inv = _mm_set1_ps(100.f/255.f);
-        v_coeff1 = _mm_set1_ps(1.388235294117647f);
-        v_coeff2 = _mm_set1_ps(1.027450980392157f);
-        v_134 = _mm_set1_ps(134.f);
-        v_140 = _mm_set1_ps(140.f);
         v_scale = _mm_set1_ps(255.f);
         v_zero = _mm_setzero_si128();
+        v_alpha = _mm_set1_ps(ColorChannel<uchar>::max());
         haveSIMD = checkHardwareSupport(CV_CPU_SSE2);
         #endif
     }
@@ -5902,6 +7161,7 @@ struct Luv2RGB_b
     #if CV_SSE2
     // 16s x 8
     void process(__m128i v_l, __m128i v_u, __m128i v_v,
+                 const __m128& v_coeffs_, const __m128& v_res_,
                  float * buf) const
     {
         __m128 v_l0 = _mm_cvtepi32_ps(_mm_unpacklo_epi16(v_l, v_zero));
@@ -5912,15 +7172,29 @@ struct Luv2RGB_b
         __m128 v_u1 = _mm_cvtepi32_ps(_mm_unpackhi_epi16(v_u, v_zero));
         __m128 v_v1 = _mm_cvtepi32_ps(_mm_unpackhi_epi16(v_v, v_zero));
 
-        v_l0 = _mm_mul_ps(v_l0, v_scale_inv);
-        v_l1 = _mm_mul_ps(v_l1, v_scale_inv);
+        __m128 v_coeffs = v_coeffs_;
+        __m128 v_res = v_res_;
+
+        v_l0 = _mm_mul_ps(v_l0, v_coeffs);
+        v_u1 = _mm_mul_ps(v_u1, v_coeffs);
+        v_l0 = _mm_sub_ps(v_l0, v_res);
+        v_u1 = _mm_sub_ps(v_u1, v_res);
+
+        v_coeffs = _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(v_coeffs), 0x49));
+        v_res = _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(v_res), 0x49));
 
-        v_u0 = _mm_sub_ps(_mm_mul_ps(v_u0, v_coeff1), v_134);
-        v_u1 = _mm_sub_ps(_mm_mul_ps(v_u1, v_coeff1), v_134);
-        v_v0 = _mm_sub_ps(_mm_mul_ps(v_v0, v_coeff2), v_140);
-        v_v1 = _mm_sub_ps(_mm_mul_ps(v_v1, v_coeff2), v_140);
+        v_l1 = _mm_mul_ps(v_l1, v_coeffs);
+        v_v0 = _mm_mul_ps(v_v0, v_coeffs);
+        v_l1 = _mm_sub_ps(v_l1, v_res);
+        v_v0 = _mm_sub_ps(v_v0, v_res);
 
-        _mm_interleave_ps(v_l0, v_l1, v_u0, v_u1, v_v0, v_v1);
+        v_coeffs = _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(v_coeffs), 0x49));
+        v_res = _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(v_res), 0x49));
+
+        v_u0 = _mm_mul_ps(v_u0, v_coeffs);
+        v_v1 = _mm_mul_ps(v_v1, v_coeffs);
+        v_u0 = _mm_sub_ps(v_u0, v_res);
+        v_v1 = _mm_sub_ps(v_v1, v_res);
 
         _mm_store_ps(buf, v_l0);
         _mm_store_ps(buf + 4, v_l1);
@@ -5937,6 +7211,11 @@ struct Luv2RGB_b
         uchar alpha = ColorChannel<uchar>::max();
         float CV_DECL_ALIGNED(16) buf[3*BLOCK_SIZE];
 
+        #if CV_SSE2
+        __m128 v_coeffs = _mm_set_ps(100.f/255.f, 1.027450980392157f, 1.388235294117647f, 100.f/255.f);
+        __m128 v_res = _mm_set_ps(0.f, 140.f, 134.f, 0.f);
+        #endif
+
         for( i = 0; i < n; i += BLOCK_SIZE, src += BLOCK_SIZE*3 )
         {
             int dn = std::min(n - i, (int)BLOCK_SIZE);
@@ -5964,36 +7243,16 @@ struct Luv2RGB_b
             #elif CV_SSE2
             if (haveSIMD)
             {
-                for ( ; j <= (dn - 32) * 3; j += 96)
+                for ( ; j <= (dn - 8) * 3; j += 24)
                 {
-                    __m128i v_r0 = _mm_loadu_si128((__m128i const *)(src + j));
-                    __m128i v_r1 = _mm_loadu_si128((__m128i const *)(src + j + 16));
-                    __m128i v_g0 = _mm_loadu_si128((__m128i const *)(src + j + 32));
-                    __m128i v_g1 = _mm_loadu_si128((__m128i const *)(src + j + 48));
-                    __m128i v_b0 = _mm_loadu_si128((__m128i const *)(src + j + 64));
-                    __m128i v_b1 = _mm_loadu_si128((__m128i const *)(src + j + 80));
-
-                    _mm_deinterleave_epi8(v_r0, v_r1, v_g0, v_g1, v_b0, v_b1);
-
-                    process(_mm_unpacklo_epi8(v_r0, v_zero),
-                            _mm_unpacklo_epi8(v_g0, v_zero),
-                            _mm_unpacklo_epi8(v_b0, v_zero),
-                            buf + j);
+                    __m128i v_src0 = _mm_loadu_si128((__m128i const *)(src + j));
+                    __m128i v_src1 = _mm_loadl_epi64((__m128i const *)(src + j + 16));
 
-                    process(_mm_unpackhi_epi8(v_r0, v_zero),
-                            _mm_unpackhi_epi8(v_g0, v_zero),
-                            _mm_unpackhi_epi8(v_b0, v_zero),
-                            buf + j + 24);
-
-                    process(_mm_unpacklo_epi8(v_r1, v_zero),
-                            _mm_unpacklo_epi8(v_g1, v_zero),
-                            _mm_unpacklo_epi8(v_b1, v_zero),
-                            buf + j + 48);
-
-                    process(_mm_unpackhi_epi8(v_r1, v_zero),
-                            _mm_unpackhi_epi8(v_g1, v_zero),
-                            _mm_unpackhi_epi8(v_b1, v_zero),
-                            buf + j + 72);
+                    process(_mm_unpacklo_epi8(v_src0, v_zero),
+                            _mm_unpackhi_epi8(v_src0, v_zero),
+                            _mm_unpacklo_epi8(v_src1, v_zero),
+                            v_coeffs, v_res,
+                            buf + j);
                 }
             }
             #endif
@@ -6057,6 +7316,32 @@ struct Luv2RGB_b
                 if (jr)
                     dst -= jr, j -= jr;
             }
+            else if (dcn == 4 && haveSIMD)
+            {
+                for ( ; j <= (dn * 3 - 12); j += 12, dst += 16)
+                {
+                    __m128 v_buf0 = _mm_mul_ps(_mm_load_ps(buf + j), v_scale);
+                    __m128 v_buf1 = _mm_mul_ps(_mm_load_ps(buf + j + 4), v_scale);
+                    __m128 v_buf2 = _mm_mul_ps(_mm_load_ps(buf + j + 8), v_scale);
+
+                    __m128 v_ba0 = _mm_unpackhi_ps(v_buf0, v_alpha);
+                    __m128 v_ba1 = _mm_unpacklo_ps(v_buf2, v_alpha);
+
+                    __m128i v_src0 = _mm_cvtps_epi32(_mm_shuffle_ps(v_buf0, v_ba0, 0x44));
+                    __m128i v_src1 = _mm_shuffle_epi32(_mm_cvtps_epi32(_mm_shuffle_ps(v_ba0, v_buf1, 0x4e)), 0x78);
+                    __m128i v_src2 = _mm_cvtps_epi32(_mm_shuffle_ps(v_buf1, v_ba1, 0x4e));
+                    __m128i v_src3 = _mm_shuffle_epi32(_mm_cvtps_epi32(_mm_shuffle_ps(v_ba1, v_buf2, 0xee)), 0x78);
+
+                    __m128i v_dst0 = _mm_packs_epi32(v_src0, v_src1);
+                    __m128i v_dst1 = _mm_packs_epi32(v_src2, v_src3);
+
+                    _mm_storeu_si128((__m128i *)dst, _mm_packus_epi16(v_dst0, v_dst1));
+                }
+
+                int jr = j % 3;
+                if (jr)
+                    dst -= jr, j -= jr;
+            }
             #endif
 
             for( ; j < dn*3; j += 3, dst += dcn )
@@ -6077,7 +7362,8 @@ struct Luv2RGB_b
     float32x4_t v_scale, v_scale_inv, v_coeff1, v_coeff2, v_134, v_140;
     uint8x8_t v_alpha;
     #elif CV_SSE2
-    __m128 v_scale, v_scale_inv, v_coeff1, v_coeff2, v_134, v_140;
+    __m128 v_scale;
+    __m128 v_alpha;
     __m128i v_zero;
     bool haveSIMD;
     #endif
@@ -6106,12 +7392,14 @@ const int ITUR_BT_601_CBV = -74448;
 template<int bIdx, int uIdx>
 struct YUV420sp2RGB888Invoker : ParallelLoopBody
 {
-    Mat* dst;
+    uchar * dst_data;
+    size_t dst_step;
+    int width;
     const uchar* my1, *muv;
-    int width, stride;
+    size_t stride;
 
-    YUV420sp2RGB888Invoker(Mat* _dst, int _stride, const uchar* _y1, const uchar* _uv)
-        : dst(_dst), my1(_y1), muv(_uv), width(_dst->cols), stride(_stride) {}
+    YUV420sp2RGB888Invoker(uchar * _dst_data, size_t _dst_step, int _dst_width, size_t _stride, const uchar* _y1, const uchar* _uv)
+        : dst_data(_dst_data), dst_step(_dst_step), width(_dst_width), my1(_y1), muv(_uv), stride(_stride) {}
 
     void operator()(const Range& range) const
     {
@@ -6128,15 +7416,10 @@ struct YUV420sp2RGB888Invoker : ParallelLoopBody
 
         const uchar* y1 = my1 + rangeBegin * stride, *uv = muv + rangeBegin * stride / 2;
 
-#ifdef HAVE_TEGRA_OPTIMIZATION
-        if(tegra::useTegra() && tegra::cvtYUV4202RGB(bIdx, uIdx, 3, y1, uv, stride, dst->ptr<uchar>(rangeBegin), dst->step, rangeEnd - rangeBegin, dst->cols))
-            return;
-#endif
-
         for (int j = rangeBegin; j < rangeEnd; j += 2, y1 += stride * 2, uv += stride)
         {
-            uchar* row1 = dst->ptr<uchar>(j);
-            uchar* row2 = dst->ptr<uchar>(j + 1);
+            uchar* row1 = dst_data + dst_step * j;
+            uchar* row2 = dst_data + dst_step * (j + 1);
             const uchar* y2 = y1 + stride;
 
             for (int i = 0; i < width; i += 2, row1 += 6, row2 += 6)
@@ -6175,12 +7458,14 @@ struct YUV420sp2RGB888Invoker : ParallelLoopBody
 template<int bIdx, int uIdx>
 struct YUV420sp2RGBA8888Invoker : ParallelLoopBody
 {
-    Mat* dst;
+    uchar * dst_data;
+    size_t dst_step;
+    int width;
     const uchar* my1, *muv;
-    int width, stride;
+    size_t stride;
 
-    YUV420sp2RGBA8888Invoker(Mat* _dst, int _stride, const uchar* _y1, const uchar* _uv)
-        : dst(_dst), my1(_y1), muv(_uv), width(_dst->cols), stride(_stride) {}
+    YUV420sp2RGBA8888Invoker(uchar * _dst_data, size_t _dst_step, int _dst_width, size_t _stride, const uchar* _y1, const uchar* _uv)
+        : dst_data(_dst_data), dst_step(_dst_step), width(_dst_width), my1(_y1), muv(_uv), stride(_stride) {}
 
     void operator()(const Range& range) const
     {
@@ -6197,15 +7482,10 @@ struct YUV420sp2RGBA8888Invoker : ParallelLoopBody
 
         const uchar* y1 = my1 + rangeBegin * stride, *uv = muv + rangeBegin * stride / 2;
 
-#ifdef HAVE_TEGRA_OPTIMIZATION
-        if(tegra::useTegra() && tegra::cvtYUV4202RGB(bIdx, uIdx, 4, y1, uv, stride, dst->ptr<uchar>(rangeBegin), dst->step, rangeEnd - rangeBegin, dst->cols))
-            return;
-#endif
-
         for (int j = rangeBegin; j < rangeEnd; j += 2, y1 += stride * 2, uv += stride)
         {
-            uchar* row1 = dst->ptr<uchar>(j);
-            uchar* row2 = dst->ptr<uchar>(j + 1);
+            uchar* row1 = dst_data + dst_step * j;
+            uchar* row2 = dst_data + dst_step * (j + 1);
             const uchar* y2 = y1 + stride;
 
             for (int i = 0; i < width; i += 2, row1 += 8, row2 += 8)
@@ -6248,20 +7528,22 @@ struct YUV420sp2RGBA8888Invoker : ParallelLoopBody
 template<int bIdx>
 struct YUV420p2RGB888Invoker : ParallelLoopBody
 {
-    Mat* dst;
+    uchar * dst_data;
+    size_t dst_step;
+    int width;
     const uchar* my1, *mu, *mv;
-    int width, stride;
+    size_t stride;
     int ustepIdx, vstepIdx;
 
-    YUV420p2RGB888Invoker(Mat* _dst, int _stride, const uchar* _y1, const uchar* _u, const uchar* _v, int _ustepIdx, int _vstepIdx)
-        : dst(_dst), my1(_y1), mu(_u), mv(_v), width(_dst->cols), stride(_stride), ustepIdx(_ustepIdx), vstepIdx(_vstepIdx) {}
+    YUV420p2RGB888Invoker(uchar * _dst_data, size_t _dst_step, int _dst_width, size_t _stride, const uchar* _y1, const uchar* _u, const uchar* _v, int _ustepIdx, int _vstepIdx)
+        : dst_data(_dst_data), dst_step(_dst_step), width(_dst_width), my1(_y1), mu(_u), mv(_v), stride(_stride), ustepIdx(_ustepIdx), vstepIdx(_vstepIdx) {}
 
     void operator()(const Range& range) const
     {
         const int rangeBegin = range.start * 2;
         const int rangeEnd = range.end * 2;
 
-        int uvsteps[2] = {width/2, stride - width/2};
+        int uvsteps[2] = {width/2, static_cast<int>(stride) - width/2};
         int usIdx = ustepIdx, vsIdx = vstepIdx;
 
         const uchar* y1 = my1 + rangeBegin * stride;
@@ -6276,8 +7558,8 @@ struct YUV420p2RGB888Invoker : ParallelLoopBody
 
         for (int j = rangeBegin; j < rangeEnd; j += 2, y1 += stride * 2, u1 += uvsteps[(usIdx++) & 1], v1 += uvsteps[(vsIdx++) & 1])
         {
-            uchar* row1 = dst->ptr<uchar>(j);
-            uchar* row2 = dst->ptr<uchar>(j + 1);
+            uchar* row1 = dst_data + dst_step * j;
+            uchar* row2 = dst_data + dst_step * (j + 1);
             const uchar* y2 = y1 + stride;
 
             for (int i = 0; i < width / 2; i += 1, row1 += 6, row2 += 6)
@@ -6316,20 +7598,22 @@ struct YUV420p2RGB888Invoker : ParallelLoopBody
 template<int bIdx>
 struct YUV420p2RGBA8888Invoker : ParallelLoopBody
 {
-    Mat* dst;
+    uchar * dst_data;
+    size_t dst_step;
+    int width;
     const uchar* my1, *mu, *mv;
-    int width, stride;
+    size_t  stride;
     int ustepIdx, vstepIdx;
 
-    YUV420p2RGBA8888Invoker(Mat* _dst, int _stride, const uchar* _y1, const uchar* _u, const uchar* _v, int _ustepIdx, int _vstepIdx)
-        : dst(_dst), my1(_y1), mu(_u), mv(_v), width(_dst->cols), stride(_stride), ustepIdx(_ustepIdx), vstepIdx(_vstepIdx) {}
+    YUV420p2RGBA8888Invoker(uchar * _dst_data, size_t _dst_step, int _dst_width, size_t _stride, const uchar* _y1, const uchar* _u, const uchar* _v, int _ustepIdx, int _vstepIdx)
+        : dst_data(_dst_data), dst_step(_dst_step), width(_dst_width), my1(_y1), mu(_u), mv(_v), stride(_stride), ustepIdx(_ustepIdx), vstepIdx(_vstepIdx) {}
 
     void operator()(const Range& range) const
     {
         int rangeBegin = range.start * 2;
         int rangeEnd = range.end * 2;
 
-        int uvsteps[2] = {width/2, stride - width/2};
+        int uvsteps[2] = {width/2, static_cast<int>(stride) - width/2};
         int usIdx = ustepIdx, vsIdx = vstepIdx;
 
         const uchar* y1 = my1 + rangeBegin * stride;
@@ -6344,8 +7628,8 @@ struct YUV420p2RGBA8888Invoker : ParallelLoopBody
 
         for (int j = rangeBegin; j < rangeEnd; j += 2, y1 += stride * 2, u1 += uvsteps[(usIdx++) & 1], v1 += uvsteps[(vsIdx++) & 1])
         {
-            uchar* row1 = dst->ptr<uchar>(j);
-            uchar* row2 = dst->ptr<uchar>(j + 1);
+            uchar* row1 = dst_data + dst_step * j;
+            uchar* row2 = dst_data + dst_step * (j + 1);
             const uchar* y2 = y1 + stride;
 
             for (int i = 0; i < width / 2; i += 1, row1 += 8, row2 += 8)
@@ -6388,70 +7672,78 @@ struct YUV420p2RGBA8888Invoker : ParallelLoopBody
 #define MIN_SIZE_FOR_PARALLEL_YUV420_CONVERSION (320*240)
 
 template<int bIdx, int uIdx>
-inline void cvtYUV420sp2RGB(Mat& _dst, int _stride, const uchar* _y1, const uchar* _uv)
+inline void cvtYUV420sp2RGB(uchar * dst_data, size_t dst_step, int dst_width, int dst_height, size_t _stride, const uchar* _y1, const uchar* _uv)
 {
-    YUV420sp2RGB888Invoker<bIdx, uIdx> converter(&_dst, _stride, _y1,  _uv);
-    if (_dst.total() >= MIN_SIZE_FOR_PARALLEL_YUV420_CONVERSION)
-        parallel_for_(Range(0, _dst.rows/2), converter);
+    YUV420sp2RGB888Invoker<bIdx, uIdx> converter(dst_data, dst_step, dst_width, _stride, _y1,  _uv);
+    if (dst_width * dst_height >= MIN_SIZE_FOR_PARALLEL_YUV420_CONVERSION)
+        parallel_for_(Range(0, dst_height/2), converter);
     else
-        converter(Range(0, _dst.rows/2));
+        converter(Range(0, dst_height/2));
 }
 
 template<int bIdx, int uIdx>
-inline void cvtYUV420sp2RGBA(Mat& _dst, int _stride, const uchar* _y1, const uchar* _uv)
+inline void cvtYUV420sp2RGBA(uchar * dst_data, size_t dst_step, int dst_width, int dst_height, size_t _stride, const uchar* _y1, const uchar* _uv)
 {
-    YUV420sp2RGBA8888Invoker<bIdx, uIdx> converter(&_dst, _stride, _y1,  _uv);
-    if (_dst.total() >= MIN_SIZE_FOR_PARALLEL_YUV420_CONVERSION)
-        parallel_for_(Range(0, _dst.rows/2), converter);
+    YUV420sp2RGBA8888Invoker<bIdx, uIdx> converter(dst_data, dst_step, dst_width, _stride, _y1,  _uv);
+    if (dst_width * dst_height >= MIN_SIZE_FOR_PARALLEL_YUV420_CONVERSION)
+        parallel_for_(Range(0, dst_height/2), converter);
     else
-        converter(Range(0, _dst.rows/2));
+        converter(Range(0, dst_height/2));
 }
 
 template<int bIdx>
-inline void cvtYUV420p2RGB(Mat& _dst, int _stride, const uchar* _y1, const uchar* _u, const uchar* _v, int ustepIdx, int vstepIdx)
+inline void cvtYUV420p2RGB(uchar * dst_data, size_t dst_step, int dst_width, int dst_height, size_t _stride, const uchar* _y1, const uchar* _u, const uchar* _v, int ustepIdx, int vstepIdx)
 {
-    YUV420p2RGB888Invoker<bIdx> converter(&_dst, _stride, _y1,  _u, _v, ustepIdx, vstepIdx);
-    if (_dst.total() >= MIN_SIZE_FOR_PARALLEL_YUV420_CONVERSION)
-        parallel_for_(Range(0, _dst.rows/2), converter);
+    YUV420p2RGB888Invoker<bIdx> converter(dst_data, dst_step, dst_width, _stride, _y1,  _u, _v, ustepIdx, vstepIdx);
+    if (dst_width * dst_height >= MIN_SIZE_FOR_PARALLEL_YUV420_CONVERSION)
+        parallel_for_(Range(0, dst_height/2), converter);
     else
-        converter(Range(0, _dst.rows/2));
+        converter(Range(0, dst_height/2));
 }
 
 template<int bIdx>
-inline void cvtYUV420p2RGBA(Mat& _dst, int _stride, const uchar* _y1, const uchar* _u, const uchar* _v, int ustepIdx, int vstepIdx)
+inline void cvtYUV420p2RGBA(uchar * dst_data, size_t dst_step, int dst_width, int dst_height, size_t _stride, const uchar* _y1, const uchar* _u, const uchar* _v, int ustepIdx, int vstepIdx)
 {
-    YUV420p2RGBA8888Invoker<bIdx> converter(&_dst, _stride, _y1,  _u, _v, ustepIdx, vstepIdx);
-    if (_dst.total() >= MIN_SIZE_FOR_PARALLEL_YUV420_CONVERSION)
-        parallel_for_(Range(0, _dst.rows/2), converter);
+    YUV420p2RGBA8888Invoker<bIdx> converter(dst_data, dst_step, dst_width, _stride, _y1,  _u, _v, ustepIdx, vstepIdx);
+    if (dst_width * dst_height >= MIN_SIZE_FOR_PARALLEL_YUV420_CONVERSION)
+        parallel_for_(Range(0, dst_height/2), converter);
     else
-        converter(Range(0, _dst.rows/2));
+        converter(Range(0, dst_height/2));
 }
 
 ///////////////////////////////////// RGB -> YUV420p /////////////////////////////////////
 
-template<int bIdx>
+template<int uIdx>
+inline void swapUV(uchar * &, uchar * &) {}
+template<>
+inline void swapUV<2>(uchar * & u, uchar * & v) { std::swap(u, v); }
+
+template<int bIdx, int uIdx>
 struct RGB888toYUV420pInvoker: public ParallelLoopBody
 {
-    RGB888toYUV420pInvoker( const Mat& src, Mat* dst, const int uIdx )
-        : src_(src),
-          dst_(dst),
-          uIdx_(uIdx) { }
+    RGB888toYUV420pInvoker(const uchar * _src_data, size_t _src_step, uchar * _dst_data, size_t _dst_step,
+                           int _src_width, int _src_height, int _scn)
+        : src_data(_src_data), src_step(_src_step),
+          dst_data(_dst_data), dst_step(_dst_step),
+          src_width(_src_width), src_height(_src_height),
+          scn(_scn) { }
 
     void operator()(const Range& rowRange) const
     {
-        const int w = src_.cols;
-        const int h = src_.rows;
+        const int w = src_width;
+        const int h = src_height;
 
-        const int cn = src_.channels();
+        const int cn = scn;
         for( int i = rowRange.start; i < rowRange.end; i++ )
         {
-            const uchar* row0 = src_.ptr<uchar>(2 * i);
-            const uchar* row1 = src_.ptr<uchar>(2 * i + 1);
+            const uchar* row0 = src_data + src_step * (2 * i);
+            const uchar* row1 = src_data + src_step * (2 * i + 1);
 
-            uchar* y = dst_->ptr<uchar>(2*i);
-            uchar* u = dst_->ptr<uchar>(h + i/2) + (i % 2) * (w/2);
-            uchar* v = dst_->ptr<uchar>(h + (i + h/2)/2) + ((i + h/2) % 2) * (w/2);
-            if( uIdx_ == 2 ) std::swap(u, v);
+            uchar* y = dst_data + dst_step * (2*i);
+            uchar* u = dst_data + dst_step * (h + i/2) + (i % 2) * (w/2);
+            uchar* v = dst_data + dst_step * (h + (i + h/2)/2) + ((i + h/2) % 2) * (w/2);
+
+            swapUV<uIdx>(u, v);
 
             for( int j = 0, k = 0; j < w * cn; j += 2 * cn, k++ )
             {
@@ -6469,8 +7761,8 @@ struct RGB888toYUV420pInvoker: public ParallelLoopBody
 
                 y[2*k + 0]            = saturate_cast<uchar>(y00 >> ITUR_BT_601_SHIFT);
                 y[2*k + 1]            = saturate_cast<uchar>(y01 >> ITUR_BT_601_SHIFT);
-                y[2*k + dst_->step + 0] = saturate_cast<uchar>(y10 >> ITUR_BT_601_SHIFT);
-                y[2*k + dst_->step + 1] = saturate_cast<uchar>(y11 >> ITUR_BT_601_SHIFT);
+                y[2*k + dst_step + 0] = saturate_cast<uchar>(y10 >> ITUR_BT_601_SHIFT);
+                y[2*k + dst_step + 1] = saturate_cast<uchar>(y11 >> ITUR_BT_601_SHIFT);
 
                 const int shifted128 = (128 << ITUR_BT_601_SHIFT);
                 int u00 = ITUR_BT_601_CRU * r00 + ITUR_BT_601_CGU * g00 + ITUR_BT_601_CBU * b00 + halfShift + shifted128;
@@ -6482,27 +7774,33 @@ struct RGB888toYUV420pInvoker: public ParallelLoopBody
         }
     }
 
-    static bool isFit( const Mat& src )
+    static bool isFit( int src_width, int src_height )
     {
-        return (src.total() >= 320*240);
+        return (src_width * src_height >= 320*240);
     }
 
 private:
     RGB888toYUV420pInvoker& operator=(const RGB888toYUV420pInvoker&);
 
-    const Mat& src_;
-    Mat* const dst_;
-    const int uIdx_;
+    const uchar * src_data;
+    size_t src_step;
+    uchar * dst_data;
+    size_t dst_step;
+    int src_width;
+    int src_height;
+    const int scn;
 };
 
 template<int bIdx, int uIdx>
-static void cvtRGBtoYUV420p(const Mat& src, Mat& dst)
+static void cvtRGBtoYUV420p(const uchar * src_data, size_t src_step,
+                            uchar * dst_data, size_t dst_step,
+                            int src_width, int src_height, int scn)
 {
-    RGB888toYUV420pInvoker<bIdx> colorConverter(src, &dst, uIdx);
-    if( RGB888toYUV420pInvoker<bIdx>::isFit(src) )
-        parallel_for_(Range(0, src.rows/2), colorConverter);
+    RGB888toYUV420pInvoker<bIdx, uIdx> colorConverter(src_data, src_step, dst_data, dst_step, src_width, src_height, scn);
+    if( RGB888toYUV420pInvoker<bIdx, uIdx>::isFit(src_width, src_height) )
+        parallel_for_(Range(0, src_height/2), colorConverter);
     else
-        colorConverter(Range(0, src.rows/2));
+        colorConverter(Range(0, src_height/2));
 }
 
 ///////////////////////////////////// YUV422 -> RGB /////////////////////////////////////
@@ -6510,12 +7808,16 @@ static void cvtRGBtoYUV420p(const Mat& src, Mat& dst)
 template<int bIdx, int uIdx, int yIdx>
 struct YUV422toRGB888Invoker : ParallelLoopBody
 {
-    Mat* dst;
-    const uchar* src;
-    int width, stride;
+    uchar * dst_data;
+    size_t dst_step;
+    const uchar * src_data;
+    size_t src_step;
+    int width;
 
-    YUV422toRGB888Invoker(Mat* _dst, int _stride, const uchar* _yuv)
-        : dst(_dst), src(_yuv), width(_dst->cols), stride(_stride) {}
+    YUV422toRGB888Invoker(uchar * _dst_data, size_t _dst_step,
+                          const uchar * _src_data, size_t _src_step,
+                          int _width)
+        : dst_data(_dst_data), dst_step(_dst_step), src_data(_src_data), src_step(_src_step), width(_width) {}
 
     void operator()(const Range& range) const
     {
@@ -6524,11 +7826,11 @@ struct YUV422toRGB888Invoker : ParallelLoopBody
 
         const int uidx = 1 - yIdx + uIdx * 2;
         const int vidx = (2 + uidx) % 4;
-        const uchar* yuv_src = src + rangeBegin * stride;
+        const uchar* yuv_src = src_data + rangeBegin * src_step;
 
-        for (int j = rangeBegin; j < rangeEnd; j++, yuv_src += stride)
+        for (int j = rangeBegin; j < rangeEnd; j++, yuv_src += src_step)
         {
-            uchar* row = dst->ptr<uchar>(j);
+            uchar* row = dst_data + dst_step * j;
 
             for (int i = 0; i < 2 * width; i += 4, row += 6)
             {
@@ -6556,12 +7858,16 @@ struct YUV422toRGB888Invoker : ParallelLoopBody
 template<int bIdx, int uIdx, int yIdx>
 struct YUV422toRGBA8888Invoker : ParallelLoopBody
 {
-    Mat* dst;
-    const uchar* src;
-    int width, stride;
+    uchar * dst_data;
+    size_t dst_step;
+    const uchar * src_data;
+    size_t src_step;
+    int width;
 
-    YUV422toRGBA8888Invoker(Mat* _dst, int _stride, const uchar* _yuv)
-        : dst(_dst), src(_yuv), width(_dst->cols), stride(_stride) {}
+    YUV422toRGBA8888Invoker(uchar * _dst_data, size_t _dst_step,
+                            const uchar * _src_data, size_t _src_step,
+                            int _width)
+        : dst_data(_dst_data), dst_step(_dst_step), src_data(_src_data), src_step(_src_step), width(_width) {}
 
     void operator()(const Range& range) const
     {
@@ -6570,11 +7876,11 @@ struct YUV422toRGBA8888Invoker : ParallelLoopBody
 
         const int uidx = 1 - yIdx + uIdx * 2;
         const int vidx = (2 + uidx) % 4;
-        const uchar* yuv_src = src + rangeBegin * stride;
+        const uchar* yuv_src = src_data + rangeBegin * src_step;
 
-        for (int j = rangeBegin; j < rangeEnd; j++, yuv_src += stride)
+        for (int j = rangeBegin; j < rangeEnd; j++, yuv_src += src_step)
         {
-            uchar* row = dst->ptr<uchar>(j);
+            uchar* row = dst_data + dst_step * j;
 
             for (int i = 0; i < 2 * width; i += 4, row += 8)
             {
@@ -6604,23 +7910,25 @@ struct YUV422toRGBA8888Invoker : ParallelLoopBody
 #define MIN_SIZE_FOR_PARALLEL_YUV422_CONVERSION (320*240)
 
 template<int bIdx, int uIdx, int yIdx>
-inline void cvtYUV422toRGB(Mat& _dst, int _stride, const uchar* _yuv)
+inline void cvtYUV422toRGB(uchar * dst_data, size_t dst_step, const uchar * src_data, size_t src_step,
+                           int width, int height)
 {
-    YUV422toRGB888Invoker<bIdx, uIdx, yIdx> converter(&_dst, _stride, _yuv);
-    if (_dst.total() >= MIN_SIZE_FOR_PARALLEL_YUV422_CONVERSION)
-        parallel_for_(Range(0, _dst.rows), converter);
+    YUV422toRGB888Invoker<bIdx, uIdx, yIdx> converter(dst_data, dst_step, src_data, src_step, width);
+    if (width * height >= MIN_SIZE_FOR_PARALLEL_YUV422_CONVERSION)
+        parallel_for_(Range(0, height), converter);
     else
-        converter(Range(0, _dst.rows));
+        converter(Range(0, height));
 }
 
 template<int bIdx, int uIdx, int yIdx>
-inline void cvtYUV422toRGBA(Mat& _dst, int _stride, const uchar* _yuv)
+inline void cvtYUV422toRGBA(uchar * dst_data, size_t dst_step, const uchar * src_data, size_t src_step,
+                           int width, int height)
 {
-    YUV422toRGBA8888Invoker<bIdx, uIdx, yIdx> converter(&_dst, _stride, _yuv);
-    if (_dst.total() >= MIN_SIZE_FOR_PARALLEL_YUV422_CONVERSION)
-        parallel_for_(Range(0, _dst.rows), converter);
+    YUV422toRGBA8888Invoker<bIdx, uIdx, yIdx> converter(dst_data, dst_step, src_data, src_step, width);
+    if (width * height >= MIN_SIZE_FOR_PARALLEL_YUV422_CONVERSION)
+        parallel_for_(Range(0, height), converter);
     else
-        converter(Range(0, _dst.rows));
+        converter(Range(0, height));
 }
 
 /////////////////////////// RGBA <-> mRGBA (alpha premultiplied) //////////////
@@ -6778,7 +8086,7 @@ static bool ocl_cvtColor( InputArray _src, OutputArray _dst, int code, int dcn )
     case COLOR_RGB2YUV:
     {
         CV_Assert(scn == 3 || scn == 4);
-        bidx = code == COLOR_RGB2YUV ? 0 : 2;
+        bidx = code == COLOR_RGB2YUV ? 2 : 0;
         dcn = 3;
         k.create("RGB2YUV", ocl::imgproc::cvtcolor_oclsrc,
                  opts + format("-D dcn=3 -D bidx=%d", bidx));
@@ -6787,9 +8095,9 @@ static bool ocl_cvtColor( InputArray _src, OutputArray _dst, int code, int dcn )
     case COLOR_YUV2BGR:
     case COLOR_YUV2RGB:
     {
-        if(dcn < 0) dcn = 3;
+        if(dcn <= 0) dcn = 3;
         CV_Assert(dcn == 3 || dcn == 4);
-        bidx = code == COLOR_YUV2RGB ? 0 : 2;
+        bidx = code == COLOR_YUV2RGB ? 2 : 0;
         k.create("YUV2RGB", ocl::imgproc::cvtcolor_oclsrc,
                  opts + format("-D dcn=%d -D bidx=%d", dcn, bidx));
         break;
@@ -7324,598 +8632,1059 @@ static bool ocl_cvtColor( InputArray _src, OutputArray _dst, int code, int dcn )
 
 #endif
 
-#ifdef HAVE_IPP
-static bool ipp_cvtColor( Mat &src, OutputArray _dst, int code, int dcn )
+}
+
+//
+// HAL functions
+//
+
+namespace cv {
+namespace hal {
+
+// 8u, 16u, 32f
+void cvtBGRtoBGR(const uchar * src_data, size_t src_step,
+                 uchar * dst_data, size_t dst_step,
+                 int width, int height,
+                 int depth, int scn, int dcn, bool swapBlue)
 {
-    int stype = src.type();
-    int scn = CV_MAT_CN(stype), depth = CV_MAT_DEPTH(stype);
+    CV_INSTRUMENT_REGION()
 
-    Mat dst;
-    Size sz = src.size();
+    CALL_HAL(cvtBGRtoBGR, cv_hal_cvtBGRtoBGR, src_data, src_step, dst_data, dst_step, width, height, depth, scn, dcn, swapBlue);
 
-    switch( code )
+#if defined(HAVE_IPP) && IPP_VERSION_X100 >= 700
+    CV_IPP_CHECK()
     {
-#if IPP_VERSION_X100 >= 700
-        case CV_BGR2BGRA: case CV_RGB2BGRA: case CV_BGRA2BGR:
-        case CV_RGBA2BGR: case CV_RGB2BGR: case CV_BGRA2RGBA:
-            CV_Assert( scn == 3 || scn == 4 );
-            dcn = code == CV_BGR2BGRA || code == CV_RGB2BGRA || code == CV_BGRA2RGBA ? 4 : 3;
-            _dst.create( sz, CV_MAKETYPE(depth, dcn));
-            dst = _dst.getMat();
-
-            if( code == CV_BGR2BGRA)
-            {
-                if ( CvtColorIPPLoop(src, dst, IPPReorderFunctor(ippiSwapChannelsC3C4RTab[depth], 0, 1, 2)) )
-                    return true;
-            }
-            else if( code == CV_BGRA2BGR )
-            {
-                if ( CvtColorIPPLoop(src, dst, IPPGeneralFunctor(ippiCopyAC4C3RTab[depth])) )
-                    return true;
-            }
-            else if( code == CV_BGR2RGBA )
-            {
-                if( CvtColorIPPLoop(src, dst, IPPReorderFunctor(ippiSwapChannelsC3C4RTab[depth], 2, 1, 0)) )
-                    return true;
-            }
-            else if( code == CV_RGBA2BGR )
-            {
-                if( CvtColorIPPLoop(src, dst, IPPReorderFunctor(ippiSwapChannelsC4C3RTab[depth], 2, 1, 0)) )
-                    return true;
-            }
-            else if( code == CV_RGB2BGR )
-            {
-                if( CvtColorIPPLoopCopy(src, dst, IPPReorderFunctor(ippiSwapChannelsC3RTab[depth], 2, 1, 0)) )
-                    return true;
-            }
+    if(scn == 3 && dcn == 4 && !swapBlue)
+    {
+        if ( CvtColorIPPLoop(src_data, src_step, dst_data, dst_step, width, height,
+                             IPPReorderFunctor(ippiSwapChannelsC3C4RTab[depth], 0, 1, 2)) )
+            return;
+    }
+    else if(scn == 4 && dcn == 3 && !swapBlue)
+    {
+        if ( CvtColorIPPLoop(src_data, src_step, dst_data, dst_step, width, height,
+                             IPPGeneralFunctor(ippiCopyAC4C3RTab[depth])) )
+            return;
+    }
+    else if(scn == 3 && dcn == 4 && swapBlue)
+    {
+        if( CvtColorIPPLoop(src_data, src_step, dst_data, dst_step, width, height,
+                            IPPReorderFunctor(ippiSwapChannelsC3C4RTab[depth], 2, 1, 0)) )
+            return;
+    }
+    else if(scn == 4 && dcn == 3 && swapBlue)
+    {
+        if( CvtColorIPPLoop(src_data, src_step, dst_data, dst_step, width, height,
+                            IPPReorderFunctor(ippiSwapChannelsC4C3RTab[depth], 2, 1, 0)) )
+            return;
+    }
+    else if(scn == 3 && dcn == 3 && swapBlue)
+    {
+        if( CvtColorIPPLoopCopy(src_data, src_step, CV_MAKETYPE(depth, scn), dst_data, dst_step, width, height,
+                                IPPReorderFunctor(ippiSwapChannelsC3RTab[depth], 2, 1, 0)) )
+            return;
+    }
 #if IPP_VERSION_X100 >= 810
-            else if( code == CV_RGBA2BGRA )
-            {
-                if( CvtColorIPPLoopCopy(src, dst, IPPReorderFunctor(ippiSwapChannelsC4RTab[depth], 2, 1, 0)) )
-                    return true;
-            }
+    else if(scn == 4 && dcn == 4 && swapBlue)
+    {
+        if( CvtColorIPPLoopCopy(src_data, src_step, CV_MAKETYPE(depth, scn), dst_data, dst_step, width, height,
+                                IPPReorderFunctor(ippiSwapChannelsC4RTab[depth], 2, 1, 0)) )
+            return;
+    }
+    }
 #endif
-            return false;
 #endif
 
-#if IPP_DISABLE_BLOCK // breaks OCL accuracy tests
-        case CV_BGR2BGR565: case CV_BGR2BGR555: case CV_RGB2BGR565: case CV_RGB2BGR555:
-        case CV_BGRA2BGR565: case CV_BGRA2BGR555: case CV_RGBA2BGR565: case CV_RGBA2BGR555:
-            CV_Assert( (scn == 3 || scn == 4) && depth == CV_8U );
-            _dst.create(sz, CV_8UC2);
-            dst = _dst.getMat();
-
-            CV_SUPPRESS_DEPRECATED_START
+    int blueIdx = swapBlue ? 2 : 0;
+    if( depth == CV_8U )
+        CvtColorLoop(src_data, src_step, dst_data, dst_step, width, height, RGB2RGB<uchar>(scn, dcn, blueIdx));
+    else if( depth == CV_16U )
+        CvtColorLoop(src_data, src_step, dst_data, dst_step, width, height, RGB2RGB<ushort>(scn, dcn, blueIdx));
+    else
+        CvtColorLoop(src_data, src_step, dst_data, dst_step, width, height, RGB2RGB<float>(scn, dcn, blueIdx));
+}
 
-            if (code == CV_BGR2BGR565 && scn == 3)
-            {
-                if (CvtColorIPPLoop(src, dst, IPPGeneralFunctor((ippiGeneralFunc)ippiBGRToBGR565_8u16u_C3R)))
-                    return true;
-            }
-            else if (code == CV_BGRA2BGR565 && scn == 4)
-            {
-                if (CvtColorIPPLoopCopy(src, dst,
-                                        IPPReorderGeneralFunctor(ippiSwapChannelsC4C3RTab[depth],
-                                        (ippiGeneralFunc)ippiBGRToBGR565_8u16u_C3R, 0, 1, 2, depth)))
-                    return true;
-            }
-            else if (code == CV_RGB2BGR565 && scn == 3)
-            {
-                if( CvtColorIPPLoopCopy(src, dst, IPPReorderGeneralFunctor(ippiSwapChannelsC3RTab[depth],
-                                                                            (ippiGeneralFunc)ippiBGRToBGR565_8u16u_C3R, 2, 1, 0, depth)) )
-                    return true;
-            }
-            else if (code == CV_RGBA2BGR565 && scn == 4)
-            {
-                if( CvtColorIPPLoopCopy(src, dst, IPPReorderGeneralFunctor(ippiSwapChannelsC4C3RTab[depth],
-                                                                            (ippiGeneralFunc)ippiBGRToBGR565_8u16u_C3R, 2, 1, 0, depth)) )
-                    return true;
-            }
-            CV_SUPPRESS_DEPRECATED_END
-            return false;
-#endif
+// only 8u
+void cvtBGRtoBGR5x5(const uchar * src_data, size_t src_step,
+                    uchar * dst_data, size_t dst_step,
+                    int width, int height,
+                    int scn, bool swapBlue, int greenBits)
+{
+    CV_INSTRUMENT_REGION()
 
-#if IPP_VERSION_X100 < 900
-        case CV_BGR5652BGR: case CV_BGR5552BGR: case CV_BGR5652RGB: case CV_BGR5552RGB:
-        case CV_BGR5652BGRA: case CV_BGR5552BGRA: case CV_BGR5652RGBA: case CV_BGR5552RGBA:
-            if(dcn <= 0) dcn = (code==CV_BGR5652BGRA || code==CV_BGR5552BGRA || code==CV_BGR5652RGBA || code==CV_BGR5552RGBA) ? 4 : 3;
-            CV_Assert( (dcn == 3 || dcn == 4) && scn == 2 && depth == CV_8U );
-            _dst.create(sz, CV_MAKETYPE(depth, dcn));
-            dst = _dst.getMat();
+    CALL_HAL(cvtBGRtoBGR5x5, cv_hal_cvtBGRtoBGR5x5, src_data, src_step, dst_data, dst_step, width, height, scn, swapBlue, greenBits);
 
-            CV_SUPPRESS_DEPRECATED_START
-            if (code == CV_BGR5652BGR && dcn == 3)
-            {
-                if (CvtColorIPPLoop(src, dst, IPPGeneralFunctor((ippiGeneralFunc)ippiBGR565ToBGR_16u8u_C3R)))
-                    return true;
-            }
-            else if (code == CV_BGR5652RGB && dcn == 3)
-            {
-                if (CvtColorIPPLoop(src, dst, IPPGeneralReorderFunctor((ippiGeneralFunc)ippiBGR565ToBGR_16u8u_C3R,
-                                                                        ippiSwapChannelsC3RTab[depth], 2, 1, 0, depth)))
-                    return true;
-            }
-            else if (code == CV_BGR5652BGRA && dcn == 4)
-            {
-                if (CvtColorIPPLoop(src, dst, IPPGeneralReorderFunctor((ippiGeneralFunc)ippiBGR565ToBGR_16u8u_C3R,
-                                                                        ippiSwapChannelsC3C4RTab[depth], 0, 1, 2, depth)))
-                    return true;
-            }
-            else if (code == CV_BGR5652RGBA && dcn == 4)
-            {
-                if (CvtColorIPPLoop(src, dst, IPPGeneralReorderFunctor((ippiGeneralFunc)ippiBGR565ToBGR_16u8u_C3R,
-                                                                        ippiSwapChannelsC3C4RTab[depth], 2, 1, 0, depth)))
-                    return true;
-            }
-            CV_SUPPRESS_DEPRECATED_END
-            return false;
+#if defined(HAVE_IPP) && IPP_DISABLE_BLOCK // breaks OCL accuracy tests
+    CV_IPP_CHECK()
+    {
+    CV_SUPPRESS_DEPRECATED_START;
+    if (scn == 3 && greenBits == 6 && !swapBlue)
+    {
+        if (CvtColorIPPLoop(src_data, src_step, dst_data, dst_step, width, height,
+                            IPPGeneralFunctor((ippiGeneralFunc)ippiBGRToBGR565_8u16u_C3R)))
+            return;
+    }
+    else if (scn == 4 && greenBits == 6 && !swapBlue)
+    {
+        if (CvtColorIPPLoopCopy(src_data, src_step, CV_MAKETYPE(CV_8U, scn), dst_data, dst_step, width, height,
+                                IPPReorderGeneralFunctor(ippiSwapChannelsC4C3RTab[CV_8U],
+                                                         (ippiGeneralFunc)ippiBGRToBGR565_8u16u_C3R, 0, 1, 2, CV_8U)))
+            return;
+    }
+    else if (scn == 3 && greenBits == 6 && swapBlue)
+    {
+        if( CvtColorIPPLoopCopy(src_data, src_step, CV_MAKETYPE(CV_8U, scn), dst_data, dst_step, width, height,
+                                IPPReorderGeneralFunctor(ippiSwapChannelsC3RTab[CV_8U],
+                                                         (ippiGeneralFunc)ippiBGRToBGR565_8u16u_C3R, 2, 1, 0, CV_8U)) )
+            return;
+    }
+    else if (scn == 4 && greenBits == 6 && swapBlue)
+    {
+        if( CvtColorIPPLoopCopy(src_data, src_step, CV_MAKETYPE(CV_8U, scn), dst_data, dst_step, width, height,
+                                IPPReorderGeneralFunctor(ippiSwapChannelsC4C3RTab[CV_8U],
+                                                         (ippiGeneralFunc)ippiBGRToBGR565_8u16u_C3R, 2, 1, 0, CV_8U)) )
+            return;
+    }
+    CV_SUPPRESS_DEPRECATED_END;
+    }
 #endif
 
-#if IPP_VERSION_X100 >= 700
-        case CV_BGR2GRAY: case CV_BGRA2GRAY: case CV_RGB2GRAY: case CV_RGBA2GRAY:
-            CV_Assert( scn == 3 || scn == 4 );
-            _dst.create(sz, CV_MAKETYPE(depth, 1));
-            dst = _dst.getMat();
+    CvtColorLoop(src_data, src_step, dst_data, dst_step, width, height, RGB2RGB5x5(scn, swapBlue ? 2 : 0, greenBits));
+}
 
-            if( code == CV_BGR2GRAY && depth == CV_32F )
-            {
-                if( CvtColorIPPLoop(src, dst, IPPColor2GrayFunctor(ippiColor2GrayC3Tab[depth])) )
-                    return true;
-            }
-            else if( code == CV_RGB2GRAY && depth == CV_32F )
-            {
-                if( CvtColorIPPLoop(src, dst, IPPGeneralFunctor(ippiRGB2GrayC3Tab[depth])) )
-                    return true;
-            }
-            else if( code == CV_BGRA2GRAY && depth == CV_32F )
-            {
-                if( CvtColorIPPLoop(src, dst, IPPColor2GrayFunctor(ippiColor2GrayC4Tab[depth])) )
-                    return true;
-            }
-            else if( code == CV_RGBA2GRAY && depth == CV_32F )
-            {
-                if( CvtColorIPPLoop(src, dst, IPPGeneralFunctor(ippiRGB2GrayC4Tab[depth])) )
-                    return true;
-            }
-            return false;
+// only 8u
+void cvtBGR5x5toBGR(const uchar * src_data, size_t src_step,
+                    uchar * dst_data, size_t dst_step,
+                    int width, int height,
+                    int dcn, bool swapBlue, int greenBits)
+{
+    CV_INSTRUMENT_REGION()
 
-        case CV_GRAY2BGR: case CV_GRAY2BGRA:
-            if( dcn <= 0 ) dcn = (code==CV_GRAY2BGRA) ? 4 : 3;
-            CV_Assert( scn == 1 && (dcn == 3 || dcn == 4));
-            _dst.create(sz, CV_MAKETYPE(depth, dcn));
-            dst = _dst.getMat();
+    CALL_HAL(cvtBGR5x5toBGR, cv_hal_cvtBGR5x5toBGR, src_data, src_step, dst_data, dst_step, width, height, dcn, swapBlue, greenBits);
 
-            if( code == CV_GRAY2BGR )
-            {
-                if( CvtColorIPPLoop(src, dst, IPPGray2BGRFunctor(ippiCopyP3C3RTab[depth])) )
-                    return true;
-            }
-            else if( code == CV_GRAY2BGRA )
-            {
-                if( CvtColorIPPLoop(src, dst, IPPGray2BGRAFunctor(ippiCopyP3C3RTab[depth], ippiSwapChannelsC3C4RTab[depth], depth)) )
-                    return true;
-            }
-            return false;
+#if defined(HAVE_IPP) && IPP_VERSION_X100 < 900
+    CV_IPP_CHECK()
+    {
+    CV_SUPPRESS_DEPRECATED_START;
+    if (dcn == 3 && greenBits == 6 && !swapBlue)
+    {
+        if (CvtColorIPPLoop(src_data, src_step, dst_data, dst_step, width, height,
+                            IPPGeneralFunctor((ippiGeneralFunc)ippiBGR565ToBGR_16u8u_C3R)))
+            return;
+    }
+    else if (dcn == 3 && greenBits == 6 && swapBlue)
+    {
+        if (CvtColorIPPLoop(src_data, src_step, dst_data, dst_step, width, height,
+                            IPPGeneralReorderFunctor((ippiGeneralFunc)ippiBGR565ToBGR_16u8u_C3R,
+                                                     ippiSwapChannelsC3RTab[CV_8U], 2, 1, 0, CV_8U)))
+            return;
+    }
+    else if (dcn == 4 && greenBits == 6 && !swapBlue)
+    {
+        if (CvtColorIPPLoop(src_data, src_step, dst_data, dst_step, width, height,
+                            IPPGeneralReorderFunctor((ippiGeneralFunc)ippiBGR565ToBGR_16u8u_C3R,
+                                                     ippiSwapChannelsC3C4RTab[CV_8U], 0, 1, 2, CV_8U)))
+            return;
+    }
+    else if (dcn == 4 && greenBits == 6 && swapBlue)
+    {
+        if (CvtColorIPPLoop(src_data, src_step, dst_data, dst_step, width, height,
+                            IPPGeneralReorderFunctor((ippiGeneralFunc)ippiBGR565ToBGR_16u8u_C3R,
+                                                     ippiSwapChannelsC3C4RTab[CV_8U], 2, 1, 0, CV_8U)))
+            return;
+    }
+    CV_SUPPRESS_DEPRECATED_END;
+    }
 #endif
 
-#if IPP_DISABLE_BLOCK
-        case CV_BGR2YCrCb: case CV_RGB2YCrCb:
-        case CV_BGR2YUV: case CV_RGB2YUV:
-        {
-            CV_Assert( scn == 3 || scn == 4 );
-            static const float yuv_f[] = { 0.114f, 0.587f, 0.299f, 0.492f, 0.877f };
-            static const int yuv_i[] = { B2Y, G2Y, R2Y, 8061, 14369 };
-            const float* coeffs_f = code == CV_BGR2YCrCb || code == CV_RGB2YCrCb ? 0 : yuv_f;
-            const int* coeffs_i = code == CV_BGR2YCrCb || code == CV_RGB2YCrCb ? 0 : yuv_i;
+    CvtColorLoop(src_data, src_step, dst_data, dst_step, width, height, RGB5x52RGB(dcn, swapBlue ? 2 : 0, greenBits));
+}
 
-            _dst.create(sz, CV_MAKETYPE(depth, 3));
-            dst = _dst.getMat();
+// 8u, 16u, 32f
+void cvtBGRtoGray(const uchar * src_data, size_t src_step,
+                  uchar * dst_data, size_t dst_step,
+                  int width, int height,
+                  int depth, int scn, bool swapBlue)
+{
+    CV_INSTRUMENT_REGION()
 
-            if (code == CV_RGB2YUV && scn == 3 && depth == CV_8U)
-            {
-                if (CvtColorIPPLoop(src, dst, IPPGeneralFunctor((ippiGeneralFunc)ippiRGBToYUV_8u_C3R)))
-                    return true;
-            }
-            else if (code == CV_BGR2YUV && scn == 3 && depth == CV_8U)
-            {
-                if (CvtColorIPPLoop(src, dst, IPPReorderGeneralFunctor(ippiSwapChannelsC3RTab[depth],
-                                                                        (ippiGeneralFunc)ippiRGBToYUV_8u_C3R, 2, 1, 0, depth)))
-                    return true;
-            }
-            else if (code == CV_RGB2YUV && scn == 4 && depth == CV_8U)
-            {
-                if (CvtColorIPPLoop(src, dst, IPPReorderGeneralFunctor(ippiSwapChannelsC4C3RTab[depth],
-                                                                        (ippiGeneralFunc)ippiRGBToYUV_8u_C3R, 0, 1, 2, depth)))
-                    return true;
-            }
-            else if (code == CV_BGR2YUV && scn == 4 && depth == CV_8U)
-            {
-                if (CvtColorIPPLoop(src, dst, IPPReorderGeneralFunctor(ippiSwapChannelsC4C3RTab[depth],
-                                                                        (ippiGeneralFunc)ippiRGBToYUV_8u_C3R, 2, 1, 0, depth)))
-                    return true;
-            }
-            return false;
-        }
+    CALL_HAL(cvtBGRtoGray, cv_hal_cvtBGRtoGray, src_data, src_step, dst_data, dst_step, width, height, depth, scn, swapBlue);
+
+#if defined(HAVE_IPP) && IPP_VERSION_X100 >= 700
+    CV_IPP_CHECK()
+    {
+    if(depth == CV_32F && scn == 3 && !swapBlue)
+    {
+        if( CvtColorIPPLoop(src_data, src_step, dst_data, dst_step, width, height,
+                            IPPColor2GrayFunctor(ippiColor2GrayC3Tab[depth])) )
+            return;
+    }
+    else if(depth == CV_32F && scn == 3 && swapBlue)
+    {
+        if( CvtColorIPPLoop(src_data, src_step, dst_data, dst_step, width, height,
+                            IPPGeneralFunctor(ippiRGB2GrayC3Tab[depth])) )
+            return;
+    }
+    else if(depth == CV_32F && scn == 4 && !swapBlue)
+    {
+        if( CvtColorIPPLoop(src_data, src_step, dst_data, dst_step, width, height,
+                            IPPColor2GrayFunctor(ippiColor2GrayC4Tab[depth])) )
+            return;
+    }
+    else if(depth == CV_32F && scn == 4 && swapBlue)
+    {
+        if( CvtColorIPPLoop(src_data, src_step, dst_data, dst_step, width, height,
+                            IPPGeneralFunctor(ippiRGB2GrayC4Tab[depth])) )
+            return;
+    }
+    }
 #endif
 
-#if IPP_DISABLE_BLOCK
-        case CV_YCrCb2BGR: case CV_YCrCb2RGB:
-        case CV_YUV2BGR: case CV_YUV2RGB:
-        {
-            if( dcn <= 0 ) dcn = 3;
-            CV_Assert( scn == 3 && (dcn == 3 || dcn == 4) );
-            static const float yuv_f[] = { 2.032f, -0.395f, -0.581f, 1.140f };
-            static const int yuv_i[] = { 33292, -6472, -9519, 18678 };
-            const float* coeffs_f = code == CV_YCrCb2BGR || code == CV_YCrCb2RGB ? 0 : yuv_f;
-            const int* coeffs_i = code == CV_YCrCb2BGR || code == CV_YCrCb2RGB ? 0 : yuv_i;
+    int blueIdx = swapBlue ? 2 : 0;
+    if( depth == CV_8U )
+        CvtColorLoop(src_data, src_step, dst_data, dst_step, width, height, RGB2Gray<uchar>(scn, blueIdx, 0));
+    else if( depth == CV_16U )
+        CvtColorLoop(src_data, src_step, dst_data, dst_step, width, height, RGB2Gray<ushort>(scn, blueIdx, 0));
+    else
+        CvtColorLoop(src_data, src_step, dst_data, dst_step, width, height, RGB2Gray<float>(scn, blueIdx, 0));
+}
 
-            _dst.create(sz, CV_MAKETYPE(depth, dcn));
-            dst = _dst.getMat();
+// 8u, 16u, 32f
+void cvtGraytoBGR(const uchar * src_data, size_t src_step,
+                  uchar * dst_data, size_t dst_step,
+                  int width, int height,
+                  int depth, int dcn)
+{
+    CV_INSTRUMENT_REGION()
 
-            if (code == CV_YUV2RGB && dcn == 3 && depth == CV_8U)
-            {
-                if (CvtColorIPPLoop(src, dst, IPPGeneralFunctor((ippiGeneralFunc)ippiYUVToRGB_8u_C3R)))
-                    return true;
-            }
-            else if (code == CV_YUV2BGR && dcn == 3 && depth == CV_8U)
-            {
-                if (CvtColorIPPLoop(src, dst, IPPGeneralReorderFunctor((ippiGeneralFunc)ippiYUVToRGB_8u_C3R,
-                                                                        ippiSwapChannelsC3RTab[depth], 2, 1, 0, depth)))
-                    return true;
-            }
-            else if (code == CV_YUV2RGB && dcn == 4 && depth == CV_8U)
-            {
-                if (CvtColorIPPLoop(src, dst, IPPGeneralReorderFunctor((ippiGeneralFunc)ippiYUVToRGB_8u_C3R,
-                                                                        ippiSwapChannelsC3C4RTab[depth], 0, 1, 2, depth)))
-                    return true;
-            }
-            else if (code == CV_YUV2BGR && dcn == 4 && depth == CV_8U)
-            {
-                if (CvtColorIPPLoop(src, dst, IPPGeneralReorderFunctor((ippiGeneralFunc)ippiYUVToRGB_8u_C3R,
-                                                                        ippiSwapChannelsC3C4RTab[depth], 2, 1, 0, depth)))
-                    return true;
-            }
-            return false;
-        }
+    CALL_HAL(cvtGraytoBGR, cv_hal_cvtGraytoBGR, src_data, src_step, dst_data, dst_step, width, height, depth, dcn);
+
+#if defined(HAVE_IPP) && IPP_VERSION_X100 >= 700
+    CV_IPP_CHECK()
+    {
+    if(dcn == 3)
+    {
+        if( CvtColorIPPLoop(src_data, src_step, dst_data, dst_step, width, height,
+                            IPPGray2BGRFunctor(ippiCopyP3C3RTab[depth])) )
+            return;
+    }
+    else if(dcn == 4)
+    {
+        if( CvtColorIPPLoop(src_data, src_step, dst_data, dst_step, width, height,
+                            IPPGray2BGRAFunctor(ippiCopyP3C3RTab[depth], ippiSwapChannelsC3C4RTab[depth], depth)) )
+            return;
+    }
+    }
 #endif
 
-#if IPP_VERSION_X100 >= 700
-        case CV_BGR2XYZ: case CV_RGB2XYZ:
-            CV_Assert( scn == 3 || scn == 4 );
-            _dst.create(sz, CV_MAKETYPE(depth, 3));
-            dst = _dst.getMat();
+    if( depth == CV_8U )
+        CvtColorLoop(src_data, src_step, dst_data, dst_step, width, height, Gray2RGB<uchar>(dcn));
+    else if( depth == CV_16U )
+        CvtColorLoop(src_data, src_step, dst_data, dst_step, width, height, Gray2RGB<ushort>(dcn));
+    else
+        CvtColorLoop(src_data, src_step, dst_data, dst_step, width, height, Gray2RGB<float>(dcn));
+}
 
-            if( code == CV_BGR2XYZ && scn == 3 && depth != CV_32F )
-            {
-                if( CvtColorIPPLoopCopy(src, dst, IPPReorderGeneralFunctor(ippiSwapChannelsC3RTab[depth], ippiRGB2XYZTab[depth], 2, 1, 0, depth)) )
-                    return true;
-            }
-            else if( code == CV_BGR2XYZ && scn == 4 && depth != CV_32F )
-            {
-                if( CvtColorIPPLoop(src, dst, IPPReorderGeneralFunctor(ippiSwapChannelsC4C3RTab[depth], ippiRGB2XYZTab[depth], 2, 1, 0, depth)) )
-                    return true;
-            }
-            else if( code == CV_RGB2XYZ && scn == 3 && depth != CV_32F )
-            {
-                if( CvtColorIPPLoopCopy(src, dst, IPPGeneralFunctor(ippiRGB2XYZTab[depth])) )
-                    return true;
-            }
-            else if( code == CV_RGB2XYZ && scn == 4 && depth != CV_32F )
-            {
-                if( CvtColorIPPLoop(src, dst, IPPReorderGeneralFunctor(ippiSwapChannelsC4C3RTab[depth], ippiRGB2XYZTab[depth], 0, 1, 2, depth)) )
-                    return true;
-            }
-            return false;
-#endif
+// only 8u
+void cvtBGR5x5toGray(const uchar * src_data, size_t src_step,
+                     uchar * dst_data, size_t dst_step,
+                     int width, int height,
+                     int greenBits)
+{
+    CV_INSTRUMENT_REGION()
 
-#if IPP_VERSION_X100 >= 700
-        case CV_XYZ2BGR: case CV_XYZ2RGB:
-            if( dcn <= 0 ) dcn = 3;
-            CV_Assert( scn == 3 && (dcn == 3 || dcn == 4) );
+    CALL_HAL(cvtBGR5x5toGray, cv_hal_cvtBGR5x5toGray, src_data, src_step, dst_data, dst_step, width, height, greenBits);
+    CvtColorLoop(src_data, src_step, dst_data, dst_step, width, height, RGB5x52Gray(greenBits));
+}
 
-            _dst.create(sz, CV_MAKETYPE(depth, dcn));
-            dst = _dst.getMat();
+// only 8u
+void cvtGraytoBGR5x5(const uchar * src_data, size_t src_step,
+                     uchar * dst_data, size_t dst_step,
+                     int width, int height,
+                     int greenBits)
+{
+    CV_INSTRUMENT_REGION()
 
-            if( code == CV_XYZ2BGR && dcn == 3 && depth != CV_32F )
-            {
-                if( CvtColorIPPLoopCopy(src, dst, IPPGeneralReorderFunctor(ippiXYZ2RGBTab[depth], ippiSwapChannelsC3RTab[depth], 2, 1, 0, depth)) )
-                    return true;
-            }
-            else if( code == CV_XYZ2BGR && dcn == 4 && depth != CV_32F )
-            {
-                if( CvtColorIPPLoop(src, dst, IPPGeneralReorderFunctor(ippiXYZ2RGBTab[depth], ippiSwapChannelsC3C4RTab[depth], 2, 1, 0, depth)) )
-                    return true;
-            }
-            if( code == CV_XYZ2RGB && dcn == 3 && depth != CV_32F )
-            {
-                if( CvtColorIPPLoopCopy(src, dst, IPPGeneralFunctor(ippiXYZ2RGBTab[depth])) )
-                    return true;
-            }
-            else if( code == CV_XYZ2RGB && dcn == 4 && depth != CV_32F )
-            {
-                if( CvtColorIPPLoop(src, dst, IPPGeneralReorderFunctor(ippiXYZ2RGBTab[depth], ippiSwapChannelsC3C4RTab[depth], 0, 1, 2, depth)) )
-                    return true;
-            }
-            return false;
-#endif
+    CALL_HAL(cvtGraytoBGR5x5, cv_hal_cvtGraytoBGR5x5, src_data, src_step, dst_data, dst_step, width, height, greenBits);
+    CvtColorLoop(src_data, src_step, dst_data, dst_step, width, height, Gray2RGB5x5(greenBits));
+}
 
-#if IPP_VERSION_X100 >= 700
-        case CV_BGR2HSV: case CV_RGB2HSV: case CV_BGR2HSV_FULL: case CV_RGB2HSV_FULL:
-        case CV_BGR2HLS: case CV_RGB2HLS: case CV_BGR2HLS_FULL: case CV_RGB2HLS_FULL:
-        {
-            CV_Assert( (scn == 3 || scn == 4) && (depth == CV_8U || depth == CV_32F) );
-            _dst.create(sz, CV_MAKETYPE(depth, 3));
-            dst = _dst.getMat();
+// 8u, 16u, 32f
+void cvtBGRtoYUV(const uchar * src_data, size_t src_step,
+                 uchar * dst_data, size_t dst_step,
+                 int width, int height,
+                 int depth, int scn, bool swapBlue, bool isCbCr)
+{
+    CV_INSTRUMENT_REGION()
 
-            if( depth == CV_8U || depth == CV_16U )
-            {
-#if IPP_DISABLE_BLOCK // breaks OCL accuracy tests
-                if( code == CV_BGR2HSV_FULL && scn == 3 )
-                {
-                    if( CvtColorIPPLoopCopy(src, dst, IPPReorderGeneralFunctor(ippiSwapChannelsC3RTab[depth], ippiRGB2HSVTab[depth], 2, 1, 0, depth)) )
-                        return true;
-                }
-                else if( code == CV_BGR2HSV_FULL && scn == 4 )
-                {
-                    if( CvtColorIPPLoop(src, dst, IPPReorderGeneralFunctor(ippiSwapChannelsC4C3RTab[depth], ippiRGB2HSVTab[depth], 2, 1, 0, depth)) )
-                        return true;
-                }
-                else if( code == CV_RGB2HSV_FULL && scn == 4 )
-                {
-                    if( CvtColorIPPLoop(src, dst, IPPReorderGeneralFunctor(ippiSwapChannelsC4C3RTab[depth], ippiRGB2HSVTab[depth], 0, 1, 2, depth)) )
-                        return true;
-                } else
+    CALL_HAL(cvtBGRtoYUV, cv_hal_cvtBGRtoYUV, src_data, src_step, dst_data, dst_step, width, height, depth, scn, swapBlue, isCbCr);
+
+#if defined(HAVE_IPP) && IPP_DISABLE_BLOCK
+    CV_IPP_CHECK()
+    {
+    if (scn == 3 && depth == CV_8U && swapBlue && !isCbCr)
+    {
+        if (CvtColorIPPLoop(src_data, src_step, dst_data, dst_step, width, height,
+                            IPPGeneralFunctor((ippiGeneralFunc)ippiRGBToYUV_8u_C3R)))
+            return;
+    }
+    else if (scn == 3 && depth == CV_8U && !swapBlue && !isCbCr)
+    {
+        if (CvtColorIPPLoop(src_data, src_step, dst_data, dst_step, width, height,
+                            IPPReorderGeneralFunctor(ippiSwapChannelsC3RTab[depth],
+                                                     (ippiGeneralFunc)ippiRGBToYUV_8u_C3R, 2, 1, 0, depth)))
+            return;
+    }
+    else if (scn == 4 && depth == CV_8U && swapBlue && !isCbCr)
+    {
+        if (CvtColorIPPLoop(src_data, src_step, dst_data, dst_step, width, height,
+                            IPPReorderGeneralFunctor(ippiSwapChannelsC4C3RTab[depth],
+                                                     (ippiGeneralFunc)ippiRGBToYUV_8u_C3R, 0, 1, 2, depth)))
+            return;
+    }
+    else if (scn == 4 && depth == CV_8U && !swapBlue && !isCbCr)
+    {
+        if (CvtColorIPPLoop(src_data, src_step, dst_data, dst_step, width, height,
+                            IPPReorderGeneralFunctor(ippiSwapChannelsC4C3RTab[depth],
+                                                     (ippiGeneralFunc)ippiRGBToYUV_8u_C3R, 2, 1, 0, depth)))
+            return;
+    }
+    }
 #endif
-                if( code == CV_RGB2HSV_FULL && scn == 3 && depth == CV_16U )
-                {
-                    if( CvtColorIPPLoopCopy(src, dst, IPPGeneralFunctor(ippiRGB2HSVTab[depth])) )
-                        return true;
-                }
-                else if( code == CV_BGR2HLS_FULL && scn == 3 )
-                {
-                    if( CvtColorIPPLoopCopy(src, dst, IPPReorderGeneralFunctor(ippiSwapChannelsC3RTab[depth], ippiRGB2HLSTab[depth], 2, 1, 0, depth)) )
-                        return true;
-                }
-                else if( code == CV_BGR2HLS_FULL && scn == 4 )
-                {
-                    if( CvtColorIPPLoop(src, dst, IPPReorderGeneralFunctor(ippiSwapChannelsC4C3RTab[depth], ippiRGB2HLSTab[depth], 2, 1, 0, depth)) )
-                        return true;
-                }
-                else if( code == CV_RGB2HLS_FULL && scn == 3 )
-                {
-                    if( CvtColorIPPLoopCopy(src, dst, IPPGeneralFunctor(ippiRGB2HLSTab[depth])) )
-                        return true;
-                }
-                else if( code == CV_RGB2HLS_FULL && scn == 4 )
-                {
-                    if( CvtColorIPPLoop(src, dst, IPPReorderGeneralFunctor(ippiSwapChannelsC4C3RTab[depth], ippiRGB2HLSTab[depth], 0, 1, 2, depth)) )
-                        return true;
-                }
+
+    int blueIdx = swapBlue ? 2 : 0;
+    if( depth == CV_8U )
+        CvtColorLoop(src_data, src_step, dst_data, dst_step, width, height, RGB2YCrCb_i<uchar>(scn, blueIdx, isCbCr));
+    else if( depth == CV_16U )
+        CvtColorLoop(src_data, src_step, dst_data, dst_step, width, height, RGB2YCrCb_i<ushort>(scn, blueIdx, isCbCr));
+    else
+        CvtColorLoop(src_data, src_step, dst_data, dst_step, width, height, RGB2YCrCb_f<float>(scn, blueIdx, isCbCr));
+}
+
+void cvtYUVtoBGR(const uchar * src_data, size_t src_step,
+                 uchar * dst_data, size_t dst_step,
+                 int width, int height,
+                 int depth, int dcn, bool swapBlue, bool isCbCr)
+{
+    CV_INSTRUMENT_REGION()
+
+    CALL_HAL(cvtYUVtoBGR, cv_hal_cvtYUVtoBGR, src_data, src_step, dst_data, dst_step, width, height, depth, dcn, swapBlue, isCbCr);
+
+
+#if defined(HAVE_IPP) && IPP_DISABLE_BLOCK
+    CV_IPP_CHECK()
+    {
+    if (dcn == 3 && depth == CV_8U && swapBlue && !isCbCr)
+    {
+        if (CvtColorIPPLoop(src_data, src_step, dst_data, dst_step, width, height,
+                            IPPGeneralFunctor((ippiGeneralFunc)ippiYUVToRGB_8u_C3R)))
+            return;
+    }
+    else if (dcn == 3 && depth == CV_8U && !swapBlue && !isCbCr)
+    {
+        if (CvtColorIPPLoop(src_data, src_step, dst_data, dst_step, width, height,
+                            IPPGeneralReorderFunctor((ippiGeneralFunc)ippiYUVToRGB_8u_C3R,
+                                                               ippiSwapChannelsC3RTab[depth], 2, 1, 0, depth)))
+            return;
+    }
+    else if (dcn == 4 && depth == CV_8U && swapBlue && !isCbCr)
+    {
+        if (CvtColorIPPLoop(src_data, src_step, dst_data, dst_step, width, height,
+                            IPPGeneralReorderFunctor((ippiGeneralFunc)ippiYUVToRGB_8u_C3R,
+                                                               ippiSwapChannelsC3C4RTab[depth], 0, 1, 2, depth)))
+            return;
+    }
+    else if (dcn == 4 && depth == CV_8U && !swapBlue && !isCbCr)
+    {
+        if (CvtColorIPPLoop(src_data, src_step, dst_data, dst_step, width, height,
+                            IPPGeneralReorderFunctor((ippiGeneralFunc)ippiYUVToRGB_8u_C3R,
+                                                               ippiSwapChannelsC3C4RTab[depth], 2, 1, 0, depth)))
+            return;
+    }
+    }
+#endif
+
+    int blueIdx = swapBlue ? 2 : 0;
+    if( depth == CV_8U )
+        CvtColorLoop(src_data, src_step, dst_data, dst_step, width, height, YCrCb2RGB_i<uchar>(dcn, blueIdx, isCbCr));
+    else if( depth == CV_16U )
+        CvtColorLoop(src_data, src_step, dst_data, dst_step, width, height, YCrCb2RGB_i<ushort>(dcn, blueIdx, isCbCr));
+    else
+        CvtColorLoop(src_data, src_step, dst_data, dst_step, width, height, YCrCb2RGB_f<float>(dcn, blueIdx, isCbCr));
+}
+
+void cvtBGRtoXYZ(const uchar * src_data, size_t src_step,
+                 uchar * dst_data, size_t dst_step,
+                 int width, int height,
+                 int depth, int scn, bool swapBlue)
+{
+    CV_INSTRUMENT_REGION()
+
+    CALL_HAL(cvtBGRtoXYZ, cv_hal_cvtBGRtoXYZ, src_data, src_step, dst_data, dst_step, width, height, depth, scn, swapBlue);
+
+#if defined(HAVE_IPP) && IPP_VERSION_X100 >= 700
+    CV_IPP_CHECK()
+    {
+    if(scn == 3 && depth != CV_32F && !swapBlue)
+    {
+        if( CvtColorIPPLoopCopy(src_data, src_step, CV_MAKETYPE(depth, scn), dst_data, dst_step, width, height,
+                                IPPReorderGeneralFunctor(ippiSwapChannelsC3RTab[depth], ippiRGB2XYZTab[depth], 2, 1, 0, depth)) )
+            return;
+    }
+    else if(scn == 4 && depth != CV_32F && !swapBlue)
+    {
+        if( CvtColorIPPLoop(src_data, src_step, dst_data, dst_step, width, height,
+                            IPPReorderGeneralFunctor(ippiSwapChannelsC4C3RTab[depth], ippiRGB2XYZTab[depth], 2, 1, 0, depth)) )
+            return;
+    }
+    else if(scn == 3 && depth != CV_32F && swapBlue)
+    {
+        if( CvtColorIPPLoopCopy(src_data, src_step, CV_MAKETYPE(depth, scn), dst_data, dst_step, width, height,
+                                IPPGeneralFunctor(ippiRGB2XYZTab[depth])) )
+            return;
+    }
+    else if(scn == 4 && depth != CV_32F && swapBlue)
+    {
+        if( CvtColorIPPLoop(src_data, src_step, dst_data, dst_step, width, height,
+                            IPPReorderGeneralFunctor(ippiSwapChannelsC4C3RTab[depth], ippiRGB2XYZTab[depth], 0, 1, 2, depth)) )
+            return;
+    }
+    }
+#endif
+
+    int blueIdx = swapBlue ? 2 : 0;
+    if( depth == CV_8U )
+        CvtColorLoop(src_data, src_step, dst_data, dst_step, width, height, RGB2XYZ_i<uchar>(scn, blueIdx, 0));
+    else if( depth == CV_16U )
+        CvtColorLoop(src_data, src_step, dst_data, dst_step, width, height, RGB2XYZ_i<ushort>(scn, blueIdx, 0));
+    else
+        CvtColorLoop(src_data, src_step, dst_data, dst_step, width, height, RGB2XYZ_f<float>(scn, blueIdx, 0));
+}
+
+void cvtXYZtoBGR(const uchar * src_data, size_t src_step,
+                 uchar * dst_data, size_t dst_step,
+                 int width, int height,
+                 int depth, int dcn, bool swapBlue)
+{
+    CV_INSTRUMENT_REGION()
+
+    CALL_HAL(cvtXYZtoBGR, cv_hal_cvtXYZtoBGR, src_data, src_step, dst_data, dst_step, width, height, depth, dcn, swapBlue);
+
+#if defined(HAVE_IPP) && IPP_VERSION_X100 >= 700
+    CV_IPP_CHECK()
+    {
+    if(dcn == 3 && depth != CV_32F && !swapBlue)
+    {
+        if( CvtColorIPPLoopCopy(src_data, src_step, CV_MAKETYPE(depth, 3), dst_data, dst_step, width, height,
+                                IPPGeneralReorderFunctor(ippiXYZ2RGBTab[depth], ippiSwapChannelsC3RTab[depth], 2, 1, 0, depth)) )
+            return;
+    }
+    else if(dcn == 4 && depth != CV_32F && !swapBlue)
+    {
+        if( CvtColorIPPLoop(src_data, src_step, dst_data, dst_step, width, height,
+                            IPPGeneralReorderFunctor(ippiXYZ2RGBTab[depth], ippiSwapChannelsC3C4RTab[depth], 2, 1, 0, depth)) )
+            return;
+    }
+    if(dcn == 3 && depth != CV_32F && swapBlue)
+    {
+        if( CvtColorIPPLoopCopy(src_data, src_step, CV_MAKETYPE(depth, 3), dst_data, dst_step, width, height,
+                                IPPGeneralFunctor(ippiXYZ2RGBTab[depth])) )
+            return;
+    }
+    else if(dcn == 4 && depth != CV_32F && swapBlue)
+    {
+        if( CvtColorIPPLoop(src_data, src_step, dst_data, dst_step, width, height,
+                            IPPGeneralReorderFunctor(ippiXYZ2RGBTab[depth], ippiSwapChannelsC3C4RTab[depth], 0, 1, 2, depth)) )
+            return;
+    }
+    }
+#endif
+
+    int blueIdx = swapBlue ? 2 : 0;
+    if( depth == CV_8U )
+        CvtColorLoop(src_data, src_step, dst_data, dst_step, width, height, XYZ2RGB_i<uchar>(dcn, blueIdx, 0));
+    else if( depth == CV_16U )
+        CvtColorLoop(src_data, src_step, dst_data, dst_step, width, height, XYZ2RGB_i<ushort>(dcn, blueIdx, 0));
+    else
+        CvtColorLoop(src_data, src_step, dst_data, dst_step, width, height, XYZ2RGB_f<float>(dcn, blueIdx, 0));
+}
+
+// 8u, 32f
+void cvtBGRtoHSV(const uchar * src_data, size_t src_step,
+                 uchar * dst_data, size_t dst_step,
+                 int width, int height,
+                 int depth, int scn, bool swapBlue, bool isFullRange, bool isHSV)
+{
+    CV_INSTRUMENT_REGION()
+
+    CALL_HAL(cvtBGRtoHSV, cv_hal_cvtBGRtoHSV, src_data, src_step, dst_data, dst_step, width, height, depth, scn, swapBlue, isFullRange, isHSV);
+
+#if defined(HAVE_IPP) && IPP_VERSION_X100 >= 700
+    CV_IPP_CHECK()
+    {
+    if (depth == CV_8U && isFullRange)
+    {
+        if (isHSV)
+        {
+#if IPP_DISABLE_BLOCK // breaks OCL accuracy tests
+            if(scn == 3 && !swapBlue)
+            {
+                if( CvtColorIPPLoopCopy(src_data, src_step, CV_MAKE_TYPE(depth, scn), dst_data, dst_step, width, height,
+                                        IPPReorderGeneralFunctor(ippiSwapChannelsC3RTab[depth], ippiRGB2HSVTab[depth], 2, 1, 0, depth)) )
+                    return;
             }
-            return false;
+            else if(scn == 4 && !swapBlue)
+            {
+                if( CvtColorIPPLoop(src_data, src_step, dst_data, dst_step, width, height,
+                                    IPPReorderGeneralFunctor(ippiSwapChannelsC4C3RTab[depth], ippiRGB2HSVTab[depth], 2, 1, 0, depth)) )
+                    return;
+            }
+            else if(scn == 4 && swapBlue)
+            {
+                if( CvtColorIPPLoop(src_data, src_step, dst_data, dst_step, width, height,
+                                    IPPReorderGeneralFunctor(ippiSwapChannelsC4C3RTab[depth], ippiRGB2HSVTab[depth], 0, 1, 2, depth)) )
+                    return;
+            }
+#endif
         }
+        else
+        {
+            if(scn == 3 && !swapBlue)
+            {
+                if( CvtColorIPPLoopCopy(src_data, src_step, CV_MAKE_TYPE(depth, scn), dst_data, dst_step, width, height,
+                                        IPPReorderGeneralFunctor(ippiSwapChannelsC3RTab[depth], ippiRGB2HLSTab[depth], 2, 1, 0, depth)) )
+                    return;
+            }
+            else if(scn == 4 && !swapBlue)
+            {
+                if( CvtColorIPPLoop(src_data, src_step, dst_data, dst_step, width, height,
+                                    IPPReorderGeneralFunctor(ippiSwapChannelsC4C3RTab[depth], ippiRGB2HLSTab[depth], 2, 1, 0, depth)) )
+                    return;
+            }
+            else if(scn == 3 && swapBlue)
+            {
+                if( CvtColorIPPLoopCopy(src_data, src_step, CV_MAKE_TYPE(depth, scn), dst_data, dst_step, width, height,
+                                        IPPGeneralFunctor(ippiRGB2HLSTab[depth])) )
+                    return;
+            }
+            else if(scn == 4 && swapBlue)
+            {
+                if( CvtColorIPPLoop(src_data, src_step, dst_data, dst_step, width, height,
+                                    IPPReorderGeneralFunctor(ippiSwapChannelsC4C3RTab[depth], ippiRGB2HLSTab[depth], 0, 1, 2, depth)) )
+                    return;
+            }
+        }
+    }
+    }
 #endif
 
-#if IPP_VERSION_X100 >= 700
-        case CV_HSV2BGR: case CV_HSV2RGB: case CV_HSV2BGR_FULL: case CV_HSV2RGB_FULL:
-        case CV_HLS2BGR: case CV_HLS2RGB: case CV_HLS2BGR_FULL: case CV_HLS2RGB_FULL:
-        {
-            if( dcn <= 0 ) dcn = 3;
-            CV_Assert( scn == 3 && (dcn == 3 || dcn == 4) && (depth == CV_8U || depth == CV_32F) );
-            _dst.create(sz, CV_MAKETYPE(depth, dcn));
-            dst = _dst.getMat();
+    int hrange = depth == CV_32F ? 360 : isFullRange ? 256 : 180;
+    int blueIdx = swapBlue ? 2 : 0;
+    if(isHSV)
+    {
+        if(depth == CV_8U)
+            CvtColorLoop(src_data, src_step, dst_data, dst_step, width, height, RGB2HSV_b(scn, blueIdx, hrange));
+        else
+            CvtColorLoop(src_data, src_step, dst_data, dst_step, width, height, RGB2HSV_f(scn, blueIdx, static_cast<float>(hrange)));
+    }
+    else
+    {
+        if( depth == CV_8U )
+            CvtColorLoop(src_data, src_step, dst_data, dst_step, width, height, RGB2HLS_b(scn, blueIdx, hrange));
+        else
+            CvtColorLoop(src_data, src_step, dst_data, dst_step, width, height, RGB2HLS_f(scn, blueIdx, static_cast<float>(hrange)));
+    }
+}
 
-            if( depth == CV_8U || depth == CV_16U )
+// 8u, 32f
+void cvtHSVtoBGR(const uchar * src_data, size_t src_step,
+                        uchar * dst_data, size_t dst_step,
+                        int width, int height,
+                        int depth, int dcn, bool swapBlue, bool isFullRange, bool isHSV)
+{
+    CV_INSTRUMENT_REGION()
+
+    CALL_HAL(cvtHSVtoBGR, cv_hal_cvtHSVtoBGR, src_data, src_step, dst_data, dst_step, width, height, depth, dcn, swapBlue, isFullRange, isHSV);
+
+#if defined(HAVE_IPP) && IPP_VERSION_X100 >= 700
+    CV_IPP_CHECK()
+    {
+    if (depth == CV_8U && isFullRange)
+    {
+        if (isHSV)
+        {
+            if(dcn == 3 && !swapBlue)
             {
-                if( code == CV_HSV2BGR_FULL && dcn == 3 )
-                {
-                    if( CvtColorIPPLoopCopy(src, dst, IPPGeneralReorderFunctor(ippiHSV2RGBTab[depth], ippiSwapChannelsC3RTab[depth], 2, 1, 0, depth)) )
-                        return true;
-                }
-                else if( code == CV_HSV2BGR_FULL && dcn == 4 )
-                {
-                    if( CvtColorIPPLoop(src, dst, IPPGeneralReorderFunctor(ippiHSV2RGBTab[depth], ippiSwapChannelsC3C4RTab[depth], 2, 1, 0, depth)) )
-                        return true;
-                }
-                else if( code == CV_HSV2RGB_FULL && dcn == 3 )
-                {
-                    if( CvtColorIPPLoopCopy(src, dst, IPPGeneralFunctor(ippiHSV2RGBTab[depth])) )
-                        return true;
-                }
-                else if( code == CV_HSV2RGB_FULL && dcn == 4 )
-                {
-                    if( CvtColorIPPLoop(src, dst, IPPGeneralReorderFunctor(ippiHSV2RGBTab[depth], ippiSwapChannelsC3C4RTab[depth], 0, 1, 2, depth)) )
-                        return true;
-                }
-                else if( code == CV_HLS2BGR_FULL && dcn == 3 )
-                {
-                    if( CvtColorIPPLoopCopy(src, dst, IPPGeneralReorderFunctor(ippiHLS2RGBTab[depth], ippiSwapChannelsC3RTab[depth], 2, 1, 0, depth)) )
-                        return true;
-                }
-                else if( code == CV_HLS2BGR_FULL && dcn == 4 )
-                {
-                    if( CvtColorIPPLoop(src, dst, IPPGeneralReorderFunctor(ippiHLS2RGBTab[depth], ippiSwapChannelsC3C4RTab[depth], 2, 1, 0, depth)) )
-                        return true;
-                }
-                else if( code == CV_HLS2RGB_FULL && dcn == 3 )
-                {
-                    if( CvtColorIPPLoopCopy(src, dst, IPPGeneralFunctor(ippiHLS2RGBTab[depth])) )
-                        return true;
-                }
-                else if( code == CV_HLS2RGB_FULL && dcn == 4 )
-                {
-                    if( CvtColorIPPLoop(src, dst, IPPGeneralReorderFunctor(ippiHLS2RGBTab[depth], ippiSwapChannelsC3C4RTab[depth], 0, 1, 2, depth)) )
-                        return true;
-                }
+                if( CvtColorIPPLoopCopy(src_data, src_step, CV_MAKETYPE(depth, 3), dst_data, dst_step, width, height,
+                                        IPPGeneralReorderFunctor(ippiHSV2RGBTab[depth], ippiSwapChannelsC3RTab[depth], 2, 1, 0, depth)) )
+                    return;
+            }
+            else if(dcn == 4 && !swapBlue)
+            {
+                if( CvtColorIPPLoop(src_data, src_step, dst_data, dst_step, width, height,
+                                    IPPGeneralReorderFunctor(ippiHSV2RGBTab[depth], ippiSwapChannelsC3C4RTab[depth], 2, 1, 0, depth)) )
+                    return;
+            }
+            else if(dcn == 3 && swapBlue)
+            {
+                if( CvtColorIPPLoopCopy(src_data, src_step, CV_MAKETYPE(depth, 3), dst_data, dst_step, width, height,
+                                        IPPGeneralFunctor(ippiHSV2RGBTab[depth])) )
+                    return;
+            }
+            else if(dcn == 4 && swapBlue)
+            {
+                if( CvtColorIPPLoop(src_data, src_step, dst_data, dst_step, width, height,
+                                    IPPGeneralReorderFunctor(ippiHSV2RGBTab[depth], ippiSwapChannelsC3C4RTab[depth], 0, 1, 2, depth)) )
+                    return;
             }
-            return false;
         }
+        else
+        {
+            if(dcn == 3 && !swapBlue)
+            {
+                if( CvtColorIPPLoopCopy(src_data, src_step, CV_MAKETYPE(depth, 3), dst_data, dst_step, width, height,
+                                        IPPGeneralReorderFunctor(ippiHLS2RGBTab[depth], ippiSwapChannelsC3RTab[depth], 2, 1, 0, depth)) )
+                    return;
+            }
+            else if(dcn == 4 && !swapBlue)
+            {
+                if( CvtColorIPPLoop(src_data, src_step, dst_data, dst_step, width, height,
+                                    IPPGeneralReorderFunctor(ippiHLS2RGBTab[depth], ippiSwapChannelsC3C4RTab[depth], 2, 1, 0, depth)) )
+                    return;
+            }
+            else if(dcn == 3 && swapBlue)
+            {
+                if( CvtColorIPPLoopCopy(src_data, src_step, CV_MAKETYPE(depth, 3), dst_data, dst_step, width, height,
+                                        IPPGeneralFunctor(ippiHLS2RGBTab[depth])) )
+                    return;
+            }
+            else if(dcn == 4 && swapBlue)
+            {
+                if( CvtColorIPPLoop(src_data, src_step, dst_data, dst_step, width, height,
+                                    IPPGeneralReorderFunctor(ippiHLS2RGBTab[depth], ippiSwapChannelsC3C4RTab[depth], 0, 1, 2, depth)) )
+                    return;
+            }
+        }
+    }
+    }
 #endif
 
-#if IPP_DISABLE_BLOCK
-        case CV_BGR2Lab: case CV_RGB2Lab: case CV_LBGR2Lab: case CV_LRGB2Lab:
-        case CV_BGR2Luv: case CV_RGB2Luv: case CV_LBGR2Luv: case CV_LRGB2Luv:
-        {
-            CV_Assert( (scn == 3 || scn == 4) && (depth == CV_8U || depth == CV_32F) );
-            bool srgb = code == CV_BGR2Lab || code == CV_RGB2Lab ||
-                        code == CV_BGR2Luv || code == CV_RGB2Luv;
+    int hrange = depth == CV_32F ? 360 : isFullRange ? 255 : 180;
+    int blueIdx = swapBlue ? 2 : 0;
+    if(isHSV)
+    {
+        if( depth == CV_8U )
+            CvtColorLoop(src_data, src_step, dst_data, dst_step, width, height, HSV2RGB_b(dcn, blueIdx, hrange));
+        else
+            CvtColorLoop(src_data, src_step, dst_data, dst_step, width, height, HSV2RGB_f(dcn, blueIdx, static_cast<float>(hrange)));
+    }
+    else
+    {
+        if( depth == CV_8U )
+            CvtColorLoop(src_data, src_step, dst_data, dst_step, width, height, HLS2RGB_b(dcn, blueIdx, hrange));
+        else
+            CvtColorLoop(src_data, src_step, dst_data, dst_step, width, height, HLS2RGB_f(dcn, blueIdx, static_cast<float>(hrange)));
+    }
+}
 
-            _dst.create(sz, CV_MAKETYPE(depth, 3));
-            dst = _dst.getMat();
+// 8u, 32f
+void cvtBGRtoLab(const uchar * src_data, size_t src_step,
+                 uchar * dst_data, size_t dst_step,
+                 int width, int height,
+                 int depth, int scn, bool swapBlue, bool isLab, bool srgb)
+{
+    CV_INSTRUMENT_REGION()
+
+    CALL_HAL(cvtBGRtoLab, cv_hal_cvtBGRtoLab, src_data, src_step, dst_data, dst_step, width, height, depth, scn, swapBlue, isLab, srgb);
 
-            if (code == CV_LBGR2Lab && scn == 3 && depth == CV_8U)
+#if defined(HAVE_IPP) && IPP_DISABLE_BLOCK
+    CV_IPP_CHECK()
+    {
+    if (!srgb)
+    {
+        if (isLab)
+        {
+            if (scn == 3 && depth == CV_8U && !swapBlue)
             {
-                if (CvtColorIPPLoop(src, dst, IPPGeneralFunctor((ippiGeneralFunc)ippiBGRToLab_8u_C3R)))
-                    return true;
+                if (CvtColorIPPLoop(src_data, src_step, dst_data,dst_step, width, height,
+                                    IPPGeneralFunctor((ippiGeneralFunc)ippiBGRToLab_8u_C3R)))
+                    return;
             }
-            else if (code == CV_LBGR2Lab && scn == 4 && depth == CV_8U)
+            else if (scn == 4 && depth == CV_8U && !swapBlue)
             {
-                if (CvtColorIPPLoop(src, dst, IPPReorderGeneralFunctor(ippiSwapChannelsC4C3RTab[depth],
-                                                                        (ippiGeneralFunc)ippiBGRToLab_8u_C3R, 0, 1, 2, depth)))
-                    return true;
+                if (CvtColorIPPLoop(src_data, src_step, dst_data,dst_step, width, height,
+                                    IPPReorderGeneralFunctor(ippiSwapChannelsC4C3RTab[depth],
+                                                             (ippiGeneralFunc)ippiBGRToLab_8u_C3R, 0, 1, 2, depth)))
+                    return;
             }
-            else
-            if (code == CV_LRGB2Lab && scn == 3 && depth == CV_8U) // slower than OpenCV
+            else if (scn == 3 && depth == CV_8U && swapBlue) // slower than OpenCV
             {
-                if (CvtColorIPPLoop(src, dst, IPPReorderGeneralFunctor(ippiSwapChannelsC3RTab[depth],
-                                                                        (ippiGeneralFunc)ippiBGRToLab_8u_C3R, 2, 1, 0, depth)))
-                    return true;
+                if (CvtColorIPPLoop(src_data, src_step, dst_data,dst_step, width, height,
+                                    IPPReorderGeneralFunctor(ippiSwapChannelsC3RTab[depth],
+                                                             (ippiGeneralFunc)ippiBGRToLab_8u_C3R, 2, 1, 0, depth)))
+                    return;
             }
-            else if (code == CV_LRGB2Lab && scn == 4 && depth == CV_8U) // slower than OpenCV
+            else if (scn == 4 && depth == CV_8U && swapBlue) // slower than OpenCV
             {
-                if (CvtColorIPPLoop(src, dst, IPPReorderGeneralFunctor(ippiSwapChannelsC4C3RTab[depth],
-                                                                        (ippiGeneralFunc)ippiBGRToLab_8u_C3R, 2, 1, 0, depth)))
-                    return true;
+                if (CvtColorIPPLoop(src_data, src_step, dst_data,dst_step, width, height,
+                                    IPPReorderGeneralFunctor(ippiSwapChannelsC4C3RTab[depth],
+                                                             (ippiGeneralFunc)ippiBGRToLab_8u_C3R, 2, 1, 0, depth)))
+                    return;
             }
-            else if (code == CV_LRGB2Luv && scn == 3)
+        }
+        else
+        {
+            if (scn == 3 && swapBlue)
             {
-                if (CvtColorIPPLoop(src, dst, IPPGeneralFunctor(ippiRGBToLUVTab[depth])))
-                    return true;
+                if (CvtColorIPPLoop(src_data, src_step, dst_data,dst_step, width, height,
+                                    IPPGeneralFunctor(ippiRGBToLUVTab[depth])))
+                    return;
             }
-            else if (code == CV_LRGB2Luv && scn == 4)
+            else if (scn == 4 && swapBlue)
             {
-                if (CvtColorIPPLoop(src, dst, IPPReorderGeneralFunctor(ippiSwapChannelsC4C3RTab[depth],
-                                                                        ippiRGBToLUVTab[depth], 0, 1, 2, depth)))
-                    return true;
+                if (CvtColorIPPLoop(src_data, src_step, dst_data,dst_step, width, height,
+                                    IPPReorderGeneralFunctor(ippiSwapChannelsC4C3RTab[depth],
+                                                             ippiRGBToLUVTab[depth], 0, 1, 2, depth)))
+                    return;
             }
-            else if (code == CV_LBGR2Luv && scn == 3)
+            else if (scn == 3 && !swapBlue)
             {
-                if (CvtColorIPPLoop(src, dst, IPPReorderGeneralFunctor(ippiSwapChannelsC3RTab[depth],
-                                                                        ippiRGBToLUVTab[depth], 2, 1, 0, depth)))
-                    return true;
+                if (CvtColorIPPLoop(src_data, src_step, dst_data,dst_step, width, height,
+                                    IPPReorderGeneralFunctor(ippiSwapChannelsC3RTab[depth],
+                                                             ippiRGBToLUVTab[depth], 2, 1, 0, depth)))
+                    return;
             }
-            else if (code == CV_LBGR2Luv && scn == 4)
+            else if (scn == 4 && !swapBlue)
             {
-                if (CvtColorIPPLoop(src, dst, IPPReorderGeneralFunctor(ippiSwapChannelsC4C3RTab[depth],
-                                                                        ippiRGBToLUVTab[depth], 2, 1, 0, depth)))
-                    return true;
+                if (CvtColorIPPLoop(src_data, src_step, dst_data,dst_step, width, height,
+                                    IPPReorderGeneralFunctor(ippiSwapChannelsC4C3RTab[depth],
+                                                             ippiRGBToLUVTab[depth], 2, 1, 0, depth)))
+                    return;
             }
-            return false;
         }
+    }
+    }
 #endif
 
-#if IPP_DISABLE_BLOCK
-        case CV_Lab2BGR: case CV_Lab2RGB: case CV_Lab2LBGR: case CV_Lab2LRGB:
-        case CV_Luv2BGR: case CV_Luv2RGB: case CV_Luv2LBGR: case CV_Luv2LRGB:
-        {
-            if( dcn <= 0 ) dcn = 3;
-            CV_Assert( scn == 3 && (dcn == 3 || dcn == 4) && (depth == CV_8U || depth == CV_32F) );
-            bool srgb = code == CV_Lab2BGR || code == CV_Lab2RGB ||
-                    code == CV_Luv2BGR || code == CV_Luv2RGB;
 
-            _dst.create(sz, CV_MAKETYPE(depth, dcn));
-            dst = _dst.getMat();
+    int blueIdx = swapBlue ? 2 : 0;
+    if(isLab)
+    {
+        if( depth == CV_8U )
+            CvtColorLoop(src_data, src_step, dst_data, dst_step, width, height, RGB2Lab_b(scn, blueIdx, 0, 0, srgb));
+        else
+            CvtColorLoop(src_data, src_step, dst_data, dst_step, width, height, RGB2Lab_f(scn, blueIdx, 0, 0, srgb));
+    }
+    else
+    {
+        if( depth == CV_8U )
+            CvtColorLoop(src_data, src_step, dst_data, dst_step, width, height, RGB2Luv_b(scn, blueIdx, 0, 0, srgb));
+        else
+            CvtColorLoop(src_data, src_step, dst_data, dst_step, width, height, RGB2Luv_f(scn, blueIdx, 0, 0, srgb));
+    }
+}
+
+// 8u, 32f
+void cvtLabtoBGR(const uchar * src_data, size_t src_step,
+                 uchar * dst_data, size_t dst_step,
+                 int width, int height,
+                 int depth, int dcn, bool swapBlue, bool isLab, bool srgb)
+{
+    CV_INSTRUMENT_REGION()
+
+    CALL_HAL(cvtLabtoBGR, cv_hal_cvtLabtoBGR, src_data, src_step, dst_data, dst_step, width, height, depth, dcn, swapBlue, isLab, srgb);
 
-            if( code == CV_Lab2LBGR && dcn == 3 && depth == CV_8U)
+#if defined(HAVE_IPP) && IPP_DISABLE_BLOCK
+    CV_IPP_CHECK()
+    {
+    if (!srgb)
+    {
+        if (isLab)
+        {
+            if( dcn == 3 && depth == CV_8U && !swapBlue)
             {
-                if( CvtColorIPPLoop(src, dst, IPPGeneralFunctor((ippiGeneralFunc)ippiLabToBGR_8u_C3R)) )
-                    return true;
+                if( CvtColorIPPLoop(src_data, src_step, dst_data,dst_step, width, height,
+                                    IPPGeneralFunctor((ippiGeneralFunc)ippiLabToBGR_8u_C3R)) )
+                    return;
             }
-            else if( code == CV_Lab2LBGR && dcn == 4 && depth == CV_8U )
+            else if( dcn == 4 && depth == CV_8U && !swapBlue)
             {
-                if( CvtColorIPPLoop(src, dst, IPPGeneralReorderFunctor((ippiGeneralFunc)ippiLabToBGR_8u_C3R,
-                                    ippiSwapChannelsC3C4RTab[depth], 0, 1, 2, depth)) )
-                    return true;
+                if( CvtColorIPPLoop(src_data, src_step, dst_data,dst_step, width, height,
+                                    IPPGeneralReorderFunctor((ippiGeneralFunc)ippiLabToBGR_8u_C3R,
+                                                             ippiSwapChannelsC3C4RTab[depth], 0, 1, 2, depth)) )
+                    return;
             }
-            if( code == CV_Lab2LRGB && dcn == 3 && depth == CV_8U )
+            if( dcn == 3 && depth == CV_8U && swapBlue)
             {
-                if( CvtColorIPPLoop(src, dst, IPPGeneralReorderFunctor((ippiGeneralFunc)ippiLabToBGR_8u_C3R,
-                                                                            ippiSwapChannelsC3RTab[depth], 2, 1, 0, depth)) )
-                    return true;
+                if( CvtColorIPPLoop(src_data, src_step, dst_data,dst_step, width, height,
+                                    IPPGeneralReorderFunctor((ippiGeneralFunc)ippiLabToBGR_8u_C3R,
+                                                             ippiSwapChannelsC3RTab[depth], 2, 1, 0, depth)) )
+                    return;
             }
-            else if( code == CV_Lab2LRGB && dcn == 4 && depth == CV_8U )
+            else if( dcn == 4 && depth == CV_8U && swapBlue)
             {
-                if( CvtColorIPPLoop(src, dst, IPPGeneralReorderFunctor((ippiGeneralFunc)ippiLabToBGR_8u_C3R,
-                                                                        ippiSwapChannelsC3C4RTab[depth], 2, 1, 0, depth)) )
-                    return true;
+                if( CvtColorIPPLoop(src_data, src_step, dst_data,dst_step, width, height,
+                                    IPPGeneralReorderFunctor((ippiGeneralFunc)ippiLabToBGR_8u_C3R,
+                                                             ippiSwapChannelsC3C4RTab[depth], 2, 1, 0, depth)) )
+                    return;
             }
-            if( code == CV_Luv2LRGB && dcn == 3 )
+        }
+        else
+        {
+            if( dcn == 3 && swapBlue)
             {
-                if( CvtColorIPPLoop(src, dst, IPPGeneralFunctor(ippiLUVToRGBTab[depth])) )
-                    return true;
+                if( CvtColorIPPLoop(src_data, src_step, dst_data,dst_step, width, height,
+                                    IPPGeneralFunctor(ippiLUVToRGBTab[depth])) )
+                    return;
             }
-            else if( code == CV_Luv2LRGB && dcn == 4 )
+            else if( dcn == 4 && swapBlue)
             {
-                if( CvtColorIPPLoop(src, dst, IPPGeneralReorderFunctor(ippiLUVToRGBTab[depth],
-                                                                        ippiSwapChannelsC3C4RTab[depth], 0, 1, 2, depth)) )
-                    return true;
+                if( CvtColorIPPLoop(src_data, src_step, dst_data,dst_step, width, height,
+                                    IPPGeneralReorderFunctor(ippiLUVToRGBTab[depth],
+                                                             ippiSwapChannelsC3C4RTab[depth], 0, 1, 2, depth)) )
+                    return;
             }
-            if( code == CV_Luv2LBGR && dcn == 3 )
+            if( dcn == 3 && !swapBlue)
             {
-                if( CvtColorIPPLoop(src, dst, IPPGeneralReorderFunctor(ippiLUVToRGBTab[depth],
-                                                                        ippiSwapChannelsC3RTab[depth], 2, 1, 0, depth)) )
-                    return true;
+                if( CvtColorIPPLoop(src_data, src_step, dst_data,dst_step, width, height,
+                                    IPPGeneralReorderFunctor(ippiLUVToRGBTab[depth],
+                                                             ippiSwapChannelsC3RTab[depth], 2, 1, 0, depth)) )
+                    return;
             }
-            else if( code == CV_Luv2LBGR && dcn == 4 )
+            else if( dcn == 4 && !swapBlue)
             {
-                if( CvtColorIPPLoop(src, dst, IPPGeneralReorderFunctor(ippiLUVToRGBTab[depth],
-                                                                        ippiSwapChannelsC3C4RTab[depth], 2, 1, 0, depth)) )
-                    return true;
+                if( CvtColorIPPLoop(src_data, src_step, dst_data,dst_step, width, height,
+                                    IPPGeneralReorderFunctor(ippiLUVToRGBTab[depth],
+                                                             ippiSwapChannelsC3C4RTab[depth], 2, 1, 0, depth)) )
+                    return;
             }
-            return false;
         }
+    }
+    }
+#endif
+
+    int blueIdx = swapBlue ? 2 : 0;
+    if(isLab)
+    {
+        if( depth == CV_8U )
+            CvtColorLoop(src_data, src_step, dst_data, dst_step, width, height, Lab2RGB_b(dcn, blueIdx, 0, 0, srgb));
+        else
+            CvtColorLoop(src_data, src_step, dst_data, dst_step, width, height, Lab2RGB_f(dcn, blueIdx, 0, 0, srgb));
+    }
+    else
+    {
+        if( depth == CV_8U )
+            CvtColorLoop(src_data, src_step, dst_data, dst_step, width, height, Luv2RGB_b(dcn, blueIdx, 0, 0, srgb));
+        else
+            CvtColorLoop(src_data, src_step, dst_data, dst_step, width, height, Luv2RGB_f(dcn, blueIdx, 0, 0, srgb));
+    }
+}
+
+void cvtTwoPlaneYUVtoBGR(const uchar * src_data, size_t src_step,
+                                uchar * dst_data, size_t dst_step,
+                                int dst_width, int dst_height,
+                                int dcn, bool swapBlue, int uIdx)
+{
+    CV_INSTRUMENT_REGION()
+
+    CALL_HAL(cvtTwoPlaneYUVtoBGR, cv_hal_cvtTwoPlaneYUVtoBGR, src_data, src_step, dst_data, dst_step, dst_width, dst_height, dcn, swapBlue, uIdx);
+    int blueIdx = swapBlue ? 2 : 0;
+    const uchar* uv = src_data + src_step * static_cast<size_t>(dst_height);
+    switch(dcn*100 + blueIdx * 10 + uIdx)
+    {
+    case 300: cvtYUV420sp2RGB<0, 0> (dst_data, dst_step, dst_width, dst_height, src_step, src_data, uv); break;
+    case 301: cvtYUV420sp2RGB<0, 1> (dst_data, dst_step, dst_width, dst_height, src_step, src_data, uv); break;
+    case 320: cvtYUV420sp2RGB<2, 0> (dst_data, dst_step, dst_width, dst_height, src_step, src_data, uv); break;
+    case 321: cvtYUV420sp2RGB<2, 1> (dst_data, dst_step, dst_width, dst_height, src_step, src_data, uv); break;
+    case 400: cvtYUV420sp2RGBA<0, 0>(dst_data, dst_step, dst_width, dst_height, src_step, src_data, uv); break;
+    case 401: cvtYUV420sp2RGBA<0, 1>(dst_data, dst_step, dst_width, dst_height, src_step, src_data, uv); break;
+    case 420: cvtYUV420sp2RGBA<2, 0>(dst_data, dst_step, dst_width, dst_height, src_step, src_data, uv); break;
+    case 421: cvtYUV420sp2RGBA<2, 1>(dst_data, dst_step, dst_width, dst_height, src_step, src_data, uv); break;
+    default: CV_Error( CV_StsBadFlag, "Unknown/unsupported color conversion code" ); break;
+    };
+}
+
+void cvtThreePlaneYUVtoBGR(const uchar * src_data, size_t src_step,
+                                  uchar * dst_data, size_t dst_step,
+                                  int dst_width, int dst_height,
+                                  int dcn, bool swapBlue, int uIdx)
+{
+    CV_INSTRUMENT_REGION()
+
+    CALL_HAL(cvtThreePlaneYUVtoBGR, cv_hal_cvtThreePlaneYUVtoBGR, src_data, src_step, dst_data, dst_step, dst_width, dst_height, dcn, swapBlue, uIdx);
+    const uchar* u = src_data + src_step * static_cast<size_t>(dst_height);
+    const uchar* v = src_data + src_step * static_cast<size_t>(dst_height + dst_height/4) + (dst_width/2) * ((dst_height % 4)/2);
+
+    int ustepIdx = 0;
+    int vstepIdx = dst_height % 4 == 2 ? 1 : 0;
+
+    if(uIdx == 1) { std::swap(u ,v), std::swap(ustepIdx, vstepIdx); }
+    int blueIdx = swapBlue ? 2 : 0;
+
+    switch(dcn*10 + blueIdx)
+    {
+    case 30: cvtYUV420p2RGB<0>(dst_data, dst_step, dst_width, dst_height, src_step, src_data, u, v, ustepIdx, vstepIdx); break;
+    case 32: cvtYUV420p2RGB<2>(dst_data, dst_step, dst_width, dst_height, src_step, src_data, u, v, ustepIdx, vstepIdx); break;
+    case 40: cvtYUV420p2RGBA<0>(dst_data, dst_step, dst_width, dst_height, src_step, src_data, u, v, ustepIdx, vstepIdx); break;
+    case 42: cvtYUV420p2RGBA<2>(dst_data, dst_step, dst_width, dst_height, src_step, src_data, u, v, ustepIdx, vstepIdx); break;
+    default: CV_Error( CV_StsBadFlag, "Unknown/unsupported color conversion code" ); break;
+    };
+}
+
+void cvtBGRtoThreePlaneYUV(const uchar * src_data, size_t src_step,
+                           uchar * dst_data, size_t dst_step,
+                           int width, int height,
+                           int scn, bool swapBlue, int uIdx)
+{
+    CV_INSTRUMENT_REGION()
+
+    CALL_HAL(cvtBGRtoThreePlaneYUV, cv_hal_cvtBGRtoThreePlaneYUV, src_data, src_step, dst_data, dst_step, width, height, scn, swapBlue, uIdx);
+    int blueIdx = swapBlue ? 2 : 0;
+    switch(blueIdx + uIdx*10)
+    {
+    case 10: cvtRGBtoYUV420p<0, 1>(src_data, src_step, dst_data, dst_step, width, height, scn); break;
+    case 12: cvtRGBtoYUV420p<2, 1>(src_data, src_step, dst_data, dst_step, width, height, scn); break;
+    case 20: cvtRGBtoYUV420p<0, 2>(src_data, src_step, dst_data, dst_step, width, height, scn); break;
+    case 22: cvtRGBtoYUV420p<2, 2>(src_data, src_step, dst_data, dst_step, width, height, scn); break;
+    default: CV_Error( CV_StsBadFlag, "Unknown/unsupported color conversion code" ); break;
+    };
+}
+
+void cvtOnePlaneYUVtoBGR(const uchar * src_data, size_t src_step,
+                         uchar * dst_data, size_t dst_step,
+                         int width, int height,
+                         int dcn, bool swapBlue, int uIdx, int ycn)
+{
+    CV_INSTRUMENT_REGION()
+
+    CALL_HAL(cvtOnePlaneYUVtoBGR, cv_hal_cvtOnePlaneYUVtoBGR, src_data, src_step, dst_data, dst_step, width, height, dcn, swapBlue, uIdx, ycn);
+    int blueIdx = swapBlue ? 2 : 0;
+    switch(dcn*1000 + blueIdx*100 + uIdx*10 + ycn)
+    {
+    case 3000: cvtYUV422toRGB<0,0,0>(dst_data, dst_step, src_data, src_step, width, height); break;
+    case 3001: cvtYUV422toRGB<0,0,1>(dst_data, dst_step, src_data, src_step, width, height); break;
+    case 3010: cvtYUV422toRGB<0,1,0>(dst_data, dst_step, src_data, src_step, width, height); break;
+    case 3200: cvtYUV422toRGB<2,0,0>(dst_data, dst_step, src_data, src_step, width, height); break;
+    case 3201: cvtYUV422toRGB<2,0,1>(dst_data, dst_step, src_data, src_step, width, height); break;
+    case 3210: cvtYUV422toRGB<2,1,0>(dst_data, dst_step, src_data, src_step, width, height); break;
+    case 4000: cvtYUV422toRGBA<0,0,0>(dst_data, dst_step, src_data, src_step, width, height); break;
+    case 4001: cvtYUV422toRGBA<0,0,1>(dst_data, dst_step, src_data, src_step, width, height); break;
+    case 4010: cvtYUV422toRGBA<0,1,0>(dst_data, dst_step, src_data, src_step, width, height); break;
+    case 4200: cvtYUV422toRGBA<2,0,0>(dst_data, dst_step, src_data, src_step, width, height); break;
+    case 4201: cvtYUV422toRGBA<2,0,1>(dst_data, dst_step, src_data, src_step, width, height); break;
+    case 4210: cvtYUV422toRGBA<2,1,0>(dst_data, dst_step, src_data, src_step, width, height); break;
+    default: CV_Error( CV_StsBadFlag, "Unknown/unsupported color conversion code" ); break;
+    };
+}
+
+void cvtRGBAtoMultipliedRGBA(const uchar * src_data, size_t src_step,
+                             uchar * dst_data, size_t dst_step,
+                             int width, int height)
+{
+    CV_INSTRUMENT_REGION()
+
+    CALL_HAL(cvtRGBAtoMultipliedRGBA, cv_hal_cvtRGBAtoMultipliedRGBA, src_data, src_step, dst_data, dst_step, width, height);
+
+#ifdef HAVE_IPP
+    CV_IPP_CHECK()
+    {
+    if (CvtColorIPPLoop(src_data, src_step, dst_data, dst_step, width, height,
+                        IPPGeneralFunctor((ippiGeneralFunc)ippiAlphaPremul_8u_AC4R)))
+        return;
+    }
 #endif
 
-        case CV_YUV2GRAY_420:
-        {
-            if (dcn <= 0) dcn = 1;
+    CvtColorLoop(src_data, src_step, dst_data, dst_step, width, height, RGBA2mRGBA<uchar>());
+}
 
-            CV_Assert( dcn == 1 );
-            CV_Assert( sz.width % 2 == 0 && sz.height % 3 == 0 && depth == CV_8U );
+void cvtMultipliedRGBAtoRGBA(const uchar * src_data, size_t src_step,
+                             uchar * dst_data, size_t dst_step,
+                             int width, int height)
+{
+    CV_INSTRUMENT_REGION()
 
-            Size dstSz(sz.width, sz.height * 2 / 3);
-            _dst.create(dstSz, CV_MAKETYPE(depth, dcn));
-            dst = _dst.getMat();
+    CALL_HAL(cvtMultipliedRGBAtoRGBA, cv_hal_cvtMultipliedRGBAtoRGBA, src_data, src_step, dst_data, dst_step, width, height);
+    CvtColorLoop(src_data, src_step, dst_data, dst_step, width, height, mRGBA2RGBA<uchar>());
+}
 
-            if (ippStsNoErr == ippiCopy_8u_C1R(src.data, (int)src.step, dst.data, (int)dst.step,
-                    ippiSize(dstSz.width, dstSz.height)))
-                return true;
-            return false;
-        }
+}} // cv::hal::
 
-        case CV_RGBA2mRGBA:
-        {
-            if (dcn <= 0) dcn = 4;
-            CV_Assert( scn == 4 && dcn == 4 );
+//
+// Helper functions
+//
 
-            _dst.create(sz, CV_MAKETYPE(depth, dcn));
-            dst = _dst.getMat();
+inline bool isHSV(int code)
+{
+    switch(code)
+    {
+    case CV_HSV2BGR: case CV_HSV2RGB: case CV_HSV2BGR_FULL: case CV_HSV2RGB_FULL:
+    case CV_BGR2HSV: case CV_RGB2HSV: case CV_BGR2HSV_FULL: case CV_RGB2HSV_FULL:
+        return true;
+    default:
+        return false;
+    }
+}
 
-            if( depth == CV_8U )
-            {
-                if (CvtColorIPPLoop(src, dst, IPPGeneralFunctor((ippiGeneralFunc)ippiAlphaPremul_8u_AC4R)))
-                    return true;
-                return false;
-            }
+inline bool isLab(int code)
+{
+    switch (code)
+    {
+    case CV_Lab2BGR: case CV_Lab2RGB: case CV_Lab2LBGR: case CV_Lab2LRGB:
+    case CV_BGR2Lab: case CV_RGB2Lab: case CV_LBGR2Lab: case CV_LRGB2Lab:
+        return true;
+    default:
+        return false;
+    }
+}
 
-            return false;
-        }
+inline bool issRGB(int code)
+{
+    switch (code)
+    {
+    case CV_BGR2Lab: case CV_RGB2Lab: case CV_BGR2Luv: case CV_RGB2Luv:
+    case CV_Lab2BGR: case CV_Lab2RGB: case CV_Luv2BGR: case CV_Luv2RGB:
+        return true;
+    default:
+        return false;
+    }
+}
 
-        default:
-            return false;
+inline bool swapBlue(int code)
+{
+    switch (code)
+    {
+    case CV_BGR2BGRA: case CV_BGRA2BGR:
+    case CV_BGR2BGR565: case CV_BGR2BGR555: case CV_BGRA2BGR565: case CV_BGRA2BGR555:
+    case CV_BGR5652BGR: case CV_BGR5552BGR: case CV_BGR5652BGRA: case CV_BGR5552BGRA:
+    case CV_BGR2GRAY: case CV_BGRA2GRAY:
+    case CV_BGR2YCrCb: case CV_BGR2YUV:
+    case CV_YCrCb2BGR: case CV_YUV2BGR:
+    case CV_BGR2XYZ: case CV_XYZ2BGR:
+    case CV_BGR2HSV: case CV_BGR2HLS: case CV_BGR2HSV_FULL: case CV_BGR2HLS_FULL:
+    case CV_YUV2BGR_YV12: case CV_YUV2BGRA_YV12: case CV_YUV2BGR_IYUV: case CV_YUV2BGRA_IYUV:
+    case CV_YUV2BGR_NV21: case CV_YUV2BGRA_NV21: case CV_YUV2BGR_NV12: case CV_YUV2BGRA_NV12:
+    case CV_Lab2BGR: case CV_Luv2BGR: case CV_Lab2LBGR: case CV_Luv2LBGR:
+    case CV_BGR2Lab: case CV_BGR2Luv: case CV_LBGR2Lab: case CV_LBGR2Luv:
+    case CV_HSV2BGR: case CV_HLS2BGR: case CV_HSV2BGR_FULL: case CV_HLS2BGR_FULL:
+    case CV_YUV2BGR_UYVY: case CV_YUV2BGRA_UYVY: case CV_YUV2BGR_YUY2:
+    case CV_YUV2BGRA_YUY2:  case CV_YUV2BGR_YVYU: case CV_YUV2BGRA_YVYU:
+    case CV_BGR2YUV_IYUV: case CV_BGRA2YUV_IYUV: case CV_BGR2YUV_YV12: case CV_BGRA2YUV_YV12:
+        return false;
+    default:
+        return true;
     }
 }
-#endif
+
+inline bool isFullRange(int code)
+{
+    switch (code)
+    {
+    case CV_BGR2HSV_FULL: case CV_RGB2HSV_FULL: case CV_BGR2HLS_FULL: case CV_RGB2HLS_FULL:
+    case CV_HSV2BGR_FULL: case CV_HSV2RGB_FULL: case CV_HLS2BGR_FULL: case CV_HLS2RGB_FULL:
+        return true;
+    default:
+        return false;
+    }
 }
 
 //////////////////////////////////////////////////////////////////////////////////////////
@@ -7924,105 +9693,71 @@ static bool ipp_cvtColor( Mat &src, OutputArray _dst, int code, int dcn )
 
 void cv::cvtColor( InputArray _src, OutputArray _dst, int code, int dcn )
 {
+    CV_INSTRUMENT_REGION()
+
     int stype = _src.type();
-    int scn = CV_MAT_CN(stype), depth = CV_MAT_DEPTH(stype), bidx;
+    int scn = CV_MAT_CN(stype), depth = CV_MAT_DEPTH(stype), uidx, gbits, ycn;
 
     CV_OCL_RUN( _src.dims() <= 2 && _dst.isUMat() && !(depth == CV_8U && (code == CV_Luv2BGR || code == CV_Luv2RGB)),
                 ocl_cvtColor(_src, _dst, code, dcn) )
 
-    Mat src = _src.getMat(), dst;
+    Mat src, dst;
+    if (_src.getObj() == _dst.getObj()) // inplace processing (#6653)
+        _src.copyTo(src);
+    else
+        src = _src.getMat();
     Size sz = src.size();
     CV_Assert( depth == CV_8U || depth == CV_16U || depth == CV_32F );
 
-    CV_IPP_RUN(true, ipp_cvtColor(src, _dst, code, dcn));
-
     switch( code )
     {
         case CV_BGR2BGRA: case CV_RGB2BGRA: case CV_BGRA2BGR:
         case CV_RGBA2BGR: case CV_RGB2BGR: case CV_BGRA2RGBA:
             CV_Assert( scn == 3 || scn == 4 );
             dcn = code == CV_BGR2BGRA || code == CV_RGB2BGRA || code == CV_BGRA2RGBA ? 4 : 3;
-            bidx = code == CV_BGR2BGRA || code == CV_BGRA2BGR ? 0 : 2;
-
             _dst.create( sz, CV_MAKETYPE(depth, dcn));
             dst = _dst.getMat();
-
-            if( depth == CV_8U )
-            {
-#ifdef HAVE_TEGRA_OPTIMIZATION
-                if(tegra::useTegra() && tegra::cvtBGR2RGB(src, dst, bidx))
-                    break;
-#endif
-                CvtColorLoop(src, dst, RGB2RGB<uchar>(scn, dcn, bidx));
-            }
-            else if( depth == CV_16U )
-                CvtColorLoop(src, dst, RGB2RGB<ushort>(scn, dcn, bidx));
-            else
-                CvtColorLoop(src, dst, RGB2RGB<float>(scn, dcn, bidx));
+            hal::cvtBGRtoBGR(src.data, src.step, dst.data, dst.step, src.cols, src.rows,
+                             depth, scn, dcn, swapBlue(code));
             break;
 
         case CV_BGR2BGR565: case CV_BGR2BGR555: case CV_RGB2BGR565: case CV_RGB2BGR555:
         case CV_BGRA2BGR565: case CV_BGRA2BGR555: case CV_RGBA2BGR565: case CV_RGBA2BGR555:
             CV_Assert( (scn == 3 || scn == 4) && depth == CV_8U );
+            gbits = code == CV_BGR2BGR565 || code == CV_RGB2BGR565 ||
+                    code == CV_BGRA2BGR565 || code == CV_RGBA2BGR565 ? 6 : 5;
             _dst.create(sz, CV_8UC2);
             dst = _dst.getMat();
-
-#ifdef HAVE_TEGRA_OPTIMIZATION
-            if(code == CV_BGR2BGR565 || code == CV_BGRA2BGR565 || code == CV_RGB2BGR565  || code == CV_RGBA2BGR565)
-                if(tegra::useTegra() && tegra::cvtRGB2RGB565(src, dst, code == CV_RGB2BGR565 || code == CV_RGBA2BGR565 ? 0 : 2))
-                    break;
-#endif
-
-            CvtColorLoop(src, dst, RGB2RGB5x5(scn,
-                      code == CV_BGR2BGR565 || code == CV_BGR2BGR555 ||
-                      code == CV_BGRA2BGR565 || code == CV_BGRA2BGR555 ? 0 : 2,
-                      code == CV_BGR2BGR565 || code == CV_RGB2BGR565 ||
-                      code == CV_BGRA2BGR565 || code == CV_RGBA2BGR565 ? 6 : 5 // green bits
-                                              ));
+            hal::cvtBGRtoBGR5x5(src.data, src.step, dst.data, dst.step, src.cols, src.rows,
+                                scn, swapBlue(code), gbits);
             break;
 
         case CV_BGR5652BGR: case CV_BGR5552BGR: case CV_BGR5652RGB: case CV_BGR5552RGB:
         case CV_BGR5652BGRA: case CV_BGR5552BGRA: case CV_BGR5652RGBA: case CV_BGR5552RGBA:
             if(dcn <= 0) dcn = (code==CV_BGR5652BGRA || code==CV_BGR5552BGRA || code==CV_BGR5652RGBA || code==CV_BGR5552RGBA) ? 4 : 3;
             CV_Assert( (dcn == 3 || dcn == 4) && scn == 2 && depth == CV_8U );
+            gbits = code == CV_BGR5652BGR || code == CV_BGR5652RGB ||
+                    code == CV_BGR5652BGRA || code == CV_BGR5652RGBA ? 6 : 5;
             _dst.create(sz, CV_MAKETYPE(depth, dcn));
             dst = _dst.getMat();
-
-            CvtColorLoop(src, dst, RGB5x52RGB(dcn,
-                      code == CV_BGR5652BGR || code == CV_BGR5552BGR ||
-                      code == CV_BGR5652BGRA || code == CV_BGR5552BGRA ? 0 : 2, // blue idx
-                      code == CV_BGR5652BGR || code == CV_BGR5652RGB ||
-                      code == CV_BGR5652BGRA || code == CV_BGR5652RGBA ? 6 : 5 // green bits
-                      ));
+            hal::cvtBGR5x5toBGR(src.data, src.step, dst.data, dst.step, src.cols, src.rows,
+                                dcn, swapBlue(code), gbits);
             break;
 
         case CV_BGR2GRAY: case CV_BGRA2GRAY: case CV_RGB2GRAY: case CV_RGBA2GRAY:
             CV_Assert( scn == 3 || scn == 4 );
             _dst.create(sz, CV_MAKETYPE(depth, 1));
             dst = _dst.getMat();
-
-            bidx = code == CV_BGR2GRAY || code == CV_BGRA2GRAY ? 0 : 2;
-
-            if( depth == CV_8U )
-            {
-#ifdef HAVE_TEGRA_OPTIMIZATION
-                if(tegra::useTegra() && tegra::cvtRGB2Gray(src, dst, bidx))
-                    break;
-#endif
-                CvtColorLoop(src, dst, RGB2Gray<uchar>(scn, bidx, 0));
-            }
-            else if( depth == CV_16U )
-                CvtColorLoop(src, dst, RGB2Gray<ushort>(scn, bidx, 0));
-            else
-                CvtColorLoop(src, dst, RGB2Gray<float>(scn, bidx, 0));
+            hal::cvtBGRtoGray(src.data, src.step, dst.data, dst.step, src.cols, src.rows,
+                              depth, scn, swapBlue(code));
             break;
 
         case CV_BGR5652GRAY: case CV_BGR5552GRAY:
             CV_Assert( scn == 2 && depth == CV_8U );
+            gbits = code == CV_BGR5652GRAY ? 6 : 5;
             _dst.create(sz, CV_8UC1);
             dst = _dst.getMat();
-
-            CvtColorLoop(src, dst, RGB5x52Gray(code == CV_BGR5652GRAY ? 6 : 5));
+            hal::cvtBGR5x5toGray(src.data, src.step, dst.data, dst.step, src.cols, src.rows, gbits);
             break;
 
         case CV_GRAY2BGR: case CV_GRAY2BGRA:
@@ -8030,235 +9765,87 @@ void cv::cvtColor( InputArray _src, OutputArray _dst, int code, int dcn )
             CV_Assert( scn == 1 && (dcn == 3 || dcn == 4));
             _dst.create(sz, CV_MAKETYPE(depth, dcn));
             dst = _dst.getMat();
-
-            if( depth == CV_8U )
-            {
-#ifdef HAVE_TEGRA_OPTIMIZATION
-                if(tegra::useTegra() && tegra::cvtGray2RGB(src, dst))
-                    break;
-#endif
-                CvtColorLoop(src, dst, Gray2RGB<uchar>(dcn));
-            }
-            else if( depth == CV_16U )
-                CvtColorLoop(src, dst, Gray2RGB<ushort>(dcn));
-            else
-                CvtColorLoop(src, dst, Gray2RGB<float>(dcn));
+            hal::cvtGraytoBGR(src.data, src.step, dst.data, dst.step, src.cols, src.rows, depth, dcn);
             break;
 
         case CV_GRAY2BGR565: case CV_GRAY2BGR555:
             CV_Assert( scn == 1 && depth == CV_8U );
+            gbits = code == CV_GRAY2BGR565 ? 6 : 5;
             _dst.create(sz, CV_8UC2);
             dst = _dst.getMat();
-
-            CvtColorLoop(src, dst, Gray2RGB5x5(code == CV_GRAY2BGR565 ? 6 : 5));
+            hal::cvtGraytoBGR5x5(src.data, src.step, dst.data, dst.step, src.cols, src.rows, gbits);
             break;
 
         case CV_BGR2YCrCb: case CV_RGB2YCrCb:
         case CV_BGR2YUV: case CV_RGB2YUV:
-            {
             CV_Assert( scn == 3 || scn == 4 );
-            bidx = code == CV_BGR2YCrCb || code == CV_BGR2YUV ? 0 : 2;
-            static const float yuv_f[] = { 0.114f, 0.587f, 0.299f, 0.492f, 0.877f };
-            static const int yuv_i[] = { B2Y, G2Y, R2Y, 8061, 14369 };
-            const float* coeffs_f = code == CV_BGR2YCrCb || code == CV_RGB2YCrCb ? 0 : yuv_f;
-            const int* coeffs_i = code == CV_BGR2YCrCb || code == CV_RGB2YCrCb ? 0 : yuv_i;
-
             _dst.create(sz, CV_MAKETYPE(depth, 3));
             dst = _dst.getMat();
-
-            if( depth == CV_8U )
-            {
-#ifdef HAVE_TEGRA_OPTIMIZATION
-                if((code == CV_RGB2YCrCb || code == CV_BGR2YCrCb) && tegra::useTegra() && tegra::cvtRGB2YCrCb(src, dst, bidx))
-                    break;
-#endif
-                CvtColorLoop(src, dst, RGB2YCrCb_i<uchar>(scn, bidx, coeffs_i));
-            }
-            else if( depth == CV_16U )
-                CvtColorLoop(src, dst, RGB2YCrCb_i<ushort>(scn, bidx, coeffs_i));
-            else
-                CvtColorLoop(src, dst, RGB2YCrCb_f<float>(scn, bidx, coeffs_f));
-            }
+            hal::cvtBGRtoYUV(src.data, src.step, dst.data, dst.step, src.cols, src.rows,
+                             depth, scn, swapBlue(code), code == CV_BGR2YCrCb || code == CV_RGB2YCrCb);
             break;
 
         case CV_YCrCb2BGR: case CV_YCrCb2RGB:
         case CV_YUV2BGR: case CV_YUV2RGB:
-            {
             if( dcn <= 0 ) dcn = 3;
             CV_Assert( scn == 3 && (dcn == 3 || dcn == 4) );
-            bidx = code == CV_YCrCb2BGR || code == CV_YUV2BGR ? 0 : 2;
-            static const float yuv_f[] = { 2.032f, -0.395f, -0.581f, 1.140f };
-            static const int yuv_i[] = { 33292, -6472, -9519, 18678 };
-            const float* coeffs_f = code == CV_YCrCb2BGR || code == CV_YCrCb2RGB ? 0 : yuv_f;
-            const int* coeffs_i = code == CV_YCrCb2BGR || code == CV_YCrCb2RGB ? 0 : yuv_i;
-
             _dst.create(sz, CV_MAKETYPE(depth, dcn));
             dst = _dst.getMat();
-
-            if( depth == CV_8U )
-                CvtColorLoop(src, dst, YCrCb2RGB_i<uchar>(dcn, bidx, coeffs_i));
-            else if( depth == CV_16U )
-                CvtColorLoop(src, dst, YCrCb2RGB_i<ushort>(dcn, bidx, coeffs_i));
-            else
-                CvtColorLoop(src, dst, YCrCb2RGB_f<float>(dcn, bidx, coeffs_f));
-            }
+            hal::cvtYUVtoBGR(src.data, src.step, dst.data, dst.step, src.cols, src.rows,
+                             depth, dcn, swapBlue(code), code == CV_YCrCb2BGR || code == CV_YCrCb2RGB);
             break;
 
         case CV_BGR2XYZ: case CV_RGB2XYZ:
             CV_Assert( scn == 3 || scn == 4 );
-            bidx = code == CV_BGR2XYZ ? 0 : 2;
-
             _dst.create(sz, CV_MAKETYPE(depth, 3));
             dst = _dst.getMat();
-
-            if( depth == CV_8U )
-                CvtColorLoop(src, dst, RGB2XYZ_i<uchar>(scn, bidx, 0));
-            else if( depth == CV_16U )
-                CvtColorLoop(src, dst, RGB2XYZ_i<ushort>(scn, bidx, 0));
-            else
-                CvtColorLoop(src, dst, RGB2XYZ_f<float>(scn, bidx, 0));
+            hal::cvtBGRtoXYZ(src.data, src.step, dst.data, dst.step, src.cols, src.rows, depth, scn, swapBlue(code));
             break;
 
         case CV_XYZ2BGR: case CV_XYZ2RGB:
             if( dcn <= 0 ) dcn = 3;
             CV_Assert( scn == 3 && (dcn == 3 || dcn == 4) );
-            bidx = code == CV_XYZ2BGR ? 0 : 2;
-
             _dst.create(sz, CV_MAKETYPE(depth, dcn));
             dst = _dst.getMat();
-
-            if( depth == CV_8U )
-                CvtColorLoop(src, dst, XYZ2RGB_i<uchar>(dcn, bidx, 0));
-            else if( depth == CV_16U )
-                CvtColorLoop(src, dst, XYZ2RGB_i<ushort>(dcn, bidx, 0));
-            else
-                CvtColorLoop(src, dst, XYZ2RGB_f<float>(dcn, bidx, 0));
+            hal::cvtXYZtoBGR(src.data, src.step, dst.data, dst.step, src.cols, src.rows, depth, dcn, swapBlue(code));
             break;
 
         case CV_BGR2HSV: case CV_RGB2HSV: case CV_BGR2HSV_FULL: case CV_RGB2HSV_FULL:
         case CV_BGR2HLS: case CV_RGB2HLS: case CV_BGR2HLS_FULL: case CV_RGB2HLS_FULL:
-            {
             CV_Assert( (scn == 3 || scn == 4) && (depth == CV_8U || depth == CV_32F) );
-            bidx = code == CV_BGR2HSV || code == CV_BGR2HLS ||
-                code == CV_BGR2HSV_FULL || code == CV_BGR2HLS_FULL ? 0 : 2;
-            int hrange = depth == CV_32F ? 360 : code == CV_BGR2HSV || code == CV_RGB2HSV ||
-                code == CV_BGR2HLS || code == CV_RGB2HLS ? 180 : 256;
-
             _dst.create(sz, CV_MAKETYPE(depth, 3));
             dst = _dst.getMat();
-
-            if( code == CV_BGR2HSV || code == CV_RGB2HSV ||
-                code == CV_BGR2HSV_FULL || code == CV_RGB2HSV_FULL )
-            {
-#ifdef HAVE_TEGRA_OPTIMIZATION
-                if(tegra::useTegra() && tegra::cvtRGB2HSV(src, dst, bidx, hrange))
-                    break;
-#endif
-                if( depth == CV_8U )
-                    CvtColorLoop(src, dst, RGB2HSV_b(scn, bidx, hrange));
-                else
-                    CvtColorLoop(src, dst, RGB2HSV_f(scn, bidx, (float)hrange));
-            }
-            else
-            {
-                if( depth == CV_8U )
-                    CvtColorLoop(src, dst, RGB2HLS_b(scn, bidx, hrange));
-                else
-                    CvtColorLoop(src, dst, RGB2HLS_f(scn, bidx, (float)hrange));
-            }
-            }
+            hal::cvtBGRtoHSV(src.data, src.step, dst.data, dst.step, src.cols, src.rows,
+                             depth, scn, swapBlue(code), isFullRange(code), isHSV(code));
             break;
 
         case CV_HSV2BGR: case CV_HSV2RGB: case CV_HSV2BGR_FULL: case CV_HSV2RGB_FULL:
         case CV_HLS2BGR: case CV_HLS2RGB: case CV_HLS2BGR_FULL: case CV_HLS2RGB_FULL:
-            {
             if( dcn <= 0 ) dcn = 3;
             CV_Assert( scn == 3 && (dcn == 3 || dcn == 4) && (depth == CV_8U || depth == CV_32F) );
-            bidx = code == CV_HSV2BGR || code == CV_HLS2BGR ||
-                code == CV_HSV2BGR_FULL || code == CV_HLS2BGR_FULL ? 0 : 2;
-            int hrange = depth == CV_32F ? 360 : code == CV_HSV2BGR || code == CV_HSV2RGB ||
-                code == CV_HLS2BGR || code == CV_HLS2RGB ? 180 : 255;
-
             _dst.create(sz, CV_MAKETYPE(depth, dcn));
             dst = _dst.getMat();
-
-            if( code == CV_HSV2BGR || code == CV_HSV2RGB ||
-                code == CV_HSV2BGR_FULL || code == CV_HSV2RGB_FULL )
-            {
-                if( depth == CV_8U )
-                    CvtColorLoop(src, dst, HSV2RGB_b(dcn, bidx, hrange));
-                else
-                    CvtColorLoop(src, dst, HSV2RGB_f(dcn, bidx, (float)hrange));
-            }
-            else
-            {
-                if( depth == CV_8U )
-                    CvtColorLoop(src, dst, HLS2RGB_b(dcn, bidx, hrange));
-                else
-                    CvtColorLoop(src, dst, HLS2RGB_f(dcn, bidx, (float)hrange));
-            }
-            }
+            hal::cvtHSVtoBGR(src.data, src.step, dst.data, dst.step, src.cols, src.rows,
+                             depth, dcn, swapBlue(code), isFullRange(code), isHSV(code));
             break;
 
         case CV_BGR2Lab: case CV_RGB2Lab: case CV_LBGR2Lab: case CV_LRGB2Lab:
         case CV_BGR2Luv: case CV_RGB2Luv: case CV_LBGR2Luv: case CV_LRGB2Luv:
-            {
             CV_Assert( (scn == 3 || scn == 4) && (depth == CV_8U || depth == CV_32F) );
-            bidx = code == CV_BGR2Lab || code == CV_BGR2Luv ||
-                   code == CV_LBGR2Lab || code == CV_LBGR2Luv ? 0 : 2;
-            bool srgb = code == CV_BGR2Lab || code == CV_RGB2Lab ||
-                        code == CV_BGR2Luv || code == CV_RGB2Luv;
-
             _dst.create(sz, CV_MAKETYPE(depth, 3));
             dst = _dst.getMat();
-
-            if( code == CV_BGR2Lab || code == CV_RGB2Lab ||
-                code == CV_LBGR2Lab || code == CV_LRGB2Lab )
-            {
-                if( depth == CV_8U )
-                    CvtColorLoop(src, dst, RGB2Lab_b(scn, bidx, 0, 0, srgb));
-                else
-                    CvtColorLoop(src, dst, RGB2Lab_f(scn, bidx, 0, 0, srgb));
-            }
-            else
-            {
-                if( depth == CV_8U )
-                    CvtColorLoop(src, dst, RGB2Luv_b(scn, bidx, 0, 0, srgb));
-                else
-                    CvtColorLoop(src, dst, RGB2Luv_f(scn, bidx, 0, 0, srgb));
-            }
-            }
+            hal::cvtBGRtoLab(src.data, src.step, dst.data, dst.step, src.cols, src.rows,
+                             depth, scn, swapBlue(code), isLab(code), issRGB(code));
             break;
 
         case CV_Lab2BGR: case CV_Lab2RGB: case CV_Lab2LBGR: case CV_Lab2LRGB:
         case CV_Luv2BGR: case CV_Luv2RGB: case CV_Luv2LBGR: case CV_Luv2LRGB:
-            {
             if( dcn <= 0 ) dcn = 3;
             CV_Assert( scn == 3 && (dcn == 3 || dcn == 4) && (depth == CV_8U || depth == CV_32F) );
-            bidx = code == CV_Lab2BGR || code == CV_Luv2BGR ||
-                   code == CV_Lab2LBGR || code == CV_Luv2LBGR ? 0 : 2;
-            bool srgb = code == CV_Lab2BGR || code == CV_Lab2RGB ||
-                    code == CV_Luv2BGR || code == CV_Luv2RGB;
-
             _dst.create(sz, CV_MAKETYPE(depth, dcn));
             dst = _dst.getMat();
-
-            if( code == CV_Lab2BGR || code == CV_Lab2RGB ||
-                code == CV_Lab2LBGR || code == CV_Lab2LRGB )
-            {
-                if( depth == CV_8U )
-                    CvtColorLoop(src, dst, Lab2RGB_b(dcn, bidx, 0, 0, srgb));
-                else
-                    CvtColorLoop(src, dst, Lab2RGB_f(dcn, bidx, 0, 0, srgb));
-            }
-            else
-            {
-                if( depth == CV_8U )
-                    CvtColorLoop(src, dst, Luv2RGB_b(dcn, bidx, 0, 0, srgb));
-                else
-                    CvtColorLoop(src, dst, Luv2RGB_f(dcn, bidx, 0, 0, srgb));
-            }
-            }
+            hal::cvtLabtoBGR(src.data, src.step, dst.data, dst.step, src.cols, src.rows,
+                             depth, dcn, swapBlue(code), isLab(code), issRGB(code));
             break;
 
         case CV_BayerBG2GRAY: case CV_BayerGB2GRAY: case CV_BayerRG2GRAY: case CV_BayerGR2GRAY:
@@ -8270,76 +9857,31 @@ void cv::cvtColor( InputArray _src, OutputArray _dst, int code, int dcn )
 
         case CV_YUV2BGR_NV21:  case CV_YUV2RGB_NV21:  case CV_YUV2BGR_NV12:  case CV_YUV2RGB_NV12:
         case CV_YUV2BGRA_NV21: case CV_YUV2RGBA_NV21: case CV_YUV2BGRA_NV12: case CV_YUV2RGBA_NV12:
-            {
-                // http://www.fourcc.org/yuv.php#NV21 == yuv420sp -> a plane of 8 bit Y samples followed by an interleaved V/U plane containing 8 bit 2x2 subsampled chroma samples
-                // http://www.fourcc.org/yuv.php#NV12 -> a plane of 8 bit Y samples followed by an interleaved U/V plane containing 8 bit 2x2 subsampled colour difference samples
-
-                if (dcn <= 0) dcn = (code==CV_YUV420sp2BGRA || code==CV_YUV420sp2RGBA || code==CV_YUV2BGRA_NV12 || code==CV_YUV2RGBA_NV12) ? 4 : 3;
-                const int bIdx = (code==CV_YUV2BGR_NV21 || code==CV_YUV2BGRA_NV21 || code==CV_YUV2BGR_NV12 || code==CV_YUV2BGRA_NV12) ? 0 : 2;
-                const int uIdx = (code==CV_YUV2BGR_NV21 || code==CV_YUV2BGRA_NV21 || code==CV_YUV2RGB_NV21 || code==CV_YUV2RGBA_NV21) ? 1 : 0;
-
-                CV_Assert( dcn == 3 || dcn == 4 );
-                CV_Assert( sz.width % 2 == 0 && sz.height % 3 == 0 && depth == CV_8U );
-
-                Size dstSz(sz.width, sz.height * 2 / 3);
-                _dst.create(dstSz, CV_MAKETYPE(depth, dcn));
-                dst = _dst.getMat();
-
-                int srcstep = (int)src.step;
-                const uchar* y = src.ptr();
-                const uchar* uv = y + srcstep * dstSz.height;
-
-                switch(dcn*100 + bIdx * 10 + uIdx)
-                {
-                    case 300: cvtYUV420sp2RGB<0, 0> (dst, srcstep, y, uv); break;
-                    case 301: cvtYUV420sp2RGB<0, 1> (dst, srcstep, y, uv); break;
-                    case 320: cvtYUV420sp2RGB<2, 0> (dst, srcstep, y, uv); break;
-                    case 321: cvtYUV420sp2RGB<2, 1> (dst, srcstep, y, uv); break;
-                    case 400: cvtYUV420sp2RGBA<0, 0>(dst, srcstep, y, uv); break;
-                    case 401: cvtYUV420sp2RGBA<0, 1>(dst, srcstep, y, uv); break;
-                    case 420: cvtYUV420sp2RGBA<2, 0>(dst, srcstep, y, uv); break;
-                    case 421: cvtYUV420sp2RGBA<2, 1>(dst, srcstep, y, uv); break;
-                    default: CV_Error( CV_StsBadFlag, "Unknown/unsupported color conversion code" ); break;
-                };
-            }
+            // http://www.fourcc.org/yuv.php#NV21 == yuv420sp -> a plane of 8 bit Y samples followed by an interleaved V/U plane containing 8 bit 2x2 subsampled chroma samples
+            // http://www.fourcc.org/yuv.php#NV12 -> a plane of 8 bit Y samples followed by an interleaved U/V plane containing 8 bit 2x2 subsampled colour difference samples
+            if (dcn <= 0) dcn = (code==CV_YUV420sp2BGRA || code==CV_YUV420sp2RGBA || code==CV_YUV2BGRA_NV12 || code==CV_YUV2RGBA_NV12) ? 4 : 3;
+            uidx = (code==CV_YUV2BGR_NV21 || code==CV_YUV2BGRA_NV21 || code==CV_YUV2RGB_NV21 || code==CV_YUV2RGBA_NV21) ? 1 : 0;
+            CV_Assert( dcn == 3 || dcn == 4 );
+            CV_Assert( sz.width % 2 == 0 && sz.height % 3 == 0 && depth == CV_8U );
+            _dst.create(Size(sz.width, sz.height * 2 / 3), CV_MAKETYPE(depth, dcn));
+            dst = _dst.getMat();
+            hal::cvtTwoPlaneYUVtoBGR(src.data, src.step, dst.data, dst.step, dst.cols, dst.rows,
+                                     dcn, swapBlue(code), uidx);
             break;
         case CV_YUV2BGR_YV12: case CV_YUV2RGB_YV12: case CV_YUV2BGRA_YV12: case CV_YUV2RGBA_YV12:
         case CV_YUV2BGR_IYUV: case CV_YUV2RGB_IYUV: case CV_YUV2BGRA_IYUV: case CV_YUV2RGBA_IYUV:
-            {
-                //http://www.fourcc.org/yuv.php#YV12 == yuv420p -> It comprises an NxM Y plane followed by (N/2)x(M/2) V and U planes.
-                //http://www.fourcc.org/yuv.php#IYUV == I420 -> It comprises an NxN Y plane followed by (N/2)x(N/2) U and V planes
-
-                if (dcn <= 0) dcn = (code==CV_YUV2BGRA_YV12 || code==CV_YUV2RGBA_YV12 || code==CV_YUV2RGBA_IYUV || code==CV_YUV2BGRA_IYUV) ? 4 : 3;
-                const int bIdx = (code==CV_YUV2BGR_YV12 || code==CV_YUV2BGRA_YV12 || code==CV_YUV2BGR_IYUV || code==CV_YUV2BGRA_IYUV) ? 0 : 2;
-                const int uIdx  = (code==CV_YUV2BGR_YV12 || code==CV_YUV2RGB_YV12 || code==CV_YUV2BGRA_YV12 || code==CV_YUV2RGBA_YV12) ? 1 : 0;
-
-                CV_Assert( dcn == 3 || dcn == 4 );
-                CV_Assert( sz.width % 2 == 0 && sz.height % 3 == 0 && depth == CV_8U );
-
-                Size dstSz(sz.width, sz.height * 2 / 3);
-                _dst.create(dstSz, CV_MAKETYPE(depth, dcn));
-                dst = _dst.getMat();
-
-                int srcstep = (int)src.step;
-                const uchar* y = src.ptr();
-                const uchar* u = y + srcstep * dstSz.height;
-                const uchar* v = y + srcstep * (dstSz.height + dstSz.height/4) + (dstSz.width/2) * ((dstSz.height % 4)/2);
-
-                int ustepIdx = 0;
-                int vstepIdx = dstSz.height % 4 == 2 ? 1 : 0;
-
-                if(uIdx == 1) { std::swap(u ,v), std::swap(ustepIdx, vstepIdx); }
-
-                switch(dcn*10 + bIdx)
-                {
-                    case 30: cvtYUV420p2RGB<0>(dst, srcstep, y, u, v, ustepIdx, vstepIdx); break;
-                    case 32: cvtYUV420p2RGB<2>(dst, srcstep, y, u, v, ustepIdx, vstepIdx); break;
-                    case 40: cvtYUV420p2RGBA<0>(dst, srcstep, y, u, v, ustepIdx, vstepIdx); break;
-                    case 42: cvtYUV420p2RGBA<2>(dst, srcstep, y, u, v, ustepIdx, vstepIdx); break;
-                    default: CV_Error( CV_StsBadFlag, "Unknown/unsupported color conversion code" ); break;
-                };
-            }
+            //http://www.fourcc.org/yuv.php#YV12 == yuv420p -> It comprises an NxM Y plane followed by (N/2)x(M/2) V and U planes.
+            //http://www.fourcc.org/yuv.php#IYUV == I420 -> It comprises an NxN Y plane followed by (N/2)x(N/2) U and V planes
+            if (dcn <= 0) dcn = (code==CV_YUV2BGRA_YV12 || code==CV_YUV2RGBA_YV12 || code==CV_YUV2RGBA_IYUV || code==CV_YUV2BGRA_IYUV) ? 4 : 3;
+            uidx  = (code==CV_YUV2BGR_YV12 || code==CV_YUV2RGB_YV12 || code==CV_YUV2BGRA_YV12 || code==CV_YUV2RGBA_YV12) ? 1 : 0;
+            CV_Assert( dcn == 3 || dcn == 4 );
+            CV_Assert( sz.width % 2 == 0 && sz.height % 3 == 0 && depth == CV_8U );
+            _dst.create(Size(sz.width, sz.height * 2 / 3), CV_MAKETYPE(depth, dcn));
+            dst = _dst.getMat();
+            hal::cvtThreePlaneYUVtoBGR(src.data, src.step, dst.data, dst.step, dst.cols, dst.rows,
+                                       dcn, swapBlue(code), uidx);
             break;
+
         case CV_YUV2GRAY_420:
             {
                 if (dcn <= 0) dcn = 1;
@@ -8350,74 +9892,41 @@ void cv::cvtColor( InputArray _src, OutputArray _dst, int code, int dcn )
                 Size dstSz(sz.width, sz.height * 2 / 3);
                 _dst.create(dstSz, CV_MAKETYPE(depth, dcn));
                 dst = _dst.getMat();
+#ifdef HAVE_IPP
+                if (CV_INSTRUMENT_FUN_IPP(ippiCopy_8u_C1R, src.data, (int)src.step, dst.data, (int)dst.step,
+                                                   ippiSize(dstSz.width, dstSz.height)) >= 0)
+                    break;
+#endif
                 src(Range(0, dstSz.height), Range::all()).copyTo(dst);
             }
             break;
         case CV_RGB2YUV_YV12: case CV_BGR2YUV_YV12: case CV_RGBA2YUV_YV12: case CV_BGRA2YUV_YV12:
         case CV_RGB2YUV_IYUV: case CV_BGR2YUV_IYUV: case CV_RGBA2YUV_IYUV: case CV_BGRA2YUV_IYUV:
-            {
-                if (dcn <= 0) dcn = 1;
-                const int bIdx = (code == CV_BGR2YUV_IYUV || code == CV_BGRA2YUV_IYUV || code == CV_BGR2YUV_YV12 || code == CV_BGRA2YUV_YV12) ? 0 : 2;
-                const int uIdx = (code == CV_BGR2YUV_IYUV || code == CV_BGRA2YUV_IYUV || code == CV_RGB2YUV_IYUV || code == CV_RGBA2YUV_IYUV) ? 1 : 2;
-
-                CV_Assert( (scn == 3 || scn == 4) && depth == CV_8U );
-                CV_Assert( dcn == 1 );
-                CV_Assert( sz.width % 2 == 0 && sz.height % 2 == 0 );
-
-                Size dstSz(sz.width, sz.height / 2 * 3);
-                _dst.create(dstSz, CV_MAKETYPE(depth, dcn));
-                dst = _dst.getMat();
-
-                switch(bIdx + uIdx*10)
-                {
-                    case 10: cvtRGBtoYUV420p<0, 1>(src, dst); break;
-                    case 12: cvtRGBtoYUV420p<2, 1>(src, dst); break;
-                    case 20: cvtRGBtoYUV420p<0, 2>(src, dst); break;
-                    case 22: cvtRGBtoYUV420p<2, 2>(src, dst); break;
-                    default: CV_Error( CV_StsBadFlag, "Unknown/unsupported color conversion code" ); break;
-                };
-            }
+            if (dcn <= 0) dcn = 1;
+            uidx = (code == CV_BGR2YUV_IYUV || code == CV_BGRA2YUV_IYUV || code == CV_RGB2YUV_IYUV || code == CV_RGBA2YUV_IYUV) ? 1 : 2;
+            CV_Assert( (scn == 3 || scn == 4) && depth == CV_8U );
+            CV_Assert( dcn == 1 );
+            CV_Assert( sz.width % 2 == 0 && sz.height % 2 == 0 );
+            _dst.create(Size(sz.width, sz.height / 2 * 3), CV_MAKETYPE(depth, dcn));
+            dst = _dst.getMat();
+            hal::cvtBGRtoThreePlaneYUV(src.data, src.step, dst.data, dst.step, src.cols, src.rows,
+                                       scn, swapBlue(code), uidx);
             break;
         case CV_YUV2RGB_UYVY: case CV_YUV2BGR_UYVY: case CV_YUV2RGBA_UYVY: case CV_YUV2BGRA_UYVY:
         case CV_YUV2RGB_YUY2: case CV_YUV2BGR_YUY2: case CV_YUV2RGB_YVYU: case CV_YUV2BGR_YVYU:
         case CV_YUV2RGBA_YUY2: case CV_YUV2BGRA_YUY2: case CV_YUV2RGBA_YVYU: case CV_YUV2BGRA_YVYU:
-            {
-                //http://www.fourcc.org/yuv.php#UYVY
-                //http://www.fourcc.org/yuv.php#YUY2
-                //http://www.fourcc.org/yuv.php#YVYU
-
-                if (dcn <= 0) dcn = (code==CV_YUV2RGBA_UYVY || code==CV_YUV2BGRA_UYVY || code==CV_YUV2RGBA_YUY2 || code==CV_YUV2BGRA_YUY2 || code==CV_YUV2RGBA_YVYU || code==CV_YUV2BGRA_YVYU) ? 4 : 3;
-                const int bIdx = (code==CV_YUV2BGR_UYVY || code==CV_YUV2BGRA_UYVY || code==CV_YUV2BGR_YUY2 || code==CV_YUV2BGRA_YUY2 || code==CV_YUV2BGR_YVYU || code==CV_YUV2BGRA_YVYU) ? 0 : 2;
-                const int ycn  = (code==CV_YUV2RGB_UYVY || code==CV_YUV2BGR_UYVY || code==CV_YUV2RGBA_UYVY || code==CV_YUV2BGRA_UYVY) ? 1 : 0;
-                const int uIdx = (code==CV_YUV2RGB_YVYU || code==CV_YUV2BGR_YVYU || code==CV_YUV2RGBA_YVYU || code==CV_YUV2BGRA_YVYU) ? 1 : 0;
-
-                CV_Assert( dcn == 3 || dcn == 4 );
-                CV_Assert( scn == 2 && depth == CV_8U );
-
-                _dst.create(sz, CV_8UC(dcn));
-                dst = _dst.getMat();
-
-                switch(dcn*1000 + bIdx*100 + uIdx*10 + ycn)
-                {
-                    case 3000: cvtYUV422toRGB<0,0,0>(dst, (int)src.step, src.ptr<uchar>()); break;
-                    case 3001: cvtYUV422toRGB<0,0,1>(dst, (int)src.step, src.ptr<uchar>()); break;
-                    case 3010: cvtYUV422toRGB<0,1,0>(dst, (int)src.step, src.ptr<uchar>()); break;
-                    case 3011: cvtYUV422toRGB<0,1,1>(dst, (int)src.step, src.ptr<uchar>()); break;
-                    case 3200: cvtYUV422toRGB<2,0,0>(dst, (int)src.step, src.ptr<uchar>()); break;
-                    case 3201: cvtYUV422toRGB<2,0,1>(dst, (int)src.step, src.ptr<uchar>()); break;
-                    case 3210: cvtYUV422toRGB<2,1,0>(dst, (int)src.step, src.ptr<uchar>()); break;
-                    case 3211: cvtYUV422toRGB<2,1,1>(dst, (int)src.step, src.ptr<uchar>()); break;
-                    case 4000: cvtYUV422toRGBA<0,0,0>(dst, (int)src.step, src.ptr<uchar>()); break;
-                    case 4001: cvtYUV422toRGBA<0,0,1>(dst, (int)src.step, src.ptr<uchar>()); break;
-                    case 4010: cvtYUV422toRGBA<0,1,0>(dst, (int)src.step, src.ptr<uchar>()); break;
-                    case 4011: cvtYUV422toRGBA<0,1,1>(dst, (int)src.step, src.ptr<uchar>()); break;
-                    case 4200: cvtYUV422toRGBA<2,0,0>(dst, (int)src.step, src.ptr<uchar>()); break;
-                    case 4201: cvtYUV422toRGBA<2,0,1>(dst, (int)src.step, src.ptr<uchar>()); break;
-                    case 4210: cvtYUV422toRGBA<2,1,0>(dst, (int)src.step, src.ptr<uchar>()); break;
-                    case 4211: cvtYUV422toRGBA<2,1,1>(dst, (int)src.step, src.ptr<uchar>()); break;
-                    default: CV_Error( CV_StsBadFlag, "Unknown/unsupported color conversion code" ); break;
-                };
-            }
+            //http://www.fourcc.org/yuv.php#UYVY
+            //http://www.fourcc.org/yuv.php#YUY2
+            //http://www.fourcc.org/yuv.php#YVYU
+            if (dcn <= 0) dcn = (code==CV_YUV2RGBA_UYVY || code==CV_YUV2BGRA_UYVY || code==CV_YUV2RGBA_YUY2 || code==CV_YUV2BGRA_YUY2 || code==CV_YUV2RGBA_YVYU || code==CV_YUV2BGRA_YVYU) ? 4 : 3;
+            ycn  = (code==CV_YUV2RGB_UYVY || code==CV_YUV2BGR_UYVY || code==CV_YUV2RGBA_UYVY || code==CV_YUV2BGRA_UYVY) ? 1 : 0;
+            uidx = (code==CV_YUV2RGB_YVYU || code==CV_YUV2BGR_YVYU || code==CV_YUV2RGBA_YVYU || code==CV_YUV2BGRA_YVYU) ? 1 : 0;
+            CV_Assert( dcn == 3 || dcn == 4 );
+            CV_Assert( scn == 2 && depth == CV_8U );
+            _dst.create(sz, CV_8UC(dcn));
+            dst = _dst.getMat();
+            hal::cvtOnePlaneYUVtoBGR(src.data, src.step, dst.data, dst.step, src.cols, src.rows,
+                                     dcn, swapBlue(code), uidx, ycn);
             break;
         case CV_YUV2GRAY_UYVY: case CV_YUV2GRAY_YUY2:
             {
@@ -8431,42 +9940,22 @@ void cv::cvtColor( InputArray _src, OutputArray _dst, int code, int dcn )
             }
             break;
         case CV_RGBA2mRGBA:
-            {
-                if (dcn <= 0) dcn = 4;
-                CV_Assert( scn == 4 && dcn == 4 );
-
-                _dst.create(sz, CV_MAKETYPE(depth, dcn));
-                dst = _dst.getMat();
-
-                if( depth == CV_8U )
-                {
-                    CvtColorLoop(src, dst, RGBA2mRGBA<uchar>());
-                }
-                else
-                {
-                    CV_Error( CV_StsBadArg, "Unsupported image depth" );
-                }
-            }
+            if (dcn <= 0) dcn = 4;
+            CV_Assert( scn == 4 && dcn == 4 && depth == CV_8U );
+            _dst.create(sz, CV_MAKETYPE(depth, dcn));
+            dst = _dst.getMat();
+            hal::cvtRGBAtoMultipliedRGBA(src.data, src.step, dst.data, dst.step, src.cols, src.rows);
             break;
         case CV_mRGBA2RGBA:
-            {
-                if (dcn <= 0) dcn = 4;
-                CV_Assert( scn == 4 && dcn == 4 );
-
-                _dst.create(sz, CV_MAKETYPE(depth, dcn));
-                dst = _dst.getMat();
-
-                if( depth == CV_8U )
-                    CvtColorLoop(src, dst, mRGBA2RGBA<uchar>());
-                else
-                {
-                    CV_Error( CV_StsBadArg, "Unsupported image depth" );
-                }
-            }
+            if (dcn <= 0) dcn = 4;
+            CV_Assert( scn == 4 && dcn == 4 && depth == CV_8U );
+            _dst.create(sz, CV_MAKETYPE(depth, dcn));
+            dst = _dst.getMat();
+            hal::cvtMultipliedRGBAtoRGBA(src.data, src.step, dst.data, dst.step, src.cols, src.rows);
             break;
         default:
             CV_Error( CV_StsBadFlag, "Unknown/unsupported color conversion code" );
-    }
+        }
 }
 
 CV_IMPL void
diff --git a/modules/imgproc/src/colormap.cpp b/modules/imgproc/src/colormap.cpp
index 6d03d7b..3fc9755 100644
--- a/modules/imgproc/src/colormap.cpp
+++ b/modules/imgproc/src/colormap.cpp
@@ -144,10 +144,7 @@ namespace colormap
 
         // Applies the colormap on a given image.
         //
-        // This function expects BGR-aligned data of type CV_8UC1 or
-        // CV_8UC3. If the wrong image type is given, the original image
-        // will be returned.
-        //
+        // This function expects BGR-aligned data of type CV_8UC1 or CV_8UC3.
         // Throws an error for wrong-aligned lookup table, which must be
         // of size 256 in the latest OpenCV release (2.3.1).
         void operator()(InputArray src, OutputArray dst) const;
@@ -495,15 +492,13 @@ namespace colormap
 
     void ColorMap::operator()(InputArray _src, OutputArray _dst) const
     {
+        CV_INSTRUMENT_REGION()
+
         if(_lut.total() != 256)
             CV_Error(Error::StsAssert, "cv::LUT only supports tables of size 256.");
         Mat src = _src.getMat();
-        // Return original matrix if wrong type is given (is fail loud better here?)
-        if(src.type() != CV_8UC1 && src.type() != CV_8UC3)
-        {
-            src.copyTo(_dst);
-            return;
-        }
+        if(src.type() != CV_8UC1  &&  src.type() != CV_8UC3)
+            CV_Error(Error::StsBadArg, "cv::ColorMap only supports source images of type CV_8UC1 or CV_8UC3");
         // Turn into a BGR matrix into its grayscale representation.
         if(src.type() == CV_8UC3)
             cvtColor(src.clone(), src, COLOR_BGR2GRAY);
diff --git a/modules/imgproc/src/connectedcomponents.cpp b/modules/imgproc/src/connectedcomponents.cpp
index 523eb14..bf53704 100644
--- a/modules/imgproc/src/connectedcomponents.cpp
+++ b/modules/imgproc/src/connectedcomponents.cpp
@@ -38,6 +38,10 @@
 // the use of this software, even if advised of the possibility of such damage.
 //
 // 2011 Jason Newton <nevion at gmail.com>
+// 2016 Costantino Grama <costantino.grana at unimore.it>
+// 2016 Federico Bolelli <federico.bolelli at hotmail.com>
+// 2016 Lorenzo Baraldi <lorenzo.baraldi at unimore.it>
+// 2016 Roberto Vezzani <roberto.vezzani at unimore.it>
 //M*/
 //
 #include "precomp.hpp"
@@ -188,7 +192,7 @@ namespace cv{
     //reference for 8-way: {{-1, -1}, {-1, 0}, {-1, 1}, {0, -1}};//a, b, c, d neighborhoods
     const int G8[4][2] = {{1, -1}, {1, 0}, {1, 1}, {0, -1}};//a, b, c, d neighborhoods
     template<typename LabelT, typename PixelT, typename StatsOp = NoOp >
-    struct LabelingImpl{
+    struct LabelingWu{
     LabelT operator()(const cv::Mat &I, cv::Mat &L, int connectivity, StatsOp &sop){
         CV_Assert(L.rows == I.rows);
         CV_Assert(L.cols == I.cols);
@@ -329,33 +333,1366 @@ namespace cv{
         fastFree(P);
 
         return nLabels;
-    }//End function LabelingImpl operator()
+    }//End function LabelingWu operator()
+    };//End struct LabelingWu
 
-    };//End struct LabelingImpl
+    // Based on �Optimized  Block-based Connected Components Labeling with Decision Trees�, Costantino Grana et al
+    // Only for 8-connectivity
+    template<typename LabelT, typename PixelT, typename StatsOp = NoOp >
+    struct LabelingGrana{
+    LabelT operator()(const cv::Mat &img, cv::Mat &imgLabels, int connectivity,  StatsOp &sop){
+        CV_Assert(img.rows == imgLabels.rows);
+        CV_Assert(img.cols == imgLabels.cols);
+        CV_Assert(connectivity == 8 || connectivity == 4);
+
+        const int h = img.rows;
+        const int w = img.cols;
+
+        //A quick and dirty upper bound for the maximimum number of labels.
+        const size_t Plength = img.rows*img.cols / 4;
+        LabelT *P = (LabelT *)fastMalloc(sizeof(LabelT)* Plength);
+        P[0] = 0;
+        LabelT lunique = 1;
+
+        // First scan
+        for (int r = 0; r<h; r += 2) {
+            // Get rows pointer
+            const PixelT* const img_row = img.ptr<PixelT>(r);
+            const PixelT* const img_row_prev = (PixelT *)(((char *)img_row) - img.step.p[0]);
+            const PixelT* const img_row_prev_prev = (PixelT *)(((char *)img_row_prev) - img.step.p[0]);
+            const PixelT* const img_row_fol = (PixelT *)(((char *)img_row) + img.step.p[0]);
+            LabelT* const imgLabels_row = imgLabels.ptr<LabelT>(r);
+            LabelT* const imgLabels_row_prev_prev = (LabelT *)(((char *)imgLabels_row) - imgLabels.step.p[0] - imgLabels.step.p[0]);
+            for (int c = 0; c < w; c += 2) {
+
+                // We work with 2x2 blocks
+                // +-+-+-+
+                // |P|Q|R|
+                // +-+-+-+
+                // |S|X|
+                // +-+-+
+
+                // The pixels are named as follows
+                // +---+---+---+
+                // |a b|c d|e f|
+                // |g h|i j|k l|
+                // +---+---+---+
+                // |m n|o p|
+                // |q r|s t|
+                // +---+---+
+
+                // Pixels a, f, l, q are not needed, since we need to understand the
+                // the connectivity between these blocks and those pixels only metter
+                // when considering the outer connectivities
+
+                // A bunch of defines used to check if the pixels are foreground,
+                // without going outside the image limits.
+                #define condition_b c-1>=0 && r-2>=0 && img_row_prev_prev[c-1]>0
+                #define condition_c r-2>=0 && img_row_prev_prev[c]>0
+                #define condition_d c+1<w && r-2>=0 && img_row_prev_prev[c+1]>0
+                #define condition_e c+2<w && r-2>=0 && img_row_prev_prev[c+2]>0
+
+                #define condition_g c-2>=0 && r-1>=0 && img_row_prev[c-2]>0
+                #define condition_h c-1>=0 && r-1>=0 && img_row_prev[c-1]>0
+                #define condition_i r-1>=0 && img_row_prev[c]>0
+                #define condition_j c+1<w && r-1>=0 && img_row_prev[c+1]>0
+                #define condition_k c+2<w && r-1>=0 && img_row_prev[c+2]>0
+
+                #define condition_m c-2>=0 && img_row[c-2]>0
+                #define condition_n c-1>=0 && img_row[c-1]>0
+                #define condition_o img_row[c]>0
+                #define condition_p c+1<w && img_row[c+1]>0
+
+                #define condition_r c-1>=0 && r+1<h && img_row_fol[c-1]>0
+                #define condition_s r+1<h && img_row_fol[c]>0
+                #define condition_t c+1<w && r+1<h && img_row_fol[c+1]>0
+
+                // This is a decision tree which allows to choose which action to
+                // perform, checking as few conditions as possible.
+                // Actions: the blocks label are provisionally stored in the top left
+                // pixel of the block in the labels image
+
+                if (condition_o) {
+                    if (condition_n) {
+                        if (condition_j) {
+                            if (condition_i) {
+                                //Action_6: Assign label of block S
+                                imgLabels_row[c] = imgLabels_row[c - 2];
+                                continue;
+                            }
+                            else {
+                                if (condition_c) {
+                                    if (condition_h) {
+                                        //Action_6: Assign label of block S
+                                        imgLabels_row[c] = imgLabels_row[c - 2];
+                                        continue;
+                                    }
+                                    else {
+                                        if (condition_g) {
+                                            if (condition_b) {
+                                                //Action_6: Assign label of block S
+                                                imgLabels_row[c] = imgLabels_row[c - 2];
+                                                continue;
+                                            }
+                                            else {
+                                                //Action_11: Merge labels of block Q and S
+                                                imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);
+                                                continue;
+                                            }
+                                        }
+                                        else {
+                                            //Action_11: Merge labels of block Q and S
+                                            imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);
+                                            continue;
+                                        }
+                                    }
+                                }
+                                else {
+                                    //Action_11: Merge labels of block Q and S
+                                    imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);
+                                    continue;
+                                }
+                            }
+                        }
+                        else {
+                            if (condition_p) {
+                                if (condition_k) {
+                                    if (condition_d) {
+                                        if (condition_i) {
+                                            //Action_6: Assign label of block S
+                                            imgLabels_row[c] = imgLabels_row[c - 2];
+                                            continue;
+                                        }
+                                        else {
+                                            if (condition_c) {
+                                                if (condition_h) {
+                                                    //Action_6: Assign label of block S
+                                                    imgLabels_row[c] = imgLabels_row[c - 2];
+                                                    continue;
+                                                }
+                                                else {
+                                                    if (condition_g) {
+                                                        if (condition_b) {
+                                                            //Action_6: Assign label of block S
+                                                            imgLabels_row[c] = imgLabels_row[c - 2];
+                                                            continue;
+                                                        }
+                                                        else {
+                                                            //Action_12: Merge labels of block R and S
+                                                            imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);
+                                                            continue;
+                                                        }
+                                                    }
+                                                    else {
+                                                        //Action_12: Merge labels of block R and S
+                                                        imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);
+                                                        continue;
+                                                    }
+                                                }
+                                            }
+                                            else {
+                                                //Action_12: Merge labels of block R and S
+                                                imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);
+                                                continue;
+                                            }
+                                        }
+                                    }
+                                    else {
+                                        //Action_12: Merge labels of block R and S
+                                        imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);
+                                        continue;
+                                    }
+                                }
+                                else {
+                                    //Action_6: Assign label of block S
+                                    imgLabels_row[c] = imgLabels_row[c - 2];
+                                    continue;
+                                }
+                            }
+                            else {
+                                //Action_6: Assign label of block S
+                                imgLabels_row[c] = imgLabels_row[c - 2];
+                                continue;
+                            }
+                        }
+                    }
+                    else {
+                        if (condition_r) {
+                            if (condition_j) {
+                                if (condition_m) {
+                                    if (condition_h) {
+                                        if (condition_i) {
+                                            //Action_6: Assign label of block S
+                                            imgLabels_row[c] = imgLabels_row[c - 2];
+                                            continue;
+                                        }
+                                        else {
+                                            if (condition_c) {
+                                                //Action_6: Assign label of block S
+                                                imgLabels_row[c] = imgLabels_row[c - 2];
+                                                continue;
+                                            }
+                                            else {
+                                                //Action_11: Merge labels of block Q and S
+                                                imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);
+                                                continue;
+                                            }
+                                        }
+                                    }
+                                    else {
+                                        if (condition_g) {
+                                            if (condition_b) {
+                                                if (condition_i) {
+                                                    //Action_6: Assign label of block S
+                                                    imgLabels_row[c] = imgLabels_row[c - 2];
+                                                    continue;
+                                                }
+                                                else {
+                                                    if (condition_c) {
+                                                        //Action_6: Assign label of block S
+                                                        imgLabels_row[c] = imgLabels_row[c - 2];
+                                                        continue;
+                                                    }
+                                                    else {
+                                                        //Action_11: Merge labels of block Q and S
+                                                        imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);
+                                                        continue;
+                                                    }
+                                                }
+                                            }
+                                            else {
+                                                //Action_11: Merge labels of block Q and S
+                                                imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);
+                                                continue;
+                                            }
+                                        }
+                                        else {
+                                            //Action_11: Merge labels of block Q and S
+                                            imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);
+                                            continue;
+                                        }
+                                    }
+                                }
+                                else {
+                                    if (condition_i) {
+                                        //Action_11: Merge labels of block Q and S
+                                        imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);
+                                        continue;
+                                    }
+                                    else {
+                                        if (condition_h) {
+                                            if (condition_c) {
+                                                //Action_11: Merge labels of block Q and S
+                                                imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);
+                                                continue;
+                                            }
+                                            else {
+                                                //Action_14: Merge labels of block P, Q and S
+                                                imgLabels_row[c] = set_union(P, set_union(P, imgLabels_row_prev_prev[c - 2], imgLabels_row_prev_prev[c]), imgLabels_row[c - 2]);
+                                                continue;
+                                            }
+                                        }
+                                        else {
+                                            //Action_11: Merge labels of block Q and S
+                                            imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);
+                                            continue;
+                                        }
+                                    }
+                                }
+                            }
+                            else {
+                                if (condition_p) {
+                                    if (condition_k) {
+                                        if (condition_m) {
+                                            if (condition_h) {
+                                                if (condition_d) {
+                                                    if (condition_i) {
+                                                        //Action_6: Assign label of block S
+                                                        imgLabels_row[c] = imgLabels_row[c - 2];
+                                                        continue;
+                                                    }
+                                                    else {
+                                                        if (condition_c) {
+                                                            //Action_6: Assign label of block S
+                                                            imgLabels_row[c] = imgLabels_row[c - 2];
+                                                            continue;
+                                                        }
+                                                        else {
+                                                            //Action_12: Merge labels of block R and S
+                                                            imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);
+                                                            continue;
+                                                        }
+                                                    }
+                                                }
+                                                else {
+                                                    //Action_12: Merge labels of block R and S
+                                                    imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);
+                                                    continue;
+                                                }
+                                            }
+                                            else {
+                                                if (condition_d) {
+                                                    if (condition_g) {
+                                                        if (condition_b) {
+                                                            if (condition_i) {
+                                                                //Action_6: Assign label of block S
+                                                                imgLabels_row[c] = imgLabels_row[c - 2];
+                                                                continue;
+                                                            }
+                                                            else {
+                                                                if (condition_c) {
+                                                                    //Action_6: Assign label of block S
+                                                                    imgLabels_row[c] = imgLabels_row[c - 2];
+                                                                    continue;
+                                                                }
+                                                                else {
+                                                                    //Action_12: Merge labels of block R and S
+                                                                    imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);
+                                                                    continue;
+                                                                }
+                                                            }
+                                                        }
+                                                        else {
+                                                            //Action_12: Merge labels of block R and S
+                                                            imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);
+                                                            continue;
+                                                        }
+                                                    }
+                                                    else {
+                                                        //Action_12: Merge labels of block R and S
+                                                        imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);
+                                                        continue;
+                                                    }
+                                                }
+                                                else {
+                                                    if (condition_i) {
+                                                        if (condition_g) {
+                                                            if (condition_b) {
+                                                                //Action_12: Merge labels of block R and S
+                                                                imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);
+                                                                continue;
+                                                            }
+                                                            else {
+                                                                //Action_16: labels of block Q, R and S
+                                                                imgLabels_row[c] = set_union(P, set_union(P, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]), imgLabels_row[c - 2]);
+                                                                continue;
+                                                            }
+                                                        }
+                                                        else {
+                                                            //Action_16: labels of block Q, R and S
+                                                            imgLabels_row[c] = set_union(P, set_union(P, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]), imgLabels_row[c - 2]);
+                                                            continue;
+                                                        }
+                                                    }
+                                                    else {
+                                                        //Action_12: Merge labels of block R and S
+                                                        imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);
+                                                        continue;
+                                                    }
+                                                }
+                                            }
+                                        }
+                                        else {
+                                            if (condition_i) {
+                                                if (condition_d) {
+                                                    //Action_12: Merge labels of block R and S
+                                                    imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);
+                                                    continue;
+                                                }
+                                                else {
+                                                    //Action_16: labels of block Q, R and S
+                                                    imgLabels_row[c] = set_union(P, set_union(P, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]), imgLabels_row[c - 2]);
+                                                    continue;
+                                                }
+                                            }
+                                            else {
+                                                if (condition_h) {
+                                                    if (condition_d) {
+                                                        if (condition_c) {
+                                                            //Action_12: Merge labels of block R and S
+                                                            imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);
+                                                            continue;
+                                                        }
+                                                        else {
+                                                            //Action_15: Merge labels of block P, R and S
+                                                            imgLabels_row[c] = set_union(P, set_union(P, imgLabels_row_prev_prev[c - 2], imgLabels_row_prev_prev[c + 2]), imgLabels_row[c - 2]);
+                                                            continue;
+                                                        }
+                                                    }
+                                                    else {
+                                                        //Action_15: Merge labels of block P, R and S
+                                                        imgLabels_row[c] = set_union(P, set_union(P, imgLabels_row_prev_prev[c - 2], imgLabels_row_prev_prev[c + 2]), imgLabels_row[c - 2]);
+                                                        continue;
+                                                    }
+                                                }
+                                                else {
+                                                    //Action_12: Merge labels of block R and S
+                                                    imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);
+                                                    continue;
+                                                }
+                                            }
+                                        }
+                                    }
+                                    else {
+                                        if (condition_h) {
+                                            if (condition_m) {
+                                                //Action_6: Assign label of block S
+                                                imgLabels_row[c] = imgLabels_row[c - 2];
+                                                continue;
+                                            }
+                                            else {
+                                                // ACTION_9 Merge labels of block P and S
+                                                imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c - 2], imgLabels_row[c - 2]);
+                                                continue;
+                                            }
+                                        }
+                                        else {
+                                            if (condition_i) {
+                                                if (condition_m) {
+                                                    if (condition_g) {
+                                                        if (condition_b) {
+                                                            //Action_6: Assign label of block S
+                                                            imgLabels_row[c] = imgLabels_row[c - 2];
+                                                            continue;
+                                                        }
+                                                        else {
+                                                            //Action_11: Merge labels of block Q and S
+                                                            imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);
+                                                            continue;
+                                                        }
+                                                    }
+                                                    else {
+                                                        //Action_11: Merge labels of block Q and S
+                                                        imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);
+                                                        continue;
+                                                    }
+                                                }
+                                                else {
+                                                    //Action_11: Merge labels of block Q and S
+                                                    imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);
+                                                    continue;
+                                                }
+                                            }
+                                            else {
+                                                //Action_6: Assign label of block S
+                                                imgLabels_row[c] = imgLabels_row[c - 2];
+                                                continue;
+                                            }
+                                        }
+                                    }
+                                }
+                                else {
+                                    if (condition_h) {
+                                        if (condition_m) {
+                                            //Action_6: Assign label of block S
+                                            imgLabels_row[c] = imgLabels_row[c - 2];
+                                            continue;
+                                        }
+                                        else {
+                                            // ACTION_9 Merge labels of block P and S
+                                            imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c - 2], imgLabels_row[c - 2]);
+                                            continue;
+                                        }
+                                    }
+                                    else {
+                                        if (condition_i) {
+                                            if (condition_m) {
+                                                if (condition_g) {
+                                                    if (condition_b) {
+                                                        //Action_6: Assign label of block S
+                                                        imgLabels_row[c] = imgLabels_row[c - 2];
+                                                        continue;
+                                                    }
+                                                    else {
+                                                        //Action_11: Merge labels of block Q and S
+                                                        imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);
+                                                        continue;
+                                                    }
+                                                }
+                                                else {
+                                                    //Action_11: Merge labels of block Q and S
+                                                    imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);
+                                                    continue;
+                                                }
+                                            }
+                                            else {
+                                                //Action_11: Merge labels of block Q and S
+                                                imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);
+                                                continue;
+                                            }
+                                        }
+                                        else {
+                                            //Action_6: Assign label of block S
+                                            imgLabels_row[c] = imgLabels_row[c - 2];
+                                            continue;
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                        else {
+                            if (condition_j) {
+                                if (condition_i) {
+                                    //Action_4: Assign label of block Q
+                                    imgLabels_row[c] = imgLabels_row_prev_prev[c];
+                                    continue;
+                                }
+                                else {
+                                    if (condition_h) {
+                                        if (condition_c) {
+                                            //Action_4: Assign label of block Q
+                                            imgLabels_row[c] = imgLabels_row_prev_prev[c];
+                                            continue;
+                                        }
+                                        else {
+                                            //Action_7: Merge labels of block P and Q
+                                            imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c - 2], imgLabels_row_prev_prev[c]);
+                                            continue;
+                                        }
+                                    }
+                                    else {
+                                        //Action_4: Assign label of block Q
+                                        imgLabels_row[c] = imgLabels_row_prev_prev[c];
+                                        continue;
+                                    }
+                                }
+                            }
+                            else {
+                                if (condition_p) {
+                                    if (condition_k) {
+                                        if (condition_i) {
+                                            if (condition_d) {
+                                                //Action_5: Assign label of block R
+                                                imgLabels_row[c] = imgLabels_row_prev_prev[c + 2];
+                                                continue;
+                                            }
+                                            else {
+                                                // ACTION_10 Merge labels of block Q and R
+                                                imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]);
+                                                continue;
+                                            }
+                                        }
+                                        else {
+                                            if (condition_h) {
+                                                if (condition_d) {
+                                                    if (condition_c) {
+                                                        //Action_5: Assign label of block R
+                                                        imgLabels_row[c] = imgLabels_row_prev_prev[c + 2];
+                                                        continue;
+                                                    }
+                                                    else {
+                                                        //Action_8: Merge labels of block P and R
+                                                        imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c - 2], imgLabels_row_prev_prev[c + 2]);
+                                                        continue;
+                                                    }
+                                                }
+                                                else {
+                                                    //Action_8: Merge labels of block P and R
+                                                    imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c - 2], imgLabels_row_prev_prev[c + 2]);
+                                                    continue;
+                                                }
+                                            }
+                                            else {
+                                                //Action_5: Assign label of block R
+                                                imgLabels_row[c] = imgLabels_row_prev_prev[c + 2];
+                                                continue;
+                                            }
+                                        }
+                                    }
+                                    else {
+                                        if (condition_i) {
+                                            //Action_4: Assign label of block Q
+                                            imgLabels_row[c] = imgLabels_row_prev_prev[c];
+                                            continue;
+                                        }
+                                        else {
+                                            if (condition_h) {
+                                                //Action_3: Assign label of block P
+                                                imgLabels_row[c] = imgLabels_row_prev_prev[c - 2];
+                                                continue;
+                                            }
+                                            else {
+                                                //Action_2: New label (the block has foreground pixels and is not connected to anything else)
+                                                imgLabels_row[c] = lunique;
+                                                P[lunique] = lunique;
+                                                lunique = lunique + 1;
+                                                continue;
+                                            }
+                                        }
+                                    }
+                                }
+                                else {
+                                    if (condition_i) {
+                                        //Action_4: Assign label of block Q
+                                        imgLabels_row[c] = imgLabels_row_prev_prev[c];
+                                        continue;
+                                    }
+                                    else {
+                                        if (condition_h) {
+                                            //Action_3: Assign label of block P
+                                            imgLabels_row[c] = imgLabels_row_prev_prev[c - 2];
+                                            continue;
+                                        }
+                                        else {
+                                            //Action_2: New label (the block has foreground pixels and is not connected to anything else)
+                                            imgLabels_row[c] = lunique;
+                                            P[lunique] = lunique;
+                                            lunique = lunique + 1;
+                                            continue;
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+                else {
+                    if (condition_s) {
+                        if (condition_p) {
+                            if (condition_n) {
+                                if (condition_j) {
+                                    if (condition_i) {
+                                        //Action_6: Assign label of block S
+                                        imgLabels_row[c] = imgLabels_row[c - 2];
+                                        continue;
+                                    }
+                                    else {
+                                        if (condition_c) {
+                                            if (condition_h) {
+                                                //Action_6: Assign label of block S
+                                                imgLabels_row[c] = imgLabels_row[c - 2];
+                                                continue;
+                                            }
+                                            else {
+                                                if (condition_g) {
+                                                    if (condition_b) {
+                                                        //Action_6: Assign label of block S
+                                                        imgLabels_row[c] = imgLabels_row[c - 2];
+                                                        continue;
+                                                    }
+                                                    else {
+                                                        //Action_11: Merge labels of block Q and S
+                                                        imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);
+                                                        continue;
+                                                    }
+                                                }
+                                                else {
+                                                    //Action_11: Merge labels of block Q and S
+                                                    imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);
+                                                    continue;
+                                                }
+                                            }
+                                        }
+                                        else {
+                                            //Action_11: Merge labels of block Q and S
+                                            imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);
+                                            continue;
+                                        }
+                                    }
+                                }
+                                else {
+                                    if (condition_k) {
+                                        if (condition_d) {
+                                            if (condition_i) {
+                                                //Action_6: Assign label of block S
+                                                imgLabels_row[c] = imgLabels_row[c - 2];
+                                                continue;
+                                            }
+                                            else {
+                                                if (condition_c) {
+                                                    if (condition_h) {
+                                                        //Action_6: Assign label of block S
+                                                        imgLabels_row[c] = imgLabels_row[c - 2];
+                                                        continue;
+                                                    }
+                                                    else {
+                                                        if (condition_g) {
+                                                            if (condition_b) {
+                                                                //Action_6: Assign label of block S
+                                                                imgLabels_row[c] = imgLabels_row[c - 2];
+                                                                continue;
+                                                            }
+                                                            else {
+                                                                //Action_12: Merge labels of block R and S
+                                                                imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);
+                                                                continue;
+                                                            }
+                                                        }
+                                                        else {
+                                                            //Action_12: Merge labels of block R and S
+                                                            imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);
+                                                            continue;
+                                                        }
+                                                    }
+                                                }
+                                                else {
+                                                    //Action_12: Merge labels of block R and S
+                                                    imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);
+                                                    continue;
+                                                }
+                                            }
+                                        }
+                                        else {
+                                            //Action_12: Merge labels of block R and S
+                                            imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);
+                                            continue;
+                                        }
+                                    }
+                                    else {
+                                        //Action_6: Assign label of block S
+                                        imgLabels_row[c] = imgLabels_row[c - 2];
+                                        continue;
+                                    }
+                                }
+                            }
+                            else {
+                                if (condition_r) {
+                                    if (condition_j) {
+                                        if (condition_m) {
+                                            if (condition_h) {
+                                                if (condition_i) {
+                                                    //Action_6: Assign label of block S
+                                                    imgLabels_row[c] = imgLabels_row[c - 2];
+                                                    continue;
+                                                }
+                                                else {
+                                                    if (condition_c) {
+                                                        //Action_6: Assign label of block S
+                                                        imgLabels_row[c] = imgLabels_row[c - 2];
+                                                        continue;
+                                                    }
+                                                    else {
+                                                        //Action_11: Merge labels of block Q and S
+                                                        imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);
+                                                        continue;
+                                                    }
+                                                }
+                                            }
+                                            else {
+                                                if (condition_g) {
+                                                    if (condition_b) {
+                                                        if (condition_i) {
+                                                            //Action_6: Assign label of block S
+                                                            imgLabels_row[c] = imgLabels_row[c - 2];
+                                                            continue;
+                                                        }
+                                                        else {
+                                                            if (condition_c) {
+                                                                //Action_6: Assign label of block S
+                                                                imgLabels_row[c] = imgLabels_row[c - 2];
+                                                                continue;
+                                                            }
+                                                            else {
+                                                                //Action_11: Merge labels of block Q and S
+                                                                imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);
+                                                                continue;
+                                                            }
+                                                        }
+                                                    }
+                                                    else {
+                                                        //Action_11: Merge labels of block Q and S
+                                                        imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);
+                                                        continue;
+                                                    }
+                                                }
+                                                else {
+                                                    //Action_11: Merge labels of block Q and S
+                                                    imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);
+                                                    continue;
+                                                }
+                                            }
+                                        }
+                                        else {
+                                            //Action_11: Merge labels of block Q and S
+                                            imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);
+                                            continue;
+                                        }
+                                    }
+                                    else {
+                                        if (condition_k) {
+                                            if (condition_d) {
+                                                if (condition_m) {
+                                                    if (condition_h) {
+                                                        if (condition_i) {
+                                                            //Action_6: Assign label of block S
+                                                            imgLabels_row[c] = imgLabels_row[c - 2];
+                                                            continue;
+                                                        }
+                                                        else {
+                                                            if (condition_c) {
+                                                                //Action_6: Assign label of block S
+                                                                imgLabels_row[c] = imgLabels_row[c - 2];
+                                                                continue;
+                                                            }
+                                                            else {
+                                                                //Action_12: Merge labels of block R and S
+                                                                imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);
+                                                                continue;
+                                                            }
+                                                        }
+                                                    }
+                                                    else {
+                                                        if (condition_g) {
+                                                            if (condition_b) {
+                                                                if (condition_i) {
+                                                                    //Action_6: Assign label of block S
+                                                                    imgLabels_row[c] = imgLabels_row[c - 2];
+                                                                    continue;
+                                                                }
+                                                                else {
+                                                                    if (condition_c) {
+                                                                        //Action_6: Assign label of block S
+                                                                        imgLabels_row[c] = imgLabels_row[c - 2];
+                                                                        continue;
+                                                                    }
+                                                                    else {
+                                                                        //Action_12: Merge labels of block R and S
+                                                                        imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);
+                                                                        continue;
+                                                                    }
+                                                                }
+                                                            }
+                                                            else {
+                                                                //Action_12: Merge labels of block R and S
+                                                                imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);
+                                                                continue;
+                                                            }
+                                                        }
+                                                        else {
+                                                            //Action_12: Merge labels of block R and S
+                                                            imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);
+                                                            continue;
+                                                        }
+                                                    }
+                                                }
+                                                else {
+                                                    //Action_12: Merge labels of block R and S
+                                                    imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);
+                                                    continue;
+                                                }
+                                            }
+                                            else {
+                                                if (condition_i) {
+                                                    if (condition_m) {
+                                                        if (condition_h) {
+                                                            //Action_12: Merge labels of block R and S
+                                                            imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);
+                                                            continue;
+                                                        }
+                                                        else {
+                                                            if (condition_g) {
+                                                                if (condition_b) {
+                                                                    //Action_12: Merge labels of block R and S
+                                                                    imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);
+                                                                    continue;
+                                                                }
+                                                                else {
+                                                                    //Action_16: labels of block Q, R and S
+                                                                    imgLabels_row[c] = set_union(P, set_union(P, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]), imgLabels_row[c - 2]);
+                                                                    continue;
+                                                                }
+                                                            }
+                                                            else {
+                                                                //Action_16: labels of block Q, R and S
+                                                                imgLabels_row[c] = set_union(P, set_union(P, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]), imgLabels_row[c - 2]);
+                                                                continue;
+                                                            }
+                                                        }
+                                                    }
+                                                    else {
+                                                        //Action_16: labels of block Q, R and S
+                                                        imgLabels_row[c] = set_union(P, set_union(P, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]), imgLabels_row[c - 2]);
+                                                        continue;
+                                                    }
+                                                }
+                                                else {
+                                                    //Action_12: Merge labels of block R and S
+                                                    imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c + 2], imgLabels_row[c - 2]);
+                                                    continue;
+                                                }
+                                            }
+                                        }
+                                        else {
+                                            if (condition_i) {
+                                                if (condition_m) {
+                                                    if (condition_h) {
+                                                        //Action_6: Assign label of block S
+                                                        imgLabels_row[c] = imgLabels_row[c - 2];
+                                                        continue;
+                                                    }
+                                                    else {
+                                                        if (condition_g) {
+                                                            if (condition_b) {
+                                                                //Action_6: Assign label of block S
+                                                                imgLabels_row[c] = imgLabels_row[c - 2];
+                                                                continue;
+                                                            }
+                                                            else {
+                                                                //Action_11: Merge labels of block Q and S
+                                                                imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);
+                                                                continue;
+                                                            }
+                                                        }
+                                                        else {
+                                                            //Action_11: Merge labels of block Q and S
+                                                            imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);
+                                                            continue;
+                                                        }
+                                                    }
+                                                }
+                                                else {
+                                                    //Action_11: Merge labels of block Q and S
+                                                    imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row[c - 2]);
+                                                    continue;
+                                                }
+                                            }
+                                            else {
+                                                //Action_6: Assign label of block S
+                                                imgLabels_row[c] = imgLabels_row[c - 2];
+                                                continue;
+                                            }
+                                        }
+                                    }
+                                }
+                                else {
+                                    if (condition_j) {
+                                        //Action_4: Assign label of block Q
+                                        imgLabels_row[c] = imgLabels_row_prev_prev[c];
+                                        continue;
+                                    }
+                                    else {
+                                        if (condition_k) {
+                                            if (condition_i) {
+                                                if (condition_d) {
+                                                    //Action_5: Assign label of block R
+                                                    imgLabels_row[c] = imgLabels_row_prev_prev[c + 2];
+                                                    continue;
+                                                }
+                                                else {
+                                                    // ACTION_10 Merge labels of block Q and R
+                                                    imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]);
+                                                    continue;
+                                                }
+                                            }
+                                            else {
+                                                //Action_5: Assign label of block R
+                                                imgLabels_row[c] = imgLabels_row_prev_prev[c + 2];
+                                                continue;
+                                            }
+                                        }
+                                        else {
+                                            if (condition_i) {
+                                                //Action_4: Assign label of block Q
+                                                imgLabels_row[c] = imgLabels_row_prev_prev[c];
+                                                continue;
+                                            }
+                                            else {
+                                                //Action_2: New label (the block has foreground pixels and is not connected to anything else)
+                                                imgLabels_row[c] = lunique;
+                                                P[lunique] = lunique;
+                                                lunique = lunique + 1;
+                                                continue;
+                                            }
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                        else {
+                            if (condition_r) {
+                                //Action_6: Assign label of block S
+                                imgLabels_row[c] = imgLabels_row[c - 2];
+                                continue;
+                            }
+                            else {
+                                if (condition_n) {
+                                    //Action_6: Assign label of block S
+                                    imgLabels_row[c] = imgLabels_row[c - 2];
+                                    continue;
+                                }
+                                else {
+                                    //Action_2: New label (the block has foreground pixels and is not connected to anything else)
+                                    imgLabels_row[c] = lunique;
+                                    P[lunique] = lunique;
+                                    lunique = lunique + 1;
+                                    continue;
+                                }
+                            }
+                        }
+                    }
+                    else {
+                        if (condition_p) {
+                            if (condition_j) {
+                                //Action_4: Assign label of block Q
+                                imgLabels_row[c] = imgLabels_row_prev_prev[c];
+                                continue;
+                            }
+                            else {
+                                if (condition_k) {
+                                    if (condition_i) {
+                                        if (condition_d) {
+                                            //Action_5: Assign label of block R
+                                            imgLabels_row[c] = imgLabels_row_prev_prev[c + 2];
+                                            continue;
+                                        }
+                                        else {
+                                            // ACTION_10 Merge labels of block Q and R
+                                            imgLabels_row[c] = set_union(P, imgLabels_row_prev_prev[c], imgLabels_row_prev_prev[c + 2]);
+                                            continue;
+                                        }
+                                    }
+                                    else {
+                                        //Action_5: Assign label of block R
+                                        imgLabels_row[c] = imgLabels_row_prev_prev[c + 2];
+                                        continue;
+                                    }
+                                }
+                                else {
+                                    if (condition_i) {
+                                        //Action_4: Assign label of block Q
+                                        imgLabels_row[c] = imgLabels_row_prev_prev[c];
+                                        continue;
+                                    }
+                                    else {
+                                        //Action_2: New label (the block has foreground pixels and is not connected to anything else)
+                                        imgLabels_row[c] = lunique;
+                                        P[lunique] = lunique;
+                                        lunique = lunique + 1;
+                                        continue;
+                                    }
+                                }
+                            }
+                        }
+                        else {
+                            if (condition_t) {
+                                //Action_2: New label (the block has foreground pixels and is not connected to anything else)
+                                imgLabels_row[c] = lunique;
+                                P[lunique] = lunique;
+                                lunique = lunique + 1;
+                                continue;
+                            }
+                            else {
+                                // Action_1: No action (the block has no foreground pixels)
+                                imgLabels_row[c] = 0;
+                                continue;
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        // Second scan + analysis
+        LabelT nLabels = flattenL(P, lunique);
+        sop.init(nLabels);
+
+        if (imgLabels.rows & 1){
+            if (imgLabels.cols & 1){
+                //Case 1: both rows and cols odd
+                for (int r = 0; r<imgLabels.rows; r += 2) {
+                    // Get rows pointer
+                    const PixelT* const img_row = img.ptr<PixelT>(r);
+                    const PixelT* const img_row_fol = (PixelT *)(((char *)img_row) + img.step.p[0]);
+                    LabelT* const imgLabels_row = imgLabels.ptr<LabelT>(r);
+                    LabelT* const imgLabels_row_fol = (LabelT *)(((char *)imgLabels_row) + imgLabels.step.p[0]);
+
+                    for (int c = 0; c<imgLabels.cols; c += 2) {
+                        LabelT iLabel = imgLabels_row[c];
+                        if (iLabel>0) {
+                            iLabel = P[iLabel];
+                            if (img_row[c] > 0){
+                                imgLabels_row[c] = iLabel;
+                                sop(r, c, iLabel);
+                            }
+                            else{
+                                imgLabels_row[c] = 0;
+                                sop(r, c, 0);
+                            }
+                            if (c + 1<imgLabels.cols) {
+                                if (img_row[c + 1] > 0){
+                                    imgLabels_row[c + 1] = iLabel;
+                                    sop(r, c + 1, iLabel);
+                                }
+                                else{
+                                    imgLabels_row[c + 1] = 0;
+                                    sop(r, c + 1, 0);
+                                }
+                                if (r + 1<imgLabels.rows) {
+                                    if (img_row_fol[c] > 0){
+                                        imgLabels_row_fol[c] = iLabel;
+                                        sop(r + 1, c, iLabel);
+                                    } else{
+                                        imgLabels_row_fol[c] = 0;
+                                        sop(r + 1, c, 0);
+                                    }
+                                    if (img_row_fol[c + 1]>0){
+                                        imgLabels_row_fol[c + 1] = iLabel;
+                                        sop(r + 1, c + 1, iLabel);
+                                    } else{
+                                        imgLabels_row_fol[c + 1] = 0;
+                                        sop(r + 1, c + 1, 0);
+                                    }
+                               }
+                            }
+                            else if (r + 1<imgLabels.rows) {
+                                if (img_row_fol[c]>0){
+                                    imgLabels_row_fol[c] = iLabel;
+                                    sop(r + 1, c, iLabel);
+                                }else{
+                                    imgLabels_row_fol[c] = 0;
+                                    sop(r + 1, c, 0);
+                                }
+                            }
+                        }
+                        else {
+                            imgLabels_row[c] = 0;
+                            sop(r, c, 0);
+                            if (c + 1<imgLabels.cols) {
+                                imgLabels_row[c + 1] = 0;
+                                sop(r, c + 1, 0);
+                                if (r + 1<imgLabels.rows) {
+                                    imgLabels_row_fol[c] = 0;
+                                    imgLabels_row_fol[c + 1] = 0;
+                                    sop(r + 1, c, 0);
+                                    sop(r + 1, c + 1, 0);
+                                }
+                            }else if (r + 1<imgLabels.rows) {
+                                imgLabels_row_fol[c] = 0;
+                                sop(r + 1, c, 0);
+                            }
+                        }
+                    }
+                }
+            }//END Case 1
+            else{
+                //Case 2: only rows odd
+                for (int r = 0; r<imgLabels.rows; r += 2) {
+                    // Get rows pointer
+                    const PixelT* const img_row = img.ptr<PixelT>(r);
+                    const PixelT* const img_row_fol = (PixelT *)(((char *)img_row) + img.step.p[0]);
+                    LabelT* const imgLabels_row = imgLabels.ptr<LabelT>(r);
+                    LabelT* const imgLabels_row_fol = (LabelT *)(((char *)imgLabels_row) + imgLabels.step.p[0]);
+
+                    for (int c = 0; c<imgLabels.cols; c += 2) {
+                        LabelT iLabel = imgLabels_row[c];
+                        if (iLabel>0) {
+                            iLabel = P[iLabel];
+                            if (img_row[c]>0){
+                                imgLabels_row[c] = iLabel;
+                                sop(r, c, iLabel);
+                            } else{
+                                imgLabels_row[c] = 0;
+                                sop(r, c, 0);
+                            }
+                            if (img_row[c + 1]>0){
+                                imgLabels_row[c + 1] = iLabel;
+                                sop(r, c + 1, iLabel);
+                            }else{
+                                imgLabels_row[c + 1] = 0;
+                                sop(r, c + 1, 0);
+                            }
+                            if (r + 1<imgLabels.rows) {
+                                if (img_row_fol[c]>0){
+                                    imgLabels_row_fol[c] = iLabel;
+                                    sop(r + 1, c, iLabel);
+                                }else{
+                                    imgLabels_row_fol[c] = 0;
+                                    sop(r + 1, c, 0);
+                                }
+                                if (img_row_fol[c + 1]>0){
+                                    imgLabels_row_fol[c + 1] = iLabel;
+                                    sop(r + 1, c + 1, iLabel);
+                                }else{
+                                    imgLabels_row_fol[c + 1] = 0;
+                                    sop(r + 1, c + 1, 0);
+                                }
+                            }
+                        }
+                        else {
+                            imgLabels_row[c] = 0;
+                            imgLabels_row[c + 1] = 0;
+                            sop(r, c, 0);
+                            sop(r, c + 1, 0);
+                            if (r + 1<imgLabels.rows) {
+                                imgLabels_row_fol[c] = 0;
+                                imgLabels_row_fol[c + 1] = 0;
+                                sop(r + 1, c, 0);
+                                sop(r + 1, c + 1, 0);
+                            }
+                        }
+                    }
+                }
+            }// END Case 2
+        }
+        else{
+            if (imgLabels.cols & 1){
+                //Case 3: only cols odd
+                for (int r = 0; r<imgLabels.rows; r += 2) {
+                    // Get rows pointer
+                    const PixelT* const img_row = img.ptr<PixelT>(r);
+                    const PixelT* const img_row_fol = (PixelT *)(((char *)img_row) + img.step.p[0]);
+                    LabelT* const imgLabels_row = imgLabels.ptr<LabelT>(r);
+                    LabelT* const imgLabels_row_fol = (LabelT *)(((char *)imgLabels_row) + imgLabels.step.p[0]);
+
+                    for (int c = 0; c<imgLabels.cols; c += 2) {
+                        LabelT iLabel = imgLabels_row[c];
+                        if (iLabel>0) {
+                            iLabel = P[iLabel];
+                            if (img_row[c]>0){
+                                imgLabels_row[c] = iLabel;
+                                sop(r, c, iLabel);
+                            }else{
+                                imgLabels_row[c] = 0;
+                                sop(r, c, 0);
+                            }
+                            if (img_row_fol[c]>0){
+                                imgLabels_row_fol[c] = iLabel;
+                                sop(r + 1, c, iLabel);
+                            }else{
+                                imgLabels_row_fol[c] = 0;
+                                sop(r + 1, c, 0);
+                            }
+                            if (c + 1<imgLabels.cols) {
+                                if (img_row[c + 1]>0){
+                                    imgLabels_row[c + 1] = iLabel;
+                                    sop(r, c + 1, iLabel);
+                                }else{
+                                    imgLabels_row[c + 1] = 0;
+                                    sop(r, c + 1, 0);
+                                }
+                                if (img_row_fol[c + 1]>0){
+                                    imgLabels_row_fol[c + 1] = iLabel;
+                                    sop(r + 1, c + 1, iLabel);
+                                }else{
+                                    imgLabels_row_fol[c + 1] = 0;
+                                    sop(r + 1, c + 1, 0);
+                                }
+                            }
+                        }
+                        else{
+                            imgLabels_row[c] = 0;
+                            imgLabels_row_fol[c] = 0;
+                            sop(r, c, 0);
+                            sop(r + 1, c, 0);
+                            if (c + 1<imgLabels.cols) {
+                                imgLabels_row[c + 1] = 0;
+                                imgLabels_row_fol[c + 1] = 0;
+                                sop(r, c + 1, 0);
+                                sop(r + 1, c + 1, 0);
+                            }
+                        }
+                    }
+                }
+            }// END case 3
+            else{
+                //Case 4: nothing odd
+                for (int r = 0; r < imgLabels.rows; r += 2) {
+                    // Get rows pointer
+                    const PixelT* const img_row = img.ptr<PixelT>(r);
+                    const PixelT* const img_row_fol = (PixelT *)(((char *)img_row) + img.step.p[0]);
+                    LabelT* const imgLabels_row = imgLabels.ptr<LabelT>(r);
+                    LabelT* const imgLabels_row_fol = (LabelT *)(((char *)imgLabels_row) + imgLabels.step.p[0]);
+
+                    for (int c = 0; c<imgLabels.cols; c += 2) {
+                        LabelT iLabel = imgLabels_row[c];
+                        if (iLabel>0) {
+                            iLabel = P[iLabel];
+                            if (img_row[c] > 0){
+                                imgLabels_row[c] = iLabel;
+                                sop(r, c, iLabel);
+                            }else{
+                                imgLabels_row[c] = 0;
+                                sop(r, c, 0);
+                            }
+                            if (img_row[c + 1] > 0){
+                                imgLabels_row[c + 1] = iLabel;
+                                sop(r, c + 1, iLabel);
+                            }else{
+                                imgLabels_row[c + 1] = 0;
+                                sop(r, c + 1, 0);
+                            }
+                            if (img_row_fol[c] > 0){
+                                imgLabels_row_fol[c] = iLabel;
+                                sop(r + 1, c, iLabel);
+                            }else{
+                                imgLabels_row_fol[c] = 0;
+                                sop(r + 1, c, 0);
+                            }
+                            if (img_row_fol[c + 1] > 0){
+                                imgLabels_row_fol[c + 1] = iLabel;
+                                sop(r + 1, c + 1, iLabel);
+                            }else{
+                                imgLabels_row_fol[c + 1] = 0;
+                                sop(r + 1, c + 1, 0);
+                            }
+                        }
+                        else {
+                            imgLabels_row[c] = 0;
+                            imgLabels_row[c + 1] = 0;
+                            imgLabels_row_fol[c] = 0;
+                            imgLabels_row_fol[c + 1] = 0;
+                            sop(r, c, 0);
+                            sop(r, c + 1, 0);
+                            sop(r + 1, c, 0);
+                            sop(r + 1, c + 1, 0);
+                        }
+                    }
+                }
+            }//END case 4
+        }
+
+        sop.finish();
+        fastFree(P);
+
+        return nLabels;
+
+    }   //End function LabelingGrana operator()
+    }; //End struct LabelingGrana
 }//end namespace connectedcomponents
 
 //L's type must have an appropriate depth for the number of pixels in I
 template<typename StatsOp>
 static
-int connectedComponents_sub1(const cv::Mat &I, cv::Mat &L, int connectivity, StatsOp &sop){
+int connectedComponents_sub1(const cv::Mat &I, cv::Mat &L, int connectivity, int ccltype, StatsOp &sop){
     CV_Assert(L.channels() == 1 && I.channels() == 1);
     CV_Assert(connectivity == 8 || connectivity == 4);
+    CV_Assert(ccltype == CCL_GRANA || ccltype == CCL_WU || ccltype == CCL_DEFAULT);
 
     int lDepth = L.depth();
     int iDepth = I.depth();
-    using connectedcomponents::LabelingImpl;
-    //warn if L's depth is not sufficient?
 
     CV_Assert(iDepth == CV_8U || iDepth == CV_8S);
 
-    if(lDepth == CV_8U){
-        return (int) LabelingImpl<uchar, uchar, StatsOp>()(I, L, connectivity, sop);
-    }else if(lDepth == CV_16U){
-        return (int) LabelingImpl<ushort, uchar, StatsOp>()(I, L, connectivity, sop);
-    }else if(lDepth == CV_32S){
-        //note that signed types don't really make sense here and not being able to use unsigned matters for scientific projects
-        //OpenCV: how should we proceed?  .at<T> typechecks in debug mode
-        return (int) LabelingImpl<int, uchar, StatsOp>()(I, L, connectivity, sop);
+    if (ccltype == CCL_WU || connectivity == 4){
+        // Wu algorithm is used
+        using connectedcomponents::LabelingWu;
+        //warn if L's depth is not sufficient?
+        if (lDepth == CV_8U){
+            return (int)LabelingWu<uchar, uchar, StatsOp>()(I, L, connectivity, sop);
+        }
+        else if (lDepth == CV_16U){
+            return (int)LabelingWu<ushort, uchar, StatsOp>()(I, L, connectivity, sop);
+        }
+        else if (lDepth == CV_32S){
+            //note that signed types don't really make sense here and not being able to use unsigned matters for scientific projects
+            //OpenCV: how should we proceed?  .at<T> typechecks in debug mode
+            return (int)LabelingWu<int, uchar, StatsOp>()(I, L, connectivity, sop);
+        }
+    }else if ((ccltype == CCL_GRANA || ccltype == CCL_DEFAULT) && connectivity == 8){
+        // Grana algorithm is used
+        using connectedcomponents::LabelingGrana;
+        //warn if L's depth is not sufficient?
+        if (lDepth == CV_8U){
+            return (int)LabelingGrana<uchar, uchar, StatsOp>()(I, L, connectivity, sop);
+        }
+        else if (lDepth == CV_16U){
+            return (int)LabelingGrana<ushort, uchar, StatsOp>()(I, L, connectivity, sop);
+        }
+        else if (lDepth == CV_32S){
+            //note that signed types don't really make sense here and not being able to use unsigned matters for scientific projects
+            //OpenCV: how should we proceed?  .at<T> typechecks in debug mode
+            return (int)LabelingGrana<int, uchar, StatsOp>()(I, L, connectivity, sop);
+        }
     }
 
     CV_Error(CV_StsUnsupportedFormat, "unsupported label/image type");
@@ -364,33 +1701,49 @@ int connectedComponents_sub1(const cv::Mat &I, cv::Mat &L, int connectivity, Sta
 
 }
 
+// Simple wrapper to ensure binary and source compatibility (ABI)
 int cv::connectedComponents(InputArray _img, OutputArray _labels, int connectivity, int ltype){
+    return cv::connectedComponents(_img, _labels, connectivity, ltype, CCL_DEFAULT);
+}
+
+int cv::connectedComponents(InputArray _img, OutputArray _labels, int connectivity, int ltype, int ccltype){
     const cv::Mat img = _img.getMat();
     _labels.create(img.size(), CV_MAT_DEPTH(ltype));
     cv::Mat labels = _labels.getMat();
     connectedcomponents::NoOp sop;
-    if(ltype == CV_16U){
-        return connectedComponents_sub1(img, labels, connectivity, sop);
-    }else if(ltype == CV_32S){
-        return connectedComponents_sub1(img, labels, connectivity, sop);
-    }else{
+    if (ltype == CV_16U){
+        return connectedComponents_sub1(img, labels, connectivity, ccltype, sop);
+    }
+    else if (ltype == CV_32S){
+        return connectedComponents_sub1(img, labels, connectivity, ccltype, sop);
+    }
+    else{
         CV_Error(CV_StsUnsupportedFormat, "the type of labels must be 16u or 32s");
         return 0;
     }
 }
 
+// Simple wrapper to ensure binary and source compatibility (ABI)
 int cv::connectedComponentsWithStats(InputArray _img, OutputArray _labels, OutputArray statsv,
                                      OutputArray centroids, int connectivity, int ltype)
 {
+    return cv::connectedComponentsWithStats(_img, _labels, statsv, centroids, connectivity, ltype, CCL_DEFAULT);
+}
+
+int cv::connectedComponentsWithStats(InputArray _img, OutputArray _labels, OutputArray statsv,
+                                     OutputArray centroids, int connectivity, int ltype, int ccltype)
+{
     const cv::Mat img = _img.getMat();
     _labels.create(img.size(), CV_MAT_DEPTH(ltype));
     cv::Mat labels = _labels.getMat();
     connectedcomponents::CCStatsOp sop(statsv, centroids);
-    if(ltype == CV_16U){
-        return connectedComponents_sub1(img, labels, connectivity, sop);
-    }else if(ltype == CV_32S){
-        return connectedComponents_sub1(img, labels, connectivity, sop);
-    }else{
+    if (ltype == CV_16U){
+        return connectedComponents_sub1(img, labels, connectivity, ccltype, sop);
+    }
+    else if (ltype == CV_32S){
+        return connectedComponents_sub1(img, labels, connectivity, ccltype, sop);
+    }
+    else{
         CV_Error(CV_StsUnsupportedFormat, "the type of labels must be 16u or 32s");
         return 0;
     }
diff --git a/modules/imgproc/src/contours.cpp b/modules/imgproc/src/contours.cpp
index 4cb3f55..baa27c4 100644
--- a/modules/imgproc/src/contours.cpp
+++ b/modules/imgproc/src/contours.cpp
@@ -50,6 +50,33 @@
 static const CvPoint icvCodeDeltas[8] =
     { CvPoint(1, 0), CvPoint(1, -1), CvPoint(0, -1), CvPoint(-1, -1), CvPoint(-1, 0), CvPoint(-1, 1), CvPoint(0, 1), CvPoint(1, 1) };
 
+#if CV_SSE2
+static
+inline unsigned int trailingZeros(unsigned int value) {
+    CV_DbgAssert(value != 0); // undefined for zero input (https://en.wikipedia.org/wiki/Find_first_set)
+#if defined(_MSC_VER)
+#if (_MSC_VER < 1700)
+    unsigned long index = 0;
+    _BitScanForward(&index, value);
+    return (unsigned int)index;
+#else
+    return _tzcnt_u32(value);
+#endif
+#elif defined(__GNUC__) || defined(__GNUG__)
+    return __builtin_ctz(value);
+#elif defined(__ICC) || defined(__INTEL_COMPILER)
+    return _bit_scan_forward(value);
+#elif defined(__clang__)
+    return llvm.cttz.i32(value, true);
+#else
+    static const int MultiplyDeBruijnBitPosition[32] = {
+        0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8,
+        31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9 };
+    return MultiplyDeBruijnBitPosition[((uint32_t)((value & -value) * 0x077CB531U)) >> 27];
+#endif
+}
+#endif
+
 CV_IMPL void
 cvStartReadChainPoints( CvChain * chain, CvChainPtReader * reader )
 {
@@ -178,10 +205,10 @@ _CvContourScanner;
    Initializes scanner structure.
    Prepare image for scanning ( clear borders and convert all pixels to 0-1.
 */
-CV_IMPL CvContourScanner
-cvStartFindContours( void* _img, CvMemStorage* storage,
+static CvContourScanner
+cvStartFindContours_Impl( void* _img, CvMemStorage* storage,
                      int  header_size, int mode,
-                     int  method, CvPoint offset )
+                     int  method, CvPoint offset, int needFillBorder )
 {
     if( !storage )
         CV_Error( CV_StsNullPtr, "" );
@@ -285,16 +312,22 @@ cvStartFindContours( void* _img, CvMemStorage* storage,
                                           scanner->cinfo_storage );
     }
 
-    /* make zero borders */
-    int esz = CV_ELEM_SIZE(mat->type);
-    memset( img, 0, size.width*esz );
-    memset( img + step * (size.height - 1), 0, size.width*esz );
+    CV_Assert(step >= 0);
+    CV_Assert(size.height >= 1);
 
-    img += step;
-    for( int y = 1; y < size.height - 1; y++, img += step )
+    /* make zero borders */
+    if(needFillBorder)
     {
-        for( int k = 0; k < esz; k++ )
-            img[k] = img[(size.width - 1)*esz + k] = (schar)0;
+        int esz = CV_ELEM_SIZE(mat->type);
+        memset( img, 0, size.width*esz );
+        memset( img + static_cast<size_t>(step) * (size.height - 1), 0, size.width*esz );
+
+        img += step;
+        for( int y = 1; y < size.height - 1; y++, img += step )
+        {
+            for( int k = 0; k < esz; k++ )
+                img[k] = img[(size.width - 1)*esz + k] = (schar)0;
+        }
     }
 
     /* converts all pixels to 0 or 1 */
@@ -304,6 +337,14 @@ cvStartFindContours( void* _img, CvMemStorage* storage,
     return scanner;
 }
 
+CV_IMPL CvContourScanner
+cvStartFindContours( void* _img, CvMemStorage* storage,
+                     int  header_size, int mode,
+                     int  method, CvPoint offset )
+{
+    return cvStartFindContours_Impl(_img, storage, header_size, mode, method, offset, 1);
+}
+
 /*
    Final stage of contour processing.
    Three variants possible:
@@ -527,10 +568,8 @@ icvFetchContour( schar                  *ptr,
     {
         s = (s - 1) & 7;
         i1 = i0 + deltas[s];
-        if( *i1 != 0 )
-            break;
     }
-    while( s != s_end );
+    while( *i1 == 0 && s != s_end );
 
     if( s == s_end )            /* single pixel domain */
     {
@@ -631,10 +670,8 @@ icvTraceContour( schar *ptr, int step, schar *stop_ptr, int is_hole )
     {
         s = (s - 1) & 7;
         i1 = i0 + deltas[s];
-        if( *i1 != 0 )
-            break;
     }
-    while( s != s_end );
+    while( *i1 == 0 && s != s_end );
 
     i3 = i0;
 
@@ -644,7 +681,6 @@ icvTraceContour( schar *ptr, int step, schar *stop_ptr, int is_hole )
         /* follow border */
         for( ;; )
         {
-            s_end = s;
 
             for( ;; )
             {
@@ -702,10 +738,8 @@ icvFetchContourEx( schar*               ptr,
     {
         s = (s - 1) & 7;
         i1 = i0 + deltas[s];
-        if( *i1 != 0 )
-            break;
     }
-    while( s != s_end );
+    while( *i1 == 0 && s != s_end );
 
     if( s == s_end )            /* single pixel domain */
     {
@@ -817,10 +851,8 @@ icvTraceContour_32s( int *ptr, int step, int *stop_ptr, int is_hole )
     {
         s = (s - 1) & 7;
         i1 = i0 + deltas[s];
-        if( (*i1 & value_mask) == ccomp_val )
-            break;
     }
-    while( s != s_end );
+    while( (*i1 & value_mask) != ccomp_val && s != s_end );
 
     i3 = i0;
 
@@ -892,10 +924,8 @@ icvFetchContourEx_32s( int*                 ptr,
     {
         s = (s - 1) & 7;
         i1 = i0 + deltas[s];
-        if( (*i1 & value_mask) == ccomp_val )
-            break;
     }
-    while( s != s_end );
+    while( (*i1 & value_mask) != ccomp_val && s != s_end );
 
     if( s == s_end )            /* single pixel domain */
     {
@@ -990,6 +1020,13 @@ cvFindNextContour( CvContourScanner scanner )
 {
     if( !scanner )
         CV_Error( CV_StsNullPtr, "" );
+
+#if CV_SSE2
+    bool haveSIMD = cv::checkHardwareSupport(CPU_SSE2);
+#endif
+
+    CV_Assert(scanner->img_step >= 0);
+
     icvEndProcessContour( scanner );
 
     /* initialize local state */
@@ -1034,13 +1071,60 @@ cvFindNextContour( CvContourScanner scanner )
             }
             else
             {
+#if CV_SSE2
+                if ((p = img[x]) != prev) {
+                    goto _next_contour;
+                } else if (haveSIMD) {
+
+                    __m128i v_prev = _mm_set1_epi8((char)prev);
+                    int v_size = width - 32;
+
+                    for (; x <= v_size; x += 32) {
+                        __m128i v_p1 = _mm_loadu_si128((const __m128i*)(img + x));
+                        __m128i v_p2 = _mm_loadu_si128((const __m128i*)(img + x + 16));
+
+                        __m128i v_cmp1 = _mm_cmpeq_epi8(v_p1, v_prev);
+                        __m128i v_cmp2 = _mm_cmpeq_epi8(v_p2, v_prev);
+
+                        unsigned int mask1 = _mm_movemask_epi8(v_cmp1);
+                        unsigned int mask2 = _mm_movemask_epi8(v_cmp2);
+
+                        mask1 ^= 0x0000ffff;
+                        mask2 ^= 0x0000ffff;
+
+                        if (mask1) {
+                            p = img[(x += trailingZeros(mask1))];
+                            goto _next_contour;
+                        }
+
+                        if (mask2) {
+                            p = img[(x += trailingZeros(mask2 << 16))];
+                            goto _next_contour;
+                        }
+                    }
+
+                    if(x <= width - 16) {
+                        __m128i v_p = _mm_loadu_si128((__m128i*)(img + x));
+
+                        unsigned int mask = _mm_movemask_epi8(_mm_cmpeq_epi8(v_p, v_prev)) ^ 0x0000ffff;
+
+                        if (mask) {
+                            p = img[(x += trailingZeros(mask))];
+                            goto _next_contour;
+                        }
+                        x += 16;
+                    }
+                }
+#endif
                 for( ; x < width && (p = img[x]) == prev; x++ )
                     ;
             }
 
             if( x >= width )
                 break;
-
+#if CV_SSE2
+        _next_contour:
+#endif
             {
                 _CvContourInfo *par_info = 0;
                 _CvContourInfo *l_cinfo = 0;
@@ -1064,7 +1148,7 @@ cvFindNextContour( CvContourScanner scanner )
                     is_hole = 1;
                 }
 
-                if( mode == 0 && (is_hole || img0[lnbd.y * step + lnbd.x] > 0) )
+                if( mode == 0 && (is_hole || img0[lnbd.y * static_cast<size_t>(step) + lnbd.x] > 0) )
                     goto resume_scan;
 
                 origin.y = y;
@@ -1078,8 +1162,8 @@ cvFindNextContour( CvContourScanner scanner )
                 else
                 {
                     int lval = (img0_i ?
-                        img0_i[lnbd.y * step_i + lnbd.x] :
-                        (int)img0[lnbd.y * step + lnbd.x]) & 0x7f;
+                        img0_i[lnbd.y * static_cast<size_t>(step_i) + lnbd.x] :
+                        (int)img0[lnbd.y * static_cast<size_t>(step) + lnbd.x]) & 0x7f;
                     _CvContourInfo *cur = scanner->cinfo_table[lval];
 
                     /* find the first bounding contour */
@@ -1091,11 +1175,11 @@ cvFindNextContour( CvContourScanner scanner )
                             if( par_info )
                             {
                                 if( (img0_i &&
-                                     icvTraceContour_32s( img0_i + par_info->origin.y * step_i +
+                                     icvTraceContour_32s( img0_i + par_info->origin.y * static_cast<size_t>(step_i) +
                                                           par_info->origin.x, step_i, img_i + lnbd.x,
                                                           par_info->is_hole ) > 0) ||
                                     (!img0_i &&
-                                     icvTraceContour( img0 + par_info->origin.y * step +
+                                     icvTraceContour( img0 + par_info->origin.y * static_cast<size_t>(step) +
                                                       par_info->origin.x, step, img + lnbd.x,
                                                       par_info->is_hole ) > 0) )
                                     break;
@@ -1275,7 +1359,6 @@ cvEndFindContours( CvContourScanner * _scanner )
 #define ICV_SINGLE                  0
 #define ICV_CONNECTING_ABOVE        1
 #define ICV_CONNECTING_BELOW        -1
-#define ICV_IS_COMPONENT_POINT(val) ((val) != 0)
 
 #define CV_GET_WRITTEN_ELEM( writer ) ((writer).ptr - (writer).seq->elem_size)
 
@@ -1287,6 +1370,105 @@ typedef  struct CvLinkedRunPoint
 }
 CvLinkedRunPoint;
 
+inline int findStartContourPoint(uchar *src_data, CvSize img_size, int j, bool haveSIMD) {
+#if CV_SSE2
+    if (haveSIMD) {
+        __m128i v_zero = _mm_setzero_si128();
+        int v_size = img_size.width - 32;
+
+        for (; j <= v_size; j += 32) {
+            __m128i v_p1 = _mm_loadu_si128((const __m128i*)(src_data + j));
+            __m128i v_p2 = _mm_loadu_si128((const __m128i*)(src_data + j + 16));
+
+            __m128i v_cmp1 = _mm_cmpeq_epi8(v_p1, v_zero);
+            __m128i v_cmp2 = _mm_cmpeq_epi8(v_p2, v_zero);
+
+            unsigned int mask1 = _mm_movemask_epi8(v_cmp1);
+            unsigned int mask2 = _mm_movemask_epi8(v_cmp2);
+
+            mask1 ^= 0x0000ffff;
+            mask2 ^= 0x0000ffff;
+
+            if (mask1) {
+                j += trailingZeros(mask1);
+                return j;
+            }
+
+            if (mask2) {
+                j += trailingZeros(mask2 << 16);
+                return j;
+            }
+        }
+
+        if (j <= img_size.width - 16) {
+            __m128i v_p = _mm_loadu_si128((const __m128i*)(src_data + j));
+
+            unsigned int mask = _mm_movemask_epi8(_mm_cmpeq_epi8(v_p, v_zero)) ^ 0x0000ffff;
+
+            if (mask) {
+                j += trailingZeros(mask);
+                return j;
+            }
+            j += 16;
+        }
+    }
+#else
+    CV_UNUSED(haveSIMD);
+#endif
+    for (; j < img_size.width && !src_data[j]; ++j)
+        ;
+    return j;
+}
+
+inline int findEndContourPoint(uchar *src_data, CvSize img_size, int j, bool haveSIMD) {
+#if CV_SSE2
+    if (j < img_size.width && !src_data[j]) {
+        return j;
+    } else if (haveSIMD) {
+        __m128i v_zero = _mm_setzero_si128();
+        int v_size = img_size.width - 32;
+
+        for (; j <= v_size; j += 32) {
+            __m128i v_p1 = _mm_loadu_si128((const __m128i*)(src_data + j));
+            __m128i v_p2 = _mm_loadu_si128((const __m128i*)(src_data + j + 16));
+
+            __m128i v_cmp1 = _mm_cmpeq_epi8(v_p1, v_zero);
+            __m128i v_cmp2 = _mm_cmpeq_epi8(v_p2, v_zero);
+
+            unsigned int mask1 = _mm_movemask_epi8(v_cmp1);
+            unsigned int mask2 = _mm_movemask_epi8(v_cmp2);
+
+            if (mask1) {
+                j += trailingZeros(mask1);
+                return j;
+            }
+
+            if (mask2) {
+                j += trailingZeros(mask2 << 16);
+                return j;
+            }
+        }
+
+        if (j <= img_size.width - 16) {
+            __m128i v_p = _mm_loadu_si128((const __m128i*)(src_data + j));
+
+            unsigned int mask = _mm_movemask_epi8(_mm_cmpeq_epi8(v_p, v_zero));
+
+            if (mask) {
+                j += trailingZeros(mask);
+                return j;
+            }
+            j += 16;
+        }
+    }
+#else
+    CV_UNUSED(haveSIMD);
+#endif
+    for (; j < img_size.width && src_data[j]; ++j)
+        ;
+
+    return j;
+}
 
 static int
 icvFindContoursInInterval( const CvArr* src,
@@ -1310,6 +1492,7 @@ icvFindContoursInInterval( const CvArr* src,
     int  lower_total;
     int  upper_total;
     int  all_total;
+    bool haveSIMD = false;
 
     CvSeq*  runs;
     CvLinkedRunPoint  tmp;
@@ -1339,7 +1522,9 @@ icvFindContoursInInterval( const CvArr* src,
 
     if( contourHeaderSize < (int)sizeof(CvContour))
         CV_Error( CV_StsBadSize, "Contour header size must be >= sizeof(CvContour)" );
-
+#if CV_SSE2
+    haveSIMD = cv::checkHardwareSupport(CPU_SSE2);
+#endif
     storage00.reset(cvCreateChildMemStorage(storage));
     storage01.reset(cvCreateChildMemStorage(storage));
 
@@ -1372,8 +1557,8 @@ icvFindContoursInInterval( const CvArr* src,
     tmp_prev = upper_line;
     for( j = 0; j < img_size.width; )
     {
-        for( ; j < img_size.width && !ICV_IS_COMPONENT_POINT(src_data[j]); j++ )
-            ;
+        j = findStartContourPoint(src_data, img_size, j, haveSIMD);
+
         if( j == img_size.width )
             break;
 
@@ -1382,10 +1567,9 @@ icvFindContoursInInterval( const CvArr* src,
         tmp_prev->next = (CvLinkedRunPoint*)CV_GET_WRITTEN_ELEM( writer );
         tmp_prev = tmp_prev->next;
 
-        for( ; j < img_size.width && ICV_IS_COMPONENT_POINT(src_data[j]); j++ )
-            ;
+        j = findEndContourPoint(src_data, img_size, j + 1, haveSIMD);
 
-        tmp.pt.x = j-1;
+        tmp.pt.x = j - 1;
         CV_WRITE_SEQ_ELEM( tmp, writer );
         tmp_prev->next = (CvLinkedRunPoint*)CV_GET_WRITTEN_ELEM( writer );
         tmp_prev->link = tmp_prev->next;
@@ -1407,8 +1591,8 @@ icvFindContoursInInterval( const CvArr* src,
         all_total = runs->total;
         for( j = 0; j < img_size.width; )
         {
-            for( ; j < img_size.width && !ICV_IS_COMPONENT_POINT(src_data[j]); j++ )
-                ;
+            j = findStartContourPoint(src_data, img_size, j, haveSIMD);
+
             if( j == img_size.width ) break;
 
             tmp.pt.x = j;
@@ -1416,10 +1600,9 @@ icvFindContoursInInterval( const CvArr* src,
             tmp_prev->next = (CvLinkedRunPoint*)CV_GET_WRITTEN_ELEM( writer );
             tmp_prev = tmp_prev->next;
 
-            for( ; j < img_size.width && ICV_IS_COMPONENT_POINT(src_data[j]); j++ )
-                ;
+            j = findEndContourPoint(src_data, img_size, j + 1, haveSIMD);
 
-            tmp.pt.x = j-1;
+            tmp.pt.x = j - 1;
             CV_WRITE_SEQ_ELEM( tmp, writer );
             tmp_prev = tmp_prev->next = (CvLinkedRunPoint*)CV_GET_WRITTEN_ELEM( writer );
         }//j
@@ -1630,33 +1813,11 @@ icvFindContoursInInterval( const CvArr* src,
     return count;
 }
 
-
-
-/*F///////////////////////////////////////////////////////////////////////////////////////
-//    Name: cvFindContours
-//    Purpose:
-//      Finds all the contours on the bi-level image.
-//    Context:
-//    Parameters:
-//      img  - source image.
-//             Non-zero pixels are considered as 1-pixels
-//             and zero pixels as 0-pixels.
-//      step - full width of source image in bytes.
-//      size - width and height of the image in pixels
-//      storage - pointer to storage where will the output contours be placed.
-//      header_size - header size of resulting contours
-//      mode - mode of contour retrieval.
-//      method - method of approximation that is applied to contours
-//      first_contour - pointer to first contour pointer
-//    Returns:
-//      CV_OK or error code
-//    Notes:
-//F*/
-CV_IMPL int
-cvFindContours( void*  img,  CvMemStorage*  storage,
+static int
+cvFindContours_Impl( void*  img,  CvMemStorage*  storage,
                 CvSeq**  firstContour, int  cntHeaderSize,
                 int  mode,
-                int  method, CvPoint offset )
+                int  method, CvPoint offset, int needFillBorder )
 {
     CvContourScanner scanner = 0;
     CvSeq *contour = 0;
@@ -1679,7 +1840,8 @@ cvFindContours( void*  img,  CvMemStorage*  storage,
     {
         try
         {
-            scanner = cvStartFindContours( img, storage, cntHeaderSize, mode, method, offset );
+            scanner = cvStartFindContours_Impl( img, storage, cntHeaderSize, mode, method, offset,
+                                            needFillBorder);
 
             do
             {
@@ -1701,22 +1863,54 @@ cvFindContours( void*  img,  CvMemStorage*  storage,
     return count;
 }
 
+/*F///////////////////////////////////////////////////////////////////////////////////////
+//    Name: cvFindContours
+//    Purpose:
+//      Finds all the contours on the bi-level image.
+//    Context:
+//    Parameters:
+//      img  - source image.
+//             Non-zero pixels are considered as 1-pixels
+//             and zero pixels as 0-pixels.
+//      step - full width of source image in bytes.
+//      size - width and height of the image in pixels
+//      storage - pointer to storage where will the output contours be placed.
+//      header_size - header size of resulting contours
+//      mode - mode of contour retrieval.
+//      method - method of approximation that is applied to contours
+//      first_contour - pointer to first contour pointer
+//    Returns:
+//      CV_OK or error code
+//    Notes:
+//F*/
+CV_IMPL int
+cvFindContours( void*  img,  CvMemStorage*  storage,
+                CvSeq**  firstContour, int  cntHeaderSize,
+                int  mode,
+                int  method, CvPoint offset )
+{
+    return cvFindContours_Impl(img, storage, firstContour, cntHeaderSize, mode, method, offset, 1);
+}
+
 void cv::findContours( InputOutputArray _image, OutputArrayOfArrays _contours,
                    OutputArray _hierarchy, int mode, int method, Point offset )
 {
+    CV_INSTRUMENT_REGION()
+
     // Sanity check: output must be of type vector<vector<Point>>
     CV_Assert((_contours.kind() == _InputArray::STD_VECTOR_VECTOR || _contours.kind() == _InputArray::STD_VECTOR_MAT ||
                 _contours.kind() == _InputArray::STD_VECTOR_UMAT));
 
     CV_Assert(_contours.empty() || (_contours.channels() == 2 && _contours.depth() == CV_32S));
 
-    Mat image = _image.getMat();
+    Mat image;
+    copyMakeBorder(_image, image, 1, 1, 1, 1, BORDER_CONSTANT | BORDER_ISOLATED, Scalar(0));
     MemStorage storage(cvCreateMemStorage());
     CvMat _cimage = image;
     CvSeq* _ccontours = 0;
     if( _hierarchy.needed() )
         _hierarchy.clear();
-    cvFindContours(&_cimage, storage, &_ccontours, sizeof(CvContour), mode, method, offset);
+    cvFindContours_Impl(&_cimage, storage, &_ccontours, sizeof(CvContour), mode, method, offset + Point(-1, -1), 0);
     if( !_ccontours )
     {
         _contours.clear();
@@ -1757,6 +1951,8 @@ void cv::findContours( InputOutputArray _image, OutputArrayOfArrays _contours,
 void cv::findContours( InputOutputArray _image, OutputArrayOfArrays _contours,
                        int mode, int method, Point offset)
 {
+    CV_INSTRUMENT_REGION()
+
     findContours(_image, _contours, noArray(), mode, method, offset);
 }
 
diff --git a/modules/imgproc/src/convhull.cpp b/modules/imgproc/src/convhull.cpp
index df50dde..1f8ef7b 100644
--- a/modules/imgproc/src/convhull.cpp
+++ b/modules/imgproc/src/convhull.cpp
@@ -128,6 +128,8 @@ struct CHullCmpPoints
 
 void convexHull( InputArray _points, OutputArray _hull, bool clockwise, bool returnPoints )
 {
+    CV_INSTRUMENT_REGION()
+
     Mat points = _points.getMat();
     int i, total = points.checkVector(2), depth = points.depth(), nout = 0;
     int miny_ind = 0, maxy_ind = 0;
@@ -264,6 +266,8 @@ void convexHull( InputArray _points, OutputArray _hull, bool clockwise, bool ret
 
 void convexityDefects( InputArray _points, InputArray _hull, OutputArray _defects )
 {
+    CV_INSTRUMENT_REGION()
+
     Mat points = _points.getMat();
     int i, j = 0, npoints = points.checkVector(2, CV_32S);
     CV_Assert( npoints >= 0 );
@@ -276,11 +280,16 @@ void convexityDefects( InputArray _points, InputArray _hull, OutputArray _defect
 
     Mat hull = _hull.getMat();
     int hpoints = hull.checkVector(1, CV_32S);
-    CV_Assert( hpoints > 2 );
+    CV_Assert( hpoints > 0 );
 
     const Point* ptr = points.ptr<Point>();
     const int* hptr = hull.ptr<int>();
     std::vector<Vec4i> defects;
+    if ( hpoints < 3 ) //if hull consists of one or two points, contour is always convex
+    {
+        _defects.release();
+        return;
+    }
 
     // 1. recognize co-orientation of the contour and its hull
     bool rev_orientation = ((hptr[1] > hptr[0]) + (hptr[2] > hptr[1]) + (hptr[0] > hptr[2])) != 2;
@@ -302,7 +311,7 @@ void convexityDefects( InputArray _points, InputArray _hull, OutputArray _defect
         int defect_deepest_point = -1;
         double defect_depth = 0;
         bool is_defect = false;
-
+        j=hcurr;
         for(;;)
         {
             // go through points to achieve next hull point
diff --git a/modules/imgproc/src/corner.cpp b/modules/imgproc/src/corner.cpp
index 946625e..7f3bad5 100644
--- a/modules/imgproc/src/corner.cpp
+++ b/modules/imgproc/src/corner.cpp
@@ -528,6 +528,8 @@ namespace cv
 {
 static bool ipp_cornerMinEigenVal( InputArray _src, OutputArray _dst, int blockSize, int ksize, int borderType )
 {
+    CV_INSTRUMENT_REGION_IPP()
+
 #if IPP_VERSION_X100 >= 800
     Mat src = _src.getMat();
     _dst.create( src.size(), CV_32FC1 );
@@ -552,23 +554,23 @@ static bool ipp_cornerMinEigenVal( InputArray _src, OutputArray _dst, int blockS
             (kerSize == 3 || kerSize == 5) && (blockSize == 3 || blockSize == 5))
         {
             ippiMinEigenValGetBufferSize getBufferSizeFunc = 0;
-            ippiMinEigenVal minEigenValFunc = 0;
+            ippiMinEigenVal ippiMinEigenVal_C1R = 0;
             float norm_coef = 0.f;
 
             if (src.type() == CV_8UC1)
             {
                 getBufferSizeFunc = (ippiMinEigenValGetBufferSize) ippiMinEigenValGetBufferSize_8u32f_C1R;
-                minEigenValFunc = (ippiMinEigenVal) ippiMinEigenVal_8u32f_C1R;
+                ippiMinEigenVal_C1R = (ippiMinEigenVal) ippiMinEigenVal_8u32f_C1R;
                 norm_coef = 1.f / 255.f;
             } else if (src.type() == CV_32FC1)
             {
                 getBufferSizeFunc = (ippiMinEigenValGetBufferSize) ippiMinEigenValGetBufferSize_32f_C1R;
-                minEigenValFunc = (ippiMinEigenVal) ippiMinEigenVal_32f_C1R;
+                ippiMinEigenVal_C1R = (ippiMinEigenVal) ippiMinEigenVal_32f_C1R;
                 norm_coef = 255.f;
             }
             norm_coef = kerType == ippKernelSobel ? norm_coef : norm_coef / 2.45f;
 
-            if (getBufferSizeFunc && minEigenValFunc)
+            if (getBufferSizeFunc && ippiMinEigenVal_C1R)
             {
                 int bufferSize;
                 IppiSize srcRoi = { src.cols, src.rows };
@@ -576,9 +578,9 @@ static bool ipp_cornerMinEigenVal( InputArray _src, OutputArray _dst, int blockS
                 if (ok >= 0)
                 {
                     AutoBuffer<uchar> buffer(bufferSize);
-                    ok = minEigenValFunc(src.ptr(), (int) src.step, dst.ptr<Ipp32f>(), (int) dst.step, srcRoi, kerType, kerSize, blockSize, buffer);
+                    ok = CV_INSTRUMENT_FUN_IPP(ippiMinEigenVal_C1R, src.ptr(), (int) src.step, dst.ptr<Ipp32f>(), (int) dst.step, srcRoi, kerType, kerSize, blockSize, buffer);
                     CV_SUPPRESS_DEPRECATED_START
-                    if (ok >= 0) ok = ippiMulC_32f_C1IR(norm_coef, dst.ptr<Ipp32f>(), (int) dst.step, srcRoi);
+                    if (ok >= 0) ok = CV_INSTRUMENT_FUN_IPP(ippiMulC_32f_C1IR, norm_coef, dst.ptr<Ipp32f>(), (int) dst.step, srcRoi);
                     CV_SUPPRESS_DEPRECATED_END
                     if (ok >= 0)
                     {
@@ -599,6 +601,8 @@ static bool ipp_cornerMinEigenVal( InputArray _src, OutputArray _dst, int blockS
 
 void cv::cornerMinEigenVal( InputArray _src, OutputArray _dst, int blockSize, int ksize, int borderType )
 {
+    CV_INSTRUMENT_REGION()
+
     CV_OCL_RUN(_src.dims() <= 2 && _dst.isUMat(),
                ocl_cornerMinEigenValVecs(_src, _dst, blockSize, ksize, 0.0, borderType, MINEIGENVAL))
 
@@ -609,7 +613,7 @@ void cv::cornerMinEigenVal( InputArray _src, OutputArray _dst, int blockSize, in
 #endif
     CV_IPP_RUN(((borderTypeNI == BORDER_REPLICATE && (!_src.isSubmatrix() || isolated)) &&
             (kerSize == 3 || kerSize == 5) && (blockSize == 3 || blockSize == 5)) && IPP_VERSION_X100 >= 800,
-    ipp_cornerMinEigenVal( _src, _dst, blockSize, ksize, borderType ));
+        ipp_cornerMinEigenVal( _src, _dst, blockSize, ksize, borderType ));
 
 
     Mat src = _src.getMat();
@@ -625,6 +629,8 @@ namespace cv
 {
 static bool ipp_cornerHarris( InputArray _src, OutputArray _dst, int blockSize, int ksize, double k, int borderType )
 {
+    CV_INSTRUMENT_REGION_IPP()
+
 #if IPP_VERSION_X100 >= 810 && IPP_DISABLE_BLOCK
     Mat src = _src.getMat();
     _dst.create( src.size(), CV_32FC1 );
@@ -658,11 +664,11 @@ static bool ipp_cornerHarris( InputArray _src, OutputArray _dst, int blockSize,
                 IppStatus status = (IppStatus)-1;
 
                 if (depth == CV_8U)
-                    status = ippiHarrisCorner_8u32f_C1R((const Ipp8u *)src.data, (int)src.step, (Ipp32f *)dst.data, (int)dst.step, roisize,
-                                                        filterType, masksize, blockSize, (Ipp32f)k, (Ipp32f)scale, borderTypeIpp, 0, buffer);
+                    status = CV_INSTRUMENT_FUN_IPP(ippiHarrisCorner_8u32f_C1R,((const Ipp8u *)src.data, (int)src.step, (Ipp32f *)dst.data, (int)dst.step, roisize,
+                        filterType, masksize, blockSize, (Ipp32f)k, (Ipp32f)scale, borderTypeIpp, 0, buffer));
                 else if (depth == CV_32F)
-                    status = ippiHarrisCorner_32f_C1R((const Ipp32f *)src.data, (int)src.step, (Ipp32f *)dst.data, (int)dst.step, roisize,
-                                                      filterType, masksize, blockSize, (Ipp32f)k, (Ipp32f)scale, borderTypeIpp, 0, buffer);
+                    status = CV_INSTRUMENT_FUN_IPP(ippiHarrisCorner_32f_C1R,((const Ipp32f *)src.data, (int)src.step, (Ipp32f *)dst.data, (int)dst.step, roisize,
+                        filterType, masksize, blockSize, (Ipp32f)k, (Ipp32f)scale, borderTypeIpp, 0, buffer));
                 ippsFree(buffer);
 
                 if (status >= 0)
@@ -683,6 +689,8 @@ static bool ipp_cornerHarris( InputArray _src, OutputArray _dst, int blockSize,
 
 void cv::cornerHarris( InputArray _src, OutputArray _dst, int blockSize, int ksize, double k, int borderType )
 {
+    CV_INSTRUMENT_REGION()
+
     CV_OCL_RUN(_src.dims() <= 2 && _dst.isUMat(),
                ocl_cornerMinEigenValVecs(_src, _dst, blockSize, ksize, k, borderType, HARRIS))
 
@@ -706,6 +714,8 @@ void cv::cornerHarris( InputArray _src, OutputArray _dst, int blockSize, int ksi
 
 void cv::cornerEigenValsAndVecs( InputArray _src, OutputArray _dst, int blockSize, int ksize, int borderType )
 {
+    CV_INSTRUMENT_REGION()
+
     Mat src = _src.getMat();
     Size dsz = _dst.size();
     int dtype = _dst.type();
@@ -719,6 +729,8 @@ void cv::cornerEigenValsAndVecs( InputArray _src, OutputArray _dst, int blockSiz
 
 void cv::preCornerDetect( InputArray _src, OutputArray _dst, int ksize, int borderType )
 {
+    CV_INSTRUMENT_REGION()
+
     int type = _src.type();
     CV_Assert( type == CV_8UC1 || type == CV_32FC1 );
 
diff --git a/modules/imgproc/src/cornersubpix.cpp b/modules/imgproc/src/cornersubpix.cpp
index 1909bbc..1bd30d2 100644
--- a/modules/imgproc/src/cornersubpix.cpp
+++ b/modules/imgproc/src/cornersubpix.cpp
@@ -44,6 +44,8 @@
 void cv::cornerSubPix( InputArray _image, InputOutputArray _corners,
                        Size win, Size zeroZone, TermCriteria criteria )
 {
+    CV_INSTRUMENT_REGION()
+
     const int MAX_ITERS = 100;
     int win_w = win.width * 2 + 1, win_h = win.height * 2 + 1;
     int i, j, k;
diff --git a/modules/imgproc/src/demosaicing.cpp b/modules/imgproc/src/demosaicing.cpp
index cec450d..296ace8 100644
--- a/modules/imgproc/src/demosaicing.cpp
+++ b/modules/imgproc/src/demosaicing.cpp
@@ -1615,6 +1615,8 @@ static void Bayer2RGB_EdgeAware_T(const Mat& src, Mat& dst, int code)
 
 void cv::demosaicing(InputArray _src, OutputArray _dst, int code, int dcn)
 {
+    CV_INSTRUMENT_REGION()
+
     Mat src = _src.getMat(), dst;
     Size sz = src.size();
     int scn = src.channels(), depth = src.depth();
diff --git a/modules/imgproc/src/deriv.cpp b/modules/imgproc/src/deriv.cpp
index dacc23d..01352be 100644
--- a/modules/imgproc/src/deriv.cpp
+++ b/modules/imgproc/src/deriv.cpp
@@ -43,6 +43,8 @@
 #include "precomp.hpp"
 #include "opencl_kernels_imgproc.hpp"
 
+#include "opencv2/core/openvx/ovx_defs.hpp"
+
 /****************************************************************************************\
                              Sobel & Scharr Derivative Filters
 \****************************************************************************************/
@@ -179,11 +181,131 @@ cv::Ptr<cv::FilterEngine> cv::createDerivFilter(int srcType, int dstType,
         kx, ky, Point(-1,-1), 0, borderType );
 }
 
+#ifdef HAVE_OPENVX
+namespace cv
+{
+    static bool openvx_sobel(InputArray _src, OutputArray _dst,
+                             int dx, int dy, int ksize,
+                             double scale, double delta, int borderType)
+    {
+        int stype = _src.type();
+        int dtype = _dst.type();
+        if (stype != CV_8UC1 || (dtype != CV_16SC1 && dtype != CV_8UC1) ||
+            ksize < 3 || ksize % 2 != 1 || delta != 0.0)
+            return false;
+
+        Mat src = _src.getMat();
+        Mat dst = _dst.getMat();
+
+        if (src.cols < ksize || src.rows < ksize)
+            return false;
+
+        int iscale = 1;
+        vx_uint32 cscale = 1;
+        if(scale != 1.0)
+        {
+            iscale = static_cast<int>(scale);
+            if (std::abs(scale - iscale) >= DBL_EPSILON)
+            {
+                int exp = 0;
+                float significand = frexp(scale, &exp);
+                if ((significand == 0.5f) && (exp <= 0))
+                {
+                    iscale = 1;
+                    cscale = 1 << (exp = -exp + 1);
+                }
+                else
+                    return false;
+            }
+        }
+
+        if ((borderType & BORDER_ISOLATED) == 0 && src.isSubmatrix())
+            return false; //Process isolated borders only
+        vx_enum border;
+        switch (borderType & ~BORDER_ISOLATED)
+        {
+        case BORDER_CONSTANT:
+            border = VX_BORDER_CONSTANT;
+            break;
+        case BORDER_REPLICATE:
+            border = VX_BORDER_REPLICATE;
+            break;
+        default:
+            return false;
+        }
+
+        try
+        {
+            ivx::Context ctx = ivx::Context::create();
+            if ((vx_size)ksize > ctx.convolutionMaxDimension())
+                return false;
+
+            Mat a;
+            if (dst.data != src.data)
+                a = src;
+            else
+                src.copyTo(a);
+
+            ivx::Image
+                ia = ivx::Image::createFromHandle(ctx, VX_DF_IMAGE_U8,
+                    ivx::Image::createAddressing(a.cols, a.rows, 1, (vx_int32)(a.step)), a.data),
+                ib = ivx::Image::createFromHandle(ctx, dtype == CV_16SC1 ? VX_DF_IMAGE_S16 : VX_DF_IMAGE_U8,
+                    ivx::Image::createAddressing(dst.cols, dst.rows, dtype == CV_16SC1 ? 2 : 1, (vx_int32)(dst.step)), dst.data);
+
+            //ATTENTION: VX_CONTEXT_IMMEDIATE_BORDER attribute change could lead to strange issues in multi-threaded environments
+            //since OpenVX standart says nothing about thread-safety for now
+            ivx::border_t prevBorder = ctx.immediateBorder();
+            ctx.setImmediateBorder(border, (vx_uint8)(0));
+            if (dtype == CV_16SC1 && ksize == 3 && ((dx | dy) == 1) && (dx + dy) == 1)
+            {
+                if(dx)
+                    ivx::IVX_CHECK_STATUS(vxuSobel3x3(ctx, ia, ib, NULL));
+                else
+                    ivx::IVX_CHECK_STATUS(vxuSobel3x3(ctx, ia, NULL, ib));
+            }
+            else
+            {
+#if VX_VERSION <= VX_VERSION_1_0
+                if (ctx.vendorID() == VX_ID_KHRONOS && ((vx_size)(src.cols) <= ctx.convolutionMaxDimension() || (vx_size)(src.rows) <= ctx.convolutionMaxDimension()))
+                {
+                    ctx.setImmediateBorder(prevBorder);
+                    return false;
+                }
+#endif
+                Mat kx, ky;
+                getDerivKernels(kx, ky, dx, dy, ksize, false);
+                flip(kx, kx, 0);
+                flip(ky, ky, 0);
+                Mat convData;
+                cv::Mat(ky*kx.t()).convertTo(convData, CV_16SC1, iscale);
+                ivx::Convolution cnv = ivx::Convolution::create(ctx, convData.cols, convData.rows);
+                cnv.copyFrom(convData);
+                cnv.setScale(cscale);
+                ivx::IVX_CHECK_STATUS(vxuConvolve(ctx, ia, cnv, ib));
+            }
+            ctx.setImmediateBorder(prevBorder);
+        }
+        catch (ivx::RuntimeError & e)
+        {
+            VX_DbgThrow(e.what());
+        }
+        catch (ivx::WrapperError & e)
+        {
+            VX_DbgThrow(e.what());
+        }
+
+        return true;
+    }
+}
+#endif
+
 #ifdef HAVE_IPP
 namespace cv
 {
 static bool IPPDerivScharr(InputArray _src, OutputArray _dst, int ddepth, int dx, int dy, double scale, double delta, int borderType)
 {
+    CV_INSTRUMENT_REGION_IPP()
+
 #if IPP_VERSION_X100 >= 810
     if ((0 > dx) || (0 > dy) || (1 != dx + dy))
         return false;
@@ -230,7 +352,7 @@ static bool IPPDerivScharr(InputArray _src, OutputArray _dst, int ddepth, int dx
             pBuffer = ippsMalloc_8u(bufferSize);
             if (NULL == pBuffer)
                 return false;
-            sts = ippiFilterScharrHorizMaskBorder_8u16s_C1R(src.ptr(), (int)src.step, dst.ptr<Ipp16s>(), (int)dst.step, roiSize, ippMskSize3x3, ippiBorderType, 0, pBuffer);
+            sts = CV_INSTRUMENT_FUN_IPP(ippiFilterScharrHorizMaskBorder_8u16s_C1R, src.ptr(), (int)src.step, dst.ptr<Ipp16s>(), (int)dst.step, roiSize, ippMskSize3x3, ippiBorderType, 0, pBuffer);
         }
         else
         {
@@ -239,7 +361,7 @@ static bool IPPDerivScharr(InputArray _src, OutputArray _dst, int ddepth, int dx
             pBuffer = ippsMalloc_8u(bufferSize);
             if (NULL == pBuffer)
                 return false;
-            sts = ippiFilterScharrVertMaskBorder_8u16s_C1R(src.ptr(), (int)src.step, dst.ptr<Ipp16s>(), (int)dst.step, roiSize, ippMskSize3x3, ippiBorderType, 0, pBuffer);
+            sts = CV_INSTRUMENT_FUN_IPP(ippiFilterScharrVertMaskBorder_8u16s_C1R, src.ptr(), (int)src.step, dst.ptr<Ipp16s>(), (int)dst.step, roiSize, ippMskSize3x3, ippiBorderType, 0, pBuffer);
         }
         ippsFree(pBuffer);
     }
@@ -253,7 +375,7 @@ static bool IPPDerivScharr(InputArray _src, OutputArray _dst, int ddepth, int dx
             pBuffer = ippsMalloc_8u(bufferSize);
             if (NULL == pBuffer)
                 return false;
-            sts = ippiFilterScharrHorizMaskBorder_16s_C1R(src.ptr<Ipp16s>(), (int)src.step, dst.ptr<Ipp16s>(), (int)dst.step, roiSize, ippMskSize3x3, ippiBorderType, 0, pBuffer);
+            sts = CV_INSTRUMENT_FUN_IPP(ippiFilterScharrHorizMaskBorder_16s_C1R, src.ptr<Ipp16s>(), (int)src.step, dst.ptr<Ipp16s>(), (int)dst.step, roiSize, ippMskSize3x3, ippiBorderType, 0, pBuffer);
         }
         else
         {
@@ -262,7 +384,7 @@ static bool IPPDerivScharr(InputArray _src, OutputArray _dst, int ddepth, int dx
             pBuffer = ippsMalloc_8u(bufferSize);
             if (NULL == pBuffer)
                 return false;
-            sts = ippiFilterScharrVertMaskBorder_16s_C1R(src.ptr<Ipp16s>(), (int)src.step, dst.ptr<Ipp16s>(), (int)dst.step, roiSize, ippMskSize3x3, ippiBorderType, 0, pBuffer);
+            sts = CV_INSTRUMENT_FUN_IPP(ippiFilterScharrVertMaskBorder_16s_C1R, src.ptr<Ipp16s>(), (int)src.step, dst.ptr<Ipp16s>(), (int)dst.step, roiSize, ippMskSize3x3, ippiBorderType, 0, pBuffer);
         }
         ippsFree(pBuffer);
     }
@@ -276,7 +398,7 @@ static bool IPPDerivScharr(InputArray _src, OutputArray _dst, int ddepth, int dx
             pBuffer = ippsMalloc_8u(bufferSize);
             if (NULL == pBuffer)
                 return false;
-            sts = ippiFilterScharrHorizMaskBorder_32f_C1R(src.ptr<Ipp32f>(), (int)src.step, dst.ptr<Ipp32f>(), (int)dst.step, roiSize, ippMskSize3x3, ippiBorderType, 0, pBuffer);
+            sts = CV_INSTRUMENT_FUN_IPP(ippiFilterScharrHorizMaskBorder_32f_C1R, src.ptr<Ipp32f>(), (int)src.step, dst.ptr<Ipp32f>(), (int)dst.step, roiSize, ippMskSize3x3, ippiBorderType, 0, pBuffer);
         }
         else
         {
@@ -285,14 +407,14 @@ static bool IPPDerivScharr(InputArray _src, OutputArray _dst, int ddepth, int dx
             pBuffer = ippsMalloc_8u(bufferSize);
             if (NULL == pBuffer)
                 return false;
-            sts = ippiFilterScharrVertMaskBorder_32f_C1R(src.ptr<Ipp32f>(), (int)src.step, dst.ptr<Ipp32f>(), (int)dst.step, roiSize, ippMskSize3x3, ippiBorderType, 0, pBuffer);
+            sts = CV_INSTRUMENT_FUN_IPP(ippiFilterScharrVertMaskBorder_32f_C1R, src.ptr<Ipp32f>(), (int)src.step, dst.ptr<Ipp32f>(), (int)dst.step, roiSize, ippMskSize3x3, ippiBorderType, 0, pBuffer);
         }
         ippsFree(pBuffer);
         if (sts < 0)
             return false;;
 
         if (FLT_EPSILON < fabs(scale - 1.0))
-            sts = ippiMulC_32f_C1R(dst.ptr<Ipp32f>(), (int)dst.step, (Ipp32f)scale, dst.ptr<Ipp32f>(), (int)dst.step, roiSize);
+            sts = CV_INSTRUMENT_FUN_IPP(ippiMulC_32f_C1R, dst.ptr<Ipp32f>(), (int)dst.step, (Ipp32f)scale, dst.ptr<Ipp32f>(), (int)dst.step, roiSize);
     }
     return (0 <= sts);
 #else
@@ -303,7 +425,9 @@ static bool IPPDerivScharr(InputArray _src, OutputArray _dst, int ddepth, int dx
 
 static bool IPPDerivSobel(InputArray _src, OutputArray _dst, int ddepth, int dx, int dy, int ksize, double scale, double delta, int borderType)
 {
-    if ((borderType != BORDER_REPLICATE) || ((3 != ksize) && (5 != ksize)))
+    CV_INSTRUMENT_REGION_IPP()
+
+    if (((borderType & ~BORDER_ISOLATED) != BORDER_REPLICATE) || ((3 != ksize) && (5 != ksize)))
         return false;
     if (fabs(delta) > FLT_EPSILON)
         return false;
@@ -313,6 +437,10 @@ static bool IPPDerivSobel(InputArray _src, OutputArray _dst, int ddepth, int dx,
     int bufSize = 0;
     cv::AutoBuffer<char> buffer;
     Mat src = _src.getMat(), dst = _dst.getMat();
+
+    if ((borderType & BORDER_ISOLATED) == 0 && src.isSubmatrix())
+        return false;
+
     if ( ddepth < 0 )
         ddepth = src.depth();
 
@@ -333,7 +461,7 @@ static bool IPPDerivSobel(InputArray _src, OutputArray _dst, int ddepth, int dx,
             buffer.allocate(bufSize);
 #endif
 
-            if (0 > ippiFilterSobelNegVertBorder_8u16s_C1R(src.ptr<Ipp8u>(), (int)src.step,
+            if (0 > CV_INSTRUMENT_FUN_IPP(ippiFilterSobelNegVertBorder_8u16s_C1R, src.ptr<Ipp8u>(), (int)src.step,
                                 dst.ptr<Ipp16s>(), (int)dst.step, roi, kernel,
                                 ippBorderRepl, 0, (Ipp8u*)(char*)buffer))
                 return false;
@@ -352,14 +480,13 @@ static bool IPPDerivSobel(InputArray _src, OutputArray _dst, int ddepth, int dx,
             buffer.allocate(bufSize);
 #endif
 
-            if (0 > ippiFilterSobelHorizBorder_8u16s_C1R(src.ptr<Ipp8u>(), (int)src.step,
+            if (0 > CV_INSTRUMENT_FUN_IPP(ippiFilterSobelHorizBorder_8u16s_C1R, src.ptr<Ipp8u>(), (int)src.step,
                                 dst.ptr<Ipp16s>(), (int)dst.step, roi, kernel,
                                 ippBorderRepl, 0, (Ipp8u*)(char*)buffer))
                 return false;
             return true;
         }
 
-#if !defined(HAVE_IPP_ICV_ONLY)
         if ((dx == 2) && (dy == 0))
         {
 #if IPP_VERSION_X100 >= 900
@@ -372,7 +499,7 @@ static bool IPPDerivSobel(InputArray _src, OutputArray _dst, int ddepth, int dx,
             buffer.allocate(bufSize);
 #endif
 
-            if (0 > ippiFilterSobelVertSecondBorder_8u16s_C1R(src.ptr<Ipp8u>(), (int)src.step,
+            if (0 > CV_INSTRUMENT_FUN_IPP(ippiFilterSobelVertSecondBorder_8u16s_C1R, src.ptr<Ipp8u>(), (int)src.step,
                                 dst.ptr<Ipp16s>(), (int)dst.step, roi, kernel,
                                 ippBorderRepl, 0, (Ipp8u*)(char*)buffer))
                 return false;
@@ -391,13 +518,12 @@ static bool IPPDerivSobel(InputArray _src, OutputArray _dst, int ddepth, int dx,
             buffer.allocate(bufSize);
 #endif
 
-            if (0 > ippiFilterSobelHorizSecondBorder_8u16s_C1R(src.ptr<Ipp8u>(), (int)src.step,
+            if (0 > CV_INSTRUMENT_FUN_IPP(ippiFilterSobelHorizSecondBorder_8u16s_C1R, src.ptr<Ipp8u>(), (int)src.step,
                                 dst.ptr<Ipp16s>(), (int)dst.step, roi, kernel,
                                 ippBorderRepl, 0, (Ipp8u*)(char*)buffer))
                 return false;
             return true;
         }
-#endif
     }
 
     if (src.type() == CV_32F && dst.type() == CV_32F)
@@ -445,7 +571,7 @@ static bool IPPDerivSobel(InputArray _src, OutputArray _dst, int ddepth, int dx,
             return true;
         }
 #endif
-#if !defined(HAVE_IPP_ICV_ONLY)
+
         if((dx == 2) && (dy == 0))
         {
 #if IPP_VERSION_X100 >= 900
@@ -458,12 +584,12 @@ static bool IPPDerivSobel(InputArray _src, OutputArray _dst, int ddepth, int dx,
             buffer.allocate(bufSize);
 #endif
 
-            if (0 > ippiFilterSobelVertSecondBorder_32f_C1R(src.ptr<Ipp32f>(), (int)src.step,
+            if (0 > CV_INSTRUMENT_FUN_IPP(ippiFilterSobelVertSecondBorder_32f_C1R, src.ptr<Ipp32f>(), (int)src.step,
                             dst.ptr<Ipp32f>(), (int)dst.step, roi, kernel,
                             ippBorderRepl, 0, (Ipp8u*)(char*)buffer))
                 return false;
             if(scale != 1)
-                ippiMulC_32f_C1R(dst.ptr<Ipp32f>(), (int)dst.step, (Ipp32f)scale, dst.ptr<Ipp32f>(), (int)dst.step, ippiSize(dst.cols*dst.channels(), dst.rows));
+                CV_INSTRUMENT_FUN_IPP(ippiMulC_32f_C1R, dst.ptr<Ipp32f>(), (int)dst.step, (Ipp32f)scale, dst.ptr<Ipp32f>(), (int)dst.step, ippiSize(dst.cols*dst.channels(), dst.rows));
             return true;
         }
 
@@ -479,22 +605,23 @@ static bool IPPDerivSobel(InputArray _src, OutputArray _dst, int ddepth, int dx,
             buffer.allocate(bufSize);
 #endif
 
-            if (0 > ippiFilterSobelHorizSecondBorder_32f_C1R(src.ptr<Ipp32f>(), (int)src.step,
+            if (0 > CV_INSTRUMENT_FUN_IPP(ippiFilterSobelHorizSecondBorder_32f_C1R, src.ptr<Ipp32f>(), (int)src.step,
                             dst.ptr<Ipp32f>(), (int)dst.step, roi, kernel,
                             ippBorderRepl, 0, (Ipp8u*)(char*)buffer))
                 return false;
 
             if(scale != 1)
-                ippiMulC_32f_C1R(dst.ptr<Ipp32f>(), (int)dst.step, (Ipp32f)scale, dst.ptr<Ipp32f>(), (int)dst.step, ippiSize(dst.cols*dst.channels(), dst.rows));
+                CV_INSTRUMENT_FUN_IPP(ippiMulC_32f_C1R, dst.ptr<Ipp32f>(), (int)dst.step, (Ipp32f)scale, dst.ptr<Ipp32f>(), (int)dst.step, ippiSize(dst.cols*dst.channels(), dst.rows));
             return true;
         }
-#endif
     }
     return false;
 }
 
 static bool ipp_sobel(InputArray _src, OutputArray _dst, int ddepth, int dx, int dy, int ksize, double scale, double delta, int borderType)
 {
+    CV_INSTRUMENT_REGION_IPP()
+
     if (ksize < 0)
     {
         if (IPPDerivScharr(_src, _dst, ddepth, dx, dy, scale, delta, borderType))
@@ -510,9 +637,71 @@ static bool ipp_sobel(InputArray _src, OutputArray _dst, int ddepth, int dx, int
 }
 #endif
 
+#ifdef HAVE_OPENCL
+namespace cv
+{
+static bool ocl_sepFilter3x3_8UC1(InputArray _src, OutputArray _dst, int ddepth,
+                                  InputArray _kernelX, InputArray _kernelY, double delta, int borderType)
+{
+    const ocl::Device & dev = ocl::Device::getDefault();
+    int type = _src.type(), sdepth = CV_MAT_DEPTH(type), cn = CV_MAT_CN(type);
+
+    if ( !(dev.isIntel() && (type == CV_8UC1) && (ddepth == CV_8U) &&
+         (_src.offset() == 0) && (_src.step() % 4 == 0) &&
+         (_src.cols() % 16 == 0) && (_src.rows() % 2 == 0)) )
+        return false;
+
+    Mat kernelX = _kernelX.getMat().reshape(1, 1);
+    if (kernelX.cols % 2 != 1)
+        return false;
+    Mat kernelY = _kernelY.getMat().reshape(1, 1);
+    if (kernelY.cols % 2 != 1)
+        return false;
+
+    if (ddepth < 0)
+        ddepth = sdepth;
+
+    Size size = _src.size();
+    size_t globalsize[2] = { 0, 0 };
+    size_t localsize[2] = { 0, 0 };
+
+    globalsize[0] = size.width / 16;
+    globalsize[1] = size.height / 2;
+
+    const char * const borderMap[] = { "BORDER_CONSTANT", "BORDER_REPLICATE", "BORDER_REFLECT", 0, "BORDER_REFLECT_101" };
+    char build_opts[1024];
+    sprintf(build_opts, "-D %s %s%s", borderMap[borderType],
+            ocl::kernelToStr(kernelX, CV_32F, "KERNEL_MATRIX_X").c_str(),
+            ocl::kernelToStr(kernelY, CV_32F, "KERNEL_MATRIX_Y").c_str());
+
+    ocl::Kernel kernel("sepFilter3x3_8UC1_cols16_rows2", cv::ocl::imgproc::sepFilter3x3_oclsrc, build_opts);
+    if (kernel.empty())
+        return false;
+
+    UMat src = _src.getUMat();
+    _dst.create(size, CV_MAKETYPE(ddepth, cn));
+    if (!(_dst.offset() == 0 && _dst.step() % 4 == 0))
+        return false;
+    UMat dst = _dst.getUMat();
+
+    int idxArg = kernel.set(0, ocl::KernelArg::PtrReadOnly(src));
+    idxArg = kernel.set(idxArg, (int)src.step);
+    idxArg = kernel.set(idxArg, ocl::KernelArg::PtrWriteOnly(dst));
+    idxArg = kernel.set(idxArg, (int)dst.step);
+    idxArg = kernel.set(idxArg, (int)dst.rows);
+    idxArg = kernel.set(idxArg, (int)dst.cols);
+    idxArg = kernel.set(idxArg, static_cast<float>(delta));
+
+    return kernel.run(2, globalsize, (localsize[0] == 0) ? NULL : localsize, false);
+}
+}
+#endif
+
 void cv::Sobel( InputArray _src, OutputArray _dst, int ddepth, int dx, int dy,
                 int ksize, double scale, double delta, int borderType )
 {
+    CV_INSTRUMENT_REGION()
+
     int stype = _src.type(), sdepth = CV_MAT_DEPTH(stype), cn = CV_MAT_CN(stype);
     if (ddepth < 0)
         ddepth = sdepth;
@@ -530,7 +719,10 @@ void cv::Sobel( InputArray _src, OutputArray _dst, int ddepth, int dx, int dy,
     }
 #endif
 
-    CV_IPP_RUN(true, ipp_sobel(_src, _dst, ddepth, dx, dy, ksize, scale, delta, borderType));
+    CV_OVX_RUN(true,
+               openvx_sobel(_src, _dst, dx, dy, ksize, scale, delta, borderType))
+
+    CV_IPP_RUN(!(ocl::useOpenCL() && _dst.isUMat()), ipp_sobel(_src, _dst, ddepth, dx, dy, ksize, scale, delta, borderType));
 
     int ktype = std::max(CV_32F, std::max(ddepth, sdepth));
 
@@ -545,6 +737,11 @@ void cv::Sobel( InputArray _src, OutputArray _dst, int ddepth, int dx, int dy,
         else
             ky *= scale;
     }
+
+    CV_OCL_RUN(_dst.isUMat() && _src.dims() <= 2 && ksize == 3 &&
+               (size_t)_src.rows() > ky.total() && (size_t)_src.cols() > kx.total(),
+               ocl_sepFilter3x3_8UC1(_src, _dst, ddepth, kx, ky, delta, borderType));
+
     sepFilter2D( _src, _dst, ddepth, kx, ky, Point(-1, -1), delta, borderType );
 }
 
@@ -552,6 +749,8 @@ void cv::Sobel( InputArray _src, OutputArray _dst, int ddepth, int dx, int dy,
 void cv::Scharr( InputArray _src, OutputArray _dst, int ddepth, int dx, int dy,
                  double scale, double delta, int borderType )
 {
+    CV_INSTRUMENT_REGION()
+
     int stype = _src.type(), sdepth = CV_MAT_DEPTH(stype), cn = CV_MAT_CN(stype);
     if (ddepth < 0)
         ddepth = sdepth;
@@ -567,7 +766,7 @@ void cv::Scharr( InputArray _src, OutputArray _dst, int ddepth, int dx, int dy,
     }
 #endif
 
-    CV_IPP_RUN(true, IPPDerivScharr(_src, _dst, ddepth, dx, dy, scale, delta, borderType));
+    CV_IPP_RUN(!(ocl::useOpenCL() && _dst.isUMat()), IPPDerivScharr(_src, _dst, ddepth, dx, dy, scale, delta, borderType));
 
     int ktype = std::max(CV_32F, std::max(ddepth, sdepth));
 
@@ -582,6 +781,11 @@ void cv::Scharr( InputArray _src, OutputArray _dst, int ddepth, int dx, int dy,
         else
             ky *= scale;
     }
+
+    CV_OCL_RUN(_dst.isUMat() && _src.dims() <= 2 &&
+               (size_t)_src.rows() > ky.total() && (size_t)_src.cols() > kx.total(),
+               ocl_sepFilter3x3_8UC1(_src, _dst, ddepth, kx, ky, delta, borderType));
+
     sepFilter2D( _src, _dst, ddepth, kx, ky, Point(-1, -1), delta, borderType );
 }
 
@@ -726,8 +930,57 @@ static bool ocl_Laplacian5(InputArray _src, OutputArray _dst,
     return k.run(2, globalsize, NULL, false);
 }
 
+static bool ocl_Laplacian3_8UC1(InputArray _src, OutputArray _dst, int ddepth,
+                                InputArray _kernel, double delta, int borderType)
+{
+    const ocl::Device & dev = ocl::Device::getDefault();
+    int type = _src.type(), sdepth = CV_MAT_DEPTH(type), cn = CV_MAT_CN(type);
+
+    if ( !(dev.isIntel() && (type == CV_8UC1) && (ddepth == CV_8U) &&
+         (borderType != BORDER_WRAP) &&
+         (_src.offset() == 0) && (_src.step() % 4 == 0) &&
+         (_src.cols() % 16 == 0) && (_src.rows() % 2 == 0)) )
+        return false;
+
+    Mat kernel = _kernel.getMat().reshape(1, 1);
+
+    if (ddepth < 0)
+        ddepth = sdepth;
+
+    Size size = _src.size();
+    size_t globalsize[2] = { 0, 0 };
+    size_t localsize[2] = { 0, 0 };
+
+    globalsize[0] = size.width / 16;
+    globalsize[1] = size.height / 2;
+
+    const char * const borderMap[] = { "BORDER_CONSTANT", "BORDER_REPLICATE", "BORDER_REFLECT", 0, "BORDER_REFLECT_101" };
+    char build_opts[1024];
+    sprintf(build_opts, "-D %s %s", borderMap[borderType],
+            ocl::kernelToStr(kernel, CV_32F, "KERNEL_MATRIX").c_str());
+
+    ocl::Kernel k("laplacian3_8UC1_cols16_rows2", cv::ocl::imgproc::laplacian3_oclsrc, build_opts);
+    if (k.empty())
+        return false;
+
+    UMat src = _src.getUMat();
+    _dst.create(size, CV_MAKETYPE(ddepth, cn));
+    if (!(_dst.offset() == 0 && _dst.step() % 4 == 0))
+        return false;
+    UMat dst = _dst.getUMat();
+
+    int idxArg = k.set(0, ocl::KernelArg::PtrReadOnly(src));
+    idxArg = k.set(idxArg, (int)src.step);
+    idxArg = k.set(idxArg, ocl::KernelArg::PtrWriteOnly(dst));
+    idxArg = k.set(idxArg, (int)dst.step);
+    idxArg = k.set(idxArg, (int)dst.rows);
+    idxArg = k.set(idxArg, (int)dst.cols);
+    idxArg = k.set(idxArg, static_cast<float>(delta));
+
+    return k.run(2, globalsize, (localsize[0] == 0) ? NULL : localsize, false);
 }
 
+}
 #endif
 
 #if defined(HAVE_IPP)
@@ -736,6 +989,8 @@ namespace cv
 static bool ipp_Laplacian(InputArray _src, OutputArray _dst, int ddepth, int ksize,
                     double scale, double delta, int borderType)
 {
+    CV_INSTRUMENT_REGION_IPP()
+
     int stype = _src.type(), sdepth = CV_MAT_DEPTH(stype), cn = CV_MAT_CN(stype);
     if (ddepth < 0)
         ddepth = sdepth;
@@ -761,7 +1016,7 @@ static bool ipp_Laplacian(InputArray _src, OutputArray _dst, int ddepth, int ksi
             if (borderTypeIpp >= 0 && ippiFilterLaplacianGetBufferSize_##ippfavor##_C1R(roisize, masksize, &bufsize) >= 0) \
             { \
                 Ipp8u * buffer = ippsMalloc_8u(bufsize); \
-                status = ippiFilterLaplacianBorder_##ippfavor##_C1R(src.ptr<ippsrctype>(), (int)src.step, dst.ptr<ippdsttype>(), \
+                status = CV_INSTRUMENT_FUN_IPP(ippiFilterLaplacianBorder_##ippfavor##_C1R, src.ptr<ippsrctype>(), (int)src.step, dst.ptr<ippdsttype>(), \
                                                                     (int)dst.step, roisize, masksize, borderTypeIpp, 0, buffer); \
                 ippsFree(buffer); \
             } \
@@ -773,18 +1028,18 @@ static bool ipp_Laplacian(InputArray _src, OutputArray _dst, int ddepth, int ksi
             IPP_FILTER_LAPLACIAN(Ipp8u, Ipp16s, 8u16s);
 
             if (needScale && status >= 0)
-                status = ippiMulC_16s_C1IRSfs((Ipp16s)iscale, dst.ptr<Ipp16s>(), (int)dst.step, roisize, 0);
+                status = CV_INSTRUMENT_FUN_IPP(ippiMulC_16s_C1IRSfs, (Ipp16s)iscale, dst.ptr<Ipp16s>(), (int)dst.step, roisize, 0);
             if (needDelta && status >= 0)
-                status = ippiAddC_16s_C1IRSfs((Ipp16s)idelta, dst.ptr<Ipp16s>(), (int)dst.step, roisize, 0);
+                status = CV_INSTRUMENT_FUN_IPP(ippiAddC_16s_C1IRSfs, (Ipp16s)idelta, dst.ptr<Ipp16s>(), (int)dst.step, roisize, 0);
         }
         else if (sdepth == CV_32F && ddepth == CV_32F)
         {
             IPP_FILTER_LAPLACIAN(Ipp32f, Ipp32f, 32f);
 
             if (needScale && status >= 0)
-                status = ippiMulC_32f_C1IR((Ipp32f)scale, dst.ptr<Ipp32f>(), (int)dst.step, roisize);
+                status = CV_INSTRUMENT_FUN_IPP(ippiMulC_32f_C1IR, (Ipp32f)scale, dst.ptr<Ipp32f>(), (int)dst.step, roisize);
             if (needDelta && status >= 0)
-                status = ippiAddC_32f_C1IR((Ipp32f)delta, dst.ptr<Ipp32f>(), (int)dst.step, roisize);
+                status = CV_INSTRUMENT_FUN_IPP(ippiAddC_32f_C1IR, (Ipp32f)delta, dst.ptr<Ipp32f>(), (int)dst.step, roisize);
         }
         CV_SUPPRESS_DEPRECATED_END
 
@@ -802,11 +1057,29 @@ static bool ipp_Laplacian(InputArray _src, OutputArray _dst, int ddepth, int ksi
 void cv::Laplacian( InputArray _src, OutputArray _dst, int ddepth, int ksize,
                     double scale, double delta, int borderType )
 {
+    CV_INSTRUMENT_REGION()
+
     int stype = _src.type(), sdepth = CV_MAT_DEPTH(stype), cn = CV_MAT_CN(stype);
     if (ddepth < 0)
         ddepth = sdepth;
     _dst.create( _src.size(), CV_MAKETYPE(ddepth, cn) );
 
+    if( ksize == 1 || ksize == 3 )
+    {
+        float K[2][9] =
+        {
+            { 0, 1, 0, 1, -4, 1, 0, 1, 0 },
+            { 2, 0, 2, 0, -8, 0, 2, 0, 2 }
+        };
+
+        Mat kernel(3, 3, CV_32F, K[ksize == 3]);
+        if( scale != 1 )
+            kernel *= scale;
+
+        CV_OCL_RUN(_dst.isUMat() && _src.dims() <= 2,
+                   ocl_Laplacian3_8UC1(_src, _dst, ddepth, kernel, delta, borderType));
+    }
+
     CV_IPP_RUN((ksize == 3 || ksize == 5) && ((borderType & BORDER_ISOLATED) != 0 || !_src.isSubmatrix()) &&
         ((stype == CV_8UC1 && ddepth == CV_16S) || (ddepth == CV_32F && stype == CV_32FC1)) && (!cv::ocl::useOpenCL()),
         ipp_Laplacian(_src, _dst, ddepth, ksize, scale, delta, borderType));
@@ -835,6 +1108,7 @@ void cv::Laplacian( InputArray _src, OutputArray _dst, int ddepth, int ksize,
         Mat kernel(3, 3, CV_32F, K[ksize == 3]);
         if( scale != 1 )
             kernel *= scale;
+
         filter2D( _src, _dst, ddepth, kernel, Point(-1, -1), delta, borderType );
     }
     else
@@ -849,15 +1123,21 @@ void cv::Laplacian( InputArray _src, OutputArray _dst, int ddepth, int ksize,
                    ocl_Laplacian5(_src, _dst, kd, ks, scale,
                                   delta, borderType, wdepth, ddepth))
 
+        Mat src = _src.getMat(), dst = _dst.getMat();
+        Point ofs;
+        Size wsz(src.cols, src.rows);
+        if(!(borderType&BORDER_ISOLATED))
+            src.locateROI( wsz, ofs );
+        borderType = (borderType&~BORDER_ISOLATED);
+
         const size_t STRIPE_SIZE = 1 << 14;
         Ptr<FilterEngine> fx = createSeparableLinearFilter(stype,
             wtype, kd, ks, Point(-1,-1), 0, borderType, borderType, Scalar() );
         Ptr<FilterEngine> fy = createSeparableLinearFilter(stype,
             wtype, ks, kd, Point(-1,-1), 0, borderType, borderType, Scalar() );
 
-        Mat src = _src.getMat(), dst = _dst.getMat();
-        int y = fx->start(src), dsty = 0, dy = 0;
-        fy->start(src);
+        int y = fx->start(src, wsz, ofs), dsty = 0, dy = 0;
+        fy->start(src, wsz, ofs);
         const uchar* sptr = src.ptr() + src.step[0] * y;
 
         int dy0 = std::min(std::max((int)(STRIPE_SIZE/(CV_ELEM_SIZE(stype)*src.cols)), 1), src.rows);
diff --git a/modules/imgproc/src/distransform.cpp b/modules/imgproc/src/distransform.cpp
index cde6ec4..36914d8 100644
--- a/modules/imgproc/src/distransform.cpp
+++ b/modules/imgproc/src/distransform.cpp
@@ -693,7 +693,7 @@ static void distanceTransform_L1_8U(InputArray _src, OutputArray _dst)
     {
         IppiSize roi = { src.cols, src.rows };
         Ipp32s pMetrics[2] = { 1, 2 }; //L1, 3x3 mask
-        if (ippiDistanceTransform_3x3_8u_C1R(src.ptr<uchar>(), (int)src.step, dst.ptr<uchar>(), (int)dst.step, roi, pMetrics)>=0)
+        if (CV_INSTRUMENT_FUN_IPP(ippiDistanceTransform_3x3_8u_C1R, src.ptr<uchar>(), (int)src.step, dst.ptr<uchar>(), (int)dst.step, roi, pMetrics) >= 0)
         {
             CV_IMPL_ADD(CV_IMPL_IPP);
             return;
@@ -710,6 +710,8 @@ static void distanceTransform_L1_8U(InputArray _src, OutputArray _dst)
 void cv::distanceTransform( InputArray _src, OutputArray _dst, OutputArray _labels,
                             int distType, int maskSize, int labelType )
 {
+    CV_INSTRUMENT_REGION()
+
     Mat src = _src.getMat(), labels;
     bool need_labels = _labels.needed();
 
@@ -754,7 +756,7 @@ void cv::distanceTransform( InputArray _src, OutputArray _dst, OutputArray _labe
                 if (status>=0)
                 {
                     pBuffer = (Ipp8u *)ippMalloc( bufSize );
-                    status = ippiTrueDistanceTransform_8u32f_C1R(src.ptr<uchar>(),(int)src.step, dst.ptr<float>(), (int)dst.step, roi, pBuffer);
+                    status = CV_INSTRUMENT_FUN_IPP(ippiTrueDistanceTransform_8u32f_C1R, src.ptr<uchar>(), (int)src.step, dst.ptr<float>(), (int)dst.step, roi, pBuffer);
                     ippFree( pBuffer );
                     if (status>=0)
                     {
@@ -789,7 +791,7 @@ void cv::distanceTransform( InputArray _src, OutputArray _dst, OutputArray _labe
             CV_IPP_CHECK()
             {
                 IppiSize roi = { src.cols, src.rows };
-                if (ippiDistanceTransform_3x3_8u32f_C1R(src.ptr<uchar>(), (int)src.step, dst.ptr<float>(), (int)dst.step, roi, _mask)>=0)
+                if (CV_INSTRUMENT_FUN_IPP(ippiDistanceTransform_3x3_8u32f_C1R, src.ptr<uchar>(), (int)src.step, dst.ptr<float>(), (int)dst.step, roi, _mask) >= 0)
                 {
                     CV_IMPL_ADD(CV_IMPL_IPP);
                     return;
@@ -806,7 +808,7 @@ void cv::distanceTransform( InputArray _src, OutputArray _dst, OutputArray _labe
             CV_IPP_CHECK()
             {
                 IppiSize roi = { src.cols, src.rows };
-                if (ippiDistanceTransform_5x5_8u32f_C1R(src.ptr<uchar>(), (int)src.step, dst.ptr<float>(), (int)dst.step, roi, _mask)>=0)
+                if (CV_INSTRUMENT_FUN_IPP(ippiDistanceTransform_5x5_8u32f_C1R, src.ptr<uchar>(), (int)src.step, dst.ptr<float>(), (int)dst.step, roi, _mask) >= 0)
                 {
                     CV_IMPL_ADD(CV_IMPL_IPP);
                     return;
@@ -825,7 +827,7 @@ void cv::distanceTransform( InputArray _src, OutputArray _dst, OutputArray _labe
         if( labelType == CV_DIST_LABEL_CCOMP )
         {
             Mat zpix = src == 0;
-            connectedComponents(zpix, labels, 8, CV_32S);
+            connectedComponents(zpix, labels, 8, CV_32S, CCL_WU);
         }
         else
         {
@@ -848,6 +850,8 @@ void cv::distanceTransform( InputArray _src, OutputArray _dst, OutputArray _labe
 void cv::distanceTransform( InputArray _src, OutputArray _dst,
                             int distanceType, int maskSize, int dstType)
 {
+    CV_INSTRUMENT_REGION()
+
     if (distanceType == CV_DIST_L1 && dstType==CV_8U)
         distanceTransform_L1_8U(_src, _dst);
     else
diff --git a/modules/imgproc/src/drawing.cpp b/modules/imgproc/src/drawing.cpp
index 8c052d1..113f499 100644
--- a/modules/imgproc/src/drawing.cpp
+++ b/modules/imgproc/src/drawing.cpp
@@ -53,12 +53,12 @@ struct PolyEdge
     //PolyEdge(int _y0, int _y1, int _x, int _dx) : y0(_y0), y1(_y1), x(_x), dx(_dx) {}
 
     int y0, y1;
-    int x, dx;
+    int64 x, dx;
     PolyEdge *next;
 };
 
 static void
-CollectPolyEdges( Mat& img, const Point* v, int npts,
+CollectPolyEdges( Mat& img, const Point2l* v, int npts,
                   std::vector<PolyEdge>& edges, const void* color, int line_type,
                   int shift, Point offset=Point() );
 
@@ -66,11 +66,11 @@ static void
 FillEdgeCollection( Mat& img, std::vector<PolyEdge>& edges, const void* color );
 
 static void
-PolyLine( Mat& img, const Point* v, int npts, bool closed,
+PolyLine( Mat& img, const Point2l* v, int npts, bool closed,
           const void* color, int thickness, int line_type, int shift );
 
 static void
-FillConvexPoly( Mat& img, const Point* v, int npts,
+FillConvexPoly( Mat& img, const Point2l* v, int npts,
                 const void* color, int line_type, int shift );
 
 /****************************************************************************************\
@@ -79,14 +79,27 @@ FillConvexPoly( Mat& img, const Point* v, int npts,
 
 bool clipLine( Size img_size, Point& pt1, Point& pt2 )
 {
-    int64 x1, y1, x2, y2;
+    Point2l p1(pt1);
+    Point2l p2(pt2);
+    bool inside = clipLine(Size2l(img_size.width, img_size.height), p1, p2);
+    pt1.x = (int)p1.x;
+    pt1.y = (int)p1.y;
+    pt2.x = (int)p2.x;
+    pt2.y = (int)p2.y;
+    return inside;
+}
+
+bool clipLine( Size2l img_size, Point2l& pt1, Point2l& pt2 )
+{
+    CV_INSTRUMENT_REGION()
+
     int c1, c2;
     int64 right = img_size.width-1, bottom = img_size.height-1;
 
     if( img_size.width <= 0 || img_size.height <= 0 )
         return false;
 
-    x1 = pt1.x; y1 = pt1.y; x2 = pt2.x; y2 = pt2.y;
+    int64 &x1 = pt1.x, &y1 = pt1.y, &x2 = pt2.x, &y2 = pt2.y;
     c1 = (x1 < 0) + (x1 > right) * 2 + (y1 < 0) * 4 + (y1 > bottom) * 8;
     c2 = (x2 < 0) + (x2 > right) * 2 + (y2 < 0) * 4 + (y2 > bottom) * 8;
 
@@ -126,11 +139,6 @@ bool clipLine( Size img_size, Point& pt1, Point& pt2 )
         }
 
         assert( (c1 & c2) != 0 || (x1 | y1 | x2 | y2) >= 0 );
-
-        pt1.x = (int)x1;
-        pt1.y = (int)y1;
-        pt2.x = (int)x2;
-        pt2.y = (int)y2;
     }
 
     return (c1 | c2) == 0;
@@ -138,6 +146,8 @@ bool clipLine( Size img_size, Point& pt1, Point& pt2 )
 
 bool clipLine( Rect img_rect, Point& pt1, Point& pt2 )
 {
+    CV_INSTRUMENT_REGION()
+
     Point tl = img_rect.tl();
     pt1 -= tl; pt2 -= tl;
     bool inside = clipLine(img_rect.size(), pt1, pt2);
@@ -281,25 +291,25 @@ static const int FilterTable[] = {
 };
 
 static void
-LineAA( Mat& img, Point pt1, Point pt2, const void* color )
+LineAA( Mat& img, Point2l pt1, Point2l pt2, const void* color )
 {
-    int dx, dy;
+    int64 dx, dy;
     int ecount, scount = 0;
     int slope;
-    int ax, ay;
-    int x_step, y_step;
-    int i, j;
+    int64 ax, ay;
+    int64 x_step, y_step;
+    int64 i, j;
     int ep_table[9];
     int cb = ((uchar*)color)[0], cg = ((uchar*)color)[1], cr = ((uchar*)color)[2], ca = ((uchar*)color)[3];
     int _cb, _cg, _cr, _ca;
     int nch = img.channels();
     uchar* ptr = img.ptr();
     size_t step = img.step;
-    Size size = img.size();
+    Size2l size(img.size());
 
     if( !((nch == 1 || nch == 3 || nch == 4) && img.depth() == CV_8U) )
     {
-        Line(img, pt1, pt2, color);
+        Line(img, Point((int)(pt1.x<<XY_SHIFT), (int)(pt1.y<<XY_SHIFT)), Point((int)(pt2.x<<XY_SHIFT), (int)(pt2.y<<XY_SHIFT)), color);
         return;
     }
 
@@ -335,11 +345,11 @@ LineAA( Mat& img, Point pt1, Point pt2, const void* color )
         pt1.y ^= pt2.y & j;
 
         x_step = XY_ONE;
-        y_step = (int) (((int64) dy << XY_SHIFT) / (ax | 1));
+        y_step = (dy << XY_SHIFT) / (ax | 1);
         pt2.x += XY_ONE;
-        ecount = (pt2.x >> XY_SHIFT) - (pt1.x >> XY_SHIFT);
+        ecount = (int)((pt2.x >> XY_SHIFT) - (pt1.x >> XY_SHIFT));
         j = -(pt1.x & (XY_ONE - 1));
-        pt1.y += (int) ((((int64) y_step) * j) >> XY_SHIFT) + (XY_ONE >> 1);
+        pt1.y += ((y_step * j) >> XY_SHIFT) + (XY_ONE >> 1);
         slope = (y_step >> (XY_SHIFT - 5)) & 0x3f;
         slope ^= (y_step < 0 ? 0x3f : 0);
 
@@ -358,12 +368,12 @@ LineAA( Mat& img, Point pt1, Point pt2, const void* color )
         pt2.y ^= pt1.y & i;
         pt1.y ^= pt2.y & i;
 
-        x_step = (int) (((int64) dx << XY_SHIFT) / (ay | 1));
+        x_step = (dx << XY_SHIFT) / (ay | 1);
         y_step = XY_ONE;
         pt2.y += XY_ONE;
-        ecount = (pt2.y >> XY_SHIFT) - (pt1.y >> XY_SHIFT);
+        ecount = (int)((pt2.y >> XY_SHIFT) - (pt1.y >> XY_SHIFT));
         j = -(pt1.y & (XY_ONE - 1));
-        pt1.x += (int) ((((int64) x_step) * j) >> XY_SHIFT) + (XY_ONE >> 1);
+        pt1.x += ((x_step * j) >> XY_SHIFT) + (XY_ONE >> 1);
         slope = (x_step >> (XY_SHIFT - 5)) & 0x3f;
         slope ^= (x_step < 0 ? 0x3f : 0);
 
@@ -377,8 +387,8 @@ LineAA( Mat& img, Point pt1, Point pt2, const void* color )
     /* Calc end point correction table */
     {
         int t0 = slope << 7;
-        int t1 = ((0x78 - i) | 4) * slope;
-        int t2 = (j | 4) * slope;
+        int t1 = ((0x78 - (int)i) | 4) * slope;
+        int t2 = ((int)j | 4) * slope;
 
         ep_table[0] = 0;
         ep_table[8] = slope;
@@ -632,23 +642,25 @@ LineAA( Mat& img, Point pt1, Point pt2, const void* color )
 
 
 static void
-Line2( Mat& img, Point pt1, Point pt2, const void* color )
+Line2( Mat& img, Point2l pt1, Point2l pt2, const void* color)
 {
-    int dx, dy;
+    int64 dx, dy;
     int ecount;
-    int ax, ay;
-    int i, j, x, y;
-    int x_step, y_step;
+    int64 ax, ay;
+    int64 i, j;
+    int x, y;
+    int64 x_step, y_step;
     int cb = ((uchar*)color)[0];
     int cg = ((uchar*)color)[1];
     int cr = ((uchar*)color)[2];
     int pix_size = (int)img.elemSize();
     uchar *ptr = img.ptr(), *tptr;
     size_t step = img.step;
-    Size size = img.size(), sizeScaled(size.width*XY_ONE, size.height*XY_ONE);
+    Size size = img.size();
 
     //assert( img && (nch == 1 || nch == 3) && img.depth() == CV_8U );
 
+    Size2l sizeScaled(((int64)size.width) << XY_SHIFT, ((int64)size.height) << XY_SHIFT);
     if( !clipLine( sizeScaled, pt1, pt2 ))
         return;
 
@@ -672,8 +684,8 @@ Line2( Mat& img, Point pt1, Point pt2, const void* color )
         pt1.y ^= pt2.y & j;
 
         x_step = XY_ONE;
-        y_step = (int) (((int64) dy << XY_SHIFT) / (ax | 1));
-        ecount = (pt2.x - pt1.x) >> XY_SHIFT;
+        y_step = (dy << XY_SHIFT) / (ax | 1);
+        ecount = (int)((pt2.x - pt1.x) >> XY_SHIFT);
     }
     else
     {
@@ -686,9 +698,9 @@ Line2( Mat& img, Point pt1, Point pt2, const void* color )
         pt2.y ^= pt1.y & i;
         pt1.y ^= pt2.y & i;
 
-        x_step = (int) (((int64) dx << XY_SHIFT) / (ay | 1));
+        x_step = (dx << XY_SHIFT) / (ay | 1);
         y_step = XY_ONE;
-        ecount = (pt2.y - pt1.y) >> XY_SHIFT;
+        ecount = (int)((pt2.y - pt1.y) >> XY_SHIFT);
     }
 
     pt1.x += (XY_ONE >> 1);
@@ -707,8 +719,8 @@ Line2( Mat& img, Point pt1, Point pt2, const void* color )
             tptr[2] = (uchar)cr;        \
         }
 
-        ICV_PUT_POINT((pt2.x + (XY_ONE >> 1)) >> XY_SHIFT,
-                      (pt2.y + (XY_ONE >> 1)) >> XY_SHIFT);
+        ICV_PUT_POINT((int)((pt2.x + (XY_ONE >> 1)) >> XY_SHIFT),
+                      (int)((pt2.y + (XY_ONE >> 1)) >> XY_SHIFT));
 
         if( ax > ay )
         {
@@ -716,7 +728,7 @@ Line2( Mat& img, Point pt1, Point pt2, const void* color )
 
             while( ecount >= 0 )
             {
-                ICV_PUT_POINT(pt1.x, pt1.y >> XY_SHIFT);
+                ICV_PUT_POINT((int)(pt1.x), (int)(pt1.y >> XY_SHIFT));
                 pt1.x++;
                 pt1.y += y_step;
                 ecount--;
@@ -728,7 +740,7 @@ Line2( Mat& img, Point pt1, Point pt2, const void* color )
 
             while( ecount >= 0 )
             {
-                ICV_PUT_POINT(pt1.x >> XY_SHIFT, pt1.y);
+                ICV_PUT_POINT((int)(pt1.x >> XY_SHIFT), (int)(pt1.y));
                 pt1.x += x_step;
                 pt1.y++;
                 ecount--;
@@ -748,8 +760,8 @@ Line2( Mat& img, Point pt1, Point pt2, const void* color )
             tptr[0] = (uchar)cb;    \
         }
 
-        ICV_PUT_POINT((pt2.x + (XY_ONE >> 1)) >> XY_SHIFT,
-                      (pt2.y + (XY_ONE >> 1)) >> XY_SHIFT);
+        ICV_PUT_POINT((int)((pt2.x + (XY_ONE >> 1)) >> XY_SHIFT),
+                      (int)((pt2.y + (XY_ONE >> 1)) >> XY_SHIFT));
 
         if( ax > ay )
         {
@@ -757,7 +769,7 @@ Line2( Mat& img, Point pt1, Point pt2, const void* color )
 
             while( ecount >= 0 )
             {
-                ICV_PUT_POINT(pt1.x, pt1.y >> XY_SHIFT);
+                ICV_PUT_POINT((int)(pt1.x), (int)(pt1.y >> XY_SHIFT));
                 pt1.x++;
                 pt1.y += y_step;
                 ecount--;
@@ -769,7 +781,7 @@ Line2( Mat& img, Point pt1, Point pt2, const void* color )
 
             while( ecount >= 0 )
             {
-                ICV_PUT_POINT(pt1.x >> XY_SHIFT, pt1.y);
+                ICV_PUT_POINT((int)(pt1.x >> XY_SHIFT), (int)(pt1.y));
                 pt1.x += x_step;
                 pt1.y++;
                 ecount--;
@@ -790,8 +802,8 @@ Line2( Mat& img, Point pt1, Point pt2, const void* color )
                 tptr[j] = ((uchar*)color)[j]; \
         }
 
-        ICV_PUT_POINT((pt2.x + (XY_ONE >> 1)) >> XY_SHIFT,
-                      (pt2.y + (XY_ONE >> 1)) >> XY_SHIFT);
+        ICV_PUT_POINT((int)((pt2.x + (XY_ONE >> 1)) >> XY_SHIFT),
+                      (int)((pt2.y + (XY_ONE >> 1)) >> XY_SHIFT));
 
         if( ax > ay )
         {
@@ -799,7 +811,7 @@ Line2( Mat& img, Point pt1, Point pt2, const void* color )
 
             while( ecount >= 0 )
             {
-                ICV_PUT_POINT(pt1.x, pt1.y >> XY_SHIFT);
+                ICV_PUT_POINT((int)(pt1.x), (int)(pt1.y >> XY_SHIFT));
                 pt1.x++;
                 pt1.y += y_step;
                 ecount--;
@@ -811,7 +823,7 @@ Line2( Mat& img, Point pt1, Point pt2, const void* color )
 
             while( ecount >= 0 )
             {
-                ICV_PUT_POINT(pt1.x >> XY_SHIFT, pt1.y);
+                ICV_PUT_POINT((int)(pt1.x >> XY_SHIFT), (int)(pt1.y));
                 pt1.x += x_step;
                 pt1.y++;
                 ecount--;
@@ -919,13 +931,38 @@ sincos( int angle, float& cosval, float& sinval )
    constructs polygon that represents elliptic arc.
 */
 void ellipse2Poly( Point center, Size axes, int angle,
+                   int arcStart, int arcEnd,
+                   int delta, CV_OUT std::vector<Point>& pts )
+{
+    std::vector<Point2d> _pts;
+    ellipse2Poly(Point2d(center.x, center.y), Size2d(axes.width, axes.height), angle,
+                 arcStart, arcEnd, delta, _pts);
+    Point prevPt(INT_MIN, INT_MIN);
+    pts.resize(0);
+    for (unsigned int i = 0; i < _pts.size(); ++i)
+    {
+        Point pt;
+        pt.x = cvRound(_pts[i].x);
+        pt.y = cvRound(_pts[i].y);
+        if (pt != prevPt) {
+            pts.push_back(pt);
+            prevPt = pt;
+        }
+    }
+
+    // If there are no points, it's a zero-size polygon
+    if (pts.size() == 1) {
+        pts.assign(2, center);
+    }
+}
+
+void ellipse2Poly( Point2d center, Size2d axes, int angle,
                    int arc_start, int arc_end,
-                   int delta, std::vector<Point>& pts )
+                   int delta, std::vector<Point2d>& pts )
 {
+    CV_INSTRUMENT_REGION()
+
     float alpha, beta;
-    double size_a = axes.width, size_b = axes.height;
-    double cx = center.x, cy = center.y;
-    Point prevPt(INT_MIN,INT_MIN);
     int i;
 
     while( angle < 0 )
@@ -966,15 +1003,12 @@ void ellipse2Poly( Point center, Size axes, int angle,
         if( angle < 0 )
             angle += 360;
 
-        x = size_a * SinTable[450-angle];
-        y = size_b * SinTable[angle];
-        Point pt;
-        pt.x = cvRound( cx + x * alpha - y * beta );
-        pt.y = cvRound( cy + x * beta + y * alpha );
-        if( pt != prevPt ){
-            pts.push_back(pt);
-            prevPt = pt;
-        }
+        x = axes.width * SinTable[450-angle];
+        y = axes.height * SinTable[angle];
+        Point2d pt;
+        pt.x = center.x + x * alpha - y * beta;
+        pt.y = center.y + x * beta + y * alpha;
+        pts.push_back(pt);
     }
 
     // If there are no points, it's a zero-size polygon
@@ -985,16 +1019,37 @@ void ellipse2Poly( Point center, Size axes, int angle,
 
 
 static void
-EllipseEx( Mat& img, Point center, Size axes,
+EllipseEx( Mat& img, Point2l center, Size2l axes,
            int angle, int arc_start, int arc_end,
            const void* color, int thickness, int line_type )
 {
     axes.width = std::abs(axes.width), axes.height = std::abs(axes.height);
-    int delta = (std::max(axes.width,axes.height)+(XY_ONE>>1))>>XY_SHIFT;
+    int delta = (int)((std::max(axes.width,axes.height)+(XY_ONE>>1))>>XY_SHIFT);
     delta = delta < 3 ? 90 : delta < 10 ? 30 : delta < 15 ? 18 : 5;
 
-    std::vector<Point> v;
-    ellipse2Poly( center, axes, angle, arc_start, arc_end, delta, v );
+    std::vector<Point2d> _v;
+    ellipse2Poly( Point2d((double)center.x, (double)center.y), Size2d((double)axes.width, (double)axes.height), angle, arc_start, arc_end, delta, _v );
+
+    std::vector<Point2l> v;
+    Point2l prevPt(0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF);
+    v.resize(0);
+    for (unsigned int i = 0; i < _v.size(); ++i)
+    {
+        Point2l pt;
+        pt.x = (int64)cvRound(_v[i].x / XY_ONE) << XY_SHIFT;
+        pt.y = (int64)cvRound(_v[i].y / XY_ONE) << XY_SHIFT;
+        pt.x += cvRound(_v[i].x - pt.x);
+        pt.y += cvRound(_v[i].y - pt.y);
+        if (pt != prevPt) {
+            v.push_back(pt);
+            prevPt = pt;
+        }
+    }
+
+    // If there are no points, it's a zero-size polygon
+    if (v.size() == 1) {
+        v.assign(2, center);
+    }
 
     if( thickness >= 0 )
         PolyLine( img, &v[0], (int)v.size(), false, color, thickness, line_type, XY_SHIFT );
@@ -1033,23 +1088,24 @@ EllipseEx( Mat& img, Point center, Size axes,
 
 /* filling convex polygon. v - array of vertices, ntps - number of points */
 static void
-FillConvexPoly( Mat& img, const Point* v, int npts, const void* color, int line_type, int shift )
+FillConvexPoly( Mat& img, const Point2l* v, int npts, const void* color, int line_type, int shift )
 {
     struct
     {
         int idx, di;
-        int x, dx, ye;
+        int64 x, dx;
+        int ye;
     }
     edge[2];
 
-    int delta = shift ? 1 << (shift - 1) : 0;
-    int i, y, imin = 0, left = 0, right = 1, x1, x2;
+    int delta = 1 << shift >> 1;
+    int i, y, imin = 0;
     int edges = npts;
-    int xmin, xmax, ymin, ymax;
+    int64 xmin, xmax, ymin, ymax;
     uchar* ptr = img.ptr();
     Size size = img.size();
     int pix_size = (int)img.elemSize();
-    Point p0;
+    Point2l p0;
     int delta1, delta2;
 
     if( line_type < CV_AA )
@@ -1067,7 +1123,7 @@ FillConvexPoly( Mat& img, const Point* v, int npts, const void* color, int line_
 
     for( i = 0; i < npts; i++ )
     {
-        Point p = v[i];
+        Point2l p = v[i];
         if( p.y < ymin )
         {
             ymin = p.y;
@@ -1086,10 +1142,10 @@ FillConvexPoly( Mat& img, const Point* v, int npts, const void* color, int line_
             if( shift == 0 )
             {
                 Point pt0, pt1;
-                pt0.x = p0.x >> XY_SHIFT;
-                pt0.y = p0.y >> XY_SHIFT;
-                pt1.x = p.x >> XY_SHIFT;
-                pt1.y = p.y >> XY_SHIFT;
+                pt0.x = (int)(p0.x >> XY_SHIFT);
+                pt0.y = (int)(p0.y >> XY_SHIFT);
+                pt1.x = (int)(p.x >> XY_SHIFT);
+                pt1.y = (int)(p.y >> XY_SHIFT);
                 Line( img, pt0, pt1, color, line_type );
             }
             else
@@ -1105,13 +1161,13 @@ FillConvexPoly( Mat& img, const Point* v, int npts, const void* color, int line_
     ymin = (ymin + delta) >> shift;
     ymax = (ymax + delta) >> shift;
 
-    if( npts < 3 || xmax < 0 || ymax < 0 || xmin >= size.width || ymin >= size.height )
+    if( npts < 3 || (int)xmax < 0 || (int)ymax < 0 || (int)xmin >= size.width || (int)ymin >= size.height )
         return;
 
     ymax = MIN( ymax, size.height - 1 );
     edge[0].idx = edge[1].idx = imin;
 
-    edge[0].ye = edge[1].ye = y = ymin;
+    edge[0].ye = edge[1].ye = y = (int)ymin;
     edge[0].di = 1;
     edge[1].di = npts - 1;
 
@@ -1119,55 +1175,54 @@ FillConvexPoly( Mat& img, const Point* v, int npts, const void* color, int line_
 
     do
     {
-        if( line_type < CV_AA || y < ymax || y == ymin )
+        if( line_type < CV_AA || y < (int)ymax || y == (int)ymin )
         {
             for( i = 0; i < 2; i++ )
             {
                 if( y >= edge[i].ye )
                 {
-                    int idx = edge[i].idx, di = edge[i].di;
-                    int xs = 0, xe, ye, ty = 0;
+                    int idx0 = edge[i].idx, di = edge[i].di;
+                    int idx = idx0 + di;
+                    if (idx >= npts) idx -= npts;
+                    int ty = 0;
 
-                    for(;;)
+                    for (; edges-- > 0; )
                     {
-                        ty = (v[idx].y + delta) >> shift;
-                        if( ty > y || edges == 0 )
+                        ty = (int)((v[idx].y + delta) >> shift);
+                        if (ty > y)
+                        {
+                            int64 xs = v[idx0].x;
+                            int64 xe = v[idx].x;
+                            if (shift != XY_SHIFT)
+                            {
+                                xs <<= XY_SHIFT - shift;
+                                xe <<= XY_SHIFT - shift;
+                            }
+
+                            edge[i].ye = ty;
+                            edge[i].dx = ((xe - xs)*2 + (ty - y)) / (2 * (ty - y));
+                            edge[i].x = xs;
+                            edge[i].idx = idx;
                             break;
-                        xs = v[idx].x;
+                        }
+                        idx0 = idx;
                         idx += di;
-                        idx -= ((idx < npts) - 1) & npts;   /* idx -= idx >= npts ? npts : 0 */
-                        edges--;
+                        if (idx >= npts) idx -= npts;
                     }
-
-                    ye = ty;
-                    xs <<= XY_SHIFT - shift;
-                    xe = v[idx].x << (XY_SHIFT - shift);
-
-                    /* no more edges */
-                    if( y >= ye )
-                        return;
-
-                    edge[i].ye = ye;
-                    edge[i].dx = ((xe - xs)*2 + (ye - y)) / (2 * (ye - y));
-                    edge[i].x = xs;
-                    edge[i].idx = idx;
                 }
             }
         }
 
-        if( edge[left].x > edge[right].x )
+        if (y >= 0)
         {
-            left ^= 1;
-            right ^= 1;
-        }
-
-        x1 = edge[left].x;
-        x2 = edge[right].x;
+            int left = 0, right = 1;
+            if (edge[0].x > edge[1].x)
+            {
+                left = 1, right = 0;
+            }
 
-        if( y >= 0 )
-        {
-            int xx1 = (x1 + delta1) >> XY_SHIFT;
-            int xx2 = (x2 + delta2) >> XY_SHIFT;
+            int xx1 = (int)((edge[left].x + delta1) >> XY_SHIFT);
+            int xx2 = (int)((edge[right].x + delta2) >> XY_SHIFT);
 
             if( xx2 >= 0 && xx1 < size.width )
             {
@@ -1178,26 +1233,27 @@ FillConvexPoly( Mat& img, const Point* v, int npts, const void* color, int line_
                 ICV_HLINE( ptr, xx1, xx2, color, pix_size );
             }
         }
+        else
+        {
+            // TODO optimize scan for negative y
+        }
 
-        x1 += edge[left].dx;
-        x2 += edge[right].dx;
-
-        edge[left].x = x1;
-        edge[right].x = x2;
+        edge[0].x += edge[0].dx;
+        edge[1].x += edge[1].dx;
         ptr += img.step;
     }
-    while( ++y <= ymax );
+    while( ++y <= (int)ymax );
 }
 
 
 /******** Arbitrary polygon **********/
 
 static void
-CollectPolyEdges( Mat& img, const Point* v, int count, std::vector<PolyEdge>& edges,
+CollectPolyEdges( Mat& img, const Point2l* v, int count, std::vector<PolyEdge>& edges,
                   const void* color, int line_type, int shift, Point offset )
 {
-    int i, delta = offset.y + (shift ? 1 << (shift - 1) : 0);
-    Point pt0 = v[count-1], pt1;
+    int i, delta = offset.y + ((1 << shift) >> 1);
+    Point2l pt0 = v[count-1], pt1;
     pt0.x = (pt0.x + offset.x) << (XY_SHIFT - shift);
     pt0.y = (pt0.y + delta) >> shift;
 
@@ -1205,7 +1261,7 @@ CollectPolyEdges( Mat& img, const Point* v, int count, std::vector<PolyEdge>& ed
 
     for( i = 0; i < count; i++, pt0 = pt1 )
     {
-        Point t0, t1;
+        Point2l t0, t1;
         PolyEdge edge;
 
         pt1 = v[i];
@@ -1232,14 +1288,14 @@ CollectPolyEdges( Mat& img, const Point* v, int count, std::vector<PolyEdge>& ed
 
         if( pt0.y < pt1.y )
         {
-            edge.y0 = pt0.y;
-            edge.y1 = pt1.y;
+            edge.y0 = (int)(pt0.y);
+            edge.y1 = (int)(pt1.y);
             edge.x = pt0.x;
         }
         else
         {
-            edge.y0 = pt1.y;
-            edge.y1 = pt0.y;
+            edge.y0 = (int)(pt1.y);
+            edge.y1 = (int)(pt0.y);
             edge.x = pt1.x;
         }
         edge.dx = (pt1.x - pt0.x) / (pt1.y - pt0.y);
@@ -1265,7 +1321,8 @@ FillEdgeCollection( Mat& img, std::vector<PolyEdge>& edges, const void* color )
     int i, y, total = (int)edges.size();
     Size size = img.size();
     PolyEdge* e;
-    int y_max = INT_MIN, x_max = INT_MIN, y_min = INT_MAX, x_min = INT_MAX;
+    int y_max = INT_MIN, y_min = INT_MAX;
+    int64 x_max = 0xFFFFFFFFFFFFFFFF, x_min = 0x7FFFFFFFFFFFFFFF;
     int pix_size = (int)img.elemSize();
 
     if( total < 2 )
@@ -1277,7 +1334,7 @@ FillEdgeCollection( Mat& img, std::vector<PolyEdge>& edges, const void* color )
         assert( e1.y0 < e1.y1 );
         // Determine x-coordinate of the end of the edge.
         // (This is not necessary x-coordinate of any vertex in the array.)
-        int x1 = e1.x + (e1.y1 - e1.y0) * e1.dx;
+        int64 x1 = e1.x + (e1.y1 - e1.y0) * e1.dx;
         y_min = std::min( y_min, e1.y0 );
         y_max = std::max( y_max, e1.y1 );
         x_min = std::min( x_min, e1.x );
@@ -1286,7 +1343,7 @@ FillEdgeCollection( Mat& img, std::vector<PolyEdge>& edges, const void* color )
         x_max = std::max( x_max, x1 );
     }
 
-    if( y_max < 0 || y_min >= size.height || x_max < 0 || x_min >= (size.width<<XY_SHIFT) )
+    if( y_max < 0 || y_min >= size.height || x_max < 0 || x_min >= ((int64)size.width<<XY_SHIFT) )
         return;
 
     std::sort( edges.begin(), edges.end(), CmpEdges() );
@@ -1342,19 +1399,18 @@ FillEdgeCollection( Mat& img, std::vector<PolyEdge>& edges, const void* color )
                 {
                     // convert x's from fixed-point to image coordinates
                     uchar *timg = img.ptr(y);
-                    int x1 = keep_prelast->x;
-                    int x2 = prelast->x;
+                    int x1, x2;
 
-                    if( x1 > x2 )
+                    if (keep_prelast->x > prelast->x)
                     {
-                        int t = x1;
-
-                        x1 = x2;
-                        x2 = t;
+                        x1 = (int)((prelast->x + XY_ONE - 1) >> XY_SHIFT);
+                        x2 = (int)(keep_prelast->x >> XY_SHIFT);
+                    }
+                    else
+                    {
+                        x1 = (int)((keep_prelast->x + XY_ONE - 1) >> XY_SHIFT);
+                        x2 = (int)(prelast->x >> XY_SHIFT);
                     }
-
-                    x1 = (x1 + XY_ONE - 1) >> XY_SHIFT;
-                    x2 = x2 >> XY_SHIFT;
 
                     // clip and draw the line
                     if( x1 < size.width && x2 >= 0 )
@@ -1554,7 +1610,7 @@ Circle( Mat& img, Point center, int radius, const void* color, int fill )
 
 
 static void
-ThickLine( Mat& img, Point p0, Point p1, const void* color,
+ThickLine( Mat& img, Point2l p0, Point2l p1, const void* color,
            int thickness, int line_type, int flags, int shift )
 {
     static const double INV_XY_ONE = 1./XY_ONE;
@@ -1584,7 +1640,7 @@ ThickLine( Mat& img, Point p0, Point p1, const void* color,
     }
     else
     {
-        Point pt[4], dp = Point(0,0);
+        Point2l pt[4], dp = Point2l(0,0);
         double dx = (p0.x - p1.x)*INV_XY_ONE, dy = (p1.y - p0.y)*INV_XY_ONE;
         double r = dx * dx + dy * dy;
         int i, oddThickness = thickness & 1;
@@ -1615,13 +1671,13 @@ ThickLine( Mat& img, Point p0, Point p1, const void* color,
                 if( line_type < CV_AA )
                 {
                     Point center;
-                    center.x = (p0.x + (XY_ONE>>1)) >> XY_SHIFT;
-                    center.y = (p0.y + (XY_ONE>>1)) >> XY_SHIFT;
+                    center.x = (int)((p0.x + (XY_ONE>>1)) >> XY_SHIFT);
+                    center.y = (int)((p0.y + (XY_ONE>>1)) >> XY_SHIFT);
                     Circle( img, center, (thickness + (XY_ONE>>1)) >> XY_SHIFT, color, 1 );
                 }
                 else
                 {
-                    EllipseEx( img, p0, cvSize(thickness, thickness),
+                    EllipseEx( img, p0, Size2l(thickness, thickness),
                                0, 0, 360, color, -1, line_type );
                 }
             }
@@ -1632,7 +1688,7 @@ ThickLine( Mat& img, Point p0, Point p1, const void* color,
 
 
 static void
-PolyLine( Mat& img, const Point* v, int count, bool is_closed,
+PolyLine( Mat& img, const Point2l* v, int count, bool is_closed,
           const void* color, int thickness,
           int line_type, int shift )
 {
@@ -1641,13 +1697,13 @@ PolyLine( Mat& img, const Point* v, int count, bool is_closed,
 
     int i = is_closed ? count - 1 : 0;
     int flags = 2 + !is_closed;
-    Point p0;
+    Point2l p0;
     CV_Assert( 0 <= shift && shift <= XY_SHIFT && thickness >= 0 );
 
     p0 = v[i];
     for( i = !is_closed; i < count; i++ )
     {
-        Point p = v[i];
+        Point2l p = v[i];
         ThickLine( img, p0, p, color, thickness, line_type, flags, shift );
         p0 = p;
         flags = 2;
@@ -1702,7 +1758,7 @@ void drawMarker(Mat& img, Point position, const Scalar& color, int markerType, i
     case MARKER_TRIANGLE_UP:
         line(img, Point(position.x-(markerSize/2), position.y+(markerSize/2)), Point(position.x+(markerSize/2), position.y+(markerSize/2)), color, thickness, line_type);
         line(img, Point(position.x+(markerSize/2), position.y+(markerSize/2)), Point(position.x, position.y-(markerSize/2)), color, thickness, line_type);
-        line(img, Point(position.x, position.y-(markerSize/2)), Point(position.x-(markerSize/2), position.y-(markerSize/2)), color, thickness, line_type);
+        line(img, Point(position.x, position.y-(markerSize/2)), Point(position.x-(markerSize/2), position.y+(markerSize/2)), color, thickness, line_type);
         break;
 
     // The triangle down marker case
@@ -1726,6 +1782,8 @@ void drawMarker(Mat& img, Point position, const Scalar& color, int markerType, i
 void line( InputOutputArray _img, Point pt1, Point pt2, const Scalar& color,
            int thickness, int line_type, int shift )
 {
+    CV_INSTRUMENT_REGION()
+
     Mat img = _img.getMat();
 
     if( line_type == CV_AA && img.depth() != CV_8U )
@@ -1742,6 +1800,8 @@ void line( InputOutputArray _img, Point pt1, Point pt2, const Scalar& color,
 void arrowedLine(InputOutputArray img, Point pt1, Point pt2, const Scalar& color,
            int thickness, int line_type, int shift, double tipLength)
 {
+    CV_INSTRUMENT_REGION()
+
     const double tipSize = norm(pt1-pt2)*tipLength; // Factor to normalize the size of the tip depending on the length of the arrow
 
     line(img, pt1, pt2, color, thickness, line_type, shift);
@@ -1761,6 +1821,8 @@ void rectangle( InputOutputArray _img, Point pt1, Point pt2,
                 const Scalar& color, int thickness,
                 int lineType, int shift )
 {
+    CV_INSTRUMENT_REGION()
+
     Mat img = _img.getMat();
 
     if( lineType == CV_AA && img.depth() != CV_8U )
@@ -1772,7 +1834,7 @@ void rectangle( InputOutputArray _img, Point pt1, Point pt2,
     double buf[4];
     scalarToRawData(color, buf, img.type(), 0);
 
-    Point pt[4];
+    Point2l pt[4];
 
     pt[0] = pt1;
     pt[1].x = pt2.x;
@@ -1792,6 +1854,8 @@ void rectangle( Mat& img, Rect rec,
                 const Scalar& color, int thickness,
                 int lineType, int shift )
 {
+    CV_INSTRUMENT_REGION()
+
     CV_Assert( 0 <= shift && shift <= XY_SHIFT );
     if( rec.area() > 0 )
         rectangle( img, rec.tl(), rec.br() - Point(1<<shift,1<<shift),
@@ -1802,6 +1866,8 @@ void rectangle( Mat& img, Rect rec,
 void circle( InputOutputArray _img, Point center, int radius,
              const Scalar& color, int thickness, int line_type, int shift )
 {
+    CV_INSTRUMENT_REGION()
+
     Mat img = _img.getMat();
 
     if( line_type == CV_AA && img.depth() != CV_8U )
@@ -1813,12 +1879,14 @@ void circle( InputOutputArray _img, Point center, int radius,
     double buf[4];
     scalarToRawData(color, buf, img.type(), 0);
 
-    if( thickness > 1 || line_type >= CV_AA || shift > 0 )
+    if( thickness > 1 || line_type != LINE_8 || shift > 0 )
     {
-        center.x <<= XY_SHIFT - shift;
-        center.y <<= XY_SHIFT - shift;
-        radius <<= XY_SHIFT - shift;
-        EllipseEx( img, center, Size(radius, radius),
+        Point2l _center(center);
+        int64 _radius(radius);
+        _center.x <<= XY_SHIFT - shift;
+        _center.y <<= XY_SHIFT - shift;
+        _radius <<= XY_SHIFT - shift;
+        EllipseEx( img, _center, Size2l(_radius, _radius),
                    0, 0, 360, buf, thickness, line_type );
     }
     else
@@ -1830,6 +1898,8 @@ void ellipse( InputOutputArray _img, Point center, Size axes,
               double angle, double start_angle, double end_angle,
               const Scalar& color, int thickness, int line_type, int shift )
 {
+    CV_INSTRUMENT_REGION()
+
     Mat img = _img.getMat();
 
     if( line_type == CV_AA && img.depth() != CV_8U )
@@ -1844,18 +1914,22 @@ void ellipse( InputOutputArray _img, Point center, Size axes,
     int _angle = cvRound(angle);
     int _start_angle = cvRound(start_angle);
     int _end_angle = cvRound(end_angle);
-    center.x <<= XY_SHIFT - shift;
-    center.y <<= XY_SHIFT - shift;
-    axes.width <<= XY_SHIFT - shift;
-    axes.height <<= XY_SHIFT - shift;
-
-    EllipseEx( img, center, axes, _angle, _start_angle,
+    Point2l _center(center);
+    Size2l _axes(axes);
+    _center.x <<= XY_SHIFT - shift;
+    _center.y <<= XY_SHIFT - shift;
+    _axes.width <<= XY_SHIFT - shift;
+    _axes.height <<= XY_SHIFT - shift;
+
+    EllipseEx( img, _center, _axes, _angle, _start_angle,
                _end_angle, buf, thickness, line_type );
 }
 
 void ellipse(InputOutputArray _img, const RotatedRect& box, const Scalar& color,
              int thickness, int lineType)
 {
+    CV_INSTRUMENT_REGION()
+
     Mat img = _img.getMat();
 
     if( lineType == CV_AA && img.depth() != CV_8U )
@@ -1868,16 +1942,22 @@ void ellipse(InputOutputArray _img, const RotatedRect& box, const Scalar& color,
     scalarToRawData(color, buf, img.type(), 0);
 
     int _angle = cvRound(box.angle);
-    Point center(cvRound(box.center.x*(1 << XY_SHIFT)),
-                 cvRound(box.center.y*(1 << XY_SHIFT)));
-    Size axes(cvRound(box.size.width*(1 << (XY_SHIFT - 1))),
-              cvRound(box.size.height*(1 << (XY_SHIFT - 1))));
+    Point2l center(cvRound(box.center.x),
+                 cvRound(box.center.y));
+    center.x = (center.x << XY_SHIFT) + cvRound((box.center.x - center.x)*XY_ONE);
+    center.y = (center.y << XY_SHIFT) + cvRound((box.center.y - center.y)*XY_ONE);
+    Size2l axes(cvRound(box.size.width),
+              cvRound(box.size.height));
+    axes.width  = (axes.width  << (XY_SHIFT - 1)) + cvRound((box.size.width - axes.width)*(XY_ONE>>1));
+    axes.height = (axes.height << (XY_SHIFT - 1)) + cvRound((box.size.height - axes.height)*(XY_ONE>>1));
     EllipseEx( img, center, axes, _angle, 0, 360, buf, thickness, lineType );
 }
 
 void fillConvexPoly( Mat& img, const Point* pts, int npts,
                      const Scalar& color, int line_type, int shift )
 {
+    CV_INSTRUMENT_REGION()
+
     if( !pts || npts <= 0 )
         return;
 
@@ -1887,7 +1967,8 @@ void fillConvexPoly( Mat& img, const Point* pts, int npts,
     double buf[4];
     CV_Assert( 0 <= shift && shift <=  XY_SHIFT );
     scalarToRawData(color, buf, img.type(), 0);
-    FillConvexPoly( img, pts, npts, buf, line_type, shift );
+    std::vector<Point2l> _pts(pts, pts + npts);
+    FillConvexPoly( img, _pts.data(), npts, buf, line_type, shift );
 }
 
 
@@ -1895,6 +1976,8 @@ void fillPoly( Mat& img, const Point** pts, const int* npts, int ncontours,
                const Scalar& color, int line_type,
                int shift, Point offset )
 {
+    CV_INSTRUMENT_REGION()
+
     if( line_type == CV_AA && img.depth() != CV_8U )
         line_type = 8;
 
@@ -1910,8 +1993,11 @@ void fillPoly( Mat& img, const Point** pts, const int* npts, int ncontours,
         total += npts[i];
 
     edges.reserve( total + 1 );
-    for( i = 0; i < ncontours; i++ )
-        CollectPolyEdges( img, pts[i], npts[i], edges, buf, line_type, shift, offset );
+    for (i = 0; i < ncontours; i++)
+    {
+        std::vector<Point2l> _pts(pts[i], pts[i] + npts[i]);
+        CollectPolyEdges(img, _pts.data(), npts[i], edges, buf, line_type, shift, offset);
+    }
 
     FillEdgeCollection(img, edges, buf);
 }
@@ -1920,6 +2006,8 @@ void fillPoly( Mat& img, const Point** pts, const int* npts, int ncontours,
 void polylines( Mat& img, const Point* const* pts, const int* npts, int ncontours, bool isClosed,
                 const Scalar& color, int thickness, int line_type, int shift )
 {
+    CV_INSTRUMENT_REGION()
+
     if( line_type == CV_AA && img.depth() != CV_8U )
         line_type = 8;
 
@@ -1931,7 +2019,10 @@ void polylines( Mat& img, const Point* const* pts, const int* npts, int ncontour
     scalarToRawData( color, buf, img.type(), 0 );
 
     for( int i = 0; i < ncontours; i++ )
-        PolyLine( img, pts[i], npts[i], isClosed, buf, thickness, line_type, shift );
+    {
+        std::vector<Point2l> _pts(pts[i], pts[i]+npts[i]);
+        PolyLine( img, _pts.data(), npts[i], isClosed, buf, thickness, line_type, shift );
+    }
 }
 
 
@@ -2155,6 +2246,8 @@ void putText( InputOutputArray _img, const String& text, Point org,
               int thickness, int line_type, bool bottomLeftOrigin )
 
 {
+    CV_INSTRUMENT_REGION()
+
     if ( text.empty() )
     {
         return;
@@ -2174,23 +2267,23 @@ void putText( InputOutputArray _img, const String& text, Point org,
     if( bottomLeftOrigin )
         vscale = -vscale;
 
-    int view_x = org.x << XY_SHIFT;
-    int view_y = (org.y << XY_SHIFT) + base_line*vscale;
-    std::vector<Point> pts;
+    int64 view_x = (int64)org.x << XY_SHIFT;
+    int64 view_y = ((int64)org.y << XY_SHIFT) + base_line*vscale;
+    std::vector<Point2l> pts;
     pts.reserve(1 << 10);
     const char **faces = cv::g_HersheyGlyphs;
 
     for( int i = 0; i < (int)text.size(); i++ )
     {
         int c = (uchar)text[i];
-        Point p;
+        Point2l p;
 
         readCheck(c, i, text, fontFace);
 
         const char* ptr = faces[ascii[(c-' ')+1]];
         p.x = (uchar)ptr[0] - 'R';
         p.y = (uchar)ptr[1] - 'R';
-        int dx = p.y*hscale;
+        int64 dx = p.y*hscale;
         view_x -= p.x*hscale;
         pts.resize(0);
 
@@ -2209,7 +2302,7 @@ void putText( InputOutputArray _img, const String& text, Point org,
                 p.x = (uchar)ptr[0] - 'R';
                 p.y = (uchar)ptr[1] - 'R';
                 ptr += 2;
-                pts.push_back(Point(p.x*hscale + view_x, p.y*vscale + view_y));
+                pts.push_back(Point2l(p.x*hscale + view_x, p.y*vscale + view_y));
             }
         }
         view_x += dx;
@@ -2252,6 +2345,8 @@ Size getTextSize( const String& text, int fontFace, double fontScale, int thickn
 void cv::fillConvexPoly(InputOutputArray _img, InputArray _points,
                         const Scalar& color, int lineType, int shift)
 {
+    CV_INSTRUMENT_REGION()
+
     Mat img = _img.getMat(), points = _points.getMat();
     CV_Assert(points.checkVector(2, CV_32S) >= 0);
     fillConvexPoly(img, points.ptr<Point>(), points.rows*points.cols*points.channels()/2, color, lineType, shift);
@@ -2261,6 +2356,8 @@ void cv::fillConvexPoly(InputOutputArray _img, InputArray _points,
 void cv::fillPoly(InputOutputArray _img, InputArrayOfArrays pts,
                   const Scalar& color, int lineType, int shift, Point offset)
 {
+    CV_INSTRUMENT_REGION()
+
     Mat img = _img.getMat();
     int i, ncontours = (int)pts.total();
     if( ncontours == 0 )
@@ -2285,6 +2382,8 @@ void cv::polylines(InputOutputArray _img, InputArrayOfArrays pts,
                    bool isClosed, const Scalar& color,
                    int thickness, int lineType, int shift )
 {
+    CV_INSTRUMENT_REGION()
+
     Mat img = _img.getMat();
     bool manyContours = pts.kind() == _InputArray::STD_VECTOR_VECTOR ||
                         pts.kind() == _InputArray::STD_VECTOR_MAT;
@@ -2347,6 +2446,8 @@ void cv::drawContours( InputOutputArray _image, InputArrayOfArrays _contours,
                    int lineType, InputArray _hierarchy,
                    int maxLevel, Point offset )
 {
+    CV_INSTRUMENT_REGION()
+
     Mat image = _image.getMat(), hierarchy = _hierarchy.getMat();
     CvMat _cimage = image;
 
@@ -2438,7 +2539,7 @@ cvDrawContours( void* _img, CvSeq* contour,
     CvSeq *contour0 = contour, *h_next = 0;
     CvTreeNodeIterator iterator;
     std::vector<cv::PolyEdge> edges;
-    std::vector<cv::Point> pts;
+    std::vector<cv::Point2l> pts;
     cv::Scalar externalColor = _externalColor, holeColor = _holeColor;
     cv::Mat img = cv::cvarrToMat(_img);
     cv::Point offset = _offset;
@@ -2562,7 +2663,7 @@ cvEllipse2Poly( CvPoint center, CvSize axes, int angle,
                 int arc_start, int arc_end, CvPoint* _pts, int delta )
 {
     std::vector<cv::Point> pts;
-    cv::ellipse2Poly( center, axes, angle, arc_start, arc_end, delta, pts );
+    cv::ellipse2Poly( Point(center), Size(axes), angle, arc_start, arc_end, delta, pts );
     memcpy( _pts, &pts[0], pts.size()*sizeof(_pts[0]) );
     return (int)pts.size();
 }
diff --git a/modules/imgproc/src/emd.cpp b/modules/imgproc/src/emd.cpp
index 22468da..96eda61 100644
--- a/modules/imgproc/src/emd.cpp
+++ b/modules/imgproc/src/emd.cpp
@@ -387,7 +387,7 @@ static int icvInitEMD( const float* signature1, int size1,
 
         }
         else if( weight < 0 )
-            CV_Error(CV_StsOutOfRange, "");
+            CV_Error(CV_StsBadArg, "signature1 must not contain negative weights");
     }
 
     for( i = 0; i < size2; i++ )
@@ -401,11 +401,13 @@ static int icvInitEMD( const float* signature1, int size1,
             state->idx2[dsize++] = i;
         }
         else if( weight < 0 )
-            CV_Error(CV_StsOutOfRange, "");
+            CV_Error(CV_StsBadArg, "signature2 must not contain negative weights");
     }
 
-    if( ssize == 0 || dsize == 0 )
-        CV_Error(CV_StsOutOfRange, "");
+    if( ssize == 0 )
+        CV_Error(CV_StsBadArg, "signature1 must contain at least one non-zero value");
+    if( dsize == 0 )
+        CV_Error(CV_StsBadArg, "signature2 must contain at least one non-zero value");
 
     /* if supply different than the demand, add a zero-cost dummy cluster */
     diff = s_sum - d_sum;
@@ -1142,6 +1144,8 @@ float cv::EMD( InputArray _signature1, InputArray _signature2,
                int distType, InputArray _cost,
                float* lowerBound, OutputArray _flow )
 {
+    CV_INSTRUMENT_REGION()
+
     Mat signature1 = _signature1.getMat(), signature2 = _signature2.getMat();
     Mat cost = _cost.getMat(), flow;
 
diff --git a/modules/imgproc/src/featureselect.cpp b/modules/imgproc/src/featureselect.cpp
index 2921d3c..fc1b034 100644
--- a/modules/imgproc/src/featureselect.cpp
+++ b/modules/imgproc/src/featureselect.cpp
@@ -42,6 +42,8 @@
 #include "precomp.hpp"
 #include "opencl_kernels_imgproc.hpp"
 
+#include "opencv2/core/openvx/ovx_defs.hpp"
+
 #include <cstdio>
 #include <vector>
 #include <iostream>
@@ -54,7 +56,8 @@ struct greaterThanPtr :
         public std::binary_function<const float *, const float *, bool>
 {
     bool operator () (const float * a, const float * b) const
-    { return *a > *b; }
+    // Ensure a fully deterministic result of the sort
+    { return (*a > *b) ? true : (*a < *b) ? false : (a > b); }
 };
 
 #ifdef HAVE_OPENCL
@@ -66,7 +69,8 @@ struct Corner
     short x;
 
     bool operator < (const Corner & c) const
-    {  return val > c.val; }
+    // Ensure a fully deterministic result of the sort
+    {  return (val > c.val) ? true : (val < c.val) ? false : (y > c.y) ? true : (y < c.y) ? false : (x > c.x); }
 };
 
 static bool ocl_goodFeaturesToTrack( InputArray _image, OutputArray _corners,
@@ -260,6 +264,95 @@ static bool ocl_goodFeaturesToTrack( InputArray _image, OutputArray _corners,
 
 #endif
 
+#ifdef HAVE_OPENVX
+struct VxKeypointsComparator
+{
+    bool operator () (const vx_keypoint_t& a, const vx_keypoint_t& b)
+    {
+        return a.strength > b.strength;
+    }
+};
+
+static bool openvx_harris(Mat image, OutputArray _corners,
+                          int _maxCorners, double _qualityLevel, double _minDistance,
+                          int _blockSize, double _harrisK)
+{
+    using namespace ivx;
+
+    if(image.type() != CV_8UC1) return false;
+
+    //OpenVX implementations don't have to provide other sizes
+    if(!(_blockSize == 3 || _blockSize == 5 || _blockSize == 7)) return false;
+
+    try
+    {
+        Context context = Context::create();
+
+        Image ovxImage = Image::createFromHandle(context, Image::matTypeToFormat(image.type()),
+                                                 Image::createAddressing(image), image.data);
+        //The minimum threshold which to eliminate Harris Corner scores (computed using the normalized Sobel kernel).
+        //set to 0, we'll filter it later by threshold
+        ivx::Scalar strengthThresh = ivx::Scalar::create<VX_TYPE_FLOAT32>(context, 0);
+
+        //The gradient window size to use on the input.
+        vx_int32 gradientSize = 3;
+
+        //The block window size used to compute the harris corner score
+        vx_int32 blockSize = _blockSize;
+
+        //The scalar sensitivity threshold k from the Harris-Stephens equation
+        ivx::Scalar sensivity = ivx::Scalar::create<VX_TYPE_FLOAT32>(context, _harrisK);
+
+        //The radial Euclidean distance for non-maximum suppression
+        ivx::Scalar minDistance = ivx::Scalar::create<VX_TYPE_FLOAT32>(context, _minDistance);
+
+        vx_size capacity = image.cols * image.rows;
+        Array corners = Array::create(context, VX_TYPE_KEYPOINT, capacity);
+        ivx::Scalar numCorners = ivx::Scalar::create<VX_TYPE_SIZE>(context, 0);
+
+        IVX_CHECK_STATUS(vxuHarrisCorners(context, ovxImage, strengthThresh, minDistance, sensivity,
+                                          gradientSize, blockSize, corners, numCorners));
+
+        std::vector<vx_keypoint_t> vxKeypoints;
+        corners.copyTo(vxKeypoints);
+
+        std::sort(vxKeypoints.begin(), vxKeypoints.end(), VxKeypointsComparator());
+
+        vx_float32 maxStrength = 0.0f;
+        if(vxKeypoints.size() > 0)
+            maxStrength = vxKeypoints[0].strength;
+        size_t maxKeypoints = min((size_t)_maxCorners, vxKeypoints.size());
+        std::vector<Point2f> keypoints;
+        keypoints.reserve(maxKeypoints);
+        for(size_t i = 0; i < maxKeypoints; i++)
+        {
+            vx_keypoint_t kp = vxKeypoints[i];
+            if(kp.strength < maxStrength*_qualityLevel) break;
+            keypoints.push_back(Point2f((float)kp.x, (float)kp.y));
+        }
+
+        Mat(keypoints).convertTo(_corners, _corners.fixedType() ? _corners.type() : CV_32F);
+
+#ifdef VX_VERSION_1_1
+        //we should take user memory back before release
+        //(it's not done automatically according to standard)
+        ovxImage.swapHandle();
+#endif
+    }
+    catch (RuntimeError & e)
+    {
+        VX_DbgThrow(e.what());
+    }
+    catch (WrapperError & e)
+    {
+        VX_DbgThrow(e.what());
+    }
+
+    return true;
+}
+
+#endif
+
 }
 
 void cv::goodFeaturesToTrack( InputArray _image, OutputArray _corners,
@@ -267,6 +360,8 @@ void cv::goodFeaturesToTrack( InputArray _image, OutputArray _corners,
                               InputArray _mask, int blockSize,
                               bool useHarrisDetector, double harrisK )
 {
+    CV_INSTRUMENT_REGION()
+
     CV_Assert( qualityLevel > 0 && minDistance >= 0 && maxCorners >= 0 );
     CV_Assert( _mask.empty() || (_mask.type() == CV_8UC1 && _mask.sameSize(_image)) );
 
@@ -281,6 +376,10 @@ void cv::goodFeaturesToTrack( InputArray _image, OutputArray _corners,
         return;
     }
 
+    // Disabled due to bad accuracy
+    CV_OVX_RUN(false && useHarrisDetector && _mask.empty(),
+               openvx_harris(image, _corners, maxCorners, qualityLevel, minDistance, blockSize, harrisK))
+
     if( useHarrisDetector )
         cornerHarris( image, eig, blockSize, 3, harrisK );
     else
diff --git a/modules/imgproc/src/filter.cpp b/modules/imgproc/src/filter.cpp
index f70389b..e379df2 100644
--- a/modules/imgproc/src/filter.cpp
+++ b/modules/imgproc/src/filter.cpp
@@ -41,7 +41,9 @@
 //M*/
 
 #include "precomp.hpp"
+#include "opencv2/core/opencl/ocl_defs.hpp"
 #include "opencl_kernels_imgproc.hpp"
+#include "hal_replacement.hpp"
 
 /****************************************************************************************\
                                     Base Image Filter
@@ -158,12 +160,12 @@ void FilterEngine::init( const Ptr<BaseFilter>& _filter2D,
 
 #define VEC_ALIGN CV_MALLOC_ALIGN
 
-int FilterEngine::start(Size _wholeSize, Rect _roi, int _maxBufRows)
+int FilterEngine::start(const Size &_wholeSize, const Size &sz, const Point &ofs)
 {
     int i, j;
 
     wholeSize = _wholeSize;
-    roi = _roi;
+    roi = Rect(ofs, sz);
     CV_Assert( roi.x >= 0 && roi.y >= 0 && roi.width >= 0 && roi.height >= 0 &&
         roi.x + roi.width <= wholeSize.width &&
         roi.y + roi.height <= wholeSize.height );
@@ -172,9 +174,9 @@ int FilterEngine::start(Size _wholeSize, Rect _roi, int _maxBufRows)
     int bufElemSize = (int)getElemSize(bufType);
     const uchar* constVal = !constBorderValue.empty() ? &constBorderValue[0] : 0;
 
-    if( _maxBufRows < 0 )
-        _maxBufRows = ksize.height + 3;
-    _maxBufRows = std::max(_maxBufRows, std::max(anchor.y, ksize.height-anchor.y-1)*2+1);
+    int _maxBufRows = std::max(ksize.height + 3,
+                               std::max(anchor.y,
+                                        ksize.height-anchor.y-1)*2+1);
 
     if( maxWidth < roi.width || _maxBufRows != (int)rows.size() )
     {
@@ -260,29 +262,12 @@ int FilterEngine::start(Size _wholeSize, Rect _roi, int _maxBufRows)
 }
 
 
-int FilterEngine::start(const Mat& src, const Rect& _srcRoi,
-                        bool isolated, int maxBufRows)
+int FilterEngine::start(const Mat& src, const Size &wsz, const Point &ofs)
 {
-    Rect srcRoi = _srcRoi;
-
-    if( srcRoi == Rect(0,0,-1,-1) )
-        srcRoi = Rect(0,0,src.cols,src.rows);
-
-    CV_Assert( srcRoi.x >= 0 && srcRoi.y >= 0 &&
-        srcRoi.width >= 0 && srcRoi.height >= 0 &&
-        srcRoi.x + srcRoi.width <= src.cols &&
-        srcRoi.y + srcRoi.height <= src.rows );
-
-    Point ofs;
-    Size wsz(src.cols, src.rows);
-    if( !isolated )
-        src.locateROI( wsz, ofs );
-    start( wsz, srcRoi + ofs, maxBufRows );
-
+    start( wsz, src.size(), ofs);
     return startY - ofs.y;
 }
 
-
 int FilterEngine::remainingInputRows() const
 {
     return endY - startY - rowCount;
@@ -392,28 +377,18 @@ int FilterEngine::proceed( const uchar* src, int srcstep, int count,
     return dy;
 }
 
-
-void FilterEngine::apply(const Mat& src, Mat& dst,
-    const Rect& _srcRoi, Point dstOfs, bool isolated)
+void FilterEngine::apply(const Mat& src, Mat& dst, const Size & wsz, const Point & ofs)
 {
-    CV_Assert( src.type() == srcType && dst.type() == dstType );
-
-    Rect srcRoi = _srcRoi;
-    if( srcRoi == Rect(0,0,-1,-1) )
-        srcRoi = Rect(0,0,src.cols,src.rows);
-
-    if( srcRoi.area() == 0 )
-        return;
+    CV_INSTRUMENT_REGION()
 
-    CV_Assert( dstOfs.x >= 0 && dstOfs.y >= 0 &&
-        dstOfs.x + srcRoi.width <= dst.cols &&
-        dstOfs.y + srcRoi.height <= dst.rows );
+    CV_Assert( src.type() == srcType && dst.type() == dstType );
 
-    int y = start(src, srcRoi, isolated);
-    proceed( src.ptr() + y*src.step + srcRoi.x*src.elemSize(),
-             (int)src.step, endY - startY,
-             dst.ptr(dstOfs.y) +
-             dstOfs.x*dst.elemSize(), (int)dst.step );
+    int y = start(src, wsz, ofs);
+    proceed(src.ptr() + y*src.step,
+            (int)src.step,
+            endY - startY,
+            dst.ptr(),
+            (int)dst.step );
 }
 
 }
@@ -533,56 +508,52 @@ struct RowVec_8u32s
 
         if( smallValues )
         {
-            for( ; i <= width - 16; i += 16 )
+            __m128i z = _mm_setzero_si128();
+            for( ; i <= width - 8; i += 8 )
             {
                 const uchar* src = _src + i;
-                __m128i f, z = _mm_setzero_si128(), s0 = z, s1 = z, s2 = z, s3 = z;
-                __m128i x0, x1, x2, x3;
+                __m128i s0 = z, s1 = z;
 
                 for( k = 0; k < _ksize; k++, src += cn )
                 {
-                    f = _mm_cvtsi32_si128(_kx[k]);
+                    __m128i f = _mm_cvtsi32_si128(_kx[k]);
                     f = _mm_shuffle_epi32(f, 0);
-                    f = _mm_packs_epi32(f, f);
 
-                    x0 = _mm_loadu_si128((const __m128i*)src);
-                    x2 = _mm_unpackhi_epi8(x0, z);
+                    __m128i x0 = _mm_loadl_epi64((const __m128i*)src);
                     x0 = _mm_unpacklo_epi8(x0, z);
-                    x1 = _mm_mulhi_epi16(x0, f);
-                    x3 = _mm_mulhi_epi16(x2, f);
-                    x0 = _mm_mullo_epi16(x0, f);
-                    x2 = _mm_mullo_epi16(x2, f);
-
-                    s0 = _mm_add_epi32(s0, _mm_unpacklo_epi16(x0, x1));
-                    s1 = _mm_add_epi32(s1, _mm_unpackhi_epi16(x0, x1));
-                    s2 = _mm_add_epi32(s2, _mm_unpacklo_epi16(x2, x3));
-                    s3 = _mm_add_epi32(s3, _mm_unpackhi_epi16(x2, x3));
+
+                    __m128i x1 = _mm_unpackhi_epi16(x0, z);
+                    x0 = _mm_unpacklo_epi16(x0, z);
+
+                    x0 = _mm_madd_epi16(x0, f);
+                    x1 = _mm_madd_epi16(x1, f);
+
+                    s0 = _mm_add_epi32(s0, x0);
+                    s1 = _mm_add_epi32(s1, x1);
                 }
 
                 _mm_store_si128((__m128i*)(dst + i), s0);
                 _mm_store_si128((__m128i*)(dst + i + 4), s1);
-                _mm_store_si128((__m128i*)(dst + i + 8), s2);
-                _mm_store_si128((__m128i*)(dst + i + 12), s3);
             }
 
-            for( ; i <= width - 4; i += 4 )
+            if( i <= width - 4 )
             {
                 const uchar* src = _src + i;
-                __m128i f, z = _mm_setzero_si128(), s0 = z, x0, x1;
+                __m128i s0 = z;
 
                 for( k = 0; k < _ksize; k++, src += cn )
                 {
-                    f = _mm_cvtsi32_si128(_kx[k]);
+                    __m128i f = _mm_cvtsi32_si128(_kx[k]);
                     f = _mm_shuffle_epi32(f, 0);
-                    f = _mm_packs_epi32(f, f);
 
-                    x0 = _mm_cvtsi32_si128(*(const int*)src);
+                    __m128i x0 = _mm_cvtsi32_si128(*(const int*)src);
                     x0 = _mm_unpacklo_epi8(x0, z);
-                    x1 = _mm_mulhi_epi16(x0, f);
-                    x0 = _mm_mullo_epi16(x0, f);
-                    s0 = _mm_add_epi32(s0, _mm_unpacklo_epi16(x0, x1));
+                    x0 = _mm_unpacklo_epi16(x0, z);
+                    x0 = _mm_madd_epi16(x0, f);
+                    s0 = _mm_add_epi32(s0, x0);
                 }
                 _mm_store_si128((__m128i*)(dst + i), s0);
+                i += 4;
             }
         }
         return i;
@@ -679,41 +650,30 @@ struct SymmRowSmallVec_8u32s
                 {
                     __m128i k0 = _mm_shuffle_epi32(_mm_cvtsi32_si128(kx[0]), 0),
                             k1 = _mm_shuffle_epi32(_mm_cvtsi32_si128(kx[1]), 0);
-                    k0 = _mm_packs_epi32(k0, k0);
                     k1 = _mm_packs_epi32(k1, k1);
 
-                    for( ; i <= width - 16; i += 16, src += 16 )
+                    for( ; i <= width - 8; i += 8, src += 8 )
                     {
-                        __m128i x0, x1, x2, y0, y1, t0, t1, z0, z1, z2, z3;
-                        x0 = _mm_loadu_si128((__m128i*)(src - cn));
-                        x1 = _mm_loadu_si128((__m128i*)src);
-                        x2 = _mm_loadu_si128((__m128i*)(src + cn));
-                        y0 = _mm_add_epi16(_mm_unpackhi_epi8(x0, z), _mm_unpackhi_epi8(x2, z));
-                        x0 = _mm_add_epi16(_mm_unpacklo_epi8(x0, z), _mm_unpacklo_epi8(x2, z));
-                        y1 = _mm_unpackhi_epi8(x1, z);
-                        x1 = _mm_unpacklo_epi8(x1, z);
+                        __m128i x0 = _mm_loadl_epi64((__m128i*)(src - cn));
+                        __m128i x1 = _mm_loadl_epi64((__m128i*)src);
+                        __m128i x2 = _mm_loadl_epi64((__m128i*)(src + cn));
 
-                        t1 = _mm_mulhi_epi16(x1, k0);
-                        t0 = _mm_mullo_epi16(x1, k0);
-                        x2 = _mm_mulhi_epi16(x0, k1);
-                        x0 = _mm_mullo_epi16(x0, k1);
-                        z0 = _mm_unpacklo_epi16(t0, t1);
-                        z1 = _mm_unpackhi_epi16(t0, t1);
-                        z0 = _mm_add_epi32(z0, _mm_unpacklo_epi16(x0, x2));
-                        z1 = _mm_add_epi32(z1, _mm_unpackhi_epi16(x0, x2));
-
-                        t1 = _mm_mulhi_epi16(y1, k0);
-                        t0 = _mm_mullo_epi16(y1, k0);
-                        y1 = _mm_mulhi_epi16(y0, k1);
-                        y0 = _mm_mullo_epi16(y0, k1);
-                        z2 = _mm_unpacklo_epi16(t0, t1);
-                        z3 = _mm_unpackhi_epi16(t0, t1);
-                        z2 = _mm_add_epi32(z2, _mm_unpacklo_epi16(y0, y1));
-                        z3 = _mm_add_epi32(z3, _mm_unpackhi_epi16(y0, y1));
-                        _mm_store_si128((__m128i*)(dst + i), z0);
-                        _mm_store_si128((__m128i*)(dst + i + 4), z1);
-                        _mm_store_si128((__m128i*)(dst + i + 8), z2);
-                        _mm_store_si128((__m128i*)(dst + i + 12), z3);
+                        x0 = _mm_unpacklo_epi8(x0, z);
+                        x1 = _mm_unpacklo_epi8(x1, z);
+                        x2 = _mm_unpacklo_epi8(x2, z);
+                        __m128i x3 = _mm_unpacklo_epi16(x0, x2);
+                        __m128i x4 = _mm_unpackhi_epi16(x0, x2);
+                        __m128i x5 = _mm_unpacklo_epi16(x1, z);
+                        __m128i x6 = _mm_unpackhi_epi16(x1, z);
+                        x3 = _mm_madd_epi16(x3, k1);
+                        x4 = _mm_madd_epi16(x4, k1);
+                        x5 = _mm_madd_epi16(x5, k0);
+                        x6 = _mm_madd_epi16(x6, k0);
+                        x3 = _mm_add_epi32(x3, x5);
+                        x4 = _mm_add_epi32(x4, x6);
+
+                        _mm_store_si128((__m128i*)(dst + i), x3);
+                        _mm_store_si128((__m128i*)(dst + i + 4), x4);
                     }
                 }
             }
@@ -744,57 +704,45 @@ struct SymmRowSmallVec_8u32s
                     __m128i k0 = _mm_shuffle_epi32(_mm_cvtsi32_si128(kx[0]), 0),
                             k1 = _mm_shuffle_epi32(_mm_cvtsi32_si128(kx[1]), 0),
                             k2 = _mm_shuffle_epi32(_mm_cvtsi32_si128(kx[2]), 0);
-                    k0 = _mm_packs_epi32(k0, k0);
                     k1 = _mm_packs_epi32(k1, k1);
                     k2 = _mm_packs_epi32(k2, k2);
 
-                    for( ; i <= width - 16; i += 16, src += 16 )
+                    for( ; i <= width - 8; i += 8, src += 8 )
                     {
-                        __m128i x0, x1, x2, y0, y1, t0, t1, z0, z1, z2, z3;
-                        x0 = _mm_loadu_si128((__m128i*)(src - cn));
-                        x1 = _mm_loadu_si128((__m128i*)src);
-                        x2 = _mm_loadu_si128((__m128i*)(src + cn));
-                        y0 = _mm_add_epi16(_mm_unpackhi_epi8(x0, z), _mm_unpackhi_epi8(x2, z));
-                        x0 = _mm_add_epi16(_mm_unpacklo_epi8(x0, z), _mm_unpacklo_epi8(x2, z));
-                        y1 = _mm_unpackhi_epi8(x1, z);
-                        x1 = _mm_unpacklo_epi8(x1, z);
-
-                        t1 = _mm_mulhi_epi16(x1, k0);
-                        t0 = _mm_mullo_epi16(x1, k0);
-                        x2 = _mm_mulhi_epi16(x0, k1);
-                        x0 = _mm_mullo_epi16(x0, k1);
-                        z0 = _mm_unpacklo_epi16(t0, t1);
-                        z1 = _mm_unpackhi_epi16(t0, t1);
-                        z0 = _mm_add_epi32(z0, _mm_unpacklo_epi16(x0, x2));
-                        z1 = _mm_add_epi32(z1, _mm_unpackhi_epi16(x0, x2));
-
-                        t1 = _mm_mulhi_epi16(y1, k0);
-                        t0 = _mm_mullo_epi16(y1, k0);
-                        y1 = _mm_mulhi_epi16(y0, k1);
-                        y0 = _mm_mullo_epi16(y0, k1);
-                        z2 = _mm_unpacklo_epi16(t0, t1);
-                        z3 = _mm_unpackhi_epi16(t0, t1);
-                        z2 = _mm_add_epi32(z2, _mm_unpacklo_epi16(y0, y1));
-                        z3 = _mm_add_epi32(z3, _mm_unpackhi_epi16(y0, y1));
+                        __m128i x0 = _mm_loadl_epi64((__m128i*)src);
 
-                        x0 = _mm_loadu_si128((__m128i*)(src - cn*2));
-                        x1 = _mm_loadu_si128((__m128i*)(src + cn*2));
-                        y1 = _mm_add_epi16(_mm_unpackhi_epi8(x0, z), _mm_unpackhi_epi8(x1, z));
-                        y0 = _mm_add_epi16(_mm_unpacklo_epi8(x0, z), _mm_unpacklo_epi8(x1, z));
-
-                        t1 = _mm_mulhi_epi16(y0, k2);
-                        t0 = _mm_mullo_epi16(y0, k2);
-                        y0 = _mm_mullo_epi16(y1, k2);
-                        y1 = _mm_mulhi_epi16(y1, k2);
-                        z0 = _mm_add_epi32(z0, _mm_unpacklo_epi16(t0, t1));
-                        z1 = _mm_add_epi32(z1, _mm_unpackhi_epi16(t0, t1));
-                        z2 = _mm_add_epi32(z2, _mm_unpacklo_epi16(y0, y1));
-                        z3 = _mm_add_epi32(z3, _mm_unpackhi_epi16(y0, y1));
-
-                        _mm_store_si128((__m128i*)(dst + i), z0);
-                        _mm_store_si128((__m128i*)(dst + i + 4), z1);
-                        _mm_store_si128((__m128i*)(dst + i + 8), z2);
-                        _mm_store_si128((__m128i*)(dst + i + 12), z3);
+                        x0 = _mm_unpacklo_epi8(x0, z);
+                        __m128i x1 = _mm_unpacklo_epi16(x0, z);
+                        __m128i x2 = _mm_unpackhi_epi16(x0, z);
+                        x1 = _mm_madd_epi16(x1, k0);
+                        x2 = _mm_madd_epi16(x2, k0);
+
+                        __m128i x3 = _mm_loadl_epi64((__m128i*)(src - cn));
+                        __m128i x4 = _mm_loadl_epi64((__m128i*)(src + cn));
+
+                        x3 = _mm_unpacklo_epi8(x3, z);
+                        x4 = _mm_unpacklo_epi8(x4, z);
+                        __m128i x5 = _mm_unpacklo_epi16(x3, x4);
+                        __m128i x6 = _mm_unpackhi_epi16(x3, x4);
+                        x5 = _mm_madd_epi16(x5, k1);
+                        x6 = _mm_madd_epi16(x6, k1);
+                        x1 = _mm_add_epi32(x1, x5);
+                        x2 = _mm_add_epi32(x2, x6);
+
+                        x3 = _mm_loadl_epi64((__m128i*)(src - cn*2));
+                        x4 = _mm_loadl_epi64((__m128i*)(src + cn*2));
+
+                        x3 = _mm_unpacklo_epi8(x3, z);
+                        x4 = _mm_unpacklo_epi8(x4, z);
+                        x5 = _mm_unpacklo_epi16(x3, x4);
+                        x6 = _mm_unpackhi_epi16(x3, x4);
+                        x5 = _mm_madd_epi16(x5, k2);
+                        x6 = _mm_madd_epi16(x6, k2);
+                        x1 = _mm_add_epi32(x1, x5);
+                        x2 = _mm_add_epi32(x2, x6);
+
+                        _mm_store_si128((__m128i*)(dst + i), x1);
+                        _mm_store_si128((__m128i*)(dst + i + 4), x2);
                     }
                 }
             }
@@ -818,77 +766,75 @@ struct SymmRowSmallVec_8u32s
                     }
                 else
                 {
-                    __m128i k1 = _mm_shuffle_epi32(_mm_cvtsi32_si128(kx[1]), 0);
-                    k1 = _mm_packs_epi32(k1, k1);
+                    __m128i k0 = _mm_set_epi32(-kx[1], kx[1], -kx[1], kx[1]);
+                    k0 = _mm_packs_epi32(k0, k0);
 
                     for( ; i <= width - 16; i += 16, src += 16 )
                     {
-                        __m128i x0, x1, y0, y1, z0, z1, z2, z3;
-                        x0 = _mm_loadu_si128((__m128i*)(src + cn));
-                        x1 = _mm_loadu_si128((__m128i*)(src - cn));
-                        y0 = _mm_sub_epi16(_mm_unpackhi_epi8(x0, z), _mm_unpackhi_epi8(x1, z));
-                        x0 = _mm_sub_epi16(_mm_unpacklo_epi8(x0, z), _mm_unpacklo_epi8(x1, z));
-
-                        x1 = _mm_mulhi_epi16(x0, k1);
-                        x0 = _mm_mullo_epi16(x0, k1);
-                        z0 = _mm_unpacklo_epi16(x0, x1);
-                        z1 = _mm_unpackhi_epi16(x0, x1);
-
-                        y1 = _mm_mulhi_epi16(y0, k1);
-                        y0 = _mm_mullo_epi16(y0, k1);
-                        z2 = _mm_unpacklo_epi16(y0, y1);
-                        z3 = _mm_unpackhi_epi16(y0, y1);
-                        _mm_store_si128((__m128i*)(dst + i), z0);
-                        _mm_store_si128((__m128i*)(dst + i + 4), z1);
-                        _mm_store_si128((__m128i*)(dst + i + 8), z2);
-                        _mm_store_si128((__m128i*)(dst + i + 12), z3);
+                        __m128i x0 = _mm_loadu_si128((__m128i*)(src + cn));
+                        __m128i x1 = _mm_loadu_si128((__m128i*)(src - cn));
+
+                        __m128i x2 = _mm_unpacklo_epi8(x0, z);
+                        __m128i x3 = _mm_unpacklo_epi8(x1, z);
+                        __m128i x4 = _mm_unpackhi_epi8(x0, z);
+                        __m128i x5 = _mm_unpackhi_epi8(x1, z);
+                        __m128i x6 = _mm_unpacklo_epi16(x2, x3);
+                        __m128i x7 = _mm_unpacklo_epi16(x4, x5);
+                        __m128i x8 = _mm_unpackhi_epi16(x2, x3);
+                        __m128i x9 = _mm_unpackhi_epi16(x4, x5);
+                        x6 = _mm_madd_epi16(x6, k0);
+                        x7 = _mm_madd_epi16(x7, k0);
+                        x8 = _mm_madd_epi16(x8, k0);
+                        x9 = _mm_madd_epi16(x9, k0);
+
+                        _mm_store_si128((__m128i*)(dst + i), x6);
+                        _mm_store_si128((__m128i*)(dst + i + 4), x8);
+                        _mm_store_si128((__m128i*)(dst + i + 8), x7);
+                        _mm_store_si128((__m128i*)(dst + i + 12), x9);
                     }
                 }
             }
             else if( _ksize == 5 )
             {
-                __m128i k0 = _mm_shuffle_epi32(_mm_cvtsi32_si128(kx[0]), 0),
-                        k1 = _mm_shuffle_epi32(_mm_cvtsi32_si128(kx[1]), 0),
-                        k2 = _mm_shuffle_epi32(_mm_cvtsi32_si128(kx[2]), 0);
+                __m128i k0 = _mm_loadl_epi64((__m128i*)(kx + 1));
+                k0 = _mm_unpacklo_epi64(k0, k0);
                 k0 = _mm_packs_epi32(k0, k0);
-                k1 = _mm_packs_epi32(k1, k1);
-                k2 = _mm_packs_epi32(k2, k2);
 
                 for( ; i <= width - 16; i += 16, src += 16 )
                 {
-                    __m128i x0, x1, x2, y0, y1, t0, t1, z0, z1, z2, z3;
-                    x0 = _mm_loadu_si128((__m128i*)(src + cn));
-                    x2 = _mm_loadu_si128((__m128i*)(src - cn));
-                    y0 = _mm_sub_epi16(_mm_unpackhi_epi8(x0, z), _mm_unpackhi_epi8(x2, z));
-                    x0 = _mm_sub_epi16(_mm_unpacklo_epi8(x0, z), _mm_unpacklo_epi8(x2, z));
-
-                    x2 = _mm_mulhi_epi16(x0, k1);
-                    x0 = _mm_mullo_epi16(x0, k1);
-                    z0 = _mm_unpacklo_epi16(x0, x2);
-                    z1 = _mm_unpackhi_epi16(x0, x2);
-                    y1 = _mm_mulhi_epi16(y0, k1);
-                    y0 = _mm_mullo_epi16(y0, k1);
-                    z2 = _mm_unpacklo_epi16(y0, y1);
-                    z3 = _mm_unpackhi_epi16(y0, y1);
-
-                    x0 = _mm_loadu_si128((__m128i*)(src + cn*2));
-                    x1 = _mm_loadu_si128((__m128i*)(src - cn*2));
-                    y1 = _mm_sub_epi16(_mm_unpackhi_epi8(x0, z), _mm_unpackhi_epi8(x1, z));
-                    y0 = _mm_sub_epi16(_mm_unpacklo_epi8(x0, z), _mm_unpacklo_epi8(x1, z));
-
-                    t1 = _mm_mulhi_epi16(y0, k2);
-                    t0 = _mm_mullo_epi16(y0, k2);
-                    y0 = _mm_mullo_epi16(y1, k2);
-                    y1 = _mm_mulhi_epi16(y1, k2);
-                    z0 = _mm_add_epi32(z0, _mm_unpacklo_epi16(t0, t1));
-                    z1 = _mm_add_epi32(z1, _mm_unpackhi_epi16(t0, t1));
-                    z2 = _mm_add_epi32(z2, _mm_unpacklo_epi16(y0, y1));
-                    z3 = _mm_add_epi32(z3, _mm_unpackhi_epi16(y0, y1));
-
-                    _mm_store_si128((__m128i*)(dst + i), z0);
-                    _mm_store_si128((__m128i*)(dst + i + 4), z1);
-                    _mm_store_si128((__m128i*)(dst + i + 8), z2);
-                    _mm_store_si128((__m128i*)(dst + i + 12), z3);
+                    __m128i x0 = _mm_loadu_si128((__m128i*)(src + cn));
+                    __m128i x1 = _mm_loadu_si128((__m128i*)(src - cn));
+
+                    __m128i x2 = _mm_unpackhi_epi8(x0, z);
+                    __m128i x3 = _mm_unpackhi_epi8(x1, z);
+                    x0 = _mm_unpacklo_epi8(x0, z);
+                    x1 = _mm_unpacklo_epi8(x1, z);
+                    __m128i x5 = _mm_sub_epi16(x2, x3);
+                    __m128i x4 = _mm_sub_epi16(x0, x1);
+
+                    __m128i x6 = _mm_loadu_si128((__m128i*)(src + cn * 2));
+                    __m128i x7 = _mm_loadu_si128((__m128i*)(src - cn * 2));
+
+                    __m128i x8 = _mm_unpackhi_epi8(x6, z);
+                    __m128i x9 = _mm_unpackhi_epi8(x7, z);
+                    x6 = _mm_unpacklo_epi8(x6, z);
+                    x7 = _mm_unpacklo_epi8(x7, z);
+                    __m128i x11 = _mm_sub_epi16(x8, x9);
+                    __m128i x10 = _mm_sub_epi16(x6, x7);
+
+                    __m128i x13 = _mm_unpackhi_epi16(x5, x11);
+                    __m128i x12 = _mm_unpackhi_epi16(x4, x10);
+                    x5 = _mm_unpacklo_epi16(x5, x11);
+                    x4 = _mm_unpacklo_epi16(x4, x10);
+                    x5 = _mm_madd_epi16(x5, k0);
+                    x4 = _mm_madd_epi16(x4, k0);
+                    x13 = _mm_madd_epi16(x13, k0);
+                    x12 = _mm_madd_epi16(x12, k0);
+
+                    _mm_store_si128((__m128i*)(dst + i), x4);
+                    _mm_store_si128((__m128i*)(dst + i + 4), x12);
+                    _mm_store_si128((__m128i*)(dst + i + 8), x5);
+                    _mm_store_si128((__m128i*)(dst + i + 12), x13);
                 }
             }
         }
@@ -897,19 +843,18 @@ struct SymmRowSmallVec_8u32s
         kx -= _ksize/2;
         for( ; i <= width - 4; i += 4, src += 4 )
         {
-            __m128i f, s0 = z, x0, x1;
+            __m128i s0 = z;
 
             for( k = j = 0; k < _ksize; k++, j += cn )
             {
-                f = _mm_cvtsi32_si128(kx[k]);
+                __m128i f = _mm_cvtsi32_si128(kx[k]);
                 f = _mm_shuffle_epi32(f, 0);
-                f = _mm_packs_epi32(f, f);
 
-                x0 = _mm_cvtsi32_si128(*(const int*)(src + j));
+                __m128i x0 = _mm_cvtsi32_si128(*(const int*)(src + j));
                 x0 = _mm_unpacklo_epi8(x0, z);
-                x1 = _mm_mulhi_epi16(x0, f);
-                x0 = _mm_mullo_epi16(x0, f);
-                s0 = _mm_add_epi32(s0, _mm_unpacklo_epi16(x0, x1));
+                x0 = _mm_unpacklo_epi16(x0, z);
+                x0 = _mm_madd_epi16(x0, f);
+                s0 = _mm_add_epi32(s0, x0);
             }
             _mm_store_si128((__m128i*)(dst + i), s0);
         }
@@ -1468,6 +1413,8 @@ private:
     mutable int bufsz;
     int ippiOperator(const uchar* _src, uchar* _dst, int width, int cn) const
     {
+        CV_INSTRUMENT_REGION_IPP()
+
         int _ksize = kernel.rows + kernel.cols - 1;
         if ((1 != cn && 3 != cn) || width < _ksize*8)
             return 0;
@@ -1489,10 +1436,10 @@ private:
         float borderValue[] = {0.f, 0.f, 0.f};
         // here is the trick. IPP needs border type and extrapolates the row. We did it already.
         // So we pass anchor=0 and ignore the right tail of results since they are incorrect there.
-        if( (cn == 1 && ippiFilterRowBorderPipeline_32f_C1R(src, step, &dst, roisz, _kx, _ksize, 0,
-                                                            ippBorderRepl, borderValue[0], bufptr) < 0) ||
-            (cn == 3 && ippiFilterRowBorderPipeline_32f_C3R(src, step, &dst, roisz, _kx, _ksize, 0,
-                                                            ippBorderRepl, borderValue, bufptr) < 0))
+        if( (cn == 1 && CV_INSTRUMENT_FUN_IPP(ippiFilterRowBorderPipeline_32f_C1R,(src, step, &dst, roisz, _kx, _ksize, 0,
+                                                            ippBorderRepl, borderValue[0], bufptr)) < 0) ||
+            (cn == 3 && CV_INSTRUMENT_FUN_IPP(ippiFilterRowBorderPipeline_32f_C3R,(src, step, &dst, roisz, _kx, _ksize, 0,
+                                                            ippBorderRepl, borderValue, bufptr)) < 0))
         {
             setIppErrorStatus();
             return 0;
@@ -4555,228 +4502,538 @@ cv::Ptr<cv::FilterEngine> cv::createLinearFilter( int _srcType, int _dstType,
         _rowBorderType, _columnBorderType, _borderValue );
 }
 
-#ifdef HAVE_IPP
-namespace cv
-{
-static bool ipp_filter2D( InputArray _src, OutputArray _dst, int ddepth,
-        InputArray _kernel, Point anchor0,
-        double delta, int borderType )
-{
-#if !HAVE_ICV
-    Mat src = _src.getMat(), kernel = _kernel.getMat();
 
-    if( ddepth < 0 )
-        ddepth = src.depth();
+//================================================================
+// HAL interface
+//================================================================
 
-    _dst.create( src.size(), CV_MAKETYPE(ddepth, src.channels()) );
-    Mat dst = _dst.getMat();
-    Point anchor = normalizeAnchor(anchor0, kernel.size());
+using namespace cv;
+
+struct ReplacementFilter : public hal::Filter2D
+{
+    cvhalFilter2D* ctx;
+    bool isInitialized;
+    ReplacementFilter() : ctx(0), isInitialized(false) { }
+    bool init(uchar* kernel_data, size_t kernel_step, int kernel_type, int kernel_width,
+              int kernel_height, int max_width, int max_height, int stype, int dtype, int borderType, double delta,
+              int anchor_x, int anchor_y, bool isSubmatrix, bool isInplace)
+    {
+        int res = cv_hal_filterInit(&ctx, kernel_data, kernel_step, kernel_type, kernel_width, kernel_height, max_width, max_height,
+                                    stype, dtype, borderType, delta, anchor_x, anchor_y, isSubmatrix, isInplace);
+        isInitialized = (res == CV_HAL_ERROR_OK);
+        return isInitialized;
+    }
+    void apply(uchar* src_data, size_t src_step, uchar* dst_data, size_t dst_step, int width, int height, int full_width, int full_height, int offset_x, int offset_y)
+    {
+        if (isInitialized)
+        {
+            int res = cv_hal_filter(ctx, src_data, src_step, dst_data, dst_step, width, height, full_width, full_height, offset_x, offset_y);
+            if (res != CV_HAL_ERROR_OK)
+                CV_Error(Error::StsNotImplemented, "HAL Filter returned an error");
+        }
+    }
+    ~ReplacementFilter()
+    {
+        if (isInitialized)
+        {
+            int res = cv_hal_filterFree(ctx);
+            if (res != CV_HAL_ERROR_OK)
+                CV_Error(Error::StsNotImplemented, "HAL Filter Free returned an error");
+        }
+    }
+};
 
-    typedef IppStatus (CV_STDCALL * ippiFilterBorder)(const void * pSrc, int srcStep, void * pDst, int dstStep, IppiSize dstRoiSize,
-        IppiBorderType border, const void * borderValue,
-        const IppiFilterBorderSpec* pSpec, Ipp8u* pBuffer);
+#ifdef HAVE_IPP
+typedef IppStatus(CV_STDCALL* IppiFilterBorder)(
+    const void* pSrc, int srcStep, void* pDst, int dstStep,
+    IppiSize dstRoiSize, IppiBorderType border, const void* borderValue,
+    const IppiFilterBorderSpec* pSpec, Ipp8u* pBuffer);
 
-    int stype = src.type(), sdepth = CV_MAT_DEPTH(stype), cn = CV_MAT_CN(stype),
-        ktype = kernel.type(), kdepth = CV_MAT_DEPTH(ktype);
-    bool isolated = (borderType & BORDER_ISOLATED) != 0;
-#if IPP_VERSION_X100 >= 900
-    Point ippAnchor((kernel.cols-1)/2, (kernel.rows-1)/2);
-#else
-    Point ippAnchor(kernel.cols >> 1, kernel.rows >> 1);
-#endif
-    int borderTypeNI = borderType & ~BORDER_ISOLATED;
-    IppiBorderType ippBorderType = ippiGetBorderType(borderTypeNI);
+static IppiFilterBorder getIppFunc(int stype)
+{
+    switch (stype)
+    {
+    case CV_8UC1:
+        return reinterpret_cast<IppiFilterBorder>(ippiFilterBorder_8u_C1R);
+    case CV_8UC3:
+        return reinterpret_cast<IppiFilterBorder>(ippiFilterBorder_8u_C3R);
+    case CV_8UC4:
+        return reinterpret_cast<IppiFilterBorder>(ippiFilterBorder_8u_C4R);
+    case CV_16UC1:
+        return reinterpret_cast<IppiFilterBorder>(ippiFilterBorder_16u_C1R);
+    case CV_16UC3:
+        return reinterpret_cast<IppiFilterBorder>(ippiFilterBorder_16u_C3R);
+    case CV_16UC4:
+        return reinterpret_cast<IppiFilterBorder>(ippiFilterBorder_16u_C4R);
+    case CV_16SC1:
+        return reinterpret_cast<IppiFilterBorder>(ippiFilterBorder_16s_C1R);
+    case CV_16SC3:
+        return reinterpret_cast<IppiFilterBorder>(ippiFilterBorder_16s_C3R);
+    case CV_16SC4:
+        return reinterpret_cast<IppiFilterBorder>(ippiFilterBorder_16s_C4R);
+    case CV_32FC1:
+        return reinterpret_cast<IppiFilterBorder>(ippiFilterBorder_32f_C1R);
+    case CV_32FC3:
+        return reinterpret_cast<IppiFilterBorder>(ippiFilterBorder_32f_C3R);
+    case CV_32FC4:
+        return reinterpret_cast<IppiFilterBorder>(ippiFilterBorder_32f_C4R);
+    default:
+        return 0;
+    }
+}
+
+template <int kdepth>
+struct IppFilterTrait { };
 
-    if (borderTypeNI == BORDER_CONSTANT || borderTypeNI == BORDER_REPLICATE)
+template <>
+struct IppFilterTrait<CV_16S>
+{
+    enum { kernel_type_id = CV_16SC1 };
+    typedef Ipp16s kernel_type;
+    typedef IppStatus(CV_STDCALL* copy_fun_type)(const kernel_type* pSrc, int srcStep, kernel_type* pDst, int dstStep, IppiSize roiSize);
+    inline static copy_fun_type get_copy_fun() { return ippiCopy_16s_C1R; }
+    inline static IppStatus runInit(const kernel_type* pKernel, IppiSize kernelSize, int divisor, IppDataType dataType, int numChannels, IppRoundMode roundMode, IppiFilterBorderSpec* pSpec)
     {
-        ippiFilterBorder ippFunc =
-            stype == CV_8UC1 ? (ippiFilterBorder)ippiFilterBorder_8u_C1R :
-            stype == CV_8UC3 ? (ippiFilterBorder)ippiFilterBorder_8u_C3R :
-            stype == CV_8UC4 ? (ippiFilterBorder)ippiFilterBorder_8u_C4R :
-            stype == CV_16UC1 ? (ippiFilterBorder)ippiFilterBorder_16u_C1R :
-            stype == CV_16UC3 ? (ippiFilterBorder)ippiFilterBorder_16u_C3R :
-            stype == CV_16UC4 ? (ippiFilterBorder)ippiFilterBorder_16u_C4R :
-            stype == CV_16SC1 ? (ippiFilterBorder)ippiFilterBorder_16s_C1R :
-            stype == CV_16SC3 ? (ippiFilterBorder)ippiFilterBorder_16s_C3R :
-            stype == CV_16SC4 ? (ippiFilterBorder)ippiFilterBorder_16s_C4R :
-            stype == CV_32FC1 ? (ippiFilterBorder)ippiFilterBorder_32f_C1R :
-            stype == CV_32FC3 ? (ippiFilterBorder)ippiFilterBorder_32f_C3R :
-            stype == CV_32FC4 ? (ippiFilterBorder)ippiFilterBorder_32f_C4R : 0;
-
-        if (sdepth == ddepth && (ktype == CV_16SC1 || ktype == CV_32FC1) &&
-            ippFunc && (int)ippBorderType >= 0 && (!src.isSubmatrix() || isolated) &&
-            std::fabs(delta - 0) < DBL_EPSILON && ippAnchor == anchor && dst.data != src.data)
-        {
-            IppiSize kernelSize = { kernel.cols, kernel.rows }, dstRoiSize = { dst.cols, dst.rows };
-            IppDataType dataType = ippiGetDataType(ddepth), kernelType = ippiGetDataType(kdepth);
-            Ipp32s specSize = 0, bufsize = 0;
-            IppStatus status = (IppStatus)-1;
+        return ippiFilterBorderInit_16s(pKernel, kernelSize, divisor, dataType, numChannels, roundMode, pSpec);
+    }
+};
 
-            if ((status = ippiFilterBorderGetSize(kernelSize, dstRoiSize, dataType, kernelType, cn, &specSize, &bufsize)) >= 0)
-            {
-                IppAutoBuffer<IppiFilterBorderSpec> spec(specSize);
-                IppAutoBuffer<Ipp8u> buffer(bufsize);
-                Ipp32f borderValue[4] = { 0, 0, 0, 0 };
+template <>
+struct IppFilterTrait<CV_32F>
+{
+    enum { kernel_type_id = CV_32FC1 };
+    typedef Ipp32f kernel_type;
+    typedef IppStatus(CV_STDCALL* copy_fun_type)(const kernel_type* pSrc, int srcStep, kernel_type* pDst, int dstStep, IppiSize roiSize);
+    inline static copy_fun_type get_copy_fun() { return ippiCopy_32f_C1R; }
+    inline static IppStatus runInit(const kernel_type* pKernel, IppiSize kernelSize, int divisor, IppDataType dataType, int numChannels, IppRoundMode roundMode, IppiFilterBorderSpec* pSpec)
+    {
+        CV_UNUSED(divisor);
+        return ippiFilterBorderInit_32f(pKernel, kernelSize, dataType, numChannels, roundMode, pSpec);
+    }
+};
 
-                if(kdepth == CV_32F)
-                {
-                    Ipp32f *pKerBuffer = (Ipp32f*)kernel.data;
-                    IppAutoBuffer<Ipp32f> kerTmp;
-                    int kerStep = sizeof(Ipp32f)*kernelSize.width;
+template <int kdepth>
+struct IppFilter : public hal::Filter2D
+{
+    typedef IppFilterTrait<kdepth> trait;
+    typedef typename trait::kernel_type kernel_type;
+
+    IppAutoBuffer<IppiFilterBorderSpec> spec;
+    IppAutoBuffer<Ipp8u> buffer;
+    IppAutoBuffer<kernel_type> kernelBuffer;
+    IppiBorderType ippBorderType;
+    int src_type;
+
+    bool init(uchar* kernel_data, size_t kernel_step, int, int kernel_width, int kernel_height,
+              int max_width, int max_height, int stype, int dtype,
+              int borderType, double delta, int anchor_x, int anchor_y, bool isSubmatrix, bool isInplace)
+    {
+        Point anchor(anchor_x, anchor_y);
 #if IPP_VERSION_X100 >= 900
-                    if((int)kernel.step != kerStep)
-                    {
-                        kerTmp.Alloc(kerStep*kernelSize.height);
-                        if(ippiCopy_32f_C1R((Ipp32f*)kernel.data, (int)kernel.step, kerTmp, kerStep, kernelSize) < 0)
-                            return false;
-                        pKerBuffer = kerTmp;
-                    }
+        Point ippAnchor((kernel_width - 1) / 2, (kernel_height - 1) / 2);
 #else
-                    kerTmp.Alloc(kerStep*kernelSize.height);
-                    Mat kerFlip(Size(kernelSize.width, kernelSize.height), CV_32FC1, kerTmp, kerStep);
-                    flip(kernel, kerFlip, -1);
-                    pKerBuffer = kerTmp;
+        Point ippAnchor(kernel_width >> 1, kernel_height >> 1);
+#endif
+        bool isIsolated = (borderType & BORDER_ISOLATED) != 0;
+        int borderTypeNI = borderType & ~BORDER_ISOLATED;
+        ippBorderType = ippiGetBorderType(borderTypeNI);
+        int ddepth = CV_MAT_DEPTH(dtype);
+        int sdepth = CV_MAT_DEPTH(stype);
+
+#if IPP_VERSION_X100 >= 201700 && IPP_VERSION_X100 < 201702 // IPP bug with 1x1 kernel
+        if(kernel_width == 1 && kernel_height == 1)
+            return false;
 #endif
 
-                    if((status = ippiFilterBorderInit_32f(pKerBuffer, kernelSize,
-                        dataType, cn, ippRndFinancial, spec)) >= 0 )
-                    {
-                        status = ippFunc(src.data, (int)src.step, dst.data, (int)dst.step, dstRoiSize,
-                            ippBorderType, borderValue, spec, buffer);
-                    }
-                }
-                else if(kdepth == CV_16S)
-                {
-                    Ipp16s *pKerBuffer = (Ipp16s*)kernel.data;
-                    IppAutoBuffer<Ipp16s> kerTmp;
-                    int kerStep = sizeof(Ipp16s)*kernelSize.width;
+        bool runIpp = true
+                      && (borderTypeNI == BORDER_CONSTANT || borderTypeNI == BORDER_REPLICATE)
+                      && (sdepth == ddepth)
+                      && (getIppFunc(stype))
+                      && ((int)ippBorderType > 0)
+                      && (!isSubmatrix || isIsolated)
+                      && (std::fabs(delta - 0) < DBL_EPSILON)
+                      && (ippAnchor == anchor)
+                      && !isInplace;
+
+        if (!runIpp)
+            return false;
+
+        src_type = stype;
+        int cn = CV_MAT_CN(stype);
+        IppiSize kernelSize = { kernel_width, kernel_height };
+        IppDataType dataType = ippiGetDataType(ddepth);
+        IppDataType kernelType = ippiGetDataType(kdepth);
+        Ipp32s specSize = 0;
+        Ipp32s bufsize = 0;
+        IppiSize dstRoiSize = { max_width, max_height };
+        IppStatus status;
+        status = ippiFilterBorderGetSize(kernelSize, dstRoiSize, dataType, kernelType, cn, &specSize, &bufsize);
+        if (status >= 0) {
+            kernel_type* pKerBuffer = (kernel_type*)kernel_data;
+            size_t good_kernel_step = sizeof(kernel_type) * static_cast<size_t>(kernelSize.width);
 #if IPP_VERSION_X100 >= 900
-                    if((int)kernel.step != kerStep)
-                    {
-                        kerTmp.Alloc(kerStep*kernelSize.height);
-                        if(ippiCopy_16s_C1R((Ipp16s*)kernel.data, (int)kernel.step, kerTmp, kerStep, kernelSize) < 0)
-                            return false;
-                        pKerBuffer = kerTmp;
-                    }
+            if (kernel_step != good_kernel_step) {
+                kernelBuffer.Alloc((int)good_kernel_step * kernelSize.height);
+                status = trait::get_copy_fun()((kernel_type*)kernel_data, (int)kernel_step, kernelBuffer, (int)good_kernel_step, kernelSize);
+                if (status < 0)
+                    return false;
+                pKerBuffer = kernelBuffer;
+            }
 #else
-                    kerTmp.Alloc(kerStep*kernelSize.height);
-                    Mat kerFlip(Size(kernelSize.width, kernelSize.height), CV_16SC1, kerTmp, kerStep);
-                    flip(kernel, kerFlip, -1);
-                    pKerBuffer = kerTmp;
+            kernelBuffer.Alloc(good_kernel_step * kernelSize.height);
+            Mat kerFlip(Size(kernelSize.width, kernelSize.height), trait::kernel_type_id, kernelBuffer, (int)good_kernel_step);
+            Mat kernel(Size(kernel_width, kernel_height), trait::kernel_type_id, kernel_data, kernel_step);
+            flip(kernel, kerFlip, -1);
+            pKerBuffer = kernelBuffer;
 #endif
-
-                    if((status = ippiFilterBorderInit_16s(pKerBuffer, kernelSize,
-                        0, dataType, cn, ippRndFinancial, spec)) >= 0)
-                    {
-                        status = ippFunc(src.data, (int)src.step, dst.data, (int)dst.step, dstRoiSize,
-                            ippBorderType, borderValue, spec, buffer);
-                    }
-                }
-            }
-
-            if (status >= 0)
-            {
-                CV_IMPL_ADD(CV_IMPL_IPP);
+            spec.Alloc(specSize);
+            buffer.Alloc(bufsize);
+            status = trait::runInit(pKerBuffer, kernelSize, 0, dataType, cn, ippRndFinancial, spec);
+            if (status >= 0) {
                 return true;
             }
         }
+        return false;
     }
-#else
-    CV_UNUSED(_src); CV_UNUSED(_dst); CV_UNUSED(ddepth); CV_UNUSED(_kernel), CV_UNUSED(anchor0), CV_UNUSED(delta), CV_UNUSED(borderType);
-#endif
-    return false;
-}
-}
-#endif
 
+    void apply(uchar* src_data, size_t src_step, uchar* dst_data, size_t dst_step, int width, int height, int, int, int, int)
+    {
+        CV_INSTRUMENT_REGION_IPP()
+
+        if (dst_data == src_data)
+            CV_Error(Error::StsBadArg, "Inplace IPP Filter2D is not supported");
+        IppiFilterBorder ippiFilterBorder = getIppFunc(src_type);
+        IppiSize dstRoiSize = { width, height };
+        kernel_type borderValue[4] = { 0, 0, 0, 0 };
+        IppStatus status = CV_INSTRUMENT_FUN_IPP(ippiFilterBorder, src_data, (int)src_step, dst_data, (int)dst_step, dstRoiSize, ippBorderType, borderValue, spec, buffer);
+        if (status >= 0) {
+            CV_IMPL_ADD(CV_IMPL_IPP);
+        }
+    }
+};
+#endif
 
-void cv::filter2D( InputArray _src, OutputArray _dst, int ddepth,
-                   InputArray _kernel, Point anchor0,
-                   double delta, int borderType )
+struct DftFilter : public hal::Filter2D
 {
-    CV_OCL_RUN(_dst.isUMat() && _src.dims() <= 2,
-               ocl_filter2D(_src, _dst, ddepth, _kernel, anchor0, delta, borderType))
-
-    Mat src = _src.getMat(), kernel = _kernel.getMat();
-
-    if( ddepth < 0 )
-        ddepth = src.depth();
+    int src_type;
+    int dst_type;
+    double delta;
+    Mat kernel;
+    Point anchor;
+    int borderType;
 
+    static bool isAppropriate(int stype, int dtype, int kernel_width, int kernel_height)
+    {
 #if CV_SSE2
-    int dft_filter_size = ((src.depth() == CV_8U && (ddepth == CV_8U || ddepth == CV_16S)) ||
-        (src.depth() == CV_32F && ddepth == CV_32F)) && checkHardwareSupport(CV_CPU_SSE3)? 130 : 50;
+        int sdepth = CV_MAT_DEPTH(stype);
+        int ddepth = CV_MAT_DEPTH(dtype);
+        int dft_filter_size = ((sdepth == CV_8U && (ddepth == CV_8U || ddepth == CV_16S)) || (sdepth == CV_32F && ddepth == CV_32F)) && checkHardwareSupport(CV_CPU_SSE3) ? 130 : 50;
 #else
-    int dft_filter_size = 50;
+        CV_UNUSED(stype);
+        CV_UNUSED(dtype);
+        int dft_filter_size = 50;
 #endif
+        return kernel_width * kernel_height >= dft_filter_size;
+    }
 
-    _dst.create( src.size(), CV_MAKETYPE(ddepth, src.channels()) );
-    Mat dst = _dst.getMat();
-    Point anchor = normalizeAnchor(anchor0, kernel.size());
-
-    CV_IPP_RUN(true, ipp_filter2D(_src, _dst, ddepth, _kernel, anchor0, delta, borderType));
-
-
-#ifdef HAVE_TEGRA_OPTIMIZATION
-    if( tegra::useTegra() && tegra::filter2D(src, dst, kernel, anchor, delta, borderType) )
-        return;
-#endif
+    bool init(uchar* kernel_data, size_t kernel_step, int kernel_type, int kernel_width, int kernel_height,
+              int, int, int stype, int dtype,
+              int borderType_, double delta_, int anchor_x, int anchor_y, bool, bool)
+    {
+        anchor = Point(anchor_x, anchor_y);
+        borderType = borderType_;
+        kernel = Mat(Size(kernel_width, kernel_height), kernel_type, kernel_data, kernel_step);
+        src_type = stype;
+        dst_type = dtype;
+        delta = delta_;
+        if (isAppropriate(stype, dtype, kernel_width, kernel_height))
+            return true;
+        return false;
+    }
 
-    if( kernel.cols*kernel.rows >= dft_filter_size )
+    void apply(uchar* src_data, size_t src_step, uchar* dst_data, size_t dst_step, int width, int height, int, int, int, int)
     {
+        Mat src(Size(width, height), src_type, src_data, src_step);
+        Mat dst(Size(width, height), dst_type, dst_data, dst_step);
         Mat temp;
+        int src_channels = CV_MAT_CN(src_type);
+        int dst_channels = CV_MAT_CN(dst_type);
+        int ddepth = CV_MAT_DEPTH(dst_type);
         // crossCorr doesn't accept non-zero delta with multiple channels
-        if( src.channels() != 1 && delta != 0 )
-        {
+        if (src_channels != 1 && delta != 0) {
             // The semantics of filter2D require that the delta be applied
             // as floating-point math.  So wee need an intermediate Mat
             // with a float datatype.  If the dest is already floats,
             // we just use that.
-            int corrDepth = dst.depth();
-            if( (dst.depth() == CV_32F || dst.depth() == CV_64F) &&
-                src.data != dst.data )
-            {
-                temp = dst;
+            int corrDepth = ddepth;
+            if ((ddepth == CV_32F || ddepth == CV_64F) && src_data != dst_data) {
+                temp = Mat(Size(width, height), dst_type, dst_data, dst_step);
+            } else {
+                corrDepth = ddepth == CV_64F ? CV_64F : CV_32F;
+                temp.create(Size(width, height), CV_MAKETYPE(corrDepth, dst_channels));
             }
+            crossCorr(src, kernel, temp, src.size(),
+                      CV_MAKETYPE(corrDepth, src_channels),
+                      anchor, 0, borderType);
+            add(temp, delta, temp);
+            if (temp.data != dst_data) {
+                temp.convertTo(dst, dst.type());
+            }
+        } else {
+            if (src_data != dst_data)
+                temp = Mat(Size(width, height), dst_type, dst_data, dst_step);
             else
+                temp.create(Size(width, height), dst_type);
+            crossCorr(src, kernel, temp, src.size(),
+                      CV_MAKETYPE(ddepth, src_channels),
+                      anchor, delta, borderType);
+            if (temp.data != dst_data)
+                temp.copyTo(dst);
+        }
+    }
+};
+
+struct OcvFilter : public hal::Filter2D
+{
+    Ptr<FilterEngine> f;
+    int src_type;
+    int dst_type;
+    bool isIsolated;
+
+    bool init(uchar* kernel_data, size_t kernel_step, int kernel_type, int kernel_width,
+              int kernel_height, int, int, int stype, int dtype, int borderType, double delta,
+              int anchor_x, int anchor_y, bool, bool)
+    {
+        isIsolated = (borderType & BORDER_ISOLATED) != 0;
+        src_type = stype;
+        dst_type = dtype;
+        int borderTypeValue = borderType & ~BORDER_ISOLATED;
+        Mat kernel = Mat(Size(kernel_width, kernel_height), kernel_type, kernel_data, kernel_step);
+        f = createLinearFilter(src_type, dst_type, kernel, Point(anchor_x, anchor_y), delta,
+                               borderTypeValue);
+        return true;
+    }
+    void apply(uchar* src_data, size_t src_step, uchar* dst_data, size_t dst_step, int width, int height, int full_width, int full_height, int offset_x, int offset_y)
+    {
+        Mat src(Size(width, height), src_type, src_data, src_step);
+        Mat dst(Size(width, height), dst_type, dst_data, dst_step);
+        f->apply(src, dst, Size(full_width, full_height), Point(offset_x, offset_y));
+    }
+};
+
+
+struct ReplacementSepFilter : public hal::SepFilter2D
+{
+    cvhalFilter2D *ctx;
+    bool isInitialized;
+    ReplacementSepFilter() : ctx(0), isInitialized(false) {}
+    bool init(int stype, int dtype, int ktype,
+              uchar * kernelx_data, int kernelx_len,
+              uchar * kernely_data, int kernely_len,
+              int anchor_x, int anchor_y, double delta, int borderType)
+    {
+        int res = cv_hal_sepFilterInit(&ctx, stype, dtype, ktype,
+                                       kernelx_data, kernelx_len,
+                                       kernely_data, kernely_len,
+                                       anchor_x, anchor_y, delta, borderType);
+        isInitialized = (res == CV_HAL_ERROR_OK);
+        return isInitialized;
+    }
+    void apply(uchar* src_data, size_t src_step, uchar* dst_data, size_t dst_step,
+             int width, int height, int full_width, int full_height,
+             int offset_x, int offset_y)
+    {
+        if (isInitialized)
+        {
+            int res = cv_hal_sepFilter(ctx, src_data, src_step, dst_data, dst_step, width, height, full_width, full_height, offset_x, offset_y);
+            if (res != CV_HAL_ERROR_OK)
+                CV_Error(Error::StsNotImplemented, "Failed to run HAL sepFilter implementation");
+        }
+    }
+    ~ReplacementSepFilter()
+    {
+        if (isInitialized)
+        {
+            int res = cv_hal_sepFilterFree(ctx);
+            if (res != CV_HAL_ERROR_OK)
+                CV_Error(Error::StsNotImplemented, "Failed to run HAL sepFilter implementation");
+        }
+    }
+};
+
+struct OcvSepFilter : public hal::SepFilter2D
+{
+    Ptr<FilterEngine> f;
+    int src_type;
+    int dst_type;
+    bool init(int stype, int dtype, int ktype,
+              uchar * kernelx_data, int kernelx_len,
+              uchar * kernely_data, int kernely_len,
+              int anchor_x, int anchor_y, double delta, int borderType)
+    {
+        src_type = stype;
+        dst_type = dtype;
+        Mat kernelX(Size(kernelx_len, 1), ktype, kernelx_data);
+        Mat kernelY(Size(kernely_len, 1), ktype, kernely_data);
+
+        f = createSeparableLinearFilter( stype, dtype, kernelX, kernelY,
+                                         Point(anchor_x, anchor_y),
+                                         delta, borderType & ~BORDER_ISOLATED );
+        return true;
+    }
+    void apply(uchar* src_data, size_t src_step, uchar* dst_data, size_t dst_step,
+             int width, int height, int full_width, int full_height,
+             int offset_x, int offset_y)
+    {
+        Mat src(Size(width, height), src_type, src_data, src_step);
+        Mat dst(Size(width, height), dst_type, dst_data, dst_step);
+        f->apply(src, dst, Size(full_width, full_height), Point(offset_x, offset_y));
+    }
+};
+
+//===================================================================
+//       HAL functions
+//===================================================================
+
+namespace cv {
+namespace hal {
+
+Ptr<hal::Filter2D> Filter2D::create(uchar* kernel_data, size_t kernel_step, int kernel_type,
+                                   int kernel_width, int kernel_height,
+                                   int max_width, int max_height,
+                                   int stype, int dtype,
+                                   int borderType, double delta, int anchor_x, int anchor_y, bool isSubmatrix, bool isInplace)
+{
+    {
+        ReplacementFilter* impl = new ReplacementFilter();
+        if (impl->init(kernel_data, kernel_step, kernel_type, kernel_width, kernel_height,
+                       max_width, max_height, stype, dtype,
+                       borderType, delta, anchor_x, anchor_y, isSubmatrix, isInplace))
+        {
+            return Ptr<hal::Filter2D>(impl);
+        }
+        delete impl;
+    }
+
+#ifdef HAVE_IPP
+    CV_IPP_CHECK()
+    {
+        if (kernel_type == CV_32FC1) {
+            IppFilter<CV_32F>* impl = new IppFilter<CV_32F>();
+            if (impl->init(kernel_data, kernel_step, kernel_type, kernel_width, kernel_height,
+                           max_width, max_height, stype, dtype,
+                           borderType, delta, anchor_x, anchor_y, isSubmatrix, isInplace))
             {
-                corrDepth = dst.depth() == CV_64F ? CV_64F : CV_32F;
-                temp.create( dst.size(), CV_MAKETYPE(corrDepth, dst.channels()) );
+                return Ptr<hal::Filter2D>(impl);
             }
-            crossCorr( src, kernel, temp, src.size(),
-                       CV_MAKETYPE(corrDepth, src.channels()),
-                       anchor, 0, borderType );
-            add( temp, delta, temp );
-            if ( temp.data != dst.data )
+            delete impl;
+        }
+
+        if (kernel_type == CV_16SC1) {
+            IppFilter<CV_16S>* impl = new IppFilter<CV_16S>();
+            if (impl->init(kernel_data, kernel_step, kernel_type, kernel_width, kernel_height,
+                           max_width, max_height, stype, dtype,
+                           borderType, delta, anchor_x, anchor_y, isSubmatrix, isInplace))
             {
-                temp.convertTo( dst, dst.type() );
+                return Ptr<hal::Filter2D>(impl);
             }
+            delete impl;
         }
-        else
+    }
+#endif
+
+    if (DftFilter::isAppropriate(stype, dtype, kernel_width, kernel_height))
+    {
+        DftFilter* impl = new DftFilter();
+        if (impl->init(kernel_data, kernel_step, kernel_type, kernel_width, kernel_height,
+                       max_width, max_height, stype, dtype,
+                       borderType, delta, anchor_x, anchor_y, isSubmatrix, isInplace))
         {
-            if( src.data != dst.data )
-                temp = dst;
-            else
-                temp.create(dst.size(), dst.type());
-            crossCorr( src, kernel, temp, src.size(),
-                       CV_MAKETYPE(ddepth, src.channels()),
-                       anchor, delta, borderType );
-            if( temp.data != dst.data )
-                temp.copyTo(dst);
+            return Ptr<hal::Filter2D>(impl);
         }
-        return;
+        delete impl;
+    }
+
+    {
+        OcvFilter* impl = new OcvFilter();
+        impl->init(kernel_data, kernel_step, kernel_type, kernel_width, kernel_height,
+                   max_width, max_height, stype, dtype,
+                   borderType, delta, anchor_x, anchor_y, isSubmatrix, isInplace);
+        return Ptr<hal::Filter2D>(impl);
     }
+}
+
+//---------------------------------------------------------------
 
-    Ptr<FilterEngine> f = createLinearFilter(src.type(), dst.type(), kernel,
-                                             anchor, delta, borderType & ~BORDER_ISOLATED );
-    f->apply(src, dst, Rect(0,0,-1,-1), Point(), (borderType & BORDER_ISOLATED) != 0 );
+Ptr<SepFilter2D> SepFilter2D::create(int stype, int dtype, int ktype,
+                                     uchar * kernelx_data, int kernelx_len,
+                                     uchar * kernely_data, int kernely_len,
+                                     int anchor_x, int anchor_y, double delta, int borderType)
+{
+    {
+        ReplacementSepFilter * impl = new ReplacementSepFilter();
+        if (impl->init(stype, dtype, ktype,
+                       kernelx_data, kernelx_len,
+                       kernely_data, kernely_len,
+                       anchor_x, anchor_y, delta, borderType))
+        {
+            return Ptr<hal::SepFilter2D>(impl);
+        }
+        delete impl;
+    }
+    {
+        OcvSepFilter * impl = new OcvSepFilter();
+        impl->init(stype, dtype, ktype,
+                   kernelx_data, kernelx_len,
+                   kernely_data, kernely_len,
+                   anchor_x, anchor_y, delta, borderType);
+        return Ptr<hal::SepFilter2D>(impl);
+    }
 }
 
+} // cv::hal::
+} // cv::
+
+//================================================================
+//   Main interface
+//================================================================
+
+void cv::filter2D( InputArray _src, OutputArray _dst, int ddepth,
+                   InputArray _kernel, Point anchor0,
+                   double delta, int borderType )
+{
+    CV_INSTRUMENT_REGION()
+
+    CV_OCL_RUN(_dst.isUMat() && _src.dims() <= 2,
+               ocl_filter2D(_src, _dst, ddepth, _kernel, anchor0, delta, borderType))
+
+    Mat src = _src.getMat(), kernel = _kernel.getMat();
+
+    if( ddepth < 0 )
+        ddepth = src.depth();
+
+    _dst.create( src.size(), CV_MAKETYPE(ddepth, src.channels()) );
+    Mat dst = _dst.getMat();
+    Point anchor = normalizeAnchor(anchor0, kernel.size());
+
+    Point ofs;
+    Size wsz(src.cols, src.rows);
+    if( (borderType & BORDER_ISOLATED) == 0 )
+        src.locateROI( wsz, ofs );
+
+    Ptr<hal::Filter2D> c = hal::Filter2D::create(kernel.data, kernel.step, kernel.type(), kernel.cols, kernel.rows,
+                                                 dst.cols, dst.rows, src.type(), dst.type(),
+                                                 borderType, delta, anchor.x, anchor.y, src.isSubmatrix(), src.data == dst.data);
+    c->apply(src.data, src.step, dst.data, dst.step, dst.cols, dst.rows, wsz.width, wsz.height, ofs.x, ofs.y);
+}
 
 void cv::sepFilter2D( InputArray _src, OutputArray _dst, int ddepth,
                       InputArray _kernelX, InputArray _kernelY, Point anchor,
                       double delta, int borderType )
 {
-    CV_OCL_RUN(_dst.isUMat() && _src.dims() <= 2,
+    CV_INSTRUMENT_REGION()
+
+    CV_OCL_RUN(_dst.isUMat() && _src.dims() <= 2 && (size_t)_src.rows() > _kernelY.total() && (size_t)_src.cols() > _kernelX.total(),
                ocl_sepFilter2D(_src, _dst, ddepth, _kernelX, _kernelY, anchor, delta, borderType))
 
     Mat src = _src.getMat(), kernelX = _kernelX.getMat(), kernelY = _kernelY.getMat();
@@ -4787,9 +5044,22 @@ void cv::sepFilter2D( InputArray _src, OutputArray _dst, int ddepth,
     _dst.create( src.size(), CV_MAKETYPE(ddepth, src.channels()) );
     Mat dst = _dst.getMat();
 
-    Ptr<FilterEngine> f = createSeparableLinearFilter(src.type(),
-        dst.type(), kernelX, kernelY, anchor, delta, borderType & ~BORDER_ISOLATED );
-    f->apply(src, dst, Rect(0,0,-1,-1), Point(), (borderType & BORDER_ISOLATED) != 0 );
+    Point ofs;
+    Size wsz(src.cols, src.rows);
+    if( (borderType & BORDER_ISOLATED) == 0 )
+        src.locateROI( wsz, ofs );
+
+    CV_Assert( kernelX.type() == kernelY.type() &&
+               (kernelX.cols == 1 || kernelX.rows == 1) &&
+               (kernelY.cols == 1 || kernelY.rows == 1) );
+
+    Mat contKernelX = kernelX.isContinuous() ? kernelX : kernelX.clone();
+    Mat contKernelY = kernelY.isContinuous() ? kernelY : kernelY.clone();
+    Ptr<hal::SepFilter2D> c = hal::SepFilter2D::create(src.type(), dst.type(), kernelX.type(),
+                                                       contKernelX.data, kernelX.cols + kernelX.rows - 1,
+                                                       contKernelY.data, kernelY.cols + kernelY.rows - 1,
+                                                       anchor.x, anchor.y, delta, borderType & ~BORDER_ISOLATED);
+    c->apply(src.data, src.step, dst.data, dst.step, dst.cols, dst.rows, wsz.width, wsz.height, ofs.x, ofs.y);
 }
 
 
diff --git a/modules/imgproc/src/filterengine.hpp b/modules/imgproc/src/filterengine.hpp
index 68875c0..9110668 100644
--- a/modules/imgproc/src/filterengine.hpp
+++ b/modules/imgproc/src/filterengine.hpp
@@ -37,6 +37,8 @@ the use of this software, even if advised of the possibility of such damage.
 #ifndef __OPENCV_IMGPROC_FILTERENGINE_HPP__
 #define __OPENCV_IMGPROC_FILTERENGINE_HPP__
 
+#include "opencv2/imgproc.hpp"
+
 namespace cv
 {
 
@@ -228,19 +230,17 @@ public:
               int _rowBorderType = BORDER_REPLICATE,
               int _columnBorderType = -1,
               const Scalar& _borderValue = Scalar());
+
     //! starts filtering of the specified ROI of an image of size wholeSize.
-    virtual int start(Size wholeSize, Rect roi, int maxBufRows = -1);
+    virtual int start(const cv::Size &wholeSize, const cv::Size &sz, const cv::Point &ofs);
     //! starts filtering of the specified ROI of the specified image.
-    virtual int start(const Mat& src, const Rect& srcRoi = Rect(0,0,-1,-1),
-                      bool isolated = false, int maxBufRows = -1);
+    virtual int start(const Mat& src, const cv::Size &wsz, const cv::Point &ofs);
     //! processes the next srcCount rows of the image.
     virtual int proceed(const uchar* src, int srcStep, int srcCount,
                         uchar* dst, int dstStep);
     //! applies filter to the specified ROI of the image. if srcRoi=(0,0,-1,-1), the whole image is filtered.
-    virtual void apply( const Mat& src, Mat& dst,
-                        const Rect& srcRoi = Rect(0,0,-1,-1),
-                        Point dstOfs = Point(0,0),
-                        bool isolated = false);
+    virtual void apply(const Mat& src, Mat& dst, const cv::Size &wsz, const cv::Point &ofs);
+
     //! returns true if the filter is separable
     bool isSeparable() const { return !filter2D; }
     //! returns the number
diff --git a/modules/imgproc/src/floodfill.cpp b/modules/imgproc/src/floodfill.cpp
index 6d8491a..0df59d3 100644
--- a/modules/imgproc/src/floodfill.cpp
+++ b/modules/imgproc/src/floodfill.cpp
@@ -459,6 +459,8 @@ int cv::floodFill( InputOutputArray _image, InputOutputArray _mask,
                   Point seedPoint, Scalar newVal, Rect* rect,
                   Scalar loDiff, Scalar upDiff, int flags )
 {
+    CV_INSTRUMENT_REGION()
+
     ConnectedComp comp;
     std::vector<FFillSegment> buffer;
 
@@ -584,7 +586,7 @@ int cv::floodFill( InputOutputArray _image, InputOutputArray _mask,
     else
         CV_Error( CV_StsUnsupportedFormat, "" );
 
-    uchar newMaskVal = (uchar)((flags & ~0xff) == 0 ? 1 : ((flags >> 8) & 255));
+    uchar newMaskVal = (uchar)((flags & 0xff00) == 0 ? 1 : ((flags >> 8) & 255));
 
     if( type == CV_8UC1 )
         floodFillGrad_CnIR<uchar, uchar, int, Diff8uC1>(
@@ -629,6 +631,8 @@ int cv::floodFill( InputOutputArray _image, Point seedPoint,
                   Scalar newVal, Rect* rect,
                   Scalar loDiff, Scalar upDiff, int flags )
 {
+    CV_INSTRUMENT_REGION()
+
     return floodFill(_image, Mat(), seedPoint, newVal, rect, loDiff, upDiff, flags);
 }
 
diff --git a/modules/imgproc/src/generalized_hough.cpp b/modules/imgproc/src/generalized_hough.cpp
index a261d64..2d0b5bf 100644
--- a/modules/imgproc/src/generalized_hough.cpp
+++ b/modules/imgproc/src/generalized_hough.cpp
@@ -415,6 +415,8 @@ namespace
 
     void GeneralizedHoughBallardImpl::calcHist()
     {
+        CV_INSTRUMENT_REGION()
+
         CV_Assert( imageEdges_.type() == CV_8UC1 );
         CV_Assert( imageDx_.type() == CV_32FC1 && imageDx_.size() == imageSize_);
         CV_Assert( imageDy_.type() == imageDx_.type() && imageDy_.size() == imageSize_);
diff --git a/modules/imgproc/src/geometry.cpp b/modules/imgproc/src/geometry.cpp
index 2d95853..0377ba3 100644
--- a/modules/imgproc/src/geometry.cpp
+++ b/modules/imgproc/src/geometry.cpp
@@ -94,6 +94,8 @@ cvBoxPoints( CvBox2D box, CvPoint2D32f pt[4] )
 
 double cv::pointPolygonTest( InputArray _contour, Point2f pt, bool measureDist )
 {
+    CV_INSTRUMENT_REGION()
+
     double result = 0;
     Mat contour = _contour.getMat();
     int i, total = contour.checkVector(2), counter = 0;
@@ -504,6 +506,8 @@ static int intersectConvexConvex_( const Point2f* P, int n, const Point2f* Q, in
 
 float cv::intersectConvexConvex( InputArray _p1, InputArray _p2, OutputArray _p12, bool handleNested )
 {
+    CV_INSTRUMENT_REGION()
+
     Mat p1 = _p1.getMat(), p2 = _p2.getMat();
     CV_Assert( p1.depth() == CV_32S || p1.depth() == CV_32F );
     CV_Assert( p2.depth() == CV_32S || p2.depth() == CV_32F );
diff --git a/modules/imgproc/src/grabcut.cpp b/modules/imgproc/src/grabcut.cpp
index 36356be..ca9b05c 100644
--- a/modules/imgproc/src/grabcut.cpp
+++ b/modules/imgproc/src/grabcut.cpp
@@ -333,7 +333,7 @@ static void checkMask( const Mat& img, const Mat& mask )
         {
             uchar val = mask.at<uchar>(y,x);
             if( val!=GC_BGD && val!=GC_FGD && val!=GC_PR_BGD && val!=GC_PR_FGD )
-                CV_Error( CV_StsBadArg, "mask element value must be equel"
+                CV_Error( CV_StsBadArg, "mask element value must be equal "
                     "GC_BGD or GC_FGD or GC_PR_BGD or GC_PR_FGD" );
         }
     }
@@ -529,6 +529,8 @@ void cv::grabCut( InputArray _img, InputOutputArray _mask, Rect rect,
                   InputOutputArray _bgdModel, InputOutputArray _fgdModel,
                   int iterCount, int mode )
 {
+    CV_INSTRUMENT_REGION()
+
     Mat img = _img.getMat();
     Mat& mask = _mask.getMatRef();
     Mat& bgdModel = _bgdModel.getMatRef();
diff --git a/modules/imgproc/src/hal_replacement.hpp b/modules/imgproc/src/hal_replacement.hpp
new file mode 100644
index 0000000..1bbc2f3
--- /dev/null
+++ b/modules/imgproc/src/hal_replacement.hpp
@@ -0,0 +1,647 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+//  By downloading, copying, installing or using the software you agree to this license.
+//  If you do not agree to this license, do not download, install,
+//  copy or use the software.
+//
+//
+//                          License Agreement
+//                For Open Source Computer Vision Library
+//
+// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
+// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
+// Copyright (C) 2013, OpenCV Foundation, all rights reserved.
+// Copyright (C) 2015, Itseez Inc., all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+//   * Redistribution's of source code must retain the above copyright notice,
+//     this list of conditions and the following disclaimer.
+//
+//   * Redistribution's in binary form must reproduce the above copyright notice,
+//     this list of conditions and the following disclaimer in the documentation
+//     and/or other materials provided with the distribution.
+//
+//   * The name of the copyright holders may not be used to endorse or promote products
+//     derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#ifndef OPENCV_IMGPROC_HAL_REPLACEMENT_HPP
+#define OPENCV_IMGPROC_HAL_REPLACEMENT_HPP
+
+#include "opencv2/core/hal/interface.h"
+#include "opencv2/imgproc/hal/interface.h"
+
+#if defined __GNUC__
+#  pragma GCC diagnostic push
+#  pragma GCC diagnostic ignored "-Wunused-parameter"
+#elif defined _MSC_VER
+#  pragma warning( push )
+#  pragma warning( disable: 4100 )
+#endif
+
+//! @addtogroup imgproc_hal_interface
+//! @note Define your functions to override default implementations:
+//! @code
+//! #undef hal_add8u
+//! #define hal_add8u my_add8u
+//! @endcode
+//! @{
+
+/**
+ at brief Dummy structure storing filtering context
+
+Users can convert this pointer to any type they want. Initialisation and destruction should be made in Init and Free function implementations correspondingly.
+Example:
+ at code{.cpp}
+int my_hal_filterInit(cvhalFilter2D **context, ...) {
+    context = static_cast<cvhalFilter2D*>(new MyFilterData());
+    //... init
+}
+
+int my_hal_filterFree(cvhalFilter2D *context) {
+    MyFilterData *c = static_cast<MyFilterData*>(context);
+    delete c;
+}
+ at endcode
+ */
+struct cvhalFilter2D {};
+
+/**
+   @brief hal_filterInit
+   @param context double pointer to user-defined context
+   @param kernel_data pointer to kernel data
+   @param kernel_step kernel step
+   @param kernel_type kernel type (CV_8U, ...)
+   @param kernel_width kernel width
+   @param kernel_height kernel height
+   @param max_width max possible image width, can be used to allocate working buffers
+   @param max_height max possible image height
+   @param src_type source image type
+   @param dst_type destination image type
+   @param borderType border processing mode (CV_HAL_BORDER_REFLECT, ...)
+   @param delta added to pixel values
+   @param anchor_x relative X position of center point within the kernel
+   @param anchor_y relative Y position of center point within the kernel
+   @param allowSubmatrix indicates whether the submatrices will be allowed as source image
+   @param allowInplace indicates whether the inplace operation will be possible
+   @sa cv::filter2D, cv::hal::Filter2D
+ */
+inline int hal_ni_filterInit(cvhalFilter2D **context, uchar *kernel_data, size_t kernel_step, int kernel_type, int kernel_width, int kernel_height, int max_width, int max_height, int src_type, int dst_type, int borderType, double delta, int anchor_x, int anchor_y, bool allowSubmatrix, bool allowInplace) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+/**
+   @brief hal_filter
+   @param context pointer to user-defined context
+   @param src_data source image data
+   @param src_step source image step
+   @param dst_data destination image data
+   @param dst_step destination image step
+   @param width images width
+   @param height images height
+   @param full_width full width of source image (outside the ROI)
+   @param full_height full height of source image (outside the ROI)
+   @param offset_x source image ROI offset X
+   @param offset_y source image ROI offset Y
+   @sa cv::filter2D, cv::hal::Filter2D
+ */
+inline int hal_ni_filter(cvhalFilter2D *context, uchar *src_data, size_t src_step, uchar *dst_data, size_t dst_step, int width, int height, int full_width, int full_height, int offset_x, int offset_y) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+/**
+   @brief hal_filterFree
+   @param context pointer to user-defined context
+   @sa cv::filter2D, cv::hal::Filter2D
+ */
+inline int hal_ni_filterFree(cvhalFilter2D *context) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+
+//! @cond IGNORED
+#define cv_hal_filterInit hal_ni_filterInit
+#define cv_hal_filter hal_ni_filter
+#define cv_hal_filterFree hal_ni_filterFree
+//! @endcond
+
+/**
+   @brief hal_sepFilterInit
+   @param context double pointer to user-defined context
+   @param src_type source image type
+   @param dst_type destination image type
+   @param kernel_type kernels type
+   @param kernelx_data pointer to x-kernel data
+   @param kernelx_length x-kernel vector length
+   @param kernely_data pointer to y-kernel data
+   @param kernely_length y-kernel vector length
+   @param anchor_x relative X position of center point within the kernel
+   @param anchor_y relative Y position of center point within the kernel
+   @param delta added to pixel values
+   @param borderType border processing mode (CV_HAL_BORDER_REFLECT, ...)
+   @sa cv::sepFilter2D, cv::hal::SepFilter2D
+ */
+inline int hal_ni_sepFilterInit(cvhalFilter2D **context, int src_type, int dst_type, int kernel_type, uchar *kernelx_data, int kernelx_length, uchar *kernely_data, int kernely_length, int anchor_x, int anchor_y, double delta, int borderType) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+/**
+   @brief hal_sepFilter
+   @param context pointer to user-defined context
+   @param src_data source image data
+   @param src_step source image step
+   @param dst_data destination image data
+   @param dst_step destination image step
+   @param width images width
+   @param height images height
+   @param full_width full width of source image (outside the ROI)
+   @param full_height full height of source image (outside the ROI)
+   @param offset_x source image ROI offset X
+   @param offset_y source image ROI offset Y
+   @sa cv::sepFilter2D, cv::hal::SepFilter2D
+ */
+inline int hal_ni_sepFilter(cvhalFilter2D *context, uchar *src_data, size_t src_step, uchar* dst_data, size_t dst_step, int width, int height, int full_width, int full_height, int offset_x, int offset_y) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+/**
+   @brief hal_sepFilterFree
+   @param context pointer to user-defined context
+   @sa cv::sepFilter2D, cv::hal::SepFilter2D
+ */
+inline int hal_ni_sepFilterFree(cvhalFilter2D *context) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+
+//! @cond IGNORED
+#define cv_hal_sepFilterInit hal_ni_sepFilterInit
+#define cv_hal_sepFilter hal_ni_sepFilter
+#define cv_hal_sepFilterFree hal_ni_sepFilterFree
+//! @endcond
+
+/**
+   @brief hal_morphInit
+   @param context double pointer to user-defined context
+   @param operation morphology operation CV_HAL_MORPH_ERODE or CV_HAL_MORPH_DILATE
+   @param src_type source image type
+   @param dst_type destination image type
+   @param max_width max possible image width, can be used to allocate working buffers
+   @param max_height max possible image height
+   @param kernel_type kernel type (CV_8U, ...)
+   @param kernel_data pointer to kernel data
+   @param kernel_step kernel step
+   @param kernel_width kernel width
+   @param kernel_height kernel height
+   @param anchor_x relative X position of center point within the kernel
+   @param anchor_y relative Y position of center point within the kernel
+   @param borderType border processing mode (CV_HAL_BORDER_REFLECT, ...)
+   @param borderValue values to use for CV_HAL_BORDER_CONSTANT mode
+   @param iterations number of iterations
+   @param allowSubmatrix indicates whether the submatrices will be allowed as source image
+   @param allowInplace indicates whether the inplace operation will be possible
+   @sa cv::erode, cv::dilate, cv::morphologyEx, cv::hal::Morph
+ */
+inline int hal_ni_morphInit(cvhalFilter2D **context, int operation, int src_type, int dst_type, int max_width, int max_height, int kernel_type, uchar *kernel_data, size_t kernel_step, int kernel_width, int kernel_height, int anchor_x, int anchor_y, int borderType, const double borderValue[4], int iterations, bool allowSubmatrix, bool allowInplace) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+/**
+   @brief hal_morph
+   @param context pointer to user-defined context
+   @param src_data source image data
+   @param src_step source image step
+   @param dst_data destination image data
+   @param dst_step destination image step
+   @param width images width
+   @param height images height
+   @param src_full_width full width of source image (outside the ROI)
+   @param src_full_height full height of source image (outside the ROI)
+   @param src_roi_x source image ROI X offset
+   @param src_roi_y source image ROI Y offset
+   @param dst_full_width full width of destination image
+   @param dst_full_height full height of destination image
+   @param dst_roi_x destination image ROI X offset
+   @param dst_roi_y destination image ROI Y offset
+   @sa cv::erode, cv::dilate, cv::morphologyEx, cv::hal::Morph
+ */
+inline int hal_ni_morph(cvhalFilter2D *context, uchar *src_data, size_t src_step, uchar *dst_data, size_t dst_step, int width, int height, int src_full_width, int src_full_height, int src_roi_x, int src_roi_y, int dst_full_width, int dst_full_height, int dst_roi_x, int dst_roi_y) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+/**
+   @brief hal_morphFree
+   @param context pointer to user-defined context
+   @sa cv::erode, cv::dilate, cv::morphologyEx, cv::hal::Morph
+ */
+inline int hal_ni_morphFree(cvhalFilter2D *context) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+
+//! @cond IGNORED
+#define cv_hal_morphInit hal_ni_morphInit
+#define cv_hal_morph hal_ni_morph
+#define cv_hal_morphFree hal_ni_morphFree
+//! @endcond
+
+/**
+   @brief hal_resize
+   @param src_type source and destination image type
+   @param src_data source image data
+   @param src_step source image step
+   @param src_width source image width
+   @param src_height source image height
+   @param dst_data destination image data
+   @param dst_step destination image step
+   @param dst_width destination image width
+   @param dst_height destination image height
+   @param inv_scale_x inversed scale X coefficient
+   @param inv_scale_y inversed scale Y coefficient
+   @param interpolation interpolation mode (CV_HAL_INTER_NEAREST, ...)
+   @sa cv::resize, cv::hal::resize
+ */
+inline int hal_ni_resize(int src_type, const uchar *src_data, size_t src_step, int src_width, int src_height, uchar *dst_data, size_t dst_step, int dst_width, int dst_height, double inv_scale_x, double inv_scale_y, int interpolation) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+/**
+   @brief hal_warpAffine
+   @param src_type source and destination image type
+   @param src_data source image data
+   @param src_step source image step
+   @param src_width source image width
+   @param src_height source image height
+   @param dst_data destination image data
+   @param dst_step destination image step
+   @param dst_width destination image width
+   @param dst_height destination image height
+   @param M 2x3 matrix with transform coefficients
+   @param interpolation interpolation mode (CV_HAL_INTER_NEAREST, ...)
+   @param borderType border processing mode (CV_HAL_BORDER_REFLECT, ...)
+   @param borderValue values to use for CV_HAL_BORDER_CONSTANT mode
+   @sa cv::warpAffine, cv::hal::warpAffine
+ */
+inline int hal_ni_warpAffine(int src_type, const uchar *src_data, size_t src_step, int src_width, int src_height, uchar *dst_data, size_t dst_step, int dst_width, int dst_height, const double M[6], int interpolation, int borderType, const double borderValue[4]) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+/**
+   @brief hal_warpPerspectve
+   @param src_type source and destination image type
+   @param src_data source image data
+   @param src_step source image step
+   @param src_width source image width
+   @param src_height source image height
+   @param dst_data destination image data
+   @param dst_step destination image step
+   @param dst_width destination image width
+   @param dst_height destination image height
+   @param M 3x3 matrix with transform coefficients
+   @param interpolation interpolation mode (CV_HAL_INTER_NEAREST, ...)
+   @param borderType border processing mode (CV_HAL_BORDER_REFLECT, ...)
+   @param borderValue values to use for CV_HAL_BORDER_CONSTANT mode
+   @sa cv::warpPerspective, cv::hal::warpPerspective
+ */
+inline int hal_ni_warpPerspectve(int src_type, const uchar *src_data, size_t src_step, int src_width, int src_height, uchar *dst_data, size_t dst_step, int dst_width, int dst_height, const double M[9], int interpolation, int borderType, const double borderValue[4]) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+
+//! @cond IGNORED
+#define cv_hal_resize hal_ni_resize
+#define cv_hal_warpAffine hal_ni_warpAffine
+#define cv_hal_warpPerspective hal_ni_warpPerspectve
+//! @endcond
+
+/**
+   @brief hal_cvtBGRtoBGR
+   @param src_data,src_step source image data and step
+   @param dst_data,dst_step destination image data and step
+   @param width,height image size
+   @param depth image depth (one of CV_8U, CV_16U, CV_32F)
+   @param scn source image channels (3 or 4)
+   @param dcn destination image channels (3 or 4)
+   @param swapBlue if set to true B and R channels will be swapped (BGR->RGB or RGB->BGR)
+   Convert between BGR, BGRA, RGB and RGBA image formats.
+ */
+inline int hal_ni_cvtBGRtoBGR(const uchar * src_data, size_t src_step, uchar * dst_data, size_t dst_step, int width, int height, int depth, int scn, int dcn, bool swapBlue) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+
+/**
+   @brief hal_cvtBGRtoBGR5x5
+   @param src_data,src_step source image data and step
+   @param dst_data,dst_step destination image data and step
+   @param width,height image size
+   @param scn source image channels (3 or 4)
+   @param swapBlue if set to true B and R source channels will be swapped (treat as RGB)
+   @param greenBits number of bits for green channel (5 or 6)
+   Convert from BGR, BGRA, RGB and RGBA to packed BGR or RGB (16 bits per pixel, 555 or 565).
+   Support only CV_8U images (input 3 or 4 channels, output 2 channels).
+ */
+inline int hal_ni_cvtBGRtoBGR5x5(const uchar * src_data, size_t src_step, uchar * dst_data, size_t dst_step, int width, int height, int scn, bool swapBlue, int greenBits) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+
+/**
+   @brief hal_cvtBGR5x5toBGR
+   @param src_data,src_step source image data and step
+   @param dst_data,dst_step destination image data and step
+   @param width,height image size
+   @param dcn destination image channels (3 or 4)
+   @param swapBlue if set to true B and R destination channels will be swapped (write RGB)
+   @param greenBits number of bits for green channel (5 or 6)
+   Convert from packed BGR or RGB (16 bits per pixel, 555 or 565) to BGR, BGRA, RGB and RGBA.
+   Support only CV_8U images (input 2 channels, output 3 or 4 channels).
+ */
+inline int hal_ni_cvtBGR5x5toBGR(const uchar * src_data, size_t src_step, uchar * dst_data, size_t dst_step, int width, int height, int dcn, bool swapBlue, int greenBits) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+
+/**
+   @brief hal_cvtBGRtoGray
+   @param src_data,src_step source image data and step
+   @param dst_data,dst_step destination image data and step
+   @param width,height image size
+   @param depth image depth (one of CV_8U, CV_16U or CV_32F)
+   @param scn source image channels (3 or 4)
+   @param swapBlue if set to true B and R source channels will be swapped (treat as RGB)
+   Convert from BGR, BGRA, RGB or RGBA to 1-channel gray.
+ */
+inline int hal_ni_cvtBGRtoGray(const uchar * src_data, size_t src_step, uchar * dst_data, size_t dst_step, int width, int height, int depth, int scn, bool swapBlue) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+
+/**
+   @brief hal_cvtGraytoBGR
+   @param src_data,src_step source image data and step
+   @param dst_data,dst_step destination image data and step
+   @param width,height image size
+   @param depth image depth (one of CV_8U, CV_16U or CV_32F)
+   @param dcn destination image channels (3 or 4)
+   Convert from 1-channel gray to BGR, RGB, RGBA or BGRA.
+ */
+inline int hal_ni_cvtGraytoBGR(const uchar * src_data, size_t src_step, uchar * dst_data, size_t dst_step, int width, int height, int depth, int dcn) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+
+/**
+   @brief hal_cvtBGR5x5toGray
+   @param src_data,src_step source image data and step
+   @param dst_data,dst_step destination image data and step
+   @param width,height image size
+   @param greenBits number of bits for green channel (5 or 6)
+   Convert from packed BGR (16 bits per pixel, 555 or 565) to 1-channel gray.
+   Support only CV_8U images.
+ */
+inline int hal_ni_cvtBGR5x5toGray(const uchar * src_data, size_t src_step, uchar * dst_data, size_t dst_step, int width, int height, int greenBits) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+
+/**
+   @brief hal_cvtGraytoBGR5x5
+   @param src_data,src_step source image data and step
+   @param dst_data,dst_step destination image data and step
+   @param width,height image size
+   @param greenBits number of bits for green channel (5 or 6)
+   Convert from 1-channel gray to packed BGR (16 bits per pixel, 555 or 565).
+   Support only CV_8U images.
+ */
+inline int hal_ni_cvtGraytoBGR5x5(const uchar * src_data, size_t src_step, uchar * dst_data, size_t dst_step, int width, int height, int greenBits) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+
+/**
+   @brief hal_cvtBGRtoYUV
+   @param src_data,src_step source image data and step
+   @param dst_data,dst_step destination image data and step
+   @param width,height image size
+   @param depth image depth (one of CV_8U, CV_16U or CV_32F)
+   @param scn source image channels (3 or 4)
+   @param swapBlue if set to true B and R source channels will be swapped (treat as RGB)
+   @param isCbCr if set to true write output in YCbCr format
+   Convert from BGR, RGB, BGRA or RGBA to YUV or YCbCr.
+ */
+inline int hal_ni_cvtBGRtoYUV(const uchar * src_data, size_t src_step, uchar * dst_data, size_t dst_step, int width, int height, int depth, int scn, bool swapBlue, bool isCbCr) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+
+/**
+   @brief hal_cvtYUVtoBGR
+   @param src_data,src_step source image data and step
+   @param dst_data,dst_step destination image data and step
+   @param width,height image size
+   @param depth image depth (one of CV_8U, CV_16U or CV_32F)
+   @param dcn destination image channels (3 or 4)
+   @param swapBlue if set to true B and R destination channels will be swapped (write RGB)
+   @param isCbCr if set to true treat source as YCbCr
+   Convert from YUV or YCbCr to BGR, RGB, BGRA or RGBA.
+ */
+inline int hal_ni_cvtYUVtoBGR(const uchar * src_data, size_t src_step, uchar * dst_data, size_t dst_step, int width, int height, int depth, int dcn, bool swapBlue, bool isCbCr) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+
+/**
+   @brief hal_cvtBGRtoXYZ
+   @param src_data,src_step source image data and step
+   @param dst_data,dst_step destination image data and step
+   @param width,height image size
+   @param depth image depth (one of CV_8U, CV_16U or CV_32F)
+   @param scn source image channels (3 or 4)
+   @param swapBlue if set to true B and R source channels will be swapped (treat as RGB)
+   Convert from BGR, RGB, BGRA or RGBA to XYZ.
+ */
+inline int hal_ni_cvtBGRtoXYZ(const uchar * src_data, size_t src_step, uchar * dst_data, size_t dst_step, int width, int height, int depth, int scn, bool swapBlue) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+
+/**
+   @brief hal_cvtXYZtoBGR
+   @param src_data,src_step source image data and step
+   @param dst_data,dst_step destination image data and step
+   @param width,height image size
+   @param depth image depth (one of CV_8U, CV_16U or CV_32F)
+   @param dcn destination image channels (3 or 4)
+   @param swapBlue if set to true B and R destination channels will be swapped (write RGB)
+   Convert from XYZ to BGR, RGB, BGRA or RGBA.
+ */
+inline int hal_ni_cvtXYZtoBGR(const uchar * src_data, size_t src_step, uchar * dst_data, size_t dst_step, int width, int height, int depth, int dcn, bool swapBlue) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+
+/**
+   @brief hal_cvtBGRtoHSV
+   @param src_data,src_step source image data and step
+   @param dst_data,dst_step destination image data and step
+   @param width,height image size
+   @param depth image depth (one of CV_8U or CV_32F)
+   @param scn source image channels (3 or 4)
+   @param swapBlue if set to true B and R source channels will be swapped (treat as RGB)
+   @param isFullRange if set to true write hue in range 0-255 (0-360 for float) otherwise in range 0-180
+   @param isHSV if set to true write HSV otherwise HSL
+   Convert from BGR, RGB, BGRA or RGBA to HSV or HSL.
+ */
+inline int hal_ni_cvtBGRtoHSV(const uchar * src_data, size_t src_step, uchar * dst_data, size_t dst_step, int width, int height, int depth, int scn, bool swapBlue, bool isFullRange, bool isHSV) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+
+/**
+   @brief hal_cvtHSVtoBGR
+   @param src_data,src_step source image data and step
+   @param dst_data,dst_step destination image data and step
+   @param width,height image size
+   @param depth image depth (one of CV_8U or CV_32F)
+   @param dcn destination image channels (3 or 4)
+   @param swapBlue if set to true B and R destination channels will be swapped (write RGB)
+   @param isFullRange if set to true read hue in range 0-255 (0-360 for float) otherwise in range 0-180
+   @param isHSV if set to true treat source as HSV otherwise HSL
+   Convert from HSV or HSL to BGR, RGB, BGRA or RGBA.
+ */
+inline int hal_ni_cvtHSVtoBGR(const uchar * src_data, size_t src_step, uchar * dst_data, size_t dst_step, int width, int height, int depth, int dcn, bool swapBlue, bool isFullRange, bool isHSV) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+
+/**
+   @brief hal_cvtBGRtoLab
+   @param src_data,src_step source image data and step
+   @param dst_data,dst_step destination image data and step
+   @param width,height image size
+   @param depth image depth (one of CV_8U or CV_32F)
+   @param scn source image channels (3 or 4)
+   @param swapBlue if set to true B and R source channels will be swapped (treat as RGB)
+   @param isLab if set to true write Lab otherwise Luv
+   @param srgb if set to true use sRGB gamma correction
+   Convert from BGR, RGB, BGRA or RGBA to Lab or Luv.
+ */
+inline int hal_ni_cvtBGRtoLab(const uchar * src_data, size_t src_step, uchar * dst_data, size_t dst_step, int width, int height, int depth, int scn, bool swapBlue, bool isLab, bool srgb) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+
+/**
+   @brief hal_cvtLabtoBGR
+   @param src_data,src_step source image data and step
+   @param dst_data,dst_step destination image data and step
+   @param width,height image size
+   @param depth image depth (one of CV_8U or CV_32F)
+   @param dcn destination image channels (3 or 4)
+   @param swapBlue if set to true B and R destination channels will be swapped (write RGB)
+   @param isLab if set to true treat input as Lab otherwise Luv
+   @param srgb if set to true use sRGB gamma correction
+   Convert from Lab or Luv to BGR, RGB, BGRA or RGBA.
+ */
+inline int hal_ni_cvtLabtoBGR(const uchar * src_data, size_t src_step, uchar * dst_data, size_t dst_step, int width, int height, int depth, int dcn, bool swapBlue, bool isLab, bool srgb) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+
+/**
+   @brief hal_cvtTwoPlaneYUVtoBGR
+   @param src_data,src_step source image data and step
+   @param dst_data,dst_step destination image data and step
+   @param dst_width,dst_height destination image size
+   @param dcn destination image channels (3 or 4)
+   @param swapBlue if set to true B and R destination channels will be swapped (write RGB)
+   @param uIdx U-channel index in the interleaved U/V plane (0 or 1)
+   Convert from YUV (YUV420sp (or NV12/NV21) - Y plane followed by interleaved U/V plane) to BGR, RGB, BGRA or RGBA.
+   Only for CV_8U.
+ */
+inline int hal_ni_cvtTwoPlaneYUVtoBGR(const uchar * src_data, size_t src_step, uchar * dst_data, size_t dst_step, int dst_width, int dst_height, int dcn, bool swapBlue, int uIdx) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+
+/**
+   @brief hal_cvtThreePlaneYUVtoBGR
+   @param src_data,src_step source image data and step
+   @param dst_data,dst_step destination image data and step
+   @param dst_width,dst_height destination image size
+   @param dcn destination image channels (3 or 4)
+   @param swapBlue if set to true B and R destination channels will be swapped (write RGB)
+   @param uIdx U-channel plane index (0 or 1)
+   Convert from YUV (YUV420p (or YV12/YV21) - Y plane followed by U and V planes) to BGR, RGB, BGRA or RGBA.
+   Only for CV_8U.
+ */
+inline int hal_ni_cvtThreePlaneYUVtoBGR(const uchar * src_data, size_t src_step, uchar * dst_data, size_t dst_step, int dst_width, int dst_height, int dcn, bool swapBlue, int uIdx) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+
+/**
+   @brief hal_cvtBGRtoThreePlaneYUV
+   @param src_data,src_step source image data and step
+   @param dst_data,dst_step destination image data and step
+   @param width,height image size
+   @param scn source image channels (3 or 4)
+   @param swapBlue if set to true B and R source channels will be swapped (treat as RGB)
+   @param uIdx U-channel plane index (0 or 1)
+   Convert from BGR, RGB, BGRA or RGBA to YUV (YUV420p (or YV12/YV21) - Y plane followed by U and V planes).
+   Only for CV_8U.
+ */
+inline int hal_ni_cvtBGRtoThreePlaneYUV(const uchar * src_data, size_t src_step, uchar * dst_data, size_t dst_step, int width, int height, int scn, bool swapBlue, int uIdx) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+
+/**
+   @brief hal_cvtOnePlaneYUVtoBGR
+   @param src_data,src_step source image data and step
+   @param dst_data,dst_step destination image data and step
+   @param width,height image size
+   @param dcn destination image channels (3 or 4)
+   @param swapBlue if set to true B and R destination channels will be swapped (write RGB)
+   @param uIdx U-channel index (0 or 1)
+   @param ycn Y-channel index (0 or 1)
+   Convert from UYVY, YUY2 or YVYU to BGR, RGB, BGRA or RGBA.
+   Only for CV_8U.
+ */
+inline int hal_ni_cvtOnePlaneYUVtoBGR(const uchar * src_data, size_t src_step, uchar * dst_data, size_t dst_step, int width, int height, int dcn, bool swapBlue, int uIdx, int ycn) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+
+
+/**
+   @brief hal_cvtRGBAtoMultipliedRGBA
+   @param src_data,src_step source image data and step
+   @param dst_data,dst_step destination image data and step
+   @param width,height image size
+   Convert from BGRA or RGBA to format with multiplied alpha channel.
+   Only for CV_8U.
+ */
+inline int hal_ni_cvtRGBAtoMultipliedRGBA(const uchar * src_data, size_t src_step, uchar * dst_data, size_t dst_step, int width, int height) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+
+/**
+   @brief hal_cvtMultipliedRGBAtoRGBA
+   @param src_data,src_step source image data and step
+   @param dst_data,dst_step destination image data and step
+   @param width,height image size
+   Convert from format with multiplied alpha channel to BGRA or RGBA.
+   Only for CV_8U.
+ */
+inline int hal_ni_cvtMultipliedRGBAtoRGBA(const uchar * src_data, size_t src_step, uchar * dst_data, size_t dst_step, int width, int height) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+
+//! @cond IGNORED
+#define cv_hal_cvtBGRtoBGR hal_ni_cvtBGRtoBGR
+#define cv_hal_cvtBGRtoBGR5x5 hal_ni_cvtBGRtoBGR5x5
+#define cv_hal_cvtBGR5x5toBGR hal_ni_cvtBGR5x5toBGR
+#define cv_hal_cvtBGRtoGray hal_ni_cvtBGRtoGray
+#define cv_hal_cvtGraytoBGR hal_ni_cvtGraytoBGR
+#define cv_hal_cvtBGR5x5toGray hal_ni_cvtBGR5x5toGray
+#define cv_hal_cvtGraytoBGR5x5 hal_ni_cvtGraytoBGR5x5
+#define cv_hal_cvtBGRtoYUV hal_ni_cvtBGRtoYUV
+#define cv_hal_cvtYUVtoBGR hal_ni_cvtYUVtoBGR
+#define cv_hal_cvtBGRtoXYZ hal_ni_cvtBGRtoXYZ
+#define cv_hal_cvtXYZtoBGR hal_ni_cvtXYZtoBGR
+#define cv_hal_cvtBGRtoHSV hal_ni_cvtBGRtoHSV
+#define cv_hal_cvtHSVtoBGR hal_ni_cvtHSVtoBGR
+#define cv_hal_cvtBGRtoLab hal_ni_cvtBGRtoLab
+#define cv_hal_cvtLabtoBGR hal_ni_cvtLabtoBGR
+#define cv_hal_cvtTwoPlaneYUVtoBGR hal_ni_cvtTwoPlaneYUVtoBGR
+#define cv_hal_cvtThreePlaneYUVtoBGR hal_ni_cvtThreePlaneYUVtoBGR
+#define cv_hal_cvtBGRtoThreePlaneYUV hal_ni_cvtBGRtoThreePlaneYUV
+#define cv_hal_cvtOnePlaneYUVtoBGR hal_ni_cvtOnePlaneYUVtoBGR
+#define cv_hal_cvtRGBAtoMultipliedRGBA hal_ni_cvtRGBAtoMultipliedRGBA
+#define cv_hal_cvtMultipliedRGBAtoRGBA hal_ni_cvtMultipliedRGBAtoRGBA
+//! @endcond
+
+/**
+   @brief Calculate integral image
+   @param depth,sdepth,sqdepth Depths of source image, sum image and square sum image
+   @param src_data,src_step Source image
+   @param sum_data,sum_step Sum image
+   @param sqsum_data,sqsum_step Square sum image
+   @param tilted_data,tilted_step Tilted sum image
+   @param width,height Source image dimensions
+   @param cn Number of channels
+   @note Following combinations of image depths are used:
+   Source | Sum | Square sum
+   -------|-----|-----------
+   CV_8U | CV_32S | CV_64F
+   CV_8U | CV_32S | CV_32F
+   CV_8U | CV_32S | CV_32S
+   CV_8U | CV_32F | CV_64F
+   CV_8U | CV_32F | CV_32F
+   CV_8U | CV_64F | CV_64F
+   CV_16U | CV_64F | CV_64F
+   CV_16S | CV_64F | CV_64F
+   CV_32F | CV_32F | CV_64F
+   CV_32F | CV_32F | CV_32F
+   CV_32F | CV_64F | CV_64F
+   CV_64F | CV_64F | CV_64F
+   @sa cv::integral
+*/
+inline int hal_ni_integral(int depth, int sdepth, int sqdepth, const uchar * src_data, size_t src_step, uchar * sum_data, size_t sum_step, uchar * sqsum_data, size_t sqsum_step, uchar * tilted_data, size_t tilted_step, int width, int height, int cn) { return CV_HAL_ERROR_NOT_IMPLEMENTED; }
+
+//! @cond IGNORED
+#define cv_hal_integral hal_ni_integral
+//! @endcond
+
+//! @}
+
+#if defined __GNUC__
+#  pragma GCC diagnostic pop
+#elif defined _MSC_VER
+#  pragma warning( pop )
+#endif
+
+#include "custom_hal.hpp"
+
+//! @cond IGNORED
+#define CALL_HAL_RET(name, fun, retval, ...) \
+    int res = fun(__VA_ARGS__, &retval); \
+    if (res == CV_HAL_ERROR_OK) \
+        return retval; \
+    else if (res != CV_HAL_ERROR_NOT_IMPLEMENTED) \
+        CV_Error_(cv::Error::StsInternal, \
+            ("HAL implementation " CVAUX_STR(name) " ==> " CVAUX_STR(fun) " returned %d (0x%08x)", res, res));
+
+
+#define CALL_HAL(name, fun, ...) \
+    int res = fun(__VA_ARGS__); \
+    if (res == CV_HAL_ERROR_OK) \
+        return; \
+    else if (res != CV_HAL_ERROR_NOT_IMPLEMENTED) \
+        CV_Error_(cv::Error::StsInternal, \
+            ("HAL implementation " CVAUX_STR(name) " ==> " CVAUX_STR(fun) " returned %d (0x%08x)", res, res));
+//! @endcond
+
+#endif
diff --git a/modules/imgproc/src/histogram.cpp b/modules/imgproc/src/histogram.cpp
index 7e18168..235f347 100644
--- a/modules/imgproc/src/histogram.cpp
+++ b/modules/imgproc/src/histogram.cpp
@@ -42,6 +42,8 @@
 #include "precomp.hpp"
 #include "opencl_kernels_imgproc.hpp"
 
+#include "opencv2/core/openvx/ovx_defs.hpp"
+
 namespace cv
 {
 
@@ -1188,6 +1190,7 @@ public:
 
     virtual void operator() (const Range & range) const
     {
+        Ipp32s levelNum = histSize + 1;
         Mat phist(hist->size(), hist->type(), Scalar::all(0));
 #if IPP_VERSION_X100 >= 900
         IppiSize roi = {src->cols, range.end - range.start};
@@ -1196,7 +1199,7 @@ public:
         IppiHistogramSpec *pSpec = NULL;
         Ipp8u *pBuffer = NULL;
 
-        if(ippiHistogramGetBufferSize(ipp8u, roi, &histSize, 1, 1, &specSize, &bufferSize) < 0)
+        if(ippiHistogramGetBufferSize(ipp8u, roi, &levelNum, 1, 1, &specSize, &bufferSize) < 0)
         {
             *ok = false;
             return;
@@ -1217,7 +1220,7 @@ public:
             return;
         }
 
-        if(ippiHistogramUniformInit(ipp8u, (Ipp32f*)&low, (Ipp32f*)&high, (Ipp32s*)&histSize, 1, pSpec) < 0)
+        if(ippiHistogramUniformInit(ipp8u, (Ipp32f*)&low, (Ipp32f*)&high, (Ipp32s*)&levelNum, 1, pSpec) < 0)
         {
             if(pSpec)   ippFree(pSpec);
             if(pBuffer) ippFree(pBuffer);
@@ -1225,7 +1228,7 @@ public:
             return;
         }
 
-        IppStatus status = ippiHistogram_8u_C1R(src->ptr(range.start), (int)src->step, ippiSize(src->cols, range.end - range.start),
+        IppStatus status = CV_INSTRUMENT_FUN_IPP(ippiHistogram_8u_C1R, src->ptr(range.start), (int)src->step, ippiSize(src->cols, range.end - range.start),
             phist.ptr<Ipp32u>(), pSpec, pBuffer);
 
         if(pSpec)   ippFree(pSpec);
@@ -1233,7 +1236,7 @@ public:
 #else
         CV_SUPPRESS_DEPRECATED_START
         IppStatus status = ippiHistogramEven_8u_C1R(src->ptr(range.start), (int)src->step, ippiSize(src->cols, range.end - range.start),
-            phist.ptr<Ipp32s>(), (Ipp32s*)(Ipp32f*)*levels, histSize, (Ipp32s)low, (Ipp32s)high);
+            phist.ptr<Ipp32s>(), (Ipp32s*)(Ipp32f*)*levels, levelNum, (Ipp32s)low, (Ipp32s)high);
         CV_SUPPRESS_DEPRECATED_END
 #endif
         if(status < 0)
@@ -1261,6 +1264,61 @@ private:
 
 }
 
+#ifdef HAVE_OPENVX
+namespace cv
+{
+    static bool openvx_calchist(const Mat& image, OutputArray _hist, const int histSize,
+        const float* _range)
+    {
+        vx_int32 offset = (vx_int32)(_range[0]);
+        vx_uint32 range = (vx_uint32)(_range[1] - _range[0]);
+        if (float(offset) != _range[0] || float(range) != (_range[1] - _range[0]))
+            return false;
+
+        size_t total_size = image.total();
+        int rows = image.dims > 1 ? image.size[0] : 1, cols = rows ? (int)(total_size / rows) : 0;
+        if (image.dims > 2 && !(image.isContinuous() && cols > 0 && (size_t)rows*cols == total_size))
+            return false;
+
+        try
+        {
+            ivx::Context ctx = ivx::Context::create();
+#if VX_VERSION <= VX_VERSION_1_0
+            if (ctx.vendorID() == VX_ID_KHRONOS && (range % histSize))
+                return false;
+#endif
+
+            ivx::Image
+                img = ivx::Image::createFromHandle(ctx, VX_DF_IMAGE_U8,
+                    ivx::Image::createAddressing(cols, rows, 1, (vx_int32)(image.step[0])), image.data);
+
+            ivx::Distribution vxHist = ivx::Distribution::create(ctx, histSize, offset, range);
+            ivx::IVX_CHECK_STATUS(vxuHistogram(ctx, img, vxHist));
+
+            _hist.create(1, &histSize, CV_32F);
+            Mat hist = _hist.getMat(), ihist = hist;
+            ihist.flags = (ihist.flags & ~CV_MAT_TYPE_MASK) | CV_32S;
+            vxHist.copyTo(ihist);
+            ihist.convertTo(hist, CV_32F);
+
+#ifdef VX_VERSION_1_1
+            img.swapHandle();
+#endif
+        }
+        catch (ivx::RuntimeError & e)
+        {
+            VX_DbgThrow(e.what());
+        }
+        catch (ivx::WrapperError & e)
+        {
+            VX_DbgThrow(e.what());
+        }
+
+        return true;
+    }
+}
+#endif
+
 #if defined(HAVE_IPP)
 namespace cv
 {
@@ -1268,6 +1326,8 @@ static bool ipp_calchist(const Mat* images, int nimages, const int* channels,
                    InputArray _mask, OutputArray _hist, int dims, const int* histSize,
                    const float** ranges, bool uniform, bool accumulate )
 {
+    CV_INSTRUMENT_REGION_IPP()
+
     Mat mask = _mask.getMat();
 
     CV_Assert(dims > 0 && histSize);
@@ -1282,7 +1342,7 @@ static bool ipp_calchist(const Mat* images, int nimages, const int* channels,
                 !accumulate && uniform)
         {
             ihist.setTo(Scalar::all(0));
-            AutoBuffer<Ipp32f> levels(histSize[0] + 1);
+            AutoBuffer<Ipp32f> levels(histSize[0]);
 
             bool ok = true;
             const Mat & src = images[0];
@@ -1290,7 +1350,7 @@ static bool ipp_calchist(const Mat* images, int nimages, const int* channels,
 #ifdef HAVE_CONCURRENCY
             nstripes = 1;
 #endif
-            IPPCalcHistInvoker invoker(src, ihist, levels, histSize[0] + 1, ranges[0][0], ranges[0][1], &ok);
+            IPPCalcHistInvoker invoker(src, ihist, levels, histSize[0], ranges[0][0], ranges[0][1], &ok);
             Range range(0, src.rows);
             parallel_for_(range, invoker, nstripes);
 
@@ -1310,6 +1370,14 @@ void cv::calcHist( const Mat* images, int nimages, const int* channels,
                    InputArray _mask, OutputArray _hist, int dims, const int* histSize,
                    const float** ranges, bool uniform, bool accumulate )
 {
+    CV_INSTRUMENT_REGION()
+
+    CV_OVX_RUN(
+        images && histSize &&
+        nimages == 1 && images[0].type() == CV_8UC1 && dims == 1 && _mask.getMat().empty() &&
+        (!channels || channels[0] == 0) && !accumulate && uniform &&
+        ranges && ranges[0],
+        openvx_calchist(images[0], _hist, histSize[0], ranges[0]))
 
     CV_IPP_RUN(nimages == 1 && images[0].type() == CV_8UC1 && dims == 1 && channels &&
                 channels[0] == 0 && _mask.getMat().empty() && images[0].dims <= 2 &&
@@ -1601,6 +1669,8 @@ void cv::calcHist( const Mat* images, int nimages, const int* channels,
                InputArray _mask, SparseMat& hist, int dims, const int* histSize,
                const float** ranges, bool uniform, bool accumulate )
 {
+    CV_INSTRUMENT_REGION()
+
     Mat mask = _mask.getMat();
     calcHist( images, nimages, channels, mask, hist, dims, histSize,
               ranges, uniform, accumulate, false );
@@ -1613,6 +1683,8 @@ void cv::calcHist( InputArrayOfArrays images, const std::vector<int>& channels,
                    const std::vector<float>& ranges,
                    bool accumulate )
 {
+    CV_INSTRUMENT_REGION()
+
     CV_OCL_RUN(images.total() == 1 && channels.size() == 1 && images.channels(0) == 1 &&
                channels[0] == 0 && images.isUMatVector() && mask.empty() && !accumulate &&
                histSize.size() == 1 && histSize[0] == BINS && ranges.size() == 2 &&
@@ -1940,6 +2012,8 @@ void cv::calcBackProject( const Mat* images, int nimages, const int* channels,
                           InputArray _hist, OutputArray _backProject,
                           const float** ranges, double scale, bool uniform )
 {
+    CV_INSTRUMENT_REGION()
+
     Mat hist = _hist.getMat();
     std::vector<uchar*> ptrs;
     std::vector<int> deltas;
@@ -2103,6 +2177,8 @@ void cv::calcBackProject( const Mat* images, int nimages, const int* channels,
                           const SparseMat& hist, OutputArray _backProject,
                           const float** ranges, double scale, bool uniform )
 {
+    CV_INSTRUMENT_REGION()
+
     std::vector<uchar*> ptrs;
     std::vector<int> deltas;
     std::vector<double> uniranges;
@@ -2282,6 +2358,8 @@ void cv::calcBackProject( InputArrayOfArrays images, const std::vector<int>& cha
                           const std::vector<float>& ranges,
                           double scale )
 {
+    CV_INSTRUMENT_REGION()
+
 #ifdef HAVE_OPENCL
     Size histSize = hist.size();
     bool _1D = histSize.height == 1 || histSize.width == 1;
@@ -2334,6 +2412,8 @@ void cv::calcBackProject( InputArrayOfArrays images, const std::vector<int>& cha
 
 double cv::compareHist( InputArray _H1, InputArray _H2, int method )
 {
+    CV_INSTRUMENT_REGION()
+
     Mat H1 = _H1.getMat(), H2 = _H2.getMat();
     const Mat* arrays[] = {&H1, &H2, 0};
     Mat planes[2];
@@ -2540,6 +2620,8 @@ double cv::compareHist( InputArray _H1, InputArray _H2, int method )
 
 double cv::compareHist( const SparseMat& H1, const SparseMat& H2, int method )
 {
+    CV_INSTRUMENT_REGION()
+
     double result = 0;
     int i, dims = H1.dims();
 
@@ -3682,8 +3764,47 @@ static bool ocl_equalizeHist(InputArray _src, OutputArray _dst)
 
 #endif
 
+#ifdef HAVE_OPENVX
+namespace cv
+{
+static bool openvx_equalize_hist(Mat srcMat, Mat dstMat)
+{
+    using namespace ivx;
+
+    try
+    {
+        Context context = Context::create();
+        Image srcImage = Image::createFromHandle(context, Image::matTypeToFormat(srcMat.type()),
+                                                 Image::createAddressing(srcMat), srcMat.data);
+        Image dstImage = Image::createFromHandle(context, Image::matTypeToFormat(dstMat.type()),
+                                                 Image::createAddressing(dstMat), dstMat.data);
+
+        IVX_CHECK_STATUS(vxuEqualizeHist(context, srcImage, dstImage));
+
+#ifdef VX_VERSION_1_1
+        //we should take user memory back before release
+        //(it's not done automatically according to standard)
+        srcImage.swapHandle(); dstImage.swapHandle();
+#endif
+    }
+    catch (RuntimeError & e)
+    {
+        VX_DbgThrow(e.what());
+    }
+    catch (WrapperError & e)
+    {
+        VX_DbgThrow(e.what());
+    }
+
+    return true;
+}
+}
+#endif
+
 void cv::equalizeHist( InputArray _src, OutputArray _dst )
 {
+    CV_INSTRUMENT_REGION()
+
     CV_Assert( _src.type() == CV_8UC1 );
 
     if (_src.empty())
@@ -3696,6 +3817,9 @@ void cv::equalizeHist( InputArray _src, OutputArray _dst )
     _dst.create( src.size(), src.type() );
     Mat dst = _dst.getMat();
 
+    CV_OVX_RUN(true,
+               openvx_equalize_hist(src, dst))
+
     Mutex histogramLockInstance;
 
     const int hist_sz = EqualizeHistCalcHist_Invoker::HIST_SZ;
diff --git a/modules/imgproc/src/hough.cpp b/modules/imgproc/src/hough.cpp
index e77544e..13c11db 100644
--- a/modules/imgproc/src/hough.cpp
+++ b/modules/imgproc/src/hough.cpp
@@ -96,7 +96,7 @@ HoughLinesStandard( const Mat& img, float rho, float theta,
     int numangle = cvRound((max_theta - min_theta) / theta);
     int numrho = cvRound(((width + height) * 2 + 1) / rho);
 
-#if defined HAVE_IPP && !defined(HAVE_IPP_ICV_ONLY) && IPP_VERSION_X100 >= 810 && IPP_DISABLE_BLOCK
+#if defined HAVE_IPP && IPP_VERSION_X100 >= 810 && IPP_DISABLE_BLOCK
     CV_IPP_CHECK()
     {
         IppiSize srcSize = { width, height };
@@ -109,7 +109,7 @@ HoughLinesStandard( const Mat& img, float rho, float theta,
         lines.resize(ipp_linesMax);
         IppStatus ok = ippiHoughLineGetSize_8u_C1R(srcSize, delta, ipp_linesMax, &bufferSize);
         Ipp8u* buffer = ippsMalloc_8u(bufferSize);
-        if (ok >= 0) ok = ippiHoughLine_Region_8u32f_C1R(image, step, srcSize, (IppPointPolar*) &lines[0], dstRoi, ipp_linesMax, &linesCount, delta, threshold, buffer);
+        if (ok >= 0) {ok = CV_INSTRUMENT_FUN_IPP(ippiHoughLine_Region_8u32f_C1R,(image, step, srcSize, (IppPointPolar*) &lines[0], dstRoi, ipp_linesMax, &linesCount, delta, threshold, buffer))};
         ippsFree(buffer);
         if (ok >= 0)
         {
@@ -429,7 +429,7 @@ HoughLinesProbabilistic( Mat& image,
     int numangle = cvRound(CV_PI / theta);
     int numrho = cvRound(((width + height) * 2 + 1) / rho);
 
-#if defined HAVE_IPP && !defined(HAVE_IPP_ICV_ONLY) && IPP_VERSION_X100 >= 810 && IPP_DISABLE_BLOCK
+#if defined HAVE_IPP && IPP_VERSION_X100 >= 810 && IPP_DISABLE_BLOCK
     CV_IPP_CHECK()
     {
         IppiSize srcSize = { width, height };
@@ -443,7 +443,7 @@ HoughLinesProbabilistic( Mat& image,
         Ipp8u* buffer = ippsMalloc_8u(bufferSize);
         pSpec = (IppiHoughProbSpec*) malloc(specSize);
         if (ok >= 0) ok = ippiHoughProbLineInit_8u32f_C1R(srcSize, delta, ippAlgHintNone, pSpec);
-        if (ok >= 0) ok = ippiHoughProbLine_8u32f_C1R(image.data, image.step, srcSize, threshold, lineLength, lineGap, (IppiPoint*) &lines[0], ipp_linesMax, &linesCount, buffer, pSpec);
+        if (ok >= 0) {ok = CV_INSTRUMENT_FUN_IPP(ippiHoughProbLine_8u32f_C1R,(image.data, image.step, srcSize, threshold, lineLength, lineGap, (IppiPoint*) &lines[0], ipp_linesMax, &linesCount, buffer, pSpec))};
 
         free(pSpec);
         ippsFree(buffer);
@@ -850,6 +850,8 @@ void cv::HoughLines( InputArray _image, OutputArray _lines,
                     double rho, double theta, int threshold,
                     double srn, double stn, double min_theta, double max_theta )
 {
+    CV_INSTRUMENT_REGION()
+
     CV_OCL_RUN(srn == 0 && stn == 0 && _image.isUMat() && _lines.isUMat(),
                ocl_HoughLines(_image, _lines, rho, theta, threshold, min_theta, max_theta));
 
@@ -869,6 +871,8 @@ void cv::HoughLinesP(InputArray _image, OutputArray _lines,
                      double rho, double theta, int threshold,
                      double minLineLength, double maxGap )
 {
+    CV_INSTRUMENT_REGION()
+
     CV_OCL_RUN(_image.isUMat() && _lines.isUMat(),
                ocl_HoughLinesP(_image, _lines, rho, theta, threshold, minLineLength, maxGap));
 
@@ -1322,6 +1326,8 @@ void cv::HoughCircles( InputArray _image, OutputArray _circles,
                        double param1, double param2,
                        int minRadius, int maxRadius )
 {
+    CV_INSTRUMENT_REGION()
+
     Ptr<CvMemStorage> storage(cvCreateMemStorage(STORAGE_SIZE));
     Mat image = _image.getMat();
     CvMat c_image = image;
diff --git a/modules/imgproc/src/imgwarp.cpp b/modules/imgproc/src/imgwarp.cpp
index 5822726..0fa5202 100644
--- a/modules/imgproc/src/imgwarp.cpp
+++ b/modules/imgproc/src/imgwarp.cpp
@@ -49,6 +49,11 @@
 
 #include "precomp.hpp"
 #include "opencl_kernels_imgproc.hpp"
+#include "hal_replacement.hpp"
+
+#include "opencv2/core/openvx/ovx_defs.hpp"
+
+using namespace cv;
 
 namespace cv
 {
@@ -66,6 +71,8 @@ namespace cv
     template <int channels, typename Type>
     bool IPPSetSimple(cv::Scalar value, void *dataPointer, int step, IppiSize &size, ippiSetFunc func)
     {
+        CV_INSTRUMENT_REGION_IPP()
+
         Type values[channels];
         for( int i = 0; i < channels; i++ )
             values[i] = saturate_cast<Type>(value[i]);
@@ -74,16 +81,18 @@ namespace cv
 
     static bool IPPSet(const cv::Scalar &value, void *dataPointer, int step, IppiSize &size, int channels, int depth)
     {
+        CV_INSTRUMENT_REGION_IPP()
+
         if( channels == 1 )
         {
             switch( depth )
             {
             case CV_8U:
-                return ippiSet_8u_C1R(saturate_cast<Ipp8u>(value[0]), (Ipp8u *)dataPointer, step, size) >= 0;
+                return CV_INSTRUMENT_FUN_IPP(ippiSet_8u_C1R,(saturate_cast<Ipp8u>(value[0]), (Ipp8u *)dataPointer, step, size)) >= 0;
             case CV_16U:
-                return ippiSet_16u_C1R(saturate_cast<Ipp16u>(value[0]), (Ipp16u *)dataPointer, step, size) >= 0;
+                return CV_INSTRUMENT_FUN_IPP(ippiSet_16u_C1R,(saturate_cast<Ipp16u>(value[0]), (Ipp16u *)dataPointer, step, size)) >= 0;
             case CV_32F:
-                return ippiSet_32f_C1R(saturate_cast<Ipp32f>(value[0]), (Ipp32f *)dataPointer, step, size) >= 0;
+                return CV_INSTRUMENT_FUN_IPP(ippiSet_32f_C1R,(saturate_cast<Ipp32f>(value[0]), (Ipp32f *)dataPointer, step, size)) >= 0;
             }
         }
         else
@@ -2709,7 +2718,7 @@ static int computeResizeAreaTab( int ssize, int dsize, int cn, double scale, Dec
 #define CHECK_IPP_STATUS(STATUS) if (STATUS < 0) { *ok = false; return; }
 
 #define SET_IPP_RESIZE_LINEAR_FUNC_PTR(TYPE, CN) \
-    func = (ippiResizeFunc)ippiResizeLinear_##TYPE##_##CN##R; \
+    ippiResize = (ippiResizeFunc)ippiResizeLinear_##TYPE##_##CN##R; \
     CHECK_IPP_STATUS(ippiResizeGetSize_##TYPE(srcSize, dstSize, (IppiInterpolationType)mode, 0, &specSize, &initSize));\
     specBuf.allocate(specSize);\
     pSpec = (uchar*)specBuf;\
@@ -2717,7 +2726,7 @@ static int computeResizeAreaTab( int ssize, int dsize, int cn, double scale, Dec
 
 #define SET_IPP_RESIZE_LINEAR_FUNC_64_PTR(TYPE, CN) \
     if (mode == (int)ippCubic) { *ok = false; return; } \
-    func = (ippiResizeFunc)ippiResizeLinear_##TYPE##_##CN##R; \
+    ippiResize = (ippiResizeFunc)ippiResizeLinear_##TYPE##_##CN##R; \
     CHECK_IPP_STATUS(ippiResizeGetSize_##TYPE(srcSize, dstSize, (IppiInterpolationType)mode, 0, &specSize, &initSize));\
     specBuf.allocate(specSize);\
     pSpec = (uchar*)specBuf;\
@@ -2726,7 +2735,7 @@ static int computeResizeAreaTab( int ssize, int dsize, int cn, double scale, Dec
     getSrcOffsetFunc =  (ippiResizeGetSrcOffset) ippiResizeGetSrcOffset_##TYPE;
 
 #define SET_IPP_RESIZE_CUBIC_FUNC_PTR(TYPE, CN) \
-    func = (ippiResizeFunc)ippiResizeCubic_##TYPE##_##CN##R; \
+    ippiResize = (ippiResizeFunc)ippiResizeCubic_##TYPE##_##CN##R; \
     CHECK_IPP_STATUS(ippiResizeGetSize_##TYPE(srcSize, dstSize, (IppiInterpolationType)mode, 0, &specSize, &initSize));\
     specBuf.allocate(specSize);\
     pSpec = (uchar*)specBuf;\
@@ -2749,7 +2758,7 @@ public:
     IPPresizeInvoker(const Mat & _src, Mat & _dst, double _inv_scale_x, double _inv_scale_y, int _mode, bool *_ok) :
         ParallelLoopBody(), src(_src), dst(_dst), inv_scale_x(_inv_scale_x),
         inv_scale_y(_inv_scale_y), pSpec(NULL), mode(_mode),
-        func(NULL), getBufferSizeFunc(NULL), getSrcOffsetFunc(NULL), ok(_ok)
+        ippiResize(NULL), getBufferSizeFunc(NULL), getSrcOffsetFunc(NULL), ok(_ok)
     {
         *ok = true;
         IppiSize srcSize, dstSize;
@@ -2809,7 +2818,7 @@ public:
         AutoBuffer<uchar> buf(bufsize + 64);
         uchar* bufptr = alignPtr((uchar*)buf, 32);
 
-        if( func( pSrc, (int)src.step[0], pDst, (int)dst.step[0], dstOffset, dstSize, ippBorderRepl, 0, pSpec, bufptr ) < 0 )
+        if( CV_INSTRUMENT_FUN_IPP(ippiResize, pSrc, (int)src.step[0], pDst, (int)dst.step[0], dstOffset, dstSize, ippBorderRepl, 0, pSpec, bufptr) < 0 )
             *ok = false;
         else
         {
@@ -2824,7 +2833,7 @@ private:
     void *pSpec;
     AutoBuffer<uchar> specBuf;
     int mode;
-    ippiResizeFunc func;
+    ippiResizeFunc ippiResize;
     ippiResizeGetBufferSize getBufferSizeFunc;
     ippiResizeGetSrcOffset getSrcOffsetFunc;
     bool *ok;
@@ -3089,9 +3098,11 @@ static bool ocl_resize( InputArray _src, OutputArray _dst, Size dsize,
 #endif
 
 #if IPP_VERSION_X100 >= 710
-static bool ipp_resize_mt(    Mat src, Mat dst,
-                        double inv_scale_x, double inv_scale_y, int interpolation)
+static bool ipp_resize_mt(Mat & src, Mat & dst,
+                          double inv_scale_x, double inv_scale_y, int interpolation)
 {
+    CV_INSTRUMENT_REGION_IPP()
+
     int mode = -1;
     if (interpolation == INTER_LINEAR && src.rows >= 2 && src.cols >= 2)
         mode = ippLinear;
@@ -3111,15 +3122,26 @@ static bool ipp_resize_mt(    Mat src, Mat dst,
 }
 #endif
 
-}
+//==================================================================================================
 
+namespace hal {
 
+void resize(int src_type,
+            const uchar * src_data, size_t src_step, int src_width, int src_height,
+            uchar * dst_data, size_t dst_step, int dst_width, int dst_height,
+            double inv_scale_x, double inv_scale_y, int interpolation)
+{
+    CV_INSTRUMENT_REGION()
 
-//////////////////////////////////////////////////////////////////////////////////////////
+    CV_Assert((dst_width * dst_height > 0) || (inv_scale_x > 0 && inv_scale_y > 0));
+    if (inv_scale_x < DBL_EPSILON || inv_scale_y < DBL_EPSILON)
+    {
+        inv_scale_x = static_cast<double>(dst_width) / src_width;
+        inv_scale_y = static_cast<double>(dst_height) / src_height;
+    }
+
+    CALL_HAL(resize, cv_hal_resize, src_type, src_data, src_step, src_width, src_height, dst_data, dst_step, dst_width, dst_height, inv_scale_x, inv_scale_y, interpolation);
 
-void cv::resize( InputArray _src, OutputArray _dst, Size dsize,
-                 double inv_scale_x, double inv_scale_y, int interpolation )
-{
     static ResizeFunc linear_tab[] =
     {
         resizeGeneric_<
@@ -3224,24 +3246,7 @@ void cv::resize( InputArray _src, OutputArray _dst, Size dsize,
         resizeArea_<double, double>, 0
     };
 
-    Size ssize = _src.size();
-
-    CV_Assert( ssize.area() > 0 );
-    CV_Assert( dsize.area() > 0 || (inv_scale_x > 0 && inv_scale_y > 0) );
-    if( dsize.area() == 0 )
-    {
-        dsize = Size(saturate_cast<int>(ssize.width*inv_scale_x),
-                     saturate_cast<int>(ssize.height*inv_scale_y));
-        CV_Assert( dsize.area() > 0 );
-    }
-    else
-    {
-        inv_scale_x = (double)dsize.width/ssize.width;
-        inv_scale_y = (double)dsize.height/ssize.height;
-    }
-
-
-    int type = _src.type(), depth = CV_MAT_DEPTH(type), cn = CV_MAT_CN(type);
+    int depth = CV_MAT_DEPTH(src_type), cn = CV_MAT_CN(src_type);
     double scale_x = 1./inv_scale_x, scale_y = 1./inv_scale_y;
 
     int iscale_x = saturate_cast<int>(scale_x);
@@ -3250,42 +3255,30 @@ void cv::resize( InputArray _src, OutputArray _dst, Size dsize,
     bool is_area_fast = std::abs(scale_x - iscale_x) < DBL_EPSILON &&
             std::abs(scale_y - iscale_y) < DBL_EPSILON;
 
+    Size dsize = Size(saturate_cast<int>(src_width*inv_scale_x),
+                      saturate_cast<int>(src_height*inv_scale_y));
+    CV_Assert( dsize.area() > 0 );
 
-    CV_OCL_RUN(_src.dims() <= 2 && _dst.isUMat() && _src.cols() > 10 && _src.rows() > 10,
-               ocl_resize(_src, _dst, dsize, inv_scale_x, inv_scale_y, interpolation))
-
-    Mat src = _src.getMat();
-    _dst.create(dsize, src.type());
-    Mat dst = _dst.getMat();
-
-    if (dsize == ssize) {
-      // Source and destination are of same size. Use simple copy.
-      src.copyTo(dst);
-      return;
-    }
-
-#ifdef HAVE_TEGRA_OPTIMIZATION
-    if (tegra::useTegra() && tegra::resize(src, dst, (float)inv_scale_x, (float)inv_scale_y, interpolation))
-        return;
-#endif
+    Mat src(Size(src_width, src_height), src_type, const_cast<uchar*>(src_data), src_step);
+    Mat dst(dsize, src_type, dst_data, dst_step);
 
 #ifdef HAVE_IPP
     int mode = -1;
-    if (interpolation == INTER_LINEAR && _src.rows() >= 2 && _src.cols() >= 2)
+    if (interpolation == INTER_LINEAR && src_height >= 2 && src_width >= 2)
         mode = INTER_LINEAR;
-    else if (interpolation == INTER_CUBIC && _src.rows() >= 4 && _src.cols() >= 4)
+    else if (interpolation == INTER_CUBIC && src_height >= 4 && src_width >= 4)
         mode = INTER_CUBIC;
 
     const double IPP_RESIZE_EPS = 1e-10;
-    double ex = fabs((double)dsize.width / _src.cols()  - inv_scale_x) / inv_scale_x;
-    double ey = fabs((double)dsize.height / _src.rows() - inv_scale_y) / inv_scale_y;
+    double ex = fabs((double)dsize.width / src_width  - inv_scale_x) / inv_scale_x;
+    double ey = fabs((double)dsize.height / src_height - inv_scale_y) / inv_scale_y;
 #endif
     CV_IPP_RUN(IPP_VERSION_X100 >= 710 && ((ex < IPP_RESIZE_EPS && ey < IPP_RESIZE_EPS && depth != CV_64F) || (ex == 0 && ey == 0 && depth == CV_64F)) &&
         (interpolation == INTER_LINEAR || interpolation == INTER_CUBIC) &&
         !(interpolation == INTER_LINEAR && is_area_fast && iscale_x == 2 && iscale_y == 2 && depth == CV_8U) &&
         mode >= 0 && (cn == 1 || cn == 3 || cn == 4) && (depth == CV_16U || depth == CV_16S || depth == CV_32F ||
-        (depth == CV_64F && mode == INTER_LINEAR)), ipp_resize_mt(src, dst, inv_scale_x, inv_scale_y, interpolation))
-
+        (depth == CV_64F && mode == INTER_LINEAR)),
+        ipp_resize_mt(src, dst, inv_scale_x, inv_scale_y, interpolation))
 
     if( interpolation == INTER_NEAREST )
     {
@@ -3309,7 +3302,7 @@ void cv::resize( InputArray _src, OutputArray _dst, Size dsize,
             if( is_area_fast )
             {
                 int area = iscale_x*iscale_y;
-                size_t srcstep = src.step / src.elemSize1();
+                size_t srcstep = src_step / src.elemSize1();
                 AutoBuffer<int> _ofs(area + dsize.width*cn);
                 int* ofs = _ofs;
                 int* xofs = ofs + area;
@@ -3335,11 +3328,11 @@ void cv::resize( InputArray _src, OutputArray _dst, Size dsize,
             ResizeAreaFunc func = area_tab[depth];
             CV_Assert( func != 0 && cn <= 4 );
 
-            AutoBuffer<DecimateAlpha> _xytab((ssize.width + ssize.height)*2);
-            DecimateAlpha* xtab = _xytab, *ytab = xtab + ssize.width*2;
+            AutoBuffer<DecimateAlpha> _xytab((src_width + src_height)*2);
+            DecimateAlpha* xtab = _xytab, *ytab = xtab + src_width*2;
 
-            int xtab_size = computeResizeAreaTab(ssize.width, dsize.width, cn, scale_x, xtab);
-            int ytab_size = computeResizeAreaTab(ssize.height, dsize.height, 1, scale_y, ytab);
+            int xtab_size = computeResizeAreaTab(src_width, dsize.width, cn, scale_x, xtab);
+            int ytab_size = computeResizeAreaTab(src_height, dsize.height, 1, scale_y, ytab);
 
             AutoBuffer<int> _tabofs(dsize.height + 1);
             int* tabofs = _tabofs;
@@ -3407,11 +3400,11 @@ void cv::resize( InputArray _src, OutputArray _dst, Size dsize,
                 fx = 0, sx = 0;
         }
 
-        if( sx + ksize2 >= ssize.width )
+        if( sx + ksize2 >= src_width )
         {
             xmax = std::min( xmax, dx );
-            if( sx >= ssize.width-1 && (interpolation != INTER_CUBIC && interpolation != INTER_LANCZOS4))
-                fx = 0, sx = ssize.width-1;
+            if( sx >= src_width-1 && (interpolation != INTER_CUBIC && interpolation != INTER_LANCZOS4))
+                fx = 0, sx = src_width-1;
         }
 
         for( k = 0, sx *= cn; k < cn; k++ )
@@ -3484,6 +3477,49 @@ void cv::resize( InputArray _src, OutputArray _dst, Size dsize,
           fixpt ? (void*)ibeta : (void*)beta, xmin, xmax, ksize );
 }
 
+} // cv::hal::
+} // cv::
+
+//==================================================================================================
+
+void cv::resize( InputArray _src, OutputArray _dst, Size dsize,
+                 double inv_scale_x, double inv_scale_y, int interpolation )
+{
+    CV_INSTRUMENT_REGION()
+
+    Size ssize = _src.size();
+
+    CV_Assert( ssize.width > 0 && ssize.height > 0 );
+    CV_Assert( dsize.area() > 0 || (inv_scale_x > 0 && inv_scale_y > 0) );
+    if( dsize.area() == 0 )
+    {
+        dsize = Size(saturate_cast<int>(ssize.width*inv_scale_x),
+                     saturate_cast<int>(ssize.height*inv_scale_y));
+        CV_Assert( dsize.area() > 0 );
+    }
+    else
+    {
+        inv_scale_x = (double)dsize.width/ssize.width;
+        inv_scale_y = (double)dsize.height/ssize.height;
+    }
+
+    CV_OCL_RUN(_src.dims() <= 2 && _dst.isUMat() && _src.cols() > 10 && _src.rows() > 10,
+               ocl_resize(_src, _dst, dsize, inv_scale_x, inv_scale_y, interpolation))
+
+    Mat src = _src.getMat();
+    _dst.create(dsize, src.type());
+    Mat dst = _dst.getMat();
+
+    if (dsize == ssize)
+    {
+        // Source and destination are of same size. Use simple copy.
+        src.copyTo(dst);
+        return;
+    }
+
+    hal::resize(src.type(), src.data, src.step, src.cols, src.rows, dst.data, dst.step, dst.cols, dst.rows, inv_scale_x, inv_scale_y, interpolation);
+}
+
 
 /****************************************************************************************\
 *                       General warping (affine, perspective, remap)                     *
@@ -4576,9 +4612,235 @@ static bool ocl_remap(InputArray _src, OutputArray _dst, InputArray _map1, Input
     return k.run(2, globalThreads, NULL, false);
 }
 
+static bool ocl_linearPolar(InputArray _src, OutputArray _dst,
+    Point2f center, double maxRadius, int flags)
+{
+    UMat src_with_border; // don't scope this variable (it holds image data)
+
+    UMat mapx, mapy, r, cp_sp;
+    UMat src = _src.getUMat();
+    _dst.create(src.size(), src.type());
+    Size dsize = src.size();
+    r.create(Size(1, dsize.width), CV_32F);
+    cp_sp.create(Size(1, dsize.height), CV_32FC2);
+
+    mapx.create(dsize, CV_32F);
+    mapy.create(dsize, CV_32F);
+    size_t w = dsize.width;
+    size_t h = dsize.height;
+    String buildOptions;
+    unsigned mem_size = 32;
+    if (flags & CV_WARP_INVERSE_MAP)
+    {
+        buildOptions = "-D InverseMap";
+    }
+    else
+    {
+        buildOptions = format("-D ForwardMap  -D MEM_SIZE=%d", mem_size);
+    }
+    String retval;
+    ocl::Program p(ocl::imgproc::linearPolar_oclsrc, buildOptions, retval);
+    ocl::Kernel k("linearPolar", p);
+    ocl::KernelArg ocl_mapx = ocl::KernelArg::PtrReadWrite(mapx), ocl_mapy = ocl::KernelArg::PtrReadWrite(mapy);
+    ocl::KernelArg  ocl_cp_sp = ocl::KernelArg::PtrReadWrite(cp_sp);
+    ocl::KernelArg ocl_r = ocl::KernelArg::PtrReadWrite(r);
+
+    if (!(flags & CV_WARP_INVERSE_MAP))
+    {
+
+
+
+        ocl::Kernel computeAngleRadius_Kernel("computeAngleRadius", p);
+        float PI2_height = (float) CV_2PI / dsize.height;
+        float maxRadius_width = (float) maxRadius / dsize.width;
+        computeAngleRadius_Kernel.args(ocl_cp_sp, ocl_r, maxRadius_width, PI2_height, (unsigned)dsize.width, (unsigned)dsize.height);
+        size_t max_dim = max(h, w);
+        computeAngleRadius_Kernel.run(1, &max_dim, NULL, false);
+        k.args(ocl_mapx, ocl_mapy, ocl_cp_sp, ocl_r, center.x, center.y, (unsigned)dsize.width, (unsigned)dsize.height);
+    }
+    else
+    {
+        const int ANGLE_BORDER = 1;
+
+        cv::copyMakeBorder(src, src_with_border, ANGLE_BORDER, ANGLE_BORDER, 0, 0, BORDER_WRAP);
+        src = src_with_border;
+        Size ssize = src_with_border.size();
+        ssize.height -= 2 * ANGLE_BORDER;
+        float ascale =  ssize.height / ((float)CV_2PI);
+        float pscale =  ssize.width / ((float) maxRadius);
+
+        k.args(ocl_mapx, ocl_mapy, ascale, pscale, center.x, center.y, ANGLE_BORDER, (unsigned)dsize.width, (unsigned)dsize.height);
+
+
+    }
+    size_t globalThreads[2] = { (size_t)dsize.width , (size_t)dsize.height };
+    size_t localThreads[2] = { mem_size , mem_size };
+    k.run(2, globalThreads, localThreads, false);
+    remap(src, _dst, mapx, mapy, flags & cv::INTER_MAX, (flags & CV_WARP_FILL_OUTLIERS) ? cv::BORDER_CONSTANT : cv::BORDER_TRANSPARENT);
+    return true;
+}
+static bool ocl_logPolar(InputArray _src, OutputArray _dst,
+    Point2f center, double M, int flags)
+{
+    if (M <= 0)
+        CV_Error(CV_StsOutOfRange, "M should be >0");
+    UMat src_with_border; // don't scope this variable (it holds image data)
+
+    UMat mapx, mapy, r, cp_sp;
+    UMat src = _src.getUMat();
+    _dst.create(src.size(), src.type());
+    Size dsize = src.size();
+    r.create(Size(1, dsize.width), CV_32F);
+    cp_sp.create(Size(1, dsize.height), CV_32FC2);
+
+    mapx.create(dsize, CV_32F);
+    mapy.create(dsize, CV_32F);
+    size_t w = dsize.width;
+    size_t h = dsize.height;
+    String buildOptions;
+    unsigned mem_size = 32;
+    if (flags & CV_WARP_INVERSE_MAP)
+    {
+        buildOptions = "-D InverseMap";
+    }
+    else
+    {
+        buildOptions = format("-D ForwardMap  -D MEM_SIZE=%d", mem_size);
+    }
+    String retval;
+    ocl::Program p(ocl::imgproc::logPolar_oclsrc, buildOptions, retval);
+    //ocl::Program p(ocl::imgproc::my_linearPolar_oclsrc, buildOptions, retval);
+    //printf("%s\n", retval);
+    ocl::Kernel k("logPolar", p);
+    ocl::KernelArg ocl_mapx = ocl::KernelArg::PtrReadWrite(mapx), ocl_mapy = ocl::KernelArg::PtrReadWrite(mapy);
+    ocl::KernelArg  ocl_cp_sp = ocl::KernelArg::PtrReadWrite(cp_sp);
+    ocl::KernelArg ocl_r = ocl::KernelArg::PtrReadWrite(r);
+
+    if (!(flags & CV_WARP_INVERSE_MAP))
+    {
+
+
+
+        ocl::Kernel computeAngleRadius_Kernel("computeAngleRadius", p);
+        float PI2_height = (float) CV_2PI / dsize.height;
+
+        computeAngleRadius_Kernel.args(ocl_cp_sp, ocl_r, (float)M, PI2_height, (unsigned)dsize.width, (unsigned)dsize.height);
+        size_t max_dim = max(h, w);
+        computeAngleRadius_Kernel.run(1, &max_dim, NULL, false);
+        k.args(ocl_mapx, ocl_mapy, ocl_cp_sp, ocl_r, center.x, center.y, (unsigned)dsize.width, (unsigned)dsize.height);
+    }
+    else
+    {
+        const int ANGLE_BORDER = 1;
+
+        cv::copyMakeBorder(src, src_with_border, ANGLE_BORDER, ANGLE_BORDER, 0, 0, BORDER_WRAP);
+        src = src_with_border;
+        Size ssize = src_with_border.size();
+        ssize.height -= 2 * ANGLE_BORDER;
+        float ascale =  ssize.height / ((float)CV_2PI);
+
+
+        k.args(ocl_mapx, ocl_mapy, ascale, (float)M, center.x, center.y, ANGLE_BORDER, (unsigned)dsize.width, (unsigned)dsize.height);
+
+
+    }
+    size_t globalThreads[2] = { (size_t)dsize.width , (size_t)dsize.height };
+    size_t localThreads[2] = { mem_size , mem_size };
+    k.run(2, globalThreads, localThreads, false);
+    remap(src, _dst, mapx, mapy, flags & cv::INTER_MAX, (flags & CV_WARP_FILL_OUTLIERS) ? cv::BORDER_CONSTANT : cv::BORDER_TRANSPARENT);
+    return true;
+}
+#endif
+
+#ifdef HAVE_OPENVX
+static bool openvx_remap(Mat src, Mat dst, Mat map1, Mat map2, int interpolation, const Scalar& borderValue)
+{
+    vx_interpolation_type_e inter_type;
+    switch (interpolation)
+    {
+    case INTER_LINEAR:
+#if VX_VERSION > VX_VERSION_1_0
+        inter_type = VX_INTERPOLATION_BILINEAR;
+#else
+        inter_type = VX_INTERPOLATION_TYPE_BILINEAR;
+#endif
+        break;
+    case INTER_NEAREST:
+/* NEAREST_NEIGHBOR mode disabled since OpenCV round half to even while OpenVX sample implementation round half up
+#if VX_VERSION > VX_VERSION_1_0
+        inter_type = VX_INTERPOLATION_NEAREST_NEIGHBOR;
+#else
+        inter_type = VX_INTERPOLATION_TYPE_NEAREST_NEIGHBOR;
+#endif
+        if (!map1.empty())
+            for (int y = 0; y < map1.rows; ++y)
+            {
+                float* line = map1.ptr<float>(y);
+                for (int x = 0; x < map1.cols; ++x)
+                    line[x] = cvRound(line[x]);
+            }
+        if (!map2.empty())
+            for (int y = 0; y < map2.rows; ++y)
+            {
+                float* line = map2.ptr<float>(y);
+                for (int x = 0; x < map2.cols; ++x)
+                    line[x] = cvRound(line[x]);
+            }
+        break;
+*/
+    case INTER_AREA://AREA interpolation mode is unsupported
+    default:
+        return false;
+    }
+
+    try
+    {
+        ivx::Context ctx = ivx::Context::create();
+
+        Mat a;
+        if (dst.data != src.data)
+            a = src;
+        else
+            src.copyTo(a);
+
+        ivx::Image
+            ia = ivx::Image::createFromHandle(ctx, VX_DF_IMAGE_U8,
+                ivx::Image::createAddressing(a.cols, a.rows, 1, (vx_int32)(a.step)), a.data),
+            ib = ivx::Image::createFromHandle(ctx, VX_DF_IMAGE_U8,
+                ivx::Image::createAddressing(dst.cols, dst.rows, 1, (vx_int32)(dst.step)), dst.data);
+
+        //ATTENTION: VX_CONTEXT_IMMEDIATE_BORDER attribute change could lead to strange issues in multi-threaded environments
+        //since OpenVX standart says nothing about thread-safety for now
+        ivx::border_t prevBorder = ctx.immediateBorder();
+        ctx.setImmediateBorder(VX_BORDER_CONSTANT, (vx_uint8)(borderValue[0]));
+
+        ivx::Remap map = ivx::Remap::create(ctx, src.cols, src.rows, dst.cols, dst.rows);
+        if (map1.empty()) map.setMappings(map2);
+        else if (map2.empty()) map.setMappings(map1);
+        else map.setMappings(map1, map2);
+        ivx::IVX_CHECK_STATUS(vxuRemap(ctx, ia, map, inter_type, ib));
+#ifdef VX_VERSION_1_1
+        ib.swapHandle();
+        ia.swapHandle();
 #endif
 
-#if defined HAVE_IPP && !defined HAVE_IPP_ICV_ONLY && IPP_DISABLE_BLOCK
+        ctx.setImmediateBorder(prevBorder);
+    }
+    catch (ivx::RuntimeError & e)
+    {
+        CV_Error(CV_StsInternal, e.what());
+        return false;
+    }
+    catch (ivx::WrapperError & e)
+    {
+        CV_Error(CV_StsInternal, e.what());
+        return false;
+    }
+    return true;
+}
+#endif
+
+#if defined HAVE_IPP && IPP_DISABLE_BLOCK
 
 typedef IppStatus (CV_STDCALL * ippiRemap)(const void * pSrc, IppiSize srcSize, int srcStep, IppiRect srcRoi,
                                            const Ipp32f* pxMap, int xMapStep, const Ipp32f* pyMap, int yMapStep,
@@ -4610,9 +4872,9 @@ public:
             return;
         }
 
-        if (ippFunc(src.ptr(), ippiSize(src.size()), (int)src.step, srcRoiRect,
+        if (CV_INSTRUMENT_FUN_PTR_CALL_IPP(ippFunc,(src.ptr(), ippiSize(src.size()), (int)src.step, srcRoiRect,
                     map1.ptr<Ipp32f>(), (int)map1.step, map2.ptr<Ipp32f>(), (int)map2.step,
-                    dstRoi.ptr(), (int)dstRoi.step, dstRoiSize, ippInterpolation) < 0)
+                    dstRoi.ptr(), (int)dstRoi.step, dstRoiSize, ippInterpolation)) < 0)
             *ok = false;
         else
         {
@@ -4636,6 +4898,8 @@ void cv::remap( InputArray _src, OutputArray _dst,
                 InputArray _map1, InputArray _map2,
                 int interpolation, int borderType, const Scalar& borderValue )
 {
+    CV_INSTRUMENT_REGION()
+
     static RemapNNFunc nn_tab[] =
     {
         remapNearest<uchar>, remapNearest<schar>, remapNearest<ushort>, remapNearest<short>,
@@ -4678,6 +4942,19 @@ void cv::remap( InputArray _src, OutputArray _dst,
     Mat src = _src.getMat(), map1 = _map1.getMat(), map2 = _map2.getMat();
     _dst.create( map1.size(), src.type() );
     Mat dst = _dst.getMat();
+
+
+    CV_OVX_RUN(
+        src.type() == CV_8UC1 && dst.type() == CV_8UC1 &&
+        (borderType& ~BORDER_ISOLATED) == BORDER_CONSTANT &&
+        ((map1.type() == CV_32FC2 && map2.empty() && map1.size == dst.size) ||
+         (map1.type() == CV_32FC1 && map2.type() == CV_32FC1 && map1.size == dst.size && map2.size == dst.size) ||
+         (map1.empty() && map2.type() == CV_32FC2 && map2.size == dst.size)) &&
+        ((borderType & BORDER_ISOLATED) != 0 || !src.isSubmatrix()),
+        openvx_remap(src, dst, map1, map2, interpolation, borderValue));
+
+    CV_Assert( dst.cols < SHRT_MAX && dst.rows < SHRT_MAX && src.cols < SHRT_MAX && src.rows < SHRT_MAX );
+
     if( dst.data == src.data )
         src = src.clone();
 
@@ -4686,7 +4963,7 @@ void cv::remap( InputArray _src, OutputArray _dst,
 
     int type = src.type(), depth = CV_MAT_DEPTH(type);
 
-#if defined HAVE_IPP && !defined HAVE_IPP_ICV_ONLY && IPP_DISABLE_BLOCK
+#if defined HAVE_IPP && IPP_DISABLE_BLOCK
     CV_IPP_CHECK()
     {
         if ((interpolation == INTER_LINEAR || interpolation == INTER_CUBIC || interpolation == INTER_NEAREST) &&
@@ -4778,6 +5055,8 @@ void cv::convertMaps( InputArray _map1, InputArray _map2,
                       OutputArray _dstmap1, OutputArray _dstmap2,
                       int dstm1type, bool nninterpolate )
 {
+    CV_INSTRUMENT_REGION()
+
     Mat map1 = _map1.getMat(), map2 = _map2.getMat(), dstmap1, dstmap2;
     Size size = map1.size();
     const Mat *m1 = &map1, *m2 = &map2;
@@ -5230,7 +5509,7 @@ class WarpAffineInvoker :
 {
 public:
     WarpAffineInvoker(const Mat &_src, Mat &_dst, int _interpolation, int _borderType,
-                      const Scalar &_borderValue, int *_adelta, int *_bdelta, double *_M) :
+                      const Scalar &_borderValue, int *_adelta, int *_bdelta, const double *_M) :
         ParallelLoopBody(), src(_src), dst(_dst), interpolation(_interpolation),
         borderType(_borderType), borderValue(_borderValue), adelta(_adelta), bdelta(_bdelta),
         M(_M)
@@ -5408,7 +5687,7 @@ private:
     int interpolation, borderType;
     Scalar borderValue;
     int *adelta, *bdelta;
-    double *M;
+    const double *M;
 };
 
 
@@ -5443,8 +5722,8 @@ public:
         }
 
         // Aug 2013: problem in IPP 7.1, 8.0 : sometimes function return ippStsCoeffErr
-        IppStatus status = func( src.ptr(), srcsize, (int)src.step[0], srcroi, dst.ptr(),
-                                (int)dst.step[0], dstroi, coeffs, mode );
+        IppStatus status = CV_INSTRUMENT_FUN_PTR_CALL_IPP(func,( src.ptr(), srcsize, (int)src.step[0], srcroi, dst.ptr(),
+                                (int)dst.step[0], dstroi, coeffs, mode ));
         if( status < 0)
             *ok = false;
         else
@@ -5469,6 +5748,81 @@ private:
 
 enum { OCL_OP_PERSPECTIVE = 1, OCL_OP_AFFINE = 0 };
 
+static bool ocl_warpTransform_cols4(InputArray _src, OutputArray _dst, InputArray _M0,
+                                    Size dsize, int flags, int borderType, const Scalar& borderValue,
+                                    int op_type)
+{
+    CV_Assert(op_type == OCL_OP_AFFINE || op_type == OCL_OP_PERSPECTIVE);
+    const ocl::Device & dev = ocl::Device::getDefault();
+    int type = _src.type(), dtype = _dst.type(), depth = CV_MAT_DEPTH(type), cn = CV_MAT_CN(type);
+
+    int interpolation = flags & INTER_MAX;
+    if( interpolation == INTER_AREA )
+        interpolation = INTER_LINEAR;
+
+    if ( !dev.isIntel() || !(type == CV_8UC1) ||
+         !(dtype == CV_8UC1) || !(_dst.cols() % 4 == 0) ||
+         !(borderType == cv::BORDER_CONSTANT &&
+          (interpolation == cv::INTER_NEAREST || interpolation == cv::INTER_LINEAR || interpolation == cv::INTER_CUBIC)))
+        return false;
+
+    const char * const warp_op[2] = { "Affine", "Perspective" };
+    const char * const interpolationMap[3] = { "nearest", "linear", "cubic" };
+    ocl::ProgramSource program = ocl::imgproc::warp_transform_oclsrc;
+    String kernelName = format("warp%s_%s_8u", warp_op[op_type], interpolationMap[interpolation]);
+
+    bool is32f = (interpolation == INTER_CUBIC || interpolation == INTER_LINEAR) && op_type == OCL_OP_AFFINE;
+    int wdepth = interpolation == INTER_NEAREST ? depth : std::max(is32f ? CV_32F : CV_32S, depth);
+    int sctype = CV_MAKETYPE(wdepth, cn);
+
+    ocl::Kernel k;
+    String opts = format("-D ST=%s", ocl::typeToStr(sctype));
+
+    k.create(kernelName.c_str(), program, opts);
+    if (k.empty())
+        return false;
+
+    float borderBuf[] = { 0, 0, 0, 0 };
+    scalarToRawData(borderValue, borderBuf, sctype);
+
+    UMat src = _src.getUMat(), M0;
+    _dst.create( dsize.area() == 0 ? src.size() : dsize, src.type() );
+    UMat dst = _dst.getUMat();
+
+    float M[9];
+    int matRows = (op_type == OCL_OP_AFFINE ? 2 : 3);
+    Mat matM(matRows, 3, CV_32F, M), M1 = _M0.getMat();
+    CV_Assert( (M1.type() == CV_32F || M1.type() == CV_64F) && M1.rows == matRows && M1.cols == 3 );
+    M1.convertTo(matM, matM.type());
+
+    if( !(flags & WARP_INVERSE_MAP) )
+    {
+        if (op_type == OCL_OP_PERSPECTIVE)
+            invert(matM, matM);
+        else
+        {
+            float D = M[0]*M[4] - M[1]*M[3];
+            D = D != 0 ? 1.f/D : 0;
+            float A11 = M[4]*D, A22=M[0]*D;
+            M[0] = A11; M[1] *= -D;
+            M[3] *= -D; M[4] = A22;
+            float b1 = -M[0]*M[2] - M[1]*M[5];
+            float b2 = -M[3]*M[2] - M[4]*M[5];
+            M[2] = b1; M[5] = b2;
+        }
+    }
+    matM.convertTo(M0, CV_32F);
+
+    k.args(ocl::KernelArg::ReadOnly(src), ocl::KernelArg::WriteOnly(dst), ocl::KernelArg::PtrReadOnly(M0),
+           ocl::KernelArg(0, 0, 0, 0, borderBuf, CV_ELEM_SIZE(sctype)));
+
+    size_t globalThreads[2];
+    globalThreads[0] = (size_t)(dst.cols / 4);
+    globalThreads[1] = (size_t)dst.rows;
+
+    return k.run(2, globalThreads, NULL, false);
+}
+
 static bool ocl_warpTransform(InputArray _src, OutputArray _dst, InputArray _M0,
                               Size dsize, int flags, int borderType, const Scalar& borderValue,
                               int op_type)
@@ -5567,13 +5921,52 @@ static bool ocl_warpTransform(InputArray _src, OutputArray _dst, InputArray _M0,
 
 #endif
 
+namespace hal {
+
+void warpAffine(int src_type,
+                const uchar * src_data, size_t src_step, int src_width, int src_height,
+                uchar * dst_data, size_t dst_step, int dst_width, int dst_height,
+                const double M[6], int interpolation, int borderType, const double borderValue[4])
+{
+    CALL_HAL(warpAffine, cv_hal_warpAffine, src_type, src_data, src_step, src_width, src_height, dst_data, dst_step, dst_width, dst_height, M, interpolation, borderType, borderValue);
+
+    Mat src(Size(src_width, src_height), src_type, const_cast<uchar*>(src_data), src_step);
+    Mat dst(Size(dst_width, dst_height), src_type, dst_data, dst_step);
+
+    int x;
+    AutoBuffer<int> _abdelta(dst.cols*2);
+    int* adelta = &_abdelta[0], *bdelta = adelta + dst.cols;
+    const int AB_BITS = MAX(10, (int)INTER_BITS);
+    const int AB_SCALE = 1 << AB_BITS;
+
+    for( x = 0; x < dst.cols; x++ )
+    {
+        adelta[x] = saturate_cast<int>(M[0]*x*AB_SCALE);
+        bdelta[x] = saturate_cast<int>(M[3]*x*AB_SCALE);
+    }
+
+    Range range(0, dst.rows);
+    WarpAffineInvoker invoker(src, dst, interpolation, borderType,
+                              Scalar(borderValue[0], borderValue[1], borderValue[2], borderValue[3]),
+                              adelta, bdelta, M);
+    parallel_for_(range, invoker, dst.total()/(double)(1<<16));
 }
 
+} // hal::
+} // cv::
+
 
 void cv::warpAffine( InputArray _src, OutputArray _dst,
                      InputArray _M0, Size dsize,
                      int flags, int borderType, const Scalar& borderValue )
 {
+    CV_INSTRUMENT_REGION()
+
+    CV_OCL_RUN(_src.dims() <= 2 && _dst.isUMat() &&
+               _src.cols() <= SHRT_MAX && _src.rows() <= SHRT_MAX,
+               ocl_warpTransform_cols4(_src, _dst, _M0, dsize, flags, borderType,
+                                       borderValue, OCL_OP_AFFINE))
+
     CV_OCL_RUN(_src.dims() <= 2 && _dst.isUMat(),
                ocl_warpTransform(_src, _dst, _M0, dsize, flags, borderType,
                                  borderValue, OCL_OP_AFFINE))
@@ -5594,11 +5987,6 @@ void cv::warpAffine( InputArray _src, OutputArray _dst,
     CV_Assert( (M0.type() == CV_32F || M0.type() == CV_64F) && M0.rows == 2 && M0.cols == 3 );
     M0.convertTo(matM, matM.type());
 
-#ifdef HAVE_TEGRA_OPTIMIZATION
-    if( tegra::useTegra() && tegra::warpAffine(src, dst, M, flags, borderType, borderValue) )
-        return;
-#endif
-
     if( !(flags & WARP_INVERSE_MAP) )
     {
         double D = M[0]*M[4] - M[1]*M[3];
@@ -5611,12 +5999,6 @@ void cv::warpAffine( InputArray _src, OutputArray _dst,
         M[2] = b1; M[5] = b2;
     }
 
-    int x;
-    AutoBuffer<int> _abdelta(dst.cols*2);
-    int* adelta = &_abdelta[0], *bdelta = adelta + dst.cols;
-    const int AB_BITS = MAX(10, (int)INTER_BITS);
-    const int AB_SCALE = 1 << AB_BITS;
-
 #if defined (HAVE_IPP) && IPP_VERSION_X100 >= 810 && IPP_DISABLE_BLOCK
     CV_IPP_CHECK()
     {
@@ -5681,16 +6063,8 @@ void cv::warpAffine( InputArray _src, OutputArray _dst,
     }
 #endif
 
-    for( x = 0; x < dst.cols; x++ )
-    {
-        adelta[x] = saturate_cast<int>(M[0]*x*AB_SCALE);
-        bdelta[x] = saturate_cast<int>(M[3]*x*AB_SCALE);
-    }
-
-    Range range(0, dst.rows);
-    WarpAffineInvoker invoker(src, dst, interpolation, borderType,
-                              borderValue, adelta, bdelta, M);
-    parallel_for_(range, invoker, dst.total()/(double)(1<<16));
+    hal::warpAffine(src.type(), src.data, src.step, src.cols, src.rows, dst.data, dst.step, dst.cols, dst.rows,
+                    M, interpolation, borderType, borderValue.val);
 }
 
 
@@ -5701,7 +6075,7 @@ class WarpPerspectiveInvoker :
     public ParallelLoopBody
 {
 public:
-    WarpPerspectiveInvoker(const Mat &_src, Mat &_dst, double *_M, int _interpolation,
+    WarpPerspectiveInvoker(const Mat &_src, Mat &_dst, const double *_M, int _interpolation,
                            int _borderType, const Scalar &_borderValue) :
         ParallelLoopBody(), src(_src), dst(_dst), M(_M), interpolation(_interpolation),
         borderType(_borderType), borderValue(_borderValue)
@@ -6035,12 +6409,11 @@ public:
 private:
     Mat src;
     Mat dst;
-    double* M;
+    const double* M;
     int interpolation, borderType;
     Scalar borderValue;
 };
 
-
 #if defined (HAVE_IPP) && IPP_VERSION_X100 >= 810 && IPP_DISABLE_BLOCK
 class IPPWarpPerspectiveInvoker :
     public ParallelLoopBody
@@ -6072,7 +6445,7 @@ public:
             }
         }
 
-        IppStatus status = func(src.ptr(), srcsize, (int)src.step[0], srcroi, dst.ptr(), (int)dst.step[0], dstroi, coeffs, mode);
+        IppStatus status = CV_INSTRUMENT_FUN_PTR_CALL_IPP(func,(src.ptr(), srcsize, (int)src.step[0], srcroi, dst.ptr(), (int)dst.step[0], dstroi, coeffs, mode));
         if (status != ippStsNoErr)
             *ok = false;
         else
@@ -6093,13 +6466,38 @@ private:
     const IPPWarpPerspectiveInvoker& operator= (const IPPWarpPerspectiveInvoker&);
 };
 #endif
+
+namespace hal {
+
+void warpPerspectve(int src_type,
+                    const uchar * src_data, size_t src_step, int src_width, int src_height,
+                    uchar * dst_data, size_t dst_step, int dst_width, int dst_height,
+                    const double M[9], int interpolation, int borderType, const double borderValue[4])
+{
+    CALL_HAL(warpPerspective, cv_hal_warpPerspective, src_type, src_data, src_step, src_width, src_height, dst_data, dst_step, dst_width, dst_height, M, interpolation, borderType, borderValue);
+    Mat src(Size(src_width, src_height), src_type, const_cast<uchar*>(src_data), src_step);
+    Mat dst(Size(dst_width, dst_height), src_type, dst_data, dst_step);
+
+    Range range(0, dst.rows);
+    WarpPerspectiveInvoker invoker(src, dst, M, interpolation, borderType, Scalar(borderValue[0], borderValue[1], borderValue[2], borderValue[3]));
+    parallel_for_(range, invoker, dst.total()/(double)(1<<16));
 }
 
+} // hal::
+} // cv::
+
 void cv::warpPerspective( InputArray _src, OutputArray _dst, InputArray _M0,
                           Size dsize, int flags, int borderType, const Scalar& borderValue )
 {
+    CV_INSTRUMENT_REGION()
+
     CV_Assert( _src.total() > 0 );
 
+    CV_OCL_RUN(_src.dims() <= 2 && _dst.isUMat() &&
+               _src.cols() <= SHRT_MAX && _src.rows() <= SHRT_MAX,
+               ocl_warpTransform_cols4(_src, _dst, _M0, dsize, flags, borderType, borderValue,
+                                       OCL_OP_PERSPECTIVE))
+
     CV_OCL_RUN(_src.dims() <= 2 && _dst.isUMat(),
                ocl_warpTransform(_src, _dst, _M0, dsize, flags, borderType, borderValue,
                               OCL_OP_PERSPECTIVE))
@@ -6120,12 +6518,6 @@ void cv::warpPerspective( InputArray _src, OutputArray _dst, InputArray _M0,
     CV_Assert( (M0.type() == CV_32F || M0.type() == CV_64F) && M0.rows == 3 && M0.cols == 3 );
     M0.convertTo(matM, matM.type());
 
-#ifdef HAVE_TEGRA_OPTIMIZATION
-    if( tegra::useTegra() && tegra::warpPerspective(src, dst, M, flags, borderType, borderValue) )
-        return;
-#endif
-
-
 #if defined (HAVE_IPP) && IPP_VERSION_X100 >= 810 && IPP_DISABLE_BLOCK
     CV_IPP_CHECK()
     {
@@ -6188,14 +6580,15 @@ void cv::warpPerspective( InputArray _src, OutputArray _dst, InputArray _M0,
     if( !(flags & WARP_INVERSE_MAP) )
         invert(matM, matM);
 
-    Range range(0, dst.rows);
-    WarpPerspectiveInvoker invoker(src, dst, M, interpolation, borderType, borderValue);
-    parallel_for_(range, invoker, dst.total()/(double)(1<<16));
+    hal::warpPerspectve(src.type(), src.data, src.step, src.cols, src.rows, dst.data, dst.step, dst.cols, dst.rows,
+                        matM.ptr<double>(), interpolation, borderType, borderValue.val);
 }
 
 
 cv::Mat cv::getRotationMatrix2D( Point2f center, double angle, double scale )
 {
+    CV_INSTRUMENT_REGION()
+
     angle *= CV_PI/180;
     double alpha = cos(angle)*scale;
     double beta = sin(angle)*scale;
@@ -6239,6 +6632,8 @@ cv::Mat cv::getRotationMatrix2D( Point2f center, double angle, double scale )
  */
 cv::Mat cv::getPerspectiveTransform( const Point2f src[], const Point2f dst[] )
 {
+    CV_INSTRUMENT_REGION()
+
     Mat M(3, 3, CV_64F), X(8, 1, CV_64F, M.ptr());
     double a[8][8], b[8];
     Mat A(8, 8, CV_64F, a), B(8, 1, CV_64F, b);
@@ -6475,11 +6870,13 @@ CV_IMPL void
 cvLogPolar( const CvArr* srcarr, CvArr* dstarr,
             CvPoint2D32f center, double M, int flags )
 {
+    Mat src_with_border; // don't scope this variable (it holds image data)
+
     cv::Ptr<CvMat> mapx, mapy;
 
     CvMat srcstub, *src = cvGetMat(srcarr, &srcstub);
     CvMat dststub, *dst = cvGetMat(dstarr, &dststub);
-    CvSize ssize, dsize;
+    CvSize dsize;
 
     if( !CV_ARE_TYPES_EQ( src, dst ))
         CV_Error( CV_StsUnmatchedFormats, "" );
@@ -6487,7 +6884,6 @@ cvLogPolar( const CvArr* srcarr, CvArr* dstarr,
     if( M <= 0 )
         CV_Error( CV_StsOutOfRange, "M should be >0" );
 
-    ssize = cvGetMatSize(src);
     dsize = cvGetMatSize(dst);
 
     mapx.reset(cvCreateMat( dsize.height, dsize.width, CV_32F ));
@@ -6500,7 +6896,7 @@ cvLogPolar( const CvArr* srcarr, CvArr* dstarr,
         double* exp_tab = _exp_tab;
 
         for( rho = 0; rho < dst->width; rho++ )
-            exp_tab[rho] = std::exp(rho/M);
+            exp_tab[rho] = std::exp(rho/M) - 1.0;
 
         for( phi = 0; phi < dsize.height; phi++ )
         {
@@ -6522,6 +6918,13 @@ cvLogPolar( const CvArr* srcarr, CvArr* dstarr,
     }
     else
     {
+        const int ANGLE_BORDER = 1;
+        Mat src_ = cv::cvarrToMat(src);
+        cv::copyMakeBorder(src_, src_with_border, ANGLE_BORDER, ANGLE_BORDER, 0, 0, BORDER_WRAP);
+        srcstub = src_with_border; src = &srcstub;
+        CvSize ssize = cvGetMatSize(src);
+        ssize.height -= 2*ANGLE_BORDER;
+
         int x, y;
         CvMat bufx, bufy, bufp, bufa;
         double ascale = ssize.height/(2*CV_PI);
@@ -6558,7 +6961,7 @@ cvLogPolar( const CvArr* srcarr, CvArr* dstarr,
                 double phi = bufa.data.fl[x]*ascale;
 
                 mx[x] = (float)rho;
-                my[x] = (float)phi;
+                my[x] = (float)phi + ANGLE_BORDER;
             }
 #else
             for( x = 0; x < dsize.width; x++ )
@@ -6585,10 +6988,115 @@ cvLogPolar( const CvArr* srcarr, CvArr* dstarr,
 void cv::logPolar( InputArray _src, OutputArray _dst,
                    Point2f center, double M, int flags )
 {
-    Mat src = _src.getMat();
-    _dst.create( src.size(), src.type() );
-    CvMat c_src = src, c_dst = _dst.getMat();
-    cvLogPolar( &c_src, &c_dst, center, M, flags );
+    CV_INSTRUMENT_REGION()
+
+    CV_OCL_RUN(_src.isUMat() && _dst.isUMat(),
+        ocl_logPolar(_src, _dst, center, M, flags));
+    Mat src_with_border; // don't scope this variable (it holds image data)
+
+    Mat mapx, mapy;
+
+    Mat srcstub, src = _src.getMat();
+    _dst.create(src.size(), src.type());
+    Size dsize = src.size();
+
+    if (M <= 0)
+        CV_Error(CV_StsOutOfRange, "M should be >0");
+
+
+    mapx.create(dsize, CV_32F);
+    mapy.create(dsize, CV_32F);
+
+    if (!(flags & CV_WARP_INVERSE_MAP))
+    {
+        int phi, rho;
+        cv::AutoBuffer<double> _exp_tab(dsize.width);
+        double* exp_tab = _exp_tab;
+
+        for (rho = 0; rho < dsize.width; rho++)
+            exp_tab[rho] = std::exp(rho / M) - 1.0;
+
+        for (phi = 0; phi < dsize.height; phi++)
+        {
+            double cp = cos(phi * 2 * CV_PI / dsize.height);
+            double sp = sin(phi * 2 * CV_PI / dsize.height);
+            float* mx = (float*)(mapx.data + phi*mapx.step);
+            float* my = (float*)(mapy.data + phi*mapy.step);
+
+            for (rho = 0; rho < dsize.width; rho++)
+            {
+                double r = exp_tab[rho];
+                double x = r*cp + center.x;
+                double y = r*sp + center.y;
+
+                mx[rho] = (float)x;
+                my[rho] = (float)y;
+            }
+        }
+    }
+    else
+    {
+        const int ANGLE_BORDER = 1;
+        cv::copyMakeBorder(src, src_with_border, ANGLE_BORDER, ANGLE_BORDER, 0, 0, BORDER_WRAP);
+        srcstub = src_with_border; src = srcstub;
+        Size ssize = src.size();
+        ssize.height -= 2 * ANGLE_BORDER;
+
+        int x, y;
+        Mat bufx, bufy, bufp, bufa;
+        double ascale = ssize.height / (2 * CV_PI);
+
+        bufx = Mat(1, dsize.width, CV_32F);
+        bufy = Mat(1, dsize.width, CV_32F);
+        bufp = Mat(1, dsize.width, CV_32F);
+        bufa = Mat(1, dsize.width, CV_32F);
+
+        for (x = 0; x < dsize.width; x++)
+            bufx.at<float>(0, x) = (float)x - center.x;
+
+        for (y = 0; y < dsize.height; y++)
+        {
+            float* mx = (float*)(mapx.data + y*mapx.step);
+            float* my = (float*)(mapy.data + y*mapy.step);
+
+            for (x = 0; x < dsize.width; x++)
+                bufy.at<float>(0, x) = (float)y - center.y;
+
+#if 1
+            cartToPolar(bufx, bufy, bufp, bufa);
+
+            for (x = 0; x < dsize.width; x++)
+                bufp.at<float>(0, x) += 1.f;
+
+            log(bufp, bufp);
+
+            for (x = 0; x < dsize.width; x++)
+            {
+                double rho = bufp.at<float>(0, x) * M;
+                double phi = bufa.at<float>(0, x) * ascale;
+
+                mx[x] = (float)rho;
+                my[x] = (float)phi + ANGLE_BORDER;
+            }
+#else
+            for (x = 0; x < dsize.width; x++)
+            {
+                double xx = bufx.at<float>(0, x);
+                double yy = bufy.at<float>(0, x);
+                double p = log(std::sqrt(xx*xx + yy*yy) + 1.)*M;
+                double a = atan2(yy, xx);
+                if (a < 0)
+                    a = 2 * CV_PI + a;
+                a *= ascale;
+                mx[x] = (float)p;
+                my[x] = (float)a;
+            }
+#endif
+        }
+    }
+
+    remap(src, _dst, mapx, mapy, flags & cv::INTER_MAX,
+        (flags & CV_WARP_FILL_OUTLIERS) ? cv::BORDER_CONSTANT : cv::BORDER_TRANSPARENT);
 }
 
 /****************************************************************************************
@@ -6599,11 +7107,13 @@ CV_IMPL
 void cvLinearPolar( const CvArr* srcarr, CvArr* dstarr,
             CvPoint2D32f center, double maxRadius, int flags )
 {
+    Mat src_with_border; // don't scope this variable (it holds image data)
+
     cv::Ptr<CvMat> mapx, mapy;
 
     CvMat srcstub, *src = (CvMat*)srcarr;
     CvMat dststub, *dst = (CvMat*)dstarr;
-    CvSize ssize, dsize;
+    CvSize dsize;
 
     src = cvGetMat( srcarr, &srcstub,0,0 );
     dst = cvGetMat( dstarr, &dststub,0,0 );
@@ -6611,10 +7121,7 @@ void cvLinearPolar( const CvArr* srcarr, CvArr* dstarr,
     if( !CV_ARE_TYPES_EQ( src, dst ))
         CV_Error( CV_StsUnmatchedFormats, "" );
 
-    ssize.width = src->cols;
-    ssize.height = src->rows;
-    dsize.width = dst->cols;
-    dsize.height = dst->rows;
+    dsize = cvGetMatSize(dst);
 
     mapx.reset(cvCreateMat( dsize.height, dsize.width, CV_32F ));
     mapy.reset(cvCreateMat( dsize.height, dsize.width, CV_32F ));
@@ -6632,7 +7139,7 @@ void cvLinearPolar( const CvArr* srcarr, CvArr* dstarr,
 
             for( rho = 0; rho < dsize.width; rho++ )
             {
-                double r = maxRadius*(rho+1)/dsize.width;
+                double r = maxRadius*rho/dsize.width;
                 double x = r*cp + center.x;
                 double y = r*sp + center.y;
 
@@ -6643,6 +7150,13 @@ void cvLinearPolar( const CvArr* srcarr, CvArr* dstarr,
     }
     else
     {
+        const int ANGLE_BORDER = 1;
+        Mat src_ = cv::cvarrToMat(src);
+        cv::copyMakeBorder(src_, src_with_border, ANGLE_BORDER, ANGLE_BORDER, 0, 0, BORDER_WRAP);
+        srcstub = src_with_border; src = &srcstub;
+        CvSize ssize = cvGetMatSize(src);
+        ssize.height -= 2*ANGLE_BORDER;
+
         int x, y;
         CvMat bufx, bufy, bufp, bufa;
         const double ascale = ssize.height/(2*CV_PI);
@@ -6670,14 +7184,11 @@ void cvLinearPolar( const CvArr* srcarr, CvArr* dstarr,
             cvCartToPolar( &bufx, &bufy, &bufp, &bufa, 0 );
 
             for( x = 0; x < dsize.width; x++ )
-                bufp.data.fl[x] += 1.f;
-
-            for( x = 0; x < dsize.width; x++ )
             {
                 double rho = bufp.data.fl[x]*pscale;
                 double phi = bufa.data.fl[x]*ascale;
                 mx[x] = (float)rho;
-                my[x] = (float)phi;
+                my[x] = (float)phi + ANGLE_BORDER;
             }
         }
     }
@@ -6688,10 +7199,88 @@ void cvLinearPolar( const CvArr* srcarr, CvArr* dstarr,
 void cv::linearPolar( InputArray _src, OutputArray _dst,
                       Point2f center, double maxRadius, int flags )
 {
-    Mat src = _src.getMat();
-    _dst.create( src.size(), src.type() );
-    CvMat c_src = src, c_dst = _dst.getMat();
-    cvLinearPolar( &c_src, &c_dst, center, maxRadius, flags );
+    CV_INSTRUMENT_REGION()
+
+    CV_OCL_RUN(_src.isUMat() && _dst.isUMat(),
+        ocl_linearPolar(_src, _dst, center, maxRadius, flags));
+    Mat src_with_border; // don't scope this variable (it holds image data)
+
+    Mat mapx, mapy;
+    Mat srcstub, src = _src.getMat();
+    _dst.create(src.size(), src.type());
+    Size dsize = src.size();
+
+
+    mapx.create(dsize, CV_32F);
+    mapy.create(dsize, CV_32F);
+
+    if (!(flags & CV_WARP_INVERSE_MAP))
+    {
+        int phi, rho;
+
+        for (phi = 0; phi < dsize.height; phi++)
+        {
+            double cp = cos(phi * 2 * CV_PI / dsize.height);
+            double sp = sin(phi * 2 * CV_PI / dsize.height);
+            float* mx = (float*)(mapx.data + phi*mapx.step);
+            float* my = (float*)(mapy.data + phi*mapy.step);
+
+            for (rho = 0; rho < dsize.width; rho++)
+            {
+                double r = maxRadius*rho / dsize.width;
+                double x = r*cp + center.x;
+                double y = r*sp + center.y;
+
+                mx[rho] = (float)x;
+                my[rho] = (float)y;
+            }
+        }
+    }
+    else
+    {
+        const int ANGLE_BORDER = 1;
+
+        cv::copyMakeBorder(src, src_with_border, ANGLE_BORDER, ANGLE_BORDER, 0, 0, BORDER_WRAP);
+        src = src_with_border;
+        Size ssize = src_with_border.size();
+        ssize.height -= 2 * ANGLE_BORDER;
+
+        int x, y;
+        Mat bufx, bufy, bufp, bufa;
+        const double ascale = ssize.height / (2 * CV_PI);
+        const double pscale = ssize.width / maxRadius;
+
+
+
+        bufx = Mat(1, dsize.width, CV_32F);
+        bufy = Mat(1, dsize.width, CV_32F);
+        bufp = Mat(1, dsize.width, CV_32F);
+        bufa = Mat(1, dsize.width, CV_32F);
+
+        for (x = 0; x < dsize.width; x++)
+            bufx.at<float>(0, x) = (float)x - center.x;
+
+        for (y = 0; y < dsize.height; y++)
+        {
+            float* mx = (float*)(mapx.data + y*mapx.step);
+            float* my = (float*)(mapy.data + y*mapy.step);
+
+            for (x = 0; x < dsize.width; x++)
+                bufy.at<float>(0, x) = (float)y - center.y;
+
+            cartToPolar(bufx, bufy, bufp, bufa, 0);
+
+            for (x = 0; x < dsize.width; x++)
+            {
+                double rho = bufp.at<float>(0, x) * pscale;
+                double phi = bufa.at<float>(0, x) * ascale;
+                mx[x] = (float)rho;
+                my[x] = (float)phi + ANGLE_BORDER;
+            }
+        }
+    }
+
+    remap(src, _dst, mapx, mapy, flags & cv::INTER_MAX, (flags & CV_WARP_FILL_OUTLIERS) ? cv::BORDER_CONSTANT : cv::BORDER_TRANSPARENT);
 }
 
 /* End of file. */
diff --git a/modules/imgproc/src/intersection.cpp b/modules/imgproc/src/intersection.cpp
index dfebd26..5da743a 100644
--- a/modules/imgproc/src/intersection.cpp
+++ b/modules/imgproc/src/intersection.cpp
@@ -49,6 +49,8 @@ namespace cv
 
 int rotatedRectangleIntersection( const RotatedRect& rect1, const RotatedRect& rect2, OutputArray intersectingRegion )
 {
+    CV_INSTRUMENT_REGION()
+
     const float samePointEps = 0.00001f; // used to test if two points are the same
 
     Point2f vec1[4], vec2[4];
diff --git a/modules/imgproc/src/linefit.cpp b/modules/imgproc/src/linefit.cpp
index dc71d88..c073e26 100644
--- a/modules/imgproc/src/linefit.cpp
+++ b/modules/imgproc/src/linefit.cpp
@@ -594,6 +594,8 @@ static void fitLine3D( Point3f * points, int count, int dist,
 void cv::fitLine( InputArray _points, OutputArray _line, int distType,
                  double param, double reps, double aeps )
 {
+    CV_INSTRUMENT_REGION()
+
     Mat points = _points.getMat();
 
     float linebuf[6]={0.f};
diff --git a/modules/imgproc/src/lsd.cpp b/modules/imgproc/src/lsd.cpp
index cda073a..e504018 100644
--- a/modules/imgproc/src/lsd.cpp
+++ b/modules/imgproc/src/lsd.cpp
@@ -230,12 +230,9 @@ public:
 
 private:
     Mat image;
-    Mat_<double> scaled_image;
-    double *scaled_image_data;
+    Mat scaled_image;
     Mat_<double> angles;     // in rads
-    double *angles_data;
     Mat_<double> modgrad;
-    double *modgrad_data;
     Mat_<uchar> used;
 
     int img_width;
@@ -270,6 +267,8 @@ private:
         struct coorlist* next;
     };
 
+    std::vector<coorlist> list;
+
     struct rect
     {
         double x1, y1, x2, y2;    // first and second point of the line segment
@@ -309,7 +308,7 @@ private:
  * @param list      Return: Vector of coordinate points that are pseudo ordered by magnitude.
  *                  Pixels would be ordered by norm value, up to a precision given by max_grad/n_bins.
  */
-    void ll_angle(const double& threshold, const unsigned int& n_bins, std::vector<coorlist>& list);
+    void ll_angle(const double& threshold, const unsigned int& n_bins);
 
 /**
  * Grow a region starting from point s with a defined precision,
@@ -317,31 +316,29 @@ private:
  *
  * @param s         Starting point for the region.
  * @param reg       Return: Vector of points, that are part of the region
- * @param reg_size  Return: The size of the region.
  * @param reg_angle Return: The mean angle of the region.
  * @param prec      The precision by which each region angle should be aligned to the mean.
  */
     void region_grow(const Point2i& s, std::vector<RegionPoint>& reg,
-                     int& reg_size, double& reg_angle, const double& prec);
+                     double& reg_angle, const double& prec);
 
 /**
  * Finds the bounding rotated rectangle of a region.
  *
  * @param reg       The region of points, from which the rectangle to be constructed from.
- * @param reg_size  The number of points in the region.
  * @param reg_angle The mean angle of the region.
  * @param prec      The precision by which points were found.
  * @param p         Probability of a point with angle within 'prec'.
  * @param rec       Return: The generated rectangle.
  */
-    void region2rect(const std::vector<RegionPoint>& reg, const int reg_size, const double reg_angle,
+    void region2rect(const std::vector<RegionPoint>& reg, const double reg_angle,
                      const double prec, const double p, rect& rec) const;
 
 /**
  * Compute region's angle as the principal inertia axis of the region.
  * @return          Regions angle.
  */
-    double get_theta(const std::vector<RegionPoint>& reg, const int& reg_size, const double& x,
+    double get_theta(const std::vector<RegionPoint>& reg, const double& x,
                      const double& y, const double& reg_angle, const double& prec) const;
 
 /**
@@ -350,14 +347,14 @@ private:
  * estimated angle tolerance. If this fails to produce a rectangle with the right density of region points,
  * 'reduce_region_radius' is called to try to satisfy this condition.
  */
-    bool refine(std::vector<RegionPoint>& reg, int& reg_size, double reg_angle,
+    bool refine(std::vector<RegionPoint>& reg, double reg_angle,
                 const double prec, double p, rect& rec, const double& density_th);
 
 /**
  * Reduce the region size, by elimination the points far from the starting point, until that leads to
  * rectangle with the right density of region points or to discard the region if too small.
  */
-    bool reduce_region_radius(std::vector<RegionPoint>& reg, int& reg_size, double reg_angle,
+    bool reduce_region_radius(std::vector<RegionPoint>& reg, double reg_angle,
                 const double prec, double p, rect& rec, double density, const double& density_th);
 
 /**
@@ -383,7 +380,7 @@ private:
  * Is the point at place 'address' aligned to angle theta, up to precision 'prec'?
  * @return      Whether the point is aligned.
  */
-    bool isAligned(const int& address, const double& theta, const double& prec) const;
+    bool isAligned(int x, int y, const double& theta, const double& prec) const;
 };
 
 /////////////////////////////////////////////////////////////////////////////////////////
@@ -412,11 +409,10 @@ LineSegmentDetectorImpl::LineSegmentDetectorImpl(int _refine, double _scale, dou
 void LineSegmentDetectorImpl::detect(InputArray _image, OutputArray _lines,
                 OutputArray _width, OutputArray _prec, OutputArray _nfa)
 {
-    Mat_<double> img = _image.getMat();
-    CV_Assert(!img.empty() && img.channels() == 1);
+    CV_INSTRUMENT_REGION()
 
-    // Convert image to double
-    img.convertTo(image, CV_64FC1);
+    image = _image.getMat();
+    CV_Assert(!image.empty() && image.type() == CV_8UC1);
 
     std::vector<Vec4f> lines;
     std::vector<double> w, p, n;
@@ -444,7 +440,6 @@ void LineSegmentDetectorImpl::flsd(std::vector<Vec4f>& lines,
     const double p = ANG_TH / 180;
     const double rho = QUANT / sin(prec);    // gradient magnitude threshold
 
-    std::vector<coorlist> list;
     if(SCALE != 1)
     {
         Mat gaussian_img;
@@ -455,45 +450,43 @@ void LineSegmentDetectorImpl::flsd(std::vector<Vec4f>& lines,
         GaussianBlur(image, gaussian_img, ksize, sigma);
         // Scale image to needed size
         resize(gaussian_img, scaled_image, Size(), SCALE, SCALE);
-        ll_angle(rho, N_BINS, list);
+        ll_angle(rho, N_BINS);
     }
     else
     {
         scaled_image = image;
-        ll_angle(rho, N_BINS, list);
+        ll_angle(rho, N_BINS);
     }
 
     LOG_NT = 5 * (log10(double(img_width)) + log10(double(img_height))) / 2 + log10(11.0);
-    const int min_reg_size = int(-LOG_NT/log10(p)); // minimal number of points in region that can give a meaningful event
+    const size_t min_reg_size = size_t(-LOG_NT/log10(p)); // minimal number of points in region that can give a meaningful event
 
     // // Initialize region only when needed
     // Mat region = Mat::zeros(scaled_image.size(), CV_8UC1);
     used = Mat_<uchar>::zeros(scaled_image.size()); // zeros = NOTUSED
-    std::vector<RegionPoint> reg(img_width * img_height);
+    std::vector<RegionPoint> reg;
 
     // Search for line segments
-    unsigned int ls_count = 0;
     for(size_t i = 0, list_size = list.size(); i < list_size; ++i)
     {
-        unsigned int adx = list[i].p.x + list[i].p.y * img_width;
-        if((used.ptr()[adx] == NOTUSED) && (angles_data[adx] != NOTDEF))
+        const Point2i& point = list[i].p;
+        if((used.at<uchar>(point) == NOTUSED) && (angles.at<double>(point) != NOTDEF))
         {
-            int reg_size;
             double reg_angle;
-            region_grow(list[i].p, reg, reg_size, reg_angle, prec);
+            region_grow(list[i].p, reg, reg_angle, prec);
 
             // Ignore small regions
-            if(reg_size < min_reg_size) { continue; }
+            if(reg.size() < min_reg_size) { continue; }
 
             // Construct rectangular approximation for the region
             rect rec;
-            region2rect(reg, reg_size, reg_angle, prec, p, rec);
+            region2rect(reg, reg_angle, prec, p, rec);
 
             double log_nfa = -1;
             if(doRefine > LSD_REFINE_NONE)
             {
                 // At least REFINE_STANDARD lvl.
-                if(!refine(reg, reg_size, reg_angle, prec, p, rec, DENSITY_TH)) { continue; }
+                if(!refine(reg, reg_angle, prec, p, rec, DENSITY_TH)) { continue; }
 
                 if(doRefine >= LSD_REFINE_ADV)
                 {
@@ -503,7 +496,6 @@ void LineSegmentDetectorImpl::flsd(std::vector<Vec4f>& lines,
                 }
             }
             // Found new line
-            ++ls_count;
 
             // Add the offset
             rec.x1 += 0.5; rec.y1 += 0.5;
@@ -522,29 +514,17 @@ void LineSegmentDetectorImpl::flsd(std::vector<Vec4f>& lines,
             if(w_needed) widths.push_back(rec.width);
             if(p_needed) precisions.push_back(rec.p);
             if(n_needed && doRefine >= LSD_REFINE_ADV) nfas.push_back(log_nfa);
-
-
-            // //Add the linesID to the region on the image
-            // for(unsigned int el = 0; el < reg_size; el++)
-            // {
-            //     region.data[reg[i].x + reg[i].y * width] = ls_count;
-            // }
         }
     }
 }
 
 void LineSegmentDetectorImpl::ll_angle(const double& threshold,
-                                   const unsigned int& n_bins,
-                                   std::vector<coorlist>& list)
+                                   const unsigned int& n_bins)
 {
     //Initialize data
     angles = Mat_<double>(scaled_image.size());
     modgrad = Mat_<double>(scaled_image.size());
 
-    angles_data = angles.ptr<double>(0);
-    modgrad_data = modgrad.ptr<double>(0);
-    scaled_image_data = scaled_image.ptr<double>(0);
-
     img_width = scaled_image.cols;
     img_height = scaled_image.rows;
 
@@ -553,30 +533,30 @@ void LineSegmentDetectorImpl::ll_angle(const double& threshold,
     angles.col(img_width - 1).setTo(NOTDEF);
 
     // Computing gradient for remaining pixels
-    CV_Assert(scaled_image.isContinuous() &&
-              modgrad.isContinuous() &&
-              angles.isContinuous());   // Accessing image data linearly
-
     double max_grad = -1;
     for(int y = 0; y < img_height - 1; ++y)
     {
-        for(int addr = y * img_width, addr_end = addr + img_width - 1; addr < addr_end; ++addr)
+        const uchar* scaled_image_row = scaled_image.ptr<uchar>(y);
+        const uchar* next_scaled_image_row = scaled_image.ptr<uchar>(y+1);
+        double* angles_row = angles.ptr<double>(y);
+        double* modgrad_row = modgrad.ptr<double>(y);
+        for(int x = 0; x < img_width-1; ++x)
         {
-            double DA = scaled_image_data[addr + img_width + 1] - scaled_image_data[addr];
-            double BC = scaled_image_data[addr + 1] - scaled_image_data[addr + img_width];
-            double gx = DA + BC;    // gradient x component
-            double gy = DA - BC;    // gradient y component
-            double norm = std::sqrt((gx * gx + gy * gy) / 4); // gradient norm
+            int DA = next_scaled_image_row[x + 1] - scaled_image_row[x];
+            int BC = scaled_image_row[x + 1] - next_scaled_image_row[x];
+            int gx = DA + BC;    // gradient x component
+            int gy = DA - BC;    // gradient y component
+            double norm = std::sqrt((gx * gx + gy * gy) / 4.0); // gradient norm
 
-            modgrad_data[addr] = norm;    // store gradient
+            modgrad_row[x] = norm;    // store gradient
 
             if (norm <= threshold)  // norm too small, gradient no defined
             {
-                angles_data[addr] = NOTDEF;
+                angles_row[x] = NOTDEF;
             }
             else
             {
-                angles_data[addr] = fastAtan2(float(gx), float(-gy)) * DEG_TO_RADS;  // gradient angle computation
+                angles_row[x] = fastAtan2(float(gx), float(-gy)) * DEG_TO_RADS;  // gradient angle computation
                 if (norm > max_grad) { max_grad = norm; }
             }
 
@@ -584,7 +564,7 @@ void LineSegmentDetectorImpl::ll_angle(const double& threshold,
     }
 
     // Compute histogram of gradient values
-    list = std::vector<coorlist>(img_width * img_height);
+    list.resize(img_width * img_height);
     std::vector<coorlist*> range_s(n_bins);
     std::vector<coorlist*> range_e(n_bins);
     unsigned int count = 0;
@@ -592,11 +572,11 @@ void LineSegmentDetectorImpl::ll_angle(const double& threshold,
 
     for(int y = 0; y < img_height - 1; ++y)
     {
-        const double* norm = modgrad_data + y * img_width;
-        for(int x = 0; x < img_width - 1; ++x, ++norm)
+        const double* modgrad_row = modgrad.ptr<double>(y);
+        for(int x = 0; x < img_width - 1; ++x)
         {
             // Store the point in the right bin according to its norm
-            int i = int((*norm) * bin_coef);
+            int i = int(modgrad_row[x] * bin_coef);
             if(!range_e[i])
             {
                 range_e[i] = range_s[i] = &list[count];
@@ -633,46 +613,51 @@ void LineSegmentDetectorImpl::ll_angle(const double& threshold,
 }
 
 void LineSegmentDetectorImpl::region_grow(const Point2i& s, std::vector<RegionPoint>& reg,
-                                      int& reg_size, double& reg_angle, const double& prec)
+                                      double& reg_angle, const double& prec)
 {
+    reg.clear();
+
     // Point to this region
-    reg_size = 1;
-    reg[0].x = s.x;
-    reg[0].y = s.y;
-    int addr = s.x + s.y * img_width;
-    reg[0].used = used.ptr() + addr;
-    reg_angle = angles_data[addr];
-    reg[0].angle = reg_angle;
-    reg[0].modgrad = modgrad_data[addr];
+    RegionPoint seed;
+    seed.x = s.x;
+    seed.y = s.y;
+    seed.used = &used.at<uchar>(s);
+    reg_angle = angles.at<double>(s);
+    seed.angle = reg_angle;
+    seed.modgrad = modgrad.at<double>(s);
+    reg.push_back(seed);
 
     float sumdx = float(std::cos(reg_angle));
     float sumdy = float(std::sin(reg_angle));
-    *reg[0].used = USED;
+    *seed.used = USED;
 
     //Try neighboring regions
-    for(int i = 0; i < reg_size; ++i)
+    for (size_t i = 0;i<reg.size();i++)
     {
         const RegionPoint& rpoint = reg[i];
         int xx_min = std::max(rpoint.x - 1, 0), xx_max = std::min(rpoint.x + 1, img_width - 1);
         int yy_min = std::max(rpoint.y - 1, 0), yy_max = std::min(rpoint.y + 1, img_height - 1);
         for(int yy = yy_min; yy <= yy_max; ++yy)
         {
-            int c_addr = xx_min + yy * img_width;
-            for(int xx = xx_min; xx <= xx_max; ++xx, ++c_addr)
+            uchar* used_row = used.ptr<uchar>(yy);
+            const double* angles_row = angles.ptr<double>(yy);
+            const double* modgrad_row = modgrad.ptr<double>(yy);
+            for(int xx = xx_min; xx <= xx_max; ++xx)
             {
-                if((used.ptr()[c_addr] != USED) &&
-                   (isAligned(c_addr, reg_angle, prec)))
+                uchar& is_used = used_row[xx];
+                if(is_used != USED &&
+                   (isAligned(xx, yy, reg_angle, prec)))
                 {
+                    const double& angle = angles_row[xx];
                     // Add point
-                    used.ptr()[c_addr] = USED;
-                    RegionPoint& region_point = reg[reg_size];
+                    is_used = USED;
+                    RegionPoint region_point;
                     region_point.x = xx;
                     region_point.y = yy;
-                    region_point.used = &(used.ptr()[c_addr]);
-                    region_point.modgrad = modgrad_data[c_addr];
-                    const double& angle = angles_data[c_addr];
+                    region_point.used = &is_used;
+                    region_point.modgrad = modgrad_row[xx];
                     region_point.angle = angle;
-                    ++reg_size;
+                    reg.push_back(region_point);
 
                     // Update region's angle
                     sumdx += cos(float(angle));
@@ -685,11 +670,11 @@ void LineSegmentDetectorImpl::region_grow(const Point2i& s, std::vector<RegionPo
     }
 }
 
-void LineSegmentDetectorImpl::region2rect(const std::vector<RegionPoint>& reg, const int reg_size,
+void LineSegmentDetectorImpl::region2rect(const std::vector<RegionPoint>& reg,
                                       const double reg_angle, const double prec, const double p, rect& rec) const
 {
     double x = 0, y = 0, sum = 0;
-    for(int i = 0; i < reg_size; ++i)
+    for(size_t i = 0; i < reg.size(); ++i)
     {
         const RegionPoint& pnt = reg[i];
         const double& weight = pnt.modgrad;
@@ -704,14 +689,14 @@ void LineSegmentDetectorImpl::region2rect(const std::vector<RegionPoint>& reg, c
     x /= sum;
     y /= sum;
 
-    double theta = get_theta(reg, reg_size, x, y, reg_angle, prec);
+    double theta = get_theta(reg, x, y, reg_angle, prec);
 
     // Find length and width
     double dx = cos(theta);
     double dy = sin(theta);
     double l_min = 0, l_max = 0, w_min = 0, w_max = 0;
 
-    for(int i = 0; i < reg_size; ++i)
+    for(size_t i = 0; i < reg.size(); ++i)
     {
         double regdx = double(reg[i].x) - x;
         double regdy = double(reg[i].y) - y;
@@ -743,7 +728,7 @@ void LineSegmentDetectorImpl::region2rect(const std::vector<RegionPoint>& reg, c
     if(rec.width < 1.0) rec.width = 1.0;
 }
 
-double LineSegmentDetectorImpl::get_theta(const std::vector<RegionPoint>& reg, const int& reg_size, const double& x,
+double LineSegmentDetectorImpl::get_theta(const std::vector<RegionPoint>& reg, const double& x,
                                       const double& y, const double& reg_angle, const double& prec) const
 {
     double Ixx = 0.0;
@@ -751,7 +736,7 @@ double LineSegmentDetectorImpl::get_theta(const std::vector<RegionPoint>& reg, c
     double Ixy = 0.0;
 
     // Compute inertia matrix
-    for(int i = 0; i < reg_size; ++i)
+    for(size_t i = 0; i < reg.size(); ++i)
     {
         const double& regx = reg[i].x;
         const double& regy = reg[i].y;
@@ -781,10 +766,10 @@ double LineSegmentDetectorImpl::get_theta(const std::vector<RegionPoint>& reg, c
     return theta;
 }
 
-bool LineSegmentDetectorImpl::refine(std::vector<RegionPoint>& reg, int& reg_size, double reg_angle,
+bool LineSegmentDetectorImpl::refine(std::vector<RegionPoint>& reg, double reg_angle,
                                  const double prec, double p, rect& rec, const double& density_th)
 {
-    double density = double(reg_size) / (dist(rec.x1, rec.y1, rec.x2, rec.y2) * rec.width);
+    double density = double(reg.size()) / (dist(rec.x1, rec.y1, rec.x2, rec.y2) * rec.width);
 
     if (density >= density_th) { return true; }
 
@@ -795,7 +780,7 @@ bool LineSegmentDetectorImpl::refine(std::vector<RegionPoint>& reg, int& reg_siz
     double sum = 0, s_sum = 0;
     int n = 0;
 
-    for (int i = 0; i < reg_size; ++i)
+    for (size_t i = 0; i < reg.size(); ++i)
     {
         *(reg[i].used) = NOTUSED;
         if (dist(xc, yc, reg[i].x, reg[i].y) < rec.width)
@@ -812,16 +797,16 @@ bool LineSegmentDetectorImpl::refine(std::vector<RegionPoint>& reg, int& reg_siz
     double tau = 2.0 * sqrt((s_sum - 2.0 * mean_angle * sum) / double(n) + mean_angle * mean_angle);
 
     // Try new region
-    region_grow(Point(reg[0].x, reg[0].y), reg, reg_size, reg_angle, tau);
+    region_grow(Point(reg[0].x, reg[0].y), reg, reg_angle, tau);
 
-    if (reg_size < 2) { return false; }
+    if (reg.size() < 2) { return false; }
 
-    region2rect(reg, reg_size, reg_angle, prec, p, rec);
-    density = double(reg_size) / (dist(rec.x1, rec.y1, rec.x2, rec.y2) * rec.width);
+    region2rect(reg, reg_angle, prec, p, rec);
+    density = double(reg.size()) / (dist(rec.x1, rec.y1, rec.x2, rec.y2) * rec.width);
 
     if (density < density_th)
     {
-        return reduce_region_radius(reg, reg_size, reg_angle, prec, p, rec, density, density_th);
+        return reduce_region_radius(reg, reg_angle, prec, p, rec, density, density_th);
     }
     else
     {
@@ -829,7 +814,7 @@ bool LineSegmentDetectorImpl::refine(std::vector<RegionPoint>& reg, int& reg_siz
     }
 }
 
-bool LineSegmentDetectorImpl::reduce_region_radius(std::vector<RegionPoint>& reg, int& reg_size, double reg_angle,
+bool LineSegmentDetectorImpl::reduce_region_radius(std::vector<RegionPoint>& reg, double reg_angle,
                 const double prec, double p, rect& rec, double density, const double& density_th)
 {
     // Compute region's radius
@@ -843,25 +828,25 @@ bool LineSegmentDetectorImpl::reduce_region_radius(std::vector<RegionPoint>& reg
     {
         radSq *= 0.75*0.75; // Reduce region's radius to 75% of its value
         // Remove points from the region and update 'used' map
-        for(int i = 0; i < reg_size; ++i)
+        for (size_t i = 0; i < reg.size(); ++i)
         {
             if(distSq(xc, yc, double(reg[i].x), double(reg[i].y)) > radSq)
             {
                 // Remove point from the region
                 *(reg[i].used) = NOTUSED;
-                std::swap(reg[i], reg[reg_size - 1]);
-                --reg_size;
+                std::swap(reg[i], reg[reg.size() - 1]);
+                reg.pop_back();
                 --i; // To avoid skipping one point
             }
         }
 
-        if(reg_size < 2) { return false; }
+        if(reg.size() < 2) { return false; }
 
         // Re-compute rectangle
-        region2rect(reg, reg_size ,reg_angle, prec, p, rec);
+        region2rect(reg ,reg_angle, prec, p, rec);
 
         // Re-compute region points density
-        density = double(reg_size) /
+        density = double(reg.size()) /
                   (dist(rec.x1, rec.y1, rec.x2, rec.y2) * rec.width);
     }
 
@@ -979,7 +964,7 @@ double LineSegmentDetectorImpl::rect_nfa(const rect& rec) const
     double dyhw = rec.dy * half_width;
     double dxhw = rec.dx * half_width;
 
-    std::vector<edge> ordered_x(4);
+    edge ordered_x[4];
     edge* min_y = &ordered_x[0];
     edge* max_y = &ordered_x[0]; // Will be used for loop range
 
@@ -988,7 +973,7 @@ double LineSegmentDetectorImpl::rect_nfa(const rect& rec) const
     ordered_x[2].p.x = int(rec.x2 + dyhw); ordered_x[2].p.y = int(rec.y2 - dxhw); ordered_x[2].taken = false;
     ordered_x[3].p.x = int(rec.x1 + dyhw); ordered_x[3].p.y = int(rec.y1 - dxhw); ordered_x[3].taken = false;
 
-    std::sort(ordered_x.begin(), ordered_x.end(), AsmallerB_XoverY);
+    std::sort(ordered_x, ordered_x + 4, AsmallerB_XoverY);
 
     // Find min y. And mark as taken. find max y.
     for(unsigned int i = 1; i < 4; ++i)
@@ -1073,13 +1058,12 @@ double LineSegmentDetectorImpl::rect_nfa(const rect& rec) const
     {
         if (y < 0 || y >= img_height) continue;
 
-        int adx = y * img_width + int(left_x);
-        for(int x = int(left_x); x <= int(right_x); ++x, ++adx)
+        for(int x = int(left_x); x <= int(right_x); ++x)
         {
             if (x < 0 || x >= img_width) continue;
 
             ++total_pts;
-            if(isAligned(adx, rec.theta, rec.prec))
+            if(isAligned(x, y, rec.theta, rec.prec))
             {
                 ++alg_pts;
             }
@@ -1133,10 +1117,10 @@ double LineSegmentDetectorImpl::nfa(const int& n, const int& k, const double& p)
     return -log10(bin_tail) - LOG_NT;
 }
 
-inline bool LineSegmentDetectorImpl::isAligned(const int& address, const double& theta, const double& prec) const
+inline bool LineSegmentDetectorImpl::isAligned(int x, int y, const double& theta, const double& prec) const
 {
-    if(address < 0) { return false; }
-    const double& a = angles_data[address];
+    if(x < 0 || y < 0 || x >= angles.cols || y >= angles.rows) { return false; }
+    const double& a = angles.at<double>(y, x);
     if(a == NOTDEF) { return false; }
 
     // It is assumed that 'theta' and 'a' are in the range [-pi,pi]
@@ -1154,6 +1138,8 @@ inline bool LineSegmentDetectorImpl::isAligned(const int& address, const double&
 
 void LineSegmentDetectorImpl::drawSegments(InputOutputArray _image, InputArray lines)
 {
+    CV_INSTRUMENT_REGION()
+
     CV_Assert(!_image.empty() && (_image.channels() == 1 || _image.channels() == 3));
 
     Mat gray;
@@ -1191,6 +1177,8 @@ void LineSegmentDetectorImpl::drawSegments(InputOutputArray _image, InputArray l
 
 int LineSegmentDetectorImpl::compareSegments(const Size& size, InputArray lines1, InputArray lines2, InputOutputArray _image)
 {
+    CV_INSTRUMENT_REGION()
+
     Size sz = size;
     if (_image.needed() && _image.size() != size) sz = _image.size();
     CV_Assert(sz.area());
diff --git a/modules/imgproc/src/matchcontours.cpp b/modules/imgproc/src/matchcontours.cpp
index 1ac6c16..1a37167 100644
--- a/modules/imgproc/src/matchcontours.cpp
+++ b/modules/imgproc/src/matchcontours.cpp
@@ -43,6 +43,8 @@
 
 double cv::matchShapes(InputArray contour1, InputArray contour2, int method, double)
 {
+    CV_INSTRUMENT_REGION()
+
     double ma[7], mb[7];
     int i, sma, smb;
     double eps = 1.e-5;
diff --git a/modules/imgproc/src/moments.cpp b/modules/imgproc/src/moments.cpp
index 15c4a61..d445ed2 100644
--- a/modules/imgproc/src/moments.cpp
+++ b/modules/imgproc/src/moments.cpp
@@ -227,16 +227,15 @@ struct MomentsInTile_SIMD<uchar, int, int>
 
         if( useSIMD )
         {
-            __m128i qx_init = _mm_setr_epi16(0, 1, 2, 3, 4, 5, 6, 7);
             __m128i dx = _mm_set1_epi16(8);
-            __m128i z = _mm_setzero_si128(), qx0 = z, qx1 = z, qx2 = z, qx3 = z, qx = qx_init;
+            __m128i z = _mm_setzero_si128(), qx0 = z, qx1 = z, qx2 = z, qx3 = z, qx = _mm_setr_epi16(0, 1, 2, 3, 4, 5, 6, 7);
 
             for( ; x <= len - 8; x += 8 )
             {
                 __m128i p = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i*)(ptr + x)), z);
                 __m128i sx = _mm_mullo_epi16(qx, qx);
 
-                qx0 = _mm_add_epi32(qx0, _mm_sad_epu8(p, z));
+                qx0 = _mm_add_epi16(qx0, p);
                 qx1 = _mm_add_epi32(qx1, _mm_madd_epi16(p, qx));
                 qx2 = _mm_add_epi32(qx2, _mm_madd_epi16(p, sx));
                 qx3 = _mm_add_epi32(qx3, _mm_madd_epi16( _mm_mullo_epi16(p, qx), sx));
@@ -244,14 +243,21 @@ struct MomentsInTile_SIMD<uchar, int, int>
                 qx = _mm_add_epi16(qx, dx);
             }
 
-            _mm_store_si128((__m128i*)buf, qx0);
-            x0 = buf[0] + buf[1] + buf[2] + buf[3];
-            _mm_store_si128((__m128i*)buf, qx1);
-            x1 = buf[0] + buf[1] + buf[2] + buf[3];
-            _mm_store_si128((__m128i*)buf, qx2);
-            x2 = buf[0] + buf[1] + buf[2] + buf[3];
-            _mm_store_si128((__m128i*)buf, qx3);
-            x3 = buf[0] + buf[1] + buf[2] + buf[3];
+            __m128i qx01_lo = _mm_unpacklo_epi32(qx0, qx1);
+            __m128i qx23_lo = _mm_unpacklo_epi32(qx2, qx3);
+            __m128i qx01_hi = _mm_unpackhi_epi32(qx0, qx1);
+            __m128i qx23_hi = _mm_unpackhi_epi32(qx2, qx3);
+            qx01_lo = _mm_add_epi32(qx01_lo, qx01_hi);
+            qx23_lo = _mm_add_epi32(qx23_lo, qx23_hi);
+            __m128i qx0123_lo = _mm_unpacklo_epi64(qx01_lo, qx23_lo);
+            __m128i qx0123_hi = _mm_unpackhi_epi64(qx01_lo, qx23_lo);
+            qx0123_lo = _mm_add_epi32(qx0123_lo, qx0123_hi);
+            _mm_store_si128((__m128i*)buf, qx0123_lo);
+
+            x0 = (buf[0] & 0xffff) + (buf[0] >> 16);
+            x1 = buf[1];
+            x2 = buf[2];
+            x3 = buf[3];
         }
 
         return x;
@@ -345,37 +351,42 @@ struct MomentsInTile_SIMD<ushort, int, int64>
 
         if (useSIMD)
         {
-            __m128i vx_init0 = _mm_setr_epi32(0, 1, 2, 3), vx_init1 = _mm_setr_epi32(4, 5, 6, 7),
-                v_delta = _mm_set1_epi32(8), v_zero = _mm_setzero_si128(), v_x0 = v_zero,
-                v_x1 = v_zero, v_x2 = v_zero, v_x3 = v_zero, v_ix0 = vx_init0, v_ix1 = vx_init1;
+            __m128i v_delta = _mm_set1_epi32(4), v_zero = _mm_setzero_si128(), v_x0 = v_zero,
+                v_x1 = v_zero, v_x2 = v_zero, v_x3 = v_zero, v_ix0 = _mm_setr_epi32(0, 1, 2, 3);
 
-            for( ; x <= len - 8; x += 8 )
+            for( ; x <= len - 4; x += 4 )
             {
-                __m128i v_src = _mm_loadu_si128((const __m128i *)(ptr + x));
-                __m128i v_src0 = _mm_unpacklo_epi16(v_src, v_zero), v_src1 = _mm_unpackhi_epi16(v_src, v_zero);
+                __m128i v_src = _mm_loadl_epi64((const __m128i *)(ptr + x));
+                v_src = _mm_unpacklo_epi16(v_src, v_zero);
 
-                v_x0 = _mm_add_epi32(v_x0, _mm_add_epi32(v_src0, v_src1));
-                __m128i v_x1_0 = _mm_mullo_epi32(v_src0, v_ix0), v_x1_1 = _mm_mullo_epi32(v_src1, v_ix1);
-                v_x1 = _mm_add_epi32(v_x1, _mm_add_epi32(v_x1_0, v_x1_1));
+                v_x0 = _mm_add_epi32(v_x0, v_src);
+                v_x1 = _mm_add_epi32(v_x1, _mm_mullo_epi32(v_src, v_ix0));
 
-                __m128i v_2ix0 = _mm_mullo_epi32(v_ix0, v_ix0), v_2ix1 = _mm_mullo_epi32(v_ix1, v_ix1);
-                v_x2 = _mm_add_epi32(v_x2, _mm_add_epi32(_mm_mullo_epi32(v_2ix0, v_src0), _mm_mullo_epi32(v_2ix1, v_src1)));
+                __m128i v_ix1 = _mm_mullo_epi32(v_ix0, v_ix0);
+                v_x2 = _mm_add_epi32(v_x2, _mm_mullo_epi32(v_src, v_ix1));
 
-                __m128i t = _mm_add_epi32(_mm_mullo_epi32(v_2ix0, v_x1_0), _mm_mullo_epi32(v_2ix1, v_x1_1));
-                v_x3 = _mm_add_epi64(v_x3, _mm_add_epi64(_mm_unpacklo_epi32(t, v_zero), _mm_unpackhi_epi32(t, v_zero)));
+                v_ix1 = _mm_mullo_epi32(v_ix0, v_ix1);
+                v_src = _mm_mullo_epi32(v_src, v_ix1);
+                v_x3 = _mm_add_epi64(v_x3, _mm_add_epi64(_mm_unpacklo_epi32(v_src, v_zero), _mm_unpackhi_epi32(v_src, v_zero)));
 
                 v_ix0 = _mm_add_epi32(v_ix0, v_delta);
-                v_ix1 = _mm_add_epi32(v_ix1, v_delta);
             }
 
-            _mm_store_si128((__m128i*)buf, v_x0);
-            x0 = buf[0] + buf[1] + buf[2] + buf[3];
-            _mm_store_si128((__m128i*)buf, v_x1);
-            x1 = buf[0] + buf[1] + buf[2] + buf[3];
-            _mm_store_si128((__m128i*)buf, v_x2);
-            x2 = buf[0] + buf[1] + buf[2] + buf[3];
-
+            __m128i v_x01_lo = _mm_unpacklo_epi32(v_x0, v_x1);
+            __m128i v_x22_lo = _mm_unpacklo_epi32(v_x2, v_x2);
+            __m128i v_x01_hi = _mm_unpackhi_epi32(v_x0, v_x1);
+            __m128i v_x22_hi = _mm_unpackhi_epi32(v_x2, v_x2);
+            v_x01_lo = _mm_add_epi32(v_x01_lo, v_x01_hi);
+            v_x22_lo = _mm_add_epi32(v_x22_lo, v_x22_hi);
+            __m128i v_x0122_lo = _mm_unpacklo_epi64(v_x01_lo, v_x22_lo);
+            __m128i v_x0122_hi = _mm_unpackhi_epi64(v_x01_lo, v_x22_lo);
+            v_x0122_lo = _mm_add_epi32(v_x0122_lo, v_x0122_hi);
             _mm_store_si128((__m128i*)buf64, v_x3);
+            _mm_store_si128((__m128i*)buf, v_x0122_lo);
+
+            x0 = buf[0];
+            x1 = buf[1];
+            x2 = buf[2];
             x3 = buf64[0] + buf64[1];
         }
 
@@ -555,6 +566,8 @@ static bool ocl_moments( InputArray _src, Moments& m, bool binary)
 
 cv::Moments cv::moments( InputArray _src, bool binary )
 {
+    CV_INSTRUMENT_REGION()
+
     const int TILE_SIZE = 32;
     MomentsInTileFunc func = 0;
     uchar nzbuf[TILE_SIZE*TILE_SIZE];
@@ -598,7 +611,7 @@ cv::Moments cv::moments( InputArray _src, bool binary )
 
                     if (ippFunc)
                     {
-                        if (ippFunc(mat.data, (int)mat.step, roi, moment) >= 0)
+                        if (CV_INSTRUMENT_FUN_IPP(ippFunc,(mat.data, (int)mat.step, roi, moment)) >= 0)
                         {
                             IppiPoint point = { 0, 0 };
                             ippiGetSpatialMoment_64f(moment, 0, 0, 0, point, &m.m00);
@@ -729,6 +742,8 @@ cv::Moments cv::moments( InputArray _src, bool binary )
 
 void cv::HuMoments( const Moments& m, double hu[7] )
 {
+    CV_INSTRUMENT_REGION()
+
     double t0 = m.nu30 + m.nu12;
     double t1 = m.nu21 + m.nu03;
 
@@ -756,6 +771,8 @@ void cv::HuMoments( const Moments& m, double hu[7] )
 
 void cv::HuMoments( const Moments& m, OutputArray _hu )
 {
+    CV_INSTRUMENT_REGION()
+
     _hu.create(7, 1, CV_64F);
     Mat hu = _hu.getMat();
     CV_Assert( hu.isContinuous() );
diff --git a/modules/imgproc/src/morph.cpp b/modules/imgproc/src/morph.cpp
index 49ddb2d..52c3411 100644
--- a/modules/imgproc/src/morph.cpp
+++ b/modules/imgproc/src/morph.cpp
@@ -43,11 +43,15 @@
 #include "precomp.hpp"
 #include <limits.h>
 #include "opencl_kernels_imgproc.hpp"
+#include <iostream>
+#include "hal_replacement.hpp"
 
 /****************************************************************************************\
                      Basic Morphological Operations: Erosion & Dilation
 \****************************************************************************************/
 
+using namespace std;
+
 namespace cv
 {
 
@@ -584,19 +588,11 @@ typedef MorphFVec<VMax32f> DilateVec32f;
 
 #else
 
-#ifdef HAVE_TEGRA_OPTIMIZATION
-using tegra::ErodeRowVec8u;
-using tegra::DilateRowVec8u;
-
-using tegra::ErodeColumnVec8u;
-using tegra::DilateColumnVec8u;
-#else
 typedef MorphRowNoVec ErodeRowVec8u;
 typedef MorphRowNoVec DilateRowVec8u;
 
 typedef MorphColumnNoVec ErodeColumnVec8u;
 typedef MorphColumnNoVec DilateColumnVec8u;
-#endif
 
 typedef MorphRowNoVec ErodeRowVec16u;
 typedef MorphRowNoVec DilateRowVec16u;
@@ -1081,303 +1077,478 @@ cv::Mat cv::getStructuringElement(int shape, Size ksize, Point anchor)
 namespace cv
 {
 
-class MorphologyRunner : public ParallelLoopBody
+// ===== 1. replacement implementation
+
+struct ReplacementMorphImpl : public hal::Morph
 {
-public:
-    MorphologyRunner(Mat _src, Mat _dst, int _nStripes, int _iterations,
-                     int _op, Mat _kernel, Point _anchor,
-                     int _rowBorderType, int _columnBorderType, const Scalar& _borderValue) :
-        borderValue(_borderValue)
+    cvhalFilter2D * ctx;
+    bool isInitialized;
+    bool init(int op, int src_type, int dst_type, int max_width, int max_height,
+              int kernel_type, uchar * kernel_data, size_t kernel_step, int kernel_width, int kernel_height,
+              int anchor_x, int anchor_y,
+              int borderType, const double borderValue[4],
+    int iterations, bool isSubmatrix, bool allowInplace)
     {
-        src = _src;
-        dst = _dst;
-
-        nStripes = _nStripes;
-        iterations = _iterations;
-
-        op = _op;
-        kernel = _kernel;
-        anchor = _anchor;
-        rowBorderType = _rowBorderType;
-        columnBorderType = _columnBorderType;
+        int res = cv_hal_morphInit(&ctx, op, src_type, dst_type, max_width, max_height,
+                                   kernel_type, kernel_data, kernel_step, kernel_width, kernel_height,
+                                   anchor_x, anchor_y,
+                                   borderType, borderValue,
+                                   iterations, isSubmatrix, allowInplace);
+        isInitialized = (res == CV_HAL_ERROR_OK);
+        return isInitialized;
     }
-
-    void operator () ( const Range& range ) const
+    void apply(uchar * src_data, size_t src_step, uchar * dst_data, size_t dst_step, int width, int height,
+               int roi_width, int roi_height, int roi_x, int roi_y,
+               int roi_width2, int roi_height2, int roi_x2, int roi_y2)
     {
-        int row0 = std::min(cvRound(range.start * src.rows / nStripes), src.rows);
-        int row1 = std::min(cvRound(range.end * src.rows / nStripes), src.rows);
+        if (isInitialized)
+        {
+            int res = cv_hal_morph(ctx, src_data, src_step, dst_data, dst_step, width, height,
+                                   roi_width, roi_height,
+                                   roi_x, roi_y,
+                                   roi_width2, roi_height2,
+                                   roi_x2, roi_y2);
+            if (res != CV_HAL_ERROR_OK)
+                CV_Error(Error::StsNotImplemented, "Failed to run HAL morph implementation");
+        }
+    }
+    ~ReplacementMorphImpl()
+    {
+        if (isInitialized)
+        {
+            int res = cv_hal_morphFree(ctx);
+            if (res != CV_HAL_ERROR_OK)
+                CV_Error(Error::StsNotImplemented, "Failed to run HAL morph implementation");
+        }
+    }
+};
 
-        /*if(0)
-            printf("Size = (%d, %d), range[%d,%d), row0 = %d, row1 = %d\n",
-                   src.rows, src.cols, range.start, range.end, row0, row1);*/
+// ===== 2. IPP implementation
 
-        Mat srcStripe = src.rowRange(row0, row1);
-        Mat dstStripe = dst.rowRange(row0, row1);
+#ifdef HAVE_IPP
 
-        Ptr<FilterEngine> f = createMorphologyFilter(op, src.type(), kernel, anchor,
-                                                     rowBorderType, columnBorderType, borderValue );
+#if IPP_VERSION_X100 >= 810
 
-        f->apply( srcStripe, dstStripe );
-        for( int i = 1; i < iterations; i++ )
-            f->apply( dstStripe, dstStripe );
-    }
+template <int cvtype> struct IppMorphTrait {};
 
-private:
-    Mat src;
-    Mat dst;
-    int nStripes;
-    int iterations;
+#if IPP_VERSION_X100 >= 900
 
-    int op;
-    Mat kernel;
-    Point anchor;
-    int rowBorderType;
-    int columnBorderType;
-    Scalar borderValue;
+#define INIT_TRAIT(cvtype, ipptype, flavor, channels, zerodef)\
+template <>\
+struct IppMorphTrait<cvtype>\
+{\
+    typedef Ipp##ipptype ipp_data_type;\
+    enum { cn = channels };\
+    IppDataType getDataType() {return ipp##ipptype;}\
+\
+    IppStatus getMorphSize(IppiSize roiSize, IppiSize maskSize, int* pSpecSize, int* pBufferSize) {return ippiMorphologyBorderGetSize_##flavor(roiSize, maskSize, pSpecSize, pBufferSize);}\
+    IppStatus morphInit(IppiSize roiSize, const Ipp8u* pMask, IppiSize maskSize, IppiMorphState* pMorphSpec, Ipp8u* pBuffer) {return ippiMorphologyBorderInit_##flavor(roiSize, pMask, maskSize, pMorphSpec, pBuffer);}\
+    IppStatus filterGetMinSize(IppiSize dstRoiSize, IppiSize maskSize, IppDataType dataType, int numChannels, int* pBufferSize) {return ippiFilterMinBorderGetBufferSize(dstRoiSize, maskSize, dataType, numChannels, pBufferSize);}\
+    IppStatus filterGetMaxSize(IppiSize dstRoiSize, IppiSize maskSize, IppDataType dataType, int numChannels, int* pBufferSize) {return ippiFilterMaxBorderGetBufferSize(dstRoiSize, maskSize, dataType, numChannels, pBufferSize);}\
+    IppStatus filterMinBorder(const ipp_data_type* pSrc, int srcStep, ipp_data_type* pDst, int dstStep, IppiSize dstRoiSize, IppiSize maskSize, IppiPoint, Ipp8u* pBuffer) { ipp_data_type zerodef; return CV_INSTRUMENT_FUN_IPP(ippiFilterMinBorder_##flavor, pSrc, srcStep, pDst, dstStep, dstRoiSize, maskSize, ippBorderRepl, zero, pBuffer); }\
+    IppStatus filterMaxBorder(const ipp_data_type* pSrc, int srcStep, ipp_data_type* pDst, int dstStep, IppiSize dstRoiSize, IppiSize maskSize, IppiPoint, Ipp8u* pBuffer) { ipp_data_type zerodef; return CV_INSTRUMENT_FUN_IPP(ippiFilterMaxBorder_##flavor, pSrc, srcStep, pDst, dstStep, dstRoiSize, maskSize, ippBorderRepl, zero, pBuffer); }\
+    IppStatus morphDilate(const ipp_data_type* pSrc, int srcStep, ipp_data_type* pDst, int dstStep, IppiSize roiSize, const IppiMorphState* pMorphSpec, Ipp8u* pBuffer) { ipp_data_type zerodef; return CV_INSTRUMENT_FUN_IPP(ippiDilateBorder_##flavor, pSrc, srcStep, pDst, dstStep, roiSize, ippBorderRepl, zero, pMorphSpec, pBuffer); }\
+    IppStatus morphErode(const ipp_data_type* pSrc, int srcStep, ipp_data_type* pDst, int dstStep, IppiSize roiSize,  const IppiMorphState* pMorphSpec, Ipp8u* pBuffer) { ipp_data_type zerodef; return CV_INSTRUMENT_FUN_IPP(ippiErodeBorder_##flavor, pSrc, srcStep, pDst, dstStep, roiSize, ippBorderRepl, zero, pMorphSpec, pBuffer); }\
 };
 
-#ifdef HAVE_IPP
-static bool ipp_MorphReplicate(int op, const Mat &src, Mat &dst, const Mat &kernel,
-                              const Size& ksize, const Point &anchor, bool rectKernel)
-{
-#if IPP_VERSION_X100 >= 810
-    int type = src.type();
-    const Mat* _src = &src;
-    Mat temp;
-    if (src.data == dst.data)
-    {
-        src.copyTo(temp);
-        _src = &temp;
-    }
+#else
+
+#define INIT_TRAIT(cvtype, ipptype, flavor, channels, zerodef)\
+template <>\
+struct IppMorphTrait<cvtype>\
+{\
+    typedef Ipp##ipptype ipp_data_type;\
+    enum { cn = channels };\
+    IppDataType getDataType() {return ipp##ipptype;}\
+\
+    IppStatus getMorphSize(IppiSize roiSize, IppiSize maskSize, int* pSpecSize, int* pBufferSize) {return ippiMorphologyBorderGetSize_##flavor(roiSize.width, maskSize, pSpecSize, pBufferSize);}\
+    IppStatus morphInit(IppiSize roiSize, const Ipp8u* pMask, IppiSize maskSize, IppiMorphState* pMorphSpec, Ipp8u* pBuffer) {return ippiMorphologyBorderInit_##flavor(roiSize.width, pMask, maskSize, pMorphSpec, pBuffer);}\
+    IppStatus filterGetMinSize(IppiSize dstRoiSize, IppiSize maskSize, IppDataType, int, int* pBufferSize) {return ippiFilterMinGetBufferSize_##flavor(dstRoiSize.width, maskSize, pBufferSize);}\
+    IppStatus filterGetMaxSize(IppiSize dstRoiSize, IppiSize maskSize, IppDataType, int, int* pBufferSize) {return ippiFilterMinGetBufferSize_##flavor(dstRoiSize.width, maskSize, pBufferSize);}\
+    IppStatus filterMinBorder(const ipp_data_type* pSrc, int srcStep, ipp_data_type* pDst, int dstStep, IppiSize dstRoiSize, IppiSize maskSize, IppiPoint anchor, Ipp8u* pBuffer) { return ippiFilterMinBorderReplicate_##flavor(pSrc, srcStep, pDst, dstStep, dstRoiSize, maskSize, anchor, pBuffer); }\
+    IppStatus filterMaxBorder(const ipp_data_type* pSrc, int srcStep, ipp_data_type* pDst, int dstStep, IppiSize dstRoiSize, IppiSize maskSize, IppiPoint anchor, Ipp8u* pBuffer) { return ippiFilterMaxBorderReplicate_##flavor(pSrc, srcStep, pDst, dstStep, dstRoiSize, maskSize, anchor, pBuffer); }\
+    IppStatus morphDilate(const ipp_data_type* pSrc, int srcStep, ipp_data_type* pDst, int dstStep, IppiSize roiSize, const IppiMorphState* pMorphSpec, Ipp8u* pBuffer) {return ippiDilateBorder_##flavor(pSrc, srcStep, pDst, dstStep, roiSize, ippBorderRepl, 0, pMorphSpec, pBuffer);}\
+    IppStatus morphErode(const ipp_data_type* pSrc, int srcStep, ipp_data_type* pDst, int dstStep, IppiSize roiSize, const IppiMorphState* pMorphSpec, Ipp8u* pBuffer) {return ippiErodeBorder_##flavor(pSrc, srcStep, pDst, dstStep, roiSize, ippBorderRepl, 0, pMorphSpec, pBuffer);}\
+};
+
+#endif
+
+INIT_TRAIT(CV_8UC1, 8u, 8u_C1R, 1, zero = 0)
+INIT_TRAIT(CV_8UC3, 8u, 8u_C3R, 3, zero[3] = {0})
+INIT_TRAIT(CV_8UC4, 8u, 8u_C4R, 4, zero[4] = {0})
+INIT_TRAIT(CV_32FC1, 32f, 32f_C1R, 1, zero = 0)
+INIT_TRAIT(CV_32FC3, 32f, 32f_C3R, 3, zero[3] = {0})
+INIT_TRAIT(CV_32FC4, 32f, 32f_C4R, 4, zero[4] = {0})
+
+#undef INIT_TRAIT
 
-    IppiSize roiSize = {src.cols, src.rows};
-    IppiSize kernelSize = {ksize.width, ksize.height};
+//--------------------------------------
 
-    if (!rectKernel)
+struct IppMorphBaseImpl : public hal::Morph
+{
+    virtual bool init(int _op, int _src_type, int dst_type, int max_width, int max_height,
+              int kernel_type, uchar * kernel_data, size_t kernel_step, int kernel_width, int kernel_height,
+              int anchor_x, int anchor_y,
+              int borderType, const double borderValue[4],
+              int iterations, bool isSubmatrix, bool allowInplace) = 0;
+};
+
+template <int cvtype>
+struct IppMorphImpl : public IppMorphBaseImpl
+{
+    IppMorphTrait<cvtype> trait;
+    typedef typename IppMorphTrait<cvtype>::ipp_data_type ipp_data_type;
+    IppAutoBuffer<IppiMorphState> specBuf;
+    IppAutoBuffer<Ipp8u> workBuf;
+    IppiSize kernelSize;
+    bool rectKernel;
+    IppiPoint anchor;
+    int op;
+    int src_type;
+    int border;
+
+    bool init(int _op, int _src_type, int dst_type, int max_width, int max_height,
+              int kernel_type, uchar * kernel_data, size_t kernel_step, int kernel_width, int kernel_height,
+              int anchor_x, int anchor_y,
+              int borderType, const double borderValue[4],
+              int iterations, bool isSubmatrix, bool allowInplace)
     {
-#if IPP_VERSION_X100 >= 900
-        if (((kernel.cols - 1) / 2 != anchor.x) || ((kernel.rows - 1) / 2 != anchor.y))
+        border = borderType; // TODO: remove
+        anchor = ippiPoint(anchor_x, anchor_y);
+        CV_UNUSED(dst_type);
+        src_type = _src_type;
+
+        Mat kernel(Size(kernel_width, kernel_height), kernel_type, kernel_data, kernel_step);
+        int depth = CV_MAT_DEPTH(src_type), cn = CV_MAT_CN(src_type);
+
+        if( !( depth == CV_8U || depth == CV_32F )
+            || !(cn == 1 || cn == 3 || cn == 4)
+            || !( borderType == cv::BORDER_REPLICATE
+                  || (borderType == cv::BORDER_CONSTANT && Vec<double, 4>(borderValue) == morphologyDefaultBorderValue() && kernel.size() == Size(3,3)))
+            || !( op == MORPH_DILATE || op == MORPH_ERODE)
+            || isSubmatrix
+            || allowInplace)
             return false;
-        #define IPP_MORPH_CASE(cvtype, flavor, data_type) \
-        case cvtype: \
-            {\
-                int specSize = 0, bufferSize = 0;\
-                if (0 > ippiMorphologyBorderGetSize_##flavor(roiSize, kernelSize, &specSize, &bufferSize))\
-                    return false;\
-                IppiMorphState *pSpec = (IppiMorphState*)ippMalloc(specSize);\
-                Ipp8u *pBuffer = (Ipp8u*)ippMalloc(bufferSize);\
-                if (0 > ippiMorphologyBorderInit_##flavor(roiSize, kernel.ptr(), kernelSize, pSpec, pBuffer))\
-                {\
-                    ippFree(pBuffer);\
-                    ippFree(pSpec);\
-                    return false;\
-                }\
-                bool ok = false;\
-                if (op == MORPH_ERODE)\
-                    ok = (0 <= ippiErodeBorder_##flavor(_src->ptr<Ipp##data_type>(), (int)_src->step[0], dst.ptr<Ipp##data_type>(), (int)dst.step[0],\
-                                            roiSize, ippBorderRepl, 0, pSpec, pBuffer));\
-                else\
-                    ok = (0 <= ippiDilateBorder_##flavor(_src->ptr<Ipp##data_type>(), (int)_src->step[0], dst.ptr<Ipp##data_type>(), (int)dst.step[0],\
-                                            roiSize, ippBorderRepl, 0, pSpec, pBuffer));\
-                ippFree(pBuffer);\
-                ippFree(pSpec);\
-                return ok;\
-            }\
-            break;
-#else
-        if (((kernel.cols - 1) / 2 != anchor.x) || ((kernel.rows - 1) / 2 != anchor.y))
-            return false;
-        #define IPP_MORPH_CASE(cvtype, flavor, data_type) \
-        case cvtype: \
-            {\
-                int specSize = 0, bufferSize = 0;\
-                if (0 > ippiMorphologyBorderGetSize_##flavor(roiSize.width, kernelSize, &specSize, &bufferSize))\
-                    return false;\
-                IppiMorphState *pSpec = (IppiMorphState*)ippMalloc(specSize);\
-                Ipp8u *pBuffer = (Ipp8u*)ippMalloc(bufferSize);\
-                if (0 > ippiMorphologyBorderInit_##flavor(roiSize.width, kernel.ptr(), kernelSize, pSpec, pBuffer))\
-                {\
-                    ippFree(pBuffer);\
-                    ippFree(pSpec);\
-                    return false;\
-                }\
-                bool ok = false;\
-                if (op == MORPH_ERODE)\
-                    ok = (0 <= ippiErodeBorder_##flavor(_src->ptr<Ipp##data_type>(), (int)_src->step[0], dst.ptr<Ipp##data_type>(), (int)dst.step[0],\
-                                            roiSize, ippBorderRepl, 0, pSpec, pBuffer));\
-                else\
-                    ok = (0 <= ippiDilateBorder_##flavor(_src->ptr<Ipp##data_type>(), (int)_src->step[0], dst.ptr<Ipp##data_type>(), (int)dst.step[0],\
-                                            roiSize, ippBorderRepl, 0, pSpec, pBuffer));\
-                ippFree(pBuffer);\
-                ippFree(pSpec);\
-                return ok;\
-            }\
-            break;
-#endif
-        CV_SUPPRESS_DEPRECATED_START
-        switch (type)
+
+        // In case BORDER_CONSTANT, IPPMorphReplicate works correct with kernels of size 3*3 only
+        if( borderType == cv::BORDER_CONSTANT && kernel.data )
         {
-        IPP_MORPH_CASE(CV_8UC1, 8u_C1R, 8u);
-        IPP_MORPH_CASE(CV_8UC3, 8u_C3R, 8u);
-        IPP_MORPH_CASE(CV_8UC4, 8u_C4R, 8u);
-        IPP_MORPH_CASE(CV_32FC1, 32f_C1R, 32f);
-        IPP_MORPH_CASE(CV_32FC3, 32f_C3R, 32f);
-        IPP_MORPH_CASE(CV_32FC4, 32f_C4R, 32f);
-        default:
-            ;
+            int x, y;
+            for( y = 0; y < kernel.rows; y++ )
+            {
+                if( kernel.at<uchar>(y, anchor.x) != 0 )
+                    continue;
+                for( x = 0; x < kernel.cols; x++ )
+                {
+                    if( kernel.at<uchar>(y,x) != 0 )
+                        return false;
+                }
+            }
+            for( x = 0; x < kernel.cols; x++ )
+            {
+                if( kernel.at<uchar>(anchor.y, x) != 0 )
+                    continue;
+                for( y = 0; y < kernel.rows; y++ )
+                {
+                    if( kernel.at<uchar>(y,x) != 0 )
+                        return false;
+                }
+            }
+
         }
-        CV_SUPPRESS_DEPRECATED_END
-        #undef IPP_MORPH_CASE
-    }
-    else
-    {
-#if IPP_VERSION_X100 != 900 // Problems with accuracy in 9.0.0
-#if IPP_VERSION_X100 >= 900
-        if (((kernelSize.width - 1) / 2 != anchor.x) || ((kernelSize.height - 1) / 2 != anchor.y)) // Arbitrary anchor is no longer supporeted since IPP 9.0.0
-            return false;
 
-        #define IPP_MORPH_CASE(cvtype, flavor, data_type, cn) \
-        case cvtype: \
-            {\
-                if (op == MORPH_ERODE)\
-                {\
-                    int bufSize = 0;\
-                    if (0 > ippiFilterMinBorderGetBufferSize(roiSize, kernelSize, ipp##data_type, cn, &bufSize))\
-                        return false;\
-                    AutoBuffer<uchar> buf(bufSize + 64);\
-                    uchar* buffer = alignPtr((uchar*)buf, 32);\
-                    return (0 <= ippiFilterMinBorder_##flavor(_src->ptr<Ipp##data_type>(), (int)_src->step[0], dst.ptr<Ipp##data_type>(), (int)dst.step[0], roiSize, kernelSize, ippBorderRepl, 0, buffer));\
-                }\
-                else\
-                {\
-                    int bufSize = 0;\
-                    if (0 > ippiFilterMaxBorderGetBufferSize(roiSize, kernelSize, ipp##data_type, cn, &bufSize))\
-                        return false;\
-                    AutoBuffer<uchar> buf(bufSize + 64);\
-                    uchar* buffer = alignPtr((uchar*)buf, 32);\
-                    return (0 <= ippiFilterMaxBorder_##flavor(_src->ptr<Ipp##data_type>(), (int)_src->step[0], dst.ptr<Ipp##data_type>(), (int)dst.step[0], roiSize, kernelSize, ippBorderRepl, 0, buffer));\
-                }\
-            }\
-            break;
-#else
-        IppiPoint point = {anchor.x, anchor.y};
-
-        #define IPP_MORPH_CASE(cvtype, flavor, data_type, cn) \
-        case cvtype: \
-            {\
-                int bufSize = 0;\
-                if (0 > ippiFilterMinGetBufferSize_##flavor(src.cols, kernelSize, &bufSize))\
-                    return false;\
-                AutoBuffer<uchar> buf(bufSize + 64);\
-                uchar* buffer = alignPtr((uchar*)buf, 32);\
-                if (op == MORPH_ERODE)\
-                    return (0 <= ippiFilterMinBorderReplicate_##flavor(_src->ptr<Ipp##data_type>(), (int)_src->step[0], dst.ptr<Ipp##data_type>(), (int)dst.step[0], roiSize, kernelSize, point, buffer));\
-                return (0 <= ippiFilterMaxBorderReplicate_##flavor(_src->ptr<Ipp##data_type>(), (int)_src->step[0], dst.ptr<Ipp##data_type>(), (int)dst.step[0], roiSize, kernelSize, point, buffer));\
-            }\
-            break;
-#endif
+        Size ksize = !kernel.empty() ? kernel.size() : Size(3,3);
 
-        CV_SUPPRESS_DEPRECATED_START
-        switch (type)
+        rectKernel = false;
+        if( kernel.empty() )
         {
-        IPP_MORPH_CASE(CV_8UC1, 8u_C1R, 8u, 1);
-        IPP_MORPH_CASE(CV_8UC3, 8u_C3R, 8u, 3);
-        IPP_MORPH_CASE(CV_8UC4, 8u_C4R, 8u, 4);
-        IPP_MORPH_CASE(CV_32FC1, 32f_C1R, 32f, 1);
-        IPP_MORPH_CASE(CV_32FC3, 32f_C3R, 32f, 3);
-        IPP_MORPH_CASE(CV_32FC4, 32f_C4R, 32f, 4);
-        default:
-            ;
+            ksize = Size(1+iterations*2,1+iterations*2);
+            anchor = ippiPoint(iterations, iterations);
+            rectKernel = true;
+            iterations = 1;
+        }
+        else if( iterations >= 1 && countNonZero(kernel) == kernel.rows*kernel.cols )
+        {
+            ksize = Size(ksize.width + (iterations-1)*(ksize.width-1),
+                 ksize.height + (iterations-1)*(ksize.height-1)),
+            anchor = ippiPoint(anchor.x*iterations, anchor.y*iterations);
+            kernel = Mat();
+            rectKernel = true;
+            iterations = 1;
         }
-        CV_SUPPRESS_DEPRECATED_END
-        #undef IPP_MORPH_CASE
-#endif
-    }
-#else
-    CV_UNUSED(op); CV_UNUSED(src); CV_UNUSED(dst); CV_UNUSED(kernel); CV_UNUSED(ksize); CV_UNUSED(anchor); CV_UNUSED(rectKernel);
-#endif
-    return false;
-}
 
-static bool ipp_MorphOp(int op, InputArray _src, OutputArray _dst,
-    const Mat& _kernel, Point anchor, int iterations,
-    int borderType, const Scalar &borderValue)
-{
-    Mat src = _src.getMat(), kernel = _kernel;
-    int type = src.type(), depth = CV_MAT_DEPTH(type), cn = CV_MAT_CN(type);
+        // TODO: implement the case of iterations > 1.
+        if( iterations > 1 )
+            return false;
 
-    if( !( depth == CV_8U || depth == CV_32F ) || !(cn == 1 || cn == 3 || cn == 4) ||
-        !( borderType == cv::BORDER_REPLICATE || (borderType == cv::BORDER_CONSTANT && borderValue == morphologyDefaultBorderValue() &&
-        kernel.size() == Size(3,3)) ) || !( op == MORPH_DILATE || op == MORPH_ERODE) || _src.isSubmatrix() )
-        return false;
+        IppiSize roiSize = {max_width, max_height};
+        kernelSize = ippiSize(ksize);
+        op = _op;
 
-    // In case BORDER_CONSTANT, IPPMorphReplicate works correct with kernels of size 3*3 only
-    if( borderType == cv::BORDER_CONSTANT && kernel.data )
-    {
-        int x, y;
-        for( y = 0; y < kernel.rows; y++ )
+        IppStatus res;
+        if (!rectKernel)
         {
-            if( kernel.at<uchar>(y, anchor.x) != 0 )
-                continue;
-            for( x = 0; x < kernel.cols; x++ )
+            if (((kernel.cols - 1) / 2 != anchor.x) || ((kernel.rows - 1) / 2 != anchor.y))
+                return false;
+            int specSize = 0, bufferSize = 0;
+            res = trait.getMorphSize(roiSize, kernelSize, &specSize, &bufferSize);
+            if (res >= 0)
             {
-                if( kernel.at<uchar>(y,x) != 0 )
-                    return false;
+                specBuf.Alloc(specSize);
+                workBuf.Alloc(bufferSize);
+                res = trait.morphInit(roiSize, kernel.ptr(), kernelSize, specBuf, workBuf);
+                if (res >= 0)
+                    return true;
             }
         }
-        for( x = 0; x < kernel.cols; x++ )
+        else
         {
-            if( kernel.at<uchar>(anchor.y, x) != 0 )
-                continue;
-            for( y = 0; y < kernel.rows; y++ )
+            if (((kernelSize.width - 1) / 2 != anchor.x) || ((kernelSize.height - 1) / 2 != anchor.y))
+                return false;
+            if (op == MORPH_ERODE)
             {
-                if( kernel.at<uchar>(y,x) != 0 )
-                    return false;
+                int bufSize = 0;
+                res = trait.filterGetMinSize(roiSize, kernelSize, trait.getDataType(), trait.cn, &bufSize);
+                if (res >= 0)
+                {
+                    workBuf.Alloc(bufSize);
+                    return true;
+                }
+            }
+            else
+            {
+                int bufSize = 0;
+                res = trait.filterGetMaxSize(roiSize, kernelSize, trait.getDataType(), trait.cn, &bufSize);
+                if (res >= 0)
+                {
+                    workBuf.Alloc(bufSize);
+                    return true;
+                }
             }
         }
-
+        return false;
     }
-    Size ksize = !kernel.empty() ? kernel.size() : Size(3,3);
 
-    _dst.create( src.size(), src.type() );
-    Mat dst = _dst.getMat();
+    void apply(uchar * src_data, size_t src_step, uchar * dst_data, size_t dst_step, int width, int height,
+               int roi_width, int roi_height, int roi_x, int roi_y,
+               int roi_width2, int roi_height2, int roi_x2, int roi_y2)
+    {
+        CV_INSTRUMENT_REGION_IPP()
+
+        CV_UNUSED(roi_width); CV_UNUSED(roi_height); CV_UNUSED(roi_x); CV_UNUSED(roi_y);
+        CV_UNUSED(roi_width2); CV_UNUSED(roi_height2); CV_UNUSED(roi_x2); CV_UNUSED(roi_y2);
+        if (src_data == dst_data)
+            CV_Error(Error::StsBadArg, "IPP Morph inplace is not alowed");
+
+        IppiSize roiSize = {width, height};
+
+        IppStatus res;
+        if (!rectKernel)
+        {
+            if (op == MORPH_ERODE)
+                res = (trait.morphErode((ipp_data_type*)src_data, (int)src_step, (ipp_data_type*)dst_data, (int)dst_step, roiSize, specBuf, workBuf));
+            else
+                res = (trait.morphDilate((ipp_data_type*)src_data, (int)src_step, (ipp_data_type*)dst_data, (int)dst_step, roiSize, specBuf, workBuf));
+        }
+        else
+        {
+            if (op == MORPH_ERODE)
+                res = (trait.filterMinBorder((ipp_data_type*)src_data, (int)src_step, (ipp_data_type*)dst_data, (int)dst_step, roiSize, kernelSize, anchor, workBuf));
+            else
+                res = (trait.filterMaxBorder((ipp_data_type*)src_data, (int)src_step, (ipp_data_type*)dst_data, (int)dst_step, roiSize, kernelSize, anchor, workBuf));
+        }
+        if (res < 0)
+            CV_Error(Error::StsBadArg, "Failed to run IPP morph");
+    }
+};
 
-    if( iterations == 0 || kernel.rows*kernel.cols == 1 )
+static IppMorphBaseImpl * createIppImpl(int type)
+{
+    switch (type)
     {
-        src.copyTo(dst);
-        return true;
+    case CV_8UC1: return new IppMorphImpl<CV_8UC1>();
+    case CV_8UC3: return new IppMorphImpl<CV_8UC3>();
+    case CV_8UC4: return new IppMorphImpl<CV_8UC4>();
+    case CV_32FC1: return new IppMorphImpl<CV_32FC1>();
+    case CV_32FC3: return new IppMorphImpl<CV_32FC3>();
+    case CV_32FC4: return new IppMorphImpl<CV_32FC4>();
     }
+    return 0;
+}
 
-    bool rectKernel = false;
-    if( kernel.empty() )
+#endif // IPP_VERSION_X100 >= 810
+#endif // HAVE_IPP
+
+// ===== 3. Fallback implementation
+
+struct OcvMorphImpl : public hal::Morph
+{
+    Ptr<FilterEngine> f;
+    int iterations;
+    int src_type;
+    int dst_type;
+    bool init(int op, int _src_type, int _dst_type, int, int,
+              int kernel_type, uchar * kernel_data, size_t kernel_step, int kernel_width, int kernel_height,
+              int anchor_x, int anchor_y,
+              int borderType, const double _borderValue[4],
+              int _iterations, bool, bool)
     {
-        ksize = Size(1+iterations*2,1+iterations*2);
-        anchor = Point(iterations, iterations);
-        rectKernel = true;
-        iterations = 1;
+        iterations = _iterations;
+        src_type = _src_type;
+        dst_type = _dst_type;
+        Mat kernel(Size(kernel_width, kernel_height), kernel_type, kernel_data, kernel_step);
+        Point anchor(anchor_x, anchor_y);
+        Vec<double, 4> borderValue(_borderValue);
+        f = createMorphologyFilter(op, src_type, kernel, anchor, borderType, borderType, borderValue );
+        return true;
     }
-    else if( iterations >= 1 && countNonZero(kernel) == kernel.rows*kernel.cols )
+
+    void apply(uchar * src_data, size_t src_step, uchar * dst_data, size_t dst_step, int width, int height,
+               int roi_width, int roi_height, int roi_x, int roi_y,
+               int roi_width2, int roi_height2, int roi_x2, int roi_y2)
     {
-        ksize = Size(ksize.width + (iterations-1)*(ksize.width-1),
-             ksize.height + (iterations-1)*(ksize.height-1)),
-        anchor = Point(anchor.x*iterations, anchor.y*iterations);
-        kernel = Mat();
-        rectKernel = true;
-        iterations = 1;
+        Mat src(Size(width, height), src_type, src_data, src_step);
+        Mat dst(Size(width, height), dst_type, dst_data, dst_step);
+        {
+            Point ofs(roi_x, roi_y);
+            Size wsz(roi_width, roi_height);
+            f->apply( src, dst, wsz, ofs );
+        }
+        {
+            Point ofs(roi_x2, roi_y2);
+            Size wsz(roi_width2, roi_height2);
+            for( int i = 1; i < iterations; i++ )
+                f->apply( dst, dst, wsz, ofs );
+        }
     }
+};
 
-    // TODO: implement the case of iterations > 1.
-    if( iterations > 1 )
-        return false;
+// ===== HAL interface implementation
 
-    return ipp_MorphReplicate( op, src, dst, kernel, ksize, anchor, rectKernel );
-}
+namespace hal {
+
+Ptr<Morph> Morph ::create(int op, int src_type, int dst_type, int max_width, int max_height,
+                                        int kernel_type, uchar * kernel_data, size_t kernel_step, int kernel_width, int kernel_height,
+                                        int anchor_x, int anchor_y,
+                                        int borderType, const double borderValue[4],
+                                        int iterations, bool isSubmatrix, bool allowInplace)
+{
+    {
+        ReplacementMorphImpl * impl = new ReplacementMorphImpl();
+        if (impl->init(op, src_type, dst_type, max_width, max_height,
+                       kernel_type, kernel_data, kernel_step, kernel_width, kernel_height,
+                       anchor_x, anchor_y,
+                       borderType, borderValue, iterations, isSubmatrix, allowInplace))
+        {
+            return Ptr<Morph>(impl);
+        }
+        delete impl;
+    }
+#if defined(HAVE_IPP) && IPP_VERSION_X100 >= 810
+    CV_IPP_CHECK()
+    {
+        IppMorphBaseImpl * impl = createIppImpl(src_type);
+        if (impl)
+        {
+            if (impl->init(op, src_type, dst_type, max_width, max_height,
+                        kernel_type, kernel_data, kernel_step, kernel_width, kernel_height,
+                        anchor_x, anchor_y,
+                        borderType, borderValue, iterations, isSubmatrix, allowInplace))
+            {
+                return Ptr<Morph>(impl);
+            }
+            delete impl;
+        }
+    }
 #endif
+    {
+        OcvMorphImpl * impl = new OcvMorphImpl();
+        impl->init(op, src_type, dst_type, max_width, max_height,
+                kernel_type, kernel_data, kernel_step, kernel_width, kernel_height,
+                anchor_x, anchor_y,
+                borderType, borderValue, iterations, isSubmatrix, allowInplace);
+        return Ptr<Morph>(impl);
+    }
+}
+
+} // cv::hal
 
 #ifdef HAVE_OPENCL
 
 #define ROUNDUP(sz, n)      ((sz) + (n) - 1 - (((sz) + (n) - 1) % (n)))
 
+static bool ocl_morph3x3_8UC1( InputArray _src, OutputArray _dst, InputArray _kernel, Point anchor,
+                               int op, int actual_op = -1, InputArray _extraMat = noArray())
+{
+    int type = _src.type(), depth = CV_MAT_DEPTH(type), cn = CV_MAT_CN(type);
+    Size ksize = _kernel.size();
+
+    Mat kernel8u;
+    String processing;
+
+    bool haveExtraMat = !_extraMat.empty();
+    CV_Assert(actual_op <= 3 || haveExtraMat);
+
+    _kernel.getMat().convertTo(kernel8u, CV_8U);
+    for (int y = 0; y < kernel8u.rows; ++y)
+        for (int x = 0; x < kernel8u.cols; ++x)
+            if (kernel8u.at<uchar>(y, x) != 0)
+                processing += format("PROCESS(%d,%d)", y, x);
+
+    if (anchor.x < 0)
+        anchor.x = ksize.width / 2;
+    if (anchor.y < 0)
+        anchor.y = ksize.height / 2;
+
+    if (actual_op < 0)
+        actual_op = op;
+
+    if (type != CV_8UC1 ||
+        !((_src.offset() == 0) && (_src.step() % 4 == 0)) ||
+        !((_src.cols() % 16 == 0) && (_src.rows() % 2 == 0)) ||
+        !(anchor.x == 1 && anchor.y == 1) ||
+        !(ksize.width == 3 && ksize.height == 3))
+        return false;
+
+    Size size = _src.size();
+    size_t globalsize[2] = { 0, 0 };
+    size_t localsize[2] = { 0, 0 };
+
+    globalsize[0] = size.width / 16;
+    globalsize[1] = size.height / 2;
+
+    static const char * const op2str[] = { "OP_ERODE", "OP_DILATE", NULL, NULL, "OP_GRADIENT", "OP_TOPHAT", "OP_BLACKHAT" };
+    String opts = format("-D PROCESS_ELEM_=%s -D %s%s", processing.c_str(), op2str[op],
+                         actual_op == op ? "" : cv::format(" -D %s", op2str[actual_op]).c_str());
+
+    ocl::Kernel k;
+    k.create("morph3x3_8UC1_cols16_rows2", cv::ocl::imgproc::morph3x3_oclsrc, opts);
+
+    if (k.empty())
+        return false;
+
+    UMat src = _src.getUMat();
+    _dst.create(size, CV_MAKETYPE(depth, cn));
+    if (!(_dst.offset() == 0 && _dst.step() % 4 == 0))
+        return false;
+    UMat dst = _dst.getUMat();
+    UMat extraMat = _extraMat.getUMat();
+
+    int idxArg = k.set(0, ocl::KernelArg::PtrReadOnly(src));
+    idxArg = k.set(idxArg, (int)src.step);
+    idxArg = k.set(idxArg, ocl::KernelArg::PtrWriteOnly(dst));
+    idxArg = k.set(idxArg, (int)dst.step);
+    idxArg = k.set(idxArg, (int)dst.rows);
+    idxArg = k.set(idxArg, (int)dst.cols);
+
+    if (haveExtraMat)
+    {
+        idxArg = k.set(idxArg, ocl::KernelArg::ReadOnlyNoSize(extraMat));
+    }
+
+    return k.run(2, globalsize, (localsize[0] == 0) ? NULL : localsize, false);
+}
+
 static bool ocl_morphSmall( InputArray _src, OutputArray _dst, InputArray _kernel, Point anchor, int borderType,
                             int op, int actual_op = -1, InputArray _extraMat = noArray())
 {
@@ -1577,6 +1748,9 @@ static bool ocl_morphOp(InputArray _src, OutputArray _dst, InputArray _kernel,
 #endif
          )
     {
+        if (ocl_morph3x3_8UC1(_src, _dst, kernel, anchor, op, actual_op, _extraMat))
+            return true;
+
         if (ocl_morphSmall(_src, _dst, kernel, anchor, borderType, op, actual_op, _extraMat))
             return true;
     }
@@ -1750,22 +1924,30 @@ static void morphOp( int op, InputArray _src, OutputArray _dst,
         iterations = 1;
     }
 
-    CV_IPP_RUN(IPP_VERSION_X100 >= 810, ipp_MorphOp(op, _src, _dst, kernel, anchor, iterations, borderType, borderValue))
-
     Mat src = _src.getMat();
     _dst.create( src.size(), src.type() );
     Mat dst = _dst.getMat();
 
-    int nStripes = 1;
-#if defined HAVE_TEGRA_OPTIMIZATION
-    if (src.data != dst.data && iterations == 1 &&  //NOTE: threads are not used for inplace processing
-        (borderType & BORDER_ISOLATED) == 0 && //TODO: check border types
-        src.rows >= 64 ) //NOTE: just heuristics
-        nStripes = 4;
-#endif
+    Point s_ofs;
+    Size s_wsz(src.cols, src.rows);
+    Point d_ofs;
+    Size d_wsz(dst.cols, dst.rows);
+    bool isolated = (borderType&BORDER_ISOLATED)?true:false;
+    borderType = (borderType&~BORDER_ISOLATED);
 
-    parallel_for_(Range(0, nStripes),
-                  MorphologyRunner(src, dst, nStripes, iterations, op, kernel, anchor, borderType, borderType, borderValue));
+    if(!isolated)
+    {
+        src.locateROI(s_wsz, s_ofs);
+        dst.locateROI(d_wsz, d_ofs);
+    }
+
+    Ptr<hal::Morph> ctx = hal::Morph::create(op, src.type(), dst.type(), src.cols, src.rows,
+                                                           kernel.type(), kernel.data, kernel.step, kernel.cols, kernel.rows,
+                                                           anchor.x, anchor.y, borderType, borderValue.val, iterations,
+                                                           (src.isSubmatrix() && !isolated), src.data == dst.data);
+    ctx->apply(src.data, src.step, dst.data, dst.step, src.cols, src.rows,
+               s_wsz.width, s_wsz.height, s_ofs.x, s_ofs.y,
+               d_wsz.width, d_wsz.height, d_ofs.x, d_ofs.y);
 }
 
 }
@@ -1774,6 +1956,8 @@ void cv::erode( InputArray src, OutputArray dst, InputArray kernel,
                 Point anchor, int iterations,
                 int borderType, const Scalar& borderValue )
 {
+    CV_INSTRUMENT_REGION()
+
     morphOp( MORPH_ERODE, src, dst, kernel, anchor, iterations, borderType, borderValue );
 }
 
@@ -1782,6 +1966,8 @@ void cv::dilate( InputArray src, OutputArray dst, InputArray kernel,
                  Point anchor, int iterations,
                  int borderType, const Scalar& borderValue )
 {
+    CV_INSTRUMENT_REGION()
+
     morphOp( MORPH_DILATE, src, dst, kernel, anchor, iterations, borderType, borderValue );
 }
 
@@ -1853,6 +2039,8 @@ void cv::morphologyEx( InputArray _src, OutputArray _dst, int op,
                        InputArray _kernel, Point anchor, int iterations,
                        int borderType, const Scalar& borderValue )
 {
+    CV_INSTRUMENT_REGION()
+
     Mat kernel = _kernel.getMat();
     if (kernel.empty())
     {
diff --git a/modules/imgproc/src/opencl/boxFilter3x3.cl b/modules/imgproc/src/opencl/boxFilter3x3.cl
new file mode 100644
index 0000000..7050a4b
--- /dev/null
+++ b/modules/imgproc/src/opencl/boxFilter3x3.cl
@@ -0,0 +1,127 @@
+// This file is part of OpenCV project.
+// It is subject to the license terms in the LICENSE file found in the top-level directory
+// of this distribution and at http://opencv.org/license.html.
+
+__kernel void boxFilter3x3_8UC1_cols16_rows2(__global const uint* src, int src_step,
+                                             __global uint* dst, int dst_step, int rows, int cols
+#ifdef NORMALIZE
+                                             , float alpha
+#endif
+                         )
+{
+    int block_x = get_global_id(0);
+    int y = get_global_id(1) * 2;
+    int ssx, dsx;
+
+    if ((block_x * 16) >= cols || y >= rows) return;
+
+    uint4 line[4];
+    uint4 line_out[2];
+    ushort a; ushort16 b; ushort c;
+    ushort d; ushort16 e; ushort f;
+    ushort g; ushort16 h; ushort i;
+    ushort j; ushort16 k; ushort l;
+
+    ssx = dsx = 1;
+    int src_index = block_x * 4 * ssx + (y - 1) * (src_step / 4);
+    line[1] = vload4(0, src + src_index + (src_step / 4));
+    line[2] = vload4(0, src + src_index + 2 * (src_step / 4));
+
+#ifdef BORDER_CONSTANT
+    line[0] = (y == 0) ? (uint4)0 : vload4(0, src + src_index);
+    line[3] = (y == (rows - 2)) ? (uint4)0 : vload4(0, src + src_index + 3 * (src_step / 4));
+#elif defined BORDER_REFLECT_101
+    line[0] = (y == 0) ? line[2] : vload4(0, src + src_index);
+    line[3] = (y == (rows - 2)) ? line[1] : vload4(0, src + src_index + 3 * (src_step / 4));
+#elif defined (BORDER_REPLICATE) || defined(BORDER_REFLECT)
+    line[0] = (y == 0) ? line[1] : vload4(0, src + src_index);
+    line[3] = (y == (rows - 2)) ? line[2] : vload4(0, src + src_index + 3 * (src_step / 4));
+#endif
+
+    ushort16 sum, mid;
+    __global uchar *src_p = (__global uchar *)src;
+
+    src_index = block_x * 16 * ssx + (y - 1) * src_step;
+    bool line_end = ((block_x + 1) * 16 == cols);
+
+    b = convert_ushort16(as_uchar16(line[0]));
+    e = convert_ushort16(as_uchar16(line[1]));
+    h = convert_ushort16(as_uchar16(line[2]));
+    k = convert_ushort16(as_uchar16(line[3]));
+
+#ifdef BORDER_CONSTANT
+    a = (block_x == 0 || y == 0) ? 0 : convert_ushort(src_p[src_index - 1]);
+    c = (line_end || y == 0) ? 0 : convert_ushort(src_p[src_index + 16]);
+
+    d = (block_x == 0) ? 0 : convert_ushort(src_p[src_index + src_step - 1]);
+    f = line_end ? 0 : convert_ushort(src_p[src_index + src_step + 16]);
+
+    g = (block_x == 0) ? 0 : convert_ushort(src_p[src_index + 2 * src_step - 1]);
+    i = line_end ? 0 : convert_ushort(src_p[src_index + 2 * src_step + 16]);
+
+    j = (block_x == 0 || y == (rows - 2)) ? 0 : convert_ushort(src_p[src_index + 3 * src_step - 1]);
+    l = (line_end || y == (rows - 2))? 0 : convert_ushort(src_p[src_index + 3 * src_step + 16]);
+
+#elif defined BORDER_REFLECT_101
+    int offset;
+    offset = (y == 0) ? (2 * src_step) : 0;
+
+    a = (block_x == 0) ? convert_ushort(src_p[src_index + offset + 1]) : convert_ushort(src_p[src_index + offset - 1]);
+    c = line_end ? convert_ushort(src_p[src_index + offset + 14]) : convert_ushort(src_p[src_index + offset + 16]);
+
+    d = (block_x == 0) ? convert_ushort(src_p[src_index + src_step + 1]) : convert_ushort(src_p[src_index + src_step - 1]);
+    f = line_end ? convert_ushort(src_p[src_index + src_step + 14]) : convert_ushort(src_p[src_index + src_step + 16]);
+
+    g = (block_x == 0) ? convert_ushort(src_p[src_index + 2 * src_step + 1]) : convert_ushort(src_p[src_index + 2 * src_step - 1]);
+    i = line_end ? convert_ushort(src_p[src_index + 2 * src_step + 14]) : convert_ushort(src_p[src_index + 2 * src_step + 16]);
+
+    offset = (y == (rows - 2)) ? (1 * src_step) : (3 * src_step);
+
+    j = (block_x == 0) ? convert_ushort(src_p[src_index + offset + 1]) : convert_ushort(src_p[src_index + offset - 1]);
+    l = line_end ? convert_ushort(src_p[src_index + offset + 14]) : convert_ushort(src_p[src_index + offset + 16]);
+
+#elif defined (BORDER_REPLICATE) || defined(BORDER_REFLECT)
+    int offset;
+    offset = (y == 0) ? (1 * src_step) : 0;
+
+    a = (block_x == 0) ? convert_ushort(src_p[src_index + offset]) : convert_ushort(src_p[src_index + offset - 1]);
+    c = line_end ? convert_ushort(src_p[src_index + offset + 15]) : convert_ushort(src_p[src_index + offset + 16]);
+
+    d = (block_x == 0) ? convert_ushort(src_p[src_index + src_step]) : convert_ushort(src_p[src_index + src_step - 1]);
+    f = line_end ? convert_ushort(src_p[src_index + src_step + 15]) : convert_ushort(src_p[src_index + src_step + 16]);
+
+    g = (block_x == 0) ? convert_ushort(src_p[src_index + 2 * src_step]) : convert_ushort(src_p[src_index + 2 * src_step - 1]);
+    i = line_end ? convert_ushort(src_p[src_index + 2 * src_step + 15]) : convert_ushort(src_p[src_index + 2 * src_step + 16]);
+
+    offset = (y == (rows - 2)) ? (2 * src_step) : (3 * src_step);
+
+    j = (block_x == 0) ? convert_ushort(src_p[src_index + offset]) : convert_ushort(src_p[src_index + offset - 1]);
+    l = line_end ? convert_ushort(src_p[src_index + offset + 15]) : convert_ushort(src_p[src_index + offset + 16]);
+
+#endif
+
+    mid = (ushort16)(d, e.s0123, e.s456789ab, e.scde) + e + (ushort16)(e.s123, e.s4567, e.s89abcdef, f) +
+          (ushort16)(g, h.s0123, h.s456789ab, h.scde) + h + (ushort16)(h.s123, h.s4567, h.s89abcdef, i);
+
+    sum = (ushort16)(a, b.s0123, b.s456789ab, b.scde) + b + (ushort16)(b.s123, b.s4567, b.s89abcdef, c) +
+          mid;
+
+#ifdef NORMALIZE
+    line_out[0] = as_uint4(convert_uchar16_sat_rte((convert_float16(sum) * alpha)));
+#else
+    line_out[0] = as_uint4(convert_uchar16_sat_rte(sum));
+#endif
+
+    sum = mid +
+          (ushort16)(j, k.s0123, k.s456789ab, k.scde) + k + (ushort16)(k.s123, k.s4567, k.s89abcdef, l);
+
+#ifdef NORMALIZE
+    line_out[1] = as_uint4(convert_uchar16_sat_rte((convert_float16(sum) * alpha)));
+#else
+    line_out[1] = as_uint4(convert_uchar16_sat_rte(sum));
+#endif
+
+    int dst_index = block_x * 4 * dsx + y * (dst_step / 4);
+    vstore4(line_out[0], 0, dst + dst_index);
+    vstore4(line_out[1], 0, dst + dst_index + (dst_step / 4));
+}
diff --git a/modules/imgproc/src/opencl/canny.cl b/modules/imgproc/src/opencl/canny.cl
index 2cc0796..6fde184 100644
--- a/modules/imgproc/src/opencl/canny.cl
+++ b/modules/imgproc/src/opencl/canny.cl
@@ -82,10 +82,10 @@ inline float3 sobel(int idx, __local const floatN *smem)
     // result: x, y, mag
     float3 res;
 
-    floatN dx = fma(2, smem[idx + GRP_SIZEX + 6] - smem[idx + GRP_SIZEX + 4],
+    floatN dx = fma((floatN)2, smem[idx + GRP_SIZEX + 6] - smem[idx + GRP_SIZEX + 4],
         smem[idx + 2] - smem[idx] + smem[idx + 2 * GRP_SIZEX + 10] - smem[idx + 2 * GRP_SIZEX + 8]);
 
-    floatN dy = fma(2, smem[idx + 1] - smem[idx + 2 * GRP_SIZEX + 9],
+    floatN dy = fma((floatN)2, smem[idx + 1] - smem[idx + 2 * GRP_SIZEX + 9],
         smem[idx + 2] - smem[idx + 2 * GRP_SIZEX + 10] + smem[idx] - smem[idx + 2 * GRP_SIZEX + 8]);
 
 #ifdef L2GRAD
@@ -260,7 +260,7 @@ __kernel void stage1_with_sobel(__global const uchar *src, int src_step, int src
 #ifdef L2GRAD
 #define dist(x, y) ((int)(x) * (x) + (int)(y) * (y))
 #else
-#define dist(x, y) (abs(x) + abs(y))
+#define dist(x, y) (abs((int)(x)) + abs((int)(y)))
 #endif
 
 __constant int prev[4][2] = {
@@ -428,6 +428,7 @@ __kernel void stage2_hysteresis(__global uchar *map_ptr, int map_step, int map_o
         int mod = l_counter % LOCAL_TOTAL;
         int pix_per_thr = l_counter / LOCAL_TOTAL + ((lid < mod) ? 1 : 0);
 
+        barrier(CLK_LOCAL_MEM_FENCE);
         for (int i = 0; i < pix_per_thr; ++i)
         {
             int index = atomic_dec(&l_counter) - 1;
diff --git a/modules/imgproc/src/opencl/clahe.cl b/modules/imgproc/src/opencl/clahe.cl
index 9f88b20..187933c 100644
--- a/modules/imgproc/src/opencl/clahe.cl
+++ b/modules/imgproc/src/opencl/clahe.cl
@@ -201,7 +201,10 @@ __kernel void calcLut(__global __const uchar * src, const int srcStep,
         tHistVal += redistBatch;
 
         int residual = totalClipped - redistBatch * 256;
-        if (tid < residual)
+        int rStep = 256 / residual;
+        if (rStep < 1)
+            rStep = 1;
+        if (tid%rStep == 0 && (tid/rStep)<residual)
             ++tHistVal;
     }
 
diff --git a/modules/imgproc/src/opencl/cvtcolor.cl b/modules/imgproc/src/opencl/cvtcolor.cl
index a7cc776..9ceafd7 100644
--- a/modules/imgproc/src/opencl/cvtcolor.cl
+++ b/modules/imgproc/src/opencl/cvtcolor.cl
@@ -49,21 +49,21 @@
 #if depth == 0
     #define DATA_TYPE uchar
     #define MAX_NUM  255
-    #define HALF_MAX 128
+    #define HALF_MAX_NUM 128
     #define COEFF_TYPE int
     #define SAT_CAST(num) convert_uchar_sat(num)
     #define DEPTH_0
 #elif depth == 2
     #define DATA_TYPE ushort
     #define MAX_NUM  65535
-    #define HALF_MAX 32768
+    #define HALF_MAX_NUM 32768
     #define COEFF_TYPE int
     #define SAT_CAST(num) convert_ushort_sat(num)
     #define DEPTH_2
 #elif depth == 5
     #define DATA_TYPE float
     #define MAX_NUM  1.0f
-    #define HALF_MAX 0.5f
+    #define HALF_MAX_NUM 0.5f
     #define COEFF_TYPE float
     #define SAT_CAST(num) (num)
     #define DEPTH_5
@@ -84,6 +84,39 @@ enum
     BLOCK_SIZE = 256
 };
 
+//constants for conversion from/to RGB and Gray, YUV, YCrCb according to BT.601
+#define B2YF 0.114f
+#define G2YF 0.587f
+#define R2YF 0.299f
+//to YCbCr
+#define YCBF 0.564f
+#define YCRF 0.713f
+#define YCBI 9241
+#define YCRI 11682
+//to YUV
+#define B2UF 0.492f
+#define R2VF 0.877f
+#define B2UI 8061
+#define R2VI 14369
+//from YUV
+#define U2BF 2.032f
+#define U2GF -0.395f
+#define V2GF -0.581f
+#define V2RF 1.140f
+#define U2BI 33292
+#define U2GI -6472
+#define V2GI -9519
+#define V2RI 18678
+//from YCrCb
+#define CR2RF 1.403f
+#define CB2GF -0.344f
+#define CR2GF -0.714f
+#define CB2BF 1.773f
+#define CR2RI 22987
+#define CB2GI -5636
+#define CR2GI -11698
+#define CB2BI 29049
+
 #define scnbytes ((int)sizeof(DATA_TYPE)*scn)
 #define dcnbytes ((int)sizeof(DATA_TYPE)*dcn)
 
@@ -151,7 +184,7 @@ __kernel void RGB2Gray(__global const uchar * srcptr, int src_step, int src_offs
                 __global DATA_TYPE* dst = (__global DATA_TYPE*)(dstptr + dst_index);
                 DATA_TYPE_4 src_pix = vload4(0, src);
 #ifdef DEPTH_5
-                dst[0] = fma(src_pix.B_COMP, 0.114f, fma(src_pix.G_COMP, 0.587f, src_pix.R_COMP * 0.299f));
+                dst[0] = fma(src_pix.B_COMP, B2YF, fma(src_pix.G_COMP, G2YF, src_pix.R_COMP * R2YF));
 #else
                 dst[0] = (DATA_TYPE)CV_DESCALE(mad24(src_pix.B_COMP, B2Y, mad24(src_pix.G_COMP, G2Y, mul24(src_pix.R_COMP, R2Y))), yuv_shift);
 #endif
@@ -201,8 +234,8 @@ __kernel void Gray2RGB(__global const uchar * srcptr, int src_step, int src_offs
 
 ///////////////////////////////////// RGB <-> YUV //////////////////////////////////////
 
-__constant float c_RGB2YUVCoeffs_f[5]  = { 0.114f, 0.587f, 0.299f, 0.492f, 0.877f };
-__constant int   c_RGB2YUVCoeffs_i[5]  = { B2Y, G2Y, R2Y, 8061, 14369 };
+__constant float c_RGB2YUVCoeffs_f[5]  = { B2YF, G2YF, R2YF, B2UF, R2VF };
+__constant int   c_RGB2YUVCoeffs_i[5]  = { B2Y, G2Y, R2Y, B2UI, R2VI };
 
 __kernel void RGB2YUV(__global const uchar* srcptr, int src_step, int src_offset,
                       __global uchar* dstptr, int dst_step, int dt_offset,
@@ -229,11 +262,11 @@ __kernel void RGB2YUV(__global const uchar* srcptr, int src_step, int src_offset
 #ifdef DEPTH_5
                 __constant float * coeffs = c_RGB2YUVCoeffs_f;
                 const DATA_TYPE Y = fma(b, coeffs[0], fma(g, coeffs[1], r * coeffs[2]));
-                const DATA_TYPE U = fma(b - Y, coeffs[3], HALF_MAX);
-                const DATA_TYPE V = fma(r - Y, coeffs[4], HALF_MAX);
+                const DATA_TYPE U = fma(b - Y, coeffs[3], HALF_MAX_NUM);
+                const DATA_TYPE V = fma(r - Y, coeffs[4], HALF_MAX_NUM);
 #else
                 __constant int * coeffs = c_RGB2YUVCoeffs_i;
-                const int delta = HALF_MAX * (1 << yuv_shift);
+                const int delta = HALF_MAX_NUM * (1 << yuv_shift);
                 const int Y = CV_DESCALE(mad24(b, coeffs[0], mad24(g, coeffs[1], mul24(r, coeffs[2]))), yuv_shift);
                 const int U = CV_DESCALE(mad24(b - Y, coeffs[3], delta), yuv_shift);
                 const int V = CV_DESCALE(mad24(r - Y, coeffs[4], delta), yuv_shift);
@@ -251,8 +284,8 @@ __kernel void RGB2YUV(__global const uchar* srcptr, int src_step, int src_offset
     }
 }
 
-__constant float c_YUV2RGBCoeffs_f[4] = { 2.032f, -0.395f, -0.581f, 1.140f };
-__constant int   c_YUV2RGBCoeffs_i[4] = { 33292, -6472, -9519, 18678 };
+__constant float c_YUV2RGBCoeffs_f[4] = { U2BF, U2GF, V2GF, V2RF };
+__constant int   c_YUV2RGBCoeffs_i[4] = { U2BI, U2GI, V2GI, V2RI };
 
 __kernel void YUV2RGB(__global const uchar* srcptr, int src_step, int src_offset,
                       __global uchar* dstptr, int dst_step, int dt_offset,
@@ -278,14 +311,14 @@ __kernel void YUV2RGB(__global const uchar* srcptr, int src_step, int src_offset
 
 #ifdef DEPTH_5
                 __constant float * coeffs = c_YUV2RGBCoeffs_f;
-                float r = fma(V - HALF_MAX, coeffs[3], Y);
-                float g = fma(V - HALF_MAX, coeffs[2], fma(U - HALF_MAX, coeffs[1], Y));
-                float b = fma(U - HALF_MAX, coeffs[0], Y);
+                float r = fma(V - HALF_MAX_NUM, coeffs[3], Y);
+                float g = fma(V - HALF_MAX_NUM, coeffs[2], fma(U - HALF_MAX_NUM, coeffs[1], Y));
+                float b = fma(U - HALF_MAX_NUM, coeffs[0], Y);
 #else
                 __constant int * coeffs = c_YUV2RGBCoeffs_i;
-                const int r = Y + CV_DESCALE(mul24(V - HALF_MAX, coeffs[3]), yuv_shift);
-                const int g = Y + CV_DESCALE(mad24(V - HALF_MAX, coeffs[2], mul24(U - HALF_MAX, coeffs[1])), yuv_shift);
-                const int b = Y + CV_DESCALE(mul24(U - HALF_MAX, coeffs[0]), yuv_shift);
+                const int r = Y + CV_DESCALE(mul24(V - HALF_MAX_NUM, coeffs[3]), yuv_shift);
+                const int g = Y + CV_DESCALE(mad24(V - HALF_MAX_NUM, coeffs[2], mul24(U - HALF_MAX_NUM, coeffs[1])), yuv_shift);
+                const int b = Y + CV_DESCALE(mul24(U - HALF_MAX_NUM, coeffs[0]), yuv_shift);
 #endif
 
                 dst[bidx] = SAT_CAST( b );
@@ -328,8 +361,8 @@ __kernel void YUV2RGB_NVx(__global const uchar* srcptr, int src_step, int src_of
                 float Y3 = ysrc[src_step];
                 float Y4 = ysrc[src_step + 1];
 
-                float U  = ((float)usrc[uidx]) - HALF_MAX;
-                float V  = ((float)usrc[1-uidx]) - HALF_MAX;
+                float U  = ((float)usrc[uidx]) - HALF_MAX_NUM;
+                float V  = ((float)usrc[1-uidx]) - HALF_MAX_NUM;
 
                 __constant float* coeffs = c_YUV2RGBCoeffs_420;
                 float ruv = fma(coeffs[4], V, 0.5f);
@@ -373,6 +406,8 @@ __kernel void YUV2RGB_NVx(__global const uchar* srcptr, int src_step, int src_of
     }
 }
 
+#if uidx < 2
+
 __kernel void YUV2RGB_YV12_IYUV(__global const uchar* srcptr, int src_step, int src_offset,
                                 __global uchar* dstptr, int dst_step, int dt_offset,
                                 int rows, int cols)
@@ -399,12 +434,12 @@ __kernel void YUV2RGB_YV12_IYUV(__global const uchar* srcptr, int src_step, int
 #ifdef SRC_CONT
                 __global const uchar* uvsrc = srcptr + mad24(rows, src_step, src_offset);
                 int u_ind = mad24(y, cols >> 1, x);
-                float uv[2] = { ((float)uvsrc[u_ind]) - HALF_MAX, ((float)uvsrc[u_ind + ((rows * cols) >> 2)]) - HALF_MAX };
+                float uv[2] = { ((float)uvsrc[u_ind]) - HALF_MAX_NUM, ((float)uvsrc[u_ind + ((rows * cols) >> 2)]) - HALF_MAX_NUM };
 #else
                 int vsteps[2] = { cols >> 1, src_step - (cols >> 1)};
                 __global const uchar* usrc = srcptr + mad24(rows + (y>>1), src_step, src_offset + (y%2)*(cols >> 1) + x);
                 __global const uchar* vsrc = usrc + mad24(rows >> 2, src_step, rows % 4 ? vsteps[y%2] : 0);
-                float uv[2] = { ((float)usrc[0]) - HALF_MAX, ((float)vsrc[0]) - HALF_MAX };
+                float uv[2] = { ((float)usrc[0]) - HALF_MAX_NUM, ((float)vsrc[0]) - HALF_MAX_NUM };
 #endif
                 float U = uv[uidx];
                 float V = uv[1-uidx];
@@ -451,6 +486,10 @@ __kernel void YUV2RGB_YV12_IYUV(__global const uchar* srcptr, int src_step, int
     }
 }
 
+#endif
+
+#if uidx < 2
+
 __constant float c_RGB2YUVCoeffs_420[8] = { 0.256999969f, 0.50399971f, 0.09799957f, -0.1479988098f, -0.2909994125f,
                                             0.438999176f, -0.3679990768f, -0.0709991455f };
 
@@ -556,6 +595,8 @@ __kernel void RGB2YUV_YV12_IYUV(__global const uchar* srcptr, int src_step, int
     }
 }
 
+#endif
+
 __kernel void YUV2RGB_422(__global const uchar* srcptr, int src_step, int src_offset,
                           __global uchar* dstptr, int dst_step, int dst_offset,
                           int rows, int cols)
@@ -576,15 +617,15 @@ __kernel void YUV2RGB_422(__global const uchar* srcptr, int src_step, int src_of
                 __constant float* coeffs = c_YUV2RGBCoeffs_420;
 
 #ifndef USE_OPTIMIZED_LOAD
-                float U = ((float) src[uidx]) - HALF_MAX;
-                float V = ((float) src[(2 + uidx) % 4]) - HALF_MAX;
+                float U = ((float) src[uidx]) - HALF_MAX_NUM;
+                float V = ((float) src[(2 + uidx) % 4]) - HALF_MAX_NUM;
                 float y00 = max(0.f, ((float) src[yidx]) - 16.f) * coeffs[0];
                 float y01 = max(0.f, ((float) src[yidx + 2]) - 16.f) * coeffs[0];
 #else
                 int load_src = *((__global int*) src);
                 float vec_src[4] = { load_src & 0xff, (load_src >> 8) & 0xff, (load_src >> 16) & 0xff, (load_src >> 24) & 0xff};
-                float U = vec_src[uidx] - HALF_MAX;
-                float V = vec_src[(2 + uidx) % 4] - HALF_MAX;
+                float U = vec_src[uidx] - HALF_MAX_NUM;
+                float V = vec_src[(2 + uidx) % 4] - HALF_MAX_NUM;
                 float y00 = max(0.f, vec_src[yidx] - 16.f) * coeffs[0];
                 float y01 = max(0.f, vec_src[yidx + 2] - 16.f) * coeffs[0];
 #endif
@@ -616,8 +657,8 @@ __kernel void YUV2RGB_422(__global const uchar* srcptr, int src_step, int src_of
 
 ///////////////////////////////////// RGB <-> YCrCb //////////////////////////////////////
 
-__constant float c_RGB2YCrCbCoeffs_f[5] = {0.299f, 0.587f, 0.114f, 0.713f, 0.564f};
-__constant int   c_RGB2YCrCbCoeffs_i[5] = {R2Y, G2Y, B2Y, 11682, 9241};
+__constant float c_RGB2YCrCbCoeffs_f[5] = {R2YF, G2YF, B2YF, YCRF, YCBF};
+__constant int   c_RGB2YCrCbCoeffs_i[5] = {R2Y, G2Y, B2Y, YCRI, YCBI};
 
 __kernel void RGB2YCrCb(__global const uchar* srcptr, int src_step, int src_offset,
                         __global uchar* dstptr, int dst_step, int dt_offset,
@@ -644,11 +685,11 @@ __kernel void RGB2YCrCb(__global const uchar* srcptr, int src_step, int src_offs
 #ifdef DEPTH_5
                 __constant float * coeffs = c_RGB2YCrCbCoeffs_f;
                 DATA_TYPE Y = fma(b, coeffs[2], fma(g, coeffs[1], r * coeffs[0]));
-                DATA_TYPE Cr = fma(r - Y, coeffs[3], HALF_MAX);
-                DATA_TYPE Cb = fma(b - Y, coeffs[4], HALF_MAX);
+                DATA_TYPE Cr = fma(r - Y, coeffs[3], HALF_MAX_NUM);
+                DATA_TYPE Cb = fma(b - Y, coeffs[4], HALF_MAX_NUM);
 #else
                 __constant int * coeffs = c_RGB2YCrCbCoeffs_i;
-                int delta = HALF_MAX * (1 << yuv_shift);
+                int delta = HALF_MAX_NUM * (1 << yuv_shift);
                 int Y =  CV_DESCALE(mad24(b, coeffs[2], mad24(g, coeffs[1], mul24(r, coeffs[0]))), yuv_shift);
                 int Cr = CV_DESCALE(mad24(r - Y, coeffs[3], delta), yuv_shift);
                 int Cb = CV_DESCALE(mad24(b - Y, coeffs[4], delta), yuv_shift);
@@ -666,8 +707,8 @@ __kernel void RGB2YCrCb(__global const uchar* srcptr, int src_step, int src_offs
     }
 }
 
-__constant float c_YCrCb2RGBCoeffs_f[4] = { 1.403f, -0.714f, -0.344f, 1.773f };
-__constant int   c_YCrCb2RGBCoeffs_i[4] = { 22987, -11698, -5636, 29049 };
+__constant float c_YCrCb2RGBCoeffs_f[4] = { CR2RF, CR2GF, CB2GF, CB2BF };
+__constant int   c_YCrCb2RGBCoeffs_i[4] = { CR2RI, CR2GI, CB2GI, CB2BI };
 
 __kernel void YCrCb2RGB(__global const uchar* src, int src_step, int src_offset,
                         __global uchar* dst, int dst_step, int dst_offset,
@@ -694,14 +735,14 @@ __kernel void YCrCb2RGB(__global const uchar* src, int src_step, int src_offset,
 
 #ifdef DEPTH_5
                 __constant float * coeff = c_YCrCb2RGBCoeffs_f;
-                float r = fma(coeff[0], cr - HALF_MAX, yp);
-                float g = fma(coeff[1], cr - HALF_MAX, fma(coeff[2], cb - HALF_MAX, yp));
-                float b = fma(coeff[3], cb - HALF_MAX, yp);
+                float r = fma(coeff[0], cr - HALF_MAX_NUM, yp);
+                float g = fma(coeff[1], cr - HALF_MAX_NUM, fma(coeff[2], cb - HALF_MAX_NUM, yp));
+                float b = fma(coeff[3], cb - HALF_MAX_NUM, yp);
 #else
                 __constant int * coeff = c_YCrCb2RGBCoeffs_i;
-                int r = yp + CV_DESCALE(coeff[0] * (cr - HALF_MAX), yuv_shift);
-                int g = yp + CV_DESCALE(mad24(coeff[1], cr - HALF_MAX, coeff[2] * (cb - HALF_MAX)), yuv_shift);
-                int b = yp + CV_DESCALE(coeff[3] * (cb - HALF_MAX), yuv_shift);
+                int r = yp + CV_DESCALE(coeff[0] * (cr - HALF_MAX_NUM), yuv_shift);
+                int g = yp + CV_DESCALE(mad24(coeff[1], cr - HALF_MAX_NUM, coeff[2] * (cb - HALF_MAX_NUM)), yuv_shift);
+                int b = yp + CV_DESCALE(coeff[3] * (cb - HALF_MAX_NUM), yuv_shift);
 #endif
 
                 dstptr[(bidx^2)] = SAT_CAST(r);
@@ -1564,9 +1605,9 @@ __kernel void RGBA2mRGBA(__global const uchar* src, int src_step, int src_offset
                 uchar4 src_pix = *(__global const uchar4 *)(src + src_index);
 
                 *(__global uchar4 *)(dst + dst_index) =
-                    (uchar4)(mad24(src_pix.x, src_pix.w, HALF_MAX) / MAX_NUM,
-                             mad24(src_pix.y, src_pix.w, HALF_MAX) / MAX_NUM,
-                             mad24(src_pix.z, src_pix.w, HALF_MAX) / MAX_NUM, src_pix.w);
+                    (uchar4)(mad24(src_pix.x, src_pix.w, HALF_MAX_NUM) / MAX_NUM,
+                             mad24(src_pix.y, src_pix.w, HALF_MAX_NUM) / MAX_NUM,
+                             mad24(src_pix.z, src_pix.w, HALF_MAX_NUM) / MAX_NUM, src_pix.w);
 
                 ++y;
                 dst_index += dst_step;
diff --git a/modules/imgproc/src/opencl/filterSmall.cl b/modules/imgproc/src/opencl/filterSmall.cl
index 967c28c..222edc6 100755
--- a/modules/imgproc/src/opencl/filterSmall.cl
+++ b/modules/imgproc/src/opencl/filterSmall.cl
@@ -154,6 +154,7 @@ inline bool isBorder(const struct RectCoords bounds, int2 coord, int numPixels)
 #endif
 
 #define float1 float
+#define double1 double
 #define uchar1 uchar
 #define int1 int
 #define uint1 unit
diff --git a/modules/imgproc/src/opencl/gaussianBlur3x3.cl b/modules/imgproc/src/opencl/gaussianBlur3x3.cl
new file mode 100644
index 0000000..724e73b
--- /dev/null
+++ b/modules/imgproc/src/opencl/gaussianBlur3x3.cl
@@ -0,0 +1,133 @@
+// This file is part of OpenCV project.
+// It is subject to the license terms in the LICENSE file found in the top-level directory
+// of this distribution and at http://opencv.org/license.html.
+
+#define DIG(a) a,
+__constant float kx[] = { KERNEL_MATRIX_X };
+__constant float ky[] = { KERNEL_MATRIX_Y };
+
+#define OP(delta, y, x) (convert_float16(arr[(y + delta) * 3 + x]) * ky[y] * kx[x])
+
+__kernel void gaussianBlur3x3_8UC1_cols16_rows2(__global const uint* src, int src_step,
+                                                __global uint* dst, int dst_step, int rows, int cols)
+{
+    int block_x = get_global_id(0);
+    int y = get_global_id(1) * 2;
+    int ssx, dsx;
+
+    if ((block_x * 16) >= cols || y >= rows) return;
+
+    uint4 line[4];
+    uint4 line_out[2];
+    uchar a; uchar16 b; uchar c;
+    uchar d; uchar16 e; uchar f;
+    uchar g; uchar16 h; uchar i;
+    uchar j; uchar16 k; uchar l;
+
+    ssx = dsx = 1;
+    int src_index = block_x * 4 * ssx + (y - 1) * (src_step / 4);
+    line[1] = vload4(0, src + src_index + (src_step / 4));
+    line[2] = vload4(0, src + src_index + 2 * (src_step / 4));
+
+#ifdef BORDER_CONSTANT
+    line[0] = (y == 0) ? (uint4)0 : vload4(0, src + src_index);
+    line[3] = (y == (rows - 2)) ? (uint4)0 : vload4(0, src + src_index + 3 * (src_step / 4));
+#elif defined BORDER_REFLECT_101
+    line[0] = (y == 0) ? line[2] : vload4(0, src + src_index);
+    line[3] = (y == (rows - 2)) ? line[1] : vload4(0, src + src_index + 3 * (src_step / 4));
+#elif defined (BORDER_REPLICATE) || defined(BORDER_REFLECT)
+    line[0] = (y == 0) ? line[1] : vload4(0, src + src_index);
+    line[3] = (y == (rows - 2)) ? line[2] : vload4(0, src + src_index + 3 * (src_step / 4));
+#endif
+
+    __global uchar *src_p = (__global uchar *)src;
+
+    src_index = block_x * 16 * ssx + (y - 1) * src_step;
+    bool line_end = ((block_x + 1) * 16 == cols);
+
+    b = as_uchar16(line[0]);
+    e = as_uchar16(line[1]);
+    h = as_uchar16(line[2]);
+    k = as_uchar16(line[3]);
+
+#ifdef BORDER_CONSTANT
+    a = (block_x == 0 || y == 0) ? 0 : src_p[src_index - 1];
+    c = (line_end || y == 0) ? 0 : src_p[src_index + 16];
+
+    d = (block_x == 0) ? 0 : src_p[src_index + src_step - 1];
+    f = line_end ? 0 : src_p[src_index + src_step + 16];
+
+    g = (block_x == 0) ? 0 : src_p[src_index + 2 * src_step - 1];
+    i = line_end ? 0 : src_p[src_index + 2 * src_step + 16];
+
+    j = (block_x == 0 || y == (rows - 2)) ? 0 : src_p[src_index + 3 * src_step - 1];
+    l = (line_end || y == (rows - 2))? 0 : src_p[src_index + 3 * src_step + 16];
+
+#elif defined BORDER_REFLECT_101
+    int offset;
+    offset = (y == 0) ? (2 * src_step) : 0;
+
+    a = (block_x == 0) ? src_p[src_index + offset + 1] : src_p[src_index + offset - 1];
+    c = line_end ? src_p[src_index + offset + 14] : src_p[src_index + offset + 16];
+
+    d = (block_x == 0) ? src_p[src_index + src_step + 1] : src_p[src_index + src_step - 1];
+    f = line_end ? src_p[src_index + src_step + 14] : src_p[src_index + src_step + 16];
+
+    g = (block_x == 0) ? src_p[src_index + 2 * src_step + 1] : src_p[src_index + 2 * src_step - 1];
+    i = line_end ? src_p[src_index + 2 * src_step + 14] : src_p[src_index + 2 * src_step + 16];
+
+    offset = (y == (rows - 2)) ? (1 * src_step) : (3 * src_step);
+
+    j = (block_x == 0) ? src_p[src_index + offset + 1] : src_p[src_index + offset - 1];
+    l = line_end ? src_p[src_index + offset + 14] : src_p[src_index + offset + 16];
+
+#elif defined (BORDER_REPLICATE) || defined(BORDER_REFLECT)
+    int offset;
+    offset = (y == 0) ? (1 * src_step) : 0;
+
+    a = (block_x == 0) ? src_p[src_index + offset] : src_p[src_index + offset - 1];
+    c = line_end ? src_p[src_index + offset + 15] : src_p[src_index + offset + 16];
+
+    d = (block_x == 0) ? src_p[src_index + src_step] : src_p[src_index + src_step - 1];
+    f = line_end ? src_p[src_index + src_step + 15] : src_p[src_index + src_step + 16];
+
+    g = (block_x == 0) ? src_p[src_index + 2 * src_step] : src_p[src_index + 2 * src_step - 1];
+    i = line_end ? src_p[src_index + 2 * src_step + 15] : src_p[src_index + 2 * src_step + 16];
+
+    offset = (y == (rows - 2)) ? (2 * src_step) : (3 * src_step);
+
+    j = (block_x == 0) ? src_p[src_index + offset] : src_p[src_index + offset - 1];
+    l = line_end ? src_p[src_index + offset + 15] : src_p[src_index + offset + 16];
+#endif
+
+    uchar16 arr[12];
+    float16 sum[2];
+
+    arr[0] = (uchar16)(a, b.s0123, b.s456789ab, b.scde);
+    arr[1] = b;
+    arr[2] = (uchar16)(b.s123, b.s4567, b.s89abcdef, c);
+    arr[3] = (uchar16)(d, e.s0123, e.s456789ab, e.scde);
+    arr[4] = e;
+    arr[5] = (uchar16)(e.s123, e.s4567, e.s89abcdef, f);
+    arr[6] = (uchar16)(g, h.s0123, h.s456789ab, h.scde);
+    arr[7] = h;
+    arr[8] = (uchar16)(h.s123, h.s4567, h.s89abcdef, i);
+    arr[9] = (uchar16)(j, k.s0123, k.s456789ab, k.scde);
+    arr[10] = k;
+    arr[11] = (uchar16)(k.s123, k.s4567, k.s89abcdef, l);
+
+    sum[0] = OP(0, 0, 0) + OP(0, 0, 1) + OP(0, 0, 2) +
+             OP(0, 1, 0) + OP(0, 1, 1) + OP(0, 1, 2) +
+             OP(0, 2, 0) + OP(0, 2, 1) + OP(0, 2, 2);
+
+    sum[1] = OP(1, 0, 0) + OP(1, 0, 1) + OP(1, 0, 2) +
+             OP(1, 1, 0) + OP(1, 1, 1) + OP(1, 1, 2) +
+             OP(1, 2, 0) + OP(1, 2, 1) + OP(1, 2, 2);
+
+    line_out[0] = as_uint4(convert_uchar16_sat_rte(sum[0]));
+    line_out[1] = as_uint4(convert_uchar16_sat_rte(sum[1]));
+
+    int dst_index = block_x * 4 * dsx + y * (dst_step / 4);
+    vstore4(line_out[0], 0, dst + dst_index);
+    vstore4(line_out[1], 0, dst + dst_index + (dst_step / 4));
+}
diff --git a/modules/imgproc/src/opencl/gaussianBlur5x5.cl b/modules/imgproc/src/opencl/gaussianBlur5x5.cl
new file mode 100644
index 0000000..dc0b15f
--- /dev/null
+++ b/modules/imgproc/src/opencl/gaussianBlur5x5.cl
@@ -0,0 +1,198 @@
+// This file is part of OpenCV project.
+// It is subject to the license terms in the LICENSE file found in the top-level directory
+// of this distribution and at http://opencv.org/license.html.
+
+#define DIG(a) a,
+__constant float kx[] = { KERNEL_MATRIX_X };
+__constant float ky[] = { KERNEL_MATRIX_Y };
+
+#define OP(y, x) (convert_float4(arr[y * 5 + x]) * ky[y] * kx[x])
+
+#define FILL_ARR(s1, s2, n, e1, e2)                                                   \
+    arr[5 * n + 0] = row_s ? (uchar4)(s1, s2, line[n].s23) : (uchar4)(line[n].s0123); \
+    arr[5 * n + 1] = row_s ? (uchar4)(s2, line[n].s234) : (uchar4)(line[n].s1234);    \
+    arr[5 * n + 2] = (uchar4)(line[n].s2345);                                         \
+    arr[5 * n + 3] = row_e ? (uchar4)(line[n].s345, e1) : (uchar4)(line[n].s3456);    \
+    arr[5 * n + 4] = row_e ? (uchar4)(line[n].s45, e1, e2) : (uchar4)(line[n].s4567);
+
+__kernel void gaussianBlur5x5_8UC1_cols4(__global const uchar* src, int src_step,
+                                         __global uint* dst, int dst_step, int rows, int cols)
+{
+    int x = get_global_id(0) * 4;
+    int y = get_global_id(1);
+
+    if (x >= cols || y >= rows) return;
+
+    uchar8 line[5];
+    int offset, src_index;
+
+    src_index = x + (y - 2) * src_step - 2;
+    offset = max(0, src_index + 2 * src_step);
+    line[2] = vload8(0, src + offset);
+    if (offset == 0) line[2] = (uchar8)(0, 0, line[2].s0123, line[2].s45);
+
+#if defined BORDER_CONSTANT || defined BORDER_REPLICATE
+    uchar8 tmp;
+#ifdef BORDER_CONSTANT
+    tmp = (uchar8)0;
+#elif defined BORDER_REPLICATE
+    tmp = line[2];
+#endif
+    line[0] = line[1] = tmp;
+    if (y > 1)
+    {
+        offset = max(0, src_index);
+        line[0] = vload8(0, src + offset);
+        if (offset == 0) line[0] = (uchar8)(0, 0, line[0].s0123, line[0].s45);
+    }
+
+    if (y > 0)
+    {
+        offset = max(0, src_index + src_step);
+        line[1] = vload8(0, src + offset);
+        if (offset == 0) line[1] = (uchar8)(0, 0, line[1].s0123, line[1].s45);
+    }
+
+    line[3] = (y == (rows - 1)) ? tmp : vload8(0, src + src_index + 3 * src_step);
+    line[4] = (y >= (rows - 2)) ? tmp : vload8(0, src + src_index + 4 * src_step);
+#elif BORDER_REFLECT
+    int t;
+    t = (y <= 1) ? (abs(y - 1) - y + 2) : 0;
+    offset = max(0, src_index + t * src_step);
+    line[0] = vload8(0, src + offset);
+    if (offset == 0) line[0] = (uchar8)(0, 0, line[0].s0123, line[0].s45);
+
+    if (y == 0)
+        line[1] = line[2];
+    else
+    {
+        offset = max(0, src_index + 1 * src_step);
+        line[1] = vload8(0, src + offset);
+        if (offset == 0) line[1] = (uchar8)(0, 0, line[1].s0123, line[0].s45);
+    }
+
+    line[3] = (y == (rows - 1)) ? line[2] : vload8(0, src + src_index + 3 * src_step);
+
+    t = (y >= (rows - 2)) ? (abs(y - (rows - 1)) - (y - (rows - 2)) + 2) : 4;
+    line[4] = vload8(0, src + src_index + t * src_step);
+#elif BORDER_REFLECT_101
+    if (y == 1)
+        line[0] = line[2];
+    else
+    {
+        offset = (y == 0) ? (src_index + 4 * src_step) : max(0, src_index);
+        line[0] = vload8(0, src + offset);
+        if (offset == 0) line[0] = (uchar8)(0, 0, line[0].s0123, line[0].s45);
+    }
+
+    offset = (y == 0) ? (src_index + 3 * src_step) : max(0, src_index + 1 * src_step);
+    line[1] = vload8(0, src + offset);
+    if (offset == 0) line[1] = (uchar8)(0, 0, line[1].s0123, line[1].s45);
+
+    line[3] = vload8(0, src + src_index + ((y == (rows - 1)) ? 1 : 3) * src_step);
+    if (y == (rows - 2))
+        line[4] = line[2];
+    else
+    {
+        line[4] = vload8(0, src + src_index + ((y == (rows - 1)) ? 1 : 4) * src_step);
+    }
+#endif
+
+    bool row_s = (x == 0);
+    bool row_e = ((x + 4) == cols);
+    uchar4 arr[25];
+    uchar s, e;
+
+#ifdef BORDER_CONSTANT
+    s = e = 0;
+
+    FILL_ARR(s, s, 0, e, e);
+    FILL_ARR(s, s, 1, e, e);
+    FILL_ARR(s, s, 2, e, e);
+    FILL_ARR(s, s, 3, e, e);
+    FILL_ARR(s, s, 4, e, e);
+#elif defined BORDER_REPLICATE
+    s = line[0].s2;
+    e = line[0].s5;
+    FILL_ARR(s, s, 0, e, e);
+
+    s = line[1].s2;
+    e = line[1].s5;
+    FILL_ARR(s, s, 1, e, e);
+
+    s = line[2].s2;
+    e = line[2].s5;
+    FILL_ARR(s, s, 2, e, e);
+
+    s = line[3].s2;
+    e = line[3].s5;
+    FILL_ARR(s, s, 3, e, e);
+
+    s = line[4].s2;
+    e = line[4].s5;
+    FILL_ARR(s, s, 4, e, e);
+#elif BORDER_REFLECT
+    uchar s1, s2;
+    uchar e1, e2;
+
+    s1 = line[0].s3;
+    s2 = line[0].s2;
+    e1 = line[0].s5;
+    e2 = line[0].s4;
+    FILL_ARR(s1, s2, 0, e1, e2);
+
+    s1 = line[1].s3;
+    s2 = line[1].s2;
+    e1 = line[1].s5;
+    e2 = line[1].s4;
+    FILL_ARR(s1, s2, 1, e1, e2);
+
+    s1 = line[2].s3;
+    s2 = line[2].s2;
+    e1 = line[2].s5;
+    e2 = line[2].s4;
+    FILL_ARR(s1, s2, 2, e1, e2);
+
+    s1 = line[3].s3;
+    s2 = line[3].s2;
+    e1 = line[3].s5;
+    e2 = line[3].s4;
+    FILL_ARR(s1, s2, 3, e1, e2);
+
+    s1 = line[4].s3;
+    s2 = line[4].s2;
+    e1 = line[4].s5;
+    e2 = line[4].s4;
+    FILL_ARR(s1, s2, 4, e1, e2);
+#elif BORDER_REFLECT_101
+    s = line[0].s4;
+    e = line[0].s3;
+    FILL_ARR(s, e, 0, s, e);
+
+    s = line[1].s4;
+    e = line[1].s3;
+    FILL_ARR(s, e, 1, s, e);
+
+    s = line[2].s4;
+    e = line[2].s3;
+    FILL_ARR(s, e, 2, s, e);
+
+    s = line[3].s4;
+    e = line[3].s3;
+    FILL_ARR(s, e, 3, s, e);
+
+    s = line[4].s4;
+    e = line[4].s3;
+    FILL_ARR(s, e, 4, s, e);
+#endif
+
+    float4 sum;
+    sum = OP(0, 0) + OP(0, 1) + OP(0, 2) + OP(0, 3) + OP(0, 4) +
+          OP(1, 0) + OP(1, 1) + OP(1, 2) + OP(1, 3) + OP(1, 4) +
+          OP(2, 0) + OP(2, 1) + OP(2, 2) + OP(2, 3) + OP(2, 4) +
+          OP(3, 0) + OP(3, 1) + OP(3, 2) + OP(3, 3) + OP(3, 4) +
+          OP(4, 0) + OP(4, 1) + OP(4, 2) + OP(4, 3) + OP(4, 4);
+
+    int dst_index = (x / 4) + y * (dst_step / 4);
+    dst[dst_index] = as_uint(convert_uchar4_sat_rte(sum));
+}
diff --git a/modules/imgproc/src/opencl/hough_lines.cl b/modules/imgproc/src/opencl/hough_lines.cl
index 4c2d0a9..9d0244c 100644
--- a/modules/imgproc/src/opencl/hough_lines.cl
+++ b/modules/imgproc/src/opencl/hough_lines.cl
@@ -80,7 +80,7 @@ __kernel void fill_accum_global(__global const uchar * list_ptr, int list_step,
             const int x = (val & 0xFFFF);
             const int y = (val >> 16) & 0xFFFF;
 
-            int r = convert_int_rte(mad(x, cosVal, y * sinVal)) + shift;
+            int r = convert_int_rte(mad((float)x, cosVal, y * sinVal)) + shift;
             atomic_inc(accum + r + 1);
         }
     }
@@ -117,7 +117,7 @@ __kernel void fill_accum_local(__global const uchar * list_ptr, int list_step, i
             const int x = (point & 0xFFFF);
             const int y = point >> 16;
 
-            int r = convert_int_rte(mad(x, cosVal, y * sinVal)) + shift;
+            int r = convert_int_rte(mad((float)x, cosVal, y * sinVal)) + shift;
             atomic_inc(l_accum + r + 1);
         }
 
@@ -186,7 +186,7 @@ __kernel void get_lines(__global const uchar * accum_ptr, int accum_step, int ac
 
     if (y < accum_rows-2)
     {
-        __global uchar* accum = accum_ptr + mad24(y+1, accum_step, mad24(x+1, (int) sizeof(int), accum_offset));
+        __global const uchar* accum = accum_ptr + mad24(y+1, accum_step, mad24(x+1, (int) sizeof(int), accum_offset));
         __global int4* lines = (__global int4*)(lines_ptr + lines_offset);
         __global int* lines_index = lines_index_ptr + 1;
 
@@ -330,4 +330,4 @@ __kernel void get_lines(__global const uchar * accum_ptr, int accum_step, int ac
     }
 }
 
-#endif
\ No newline at end of file
+#endif
diff --git a/modules/imgproc/src/opencl/integral_sum.cl b/modules/imgproc/src/opencl/integral_sum.cl
index 3c51c1a..29aba22 100644
--- a/modules/imgproc/src/opencl/integral_sum.cl
+++ b/modules/imgproc/src/opencl/integral_sum.cl
@@ -125,7 +125,7 @@ kernel void integral_sum_rows(__global const uchar *buf_ptr, int buf_step, int b
     sumT accum = 0;
 
 #ifdef SUM_SQUARE
-    __global sumSQT *dst_sq = (__global sumT *)(dst_sq_ptr + dst_sq_offset);
+    __global sumSQT *dst_sq = (__global sumSQT *)(dst_sq_ptr + dst_sq_offset);
     for (int xin = x; xin < cols; xin += gs)
     {
         dst_sq[xin] = 0;
diff --git a/modules/imgproc/src/opencl/laplacian3.cl b/modules/imgproc/src/opencl/laplacian3.cl
new file mode 100644
index 0000000..2d57032
--- /dev/null
+++ b/modules/imgproc/src/opencl/laplacian3.cl
@@ -0,0 +1,134 @@
+// This file is part of OpenCV project.
+// It is subject to the license terms in the LICENSE file found in the top-level directory
+// of this distribution and at http://opencv.org/license.html.
+
+#define DIG(a) a,
+__constant float kx[] = { KERNEL_MATRIX };
+
+#define OP(delta, x) (convert_float16(arr[delta + x]) * kx[x])
+
+__kernel void laplacian3_8UC1_cols16_rows2(__global const uint* src, int src_step,
+                                           __global uint* dst, int dst_step,
+                                           int rows, int cols, float delta)
+{
+    int block_x = get_global_id(0);
+    int y = get_global_id(1) * 2;
+    int ssx, dsx;
+
+    if ((block_x * 16) >= cols || y >= rows) return;
+
+    uint4 line[4];
+    uint4 line_out[2];
+    uchar a; uchar16 b; uchar c;
+    uchar d; uchar16 e; uchar f;
+    uchar g; uchar16 h; uchar i;
+    uchar j; uchar16 k; uchar l;
+
+    ssx = dsx = 1;
+    int src_index = block_x * 4 * ssx + (y - 1) * (src_step / 4);
+    line[1] = vload4(0, src + src_index + (src_step / 4));
+    line[2] = vload4(0, src + src_index + 2 * (src_step / 4));
+
+#ifdef BORDER_CONSTANT
+    line[0] = (y == 0) ? (uint4)0 : vload4(0, src + src_index);
+    line[3] = (y == (rows - 2)) ? (uint4)0 : vload4(0, src + src_index + 3 * (src_step / 4));
+#elif defined BORDER_REFLECT_101
+    line[0] = (y == 0) ? line[2] : vload4(0, src + src_index);
+    line[3] = (y == (rows - 2)) ? line[1] : vload4(0, src + src_index + 3 * (src_step / 4));
+#elif defined (BORDER_REPLICATE) || defined(BORDER_REFLECT)
+    line[0] = (y == 0) ? line[1] : vload4(0, src + src_index);
+    line[3] = (y == (rows - 2)) ? line[2] : vload4(0, src + src_index + 3 * (src_step / 4));
+#endif
+
+    __global uchar *src_p = (__global uchar *)src;
+
+    src_index = block_x * 16 * ssx + (y - 1) * src_step;
+    bool line_end = ((block_x + 1) * 16 == cols);
+
+    b = as_uchar16(line[0]);
+    e = as_uchar16(line[1]);
+    h = as_uchar16(line[2]);
+    k = as_uchar16(line[3]);
+
+#ifdef BORDER_CONSTANT
+    a = (block_x == 0 || y == 0) ? 0 : src_p[src_index - 1];
+    c = (line_end || y == 0) ? 0 : src_p[src_index + 16];
+
+    d = (block_x == 0) ? 0 : src_p[src_index + src_step - 1];
+    f = line_end ? 0 : src_p[src_index + src_step + 16];
+
+    g = (block_x == 0) ? 0 : src_p[src_index + 2 * src_step - 1];
+    i = line_end ? 0 : src_p[src_index + 2 * src_step + 16];
+
+    j = (block_x == 0 || y == (rows - 2)) ? 0 : src_p[src_index + 3 * src_step - 1];
+    l = (line_end || y == (rows - 2))? 0 : src_p[src_index + 3 * src_step + 16];
+
+#elif defined BORDER_REFLECT_101
+    int offset;
+    offset = (y == 0) ? (2 * src_step) : 0;
+
+    a = (block_x == 0) ? src_p[src_index + offset + 1] : src_p[src_index + offset - 1];
+    c = line_end ? src_p[src_index + offset + 14] : src_p[src_index + offset + 16];
+
+    d = (block_x == 0) ? src_p[src_index + src_step + 1] : src_p[src_index + src_step - 1];
+    f = line_end ? src_p[src_index + src_step + 14] : src_p[src_index + src_step + 16];
+
+    g = (block_x == 0) ? src_p[src_index + 2 * src_step + 1] : src_p[src_index + 2 * src_step - 1];
+    i = line_end ? src_p[src_index + 2 * src_step + 14] : src_p[src_index + 2 * src_step + 16];
+
+    offset = (y == (rows - 2)) ? (1 * src_step) : (3 * src_step);
+
+    j = (block_x == 0) ? src_p[src_index + offset + 1] : src_p[src_index + offset - 1];
+    l = line_end ? src_p[src_index + offset + 14] : src_p[src_index + offset + 16];
+
+#elif defined (BORDER_REPLICATE) || defined(BORDER_REFLECT)
+    int offset;
+    offset = (y == 0) ? (1 * src_step) : 0;
+
+    a = (block_x == 0) ? src_p[src_index + offset] : src_p[src_index + offset - 1];
+    c = line_end ? src_p[src_index + offset + 15] : src_p[src_index + offset + 16];
+
+    d = (block_x == 0) ? src_p[src_index + src_step] : src_p[src_index + src_step - 1];
+    f = line_end ? src_p[src_index + src_step + 15] : src_p[src_index + src_step + 16];
+
+    g = (block_x == 0) ? src_p[src_index + 2 * src_step] : src_p[src_index + 2 * src_step - 1];
+    i = line_end ? src_p[src_index + 2 * src_step + 15] : src_p[src_index + 2 * src_step + 16];
+
+    offset = (y == (rows - 2)) ? (2 * src_step) : (3 * src_step);
+
+    j = (block_x == 0) ? src_p[src_index + offset] : src_p[src_index + offset - 1];
+    l = line_end ? src_p[src_index + offset + 15] : src_p[src_index + offset + 16];
+
+#endif
+
+    uchar16 arr[12];
+    float16 sum[2];
+
+    arr[0] = (uchar16)(a, b.s0123, b.s456789ab, b.scde);
+    arr[1] = b;
+    arr[2] = (uchar16)(b.s123, b.s4567, b.s89abcdef, c);
+    arr[3] = (uchar16)(d, e.s0123, e.s456789ab, e.scde);
+    arr[4] = e;
+    arr[5] = (uchar16)(e.s123, e.s4567, e.s89abcdef, f);
+    arr[6] = (uchar16)(g, h.s0123, h.s456789ab, h.scde);
+    arr[7] = h;
+    arr[8] = (uchar16)(h.s123, h.s4567, h.s89abcdef, i);
+    arr[9] = (uchar16)(j, k.s0123, k.s456789ab, k.scde);
+    arr[10] = k;
+    arr[11] = (uchar16)(k.s123, k.s4567, k.s89abcdef, l);
+
+    sum[0] = OP(0, 0) + OP(0, 1) + OP(0, 2) +
+             OP(0, 3) + OP(0, 4) + OP(0, 5) +
+             OP(0, 6) + OP(0, 7) + OP(0, 8);
+
+    sum[1] = OP(3, 0) + OP(3, 1) + OP(3, 2) +
+             OP(3, 3) + OP(3, 4) + OP(3, 5) +
+             OP(3, 6) + OP(3, 7) + OP(3, 8);
+
+    line_out[0] = as_uint4(convert_uchar16_sat_rte(sum[0] + delta));
+    line_out[1] = as_uint4(convert_uchar16_sat_rte(sum[1] + delta));
+
+    int dst_index = block_x * 4 * dsx + y * (dst_step / 4);
+    vstore4(line_out[0], 0, dst + dst_index);
+    vstore4(line_out[1], 0, dst + dst_index + (dst_step / 4));
+}
diff --git a/modules/imgproc/src/opencl/linearPolar.cl b/modules/imgproc/src/opencl/linearPolar.cl
new file mode 100644
index 0000000..7a543fc
--- /dev/null
+++ b/modules/imgproc/src/opencl/linearPolar.cl
@@ -0,0 +1,69 @@
+#define CV_2PI 6.283185307179586476925286766559
+#ifdef ForwardMap
+__kernel void computeAngleRadius(__global float2* cp_sp, __global float* r, float maxRadius_width,  float PI2_height,  unsigned width, unsigned height)
+{
+    unsigned gid = get_global_id(0);
+    if (gid < height)
+    {
+        float angle = gid * PI2_height;
+        float2 angle_tri=(float2)(cos(angle), sin(angle));
+        cp_sp[gid] = angle_tri;
+    }
+    if (gid < width)
+    {
+        r[gid] = maxRadius_width*gid;
+    }
+}
+__kernel void linearPolar(__global float* mx, __global float* my, __global float2* cp_sp,  __global float* r, float cx, float cy, unsigned width, unsigned height)
+{
+    __local float l_r[MEM_SIZE];
+    __local float2 l_double[MEM_SIZE];
+    unsigned rho = get_global_id(0);
+
+    unsigned phi = get_global_id(1);
+    unsigned local_0 = get_local_id(0);
+    unsigned local_1 = get_local_id(1);
+    if (local_1 == 0)
+    {
+        unsigned temp_phi=phi + local_0;
+        if (temp_phi < height)
+        {
+            l_double[local_0] = cp_sp[temp_phi];
+        }
+    }
+    if (local_1 == 1 )
+    {
+        if (rho < width)
+        {
+            l_r[local_0 ] = r[rho];
+        }
+    }
+    barrier(CLK_LOCAL_MEM_FENCE);
+    if (rho<width && phi<height)
+    {
+        unsigned g_id = rho + phi*width;
+        float radius = l_r[local_0];
+        float2 tri= l_double[local_1];
+        mx[g_id] = fma(radius, tri.x , cx);
+        my[g_id] = fma(radius, tri.y , cy);
+    }
+}
+#elif defined (InverseMap)
+__kernel void linearPolar(__global float* mx, __global float* my, float ascale, float pscale, float cx, float cy, int angle_border, unsigned width, unsigned height)
+{
+    const int x = get_global_id(0);
+    const int y = get_global_id(1);
+    if (x < width && y < height)
+    {
+        unsigned g_id = x + y*width;
+        float dx = (float)x - cx;
+        float dy = (float)y - cy;
+        float mag = sqrt(dx*dx + dy*dy);
+        float angle = atan2(dy, dx);
+        if (angle < 0)
+            angle = angle + CV_2PI;
+        mx[g_id] = mag*pscale;
+        my[g_id] = (angle*ascale) + angle_border;
+    }
+}
+#endif
\ No newline at end of file
diff --git a/modules/imgproc/src/opencl/logPolar.cl b/modules/imgproc/src/opencl/logPolar.cl
new file mode 100644
index 0000000..149416a
--- /dev/null
+++ b/modules/imgproc/src/opencl/logPolar.cl
@@ -0,0 +1,69 @@
+#define CV_2PI 6.283185307179586476925286766559
+#ifdef ForwardMap
+__kernel void computeAngleRadius(__global float2* cp_sp, __global float* r, float m, float PI2_height, unsigned width, unsigned height)
+{
+    unsigned gid = get_global_id(0);
+    if (gid < height)
+    {
+        float angle = gid * PI2_height;
+        float2 angle_tri = (float2)(cos(angle), sin(angle));
+        cp_sp[gid] = angle_tri;
+    }
+    if (gid < width)
+    {
+        r[gid] = exp(gid/m)-1.0f;
+    }
+}
+__kernel void logPolar(__global float* mx, __global float* my, __global float2* cp_sp, __global float* r, float cx, float cy, unsigned width, unsigned height)
+{
+    __local float l_r[MEM_SIZE];
+    __local float2 l_double[MEM_SIZE];
+    unsigned rho = get_global_id(0);
+
+    unsigned phi = get_global_id(1);
+    unsigned local_0 = get_local_id(0);
+    unsigned local_1 = get_local_id(1);
+    if (local_1 == 0)
+    {
+        unsigned temp_phi = phi + local_0;
+        if (temp_phi < height)
+        {
+            l_double[local_0] = cp_sp[temp_phi];
+        }
+    }
+    if (local_1 == 1)
+    {
+        if (rho < width)
+        {
+            l_r[local_0] = r[rho];
+        }
+    }
+    barrier(CLK_LOCAL_MEM_FENCE);
+    if (rho<width && phi<height)
+    {
+        unsigned g_id = rho + phi*width;
+        float radius = l_r[local_0];
+        float2 tri = l_double[local_1];
+        mx[g_id] = fma(radius, tri.x , cx);
+        my[g_id] = fma(radius, tri.y, cy);
+    }
+}
+#elif defined (InverseMap)
+__kernel void logPolar(__global float* mx, __global float* my, float ascale, float m, float cx, float cy, int angle_border, unsigned width, unsigned height)
+{
+    const int x = get_global_id(0);
+    const int y = get_global_id(1);
+    if (x < width && y < height)
+    {
+        unsigned g_id = x + y*width;
+        float dx = (float)x - cx;
+        float dy = (float)y - cy;
+        float mag = log(sqrt(dx*dx + dy*dy)+1.0f);
+        float angle = atan2(dy, dx);
+        if (angle < 0)
+            angle = angle + CV_2PI;
+        mx[g_id] = mag*m;
+        my[g_id] = (angle*ascale) + angle_border;
+    }
+}
+#endif
\ No newline at end of file
diff --git a/modules/imgproc/src/opencl/match_template.cl b/modules/imgproc/src/opencl/match_template.cl
index f1bce5e..3fc8cd5 100644
--- a/modules/imgproc/src/opencl/match_template.cl
+++ b/modules/imgproc/src/opencl/match_template.cl
@@ -465,10 +465,10 @@ __kernel void matchTemplate_CCOEFF_NORMED(__global const uchar * src_sums, int s
         T value_sum   = sum[mad24(t_rows, step, t_cols)] - sum[mad24(t_rows, step, 0)] - sum[t_cols] + sum[0];
         T value_sqsum = sqsum[mad24(t_rows, step, t_cols)] - sqsum[mad24(t_rows, step, 0)] - sqsum[t_cols] + sqsum[0];
 
-        float num = convertToDT(mad(value_sum, template_sum, 0));
+        float num = convertToDT(mad(value_sum, template_sum, (float)0));
 
         value_sqsum -= weight * value_sum * value_sum;
-        float denum = sqrt(mad(template_sqsum, convertToDT(value_sqsum), 0));
+        float denum = sqrt(mad(template_sqsum, convertToDT(value_sqsum), (float)0));
 
         int dst_idx = mad24(y, dst_step, mad24(x, (int)sizeof(float), dst_offset));
         __global float * dstult = (__global float *)(dst+dst_idx);
@@ -509,7 +509,7 @@ __kernel void matchTemplate_CCOEFF_NORMED(__global const uchar * src_sums, int s
         float num = convertToDT(mad(value_sum, temp_sum, 0));
 
         value_sqsum -= weight * value_sum * value_sum;
-        float denum = sqrt(mad(template_sqsum, convertToDT(value_sqsum), 0));
+        float denum = sqrt(mad(template_sqsum, convertToDT(value_sqsum), (float)0));
 
         int dst_idx = mad24(y, dst_step, mad24(x, (int)sizeof(float), dst_offset));
         __global float * dstult = (__global float *)(dst+dst_idx);
@@ -549,7 +549,7 @@ __kernel void matchTemplate_CCOEFF_NORMED(__global const uchar * src_sums, int s
         float num = convertToDT(mad(value_sum, temp_sum, 0));
 
         value_sqsum -= weight * value_sum * value_sum;
-        float denum = sqrt(mad(template_sqsum, convertToDT(value_sqsum), 0));
+        float denum = sqrt(mad(template_sqsum, convertToDT(value_sqsum), (float)0));
 
         int dst_idx = mad24(y, dst_step, mad24(x, (int)sizeof(float), dst_offset));
         __global float * dstult = (__global float *)(dst+dst_idx);
diff --git a/modules/imgproc/src/opencl/morph3x3.cl b/modules/imgproc/src/opencl/morph3x3.cl
new file mode 100644
index 0000000..3dde505
--- /dev/null
+++ b/modules/imgproc/src/opencl/morph3x3.cl
@@ -0,0 +1,119 @@
+// This file is part of OpenCV project.
+// It is subject to the license terms in the LICENSE file found in the top-level directory
+// of this distribution and at http://opencv.org/license.html.
+
+#ifdef OP_ERODE
+#define OP(m1, m2) min(m1, m2)
+#define VAL UCHAR_MAX
+#endif
+
+#ifdef OP_DILATE
+#define OP(m1, m2) max(m1, m2)
+#define VAL 0
+#endif
+
+#if defined OP_GRADIENT || defined OP_TOPHAT || defined OP_BLACKHAT
+#define EXTRA_PARAMS , __global const uchar * matptr, int mat_step, int mat_offset
+#else
+#define EXTRA_PARAMS
+#endif
+
+#define PROCESS(_y, _x) \
+    line_out[0] = OP(line_out[0], arr[_x + 3 * _y]); \
+    line_out[1] = OP(line_out[1], arr[_x + 3 * (_y + 1)]);
+
+#define PROCESS_ELEM \
+    line_out[0] = (uchar16)VAL; \
+    line_out[1] = (uchar16)VAL; \
+    PROCESS_ELEM_
+
+__kernel void morph3x3_8UC1_cols16_rows2(__global const uint* src, int src_step,
+                                         __global uint* dst, int dst_step,
+                                         int rows, int cols
+                                         EXTRA_PARAMS)
+{
+    int block_x = get_global_id(0);
+    int y = get_global_id(1) * 2;
+    int ssx = 1, dsx = 1;
+
+    if ((block_x * 16) >= cols || y >= rows) return;
+
+    uchar a; uchar16 b; uchar c;
+    uchar d; uchar16 e; uchar f;
+    uchar g; uchar16 h; uchar i;
+    uchar j; uchar16 k; uchar l;
+
+    uchar16 line[4];
+    uchar16 line_out[2];
+
+    int src_index = block_x * 4 * ssx + (y - 1) * (src_step / 4);
+    line[0] = (y == 0) ? (uchar16)VAL: as_uchar16(vload4(0, src + src_index));
+    line[1] = as_uchar16(vload4(0, src + src_index + (src_step / 4)));
+    line[2] = as_uchar16(vload4(0, src + src_index + 2 * (src_step / 4)));
+    line[3] = (y == (rows - 2)) ? (uchar16)VAL: as_uchar16(vload4(0, src + src_index + 3 * (src_step / 4)));
+
+    __global uchar *src_p = (__global uchar *)src;
+    bool line_end = ((block_x + 1) * 16 == cols);
+
+    src_index = block_x * 16 * ssx + (y - 1) * src_step;
+
+    a = (block_x == 0 || y == 0) ? VAL : src_p[src_index - 1];
+    b = line[0];
+    c = (line_end || y == 0) ? VAL : src_p[src_index + 16];
+
+    d = (block_x == 0) ? VAL : src_p[src_index + src_step - 1];
+    e = line[1];
+    f = line_end ? VAL : src_p[src_index + src_step + 16];
+
+    g = (block_x == 0) ? VAL : src_p[src_index + 2 * src_step - 1];
+    h = line[2];
+    i = line_end ? VAL : src_p[src_index + 2 * src_step + 16];
+
+    j = (block_x == 0 || y == (rows - 2)) ? VAL : src_p[src_index + 3 * src_step - 1];
+    k = line[3];
+    l = (line_end || y == (rows - 2)) ? VAL : src_p[src_index + 3 * src_step + 16];
+
+    uchar16 arr[12];
+    arr[0] = (uchar16)(a, b.s01234567, b.s89ab, b.scde);
+    arr[1] = b;
+    arr[2] = (uchar16)(b.s12345678, b.s9abc, b.sdef, c);
+    arr[3] = (uchar16)(d, e.s01234567, e.s89ab, e.scde);
+    arr[4] = e;
+    arr[5] = (uchar16)(e.s12345678, e.s9abc, e.sdef, f);
+    arr[6] = (uchar16)(g, h.s01234567, h.s89ab, h.scde);
+    arr[7] = h;
+    arr[8] = (uchar16)(h.s12345678, h.s9abc, h.sdef, i);
+    arr[9] = (uchar16)(j, k.s01234567, k.s89ab, k.scde);
+    arr[10] = k;
+    arr[11] = (uchar16)(k.s12345678, k.s9abc, k.sdef, l);
+
+    PROCESS_ELEM;
+
+    int dst_index = block_x * 4 * dsx + y * (dst_step / 4);
+
+#if defined OP_GRADIENT || defined OP_TOPHAT || defined OP_BLACKHAT
+    int mat_index = y * mat_step + block_x * 16 * ssx + mat_offset;
+    uchar16 val0 = vload16(0, matptr + mat_index);
+    uchar16 val1 = vload16(0, matptr + mat_index + mat_step);
+
+#ifdef OP_GRADIENT
+    line_out[0] = convert_uchar16_sat(convert_int16(line_out[0]) - convert_int16(val0));
+    line_out[1] = convert_uchar16_sat(convert_int16(line_out[1]) - convert_int16(val1));
+    vstore4(as_uint4(line_out[0]), 0, dst + dst_index);
+    vstore4(as_uint4(line_out[1]), 0, dst + dst_index + (dst_step / 4));
+#elif defined OP_TOPHAT
+    line_out[0] = convert_uchar16_sat(convert_int16(val0) - convert_int16(line_out[0]));
+    line_out[1] = convert_uchar16_sat(convert_int16(val1) - convert_int16(line_out[1]));
+    vstore4(as_uint4(line_out[0]), 0, dst + dst_index);
+    vstore4(as_uint4(line_out[1]), 0, dst + dst_index + (dst_step / 4));
+#elif defined OP_BLACKHAT
+    line_out[0] = convert_uchar16_sat(convert_int16(line_out[0]) - convert_int16(val0));
+    line_out[1] = convert_uchar16_sat(convert_int16(line_out[1]) - convert_int16(val1));
+    vstore4(as_uint4(line_out[0]), 0, dst + dst_index);
+    vstore4(as_uint4(line_out[1]), 0, dst + dst_index + (dst_step / 4));
+#endif
+#else
+    vstore4(as_uint4(line_out[0]), 0, dst + dst_index);
+    vstore4(as_uint4(line_out[1]), 0, dst + dst_index + (dst_step / 4));
+#endif
+}
diff --git a/modules/imgproc/src/opencl/pyr_down.cl b/modules/imgproc/src/opencl/pyr_down.cl
index b6927fa..5d2e715 100644
--- a/modules/imgproc/src/opencl/pyr_down.cl
+++ b/modules/imgproc/src/opencl/pyr_down.cl
@@ -148,6 +148,7 @@ __kernel void pyrDown(__global const uchar * src, int src_step, int src_offset,
 
     if (src_y >= 2 && src_y < src_rows - 4)
     {
+#undef EXTRAPOLATE_
 #define EXTRAPOLATE_(val, maxVal)   val
 #if kercn == 1
         col = EXTRAPOLATE(x, src_cols);
@@ -180,6 +181,7 @@ __kernel void pyrDown(__global const uchar * src, int src_step, int src_offset,
     }
     else // need extrapolate y
     {
+#undef EXTRAPOLATE_
 #define EXTRAPOLATE_(val, maxVal)   EXTRAPOLATE(val, maxVal)
 #if kercn == 1
         col = EXTRAPOLATE(x, src_cols);
diff --git a/modules/imgproc/src/opencl/pyramid_up.cl b/modules/imgproc/src/opencl/pyramid_up.cl
new file mode 100644
index 0000000..4c3cde8
--- /dev/null
+++ b/modules/imgproc/src/opencl/pyramid_up.cl
@@ -0,0 +1,114 @@
+// This file is part of OpenCV project.
+// It is subject to the license terms in the LICENSE file found in the top-level directory
+// of this distribution and at http://opencv.org/license.html.
+
+__constant float kx[] = { 0.125, 0.5, 0.75, 0.5, 0.125 };
+__constant float ky[] = { 0.125, 0.5, 0.75, 0.5, 0.125 };
+
+#define OP(delta, y, x) (convert_float4(arr[(y + delta) * 5 + x]) * ky[y] * kx[x])
+
+__kernel void pyrUp_cols2(__global const uchar * src, int src_step, int src_offset, int src_rows, int src_cols,
+                          __global uchar * dst, int dst_step, int dst_offset, int dst_rows, int dst_cols)
+{
+    int block_x = get_global_id(0);
+    int y = get_global_id(1) * 2;
+
+    if ((block_x * 4) >= dst_cols || y >= dst_rows) return;
+
+    uchar8 line[6];
+    uchar4 line_out;
+
+    int offset, src_index;
+    src_index = block_x * 2 + (y / 2 - 1) * src_step - 1 + src_offset;
+
+    uchar4 tmp;
+
+    line[0] = line[2] = line[4] = (uchar8)0;
+    line[1] = line[3] = line[5] = (uchar8)0;
+
+    offset = max(0, src_index + 1 * src_step);
+    tmp = vload4(0, src + offset);
+    if (offset == 0) tmp = (uchar4)(0, tmp.s012);
+    line[2].even = tmp;
+
+    offset = max(0, src_index + ((y == 0) ? 2 : 0) * src_step);
+    tmp = vload4(0, src + offset);
+    if (offset == 0) tmp = (uchar4)(0, tmp.s012);
+    line[0].even = tmp;
+
+    if (y == (dst_rows - 2))
+        line[4] = line[2];
+    else
+        line[4].even = vload4(0, src + src_index + 2 * src_step);
+
+    bool row_s = (block_x == 0);
+    bool row_e = ((block_x + 1) * 4 == dst_cols);
+    uchar4 arr[30];
+    uchar s, e;
+
+    s = line[0].s4;
+    e = line[0].s3;
+    arr[0] = row_s ? (uchar4)(s, e, line[0].s23) : (uchar4)(line[0].s0123);
+    arr[1] = row_s ? (uchar4)(e, line[0].s234) : (uchar4)(line[0].s1234);
+    arr[2] = (uchar4)(line[0].s2345);
+    arr[3] = row_e ? (uchar4)(line[0].s345, s) : (uchar4)(line[0].s3456);
+    arr[4] = row_e ? (uchar4)(line[0].s45, s, e) : (uchar4)(line[0].s4567);
+
+    s = line[1].s4;
+    e = line[1].s3;
+    arr[5] = row_s ? (uchar4)(s, e, line[1].s23) : (uchar4)(line[1].s0123);
+    arr[6] = row_s ? (uchar4)(e, line[1].s234) : (uchar4)(line[1].s1234);
+    arr[7] = (uchar4)(line[1].s2345);
+    arr[8] = row_e ? (uchar4)(line[1].s345, s) : (uchar4)(line[1].s3456);
+    arr[9] = row_e ? (uchar4)(line[1].s45, s, e) : (uchar4)(line[1].s4567);
+
+    s = line[2].s4;
+    e = line[2].s3;
+    arr[10] = row_s ? (uchar4)(s, e, line[2].s23) : (uchar4)(line[2].s0123);
+    arr[11] = row_s ? (uchar4)(e, line[2].s234) : (uchar4)(line[2].s1234);
+    arr[12] = (uchar4)(line[2].s2345);
+    arr[13] = row_e ? (uchar4)(line[2].s345, s) : (uchar4)(line[2].s3456);
+    arr[14] = row_e ? (uchar4)(line[2].s45, s, e) : (uchar4)(line[2].s4567);
+
+    s = line[3].s4;
+    e = line[3].s3;
+    arr[15] = row_s ? (uchar4)(s, e, line[3].s23) : (uchar4)(line[3].s0123);
+    arr[16] = row_s ? (uchar4)(e, line[3].s234) : (uchar4)(line[3].s1234);
+    arr[17] = (uchar4)(line[3].s2345);
+    arr[18] = row_e ? (uchar4)(line[3].s345, s) : (uchar4)(line[3].s3456);
+    arr[19] = row_e ? (uchar4)(line[3].s45, s, e) : (uchar4)(line[3].s4567);
+
+    s = line[4].s4;
+    e = line[4].s3;
+    arr[20] = row_s ? (uchar4)(s, e, line[4].s23) : (uchar4)(line[4].s0123);
+    arr[21] = row_s ? (uchar4)(e, line[4].s234) : (uchar4)(line[4].s1234);
+    arr[22] = (uchar4)(line[4].s2345);
+    arr[23] = row_e ? (uchar4)(line[4].s345, s) : (uchar4)(line[4].s3456);
+    arr[24] = row_e ? (uchar4)(line[4].s45, s, e) : (uchar4)(line[4].s4567);
+
+    s = line[5].s4;
+    e = line[5].s3;
+    arr[25] = row_s ? (uchar4)(s, e, line[5].s23) : (uchar4)(line[5].s0123);
+    arr[26] = row_s ? (uchar4)(e, line[5].s234) : (uchar4)(line[5].s1234);
+    arr[27] = (uchar4)(line[5].s2345);
+    arr[28] = row_e ? (uchar4)(line[5].s345, s) : (uchar4)(line[5].s3456);
+    arr[29] = row_e ? (uchar4)(line[5].s45, s, e) : (uchar4)(line[5].s4567);
+
+    float4 sum[2];
+
+    sum[0] = OP(0, 0, 0) + OP(0, 0, 1) + OP(0, 0, 2) + OP(0, 0, 3) + OP(0, 0, 4) +
+             OP(0, 1, 0) + OP(0, 1, 1) + OP(0, 1, 2) + OP(0, 1, 3) + OP(0, 1, 4) +
+             OP(0, 2, 0) + OP(0, 2, 1) + OP(0, 2, 2) + OP(0, 2, 3) + OP(0, 2, 4) +
+             OP(0, 3, 0) + OP(0, 3, 1) + OP(0, 3, 2) + OP(0, 3, 3) + OP(0, 3, 4) +
+             OP(0, 4, 0) + OP(0, 4, 1) + OP(0, 4, 2) + OP(0, 4, 3) + OP(0, 4, 4);
+
+    sum[1] = OP(1, 0, 0) + OP(1, 0, 1) + OP(1, 0, 2) + OP(1, 0, 3) + OP(1, 0, 4) +
+             OP(1, 1, 0) + OP(1, 1, 1) + OP(1, 1, 2) + OP(1, 1, 3) + OP(1, 1, 4) +
+             OP(1, 2, 0) + OP(1, 2, 1) + OP(1, 2, 2) + OP(1, 2, 3) + OP(1, 2, 4) +
+             OP(1, 3, 0) + OP(1, 3, 1) + OP(1, 3, 2) + OP(1, 3, 3) + OP(1, 3, 4) +
+             OP(1, 4, 0) + OP(1, 4, 1) + OP(1, 4, 2) + OP(1, 4, 3) + OP(1, 4, 4);
+
+    int dst_index = block_x * 4 + y * dst_step + dst_offset;
+    vstore4(convert_uchar4_sat_rte(sum[0]), 0, dst + dst_index);
+    vstore4(convert_uchar4_sat_rte(sum[1]), 0, dst + dst_index + dst_step);
+}
diff --git a/modules/imgproc/src/opencl/remap.cl b/modules/imgproc/src/opencl/remap.cl
index 41f5fa8..1a30c32 100644
--- a/modules/imgproc/src/opencl/remap.cl
+++ b/modules/imgproc/src/opencl/remap.cl
@@ -414,8 +414,8 @@ __kernel void remap_2_32FC1(__global const uchar * srcptr, int src_step, int src
 
 #if defined BORDER_CONSTANT
                 float xf = map1[0], yf = map2[0];
-                int sx = convert_int_sat_rtz(mad(xf, INTER_TAB_SIZE, 0.5f)) >> INTER_BITS;
-                int sy = convert_int_sat_rtz(mad(yf, INTER_TAB_SIZE, 0.5f)) >> INTER_BITS;
+                int sx = convert_int_sat_rtz(mad(xf, (float)INTER_TAB_SIZE, 0.5f)) >> INTER_BITS;
+                int sy = convert_int_sat_rtz(mad(yf, (float)INTER_TAB_SIZE, 0.5f)) >> INTER_BITS;
 
                 __constant float * coeffs_x = coeffs + ((convert_int_rte(xf * INTER_TAB_SIZE) & (INTER_TAB_SIZE - 1)) << 1);
                 __constant float * coeffs_y = coeffs + ((convert_int_rte(yf * INTER_TAB_SIZE) & (INTER_TAB_SIZE - 1)) << 1);
diff --git a/modules/imgproc/src/opencl/sepFilter3x3.cl b/modules/imgproc/src/opencl/sepFilter3x3.cl
new file mode 100644
index 0000000..fc8bc06
--- /dev/null
+++ b/modules/imgproc/src/opencl/sepFilter3x3.cl
@@ -0,0 +1,135 @@
+// This file is part of OpenCV project.
+// It is subject to the license terms in the LICENSE file found in the top-level directory
+// of this distribution and at http://opencv.org/license.html.
+
+#define DIG(a) a,
+__constant float kx[] = { KERNEL_MATRIX_X };
+__constant float ky[] = { KERNEL_MATRIX_Y };
+
+#define OP(delta, y, x) (convert_float16(arr[(y + delta) * 3 + x]) * ky[y] * kx[x])
+
+__kernel void sepFilter3x3_8UC1_cols16_rows2(__global const uint* src, int src_step,
+                                             __global uint* dst, int dst_step,
+                                             int rows, int cols, float delta)
+{
+    int block_x = get_global_id(0);
+    int y = get_global_id(1) * 2;
+    int ssx, dsx;
+
+    if ((block_x * 16) >= cols || y >= rows) return;
+
+    uint4 line[4];
+    uint4 line_out[2];
+    uchar a; uchar16 b; uchar c;
+    uchar d; uchar16 e; uchar f;
+    uchar g; uchar16 h; uchar i;
+    uchar j; uchar16 k; uchar l;
+
+    ssx = dsx = 1;
+    int src_index = block_x * 4 * ssx + (y - 1) * (src_step / 4);
+    line[1] = vload4(0, src + src_index + (src_step / 4));
+    line[2] = vload4(0, src + src_index + 2 * (src_step / 4));
+
+#ifdef BORDER_CONSTANT
+    line[0] = (y == 0) ? (uint4)0 : vload4(0, src + src_index);
+    line[3] = (y == (rows - 2)) ? (uint4)0 : vload4(0, src + src_index + 3 * (src_step / 4));
+#elif defined BORDER_REFLECT_101
+    line[0] = (y == 0) ? line[2] : vload4(0, src + src_index);
+    line[3] = (y == (rows - 2)) ? line[1] : vload4(0, src + src_index + 3 * (src_step / 4));
+#elif defined (BORDER_REPLICATE) || defined(BORDER_REFLECT)
+    line[0] = (y == 0) ? line[1] : vload4(0, src + src_index);
+    line[3] = (y == (rows - 2)) ? line[2] : vload4(0, src + src_index + 3 * (src_step / 4));
+#endif
+
+    __global uchar *src_p = (__global uchar *)src;
+
+    src_index = block_x * 16 * ssx + (y - 1) * src_step;
+    bool line_end = ((block_x + 1) * 16 == cols);
+
+    b = as_uchar16(line[0]);
+    e = as_uchar16(line[1]);
+    h = as_uchar16(line[2]);
+    k = as_uchar16(line[3]);
+
+#ifdef BORDER_CONSTANT
+    a = (block_x == 0 || y == 0) ? 0 : src_p[src_index - 1];
+    c = (line_end || y == 0) ? 0 : src_p[src_index + 16];
+
+    d = (block_x == 0) ? 0 : src_p[src_index + src_step - 1];
+    f = line_end ? 0 : src_p[src_index + src_step + 16];
+
+    g = (block_x == 0) ? 0 : src_p[src_index + 2 * src_step - 1];
+    i = line_end ? 0 : src_p[src_index + 2 * src_step + 16];
+
+    j = (block_x == 0 || y == (rows - 2)) ? 0 : src_p[src_index + 3 * src_step - 1];
+    l = (line_end || y == (rows - 2))? 0 : src_p[src_index + 3 * src_step + 16];
+
+#elif defined BORDER_REFLECT_101
+    int offset;
+    offset = (y == 0) ? (2 * src_step) : 0;
+
+    a = (block_x == 0) ? src_p[src_index + offset + 1] : src_p[src_index + offset - 1];
+    c = line_end ? src_p[src_index + offset + 14] : src_p[src_index + offset + 16];
+
+    d = (block_x == 0) ? src_p[src_index + src_step + 1] : src_p[src_index + src_step - 1];
+    f = line_end ? src_p[src_index + src_step + 14] : src_p[src_index + src_step + 16];
+
+    g = (block_x == 0) ? src_p[src_index + 2 * src_step + 1] : src_p[src_index + 2 * src_step - 1];
+    i = line_end ? src_p[src_index + 2 * src_step + 14] : src_p[src_index + 2 * src_step + 16];
+
+    offset = (y == (rows - 2)) ? (1 * src_step) : (3 * src_step);
+
+    j = (block_x == 0) ? src_p[src_index + offset + 1] : src_p[src_index + offset - 1];
+    l = line_end ? src_p[src_index + offset + 14] : src_p[src_index + offset + 16];
+
+#elif defined (BORDER_REPLICATE) || defined(BORDER_REFLECT)
+    int offset;
+    offset = (y == 0) ? (1 * src_step) : 0;
+
+    a = (block_x == 0) ? src_p[src_index + offset] : src_p[src_index + offset - 1];
+    c = line_end ? src_p[src_index + offset + 15] : src_p[src_index + offset + 16];
+
+    d = (block_x == 0) ? src_p[src_index + src_step] : src_p[src_index + src_step - 1];
+    f = line_end ? src_p[src_index + src_step + 15] : src_p[src_index + src_step + 16];
+
+    g = (block_x == 0) ? src_p[src_index + 2 * src_step] : src_p[src_index + 2 * src_step - 1];
+    i = line_end ? src_p[src_index + 2 * src_step + 15] : src_p[src_index + 2 * src_step + 16];
+
+    offset = (y == (rows - 2)) ? (2 * src_step) : (3 * src_step);
+
+    j = (block_x == 0) ? src_p[src_index + offset] : src_p[src_index + offset - 1];
+    l = line_end ? src_p[src_index + offset + 15] : src_p[src_index + offset + 16];
+
+#endif
+
+    uchar16 arr[12];
+    float16 sum[2];
+
+    arr[0] = (uchar16)(a, b.s0123, b.s456789ab, b.scde);
+    arr[1] = b;
+    arr[2] = (uchar16)(b.s123, b.s4567, b.s89abcdef, c);
+    arr[3] = (uchar16)(d, e.s0123, e.s456789ab, e.scde);
+    arr[4] = e;
+    arr[5] = (uchar16)(e.s123, e.s4567, e.s89abcdef, f);
+    arr[6] = (uchar16)(g, h.s0123, h.s456789ab, h.scde);
+    arr[7] = h;
+    arr[8] = (uchar16)(h.s123, h.s4567, h.s89abcdef, i);
+    arr[9] = (uchar16)(j, k.s0123, k.s456789ab, k.scde);
+    arr[10] = k;
+    arr[11] = (uchar16)(k.s123, k.s4567, k.s89abcdef, l);
+
+    sum[0] = OP(0, 0, 0) + OP(0, 0, 1) + OP(0, 0, 2) +
+             OP(0, 1, 0) + OP(0, 1, 1) + OP(0, 1, 2) +
+             OP(0, 2, 0) + OP(0, 2, 1) + OP(0, 2, 2);
+
+    sum[1] = OP(1, 0, 0) + OP(1, 0, 1) + OP(1, 0, 2) +
+             OP(1, 1, 0) + OP(1, 1, 1) + OP(1, 1, 2) +
+             OP(1, 2, 0) + OP(1, 2, 1) + OP(1, 2, 2);
+
+    line_out[0] = as_uint4(convert_uchar16_sat_rte(sum[0] + delta));
+    line_out[1] = as_uint4(convert_uchar16_sat_rte(sum[1] + delta));
+
+    int dst_index = block_x * 4 * dsx + y * (dst_step / 4);
+    vstore4(line_out[0], 0, dst + dst_index);
+    vstore4(line_out[1], 0, dst + dst_index + (dst_step / 4));
+}
diff --git a/modules/imgproc/src/opencl/warp_affine.cl b/modules/imgproc/src/opencl/warp_affine.cl
index 229336e..8c6c5f9 100644
--- a/modules/imgproc/src/opencl/warp_affine.cl
+++ b/modules/imgproc/src/opencl/warp_affine.cl
@@ -104,8 +104,8 @@ __kernel void warpAffine(__global const uchar * srcptr, int src_step, int src_of
 
         for (int dy = dy0, dy1 = min(dst_rows, dy0 + rowsPerWI); dy < dy1; ++dy, dst_index += dst_step)
         {
-            int X0 = X0_ + rint(fma(M[1], dy, M[2]) * AB_SCALE) + round_delta;
-            int Y0 = Y0_ + rint(fma(M[4], dy, M[5]) * AB_SCALE) + round_delta;
+            int X0 = X0_ + rint(fma(M[1], (CT)dy, M[2]) * AB_SCALE) + round_delta;
+            int Y0 = Y0_ + rint(fma(M[4], (CT)dy, M[5]) * AB_SCALE) + round_delta;
 
             short sx = convert_short_sat(X0 >> AB_BITS);
             short sy = convert_short_sat(Y0 >> AB_BITS);
@@ -146,8 +146,8 @@ __kernel void warpAffine(__global const uchar * srcptr, int src_step, int src_of
 
         for (int dy = dy0, dy1 = min(dst_rows, dy0 + rowsPerWI); dy < dy1; ++dy)
         {
-            int X0 = X0_ + rint(fma(M[1], dy, M[2]) * AB_SCALE) + ROUND_DELTA;
-            int Y0 = Y0_ + rint(fma(M[4], dy, M[5]) * AB_SCALE) + ROUND_DELTA;
+            int X0 = X0_ + rint(fma(M[1], (CT)dy, M[2]) * AB_SCALE) + ROUND_DELTA;
+            int Y0 = Y0_ + rint(fma(M[4], (CT)dy, M[5]) * AB_SCALE) + ROUND_DELTA;
             X0 = X0 >> (AB_BITS - INTER_BITS);
             Y0 = Y0 >> (AB_BITS - INTER_BITS);
 
@@ -274,8 +274,8 @@ __kernel void warpAffine(__global const uchar * srcptr, int src_step, int src_of
     if (dx < dst_cols && dy < dst_rows)
     {
         int tmp = (dx << AB_BITS);
-        int X0 = rint(M[0] * tmp) + rint(fma(M[1], dy, M[2]) * AB_SCALE) + ROUND_DELTA;
-        int Y0 = rint(M[3] * tmp) + rint(fma(M[4], dy, M[5]) * AB_SCALE) + ROUND_DELTA;
+        int X0 = rint(M[0] * tmp) + rint(fma(M[1], (CT)dy, M[2]) * AB_SCALE) + ROUND_DELTA;
+        int Y0 = rint(M[3] * tmp) + rint(fma(M[4], (CT)dy, M[5]) * AB_SCALE) + ROUND_DELTA;
 
         X0 = X0 >> (AB_BITS - INTER_BITS);
         Y0 = Y0 >> (AB_BITS - INTER_BITS);
@@ -373,4 +373,4 @@ __kernel void warpAffine(__global const uchar * srcptr, int src_step, int src_of
     }
 }
 
-#endif
\ No newline at end of file
+#endif
diff --git a/modules/imgproc/src/opencl/warp_transform.cl b/modules/imgproc/src/opencl/warp_transform.cl
new file mode 100644
index 0000000..738613f
--- /dev/null
+++ b/modules/imgproc/src/opencl/warp_transform.cl
@@ -0,0 +1,408 @@
+// This file is part of OpenCV project.
+// It is subject to the license terms in the LICENSE file found in the top-level directory
+// of this distribution and at http://opencv.org/license.html.
+
+__constant short4 vec_offset = (short4)(0, 1, 2, 3);
+
+#define GET_VAL(x, y) ((x) < 0 || (x) >= src_cols || (y) < 0 || (y) >= src_rows) ? scalar : src[src_offset + y * src_step + x]
+
+__kernel void warpAffine_nearest_8u(__global const uchar * src, int src_step, int src_offset, int src_rows, int src_cols,
+                                    __global uchar * dst, int dst_step, int dst_offset, int dst_rows, int dst_cols,
+                                    __constant float * M, ST scalar_)
+{
+    int x = get_global_id(0) * 4;
+    int y = get_global_id(1);
+    uchar scalar = convert_uchar_sat_rte(scalar_);
+
+    if (x >= dst_cols || y >= dst_rows) return;
+
+    /* { M0, M1, M2 }
+     * { M3, M4, M5 }
+     */
+
+    short4 new_x, new_y;
+    new_x = convert_short4_sat_rte(M[0] * convert_float4(vec_offset + (short4)(x)) +
+                                   M[1] * convert_float4((short4)y) + M[2]);
+
+    new_y = convert_short4_sat_rte(M[3] * convert_float4(vec_offset + (short4)(x)) +
+                                   M[4] * convert_float4((short4)y) + M[5]);
+
+    uchar4 pix = (uchar4)scalar;
+
+    pix.s0 = GET_VAL(new_x.s0, new_y.s0);
+    pix.s1 = GET_VAL(new_x.s1, new_y.s1);
+    pix.s2 = GET_VAL(new_x.s2, new_y.s2);
+    pix.s3 = GET_VAL(new_x.s3, new_y.s3);
+
+    int dst_index = x + y * dst_step + dst_offset;
+
+    vstore4(pix, 0,  dst + dst_index);
+}
+
+uchar4 read_pixels(__global const uchar * src, short tx, short ty,
+                   int src_offset, int src_step, int src_cols, int
+                   src_rows, uchar scalar)
+{
+    uchar2 pt, pb;
+    short bx, by;
+
+    bx = tx + 1;
+    by = ty + 1;
+
+    if (tx >= 0 && (tx + 1) < src_cols && ty >= 0 && ty < src_rows)
+    {
+        pt = vload2(0, src + src_offset + ty * src_step + tx);
+    }
+    else
+    {
+        pt.s0 = GET_VAL(tx, ty);
+        pt.s1 = GET_VAL(bx, ty);
+    }
+
+    if (tx >= 0 && (tx + 1) < src_cols && by >= 0 && by < src_rows)
+    {
+        pb = vload2(0, src + src_offset + by * src_step + tx);
+    }
+    else
+    {
+        pb.s0 = GET_VAL(tx, by);
+        pb.s1 = GET_VAL(bx, by);
+    }
+
+    return (uchar4)(pt, pb);
+}
+
+__kernel void warpAffine_linear_8u(__global const uchar * src, int src_step, int src_offset, int src_rows, int src_cols,
+                                   __global uchar * dst, int dst_step, int dst_offset, int dst_rows, int dst_cols,
+                                   __constant float * M, ST scalar_)
+{
+    int x = get_global_id(0) * 4;
+    int y = get_global_id(1);
+    uchar scalar = convert_uchar_sat_rte(scalar_);
+
+    if (x >= dst_cols || y >= dst_rows) return;
+
+    /* { M0, M1, M2 }
+     * { M3, M4, M5 }
+     */
+
+    float4 nx, ny;
+    nx = M[0] * convert_float4((vec_offset + (short4)x)) + M[1] * convert_float4((short4)y) + M[2];
+    ny = M[3] * convert_float4((vec_offset + (short4)x)) + M[4] * convert_float4((short4)y) + M[5];
+
+    float4 s, t;
+    s = round((nx - floor(nx)) * 32.0f) / 32.0f;
+    t = round((ny - floor(ny)) * 32.0f) / 32.0f;
+
+    short4 tx, ty;
+    tx = convert_short4_sat_rtn(nx);
+    ty = convert_short4_sat_rtn(ny);
+
+    uchar4 pix[4];
+    pix[0] = read_pixels(src, tx.s0, ty.s0, src_offset, src_step, src_cols, src_rows, scalar);
+    pix[1] = read_pixels(src, tx.s1, ty.s1, src_offset, src_step, src_cols, src_rows, scalar);
+    pix[2] = read_pixels(src, tx.s2, ty.s2, src_offset, src_step, src_cols, src_rows, scalar);
+    pix[3] = read_pixels(src, tx.s3, ty.s3, src_offset, src_step, src_cols, src_rows, scalar);
+
+    float4 tl, tr, bl, br;
+    tl = convert_float4((uchar4)(pix[0].s0, pix[1].s0, pix[2].s0, pix[3].s0));
+    tr = convert_float4((uchar4)(pix[0].s1, pix[1].s1, pix[2].s1, pix[3].s1));
+    bl = convert_float4((uchar4)(pix[0].s2, pix[1].s2, pix[2].s2, pix[3].s2));
+    br = convert_float4((uchar4)(pix[0].s3, pix[1].s3, pix[2].s3, pix[3].s3));
+
+    float4 pixel;
+    pixel = tl * (1 - s) * (1 - t) + tr * s * (1 - t) + bl * (1 - s) * t + br * s * t;
+
+    int dst_index = x + y * dst_step + dst_offset;
+    vstore4(convert_uchar4_sat_rte(pixel), 0, dst + dst_index);
+}
+
+__constant float coeffs[128] =
+    { 0.000000f, 1.000000f, 0.000000f, 0.000000f, -0.021996f, 0.997841f, 0.024864f, -0.000710f, -0.041199f, 0.991516f, 0.052429f, -0.002747f,
+    -0.057747f, 0.981255f, 0.082466f, -0.005974f, -0.071777f, 0.967285f, 0.114746f, -0.010254f, -0.083427f, 0.949837f, 0.149040f, -0.015450f,
+    -0.092834f, 0.929138f, 0.185120f, -0.021423f, -0.100136f, 0.905418f, 0.222755f, -0.028038f, -0.105469f, 0.878906f, 0.261719f, -0.035156f,
+    -0.108971f, 0.849831f, 0.301781f, -0.042641f, -0.110779f, 0.818420f, 0.342712f, -0.050354f, -0.111031f, 0.784904f, 0.384285f, -0.058159f,
+    -0.109863f, 0.749512f, 0.426270f, -0.065918f, -0.107414f, 0.712471f, 0.468437f, -0.073494f, -0.103821f, 0.674011f, 0.510559f, -0.080750f,
+    -0.099220f, 0.634361f, 0.552406f, -0.087547f, -0.093750f, 0.593750f, 0.593750f, -0.093750f, -0.087547f, 0.552406f, 0.634361f, -0.099220f,
+    -0.080750f, 0.510559f, 0.674011f, -0.103821f, -0.073494f, 0.468437f, 0.712471f, -0.107414f, -0.065918f, 0.426270f, 0.749512f, -0.109863f,
+    -0.058159f, 0.384285f, 0.784904f, -0.111031f, -0.050354f, 0.342712f, 0.818420f, -0.110779f, -0.042641f, 0.301781f, 0.849831f, -0.108971f,
+    -0.035156f, 0.261719f, 0.878906f, -0.105469f, -0.028038f, 0.222755f, 0.905418f, -0.100136f, -0.021423f, 0.185120f, 0.929138f, -0.092834f,
+    -0.015450f, 0.149040f, 0.949837f, -0.083427f, -0.010254f, 0.114746f, 0.967285f, -0.071777f, -0.005974f, 0.082466f, 0.981255f, -0.057747f,
+    -0.002747f, 0.052429f, 0.991516f, -0.041199f, -0.000710f, 0.024864f, 0.997841f, -0.021996f };
+
+uchar4 read_pixels_cubic(__global const uchar * src, int tx, int ty,
+                         int src_offset, int src_step, int src_cols, int src_rows, uchar scalar)
+{
+    uchar4 pix;
+
+    if (tx >= 0 && (tx + 3) < src_cols && ty >= 0 && ty < src_rows)
+    {
+        pix = vload4(0, src + src_offset + ty * src_step + tx);
+    }
+    else
+    {
+        pix.s0 = GET_VAL((tx + 0), ty);
+        pix.s1 = GET_VAL((tx + 1), ty);
+        pix.s2 = GET_VAL((tx + 2), ty);
+        pix.s3 = GET_VAL((tx + 3), ty);
+    }
+
+    return pix;
+}
+
+__kernel void warpAffine_cubic_8u(__global const uchar * src, int src_step, int src_offset, int src_rows, int src_cols,
+                                  __global uchar * dst, int dst_step, int dst_offset, int dst_rows, int dst_cols,
+                                  __constant float * M, ST scalar_)
+{
+    int x = get_global_id(0) * 4;
+    int y = get_global_id(1);
+    uchar scalar = convert_uchar_sat_rte(scalar_);
+
+    if (x >= dst_cols || y >= dst_rows) return;
+
+    /* { M0, M1, M2 }
+     * { M3, M4, M5 }
+     */
+
+    float4 nx, ny;
+    nx = M[0] * convert_float4((vec_offset + (short4)x)) + M[1] * convert_float4((short4)y) + M[2];
+    ny = M[3] * convert_float4((vec_offset + (short4)x)) + M[4] * convert_float4((short4)y) + M[5];
+
+    int4 ax, ay;
+    ax = convert_int4_sat_rte((nx - floor(nx)) * 32.0f) & 31;
+    ay = convert_int4_sat_rte((ny - floor(ny)) * 32.0f) & 31;
+
+    int4 tx, ty;
+    int4 delta_x, delta_y;
+
+    delta_x = select((int4)1, (int4)0, ((nx - floor(nx))) * 64 > 63);
+    delta_y = select((int4)1, (int4)0, ((ny - floor(ny))) * 64 > 63);
+
+    tx = convert_int4_sat_rtn(nx) - delta_x;
+    ty = convert_int4_sat_rtn(ny) - delta_y;
+
+    __constant float * coeffs_x, * coeffs_y;
+    float4 sum = (float4)0.0f;
+    uchar4 pix;
+    float xsum;
+
+    coeffs_x = coeffs + (ax.s0 << 2);
+    coeffs_y = coeffs + (ay.s0 << 2);
+    for (int i = 0; i < 4; i++)
+    {
+        pix = read_pixels_cubic(src, tx.s0, ty.s0 + i, src_offset, src_step, src_cols, src_rows, scalar);
+        xsum = dot(convert_float4(pix), (float4)(coeffs_x[0], coeffs_x[1], coeffs_x[2], coeffs_x[3]));
+        sum.s0 = fma(xsum, coeffs_y[i], sum.s0);
+    }
+
+    coeffs_x = coeffs + (ax.s1 << 2);
+    coeffs_y = coeffs + (ay.s1 << 2);
+    for (int i = 0; i < 4; i++)
+    {
+        pix = read_pixels_cubic(src, tx.s1, ty.s1 + i, src_offset, src_step, src_cols, src_rows, scalar);
+        xsum = dot(convert_float4(pix), (float4)(coeffs_x[0], coeffs_x[1], coeffs_x[2], coeffs_x[3]));
+        sum.s1 = fma(xsum, coeffs_y[i], sum.s1);
+    }
+
+    coeffs_x = coeffs + (ax.s2 << 2);
+    coeffs_y = coeffs + (ay.s2 << 2);
+    for (int i = 0; i < 4; i++)
+    {
+        pix = read_pixels_cubic(src, tx.s2, ty.s2 + i, src_offset, src_step, src_cols, src_rows, scalar);
+        xsum = dot(convert_float4(pix), (float4)(coeffs_x[0], coeffs_x[1], coeffs_x[2], coeffs_x[3]));
+        sum.s2 = fma(xsum, coeffs_y[i], sum.s2);
+    }
+
+    coeffs_x = coeffs + (ax.s3 << 2);
+    coeffs_y = coeffs + (ay.s3 << 2);
+    for (int i = 0; i < 4; i++)
+    {
+        pix = read_pixels_cubic(src, tx.s3, ty.s3 + i, src_offset, src_step, src_cols, src_rows, scalar);
+        xsum = dot(convert_float4(pix), (float4)(coeffs_x[0], coeffs_x[1], coeffs_x[2], coeffs_x[3]));
+        sum.s3 = fma(xsum, coeffs_y[i], sum.s3);
+    }
+
+    int dst_index = x + y * dst_step + dst_offset;
+    vstore4(convert_uchar4_sat_rte(sum), 0, dst + dst_index);
+}
+
+__kernel void warpPerspective_nearest_8u(__global const uchar * src, int src_step, int src_offset, int src_rows, int src_cols,
+                                         __global uchar * dst, int dst_step, int dst_offset, int dst_rows, int dst_cols,
+                                         __constant float * M, ST scalar_)
+{
+    int x = get_global_id(0) * 4;
+    int y = get_global_id(1);
+    uchar scalar = convert_uchar_sat_rte(scalar_);
+
+    if (x >= dst_cols || y >= dst_rows) return;
+
+    /* { M0, M1, M2 }
+     * { M3, M4, M5 }
+     * { M6, M7, M8 }
+     */
+
+    float4 nx, ny, nz;
+    nx = M[0] * convert_float4(vec_offset + (short4)(x)) +
+         M[1] * convert_float4((short4)y) + M[2];
+
+    ny = M[3] * convert_float4(vec_offset + (short4)(x)) +
+         M[4] * convert_float4((short4)y) + M[5];
+
+    nz = M[6] * convert_float4(vec_offset + (short4)(x)) +
+         M[7] * convert_float4((short4)y) + M[8];
+
+    short4 new_x, new_y;
+    float4 fz = select((float4)(0.0f), (float4)(1.0f / nz), nz != 0.0f);
+    new_x = convert_short4_sat_rte(nx * fz);
+    new_y = convert_short4_sat_rte(ny * fz);
+
+    uchar4 pix = (uchar4)scalar;
+
+    pix.s0 = GET_VAL(new_x.s0, new_y.s0);
+    pix.s1 = GET_VAL(new_x.s1, new_y.s1);
+    pix.s2 = GET_VAL(new_x.s2, new_y.s2);
+    pix.s3 = GET_VAL(new_x.s3, new_y.s3);
+
+    int dst_index = x + y * dst_step + dst_offset;
+
+    vstore4(pix, 0,  dst + dst_index);
+}
+
+__kernel void warpPerspective_linear_8u(__global const uchar * src, int src_step, int src_offset, int src_rows, int src_cols,
+                                        __global uchar * dst, int dst_step, int dst_offset, int dst_rows, int dst_cols,
+                                        __constant float * M, ST scalar_)
+{
+    int x = get_global_id(0) * 4;
+    int y = get_global_id(1);
+    uchar scalar = convert_uchar_sat_rte(scalar_);
+
+    if (x >= dst_cols || y >= dst_rows) return;
+
+    /* { M0, M1, M2 }
+     * { M3, M4, M5 }
+     * { M6, M7, M8 }
+     */
+
+    float4 nx, ny, nz;
+    nx = M[0] * convert_float4(vec_offset + (short4)(x)) + M[1] * convert_float4((short4)y) + M[2];
+
+    ny = M[3] * convert_float4(vec_offset + (short4)(x)) + M[4] * convert_float4((short4)y) + M[5];
+
+    nz = M[6] * convert_float4(vec_offset + (short4)(x)) + M[7] * convert_float4((short4)y) + M[8];
+
+    float4 fz = select((float4)(0.0f), (float4)(1.0f / nz), nz != 0.0f);
+
+    nx = nx * fz;
+    ny = ny * fz;
+
+    float4 s, t;
+    s = round((nx - floor(nx)) * 32.0f) / (float4)32.0f;
+    t = round((ny - floor(ny)) * 32.0f) / (float4)32.0f;
+
+    short4 tx, ty;
+    tx = convert_short4_sat_rtn(nx);
+    ty = convert_short4_sat_rtn(ny);
+
+    uchar4 pix[4];
+    pix[0] = read_pixels(src, tx.s0, ty.s0, src_offset, src_step, src_cols, src_rows, scalar);
+    pix[1] = read_pixels(src, tx.s1, ty.s1, src_offset, src_step, src_cols, src_rows, scalar);
+    pix[2] = read_pixels(src, tx.s2, ty.s2, src_offset, src_step, src_cols, src_rows, scalar);
+    pix[3] = read_pixels(src, tx.s3, ty.s3, src_offset, src_step, src_cols, src_rows, scalar);
+
+    float4 tl, tr, bl, br;
+    tl = convert_float4((uchar4)(pix[0].s0, pix[1].s0, pix[2].s0, pix[3].s0));
+    tr = convert_float4((uchar4)(pix[0].s1, pix[1].s1, pix[2].s1, pix[3].s1));
+    bl = convert_float4((uchar4)(pix[0].s2, pix[1].s2, pix[2].s2, pix[3].s2));
+    br = convert_float4((uchar4)(pix[0].s3, pix[1].s3, pix[2].s3, pix[3].s3));
+
+    float4 pixel;
+    pixel = tl * (1 - s) * (1 - t) + tr * s * (1 - t) + bl * (1 - s) * t + br * s * t;
+
+    int dst_index = x + y * dst_step + dst_offset;
+    vstore4(convert_uchar4_sat_rte(pixel), 0,  dst + dst_index);
+}
+
+__kernel void warpPerspective_cubic_8u(__global const uchar * src, int src_step, int src_offset, int src_rows, int src_cols,
+                                       __global uchar * dst, int dst_step, int dst_offset, int dst_rows, int dst_cols,
+                                       __constant float * M, ST scalar_)
+{
+    int x = get_global_id(0) * 4;
+    int y = get_global_id(1);
+    uchar scalar = convert_uchar_sat_rte(scalar_);
+
+    if (x >= dst_cols || y >= dst_rows) return;
+
+    /* { M0, M1, M2 }
+     * { M3, M4, M5 }
+     * { M6, M7, M8 }
+     */
+
+    float4 nx, ny, nz;
+    nx = M[0] * convert_float4(vec_offset + (short4)(x)) + M[1] * convert_float4((short4)y) + M[2];
+
+    ny = M[3] * convert_float4(vec_offset + (short4)(x)) + M[4] * convert_float4((short4)y) + M[5];
+
+    nz = M[6] * convert_float4(vec_offset + (short4)(x)) + M[7] * convert_float4((short4)y) + M[8];
+
+    float4 fz = select((float4)(0.0f), (float4)(1.0f / nz), nz != 0.0f);
+
+    nx = nx * fz;
+    ny = ny * fz;
+
+    int4 ax, ay;
+    ax = convert_int4_sat_rte((nx - floor(nx)) * 32.0f) & 31;
+    ay = convert_int4_sat_rte((ny - floor(ny)) * 32.0f) & 31;
+
+    int4 tx, ty;
+    int4 delta_x, delta_y;
+
+    delta_x = select((int4)1, (int4)0, ((nx - floor(nx))) * 64 > 63);
+    delta_y = select((int4)1, (int4)0, ((ny - floor(ny))) * 64 > 63);
+
+    tx = convert_int4_sat_rtn(nx) - delta_x;
+    ty = convert_int4_sat_rtn(ny) - delta_y;
+
+    __constant float * coeffs_x, * coeffs_y;
+    float4 sum = (float4)0.0f;
+    uchar4 pix;
+    float xsum;
+
+    coeffs_x = coeffs + (ax.s0 << 2);
+    coeffs_y = coeffs + (ay.s0 << 2);
+    for (int i = 0; i < 4; i++)
+    {
+        pix = read_pixels_cubic(src, tx.s0, ty.s0 + i, src_offset, src_step, src_cols, src_rows, scalar);
+        xsum = dot(convert_float4(pix), (float4)(coeffs_x[0], coeffs_x[1], coeffs_x[2], coeffs_x[3]));
+        sum.s0 = fma(xsum, coeffs_y[i], sum.s0);
+    }
+
+    coeffs_x = coeffs + (ax.s1 << 2);
+    coeffs_y = coeffs + (ay.s1 << 2);
+    for (int i = 0; i < 4; i++)
+    {
+        pix = read_pixels_cubic(src, tx.s1, ty.s1 + i, src_offset, src_step, src_cols, src_rows, scalar);
+        xsum = dot(convert_float4(pix), (float4)(coeffs_x[0], coeffs_x[1], coeffs_x[2], coeffs_x[3]));
+        sum.s1 = fma(xsum, coeffs_y[i], sum.s1);
+    }
+
+    coeffs_x = coeffs + (ax.s2 << 2);
+    coeffs_y = coeffs + (ay.s2 << 2);
+    for (int i = 0; i < 4; i++)
+    {
+        pix = read_pixels_cubic(src, tx.s2, ty.s2 + i, src_offset, src_step, src_cols, src_rows, scalar);
+        xsum = dot(convert_float4(pix), (float4)(coeffs_x[0], coeffs_x[1], coeffs_x[2], coeffs_x[3]));
+        sum.s2 = fma(xsum, coeffs_y[i], sum.s2);
+    }
+
+    coeffs_x = coeffs + (ax.s3 << 2);
+    coeffs_y = coeffs + (ay.s3 << 2);
+    for (int i = 0; i < 4; i++)
+    {
+        pix = read_pixels_cubic(src, tx.s3, ty.s3 + i, src_offset, src_step, src_cols, src_rows, scalar);
+        xsum = dot(convert_float4(pix), (float4)(coeffs_x[0], coeffs_x[1], coeffs_x[2], coeffs_x[3]));
+        sum.s3 = fma(xsum, coeffs_y[i], sum.s3);
+    }
+
+    int dst_index = x + y * dst_step + dst_offset;
+    vstore4(convert_uchar4_sat_rte(sum), 0, dst + dst_index);
+}
diff --git a/modules/imgproc/src/phasecorr.cpp b/modules/imgproc/src/phasecorr.cpp
index e6416ea..0b02a1e 100644
--- a/modules/imgproc/src/phasecorr.cpp
+++ b/modules/imgproc/src/phasecorr.cpp
@@ -167,6 +167,9 @@ static void divSpectrums( InputArray _srcA, InputArray _srcB, OutputArray _dst,
     _dst.create( srcA.rows, srcA.cols, type );
     Mat dst = _dst.getMat();
 
+    CV_Assert(dst.data != srcA.data); // non-inplace check
+    CV_Assert(dst.data != srcB.data); // non-inplace check
+
     bool is_1d = (flags & DFT_ROWS) || (rows == 1 || (cols == 1 &&
              srcA.isContinuous() && srcB.isContinuous() && dst.isContinuous()));
 
@@ -490,6 +493,8 @@ static Point2d weightedCentroid(InputArray _src, cv::Point peakLocation, cv::Siz
 
 cv::Point2d cv::phaseCorrelate(InputArray _src1, InputArray _src2, InputArray _window, double* response)
 {
+    CV_INSTRUMENT_REGION()
+
     Mat src1 = _src1.getMat();
     Mat src2 = _src2.getMat();
     Mat window = _window.getMat();
@@ -571,6 +576,8 @@ cv::Point2d cv::phaseCorrelate(InputArray _src1, InputArray _src2, InputArray _w
 
 void cv::createHanningWindow(OutputArray _dst, cv::Size winSize, int type)
 {
+    CV_INSTRUMENT_REGION()
+
     CV_Assert( type == CV_32FC1 || type == CV_64FC1 );
 
     _dst.create(winSize, type);
diff --git a/modules/imgproc/src/precomp.hpp b/modules/imgproc/src/precomp.hpp
index ed27eea..20a43a6 100644
--- a/modules/imgproc/src/precomp.hpp
+++ b/modules/imgproc/src/precomp.hpp
@@ -50,6 +50,8 @@
 #include "opencv2/core/private.hpp"
 #include "opencv2/core/ocl.hpp"
 #include "opencv2/core/hal/hal.hpp"
+#include "opencv2/imgproc/hal/hal.hpp"
+#include "hal_replacement.hpp"
 
 #include <math.h>
 #include <assert.h>
diff --git a/modules/imgproc/src/pyramids.cpp b/modules/imgproc/src/pyramids.cpp
index 0d311e2..c0e18c1 100644
--- a/modules/imgproc/src/pyramids.cpp
+++ b/modules/imgproc/src/pyramids.cpp
@@ -44,6 +44,8 @@
 #include "precomp.hpp"
 #include "opencl_kernels_imgproc.hpp"
 
+#include "opencv2/core/openvx/ovx_defs.hpp"
+
 namespace cv
 {
 
@@ -1010,7 +1012,7 @@ pyrUp_( const Mat& _src, Mat& _dst, int)
         for( ; sy <= y + 1; sy++ )
         {
             WT* row = buf + ((sy - sy0) % PU_SZ)*bufstep;
-            int _sy = borderInterpolate(sy*2, dsize.height, BORDER_REFLECT_101)/2;
+            int _sy = borderInterpolate(sy*2, ssize.height*2, BORDER_REFLECT_101)/2;
             const T* src = _src.ptr<T>(_sy);
 
             if( ssize.width == cn )
@@ -1031,6 +1033,11 @@ pyrUp_( const Mat& _src, Mat& _dst, int)
                 t0 = src[sx - cn] + src[sx]*7;
                 t1 = src[sx]*8;
                 row[dx] = t0; row[dx + cn] = t1;
+
+                if (dsize.width > ssize.width*2)
+                {
+                    row[(_dst.cols-1) + x] = row[dx + cn];
+                }
             }
 
             for( x = cn; x < ssize.width - cn; x++ )
@@ -1057,6 +1064,17 @@ pyrUp_( const Mat& _src, Mat& _dst, int)
             dst1[x] = t1; dst0[x] = t0;
         }
     }
+
+    if (dsize.height > ssize.height*2)
+    {
+        T* dst0 = _dst.ptr<T>(ssize.height*2-2);
+        T* dst2 = _dst.ptr<T>(ssize.height*2);
+
+        for(x = 0; x < dsize.width ; x++ )
+        {
+            dst2[x] = dst0[x];
+        }
+    }
 }
 
 typedef void (*PyrFunc)(const Mat&, Mat&, int);
@@ -1149,8 +1167,17 @@ static bool ocl_pyrUp( InputArray _src, OutputArray _dst, const Size& _dsz, int
     ocl::Kernel k;
     if (ocl::Device::getDefault().isIntel() && channels == 1)
     {
-        k.create("pyrUp_unrolled", ocl::imgproc::pyr_up_oclsrc, buildOptions);
-        globalThreads[0] = dst.cols/2; globalThreads[1] = dst.rows/2;
+        if (type == CV_8UC1 && src.cols % 2 == 0)
+        {
+            buildOptions.clear();
+            k.create("pyrUp_cols2", ocl::imgproc::pyramid_up_oclsrc, buildOptions);
+            globalThreads[0] = dst.cols/4; globalThreads[1] = dst.rows/2;
+        }
+        else
+        {
+            k.create("pyrUp_unrolled", ocl::imgproc::pyr_up_oclsrc, buildOptions);
+            globalThreads[0] = dst.cols/2; globalThreads[1] = dst.rows/2;
+        }
     }
     else
         k.create("pyrUp", ocl::imgproc::pyr_up_oclsrc, buildOptions);
@@ -1171,6 +1198,8 @@ namespace cv
 {
 static bool ipp_pyrdown( InputArray _src, OutputArray _dst, const Size& _dsz, int borderType )
 {
+    CV_INSTRUMENT_REGION_IPP()
+
 #if IPP_VERSION_X100 >= 810 && IPP_DISABLE_BLOCK
     Size dsz = _dsz.area() == 0 ? Size((_src.cols() + 1)/2, (_src.rows() + 1)/2) : _dsz;
     bool isolated = (borderType & BORDER_ISOLATED) != 0;
@@ -1227,13 +1256,94 @@ static bool ipp_pyrdown( InputArray _src, OutputArray _dst, const Size& _dsz, in
 }
 #endif
 
+#ifdef HAVE_OPENVX
+namespace cv
+{
+static bool openvx_pyrDown( InputArray _src, OutputArray _dst, const Size& _dsz, int borderType )
+{
+    using namespace ivx;
+
+    Mat srcMat = _src.getMat();
+
+    CV_Assert(!srcMat.empty());
+
+    Size ssize = _src.size();
+    Size acceptableSize = Size((ssize.width + 1) / 2, (ssize.height + 1) / 2);
+
+    // OpenVX limitations
+    if((srcMat.type() != CV_8U) ||
+       (borderType != BORDER_REPLICATE) ||
+       (_dsz != acceptableSize && _dsz.area() != 0))
+        return false;
+
+    // The only border mode which is supported by both cv::pyrDown() and OpenVX
+    // and produces predictable results
+    ivx::border_t borderMode;
+    borderMode.mode = VX_BORDER_REPLICATE;
+
+    _dst.create( acceptableSize, srcMat.type() );
+    Mat dstMat = _dst.getMat();
+
+    CV_Assert( ssize.width > 0 && ssize.height > 0 &&
+            std::abs(acceptableSize.width*2 - ssize.width) <= 2 &&
+            std::abs(acceptableSize.height*2 - ssize.height) <= 2 );
+
+    try
+    {
+        Context context = Context::create();
+        if(context.vendorID() == VX_ID_KHRONOS)
+        {
+            // This implementation performs floor-like rounding
+            // (OpenCV uses floor(x+0.5)-like rounding)
+            // and ignores border mode (and loses 1px size border)
+            return false;
+        }
+
+        Image srcImg = Image::createFromHandle(context, Image::matTypeToFormat(srcMat.type()),
+                                               Image::createAddressing(srcMat), (void*)srcMat.data);
+        Image dstImg = Image::createFromHandle(context, Image::matTypeToFormat(dstMat.type()),
+                                               Image::createAddressing(dstMat), (void*)dstMat.data);
+
+        ivx::Scalar kernelSize = ivx::Scalar::create<VX_TYPE_INT32>(context, 5);
+        Graph graph = Graph::create(context);
+        ivx::Node halfNode = ivx::Node::create(graph, VX_KERNEL_HALFSCALE_GAUSSIAN, srcImg, dstImg, kernelSize);
+        halfNode.setBorder(borderMode);
+        graph.verify();
+        graph.process();
+
+#ifdef VX_VERSION_1_1
+        //we should take user memory back before release
+        //(it's not done automatically according to standard)
+        srcImg.swapHandle(); dstImg.swapHandle();
+#endif
+    }
+    catch (RuntimeError & e)
+    {
+        VX_DbgThrow(e.what());
+    }
+    catch (WrapperError & e)
+    {
+        VX_DbgThrow(e.what());
+    }
+
+    return true;
+}
+
+}
+#endif
+
 void cv::pyrDown( InputArray _src, OutputArray _dst, const Size& _dsz, int borderType )
 {
+    CV_INSTRUMENT_REGION()
+
     CV_Assert(borderType != BORDER_CONSTANT);
 
     CV_OCL_RUN(_src.dims() <= 2 && _dst.isUMat(),
                ocl_pyrDown(_src, _dst, _dsz, borderType))
 
+    CV_OVX_RUN(_src.dims() <= 2,
+               openvx_pyrDown(_src, _dst, _dsz, borderType))
+
     Mat src = _src.getMat();
     Size dsz = _dsz.area() == 0 ? Size((src.cols + 1)/2, (src.rows + 1)/2) : _dsz;
     _dst.create( dsz, src.type() );
@@ -1276,6 +1386,8 @@ namespace cv
 {
 static bool ipp_pyrup( InputArray _src, OutputArray _dst, const Size& _dsz, int borderType )
 {
+    CV_INSTRUMENT_REGION_IPP()
+
 #if IPP_VERSION_X100 >= 810 && IPP_DISABLE_BLOCK
     Size sz = _src.dims() <= 2 ? _src.size() : Size();
     Size dsz = _dsz.area() == 0 ? Size(_src.cols()*2, _src.rows()*2) : _dsz;
@@ -1332,6 +1444,8 @@ static bool ipp_pyrup( InputArray _src, OutputArray _dst, const Size& _dsz, int
 
 void cv::pyrUp( InputArray _src, OutputArray _dst, const Size& _dsz, int borderType )
 {
+    CV_INSTRUMENT_REGION()
+
     CV_Assert(borderType == BORDER_DEFAULT);
 
     CV_OCL_RUN(_src.dims() <= 2 && _dst.isUMat(),
@@ -1380,6 +1494,8 @@ namespace cv
 {
 static bool ipp_buildpyramid( InputArray _src, OutputArrayOfArrays _dst, int maxlevel, int borderType )
 {
+    CV_INSTRUMENT_REGION_IPP()
+
 #if IPP_VERSION_X100 >= 810 && IPP_DISABLE_BLOCK
     Mat src = _src.getMat();
     _dst.create( maxlevel + 1, 1, 0 );
@@ -1490,6 +1606,8 @@ static bool ipp_buildpyramid( InputArray _src, OutputArrayOfArrays _dst, int max
 
 void cv::buildPyramid( InputArray _src, OutputArrayOfArrays _dst, int maxlevel, int borderType )
 {
+    CV_INSTRUMENT_REGION()
+
     CV_Assert(borderType != BORDER_CONSTANT);
 
     if (_src.dims() <= 2 && _dst.isUMatVector())
diff --git a/modules/imgproc/src/rotcalipers.cpp b/modules/imgproc/src/rotcalipers.cpp
index c80636b..d19addd 100644
--- a/modules/imgproc/src/rotcalipers.cpp
+++ b/modules/imgproc/src/rotcalipers.cpp
@@ -346,6 +346,8 @@ static void rotatingCalipers( const Point2f* points, int n, int mode, float* out
 
 cv::RotatedRect cv::minAreaRect( InputArray _points )
 {
+    CV_INSTRUMENT_REGION()
+
     Mat hull;
     Point2f out[3];
     RotatedRect box;
@@ -404,6 +406,8 @@ cvMinAreaRect2( const CvArr* array, CvMemStorage* /*storage*/ )
 
 void cv::boxPoints(cv::RotatedRect box, OutputArray _pts)
 {
+    CV_INSTRUMENT_REGION()
+
     _pts.create(4, 2, CV_32F);
     Mat pts = _pts.getMat();
     box.points(pts.ptr<Point2f>());
diff --git a/modules/imgproc/src/samplers.cpp b/modules/imgproc/src/samplers.cpp
index c89bd32..df9a2ef 100644
--- a/modules/imgproc/src/samplers.cpp
+++ b/modules/imgproc/src/samplers.cpp
@@ -365,6 +365,8 @@ getQuadrangleSubPix_8u32f_CnR( const uchar* src, size_t src_step, Size src_size,
 void cv::getRectSubPix( InputArray _image, Size patchSize, Point2f center,
                        OutputArray _patch, int patchType )
 {
+    CV_INSTRUMENT_REGION()
+
     Mat image = _image.getMat();
     int depth = image.depth(), cn = image.channels();
     int ddepth = patchType < 0 ? depth : CV_MAT_DEPTH(patchType);
@@ -387,15 +389,15 @@ void cv::getRectSubPix( InputArray _image, Size patchSize, Point2f center,
         IppiPoint_32f icenter = {center.x, center.y};
         IppiSize src_size={image.cols, image.rows}, win_size={patch.cols, patch.rows};
         int srctype = image.type();
-        ippiGetRectSubPixFunc ippfunc =
+        ippiGetRectSubPixFunc ippiCopySubpixIntersect =
             srctype == CV_8UC1 && ddepth == CV_8U ? (ippiGetRectSubPixFunc)ippiCopySubpixIntersect_8u_C1R :
             srctype == CV_8UC1 && ddepth == CV_32F ? (ippiGetRectSubPixFunc)ippiCopySubpixIntersect_8u32f_C1R :
             srctype == CV_32FC1 && ddepth == CV_32F ? (ippiGetRectSubPixFunc)ippiCopySubpixIntersect_32f_C1R : 0;
 
-        if( ippfunc)
+        if( ippiCopySubpixIntersect)
         {
-            if (ippfunc(image.ptr(), (int)image.step, src_size, patch.ptr(),
-                        (int)patch.step, win_size, icenter, &minpt, &maxpt) >= 0 )
+            if (CV_INSTRUMENT_FUN_IPP(ippiCopySubpixIntersect, image.ptr(), (int)image.step, src_size, patch.ptr(),
+                        (int)patch.step, win_size, icenter, &minpt, &maxpt) >= 0)
             {
                 CV_IMPL_ADD(CV_IMPL_IPP);
                 return;
diff --git a/modules/imgproc/src/segmentation.cpp b/modules/imgproc/src/segmentation.cpp
index 124aecd..b803770 100644
--- a/modules/imgproc/src/segmentation.cpp
+++ b/modules/imgproc/src/segmentation.cpp
@@ -87,6 +87,8 @@ allocWSNodes( std::vector<WSNode>& storage )
 
 void cv::watershed( InputArray _src, InputOutputArray _markers )
 {
+    CV_INSTRUMENT_REGION()
+
     // Labels for pixels
     const int IN_QUEUE = -2; // Pixel visited
     const int WSHED = -1; // Pixel belongs to watershed
@@ -332,6 +334,8 @@ void cv::pyrMeanShiftFiltering( InputArray _src, OutputArray _dst,
                                 double sp0, double sr, int max_level,
                                 TermCriteria termcrit )
 {
+    CV_INSTRUMENT_REGION()
+
     Mat src0 = _src.getMat();
 
     if( src0.empty() )
diff --git a/modules/imgproc/src/shapedescr.cpp b/modules/imgproc/src/shapedescr.cpp
index 294f4fa..56186bb 100644
--- a/modules/imgproc/src/shapedescr.cpp
+++ b/modules/imgproc/src/shapedescr.cpp
@@ -206,6 +206,8 @@ static void findMinEnclosingCircle(const PT *pts, int count, Point2f &center, fl
 // see Welzl, Emo. Smallest enclosing disks (balls and ellipsoids). Springer Berlin Heidelberg, 1991.
 void cv::minEnclosingCircle( InputArray _points, Point2f& _center, float& _radius )
 {
+    CV_INSTRUMENT_REGION()
+
     Mat points = _points.getMat();
     int count = points.checkVector(2);
     int depth = points.depth();
@@ -275,6 +277,8 @@ void cv::minEnclosingCircle( InputArray _points, Point2f& _center, float& _radiu
 // calculates length of a curve (e.g. contour perimeter)
 double cv::arcLength( InputArray _curve, bool is_closed )
 {
+    CV_INSTRUMENT_REGION()
+
     Mat curve = _curve.getMat();
     int count = curve.checkVector(2);
     int depth = curve.depth();
@@ -308,6 +312,8 @@ double cv::arcLength( InputArray _curve, bool is_closed )
 // area of a whole sequence
 double cv::contourArea( InputArray _contour, bool oriented )
 {
+    CV_INSTRUMENT_REGION()
+
     Mat contour = _contour.getMat();
     int npoints = contour.checkVector(2);
     int depth = contour.depth();
@@ -339,6 +345,8 @@ double cv::contourArea( InputArray _contour, bool oriented )
 
 cv::RotatedRect cv::fitEllipse( InputArray _points )
 {
+    CV_INSTRUMENT_REGION()
+
     Mat points = _points.getMat();
     int i, n = points.checkVector(2);
     int depth = points.depth();
@@ -668,6 +676,8 @@ static Rect maskBoundingRect( const Mat& img )
 
 cv::Rect cv::boundingRect(InputArray array)
 {
+    CV_INSTRUMENT_REGION()
+
     Mat m = array.getMat();
     return m.depth() <= CV_8U ? maskBoundingRect(m) : pointSetBoundingRect(m);
 }
diff --git a/modules/imgproc/src/smooth.cpp b/modules/imgproc/src/smooth.cpp
index df744ef..d8514da 100644
--- a/modules/imgproc/src/smooth.cpp
+++ b/modules/imgproc/src/smooth.cpp
@@ -44,6 +44,8 @@
 #include "precomp.hpp"
 #include "opencl_kernels_imgproc.hpp"
 
+#include "opencv2/core/openvx/ovx_defs.hpp"
+
 /*
  * This file includes the code, contributed by Simon Perreault
  * (the function icvMedianBlur_8u_O1)
@@ -86,18 +88,93 @@ struct RowSum :
         int i = 0, k, ksz_cn = ksize*cn;
 
         width = (width - 1)*cn;
-        for( k = 0; k < cn; k++, S++, D++ )
+        if( ksize == 3 )
+        {
+            for( i = 0; i < width + cn; i++ )
+            {
+                D[i] = (ST)S[i] + (ST)S[i+cn] + (ST)S[i+cn*2];
+            }
+        }
+        else if( ksize == 5 )
+        {
+            for( i = 0; i < width + cn; i++ )
+            {
+                D[i] = (ST)S[i] + (ST)S[i+cn] + (ST)S[i+cn*2] + (ST)S[i + cn*3] + (ST)S[i + cn*4];
+            }
+        }
+        else if( cn == 1 )
         {
             ST s = 0;
-            for( i = 0; i < ksz_cn; i += cn )
-                s += S[i];
+            for( i = 0; i < ksz_cn; i++ )
+                s += (ST)S[i];
             D[0] = s;
-            for( i = 0; i < width; i += cn )
+            for( i = 0; i < width; i++ )
             {
-                s += S[i + ksz_cn] - S[i];
-                D[i+cn] = s;
+                s += (ST)S[i + ksz_cn] - (ST)S[i];
+                D[i+1] = s;
+            }
+        }
+        else if( cn == 3 )
+        {
+            ST s0 = 0, s1 = 0, s2 = 0;
+            for( i = 0; i < ksz_cn; i += 3 )
+            {
+                s0 += (ST)S[i];
+                s1 += (ST)S[i+1];
+                s2 += (ST)S[i+2];
+            }
+            D[0] = s0;
+            D[1] = s1;
+            D[2] = s2;
+            for( i = 0; i < width; i += 3 )
+            {
+                s0 += (ST)S[i + ksz_cn] - (ST)S[i];
+                s1 += (ST)S[i + ksz_cn + 1] - (ST)S[i + 1];
+                s2 += (ST)S[i + ksz_cn + 2] - (ST)S[i + 2];
+                D[i+3] = s0;
+                D[i+4] = s1;
+                D[i+5] = s2;
+            }
+        }
+        else if( cn == 4 )
+        {
+            ST s0 = 0, s1 = 0, s2 = 0, s3 = 0;
+            for( i = 0; i < ksz_cn; i += 4 )
+            {
+                s0 += (ST)S[i];
+                s1 += (ST)S[i+1];
+                s2 += (ST)S[i+2];
+                s3 += (ST)S[i+3];
+            }
+            D[0] = s0;
+            D[1] = s1;
+            D[2] = s2;
+            D[3] = s3;
+            for( i = 0; i < width; i += 4 )
+            {
+                s0 += (ST)S[i + ksz_cn] - (ST)S[i];
+                s1 += (ST)S[i + ksz_cn + 1] - (ST)S[i + 1];
+                s2 += (ST)S[i + ksz_cn + 2] - (ST)S[i + 2];
+                s3 += (ST)S[i + ksz_cn + 3] - (ST)S[i + 3];
+                D[i+4] = s0;
+                D[i+5] = s1;
+                D[i+6] = s2;
+                D[i+7] = s3;
             }
         }
+        else
+            for( k = 0; k < cn; k++, S++, D++ )
+            {
+                ST s = 0;
+                for( i = 0; i < ksz_cn; i += cn )
+                    s += (ST)S[i];
+                D[0] = s;
+                for( i = 0; i < width; i += cn )
+                {
+                    s += (ST)S[i + ksz_cn] - (ST)S[i];
+                    D[i+cn] = s;
+                }
+            }
     }
 };
 
@@ -138,13 +215,8 @@ struct ColumnSum :
             for( ; sumCount < ksize - 1; sumCount++, src++ )
             {
                 const ST* Sp = (const ST*)src[0];
-                for( i = 0; i <= width - 2; i += 2 )
-                {
-                    ST s0 = SUM[i] + Sp[i], s1 = SUM[i+1] + Sp[i+1];
-                    SUM[i] = s0; SUM[i+1] = s1;
-                }
 
-                for( ; i < width; i++ )
+                for( i = 0; i < width; i++ )
                     SUM[i] += Sp[i];
             }
         }
@@ -222,13 +294,14 @@ struct ColumnSum<int, uchar> :
 
     virtual void operator()(const uchar** src, uchar* dst, int dststep, int count, int width)
     {
-        int i;
         int* SUM;
         bool haveScale = scale != 1;
         double _scale = scale;
 
         #if CV_SSE2
             bool haveSSE2 = checkHardwareSupport(CV_CPU_SSE2);
+        #elif CV_NEON
+            bool haveNEON = checkHardwareSupport(CV_CPU_NEON);
         #endif
 
         if( width != (int)sum.size() )
@@ -244,7 +317,7 @@ struct ColumnSum<int, uchar> :
             for( ; sumCount < ksize - 1; sumCount++, src++ )
             {
                 const int* Sp = (const int*)src[0];
-                i = 0;
+                int i = 0;
                 #if CV_SSE2
                 if(haveSSE2)
                 {
@@ -256,8 +329,11 @@ struct ColumnSum<int, uchar> :
                     }
                 }
                 #elif CV_NEON
-                for( ; i <= width - 4; i+=4 )
-                    vst1q_s32(SUM + i, vaddq_s32(vld1q_s32(SUM + i), vld1q_s32(Sp + i)));
+                if(haveNEON)
+                {
+                    for( ; i <= width - 4; i+=4 )
+                        vst1q_s32(SUM + i, vaddq_s32(vld1q_s32(SUM + i), vld1q_s32(Sp + i)));
+                }
                 #endif
                 for( ; i < width; i++ )
                     SUM[i] += Sp[i];
@@ -276,7 +352,7 @@ struct ColumnSum<int, uchar> :
             uchar* D = (uchar*)dst;
             if( haveScale )
             {
-                i = 0;
+                int i = 0;
                 #if CV_SSE2
                 if(haveSSE2)
                 {
@@ -303,20 +379,23 @@ struct ColumnSum<int, uchar> :
                     }
                 }
                 #elif CV_NEON
-                float32x4_t v_scale = vdupq_n_f32((float)_scale);
-                for( ; i <= width-8; i+=8 )
+                if(haveNEON)
                 {
-                    int32x4_t v_s0 = vaddq_s32(vld1q_s32(SUM + i), vld1q_s32(Sp + i));
-                    int32x4_t v_s01 = vaddq_s32(vld1q_s32(SUM + i + 4), vld1q_s32(Sp + i + 4));
+                    float32x4_t v_scale = vdupq_n_f32((float)_scale);
+                    for( ; i <= width-8; i+=8 )
+                    {
+                        int32x4_t v_s0 = vaddq_s32(vld1q_s32(SUM + i), vld1q_s32(Sp + i));
+                        int32x4_t v_s01 = vaddq_s32(vld1q_s32(SUM + i + 4), vld1q_s32(Sp + i + 4));
 
-                    uint32x4_t v_s0d = cv_vrndq_u32_f32(vmulq_f32(vcvtq_f32_s32(v_s0), v_scale));
-                    uint32x4_t v_s01d = cv_vrndq_u32_f32(vmulq_f32(vcvtq_f32_s32(v_s01), v_scale));
+                        uint32x4_t v_s0d = cv_vrndq_u32_f32(vmulq_f32(vcvtq_f32_s32(v_s0), v_scale));
+                        uint32x4_t v_s01d = cv_vrndq_u32_f32(vmulq_f32(vcvtq_f32_s32(v_s01), v_scale));
 
-                    uint16x8_t v_dst = vcombine_u16(vqmovn_u32(v_s0d), vqmovn_u32(v_s01d));
-                    vst1_u8(D + i, vqmovn_u16(v_dst));
+                        uint16x8_t v_dst = vcombine_u16(vqmovn_u32(v_s0d), vqmovn_u32(v_s01d));
+                        vst1_u8(D + i, vqmovn_u16(v_dst));
 
-                    vst1q_s32(SUM + i, vsubq_s32(v_s0, vld1q_s32(Sm + i)));
-                    vst1q_s32(SUM + i + 4, vsubq_s32(v_s01, vld1q_s32(Sm + i + 4)));
+                        vst1q_s32(SUM + i, vsubq_s32(v_s0, vld1q_s32(Sm + i)));
+                        vst1q_s32(SUM + i + 4, vsubq_s32(v_s01, vld1q_s32(Sm + i + 4)));
+                    }
                 }
                 #endif
                 for( ; i < width; i++ )
@@ -328,7 +407,7 @@ struct ColumnSum<int, uchar> :
             }
             else
             {
-                i = 0;
+                int i = 0;
                 #if CV_SSE2
                 if(haveSSE2)
                 {
@@ -351,16 +430,19 @@ struct ColumnSum<int, uchar> :
                     }
                 }
                 #elif CV_NEON
-                for( ; i <= width-8; i+=8 )
+                if(haveNEON)
                 {
-                    int32x4_t v_s0 = vaddq_s32(vld1q_s32(SUM + i), vld1q_s32(Sp + i));
-                    int32x4_t v_s01 = vaddq_s32(vld1q_s32(SUM + i + 4), vld1q_s32(Sp + i + 4));
+                    for( ; i <= width-8; i+=8 )
+                    {
+                        int32x4_t v_s0 = vaddq_s32(vld1q_s32(SUM + i), vld1q_s32(Sp + i));
+                        int32x4_t v_s01 = vaddq_s32(vld1q_s32(SUM + i + 4), vld1q_s32(Sp + i + 4));
 
-                    uint16x8_t v_dst = vcombine_u16(vqmovun_s32(v_s0), vqmovun_s32(v_s01));
-                    vst1_u8(D + i, vqmovn_u16(v_dst));
+                        uint16x8_t v_dst = vcombine_u16(vqmovun_s32(v_s0), vqmovun_s32(v_s01));
+                        vst1_u8(D + i, vqmovn_u16(v_dst));
 
-                    vst1q_s32(SUM + i, vsubq_s32(v_s0, vld1q_s32(Sm + i)));
-                    vst1q_s32(SUM + i + 4, vsubq_s32(v_s01, vld1q_s32(Sm + i + 4)));
+                        vst1q_s32(SUM + i, vsubq_s32(v_s0, vld1q_s32(Sm + i)));
+                        vst1q_s32(SUM + i + 4, vsubq_s32(v_s01, vld1q_s32(Sm + i + 4)));
+                    }
                 }
                 #endif
 
@@ -380,6 +462,152 @@ struct ColumnSum<int, uchar> :
     std::vector<int> sum;
 };
 
+
+template<>
+struct ColumnSum<ushort, uchar> :
+public BaseColumnFilter
+{
+    ColumnSum( int _ksize, int _anchor, double _scale ) :
+    BaseColumnFilter()
+    {
+        ksize = _ksize;
+        anchor = _anchor;
+        scale = _scale;
+        sumCount = 0;
+        divDelta = 0;
+        divScale = 1;
+        if( scale != 1 )
+        {
+            int d = cvRound(1./scale);
+            double scalef = ((double)(1 << 16))/d;
+            divScale = cvFloor(scalef);
+            scalef -= divScale;
+            divDelta = d/2;
+            if( scalef < 0.5 )
+                divDelta++;
+            else
+                divScale++;
+        }
+    }
+
+    virtual void reset() { sumCount = 0; }
+
+    virtual void operator()(const uchar** src, uchar* dst, int dststep, int count, int width)
+    {
+        const int ds = divScale;
+        const int dd = divDelta;
+        ushort* SUM;
+        const bool haveScale = scale != 1;
+
+#if CV_SSE2
+        bool haveSSE2 = checkHardwareSupport(CV_CPU_SSE2);
+#elif CV_NEON
+        bool haveNEON = checkHardwareSupport(CV_CPU_NEON);
+#endif
+
+        if( width != (int)sum.size() )
+        {
+            sum.resize(width);
+            sumCount = 0;
+        }
+
+        SUM = &sum[0];
+        if( sumCount == 0 )
+        {
+            memset((void*)SUM, 0, width*sizeof(SUM[0]));
+            for( ; sumCount < ksize - 1; sumCount++, src++ )
+            {
+                const ushort* Sp = (const ushort*)src[0];
+                int i = 0;
+#if CV_SSE2
+                if(haveSSE2)
+                {
+                    for( ; i <= width-8; i+=8 )
+                    {
+                        __m128i _sum = _mm_loadu_si128((const __m128i*)(SUM+i));
+                        __m128i _sp = _mm_loadu_si128((const __m128i*)(Sp+i));
+                        _mm_storeu_si128((__m128i*)(SUM+i),_mm_add_epi16(_sum, _sp));
+                    }
+                }
+#elif CV_NEON
+                if(haveNEON)
+                {
+                    for( ; i <= width - 8; i+=8 )
+                        vst1q_u16(SUM + i, vaddq_u16(vld1q_u16(SUM + i), vld1q_u16(Sp + i)));
+                }
+#endif
+                for( ; i < width; i++ )
+                    SUM[i] += Sp[i];
+            }
+        }
+        else
+        {
+            CV_Assert( sumCount == ksize-1 );
+            src += ksize-1;
+        }
+
+        for( ; count--; src++ )
+        {
+            const ushort* Sp = (const ushort*)src[0];
+            const ushort* Sm = (const ushort*)src[1-ksize];
+            uchar* D = (uchar*)dst;
+            if( haveScale )
+            {
+                int i = 0;
+    #if CV_SSE2
+                if(haveSSE2)
+                {
+                    __m128i ds8 = _mm_set1_epi16((short)ds);
+                    __m128i dd8 = _mm_set1_epi16((short)dd);
+
+                    for( ; i <= width-16; i+=16 )
+                    {
+                        __m128i _sm0  = _mm_loadu_si128((const __m128i*)(Sm+i));
+                        __m128i _sm1  = _mm_loadu_si128((const __m128i*)(Sm+i+8));
+
+                        __m128i _s0  = _mm_add_epi16(_mm_loadu_si128((const __m128i*)(SUM+i)),
+                                                     _mm_loadu_si128((const __m128i*)(Sp+i)));
+                        __m128i _s1  = _mm_add_epi16(_mm_loadu_si128((const __m128i*)(SUM+i+8)),
+                                                     _mm_loadu_si128((const __m128i*)(Sp+i+8)));
+                        __m128i _s2 = _mm_mulhi_epu16(_mm_adds_epu16(_s0, dd8), ds8);
+                        __m128i _s3 = _mm_mulhi_epu16(_mm_adds_epu16(_s1, dd8), ds8);
+                        _s0 = _mm_sub_epi16(_s0, _sm0);
+                        _s1 = _mm_sub_epi16(_s1, _sm1);
+                        _mm_storeu_si128((__m128i*)(D+i), _mm_packus_epi16(_s2, _s3));
+                        _mm_storeu_si128((__m128i*)(SUM+i), _s0);
+                        _mm_storeu_si128((__m128i*)(SUM+i+8), _s1);
+                    }
+                }
+    #endif
+                for( ; i < width; i++ )
+                {
+                    int s0 = SUM[i] + Sp[i];
+                    D[i] = (uchar)((s0 + dd)*ds >> 16);
+                    SUM[i] = (ushort)(s0 - Sm[i]);
+                }
+            }
+            else
+            {
+                int i = 0;
+                for( ; i < width; i++ )
+                {
+                    int s0 = SUM[i] + Sp[i];
+                    D[i] = saturate_cast<uchar>(s0);
+                    SUM[i] = (ushort)(s0 - Sm[i]);
+                }
+            }
+            dst += dststep;
+        }
+    }
+
+    double scale;
+    int sumCount;
+    int divDelta;
+    int divScale;
+    std::vector<ushort> sum;
+};
+
+
 template<>
 struct ColumnSum<int, short> :
         public BaseColumnFilter
@@ -404,6 +632,8 @@ struct ColumnSum<int, short> :
 
         #if CV_SSE2
             bool haveSSE2 = checkHardwareSupport(CV_CPU_SSE2);
+        #elif CV_NEON
+            bool haveNEON = checkHardwareSupport(CV_CPU_NEON);
         #endif
 
         if( width != (int)sum.size() )
@@ -411,6 +641,7 @@ struct ColumnSum<int, short> :
             sum.resize(width);
             sumCount = 0;
         }
+
         SUM = &sum[0];
         if( sumCount == 0 )
         {
@@ -430,8 +661,11 @@ struct ColumnSum<int, short> :
                     }
                 }
                 #elif CV_NEON
-                for( ; i <= width - 4; i+=4 )
-                    vst1q_s32(SUM + i, vaddq_s32(vld1q_s32(SUM + i), vld1q_s32(Sp + i)));
+                if(haveNEON)
+                {
+                    for( ; i <= width - 4; i+=4 )
+                        vst1q_s32(SUM + i, vaddq_s32(vld1q_s32(SUM + i), vld1q_s32(Sp + i)));
+                }
                 #endif
                 for( ; i < width; i++ )
                     SUM[i] += Sp[i];
@@ -475,18 +709,21 @@ struct ColumnSum<int, short> :
                     }
                 }
                 #elif CV_NEON
-                float32x4_t v_scale = vdupq_n_f32((float)_scale);
-                for( ; i <= width-8; i+=8 )
+                if(haveNEON)
                 {
-                    int32x4_t v_s0 = vaddq_s32(vld1q_s32(SUM + i), vld1q_s32(Sp + i));
-                    int32x4_t v_s01 = vaddq_s32(vld1q_s32(SUM + i + 4), vld1q_s32(Sp + i + 4));
+                    float32x4_t v_scale = vdupq_n_f32((float)_scale);
+                    for( ; i <= width-8; i+=8 )
+                    {
+                        int32x4_t v_s0 = vaddq_s32(vld1q_s32(SUM + i), vld1q_s32(Sp + i));
+                        int32x4_t v_s01 = vaddq_s32(vld1q_s32(SUM + i + 4), vld1q_s32(Sp + i + 4));
 
-                    int32x4_t v_s0d = cv_vrndq_s32_f32(vmulq_f32(vcvtq_f32_s32(v_s0), v_scale));
-                    int32x4_t v_s01d = cv_vrndq_s32_f32(vmulq_f32(vcvtq_f32_s32(v_s01), v_scale));
-                    vst1q_s16(D + i, vcombine_s16(vqmovn_s32(v_s0d), vqmovn_s32(v_s01d)));
+                        int32x4_t v_s0d = cv_vrndq_s32_f32(vmulq_f32(vcvtq_f32_s32(v_s0), v_scale));
+                        int32x4_t v_s01d = cv_vrndq_s32_f32(vmulq_f32(vcvtq_f32_s32(v_s01), v_scale));
+                        vst1q_s16(D + i, vcombine_s16(vqmovn_s32(v_s0d), vqmovn_s32(v_s01d)));
 
-                    vst1q_s32(SUM + i, vsubq_s32(v_s0, vld1q_s32(Sm + i)));
-                    vst1q_s32(SUM + i + 4, vsubq_s32(v_s01, vld1q_s32(Sm + i + 4)));
+                        vst1q_s32(SUM + i, vsubq_s32(v_s0, vld1q_s32(Sm + i)));
+                        vst1q_s32(SUM + i + 4, vsubq_s32(v_s01, vld1q_s32(Sm + i + 4)));
+                    }
                 }
                 #endif
                 for( ; i < width; i++ )
@@ -520,15 +757,18 @@ struct ColumnSum<int, short> :
                     }
                 }
                 #elif CV_NEON
-                for( ; i <= width-8; i+=8 )
+                if(haveNEON)
                 {
-                    int32x4_t v_s0 = vaddq_s32(vld1q_s32(SUM + i), vld1q_s32(Sp + i));
-                    int32x4_t v_s01 = vaddq_s32(vld1q_s32(SUM + i + 4), vld1q_s32(Sp + i + 4));
+                    for( ; i <= width-8; i+=8 )
+                    {
+                        int32x4_t v_s0 = vaddq_s32(vld1q_s32(SUM + i), vld1q_s32(Sp + i));
+                        int32x4_t v_s01 = vaddq_s32(vld1q_s32(SUM + i + 4), vld1q_s32(Sp + i + 4));
 
-                    vst1q_s16(D + i, vcombine_s16(vqmovn_s32(v_s0), vqmovn_s32(v_s01)));
+                        vst1q_s16(D + i, vcombine_s16(vqmovn_s32(v_s0), vqmovn_s32(v_s01)));
 
-                    vst1q_s32(SUM + i, vsubq_s32(v_s0, vld1q_s32(Sm + i)));
-                    vst1q_s32(SUM + i + 4, vsubq_s32(v_s01, vld1q_s32(Sm + i + 4)));
+                        vst1q_s32(SUM + i, vsubq_s32(v_s0, vld1q_s32(Sm + i)));
+                        vst1q_s32(SUM + i + 4, vsubq_s32(v_s01, vld1q_s32(Sm + i + 4)));
+                    }
                 }
                 #endif
 
@@ -566,12 +806,14 @@ struct ColumnSum<int, ushort> :
 
     virtual void operator()(const uchar** src, uchar* dst, int dststep, int count, int width)
     {
-        int i;
         int* SUM;
         bool haveScale = scale != 1;
         double _scale = scale;
+
         #if CV_SSE2
-                bool haveSSE2 =  checkHardwareSupport(CV_CPU_SSE2);
+            bool haveSSE2 = checkHardwareSupport(CV_CPU_SSE2);
+        #elif CV_NEON
+            bool haveNEON = checkHardwareSupport(CV_CPU_NEON);
         #endif
 
         if( width != (int)sum.size() )
@@ -579,6 +821,7 @@ struct ColumnSum<int, ushort> :
             sum.resize(width);
             sumCount = 0;
         }
+
         SUM = &sum[0];
         if( sumCount == 0 )
         {
@@ -586,20 +829,23 @@ struct ColumnSum<int, ushort> :
             for( ; sumCount < ksize - 1; sumCount++, src++ )
             {
                 const int* Sp = (const int*)src[0];
-                i = 0;
+                int i = 0;
                 #if CV_SSE2
                 if(haveSSE2)
                 {
-                    for( ; i < width-4; i+=4 )
+                    for( ; i <= width-4; i+=4 )
                     {
                         __m128i _sum = _mm_loadu_si128((const __m128i*)(SUM+i));
                         __m128i _sp = _mm_loadu_si128((const __m128i*)(Sp+i));
-                        _mm_storeu_si128((__m128i*)(SUM+i), _mm_add_epi32(_sum, _sp));
+                        _mm_storeu_si128((__m128i*)(SUM+i),_mm_add_epi32(_sum, _sp));
                     }
                 }
                 #elif CV_NEON
-                for( ; i <= width - 4; i+=4 )
-                    vst1q_s32(SUM + i, vaddq_s32(vld1q_s32(SUM + i), vld1q_s32(Sp + i)));
+                if(haveNEON)
+                {
+                    for( ; i <= width - 4; i+=4 )
+                        vst1q_s32(SUM + i, vaddq_s32(vld1q_s32(SUM + i), vld1q_s32(Sp + i)));
+                }
                 #endif
                 for( ; i < width; i++ )
                     SUM[i] += Sp[i];
@@ -618,7 +864,7 @@ struct ColumnSum<int, ushort> :
             ushort* D = (ushort*)dst;
             if( haveScale )
             {
-                i = 0;
+                int i = 0;
                 #if CV_SSE2
                 if(haveSSE2)
                 {
@@ -642,18 +888,21 @@ struct ColumnSum<int, ushort> :
                     }
                 }
                 #elif CV_NEON
-                float32x4_t v_scale = vdupq_n_f32((float)_scale);
-                for( ; i <= width-8; i+=8 )
+                if(haveNEON)
                 {
-                    int32x4_t v_s0 = vaddq_s32(vld1q_s32(SUM + i), vld1q_s32(Sp + i));
-                    int32x4_t v_s01 = vaddq_s32(vld1q_s32(SUM + i + 4), vld1q_s32(Sp + i + 4));
+                    float32x4_t v_scale = vdupq_n_f32((float)_scale);
+                    for( ; i <= width-8; i+=8 )
+                    {
+                        int32x4_t v_s0 = vaddq_s32(vld1q_s32(SUM + i), vld1q_s32(Sp + i));
+                        int32x4_t v_s01 = vaddq_s32(vld1q_s32(SUM + i + 4), vld1q_s32(Sp + i + 4));
 
-                    uint32x4_t v_s0d = cv_vrndq_u32_f32(vmulq_f32(vcvtq_f32_s32(v_s0), v_scale));
-                    uint32x4_t v_s01d = cv_vrndq_u32_f32(vmulq_f32(vcvtq_f32_s32(v_s01), v_scale));
-                    vst1q_u16(D + i, vcombine_u16(vqmovn_u32(v_s0d), vqmovn_u32(v_s01d)));
+                        uint32x4_t v_s0d = cv_vrndq_u32_f32(vmulq_f32(vcvtq_f32_s32(v_s0), v_scale));
+                        uint32x4_t v_s01d = cv_vrndq_u32_f32(vmulq_f32(vcvtq_f32_s32(v_s01), v_scale));
+                        vst1q_u16(D + i, vcombine_u16(vqmovn_u32(v_s0d), vqmovn_u32(v_s01d)));
 
-                    vst1q_s32(SUM + i, vsubq_s32(v_s0, vld1q_s32(Sm + i)));
-                    vst1q_s32(SUM + i + 4, vsubq_s32(v_s01, vld1q_s32(Sm + i + 4)));
+                        vst1q_s32(SUM + i, vsubq_s32(v_s0, vld1q_s32(Sm + i)));
+                        vst1q_s32(SUM + i + 4, vsubq_s32(v_s01, vld1q_s32(Sm + i + 4)));
+                    }
                 }
                 #endif
                 for( ; i < width; i++ )
@@ -665,8 +914,8 @@ struct ColumnSum<int, ushort> :
             }
             else
             {
-                i = 0;
-                #if  CV_SSE2
+                int i = 0;
+                #if CV_SSE2
                 if(haveSSE2)
                 {
                     const __m128i delta0 = _mm_set1_epi32(0x8000);
@@ -686,15 +935,18 @@ struct ColumnSum<int, ushort> :
                     }
                 }
                 #elif CV_NEON
-                for( ; i <= width-8; i+=8 )
+                if(haveNEON)
                 {
-                    int32x4_t v_s0 = vaddq_s32(vld1q_s32(SUM + i), vld1q_s32(Sp + i));
-                    int32x4_t v_s01 = vaddq_s32(vld1q_s32(SUM + i + 4), vld1q_s32(Sp + i + 4));
+                    for( ; i <= width-8; i+=8 )
+                    {
+                        int32x4_t v_s0 = vaddq_s32(vld1q_s32(SUM + i), vld1q_s32(Sp + i));
+                        int32x4_t v_s01 = vaddq_s32(vld1q_s32(SUM + i + 4), vld1q_s32(Sp + i + 4));
 
-                    vst1q_u16(D + i, vcombine_u16(vqmovun_s32(v_s0), vqmovun_s32(v_s01)));
+                        vst1q_u16(D + i, vcombine_u16(vqmovun_s32(v_s0), vqmovun_s32(v_s01)));
 
-                    vst1q_s32(SUM + i, vsubq_s32(v_s0, vld1q_s32(Sm + i)));
-                    vst1q_s32(SUM + i + 4, vsubq_s32(v_s01, vld1q_s32(Sm + i + 4)));
+                        vst1q_s32(SUM + i, vsubq_s32(v_s0, vld1q_s32(Sm + i)));
+                        vst1q_s32(SUM + i + 4, vsubq_s32(v_s01, vld1q_s32(Sm + i + 4)));
+                    }
                 }
                 #endif
 
@@ -731,13 +983,14 @@ struct ColumnSum<int, int> :
 
     virtual void operator()(const uchar** src, uchar* dst, int dststep, int count, int width)
     {
-        int i;
         int* SUM;
         bool haveScale = scale != 1;
         double _scale = scale;
 
         #if CV_SSE2
             bool haveSSE2 = checkHardwareSupport(CV_CPU_SSE2);
+        #elif CV_NEON
+            bool haveNEON = checkHardwareSupport(CV_CPU_NEON);
         #endif
 
         if( width != (int)sum.size() )
@@ -745,6 +998,7 @@ struct ColumnSum<int, int> :
             sum.resize(width);
             sumCount = 0;
         }
+
         SUM = &sum[0];
         if( sumCount == 0 )
         {
@@ -752,7 +1006,7 @@ struct ColumnSum<int, int> :
             for( ; sumCount < ksize - 1; sumCount++, src++ )
             {
                 const int* Sp = (const int*)src[0];
-                i = 0;
+                int i = 0;
                 #if CV_SSE2
                 if(haveSSE2)
                 {
@@ -764,8 +1018,11 @@ struct ColumnSum<int, int> :
                     }
                 }
                 #elif CV_NEON
-                for( ; i <= width - 4; i+=4 )
-                    vst1q_s32(SUM + i, vaddq_s32(vld1q_s32(SUM + i), vld1q_s32(Sp + i)));
+                if(haveNEON)
+                {
+                    for( ; i <= width - 4; i+=4 )
+                        vst1q_s32(SUM + i, vaddq_s32(vld1q_s32(SUM + i), vld1q_s32(Sp + i)));
+                }
                 #endif
                 for( ; i < width; i++ )
                     SUM[i] += Sp[i];
@@ -784,7 +1041,7 @@ struct ColumnSum<int, int> :
             int* D = (int*)dst;
             if( haveScale )
             {
-                i = 0;
+                int i = 0;
                 #if CV_SSE2
                 if(haveSSE2)
                 {
@@ -803,15 +1060,18 @@ struct ColumnSum<int, int> :
                     }
                 }
                 #elif CV_NEON
-                float32x4_t v_scale = vdupq_n_f32((float)_scale);
-                for( ; i <= width-4; i+=4 )
+                if(haveNEON)
                 {
-                    int32x4_t v_s0 = vaddq_s32(vld1q_s32(SUM + i), vld1q_s32(Sp + i));
+                    float32x4_t v_scale = vdupq_n_f32((float)_scale);
+                    for( ; i <= width-4; i+=4 )
+                    {
+                        int32x4_t v_s0 = vaddq_s32(vld1q_s32(SUM + i), vld1q_s32(Sp + i));
 
-                    int32x4_t v_s0d = cv_vrndq_s32_f32(vmulq_f32(vcvtq_f32_s32(v_s0), v_scale));
-                    vst1q_s32(D + i, v_s0d);
+                        int32x4_t v_s0d = cv_vrndq_s32_f32(vmulq_f32(vcvtq_f32_s32(v_s0), v_scale));
+                        vst1q_s32(D + i, v_s0d);
 
-                    vst1q_s32(SUM + i, vsubq_s32(v_s0, vld1q_s32(Sm + i)));
+                        vst1q_s32(SUM + i, vsubq_s32(v_s0, vld1q_s32(Sm + i)));
+                    }
                 }
                 #endif
                 for( ; i < width; i++ )
@@ -823,7 +1083,7 @@ struct ColumnSum<int, int> :
             }
             else
             {
-                i = 0;
+                int i = 0;
                 #if CV_SSE2
                 if(haveSSE2)
                 {
@@ -838,12 +1098,15 @@ struct ColumnSum<int, int> :
                     }
                 }
                 #elif CV_NEON
-                for( ; i <= width-4; i+=4 )
+                if(haveNEON)
                 {
-                    int32x4_t v_s0 = vaddq_s32(vld1q_s32(SUM + i), vld1q_s32(Sp + i));
+                    for( ; i <= width-4; i+=4 )
+                    {
+                        int32x4_t v_s0 = vaddq_s32(vld1q_s32(SUM + i), vld1q_s32(Sp + i));
 
-                    vst1q_s32(D + i, v_s0);
-                    vst1q_s32(SUM + i, vsubq_s32(v_s0, vld1q_s32(Sm + i)));
+                        vst1q_s32(D + i, v_s0);
+                        vst1q_s32(SUM + i, vsubq_s32(v_s0, vld1q_s32(Sm + i)));
+                    }
                 }
                 #endif
 
@@ -881,13 +1144,14 @@ struct ColumnSum<int, float> :
 
     virtual void operator()(const uchar** src, uchar* dst, int dststep, int count, int width)
     {
-        int i;
         int* SUM;
         bool haveScale = scale != 1;
         double _scale = scale;
 
         #if CV_SSE2
-        bool haveSSE2 =  checkHardwareSupport(CV_CPU_SSE2);
+            bool haveSSE2 = checkHardwareSupport(CV_CPU_SSE2);
+        #elif CV_NEON
+            bool haveNEON = checkHardwareSupport(CV_CPU_NEON);
         #endif
 
         if( width != (int)sum.size() )
@@ -899,26 +1163,27 @@ struct ColumnSum<int, float> :
         SUM = &sum[0];
         if( sumCount == 0 )
         {
-            memset((void *)SUM, 0, sizeof(int) * width);
-
+            memset((void*)SUM, 0, width*sizeof(int));
             for( ; sumCount < ksize - 1; sumCount++, src++ )
             {
                 const int* Sp = (const int*)src[0];
-                i = 0;
-
+                int i = 0;
                 #if CV_SSE2
                 if(haveSSE2)
                 {
-                    for( ; i < width-4; i+=4 )
+                    for( ; i <= width-4; i+=4 )
                     {
                         __m128i _sum = _mm_loadu_si128((const __m128i*)(SUM+i));
                         __m128i _sp = _mm_loadu_si128((const __m128i*)(Sp+i));
-                        _mm_storeu_si128((__m128i*)(SUM+i), _mm_add_epi32(_sum, _sp));
+                        _mm_storeu_si128((__m128i*)(SUM+i),_mm_add_epi32(_sum, _sp));
                     }
                 }
                 #elif CV_NEON
-                for( ; i <= width - 4; i+=4 )
-                    vst1q_s32(SUM + i, vaddq_s32(vld1q_s32(SUM + i), vld1q_s32(Sp + i)));
+                if(haveNEON)
+                {
+                    for( ; i <= width - 4; i+=4 )
+                        vst1q_s32(SUM + i, vaddq_s32(vld1q_s32(SUM + i), vld1q_s32(Sp + i)));
+                }
                 #endif
 
                 for( ; i < width; i++ )
@@ -938,7 +1203,7 @@ struct ColumnSum<int, float> :
             float* D = (float*)dst;
             if( haveScale )
             {
-                i = 0;
+                int i = 0;
 
                 #if CV_SSE2
                 if(haveSSE2)
@@ -956,17 +1221,20 @@ struct ColumnSum<int, float> :
                     }
                 }
                 #elif CV_NEON
-                float32x4_t v_scale = vdupq_n_f32((float)_scale);
-                for( ; i <= width-8; i+=8 )
+                if(haveNEON)
                 {
-                    int32x4_t v_s0 = vaddq_s32(vld1q_s32(SUM + i), vld1q_s32(Sp + i));
-                    int32x4_t v_s01 = vaddq_s32(vld1q_s32(SUM + i + 4), vld1q_s32(Sp + i + 4));
+                    float32x4_t v_scale = vdupq_n_f32((float)_scale);
+                    for( ; i <= width-8; i+=8 )
+                    {
+                        int32x4_t v_s0 = vaddq_s32(vld1q_s32(SUM + i), vld1q_s32(Sp + i));
+                        int32x4_t v_s01 = vaddq_s32(vld1q_s32(SUM + i + 4), vld1q_s32(Sp + i + 4));
 
-                    vst1q_f32(D + i, vmulq_f32(vcvtq_f32_s32(v_s0), v_scale));
-                    vst1q_f32(D + i + 4, vmulq_f32(vcvtq_f32_s32(v_s01), v_scale));
+                        vst1q_f32(D + i, vmulq_f32(vcvtq_f32_s32(v_s0), v_scale));
+                        vst1q_f32(D + i + 4, vmulq_f32(vcvtq_f32_s32(v_s01), v_scale));
 
-                    vst1q_s32(SUM + i, vsubq_s32(v_s0, vld1q_s32(Sm + i)));
-                    vst1q_s32(SUM + i + 4, vsubq_s32(v_s01, vld1q_s32(Sm + i + 4)));
+                        vst1q_s32(SUM + i, vsubq_s32(v_s0, vld1q_s32(Sm + i)));
+                        vst1q_s32(SUM + i + 4, vsubq_s32(v_s01, vld1q_s32(Sm + i + 4)));
+                    }
                 }
                 #endif
 
@@ -979,7 +1247,7 @@ struct ColumnSum<int, float> :
             }
             else
             {
-                i = 0;
+                int i = 0;
 
                 #if CV_SSE2
                 if(haveSSE2)
@@ -995,16 +1263,19 @@ struct ColumnSum<int, float> :
                     }
                 }
                 #elif CV_NEON
-                for( ; i <= width-8; i+=8 )
+                if(haveNEON)
                 {
-                    int32x4_t v_s0 = vaddq_s32(vld1q_s32(SUM + i), vld1q_s32(Sp + i));
-                    int32x4_t v_s01 = vaddq_s32(vld1q_s32(SUM + i + 4), vld1q_s32(Sp + i + 4));
+                    for( ; i <= width-8; i+=8 )
+                    {
+                        int32x4_t v_s0 = vaddq_s32(vld1q_s32(SUM + i), vld1q_s32(Sp + i));
+                        int32x4_t v_s01 = vaddq_s32(vld1q_s32(SUM + i + 4), vld1q_s32(Sp + i + 4));
 
-                    vst1q_f32(D + i, vcvtq_f32_s32(v_s0));
-                    vst1q_f32(D + i + 4, vcvtq_f32_s32(v_s01));
+                        vst1q_f32(D + i, vcvtq_f32_s32(v_s0));
+                        vst1q_f32(D + i + 4, vcvtq_f32_s32(v_s01));
 
-                    vst1q_s32(SUM + i, vsubq_s32(v_s0, vld1q_s32(Sm + i)));
-                    vst1q_s32(SUM + i + 4, vsubq_s32(v_s01, vld1q_s32(Sm + i + 4)));
+                        vst1q_s32(SUM + i, vsubq_s32(v_s0, vld1q_s32(Sm + i)));
+                        vst1q_s32(SUM + i + 4, vsubq_s32(v_s01, vld1q_s32(Sm + i + 4)));
+                    }
                 }
                 #endif
 
@@ -1026,6 +1297,61 @@ struct ColumnSum<int, float> :
 
 #ifdef HAVE_OPENCL
 
+static bool ocl_boxFilter3x3_8UC1( InputArray _src, OutputArray _dst, int ddepth,
+                                   Size ksize, Point anchor, int borderType, bool normalize )
+{
+    const ocl::Device & dev = ocl::Device::getDefault();
+    int type = _src.type(), sdepth = CV_MAT_DEPTH(type), cn = CV_MAT_CN(type);
+
+    if (ddepth < 0)
+        ddepth = sdepth;
+
+    if (anchor.x < 0)
+        anchor.x = ksize.width / 2;
+    if (anchor.y < 0)
+        anchor.y = ksize.height / 2;
+
+    if ( !(dev.isIntel() && (type == CV_8UC1) &&
+         (_src.offset() == 0) && (_src.step() % 4 == 0) &&
+         (_src.cols() % 16 == 0) && (_src.rows() % 2 == 0) &&
+         (anchor.x == 1) && (anchor.y == 1) &&
+         (ksize.width == 3) && (ksize.height == 3)) )
+        return false;
+
+    float alpha = 1.0f / (ksize.height * ksize.width);
+    Size size = _src.size();
+    size_t globalsize[2] = { 0, 0 };
+    size_t localsize[2] = { 0, 0 };
+    const char * const borderMap[] = { "BORDER_CONSTANT", "BORDER_REPLICATE", "BORDER_REFLECT", 0, "BORDER_REFLECT_101" };
+
+    globalsize[0] = size.width / 16;
+    globalsize[1] = size.height / 2;
+
+    char build_opts[1024];
+    sprintf(build_opts, "-D %s %s", borderMap[borderType], normalize ? "-D NORMALIZE" : "");
+
+    ocl::Kernel kernel("boxFilter3x3_8UC1_cols16_rows2", cv::ocl::imgproc::boxFilter3x3_oclsrc, build_opts);
+    if (kernel.empty())
+        return false;
+
+    UMat src = _src.getUMat();
+    _dst.create(size, CV_MAKETYPE(ddepth, cn));
+    if (!(_dst.offset() == 0 && _dst.step() % 4 == 0))
+        return false;
+    UMat dst = _dst.getUMat();
+
+    int idxArg = kernel.set(0, ocl::KernelArg::PtrReadOnly(src));
+    idxArg = kernel.set(idxArg, (int)src.step);
+    idxArg = kernel.set(idxArg, ocl::KernelArg::PtrWriteOnly(dst));
+    idxArg = kernel.set(idxArg, (int)dst.step);
+    idxArg = kernel.set(idxArg, (int)dst.rows);
+    idxArg = kernel.set(idxArg, (int)dst.cols);
+    if (normalize)
+        idxArg = kernel.set(idxArg, (float)alpha);
+
+    return kernel.run(2, globalsize, (localsize[0] == 0) ? NULL : localsize, false);
+}
+
 #define DIVUP(total, grain) ((total + grain - 1) / (grain))
 #define ROUNDUP(sz, n)      ((sz) + (n) - 1 - (((sz) + (n) - 1) % (n)))
 
@@ -1219,6 +1545,8 @@ cv::Ptr<cv::BaseRowFilter> cv::getRowSumFilter(int srcType, int sumType, int ksi
 
     if( sdepth == CV_8U && ddepth == CV_32S )
         return makePtr<RowSum<uchar, int> >(ksize, anchor);
+    if( sdepth == CV_8U && ddepth == CV_16U )
+        return makePtr<RowSum<uchar, ushort> >(ksize, anchor);
     if( sdepth == CV_8U && ddepth == CV_64F )
         return makePtr<RowSum<uchar, double> >(ksize, anchor);
     if( sdepth == CV_16U && ddepth == CV_32S )
@@ -1255,6 +1583,8 @@ cv::Ptr<cv::BaseColumnFilter> cv::getColumnSumFilter(int sumType, int dstType, i
 
     if( ddepth == CV_8U && sdepth == CV_32S )
         return makePtr<ColumnSum<int, uchar> >(ksize, anchor, scale);
+    if( ddepth == CV_8U && sdepth == CV_16U )
+        return makePtr<ColumnSum<ushort, uchar> >(ksize, anchor, scale);
     if( ddepth == CV_8U && sdepth == CV_64F )
         return makePtr<ColumnSum<double, uchar> >(ksize, anchor, scale);
     if( ddepth == CV_16U && sdepth == CV_32S )
@@ -1289,7 +1619,10 @@ cv::Ptr<cv::FilterEngine> cv::createBoxFilter( int srcType, int dstType, Size ks
 {
     int sdepth = CV_MAT_DEPTH(srcType);
     int cn = CV_MAT_CN(srcType), sumType = CV_64F;
-    if( sdepth <= CV_32S && (!normalize ||
+    if( sdepth == CV_8U && CV_MAT_DEPTH(dstType) == CV_8U &&
+        ksize.width*ksize.height <= 256 )
+        sumType = CV_16U;
+    else if( sdepth <= CV_32S && (!normalize ||
         ksize.width*ksize.height <= (sdepth == CV_8U ? (1<<23) :
             sdepth == CV_16U ? (1 << 15) : (1 << 16))) )
         sumType = CV_32S;
@@ -1303,13 +1636,114 @@ cv::Ptr<cv::FilterEngine> cv::createBoxFilter( int srcType, int dstType, Size ks
            srcType, dstType, sumType, borderType );
 }
 
-#if defined(HAVE_IPP)
+#ifdef HAVE_OPENVX
+namespace cv
+{
+    static bool openvx_boxfilter(InputArray _src, OutputArray _dst, int ddepth,
+                                 Size ksize, Point anchor,
+                                 bool normalize, int borderType)
+    {
+        int stype = _src.type();
+        if (ddepth < 0)
+            ddepth = CV_8UC1;
+        if (stype != CV_8UC1 || (ddepth != CV_8U && ddepth != CV_16S) ||
+            (anchor.x >= 0 && anchor.x != ksize.width / 2) ||
+            (anchor.y >= 0 && anchor.y != ksize.height / 2) ||
+            ksize.width % 2 != 1 || ksize.height % 2 != 1 ||
+            ksize.width < 3 || ksize.height < 3)
+            return false;
+
+        Mat src = _src.getMat();
+        _dst.create(src.size(), CV_MAKETYPE(ddepth, 1));
+        Mat dst = _dst.getMat();
+
+        if (src.cols < ksize.width || src.rows < ksize.height)
+            return false;
+
+        if ((borderType & BORDER_ISOLATED) == 0 && src.isSubmatrix())
+            return false; //Process isolated borders only
+        vx_enum border;
+        switch (borderType & ~BORDER_ISOLATED)
+        {
+        case BORDER_CONSTANT:
+            border = VX_BORDER_CONSTANT;
+            break;
+        case BORDER_REPLICATE:
+            border = VX_BORDER_REPLICATE;
+            break;
+        default:
+            return false;
+        }
+
+        try
+        {
+            ivx::Context ctx = ivx::Context::create();
+            if ((vx_size)(ksize.width) > ctx.convolutionMaxDimension() || (vx_size)(ksize.height) > ctx.convolutionMaxDimension())
+                return false;
+
+            Mat a;
+            if (dst.data != src.data)
+                a = src;
+            else
+                src.copyTo(a);
+
+            ivx::Image
+                ia = ivx::Image::createFromHandle(ctx, VX_DF_IMAGE_U8,
+                                                  ivx::Image::createAddressing(a.cols, a.rows, 1, (vx_int32)(a.step)), a.data),
+                ib = ivx::Image::createFromHandle(ctx, ddepth == CV_16S ? VX_DF_IMAGE_S16 : VX_DF_IMAGE_U8,
+                                                  ivx::Image::createAddressing(dst.cols, dst.rows, ddepth == CV_16S ? 2 : 1, (vx_int32)(dst.step)), dst.data);
+
+            //ATTENTION: VX_CONTEXT_IMMEDIATE_BORDER attribute change could lead to strange issues in multi-threaded environments
+            //since OpenVX standart says nothing about thread-safety for now
+            ivx::border_t prevBorder = ctx.immediateBorder();
+            ctx.setImmediateBorder(border, (vx_uint8)(0));
+            if (ddepth == CV_8U && ksize.width == 3 && ksize.height == 3 && normalize)
+            {
+                ivx::IVX_CHECK_STATUS(vxuBox3x3(ctx, ia, ib));
+            }
+            else
+            {
+#if VX_VERSION <= VX_VERSION_1_0
+                if (ctx.vendorID() == VX_ID_KHRONOS && ((vx_size)(src.cols) <= ctx.convolutionMaxDimension() || (vx_size)(src.rows) <= ctx.convolutionMaxDimension()))
+                {
+                    ctx.setImmediateBorder(prevBorder);
+                    return false;
+                }
+#endif
+                Mat convData(ksize, CV_16SC1);
+                convData = normalize ? (1 << 15) / (ksize.width * ksize.height) : 1;
+                ivx::Convolution cnv = ivx::Convolution::create(ctx, convData.cols, convData.rows);
+                cnv.copyFrom(convData);
+                if (normalize)
+                    cnv.setScale(1 << 15);
+                ivx::IVX_CHECK_STATUS(vxuConvolve(ctx, ia, cnv, ib));
+            }
+            ctx.setImmediateBorder(prevBorder);
+        }
+        catch (ivx::RuntimeError & e)
+        {
+            VX_DbgThrow(e.what());
+        }
+        catch (ivx::WrapperError & e)
+        {
+            VX_DbgThrow(e.what());
+        }
+
+        return true;
+    }
+}
+#endif
+
+// TODO: IPP performance regression
+#if defined(HAVE_IPP) && IPP_DISABLE_BLOCK
 namespace cv
 {
 static bool ipp_boxfilter( InputArray _src, OutputArray _dst, int ddepth,
                 Size ksize, Point anchor,
                 bool normalize, int borderType )
 {
+    CV_INSTRUMENT_REGION_IPP()
+
     int stype = _src.type(), sdepth = CV_MAT_DEPTH(stype), cn = CV_MAT_CN(stype);
     if( ddepth < 0 )
         ddepth = sdepth;
@@ -1348,7 +1782,7 @@ static bool ipp_boxfilter( InputArray _src, OutputArray _dst, int ddepth,
                     Ipp8u * buffer = ippsMalloc_8u(bufSize); \
                     ippType borderValue[4] = { 0, 0, 0, 0 }; \
                     ippBorderType = ippBorderType == BORDER_CONSTANT ? ippBorderConst : ippBorderRepl; \
-                    IppStatus status = ippiFilterBoxBorder_##flavor(src.ptr<ippType>(), (int)src.step, dst.ptr<ippType>(), \
+                    IppStatus status = CV_INSTRUMENT_FUN_IPP(ippiFilterBoxBorder_##flavor, src.ptr<ippType>(), (int)src.step, dst.ptr<ippType>(), \
                                                                     (int)dst.step, roiSize, maskSize, \
                                                                     (IppiBorderType)ippBorderType, borderValue, buffer); \
                     ippsFree(buffer); \
@@ -1402,8 +1836,18 @@ void cv::boxFilter( InputArray _src, OutputArray _dst, int ddepth,
                 Size ksize, Point anchor,
                 bool normalize, int borderType )
 {
+    CV_INSTRUMENT_REGION()
+
+    CV_OCL_RUN(_dst.isUMat() &&
+               (borderType == BORDER_REPLICATE || borderType == BORDER_CONSTANT ||
+                borderType == BORDER_REFLECT || borderType == BORDER_REFLECT_101),
+               ocl_boxFilter3x3_8UC1(_src, _dst, ddepth, ksize, anchor, borderType, normalize))
+
     CV_OCL_RUN(_dst.isUMat(), ocl_boxFilter(_src, _dst, ddepth, ksize, anchor, borderType, normalize))
 
+    CV_OVX_RUN(true,
+               openvx_boxfilter(_src, _dst, ddepth, ksize, anchor, normalize, borderType))
+
     Mat src = _src.getMat();
     int stype = src.type(), sdepth = CV_MAT_DEPTH(stype), cn = CV_MAT_CN(stype);
     if( ddepth < 0 )
@@ -1422,9 +1866,8 @@ void cv::boxFilter( InputArray _src, OutputArray _dst, int ddepth,
         return;
 #endif
 
-#ifdef HAVE_IPP
+#if defined HAVE_IPP && IPP_DISABLE_BLOCK
     int ippBorderType = borderType & ~BORDER_ISOLATED;
-#endif
     Point ocvAnchor, ippAnchor;
     ocvAnchor.x = anchor.x < 0 ? ksize.width / 2 : anchor.x;
     ocvAnchor.y = anchor.y < 0 ? ksize.height / 2 : anchor.y;
@@ -1435,17 +1878,26 @@ void cv::boxFilter( InputArray _src, OutputArray _dst, int ddepth,
              ippBorderType == BORDER_CONSTANT) && ocvAnchor == ippAnchor &&
              _dst.cols() != ksize.width && _dst.rows() != ksize.height),
              ipp_boxfilter( _src,  _dst,  ddepth, ksize,  anchor, normalize,  borderType));
+#endif
 
+    Point ofs;
+    Size wsz(src.cols, src.rows);
+    if(!(borderType&BORDER_ISOLATED))
+        src.locateROI( wsz, ofs );
+    borderType = (borderType&~BORDER_ISOLATED);
 
     Ptr<FilterEngine> f = createBoxFilter( src.type(), dst.type(),
                         ksize, anchor, normalize, borderType );
-    f->apply( src, dst );
+
+    f->apply( src, dst, wsz, ofs );
 }
 
 
 void cv::blur( InputArray src, OutputArray dst,
            Size ksize, Point anchor, int borderType )
 {
+    CV_INSTRUMENT_REGION()
+
     boxFilter( src, dst, -1, ksize, anchor, true, borderType );
 }
 
@@ -1528,6 +1980,8 @@ void cv::sqrBoxFilter( InputArray _src, OutputArray _dst, int ddepth,
                        Size ksize, Point anchor,
                        bool normalize, int borderType )
 {
+    CV_INSTRUMENT_REGION()
+
     int srcType = _src.type(), sdepth = CV_MAT_DEPTH(srcType), cn = CV_MAT_CN(srcType);
     Size size = _src.size();
 
@@ -1561,7 +2015,11 @@ void cv::sqrBoxFilter( InputArray _src, OutputArray _dst, int ddepth,
 
     Ptr<FilterEngine> f = makePtr<FilterEngine>(Ptr<BaseFilter>(), rowFilter, columnFilter,
                                                 srcType, dstType, sumType, borderType );
-    f->apply( src, dst );
+    Point ofs;
+    Size wsz(src.cols, src.rows);
+    src.locateROI( wsz, ofs );
+
+    f->apply( src, dst, wsz, ofs );
 }
 
 
@@ -1661,14 +2119,193 @@ cv::Ptr<cv::FilterEngine> cv::createGaussianFilter( int type, Size ksize,
     return createSeparableLinearFilter( type, type, kx, ky, Point(-1,-1), 0, borderType );
 }
 
-#ifdef HAVE_IPP
 namespace cv
 {
+#ifdef HAVE_OPENCL
+
+static bool ocl_GaussianBlur_8UC1(InputArray _src, OutputArray _dst, Size ksize, int ddepth,
+                                  InputArray _kernelX, InputArray _kernelY, int borderType)
+{
+    const ocl::Device & dev = ocl::Device::getDefault();
+    int type = _src.type(), sdepth = CV_MAT_DEPTH(type), cn = CV_MAT_CN(type);
+
+    if ( !(dev.isIntel() && (type == CV_8UC1) &&
+         (_src.offset() == 0) && (_src.step() % 4 == 0) &&
+         ((ksize.width == 5 && (_src.cols() % 4 == 0)) ||
+         (ksize.width == 3 && (_src.cols() % 16 == 0) && (_src.rows() % 2 == 0)))) )
+        return false;
+
+    Mat kernelX = _kernelX.getMat().reshape(1, 1);
+    if (kernelX.cols % 2 != 1)
+        return false;
+    Mat kernelY = _kernelY.getMat().reshape(1, 1);
+    if (kernelY.cols % 2 != 1)
+        return false;
+
+    if (ddepth < 0)
+        ddepth = sdepth;
+
+    Size size = _src.size();
+    size_t globalsize[2] = { 0, 0 };
+    size_t localsize[2] = { 0, 0 };
+
+    if (ksize.width == 3)
+    {
+        globalsize[0] = size.width / 16;
+        globalsize[1] = size.height / 2;
+    }
+    else if (ksize.width == 5)
+    {
+        globalsize[0] = size.width / 4;
+        globalsize[1] = size.height / 1;
+    }
+
+    const char * const borderMap[] = { "BORDER_CONSTANT", "BORDER_REPLICATE", "BORDER_REFLECT", 0, "BORDER_REFLECT_101" };
+    char build_opts[1024];
+    sprintf(build_opts, "-D %s %s%s", borderMap[borderType],
+            ocl::kernelToStr(kernelX, CV_32F, "KERNEL_MATRIX_X").c_str(),
+            ocl::kernelToStr(kernelY, CV_32F, "KERNEL_MATRIX_Y").c_str());
+
+    ocl::Kernel kernel;
+
+    if (ksize.width == 3)
+        kernel.create("gaussianBlur3x3_8UC1_cols16_rows2", cv::ocl::imgproc::gaussianBlur3x3_oclsrc, build_opts);
+    else if (ksize.width == 5)
+        kernel.create("gaussianBlur5x5_8UC1_cols4", cv::ocl::imgproc::gaussianBlur5x5_oclsrc, build_opts);
+
+    if (kernel.empty())
+        return false;
+
+    UMat src = _src.getUMat();
+    _dst.create(size, CV_MAKETYPE(ddepth, cn));
+    if (!(_dst.offset() == 0 && _dst.step() % 4 == 0))
+        return false;
+    UMat dst = _dst.getUMat();
+
+    int idxArg = kernel.set(0, ocl::KernelArg::PtrReadOnly(src));
+    idxArg = kernel.set(idxArg, (int)src.step);
+    idxArg = kernel.set(idxArg, ocl::KernelArg::PtrWriteOnly(dst));
+    idxArg = kernel.set(idxArg, (int)dst.step);
+    idxArg = kernel.set(idxArg, (int)dst.rows);
+    idxArg = kernel.set(idxArg, (int)dst.cols);
+
+    return kernel.run(2, globalsize, (localsize[0] == 0) ? NULL : localsize, false);
+}
+
+#endif
+
+#ifdef HAVE_OPENVX
+
+static bool openvx_gaussianBlur(InputArray _src, OutputArray _dst, Size ksize,
+                                double sigma1, double sigma2, int borderType)
+{
+    int stype = _src.type();
+    if (sigma2 <= 0)
+        sigma2 = sigma1;
+    // automatic detection of kernel size from sigma
+    if (ksize.width <= 0 && sigma1 > 0)
+        ksize.width = cvRound(sigma1*6 + 1) | 1;
+    if (ksize.height <= 0 && sigma2 > 0)
+        ksize.height = cvRound(sigma2*6 + 1) | 1;
+
+    if (stype != CV_8UC1 ||
+        ksize.width < 3 || ksize.height < 3 ||
+        ksize.width % 2 != 1 || ksize.height % 2 != 1)
+        return false;
+
+    sigma1 = std::max(sigma1, 0.);
+    sigma2 = std::max(sigma2, 0.);
+
+    Mat src = _src.getMat();
+    Mat dst = _dst.getMat();
+
+    if (src.cols < ksize.width || src.rows < ksize.height)
+        return false;
+
+    if ((borderType & BORDER_ISOLATED) == 0 && src.isSubmatrix())
+        return false; //Process isolated borders only
+    vx_enum border;
+    switch (borderType & ~BORDER_ISOLATED)
+    {
+    case BORDER_CONSTANT:
+        border = VX_BORDER_CONSTANT;
+        break;
+    case BORDER_REPLICATE:
+        border = VX_BORDER_REPLICATE;
+        break;
+    default:
+        return false;
+    }
+
+    try
+    {
+        ivx::Context ctx = ivx::Context::create();
+        if ((vx_size)(ksize.width) > ctx.convolutionMaxDimension() || (vx_size)(ksize.height) > ctx.convolutionMaxDimension())
+            return false;
+
+        Mat a;
+        if (dst.data != src.data)
+            a = src;
+        else
+            src.copyTo(a);
+
+        ivx::Image
+            ia = ivx::Image::createFromHandle(ctx, VX_DF_IMAGE_U8,
+                ivx::Image::createAddressing(a.cols, a.rows, 1, (vx_int32)(a.step)), a.data),
+            ib = ivx::Image::createFromHandle(ctx, VX_DF_IMAGE_U8,
+                ivx::Image::createAddressing(dst.cols, dst.rows, 1, (vx_int32)(dst.step)), dst.data);
+
+        //ATTENTION: VX_CONTEXT_IMMEDIATE_BORDER attribute change could lead to strange issues in multi-threaded environments
+        //since OpenVX standart says nothing about thread-safety for now
+        ivx::border_t prevBorder = ctx.immediateBorder();
+        ctx.setImmediateBorder(border, (vx_uint8)(0));
+        if (ksize.width == 3 && ksize.height == 3 && (sigma1 == 0.0 || (sigma1 - 0.8) < DBL_EPSILON) && (sigma2 == 0.0 || (sigma2 - 0.8) < DBL_EPSILON))
+        {
+            ivx::IVX_CHECK_STATUS(vxuGaussian3x3(ctx, ia, ib));
+        }
+        else
+        {
+#if VX_VERSION <= VX_VERSION_1_0
+            if (ctx.vendorID() == VX_ID_KHRONOS && ((vx_size)(a.cols) <= ctx.convolutionMaxDimension() || (vx_size)(a.rows) <= ctx.convolutionMaxDimension()))
+            {
+                ctx.setImmediateBorder(prevBorder);
+                return false;
+            }
+#endif
+            Mat convData;
+            cv::Mat(cv::getGaussianKernel(ksize.height, sigma2)*cv::getGaussianKernel(ksize.width, sigma1).t()).convertTo(convData, CV_16SC1, (1 << 15));
+            ivx::Convolution cnv = ivx::Convolution::create(ctx, convData.cols, convData.rows);
+            cnv.copyFrom(convData);
+            cnv.setScale(1 << 15);
+            ivx::IVX_CHECK_STATUS(vxuConvolve(ctx, ia, cnv, ib));
+        }
+        ctx.setImmediateBorder(prevBorder);
+    }
+    catch (ivx::RuntimeError & e)
+    {
+        VX_DbgThrow(e.what());
+    }
+    catch (ivx::WrapperError & e)
+    {
+        VX_DbgThrow(e.what());
+    }
+    return true;
+}
+
+#endif
+
+#ifdef HAVE_IPP
+
 static bool ipp_GaussianBlur( InputArray _src, OutputArray _dst, Size ksize,
                    double sigma1, double sigma2,
                    int borderType )
 {
+    CV_INSTRUMENT_REGION_IPP()
+
 #if IPP_VERSION_X100 >= 810
+    if ((borderType & BORDER_ISOLATED) == 0 && _src.isSubmatrix())
+        return false;
+
     int type = _src.type();
     Size size = _src.size();
 
@@ -1703,19 +2340,18 @@ static bool ipp_GaussianBlur( InputArray _src, OutputArray _dst, Size ksize,
 #define IPP_FILTER_GAUSS_C1(ippfavor) \
                     { \
                         Ipp##ippfavor borderValues = 0; \
-                        status = ippiFilterGaussianBorder_##ippfavor##_C1R(src.ptr<Ipp##ippfavor>(), (int)src.step, \
+                        status = CV_INSTRUMENT_FUN_IPP(ippiFilterGaussianBorder_##ippfavor##_C1R, src.ptr<Ipp##ippfavor>(), (int)src.step, \
                                 dst.ptr<Ipp##ippfavor>(), (int)dst.step, roiSize, borderValues, spec, buffer); \
                     }
 
 #define IPP_FILTER_GAUSS_CN(ippfavor, ippcn) \
                     { \
                         Ipp##ippfavor borderValues[] = { 0, 0, 0 }; \
-                        status = ippiFilterGaussianBorder_##ippfavor##_C##ippcn##R(src.ptr<Ipp##ippfavor>(), (int)src.step, \
+                        status = CV_INSTRUMENT_FUN_IPP(ippiFilterGaussianBorder_##ippfavor##_C##ippcn##R, src.ptr<Ipp##ippfavor>(), (int)src.step, \
                                 dst.ptr<Ipp##ippfavor>(), (int)dst.step, roiSize, borderValues, spec, buffer); \
                     }
 
                     IppStatus status = ippStsErr;
-#if !HAVE_ICV
 #if IPP_VERSION_X100 > 900 // Buffer overflow may happen in IPP 9.0.0 and less
                     if (type == CV_8UC1)
                         IPP_FILTER_GAUSS_C1(8u)
@@ -1733,9 +2369,7 @@ static bool ipp_GaussianBlur( InputArray _src, OutputArray _dst, Size ksize,
                         IPP_FILTER_GAUSS_CN(16s, 3)
                     else if (type == CV_32FC3)
                         IPP_FILTER_GAUSS_CN(32f, 3)
-                    else
-#endif
-                    if (type == CV_32FC1)
+                    else if (type == CV_32FC1)
                         IPP_FILTER_GAUSS_C1(32f)
 
                     if(status >= 0)
@@ -1752,14 +2386,16 @@ static bool ipp_GaussianBlur( InputArray _src, OutputArray _dst, Size ksize,
 #endif
     return false;
 }
-}
 #endif
+}
 
 
 void cv::GaussianBlur( InputArray _src, OutputArray _dst, Size ksize,
                    double sigma1, double sigma2,
                    int borderType )
 {
+    CV_INSTRUMENT_REGION()
+
     int type = _src.type();
     Size size = _src.size();
     _dst.create( size, type );
@@ -1778,6 +2414,9 @@ void cv::GaussianBlur( InputArray _src, OutputArray _dst, Size ksize,
         return;
     }
 
+    CV_OVX_RUN(true,
+               openvx_gaussianBlur(_src, _dst, ksize, sigma1, sigma2, borderType))
+
 #ifdef HAVE_TEGRA_OPTIMIZATION
     Mat src = _src.getMat();
     Mat dst = _dst.getMat();
@@ -1785,10 +2424,17 @@ void cv::GaussianBlur( InputArray _src, OutputArray _dst, Size ksize,
         return;
 #endif
 
-    CV_IPP_RUN(true, ipp_GaussianBlur( _src,  _dst,  ksize, sigma1,  sigma2, borderType));
+    CV_IPP_RUN(!(ocl::useOpenCL() && _dst.isUMat()), ipp_GaussianBlur( _src,  _dst,  ksize, sigma1,  sigma2, borderType));
 
     Mat kx, ky;
     createGaussianKernels(kx, ky, type, ksize, sigma1, sigma2);
+
+    CV_OCL_RUN(_dst.isUMat() && _src.dims() <= 2 &&
+               ((ksize.width == 3 && ksize.height == 3) ||
+               (ksize.width == 5 && ksize.height == 5)) &&
+               (size_t)_src.rows() > ky.total() && (size_t)_src.cols() > kx.total(),
+               ocl_GaussianBlur_8UC1(_src, _dst, ksize, CV_MAT_DEPTH(type), kx, ky, borderType));
+
     sepFilter2D(_src, _dst, CV_MAT_DEPTH(type), kx, ky, Point(-1,-1), 0, borderType );
 }
 
@@ -2698,11 +3344,96 @@ static bool ocl_medianFilter(InputArray _src, OutputArray _dst, int m)
 
 }
 
+#ifdef HAVE_OPENVX
+namespace cv
+{
+    static bool openvx_medianFilter(InputArray _src, OutputArray _dst, int ksize)
+    {
+        if (_src.type() != CV_8UC1 || _dst.type() != CV_8U
+#ifndef VX_VERSION_1_1
+            || ksize != 3
+#endif
+            )
+            return false;
+
+        Mat src = _src.getMat();
+        Mat dst = _dst.getMat();
+
+        try
+        {
+            ivx::Context ctx = ivx::Context::create();
+#ifdef VX_VERSION_1_1
+            if ((vx_size)ksize > ctx.nonlinearMaxDimension())
+                return false;
+#endif
+
+            Mat a;
+            if (dst.data != src.data)
+                a = src;
+            else
+                src.copyTo(a);
+
+            ivx::Image
+                ia = ivx::Image::createFromHandle(ctx, VX_DF_IMAGE_U8,
+                    ivx::Image::createAddressing(a.cols, a.rows, 1, (vx_int32)(a.step)), a.data),
+                ib = ivx::Image::createFromHandle(ctx, VX_DF_IMAGE_U8,
+                    ivx::Image::createAddressing(dst.cols, dst.rows, 1, (vx_int32)(dst.step)), dst.data);
+
+            //ATTENTION: VX_CONTEXT_IMMEDIATE_BORDER attribute change could lead to strange issues in multi-threaded environments
+            //since OpenVX standart says nothing about thread-safety for now
+            ivx::border_t prevBorder = ctx.immediateBorder();
+            ctx.setImmediateBorder(VX_BORDER_REPLICATE);
+#ifdef VX_VERSION_1_1
+            if (ksize == 3)
+#endif
+            {
+                ivx::IVX_CHECK_STATUS(vxuMedian3x3(ctx, ia, ib));
+            }
+#ifdef VX_VERSION_1_1
+            else
+            {
+                ivx::Matrix mtx;
+                if(ksize == 5)
+                    mtx = ivx::Matrix::createFromPattern(ctx, VX_PATTERN_BOX, ksize, ksize);
+                else
+                {
+                    vx_size supportedSize;
+                    ivx::IVX_CHECK_STATUS(vxQueryContext(ctx, VX_CONTEXT_NONLINEAR_MAX_DIMENSION, &supportedSize, sizeof(supportedSize)));
+                    if ((vx_size)ksize > supportedSize)
+                    {
+                        ctx.setImmediateBorder(prevBorder);
+                        return false;
+                    }
+                    Mat mask(ksize, ksize, CV_8UC1, Scalar(255));
+                    mtx = ivx::Matrix::create(ctx, VX_TYPE_UINT8, ksize, ksize);
+                    mtx.copyFrom(mask);
+                }
+                ivx::IVX_CHECK_STATUS(vxuNonLinearFilter(ctx, VX_NONLINEAR_FILTER_MEDIAN, ia, mtx, ib));
+            }
+#endif
+            ctx.setImmediateBorder(prevBorder);
+        }
+        catch (ivx::RuntimeError & e)
+        {
+            VX_DbgThrow(e.what());
+        }
+        catch (ivx::WrapperError & e)
+        {
+            VX_DbgThrow(e.what());
+        }
+
+        return true;
+    }
+}
+#endif
+
 #ifdef HAVE_IPP
 namespace cv
 {
 static bool ipp_medianFilter( InputArray _src0, OutputArray _dst, int ksize )
 {
+    CV_INSTRUMENT_REGION_IPP()
+
 #if IPP_VERSION_X100 >= 810
     Mat src0 = _src0.getMat();
     _dst.create( src0.size(), src0.type() );
@@ -2715,7 +3446,7 @@ static bool ipp_medianFilter( InputArray _src0, OutputArray _dst, int ksize )
         ippDataType, CV_MAT_CN(type), &bufSize) >= 0) \
         { \
             Ipp8u * buffer = ippsMalloc_8u(bufSize); \
-            IppStatus status = ippiFilterMedianBorder_##flavor(src.ptr<ippType>(), (int)src.step, \
+            IppStatus status = CV_INSTRUMENT_FUN_IPP(ippiFilterMedianBorder_##flavor, src.ptr<ippType>(), (int)src.step, \
             dst.ptr<ippType>(), (int)dst.step, dstRoiSize, maskSize, \
             ippBorderRepl, (ippType)0, buffer); \
             ippsFree(buffer); \
@@ -2759,6 +3490,8 @@ static bool ipp_medianFilter( InputArray _src0, OutputArray _dst, int ksize )
 
 void cv::medianBlur( InputArray _src0, OutputArray _dst, int ksize )
 {
+    CV_INSTRUMENT_REGION()
+
     CV_Assert( (ksize % 2 == 1) && (_src0.dims() <= 2 ));
 
     if( ksize <= 1 )
@@ -2774,6 +3507,9 @@ void cv::medianBlur( InputArray _src0, OutputArray _dst, int ksize )
     _dst.create( src0.size(), src0.type() );
     Mat dst = _dst.getMat();
 
+    CV_OVX_RUN(true,
+               openvx_medianFilter(_src0, _dst, ksize))
+
     CV_IPP_RUN(IPP_VERSION_X100 >= 810 && ksize <= 5, ipp_medianFilter(_src0,_dst, ksize));
 
 #ifdef HAVE_TEGRA_OPTIMIZATION
@@ -2783,7 +3519,7 @@ void cv::medianBlur( InputArray _src0, OutputArray _dst, int ksize )
 
     bool useSortNet = ksize == 3 || (ksize == 5
 #if !(CV_SSE2 || CV_NEON)
-            && src0.depth() > CV_8U
+            && ( src0.depth() > CV_8U || src0.channels() == 2 || src0.channels() > 4 )
 #endif
         );
 
@@ -2952,16 +3688,16 @@ public:
                             _g = _mm_mul_ps(_g, _w);
                             _r = _mm_mul_ps(_r, _w);
 
-                             _w = _mm_hadd_ps(_w, _b);
-                             _g = _mm_hadd_ps(_g, _r);
+                            _w = _mm_hadd_ps(_w, _b);
+                            _g = _mm_hadd_ps(_g, _r);
 
-                             _w = _mm_hadd_ps(_w, _g);
-                             _mm_store_ps(bufSum, _w);
+                            _w = _mm_hadd_ps(_w, _g);
+                            _mm_store_ps(bufSum, _w);
 
-                             wsum  += bufSum[0];
-                             sum_b += bufSum[1];
-                             sum_g += bufSum[2];
-                             sum_r += bufSum[3];
+                            wsum  += bufSum[0];
+                            sum_b += bufSum[1];
+                            sum_g += bufSum[2];
+                            sum_r += bufSum[3];
                          }
                     }
                     #endif
@@ -2992,7 +3728,7 @@ private:
     float *space_weight, *color_weight;
 };
 
-#if defined (HAVE_IPP) && !defined(HAVE_IPP_ICV_ONLY) && IPP_DISABLE_BLOCK
+#if defined (HAVE_IPP) && IPP_DISABLE_BLOCK
 class IPPBilateralFilter_8u_Invoker :
     public ParallelLoopBody
 {
@@ -3228,11 +3964,15 @@ public:
     {
         int i, j, k;
         Size size = dest->size();
-        #if CV_SSE3
+        #if CV_SSE3 || CV_NEON
         int CV_DECL_ALIGNED(16) idxBuf[4];
         float CV_DECL_ALIGNED(16) bufSum32[4];
         static const unsigned int CV_DECL_ALIGNED(16) bufSignMask[] = { 0x80000000, 0x80000000, 0x80000000, 0x80000000 };
+        #endif
+        #if CV_SSE3
         bool haveSSE3 = checkHardwareSupport(CV_CPU_SSE3);
+        #elif CV_NEON
+        bool haveNEON = checkHardwareSupport(CV_CPU_NEON);
         #endif
 
         for( i = range.start; i < range.end; i++ )
@@ -3274,15 +4014,56 @@ public:
                             __m128 _w = _mm_mul_ps(_sw, _mm_add_ps(_explut, _mm_mul_ps(_alpha, _mm_sub_ps(_explut1, _explut))));
                             _val = _mm_mul_ps(_w, _val);
 
-                             _sw = _mm_hadd_ps(_w, _val);
-                             _sw = _mm_hadd_ps(_sw, _sw);
-                             psum = _mm_add_ps(_sw, psum);
+                            _sw = _mm_hadd_ps(_w, _val);
+                            _sw = _mm_hadd_ps(_sw, _sw);
+                            psum = _mm_add_ps(_sw, psum);
                         }
                         _mm_storel_pi((__m64*)bufSum32, psum);
 
                         sum = bufSum32[1];
                         wsum = bufSum32[0];
                     }
+                    #elif CV_NEON
+                    if( haveNEON )
+                    {
+                        float32x2_t psum = vdup_n_f32(0.0f);
+                        const volatile float32x4_t _val0 = vdupq_n_f32(sptr[j]);
+                        const float32x4_t _scale_index = vdupq_n_f32(scale_index);
+                        const uint32x4_t _signMask = vld1q_u32(bufSignMask);
+
+                        for( ; k <= maxk - 4 ; k += 4 )
+                        {
+                            float32x4_t _sw  = vld1q_f32(space_weight + k);
+                            float CV_DECL_ALIGNED(16) _data[] = {sptr[j + space_ofs[k]],   sptr[j + space_ofs[k+1]],
+                                                                 sptr[j + space_ofs[k+2]], sptr[j + space_ofs[k+3]],};
+                            float32x4_t _val = vld1q_f32(_data);
+                            float32x4_t _alpha = vsubq_f32(_val, _val0);
+                            _alpha = vreinterpretq_f32_u32(vbicq_u32(vreinterpretq_u32_f32(_alpha), _signMask));
+                            _alpha = vmulq_f32(_alpha, _scale_index);
+                            int32x4_t _idx = vcvtq_s32_f32(_alpha);
+                            vst1q_s32(idxBuf, _idx);
+                            _alpha = vsubq_f32(_alpha, vcvtq_f32_s32(_idx));
+
+                            bufSum32[0] = expLUT[idxBuf[0]];
+                            bufSum32[1] = expLUT[idxBuf[1]];
+                            bufSum32[2] = expLUT[idxBuf[2]];
+                            bufSum32[3] = expLUT[idxBuf[3]];
+                            float32x4_t _explut = vld1q_f32(bufSum32);
+                            bufSum32[0] = expLUT[idxBuf[0]+1];
+                            bufSum32[1] = expLUT[idxBuf[1]+1];
+                            bufSum32[2] = expLUT[idxBuf[2]+1];
+                            bufSum32[3] = expLUT[idxBuf[3]+1];
+                            float32x4_t _explut1 = vld1q_f32(bufSum32);
+
+                            float32x4_t _w = vmulq_f32(_sw, vaddq_f32(_explut, vmulq_f32(_alpha, vsubq_f32(_explut1, _explut))));
+                            _val = vmulq_f32(_w, _val);
+
+                            float32x2_t _wval = vpadd_f32(vpadd_f32(vget_low_f32(_w),vget_high_f32(_w)), vpadd_f32(vget_low_f32(_val), vget_high_f32(_val)));
+                            psum = vadd_f32(_wval, psum);
+                        }
+                        sum = vget_lane_f32(psum, 1);
+                        wsum = vget_lane_f32(psum, 0);
+                    }
                     #endif
 
                     for( ; k < maxk; k++ )
@@ -3362,6 +4143,72 @@ public:
                         sum_g = bufSum32[2];
                         sum_r = bufSum32[3];
                     }
+                    #elif CV_NEON
+                    if( haveNEON )
+                    {
+                        float32x4_t sum = vdupq_n_f32(0.0f);
+                        const float32x4_t _b0 = vdupq_n_f32(b0);
+                        const float32x4_t _g0 = vdupq_n_f32(g0);
+                        const float32x4_t _r0 = vdupq_n_f32(r0);
+                        const float32x4_t _scale_index = vdupq_n_f32(scale_index);
+                        const uint32x4_t _signMask = vld1q_u32(bufSignMask);
+
+                        for( ; k <= maxk-4; k += 4 )
+                        {
+                            float32x4_t _sw = vld1q_f32(space_weight + k);
+
+                            const float* const sptr_k0 = sptr + j + space_ofs[k];
+                            const float* const sptr_k1 = sptr + j + space_ofs[k+1];
+                            const float* const sptr_k2 = sptr + j + space_ofs[k+2];
+                            const float* const sptr_k3 = sptr + j + space_ofs[k+3];
+
+                            float32x4_t _v0 = vld1q_f32(sptr_k0);
+                            float32x4_t _v1 = vld1q_f32(sptr_k1);
+                            float32x4_t _v2 = vld1q_f32(sptr_k2);
+                            float32x4_t _v3 = vld1q_f32(sptr_k3);
+
+                            float32x4x2_t v01 = vtrnq_f32(_v0, _v1);
+                            float32x4x2_t v23 = vtrnq_f32(_v2, _v3);
+                            float32x4_t _b = vcombine_f32(vget_low_f32(v01.val[0]), vget_low_f32(v23.val[0]));
+                            float32x4_t _g = vcombine_f32(vget_low_f32(v01.val[1]), vget_low_f32(v23.val[1]));
+                            float32x4_t _r = vcombine_f32(vget_high_f32(v01.val[0]), vget_high_f32(v23.val[0]));
+
+                            float32x4_t _bt = vreinterpretq_f32_u32(vbicq_u32(vreinterpretq_u32_f32(vsubq_f32(_b, _b0)), _signMask));
+                            float32x4_t _gt = vreinterpretq_f32_u32(vbicq_u32(vreinterpretq_u32_f32(vsubq_f32(_g, _g0)), _signMask));
+                            float32x4_t _rt = vreinterpretq_f32_u32(vbicq_u32(vreinterpretq_u32_f32(vsubq_f32(_r, _r0)), _signMask));
+                            float32x4_t _alpha = vmulq_f32(_scale_index, vaddq_f32(_bt, vaddq_f32(_gt, _rt)));
+
+                            int32x4_t _idx = vcvtq_s32_f32(_alpha);
+                            vst1q_s32((int*)idxBuf, _idx);
+                            bufSum32[0] = expLUT[idxBuf[0]];
+                            bufSum32[1] = expLUT[idxBuf[1]];
+                            bufSum32[2] = expLUT[idxBuf[2]];
+                            bufSum32[3] = expLUT[idxBuf[3]];
+                            float32x4_t _explut = vld1q_f32(bufSum32);
+                            bufSum32[0] = expLUT[idxBuf[0]+1];
+                            bufSum32[1] = expLUT[idxBuf[1]+1];
+                            bufSum32[2] = expLUT[idxBuf[2]+1];
+                            bufSum32[3] = expLUT[idxBuf[3]+1];
+                            float32x4_t _explut1 = vld1q_f32(bufSum32);
+
+                            float32x4_t _w = vmulq_f32(_sw, vaddq_f32(_explut, vmulq_f32(_alpha, vsubq_f32(_explut1, _explut))));
+
+                            _b = vmulq_f32(_b, _w);
+                            _g = vmulq_f32(_g, _w);
+                            _r = vmulq_f32(_r, _w);
+
+                            float32x2_t _wb = vpadd_f32(vpadd_f32(vget_low_f32(_w),vget_high_f32(_w)), vpadd_f32(vget_low_f32(_b), vget_high_f32(_b)));
+                            float32x2_t _gr = vpadd_f32(vpadd_f32(vget_low_f32(_g),vget_high_f32(_g)), vpadd_f32(vget_low_f32(_r), vget_high_f32(_r)));
+
+                            _w = vcombine_f32(_wb, _gr);
+                            sum = vaddq_f32(sum, _w);
+                        }
+                        vst1q_f32(bufSum32, sum);
+                        wsum  = bufSum32[0];
+                        sum_b = bufSum32[1];
+                        sum_g = bufSum32[2];
+                        sum_r = bufSum32[3];
+                    }
                     #endif
 
                     for(; k < maxk; k++ )
@@ -3489,6 +4336,8 @@ void cv::bilateralFilter( InputArray _src, OutputArray _dst, int d,
                       double sigmaColor, double sigmaSpace,
                       int borderType )
 {
+    CV_INSTRUMENT_REGION()
+
     _dst.create( _src.size(), _src.type() );
 
     CV_OCL_RUN(_src.dims() <= 2 && _dst.isUMat(),
diff --git a/modules/imgproc/src/spatialgradient.cpp b/modules/imgproc/src/spatialgradient.cpp
index 411c299..9217558 100644
--- a/modules/imgproc/src/spatialgradient.cpp
+++ b/modules/imgproc/src/spatialgradient.cpp
@@ -78,6 +78,7 @@ static inline void spatialGradientKernel( T& vx, T& vy,
 void spatialGradient( InputArray _src, OutputArray _dx, OutputArray _dy,
                       int ksize, int borderType )
 {
+    CV_INSTRUMENT_REGION()
 
     // Prepare InputArray src
     Mat src = _src.getMat();
@@ -129,140 +130,143 @@ void spatialGradient( InputArray _src, OutputArray _dx, OutputArray _dy,
     int i_start = 0;
     int j_start = 0;
 #if CV_SIMD128 && CV_SSE2
-    uchar *m_src;
-    short *n_dx, *n_dy;
-
-    // Characters in variable names have the following meanings:
-    // u: unsigned char
-    // s: signed int
-    //
-    // [row][column]
-    // m: offset -1
-    // n: offset  0
-    // p: offset  1
-    // Example: umn is offset -1 in row and offset 0 in column
-    for ( i = 0; i < H - 1; i += 2 )
+    if(hasSIMD128())
     {
-        if   ( i == 0 ) p_src = src.ptr<uchar>(i_top);
-        else            p_src = src.ptr<uchar>(i-1);
-
-        c_src = src.ptr<uchar>(i);
-        n_src = src.ptr<uchar>(i+1);
-
-        if ( i == H - 2 ) m_src = src.ptr<uchar>(i_bottom);
-        else              m_src = src.ptr<uchar>(i+2);
-
-        c_dx = dx.ptr<short>(i);
-        c_dy = dy.ptr<short>(i);
-        n_dx = dx.ptr<short>(i+1);
-        n_dy = dy.ptr<short>(i+1);
-
-        v_uint8x16 v_select_m = v_uint8x16(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-                                           0, 0, 0, 0xFF);
-
-        // Process rest of columns 16-column chunks at a time
-        for ( j = 1; j < W - 16; j += 16 )
+        uchar *m_src;
+        short *n_dx, *n_dy;
+
+        // Characters in variable names have the following meanings:
+        // u: unsigned char
+        // s: signed int
+        //
+        // [row][column]
+        // m: offset -1
+        // n: offset  0
+        // p: offset  1
+        // Example: umn is offset -1 in row and offset 0 in column
+        for ( i = 0; i < H - 1; i += 2 )
         {
-            // Load top row for 3x3 Sobel filter
-            v_uint8x16 v_um = v_load(&p_src[j-1]);
-            v_uint8x16 v_up = v_load(&p_src[j+1]);
-            // TODO: Replace _mm_slli_si128 with hal method
-            v_uint8x16 v_un = v_select(v_select_m, v_uint8x16(_mm_slli_si128(v_up.val, 1)),
-                                                   v_uint8x16(_mm_srli_si128(v_um.val, 1)));
-            v_uint16x8 v_um1, v_um2, v_un1, v_un2, v_up1, v_up2;
-            v_expand(v_um, v_um1, v_um2);
-            v_expand(v_un, v_un1, v_un2);
-            v_expand(v_up, v_up1, v_up2);
-            v_int16x8 v_s1m1 = v_reinterpret_as_s16(v_um1);
-            v_int16x8 v_s1m2 = v_reinterpret_as_s16(v_um2);
-            v_int16x8 v_s1n1 = v_reinterpret_as_s16(v_un1);
-            v_int16x8 v_s1n2 = v_reinterpret_as_s16(v_un2);
-            v_int16x8 v_s1p1 = v_reinterpret_as_s16(v_up1);
-            v_int16x8 v_s1p2 = v_reinterpret_as_s16(v_up2);
-
-            // Load second row for 3x3 Sobel filter
-            v_um = v_load(&c_src[j-1]);
-            v_up = v_load(&c_src[j+1]);
-            // TODO: Replace _mm_slli_si128 with hal method
-            v_un = v_select(v_select_m, v_uint8x16(_mm_slli_si128(v_up.val, 1)),
-                                        v_uint8x16(_mm_srli_si128(v_um.val, 1)));
-            v_expand(v_um, v_um1, v_um2);
-            v_expand(v_un, v_un1, v_un2);
-            v_expand(v_up, v_up1, v_up2);
-            v_int16x8 v_s2m1 = v_reinterpret_as_s16(v_um1);
-            v_int16x8 v_s2m2 = v_reinterpret_as_s16(v_um2);
-            v_int16x8 v_s2n1 = v_reinterpret_as_s16(v_un1);
-            v_int16x8 v_s2n2 = v_reinterpret_as_s16(v_un2);
-            v_int16x8 v_s2p1 = v_reinterpret_as_s16(v_up1);
-            v_int16x8 v_s2p2 = v_reinterpret_as_s16(v_up2);
-
-            // Load third row for 3x3 Sobel filter
-            v_um = v_load(&n_src[j-1]);
-            v_up = v_load(&n_src[j+1]);
-            // TODO: Replace _mm_slli_si128 with hal method
-            v_un = v_select(v_select_m, v_uint8x16(_mm_slli_si128(v_up.val, 1)),
-                                        v_uint8x16(_mm_srli_si128(v_um.val, 1)));
-            v_expand(v_um, v_um1, v_um2);
-            v_expand(v_un, v_un1, v_un2);
-            v_expand(v_up, v_up1, v_up2);
-            v_int16x8 v_s3m1 = v_reinterpret_as_s16(v_um1);
-            v_int16x8 v_s3m2 = v_reinterpret_as_s16(v_um2);
-            v_int16x8 v_s3n1 = v_reinterpret_as_s16(v_un1);
-            v_int16x8 v_s3n2 = v_reinterpret_as_s16(v_un2);
-            v_int16x8 v_s3p1 = v_reinterpret_as_s16(v_up1);
-            v_int16x8 v_s3p2 = v_reinterpret_as_s16(v_up2);
-
-            // dx & dy for rows 1, 2, 3
-            v_int16x8 v_sdx1, v_sdy1;
-            spatialGradientKernel<v_int16x8>( v_sdx1, v_sdy1,
-                                              v_s1m1, v_s1n1, v_s1p1,
-                                              v_s2m1,         v_s2p1,
-                                              v_s3m1, v_s3n1, v_s3p1 );
-
-            v_int16x8 v_sdx2, v_sdy2;
-            spatialGradientKernel<v_int16x8>( v_sdx2, v_sdy2,
-                                              v_s1m2, v_s1n2, v_s1p2,
-                                              v_s2m2,         v_s2p2,
-                                              v_s3m2, v_s3n2, v_s3p2 );
-
-            // Store
-            v_store(&c_dx[j],   v_sdx1);
-            v_store(&c_dx[j+8], v_sdx2);
-            v_store(&c_dy[j],   v_sdy1);
-            v_store(&c_dy[j+8], v_sdy2);
-
-            // Load fourth row for 3x3 Sobel filter
-            v_um = v_load(&m_src[j-1]);
-            v_up = v_load(&m_src[j+1]);
-            // TODO: Replace _mm_slli_si128 with hal method
-            v_un = v_select(v_select_m, v_uint8x16(_mm_slli_si128(v_up.val, 1)),
-                                        v_uint8x16(_mm_srli_si128(v_um.val, 1)));
-            v_expand(v_um, v_um1, v_um2);
-            v_expand(v_un, v_un1, v_un2);
-            v_expand(v_up, v_up1, v_up2);
-            v_int16x8 v_s4m1 = v_reinterpret_as_s16(v_um1);
-            v_int16x8 v_s4m2 = v_reinterpret_as_s16(v_um2);
-            v_int16x8 v_s4n1 = v_reinterpret_as_s16(v_un1);
-            v_int16x8 v_s4n2 = v_reinterpret_as_s16(v_un2);
-            v_int16x8 v_s4p1 = v_reinterpret_as_s16(v_up1);
-            v_int16x8 v_s4p2 = v_reinterpret_as_s16(v_up2);
-
-            // dx & dy for rows 2, 3, 4
-            spatialGradientKernel<v_int16x8>( v_sdx1, v_sdy1,
-                                              v_s2m1, v_s2n1, v_s2p1,
-                                              v_s3m1,         v_s3p1,
-                                              v_s4m1, v_s4n1, v_s4p1 );
-
-            spatialGradientKernel<v_int16x8>( v_sdx2, v_sdy2,
-                                              v_s2m2, v_s2n2, v_s2p2,
-                                              v_s3m2,         v_s3p2,
-                                              v_s4m2, v_s4n2, v_s4p2 );
-
-            // Store
-            v_store(&n_dx[j],   v_sdx1);
-            v_store(&n_dx[j+8], v_sdx2);
-            v_store(&n_dy[j],   v_sdy1);
-            v_store(&n_dy[j+8], v_sdy2);
+            if   ( i == 0 ) p_src = src.ptr<uchar>(i_top);
+            else            p_src = src.ptr<uchar>(i-1);
+
+            c_src = src.ptr<uchar>(i);
+            n_src = src.ptr<uchar>(i+1);
+
+            if ( i == H - 2 ) m_src = src.ptr<uchar>(i_bottom);
+            else              m_src = src.ptr<uchar>(i+2);
+
+            c_dx = dx.ptr<short>(i);
+            c_dy = dy.ptr<short>(i);
+            n_dx = dx.ptr<short>(i+1);
+            n_dy = dy.ptr<short>(i+1);
+
+            v_uint8x16 v_select_m = v_uint8x16(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+                                               0, 0, 0, 0xFF);
+
+            // Process rest of columns 16-column chunks at a time
+            for ( j = 1; j < W - 16; j += 16 )
+            {
+                // Load top row for 3x3 Sobel filter
+                v_uint8x16 v_um = v_load(&p_src[j-1]);
+                v_uint8x16 v_up = v_load(&p_src[j+1]);
+                // TODO: Replace _mm_slli_si128 with hal method
+                v_uint8x16 v_un = v_select(v_select_m, v_uint8x16(_mm_slli_si128(v_up.val, 1)),
+                                                       v_uint8x16(_mm_srli_si128(v_um.val, 1)));
+                v_uint16x8 v_um1, v_um2, v_un1, v_un2, v_up1, v_up2;
+                v_expand(v_um, v_um1, v_um2);
+                v_expand(v_un, v_un1, v_un2);
+                v_expand(v_up, v_up1, v_up2);
+                v_int16x8 v_s1m1 = v_reinterpret_as_s16(v_um1);
+                v_int16x8 v_s1m2 = v_reinterpret_as_s16(v_um2);
+                v_int16x8 v_s1n1 = v_reinterpret_as_s16(v_un1);
+                v_int16x8 v_s1n2 = v_reinterpret_as_s16(v_un2);
+                v_int16x8 v_s1p1 = v_reinterpret_as_s16(v_up1);
+                v_int16x8 v_s1p2 = v_reinterpret_as_s16(v_up2);
+
+                // Load second row for 3x3 Sobel filter
+                v_um = v_load(&c_src[j-1]);
+                v_up = v_load(&c_src[j+1]);
+                // TODO: Replace _mm_slli_si128 with hal method
+                v_un = v_select(v_select_m, v_uint8x16(_mm_slli_si128(v_up.val, 1)),
+                                            v_uint8x16(_mm_srli_si128(v_um.val, 1)));
+                v_expand(v_um, v_um1, v_um2);
+                v_expand(v_un, v_un1, v_un2);
+                v_expand(v_up, v_up1, v_up2);
+                v_int16x8 v_s2m1 = v_reinterpret_as_s16(v_um1);
+                v_int16x8 v_s2m2 = v_reinterpret_as_s16(v_um2);
+                v_int16x8 v_s2n1 = v_reinterpret_as_s16(v_un1);
+                v_int16x8 v_s2n2 = v_reinterpret_as_s16(v_un2);
+                v_int16x8 v_s2p1 = v_reinterpret_as_s16(v_up1);
+                v_int16x8 v_s2p2 = v_reinterpret_as_s16(v_up2);
+
+                // Load third row for 3x3 Sobel filter
+                v_um = v_load(&n_src[j-1]);
+                v_up = v_load(&n_src[j+1]);
+                // TODO: Replace _mm_slli_si128 with hal method
+                v_un = v_select(v_select_m, v_uint8x16(_mm_slli_si128(v_up.val, 1)),
+                                            v_uint8x16(_mm_srli_si128(v_um.val, 1)));
+                v_expand(v_um, v_um1, v_um2);
+                v_expand(v_un, v_un1, v_un2);
+                v_expand(v_up, v_up1, v_up2);
+                v_int16x8 v_s3m1 = v_reinterpret_as_s16(v_um1);
+                v_int16x8 v_s3m2 = v_reinterpret_as_s16(v_um2);
+                v_int16x8 v_s3n1 = v_reinterpret_as_s16(v_un1);
+                v_int16x8 v_s3n2 = v_reinterpret_as_s16(v_un2);
+                v_int16x8 v_s3p1 = v_reinterpret_as_s16(v_up1);
+                v_int16x8 v_s3p2 = v_reinterpret_as_s16(v_up2);
+
+                // dx & dy for rows 1, 2, 3
+                v_int16x8 v_sdx1, v_sdy1;
+                spatialGradientKernel<v_int16x8>( v_sdx1, v_sdy1,
+                                                  v_s1m1, v_s1n1, v_s1p1,
+                                                  v_s2m1,         v_s2p1,
+                                                  v_s3m1, v_s3n1, v_s3p1 );
+
+                v_int16x8 v_sdx2, v_sdy2;
+                spatialGradientKernel<v_int16x8>( v_sdx2, v_sdy2,
+                                                  v_s1m2, v_s1n2, v_s1p2,
+                                                  v_s2m2,         v_s2p2,
+                                                  v_s3m2, v_s3n2, v_s3p2 );
+
+                // Store
+                v_store(&c_dx[j],   v_sdx1);
+                v_store(&c_dx[j+8], v_sdx2);
+                v_store(&c_dy[j],   v_sdy1);
+                v_store(&c_dy[j+8], v_sdy2);
+
+                // Load fourth row for 3x3 Sobel filter
+                v_um = v_load(&m_src[j-1]);
+                v_up = v_load(&m_src[j+1]);
+                // TODO: Replace _mm_slli_si128 with hal method
+                v_un = v_select(v_select_m, v_uint8x16(_mm_slli_si128(v_up.val, 1)),
+                                            v_uint8x16(_mm_srli_si128(v_um.val, 1)));
+                v_expand(v_um, v_um1, v_um2);
+                v_expand(v_un, v_un1, v_un2);
+                v_expand(v_up, v_up1, v_up2);
+                v_int16x8 v_s4m1 = v_reinterpret_as_s16(v_um1);
+                v_int16x8 v_s4m2 = v_reinterpret_as_s16(v_um2);
+                v_int16x8 v_s4n1 = v_reinterpret_as_s16(v_un1);
+                v_int16x8 v_s4n2 = v_reinterpret_as_s16(v_un2);
+                v_int16x8 v_s4p1 = v_reinterpret_as_s16(v_up1);
+                v_int16x8 v_s4p2 = v_reinterpret_as_s16(v_up2);
+
+                // dx & dy for rows 2, 3, 4
+                spatialGradientKernel<v_int16x8>( v_sdx1, v_sdy1,
+                                                  v_s2m1, v_s2n1, v_s2p1,
+                                                  v_s3m1,         v_s3p1,
+                                                  v_s4m1, v_s4n1, v_s4p1 );
+
+                spatialGradientKernel<v_int16x8>( v_sdx2, v_sdy2,
+                                                  v_s2m2, v_s2n2, v_s2p2,
+                                                  v_s3m2,         v_s3p2,
+                                                  v_s4m2, v_s4n2, v_s4p2 );
+
+                // Store
+                v_store(&n_dx[j],   v_sdx1);
+                v_store(&n_dx[j+8], v_sdx2);
+                v_store(&n_dy[j],   v_sdy1);
+                v_store(&n_dy[j+8], v_sdy2);
+            }
         }
     }
     i_start = i;
diff --git a/modules/imgproc/src/subdivision2d.cpp b/modules/imgproc/src/subdivision2d.cpp
index d849d2a..93c8b4c 100644
--- a/modules/imgproc/src/subdivision2d.cpp
+++ b/modules/imgproc/src/subdivision2d.cpp
@@ -275,6 +275,8 @@ void Subdiv2D::deletePoint(int vidx)
 
 int Subdiv2D::locate(Point2f pt, int& _edge, int& _vertex)
 {
+    CV_INSTRUMENT_REGION()
+
     int vertex = 0;
 
     int i, maxEdges = (int)(qedges.size() * 4);
@@ -409,6 +411,8 @@ isPtInCircle3( Point2f pt, Point2f a, Point2f b, Point2f c)
 
 int Subdiv2D::insert(Point2f pt)
 {
+    CV_INSTRUMENT_REGION()
+
     int curr_point = 0, curr_edge = 0, deleted_edge = 0;
     int location = locate( pt, curr_edge, curr_point );
 
@@ -479,12 +483,16 @@ int Subdiv2D::insert(Point2f pt)
 
 void Subdiv2D::insert(const std::vector<Point2f>& ptvec)
 {
+    CV_INSTRUMENT_REGION()
+
     for( size_t i = 0; i < ptvec.size(); i++ )
         insert(ptvec[i]);
 }
 
 void Subdiv2D::initDelaunay( Rect rect )
 {
+    CV_INSTRUMENT_REGION()
+
     float big_coord = 3.f * MAX( rect.width, rect.height );
     float rx = (float)rect.x;
     float ry = (float)rect.y;
@@ -644,6 +652,8 @@ isRightOf2( const Point2f& pt, const Point2f& org, const Point2f& diff )
 
 int Subdiv2D::findNearest(Point2f pt, Point2f* nearestPt)
 {
+    CV_INSTRUMENT_REGION()
+
     if( !validGeometry )
         calcVoronoi();
 
@@ -723,6 +733,26 @@ void Subdiv2D::getEdgeList(std::vector<Vec4f>& edgeList) const
     }
 }
 
+void Subdiv2D::getLeadingEdgeList(std::vector<int>& leadingEdgeList) const
+{
+    leadingEdgeList.clear();
+    int i, total = (int)(qedges.size()*4);
+    std::vector<bool> edgemask(total, false);
+
+    for( i = 4; i < total; i += 2 )
+    {
+        if( edgemask[i] )
+            continue;
+        int edge = i;
+        edgemask[edge] = true;
+        edge = getEdge(edge, NEXT_AROUND_LEFT);
+        edgemask[edge] = true;
+        edge = getEdge(edge, NEXT_AROUND_LEFT);
+        edgemask[edge] = true;
+        leadingEdgeList.push_back(i);
+    }
+}
+
 void Subdiv2D::getTriangleList(std::vector<Vec6f>& triangleList) const
 {
     triangleList.clear();
diff --git a/modules/imgproc/src/sumpixels.cpp b/modules/imgproc/src/sumpixels.cpp
index 7771d2c..c9793b2 100755
--- a/modules/imgproc/src/sumpixels.cpp
+++ b/modules/imgproc/src/sumpixels.cpp
@@ -54,7 +54,7 @@ struct Integral_SIMD
                     ST *, size_t,
                     QT *, size_t,
                     ST *, size_t,
-                    Size, int) const
+                    int, int, int) const
     {
         return false;
     }
@@ -74,19 +74,19 @@ struct Integral_SIMD<uchar, int, double>
                     int * sum, size_t _sumstep,
                     double * sqsum, size_t,
                     int * tilted, size_t,
-                    Size size, int cn) const
+                    int width, int height, int cn) const
     {
         if (sqsum || tilted || cn != 1 || !haveSSE2)
             return false;
 
         // the first iteration
-        memset(sum, 0, (size.width + 1) * sizeof(int));
+        memset(sum, 0, (width + 1) * sizeof(int));
 
         __m128i v_zero = _mm_setzero_si128(), prev = v_zero;
         int j = 0;
 
         // the others
-        for (int i = 0; i < size.height; ++i)
+        for (int i = 0; i < height; ++i)
         {
             const uchar * src_row = src + _srcstep * i;
             int * prev_sum_row = (int *)((uchar *)sum + _sumstep * i) + 1;
@@ -97,7 +97,7 @@ struct Integral_SIMD<uchar, int, double>
             prev = v_zero;
             j = 0;
 
-            for ( ; j + 7 < size.width; j += 8)
+            for ( ; j + 7 < width; j += 8)
             {
                 __m128i vsuml = _mm_loadu_si128((const __m128i *)(prev_sum_row + j));
                 __m128i vsumh = _mm_loadu_si128((const __m128i *)(prev_sum_row + j + 4));
@@ -128,7 +128,7 @@ struct Integral_SIMD<uchar, int, double>
                 prev = _mm_add_epi32(prev, _mm_shuffle_epi32(el4h, _MM_SHUFFLE(3, 3, 3, 3)));
             }
 
-            for (int v = sum_row[j - 1] - prev_sum_row[j - 1]; j < size.width; ++j)
+            for (int v = sum_row[j - 1] - prev_sum_row[j - 1]; j < width; ++j)
                 sum_row[j] = (v += src_row[j]) + prev_sum_row[j];
         }
 
@@ -143,7 +143,7 @@ struct Integral_SIMD<uchar, int, double>
 template<typename T, typename ST, typename QT>
 void integral_( const T* src, size_t _srcstep, ST* sum, size_t _sumstep,
                 QT* sqsum, size_t _sqsumstep, ST* tilted, size_t _tiltedstep,
-                Size size, int cn )
+                int width, int height, int cn )
 {
     int x, y, k;
 
@@ -151,7 +151,7 @@ void integral_( const T* src, size_t _srcstep, ST* sum, size_t _sumstep,
                                    sum, _sumstep,
                                    sqsum, _sqsumstep,
                                    tilted, _tiltedstep,
-                                   size, cn))
+                                   width, height, cn))
         return;
 
     int srcstep = (int)(_srcstep/sizeof(T));
@@ -159,31 +159,31 @@ void integral_( const T* src, size_t _srcstep, ST* sum, size_t _sumstep,
     int tiltedstep = (int)(_tiltedstep/sizeof(ST));
     int sqsumstep = (int)(_sqsumstep/sizeof(QT));
 
-    size.width *= cn;
+    width *= cn;
 
-    memset( sum, 0, (size.width+cn)*sizeof(sum[0]));
+    memset( sum, 0, (width+cn)*sizeof(sum[0]));
     sum += sumstep + cn;
 
     if( sqsum )
     {
-        memset( sqsum, 0, (size.width+cn)*sizeof(sqsum[0]));
+        memset( sqsum, 0, (width+cn)*sizeof(sqsum[0]));
         sqsum += sqsumstep + cn;
     }
 
     if( tilted )
     {
-        memset( tilted, 0, (size.width+cn)*sizeof(tilted[0]));
+        memset( tilted, 0, (width+cn)*sizeof(tilted[0]));
         tilted += tiltedstep + cn;
     }
 
     if( sqsum == 0 && tilted == 0 )
     {
-        for( y = 0; y < size.height; y++, src += srcstep - cn, sum += sumstep - cn )
+        for( y = 0; y < height; y++, src += srcstep - cn, sum += sumstep - cn )
         {
             for( k = 0; k < cn; k++, src++, sum++ )
             {
                 ST s = sum[-cn] = 0;
-                for( x = 0; x < size.width; x += cn )
+                for( x = 0; x < width; x += cn )
                 {
                     s += src[x];
                     sum[x] = sum[x - sumstep] + s;
@@ -193,14 +193,14 @@ void integral_( const T* src, size_t _srcstep, ST* sum, size_t _sumstep,
     }
     else if( tilted == 0 )
     {
-        for( y = 0; y < size.height; y++, src += srcstep - cn,
+        for( y = 0; y < height; y++, src += srcstep - cn,
                         sum += sumstep - cn, sqsum += sqsumstep - cn )
         {
             for( k = 0; k < cn; k++, src++, sum++, sqsum++ )
             {
                 ST s = sum[-cn] = 0;
                 QT sq = sqsum[-cn] = 0;
-                for( x = 0; x < size.width; x += cn )
+                for( x = 0; x < width; x += cn )
                 {
                     T it = src[x];
                     s += it;
@@ -215,7 +215,7 @@ void integral_( const T* src, size_t _srcstep, ST* sum, size_t _sumstep,
     }
     else
     {
-        AutoBuffer<ST> _buf(size.width+cn);
+        AutoBuffer<ST> _buf(width+cn);
         ST* buf = _buf;
         ST s;
         QT sq;
@@ -223,7 +223,7 @@ void integral_( const T* src, size_t _srcstep, ST* sum, size_t _sumstep,
         {
             sum[-cn] = tilted[-cn] = 0;
 
-            for( x = 0, s = 0, sq = 0; x < size.width; x += cn )
+            for( x = 0, s = 0, sq = 0; x < width; x += cn )
             {
                 T it = src[x];
                 buf[x] = tilted[x] = it;
@@ -234,7 +234,7 @@ void integral_( const T* src, size_t _srcstep, ST* sum, size_t _sumstep,
                     sqsum[x] = sq;
             }
 
-            if( size.width == cn )
+            if( width == cn )
                 buf[cn] = 0;
 
             if( sqsum )
@@ -244,7 +244,7 @@ void integral_( const T* src, size_t _srcstep, ST* sum, size_t _sumstep,
             }
         }
 
-        for( y = 1; y < size.height; y++ )
+        for( y = 1; y < height; y++ )
         {
             src += srcstep - cn;
             sum += sumstep - cn;
@@ -270,7 +270,7 @@ void integral_( const T* src, size_t _srcstep, ST* sum, size_t _sumstep,
                     sqsum[0] = sqsum[-sqsumstep] + tq0;
                 tilted[0] = tilted[-tiltedstep] + t0 + buf[cn];
 
-                for( x = cn; x < size.width - cn; x += cn )
+                for( x = cn; x < width - cn; x += cn )
                 {
                     ST t1 = buf[x];
                     buf[x - cn] = t1 + t0;
@@ -285,7 +285,7 @@ void integral_( const T* src, size_t _srcstep, ST* sum, size_t _sumstep,
                     tilted[x] = t1;
                 }
 
-                if( size.width > cn )
+                if( width > cn )
                 {
                     ST t1 = buf[x];
                     buf[x - cn] = t1 + t0;
@@ -308,29 +308,6 @@ void integral_( const T* src, size_t _srcstep, ST* sum, size_t _sumstep,
 }
 
 
-#define DEF_INTEGRAL_FUNC(suffix, T, ST, QT) \
-static void integral_##suffix( T* src, size_t srcstep, ST* sum, size_t sumstep, QT* sqsum, size_t sqsumstep, \
-                              ST* tilted, size_t tiltedstep, Size size, int cn ) \
-{ integral_(src, srcstep, sum, sumstep, sqsum, sqsumstep, tilted, tiltedstep, size, cn); }
-
-DEF_INTEGRAL_FUNC(8u32s, uchar, int, double)
-DEF_INTEGRAL_FUNC(8u32s32s, uchar, int, int)
-DEF_INTEGRAL_FUNC(8u32f64f, uchar, float, double)
-DEF_INTEGRAL_FUNC(8u64f64f, uchar, double, double)
-DEF_INTEGRAL_FUNC(16u64f64f, ushort, double, double)
-DEF_INTEGRAL_FUNC(16s64f64f, short, double, double)
-DEF_INTEGRAL_FUNC(32f32f64f, float, float, double)
-DEF_INTEGRAL_FUNC(32f64f64f, float, double, double)
-DEF_INTEGRAL_FUNC(64f64f64f, double, double, double)
-
-DEF_INTEGRAL_FUNC(8u32s32f, uchar, int, float)
-DEF_INTEGRAL_FUNC(8u32f32f, uchar, float, float)
-DEF_INTEGRAL_FUNC(32f32f32f, float, float, float)
-
-typedef void (*IntegralFunc)(const uchar* src, size_t srcstep, uchar* sum, size_t sumstep,
-                             uchar* sqsum, size_t sqsumstep, uchar* tilted, size_t tstep,
-                             Size size, int cn );
-
 #ifdef HAVE_OPENCL
 
 static bool ocl_integral( InputArray _src, OutputArray _sum, int sdepth )
@@ -423,51 +400,46 @@ static bool ocl_integral( InputArray _src, OutputArray _sum, OutputArray _sqsum,
 #if defined(HAVE_IPP)
 namespace cv
 {
-static bool ipp_integral(InputArray _src, OutputArray _sum, OutputArray _sqsum, OutputArray _tilted, int sdepth, int sqdepth)
+static bool ipp_integral(
+    int depth, int sdepth, int sqdepth,
+    const uchar* src, size_t srcstep,
+    uchar* sum, size_t sumstep,
+    uchar* sqsum, size_t sqsumstep,
+    int width, int height, int cn)
 {
-#if !defined(HAVE_IPP_ICV_ONLY) && (IPP_VERSION_X100 != 900) // Disabled on ICV due invalid results
-    int type = _src.type(), depth = CV_MAT_DEPTH(type), cn = CV_MAT_CN(type);
+    CV_INSTRUMENT_REGION_IPP()
+
+#if IPP_VERSION_X100 != 900 // Disabled on ICV due invalid results
     if( sdepth <= 0 )
         sdepth = depth == CV_8U ? CV_32S : CV_64F;
     if ( sqdepth <= 0 )
          sqdepth = CV_64F;
     sdepth = CV_MAT_DEPTH(sdepth), sqdepth = CV_MAT_DEPTH(sqdepth);
 
-
-    Size ssize = _src.size(), isize(ssize.width + 1, ssize.height + 1);
-    _sum.create( isize, CV_MAKETYPE(sdepth, cn) );
-    Mat src = _src.getMat(), sum =_sum.getMat(), sqsum, tilted;
-
-    if( _sqsum.needed() )
-    {
-        _sqsum.create( isize, CV_MAKETYPE(sqdepth, cn) );
-        sqsum = _sqsum.getMat();
-    };
-
-    if( ( depth == CV_8U ) && ( sdepth == CV_32F || sdepth == CV_32S ) && ( !_tilted.needed() ) && ( !_sqsum.needed() || sqdepth == CV_64F ) && ( cn == 1 ) )
+    if( ( depth == CV_8U ) && ( sdepth == CV_32F || sdepth == CV_32S ) && ( !sqsum || sqdepth == CV_64F ) && ( cn == 1 ) )
     {
         IppStatus status = ippStsErr;
-        IppiSize srcRoiSize = ippiSize( src.cols, src.rows );
+        IppiSize srcRoiSize = ippiSize( width, height );
         if( sdepth == CV_32F )
         {
-            if( _sqsum.needed() )
+            if( sqsum )
             {
-                status = ippiSqrIntegral_8u32f64f_C1R( (const Ipp8u*)src.data, (int)src.step, (Ipp32f*)sum.data, (int)sum.step, (Ipp64f*)sqsum.data, (int)sqsum.step, srcRoiSize, 0, 0 );
+                status = CV_INSTRUMENT_FUN_IPP(ippiSqrIntegral_8u32f64f_C1R, (const Ipp8u*)src, (int)srcstep, (Ipp32f*)sum, (int)sumstep, (Ipp64f*)sqsum, (int)sqsumstep, srcRoiSize, 0, 0);
             }
             else
             {
-                status = ippiIntegral_8u32f_C1R( (const Ipp8u*)src.data, (int)src.step, (Ipp32f*)sum.data, (int)sum.step, srcRoiSize, 0 );
+                status = CV_INSTRUMENT_FUN_IPP(ippiIntegral_8u32f_C1R, (const Ipp8u*)src, (int)srcstep, (Ipp32f*)sum, (int)sumstep, srcRoiSize, 0);
             }
         }
         else if( sdepth == CV_32S )
         {
-            if( _sqsum.needed() )
+            if( sqsum )
             {
-                status = ippiSqrIntegral_8u32s64f_C1R( (const Ipp8u*)src.data, (int)src.step, (Ipp32s*)sum.data, (int)sum.step, (Ipp64f*)sqsum.data, (int)sqsum.step, srcRoiSize, 0, 0 );
+                status = CV_INSTRUMENT_FUN_IPP(ippiSqrIntegral_8u32s64f_C1R, (const Ipp8u*)src, (int)srcstep, (Ipp32s*)sum, (int)sumstep, (Ipp64f*)sqsum, (int)sqsumstep, srcRoiSize, 0, 0);
             }
             else
             {
-                status = ippiIntegral_8u32s_C1R( (const Ipp8u*)src.data, (int)src.step, (Ipp32s*)sum.data, (int)sum.step, srcRoiSize, 0 );
+                status = CV_INSTRUMENT_FUN_IPP(ippiIntegral_8u32s_C1R, (const Ipp8u*)src, (int)srcstep, (Ipp32s*)sum, (int)sumstep, srcRoiSize, 0);
             }
         }
         if (0 <= status)
@@ -477,15 +449,73 @@ static bool ipp_integral(InputArray _src, OutputArray _sum, OutputArray _sqsum,
         }
     }
 #else
-    CV_UNUSED(_src); CV_UNUSED(_sum); CV_UNUSED(_sqsum); CV_UNUSED(_tilted); CV_UNUSED(sdepth); CV_UNUSED(sqdepth);
+    CV_UNUSED(depth); CV_UNUSED(sdepth); CV_UNUSED(sqdepth);
+    CV_UNUSED(src); CV_UNUSED(srcstep);
+    CV_UNUSED(sum); CV_UNUSED(sumstep);
+    CV_UNUSED(sqsum); CV_UNUSED(sqsumstep);
+    CV_UNUSED(tilted); CV_UNUSED(tstep);
+    CV_UNUSED(width); CV_UNUSED(height); CV_UNUSED(cn);
 #endif
     return false;
 }
 }
 #endif
 
+namespace cv { namespace hal {
+
+void integral(int depth, int sdepth, int sqdepth,
+              const uchar* src, size_t srcstep,
+              uchar* sum, size_t sumstep,
+              uchar* sqsum, size_t sqsumstep,
+              uchar* tilted, size_t tstep,
+              int width, int height, int cn)
+{
+    CALL_HAL(integral, cv_hal_integral, depth, sdepth, sqdepth, src, srcstep, sum, sumstep, sqsum, sqsumstep, tilted, tstep, width, height, cn);
+    CV_IPP_RUN(( depth == CV_8U )
+               && ( sdepth == CV_32F || sdepth == CV_32S )
+               && ( !tilted )
+               && ( !sqsum || sqdepth == CV_64F )
+               && ( cn == 1 ),
+               ipp_integral(depth, sdepth, sqdepth, src, srcstep, sum, sumstep, sqsum, sqsumstep, width, height, cn));
+
+#define ONE_CALL(A, B, C) integral_<A, B, C>((const A*)src, srcstep, (B*)sum, sumstep, (C*)sqsum, sqsumstep, (B*)tilted, tstep, width, height, cn)
+
+    if( depth == CV_8U && sdepth == CV_32S && sqdepth == CV_64F )
+        ONE_CALL(uchar, int, double);
+    else if( depth == CV_8U && sdepth == CV_32S && sqdepth == CV_32F )
+        ONE_CALL(uchar, int, float);
+    else if( depth == CV_8U && sdepth == CV_32S && sqdepth == CV_32S )
+        ONE_CALL(uchar, int, int);
+    else if( depth == CV_8U && sdepth == CV_32F && sqdepth == CV_64F )
+        ONE_CALL(uchar, float, double);
+    else if( depth == CV_8U && sdepth == CV_32F && sqdepth == CV_32F )
+        ONE_CALL(uchar, float, float);
+    else if( depth == CV_8U && sdepth == CV_64F && sqdepth == CV_64F )
+        ONE_CALL(uchar, double, double);
+    else if( depth == CV_16U && sdepth == CV_64F && sqdepth == CV_64F )
+        ONE_CALL(ushort, double, double);
+    else if( depth == CV_16S && sdepth == CV_64F && sqdepth == CV_64F )
+        ONE_CALL(short, double, double);
+    else if( depth == CV_32F && sdepth == CV_32F && sqdepth == CV_64F )
+        ONE_CALL(float, float, double);
+    else if( depth == CV_32F && sdepth == CV_32F && sqdepth == CV_32F )
+        ONE_CALL(float, float, float);
+    else if( depth == CV_32F && sdepth == CV_64F && sqdepth == CV_64F )
+        ONE_CALL(float, double, double);
+    else if( depth == CV_64F && sdepth == CV_64F && sqdepth == CV_64F )
+        ONE_CALL(double, double, double);
+    else
+        CV_Error( CV_StsUnsupportedFormat, "" );
+
+#undef ONE_CALL
+}
+
+}} // cv::hal::
+
 void cv::integral( InputArray _src, OutputArray _sum, OutputArray _sqsum, OutputArray _tilted, int sdepth, int sqdepth )
 {
+    CV_INSTRUMENT_REGION()
+
     int type = _src.type(), depth = CV_MAT_DEPTH(type), cn = CV_MAT_CN(type);
     if( sdepth <= 0 )
         sdepth = depth == CV_8U ? CV_32S : CV_64F;
@@ -515,55 +545,31 @@ void cv::integral( InputArray _src, OutputArray _sum, OutputArray _sqsum, Output
         sqsum = _sqsum.getMat();
     };
 
-    CV_IPP_RUN(( depth == CV_8U ) && ( sdepth == CV_32F || sdepth == CV_32S ) &&
-        ( !_tilted.needed() ) && ( !_sqsum.needed() || sqdepth == CV_64F ) && ( cn == 1 ),
-        ipp_integral(_src, _sum, _sqsum, _tilted, sdepth, sqdepth));
-
     if( _tilted.needed() )
     {
         _tilted.create( isize, CV_MAKETYPE(sdepth, cn) );
         tilted = _tilted.getMat();
     }
 
-    IntegralFunc func = 0;
-    if( depth == CV_8U && sdepth == CV_32S && sqdepth == CV_64F )
-        func = (IntegralFunc)GET_OPTIMIZED(integral_8u32s);
-    else if( depth == CV_8U && sdepth == CV_32S && sqdepth == CV_32F )
-        func = (IntegralFunc)integral_8u32s32f;
-    else if( depth == CV_8U && sdepth == CV_32S && sqdepth == CV_32S )
-        func = (IntegralFunc)integral_8u32s32s;
-    else if( depth == CV_8U && sdepth == CV_32F && sqdepth == CV_64F )
-        func = (IntegralFunc)integral_8u32f64f;
-    else if( depth == CV_8U && sdepth == CV_32F && sqdepth == CV_32F )
-        func = (IntegralFunc)integral_8u32f32f;
-    else if( depth == CV_8U && sdepth == CV_64F && sqdepth == CV_64F )
-        func = (IntegralFunc)integral_8u64f64f;
-    else if( depth == CV_16U && sdepth == CV_64F && sqdepth == CV_64F )
-        func = (IntegralFunc)integral_16u64f64f;
-    else if( depth == CV_16S && sdepth == CV_64F && sqdepth == CV_64F )
-        func = (IntegralFunc)integral_16s64f64f;
-    else if( depth == CV_32F && sdepth == CV_32F && sqdepth == CV_64F )
-        func = (IntegralFunc)integral_32f32f64f;
-    else if( depth == CV_32F && sdepth == CV_32F && sqdepth == CV_32F )
-        func = (IntegralFunc)integral_32f32f32f;
-    else if( depth == CV_32F && sdepth == CV_64F && sqdepth == CV_64F )
-        func = (IntegralFunc)integral_32f64f64f;
-    else if( depth == CV_64F && sdepth == CV_64F && sqdepth == CV_64F )
-        func = (IntegralFunc)integral_64f64f64f;
-    else
-        CV_Error( CV_StsUnsupportedFormat, "" );
-
-    func( src.ptr(), src.step, sum.ptr(), sum.step, sqsum.ptr(), sqsum.step,
-          tilted.ptr(), tilted.step, src.size(), cn );
+    hal::integral(depth, sdepth, sqdepth,
+                  src.ptr(), src.step,
+                  sum.ptr(), sum.step,
+                  sqsum.ptr(), sqsum.step,
+                  tilted.ptr(), tilted.step,
+                  src.cols, src.rows, cn);
 }
 
 void cv::integral( InputArray src, OutputArray sum, int sdepth )
 {
+    CV_INSTRUMENT_REGION()
+
     integral( src, sum, noArray(), noArray(), sdepth );
 }
 
 void cv::integral( InputArray src, OutputArray sum, OutputArray sqsum, int sdepth, int sqdepth )
 {
+    CV_INSTRUMENT_REGION()
+
     integral( src, sum, sqsum, noArray(), sdepth, sqdepth );
 }
 
diff --git a/modules/imgproc/src/templmatch.cpp b/modules/imgproc/src/templmatch.cpp
index 59b0703..5bae692 100644
--- a/modules/imgproc/src/templmatch.cpp
+++ b/modules/imgproc/src/templmatch.cpp
@@ -566,6 +566,8 @@ typedef IppStatus (CV_STDCALL * ippimatchTemplate)(const void*, int, IppiSize, c
 
 static bool ipp_crossCorr(const Mat& src, const Mat& tpl, Mat& dst)
 {
+    CV_INSTRUMENT_REGION_IPP()
+
     IppStatus status;
 
     IppiSize srcRoiSize = {src.cols,src.rows};
@@ -576,11 +578,11 @@ static bool ipp_crossCorr(const Mat& src, const Mat& tpl, Mat& dst)
 
     int depth = src.depth();
 
-    ippimatchTemplate ippFunc =
+    ippimatchTemplate ippiCrossCorrNorm =
             depth==CV_8U ? (ippimatchTemplate)ippiCrossCorrNorm_8u32f_C1R:
             depth==CV_32F? (ippimatchTemplate)ippiCrossCorrNorm_32f_C1R: 0;
 
-    if (ippFunc==0)
+    if (ippiCrossCorrNorm==0)
         return false;
 
     IppEnum funCfg = (IppEnum)(ippAlgAuto | ippiNormNone | ippiROIValid);
@@ -591,7 +593,7 @@ static bool ipp_crossCorr(const Mat& src, const Mat& tpl, Mat& dst)
 
     pBuffer = ippsMalloc_8u( bufSize );
 
-    status = ippFunc(src.ptr(), (int)src.step, srcRoiSize, tpl.ptr(), (int)tpl.step, tplRoiSize, dst.ptr<Ipp32f>(), (int)dst.step, funCfg, pBuffer);
+    status = CV_INSTRUMENT_FUN_IPP(ippiCrossCorrNorm, src.ptr(), (int)src.step, srcRoiSize, tpl.ptr(), (int)tpl.step, tplRoiSize, dst.ptr<Ipp32f>(), (int)dst.step, funCfg, pBuffer);
 
     ippsFree( pBuffer );
     return status >= 0;
@@ -599,6 +601,8 @@ static bool ipp_crossCorr(const Mat& src, const Mat& tpl, Mat& dst)
 
 static bool ipp_sqrDistance(const Mat& src, const Mat& tpl, Mat& dst)
 {
+    CV_INSTRUMENT_REGION_IPP()
+
     IppStatus status;
 
     IppiSize srcRoiSize = {src.cols,src.rows};
@@ -609,11 +613,11 @@ static bool ipp_sqrDistance(const Mat& src, const Mat& tpl, Mat& dst)
 
     int depth = src.depth();
 
-    ippimatchTemplate ippFunc =
+    ippimatchTemplate ippiSqrDistanceNorm =
             depth==CV_8U ? (ippimatchTemplate)ippiSqrDistanceNorm_8u32f_C1R:
             depth==CV_32F? (ippimatchTemplate)ippiSqrDistanceNorm_32f_C1R: 0;
 
-    if (ippFunc==0)
+    if (ippiSqrDistanceNorm==0)
         return false;
 
     IppEnum funCfg = (IppEnum)(ippAlgAuto | ippiNormNone | ippiROIValid);
@@ -624,7 +628,7 @@ static bool ipp_sqrDistance(const Mat& src, const Mat& tpl, Mat& dst)
 
     pBuffer = ippsMalloc_8u( bufSize );
 
-    status = ippFunc(src.ptr(), (int)src.step, srcRoiSize, tpl.ptr(), (int)tpl.step, tplRoiSize, dst.ptr<Ipp32f>(), (int)dst.step, funCfg, pBuffer);
+    status = CV_INSTRUMENT_FUN_IPP(ippiSqrDistanceNorm, src.ptr(), (int)src.step, srcRoiSize, tpl.ptr(), (int)tpl.step, tplRoiSize, dst.ptr<Ipp32f>(), (int)dst.step, funCfg, pBuffer);
 
     ippsFree( pBuffer );
     return status >= 0;
@@ -632,6 +636,8 @@ static bool ipp_sqrDistance(const Mat& src, const Mat& tpl, Mat& dst)
 
 #endif
 
+#include "opencv2/core/hal/hal.hpp"
+
 void crossCorr( const Mat& img, const Mat& _templ, Mat& corr,
                 Size corrsize, int ctype,
                 Point anchor, double delta, int borderType )
@@ -698,6 +704,8 @@ void crossCorr( const Mat& img, const Mat& _templ, Mat& corr,
 
     buf.resize(bufSize);
 
+    Ptr<hal::DFT2D> c = hal::DFT2D::create(dftsize.width, dftsize.height, dftTempl.depth(), 1, 1, CV_HAL_DFT_IS_INPLACE, templ.rows);
+
     // compute DFT of each template plane
     for( k = 0; k < tcn; k++ )
     {
@@ -721,7 +729,7 @@ void crossCorr( const Mat& img, const Mat& _templ, Mat& corr,
             Mat part(dst, Range(0, templ.rows), Range(templ.cols, dst.cols));
             part = Scalar::all(0);
         }
-        dft(dst, dst, 0, templ.rows);
+        c->apply(dst.data, (int)dst.step, dst.data, (int)dst.step);
     }
 
     int tileCountX = (corr.cols + blocksize.width - 1)/blocksize.width;
@@ -740,6 +748,12 @@ void crossCorr( const Mat& img, const Mat& _templ, Mat& corr,
     }
     borderType |= BORDER_ISOLATED;
 
+    Ptr<hal::DFT2D> cF, cR;
+    int f = CV_HAL_DFT_IS_INPLACE;
+    int f_inv = f | CV_HAL_DFT_INVERSE | CV_HAL_DFT_SCALE;
+    cF = hal::DFT2D::create(dftsize.width, dftsize.height, maxDepth, 1, 1, f, blocksize.height + templ.rows - 1);
+    cR = hal::DFT2D::create(dftsize.width, dftsize.height, maxDepth, 1, 1, f_inv, blocksize.height);
+
     // calculate correlation by blocks
     for( i = 0; i < tileCount; i++ )
     {
@@ -777,11 +791,19 @@ void crossCorr( const Mat& img, const Mat& _templ, Mat& corr,
                 copyMakeBorder(dst1, dst, y1-y0, dst.rows-dst1.rows-(y1-y0),
                                x1-x0, dst.cols-dst1.cols-(x1-x0), borderType);
 
-            dft( dftImg, dftImg, 0, dsz.height );
+            if (bsz.height == blocksize.height)
+                cF->apply(dftImg.data, (int)dftImg.step, dftImg.data, (int)dftImg.step);
+            else
+                dft( dftImg, dftImg, 0, dsz.height );
+
             Mat dftTempl1(dftTempl, Rect(0, tcn > 1 ? k*dftsize.height : 0,
                                          dftsize.width, dftsize.height));
             mulSpectrums(dftImg, dftTempl1, dftImg, 0, true);
-            dft( dftImg, dftImg, DFT_INVERSE + DFT_SCALE, bsz.height );
+
+            if (bsz.height == blocksize.height)
+                cR->apply(dftImg.data, (int)dftImg.step, dftImg.data, (int)dftImg.step);
+            else
+                dft( dftImg, dftImg, DFT_INVERSE + DFT_SCALE, bsz.height );
 
             src = dftImg(Rect(0, 0, bsz.width, bsz.height));
 
@@ -1023,6 +1045,8 @@ namespace cv
 {
 static bool ipp_matchTemplate( Mat& img, Mat& templ, Mat& result, int method, int cn )
 {
+    CV_INSTRUMENT_REGION_IPP()
+
     bool useIppMT = (templ.rows < img.rows/2 && templ.cols < img.cols/2);
 
     if(cn == 1 && useIppMT)
@@ -1051,6 +1075,8 @@ static bool ipp_matchTemplate( Mat& img, Mat& templ, Mat& result, int method, in
 
 void cv::matchTemplate( InputArray _img, InputArray _templ, OutputArray _result, int method, InputArray _mask )
 {
+    CV_INSTRUMENT_REGION()
+
     if (!_mask.empty())
     {
         cv::matchTemplateMask(_img, _templ, _result, method, _mask);
diff --git a/modules/imgproc/src/thresh.cpp b/modules/imgproc/src/thresh.cpp
index 0b61347..f4f3297 100644
--- a/modules/imgproc/src/thresh.cpp
+++ b/modules/imgproc/src/thresh.cpp
@@ -42,6 +42,9 @@
 
 #include "precomp.hpp"
 #include "opencl_kernels_imgproc.hpp"
+#include "opencv2/core/hal/intrin.hpp"
+
+#include "opencv2/core/openvx/ovx_defs.hpp"
 
 namespace cv
 {
@@ -49,8 +52,6 @@ namespace cv
 static void
 thresh_8u( const Mat& _src, Mat& _dst, uchar thresh, uchar maxval, int type )
 {
-    int i, j, j_scalar = 0;
-    uchar tab[256];
     Size roi = _src.size();
     roi.width *= _src.channels();
     size_t src_step = _src.step;
@@ -76,14 +77,12 @@ thresh_8u( const Mat& _src, Mat& _dst, uchar thresh, uchar maxval, int type )
         switch( type )
         {
         case THRESH_TRUNC:
-#ifndef HAVE_IPP_ICV_ONLY
-            if (_src.data == _dst.data && ippiThreshold_GT_8u_C1IR(_dst.ptr(), (int)dst_step, sz, thresh) >= 0)
+            if (_src.data == _dst.data && CV_INSTRUMENT_FUN_IPP(ippiThreshold_GT_8u_C1IR, _dst.ptr(), (int)dst_step, sz, thresh) >= 0)
             {
                 CV_IMPL_ADD(CV_IMPL_IPP);
                 return;
             }
-#endif
-            if (ippiThreshold_GT_8u_C1R(_src.ptr(), (int)src_step, _dst.ptr(), (int)dst_step, sz, thresh) >= 0)
+            if (CV_INSTRUMENT_FUN_IPP(ippiThreshold_GT_8u_C1R, _src.ptr(), (int)src_step, _dst.ptr(), (int)dst_step, sz, thresh) >= 0)
             {
                 CV_IMPL_ADD(CV_IMPL_IPP);
                 return;
@@ -91,14 +90,12 @@ thresh_8u( const Mat& _src, Mat& _dst, uchar thresh, uchar maxval, int type )
             setIppErrorStatus();
             break;
         case THRESH_TOZERO:
-#ifndef HAVE_IPP_ICV_ONLY
-            if (_src.data == _dst.data && ippiThreshold_LTVal_8u_C1IR(_dst.ptr(), (int)dst_step, sz, thresh+1, 0) >= 0)
+            if (_src.data == _dst.data && CV_INSTRUMENT_FUN_IPP(ippiThreshold_LTVal_8u_C1IR, _dst.ptr(), (int)dst_step, sz, thresh+1, 0) >= 0)
             {
                 CV_IMPL_ADD(CV_IMPL_IPP);
                 return;
             }
-#endif
-            if (ippiThreshold_LTVal_8u_C1R(_src.ptr(), (int)src_step, _dst.ptr(), (int)dst_step, sz, thresh+1, 0) >= 0)
+            if (CV_INSTRUMENT_FUN_IPP(ippiThreshold_LTVal_8u_C1R, _src.ptr(), (int)src_step, _dst.ptr(), (int)dst_step, sz, thresh + 1, 0) >= 0)
             {
                 CV_IMPL_ADD(CV_IMPL_IPP);
                 return;
@@ -106,14 +103,12 @@ thresh_8u( const Mat& _src, Mat& _dst, uchar thresh, uchar maxval, int type )
             setIppErrorStatus();
             break;
         case THRESH_TOZERO_INV:
-#ifndef HAVE_IPP_ICV_ONLY
-            if (_src.data == _dst.data && ippiThreshold_GTVal_8u_C1IR(_dst.ptr(), (int)dst_step, sz, thresh, 0) >= 0)
+            if (_src.data == _dst.data && CV_INSTRUMENT_FUN_IPP(ippiThreshold_GTVal_8u_C1IR, _dst.ptr(), (int)dst_step, sz, thresh, 0) >= 0)
             {
                 CV_IMPL_ADD(CV_IMPL_IPP);
                 return;
             }
-#endif
-            if (ippiThreshold_GTVal_8u_C1R(_src.ptr(), (int)src_step, _dst.ptr(), (int)dst_step, sz, thresh, 0) >= 0)
+            if (CV_INSTRUMENT_FUN_IPP(ippiThreshold_GTVal_8u_C1R, _src.ptr(), (int)src_step, _dst.ptr(), (int)dst_step, sz, thresh, 0) >= 0)
             {
                 CV_IMPL_ADD(CV_IMPL_IPP);
                 return;
@@ -125,242 +120,132 @@ thresh_8u( const Mat& _src, Mat& _dst, uchar thresh, uchar maxval, int type )
     }
 #endif
 
-    switch( type )
-    {
-    case THRESH_BINARY:
-        for( i = 0; i <= thresh; i++ )
-            tab[i] = 0;
-        for( ; i < 256; i++ )
-            tab[i] = maxval;
-        break;
-    case THRESH_BINARY_INV:
-        for( i = 0; i <= thresh; i++ )
-            tab[i] = maxval;
-        for( ; i < 256; i++ )
-            tab[i] = 0;
-        break;
-    case THRESH_TRUNC:
-        for( i = 0; i <= thresh; i++ )
-            tab[i] = (uchar)i;
-        for( ; i < 256; i++ )
-            tab[i] = thresh;
-        break;
-    case THRESH_TOZERO:
-        for( i = 0; i <= thresh; i++ )
-            tab[i] = 0;
-        for( ; i < 256; i++ )
-            tab[i] = (uchar)i;
-        break;
-    case THRESH_TOZERO_INV:
-        for( i = 0; i <= thresh; i++ )
-            tab[i] = (uchar)i;
-        for( ; i < 256; i++ )
-            tab[i] = 0;
-        break;
-    default:
-        CV_Error( CV_StsBadArg, "Unknown threshold type" );
-    }
-
-#if CV_SSE2
-    if( checkHardwareSupport(CV_CPU_SSE2) )
+    int j = 0;
+    const uchar* src = _src.ptr();
+    uchar* dst = _dst.ptr();
+#if CV_SIMD128
+    bool useSIMD = checkHardwareSupport( CV_CPU_SSE2 ) || checkHardwareSupport( CV_CPU_NEON );
+    if( useSIMD )
     {
-        __m128i _x80 = _mm_set1_epi8('\x80');
-        __m128i thresh_u = _mm_set1_epi8(thresh);
-        __m128i thresh_s = _mm_set1_epi8(thresh ^ 0x80);
-        __m128i maxval_ = _mm_set1_epi8(maxval);
-        j_scalar = roi.width & -8;
+        v_uint8x16 thresh_u = v_setall_u8( thresh );
+        v_uint8x16 maxval16 = v_setall_u8( maxval );
 
-        for( i = 0; i < roi.height; i++ )
+        switch( type )
         {
-            const uchar* src = _src.ptr() + src_step*i;
-            uchar* dst = _dst.ptr() + dst_step*i;
-
-            switch( type )
+        case THRESH_BINARY:
+            for( int i = 0; i < roi.height; i++, src += src_step, dst += dst_step )
             {
-            case THRESH_BINARY:
-                for( j = 0; j <= roi.width - 32; j += 32 )
-                {
-                    __m128i v0, v1;
-                    v0 = _mm_loadu_si128( (const __m128i*)(src + j) );
-                    v1 = _mm_loadu_si128( (const __m128i*)(src + j + 16) );
-                    v0 = _mm_cmpgt_epi8( _mm_xor_si128(v0, _x80), thresh_s );
-                    v1 = _mm_cmpgt_epi8( _mm_xor_si128(v1, _x80), thresh_s );
-                    v0 = _mm_and_si128( v0, maxval_ );
-                    v1 = _mm_and_si128( v1, maxval_ );
-                    _mm_storeu_si128( (__m128i*)(dst + j), v0 );
-                    _mm_storeu_si128( (__m128i*)(dst + j + 16), v1 );
-                }
-
-                for( ; j <= roi.width - 8; j += 8 )
-                {
-                    __m128i v0 = _mm_loadl_epi64( (const __m128i*)(src + j) );
-                    v0 = _mm_cmpgt_epi8( _mm_xor_si128(v0, _x80), thresh_s );
-                    v0 = _mm_and_si128( v0, maxval_ );
-                    _mm_storel_epi64( (__m128i*)(dst + j), v0 );
-                }
-                break;
-
-            case THRESH_BINARY_INV:
-                for( j = 0; j <= roi.width - 32; j += 32 )
+                for( j = 0; j <= roi.width - 16; j += 16 )
                 {
-                    __m128i v0, v1;
-                    v0 = _mm_loadu_si128( (const __m128i*)(src + j) );
-                    v1 = _mm_loadu_si128( (const __m128i*)(src + j + 16) );
-                    v0 = _mm_cmpgt_epi8( _mm_xor_si128(v0, _x80), thresh_s );
-                    v1 = _mm_cmpgt_epi8( _mm_xor_si128(v1, _x80), thresh_s );
-                    v0 = _mm_andnot_si128( v0, maxval_ );
-                    v1 = _mm_andnot_si128( v1, maxval_ );
-                    _mm_storeu_si128( (__m128i*)(dst + j), v0 );
-                    _mm_storeu_si128( (__m128i*)(dst + j + 16), v1 );
+                    v_uint8x16 v0;
+                    v0 = v_load( src + j );
+                    v0 = thresh_u < v0;
+                    v0 = v0 & maxval16;
+                    v_store( dst + j, v0 );
                 }
+            }
+            break;
 
-                for( ; j <= roi.width - 8; j += 8 )
-                {
-                    __m128i v0 = _mm_loadl_epi64( (const __m128i*)(src + j) );
-                    v0 = _mm_cmpgt_epi8( _mm_xor_si128(v0, _x80), thresh_s );
-                    v0 = _mm_andnot_si128( v0, maxval_ );
-                    _mm_storel_epi64( (__m128i*)(dst + j), v0 );
-                }
-                break;
-
-            case THRESH_TRUNC:
-                for( j = 0; j <= roi.width - 32; j += 32 )
-                {
-                    __m128i v0, v1;
-                    v0 = _mm_loadu_si128( (const __m128i*)(src + j) );
-                    v1 = _mm_loadu_si128( (const __m128i*)(src + j + 16) );
-                    v0 = _mm_subs_epu8( v0, _mm_subs_epu8( v0, thresh_u ));
-                    v1 = _mm_subs_epu8( v1, _mm_subs_epu8( v1, thresh_u ));
-                    _mm_storeu_si128( (__m128i*)(dst + j), v0 );
-                    _mm_storeu_si128( (__m128i*)(dst + j + 16), v1 );
-                }
-
-                for( ; j <= roi.width - 8; j += 8 )
-                {
-                    __m128i v0 = _mm_loadl_epi64( (const __m128i*)(src + j) );
-                    v0 = _mm_subs_epu8( v0, _mm_subs_epu8( v0, thresh_u ));
-                    _mm_storel_epi64( (__m128i*)(dst + j), v0 );
-                }
-                break;
-
-            case THRESH_TOZERO:
-                for( j = 0; j <= roi.width - 32; j += 32 )
+        case THRESH_BINARY_INV:
+            for( int i = 0; i < roi.height; i++, src += src_step, dst += dst_step )
+            {
+                for( j = 0; j <= roi.width - 16; j += 16 )
                 {
-                    __m128i v0, v1;
-                    v0 = _mm_loadu_si128( (const __m128i*)(src + j) );
-                    v1 = _mm_loadu_si128( (const __m128i*)(src + j + 16) );
-                    v0 = _mm_and_si128( v0, _mm_cmpgt_epi8(_mm_xor_si128(v0, _x80), thresh_s ));
-                    v1 = _mm_and_si128( v1, _mm_cmpgt_epi8(_mm_xor_si128(v1, _x80), thresh_s ));
-                    _mm_storeu_si128( (__m128i*)(dst + j), v0 );
-                    _mm_storeu_si128( (__m128i*)(dst + j + 16), v1 );
+                    v_uint8x16 v0;
+                    v0 = v_load( src + j );
+                    v0 = v0 <= thresh_u;
+                    v0 = v0 & maxval16;
+                    v_store( dst + j, v0 );
                 }
+            }
+            break;
 
-                for( ; j <= roi.width - 8; j += 8 )
+        case THRESH_TRUNC:
+            for( int i = 0; i < roi.height; i++, src += src_step, dst += dst_step )
+            {
+                for( j = 0; j <= roi.width - 16; j += 16 )
                 {
-                    __m128i v0 = _mm_loadl_epi64( (const __m128i*)(src + j) );
-                    v0 = _mm_and_si128( v0, _mm_cmpgt_epi8(_mm_xor_si128(v0, _x80), thresh_s ));
-                    _mm_storel_epi64( (__m128i*)(dst + j), v0 );
+                    v_uint8x16 v0;
+                    v0 = v_load( src + j );
+                    v0 = v0 - ( v0 - thresh_u );
+                    v_store( dst + j, v0 );
                 }
-                break;
+            }
+            break;
 
-            case THRESH_TOZERO_INV:
-                for( j = 0; j <= roi.width - 32; j += 32 )
+        case THRESH_TOZERO:
+            for( int i = 0; i < roi.height; i++, src += src_step, dst += dst_step )
+            {
+                for( j = 0; j <= roi.width - 16; j += 16 )
                 {
-                    __m128i v0, v1;
-                    v0 = _mm_loadu_si128( (const __m128i*)(src + j) );
-                    v1 = _mm_loadu_si128( (const __m128i*)(src + j + 16) );
-                    v0 = _mm_andnot_si128( _mm_cmpgt_epi8(_mm_xor_si128(v0, _x80), thresh_s ), v0 );
-                    v1 = _mm_andnot_si128( _mm_cmpgt_epi8(_mm_xor_si128(v1, _x80), thresh_s ), v1 );
-                    _mm_storeu_si128( (__m128i*)(dst + j), v0 );
-                    _mm_storeu_si128( (__m128i*)(dst + j + 16), v1 );
+                    v_uint8x16 v0;
+                    v0 = v_load( src + j );
+                    v0 = ( thresh_u < v0 ) & v0;
+                    v_store( dst + j, v0 );
                 }
+            }
+            break;
 
-                for( ; j <= roi.width - 8; j += 8 )
+        case THRESH_TOZERO_INV:
+            for( int i = 0; i < roi.height; i++, src += src_step, dst += dst_step )
+            {
+                for( j = 0; j <= roi.width - 16; j += 16 )
                 {
-                    __m128i v0 = _mm_loadl_epi64( (const __m128i*)(src + j) );
-                    v0 = _mm_andnot_si128( _mm_cmpgt_epi8(_mm_xor_si128(v0, _x80), thresh_s ), v0 );
-                    _mm_storel_epi64( (__m128i*)(dst + j), v0 );
+                    v_uint8x16 v0;
+                    v0 = v_load( src + j );
+                    v0 = ( v0 <= thresh_u ) & v0;
+                    v_store( dst + j, v0 );
                 }
-                break;
             }
+            break;
         }
     }
-#elif CV_NEON
-    uint8x16_t v_thresh = vdupq_n_u8(thresh), v_maxval = vdupq_n_u8(maxval);
+#endif
 
-    switch( type )
+    int j_scalar = j;
+    if( j_scalar < roi.width )
     {
-    case THRESH_BINARY:
-        for( i = 0; i < roi.height; i++ )
-        {
-            const uchar* src = _src.ptr() + src_step*i;
-            uchar* dst = _dst.ptr() + dst_step*i;
-
-            for ( j_scalar = 0; j_scalar <= roi.width - 16; j_scalar += 16)
-                vst1q_u8(dst + j_scalar, vandq_u8(vcgtq_u8(vld1q_u8(src + j_scalar), v_thresh), v_maxval));
-        }
-        break;
-
-    case THRESH_BINARY_INV:
-        for( i = 0; i < roi.height; i++ )
-        {
-            const uchar* src = _src.ptr() + src_step*i;
-            uchar* dst = _dst.ptr() + dst_step*i;
-
-            for ( j_scalar = 0; j_scalar <= roi.width - 16; j_scalar += 16)
-                vst1q_u8(dst + j_scalar, vandq_u8(vcleq_u8(vld1q_u8(src + j_scalar), v_thresh), v_maxval));
-        }
-        break;
-
-    case THRESH_TRUNC:
-        for( i = 0; i < roi.height; i++ )
-        {
-            const uchar* src = _src.ptr() + src_step*i;
-            uchar* dst = _dst.ptr() + dst_step*i;
-
-            for ( j_scalar = 0; j_scalar <= roi.width - 16; j_scalar += 16)
-                vst1q_u8(dst + j_scalar, vminq_u8(vld1q_u8(src + j_scalar), v_thresh));
-        }
-        break;
-
-    case THRESH_TOZERO:
-        for( i = 0; i < roi.height; i++ )
+        const int thresh_pivot = thresh + 1;
+        uchar tab[256];
+        switch( type )
         {
-            const uchar* src = _src.ptr() + src_step*i;
-            uchar* dst = _dst.ptr() + dst_step*i;
-
-            for ( j_scalar = 0; j_scalar <= roi.width - 16; j_scalar += 16)
-            {
-                uint8x16_t v_src = vld1q_u8(src + j_scalar), v_mask = vcgtq_u8(v_src, v_thresh);
-                vst1q_u8(dst + j_scalar, vandq_u8(v_mask, v_src));
+        case THRESH_BINARY:
+            memset(tab, 0, thresh_pivot);
+            if (thresh_pivot < 256) {
+                memset(tab + thresh_pivot, maxval, 256 - thresh_pivot);
             }
-        }
-        break;
-
-    case THRESH_TOZERO_INV:
-        for( i = 0; i < roi.height; i++ )
-        {
-            const uchar* src = _src.ptr() + src_step*i;
-            uchar* dst = _dst.ptr() + dst_step*i;
-
-            for ( j_scalar = 0; j_scalar <= roi.width - 16; j_scalar += 16)
-            {
-                uint8x16_t v_src = vld1q_u8(src + j_scalar), v_mask = vcleq_u8(v_src, v_thresh);
-                vst1q_u8(dst + j_scalar, vandq_u8(v_mask, v_src));
+            break;
+        case THRESH_BINARY_INV:
+            memset(tab, maxval, thresh_pivot);
+            if (thresh_pivot < 256) {
+                memset(tab + thresh_pivot, 0, 256 - thresh_pivot);
             }
+            break;
+        case THRESH_TRUNC:
+            for( int i = 0; i <= thresh; i++ )
+                tab[i] = (uchar)i;
+            if (thresh_pivot < 256) {
+                memset(tab + thresh_pivot, thresh, 256 - thresh_pivot);
+            }
+            break;
+        case THRESH_TOZERO:
+            memset(tab, 0, thresh_pivot);
+            for( int i = thresh_pivot; i < 256; i++ )
+                tab[i] = (uchar)i;
+            break;
+        case THRESH_TOZERO_INV:
+            for( int i = 0; i <= thresh; i++ )
+                tab[i] = (uchar)i;
+            if (thresh_pivot < 256) {
+                memset(tab + thresh_pivot, 0, 256 - thresh_pivot);
+            }
+            break;
         }
-        break;
-    default:
-        return CV_Error( CV_StsBadArg, "" );
-    }
-#endif
 
-    if( j_scalar < roi.width )
-    {
-        for( i = 0; i < roi.height; i++ )
+        src = _src.ptr();
+        dst = _dst.ptr();
+        for( int i = 0; i < roi.height; i++, src += src_step, dst += dst_step )
         {
-            const uchar* src = _src.ptr() + src_step*i;
-            uchar* dst = _dst.ptr() + dst_step*i;
             j = j_scalar;
 #if CV_ENABLE_UNROLLED
             for( ; j <= roi.width - 4; j += 4 )
@@ -396,10 +281,6 @@ thresh_16s( const Mat& _src, Mat& _dst, short thresh, short maxval, int type )
     size_t src_step = _src.step/sizeof(src[0]);
     size_t dst_step = _dst.step/sizeof(dst[0]);
 
-#if CV_SSE2
-    volatile bool useSIMD = checkHardwareSupport(CV_CPU_SSE);
-#endif
-
     if( _src.isContinuous() && _dst.isContinuous() )
     {
         roi.width *= roi.height;
@@ -420,14 +301,12 @@ thresh_16s( const Mat& _src, Mat& _dst, short thresh, short maxval, int type )
         switch( type )
         {
         case THRESH_TRUNC:
-#ifndef HAVE_IPP_ICV_ONLY
-            if (_src.data == _dst.data && ippiThreshold_GT_16s_C1IR(dst, (int)dst_step*sizeof(dst[0]), sz, thresh) >= 0)
+            if (_src.data == _dst.data && CV_INSTRUMENT_FUN_IPP(ippiThreshold_GT_16s_C1IR, dst, (int)dst_step*sizeof(dst[0]), sz, thresh) >= 0)
             {
                 CV_IMPL_ADD(CV_IMPL_IPP);
                 return;
             }
-#endif
-            if (ippiThreshold_GT_16s_C1R(src, (int)src_step*sizeof(src[0]), dst, (int)dst_step*sizeof(dst[0]), sz, thresh) >= 0)
+            if (CV_INSTRUMENT_FUN_IPP(ippiThreshold_GT_16s_C1R, src, (int)src_step*sizeof(src[0]), dst, (int)dst_step*sizeof(dst[0]), sz, thresh) >= 0)
             {
                 CV_IMPL_ADD(CV_IMPL_IPP);
                 return;
@@ -435,14 +314,12 @@ thresh_16s( const Mat& _src, Mat& _dst, short thresh, short maxval, int type )
             setIppErrorStatus();
             break;
         case THRESH_TOZERO:
-#ifndef HAVE_IPP_ICV_ONLY
-            if (_src.data == _dst.data && ippiThreshold_LTVal_16s_C1IR(dst, (int)dst_step*sizeof(dst[0]), sz, thresh + 1, 0) >= 0)
+            if (_src.data == _dst.data && CV_INSTRUMENT_FUN_IPP(ippiThreshold_LTVal_16s_C1IR, dst, (int)dst_step*sizeof(dst[0]), sz, thresh + 1, 0) >= 0)
             {
                 CV_IMPL_ADD(CV_IMPL_IPP);
                 return;
             }
-#endif
-            if (ippiThreshold_LTVal_16s_C1R(src, (int)src_step*sizeof(src[0]), dst, (int)dst_step*sizeof(dst[0]), sz, thresh+1, 0) >= 0)
+            if (CV_INSTRUMENT_FUN_IPP(ippiThreshold_LTVal_16s_C1R, src, (int)src_step*sizeof(src[0]), dst, (int)dst_step*sizeof(dst[0]), sz, thresh + 1, 0) >= 0)
             {
                 CV_IMPL_ADD(CV_IMPL_IPP);
                 return;
@@ -450,14 +327,12 @@ thresh_16s( const Mat& _src, Mat& _dst, short thresh, short maxval, int type )
             setIppErrorStatus();
             break;
         case THRESH_TOZERO_INV:
-#ifndef HAVE_IPP_ICV_ONLY
-            if (_src.data == _dst.data && ippiThreshold_GTVal_16s_C1IR(dst, (int)dst_step*sizeof(dst[0]), sz, thresh, 0) >= 0)
+            if (_src.data == _dst.data && CV_INSTRUMENT_FUN_IPP(ippiThreshold_GTVal_16s_C1IR, dst, (int)dst_step*sizeof(dst[0]), sz, thresh, 0) >= 0)
             {
                 CV_IMPL_ADD(CV_IMPL_IPP);
                 return;
             }
-#endif
-            if (ippiThreshold_GTVal_16s_C1R(src, (int)src_step*sizeof(src[0]), dst, (int)dst_step*sizeof(dst[0]), sz, thresh, 0) >= 0)
+            if (CV_INSTRUMENT_FUN_IPP(ippiThreshold_GTVal_16s_C1R, src, (int)src_step*sizeof(src[0]), dst, (int)dst_step*sizeof(dst[0]), sz, thresh, 0) >= 0)
             {
                 CV_IMPL_ADD(CV_IMPL_IPP);
                 return;
@@ -469,187 +344,181 @@ thresh_16s( const Mat& _src, Mat& _dst, short thresh, short maxval, int type )
     }
 #endif
 
-    switch( type )
+#if CV_SIMD128
+    bool useSIMD = checkHardwareSupport( CV_CPU_SSE2 ) || checkHardwareSupport( CV_CPU_NEON );
+    if( useSIMD )
     {
-    case THRESH_BINARY:
-        for( i = 0; i < roi.height; i++, src += src_step, dst += dst_step )
+        v_int16x8 thresh8 = v_setall_s16( thresh );
+        v_int16x8 maxval8 = v_setall_s16( maxval );
+
+        switch( type )
         {
-            j = 0;
-        #if CV_SSE2
-            if( useSIMD )
+        case THRESH_BINARY:
+            for( i = 0; i < roi.height; i++, src += src_step, dst += dst_step )
             {
-                __m128i thresh8 = _mm_set1_epi16(thresh), maxval8 = _mm_set1_epi16(maxval);
+                j = 0;
                 for( ; j <= roi.width - 16; j += 16 )
                 {
-                    __m128i v0, v1;
-                    v0 = _mm_loadu_si128( (const __m128i*)(src + j) );
-                    v1 = _mm_loadu_si128( (const __m128i*)(src + j + 8) );
-                    v0 = _mm_cmpgt_epi16( v0, thresh8 );
-                    v1 = _mm_cmpgt_epi16( v1, thresh8 );
-                    v0 = _mm_and_si128( v0, maxval8 );
-                    v1 = _mm_and_si128( v1, maxval8 );
-                    _mm_storeu_si128((__m128i*)(dst + j), v0 );
-                    _mm_storeu_si128((__m128i*)(dst + j + 8), v1 );
+                    v_int16x8 v0, v1;
+                    v0 = v_load( src + j );
+                    v1 = v_load( src + j + 8 );
+                    v0 = thresh8 < v0;
+                    v1 = thresh8 < v1;
+                    v0 = v0 & maxval8;
+                    v1 = v1 & maxval8;
+                    v_store( dst + j, v0 );
+                    v_store( dst + j + 8, v1 );
                 }
-            }
-        #elif CV_NEON
-            int16x8_t v_thresh = vdupq_n_s16(thresh), v_maxval = vdupq_n_s16(maxval);
 
-            for( ; j <= roi.width - 8; j += 8 )
-            {
-                uint16x8_t v_mask = vcgtq_s16(vld1q_s16(src + j), v_thresh);
-                vst1q_s16(dst + j, vandq_s16(vreinterpretq_s16_u16(v_mask), v_maxval));
+                for( ; j < roi.width; j++ )
+                    dst[j] = src[j] > thresh ? maxval : 0;
             }
-        #endif
-
-            for( ; j < roi.width; j++ )
-                dst[j] = src[j] > thresh ? maxval : 0;
-        }
-        break;
+            break;
 
-    case THRESH_BINARY_INV:
-        for( i = 0; i < roi.height; i++, src += src_step, dst += dst_step )
-        {
-            j = 0;
-        #if CV_SSE2
-            if( useSIMD )
+        case THRESH_BINARY_INV:
+            for( i = 0; i < roi.height; i++, src += src_step, dst += dst_step )
             {
-                __m128i thresh8 = _mm_set1_epi16(thresh), maxval8 = _mm_set1_epi16(maxval);
+                j = 0;
                 for( ; j <= roi.width - 16; j += 16 )
                 {
-                    __m128i v0, v1;
-                    v0 = _mm_loadu_si128( (const __m128i*)(src + j) );
-                    v1 = _mm_loadu_si128( (const __m128i*)(src + j + 8) );
-                    v0 = _mm_cmpgt_epi16( v0, thresh8 );
-                    v1 = _mm_cmpgt_epi16( v1, thresh8 );
-                    v0 = _mm_andnot_si128( v0, maxval8 );
-                    v1 = _mm_andnot_si128( v1, maxval8 );
-                    _mm_storeu_si128((__m128i*)(dst + j), v0 );
-                    _mm_storeu_si128((__m128i*)(dst + j + 8), v1 );
+                    v_int16x8 v0, v1;
+                    v0 = v_load( src + j );
+                    v1 = v_load( src + j + 8 );
+                    v0 = v0 <= thresh8;
+                    v1 = v1 <= thresh8;
+                    v0 = v0 & maxval8;
+                    v1 = v1 & maxval8;
+                    v_store( dst + j, v0 );
+                    v_store( dst + j + 8, v1 );
                 }
-            }
-        #elif CV_NEON
-            int16x8_t v_thresh = vdupq_n_s16(thresh), v_maxval = vdupq_n_s16(maxval);
 
-            for( ; j <= roi.width - 8; j += 8 )
-            {
-                uint16x8_t v_mask = vcleq_s16(vld1q_s16(src + j), v_thresh);
-                vst1q_s16(dst + j, vandq_s16(vreinterpretq_s16_u16(v_mask), v_maxval));
+                for( ; j < roi.width; j++ )
+                    dst[j] = src[j] <= thresh ? maxval : 0;
             }
-        #endif
-
-            for( ; j < roi.width; j++ )
-                dst[j] = src[j] <= thresh ? maxval : 0;
-        }
-        break;
+            break;
 
-    case THRESH_TRUNC:
-        for( i = 0; i < roi.height; i++, src += src_step, dst += dst_step )
-        {
-            j = 0;
-        #if CV_SSE2
-            if( useSIMD )
+        case THRESH_TRUNC:
+            for( i = 0; i < roi.height; i++, src += src_step, dst += dst_step )
             {
-                __m128i thresh8 = _mm_set1_epi16(thresh);
+                j = 0;
                 for( ; j <= roi.width - 16; j += 16 )
                 {
-                    __m128i v0, v1;
-                    v0 = _mm_loadu_si128( (const __m128i*)(src + j) );
-                    v1 = _mm_loadu_si128( (const __m128i*)(src + j + 8) );
-                    v0 = _mm_min_epi16( v0, thresh8 );
-                    v1 = _mm_min_epi16( v1, thresh8 );
-                    _mm_storeu_si128((__m128i*)(dst + j), v0 );
-                    _mm_storeu_si128((__m128i*)(dst + j + 8), v1 );
+                    v_int16x8 v0, v1;
+                    v0 = v_load( src + j );
+                    v1 = v_load( src + j + 8 );
+                    v0 = v_min( v0, thresh8 );
+                    v1 = v_min( v1, thresh8 );
+                    v_store( dst + j, v0 );
+                    v_store( dst + j + 8, v1 );
                 }
+
+                for( ; j < roi.width; j++ )
+                    dst[j] = std::min( src[j], thresh );
             }
-        #elif CV_NEON
-            int16x8_t v_thresh = vdupq_n_s16(thresh);
+            break;
 
-            for( ; j <= roi.width - 8; j += 8 )
-                vst1q_s16(dst + j, vminq_s16(vld1q_s16(src + j), v_thresh));
-        #endif
+        case THRESH_TOZERO:
+            for( i = 0; i < roi.height; i++, src += src_step, dst += dst_step )
+            {
+                j = 0;
+                for( ; j <= roi.width - 16; j += 16 )
+                {
+                    v_int16x8 v0, v1;
+                    v0 = v_load( src + j );
+                    v1 = v_load( src + j + 8 );
+                    v0 = ( thresh8 < v0 ) & v0;
+                    v1 = ( thresh8 < v1 ) & v1;
+                    v_store( dst + j, v0 );
+                    v_store( dst + j + 8, v1 );
+                }
 
-            for( ; j < roi.width; j++ )
-                dst[j] = std::min(src[j], thresh);
-        }
-        break;
+                for( ; j < roi.width; j++ )
+                {
+                    short v = src[j];
+                    dst[j] = v > thresh ? v : 0;
+                }
+            }
+            break;
 
-    case THRESH_TOZERO:
-        for( i = 0; i < roi.height; i++, src += src_step, dst += dst_step )
-        {
-            j = 0;
-        #if CV_SSE2
-            if( useSIMD )
+        case THRESH_TOZERO_INV:
+            for( i = 0; i < roi.height; i++, src += src_step, dst += dst_step )
             {
-                __m128i thresh8 = _mm_set1_epi16(thresh);
+                j = 0;
                 for( ; j <= roi.width - 16; j += 16 )
                 {
-                    __m128i v0, v1;
-                    v0 = _mm_loadu_si128( (const __m128i*)(src + j) );
-                    v1 = _mm_loadu_si128( (const __m128i*)(src + j + 8) );
-                    v0 = _mm_and_si128(v0, _mm_cmpgt_epi16(v0, thresh8));
-                    v1 = _mm_and_si128(v1, _mm_cmpgt_epi16(v1, thresh8));
-                    _mm_storeu_si128((__m128i*)(dst + j), v0 );
-                    _mm_storeu_si128((__m128i*)(dst + j + 8), v1 );
+                    v_int16x8 v0, v1;
+                    v0 = v_load( src + j );
+                    v1 = v_load( src + j + 8 );
+                    v0 = ( v0 <= thresh8 ) & v0;
+                    v1 = ( v1 <= thresh8 ) & v1;
+                    v_store( dst + j, v0 );
+                    v_store( dst + j + 8, v1 );
+                }
+
+                for( ; j < roi.width; j++ )
+                {
+                    short v = src[j];
+                    dst[j] = v <= thresh ? v : 0;
                 }
             }
-        #elif CV_NEON
-            int16x8_t v_thresh = vdupq_n_s16(thresh);
+            break;
+        default:
+            return CV_Error( CV_StsBadArg, "" );
+        }
+    }
+    else
+#endif
+    {
+        switch( type )
+        {
+        case THRESH_BINARY:
+            for( i = 0; i < roi.height; i++, src += src_step, dst += dst_step )
+            {
+                for( j = 0; j < roi.width; j++ )
+                    dst[j] = src[j] > thresh ? maxval : 0;
+            }
+            break;
 
-            for( ; j <= roi.width - 8; j += 8 )
+        case THRESH_BINARY_INV:
+            for( i = 0; i < roi.height; i++, src += src_step, dst += dst_step )
             {
-                int16x8_t v_src = vld1q_s16(src + j);
-                uint16x8_t v_mask = vcgtq_s16(v_src, v_thresh);
-                vst1q_s16(dst + j, vandq_s16(vreinterpretq_s16_u16(v_mask), v_src));
+                for( j = 0; j < roi.width; j++ )
+                    dst[j] = src[j] <= thresh ? maxval : 0;
             }
-        #endif
+            break;
 
-            for( ; j < roi.width; j++ )
+        case THRESH_TRUNC:
+            for( i = 0; i < roi.height; i++, src += src_step, dst += dst_step )
             {
-                short v = src[j];
-                dst[j] = v > thresh ? v : 0;
+                for( j = 0; j < roi.width; j++ )
+                    dst[j] = std::min( src[j], thresh );
             }
-        }
-        break;
+            break;
 
-    case THRESH_TOZERO_INV:
-        for( i = 0; i < roi.height; i++, src += src_step, dst += dst_step )
-        {
-            j = 0;
-        #if CV_SSE2
-            if( useSIMD )
+        case THRESH_TOZERO:
+            for( i = 0; i < roi.height; i++, src += src_step, dst += dst_step )
             {
-                __m128i thresh8 = _mm_set1_epi16(thresh);
-                for( ; j <= roi.width - 16; j += 16 )
+                for( j = 0; j < roi.width; j++ )
                 {
-                    __m128i v0, v1;
-                    v0 = _mm_loadu_si128( (const __m128i*)(src + j) );
-                    v1 = _mm_loadu_si128( (const __m128i*)(src + j + 8) );
-                    v0 = _mm_andnot_si128(_mm_cmpgt_epi16(v0, thresh8), v0);
-                    v1 = _mm_andnot_si128(_mm_cmpgt_epi16(v1, thresh8), v1);
-                    _mm_storeu_si128((__m128i*)(dst + j), v0 );
-                    _mm_storeu_si128((__m128i*)(dst + j + 8), v1 );
+                    short v = src[j];
+                    dst[j] = v > thresh ? v : 0;
                 }
             }
-        #elif CV_NEON
-            int16x8_t v_thresh = vdupq_n_s16(thresh);
+            break;
 
-            for( ; j <= roi.width - 8; j += 8 )
-            {
-                int16x8_t v_src = vld1q_s16(src + j);
-                uint16x8_t v_mask = vcleq_s16(v_src, v_thresh);
-                vst1q_s16(dst + j, vandq_s16(vreinterpretq_s16_u16(v_mask), v_src));
-            }
-        #endif
-            for( ; j < roi.width; j++ )
+        case THRESH_TOZERO_INV:
+            for( i = 0; i < roi.height; i++, src += src_step, dst += dst_step )
             {
-                short v = src[j];
-                dst[j] = v <= thresh ? v : 0;
+                for( j = 0; j < roi.width; j++ )
+                {
+                    short v = src[j];
+                    dst[j] = v <= thresh ? v : 0;
+                }
             }
+            break;
+        default:
+            return CV_Error( CV_StsBadArg, "" );
         }
-        break;
-    default:
-        return CV_Error( CV_StsBadArg, "" );
     }
 }
 
@@ -665,10 +534,6 @@ thresh_32f( const Mat& _src, Mat& _dst, float thresh, float maxval, int type )
     size_t src_step = _src.step/sizeof(src[0]);
     size_t dst_step = _dst.step/sizeof(dst[0]);
 
-#if CV_SSE2
-    volatile bool useSIMD = checkHardwareSupport(CV_CPU_SSE);
-#endif
-
     if( _src.isContinuous() && _dst.isContinuous() )
     {
         roi.width *= roi.height;
@@ -687,7 +552,7 @@ thresh_32f( const Mat& _src, Mat& _dst, float thresh, float maxval, int type )
         switch( type )
         {
         case THRESH_TRUNC:
-            if (0 <= ippiThreshold_GT_32f_C1R(src, (int)src_step*sizeof(src[0]), dst, (int)dst_step*sizeof(dst[0]), sz, thresh))
+            if (0 <= CV_INSTRUMENT_FUN_IPP(ippiThreshold_GT_32f_C1R, src, (int)src_step*sizeof(src[0]), dst, (int)dst_step*sizeof(dst[0]), sz, thresh))
             {
                 CV_IMPL_ADD(CV_IMPL_IPP);
                 return;
@@ -695,7 +560,7 @@ thresh_32f( const Mat& _src, Mat& _dst, float thresh, float maxval, int type )
             setIppErrorStatus();
             break;
         case THRESH_TOZERO:
-            if (0 <= ippiThreshold_LTVal_32f_C1R(src, (int)src_step*sizeof(src[0]), dst, (int)dst_step*sizeof(dst[0]), sz, thresh+FLT_EPSILON, 0))
+            if (0 <= CV_INSTRUMENT_FUN_IPP(ippiThreshold_LTVal_32f_C1R, src, (int)src_step*sizeof(src[0]), dst, (int)dst_step*sizeof(dst[0]), sz, thresh + FLT_EPSILON, 0))
             {
                 CV_IMPL_ADD(CV_IMPL_IPP);
                 return;
@@ -703,7 +568,7 @@ thresh_32f( const Mat& _src, Mat& _dst, float thresh, float maxval, int type )
             setIppErrorStatus();
             break;
         case THRESH_TOZERO_INV:
-            if (0 <= ippiThreshold_GTVal_32f_C1R(src, (int)src_step*sizeof(src[0]), dst, (int)dst_step*sizeof(dst[0]), sz, thresh, 0))
+            if (0 <= CV_INSTRUMENT_FUN_IPP(ippiThreshold_GTVal_32f_C1R, src, (int)src_step*sizeof(src[0]), dst, (int)dst_step*sizeof(dst[0]), sz, thresh, 0))
             {
                 CV_IMPL_ADD(CV_IMPL_IPP);
                 return;
@@ -714,40 +579,226 @@ thresh_32f( const Mat& _src, Mat& _dst, float thresh, float maxval, int type )
     }
 #endif
 
-    switch( type )
+#if CV_SIMD128
+    bool useSIMD = checkHardwareSupport( CV_CPU_SSE2 ) || checkHardwareSupport( CV_CPU_NEON );
+    if( useSIMD )
     {
-        case THRESH_BINARY:
-            for( i = 0; i < roi.height; i++, src += src_step, dst += dst_step )
-            {
-                j = 0;
-#if CV_SSE2
-                if( useSIMD )
+        v_float32x4 thresh4 = v_setall_f32( thresh );
+        v_float32x4 maxval4 = v_setall_f32( maxval );
+
+        switch( type )
+        {
+            case THRESH_BINARY:
+                for( i = 0; i < roi.height; i++, src += src_step, dst += dst_step )
                 {
-                    __m128 thresh4 = _mm_set1_ps(thresh), maxval4 = _mm_set1_ps(maxval);
+                    j = 0;
                     for( ; j <= roi.width - 8; j += 8 )
                     {
-                        __m128 v0, v1;
-                        v0 = _mm_loadu_ps( src + j );
-                        v1 = _mm_loadu_ps( src + j + 4 );
-                        v0 = _mm_cmpgt_ps( v0, thresh4 );
-                        v1 = _mm_cmpgt_ps( v1, thresh4 );
-                        v0 = _mm_and_ps( v0, maxval4 );
-                        v1 = _mm_and_ps( v1, maxval4 );
-                        _mm_storeu_ps( dst + j, v0 );
-                        _mm_storeu_ps( dst + j + 4, v1 );
+                        v_float32x4 v0, v1;
+                        v0 = v_load( src + j );
+                        v1 = v_load( src + j + 4 );
+                        v0 = thresh4 < v0;
+                        v1 = thresh4 < v1;
+                        v0 = v0 & maxval4;
+                        v1 = v1 & maxval4;
+                        v_store( dst + j, v0 );
+                        v_store( dst + j + 4, v1 );
                     }
+
+                    for( ; j < roi.width; j++ )
+                        dst[j] = src[j] > thresh ? maxval : 0;
                 }
-#elif CV_NEON
-                float32x4_t v_thresh = vdupq_n_f32(thresh);
-                uint32x4_t v_maxval = vreinterpretq_u32_f32(vdupq_n_f32(maxval));
+                break;
 
-                for( ; j <= roi.width - 4; j += 4 )
+            case THRESH_BINARY_INV:
+                for( i = 0; i < roi.height; i++, src += src_step, dst += dst_step )
+                {
+                    j = 0;
+                    for( ; j <= roi.width - 8; j += 8 )
+                    {
+                        v_float32x4 v0, v1;
+                        v0 = v_load( src + j );
+                        v1 = v_load( src + j + 4 );
+                        v0 = v0 <= thresh4;
+                        v1 = v1 <= thresh4;
+                        v0 = v0 & maxval4;
+                        v1 = v1 & maxval4;
+                        v_store( dst + j, v0 );
+                        v_store( dst + j + 4, v1 );
+                    }
+
+                    for( ; j < roi.width; j++ )
+                        dst[j] = src[j] <= thresh ? maxval : 0;
+                }
+                break;
+
+            case THRESH_TRUNC:
+                for( i = 0; i < roi.height; i++, src += src_step, dst += dst_step )
                 {
-                    float32x4_t v_src = vld1q_f32(src + j);
-                    uint32x4_t v_dst = vandq_u32(vcgtq_f32(v_src, v_thresh), v_maxval);
-                    vst1q_f32(dst + j, vreinterpretq_f32_u32(v_dst));
+                    j = 0;
+                    for( ; j <= roi.width - 8; j += 8 )
+                    {
+                        v_float32x4 v0, v1;
+                        v0 = v_load( src + j );
+                        v1 = v_load( src + j + 4 );
+                        v0 = v_min( v0, thresh4 );
+                        v1 = v_min( v1, thresh4 );
+                        v_store( dst + j, v0 );
+                        v_store( dst + j + 4, v1 );
+                    }
+
+                    for( ; j < roi.width; j++ )
+                        dst[j] = std::min( src[j], thresh );
                 }
+                break;
+
+            case THRESH_TOZERO:
+                for( i = 0; i < roi.height; i++, src += src_step, dst += dst_step )
+                {
+                    j = 0;
+                    for( ; j <= roi.width - 8; j += 8 )
+                    {
+                        v_float32x4 v0, v1;
+                        v0 = v_load( src + j );
+                        v1 = v_load( src + j + 4 );
+                        v0 = ( thresh4 < v0 ) & v0;
+                        v1 = ( thresh4 < v1 ) & v1;
+                        v_store( dst + j, v0 );
+                        v_store( dst + j + 4, v1 );
+                    }
+
+                    for( ; j < roi.width; j++ )
+                    {
+                        float v = src[j];
+                        dst[j] = v > thresh ? v : 0;
+                    }
+                }
+                break;
+
+            case THRESH_TOZERO_INV:
+                for( i = 0; i < roi.height; i++, src += src_step, dst += dst_step )
+                {
+                    j = 0;
+                    for( ; j <= roi.width - 8; j += 8 )
+                    {
+                        v_float32x4 v0, v1;
+                        v0 = v_load( src + j );
+                        v1 = v_load( src + j + 4 );
+                        v0 = ( v0 <= thresh4 ) & v0;
+                        v1 = ( v1 <= thresh4 ) & v1;
+                        v_store( dst + j, v0 );
+                        v_store( dst + j + 4, v1 );
+                    }
+
+                    for( ; j < roi.width; j++ )
+                    {
+                        float v = src[j];
+                        dst[j] = v <= thresh ? v : 0;
+                    }
+                }
+                break;
+            default:
+                return CV_Error( CV_StsBadArg, "" );
+        }
+    }
+    else
 #endif
+    {
+        switch( type )
+        {
+            case THRESH_BINARY:
+                for( i = 0; i < roi.height; i++, src += src_step, dst += dst_step )
+                {
+                    for( j = 0; j < roi.width; j++ )
+                        dst[j] = src[j] > thresh ? maxval : 0;
+                }
+                break;
+
+            case THRESH_BINARY_INV:
+                for( i = 0; i < roi.height; i++, src += src_step, dst += dst_step )
+                {
+                    for( j = 0; j < roi.width; j++ )
+                        dst[j] = src[j] <= thresh ? maxval : 0;
+                }
+                break;
+
+            case THRESH_TRUNC:
+                for( i = 0; i < roi.height; i++, src += src_step, dst += dst_step )
+                {
+                    for( j = 0; j < roi.width; j++ )
+                        dst[j] = std::min( src[j], thresh );
+                }
+                break;
+
+            case THRESH_TOZERO:
+                for( i = 0; i < roi.height; i++, src += src_step, dst += dst_step )
+                {
+                    for( j = 0; j < roi.width; j++ )
+                    {
+                        float v = src[j];
+                        dst[j] = v > thresh ? v : 0;
+                    }
+                }
+                break;
+
+            case THRESH_TOZERO_INV:
+                for( i = 0; i < roi.height; i++, src += src_step, dst += dst_step )
+                {
+                    for( j = 0; j < roi.width; j++ )
+                    {
+                        float v = src[j];
+                        dst[j] = v <= thresh ? v : 0;
+                    }
+                }
+                break;
+            default:
+                return CV_Error( CV_StsBadArg, "" );
+        }
+    }
+}
+
+static void
+thresh_64f(const Mat& _src, Mat& _dst, double thresh, double maxval, int type)
+{
+    int i, j;
+    Size roi = _src.size();
+    roi.width *= _src.channels();
+    const double* src = _src.ptr<double>();
+    double* dst = _dst.ptr<double>();
+    size_t src_step = _src.step / sizeof(src[0]);
+    size_t dst_step = _dst.step / sizeof(dst[0]);
+
+    if (_src.isContinuous() && _dst.isContinuous())
+    {
+        roi.width *= roi.height;
+        roi.height = 1;
+    }
+
+#if CV_SIMD128_64F
+    bool useSIMD = checkHardwareSupport( CV_CPU_SSE2 ) || checkHardwareSupport( CV_CPU_NEON );
+    if( useSIMD )
+    {
+        v_float64x2 thresh2 = v_setall_f64( thresh );
+        v_float64x2 maxval2 = v_setall_f64( maxval );
+
+        switch( type )
+        {
+        case THRESH_BINARY:
+            for( i = 0; i < roi.height; i++, src += src_step, dst += dst_step )
+            {
+                j = 0;
+                for( ; j <= roi.width - 4; j += 4 )
+                {
+                    v_float64x2 v0, v1;
+                    v0 = v_load( src + j );
+                    v1 = v_load( src + j + 2 );
+                    v0 = thresh2 < v0;
+                    v1 = thresh2 < v1;
+                    v0 = v0 & maxval2;
+                    v1 = v1 & maxval2;
+                    v_store( dst + j, v0 );
+                    v_store( dst + j + 2, v1 );
+                }
 
                 for( ; j < roi.width; j++ )
                     dst[j] = src[j] > thresh ? maxval : 0;
@@ -758,34 +809,18 @@ thresh_32f( const Mat& _src, Mat& _dst, float thresh, float maxval, int type )
             for( i = 0; i < roi.height; i++, src += src_step, dst += dst_step )
             {
                 j = 0;
-#if CV_SSE2
-                if( useSIMD )
-                {
-                    __m128 thresh4 = _mm_set1_ps(thresh), maxval4 = _mm_set1_ps(maxval);
-                    for( ; j <= roi.width - 8; j += 8 )
-                    {
-                        __m128 v0, v1;
-                        v0 = _mm_loadu_ps( src + j );
-                        v1 = _mm_loadu_ps( src + j + 4 );
-                        v0 = _mm_cmple_ps( v0, thresh4 );
-                        v1 = _mm_cmple_ps( v1, thresh4 );
-                        v0 = _mm_and_ps( v0, maxval4 );
-                        v1 = _mm_and_ps( v1, maxval4 );
-                        _mm_storeu_ps( dst + j, v0 );
-                        _mm_storeu_ps( dst + j + 4, v1 );
-                    }
-                }
-#elif CV_NEON
-                float32x4_t v_thresh = vdupq_n_f32(thresh);
-                uint32x4_t v_maxval = vreinterpretq_u32_f32(vdupq_n_f32(maxval));
-
                 for( ; j <= roi.width - 4; j += 4 )
                 {
-                    float32x4_t v_src = vld1q_f32(src + j);
-                    uint32x4_t v_dst = vandq_u32(vcleq_f32(v_src, v_thresh), v_maxval);
-                    vst1q_f32(dst + j, vreinterpretq_f32_u32(v_dst));
+                    v_float64x2 v0, v1;
+                    v0 = v_load( src + j );
+                    v1 = v_load( src + j + 2 );
+                    v0 = v0 <= thresh2;
+                    v1 = v1 <= thresh2;
+                    v0 = v0 & maxval2;
+                    v1 = v1 & maxval2;
+                    v_store( dst + j, v0 );
+                    v_store( dst + j + 2, v1 );
                 }
-#endif
 
                 for( ; j < roi.width; j++ )
                     dst[j] = src[j] <= thresh ? maxval : 0;
@@ -796,30 +831,19 @@ thresh_32f( const Mat& _src, Mat& _dst, float thresh, float maxval, int type )
             for( i = 0; i < roi.height; i++, src += src_step, dst += dst_step )
             {
                 j = 0;
-#if CV_SSE2
-                if( useSIMD )
+                for( ; j <= roi.width - 4; j += 4 )
                 {
-                    __m128 thresh4 = _mm_set1_ps(thresh);
-                    for( ; j <= roi.width - 8; j += 8 )
-                    {
-                        __m128 v0, v1;
-                        v0 = _mm_loadu_ps( src + j );
-                        v1 = _mm_loadu_ps( src + j + 4 );
-                        v0 = _mm_min_ps( v0, thresh4 );
-                        v1 = _mm_min_ps( v1, thresh4 );
-                        _mm_storeu_ps( dst + j, v0 );
-                        _mm_storeu_ps( dst + j + 4, v1 );
-                    }
+                    v_float64x2 v0, v1;
+                    v0 = v_load( src + j );
+                    v1 = v_load( src + j + 2 );
+                    v0 = v_min( v0, thresh2 );
+                    v1 = v_min( v1, thresh2 );
+                    v_store( dst + j, v0 );
+                    v_store( dst + j + 2, v1 );
                 }
-#elif CV_NEON
-                float32x4_t v_thresh = vdupq_n_f32(thresh);
-
-                for( ; j <= roi.width - 4; j += 4 )
-                    vst1q_f32(dst + j, vminq_f32(vld1q_f32(src + j), v_thresh));
-#endif
 
                 for( ; j < roi.width; j++ )
-                    dst[j] = std::min(src[j], thresh);
+                    dst[j] = std::min( src[j], thresh );
             }
             break;
 
@@ -827,36 +851,20 @@ thresh_32f( const Mat& _src, Mat& _dst, float thresh, float maxval, int type )
             for( i = 0; i < roi.height; i++, src += src_step, dst += dst_step )
             {
                 j = 0;
-#if CV_SSE2
-                if( useSIMD )
-                {
-                    __m128 thresh4 = _mm_set1_ps(thresh);
-                    for( ; j <= roi.width - 8; j += 8 )
-                    {
-                        __m128 v0, v1;
-                        v0 = _mm_loadu_ps( src + j );
-                        v1 = _mm_loadu_ps( src + j + 4 );
-                        v0 = _mm_and_ps(v0, _mm_cmpgt_ps(v0, thresh4));
-                        v1 = _mm_and_ps(v1, _mm_cmpgt_ps(v1, thresh4));
-                        _mm_storeu_ps( dst + j, v0 );
-                        _mm_storeu_ps( dst + j + 4, v1 );
-                    }
-                }
-#elif CV_NEON
-                float32x4_t v_thresh = vdupq_n_f32(thresh);
-
                 for( ; j <= roi.width - 4; j += 4 )
                 {
-                    float32x4_t v_src = vld1q_f32(src + j);
-                    uint32x4_t v_dst = vandq_u32(vcgtq_f32(v_src, v_thresh),
-                                                 vreinterpretq_u32_f32(v_src));
-                    vst1q_f32(dst + j, vreinterpretq_f32_u32(v_dst));
+                    v_float64x2 v0, v1;
+                    v0 = v_load( src + j );
+                    v1 = v_load( src + j + 2 );
+                    v0 = ( thresh2 < v0 ) & v0;
+                    v1 = ( thresh2 < v1 ) & v1;
+                    v_store( dst + j, v0 );
+                    v_store( dst + j + 2, v1 );
                 }
-#endif
 
                 for( ; j < roi.width; j++ )
                 {
-                    float v = src[j];
+                    double v = src[j];
                     dst[j] = v > thresh ? v : 0;
                 }
             }
@@ -866,52 +874,99 @@ thresh_32f( const Mat& _src, Mat& _dst, float thresh, float maxval, int type )
             for( i = 0; i < roi.height; i++, src += src_step, dst += dst_step )
             {
                 j = 0;
-#if CV_SSE2
-                if( useSIMD )
+                for( ; j <= roi.width - 4; j += 4 )
                 {
-                    __m128 thresh4 = _mm_set1_ps(thresh);
-                    for( ; j <= roi.width - 8; j += 8 )
-                    {
-                        __m128 v0, v1;
-                        v0 = _mm_loadu_ps( src + j );
-                        v1 = _mm_loadu_ps( src + j + 4 );
-                        v0 = _mm_and_ps(v0, _mm_cmple_ps(v0, thresh4));
-                        v1 = _mm_and_ps(v1, _mm_cmple_ps(v1, thresh4));
-                        _mm_storeu_ps( dst + j, v0 );
-                        _mm_storeu_ps( dst + j + 4, v1 );
-                    }
+                    v_float64x2 v0, v1;
+                    v0 = v_load( src + j );
+                    v1 = v_load( src + j + 2 );
+                    v0 = ( v0 <= thresh2 ) & v0;
+                    v1 = ( v1 <= thresh2 ) & v1;
+                    v_store( dst + j, v0 );
+                    v_store( dst + j + 2, v1 );
                 }
-#elif CV_NEON
-                float32x4_t v_thresh = vdupq_n_f32(thresh);
 
-                for( ; j <= roi.width - 4; j += 4 )
+                for( ; j < roi.width; j++ )
                 {
-                    float32x4_t v_src = vld1q_f32(src + j);
-                    uint32x4_t v_dst = vandq_u32(vcleq_f32(v_src, v_thresh),
-                                                 vreinterpretq_u32_f32(v_src));
-                    vst1q_f32(dst + j, vreinterpretq_f32_u32(v_dst));
+                    double v = src[j];
+                    dst[j] = v <= thresh ? v : 0;
                 }
+            }
+            break;
+        default:
+            return CV_Error(CV_StsBadArg, "");
+        }
+    }
+    else
 #endif
+    {
+        switch( type )
+        {
+        case THRESH_BINARY:
+            for( i = 0; i < roi.height; i++, src += src_step, dst += dst_step )
+            {
+                j = 0;
+                for( ; j < roi.width; j++ )
+                    dst[j] = src[j] > thresh ? maxval : 0;
+            }
+            break;
+
+        case THRESH_BINARY_INV:
+            for( i = 0; i < roi.height; i++, src += src_step, dst += dst_step )
+            {
+                j = 0;
+                for( ; j < roi.width; j++ )
+                    dst[j] = src[j] <= thresh ? maxval : 0;
+            }
+            break;
+
+        case THRESH_TRUNC:
+            for( i = 0; i < roi.height; i++, src += src_step, dst += dst_step )
+            {
+                j = 0;
+                for( ; j < roi.width; j++ )
+                    dst[j] = std::min( src[j], thresh );
+            }
+            break;
+
+        case THRESH_TOZERO:
+            for( i = 0; i < roi.height; i++, src += src_step, dst += dst_step )
+            {
+                j = 0;
                 for( ; j < roi.width; j++ )
                 {
-                    float v = src[j];
+                    double v = src[j];
+                    dst[j] = v > thresh ? v : 0;
+                }
+            }
+            break;
+
+        case THRESH_TOZERO_INV:
+            for( i = 0; i < roi.height; i++, src += src_step, dst += dst_step )
+            {
+                j = 0;
+                for( ; j < roi.width; j++ )
+                {
+                    double v = src[j];
                     dst[j] = v <= thresh ? v : 0;
                 }
             }
             break;
         default:
-            return CV_Error( CV_StsBadArg, "" );
+            return CV_Error(CV_StsBadArg, "");
+        }
     }
 }
 
 #ifdef HAVE_IPP
 static bool ipp_getThreshVal_Otsu_8u( const unsigned char* _src, int step, Size size, unsigned char &thresh)
 {
-#if IPP_VERSION_X100 >= 810 && !HAVE_ICV
+    CV_INSTRUMENT_REGION_IPP()
+
+#if IPP_VERSION_X100 >= 810
     int ippStatus = -1;
     IppiSize srcSize = { size.width, size.height };
     CV_SUPPRESS_DEPRECATED_START
-    ippStatus = ippiComputeThreshold_Otsu_8u_C1R(_src, step, srcSize, &thresh);
+    ippStatus = CV_INSTRUMENT_FUN_IPP(ippiComputeThreshold_Otsu_8u_C1R, _src, step, srcSize, &thresh);
     CV_SUPPRESS_DEPRECATED_END
 
     if(ippStatus >= 0)
@@ -937,7 +992,7 @@ getThreshVal_Otsu_8u( const Mat& _src )
 
 #ifdef HAVE_IPP
     unsigned char thresh;
-    CV_IPP_RUN(IPP_VERSION_X100 >= 810 && !HAVE_ICV, ipp_getThreshVal_Otsu_8u(_src.ptr(), step, size, thresh), thresh);
+    CV_IPP_RUN(IPP_VERSION_X100 >= 810, ipp_getThreshVal_Otsu_8u(_src.ptr(), step, size, thresh), thresh);
 #endif
 
     const int N = 256;
@@ -1129,6 +1184,10 @@ public:
         {
             thresh_32f( srcStripe, dstStripe, (float)thresh, (float)maxval, thresholdType );
         }
+        else if( srcStripe.depth() == CV_64F )
+        {
+            thresh_64f(srcStripe, dstStripe, thresh, maxval, thresholdType);
+        }
     }
 
 private:
@@ -1187,10 +1246,103 @@ static bool ocl_threshold( InputArray _src, OutputArray _dst, double & thresh, d
 
 #endif
 
+
+#ifdef HAVE_OPENVX
+#define IMPL_OPENVX_TOZERO 1
+static bool openvx_threshold(Mat src, Mat dst, int thresh, int maxval, int type)
+{
+    Mat a = src;
+
+    int trueVal, falseVal;
+    switch (type)
+    {
+    case THRESH_BINARY:
+#ifndef VX_VERSION_1_1
+        if (maxval != 255)
+            return false;
+#endif
+        trueVal = maxval;
+        falseVal = 0;
+        break;
+    case THRESH_TOZERO:
+#if IMPL_OPENVX_TOZERO
+        trueVal = 255;
+        falseVal = 0;
+        if (dst.data == src.data)
+        {
+            a = Mat(src.size(), src.type());
+            src.copyTo(a);
+        }
+        break;
+#endif
+    case THRESH_BINARY_INV:
+#ifdef VX_VERSION_1_1
+        trueVal = 0;
+        falseVal = maxval;
+        break;
+#endif
+    case THRESH_TOZERO_INV:
+#ifdef VX_VERSION_1_1
+#if IMPL_OPENVX_TOZERO
+        trueVal = 0;
+        falseVal = 255;
+        if (dst.data == src.data)
+        {
+            a = Mat(src.size(), src.type());
+            src.copyTo(a);
+        }
+        break;
+#endif
+#endif
+    case THRESH_TRUNC:
+    default:
+        return false;
+    }
+
+    try
+    {
+        ivx::Context ctx = ivx::Context::create();
+
+        ivx::Threshold thh = ivx::Threshold::createBinary(ctx, VX_TYPE_UINT8, thresh);
+        thh.setValueTrue(trueVal);
+        thh.setValueFalse(falseVal);
+
+        ivx::Image
+            ia = ivx::Image::createFromHandle(ctx, VX_DF_IMAGE_U8,
+                ivx::Image::createAddressing(a.cols*a.channels(), a.rows, 1, (vx_int32)(a.step)), src.data),
+            ib = ivx::Image::createFromHandle(ctx, VX_DF_IMAGE_U8,
+                ivx::Image::createAddressing(dst.cols*dst.channels(), dst.rows, 1, (vx_int32)(dst.step)), dst.data);
+
+        ivx::IVX_CHECK_STATUS(vxuThreshold(ctx, ia, thh, ib));
+#if IMPL_OPENVX_TOZERO
+        if (type == THRESH_TOZERO || type == THRESH_TOZERO_INV)
+        {
+            ivx::Image
+                ic = ivx::Image::createFromHandle(ctx, VX_DF_IMAGE_U8,
+                    ivx::Image::createAddressing(dst.cols*dst.channels(), dst.rows, 1, (vx_int32)(dst.step)), dst.data);
+            ivx::IVX_CHECK_STATUS(vxuAnd(ctx, ib, ia, ic));
+        }
+#endif
+    }
+    catch (ivx::RuntimeError & e)
+    {
+        VX_DbgThrow(e.what());
+    }
+    catch (ivx::WrapperError & e)
+    {
+        VX_DbgThrow(e.what());
+    }
+
+    return true;
+}
+#endif
+
 }
 
 double cv::threshold( InputArray _src, OutputArray _dst, double thresh, double maxval, int type )
 {
+    CV_INSTRUMENT_REGION()
+
     CV_OCL_RUN_(_src.dims() <= 2 && _dst.isUMat(),
                 ocl_threshold(_src, _dst, thresh, maxval, type), thresh)
 
@@ -1237,6 +1389,10 @@ double cv::threshold( InputArray _src, OutputArray _dst, double thresh, double m
                 src.copyTo(dst);
             return thresh;
         }
+
+       CV_OVX_RUN(true,
+                  openvx_threshold(src, dst, ithresh, imaxval, type), (double)ithresh)
+
         thresh = ithresh;
         maxval = imaxval;
     }
@@ -1269,6 +1425,8 @@ double cv::threshold( InputArray _src, OutputArray _dst, double thresh, double m
     }
     else if( src.depth() == CV_32F )
         ;
+    else if( src.depth() == CV_64F )
+        ;
     else
         CV_Error( CV_StsUnsupportedFormat, "" );
 
@@ -1282,6 +1440,8 @@ double cv::threshold( InputArray _src, OutputArray _dst, double thresh, double m
 void cv::adaptiveThreshold( InputArray _src, OutputArray _dst, double maxValue,
                             int method, int type, int blockSize, double delta )
 {
+    CV_INSTRUMENT_REGION()
+
     Mat src = _src.getMat();
     CV_Assert( src.type() == CV_8UC1 );
     CV_Assert( blockSize % 2 == 1 && blockSize > 1 );
diff --git a/modules/imgproc/src/undistort.cpp b/modules/imgproc/src/undistort.cpp
index 5e6cf05..127481f 100644
--- a/modules/imgproc/src/undistort.cpp
+++ b/modules/imgproc/src/undistort.cpp
@@ -182,6 +182,8 @@ void cv::initUndistortRectifyMap( InputArray _cameraMatrix, InputArray _distCoef
 void cv::undistort( InputArray _src, OutputArray _dst, InputArray _cameraMatrix,
                     InputArray _distCoeffs, InputArray _newCameraMatrix )
 {
+    CV_INSTRUMENT_REGION()
+
     Mat src = _src.getMat(), cameraMatrix = _cameraMatrix.getMat();
     Mat distCoeffs = _distCoeffs.getMat(), newCameraMatrix = _newCameraMatrix.getMat();
 
@@ -278,16 +280,9 @@ void cvUndistortPoints( const CvMat* _src, CvMat* _dst, const CvMat* _cameraMatr
                    const CvMat* _distCoeffs,
                    const CvMat* matR, const CvMat* matP )
 {
-    double A[3][3], RR[3][3], k[14]={0,0,0,0,0,0,0,0,0,0,0,0,0,0}, fx, fy, ifx, ify, cx, cy;
+    double A[3][3], RR[3][3], k[14]={0,0,0,0,0,0,0,0,0,0,0,0,0,0};
     CvMat matA=cvMat(3, 3, CV_64F, A), _Dk;
     CvMat _RR=cvMat(3, 3, CV_64F, RR);
-    const CvPoint2D32f* srcf;
-    const CvPoint2D64f* srcd;
-    CvPoint2D32f* dstf;
-    CvPoint2D64f* dstd;
-    int stype, dtype;
-    int sstep, dstep;
-    int i, j, n, iters = 1;
     cv::Matx33d invMatTilt = cv::Matx33d::eye();
 
     CV_Assert( CV_IS_MAT(_src) && CV_IS_MAT(_dst) &&
@@ -302,6 +297,8 @@ void cvUndistortPoints( const CvMat* _src, CvMat* _dst, const CvMat* _cameraMatr
 
     cvConvert( _cameraMatrix, &matA );
 
+    int iters = 0;
+
     if( _distCoeffs )
     {
         CV_Assert( CV_IS_MAT(_distCoeffs) &&
@@ -338,27 +335,26 @@ void cvUndistortPoints( const CvMat* _src, CvMat* _dst, const CvMat* _cameraMatr
         cvMatMul( &_PP, &_RR, &_RR );
     }
 
-    srcf = (const CvPoint2D32f*)_src->data.ptr;
-    srcd = (const CvPoint2D64f*)_src->data.ptr;
-    dstf = (CvPoint2D32f*)_dst->data.ptr;
-    dstd = (CvPoint2D64f*)_dst->data.ptr;
-    stype = CV_MAT_TYPE(_src->type);
-    dtype = CV_MAT_TYPE(_dst->type);
-    sstep = _src->rows == 1 ? 1 : _src->step/CV_ELEM_SIZE(stype);
-    dstep = _dst->rows == 1 ? 1 : _dst->step/CV_ELEM_SIZE(dtype);
-
-    n = _src->rows + _src->cols - 1;
-
-    fx = A[0][0];
-    fy = A[1][1];
-    ifx = 1./fx;
-    ify = 1./fy;
-    cx = A[0][2];
-    cy = A[1][2];
-
-    for( i = 0; i < n; i++ )
+    const CvPoint2D32f* srcf = (const CvPoint2D32f*)_src->data.ptr;
+    const CvPoint2D64f* srcd = (const CvPoint2D64f*)_src->data.ptr;
+    CvPoint2D32f* dstf = (CvPoint2D32f*)_dst->data.ptr;
+    CvPoint2D64f* dstd = (CvPoint2D64f*)_dst->data.ptr;
+    int stype = CV_MAT_TYPE(_src->type);
+    int dtype = CV_MAT_TYPE(_dst->type);
+    int sstep = _src->rows == 1 ? 1 : _src->step/CV_ELEM_SIZE(stype);
+    int dstep = _dst->rows == 1 ? 1 : _dst->step/CV_ELEM_SIZE(dtype);
+
+    double fx = A[0][0];
+    double fy = A[1][1];
+    double ifx = 1./fx;
+    double ify = 1./fy;
+    double cx = A[0][2];
+    double cy = A[1][2];
+
+    int n = _src->rows + _src->cols - 1;
+    for( int i = 0; i < n; i++ )
     {
-        double x, y, x0, y0;
+        double x, y, x0 = 0, y0 = 0;
         if( stype == CV_32FC2 )
         {
             x = srcf[i*sstep].x;
@@ -373,14 +369,16 @@ void cvUndistortPoints( const CvMat* _src, CvMat* _dst, const CvMat* _cameraMatr
         x = (x - cx)*ifx;
         y = (y - cy)*ify;
 
-        // compensate tilt distortion
-        cv::Vec3d vecUntilt = invMatTilt * cv::Vec3d(x, y, 1);
-        double invProj = vecUntilt(2) ? 1./vecUntilt(2) : 1;
-        x0 = x = invProj * vecUntilt(0);
-        y0 = y = invProj * vecUntilt(1);
+        if( iters ) {
+            // compensate tilt distortion
+            cv::Vec3d vecUntilt = invMatTilt * cv::Vec3d(x, y, 1);
+            double invProj = vecUntilt(2) ? 1./vecUntilt(2) : 1;
+            x0 = x = invProj * vecUntilt(0);
+            y0 = y = invProj * vecUntilt(1);
+        }
 
         // compensate distortion iteratively
-        for( j = 0; j < iters; j++ )
+        for( int j = 0; j < iters; j++ )
         {
             double r2 = x*x + y*y;
             double icdist = (1 + ((k[7]*r2 + k[6])*r2 + k[5])*r2)/(1 + ((k[4]*r2 + k[1])*r2 + k[0])*r2);
diff --git a/modules/imgproc/test/ocl/test_boxfilter.cpp b/modules/imgproc/test/ocl/test_boxfilter.cpp
index 19a6ace..5d6803a 100644
--- a/modules/imgproc/test/ocl/test_boxfilter.cpp
+++ b/modules/imgproc/test/ocl/test_boxfilter.cpp
@@ -157,6 +157,80 @@ OCL_INSTANTIATE_TEST_CASE_P(ImageProc, SqrBoxFilter,
                            );
 
 
+PARAM_TEST_CASE(BoxFilter3x3_cols16_rows2_Base, MatDepth, Channels, BorderType, bool, bool)
+{
+    int depth, cn, borderType;
+    Size ksize, dsize;
+    Point anchor;
+    bool normalize, useRoi;
+
+    TEST_DECLARE_INPUT_PARAMETER(src);
+    TEST_DECLARE_OUTPUT_PARAMETER(dst);
+
+    virtual void SetUp()
+    {
+        depth = GET_PARAM(0);
+        cn = GET_PARAM(1);
+        borderType = GET_PARAM(2); // only not isolated border tested, because CPU module doesn't support isolated border case.
+        normalize = GET_PARAM(3);
+        useRoi = GET_PARAM(4);
+    }
+
+    void random_roi()
+    {
+        int type = CV_MAKE_TYPE(depth, cn);
+        ksize = Size(3,3);
+
+        Size roiSize = randomSize(ksize.width, MAX_VALUE, ksize.height, MAX_VALUE);
+        roiSize.width = std::max(ksize.width + 13, roiSize.width & (~0xf));
+        roiSize.height = std::max(ksize.height + 1, roiSize.height & (~0x1));
+        Border srcBorder = {0, 0, 0, 0};
+        randomSubMat(src, src_roi, roiSize, srcBorder, type, -MAX_VALUE, MAX_VALUE);
+
+        Border dstBorder = {0, 0, 0, 0};
+        randomSubMat(dst, dst_roi, roiSize, dstBorder, type, -MAX_VALUE, MAX_VALUE);
+
+        anchor.x = -1;
+        anchor.y = -1;
+
+        UMAT_UPLOAD_INPUT_PARAMETER(src);
+        UMAT_UPLOAD_OUTPUT_PARAMETER(dst);
+    }
+
+    void Near(double threshold = 0.0)
+    {
+        OCL_EXPECT_MATS_NEAR(dst, threshold);
+    }
+};
+
+typedef BoxFilter3x3_cols16_rows2_Base BoxFilter3x3_cols16_rows2;
+
+OCL_TEST_P(BoxFilter3x3_cols16_rows2, Mat)
+{
+    for (int j = 0; j < test_loop_times; j++)
+    {
+        random_roi();
+
+        OCL_OFF(cv::boxFilter(src_roi, dst_roi, -1, ksize, anchor, normalize, borderType));
+        OCL_ON(cv::boxFilter(usrc_roi, udst_roi, -1, ksize, anchor, normalize, borderType));
+
+        Near(depth <= CV_32S ? 1 : 3e-3);
+    }
+}
+
+OCL_INSTANTIATE_TEST_CASE_P(ImageProc, BoxFilter3x3_cols16_rows2,
+                            Combine(
+                                Values((MatDepth)CV_8U),
+                                Values((Channels)1),
+                                Values((BorderType)BORDER_CONSTANT,
+                                       (BorderType)BORDER_REPLICATE,
+                                       (BorderType)BORDER_REFLECT,
+                                       (BorderType)BORDER_REFLECT_101),
+                                Bool(),
+                                Values(false) // ROI
+                                )
+                           );
+
 } } // namespace cvtest::ocl
 
 #endif // HAVE_OPENCL
diff --git a/modules/imgproc/test/ocl/test_canny.cpp b/modules/imgproc/test/ocl/test_canny.cpp
index 70e4bb1..c5e0485 100644
--- a/modules/imgproc/test/ocl/test_canny.cpp
+++ b/modules/imgproc/test/ocl/test_canny.cpp
@@ -54,13 +54,13 @@ namespace ocl {
 ////////////////////////////////////////////////////////
 // Canny
 
-IMPLEMENT_PARAM_CLASS(AppertureSize, int)
+IMPLEMENT_PARAM_CLASS(ApertureSize, int)
 IMPLEMENT_PARAM_CLASS(L2gradient, bool)
 IMPLEMENT_PARAM_CLASS(UseRoi, bool)
 
-PARAM_TEST_CASE(Canny, Channels, AppertureSize, L2gradient, UseRoi)
+PARAM_TEST_CASE(Canny, Channels, ApertureSize, L2gradient, UseRoi)
 {
-    int cn, apperture_size;
+    int cn, aperture_size;
     bool useL2gradient, use_roi;
 
     TEST_DECLARE_INPUT_PARAMETER(src);
@@ -69,7 +69,7 @@ PARAM_TEST_CASE(Canny, Channels, AppertureSize, L2gradient, UseRoi)
     virtual void SetUp()
     {
         cn = GET_PARAM(0);
-        apperture_size = GET_PARAM(1);
+        aperture_size = GET_PARAM(1);
         useL2gradient = GET_PARAM(2);
         use_roi = GET_PARAM(3);
     }
@@ -99,14 +99,29 @@ OCL_TEST_P(Canny, Accuracy)
     generateTestData();
 
     const double low_thresh = 50.0, high_thresh = 100.0;
-    double eps = 1e-2;
-#ifdef ANDROID
-    if (cv::ocl::Device::getDefault().isNVidia())
-        eps = 12e-3;
-#endif
+    double eps = 0.03;
 
-    OCL_OFF(cv::Canny(src_roi, dst_roi, low_thresh, high_thresh, apperture_size, useL2gradient));
-    OCL_ON(cv::Canny(usrc_roi, udst_roi, low_thresh, high_thresh, apperture_size, useL2gradient));
+    OCL_OFF(cv::Canny(src_roi, dst_roi, low_thresh, high_thresh, aperture_size, useL2gradient));
+    OCL_ON(cv::Canny(usrc_roi, udst_roi, low_thresh, high_thresh, aperture_size, useL2gradient));
+
+    EXPECT_MAT_SIMILAR(dst_roi, udst_roi, eps);
+    EXPECT_MAT_SIMILAR(dst, udst, eps);
+}
+
+OCL_TEST_P(Canny, AccuracyCustomGradient)
+{
+    generateTestData();
+
+    const double low_thresh = 50.0, high_thresh = 100.0;
+    double eps = 0.03;
+
+    OCL_OFF(cv::Canny(src_roi, dst_roi, low_thresh, high_thresh, aperture_size, useL2gradient));
+    OCL_ON(
+        UMat dx, dy;
+        Sobel(usrc_roi, dx, CV_16S, 1, 0, aperture_size, 1, 0, BORDER_REPLICATE);
+        Sobel(usrc_roi, dy, CV_16S, 0, 1, aperture_size, 1, 0, BORDER_REPLICATE);
+        cv::Canny(dx, dy, udst_roi, low_thresh, high_thresh, useL2gradient);
+    );
 
     EXPECT_MAT_SIMILAR(dst_roi, udst_roi, eps);
     EXPECT_MAT_SIMILAR(dst, udst, eps);
@@ -114,10 +129,12 @@ OCL_TEST_P(Canny, Accuracy)
 
 OCL_INSTANTIATE_TEST_CASE_P(ImgProc, Canny, testing::Combine(
                                 testing::Values(1, 3),
-                                testing::Values(AppertureSize(3), AppertureSize(5)),
+                                testing::Values(ApertureSize(3), ApertureSize(5)),
                                 testing::Values(L2gradient(false), L2gradient(true)),
                                 testing::Values(UseRoi(false), UseRoi(true))));
 
-} } // namespace cvtest::ocl
+} // namespace ocl
+
+} // namespace cvtest
 
 #endif // HAVE_OPENCL
diff --git a/modules/imgproc/test/ocl/test_color.cpp b/modules/imgproc/test/ocl/test_color.cpp
index 160c035..c0218cc 100644
--- a/modules/imgproc/test/ocl/test_color.cpp
+++ b/modules/imgproc/test/ocl/test_color.cpp
@@ -98,7 +98,29 @@ PARAM_TEST_CASE(CvtColor, MatDepth, bool)
             OCL_OFF(cv::cvtColor(src_roi, dst_roi, code, channelsOut));
             OCL_ON(cv::cvtColor(usrc_roi, udst_roi, code, channelsOut));
 
-            Near(threshold);
+            int h_limit = 256;
+            switch (code)
+            {
+            case COLOR_RGB2HLS: case COLOR_BGR2HLS:
+                h_limit = 180;
+            case COLOR_RGB2HLS_FULL: case COLOR_BGR2HLS_FULL:
+            {
+                ASSERT_EQ(dst_roi.type(), udst_roi.type());
+                ASSERT_EQ(dst_roi.size(), udst_roi.size());
+                Mat gold, actual;
+                dst_roi.convertTo(gold, CV_32FC3);
+                udst_roi.getMat(ACCESS_READ).convertTo(actual, CV_32FC3);
+                Mat absdiff1, absdiff2, absdiff3;
+                cv::absdiff(gold, actual, absdiff1);
+                cv::absdiff(gold, actual + h_limit, absdiff2);
+                cv::absdiff(gold, actual - h_limit, absdiff3);
+                Mat diff = cv::min(cv::min(absdiff1, absdiff2), absdiff3);
+                EXPECT_LE(cvtest::norm(diff, NORM_INF), threshold);
+                break;
+            }
+            default:
+                Near(threshold);
+            }
         }
     }
 };
diff --git a/modules/imgproc/test/ocl/test_filters.cpp b/modules/imgproc/test/ocl/test_filters.cpp
index 0c4564e..481edf2 100644
--- a/modules/imgproc/test/ocl/test_filters.cpp
+++ b/modules/imgproc/test/ocl/test_filters.cpp
@@ -165,6 +165,83 @@ OCL_TEST_P(LaplacianTest, Accuracy)
     }
 }
 
+PARAM_TEST_CASE(Deriv3x3_cols16_rows2_Base, MatType,
+                int, // kernel size
+                Size, // dx, dy
+                BorderType, // border type
+                double, // optional parameter
+                bool, // roi or not
+                int)  // width multiplier
+{
+    int type, borderType, ksize;
+    Size size;
+    double param;
+    bool useRoi;
+    int widthMultiple;
+
+    TEST_DECLARE_INPUT_PARAMETER(src);
+    TEST_DECLARE_OUTPUT_PARAMETER(dst);
+
+    virtual void SetUp()
+    {
+        type = GET_PARAM(0);
+        ksize = GET_PARAM(1);
+        size = GET_PARAM(2);
+        borderType = GET_PARAM(3);
+        param = GET_PARAM(4);
+        useRoi = GET_PARAM(5);
+        widthMultiple = GET_PARAM(6);
+    }
+
+    void random_roi()
+    {
+        size = Size(3, 3);
+
+        Size roiSize = randomSize(size.width, MAX_VALUE, size.height, MAX_VALUE);
+        roiSize.width = std::max(size.width + 13, roiSize.width & (~0xf));
+        roiSize.height = std::max(size.height + 1, roiSize.height & (~0x1));
+
+        Border srcBorder = randomBorder(0, useRoi ? MAX_VALUE : 0);
+        randomSubMat(src, src_roi, roiSize, srcBorder, type, 5, 256);
+
+        Border dstBorder = randomBorder(0, useRoi ? MAX_VALUE : 0);
+        randomSubMat(dst, dst_roi, roiSize, dstBorder, type, -60, 70);
+
+        UMAT_UPLOAD_INPUT_PARAMETER(src);
+        UMAT_UPLOAD_OUTPUT_PARAMETER(dst);
+    }
+
+    void Near()
+    {
+        Near(1, false);
+    }
+
+    void Near(double threshold, bool relative)
+    {
+        if (relative)
+            OCL_EXPECT_MATS_NEAR_RELATIVE(dst, threshold);
+        else
+            OCL_EXPECT_MATS_NEAR(dst, threshold);
+    }
+};
+
+typedef Deriv3x3_cols16_rows2_Base Laplacian3_cols16_rows2;
+
+OCL_TEST_P(Laplacian3_cols16_rows2, Accuracy)
+{
+    double scale = param;
+
+    for (int j = 0; j < test_loop_times; j++)
+    {
+        random_roi();
+
+        OCL_OFF(cv::Laplacian(src_roi, dst_roi, -1, ksize, scale, 10, borderType));
+        OCL_ON(cv::Laplacian(usrc_roi, udst_roi, -1, ksize, scale, 10, borderType));
+
+        Near();
+    }
+}
+
 
 /////////////////////////////////////////////////////////////////////////////////////////////////
 // Sobel
@@ -187,6 +264,24 @@ OCL_TEST_P(SobelTest, Mat)
     }
 }
 
+typedef Deriv3x3_cols16_rows2_Base Sobel3x3_cols16_rows2;
+
+OCL_TEST_P(Sobel3x3_cols16_rows2, Mat)
+{
+    int dx = size.width, dy = size.height;
+    double scale = param;
+
+    for (int j = 0; j < test_loop_times; j++)
+    {
+        random_roi();
+
+        OCL_OFF(cv::Sobel(src_roi, dst_roi, -1, dx, dy, ksize, scale, /* delta */0, borderType));
+        OCL_ON(cv::Sobel(usrc_roi, udst_roi, -1, dx, dy, ksize, scale, /* delta */0, borderType));
+
+        Near();
+    }
+}
+
 /////////////////////////////////////////////////////////////////////////////////////////////////
 // Scharr
 
@@ -208,6 +303,24 @@ OCL_TEST_P(ScharrTest, Mat)
     }
 }
 
+typedef Deriv3x3_cols16_rows2_Base Scharr3x3_cols16_rows2;
+
+OCL_TEST_P(Scharr3x3_cols16_rows2, Mat)
+{
+    int dx = size.width, dy = size.height;
+    double scale = param;
+
+    for (int j = 0; j < test_loop_times; j++)
+    {
+        random_roi();
+
+        OCL_OFF(cv::Scharr(src_roi, dst_roi, -1, dx, dy, scale, /* delta */ 0, borderType));
+        OCL_ON(cv::Scharr(usrc_roi, udst_roi, -1, dx, dy, scale, /* delta */ 0, borderType));
+
+        Near();
+    }
+}
+
 /////////////////////////////////////////////////////////////////////////////////////////////////
 // GaussianBlur
 
@@ -225,7 +338,94 @@ OCL_TEST_P(GaussianBlurTest, Mat)
         OCL_OFF(cv::GaussianBlur(src_roi, dst_roi, Size(ksize, ksize), sigma1, sigma2, borderType));
         OCL_ON(cv::GaussianBlur(usrc_roi, udst_roi, Size(ksize, ksize), sigma1, sigma2, borderType));
 
-        Near(CV_MAT_DEPTH(type) >= CV_32F ? 7e-5 : 1, false);
+        Near(CV_MAT_DEPTH(type) >= CV_32F ? 1e-3 : 4, CV_MAT_DEPTH(type) >= CV_32F);
+    }
+}
+
+PARAM_TEST_CASE(GaussianBlur_multicols_Base, MatType,
+                int, // kernel size
+                Size, // dx, dy
+                BorderType, // border type
+                double, // optional parameter
+                bool, // roi or not
+                int)  // width multiplier
+{
+    int type, borderType, ksize;
+    Size size;
+    double param;
+    bool useRoi;
+    int widthMultiple;
+
+    TEST_DECLARE_INPUT_PARAMETER(src);
+    TEST_DECLARE_OUTPUT_PARAMETER(dst);
+
+    virtual void SetUp()
+    {
+        type = GET_PARAM(0);
+        ksize = GET_PARAM(1);
+        size = GET_PARAM(2);
+        borderType = GET_PARAM(3);
+        param = GET_PARAM(4);
+        useRoi = GET_PARAM(5);
+        widthMultiple = GET_PARAM(6);
+    }
+
+    void random_roi()
+    {
+        size = Size(ksize, ksize);
+
+        Size roiSize = randomSize(size.width, MAX_VALUE, size.height, MAX_VALUE);
+        if (ksize == 3)
+        {
+            roiSize.width = std::max((size.width + 15) & 0x10, roiSize.width & (~0xf));
+            roiSize.height = std::max(size.height + 1, roiSize.height & (~0x1));
+        }
+        else if (ksize == 5)
+        {
+            roiSize.width = std::max((size.width + 3) & 0x4, roiSize.width & (~0x3));
+        }
+
+        Border srcBorder = randomBorder(0, useRoi ? MAX_VALUE : 0);
+        randomSubMat(src, src_roi, roiSize, srcBorder, type, 5, 256);
+
+        Border dstBorder = randomBorder(0, useRoi ? MAX_VALUE : 0);
+        randomSubMat(dst, dst_roi, roiSize, dstBorder, type, -60, 70);
+
+        UMAT_UPLOAD_INPUT_PARAMETER(src);
+        UMAT_UPLOAD_OUTPUT_PARAMETER(dst);
+    }
+
+    void Near()
+    {
+        Near(1, false);
+    }
+
+    void Near(double threshold, bool relative)
+    {
+        if (relative)
+            OCL_EXPECT_MATS_NEAR_RELATIVE(dst, threshold);
+        else
+            OCL_EXPECT_MATS_NEAR(dst, threshold);
+    }
+};
+
+typedef GaussianBlur_multicols_Base GaussianBlur_multicols;
+
+OCL_TEST_P(GaussianBlur_multicols, Mat)
+{
+    Size kernelSize(ksize, ksize);
+
+    for (int j = 0; j < test_loop_times; j++)
+    {
+        random_roi();
+
+        double sigma1 = rng.uniform(0.1, 1.0);
+        double sigma2 = j % 2 == 0 ? sigma1 : rng.uniform(0.1, 1.0);
+
+        OCL_OFF(cv::GaussianBlur(src_roi, dst_roi, Size(ksize, ksize), sigma1, sigma2, borderType));
+        OCL_ON(cv::GaussianBlur(usrc_roi, udst_roi, Size(ksize, ksize), sigma1, sigma2, borderType));
+
+        Near(CV_MAT_DEPTH(type) >= CV_32F ? 1e-3 : 4, CV_MAT_DEPTH(type) >= CV_32F);
     }
 }
 
@@ -273,6 +473,85 @@ OCL_TEST_P(Dilate, Mat)
     }
 }
 
+PARAM_TEST_CASE(MorphFilter3x3_cols16_rows2_Base, MatType,
+                int, // kernel size
+                Size, // dx, dy
+                BorderType, // border type
+                double, // optional parameter
+                bool, // roi or not
+                int)  // width multiplier
+{
+    int type, borderType, ksize;
+    Size size;
+    double param;
+    bool useRoi;
+    int widthMultiple;
+
+    TEST_DECLARE_INPUT_PARAMETER(src);
+    TEST_DECLARE_OUTPUT_PARAMETER(dst);
+
+    virtual void SetUp()
+    {
+        type = GET_PARAM(0);
+        ksize = GET_PARAM(1);
+        size = GET_PARAM(2);
+        borderType = GET_PARAM(3);
+        param = GET_PARAM(4);
+        useRoi = GET_PARAM(5);
+        widthMultiple = GET_PARAM(6);
+    }
+
+    void random_roi()
+    {
+        size = Size(3, 3);
+
+        Size roiSize = randomSize(size.width, MAX_VALUE, size.height, MAX_VALUE);
+        roiSize.width = std::max(size.width + 13, roiSize.width & (~0xf));
+        roiSize.height = std::max(size.height + 1, roiSize.height & (~0x1));
+
+        Border srcBorder = randomBorder(0, useRoi ? MAX_VALUE : 0);
+        randomSubMat(src, src_roi, roiSize, srcBorder, type, 5, 256);
+
+        Border dstBorder = randomBorder(0, useRoi ? MAX_VALUE : 0);
+        randomSubMat(dst, dst_roi, roiSize, dstBorder, type, -60, 70);
+
+        UMAT_UPLOAD_INPUT_PARAMETER(src);
+        UMAT_UPLOAD_OUTPUT_PARAMETER(dst);
+    }
+
+    void Near()
+    {
+        Near(1, false);
+    }
+
+    void Near(double threshold, bool relative)
+    {
+        if (relative)
+            OCL_EXPECT_MATS_NEAR_RELATIVE(dst, threshold);
+        else
+            OCL_EXPECT_MATS_NEAR(dst, threshold);
+    }
+};
+
+typedef MorphFilter3x3_cols16_rows2_Base MorphFilter3x3_cols16_rows2;
+
+OCL_TEST_P(MorphFilter3x3_cols16_rows2, Mat)
+{
+    Size kernelSize(ksize, ksize);
+    int iterations = (int)param;
+
+    for (int j = 0; j < test_loop_times; j++)
+    {
+        random_roi();
+        Mat kernel = ksize==0 ? Mat() : randomMat(kernelSize, CV_8UC1, 0, 3);
+
+        OCL_OFF(cv::dilate(src_roi, dst_roi, kernel, Point(-1, -1), iterations) );
+        OCL_ON(cv::dilate(usrc_roi, udst_roi, kernel, Point(-1, -1), iterations) );
+
+        Near();
+    }
+}
+
 /////////////////////////////////////////////////////////////////////////////////////////////////
 // MorphologyEx
 IMPLEMENT_PARAM_CLASS(MorphOp, int)
@@ -384,6 +663,15 @@ OCL_INSTANTIATE_TEST_CASE_P(Filter, LaplacianTest, Combine(
                             Bool(),
                             Values(1))); // not used
 
+OCL_INSTANTIATE_TEST_CASE_P(Filter, Laplacian3_cols16_rows2, Combine(
+                            Values((MatType)CV_8UC1),
+                            Values(3), // kernel size
+                            Values(Size(0, 0)), // not used
+                            FILTER_BORDER_SET_NO_WRAP_NO_ISOLATED,
+                            Values(1.0, 0.2, 3.0), // kernel scale
+                            Bool(),
+                            Values(1))); // not used
+
 OCL_INSTANTIATE_TEST_CASE_P(Filter, SobelTest, Combine(
                             FILTER_TYPES,
                             Values(3, 5), // kernel size
@@ -393,6 +681,15 @@ OCL_INSTANTIATE_TEST_CASE_P(Filter, SobelTest, Combine(
                             Bool(),
                             Values(1))); // not used
 
+OCL_INSTANTIATE_TEST_CASE_P(Filter, Sobel3x3_cols16_rows2, Combine(
+                            Values((MatType)CV_8UC1),
+                            Values(3), // kernel size
+                            Values(Size(1, 0), Size(1, 1), Size(2, 0), Size(2, 1)), // dx, dy
+                            FILTER_BORDER_SET_NO_WRAP_NO_ISOLATED,
+                            Values(0.0), // not used
+                            Bool(),
+                            Values(1))); // not used
+
 OCL_INSTANTIATE_TEST_CASE_P(Filter, ScharrTest, Combine(
                             FILTER_TYPES,
                             Values(0), // not used
@@ -402,6 +699,15 @@ OCL_INSTANTIATE_TEST_CASE_P(Filter, ScharrTest, Combine(
                             Bool(),
                             Values(1))); // not used
 
+OCL_INSTANTIATE_TEST_CASE_P(Filter, Scharr3x3_cols16_rows2, Combine(
+                            FILTER_TYPES,
+                            Values(0), // not used
+                            Values(Size(0, 1), Size(1, 0)), // dx, dy
+                            FILTER_BORDER_SET_NO_WRAP_NO_ISOLATED,
+                            Values(1.0, 0.2), // kernel scale
+                            Bool(),
+                            Values(1))); // not used
+
 OCL_INSTANTIATE_TEST_CASE_P(Filter, GaussianBlurTest, Combine(
                             FILTER_TYPES,
                             Values(3, 5), // kernel size
@@ -411,6 +717,15 @@ OCL_INSTANTIATE_TEST_CASE_P(Filter, GaussianBlurTest, Combine(
                             Bool(),
                             Values(1))); // not used
 
+OCL_INSTANTIATE_TEST_CASE_P(Filter, GaussianBlur_multicols, Combine(
+                            Values((MatType)CV_8UC1),
+                            Values(3, 5), // kernel size
+                            Values(Size(0, 0)), // not used
+                            FILTER_BORDER_SET_NO_WRAP_NO_ISOLATED,
+                            Values(0.0), // not used
+                            Bool(),
+                            Values(1))); // not used
+
 OCL_INSTANTIATE_TEST_CASE_P(Filter, Erode, Combine(
                             Values(CV_8UC1, CV_8UC3, CV_8UC4, CV_32FC1, CV_32FC3, CV_32FC4, CV_64FC1, CV_64FC4),
                             Values(0, 3, 5, 7), // kernel size, 0 means kernel = Mat()
@@ -429,6 +744,15 @@ OCL_INSTANTIATE_TEST_CASE_P(Filter, Dilate, Combine(
                             Bool(),
                             Values(1))); // not used
 
+OCL_INSTANTIATE_TEST_CASE_P(Filter, MorphFilter3x3_cols16_rows2, Combine(
+                            Values((MatType)CV_8UC1),
+                            Values(0, 3), // kernel size, 0 means kernel = Mat()
+                            Values(Size(0, 0)), // not used
+                            Values((BorderType)BORDER_CONSTANT),
+                            Values(1.0, 2.0, 3.0),
+                            Bool(),
+                            Values(1))); // not used
+
 OCL_INSTANTIATE_TEST_CASE_P(Filter, MorphologyEx, Combine(
                             Values(CV_8UC1, CV_8UC3, CV_8UC4, CV_32FC1, CV_32FC3, CV_32FC4),
                             Values(3, 5, 7), // kernel size
diff --git a/modules/imgproc/test/ocl/test_histogram.cpp b/modules/imgproc/test/ocl/test_histogram.cpp
index 6a16efa..b7017c1 100644
--- a/modules/imgproc/test/ocl/test_histogram.cpp
+++ b/modules/imgproc/test/ocl/test_histogram.cpp
@@ -94,7 +94,7 @@ PARAM_TEST_CASE(CalcBackProject, MatDepth, int, bool)
         uimages_roi.resize(N);
     }
 
-    virtual void random_roi()
+    void random_roi()
     {
         Size roiSize = randomSize(1, MAX_VALUE);
 
@@ -233,7 +233,7 @@ PARAM_TEST_CASE(CalcHist, bool)
         useRoi = GET_PARAM(0);
     }
 
-    virtual void random_roi()
+    void random_roi()
     {
         Size roiSize = randomSize(1, MAX_VALUE);
 
diff --git a/modules/imgproc/test/ocl/test_houghlines.cpp b/modules/imgproc/test/ocl/test_houghlines.cpp
index 1f9d802..0367593 100644
--- a/modules/imgproc/test/ocl/test_houghlines.cpp
+++ b/modules/imgproc/test/ocl/test_houghlines.cpp
@@ -40,7 +40,7 @@ PARAM_TEST_CASE(HoughLines, double, double, int)
         threshold = GET_PARAM(2);
     }
 
-    virtual void generateTestData()
+    void generateTestData()
     {
         src_size = randomSize(500, 1920);
         src.create(src_size, CV_8UC1);
@@ -55,7 +55,7 @@ PARAM_TEST_CASE(HoughLines, double, double, int)
         src.copyTo(usrc);
     }
 
-    virtual void readRealTestData()
+    void readRealTestData()
     {
         Mat img = readImage("shared/pic5.png", IMREAD_GRAYSCALE);
         Canny(img, src, 100, 150, 3);
@@ -63,7 +63,7 @@ PARAM_TEST_CASE(HoughLines, double, double, int)
         src.copyTo(usrc);
     }
 
-    virtual void Near(double eps = 0.)
+    void Near(double eps = 0.)
     {
         EXPECT_EQ(dst.size(), udst.size());
 
@@ -124,7 +124,7 @@ PARAM_TEST_CASE(HoughLinesP, int, double, double)
         maxGap = GET_PARAM(2);
     }
 
-    virtual void readRealTestData()
+    void readRealTestData()
     {
         Mat img = readImage("shared/pic5.png", IMREAD_GRAYSCALE);
         Canny(img, src, 50, 200, 3);
@@ -132,7 +132,7 @@ PARAM_TEST_CASE(HoughLinesP, int, double, double)
         src.copyTo(usrc);
     }
 
-    virtual void Near(double eps = 0.)
+    void Near(double eps = 0.)
     {
         Mat lines_gpu = udst.getMat(ACCESS_READ);
 
diff --git a/modules/imgproc/test/ocl/test_imgproc.cpp b/modules/imgproc/test/ocl/test_imgproc.cpp
index d891017..6943fb7 100644
--- a/modules/imgproc/test/ocl/test_imgproc.cpp
+++ b/modules/imgproc/test/ocl/test_imgproc.cpp
@@ -81,7 +81,7 @@ PARAM_TEST_CASE(ImgprocTestBase, MatType,
         useRoi = GET_PARAM(3);
     }
 
-    virtual void random_roi()
+    void random_roi()
     {
         Size roiSize = randomSize(1, MAX_VALUE);
         Border srcBorder = randomBorder(0, useRoi ? MAX_VALUE : 0);
@@ -193,7 +193,7 @@ OCL_TEST_P(EqualizeHist, Mat)
 struct CornerTestBase :
         public ImgprocTestBase
 {
-    virtual void random_roi()
+    void random_roi()
     {
         Mat image = readImageType("../gpu/stereobm/aloe-L.png", type);
         ASSERT_FALSE(image.empty());
@@ -296,7 +296,7 @@ struct Integral :
         useRoi = GET_PARAM(3);
     }
 
-    virtual void random_roi()
+    void random_roi()
     {
         ASSERT_EQ(CV_MAT_CN(type), 1);
 
diff --git a/modules/imgproc/test/ocl/test_match_template.cpp b/modules/imgproc/test/ocl/test_match_template.cpp
index 6cf0fe4..1d3962b 100644
--- a/modules/imgproc/test/ocl/test_match_template.cpp
+++ b/modules/imgproc/test/ocl/test_match_template.cpp
@@ -74,7 +74,7 @@ PARAM_TEST_CASE(MatchTemplate, MatDepth, Channels, MatchTemplType, bool)
         use_roi = GET_PARAM(3);
     }
 
-    virtual void generateTestData()
+    void generateTestData()
     {
         Size image_roiSize = randomSize(2, 100);
         Size templ_roiSize = Size(randomInt(1, image_roiSize.width), randomInt(1, image_roiSize.height));
diff --git a/modules/imgproc/test/ocl/test_medianfilter.cpp b/modules/imgproc/test/ocl/test_medianfilter.cpp
index 74077f6..30c273b 100644
--- a/modules/imgproc/test/ocl/test_medianfilter.cpp
+++ b/modules/imgproc/test/ocl/test_medianfilter.cpp
@@ -67,7 +67,7 @@ PARAM_TEST_CASE(MedianFilter, MatDepth, Channels, int, bool)
         use_roi = GET_PARAM(3);
     }
 
-    virtual void generateTestData()
+    void generateTestData()
     {
         Size roiSize = randomSize(1, MAX_VALUE);
         Border srcBorder = randomBorder(0, use_roi ? MAX_VALUE : 0);
diff --git a/modules/imgproc/test/ocl/test_pyramids.cpp b/modules/imgproc/test/ocl/test_pyramids.cpp
index 5ac8841..07a95bd 100644
--- a/modules/imgproc/test/ocl/test_pyramids.cpp
+++ b/modules/imgproc/test/ocl/test_pyramids.cpp
@@ -134,6 +134,24 @@ OCL_TEST_P(PyrUp, Mat)
     }
 }
 
+typedef PyrTestBase PyrUp_cols2;
+
+OCL_TEST_P(PyrUp_cols2, Mat)
+{
+    for (int j = 0; j < test_loop_times; j++)
+    {
+        Size src_roiSize = randomSize(1, MAX_VALUE);
+        src_roiSize.width += (src_roiSize.width % 2);
+        Size dst_roiSize = Size(2 * src_roiSize.width, 2 * src_roiSize.height);
+        generateTestData(src_roiSize, dst_roiSize);
+
+        OCL_OFF(pyrUp(src_roi, dst_roi, dst_roiSize, borderType));
+        OCL_ON(pyrUp(usrc_roi, udst_roi, dst_roiSize, borderType));
+
+        Near(depth == CV_32F ? 1e-4f : 1.0f);
+    }
+}
+
 OCL_INSTANTIATE_TEST_CASE_P(ImgprocPyr, PyrUp, Combine(
                             Values(CV_8U, CV_16U, CV_16S, CV_32F, CV_64F),
                             Values(1, 2, 3, 4),
@@ -141,6 +159,13 @@ OCL_INSTANTIATE_TEST_CASE_P(ImgprocPyr, PyrUp, Combine(
                             Bool()
                             ));
 
+OCL_INSTANTIATE_TEST_CASE_P(ImgprocPyr, PyrUp_cols2, Combine(
+                            Values((MatDepth)CV_8U),
+                            Values((Channels)1),
+                            Values((BorderType)BORDER_REFLECT_101),
+                            Bool()
+                            ));
+
 } } // namespace cvtest::ocl
 
 #endif // HAVE_OPENCL
diff --git a/modules/imgproc/test/ocl/test_warp.cpp b/modules/imgproc/test/ocl/test_warp.cpp
index da70f73..c69d597 100644
--- a/modules/imgproc/test/ocl/test_warp.cpp
+++ b/modules/imgproc/test/ocl/test_warp.cpp
@@ -113,6 +113,57 @@ PARAM_TEST_CASE(WarpTestBase, MatType, Interpolation, bool, bool)
     }
 };
 
+PARAM_TEST_CASE(WarpTest_cols4_Base, MatType, Interpolation, bool, bool)
+{
+    int type, interpolation;
+    Size dsize;
+    bool useRoi, mapInverse;
+    int depth;
+
+    TEST_DECLARE_INPUT_PARAMETER(src);
+    TEST_DECLARE_OUTPUT_PARAMETER(dst);
+
+    virtual void SetUp()
+    {
+        type = GET_PARAM(0);
+        interpolation = GET_PARAM(1);
+        mapInverse = GET_PARAM(2);
+        useRoi = GET_PARAM(3);
+        depth = CV_MAT_DEPTH(type);
+
+        if (mapInverse)
+            interpolation |= WARP_INVERSE_MAP;
+    }
+
+    void random_roi()
+    {
+        dsize = randomSize(1, MAX_VALUE);
+        dsize.width = ((dsize.width >> 2) + 1) * 4;
+
+        Size roiSize = randomSize(1, MAX_VALUE);
+        Border srcBorder = randomBorder(0, useRoi ? MAX_VALUE : 0);
+        randomSubMat(src, src_roi, roiSize, srcBorder, type, -MAX_VALUE, MAX_VALUE);
+
+        Border dstBorder = randomBorder(0, useRoi ? MAX_VALUE : 0);
+        randomSubMat(dst, dst_roi, dsize, dstBorder, type, -MAX_VALUE, MAX_VALUE);
+
+        UMAT_UPLOAD_INPUT_PARAMETER(src);
+        UMAT_UPLOAD_OUTPUT_PARAMETER(dst);
+    }
+
+    void Near(double threshold = 0.0)
+    {
+        if (depth < CV_32F)
+            EXPECT_MAT_N_DIFF(dst_roi, udst_roi, cvRound(dst_roi.total()*threshold));
+        else
+            OCL_EXPECT_MATS_NEAR_RELATIVE(dst, threshold);
+    }
+};
+
+/////warpAffine
+
+typedef WarpTestBase WarpAffine;
+
 /////warpAffine
 
 typedef WarpTestBase WarpAffine;
@@ -134,6 +185,25 @@ OCL_TEST_P(WarpAffine, Mat)
     }
 }
 
+typedef WarpTest_cols4_Base WarpAffine_cols4;
+
+OCL_TEST_P(WarpAffine_cols4, Mat)
+{
+    for (int j = 0; j < test_loop_times; j++)
+    {
+        double eps = depth < CV_32F ? 0.04 : 0.06;
+        random_roi();
+
+        Mat M = getRotationMatrix2D(Point2f(src_roi.cols / 2.0f, src_roi.rows / 2.0f),
+            rng.uniform(-180.f, 180.f), rng.uniform(0.4f, 2.0f));
+
+        OCL_OFF(cv::warpAffine(src_roi, dst_roi, M, dsize, interpolation));
+        OCL_ON(cv::warpAffine(usrc_roi, udst_roi, M, dsize, interpolation));
+
+        Near(eps);
+    }
+}
+
 //// warpPerspective
 
 typedef WarpTestBase WarpPerspective;
@@ -161,6 +231,30 @@ OCL_TEST_P(WarpPerspective, Mat)
     }
 }
 
+typedef WarpTest_cols4_Base WarpPerspective_cols4;
+
+OCL_TEST_P(WarpPerspective_cols4, Mat)
+{
+    for (int j = 0; j < test_loop_times; j++)
+    {
+        double eps = depth < CV_32F ? 0.03 : 0.06;
+        random_roi();
+
+        float cols = static_cast<float>(src_roi.cols), rows = static_cast<float>(src_roi.rows);
+        float cols2 = cols / 2.0f, rows2 = rows / 2.0f;
+        Point2f sp[] = { Point2f(0.0f, 0.0f), Point2f(cols, 0.0f), Point2f(0.0f, rows), Point2f(cols, rows) };
+        Point2f dp[] = { Point2f(rng.uniform(0.0f, cols2), rng.uniform(0.0f, rows2)),
+            Point2f(rng.uniform(cols2, cols), rng.uniform(0.0f, rows2)),
+            Point2f(rng.uniform(0.0f, cols2), rng.uniform(rows2, rows)),
+            Point2f(rng.uniform(cols2, cols), rng.uniform(rows2, rows)) };
+        Mat M = getPerspectiveTransform(sp, dp);
+
+        OCL_OFF(cv::warpPerspective(src_roi, dst_roi, M, dsize, interpolation));
+        OCL_ON(cv::warpPerspective(usrc_roi, udst_roi, M, dsize, interpolation));
+
+        Near(eps);
+    }
+}
 
 /////////////////////////////////////////////////////////////////////////////////////////////////
 //// resize
@@ -341,12 +435,24 @@ OCL_INSTANTIATE_TEST_CASE_P(ImgprocWarp, WarpAffine, Combine(
                             Bool(),
                             Bool()));
 
+OCL_INSTANTIATE_TEST_CASE_P(ImgprocWarp, WarpAffine_cols4, Combine(
+                            Values((MatType)CV_8UC1),
+                            Values((Interpolation)INTER_NEAREST, (Interpolation)INTER_LINEAR, (Interpolation)INTER_CUBIC),
+                            Bool(),
+                            Bool()));
+
 OCL_INSTANTIATE_TEST_CASE_P(ImgprocWarp, WarpPerspective, Combine(
                             Values(CV_8UC1, CV_8UC3, CV_8UC4, CV_32FC1, CV_32FC3, CV_32FC4),
                             Values((Interpolation)INTER_NEAREST, (Interpolation)INTER_LINEAR, (Interpolation)INTER_CUBIC),
                             Bool(),
                             Bool()));
 
+OCL_INSTANTIATE_TEST_CASE_P(ImgprocWarp, WarpPerspective_cols4, Combine(
+                            Values((MatType)CV_8UC1),
+                            Values((Interpolation)INTER_NEAREST, (Interpolation)INTER_LINEAR, (Interpolation)INTER_CUBIC),
+                            Bool(),
+                            Bool()));
+
 OCL_INSTANTIATE_TEST_CASE_P(ImgprocWarp, Resize, Combine(
                             Values(CV_8UC1, CV_8UC4, CV_16UC2, CV_32FC1, CV_32FC4),
                             Values(0.5, 1.5, 2.0, 0.2),
diff --git a/modules/imgproc/test/test_canny.cpp b/modules/imgproc/test/test_canny.cpp
index 15b9ea5..cee069a 100644
--- a/modules/imgproc/test/test_canny.cpp
+++ b/modules/imgproc/test/test_canny.cpp
@@ -47,7 +47,7 @@ using namespace std;
 class CV_CannyTest : public cvtest::ArrayTest
 {
 public:
-    CV_CannyTest();
+    CV_CannyTest(bool custom_deriv = false);
 
 protected:
     void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
@@ -61,10 +61,13 @@ protected:
     bool use_true_gradient;
     double threshold1, threshold2;
     bool test_cpp;
+    bool test_custom_deriv;
+
+    Mat img;
 };
 
 
-CV_CannyTest::CV_CannyTest()
+CV_CannyTest::CV_CannyTest(bool custom_deriv)
 {
     test_array[INPUT].push_back(NULL);
     test_array[OUTPUT].push_back(NULL);
@@ -75,6 +78,10 @@ CV_CannyTest::CV_CannyTest()
     threshold1 = threshold2 = 0;
 
     test_cpp = false;
+    test_custom_deriv = custom_deriv;
+
+    const char imgPath[] = "shared/fruits.png";
+    img = cv::imread(cvtest::TS::ptr()->get_data_path() + imgPath, IMREAD_GRAYSCALE);
 }
 
 
@@ -99,6 +106,9 @@ void CV_CannyTest::get_test_array_types_and_sizes( int test_case_idx,
 
     use_true_gradient = cvtest::randInt(rng) % 2 != 0;
     test_cpp = (cvtest::randInt(rng) & 256) == 0;
+
+    ts->printf(cvtest::TS::LOG, "Canny(size = %d x %d, aperture_size = %d, threshold1 = %g, threshold2 = %g, L2 = %s) test_cpp = %s (test case #%d)\n",
+        sizes[0][0].width, sizes[0][0].height, aperture_size, threshold1, threshold2, use_true_gradient ? "TRUE" : "FALSE", test_cpp ? "TRUE" : "FALSE", test_case_idx);
 }
 
 
@@ -107,8 +117,21 @@ int CV_CannyTest::prepare_test_case( int test_case_idx )
     int code = cvtest::ArrayTest::prepare_test_case( test_case_idx );
     if( code > 0 )
     {
+        RNG& rng = ts->get_rng();
         Mat& src = test_mat[INPUT][0];
-        GaussianBlur(src, src, Size(11, 11), 5, 5);
+        //GaussianBlur(src, src, Size(11, 11), 5, 5);
+        if(src.cols > img.cols || src.rows > img.rows)
+            resize(img, src, src.size());
+        else
+            img(
+                Rect(
+                    cvtest::randInt(rng) % (img.cols-src.cols),
+                    cvtest::randInt(rng) % (img.rows-src.rows),
+                    src.cols,
+                    src.rows
+                )
+            ).copyTo(src);
+        GaussianBlur(src, src, Size(5, 5), 0);
     }
 
     return code;
@@ -123,9 +146,24 @@ double CV_CannyTest::get_success_error_level( int /*test_case_idx*/, int /*i*/,
 
 void CV_CannyTest::run_func()
 {
-    if(!test_cpp)
+    if (test_custom_deriv)
+    {
+        cv::Mat _out = cv::cvarrToMat(test_array[OUTPUT][0]);
+        cv::Mat src = cv::cvarrToMat(test_array[INPUT][0]);
+        cv::Mat dx, dy;
+        int m = aperture_size;
+        Point anchor(m/2, m/2);
+        Mat dxkernel = cvtest::calcSobelKernel2D( 1, 0, m, 0 );
+        Mat dykernel = cvtest::calcSobelKernel2D( 0, 1, m, 0 );
+        cvtest::filter2D(src, dx, CV_16S, dxkernel, anchor, 0, BORDER_REPLICATE);
+        cvtest::filter2D(src, dy, CV_16S, dykernel, anchor, 0, BORDER_REPLICATE);
+        cv::Canny(dx, dy, _out, threshold1, threshold2, use_true_gradient);
+    }
+    else if(!test_cpp)
+    {
         cvCanny( test_array[INPUT][0], test_array[OUTPUT][0], threshold1, threshold2,
                 aperture_size + (use_true_gradient ? CV_CANNY_L2_GRADIENT : 0));
+    }
     else
     {
         cv::Mat _out = cv::cvarrToMat(test_array[OUTPUT][0]);
@@ -283,5 +321,109 @@ int CV_CannyTest::validate_test_results( int test_case_idx )
 }
 
 TEST(Imgproc_Canny, accuracy) { CV_CannyTest test; test.safe_run(); }
+TEST(Imgproc_Canny, accuracy_deriv) { CV_CannyTest test(true); test.safe_run(); }
+
+
+/*
+ * Comparing OpenVX based implementation with the main one
+*/
+
+#ifndef IMPLEMENT_PARAM_CLASS
+#define IMPLEMENT_PARAM_CLASS(name, type) \
+    class name \
+    { \
+    public: \
+        name ( type arg = type ()) : val_(arg) {} \
+        operator type () const {return val_;} \
+    private: \
+        type val_; \
+    }; \
+    inline void PrintTo( name param, std::ostream* os) \
+    { \
+        *os << #name <<  "(" << testing::PrintToString(static_cast< type >(param)) << ")"; \
+    }
+#endif // IMPLEMENT_PARAM_CLASS
+
+IMPLEMENT_PARAM_CLASS(ImagePath, string)
+IMPLEMENT_PARAM_CLASS(ApertureSize, int)
+IMPLEMENT_PARAM_CLASS(L2gradient, bool)
+
+PARAM_TEST_CASE(CannyVX, ImagePath, ApertureSize, L2gradient)
+{
+    string imgPath;
+    int kSize;
+    bool useL2;
+    Mat src, dst;
+
+    virtual void SetUp()
+    {
+        imgPath = GET_PARAM(0);
+        kSize = GET_PARAM(1);
+        useL2 = GET_PARAM(2);
+    }
+
+    void loadImage()
+    {
+        src = cv::imread(cvtest::TS::ptr()->get_data_path() + imgPath, IMREAD_GRAYSCALE);
+        ASSERT_FALSE(src.empty()) << "cann't load image: " << imgPath;
+    }
+};
+
+TEST_P(CannyVX, Accuracy)
+{
+    if(haveOpenVX())
+    {
+        loadImage();
+
+        setUseOpenVX(false);
+        Mat canny;
+        cv::Canny(src, canny, 100, 150, 3);
+
+        setUseOpenVX(true);
+        Mat cannyVX;
+        cv::Canny(src, cannyVX, 100, 150, 3);
+
+        // 'smart' diff check (excluding isolated pixels)
+        Mat diff, diff1;
+        absdiff(canny, cannyVX, diff);
+        boxFilter(diff, diff1, -1, Size(3,3));
+        const int minPixelsAroud = 3; // empirical number
+        diff1 = diff1 > 255/9 * minPixelsAroud;
+        erode(diff1, diff1, Mat());
+        double error = cv::norm(diff1, NORM_L1) / 255;
+        const int maxError = std::min(10, diff.size().area()/100); // empirical number
+        if(error > maxError)
+        {
+            string outPath =
+                    string("CannyVX-diff-") +
+                    imgPath + '-' +
+                    'k' + char(kSize+'0') + '-' +
+                    (useL2 ? "l2" : "l1");
+            std::replace(outPath.begin(), outPath.end(), '/', '_');
+            std::replace(outPath.begin(), outPath.end(), '\\', '_');
+            std::replace(outPath.begin(), outPath.end(), '.', '_');
+            imwrite(outPath+".png", diff);
+        }
+        ASSERT_LE(error, maxError);
+
+    }
+}
+
+    INSTANTIATE_TEST_CASE_P(
+                ImgProc, CannyVX,
+                testing::Combine(
+                    testing::Values(
+                        string("shared/baboon.png"),
+                        string("shared/fruits.png"),
+                        string("shared/lena.png"),
+                        string("shared/pic1.png"),
+                        string("shared/pic3.png"),
+                        string("shared/pic5.png"),
+                        string("shared/pic6.png")
+                    ),
+                    testing::Values(ApertureSize(3), ApertureSize(5)),
+                    testing::Values(L2gradient(false), L2gradient(true))
+                )
+    );
 
 /* End of file. */
diff --git a/modules/imgproc/test/test_connectedcomponents.cpp b/modules/imgproc/test/test_connectedcomponents.cpp
index dd4d833..d1c7b6a 100644
--- a/modules/imgproc/test/test_connectedcomponents.cpp
+++ b/modules/imgproc/test/test_connectedcomponents.cpp
@@ -42,6 +42,7 @@
 
 #include "test_precomp.hpp"
 #include <string>
+#include <vector>
 
 using namespace cv;
 using namespace std;
@@ -58,49 +59,81 @@ protected:
 CV_ConnectedComponentsTest::CV_ConnectedComponentsTest() {}
 CV_ConnectedComponentsTest::~CV_ConnectedComponentsTest() {}
 
+// This function force a row major order for the labels
+void normalizeLabels(Mat1i& imgLabels, int iNumLabels) {
+    vector<int> vecNewLabels(iNumLabels + 1, 0);
+    int iMaxNewLabel = 0;
+
+    for (int r = 0; r<imgLabels.rows; ++r) {
+        for (int c = 0; c<imgLabels.cols; ++c) {
+            int iCurLabel = imgLabels(r, c);
+            if (iCurLabel>0) {
+                if (vecNewLabels[iCurLabel] == 0) {
+                    vecNewLabels[iCurLabel] = ++iMaxNewLabel;
+                }
+                imgLabels(r, c) = vecNewLabels[iCurLabel];
+            }
+        }
+    }
+}
+
+
 void CV_ConnectedComponentsTest::run( int /* start_from */)
 {
+
+    int ccltype[] = { cv::CCL_WU, cv::CCL_DEFAULT, cv::CCL_GRANA };
+
     string exp_path = string(ts->get_data_path()) + "connectedcomponents/ccomp_exp.png";
     Mat exp = imread(exp_path, 0);
     Mat orig = imread(string(ts->get_data_path()) + "connectedcomponents/concentric_circles.png", 0);
 
     if (orig.empty())
     {
-        ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_TEST_DATA );
+        ts->set_failed_test_info(cvtest::TS::FAIL_INVALID_TEST_DATA);
         return;
     }
 
     Mat bw = orig > 128;
-    Mat labelImage;
-    int nLabels = connectedComponents(bw, labelImage, 8, CV_32S);
-
-    for(int r = 0; r < labelImage.rows; ++r){
-        for(int c = 0; c < labelImage.cols; ++c){
-            int l = labelImage.at<int>(r, c);
-            bool pass = l >= 0 && l <= nLabels;
-            if(!pass){
-                ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
-                return;
+
+    for (uint cclt = 0; cclt < sizeof(ccltype)/sizeof(int); ++cclt)
+    {
+
+        Mat1i labelImage;
+        int nLabels = connectedComponents(bw, labelImage, 8, CV_32S, ccltype[cclt]);
+
+        normalizeLabels(labelImage, nLabels);
+
+        // Validate test results
+        for (int r = 0; r < labelImage.rows; ++r){
+            for (int c = 0; c < labelImage.cols; ++c){
+                int l = labelImage.at<int>(r, c);
+                bool pass = l >= 0 && l <= nLabels;
+                if (!pass){
+                    ts->set_failed_test_info(cvtest::TS::FAIL_INVALID_OUTPUT);
+                    return;
+                }
             }
         }
-    }
 
-    if( exp.empty() || orig.size() != exp.size() )
-    {
-        imwrite(exp_path, labelImage);
-        exp = labelImage;
-    }
+        if (exp.empty() || orig.size() != exp.size())
+        {
+            imwrite(exp_path, labelImage);
+            exp = labelImage;
+        }
+
+        if (0 != cvtest::norm(labelImage > 0, exp > 0, NORM_INF))
+        {
+            ts->set_failed_test_info(cvtest::TS::FAIL_MISMATCH);
+            return;
+        }
+        if (nLabels != cvtest::norm(labelImage, NORM_INF) + 1)
+        {
+            ts->set_failed_test_info(cvtest::TS::FAIL_MISMATCH);
+            return;
+        }
 
-    if (0 != cvtest::norm(labelImage > 0, exp > 0, NORM_INF))
-    {
-        ts->set_failed_test_info( cvtest::TS::FAIL_MISMATCH );
-        return;
-    }
-    if (nLabels != cvtest::norm(labelImage, NORM_INF)+1)
-    {
-        ts->set_failed_test_info( cvtest::TS::FAIL_MISMATCH );
-        return;
     }
+
     ts->set_failed_test_info(cvtest::TS::OK);
 }
 
diff --git a/modules/imgproc/test/test_contours.cpp b/modules/imgproc/test/test_contours.cpp
index d8d51f2..d5c4e44 100644
--- a/modules/imgproc/test/test_contours.cpp
+++ b/modules/imgproc/test/test_contours.cpp
@@ -63,13 +63,24 @@ protected:
     int blob_count, max_log_blob_count;
     int retr_mode, approx_method;
 
-    int min_log_img_size, max_log_img_size;
+    int min_log_img_width, max_log_img_width;
+    int min_log_img_height, max_log_img_height;
     CvSize img_size;
     int count, count2;
 
     IplImage* img[NUM_IMG];
     CvMemStorage* storage;
     CvSeq *contours, *contours2, *chain;
+
+    static const bool useVeryWideImages =
+#if SIZE_MAX <= 0xffffffff
+        // 32-bit: don't even try the very wide images
+        false
+#else
+        // 64-bit: test with very wide images
+        true
+#endif
+        ;
 };
 
 
@@ -77,13 +88,16 @@ CV_FindContourTest::CV_FindContourTest()
 {
     int i;
 
-    test_case_count    = 300;
+    test_case_count    = useVeryWideImages ? 10 : 300;
     min_blob_size      = 1;
     max_blob_size      = 50;
     max_log_blob_count = 10;
 
-    min_log_img_size   = 3;
-    max_log_img_size   = 10;
+    min_log_img_width  = useVeryWideImages ? 17 : 3;
+    max_log_img_width  = useVeryWideImages ? 17 : 10;
+
+    min_log_img_height = 3;
+    max_log_img_height = 10;
 
     for( i = 0; i < NUM_IMG; i++ )
         img[i] = 0;
@@ -122,8 +136,10 @@ int CV_FindContourTest::read_params( CvFileStorage* fs )
     min_blob_size      = cvReadInt( find_param( fs, "min_blob_size" ), min_blob_size );
     max_blob_size      = cvReadInt( find_param( fs, "max_blob_size" ), max_blob_size );
     max_log_blob_count = cvReadInt( find_param( fs, "max_log_blob_count" ), max_log_blob_count );
-    min_log_img_size   = cvReadInt( find_param( fs, "min_log_img_size" ), min_log_img_size );
-    max_log_img_size   = cvReadInt( find_param( fs, "max_log_img_size" ), max_log_img_size );
+    min_log_img_width  = cvReadInt( find_param( fs, "min_log_img_width" ), min_log_img_width );
+    max_log_img_width  = cvReadInt( find_param( fs, "max_log_img_width" ), max_log_img_width );
+    min_log_img_height = cvReadInt( find_param( fs, "min_log_img_height"), min_log_img_height );
+    max_log_img_height = cvReadInt( find_param( fs, "max_log_img_height"), max_log_img_height );
 
     min_blob_size = cvtest::clipInt( min_blob_size, 1, 100 );
     max_blob_size = cvtest::clipInt( max_blob_size, 1, 100 );
@@ -133,11 +149,16 @@ int CV_FindContourTest::read_params( CvFileStorage* fs )
 
     max_log_blob_count = cvtest::clipInt( max_log_blob_count, 1, 10 );
 
-    min_log_img_size = cvtest::clipInt( min_log_img_size, 1, 10 );
-    max_log_img_size = cvtest::clipInt( max_log_img_size, 1, 10 );
+    min_log_img_width  = cvtest::clipInt( min_log_img_width, 1, useVeryWideImages ? 17 : 10 );
+    min_log_img_width  = cvtest::clipInt( max_log_img_width, 1, useVeryWideImages ? 17 : 10 );
+    min_log_img_height = cvtest::clipInt( min_log_img_height, 1, 10 );
+    min_log_img_height = cvtest::clipInt( max_log_img_height, 1, 10 );
+
+    if( min_log_img_width > max_log_img_width )
+        std::swap( min_log_img_width, max_log_img_width );
 
-    if( min_log_img_size > max_log_img_size )
-        CV_SWAP( min_log_img_size, max_log_img_size, t );
+    if (min_log_img_height > max_log_img_height)
+        std::swap(min_log_img_height, max_log_img_height);
 
     return 0;
 }
@@ -215,9 +236,9 @@ int CV_FindContourTest::prepare_test_case( int test_case_idx )
     blob_count = cvRound(exp(cvtest::randReal(rng)*max_log_blob_count*CV_LOG2));
 
     img_size.width = cvRound(exp((cvtest::randReal(rng)*
-        (max_log_img_size - min_log_img_size) + min_log_img_size)*CV_LOG2));
+        (max_log_img_width - min_log_img_width) + min_log_img_width)*CV_LOG2));
     img_size.height = cvRound(exp((cvtest::randReal(rng)*
-        (max_log_img_size - min_log_img_size) + min_log_img_size)*CV_LOG2));
+        (max_log_img_height - min_log_img_height) + min_log_img_height)*CV_LOG2));
 
     approx_method = cvtest::randInt( rng ) % 4 + 1;
     retr_mode = cvtest::randInt( rng ) % 4;
@@ -389,47 +410,6 @@ _exit_:
 
 TEST(Imgproc_FindContours, accuracy) { CV_FindContourTest test; test.safe_run(); }
 
-TEST(Core_Drawing, _914)
-{
-    const int rows = 256;
-    const int cols = 256;
-
-    Mat img(rows, cols, CV_8UC1, Scalar(255));
-
-    line(img, Point(0, 10), Point(255, 10), Scalar(0), 2, 4);
-    line(img, Point(-5, 20), Point(260, 20), Scalar(0), 2, 4);
-    line(img, Point(10, 0), Point(10, 255), Scalar(0), 2, 4);
-
-    double x0 = 0.0/pow(2.0, -2.0);
-    double x1 = 255.0/pow(2.0, -2.0);
-    double y = 30.5/pow(2.0, -2.0);
-
-    line(img, Point(int(x0), int(y)), Point(int(x1), int(y)), Scalar(0), 2, 4, 2);
-
-    int pixelsDrawn = rows*cols - countNonZero(img);
-    ASSERT_EQ( (3*rows + cols)*3 - 3*9, pixelsDrawn);
-}
-
-TEST(Core_Drawing, polylines_empty)
-{
-    Mat img(100, 100, CV_8UC1, Scalar(0));
-    vector<Point> pts; // empty
-    polylines(img, pts, false, Scalar(255));
-    int cnt = countNonZero(img);
-    ASSERT_EQ(cnt, 0);
-}
-
-TEST(Core_Drawing, polylines)
-{
-    Mat img(100, 100, CV_8UC1, Scalar(0));
-    vector<Point> pts;
-    pts.push_back(Point(0, 0));
-    pts.push_back(Point(20, 0));
-    polylines(img, pts, false, Scalar(255));
-    int cnt = countNonZero(img);
-    ASSERT_EQ(cnt, 21);
-}
-
 //rotate/flip a quadrant appropriately
 static void rot(int n, int *x, int *y, int rx, int ry)
 {
@@ -483,10 +463,26 @@ TEST(Imgproc_FindContours, hilbert)
     img.setTo(Scalar::all(0));
 
     drawContours(img, contours, 0, Scalar::all(255), 1);
-    //imshow("hilbert", img);
-    //waitKey();
+
     ASSERT_EQ(1, (int)contours.size());
     ASSERT_EQ(9832, (int)contours[0].size());
 }
 
+TEST(Imgproc_FindContours, border)
+{
+    Mat img;
+    copyMakeBorder(Mat::zeros(8, 10, CV_8U), img, 1, 1, 1, 1, BORDER_CONSTANT, Scalar(1));
+
+    std::vector<std::vector<cv::Point> > contours;
+    findContours(img, contours, RETR_LIST, CHAIN_APPROX_NONE);
+
+    Mat img_draw_contours = Mat::zeros(img.size(), CV_8U);
+    for (size_t cpt = 0; cpt < contours.size(); cpt++)
+    {
+      drawContours(img_draw_contours, contours, static_cast<int>(cpt), cv::Scalar(255));
+    }
+
+    ASSERT_TRUE(norm(img - img_draw_contours, NORM_INF) == 0.0);
+}
+
 /* End of file. */
diff --git a/modules/imgproc/test/test_convhull.cpp b/modules/imgproc/test/test_convhull.cpp
index 116a4ae..fdca2d4 100644
--- a/modules/imgproc/test/test_convhull.cpp
+++ b/modules/imgproc/test/test_convhull.cpp
@@ -1913,4 +1913,61 @@ TEST(Imgproc_ContourMoments, accuracy) { CV_ContourMomentsTest test; test.safe_r
 TEST(Imgproc_ContourPerimeterSlice, accuracy) { CV_PerimeterAreaSliceTest test; test.safe_run(); }
 TEST(Imgproc_FitEllipse, small) { CV_FitEllipseSmallTest test; test.safe_run(); }
 
+
+
+PARAM_TEST_CASE(ConvexityDefects_regression_5908, bool, int)
+{
+public:
+    int start_index;
+    bool clockwise;
+
+    Mat contour;
+
+    virtual void SetUp()
+    {
+        clockwise = GET_PARAM(0);
+        start_index = GET_PARAM(1);
+
+        const int N = 11;
+        const Point2i points[N] = {
+            Point2i(154, 408),
+            Point2i(45, 223),
+            Point2i(115, 275), // inner
+            Point2i(104, 166),
+            Point2i(154, 256), // inner
+            Point2i(169, 144),
+            Point2i(185, 256), // inner
+            Point2i(235, 170),
+            Point2i(240, 320), // inner
+            Point2i(330, 287),
+            Point2i(224, 390)
+        };
+
+        contour = Mat(N, 1, CV_32SC2);
+        for (int i = 0; i < N; i++)
+        {
+            contour.at<Point2i>(i) = (!clockwise) // image and convexHull coordinate systems are different
+                    ? points[(start_index + i) % N]
+                    : points[N - 1 - ((start_index + i) % N)];
+        }
+    }
+};
+
+TEST_P(ConvexityDefects_regression_5908, simple)
+{
+    std::vector<int> hull;
+    cv::convexHull(contour, hull, clockwise, false);
+
+    std::vector<Vec4i> result;
+    cv::convexityDefects(contour, hull, result);
+
+    EXPECT_EQ(4, (int)result.size());
+}
+
+INSTANTIATE_TEST_CASE_P(Imgproc, ConvexityDefects_regression_5908,
+        testing::Combine(
+                testing::Bool(),
+                testing::Values(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
+        ));
+
 /* End of file. */
diff --git a/modules/imgproc/test/test_drawing.cpp b/modules/imgproc/test/test_drawing.cpp
new file mode 100644
index 0000000..1d6a2a8
--- /dev/null
+++ b/modules/imgproc/test/test_drawing.cpp
@@ -0,0 +1,729 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+//  By downloading, copying, installing or using the software you agree to this license.
+//  If you do not agree to this license, do not download, install,
+//  copy or use the software.
+//
+//
+//                          License Agreement
+//                For Open Source Computer Vision Library
+//
+// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
+// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+//   * Redistribution's of source code must retain the above copyright notice,
+//     this list of conditions and the following disclaimer.
+//
+//   * Redistribution's in binary form must reproduce the above copyright notice,
+//     this list of conditions and the following disclaimer in the documentation
+//     and/or other materials provided with the distribution.
+//
+//   * The name of the copyright holders may not be used to endorse or promote products
+//     derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "test_precomp.hpp"
+
+namespace {
+
+using namespace std;
+using namespace cv;
+
+//#define DRAW_TEST_IMAGE
+
+class CV_DrawingTest : public cvtest::BaseTest
+{
+public:
+    CV_DrawingTest(){}
+protected:
+    void run( int );
+    virtual void draw( Mat& img ) = 0;
+    virtual int checkLineIterator( Mat& img) = 0;
+};
+
+void CV_DrawingTest::run( int )
+{
+    Mat testImg, valImg;
+    const string fname = "../highgui/drawing/image.png";
+    string path = ts->get_data_path(), filename;
+    filename = path + fname;
+
+    draw( testImg );
+
+    valImg = imread( filename );
+    if( valImg.empty() )
+    {
+        //imwrite( filename, testImg );
+        ts->printf( ts->LOG, "test image can not be read");
+#ifdef HAVE_PNG
+        ts->set_failed_test_info(cvtest::TS::FAIL_INVALID_TEST_DATA);
+#else
+        ts->printf( ts->LOG, "PNG image support is not available");
+        ts->set_failed_test_info(cvtest::TS::OK);
+#endif
+        return;
+    }
+    else
+    {
+        // image should match exactly
+        float err = (float)cvtest::norm( testImg, valImg, NORM_L1 );
+        float Eps = 1;
+        if( err > Eps)
+        {
+            ts->printf( ts->LOG, "NORM_L1 between testImg and valImg is equal %f (larger than %f)\n", err, Eps );
+            ts->set_failed_test_info(cvtest::TS::FAIL_BAD_ACCURACY);
+        }
+        else
+        {
+            ts->set_failed_test_info(checkLineIterator( testImg ));
+        }
+    }
+    ts->set_failed_test_info(cvtest::TS::OK);
+}
+
+class CV_DrawingTest_CPP : public CV_DrawingTest
+{
+public:
+    CV_DrawingTest_CPP() {}
+protected:
+    virtual void draw( Mat& img );
+    virtual int checkLineIterator( Mat& img);
+};
+
+void CV_DrawingTest_CPP::draw( Mat& img )
+{
+    Size imgSize( 600, 400 );
+    img.create( imgSize, CV_8UC3 );
+
+    vector<Point> polyline(4);
+    polyline[0] = Point(0, 0);
+    polyline[1] = Point(imgSize.width, 0);
+    polyline[2] = Point(imgSize.width, imgSize.height);
+    polyline[3] = Point(0, imgSize.height);
+    const Point* pts = &polyline[0];
+    int n = (int)polyline.size();
+    fillPoly( img, &pts, &n, 1, Scalar::all(255) );
+
+    Point p1(1,1), p2(3,3);
+    if( clipLine(Rect(0,0,imgSize.width,imgSize.height), p1, p2) && clipLine(imgSize, p1, p2) )
+        circle( img, Point(300,100), 40, Scalar(0,0,255), 3 ); // draw
+
+    p2 = Point(3,imgSize.height+1000);
+    if( clipLine(Rect(0,0,imgSize.width,imgSize.height), p1, p2) && clipLine(imgSize, p1, p2) )
+        circle( img, Point(500,300), 50, cvColorToScalar(255,CV_8UC3), 5, 8, 1 ); // draw
+
+    p1 = Point(imgSize.width,1), p2 = Point(imgSize.width,3);
+    if( clipLine(Rect(0,0,imgSize.width,imgSize.height), p1, p2) && clipLine(imgSize, p1, p2) )
+        circle( img, Point(390,100), 10, Scalar(0,0,255), 3 ); // not draw
+
+    p1 = Point(imgSize.width-1,1), p2 = Point(imgSize.width,3);
+    if( clipLine(Rect(0,0,imgSize.width,imgSize.height), p1, p2) && clipLine(imgSize, p1, p2) )
+        ellipse( img, Point(390,100), Size(20,30), 60, 0, 220.0, Scalar(0,200,0), 4 ); //draw
+
+    ellipse( img, RotatedRect(Point(100,200),Size(200,100),160), Scalar(200,200,255), 5 );
+
+    polyline.clear();
+    ellipse2Poly( Point(430,180), Size(100,150), 30, 0, 150, 20, polyline );
+    pts = &polyline[0];
+    n = (int)polyline.size();
+    polylines( img, &pts, &n, 1, false, Scalar(0,0,150), 4, CV_AA );
+    n = 0;
+    for( vector<Point>::const_iterator it = polyline.begin(); n < (int)polyline.size()-1; ++it, n++ )
+    {
+        line( img, *it, *(it+1), Scalar(50,250,100));
+    }
+
+    polyline.clear();
+    ellipse2Poly( Point(500,300), Size(50,80), 0, 0, 180, 10, polyline );
+    pts = &polyline[0];
+    n = (int)polyline.size();
+    polylines( img, &pts, &n, 1, true, Scalar(100,200,100), 20 );
+    fillConvexPoly( img, pts, n, Scalar(0, 80, 0) );
+
+    polyline.resize(8);
+    // external rectengular
+    polyline[0] = Point(0, 0);
+    polyline[1] = Point(80, 0);
+    polyline[2] = Point(80, 80);
+    polyline[3] = Point(0, 80);
+    // internal rectangular
+    polyline[4] = Point(20, 20);
+    polyline[5] = Point(60, 20);
+    polyline[6] = Point(60, 60);
+    polyline[7] = Point(20, 60);
+    const Point* ppts[] = {&polyline[0], &polyline[0]+4};
+    int pn[] = {4, 4};
+    fillPoly( img, ppts, pn, 2, Scalar(100, 100, 0), 8, 0, Point(500, 20) );
+
+    rectangle( img, Point(0, 300), Point(50, 398), Scalar(0,0,255) );
+
+    string text1 = "OpenCV";
+    int baseline = 0, thickness = 3, fontFace = FONT_HERSHEY_SCRIPT_SIMPLEX;
+    float fontScale = 2;
+    Size textSize = getTextSize( text1, fontFace, fontScale, thickness, &baseline);
+    baseline += thickness;
+    Point textOrg((img.cols - textSize.width)/2, (img.rows + textSize.height)/2);
+    rectangle(img, textOrg + Point(0, baseline), textOrg + Point(textSize.width, -textSize.height), Scalar(0,0,255));
+    line(img, textOrg + Point(0, thickness), textOrg + Point(textSize.width, thickness), Scalar(0, 0, 255));
+    putText(img, text1, textOrg, fontFace, fontScale, Scalar(150,0,150), thickness, 8);
+
+    string text2 = "abcdefghijklmnopqrstuvwxyz1234567890";
+    Scalar color(200,0,0);
+    fontScale = 0.5, thickness = 1;
+    int dist = 5;
+
+    textSize = getTextSize( text2, FONT_HERSHEY_SIMPLEX, fontScale, thickness, &baseline);
+    textOrg = Point(5,5)+Point(0,textSize.height+dist);
+    putText(img, text2, textOrg, FONT_HERSHEY_SIMPLEX, fontScale, color, thickness, CV_AA);
+
+    fontScale = 1;
+    textSize = getTextSize( text2, FONT_HERSHEY_PLAIN, fontScale, thickness, &baseline);
+    textOrg += Point(0,textSize.height+dist);
+    putText(img, text2, textOrg, FONT_HERSHEY_PLAIN, fontScale, color, thickness, CV_AA);
+
+    fontScale = 0.5;
+    textSize = getTextSize( text2, FONT_HERSHEY_DUPLEX, fontScale, thickness, &baseline);
+    textOrg += Point(0,textSize.height+dist);
+    putText(img, text2, textOrg, FONT_HERSHEY_DUPLEX, fontScale, color, thickness, CV_AA);
+
+    textSize = getTextSize( text2, FONT_HERSHEY_COMPLEX, fontScale, thickness, &baseline);
+    textOrg += Point(0,textSize.height+dist);
+    putText(img, text2, textOrg, FONT_HERSHEY_COMPLEX, fontScale, color, thickness, CV_AA);
+
+    textSize = getTextSize( text2, FONT_HERSHEY_TRIPLEX, fontScale, thickness, &baseline);
+    textOrg += Point(0,textSize.height+dist);
+    putText(img, text2, textOrg, FONT_HERSHEY_TRIPLEX, fontScale, color, thickness, CV_AA);
+
+    fontScale = 1;
+    textSize = getTextSize( text2, FONT_HERSHEY_COMPLEX_SMALL, fontScale, thickness, &baseline);
+    textOrg += Point(0,180) + Point(0,textSize.height+dist);
+    putText(img, text2, textOrg, FONT_HERSHEY_COMPLEX_SMALL, fontScale, color, thickness, CV_AA);
+
+    textSize = getTextSize( text2, FONT_HERSHEY_SCRIPT_SIMPLEX, fontScale, thickness, &baseline);
+    textOrg += Point(0,textSize.height+dist);
+    putText(img, text2, textOrg, FONT_HERSHEY_SCRIPT_SIMPLEX, fontScale, color, thickness, CV_AA);
+
+    textSize = getTextSize( text2, FONT_HERSHEY_SCRIPT_COMPLEX, fontScale, thickness, &baseline);
+    textOrg += Point(0,textSize.height+dist);
+    putText(img, text2, textOrg, FONT_HERSHEY_SCRIPT_COMPLEX, fontScale, color, thickness, CV_AA);
+
+    dist = 15, fontScale = 0.5;
+    textSize = getTextSize( text2, FONT_ITALIC, fontScale, thickness, &baseline);
+    textOrg += Point(0,textSize.height+dist);
+    putText(img, text2, textOrg, FONT_ITALIC, fontScale, color, thickness, CV_AA);
+}
+
+int CV_DrawingTest_CPP::checkLineIterator( Mat& img )
+{
+    LineIterator it( img, Point(0,300), Point(1000, 300) );
+    for(int i = 0; i < it.count; ++it, i++ )
+    {
+        Vec3b v = (Vec3b)(*(*it)) - img.at<Vec3b>(300,i);
+        float err = (float)cvtest::norm( v, NORM_L2 );
+        if( err != 0 )
+        {
+            ts->printf( ts->LOG, "LineIterator works incorrect" );
+            ts->set_failed_test_info(cvtest::TS::FAIL_INVALID_OUTPUT);
+        }
+    }
+    ts->set_failed_test_info(cvtest::TS::OK);
+    return 0;
+}
+
+class CV_DrawingTest_C : public CV_DrawingTest
+{
+public:
+    CV_DrawingTest_C() {}
+protected:
+    virtual void draw( Mat& img );
+    virtual int checkLineIterator( Mat& img);
+};
+
+void CV_DrawingTest_C::draw( Mat& _img )
+{
+    CvSize imgSize = cvSize(600, 400);
+    _img.create( imgSize, CV_8UC3 );
+    CvMat img = _img;
+
+    vector<CvPoint> polyline(4);
+    polyline[0] = cvPoint(0, 0);
+    polyline[1] = cvPoint(imgSize.width, 0);
+    polyline[2] = cvPoint(imgSize.width, imgSize.height);
+    polyline[3] = cvPoint(0, imgSize.height);
+    CvPoint* pts = &polyline[0];
+    int n = (int)polyline.size();
+    int actualSize = 0;
+    cvFillPoly( &img, &pts, &n, 1, cvScalar(255,255,255) );
+
+    CvPoint p1 = cvPoint(1,1), p2 = cvPoint(3,3);
+    if( cvClipLine(imgSize, &p1, &p2) )
+        cvCircle( &img, cvPoint(300,100), 40, cvScalar(0,0,255), 3 ); // draw
+
+    p1 = cvPoint(1,1), p2 = cvPoint(3,imgSize.height+1000);
+    if( cvClipLine(imgSize, &p1, &p2) )
+        cvCircle( &img, cvPoint(500,300), 50, cvScalar(255,0,0), 5, 8, 1 ); // draw
+
+    p1 = cvPoint(imgSize.width,1), p2 = cvPoint(imgSize.width,3);
+    if( cvClipLine(imgSize, &p1, &p2) )
+        cvCircle( &img, cvPoint(390,100), 10, cvScalar(0,0,255), 3 ); // not draw
+
+    p1 = Point(imgSize.width-1,1), p2 = Point(imgSize.width,3);
+    if( cvClipLine(imgSize, &p1, &p2) )
+        cvEllipse( &img, cvPoint(390,100), cvSize(20,30), 60, 0, 220.0, cvScalar(0,200,0), 4 ); //draw
+
+    CvBox2D box;
+    box.center.x = 100;
+    box.center.y = 200;
+    box.size.width = 200;
+    box.size.height = 100;
+    box.angle = 160;
+    cvEllipseBox( &img, box, Scalar(200,200,255), 5 );
+
+    polyline.resize(9);
+    pts = &polyline[0];
+    n = (int)polyline.size();
+    actualSize = cvEllipse2Poly( cvPoint(430,180), cvSize(100,150), 30, 0, 150, &polyline[0], 20 );
+    CV_Assert(actualSize == n);
+    cvPolyLine( &img, &pts, &n, 1, false, cvScalar(0,0,150), 4, CV_AA );
+    n = 0;
+    for( vector<CvPoint>::const_iterator it = polyline.begin(); n < (int)polyline.size()-1; ++it, n++ )
+    {
+        cvLine( &img, *it, *(it+1), cvScalar(50,250,100) );
+    }
+
+    polyline.resize(19);
+    pts = &polyline[0];
+    n = (int)polyline.size();
+    actualSize = cvEllipse2Poly( cvPoint(500,300), cvSize(50,80), 0, 0, 180, &polyline[0], 10 );
+    CV_Assert(actualSize == n);
+    cvPolyLine( &img, &pts, &n, 1, true, Scalar(100,200,100), 20 );
+    cvFillConvexPoly( &img, pts, n, cvScalar(0, 80, 0) );
+
+    polyline.resize(8);
+    // external rectengular
+    polyline[0] = cvPoint(500, 20);
+    polyline[1] = cvPoint(580, 20);
+    polyline[2] = cvPoint(580, 100);
+    polyline[3] = cvPoint(500, 100);
+    // internal rectangular
+    polyline[4] = cvPoint(520, 40);
+    polyline[5] = cvPoint(560, 40);
+    polyline[6] = cvPoint(560, 80);
+    polyline[7] = cvPoint(520, 80);
+    CvPoint* ppts[] = {&polyline[0], &polyline[0]+4};
+    int pn[] = {4, 4};
+    cvFillPoly( &img, ppts, pn, 2, cvScalar(100, 100, 0), 8, 0 );
+
+    cvRectangle( &img, cvPoint(0, 300), cvPoint(50, 398), cvScalar(0,0,255) );
+
+    string text1 = "OpenCV";
+    CvFont font;
+    cvInitFont( &font, FONT_HERSHEY_SCRIPT_SIMPLEX, 2, 2, 0, 3 );
+    int baseline = 0;
+    CvSize textSize;
+    cvGetTextSize( text1.c_str(), &font, &textSize, &baseline );
+    baseline += font.thickness;
+    CvPoint textOrg = cvPoint((imgSize.width - textSize.width)/2, (imgSize.height + textSize.height)/2);
+    cvRectangle( &img, cvPoint( textOrg.x, textOrg.y + baseline),
+                 cvPoint(textOrg.x + textSize.width, textOrg.y - textSize.height), cvScalar(0,0,255));
+    cvLine( &img, cvPoint(textOrg.x, textOrg.y + font.thickness),
+            cvPoint(textOrg.x + textSize.width, textOrg.y + font.thickness), cvScalar(0, 0, 255));
+    cvPutText( &img, text1.c_str(), textOrg, &font, cvScalar(150,0,150) );
+
+    int dist = 5;
+    string text2 = "abcdefghijklmnopqrstuvwxyz1234567890";
+    CvScalar color = cvScalar(200,0,0);
+    cvInitFont( &font, FONT_HERSHEY_SIMPLEX, 0.5, 0.5, 0, 1, CV_AA );
+    cvGetTextSize( text2.c_str(), &font, &textSize, &baseline );
+    textOrg = cvPoint(5, 5+textSize.height+dist);
+    cvPutText(&img, text2.c_str(), textOrg, &font, color );
+
+    cvInitFont( &font, FONT_HERSHEY_PLAIN, 1, 1, 0, 1, CV_AA );
+    cvGetTextSize( text2.c_str(), &font, &textSize, &baseline );
+    textOrg = cvPoint(textOrg.x,textOrg.y+textSize.height+dist);
+    cvPutText(&img, text2.c_str(), textOrg, &font, color );
+
+    cvInitFont( &font, FONT_HERSHEY_DUPLEX, 0.5, 0.5, 0, 1, CV_AA );
+    cvGetTextSize( text2.c_str(), &font, &textSize, &baseline );
+    textOrg = cvPoint(textOrg.x,textOrg.y+textSize.height+dist);
+    cvPutText(&img, text2.c_str(), textOrg, &font, color );
+
+    cvInitFont( &font, FONT_HERSHEY_COMPLEX, 0.5, 0.5, 0, 1, CV_AA );
+    cvGetTextSize( text2.c_str(), &font, &textSize, &baseline );
+    textOrg = cvPoint(textOrg.x,textOrg.y+textSize.height+dist);
+    cvPutText(&img, text2.c_str(), textOrg, &font, color );
+
+    cvInitFont( &font, FONT_HERSHEY_TRIPLEX, 0.5, 0.5, 0, 1, CV_AA );
+    cvGetTextSize( text2.c_str(), &font, &textSize, &baseline );
+    textOrg = cvPoint(textOrg.x,textOrg.y+textSize.height+dist);
+    cvPutText(&img, text2.c_str(), textOrg, &font, color );
+
+    cvInitFont( &font, FONT_HERSHEY_COMPLEX_SMALL, 1, 1, 0, 1, CV_AA );
+    cvGetTextSize( text2.c_str(), &font, &textSize, &baseline );
+    textOrg = cvPoint(textOrg.x,textOrg.y+textSize.height+dist + 180);
+    cvPutText(&img, text2.c_str(), textOrg, &font, color );
+
+    cvInitFont( &font, FONT_HERSHEY_SCRIPT_SIMPLEX, 1, 1, 0, 1, CV_AA );
+    cvGetTextSize( text2.c_str(), &font, &textSize, &baseline );
+    textOrg = cvPoint(textOrg.x,textOrg.y+textSize.height+dist);
+    cvPutText(&img, text2.c_str(), textOrg, &font, color );
+
+    cvInitFont( &font, FONT_HERSHEY_SCRIPT_COMPLEX, 1, 1, 0, 1, CV_AA );
+    cvGetTextSize( text2.c_str(), &font, &textSize, &baseline );
+    textOrg = cvPoint(textOrg.x,textOrg.y+textSize.height+dist);
+    cvPutText(&img, text2.c_str(), textOrg, &font, color );
+
+    dist = 15;
+    cvInitFont( &font, FONT_ITALIC, 0.5, 0.5, 0, 1, CV_AA );
+    cvGetTextSize( text2.c_str(), &font, &textSize, &baseline );
+    textOrg = cvPoint(textOrg.x,textOrg.y+textSize.height+dist);
+    cvPutText(&img, text2.c_str(), textOrg, &font, color );
+}
+
+int CV_DrawingTest_C::checkLineIterator( Mat& _img )
+{
+    CvLineIterator it;
+    CvMat img = _img;
+    int count = cvInitLineIterator( &img, cvPoint(0,300), cvPoint(1000, 300), &it );
+    for(int i = 0; i < count; i++ )
+    {
+        Vec3b v = (Vec3b)(*(it.ptr)) - _img.at<Vec3b>(300,i);
+        float err = (float)cvtest::norm( v, NORM_L2 );
+        if( err != 0 )
+        {
+            ts->printf( ts->LOG, "CvLineIterator works incorrect" );
+            ts->set_failed_test_info(cvtest::TS::FAIL_INVALID_OUTPUT);
+        }
+        CV_NEXT_LINE_POINT(it);
+    }
+    ts->set_failed_test_info(cvtest::TS::OK);
+    return 0;
+}
+
+class CV_DrawingTest_Far : public CV_DrawingTest_CPP
+{
+public:
+    CV_DrawingTest_Far() {}
+protected:
+    virtual void draw(Mat& img);
+};
+
+void CV_DrawingTest_Far::draw(Mat& img)
+{
+    Size imgSize(32768 + 600, 400);
+    img.create(imgSize, CV_8UC3);
+
+    vector<Point> polyline(4);
+    polyline[0] = Point(32768 + 0, 0);
+    polyline[1] = Point(imgSize.width, 0);
+    polyline[2] = Point(imgSize.width, imgSize.height);
+    polyline[3] = Point(32768 + 0, imgSize.height);
+    const Point* pts = &polyline[0];
+    int n = (int)polyline.size();
+    fillPoly(img, &pts, &n, 1, Scalar::all(255));
+
+    Point p1(32768 + 1, 1), p2(32768 + 3, 3);
+    if (clipLine(Rect(32768 + 0, 0, imgSize.width, imgSize.height), p1, p2) && clipLine(imgSize, p1, p2))
+        circle(img, Point(32768 + 300, 100), 40, Scalar(0, 0, 255), 3); // draw
+
+    p2 = Point(32768 + 3, imgSize.height + 1000);
+    if (clipLine(Rect(32768 + 0, 0, imgSize.width, imgSize.height), p1, p2) && clipLine(imgSize, p1, p2))
+        circle(img, Point(65536 + 500, 300), 50, cvColorToScalar(255, CV_8UC3), 5, 8, 1); // draw
+
+    p1 = Point(imgSize.width, 1), p2 = Point(imgSize.width, 3);
+    if (clipLine(Rect(32768 + 0, 0, imgSize.width, imgSize.height), p1, p2) && clipLine(imgSize, p1, p2))
+        circle(img, Point(32768 + 390, 100), 10, Scalar(0, 0, 255), 3); // not draw
+
+    p1 = Point(imgSize.width - 1, 1), p2 = Point(imgSize.width, 3);
+    if (clipLine(Rect(32768 + 0, 0, imgSize.width, imgSize.height), p1, p2) && clipLine(imgSize, p1, p2))
+        ellipse(img, Point(32768 + 390, 100), Size(20, 30), 60, 0, 220.0, Scalar(0, 200, 0), 4); //draw
+
+    ellipse(img, RotatedRect(Point(32768 + 100, 200), Size(200, 100), 160), Scalar(200, 200, 255), 5);
+
+    polyline.clear();
+    ellipse2Poly(Point(32768 + 430, 180), Size(100, 150), 30, 0, 150, 20, polyline);
+    pts = &polyline[0];
+    n = (int)polyline.size();
+    polylines(img, &pts, &n, 1, false, Scalar(0, 0, 150), 4, CV_AA);
+    n = 0;
+    for (vector<Point>::const_iterator it = polyline.begin(); n < (int)polyline.size() - 1; ++it, n++)
+    {
+        line(img, *it, *(it + 1), Scalar(50, 250, 100));
+    }
+
+    polyline.clear();
+    ellipse2Poly(Point(32768 + 500, 300), Size(50, 80), 0, 0, 180, 10, polyline);
+    pts = &polyline[0];
+    n = (int)polyline.size();
+    polylines(img, &pts, &n, 1, true, Scalar(100, 200, 100), 20);
+    fillConvexPoly(img, pts, n, Scalar(0, 80, 0));
+
+    polyline.resize(8);
+    // external rectengular
+    polyline[0] = Point(32768 + 0, 0);
+    polyline[1] = Point(32768 + 80, 0);
+    polyline[2] = Point(32768 + 80, 80);
+    polyline[3] = Point(32768 + 0, 80);
+    // internal rectangular
+    polyline[4] = Point(32768 + 20, 20);
+    polyline[5] = Point(32768 + 60, 20);
+    polyline[6] = Point(32768 + 60, 60);
+    polyline[7] = Point(32768 + 20, 60);
+    const Point* ppts[] = { &polyline[0], &polyline[0] + 4 };
+    int pn[] = { 4, 4 };
+    fillPoly(img, ppts, pn, 2, Scalar(100, 100, 0), 8, 0, Point(500, 20));
+
+    rectangle(img, Point(32768 + 0, 300), Point(32768 + 50, 398), Scalar(0, 0, 255));
+
+    string text1 = "OpenCV";
+    int baseline = 0, thickness = 3, fontFace = FONT_HERSHEY_SCRIPT_SIMPLEX;
+    float fontScale = 2;
+    Size textSize = getTextSize(text1, fontFace, fontScale, thickness, &baseline);
+    baseline += thickness;
+    Point textOrg((32768 + img.cols - textSize.width) / 2, (img.rows + textSize.height) / 2);
+    rectangle(img, textOrg + Point(0, baseline), textOrg + Point(textSize.width, -textSize.height), Scalar(0, 0, 255));
+    line(img, textOrg + Point(0, thickness), textOrg + Point(textSize.width, thickness), Scalar(0, 0, 255));
+    putText(img, text1, textOrg, fontFace, fontScale, Scalar(150, 0, 150), thickness, 8);
+
+    string text2 = "abcdefghijklmnopqrstuvwxyz1234567890";
+    Scalar color(200, 0, 0);
+    fontScale = 0.5, thickness = 1;
+    int dist = 5;
+
+    textSize = getTextSize(text2, FONT_HERSHEY_SIMPLEX, fontScale, thickness, &baseline);
+    textOrg = Point(32768 + 5, 5) + Point(0, textSize.height + dist);
+    putText(img, text2, textOrg, FONT_HERSHEY_SIMPLEX, fontScale, color, thickness, CV_AA);
+
+    fontScale = 1;
+    textSize = getTextSize(text2, FONT_HERSHEY_PLAIN, fontScale, thickness, &baseline);
+    textOrg += Point(0, textSize.height + dist);
+    putText(img, text2, textOrg, FONT_HERSHEY_PLAIN, fontScale, color, thickness, CV_AA);
+
+    fontScale = 0.5;
+    textSize = getTextSize(text2, FONT_HERSHEY_DUPLEX, fontScale, thickness, &baseline);
+    textOrg += Point(0, textSize.height + dist);
+    putText(img, text2, textOrg, FONT_HERSHEY_DUPLEX, fontScale, color, thickness, CV_AA);
+
+    textSize = getTextSize(text2, FONT_HERSHEY_COMPLEX, fontScale, thickness, &baseline);
+    textOrg += Point(0, textSize.height + dist);
+    putText(img, text2, textOrg, FONT_HERSHEY_COMPLEX, fontScale, color, thickness, CV_AA);
+
+    textSize = getTextSize(text2, FONT_HERSHEY_TRIPLEX, fontScale, thickness, &baseline);
+    textOrg += Point(0, textSize.height + dist);
+    putText(img, text2, textOrg, FONT_HERSHEY_TRIPLEX, fontScale, color, thickness, CV_AA);
+
+    fontScale = 1;
+    textSize = getTextSize(text2, FONT_HERSHEY_COMPLEX_SMALL, fontScale, thickness, &baseline);
+    textOrg += Point(0, 180) + Point(0, textSize.height + dist);
+    putText(img, text2, textOrg, FONT_HERSHEY_COMPLEX_SMALL, fontScale, color, thickness, CV_AA);
+
+    textSize = getTextSize(text2, FONT_HERSHEY_SCRIPT_SIMPLEX, fontScale, thickness, &baseline);
+    textOrg += Point(0, textSize.height + dist);
+    putText(img, text2, textOrg, FONT_HERSHEY_SCRIPT_SIMPLEX, fontScale, color, thickness, CV_AA);
+
+    textSize = getTextSize(text2, FONT_HERSHEY_SCRIPT_COMPLEX, fontScale, thickness, &baseline);
+    textOrg += Point(0, textSize.height + dist);
+    putText(img, text2, textOrg, FONT_HERSHEY_SCRIPT_COMPLEX, fontScale, color, thickness, CV_AA);
+
+    dist = 15, fontScale = 0.5;
+    textSize = getTextSize(text2, FONT_ITALIC, fontScale, thickness, &baseline);
+    textOrg += Point(0, textSize.height + dist);
+    putText(img, text2, textOrg, FONT_ITALIC, fontScale, color, thickness, CV_AA);
+
+    img = img(Rect(32768, 0, 600, 400)).clone();
+}
+
+TEST(Drawing,    cpp_regression) { CV_DrawingTest_CPP test; test.safe_run(); }
+TEST(Drawing,      c_regression) { CV_DrawingTest_C   test; test.safe_run(); }
+TEST(Drawing,    far_regression) { CV_DrawingTest_Far test; test.safe_run(); }
+
+class CV_FillConvexPolyTest : public cvtest::BaseTest
+{
+public:
+    CV_FillConvexPolyTest() {}
+    ~CV_FillConvexPolyTest() {}
+protected:
+    void run(int)
+    {
+        vector<Point> line1;
+        vector<Point> line2;
+
+        line1.push_back(Point(1, 1));
+        line1.push_back(Point(5, 1));
+        line1.push_back(Point(5, 8));
+        line1.push_back(Point(1, 8));
+
+        line2.push_back(Point(2, 2));
+        line2.push_back(Point(10, 2));
+        line2.push_back(Point(10, 16));
+        line2.push_back(Point(2, 16));
+
+        Mat gray0(10,10,CV_8U, Scalar(0));
+        fillConvexPoly(gray0, line1, Scalar(255), 8, 0);
+        int nz1 = countNonZero(gray0);
+
+        fillConvexPoly(gray0, line2, Scalar(0), 8, 1);
+        int nz2 = countNonZero(gray0)/255;
+
+        CV_Assert( nz1 == 40 && nz2 == 0 );
+    }
+};
+
+TEST(Drawing, fillconvexpoly_clipping) { CV_FillConvexPolyTest test; test.safe_run(); }
+
+class CV_DrawingTest_UTF8 : public cvtest::BaseTest
+{
+public:
+    CV_DrawingTest_UTF8() {}
+    ~CV_DrawingTest_UTF8() {}
+protected:
+    void run(int)
+    {
+        vector<string> lines;
+        lines.push_back("abcdefghijklmnopqrstuvwxyz1234567890");
+        // cyrillic letters small
+        lines.push_back("\xD0\xB0\xD0\xB1\xD0\xB2\xD0\xB3\xD0\xB4\xD0\xB5\xD1\x91\xD0\xB6\xD0\xB7"
+                        "\xD0\xB8\xD0\xB9\xD0\xBA\xD0\xBB\xD0\xBC\xD0\xBD\xD0\xBE\xD0\xBF\xD1\x80"
+                        "\xD1\x81\xD1\x82\xD1\x83\xD1\x84\xD1\x85\xD1\x86\xD1\x87\xD1\x88\xD1\x89"
+                        "\xD1\x8A\xD1\x8B\xD1\x8C\xD1\x8D\xD1\x8E\xD1\x8F");
+        // cyrillic letters capital
+        lines.push_back("\xD0\x90\xD0\x91\xD0\x92\xD0\x93\xD0\x94\xD0\x95\xD0\x81\xD0\x96\xD0\x97"
+                        "\xD0\x98\xD0\x99\xD0\x9A\xD0\x9B\xD0\x9C\xD0\x9D\xD0\x9E\xD0\x9F\xD0\xA0"
+                        "\xD0\xA1\xD0\xA2\xD0\xA3\xD0\xA4\xD0\xA5\xD0\xA6\xD0\xA7\xD0\xA8\xD0\xA9"
+                        "\xD0\xAA\xD0\xAB\xD0\xAC\xD0\xAD\xD0\xAE\xD0\xAF");
+        // bounds
+        lines.push_back("-\xD0\x80-\xD0\x8E-\xD0\x8F-");
+        lines.push_back("-\xD1\x90-\xD1\x91-\xD1\xBF-");
+        // bad utf8
+        lines.push_back("-\x81-\x82-\x83-");
+        lines.push_back("--\xF0--");
+        lines.push_back("-\xF0");
+
+        vector<int> fonts;
+        fonts.push_back(FONT_HERSHEY_SIMPLEX);
+        fonts.push_back(FONT_HERSHEY_PLAIN);
+        fonts.push_back(FONT_HERSHEY_DUPLEX);
+        fonts.push_back(FONT_HERSHEY_COMPLEX);
+        fonts.push_back(FONT_HERSHEY_TRIPLEX);
+        fonts.push_back(FONT_HERSHEY_COMPLEX_SMALL);
+        fonts.push_back(FONT_HERSHEY_SCRIPT_SIMPLEX);
+        fonts.push_back(FONT_HERSHEY_SCRIPT_COMPLEX);
+
+        vector<Mat> results;
+        Size bigSize(0, 0);
+        for (vector<int>::const_iterator font = fonts.begin(); font != fonts.end(); ++font)
+        {
+            for (int italic = 0; italic <= FONT_ITALIC; italic += FONT_ITALIC)
+            {
+                for (vector<string>::const_iterator line = lines.begin(); line != lines.end(); ++line)
+                {
+                    const float fontScale = 1;
+                    const int thickness = 1;
+                    const Scalar color(20,20,20);
+                    int baseline = 0;
+
+                    Size textSize = getTextSize(*line, *font | italic, fontScale, thickness, &baseline);
+                    Point textOrg(0, textSize.height + 2);
+                    Mat img(textSize + Size(0, baseline), CV_8UC3, Scalar(255, 255, 255));
+                    putText(img, *line, textOrg, *font | italic, fontScale, color, thickness, CV_AA);
+
+                    results.push_back(img);
+                    bigSize.width = max(bigSize.width, img.size().width);
+                    bigSize.height += img.size().height + 1;
+                }
+            }
+        }
+
+        int shift = 0;
+        Mat result(bigSize, CV_8UC3, Scalar(100, 100, 100));
+        for (vector<Mat>::const_iterator img = results.begin(); img != results.end(); ++img)
+        {
+            Rect roi(Point(0, shift), img->size());
+            Mat sub(result, roi);
+            img->copyTo(sub);
+            shift += img->size().height + 1;
+        }
+        //imwrite("/tmp/all_fonts.png", result);
+    }
+};
+
+TEST(Drawing, utf8_support) { CV_DrawingTest_UTF8 test; test.safe_run(); }
+
+
+TEST(Drawing, _914)
+{
+    const int rows = 256;
+    const int cols = 256;
+
+    Mat img(rows, cols, CV_8UC1, Scalar(255));
+
+    line(img, Point(0, 10), Point(255, 10), Scalar(0), 2, 4);
+    line(img, Point(-5, 20), Point(260, 20), Scalar(0), 2, 4);
+    line(img, Point(10, 0), Point(10, 255), Scalar(0), 2, 4);
+
+    double x0 = 0.0/pow(2.0, -2.0);
+    double x1 = 255.0/pow(2.0, -2.0);
+    double y = 30.5/pow(2.0, -2.0);
+
+    line(img, Point(int(x0), int(y)), Point(int(x1), int(y)), Scalar(0), 2, 4, 2);
+
+    int pixelsDrawn = rows*cols - countNonZero(img);
+    ASSERT_EQ( (3*rows + cols)*3 - 3*9, pixelsDrawn);
+}
+
+TEST(Drawing, polylines_empty)
+{
+    Mat img(100, 100, CV_8UC1, Scalar(0));
+    vector<Point> pts; // empty
+    polylines(img, pts, false, Scalar(255));
+    int cnt = countNonZero(img);
+    ASSERT_EQ(cnt, 0);
+}
+
+TEST(Drawing, polylines)
+{
+    Mat img(100, 100, CV_8UC1, Scalar(0));
+    vector<Point> pts;
+    pts.push_back(Point(0, 0));
+    pts.push_back(Point(20, 0));
+    polylines(img, pts, false, Scalar(255));
+    int cnt = countNonZero(img);
+    ASSERT_EQ(cnt, 21);
+}
+
+
+TEST(Drawing, putText_no_garbage)
+{
+    Size sz(640, 480);
+    Mat mat = Mat::zeros(sz, CV_8UC1);
+
+    mat = Scalar::all(0);
+    putText(mat, "029", Point(10, 350), 0, 10, Scalar(128), 15);
+
+    EXPECT_EQ(0, cv::countNonZero(mat(Rect(0, 0,           10, sz.height))));
+    EXPECT_EQ(0, cv::countNonZero(mat(Rect(sz.width-10, 0, 10, sz.height))));
+    EXPECT_EQ(0, cv::countNonZero(mat(Rect(205, 0,         10, sz.height))));
+    EXPECT_EQ(0, cv::countNonZero(mat(Rect(405, 0,         10, sz.height))));
+}
+
+
+
+} // namespace
diff --git a/modules/imgproc/test/test_filter.cpp b/modules/imgproc/test/test_filter.cpp
index 5994b1b..886c5ab 100644
--- a/modules/imgproc/test/test_filter.cpp
+++ b/modules/imgproc/test/test_filter.cpp
@@ -2015,3 +2015,53 @@ TEST(Imgproc_Morphology, iterated)
         ASSERT_EQ(0.0, norm(dst0, dst2, NORM_INF));
     }
 }
+
+TEST(Imgproc_Sobel, borderTypes)
+{
+    int kernelSize = 3;
+
+    /// ksize > src_roi.size()
+    Mat src = (Mat_<uchar>(3, 3) << 1, 2, 3, 4, 5, 6, 7, 8, 9), dst, expected_dst;
+    Mat src_roi = src(Rect(1, 1, 1, 1));
+    src_roi.setTo(cv::Scalar::all(0));
+
+    // should work like !BORDER_ISOLATED, so the function MUST read values in full matrix
+    Sobel(src_roi, dst, CV_16S, 1, 0, kernelSize, 1, 0, BORDER_REPLICATE);
+    EXPECT_EQ(8, dst.at<short>(0, 0));
+    Sobel(src_roi, dst, CV_16S, 1, 0, kernelSize, 1, 0, BORDER_REFLECT);
+    EXPECT_EQ(8, dst.at<short>(0, 0));
+
+    // should work like BORDER_ISOLATED
+    Sobel(src_roi, dst, CV_16S, 1, 0, kernelSize, 1, 0, BORDER_REPLICATE | BORDER_ISOLATED);
+    EXPECT_EQ(0, dst.at<short>(0, 0));
+    Sobel(src_roi, dst, CV_16S, 1, 0, kernelSize, 1, 0, BORDER_REFLECT | BORDER_ISOLATED);
+    EXPECT_EQ(0, dst.at<short>(0, 0));
+
+    /// ksize <= src_roi.size()
+    src = Mat(5, 5, CV_8UC1, cv::Scalar(5));
+    src_roi = src(Rect(1, 1, 3, 3));
+    src_roi.setTo(0);
+
+    // should work like !BORDER_ISOLATED, so the function MUST read values in full matrix
+    expected_dst =
+        (Mat_<short>(3, 3) << -15, 0, 15, -20, 0, 20, -15, 0, 15);
+    Sobel(src_roi, dst, CV_16S, 1, 0, kernelSize, 1, 0, BORDER_REPLICATE);
+    EXPECT_EQ(expected_dst.type(), dst.type());
+    EXPECT_EQ(expected_dst.size(), dst.size());
+    EXPECT_DOUBLE_EQ(0.0, cvtest::norm(expected_dst, dst, NORM_INF));
+    Sobel(src_roi, dst, CV_16S, 1, 0, kernelSize, 1, 0, BORDER_REFLECT);
+    EXPECT_EQ(expected_dst.type(), dst.type());
+    EXPECT_EQ(expected_dst.size(), dst.size());
+    EXPECT_DOUBLE_EQ(0.0, cvtest::norm(expected_dst, dst, NORM_INF));
+
+    // should work like !BORDER_ISOLATED, so the function MUST read values in full matrix
+    expected_dst = Mat::zeros(3, 3, CV_16SC1);
+    Sobel(src_roi, dst, CV_16S, 1, 0, kernelSize, 1, 0, BORDER_REPLICATE | BORDER_ISOLATED);
+    EXPECT_EQ(expected_dst.type(), dst.type());
+    EXPECT_EQ(expected_dst.size(), dst.size());
+    EXPECT_DOUBLE_EQ(0.0, cvtest::norm(expected_dst, dst, NORM_INF));
+    Sobel(src_roi, dst, CV_16S, 1, 0, kernelSize, 1, 0, BORDER_REFLECT | BORDER_ISOLATED);
+    EXPECT_EQ(expected_dst.type(), dst.type());
+    EXPECT_EQ(expected_dst.size(), dst.size());
+    EXPECT_DOUBLE_EQ(0.0, cvtest::norm(expected_dst, dst, NORM_INF));
+}
diff --git a/modules/imgproc/test/test_fitellipse.cpp b/modules/imgproc/test/test_fitellipse.cpp
new file mode 100644
index 0000000..57ad068
--- /dev/null
+++ b/modules/imgproc/test/test_fitellipse.cpp
@@ -0,0 +1,70 @@
+// This file is part of OpenCV project.
+// It is subject to the license terms in the LICENSE file found in the top-level directory
+// of this distribution and at http://opencv.org/license.html.
+//
+// Copyright (C) 2016, Itseez, Inc, all rights reserved.
+
+#include "test_precomp.hpp"
+#include <vector>
+#include <cmath>
+
+using namespace cv;
+using namespace std;
+
+// return true if point lies inside ellipse
+static bool check_pt_in_ellipse(const Point2f& pt, const RotatedRect& el) {
+    Point2f to_pt = pt - el.center;
+    double pt_angle = atan2(to_pt.y, to_pt.x);
+    double el_angle = el.angle * CV_PI / 180;
+    double x_dist = 0.5 * el.size.width * cos(pt_angle + el_angle);
+    double y_dist = 0.5 * el.size.height * sin(pt_angle + el_angle);
+    double el_dist = sqrt(x_dist * x_dist + y_dist * y_dist);
+    return norm(to_pt) < el_dist;
+}
+
+// Return true if mass center of fitted points lies inside ellipse
+static bool fit_and_check_ellipse(const vector<Point2f>& pts) {
+    RotatedRect ellipse = fitEllipse(pts);
+
+    Point2f mass_center;
+    for (size_t i = 0; i < pts.size(); i++) {
+        mass_center += pts[i];
+    }
+    mass_center /= (float)pts.size();
+
+    return check_pt_in_ellipse(mass_center, ellipse);
+}
+
+TEST(Imgproc_FitEllipse_Issue_4515, DISABLED_accuracy) {
+    vector<Point2f> pts;
+    pts.push_back(Point2f(327, 317));
+    pts.push_back(Point2f(328, 316));
+    pts.push_back(Point2f(329, 315));
+    pts.push_back(Point2f(330, 314));
+    pts.push_back(Point2f(331, 314));
+    pts.push_back(Point2f(332, 314));
+    pts.push_back(Point2f(333, 315));
+    pts.push_back(Point2f(333, 316));
+    pts.push_back(Point2f(333, 317));
+    pts.push_back(Point2f(333, 318));
+    pts.push_back(Point2f(333, 319));
+    pts.push_back(Point2f(333, 320));
+
+    EXPECT_TRUE(fit_and_check_ellipse(pts));
+}
+
+TEST(Imgproc_FitEllipse_Issue_6544, DISABLED_accuracy) {
+    vector<Point2f> pts;
+    pts.push_back(Point2f(924.784f, 764.160f));
+    pts.push_back(Point2f(928.388f, 615.903f));
+    pts.push_back(Point2f(847.4f,   888.014f));
+    pts.push_back(Point2f(929.406f, 741.675f));
+    pts.push_back(Point2f(904.564f, 825.605f));
+    pts.push_back(Point2f(926.742f, 760.746f));
+    pts.push_back(Point2f(863.479f, 873.406f));
+    pts.push_back(Point2f(910.987f, 808.863f));
+    pts.push_back(Point2f(929.145f, 744.976f));
+    pts.push_back(Point2f(917.474f, 791.823f));
+
+    EXPECT_TRUE(fit_and_check_ellipse(pts));
+}
diff --git a/modules/imgproc/test/test_floodfill.cpp b/modules/imgproc/test/test_floodfill.cpp
index bb34449..fe2fba6 100644
--- a/modules/imgproc/test/test_floodfill.cpp
+++ b/modules/imgproc/test/test_floodfill.cpp
@@ -528,4 +528,18 @@ void CV_FloodFillTest::prepare_to_validation( int /*test_case_idx*/ )
 
 TEST(Imgproc_FloodFill, accuracy) { CV_FloodFillTest test; test.safe_run(); }
 
+TEST(Imgproc_FloodFill, maskValue)
+{
+    const int n = 50;
+    Mat img = Mat::zeros(n, n, CV_8U);
+    Mat mask = Mat::zeros(n + 2, n + 2, CV_8U);
+
+    circle(img, Point(n/2, n/2), 20, Scalar(100), 4);
+
+    int flags = 4 + CV_FLOODFILL_MASK_ONLY;
+    floodFill(img, mask, Point(n/2 + 13, n/2), Scalar(100), NULL, Scalar(),  Scalar(), flags);
+
+    ASSERT_TRUE(norm(mask.rowRange(1, n-1).colRange(1, n-1), NORM_INF) == 1.);
+}
+
 /* End of file. */
diff --git a/modules/imgproc/test/test_houghLines.cpp b/modules/imgproc/test/test_houghLines.cpp
index a508841..93a1202 100644
--- a/modules/imgproc/test/test_houghLines.cpp
+++ b/modules/imgproc/test/test_houghLines.cpp
@@ -189,7 +189,7 @@ void BaseHoughLineTest::run_test(int type)
     else if (type == PROBABILISTIC)
         count = countMatIntersection<Vec4i>(exp_lines, lines, 1e-4f, 0.f);
 
-#if defined HAVE_IPP && !defined(HAVE_IPP_ICV_ONLY) && IPP_VERSION_X100 >= 810 && IPP_DISABLE_BLOCK
+#if defined HAVE_IPP && IPP_VERSION_X100 >= 810 && IPP_DISABLE_BLOCK
     EXPECT_GE( count, (int) (exp_lines.total() * 0.8) );
 #else
     EXPECT_EQ( count, (int) exp_lines.total());
diff --git a/modules/imgproc/test/test_imgwarp.cpp b/modules/imgproc/test/test_imgwarp.cpp
index 0568cbc..8246754 100644
--- a/modules/imgproc/test/test_imgwarp.cpp
+++ b/modules/imgproc/test/test_imgwarp.cpp
@@ -1744,4 +1744,86 @@ TEST(Imgproc_Remap, DISABLED_memleak)
     }
 }
 
+
+TEST(Imgproc_linearPolar, identity)
+{
+    const int N = 33;
+    Mat in(N, N, CV_8UC3, Scalar(255, 0, 0));
+    in(cv::Rect(N/3, N/3, N/3, N/3)).setTo(Scalar::all(255));
+    cv::blur(in, in, Size(5, 5));
+    cv::blur(in, in, Size(5, 5));
+
+    Mat src = in.clone();
+    Mat dst;
+
+    Rect roi = Rect(0, 0, in.cols - ((N+19)/20), in.rows);
+
+    for (int i = 1; i <= 5; i++)
+    {
+        linearPolar(src, dst,
+            Point2f((N-1) * 0.5f, (N-1) * 0.5f), N * 0.5f,
+            CV_WARP_FILL_OUTLIERS | CV_INTER_LINEAR | CV_WARP_INVERSE_MAP);
+
+        linearPolar(dst, src,
+            Point2f((N-1) * 0.5f, (N-1) * 0.5f), N * 0.5f,
+            CV_WARP_FILL_OUTLIERS | CV_INTER_LINEAR);
+
+        double psnr = cvtest::PSNR(in(roi), src(roi));
+        EXPECT_LE(25, psnr) << "iteration=" << i;
+    }
+
+#if 0
+    Mat all(N*2+2,N*2+2, src.type(), Scalar(0,0,255));
+    in.copyTo(all(Rect(0,0,N,N)));
+    src.copyTo(all(Rect(0,N+1,N,N)));
+    src.copyTo(all(Rect(N+1,0,N,N)));
+    dst.copyTo(all(Rect(N+1,N+1,N,N)));
+    imwrite("linearPolar.png", all);
+    imshow("input", in); imshow("result", dst); imshow("restore", src); imshow("all", all);
+    cv::waitKey();
+#endif
+}
+
+
+TEST(Imgproc_logPolar, identity)
+{
+    const int N = 33;
+    Mat in(N, N, CV_8UC3, Scalar(255, 0, 0));
+    in(cv::Rect(N/3, N/3, N/3, N/3)).setTo(Scalar::all(255));
+    cv::blur(in, in, Size(5, 5));
+    cv::blur(in, in, Size(5, 5));
+
+    Mat src = in.clone();
+    Mat dst;
+
+    Rect roi = Rect(0, 0, in.cols - ((N+19)/20), in.rows);
+
+    double M = N/log(N * 0.5f);
+    for (int i = 1; i <= 5; i++)
+    {
+        logPolar(src, dst,
+            Point2f((N-1) * 0.5f, (N-1) * 0.5f), M,
+            CV_WARP_FILL_OUTLIERS | CV_INTER_LINEAR | CV_WARP_INVERSE_MAP);
+
+        logPolar(dst, src,
+            Point2f((N-1) * 0.5f, (N-1) * 0.5f), M,
+            CV_WARP_FILL_OUTLIERS | CV_INTER_LINEAR);
+
+        double psnr = cvtest::PSNR(in(roi), src(roi));
+        EXPECT_LE(25, psnr) << "iteration=" << i;
+    }
+
+#if 0
+    Mat all(N*2+2,N*2+2, src.type(), Scalar(0,0,255));
+    in.copyTo(all(Rect(0,0,N,N)));
+    src.copyTo(all(Rect(0,N+1,N,N)));
+    src.copyTo(all(Rect(N+1,0,N,N)));
+    dst.copyTo(all(Rect(N+1,N+1,N,N)));
+    imwrite("logPolar.png", all);
+    imshow("input", in); imshow("result", dst); imshow("restore", src); imshow("all", all);
+    cv::waitKey();
+#endif
+}
+
+
 /* End of file. */
diff --git a/modules/imgproc/test/test_imgwarp_strict.cpp b/modules/imgproc/test/test_imgwarp_strict.cpp
index 4756b7f..7a9c912 100644
--- a/modules/imgproc/test/test_imgwarp_strict.cpp
+++ b/modules/imgproc/test/test_imgwarp_strict.cpp
@@ -1218,3 +1218,34 @@ TEST(Imgproc_Resize_Test, accuracy) { CV_Resize_Test test; test.safe_run(); }
 TEST(Imgproc_Remap_Test, accuracy) { CV_Remap_Test test; test.safe_run(); }
 TEST(Imgproc_WarpAffine_Test, accuracy) { CV_WarpAffine_Test test; test.safe_run(); }
 TEST(Imgproc_WarpPerspective_Test, accuracy) { CV_WarpPerspective_Test test; test.safe_run(); }
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef OPENCV_TEST_BIGDATA
+
+CV_ENUM(Interpolation, INTER_NEAREST, INTER_LINEAR, INTER_CUBIC, INTER_AREA)
+
+class Imgproc_Resize :
+        public ::testing::TestWithParam<Interpolation>
+{
+public:
+    virtual void SetUp()
+    {
+        inter = GetParam();
+    }
+
+protected:
+    int inter;
+};
+
+TEST_P(Imgproc_Resize, BigSize)
+{
+    cv::Mat src(46342, 46342, CV_8UC3, cv::Scalar::all(10)), dst;
+    ASSERT_FALSE(src.empty());
+
+    ASSERT_NO_THROW(cv::resize(src, dst, cv::Size(), 0.5, 0.5, inter));
+}
+
+INSTANTIATE_TEST_CASE_P(Imgproc, Imgproc_Resize, Interpolation::all());
+
+#endif
diff --git a/modules/imgproc/test/test_thresh.cpp b/modules/imgproc/test/test_thresh.cpp
index f59fec1..469ccf5 100644
--- a/modules/imgproc/test/test_thresh.cpp
+++ b/modules/imgproc/test/test_thresh.cpp
@@ -56,8 +56,8 @@ protected:
     void prepare_to_validation( int );
 
     int thresh_type;
-    float thresh_val;
-    float max_val;
+    double thresh_val;
+    double max_val;
 };
 
 
@@ -75,33 +75,33 @@ void CV_ThreshTest::get_test_array_types_and_sizes( int test_case_idx,
                                                 vector<vector<Size> >& sizes, vector<vector<int> >& types )
 {
     RNG& rng = ts->get_rng();
-    int depth = cvtest::randInt(rng) % 3, cn = cvtest::randInt(rng) % 4 + 1;
+    int depth = cvtest::randInt(rng) % 4, cn = cvtest::randInt(rng) % 4 + 1;
     cvtest::ArrayTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
-    depth = depth == 0 ? CV_8U : depth == 1 ? CV_16S : CV_32F;
+    depth = depth == 0 ? CV_8U : depth == 1 ? CV_16S : depth == 2 ? CV_32F : CV_64F;
 
     types[INPUT][0] = types[OUTPUT][0] = types[REF_OUTPUT][0] = CV_MAKETYPE(depth,cn);
     thresh_type = cvtest::randInt(rng) % 5;
 
     if( depth == CV_8U )
     {
-        thresh_val = (float)(cvtest::randReal(rng)*350. - 50.);
-        max_val = (float)(cvtest::randReal(rng)*350. - 50.);
+        thresh_val = (cvtest::randReal(rng)*350. - 50.);
+        max_val = (cvtest::randReal(rng)*350. - 50.);
         if( cvtest::randInt(rng)%4 == 0 )
             max_val = 255.f;
     }
     else if( depth == CV_16S )
     {
-        float min_val = SHRT_MIN-100.f;
+        double min_val = SHRT_MIN-100.f;
         max_val = SHRT_MAX+100.f;
-        thresh_val = (float)(cvtest::randReal(rng)*(max_val - min_val) + min_val);
-        max_val = (float)(cvtest::randReal(rng)*(max_val - min_val) + min_val);
+        thresh_val = (cvtest::randReal(rng)*(max_val - min_val) + min_val);
+        max_val = (cvtest::randReal(rng)*(max_val - min_val) + min_val);
         if( cvtest::randInt(rng)%4 == 0 )
-            max_val = (float)SHRT_MAX;
+            max_val = (double)SHRT_MAX;
     }
     else
     {
-        thresh_val = (float)(cvtest::randReal(rng)*1000. - 500.);
-        max_val = (float)(cvtest::randReal(rng)*1000. - 500.);
+        thresh_val = (cvtest::randReal(rng)*1000. - 500.);
+        max_val = (cvtest::randReal(rng)*1000. - 500.);
     }
 }
 
@@ -120,7 +120,7 @@ void CV_ThreshTest::run_func()
 
 
 static void test_threshold( const Mat& _src, Mat& _dst,
-                            float thresh, float maxval, int thresh_type )
+                            double thresh, double maxval, int thresh_type )
 {
     int i, j;
     int depth = _src.depth(), cn = _src.channels();
@@ -144,7 +144,7 @@ static void test_threshold( const Mat& _src, Mat& _dst,
         imaxval = cvRound(maxval);
     }
 
-    assert( depth == CV_8U || depth == CV_16S || depth == CV_32F );
+    assert( depth == CV_8U || depth == CV_16S || depth == CV_32F || depth == CV_64F );
 
     switch( thresh_type )
     {
@@ -165,12 +165,19 @@ static void test_threshold( const Mat& _src, Mat& _dst,
                 for( j = 0; j < width_n; j++ )
                     dst[j] = (short)(src[j] > ithresh ? imaxval : 0);
             }
-            else
+            else if( depth == CV_32F )
             {
                 const float* src = _src.ptr<float>(i);
                 float* dst = _dst.ptr<float>(i);
                 for( j = 0; j < width_n; j++ )
-                    dst[j] = src[j] > thresh ? maxval : 0.f;
+                    dst[j] = (float)(src[j] > thresh ? maxval : 0.f);
+            }
+            else
+            {
+                const double* src = _src.ptr<double>(i);
+                double* dst = _dst.ptr<double>(i);
+                for( j = 0; j < width_n; j++ )
+                    dst[j] = src[j] > thresh ? maxval : 0.0;
             }
         }
         break;
@@ -191,12 +198,19 @@ static void test_threshold( const Mat& _src, Mat& _dst,
                 for( j = 0; j < width_n; j++ )
                     dst[j] = (short)(src[j] > ithresh ? 0 : imaxval);
             }
-            else
+            else if( depth == CV_32F )
             {
                 const float* src = _src.ptr<float>(i);
                 float* dst = _dst.ptr<float>(i);
                 for( j = 0; j < width_n; j++ )
-                    dst[j] = src[j] > thresh ? 0.f : maxval;
+                    dst[j] = (float)(src[j] > thresh ? 0.f : maxval);
+            }
+            else
+            {
+                const double* src = _src.ptr<double>(i);
+                double* dst = _dst.ptr<double>(i);
+                for( j = 0; j < width_n; j++ )
+                    dst[j] = src[j] > thresh ? 0.0 : maxval;
             }
         }
         break;
@@ -223,13 +237,23 @@ static void test_threshold( const Mat& _src, Mat& _dst,
                     dst[j] = (short)(s > ithresh ? ithresh2 : s);
                 }
             }
-            else
+            else if( depth == CV_32F )
             {
                 const float* src = _src.ptr<float>(i);
                 float* dst = _dst.ptr<float>(i);
                 for( j = 0; j < width_n; j++ )
                 {
                     float s = src[j];
+                    dst[j] = (float)(s > thresh ? thresh : s);
+                }
+            }
+            else
+            {
+                const double* src = _src.ptr<double>(i);
+                double* dst = _dst.ptr<double>(i);
+                for( j = 0; j < width_n; j++ )
+                {
+                    double s = src[j];
                     dst[j] = s > thresh ? thresh : s;
                 }
             }
@@ -258,7 +282,7 @@ static void test_threshold( const Mat& _src, Mat& _dst,
                     dst[j] = (short)(s > ithresh ? s : 0);
                 }
             }
-            else
+            else if( depth == CV_32F )
             {
                 const float* src = _src.ptr<float>(i);
                 float* dst = _dst.ptr<float>(i);
@@ -268,6 +292,16 @@ static void test_threshold( const Mat& _src, Mat& _dst,
                     dst[j] = s > thresh ? s : 0.f;
                 }
             }
+            else
+            {
+                const double* src = _src.ptr<double>(i);
+                double* dst = _dst.ptr<double>(i);
+                for( j = 0; j < width_n; j++ )
+                {
+                    double s = src[j];
+                    dst[j] = s > thresh ? s : 0.0;
+                }
+            }
         }
         break;
     case CV_THRESH_TOZERO_INV:
@@ -293,7 +327,7 @@ static void test_threshold( const Mat& _src, Mat& _dst,
                     dst[j] = (short)(s > ithresh ? 0 : s);
                 }
             }
-            else
+            else if (depth == CV_32F)
             {
                 const float* src = _src.ptr<float>(i);
                 float* dst = _dst.ptr<float>(i);
@@ -303,6 +337,16 @@ static void test_threshold( const Mat& _src, Mat& _dst,
                     dst[j] = s > thresh ? 0.f : s;
                 }
             }
+            else
+            {
+                const double* src = _src.ptr<double>(i);
+                double* dst = _dst.ptr<double>(i);
+                for( j = 0; j < width_n; j++ )
+                {
+                    double s = src[j];
+                    dst[j] = s > thresh ? 0.0 : s;
+                }
+            }
         }
         break;
     default:
diff --git a/modules/java/CMakeLists.txt b/modules/java/CMakeLists.txt
index 9f241d3..ed92e05 100644
--- a/modules/java/CMakeLists.txt
+++ b/modules/java/CMakeLists.txt
@@ -129,7 +129,7 @@ set(scripts_gen_java "${CMAKE_CURRENT_SOURCE_DIR}/generator/gen_java.py")
 set(scripts_hdr_parser "${CMAKE_CURRENT_SOURCE_DIR}/../python/src2/hdr_parser.py")
 
 # directory to store temporary files generated on first gen_java.py run
-set(probe_dir "${CMAKE_CURRENT_BINARY_DIR}/gen_java_out")
+set(probe_dir "${CMAKE_CURRENT_BINARY_DIR}/test_gen")
 
 # handwritten C/C++ and Java sources
 glob_more_specific_sources(H "${CMAKE_CURRENT_SOURCE_DIR}/generator" handwritten_h_sources)
@@ -159,10 +159,19 @@ foreach(module ${OPENCV_JAVA_MODULES})
 
   set(opencv_public_headers_${module} ${module_headers})
   list(APPEND opencv_public_headers ${module_headers})
-  list(APPEND generated_cpp_sources "${CMAKE_CURRENT_BINARY_DIR}/${module}.cpp")
+  list(APPEND generated_cpp_sources "${CMAKE_CURRENT_BINARY_DIR}/gen/${module}.cpp")
 
   include_directories("${module_java_dir}/src/cpp")
 
+  foreach(m ${OPENCV_MODULE_opencv_${module}_DEPS})
+    set(common_header_list "${OPENCV_MODULE_${m}_LOCATION}/misc/java/filelist_common")
+    if(EXISTS "${common_header_list}")
+      file(STRINGS "${common_header_list}" __headers)
+      ocv_list_add_prefix(__headers "${OPENCV_MODULE_${m}_LOCATION}/")
+      list(APPEND opencv_java_common_headers_${module} ${__headers})
+    endif()
+  endforeach()
+
   glob_more_specific_sources(H "${module_java_dir}" handwritten_h_sources)
   glob_more_specific_sources(CPP "${module_java_dir}" handwritten_cpp_sources)
   glob_more_specific_sources(JAVA "${module_java_dir}" handwritten_java_sources)
@@ -171,11 +180,11 @@ foreach(module ${OPENCV_JAVA_MODULES})
   # first run of gen_java.py (to get list of generated files)
   file(REMOVE_RECURSE "${probe_dir}")
   file(MAKE_DIRECTORY "${probe_dir}")
-  execute_process(COMMAND ${PYTHON_DEFAULT_EXECUTABLE} "${scripts_gen_java}" "${scripts_hdr_parser}" ${module} ${opencv_public_headers_${module}}
+  execute_process(COMMAND ${PYTHON_DEFAULT_EXECUTABLE} "${scripts_gen_java}" "${scripts_hdr_parser}" ${module} ${opencv_public_headers_${module}} "--common" ${opencv_java_common_headers_${module}}
                   WORKING_DIRECTORY "${probe_dir}"
                   OUTPUT_QUIET ERROR_QUIET)
   file(GLOB_RECURSE generated_java_sources_${module} RELATIVE "${probe_dir}" "${probe_dir}/*.java")
-  ocv_list_add_prefix(generated_java_sources_${module} "${CMAKE_CURRENT_BINARY_DIR}/")
+  ocv_list_add_prefix(generated_java_sources_${module} "${CMAKE_CURRENT_BINARY_DIR}/gen/")
   list(APPEND generated_java_sources ${generated_java_sources_${module}})
 endforeach()
 
@@ -205,13 +214,14 @@ add_cmake_dependencies(${scripts_gen_java} ${scripts_hdr_parser} ${opencv_public
 ######################################################################################################################################
 
 # step 1: generate .cpp/.java from OpenCV headers
+file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/gen")
 set(step1_depends "${scripts_gen_java}" "${scripts_hdr_parser}" ${opencv_public_headers})
 foreach(module ${OPENCV_JAVA_MODULES})
   # second run of gen_java.py (at build time)
-  add_custom_command(OUTPUT ${generated_java_sources_${module}} "${CMAKE_CURRENT_BINARY_DIR}/${module}.cpp"
-                     COMMAND ${PYTHON_DEFAULT_EXECUTABLE} "${scripts_gen_java}" "${scripts_hdr_parser}" ${module} ${opencv_public_headers_${module}}
-                     WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
-                     DEPENDS "${scripts_gen_java}" "${scripts_hdr_parser}" ${opencv_public_headers_${module}}
+  add_custom_command(OUTPUT ${generated_java_sources_${module}} "${CMAKE_CURRENT_BINARY_DIR}/gen/${module}.cpp"
+                     COMMAND ${PYTHON_DEFAULT_EXECUTABLE} "${scripts_gen_java}" "${scripts_hdr_parser}" ${module} ${opencv_public_headers_${module}} "--common" ${opencv_java_common_headers_${module}}
+                     WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/gen/"
+                     DEPENDS "${scripts_gen_java}" "${scripts_hdr_parser}" ${opencv_public_headers_${module}} ${opencv_java_common_headers_${module}}
                     )
 endforeach()
 
@@ -287,9 +297,12 @@ if(ANDROID AND ANDROID_EXECUTABLE)
 
   install(FILES "${OpenCV_BINARY_DIR}/${ANDROID_PROJECT_PROPERTIES_FILE}" DESTINATION ${JAVA_INSTALL_ROOT} COMPONENT java)
   install(FILES "${OpenCV_BINARY_DIR}/${ANDROID_MANIFEST_FILE}" DESTINATION ${JAVA_INSTALL_ROOT} COMPONENT java)
+
   # creating empty 'gen' and 'res' folders
-  install(CODE "MAKE_DIRECTORY(\"\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/${JAVA_INSTALL_ROOT}/gen\")" COMPONENT java)
-  install(CODE "MAKE_DIRECTORY(\"\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/${JAVA_INSTALL_ROOT}/res\")" COMPONENT java)
+  file(MAKE_DIRECTORY ${OpenCV_BINARY_DIR}/sdk/java/gen ${OpenCV_BINARY_DIR}/sdk/java/res )
+
+  install(DIRECTORY ${OpenCV_BINARY_DIR}/sdk/java/gen DESTINATION ${JAVA_INSTALL_ROOT}/ COMPONENT java)
+  install(DIRECTORY ${OpenCV_BINARY_DIR}/sdk/java/res DESTINATION ${JAVA_INSTALL_ROOT}/ COMPONENT java)
 endif(ANDROID AND ANDROID_EXECUTABLE)
 
 set(step3_depends ${step2_depends} ${step3_input_files} ${copied_files})
@@ -346,17 +359,11 @@ endif(ANDROID)
 
 # workarounding lack of `__attribute__ ((visibility("default")))` in jni_md.h/JNIEXPORT
 string(REPLACE "-fvisibility=hidden" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
+ocv_warnings_disable(CMAKE_CXX_FLAGS -Wunused-const-variable)
 
-if(ANDROID)
-  # Android native code need to link with libopencv_java.so
-  ocv_add_library(${the_module} SHARED ${handwritten_h_sources} ${handwritten_cpp_sources} ${generated_cpp_sources}
+ocv_add_library(${the_module} SHARED ${handwritten_h_sources} ${handwritten_cpp_sources} ${generated_cpp_sources}
                                  ${copied_files}
                                 "${JAR_FILE}" "${JAR_FILE}.dephelper")
-else()
-  ocv_add_library(${the_module} MODULE ${handwritten_h_sources} ${handwritten_cpp_sources} ${generated_cpp_sources}
-                                 ${copied_files}
-                                "${JAR_FILE}" "${JAR_FILE}.dephelper")
-endif()
 
 if(BUILD_FAT_JAVA_LIB)
   set(__deps ${OPENCV_MODULE_${the_module}_DEPS} ${OPENCV_MODULES_BUILD})
@@ -390,7 +397,6 @@ set_target_properties(${the_module} PROPERTIES
     ARCHIVE_OUTPUT_DIRECTORY ${LIBRARY_OUTPUT_PATH}
     LIBRARY_OUTPUT_DIRECTORY ${LIBRARY_OUTPUT_PATH}
     RUNTIME_OUTPUT_DIRECTORY ${EXECUTABLE_OUTPUT_PATH}
-    INSTALL_NAME_DIR ${OPENCV_LIB_INSTALL_PATH}
     LINK_INTERFACE_LIBRARIES ""
     )
 
diff --git a/modules/java/android_test/src/org/opencv/test/OpenCVTestCase.java b/modules/java/android_test/src/org/opencv/test/OpenCVTestCase.java
index 78eb738..2cd2b86 100644
--- a/modules/java/android_test/src/org/opencv/test/OpenCVTestCase.java
+++ b/modules/java/android_test/src/org/opencv/test/OpenCVTestCase.java
@@ -24,13 +24,24 @@ import org.opencv.core.KeyPoint;
 import org.opencv.imgcodecs.Imgcodecs;
 
 import android.util.Log;
+import java.lang.reflect.Method;
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
 
 public class OpenCVTestCase extends TestCase {
+
+    public static class TestSkipException extends RuntimeException {
+        public TestSkipException() {}
+    }
+
     //change to 'true' to unblock fail on fail("Not yet implemented")
     public static final boolean passNYI = true;
 
     protected static boolean isTestCaseEnabled = true;
 
+    protected static final String XFEATURES2D = "org.opencv.xfeatures2d.";
+    protected static final String DEFAULT_FACTORY = "create";
+
     protected static final int matSize = 10;
     protected static final double EPS = 0.001;
     protected static final double weakEPS = 0.5;
@@ -182,12 +193,40 @@ public class OpenCVTestCase extends TestCase {
     protected void runTest() throws Throwable {
         // Do nothing if the precondition does not hold.
         if (isTestCaseEnabled) {
-            super.runTest();
+            try {
+                super.runTest();
+            } catch (TestSkipException ex) {
+                Log.w(TAG, "Test case \"" + this.getClass().getName() + "\" skipped!");
+                assertTrue(true);
+            }
         } else {
             Log.e(TAG, "Test case \"" + this.getClass().getName() + "\" disabled!");
         }
     }
 
+    public void runBare() throws Throwable {
+        Throwable exception = null;
+        try {
+            setUp();
+        } catch (TestSkipException ex) {
+            Log.w(TAG, "Test case \"" + this.getClass().getName() + "\" skipped!");
+            assertTrue(true);
+            return;
+        }
+        try {
+            runTest();
+        } catch (Throwable running) {
+            exception = running;
+        } finally {
+            try {
+                tearDown();
+            } catch (Throwable tearingDown) {
+                if (exception == null) exception = tearingDown;
+            }
+        }
+        if (exception != null) throw exception;
+    }
+
     protected Mat getMat(int type, double... vals)
     {
         return new Mat(matSize, matSize, type, new Scalar(vals));
@@ -205,6 +244,10 @@ public class OpenCVTestCase extends TestCase {
         TestCase.fail(msg);
     }
 
+    public static void assertGE(double v1, double v2) {
+        assertTrue("Failed: " + v1 + " >= " + v2, v1 >= v2);
+    }
+
     public static <E extends Number> void assertListEquals(List<E> list1, List<E> list2) {
         if (list1.size() != list2.size()) {
             throw new UnsupportedOperationException();
@@ -419,10 +462,10 @@ public class OpenCVTestCase extends TestCase {
 
         if (isEqualityMeasured)
             assertTrue("Max difference between expected and actiual Mats is "+ maxDiff + ", that bigger than " + eps,
-                    Core.checkRange(diff, true, 0.0, eps));
+                    maxDiff <= eps);
         else
             assertFalse("Max difference between expected and actiual Mats is "+ maxDiff + ", that less than " + eps,
-                    Core.checkRange(diff, true, 0.0, eps));
+                    maxDiff <= eps);
     }
 
     protected static String readFile(String path) {
@@ -461,4 +504,82 @@ public class OpenCVTestCase extends TestCase {
         }
     }
 
+    protected <T> T createClassInstance(String cname, String factoryName, Class cParams[], Object oValues[]) {
+        T instance = null;
+
+        assertFalse("Class name should not be empty", "".equals(cname));
+
+        String message="";
+        try {
+            Class algClass = getClassForName(cname);
+            Method factory = null;
+
+            if(cParams!=null && cParams.length>0) {
+                if(!"".equals(factoryName)) {
+                    factory = algClass.getDeclaredMethod(factoryName, cParams);
+                    instance = (T) factory.invoke(null, oValues);
+                }
+                else {
+                    instance = (T) algClass.getConstructor(cParams).newInstance(oValues);
+                }
+            }
+            else {
+                if(!"".equals(factoryName)) {
+                    factory = algClass.getDeclaredMethod(factoryName);
+                    instance = (T) factory.invoke(null);
+                }
+                else {
+                    instance = (T) algClass.getConstructor().newInstance();
+                }
+            }
+        }
+        catch(Exception ex) {
+            if (cname.startsWith(XFEATURES2D))
+            {
+                throw new TestSkipException();
+            }
+            message = TAG + " :: " + "could not instantiate " + cname + "! Exception: " + ex.getMessage();
+        }
+
+        assertTrue(message, instance!=null);
+
+        return instance;
+    }
+
+    protected <T> void setProperty(T instance, String propertyName, String propertyType, Object propertyValue) {
+        String message = "";
+        try {
+            String smethod = "set" + propertyName.substring(0,1).toUpperCase() + propertyName.substring(1);
+            Method setter = instance.getClass().getMethod(smethod, getClassForName(propertyType));
+            setter.invoke(instance, propertyValue);
+        }
+        catch(Exception ex) {
+            message = "Error when setting property [" + propertyName + "]: " + ex.getMessage();
+        }
+
+        assertTrue(message, "".equals(message));
+    }
+
+    protected Class getClassForName(String sclass) throws ClassNotFoundException{
+        if("int".equals(sclass))
+            return Integer.TYPE;
+        else if("long".equals(sclass))
+            return Long.TYPE;
+        else if("double".equals(sclass))
+            return Double.TYPE;
+        else if("float".equals(sclass))
+            return Float.TYPE;
+        else if("boolean".equals(sclass))
+            return Boolean.TYPE;
+        else if("char".equals(sclass))
+            return Character.TYPE;
+        else if("byte".equals(sclass))
+            return Byte.TYPE;
+        else if("short".equals(sclass))
+            return Short.TYPE;
+        else
+            return Class.forName(sclass);
+
+    }
+
 }
diff --git a/modules/java/generator/gen_java.py b/modules/java/generator/gen_java.py
index 8c86975..fc8cc14 100755
--- a/modules/java/generator/gen_java.py
+++ b/modules/java/generator/gen_java.py
@@ -13,6 +13,8 @@ else:
 class_ignore_list = (
     #core
     "FileNode", "FileStorage", "KDTree", "KeyPoint", "DMatch",
+    #features2d
+    "SimpleBlobDetector"
 )
 
 const_ignore_list = (
@@ -781,6 +783,7 @@ class ClassInfo(GeneralInfo):
         self.imports = set()
         self.props= []
         self.jname = self.name
+        self.smart = None # True if class stores Ptr<T>* instead of T* in nativeObj field
         self.j_code = None # java code stream
         self.jn_code = None # jni code stream
         self.cpp_code = None # cpp code stream
@@ -793,7 +796,7 @@ class ClassInfo(GeneralInfo):
             self.base = re.sub(r"^.*:", "", decl[1].split(",")[0]).strip().replace(self.jname, "")
 
     def __repr__(self):
-        return Template("CLASS $namespace.$classpath.$name : $base").substitute(**self.__dict__)
+        return Template("CLASS $namespace::$classpath.$name : $base").substitute(**self.__dict__)
 
     def getAllImports(self, module):
         return ["import %s;" % c for c in sorted(self.imports) if not c.startswith('org.opencv.'+module)]
@@ -805,6 +808,8 @@ class ClassInfo(GeneralInfo):
             self.imports.add("java.util.List")
             self.imports.add("java.util.ArrayList")
             self.addImports(ctype.replace('vector_vector', 'vector'))
+        elif ctype.startswith('Feature2D'):
+            self.imports.add("org.opencv.features2d.Feature2D")
         elif ctype.startswith('vector'):
             self.imports.add("org.opencv.core.Mat")
             self.imports.add('java.util.ArrayList')
@@ -989,12 +994,12 @@ class JavaWrapperGenerator(object):
 
         if classinfo.base:
             classinfo.addImports(classinfo.base)
-            type_dict["Ptr_"+name] = \
-                { "j_type" : name,
-                  "jn_type" : "long", "jn_args" : (("__int64", ".nativeObj"),),
-                  "jni_name" : "Ptr<"+name+">(("+name+"*)%(n)s_nativeObj)", "jni_type" : "jlong",
-                  "suffix" : "J" }
-        logging.info('ok: %s', classinfo)
+        type_dict["Ptr_"+name] = \
+            { "j_type" : classinfo.jname,
+              "jn_type" : "long", "jn_args" : (("__int64", ".nativeObj"),),
+              "jni_name" : "Ptr<"+classinfo.fullName(isCPP=True)+">(("+classinfo.fullName(isCPP=True)+"*)%(n)s_nativeObj)", "jni_type" : "jlong",
+              "suffix" : "J" }
+        logging.info('ok: class %s, name: %s, base: %s', classinfo, name, classinfo.base)
 
     def add_const(self, decl): # [ "const cname", val, [], [] ]
         constinfo = ConstInfo(decl, namespaces=self.namespaces)
@@ -1035,16 +1040,20 @@ class JavaWrapperGenerator(object):
         f.write(buf)
         f.close()
 
-    def gen(self, srcfiles, module, output_path):
+    def gen(self, srcfiles, module, output_path, common_headers):
         self.clear()
         self.module = module
         self.Module = module.capitalize()
-        parser = hdr_parser.CppHeaderParser()
+        # TODO: support UMat versions of declarations (implement UMat-wrapper for Java)
+        parser = hdr_parser.CppHeaderParser(generate_umat_decls=False)
 
         self.add_class( ['class ' + self.Module, '', [], []] ) # [ 'class/struct cname', ':bases', [modlist] [props] ]
 
         # scan the headers and build more descriptive maps of classes, consts, functions
         includes = [];
+        for hdr in common_headers:
+            logging.info("\n===== Common header : %s =====", hdr)
+            includes.append('#include "' + hdr + '"')
         for hdr in srcfiles:
             decls = parser.parse(hdr)
             self.namespaces = parser.namespaces
@@ -1052,6 +1061,8 @@ class JavaWrapperGenerator(object):
             logging.info("Namespaces: %s", parser.namespaces)
             if decls:
                 includes.append('#include "' + hdr + '"')
+            else:
+                logging.info("Ignore header: %s", hdr)
             for decl in decls:
                 logging.info("\n--- Incoming ---\n%s", pformat(decl, 4))
                 name = decl[0]
@@ -1150,6 +1161,7 @@ class JavaWrapperGenerator(object):
 
         # java args
         args = fi.args[:] # copy
+        j_signatures=[]
         suffix_counter = int(ci.methods_suffixes.get(fi.jname, -1))
         while True:
             suffix_counter += 1
@@ -1228,6 +1240,25 @@ class JavaWrapperGenerator(object):
                                 i += 1
                             j_epilogue.append( "if("+a.name+"!=null){ " + "; ".join(set_vals) + "; } ")
 
+            # calculate java method signature to check for uniqueness
+            j_args = []
+            for a in args:
+                if not a.ctype: #hidden
+                    continue
+                jt = type_dict[a.ctype]["j_type"]
+                if a.out and a.ctype in ('bool', 'int', 'long', 'float', 'double'):
+                    jt += '[]'
+                j_args.append( jt + ' ' + a.name )
+            j_signature = type_dict[fi.ctype]["j_type"] + " " + \
+                fi.jname + "(" + ", ".join(j_args) + ")"
+            logging.info("java: " + j_signature)
+
+            if(j_signature in j_signatures):
+                if args:
+                    pop(args)
+                    continue
+                else:
+                    break
 
             # java part:
             # private java NATIVE method decl
@@ -1292,15 +1323,6 @@ class JavaWrapperGenerator(object):
             if fi.classname:
                 static = fi.static
 
-            j_args = []
-            for a in args:
-                if not a.ctype: #hidden
-                    continue
-                jt = type_dict[a.ctype]["j_type"]
-                if a.out and a.ctype in ('bool', 'int', 'long', 'float', 'double'):
-                    jt += '[]'
-                j_args.append( jt + ' ' + a.name )
-
             j_code.write( Template(\
 """    public $static $j_type $j_name($j_args)
     {
@@ -1376,10 +1398,10 @@ class JavaWrapperGenerator(object):
                 elif fi.static:
                     cvname = fi.fullName(isCPP=True)
                 else:
-                    cvname = ("me->" if  not self.isSmartClass(fi.classname) else "(*me)->") + name
+                    cvname = ("me->" if  not self.isSmartClass(ci) else "(*me)->") + name
                     c_prologue.append(\
                         "%(cls)s* me = (%(cls)s*) self; //TODO: check for NULL" \
-                            % { "cls" : self.smartWrap(fi.classname, fi.fullClass(isCPP=True))} \
+                            % { "cls" : self.smartWrap(ci, fi.fullClass(isCPP=True))} \
                     )
             cvargs = []
             for a in args:
@@ -1404,6 +1426,8 @@ class JavaWrapperGenerator(object):
             clazz = ci.jname
             cpp_code.write ( Template( \
 """
+${namespace}
+
 JNIEXPORT $rtype JNICALL Java_org_opencv_${module}_${clazz}_$fname ($argst);
 
 JNIEXPORT $rtype JNICALL Java_org_opencv_${module}_${clazz}_$fname
@@ -1426,7 +1450,7 @@ JNIEXPORT $rtype JNICALL Java_org_opencv_${module}_${clazz}_$fname
 
 """ ).substitute( \
         rtype = rtype, \
-        module = self.module, \
+        module = self.module.replace('_', '_1'), \
         clazz = clazz.replace('_', '_1'), \
         fname = (fi.jname + '_' + str(suffix_counter)).replace('_', '_1'), \
         args  = ", ".join(["%s %s" % (type_dict[a.ctype].get("jni_type"), a.name) for a in jni_args]), \
@@ -1438,8 +1462,12 @@ JNIEXPORT $rtype JNICALL Java_org_opencv_${module}_${clazz}_$fname
         cvargs = ", ".join(cvargs), \
         default = default, \
         retval = retval, \
+        namespace = ('using namespace ' + ci.namespace.replace('.', '::') + ';') if ci.namespace else ''
     ) )
 
+            # adding method signature to dictionarry
+            j_signatures.append(j_signature)
+
             # processing args with default values
             if not args or not args[-1].defval:
                 break
@@ -1519,7 +1547,7 @@ JNIEXPORT void JNICALL Java_org_opencv_%(module)s_%(j_cls)s_delete
     delete (%(cls)s*) self;
 }
 
-""" % {"module" : module, "cls" : self.smartWrap(ci.name, ci.fullName(isCPP=True)), "j_cls" : ci.jname.replace('_', '_1')}
+""" % {"module" : module.replace('_', '_1'), "cls" : self.smartWrap(ci, ci.fullName(isCPP=True)), "j_cls" : ci.jname.replace('_', '_1')}
             )
 
     def getClass(self, classname):
@@ -1529,17 +1557,31 @@ JNIEXPORT void JNICALL Java_org_opencv_%(module)s_%(j_cls)s_delete
         name = classname or self.Module
         return name in self.classes
 
-    def isSmartClass(self, classname):
+    def isSmartClass(self, ci):
         '''
         Check if class stores Ptr<T>* instead of T* in nativeObj field
         '''
-        return self.isWrapped(classname) and self.classes[classname].base
+        if ci.smart != None:
+            return ci.smart
+
+        # if parents are smart (we hope) then children are!
+        # if not we believe the class is smart if it has "create" method
+        ci.smart = False
+        if ci.base:
+            ci.smart = True
+        else:
+            for fi in ci.methods:
+                if fi.name == "create":
+                    ci.smart = True
+                    break
+
+        return ci.smart
 
-    def smartWrap(self, name, fullname):
+    def smartWrap(self, ci, fullname):
         '''
         Wraps fullname with Ptr<> if needed
         '''
-        if self.isSmartClass(name):
+        if self.isSmartClass(ci):
             return "Ptr<" + fullname + ">"
         return fullname
 
@@ -1560,10 +1602,15 @@ if __name__ == "__main__":
     import hdr_parser
     module = sys.argv[2]
     srcfiles = sys.argv[3:]
+    common_headers = []
+    if '--common' in srcfiles:
+        pos = srcfiles.index('--common')
+        common_headers = srcfiles[pos+1:]
+        srcfiles = srcfiles[:pos]
     logging.basicConfig(filename='%s/%s.log' % (dstdir, module), format=None, filemode='w', level=logging.INFO)
     handler = logging.StreamHandler()
     handler.setLevel(logging.WARNING)
     logging.getLogger().addHandler(handler)
     #print("Generating module '" + module + "' from headers:\n\t" + "\n\t".join(srcfiles))
     generator = JavaWrapperGenerator()
-    generator.gen(srcfiles, module, dstdir)
+    generator.gen(srcfiles, module, dstdir, common_headers)
diff --git a/modules/java/generator/src/cpp/Mat.cpp b/modules/java/generator/src/cpp/Mat.cpp
index d8483cd..c85a3d7 100644
--- a/modules/java/generator/src/cpp/Mat.cpp
+++ b/modules/java/generator/src/cpp/Mat.cpp
@@ -1815,6 +1815,29 @@ JNIEXPORT jint JNICALL Java_org_opencv_core_Mat_nPutD
 
 } // extern "C"
 
+namespace {
+  /// map java-array-types to assigned data
+  template<class T> struct JavaOpenCVTrait;
+
+/// less typing for specialisations
+#define JOCvT(t,s,c1,c2) \
+  template<> struct JavaOpenCVTrait<t##Array> { \
+    typedef t value_type;    /* type of array element */ \
+    static const char get[]; /* name of getter */ \
+    static const char put[]; /* name of putter */ \
+    enum {cvtype_1 = c1, cvtype_2 = c2 }; /* allowed OpenCV-types */ \
+  }; \
+  const char JavaOpenCVTrait<t##Array>::get[] = "Mat::nGet" s "()"; \
+  const char JavaOpenCVTrait<t##Array>::put[] = "Mat::nPut" s "()"
+
+  JOCvT(jbyte, "B", CV_8U, CV_8S);
+  JOCvT(jshort, "S", CV_16U, CV_16S);
+  JOCvT(jint, "I", CV_32S, CV_32S);
+  JOCvT(jfloat, "F", CV_32F, CV_32F);
+  JOCvT(jdouble, "D", CV_64F, CV_64F);
+#undef JOCvT
+}
+
 template<typename T> static int mat_put(cv::Mat* m, int row, int col, int count, char* buff)
 {
     if(! m) return 0;
@@ -1845,26 +1868,19 @@ template<typename T> static int mat_put(cv::Mat* m, int row, int col, int count,
     return res;
 }
 
-
-extern "C" {
-
-JNIEXPORT jint JNICALL Java_org_opencv_core_Mat_nPutB
-    (JNIEnv* env, jclass, jlong self, jint row, jint col, jint count, jbyteArray vals);
-
-JNIEXPORT jint JNICALL Java_org_opencv_core_Mat_nPutB
-    (JNIEnv* env, jclass, jlong self, jint row, jint col, jint count, jbyteArray vals)
+template<class ARRAY> static jint java_mat_put(JNIEnv* env, jlong self, jint row, jint col, jint count, ARRAY vals)
 {
-    static const char method_name[] = "Mat::nPutB()";
+    static const char *method_name = JavaOpenCVTrait<ARRAY>::put;
     try {
         LOGD("%s", method_name);
         cv::Mat* me = (cv::Mat*) self;
         if(! self) return 0; // no native object behind
-        if(me->depth() != CV_8U && me->depth() != CV_8S) return 0; // incompatible type
+        if(me->depth() != JavaOpenCVTrait<ARRAY>::cvtype_1 && me->depth() != JavaOpenCVTrait<ARRAY>::cvtype_2) return 0; // incompatible type
         if(me->rows<=row || me->cols<=col) return 0; // indexes out of range
 
         char* values = (char*)env->GetPrimitiveArrayCritical(vals, 0);
-        int res = mat_put<char>(me, row, col, count, values);
-        env->ReleasePrimitiveArrayCritical(vals, values, 0);
+        int res = mat_put<typename JavaOpenCVTrait<ARRAY>::value_type>(me, row, col, count, values);
+        env->ReleasePrimitiveArrayCritical(vals, values, JNI_ABORT);
         return res;
     } catch(const std::exception &e) {
         throwJavaException(env, &e, method_name);
@@ -1875,31 +1891,24 @@ JNIEXPORT jint JNICALL Java_org_opencv_core_Mat_nPutB
     return 0;
 }
 
+extern "C" {
+
+JNIEXPORT jint JNICALL Java_org_opencv_core_Mat_nPutB
+    (JNIEnv* env, jclass, jlong self, jint row, jint col, jint count, jbyteArray vals);
+
+JNIEXPORT jint JNICALL Java_org_opencv_core_Mat_nPutB
+    (JNIEnv* env, jclass, jlong self, jint row, jint col, jint count, jbyteArray vals)
+{
+  return java_mat_put(env, self, row, col, count, vals);
+}
+
 JNIEXPORT jint JNICALL Java_org_opencv_core_Mat_nPutS
     (JNIEnv* env, jclass, jlong self, jint row, jint col, jint count, jshortArray vals);
 
 JNIEXPORT jint JNICALL Java_org_opencv_core_Mat_nPutS
     (JNIEnv* env, jclass, jlong self, jint row, jint col, jint count, jshortArray vals)
 {
-    static const char method_name[] = "Mat::nPutS()";
-    try {
-        LOGD("%s", method_name);
-        cv::Mat* me = (cv::Mat*) self;
-        if(! self) return 0; // no native object behind
-        if(me->depth() != CV_16U && me->depth() != CV_16S) return 0; // incompatible type
-        if(me->rows<=row || me->cols<=col) return 0; // indexes out of range
-
-        char* values = (char*)env->GetPrimitiveArrayCritical(vals, 0);
-        int res = mat_put<short>(me, row, col, count, values);
-        env->ReleasePrimitiveArrayCritical(vals, values, 0);
-        return res;
-    } catch(const std::exception &e) {
-        throwJavaException(env, &e, method_name);
-    } catch (...) {
-        throwJavaException(env, 0, method_name);
-    }
-
-    return 0;
+  return java_mat_put(env, self, row, col, count, vals);
 }
 
 JNIEXPORT jint JNICALL Java_org_opencv_core_Mat_nPutI
@@ -1908,25 +1917,7 @@ JNIEXPORT jint JNICALL Java_org_opencv_core_Mat_nPutI
 JNIEXPORT jint JNICALL Java_org_opencv_core_Mat_nPutI
     (JNIEnv* env, jclass, jlong self, jint row, jint col, jint count, jintArray vals)
 {
-    static const char method_name[] = "Mat::nPutI()";
-    try {
-        LOGD("%s", method_name);
-        cv::Mat* me = (cv::Mat*) self;
-        if(! self) return 0; // no native object behind
-        if(me->depth() != CV_32S) return 0; // incompatible type
-        if(me->rows<=row || me->cols<=col) return 0; // indexes out of range
-
-        char* values = (char*)env->GetPrimitiveArrayCritical(vals, 0);
-        int res = mat_put<int>(me, row, col, count, values);
-        env->ReleasePrimitiveArrayCritical(vals, values, 0);
-        return res;
-    } catch(const std::exception &e) {
-        throwJavaException(env, &e, method_name);
-    } catch (...) {
-        throwJavaException(env, 0, method_name);
-    }
-
-    return 0;
+  return java_mat_put(env, self, row, col, count, vals);
 }
 
 JNIEXPORT jint JNICALL Java_org_opencv_core_Mat_nPutF
@@ -1935,31 +1926,12 @@ JNIEXPORT jint JNICALL Java_org_opencv_core_Mat_nPutF
 JNIEXPORT jint JNICALL Java_org_opencv_core_Mat_nPutF
     (JNIEnv* env, jclass, jlong self, jint row, jint col, jint count, jfloatArray vals)
 {
-    static const char method_name[] = "Mat::nPutF()";
-    try {
-        LOGD("%s", method_name);
-        cv::Mat* me = (cv::Mat*) self;
-        if(! self) return 0; // no native object behind
-        if(me->depth() != CV_32F) return 0; // incompatible type
-        if(me->rows<=row || me->cols<=col) return 0; // indexes out of range
-
-        char* values = (char*)env->GetPrimitiveArrayCritical(vals, 0);
-        int res = mat_put<float>(me, row, col, count, values);
-        env->ReleasePrimitiveArrayCritical(vals, values, 0);
-        return res;
-    } catch(const std::exception &e) {
-        throwJavaException(env, &e, method_name);
-    } catch (...) {
-        throwJavaException(env, 0, method_name);
-    }
-
-    return 0;
+  return java_mat_put(env, self, row, col, count, vals);
 }
 
-
 } // extern "C"
 
-template<typename T> int mat_get(cv::Mat* m, int row, int col, int count, char* buff)
+template<typename T> static int mat_get(cv::Mat* m, int row, int col, int count, char* buff)
 {
     if(! m) return 0;
     if(! buff) return 0;
@@ -1989,24 +1961,17 @@ template<typename T> int mat_get(cv::Mat* m, int row, int col, int count, char*
     return res;
 }
 
-extern "C" {
-
-JNIEXPORT jint JNICALL Java_org_opencv_core_Mat_nGetB
-    (JNIEnv* env, jclass, jlong self, jint row, jint col, jint count, jbyteArray vals);
-
-JNIEXPORT jint JNICALL Java_org_opencv_core_Mat_nGetB
-    (JNIEnv* env, jclass, jlong self, jint row, jint col, jint count, jbyteArray vals)
-{
-    static const char method_name[] = "Mat::nGetB()";
+template<class ARRAY> static jint java_mat_get(JNIEnv* env, jlong self, jint row, jint col, jint count, ARRAY vals) {
+    static const char *method_name = JavaOpenCVTrait<ARRAY>::get;
     try {
         LOGD("%s", method_name);
         cv::Mat* me = (cv::Mat*) self;
         if(! self) return 0; // no native object behind
-        if(me->depth() != CV_8U && me->depth() != CV_8S) return 0; // incompatible type
+        if(me->depth() != JavaOpenCVTrait<ARRAY>::cvtype_1 && me->depth() != JavaOpenCVTrait<ARRAY>::cvtype_2) return 0; // incompatible type
         if(me->rows<=row || me->cols<=col) return 0; // indexes out of range
 
         char* values = (char*)env->GetPrimitiveArrayCritical(vals, 0);
-        int res = mat_get<char>(me, row, col, count, values);
+        int res = mat_get<typename JavaOpenCVTrait<ARRAY>::value_type>(me, row, col, count, values);
         env->ReleasePrimitiveArrayCritical(vals, values, 0);
         return res;
     } catch(const std::exception &e) {
@@ -2018,31 +1983,24 @@ JNIEXPORT jint JNICALL Java_org_opencv_core_Mat_nGetB
     return 0;
 }
 
+extern "C" {
+
+JNIEXPORT jint JNICALL Java_org_opencv_core_Mat_nGetB
+    (JNIEnv* env, jclass, jlong self, jint row, jint col, jint count, jbyteArray vals);
+
+JNIEXPORT jint JNICALL Java_org_opencv_core_Mat_nGetB
+    (JNIEnv* env, jclass, jlong self, jint row, jint col, jint count, jbyteArray vals)
+{
+  return java_mat_get(env, self, row, col, count, vals);
+}
+
 JNIEXPORT jint JNICALL Java_org_opencv_core_Mat_nGetS
     (JNIEnv* env, jclass, jlong self, jint row, jint col, jint count, jshortArray vals);
 
 JNIEXPORT jint JNICALL Java_org_opencv_core_Mat_nGetS
     (JNIEnv* env, jclass, jlong self, jint row, jint col, jint count, jshortArray vals)
 {
-    static const char method_name[] = "Mat::nGetS()";
-    try {
-        LOGD("%s", method_name);
-        cv::Mat* me = (cv::Mat*) self;
-        if(! self) return 0; // no native object behind
-        if(me->depth() != CV_16U && me->depth() != CV_16S) return 0; // incompatible type
-        if(me->rows<=row || me->cols<=col) return 0; // indexes out of range
-
-        char* values = (char*)env->GetPrimitiveArrayCritical(vals, 0);
-        int res = mat_get<short>(me, row, col, count, values);
-        env->ReleasePrimitiveArrayCritical(vals, values, 0);
-        return res;
-    } catch(const std::exception &e) {
-        throwJavaException(env, &e, method_name);
-    } catch (...) {
-        throwJavaException(env, 0, method_name);
-    }
-
-    return 0;
+  return java_mat_get(env, self, row, col, count, vals);
 }
 
 JNIEXPORT jint JNICALL Java_org_opencv_core_Mat_nGetI
@@ -2051,25 +2009,7 @@ JNIEXPORT jint JNICALL Java_org_opencv_core_Mat_nGetI
 JNIEXPORT jint JNICALL Java_org_opencv_core_Mat_nGetI
     (JNIEnv* env, jclass, jlong self, jint row, jint col, jint count, jintArray vals)
 {
-    static const char method_name[] = "Mat::nGetI()";
-    try {
-        LOGD("%s", method_name);
-        cv::Mat* me = (cv::Mat*) self;
-        if(! self) return 0; // no native object behind
-        if(me->depth() != CV_32S) return 0; // incompatible type
-        if(me->rows<=row || me->cols<=col) return 0; // indexes out of range
-
-        char* values = (char*)env->GetPrimitiveArrayCritical(vals, 0);
-        int res = mat_get<int>(me, row, col, count, values);
-        env->ReleasePrimitiveArrayCritical(vals, values, 0);
-        return res;
-    } catch(const std::exception &e) {
-        throwJavaException(env, &e, method_name);
-    } catch (...) {
-        throwJavaException(env, 0, method_name);
-    }
-
-    return 0;
+  return java_mat_get(env, self, row, col, count, vals);
 }
 
 JNIEXPORT jint JNICALL Java_org_opencv_core_Mat_nGetF
@@ -2078,25 +2018,7 @@ JNIEXPORT jint JNICALL Java_org_opencv_core_Mat_nGetF
 JNIEXPORT jint JNICALL Java_org_opencv_core_Mat_nGetF
     (JNIEnv* env, jclass, jlong self, jint row, jint col, jint count, jfloatArray vals)
 {
-    static const char method_name[] = "Mat::nGetF()";
-    try {
-        LOGD("%s", method_name);
-        cv::Mat* me = (cv::Mat*) self;
-        if(! self) return 0; // no native object behind
-        if(me->depth() != CV_32F) return 0; // incompatible type
-        if(me->rows<=row || me->cols<=col) return 0; // indexes out of range
-
-        char* values = (char*)env->GetPrimitiveArrayCritical(vals, 0);
-        int res = mat_get<float>(me, row, col, count, values);
-        env->ReleasePrimitiveArrayCritical(vals, values, 0);
-        return res;
-    } catch(const std::exception &e) {
-        throwJavaException(env, &e, method_name);
-    } catch (...) {
-        throwJavaException(env, 0, method_name);
-    }
-
-    return 0;
+  return java_mat_get(env, self, row, col, count, vals);
 }
 
 JNIEXPORT jint JNICALL Java_org_opencv_core_Mat_nGetD
@@ -2105,25 +2027,7 @@ JNIEXPORT jint JNICALL Java_org_opencv_core_Mat_nGetD
 JNIEXPORT jint JNICALL Java_org_opencv_core_Mat_nGetD
     (JNIEnv* env, jclass, jlong self, jint row, jint col, jint count, jdoubleArray vals)
 {
-    static const char method_name[] = "Mat::nGetD()";
-    try {
-        LOGD("%s", method_name);
-        cv::Mat* me = (cv::Mat*) self;
-        if(! self) return 0; // no native object behind
-        if(me->depth() != CV_64F) return 0; // incompatible type
-        if(me->rows<=row || me->cols<=col) return 0; // indexes out of range
-
-        char* values = (char*)env->GetPrimitiveArrayCritical(vals, 0);
-        int res = mat_get<double>(me, row, col, count, values);
-        env->ReleasePrimitiveArrayCritical(vals, values, 0);
-        return res;
-    } catch(const std::exception &e) {
-        throwJavaException(env, &e, method_name);
-    } catch (...) {
-        throwJavaException(env, 0, method_name);
-    }
-
-    return 0;
+  return java_mat_get(env, self, row, col, count, vals);
 }
 
 JNIEXPORT jdoubleArray JNICALL Java_org_opencv_core_Mat_nGet
diff --git a/modules/java/generator/src/java/android+CameraBridgeViewBase.java b/modules/java/generator/src/java/android+CameraBridgeViewBase.java
index 14e0411..ef2af81 100644
--- a/modules/java/generator/src/java/android+CameraBridgeViewBase.java
+++ b/modules/java/generator/src/java/android+CameraBridgeViewBase.java
@@ -2,6 +2,7 @@ package org.opencv.android;
 
 import java.util.List;
 
+import org.opencv.BuildConfig;
 import org.opencv.R;
 import org.opencv.core.Mat;
 import org.opencv.core.Size;
@@ -409,7 +410,8 @@ public abstract class CameraBridgeViewBase extends SurfaceView implements Surfac
             Canvas canvas = getHolder().lockCanvas();
             if (canvas != null) {
                 canvas.drawColor(0, android.graphics.PorterDuff.Mode.CLEAR);
-                Log.d(TAG, "mStretch value: " + mScale);
+                if (BuildConfig.DEBUG)
+                    Log.d(TAG, "mStretch value: " + mScale);
 
                 if (mScale != 0) {
                     canvas.drawBitmap(mCacheBitmap, new Rect(0,0,mCacheBitmap.getWidth(), mCacheBitmap.getHeight()),
diff --git a/modules/java/generator/src/java/android+JavaCameraView.java b/modules/java/generator/src/java/android+JavaCameraView.java
index f4405c3..7b0ecd4 100644
--- a/modules/java/generator/src/java/android+JavaCameraView.java
+++ b/modules/java/generator/src/java/android+JavaCameraView.java
@@ -12,6 +12,7 @@ import android.util.AttributeSet;
 import android.util.Log;
 import android.view.ViewGroup.LayoutParams;
 
+import org.opencv.BuildConfig;
 import org.opencv.core.CvType;
 import org.opencv.core.Mat;
 import org.opencv.core.Size;
@@ -283,7 +284,8 @@ public class JavaCameraView extends CameraBridgeViewBase implements PreviewCallb
 
     @Override
     public void onPreviewFrame(byte[] frame, Camera arg1) {
-        Log.d(TAG, "Preview Frame received. Frame size: " + frame.length);
+        if (BuildConfig.DEBUG)
+            Log.d(TAG, "Preview Frame received. Frame size: " + frame.length);
         synchronized (this) {
             mFrameChain[mChainIdx].put(0, 0, frame);
             mCameraFrameReady = true;
diff --git a/modules/java/generator/src/java/android+OpenCVLoader.java b/modules/java/generator/src/java/android+OpenCVLoader.java
index b8a9705..a84a49e 100644
--- a/modules/java/generator/src/java/android+OpenCVLoader.java
+++ b/modules/java/generator/src/java/android+OpenCVLoader.java
@@ -58,6 +58,16 @@ public class OpenCVLoader
     public static final String OPENCV_VERSION_2_4_11 = "2.4.11";
 
     /**
+     * OpenCV Library version 2.4.12.
+     */
+    public static final String OPENCV_VERSION_2_4_12 = "2.4.12";
+
+    /**
+     * OpenCV Library version 2.4.13.
+     */
+    public static final String OPENCV_VERSION_2_4_13 = "2.4.13";
+
+    /**
      * OpenCV Library version 3.0.0.
      */
     public static final String OPENCV_VERSION_3_0_0 = "3.0.0";
@@ -67,6 +77,10 @@ public class OpenCVLoader
      */
     public static final String OPENCV_VERSION_3_1_0 = "3.1.0";
 
+    /**
+     * OpenCV Library version 3.2.0.
+     */
+    public static final String OPENCV_VERSION_3_2_0 = "3.2.0";
 
     /**
      * Loads and initializes OpenCV library from current application package. Roughly, it's an analog of system.loadLibrary("opencv_java").
diff --git a/modules/java/pure_test/build.xml b/modules/java/pure_test/build.xml
index 4b25a3c..6d74306 100644
--- a/modules/java/pure_test/build.xml
+++ b/modules/java/pure_test/build.xml
@@ -1,4 +1,5 @@
 <project>
+  <property environment="env"/>
   <property file="ant-${opencv.build.type}.properties"/>
   <property name="test.dir" value="testResults"/>
   <property name="build.dir" value="build"/>
@@ -37,9 +38,9 @@
 
   <target name="test">
     <mkdir dir="${test.dir}"/>
-    <junit printsummary="true" haltonfailure="false" haltonerror="false" showoutput="false" logfailedtests="true" maxmemory="256m">
+    <junit printsummary="true" haltonfailure="false" haltonerror="false" showoutput="true" logfailedtests="true" maxmemory="256m">
       <sysproperty key="java.library.path" path="${opencv.lib.path}"/>
-      <env key="PATH" path="${opencv.lib.path}"/>
+      <env key="PATH" path="${opencv.lib.path}:${env.PATH}:${env.Path}"/>
       <classpath refid="master-classpath"/>
       <classpath>
         <pathelement location="build/classes"/>
diff --git a/modules/java/pure_test/src/org/opencv/test/OpenCVTestCase.java b/modules/java/pure_test/src/org/opencv/test/OpenCVTestCase.java
index e7d1506..f369bb1 100644
--- a/modules/java/pure_test/src/org/opencv/test/OpenCVTestCase.java
+++ b/modules/java/pure_test/src/org/opencv/test/OpenCVTestCase.java
@@ -4,11 +4,10 @@ package org.opencv.test;
 
 import java.io.BufferedReader;
 import java.io.File;
-import java.io.FileInputStream;
 import java.io.FileOutputStream;
 import java.io.FileReader;
 import java.io.IOException;
-import java.nio.MappedByteBuffer;
+import java.lang.reflect.Method;
 import java.nio.channels.FileChannel;
 import java.nio.charset.Charset;
 import java.util.List;
@@ -28,11 +27,19 @@ import org.opencv.core.KeyPoint;
 import org.opencv.imgcodecs.Imgcodecs;
 
 public class OpenCVTestCase extends TestCase {
+
+    public static class TestSkipException extends RuntimeException {
+        public TestSkipException() {}
+    }
+
     //change to 'true' to unblock fail on fail("Not yet implemented")
     public static final boolean passNYI = true;
 
     protected static boolean isTestCaseEnabled = true;
 
+    protected static final String XFEATURES2D = "org.opencv.xfeatures2d.";
+    protected static final String DEFAULT_FACTORY = "create";
+
     protected static final int matSize = 10;
     protected static final double EPS = 0.001;
     protected static final double weakEPS = 0.5;
@@ -212,12 +219,40 @@ public class OpenCVTestCase extends TestCase {
     protected void runTest() throws Throwable {
         // Do nothing if the precondition does not hold.
         if (isTestCaseEnabled) {
-            super.runTest();
+            try {
+                super.runTest();
+            } catch (TestSkipException ex) {
+                OpenCVTestRunner.Log(TAG + " :: " + "Test case \"" + this.getClass().getName() + "\" skipped!");
+                assertTrue(true);
+            }
         } else {
             OpenCVTestRunner.Log(TAG + " :: " + "Test case \"" + this.getClass().getName() + "\" disabled!");
         }
     }
 
+    public void runBare() throws Throwable {
+        Throwable exception = null;
+        try {
+            setUp();
+        } catch (TestSkipException ex) {
+            OpenCVTestRunner.Log(TAG + " :: " + "Test case \"" + this.getClass().getName() + "\" skipped!");
+            assertTrue(true);
+            return;
+        }
+        try {
+            runTest();
+        } catch (Throwable running) {
+            exception = running;
+        } finally {
+            try {
+                tearDown();
+            } catch (Throwable tearingDown) {
+                if (exception == null) exception = tearingDown;
+            }
+        }
+        if (exception != null) throw exception;
+    }
+
     protected Mat getMat(int type, double... vals)
     {
         return new Mat(matSize, matSize, type, new Scalar(vals));
@@ -235,6 +270,10 @@ public class OpenCVTestCase extends TestCase {
         TestCase.fail(msg);
     }
 
+    public static void assertGE(double v1, double v2) {
+        assertTrue("Failed: " + v1 + " >= " + v2, v1 >= v2);
+    }
+
     public static <E extends Number> void assertListEquals(List<E> list1, List<E> list2) {
         if (list1.size() != list2.size()) {
             throw new UnsupportedOperationException();
@@ -449,10 +488,10 @@ public class OpenCVTestCase extends TestCase {
 
         if (isEqualityMeasured)
             assertTrue("Max difference between expected and actiual Mats is "+ maxDiff + ", that bigger than " + eps,
-                    Core.checkRange(diff, true, 0.0, eps));
+                    maxDiff <= eps);
         else
             assertFalse("Max difference between expected and actiual Mats is "+ maxDiff + ", that less than " + eps,
-                    Core.checkRange(diff, true, 0.0, eps));
+                    maxDiff <= eps);
     }
 
     protected static String readFile(String path) {
@@ -491,4 +530,81 @@ public class OpenCVTestCase extends TestCase {
         }
     }
 
+    protected <T> T createClassInstance(String cname, String factoryName, Class cParams[], Object oValues[]) {
+        T instance = null;
+
+        assertFalse("Class name should not be empty", "".equals(cname));
+
+        String message="";
+        try {
+            Class algClass = getClassForName(cname);
+            Method factory = null;
+
+            if(cParams!=null && cParams.length>0) {
+                if(!"".equals(factoryName)) {
+                    factory = algClass.getDeclaredMethod(factoryName, cParams);
+                    instance = (T) factory.invoke(null, oValues);
+                }
+                else {
+                    instance = (T) algClass.getConstructor(cParams).newInstance(oValues);
+                }
+            }
+            else {
+                if(!"".equals(factoryName)) {
+                    factory = algClass.getDeclaredMethod(factoryName);
+                    instance = (T) factory.invoke(null);
+                }
+                else {
+                    instance = (T) algClass.getConstructor().newInstance();
+                }
+            }
+        }
+        catch(Exception ex) {
+            if (cname.startsWith(XFEATURES2D))
+            {
+                throw new TestSkipException();
+            }
+            message = TAG + " :: " + "could not instantiate " + cname + "! Exception: " + ex.getMessage();
+        }
+
+        assertTrue(message, instance!=null);
+
+        return instance;
+    }
+
+    protected <T> void setProperty(T instance, String propertyName, String propertyType, Object propertyValue) {
+        String message = "";
+        try {
+            String smethod = "set" + propertyName.substring(0,1).toUpperCase() + propertyName.substring(1);
+            Method setter = instance.getClass().getMethod(smethod, getClassForName(propertyType));
+            setter.invoke(instance, propertyValue);
+        }
+        catch(Exception ex) {
+            message = "Error when setting property [" + propertyName + "]: " + ex.getMessage();
+        }
+
+        assertTrue(message, "".equals(message));
+    }
+
+    protected Class getClassForName(String sclass) throws ClassNotFoundException{
+        if("int".equals(sclass))
+            return Integer.TYPE;
+        else if("long".equals(sclass))
+            return Long.TYPE;
+        else if("double".equals(sclass))
+            return Double.TYPE;
+        else if("float".equals(sclass))
+            return Float.TYPE;
+        else if("boolean".equals(sclass))
+            return Boolean.TYPE;
+        else if("char".equals(sclass))
+            return Character.TYPE;
+        else if("byte".equals(sclass))
+            return Byte.TYPE;
+        else if("short".equals(sclass))
+            return Short.TYPE;
+        else
+            return Class.forName(sclass);
+
+    }
 }
diff --git a/modules/ml/include/opencv2/ml.hpp b/modules/ml/include/opencv2/ml.hpp
index 862f3f9..99f5883 100644
--- a/modules/ml/include/opencv2/ml.hpp
+++ b/modules/ml/include/opencv2/ml.hpp
@@ -41,8 +41,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_ML_HPP__
-#define __OPENCV_ML_HPP__
+#ifndef OPENCV_ML_HPP
+#define OPENCV_ML_HPP
 
 #ifdef __cplusplus
 #  include "opencv2/core.hpp"
@@ -190,6 +190,7 @@ public:
     CV_WRAP virtual Mat getTestSampleWeights() const = 0;
     CV_WRAP virtual Mat getVarIdx() const = 0;
     CV_WRAP virtual Mat getVarType() const = 0;
+    CV_WRAP Mat getVarSymbolFlags() const;
     CV_WRAP virtual int getResponseType() const = 0;
     CV_WRAP virtual Mat getTrainSampleIdx() const = 0;
     CV_WRAP virtual Mat getTestSampleIdx() const = 0;
@@ -224,6 +225,12 @@ public:
     CV_WRAP virtual void setTrainTestSplitRatio(double ratio, bool shuffle=true) = 0;
     CV_WRAP virtual void shuffleTrainTest() = 0;
 
+    /** @brief Returns matrix of test samples */
+    CV_WRAP Mat getTestSamples() const;
+
+    /** @brief Returns vector of symbolic names captured in loadFromCSV() */
+    CV_WRAP void getNames(std::vector<String>& names) const;
+
     CV_WRAP static Mat getSubVector(const Mat& vec, const Mat& idx);
 
     /** @brief Reads the dataset from a .csv file and returns the ready-to-use training data.
@@ -719,6 +726,15 @@ public:
     Use StatModel::train to train the model. Since %SVM has several parameters, you may want to
     find the best parameters for your problem, it can be done with SVM::trainAuto. */
     CV_WRAP static Ptr<SVM> create();
+
+    /** @brief Loads and creates a serialized svm from a file
+     *
+     * Use SVM::save to serialize and store an SVM to disk.
+     * Load the SVM from this file again, by calling this function with the path to the file.
+     *
+     * @param filepath path to serialized svm
+     */
+    CV_WRAP static Ptr<SVM> load(const String& filepath);
 };
 
 /****************************************************************************************\
@@ -1389,6 +1405,16 @@ public:
     Note that the train method has optional flags: ANN_MLP::TrainFlags.
      */
     CV_WRAP static Ptr<ANN_MLP> create();
+
+    /** @brief Loads and creates a serialized ANN from a file
+     *
+     * Use ANN::save to serialize and store an ANN to disk.
+     * Load the ANN from this file again, by calling this function with the path to the file.
+     *
+     * @param filepath path to serialized ANN
+     */
+    CV_WRAP static Ptr<ANN_MLP> load(const String& filepath);
+
 };
 
 /****************************************************************************************\
@@ -1477,6 +1503,165 @@ public:
     CV_WRAP static Ptr<LogisticRegression> create();
 };
 
+
+/****************************************************************************************\
+*                        Stochastic Gradient Descent SVM Classifier                      *
+\****************************************************************************************/
+
+/*!
+ at brief Stochastic Gradient Descent SVM classifier
+
+SVMSGD provides a fast and easy-to-use implementation of the SVM classifier using the Stochastic Gradient Descent approach,
+as presented in @cite bottou2010large.
+
+The classifier has following parameters:
+- model type,
+- margin type,
+- margin regularization (\f$\lambda\f$),
+- initial step size (\f$\gamma_0\f$),
+- step decreasing power (\f$c\f$),
+- and termination criteria.
+
+The model type may have one of the following values: \ref SGD and \ref ASGD.
+
+- \ref SGD is the classic version of SVMSGD classifier: every next step is calculated by the formula
+  \f[w_{t+1} = w_t - \gamma(t) \frac{dQ_i}{dw} |_{w = w_t}\f]
+  where
+  - \f$w_t\f$ is the weights vector for decision function at step \f$t\f$,
+  - \f$\gamma(t)\f$ is the step size of model parameters at the iteration \f$t\f$, it is decreased on each step by the formula
+    \f$\gamma(t) = \gamma_0  (1 + \lambda  \gamma_0 t) ^ {-c}\f$
+  - \f$Q_i\f$ is the target functional from SVM task for sample with number \f$i\f$, this sample is chosen stochastically on each step of the algorithm.
+
+- \ref ASGD is Average Stochastic Gradient Descent SVM Classifier. ASGD classifier averages weights vector on each step of algorithm by the formula
+\f$\widehat{w}_{t+1} = \frac{t}{1+t}\widehat{w}_{t} + \frac{1}{1+t}w_{t+1}\f$
+
+The recommended model type is ASGD (following @cite bottou2010large).
+
+The margin type may have one of the following values: \ref SOFT_MARGIN or \ref HARD_MARGIN.
+
+- You should use \ref HARD_MARGIN type, if you have linearly separable sets.
+- You should use \ref SOFT_MARGIN type, if you have non-linearly separable sets or sets with outliers.
+- In the general case (if you know nothing about linear separability of your sets), use SOFT_MARGIN.
+
+The other parameters may be described as follows:
+- Margin regularization parameter is responsible for weights decreasing at each step and for the strength of restrictions on outliers
+  (the less the parameter, the less probability that an outlier will be ignored).
+  Recommended value for SGD model is 0.0001, for ASGD model is 0.00001.
+
+- Initial step size parameter is the initial value for the step size \f$\gamma(t)\f$.
+  You will have to find the best initial step for your problem.
+
+- Step decreasing power is the power parameter for \f$\gamma(t)\f$ decreasing by the formula, mentioned above.
+  Recommended value for SGD model is 1, for ASGD model is 0.75.
+
+- Termination criteria can be TermCriteria::COUNT, TermCriteria::EPS or TermCriteria::COUNT + TermCriteria::EPS.
+  You will have to find the best termination criteria for your problem.
+
+Note that the parameters margin regularization, initial step size, and step decreasing power should be positive.
+
+To use SVMSGD algorithm do as follows:
+
+- first, create the SVMSGD object. The algoorithm will set optimal parameters by default, but you can set your own parameters via functions setSvmsgdType(),
+  setMarginType(), setMarginRegularization(), setInitialStepSize(), and setStepDecreasingPower().
+
+- then the SVM model can be trained using the train features and the correspondent labels by the method train().
+
+- after that, the label of a new feature vector can be predicted using the method predict().
+
+ at code
+// Create empty object
+cv::Ptr<SVMSGD> svmsgd = SVMSGD::create();
+
+// Train the Stochastic Gradient Descent SVM
+svmsgd->train(trainData);
+
+// Predict labels for the new samples
+svmsgd->predict(samples, responses);
+ at endcode
+
+*/
+
+class CV_EXPORTS_W SVMSGD : public cv::ml::StatModel
+{
+public:
+
+    /** SVMSGD type.
+    ASGD is often the preferable choice. */
+    enum SvmsgdType
+    {
+        SGD, //!< Stochastic Gradient Descent
+        ASGD //!< Average Stochastic Gradient Descent
+    };
+
+    /** Margin type.*/
+    enum MarginType
+    {
+        SOFT_MARGIN, //!< General case, suits to the case of non-linearly separable sets, allows outliers.
+        HARD_MARGIN  //!< More accurate for the case of linearly separable sets.
+    };
+
+    /**
+     * @return the weights of the trained model (decision function f(x) = weights * x + shift).
+    */
+    CV_WRAP virtual Mat getWeights() = 0;
+
+    /**
+     * @return the shift of the trained model (decision function f(x) = weights * x + shift).
+    */
+    CV_WRAP virtual float getShift() = 0;
+
+    /** @brief Creates empty model.
+     * Use StatModel::train to train the model. Since %SVMSGD has several parameters, you may want to
+     * find the best parameters for your problem or use setOptimalParameters() to set some default parameters.
+    */
+    CV_WRAP static Ptr<SVMSGD> create();
+
+    /** @brief Function sets optimal parameters values for chosen SVM SGD model.
+     * @param svmsgdType is the type of SVMSGD classifier.
+     * @param marginType is the type of margin constraint.
+    */
+    CV_WRAP virtual void setOptimalParameters(int svmsgdType = SVMSGD::ASGD, int marginType = SVMSGD::SOFT_MARGIN) = 0;
+
+    /** @brief %Algorithm type, one of SVMSGD::SvmsgdType. */
+    /** @see setSvmsgdType */
+    CV_WRAP virtual int getSvmsgdType() const = 0;
+    /** @copybrief getSvmsgdType @see getSvmsgdType */
+    CV_WRAP virtual void setSvmsgdType(int svmsgdType) = 0;
+
+    /** @brief %Margin type, one of SVMSGD::MarginType. */
+    /** @see setMarginType */
+    CV_WRAP virtual int getMarginType() const = 0;
+    /** @copybrief getMarginType @see getMarginType */
+    CV_WRAP virtual void setMarginType(int marginType) = 0;
+
+    /** @brief Parameter marginRegularization of a %SVMSGD optimization problem. */
+    /** @see setMarginRegularization */
+    CV_WRAP virtual float getMarginRegularization() const = 0;
+    /** @copybrief getMarginRegularization @see getMarginRegularization */
+    CV_WRAP virtual void setMarginRegularization(float marginRegularization) = 0;
+
+    /** @brief Parameter initialStepSize of a %SVMSGD optimization problem. */
+    /** @see setInitialStepSize */
+    CV_WRAP virtual float getInitialStepSize() const = 0;
+    /** @copybrief getInitialStepSize @see getInitialStepSize */
+    CV_WRAP virtual void setInitialStepSize(float InitialStepSize) = 0;
+
+    /** @brief Parameter stepDecreasingPower of a %SVMSGD optimization problem. */
+    /** @see setStepDecreasingPower */
+    CV_WRAP virtual float getStepDecreasingPower() const = 0;
+    /** @copybrief getStepDecreasingPower @see getStepDecreasingPower */
+    CV_WRAP virtual void setStepDecreasingPower(float stepDecreasingPower) = 0;
+
+    /** @brief Termination criteria of the training algorithm.
+    You can specify the maximum number of iterations (maxCount) and/or how much the error could
+    change between the iterations to make the algorithm continue (epsilon).*/
+    /** @see setTermCriteria */
+    CV_WRAP virtual TermCriteria getTermCriteria() const = 0;
+    /** @copybrief getTermCriteria @see getTermCriteria */
+    CV_WRAP virtual void setTermCriteria(const cv::TermCriteria &val) = 0;
+};
+
+
 /****************************************************************************************\
 *                           Auxilary functions declarations                              *
 \****************************************************************************************/
@@ -1500,6 +1685,6 @@ CV_EXPORTS void createConcentricSpheresTestSet( int nsamples, int nfeatures, int
 }
 
 #endif // __cplusplus
-#endif // __OPENCV_ML_HPP__
+#endif // OPENCV_ML_HPP
 
 /* End of file. */
diff --git a/modules/ml/misc/python/pyopencv_ml.hpp b/modules/ml/misc/python/pyopencv_ml.hpp
new file mode 100644
index 0000000..6a86c46
--- /dev/null
+++ b/modules/ml/misc/python/pyopencv_ml.hpp
@@ -0,0 +1,22 @@
+template<>
+bool pyopencv_to(PyObject *obj, CvTermCriteria& dst, const char *name)
+{
+    (void)name;
+    if(!obj)
+        return true;
+    return PyArg_ParseTuple(obj, "iid", &dst.type, &dst.max_iter, &dst.epsilon) > 0;
+}
+
+template<>
+bool pyopencv_to(PyObject* obj, CvSlice& r, const char* name)
+{
+    (void)name;
+    if(!obj || obj == Py_None)
+        return true;
+    if(PyObject_Size(obj) == 0)
+    {
+        r = CV_WHOLE_SEQ;
+        return true;
+    }
+    return PyArg_ParseTuple(obj, "ii", &r.start_index, &r.end_index) > 0;
+}
\ No newline at end of file
diff --git a/modules/ml/src/ann_mlp.cpp b/modules/ml/src/ann_mlp.cpp
index ff6512d..fdc73d9 100644
--- a/modules/ml/src/ann_mlp.cpp
+++ b/modules/ml/src/ann_mlp.cpp
@@ -333,7 +333,7 @@ public:
         {
             for( int i = 0; i < _src.rows; i++ )
             {
-                const float* src = _src.ptr<float>(i);
+                const double* src = _src.ptr<double>(i);
                 double* dst = _dst.ptr<double>(i);
                 for( int j = 0; j < cols; j++ )
                     dst[j] = src[j]*w[j*2] + w[j*2+1];
@@ -432,8 +432,15 @@ public:
                     double* data = sums.ptr<double>(i);
                     for( j = 0; j < cols; j++ )
                     {
-                        double t = scale2*(1. - data[j])/(1. + data[j]);
-                        data[j] = t;
+                        if(!cvIsInf(data[j]))
+                        {
+                            double t = scale2*(1. - data[j])/(1. + data[j]);
+                            data[j] = t;
+                        }
+                        else
+                        {
+                            data[j] = -scale2;
+                        }
                     }
                 }
                 break;
@@ -1151,6 +1158,7 @@ public:
             return;
         int i, l_count = layer_count();
 
+        writeFormat(fs);
         fs << "layer_sizes" << layer_sizes;
 
         write_params( fs );
@@ -1317,6 +1325,18 @@ Ptr<ANN_MLP> ANN_MLP::create()
     return makePtr<ANN_MLPImpl>();
 }
 
-}}
+Ptr<ANN_MLP> ANN_MLP::load(const String& filepath)
+{
+    FileStorage fs;
+    fs.open(filepath, FileStorage::READ);
+
+    Ptr<ANN_MLP> ann = makePtr<ANN_MLPImpl>();
+
+    ((ANN_MLPImpl*)ann.get())->read(fs.getFirstTopLevelNode());
+    return ann;
+}
+
+
+    }}
 
 /* End of file. */
diff --git a/modules/ml/src/boost.cpp b/modules/ml/src/boost.cpp
index d7b6c61..3b6bd7a 100644
--- a/modules/ml/src/boost.cpp
+++ b/modules/ml/src/boost.cpp
@@ -387,6 +387,7 @@ public:
         if( roots.empty() )
             CV_Error( CV_StsBadArg, "RTrees have not been trained" );
 
+        writeFormat(fs);
         writeParams(fs);
 
         int k, ntrees = (int)roots.size();
diff --git a/modules/ml/src/data.cpp b/modules/ml/src/data.cpp
index a1608e3..5e1b6d2 100644
--- a/modules/ml/src/data.cpp
+++ b/modules/ml/src/data.cpp
@@ -50,6 +50,13 @@ static const int VAR_MISSED = VAR_ORDERED;
 
 TrainData::~TrainData() {}
 
+Mat TrainData::getTestSamples() const
+{
+    Mat idx = getTestSampleIdx();
+    Mat samples = getSamples();
+    return idx.empty() ? Mat() : getSubVector(samples, idx);
+}
+
 Mat TrainData::getSubVector(const Mat& vec, const Mat& idx)
 {
     if( idx.empty() )
@@ -213,6 +220,7 @@ public:
         samples.release();
         missing.release();
         varType.release();
+        varSymbolFlags.release();
         responses.release();
         sampleIdx.release();
         trainSampleIdx.release();
@@ -515,6 +523,7 @@ public:
         std::vector<float> allresponses;
         std::vector<float> rowvals;
         std::vector<uchar> vtypes, rowtypes;
+        std::vector<uchar> vsymbolflags;
         bool haveMissed = false;
         char* buf = &_buf[0];
 
@@ -576,6 +585,9 @@ public:
                 }
                 else
                     vtypes = rowtypes;
+                vsymbolflags.resize(nvars);
+                for( i = 0; i < nvars; i++ )
+                    vsymbolflags[i] = (uchar)(rowtypes[i] == VAR_CATEGORICAL);
 
                 ridx0 = ridx0 >= 0 ? ridx0 : ridx0 == -1 ? nvars - 1 : -1;
                 ridx1 = ridx1 >= 0 ? ridx1 : ridx0 >= 0 ? ridx0+1 : -1;
@@ -591,6 +603,11 @@ public:
             {
                 CV_Assert( (!varTypesSet && vtypes[i] == rowtypes[i]) ||
                            (varTypesSet && (vtypes[i] == rowtypes[i] || rowtypes[i] == VAR_ORDERED)) );
+                uchar sflag = (uchar)(rowtypes[i] == VAR_CATEGORICAL);
+                if( vsymbolflags[i] == VAR_MISSED )
+                    vsymbolflags[i] = sflag;
+                else
+                    CV_Assert(vsymbolflags[i] == sflag || rowtypes[i] == VAR_MISSED);
             }
 
             if( ridx0 >= 0 )
@@ -650,7 +667,10 @@ public:
         }
         bool ok = !samples.empty();
         if(ok)
+        {
             std::swap(tempNameMap, nameMap);
+            Mat(vsymbolflags).copyTo(varSymbolFlags);
+        }
         return ok;
     }
 
@@ -740,9 +760,6 @@ public:
                     }
                 }
                 while(*stopstring != ']');
-
-                if( stopstring[1] != '\0' && stopstring[1] != ',')
-                    CV_Error( CV_StsBadArg, errmsg );
             }
         }
 
@@ -972,13 +989,38 @@ public:
 
     FILE* file;
     int layout;
-    Mat samples, missing, varType, varIdx, responses, missingSubst;
+    Mat samples, missing, varType, varIdx, varSymbolFlags, responses, missingSubst;
     Mat sampleIdx, trainSampleIdx, testSampleIdx;
     Mat sampleWeights, catMap, catOfs;
     Mat normCatResponses, classLabels, classCounters;
     MapType nameMap;
 };
 
+void TrainData::getNames(std::vector<String>& names) const
+{
+    const TrainDataImpl* impl = dynamic_cast<const TrainDataImpl*>(this);
+    CV_Assert(impl != 0);
+    size_t n = impl->nameMap.size();
+    TrainDataImpl::MapType::const_iterator it = impl->nameMap.begin(),
+                                           it_end = impl->nameMap.end();
+    names.resize(n+1);
+    names[0] = "?";
+    for( ; it != it_end; ++it )
+    {
+        String s = it->first;
+        int label = it->second;
+        CV_Assert( label > 0 && label <= (int)n );
+        names[label] = s;
+    }
+}
+
+Mat TrainData::getVarSymbolFlags() const
+{
+    const TrainDataImpl* impl = dynamic_cast<const TrainDataImpl*>(this);
+    CV_Assert(impl != 0);
+    return impl->varSymbolFlags;
+}
+
 Ptr<TrainData> TrainData::loadFromCSV(const String& filename,
                                       int headerLines,
                                       int responseStartIdx,
diff --git a/modules/ml/src/em.cpp b/modules/ml/src/em.cpp
index ce2d92c..5b833cd 100644
--- a/modules/ml/src/em.cpp
+++ b/modules/ml/src/em.cpp
@@ -170,6 +170,7 @@ public:
             if( _outputs.fixedType() )
                 ptype = _outputs.type();
             _outputs.create(samples.rows, nclusters, ptype);
+            probs = _outputs.getMat();
         }
         else
             nsamples = std::min(nsamples, 1);
@@ -198,7 +199,7 @@ public:
             sample.convertTo(tmp, CV_64FC1);
             sample = tmp;
         }
-        sample.reshape(1, 1);
+        sample = sample.reshape(1, 1);
 
         Mat probs;
         if( _probs.needed() )
@@ -342,7 +343,7 @@ public:
         if(weights0 && (startStep == START_E_STEP && covs0))
         {
             weights0->convertTo(weights, CV_64FC1);
-            weights.reshape(1,1);
+            weights = weights.reshape(1,1);
             preprocessProbability(weights);
         }
 
@@ -769,6 +770,7 @@ public:
 
     void write(FileStorage& fs) const
     {
+        writeFormat(fs);
         fs << "training_params" << "{";
         write_params(fs);
         fs << "}";
diff --git a/modules/ml/src/inner_functions.cpp b/modules/ml/src/inner_functions.cpp
index b39d403..3966906 100644
--- a/modules/ml/src/inner_functions.cpp
+++ b/modules/ml/src/inner_functions.cpp
@@ -74,6 +74,7 @@ float StatModel::calcError( const Ptr<TrainData>& data, bool testerr, OutputArra
     int i, n = (int)sidx.total();
     bool isclassifier = isClassifier();
     Mat responses = data->getResponses();
+    int responses_type = responses.type();
 
     if( n == 0 )
         n = data->getNSamples();
@@ -91,7 +92,7 @@ float StatModel::calcError( const Ptr<TrainData>& data, bool testerr, OutputArra
         int si = sidx_ptr ? sidx_ptr[i] : i;
         Mat sample = layout == ROW_SAMPLE ? samples.row(si) : samples.col(si);
         float val = predict(sample);
-        float val0 = responses.at<float>(si);
+        float val0 = (responses_type == CV_32S) ? (float)responses.at<int>(si) : responses.at<float>(si);
 
         if( isclassifier )
             err += fabs(val - val0) > FLT_EPSILON;
@@ -116,35 +117,12 @@ static void Cholesky( const Mat& A, Mat& S )
 {
     CV_Assert(A.type() == CV_32F);
 
-    int dim = A.rows;
-    S.create(dim, dim, CV_32F);
-
-    int i, j, k;
-
-    for( i = 0; i < dim; i++ )
-    {
-        for( j = 0; j < i; j++ )
-            S.at<float>(i,j) = 0.f;
-
-        float sum = 0.f;
-        for( k = 0; k < i; k++ )
-        {
-            float val = S.at<float>(k,i);
-            sum += val*val;
-        }
-
-        S.at<float>(i,i) = std::sqrt(std::max(A.at<float>(i,i) - sum, 0.f));
-        float ival = 1.f/S.at<float>(i, i);
-
-        for( j = i + 1; j < dim; j++ )
-        {
-            sum = 0;
-            for( k = 0; k < i; k++ )
-                sum += S.at<float>(k, i) * S.at<float>(k, j);
-
-            S.at<float>(i, j) = (A.at<float>(i, j) - sum)*ival;
-        }
-    }
+    S = A.clone();
+    cv::Cholesky ((float*)S.ptr(),S.step, S.rows,NULL, 0, 0);
+    S = S.t();
+    for (int i=1;i<S.rows;i++)
+        for (int j=0;j<i;j++)
+            S.at<float>(i,j)=0;
 }
 
 /* Generates <sample> from multivariate normal distribution, where <mean> - is an
diff --git a/modules/ml/src/knearest.cpp b/modules/ml/src/knearest.cpp
index 99477cd..24c08da 100644
--- a/modules/ml/src/knearest.cpp
+++ b/modules/ml/src/knearest.cpp
@@ -466,6 +466,7 @@ public:
 
     void write( FileStorage& fs ) const
     {
+        writeFormat(fs);
         impl->write(fs);
     }
 
diff --git a/modules/ml/src/lr.cpp b/modules/ml/src/lr.cpp
index a378947..99692f3 100644
--- a/modules/ml/src/lr.cpp
+++ b/modules/ml/src/lr.cpp
@@ -96,11 +96,11 @@ public:
     CV_IMPL_PROPERTY(TermCriteria, TermCriteria, params.term_crit)
 
     virtual bool train( const Ptr<TrainData>& trainData, int=0 );
-    virtual float predict(InputArray samples, OutputArray results, int) const;
+    virtual float predict(InputArray samples, OutputArray results, int flags=0) const;
     virtual void clear();
     virtual void write(FileStorage& fs) const;
     virtual void read(const FileNode& fn);
-    virtual Mat get_learnt_thetas() const;
+    virtual Mat get_learnt_thetas() const { return learnt_thetas; }
     virtual int getVarCount() const { return learnt_thetas.cols; }
     virtual bool isTrained() const { return !learnt_thetas.empty(); }
     virtual bool isClassifier() const { return true; }
@@ -129,57 +129,48 @@ Ptr<LogisticRegression> LogisticRegression::create()
 
 bool LogisticRegressionImpl::train(const Ptr<TrainData>& trainData, int)
 {
+    // return value
+    bool ok = false;
+
     clear();
     Mat _data_i = trainData->getSamples();
     Mat _labels_i = trainData->getResponses();
 
+    // check size and type of training data
     CV_Assert( !_labels_i.empty() && !_data_i.empty());
-
-    // check the number of columns
     if(_labels_i.cols != 1)
     {
-        CV_Error( CV_StsBadArg, "_labels_i should be a column matrix" );
+        CV_Error( CV_StsBadArg, "labels should be a column matrix" );
     }
-
-    // check data type.
-    // data should be of floating type CV_32FC1
-
-    if((_data_i.type() != CV_32FC1) || (_labels_i.type() != CV_32FC1))
+    if(_data_i.type() != CV_32FC1 || _labels_i.type() != CV_32FC1)
     {
         CV_Error( CV_StsBadArg, "data and labels must be a floating point matrix" );
     }
+    if(_labels_i.rows != _data_i.rows)
+    {
+        CV_Error( CV_StsBadArg, "number of rows in data and labels should be equal" );
+    }
 
-    bool ok = false;
-
-    Mat labels;
-
+    // class labels
     set_label_map(_labels_i);
+    Mat labels_l = remap_labels(_labels_i, this->forward_mapper);
     int num_classes = (int) this->forward_mapper.size();
-
-    // add a column of ones
-    Mat data_t;
-    hconcat( cv::Mat::ones( _data_i.rows, 1, CV_32F ), _data_i, data_t );
-
     if(num_classes < 2)
     {
         CV_Error( CV_StsBadArg, "data should have atleast 2 classes" );
     }
 
-    if(_labels_i.rows != _data_i.rows)
-    {
-        CV_Error( CV_StsBadArg, "number of rows in data and labels should be the equal" );
-    }
-
+    // add a column of ones to the data (bias/intercept term)
+    Mat data_t;
+    hconcat( cv::Mat::ones( _data_i.rows, 1, CV_32F ), _data_i, data_t );
 
-    Mat thetas = Mat::zeros(num_classes, data_t.cols, CV_32F);
+    // coefficient matrix (zero-initialized)
+    Mat thetas;
     Mat init_theta = Mat::zeros(data_t.cols, 1, CV_32F);
 
-    Mat labels_l = remap_labels(_labels_i, this->forward_mapper);
-    Mat new_local_labels;
-
-    int ii=0;
+    // fit the model (handles binary and multiclass cases)
     Mat new_theta;
-
+    Mat labels;
     if(num_classes == 2)
     {
         labels_l.convertTo(labels, CV_32F);
@@ -193,12 +184,14 @@ bool LogisticRegressionImpl::train(const Ptr<TrainData>& trainData, int)
     {
         /* take each class and rename classes you will get a theta per class
         as in multi class class scenario, we will have n thetas for n classes */
-        ii = 0;
-
+        thetas.create(num_classes, data_t.cols, CV_32F);
+        Mat labels_binary;
+        int ii = 0;
         for(map<int,int>::iterator it = this->forward_mapper.begin(); it != this->forward_mapper.end(); ++it)
         {
-            new_local_labels = (labels_l == it->second)/255;
-            new_local_labels.convertTo(labels, CV_32F);
+            // one-vs-rest (OvR) scheme
+            labels_binary = (labels_l == it->second)/255;
+            labels_binary.convertTo(labels, CV_32F);
             if(this->params.train_method == LogisticRegression::BATCH)
                 new_theta = batch_gradient_descent(data_t, labels, init_theta);
             else
@@ -208,38 +201,28 @@ bool LogisticRegressionImpl::train(const Ptr<TrainData>& trainData, int)
         }
     }
 
+    // check that the estimates are stable and finite
     this->learnt_thetas = thetas.clone();
     if( cvIsNaN( (double)sum(this->learnt_thetas)[0] ) )
     {
         CV_Error( CV_StsBadArg, "check training parameters. Invalid training classifier" );
     }
+
+    // success
     ok = true;
     return ok;
 }
 
 float LogisticRegressionImpl::predict(InputArray samples, OutputArray results, int flags) const
 {
-    /* returns a class of the predicted class
-    class names can be 1,2,3,4, .... etc */
-    Mat thetas, data, pred_labs;
-    data = samples.getMat();
-
-    const bool rawout = flags & StatModel::RAW_OUTPUT;
-
     // check if learnt_mats array is populated
-    if(this->learnt_thetas.total()<=0)
+    if(!this->isTrained())
     {
         CV_Error( CV_StsBadArg, "classifier should be trained first" );
     }
-    if(data.type() != CV_32F)
-    {
-        CV_Error( CV_StsBadArg, "data must be of floating type" );
-    }
-
-    // add a column of ones
-    Mat data_t;
-    hconcat( cv::Mat::ones( data.rows, 1, CV_32F ), data, data_t );
 
+    // coefficient matrix
+    Mat thetas;
     if ( learnt_thetas.type() == CV_32F )
     {
         thetas = learnt_thetas;
@@ -248,52 +231,65 @@ float LogisticRegressionImpl::predict(InputArray samples, OutputArray results, i
     {
         this->learnt_thetas.convertTo( thetas, CV_32F );
     }
-
     CV_Assert(thetas.rows > 0);
 
-    double min_val;
-    double max_val;
+    // data samples
+    Mat data = samples.getMat();
+    if(data.type() != CV_32F)
+    {
+        CV_Error( CV_StsBadArg, "data must be of floating type" );
+    }
 
-    Point min_loc;
-    Point max_loc;
+    // add a column of ones to the data (bias/intercept term)
+    Mat data_t;
+    hconcat( cv::Mat::ones( data.rows, 1, CV_32F ), data, data_t );
+    CV_Assert(data_t.cols == thetas.cols);
 
-    Mat labels;
+    // predict class labels for samples (handles binary and multiclass cases)
     Mat labels_c;
+    Mat pred_m;
     Mat temp_pred;
-    Mat pred_m = Mat::zeros(data_t.rows, thetas.rows, data.type());
-
     if(thetas.rows == 1)
     {
-        temp_pred = calc_sigmoid(data_t*thetas.t());
+        // apply sigmoid function
+        temp_pred = calc_sigmoid(data_t * thetas.t());
         CV_Assert(temp_pred.cols==1);
+        pred_m = temp_pred.clone();
 
         // if greater than 0.5, predict class 0 or predict class 1
-        temp_pred = (temp_pred>0.5)/255;
+        temp_pred = (temp_pred > 0.5f) / 255;
         temp_pred.convertTo(labels_c, CV_32S);
     }
     else
     {
-        for(int i = 0;i<thetas.rows;i++)
+        // apply sigmoid function
+        pred_m.create(data_t.rows, thetas.rows, data.type());
+        for(int i = 0; i < thetas.rows; i++)
         {
             temp_pred = calc_sigmoid(data_t * thetas.row(i).t());
             vconcat(temp_pred, pred_m.col(i));
         }
-        for(int i = 0;i<pred_m.rows;i++)
+
+        // predict class with the maximum output
+        Point max_loc;
+        Mat labels;
+        for(int i = 0; i < pred_m.rows; i++)
         {
             temp_pred = pred_m.row(i);
-            minMaxLoc( temp_pred, &min_val, &max_val, &min_loc, &max_loc, Mat() );
+            minMaxLoc( temp_pred, NULL, NULL, NULL, &max_loc );
             labels.push_back(max_loc.x);
         }
         labels.convertTo(labels_c, CV_32S);
     }
-    pred_labs = remap_labels(labels_c, this->reverse_mapper);
-    // convert pred_labs to integer type
+
+    // return label of the predicted class. class names can be 1,2,3,...
+    Mat pred_labs = remap_labels(labels_c, this->reverse_mapper);
     pred_labs.convertTo(pred_labs, CV_32S);
 
     // return either the labels or the raw output
     if ( results.needed() )
     {
-        if ( rawout )
+        if ( flags & StatModel::RAW_OUTPUT )
         {
             pred_m.copyTo( results );
         }
@@ -303,7 +299,7 @@ float LogisticRegressionImpl::predict(InputArray samples, OutputArray results, i
         }
     }
 
-    return ( pred_labs.empty() ? 0.f : (float) pred_labs.at< int >( 0 ) );
+    return ( pred_labs.empty() ? 0.f : static_cast<float>(pred_labs.at<int>(0)) );
 }
 
 Mat LogisticRegressionImpl::calc_sigmoid(const Mat& data) const
@@ -366,6 +362,42 @@ double LogisticRegressionImpl::compute_cost(const Mat& _data, const Mat& _labels
     return cost;
 }
 
+struct LogisticRegressionImpl_ComputeDradient_Impl : ParallelLoopBody
+{
+    const Mat* data;
+    const Mat* theta;
+    const Mat* pcal_a;
+    Mat* gradient;
+    double lambda;
+
+    LogisticRegressionImpl_ComputeDradient_Impl(const Mat& _data, const Mat &_theta, const Mat& _pcal_a, const double _lambda, Mat & _gradient)
+        : data(&_data)
+        , theta(&_theta)
+        , pcal_a(&_pcal_a)
+        , gradient(&_gradient)
+        , lambda(_lambda)
+    {
+
+    }
+
+    void operator()(const cv::Range& r) const
+    {
+        const Mat& _data  = *data;
+        const Mat &_theta = *theta;
+        Mat & _gradient   = *gradient;
+        const Mat & _pcal_a = *pcal_a;
+        const int m = _data.rows;
+        Mat pcal_ab;
+
+        for (int ii = r.start; ii<r.end; ii++)
+        {
+            Mat pcal_b = _data(Range::all(), Range(ii,ii+1));
+            multiply(_pcal_a, pcal_b, pcal_ab, 1);
+
+            _gradient.row(ii) = (1.0/m)*sum(pcal_ab)[0] + (lambda/m) * _theta.row(ii);
+        }
+    }
+};
 
 void LogisticRegressionImpl::compute_gradient(const Mat& _data, const Mat& _labels, const Mat &_theta, const double _lambda, Mat & _gradient )
 {
@@ -383,13 +415,8 @@ void LogisticRegressionImpl::compute_gradient(const Mat& _data, const Mat& _labe
     _gradient.row(0) = ((float)1/m) * sum(pcal_ab)[0];
 
     //cout<<"for each training data entry"<<endl;
-    for(int ii = 1;ii<_gradient.rows;ii++)
-    {
-        pcal_b = _data(Range::all(), Range(ii,ii+1));
-        multiply(pcal_a, pcal_b, pcal_ab, 1);
-
-        _gradient.row(ii) = (1.0/m)*sum(pcal_ab)[0] + (_lambda/m) * _theta.row(ii);
-    }
+    LogisticRegressionImpl_ComputeDradient_Impl invoker(_data, _theta, pcal_a, _lambda, _gradient);
+    cv::parallel_for_(cv::Range(1, _gradient.rows), invoker);
 }
 
 
@@ -551,6 +578,7 @@ void LogisticRegressionImpl::write(FileStorage& fs) const
     {
         CV_Error(CV_StsBadArg,"file can't open. Check file path");
     }
+    writeFormat(fs);
     string desc = "Logisitic Regression Classifier";
     fs<<"classifier"<<desc.c_str();
     fs<<"alpha"<<this->params.alpha;
@@ -595,11 +623,6 @@ void LogisticRegressionImpl::read(const FileNode& fn)
     }
 }
 
-Mat LogisticRegressionImpl::get_learnt_thetas() const
-{
-    return this->learnt_thetas;
-}
-
 }
 }
 
diff --git a/modules/ml/src/nbayes.cpp b/modules/ml/src/nbayes.cpp
index 221db93..c46367c 100644
--- a/modules/ml/src/nbayes.cpp
+++ b/modules/ml/src/nbayes.cpp
@@ -236,7 +236,7 @@ public:
             if (results_prob)
             {
                 rptype = results_prob->type();
-                rpstep = results_prob->isContinuous() ? 1 : results_prob->step/results_prob->elemSize();
+                rpstep = results_prob->isContinuous() ? results_prob->cols : results_prob->step/results_prob->elemSize();
             }
             // allocate memory and initializing headers for calculating
             cv::AutoBuffer<double> _buffer(nvars*2);
@@ -342,6 +342,7 @@ public:
     {
         int nclasses = (int)cls_labels.total(), i;
 
+        writeFormat(fs);
         fs << "var_count" << (var_idx.empty() ? nallvars : (int)var_idx.total());
         fs << "var_all" << nallvars;
 
diff --git a/modules/ml/src/rtrees.cpp b/modules/ml/src/rtrees.cpp
index 1c9120a..cab33ab 100644
--- a/modules/ml/src/rtrees.cpp
+++ b/modules/ml/src/rtrees.cpp
@@ -296,6 +296,7 @@ public:
         if( roots.empty() )
             CV_Error( CV_StsBadArg, "RTrees have not been trained" );
 
+        writeFormat(fs);
         writeParams(fs);
 
         fs << "oob_error" << oobError;
@@ -381,6 +382,8 @@ public:
 
     bool train( const Ptr<TrainData>& trainData, int flags )
     {
+        if (impl.getCVFolds() != 0)
+            CV_Error(Error::StsBadArg, "Cross validation for RTrees is not implemented");
         return impl.train(trainData, flags);
     }
 
diff --git a/modules/ml/src/svm.cpp b/modules/ml/src/svm.cpp
index 757bb7a..5e5b891 100644
--- a/modules/ml/src/svm.cpp
+++ b/modules/ml/src/svm.cpp
@@ -1442,7 +1442,7 @@ public:
             //check that while cross-validation there were the samples from all the classes
             if( class_ranges[class_count] <= 0 )
                 CV_Error( CV_StsBadArg, "While cross-validation one or more of the classes have "
-                "been fell out of the sample. Try to enlarge <Params::k_fold>" );
+                "been fell out of the sample. Try to reduce <Params::k_fold>" );
 
             if( svmType == NU_SVC )
             {
@@ -2037,6 +2037,7 @@ public:
         if( !isTrained() )
             CV_Error( CV_StsParseError, "SVM model data is invalid, check sv_count, var_* and class_count tags" );
 
+        writeFormat(fs);
         write_params( fs );
 
         fs << "var_count" << var_count;
@@ -2092,7 +2093,7 @@ public:
                << "alpha" << "[:";
             fs.writeRaw("d", (const uchar*)&df_alpha[df.ofs], sv_count*sizeof(df_alpha[0]));
             fs << "]";
-            if( class_count > 2 )
+            if( class_count >= 2 )
             {
                 fs << "index" << "[:";
                 fs.writeRaw("i", (const uchar*)&df_index[df.ofs], sv_count*sizeof(df_index[0]));
@@ -2234,11 +2235,11 @@ public:
             df_index.resize(ofs + sv_count);
             df_alpha.resize(ofs + sv_count);
             dfi["alpha"].readRaw("d", (uchar*)&df_alpha[ofs], sv_count*sizeof(df_alpha[0]));
-            if( class_count > 2 )
+            if( class_count >= 2 )
                 dfi["index"].readRaw("i", (uchar*)&df_index[ofs], sv_count*sizeof(df_index[0]));
             decision_func.push_back(df);
         }
-        if( class_count <= 2 )
+        if( class_count < 2 )
             setRangeVector(df_index, sv_total);
         if( (int)fn["optimize_linear"] != 0 )
             optimize_linear_svm();
@@ -2261,6 +2262,17 @@ Ptr<SVM> SVM::create()
     return makePtr<SVMImpl>();
 }
 
+Ptr<SVM> SVM::load(const String& filepath)
+{
+    FileStorage fs;
+    fs.open(filepath, FileStorage::READ);
+
+    Ptr<SVM> svm = makePtr<SVMImpl>();
+
+    ((SVMImpl*)svm.get())->read(fs.getFirstTopLevelNode());
+    return svm;
+}
+
 Mat SVM::getUncompressedSupportVectors() const
 {
     const SVMImpl* this_ = dynamic_cast<const SVMImpl*>(this);
diff --git a/modules/ml/src/svmsgd.cpp b/modules/ml/src/svmsgd.cpp
new file mode 100644
index 0000000..0ef9175
--- /dev/null
+++ b/modules/ml/src/svmsgd.cpp
@@ -0,0 +1,511 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+//  By downloading, copying, installing or using the software you agree to this license.
+//  If you do not agree to this license, do not download, install,
+//  copy or use the software.
+//
+//
+//                           License Agreement
+//                For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Copyright (C) 2016, Itseez Inc, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+//   * Redistribution's of source code must retain the above copyright notice,
+//     this list of conditions and the following disclaimer.
+//
+//   * Redistribution's in binary form must reproduce the above copyright notice,
+//     this list of conditions and the following disclaimer in the documentation
+//     and/or other materials provided with the distribution.
+//
+//   * The name of the copyright holders may not be used to endorse or promote products
+//     derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "precomp.hpp"
+#include "limits"
+
+#include <iostream>
+
+using std::cout;
+using std::endl;
+
+/****************************************************************************************\
+*                        Stochastic Gradient Descent SVM Classifier                      *
+\****************************************************************************************/
+
+namespace cv
+{
+namespace ml
+{
+
+class SVMSGDImpl : public SVMSGD
+{
+
+public:
+    SVMSGDImpl();
+
+    virtual ~SVMSGDImpl() {}
+
+    virtual bool train(const Ptr<TrainData>& data, int);
+
+    virtual float predict( InputArray samples, OutputArray results=noArray(), int flags = 0 ) const;
+
+    virtual bool isClassifier() const;
+
+    virtual bool isTrained() const;
+
+    virtual void clear();
+
+    virtual void write(FileStorage &fs) const;
+
+    virtual void read(const FileNode &fn);
+
+    virtual Mat getWeights(){ return weights_; }
+
+    virtual float getShift(){ return shift_; }
+
+    virtual int getVarCount() const { return weights_.cols; }
+
+    virtual String getDefaultName() const {return "opencv_ml_svmsgd";}
+
+    virtual void setOptimalParameters(int svmsgdType = ASGD, int marginType = SOFT_MARGIN);
+
+    CV_IMPL_PROPERTY(int, SvmsgdType, params.svmsgdType)
+    CV_IMPL_PROPERTY(int, MarginType, params.marginType)
+    CV_IMPL_PROPERTY(float, MarginRegularization, params.marginRegularization)
+    CV_IMPL_PROPERTY(float, InitialStepSize, params.initialStepSize)
+    CV_IMPL_PROPERTY(float, StepDecreasingPower, params.stepDecreasingPower)
+    CV_IMPL_PROPERTY_S(cv::TermCriteria, TermCriteria, params.termCrit)
+
+private:
+    void updateWeights(InputArray sample, bool positive, float stepSize, Mat &weights);
+
+    void writeParams( FileStorage &fs ) const;
+
+    void readParams( const FileNode &fn );
+
+    static inline bool isPositive(float val) { return val > 0; }
+
+    static void normalizeSamples(Mat &matrix, Mat &average, float &multiplier);
+
+    float calcShift(InputArray _samples, InputArray _responses) const;
+
+    static void makeExtendedTrainSamples(const Mat &trainSamples, Mat &extendedTrainSamples, Mat &average, float &multiplier);
+
+    // Vector with SVM weights
+    Mat weights_;
+    float shift_;
+
+    // Parameters for learning
+    struct SVMSGDParams
+    {
+        float marginRegularization;
+        float initialStepSize;
+        float stepDecreasingPower;
+        TermCriteria termCrit;
+        int svmsgdType;
+        int marginType;
+    };
+
+    SVMSGDParams params;
+};
+
+Ptr<SVMSGD> SVMSGD::create()
+{
+    return makePtr<SVMSGDImpl>();
+}
+
+void SVMSGDImpl::normalizeSamples(Mat &samples, Mat &average, float &multiplier)
+{
+    int featuresCount = samples.cols;
+    int samplesCount = samples.rows;
+
+    average = Mat(1, featuresCount, samples.type());
+    CV_Assert(average.type() ==  CV_32FC1);
+    for (int featureIndex = 0; featureIndex < featuresCount; featureIndex++)
+    {
+        average.at<float>(featureIndex) = static_cast<float>(mean(samples.col(featureIndex))[0]);
+    }
+
+    for (int sampleIndex = 0; sampleIndex < samplesCount; sampleIndex++)
+    {
+        samples.row(sampleIndex) -= average;
+    }
+
+    double normValue = norm(samples);
+
+    multiplier = static_cast<float>(sqrt(static_cast<double>(samples.total())) / normValue);
+
+    samples *= multiplier;
+}
+
+void SVMSGDImpl::makeExtendedTrainSamples(const Mat &trainSamples, Mat &extendedTrainSamples, Mat &average, float &multiplier)
+{
+    Mat normalizedTrainSamples = trainSamples.clone();
+    int samplesCount = normalizedTrainSamples.rows;
+
+    normalizeSamples(normalizedTrainSamples, average, multiplier);
+
+    Mat onesCol = Mat::ones(samplesCount, 1, CV_32F);
+    cv::hconcat(normalizedTrainSamples, onesCol, extendedTrainSamples);
+}
+
+void SVMSGDImpl::updateWeights(InputArray _sample, bool positive, float stepSize, Mat& weights)
+{
+    Mat sample = _sample.getMat();
+
+    int response = positive ? 1 : -1; // ensure that trainResponses are -1 or 1
+
+    if ( sample.dot(weights) * response > 1)
+    {
+        // Not a support vector, only apply weight decay
+        weights *= (1.f - stepSize * params.marginRegularization);
+    }
+    else
+    {
+        // It's a support vector, add it to the weights
+        weights -= (stepSize * params.marginRegularization) * weights - (stepSize * response) * sample;
+    }
+}
+
+float SVMSGDImpl::calcShift(InputArray _samples, InputArray _responses) const
+{
+    float margin[2] = { std::numeric_limits<float>::max(), std::numeric_limits<float>::max() };
+
+    Mat trainSamples = _samples.getMat();
+    int trainSamplesCount = trainSamples.rows;
+
+    Mat trainResponses = _responses.getMat();
+
+    CV_Assert(trainResponses.type() ==  CV_32FC1);
+    for (int samplesIndex = 0; samplesIndex < trainSamplesCount; samplesIndex++)
+    {
+        Mat currentSample = trainSamples.row(samplesIndex);
+        float dotProduct = static_cast<float>(currentSample.dot(weights_));
+
+        bool positive = isPositive(trainResponses.at<float>(samplesIndex));
+        int index = positive ? 0 : 1;
+        float signToMul = positive ? 1.f : -1.f;
+        float curMargin = dotProduct * signToMul;
+
+        if (curMargin < margin[index])
+        {
+            margin[index] = curMargin;
+        }
+    }
+
+    return -(margin[0] - margin[1]) / 2.f;
+}
+
+bool SVMSGDImpl::train(const Ptr<TrainData>& data, int)
+{
+    clear();
+    CV_Assert( isClassifier() );   //toDo: consider
+
+    Mat trainSamples = data->getTrainSamples();
+
+    int featureCount = trainSamples.cols;
+    Mat trainResponses = data->getTrainResponses();        // (trainSamplesCount x 1) matrix
+
+    CV_Assert(trainResponses.rows == trainSamples.rows);
+
+    if (trainResponses.empty())
+    {
+        return false;
+    }
+
+    int positiveCount = countNonZero(trainResponses >= 0);
+    int negativeCount = countNonZero(trainResponses < 0);
+
+    if ( positiveCount <= 0 || negativeCount <= 0 )
+    {
+        weights_ = Mat::zeros(1, featureCount, CV_32F);
+        shift_ = (positiveCount > 0) ? 1.f : -1.f;
+        return true;
+    }
+
+    Mat extendedTrainSamples;
+    Mat average;
+    float multiplier = 0;
+    makeExtendedTrainSamples(trainSamples, extendedTrainSamples, average, multiplier);
+
+    int extendedTrainSamplesCount = extendedTrainSamples.rows;
+    int extendedFeatureCount = extendedTrainSamples.cols;
+
+    Mat extendedWeights = Mat::zeros(1, extendedFeatureCount, CV_32F);
+    Mat previousWeights = Mat::zeros(1, extendedFeatureCount, CV_32F);
+    Mat averageExtendedWeights;
+    if (params.svmsgdType == ASGD)
+    {
+        averageExtendedWeights = Mat::zeros(1, extendedFeatureCount, CV_32F);
+    }
+
+    RNG rng(0);
+
+    CV_Assert (params.termCrit.type & TermCriteria::COUNT || params.termCrit.type & TermCriteria::EPS);
+    int maxCount = (params.termCrit.type & TermCriteria::COUNT) ? params.termCrit.maxCount : INT_MAX;
+    double epsilon = (params.termCrit.type & TermCriteria::EPS) ? params.termCrit.epsilon : 0;
+
+    double err = DBL_MAX;
+    CV_Assert (trainResponses.type() == CV_32FC1);
+    // Stochastic gradient descent SVM
+    for (int iter = 0; (iter < maxCount) && (err > epsilon); iter++)
+    {
+        int randomNumber = rng.uniform(0, extendedTrainSamplesCount);             //generate sample number
+
+        Mat currentSample = extendedTrainSamples.row(randomNumber);
+
+        float stepSize = params.initialStepSize * std::pow((1 + params.marginRegularization * params.initialStepSize * (float)iter), (-params.stepDecreasingPower));    //update stepSize
+
+        updateWeights( currentSample, isPositive(trainResponses.at<float>(randomNumber)), stepSize, extendedWeights );
+
+        //average weights (only for ASGD model)
+        if (params.svmsgdType == ASGD)
+        {
+            averageExtendedWeights = ((float)iter/ (1 + (float)iter)) * averageExtendedWeights  + extendedWeights / (1 + (float) iter);
+            err = norm(averageExtendedWeights - previousWeights);
+            averageExtendedWeights.copyTo(previousWeights);
+        }
+        else
+        {
+            err = norm(extendedWeights - previousWeights);
+            extendedWeights.copyTo(previousWeights);
+        }
+    }
+
+    if (params.svmsgdType == ASGD)
+    {
+        extendedWeights = averageExtendedWeights;
+    }
+
+    Rect roi(0, 0, featureCount, 1);
+    weights_ = extendedWeights(roi);
+    weights_ *= multiplier;
+
+    CV_Assert((params.marginType == SOFT_MARGIN || params.marginType == HARD_MARGIN) && (extendedWeights.type() ==  CV_32FC1));
+
+    if (params.marginType == SOFT_MARGIN)
+    {
+        shift_ = extendedWeights.at<float>(featureCount) - static_cast<float>(weights_.dot(average));
+    }
+    else
+    {
+        shift_ = calcShift(trainSamples, trainResponses);
+    }
+
+    return true;
+}
+
+float SVMSGDImpl::predict( InputArray _samples, OutputArray _results, int ) const
+{
+    float result = 0;
+    cv::Mat samples = _samples.getMat();
+    int nSamples = samples.rows;
+    cv::Mat results;
+
+    CV_Assert( samples.cols == weights_.cols && samples.type() == CV_32FC1);
+
+    if( _results.needed() )
+    {
+        _results.create( nSamples, 1, samples.type() );
+        results = _results.getMat();
+    }
+    else
+    {
+        CV_Assert( nSamples == 1 );
+        results = Mat(1, 1, CV_32FC1, &result);
+    }
+
+    for (int sampleIndex = 0; sampleIndex < nSamples; sampleIndex++)
+    {
+        Mat currentSample = samples.row(sampleIndex);
+        float criterion = static_cast<float>(currentSample.dot(weights_)) + shift_;
+        results.at<float>(sampleIndex) = (criterion >= 0) ? 1.f : -1.f;
+    }
+
+    return result;
+}
+
+bool SVMSGDImpl::isClassifier() const
+{
+    return (params.svmsgdType == SGD || params.svmsgdType == ASGD)
+            &&
+            (params.marginType == SOFT_MARGIN || params.marginType == HARD_MARGIN)
+            &&
+            (params.marginRegularization > 0) && (params.initialStepSize > 0) && (params.stepDecreasingPower >= 0);
+}
+
+bool SVMSGDImpl::isTrained() const
+{
+    return !weights_.empty();
+}
+
+void SVMSGDImpl::write(FileStorage& fs) const
+{
+    if( !isTrained() )
+        CV_Error( CV_StsParseError, "SVMSGD model data is invalid, it hasn't been trained" );
+
+    writeFormat(fs);
+    writeParams( fs );
+
+    fs << "weights" << weights_;
+    fs << "shift" << shift_;
+}
+
+void SVMSGDImpl::writeParams( FileStorage& fs ) const
+{
+    String SvmsgdTypeStr;
+
+    switch (params.svmsgdType)
+    {
+    case SGD:
+        SvmsgdTypeStr = "SGD";
+        break;
+    case ASGD:
+        SvmsgdTypeStr = "ASGD";
+        break;
+    default:
+        SvmsgdTypeStr = format("Unknown_%d", params.svmsgdType);
+    }
+
+    fs << "svmsgdType" << SvmsgdTypeStr;
+
+    String marginTypeStr;
+
+    switch (params.marginType)
+    {
+    case SOFT_MARGIN:
+        marginTypeStr = "SOFT_MARGIN";
+        break;
+    case HARD_MARGIN:
+        marginTypeStr = "HARD_MARGIN";
+        break;
+    default:
+        marginTypeStr = format("Unknown_%d", params.marginType);
+    }
+
+    fs << "marginType" << marginTypeStr;
+
+    fs << "marginRegularization" << params.marginRegularization;
+    fs << "initialStepSize" << params.initialStepSize;
+    fs << "stepDecreasingPower" << params.stepDecreasingPower;
+
+    fs << "term_criteria" << "{:";
+    if( params.termCrit.type & TermCriteria::EPS )
+        fs << "epsilon" << params.termCrit.epsilon;
+    if( params.termCrit.type & TermCriteria::COUNT )
+        fs << "iterations" << params.termCrit.maxCount;
+    fs << "}";
+}
+void SVMSGDImpl::readParams( const FileNode& fn )
+{
+    String svmsgdTypeStr = (String)fn["svmsgdType"];
+    int svmsgdType =
+            svmsgdTypeStr == "SGD" ? SGD :
+                                     svmsgdTypeStr == "ASGD" ? ASGD : -1;
+
+    if( svmsgdType < 0 )
+        CV_Error( CV_StsParseError, "Missing or invalid SVMSGD type" );
+
+    params.svmsgdType = svmsgdType;
+
+    String marginTypeStr = (String)fn["marginType"];
+    int marginType =
+            marginTypeStr == "SOFT_MARGIN" ? SOFT_MARGIN :
+                                             marginTypeStr == "HARD_MARGIN" ? HARD_MARGIN : -1;
+
+    if( marginType < 0 )
+        CV_Error( CV_StsParseError, "Missing or invalid margin type" );
+
+    params.marginType = marginType;
+
+    CV_Assert ( fn["marginRegularization"].isReal() );
+    params.marginRegularization = (float)fn["marginRegularization"];
+
+    CV_Assert ( fn["initialStepSize"].isReal() );
+    params.initialStepSize = (float)fn["initialStepSize"];
+
+    CV_Assert ( fn["stepDecreasingPower"].isReal() );
+    params.stepDecreasingPower = (float)fn["stepDecreasingPower"];
+
+    FileNode tcnode = fn["term_criteria"];
+    CV_Assert(!tcnode.empty());
+    params.termCrit.epsilon = (double)tcnode["epsilon"];
+    params.termCrit.maxCount = (int)tcnode["iterations"];
+    params.termCrit.type = (params.termCrit.epsilon > 0 ? TermCriteria::EPS : 0) +
+            (params.termCrit.maxCount > 0 ? TermCriteria::COUNT : 0);
+    CV_Assert ((params.termCrit.type & TermCriteria::COUNT || params.termCrit.type & TermCriteria::EPS));
+}
+
+void SVMSGDImpl::read(const FileNode& fn)
+{
+    clear();
+
+    readParams(fn);
+
+    fn["weights"] >> weights_;
+    fn["shift"] >> shift_;
+}
+
+void SVMSGDImpl::clear()
+{
+    weights_.release();
+    shift_ = 0;
+}
+
+
+SVMSGDImpl::SVMSGDImpl()
+{
+    clear();
+    setOptimalParameters();
+}
+
+void SVMSGDImpl::setOptimalParameters(int svmsgdType, int marginType)
+{
+    switch (svmsgdType)
+    {
+    case SGD:
+        params.svmsgdType = SGD;
+        params.marginType = (marginType == SOFT_MARGIN) ? SOFT_MARGIN :
+                                                          (marginType == HARD_MARGIN) ? HARD_MARGIN : -1;
+        params.marginRegularization = 0.0001f;
+        params.initialStepSize = 0.05f;
+        params.stepDecreasingPower = 1.f;
+        params.termCrit = TermCriteria(TermCriteria::COUNT + TermCriteria::EPS, 100000, 0.00001);
+        break;
+
+    case ASGD:
+        params.svmsgdType = ASGD;
+        params.marginType = (marginType == SOFT_MARGIN) ? SOFT_MARGIN :
+                                                          (marginType == HARD_MARGIN) ? HARD_MARGIN : -1;
+        params.marginRegularization = 0.00001f;
+        params.initialStepSize = 0.05f;
+        params.stepDecreasingPower = 0.75f;
+        params.termCrit = TermCriteria(TermCriteria::COUNT + TermCriteria::EPS, 100000, 0.00001);
+        break;
+
+    default:
+        CV_Error( CV_StsParseError, "SVMSGD model data is invalid" );
+    }
+}
+}   //ml
+}   //cv
diff --git a/modules/ml/src/testset.cpp b/modules/ml/src/testset.cpp
index 8b8bba5..48cd134 100644
--- a/modules/ml/src/testset.cpp
+++ b/modules/ml/src/testset.cpp
@@ -104,7 +104,7 @@ void createConcentricSpheresTestSet( int num_samples, int num_features, int num_
         max_dst = std::max( max_dst, dis[i].d );
 
         for( ; i < num_samples && dis[i].d <= max_dst; ++i )
-            responses.at<int>(i) = cur_class;
+            responses.at<int>(dis[i].i) = cur_class;
     }
 }
 
diff --git a/modules/ml/src/tree.cpp b/modules/ml/src/tree.cpp
index 143e1fb..c02b744 100644
--- a/modules/ml/src/tree.cpp
+++ b/modules/ml/src/tree.cpp
@@ -638,7 +638,6 @@ void DTreesImpl::calcValue( int nidx, const vector<int>& _sidx )
 
 DTreesImpl::WSplit DTreesImpl::findSplitOrdClass( int vi, const vector<int>& _sidx, double initQuality )
 {
-    const double epsilon = FLT_EPSILON*2;
     int n = (int)_sidx.size();
     int m = (int)classLabels.size();
 
@@ -688,7 +687,8 @@ DTreesImpl::WSplit DTreesImpl::findSplitOrdClass( int vi, const vector<int>& _si
         rsum2 -= 2*rv*wval - w2;
         lcw[idx] = lv + wval; rcw[idx] = rv - wval;
 
-        if( values[curr] + epsilon < values[next] )
+        float value_between = (values[next] + values[curr]) * 0.5f;
+        if( value_between > values[curr] && value_between < values[next] )
         {
             double val = (lsum2*R + rsum2*L)/(L*R);
             if( best_val < val )
@@ -985,7 +985,6 @@ DTreesImpl::WSplit DTreesImpl::findSplitCatClass( int vi, const vector<int>& _si
 
 DTreesImpl::WSplit DTreesImpl::findSplitOrdReg( int vi, const vector<int>& _sidx, double initQuality )
 {
-    const float epsilon = FLT_EPSILON*2;
     const double* weights = &w->sample_weights[0];
     int n = (int)_sidx.size();
 
@@ -1021,7 +1020,8 @@ DTreesImpl::WSplit DTreesImpl::findSplitOrdReg( int vi, const vector<int>& _sidx
         L += wval; R -= wval;
         lsum += t; rsum -= t;
 
-        if( values[curr] + epsilon < values[next] )
+        float value_between = (values[next] + values[curr]) * 0.5f;
+        if( value_between > values[curr] && value_between < values[next] )
         {
             double val = (lsum*lsum*R + rsum*rsum*L)/(L*R);
             if( best_val < val )
@@ -1681,6 +1681,7 @@ void DTreesImpl::writeTree( FileStorage& fs, int root ) const
 
 void DTreesImpl::write( FileStorage& fs ) const
 {
+    writeFormat(fs);
     writeParams(fs);
     writeTree(fs, roots[0]);
 }
diff --git a/modules/ml/test/test_mltests.cpp b/modules/ml/test/test_mltests.cpp
index 2ffa531..70cc0f7 100644
--- a/modules/ml/test/test_mltests.cpp
+++ b/modules/ml/test/test_mltests.cpp
@@ -128,4 +128,48 @@ TEST(ML_Boost, regression) { CV_AMLTest test( CV_BOOST ); test.safe_run(); }
 TEST(ML_RTrees, regression) { CV_AMLTest test( CV_RTREES ); test.safe_run(); }
 TEST(DISABLED_ML_ERTrees, regression) { CV_AMLTest test( CV_ERTREES ); test.safe_run(); }
 
+TEST(ML_NBAYES, regression_5911)
+{
+    int N=12;
+    Ptr<ml::NormalBayesClassifier> nb = cv::ml::NormalBayesClassifier::create();
+
+    // data:
+    Mat_<float> X(N,4);
+    X << 1,2,3,4,  1,2,3,4,   1,2,3,4,    1,2,3,4,
+         5,5,5,5,  5,5,5,5,   5,5,5,5,    5,5,5,5,
+         4,3,2,1,  4,3,2,1,   4,3,2,1,    4,3,2,1;
+
+    // labels:
+    Mat_<int> Y(N,1);
+    Y << 0,0,0,0, 1,1,1,1, 2,2,2,2;
+    nb->train(X, ml::ROW_SAMPLE, Y);
+
+    // single prediction:
+    Mat R1,P1;
+    for (int i=0; i<N; i++)
+    {
+        Mat r,p;
+        nb->predictProb(X.row(i), r, p);
+        R1.push_back(r);
+        P1.push_back(p);
+    }
+
+    // bulk prediction (continuous memory):
+    Mat R2,P2;
+    nb->predictProb(X, R2, P2);
+
+    EXPECT_EQ(sum(R1 == R2)[0], 255 * R2.total());
+    EXPECT_EQ(sum(P1 == P2)[0], 255 * P2.total());
+
+    // bulk prediction, with non-continuous memory storage
+    Mat R3_(N, 1+1, CV_32S),
+        P3_(N, 3+1, CV_32F);
+    nb->predictProb(X, R3_.col(0), P3_.colRange(0,3));
+    Mat R3 = R3_.col(0).clone(),
+        P3 = P3_.colRange(0,3).clone();
+
+    EXPECT_EQ(sum(R1 == R3)[0], 255 * R3.total());
+    EXPECT_EQ(sum(P1 == P3)[0], 255 * P3.total());
+}
+
 /* End of file. */
diff --git a/modules/ml/test/test_mltests2.cpp b/modules/ml/test/test_mltests2.cpp
index 919fae6..15ae200 100644
--- a/modules/ml/test/test_mltests2.cpp
+++ b/modules/ml/test/test_mltests2.cpp
@@ -193,6 +193,25 @@ int str_to_boost_type( String& str )
 // 8. rtrees
 // 9. ertrees
 
+int str_to_svmsgd_type( String& str )
+{
+    if ( !str.compare("SGD") )
+        return SVMSGD::SGD;
+    if ( !str.compare("ASGD") )
+        return SVMSGD::ASGD;
+    CV_Error( CV_StsBadArg, "incorrect svmsgd type string" );
+    return -1;
+}
+
+int str_to_margin_type( String& str )
+{
+    if ( !str.compare("SOFT_MARGIN") )
+        return SVMSGD::SOFT_MARGIN;
+    if ( !str.compare("HARD_MARGIN") )
+        return SVMSGD::HARD_MARGIN;
+    CV_Error( CV_StsBadArg, "incorrect svmsgd margin type string" );
+    return -1;
+}
 // ---------------------------------- MLBaseTest ---------------------------------------------------
 
 CV_MLBaseTest::CV_MLBaseTest(const char* _modelName)
@@ -436,6 +455,27 @@ int CV_MLBaseTest::train( int testCaseIdx )
         model = m;
     }
 
+    else if( modelName == CV_SVMSGD )
+    {
+        String svmsgdTypeStr;
+        modelParamsNode["svmsgdType"] >> svmsgdTypeStr;
+
+        Ptr<SVMSGD> m = SVMSGD::create();
+        int svmsgdType = str_to_svmsgd_type( svmsgdTypeStr );
+        m->setSvmsgdType(svmsgdType);
+
+        String marginTypeStr;
+        modelParamsNode["marginType"] >> marginTypeStr;
+        int marginType = str_to_margin_type( marginTypeStr );
+        m->setMarginType(marginType);
+
+        m->setMarginRegularization(modelParamsNode["marginRegularization"]);
+        m->setInitialStepSize(modelParamsNode["initialStepSize"]);
+        m->setStepDecreasingPower(modelParamsNode["stepDecreasingPower"]);
+        m->setTermCriteria(TermCriteria(TermCriteria::COUNT + TermCriteria::EPS, 10000, 0.00001));
+        model = m;
+    }
+
     if( !model.empty() )
         is_trained = model->train(data, 0);
 
@@ -457,7 +497,7 @@ float CV_MLBaseTest::get_test_error( int /*testCaseIdx*/, vector<float> *resp )
     else if( modelName == CV_ANN )
         err = ann_calc_error( model, data, cls_map, type, resp );
     else if( modelName == CV_DTREE || modelName == CV_BOOST || modelName == CV_RTREES ||
-             modelName == CV_SVM || modelName == CV_NBAYES || modelName == CV_KNEAREST )
+             modelName == CV_SVM || modelName == CV_NBAYES || modelName == CV_KNEAREST || modelName == CV_SVMSGD )
         err = model->calcError( data, true, _resp );
     if( !_resp.empty() && resp )
         _resp.convertTo(*resp, CV_32F);
@@ -485,6 +525,8 @@ void CV_MLBaseTest::load( const char* filename )
         model = Algorithm::load<Boost>( filename );
     else if( modelName == CV_RTREES )
         model = Algorithm::load<RTrees>( filename );
+    else if( modelName == CV_SVMSGD )
+        model = Algorithm::load<SVMSGD>( filename );
     else
         CV_Error( CV_StsNotImplemented, "invalid stat model name");
 }
diff --git a/modules/ml/test/test_precomp.hpp b/modules/ml/test/test_precomp.hpp
index 329b9bd..3147a9d 100644
--- a/modules/ml/test/test_precomp.hpp
+++ b/modules/ml/test/test_precomp.hpp
@@ -24,6 +24,7 @@
 #define CV_BOOST    "boost"
 #define CV_RTREES   "rtrees"
 #define CV_ERTREES  "ertrees"
+#define CV_SVMSGD   "svmsgd"
 
 enum { CV_TRAIN_ERROR=0, CV_TEST_ERROR=1 };
 
@@ -38,6 +39,7 @@ using cv::ml::ANN_MLP;
 using cv::ml::DTrees;
 using cv::ml::Boost;
 using cv::ml::RTrees;
+using cv::ml::SVMSGD;
 
 class CV_MLBaseTest : public cvtest::BaseTest
 {
diff --git a/modules/ml/test/test_save_load.cpp b/modules/ml/test/test_save_load.cpp
index 2d6f144..b97c8c3 100644
--- a/modules/ml/test/test_save_load.cpp
+++ b/modules/ml/test/test_save_load.cpp
@@ -64,12 +64,12 @@ int CV_SLMLTest::run_test_case( int testCaseIdx )
         if( code == cvtest::TS::OK )
         {
             get_test_error( testCaseIdx, &test_resps1 );
-            fname1 = tempfile(".yml.gz");
-            save( fname1.c_str() );
+            fname1 = tempfile(".json.gz");
+            save( (fname1 + "?base64").c_str() );
             load( fname1.c_str() );
             get_test_error( testCaseIdx, &test_resps2 );
-            fname2 = tempfile(".yml.gz");
-            save( fname2.c_str() );
+            fname2 = tempfile(".json.gz");
+            save( (fname2 + "?base64").c_str() );
         }
         else
             ts->printf( cvtest::TS::LOG, "model can not be trained" );
@@ -156,6 +156,7 @@ TEST(ML_DTree, save_load) { CV_SLMLTest test( CV_DTREE ); test.safe_run(); }
 TEST(ML_Boost, save_load) { CV_SLMLTest test( CV_BOOST ); test.safe_run(); }
 TEST(ML_RTrees, save_load) { CV_SLMLTest test( CV_RTREES ); test.safe_run(); }
 TEST(DISABLED_ML_ERTrees, save_load) { CV_SLMLTest test( CV_ERTREES ); test.safe_run(); }
+TEST(MV_SVMSGD, save_load){ CV_SLMLTest test( CV_SVMSGD ); test.safe_run(); }
 
 class CV_LegacyTest : public cvtest::BaseTest
 {
@@ -201,6 +202,8 @@ protected:
             model = Algorithm::load<SVM>(filename);
         else if (modelName == CV_RTREES)
             model = Algorithm::load<RTrees>(filename);
+        else if (modelName == CV_SVMSGD)
+            model = Algorithm::load<SVMSGD>(filename);
         if (!model)
         {
             code = cvtest::TS::FAIL_INVALID_TEST_DATA;
@@ -260,6 +263,7 @@ TEST(ML_DTree, legacy_load) { CV_LegacyTest test(CV_DTREE, "_abalone.xml;_mushro
 TEST(ML_NBayes, legacy_load) { CV_LegacyTest test(CV_NBAYES, "_waveform.xml"); test.safe_run(); }
 TEST(ML_SVM, legacy_load) { CV_LegacyTest test(CV_SVM, "_poletelecomm.xml;_waveform.xml"); test.safe_run(); }
 TEST(ML_RTrees, legacy_load) { CV_LegacyTest test(CV_RTREES, "_waveform.xml"); test.safe_run(); }
+TEST(ML_SVMSGD, legacy_load) { CV_LegacyTest test(CV_SVMSGD, "_waveform.xml"); test.safe_run(); }
 
 /*TEST(ML_SVM, throw_exception_when_save_untrained_model)
 {
@@ -275,8 +279,8 @@ TEST(DISABLED_ML_SVM, linear_save_load)
 
     svm1 = Algorithm::load<SVM>("SVM45_X_38-1.xml");
     svm2 = Algorithm::load<SVM>("SVM45_X_38-2.xml");
-    string tname = tempfile("a.xml");
-    svm2->save(tname);
+    string tname = tempfile("a.json");
+    svm2->save(tname + "?base64");
     svm3 = Algorithm::load<SVM>(tname);
 
     ASSERT_EQ(svm1->getVarCount(), svm2->getVarCount());
diff --git a/modules/ml/test/test_svmsgd.cpp b/modules/ml/test/test_svmsgd.cpp
new file mode 100644
index 0000000..8d9103e
--- /dev/null
+++ b/modules/ml/test/test_svmsgd.cpp
@@ -0,0 +1,318 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+//  By downloading, copying, installing or using the software you agree to this license.
+//  If you do not agree to this license, do not download, install,
+//  copy or use the software.
+//
+//
+//                        Intel License Agreement
+//                For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+//   * Redistribution's of source code must retain the above copyright notice,
+//     this list of conditions and the following disclaimer.
+//
+//   * Redistribution's in binary form must reproduce the above copyright notice,
+//     this list of conditions and the following disclaimer in the documentation
+//     and/or other materials provided with the distribution.
+//
+//   * The name of Intel Corporation may not be used to endorse or promote products
+//     derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "test_precomp.hpp"
+#include "opencv2/highgui.hpp"
+
+using namespace cv;
+using namespace cv::ml;
+using cv::ml::SVMSGD;
+using cv::ml::TrainData;
+
+
+
+class CV_SVMSGDTrainTest : public cvtest::BaseTest
+{
+public:
+    enum TrainDataType
+    {
+        UNIFORM_SAME_SCALE,
+        UNIFORM_DIFFERENT_SCALES
+    };
+
+    CV_SVMSGDTrainTest(const Mat &_weights, float shift, TrainDataType type, double precision = 0.01);
+private:
+    virtual void run( int start_from );
+    static float decisionFunction(const Mat &sample, const Mat &weights, float shift);
+    void makeData(int samplesCount, const Mat &weights, float shift, RNG &rng, Mat &samples, Mat & responses);
+    void generateSameBorders(int featureCount);
+    void generateDifferentBorders(int featureCount);
+
+    TrainDataType type;
+    double precision;
+    std::vector<std::pair<float,float> > borders;
+    cv::Ptr<TrainData> data;
+    cv::Mat testSamples;
+    cv::Mat testResponses;
+    static const int TEST_VALUE_LIMIT = 500;
+};
+
+void CV_SVMSGDTrainTest::generateSameBorders(int featureCount)
+{
+    float lowerLimit = -TEST_VALUE_LIMIT;
+    float upperLimit = TEST_VALUE_LIMIT;
+
+    for (int featureIndex = 0; featureIndex < featureCount; featureIndex++)
+    {
+        borders.push_back(std::pair<float,float>(lowerLimit, upperLimit));
+    }
+}
+
+void CV_SVMSGDTrainTest::generateDifferentBorders(int featureCount)
+{
+    float lowerLimit = -TEST_VALUE_LIMIT;
+    float upperLimit = TEST_VALUE_LIMIT;
+    cv::RNG rng(0);
+
+    for (int featureIndex = 0; featureIndex < featureCount; featureIndex++)
+    {
+        int crit = rng.uniform(0, 2);
+
+        if (crit > 0)
+        {
+            borders.push_back(std::pair<float,float>(lowerLimit, upperLimit));
+        }
+        else
+        {
+            borders.push_back(std::pair<float,float>(lowerLimit/1000, upperLimit/1000));
+        }
+    }
+}
+
+float CV_SVMSGDTrainTest::decisionFunction(const Mat &sample, const Mat &weights, float shift)
+{
+    return static_cast<float>(sample.dot(weights)) + shift;
+}
+
+void CV_SVMSGDTrainTest::makeData(int samplesCount, const Mat &weights, float shift, RNG &rng, Mat &samples, Mat & responses)
+{
+    int featureCount = weights.cols;
+
+    samples.create(samplesCount, featureCount, CV_32FC1);
+    for (int featureIndex = 0; featureIndex < featureCount; featureIndex++)
+    {
+        rng.fill(samples.col(featureIndex), RNG::UNIFORM, borders[featureIndex].first, borders[featureIndex].second);
+    }
+
+    responses.create(samplesCount, 1, CV_32FC1);
+
+    for (int i = 0 ; i < samplesCount; i++)
+    {
+        responses.at<float>(i) = decisionFunction(samples.row(i), weights, shift) > 0 ? 1.f : -1.f;
+    }
+
+}
+
+CV_SVMSGDTrainTest::CV_SVMSGDTrainTest(const Mat &weights, float shift, TrainDataType _type, double _precision)
+{
+    type = _type;
+    precision = _precision;
+
+    int featureCount = weights.cols;
+
+    switch(type)
+    {
+    case UNIFORM_SAME_SCALE:
+        generateSameBorders(featureCount);
+        break;
+    case UNIFORM_DIFFERENT_SCALES:
+        generateDifferentBorders(featureCount);
+        break;
+    default:
+        CV_Error(CV_StsBadArg, "Unknown train data type");
+    }
+
+    RNG rng(0);
+
+    Mat trainSamples;
+    Mat trainResponses;
+    int trainSamplesCount = 10000;
+    makeData(trainSamplesCount, weights, shift, rng, trainSamples, trainResponses);
+    data = TrainData::create(trainSamples, cv::ml::ROW_SAMPLE, trainResponses);
+
+    int testSamplesCount = 100000;
+    makeData(testSamplesCount, weights, shift, rng, testSamples, testResponses);
+}
+
+void CV_SVMSGDTrainTest::run( int /*start_from*/ )
+{
+    cv::Ptr<SVMSGD> svmsgd = SVMSGD::create();
+
+    svmsgd->train(data);
+
+    Mat responses;
+
+    svmsgd->predict(testSamples, responses);
+
+    int errCount = 0;
+    int testSamplesCount = testSamples.rows;
+
+    CV_Assert((responses.type() == CV_32FC1) && (testResponses.type() == CV_32FC1));
+    for (int i = 0; i < testSamplesCount; i++)
+    {
+        if (responses.at<float>(i) * testResponses.at<float>(i) < 0)
+            errCount++;
+    }
+
+    float err = (float)errCount / testSamplesCount;
+
+    if ( err > precision )
+    {
+        ts->set_failed_test_info(cvtest::TS::FAIL_BAD_ACCURACY);
+    }
+}
+
+void makeWeightsAndShift(int featureCount, Mat &weights, float &shift)
+{
+    weights.create(1, featureCount, CV_32FC1);
+    cv::RNG rng(0);
+    double lowerLimit = -1;
+    double upperLimit = 1;
+
+    rng.fill(weights, RNG::UNIFORM, lowerLimit, upperLimit);
+    shift = static_cast<float>(rng.uniform(-featureCount, featureCount));
+}
+
+
+TEST(ML_SVMSGD, trainSameScale2)
+{
+    int featureCount = 2;
+
+    Mat weights;
+
+    float shift = 0;
+    makeWeightsAndShift(featureCount, weights, shift);
+
+    CV_SVMSGDTrainTest test(weights, shift, CV_SVMSGDTrainTest::UNIFORM_SAME_SCALE);
+    test.safe_run();
+}
+
+TEST(ML_SVMSGD, trainSameScale5)
+{
+    int featureCount = 5;
+
+    Mat weights;
+
+    float shift = 0;
+    makeWeightsAndShift(featureCount, weights, shift);
+
+    CV_SVMSGDTrainTest test(weights, shift, CV_SVMSGDTrainTest::UNIFORM_SAME_SCALE);
+    test.safe_run();
+}
+
+TEST(ML_SVMSGD, trainSameScale100)
+{
+    int featureCount = 100;
+
+    Mat weights;
+
+    float shift = 0;
+    makeWeightsAndShift(featureCount, weights, shift);
+
+    CV_SVMSGDTrainTest test(weights, shift, CV_SVMSGDTrainTest::UNIFORM_SAME_SCALE, 0.02);
+    test.safe_run();
+}
+
+TEST(ML_SVMSGD, trainDifferentScales2)
+{
+    int featureCount = 2;
+
+    Mat weights;
+
+    float shift = 0;
+    makeWeightsAndShift(featureCount, weights, shift);
+
+    CV_SVMSGDTrainTest test(weights, shift, CV_SVMSGDTrainTest::UNIFORM_DIFFERENT_SCALES, 0.01);
+    test.safe_run();
+}
+
+TEST(ML_SVMSGD, trainDifferentScales5)
+{
+    int featureCount = 5;
+
+    Mat weights;
+
+    float shift = 0;
+    makeWeightsAndShift(featureCount, weights, shift);
+
+    CV_SVMSGDTrainTest test(weights, shift, CV_SVMSGDTrainTest::UNIFORM_DIFFERENT_SCALES, 0.01);
+    test.safe_run();
+}
+
+TEST(ML_SVMSGD, trainDifferentScales100)
+{
+    int featureCount = 100;
+
+    Mat weights;
+
+    float shift = 0;
+    makeWeightsAndShift(featureCount, weights, shift);
+
+    CV_SVMSGDTrainTest test(weights, shift, CV_SVMSGDTrainTest::UNIFORM_DIFFERENT_SCALES, 0.01);
+    test.safe_run();
+}
+
+TEST(ML_SVMSGD, twoPoints)
+{
+    Mat samples(2, 2, CV_32FC1);
+    samples.at<float>(0,0) = 0;
+    samples.at<float>(0,1) = 0;
+    samples.at<float>(1,0) = 1000;
+    samples.at<float>(1,1) = 1;
+
+    Mat responses(2, 1, CV_32FC1);
+    responses.at<float>(0) = -1;
+    responses.at<float>(1) = 1;
+
+    cv::Ptr<TrainData> trainData = TrainData::create(samples, cv::ml::ROW_SAMPLE, responses);
+
+    Mat realWeights(1, 2, CV_32FC1);
+    realWeights.at<float>(0) = 1000;
+    realWeights.at<float>(1) = 1;
+
+    float realShift = -500000.5;
+
+    float normRealWeights = static_cast<float>(norm(realWeights));
+    realWeights /= normRealWeights;
+    realShift /= normRealWeights;
+
+    cv::Ptr<SVMSGD> svmsgd = SVMSGD::create();
+    svmsgd->setOptimalParameters();
+    svmsgd->train( trainData );
+
+    Mat foundWeights = svmsgd->getWeights();
+    float foundShift = svmsgd->getShift();
+
+    float normFoundWeights = static_cast<float>(norm(foundWeights));
+    foundWeights /= normFoundWeights;
+    foundShift /= normFoundWeights;
+    CV_Assert((norm(foundWeights - realWeights) < 0.001) && (abs((foundShift - realShift) / realShift) < 0.05));
+}
diff --git a/modules/objdetect/include/opencv2/objdetect.hpp b/modules/objdetect/include/opencv2/objdetect.hpp
index 6587b3d..cd444d2 100644
--- a/modules/objdetect/include/opencv2/objdetect.hpp
+++ b/modules/objdetect/include/opencv2/objdetect.hpp
@@ -41,8 +41,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_OBJDETECT_HPP__
-#define __OPENCV_OBJDETECT_HPP__
+#ifndef OPENCV_OBJDETECT_HPP
+#define OPENCV_OBJDETECT_HPP
 
 #include "opencv2/core.hpp"
 
@@ -91,7 +91,7 @@ compensate for the differences in the size of areas. The sums of pixel values ov
 regions are calculated rapidly using integral images (see below and the integral description).
 
 To see the object detector at work, have a look at the facedetect demo:
-<https://github.com/Itseez/opencv/tree/master/samples/cpp/dbt_face_detection.cpp>
+<https://github.com/opencv/opencv/tree/master/samples/cpp/dbt_face_detection.cpp>
 
 The following reference is for the detection part only. There is a separate application called
 opencv_traincascade that can train a cascade of boosted classifiers from a set of samples.
@@ -124,7 +124,7 @@ public:
     SimilarRects(double _eps) : eps(_eps) {}
     inline bool operator()(const Rect& r1, const Rect& r2) const
     {
-        double delta = eps*(std::min(r1.width, r2.width) + std::min(r1.height, r2.height))*0.5;
+        double delta = eps * ((std::min)(r1.width, r2.width) + (std::min)(r1.height, r2.height)) * 0.5;
         return std::abs(r1.x - r2.x) <= delta &&
             std::abs(r1.y - r2.y) <= delta &&
             std::abs(r1.x + r1.width - r2.x - r2.width) <= delta &&
@@ -255,7 +255,7 @@ public:
     @param flags Parameter with the same meaning for an old cascade as in the function
     cvHaarDetectObjects. It is not used for a new cascade.
     @param minSize Minimum possible object size. Objects smaller than that are ignored.
-    @param maxSize Maximum possible object size. Objects larger than that are ignored.
+    @param maxSize Maximum possible object size. Objects larger than that are ignored. If `maxSize == minSize` model is evaluated on single scale.
 
     The function is parallelized with the TBB library.
 
@@ -283,7 +283,7 @@ public:
     @param flags Parameter with the same meaning for an old cascade as in the function
     cvHaarDetectObjects. It is not used for a new cascade.
     @param minSize Minimum possible object size. Objects smaller than that are ignored.
-    @param maxSize Maximum possible object size. Objects larger than that are ignored.
+    @param maxSize Maximum possible object size. Objects larger than that are ignored. If `maxSize == minSize` model is evaluated on single scale.
     */
     CV_WRAP_AS(detectMultiScale2) void detectMultiScale( InputArray image,
                           CV_OUT std::vector<Rect>& objects,
diff --git a/modules/objdetect/include/opencv2/objdetect/detection_based_tracker.hpp b/modules/objdetect/include/opencv2/objdetect/detection_based_tracker.hpp
index 1f5f1d3..b93c8f5 100644
--- a/modules/objdetect/include/opencv2/objdetect/detection_based_tracker.hpp
+++ b/modules/objdetect/include/opencv2/objdetect/detection_based_tracker.hpp
@@ -41,12 +41,12 @@
 //
 //M*/
 
-#ifndef __OPENCV_OBJDETECT_DBT_HPP__
-#define __OPENCV_OBJDETECT_DBT_HPP__
+#ifndef OPENCV_OBJDETECT_DBT_HPP
+#define OPENCV_OBJDETECT_DBT_HPP
 
 // After this condition removal update blacklist for bindings: modules/python/common.cmake
 #if defined(__linux__) || defined(LINUX) || defined(__APPLE__) || defined(__ANDROID__) || \
-  (defined(__cplusplus) &&  __cplusplus > 201103L) || (defined(_MSC_VER) && _MSC_VER >= 1700)
+  (defined(__cplusplus) &&  __cplusplus > 199711L) || (defined(_MSC_VER) && _MSC_VER >= 1700)
 
 #include <vector>
 
@@ -59,7 +59,7 @@ namespace cv
 class CV_EXPORTS DetectionBasedTracker
 {
     public:
-        struct Parameters
+        struct CV_EXPORTS Parameters
         {
             int maxTrackLifetime;
             int minDetectionPeriod; //the minimal time between run of the big object detector (on the whole frame) in ms (1000 mean 1 sec), default=0
diff --git a/modules/objdetect/include/opencv2/objdetect/objdetect_c.h b/modules/objdetect/include/opencv2/objdetect/objdetect_c.h
index 632a438..b3ee7f4 100644
--- a/modules/objdetect/include/opencv2/objdetect/objdetect_c.h
+++ b/modules/objdetect/include/opencv2/objdetect/objdetect_c.h
@@ -41,8 +41,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_OBJDETECT_C_H__
-#define __OPENCV_OBJDETECT_C_H__
+#ifndef OPENCV_OBJDETECT_C_H
+#define OPENCV_OBJDETECT_C_H
 
 #include "opencv2/core/core_c.h"
 
@@ -162,4 +162,4 @@ CV_EXPORTS CvSeq* cvHaarDetectObjectsForROC( const CvArr* image,
 
 #endif
 
-#endif /* __OPENCV_OBJDETECT_C_H__ */
+#endif /* OPENCV_OBJDETECT_C_H */
diff --git a/modules/objdetect/src/cascadedetect.cpp b/modules/objdetect/src/cascadedetect.cpp
index 5677707..1670ddf 100644
--- a/modules/objdetect/src/cascadedetect.cpp
+++ b/modules/objdetect/src/cascadedetect.cpp
@@ -41,6 +41,7 @@
 
 #include "precomp.hpp"
 #include <cstdio>
+#include <iostream>
 
 #include "cascadedetect.hpp"
 #include "opencv2/objdetect/objdetect_c.h"
@@ -59,6 +60,8 @@ template<typename _Tp> void copyVectorToUMat(const std::vector<_Tp>& v, UMat& um
 void groupRectangles(std::vector<Rect>& rectList, int groupThreshold, double eps,
                      std::vector<int>* weights, std::vector<double>* levelWeights)
 {
+    CV_INSTRUMENT_REGION()
+
     if( groupThreshold <= 0 || rectList.empty() )
     {
         if( weights )
@@ -359,23 +362,31 @@ static void groupRectangles_meanshift(std::vector<Rect>& rectList, double detect
 
 void groupRectangles(std::vector<Rect>& rectList, int groupThreshold, double eps)
 {
+    CV_INSTRUMENT_REGION()
+
     groupRectangles(rectList, groupThreshold, eps, 0, 0);
 }
 
 void groupRectangles(std::vector<Rect>& rectList, std::vector<int>& weights, int groupThreshold, double eps)
 {
+    CV_INSTRUMENT_REGION()
+
     groupRectangles(rectList, groupThreshold, eps, &weights, 0);
 }
 //used for cascade detection algorithm for ROC-curve calculating
 void groupRectangles(std::vector<Rect>& rectList, std::vector<int>& rejectLevels,
                      std::vector<double>& levelWeights, int groupThreshold, double eps)
 {
+    CV_INSTRUMENT_REGION()
+
     groupRectangles(rectList, groupThreshold, eps, &rejectLevels, &levelWeights);
 }
 //can be used for HOG detection algorithm only
 void groupRectangles_meanshift(std::vector<Rect>& rectList, std::vector<double>& foundWeights,
                                std::vector<double>& foundScales, double detectThreshold, Size winDetSize)
 {
+    CV_INSTRUMENT_REGION()
+
     groupRectangles_meanshift(rectList, detectThreshold, &foundWeights, foundScales, winDetSize);
 }
 
@@ -998,7 +1009,7 @@ public:
                     {
                         if( result == 1 )
                             result = -(int)classifier->data.stages.size();
-                        if( -result >= 0 ) // TODO: Add variable to define a specific last accepted Stage - ABI_COMPATIBILITY problem with new/changed virtual functions - PR #5362
+                        if( classifier->data.stages.size() + result == 0 )
                         {
                             mtx->lock();
                             rectangles->push_back(Rect(cvRound(x*scalingFactor),
@@ -1211,79 +1222,102 @@ static void detectMultiScaleOldFormat( const Mat& image, Ptr<CvHaarClassifierCas
     std::transform(vecAvgComp.begin(), vecAvgComp.end(), objects.begin(), getRect());
 }
 
-
 void CascadeClassifierImpl::detectMultiScaleNoGrouping( InputArray _image, std::vector<Rect>& candidates,
                                                     std::vector<int>& rejectLevels, std::vector<double>& levelWeights,
                                                     double scaleFactor, Size minObjectSize, Size maxObjectSize,
                                                     bool outputRejectLevels )
 {
+    CV_INSTRUMENT_REGION()
+
     Size imgsz = _image.size();
+    Size originalWindowSize = getOriginalWindowSize();
 
-    Mat grayImage;
-    _InputArray gray;
+    if( maxObjectSize.height == 0 || maxObjectSize.width == 0 )
+        maxObjectSize = imgsz;
+
+    // If a too small image patch is entering the function, break early before any processing
+    if( (imgsz.height < originalWindowSize.height) || (imgsz.width < originalWindowSize.width) )
+        return;
+
+    std::vector<float> all_scales, scales;
+    all_scales.reserve(1024);
+    scales.reserve(1024);
+
+    // First calculate all possible scales for the given image and model, then remove undesired scales
+    // This allows us to cope with single scale detections (minSize == maxSize) that do not fall on precalculated scale
+    for( double factor = 1; ; factor *= scaleFactor )
+    {
+        Size windowSize( cvRound(originalWindowSize.width*factor), cvRound(originalWindowSize.height*factor) );
+        if( windowSize.width > imgsz.width || windowSize.height > imgsz.height )
+            break;
+        all_scales.push_back((float)factor);
+    }
+
+    // This will capture allowed scales and a minSize==maxSize scale, if it is in the precalculated scales
+    for( size_t index = 0; index < all_scales.size(); index++){
+        Size windowSize( cvRound(originalWindowSize.width*all_scales[index]), cvRound(originalWindowSize.height*all_scales[index]) );
+        if( windowSize.width > maxObjectSize.width || windowSize.height > maxObjectSize.height)
+            break;
+        if( windowSize.width < minObjectSize.width || windowSize.height < minObjectSize.height )
+            continue;
+        scales.push_back(all_scales[index]);
+    }
+
+    // If minSize and maxSize parameter are equal and scales is not filled yet, then the scale was not available in the precalculated scales
+    // In that case we want to return the most fitting scale (closest corresponding scale using L2 distance)
+    if( scales.empty() && !all_scales.empty() ){
+        std::vector<double> distances;
+        // Calculate distances
+        for(size_t v = 0; v < all_scales.size(); v++){
+            Size windowSize( cvRound(originalWindowSize.width*all_scales[v]), cvRound(originalWindowSize.height*all_scales[v]) );
+            double d = (minObjectSize.width - windowSize.width) * (minObjectSize.width - windowSize.width)
+                       + (minObjectSize.height - windowSize.height) * (minObjectSize.height - windowSize.height);
+            distances.push_back(d);
+        }
+        // Take the index of lowest value
+        // Use that index to push the correct scale parameter
+        size_t iMin=0;
+        for(size_t i = 0; i < distances.size(); ++i){
+            if(distances[iMin] > distances[i])
+                    iMin=i;
+        }
+        scales.push_back(all_scales[iMin]);
+    }
 
     candidates.clear();
     rejectLevels.clear();
     levelWeights.clear();
 
-    if( maxObjectSize.height == 0 || maxObjectSize.width == 0 )
-        maxObjectSize = imgsz;
-
 #ifdef HAVE_OPENCL
     bool use_ocl = tryOpenCL && ocl::useOpenCL() &&
+         OCL_FORCE_CHECK(_image.isUMat()) &&
          featureEvaluator->getLocalSize().area() > 0 &&
-         ocl::Device::getDefault().type() != ocl::Device::TYPE_CPU &&
          (data.minNodesPerTree == data.maxNodesPerTree) &&
          !isOldFormatCascade() &&
          maskGenerator.empty() &&
          !outputRejectLevels;
 #endif
 
-    /*if( use_ocl )
-    {
-        if (_image.channels() > 1)
-            cvtColor(_image, ugrayImage, COLOR_BGR2GRAY);
-        else if (_image.isUMat())
-            ugrayImage = _image.getUMat();
-        else
-            _image.copyTo(ugrayImage);
-        gray = ugrayImage;
-    }
-    else*/
-    {
-        if (_image.channels() > 1)
-            cvtColor(_image, grayImage, COLOR_BGR2GRAY);
-        else if (_image.isMat())
-            grayImage = _image.getMat();
-        else
-            _image.copyTo(grayImage);
-        gray = grayImage;
-    }
-
-    std::vector<float> scales;
-    scales.reserve(1024);
-
-    for( double factor = 1; ; factor *= scaleFactor )
-    {
-        Size originalWindowSize = getOriginalWindowSize();
+    Mat grayImage;
+    _InputArray gray;
 
-        Size windowSize( cvRound(originalWindowSize.width*factor), cvRound(originalWindowSize.height*factor) );
-        if( windowSize.width > maxObjectSize.width || windowSize.height > maxObjectSize.height ||
-            windowSize.width > imgsz.width || windowSize.height > imgsz.height )
-            break;
-        if( windowSize.width < minObjectSize.width || windowSize.height < minObjectSize.height )
-            continue;
-        scales.push_back((float)factor);
-    }
+    if (_image.channels() > 1)
+        cvtColor(_image, grayImage, COLOR_BGR2GRAY);
+    else if (_image.isMat())
+        grayImage = _image.getMat();
+    else
+        _image.copyTo(grayImage);
+    gray = grayImage;
 
-    if( scales.size() == 0 || !featureEvaluator->setImage(gray, scales) )
+    if( !featureEvaluator->setImage(gray, scales) )
         return;
 
 #ifdef HAVE_OPENCL
     // OpenCL code
     CV_OCL_RUN(use_ocl, ocl_detectMultiScaleNoGrouping( scales, candidates ))
 
-    tryOpenCL = false;
+    if (use_ocl)
+        tryOpenCL = false;
 #endif
 
     // CPU code
@@ -1320,6 +1354,8 @@ void CascadeClassifierImpl::detectMultiScale( InputArray _image, std::vector<Rec
                                           int flags, Size minObjectSize, Size maxObjectSize,
                                           bool outputRejectLevels )
 {
+    CV_INSTRUMENT_REGION()
+
     CV_Assert( scaleFactor > 1 && _image.depth() == CV_8U );
 
     if( empty() )
@@ -1352,6 +1388,8 @@ void CascadeClassifierImpl::detectMultiScale( InputArray _image, std::vector<Rec
                                           double scaleFactor, int minNeighbors,
                                           int flags, Size minObjectSize, Size maxObjectSize)
 {
+    CV_INSTRUMENT_REGION()
+
     std::vector<int> fakeLevels;
     std::vector<double> fakeWeights;
     detectMultiScale( _image, objects, fakeLevels, fakeWeights, scaleFactor,
@@ -1363,6 +1401,8 @@ void CascadeClassifierImpl::detectMultiScale( InputArray _image, std::vector<Rec
                                           int minNeighbors, int flags, Size minObjectSize,
                                           Size maxObjectSize )
 {
+    CV_INSTRUMENT_REGION()
+
     Mat image = _image.getMat();
     CV_Assert( scaleFactor > 1 && image.depth() == CV_8U );
 
@@ -1636,6 +1676,8 @@ void CascadeClassifier::detectMultiScale( InputArray image,
                       Size minSize,
                       Size maxSize )
 {
+    CV_INSTRUMENT_REGION()
+
     CV_Assert(!empty());
     cc->detectMultiScale(image, objects, scaleFactor, minNeighbors, flags, minSize, maxSize);
     clipObjects(image.size(), objects, 0, 0);
@@ -1648,6 +1690,8 @@ void CascadeClassifier::detectMultiScale( InputArray image,
                       int minNeighbors, int flags,
                       Size minSize, Size maxSize )
 {
+    CV_INSTRUMENT_REGION()
+
     CV_Assert(!empty());
     cc->detectMultiScale(image, objects, numDetections,
                          scaleFactor, minNeighbors, flags, minSize, maxSize);
@@ -1663,6 +1707,8 @@ void CascadeClassifier::detectMultiScale( InputArray image,
                       Size minSize, Size maxSize,
                       bool outputRejectLevels )
 {
+    CV_INSTRUMENT_REGION()
+
     CV_Assert(!empty());
     cc->detectMultiScale(image, objects, rejectLevels, levelWeights,
                          scaleFactor, minNeighbors, flags,
diff --git a/modules/objdetect/src/detection_based_tracker.cpp b/modules/objdetect/src/detection_based_tracker.cpp
index 040784b..88c7923 100644
--- a/modules/objdetect/src/detection_based_tracker.cpp
+++ b/modules/objdetect/src/detection_based_tracker.cpp
@@ -42,6 +42,7 @@
 //M*/
 
 #include "precomp.hpp"
+#include <cassert>
 
 #if (defined(__cplusplus) &&  __cplusplus > 199711L) || (defined(_MSC_VER) && _MSC_VER >= 1700)
 #define USE_STD_THREADS
@@ -124,7 +125,8 @@ namespace cv
 class cv::DetectionBasedTracker::SeparateDetectionWork
 {
     public:
-        SeparateDetectionWork(cv::DetectionBasedTracker& _detectionBasedTracker, cv::Ptr<DetectionBasedTracker::IDetector> _detector);
+        SeparateDetectionWork(cv::DetectionBasedTracker& _detectionBasedTracker, cv::Ptr<DetectionBasedTracker::IDetector> _detector,
+                              const cv::DetectionBasedTracker::Parameters& params);
         virtual ~SeparateDetectionWork();
         bool communicateWithDetectingThread(const Mat& imageGray, std::vector<Rect>& rectsWhereRegions);
         bool run();
@@ -135,23 +137,36 @@ class cv::DetectionBasedTracker::SeparateDetectionWork
         {
             return (stateThread==STATE_THREAD_WORKING_SLEEPING) || (stateThread==STATE_THREAD_WORKING_WITH_IMAGE);
         }
-        inline void lock()
+        void setParameters(const cv::DetectionBasedTracker::Parameters& params)
         {
 #ifdef USE_STD_THREADS
-            mtx_lock.lock();
+            std::unique_lock<std::mutex> mtx_lock(mtx);
 #else
             pthread_mutex_lock(&mutex);
 #endif
+            parameters = params;
+#ifndef USE_STD_THREADS
+            pthread_mutex_unlock(&mutex);
+#endif
         }
-        inline void unlock()
+
+        inline void init()
         {
 #ifdef USE_STD_THREADS
-            mtx_lock.unlock();
+            std::unique_lock<std::mutex> mtx_lock(mtx);
+#else
+            pthread_mutex_lock(&mutex);
+#endif
+            stateThread = STATE_THREAD_STOPPED;
+            isObjectDetectingReady = false;
+            shouldObjectDetectingResultsBeForgot = false;
+#ifdef USE_STD_THREADS
+            objectDetectorThreadStartStop.notify_one();
 #else
+            pthread_cond_signal(&(objectDetectorThreadStartStop));
             pthread_mutex_unlock(&mutex);
 #endif
         }
-
     protected:
 
         DetectionBasedTracker& detectionBasedTracker;
@@ -159,7 +174,6 @@ class cv::DetectionBasedTracker::SeparateDetectionWork
 #ifdef USE_STD_THREADS
         std::thread second_workthread;
         std::mutex mtx;
-        std::unique_lock<std::mutex> mtx_lock;
         std::condition_variable objectDetectorRun;
         std::condition_variable objectDetectorThreadStartStop;
 #else
@@ -187,23 +201,23 @@ class cv::DetectionBasedTracker::SeparateDetectionWork
         friend void* workcycleObjectDetectorFunction(void* p);
 
         long long  timeWhenDetectingThreadStartedWork;
+        cv::DetectionBasedTracker::Parameters parameters;
 };
 
-cv::DetectionBasedTracker::SeparateDetectionWork::SeparateDetectionWork(DetectionBasedTracker& _detectionBasedTracker, cv::Ptr<DetectionBasedTracker::IDetector> _detector)
+cv::DetectionBasedTracker::SeparateDetectionWork::SeparateDetectionWork(DetectionBasedTracker& _detectionBasedTracker, cv::Ptr<DetectionBasedTracker::IDetector> _detector,
+                                                                        const cv::DetectionBasedTracker::Parameters& params)
     :detectionBasedTracker(_detectionBasedTracker),
     cascadeInThread(),
     isObjectDetectingReady(false),
     shouldObjectDetectingResultsBeForgot(false),
     stateThread(STATE_THREAD_STOPPED),
-    timeWhenDetectingThreadStartedWork(-1)
+    timeWhenDetectingThreadStartedWork(-1),
+    parameters(params)
 {
     CV_Assert(_detector);
 
     cascadeInThread = _detector;
-#ifdef USE_STD_THREADS
-    mtx_lock =  std::unique_lock<std::mutex>(mtx);
-    mtx_lock.unlock();
-#else
+#ifndef USE_STD_THREADS
     int res=0;
     res=pthread_mutex_init(&mutex, NULL);//TODO: should be attributes?
     if (res) {
@@ -235,21 +249,22 @@ cv::DetectionBasedTracker::SeparateDetectionWork::~SeparateDetectionWork()
     pthread_cond_destroy(&objectDetectorThreadStartStop);
     pthread_cond_destroy(&objectDetectorRun);
     pthread_mutex_destroy(&mutex);
+#else
+    second_workthread.join();
 #endif
 }
 bool cv::DetectionBasedTracker::SeparateDetectionWork::run()
 {
     LOGD("DetectionBasedTracker::SeparateDetectionWork::run() --- start");
 #ifdef USE_STD_THREADS
-    mtx_lock.lock();
+    std::unique_lock<std::mutex> mtx_lock(mtx);
+    // unlocked when leaving scope
 #else
     pthread_mutex_lock(&mutex);
 #endif
     if (stateThread != STATE_THREAD_STOPPED) {
         LOGE("DetectionBasedTracker::SeparateDetectionWork::run is called while the previous run is not stopped");
-#ifdef USE_STD_THREADS
-        mtx_lock.unlock();
-#else
+#ifndef USE_STD_THREADS
         pthread_mutex_unlock(&mutex);
 #endif
         return false;
@@ -258,7 +273,6 @@ bool cv::DetectionBasedTracker::SeparateDetectionWork::run()
 #ifdef USE_STD_THREADS
     second_workthread = std::thread(workcycleObjectDetectorFunction, (void*)this); //TODO: add attributes?
     objectDetectorThreadStartStop.wait(mtx_lock);
-    mtx_lock.unlock();
 #else
     pthread_create(&second_workthread, NULL, workcycleObjectDetectorFunction, (void*)this); //TODO: add attributes?
     pthread_cond_wait(&objectDetectorThreadStartStop, &mutex);
@@ -284,16 +298,7 @@ void* cv::workcycleObjectDetectorFunction(void* p)
 {
     CATCH_ALL_AND_LOG({ ((cv::DetectionBasedTracker::SeparateDetectionWork*)p)->workcycleObjectDetector(); });
     try{
-        ((cv::DetectionBasedTracker::SeparateDetectionWork*)p)->lock();
-        ((cv::DetectionBasedTracker::SeparateDetectionWork*)p)->stateThread = cv::DetectionBasedTracker::SeparateDetectionWork::STATE_THREAD_STOPPED;
-        ((cv::DetectionBasedTracker::SeparateDetectionWork*)p)->isObjectDetectingReady=false;
-        ((cv::DetectionBasedTracker::SeparateDetectionWork*)p)->shouldObjectDetectingResultsBeForgot=false;
-#ifdef USE_STD_THREADS
-        ((cv::DetectionBasedTracker::SeparateDetectionWork*)p)->objectDetectorThreadStartStop.notify_one();
-#else
-        pthread_cond_signal(&(((cv::DetectionBasedTracker::SeparateDetectionWork*)p)->objectDetectorThreadStartStop));
-#endif
-        ((cv::DetectionBasedTracker::SeparateDetectionWork*)p)->unlock();
+        ((cv::DetectionBasedTracker::SeparateDetectionWork*)p)->init();
     } catch(...) {
         LOGE0("DetectionBasedTracker: workcycleObjectDetectorFunction: ERROR concerning pointer, received as the function parameter");
     }
@@ -308,7 +313,7 @@ void cv::DetectionBasedTracker::SeparateDetectionWork::workcycleObjectDetector()
 
     CV_Assert(stateThread==STATE_THREAD_WORKING_SLEEPING);
 #ifdef USE_STD_THREADS
-    mtx_lock.lock();
+    std::unique_lock<std::mutex> mtx_lock(mtx);
 #else
     pthread_mutex_lock(&mutex);
 #endif
@@ -453,7 +458,7 @@ void cv::DetectionBasedTracker::SeparateDetectionWork::stop()
 {
     //FIXME: TODO: should add quickStop functionality
 #ifdef USE_STD_THREADS
-    mtx_lock.lock();
+  std::unique_lock<std::mutex> mtx_lock(mtx);
 #else
     pthread_mutex_lock(&mutex);
 #endif
@@ -464,6 +469,7 @@ void cv::DetectionBasedTracker::SeparateDetectionWork::stop()
         pthread_mutex_unlock(&mutex);
 #endif
         LOGE("SimpleHighguiDemoCore::stop is called but the SimpleHighguiDemoCore pthread is not active");
+        stateThread = STATE_THREAD_STOPPING;
         return;
     }
     stateThread=STATE_THREAD_STOPPING;
@@ -485,7 +491,7 @@ void cv::DetectionBasedTracker::SeparateDetectionWork::resetTracking()
 {
     LOGD("DetectionBasedTracker::SeparateDetectionWork::resetTracking");
 #ifdef USE_STD_THREADS
-    mtx_lock.lock();
+    std::unique_lock<std::mutex> mtx_lock(mtx);
 #else
     pthread_mutex_lock(&mutex);
 #endif
@@ -523,7 +529,7 @@ bool cv::DetectionBasedTracker::SeparateDetectionWork::communicateWithDetectingT
     bool shouldHandleResult = false;
 
 #ifdef USE_STD_THREADS
-    mtx_lock.lock();
+    std::unique_lock<std::mutex> mtx_lock(mtx);
 #else
     pthread_mutex_lock(&mutex);
 #endif
@@ -574,8 +580,8 @@ bool cv::DetectionBasedTracker::SeparateDetectionWork::communicateWithDetectingT
 
 cv::DetectionBasedTracker::Parameters::Parameters()
 {
-    maxTrackLifetime=5;
-    minDetectionPeriod=0;
+  maxTrackLifetime = 5;
+  minDetectionPeriod = 0;
 }
 
 cv::DetectionBasedTracker::InnerParameters::InnerParameters()
@@ -603,7 +609,7 @@ cv::DetectionBasedTracker::DetectionBasedTracker(cv::Ptr<IDetector> mainDetector
             && trackingDetector );
 
     if (mainDetector) {
-        separateDetectionWork.reset(new SeparateDetectionWork(*this, mainDetector));
+        separateDetectionWork.reset(new SeparateDetectionWork(*this, mainDetector, params));
     }
 
     weightsPositionsSmoothing.push_back(1);
@@ -618,6 +624,8 @@ cv::DetectionBasedTracker::~DetectionBasedTracker()
 
 void DetectionBasedTracker::process(const Mat& imageGray)
 {
+    CV_INSTRUMENT_REGION()
+
     CV_Assert(imageGray.type()==CV_8UC1);
 
     if ( separateDetectionWork && !separateDetectionWork->isWorking() ) {
@@ -1014,12 +1022,9 @@ bool cv::DetectionBasedTracker::setParameters(const Parameters& params)
     }
 
     if (separateDetectionWork) {
-        separateDetectionWork->lock();
+        separateDetectionWork->setParameters(params);
     }
     parameters=params;
-    if (separateDetectionWork) {
-        separateDetectionWork->unlock();
-    }
     return true;
 }
 
diff --git a/modules/objdetect/src/haar.cpp b/modules/objdetect/src/haar.cpp
index 66ea517..51843fa 100644
--- a/modules/objdetect/src/haar.cpp
+++ b/modules/objdetect/src/haar.cpp
@@ -1275,6 +1275,8 @@ CV_IMPL int
 cvRunHaarClassifierCascade( const CvHaarClassifierCascade* _cascade,
                             CvPoint pt, int start_stage )
 {
+    CV_INSTRUMENT_REGION()
+
     double stage_sum;
     return cvRunHaarClassifierCascadeSum(_cascade, pt, stage_sum, start_stage);
 }
@@ -1308,6 +1310,8 @@ public:
 
     void operator()( const Range& range ) const
     {
+        CV_INSTRUMENT_REGION()
+
         Size winSize0 = cascade->orig_window_size;
         Size winSize(cvRound(winSize0.width*factor), cvRound(winSize0.height*factor));
         int y1 = range.start*stripSize, y2 = std::min(range.end*stripSize, sum1.rows - 1 - winSize0.height);
@@ -1322,10 +1326,10 @@ public:
         if(CV_IPP_CHECK_COND && cascade->hid_cascade->ipp_stages )
         {
             IppiRect iequRect = {equRect.x, equRect.y, equRect.width, equRect.height};
-            ippiRectStdDev_32f_C1R(sum1.ptr<float>(y1), (int)sum1.step,
+            CV_INSTRUMENT_FUN_IPP(ippiRectStdDev_32f_C1R, sum1.ptr<float>(y1), (int)sum1.step,
                                    sqsum1.ptr<double>(y1), (int)sqsum1.step,
                                    norm1->ptr<float>(y1), (int)norm1->step,
-                                   ippiSize(ssz.width, ssz.height), iequRect );
+                                   ippiSize(ssz.width, ssz.height), iequRect);
 
             int positive = (ssz.width/ystep)*((ssz.height + ystep-1)/ystep);
 
@@ -1344,7 +1348,7 @@ public:
 
             for( int j = 0; j < cascade->count; j++ )
             {
-                if( ippiApplyHaarClassifier_32f_C1R(
+                if (CV_INSTRUMENT_FUN_IPP(ippiApplyHaarClassifier_32f_C1R,
                             sum1.ptr<float>(y1), (int)sum1.step,
                             norm1->ptr<float>(y1), (int)norm1->step,
                             mask1->ptr<uchar>(y1), (int)mask1->step,
@@ -1441,6 +1445,8 @@ public:
 
     void operator()( const Range& range ) const
     {
+        CV_INSTRUMENT_REGION()
+
         int iy, startY = range.start, endY = range.end;
         const int *p0 = p[0], *p1 = p[1], *p2 = p[2], *p3 = p[3];
         const int *pq0 = pq[0], *pq1 = pq[1], *pq2 = pq[2], *pq3 = pq[3];
@@ -1500,6 +1506,8 @@ cvHaarDetectObjectsForROC( const CvArr* _img,
                      double scaleFactor, int minNeighbors, int flags,
                      CvSize minSize, CvSize maxSize, bool outputRejectLevels )
 {
+    CV_INSTRUMENT_REGION()
+
     const double GROUP_EPS = 0.2;
     CvMat stub, *img = (CvMat*)_img;
     cv::Ptr<CvMat> temp, sum, tilted, sqsum, normImg, sumcanny, imgSmall;
diff --git a/modules/objdetect/src/hog.cpp b/modules/objdetect/src/hog.cpp
index 77dd712..84baed6 100644
--- a/modules/objdetect/src/hog.cpp
+++ b/modules/objdetect/src/hog.cpp
@@ -222,9 +222,22 @@ void HOGDescriptor::copyTo(HOGDescriptor& c) const
     c.signedGradient = signedGradient;
 }
 
+#if CV_NEON
+// replace of _mm_set_ps
+inline float32x4_t vsetq_f32(float f0, float f1, float f2, float f3)
+{
+    float32x4_t a = vdupq_n_f32(f0);
+    a = vsetq_lane_f32(f1, a, 1);
+    a = vsetq_lane_f32(f2, a, 2);
+    a = vsetq_lane_f32(f3, a, 3);
+    return a;
+}
+#endif
 void HOGDescriptor::computeGradient(const Mat& img, Mat& grad, Mat& qangle,
     Size paddingTL, Size paddingBR) const
 {
+    CV_INSTRUMENT_REGION()
+
     CV_Assert( img.type() == CV_8U || img.type() == CV_8UC3 );
 
     Size gradsize(img.cols + paddingTL.width + paddingBR.width,
@@ -259,6 +272,21 @@ void HOGDescriptor::computeGradient(const Mat& img, Mat& grad, Mat& qangle,
             _mm_storeu_ps(_data + i, _mm_cvtepi32_ps(idx));
             idx = _mm_add_epi32(idx, ifour);
         }
+#elif CV_NEON
+    const int indeces[] = { 0, 1, 2, 3 };
+    uint32x4_t idx = *(uint32x4_t*)indeces;
+    uint32x4_t ifour = vdupq_n_u32(4);
+
+    float* const _data = &_lut(0, 0);
+    if( gammaCorrection )
+        for( i = 0; i < 256; i++ )
+            _lut(0,i) = std::sqrt((float)i);
+    else
+        for( i = 0; i < 256; i += 4 )
+        {
+            vst1q_f32(_data + i, vcvtq_f32_u32(idx));
+            idx = vaddq_u32 (idx, ifour);
+        }
 #else
     if( gammaCorrection )
         for( i = 0; i < 256; i++ )
@@ -299,6 +327,10 @@ void HOGDescriptor::computeGradient(const Mat& img, Mat& grad, Mat& qangle,
         for ( ; x <= end - 4; x += 4)
             _mm_storeu_si128((__m128i*)(xmap + x), _mm_mullo_epi16(ithree,
                 _mm_loadu_si128((const __m128i*)(xmap + x))));
+#elif CV_NEON
+        int32x4_t ithree = vdupq_n_s32(3);
+        for ( ; x <= end - 4; x += 4)
+            vst1q_s32(xmap + x, vmulq_s32(ithree, vld1q_s32(xmap + x)));
 #endif
         for ( ; x < end; ++x)
             xmap[x] *= 3;
@@ -368,6 +400,45 @@ void HOGDescriptor::computeGradient(const Mat& img, Mat& grad, Mat& qangle,
                 _mm_storeu_ps(dbuf + x, _dx2);
                 _mm_storeu_ps(dbuf + x + width, _dy2);
             }
+#elif CV_NEON
+            for( ; x <= width - 4; x += 4 )
+            {
+                int x0 = xmap[x], x1 = xmap[x+1], x2 = xmap[x+2], x3 = xmap[x+3];
+                typedef const uchar* const T;
+                T p02 = imgPtr + xmap[x+1], p00 = imgPtr + xmap[x-1];
+                T p12 = imgPtr + xmap[x+2], p10 = imgPtr + xmap[x];
+                T p22 = imgPtr + xmap[x+3], p20 = p02;
+                T p32 = imgPtr + xmap[x+4], p30 = p12;
+
+                float32x4_t _dx0 = vsubq_f32(vsetq_f32(lut[p02[0]], lut[p12[0]], lut[p22[0]], lut[p32[0]]),
+                                             vsetq_f32(lut[p00[0]], lut[p10[0]], lut[p20[0]], lut[p30[0]]));
+                float32x4_t _dx1 = vsubq_f32(vsetq_f32(lut[p02[1]], lut[p12[1]], lut[p22[1]], lut[p32[1]]),
+                                             vsetq_f32(lut[p00[1]], lut[p10[1]], lut[p20[1]], lut[p30[1]]));
+                float32x4_t _dx2 = vsubq_f32(vsetq_f32(lut[p02[2]], lut[p12[2]], lut[p22[2]], lut[p32[2]]),
+                                             vsetq_f32(lut[p00[2]], lut[p10[2]], lut[p20[2]], lut[p30[2]]));
+
+                float32x4_t _dy0 = vsubq_f32(vsetq_f32(lut[nextPtr[x0]], lut[nextPtr[x1]], lut[nextPtr[x2]], lut[nextPtr[x3]]),
+                                             vsetq_f32(lut[prevPtr[x0]], lut[prevPtr[x1]], lut[prevPtr[x2]], lut[prevPtr[x3]]));
+                float32x4_t _dy1 = vsubq_f32(vsetq_f32(lut[nextPtr[x0+1]], lut[nextPtr[x1+1]], lut[nextPtr[x2+1]], lut[nextPtr[x3+1]]),
+                                             vsetq_f32(lut[prevPtr[x0+1]], lut[prevPtr[x1+1]], lut[prevPtr[x2+1]], lut[prevPtr[x3+1]]));
+                float32x4_t _dy2 = vsubq_f32(vsetq_f32(lut[nextPtr[x0+2]], lut[nextPtr[x1+2]], lut[nextPtr[x2+2]], lut[nextPtr[x3+2]]),
+                                             vsetq_f32(lut[prevPtr[x0+2]], lut[prevPtr[x1+2]], lut[prevPtr[x2+2]], lut[prevPtr[x3+2]]));
+
+                float32x4_t _mag0 = vaddq_f32(vmulq_f32(_dx0, _dx0), vmulq_f32(_dy0, _dy0));
+                float32x4_t _mag1 = vaddq_f32(vmulq_f32(_dx1, _dx1), vmulq_f32(_dy1, _dy1));
+                float32x4_t _mag2 = vaddq_f32(vmulq_f32(_dx2, _dx2), vmulq_f32(_dy2, _dy2));
+
+                uint32x4_t mask = vcgtq_f32(_mag2, _mag1);
+                _dx2 = vbslq_f32(mask, _dx2, _dx1);
+                _dy2 = vbslq_f32(mask, _dy2, _dy1);
+
+                mask = vcgtq_f32(vmaxq_f32(_mag2, _mag1), _mag0);
+                _dx2 = vbslq_f32(mask, _dx2, _dx0);
+                _dy2 = vbslq_f32(mask, _dy2, _dy0);
+
+                vst1q_f32(dbuf + x, _dx2);
+                vst1q_f32(dbuf + x + width, _dy2);
+            }
 #endif
             for( ; x < width; x++ )
             {
@@ -600,6 +671,19 @@ void HOGCache::init(const HOGDescriptor* _descriptor,
             idx = _mm_add_epi32(idx, ifour);
             _mm_storeu_ps(_di + i, t);
         }
+    #elif CV_NEON
+        const int a[] = { 0, 1, 2, 3 };
+        int32x4_t idx = vld1q_s32(a);
+        float32x4_t _bw = vdupq_n_f32(bw), _bh = vdupq_n_f32(bh);
+        int32x4_t ifour = vdupq_n_s32(4);
+
+        for (; i <= blockSize.height - 4; i += 4)
+        {
+            float32x4_t t = vsubq_f32(vcvtq_f32_s32(idx), _bh);
+            t = vmulq_f32(t, t);
+            idx = vaddq_s32(idx, ifour);
+            vst1q_f32(_di + i, t);
+        }
     #endif
         for ( ; i < blockSize.height; ++i)
         {
@@ -617,6 +701,15 @@ void HOGCache::init(const HOGDescriptor* _descriptor,
             idx = _mm_add_epi32(idx, ifour);
             _mm_storeu_ps(_dj + j, t);
         }
+    #elif CV_NEON
+        idx = vld1q_s32(a);
+        for (; j <= blockSize.width - 4; j += 4)
+        {
+            float32x4_t t = vsubq_f32(vcvtq_f32_s32(idx), _bw);
+            t = vmulq_f32(t, t);
+            idx = vaddq_s32(idx, ifour);
+            vst1q_f32(_dj + j, t);
+        }
     #endif
         for ( ; j < blockSize.width; ++j)
         {
@@ -839,6 +932,31 @@ const float* HOGCache::getBlock(Point pt, float* buf)
         t1 = hist[h1] + hist1[1];
         hist[h0] = t0; hist[h1] = t1;
     }
+#elif CV_NEON
+    float hist0[4], hist1[4];
+    for( ; k < C2; k++ )
+    {
+        const PixData& pk = _pixData[k];
+        const float* const a = gradPtr + pk.gradOfs;
+        const uchar* const h = qanglePtr + pk.qangleOfs;
+        int h0 = h[0], h1 = h[1];
+
+        float32x4_t _a0 = vdupq_n_f32(a[0]), _a1 = vdupq_n_f32(a[1]);
+        float32x4_t _w = vmulq_f32(vdupq_n_f32(pk.gradWeight), vld1q_f32(pk.histWeights));
+
+        float32x4_t _h0 = vsetq_f32((blockHist + pk.histOfs[0])[h0], (blockHist + pk.histOfs[1])[h0], 0,  0);
+        float32x4_t _h1 = vsetq_f32((blockHist + pk.histOfs[0])[h1], (blockHist + pk.histOfs[1])[h1], 0,  0);
+
+        float32x4_t _t0 = vmlaq_f32(_h0, _a0, _w), _t1 = vmlaq_f32(_h1, _a1, _w);
+        vst1q_f32(hist0, _t0);
+        vst1q_f32(hist1, _t1);
+
+        (blockHist + pk.histOfs[0])[h0] = hist0[0];
+        (blockHist + pk.histOfs[1])[h0] = hist0[1];
+
+        (blockHist + pk.histOfs[0])[h1] = hist1[0];
+        (blockHist + pk.histOfs[1])[h1] = hist1[1];
+    }
 #else
     for( ; k < C2; k++ )
     {
@@ -918,6 +1036,41 @@ const float* HOGCache::getBlock(Point pt, float* buf)
 //        (pk.histOfs[2] + blockHist)[h1] = hist1[2];
 //        (pk.histOfs[3] + blockHist)[h1] = hist1[3];
     }
+#elif CV_NEON
+    for( ; k < C4; k++ )
+    {
+        const PixData& pk = _pixData[k];
+        const float* const a = gradPtr + pk.gradOfs;
+        const uchar* const h = qanglePtr + pk.qangleOfs;
+        int h0 = h[0], h1 = h[1];
+
+        float32x4_t _a0 = vdupq_n_f32(a[0]), _a1 = vdupq_n_f32(a[1]);
+        float32x4_t _w = vmulq_f32(vdupq_n_f32(pk.gradWeight), vld1q_f32(pk.histWeights));
+
+        float32x4_t _h0 = vsetq_f32((blockHist + pk.histOfs[0])[h0],
+                                    (blockHist + pk.histOfs[1])[h0],
+                                    (blockHist + pk.histOfs[2])[h0],
+                                    (blockHist + pk.histOfs[3])[h0]);
+        float32x4_t _h1 = vsetq_f32((blockHist + pk.histOfs[0])[h1],
+                                    (blockHist + pk.histOfs[1])[h1],
+                                    (blockHist + pk.histOfs[2])[h1],
+                                    (blockHist + pk.histOfs[3])[h1]);
+
+
+        float32x4_t _t0 = vmlaq_f32(_h0, _a0, _w), _t1 = vmlaq_f32(_h1, _a1, _w);
+        vst1q_f32(hist0, _t0);
+        vst1q_f32(hist1, _t1);
+
+        (blockHist + pk.histOfs[0])[h0] = hist0[0];
+        (blockHist + pk.histOfs[1])[h0] = hist0[1];
+        (blockHist + pk.histOfs[2])[h0] = hist0[2];
+        (blockHist + pk.histOfs[3])[h0] = hist0[3];
+
+        (blockHist + pk.histOfs[0])[h1] = hist1[0];
+        (blockHist + pk.histOfs[1])[h1] = hist1[1];
+        (blockHist + pk.histOfs[2])[h1] = hist1[2];
+        (blockHist + pk.histOfs[3])[h1] = hist1[3];
+    }
 #else
     for( ; k < C4; k++ )
     {
@@ -973,6 +1126,16 @@ void HOGCache::normalizeBlockHistogram(float* _hist) const
         s = _mm_add_ps(s, _mm_mul_ps(p0, p0));
     }
     _mm_storeu_ps(partSum, s);
+#elif CV_NEON
+    float32x4_t p0 = vld1q_f32(hist);
+    float32x4_t s = vmulq_f32(p0, p0);
+
+    for (i = 4; i <= sz - 4; i += 4)
+    {
+        p0 = vld1q_f32(hist + i);
+        s = vaddq_f32(s, vmulq_f32(p0, p0));
+    }
+    vst1q_f32(partSum, s);
 #else
     partSum[0] = 0.0f;
     partSum[1] = 0.0f;
@@ -1014,6 +1177,25 @@ void HOGCache::normalizeBlockHistogram(float* _hist) const
     }
 
     _mm_storeu_ps(partSum, s);
+#elif CV_NEON
+    float32x4_t _scale = vdupq_n_f32(scale);
+    static float32x4_t _threshold = vdupq_n_f32(thresh);
+
+    float32x4_t p = vmulq_f32(_scale, vld1q_f32(hist));
+    p = vminq_f32(p, _threshold);
+    s = vmulq_f32(p, p);
+    vst1q_f32(hist, p);
+
+    for(i = 4 ; i <= sz - 4; i += 4)
+    {
+        p = vld1q_f32(hist + i);
+        p = vmulq_f32(p, _scale);
+        p = vminq_f32(p, _threshold);
+        s = vaddq_f32(s, vmulq_f32(p, p));
+        vst1q_f32(hist + i, p);
+    }
+
+    vst1q_f32(partSum, s);
 #else
     partSum[0] = 0.0f;
     partSum[1] = 0.0f;
@@ -1048,6 +1230,13 @@ void HOGCache::normalizeBlockHistogram(float* _hist) const
         __m128 t = _mm_mul_ps(_scale2, _mm_loadu_ps(hist + i));
         _mm_storeu_ps(hist + i, t);
     }
+#elif CV_NEON
+    float32x4_t _scale2 = vdupq_n_f32(scale);
+    for ( ; i <= sz - 4; i += 4)
+    {
+        float32x4_t t = vmulq_f32(_scale2, vld1q_f32(hist + i));
+        vst1q_f32(hist + i, t);
+    }
 #endif
     for ( ; i < sz; ++i)
         hist[i] *= scale;
@@ -1395,6 +1584,8 @@ static bool ocl_compute(InputArray _img, Size win_stride, std::vector<float>& _d
 void HOGDescriptor::compute(InputArray _img, std::vector<float>& descriptors,
     Size winStride, Size padding, const std::vector<Point>& locations) const
 {
+    CV_INSTRUMENT_REGION()
+
     if( winStride == Size() )
         winStride = cellSize;
     Size cacheStride(gcd(winStride.width, blockStride.width),
@@ -1460,6 +1651,8 @@ void HOGDescriptor::detect(const Mat& img,
     std::vector<Point>& hits, std::vector<double>& weights, double hitThreshold,
     Size winStride, Size padding, const std::vector<Point>& locations) const
 {
+    CV_INSTRUMENT_REGION()
+
     hits.clear();
     weights.clear();
     if( svmDetector.empty() )
@@ -1489,7 +1682,7 @@ void HOGDescriptor::detect(const Mat& img,
     double rho = svmDetector.size() > dsize ? svmDetector[dsize] : 0;
     std::vector<float> blockHist(blockHistogramSize);
 
-#if CV_SSE2
+#if CV_SSE2 || CV_NEON
     float partSum[4];
 #endif
 
@@ -1535,6 +1728,23 @@ void HOGDescriptor::detect(const Mat& img,
             double t0 = partSum[0] + partSum[1];
             double t1 = partSum[2] + partSum[3];
             s += t0 + t1;
+#elif CV_NEON
+            float32x4_t _vec = vld1q_f32(vec);
+            float32x4_t _svmVec = vld1q_f32(svmVec);
+            float32x4_t sum = vmulq_f32(_svmVec, _vec);
+
+            for( k = 4; k <= blockHistogramSize - 4; k += 4 )
+            {
+                _vec = vld1q_f32(vec + k);
+                _svmVec = vld1q_f32(svmVec + k);
+
+                sum = vaddq_f32(sum, vmulq_f32(_vec, _svmVec));
+            }
+
+            vst1q_f32(partSum, sum);
+            double t0 = partSum[0] + partSum[1];
+            double t1 = partSum[2] + partSum[3];
+            s += t0 + t1;
 #else
             for( k = 0; k <= blockHistogramSize - 4; k += 4 )
                 s += vec[k]*svmVec[k] + vec[k+1]*svmVec[k+1] +
@@ -1554,6 +1764,8 @@ void HOGDescriptor::detect(const Mat& img,
 void HOGDescriptor::detect(const Mat& img, std::vector<Point>& hits, double hitThreshold,
     Size winStride, Size padding, const std::vector<Point>& locations) const
 {
+    CV_INSTRUMENT_REGION()
+
     std::vector<double> weightsV;
     detect(img, hits, weightsV, hitThreshold, winStride, padding, locations);
 }
@@ -1836,6 +2048,8 @@ void HOGDescriptor::detectMultiScale(
     double hitThreshold, Size winStride, Size padding,
     double scale0, double finalThreshold, bool useMeanshiftGrouping) const
 {
+    CV_INSTRUMENT_REGION()
+
     double scale = 1.;
     int levels = 0;
 
@@ -1889,6 +2103,8 @@ void HOGDescriptor::detectMultiScale(InputArray img, std::vector<Rect>& foundLoc
     double hitThreshold, Size winStride, Size padding,
     double scale0, double finalThreshold, bool useMeanshiftGrouping) const
 {
+    CV_INSTRUMENT_REGION()
+
     std::vector<double> foundWeights;
     detectMultiScale(img, foundLocations, foundWeights, hitThreshold, winStride,
                 padding, scale0, finalThreshold, useMeanshiftGrouping);
@@ -3285,6 +3501,8 @@ public:
 
     void operator()( const Range& range ) const
     {
+        CV_INSTRUMENT_REGION()
+
         int i, i1 = range.start, i2 = range.end;
 
         Size maxSz(cvCeil(img.cols/(*locations)[0].scale), cvCeil(img.rows/(*locations)[0].scale));
@@ -3327,6 +3545,8 @@ void HOGDescriptor::detectROI(const cv::Mat& img, const std::vector<cv::Point> &
     CV_OUT std::vector<cv::Point>& foundLocations, CV_OUT std::vector<double>& confidences,
     double hitThreshold, cv::Size winStride, cv::Size padding) const
 {
+    CV_INSTRUMENT_REGION()
+
     foundLocations.clear();
     confidences.clear();
 
@@ -3357,7 +3577,7 @@ void HOGDescriptor::detectROI(const cv::Mat& img, const std::vector<cv::Point> &
     double rho = svmDetector.size() > dsize ? svmDetector[dsize] : 0;
     std::vector<float> blockHist(blockHistogramSize);
 
-#if CV_SSE2
+#if CV_SSE2 || CV_NEON
     float partSum[4];
 #endif
 
@@ -3401,6 +3621,23 @@ void HOGDescriptor::detectROI(const cv::Mat& img, const std::vector<cv::Point> &
             double t0 = partSum[0] + partSum[1];
             double t1 = partSum[2] + partSum[3];
             s += t0 + t1;
+#elif CV_NEON
+            float32x4_t _vec = vld1q_f32(vec);
+            float32x4_t _svmVec = vld1q_f32(svmVec);
+            float32x4_t sum = vmulq_f32(_svmVec, _vec);
+
+            for( k = 4; k <= blockHistogramSize - 4; k += 4 )
+            {
+                _vec = vld1q_f32(vec + k);
+                _svmVec = vld1q_f32(svmVec + k);
+
+                sum = vaddq_f32(sum, vmulq_f32(_vec, _svmVec));
+            }
+
+            vst1q_f32(partSum, sum);
+            double t0 = partSum[0] + partSum[1];
+            double t1 = partSum[2] + partSum[3];
+            s += t0 + t1;
 #else
             for( k = 0; k <= blockHistogramSize - 4; k += 4 )
                 s += vec[k]*svmVec[k] + vec[k+1]*svmVec[k+1] +
@@ -3420,6 +3657,8 @@ void HOGDescriptor::detectMultiScaleROI(const cv::Mat& img,
     CV_OUT std::vector<cv::Rect>& foundLocations, std::vector<DetectionROI>& locations,
     double hitThreshold, int groupThreshold) const
 {
+    CV_INSTRUMENT_REGION()
+
     std::vector<Rect> allCandidates;
     Mutex mtx;
 
@@ -3526,6 +3765,8 @@ void HOGDescriptor::readALTModel(String modelfile)
 
 void HOGDescriptor::groupRectangles(std::vector<cv::Rect>& rectList, std::vector<double>& weights, int groupThreshold, double eps) const
 {
+    CV_INSTRUMENT_REGION()
+
     if( groupThreshold <= 0 || rectList.empty() )
     {
         return;
diff --git a/modules/objdetect/src/opencl/cascadedetect.cl b/modules/objdetect/src/opencl/cascadedetect.cl
index ccc9c6d..cdd72e9 100644
--- a/modules/objdetect/src/opencl/cascadedetect.cl
+++ b/modules/objdetect/src/opencl/cascadedetect.cl
@@ -180,11 +180,11 @@ void runHaarClassifier(
                         int4 ofs = f->ofs[0];
                         sval = (psum[ofs.x] - psum[ofs.y] - psum[ofs.z] + psum[ofs.w])*weight.x;
                         ofs = f->ofs[1];
-                        sval = mad((psum[ofs.x] - psum[ofs.y] - psum[ofs.z] + psum[ofs.w]), weight.y, sval);
+                        sval = mad((float)(psum[ofs.x] - psum[ofs.y] - psum[ofs.z] + psum[ofs.w]), weight.y, sval);
                         if( weight.z > 0 )
                         {
                             ofs = f->ofs[2];
-                            sval = mad((psum[ofs.x] - psum[ofs.y] - psum[ofs.z] + psum[ofs.w]), weight.z, sval);
+                            sval = mad((float)(psum[ofs.x] - psum[ofs.y] - psum[ofs.z] + psum[ofs.w]), weight.z, sval);
                         }
 
                         s += (sval < st.y*nf) ? st.z : st.w;
@@ -204,11 +204,11 @@ void runHaarClassifier(
 
                             sval = (psum[ofs.x] - psum[ofs.y] - psum[ofs.z] + psum[ofs.w])*weight.x;
                             ofs = f->ofs[1];
-                            sval = mad((psum[ofs.x] - psum[ofs.y] - psum[ofs.z] + psum[ofs.w]), weight.y, sval);
+                            sval = mad((float)(psum[ofs.x] - psum[ofs.y] - psum[ofs.z] + psum[ofs.w]), weight.y, sval);
                             if( weight.z > 0 )
                             {
                                 ofs = f->ofs[2];
-                                sval = mad((psum[ofs.x] - psum[ofs.y] - psum[ofs.z] + psum[ofs.w]), weight.z, sval);
+                                sval = mad((float)(psum[ofs.x] - psum[ofs.y] - psum[ofs.z] + psum[ofs.w]), weight.z, sval);
                             }
 
                             idx = (sval < as_float(n.y)*nf) ? n.z : n.w;
@@ -281,12 +281,12 @@ void runHaarClassifier(
                             int4 ofs = f->ofs[0];
                             float sval = (psum[ofs.x] - psum[ofs.y] - psum[ofs.z] + psum[ofs.w])*weight.x;
                             ofs = f->ofs[1];
-                            sval = mad((psum[ofs.x] - psum[ofs.y] - psum[ofs.z] + psum[ofs.w]), weight.y, sval);
+                            sval = mad((float)(psum[ofs.x] - psum[ofs.y] - psum[ofs.z] + psum[ofs.w]), weight.y, sval);
                             //if( weight.z > 0 )
                             if( fabs(weight.z) > 0 )
                             {
                                 ofs = f->ofs[2];
-                                sval = mad((psum[ofs.x] - psum[ofs.y] - psum[ofs.z] + psum[ofs.w]), weight.z, sval);
+                                sval = mad((float)(psum[ofs.x] - psum[ofs.y] - psum[ofs.z] + psum[ofs.w]), weight.z, sval);
                             }
 
                             partsum += (sval < st.y*nf) ? st.z : st.w;
@@ -304,11 +304,11 @@ void runHaarClassifier(
 
                                 float sval = (psum[ofs.x] - psum[ofs.y] - psum[ofs.z] + psum[ofs.w])*weight.x;
                                 ofs = f->ofs[1];
-                                sval = mad((psum[ofs.x] - psum[ofs.y] - psum[ofs.z] + psum[ofs.w]), weight.y, sval);
+                                sval = mad((float)(psum[ofs.x] - psum[ofs.y] - psum[ofs.z] + psum[ofs.w]), weight.y, sval);
                                 if( weight.z > 0 )
                                 {
                                     ofs = f->ofs[2];
-                                    sval = mad((psum[ofs.x] - psum[ofs.y] - psum[ofs.z] + psum[ofs.w]), weight.z, sval);
+                                    sval = mad((float)(psum[ofs.x] - psum[ofs.y] - psum[ofs.z] + psum[ofs.w]), weight.z, sval);
                                 }
 
                                 idx = (sval < as_float(n.y)*nf) ? n.z : n.w;
diff --git a/modules/objdetect/test/test_cascadeandhog.cpp b/modules/objdetect/test/test_cascadeandhog.cpp
index 31afbe6..806ce1f 100644
--- a/modules/objdetect/test/test_cascadeandhog.cpp
+++ b/modules/objdetect/test/test_cascadeandhog.cpp
@@ -1086,8 +1086,8 @@ void HOGDescriptorTester::detect(const Mat& img,
         return;
     }
 
-    const double eps = 0.0;
-    double diff_norm = cvtest::norm(actual_weights, weights, NORM_L2);
+    const double eps = FLT_EPSILON * 100;
+    double diff_norm = cvtest::norm(actual_weights, weights, NORM_L2 + NORM_RELATIVE);
     if (diff_norm > eps)
     {
         ts->printf(cvtest::TS::SUMMARY, "Weights for found locations aren't equal.\n"
@@ -1096,7 +1096,6 @@ void HOGDescriptorTester::detect(const Mat& img,
         failed = true;
         ts->set_failed_test_info(cvtest::TS::FAIL_BAD_ACCURACY);
         ts->set_gtest_status();
-        return;
     }
 }
 
@@ -1168,8 +1167,8 @@ void HOGDescriptorTester::compute(InputArray _img, vector<float>& descriptors,
     std::vector<float> actual_descriptors;
     actual_hog->compute(img, actual_descriptors, winStride, padding, locations);
 
-    double diff_norm = cvtest::norm(actual_descriptors, descriptors, NORM_L2);
-    const double eps = 0.0;
+    double diff_norm = cvtest::norm(actual_descriptors, descriptors, NORM_L2 + NORM_RELATIVE);
+    const double eps = FLT_EPSILON * 100;
     if (diff_norm > eps)
     {
         ts->printf(cvtest::TS::SUMMARY, "Norm of the difference: %lf\n", diff_norm);
@@ -1178,7 +1177,6 @@ void HOGDescriptorTester::compute(InputArray _img, vector<float>& descriptors,
         ts->printf(cvtest::TS::LOG, "Channels: %d\n", img.channels());
         ts->set_gtest_status();
         failed = true;
-        return;
     }
 }
 
@@ -1315,10 +1313,10 @@ void HOGDescriptorTester::computeGradient(const Mat& img, Mat& grad, Mat& qangle
     const char* args[] = { "Gradient's", "Qangles's" };
     actual_hog->computeGradient(img, actual_mats[0], actual_mats[1], paddingTL, paddingBR);
 
-    const double eps = 0.0;
+    const double eps = FLT_EPSILON * 100;
     for (i = 0; i < 2; ++i)
     {
-       double diff_norm = cvtest::norm(reference_mats[i], actual_mats[i], NORM_L2);
+       double diff_norm = cvtest::norm(actual_mats[i], reference_mats[i], NORM_L2 + NORM_RELATIVE);
        if (diff_norm > eps)
        {
            ts->printf(cvtest::TS::LOG, "%s matrices are not equal\n"
@@ -1327,7 +1325,6 @@ void HOGDescriptorTester::computeGradient(const Mat& img, Mat& grad, Mat& qangle
            ts->set_failed_test_info(cvtest::TS::FAIL_BAD_ACCURACY);
            ts->set_gtest_status();
            failed = true;
-           return;
        }
     }
 }
diff --git a/modules/photo/include/opencv2/photo.hpp b/modules/photo/include/opencv2/photo.hpp
index c093f65..a445dd3 100644
--- a/modules/photo/include/opencv2/photo.hpp
+++ b/modules/photo/include/opencv2/photo.hpp
@@ -40,8 +40,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_PHOTO_HPP__
-#define __OPENCV_PHOTO_HPP__
+#ifndef OPENCV_PHOTO_HPP
+#define OPENCV_PHOTO_HPP
 
 #include "opencv2/core.hpp"
 #include "opencv2/imgproc.hpp"
diff --git a/modules/photo/include/opencv2/photo/cuda.hpp b/modules/photo/include/opencv2/photo/cuda.hpp
index aeac1fa..a2f3816 100644
--- a/modules/photo/include/opencv2/photo/cuda.hpp
+++ b/modules/photo/include/opencv2/photo/cuda.hpp
@@ -40,8 +40,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_PHOTO_CUDA_HPP__
-#define __OPENCV_PHOTO_CUDA_HPP__
+#ifndef OPENCV_PHOTO_CUDA_HPP
+#define OPENCV_PHOTO_CUDA_HPP
 
 #include "opencv2/core/cuda.hpp"
 
@@ -129,4 +129,4 @@ CV_EXPORTS void fastNlMeansDenoisingColored(InputArray src, OutputArray dst,
 
 }} // namespace cv { namespace cuda {
 
-#endif /* __OPENCV_PHOTO_CUDA_HPP__ */
+#endif /* OPENCV_PHOTO_CUDA_HPP */
diff --git a/modules/photo/include/opencv2/photo/photo_c.h b/modules/photo/include/opencv2/photo/photo_c.h
index 07ca9b3..cd623c1 100644
--- a/modules/photo/include/opencv2/photo/photo_c.h
+++ b/modules/photo/include/opencv2/photo/photo_c.h
@@ -40,8 +40,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_PHOTO_C_H__
-#define __OPENCV_PHOTO_C_H__
+#ifndef OPENCV_PHOTO_C_H
+#define OPENCV_PHOTO_C_H
 
 #include "opencv2/core/core_c.h"
 
@@ -71,4 +71,4 @@ CVAPI(void) cvInpaint( const CvArr* src, const CvArr* inpaint_mask,
 } //extern "C"
 #endif
 
-#endif //__OPENCV_PHOTO_C_H__
+#endif //OPENCV_PHOTO_C_H
diff --git a/modules/photo/src/align.cpp b/modules/photo/src/align.cpp
index 94be92d..0208711 100644
--- a/modules/photo/src/align.cpp
+++ b/modules/photo/src/align.cpp
@@ -61,11 +61,15 @@ public:
     void process(InputArrayOfArrays src, std::vector<Mat>& dst,
                  InputArray, InputArray)
     {
+        CV_INSTRUMENT_REGION()
+
         process(src, dst);
     }
 
     void process(InputArrayOfArrays _src, std::vector<Mat>& dst)
     {
+        CV_INSTRUMENT_REGION()
+
         std::vector<Mat> src;
         _src.getMatVector(src);
 
@@ -114,6 +118,8 @@ public:
 
     Point calculateShift(InputArray _img0, InputArray _img1)
     {
+        CV_INSTRUMENT_REGION()
+
         Mat img0 = _img0.getMat();
         Mat img1 = _img1.getMat();
         CV_Assert(img0.channels() == 1 && img0.type() == img1.type());
@@ -160,6 +166,8 @@ public:
 
     void shiftMat(InputArray _src, OutputArray _dst, const Point shift)
     {
+        CV_INSTRUMENT_REGION()
+
         Mat src = _src.getMat();
         _dst.create(src.size(), src.type());
         Mat dst = _dst.getMat();
@@ -184,6 +192,7 @@ public:
 
     void write(FileStorage& fs) const
     {
+        writeFormat(fs);
         fs << "name" << name
            << "max_bits" << max_bits
            << "exclude_range" << exclude_range
@@ -202,6 +211,8 @@ public:
 
     void computeBitmaps(InputArray _img, OutputArray _tb, OutputArray _eb)
     {
+        CV_INSTRUMENT_REGION()
+
         Mat img = _img.getMat();
         _tb.create(img.size(), CV_8U);
         _eb.create(img.size(), CV_8U);
diff --git a/modules/photo/src/calibrate.cpp b/modules/photo/src/calibrate.cpp
index 63f1818..dd30005 100644
--- a/modules/photo/src/calibrate.cpp
+++ b/modules/photo/src/calibrate.cpp
@@ -63,6 +63,8 @@ public:
 
     void process(InputArrayOfArrays src, OutputArray dst, InputArray _times)
     {
+        CV_INSTRUMENT_REGION()
+
         std::vector<Mat> images;
         src.getMatVector(images);
         Mat times = _times.getMat();
@@ -141,6 +143,7 @@ public:
 
     void write(FileStorage& fs) const
     {
+        writeFormat(fs);
         fs << "name" << name
            << "samples" << samples
            << "lambda" << lambda
@@ -183,6 +186,8 @@ public:
 
     void process(InputArrayOfArrays src, OutputArray dst, InputArray _times)
     {
+        CV_INSTRUMENT_REGION()
+
         std::vector<Mat> images;
         src.getMatVector(images);
         Mat times = _times.getMat();
@@ -250,6 +255,7 @@ public:
 
     void write(FileStorage& fs) const
     {
+        writeFormat(fs);
         fs << "name" << name
            << "max_iter" << max_iter
            << "threshold" << threshold;
diff --git a/modules/photo/src/contrast_preserve.cpp b/modules/photo/src/contrast_preserve.cpp
index 55ea321..8c6caed 100644
--- a/modules/photo/src/contrast_preserve.cpp
+++ b/modules/photo/src/contrast_preserve.cpp
@@ -52,6 +52,8 @@ using namespace cv;
 
 void cv::decolor(InputArray _src, OutputArray _dst, OutputArray _color_boost)
 {
+    CV_INSTRUMENT_REGION()
+
     Mat I = _src.getMat();
     _dst.create(I.size(), CV_8UC1);
     Mat dst = _dst.getMat();
diff --git a/modules/photo/src/denoising.cpp b/modules/photo/src/denoising.cpp
index 93d4b4e..ebf345c 100644
--- a/modules/photo/src/denoising.cpp
+++ b/modules/photo/src/denoising.cpp
@@ -104,6 +104,8 @@ static void fastNlMeansDenoising_( const Mat& src, Mat& dst, const std::vector<f
 void cv::fastNlMeansDenoising( InputArray _src, OutputArray _dst, float h,
                                int templateWindowSize, int searchWindowSize)
 {
+    CV_INSTRUMENT_REGION()
+
     fastNlMeansDenoising(_src, _dst, std::vector<float>(1, h),
                          templateWindowSize, searchWindowSize);
 }
@@ -111,6 +113,8 @@ void cv::fastNlMeansDenoising( InputArray _src, OutputArray _dst, float h,
 void cv::fastNlMeansDenoising( InputArray _src, OutputArray _dst, const std::vector<float>& h,
                                int templateWindowSize, int searchWindowSize, int normType)
 {
+    CV_INSTRUMENT_REGION()
+
     int hn = (int)h.size(), type = _src.type(), depth = CV_MAT_DEPTH(type), cn = CV_MAT_CN(type);
     CV_Assert(hn == 1 || hn == cn);
 
@@ -169,6 +173,8 @@ void cv::fastNlMeansDenoisingColored( InputArray _src, OutputArray _dst,
                                       float h, float hForColorComponents,
                                       int templateWindowSize, int searchWindowSize)
 {
+    CV_INSTRUMENT_REGION()
+
     int type = _src.type(), depth = CV_MAT_DEPTH(type), cn = CV_MAT_CN(type);
     Size src_size = _src.size();
     if (type != CV_8UC3 && type != CV_8UC4)
@@ -308,6 +314,8 @@ void cv::fastNlMeansDenoisingMulti( InputArrayOfArrays _srcImgs, OutputArray _ds
                                     int imgToDenoiseIndex, int temporalWindowSize,
                                     float h, int templateWindowSize, int searchWindowSize)
 {
+    CV_INSTRUMENT_REGION()
+
     fastNlMeansDenoisingMulti(_srcImgs, _dst, imgToDenoiseIndex, temporalWindowSize,
                               std::vector<float>(1, h), templateWindowSize, searchWindowSize);
 }
@@ -317,6 +325,8 @@ void cv::fastNlMeansDenoisingMulti( InputArrayOfArrays _srcImgs, OutputArray _ds
                                     const std::vector<float>& h,
                                     int templateWindowSize, int searchWindowSize, int normType)
 {
+    CV_INSTRUMENT_REGION()
+
     std::vector<Mat> srcImgs;
     _srcImgs.getMatVector(srcImgs);
 
@@ -378,6 +388,8 @@ void cv::fastNlMeansDenoisingColoredMulti( InputArrayOfArrays _srcImgs, OutputAr
                                            float h, float hForColorComponents,
                                            int templateWindowSize, int searchWindowSize)
 {
+    CV_INSTRUMENT_REGION()
+
     std::vector<Mat> srcImgs;
     _srcImgs.getMatVector(srcImgs);
 
diff --git a/modules/photo/src/inpaint.cpp b/modules/photo/src/inpaint.cpp
index f91db5f..4ae3cf3 100644
--- a/modules/photo/src/inpaint.cpp
+++ b/modules/photo/src/inpaint.cpp
@@ -810,8 +810,11 @@ cvInpaint( const CvArr* _input_img, const CvArr* _inpaint_mask, CvArr* _output_i
 void cv::inpaint( InputArray _src, InputArray _mask, OutputArray _dst,
                   double inpaintRange, int flags )
 {
+    CV_INSTRUMENT_REGION()
+
     Mat src = _src.getMat(), mask = _mask.getMat();
     _dst.create( src.size(), src.type() );
-    CvMat c_src = src, c_mask = mask, c_dst = _dst.getMat();
+    Mat dst = _dst.getMat();
+    CvMat c_src = src, c_mask = mask, c_dst = dst;
     cvInpaint( &c_src, &c_mask, &c_dst, inpaintRange, flags );
 }
diff --git a/modules/photo/src/merge.cpp b/modules/photo/src/merge.cpp
index f051f55..3e59180 100644
--- a/modules/photo/src/merge.cpp
+++ b/modules/photo/src/merge.cpp
@@ -58,6 +58,8 @@ public:
 
     void process(InputArrayOfArrays src, OutputArray dst, InputArray _times, InputArray input_response)
     {
+        CV_INSTRUMENT_REGION()
+
         std::vector<Mat> images;
         src.getMatVector(images);
         Mat times = _times.getMat();
@@ -85,7 +87,7 @@ public:
         CV_Assert(log_response.rows == LDR_SIZE && log_response.cols == 1 &&
                   log_response.channels() == channels);
 
-        Mat exp_values(times);
+        Mat exp_values(times.clone());
         log(exp_values, exp_values);
 
         result = Mat::zeros(size, CV_32FCC);
@@ -122,6 +124,8 @@ public:
 
     void process(InputArrayOfArrays src, OutputArray dst, InputArray times)
     {
+        CV_INSTRUMENT_REGION()
+
         process(src, dst, times, Mat());
     }
 
@@ -148,11 +152,15 @@ public:
 
     void process(InputArrayOfArrays src, OutputArrayOfArrays dst, InputArray, InputArray)
     {
+        CV_INSTRUMENT_REGION()
+
         process(src, dst);
     }
 
     void process(InputArrayOfArrays src, OutputArray dst)
     {
+        CV_INSTRUMENT_REGION()
+
         std::vector<Mat> images;
         src.getMatVector(images);
         checkImageDimensions(images);
@@ -265,6 +273,7 @@ public:
 
     void write(FileStorage& fs) const
     {
+        writeFormat(fs);
         fs << "name" << name
            << "contrast_weight" << wcon
            << "saturation_weight" << wsat
@@ -301,6 +310,8 @@ public:
 
     void process(InputArrayOfArrays src, OutputArray dst, InputArray _times, InputArray input_response)
     {
+        CV_INSTRUMENT_REGION()
+
         std::vector<Mat> images;
         src.getMatVector(images);
         Mat times = _times.getMat();
@@ -338,6 +349,8 @@ public:
 
     void process(InputArrayOfArrays src, OutputArray dst, InputArray times)
     {
+        CV_INSTRUMENT_REGION()
+
         process(src, dst, times, Mat());
     }
 
diff --git a/modules/photo/src/npr.cpp b/modules/photo/src/npr.cpp
index 761f3c7..e800ce9 100644
--- a/modules/photo/src/npr.cpp
+++ b/modules/photo/src/npr.cpp
@@ -51,6 +51,8 @@ using namespace cv;
 
 void cv::edgePreservingFilter(InputArray _src, OutputArray _dst, int flags, float sigma_s, float sigma_r)
 {
+    CV_INSTRUMENT_REGION()
+
     Mat I = _src.getMat();
     _dst.create(I.size(), CV_8UC3);
     Mat dst = _dst.getMat();
@@ -73,6 +75,8 @@ void cv::edgePreservingFilter(InputArray _src, OutputArray _dst, int flags, floa
 
 void cv::detailEnhance(InputArray _src, OutputArray _dst, float sigma_s, float sigma_r)
 {
+    CV_INSTRUMENT_REGION()
+
     Mat I = _src.getMat();
     _dst.create(I.size(), CV_8UC3);
     Mat dst = _dst.getMat();
@@ -118,6 +122,8 @@ void cv::detailEnhance(InputArray _src, OutputArray _dst, float sigma_s, float s
 
 void cv::pencilSketch(InputArray _src, OutputArray _dst1, OutputArray _dst2, float sigma_s, float sigma_r, float shade_factor)
 {
+    CV_INSTRUMENT_REGION()
+
     Mat I = _src.getMat();
     _dst1.create(I.size(), CV_8UC1);
     Mat dst1 = _dst1.getMat();
@@ -142,6 +148,8 @@ void cv::pencilSketch(InputArray _src, OutputArray _dst1, OutputArray _dst2, flo
 
 void cv::stylization(InputArray _src, OutputArray _dst, float sigma_s, float sigma_r)
 {
+    CV_INSTRUMENT_REGION()
+
     Mat I = _src.getMat();
     _dst.create(I.size(), CV_8UC3);
     Mat dst = _dst.getMat();
diff --git a/modules/photo/src/seamless_cloning.cpp b/modules/photo/src/seamless_cloning.cpp
index 2564145..ed02f8c 100644
--- a/modules/photo/src/seamless_cloning.cpp
+++ b/modules/photo/src/seamless_cloning.cpp
@@ -49,6 +49,8 @@ using namespace cv;
 
 void cv::seamlessClone(InputArray _src, InputArray _dst, InputArray _mask, Point p, OutputArray _blend, int flags)
 {
+    CV_INSTRUMENT_REGION()
+
     const Mat src  = _src.getMat();
     const Mat dest = _dst.getMat();
     const Mat mask = _mask.getMat();
@@ -116,6 +118,8 @@ void cv::seamlessClone(InputArray _src, InputArray _dst, InputArray _mask, Point
 
 void cv::colorChange(InputArray _src, InputArray _mask, OutputArray _dst, float r, float g, float b)
 {
+    CV_INSTRUMENT_REGION()
+
     Mat src  = _src.getMat();
     Mat mask  = _mask.getMat();
     _dst.create(src.size(), src.type());
@@ -142,6 +146,8 @@ void cv::colorChange(InputArray _src, InputArray _mask, OutputArray _dst, float
 
 void cv::illuminationChange(InputArray _src, InputArray _mask, OutputArray _dst, float a, float b)
 {
+    CV_INSTRUMENT_REGION()
+
 
     Mat src  = _src.getMat();
     Mat mask  = _mask.getMat();
@@ -169,6 +175,8 @@ void cv::illuminationChange(InputArray _src, InputArray _mask, OutputArray _dst,
 void cv::textureFlattening(InputArray _src, InputArray _mask, OutputArray _dst,
                            float low_threshold, float high_threshold, int kernel_size)
 {
+    CV_INSTRUMENT_REGION()
+
 
     Mat src  = _src.getMat();
     Mat mask  = _mask.getMat();
diff --git a/modules/photo/src/seamless_cloning_impl.cpp b/modules/photo/src/seamless_cloning_impl.cpp
index fe2751d..6073a9b 100644
--- a/modules/photo/src/seamless_cloning_impl.cpp
+++ b/modules/photo/src/seamless_cloning_impl.cpp
@@ -420,6 +420,8 @@ void Cloning::localColorChange(Mat &I, Mat &mask, Mat &wmask, Mat &cloned, float
 
 void Cloning::illuminationChange(Mat &I, Mat &mask, Mat &wmask, Mat &cloned, float alpha, float beta)
 {
+    CV_INSTRUMENT_REGION()
+
     computeDerivatives(I,mask,wmask);
 
     arrayProduct(patchGradientX,binaryMaskFloat, patchGradientX);
diff --git a/modules/photo/src/tonemap.cpp b/modules/photo/src/tonemap.cpp
index 1ccc84e..acfca04 100644
--- a/modules/photo/src/tonemap.cpp
+++ b/modules/photo/src/tonemap.cpp
@@ -62,6 +62,8 @@ public:
 
     void process(InputArray _src, OutputArray _dst)
     {
+        CV_INSTRUMENT_REGION()
+
         Mat src = _src.getMat();
         CV_Assert(!src.empty());
         _dst.create(src.size(), CV_32FC3);
@@ -83,6 +85,7 @@ public:
 
     void write(FileStorage& fs) const
     {
+        writeFormat(fs);
         fs << "name" << name
            << "gamma" << gamma;
     }
@@ -117,6 +120,8 @@ public:
 
     void process(InputArray _src, OutputArray _dst)
     {
+        CV_INSTRUMENT_REGION()
+
         Mat src = _src.getMat();
         CV_Assert(!src.empty());
         _dst.create(src.size(), CV_32FC3);
@@ -161,6 +166,7 @@ public:
 
     void write(FileStorage& fs) const
     {
+        writeFormat(fs);
         fs << "name" << name
            << "gamma" << gamma
            << "bias" << bias
@@ -201,6 +207,8 @@ public:
 
     void process(InputArray _src, OutputArray _dst)
     {
+        CV_INSTRUMENT_REGION()
+
         Mat src = _src.getMat();
         CV_Assert(!src.empty());
         _dst.create(src.size(), CV_32FC3);
@@ -242,6 +250,7 @@ public:
 
     void write(FileStorage& fs) const
     {
+        writeFormat(fs);
         fs << "name" << name
            << "gamma" << gamma
            << "contrast" << contrast
@@ -285,6 +294,8 @@ public:
 
     void process(InputArray _src, OutputArray _dst)
     {
+        CV_INSTRUMENT_REGION()
+
         Mat src = _src.getMat();
         CV_Assert(!src.empty());
         _dst.create(src.size(), CV_32FC3);
@@ -339,6 +350,7 @@ public:
 
     void write(FileStorage& fs) const
     {
+        writeFormat(fs);
         fs << "name" << name
            << "gamma" << gamma
            << "intensity" << intensity
@@ -379,6 +391,8 @@ public:
 
     void process(InputArray _src, OutputArray _dst)
     {
+        CV_INSTRUMENT_REGION()
+
         Mat src = _src.getMat();
         CV_Assert(!src.empty());
         _dst.create(src.size(), CV_32FC3);
@@ -446,6 +460,7 @@ public:
 
     void write(FileStorage& fs) const
     {
+        writeFormat(fs);
         fs << "name" << name
            << "gamma" << gamma
            << "scale" << scale
diff --git a/modules/photo/test/ocl/test_denoising.cpp b/modules/photo/test/ocl/test_denoising.cpp
index f749564..44f506b 100644
--- a/modules/photo/test/ocl/test_denoising.cpp
+++ b/modules/photo/test/ocl/test_denoising.cpp
@@ -37,7 +37,7 @@ PARAM_TEST_CASE(FastNlMeansDenoisingTestBase, Channels, int, bool, bool)
             h[i] = 3.0f + 0.5f*i;
     }
 
-    virtual void generateTestData()
+    void generateTestData()
     {
         const int type = CV_8UC(cn);
         Mat image;
diff --git a/modules/photo/test/test_decolor.cpp b/modules/photo/test/test_decolor.cpp
index 259f7af..d7b620c 100644
--- a/modules/photo/test/test_decolor.cpp
+++ b/modules/photo/test/test_decolor.cpp
@@ -47,8 +47,6 @@
 using namespace cv;
 using namespace std;
 
-static const double numerical_precision = 10.;
-
 TEST(Photo_Decolor, regression)
 {
         string folder = string(cvtest::TS::ptr()->get_data_path()) + "decolor/";
@@ -57,16 +55,16 @@ TEST(Photo_Decolor, regression)
         Mat original = imread(original_path, IMREAD_COLOR);
 
         ASSERT_FALSE(original.empty()) << "Could not load input image " << original_path;
-        ASSERT_FALSE(original.channels()!=3) << "Load color input image " << original_path;
+        ASSERT_EQ(3, original.channels()) << "Load color input image " << original_path;
 
         Mat grayscale, color_boost;
         decolor(original, grayscale, color_boost);
 
         Mat reference_grayscale = imread(folder + "grayscale_reference.png", 0 /* == grayscale image*/);
-        double error_grayscale = cvtest::norm(reference_grayscale, grayscale, NORM_L1);
-        EXPECT_LE(error_grayscale, numerical_precision);
+        double gray_psnr = cvtest::PSNR(reference_grayscale, grayscale);
+        EXPECT_GT(gray_psnr, 60.0);
 
         Mat reference_boost = imread(folder + "boost_reference.png");
-        double error_boost = cvtest::norm(reference_boost, color_boost, NORM_L1);
-        EXPECT_LE(error_boost, numerical_precision);
+        double boost_psnr = cvtest::PSNR(reference_boost, color_boost);
+        EXPECT_GT(boost_psnr, 60.0);
 }
diff --git a/modules/python/common.cmake b/modules/python/common.cmake
index 29b8816..e014d0e 100644
--- a/modules/python/common.cmake
+++ b/modules/python/common.cmake
@@ -1,11 +1,15 @@
 # This file is included from a subdirectory
 set(PYTHON_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../")
 
+# try to use dynamic symbols linking with libpython.so
+set(OPENCV_FORCE_PYTHON_LIBS OFF CACHE BOOL "")
+string(REPLACE "-Wl,--no-undefined" "" CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS}")
+
 ocv_add_module(${MODULE_NAME} BINDINGS)
 
 ocv_module_include_directories(
-    "${PYTHON_INCLUDE_PATH}"
-    ${PYTHON_NUMPY_INCLUDE_DIRS}
+    "${${PYTHON}_INCLUDE_PATH}"
+    ${${PYTHON}_NUMPY_INCLUDE_DIRS}
     "${PYTHON_SOURCE_DIR}/src2"
     )
 
@@ -20,16 +24,20 @@ foreach(m ${OPENCV_MODULES_BUILD})
 endforeach()
 
 set(opencv_hdrs "")
+set(opencv_userdef_hdrs "")
 foreach(m ${OPENCV_PYTHON_MODULES})
   list(APPEND opencv_hdrs ${OPENCV_MODULE_${m}_HEADERS})
+  file(GLOB userdef_hdrs ${OPENCV_MODULE_${m}_LOCATION}/misc/python/pyopencv*.hpp)
+  list(APPEND opencv_userdef_hdrs ${userdef_hdrs})
 endforeach(m)
 
 # header blacklist
-ocv_list_filterout(opencv_hdrs ".h$")
-ocv_list_filterout(opencv_hdrs "cuda")
-ocv_list_filterout(opencv_hdrs "cudev")
-ocv_list_filterout(opencv_hdrs "/hal/")
-ocv_list_filterout(opencv_hdrs "detection_based_tracker.hpp") # Conditional compilation
+ocv_list_filterout(opencv_hdrs "modules/.*.h$")
+ocv_list_filterout(opencv_hdrs "modules/core/.*/cuda")
+ocv_list_filterout(opencv_hdrs "modules/cuda.*")
+ocv_list_filterout(opencv_hdrs "modules/cudev")
+ocv_list_filterout(opencv_hdrs "modules/core/.*/hal/")
+ocv_list_filterout(opencv_hdrs "modules/.*/detection_based_tracker.hpp") # Conditional compilation
 
 set(cv2_generated_hdrs
     "${CMAKE_CURRENT_BINARY_DIR}/pyopencv_generated_include.h"
@@ -41,32 +49,46 @@ set(cv2_generated_hdrs
 file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/headers.txt" "${opencv_hdrs}")
 add_custom_command(
    OUTPUT ${cv2_generated_hdrs}
-   COMMAND ${PYTHON_EXECUTABLE} "${PYTHON_SOURCE_DIR}/src2/gen2.py" ${CMAKE_CURRENT_BINARY_DIR} "${CMAKE_CURRENT_BINARY_DIR}/headers.txt"
+   COMMAND ${PYTHON_DEFAULT_EXECUTABLE} "${PYTHON_SOURCE_DIR}/src2/gen2.py" ${CMAKE_CURRENT_BINARY_DIR} "${CMAKE_CURRENT_BINARY_DIR}/headers.txt" "${PYTHON}"
    DEPENDS ${PYTHON_SOURCE_DIR}/src2/gen2.py
    DEPENDS ${PYTHON_SOURCE_DIR}/src2/hdr_parser.py
    DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/headers.txt
    DEPENDS ${opencv_hdrs})
 
-ocv_add_library(${the_module} MODULE ${PYTHON_SOURCE_DIR}/src2/cv2.cpp ${cv2_generated_hdrs})
+set(cv2_custom_hdr "${CMAKE_CURRENT_BINARY_DIR}/pyopencv_custom_headers.h")
+file(WRITE ${cv2_custom_hdr} "//user-defined headers\n")
+foreach(uh ${opencv_userdef_hdrs})
+    file(APPEND ${cv2_custom_hdr} "#include \"${uh}\"\n")
+endforeach(uh)
 
-if(PYTHON_DEBUG_LIBRARIES AND NOT PYTHON_LIBRARIES MATCHES "optimized.*debug")
-  ocv_target_link_libraries(${the_module} debug ${PYTHON_DEBUG_LIBRARIES} optimized ${PYTHON_LIBRARIES})
-else()
-  if(APPLE)
-    set_target_properties(${the_module} PROPERTIES LINK_FLAGS "-undefined dynamic_lookup")
+ocv_add_library(${the_module} MODULE ${PYTHON_SOURCE_DIR}/src2/cv2.cpp ${cv2_generated_hdrs} ${opencv_userdef_hdrs} ${cv2_custom_hdr})
+
+if(APPLE)
+  set_target_properties(${the_module} PROPERTIES LINK_FLAGS "-undefined dynamic_lookup")
+elseif(WIN32 OR OPENCV_FORCE_PYTHON_LIBS)
+  if(${PYTHON}_DEBUG_LIBRARIES AND NOT ${PYTHON}_LIBRARIES MATCHES "optimized.*debug")
+    ocv_target_link_libraries(${the_module} debug ${${PYTHON}_DEBUG_LIBRARIES} optimized ${${PYTHON}_LIBRARIES})
   else()
-    ocv_target_link_libraries(${the_module} ${PYTHON_LIBRARIES})
+    ocv_target_link_libraries(${the_module} ${${PYTHON}_LIBRARIES})
   endif()
 endif()
 ocv_target_link_libraries(${the_module} ${OPENCV_MODULE_${the_module}_DEPS})
 
-execute_process(COMMAND ${PYTHON_EXECUTABLE} -c "import distutils.sysconfig; print(distutils.sysconfig.get_config_var('SO'))"
-                RESULT_VARIABLE PYTHON_CVPY_PROCESS
-                OUTPUT_VARIABLE CVPY_SUFFIX
-                OUTPUT_STRIP_TRAILING_WHITESPACE)
+if(DEFINED ${PYTHON}_CVPY_SUFFIX)
+  set(CVPY_SUFFIX "${${PYTHON}_CVPY_SUFFIX}")
+else()
+  execute_process(COMMAND ${${PYTHON}_EXECUTABLE} -c "import distutils.sysconfig; print(distutils.sysconfig.get_config_var('SO'))"
+                  RESULT_VARIABLE PYTHON_CVPY_PROCESS
+                  OUTPUT_VARIABLE CVPY_SUFFIX
+                  OUTPUT_STRIP_TRAILING_WHITESPACE)
+  if(NOT PYTHON_CVPY_PROCESS EQUAL 0)
+    set(CVPY_SUFFIX ".so")
+  endif()
+endif()
 
 set_target_properties(${the_module} PROPERTIES
                       LIBRARY_OUTPUT_DIRECTORY  "${LIBRARY_OUTPUT_PATH}/${MODULE_INSTALL_SUBDIR}"
+                      ARCHIVE_OUTPUT_NAME ${the_module}  # prevent name conflict for python2/3 outputs
                       PREFIX ""
                       OUTPUT_NAME cv2
                       SUFFIX ${CVPY_SUFFIX})
@@ -90,11 +112,13 @@ if(MSVC AND NOT ENABLE_NOISY_WARNINGS)
   string(REPLACE "/W4" "/W3" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
 endif()
 
+ocv_warnings_disable(CMAKE_CXX_FLAGS -Woverloaded-virtual -Wunused-private-field)
+
 if(MSVC AND NOT BUILD_SHARED_LIBS)
   set_target_properties(${the_module} PROPERTIES LINK_FLAGS "/NODEFAULTLIB:atlthunk.lib /NODEFAULTLIB:atlsd.lib /DEBUG")
 endif()
 
-if(MSVC AND NOT PYTHON_DEBUG_LIBRARIES)
+if(MSVC AND NOT ${PYTHON}_DEBUG_LIBRARIES)
   set(PYTHON_INSTALL_CONFIGURATIONS CONFIGURATIONS Release)
 else()
   set(PYTHON_INSTALL_CONFIGURATIONS "")
@@ -103,29 +127,34 @@ endif()
 if(WIN32)
   set(PYTHON_INSTALL_ARCHIVE "")
 else()
-  set(PYTHON_INSTALL_ARCHIVE ARCHIVE DESTINATION ${PYTHON_PACKAGES_PATH} COMPONENT python)
+  set(PYTHON_INSTALL_ARCHIVE ARCHIVE DESTINATION ${${PYTHON}_PACKAGES_PATH} COMPONENT python)
 endif()
 
-if(NOT INSTALL_CREATE_DISTRIB)
-  install(TARGETS ${the_module} OPTIONAL
-          ${PYTHON_INSTALL_CONFIGURATIONS}
-          RUNTIME DESTINATION ${PYTHON_PACKAGES_PATH} COMPONENT python
-          LIBRARY DESTINATION ${PYTHON_PACKAGES_PATH} COMPONENT python
-          ${PYTHON_INSTALL_ARCHIVE}
-          )
-else()
-  if(DEFINED PYTHON_VERSION_MAJOR)
-    set(__ver "${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR}")
+if(NOT INSTALL_CREATE_DISTRIB AND DEFINED ${PYTHON}_PACKAGES_PATH)
+  set(__dst "${${PYTHON}_PACKAGES_PATH}")
+endif()
+if(NOT __dst)
+  if(DEFINED ${PYTHON}_VERSION_MAJOR)
+    set(__ver "${${PYTHON}_VERSION_MAJOR}.${${PYTHON}_VERSION_MINOR}")
+  elseif(DEFINED ${PYTHON}_VERSION_STRING)
+    set(__ver "${${PYTHON}_VERSION_STRING}")
   else()
     set(__ver "unknown")
   endif()
-  install(TARGETS ${the_module}
-          CONFIGURATIONS Release
-          RUNTIME DESTINATION python/${__ver}/${OpenCV_ARCH} COMPONENT python
-          LIBRARY DESTINATION python/${__ver}/${OpenCV_ARCH} COMPONENT python
-          )
+  if(INSTALL_CREATE_DISTRIB)
+    set(__dst "python/${__ver}/${OpenCV_ARCH}")
+  else()
+    set(__dst "python/${__ver}")
+  endif()
 endif()
 
+install(TARGETS ${the_module}
+        ${PYTHON_INSTALL_CONFIGURATIONS}
+        RUNTIME DESTINATION "${__dst}" COMPONENT python
+        LIBRARY DESTINATION "${__dst}" COMPONENT python
+        ${PYTHON_INSTALL_ARCHIVE}
+        )
+
 unset(PYTHON_SRC_DIR)
 unset(PYTHON_CVPY_PROCESS)
 unset(CVPY_SUFFIX)
diff --git a/modules/python/python2/CMakeLists.txt b/modules/python/python2/CMakeLists.txt
index 158763e..37e20fe 100644
--- a/modules/python/python2/CMakeLists.txt
+++ b/modules/python/python2/CMakeLists.txt
@@ -1,4 +1,4 @@
-if(NOT PYTHON2LIBS_FOUND OR NOT PYTHON2_NUMPY_INCLUDE_DIRS)
+if(NOT PYTHON2_INCLUDE_PATH OR NOT PYTHON2_NUMPY_INCLUDE_DIRS)
   ocv_module_disable(python2)
 endif()
 
@@ -7,24 +7,9 @@ set(MODULE_NAME python2)
 # Buildbot requires Python 2 to be in root lib dir
 set(MODULE_INSTALL_SUBDIR "")
 
-set(PYTHON_INCLUDE_PATH ${PYTHON2_INCLUDE_PATH})
-set(PYTHON_NUMPY_INCLUDE_DIRS ${PYTHON2_NUMPY_INCLUDE_DIRS})
-set(PYTHON_EXECUTABLE ${PYTHON2_EXECUTABLE})
-set(PYTHON_DEBUG_LIBRARIES ${PYTHON2_DEBUG_LIBRARIES})
-set(PYTHON_LIBRARIES ${PYTHON2_LIBRARIES})
-set(PYTHON_PACKAGES_PATH ${PYTHON2_PACKAGES_PATH})
-set(PYTHON_VERSION_MAJOR ${PYTHON2_VERSION_MAJOR})
-set(PYTHON_VERSION_MINOR ${PYTHON2_VERSION_MINOR})
+set(PYTHON PYTHON2)
 
 include(../common.cmake)
 
 unset(MODULE_NAME)
 unset(MODULE_INSTALL_SUBDIR)
-unset(PYTHON_INCLUDE_PATH)
-unset(PYTHON_NUMPY_INCLUDE_DIRS)
-unset(PYTHON_EXECUTABLE)
-unset(PYTHON_DEBUG_LIBRARIES)
-unset(PYTHON_LIBRARIES)
-unset(PYTHON_PACKAGES_PATH)
-unset(PYTHON_VERSION_MAJOR)
-unset(PYTHON_VERSION_MINOR)
diff --git a/modules/python/python3/CMakeLists.txt b/modules/python/python3/CMakeLists.txt
index 4b6fe4f..da86ba5 100644
--- a/modules/python/python3/CMakeLists.txt
+++ b/modules/python/python3/CMakeLists.txt
@@ -1,4 +1,4 @@
-if(NOT PYTHON3LIBS_FOUND OR NOT PYTHON3_NUMPY_INCLUDE_DIRS)
+if(NOT PYTHON3_INCLUDE_PATH OR NOT PYTHON3_NUMPY_INCLUDE_DIRS)
   ocv_module_disable(python3)
 endif()
 
@@ -6,24 +6,9 @@ set(the_description "The python3 bindings")
 set(MODULE_NAME python3)
 set(MODULE_INSTALL_SUBDIR python3)
 
-set(PYTHON_INCLUDE_PATH ${PYTHON3_INCLUDE_PATH})
-set(PYTHON_NUMPY_INCLUDE_DIRS ${PYTHON3_NUMPY_INCLUDE_DIRS})
-set(PYTHON_EXECUTABLE ${PYTHON3_EXECUTABLE})
-set(PYTHON_DEBUG_LIBRARIES ${PYTHON3_DEBUG_LIBRARIES})
-set(PYTHON_LIBRARIES ${PYTHON3_LIBRARIES})
-set(PYTHON_PACKAGES_PATH ${PYTHON3_PACKAGES_PATH})
-set(PYTHON_VERSION_MAJOR ${PYTHON3_VERSION_MAJOR})
-set(PYTHON_VERSION_MINOR ${PYTHON3_VERSION_MINOR})
+set(PYTHON PYTHON3)
 
 include(../common.cmake)
 
 unset(MODULE_NAME)
 unset(MODULE_INSTALL_SUBDIR)
-unset(PYTHON_INCLUDE_PATH)
-unset(PYTHON_NUMPY_INCLUDE_DIRS)
-unset(PYTHON_EXECUTABLE)
-unset(PYTHON_DEBUG_LIBRARIES)
-unset(PYTHON_LIBRARIES)
-unset(PYTHON_PACKAGES_PATH)
-unset(PYTHON_VERSION_MAJOR)
-unset(PYTHON_VERSION_MINOR)
diff --git a/modules/python/src2/cv2.cpp b/modules/python/src2/cv2.cpp
index 9369f29..e69e933 100644
--- a/modules/python/src2/cv2.cpp
+++ b/modules/python/src2/cv2.cpp
@@ -101,6 +101,7 @@ typedef std::vector<Rect> vector_Rect;
 typedef std::vector<Rect2d> vector_Rect2d;
 typedef std::vector<KeyPoint> vector_KeyPoint;
 typedef std::vector<Mat> vector_Mat;
+typedef std::vector<UMat> vector_UMat;
 typedef std::vector<DMatch> vector_DMatch;
 typedef std::vector<String> vector_String;
 typedef std::vector<Scalar> vector_Scalar;
@@ -110,19 +111,7 @@ typedef std::vector<std::vector<Point> > vector_vector_Point;
 typedef std::vector<std::vector<Point2f> > vector_vector_Point2f;
 typedef std::vector<std::vector<Point3f> > vector_vector_Point3f;
 typedef std::vector<std::vector<DMatch> > vector_vector_DMatch;
-
-#ifdef HAVE_OPENCV_FEATURES2D
-typedef SimpleBlobDetector::Params SimpleBlobDetector_Params;
-#endif
-
-#ifdef HAVE_OPENCV_FLANN
-typedef cvflann::flann_distance_t cvflann_flann_distance_t;
-typedef cvflann::flann_algorithm_t cvflann_flann_algorithm_t;
-#endif
-
-#ifdef HAVE_OPENCV_STITCHING
-typedef Stitcher::Status Status;
-#endif
+typedef std::vector<std::vector<KeyPoint> > vector_vector_KeyPoint;
 
 static PyObject* failmsgp(const char *fmt, ...)
 {
@@ -422,6 +411,152 @@ PyObject* pyopencv_from(const Mat& m)
     return o;
 }
 
+
+typedef struct {
+    PyObject_HEAD
+    UMat* um;
+} cv2_UMatWrapperObject;
+
+// UMatWrapper init - takes one optional argument, that converts to Mat, that converts to UMat and stored inside.
+// If no argument given - empty UMat created.
+static int UMatWrapper_init(cv2_UMatWrapperObject *self, PyObject *args, PyObject *kwds)
+{
+    self->um = new UMat();
+
+    PyObject *np_mat = NULL;
+
+    static char *kwlist[] = {new char[3], NULL};
+    strcpy(kwlist[0], "mat");
+
+    if (! PyArg_ParseTupleAndKeywords(args, kwds, "|O", kwlist, &np_mat))
+        return -1;
+
+    if (np_mat) {
+        Mat m;
+        if (!pyopencv_to(np_mat, m, ArgInfo("UMatWrapper.np_mat", 0)))
+            return -1;
+
+        m.copyTo(*self->um);
+    }
+
+    return 0;
+}
+
+static void UMatWrapper_dealloc(cv2_UMatWrapperObject* self)
+{
+    delete self->um;
+#if PY_MAJOR_VERSION >= 3
+    Py_TYPE(self)->tp_free((PyObject*)self);
+#else
+    self->ob_type->tp_free((PyObject*)self);
+#endif
+}
+
+// UMatWrapper.get() - returns numpy array by transferring UMat data to Mat and than wrapping it to numpy array
+// (using numpy allocator - and so without unnecessary copy)
+static PyObject * UMatWrapper_get(cv2_UMatWrapperObject* self)
+{
+    Mat m;
+    m.allocator = &g_numpyAllocator;
+    self->um->copyTo(m);
+
+    return pyopencv_from(m);
+}
+
+static PyMethodDef UMatWrapper_methods[] = {
+        {"get", (PyCFunction)UMatWrapper_get, METH_NOARGS,
+                "Returns numpy array"
+        },
+        {NULL, NULL, 0, NULL}  /* Sentinel */
+};
+
+
+static PyTypeObject cv2_UMatWrapperType = {
+#if PY_MAJOR_VERSION >= 3
+        PyVarObject_HEAD_INIT(NULL, 0)
+#else
+        PyObject_HEAD_INIT(NULL)
+        0,                             /*ob_size*/
+#endif
+        "cv2.UMat",                    /* tp_name */
+        sizeof(cv2_UMatWrapperObject), /* tp_basicsize */
+        0,                             /* tp_itemsize */
+      (destructor)UMatWrapper_dealloc, /* tp_dealloc */
+        0,                             /* tp_print */
+        0,                             /* tp_getattr */
+        0,                             /* tp_setattr */
+        0,                             /* tp_reserved */
+        0,                             /* tp_repr */
+        0,                             /* tp_as_number */
+        0,                             /* tp_as_sequence */
+        0,                             /* tp_as_mapping */
+        0,                             /* tp_hash  */
+        0,                             /* tp_call */
+        0,                             /* tp_str */
+        0,                             /* tp_getattro */
+        0,                             /* tp_setattro */
+        0,                             /* tp_as_buffer */
+        Py_TPFLAGS_DEFAULT,            /* tp_flags */
+        "OpenCV 3 UMat wrapper. Used for T-API support.", /* tp_doc */
+        0,                             /* tp_traverse */
+        0,                             /* tp_clear */
+        0,                             /* tp_richcompare */
+        0,                             /* tp_weaklistoffset */
+        0,                             /* tp_iter */
+        0,                             /* tp_iternext */
+        UMatWrapper_methods,           /* tp_methods */
+        0,                             /* tp_members */
+        0,                             /* tp_getset */
+        0,                             /* tp_base */
+        0,                             /* tp_dict */
+        0,                             /* tp_descr_get */
+        0,                             /* tp_descr_set */
+        0,                             /* tp_dictoffset */
+        (initproc)UMatWrapper_init,    /* tp_init */
+        0,                             /* tp_alloc */
+        PyType_GenericNew,             /* tp_new */
+        0,                             /* tp_free */
+        0,                             /* tp_is_gc */
+        0,                             /* tp_bases */
+        0,                             /* tp_mro */
+        0,                             /* tp_cache */
+        0,                             /* tp_subclasses */
+        0,                             /* tp_weaklist */
+        0,                             /* tp_del */
+        0,                             /* tp_version_tag */
+#if PY_MAJOR_VERSION >= 3
+        0,                             /* tp_finalize */
+#endif
+};
+
+static bool pyopencv_to(PyObject* o, UMat& um, const ArgInfo info) {
+    if (o != NULL && PyObject_TypeCheck(o, &cv2_UMatWrapperType) ) {
+        um = *((cv2_UMatWrapperObject *) o)->um;
+        return true;
+    }
+
+    Mat m;
+    if (!pyopencv_to(o, m, info)) {
+        return false;
+    }
+
+    m.copyTo(um);
+    return true;
+}
+
+template<>
+bool pyopencv_to(PyObject* o, UMat& um, const char* name)
+{
+    return pyopencv_to(o, um, ArgInfo(name, 0));
+}
+
+template<>
+PyObject* pyopencv_from(const UMat& m) {
+    PyObject *o = PyObject_CallObject((PyObject *) &cv2_UMatWrapperType, NULL);
+    *((cv2_UMatWrapperObject *) o)->um = m;
+    return o;
+}
+
 template<>
 bool pyopencv_to(PyObject *o, Scalar& s, const char *name)
 {
@@ -469,14 +604,6 @@ PyObject* pyopencv_from(const bool& value)
     return PyBool_FromLong(value);
 }
 
-#ifdef HAVE_OPENCV_STITCHING
-template<>
-PyObject* pyopencv_from(const Status& value)
-{
-    return PyInt_FromLong(value);
-}
-#endif
-
 template<>
 bool pyopencv_to(PyObject* obj, bool& value, const char* name)
 {
@@ -512,20 +639,6 @@ PyObject* pyopencv_from(const int& value)
     return PyInt_FromLong(value);
 }
 
-#ifdef HAVE_OPENCV_FLANN
-template<>
-PyObject* pyopencv_from(const cvflann_flann_algorithm_t& value)
-{
-    return PyInt_FromLong(int(value));
-}
-
-template<>
-PyObject* pyopencv_from(const cvflann_flann_distance_t& value)
-{
-    return PyInt_FromLong(int(value));
-}
-#endif
-
 template<>
 bool pyopencv_to(PyObject* obj, int& value, const char* name)
 {
@@ -967,6 +1080,24 @@ template<typename _Tp> static inline PyObject* pyopencv_from_generic_vec(const s
     return seq;
 }
 
+template<>
+PyObject* pyopencv_from(const std::pair<int, double>& src)
+{
+    return Py_BuildValue("(id)", src.first, src.second);
+}
+
+template<typename _Tp, typename _Tr> struct pyopencvVecConverter<std::pair<_Tp, _Tr> >
+{
+    static bool to(PyObject* obj, std::vector<std::pair<_Tp, _Tr> >& value, const ArgInfo info)
+    {
+        return pyopencv_to_generic_vec(obj, value, info);
+    }
+
+    static PyObject* from(const std::vector<std::pair<_Tp, _Tr> >& value)
+    {
+        return pyopencv_from_generic_vec(value);
+    }
+};
 
 template<typename _Tp> struct pyopencvVecConverter<std::vector<_Tp> >
 {
@@ -1076,62 +1207,6 @@ PyObject* pyopencv_from(const Moments& m)
                          "nu30", m.nu30, "nu21", m.nu21, "nu12", m.nu12, "nu03", m.nu03);
 }
 
-#ifdef HAVE_OPENCV_FLANN
-template<>
-bool pyopencv_to(PyObject *o, cv::flann::IndexParams& p, const char *name)
-{
-    (void)name;
-    bool ok = true;
-    PyObject* key = NULL;
-    PyObject* item = NULL;
-    Py_ssize_t pos = 0;
-
-    if(PyDict_Check(o)) {
-        while(PyDict_Next(o, &pos, &key, &item)) {
-            if( !PyString_Check(key) ) {
-                ok = false;
-                break;
-            }
-
-            String k = PyString_AsString(key);
-            if( PyString_Check(item) )
-            {
-                const char* value = PyString_AsString(item);
-                p.setString(k, value);
-            }
-            else if( !!PyBool_Check(item) )
-                p.setBool(k, item == Py_True);
-            else if( PyInt_Check(item) )
-            {
-                int value = (int)PyInt_AsLong(item);
-                if( strcmp(k.c_str(), "algorithm") == 0 )
-                    p.setAlgorithm(value);
-                else
-                    p.setInt(k, value);
-            }
-            else if( PyFloat_Check(item) )
-            {
-                double value = PyFloat_AsDouble(item);
-                p.setDouble(k, value);
-            }
-            else
-            {
-                ok = false;
-                break;
-            }
-        }
-    }
-
-    return ok && !PyErr_Occurred();
-}
-
-template<>
-bool pyopencv_to(PyObject* obj, cv::flann::SearchParams & value, const char * name)
-{
-    return pyopencv_to<cv::flann::IndexParams>(obj, value, name);
-}
-#endif
-
 template <typename T>
 bool pyopencv_to(PyObject *o, Ptr<T>& p, const char *name)
 {
@@ -1139,45 +1214,7 @@ bool pyopencv_to(PyObject *o, Ptr<T>& p, const char *name)
     return pyopencv_to(o, *p, name);
 }
 
-#ifdef HAVE_OPENCV_FLANN
-template<>
-bool pyopencv_to(PyObject *o, cvflann::flann_distance_t& dist, const char *name)
-{
-    int d = (int)dist;
-    bool ok = pyopencv_to(o, d, name);
-    dist = (cvflann::flann_distance_t)d;
-    return ok;
-}
-#endif
-
-
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// TODO: REMOVE used only by ml wrapper
-
-template<>
-bool pyopencv_to(PyObject *obj, CvTermCriteria& dst, const char *name)
-{
-    (void)name;
-    if(!obj)
-        return true;
-    return PyArg_ParseTuple(obj, "iid", &dst.type, &dst.max_iter, &dst.epsilon) > 0;
-}
-
-template<>
-bool pyopencv_to(PyObject* obj, CvSlice& r, const char* name)
-{
-    (void)name;
-    if(!obj || obj == Py_None)
-        return true;
-    if(PyObject_Size(obj) == 0)
-    {
-        r = CV_WHOLE_SEQ;
-        return true;
-    }
-    return PyArg_ParseTuple(obj, "ii", &r.start_index, &r.end_index) > 0;
-}
-
-////////////////////////////////////////////////////////////////////////////////////////////////////
+#include "pyopencv_custom_headers.h"
 
 static void OnMouse(int event, int x, int y, int flags, void* param)
 {
@@ -1250,6 +1287,52 @@ static PyObject *pycvCreateTrackbar(PyObject*, PyObject *args)
     ERRWRAP2(createTrackbar(trackbar_name, window_name, value, count, OnChange, Py_BuildValue("OO", on_change, Py_None)));
     Py_RETURN_NONE;
 }
+
+static void OnButtonChange(int state, void *param)
+{
+    PyGILState_STATE gstate;
+    gstate = PyGILState_Ensure();
+
+    PyObject *o = (PyObject*)param;
+    PyObject *args;
+    if(PyTuple_GetItem(o, 1) != NULL)
+    {
+        args = Py_BuildValue("(iO)", state, PyTuple_GetItem(o,1));
+    }
+    else
+    {
+        args = Py_BuildValue("(i)", state);
+    }
+
+    PyObject *r = PyObject_Call(PyTuple_GetItem(o, 0), args, NULL);
+    if (r == NULL)
+        PyErr_Print();
+    Py_DECREF(args);
+    PyGILState_Release(gstate);
+}
+
+static PyObject *pycvCreateButton(PyObject*, PyObject *args, PyObject *kw)
+{
+    const char* keywords[] = {"buttonName", "onChange", "userData", "buttonType", "initialButtonState", NULL};
+    PyObject *on_change;
+    PyObject *userdata = NULL;
+    char* button_name;
+    int button_type = 0;
+    bool initial_button_state = false;
+
+    if (!PyArg_ParseTupleAndKeywords(args, kw, "sO|Oii", (char**)keywords, &button_name, &on_change, &userdata, &button_type, &initial_button_state))
+        return NULL;
+    if (!PyCallable_Check(on_change)) {
+        PyErr_SetString(PyExc_TypeError, "onChange must be callable");
+        return NULL;
+    }
+    if (userdata == NULL) {
+        userdata = Py_None;
+    }
+
+    ERRWRAP2(createButton(button_name, OnButtonChange, Py_BuildValue("OO", on_change, userdata), button_type, initial_button_state));
+    Py_RETURN_NONE;
+}
 #endif
 
 ///////////////////////////////////////////////////////////////////////////////////////
@@ -1282,6 +1365,7 @@ static int convert_to_char(PyObject *o, char *dst, const char *name = "no_name")
 static PyMethodDef special_methods[] = {
 #ifdef HAVE_OPENCV_HIGHGUI
   {"createTrackbar", pycvCreateTrackbar, METH_VARARGS, "createTrackbar(trackbarName, windowName, value, count, onChange) -> None"},
+  {"createButton", (PyCFunction)pycvCreateButton, METH_VARARGS | METH_KEYWORDS, "createButton(buttonName, onChange [, userData, buttonType, initialButtonState]) -> None"},
   {"setMouseCallback", (PyCFunction)pycvSetMouseCallback, METH_VARARGS | METH_KEYWORDS, "setMouseCallback(windowName, onMouse [, param]) -> None"},
 #endif
   {NULL, NULL},
@@ -1385,6 +1469,23 @@ void initcv2()
   opencv_error = PyErr_NewException((char*)MODULESTR".error", NULL, NULL);
   PyDict_SetItemString(d, "error", opencv_error);
 
+//Registering UMatWrapper python class in cv2 module:
+  if (PyType_Ready(&cv2_UMatWrapperType) < 0)
+#if PY_MAJOR_VERSION >= 3
+    return NULL;
+#else
+    return;
+#endif
+
+#if PY_MAJOR_VERSION >= 3
+  Py_INCREF(&cv2_UMatWrapperType);
+#else
+  // Unrolled Py_INCREF(&cv2_UMatWrapperType) without (PyObject*) cast
+  // due to "warning: dereferencing type-punned pointer will break strict-aliasing rules"
+  _Py_INC_REFTOTAL _Py_REF_DEBUG_COMMA (&cv2_UMatWrapperType)->ob_refcnt++;
+#endif
+  PyModule_AddObject(m, "UMat", (PyObject *)&cv2_UMatWrapperType);
+
 #define PUBLISH(I) PyDict_SetItemString(d, #I, PyInt_FromLong(I))
 //#define PUBLISHU(I) PyDict_SetItemString(d, #I, PyLong_FromUnsignedLong(I))
 #define PUBLISH2(I, value) PyDict_SetItemString(d, #I, PyLong_FromLong(value))
diff --git a/modules/python/src2/gen2.py b/modules/python/src2/gen2.py
index 20c5c81..888fb40 100755
--- a/modules/python/src2/gen2.py
+++ b/modules/python/src2/gen2.py
@@ -30,7 +30,7 @@ gen_template_call_constructor = Template("""self->v.reset(new ${cname}${args})""
 gen_template_simple_call_constructor_prelude = Template("""self = PyObject_NEW(pyopencv_${name}_t, &pyopencv_${name}_Type);
         if(self) """)
 
-gen_template_simple_call_constructor = Template("""self->v = ${cname}${args}""")
+gen_template_simple_call_constructor = Template("""new (&(self->v)) ${cname}${args}""")
 
 gen_template_parse_args = Template("""const char* keywords[] = { $kw_list, NULL };
     if( PyArg_ParseTupleAndKeywords(args, kw, "$fmtspec", (char**)keywords, $parse_arglist)$code_cvt )""")
@@ -44,6 +44,14 @@ gen_template_func_body = Template("""$code_decl
 """)
 
 py_major_version = sys.version_info[0]
+if __name__ == "__main__":
+    if len(sys.argv) > 3:
+        if sys.argv[3] == 'PYTHON3':
+            py_major_version = 3
+        elif sys.argv[3] == 'PYTHON2':
+            py_major_version = 2
+        else:
+            raise Exception('Incorrect argument: expected PYTHON2 or PYTHON3, received: ' + sys.argv[3])
 if py_major_version >= 3:
     head_init_str = "PyVarObject_HEAD_INIT(&PyType_Type, 0)"
 else:
@@ -66,13 +74,14 @@ static PyTypeObject pyopencv_${name}_Type =
 
 static void pyopencv_${name}_dealloc(PyObject* self)
 {
+    ((pyopencv_${name}_t*)self)->v.${cname}::~${sname}();
     PyObject_Del(self);
 }
 
 template<> PyObject* pyopencv_from(const ${cname}& r)
 {
     pyopencv_${name}_t *m = PyObject_NEW(pyopencv_${name}_t, &pyopencv_${name}_Type);
-    m->v = r;
+    new (&m->v) ${cname}(r); //Copy constructor
     return (PyObject*)m;
 }
 
@@ -228,6 +237,7 @@ gen_template_rw_prop_init = Template("""
 
 simple_argtype_mapping = {
     "bool": ("bool", "b", "0"),
+    "size_t": ("size_t", "I", "0"),
     "int": ("int", "i", "0"),
     "float": ("float", "f", "0.f"),
     "double": ("double", "d", "0"),
@@ -249,6 +259,7 @@ class ClassInfo(object):
     def __init__(self, name, decl=None):
         self.cname = name.replace(".", "::")
         self.name = self.wname = normalize_class_name(name)
+        self.sname = name[name.rfind('.') + 1:]
         self.ismap = False
         self.issimple = False
         self.isalgorithm = False
@@ -381,7 +392,8 @@ class ArgInfo(object):
         self.py_outputarg = False
 
     def isbig(self):
-        return self.tp == "Mat" or self.tp == "vector_Mat"# or self.tp.startswith("vector")
+        return self.tp == "Mat" or self.tp == "vector_Mat"\
+               or self.tp == "UMat" or self.tp == "vector_UMat" # or self.tp.startswith("vector")
 
     def crepr(self):
         return "ArgInfo(\"%s\", %d)" % (self.name, self.outputarg)
@@ -623,6 +635,10 @@ class FuncInfo(object):
                 defval = a.defval
                 if not defval:
                     defval = amapping[2]
+                else:
+                    if "UMat" in tp:
+                        if "Mat" in defval and "UMat" not in defval:
+                            defval = defval.replace("Mat", "UMat")
                 # "tp arg = tp();" is equivalent to "tp arg;" in the case of complex types
                 if defval == tp + "()" and amapping[1] == "O":
                     defval = ""
@@ -845,7 +861,7 @@ class PythonWrapperGenerator(object):
 
     def gen(self, srcfiles, output_path):
         self.clear()
-        self.parser = hdr_parser.CppHeaderParser()
+        self.parser = hdr_parser.CppHeaderParser(generate_umat_decls=True)
 
         # step 1: scan the headers and build more descriptive maps of classes, consts, functions
         for hdr in srcfiles:
@@ -895,7 +911,7 @@ class PythonWrapperGenerator(object):
                     templ = gen_template_simple_type_decl
                 else:
                     templ = gen_template_type_decl
-                self.code_types.write(templ.substitute(name=name, wname=classinfo.wname, cname=classinfo.cname,
+                self.code_types.write(templ.substitute(name=name, wname=classinfo.wname, cname=classinfo.cname, sname=classinfo.sname,
                                       cname1=("cv::Algorithm" if classinfo.isalgorithm else classinfo.cname)))
 
         # register classes in the same order as they have been declared.
diff --git a/modules/python/src2/hdr_parser.py b/modules/python/src2/hdr_parser.py
index 7fc08c9..da90d80 100755
--- a/modules/python/src2/hdr_parser.py
+++ b/modules/python/src2/hdr_parser.py
@@ -17,7 +17,7 @@ opencv_hdr_list = [
 "../../objdetect/include/opencv2/objdetect.hpp",
 "../../imgcodecs/include/opencv2/imgcodecs.hpp",
 "../../videoio/include/opencv2/videoio.hpp",
-"../../highgui/include/opencv2/highgui.hpp"
+"../../highgui/include/opencv2/highgui.hpp",
 ]
 
 """
@@ -31,7 +31,9 @@ where the list of modifiers is yet another nested list of strings
 
 class CppHeaderParser(object):
 
-    def __init__(self):
+    def __init__(self, generate_umat_decls=False):
+        self._generate_umat_decls = generate_umat_decls
+
         self.BLOCK_TYPE = 0
         self.BLOCK_NAME = 1
         self.PROCESS_FLAG = 2
@@ -248,7 +250,7 @@ class CppHeaderParser(object):
             l = l[:npos] + l[npos3+1:]
 
         l = self.batch_replace(l, [("CV_EXPORTS_W", ""), ("CV_EXPORTS", ""), ("public virtual ", " "), ("public ", " "), ("::", ".")]).strip()
-        ll = re.split(r'\s*[,:]?\s*', l)
+        ll = re.split(r'\s+|\s*[,:]\s*', l)
         ll = [le for le in ll if le]
         classname = ll[1]
         bases = ll[2:]
@@ -368,7 +370,7 @@ class CppHeaderParser(object):
             print(decl_str)
         return decl
 
-    def parse_func_decl(self, decl_str):
+    def parse_func_decl(self, decl_str, use_umat=False):
         """
         Parses the function or method declaration in the form:
         [([CV_EXPORTS] <rettype>) | CVAPI(rettype)]
@@ -537,28 +539,34 @@ class CppHeaderParser(object):
                         a = a[:eqpos].strip()
                     arg_type, arg_name, modlist, argno = self.parse_arg(a, argno)
                     if self.wrap_mode:
+                        mat = "UMat" if use_umat else "Mat"
+
+                        # TODO: Vectors should contain UMat, but this is not very easy to support and not very needed
+                        vector_mat = "vector_{}".format("Mat")
+                        vector_mat_template = "vector<{}>".format("Mat")
+
                         if arg_type == "InputArray":
-                            arg_type = "Mat"
+                            arg_type = mat
                         elif arg_type == "InputOutputArray":
-                            arg_type = "Mat"
+                            arg_type = mat
                             modlist.append("/IO")
                         elif arg_type == "OutputArray":
-                            arg_type = "Mat"
+                            arg_type = mat
                             modlist.append("/O")
                         elif arg_type == "InputArrayOfArrays":
-                            arg_type = "vector_Mat"
+                            arg_type = vector_mat
                         elif arg_type == "InputOutputArrayOfArrays":
-                            arg_type = "vector_Mat"
+                            arg_type = vector_mat
                             modlist.append("/IO")
                         elif arg_type == "OutputArrayOfArrays":
-                            arg_type = "vector_Mat"
+                            arg_type = vector_mat
                             modlist.append("/O")
-                        defval = self.batch_replace(defval, [("InputArrayOfArrays", "vector<Mat>"),
-                                                             ("InputOutputArrayOfArrays", "vector<Mat>"),
-                                                             ("OutputArrayOfArrays", "vector<Mat>"),
-                                                             ("InputArray", "Mat"),
-                                                             ("InputOutputArray", "Mat"),
-                                                             ("OutputArray", "Mat"),
+                        defval = self.batch_replace(defval, [("InputArrayOfArrays", vector_mat_template),
+                                                             ("InputOutputArrayOfArrays", vector_mat_template),
+                                                             ("OutputArrayOfArrays", vector_mat_template),
+                                                             ("InputArray", mat),
+                                                             ("InputOutputArray", mat),
+                                                             ("OutputArray", mat),
                                                              ("noArray", arg_type)]).strip()
                     args.append([arg_type, arg_name, defval, modlist])
                 npos = arg_start-1
@@ -604,7 +612,7 @@ class CppHeaderParser(object):
             n = "cv.Algorithm"
         return n
 
-    def parse_stmt(self, stmt, end_token):
+    def parse_stmt(self, stmt, end_token, use_umat=False):
         """
         parses the statement (ending with ';' or '}') or a block head (ending with '{')
 
@@ -696,7 +704,7 @@ class CppHeaderParser(object):
             # since we filtered off the other places where '(' can normally occur:
             #   - code blocks
             #   - function pointer typedef's
-            decl = self.parse_func_decl(stmt)
+            decl = self.parse_func_decl(stmt, use_umat=use_umat)
             # we return parse_flag == False to prevent the parser to look inside function/method bodies
             # (except for tracking the nested blocks)
             return stmt_type, "", False, decl
@@ -839,6 +847,15 @@ class CppHeaderParser(object):
                                 decls.append(d)
                         else:
                             decls.append(decl)
+
+                            if self._generate_umat_decls:
+                                # If function takes as one of arguments Mat or vector<Mat> - we want to create the
+                                # same declaration working with UMat (this is important for T-Api access)
+                                args = decl[3]
+                                has_mat = len(list(filter(lambda x: x[0] in {"Mat", "vector_Mat"}, args))) > 0
+                                if has_mat:
+                                    _, _, _, umat_decl = self.parse_stmt(stmt, token, use_umat=True)
+                                    decls.append(umat_decl)
                     if stmt_type == "namespace":
                         chunks = [block[1] for block in self.block_stack if block[0] == 'namespace'] + [name]
                         self.namespaces.add('.'.join(chunks))
@@ -878,7 +895,7 @@ class CppHeaderParser(object):
                     print()
 
 if __name__ == '__main__':
-    parser = CppHeaderParser()
+    parser = CppHeaderParser(generate_umat_decls=True)
     decls = []
     for hname in opencv_hdr_list:
         decls += parser.parse(hname)
diff --git a/modules/python/test/calchist.py b/modules/python/test/calchist.py
deleted file mode 100755
index dba6796..0000000
--- a/modules/python/test/calchist.py
+++ /dev/null
@@ -1,53 +0,0 @@
-#!/usr/bin/env python
-
-# Calculating and displaying 2D Hue-Saturation histogram of a color image
-import sys
-import cv2.cv as cv
-
-def hs_histogram(src):
-    # Convert to HSV
-    hsv = cv.CreateImage(cv.GetSize(src), 8, 3)
-    cv.CvtColor(src, hsv, cv.CV_BGR2HSV)
-
-    # Extract the H and S planes
-    h_plane = cv.CreateMat(src.rows, src.cols, cv.CV_8UC1)
-    s_plane = cv.CreateMat(src.rows, src.cols, cv.CV_8UC1)
-    cv.Split(hsv, h_plane, s_plane, None, None)
-    planes = [h_plane, s_plane]
-
-    h_bins = 30
-    s_bins = 32
-    hist_size = [h_bins, s_bins]
-    # hue varies from 0 (~0 deg red) to 180 (~360 deg red again */
-    h_ranges = [0, 180]
-    # saturation varies from 0 (black-gray-white) to
-    # 255 (pure spectrum color)
-    s_ranges = [0, 255]
-    ranges = [h_ranges, s_ranges]
-    scale = 10
-    hist = cv.CreateHist([h_bins, s_bins], cv.CV_HIST_ARRAY, ranges, 1)
-    cv.CalcHist([cv.GetImage(i) for i in planes], hist)
-    (_, max_value, _, _) = cv.GetMinMaxHistValue(hist)
-
-    hist_img = cv.CreateImage((h_bins*scale, s_bins*scale), 8, 3)
-
-    for h in range(h_bins):
-        for s in range(s_bins):
-            bin_val = cv.QueryHistValue_2D(hist, h, s)
-            intensity = cv.Round(bin_val * 255 / max_value)
-            cv.Rectangle(hist_img,
-                         (h*scale, s*scale),
-                         ((h+1)*scale - 1, (s+1)*scale - 1),
-                         cv.RGB(intensity, intensity, intensity),
-                         cv.CV_FILLED)
-    return hist_img
-
-if __name__ == '__main__':
-    src = cv.LoadImageM(sys.argv[1])
-    cv.NamedWindow("Source", 1)
-    cv.ShowImage("Source", src)
-
-    cv.NamedWindow("H-S Histogram", 1)
-    cv.ShowImage("H-S Histogram", hs_histogram(src))
-
-    cv.WaitKey(0)
diff --git a/modules/python/test/camera_calibration.py b/modules/python/test/camera_calibration.py
deleted file mode 100755
index 8ffc5b1..0000000
--- a/modules/python/test/camera_calibration.py
+++ /dev/null
@@ -1,360 +0,0 @@
-#!/usr/bin/env python
-
-import sys
-import math
-import time
-import random
-
-import numpy
-import transformations
-import cv2.cv as cv
-
-def clamp(a, x, b):
-    return numpy.maximum(a, numpy.minimum(x, b))
-
-def norm(v):
-    mag = numpy.sqrt(sum([e * e for e in v]))
-    return v / mag
-
-class Vec3:
-    def __init__(self, x, y, z):
-        self.v = (x, y, z)
-    def x(self):
-        return self.v[0]
-    def y(self):
-        return self.v[1]
-    def z(self):
-        return self.v[2]
-    def __repr__(self):
-        return "<Vec3 (%s,%s,%s)>" % tuple([repr(c) for c in self.v])
-    def __add__(self, other):
-        return Vec3(*[self.v[i] + other.v[i] for i in range(3)])
-    def __sub__(self, other):
-        return Vec3(*[self.v[i] - other.v[i] for i in range(3)])
-    def __mul__(self, other):
-        if isinstance(other, Vec3):
-            return Vec3(*[self.v[i] * other.v[i] for i in range(3)])
-        else:
-            return Vec3(*[self.v[i] * other for i in range(3)])
-    def mag2(self):
-        return sum([e * e for e in self.v])
-    def __abs__(self):
-        return numpy.sqrt(sum([e * e for e in self.v]))
-    def norm(self):
-        return self * (1.0 / abs(self))
-    def dot(self, other):
-        return sum([self.v[i] * other.v[i] for i in range(3)])
-    def cross(self, other):
-        (ax, ay, az) = self.v
-        (bx, by, bz) = other.v
-        return Vec3(ay * bz - by * az, az * bx - bz * ax, ax * by - bx * ay)
-
-
-class Ray:
-
-    def __init__(self, o, d):
-        self.o = o
-        self.d = d
-
-    def project(self, d):
-        return self.o + self.d * d
-
-class Camera:
-
-    def __init__(self, F):
-        R = Vec3(1., 0., 0.)
-        U = Vec3(0, 1., 0)
-        self.center = Vec3(0, 0, 0)
-        self.pcenter = Vec3(0, 0, F)
-        self.up = U
-        self.right = R
-
-    def genray(self, x, y):
-        """ -1 <= y <= 1 """
-        r = numpy.sqrt(x * x + y * y)
-        if 0:
-            rprime = r + (0.17 * r**2)
-        else:
-            rprime = (10 * numpy.sqrt(17 * r + 25) - 50) / 17
-        print "scale", rprime / r
-        x *= rprime / r
-        y *= rprime / r
-        o = self.center
-        r = (self.pcenter + (self.right * x) + (self.up * y)) - o
-        return Ray(o, r.norm())
-
-class Sphere:
-
-    def __init__(self, center, radius):
-        self.center = center
-        self.radius = radius
-
-    def hit(self, r):
-        # a = mag2(r.d)
-        a = 1.
-        v = r.o - self.center
-        b = 2 * r.d.dot(v)
-        c = self.center.mag2() + r.o.mag2() + -2 * self.center.dot(r.o) - (self.radius ** 2)
-        det = (b * b) - (4 * c)
-        pred = 0 < det
-
-        sq = numpy.sqrt(abs(det))
-        h0 = (-b - sq) / (2)
-        h1 = (-b + sq) / (2)
-
-        h = numpy.minimum(h0, h1)
-
-        pred = pred & (h > 0)
-        normal = (r.project(h) - self.center) * (1.0 / self.radius)
-        return (pred, numpy.where(pred, h, 999999.), normal)
-
-def pt2plane(p, plane):
-    return p.dot(plane) * (1. / abs(plane))
-
-class Plane:
-
-    def __init__(self, p, n, right):
-        self.D = -pt2plane(p, n)
-        self.Pn = n
-        self.right = right
-        self.rightD = -pt2plane(p, right)
-        self.up = n.cross(right)
-        self.upD = -pt2plane(p, self.up)
-
-    def hit(self, r):
-        Vd = self.Pn.dot(r.d)
-        V0 = -(self.Pn.dot(r.o) + self.D)
-        h = V0 / Vd
-        pred = (0 <= h)
-
-        return (pred, numpy.where(pred, h, 999999.), self.Pn)
-
-    def localxy(self, loc):
-        x = (loc.dot(self.right) + self.rightD)
-        y = (loc.dot(self.up) + self.upD)
-        return (x, y)
-
-# lena = numpy.fromstring(cv.LoadImage("../samples/c/lena.jpg", 0).tostring(), numpy.uint8) / 255.0
-
-def texture(xy):
-    x,y = xy
-    xa = numpy.floor(x * 512)
-    ya = numpy.floor(y * 512)
-    a = (512 * ya) + xa
-    safe = (0 <= x) & (0 <= y) & (x < 1) & (y < 1)
-    if 0:
-        a = numpy.where(safe, a, 0).astype(numpy.int)
-        return numpy.where(safe, numpy.take(lena, a), 0.0)
-    else:
-        xi = numpy.floor(x * 11).astype(numpy.int)
-        yi = numpy.floor(y * 11).astype(numpy.int)
-        inside = (1 <= xi) & (xi < 10) & (2 <= yi) & (yi < 9)
-        checker = (xi & 1) ^ (yi & 1)
-        final = numpy.where(inside, checker, 1.0)
-        return numpy.where(safe, final, 0.5)
-
-def under(vv, m):
-    return Vec3(*(numpy.dot(m, vv.v + (1,))[:3]))
-
-class Renderer:
-
-    def __init__(self, w, h, oversample):
-        self.w = w
-        self.h = h
-
-        random.seed(1)
-        x = numpy.arange(self.w*self.h) % self.w
-        y = numpy.floor(numpy.arange(self.w*self.h) / self.w)
-        h2 = h / 2.0
-        w2 = w / 2.0
-        self.r = [ None ] * oversample
-        for o in range(oversample):
-            stoch_x = numpy.random.rand(self.w * self.h)
-            stoch_y = numpy.random.rand(self.w * self.h)
-            nx = (x + stoch_x - 0.5 - w2) / h2
-            ny = (y + stoch_y - 0.5 - h2) / h2
-            self.r[o] = cam.genray(nx, ny)
-
-        self.rnds = [random.random() for i in range(10)]
-
-    def frame(self, i):
-
-        rnds = self.rnds
-        roll = math.sin(i * .01 * rnds[0] + rnds[1])
-        pitch = math.sin(i * .01 * rnds[2] + rnds[3])
-        yaw = math.pi * math.sin(i * .01 * rnds[4] + rnds[5])
-        x = math.sin(i * 0.01 * rnds[6])
-        y = math.sin(i * 0.01 * rnds[7])
-
-        x,y,z = -0.5,0.5,1
-        roll,pitch,yaw = (0,0,0)
-
-        z = 4 + 3 * math.sin(i * 0.1 * rnds[8])
-        print z
-
-        rz = transformations.euler_matrix(roll, pitch, yaw)
-        p = Plane(Vec3(x, y, z), under(Vec3(0,0,-1), rz), under(Vec3(1, 0, 0), rz))
-
-        acc = 0
-        for r in self.r:
-            (pred, h, norm) = p.hit(r)
-            l = numpy.where(pred, texture(p.localxy(r.project(h))), 0.0)
-            acc += l
-        acc *= (1.0 / len(self.r))
-
-        # print "took", time.time() - st
-
-        img = cv.CreateMat(self.h, self.w, cv.CV_8UC1)
-        cv.SetData(img, (clamp(0, acc, 1) * 255).astype(numpy.uint8).tostring(), self.w)
-        return img
-
-#########################################################################
-
-num_x_ints = 8
-num_y_ints = 6
-num_pts = num_x_ints * num_y_ints
-
-def get_corners(mono, refine = False):
-    (ok, corners) = cv.FindChessboardCorners(mono, (num_x_ints, num_y_ints), cv.CV_CALIB_CB_ADAPTIVE_THRESH | cv.CV_CALIB_CB_NORMALIZE_IMAGE)
-    if refine and ok:
-        corners = cv.FindCornerSubPix(mono, corners, (5,5), (-1,-1), ( cv.CV_TERMCRIT_EPS+cv.CV_TERMCRIT_ITER, 30, 0.1 ))
-    return (ok, corners)
-
-def mk_object_points(nimages, squaresize = 1):
-    opts = cv.CreateMat(nimages * num_pts, 3, cv.CV_32FC1)
-    for i in range(nimages):
-        for j in range(num_pts):
-            opts[i * num_pts + j, 0] = (j / num_x_ints) * squaresize
-            opts[i * num_pts + j, 1] = (j % num_x_ints) * squaresize
-            opts[i * num_pts + j, 2] = 0
-    return opts
-
-def mk_image_points(goodcorners):
-    ipts = cv.CreateMat(len(goodcorners) * num_pts, 2, cv.CV_32FC1)
-    for (i, co) in enumerate(goodcorners):
-        for j in range(num_pts):
-            ipts[i * num_pts + j, 0] = co[j][0]
-            ipts[i * num_pts + j, 1] = co[j][1]
-    return ipts
-
-def mk_point_counts(nimages):
-    npts = cv.CreateMat(nimages, 1, cv.CV_32SC1)
-    for i in range(nimages):
-        npts[i, 0] = num_pts
-    return npts
-
-def cvmat_iterator(cvmat):
-    for i in range(cvmat.rows):
-        for j in range(cvmat.cols):
-            yield cvmat[i,j]
-
-cam = Camera(3.0)
-rend = Renderer(640, 480, 2)
-cv.NamedWindow("snap")
-
-#images = [rend.frame(i) for i in range(0, 2000, 400)]
-images = [rend.frame(i) for i in [1200]]
-
-if 0:
-    for i,img in enumerate(images):
-        cv.SaveImage("final/%06d.png" % i, img)
-
-size = cv.GetSize(images[0])
-corners = [get_corners(i) for i in images]
-
-goodcorners = [co for (im, (ok, co)) in zip(images, corners) if ok]
-
-def checkerboard_error(xformed):
-    def pt2line(a, b, c):
-        x0,y0 = a
-        x1,y1 = b
-        x2,y2 = c
-        return abs((x2 - x1) * (y1 - y0) - (x1 - x0) * (y2 - y1)) / math.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2)
-    errorsum = 0.
-    for im in xformed:
-        for row in range(6):
-            l0 = im[8 * row]
-            l1 = im[8 * row + 7]
-            for col in range(1, 7):
-                e = pt2line(im[8 * row + col], l0, l1)
-                #print "row", row, "e", e
-                errorsum += e
-
-    return errorsum
-
-if True:
-    from scipy.optimize import fmin
-
-    def xf(pt, poly):
-        x, y = pt
-        r = math.sqrt((x - 320) ** 2 + (y - 240) ** 2)
-        fr = poly(r) / r
-        return (320 + (x - 320) * fr, 240 + (y - 240) * fr)
-    def silly(p, goodcorners):
-    #    print "eval", p
-
-        d = 1.0 # - sum(p)
-        poly = numpy.poly1d(list(p) + [d, 0.])
-
-        xformed = [[xf(pt, poly) for pt in co] for co in goodcorners]
-
-        return checkerboard_error(xformed)
-
-    x0 = [ 0. ]
-    #print silly(x0, goodcorners)
-    print "initial error", silly(x0, goodcorners)
-    xopt = fmin(silly, x0, args=(goodcorners,))
-    print "xopt", xopt
-    print "final error", silly(xopt, goodcorners)
-
-    d = 1.0 # - sum(xopt)
-    poly = numpy.poly1d(list(xopt) + [d, 0.])
-    print "final polynomial"
-    print poly
-
-    for co in goodcorners:
-        scrib = cv.CreateMat(480, 640, cv.CV_8UC3)
-        cv.SetZero(scrib)
-        cv.DrawChessboardCorners(scrib, (num_x_ints, num_y_ints), [xf(pt, poly) for pt in co], True)
-        cv.ShowImage("snap", scrib)
-        cv.WaitKey()
-
-    sys.exit(0)
-
-for (i, (img, (ok, co))) in enumerate(zip(images, corners)):
-    scrib = cv.CreateMat(img.rows, img.cols, cv.CV_8UC3)
-    cv.CvtColor(img, scrib, cv.CV_GRAY2BGR)
-    if ok:
-        cv.DrawChessboardCorners(scrib, (num_x_ints, num_y_ints), co, True)
-    cv.ShowImage("snap", scrib)
-    cv.WaitKey()
-
-print len(goodcorners)
-ipts = mk_image_points(goodcorners)
-opts = mk_object_points(len(goodcorners), .1)
-npts = mk_point_counts(len(goodcorners))
-
-intrinsics = cv.CreateMat(3, 3, cv.CV_64FC1)
-distortion = cv.CreateMat(4, 1, cv.CV_64FC1)
-cv.SetZero(intrinsics)
-cv.SetZero(distortion)
-# focal lengths have 1/1 ratio
-intrinsics[0,0] = 1.0
-intrinsics[1,1] = 1.0
-cv.CalibrateCamera2(opts, ipts, npts,
-           cv.GetSize(images[0]),
-           intrinsics,
-           distortion,
-           cv.CreateMat(len(goodcorners), 3, cv.CV_32FC1),
-           cv.CreateMat(len(goodcorners), 3, cv.CV_32FC1),
-           flags = 0) # cv.CV_CALIB_ZERO_TANGENT_DIST)
-print "D =", list(cvmat_iterator(distortion))
-print "K =", list(cvmat_iterator(intrinsics))
-mapx = cv.CreateImage((640, 480), cv.IPL_DEPTH_32F, 1)
-mapy = cv.CreateImage((640, 480), cv.IPL_DEPTH_32F, 1)
-cv.InitUndistortMap(intrinsics, distortion, mapx, mapy)
-for img in images:
-    r = cv.CloneMat(img)
-    cv.Remap(img, r, mapx, mapy)
-    cv.ShowImage("snap", r)
-    cv.WaitKey()
diff --git a/modules/python/test/findstereocorrespondence.py b/modules/python/test/findstereocorrespondence.py
deleted file mode 100755
index 40a9603..0000000
--- a/modules/python/test/findstereocorrespondence.py
+++ /dev/null
@@ -1,25 +0,0 @@
-#!/usr/bin/env python
-
-import sys
-import cv2.cv as cv
-
-def findstereocorrespondence(image_left, image_right):
-    # image_left and image_right are the input 8-bit single-channel images
-    # from the left and the right cameras, respectively
-    (r, c) = (image_left.rows, image_left.cols)
-    disparity_left = cv.CreateMat(r, c, cv.CV_16S)
-    disparity_right = cv.CreateMat(r, c, cv.CV_16S)
-    state = cv.CreateStereoGCState(16, 2)
-    cv.FindStereoCorrespondenceGC(image_left, image_right, disparity_left, disparity_right, state, 0)
-    return (disparity_left, disparity_right)
-
-
-if __name__ == '__main__':
-
-    (l, r) = [cv.LoadImageM(f, cv.CV_LOAD_IMAGE_GRAYSCALE) for f in sys.argv[1:]]
-
-    (disparity_left, disparity_right) = findstereocorrespondence(l, r)
-
-    disparity_left_visual = cv.CreateMat(l.rows, l.cols, cv.CV_8U)
-    cv.ConvertScale(disparity_left, disparity_left_visual, -16)
-    cv.SaveImage("disparity.pgm", disparity_left_visual)
diff --git a/modules/python/test/goodfeatures.py b/modules/python/test/goodfeatures.py
deleted file mode 100755
index 5ccd5b4..0000000
--- a/modules/python/test/goodfeatures.py
+++ /dev/null
@@ -1,36 +0,0 @@
-#!/usr/bin/env python
-
-import cv2.cv as cv
-import unittest
-
-class TestGoodFeaturesToTrack(unittest.TestCase):
-    def test(self):
-        arr = cv.LoadImage("../samples/c/lena.jpg", 0)
-        original = cv.CloneImage(arr)
-        size = cv.GetSize(arr)
-        eig_image = cv.CreateImage(size, cv.IPL_DEPTH_32F, 1)
-        temp_image = cv.CreateImage(size, cv.IPL_DEPTH_32F, 1)
-        threshes = [ x / 100. for x in range(1,10) ]
-
-        results = dict([(t, cv.GoodFeaturesToTrack(arr, eig_image, temp_image, 20000, t, 2, useHarris = 1)) for t in threshes])
-
-        # Check that GoodFeaturesToTrack has not modified input image
-        self.assert_(arr.tostring() == original.tostring())
-
-        # Check for repeatability
-        for i in range(10):
-            results2 = dict([(t, cv.GoodFeaturesToTrack(arr, eig_image, temp_image, 20000, t, 2, useHarris = 1)) for t in threshes])
-            self.assert_(results == results2)
-
-        for t0,t1 in zip(threshes, threshes[1:]):
-             r0 = results[t0]
-             r1 = results[t1]
-
-             # Increasing thresh should make result list shorter
-             self.assert_(len(r0) > len(r1))
-
-             # Increasing thresh should monly truncate result list
-             self.assert_(r0[:len(r1)] == r1)
-
-if __name__ == '__main__':
-    unittest.main()
diff --git a/modules/python/test/leak1.py b/modules/python/test/leak1.py
deleted file mode 100755
index dbd6040..0000000
--- a/modules/python/test/leak1.py
+++ /dev/null
@@ -1,9 +0,0 @@
-#!/usr/bin/env python
-
-import cv2.cv as cv
-import numpy as np
-cv.NamedWindow('Leak')
-while 1:
-    leak = np.random.random((480, 640)) * 255
-    cv.ShowImage('Leak', leak.astype(np.uint8))
-    cv.WaitKey(10)
diff --git a/modules/python/test/leak2.py b/modules/python/test/leak2.py
deleted file mode 100755
index 5182264..0000000
--- a/modules/python/test/leak2.py
+++ /dev/null
@@ -1,12 +0,0 @@
-#!/usr/bin/env python
-
-import cv2.cv as cv
-import numpy as np
-import time
-
-while True:
-    for i in range(4000):
-        a = cv.CreateImage((1024,1024), cv.IPL_DEPTH_8U, 1)
-        b = cv.CreateMat(1024, 1024, cv.CV_8UC1)
-        c = cv.CreateMatND([1024,1024], cv.CV_8UC1)
-    print "pause..."
diff --git a/modules/python/test/leak3.py b/modules/python/test/leak3.py
deleted file mode 100755
index d763c40..0000000
--- a/modules/python/test/leak3.py
+++ /dev/null
@@ -1,8 +0,0 @@
-#!/usr/bin/env python
-
-import cv2.cv as cv
-import math
-import time
-
-while True:
-    h = cv.CreateHist([40], cv.CV_HIST_ARRAY, [[0,255]], 1)
diff --git a/modules/python/test/leak4.py b/modules/python/test/leak4.py
deleted file mode 100755
index 9e58640..0000000
--- a/modules/python/test/leak4.py
+++ /dev/null
@@ -1,11 +0,0 @@
-#!/usr/bin/env python
-
-import cv2.cv as cv
-import math
-import time
-
-N=50000
-print "leak4"
-while True:
-    seq=list((i*1., i*1.) for i in range(N))
-    cv.Moments(seq)
diff --git a/modules/python/test/precornerdetect.py b/modules/python/test/precornerdetect.py
deleted file mode 100755
index 97aa906..0000000
--- a/modules/python/test/precornerdetect.py
+++ /dev/null
@@ -1,16 +0,0 @@
-#!/usr/bin/env python
-
-import cv2.cv as cv
-
-def precornerdetect(image):
-    # assume that the image is floating-point
-    corners = cv.CloneMat(image)
-    cv.PreCornerDetect(image, corners, 3)
-
-    dilated_corners = cv.CloneMat(image)
-    cv.Dilate(corners, dilated_corners, None, 1)
-
-    corner_mask = cv.CreateMat(image.rows, image.cols, cv.CV_8UC1)
-    cv.Sub(corners, dilated_corners, corners)
-    cv.CmpS(corners, 0, corner_mask, cv.CV_CMP_GE)
-    return (corners, corner_mask)
diff --git a/modules/python/test/test.py b/modules/python/test/test.py
old mode 100644
new mode 100755
index 093979a..5a66769
--- a/modules/python/test/test.py
+++ b/modules/python/test/test.py
@@ -23,48 +23,16 @@ try:
 except ImportError:
     from urllib import urlopen
 
-class NewOpenCVTests(unittest.TestCase):
-
-    # path to local repository folder containing 'samples' folder
-    repoPath = None
-    # github repository url
-    repoUrl = 'https://raw.github.com/Itseez/opencv/master'
-
-    def get_sample(self, filename, iscolor = cv2.IMREAD_COLOR):
-        if not filename in self.image_cache:
-            filedata = None
-            if NewOpenCVTests.repoPath is not None:
-                candidate = NewOpenCVTests.repoPath + '/' + filename
-                if os.path.isfile(candidate):
-                    with open(candidate, 'rb') as f:
-                        filedata = f.read()
-            if filedata is None:
-                filedata = urlopen(NewOpenCVTests.repoUrl + '/' + filename).read()
-            self.image_cache[filename] = cv2.imdecode(np.fromstring(filedata, dtype=np.uint8), iscolor)
-        return self.image_cache[filename]
-
-    def setUp(self):
-        self.image_cache = {}
-
-    def hashimg(self, im):
-        """ Compute a hash for an image, useful for image comparisons """
-        return hashlib.md5(im.tostring()).digest()
-
-    if sys.version_info[:2] == (2, 6):
-        def assertLess(self, a, b, msg=None):
-            if not a < b:
-                self.fail('%s not less than %s' % (repr(a), repr(b)))
-
-        def assertLessEqual(self, a, b, msg=None):
-            if not a <= b:
-                self.fail('%s not less than or equal to %s' % (repr(a), repr(b)))
-
-        def assertGreater(self, a, b, msg=None):
-            if not a > b:
-                self.fail('%s not greater than %s' % (repr(a), repr(b)))
+from tests_common import NewOpenCVTests
 
 # Tests to run first; check the handful of basic operations that the later tests rely on
 
+basedir = os.path.abspath(os.path.dirname(__file__))
+
+def load_tests(loader, tests, pattern):
+    tests.addTests(loader.discover(basedir, pattern='test_*.py'))
+    return tests
+
 class Hackathon244Tests(NewOpenCVTests):
 
     def test_int_array(self):
@@ -155,6 +123,60 @@ class Hackathon244Tests(NewOpenCVTests):
         boost.getMaxDepth() # from ml::DTrees
         boost.isClassifier() # from ml::StatModel
 
+    def test_umat_matching(self):
+        img1 = self.get_sample("samples/data/right01.jpg")
+        img2 = self.get_sample("samples/data/right02.jpg")
+
+        orb = cv2.ORB_create()
+
+        img1, img2 = cv2.UMat(img1), cv2.UMat(img2)
+        ps1, descs_umat1 = orb.detectAndCompute(img1, None)
+        ps2, descs_umat2 = orb.detectAndCompute(img2, None)
+
+        self.assertIsInstance(descs_umat1, cv2.UMat)
+        self.assertIsInstance(descs_umat2, cv2.UMat)
+        self.assertGreater(len(ps1), 0)
+        self.assertGreater(len(ps2), 0)
+
+        bf = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=True)
+
+        res_umats = bf.match(descs_umat1, descs_umat2)
+        res = bf.match(descs_umat1.get(), descs_umat2.get())
+
+        self.assertGreater(len(res), 0)
+        self.assertEqual(len(res_umats), len(res))
+
+    def test_umat_optical_flow(self):
+        img1 = self.get_sample("samples/data/right01.jpg", cv2.IMREAD_GRAYSCALE)
+        img2 = self.get_sample("samples/data/right02.jpg", cv2.IMREAD_GRAYSCALE)
+        # Note, that if you want to see performance boost by OCL implementation - you need enough data
+        # For example you can increase maxCorners param to 10000 and increase img1 and img2 in such way:
+        # img = np.hstack([np.vstack([img] * 6)] * 6)
+
+        feature_params = dict(maxCorners=239,
+                              qualityLevel=0.3,
+                              minDistance=7,
+                              blockSize=7)
+
+        p0 = cv2.goodFeaturesToTrack(img1, mask=None, **feature_params)
+        p0_umat = cv2.goodFeaturesToTrack(cv2.UMat(img1), mask=None, **feature_params)
+        self.assertEqual(p0_umat.get().shape, p0.shape)
+
+        p0 = np.array(sorted(p0, key=lambda p: tuple(p[0])))
+        p0_umat = cv2.UMat(np.array(sorted(p0_umat.get(), key=lambda p: tuple(p[0]))))
+        self.assertTrue(np.allclose(p0_umat.get(), p0))
+
+        p1_mask_err = cv2.calcOpticalFlowPyrLK(img1, img2, p0, None)
+
+        p1_mask_err_umat0 = map(cv2.UMat.get, cv2.calcOpticalFlowPyrLK(img1, img2, p0_umat, None))
+        p1_mask_err_umat1 = map(cv2.UMat.get, cv2.calcOpticalFlowPyrLK(cv2.UMat(img1), img2, p0_umat, None))
+        p1_mask_err_umat2 = map(cv2.UMat.get, cv2.calcOpticalFlowPyrLK(img1, cv2.UMat(img2), p0_umat, None))
+
+        # # results of OCL optical flow differs from CPU implementation, so result can not be easily compared
+        # for p1_mask_err_umat in [p1_mask_err_umat0, p1_mask_err_umat1, p1_mask_err_umat2]:
+        #     for data, data_umat in zip(p1_mask_err, p1_mask_err_umat):
+        #         self.assertTrue(np.allclose(data, data_umat))
+
 if __name__ == '__main__':
     parser = argparse.ArgumentParser(description='run OpenCV python tests')
     parser.add_argument('--repo', help='use sample image files from local git repository (path to folder), '
@@ -165,6 +187,10 @@ if __name__ == '__main__':
     print("Testing OpenCV", cv2.__version__)
     print("Local repo path:", args.repo)
     NewOpenCVTests.repoPath = args.repo
+    try:
+        NewOpenCVTests.extraTestDataPath = os.environ['OPENCV_TEST_DATA_PATH']
+    except KeyError:
+        print('Missing opencv extra repository. Some of tests may fail.')
     random.seed(0)
     unit_argv = [sys.argv[0]] + other;
     unittest.main(argv=unit_argv)
diff --git a/modules/python/test/test_calibration.py b/modules/python/test/test_calibration.py
new file mode 100644
index 0000000..584c7e6
--- /dev/null
+++ b/modules/python/test/test_calibration.py
@@ -0,0 +1,71 @@
+#!/usr/bin/env python
+
+'''
+camera calibration for distorted images with chess board samples
+reads distorted images, calculates the calibration and write undistorted images
+'''
+
+# Python 2/3 compatibility
+from __future__ import print_function
+
+import numpy as np
+import cv2
+
+from tests_common import NewOpenCVTests
+
+class calibration_test(NewOpenCVTests):
+
+    def test_calibration(self):
+
+        from glob import glob
+        img_names = []
+        for i in range(1, 15):
+            if i < 10:
+                img_names.append('samples/data/left0{}.jpg'.format(str(i)))
+            elif i != 10:
+                img_names.append('samples/data/left{}.jpg'.format(str(i)))
+
+        square_size = 1.0
+        pattern_size = (9, 6)
+        pattern_points = np.zeros((np.prod(pattern_size), 3), np.float32)
+        pattern_points[:, :2] = np.indices(pattern_size).T.reshape(-1, 2)
+        pattern_points *= square_size
+
+        obj_points = []
+        img_points = []
+        h, w = 0, 0
+        img_names_undistort = []
+        for fn in img_names:
+            img = self.get_sample(fn, 0)
+            if img is None:
+                continue
+
+            h, w = img.shape[:2]
+            found, corners = cv2.findChessboardCorners(img, pattern_size)
+            if found:
+                term = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_COUNT, 30, 0.1)
+                cv2.cornerSubPix(img, corners, (5, 5), (-1, -1), term)
+
+            if not found:
+                continue
+
+            img_points.append(corners.reshape(-1, 2))
+            obj_points.append(pattern_points)
+
+        # calculate camera distortion
+        rms, camera_matrix, dist_coefs, rvecs, tvecs = cv2.calibrateCamera(obj_points, img_points, (w, h), None, None, flags = 0)
+
+        eps = 0.01
+        normCamEps = 10.0
+        normDistEps = 0.05
+
+        cameraMatrixTest = [[ 532.80992189,    0.,          342.4952186 ],
+         [   0.,         532.93346422,  233.8879292 ],
+         [   0.,            0.,            1.        ]]
+
+        distCoeffsTest = [ -2.81325576e-01,   2.91130406e-02,
+           1.21234330e-03,  -1.40825372e-04, 1.54865844e-01]
+
+        self.assertLess(abs(rms - 0.196334638034), eps)
+        self.assertLess(cv2.norm(camera_matrix - cameraMatrixTest, cv2.NORM_L1), normCamEps)
+        self.assertLess(cv2.norm(dist_coefs - distCoeffsTest, cv2.NORM_L1), normDistEps)
diff --git a/modules/python/test/test_camshift.py b/modules/python/test/test_camshift.py
new file mode 100644
index 0000000..a824320
--- /dev/null
+++ b/modules/python/test/test_camshift.py
@@ -0,0 +1,92 @@
+#!/usr/bin/env python
+
+'''
+Camshift tracker
+================
+
+This is a demo that shows mean-shift based tracking
+You select a color objects such as your face and it tracks it.
+This reads from video camera (0 by default, or the camera number the user enters)
+
+http://www.robinhewitt.com/research/track/camshift.html
+
+'''
+
+# Python 2/3 compatibility
+from __future__ import print_function
+import sys
+PY3 = sys.version_info[0] == 3
+
+if PY3:
+    xrange = range
+
+import numpy as np
+import cv2
+from tst_scene_render import TestSceneRender
+
+from tests_common import NewOpenCVTests, intersectionRate
+
+class camshift_test(NewOpenCVTests):
+
+    framesNum = 300
+    frame = None
+    selection = None
+    drag_start = None
+    show_backproj = False
+    track_window = None
+    render = None
+    errors = 0
+
+    def prepareRender(self):
+
+        self.render = TestSceneRender(self.get_sample('samples/data/pca_test1.jpg'), deformation = True)
+
+    def runTracker(self):
+
+        framesCounter = 0
+        self.selection = True
+
+        xmin, ymin, xmax, ymax = self.render.getCurrentRect()
+
+        self.track_window = (xmin, ymin, xmax - xmin, ymax - ymin)
+
+        while True:
+            framesCounter += 1
+            self.frame = self.render.getNextFrame()
+            hsv = cv2.cvtColor(self.frame, cv2.COLOR_BGR2HSV)
+            mask = cv2.inRange(hsv, np.array((0., 60., 32.)), np.array((180., 255., 255.)))
+
+            if self.selection:
+                x0, y0, x1, y1 = self.render.getCurrentRect() + 50
+                x0 -= 100
+                y0 -= 100
+
+                hsv_roi = hsv[y0:y1, x0:x1]
+                mask_roi = mask[y0:y1, x0:x1]
+                hist = cv2.calcHist( [hsv_roi], [0], mask_roi, [16], [0, 180] )
+                cv2.normalize(hist, hist, 0, 255, cv2.NORM_MINMAX)
+                self.hist = hist.reshape(-1)
+                self.selection = False
+
+            if self.track_window and self.track_window[2] > 0 and self.track_window[3] > 0:
+                self.selection = None
+                prob = cv2.calcBackProject([hsv], [0], self.hist, [0, 180], 1)
+                prob &= mask
+                term_crit = ( cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 10, 1 )
+                track_box, self.track_window = cv2.CamShift(prob, self.track_window, term_crit)
+
+            trackingRect = np.array(self.track_window)
+            trackingRect[2] += trackingRect[0]
+            trackingRect[3] += trackingRect[1]
+
+            if intersectionRate(self.render.getCurrentRect(), trackingRect) < 0.4:
+                self.errors += 1
+
+            if framesCounter > self.framesNum:
+                break
+
+        self.assertLess(float(self.errors) / self.framesNum, 0.4)
+
+    def test_camshift(self):
+        self.prepareRender()
+        self.runTracker()
\ No newline at end of file
diff --git a/modules/python/test/test_dft.py b/modules/python/test/test_dft.py
new file mode 100644
index 0000000..f796939
--- /dev/null
+++ b/modules/python/test/test_dft.py
@@ -0,0 +1,46 @@
+#!/usr/bin/env python
+
+'''
+Test for disctrete fourier transform (dft)
+'''
+
+# Python 2/3 compatibility
+from __future__ import print_function
+
+import cv2
+import numpy as np
+import sys
+
+from tests_common import NewOpenCVTests
+
+class dft_test(NewOpenCVTests):
+    def test_dft(self):
+
+        img = self.get_sample('samples/data/rubberwhale1.png', 0)
+        eps = 0.001
+
+        #test direct transform
+        refDft = np.fft.fft2(img)
+        refDftShift = np.fft.fftshift(refDft)
+        refMagnitide = np.log(1.0 + np.abs(refDftShift))
+
+        testDft = cv2.dft(np.float32(img),flags = cv2.DFT_COMPLEX_OUTPUT)
+        testDftShift = np.fft.fftshift(testDft)
+        testMagnitude = np.log(1.0 + cv2.magnitude(testDftShift[:,:,0], testDftShift[:,:,1]))
+
+        refMagnitide = cv2.normalize(refMagnitide, 0.0, 1.0, cv2.NORM_MINMAX)
+        testMagnitude = cv2.normalize(testMagnitude, 0.0, 1.0, cv2.NORM_MINMAX)
+
+        self.assertLess(cv2.norm(refMagnitide - testMagnitude), eps)
+
+        #test inverse transform
+        img_back = np.fft.ifft2(refDft)
+        img_back = np.abs(img_back)
+
+        img_backTest = cv2.idft(testDft)
+        img_backTest = cv2.magnitude(img_backTest[:,:,0], img_backTest[:,:,1])
+
+        img_backTest = cv2.normalize(img_backTest, 0.0, 1.0, cv2.NORM_MINMAX)
+        img_back = cv2.normalize(img_back, 0.0, 1.0, cv2.NORM_MINMAX)
+
+        self.assertLess(cv2.norm(img_back - img_backTest), eps)
\ No newline at end of file
diff --git a/modules/python/test/test_digits.py b/modules/python/test/test_digits.py
new file mode 100644
index 0000000..c7ac996
--- /dev/null
+++ b/modules/python/test/test_digits.py
@@ -0,0 +1,197 @@
+#!/usr/bin/env python
+
+'''
+SVM and KNearest digit recognition.
+
+Sample loads a dataset of handwritten digits from '../data/digits.png'.
+Then it trains a SVM and KNearest classifiers on it and evaluates
+their accuracy.
+
+Following preprocessing is applied to the dataset:
+ - Moment-based image deskew (see deskew())
+ - Digit images are split into 4 10x10 cells and 16-bin
+   histogram of oriented gradients is computed for each
+   cell
+ - Transform histograms to space with Hellinger metric (see [1] (RootSIFT))
+
+
+[1] R. Arandjelovic, A. Zisserman
+    "Three things everyone should know to improve object retrieval"
+    http://www.robots.ox.ac.uk/~vgg/publications/2012/Arandjelovic12/arandjelovic12.pdf
+
+'''
+
+
+# Python 2/3 compatibility
+from __future__ import print_function
+
+# built-in modules
+from multiprocessing.pool import ThreadPool
+
+import cv2
+
+import numpy as np
+from numpy.linalg import norm
+
+
+SZ = 20 # size of each digit is SZ x SZ
+CLASS_N = 10
+DIGITS_FN = 'samples/data/digits.png'
+
+def split2d(img, cell_size, flatten=True):
+    h, w = img.shape[:2]
+    sx, sy = cell_size
+    cells = [np.hsplit(row, w//sx) for row in np.vsplit(img, h//sy)]
+    cells = np.array(cells)
+    if flatten:
+        cells = cells.reshape(-1, sy, sx)
+    return cells
+
+def deskew(img):
+    m = cv2.moments(img)
+    if abs(m['mu02']) < 1e-2:
+        return img.copy()
+    skew = m['mu11']/m['mu02']
+    M = np.float32([[1, skew, -0.5*SZ*skew], [0, 1, 0]])
+    img = cv2.warpAffine(img, M, (SZ, SZ), flags=cv2.WARP_INVERSE_MAP | cv2.INTER_LINEAR)
+    return img
+
+class StatModel(object):
+    def load(self, fn):
+        self.model.load(fn)  # Known bug: https://github.com/opencv/opencv/issues/4969
+    def save(self, fn):
+        self.model.save(fn)
+
+class KNearest(StatModel):
+    def __init__(self, k = 3):
+        self.k = k
+        self.model = cv2.ml.KNearest_create()
+
+    def train(self, samples, responses):
+        self.model.train(samples, cv2.ml.ROW_SAMPLE, responses)
+
+    def predict(self, samples):
+        retval, results, neigh_resp, dists = self.model.findNearest(samples, self.k)
+        return results.ravel()
+
+class SVM(StatModel):
+    def __init__(self, C = 1, gamma = 0.5):
+        self.model = cv2.ml.SVM_create()
+        self.model.setGamma(gamma)
+        self.model.setC(C)
+        self.model.setKernel(cv2.ml.SVM_RBF)
+        self.model.setType(cv2.ml.SVM_C_SVC)
+
+    def train(self, samples, responses):
+        self.model.train(samples, cv2.ml.ROW_SAMPLE, responses)
+
+    def predict(self, samples):
+        return self.model.predict(samples)[1].ravel()
+
+
+def evaluate_model(model, digits, samples, labels):
+    resp = model.predict(samples)
+    err = (labels != resp).mean()
+
+    confusion = np.zeros((10, 10), np.int32)
+    for i, j in zip(labels, resp):
+        confusion[int(i), int(j)] += 1
+
+    return err, confusion
+
+def preprocess_simple(digits):
+    return np.float32(digits).reshape(-1, SZ*SZ) / 255.0
+
+def preprocess_hog(digits):
+    samples = []
+    for img in digits:
+        gx = cv2.Sobel(img, cv2.CV_32F, 1, 0)
+        gy = cv2.Sobel(img, cv2.CV_32F, 0, 1)
+        mag, ang = cv2.cartToPolar(gx, gy)
+        bin_n = 16
+        bin = np.int32(bin_n*ang/(2*np.pi))
+        bin_cells = bin[:10,:10], bin[10:,:10], bin[:10,10:], bin[10:,10:]
+        mag_cells = mag[:10,:10], mag[10:,:10], mag[:10,10:], mag[10:,10:]
+        hists = [np.bincount(b.ravel(), m.ravel(), bin_n) for b, m in zip(bin_cells, mag_cells)]
+        hist = np.hstack(hists)
+
+        # transform to Hellinger kernel
+        eps = 1e-7
+        hist /= hist.sum() + eps
+        hist = np.sqrt(hist)
+        hist /= norm(hist) + eps
+
+        samples.append(hist)
+    return np.float32(samples)
+
+from tests_common import NewOpenCVTests
+
+class digits_test(NewOpenCVTests):
+
+    def load_digits(self, fn):
+        digits_img = self.get_sample(fn, 0)
+        digits = split2d(digits_img, (SZ, SZ))
+        labels = np.repeat(np.arange(CLASS_N), len(digits)/CLASS_N)
+        return digits, labels
+
+    def test_digits(self):
+
+        digits, labels = self.load_digits(DIGITS_FN)
+
+        # shuffle digits
+        rand = np.random.RandomState(321)
+        shuffle = rand.permutation(len(digits))
+        digits, labels = digits[shuffle], labels[shuffle]
+
+        digits2 = list(map(deskew, digits))
+        samples = preprocess_hog(digits2)
+
+        train_n = int(0.9*len(samples))
+        digits_train, digits_test = np.split(digits2, [train_n])
+        samples_train, samples_test = np.split(samples, [train_n])
+        labels_train, labels_test = np.split(labels, [train_n])
+        errors = list()
+        confusionMatrixes = list()
+
+        model = KNearest(k=4)
+        model.train(samples_train, labels_train)
+        error, confusion = evaluate_model(model, digits_test, samples_test, labels_test)
+        errors.append(error)
+        confusionMatrixes.append(confusion)
+
+        model = SVM(C=2.67, gamma=5.383)
+        model.train(samples_train, labels_train)
+        error, confusion = evaluate_model(model, digits_test, samples_test, labels_test)
+        errors.append(error)
+        confusionMatrixes.append(confusion)
+
+        eps = 0.001
+        normEps = len(samples_test) * 0.02
+
+        confusionKNN = [[45,  0,  0,  0,  0,  0,  0,  0,  0,  0],
+         [ 0, 57,  0,  0,  0,  0,  0,  0,  0,  0],
+         [ 0,  0, 59,  1,  0,  0,  0,  0,  1,  0],
+         [ 0,  0,  0, 43,  0,  0,  0,  1,  0,  0],
+         [ 0,  0,  0,  0, 38,  0,  2,  0,  0,  0],
+         [ 0,  0,  0,  2,  0, 48,  0,  0,  1,  0],
+         [ 0,  1,  0,  0,  0,  0, 51,  0,  0,  0],
+         [ 0,  0,  1,  0,  0,  0,  0, 54,  0,  0],
+         [ 0,  0,  0,  0,  0,  1,  0,  0, 46,  0],
+         [ 1,  1,  0,  1,  1,  0,  0,  0,  2, 42]]
+
+        confusionSVM = [[45,  0,  0,  0,  0,  0,  0,  0,  0,  0],
+          [ 0, 57,  0,  0,  0,  0,  0,  0,  0,  0],
+          [ 0,  0, 59,  2,  0,  0,  0,  0,  0,  0],
+          [ 0,  0,  0, 43,  0,  0,  0,  1,  0,  0],
+          [ 0,  0,  0,  0, 40,  0,  0,  0,  0,  0],
+          [ 0,  0,  0,  1,  0, 50,  0,  0,  0,  0],
+          [ 0,  0,  0,  0,  1,  0,  51, 0,  0,  0],
+          [ 0,  0,  1,  0,  0,  0,  0,  54, 0,  0],
+          [ 0,  0,  0,  0,  0,  0,  0,  0, 47,  0],
+          [ 0,  1,  0,  1,  0,  0,  0,  0,  1, 45]]
+
+        self.assertLess(cv2.norm(confusionMatrixes[0] - confusionKNN, cv2.NORM_L1), normEps)
+        self.assertLess(cv2.norm(confusionMatrixes[1] - confusionSVM, cv2.NORM_L1), normEps)
+
+        self.assertLess(errors[0] - 0.034, eps)
+        self.assertLess(errors[1] - 0.018, eps)
\ No newline at end of file
diff --git a/modules/python/test/test_facedetect.py b/modules/python/test/test_facedetect.py
new file mode 100644
index 0000000..8d64fde
--- /dev/null
+++ b/modules/python/test/test_facedetect.py
@@ -0,0 +1,90 @@
+#!/usr/bin/env python
+
+'''
+face detection using haar cascades
+'''
+
+# Python 2/3 compatibility
+from __future__ import print_function
+
+import numpy as np
+import cv2
+
+def detect(img, cascade):
+    rects = cascade.detectMultiScale(img, scaleFactor=1.3, minNeighbors=4, minSize=(30, 30),
+                                     flags=cv2.CASCADE_SCALE_IMAGE)
+    if len(rects) == 0:
+        return []
+    rects[:,2:] += rects[:,:2]
+    return rects
+
+from tests_common import NewOpenCVTests, intersectionRate
+
+class facedetect_test(NewOpenCVTests):
+
+    def test_facedetect(self):
+        import sys, getopt
+
+        cascade_fn = self.repoPath + '/data/haarcascades/haarcascade_frontalface_alt.xml'
+        nested_fn  = self.repoPath + '/data/haarcascades/haarcascade_eye.xml'
+
+        cascade = cv2.CascadeClassifier(cascade_fn)
+        nested = cv2.CascadeClassifier(nested_fn)
+
+        samples = ['samples/data/lena.jpg', 'cv/cascadeandhog/images/mona-lisa.png']
+
+        faces = []
+        eyes = []
+
+        testFaces = [
+        #lena
+        [[218, 200, 389, 371],
+        [ 244, 240, 294, 290],
+        [ 309, 246, 352, 289]],
+
+        #lisa
+        [[167, 119, 307, 259],
+        [188, 153, 229, 194],
+        [236, 153, 277, 194]]
+        ]
+
+        for sample in samples:
+
+            img = self.get_sample(  sample)
+            gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
+            gray = cv2.GaussianBlur(gray, (5, 5), 5.1)
+
+            rects = detect(gray, cascade)
+            faces.append(rects)
+
+            if not nested.empty():
+                for x1, y1, x2, y2 in rects:
+                    roi = gray[y1:y2, x1:x2]
+                    subrects = detect(roi.copy(), nested)
+
+                    for rect in subrects:
+                        rect[0] += x1
+                        rect[2] += x1
+                        rect[1] += y1
+                        rect[3] += y1
+
+                    eyes.append(subrects)
+
+        faces_matches = 0
+        eyes_matches = 0
+
+        eps = 0.8
+
+        for i in range(len(faces)):
+            for j in range(len(testFaces)):
+                if intersectionRate(faces[i][0], testFaces[j][0]) > eps:
+                    faces_matches += 1
+                    #check eyes
+                    if len(eyes[i]) == 2:
+                        if intersectionRate(eyes[i][0], testFaces[j][1]) > eps and intersectionRate(eyes[i][1] , testFaces[j][2]) > eps:
+                            eyes_matches += 1
+                        elif intersectionRate(eyes[i][1], testFaces[j][1]) > eps and intersectionRate(eyes[i][0], testFaces[j][2]) > eps:
+                            eyes_matches += 1
+
+        self.assertEqual(faces_matches, 2)
+        self.assertEqual(eyes_matches, 2)
\ No newline at end of file
diff --git a/modules/python/test/test_feature_homography.py b/modules/python/test/test_feature_homography.py
new file mode 100644
index 0000000..861ff92
--- /dev/null
+++ b/modules/python/test/test_feature_homography.py
@@ -0,0 +1,160 @@
+#!/usr/bin/env python
+
+'''
+Feature homography
+==================
+
+Example of using features2d framework for interactive video homography matching.
+ORB features and FLANN matcher are used. The actual tracking is implemented by
+PlaneTracker class in plane_tracker.py
+'''
+
+# Python 2/3 compatibility
+from __future__ import print_function
+
+import numpy as np
+import cv2
+import sys
+PY3 = sys.version_info[0] == 3
+
+if PY3:
+    xrange = range
+
+# local modules
+from tst_scene_render import TestSceneRender
+
+def intersectionRate(s1, s2):
+
+    x1, y1, x2, y2 = s1
+    s1 = np.array([[x1, y1], [x2,y1], [x2, y2], [x1, y2]])
+
+    area, intersection = cv2.intersectConvexConvex(s1, np.array(s2))
+    return 2 * area / (cv2.contourArea(s1) + cv2.contourArea(np.array(s2)))
+
+from tests_common import NewOpenCVTests
+
+class feature_homography_test(NewOpenCVTests):
+
+    render = None
+    tracker = None
+    framesCounter = 0
+    frame = None
+
+    def test_feature_homography(self):
+
+        self.render = TestSceneRender(self.get_sample('samples/data/graf1.png'),
+            self.get_sample('samples/data/box.png'), noise = 0.5, speed = 0.5)
+        self.frame = self.render.getNextFrame()
+        self.tracker = PlaneTracker()
+        self.tracker.clear()
+        self.tracker.add_target(self.frame, self.render.getCurrentRect())
+
+        while self.framesCounter < 100:
+            self.framesCounter += 1
+            tracked = self.tracker.track(self.frame)
+            if len(tracked) > 0:
+                tracked = tracked[0]
+                self.assertGreater(intersectionRate(self.render.getCurrentRect(), np.int32(tracked.quad)), 0.6)
+            else:
+                self.assertEqual(0, 1, 'Tracking error')
+            self.frame = self.render.getNextFrame()
+
+
+# built-in modules
+from collections import namedtuple
+
+FLANN_INDEX_KDTREE = 1
+FLANN_INDEX_LSH    = 6
+flann_params= dict(algorithm = FLANN_INDEX_LSH,
+                   table_number = 6, # 12
+                   key_size = 12,     # 20
+                   multi_probe_level = 1) #2
+
+MIN_MATCH_COUNT = 10
+
+'''
+  image     - image to track
+  rect      - tracked rectangle (x1, y1, x2, y2)
+  keypoints - keypoints detected inside rect
+  descrs    - their descriptors
+  data      - some user-provided data
+'''
+PlanarTarget = namedtuple('PlaneTarget', 'image, rect, keypoints, descrs, data')
+
+'''
+  target - reference to PlanarTarget
+  p0     - matched points coords in target image
+  p1     - matched points coords in input frame
+  H      - homography matrix from p0 to p1
+  quad   - target bounary quad in input frame
+'''
+TrackedTarget = namedtuple('TrackedTarget', 'target, p0, p1, H, quad')
+
+class PlaneTracker:
+    def __init__(self):
+        self.detector = cv2.AKAZE_create(threshold = 0.003)
+        self.matcher = cv2.FlannBasedMatcher(flann_params, {})  # bug : need to pass empty dict (#1329)
+        self.targets = []
+        self.frame_points = []
+
+    def add_target(self, image, rect, data=None):
+        '''Add a new tracking target.'''
+        x0, y0, x1, y1 = rect
+        raw_points, raw_descrs = self.detect_features(image)
+        points, descs = [], []
+        for kp, desc in zip(raw_points, raw_descrs):
+            x, y = kp.pt
+            if x0 <= x <= x1 and y0 <= y <= y1:
+                points.append(kp)
+                descs.append(desc)
+        descs = np.uint8(descs)
+        self.matcher.add([descs])
+        target = PlanarTarget(image = image, rect=rect, keypoints = points, descrs=descs, data=data)
+        self.targets.append(target)
+
+    def clear(self):
+        '''Remove all targets'''
+        self.targets = []
+        self.matcher.clear()
+
+    def track(self, frame):
+        '''Returns a list of detected TrackedTarget objects'''
+        self.frame_points, frame_descrs = self.detect_features(frame)
+        if len(self.frame_points) < MIN_MATCH_COUNT:
+            return []
+        matches = self.matcher.knnMatch(frame_descrs, k = 2)
+        matches = [m[0] for m in matches if len(m) == 2 and m[0].distance < m[1].distance * 0.75]
+        if len(matches) < MIN_MATCH_COUNT:
+            return []
+        matches_by_id = [[] for _ in xrange(len(self.targets))]
+        for m in matches:
+            matches_by_id[m.imgIdx].append(m)
+        tracked = []
+        for imgIdx, matches in enumerate(matches_by_id):
+            if len(matches) < MIN_MATCH_COUNT:
+                continue
+            target = self.targets[imgIdx]
+            p0 = [target.keypoints[m.trainIdx].pt for m in matches]
+            p1 = [self.frame_points[m.queryIdx].pt for m in matches]
+            p0, p1 = np.float32((p0, p1))
+            H, status = cv2.findHomography(p0, p1, cv2.RANSAC, 3.0)
+            status = status.ravel() != 0
+            if status.sum() < MIN_MATCH_COUNT:
+                continue
+            p0, p1 = p0[status], p1[status]
+
+            x0, y0, x1, y1 = target.rect
+            quad = np.float32([[x0, y0], [x1, y0], [x1, y1], [x0, y1]])
+            quad = cv2.perspectiveTransform(quad.reshape(1, -1, 2), H).reshape(-1, 2)
+
+            track = TrackedTarget(target=target, p0=p0, p1=p1, H=H, quad=quad)
+            tracked.append(track)
+        tracked.sort(key = lambda t: len(t.p0), reverse=True)
+        return tracked
+
+    def detect_features(self, frame):
+        '''detect_features(self, frame) -> keypoints, descrs'''
+        keypoints, descrs = self.detector.detectAndCompute(frame, None)
+        if descrs is None:  # detectAndCompute returns descs=None if no keypoints found
+            descrs = []
+        return keypoints, descrs
\ No newline at end of file
diff --git a/modules/python/test/test_fitline.py b/modules/python/test/test_fitline.py
new file mode 100644
index 0000000..7de9573
--- /dev/null
+++ b/modules/python/test/test_fitline.py
@@ -0,0 +1,66 @@
+#!/usr/bin/env python
+
+'''
+Robust line fitting.
+==================
+
+Example of using cv2.fitLine function for fitting line
+to points in presence of outliers.
+
+Switch through different M-estimator functions and see,
+how well the robust functions fit the line even
+in case of ~50% of outliers.
+
+'''
+
+# Python 2/3 compatibility
+from __future__ import print_function
+import sys
+PY3 = sys.version_info[0] == 3
+
+import numpy as np
+import cv2
+
+from tests_common import NewOpenCVTests
+
+w, h = 512, 256
+
+def toint(p):
+    return tuple(map(int, p))
+
+def sample_line(p1, p2, n, noise=0.0):
+    np.random.seed(10)
+    p1 = np.float32(p1)
+    t = np.random.rand(n,1)
+    return p1 + (p2-p1)*t + np.random.normal(size=(n, 2))*noise
+
+dist_func_names = ['DIST_L2', 'DIST_L1', 'DIST_L12', 'DIST_FAIR', 'DIST_WELSCH', 'DIST_HUBER']
+
+class fitline_test(NewOpenCVTests):
+
+    def test_fitline(self):
+
+        noise = 5
+        n = 200
+        r = 5 / 100.0
+        outn = int(n*r)
+
+        p0, p1 = (90, 80), (w-90, h-80)
+        line_points = sample_line(p0, p1, n-outn, noise)
+        outliers = np.random.rand(outn, 2) * (w, h)
+        points = np.vstack([line_points, outliers])
+
+        lines = []
+
+        for name in dist_func_names:
+            func = getattr(cv2, name)
+            vx, vy, cx, cy = cv2.fitLine(np.float32(points), func, 0, 0.01, 0.01)
+            line = [float(vx), float(vy), float(cx), float(cy)]
+            lines.append(line)
+
+        eps = 0.05
+
+        refVec =  (np.float32(p1) - p0) / cv2.norm(np.float32(p1) - p0)
+
+        for i in range(len(lines)):
+            self.assertLessEqual(cv2.norm(refVec - lines[i][0:2], cv2.NORM_L2), eps)
\ No newline at end of file
diff --git a/modules/python/test/test_gaussian_mix.py b/modules/python/test/test_gaussian_mix.py
new file mode 100644
index 0000000..78a29ce
--- /dev/null
+++ b/modules/python/test/test_gaussian_mix.py
@@ -0,0 +1,60 @@
+#!/usr/bin/env python
+
+# Python 2/3 compatibility
+from __future__ import print_function
+import sys
+PY3 = sys.version_info[0] == 3
+
+if PY3:
+    xrange = range
+
+import numpy as np
+from numpy import random
+import cv2
+
+def make_gaussians(cluster_n, img_size):
+    points = []
+    ref_distrs = []
+    for i in xrange(cluster_n):
+        mean = (0.1 + 0.8*random.rand(2)) * img_size
+        a = (random.rand(2, 2)-0.5)*img_size*0.1
+        cov = np.dot(a.T, a) + img_size*0.05*np.eye(2)
+        n = 100 + random.randint(900)
+        pts = random.multivariate_normal(mean, cov, n)
+        points.append( pts )
+        ref_distrs.append( (mean, cov) )
+    points = np.float32( np.vstack(points) )
+    return points, ref_distrs
+
+from tests_common import NewOpenCVTests
+
+class gaussian_mix_test(NewOpenCVTests):
+
+    def test_gaussian_mix(self):
+
+        np.random.seed(10)
+        cluster_n = 5
+        img_size = 512
+
+        points, ref_distrs = make_gaussians(cluster_n, img_size)
+
+        em = cv2.ml.EM_create()
+        em.setClustersNumber(cluster_n)
+        em.setCovarianceMatrixType(cv2.ml.EM_COV_MAT_GENERIC)
+        em.trainEM(points)
+        means = em.getMeans()
+        covs = em.getCovs()  # Known bug: https://github.com/opencv/opencv/pull/4232
+        found_distrs = zip(means, covs)
+
+        matches_count = 0
+
+        meanEps = 0.05
+        covEps = 0.1
+
+        for i in range(cluster_n):
+            for j in range(cluster_n):
+                if (cv2.norm(means[i] - ref_distrs[j][0], cv2.NORM_L2) / cv2.norm(ref_distrs[j][0], cv2.NORM_L2) < meanEps and
+                    cv2.norm(covs[i] - ref_distrs[j][1], cv2.NORM_L2) / cv2.norm(ref_distrs[j][1], cv2.NORM_L2) < covEps):
+                    matches_count += 1
+
+        self.assertEqual(matches_count, cluster_n)
\ No newline at end of file
diff --git a/modules/python/test/test_goodfeatures.py b/modules/python/test/test_goodfeatures.py
new file mode 100644
index 0000000..5114ad8
--- /dev/null
+++ b/modules/python/test/test_goodfeatures.py
@@ -0,0 +1,36 @@
+#!/usr/bin/env python
+
+# Python 2/3 compatibility
+from __future__ import print_function
+
+import cv2
+import numpy as np
+
+from tests_common import NewOpenCVTests
+
+class TestGoodFeaturesToTrack_test(NewOpenCVTests):
+    def test_goodFeaturesToTrack(self):
+        arr = self.get_sample('samples/data/lena.jpg', 0)
+        original = arr.copy(True)
+        threshes = [ x / 100. for x in range(1,10) ]
+        numPoints = 20000
+
+        results = dict([(t, cv2.goodFeaturesToTrack(arr, numPoints, t, 2, useHarrisDetector=True)) for t in threshes])
+        # Check that GoodFeaturesToTrack has not modified input image
+        self.assertTrue(arr.tostring() == original.tostring())
+        # Check for repeatability
+        for i in range(1):
+            results2 = dict([(t, cv2.goodFeaturesToTrack(arr, numPoints, t, 2, useHarrisDetector=True)) for t in threshes])
+            for t in threshes:
+                self.assertTrue(len(results2[t]) == len(results[t]))
+                for i in range(len(results[t])):
+                    self.assertTrue(cv2.norm(results[t][i][0] - results2[t][i][0]) == 0)
+
+        for t0,t1 in zip(threshes, threshes[1:]):
+             r0 = results[t0]
+             r1 = results[t1]
+             # Increasing thresh should make result list shorter
+             self.assertTrue(len(r0) > len(r1))
+             # Increasing thresh should monly truncate result list
+             for i in range(len(r1)):
+                self.assertTrue(cv2.norm(r1[i][0] - r0[i][0])==0)
\ No newline at end of file
diff --git a/modules/python/test/test_grabcut.py b/modules/python/test/test_grabcut.py
new file mode 100644
index 0000000..38211f7
--- /dev/null
+++ b/modules/python/test/test_grabcut.py
@@ -0,0 +1,67 @@
+#!/usr/bin/env python
+'''
+===============================================================================
+Interactive Image Segmentation using GrabCut algorithm.
+===============================================================================
+'''
+
+# Python 2/3 compatibility
+from __future__ import print_function
+
+import numpy as np
+import cv2
+import sys
+
+from tests_common import NewOpenCVTests
+
+class grabcut_test(NewOpenCVTests):
+
+    def verify(self, mask, exp):
+
+        maxDiffRatio = 0.02
+        expArea = np.count_nonzero(exp)
+        nonIntersectArea = np.count_nonzero(mask != exp)
+        curRatio = float(nonIntersectArea) / expArea
+        return curRatio < maxDiffRatio
+
+    def scaleMask(self, mask):
+
+        return np.where((mask==cv2.GC_FGD) + (mask==cv2.GC_PR_FGD),255,0).astype('uint8')
+
+    def test_grabcut(self):
+
+        img = self.get_sample('cv/shared/airplane.png')
+        mask_prob = self.get_sample("cv/grabcut/mask_probpy.png", 0)
+        exp_mask1 = self.get_sample("cv/grabcut/exp_mask1py.png", 0)
+        exp_mask2 = self.get_sample("cv/grabcut/exp_mask2py.png", 0)
+
+        if img is None:
+            self.assertTrue(False, 'Missing test data')
+
+        rect = (24, 126, 459, 168)
+        mask = np.zeros(img.shape[:2], dtype = np.uint8)
+        bgdModel = np.zeros((1,65),np.float64)
+        fgdModel = np.zeros((1,65),np.float64)
+        cv2.grabCut(img, mask, rect, bgdModel, fgdModel, 0, cv2.GC_INIT_WITH_RECT)
+        cv2.grabCut(img, mask, rect, bgdModel, fgdModel, 2, cv2.GC_EVAL)
+
+        if mask_prob is None:
+            mask_prob = mask.copy()
+            cv2.imwrite(self.extraTestDataPath + '/cv/grabcut/mask_probpy.png', mask_prob)
+        if exp_mask1 is None:
+            exp_mask1 = self.scaleMask(mask)
+            cv2.imwrite(self.extraTestDataPath + '/cv/grabcut/exp_mask1py.png', exp_mask1)
+
+        self.assertEqual(self.verify(self.scaleMask(mask), exp_mask1), True)
+
+        mask = mask_prob
+        bgdModel = np.zeros((1,65),np.float64)
+        fgdModel = np.zeros((1,65),np.float64)
+        cv2.grabCut(img, mask, rect, bgdModel, fgdModel, 0, cv2.GC_INIT_WITH_MASK)
+        cv2.grabCut(img, mask, rect, bgdModel, fgdModel, 1, cv2.GC_EVAL)
+
+        if exp_mask2 is None:
+            exp_mask2 = self.scaleMask(mask)
+            cv2.imwrite(self.extraTestDataPath + '/cv/grabcut/exp_mask2py.png', exp_mask2)
+
+        self.assertEqual(self.verify(self.scaleMask(mask), exp_mask2), True)
\ No newline at end of file
diff --git a/modules/python/test/test_houghcircles.py b/modules/python/test/test_houghcircles.py
new file mode 100644
index 0000000..318153a
--- /dev/null
+++ b/modules/python/test/test_houghcircles.py
@@ -0,0 +1,81 @@
+#!/usr/bin/python
+
+'''
+This example illustrates how to use cv2.HoughCircles() function.
+'''
+
+# Python 2/3 compatibility
+from __future__ import print_function
+
+import cv2
+import numpy as np
+import sys
+from numpy import pi, sin, cos
+
+from tests_common import NewOpenCVTests
+
+def circleApproximation(circle):
+
+    nPoints = 30
+    phi = 0
+    dPhi = 2*pi / nPoints
+    contour = []
+    for i in range(nPoints):
+        contour.append(([circle[0] + circle[2]*cos(i*dPhi),
+            circle[1] + circle[2]*sin(i*dPhi)]))
+
+    return np.array(contour).astype(int)
+
+def convContoursIntersectiponRate(c1, c2):
+
+    s1 = cv2.contourArea(c1)
+    s2 = cv2.contourArea(c2)
+
+    s, _ = cv2.intersectConvexConvex(c1, c2)
+
+    return 2*s/(s1+s2)
+
+class houghcircles_test(NewOpenCVTests):
+
+    def test_houghcircles(self):
+
+        fn = "samples/data/board.jpg"
+
+        src = self.get_sample(fn, 1)
+        img = cv2.cvtColor(src, cv2.COLOR_BGR2GRAY)
+        img = cv2.medianBlur(img, 5)
+
+        circles = cv2.HoughCircles(img, cv2.HOUGH_GRADIENT, 1, 10, np.array([]), 100, 30, 1, 30)[0]
+
+        testCircles = [[38, 181, 17.6],
+        [99.7, 166, 13.12],
+        [142.7, 160, 13.52],
+        [223.6, 110, 8.62],
+        [79.1, 206.7, 8.62],
+        [47.5, 351.6, 11.64],
+        [189.5, 354.4, 11.64],
+        [189.8, 298.9, 10.64],
+        [189.5, 252.4, 14.62],
+        [252.5, 393.4, 15.62],
+        [602.9, 467.5, 11.42],
+        [222, 210.4, 9.12],
+        [263.1, 216.7, 9.12],
+        [359.8, 222.6, 9.12],
+        [518.9, 120.9, 9.12],
+        [413.8, 113.4, 9.12],
+        [489, 127.2, 9.12],
+        [448.4, 121.3, 9.12],
+        [384.6, 128.9, 8.62]]
+
+        matches_counter = 0
+
+        for i in range(len(testCircles)):
+            for j in range(len(circles)):
+
+                tstCircle = circleApproximation(testCircles[i])
+                circle = circleApproximation(circles[j])
+                if convContoursIntersectiponRate(tstCircle, circle) > 0.6:
+                    matches_counter += 1
+
+        self.assertGreater(float(matches_counter) / len(testCircles), .5)
+        self.assertLess(float(len(circles) - matches_counter) / len(circles), .75)
\ No newline at end of file
diff --git a/modules/python/test/test_houghlines.py b/modules/python/test/test_houghlines.py
new file mode 100644
index 0000000..9f056ce
--- /dev/null
+++ b/modules/python/test/test_houghlines.py
@@ -0,0 +1,65 @@
+#!/usr/bin/python
+
+'''
+This example illustrates how to use Hough Transform to find lines
+'''
+
+# Python 2/3 compatibility
+from __future__ import print_function
+
+import cv2
+import numpy as np
+import sys
+import math
+
+from tests_common import NewOpenCVTests
+
+def linesDiff(line1, line2):
+
+    norm1 = cv2.norm(line1 - line2, cv2.NORM_L2)
+    line3 = line1[2:4] + line1[0:2]
+    norm2 = cv2.norm(line3 - line2, cv2.NORM_L2)
+
+    return min(norm1, norm2)
+
+class houghlines_test(NewOpenCVTests):
+
+    def test_houghlines(self):
+
+        fn = "/samples/data/pic1.png"
+
+        src = self.get_sample(fn)
+        dst = cv2.Canny(src, 50, 200)
+
+        lines = cv2.HoughLinesP(dst, 1, math.pi/180.0, 40, np.array([]), 50, 10)[:,0,:]
+
+        eps = 5
+        testLines = [
+            #rect1
+             [ 232,  25, 43, 25],
+             [ 43, 129, 232, 129],
+             [ 43, 129,  43,  25],
+             [232, 129, 232,  25],
+            #rect2
+             [251,  86, 314, 183],
+             [252,  86, 323,  40],
+             [315, 183, 386, 137],
+             [324,  40, 386, 136],
+            #triangle
+             [245, 205, 377, 205],
+             [244, 206, 305, 278],
+             [306, 279, 377, 205],
+            #rect3
+             [153, 177, 196, 177],
+             [153, 277, 153, 179],
+             [153, 277, 196, 277],
+             [196, 177, 196, 277]]
+
+        matches_counter = 0
+
+        for i in range(len(testLines)):
+            for j in range(len(lines)):
+                if linesDiff(testLines[i], lines[j]) < eps:
+                    matches_counter += 1
+
+        self.assertGreater(float(matches_counter) / len(testLines), .7)
\ No newline at end of file
diff --git a/modules/python/test/test_kmeans.py b/modules/python/test/test_kmeans.py
new file mode 100644
index 0000000..4f886d9
--- /dev/null
+++ b/modules/python/test/test_kmeans.py
@@ -0,0 +1,70 @@
+#!/usr/bin/env python
+
+'''
+K-means clusterization test
+'''
+
+# Python 2/3 compatibility
+from __future__ import print_function
+
+import numpy as np
+import cv2
+from numpy import random
+import sys
+PY3 = sys.version_info[0] == 3
+if PY3:
+    xrange = range
+
+from tests_common import NewOpenCVTests
+
+def make_gaussians(cluster_n, img_size):
+    points = []
+    ref_distrs = []
+    sizes = []
+    for i in xrange(cluster_n):
+        mean = (0.1 + 0.8*random.rand(2)) * img_size
+        a = (random.rand(2, 2)-0.5)*img_size*0.1
+        cov = np.dot(a.T, a) + img_size*0.05*np.eye(2)
+        n = 100 + random.randint(900)
+        pts = random.multivariate_normal(mean, cov, n)
+        points.append( pts )
+        ref_distrs.append( (mean, cov) )
+        sizes.append(n)
+    points = np.float32( np.vstack(points) )
+    return points, ref_distrs, sizes
+
+def getMainLabelConfidence(labels, nLabels):
+
+    n = len(labels)
+    labelsDict = dict.fromkeys(range(nLabels), 0)
+    labelsConfDict = dict.fromkeys(range(nLabels))
+
+    for i in range(n):
+        labelsDict[labels[i][0]] += 1
+
+    for i in range(nLabels):
+        labelsConfDict[i] = float(labelsDict[i]) / n
+
+    return max(labelsConfDict.values())
+
+class kmeans_test(NewOpenCVTests):
+
+    def test_kmeans(self):
+
+        np.random.seed(10)
+
+        cluster_n = 5
+        img_size = 512
+
+        points, _, clusterSizes = make_gaussians(cluster_n, img_size)
+
+        term_crit = (cv2.TERM_CRITERIA_EPS, 30, 0.1)
+        ret, labels, centers = cv2.kmeans(points, cluster_n, None, term_crit, 10, 0)
+
+        self.assertEqual(len(centers), cluster_n)
+
+        offset = 0
+        for i in range(cluster_n):
+            confidence = getMainLabelConfidence(labels[offset : (offset + clusterSizes[i])], cluster_n)
+            offset += clusterSizes[i]
+            self.assertGreater(confidence, 0.9)
\ No newline at end of file
diff --git a/modules/python/test/test_letter_recog.py b/modules/python/test/test_letter_recog.py
new file mode 100644
index 0000000..574741f
--- /dev/null
+++ b/modules/python/test/test_letter_recog.py
@@ -0,0 +1,167 @@
+#!/usr/bin/env python
+
+'''
+The sample demonstrates how to train Random Trees classifier
+(or Boosting classifier, or MLP, or Knearest, or Support Vector Machines) using the provided dataset.
+
+We use the sample database letter-recognition.data
+from UCI Repository, here is the link:
+
+Newman, D.J. & Hettich, S. & Blake, C.L. & Merz, C.J. (1998).
+UCI Repository of machine learning databases
+[http://www.ics.uci.edu/~mlearn/MLRepository.html].
+Irvine, CA: University of California, Department of Information and Computer Science.
+
+The dataset consists of 20000 feature vectors along with the
+responses - capital latin letters A..Z.
+The first 10000 samples are used for training
+and the remaining 10000 - to test the classifier.
+======================================================
+  Models: RTrees, KNearest, Boost, SVM, MLP
+'''
+
+# Python 2/3 compatibility
+from __future__ import print_function
+
+import numpy as np
+import cv2
+
+def load_base(fn):
+    a = np.loadtxt(fn, np.float32, delimiter=',', converters={ 0 : lambda ch : ord(ch)-ord('A') })
+    samples, responses = a[:,1:], a[:,0]
+    return samples, responses
+
+class LetterStatModel(object):
+    class_n = 26
+    train_ratio = 0.5
+
+    def load(self, fn):
+        self.model.load(fn)
+    def save(self, fn):
+        self.model.save(fn)
+
+    def unroll_samples(self, samples):
+        sample_n, var_n = samples.shape
+        new_samples = np.zeros((sample_n * self.class_n, var_n+1), np.float32)
+        new_samples[:,:-1] = np.repeat(samples, self.class_n, axis=0)
+        new_samples[:,-1] = np.tile(np.arange(self.class_n), sample_n)
+        return new_samples
+
+    def unroll_responses(self, responses):
+        sample_n = len(responses)
+        new_responses = np.zeros(sample_n*self.class_n, np.int32)
+        resp_idx = np.int32( responses + np.arange(sample_n)*self.class_n )
+        new_responses[resp_idx] = 1
+        return new_responses
+
+class RTrees(LetterStatModel):
+    def __init__(self):
+        self.model = cv2.ml.RTrees_create()
+
+    def train(self, samples, responses):
+        sample_n, var_n = samples.shape
+        self.model.setMaxDepth(20)
+        self.model.train(samples, cv2.ml.ROW_SAMPLE, responses.astype(int))
+
+    def predict(self, samples):
+        ret, resp = self.model.predict(samples)
+        return resp.ravel()
+
+
+class KNearest(LetterStatModel):
+    def __init__(self):
+        self.model = cv2.ml.KNearest_create()
+
+    def train(self, samples, responses):
+        self.model.train(samples, cv2.ml.ROW_SAMPLE, responses)
+
+    def predict(self, samples):
+        retval, results, neigh_resp, dists = self.model.findNearest(samples, k = 10)
+        return results.ravel()
+
+
+class Boost(LetterStatModel):
+    def __init__(self):
+        self.model = cv2.ml.Boost_create()
+
+    def train(self, samples, responses):
+        sample_n, var_n = samples.shape
+        new_samples = self.unroll_samples(samples)
+        new_responses = self.unroll_responses(responses)
+        var_types = np.array([cv2.ml.VAR_NUMERICAL] * var_n + [cv2.ml.VAR_CATEGORICAL, cv2.ml.VAR_CATEGORICAL], np.uint8)
+
+        self.model.setWeakCount(15)
+        self.model.setMaxDepth(10)
+        self.model.train(cv2.ml.TrainData_create(new_samples, cv2.ml.ROW_SAMPLE, new_responses.astype(int), varType = var_types))
+
+    def predict(self, samples):
+        new_samples = self.unroll_samples(samples)
+        ret, resp = self.model.predict(new_samples)
+
+        return resp.ravel().reshape(-1, self.class_n).argmax(1)
+
+
+class SVM(LetterStatModel):
+    def __init__(self):
+        self.model = cv2.ml.SVM_create()
+
+    def train(self, samples, responses):
+        self.model.setType(cv2.ml.SVM_C_SVC)
+        self.model.setC(1)
+        self.model.setKernel(cv2.ml.SVM_RBF)
+        self.model.setGamma(.1)
+        self.model.train(samples, cv2.ml.ROW_SAMPLE, responses.astype(int))
+
+    def predict(self, samples):
+        ret, resp = self.model.predict(samples)
+        return resp.ravel()
+
+
+class MLP(LetterStatModel):
+    def __init__(self):
+        self.model = cv2.ml.ANN_MLP_create()
+
+    def train(self, samples, responses):
+        sample_n, var_n = samples.shape
+        new_responses = self.unroll_responses(responses).reshape(-1, self.class_n)
+        layer_sizes = np.int32([var_n, 100, 100, self.class_n])
+
+        self.model.setLayerSizes(layer_sizes)
+        self.model.setTrainMethod(cv2.ml.ANN_MLP_BACKPROP)
+        self.model.setBackpropMomentumScale(0)
+        self.model.setBackpropWeightScale(0.001)
+        self.model.setTermCriteria((cv2.TERM_CRITERIA_COUNT, 20, 0.01))
+        self.model.setActivationFunction(cv2.ml.ANN_MLP_SIGMOID_SYM, 2, 1)
+
+        self.model.train(samples, cv2.ml.ROW_SAMPLE, np.float32(new_responses))
+
+    def predict(self, samples):
+        ret, resp = self.model.predict(samples)
+        return resp.argmax(-1)
+
+from tests_common import NewOpenCVTests
+
+class letter_recog_test(NewOpenCVTests):
+
+    def test_letter_recog(self):
+
+        eps = 0.01
+
+        models = [RTrees, KNearest, Boost, SVM, MLP]
+        models = dict( [(cls.__name__.lower(), cls) for cls in models] )
+        testErrors = {RTrees: (98.930000, 92.390000), KNearest: (94.960000, 92.010000),
+         Boost: (85.970000, 74.920000), SVM: (99.780000, 95.680000), MLP: (90.060000, 87.410000)}
+
+        for model in models:
+            Model = models[model]
+            classifier = Model()
+
+            samples, responses = load_base(self.repoPath + '/samples/data/letter-recognition.data')
+            train_n = int(len(samples)*classifier.train_ratio)
+
+            classifier.train(samples[:train_n], responses[:train_n])
+            train_rate = np.mean(classifier.predict(samples[:train_n]) == responses[:train_n].astype(int))
+            test_rate  = np.mean(classifier.predict(samples[train_n:]) == responses[train_n:].astype(int))
+
+            self.assertLess(train_rate - testErrors[Model][0], eps)
+            self.assertLess(test_rate - testErrors[Model][1], eps)
\ No newline at end of file
diff --git a/modules/python/test/test_lk_homography.py b/modules/python/test/test_lk_homography.py
new file mode 100644
index 0000000..8e526d0
--- /dev/null
+++ b/modules/python/test/test_lk_homography.py
@@ -0,0 +1,96 @@
+#!/usr/bin/env python
+
+'''
+Lucas-Kanade homography tracker test
+===============================
+Uses goodFeaturesToTrack for track initialization and back-tracking for match verification
+between frames. Finds homography between reference and current views.
+'''
+
+# Python 2/3 compatibility
+from __future__ import print_function
+
+import numpy as np
+import cv2
+
+#local modules
+from tst_scene_render import TestSceneRender
+from tests_common import NewOpenCVTests, isPointInRect
+
+lk_params = dict( winSize  = (19, 19),
+                  maxLevel = 2,
+                  criteria = (cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 10, 0.03))
+
+feature_params = dict( maxCorners = 1000,
+                       qualityLevel = 0.01,
+                       minDistance = 8,
+                       blockSize = 19 )
+
+def checkedTrace(img0, img1, p0, back_threshold = 1.0):
+    p1, st, err = cv2.calcOpticalFlowPyrLK(img0, img1, p0, None, **lk_params)
+    p0r, st, err = cv2.calcOpticalFlowPyrLK(img1, img0, p1, None, **lk_params)
+    d = abs(p0-p0r).reshape(-1, 2).max(-1)
+    status = d < back_threshold
+    return p1, status
+
+class lk_homography_test(NewOpenCVTests):
+
+    render = None
+    framesCounter = 0
+    frame = frame0 = None
+    p0 = None
+    p1 = None
+    gray0 = gray1 = None
+    numFeaturesInRectOnStart = 0
+
+    def test_lk_homography(self):
+        self.render = TestSceneRender(self.get_sample('samples/data/graf1.png'),
+            self.get_sample('samples/data/box.png'), noise = 0.1, speed = 1.0)
+
+        frame = self.render.getNextFrame()
+        frame_gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
+        self.frame0 = frame.copy()
+        self.p0 = cv2.goodFeaturesToTrack(frame_gray, **feature_params)
+
+        isForegroundHomographyFound = False
+
+        if self.p0 is not None:
+            self.p1 = self.p0
+            self.gray0 = frame_gray
+            self.gray1 = frame_gray
+            currRect = self.render.getCurrentRect()
+            for (x,y) in self.p0[:,0]:
+                if isPointInRect((x,y), currRect):
+                    self.numFeaturesInRectOnStart += 1
+
+        while self.framesCounter < 200:
+            self.framesCounter += 1
+            frame = self.render.getNextFrame()
+            frame_gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
+            if self.p0 is not None:
+                p2, trace_status = checkedTrace(self.gray1, frame_gray, self.p1)
+
+                self.p1 = p2[trace_status].copy()
+                self.p0 = self.p0[trace_status].copy()
+                self.gray1 = frame_gray
+
+                if len(self.p0) < 4:
+                    self.p0 = None
+                    continue
+                H, status = cv2.findHomography(self.p0, self.p1, cv2.RANSAC, 5.0)
+
+                goodPointsInRect = 0
+                goodPointsOutsideRect = 0
+                for (x0, y0), (x1, y1), good in zip(self.p0[:,0], self.p1[:,0], status[:,0]):
+                    if good:
+                        if isPointInRect((x1,y1), self.render.getCurrentRect()):
+                            goodPointsInRect += 1
+                        else: goodPointsOutsideRect += 1
+
+                if goodPointsOutsideRect < goodPointsInRect:
+                    isForegroundHomographyFound = True
+                    self.assertGreater(float(goodPointsInRect) / (self.numFeaturesInRectOnStart + 1), 0.6)
+            else:
+                p = cv2.goodFeaturesToTrack(frame_gray, **feature_params)
+
+        self.assertEqual(isForegroundHomographyFound, True)
\ No newline at end of file
diff --git a/modules/python/test/test_lk_track.py b/modules/python/test/test_lk_track.py
new file mode 100644
index 0000000..ccc67a5
--- /dev/null
+++ b/modules/python/test/test_lk_track.py
@@ -0,0 +1,111 @@
+#!/usr/bin/env python
+
+'''
+Lucas-Kanade tracker
+====================
+
+Lucas-Kanade sparse optical flow demo. Uses goodFeaturesToTrack
+for track initialization and back-tracking for match verification
+between frames.
+'''
+
+# Python 2/3 compatibility
+from __future__ import print_function
+
+import numpy as np
+import cv2
+
+#local modules
+from tst_scene_render import TestSceneRender
+from tests_common import NewOpenCVTests, intersectionRate, isPointInRect
+
+lk_params = dict( winSize  = (15, 15),
+                  maxLevel = 2,
+                  criteria = (cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 10, 0.03))
+
+feature_params = dict( maxCorners = 500,
+                       qualityLevel = 0.3,
+                       minDistance = 7,
+                       blockSize = 7 )
+
+def getRectFromPoints(points):
+
+    distances = []
+    for point in points:
+        distances.append(cv2.norm(point, cv2.NORM_L2))
+
+    x0, y0 = points[np.argmin(distances)]
+    x1, y1 = points[np.argmax(distances)]
+
+    return np.array([x0, y0, x1, y1])
+
+
+class lk_track_test(NewOpenCVTests):
+
+    track_len = 10
+    detect_interval = 5
+    tracks = []
+    frame_idx = 0
+    render = None
+
+    def test_lk_track(self):
+
+        self.render = TestSceneRender(self.get_sample('samples/data/graf1.png'), self.get_sample('samples/data/box.png'))
+        self.runTracker()
+
+    def runTracker(self):
+        foregroundPointsNum = 0
+
+        while True:
+            frame = self.render.getNextFrame()
+            frame_gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
+
+            if len(self.tracks) > 0:
+                img0, img1 = self.prev_gray, frame_gray
+                p0 = np.float32([tr[-1][0] for tr in self.tracks]).reshape(-1, 1, 2)
+                p1, st, err = cv2.calcOpticalFlowPyrLK(img0, img1, p0, None, **lk_params)
+                p0r, st, err = cv2.calcOpticalFlowPyrLK(img1, img0, p1, None, **lk_params)
+                d = abs(p0-p0r).reshape(-1, 2).max(-1)
+                good = d < 1
+                new_tracks = []
+                for tr, (x, y), good_flag in zip(self.tracks, p1.reshape(-1, 2), good):
+                    if not good_flag:
+                        continue
+                    tr.append([(x, y), self.frame_idx])
+                    if len(tr) > self.track_len:
+                        del tr[0]
+                    new_tracks.append(tr)
+                self.tracks = new_tracks
+
+            if self.frame_idx % self.detect_interval == 0:
+                goodTracksCount = 0
+                for tr in self.tracks:
+                    oldRect = self.render.getRectInTime(self.render.timeStep * tr[0][1])
+                    newRect = self.render.getRectInTime(self.render.timeStep * tr[-1][1])
+                    if isPointInRect(tr[0][0], oldRect) and isPointInRect(tr[-1][0], newRect):
+                        goodTracksCount += 1
+
+                if self.frame_idx == self.detect_interval:
+                    foregroundPointsNum = goodTracksCount
+
+                fgIndex = float(foregroundPointsNum) / (foregroundPointsNum + 1)
+                fgRate = float(goodTracksCount) / (len(self.tracks) + 1)
+
+                if self.frame_idx > 0:
+                    self.assertGreater(fgIndex, 0.9)
+                    self.assertGreater(fgRate, 0.2)
+
+                mask = np.zeros_like(frame_gray)
+                mask[:] = 255
+                for x, y in [np.int32(tr[-1][0]) for tr in self.tracks]:
+                    cv2.circle(mask, (x, y), 5, 0, -1)
+                p = cv2.goodFeaturesToTrack(frame_gray, mask = mask, **feature_params)
+                if p is not None:
+                    for x, y in np.float32(p).reshape(-1, 2):
+                        self.tracks.append([[(x, y), self.frame_idx]])
+
+            self.frame_idx += 1
+            self.prev_gray = frame_gray
+
+            if self.frame_idx > 300:
+                break
\ No newline at end of file
diff --git a/modules/python/test/test_morphology.py b/modules/python/test/test_morphology.py
new file mode 100644
index 0000000..309c80c
--- /dev/null
+++ b/modules/python/test/test_morphology.py
@@ -0,0 +1,51 @@
+#!/usr/bin/env python
+
+'''
+Morphology operations.
+'''
+
+# Python 2/3 compatibility
+from __future__ import print_function
+import sys
+PY3 = sys.version_info[0] == 3
+
+import numpy as np
+import cv2
+
+from tests_common import NewOpenCVTests
+
+class morphology_test(NewOpenCVTests):
+
+    def test_morphology(self):
+
+        fn = 'samples/data/rubberwhale1.png'
+        img = self.get_sample(fn)
+
+        modes = ['erode/dilate', 'open/close', 'blackhat/tophat', 'gradient']
+        str_modes = ['ellipse', 'rect', 'cross']
+
+        referenceHashes = { modes[0]: '071a526425b79e45b4d0d71ef51b0562', modes[1] : '071a526425b79e45b4d0d71ef51b0562',
+            modes[2] : '427e89f581b7df1b60a831b1ed4c8618', modes[3] : '0dd8ad251088a63d0dd022bcdc57361c'}
+
+        def update(cur_mode):
+            cur_str_mode = str_modes[0]
+            sz = 10
+            iters = 1
+            opers = cur_mode.split('/')
+            if len(opers) > 1:
+                sz = sz - 10
+                op = opers[sz > 0]
+                sz = abs(sz)
+            else:
+                op = opers[0]
+            sz = sz*2+1
+
+            str_name = 'MORPH_' + cur_str_mode.upper()
+            oper_name = 'MORPH_' + op.upper()
+
+            st = cv2.getStructuringElement(getattr(cv2, str_name), (sz, sz))
+            return cv2.morphologyEx(img, getattr(cv2, oper_name), st, iterations=iters)
+
+        for mode in modes:
+            res = update(mode)
+            self.assertEqual(self.hashimg(res), referenceHashes[mode])
\ No newline at end of file
diff --git a/modules/python/test/test_mser.py b/modules/python/test/test_mser.py
new file mode 100644
index 0000000..f66582e
--- /dev/null
+++ b/modules/python/test/test_mser.py
@@ -0,0 +1,69 @@
+#!/usr/bin/env python
+
+'''
+MSER detector test
+'''
+# Python 2/3 compatibility
+from __future__ import print_function
+
+import numpy as np
+import cv2
+
+from tests_common import NewOpenCVTests
+
+class mser_test(NewOpenCVTests):
+    def test_mser(self):
+
+        img = self.get_sample('cv/mser/puzzle.png', 0)
+        smallImg = [
+         [255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],
+         [255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],
+         [255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],
+         [255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],
+         [255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],
+         [255, 255, 255, 255, 255,   0,   0,   0,   0, 255, 255, 255, 255, 255, 255, 255, 255, 255,   0,   0,   0,   0, 255, 255, 255, 255],
+         [255, 255, 255, 255, 255,   0,   0,   0,   0,   0, 255, 255, 255, 255, 255, 255, 255, 255,   0,   0,   0,   0, 255, 255, 255, 255],
+         [255, 255, 255, 255, 255,   0,   0,   0,   0,   0, 255, 255, 255, 255, 255, 255, 255, 255,   0,   0,   0,   0, 255, 255, 255, 255],
+         [255, 255, 255, 255, 255,   0,   0,   0,   0, 255, 255, 255, 255, 255, 255, 255, 255, 255,   0,   0,   0,   0, 255, 255, 255, 255],
+         [255, 255, 255, 255, 255, 255,   0,   0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,   0,   0, 255, 255, 255, 255, 255],
+         [255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],
+         [255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],
+         [255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255],
+         [255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255]
+        ]
+        thresharr = [ 0, 70, 120, 180, 255 ]
+        kDelta = 5
+        mserExtractor = cv2.MSER_create()
+        mserExtractor.setDelta(kDelta)
+        np.random.seed(10)
+
+        for i in range(100):
+
+            use_big_image = int(np.random.rand(1,1)*7) != 0
+            invert = int(np.random.rand(1,1)*2) != 0
+            binarize = int(np.random.rand(1,1)*5) != 0 if use_big_image else False
+            blur = int(np.random.rand(1,1)*2) != 0
+            thresh = thresharr[int(np.random.rand(1,1)*5)]
+            src0 = img if use_big_image else np.array(smallImg).astype('uint8')
+            src = src0.copy()
+
+            kMinArea = 256 if use_big_image else 10
+            kMaxArea = int(src.shape[0]*src.shape[1]/4)
+
+            mserExtractor.setMinArea(kMinArea)
+            mserExtractor.setMaxArea(kMaxArea)
+            if invert:
+                cv2.bitwise_not(src, src)
+            if binarize:
+                _, src = cv2.threshold(src, thresh, 255, cv2.THRESH_BINARY)
+            if blur:
+                src = cv2.GaussianBlur(src, (5, 5), 1.5, 1.5)
+            minRegs = 7 if use_big_image else 2
+            maxRegs = 1000 if use_big_image else 20
+            if binarize and (thresh == 0 or thresh == 255):
+                minRegs = maxRegs = 0
+            msers, boxes = mserExtractor.detectRegions(src)
+            nmsers = len(msers)
+            self.assertEqual(nmsers, len(boxes))
+            self.assertLessEqual(minRegs, nmsers)
+            self.assertGreaterEqual(maxRegs, nmsers)
diff --git a/modules/python/test/test_peopledetect.py b/modules/python/test/test_peopledetect.py
new file mode 100644
index 0000000..fb0a9e9
--- /dev/null
+++ b/modules/python/test/test_peopledetect.py
@@ -0,0 +1,62 @@
+#!/usr/bin/env python
+
+'''
+example to detect upright people in images using HOG features
+'''
+
+# Python 2/3 compatibility
+from __future__ import print_function
+
+import numpy as np
+import cv2
+
+
+def inside(r, q):
+    rx, ry, rw, rh = r
+    qx, qy, qw, qh = q
+    return rx > qx and ry > qy and rx + rw < qx + qw and ry + rh < qy + qh
+
+from tests_common import NewOpenCVTests, intersectionRate
+
+class peopledetect_test(NewOpenCVTests):
+    def test_peopledetect(self):
+
+        hog = cv2.HOGDescriptor()
+        hog.setSVMDetector( cv2.HOGDescriptor_getDefaultPeopleDetector() )
+
+        dirPath = 'samples/data/'
+        samples = ['basketball1.png', 'basketball2.png']
+
+        testPeople = [
+        [[23, 76, 164, 477], [440, 22, 637, 478]],
+        [[23, 76, 164, 477], [440, 22, 637, 478]]
+        ]
+
+        eps = 0.5
+
+        for sample in samples:
+
+            img = self.get_sample(dirPath + sample, 0)
+
+            found, w = hog.detectMultiScale(img, winStride=(8,8), padding=(32,32), scale=1.05)
+            found_filtered = []
+            for ri, r in enumerate(found):
+                for qi, q in enumerate(found):
+                    if ri != qi and inside(r, q):
+                        break
+                else:
+                    found_filtered.append(r)
+
+            matches = 0
+
+            for i in range(len(found_filtered)):
+                for j in range(len(testPeople)):
+
+                    found_rect = (found_filtered[i][0], found_filtered[i][1],
+                        found_filtered[i][0] + found_filtered[i][2],
+                        found_filtered[i][1] + found_filtered[i][3])
+
+                    if intersectionRate(found_rect, testPeople[j][0]) > eps or intersectionRate(found_rect, testPeople[j][1]) > eps:
+                        matches += 1
+
+            self.assertGreater(matches, 0)
\ No newline at end of file
diff --git a/modules/python/test/test_squares.py b/modules/python/test/test_squares.py
new file mode 100644
index 0000000..214c64b
--- /dev/null
+++ b/modules/python/test/test_squares.py
@@ -0,0 +1,96 @@
+#!/usr/bin/env python
+
+'''
+Simple "Square Detector" program.
+
+Loads several images sequentially and tries to find squares in each image.
+'''
+
+# Python 2/3 compatibility
+import sys
+PY3 = sys.version_info[0] == 3
+
+if PY3:
+    xrange = range
+
+import numpy as np
+import cv2
+
+
+def angle_cos(p0, p1, p2):
+    d1, d2 = (p0-p1).astype('float'), (p2-p1).astype('float')
+    return abs( np.dot(d1, d2) / np.sqrt( np.dot(d1, d1)*np.dot(d2, d2) ) )
+
+def find_squares(img):
+    img = cv2.GaussianBlur(img, (5, 5), 0)
+    squares = []
+    for gray in cv2.split(img):
+        for thrs in xrange(0, 255, 26):
+            if thrs == 0:
+                bin = cv2.Canny(gray, 0, 50, apertureSize=5)
+                bin = cv2.dilate(bin, None)
+            else:
+                retval, bin = cv2.threshold(gray, thrs, 255, cv2.THRESH_BINARY)
+            bin, contours, hierarchy = cv2.findContours(bin, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
+            for cnt in contours:
+                cnt_len = cv2.arcLength(cnt, True)
+                cnt = cv2.approxPolyDP(cnt, 0.02*cnt_len, True)
+                if len(cnt) == 4 and cv2.contourArea(cnt) > 1000 and cv2.isContourConvex(cnt):
+                    cnt = cnt.reshape(-1, 2)
+                    max_cos = np.max([angle_cos( cnt[i], cnt[(i+1) % 4], cnt[(i+2) % 4] ) for i in xrange(4)])
+                    if max_cos < 0.1 and filterSquares(squares, cnt):
+                        squares.append(cnt)
+
+    return squares
+
+def intersectionRate(s1, s2):
+    area, intersection = cv2.intersectConvexConvex(np.array(s1), np.array(s2))
+    return 2 * area / (cv2.contourArea(np.array(s1)) + cv2.contourArea(np.array(s2)))
+
+def filterSquares(squares, square):
+
+    for i in range(len(squares)):
+        if intersectionRate(squares[i], square) > 0.95:
+            return False
+
+    return True
+
+from tests_common import NewOpenCVTests
+
+class squares_test(NewOpenCVTests):
+
+    def test_squares(self):
+
+        img = self.get_sample('samples/data/pic1.png')
+        squares = find_squares(img)
+
+        testSquares = [
+        [[43, 25],
+        [43, 129],
+        [232, 129],
+        [232, 25]],
+
+        [[252, 87],
+        [324, 40],
+        [387, 137],
+        [315, 184]],
+
+        [[154, 178],
+        [196, 180],
+        [198, 278],
+        [154, 278]],
+
+        [[0, 0],
+        [400, 0],
+        [400, 300],
+        [0, 300]]
+        ]
+
+        matches_counter = 0
+        for i in range(len(squares)):
+            for j in range(len(testSquares)):
+                if intersectionRate(squares[i], testSquares[j]) > 0.9:
+                    matches_counter += 1
+
+        self.assertGreater(matches_counter / len(testSquares), 0.9)
+        self.assertLess( (len(squares) - matches_counter) / len(squares), 0.2)
\ No newline at end of file
diff --git a/modules/python/test/test_texture_flow.py b/modules/python/test/test_texture_flow.py
new file mode 100644
index 0000000..b0f5520
--- /dev/null
+++ b/modules/python/test/test_texture_flow.py
@@ -0,0 +1,44 @@
+#!/usr/bin/env python
+
+'''
+Texture flow direction estimation.
+
+Sample shows how cv2.cornerEigenValsAndVecs function can be used
+to estimate image texture flow direction.
+'''
+
+# Python 2/3 compatibility
+from __future__ import print_function
+
+import numpy as np
+import cv2
+import sys
+
+from tests_common import NewOpenCVTests
+
+
+class texture_flow_test(NewOpenCVTests):
+
+    def test_texture_flow(self):
+
+        img = self.get_sample('samples/data/chessboard.png')
+
+        gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
+        h, w = img.shape[:2]
+
+        eigen = cv2.cornerEigenValsAndVecs(gray, 5, 3)
+        eigen = eigen.reshape(h, w, 3, 2)  # [[e1, e2], v1, v2]
+        flow = eigen[:,:,2]
+
+        d = 300
+        eps = d / 30
+
+        points =  np.dstack( np.mgrid[d/2:w:d, d/2:h:d] ).reshape(-1, 2)
+
+        textureVectors = []
+        for x, y in np.int32(points):
+            textureVectors.append(np.int32(flow[y, x]*d))
+
+        for i in range(len(textureVectors)):
+            self.assertTrue(cv2.norm(textureVectors[i], cv2.NORM_L2) < eps
+            or abs(cv2.norm(textureVectors[i], cv2.NORM_L2) - d) < eps)
diff --git a/modules/python/test/test_watershed.py b/modules/python/test/test_watershed.py
new file mode 100644
index 0000000..0a1d222
--- /dev/null
+++ b/modules/python/test/test_watershed.py
@@ -0,0 +1,33 @@
+#!/usr/bin/env python
+
+'''
+Watershed segmentation test
+'''
+
+# Python 2/3 compatibility
+from __future__ import print_function
+
+import numpy as np
+import cv2
+
+from tests_common import NewOpenCVTests
+
+class watershed_test(NewOpenCVTests):
+    def test_watershed(self):
+
+        img = self.get_sample('cv/inpaint/orig.png')
+        markers = self.get_sample('cv/watershed/wshed_exp.png', 0)
+        refSegments = self.get_sample('cv/watershed/wshed_segments.png')
+
+        if img is None or markers is None:
+            self.assertEqual(0, 1, 'Missing test data')
+
+        colors = np.int32( list(np.ndindex(3, 3, 3)) ) * 122
+        cv2.watershed(img, np.int32(markers))
+        segments = colors[np.maximum(markers, 0)]
+
+        if refSegments is None:
+            refSegments = segments.copy()
+            cv2.imwrite(self.extraTestDataPath + '/cv/watershed/wshed_segments.png', refSegments)
+
+        self.assertLess(cv2.norm(segments - refSegments, cv2.NORM_L1) / 255.0, 50)
\ No newline at end of file
diff --git a/modules/python/test/tests_common.py b/modules/python/test/tests_common.py
new file mode 100644
index 0000000..17ef0dc
--- /dev/null
+++ b/modules/python/test/tests_common.py
@@ -0,0 +1,80 @@
+#!/usr/bin/env python
+
+from __future__ import print_function
+
+import unittest
+import sys
+import hashlib
+import os
+import numpy as np
+import cv2
+
+# Python 3 moved urlopen to urllib.requests
+try:
+    from urllib.request import urlopen
+except ImportError:
+    from urllib import urlopen
+
+class NewOpenCVTests(unittest.TestCase):
+
+    # path to local repository folder containing 'samples' folder
+    repoPath = None
+    extraTestDataPath = None
+    # github repository url
+    repoUrl = 'https://raw.github.com/opencv/opencv/master'
+
+    def get_sample(self, filename, iscolor = cv2.IMREAD_COLOR):
+        if not filename in self.image_cache:
+            filedata = None
+            if NewOpenCVTests.repoPath is not None:
+                candidate = NewOpenCVTests.repoPath + '/' + filename
+                if os.path.isfile(candidate):
+                    with open(candidate, 'rb') as f:
+                        filedata = f.read()
+            if NewOpenCVTests.extraTestDataPath is not None:
+                candidate = NewOpenCVTests.extraTestDataPath + '/' + filename
+                if os.path.isfile(candidate):
+                    with open(candidate, 'rb') as f:
+                        filedata = f.read()
+            if filedata is None:
+                return None#filedata = urlopen(NewOpenCVTests.repoUrl + '/' + filename).read()
+            self.image_cache[filename] = cv2.imdecode(np.fromstring(filedata, dtype=np.uint8), iscolor)
+        return self.image_cache[filename]
+
+    def setUp(self):
+        cv2.setRNGSeed(10)
+        self.image_cache = {}
+
+    def hashimg(self, im):
+        """ Compute a hash for an image, useful for image comparisons """
+        return hashlib.md5(im.tostring()).hexdigest()
+
+    if sys.version_info[:2] == (2, 6):
+        def assertLess(self, a, b, msg=None):
+            if not a < b:
+                self.fail('%s not less than %s' % (repr(a), repr(b)))
+
+        def assertLessEqual(self, a, b, msg=None):
+            if not a <= b:
+                self.fail('%s not less than or equal to %s' % (repr(a), repr(b)))
+
+        def assertGreater(self, a, b, msg=None):
+            if not a > b:
+                self.fail('%s not greater than %s' % (repr(a), repr(b)))
+
+def intersectionRate(s1, s2):
+
+    x1, y1, x2, y2 = s1
+    s1 = np.array([[x1, y1], [x2,y1], [x2, y2], [x1, y2]])
+
+    x1, y1, x2, y2 = s2
+    s2 = np.array([[x1, y1], [x2,y1], [x2, y2], [x1, y2]])
+
+    area, intersection = cv2.intersectConvexConvex(s1, s2)
+    return 2 * area / (cv2.contourArea(s1) + cv2.contourArea(s2))
+
+def isPointInRect(p, rect):
+    if rect[0] <= p[0] and rect[1] <=p[1] and p[0] <= rect[2] and p[1] <= rect[3]:
+        return True
+    else:
+        return False
\ No newline at end of file
diff --git a/modules/python/test/ticket_6.py b/modules/python/test/ticket_6.py
deleted file mode 100755
index 7249ff2..0000000
--- a/modules/python/test/ticket_6.py
+++ /dev/null
@@ -1,78 +0,0 @@
-#!/usr/bin/env python
-
-import urllib
-import cv2.cv as cv
-import Image
-import unittest
-
-class TestLoadImage(unittest.TestCase):
-    def setUp(self):
-        open("large.jpg", "w").write(urllib.urlopen("http://www.cs.ubc.ca/labs/lci/curious_george/img/ROS_bug_imgs/IMG_3560.jpg").read())
-
-    def test_load(self):
-        pilim = Image.open("large.jpg")
-        cvim = cv.LoadImage("large.jpg")
-        self.assert_(len(pilim.tostring()) == len(cvim.tostring()))
-
-class Creating(unittest.TestCase):
-    size=(640, 480)
-    repeat=100
-    def test_0_Create(self):
-        image = cv.CreateImage(self.size, cv.IPL_DEPTH_8U, 1)
-        cnt=cv.CountNonZero(image)
-        self.assertEqual(cnt, 0, msg="Created image is not black. CountNonZero=%i" % cnt)
-
-    def test_2_CreateRepeat(self):
-        cnt=0
-        for i in range(self.repeat):
-            image = cv.CreateImage(self.size, cv.IPL_DEPTH_8U, 1)
-            cnt+=cv.CountNonZero(image)
-        self.assertEqual(cnt, 0, msg="Created images are not black. Mean CountNonZero=%.3f" % (1.*cnt/self.repeat))
-
-    def test_2a_MemCreated(self):
-        cnt=0
-        v=[]
-        for i in range(self.repeat):
-            image = cv.CreateImage(self.size, cv.IPL_DEPTH_8U, 1)
-            cv.FillPoly(image, [[(0, 0), (0, 100), (100, 0)]], 0)
-            cnt+=cv.CountNonZero(image)
-            v.append(image)
-        self.assertEqual(cnt, 0, msg="Memorized images are not black. Mean CountNonZero=%.3f" % (1.*cnt/self.repeat))
-
-    def test_3_tostirng(self):
-        image = cv.CreateImage(self.size, cv.IPL_DEPTH_8U, 1)
-        image.tostring()
-        cnt=cv.CountNonZero(image)
-        self.assertEqual(cnt, 0, msg="After tostring(): CountNonZero=%i" % cnt)
-
-    def test_40_tostringRepeat(self):
-        cnt=0
-        image = cv.CreateImage(self.size, cv.IPL_DEPTH_8U, 1)
-        cv.Set(image, cv.Scalar(0,0,0,0))
-        for i in range(self.repeat*100):
-            image.tostring()
-        cnt=cv.CountNonZero(image)
-        self.assertEqual(cnt, 0, msg="Repeating tostring(): Mean CountNonZero=%.3f" % (1.*cnt/self.repeat))
-
-    def test_41_CreateToStringRepeat(self):
-        cnt=0
-        for i in range(self.repeat*100):
-            image = cv.CreateImage(self.size, cv.IPL_DEPTH_8U, 1)
-            cv.Set(image, cv.Scalar(0,0,0,0))
-            image.tostring()
-            cnt+=cv.CountNonZero(image)
-        self.assertEqual(cnt, 0, msg="Repeating create and tostring(): Mean CountNonZero=%.3f" % (1.*cnt/self.repeat))
-
-    def test_4a_MemCreatedToString(self):
-        cnt=0
-        v=[]
-        for i in range(self.repeat):
-            image = cv.CreateImage(self.size, cv.IPL_DEPTH_8U, 1)
-            cv.Set(image, cv.Scalar(0,0,0,0))
-            image.tostring()
-            cnt+=cv.CountNonZero(image)
-            v.append(image)
-        self.assertEqual(cnt, 0, msg="Repeating and memorizing after tostring(): Mean CountNonZero=%.3f" % (1.*cnt/self.repeat))
-
-if __name__ == '__main__':
-    unittest.main()
diff --git a/modules/python/test/tickets.py b/modules/python/test/tickets.py
deleted file mode 100755
index de51e7a..0000000
--- a/modules/python/test/tickets.py
+++ /dev/null
@@ -1,91 +0,0 @@
-#!/usr/bin/env python
-
-import unittest
-import random
-import time
-import math
-import sys
-import array
-import os
-
-import cv2.cv as cv
-
-def find_sample(s):
-    for d in ["../samples/c/", "../doc/pics/"]:
-        path = os.path.join(d, s)
-        if os.access(path, os.R_OK):
-            return path
-    return s
-
-class TestTickets(unittest.TestCase):
-
-    def test_2542670(self):
-        xys = [(94, 121), (94, 122), (93, 123), (92, 123), (91, 124), (91, 125), (91, 126), (92, 127), (92, 128), (92, 129), (92, 130), (92, 131), (91, 132), (90, 131), (90, 130), (90, 131), (91, 132), (92, 133), (92, 134), (93, 135), (94, 136), (94, 137), (94, 138), (95, 139), (96, 140), (96, 141), (96, 142), (96, 143), (97, 144), (97, 145), (98, 146), (99, 146), (100, 146), (101, 146), (102, 146), (103, 146), (104, 146), (105, 146), (106, 146), (107, 146), (108, 146), (109, 146), (110, [...]
-
-        #xys = xys[:12] + xys[16:]
-        pts = cv.CreateMat(len(xys), 1, cv.CV_32SC2)
-        for i,(x,y) in enumerate(xys):
-            pts[i,0] = (x, y)
-        storage = cv.CreateMemStorage()
-        hull = cv.ConvexHull2(pts, storage)
-        hullp = cv.ConvexHull2(pts, storage, return_points = 1)
-        defects = cv.ConvexityDefects(pts, hull, storage)
-
-        vis = cv.CreateImage((1000,1000), 8, 3)
-        x0 = min([x for (x,y) in xys]) - 10
-        x1 = max([x for (x,y) in xys]) + 10
-        y0 = min([y for (y,y) in xys]) - 10
-        y1 = max([y for (y,y) in xys]) + 10
-        def xform(pt):
-            x,y = pt
-            return (1000 * (x - x0) / (x1 - x0),
-                    1000 * (y - y0) / (y1 - y0))
-
-        for d in defects[:2]:
-            cv.Zero(vis)
-
-            # First draw the defect as a red triangle
-            cv.FillConvexPoly(vis, [xform(p) for p in d[:3]], cv.RGB(255,0,0))
-
-            # Draw the convex hull as a thick green line
-            for a,b in zip(hullp, hullp[1:]):
-                cv.Line(vis, xform(a), xform(b), cv.RGB(0,128,0), 3)
-
-            # Draw the original contour as a white line
-            for a,b in zip(xys, xys[1:]):
-                cv.Line(vis, xform(a), xform(b), (255,255,255))
-
-            self.snap(vis)
-
-    def test_2686307(self):
-        lena = cv.LoadImage(find_sample("lena.jpg"), 1)
-        dst = cv.CreateImage((512,512), 8, 3)
-        cv.Set(dst, (128,192,255))
-        mask = cv.CreateImage((512,512), 8, 1)
-        cv.Zero(mask)
-        cv.Rectangle(mask, (10,10), (300,100), 255, -1)
-        cv.Copy(lena, dst, mask)
-        self.snapL([lena, dst, mask])
-        m = cv.CreateMat(480, 640, cv.CV_8UC1)
-        print "ji", m
-        print m.rows, m.cols, m.type, m.step
-
-    def snap(self, img):
-        self.snapL([img])
-
-    def snapL(self, L):
-        for i,img in enumerate(L):
-            cv.NamedWindow("snap-%d" % i, 1)
-            cv.ShowImage("snap-%d" % i, img)
-        cv.WaitKey()
-        cv.DestroyAllWindows()
-
-if __name__ == '__main__':
-    random.seed(0)
-    if len(sys.argv) == 1:
-        suite = unittest.TestLoader().loadTestsFromTestCase(TestTickets)
-        unittest.TextTestRunner(verbosity=2).run(suite)
-    else:
-        suite = unittest.TestSuite()
-        suite.addTest(TestTickets(sys.argv[1]))
-        unittest.TextTestRunner(verbosity=2).run(suite)
diff --git a/modules/python/test/transformations.py b/modules/python/test/transformations.py
deleted file mode 100755
index 5dce6b0..0000000
--- a/modules/python/test/transformations.py
+++ /dev/null
@@ -1,1707 +0,0 @@
-#!/usr/bin/env python
-
-# -*- coding: utf-8 -*-
-# transformations.py
-
-# Copyright (c) 2006, Christoph Gohlke
-# Copyright (c) 2006-2009, The Regents of the University of California
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are met:
-#
-# * Redistributions of source code must retain the above copyright
-#   notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above copyright
-#   notice, this list of conditions and the following disclaimer in the
-#   documentation and/or other materials provided with the distribution.
-# * Neither the name of the copyright holders nor the names of any
-#   contributors may be used to endorse or promote products derived
-#   from this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-# ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-# POSSIBILITY OF SUCH DAMAGE.
-
-"""Homogeneous Transformation Matrices and Quaternions.
-
-A library for calculating 4x4 matrices for translating, rotating, reflecting,
-scaling, shearing, projecting, orthogonalizing, and superimposing arrays of
-3D homogeneous coordinates as well as for converting between rotation matrices,
-Euler angles, and quaternions. Also includes an Arcball control object and
-functions to decompose transformation matrices.
-
-:Authors:
-  `Christoph Gohlke <http://www.lfd.uci.edu/~gohlke/>`__,
-  Laboratory for Fluorescence Dynamics, University of California, Irvine
-
-:Version: 20090418
-
-Requirements
-------------
-
-* `Python 2.6 <http://www.python.org>`__
-* `Numpy 1.3 <http://numpy.scipy.org>`__
-* `transformations.c 20090418 <http://www.lfd.uci.edu/~gohlke/>`__
-  (optional implementation of some functions in C)
-
-Notes
------
-
-Matrices (M) can be inverted using numpy.linalg.inv(M), concatenated using
-numpy.dot(M0, M1), or used to transform homogeneous coordinates (v) using
-numpy.dot(M, v) for shape (4, \*) "point of arrays", respectively
-numpy.dot(v, M.T) for shape (\*, 4) "array of points".
-
-Calculations are carried out with numpy.float64 precision.
-
-This Python implementation is not optimized for speed.
-
-Vector, point, quaternion, and matrix function arguments are expected to be
-"array like", i.e. tuple, list, or numpy arrays.
-
-Return types are numpy arrays unless specified otherwise.
-
-Angles are in radians unless specified otherwise.
-
-Quaternions ix+jy+kz+w are represented as [x, y, z, w].
-
-Use the transpose of transformation matrices for OpenGL glMultMatrixd().
-
-A triple of Euler angles can be applied/interpreted in 24 ways, which can
-be specified using a 4 character string or encoded 4-tuple:
-
-  *Axes 4-string*: e.g. 'sxyz' or 'ryxy'
-
-  - first character : rotations are applied to 's'tatic or 'r'otating frame
-  - remaining characters : successive rotation axis 'x', 'y', or 'z'
-
-  *Axes 4-tuple*: e.g. (0, 0, 0, 0) or (1, 1, 1, 1)
-
-  - inner axis: code of axis ('x':0, 'y':1, 'z':2) of rightmost matrix.
-  - parity : even (0) if inner axis 'x' is followed by 'y', 'y' is followed
-    by 'z', or 'z' is followed by 'x'. Otherwise odd (1).
-  - repetition : first and last axis are same (1) or different (0).
-  - frame : rotations are applied to static (0) or rotating (1) frame.
-
-References
-----------
-
-(1)  Matrices and transformations. Ronald Goldman.
-     In "Graphics Gems I", pp 472-475. Morgan Kaufmann, 1990.
-(2)  More matrices and transformations: shear and pseudo-perspective.
-     Ronald Goldman. In "Graphics Gems II", pp 320-323. Morgan Kaufmann, 1991.
-(3)  Decomposing a matrix into simple transformations. Spencer Thomas.
-     In "Graphics Gems II", pp 320-323. Morgan Kaufmann, 1991.
-(4)  Recovering the data from the transformation matrix. Ronald Goldman.
-     In "Graphics Gems II", pp 324-331. Morgan Kaufmann, 1991.
-(5)  Euler angle conversion. Ken Shoemake.
-     In "Graphics Gems IV", pp 222-229. Morgan Kaufmann, 1994.
-(6)  Arcball rotation control. Ken Shoemake.
-     In "Graphics Gems IV", pp 175-192. Morgan Kaufmann, 1994.
-(7)  Representing attitude: Euler angles, unit quaternions, and rotation
-     vectors. James Diebel. 2006.
-(8)  A discussion of the solution for the best rotation to relate two sets
-     of vectors. W Kabsch. Acta Cryst. 1978. A34, 827-828.
-(9)  Closed-form solution of absolute orientation using unit quaternions.
-     BKP Horn. J Opt Soc Am A. 1987. 4(4), 629-642.
-(10) Quaternions. Ken Shoemake.
-     http://www.sfu.ca/~jwa3/cmpt461/files/quatut.pdf
-(11) From quaternion to matrix and back. JMP van Waveren. 2005.
-     http://www.intel.com/cd/ids/developer/asmo-na/eng/293748.htm
-(12) Uniform random rotations. Ken Shoemake.
-     In "Graphics Gems III", pp 124-132. Morgan Kaufmann, 1992.
-
-
-Examples
---------
-
->>> alpha, beta, gamma = 0.123, -1.234, 2.345
->>> origin, xaxis, yaxis, zaxis = (0, 0, 0), (1, 0, 0), (0, 1, 0), (0, 0, 1)
->>> I = identity_matrix()
->>> Rx = rotation_matrix(alpha, xaxis)
->>> Ry = rotation_matrix(beta, yaxis)
->>> Rz = rotation_matrix(gamma, zaxis)
->>> R = concatenate_matrices(Rx, Ry, Rz)
->>> euler = euler_from_matrix(R, 'rxyz')
->>> numpy.allclose([alpha, beta, gamma], euler)
-True
->>> Re = euler_matrix(alpha, beta, gamma, 'rxyz')
->>> is_same_transform(R, Re)
-True
->>> al, be, ga = euler_from_matrix(Re, 'rxyz')
->>> is_same_transform(Re, euler_matrix(al, be, ga, 'rxyz'))
-True
->>> qx = quaternion_about_axis(alpha, xaxis)
->>> qy = quaternion_about_axis(beta, yaxis)
->>> qz = quaternion_about_axis(gamma, zaxis)
->>> q = quaternion_multiply(qx, qy)
->>> q = quaternion_multiply(q, qz)
->>> Rq = quaternion_matrix(q)
->>> is_same_transform(R, Rq)
-True
->>> S = scale_matrix(1.23, origin)
->>> T = translation_matrix((1, 2, 3))
->>> Z = shear_matrix(beta, xaxis, origin, zaxis)
->>> R = random_rotation_matrix(numpy.random.rand(3))
->>> M = concatenate_matrices(T, R, Z, S)
->>> scale, shear, angles, trans, persp = decompose_matrix(M)
->>> numpy.allclose(scale, 1.23)
-True
->>> numpy.allclose(trans, (1, 2, 3))
-True
->>> numpy.allclose(shear, (0, math.tan(beta), 0))
-True
->>> is_same_transform(R, euler_matrix(axes='sxyz', *angles))
-True
->>> M1 = compose_matrix(scale, shear, angles, trans, persp)
->>> is_same_transform(M, M1)
-True
-
-"""
-
-from __future__ import division
-
-import warnings
-import math
-
-import numpy
-
-# Documentation in HTML format can be generated with Epydoc
-__docformat__ = "restructuredtext en"
-
-
-def identity_matrix():
-    """Return 4x4 identity/unit matrix.
-
-    >>> I = identity_matrix()
-    >>> numpy.allclose(I, numpy.dot(I, I))
-    True
-    >>> numpy.sum(I), numpy.trace(I)
-    (4.0, 4.0)
-    >>> numpy.allclose(I, numpy.identity(4, dtype=numpy.float64))
-    True
-
-    """
-    return numpy.identity(4, dtype=numpy.float64)
-
-
-def translation_matrix(direction):
-    """Return matrix to translate by direction vector.
-
-    >>> v = numpy.random.random(3) - 0.5
-    >>> numpy.allclose(v, translation_matrix(v)[:3, 3])
-    True
-
-    """
-    M = numpy.identity(4)
-    M[:3, 3] = direction[:3]
-    return M
-
-
-def translation_from_matrix(matrix):
-    """Return translation vector from translation matrix.
-
-    >>> v0 = numpy.random.random(3) - 0.5
-    >>> v1 = translation_from_matrix(translation_matrix(v0))
-    >>> numpy.allclose(v0, v1)
-    True
-
-    """
-    return numpy.array(matrix, copy=False)[:3, 3].copy()
-
-
-def reflection_matrix(point, normal):
-    """Return matrix to mirror at plane defined by point and normal vector.
-
-    >>> v0 = numpy.random.random(4) - 0.5
-    >>> v0[3] = 1.0
-    >>> v1 = numpy.random.random(3) - 0.5
-    >>> R = reflection_matrix(v0, v1)
-    >>> numpy.allclose(2., numpy.trace(R))
-    True
-    >>> numpy.allclose(v0, numpy.dot(R, v0))
-    True
-    >>> v2 = v0.copy()
-    >>> v2[:3] += v1
-    >>> v3 = v0.copy()
-    >>> v2[:3] -= v1
-    >>> numpy.allclose(v2, numpy.dot(R, v3))
-    True
-
-    """
-    normal = unit_vector(normal[:3])
-    M = numpy.identity(4)
-    M[:3, :3] -= 2.0 * numpy.outer(normal, normal)
-    M[:3, 3] = (2.0 * numpy.dot(point[:3], normal)) * normal
-    return M
-
-
-def reflection_from_matrix(matrix):
-    """Return mirror plane point and normal vector from reflection matrix.
-
-    >>> v0 = numpy.random.random(3) - 0.5
-    >>> v1 = numpy.random.random(3) - 0.5
-    >>> M0 = reflection_matrix(v0, v1)
-    >>> point, normal = reflection_from_matrix(M0)
-    >>> M1 = reflection_matrix(point, normal)
-    >>> is_same_transform(M0, M1)
-    True
-
-    """
-    M = numpy.array(matrix, dtype=numpy.float64, copy=False)
-    # normal: unit eigenvector corresponding to eigenvalue -1
-    l, V = numpy.linalg.eig(M[:3, :3])
-    i = numpy.where(abs(numpy.real(l) + 1.0) < 1e-8)[0]
-    if not len(i):
-        raise ValueError("no unit eigenvector corresponding to eigenvalue -1")
-    normal = numpy.real(V[:, i[0]]).squeeze()
-    # point: any unit eigenvector corresponding to eigenvalue 1
-    l, V = numpy.linalg.eig(M)
-    i = numpy.where(abs(numpy.real(l) - 1.0) < 1e-8)[0]
-    if not len(i):
-        raise ValueError("no unit eigenvector corresponding to eigenvalue 1")
-    point = numpy.real(V[:, i[-1]]).squeeze()
-    point /= point[3]
-    return point, normal
-
-
-def rotation_matrix(angle, direction, point=None):
-    """Return matrix to rotate about axis defined by point and direction.
-
-    >>> angle = (random.random() - 0.5) * (2*math.pi)
-    >>> direc = numpy.random.random(3) - 0.5
-    >>> point = numpy.random.random(3) - 0.5
-    >>> R0 = rotation_matrix(angle, direc, point)
-    >>> R1 = rotation_matrix(angle-2*math.pi, direc, point)
-    >>> is_same_transform(R0, R1)
-    True
-    >>> R0 = rotation_matrix(angle, direc, point)
-    >>> R1 = rotation_matrix(-angle, -direc, point)
-    >>> is_same_transform(R0, R1)
-    True
-    >>> I = numpy.identity(4, numpy.float64)
-    >>> numpy.allclose(I, rotation_matrix(math.pi*2, direc))
-    True
-    >>> numpy.allclose(2., numpy.trace(rotation_matrix(math.pi/2,
-    ...                                                direc, point)))
-    True
-
-    """
-    sina = math.sin(angle)
-    cosa = math.cos(angle)
-    direction = unit_vector(direction[:3])
-    # rotation matrix around unit vector
-    R = numpy.array(((cosa, 0.0,  0.0),
-                     (0.0,  cosa, 0.0),
-                     (0.0,  0.0,  cosa)), dtype=numpy.float64)
-    R += numpy.outer(direction, direction) * (1.0 - cosa)
-    direction *= sina
-    R += numpy.array((( 0.0,         -direction[2],  direction[1]),
-                      ( direction[2], 0.0,          -direction[0]),
-                      (-direction[1], direction[0],  0.0)),
-                     dtype=numpy.float64)
-    M = numpy.identity(4)
-    M[:3, :3] = R
-    if point is not None:
-        # rotation not around origin
-        point = numpy.array(point[:3], dtype=numpy.float64, copy=False)
-        M[:3, 3] = point - numpy.dot(R, point)
-    return M
-
-
-def rotation_from_matrix(matrix):
-    """Return rotation angle and axis from rotation matrix.
-
-    >>> angle = (random.random() - 0.5) * (2*math.pi)
-    >>> direc = numpy.random.random(3) - 0.5
-    >>> point = numpy.random.random(3) - 0.5
-    >>> R0 = rotation_matrix(angle, direc, point)
-    >>> angle, direc, point = rotation_from_matrix(R0)
-    >>> R1 = rotation_matrix(angle, direc, point)
-    >>> is_same_transform(R0, R1)
-    True
-
-    """
-    R = numpy.array(matrix, dtype=numpy.float64, copy=False)
-    R33 = R[:3, :3]
-    # direction: unit eigenvector of R33 corresponding to eigenvalue of 1
-    l, W = numpy.linalg.eig(R33.T)
-    i = numpy.where(abs(numpy.real(l) - 1.0) < 1e-8)[0]
-    if not len(i):
-        raise ValueError("no unit eigenvector corresponding to eigenvalue 1")
-    direction = numpy.real(W[:, i[-1]]).squeeze()
-    # point: unit eigenvector of R33 corresponding to eigenvalue of 1
-    l, Q = numpy.linalg.eig(R)
-    i = numpy.where(abs(numpy.real(l) - 1.0) < 1e-8)[0]
-    if not len(i):
-        raise ValueError("no unit eigenvector corresponding to eigenvalue 1")
-    point = numpy.real(Q[:, i[-1]]).squeeze()
-    point /= point[3]
-    # rotation angle depending on direction
-    cosa = (numpy.trace(R33) - 1.0) / 2.0
-    if abs(direction[2]) > 1e-8:
-        sina = (R[1, 0] + (cosa-1.0)*direction[0]*direction[1]) / direction[2]
-    elif abs(direction[1]) > 1e-8:
-        sina = (R[0, 2] + (cosa-1.0)*direction[0]*direction[2]) / direction[1]
-    else:
-        sina = (R[2, 1] + (cosa-1.0)*direction[1]*direction[2]) / direction[0]
-    angle = math.atan2(sina, cosa)
-    return angle, direction, point
-
-
-def scale_matrix(factor, origin=None, direction=None):
-    """Return matrix to scale by factor around origin in direction.
-
-    Use factor -1 for point symmetry.
-
-    >>> v = (numpy.random.rand(4, 5) - 0.5) * 20.0
-    >>> v[3] = 1.0
-    >>> S = scale_matrix(-1.234)
-    >>> numpy.allclose(numpy.dot(S, v)[:3], -1.234*v[:3])
-    True
-    >>> factor = random.random() * 10 - 5
-    >>> origin = numpy.random.random(3) - 0.5
-    >>> direct = numpy.random.random(3) - 0.5
-    >>> S = scale_matrix(factor, origin)
-    >>> S = scale_matrix(factor, origin, direct)
-
-    """
-    if direction is None:
-        # uniform scaling
-        M = numpy.array(((factor, 0.0,    0.0,    0.0),
-                         (0.0,    factor, 0.0,    0.0),
-                         (0.0,    0.0,    factor, 0.0),
-                         (0.0,    0.0,    0.0,    1.0)), dtype=numpy.float64)
-        if origin is not None:
-            M[:3, 3] = origin[:3]
-            M[:3, 3] *= 1.0 - factor
-    else:
-        # nonuniform scaling
-        direction = unit_vector(direction[:3])
-        factor = 1.0 - factor
-        M = numpy.identity(4)
-        M[:3, :3] -= factor * numpy.outer(direction, direction)
-        if origin is not None:
-            M[:3, 3] = (factor * numpy.dot(origin[:3], direction)) * direction
-    return M
-
-
-def scale_from_matrix(matrix):
-    """Return scaling factor, origin and direction from scaling matrix.
-
-    >>> factor = random.random() * 10 - 5
-    >>> origin = numpy.random.random(3) - 0.5
-    >>> direct = numpy.random.random(3) - 0.5
-    >>> S0 = scale_matrix(factor, origin)
-    >>> factor, origin, direction = scale_from_matrix(S0)
-    >>> S1 = scale_matrix(factor, origin, direction)
-    >>> is_same_transform(S0, S1)
-    True
-    >>> S0 = scale_matrix(factor, origin, direct)
-    >>> factor, origin, direction = scale_from_matrix(S0)
-    >>> S1 = scale_matrix(factor, origin, direction)
-    >>> is_same_transform(S0, S1)
-    True
-
-    """
-    M = numpy.array(matrix, dtype=numpy.float64, copy=False)
-    M33 = M[:3, :3]
-    factor = numpy.trace(M33) - 2.0
-    try:
-        # direction: unit eigenvector corresponding to eigenvalue factor
-        l, V = numpy.linalg.eig(M33)
-        i = numpy.where(abs(numpy.real(l) - factor) < 1e-8)[0][0]
-        direction = numpy.real(V[:, i]).squeeze()
-        direction /= vector_norm(direction)
-    except IndexError:
-        # uniform scaling
-        factor = (factor + 2.0) / 3.0
-        direction = None
-    # origin: any eigenvector corresponding to eigenvalue 1
-    l, V = numpy.linalg.eig(M)
-    i = numpy.where(abs(numpy.real(l) - 1.0) < 1e-8)[0]
-    if not len(i):
-        raise ValueError("no eigenvector corresponding to eigenvalue 1")
-    origin = numpy.real(V[:, i[-1]]).squeeze()
-    origin /= origin[3]
-    return factor, origin, direction
-
-
-def projection_matrix(point, normal, direction=None,
-                      perspective=None, pseudo=False):
-    """Return matrix to project onto plane defined by point and normal.
-
-    Using either perspective point, projection direction, or none of both.
-
-    If pseudo is True, perspective projections will preserve relative depth
-    such that Perspective = dot(Orthogonal, PseudoPerspective).
-
-    >>> P = projection_matrix((0, 0, 0), (1, 0, 0))
-    >>> numpy.allclose(P[1:, 1:], numpy.identity(4)[1:, 1:])
-    True
-    >>> point = numpy.random.random(3) - 0.5
-    >>> normal = numpy.random.random(3) - 0.5
-    >>> direct = numpy.random.random(3) - 0.5
-    >>> persp = numpy.random.random(3) - 0.5
-    >>> P0 = projection_matrix(point, normal)
-    >>> P1 = projection_matrix(point, normal, direction=direct)
-    >>> P2 = projection_matrix(point, normal, perspective=persp)
-    >>> P3 = projection_matrix(point, normal, perspective=persp, pseudo=True)
-    >>> is_same_transform(P2, numpy.dot(P0, P3))
-    True
-    >>> P = projection_matrix((3, 0, 0), (1, 1, 0), (1, 0, 0))
-    >>> v0 = (numpy.random.rand(4, 5) - 0.5) * 20.0
-    >>> v0[3] = 1.0
-    >>> v1 = numpy.dot(P, v0)
-    >>> numpy.allclose(v1[1], v0[1])
-    True
-    >>> numpy.allclose(v1[0], 3.0-v1[1])
-    True
-
-    """
-    M = numpy.identity(4)
-    point = numpy.array(point[:3], dtype=numpy.float64, copy=False)
-    normal = unit_vector(normal[:3])
-    if perspective is not None:
-        # perspective projection
-        perspective = numpy.array(perspective[:3], dtype=numpy.float64,
-                                  copy=False)
-        M[0, 0] = M[1, 1] = M[2, 2] = numpy.dot(perspective-point, normal)
-        M[:3, :3] -= numpy.outer(perspective, normal)
-        if pseudo:
-            # preserve relative depth
-            M[:3, :3] -= numpy.outer(normal, normal)
-            M[:3, 3] = numpy.dot(point, normal) * (perspective+normal)
-        else:
-            M[:3, 3] = numpy.dot(point, normal) * perspective
-        M[3, :3] = -normal
-        M[3, 3] = numpy.dot(perspective, normal)
-    elif direction is not None:
-        # parallel projection
-        direction = numpy.array(direction[:3], dtype=numpy.float64, copy=False)
-        scale = numpy.dot(direction, normal)
-        M[:3, :3] -= numpy.outer(direction, normal) / scale
-        M[:3, 3] = direction * (numpy.dot(point, normal) / scale)
-    else:
-        # orthogonal projection
-        M[:3, :3] -= numpy.outer(normal, normal)
-        M[:3, 3] = numpy.dot(point, normal) * normal
-    return M
-
-
-def projection_from_matrix(matrix, pseudo=False):
-    """Return projection plane and perspective point from projection matrix.
-
-    Return values are same as arguments for projection_matrix function:
-    point, normal, direction, perspective, and pseudo.
-
-    >>> point = numpy.random.random(3) - 0.5
-    >>> normal = numpy.random.random(3) - 0.5
-    >>> direct = numpy.random.random(3) - 0.5
-    >>> persp = numpy.random.random(3) - 0.5
-    >>> P0 = projection_matrix(point, normal)
-    >>> result = projection_from_matrix(P0)
-    >>> P1 = projection_matrix(*result)
-    >>> is_same_transform(P0, P1)
-    True
-    >>> P0 = projection_matrix(point, normal, direct)
-    >>> result = projection_from_matrix(P0)
-    >>> P1 = projection_matrix(*result)
-    >>> is_same_transform(P0, P1)
-    True
-    >>> P0 = projection_matrix(point, normal, perspective=persp, pseudo=False)
-    >>> result = projection_from_matrix(P0, pseudo=False)
-    >>> P1 = projection_matrix(*result)
-    >>> is_same_transform(P0, P1)
-    True
-    >>> P0 = projection_matrix(point, normal, perspective=persp, pseudo=True)
-    >>> result = projection_from_matrix(P0, pseudo=True)
-    >>> P1 = projection_matrix(*result)
-    >>> is_same_transform(P0, P1)
-    True
-
-    """
-    M = numpy.array(matrix, dtype=numpy.float64, copy=False)
-    M33 = M[:3, :3]
-    l, V = numpy.linalg.eig(M)
-    i = numpy.where(abs(numpy.real(l) - 1.0) < 1e-8)[0]
-    if not pseudo and len(i):
-        # point: any eigenvector corresponding to eigenvalue 1
-        point = numpy.real(V[:, i[-1]]).squeeze()
-        point /= point[3]
-        # direction: unit eigenvector corresponding to eigenvalue 0
-        l, V = numpy.linalg.eig(M33)
-        i = numpy.where(abs(numpy.real(l)) < 1e-8)[0]
-        if not len(i):
-            raise ValueError("no eigenvector corresponding to eigenvalue 0")
-        direction = numpy.real(V[:, i[0]]).squeeze()
-        direction /= vector_norm(direction)
-        # normal: unit eigenvector of M33.T corresponding to eigenvalue 0
-        l, V = numpy.linalg.eig(M33.T)
-        i = numpy.where(abs(numpy.real(l)) < 1e-8)[0]
-        if len(i):
-            # parallel projection
-            normal = numpy.real(V[:, i[0]]).squeeze()
-            normal /= vector_norm(normal)
-            return point, normal, direction, None, False
-        else:
-            # orthogonal projection, where normal equals direction vector
-            return point, direction, None, None, False
-    else:
-        # perspective projection
-        i = numpy.where(abs(numpy.real(l)) > 1e-8)[0]
-        if not len(i):
-            raise ValueError(
-                "no eigenvector not corresponding to eigenvalue 0")
-        point = numpy.real(V[:, i[-1]]).squeeze()
-        point /= point[3]
-        normal = - M[3, :3]
-        perspective = M[:3, 3] / numpy.dot(point[:3], normal)
-        if pseudo:
-            perspective -= normal
-        return point, normal, None, perspective, pseudo
-
-
-def clip_matrix(left, right, bottom, top, near, far, perspective=False):
-    """Return matrix to obtain normalized device coordinates from frustrum.
-
-    The frustrum bounds are axis-aligned along x (left, right),
-    y (bottom, top) and z (near, far).
-
-    Normalized device coordinates are in range [-1, 1] if coordinates are
-    inside the frustrum.
-
-    If perspective is True the frustrum is a truncated pyramid with the
-    perspective point at origin and direction along z axis, otherwise an
-    orthographic canonical view volume (a box).
-
-    Homogeneous coordinates transformed by the perspective clip matrix
-    need to be dehomogenized (devided by w coordinate).
-
-    >>> frustrum = numpy.random.rand(6)
-    >>> frustrum[1] += frustrum[0]
-    >>> frustrum[3] += frustrum[2]
-    >>> frustrum[5] += frustrum[4]
-    >>> M = clip_matrix(*frustrum, perspective=False)
-    >>> numpy.dot(M, [frustrum[0], frustrum[2], frustrum[4], 1.0])
-    array([-1., -1., -1.,  1.])
-    >>> numpy.dot(M, [frustrum[1], frustrum[3], frustrum[5], 1.0])
-    array([ 1.,  1.,  1.,  1.])
-    >>> M = clip_matrix(*frustrum, perspective=True)
-    >>> v = numpy.dot(M, [frustrum[0], frustrum[2], frustrum[4], 1.0])
-    >>> v / v[3]
-    array([-1., -1., -1.,  1.])
-    >>> v = numpy.dot(M, [frustrum[1], frustrum[3], frustrum[4], 1.0])
-    >>> v / v[3]
-    array([ 1.,  1., -1.,  1.])
-
-    """
-    if left >= right or bottom >= top or near >= far:
-        raise ValueError("invalid frustrum")
-    if perspective:
-        if near <= _EPS:
-            raise ValueError("invalid frustrum: near <= 0")
-        t = 2.0 * near
-        M = ((-t/(right-left), 0.0, (right+left)/(right-left), 0.0),
-             (0.0, -t/(top-bottom), (top+bottom)/(top-bottom), 0.0),
-             (0.0, 0.0, -(far+near)/(far-near), t*far/(far-near)),
-             (0.0, 0.0, -1.0, 0.0))
-    else:
-        M = ((2.0/(right-left), 0.0, 0.0, (right+left)/(left-right)),
-             (0.0, 2.0/(top-bottom), 0.0, (top+bottom)/(bottom-top)),
-             (0.0, 0.0, 2.0/(far-near), (far+near)/(near-far)),
-             (0.0, 0.0, 0.0, 1.0))
-    return numpy.array(M, dtype=numpy.float64)
-
-
-def shear_matrix(angle, direction, point, normal):
-    """Return matrix to shear by angle along direction vector on shear plane.
-
-    The shear plane is defined by a point and normal vector. The direction
-    vector must be orthogonal to the plane's normal vector.
-
-    A point P is transformed by the shear matrix into P" such that
-    the vector P-P" is parallel to the direction vector and its extent is
-    given by the angle of P-P'-P", where P' is the orthogonal projection
-    of P onto the shear plane.
-
-    >>> angle = (random.random() - 0.5) * 4*math.pi
-    >>> direct = numpy.random.random(3) - 0.5
-    >>> point = numpy.random.random(3) - 0.5
-    >>> normal = numpy.cross(direct, numpy.random.random(3))
-    >>> S = shear_matrix(angle, direct, point, normal)
-    >>> numpy.allclose(1.0, numpy.linalg.det(S))
-    True
-
-    """
-    normal = unit_vector(normal[:3])
-    direction = unit_vector(direction[:3])
-    if abs(numpy.dot(normal, direction)) > 1e-6:
-        raise ValueError("direction and normal vectors are not orthogonal")
-    angle = math.tan(angle)
-    M = numpy.identity(4)
-    M[:3, :3] += angle * numpy.outer(direction, normal)
-    M[:3, 3] = -angle * numpy.dot(point[:3], normal) * direction
-    return M
-
-
-def shear_from_matrix(matrix):
-    """Return shear angle, direction and plane from shear matrix.
-
-    >>> angle = (random.random() - 0.5) * 4*math.pi
-    >>> direct = numpy.random.random(3) - 0.5
-    >>> point = numpy.random.random(3) - 0.5
-    >>> normal = numpy.cross(direct, numpy.random.random(3))
-    >>> S0 = shear_matrix(angle, direct, point, normal)
-    >>> angle, direct, point, normal = shear_from_matrix(S0)
-    >>> S1 = shear_matrix(angle, direct, point, normal)
-    >>> is_same_transform(S0, S1)
-    True
-
-    """
-    M = numpy.array(matrix, dtype=numpy.float64, copy=False)
-    M33 = M[:3, :3]
-    # normal: cross independent eigenvectors corresponding to the eigenvalue 1
-    l, V = numpy.linalg.eig(M33)
-    i = numpy.where(abs(numpy.real(l) - 1.0) < 1e-4)[0]
-    if len(i) < 2:
-        raise ValueError("No two linear independent eigenvectors found %s" % l)
-    V = numpy.real(V[:, i]).squeeze().T
-    lenorm = -1.0
-    for i0, i1 in ((0, 1), (0, 2), (1, 2)):
-        n = numpy.cross(V[i0], V[i1])
-        l = vector_norm(n)
-        if l > lenorm:
-            lenorm = l
-            normal = n
-    normal /= lenorm
-    # direction and angle
-    direction = numpy.dot(M33 - numpy.identity(3), normal)
-    angle = vector_norm(direction)
-    direction /= angle
-    angle = math.atan(angle)
-    # point: eigenvector corresponding to eigenvalue 1
-    l, V = numpy.linalg.eig(M)
-    i = numpy.where(abs(numpy.real(l) - 1.0) < 1e-8)[0]
-    if not len(i):
-        raise ValueError("no eigenvector corresponding to eigenvalue 1")
-    point = numpy.real(V[:, i[-1]]).squeeze()
-    point /= point[3]
-    return angle, direction, point, normal
-
-
-def decompose_matrix(matrix):
-    """Return sequence of transformations from transformation matrix.
-
-    matrix : array_like
-        Non-degenerative homogeneous transformation matrix
-
-    Return tuple of:
-        scale : vector of 3 scaling factors
-        shear : list of shear factors for x-y, x-z, y-z axes
-        angles : list of Euler angles about static x, y, z axes
-        translate : translation vector along x, y, z axes
-        perspective : perspective partition of matrix
-
-    Raise ValueError if matrix is of wrong type or degenerative.
-
-    >>> T0 = translation_matrix((1, 2, 3))
-    >>> scale, shear, angles, trans, persp = decompose_matrix(T0)
-    >>> T1 = translation_matrix(trans)
-    >>> numpy.allclose(T0, T1)
-    True
-    >>> S = scale_matrix(0.123)
-    >>> scale, shear, angles, trans, persp = decompose_matrix(S)
-    >>> scale[0]
-    0.123
-    >>> R0 = euler_matrix(1, 2, 3)
-    >>> scale, shear, angles, trans, persp = decompose_matrix(R0)
-    >>> R1 = euler_matrix(*angles)
-    >>> numpy.allclose(R0, R1)
-    True
-
-    """
-    M = numpy.array(matrix, dtype=numpy.float64, copy=True).T
-    if abs(M[3, 3]) < _EPS:
-        raise ValueError("M[3, 3] is zero")
-    M /= M[3, 3]
-    P = M.copy()
-    P[:, 3] = 0, 0, 0, 1
-    if not numpy.linalg.det(P):
-        raise ValueError("Matrix is singular")
-
-    scale = numpy.zeros((3, ), dtype=numpy.float64)
-    shear = [0, 0, 0]
-    angles = [0, 0, 0]
-
-    if any(abs(M[:3, 3]) > _EPS):
-        perspective = numpy.dot(M[:, 3], numpy.linalg.inv(P.T))
-        M[:, 3] = 0, 0, 0, 1
-    else:
-        perspective = numpy.array((0, 0, 0, 1), dtype=numpy.float64)
-
-    translate = M[3, :3].copy()
-    M[3, :3] = 0
-
-    row = M[:3, :3].copy()
-    scale[0] = vector_norm(row[0])
-    row[0] /= scale[0]
-    shear[0] = numpy.dot(row[0], row[1])
-    row[1] -= row[0] * shear[0]
-    scale[1] = vector_norm(row[1])
-    row[1] /= scale[1]
-    shear[0] /= scale[1]
-    shear[1] = numpy.dot(row[0], row[2])
-    row[2] -= row[0] * shear[1]
-    shear[2] = numpy.dot(row[1], row[2])
-    row[2] -= row[1] * shear[2]
-    scale[2] = vector_norm(row[2])
-    row[2] /= scale[2]
-    shear[1:] /= scale[2]
-
-    if numpy.dot(row[0], numpy.cross(row[1], row[2])) < 0:
-        scale *= -1
-        row *= -1
-
-    angles[1] = math.asin(-row[0, 2])
-    if math.cos(angles[1]):
-        angles[0] = math.atan2(row[1, 2], row[2, 2])
-        angles[2] = math.atan2(row[0, 1], row[0, 0])
-    else:
-        #angles[0] = math.atan2(row[1, 0], row[1, 1])
-        angles[0] = math.atan2(-row[2, 1], row[1, 1])
-        angles[2] = 0.0
-
-    return scale, shear, angles, translate, perspective
-
-
-def compose_matrix(scale=None, shear=None, angles=None, translate=None,
-                   perspective=None):
-    """Return transformation matrix from sequence of transformations.
-
-    This is the inverse of the decompose_matrix function.
-
-    Sequence of transformations:
-        scale : vector of 3 scaling factors
-        shear : list of shear factors for x-y, x-z, y-z axes
-        angles : list of Euler angles about static x, y, z axes
-        translate : translation vector along x, y, z axes
-        perspective : perspective partition of matrix
-
-    >>> scale = numpy.random.random(3) - 0.5
-    >>> shear = numpy.random.random(3) - 0.5
-    >>> angles = (numpy.random.random(3) - 0.5) * (2*math.pi)
-    >>> trans = numpy.random.random(3) - 0.5
-    >>> persp = numpy.random.random(4) - 0.5
-    >>> M0 = compose_matrix(scale, shear, angles, trans, persp)
-    >>> result = decompose_matrix(M0)
-    >>> M1 = compose_matrix(*result)
-    >>> is_same_transform(M0, M1)
-    True
-
-    """
-    M = numpy.identity(4)
-    if perspective is not None:
-        P = numpy.identity(4)
-        P[3, :] = perspective[:4]
-        M = numpy.dot(M, P)
-    if translate is not None:
-        T = numpy.identity(4)
-        T[:3, 3] = translate[:3]
-        M = numpy.dot(M, T)
-    if angles is not None:
-        R = euler_matrix(angles[0], angles[1], angles[2], 'sxyz')
-        M = numpy.dot(M, R)
-    if shear is not None:
-        Z = numpy.identity(4)
-        Z[1, 2] = shear[2]
-        Z[0, 2] = shear[1]
-        Z[0, 1] = shear[0]
-        M = numpy.dot(M, Z)
-    if scale is not None:
-        S = numpy.identity(4)
-        S[0, 0] = scale[0]
-        S[1, 1] = scale[1]
-        S[2, 2] = scale[2]
-        M = numpy.dot(M, S)
-    M /= M[3, 3]
-    return M
-
-
-def orthogonalization_matrix(lengths, angles):
-    """Return orthogonalization matrix for crystallographic cell coordinates.
-
-    Angles are expected in degrees.
-
-    The de-orthogonalization matrix is the inverse.
-
-    >>> O = orthogonalization_matrix((10., 10., 10.), (90., 90., 90.))
-    >>> numpy.allclose(O[:3, :3], numpy.identity(3, float) * 10)
-    True
-    >>> O = orthogonalization_matrix([9.8, 12.0, 15.5], [87.2, 80.7, 69.7])
-    >>> numpy.allclose(numpy.sum(O), 43.063229)
-    True
-
-    """
-    a, b, c = lengths
-    angles = numpy.radians(angles)
-    sina, sinb, _ = numpy.sin(angles)
-    cosa, cosb, cosg = numpy.cos(angles)
-    co = (cosa * cosb - cosg) / (sina * sinb)
-    return numpy.array((
-        ( a*sinb*math.sqrt(1.0-co*co),  0.0,    0.0, 0.0),
-        (-a*sinb*co,                    b*sina, 0.0, 0.0),
-        ( a*cosb,                       b*cosa, c,   0.0),
-        ( 0.0,                          0.0,    0.0, 1.0)),
-        dtype=numpy.float64)
-
-
-def superimposition_matrix(v0, v1, scaling=False, usesvd=True):
-    """Return matrix to transform given vector set into second vector set.
-
-    v0 and v1 are shape (3, \*) or (4, \*) arrays of at least 3 vectors.
-
-    If usesvd is True, the weighted sum of squared deviations (RMSD) is
-    minimized according to the algorithm by W. Kabsch [8]. Otherwise the
-    quaternion based algorithm by B. Horn [9] is used (slower when using
-    this Python implementation).
-
-    The returned matrix performs rotation, translation and uniform scaling
-    (if specified).
-
-    >>> v0 = numpy.random.rand(3, 10)
-    >>> M = superimposition_matrix(v0, v0)
-    >>> numpy.allclose(M, numpy.identity(4))
-    True
-    >>> R = random_rotation_matrix(numpy.random.random(3))
-    >>> v0 = ((1,0,0), (0,1,0), (0,0,1), (1,1,1))
-    >>> v1 = numpy.dot(R, v0)
-    >>> M = superimposition_matrix(v0, v1)
-    >>> numpy.allclose(v1, numpy.dot(M, v0))
-    True
-    >>> v0 = (numpy.random.rand(4, 100) - 0.5) * 20.0
-    >>> v0[3] = 1.0
-    >>> v1 = numpy.dot(R, v0)
-    >>> M = superimposition_matrix(v0, v1)
-    >>> numpy.allclose(v1, numpy.dot(M, v0))
-    True
-    >>> S = scale_matrix(random.random())
-    >>> T = translation_matrix(numpy.random.random(3)-0.5)
-    >>> M = concatenate_matrices(T, R, S)
-    >>> v1 = numpy.dot(M, v0)
-    >>> v0[:3] += numpy.random.normal(0.0, 1e-9, 300).reshape(3, -1)
-    >>> M = superimposition_matrix(v0, v1, scaling=True)
-    >>> numpy.allclose(v1, numpy.dot(M, v0))
-    True
-    >>> M = superimposition_matrix(v0, v1, scaling=True, usesvd=False)
-    >>> numpy.allclose(v1, numpy.dot(M, v0))
-    True
-    >>> v = numpy.empty((4, 100, 3), dtype=numpy.float64)
-    >>> v[:, :, 0] = v0
-    >>> M = superimposition_matrix(v0, v1, scaling=True, usesvd=False)
-    >>> numpy.allclose(v1, numpy.dot(M, v[:, :, 0]))
-    True
-
-    """
-    v0 = numpy.array(v0, dtype=numpy.float64, copy=False)[:3]
-    v1 = numpy.array(v1, dtype=numpy.float64, copy=False)[:3]
-
-    if v0.shape != v1.shape or v0.shape[1] < 3:
-        raise ValueError("Vector sets are of wrong shape or type.")
-
-    # move centroids to origin
-    t0 = numpy.mean(v0, axis=1)
-    t1 = numpy.mean(v1, axis=1)
-    v0 = v0 - t0.reshape(3, 1)
-    v1 = v1 - t1.reshape(3, 1)
-
-    if usesvd:
-        # Singular Value Decomposition of covariance matrix
-        u, s, vh = numpy.linalg.svd(numpy.dot(v1, v0.T))
-        # rotation matrix from SVD orthonormal bases
-        R = numpy.dot(u, vh)
-        if numpy.linalg.det(R) < 0.0:
-            # R does not constitute right handed system
-            R -= numpy.outer(u[:, 2], vh[2, :]*2.0)
-            s[-1] *= -1.0
-        # homogeneous transformation matrix
-        M = numpy.identity(4)
-        M[:3, :3] = R
-    else:
-        # compute symmetric matrix N
-        xx, yy, zz = numpy.sum(v0 * v1, axis=1)
-        xy, yz, zx = numpy.sum(v0 * numpy.roll(v1, -1, axis=0), axis=1)
-        xz, yx, zy = numpy.sum(v0 * numpy.roll(v1, -2, axis=0), axis=1)
-        N = ((xx+yy+zz, yz-zy,    zx-xz,    xy-yx),
-             (yz-zy,    xx-yy-zz, xy+yx,    zx+xz),
-             (zx-xz,    xy+yx,   -xx+yy-zz, yz+zy),
-             (xy-yx,    zx+xz,    yz+zy,   -xx-yy+zz))
-        # quaternion: eigenvector corresponding to most positive eigenvalue
-        l, V = numpy.linalg.eig(N)
-        q = V[:, numpy.argmax(l)]
-        q /= vector_norm(q) # unit quaternion
-        q = numpy.roll(q, -1) # move w component to end
-        # homogeneous transformation matrix
-        M = quaternion_matrix(q)
-
-    # scale: ratio of rms deviations from centroid
-    if scaling:
-        v0 *= v0
-        v1 *= v1
-        M[:3, :3] *= math.sqrt(numpy.sum(v1) / numpy.sum(v0))
-
-    # translation
-    M[:3, 3] = t1
-    T = numpy.identity(4)
-    T[:3, 3] = -t0
-    M = numpy.dot(M, T)
-    return M
-
-
-def euler_matrix(ai, aj, ak, axes='sxyz'):
-    """Return homogeneous rotation matrix from Euler angles and axis sequence.
-
-    ai, aj, ak : Euler's roll, pitch and yaw angles
-    axes : One of 24 axis sequences as string or encoded tuple
-
-    >>> R = euler_matrix(1, 2, 3, 'syxz')
-    >>> numpy.allclose(numpy.sum(R[0]), -1.34786452)
-    True
-    >>> R = euler_matrix(1, 2, 3, (0, 1, 0, 1))
-    >>> numpy.allclose(numpy.sum(R[0]), -0.383436184)
-    True
-    >>> ai, aj, ak = (4.0*math.pi) * (numpy.random.random(3) - 0.5)
-    >>> for axes in _AXES2TUPLE.keys():
-    ...    R = euler_matrix(ai, aj, ak, axes)
-    >>> for axes in _TUPLE2AXES.keys():
-    ...    R = euler_matrix(ai, aj, ak, axes)
-
-    """
-    try:
-        firstaxis, parity, repetition, frame = _AXES2TUPLE[axes]
-    except (AttributeError, KeyError):
-        _ = _TUPLE2AXES[axes]
-        firstaxis, parity, repetition, frame = axes
-
-    i = firstaxis
-    j = _NEXT_AXIS[i+parity]
-    k = _NEXT_AXIS[i-parity+1]
-
-    if frame:
-        ai, ak = ak, ai
-    if parity:
-        ai, aj, ak = -ai, -aj, -ak
-
-    si, sj, sk = math.sin(ai), math.sin(aj), math.sin(ak)
-    ci, cj, ck = math.cos(ai), math.cos(aj), math.cos(ak)
-    cc, cs = ci*ck, ci*sk
-    sc, ss = si*ck, si*sk
-
-    M = numpy.identity(4)
-    if repetition:
-        M[i, i] = cj
-        M[i, j] = sj*si
-        M[i, k] = sj*ci
-        M[j, i] = sj*sk
-        M[j, j] = -cj*ss+cc
-        M[j, k] = -cj*cs-sc
-        M[k, i] = -sj*ck
-        M[k, j] = cj*sc+cs
-        M[k, k] = cj*cc-ss
-    else:
-        M[i, i] = cj*ck
-        M[i, j] = sj*sc-cs
-        M[i, k] = sj*cc+ss
-        M[j, i] = cj*sk
-        M[j, j] = sj*ss+cc
-        M[j, k] = sj*cs-sc
-        M[k, i] = -sj
-        M[k, j] = cj*si
-        M[k, k] = cj*ci
-    return M
-
-
-def euler_from_matrix(matrix, axes='sxyz'):
-    """Return Euler angles from rotation matrix for specified axis sequence.
-
-    axes : One of 24 axis sequences as string or encoded tuple
-
-    Note that many Euler angle triplets can describe one matrix.
-
-    >>> R0 = euler_matrix(1, 2, 3, 'syxz')
-    >>> al, be, ga = euler_from_matrix(R0, 'syxz')
-    >>> R1 = euler_matrix(al, be, ga, 'syxz')
-    >>> numpy.allclose(R0, R1)
-    True
-    >>> angles = (4.0*math.pi) * (numpy.random.random(3) - 0.5)
-    >>> for axes in _AXES2TUPLE.keys():
-    ...    R0 = euler_matrix(axes=axes, *angles)
-    ...    R1 = euler_matrix(axes=axes, *euler_from_matrix(R0, axes))
-    ...    if not numpy.allclose(R0, R1): print axes, "failed"
-
-    """
-    try:
-        firstaxis, parity, repetition, frame = _AXES2TUPLE[axes.lower()]
-    except (AttributeError, KeyError):
-        _ = _TUPLE2AXES[axes]
-        firstaxis, parity, repetition, frame = axes
-
-    i = firstaxis
-    j = _NEXT_AXIS[i+parity]
-    k = _NEXT_AXIS[i-parity+1]
-
-    M = numpy.array(matrix, dtype=numpy.float64, copy=False)[:3, :3]
-    if repetition:
-        sy = math.sqrt(M[i, j]*M[i, j] + M[i, k]*M[i, k])
-        if sy > _EPS:
-            ax = math.atan2( M[i, j],  M[i, k])
-            ay = math.atan2( sy,       M[i, i])
-            az = math.atan2( M[j, i], -M[k, i])
-        else:
-            ax = math.atan2(-M[j, k],  M[j, j])
-            ay = math.atan2( sy,       M[i, i])
-            az = 0.0
-    else:
-        cy = math.sqrt(M[i, i]*M[i, i] + M[j, i]*M[j, i])
-        if cy > _EPS:
-            ax = math.atan2( M[k, j],  M[k, k])
-            ay = math.atan2(-M[k, i],  cy)
-            az = math.atan2( M[j, i],  M[i, i])
-        else:
-            ax = math.atan2(-M[j, k],  M[j, j])
-            ay = math.atan2(-M[k, i],  cy)
-            az = 0.0
-
-    if parity:
-        ax, ay, az = -ax, -ay, -az
-    if frame:
-        ax, az = az, ax
-    return ax, ay, az
-
-
-def euler_from_quaternion(quaternion, axes='sxyz'):
-    """Return Euler angles from quaternion for specified axis sequence.
-
-    >>> angles = euler_from_quaternion([0.06146124, 0, 0, 0.99810947])
-    >>> numpy.allclose(angles, [0.123, 0, 0])
-    True
-
-    """
-    return euler_from_matrix(quaternion_matrix(quaternion), axes)
-
-
-def quaternion_from_euler(ai, aj, ak, axes='sxyz'):
-    """Return quaternion from Euler angles and axis sequence.
-
-    ai, aj, ak : Euler's roll, pitch and yaw angles
-    axes : One of 24 axis sequences as string or encoded tuple
-
-    >>> q = quaternion_from_euler(1, 2, 3, 'ryxz')
-    >>> numpy.allclose(q, [0.310622, -0.718287, 0.444435, 0.435953])
-    True
-
-    """
-    try:
-        firstaxis, parity, repetition, frame = _AXES2TUPLE[axes.lower()]
-    except (AttributeError, KeyError):
-        _ = _TUPLE2AXES[axes]
-        firstaxis, parity, repetition, frame = axes
-
-    i = firstaxis
-    j = _NEXT_AXIS[i+parity]
-    k = _NEXT_AXIS[i-parity+1]
-
-    if frame:
-        ai, ak = ak, ai
-    if parity:
-        aj = -aj
-
-    ai /= 2.0
-    aj /= 2.0
-    ak /= 2.0
-    ci = math.cos(ai)
-    si = math.sin(ai)
-    cj = math.cos(aj)
-    sj = math.sin(aj)
-    ck = math.cos(ak)
-    sk = math.sin(ak)
-    cc = ci*ck
-    cs = ci*sk
-    sc = si*ck
-    ss = si*sk
-
-    quaternion = numpy.empty((4, ), dtype=numpy.float64)
-    if repetition:
-        quaternion[i] = cj*(cs + sc)
-        quaternion[j] = sj*(cc + ss)
-        quaternion[k] = sj*(cs - sc)
-        quaternion[3] = cj*(cc - ss)
-    else:
-        quaternion[i] = cj*sc - sj*cs
-        quaternion[j] = cj*ss + sj*cc
-        quaternion[k] = cj*cs - sj*sc
-        quaternion[3] = cj*cc + sj*ss
-    if parity:
-        quaternion[j] *= -1
-
-    return quaternion
-
-
-def quaternion_about_axis(angle, axis):
-    """Return quaternion for rotation about axis.
-
-    >>> q = quaternion_about_axis(0.123, (1, 0, 0))
-    >>> numpy.allclose(q, [0.06146124, 0, 0, 0.99810947])
-    True
-
-    """
-    quaternion = numpy.zeros((4, ), dtype=numpy.float64)
-    quaternion[:3] = axis[:3]
-    qlen = vector_norm(quaternion)
-    if qlen > _EPS:
-        quaternion *= math.sin(angle/2.0) / qlen
-    quaternion[3] = math.cos(angle/2.0)
-    return quaternion
-
-
-def quaternion_matrix(quaternion):
-    """Return homogeneous rotation matrix from quaternion.
-
-    >>> R = quaternion_matrix([0.06146124, 0, 0, 0.99810947])
-    >>> numpy.allclose(R, rotation_matrix(0.123, (1, 0, 0)))
-    True
-
-    """
-    q = numpy.array(quaternion[:4], dtype=numpy.float64, copy=True)
-    nq = numpy.dot(q, q)
-    if nq < _EPS:
-        return numpy.identity(4)
-    q *= math.sqrt(2.0 / nq)
-    q = numpy.outer(q, q)
-    return numpy.array((
-        (1.0-q[1, 1]-q[2, 2],     q[0, 1]-q[2, 3],     q[0, 2]+q[1, 3], 0.0),
-        (    q[0, 1]+q[2, 3], 1.0-q[0, 0]-q[2, 2],     q[1, 2]-q[0, 3], 0.0),
-        (    q[0, 2]-q[1, 3],     q[1, 2]+q[0, 3], 1.0-q[0, 0]-q[1, 1], 0.0),
-        (                0.0,                 0.0,                 0.0, 1.0)
-        ), dtype=numpy.float64)
-
-
-def quaternion_from_matrix(matrix):
-    """Return quaternion from rotation matrix.
-
-    >>> R = rotation_matrix(0.123, (1, 2, 3))
-    >>> q = quaternion_from_matrix(R)
-    >>> numpy.allclose(q, [0.0164262, 0.0328524, 0.0492786, 0.9981095])
-    True
-
-    """
-    q = numpy.empty((4, ), dtype=numpy.float64)
-    M = numpy.array(matrix, dtype=numpy.float64, copy=False)[:4, :4]
-    t = numpy.trace(M)
-    if t > M[3, 3]:
-        q[3] = t
-        q[2] = M[1, 0] - M[0, 1]
-        q[1] = M[0, 2] - M[2, 0]
-        q[0] = M[2, 1] - M[1, 2]
-    else:
-        i, j, k = 0, 1, 2
-        if M[1, 1] > M[0, 0]:
-            i, j, k = 1, 2, 0
-        if M[2, 2] > M[i, i]:
-            i, j, k = 2, 0, 1
-        t = M[i, i] - (M[j, j] + M[k, k]) + M[3, 3]
-        q[i] = t
-        q[j] = M[i, j] + M[j, i]
-        q[k] = M[k, i] + M[i, k]
-        q[3] = M[k, j] - M[j, k]
-    q *= 0.5 / math.sqrt(t * M[3, 3])
-    return q
-
-
-def quaternion_multiply(quaternion1, quaternion0):
-    """Return multiplication of two quaternions.
-
-    >>> q = quaternion_multiply([1, -2, 3, 4], [-5, 6, 7, 8])
-    >>> numpy.allclose(q, [-44, -14, 48, 28])
-    True
-
-    """
-    x0, y0, z0, w0 = quaternion0
-    x1, y1, z1, w1 = quaternion1
-    return numpy.array((
-         x1*w0 + y1*z0 - z1*y0 + w1*x0,
-        -x1*z0 + y1*w0 + z1*x0 + w1*y0,
-         x1*y0 - y1*x0 + z1*w0 + w1*z0,
-        -x1*x0 - y1*y0 - z1*z0 + w1*w0), dtype=numpy.float64)
-
-
-def quaternion_conjugate(quaternion):
-    """Return conjugate of quaternion.
-
-    >>> q0 = random_quaternion()
-    >>> q1 = quaternion_conjugate(q0)
-    >>> q1[3] == q0[3] and all(q1[:3] == -q0[:3])
-    True
-
-    """
-    return numpy.array((-quaternion[0], -quaternion[1],
-                        -quaternion[2], quaternion[3]), dtype=numpy.float64)
-
-
-def quaternion_inverse(quaternion):
-    """Return inverse of quaternion.
-
-    >>> q0 = random_quaternion()
-    >>> q1 = quaternion_inverse(q0)
-    >>> numpy.allclose(quaternion_multiply(q0, q1), [0, 0, 0, 1])
-    True
-
-    """
-    return quaternion_conjugate(quaternion) / numpy.dot(quaternion, quaternion)
-
-
-def quaternion_slerp(quat0, quat1, fraction, spin=0, shortestpath=True):
-    """Return spherical linear interpolation between two quaternions.
-
-    >>> q0 = random_quaternion()
-    >>> q1 = random_quaternion()
-    >>> q = quaternion_slerp(q0, q1, 0.0)
-    >>> numpy.allclose(q, q0)
-    True
-    >>> q = quaternion_slerp(q0, q1, 1.0, 1)
-    >>> numpy.allclose(q, q1)
-    True
-    >>> q = quaternion_slerp(q0, q1, 0.5)
-    >>> angle = math.acos(numpy.dot(q0, q))
-    >>> numpy.allclose(2.0, math.acos(numpy.dot(q0, q1)) / angle) or \
-        numpy.allclose(2.0, math.acos(-numpy.dot(q0, q1)) / angle)
-    True
-
-    """
-    q0 = unit_vector(quat0[:4])
-    q1 = unit_vector(quat1[:4])
-    if fraction == 0.0:
-        return q0
-    elif fraction == 1.0:
-        return q1
-    d = numpy.dot(q0, q1)
-    if abs(abs(d) - 1.0) < _EPS:
-        return q0
-    if shortestpath and d < 0.0:
-        # invert rotation
-        d = -d
-        q1 *= -1.0
-    angle = math.acos(d) + spin * math.pi
-    if abs(angle) < _EPS:
-        return q0
-    isin = 1.0 / math.sin(angle)
-    q0 *= math.sin((1.0 - fraction) * angle) * isin
-    q1 *= math.sin(fraction * angle) * isin
-    q0 += q1
-    return q0
-
-
-def random_quaternion(rand=None):
-    """Return uniform random unit quaternion.
-
-    rand: array like or None
-        Three independent random variables that are uniformly distributed
-        between 0 and 1.
-
-    >>> q = random_quaternion()
-    >>> numpy.allclose(1.0, vector_norm(q))
-    True
-    >>> q = random_quaternion(numpy.random.random(3))
-    >>> q.shape
-    (4,)
-
-    """
-    if rand is None:
-        rand = numpy.random.rand(3)
-    else:
-        assert len(rand) == 3
-    r1 = numpy.sqrt(1.0 - rand[0])
-    r2 = numpy.sqrt(rand[0])
-    pi2 = math.pi * 2.0
-    t1 = pi2 * rand[1]
-    t2 = pi2 * rand[2]
-    return numpy.array((numpy.sin(t1)*r1,
-                        numpy.cos(t1)*r1,
-                        numpy.sin(t2)*r2,
-                        numpy.cos(t2)*r2), dtype=numpy.float64)
-
-
-def random_rotation_matrix(rand=None):
-    """Return uniform random rotation matrix.
-
-    rnd: array like
-        Three independent random variables that are uniformly distributed
-        between 0 and 1 for each returned quaternion.
-
-    >>> R = random_rotation_matrix()
-    >>> numpy.allclose(numpy.dot(R.T, R), numpy.identity(4))
-    True
-
-    """
-    return quaternion_matrix(random_quaternion(rand))
-
-
-class Arcball(object):
-    """Virtual Trackball Control.
-
-    >>> ball = Arcball()
-    >>> ball = Arcball(initial=numpy.identity(4))
-    >>> ball.place([320, 320], 320)
-    >>> ball.down([500, 250])
-    >>> ball.drag([475, 275])
-    >>> R = ball.matrix()
-    >>> numpy.allclose(numpy.sum(R), 3.90583455)
-    True
-    >>> ball = Arcball(initial=[0, 0, 0, 1])
-    >>> ball.place([320, 320], 320)
-    >>> ball.setaxes([1,1,0], [-1, 1, 0])
-    >>> ball.setconstrain(True)
-    >>> ball.down([400, 200])
-    >>> ball.drag([200, 400])
-    >>> R = ball.matrix()
-    >>> numpy.allclose(numpy.sum(R), 0.2055924)
-    True
-    >>> ball.next()
-
-    """
-
-    def __init__(self, initial=None):
-        """Initialize virtual trackball control.
-
-        initial : quaternion or rotation matrix
-
-        """
-        self._axis = None
-        self._axes = None
-        self._radius = 1.0
-        self._center = [0.0, 0.0]
-        self._vdown = numpy.array([0, 0, 1], dtype=numpy.float64)
-        self._constrain = False
-
-        if initial is None:
-            self._qdown = numpy.array([0, 0, 0, 1], dtype=numpy.float64)
-        else:
-            initial = numpy.array(initial, dtype=numpy.float64)
-            if initial.shape == (4, 4):
-                self._qdown = quaternion_from_matrix(initial)
-            elif initial.shape == (4, ):
-                initial /= vector_norm(initial)
-                self._qdown = initial
-            else:
-                raise ValueError("initial not a quaternion or matrix.")
-
-        self._qnow = self._qpre = self._qdown
-
-    def place(self, center, radius):
-        """Place Arcball, e.g. when window size changes.
-
-        center : sequence[2]
-            Window coordinates of trackball center.
-        radius : float
-            Radius of trackball in window coordinates.
-
-        """
-        self._radius = float(radius)
-        self._center[0] = center[0]
-        self._center[1] = center[1]
-
-    def setaxes(self, *axes):
-        """Set axes to constrain rotations."""
-        if axes is None:
-            self._axes = None
-        else:
-            self._axes = [unit_vector(axis) for axis in axes]
-
-    def setconstrain(self, constrain):
-        """Set state of constrain to axis mode."""
-        self._constrain = constrain == True
-
-    def getconstrain(self):
-        """Return state of constrain to axis mode."""
-        return self._constrain
-
-    def down(self, point):
-        """Set initial cursor window coordinates and pick constrain-axis."""
-        self._vdown = arcball_map_to_sphere(point, self._center, self._radius)
-        self._qdown = self._qpre = self._qnow
-
-        if self._constrain and self._axes is not None:
-            self._axis = arcball_nearest_axis(self._vdown, self._axes)
-            self._vdown = arcball_constrain_to_axis(self._vdown, self._axis)
-        else:
-            self._axis = None
-
-    def drag(self, point):
-        """Update current cursor window coordinates."""
-        vnow = arcball_map_to_sphere(point, self._center, self._radius)
-
-        if self._axis is not None:
-            vnow = arcball_constrain_to_axis(vnow, self._axis)
-
-        self._qpre = self._qnow
-
-        t = numpy.cross(self._vdown, vnow)
-        if numpy.dot(t, t) < _EPS:
-            self._qnow = self._qdown
-        else:
-            q = [t[0], t[1], t[2], numpy.dot(self._vdown, vnow)]
-            self._qnow = quaternion_multiply(q, self._qdown)
-
-    def next(self, acceleration=0.0):
-        """Continue rotation in direction of last drag."""
-        q = quaternion_slerp(self._qpre, self._qnow, 2.0+acceleration, False)
-        self._qpre, self._qnow = self._qnow, q
-
-    def matrix(self):
-        """Return homogeneous rotation matrix."""
-        return quaternion_matrix(self._qnow)
-
-
-def arcball_map_to_sphere(point, center, radius):
-    """Return unit sphere coordinates from window coordinates."""
-    v = numpy.array(((point[0] - center[0]) / radius,
-                     (center[1] - point[1]) / radius,
-                     0.0), dtype=numpy.float64)
-    n = v[0]*v[0] + v[1]*v[1]
-    if n > 1.0:
-        v /= math.sqrt(n) # position outside of sphere
-    else:
-        v[2] = math.sqrt(1.0 - n)
-    return v
-
-
-def arcball_constrain_to_axis(point, axis):
-    """Return sphere point perpendicular to axis."""
-    v = numpy.array(point, dtype=numpy.float64, copy=True)
-    a = numpy.array(axis, dtype=numpy.float64, copy=True)
-    v -= a * numpy.dot(a, v) # on plane
-    n = vector_norm(v)
-    if n > _EPS:
-        if v[2] < 0.0:
-            v *= -1.0
-        v /= n
-        return v
-    if a[2] == 1.0:
-        return numpy.array([1, 0, 0], dtype=numpy.float64)
-    return unit_vector([-a[1], a[0], 0])
-
-
-def arcball_nearest_axis(point, axes):
-    """Return axis, which arc is nearest to point."""
-    point = numpy.array(point, dtype=numpy.float64, copy=False)
-    nearest = None
-    mx = -1.0
-    for axis in axes:
-        t = numpy.dot(arcball_constrain_to_axis(point, axis), point)
-        if t > mx:
-            nearest = axis
-            mx = t
-    return nearest
-
-
-# epsilon for testing whether a number is close to zero
-_EPS = numpy.finfo(float).eps * 4.0
-
-# axis sequences for Euler angles
-_NEXT_AXIS = [1, 2, 0, 1]
-
-# map axes strings to/from tuples of inner axis, parity, repetition, frame
-_AXES2TUPLE = {
-    'sxyz': (0, 0, 0, 0), 'sxyx': (0, 0, 1, 0), 'sxzy': (0, 1, 0, 0),
-    'sxzx': (0, 1, 1, 0), 'syzx': (1, 0, 0, 0), 'syzy': (1, 0, 1, 0),
-    'syxz': (1, 1, 0, 0), 'syxy': (1, 1, 1, 0), 'szxy': (2, 0, 0, 0),
-    'szxz': (2, 0, 1, 0), 'szyx': (2, 1, 0, 0), 'szyz': (2, 1, 1, 0),
-    'rzyx': (0, 0, 0, 1), 'rxyx': (0, 0, 1, 1), 'ryzx': (0, 1, 0, 1),
-    'rxzx': (0, 1, 1, 1), 'rxzy': (1, 0, 0, 1), 'ryzy': (1, 0, 1, 1),
-    'rzxy': (1, 1, 0, 1), 'ryxy': (1, 1, 1, 1), 'ryxz': (2, 0, 0, 1),
-    'rzxz': (2, 0, 1, 1), 'rxyz': (2, 1, 0, 1), 'rzyz': (2, 1, 1, 1)}
-
-_TUPLE2AXES = dict((v, k) for k, v in _AXES2TUPLE.items())
-
-# helper functions
-
-def vector_norm(data, axis=None, out=None):
-    """Return length, i.e. eucledian norm, of ndarray along axis.
-
-    >>> v = numpy.random.random(3)
-    >>> n = vector_norm(v)
-    >>> numpy.allclose(n, numpy.linalg.norm(v))
-    True
-    >>> v = numpy.random.rand(6, 5, 3)
-    >>> n = vector_norm(v, axis=-1)
-    >>> numpy.allclose(n, numpy.sqrt(numpy.sum(v*v, axis=2)))
-    True
-    >>> n = vector_norm(v, axis=1)
-    >>> numpy.allclose(n, numpy.sqrt(numpy.sum(v*v, axis=1)))
-    True
-    >>> v = numpy.random.rand(5, 4, 3)
-    >>> n = numpy.empty((5, 3), dtype=numpy.float64)
-    >>> vector_norm(v, axis=1, out=n)
-    >>> numpy.allclose(n, numpy.sqrt(numpy.sum(v*v, axis=1)))
-    True
-    >>> vector_norm([])
-    0.0
-    >>> vector_norm([1.0])
-    1.0
-
-    """
-    data = numpy.array(data, dtype=numpy.float64, copy=True)
-    if out is None:
-        if data.ndim == 1:
-            return math.sqrt(numpy.dot(data, data))
-        data *= data
-        out = numpy.atleast_1d(numpy.sum(data, axis=axis))
-        numpy.sqrt(out, out)
-        return out
-    else:
-        data *= data
-        numpy.sum(data, axis=axis, out=out)
-        numpy.sqrt(out, out)
-
-
-def unit_vector(data, axis=None, out=None):
-    """Return ndarray normalized by length, i.e. eucledian norm, along axis.
-
-    >>> v0 = numpy.random.random(3)
-    >>> v1 = unit_vector(v0)
-    >>> numpy.allclose(v1, v0 / numpy.linalg.norm(v0))
-    True
-    >>> v0 = numpy.random.rand(5, 4, 3)
-    >>> v1 = unit_vector(v0, axis=-1)
-    >>> v2 = v0 / numpy.expand_dims(numpy.sqrt(numpy.sum(v0*v0, axis=2)), 2)
-    >>> numpy.allclose(v1, v2)
-    True
-    >>> v1 = unit_vector(v0, axis=1)
-    >>> v2 = v0 / numpy.expand_dims(numpy.sqrt(numpy.sum(v0*v0, axis=1)), 1)
-    >>> numpy.allclose(v1, v2)
-    True
-    >>> v1 = numpy.empty((5, 4, 3), dtype=numpy.float64)
-    >>> unit_vector(v0, axis=1, out=v1)
-    >>> numpy.allclose(v1, v2)
-    True
-    >>> list(unit_vector([]))
-    []
-    >>> list(unit_vector([1.0]))
-    [1.0]
-
-    """
-    if out is None:
-        data = numpy.array(data, dtype=numpy.float64, copy=True)
-        if data.ndim == 1:
-            data /= math.sqrt(numpy.dot(data, data))
-            return data
-    else:
-        if out is not data:
-            out[:] = numpy.array(data, copy=False)
-        data = out
-    length = numpy.atleast_1d(numpy.sum(data*data, axis))
-    numpy.sqrt(length, length)
-    if axis is not None:
-        length = numpy.expand_dims(length, axis)
-    data /= length
-    if out is None:
-        return data
-
-
-def random_vector(size):
-    """Return array of random doubles in the half-open interval [0.0, 1.0).
-
-    >>> v = random_vector(10000)
-    >>> numpy.all(v >= 0.0) and numpy.all(v < 1.0)
-    True
-    >>> v0 = random_vector(10)
-    >>> v1 = random_vector(10)
-    >>> numpy.any(v0 == v1)
-    False
-
-    """
-    return numpy.random.random(size)
-
-
-def inverse_matrix(matrix):
-    """Return inverse of square transformation matrix.
-
-    >>> M0 = random_rotation_matrix()
-    >>> M1 = inverse_matrix(M0.T)
-    >>> numpy.allclose(M1, numpy.linalg.inv(M0.T))
-    True
-    >>> for size in range(1, 7):
-    ...     M0 = numpy.random.rand(size, size)
-    ...     M1 = inverse_matrix(M0)
-    ...     if not numpy.allclose(M1, numpy.linalg.inv(M0)): print size
-
-    """
-    return numpy.linalg.inv(matrix)
-
-
-def concatenate_matrices(*matrices):
-    """Return concatenation of series of transformation matrices.
-
-    >>> M = numpy.random.rand(16).reshape((4, 4)) - 0.5
-    >>> numpy.allclose(M, concatenate_matrices(M))
-    True
-    >>> numpy.allclose(numpy.dot(M, M.T), concatenate_matrices(M, M.T))
-    True
-
-    """
-    M = numpy.identity(4)
-    for i in matrices:
-        M = numpy.dot(M, i)
-    return M
-
-
-def is_same_transform(matrix0, matrix1):
-    """Return True if two matrices perform same transformation.
-
-    >>> is_same_transform(numpy.identity(4), numpy.identity(4))
-    True
-    >>> is_same_transform(numpy.identity(4), random_rotation_matrix())
-    False
-
-    """
-    matrix0 = numpy.array(matrix0, dtype=numpy.float64, copy=True)
-    matrix0 /= matrix0[3, 3]
-    matrix1 = numpy.array(matrix1, dtype=numpy.float64, copy=True)
-    matrix1 /= matrix1[3, 3]
-    return numpy.allclose(matrix0, matrix1)
-
-
-def _import_module(module_name, warn=True, prefix='_py_', ignore='_'):
-    """Try import all public attributes from module into global namespace.
-
-    Existing attributes with name clashes are renamed with prefix.
-    Attributes starting with underscore are ignored by default.
-
-    Return True on successful import.
-
-    """
-    try:
-        module = __import__(module_name)
-    except ImportError:
-        if warn:
-            warnings.warn("Failed to import module " + module_name)
-    else:
-        for attr in dir(module):
-            if ignore and attr.startswith(ignore):
-                continue
-            if prefix:
-                if attr in globals():
-                    globals()[prefix + attr] = globals()[attr]
-                elif warn:
-                    warnings.warn("No Python implementation of " + attr)
-            globals()[attr] = getattr(module, attr)
-        return True
diff --git a/modules/python/test/tst_scene_render.py b/modules/python/test/tst_scene_render.py
new file mode 100644
index 0000000..25d5a40
--- /dev/null
+++ b/modules/python/test/tst_scene_render.py
@@ -0,0 +1,119 @@
+#!/usr/bin/env python
+
+
+# Python 2/3 compatibility
+from __future__ import print_function
+
+import numpy as np
+from numpy import pi, sin, cos
+
+import cv2
+
+defaultSize = 512
+
+class TestSceneRender():
+
+    def __init__(self, bgImg = None, fgImg = None, deformation = False, noise = 0.0, speed = 0.25, **params):
+        self.time = 0.0
+        self.timeStep = 1.0 / 30.0
+        self.foreground = fgImg
+        self.deformation = deformation
+        self.noise = noise
+        self.speed = speed
+
+        if bgImg is not None:
+            self.sceneBg = bgImg.copy()
+        else:
+            self.sceneBg = np.zeros(defaultSize, defaultSize, np.uint8)
+
+        self.w = self.sceneBg.shape[0]
+        self.h = self.sceneBg.shape[1]
+
+        if fgImg is not None:
+            self.foreground = fgImg.copy()
+            self.center = self.currentCenter = (int(self.w/2 - fgImg.shape[0]/2), int(self.h/2 - fgImg.shape[1]/2))
+
+            self.xAmpl = self.sceneBg.shape[0] - (self.center[0] + fgImg.shape[0])
+            self.yAmpl = self.sceneBg.shape[1] - (self.center[1] + fgImg.shape[1])
+
+        self.initialRect = np.array([ (self.h/2, self.w/2), (self.h/2, self.w/2 + self.w/10),
+         (self.h/2 + self.h/10, self.w/2 + self.w/10), (self.h/2 + self.h/10, self.w/2)]).astype(int)
+        self.currentRect = self.initialRect
+        np.random.seed(10)
+
+    def getXOffset(self, time):
+        return int(self.xAmpl*cos(time*self.speed))
+
+
+    def getYOffset(self, time):
+        return int(self.yAmpl*sin(time*self.speed))
+
+    def setInitialRect(self, rect):
+        self.initialRect = rect
+
+    def getRectInTime(self, time):
+
+        if self.foreground is not None:
+            tmp = np.array(self.center) + np.array((self.getXOffset(time), self.getYOffset(time)))
+            x0, y0 = tmp
+            x1, y1 = tmp + self.foreground.shape[0:2]
+            return np.array([y0, x0, y1, x1])
+        else:
+            x0, y0 = self.initialRect[0] + np.array((self.getXOffset(time), self.getYOffset(time)))
+            x1, y1 = self.initialRect[2] + np.array((self.getXOffset(time), self.getYOffset(time)))
+            return np.array([y0, x0, y1, x1])
+
+    def getCurrentRect(self):
+
+        if self.foreground is not None:
+
+            x0 = self.currentCenter[0]
+            y0 = self.currentCenter[1]
+            x1 = self.currentCenter[0] + self.foreground.shape[0]
+            y1 = self.currentCenter[1] + self.foreground.shape[1]
+            return np.array([y0, x0, y1, x1])
+        else:
+            x0, y0 = self.currentRect[0]
+            x1, y1 = self.currentRect[2]
+            return np.array([x0, y0, x1, y1])
+
+    def getNextFrame(self):
+        img = self.sceneBg.copy()
+
+        if self.foreground is not None:
+            self.currentCenter = (self.center[0] + self.getXOffset(self.time), self.center[1] + self.getYOffset(self.time))
+            img[self.currentCenter[0]:self.currentCenter[0]+self.foreground.shape[0],
+             self.currentCenter[1]:self.currentCenter[1]+self.foreground.shape[1]] = self.foreground
+        else:
+            self.currentRect = self.initialRect + np.int( 30*cos(self.time) + 50*sin(self.time/3))
+            if self.deformation:
+                self.currentRect[1:3] += int(self.h/20*cos(self.time))
+            cv2.fillConvexPoly(img, self.currentRect, (0, 0, 255))
+
+        self.time += self.timeStep
+
+        if self.noise:
+            noise = np.zeros(self.sceneBg.shape, np.int8)
+            cv2.randn(noise, np.zeros(3), np.ones(3)*255*self.noise)
+            img = cv2.add(img, noise, dtype=cv2.CV_8UC3)
+        return img
+
+    def resetTime(self):
+        self.time = 0.0
+
+
+if __name__ == '__main__':
+
+    backGr = cv2.imread('../../../samples/data/lena.jpg')
+
+    render = TestSceneRender(backGr, noise = 0.5)
+
+    while True:
+
+        img = render.getNextFrame()
+        cv2.imshow('img', img)
+
+        ch = cv2.waitKey(3)
+        if ch == 27:
+            break
+    cv2.destroyAllWindows()
diff --git a/modules/shape/include/opencv2/shape.hpp b/modules/shape/include/opencv2/shape.hpp
index 6999476..f302b6b 100644
--- a/modules/shape/include/opencv2/shape.hpp
+++ b/modules/shape/include/opencv2/shape.hpp
@@ -40,8 +40,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_SHAPE_HPP__
-#define __OPENCV_SHAPE_HPP__
+#ifndef OPENCV_SHAPE_HPP
+#define OPENCV_SHAPE_HPP
 
 #include "opencv2/shape/emdL1.hpp"
 #include "opencv2/shape/shape_transformer.hpp"
diff --git a/modules/shape/include/opencv2/shape/emdL1.hpp b/modules/shape/include/opencv2/shape/emdL1.hpp
index 1dfa758..a15d68c 100644
--- a/modules/shape/include/opencv2/shape/emdL1.hpp
+++ b/modules/shape/include/opencv2/shape/emdL1.hpp
@@ -40,8 +40,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_EMD_L1_HPP__
-#define __OPENCV_EMD_L1_HPP__
+#ifndef OPENCV_EMD_L1_HPP
+#define OPENCV_EMD_L1_HPP
 
 #include "opencv2/core.hpp"
 
diff --git a/modules/shape/include/opencv2/shape/hist_cost.hpp b/modules/shape/include/opencv2/shape/hist_cost.hpp
index 15c0a87..21d0d68 100644
--- a/modules/shape/include/opencv2/shape/hist_cost.hpp
+++ b/modules/shape/include/opencv2/shape/hist_cost.hpp
@@ -41,8 +41,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_HIST_COST_HPP__
-#define __OPENCV_HIST_COST_HPP__
+#ifndef OPENCV_HIST_COST_HPP
+#define OPENCV_HIST_COST_HPP
 
 #include "opencv2/imgproc.hpp"
 
diff --git a/modules/shape/include/opencv2/shape/shape_distance.hpp b/modules/shape/include/opencv2/shape/shape_distance.hpp
index 4b0c3b5..e4c3a87 100644
--- a/modules/shape/include/opencv2/shape/shape_distance.hpp
+++ b/modules/shape/include/opencv2/shape/shape_distance.hpp
@@ -41,8 +41,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_SHAPE_SHAPE_DISTANCE_HPP__
-#define __OPENCV_SHAPE_SHAPE_DISTANCE_HPP__
+#ifndef OPENCV_SHAPE_SHAPE_DISTANCE_HPP
+#define OPENCV_SHAPE_SHAPE_DISTANCE_HPP
 #include "opencv2/core.hpp"
 #include "opencv2/shape/hist_cost.hpp"
 #include "opencv2/shape/shape_transformer.hpp"
diff --git a/modules/shape/include/opencv2/shape/shape_transformer.hpp b/modules/shape/include/opencv2/shape/shape_transformer.hpp
index 2180613..ace104e 100644
--- a/modules/shape/include/opencv2/shape/shape_transformer.hpp
+++ b/modules/shape/include/opencv2/shape/shape_transformer.hpp
@@ -41,8 +41,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_SHAPE_SHAPE_TRANSFORM_HPP__
-#define __OPENCV_SHAPE_SHAPE_TRANSFORM_HPP__
+#ifndef OPENCV_SHAPE_SHAPE_TRANSFORM_HPP
+#define OPENCV_SHAPE_SHAPE_TRANSFORM_HPP
 #include <vector>
 #include "opencv2/core.hpp"
 #include "opencv2/imgproc.hpp"
diff --git a/modules/shape/src/aff_trans.cpp b/modules/shape/src/aff_trans.cpp
index ec2342f..bbcd8ab 100644
--- a/modules/shape/src/aff_trans.cpp
+++ b/modules/shape/src/aff_trans.cpp
@@ -79,6 +79,7 @@ public:
     //! write/read
     virtual void write(FileStorage& fs) const
     {
+        writeFormat(fs);
         fs << "name" << name_
            << "affine_type" << int(fullAffine);
     }
@@ -101,6 +102,8 @@ protected:
 void AffineTransformerImpl::warpImage(InputArray transformingImage, OutputArray output,
                                       int flags, int borderMode, const Scalar& borderValue) const
 {
+    CV_INSTRUMENT_REGION()
+
     CV_Assert(!affineMat.empty());
     warpAffine(transformingImage, output, affineMat, transformingImage.getMat().size(), flags, borderMode, borderValue);
 }
@@ -182,6 +185,8 @@ static Mat _localAffineEstimate(const std::vector<Point2f>& shape1, const std::v
 
 void AffineTransformerImpl::estimateTransformation(InputArray _pts1, InputArray _pts2, std::vector<DMatch>& _matches)
 {
+    CV_INSTRUMENT_REGION()
+
     Mat pts1 = _pts1.getMat();
     Mat pts2 = _pts2.getMat();
     CV_Assert((pts1.channels()==2) && (pts1.cols>0) && (pts2.channels()==2) && (pts2.cols>0));
@@ -227,6 +232,8 @@ void AffineTransformerImpl::estimateTransformation(InputArray _pts1, InputArray
 
 float AffineTransformerImpl::applyTransformation(InputArray inPts, OutputArray outPts)
 {
+    CV_INSTRUMENT_REGION()
+
     Mat pts1 = inPts.getMat();
     CV_Assert((pts1.channels()==2) && (pts1.cols>0));
 
diff --git a/modules/shape/src/emdL1.cpp b/modules/shape/src/emdL1.cpp
index 75f1b13..7baa97f 100644
--- a/modules/shape/src/emdL1.cpp
+++ b/modules/shape/src/emdL1.cpp
@@ -787,6 +787,8 @@ float EmdL1::compuTotalFlow()
 
 float cv::EMDL1(InputArray _signature1, InputArray _signature2)
 {
+    CV_INSTRUMENT_REGION()
+
     Mat signature1 = _signature1.getMat(), signature2 = _signature2.getMat();
     EmdL1 emdl1;
     return emdl1.getEMDL1(signature1, signature2);
diff --git a/modules/shape/src/haus_dis.cpp b/modules/shape/src/haus_dis.cpp
index 6f2679f..6f372c4 100644
--- a/modules/shape/src/haus_dis.cpp
+++ b/modules/shape/src/haus_dis.cpp
@@ -77,6 +77,7 @@ public:
     //! write/read
     virtual void write(FileStorage& fs) const
     {
+        writeFormat(fs);
         fs << "name" << name_
            << "distance" << distanceFlag
            << "rank" << rankProportion;
@@ -128,6 +129,8 @@ static float _apply(const Mat &set1, const Mat &set2, int distType, double propR
 
 float HausdorffDistanceExtractorImpl::computeDistance(InputArray contour1, InputArray contour2)
 {
+    CV_INSTRUMENT_REGION()
+
     Mat set1=contour1.getMat(), set2=contour2.getMat();
     if (set1.type() != CV_32F)
         set1.convertTo(set1, CV_32F);
diff --git a/modules/shape/src/hist_cost.cpp b/modules/shape/src/hist_cost.cpp
index 53c2c68..db1d42e 100644
--- a/modules/shape/src/hist_cost.cpp
+++ b/modules/shape/src/hist_cost.cpp
@@ -99,6 +99,7 @@ public:
     //! write/read
     virtual void write(FileStorage& fs) const
     {
+        writeFormat(fs);
         fs << "name" << name_
            << "flag" << flag
            << "dummies" << nDummies
@@ -124,6 +125,8 @@ protected:
 
 void NormHistogramCostExtractorImpl::buildCostMatrix(InputArray _descriptors1, InputArray _descriptors2, OutputArray _costMatrix)
 {
+    CV_INSTRUMENT_REGION()
+
     // size of the costMatrix with dummies //
     Mat descriptors1=_descriptors1.getMat();
     Mat descriptors2=_descriptors2.getMat();
@@ -224,6 +227,7 @@ public:
     //! write/read
     virtual void write(FileStorage& fs) const
     {
+        writeFormat(fs);
         fs << "name" << name_
            << "flag" << flag
            << "dummies" << nDummies
@@ -249,6 +253,8 @@ protected:
 
 void EMDHistogramCostExtractorImpl::buildCostMatrix(InputArray _descriptors1, InputArray _descriptors2, OutputArray _costMatrix)
 {
+    CV_INSTRUMENT_REGION()
+
     // size of the costMatrix with dummies //
     Mat descriptors1=_descriptors1.getMat();
     Mat descriptors2=_descriptors2.getMat();
@@ -350,6 +356,7 @@ public:
     //! write/read
     virtual void write(FileStorage& fs) const
     {
+        writeFormat(fs);
         fs << "name" << name_
            << "dummies" << nDummies
            << "default" << defaultCost;
@@ -370,6 +377,8 @@ protected:
 
 void ChiHistogramCostExtractorImpl::buildCostMatrix(InputArray _descriptors1, InputArray _descriptors2, OutputArray _costMatrix)
 {
+    CV_INSTRUMENT_REGION()
+
     // size of the costMatrix with dummies //
     Mat descriptors1=_descriptors1.getMat();
     Mat descriptors2=_descriptors2.getMat();
@@ -466,6 +475,7 @@ public:
     //! write/read
     virtual void write(FileStorage& fs) const
     {
+        writeFormat(fs);
         fs << "name" << name_
            << "dummies" << nDummies
            << "default" << defaultCost;
@@ -486,6 +496,8 @@ protected:
 
 void EMDL1HistogramCostExtractorImpl::buildCostMatrix(InputArray _descriptors1, InputArray _descriptors2, OutputArray _costMatrix)
 {
+    CV_INSTRUMENT_REGION()
+
     // size of the costMatrix with dummies //
     Mat descriptors1=_descriptors1.getMat();
     Mat descriptors2=_descriptors2.getMat();
diff --git a/modules/shape/src/sc_dis.cpp b/modules/shape/src/sc_dis.cpp
index 3f11e8b..89c6d91 100644
--- a/modules/shape/src/sc_dis.cpp
+++ b/modules/shape/src/sc_dis.cpp
@@ -124,10 +124,8 @@ public:
     virtual void getImages(OutputArray _image1, OutputArray _image2) const
     {
         CV_Assert((!image1.empty()) && (!image2.empty()));
-        _image1.create(image1.size(), image1.type());
-        _image2.create(image2.size(), image2.type());
-        _image1.getMat()=image1;
-        _image2.getMat()=image2;
+        image1.copyTo(_image1);
+        image2.copyTo(_image2);
     }
 
     virtual void setIterations(int _iterations) {CV_Assert(_iterations>0); iterations=_iterations;}
@@ -139,6 +137,7 @@ public:
     //! write/read
     virtual void write(FileStorage& fs) const
     {
+        writeFormat(fs);
         fs << "name" << name_
            << "nRads" << nRadialBins
            << "nAngs" << nAngularBins
@@ -187,6 +186,8 @@ protected:
 
 float ShapeContextDistanceExtractorImpl::computeDistance(InputArray contour1, InputArray contour2)
 {
+    CV_INSTRUMENT_REGION()
+
     // Checking //
     Mat sset1=contour1.getMat(), sset2=contour2.getMat(), set1, set2;
     if (set1.type() != CV_32F)
@@ -493,6 +494,8 @@ void SCDMatcher::matchDescriptors(cv::Mat &descriptors1, cv::Mat &descriptors2,
 void SCDMatcher::buildCostMatrix(const cv::Mat &descriptors1, const cv::Mat &descriptors2,
                                  cv::Mat &costMatrix, cv::Ptr<cv::HistogramCostExtractor> &comparer) const
 {
+    CV_INSTRUMENT_REGION()
+
     comparer->buildCostMatrix(descriptors1, descriptors2, costMatrix);
 }
 
@@ -763,7 +766,7 @@ void SCDMatcher::hungarian(cv::Mat &costMatrix, std::vector<cv::DMatch> &outMatc
     inliers1.reserve(sizeScd1);
     for (size_t kc = 0; kc<inliers1.size(); kc++)
     {
-        if (rowsol[kc]<sizeScd1) // if a real match
+        if (rowsol[kc]<sizeScd2) // if a real match
             inliers1[kc]=1;
         else
             inliers1[kc]=0;
@@ -771,7 +774,7 @@ void SCDMatcher::hungarian(cv::Mat &costMatrix, std::vector<cv::DMatch> &outMatc
     inliers2.reserve(sizeScd2);
     for (size_t kc = 0; kc<inliers2.size(); kc++)
     {
-        if (colsol[kc]<sizeScd2) // if a real match
+        if (colsol[kc]<sizeScd1) // if a real match
             inliers2[kc]=1;
         else
             inliers2[kc]=0;
diff --git a/modules/shape/src/tps_trans.cpp b/modules/shape/src/tps_trans.cpp
index 038fd2a..06cc6d7 100644
--- a/modules/shape/src/tps_trans.cpp
+++ b/modules/shape/src/tps_trans.cpp
@@ -81,6 +81,7 @@ public:
     //! write/read
     virtual void write(FileStorage& fs) const
     {
+        writeFormat(fs);
         fs << "name" << name_
            << "regularization" << regularizationParameter;
     }
@@ -145,6 +146,8 @@ static Point2f _applyTransformation(const Mat &shapeRef, const Point2f point, co
 void ThinPlateSplineShapeTransformerImpl::warpImage(InputArray transformingImage, OutputArray output,
                                       int flags, int borderMode, const Scalar& borderValue) const
 {
+    CV_INSTRUMENT_REGION()
+
     CV_Assert(tpsComputed==true);
 
     Mat theinput = transformingImage.getMat();
@@ -165,6 +168,8 @@ void ThinPlateSplineShapeTransformerImpl::warpImage(InputArray transformingImage
 
 float ThinPlateSplineShapeTransformerImpl::applyTransformation(InputArray inPts, OutputArray outPts)
 {
+    CV_INSTRUMENT_REGION()
+
     CV_Assert(tpsComputed);
     Mat pts1 = inPts.getMat();
     CV_Assert((pts1.channels()==2) && (pts1.cols>0));
@@ -188,6 +193,8 @@ float ThinPlateSplineShapeTransformerImpl::applyTransformation(InputArray inPts,
 void ThinPlateSplineShapeTransformerImpl::estimateTransformation(InputArray _pts1, InputArray _pts2,
                                                                std::vector<DMatch>& _matches )
 {
+    CV_INSTRUMENT_REGION()
+
     Mat pts1 = _pts1.getMat();
     Mat pts2 = _pts2.getMat();
     CV_Assert((pts1.channels()==2) && (pts1.cols>0) && (pts2.channels()==2) && (pts2.cols>0));
diff --git a/modules/stitching/include/opencv2/stitching.hpp b/modules/stitching/include/opencv2/stitching.hpp
index 96cde14..387e1de 100644
--- a/modules/stitching/include/opencv2/stitching.hpp
+++ b/modules/stitching/include/opencv2/stitching.hpp
@@ -40,8 +40,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_STITCHING_STITCHER_HPP__
-#define __OPENCV_STITCHING_STITCHER_HPP__
+#ifndef OPENCV_STITCHING_STITCHER_HPP
+#define OPENCV_STITCHING_STITCHER_HPP
 
 #include "opencv2/core.hpp"
 #include "opencv2/features2d.hpp"
@@ -53,6 +53,12 @@
 #include "opencv2/stitching/detail/blenders.hpp"
 #include "opencv2/stitching/detail/camera.hpp"
 
+
+#if defined(Status)
+#  warning Detected X11 'Status' macro definition, it can cause build conflicts. Please, include this header before any X11 headers.
+#endif
+
+
 /**
 @defgroup stitching Images stitching
 
@@ -63,7 +69,29 @@ one can combine and use them separately.
 
 The implemented stitching pipeline is very similar to the one proposed in @cite BL07 .
 
-![image](StitchingPipeline.jpg)
+![stitching pipeline](StitchingPipeline.jpg)
+
+Camera models
+-------------
+
+There are currently 2 camera models implemented in stitching pipeline.
+
+- _Homography model_ expecting perspective transformations between images
+  implemented in @ref cv::detail::BestOf2NearestMatcher cv::detail::HomographyBasedEstimator
+  cv::detail::BundleAdjusterReproj cv::detail::BundleAdjusterRay
+- _Affine model_ expecting affine transformation with 6 DOF or 4 DOF implemented in
+  @ref cv::detail::AffineBestOf2NearestMatcher cv::detail::AffineBasedEstimator
+  cv::detail::BundleAdjusterAffine cv::detail::BundleAdjusterAffinePartial cv::AffineWarper
+
+Homography model is useful for creating photo panoramas captured by camera,
+while affine-based model can be used to stitch scans and object captured by
+specialized devices. Use @ref cv::Stitcher::create to get preconfigured pipeline for one
+of those models.
+
+ at note
+Certain detailed settings of @ref cv::Stitcher might not make sense. Especially
+you should not mix classes implementing affine model and classes implementing
+Homography model, as they work with different transformations.
 
 @{
     @defgroup stitching_match Features Finding and Images Matching
@@ -104,6 +132,22 @@ public:
         ERR_HOMOGRAPHY_EST_FAIL = 2,
         ERR_CAMERA_PARAMS_ADJUST_FAIL = 3
     };
+    enum Mode
+    {
+        /** Mode for creating photo panoramas. Expects images under perspective
+        transformation and projects resulting pano to sphere.
+
+        @sa detail::BestOf2NearestMatcher SphericalWarper
+        */
+        PANORAMA = 0,
+        /** Mode for composing scans. Expects images under affine transformation does
+        not compensate exposure by default.
+
+        @sa detail::AffineBestOf2NearestMatcher AffineWarper
+        */
+        SCANS = 1,
+
+    };
 
    // Stitcher() {}
     /** @brief Creates a stitcher with the default parameters.
@@ -112,6 +156,15 @@ public:
     @return Stitcher class instance.
      */
     static Stitcher createDefault(bool try_use_gpu = false);
+    /** @brief Creates a Stitcher configured in one of the stitching modes.
+
+    @param mode Scenario for stitcher operation. This is usually determined by source of images
+    to stitch and their transformation. Default parameters will be chosen for operation in given
+    scenario.
+    @param try_use_gpu Flag indicating whether GPU should be used whenever it's possible.
+    @return Stitcher class instance.
+     */
+    static Ptr<Stitcher> create(Mode mode = PANORAMA, bool try_use_gpu = false);
 
     CV_WRAP double registrationResol() const { return registr_resol_; }
     CV_WRAP void setRegistrationResol(double resol_mpx) { registr_resol_ = resol_mpx; }
@@ -153,6 +206,13 @@ public:
     void setBundleAdjuster(Ptr<detail::BundleAdjusterBase> bundle_adjuster)
         { bundle_adjuster_ = bundle_adjuster; }
 
+    /* TODO OpenCV ABI 4.x
+    Ptr<detail::Estimator> estimator() { return estimator_; }
+    const Ptr<detail::Estimator> estimator() const { return estimator_; }
+    void setEstimator(Ptr<detail::Estimator> estimator)
+        { estimator_ = estimator; }
+    */
+
     Ptr<WarperCreator> warper() { return warper_; }
     const Ptr<WarperCreator> warper() const { return warper_; }
     void setWarper(Ptr<WarperCreator> creator) { warper_ = creator; }
@@ -227,6 +287,9 @@ private:
     Ptr<detail::FeaturesMatcher> features_matcher_;
     cv::UMat matching_mask_;
     Ptr<detail::BundleAdjusterBase> bundle_adjuster_;
+    /* TODO OpenCV ABI 4.x
+    Ptr<detail::Estimator> estimator_;
+    */
     bool do_wave_correct_;
     detail::WaveCorrectKind wave_correct_kind_;
     Ptr<WarperCreator> warper_;
@@ -254,4 +317,4 @@ CV_EXPORTS_W Ptr<Stitcher> createStitcher(bool try_use_gpu = false);
 
 } // namespace cv
 
-#endif // __OPENCV_STITCHING_STITCHER_HPP__
+#endif // OPENCV_STITCHING_STITCHER_HPP
diff --git a/modules/stitching/include/opencv2/stitching/detail/autocalib.hpp b/modules/stitching/include/opencv2/stitching/detail/autocalib.hpp
index ccc0aa1..19705e2 100644
--- a/modules/stitching/include/opencv2/stitching/detail/autocalib.hpp
+++ b/modules/stitching/include/opencv2/stitching/detail/autocalib.hpp
@@ -40,8 +40,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_STITCHING_AUTOCALIB_HPP__
-#define __OPENCV_STITCHING_AUTOCALIB_HPP__
+#ifndef OPENCV_STITCHING_AUTOCALIB_HPP
+#define OPENCV_STITCHING_AUTOCALIB_HPP
 
 #include "opencv2/core.hpp"
 #include "matchers.hpp"
@@ -83,4 +83,4 @@ bool CV_EXPORTS calibrateRotatingCamera(const std::vector<Mat> &Hs, Mat &K);
 } // namespace detail
 } // namespace cv
 
-#endif // __OPENCV_STITCHING_AUTOCALIB_HPP__
+#endif // OPENCV_STITCHING_AUTOCALIB_HPP
diff --git a/modules/stitching/include/opencv2/stitching/detail/blenders.hpp b/modules/stitching/include/opencv2/stitching/detail/blenders.hpp
index 0e60725..4ccaa70 100644
--- a/modules/stitching/include/opencv2/stitching/detail/blenders.hpp
+++ b/modules/stitching/include/opencv2/stitching/detail/blenders.hpp
@@ -40,8 +40,12 @@
 //
 //M*/
 
-#ifndef __OPENCV_STITCHING_BLENDERS_HPP__
-#define __OPENCV_STITCHING_BLENDERS_HPP__
+#ifndef OPENCV_STITCHING_BLENDERS_HPP
+#define OPENCV_STITCHING_BLENDERS_HPP
+
+#if defined(NO)
+#  warning Detected Apple 'NO' macro definition, it can cause build conflicts. Please, include this header before any Apple headers.
+#endif
 
 #include "opencv2/core.hpp"
 
@@ -160,4 +164,4 @@ void CV_EXPORTS restoreImageFromLaplacePyrGpu(std::vector<UMat>& pyr);
 } // namespace detail
 } // namespace cv
 
-#endif // __OPENCV_STITCHING_BLENDERS_HPP__
+#endif // OPENCV_STITCHING_BLENDERS_HPP
diff --git a/modules/stitching/include/opencv2/stitching/detail/camera.hpp b/modules/stitching/include/opencv2/stitching/detail/camera.hpp
index c231ba5..7013747 100644
--- a/modules/stitching/include/opencv2/stitching/detail/camera.hpp
+++ b/modules/stitching/include/opencv2/stitching/detail/camera.hpp
@@ -40,8 +40,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_STITCHING_CAMERA_HPP__
-#define __OPENCV_STITCHING_CAMERA_HPP__
+#ifndef OPENCV_STITCHING_CAMERA_HPP
+#define OPENCV_STITCHING_CAMERA_HPP
 
 #include "opencv2/core.hpp"
 
@@ -75,4 +75,4 @@ struct CV_EXPORTS CameraParams
 } // namespace detail
 } // namespace cv
 
-#endif // #ifndef __OPENCV_STITCHING_CAMERA_HPP__
+#endif // #ifndef OPENCV_STITCHING_CAMERA_HPP
diff --git a/modules/stitching/include/opencv2/stitching/detail/exposure_compensate.hpp b/modules/stitching/include/opencv2/stitching/detail/exposure_compensate.hpp
index ef64e12..f5a8122 100644
--- a/modules/stitching/include/opencv2/stitching/detail/exposure_compensate.hpp
+++ b/modules/stitching/include/opencv2/stitching/detail/exposure_compensate.hpp
@@ -40,8 +40,12 @@
 //
 //M*/
 
-#ifndef __OPENCV_STITCHING_EXPOSURE_COMPENSATE_HPP__
-#define __OPENCV_STITCHING_EXPOSURE_COMPENSATE_HPP__
+#ifndef OPENCV_STITCHING_EXPOSURE_COMPENSATE_HPP
+#define OPENCV_STITCHING_EXPOSURE_COMPENSATE_HPP
+
+#if defined(NO)
+#  warning Detected Apple 'NO' macro definition, it can cause build conflicts. Please, include this header before any Apple headers.
+#endif
 
 #include "opencv2/core.hpp"
 
@@ -129,4 +133,4 @@ private:
 } // namespace detail
 } // namespace cv
 
-#endif // __OPENCV_STITCHING_EXPOSURE_COMPENSATE_HPP__
+#endif // OPENCV_STITCHING_EXPOSURE_COMPENSATE_HPP
diff --git a/modules/stitching/include/opencv2/stitching/detail/matchers.hpp b/modules/stitching/include/opencv2/stitching/detail/matchers.hpp
index 8f34bd2..bc81a84 100644
--- a/modules/stitching/include/opencv2/stitching/detail/matchers.hpp
+++ b/modules/stitching/include/opencv2/stitching/detail/matchers.hpp
@@ -40,8 +40,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_STITCHING_MATCHERS_HPP__
-#define __OPENCV_STITCHING_MATCHERS_HPP__
+#ifndef OPENCV_STITCHING_MATCHERS_HPP
+#define OPENCV_STITCHING_MATCHERS_HPP
 
 #include "opencv2/core.hpp"
 #include "opencv2/features2d.hpp"
@@ -83,9 +83,27 @@ public:
     @sa detail::ImageFeatures, Rect_
     */
     void operator ()(InputArray image, ImageFeatures &features, const std::vector<cv::Rect> &rois);
+    /** @brief Finds features in the given images in parallel.
+
+    @param images Source images
+    @param features Found features for each image
+    @param rois Regions of interest for each image
+
+    @sa detail::ImageFeatures, Rect_
+    */
+    void operator ()(InputArrayOfArrays images, std::vector<ImageFeatures> &features,
+                     const std::vector<std::vector<cv::Rect> > &rois);
+    /** @overload */
+    void operator ()(InputArrayOfArrays images, std::vector<ImageFeatures> &features);
     /** @brief Frees unused memory allocated before if there is any. */
     virtual void collectGarbage() {}
 
+    /* TODO OpenCV ABI 4.x
+    reimplement this as public method similar to FeaturesMatcher and remove private function hack
+    @return True, if it's possible to use the same finder instance in parallel, false otherwise
+    bool isThreadSafe() const { return is_thread_safe_; }
+    */
+
 protected:
     /** @brief This method must implement features finding logic in order to make the wrappers
     detail::FeaturesFinder::operator()_ work.
@@ -95,6 +113,10 @@ protected:
 
     @sa detail::ImageFeatures */
     virtual void find(InputArray image, ImageFeatures &features) = 0;
+    /** @brief uses dynamic_cast to determine thread-safety
+    @return True, if it's possible to use the same finder instance in parallel, false otherwise
+    */
+    bool isThreadSafe() const;
 };
 
 /** @brief SURF features finder.
@@ -131,6 +153,26 @@ private:
     Size grid_size;
 };
 
+/** @brief AKAZE features finder. :
+
+ at sa detail::FeaturesFinder, AKAZE
+*/
+class CV_EXPORTS AKAZEFeaturesFinder : public detail::FeaturesFinder
+{
+public:
+    AKAZEFeaturesFinder(int descriptor_type = AKAZE::DESCRIPTOR_MLDB,
+                        int descriptor_size = 0,
+                        int descriptor_channels = 3,
+                        float threshold = 0.001f,
+                        int nOctaves = 4,
+                        int nOctaveLayers = 4,
+                        int diffusivity = KAZE::DIFF_PM_G2);
+
+private:
+    void find(InputArray image, detail::ImageFeatures &features);
+
+    Ptr<AKAZE> akaze;
+};
 
 #ifdef HAVE_OPENCV_XFEATURES2D
 class CV_EXPORTS SurfFeaturesFinderGpu : public FeaturesFinder
@@ -156,7 +198,10 @@ private:
 
 /** @brief Structure containing information about matches between two images.
 
-It's assumed that there is a homography between those images.
+It's assumed that there is a transformation between those images. Transformation may be
+homography or affine transformation based on selected matcher.
+
+ at sa detail::FeaturesMatcher
 */
 struct CV_EXPORTS MatchesInfo
 {
@@ -168,7 +213,7 @@ struct CV_EXPORTS MatchesInfo
     std::vector<DMatch> matches;
     std::vector<uchar> inliers_mask;    //!< Geometrically consistent matches mask
     int num_inliers;                    //!< Number of geometrically consistent matches
-    Mat H;                              //!< Estimated homography
+    Mat H;                              //!< Estimated transformation
     double confidence;                  //!< Confidence two images are from the same panorama
 };
 
@@ -267,9 +312,44 @@ protected:
     int range_width_;
 };
 
+/** @brief Features matcher similar to cv::detail::BestOf2NearestMatcher which
+finds two best matches for each feature and leaves the best one only if the
+ratio between descriptor distances is greater than the threshold match_conf.
+
+Unlike cv::detail::BestOf2NearestMatcher this matcher uses affine
+transformation (affine trasformation estimate will be placed in matches_info).
+
+ at sa cv::detail::FeaturesMatcher cv::detail::BestOf2NearestMatcher
+ */
+class CV_EXPORTS AffineBestOf2NearestMatcher : public BestOf2NearestMatcher
+{
+public:
+    /** @brief Constructs a "best of 2 nearest" matcher that expects affine trasformation
+    between images
+
+    @param full_affine whether to use full affine transformation with 6 degress of freedom or reduced
+    transformation with 4 degrees of freedom using only rotation, translation and uniform scaling
+    @param try_use_gpu Should try to use GPU or not
+    @param match_conf Match distances ration threshold
+    @param num_matches_thresh1 Minimum number of matches required for the 2D affine transform
+    estimation used in the inliers classification step
+
+    @sa cv::estimateAffine2D cv::estimateAffinePartial2D
+     */
+    AffineBestOf2NearestMatcher(bool full_affine = false, bool try_use_gpu = false,
+                                float match_conf = 0.3f, int num_matches_thresh1 = 6) :
+        BestOf2NearestMatcher(try_use_gpu, match_conf, num_matches_thresh1, num_matches_thresh1),
+        full_affine_(full_affine) {}
+
+protected:
+    void match(const ImageFeatures &features1, const ImageFeatures &features2, MatchesInfo &matches_info);
+
+    bool full_affine_;
+};
+
 //! @} stitching_match
 
 } // namespace detail
 } // namespace cv
 
-#endif // __OPENCV_STITCHING_MATCHERS_HPP__
+#endif // OPENCV_STITCHING_MATCHERS_HPP
diff --git a/modules/stitching/include/opencv2/stitching/detail/motion_estimators.hpp b/modules/stitching/include/opencv2/stitching/detail/motion_estimators.hpp
index 2c86e63..5276fd1 100644
--- a/modules/stitching/include/opencv2/stitching/detail/motion_estimators.hpp
+++ b/modules/stitching/include/opencv2/stitching/detail/motion_estimators.hpp
@@ -40,8 +40,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_STITCHING_MOTION_ESTIMATORS_HPP__
-#define __OPENCV_STITCHING_MOTION_ESTIMATORS_HPP__
+#ifndef OPENCV_STITCHING_MOTION_ESTIMATORS_HPP
+#define OPENCV_STITCHING_MOTION_ESTIMATORS_HPP
 
 #include "opencv2/core.hpp"
 #include "matchers.hpp"
@@ -109,6 +109,21 @@ private:
     bool is_focals_estimated_;
 };
 
+/** @brief Affine transformation based estimator.
+
+This estimator uses pairwise tranformations estimated by matcher to estimate
+final transformation for each camera.
+
+ at sa cv::detail::HomographyBasedEstimator
+ */
+class CV_EXPORTS AffineBasedEstimator : public Estimator
+{
+private:
+    virtual bool estimate(const std::vector<ImageFeatures> &features,
+                          const std::vector<MatchesInfo> &pairwise_matches,
+                          std::vector<CameraParams> &cameras);
+};
+
 /** @brief Base class for all camera parameters refinement methods.
  */
 class CV_EXPORTS BundleAdjusterBase : public Estimator
@@ -195,6 +210,26 @@ protected:
 };
 
 
+/** @brief Stub bundle adjuster that does nothing.
+ */
+class CV_EXPORTS NoBundleAdjuster : public BundleAdjusterBase
+{
+public:
+    NoBundleAdjuster() : BundleAdjusterBase(0, 0) {}
+
+private:
+    bool estimate(const std::vector<ImageFeatures> &, const std::vector<MatchesInfo> &,
+                  std::vector<CameraParams> &)
+    {
+        return true;
+    }
+    void setUpInitialCameraParams(const std::vector<CameraParams> &) {}
+    void obtainRefinedCameraParams(std::vector<CameraParams> &) const {}
+    void calcError(Mat &) {}
+    void calcJacobian(Mat &) {}
+};
+
+
 /** @brief Implementation of the camera parameters refinement algorithm which minimizes sum of the reprojection
 error squares
 
@@ -236,6 +271,54 @@ private:
 };
 
 
+/** @brief Bundle adjuster that expects affine transformation
+represented in homogeneous coordinates in R for each camera param. Implements
+camera parameters refinement algorithm which minimizes sum of the reprojection
+error squares
+
+It estimates all transformation parameters. Refinement mask is ignored.
+
+ at sa AffineBasedEstimator AffineBestOf2NearestMatcher BundleAdjusterAffinePartial
+ */
+class CV_EXPORTS BundleAdjusterAffine : public BundleAdjusterBase
+{
+public:
+    BundleAdjusterAffine() : BundleAdjusterBase(6, 2) {}
+
+private:
+    void setUpInitialCameraParams(const std::vector<CameraParams> &cameras);
+    void obtainRefinedCameraParams(std::vector<CameraParams> &cameras) const;
+    void calcError(Mat &err);
+    void calcJacobian(Mat &jac);
+
+    Mat err1_, err2_;
+};
+
+
+/** @brief Bundle adjuster that expects affine transformation with 4 DOF
+represented in homogeneous coordinates in R for each camera param. Implements
+camera parameters refinement algorithm which minimizes sum of the reprojection
+error squares
+
+It estimates all transformation parameters. Refinement mask is ignored.
+
+ at sa AffineBasedEstimator AffineBestOf2NearestMatcher BundleAdjusterAffine
+ */
+class CV_EXPORTS BundleAdjusterAffinePartial : public BundleAdjusterBase
+{
+public:
+    BundleAdjusterAffinePartial() : BundleAdjusterBase(4, 2) {}
+
+private:
+    void setUpInitialCameraParams(const std::vector<CameraParams> &cameras);
+    void obtainRefinedCameraParams(std::vector<CameraParams> &cameras) const;
+    void calcError(Mat &err);
+    void calcJacobian(Mat &jac);
+
+    Mat err1_, err2_;
+};
+
+
 enum WaveCorrectKind
 {
     WAVE_CORRECT_HORIZ,
@@ -271,4 +354,4 @@ void CV_EXPORTS findMaxSpanningTree(
 } // namespace detail
 } // namespace cv
 
-#endif // __OPENCV_STITCHING_MOTION_ESTIMATORS_HPP__
+#endif // OPENCV_STITCHING_MOTION_ESTIMATORS_HPP
diff --git a/modules/stitching/include/opencv2/stitching/detail/seam_finders.hpp b/modules/stitching/include/opencv2/stitching/detail/seam_finders.hpp
index 4ff22c4..a251f48 100644
--- a/modules/stitching/include/opencv2/stitching/detail/seam_finders.hpp
+++ b/modules/stitching/include/opencv2/stitching/detail/seam_finders.hpp
@@ -40,8 +40,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_STITCHING_SEAM_FINDERS_HPP__
-#define __OPENCV_STITCHING_SEAM_FINDERS_HPP__
+#ifndef OPENCV_STITCHING_SEAM_FINDERS_HPP
+#define OPENCV_STITCHING_SEAM_FINDERS_HPP
 
 #include <set>
 #include "opencv2/core.hpp"
@@ -282,4 +282,4 @@ private:
 } // namespace detail
 } // namespace cv
 
-#endif // __OPENCV_STITCHING_SEAM_FINDERS_HPP__
+#endif // OPENCV_STITCHING_SEAM_FINDERS_HPP
diff --git a/modules/stitching/include/opencv2/stitching/detail/timelapsers.hpp b/modules/stitching/include/opencv2/stitching/detail/timelapsers.hpp
index d64c03c..ae37b03 100644
--- a/modules/stitching/include/opencv2/stitching/detail/timelapsers.hpp
+++ b/modules/stitching/include/opencv2/stitching/detail/timelapsers.hpp
@@ -41,8 +41,8 @@
 //M*/
 
 
-#ifndef __OPENCV_STITCHING_TIMELAPSERS_HPP__
-#define __OPENCV_STITCHING_TIMELAPSERS_HPP__
+#ifndef OPENCV_STITCHING_TIMELAPSERS_HPP
+#define OPENCV_STITCHING_TIMELAPSERS_HPP
 
 #include "opencv2/core.hpp"
 
@@ -88,4 +88,4 @@ public:
 } // namespace detail
 } // namespace cv
 
-#endif // __OPENCV_STITCHING_TIMELAPSERS_HPP__
+#endif // OPENCV_STITCHING_TIMELAPSERS_HPP
diff --git a/modules/stitching/include/opencv2/stitching/detail/util.hpp b/modules/stitching/include/opencv2/stitching/detail/util.hpp
index 3845ba5..78301b8 100644
--- a/modules/stitching/include/opencv2/stitching/detail/util.hpp
+++ b/modules/stitching/include/opencv2/stitching/detail/util.hpp
@@ -40,62 +40,12 @@
 //
 //M*/
 
-#ifndef __OPENCV_STITCHING_UTIL_HPP__
-#define __OPENCV_STITCHING_UTIL_HPP__
+#ifndef OPENCV_STITCHING_UTIL_HPP
+#define OPENCV_STITCHING_UTIL_HPP
 
 #include <list>
 #include "opencv2/core.hpp"
 
-#ifndef ENABLE_LOG
-#define ENABLE_LOG 0
-#endif
-
-// TODO remove LOG macros, add logging class
-#if ENABLE_LOG
-#ifdef ANDROID
-  #include <iostream>
-  #include <sstream>
-  #include <android/log.h>
-  #define LOG_STITCHING_MSG(msg) \
-    do { \
-        Stringstream _os; \
-        _os << msg; \
-       __android_log_print(ANDROID_LOG_DEBUG, "STITCHING", "%s", _os.str().c_str()); \
-    } while(0);
-#else
-  #include <iostream>
-  #define LOG_STITCHING_MSG(msg) for(;;) { std::cout << msg; std::cout.flush(); break; }
-#endif
-#else
-  #define LOG_STITCHING_MSG(msg)
-#endif
-
-#define LOG_(_level, _msg)                     \
-    for(;;)                                    \
-    {                                          \
-        using namespace std;                   \
-        if ((_level) >= ::cv::detail::stitchingLogLevel()) \
-        {                                      \
-            LOG_STITCHING_MSG(_msg);           \
-        }                                      \
-    break;                                 \
-    }
-
-
-#define LOG(msg) LOG_(1, msg)
-#define LOG_CHAT(msg) LOG_(0, msg)
-
-#define LOGLN(msg) LOG(msg << std::endl)
-#define LOGLN_CHAT(msg) LOG_CHAT(msg << std::endl)
-
-//#if DEBUG_LOG_CHAT
-//  #define LOG_CHAT(msg) LOG(msg)
-//  #define LOGLN_CHAT(msg) LOGLN(msg)
-//#else
-//  #define LOG_CHAT(msg) do{}while(0)
-//  #define LOGLN_CHAT(msg) do{}while(0)
-//#endif
-
 namespace cv {
 namespace detail {
 
@@ -168,4 +118,4 @@ CV_EXPORTS int& stitchingLogLevel();
 
 #include "util_inl.hpp"
 
-#endif // __OPENCV_STITCHING_UTIL_HPP__
+#endif // OPENCV_STITCHING_UTIL_HPP
diff --git a/modules/stitching/include/opencv2/stitching/detail/util_inl.hpp b/modules/stitching/include/opencv2/stitching/detail/util_inl.hpp
index 6ac6f8e..dafab8b 100644
--- a/modules/stitching/include/opencv2/stitching/detail/util_inl.hpp
+++ b/modules/stitching/include/opencv2/stitching/detail/util_inl.hpp
@@ -40,8 +40,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_STITCHING_UTIL_INL_HPP__
-#define __OPENCV_STITCHING_UTIL_INL_HPP__
+#ifndef OPENCV_STITCHING_UTIL_INL_HPP
+#define OPENCV_STITCHING_UTIL_INL_HPP
 
 #include <queue>
 #include "opencv2/core.hpp"
@@ -128,4 +128,4 @@ static inline double sqr(double x) { return x * x; }
 
 //! @endcond
 
-#endif // __OPENCV_STITCHING_UTIL_INL_HPP__
+#endif // OPENCV_STITCHING_UTIL_INL_HPP
diff --git a/modules/stitching/include/opencv2/stitching/detail/warpers.hpp b/modules/stitching/include/opencv2/stitching/detail/warpers.hpp
index ee8e824..1515d76 100644
--- a/modules/stitching/include/opencv2/stitching/detail/warpers.hpp
+++ b/modules/stitching/include/opencv2/stitching/detail/warpers.hpp
@@ -40,8 +40,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_STITCHING_WARPERS_HPP__
-#define __OPENCV_STITCHING_WARPERS_HPP__
+#ifndef OPENCV_STITCHING_WARPERS_HPP
+#define OPENCV_STITCHING_WARPERS_HPP
 
 #include "opencv2/core.hpp"
 #include "opencv2/core/cuda.hpp"
@@ -205,6 +205,34 @@ protected:
 };
 
 
+/** @brief Affine warper that uses rotations and translations
+
+ Uses affine transformation in homogeneous coordinates to represent both rotation and
+ translation in camera rotation matrix.
+ */
+class CV_EXPORTS AffineWarper : public PlaneWarper
+{
+public:
+    /** @brief Construct an instance of the affine warper class.
+
+    @param scale Projected image scale multiplier
+     */
+    AffineWarper(float scale = 1.f) : PlaneWarper(scale) {}
+
+    Point2f warpPoint(const Point2f &pt, InputArray K, InputArray R);
+    Rect buildMaps(Size src_size, InputArray K, InputArray R, OutputArray xmap, OutputArray ymap);
+    Point warp(InputArray src, InputArray K, InputArray R,
+               int interp_mode, int border_mode, OutputArray dst);
+    Rect warpRoi(Size src_size, InputArray K, InputArray R);
+
+protected:
+    /** @brief Extracts rotation and translation matrices from matrix H representing
+        affine transformation in homogeneous coordinates
+     */
+    void getRTfromHomogeneous(InputArray H, Mat &R, Mat &T);
+};
+
+
 struct CV_EXPORTS SphericalProjector : ProjectorBase
 {
     void mapForward(float x, float y, float &u, float &v);
@@ -214,7 +242,8 @@ struct CV_EXPORTS SphericalProjector : ProjectorBase
 
 /** @brief Warper that maps an image onto the unit sphere located at the origin.
 
- Projects image onto unit sphere with origin at (0, 0, 0).
+ Projects image onto unit sphere with origin at (0, 0, 0) and radius scale, measured in pixels.
+ A 360° panorama would therefore have a resulting width of 2 * scale * PI pixels.
  Poles are located at (0, -1, 0) and (0, 1, 0) points.
 */
 class CV_EXPORTS SphericalWarper : public RotationWarperBase<SphericalProjector>
@@ -222,7 +251,8 @@ class CV_EXPORTS SphericalWarper : public RotationWarperBase<SphericalProjector>
 public:
     /** @brief Construct an instance of the spherical warper class.
 
-    @param scale Projected image scale multiplier
+    @param scale Radius of the projected sphere, in pixels. An image spanning the
+                 whole sphere will have a width of 2 * scale * PI pixels.
      */
     SphericalWarper(float scale) { projector_.scale = scale; }
 
@@ -583,4 +613,4 @@ protected:
 
 #include "warpers_inl.hpp"
 
-#endif // __OPENCV_STITCHING_WARPERS_HPP__
+#endif // OPENCV_STITCHING_WARPERS_HPP
diff --git a/modules/stitching/include/opencv2/stitching/detail/warpers_inl.hpp b/modules/stitching/include/opencv2/stitching/detail/warpers_inl.hpp
index 0416ecb..f4a19d9 100644
--- a/modules/stitching/include/opencv2/stitching/detail/warpers_inl.hpp
+++ b/modules/stitching/include/opencv2/stitching/detail/warpers_inl.hpp
@@ -40,8 +40,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_STITCHING_WARPERS_INL_HPP__
-#define __OPENCV_STITCHING_WARPERS_INL_HPP__
+#ifndef OPENCV_STITCHING_WARPERS_INL_HPP
+#define OPENCV_STITCHING_WARPERS_INL_HPP
 
 #include "opencv2/core.hpp"
 #include "warpers.hpp" // Make your IDE see declarations
@@ -150,10 +150,10 @@ Rect RotationWarperBase<P>::warpRoi(Size src_size, InputArray K, InputArray R)
 template <class P>
 void RotationWarperBase<P>::detectResultRoi(Size src_size, Point &dst_tl, Point &dst_br)
 {
-    float tl_uf = std::numeric_limits<float>::max();
-    float tl_vf = std::numeric_limits<float>::max();
-    float br_uf = -std::numeric_limits<float>::max();
-    float br_vf = -std::numeric_limits<float>::max();
+    float tl_uf = (std::numeric_limits<float>::max)();
+    float tl_vf = (std::numeric_limits<float>::max)();
+    float br_uf = -(std::numeric_limits<float>::max)();
+    float br_vf = -(std::numeric_limits<float>::max)();
 
     float u, v;
     for (int y = 0; y < src_size.height; ++y)
@@ -161,8 +161,8 @@ void RotationWarperBase<P>::detectResultRoi(Size src_size, Point &dst_tl, Point
         for (int x = 0; x < src_size.width; ++x)
         {
             projector_.mapForward(static_cast<float>(x), static_cast<float>(y), u, v);
-            tl_uf = std::min(tl_uf, u); tl_vf = std::min(tl_vf, v);
-            br_uf = std::max(br_uf, u); br_vf = std::max(br_vf, v);
+            tl_uf = (std::min)(tl_uf, u); tl_vf = (std::min)(tl_vf, v);
+            br_uf = (std::max)(br_uf, u); br_vf = (std::max)(br_vf, v);
         }
     }
 
@@ -176,31 +176,31 @@ void RotationWarperBase<P>::detectResultRoi(Size src_size, Point &dst_tl, Point
 template <class P>
 void RotationWarperBase<P>::detectResultRoiByBorder(Size src_size, Point &dst_tl, Point &dst_br)
 {
-    float tl_uf = std::numeric_limits<float>::max();
-    float tl_vf = std::numeric_limits<float>::max();
-    float br_uf = -std::numeric_limits<float>::max();
-    float br_vf = -std::numeric_limits<float>::max();
+    float tl_uf = (std::numeric_limits<float>::max)();
+    float tl_vf = (std::numeric_limits<float>::max)();
+    float br_uf = -(std::numeric_limits<float>::max)();
+    float br_vf = -(std::numeric_limits<float>::max)();
 
     float u, v;
     for (float x = 0; x < src_size.width; ++x)
     {
         projector_.mapForward(static_cast<float>(x), 0, u, v);
-        tl_uf = std::min(tl_uf, u); tl_vf = std::min(tl_vf, v);
-        br_uf = std::max(br_uf, u); br_vf = std::max(br_vf, v);
+        tl_uf = (std::min)(tl_uf, u); tl_vf = (std::min)(tl_vf, v);
+        br_uf = (std::max)(br_uf, u); br_vf = (std::max)(br_vf, v);
 
         projector_.mapForward(static_cast<float>(x), static_cast<float>(src_size.height - 1), u, v);
-        tl_uf = std::min(tl_uf, u); tl_vf = std::min(tl_vf, v);
-        br_uf = std::max(br_uf, u); br_vf = std::max(br_vf, v);
+        tl_uf = (std::min)(tl_uf, u); tl_vf = (std::min)(tl_vf, v);
+        br_uf = (std::max)(br_uf, u); br_vf = (std::max)(br_vf, v);
     }
     for (int y = 0; y < src_size.height; ++y)
     {
         projector_.mapForward(0, static_cast<float>(y), u, v);
-        tl_uf = std::min(tl_uf, u); tl_vf = std::min(tl_vf, v);
-        br_uf = std::max(br_uf, u); br_vf = std::max(br_vf, v);
+        tl_uf = (std::min)(tl_uf, u); tl_vf = (std::min)(tl_vf, v);
+        br_uf = (std::max)(br_uf, u); br_vf = (std::max)(br_vf, v);
 
         projector_.mapForward(static_cast<float>(src_size.width - 1), static_cast<float>(y), u, v);
-        tl_uf = std::min(tl_uf, u); tl_vf = std::min(tl_vf, v);
-        br_uf = std::max(br_uf, u); br_vf = std::max(br_vf, v);
+        tl_uf = (std::min)(tl_uf, u); tl_vf = (std::min)(tl_vf, v);
+        br_uf = (std::max)(br_uf, u); br_vf = (std::max)(br_vf, v);
     }
 
     dst_tl.x = static_cast<int>(tl_uf);
@@ -771,4 +771,4 @@ void PlanePortraitProjector::mapBackward(float u0, float v0, float &x, float &y)
 
 //! @endcond
 
-#endif // __OPENCV_STITCHING_WARPERS_INL_HPP__
+#endif // OPENCV_STITCHING_WARPERS_INL_HPP
diff --git a/modules/stitching/include/opencv2/stitching/warpers.hpp b/modules/stitching/include/opencv2/stitching/warpers.hpp
index 7e570d3..139e052 100644
--- a/modules/stitching/include/opencv2/stitching/warpers.hpp
+++ b/modules/stitching/include/opencv2/stitching/warpers.hpp
@@ -40,8 +40,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_STITCHING_WARPER_CREATORS_HPP__
-#define __OPENCV_STITCHING_WARPER_CREATORS_HPP__
+#ifndef OPENCV_STITCHING_WARPER_CREATORS_HPP
+#define OPENCV_STITCHING_WARPER_CREATORS_HPP
 
 #include "opencv2/stitching/detail/warpers.hpp"
 
@@ -68,6 +68,15 @@ public:
     Ptr<detail::RotationWarper> create(float scale) const { return makePtr<detail::PlaneWarper>(scale); }
 };
 
+/** @brief Affine warper factory class.
+  @sa detail::AffineWarper
+ */
+class AffineWarper : public WarperCreator
+{
+public:
+    Ptr<detail::RotationWarper> create(float scale) const { return makePtr<detail::AffineWarper>(scale); }
+};
+
 /** @brief Cylindrical warper factory class.
 @sa detail::CylindricalWarper
 */
@@ -180,4 +189,4 @@ public:
 
 } // namespace cv
 
-#endif // __OPENCV_STITCHING_WARPER_CREATORS_HPP__
+#endif // OPENCV_STITCHING_WARPER_CREATORS_HPP
diff --git a/modules/stitching/misc/python/pyopencv_stitching.hpp b/modules/stitching/misc/python/pyopencv_stitching.hpp
new file mode 100644
index 0000000..e5d0cd2
--- /dev/null
+++ b/modules/stitching/misc/python/pyopencv_stitching.hpp
@@ -0,0 +1,9 @@
+#ifdef HAVE_OPENCV_STITCHING
+typedef Stitcher::Status Status;
+
+template<>
+PyObject* pyopencv_from(const Status& value)
+{
+    return PyInt_FromLong(value);
+}
+#endif
\ No newline at end of file
diff --git a/modules/stitching/perf/opencl/perf_stitch.cpp b/modules/stitching/perf/opencl/perf_stitch.cpp
index ce7c3a9..8b25c50 100644
--- a/modules/stitching/perf/opencl/perf_stitch.cpp
+++ b/modules/stitching/perf/opencl/perf_stitch.cpp
@@ -7,9 +7,13 @@
 #include "../perf_precomp.hpp"
 #include "opencv2/ts/ocl_perf.hpp"
 
+#ifdef HAVE_OPENCL
+
+namespace cvtest {
+namespace ocl {
+
 using namespace cv;
 using namespace perf;
-using namespace cvtest::ocl;
 using namespace std;
 using namespace std::tr1;
 
@@ -19,7 +23,7 @@ using namespace std::tr1;
 
 typedef TestBaseWithParam<string> stitch;
 
-#ifdef HAVE_OPENCV_NONFREE_TODO_FIND_WHY_SURF_IS_NOT_ABLE_TO_STITCH_PANOS
+#ifdef HAVE_OPENCV_XFEATURES2D
 #define TEST_DETECTORS testing::Values("surf", "orb")
 #else
 #define TEST_DETECTORS testing::Values<string>("orb")
@@ -142,3 +146,7 @@ OCL_PERF_TEST_P(stitch, boat, TEST_DETECTORS)
 
     SANITY_CHECK_NOTHING();
 }
+
+} } // namespace cvtest::ocl
+
+#endif // HAVE_OPENCL
diff --git a/modules/stitching/perf/opencl/perf_warpers.cpp b/modules/stitching/perf/opencl/perf_warpers.cpp
index 57ca9a6..1aa738c 100644
--- a/modules/stitching/perf/opencl/perf_warpers.cpp
+++ b/modules/stitching/perf/opencl/perf_warpers.cpp
@@ -54,7 +54,8 @@ enum
 {
     SphericalWarperType = 0,
     CylindricalWarperType = 1,
-    PlaneWarperType = 2
+    PlaneWarperType = 2,
+    AffineWarperType = 3,
 };
 
 class WarperBase
@@ -69,6 +70,8 @@ public:
             creator = makePtr<CylindricalWarper>();
         else if (type == PlaneWarperType)
             creator = makePtr<PlaneWarper>();
+        else if (type == AffineWarperType)
+            creator = makePtr<AffineWarper>();
         CV_Assert(!creator.empty());
 
         K = Mat::eye(3, 3, CV_32FC1);
@@ -98,7 +101,7 @@ private:
     Mat K, R;
 };
 
-CV_ENUM(WarperType, SphericalWarperType, CylindricalWarperType, PlaneWarperType)
+CV_ENUM(WarperType, SphericalWarperType, CylindricalWarperType, PlaneWarperType, AffineWarperType)
 
 typedef tuple<Size, WarperType> StitchingWarpersParams;
 typedef TestBaseWithParam<StitchingWarpersParams> StitchingWarpersFixture;
diff --git a/modules/stitching/perf/perf_estimators.cpp b/modules/stitching/perf/perf_estimators.cpp
new file mode 100644
index 0000000..7de470c
--- /dev/null
+++ b/modules/stitching/perf/perf_estimators.cpp
@@ -0,0 +1,100 @@
+#include "perf_precomp.hpp"
+#include "opencv2/imgcodecs.hpp"
+#include "opencv2/opencv_modules.hpp"
+
+using namespace std;
+using namespace cv;
+using namespace perf;
+using std::tr1::tuple;
+using std::tr1::get;
+
+typedef TestBaseWithParam<tuple<string, string> > bundleAdjuster;
+
+#ifdef HAVE_OPENCV_XFEATURES2D
+#define TEST_DETECTORS testing::Values("surf", "orb")
+#else
+#define TEST_DETECTORS testing::Values<string>("orb")
+#endif
+#define WORK_MEGAPIX 0.6
+#define AFFINE_FUNCTIONS testing::Values("affinePartial", "affine")
+
+PERF_TEST_P(bundleAdjuster, affine, testing::Combine(TEST_DETECTORS, AFFINE_FUNCTIONS))
+{
+    Mat img1, img1_full = imread(getDataPath("stitching/s1.jpg"));
+    Mat img2, img2_full = imread(getDataPath("stitching/s2.jpg"));
+    float scale1 = (float)std::min(1.0, sqrt(WORK_MEGAPIX * 1e6 / img1_full.total()));
+    float scale2 = (float)std::min(1.0, sqrt(WORK_MEGAPIX * 1e6 / img2_full.total()));
+    resize(img1_full, img1, Size(), scale1, scale1);
+    resize(img2_full, img2, Size(), scale2, scale2);
+
+    string detector = get<0>(GetParam());
+    string affine_fun = get<1>(GetParam());
+
+    Ptr<detail::FeaturesFinder> finder;
+    Ptr<detail::FeaturesMatcher> matcher;
+    Ptr<detail::BundleAdjusterBase> bundle_adjuster;
+    if (detector == "surf")
+        finder = makePtr<detail::SurfFeaturesFinder>();
+    else if (detector == "orb")
+        finder = makePtr<detail::OrbFeaturesFinder>();
+    if (affine_fun == "affinePartial")
+    {
+        matcher = makePtr<detail::AffineBestOf2NearestMatcher>(false);
+        bundle_adjuster = makePtr<detail::BundleAdjusterAffinePartial>();
+    }
+    else if (affine_fun == "affine")
+    {
+        matcher = makePtr<detail::AffineBestOf2NearestMatcher>(true);
+        bundle_adjuster = makePtr<detail::BundleAdjusterAffine>();
+    }
+    Ptr<detail::Estimator> estimator = makePtr<detail::AffineBasedEstimator>();
+
+    std::vector<Mat> images;
+    images.push_back(img1), images.push_back(img2);
+    std::vector<detail::ImageFeatures> features;
+    std::vector<detail::MatchesInfo> pairwise_matches;
+    std::vector<detail::CameraParams> cameras;
+    std::vector<detail::CameraParams> cameras2;
+
+    (*finder)(images, features);
+    (*matcher)(features, pairwise_matches);
+    if (!(*estimator)(features, pairwise_matches, cameras))
+        FAIL() << "estimation failed. this should never happen.";
+    // this is currently required
+    for (size_t i = 0; i < cameras.size(); ++i)
+    {
+        Mat R;
+        cameras[i].R.convertTo(R, CV_32F);
+        cameras[i].R = R;
+    }
+
+    cameras2 = cameras;
+    bool success = true;
+    while(next())
+    {
+        cameras = cameras2; // revert cameras back to original initial guess
+        startTimer();
+        success = (*bundle_adjuster)(features, pairwise_matches, cameras);
+        stopTimer();
+    }
+
+    EXPECT_TRUE(success);
+    EXPECT_TRUE(cameras.size() == 2);
+
+    // fist camera should be just identity
+    Mat &first = cameras[0].R;
+    SANITY_CHECK(first, 1e-3, ERROR_ABSOLUTE);
+    // second camera should be the estimated transform between images
+    // separate rotation and translation in transform matrix
+    Mat T_second (cameras[1].R, Range(0, 2), Range(2, 3));
+    Mat R_second (cameras[1].R, Range(0, 2), Range(0, 2));
+    Mat h (cameras[1].R, Range(2, 3), Range::all());
+    SANITY_CHECK(T_second, 5, ERROR_ABSOLUTE); // allow 5 pixels diff in translations
+    SANITY_CHECK(R_second, .01, ERROR_ABSOLUTE); // rotations must be more precise
+    // last row should be precisely (0, 0, 1) as it is just added for representation in homogeneous
+    // coordinates
+    EXPECT_TRUE(h.type() == CV_32F);
+    EXPECT_FLOAT_EQ(h.at<float>(0), 0.f);
+    EXPECT_FLOAT_EQ(h.at<float>(1), 0.f);
+    EXPECT_FLOAT_EQ(h.at<float>(2), 1.f);
+}
diff --git a/modules/stitching/perf/perf_matchers.cpp b/modules/stitching/perf/perf_matchers.cpp
new file mode 100644
index 0000000..4e5b03d
--- /dev/null
+++ b/modules/stitching/perf/perf_matchers.cpp
@@ -0,0 +1,301 @@
+#include "perf_precomp.hpp"
+#include "opencv2/imgcodecs.hpp"
+#include "opencv2/opencv_modules.hpp"
+#include "opencv2/flann.hpp"
+
+using namespace std;
+using namespace cv;
+using namespace perf;
+using std::tr1::make_tuple;
+using std::tr1::get;
+
+typedef TestBaseWithParam<size_t> FeaturesFinderVec;
+typedef TestBaseWithParam<string> match;
+typedef std::tr1::tuple<string, int> matchVector_t;
+typedef TestBaseWithParam<matchVector_t> matchVector;
+
+#define NUMBER_IMAGES testing::Values(1, 5, 20)
+#define SURF_MATCH_CONFIDENCE 0.65f
+#define ORB_MATCH_CONFIDENCE  0.3f
+#define WORK_MEGAPIX 0.6
+
+#ifdef HAVE_OPENCV_XFEATURES2D
+#define TEST_DETECTORS testing::Values("surf", "orb")
+#else
+#define TEST_DETECTORS testing::Values<string>("orb")
+#endif
+
+PERF_TEST_P(FeaturesFinderVec, ParallelFeaturesFinder, NUMBER_IMAGES)
+{
+    Mat img = imread( getDataPath("stitching/a1.png") );
+    vector<Mat> imgs(GetParam(), img);
+    vector<detail::ImageFeatures> features(imgs.size());
+
+    Ptr<detail::FeaturesFinder> featuresFinder = makePtr<detail::OrbFeaturesFinder>();
+
+    TEST_CYCLE()
+    {
+        (*featuresFinder)(imgs, features);
+    }
+
+    SANITY_CHECK_NOTHING();
+}
+
+PERF_TEST_P(FeaturesFinderVec, SerialFeaturesFinder, NUMBER_IMAGES)
+{
+    Mat img = imread( getDataPath("stitching/a1.png") );
+    vector<Mat> imgs(GetParam(), img);
+    vector<detail::ImageFeatures> features(imgs.size());
+
+    Ptr<detail::FeaturesFinder> featuresFinder = makePtr<detail::OrbFeaturesFinder>();
+
+    TEST_CYCLE()
+    {
+        for (size_t i = 0; i < imgs.size(); ++i)
+            (*featuresFinder)(imgs[i], features[i]);
+    }
+
+    SANITY_CHECK_NOTHING();
+}
+
+PERF_TEST_P( match, bestOf2Nearest, TEST_DETECTORS)
+{
+    Mat img1, img1_full = imread( getDataPath("stitching/boat1.jpg") );
+    Mat img2, img2_full = imread( getDataPath("stitching/boat2.jpg") );
+    float scale1 = (float)std::min(1.0, sqrt(WORK_MEGAPIX * 1e6 / img1_full.total()));
+    float scale2 = (float)std::min(1.0, sqrt(WORK_MEGAPIX * 1e6 / img2_full.total()));
+    resize(img1_full, img1, Size(), scale1, scale1);
+    resize(img2_full, img2, Size(), scale2, scale2);
+
+    Ptr<detail::FeaturesFinder> finder;
+    Ptr<detail::FeaturesMatcher> matcher;
+    if (GetParam() == "surf")
+    {
+        finder = makePtr<detail::SurfFeaturesFinder>();
+        matcher = makePtr<detail::BestOf2NearestMatcher>(false, SURF_MATCH_CONFIDENCE);
+    }
+    else if (GetParam() == "orb")
+    {
+        finder = makePtr<detail::OrbFeaturesFinder>();
+        matcher = makePtr<detail::BestOf2NearestMatcher>(false, ORB_MATCH_CONFIDENCE);
+    }
+    else
+    {
+        FAIL() << "Unknown 2D features type: " << GetParam();
+    }
+
+    detail::ImageFeatures features1, features2;
+    (*finder)(img1, features1);
+    (*finder)(img2, features2);
+
+    detail::MatchesInfo pairwise_matches;
+
+    declare.in(features1.descriptors, features2.descriptors);
+
+    while(next())
+    {
+        cvflann::seed_random(42);//for predictive FlannBasedMatcher
+        startTimer();
+        (*matcher)(features1, features2, pairwise_matches);
+        stopTimer();
+        matcher->collectGarbage();
+    }
+
+    Mat dist (pairwise_matches.H, Range::all(), Range(2, 3));
+    Mat R (pairwise_matches.H, Range::all(), Range(0, 2));
+    // separate transform matrix, use lower error on rotations
+    SANITY_CHECK(dist, 1., ERROR_ABSOLUTE);
+    SANITY_CHECK(R, .015, ERROR_ABSOLUTE);
+}
+
+PERF_TEST_P( matchVector, bestOf2NearestVectorFeatures, testing::Combine(
+                 TEST_DETECTORS,
+                 testing::Values(2, 4, 8))
+             )
+{
+    Mat img1, img1_full = imread( getDataPath("stitching/boat1.jpg") );
+    Mat img2, img2_full = imread( getDataPath("stitching/boat2.jpg") );
+    float scale1 = (float)std::min(1.0, sqrt(WORK_MEGAPIX * 1e6 / img1_full.total()));
+    float scale2 = (float)std::min(1.0, sqrt(WORK_MEGAPIX * 1e6 / img2_full.total()));
+    resize(img1_full, img1, Size(), scale1, scale1);
+    resize(img2_full, img2, Size(), scale2, scale2);
+
+    Ptr<detail::FeaturesFinder> finder;
+    Ptr<detail::FeaturesMatcher> matcher;
+    string detectorName = get<0>(GetParam());
+    int featuresVectorSize = get<1>(GetParam());
+    if (detectorName == "surf")
+    {
+        finder = makePtr<detail::SurfFeaturesFinder>();
+        matcher = makePtr<detail::BestOf2NearestMatcher>(false, SURF_MATCH_CONFIDENCE);
+    }
+    else if (detectorName == "orb")
+    {
+        finder = makePtr<detail::OrbFeaturesFinder>();
+        matcher = makePtr<detail::BestOf2NearestMatcher>(false, ORB_MATCH_CONFIDENCE);
+    }
+    else
+    {
+        FAIL() << "Unknown 2D features type: " << get<0>(GetParam());
+    }
+
+    detail::ImageFeatures features1, features2;
+    (*finder)(img1, features1);
+    (*finder)(img2, features2);
+    vector<detail::ImageFeatures> features;
+    vector<detail::MatchesInfo> pairwise_matches;
+    for(int i = 0; i < featuresVectorSize/2; i++)
+    {
+        features.push_back(features1);
+        features.push_back(features2);
+    }
+
+    declare.time(200);
+    while(next())
+    {
+        cvflann::seed_random(42);//for predictive FlannBasedMatcher
+        startTimer();
+        (*matcher)(features, pairwise_matches);
+        stopTimer();
+        matcher->collectGarbage();
+    }
+
+    size_t matches_count = 0;
+    for (size_t i = 0; i < pairwise_matches.size(); ++i)
+    {
+        if (pairwise_matches[i].src_img_idx < 0)
+            continue;
+
+        EXPECT_TRUE(pairwise_matches[i].matches.size() > 100);
+        EXPECT_FALSE(pairwise_matches[i].H.empty());
+        ++matches_count;
+    }
+
+    EXPECT_TRUE(matches_count > 0);
+
+    SANITY_CHECK_NOTHING();
+}
+
+PERF_TEST_P( match, affineBestOf2Nearest, TEST_DETECTORS)
+{
+    Mat img1, img1_full = imread( getDataPath("stitching/s1.jpg") );
+    Mat img2, img2_full = imread( getDataPath("stitching/s2.jpg") );
+    float scale1 = (float)std::min(1.0, sqrt(WORK_MEGAPIX * 1e6 / img1_full.total()));
+    float scale2 = (float)std::min(1.0, sqrt(WORK_MEGAPIX * 1e6 / img2_full.total()));
+    resize(img1_full, img1, Size(), scale1, scale1);
+    resize(img2_full, img2, Size(), scale2, scale2);
+
+    Ptr<detail::FeaturesFinder> finder;
+    Ptr<detail::FeaturesMatcher> matcher;
+    if (GetParam() == "surf")
+    {
+        finder = makePtr<detail::SurfFeaturesFinder>();
+        matcher = makePtr<detail::AffineBestOf2NearestMatcher>(false, false, SURF_MATCH_CONFIDENCE);
+    }
+    else if (GetParam() == "orb")
+    {
+        finder = makePtr<detail::OrbFeaturesFinder>();
+        matcher = makePtr<detail::AffineBestOf2NearestMatcher>(false, false, ORB_MATCH_CONFIDENCE);
+    }
+    else
+    {
+        FAIL() << "Unknown 2D features type: " << GetParam();
+    }
+
+    detail::ImageFeatures features1, features2;
+    (*finder)(img1, features1);
+    (*finder)(img2, features2);
+
+    detail::MatchesInfo pairwise_matches;
+
+    declare.in(features1.descriptors, features2.descriptors);
+
+    while(next())
+    {
+        cvflann::seed_random(42);//for predictive FlannBasedMatcher
+        startTimer();
+        (*matcher)(features1, features2, pairwise_matches);
+        stopTimer();
+        matcher->collectGarbage();
+    }
+
+    // separate rotation and translation in transform matrix
+    Mat T (pairwise_matches.H, Range(0, 2), Range(2, 3));
+    Mat R (pairwise_matches.H, Range(0, 2), Range(0, 2));
+    Mat h (pairwise_matches.H, Range(2, 3), Range::all());
+    SANITY_CHECK(T, 5, ERROR_ABSOLUTE); // allow 5 pixels diff in translations
+    SANITY_CHECK(R, .01, ERROR_ABSOLUTE); // rotations must be more precise
+    // last row should be precisely (0, 0, 1) as it is just added for representation in homogeneous
+    // coordinates
+    EXPECT_DOUBLE_EQ(h.at<double>(0), 0.);
+    EXPECT_DOUBLE_EQ(h.at<double>(1), 0.);
+    EXPECT_DOUBLE_EQ(h.at<double>(2), 1.);
+}
+
+PERF_TEST_P( matchVector, affineBestOf2NearestVectorFeatures, testing::Combine(
+                 TEST_DETECTORS,
+                 testing::Values(2, 4, 8))
+             )
+{
+    Mat img1, img1_full = imread( getDataPath("stitching/s1.jpg") );
+    Mat img2, img2_full = imread( getDataPath("stitching/s2.jpg") );
+    float scale1 = (float)std::min(1.0, sqrt(WORK_MEGAPIX * 1e6 / img1_full.total()));
+    float scale2 = (float)std::min(1.0, sqrt(WORK_MEGAPIX * 1e6 / img2_full.total()));
+    resize(img1_full, img1, Size(), scale1, scale1);
+    resize(img2_full, img2, Size(), scale2, scale2);
+
+    Ptr<detail::FeaturesFinder> finder;
+    Ptr<detail::FeaturesMatcher> matcher;
+    string detectorName = get<0>(GetParam());
+    int featuresVectorSize = get<1>(GetParam());
+    if (detectorName == "surf")
+    {
+        finder = makePtr<detail::SurfFeaturesFinder>();
+        matcher = makePtr<detail::AffineBestOf2NearestMatcher>(false, false, SURF_MATCH_CONFIDENCE);
+    }
+    else if (detectorName == "orb")
+    {
+        finder = makePtr<detail::OrbFeaturesFinder>();
+        matcher = makePtr<detail::AffineBestOf2NearestMatcher>(false, false, ORB_MATCH_CONFIDENCE);
+    }
+    else
+    {
+        FAIL() << "Unknown 2D features type: " << get<0>(GetParam());
+    }
+
+    detail::ImageFeatures features1, features2;
+    (*finder)(img1, features1);
+    (*finder)(img2, features2);
+    vector<detail::ImageFeatures> features;
+    vector<detail::MatchesInfo> pairwise_matches;
+    for(int i = 0; i < featuresVectorSize/2; i++)
+    {
+        features.push_back(features1);
+        features.push_back(features2);
+    }
+
+    declare.time(200);
+    while(next())
+    {
+        cvflann::seed_random(42);//for predictive FlannBasedMatcher
+        startTimer();
+        (*matcher)(features, pairwise_matches);
+        stopTimer();
+        matcher->collectGarbage();
+    }
+
+    size_t matches_count = 0;
+    for (size_t i = 0; i < pairwise_matches.size(); ++i)
+    {
+        if (pairwise_matches[i].src_img_idx < 0)
+            continue;
+
+        EXPECT_TRUE(pairwise_matches[i].matches.size() > 400);
+        EXPECT_FALSE(pairwise_matches[i].H.empty());
+        ++matches_count;
+    }
+
+    EXPECT_TRUE(matches_count > 0);
+
+    SANITY_CHECK_NOTHING();
+}
diff --git a/modules/stitching/perf/perf_stich.cpp b/modules/stitching/perf/perf_stich.cpp
index 74fd1cc..ded2571 100644
--- a/modules/stitching/perf/perf_stich.cpp
+++ b/modules/stitching/perf/perf_stich.cpp
@@ -1,12 +1,11 @@
 #include "perf_precomp.hpp"
 #include "opencv2/imgcodecs.hpp"
-#include "opencv2/flann.hpp"
 #include "opencv2/opencv_modules.hpp"
 
 using namespace std;
 using namespace cv;
 using namespace perf;
-using std::tr1::make_tuple;
+using std::tr1::tuple;
 using std::tr1::get;
 
 #define SURF_MATCH_CONFIDENCE 0.65f
@@ -14,15 +13,14 @@ using std::tr1::get;
 #define WORK_MEGAPIX 0.6
 
 typedef TestBaseWithParam<string> stitch;
-typedef TestBaseWithParam<string> match;
-typedef std::tr1::tuple<string, int> matchVector_t;
-typedef TestBaseWithParam<matchVector_t> matchVector;
+typedef TestBaseWithParam<tuple<string, string> > stitchDatasets;
 
-#ifdef HAVE_OPENCV_XFEATURES2D_TODO_FIND_WHY_SURF_IS_NOT_ABLE_TO_STITCH_PANOS
+#ifdef HAVE_OPENCV_XFEATURES2D
 #define TEST_DETECTORS testing::Values("surf", "orb")
 #else
 #define TEST_DETECTORS testing::Values<string>("orb")
 #endif
+#define AFFINE_DATASETS testing::Values("s", "budapest", "newspaper", "prague")
 
 PERF_TEST_P(stitch, a123, TEST_DETECTORS)
 {
@@ -93,118 +91,83 @@ PERF_TEST_P(stitch, b12, TEST_DETECTORS)
         stopTimer();
     }
 
-    Mat pano_small;
-    if (!pano.empty())
-        resize(pano, pano_small, Size(320, 240), 0, 0, INTER_AREA);
+    EXPECT_NEAR(pano.size().width, 1117, 50);
+    EXPECT_NEAR(pano.size().height, 642, 30);
 
-    SANITY_CHECK(pano_small, 5);
+    SANITY_CHECK_NOTHING();
 }
 
-PERF_TEST_P( match, bestOf2Nearest, TEST_DETECTORS)
+PERF_TEST_P(stitchDatasets, affine, testing::Combine(AFFINE_DATASETS, TEST_DETECTORS))
 {
-    Mat img1, img1_full = imread( getDataPath("stitching/b1.png") );
-    Mat img2, img2_full = imread( getDataPath("stitching/b2.png") );
-    float scale1 = (float)std::min(1.0, sqrt(WORK_MEGAPIX * 1e6 / img1_full.total()));
-    float scale2 = (float)std::min(1.0, sqrt(WORK_MEGAPIX * 1e6 / img2_full.total()));
-    resize(img1_full, img1, Size(), scale1, scale1);
-    resize(img2_full, img2, Size(), scale2, scale2);
-
-    Ptr<detail::FeaturesFinder> finder;
-    Ptr<detail::FeaturesMatcher> matcher;
-    if (GetParam() == "surf")
-    {
-        finder = makePtr<detail::SurfFeaturesFinder>();
-        matcher = makePtr<detail::BestOf2NearestMatcher>(false, SURF_MATCH_CONFIDENCE);
-    }
-    else if (GetParam() == "orb")
-    {
-        finder = makePtr<detail::OrbFeaturesFinder>();
-        matcher = makePtr<detail::BestOf2NearestMatcher>(false, ORB_MATCH_CONFIDENCE);
-    }
-    else
-    {
-        FAIL() << "Unknown 2D features type: " << GetParam();
-    }
-
-    detail::ImageFeatures features1, features2;
-    (*finder)(img1, features1);
-    (*finder)(img2, features2);
+    string dataset = get<0>(GetParam());
+    string detector = get<1>(GetParam());
 
-    detail::MatchesInfo pairwise_matches;
+    Mat pano;
+    vector<Mat> imgs;
+    int width, height, allowed_diff = 10;
+    Ptr<detail::FeaturesFinder> featuresFinder;
 
-    declare.in(features1.descriptors, features2.descriptors);
+    if(detector == "orb")
+        featuresFinder = makePtr<detail::OrbFeaturesFinder>();
+    else
+        featuresFinder = makePtr<detail::SurfFeaturesFinder>();
 
-    while(next())
+    if(dataset == "budapest")
     {
-        cvflann::seed_random(42);//for predictive FlannBasedMatcher
-        startTimer();
-        (*matcher)(features1, features2, pairwise_matches);
-        stopTimer();
-        matcher->collectGarbage();
+        imgs.push_back(imread(getDataPath("stitching/budapest1.jpg")));
+        imgs.push_back(imread(getDataPath("stitching/budapest2.jpg")));
+        imgs.push_back(imread(getDataPath("stitching/budapest3.jpg")));
+        imgs.push_back(imread(getDataPath("stitching/budapest4.jpg")));
+        imgs.push_back(imread(getDataPath("stitching/budapest5.jpg")));
+        imgs.push_back(imread(getDataPath("stitching/budapest6.jpg")));
+        width = 2313;
+        height = 1158;
+        // this dataset is big, the results between surf and orb differ slightly,
+        // but both are still good
+        allowed_diff = 27;
     }
-
-    std::vector<DMatch>& matches = pairwise_matches.matches;
-    if (GetParam() == "orb") matches.resize(0);
-    for(size_t q = 0; q < matches.size(); ++q)
-        if (matches[q].imgIdx < 0) { matches.resize(q); break;}
-    SANITY_CHECK_MATCHES(matches);
-}
-
-PERF_TEST_P( matchVector, bestOf2NearestVectorFeatures, testing::Combine(
-                 TEST_DETECTORS,
-                 testing::Values(2, 4, 8))
-             )
-{
-    Mat img1, img1_full = imread( getDataPath("stitching/b1.png") );
-    Mat img2, img2_full = imread( getDataPath("stitching/b2.png") );
-    float scale1 = (float)std::min(1.0, sqrt(WORK_MEGAPIX * 1e6 / img1_full.total()));
-    float scale2 = (float)std::min(1.0, sqrt(WORK_MEGAPIX * 1e6 / img2_full.total()));
-    resize(img1_full, img1, Size(), scale1, scale1);
-    resize(img2_full, img2, Size(), scale2, scale2);
-
-    Ptr<detail::FeaturesFinder> finder;
-    Ptr<detail::FeaturesMatcher> matcher;
-    string detectorName = get<0>(GetParam());
-    int featuresVectorSize = get<1>(GetParam());
-    if (detectorName == "surf")
+    else if (dataset == "newspaper")
     {
-        finder = makePtr<detail::SurfFeaturesFinder>();
-        matcher = makePtr<detail::BestOf2NearestMatcher>(false, SURF_MATCH_CONFIDENCE);
+        imgs.push_back(imread(getDataPath("stitching/newspaper1.jpg")));
+        imgs.push_back(imread(getDataPath("stitching/newspaper2.jpg")));
+        imgs.push_back(imread(getDataPath("stitching/newspaper3.jpg")));
+        imgs.push_back(imread(getDataPath("stitching/newspaper4.jpg")));
+        width = 1791;
+        height = 1136;
+        // we need to boost ORB number of features to be able to stitch this dataset
+        // SURF works just fine with default settings
+        if(detector == "orb")
+            featuresFinder = makePtr<detail::OrbFeaturesFinder>(Size(3,1), 3000);
     }
-    else if (detectorName == "orb")
+    else if (dataset == "prague")
     {
-        finder = makePtr<detail::OrbFeaturesFinder>();
-        matcher = makePtr<detail::BestOf2NearestMatcher>(false, ORB_MATCH_CONFIDENCE);
+        imgs.push_back(imread(getDataPath("stitching/prague1.jpg")));
+        imgs.push_back(imread(getDataPath("stitching/prague2.jpg")));
+        width = 983;
+        height = 1759;
     }
-    else
+    else // dataset == "s"
     {
-        FAIL() << "Unknown 2D features type: " << get<0>(GetParam());
+        imgs.push_back(imread(getDataPath("stitching/s1.jpg")));
+        imgs.push_back(imread(getDataPath("stitching/s2.jpg")));
+        width = 1815;
+        height = 700;
     }
 
-    detail::ImageFeatures features1, features2;
-    (*finder)(img1, features1);
-    (*finder)(img2, features2);
-    vector<detail::ImageFeatures> features;
-    vector<detail::MatchesInfo> pairwise_matches;
-    for(int i = 0; i < featuresVectorSize/2; i++)
-    {
-        features.push_back(features1);
-        features.push_back(features2);
-    }
+    declare.time(30 * 20).iterations(20);
 
-    declare.time(200);
     while(next())
     {
-        cvflann::seed_random(42);//for predictive FlannBasedMatcher
+        Ptr<Stitcher> stitcher = Stitcher::create(Stitcher::SCANS, false);
+        stitcher->setFeaturesFinder(featuresFinder);
+
         startTimer();
-        (*matcher)(features, pairwise_matches);
+        stitcher->stitch(imgs, pano);
         stopTimer();
-        matcher->collectGarbage();
     }
 
+    EXPECT_NEAR(pano.size().width, width, allowed_diff);
+    EXPECT_NEAR(pano.size().height, height, allowed_diff);
 
-    std::vector<DMatch>& matches = pairwise_matches[detectorName == "surf" ? 1 : 0].matches;
-    for(size_t q = 0; q < matches.size(); ++q)
-        if (matches[q].imgIdx < 0) { matches.resize(q); break;}
-    SANITY_CHECK_MATCHES(matches);
+    SANITY_CHECK_NOTHING();
 }
diff --git a/modules/stitching/src/autocalib.cpp b/modules/stitching/src/autocalib.cpp
index 2414524..18b6e04 100644
--- a/modules/stitching/src/autocalib.cpp
+++ b/modules/stitching/src/autocalib.cpp
@@ -51,9 +51,6 @@ static inline bool decomposeCholesky(double* A, size_t astep, int m)
 {
     if (!hal::Cholesky64f(A, astep, m, 0, 0, 0))
         return false;
-    astep /= sizeof(A[0]);
-    for (int i = 0; i < m; ++i)
-        A[i*astep + i] = (double)(1./A[i*astep + i]);
     return true;
 }
 
diff --git a/modules/stitching/src/exposure_compensate.cpp b/modules/stitching/src/exposure_compensate.cpp
index 1f04fff..6f2562b 100644
--- a/modules/stitching/src/exposure_compensate.cpp
+++ b/modules/stitching/src/exposure_compensate.cpp
@@ -147,6 +147,8 @@ void GainCompensator::feed(const std::vector<Point> &corners, const std::vector<
 
 void GainCompensator::apply(int index, Point /*corner*/, InputOutputArray image, InputArray /*mask*/)
 {
+    CV_INSTRUMENT_REGION()
+
     multiply(image, gains_(index, 0), image);
 }
 
@@ -225,6 +227,8 @@ void BlocksGainCompensator::feed(const std::vector<Point> &corners, const std::v
 
 void BlocksGainCompensator::apply(int index, Point /*corner*/, InputOutputArray _image, InputArray /*mask*/)
 {
+    CV_INSTRUMENT_REGION()
+
     CV_Assert(_image.type() == CV_8UC3);
 
     UMat u_gain_map;
diff --git a/modules/stitching/src/matchers.cpp b/modules/stitching/src/matchers.cpp
index 40988b9..edd6b61 100644
--- a/modules/stitching/src/matchers.cpp
+++ b/modules/stitching/src/matchers.cpp
@@ -107,6 +107,35 @@ private:
 };
 
 
+struct FindFeaturesBody : ParallelLoopBody
+{
+    FindFeaturesBody(FeaturesFinder &finder, InputArrayOfArrays images,
+                     std::vector<ImageFeatures> &features, const std::vector<std::vector<cv::Rect> > *rois)
+            : finder_(finder), images_(images), features_(features), rois_(rois) {}
+
+    void operator ()(const Range &r) const
+    {
+        for (int i = r.start; i < r.end; ++i)
+        {
+            Mat image = images_.getMat(i);
+            if (rois_)
+                finder_(image, features_[i], (*rois_)[i]);
+            else
+                finder_(image, features_[i]);
+        }
+    }
+
+private:
+    FeaturesFinder &finder_;
+    InputArrayOfArrays images_;
+    std::vector<ImageFeatures> &features_;
+    const std::vector<std::vector<cv::Rect> > *rois_;
+
+    // to cease visual studio warning
+    void operator =(const FindFeaturesBody&);
+};
+
+
 //////////////////////////////////////////////////////////////////////////////
 
 typedef std::set<std::pair<int,int> > MatchesSet;
@@ -144,6 +173,8 @@ private:
 
 void CpuMatcher::match(const ImageFeatures &features1, const ImageFeatures &features2, MatchesInfo& matches_info)
 {
+    CV_INSTRUMENT_REGION()
+
     CV_Assert(features1.descriptors.type() == features2.descriptors.type());
     CV_Assert(features2.descriptors.depth() == CV_8U || features2.descriptors.depth() == CV_32F);
 
@@ -212,6 +243,8 @@ void CpuMatcher::match(const ImageFeatures &features1, const ImageFeatures &feat
 #ifdef HAVE_OPENCV_CUDAFEATURES2D
 void GpuMatcher::match(const ImageFeatures &features1, const ImageFeatures &features2, MatchesInfo& matches_info)
 {
+    CV_INSTRUMENT_REGION()
+
     matches_info.matches.clear();
 
     ensureSizeIsEnough(features1.descriptors.size(), features1.descriptors.type(), descriptors1_);
@@ -320,6 +353,55 @@ void FeaturesFinder::operator ()(InputArray image, ImageFeatures &features, cons
 }
 
 
+void FeaturesFinder::operator ()(InputArrayOfArrays images, std::vector<ImageFeatures> &features)
+{
+    size_t count = images.total();
+    features.resize(count);
+
+    FindFeaturesBody body(*this, images, features, NULL);
+    if (isThreadSafe())
+        parallel_for_(Range(0, static_cast<int>(count)), body);
+    else
+        body(Range(0, static_cast<int>(count)));
+}
+
+
+void FeaturesFinder::operator ()(InputArrayOfArrays images, std::vector<ImageFeatures> &features,
+                                  const std::vector<std::vector<cv::Rect> > &rois)
+{
+    CV_Assert(rois.size() == images.total());
+    size_t count = images.total();
+    features.resize(count);
+
+    FindFeaturesBody body(*this, images, features, &rois);
+    if (isThreadSafe())
+        parallel_for_(Range(0, static_cast<int>(count)), body);
+    else
+        body(Range(0, static_cast<int>(count)));
+}
+
+
+bool FeaturesFinder::isThreadSafe() const
+{
+    if (ocl::useOpenCL())
+    {
+        return false;
+    }
+    if (dynamic_cast<const SurfFeaturesFinder*>(this))
+    {
+        return true;
+    }
+    else if (dynamic_cast<const OrbFeaturesFinder*>(this))
+    {
+        return true;
+    }
+    else
+    {
+        return false;
+    }
+}
+
+
 SurfFeaturesFinder::SurfFeaturesFinder(double hess_thresh, int num_octaves, int num_layers,
                                        int num_octaves_descr, int num_layers_descr)
 {
@@ -458,6 +540,27 @@ void OrbFeaturesFinder::find(InputArray image, ImageFeatures &features)
     }
 }
 
+AKAZEFeaturesFinder::AKAZEFeaturesFinder(int descriptor_type,
+                                         int descriptor_size,
+                                         int descriptor_channels,
+                                         float threshold,
+                                         int nOctaves,
+                                         int nOctaveLayers,
+                                         int diffusivity)
+{
+    akaze = AKAZE::create(descriptor_type, descriptor_size, descriptor_channels,
+                          threshold, nOctaves, nOctaveLayers, diffusivity);
+}
+
+void AKAZEFeaturesFinder::find(InputArray image, detail::ImageFeatures &features)
+{
+    CV_Assert((image.type() == CV_8UC3) || (image.type() == CV_8UC1));
+    Mat descriptors;
+    UMat uimage = image.getUMat();
+    akaze->detectAndCompute(uimage, UMat(), features.keypoints, descriptors);
+    features.descriptors = descriptors.getUMat(ACCESS_READ);
+}
+
 #ifdef HAVE_OPENCV_XFEATURES2D
 SurfFeaturesFinderGpu::SurfFeaturesFinderGpu(double hess_thresh, int num_octaves, int num_layers,
                                              int num_octaves_descr, int num_layers_descr)
@@ -581,6 +684,8 @@ BestOf2NearestMatcher::BestOf2NearestMatcher(bool try_use_gpu, float match_conf,
 void BestOf2NearestMatcher::match(const ImageFeatures &features1, const ImageFeatures &features2,
                                   MatchesInfo &matches_info)
 {
+    CV_INSTRUMENT_REGION()
+
     (*impl_)(features1, features2, matches_info);
 
     // Check if it makes sense to find homography
@@ -695,5 +800,57 @@ void BestOf2NearestRangeMatcher::operator ()(const std::vector<ImageFeatures> &f
 }
 
 
+void AffineBestOf2NearestMatcher::match(const ImageFeatures &features1, const ImageFeatures &features2,
+                                        MatchesInfo &matches_info)
+{
+    (*impl_)(features1, features2, matches_info);
+
+    // Check if it makes sense to find transform
+    if (matches_info.matches.size() < static_cast<size_t>(num_matches_thresh1_))
+        return;
+
+    // Construct point-point correspondences for transform estimation
+    Mat src_points(1, static_cast<int>(matches_info.matches.size()), CV_32FC2);
+    Mat dst_points(1, static_cast<int>(matches_info.matches.size()), CV_32FC2);
+    for (size_t i = 0; i < matches_info.matches.size(); ++i)
+    {
+        const cv::DMatch &m = matches_info.matches[i];
+        src_points.at<Point2f>(0, static_cast<int>(i)) = features1.keypoints[m.queryIdx].pt;
+        dst_points.at<Point2f>(0, static_cast<int>(i)) = features2.keypoints[m.trainIdx].pt;
+    }
+
+    // Find pair-wise motion
+    if (full_affine_)
+        matches_info.H = estimateAffine2D(src_points, dst_points, matches_info.inliers_mask);
+    else
+        matches_info.H = estimateAffinePartial2D(src_points, dst_points, matches_info.inliers_mask);
+
+    if (matches_info.H.empty()) {
+        // could not find transformation
+        matches_info.confidence = 0;
+        matches_info.num_inliers = 0;
+        return;
+    }
+
+    // Find number of inliers
+    matches_info.num_inliers = 0;
+    for (size_t i = 0; i < matches_info.inliers_mask.size(); ++i)
+        if (matches_info.inliers_mask[i])
+            matches_info.num_inliers++;
+
+    // These coeffs are from paper M. Brown and D. Lowe. "Automatic Panoramic
+    // Image Stitching using Invariant Features"
+    matches_info.confidence =
+        matches_info.num_inliers / (8 + 0.3 * matches_info.matches.size());
+
+    /* should we remove matches between too close images? */
+    // matches_info.confidence = matches_info.confidence > 3. ? 0. : matches_info.confidence;
+
+    // extend H to represent linear tranformation in homogeneous coordinates
+    matches_info.H.push_back(Mat::zeros(1, 3, CV_64F));
+    matches_info.H.at<double>(2, 2) = 1;
+}
+
+
 } // namespace detail
 } // namespace cv
diff --git a/modules/stitching/src/motion_estimators.cpp b/modules/stitching/src/motion_estimators.cpp
index dd87725..f76309f 100644
--- a/modules/stitching/src/motion_estimators.cpp
+++ b/modules/stitching/src/motion_estimators.cpp
@@ -88,6 +88,28 @@ struct CalcRotation
 };
 
 
+/**
+ * @brief Functor calculating final tranformation by chaining linear transformations
+ */
+struct CalcAffineTransform
+{
+    CalcAffineTransform(int _num_images,
+                      const std::vector<MatchesInfo> &_pairwise_matches,
+                      std::vector<CameraParams> &_cameras)
+    : num_images(_num_images), pairwise_matches(&_pairwise_matches[0]), cameras(&_cameras[0]) {}
+
+    void operator()(const GraphEdge &edge)
+    {
+        int pair_idx = edge.from * num_images + edge.to;
+        cameras[edge.to].R = cameras[edge.from].R * pairwise_matches[pair_idx].H;
+    }
+
+    int num_images;
+    const MatchesInfo *pairwise_matches;
+    CameraParams *cameras;
+};
+
+
 //////////////////////////////////////////////////////////////////////////////
 
 void calcDeriv(const Mat &err1, const Mat &err2, double h, Mat res)
@@ -173,6 +195,31 @@ bool HomographyBasedEstimator::estimate(
 
 //////////////////////////////////////////////////////////////////////////////
 
+bool AffineBasedEstimator::estimate(const std::vector<ImageFeatures> &features,
+                                    const std::vector<MatchesInfo> &pairwise_matches,
+                                    std::vector<CameraParams> &cameras)
+{
+    cameras.resize(features.size());
+    const int num_images = static_cast<int>(features.size());
+
+    // find maximum spaning tree on pairwise matches
+    cv::detail::Graph span_tree;
+    std::vector<int> span_tree_centers;
+    // uses number of inliers as weights
+    findMaxSpanningTree(num_images, pairwise_matches, span_tree,
+                      span_tree_centers);
+
+    // compute final transform by chaining H together
+    span_tree.walkBreadthFirst(
+            span_tree_centers[0],
+            CalcAffineTransform(num_images, pairwise_matches, cameras));
+    // this estimator never fails
+    return true;
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
+
 bool BundleAdjusterBase::estimate(const std::vector<ImageFeatures> &features,
                                   const std::vector<MatchesInfo> &pairwise_matches,
                                   std::vector<CameraParams> &cameras)
@@ -598,6 +645,243 @@ void BundleAdjusterRay::calcJacobian(Mat &jac)
     }
 }
 
+//////////////////////////////////////////////////////////////////////////////
+
+void BundleAdjusterAffine::setUpInitialCameraParams(const std::vector<CameraParams> &cameras)
+{
+    cam_params_.create(num_images_ * 6, 1, CV_64F);
+    for (size_t i = 0; i < static_cast<size_t>(num_images_); ++i)
+    {
+        CV_Assert(cameras[i].R.type() == CV_32F);
+        // cameras[i].R is
+        //     a b tx
+        //     c d ty
+        //     0 0 1. (optional)
+        // cam_params_ model for LevMarq is
+        //     (a, b, tx, c, d, ty)
+        Mat params (2, 3, CV_64F, cam_params_.ptr<double>() + i * 6);
+        cameras[i].R.rowRange(0, 2).convertTo(params, CV_64F);
+    }
+}
+
+
+void BundleAdjusterAffine::obtainRefinedCameraParams(std::vector<CameraParams> &cameras) const
+{
+    for (int i = 0; i < num_images_; ++i)
+    {
+        // cameras[i].R will be
+        //     a b tx
+        //     c d ty
+        //     0 0 1
+        cameras[i].R = Mat::eye(3, 3, CV_32F);
+        Mat params = cam_params_.rowRange(i * 6, i * 6 + 6).reshape(1, 2);
+        params.convertTo(cameras[i].R.rowRange(0, 2), CV_32F);
+    }
+}
+
+
+void BundleAdjusterAffine::calcError(Mat &err)
+{
+    err.create(total_num_matches_ * 2, 1, CV_64F);
+
+    int match_idx = 0;
+    for (size_t edge_idx = 0; edge_idx < edges_.size(); ++edge_idx)
+    {
+        size_t i = edges_[edge_idx].first;
+        size_t j = edges_[edge_idx].second;
+
+        const ImageFeatures& features1 = features_[i];
+        const ImageFeatures& features2 = features_[j];
+        const MatchesInfo& matches_info = pairwise_matches_[i * num_images_ + j];
+
+        Mat H1 (2, 3, CV_64F, cam_params_.ptr<double>() + i * 6);
+        Mat H2 (2, 3, CV_64F, cam_params_.ptr<double>() + j * 6);
+
+        // invert H1
+        Mat H1_inv;
+        invertAffineTransform(H1, H1_inv);
+
+        // convert to representation in homogeneous coordinates
+        Mat last_row = Mat::zeros(1, 3, CV_64F);
+        last_row.at<double>(2) = 1.;
+        H1_inv.push_back(last_row);
+        H2.push_back(last_row);
+
+        Mat_<double> H = H1_inv * H2;
+
+        for (size_t k = 0; k < matches_info.matches.size(); ++k)
+        {
+            if (!matches_info.inliers_mask[k])
+                continue;
+
+            const DMatch& m = matches_info.matches[k];
+            const Point2f& p1 = features1.keypoints[m.queryIdx].pt;
+            const Point2f& p2 = features2.keypoints[m.trainIdx].pt;
+
+            double x = H(0,0)*p1.x + H(0,1)*p1.y + H(0,2);
+            double y = H(1,0)*p1.x + H(1,1)*p1.y + H(1,2);
+
+            err.at<double>(2 * match_idx + 0, 0) = p2.x - x;
+            err.at<double>(2 * match_idx + 1, 0) = p2.y - y;
+
+            ++match_idx;
+        }
+    }
+}
+
+
+void BundleAdjusterAffine::calcJacobian(Mat &jac)
+{
+    jac.create(total_num_matches_ * 2, num_images_ * 6, CV_64F);
+
+    double val;
+    const double step = 1e-4;
+
+    for (int i = 0; i < num_images_; ++i)
+    {
+        for (int j = 0; j < 6; ++j)
+        {
+            val = cam_params_.at<double>(i * 6 + j, 0);
+            cam_params_.at<double>(i * 6 + j, 0) = val - step;
+            calcError(err1_);
+            cam_params_.at<double>(i * 6 + j, 0) = val + step;
+            calcError(err2_);
+            calcDeriv(err1_, err2_, 2 * step, jac.col(i * 6 + j));
+            cam_params_.at<double>(i * 6 + j, 0) = val;
+        }
+    }
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
+
+void BundleAdjusterAffinePartial::setUpInitialCameraParams(const std::vector<CameraParams> &cameras)
+{
+    cam_params_.create(num_images_ * 4, 1, CV_64F);
+    for (size_t i = 0; i < static_cast<size_t>(num_images_); ++i)
+    {
+        CV_Assert(cameras[i].R.type() == CV_32F);
+        // cameras[i].R is
+        //     a -b tx
+        //     b  a ty
+        //     0  0 1. (optional)
+        // cam_params_ model for LevMarq is
+        //     (a, b, tx, ty)
+        double *params = cam_params_.ptr<double>() + i * 4;
+        params[0] = cameras[i].R.at<float>(0, 0);
+        params[1] = cameras[i].R.at<float>(1, 0);
+        params[2] = cameras[i].R.at<float>(0, 2);
+        params[3] = cameras[i].R.at<float>(1, 2);
+    }
+}
+
+
+void BundleAdjusterAffinePartial::obtainRefinedCameraParams(std::vector<CameraParams> &cameras) const
+{
+    for (size_t i = 0; i < static_cast<size_t>(num_images_); ++i)
+    {
+        // cameras[i].R will be
+        //     a -b tx
+        //     b  a ty
+        //     0  0 1
+        // cam_params_ model for LevMarq is
+        //     (a, b, tx, ty)
+        const double *params = cam_params_.ptr<double>() + i * 4;
+        double transform_buf[9] =
+        {
+            params[0], -params[1], params[2],
+            params[1],  params[0], params[3],
+            0., 0., 1.
+        };
+        Mat transform(3, 3, CV_64F, transform_buf);
+        transform.convertTo(cameras[i].R, CV_32F);
+    }
+}
+
+
+void BundleAdjusterAffinePartial::calcError(Mat &err)
+{
+    err.create(total_num_matches_ * 2, 1, CV_64F);
+
+    int match_idx = 0;
+    for (size_t edge_idx = 0; edge_idx < edges_.size(); ++edge_idx)
+    {
+        size_t i = edges_[edge_idx].first;
+        size_t j = edges_[edge_idx].second;
+
+        const ImageFeatures& features1 = features_[i];
+        const ImageFeatures& features2 = features_[j];
+        const MatchesInfo& matches_info = pairwise_matches_[i * num_images_ + j];
+
+        const double *H1_ptr = cam_params_.ptr<double>() + i * 4;
+        double H1_buf[9] =
+        {
+            H1_ptr[0], -H1_ptr[1], H1_ptr[2],
+            H1_ptr[1],  H1_ptr[0], H1_ptr[3],
+            0., 0., 1.
+        };
+        Mat H1 (3, 3, CV_64F, H1_buf);
+        const double *H2_ptr = cam_params_.ptr<double>() + j * 4;
+        double H2_buf[9] =
+        {
+            H2_ptr[0], -H2_ptr[1], H2_ptr[2],
+            H2_ptr[1],  H2_ptr[0], H2_ptr[3],
+            0., 0., 1.
+        };
+        Mat H2 (3, 3, CV_64F, H2_buf);
+
+        // invert H1
+        Mat H1_aff (H1, Range(0, 2));
+        double H1_inv_buf[6];
+        Mat H1_inv (2, 3, CV_64F, H1_inv_buf);
+        invertAffineTransform(H1_aff, H1_inv);
+        H1_inv.copyTo(H1_aff);
+
+        Mat_<double> H = H1 * H2;
+
+        for (size_t k = 0; k < matches_info.matches.size(); ++k)
+        {
+            if (!matches_info.inliers_mask[k])
+                continue;
+
+            const DMatch& m = matches_info.matches[k];
+            const Point2f& p1 = features1.keypoints[m.queryIdx].pt;
+            const Point2f& p2 = features2.keypoints[m.trainIdx].pt;
+
+            double x = H(0,0)*p1.x + H(0,1)*p1.y + H(0,2);
+            double y = H(1,0)*p1.x + H(1,1)*p1.y + H(1,2);
+
+            err.at<double>(2 * match_idx + 0, 0) = p2.x - x;
+            err.at<double>(2 * match_idx + 1, 0) = p2.y - y;
+
+            ++match_idx;
+        }
+    }
+}
+
+
+void BundleAdjusterAffinePartial::calcJacobian(Mat &jac)
+{
+    jac.create(total_num_matches_ * 2, num_images_ * 4, CV_64F);
+
+    double val;
+    const double step = 1e-4;
+
+    for (int i = 0; i < num_images_; ++i)
+    {
+        for (int j = 0; j < 4; ++j)
+        {
+            val = cam_params_.at<double>(i * 4 + j, 0);
+            cam_params_.at<double>(i * 4 + j, 0) = val - step;
+            calcError(err1_);
+            cam_params_.at<double>(i * 4 + j, 0) = val + step;
+            calcError(err2_);
+            calcDeriv(err1_, err2_, 2 * step, jac.col(i * 4 + j));
+            cam_params_.at<double>(i * 4 + j, 0) = val;
+        }
+    }
+}
+
 
 //////////////////////////////////////////////////////////////////////////////
 
diff --git a/modules/stitching/src/precomp.hpp b/modules/stitching/src/precomp.hpp
index 70636b6..eff78cf 100644
--- a/modules/stitching/src/precomp.hpp
+++ b/modules/stitching/src/precomp.hpp
@@ -99,4 +99,6 @@
 # include "opencv2/stitching/stitching_tegra.hpp"
 #endif
 
+#include "util_log.hpp"
+
 #endif
diff --git a/modules/stitching/src/seam_finders.cpp b/modules/stitching/src/seam_finders.cpp
index dbed801..90bf599 100644
--- a/modules/stitching/src/seam_finders.cpp
+++ b/modules/stitching/src/seam_finders.cpp
@@ -203,6 +203,8 @@ void DpSeamFinder::process(
         const Mat &image1, const Mat &image2, Point tl1, Point tl2,
         Mat &mask1, Mat &mask2)
 {
+    CV_INSTRUMENT_REGION()
+
     CV_Assert(image1.size() == mask1.size());
     CV_Assert(image2.size() == mask2.size());
 
@@ -638,7 +640,7 @@ bool DpSeamFinder::getSeamTips(int comp1, int comp2, Point &p1, Point &p2)
         {
             double size1 = static_cast<double>(points[i].size()), size2 = static_cast<double>(points[j].size());
             double cx1 = cvRound(sum[i].x / size1), cy1 = cvRound(sum[i].y / size1);
-            double cx2 = cvRound(sum[j].x / size2), cy2 = cvRound(sum[j].y / size1);
+            double cx2 = cvRound(sum[j].x / size2), cy2 = cvRound(sum[j].y / size2);
 
             double dist = (cx1 - cx2) * (cx1 - cx2) + (cy1 - cy2) * (cy1 - cy2);
             if (dist > maxDist)
diff --git a/modules/stitching/src/stitcher.cpp b/modules/stitching/src/stitcher.cpp
index 41fe81f..f7b9172 100644
--- a/modules/stitching/src/stitcher.cpp
+++ b/modules/stitching/src/stitcher.cpp
@@ -56,7 +56,7 @@ Stitcher Stitcher::createDefault(bool try_use_gpu)
     stitcher.setFeaturesMatcher(makePtr<detail::BestOf2NearestMatcher>(try_use_gpu));
     stitcher.setBundleAdjuster(makePtr<detail::BundleAdjusterRay>());
 
-#ifdef HAVE_CUDA
+#ifdef HAVE_OPENCV_CUDALEGACY
     if (try_use_gpu && cuda::getCudaEnabledDeviceCount() > 0)
     {
 #ifdef HAVE_OPENCV_XFEATURES2D
@@ -91,14 +91,46 @@ Stitcher Stitcher::createDefault(bool try_use_gpu)
 }
 
 
+Ptr<Stitcher> Stitcher::create(Mode mode, bool try_use_gpu)
+{
+    Stitcher stit = createDefault(try_use_gpu);
+    Ptr<Stitcher> stitcher = makePtr<Stitcher>(stit);
+
+    switch (mode)
+    {
+    case PANORAMA: // PANORAMA is the default
+        // already setup
+    break;
+
+    case SCANS:
+        stitcher->setWaveCorrection(false);
+        stitcher->setFeaturesMatcher(makePtr<detail::AffineBestOf2NearestMatcher>(false, try_use_gpu));
+        stitcher->setBundleAdjuster(makePtr<detail::BundleAdjusterAffinePartial>());
+        stitcher->setWarper(makePtr<AffineWarper>());
+        stitcher->setExposureCompensator(makePtr<detail::NoExposureCompensator>());
+    break;
+
+    default:
+        CV_Error(Error::StsBadArg, "Invalid stitching mode. Must be one of Stitcher::Mode");
+    break;
+    }
+
+    return stitcher;
+}
+
+
 Stitcher::Status Stitcher::estimateTransform(InputArrayOfArrays images)
 {
+    CV_INSTRUMENT_REGION()
+
     return estimateTransform(images, std::vector<std::vector<Rect> >());
 }
 
 
 Stitcher::Status Stitcher::estimateTransform(InputArrayOfArrays images, const std::vector<std::vector<Rect> > &rois)
 {
+    CV_INSTRUMENT_REGION()
+
     images.getUMatVector(imgs_);
     rois_ = rois;
 
@@ -117,12 +149,16 @@ Stitcher::Status Stitcher::estimateTransform(InputArrayOfArrays images, const st
 
 Stitcher::Status Stitcher::composePanorama(OutputArray pano)
 {
+    CV_INSTRUMENT_REGION()
+
     return composePanorama(std::vector<UMat>(), pano);
 }
 
 
 Stitcher::Status Stitcher::composePanorama(InputArrayOfArrays images, OutputArray pano)
 {
+    CV_INSTRUMENT_REGION()
+
     LOGLN("Warping images (auxiliary)... ");
 
     std::vector<UMat> imgs;
@@ -184,20 +220,24 @@ Stitcher::Status Stitcher::composePanorama(InputArrayOfArrays images, OutputArra
         K(1,1) *= (float)seam_work_aspect_;
         K(1,2) *= (float)seam_work_aspect_;
 
-        corners[i] = w->warp(seam_est_imgs_[i], K, cameras_[i].R, INTER_LINEAR, BORDER_CONSTANT, images_warped[i]);
+        corners[i] = w->warp(seam_est_imgs_[i], K, cameras_[i].R, INTER_LINEAR, BORDER_REFLECT, images_warped[i]);
         sizes[i] = images_warped[i].size();
 
         w->warp(masks[i], K, cameras_[i].R, INTER_NEAREST, BORDER_CONSTANT, masks_warped[i]);
     }
 
-    std::vector<UMat> images_warped_f(imgs_.size());
-    for (size_t i = 0; i < imgs_.size(); ++i)
-        images_warped[i].convertTo(images_warped_f[i], CV_32F);
 
     LOGLN("Warping images, time: " << ((getTickCount() - t) / getTickFrequency()) << " sec");
 
-    // Find seams
+    // Compensate exposure before finding seams
     exposure_comp_->feed(corners, images_warped, masks_warped);
+    for (size_t i = 0; i < imgs_.size(); ++i)
+        exposure_comp_->apply(int(i), corners[i], images_warped[i], masks_warped[i]);
+
+    // Find seams
+    std::vector<UMat> images_warped_f(imgs_.size());
+    for (size_t i = 0; i < imgs_.size(); ++i)
+        images_warped[i].convertTo(images_warped_f[i], CV_32F);
     seam_finder_->find(images_warped_f, corners, masks_warped);
 
     // Release unused memory
@@ -290,7 +330,7 @@ Stitcher::Status Stitcher::composePanorama(InputArrayOfArrays images, OutputArra
         int64 pt = getTickCount();
 #endif
         // Warp the current image
-        w->warp(img, K, cameras_[img_idx].R, INTER_LINEAR, BORDER_CONSTANT, img_warped);
+        w->warp(img, K, cameras_[img_idx].R, INTER_LINEAR, BORDER_REFLECT, img_warped);
         LOGLN(" warp the current image: " << ((getTickCount() - pt) / getTickFrequency()) << " sec");
 #if ENABLE_LOG
         pt = getTickCount();
@@ -365,6 +405,8 @@ Stitcher::Status Stitcher::composePanorama(InputArrayOfArrays images, OutputArra
 
 Stitcher::Status Stitcher::stitch(InputArrayOfArrays images, OutputArray pano)
 {
+    CV_INSTRUMENT_REGION()
+
     Status status = estimateTransform(images);
     if (status != OK)
         return status;
@@ -374,6 +416,8 @@ Stitcher::Status Stitcher::stitch(InputArrayOfArrays images, OutputArray pano)
 
 Stitcher::Status Stitcher::stitch(InputArrayOfArrays images, const std::vector<std::vector<Rect> > &rois, OutputArray pano)
 {
+    CV_INSTRUMENT_REGION()
+
     Status status = estimateTransform(images, rois);
     if (status != OK)
         return status;
@@ -404,6 +448,9 @@ Stitcher::Status Stitcher::matchImages()
     int64 t = getTickCount();
 #endif
 
+    std::vector<UMat> feature_find_imgs(imgs_.size());
+    std::vector<std::vector<Rect> > feature_find_rois(rois_.size());
+
     for (size_t i = 0; i < imgs_.size(); ++i)
     {
         full_img = imgs_[i];
@@ -432,17 +479,17 @@ Stitcher::Status Stitcher::matchImages()
         }
 
         if (rois_.empty())
-            (*features_finder_)(img, features_[i]);
+            feature_find_imgs[i] = img;
         else
         {
-            std::vector<Rect> rois(rois_[i].size());
+            feature_find_rois[i].resize(rois_[i].size());
             for (size_t j = 0; j < rois_[i].size(); ++j)
             {
                 Point tl(cvRound(rois_[i][j].x * work_scale_), cvRound(rois_[i][j].y * work_scale_));
                 Point br(cvRound(rois_[i][j].br().x * work_scale_), cvRound(rois_[i][j].br().y * work_scale_));
-                rois[j] = Rect(tl, br);
+                feature_find_rois[i][j] = Rect(tl, br);
             }
-            (*features_finder_)(img, features_[i], rois);
+            feature_find_imgs[i] = img;
         }
         features_[i].img_idx = (int)i;
         LOGLN("Features in image #" << i+1 << ": " << features_[i].keypoints.size());
@@ -451,10 +498,18 @@ Stitcher::Status Stitcher::matchImages()
         seam_est_imgs_[i] = img.clone();
     }
 
+    // find features possibly in parallel
+    if (rois_.empty())
+        (*features_finder_)(feature_find_imgs, features_);
+    else
+        (*features_finder_)(feature_find_imgs, features_, feature_find_rois);
+
     // Do it to save memory
     features_finder_->collectGarbage();
     full_img.release();
     img.release();
+    feature_find_imgs.clear();
+    feature_find_rois.clear();
 
     LOGLN("Finding features, time: " << ((getTickCount() - t) / getTickFrequency()) << " sec");
 
@@ -493,8 +548,16 @@ Stitcher::Status Stitcher::matchImages()
 
 Stitcher::Status Stitcher::estimateCameraParams()
 {
-    detail::HomographyBasedEstimator estimator;
-    if (!estimator(features_, pairwise_matches_, cameras_))
+    /* TODO OpenCV ABI 4.x
+    get rid of this dynamic_cast hack and use estimator_
+    */
+    Ptr<detail::Estimator> estimator;
+    if (dynamic_cast<detail::AffineBestOf2NearestMatcher*>(features_matcher_.get()))
+        estimator = makePtr<detail::AffineBasedEstimator>();
+    else
+        estimator = makePtr<detail::HomographyBasedEstimator>();
+
+    if (!(*estimator)(features_, pairwise_matches_, cameras_))
         return ERR_HOMOGRAPHY_EST_FAIL;
 
     for (size_t i = 0; i < cameras_.size(); ++i)
@@ -539,6 +602,8 @@ Stitcher::Status Stitcher::estimateCameraParams()
 
 Ptr<Stitcher> createStitcher(bool try_use_gpu)
 {
+    CV_INSTRUMENT_REGION()
+
     Ptr<Stitcher> stitcher = makePtr<Stitcher>();
     stitcher->setRegistrationResol(0.6);
     stitcher->setSeamEstimationResol(0.1);
@@ -549,7 +614,7 @@ Ptr<Stitcher> createStitcher(bool try_use_gpu)
     stitcher->setFeaturesMatcher(makePtr<detail::BestOf2NearestMatcher>(try_use_gpu));
     stitcher->setBundleAdjuster(makePtr<detail::BundleAdjusterRay>());
 
-    #ifdef HAVE_CUDA
+    #ifdef HAVE_OPENCV_CUDALEGACY
     if (try_use_gpu && cuda::getCudaEnabledDeviceCount() > 0)
     {
         #ifdef HAVE_OPENCV_NONFREE
@@ -561,20 +626,20 @@ Ptr<Stitcher> createStitcher(bool try_use_gpu)
         stitcher->setSeamFinder(makePtr<detail::GraphCutSeamFinderGpu>());
     }
     else
+    #endif
+    {
+        #ifdef HAVE_OPENCV_NONFREE
+        stitcher->setFeaturesFinder(makePtr<detail::SurfFeaturesFinder>());
+        #else
+        stitcher->setFeaturesFinder(makePtr<detail::OrbFeaturesFinder>());
         #endif
-        {
-            #ifdef HAVE_OPENCV_NONFREE
-            stitcher->setFeaturesFinder(makePtr<detail::SurfFeaturesFinder>());
-            #else
-            stitcher->setFeaturesFinder(makePtr<detail::OrbFeaturesFinder>());
-            #endif
-            stitcher->setWarper(makePtr<SphericalWarper>());
-            stitcher->setSeamFinder(makePtr<detail::GraphCutSeamFinder>(detail::GraphCutSeamFinderBase::COST_COLOR));
-        }
+        stitcher->setWarper(makePtr<SphericalWarper>());
+        stitcher->setSeamFinder(makePtr<detail::GraphCutSeamFinder>(detail::GraphCutSeamFinderBase::COST_COLOR));
+    }
 
-        stitcher->setExposureCompensator(makePtr<detail::BlocksGainCompensator>());
-        stitcher->setBlender(makePtr<detail::MultiBandBlender>(try_use_gpu));
+    stitcher->setExposureCompensator(makePtr<detail::BlocksGainCompensator>());
+    stitcher->setBlender(makePtr<detail::MultiBandBlender>(try_use_gpu));
 
-        return stitcher;
+    return stitcher;
 }
 } // namespace cv
diff --git a/modules/stitching/src/timelapsers.cpp b/modules/stitching/src/timelapsers.cpp
index bc1d62e..b42e79a 100644
--- a/modules/stitching/src/timelapsers.cpp
+++ b/modules/stitching/src/timelapsers.cpp
@@ -65,6 +65,8 @@ void Timelapser::initialize(const std::vector<Point> &corners, const std::vector
 
 void Timelapser::process(InputArray _img, InputArray /*_mask*/, Point tl)
 {
+    CV_INSTRUMENT_REGION()
+
     dst_.setTo(Scalar::all(0));
 
     Mat img = _img.getMat();
diff --git a/modules/stitching/src/util_log.hpp b/modules/stitching/src/util_log.hpp
new file mode 100644
index 0000000..da45477
--- /dev/null
+++ b/modules/stitching/src/util_log.hpp
@@ -0,0 +1,58 @@
+// This file is part of OpenCV project.
+// It is subject to the license terms in the LICENSE file found in the top-level directory
+// of this distribution and at http://opencv.org/license.html.
+
+#ifndef __OPENCV_STITCHING_UTIL_LOG_HPP__
+#define __OPENCV_STITCHING_UTIL_LOG_HPP__
+
+#ifndef ENABLE_LOG
+#define ENABLE_LOG 0
+#endif
+
+// TODO remove LOG macros, add logging class
+#if ENABLE_LOG
+#ifdef ANDROID
+  #include <iostream>
+  #include <sstream>
+  #include <android/log.h>
+  #define LOG_STITCHING_MSG(msg) \
+    do { \
+        Stringstream _os; \
+        _os << msg; \
+       __android_log_print(ANDROID_LOG_DEBUG, "STITCHING", "%s", _os.str().c_str()); \
+    } while(0);
+#else
+  #include <iostream>
+  #define LOG_STITCHING_MSG(msg) for(;;) { std::cout << msg; std::cout.flush(); break; }
+#endif
+#else
+  #define LOG_STITCHING_MSG(msg)
+#endif
+
+#define LOG_(_level, _msg)                     \
+    for(;;)                                    \
+    {                                          \
+        using namespace std;                   \
+        if ((_level) >= ::cv::detail::stitchingLogLevel()) \
+        {                                      \
+            LOG_STITCHING_MSG(_msg);           \
+        }                                      \
+    break;                                 \
+    }
+
+
+#define LOG(msg) LOG_(1, msg)
+#define LOG_CHAT(msg) LOG_(0, msg)
+
+#define LOGLN(msg) LOG(msg << std::endl)
+#define LOGLN_CHAT(msg) LOG_CHAT(msg << std::endl)
+
+//#if DEBUG_LOG_CHAT
+//  #define LOG_CHAT(msg) LOG(msg)
+//  #define LOGLN_CHAT(msg) LOGLN(msg)
+//#else
+//  #define LOG_CHAT(msg) do{}while(0)
+//  #define LOGLN_CHAT(msg) do{}while(0)
+//#endif
+
+#endif // __OPENCV_STITCHING_UTIL_LOG_HPP__
diff --git a/modules/stitching/src/warpers.cpp b/modules/stitching/src/warpers.cpp
index 3163fa4..96fe7f7 100644
--- a/modules/stitching/src/warpers.cpp
+++ b/modules/stitching/src/warpers.cpp
@@ -222,6 +222,58 @@ void PlaneWarper::detectResultRoi(Size src_size, Point &dst_tl, Point &dst_br)
 }
 
 
+Point2f AffineWarper::warpPoint(const Point2f &pt, InputArray K, InputArray H)
+{
+    Mat R, T;
+    getRTfromHomogeneous(H, R, T);
+    return PlaneWarper::warpPoint(pt, K, R, T);
+}
+
+
+Rect AffineWarper::buildMaps(Size src_size, InputArray K, InputArray H, OutputArray xmap, OutputArray ymap)
+{
+    Mat R, T;
+    getRTfromHomogeneous(H, R, T);
+    return PlaneWarper::buildMaps(src_size, K, R, T, xmap, ymap);
+}
+
+
+Point AffineWarper::warp(InputArray src, InputArray K, InputArray H,
+                         int interp_mode, int border_mode, OutputArray dst)
+{
+    Mat R, T;
+    getRTfromHomogeneous(H, R, T);
+    return PlaneWarper::warp(src, K, R, T, interp_mode, border_mode, dst);
+}
+
+
+Rect AffineWarper::warpRoi(Size src_size, InputArray K, InputArray H)
+{
+    Mat R, T;
+    getRTfromHomogeneous(H, R, T);
+    return PlaneWarper::warpRoi(src_size, K, R, T);
+}
+
+
+void AffineWarper::getRTfromHomogeneous(InputArray H_, Mat &R, Mat &T)
+{
+    Mat H = H_.getMat();
+    CV_Assert(H.size() == Size(3, 3) && H.type() == CV_32F);
+
+    T = Mat::zeros(3, 1, CV_32F);
+    R = H.clone();
+
+    T.at<float>(0,0) = R.at<float>(0,2);
+    T.at<float>(1,0) = R.at<float>(1,2);
+    R.at<float>(0,2) = 0.f;
+    R.at<float>(1,2) = 0.f;
+
+    // we want to compensate transform to fit into plane warper
+    R = R.t();
+    T = (R * T) * -1;
+}
+
+
 void SphericalWarper::detectResultRoi(Size src_size, Point &dst_tl, Point &dst_br)
 {
     detectResultRoiByBorder(src_size, dst_tl, dst_br);
diff --git a/modules/stitching/test/ocl/test_warpers.cpp b/modules/stitching/test/ocl/test_warpers.cpp
index 79137bf..2b74372 100644
--- a/modules/stitching/test/ocl/test_warpers.cpp
+++ b/modules/stitching/test/ocl/test_warpers.cpp
@@ -55,7 +55,7 @@ struct WarperTestBase :
     UMat usrc, udst, uxmap, uymap;
     Mat K, R;
 
-    virtual void generateTestData()
+    void generateTestData()
     {
         Size size = randomSize(1, MAX_VALUE);
 
@@ -143,6 +143,27 @@ OCL_TEST_F(PlaneWarperTest, Mat)
     }
 }
 
+typedef WarperTestBase AffineWarperTest;
+
+OCL_TEST_F(AffineWarperTest, Mat)
+{
+    for (int j = 0; j < test_loop_times; j++)
+    {
+        generateTestData();
+
+        Ptr<WarperCreator> creator = makePtr<AffineWarper>();
+        Ptr<detail::RotationWarper> warper = creator->create(1.0);
+
+        OCL_OFF(warper->buildMaps(src.size(), K, R, xmap, ymap));
+        OCL_ON(warper->buildMaps(usrc.size(), K, R, uxmap, uymap));
+
+        OCL_OFF(warper->warp(src, K, R, INTER_LINEAR, BORDER_REPLICATE, dst));
+        OCL_ON(warper->warp(usrc, K, R, INTER_LINEAR, BORDER_REPLICATE, udst));
+
+        Near(1.5e-4);
+    }
+}
+
 } } // namespace cvtest::ocl
 
 #endif // HAVE_OPENCL
diff --git a/modules/stitching/test/test_matchers.cpp b/modules/stitching/test/test_matchers.cpp
index 6deed7b..61d86a6 100644
--- a/modules/stitching/test/test_matchers.cpp
+++ b/modules/stitching/test/test_matchers.cpp
@@ -42,11 +42,11 @@
 #include "test_precomp.hpp"
 #include "opencv2/opencv_modules.hpp"
 
-#ifdef HAVE_OPENCV_XFEATURES2D
-
 using namespace cv;
 using namespace std;
 
+#ifdef HAVE_OPENCV_XFEATURES2D
+
 TEST(SurfFeaturesFinder, CanFindInROIs)
 {
     Ptr<detail::FeaturesFinder> finder = makePtr<detail::SurfFeaturesFinder>();
@@ -75,4 +75,27 @@ TEST(SurfFeaturesFinder, CanFindInROIs)
     ASSERT_EQ(bad_count, 0);
 }
 
-#endif
+#endif // HAVE_OPENCV_XFEATURES2D
+
+TEST(ParallelFeaturesFinder, IsSameWithSerial)
+{
+    Ptr<detail::FeaturesFinder> para_finder = makePtr<detail::OrbFeaturesFinder>();
+    Ptr<detail::FeaturesFinder> serial_finder = makePtr<detail::OrbFeaturesFinder>();
+    Mat img  = imread(string(cvtest::TS::ptr()->get_data_path()) + "stitching/a3.png", IMREAD_GRAYSCALE);
+
+    vector<Mat> imgs(50, img);
+    detail::ImageFeatures serial_features;
+    vector<detail::ImageFeatures> para_features(imgs.size());
+
+    (*serial_finder)(img, serial_features);
+    (*para_finder)(imgs, para_features);
+
+    // results must be the same
+    for(size_t i = 0; i < para_features.size(); ++i)
+    {
+        Mat diff_descriptors = serial_features.descriptors.getMat(ACCESS_READ) != para_features[i].descriptors.getMat(ACCESS_READ);
+        ASSERT_EQ(countNonZero(diff_descriptors), 0);
+        ASSERT_EQ(serial_features.img_size, para_features[i].img_size);
+        ASSERT_EQ(serial_features.keypoints.size(), para_features[i].keypoints.size());
+    }
+}
diff --git a/modules/superres/include/opencv2/superres.hpp b/modules/superres/include/opencv2/superres.hpp
index dec8e4e..60d4faa 100644
--- a/modules/superres/include/opencv2/superres.hpp
+++ b/modules/superres/include/opencv2/superres.hpp
@@ -40,8 +40,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_SUPERRES_HPP__
-#define __OPENCV_SUPERRES_HPP__
+#ifndef OPENCV_SUPERRES_HPP
+#define OPENCV_SUPERRES_HPP
 
 #include "opencv2/core.hpp"
 #include "opencv2/superres/optical_flow.hpp"
@@ -204,4 +204,4 @@ namespace cv
     }
 }
 
-#endif // __OPENCV_SUPERRES_HPP__
+#endif // OPENCV_SUPERRES_HPP
diff --git a/modules/superres/include/opencv2/superres/optical_flow.hpp b/modules/superres/include/opencv2/superres/optical_flow.hpp
index d2f29a3..07e7ca9 100644
--- a/modules/superres/include/opencv2/superres/optical_flow.hpp
+++ b/modules/superres/include/opencv2/superres/optical_flow.hpp
@@ -40,8 +40,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_SUPERRES_OPTICAL_FLOW_HPP__
-#define __OPENCV_SUPERRES_OPTICAL_FLOW_HPP__
+#ifndef OPENCV_SUPERRES_OPTICAL_FLOW_HPP
+#define OPENCV_SUPERRES_OPTICAL_FLOW_HPP
 
 #include "opencv2/core.hpp"
 
@@ -200,4 +200,4 @@ namespace cv
     }
 }
 
-#endif // __OPENCV_SUPERRES_OPTICAL_FLOW_HPP__
+#endif // OPENCV_SUPERRES_OPTICAL_FLOW_HPP
diff --git a/modules/superres/src/btv_l1.cpp b/modules/superres/src/btv_l1.cpp
index d47453f..9c86341 100644
--- a/modules/superres/src/btv_l1.cpp
+++ b/modules/superres/src/btv_l1.cpp
@@ -658,6 +658,8 @@ namespace
     void BTVL1_Base::process(InputArrayOfArrays _src, OutputArray _dst, InputArrayOfArrays _forwardMotions,
                              InputArrayOfArrays _backwardMotions, int baseIdx)
     {
+        CV_INSTRUMENT_REGION()
+
         CV_Assert( scale_ > 1 );
         CV_Assert( iterations_ > 0 );
         CV_Assert( tau_ > 0.0 );
@@ -954,6 +956,8 @@ namespace
 
     void BTVL1::processImpl(Ptr<FrameSource>& frameSource, OutputArray _output)
     {
+        CV_INSTRUMENT_REGION()
+
         if (outPos_ >= storePos_)
         {
             _output.release();
@@ -1003,6 +1007,8 @@ namespace
 
     void BTVL1::readNextFrame(Ptr<FrameSource>& frameSource)
     {
+        CV_INSTRUMENT_REGION()
+
         frameSource->nextFrame(curFrame_);
         if (curFrame_.empty())
             return;
@@ -1065,6 +1071,8 @@ namespace
 
     void BTVL1::processFrame(int idx)
     {
+        CV_INSTRUMENT_REGION()
+
         CV_OCL_RUN(isUmat_,
                    ocl_processFrame(idx))
 
diff --git a/modules/superres/src/input_array_utility.cpp b/modules/superres/src/input_array_utility.cpp
index a823e43..b3ea4bb 100644
--- a/modules/superres/src/input_array_utility.cpp
+++ b/modules/superres/src/input_array_utility.cpp
@@ -235,6 +235,8 @@ namespace
 
 Mat cv::superres::convertToType(const Mat& src, int type, Mat& buf0, Mat& buf1)
 {
+    CV_INSTRUMENT_REGION()
+
     if (src.type() == type)
         return src;
 
@@ -260,6 +262,8 @@ Mat cv::superres::convertToType(const Mat& src, int type, Mat& buf0, Mat& buf1)
 
 UMat cv::superres::convertToType(const UMat& src, int type, UMat& buf0, UMat& buf1)
 {
+    CV_INSTRUMENT_REGION()
+
     if (src.type() == type)
         return src;
 
diff --git a/modules/superres/src/optical_flow.cpp b/modules/superres/src/optical_flow.cpp
index 25a10af..89a6789 100644
--- a/modules/superres/src/optical_flow.cpp
+++ b/modules/superres/src/optical_flow.cpp
@@ -65,7 +65,9 @@ namespace
         virtual void impl(InputArray input0, InputArray input1, OutputArray dst) = 0;
 
     private:
+#ifdef HAVE_OPENCL
         bool ocl_calc(InputArray frame0, InputArray frame1, OutputArray flow1, OutputArray flow2);
+#endif
 
         int work_type_;
 
@@ -85,6 +87,7 @@ namespace
     {
     }
 
+#ifdef HAVE_OPENCL
     bool CpuOpticalFlow::ocl_calc(InputArray _frame0, InputArray _frame1, OutputArray _flow1, OutputArray _flow2)
     {
         UMat frame0 = arrGetUMat(_frame0, ubuf_[0]);
@@ -116,9 +119,12 @@ namespace
 
         return true;
     }
+#endif
 
     void CpuOpticalFlow::calc(InputArray _frame0, InputArray _frame1, OutputArray _flow1, OutputArray _flow2)
     {
+        CV_INSTRUMENT_REGION()
+
         CV_OCL_RUN(_flow1.isUMat() && (_flow2.isUMat() || !_flow2.needed()),
                    ocl_calc(_frame0, _frame1, _flow1, _flow2))
 
@@ -214,6 +220,8 @@ namespace
 
     void Farneback::calc(InputArray frame0, InputArray frame1, OutputArray flow1, OutputArray flow2)
     {
+        CV_INSTRUMENT_REGION()
+
         CpuOpticalFlow::calc(frame0, frame1, flow1, flow2);
     }
 
@@ -358,6 +366,8 @@ namespace
 
     void DualTVL1::calc(InputArray frame0, InputArray frame1, OutputArray flow1, OutputArray flow2)
     {
+        CV_INSTRUMENT_REGION()
+
         CpuOpticalFlow::calc(frame0, frame1, flow1, flow2);
     }
 
@@ -434,6 +444,8 @@ namespace
 
     void GpuOpticalFlow::calc(InputArray _frame0, InputArray _frame1, OutputArray _flow1, OutputArray _flow2)
     {
+        CV_INSTRUMENT_REGION()
+
         GpuMat frame0 = arrGetGpuMat(_frame0, buf_[0]);
         GpuMat frame1 = arrGetGpuMat(_frame1, buf_[1]);
 
diff --git a/modules/superres/src/super_resolution.cpp b/modules/superres/src/super_resolution.cpp
index 3eae5a6..6055920 100644
--- a/modules/superres/src/super_resolution.cpp
+++ b/modules/superres/src/super_resolution.cpp
@@ -61,6 +61,8 @@ void cv::superres::SuperResolution::setInput(const Ptr<FrameSource>& frameSource
 
 void cv::superres::SuperResolution::nextFrame(OutputArray frame)
 {
+    CV_INSTRUMENT_REGION()
+
     isUmat_ = frame.isUMat();
 
     if (firstCall_)
diff --git a/modules/ts/CMakeLists.txt b/modules/ts/CMakeLists.txt
index 8d625f8..f95bed0 100644
--- a/modules/ts/CMakeLists.txt
+++ b/modules/ts/CMakeLists.txt
@@ -21,3 +21,23 @@ ocv_add_module(ts INTERNAL opencv_core opencv_imgproc opencv_imgcodecs opencv_vi
 ocv_glob_module_sources()
 ocv_module_include_directories()
 ocv_create_module()
+
+# generate config file
+set(OPENCV_TESTS_CONFIG_FILE "${CMAKE_BINARY_DIR}/opencv_tests_config.hpp")
+set(OPENCV_TESTS_CONFIG_STR "")
+if(CMAKE_INSTALL_PREFIX)
+  set(OPENCV_TESTS_CONFIG_STR "${OPENCV_TESTS_CONFIG_STR}
+#define OPENCV_INSTALL_PREFIX \"${CMAKE_INSTALL_PREFIX}\"
+")
+endif()
+if(OPENCV_TEST_DATA_INSTALL_PATH)
+  set(OPENCV_TESTS_CONFIG_STR "${OPENCV_TESTS_CONFIG_STR}
+#define OPENCV_TEST_DATA_INSTALL_PATH \"${OPENCV_TEST_DATA_INSTALL_PATH}\"
+")
+endif()
+if(EXISTS "${OPENCV_TESTS_CONFIG_FILE}")
+  file(READ "${OPENCV_TESTS_CONFIG_FILE}" __content)
+endif()
+if(NOT OPENCV_TESTS_CONFIG_STR STREQUAL "${__content}")
+  file(WRITE "${OPENCV_TESTS_CONFIG_FILE}" "${OPENCV_TESTS_CONFIG_STR}")
+endif()
diff --git a/modules/ts/include/opencv2/ts.hpp b/modules/ts/include/opencv2/ts.hpp
index e809f6b..c573905 100644
--- a/modules/ts/include/opencv2/ts.hpp
+++ b/modules/ts/include/opencv2/ts.hpp
@@ -1,5 +1,5 @@
-#ifndef __OPENCV_GTESTCV_HPP__
-#define __OPENCV_GTESTCV_HPP__
+#ifndef OPENCV_TS_HPP
+#define OPENCV_TS_HPP
 
 #include "opencv2/core/cvdef.h"
 #include <stdarg.h> // for va_list
@@ -35,6 +35,9 @@
 #  define GTEST_USES_POSIX_RE 0
 #endif
 
+#define PARAM_TEST_CASE(name, ...) struct name : testing::TestWithParam< std::tr1::tuple< __VA_ARGS__ > >
+#define GET_PARAM(k) std::tr1::get< k >(GetParam())
+
 #include "opencv2/core.hpp"
 #include "opencv2/core/utility.hpp"
 
@@ -52,6 +55,14 @@ using cv::Rect;
 using cv::InputArray;
 using cv::noArray;
 
+class SkipTestException: public cv::Exception
+{
+public:
+    int dummy; // workaround for MacOSX Xcode 7.3 bug (don't make class "empty")
+    SkipTestException() : dummy(0) {}
+    SkipTestException(const cv::String& message) : dummy(0) { this->msg = message; }
+};
+
 class CV_EXPORTS TS;
 
 CV_EXPORTS int64 readSeed(const char* str);
@@ -161,7 +172,7 @@ CV_EXPORTS void compare(const Mat& src1, const Mat& src2, Mat& dst, int cmpop);
 CV_EXPORTS void compare(const Mat& src, double s, Mat& dst, int cmpop);
 CV_EXPORTS void gemm(const Mat& src1, const Mat& src2, double alpha,
                      const Mat& src3, double beta, Mat& dst, int flags);
-    CV_EXPORTS void transform( const Mat& src, Mat& dst, const Mat& transmat, const Mat& shift );
+CV_EXPORTS void transform( const Mat& src, Mat& dst, const Mat& transmat, const Mat& shift );
 CV_EXPORTS double crossCorr(const Mat& src1, const Mat& src2);
 CV_EXPORTS void threshold( const Mat& src, Mat& dst, double thresh, double maxval, int thresh_type );
 CV_EXPORTS void minMaxIdx( InputArray _img, double* minVal, double* maxVal,
@@ -417,6 +428,8 @@ public:
     // returns textual description of failure code
     static string str_from_code( const TS::FailureCode code );
 
+    std::vector<std::string> data_search_path;
+    std::vector<std::string> data_search_subdir;
 protected:
 
     // these are allocated within a test to try keep them valid in case of stack corruption
@@ -526,27 +539,49 @@ protected:
     }
 };
 
+extern uint64 param_seed;
+
 struct CV_EXPORTS DefaultRngAuto
 {
     const uint64 old_state;
 
-    DefaultRngAuto() : old_state(cv::theRNG().state) { cv::theRNG().state = (uint64)-1; }
+    DefaultRngAuto() : old_state(cv::theRNG().state) { cv::theRNG().state = cvtest::param_seed; }
     ~DefaultRngAuto() { cv::theRNG().state = old_state; }
 
     DefaultRngAuto& operator=(const DefaultRngAuto&);
 };
 
-}
-
-namespace cvtest
-{
 
 // test images generation functions
 CV_EXPORTS void fillGradient(Mat& img, int delta = 5);
 CV_EXPORTS void smoothBorder(Mat& img, const Scalar& color, int delta = 3);
 
 CV_EXPORTS void printVersionInfo(bool useStdOut = true);
-} //namespace cvtest
+
+
+// Utility functions
+
+CV_EXPORTS void addDataSearchPath(const std::string& path);
+CV_EXPORTS void addDataSearchSubDirectory(const std::string& subdir);
+
+/*! @brief Try to find requested data file
+
+  Search directories:
+
+  0. TS::data_search_path (search sub-directories are not used)
+  1. OPENCV_TEST_DATA_PATH environment variable
+  2. One of these:
+     a. OpenCV testdata based on build location: "./" + "share/OpenCV/testdata"
+     b. OpenCV testdata at install location: CMAKE_INSTALL_PREFIX + "share/OpenCV/testdata"
+
+  Search sub-directories:
+
+  - addDataSearchSubDirectory()
+  - modulename from TS::init()
+
+ */
+CV_EXPORTS std::string findDataFile(const std::string& relative_path, bool required = true);
+
 
 #ifndef __CV_TEST_EXEC_ARGS
 #if defined(_MSC_VER) && (_MSC_VER <= 1400)
@@ -559,9 +594,9 @@ CV_EXPORTS void printVersionInfo(bool useStdOut = true);
 #endif
 
 #ifdef HAVE_OPENCL
-namespace cvtest { namespace ocl {
+namespace ocl {
 void dumpOpenCLDevice();
-} }
+}
 #define TEST_DUMP_OCL_INFO cvtest::ocl::dumpOpenCLDevice();
 #else
 #define TEST_DUMP_OCL_INFO
@@ -572,11 +607,13 @@ void parseCustomOptions(int argc, char **argv);
 #define CV_TEST_MAIN(resourcesubdir, ...) \
 int main(int argc, char **argv) \
 { \
-    __CV_TEST_EXEC_ARGS(__VA_ARGS__) \
-    cvtest::TS::ptr()->init(resourcesubdir); \
+    using namespace cvtest; \
+    TS* ts = TS::ptr(); \
+    ts->init(resourcesubdir); \
     ::testing::InitGoogleTest(&argc, argv); \
     cvtest::printVersionInfo(); \
     TEST_DUMP_OCL_INFO \
+    __CV_TEST_EXEC_ARGS(__VA_ARGS__) \
     parseCustomOptions(argc, argv); \
     return RUN_ALL_TESTS(); \
 }
@@ -588,7 +625,9 @@ int main(int argc, char **argv) \
     FAIL() << "No equivalent implementation."; \
 } while (0)
 
-#endif
+} //namespace cvtest
+
+#endif // OPENCV_TS_HPP
 
 #include "opencv2/ts/ts_perf.hpp"
 
diff --git a/modules/ts/include/opencv2/ts/cuda_perf.hpp b/modules/ts/include/opencv2/ts/cuda_perf.hpp
index c179b72..672b9ff 100644
--- a/modules/ts/include/opencv2/ts/cuda_perf.hpp
+++ b/modules/ts/include/opencv2/ts/cuda_perf.hpp
@@ -40,8 +40,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_CUDA_PERF_UTILITY_HPP__
-#define __OPENCV_CUDA_PERF_UTILITY_HPP__
+#ifndef OPENCV_CUDA_PERF_UTILITY_HPP
+#define OPENCV_CUDA_PERF_UTILITY_HPP
 
 #include "opencv2/core.hpp"
 #include "opencv2/imgcodecs.hpp"
@@ -125,4 +125,4 @@ namespace perf
 #endif
 }
 
-#endif // __OPENCV_CUDA_PERF_UTILITY_HPP__
+#endif // OPENCV_CUDA_PERF_UTILITY_HPP
diff --git a/modules/ts/include/opencv2/ts/cuda_test.hpp b/modules/ts/include/opencv2/ts/cuda_test.hpp
index 8783fb6..b459bb3 100644
--- a/modules/ts/include/opencv2/ts/cuda_test.hpp
+++ b/modules/ts/include/opencv2/ts/cuda_test.hpp
@@ -40,8 +40,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_CUDA_TEST_UTILITY_HPP__
-#define __OPENCV_CUDA_TEST_UTILITY_HPP__
+#ifndef OPENCV_CUDA_TEST_UTILITY_HPP
+#define OPENCV_CUDA_TEST_UTILITY_HPP
 
 #include <stdexcept>
 #include "cvconfig.h"
@@ -180,14 +180,17 @@ namespace cvtest
         static int AddToRegistry() { \
           ::testing::UnitTest::GetInstance()->parameterized_test_registry(). \
               GetTestCasePatternHolder<test_case_name>(\
-                  #test_case_name, __FILE__, __LINE__)->AddTestPattern(\
-                      #test_case_name, \
-                      #test_name, \
-                      new ::testing::internal::TestMetaFactory< \
-                          GTEST_TEST_CLASS_NAME_(test_case_name, test_name)>()); \
+                  #test_case_name, \
+                  ::testing::internal::CodeLocation(\
+                      __FILE__, __LINE__))->AddTestPattern(\
+                          #test_case_name, \
+                          #test_name, \
+                          new ::testing::internal::TestMetaFactory< \
+                              GTEST_TEST_CLASS_NAME_(\
+                                  test_case_name, test_name)>()); \
           return 0; \
         } \
-        static int gtest_registering_dummy_; \
+        static int gtest_registering_dummy_ GTEST_ATTRIBUTE_UNUSED_; \
         GTEST_DISALLOW_COPY_AND_ASSIGN_(\
             GTEST_TEST_CLASS_NAME_(test_case_name, test_name)); \
       }; \
@@ -208,9 +211,6 @@ namespace cvtest
       } \
       void GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::UnsafeTestBody()
 
-    #define PARAM_TEST_CASE(name, ...) struct name : testing::TestWithParam< std::tr1::tuple< __VA_ARGS__ > >
-    #define GET_PARAM(k) std::tr1::get< k >(GetParam())
-
     #define DIFFERENT_SIZES testing::Values(cv::Size(128, 128), cv::Size(113, 113))
 
     // Depth
@@ -366,4 +366,4 @@ namespace cv { namespace cuda
 #endif // HAVE_CUDA
 
 
-#endif // __OPENCV_CUDA_TEST_UTILITY_HPP__
+#endif // OPENCV_CUDA_TEST_UTILITY_HPP
diff --git a/modules/ts/include/opencv2/ts/ocl_perf.hpp b/modules/ts/include/opencv2/ts/ocl_perf.hpp
index c2e8600..58091f3 100644
--- a/modules/ts/include/opencv2/ts/ocl_perf.hpp
+++ b/modules/ts/include/opencv2/ts/ocl_perf.hpp
@@ -39,8 +39,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_TS_OCL_PERF_HPP__
-#define __OPENCV_TS_OCL_PERF_HPP__
+#ifndef OPENCV_TS_OCL_PERF_HPP
+#define OPENCV_TS_OCL_PERF_HPP
 
 #include "ocl_test.hpp"
 #include "ts_perf.hpp"
@@ -97,13 +97,13 @@ using std::tr1::tuple;
 
 // TODO Replace finish call to dstUMat.wait()
 #define OCL_TEST_CYCLE() \
-    for (cvtest::ocl::perf::safeFinish(); startTimer(), next(); cvtest::ocl::perf::safeFinish(), stopTimer())
+    for (cvtest::ocl::perf::safeFinish(); next() && startTimer(); cvtest::ocl::perf::safeFinish(), stopTimer())
 
 #define OCL_TEST_CYCLE_N(n) \
-    for(declare.iterations(n), cvtest::ocl::perf::safeFinish(); startTimer(), next(); cvtest::ocl::perf::safeFinish(), stopTimer())
+    for (declare.iterations(n), cvtest::ocl::perf::safeFinish(); next() && startTimer(); cvtest::ocl::perf::safeFinish(), stopTimer())
 
 #define OCL_TEST_CYCLE_MULTIRUN(runsNum) \
-    for (declare.runs(runsNum), cvtest::ocl::perf::safeFinish(); startTimer(), next(); cvtest::ocl::perf::safeFinish(), stopTimer()) \
+    for (declare.runs(runsNum), cvtest::ocl::perf::safeFinish(); next() && startTimer(); cvtest::ocl::perf::safeFinish(), stopTimer()) \
         for (int r = 0; r < runsNum; cvtest::ocl::perf::safeFinish(), ++r)
 
 
@@ -128,4 +128,4 @@ using namespace perf;
 } // namespace cvtest::ocl
 } // namespace cvtest
 
-#endif // __OPENCV_TS_OCL_PERF_HPP__
+#endif // OPENCV_TS_OCL_PERF_HPP
diff --git a/modules/ts/include/opencv2/ts/ocl_test.hpp b/modules/ts/include/opencv2/ts/ocl_test.hpp
index 559f4aa..c967cd7 100644
--- a/modules/ts/include/opencv2/ts/ocl_test.hpp
+++ b/modules/ts/include/opencv2/ts/ocl_test.hpp
@@ -39,8 +39,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_TS_OCL_TEST_HPP__
-#define __OPENCV_TS_OCL_TEST_HPP__
+#ifndef OPENCV_TS_OCL_TEST_HPP
+#define OPENCV_TS_OCL_TEST_HPP
 
 #include "opencv2/opencv_modules.hpp"
 
@@ -324,10 +324,9 @@ struct CV_EXPORTS TSTestWithParam : public TestUtils, public ::testing::TestWith
 
 };
 
+#undef PARAM_TEST_CASE
 #define PARAM_TEST_CASE(name, ...) struct name : public TSTestWithParam< std::tr1::tuple< __VA_ARGS__ > >
 
-#define GET_PARAM(k) std::tr1::get< k >(GetParam())
-
 #ifndef IMPLEMENT_PARAM_CLASS
 #define IMPLEMENT_PARAM_CLASS(name, type) \
     class name \
@@ -350,8 +349,8 @@ IMPLEMENT_PARAM_CLASS(Channels, int)
 #define OCL_TEST_F(name, ...) typedef name OCL_##name; TEST_F(OCL_##name, __VA_ARGS__)
 #define OCL_TEST(name, ...) TEST(OCL_##name, __VA_ARGS__)
 
-#define OCL_OFF(fn) cv::ocl::setUseOpenCL(false); fn
-#define OCL_ON(fn) cv::ocl::setUseOpenCL(true); fn
+#define OCL_OFF(...) cv::ocl::setUseOpenCL(false); __VA_ARGS__ ;
+#define OCL_ON(...) cv::ocl::setUseOpenCL(true); __VA_ARGS__ ;
 
 #define OCL_ALL_DEPTHS Values(CV_8U, CV_8S, CV_16U, CV_16S, CV_32S, CV_32F, CV_64F)
 #define OCL_ALL_CHANNELS Values(1, 2, 3, 4)
@@ -365,4 +364,4 @@ CV_ENUM(BorderType, BORDER_CONSTANT, BORDER_REPLICATE, BORDER_REFLECT, BORDER_WR
 
 } } // namespace cvtest::ocl
 
-#endif // __OPENCV_TS_OCL_TEST_HPP__
+#endif // OPENCV_TS_OCL_TEST_HPP
diff --git a/modules/ts/include/opencv2/ts/ts_ext.hpp b/modules/ts/include/opencv2/ts/ts_ext.hpp
index 08039ba..05ccc63 100644
--- a/modules/ts/include/opencv2/ts/ts_ext.hpp
+++ b/modules/ts/include/opencv2/ts/ts_ext.hpp
@@ -5,10 +5,30 @@
 // Copyright (C) 2014, Intel, Inc., all rights reserved.
 // Third party copyrights are property of their respective owners.
 
-#ifndef __OPENCV_TS_EXT_HPP__
-#define __OPENCV_TS_EXT_HPP__
+#ifndef OPENCV_TS_EXT_HPP
+#define OPENCV_TS_EXT_HPP
 
+namespace cvtest {
 void checkIppStatus();
+}
+
+#define CV_TEST_INIT \
+    cv::ipp::setIppStatus(0); \
+    cv::theRNG().state = cvtest::param_seed;
+#define CV_TEST_CLEANUP ::cvtest::checkIppStatus();
+#define CV_TEST_BODY_IMPL \
+    { \
+       try { \
+          CV_TEST_INIT \
+          Body(); \
+          CV_TEST_CLEANUP \
+       } \
+       catch (cvtest::SkipTestException& e) \
+       { \
+          printf("[     SKIP ] %s\n", e.what()); \
+       } \
+    } \
+
 
 #undef TEST
 #define TEST(test_case_name, test_name) \
@@ -27,12 +47,13 @@ void checkIppStatus();
       ::test_info_ =\
         ::testing::internal::MakeAndRegisterTestInfo(\
             #test_case_name, #test_name, NULL, NULL, \
+            ::testing::internal::CodeLocation(__FILE__, __LINE__), \
             (::testing::internal::GetTestTypeId()), \
             ::testing::Test::SetUpTestCase, \
             ::testing::Test::TearDownTestCase, \
             new ::testing::internal::TestFactoryImpl<\
                 GTEST_TEST_CLASS_NAME_(test_case_name, test_name)>);\
-    void GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::TestBody() { cv::ipp::setIppStatus(0); Body(); checkIppStatus(); } \
+    void GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::TestBody() CV_TEST_BODY_IMPL \
     void GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::Body()
 
 #undef TEST_F
@@ -52,12 +73,13 @@ void checkIppStatus();
       ::test_info_ =\
         ::testing::internal::MakeAndRegisterTestInfo(\
             #test_fixture, #test_name, NULL, NULL, \
+            ::testing::internal::CodeLocation(__FILE__, __LINE__), \
             (::testing::internal::GetTypeId<test_fixture>()), \
             test_fixture::SetUpTestCase, \
             test_fixture::TearDownTestCase, \
             new ::testing::internal::TestFactoryImpl<\
                 GTEST_TEST_CLASS_NAME_(test_fixture, test_name)>);\
-    void GTEST_TEST_CLASS_NAME_(test_fixture, test_name)::TestBody() { cv::ipp::setIppStatus(0); Body(); checkIppStatus(); } \
+    void GTEST_TEST_CLASS_NAME_(test_fixture, test_name)::TestBody() CV_TEST_BODY_IMPL \
     void GTEST_TEST_CLASS_NAME_(test_fixture, test_name)::Body()
 
 #undef TEST_P
@@ -72,21 +94,24 @@ void checkIppStatus();
     static int AddToRegistry() { \
       ::testing::UnitTest::GetInstance()->parameterized_test_registry(). \
           GetTestCasePatternHolder<test_case_name>(\
-              #test_case_name, __FILE__, __LINE__)->AddTestPattern(\
-                  #test_case_name, \
-                  #test_name, \
-                  new ::testing::internal::TestMetaFactory< \
-                      GTEST_TEST_CLASS_NAME_(test_case_name, test_name)>()); \
+              #test_case_name, \
+              ::testing::internal::CodeLocation(\
+                  __FILE__, __LINE__))->AddTestPattern(\
+                      #test_case_name, \
+                      #test_name, \
+                      new ::testing::internal::TestMetaFactory< \
+                          GTEST_TEST_CLASS_NAME_(\
+                              test_case_name, test_name)>()); \
       return 0; \
     } \
-    static int gtest_registering_dummy_; \
+    static int gtest_registering_dummy_ GTEST_ATTRIBUTE_UNUSED_; \
     GTEST_DISALLOW_COPY_AND_ASSIGN_(\
         GTEST_TEST_CLASS_NAME_(test_case_name, test_name)); \
   }; \
   int GTEST_TEST_CLASS_NAME_(test_case_name, \
                              test_name)::gtest_registering_dummy_ = \
       GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::AddToRegistry(); \
-    void GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::TestBody() { cv::ipp::setIppStatus(0); Body(); checkIppStatus(); } \
+    void GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::TestBody() CV_TEST_BODY_IMPL \
     void GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::Body()
 
-#endif  // __OPENCV_TS_EXT_HPP__
+#endif  // OPENCV_TS_EXT_HPP
diff --git a/modules/ts/include/opencv2/ts/ts_gtest.h b/modules/ts/include/opencv2/ts/ts_gtest.h
index cec926a..d886c97 100644
--- a/modules/ts/include/opencv2/ts/ts_gtest.h
+++ b/modules/ts/include/opencv2/ts/ts_gtest.h
@@ -126,8 +126,11 @@
 // Authors: wan at google.com (Zhanyong Wan)
 //
 // Low-level types and utilities for porting Google Test to various
-// platforms.  They are subject to change without notice.  DO NOT USE
-// THEM IN USER CODE.
+// platforms.  All macros ending with _ and symbols defined in an
+// internal namespace are subject to change without notice.  Code
+// outside Google Test MUST NOT USE THEM DIRECTLY.  Macros that don't
+// end with _ are part of Google Test's public API and can be used by
+// code outside Google Test.
 //
 // This file is fundamental to Google Test.  All other Google Test source
 // files are expected to #include this.  Therefore, it cannot #include
@@ -136,9 +139,30 @@
 #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_
 #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_
 
-// The user can define the following macros in the build script to
-// control Google Test's behavior.  If the user doesn't define a macro
-// in this list, Google Test will define it.
+// Environment-describing macros
+// -----------------------------
+//
+// Google Test can be used in many different environments.  Macros in
+// this section tell Google Test what kind of environment it is being
+// used in, such that Google Test can provide environment-specific
+// features and implementations.
+//
+// Google Test tries to automatically detect the properties of its
+// environment, so users usually don't need to worry about these
+// macros.  However, the automatic detection is not perfect.
+// Sometimes it's necessary for a user to define some of the following
+// macros in the build script to override Google Test's decisions.
+//
+// If the user doesn't define a macro in the list, Google Test will
+// provide a default definition.  After this header is #included, all
+// macros in this list will be defined to either 1 or 0.
+//
+// Notes to maintainers:
+//   - Each macro here is a user-tweakable knob; do not grow the list
+//     lightly.
+//   - Use #if to key off these macros.  Don't use #ifdef or "#if
+//     defined(...)", which will not work as these macros are ALWAYS
+//     defined.
 //
 //   GTEST_HAS_CLONE          - Define it to 1/0 to indicate that clone(2)
 //                              is/isn't available.
@@ -182,18 +206,23 @@
 //                            - Define to 1 when compiling Google Test itself
 //                              as a shared library.
 
-// This header defines the following utilities:
+// Platform-indicating macros
+// --------------------------
+//
+// Macros indicating the platform on which Google Test is being used
+// (a macro is defined to 1 if compiled on the given platform;
+// otherwise UNDEFINED -- it's never defined to 0.).  Google Test
+// defines these macros automatically.  Code outside Google Test MUST
+// NOT define them.
 //
-// Macros indicating the current platform (defined to 1 if compiled on
-// the given platform; otherwise undefined):
 //   GTEST_OS_AIX      - IBM AIX
 //   GTEST_OS_CYGWIN   - Cygwin
+//   GTEST_OS_FREEBSD  - FreeBSD
 //   GTEST_OS_HPUX     - HP-UX
 //   GTEST_OS_LINUX    - Linux
 //     GTEST_OS_LINUX_ANDROID - Google Android
 //   GTEST_OS_MAC      - Mac OS X
 //     GTEST_OS_IOS    - iOS
-//       GTEST_OS_IOS_SIMULATOR - iOS simulator
 //   GTEST_OS_NACL     - Google Native Client (NaCl)
 //   GTEST_OS_OPENBSD  - OpenBSD
 //   GTEST_OS_QNX      - QNX
@@ -203,6 +232,8 @@
 //     GTEST_OS_WINDOWS_DESKTOP  - Windows Desktop
 //     GTEST_OS_WINDOWS_MINGW    - MinGW
 //     GTEST_OS_WINDOWS_MOBILE   - Windows Mobile
+//     GTEST_OS_WINDOWS_PHONE    - Windows Phone
+//     GTEST_OS_WINDOWS_RT       - Windows Store App/WinRT
 //   GTEST_OS_ZOS      - z/OS
 //
 // Among the platforms, Cygwin, Linux, Max OS X, and Windows have the
@@ -212,22 +243,50 @@
 // googletestframework at googlegroups.com (patches for fixing them are
 // even more welcome!).
 //
-// Note that it is possible that none of the GTEST_OS_* macros are defined.
+// It is possible that none of the GTEST_OS_* macros are defined.
+
+// Feature-indicating macros
+// -------------------------
+//
+// Macros indicating which Google Test features are available (a macro
+// is defined to 1 if the corresponding feature is supported;
+// otherwise UNDEFINED -- it's never defined to 0.).  Google Test
+// defines these macros automatically.  Code outside Google Test MUST
+// NOT define them.
+//
+// These macros are public so that portable tests can be written.
+// Such tests typically surround code using a feature with an #if
+// which controls that code.  For example:
+//
+// #if GTEST_HAS_DEATH_TEST
+//   EXPECT_DEATH(DoSomethingDeadly());
+// #endif
 //
-// Macros indicating available Google Test features (defined to 1 if
-// the corresponding feature is supported; otherwise undefined):
 //   GTEST_HAS_COMBINE      - the Combine() function (for value-parameterized
 //                            tests)
 //   GTEST_HAS_DEATH_TEST   - death tests
 //   GTEST_HAS_PARAM_TEST   - value-parameterized tests
 //   GTEST_HAS_TYPED_TEST   - typed tests
 //   GTEST_HAS_TYPED_TEST_P - type-parameterized tests
+//   GTEST_IS_THREADSAFE    - Google Test is thread-safe.
 //   GTEST_USES_POSIX_RE    - enhanced POSIX regex is used. Do not confuse with
 //                            GTEST_HAS_POSIX_RE (see above) which users can
 //                            define themselves.
 //   GTEST_USES_SIMPLE_RE   - our own simple regex is used;
 //                            the above two are mutually exclusive.
 //   GTEST_CAN_COMPARE_NULL - accepts untyped NULL in EXPECT_EQ().
+
+// Misc public macros
+// ------------------
+//
+//   GTEST_FLAG(flag_name)  - references the variable corresponding to
+//                            the given Google Test flag.
+
+// Internal utilities
+// ------------------
+//
+// The following macros and utilities are for Google Test's INTERNAL
+// use only.  Code outside Google Test MUST NOT USE THEM DIRECTLY.
 //
 // Macros for basic C++ coding:
 //   GTEST_AMBIGUOUS_ELSE_BLOCKER_ - for disabling a gcc warning.
@@ -236,13 +295,18 @@
 //   GTEST_DISALLOW_ASSIGN_   - disables operator=.
 //   GTEST_DISALLOW_COPY_AND_ASSIGN_ - disables copy ctor and operator=.
 //   GTEST_MUST_USE_RESULT_   - declares that a function's result must be used.
+//   GTEST_INTENTIONAL_CONST_COND_PUSH_ - start code section where MSVC C4127 is
+//                                        suppressed (constant conditional).
+//   GTEST_INTENTIONAL_CONST_COND_POP_  - finish code section where MSVC C4127
+//                                        is suppressed.
+//
+// C++11 feature wrappers:
+//
+//   testing::internal::move  - portability wrapper for std::move.
 //
 // Synchronization:
 //   Mutex, MutexLock, ThreadLocal, GetThreadCount()
-//                  - synchronization primitives.
-//   GTEST_IS_THREADSAFE - defined to 1 to indicate that the above
-//                         synchronization primitives have real implementations
-//                         and Google Test is thread-safe; or 0 otherwise.
+//                            - synchronization primitives.
 //
 // Template meta programming:
 //   is_pointer     - as in TR1; needed on Symbian and IBM XL C/C++ only.
@@ -278,7 +342,6 @@
 //   BiggestInt     - the biggest signed integer type.
 //
 // Command-line utilities:
-//   GTEST_FLAG()       - references a flag.
 //   GTEST_DECLARE_*()  - declares a flag.
 //   GTEST_DEFINE_*()   - defines a flag.
 //   GetInjectableArgvs() - returns the command line as a vector of strings.
@@ -304,23 +367,49 @@
 # include <TargetConditionals.h>
 #endif
 
+#include <algorithm>  // NOLINT
 #include <iostream>  // NOLINT
 #include <sstream>  // NOLINT
 #include <string>  // NOLINT
+#include <utility>
+#include <vector>  // NOLINT
 
-#define GTEST_DEV_EMAIL_ "googletestframework@@googlegroups.com"
-#define GTEST_FLAG_PREFIX_ "gtest_"
-#define GTEST_FLAG_PREFIX_DASH_ "gtest-"
-#define GTEST_FLAG_PREFIX_UPPER_ "GTEST_"
-#define GTEST_NAME_ "Google Test"
-#define GTEST_PROJECT_URL_ "http://code.google.com/p/googletest/"
+// Copyright 2015, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// The Google C++ Testing Framework (Google Test)
+//
+// This header file defines the GTEST_OS_* macro.
+// It is separate from gtest-port.h so that custom/gtest-port.h can include it.
 
-// Determines the version of gcc that is used to compile this.
-#ifdef __GNUC__
-// 40302 means version 4.3.2.
-# define GTEST_GCC_VER_ \
-    (__GNUC__*10000 + __GNUC_MINOR__*100 + __GNUC_PATCHLEVEL__)
-#endif  // __GNUC__
+#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_ARCH_H_
+#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_ARCH_H_
 
 // Determines the platform on which Google Test is compiled.
 #define GTEST_OS_CYGWIN 0
@@ -329,6 +418,8 @@
 #define GTEST_OS_WINDOWS_MOBILE 0
 #define GTEST_OS_WINDOWS_MINGW 0
 #define GTEST_OS_WINDOWS_DESKTOP 0
+#define GTEST_OS_WINDOWS_PHONE 0
+#define GTEST_OS_WINDOWS_RT 0
 #define GTEST_OS_MAC 0
 #define GTEST_OS_LINUX 0
 #define GTEST_OS_LINUX_ANDROID 0
@@ -341,6 +432,7 @@
 #define GTEST_OS_QNX 0
 #define GTEST_OS_IOS 0
 #define GTEST_OS_IOS_SIMULATOR 0
+#define GTEST_OS_FREEBSD 0
 
 #ifdef __CYGWIN__
 # undef GTEST_OS_CYGWIN
@@ -357,6 +449,23 @@
 # elif defined(__MINGW__) || defined(__MINGW32__)
 #  undef GTEST_OS_WINDOWS_MINGW
 #  define GTEST_OS_WINDOWS_MINGW 1
+# elif defined(WINAPI_FAMILY)
+#  include <winapifamily.h>
+#  if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
+#   undef GTEST_OS_WINDOWS_DESKTOP
+#   define GTEST_OS_WINDOWS_DESKTOP 1
+#  elif WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP)
+#   undef GTEST_OS_WINDOWS_PHONE
+#   define GTEST_OS_WINDOWS_PHONE 1
+#  elif WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP)
+#   undef GTEST_OS_WINDOWS_RT
+#   define GTEST_OS_WINDOWS_RT 1
+#  else
+    // WINAPI_FAMILY defined but no known partition matched.
+    // Default to desktop.
+#   undef GTEST_OS_WINDOWS_DESKTOP
+#   define GTEST_OS_WINDOWS_DESKTOP 1
+#  endif
 # else
 #  undef GTEST_OS_WINDOWS_DESKTOP
 #  define GTEST_OS_WINDOWS_DESKTOP 1
@@ -372,6 +481,9 @@
 #   define GTEST_OS_IOS_SIMULATOR 1
 #  endif
 # endif
+#elif defined __FreeBSD__
+# undef GTEST_OS_FREEBSD
+# define GTEST_OS_FREEBSD 1
 #elif defined __linux__
 # undef GTEST_OS_LINUX
 # define GTEST_OS_LINUX 1
@@ -402,6 +514,121 @@
 # define GTEST_OS_QNX 1
 #endif  // __CYGWIN__
 
+#endif  // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_ARCH_H_
+// Copyright 2015, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Injection point for custom user configurations.
+// The following macros can be defined:
+//
+//   Flag related macros:
+//     GTEST_FLAG(flag_name)
+//     GTEST_USE_OWN_FLAGFILE_FLAG_  - Define to 0 when the system provides its
+//                                     own flagfile flag parsing.
+//     GTEST_DECLARE_bool_(name)
+//     GTEST_DECLARE_int32_(name)
+//     GTEST_DECLARE_string_(name)
+//     GTEST_DEFINE_bool_(name, default_val, doc)
+//     GTEST_DEFINE_int32_(name, default_val, doc)
+//     GTEST_DEFINE_string_(name, default_val, doc)
+//
+//   Test filtering:
+//     GTEST_TEST_FILTER_ENV_VAR_ - The name of an environment variable that
+//                                  will be used if --GTEST_FLAG(test_filter)
+//                                  is not provided.
+//
+//   Logging:
+//     GTEST_LOG_(severity)
+//     GTEST_CHECK_(condition)
+//     Functions LogToStderr() and FlushInfoLog() have to be provided too.
+//
+//   Threading:
+//     GTEST_HAS_NOTIFICATION_ - Enabled if Notification is already provided.
+//     GTEST_HAS_MUTEX_AND_THREAD_LOCAL_ - Enabled if Mutex and ThreadLocal are
+//                                         already provided.
+//     Must also provide GTEST_DECLARE_STATIC_MUTEX_(mutex) and
+//     GTEST_DEFINE_STATIC_MUTEX_(mutex)
+//
+//     GTEST_EXCLUSIVE_LOCK_REQUIRED_(locks)
+//     GTEST_LOCK_EXCLUDED_(locks)
+//
+// ** Custom implementation starts here **
+
+#ifndef GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PORT_H_
+#define GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PORT_H_
+
+#endif  // GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PORT_H_
+
+#ifndef GTEST_HAS_NOTIFICATION_
+#define GTEST_HAS_NOTIFICATION_ 0
+#endif
+#ifndef GTEST_HAS_MUTEX_AND_THREAD_LOCAL_
+#define GTEST_HAS_MUTEX_AND_THREAD_LOCAL_ 0
+#endif
+
+#if !defined(GTEST_DEV_EMAIL_)
+# define GTEST_DEV_EMAIL_ "googletestframework@@googlegroups.com"
+# define GTEST_FLAG_PREFIX_ "gtest_"
+# define GTEST_FLAG_PREFIX_DASH_ "gtest-"
+# define GTEST_FLAG_PREFIX_UPPER_ "GTEST_"
+# define GTEST_NAME_ "Google Test"
+# define GTEST_PROJECT_URL_ "https://github.com/google/googletest/"
+#endif  // !defined(GTEST_DEV_EMAIL_)
+
+#if !defined(GTEST_INIT_GOOGLE_TEST_NAME_)
+# define GTEST_INIT_GOOGLE_TEST_NAME_ "testing::InitGoogleTest"
+#endif  // !defined(GTEST_INIT_GOOGLE_TEST_NAME_)
+
+// Determines the version of gcc that is used to compile this.
+#ifdef __GNUC__
+// 40302 means version 4.3.2.
+# define GTEST_GCC_VER_ \
+    (__GNUC__*10000 + __GNUC_MINOR__*100 + __GNUC_PATCHLEVEL__)
+#endif  // __GNUC__
+
+// Macros for disabling Microsoft Visual C++ warnings.
+//
+//   GTEST_DISABLE_MSC_WARNINGS_PUSH_(4800 4385)
+//   /* code that triggers warnings C4800 and C4385 */
+//   GTEST_DISABLE_MSC_WARNINGS_POP_()
+#if defined(_MSC_VER) && _MSC_VER >= 1500
+# define GTEST_DISABLE_MSC_WARNINGS_PUSH_(warnings) \
+    __pragma(warning(push))                        \
+    __pragma(warning(disable: warnings))
+# define GTEST_DISABLE_MSC_WARNINGS_POP_()          \
+    __pragma(warning(pop))
+#else
+// Older versions of MSVC don't have __pragma.
+# define GTEST_DISABLE_MSC_WARNINGS_PUSH_(warnings)
+# define GTEST_DISABLE_MSC_WARNINGS_POP_()
+#endif
+
 #ifndef GTEST_LANG_CXX11
 // gcc and clang define __GXX_EXPERIMENTAL_CXX0X__ when
 // -std={c,gnu}++{0x,11} is passed.  The C++11 standard specifies a
@@ -415,19 +642,95 @@
 # endif
 #endif
 
+// Distinct from C++11 language support, some environments don't provide
+// proper C++11 library support. Notably, it's possible to build in
+// C++11 mode when targeting Mac OS X 10.6, which has an old libstdc++
+// with no C++11 support.
+//
+// libstdc++ has sufficient C++11 support as of GCC 4.6.0, __GLIBCXX__
+// 20110325, but maintenance releases in the 4.4 and 4.5 series followed
+// this date, so check for those versions by their date stamps.
+// https://gcc.gnu.org/onlinedocs/libstdc++/manual/abi.html#abi.versioning
+#if GTEST_LANG_CXX11 && \
+    (!defined(__GLIBCXX__) || ( \
+        __GLIBCXX__ >= 20110325ul &&  /* GCC >= 4.6.0 */ \
+        /* Blacklist of patch releases of older branches: */ \
+        __GLIBCXX__ != 20110416ul &&  /* GCC 4.4.6 */ \
+        __GLIBCXX__ != 20120313ul &&  /* GCC 4.4.7 */ \
+        __GLIBCXX__ != 20110428ul &&  /* GCC 4.5.3 */ \
+        __GLIBCXX__ != 20120702ul))   /* GCC 4.5.4 */
+# define GTEST_STDLIB_CXX11 1
+#else
+# define GTEST_STDLIB_CXX11 0
+#endif
+
+// Only use C++11 library features if the library provides them.
+#if GTEST_STDLIB_CXX11
+# define GTEST_HAS_STD_BEGIN_AND_END_ 1
+# define GTEST_HAS_STD_FORWARD_LIST_ 1
+# define GTEST_HAS_STD_FUNCTION_ 1
+# define GTEST_HAS_STD_INITIALIZER_LIST_ 1
+# define GTEST_HAS_STD_MOVE_ 1
+# define GTEST_HAS_STD_SHARED_PTR_ 1
+# define GTEST_HAS_STD_TYPE_TRAITS_ 1
+# define GTEST_HAS_STD_UNIQUE_PTR_ 1
+#else
+# define GTEST_HAS_STD_BEGIN_AND_END_ 0
+# define GTEST_HAS_STD_FORWARD_LIST_ 0
+# define GTEST_HAS_STD_FUNCTION_ 0
+# define GTEST_HAS_STD_INITIALIZER_LIST_ 0
+# define GTEST_HAS_STD_MOVE_ 0
+# define GTEST_HAS_STD_SHARED_PTR_ 0
+# define GTEST_HAS_STD_TYPE_TRAITS_ 0
+# define GTEST_HAS_STD_UNIQUE_PTR_ 0
+#endif
+
+// C++11 specifies that <tuple> provides std::tuple.
+// Some platforms still might not have it, however.
+#if GTEST_LANG_CXX11
+# define GTEST_HAS_STD_TUPLE_ 1
+# if defined(__clang__)
+// Inspired by http://clang.llvm.org/docs/LanguageExtensions.html#__has_include
+#  if defined(__has_include) && !__has_include(<tuple>)
+#   undef GTEST_HAS_STD_TUPLE_
+#  endif
+# elif defined(_MSC_VER)
+// Inspired by boost/config/stdlib/dinkumware.hpp
+#  if defined(_CPPLIB_VER) && _CPPLIB_VER < 520
+#   undef GTEST_HAS_STD_TUPLE_
+#  endif
+# elif defined(__GLIBCXX__)
+// Inspired by boost/config/stdlib/libstdcpp3.hpp,
+// http://gcc.gnu.org/gcc-4.2/changes.html and
+// http://gcc.gnu.org/onlinedocs/libstdc++/manual/bk01pt01ch01.html#manual.intro.status.standard.200x
+#  if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 2)
+#   undef GTEST_HAS_STD_TUPLE_
+#  endif
+# endif
+#else
+# define GTEST_HAS_STD_TUPLE_ 0
+#endif
+
 // Brings in definitions for functions used in the testing::internal::posix
 // namespace (read, write, close, chdir, isatty, stat). We do not currently
 // use them on Windows Mobile.
-#if !GTEST_OS_WINDOWS
+#if GTEST_OS_WINDOWS
+# if !GTEST_OS_WINDOWS_MOBILE
+#  include <direct.h>
+#  include <io.h>
+# endif
+// In order to avoid having to include <windows.h>, use forward declaration
+// assuming CRITICAL_SECTION is a typedef of _RTL_CRITICAL_SECTION.
+// This assumption is verified by
+// WindowsTypesTest.CRITICAL_SECTIONIs_RTL_CRITICAL_SECTION.
+struct _RTL_CRITICAL_SECTION;
+#else
 // This assumes that non-Windows OSes provide unistd.h. For OSes where this
 // is not the case, we need to include headers that provide the functions
 // mentioned above.
 # include <unistd.h>
 # include <strings.h>
-#elif !GTEST_OS_WINDOWS_MOBILE
-# include <direct.h>
-# include <io.h>
-#endif
+#endif  // GTEST_OS_WINDOWS
 
 #if GTEST_OS_LINUX_ANDROID
 // Used to define __ANDROID_API__ matching the target NDK API level.
@@ -444,7 +747,10 @@
 #endif
 #endif
 
-#if GTEST_HAS_POSIX_RE
+#if defined(GTEST_USES_PCRE) && GTEST_USES_PCRE
+// The appropriate headers have already been included.
+
+#elif GTEST_HAS_POSIX_RE
 
 // On some platforms, <regex.h> needs someone to define size_t, and
 // won't compile otherwise.  We can #include it here as we already
@@ -469,7 +775,7 @@
 # define GTEST_USES_SIMPLE_RE 1
 # define GTEST_USES_POSIX_RE  0
 
-#endif  // GTEST_HAS_POSIX_RE
+#endif  // GTEST_USES_PCRE
 
 #ifndef GTEST_HAS_EXCEPTIONS
 // The user didn't tell us whether exceptions are enabled, so we need
@@ -482,6 +788,15 @@
 #   define _HAS_EXCEPTIONS 1
 #  endif  // _HAS_EXCEPTIONS
 #  define GTEST_HAS_EXCEPTIONS _HAS_EXCEPTIONS
+# elif defined(__clang__)
+// clang defines __EXCEPTIONS iff exceptions are enabled before clang 220714,
+// but iff cleanups are enabled after that. In Obj-C++ files, there can be
+// cleanups for ObjC exceptions which also need cleanups, even if C++ exceptions
+// are disabled. clang has __has_feature(cxx_exceptions) which checks for C++
+// exceptions starting at clang r206352, but which checked for cleanups prior to
+// that. To reliably check for C++ exception availability with clang, check for
+// __EXCEPTIONS && __has_feature(cxx_exceptions).
+#  define GTEST_HAS_EXCEPTIONS (__EXCEPTIONS && __has_feature(cxx_exceptions))
 # elif defined(__GNUC__) && __EXCEPTIONS
 // gcc defines __EXCEPTIONS to 1 iff exceptions are enabled.
 #  define GTEST_HAS_EXCEPTIONS 1
@@ -607,13 +922,13 @@
 
 // Determines whether Google Test can use the pthreads library.
 #ifndef GTEST_HAS_PTHREAD
-// The user didn't tell us explicitly, so we assume pthreads support is
-// available on Linux and Mac.
+// The user didn't tell us explicitly, so we make reasonable assumptions about
+// which platforms have pthreads support.
 //
 // To disable threading support in Google Test, add -DGTEST_HAS_PTHREAD=0
 // to your compiler flags.
 # define GTEST_HAS_PTHREAD (GTEST_OS_LINUX || GTEST_OS_MAC || GTEST_OS_HPUX \
-    || GTEST_OS_QNX)
+    || GTEST_OS_QNX || GTEST_OS_FREEBSD || GTEST_OS_NACL)
 #endif  // GTEST_HAS_PTHREAD
 
 #if GTEST_HAS_PTHREAD
@@ -625,6 +940,15 @@
 # include <time.h>  // NOLINT
 #endif
 
+// Determines if hash_map/hash_set are available.
+// Only used for testing against those containers.
+#if !defined(GTEST_HAS_HASH_MAP_)
+# ifdef _MSC_VER
+#  define GTEST_HAS_HASH_MAP_ 1  // Indicates that hash_map is available.
+#  define GTEST_HAS_HASH_SET_ 1  // Indicates that hash_set is available.
+# endif  // _MSC_VER
+#endif  // !defined(GTEST_HAS_HASH_MAP_)
+
 // Determines whether Google Test can use tr1/tuple.  You can define
 // this macro to 0 to prevent Google Test from using tuple (any
 // feature depending on tuple with be disabled in this mode).
@@ -682,8 +1006,18 @@
 
 // To avoid conditional compilation everywhere, we make it
 // gtest-port.h's responsibility to #include the header implementing
-// tr1/tuple.
+// tuple.
+#if GTEST_HAS_STD_TUPLE_
+# include <tuple>  // IWYU pragma: export
+# define GTEST_TUPLE_NAMESPACE_ ::std
+#endif  // GTEST_HAS_STD_TUPLE_
+
+// We include tr1::tuple even if std::tuple is available to define printers for
+// them.
 #if GTEST_HAS_TR1_TUPLE
+# ifndef GTEST_TUPLE_NAMESPACE_
+#  define GTEST_TUPLE_NAMESPACE_ ::std::tr1
+# endif  // GTEST_TUPLE_NAMESPACE_
 
 # if GTEST_USE_OWN_TR1_TUPLE
 // This file was GENERATED by command:
@@ -741,6 +1075,14 @@
    private:
 #endif
 
+// Visual Studio 2010, 2012, and 2013 define symbols in std::tr1 that conflict
+// with our own definitions. Therefore using our own tuple does not work on
+// those compilers.
+#if defined(_MSC_VER) && _MSC_VER >= 1600  /* 1600 is Visual Studio 2010 */
+# error "gtest's tuple doesn't compile on Visual Studio 2010 or later. \
+GTEST_USE_OWN_TR1_TUPLE must be set to 0 on those compilers."
+#endif
+
 // GTEST_n_TUPLE_(T) is the type of an n-tuple.
 #define GTEST_0_TUPLE_(T) tuple<>
 #define GTEST_1_TUPLE_(T) tuple<T##0, void, void, void, void, void, void, \
@@ -1728,7 +2070,7 @@ using ::std::tuple_size;
 // This prevents <boost/tr1/detail/config.hpp>, which defines
 // BOOST_HAS_TR1_TUPLE, from being #included by Boost's <tuple>.
 #  define BOOST_TR1_DETAIL_CONFIG_HPP_INCLUDED
-#  include <tuple>
+#  include <tuple>  // IWYU pragma: export  // NOLINT
 
 # elif defined(__GNUC__) && (GTEST_GCC_VER_ >= 40000)
 // GCC 4.0+ implements tr1/tuple in the <tr1/tuple> header.  This does
@@ -1751,7 +2093,7 @@ using ::std::tuple_size;
 # else
 // If the compiler is not GCC 4.0+, we assume the user is using a
 // spec-conforming TR1 implementation.
-#  include <tuple>  // NOLINT
+#  include <tuple>  // IWYU pragma: export  // NOLINT
 # endif  // GTEST_USE_OWN_TR1_TUPLE
 
 #endif  // GTEST_HAS_TR1_TUPLE
@@ -1785,7 +2127,8 @@ using ::std::tuple_size;
 #ifndef GTEST_HAS_STREAM_REDIRECTION
 // By default, we assume that stream redirection is supported on all
 // platforms except known mobile ones.
-# if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_SYMBIAN
+# if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_SYMBIAN || \
+    GTEST_OS_WINDOWS_PHONE || GTEST_OS_WINDOWS_RT
 #  define GTEST_HAS_STREAM_REDIRECTION 0
 # else
 #  define GTEST_HAS_STREAM_REDIRECTION 1
@@ -1797,10 +2140,10 @@ using ::std::tuple_size;
 // abort() in a VC 7.1 application compiled as GUI in debug config
 // pops up a dialog window that cannot be suppressed programmatically.
 #if (GTEST_OS_LINUX || GTEST_OS_CYGWIN || GTEST_OS_SOLARIS || \
-     (GTEST_OS_MAC && !GTEST_OS_IOS) || GTEST_OS_IOS_SIMULATOR || \
+     (GTEST_OS_MAC && !GTEST_OS_IOS) || \
      (GTEST_OS_WINDOWS_DESKTOP && _MSC_VER >= 1400) || \
      GTEST_OS_WINDOWS_MINGW || GTEST_OS_AIX || GTEST_OS_HPUX || \
-     GTEST_OS_OPENBSD || GTEST_OS_QNX)
+     GTEST_OS_OPENBSD || GTEST_OS_QNX || GTEST_OS_FREEBSD)
 # define GTEST_HAS_DEATH_TEST 1
 # include <vector>  // NOLINT
 #else
@@ -1870,7 +2213,12 @@ using ::std::tuple_size;
 // compiler the variable/parameter does not have to be used.
 #if defined(__GNUC__) && !defined(COMPILER_ICC)
 # define GTEST_ATTRIBUTE_UNUSED_ __attribute__ ((unused))
-#else
+#elif defined(__clang__)
+# if __has_attribute(unused)
+#  define GTEST_ATTRIBUTE_UNUSED_ __attribute__ ((unused))
+# endif
+#endif
+#ifndef GTEST_ATTRIBUTE_UNUSED_
 # define GTEST_ATTRIBUTE_UNUSED_
 #endif
 
@@ -1896,6 +2244,19 @@ using ::std::tuple_size;
 # define GTEST_MUST_USE_RESULT_
 #endif  // __GNUC__ && (GTEST_GCC_VER_ >= 30400) && !COMPILER_ICC
 
+// MS C++ compiler emits warning when a conditional expression is compile time
+// constant. In some contexts this warning is false positive and needs to be
+// suppressed. Use the following two macros in such cases:
+//
+// GTEST_INTENTIONAL_CONST_COND_PUSH_()
+// while (true) {
+// GTEST_INTENTIONAL_CONST_COND_POP_()
+// }
+# define GTEST_INTENTIONAL_CONST_COND_PUSH_() \
+    GTEST_DISABLE_MSC_WARNINGS_PUSH_(4127)
+# define GTEST_INTENTIONAL_CONST_COND_POP_() \
+    GTEST_DISABLE_MSC_WARNINGS_POP_()
+
 // Determine whether the compiler supports Microsoft's Structured Exception
 // Handling.  This is supported by several Windows compilers but generally
 // does not exist on any other system.
@@ -1910,17 +2271,22 @@ using ::std::tuple_size;
 #  define GTEST_HAS_SEH 0
 # endif
 
+#define GTEST_IS_THREADSAFE \
+    (GTEST_HAS_MUTEX_AND_THREAD_LOCAL_ \
+     || (GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT) \
+     || GTEST_HAS_PTHREAD)
+
 #endif  // GTEST_HAS_SEH
 
 #ifdef _MSC_VER
-
 # if GTEST_LINKED_AS_SHARED_LIBRARY
 #  define GTEST_API_ __declspec(dllimport)
 # elif GTEST_CREATE_SHARED_LIBRARY
 #  define GTEST_API_ __declspec(dllexport)
 # endif
-
-#endif  // _MSC_VER
+#elif __GNUC__ >= 4 || defined(__clang__)
+# define GTEST_API_ __attribute__((visibility ("default")))
+#endif // _MSC_VER
 
 #ifndef GTEST_API_
 # define GTEST_API_ CV_EXPORTS
@@ -1940,10 +2306,58 @@ using ::std::tuple_size;
 # define GTEST_HAS_CXXABI_H_ 0
 #endif
 
+// A function level attribute to disable checking for use of uninitialized
+// memory when built with MemorySanitizer.
+#if defined(__clang__)
+# if __has_feature(memory_sanitizer)
+#  define GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_ \
+       __attribute__((no_sanitize_memory))
+# else
+#  define GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_
+# endif  // __has_feature(memory_sanitizer)
+#else
+# define GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_
+#endif  // __clang__
+
+// A function level attribute to disable AddressSanitizer instrumentation.
+#if defined(__clang__)
+# if __has_feature(address_sanitizer)
+#  define GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_ \
+       __attribute__((no_sanitize_address))
+# else
+#  define GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_
+# endif  // __has_feature(address_sanitizer)
+#else
+# define GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_
+#endif  // __clang__
+
+// A function level attribute to disable ThreadSanitizer instrumentation.
+#if defined(__clang__)
+# if __has_feature(thread_sanitizer)
+#  define GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_ \
+       __attribute__((no_sanitize_thread))
+# else
+#  define GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_
+# endif  // __has_feature(thread_sanitizer)
+#else
+# define GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_
+#endif  // __clang__
+
 namespace testing {
 
 class Message;
 
+#if defined(GTEST_TUPLE_NAMESPACE_)
+// Import tuple and friends into the ::testing namespace.
+// It is part of our interface, having them in ::testing allows us to change
+// their types as needed.
+using GTEST_TUPLE_NAMESPACE_::get;
+using GTEST_TUPLE_NAMESPACE_::make_tuple;
+using GTEST_TUPLE_NAMESPACE_::tuple;
+using GTEST_TUPLE_NAMESPACE_::tuple_size;
+using GTEST_TUPLE_NAMESPACE_::tuple_element;
+#endif  // defined(GTEST_TUPLE_NAMESPACE_)
+
 namespace internal {
 
 // A secret type that Google Test users don't know about.  It has no
@@ -1955,8 +2369,8 @@ class Secret;
 // expression is true. For example, you could use it to verify the
 // size of a static array:
 //
-//   GTEST_COMPILE_ASSERT_(ARRAYSIZE(content_type_names) == CONTENT_NUM_TYPES,
-//                         content_type_names_incorrect_size);
+//   GTEST_COMPILE_ASSERT_(GTEST_ARRAY_SIZE_(names) == NUM_NAMES,
+//                         names_incorrect_size);
 //
 // or to make sure a struct is smaller than a certain size:
 //
@@ -1966,16 +2380,22 @@ class Secret;
 // the expression is false, most compilers will issue a warning/error
 // containing the name of the variable.
 
+#if GTEST_LANG_CXX11
+# define GTEST_COMPILE_ASSERT_(expr, msg) static_assert(expr, #msg)
+#else  // !GTEST_LANG_CXX11
 template <bool>
-struct CompileAssert {
+  struct CompileAssert {
 };
 
-#define GTEST_COMPILE_ASSERT_(expr, msg) \
+# define GTEST_COMPILE_ASSERT_(expr, msg) \
   typedef ::testing::internal::CompileAssert<(static_cast<bool>(expr))> \
       msg[static_cast<bool>(expr) ? 1 : -1] GTEST_ATTRIBUTE_UNUSED_
+#endif  // !GTEST_LANG_CXX11
 
 // Implementation details of GTEST_COMPILE_ASSERT_:
 //
+// (In C++11, we simply use static_assert instead of the following)
+//
 // - GTEST_COMPILE_ASSERT_ works by defining an array type that has -1
 //   elements (and thus is invalid) when the expression is false.
 //
@@ -2022,7 +2442,12 @@ template <typename T1, typename T2>
 struct StaticAssertTypeEqHelper;
 
 template <typename T>
-struct StaticAssertTypeEqHelper<T, T> {};
+struct StaticAssertTypeEqHelper<T, T> {
+  enum { value = true };
+};
+
+// Evaluates to the number of elements in 'array'.
+#define GTEST_ARRAY_SIZE_(array) (sizeof(array) / sizeof(array[0]))
 
 #if GTEST_HAS_GLOBAL_STRING
 typedef ::string string;
@@ -2040,6 +2465,9 @@ typedef ::std::wstring wstring;
 // returns 'condition'.
 GTEST_API_ bool IsTrue(bool condition);
 
+template <typename T> class scoped_ptr;
+template <typename T> static void swap(scoped_ptr<T>& a, scoped_ptr<T>& b);
+
 // Defines scoped_ptr.
 
 // This implementation of scoped_ptr is PARTIAL - it only contains
@@ -2071,12 +2499,20 @@ class scoped_ptr {
     }
   }
 
+  friend void swap<T>(scoped_ptr<T>& a, scoped_ptr<T>& b);
+
  private:
   T* ptr_;
 
   GTEST_DISALLOW_COPY_AND_ASSIGN_(scoped_ptr);
 };
 
+template <typename T>
+static void swap(scoped_ptr<T>& a, scoped_ptr<T>& b) {
+  using std::swap;
+  swap(a.ptr_, b.ptr_);
+}
+
 // Defines RE.
 
 // A simple C++ wrapper for <regex.h>.  It uses the POSIX Extended
@@ -2194,13 +2630,18 @@ class GTEST_API_ GTestLog {
   GTEST_DISALLOW_COPY_AND_ASSIGN_(GTestLog);
 };
 
-#define GTEST_LOG_(severity) \
+#if !defined(GTEST_LOG_)
+
+# define GTEST_LOG_(severity) \
     ::testing::internal::GTestLog(::testing::internal::GTEST_##severity, \
                                   __FILE__, __LINE__).GetStream()
 
 inline void LogToStderr() {}
 inline void FlushInfoLog() { fflush(NULL); }
 
+#endif  // !defined(GTEST_LOG_)
+
+#if !defined(GTEST_CHECK_)
 // INTERNAL IMPLEMENTATION - DO NOT USE.
 //
 // GTEST_CHECK_ is an all-mode assert. It aborts the program if the condition
@@ -2215,12 +2656,13 @@ inline void FlushInfoLog() { fflush(NULL); }
 //    condition itself, plus additional message streamed into it, if any,
 //    and then it aborts the program. It aborts the program irrespective of
 //    whether it is built in the debug mode or not.
-#define GTEST_CHECK_(condition) \
+# define GTEST_CHECK_(condition) \
     GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
     if (::testing::internal::IsTrue(condition)) \
       ; \
     else \
       GTEST_LOG_(FATAL) << "Condition " #condition " failed. "
+#endif  // !defined(GTEST_CHECK_)
 
 // An all-mode assert to verify that the given POSIX-style function
 // call returns 0 (indicating success).  Known limitation: this
@@ -2232,6 +2674,15 @@ inline void FlushInfoLog() { fflush(NULL); }
     GTEST_LOG_(FATAL) << #posix_call << "failed with error " \
                       << gtest_error
 
+#if GTEST_HAS_STD_MOVE_
+using std::move;
+#else  // GTEST_HAS_STD_MOVE_
+template <typename T>
+const T& move(const T& t) {
+  return t;
+}
+#endif  // GTEST_HAS_STD_MOVE_
+
 // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
 //
 // Use ImplicitCast_ as a safe version of static_cast for upcasting in
@@ -2282,7 +2733,9 @@ inline To DownCast_(From* f) {  // so we only accept pointers
   // for compile-time type checking, and has no overhead in an
   // optimized build at run-time, as it will be optimized away
   // completely.
+  GTEST_INTENTIONAL_CONST_COND_PUSH_()
   if (false) {
+  GTEST_INTENTIONAL_CONST_COND_POP_()
     const To to = NULL;
     ::testing::internal::ImplicitCast_<From*>(to);
   }
@@ -2303,6 +2756,11 @@ template <class Derived, class Base>
 Derived* CheckedDowncastToActualType(Base* base) {
 #if GTEST_HAS_RTTI
   GTEST_CHECK_(typeid(*base) == typeid(Derived));
+#endif
+
+#if defined(GTEST_HAS_DOWNCAST_) && GTEST_HAS_DOWNCAST_
+  return ::down_cast<Derived*>(base);
+#elif GTEST_HAS_RTTI
   return dynamic_cast<Derived*>(base);  // NOLINT
 #else
   return static_cast<Derived*>(base);  // Poor man's downcast.
@@ -2324,6 +2782,17 @@ GTEST_API_ std::string GetCapturedStderr();
 
 #endif  // GTEST_HAS_STREAM_REDIRECTION
 
+// Returns a path to temporary directory.
+GTEST_API_ std::string TempDir();
+
+// Returns the size (in bytes) of a file.
+GTEST_API_ size_t GetFileSize(FILE* file);
+
+// Reads the entire content of a file as a string.
+GTEST_API_ std::string ReadEntireFile(FILE* file);
+
+// All command line arguments.
+GTEST_API_ const ::std::vector<testing::internal::string>& GetArgvs();
 
 #if GTEST_HAS_DEATH_TEST
 
@@ -2331,18 +2800,15 @@ const ::std::vector<testing::internal::string>& GetInjectableArgvs();
 void SetInjectableArgvs(const ::std::vector<testing::internal::string>*
                              new_argvs);
 
-// A copy of all command line arguments.  Set by InitGoogleTest().
-extern ::std::vector<testing::internal::string> g_argvs;
 
 #endif  // GTEST_HAS_DEATH_TEST
 
 // Defines synchronization primitives.
-
-#if GTEST_HAS_PTHREAD
-
-// Sleeps for (roughly) n milli-seconds.  This function is only for
-// testing Google Test's own constructs.  Don't use it in user tests,
-// either directly or indirectly.
+#if GTEST_IS_THREADSAFE
+# if GTEST_HAS_PTHREAD
+// Sleeps for (roughly) n milliseconds.  This function is only for testing
+// Google Test's own constructs.  Don't use it in user tests, either
+// directly or indirectly.
 inline void SleepMilliseconds(int n) {
   const timespec time = {
     0,                  // 0 seconds.
@@ -2350,7 +2816,13 @@ inline void SleepMilliseconds(int n) {
   };
   nanosleep(&time, NULL);
 }
+# endif  // GTEST_HAS_PTHREAD
+
+# if GTEST_HAS_NOTIFICATION_
+// Notification has already been imported into the namespace.
+// Nothing to do here.
 
+# elif GTEST_HAS_PTHREAD
 // Allows a controller thread to pause execution of newly created
 // threads until notified.  Instances of this class must be created
 // and destroyed in the controller thread.
@@ -2394,6 +2866,62 @@ class Notification {
   GTEST_DISALLOW_COPY_AND_ASSIGN_(Notification);
 };
 
+# elif GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT
+
+GTEST_API_ void SleepMilliseconds(int n);
+
+// Provides leak-safe Windows kernel handle ownership.
+// Used in death tests and in threading support.
+class GTEST_API_ AutoHandle {
+ public:
+  // Assume that Win32 HANDLE type is equivalent to void*. Doing so allows us to
+  // avoid including <windows.h> in this header file. Including <windows.h> is
+  // undesirable because it defines a lot of symbols and macros that tend to
+  // conflict with client code. This assumption is verified by
+  // WindowsTypesTest.HANDLEIsVoidStar.
+  typedef void* Handle;
+  AutoHandle();
+  explicit AutoHandle(Handle handle);
+
+  ~AutoHandle();
+
+  Handle Get() const;
+  void Reset();
+  void Reset(Handle handle);
+
+ private:
+  // Returns true iff the handle is a valid handle object that can be closed.
+  bool IsCloseable() const;
+
+  Handle handle_;
+
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(AutoHandle);
+};
+
+// Allows a controller thread to pause execution of newly created
+// threads until notified.  Instances of this class must be created
+// and destroyed in the controller thread.
+//
+// This class is only for testing Google Test's own constructs. Do not
+// use it in user tests, either directly or indirectly.
+class GTEST_API_ Notification {
+ public:
+  Notification();
+  void Notify();
+  void WaitForNotification();
+
+ private:
+  AutoHandle event_;
+
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(Notification);
+};
+# endif  // GTEST_HAS_NOTIFICATION_
+
+// On MinGW, we can have both GTEST_OS_WINDOWS and GTEST_HAS_PTHREAD
+// defined, but we don't want to use MinGW's pthreads implementation, which
+// has conformance problems with some versions of the POSIX standard.
+# if GTEST_HAS_PTHREAD && !GTEST_OS_WINDOWS_MINGW
+
 // As a C-function, ThreadFuncWithCLinkage cannot be templated itself.
 // Consequently, it cannot select a correct instantiation of ThreadWithParam
 // in order to call its Run(). Introducing ThreadWithParamBase as a
@@ -2431,66 +2959,332 @@ extern "C" inline void* ThreadFuncWithCLinkage(void* thread) {
 template <typename T>
 class ThreadWithParam : public ThreadWithParamBase {
  public:
-  typedef void (*UserThreadFunc)(T);
+  typedef void UserThreadFunc(T);
+
+  ThreadWithParam(UserThreadFunc* func, T param, Notification* thread_can_start)
+      : func_(func),
+        param_(param),
+        thread_can_start_(thread_can_start),
+        finished_(false) {
+    ThreadWithParamBase* const base = this;
+    // The thread can be created only after all fields except thread_
+    // have been initialized.
+    GTEST_CHECK_POSIX_SUCCESS_(
+        pthread_create(&thread_, 0, &ThreadFuncWithCLinkage, base));
+  }
+  ~ThreadWithParam() { Join(); }
+
+  void Join() {
+    if (!finished_) {
+      GTEST_CHECK_POSIX_SUCCESS_(pthread_join(thread_, 0));
+      finished_ = true;
+    }
+  }
+
+  virtual void Run() {
+    if (thread_can_start_ != NULL)
+      thread_can_start_->WaitForNotification();
+    func_(param_);
+  }
+
+ private:
+  UserThreadFunc* const func_;  // User-supplied thread function.
+  const T param_;  // User-supplied parameter to the thread function.
+  // When non-NULL, used to block execution until the controller thread
+  // notifies.
+  Notification* const thread_can_start_;
+  bool finished_;  // true iff we know that the thread function has finished.
+  pthread_t thread_;  // The native thread object.
+
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadWithParam);
+};
+# endif  // !GTEST_OS_WINDOWS && GTEST_HAS_PTHREAD ||
+         // GTEST_HAS_MUTEX_AND_THREAD_LOCAL_
+
+# if GTEST_HAS_MUTEX_AND_THREAD_LOCAL_
+// Mutex and ThreadLocal have already been imported into the namespace.
+// Nothing to do here.
+
+# elif GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT
+
+// Mutex implements mutex on Windows platforms.  It is used in conjunction
+// with class MutexLock:
+//
+//   Mutex mutex;
+//   ...
+//   MutexLock lock(&mutex);  // Acquires the mutex and releases it at the
+//                            // end of the current scope.
+//
+// A static Mutex *must* be defined or declared using one of the following
+// macros:
+//   GTEST_DEFINE_STATIC_MUTEX_(g_some_mutex);
+//   GTEST_DECLARE_STATIC_MUTEX_(g_some_mutex);
+//
+// (A non-static Mutex is defined/declared in the usual way).
+class GTEST_API_ Mutex {
+ public:
+  enum MutexType { kStatic = 0, kDynamic = 1 };
+  // We rely on kStaticMutex being 0 as it is to what the linker initializes
+  // type_ in static mutexes.  critical_section_ will be initialized lazily
+  // in ThreadSafeLazyInit().
+  enum StaticConstructorSelector { kStaticMutex = 0 };
+
+  // This constructor intentionally does nothing.  It relies on type_ being
+  // statically initialized to 0 (effectively setting it to kStatic) and on
+  // ThreadSafeLazyInit() to lazily initialize the rest of the members.
+  explicit Mutex(StaticConstructorSelector /*dummy*/) {}
+
+  Mutex();
+  ~Mutex();
+
+  void Lock();
+
+  void Unlock();
+
+  // Does nothing if the current thread holds the mutex. Otherwise, crashes
+  // with high probability.
+  void AssertHeld();
+
+ private:
+  // Initializes owner_thread_id_ and critical_section_ in static mutexes.
+  void ThreadSafeLazyInit();
+
+  // Per http://blogs.msdn.com/b/oldnewthing/archive/2004/02/23/78395.aspx,
+  // we assume that 0 is an invalid value for thread IDs.
+  unsigned int owner_thread_id_;
+
+  // For static mutexes, we rely on these members being initialized to zeros
+  // by the linker.
+  MutexType type_;
+  long critical_section_init_phase_;  // NOLINT
+  _RTL_CRITICAL_SECTION* critical_section_;
+
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(Mutex);
+};
+
+# define GTEST_DECLARE_STATIC_MUTEX_(mutex) \
+    extern ::testing::internal::Mutex mutex
+
+# define GTEST_DEFINE_STATIC_MUTEX_(mutex) \
+    ::testing::internal::Mutex mutex(::testing::internal::Mutex::kStaticMutex)
+
+// We cannot name this class MutexLock because the ctor declaration would
+// conflict with a macro named MutexLock, which is defined on some
+// platforms. That macro is used as a defensive measure to prevent against
+// inadvertent misuses of MutexLock like "MutexLock(&mu)" rather than
+// "MutexLock l(&mu)".  Hence the typedef trick below.
+class GTestMutexLock {
+ public:
+  explicit GTestMutexLock(Mutex* mutex)
+      : mutex_(mutex) { mutex_->Lock(); }
+
+  ~GTestMutexLock() { mutex_->Unlock(); }
+
+ private:
+  Mutex* const mutex_;
+
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(GTestMutexLock);
+};
+
+typedef GTestMutexLock MutexLock;
+
+// Base class for ValueHolder<T>.  Allows a caller to hold and delete a value
+// without knowing its type.
+class ThreadLocalValueHolderBase {
+ public:
+  virtual ~ThreadLocalValueHolderBase() {}
+};
+
+// Provides a way for a thread to send notifications to a ThreadLocal
+// regardless of its parameter type.
+class ThreadLocalBase {
+ public:
+  // Creates a new ValueHolder<T> object holding a default value passed to
+  // this ThreadLocal<T>'s constructor and returns it.  It is the caller's
+  // responsibility not to call this when the ThreadLocal<T> instance already
+  // has a value on the current thread.
+  virtual ThreadLocalValueHolderBase* NewValueForCurrentThread() const = 0;
+
+ protected:
+  ThreadLocalBase() {}
+  virtual ~ThreadLocalBase() {}
+
+ private:
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadLocalBase);
+};
+
+// Maps a thread to a set of ThreadLocals that have values instantiated on that
+// thread and notifies them when the thread exits.  A ThreadLocal instance is
+// expected to persist until all threads it has values on have terminated.
+class GTEST_API_ ThreadLocalRegistry {
+ public:
+  // Registers thread_local_instance as having value on the current thread.
+  // Returns a value that can be used to identify the thread from other threads.
+  static ThreadLocalValueHolderBase* GetValueOnCurrentThread(
+      const ThreadLocalBase* thread_local_instance);
+
+  // Invoked when a ThreadLocal instance is destroyed.
+  static void OnThreadLocalDestroyed(
+      const ThreadLocalBase* thread_local_instance);
+};
+
+class GTEST_API_ ThreadWithParamBase {
+ public:
+  void Join();
+
+ protected:
+  class Runnable {
+   public:
+    virtual ~Runnable() {}
+    virtual void Run() = 0;
+  };
+
+  ThreadWithParamBase(Runnable *runnable, Notification* thread_can_start);
+  virtual ~ThreadWithParamBase();
+
+ private:
+  AutoHandle thread_;
+};
+
+// Helper class for testing Google Test's multi-threading constructs.
+template <typename T>
+class ThreadWithParam : public ThreadWithParamBase {
+ public:
+  typedef void UserThreadFunc(T);
+
+  ThreadWithParam(UserThreadFunc* func, T param, Notification* thread_can_start)
+      : ThreadWithParamBase(new RunnableImpl(func, param), thread_can_start) {
+  }
+  virtual ~ThreadWithParam() {}
+
+ private:
+  class RunnableImpl : public Runnable {
+   public:
+    RunnableImpl(UserThreadFunc* func, T param)
+        : func_(func),
+          param_(param) {
+    }
+    virtual ~RunnableImpl() {}
+    virtual void Run() {
+      func_(param_);
+    }
+
+   private:
+    UserThreadFunc* const func_;
+    const T param_;
+
+    GTEST_DISALLOW_COPY_AND_ASSIGN_(RunnableImpl);
+  };
+
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadWithParam);
+};
+
+// Implements thread-local storage on Windows systems.
+//
+//   // Thread 1
+//   ThreadLocal<int> tl(100);  // 100 is the default value for each thread.
+//
+//   // Thread 2
+//   tl.set(150);  // Changes the value for thread 2 only.
+//   EXPECT_EQ(150, tl.get());
+//
+//   // Thread 1
+//   EXPECT_EQ(100, tl.get());  // In thread 1, tl has the original value.
+//   tl.set(200);
+//   EXPECT_EQ(200, tl.get());
+//
+// The template type argument T must have a public copy constructor.
+// In addition, the default ThreadLocal constructor requires T to have
+// a public default constructor.
+//
+// The users of a TheadLocal instance have to make sure that all but one
+// threads (including the main one) using that instance have exited before
+// destroying it. Otherwise, the per-thread objects managed for them by the
+// ThreadLocal instance are not guaranteed to be destroyed on all platforms.
+//
+// Google Test only uses global ThreadLocal objects.  That means they
+// will die after main() has returned.  Therefore, no per-thread
+// object managed by Google Test will be leaked as long as all threads
+// using Google Test have exited when main() returns.
+template <typename T>
+class ThreadLocal : public ThreadLocalBase {
+ public:
+  ThreadLocal() : default_factory_(new DefaultValueHolderFactory()) {}
+  explicit ThreadLocal(const T& value)
+      : default_factory_(new InstanceValueHolderFactory(value)) {}
+
+  ~ThreadLocal() { ThreadLocalRegistry::OnThreadLocalDestroyed(this); }
+
+  T* pointer() { return GetOrCreateValue(); }
+  const T* pointer() const { return GetOrCreateValue(); }
+  const T& get() const { return *pointer(); }
+  void set(const T& value) { *pointer() = value; }
+
+ private:
+  // Holds a value of T.  Can be deleted via its base class without the caller
+  // knowing the type of T.
+  class ValueHolder : public ThreadLocalValueHolderBase {
+   public:
+    ValueHolder() : value_() {}
+    explicit ValueHolder(const T& value) : value_(value) {}
+
+    T* pointer() { return &value_; }
+
+   private:
+    T value_;
+    GTEST_DISALLOW_COPY_AND_ASSIGN_(ValueHolder);
+  };
 
-  ThreadWithParam(
-      UserThreadFunc func, T param, Notification* thread_can_start)
-      : func_(func),
-        param_(param),
-        thread_can_start_(thread_can_start),
-        finished_(false) {
-    ThreadWithParamBase* const base = this;
-    // The thread can be created only after all fields except thread_
-    // have been initialized.
-    GTEST_CHECK_POSIX_SUCCESS_(
-        pthread_create(&thread_, 0, &ThreadFuncWithCLinkage, base));
-  }
-  ~ThreadWithParam() { Join(); }
 
-  void Join() {
-    if (!finished_) {
-      GTEST_CHECK_POSIX_SUCCESS_(pthread_join(thread_, 0));
-      finished_ = true;
-    }
+  T* GetOrCreateValue() const {
+    return static_cast<ValueHolder*>(
+        ThreadLocalRegistry::GetValueOnCurrentThread(this))->pointer();
   }
 
-  virtual void Run() {
-    if (thread_can_start_ != NULL)
-      thread_can_start_->WaitForNotification();
-    func_(param_);
+  virtual ThreadLocalValueHolderBase* NewValueForCurrentThread() const {
+    return default_factory_->MakeNewHolder();
   }
 
- private:
-  const UserThreadFunc func_;  // User-supplied thread function.
-  const T param_;  // User-supplied parameter to the thread function.
-  // When non-NULL, used to block execution until the controller thread
-  // notifies.
-  Notification* const thread_can_start_;
-  bool finished_;  // true iff we know that the thread function has finished.
-  pthread_t thread_;  // The native thread object.
+  class ValueHolderFactory {
+   public:
+    ValueHolderFactory() {}
+    virtual ~ValueHolderFactory() {}
+    virtual ValueHolder* MakeNewHolder() const = 0;
 
-  GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadWithParam);
+   private:
+    GTEST_DISALLOW_COPY_AND_ASSIGN_(ValueHolderFactory);
+  };
+
+  class DefaultValueHolderFactory : public ValueHolderFactory {
+   public:
+    DefaultValueHolderFactory() {}
+    virtual ValueHolder* MakeNewHolder() const { return new ValueHolder(); }
+
+   private:
+    GTEST_DISALLOW_COPY_AND_ASSIGN_(DefaultValueHolderFactory);
+  };
+
+  class InstanceValueHolderFactory : public ValueHolderFactory {
+   public:
+    explicit InstanceValueHolderFactory(const T& value) : value_(value) {}
+    virtual ValueHolder* MakeNewHolder() const {
+      return new ValueHolder(value_);
+    }
+
+   private:
+    const T value_;  // The value for each thread.
+
+    GTEST_DISALLOW_COPY_AND_ASSIGN_(InstanceValueHolderFactory);
+  };
+
+  scoped_ptr<ValueHolderFactory> default_factory_;
+
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadLocal);
 };
 
-// MutexBase and Mutex implement mutex on pthreads-based platforms. They
-// are used in conjunction with class MutexLock:
-//
-//   Mutex mutex;
-//   ...
-//   MutexLock lock(&mutex);  // Acquires the mutex and releases it at the end
-//                            // of the current scope.
-//
-// MutexBase implements behavior for both statically and dynamically
-// allocated mutexes.  Do not use MutexBase directly.  Instead, write
-// the following to define a static mutex:
-//
-//   GTEST_DEFINE_STATIC_MUTEX_(g_some_mutex);
-//
-// You can forward declare a static mutex like this:
-//
-//   GTEST_DECLARE_STATIC_MUTEX_(g_some_mutex);
-//
-// To create a dynamic mutex, just define an object of type Mutex.
+# elif GTEST_HAS_PTHREAD
+
+// MutexBase and Mutex implement mutex on pthreads-based platforms.
 class MutexBase {
  public:
   // Acquires this mutex.
@@ -2535,17 +3329,12 @@ class MutexBase {
 };
 
 // Forward-declares a static mutex.
-# define GTEST_DECLARE_STATIC_MUTEX_(mutex) \
-    extern ::testing::internal::MutexBase mutex
+#  define GTEST_DECLARE_STATIC_MUTEX_(mutex) \
+     extern ::testing::internal::MutexBase mutex
 
 // Defines and statically (i.e. at link time) initializes a static mutex.
-// The initialization list here does not explicitly initialize each field,
-// instead relying on default initialization for the unspecified fields. In
-// particular, the owner_ field (a pthread_t) is not explicitly initialized.
-// This allows initialization to work whether pthread_t is a scalar or struct.
-// The flag -Wmissing-field-initializers must not be specified for this to work.
-# define GTEST_DEFINE_STATIC_MUTEX_(mutex) \
-    ::testing::internal::MutexBase mutex = { PTHREAD_MUTEX_INITIALIZER, false }
+#  define GTEST_DEFINE_STATIC_MUTEX_(mutex) \
+     ::testing::internal::MutexBase mutex = { PTHREAD_MUTEX_INITIALIZER, false, pthread_t() }
 
 // The Mutex class can only be used for mutexes created at runtime. It
 // shares its API with MutexBase otherwise.
@@ -2563,9 +3352,11 @@ class Mutex : public MutexBase {
   GTEST_DISALLOW_COPY_AND_ASSIGN_(Mutex);
 };
 
-// We cannot name this class MutexLock as the ctor declaration would
+// We cannot name this class MutexLock because the ctor declaration would
 // conflict with a macro named MutexLock, which is defined on some
-// platforms.  Hence the typedef trick below.
+// platforms. That macro is used as a defensive measure to prevent against
+// inadvertent misuses of MutexLock like "MutexLock(&mu)" rather than
+// "MutexLock l(&mu)".  Hence the typedef trick below.
 class GTestMutexLock {
  public:
   explicit GTestMutexLock(MutexBase* mutex)
@@ -2599,41 +3390,14 @@ extern "C" inline void DeleteThreadLocalValue(void* value_holder) {
 }
 
 // Implements thread-local storage on pthreads-based systems.
-//
-//   // Thread 1
-//   ThreadLocal<int> tl(100);  // 100 is the default value for each thread.
-//
-//   // Thread 2
-//   tl.set(150);  // Changes the value for thread 2 only.
-//   EXPECT_EQ(150, tl.get());
-//
-//   // Thread 1
-//   EXPECT_EQ(100, tl.get());  // In thread 1, tl has the original value.
-//   tl.set(200);
-//   EXPECT_EQ(200, tl.get());
-//
-// The template type argument T must have a public copy constructor.
-// In addition, the default ThreadLocal constructor requires T to have
-// a public default constructor.
-//
-// An object managed for a thread by a ThreadLocal instance is deleted
-// when the thread exits.  Or, if the ThreadLocal instance dies in
-// that thread, when the ThreadLocal dies.  It's the user's
-// responsibility to ensure that all other threads using a ThreadLocal
-// have exited when it dies, or the per-thread objects for those
-// threads will not be deleted.
-//
-// Google Test only uses global ThreadLocal objects.  That means they
-// will die after main() has returned.  Therefore, no per-thread
-// object managed by Google Test will be leaked as long as all threads
-// using Google Test have exited when main() returns.
 template <typename T>
 class ThreadLocal {
  public:
-  ThreadLocal() : key_(CreateKey()),
-                  default_() {}
-  explicit ThreadLocal(const T& value) : key_(CreateKey()),
-                                         default_(value) {}
+  ThreadLocal()
+      : key_(CreateKey()), default_factory_(new DefaultValueHolderFactory()) {}
+  explicit ThreadLocal(const T& value)
+      : key_(CreateKey()),
+        default_factory_(new InstanceValueHolderFactory(value)) {}
 
   ~ThreadLocal() {
     // Destroys the managed object for the current thread, if any.
@@ -2653,6 +3417,7 @@ class ThreadLocal {
   // Holds a value of type T.
   class ValueHolder : public ThreadLocalValueHolderBase {
    public:
+    ValueHolder() : value_() {}
     explicit ValueHolder(const T& value) : value_(value) {}
 
     T* pointer() { return &value_; }
@@ -2678,22 +3443,54 @@ class ThreadLocal {
       return CheckedDowncastToActualType<ValueHolder>(holder)->pointer();
     }
 
-    ValueHolder* const new_holder = new ValueHolder(default_);
+    ValueHolder* const new_holder = default_factory_->MakeNewHolder();
     ThreadLocalValueHolderBase* const holder_base = new_holder;
     GTEST_CHECK_POSIX_SUCCESS_(pthread_setspecific(key_, holder_base));
     return new_holder->pointer();
   }
 
+  class ValueHolderFactory {
+   public:
+    ValueHolderFactory() {}
+    virtual ~ValueHolderFactory() {}
+    virtual ValueHolder* MakeNewHolder() const = 0;
+
+   private:
+    GTEST_DISALLOW_COPY_AND_ASSIGN_(ValueHolderFactory);
+  };
+
+  class DefaultValueHolderFactory : public ValueHolderFactory {
+   public:
+    DefaultValueHolderFactory() {}
+    virtual ValueHolder* MakeNewHolder() const { return new ValueHolder(); }
+
+   private:
+    GTEST_DISALLOW_COPY_AND_ASSIGN_(DefaultValueHolderFactory);
+  };
+
+  class InstanceValueHolderFactory : public ValueHolderFactory {
+   public:
+    explicit InstanceValueHolderFactory(const T& value) : value_(value) {}
+    virtual ValueHolder* MakeNewHolder() const {
+      return new ValueHolder(value_);
+    }
+
+   private:
+    const T value_;  // The value for each thread.
+
+    GTEST_DISALLOW_COPY_AND_ASSIGN_(InstanceValueHolderFactory);
+  };
+
   // A key pthreads uses for looking up per-thread values.
   const pthread_key_t key_;
-  const T default_;  // The default value for each thread.
+  scoped_ptr<ValueHolderFactory> default_factory_;
 
   GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadLocal);
 };
 
-# define GTEST_IS_THREADSAFE 1
+# endif  // GTEST_HAS_MUTEX_AND_THREAD_LOCAL_
 
-#else  // GTEST_HAS_PTHREAD
+#else  // GTEST_IS_THREADSAFE
 
 // A dummy implementation of synchronization primitives (mutex, lock,
 // and thread-local variable).  Necessary for compiling Google Test where
@@ -2713,6 +3510,11 @@ class Mutex {
 
 # define GTEST_DEFINE_STATIC_MUTEX_(mutex) ::testing::internal::Mutex mutex
 
+// We cannot name this class MutexLock because the ctor declaration would
+// conflict with a macro named MutexLock, which is defined on some
+// platforms. That macro is used as a defensive measure to prevent against
+// inadvertent misuses of MutexLock like "MutexLock(&mu)" rather than
+// "MutexLock l(&mu)".  Hence the typedef trick below.
 class GTestMutexLock {
  public:
   explicit GTestMutexLock(Mutex*) {}  // NOLINT
@@ -2733,11 +3535,7 @@ class ThreadLocal {
   T value_;
 };
 
-// The above synchronization primitives have dummy implementations.
-// Therefore Google Test is not thread-safe.
-# define GTEST_IS_THREADSAFE 0
-
-#endif  // GTEST_HAS_PTHREAD
+#endif  // GTEST_IS_THREADSAFE
 
 // Returns the number of threads running in the process, or 0 to indicate that
 // we cannot detect it.
@@ -2847,6 +3645,13 @@ inline char ToUpper(char ch) {
   return static_cast<char>(toupper(static_cast<unsigned char>(ch)));
 }
 
+inline std::string StripTrailingSpaces(std::string str) {
+  std::string::iterator it = str.end();
+  while (it != str.begin() && IsSpace(*--it))
+    it = str.erase(it);
+  return str;
+}
+
 // The testing::internal::posix namespace holds wrappers for common
 // POSIX functions.  These wrappers hide the differences between
 // Windows/MSVC and POSIX systems.  Since some compilers define these
@@ -2910,11 +3715,7 @@ inline bool IsDir(const StatStruct& st) { return S_ISDIR(st.st_mode); }
 
 // Functions deprecated by MSVC 8.0.
 
-#ifdef _MSC_VER
-// Temporarily disable warning 4996 (deprecated function).
-# pragma warning(push)
-# pragma warning(disable:4996)
-#endif
+GTEST_DISABLE_MSC_WARNINGS_PUSH_(4996 /* deprecated function */)
 
 inline const char* StrNCpy(char* dest, const char* src, size_t n) {
   return strncpy(dest, src, n);
@@ -2924,7 +3725,7 @@ inline const char* StrNCpy(char* dest, const char* src, size_t n) {
 // StrError() aren't needed on Windows CE at this time and thus not
 // defined there.
 
-#if !GTEST_OS_WINDOWS_MOBILE && !defined WINRT
+#if !GTEST_OS_WINDOWS_MOBILE && !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT
 inline int ChDir(const char* dir) { return chdir(dir); }
 #endif
 inline FILE* FOpen(const char* path, const char* mode) {
@@ -2948,8 +3749,9 @@ inline int Close(int fd) { return close(fd); }
 inline const char* StrError(int errnum) { return strerror(errnum); }
 #endif
 inline const char* GetEnv(const char* name) {
-#if GTEST_OS_WINDOWS_MOBILE || defined WINRT
+#if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_WINDOWS_PHONE || GTEST_OS_WINDOWS_RT
   // We are on Windows CE, which has no environment variables.
+  static_cast<void>(name);  // To prevent 'unused argument' warning.
   return NULL;
 #elif defined(__BORLANDC__) || defined(__SunOS_5_8) || defined(__SunOS_5_9)
   // Environment variables which we programmatically clear will be set to the
@@ -2961,9 +3763,7 @@ inline const char* GetEnv(const char* name) {
 #endif
 }
 
-#ifdef _MSC_VER
-# pragma warning(pop)  // Restores the warning state.
-#endif
+GTEST_DISABLE_MSC_WARNINGS_POP_()
 
 #if GTEST_OS_WINDOWS_MOBILE
 // Windows CE has no C library. The abort() function is used in
@@ -3064,11 +3864,20 @@ typedef TypeWithSize<8>::Int TimeInMillis;  // Represents time in milliseconds.
 // Utilities for command line flags and environment variables.
 
 // Macro for referencing flags.
-#define GTEST_FLAG(name) FLAGS_gtest_##name
+#if !defined(GTEST_FLAG)
+# define GTEST_FLAG(name) FLAGS_gtest_##name
+#endif  // !defined(GTEST_FLAG)
+
+#if !defined(GTEST_USE_OWN_FLAGFILE_FLAG_)
+# define GTEST_USE_OWN_FLAGFILE_FLAG_ 1
+#endif  // !defined(GTEST_USE_OWN_FLAGFILE_FLAG_)
+
+#if !defined(GTEST_DECLARE_bool_)
+# define GTEST_FLAG_SAVER_ ::testing::internal::GTestFlagSaver
 
 // Macros for declaring flags.
-#define GTEST_DECLARE_bool_(name) GTEST_API_ extern bool GTEST_FLAG(name)
-#define GTEST_DECLARE_int32_(name) \
+# define GTEST_DECLARE_bool_(name) GTEST_API_ extern bool GTEST_FLAG(name)
+# define GTEST_DECLARE_int32_(name) \
     GTEST_API_ extern ::testing::internal::Int32 GTEST_FLAG(name)
 #define GTEST_DECLARE_string_(name) \
     GTEST_API_ extern ::std::string GTEST_FLAG(name)
@@ -3081,9 +3890,13 @@ typedef TypeWithSize<8>::Int TimeInMillis;  // Represents time in milliseconds.
 #define GTEST_DEFINE_string_(name, default_val, doc) \
     GTEST_API_ ::std::string GTEST_FLAG(name) = (default_val)
 
+#endif  // !defined(GTEST_DECLARE_bool_)
+
 // Thread annotations
-#define GTEST_EXCLUSIVE_LOCK_REQUIRED_(locks)
-#define GTEST_LOCK_EXCLUDED_(locks)
+#if !defined(GTEST_EXCLUSIVE_LOCK_REQUIRED_)
+# define GTEST_EXCLUSIVE_LOCK_REQUIRED_(locks)
+# define GTEST_LOCK_EXCLUDED_(locks)
+#endif  // !defined(GTEST_EXCLUSIVE_LOCK_REQUIRED_)
 
 // Parses 'str' for a 32-bit signed integer.  If successful, writes the result
 // to *value and returns true; otherwise leaves *value unchanged and returns
@@ -3097,7 +3910,7 @@ bool ParseInt32(const Message& src_text, const char* str, Int32* value);
 // corresponding to the given Google Test flag.
 bool BoolFromGTestEnv(const char* flag, bool default_val);
 GTEST_API_ Int32 Int32FromGTestEnv(const char* flag, Int32 default_val);
-const char* StringFromGTestEnv(const char* flag, const char* default_val);
+std::string StringFromGTestEnv(const char* flag, const char* default_val);
 
 }  // namespace internal
 }  // namespace testing
@@ -3120,7 +3933,10 @@ const char* StringFromGTestEnv(const char* flag, const char* default_val);
 #include <string.h>
 #include <iomanip>
 #include <limits>
+#include <map>
 #include <set>
+#include <string>
+#include <vector>
 
 // Copyright 2005, Google Inc.
 // All rights reserved.
@@ -7108,9 +7924,6 @@ class ScopedTrace;                     // Implements scoped trace.
 class TestInfoImpl;                    // Opaque implementation of TestInfo
 class UnitTestImpl;                    // Opaque implementation of UnitTest
 
-// How many times InitGoogleTest() has been called.
-GTEST_API_ extern int g_init_gtest_count;
-
 // The text used in failure messages to indicate the start of the
 // stack trace.
 GTEST_API_ extern const char kStackTraceMarker[];
@@ -7192,6 +8005,36 @@ class GTEST_API_ ScopedTrace {
                             // c'tor and d'tor.  Therefore it doesn't
                             // need to be used otherwise.
 
+namespace edit_distance {
+// Returns the optimal edits to go from 'left' to 'right'.
+// All edits cost the same, with replace having lower priority than
+// add/remove.
+// Simple implementation of the Wagner–Fischer algorithm.
+// See http://en.wikipedia.org/wiki/Wagner-Fischer_algorithm
+enum EditType { kMatch, kAdd, kRemove, kReplace };
+GTEST_API_ std::vector<EditType> CalculateOptimalEdits(
+    const std::vector<size_t>& left, const std::vector<size_t>& right);
+
+// Same as above, but the input is represented as strings.
+GTEST_API_ std::vector<EditType> CalculateOptimalEdits(
+    const std::vector<std::string>& left,
+    const std::vector<std::string>& right);
+
+// Create a diff of the input strings in Unified diff format.
+GTEST_API_ std::string CreateUnifiedDiff(const std::vector<std::string>& left,
+                                         const std::vector<std::string>& right,
+                                         size_t context = 2);
+
+}  // namespace edit_distance
+
+// Calculate the diff between 'left' and 'right' and return it in unified diff
+// format.
+// If not null, stores in 'total_line_count' the total number of lines found
+// in left + right.
+GTEST_API_ std::string DiffStrings(const std::string& left,
+                                   const std::string& right,
+                                   size_t* total_line_count);
+
 // Constructs and returns the message for an equality assertion
 // (e.g. ASSERT_EQ, EXPECT_STREQ, etc) failure.
 //
@@ -7492,6 +8335,13 @@ GTEST_API_ AssertionResult IsHRESULTFailure(const char* expr,
 typedef void (*SetUpTestCaseFunc)();
 typedef void (*TearDownTestCaseFunc)();
 
+struct CodeLocation {
+  CodeLocation(const string& a_file, int a_line) : file(a_file), line(a_line) {}
+
+  string file;
+  int line;
+};
+
 // Creates a new TestInfo object and registers it with Google Test;
 // returns the created object.
 //
@@ -7503,6 +8353,7 @@ typedef void (*TearDownTestCaseFunc)();
 //                     this is not a typed or a type-parameterized test.
 //   value_param       text representation of the test's value parameter,
 //                     or NULL if this is not a type-parameterized test.
+//   code_location:    code location where the test is defined
 //   fixture_class_id: ID of the test fixture class
 //   set_up_tc:        pointer to the function that sets up the test case
 //   tear_down_tc:     pointer to the function that tears down the test case
@@ -7514,6 +8365,7 @@ GTEST_API_ TestInfo* MakeAndRegisterTestInfo(
     const char* name,
     const char* type_param,
     const char* value_param,
+    CodeLocation code_location,
     TypeId fixture_class_id,
     SetUpTestCaseFunc set_up_tc,
     TearDownTestCaseFunc tear_down_tc,
@@ -7543,10 +8395,21 @@ class GTEST_API_ TypedTestCasePState {
       fflush(stderr);
       posix::Abort();
     }
-    defined_test_names_.insert(test_name);
+    registered_tests_.insert(
+        ::std::make_pair(test_name, CodeLocation(file, line)));
     return true;
   }
 
+  bool TestExists(const std::string& test_name) const {
+    return registered_tests_.count(test_name) > 0;
+  }
+
+  const CodeLocation& GetCodeLocation(const std::string& test_name) const {
+    RegisteredTestsMap::const_iterator it = registered_tests_.find(test_name);
+    GTEST_CHECK_(it != registered_tests_.end());
+    return it->second;
+  }
+
   // Verifies that registered_tests match the test names in
   // defined_test_names_; returns registered_tests if successful, or
   // aborts the program otherwise.
@@ -7554,8 +8417,10 @@ class GTEST_API_ TypedTestCasePState {
       const char* file, int line, const char* registered_tests);
 
  private:
+  typedef ::std::map<std::string, CodeLocation> RegisteredTestsMap;
+
   bool registered_;
-  ::std::set<const char*> defined_test_names_;
+  RegisteredTestsMap registered_tests_;
 };
 
 // Skips to the first non-space char after the first comma in 'str';
@@ -7576,6 +8441,11 @@ inline std::string GetPrefixUntilComma(const char* str) {
   return comma == NULL ? str : std::string(str, comma);
 }
 
+// Splits a given string on a given delimiter, populating a given
+// vector with the fields.
+void SplitString(const ::std::string& str, char delimiter,
+                 ::std::vector< ::std::string>* dest);
+
 // TypeParameterizedTest<Fixture, TestSel, Types>::Register()
 // registers a list of type-parameterized tests with Google Test.  The
 // return value is insignificant - we just need to return something
@@ -7590,8 +8460,10 @@ class TypeParameterizedTest {
   // specified in INSTANTIATE_TYPED_TEST_CASE_P(Prefix, TestCase,
   // Types).  Valid values for 'index' are [0, N - 1] where N is the
   // length of Types.
-  static bool Register(const char* prefix, const char* case_name,
-                       const char* test_names, int index) {
+  static bool Register(const char* prefix,
+                       CodeLocation code_location,
+                       const char* case_name, const char* test_names,
+                       int index) {
     typedef typename Types::Head Type;
     typedef Fixture<Type> FixtureClass;
     typedef typename GTEST_BIND_(TestSel, Type) TestClass;
@@ -7601,9 +8473,10 @@ class TypeParameterizedTest {
     MakeAndRegisterTestInfo(
         (std::string(prefix) + (prefix[0] == '\0' ? "" : "/") + case_name + "/"
          + StreamableToString(index)).c_str(),
-        GetPrefixUntilComma(test_names).c_str(),
+        StripTrailingSpaces(GetPrefixUntilComma(test_names)).c_str(),
         GetTypeName<Type>().c_str(),
         NULL,  // No value parameter.
+        code_location,
         GetTypeId<FixtureClass>(),
         TestClass::SetUpTestCase,
         TestClass::TearDownTestCase,
@@ -7611,7 +8484,7 @@ class TypeParameterizedTest {
 
     // Next, recurses (at compile time) with the tail of the type list.
     return TypeParameterizedTest<Fixture, TestSel, typename Types::Tail>
-        ::Register(prefix, case_name, test_names, index + 1);
+        ::Register(prefix, code_location, case_name, test_names, index + 1);
   }
 };
 
@@ -7619,8 +8492,9 @@ class TypeParameterizedTest {
 template <GTEST_TEMPLATE_ Fixture, class TestSel>
 class TypeParameterizedTest<Fixture, TestSel, Types0> {
  public:
-  static bool Register(const char* /*prefix*/, const char* /*case_name*/,
-                       const char* /*test_names*/, int /*index*/) {
+  static bool Register(const char* /*prefix*/, CodeLocation,
+                       const char* /*case_name*/, const char* /*test_names*/,
+                       int /*index*/) {
     return true;
   }
 };
@@ -7632,17 +8506,31 @@ class TypeParameterizedTest<Fixture, TestSel, Types0> {
 template <GTEST_TEMPLATE_ Fixture, typename Tests, typename Types>
 class TypeParameterizedTestCase {
  public:
-  static bool Register(const char* prefix, const char* case_name,
-                       const char* test_names) {
+  static bool Register(const char* prefix, CodeLocation code_location,
+                       const TypedTestCasePState* state,
+                       const char* case_name, const char* test_names) {
+    std::string test_name = StripTrailingSpaces(
+        GetPrefixUntilComma(test_names));
+    if (!state->TestExists(test_name)) {
+      fprintf(stderr, "Failed to get code location for test %s.%s at %s.",
+              case_name, test_name.c_str(),
+              FormatFileLocation(code_location.file.c_str(),
+                                 code_location.line).c_str());
+      fflush(stderr);
+      posix::Abort();
+    }
+    const CodeLocation& test_location = state->GetCodeLocation(test_name);
+
     typedef typename Tests::Head Head;
 
     // First, register the first test in 'Test' for each type in 'Types'.
     TypeParameterizedTest<Fixture, Head, Types>::Register(
-        prefix, case_name, test_names, 0);
+        prefix, test_location, case_name, test_names, 0);
 
     // Next, recurses (at compile time) with the tail of the test list.
     return TypeParameterizedTestCase<Fixture, typename Tests::Tail, Types>
-        ::Register(prefix, case_name, SkipComma(test_names));
+        ::Register(prefix, code_location, state,
+                   case_name, SkipComma(test_names));
   }
 };
 
@@ -7650,8 +8538,9 @@ class TypeParameterizedTestCase {
 template <GTEST_TEMPLATE_ Fixture, typename Types>
 class TypeParameterizedTestCase<Fixture, Templates0, Types> {
  public:
-  static bool Register(const char* /*prefix*/, const char* /*case_name*/,
-                       const char* /*test_names*/) {
+  static bool Register(const char* /*prefix*/, CodeLocation,
+                       const TypedTestCasePState* /*state*/,
+                       const char* /*case_name*/, const char* /*test_names*/) {
     return true;
   }
 };
@@ -7805,7 +8694,7 @@ class ImplicitlyConvertible {
   // MakeFrom() is an expression whose type is From.  We cannot simply
   // use From(), as the type From may not have a public default
   // constructor.
-  static From MakeFrom();
+  static typename AddReference<From>::type MakeFrom();
 
   // These two functions are overloaded.  Given an expression
   // Helper(x), the compiler will pick the first version if x can be
@@ -7823,25 +8712,20 @@ class ImplicitlyConvertible {
   // We have to put the 'public' section after the 'private' section,
   // or MSVC refuses to compile the code.
  public:
-  // MSVC warns about implicitly converting from double to int for
-  // possible loss of data, so we need to temporarily disable the
-  // warning.
-#ifdef _MSC_VER
-# pragma warning(push)          // Saves the current warning state.
-# pragma warning(disable:4244)  // Temporarily disables warning 4244.
-
-  static const bool value =
-      sizeof(Helper(ImplicitlyConvertible::MakeFrom())) == 1;
-# pragma warning(pop)           // Restores the warning state.
-#elif defined(__BORLANDC__)
+#if defined(__BORLANDC__)
   // C++Builder cannot use member overload resolution during template
   // instantiation.  The simplest workaround is to use its C++0x type traits
   // functions (C++Builder 2009 and above only).
   static const bool value = __is_convertible(From, To);
 #else
+  // MSVC warns about implicitly converting from double to int for
+  // possible loss of data, so we need to temporarily disable the
+  // warning.
+  GTEST_DISABLE_MSC_WARNINGS_PUSH_(4244)
   static const bool value =
       sizeof(Helper(ImplicitlyConvertible::MakeFrom())) == 1;
-#endif  // _MSV_VER
+  GTEST_DISABLE_MSC_WARNINGS_POP_()
+#endif  // __BORLANDC__
 };
 template <typename From, typename To>
 const bool ImplicitlyConvertible<From, To>::value;
@@ -7967,11 +8851,10 @@ void CopyArray(const T* from, size_t size, U* to) {
 
 // The relation between an NativeArray object (see below) and the
 // native array it represents.
-enum RelationToSource {
-  kReference,  // The NativeArray references the native array.
-  kCopy        // The NativeArray makes a copy of the native array and
-               // owns the copy.
-};
+// We use 2 different structs to allow non-copyable types to be used, as long
+// as RelationToSourceReference() is passed.
+struct RelationToSourceReference {};
+struct RelationToSourceCopy {};
 
 // Adapts a native array to a read-only STL-style container.  Instead
 // of the complete STL container concept, this adaptor only implements
@@ -7989,22 +8872,23 @@ class NativeArray {
   typedef Element* iterator;
   typedef const Element* const_iterator;
 
-  // Constructs from a native array.
-  NativeArray(const Element* array, size_t count, RelationToSource relation) {
-    Init(array, count, relation);
+  // Constructs from a native array. References the source.
+  NativeArray(const Element* array, size_t count, RelationToSourceReference) {
+    InitRef(array, count);
+  }
+
+  // Constructs from a native array. Copies the source.
+  NativeArray(const Element* array, size_t count, RelationToSourceCopy) {
+    InitCopy(array, count);
   }
 
   // Copy constructor.
   NativeArray(const NativeArray& rhs) {
-    Init(rhs.array_, rhs.size_, rhs.relation_to_source_);
+    (this->*rhs.clone_)(rhs.array_, rhs.size_);
   }
 
   ~NativeArray() {
-    // Ensures that the user doesn't instantiate NativeArray with a
-    // const or reference type.
-    static_cast<void>(StaticAssertTypeEqHelper<Element,
-        GTEST_REMOVE_REFERENCE_AND_CONST_(Element)>());
-    if (relation_to_source_ == kCopy)
+    if (clone_ != &NativeArray::InitRef)
       delete[] array_;
   }
 
@@ -8018,23 +8902,30 @@ class NativeArray {
   }
 
  private:
-  // Initializes this object; makes a copy of the input array if
-  // 'relation' is kCopy.
-  void Init(const Element* array, size_t a_size, RelationToSource relation) {
-    if (relation == kReference) {
-      array_ = array;
-    } else {
-      Element* const copy = new Element[a_size];
-      CopyArray(array, a_size, copy);
-      array_ = copy;
-    }
+  enum {
+    kCheckTypeIsNotConstOrAReference = StaticAssertTypeEqHelper<
+        Element, GTEST_REMOVE_REFERENCE_AND_CONST_(Element)>::value,
+  };
+
+  // Initializes this object with a copy of the input.
+  void InitCopy(const Element* array, size_t a_size) {
+    Element* const copy = new Element[a_size];
+    CopyArray(array, a_size, copy);
+    array_ = copy;
+    size_ = a_size;
+    clone_ = &NativeArray::InitCopy;
+  }
+
+  // Initializes this object with a reference of the input.
+  void InitRef(const Element* array, size_t a_size) {
+    array_ = array;
     size_ = a_size;
-    relation_to_source_ = relation;
+    clone_ = &NativeArray::InitRef;
   }
 
   const Element* array_;
   size_t size_;
-  RelationToSource relation_to_source_;
+  void (NativeArray::*clone_)(const Element*, size_t);
 
   GTEST_DISALLOW_ASSIGN_(NativeArray);
 };
@@ -8169,6 +9060,7 @@ class GTEST_TEST_CLASS_NAME_(test_case_name, test_name) : public parent_class {\
   ::test_info_ =\
     ::testing::internal::MakeAndRegisterTestInfo(\
         #test_case_name, #test_name, NULL, NULL, \
+        ::testing::internal::CodeLocation(__FILE__, __LINE__), \
         (parent_id), \
         parent_class::SetUpTestCase, \
         parent_class::TearDownTestCase, \
@@ -8177,6 +9069,7 @@ class GTEST_TEST_CLASS_NAME_(test_case_name, test_name) : public parent_class {\
 void GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::TestBody()
 
 #endif  // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_
+
 // Copyright 2005, Google Inc.
 // All rights reserved.
 //
@@ -9013,7 +9906,10 @@ TEST_P(DerivedTest, DoesBlah) {
 #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_
 #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_
 
+#include <ctype.h>
+
 #include <iterator>
+#include <set>
 #include <utility>
 #include <vector>
 
@@ -9131,7 +10027,12 @@ class linked_ptr_internal {
     MutexLock lock(&g_linked_ptr_mutex);
 
     linked_ptr_internal const* p = ptr;
-    while (p->next_ != ptr) p = p->next_;
+    while (p->next_ != ptr) {
+      assert(p->next_ != this &&
+             "Trying to join() a linked ring we are already in. "
+             "Is GMock thread safety enabled?");
+      p = p->next_;
+    }
     p->next_ = this;
     next_ = ptr;
   }
@@ -9144,7 +10045,12 @@ class linked_ptr_internal {
 
     if (next_ == this) return true;
     linked_ptr_internal const* p = next_;
-    while (p->next_ != this) p = p->next_;
+    while (p->next_ != this) {
+      assert(p->next_ != next_ &&
+             "Trying to depart() a linked ring we are not in. "
+             "Is GMock thread safety enabled?");
+      p = p->next_;
+    }
     p->next_ = next_;
     return false;
   }
@@ -9355,6 +10261,10 @@ linked_ptr<T> make_linked_ptr(T* ptr) {
 #include <utility>
 #include <vector>
 
+#if GTEST_HAS_STD_TUPLE_
+# include <tuple>
+#endif
+
 namespace testing {
 
 // Definitions in the 'internal' and 'internal2' name spaces are
@@ -9502,6 +10412,103 @@ void DefaultPrintNonContainerTo(const T& value, ::std::ostream* os) {
 namespace testing {
 namespace internal {
 
+// FormatForComparison<ToPrint, OtherOperand>::Format(value) formats a
+// value of type ToPrint that is an operand of a comparison assertion
+// (e.g. ASSERT_EQ).  OtherOperand is the type of the other operand in
+// the comparison, and is used to help determine the best way to
+// format the value.  In particular, when the value is a C string
+// (char pointer) and the other operand is an STL string object, we
+// want to format the C string as a string, since we know it is
+// compared by value with the string object.  If the value is a char
+// pointer but the other operand is not an STL string object, we don't
+// know whether the pointer is supposed to point to a NUL-terminated
+// string, and thus want to print it as a pointer to be safe.
+//
+// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+
+// The default case.
+template <typename ToPrint, typename OtherOperand>
+class FormatForComparison {
+ public:
+  static ::std::string Format(const ToPrint& value) {
+    return ::testing::PrintToString(value);
+  }
+};
+
+// Array.
+template <typename ToPrint, size_t N, typename OtherOperand>
+class FormatForComparison<ToPrint[N], OtherOperand> {
+ public:
+  static ::std::string Format(const ToPrint* value) {
+    return FormatForComparison<const ToPrint*, OtherOperand>::Format(value);
+  }
+};
+
+// By default, print C string as pointers to be safe, as we don't know
+// whether they actually point to a NUL-terminated string.
+
+#define GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(CharType)                \
+  template <typename OtherOperand>                                      \
+  class FormatForComparison<CharType*, OtherOperand> {                  \
+   public:                                                              \
+    static ::std::string Format(CharType* value) {                      \
+      return ::testing::PrintToString(static_cast<const void*>(value)); \
+    }                                                                   \
+  }
+
+GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(char);
+GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(const char);
+GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(wchar_t);
+GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(const wchar_t);
+
+#undef GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_
+
+// If a C string is compared with an STL string object, we know it's meant
+// to point to a NUL-terminated string, and thus can print it as a string.
+
+#define GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(CharType, OtherStringType) \
+  template <>                                                           \
+  class FormatForComparison<CharType*, OtherStringType> {               \
+   public:                                                              \
+    static ::std::string Format(CharType* value) {                      \
+      return ::testing::PrintToString(value);                           \
+    }                                                                   \
+  }
+
+GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(char, ::std::string);
+GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const char, ::std::string);
+
+#if GTEST_HAS_GLOBAL_STRING
+GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(char, ::string);
+GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const char, ::string);
+#endif
+
+#if GTEST_HAS_GLOBAL_WSTRING
+GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(wchar_t, ::wstring);
+GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const wchar_t, ::wstring);
+#endif
+
+#if GTEST_HAS_STD_WSTRING
+GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(wchar_t, ::std::wstring);
+GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const wchar_t, ::std::wstring);
+#endif
+
+#undef GTEST_IMPL_FORMAT_C_STRING_AS_STRING_
+
+// Formats a comparison assertion (e.g. ASSERT_EQ, EXPECT_LT, and etc)
+// operand to be used in a failure message.  The type (but not value)
+// of the other operand may affect the format.  This allows us to
+// print a char* as a raw pointer when it is compared against another
+// char* or void*, and print it as a C string when it is compared
+// against an std::string object, for example.
+//
+// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+template <typename T1, typename T2>
+std::string FormatForComparisonFailureMessage(
+    const T1& value, const T2& /* other_operand */) {
+  return FormatForComparison<T1, T2>::Format(value);
+}
+
 // UniversalPrinter<T>::Print(value, ostream_ptr) prints the given
 // value to the given ostream.  The caller must ensure that
 // 'ostream_ptr' is not NULL, or the behavior is undefined.
@@ -9732,14 +10739,16 @@ inline void PrintTo(const ::std::wstring& s, ::std::ostream* os) {
 }
 #endif  // GTEST_HAS_STD_WSTRING
 
-#if GTEST_HAS_TR1_TUPLE
-// Overload for ::std::tr1::tuple.  Needed for printing function arguments,
-// which are packed as tuples.
-
+#if GTEST_HAS_TR1_TUPLE || GTEST_HAS_STD_TUPLE_
 // Helper function for printing a tuple.  T must be instantiated with
 // a tuple type.
 template <typename T>
 void PrintTupleTo(const T& t, ::std::ostream* os);
+#endif  // GTEST_HAS_TR1_TUPLE || GTEST_HAS_STD_TUPLE_
+
+#if GTEST_HAS_TR1_TUPLE
+// Overload for ::std::tr1::tuple.  Needed for printing function arguments,
+// which are packed as tuples.
 
 // Overloaded PrintTo() for tuples of various arities.  We support
 // tuples of up-to 10 fields.  The following implementation works
@@ -9813,6 +10822,13 @@ void PrintTo(
 }
 #endif  // GTEST_HAS_TR1_TUPLE
 
+#if GTEST_HAS_STD_TUPLE_
+template <typename... Types>
+void PrintTo(const ::std::tuple<Types...>& t, ::std::ostream* os) {
+  PrintTupleTo(t, os);
+}
+#endif  // GTEST_HAS_STD_TUPLE_
+
 // Overload for std::pair.
 template <typename T1, typename T2>
 void PrintTo(const ::std::pair<T1, T2>& value, ::std::ostream* os) {
@@ -9832,10 +10848,7 @@ class UniversalPrinter {
  public:
   // MSVC warns about adding const to a function type, so we want to
   // disable the warning.
-#ifdef _MSC_VER
-# pragma warning(push)          // Saves the current warning state.
-# pragma warning(disable:4180)  // Temporarily disables warning 4180.
-#endif  // _MSC_VER
+  GTEST_DISABLE_MSC_WARNINGS_PUSH_(4180)
 
   // Note: we deliberately don't call this PrintTo(), as that name
   // conflicts with ::testing::internal::PrintTo in the body of the
@@ -9852,9 +10865,7 @@ class UniversalPrinter {
     PrintTo(value, os);
   }
 
-#ifdef _MSC_VER
-# pragma warning(pop)           // Restores the warning state.
-#endif  // _MSC_VER
+  GTEST_DISABLE_MSC_WARNINGS_POP_()
 };
 
 // UniversalPrintArray(begin, len, os) prints an array of 'len'
@@ -9906,10 +10917,7 @@ class UniversalPrinter<T&> {
  public:
   // MSVC warns about adding const to a function type, so we want to
   // disable the warning.
-#ifdef _MSC_VER
-# pragma warning(push)          // Saves the current warning state.
-# pragma warning(disable:4180)  // Temporarily disables warning 4180.
-#endif  // _MSC_VER
+  GTEST_DISABLE_MSC_WARNINGS_PUSH_(4180)
 
   static void Print(const T& value, ::std::ostream* os) {
     // Prints the address of the value.  We use reinterpret_cast here
@@ -9920,9 +10928,7 @@ class UniversalPrinter<T&> {
     UniversalPrint(value, os);
   }
 
-#ifdef _MSC_VER
-# pragma warning(pop)           // Restores the warning state.
-#endif  // _MSC_VER
+  GTEST_DISABLE_MSC_WARNINGS_POP_()
 };
 
 // Prints a value tersely: for a reference type, the referenced value
@@ -10008,16 +11014,65 @@ void UniversalPrint(const T& value, ::std::ostream* os) {
   UniversalPrinter<T1>::Print(value, os);
 }
 
-#if GTEST_HAS_TR1_TUPLE
 typedef ::std::vector<string> Strings;
 
+// TuplePolicy<TupleT> must provide:
+// - tuple_size
+//     size of tuple TupleT.
+// - get<size_t I>(const TupleT& t)
+//     static function extracting element I of tuple TupleT.
+// - tuple_element<size_t I>::type
+//     type of element I of tuple TupleT.
+template <typename TupleT>
+struct TuplePolicy;
+
+#if GTEST_HAS_TR1_TUPLE
+template <typename TupleT>
+struct TuplePolicy {
+  typedef TupleT Tuple;
+  static const size_t tuple_size = ::std::tr1::tuple_size<Tuple>::value;
+
+  template <size_t I>
+  struct tuple_element : ::std::tr1::tuple_element<I, Tuple> {};
+
+  template <size_t I>
+  static typename AddReference<
+      const typename ::std::tr1::tuple_element<I, Tuple>::type>::type get(
+      const Tuple& tuple) {
+    return ::std::tr1::get<I>(tuple);
+  }
+};
+template <typename TupleT>
+const size_t TuplePolicy<TupleT>::tuple_size;
+#endif  // GTEST_HAS_TR1_TUPLE
+
+#if GTEST_HAS_STD_TUPLE_
+template <typename... Types>
+struct TuplePolicy< ::std::tuple<Types...> > {
+  typedef ::std::tuple<Types...> Tuple;
+  static const size_t tuple_size = ::std::tuple_size<Tuple>::value;
+
+  template <size_t I>
+  struct tuple_element : ::std::tuple_element<I, Tuple> {};
+
+  template <size_t I>
+  static const typename ::std::tuple_element<I, Tuple>::type& get(
+      const Tuple& tuple) {
+    return ::std::get<I>(tuple);
+  }
+};
+template <typename... Types>
+const size_t TuplePolicy< ::std::tuple<Types...> >::tuple_size;
+#endif  // GTEST_HAS_STD_TUPLE_
+
+#if GTEST_HAS_TR1_TUPLE || GTEST_HAS_STD_TUPLE_
 // This helper template allows PrintTo() for tuples and
 // UniversalTersePrintTupleFieldsToStrings() to be defined by
 // induction on the number of tuple fields.  The idea is that
 // TuplePrefixPrinter<N>::PrintPrefixTo(t, os) prints the first N
 // fields in tuple t, and can be defined in terms of
 // TuplePrefixPrinter<N - 1>.
-
+//
 // The inductive case.
 template <size_t N>
 struct TuplePrefixPrinter {
@@ -10025,9 +11080,14 @@ struct TuplePrefixPrinter {
   template <typename Tuple>
   static void PrintPrefixTo(const Tuple& t, ::std::ostream* os) {
     TuplePrefixPrinter<N - 1>::PrintPrefixTo(t, os);
-    *os << ", ";
-    UniversalPrinter<typename ::std::tr1::tuple_element<N - 1, Tuple>::type>
-        ::Print(::std::tr1::get<N - 1>(t), os);
+    GTEST_INTENTIONAL_CONST_COND_PUSH_()
+    if (N > 1) {
+    GTEST_INTENTIONAL_CONST_COND_POP_()
+      *os << ", ";
+    }
+    UniversalPrinter<
+        typename TuplePolicy<Tuple>::template tuple_element<N - 1>::type>
+        ::Print(TuplePolicy<Tuple>::template get<N - 1>(t), os);
   }
 
   // Tersely prints the first N fields of a tuple to a string vector,
@@ -10036,12 +11096,12 @@ struct TuplePrefixPrinter {
   static void TersePrintPrefixToStrings(const Tuple& t, Strings* strings) {
     TuplePrefixPrinter<N - 1>::TersePrintPrefixToStrings(t, strings);
     ::std::stringstream ss;
-    UniversalTersePrint(::std::tr1::get<N - 1>(t), &ss);
+    UniversalTersePrint(TuplePolicy<Tuple>::template get<N - 1>(t), &ss);
     strings->push_back(ss.str());
   }
 };
 
-// Base cases.
+// Base case.
 template <>
 struct TuplePrefixPrinter<0> {
   template <typename Tuple>
@@ -10050,34 +11110,13 @@ struct TuplePrefixPrinter<0> {
   template <typename Tuple>
   static void TersePrintPrefixToStrings(const Tuple&, Strings*) {}
 };
-// We have to specialize the entire TuplePrefixPrinter<> class
-// template here, even though the definition of
-// TersePrintPrefixToStrings() is the same as the generic version, as
-// Embarcadero (formerly CodeGear, formerly Borland) C++ doesn't
-// support specializing a method template of a class template.
-template <>
-struct TuplePrefixPrinter<1> {
-  template <typename Tuple>
-  static void PrintPrefixTo(const Tuple& t, ::std::ostream* os) {
-    UniversalPrinter<typename ::std::tr1::tuple_element<0, Tuple>::type>::
-        Print(::std::tr1::get<0>(t), os);
-  }
-
-  template <typename Tuple>
-  static void TersePrintPrefixToStrings(const Tuple& t, Strings* strings) {
-    ::std::stringstream ss;
-    UniversalTersePrint(::std::tr1::get<0>(t), &ss);
-    strings->push_back(ss.str());
-  }
-};
 
-// Helper function for printing a tuple.  T must be instantiated with
-// a tuple type.
-template <typename T>
-void PrintTupleTo(const T& t, ::std::ostream* os) {
+// Helper function for printing a tuple.
+// Tuple must be either std::tr1::tuple or std::tuple type.
+template <typename Tuple>
+void PrintTupleTo(const Tuple& t, ::std::ostream* os) {
   *os << "(";
-  TuplePrefixPrinter< ::std::tr1::tuple_size<T>::value>::
-      PrintPrefixTo(t, os);
+  TuplePrefixPrinter<TuplePolicy<Tuple>::tuple_size>::PrintPrefixTo(t, os);
   *os << ")";
 }
 
@@ -10087,11 +11126,11 @@ void PrintTupleTo(const T& t, ::std::ostream* os) {
 template <typename Tuple>
 Strings UniversalTersePrintTupleFieldsToStrings(const Tuple& value) {
   Strings result;
-  TuplePrefixPrinter< ::std::tr1::tuple_size<Tuple>::value>::
+  TuplePrefixPrinter<TuplePolicy<Tuple>::tuple_size>::
       TersePrintPrefixToStrings(value, &result);
   return result;
 }
-#endif  // GTEST_HAS_TR1_TUPLE
+#endif  // GTEST_HAS_TR1_TUPLE || GTEST_HAS_STD_TUPLE_
 
 }  // namespace internal
 
@@ -10104,11 +11143,78 @@ template <typename T>
 
 }  // namespace testing
 
+// Include any custom printer added by the local installation.
+// We must include this header at the end to make sure it can use the
+// declarations from this file.
+// Copyright 2015, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// This file provides an injection point for custom printers in a local
+// installation of gTest.
+// It will be included from gtest-printers.h and the overrides in this file
+// will be visible to everyone.
+// See documentation at gtest/gtest-printers.h for details on how to define a
+// custom printer.
+//
+// ** Custom implementation starts here **
+
+#ifndef GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PRINTERS_H_
+#define GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PRINTERS_H_
+
+#endif  // GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PRINTERS_H_
+
 #endif  // GTEST_INCLUDE_GTEST_GTEST_PRINTERS_H_
 
 #if GTEST_HAS_PARAM_TEST
 
 namespace testing {
+
+// Input to a parameterized test name generator, describing a test parameter.
+// Consists of the parameter value and the integer parameter index.
+template <class ParamType>
+struct TestParamInfo {
+  TestParamInfo(const ParamType& a_param, size_t an_index) :
+    param(a_param),
+    index(an_index) {}
+  ParamType param;
+  size_t index;
+};
+
+// A builtin parameterized test name generator which returns the result of
+// testing::PrintToString.
+struct PrintToStringParamName {
+  template <class ParamType>
+  std::string operator()(const TestParamInfo<ParamType>& info) const {
+    return PrintToString(info.param);
+  }
+};
+
 namespace internal {
 
 // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
@@ -10118,7 +11224,7 @@ namespace internal {
 // TEST_P macro is used to define two tests with the same name
 // but in different namespaces.
 GTEST_API_ void ReportInvalidTestCaseType(const char* test_case_name,
-                                          const char* file, int line);
+                                          CodeLocation code_location);
 
 template <typename> class ParamGeneratorInterface;
 template <typename> class ParamGenerator;
@@ -10266,7 +11372,7 @@ class RangeGenerator : public ParamGeneratorInterface<T> {
       return base_;
     }
     virtual void Advance() {
-      value_ = value_ + step_;
+      value_ = static_cast<T>(value_ + step_);
       index_++;
     }
     virtual ParamIteratorInterface<T>* Clone() const {
@@ -10303,7 +11409,7 @@ class RangeGenerator : public ParamGeneratorInterface<T> {
                                const T& end,
                                const IncrementT& step) {
     int end_index = 0;
-    for (T i = begin; i < end; i = i + step)
+    for (T i = begin; i < end; i = static_cast<T>(i + step))
       end_index++;
     return end_index;
   }
@@ -10407,6 +11513,37 @@ class ValuesInIteratorRangeGenerator : public ParamGeneratorInterface<T> {
 
 // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
 //
+// Default parameterized test name generator, returns a string containing the
+// integer test parameter index.
+template <class ParamType>
+std::string DefaultParamName(const TestParamInfo<ParamType>& info) {
+  Message name_stream;
+  name_stream << info.index;
+  return name_stream.GetString();
+}
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+//
+// Parameterized test name overload helpers, which help the
+// INSTANTIATE_TEST_CASE_P macro choose between the default parameterized
+// test name generator and user param name generator.
+template <class ParamType, class ParamNameGenFunctor>
+ParamNameGenFunctor GetParamNameGen(ParamNameGenFunctor func) {
+  return func;
+}
+
+template <class ParamType>
+struct ParamNameGenFunc {
+  typedef std::string Type(const TestParamInfo<ParamType>&);
+};
+
+template <class ParamType>
+typename ParamNameGenFunc<ParamType>::Type *GetParamNameGen() {
+  return DefaultParamName;
+}
+
+// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
+//
 // Stores a parameter value and later creates tests parameterized with that
 // value.
 template <class TestClass>
@@ -10509,9 +11646,11 @@ class ParameterizedTestCaseInfo : public ParameterizedTestCaseInfoBase {
   typedef typename TestCase::ParamType ParamType;
   // A function that returns an instance of appropriate generator type.
   typedef ParamGenerator<ParamType>(GeneratorCreationFunc)();
+  typedef typename ParamNameGenFunc<ParamType>::Type ParamNameGeneratorFunc;
 
-  explicit ParameterizedTestCaseInfo(const char* name)
-      : test_case_name_(name) {}
+  explicit ParameterizedTestCaseInfo(
+      const char* name, CodeLocation code_location)
+      : test_case_name_(name), code_location_(code_location) {}
 
   // Test case base name for display purposes.
   virtual const string& GetTestCaseName() const { return test_case_name_; }
@@ -10534,9 +11673,11 @@ class ParameterizedTestCaseInfo : public ParameterizedTestCaseInfoBase {
   // about a generator.
   int AddTestCaseInstantiation(const string& instantiation_name,
                                GeneratorCreationFunc* func,
-                               const char* /* file */,
-                               int /* line */) {
-    instantiations_.push_back(::std::make_pair(instantiation_name, func));
+                               ParamNameGeneratorFunc* name_func,
+                               const char* file,
+                               int line) {
+    instantiations_.push_back(
+        InstantiationInfo(instantiation_name, func, name_func, file, line));
     return 0;  // Return value used only to run this method in namespace scope.
   }
   // UnitTest class invokes this method to register tests in this test case
@@ -10551,25 +11692,45 @@ class ParameterizedTestCaseInfo : public ParameterizedTestCaseInfoBase {
       for (typename InstantiationContainer::iterator gen_it =
                instantiations_.begin(); gen_it != instantiations_.end();
                ++gen_it) {
-        const string& instantiation_name = gen_it->first;
-        ParamGenerator<ParamType> generator((*gen_it->second)());
+        const string& instantiation_name = gen_it->name;
+        ParamGenerator<ParamType> generator((*gen_it->generator)());
+        ParamNameGeneratorFunc* name_func = gen_it->name_func;
+        const char* file = gen_it->file;
+        int line = gen_it->line;
 
         string test_case_name;
         if ( !instantiation_name.empty() )
           test_case_name = instantiation_name + "/";
         test_case_name += test_info->test_case_base_name;
 
-        int i = 0;
+        size_t i = 0;
+        std::set<std::string> test_param_names;
         for (typename ParamGenerator<ParamType>::iterator param_it =
                  generator.begin();
              param_it != generator.end(); ++param_it, ++i) {
           Message test_name_stream;
-          test_name_stream << test_info->test_base_name << "/" << i;
+
+          std::string param_name = name_func(
+              TestParamInfo<ParamType>(*param_it, i));
+
+          GTEST_CHECK_(IsValidParamName(param_name))
+              << "Parameterized test name '" << param_name
+              << "' is invalid, in " << file
+              << " line " << line << std::endl;
+
+          GTEST_CHECK_(test_param_names.count(param_name) == 0)
+              << "Duplicate parameterized test name '" << param_name
+              << "', in " << file << " line " << line << std::endl;
+
+          test_param_names.insert(param_name);
+
+          test_name_stream << test_info->test_base_name << "/" << param_name;
           MakeAndRegisterTestInfo(
               test_case_name.c_str(),
               test_name_stream.GetString().c_str(),
               NULL,  // No type parameter.
               PrintToString(*param_it).c_str(),
+              code_location_,
               GetTestCaseTypeId(),
               TestCase::SetUpTestCase,
               TestCase::TearDownTestCase,
@@ -10595,12 +11756,45 @@ class ParameterizedTestCaseInfo : public ParameterizedTestCaseInfoBase {
     const scoped_ptr<TestMetaFactoryBase<ParamType> > test_meta_factory;
   };
   typedef ::std::vector<linked_ptr<TestInfo> > TestInfoContainer;
-  // Keeps pairs of <Instantiation name, Sequence generator creation function>
-  // received from INSTANTIATE_TEST_CASE_P macros.
-  typedef ::std::vector<std::pair<string, GeneratorCreationFunc*> >
-      InstantiationContainer;
+  // Records data received from INSTANTIATE_TEST_CASE_P macros:
+  //  <Instantiation name, Sequence generator creation function,
+  //     Name generator function, Source file, Source line>
+  struct InstantiationInfo {
+      InstantiationInfo(const std::string &name_in,
+                        GeneratorCreationFunc* generator_in,
+                        ParamNameGeneratorFunc* name_func_in,
+                        const char* file_in,
+                        int line_in)
+          : name(name_in),
+            generator(generator_in),
+            name_func(name_func_in),
+            file(file_in),
+            line(line_in) {}
+
+      std::string name;
+      GeneratorCreationFunc* generator;
+      ParamNameGeneratorFunc* name_func;
+      const char* file;
+      int line;
+  };
+  typedef ::std::vector<InstantiationInfo> InstantiationContainer;
+
+  static bool IsValidParamName(const std::string& name) {
+    // Check for empty string
+    if (name.empty())
+      return false;
+
+    // Check for invalid characters
+    for (std::string::size_type index = 0; index < name.size(); ++index) {
+      if (!isalnum(name[index]) && name[index] != '_')
+        return false;
+    }
+
+    return true;
+  }
 
   const string test_case_name_;
+  CodeLocation code_location_;
   TestInfoContainer tests_;
   InstantiationContainer instantiations_;
 
@@ -10628,8 +11822,7 @@ class ParameterizedTestCaseRegistry {
   template <class TestCase>
   ParameterizedTestCaseInfo<TestCase>* GetTestCasePatternHolder(
       const char* test_case_name,
-      const char* file,
-      int line) {
+      CodeLocation code_location) {
     ParameterizedTestCaseInfo<TestCase>* typed_test_info = NULL;
     for (TestCaseInfoContainer::iterator it = test_case_infos_.begin();
          it != test_case_infos_.end(); ++it) {
@@ -10638,7 +11831,7 @@ class ParameterizedTestCaseRegistry {
           // Complain about incorrect usage of Google Test facilities
           // and terminate the program since we cannot guaranty correct
           // test case setup and tear-down in this case.
-          ReportInvalidTestCaseType(test_case_name,  file, line);
+          ReportInvalidTestCaseType(test_case_name, code_location);
           posix::Abort();
         } else {
           // At this point we are sure that the object we found is of the same
@@ -10651,7 +11844,8 @@ class ParameterizedTestCaseRegistry {
       }
     }
     if (typed_test_info == NULL) {
-      typed_test_info = new ParameterizedTestCaseInfo<TestCase>(test_case_name);
+      typed_test_info = new ParameterizedTestCaseInfo<TestCase>(
+          test_case_name, code_location);
       test_case_infos_.push_back(typed_test_info);
     }
     return typed_test_info;
@@ -10719,7 +11913,7 @@ class ParameterizedTestCaseRegistry {
 // and at most 10 arguments in Combine. Please contact
 // googletestframework at googlegroups.com if you need more.
 // Please note that the number of arguments to Combine is limited
-// by the maximum arity of the implementation of tr1::tuple which is
+// by the maximum arity of the implementation of tuple which is
 // currently set at 10.
 
 #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_
@@ -10756,7 +11950,10 @@ class ValueArray1 {
   explicit ValueArray1(T1 v1) : v1_(v1) {}
 
   template <typename T>
-  operator ParamGenerator<T>() const { return ValuesIn(&v1_, &v1_ + 1); }
+  operator ParamGenerator<T>() const {
+    const T array[] = {static_cast<T>(v1_)};
+    return ValuesIn(array);
+  }
 
  private:
   // No implementation - assignment is unsupported.
@@ -13834,9 +15031,9 @@ class ValueArray50 {
 //
 template <typename T1, typename T2>
 class CartesianProductGenerator2
-    : public ParamGeneratorInterface< ::std::tr1::tuple<T1, T2> > {
+    : public ParamGeneratorInterface< ::testing::tuple<T1, T2> > {
  public:
-  typedef ::std::tr1::tuple<T1, T2> ParamType;
+  typedef ::testing::tuple<T1, T2> ParamType;
 
   CartesianProductGenerator2(const ParamGenerator<T1>& g1,
       const ParamGenerator<T2>& g2)
@@ -13949,9 +15146,9 @@ class CartesianProductGenerator2
 
 template <typename T1, typename T2, typename T3>
 class CartesianProductGenerator3
-    : public ParamGeneratorInterface< ::std::tr1::tuple<T1, T2, T3> > {
+    : public ParamGeneratorInterface< ::testing::tuple<T1, T2, T3> > {
  public:
-  typedef ::std::tr1::tuple<T1, T2, T3> ParamType;
+  typedef ::testing::tuple<T1, T2, T3> ParamType;
 
   CartesianProductGenerator3(const ParamGenerator<T1>& g1,
       const ParamGenerator<T2>& g2, const ParamGenerator<T3>& g3)
@@ -14081,9 +15278,9 @@ class CartesianProductGenerator3
 
 template <typename T1, typename T2, typename T3, typename T4>
 class CartesianProductGenerator4
-    : public ParamGeneratorInterface< ::std::tr1::tuple<T1, T2, T3, T4> > {
+    : public ParamGeneratorInterface< ::testing::tuple<T1, T2, T3, T4> > {
  public:
-  typedef ::std::tr1::tuple<T1, T2, T3, T4> ParamType;
+  typedef ::testing::tuple<T1, T2, T3, T4> ParamType;
 
   CartesianProductGenerator4(const ParamGenerator<T1>& g1,
       const ParamGenerator<T2>& g2, const ParamGenerator<T3>& g3,
@@ -14232,9 +15429,9 @@ class CartesianProductGenerator4
 
 template <typename T1, typename T2, typename T3, typename T4, typename T5>
 class CartesianProductGenerator5
-    : public ParamGeneratorInterface< ::std::tr1::tuple<T1, T2, T3, T4, T5> > {
+    : public ParamGeneratorInterface< ::testing::tuple<T1, T2, T3, T4, T5> > {
  public:
-  typedef ::std::tr1::tuple<T1, T2, T3, T4, T5> ParamType;
+  typedef ::testing::tuple<T1, T2, T3, T4, T5> ParamType;
 
   CartesianProductGenerator5(const ParamGenerator<T1>& g1,
       const ParamGenerator<T2>& g2, const ParamGenerator<T3>& g3,
@@ -14400,10 +15597,10 @@ class CartesianProductGenerator5
 template <typename T1, typename T2, typename T3, typename T4, typename T5,
     typename T6>
 class CartesianProductGenerator6
-    : public ParamGeneratorInterface< ::std::tr1::tuple<T1, T2, T3, T4, T5,
+    : public ParamGeneratorInterface< ::testing::tuple<T1, T2, T3, T4, T5,
         T6> > {
  public:
-  typedef ::std::tr1::tuple<T1, T2, T3, T4, T5, T6> ParamType;
+  typedef ::testing::tuple<T1, T2, T3, T4, T5, T6> ParamType;
 
   CartesianProductGenerator6(const ParamGenerator<T1>& g1,
       const ParamGenerator<T2>& g2, const ParamGenerator<T3>& g3,
@@ -14586,10 +15783,10 @@ class CartesianProductGenerator6
 template <typename T1, typename T2, typename T3, typename T4, typename T5,
     typename T6, typename T7>
 class CartesianProductGenerator7
-    : public ParamGeneratorInterface< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6,
+    : public ParamGeneratorInterface< ::testing::tuple<T1, T2, T3, T4, T5, T6,
         T7> > {
  public:
-  typedef ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7> ParamType;
+  typedef ::testing::tuple<T1, T2, T3, T4, T5, T6, T7> ParamType;
 
   CartesianProductGenerator7(const ParamGenerator<T1>& g1,
       const ParamGenerator<T2>& g2, const ParamGenerator<T3>& g3,
@@ -14789,10 +15986,10 @@ class CartesianProductGenerator7
 template <typename T1, typename T2, typename T3, typename T4, typename T5,
     typename T6, typename T7, typename T8>
 class CartesianProductGenerator8
-    : public ParamGeneratorInterface< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6,
+    : public ParamGeneratorInterface< ::testing::tuple<T1, T2, T3, T4, T5, T6,
         T7, T8> > {
  public:
-  typedef ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8> ParamType;
+  typedef ::testing::tuple<T1, T2, T3, T4, T5, T6, T7, T8> ParamType;
 
   CartesianProductGenerator8(const ParamGenerator<T1>& g1,
       const ParamGenerator<T2>& g2, const ParamGenerator<T3>& g3,
@@ -15011,10 +16208,10 @@ class CartesianProductGenerator8
 template <typename T1, typename T2, typename T3, typename T4, typename T5,
     typename T6, typename T7, typename T8, typename T9>
 class CartesianProductGenerator9
-    : public ParamGeneratorInterface< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6,
+    : public ParamGeneratorInterface< ::testing::tuple<T1, T2, T3, T4, T5, T6,
         T7, T8, T9> > {
  public:
-  typedef ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8, T9> ParamType;
+  typedef ::testing::tuple<T1, T2, T3, T4, T5, T6, T7, T8, T9> ParamType;
 
   CartesianProductGenerator9(const ParamGenerator<T1>& g1,
       const ParamGenerator<T2>& g2, const ParamGenerator<T3>& g3,
@@ -15250,10 +16447,10 @@ class CartesianProductGenerator9
 template <typename T1, typename T2, typename T3, typename T4, typename T5,
     typename T6, typename T7, typename T8, typename T9, typename T10>
 class CartesianProductGenerator10
-    : public ParamGeneratorInterface< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6,
+    : public ParamGeneratorInterface< ::testing::tuple<T1, T2, T3, T4, T5, T6,
         T7, T8, T9, T10> > {
  public:
-  typedef ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> ParamType;
+  typedef ::testing::tuple<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> ParamType;
 
   CartesianProductGenerator10(const ParamGenerator<T1>& g1,
       const ParamGenerator<T2>& g2, const ParamGenerator<T3>& g3,
@@ -15515,8 +16712,8 @@ class CartesianProductHolder2 {
 CartesianProductHolder2(const Generator1& g1, const Generator2& g2)
       : g1_(g1), g2_(g2) {}
   template <typename T1, typename T2>
-  operator ParamGenerator< ::std::tr1::tuple<T1, T2> >() const {
-    return ParamGenerator< ::std::tr1::tuple<T1, T2> >(
+  operator ParamGenerator< ::testing::tuple<T1, T2> >() const {
+    return ParamGenerator< ::testing::tuple<T1, T2> >(
         new CartesianProductGenerator2<T1, T2>(
         static_cast<ParamGenerator<T1> >(g1_),
         static_cast<ParamGenerator<T2> >(g2_)));
@@ -15537,8 +16734,8 @@ CartesianProductHolder3(const Generator1& g1, const Generator2& g2,
     const Generator3& g3)
       : g1_(g1), g2_(g2), g3_(g3) {}
   template <typename T1, typename T2, typename T3>
-  operator ParamGenerator< ::std::tr1::tuple<T1, T2, T3> >() const {
-    return ParamGenerator< ::std::tr1::tuple<T1, T2, T3> >(
+  operator ParamGenerator< ::testing::tuple<T1, T2, T3> >() const {
+    return ParamGenerator< ::testing::tuple<T1, T2, T3> >(
         new CartesianProductGenerator3<T1, T2, T3>(
         static_cast<ParamGenerator<T1> >(g1_),
         static_cast<ParamGenerator<T2> >(g2_),
@@ -15562,8 +16759,8 @@ CartesianProductHolder4(const Generator1& g1, const Generator2& g2,
     const Generator3& g3, const Generator4& g4)
       : g1_(g1), g2_(g2), g3_(g3), g4_(g4) {}
   template <typename T1, typename T2, typename T3, typename T4>
-  operator ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4> >() const {
-    return ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4> >(
+  operator ParamGenerator< ::testing::tuple<T1, T2, T3, T4> >() const {
+    return ParamGenerator< ::testing::tuple<T1, T2, T3, T4> >(
         new CartesianProductGenerator4<T1, T2, T3, T4>(
         static_cast<ParamGenerator<T1> >(g1_),
         static_cast<ParamGenerator<T2> >(g2_),
@@ -15589,8 +16786,8 @@ CartesianProductHolder5(const Generator1& g1, const Generator2& g2,
     const Generator3& g3, const Generator4& g4, const Generator5& g5)
       : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5) {}
   template <typename T1, typename T2, typename T3, typename T4, typename T5>
-  operator ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5> >() const {
-    return ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5> >(
+  operator ParamGenerator< ::testing::tuple<T1, T2, T3, T4, T5> >() const {
+    return ParamGenerator< ::testing::tuple<T1, T2, T3, T4, T5> >(
         new CartesianProductGenerator5<T1, T2, T3, T4, T5>(
         static_cast<ParamGenerator<T1> >(g1_),
         static_cast<ParamGenerator<T2> >(g2_),
@@ -15620,8 +16817,8 @@ CartesianProductHolder6(const Generator1& g1, const Generator2& g2,
       : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6) {}
   template <typename T1, typename T2, typename T3, typename T4, typename T5,
       typename T6>
-  operator ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6> >() const {
-    return ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6> >(
+  operator ParamGenerator< ::testing::tuple<T1, T2, T3, T4, T5, T6> >() const {
+    return ParamGenerator< ::testing::tuple<T1, T2, T3, T4, T5, T6> >(
         new CartesianProductGenerator6<T1, T2, T3, T4, T5, T6>(
         static_cast<ParamGenerator<T1> >(g1_),
         static_cast<ParamGenerator<T2> >(g2_),
@@ -15653,9 +16850,9 @@ CartesianProductHolder7(const Generator1& g1, const Generator2& g2,
       : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7) {}
   template <typename T1, typename T2, typename T3, typename T4, typename T5,
       typename T6, typename T7>
-  operator ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6,
+  operator ParamGenerator< ::testing::tuple<T1, T2, T3, T4, T5, T6,
       T7> >() const {
-    return ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7> >(
+    return ParamGenerator< ::testing::tuple<T1, T2, T3, T4, T5, T6, T7> >(
         new CartesianProductGenerator7<T1, T2, T3, T4, T5, T6, T7>(
         static_cast<ParamGenerator<T1> >(g1_),
         static_cast<ParamGenerator<T2> >(g2_),
@@ -15691,9 +16888,9 @@ CartesianProductHolder8(const Generator1& g1, const Generator2& g2,
           g8_(g8) {}
   template <typename T1, typename T2, typename T3, typename T4, typename T5,
       typename T6, typename T7, typename T8>
-  operator ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7,
+  operator ParamGenerator< ::testing::tuple<T1, T2, T3, T4, T5, T6, T7,
       T8> >() const {
-    return ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8> >(
+    return ParamGenerator< ::testing::tuple<T1, T2, T3, T4, T5, T6, T7, T8> >(
         new CartesianProductGenerator8<T1, T2, T3, T4, T5, T6, T7, T8>(
         static_cast<ParamGenerator<T1> >(g1_),
         static_cast<ParamGenerator<T2> >(g2_),
@@ -15732,9 +16929,9 @@ CartesianProductHolder9(const Generator1& g1, const Generator2& g2,
           g9_(g9) {}
   template <typename T1, typename T2, typename T3, typename T4, typename T5,
       typename T6, typename T7, typename T8, typename T9>
-  operator ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8,
+  operator ParamGenerator< ::testing::tuple<T1, T2, T3, T4, T5, T6, T7, T8,
       T9> >() const {
-    return ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8,
+    return ParamGenerator< ::testing::tuple<T1, T2, T3, T4, T5, T6, T7, T8,
         T9> >(
         new CartesianProductGenerator9<T1, T2, T3, T4, T5, T6, T7, T8, T9>(
         static_cast<ParamGenerator<T1> >(g1_),
@@ -15776,10 +16973,10 @@ CartesianProductHolder10(const Generator1& g1, const Generator2& g2,
           g9_(g9), g10_(g10) {}
   template <typename T1, typename T2, typename T3, typename T4, typename T5,
       typename T6, typename T7, typename T8, typename T9, typename T10>
-  operator ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8,
-      T9, T10> >() const {
-    return ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8,
-        T9, T10> >(
+  operator ParamGenerator< ::testing::tuple<T1, T2, T3, T4, T5, T6, T7, T8, T9,
+      T10> >() const {
+    return ParamGenerator< ::testing::tuple<T1, T2, T3, T4, T5, T6, T7, T8, T9,
+        T10> >(
         new CartesianProductGenerator10<T1, T2, T3, T4, T5, T6, T7, T8, T9,
             T10>(
         static_cast<ParamGenerator<T1> >(g1_),
@@ -17014,14 +18211,17 @@ internal::CartesianProductHolder10<Generator1, Generator2, Generator3,
     static int AddToRegistry() { \
       ::testing::UnitTest::GetInstance()->parameterized_test_registry(). \
           GetTestCasePatternHolder<test_case_name>(\
-              #test_case_name, __FILE__, __LINE__)->AddTestPattern(\
-                  #test_case_name, \
-                  #test_name, \
-                  new ::testing::internal::TestMetaFactory< \
-                      GTEST_TEST_CLASS_NAME_(test_case_name, test_name)>()); \
+              #test_case_name, \
+              ::testing::internal::CodeLocation(\
+                  __FILE__, __LINE__))->AddTestPattern(\
+                      #test_case_name, \
+                      #test_name, \
+                      new ::testing::internal::TestMetaFactory< \
+                          GTEST_TEST_CLASS_NAME_(\
+                              test_case_name, test_name)>()); \
       return 0; \
     } \
-    static int gtest_registering_dummy_; \
+    static int gtest_registering_dummy_ GTEST_ATTRIBUTE_UNUSED_; \
     GTEST_DISALLOW_COPY_AND_ASSIGN_(\
         GTEST_TEST_CLASS_NAME_(test_case_name, test_name)); \
   }; \
@@ -17030,16 +18230,36 @@ internal::CartesianProductHolder10<Generator1, Generator2, Generator3,
       GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::AddToRegistry(); \
   void GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::TestBody()
 
-# define INSTANTIATE_TEST_CASE_P(prefix, test_case_name, generator) \
+// The optional last argument to INSTANTIATE_TEST_CASE_P allows the user
+// to specify a function or functor that generates custom test name suffixes
+// based on the test parameters. The function should accept one argument of
+// type testing::TestParamInfo<class ParamType>, and return std::string.
+//
+// testing::PrintToStringParamName is a builtin test suffix generator that
+// returns the value of testing::PrintToString(GetParam()). It does not work
+// for std::string or C strings.
+//
+// Note: test names must be non-empty, unique, and may only contain ASCII
+// alphanumeric characters or underscore.
+
+# define INSTANTIATE_TEST_CASE_P(prefix, test_case_name, generator, ...) \
   ::testing::internal::ParamGenerator<test_case_name::ParamType> \
       gtest_##prefix##test_case_name##_EvalGenerator_() { return generator; } \
-  int gtest_##prefix##test_case_name##_dummy_ = \
+  ::std::string gtest_##prefix##test_case_name##_EvalGenerateName_( \
+      const ::testing::TestParamInfo<test_case_name::ParamType>& info) { \
+    return ::testing::internal::GetParamNameGen<test_case_name::ParamType> \
+        (__VA_ARGS__)(info); \
+  } \
+  int gtest_##prefix##test_case_name##_dummy_ GTEST_ATTRIBUTE_UNUSED_ = \
       ::testing::UnitTest::GetInstance()->parameterized_test_registry(). \
           GetTestCasePatternHolder<test_case_name>(\
-              #test_case_name, __FILE__, __LINE__)->AddTestCaseInstantiation(\
-                  #prefix, \
-                  &gtest_##prefix##test_case_name##_EvalGenerator_, \
-                  __FILE__, __LINE__)
+              #test_case_name, \
+              ::testing::internal::CodeLocation(\
+                  __FILE__, __LINE__))->AddTestCaseInstantiation(\
+                      #prefix, \
+                      &gtest_##prefix##test_case_name##_EvalGenerator_, \
+                      &gtest_##prefix##test_case_name##_EvalGenerateName_, \
+                      __FILE__, __LINE__)
 
 }  // namespace testing
 
@@ -17462,7 +18682,8 @@ INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, MyTypes);
           ::testing::internal::TemplateSel< \
               GTEST_TEST_CLASS_NAME_(CaseName, TestName)>, \
           GTEST_TYPE_PARAMS_(CaseName)>::Register(\
-              "", #CaseName, #TestName, 0); \
+              "", ::testing::internal::CodeLocation(__FILE__, __LINE__), \
+              #CaseName, #TestName, 0); \
   template <typename gtest_TypeParam_> \
   void GTEST_TEST_CLASS_NAME_(CaseName, TestName)<gtest_TypeParam_>::TestBody()
 
@@ -17533,7 +18754,10 @@ INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, MyTypes);
       ::testing::internal::TypeParameterizedTestCase<CaseName, \
           GTEST_CASE_NAMESPACE_(CaseName)::gtest_AllTests_, \
           ::testing::internal::TypeList< Types >::type>::Register(\
-              #Prefix, #CaseName, GTEST_REGISTERED_TEST_NAMES_(CaseName))
+              #Prefix, \
+              ::testing::internal::CodeLocation(__FILE__, __LINE__), \
+              &GTEST_TYPED_TEST_CASE_P_STATE_(CaseName), \
+              #CaseName, GTEST_REGISTERED_TEST_NAMES_(CaseName))
 
 #endif  // GTEST_HAS_TYPED_TEST_P
 
@@ -17544,14 +18768,14 @@ INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, MyTypes);
 // class ::string, which has the same interface as ::std::string, but
 // has a different implementation.
 //
-// The user can define GTEST_HAS_GLOBAL_STRING to 1 to indicate that
+// You can define GTEST_HAS_GLOBAL_STRING to 1 to indicate that
 // ::string is available AND is a distinct type to ::std::string, or
 // define it to 0 to indicate otherwise.
 //
-// If the user's ::std::string and ::string are the same class due to
-// aliasing, he should define GTEST_HAS_GLOBAL_STRING to 0.
+// If ::std::string and ::string are the same class on your platform
+// due to aliasing, you should define GTEST_HAS_GLOBAL_STRING to 0.
 //
-// If the user doesn't define GTEST_HAS_GLOBAL_STRING, it is defined
+// If you do not define GTEST_HAS_GLOBAL_STRING, it is defined
 // heuristically.
 
 namespace testing {
@@ -17735,8 +18959,31 @@ class GTEST_API_ AssertionResult {
   // Copy constructor.
   // Used in EXPECT_TRUE/FALSE(assertion_result).
   AssertionResult(const AssertionResult& other);
+
+  GTEST_DISABLE_MSC_WARNINGS_PUSH_(4800 /* forcing value to bool */)
+
   // Used in the EXPECT_TRUE/FALSE(bool_expression).
-  explicit AssertionResult(bool success) : success_(success) {}
+  //
+  // T must be contextually convertible to bool.
+  //
+  // The second parameter prevents this overload from being considered if
+  // the argument is implicitly convertible to AssertionResult. In that case
+  // we want AssertionResult's copy constructor to be used.
+  template <typename T>
+  explicit AssertionResult(
+      const T& success,
+      typename internal::EnableIf<
+          !internal::ImplicitlyConvertible<T, AssertionResult>::value>::type*
+          /*enabler*/ = NULL)
+      : success_(success) {}
+
+  GTEST_DISABLE_MSC_WARNINGS_POP_()
+
+  // Assignment operator.
+  AssertionResult& operator=(AssertionResult other) {
+    swap(other);
+    return *this;
+  }
 
   // Returns true iff the assertion succeeded.
   operator bool() const { return success_; }  // NOLINT
@@ -17777,6 +19024,9 @@ class GTEST_API_ AssertionResult {
     message_->append(a_message.GetString().c_str());
   }
 
+  // Swap the contents of this AssertionResult with other.
+  void swap(AssertionResult& other);
+
   // Stores result of the assertion predicate.
   bool success_;
   // Stores the message describing the condition in case the expectation
@@ -17784,8 +19034,6 @@ class GTEST_API_ AssertionResult {
   // Referenced via a pointer to avoid taking too much stack frame space
   // with test assertions.
   internal::scoped_ptr< ::std::string> message_;
-
-  GTEST_DISALLOW_ASSIGN_(AssertionResult);
 };
 
 // Makes a successful assertion result.
@@ -17812,8 +19060,8 @@ GTEST_API_ AssertionResult AssertionFailure(const Message& msg);
 //
 //   class FooTest : public testing::Test {
 //    protected:
-//     virtual void SetUp() { ... }
-//     virtual void TearDown() { ... }
+//     void SetUp() override { ... }
+//     void TearDown() override { ... }
 //     ...
 //   };
 //
@@ -17905,20 +19153,19 @@ class GTEST_API_ Test {
   // internal method to avoid clashing with names used in user TESTs.
   void DeleteSelf_() { delete this; }
 
-  // Uses a GTestFlagSaver to save and restore all Google Test flags.
-  const internal::GTestFlagSaver* const gtest_flag_saver_;
+  const internal::scoped_ptr< GTEST_FLAG_SAVER_ > gtest_flag_saver_;
 
-  // Often a user mis-spells SetUp() as Setup() and spends a long time
+  // Often a user misspells SetUp() as Setup() and spends a long time
   // wondering why it is never called by Google Test.  The declaration of
   // the following method is solely for catching such an error at
   // compile time:
   //
   //   - The return type is deliberately chosen to be not void, so it
-  //   will be a conflict if a user declares void Setup() in his test
-  //   fixture.
+  //   will be a conflict if void Setup() is declared in the user's
+  //   test fixture.
   //
   //   - This method is private, so it will be another compiler error
-  //   if a user calls it from his test fixture.
+  //   if the method is called from the user's test fixture.
   //
   // DO NOT OVERRIDE THIS FUNCTION.
   //
@@ -18123,6 +19370,12 @@ class GTEST_API_ TestInfo {
     return NULL;
   }
 
+  // Returns the file name where this test is defined.
+  const char* file() const { return location_.file.c_str(); }
+
+  // Returns the line where this test is defined.
+  int line() const { return location_.line; }
+
   // Returns true if this test should run, that is if the test is not
   // disabled (or it is disabled but the also_run_disabled_tests flag has
   // been specified) and its full name matches the user-specified filter.
@@ -18165,6 +19418,7 @@ class GTEST_API_ TestInfo {
       const char* name,
       const char* type_param,
       const char* value_param,
+      internal::CodeLocation code_location,
       internal::TypeId fixture_class_id,
       Test::SetUpTestCaseFunc set_up_tc,
       Test::TearDownTestCaseFunc tear_down_tc,
@@ -18176,6 +19430,7 @@ class GTEST_API_ TestInfo {
            const std::string& name,
            const char* a_type_param,   // NULL if not a type-parameterized test
            const char* a_value_param,  // NULL if not a value-parameterized test
+           internal::CodeLocation a_code_location,
            internal::TypeId fixture_class_id,
            internal::TestFactoryBase* factory);
 
@@ -18202,6 +19457,7 @@ class GTEST_API_ TestInfo {
   // Text representation of the value parameter, or NULL if this is not a
   // value-parameterized test.
   const internal::scoped_ptr<const ::std::string> value_param_;
+  internal::CodeLocation location_;
   const internal::TypeId fixture_class_id_;   // ID of the test fixture class
   bool should_run_;                 // True iff this test should run
   bool is_disabled_;                // True iff this test is disabled
@@ -18401,7 +19657,7 @@ class GTEST_API_ TestCase {
 };
 
 // An Environment object is capable of setting up and tearing down an
-// environment.  The user should subclass this to define his own
+// environment.  You should subclass this to define your own
 // environment(s).
 //
 // An Environment object does the set-up and tear-down in virtual
@@ -18813,137 +20069,42 @@ GTEST_API_ void InitGoogleTest(int* argc, wchar_t** argv);
 
 namespace internal {
 
-// FormatForComparison<ToPrint, OtherOperand>::Format(value) formats a
-// value of type ToPrint that is an operand of a comparison assertion
-// (e.g. ASSERT_EQ).  OtherOperand is the type of the other operand in
-// the comparison, and is used to help determine the best way to
-// format the value.  In particular, when the value is a C string
-// (char pointer) and the other operand is an STL string object, we
-// want to format the C string as a string, since we know it is
-// compared by value with the string object.  If the value is a char
-// pointer but the other operand is not an STL string object, we don't
-// know whether the pointer is supposed to point to a NUL-terminated
-// string, and thus want to print it as a pointer to be safe.
-//
-// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
-
-// The default case.
-template <typename ToPrint, typename OtherOperand>
-class FormatForComparison {
- public:
-  static ::std::string Format(const ToPrint& value) {
-    return ::testing::PrintToString(value);
-  }
-};
-
-// Array.
-template <typename ToPrint, size_t N, typename OtherOperand>
-class FormatForComparison<ToPrint[N], OtherOperand> {
- public:
-  static ::std::string Format(const ToPrint* value) {
-    return FormatForComparison<const ToPrint*, OtherOperand>::Format(value);
-  }
-};
-
-// By default, print C string as pointers to be safe, as we don't know
-// whether they actually point to a NUL-terminated string.
-
-#define GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(CharType)                \
-  template <typename OtherOperand>                                      \
-  class FormatForComparison<CharType*, OtherOperand> {                  \
-   public:                                                              \
-    static ::std::string Format(CharType* value) {                      \
-      return ::testing::PrintToString(static_cast<const void*>(value)); \
-    }                                                                   \
-  }
-
-GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(char);
-GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(const char);
-GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(wchar_t);
-GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(const wchar_t);
-
-#undef GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_
-
-// If a C string is compared with an STL string object, we know it's meant
-// to point to a NUL-terminated string, and thus can print it as a string.
-
-#define GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(CharType, OtherStringType) \
-  template <>                                                           \
-  class FormatForComparison<CharType*, OtherStringType> {               \
-   public:                                                              \
-    static ::std::string Format(CharType* value) {                      \
-      return ::testing::PrintToString(value);                           \
-    }                                                                   \
-  }
-
-GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(char, ::std::string);
-GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const char, ::std::string);
-
-#if GTEST_HAS_GLOBAL_STRING
-GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(char, ::string);
-GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const char, ::string);
-#endif
-
-#if GTEST_HAS_GLOBAL_WSTRING
-GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(wchar_t, ::wstring);
-GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const wchar_t, ::wstring);
-#endif
-
-#if GTEST_HAS_STD_WSTRING
-GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(wchar_t, ::std::wstring);
-GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const wchar_t, ::std::wstring);
-#endif
-
-#undef GTEST_IMPL_FORMAT_C_STRING_AS_STRING_
-
-// Formats a comparison assertion (e.g. ASSERT_EQ, EXPECT_LT, and etc)
-// operand to be used in a failure message.  The type (but not value)
-// of the other operand may affect the format.  This allows us to
-// print a char* as a raw pointer when it is compared against another
-// char* or void*, and print it as a C string when it is compared
-// against an std::string object, for example.
-//
-// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+// Separate the error generating code from the code path to reduce the stack
+// frame size of CmpHelperEQ. This helps reduce the overhead of some sanitizers
+// when calling EXPECT_* in a tight loop.
 template <typename T1, typename T2>
-std::string FormatForComparisonFailureMessage(
-    const T1& value, const T2& /* other_operand */) {
-  return FormatForComparison<T1, T2>::Format(value);
+AssertionResult CmpHelperEQFailure(const char* lhs_expression,
+                                   const char* rhs_expression,
+                                   const T1& lhs, const T2& rhs) {
+  return EqFailure(lhs_expression,
+                   rhs_expression,
+                   FormatForComparisonFailureMessage(lhs, rhs),
+                   FormatForComparisonFailureMessage(rhs, lhs),
+                   false);
 }
 
 // The helper function for {ASSERT|EXPECT}_EQ.
 template <typename T1, typename T2>
-AssertionResult CmpHelperEQ(const char* expected_expression,
-                            const char* actual_expression,
-                            const T1& expected,
-                            const T2& actual) {
-#ifdef _MSC_VER
-# pragma warning(push)          // Saves the current warning state.
-# pragma warning(disable:4389)  // Temporarily disables warning on
-                                // signed/unsigned mismatch.
-#endif
-
-  if (expected == actual) {
+AssertionResult CmpHelperEQ(const char* lhs_expression,
+                            const char* rhs_expression,
+                            const T1& lhs,
+                            const T2& rhs) {
+GTEST_DISABLE_MSC_WARNINGS_PUSH_(4389 /* signed/unsigned mismatch */)
+  if (lhs == rhs) {
     return AssertionSuccess();
   }
+GTEST_DISABLE_MSC_WARNINGS_POP_()
 
-#ifdef _MSC_VER
-# pragma warning(pop)          // Restores the warning state.
-#endif
-
-  return EqFailure(expected_expression,
-                   actual_expression,
-                   FormatForComparisonFailureMessage(expected, actual),
-                   FormatForComparisonFailureMessage(actual, expected),
-                   false);
+  return CmpHelperEQFailure(lhs_expression, rhs_expression, lhs, rhs);
 }
 
 // With this overloaded version, we allow anonymous enums to be used
 // in {ASSERT|EXPECT}_EQ when compiled with gcc 4, as anonymous enums
 // can be implicitly cast to BiggestInt.
-GTEST_API_ AssertionResult CmpHelperEQ(const char* expected_expression,
-                                       const char* actual_expression,
-                                       BiggestInt expected,
-                                       BiggestInt actual);
+GTEST_API_ AssertionResult CmpHelperEQ(const char* lhs_expression,
+                                       const char* rhs_expression,
+                                       BiggestInt lhs,
+                                       BiggestInt rhs);
 
 // The helper class for {ASSERT|EXPECT}_EQ.  The template argument
 // lhs_is_null_literal is true iff the first argument to ASSERT_EQ()
@@ -18954,12 +20115,11 @@ class EqHelper {
  public:
   // This templatized version is for the general case.
   template <typename T1, typename T2>
-  static AssertionResult Compare(const char* expected_expression,
-                                 const char* actual_expression,
-                                 const T1& expected,
-                                 const T2& actual) {
-    return CmpHelperEQ(expected_expression, actual_expression, expected,
-                       actual);
+  static AssertionResult Compare(const char* lhs_expression,
+                                 const char* rhs_expression,
+                                 const T1& lhs,
+                                 const T2& rhs) {
+    return CmpHelperEQ(lhs_expression, rhs_expression, lhs, rhs);
   }
 
   // With this overloaded version, we allow anonymous enums to be used
@@ -18968,12 +20128,11 @@ class EqHelper {
   //
   // Even though its body looks the same as the above version, we
   // cannot merge the two, as it will make anonymous enums unhappy.
-  static AssertionResult Compare(const char* expected_expression,
-                                 const char* actual_expression,
-                                 BiggestInt expected,
-                                 BiggestInt actual) {
-    return CmpHelperEQ(expected_expression, actual_expression, expected,
-                       actual);
+  static AssertionResult Compare(const char* lhs_expression,
+                                 const char* rhs_expression,
+                                 BiggestInt lhs,
+                                 BiggestInt rhs) {
+    return CmpHelperEQ(lhs_expression, rhs_expression, lhs, rhs);
   }
 };
 
@@ -18988,40 +20147,52 @@ class EqHelper<true> {
   // EXPECT_EQ(false, a_bool).
   template <typename T1, typename T2>
   static AssertionResult Compare(
-      const char* expected_expression,
-      const char* actual_expression,
-      const T1& expected,
-      const T2& actual,
+      const char* lhs_expression,
+      const char* rhs_expression,
+      const T1& lhs,
+      const T2& rhs,
       // The following line prevents this overload from being considered if T2
       // is not a pointer type.  We need this because ASSERT_EQ(NULL, my_ptr)
       // expands to Compare("", "", NULL, my_ptr), which requires a conversion
       // to match the Secret* in the other overload, which would otherwise make
       // this template match better.
       typename EnableIf<!is_pointer<T2>::value>::type* = 0) {
-    return CmpHelperEQ(expected_expression, actual_expression, expected,
-                       actual);
+    return CmpHelperEQ(lhs_expression, rhs_expression, lhs, rhs);
   }
 
   // This version will be picked when the second argument to ASSERT_EQ() is a
   // pointer, e.g. ASSERT_EQ(NULL, a_pointer).
   template <typename T>
   static AssertionResult Compare(
-      const char* expected_expression,
-      const char* actual_expression,
+      const char* lhs_expression,
+      const char* rhs_expression,
       // We used to have a second template parameter instead of Secret*.  That
       // template parameter would deduce to 'long', making this a better match
       // than the first overload even without the first overload's EnableIf.
       // Unfortunately, gcc with -Wconversion-null warns when "passing NULL to
       // non-pointer argument" (even a deduced integral argument), so the old
       // implementation caused warnings in user code.
-      Secret* /* expected (NULL) */,
-      T* actual) {
-    // We already know that 'expected' is a null pointer.
-    return CmpHelperEQ(expected_expression, actual_expression,
-                       static_cast<T*>(NULL), actual);
+      Secret* /* lhs (NULL) */,
+      T* rhs) {
+    // We already know that 'lhs' is a null pointer.
+    return CmpHelperEQ(lhs_expression, rhs_expression,
+                       static_cast<T*>(NULL), rhs);
   }
 };
 
+// Separate the error generating code from the code path to reduce the stack
+// frame size of CmpHelperOP. This helps reduce the overhead of some sanitizers
+// when calling EXPECT_OP in a tight loop.
+template <typename T1, typename T2>
+AssertionResult CmpHelperOpFailure(const char* expr1, const char* expr2,
+                                   const T1& val1, const T2& val2,
+                                   const char* op) {
+  return AssertionFailure()
+         << "Expected: (" << expr1 << ") " << op << " (" << expr2
+         << "), actual: " << FormatForComparisonFailureMessage(val1, val2)
+         << " vs " << FormatForComparisonFailureMessage(val2, val1);
+}
+
 // A macro for implementing the helper functions needed to implement
 // ASSERT_?? and EXPECT_??.  It is here just to avoid copy-and-paste
 // of similar code.
@@ -19032,6 +20203,7 @@ class EqHelper<true> {
 // with gcc 4.
 //
 // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
+
 #define GTEST_IMPL_CMP_HELPER_(op_name, op)\
 template <typename T1, typename T2>\
 AssertionResult CmpHelper##op_name(const char* expr1, const char* expr2, \
@@ -19039,10 +20211,7 @@ AssertionResult CmpHelper##op_name(const char* expr1, const char* expr2, \
   if (val1 op val2) {\
     return AssertionSuccess();\
   } else {\
-    return AssertionFailure() \
-        << "Expected: (" << expr1 << ") " #op " (" << expr2\
-        << "), actual: " << FormatForComparisonFailureMessage(val1, val2)\
-        << " vs " << FormatForComparisonFailureMessage(val2, val1);\
+    return CmpHelperOpFailure(expr1, expr2, val1, val2, #op);\
   }\
 }\
 GTEST_API_ AssertionResult CmpHelper##op_name(\
@@ -19066,18 +20235,18 @@ GTEST_IMPL_CMP_HELPER_(GT, >);
 // The helper function for {ASSERT|EXPECT}_STREQ.
 //
 // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
-GTEST_API_ AssertionResult CmpHelperSTREQ(const char* expected_expression,
-                                          const char* actual_expression,
-                                          const char* expected,
-                                          const char* actual);
+GTEST_API_ AssertionResult CmpHelperSTREQ(const char* s1_expression,
+                                          const char* s2_expression,
+                                          const char* s1,
+                                          const char* s2);
 
 // The helper function for {ASSERT|EXPECT}_STRCASEEQ.
 //
 // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
-GTEST_API_ AssertionResult CmpHelperSTRCASEEQ(const char* expected_expression,
-                                              const char* actual_expression,
-                                              const char* expected,
-                                              const char* actual);
+GTEST_API_ AssertionResult CmpHelperSTRCASEEQ(const char* s1_expression,
+                                              const char* s2_expression,
+                                              const char* s1,
+                                              const char* s2);
 
 // The helper function for {ASSERT|EXPECT}_STRNE.
 //
@@ -19099,10 +20268,10 @@ GTEST_API_ AssertionResult CmpHelperSTRCASENE(const char* s1_expression,
 // Helper function for *_STREQ on wide strings.
 //
 // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
-GTEST_API_ AssertionResult CmpHelperSTREQ(const char* expected_expression,
-                                          const char* actual_expression,
-                                          const wchar_t* expected,
-                                          const wchar_t* actual);
+GTEST_API_ AssertionResult CmpHelperSTREQ(const char* s1_expression,
+                                          const char* s2_expression,
+                                          const wchar_t* s1,
+                                          const wchar_t* s2);
 
 // Helper function for *_STRNE on wide strings.
 //
@@ -19160,28 +20329,28 @@ namespace internal {
 //
 // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
 template <typename RawType>
-AssertionResult CmpHelperFloatingPointEQ(const char* expected_expression,
-                                         const char* actual_expression,
-                                         RawType expected,
-                                         RawType actual) {
-  const FloatingPoint<RawType> lhs(expected), rhs(actual);
+AssertionResult CmpHelperFloatingPointEQ(const char* lhs_expression,
+                                         const char* rhs_expression,
+                                         RawType lhs_value,
+                                         RawType rhs_value) {
+  const FloatingPoint<RawType> lhs(lhs_value), rhs(rhs_value);
 
   if (lhs.AlmostEquals(rhs)) {
     return AssertionSuccess();
   }
 
-  ::std::stringstream expected_ss;
-  expected_ss << std::setprecision(std::numeric_limits<RawType>::digits10 + 2)
-              << expected;
+  ::std::stringstream lhs_ss;
+  lhs_ss << std::setprecision(std::numeric_limits<RawType>::digits10 + 2)
+         << lhs_value;
 
-  ::std::stringstream actual_ss;
-  actual_ss << std::setprecision(std::numeric_limits<RawType>::digits10 + 2)
-            << actual;
+  ::std::stringstream rhs_ss;
+  rhs_ss << std::setprecision(std::numeric_limits<RawType>::digits10 + 2)
+         << rhs_value;
 
-  return EqFailure(expected_expression,
-                   actual_expression,
-                   StringStreamToString(&expected_ss),
-                   StringStreamToString(&actual_ss),
+  return EqFailure(lhs_expression,
+                   rhs_expression,
+                   StringStreamToString(&lhs_ss),
+                   StringStreamToString(&rhs_ss),
                    false);
 }
 
@@ -19389,13 +20558,13 @@ class TestWithParam : public Test, public WithParamInterface<T> {
 // AssertionResult. For more information on how to use AssertionResult with
 // these macros see comments on that class.
 #define EXPECT_TRUE(condition) \
-  GTEST_TEST_BOOLEAN_(condition, #condition, false, true, \
+  GTEST_TEST_BOOLEAN_((condition), #condition, false, true, \
                       GTEST_NONFATAL_FAILURE_)
 #define EXPECT_FALSE(condition) \
   GTEST_TEST_BOOLEAN_(!(condition), #condition, true, false, \
                       GTEST_NONFATAL_FAILURE_)
 #define ASSERT_TRUE(condition) \
-  GTEST_TEST_BOOLEAN_(condition, #condition, false, true, \
+  GTEST_TEST_BOOLEAN_((condition), #condition, false, true, \
                       GTEST_FATAL_FAILURE_)
 #define ASSERT_FALSE(condition) \
   GTEST_TEST_BOOLEAN_(!(condition), #condition, true, false, \
@@ -19764,12 +20933,12 @@ AssertionResult AssertPred5Helper(const char* pred_text,
 
 // Macros for testing equalities and inequalities.
 //
-//    * {ASSERT|EXPECT}_EQ(expected, actual): Tests that expected == actual
-//    * {ASSERT|EXPECT}_NE(v1, v2):           Tests that v1 != v2
-//    * {ASSERT|EXPECT}_LT(v1, v2):           Tests that v1 < v2
-//    * {ASSERT|EXPECT}_LE(v1, v2):           Tests that v1 <= v2
-//    * {ASSERT|EXPECT}_GT(v1, v2):           Tests that v1 > v2
-//    * {ASSERT|EXPECT}_GE(v1, v2):           Tests that v1 >= v2
+//    * {ASSERT|EXPECT}_EQ(v1, v2): Tests that v1 == v2
+//    * {ASSERT|EXPECT}_NE(v1, v2): Tests that v1 != v2
+//    * {ASSERT|EXPECT}_LT(v1, v2): Tests that v1 < v2
+//    * {ASSERT|EXPECT}_LE(v1, v2): Tests that v1 <= v2
+//    * {ASSERT|EXPECT}_GT(v1, v2): Tests that v1 > v2
+//    * {ASSERT|EXPECT}_GE(v1, v2): Tests that v1 >= v2
 //
 // When they are not, Google Test prints both the tested expressions and
 // their actual values.  The values must be compatible built-in types,
@@ -19791,8 +20960,8 @@ AssertionResult AssertPred5Helper(const char* pred_text,
 //   are related, not how their content is related.  To compare two C
 //   strings by content, use {ASSERT|EXPECT}_STR*().
 //
-//   3. {ASSERT|EXPECT}_EQ(expected, actual) is preferred to
-//   {ASSERT|EXPECT}_TRUE(expected == actual), as the former tells you
+//   3. {ASSERT|EXPECT}_EQ(v1, v2) is preferred to
+//   {ASSERT|EXPECT}_TRUE(v1 == v2), as the former tells you
 //   what the actual value is when it fails, and similarly for the
 //   other comparisons.
 //
@@ -19808,12 +20977,12 @@ AssertionResult AssertPred5Helper(const char* pred_text,
 //   ASSERT_LT(i, array_size);
 //   ASSERT_GT(records.size(), 0) << "There is no record left.";
 
-#define EXPECT_EQ(expected, actual) \
+#define EXPECT_EQ(val1, val2) \
   EXPECT_PRED_FORMAT2(::testing::internal:: \
-                      EqHelper<GTEST_IS_NULL_LITERAL_(expected)>::Compare, \
-                      expected, actual)
-#define EXPECT_NE(expected, actual) \
-  EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperNE, expected, actual)
+                      EqHelper<GTEST_IS_NULL_LITERAL_(val1)>::Compare, \
+                      val1, val2)
+#define EXPECT_NE(val1, val2) \
+  EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperNE, val1, val2)
 #define EXPECT_LE(val1, val2) \
   EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperLE, val1, val2)
 #define EXPECT_LT(val1, val2) \
@@ -19823,10 +20992,10 @@ AssertionResult AssertPred5Helper(const char* pred_text,
 #define EXPECT_GT(val1, val2) \
   EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperGT, val1, val2)
 
-#define GTEST_ASSERT_EQ(expected, actual) \
+#define GTEST_ASSERT_EQ(val1, val2) \
   ASSERT_PRED_FORMAT2(::testing::internal:: \
-                      EqHelper<GTEST_IS_NULL_LITERAL_(expected)>::Compare, \
-                      expected, actual)
+                      EqHelper<GTEST_IS_NULL_LITERAL_(val1)>::Compare, \
+                      val1, val2)
 #define GTEST_ASSERT_NE(val1, val2) \
   ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperNE, val1, val2)
 #define GTEST_ASSERT_LE(val1, val2) \
@@ -19881,29 +21050,29 @@ AssertionResult AssertPred5Helper(const char* pred_text,
 //
 // These macros evaluate their arguments exactly once.
 
-#define EXPECT_STREQ(expected, actual) \
-  EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTREQ, expected, actual)
+#define EXPECT_STREQ(s1, s2) \
+  EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTREQ, s1, s2)
 #define EXPECT_STRNE(s1, s2) \
   EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTRNE, s1, s2)
-#define EXPECT_STRCASEEQ(expected, actual) \
-  EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASEEQ, expected, actual)
+#define EXPECT_STRCASEEQ(s1, s2) \
+  EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASEEQ, s1, s2)
 #define EXPECT_STRCASENE(s1, s2)\
   EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASENE, s1, s2)
 
-#define ASSERT_STREQ(expected, actual) \
-  ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTREQ, expected, actual)
+#define ASSERT_STREQ(s1, s2) \
+  ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTREQ, s1, s2)
 #define ASSERT_STRNE(s1, s2) \
   ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTRNE, s1, s2)
-#define ASSERT_STRCASEEQ(expected, actual) \
-  ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASEEQ, expected, actual)
+#define ASSERT_STRCASEEQ(s1, s2) \
+  ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASEEQ, s1, s2)
 #define ASSERT_STRCASENE(s1, s2)\
   ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASENE, s1, s2)
 
 // Macros for comparing floating-point numbers.
 //
-//    * {ASSERT|EXPECT}_FLOAT_EQ(expected, actual):
+//    * {ASSERT|EXPECT}_FLOAT_EQ(val1, val2):
 //         Tests that two float values are almost equal.
-//    * {ASSERT|EXPECT}_DOUBLE_EQ(expected, actual):
+//    * {ASSERT|EXPECT}_DOUBLE_EQ(val1, val2):
 //         Tests that two double values are almost equal.
 //    * {ASSERT|EXPECT}_NEAR(v1, v2, abs_error):
 //         Tests that v1 and v2 are within the given distance to each other.
@@ -19913,21 +21082,21 @@ AssertionResult AssertPred5Helper(const char* pred_text,
 // FloatingPoint template class in gtest-internal.h if you are
 // interested in the implementation details.
 
-#define EXPECT_FLOAT_EQ(expected, actual)\
+#define EXPECT_FLOAT_EQ(val1, val2)\
   EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ<float>, \
-                      expected, actual)
+                      val1, val2)
 
-#define EXPECT_DOUBLE_EQ(expected, actual)\
+#define EXPECT_DOUBLE_EQ(val1, val2)\
   EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ<double>, \
-                      expected, actual)
+                      val1, val2)
 
-#define ASSERT_FLOAT_EQ(expected, actual)\
+#define ASSERT_FLOAT_EQ(val1, val2)\
   ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ<float>, \
-                      expected, actual)
+                      val1, val2)
 
-#define ASSERT_DOUBLE_EQ(expected, actual)\
+#define ASSERT_DOUBLE_EQ(val1, val2)\
   ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ<double>, \
-                      expected, actual)
+                      val1, val2)
 
 #define EXPECT_NEAR(val1, val2, abs_error)\
   EXPECT_PRED_FORMAT3(::testing::internal::DoubleNearPredFormat, \
@@ -20049,8 +21218,8 @@ bool StaticAssertTypeEq() {
 // The convention is to end the test case name with "Test".  For
 // example, a test case for the Foo class can be named FooTest.
 //
-// The user should put his test code between braces after using this
-// macro.  Example:
+// Test code should appear between braces after an invocation of
+// this macro.  Example:
 //
 //   TEST(FooTest, InitializesCorrectly) {
 //     Foo foo;
diff --git a/modules/ts/include/opencv2/ts/ts_perf.hpp b/modules/ts/include/opencv2/ts/ts_perf.hpp
index 703aed0..bfa1811 100644
--- a/modules/ts/include/opencv2/ts/ts_perf.hpp
+++ b/modules/ts/include/opencv2/ts/ts_perf.hpp
@@ -1,5 +1,5 @@
-#ifndef __OPENCV_TS_PERF_HPP__
-#define __OPENCV_TS_PERF_HPP__
+#ifndef OPENCV_TS_PERF_HPP
+#define OPENCV_TS_PERF_HPP
 
 #include "opencv2/core.hpp"
 #include "ts_gtest.h"
@@ -95,11 +95,11 @@ private:
 
 #define CV_ENUM(class_name, ...)                                                        \
     namespace {                                                                         \
+    using namespace cv;using namespace cv::cuda; using namespace cv::ocl;               \
     struct class_name {                                                                 \
         class_name(int val = 0) : val_(val) {}                                          \
         operator int() const { return val_; }                                           \
         void PrintTo(std::ostream* os) const {                                          \
-            using namespace cv;using namespace cv::cuda; using namespace cv::ocl;        \
             const int vals[] = { __VA_ARGS__ };                                         \
             const char* svals = #__VA_ARGS__;                                           \
             for(int i = 0, pos = 0; i < (int)(sizeof(vals)/sizeof(int)); ++i) {         \
@@ -115,13 +115,12 @@ private:
             *os << "UNKNOWN";                                                           \
         }                                                                               \
         static ::testing::internal::ParamGenerator<class_name> all() {                  \
-            using namespace cv;using namespace cv::cuda; using namespace cv::ocl;        \
-            static class_name vals[] = { __VA_ARGS__ };                                 \
+            const class_name vals[] = { __VA_ARGS__ };                                  \
             return ::testing::ValuesIn(vals);                                           \
         }                                                                               \
     private: int val_;                                                                  \
     };                                                                                  \
-    inline void PrintTo(const class_name& t, std::ostream* os) { t.PrintTo(os); } }
+    static inline void PrintTo(const class_name& t, std::ostream* os) { t.PrintTo(os); } }
 
 #define CV_FLAGS(class_name, ...)                                                       \
     namespace {                                                                         \
@@ -150,7 +149,7 @@ private:
         }                                                                               \
     private: int val_;                                                                  \
     };                                                                                  \
-    inline void PrintTo(const class_name& t, std::ostream* os) { t.PrintTo(os); } }
+    static inline void PrintTo(const class_name& t, std::ostream* os) { t.PrintTo(os); } }
 
 CV_ENUM(MatDepth, CV_8U, CV_8S, CV_16U, CV_16S, CV_32S, CV_32F, CV_64F, CV_USRTYPE1)
 
@@ -300,7 +299,7 @@ typedef struct ImplData
     {
         std::vector<cv::String> out;
 
-        for(int i = 0; i < implCode.size(); i++)
+        for(int i = 0; i < (int)implCode.size(); i++)
         {
             if(impl == implCode[i])
                 out.push_back(funName[i]);
@@ -314,10 +313,10 @@ typedef struct ImplData
         std::vector<int> savedCode;
         std::vector<cv::String> savedName;
 
-        for(int i = 0; i < implCode.size(); i++)
+        for(int i = 0; i < (int)implCode.size(); i++)
         {
             bool match = false;
-            for(int j = 0; j < savedCode.size(); j++)
+            for(int j = 0; j < (int)savedCode.size(); j++)
             {
                 if(implCode[i] == savedCode[j] && !funName[i].compare(savedName[j]))
                 {
@@ -354,6 +353,15 @@ typedef struct ImplData
 } ImplData;
 #endif
 
+#ifdef ENABLE_INSTRUMENTATION
+class InstumentData
+{
+public:
+    static ::cv::String treeToString();
+    static void         printTree();
+};
+#endif
+
 class CV_EXPORTS TestBase: public ::testing::Test
 {
 public:
@@ -369,7 +377,12 @@ public:
     static enum PERF_STRATEGY getCurrentModulePerformanceStrategy();
     static enum PERF_STRATEGY setModulePerformanceStrategy(enum PERF_STRATEGY strategy);
 
-    class PerfSkipTestException: public cv::Exception {};
+    class PerfSkipTestException: public cv::Exception
+    {
+    public:
+        int dummy; // workaround for MacOSX Xcode 7.3 bug (don't make class "empty")
+        PerfSkipTestException() : dummy(0) {}
+    };
 
 protected:
     virtual void PerfTestBody() = 0;
@@ -377,7 +390,7 @@ protected:
     virtual void SetUp();
     virtual void TearDown();
 
-    void startTimer();
+    bool startTimer(); // bool is dummy for conditional loop
     void stopTimer();
     bool next();
 
@@ -401,6 +414,10 @@ protected:
 #ifdef CV_COLLECT_IMPL_DATA
     ImplData implConf;
 #endif
+#ifdef ENABLE_INSTRUMENTATION
+    InstumentData instrConf;
+#endif
+
 private:
     typedef std::vector<std::pair<int, cv::Size> > SizeVector;
     typedef std::vector<int64> TimeVector;
@@ -640,9 +657,9 @@ int main(int argc, char **argv)\
     CV_PERF_TEST_MAIN_INTERNALS(modulename, plain_only, __VA_ARGS__)\
 }
 
-#define TEST_CYCLE_N(n) for(declare.iterations(n); startTimer(), next(); stopTimer())
-#define TEST_CYCLE() for(; startTimer(), next(); stopTimer())
-#define TEST_CYCLE_MULTIRUN(runsNum) for(declare.runs(runsNum); startTimer(), next(); stopTimer()) for(int r = 0; r < runsNum; ++r)
+#define TEST_CYCLE_N(n) for(declare.iterations(n); next() && startTimer(); stopTimer())
+#define TEST_CYCLE() for(; next() && startTimer(); stopTimer())
+#define TEST_CYCLE_MULTIRUN(runsNum) for(declare.runs(runsNum); next() && startTimer(); stopTimer()) for(int r = 0; r < runsNum; ++r)
 
 namespace perf
 {
@@ -686,4 +703,4 @@ struct CV_EXPORTS KeypointGreater :
 void CV_EXPORTS sort(std::vector<cv::KeyPoint>& pts, cv::InputOutputArray descriptors);
 } //namespace perf
 
-#endif //__OPENCV_TS_PERF_HPP__
+#endif //OPENCV_TS_PERF_HPP
diff --git a/modules/ts/misc/run_long.py b/modules/ts/misc/run_long.py
new file mode 100644
index 0000000..6ae76ae
--- /dev/null
+++ b/modules/ts/misc/run_long.py
@@ -0,0 +1,92 @@
+#!/usr/bin/env python
+
+from __future__ import print_function
+import xml.etree.ElementTree as ET
+from glob import glob
+from pprint import PrettyPrinter as PP
+
+LONG_TESTS_DEBUG_VALGRIND = [
+    ('calib3d', 'Calib3d_InitUndistortRectifyMap.accuracy', 2017.22),
+    ('features2d', 'Features2d_Feature2d.no_crash', 1235.68),
+    ('ml', 'ML_RTrees.regression', 1423.47),
+    ('optflow', 'DenseOpticalFlow_DeepFlow.ReferenceAccuracy', 1360.95),
+    ('optflow', 'DenseOpticalFlow_DeepFlow_perf.perf/0', 1881.59),
+    ('optflow', 'DenseOpticalFlow_DeepFlow_perf.perf/1', 5608.75),
+    ('optflow', 'DenseOpticalFlow_GlobalPatchColliderDCT.ReferenceAccuracy', 5433.84),
+    ('optflow', 'DenseOpticalFlow_GlobalPatchColliderWHT.ReferenceAccuracy', 5232.73),
+    ('optflow', 'DenseOpticalFlow_SimpleFlow.ReferenceAccuracy', 1542.1),
+    ('photo', 'Photo_Denoising.speed', 1484.87),
+    ('photo', 'Photo_DenoisingColoredMulti.regression', 2447.11),
+    ('rgbd', 'Rgbd_Normals.compute', 1156.32),
+    ('shape', 'Hauss.regression', 2625.72),
+    ('shape', 'ShapeEMD_SCD.regression', 61913.7),
+    ('shape', 'Shape_SCD.regression', 3311.46),
+    ('tracking', 'AUKF.br_mean_squared_error', 10764.6),
+    ('tracking', 'UKF.br_mean_squared_error', 5228.27),
+    ('xfeatures2d', 'Features2d_RotationInvariance_Descriptor_BoostDesc_LBGM.regression', 1124.51),
+    ('xfeatures2d', 'Features2d_RotationInvariance_Descriptor_VGG120.regression', 2198.1),
+    ('xfeatures2d', 'Features2d_RotationInvariance_Descriptor_VGG48.regression', 1958.52),
+    ('xfeatures2d', 'Features2d_RotationInvariance_Descriptor_VGG64.regression', 2113.12),
+    ('xfeatures2d', 'Features2d_RotationInvariance_Descriptor_VGG80.regression', 2167.16),
+    ('xfeatures2d', 'Features2d_ScaleInvariance_Descriptor_BoostDesc_LBGM.regression', 1511.39),
+    ('xfeatures2d', 'Features2d_ScaleInvariance_Descriptor_VGG120.regression', 1222.07),
+    ('xfeatures2d', 'Features2d_ScaleInvariance_Descriptor_VGG48.regression', 1059.14),
+    ('xfeatures2d', 'Features2d_ScaleInvariance_Descriptor_VGG64.regression', 1163.41),
+    ('xfeatures2d', 'Features2d_ScaleInvariance_Descriptor_VGG80.regression', 1179.06),
+    ('ximgproc', 'L0SmoothTest.SplatSurfaceAccuracy', 6382.26),
+    ('ximgproc', 'L0SmoothTest_perf.perf/17', 2052.16),
+    ('ximgproc', 'RollingGuidanceFilterTest_perf.perf/59', 2760.29),
+    ('ximgproc', 'TypicalSet1/RollingGuidanceFilterTest.MultiThreadReproducibility/5', 1086.33),
+    ('ximgproc', 'TypicalSet1/RollingGuidanceFilterTest.MultiThreadReproducibility/7', 1405.05),
+    ('ximgproc', 'TypicalSet1/RollingGuidanceFilterTest.SplatSurfaceAccuracy/5', 1253.07),
+    ('ximgproc', 'TypicalSet1/RollingGuidanceFilterTest.SplatSurfaceAccuracy/7', 1599.98),
+]
+
+
+def longTestFilter(data):
+    res = ['*', '-']
+    for _, v, _ in data:
+        res.append(v)
+    return '--gtest_filter={}'.format(':'.join(res))
+
+
+# Parse one xml file, filter out tests which took less than 'timeLimit' seconds
+# Returns tuple: ( <module_name>, [ (<module_name>, <test_name>, <test_time>), ... ] )
+def parseOneFile(filename, timeLimit):
+    tree = ET.parse(filename)
+    root = tree.getroot()
+
+    def guess(s, delims):
+        for delim in delims:
+            tmp = s.partition(delim)
+            if len(tmp[1]) != 0:
+                return tmp[0]
+        return None
+    module = guess(filename, ['_posix_', '_nt_', '__']) or root.get('cv_module_name')
+    if not module:
+        return (None, None)
+    res = []
+    for elem in root.findall('.//testcase'):
+        key = '{}.{}'.format(elem.get('classname'), elem.get('name'))
+        val = elem.get('time')
+        if float(val) >= timeLimit:
+            res.append((module, key, float(val)))
+    return (module, res)
+
+
+# Parse all xml files in current folder and combine results into one list
+# Print result to the stdout
+if __name__ == '__main__':
+    LIMIT = 1000
+    res = []
+    xmls = glob('*.xml')
+    for xml in xmls:
+        print('Parsing file', xml, '...')
+        module, testinfo = parseOneFile(xml, LIMIT)
+        if not module:
+            print('SKIP')
+            continue
+        res.extend(testinfo)
+
+    print('========= RESULTS =========')
+    PP(indent=4, width=100).pprint(sorted(res))
diff --git a/modules/ts/misc/run_suite.py b/modules/ts/misc/run_suite.py
index 280c21c..ca0841d 100644
--- a/modules/ts/misc/run_suite.py
+++ b/modules/ts/misc/run_suite.py
@@ -2,6 +2,7 @@
 
 import datetime
 from run_utils import *
+from run_long import LONG_TESTS_DEBUG_VALGRIND, longTestFilter
 
 class TestSuite(object):
     def __init__(self, options, cache):
@@ -85,8 +86,8 @@ class TestSuite(object):
         return set(res)
 
     def isTest(self, fullpath):
-        if fullpath == "java":
-            return True
+        if fullpath in ['java', 'python2', 'python3']:
+            return self.options.mode == 'test'
         if not os.path.isfile(fullpath):
             return False
         if self.cache.getOS() == "nt" and not fullpath.endswith(".exe"):
@@ -99,9 +100,17 @@ class TestSuite(object):
             if self.options.valgrind_supp:
                 res.append("--suppressions=%s" % self.options.valgrind_supp)
             res.extend(self.options.valgrind_opt)
-            return res + cmd
+            return res + cmd + [longTestFilter(LONG_TESTS_DEBUG_VALGRIND)]
         return cmd
 
+    def tryCommand(self, cmd):
+        try:
+            if 0 == execute(cmd, cwd = workingDir):
+                return True
+        except:
+            pass
+        return False
+
     def runTest(self, path, logfile, workingDir, args = []):
         args = args[:]
         exe = os.path.abspath(path)
@@ -109,6 +118,22 @@ class TestSuite(object):
             cmd = [self.cache.ant_executable, "-Dopencv.build.type=%s" % self.cache.build_type, "buildAndTest"]
             ret = execute(cmd, cwd = self.cache.java_test_binary_dir + "/.build")
             return None, ret
+        elif path in ['python2', 'python3']:
+            executable = os.getenv('OPENCV_PYTHON_BINARY', None)
+            if executable is None:
+                executable = path
+                if not self.tryCommand([executable, '--version']):
+                    executable = 'python'
+            cmd = [executable, self.cache.opencv_home + '/modules/python/test/test.py', '--repo', self.cache.opencv_home, '-v'] + args
+            module_suffix = '' if not 'Visual Studio' in self.cache.cmake_generator else '/' + self.cache.build_type
+            env = {}
+            env['PYTHONPATH'] = self.cache.opencv_build + '/lib' + module_suffix + os.pathsep + os.getenv('PYTHONPATH', '')
+            if self.cache.getOS() == 'nt':
+                env['PATH'] = self.cache.opencv_build + '/bin' + module_suffix + os.pathsep + os.getenv('PATH', '')
+            else:
+                env['LD_LIBRARY_PATH'] = self.cache.opencv_build + '/bin' + os.pathsep + os.getenv('LD_LIBRARY_PATH', '')
+            ret = execute(cmd, cwd = workingDir, env = env)
+            return None, ret
         else:
             if isColorEnabled(args):
                 args.append("--gtest_color=yes")
@@ -140,12 +165,15 @@ class TestSuite(object):
             more_args = []
             exe = self.getTest(test)
 
-            userlog = [a for a in args if a.startswith("--gtest_output=")]
-            if len(userlog) == 0:
-                logname = self.getLogName(exe, date)
-                more_args.append("--gtest_output=xml:" + logname)
+            if exe in ["java", "python2", "python3"]:
+                logname = None
             else:
-                logname = userlog[0][userlog[0].find(":")+1:]
+                userlog = [a for a in args if a.startswith("--gtest_output=")]
+                if len(userlog) == 0:
+                    logname = self.getLogName(exe, date)
+                    more_args.append("--gtest_output=xml:" + logname)
+                else:
+                    logname = userlog[0][userlog[0].find(":")+1:]
 
             log.debug("Running the test: %s (%s) ==> %s in %s", exe, args + more_args, logname, workingDir)
             if self.options.dry_run:
diff --git a/modules/ts/misc/run_utils.py b/modules/ts/misc/run_utils.py
index 5841631..8740aa7 100644
--- a/modules/ts/misc/run_utils.py
+++ b/modules/ts/misc/run_utils.py
@@ -22,13 +22,17 @@ class Err(Exception):
     def __init__(self, msg, *args):
         self.msg = msg % args
 
-def execute(cmd, silent = False, cwd = "."):
+def execute(cmd, silent = False, cwd = ".", env = None):
     try:
         log.debug("Run: %s", cmd)
+        if env:
+            for k in env:
+                log.debug("    Environ: %s=%s", k, env[k])
+            env = os.environ.update(env)
         if silent:
-            return check_output(cmd, stderr = STDOUT, cwd = cwd).decode("latin-1")
+            return check_output(cmd, stderr = STDOUT, cwd = cwd, env = env).decode("latin-1")
         else:
-            return check_call(cmd, cwd = cwd)
+            return check_call(cmd, cwd = cwd, env = env)
     except CalledProcessError as e:
         if silent:
             log.debug("Process returned: %d", e.returncode)
@@ -171,6 +175,8 @@ parse_patterns = (
     {'name': "cuda_library",             'default': None,       'pattern': re.compile(r"^CUDA_CUDA_LIBRARY:FILEPATH=(.+)$")},
     {'name': "cuda_version",             'default': None,       'pattern': re.compile(r"^CUDA_VERSION:STRING=(.+)$")},
     {'name': "core_dependencies",        'default': None,       'pattern': re.compile(r"^opencv_core_LIB_DEPENDS:STATIC=(.+)$")},
+    {'name': "python2",                  'default': None,       'pattern': re.compile(r"^BUILD_opencv_python2:BOOL=(.*)$")},
+    {'name': "python3",                  'default': None,       'pattern': re.compile(r"^BUILD_opencv_python3:BOOL=(.*)$")},
 )
 
 class CMakeCache:
@@ -247,11 +253,15 @@ class CMakeCache:
             files = glob.glob(os.path.join(d, mask))
             if not self.getOS() == "android" and self.withJava():
                 files.append("java")
+            if self.withPython2():
+                files.append("python2")
+            if self.withPython3():
+                files.append("python3")
             return [f for f in files if isGood(f)]
         return []
 
     def isMainModule(self, name):
-        return name in self.main_modules
+        return name in self.main_modules + ['python2', 'python3']
 
     def withCuda(self):
         return self.cuda_version and self.with_cuda == "ON" and self.cuda_library and not self.cuda_library.endswith("-NOTFOUND")
@@ -259,6 +269,12 @@ class CMakeCache:
     def withJava(self):
         return self.ant_executable and self.java_test_binary_dir
 
+    def withPython2(self):
+        return self.python2 == 'ON'
+
+    def withPython3(self):
+        return self.python3 == 'ON'
+
     def getGitVersion(self):
         if self.cmake_home_vcver:
             if self.cmake_home_vcver == self.opencv_home_vcver:
diff --git a/modules/ts/src/ocl_test.cpp b/modules/ts/src/ocl_test.cpp
index 69d10aa..abc8d95 100644
--- a/modules/ts/src/ocl_test.cpp
+++ b/modules/ts/src/ocl_test.cpp
@@ -267,7 +267,7 @@ double TestUtils::checkRectSimilarity(const Size & sz, std::vector<Rect>& ob1, s
         cv::Mat cpu_result(sz, CV_8UC1);
         cpu_result.setTo(0);
 
-        for (vector<Rect>::const_iterator r = ob1.begin(); r != ob1.end(); r++)
+        for (vector<Rect>::const_iterator r = ob1.begin(); r != ob1.end(); ++r)
         {
             cv::Mat cpu_result_roi(cpu_result, *r);
             cpu_result_roi.setTo(1);
@@ -277,7 +277,7 @@ double TestUtils::checkRectSimilarity(const Size & sz, std::vector<Rect>& ob1, s
 
         cv::Mat gpu_result(sz, CV_8UC1);
         gpu_result.setTo(0);
-        for(vector<Rect>::const_iterator r2 = ob2.begin(); r2 != ob2.end(); r2++)
+        for(vector<Rect>::const_iterator r2 = ob2.begin(); r2 != ob2.end(); ++r2)
         {
             cv::Mat gpu_result_roi(gpu_result, *r2);
             gpu_result_roi.setTo(1);
diff --git a/modules/ts/src/ts.cpp b/modules/ts/src/ts.cpp
index c02822e..b2763d4 100644
--- a/modules/ts/src/ts.cpp
+++ b/modules/ts/src/ts.cpp
@@ -66,9 +66,34 @@
 #include <setjmp.h>
 #endif
 
+// isDirectory
+#if defined WIN32 || defined _WIN32 || defined WINCE
+# include <windows.h>
+#else
+# include <dirent.h>
+# include <sys/stat.h>
+#endif
+
+
+#include "opencv_tests_config.hpp"
+
 namespace cvtest
 {
 
+uint64 param_seed = 0x12345678; // real value is passed via parseCustomOptions function
+
+static std::string path_join(const std::string& prefix, const std::string& subpath)
+{
+    CV_Assert(subpath.empty() || subpath[0] != '/');
+    if (prefix.empty())
+        return subpath;
+    bool skipSlash = prefix.size() > 0 ? (prefix[prefix.size()-1] == '/' || prefix[prefix.size()-1] == '\\') : false;
+    std::string path = prefix + (skipSlash ? "" : "/") + subpath;
+    return path;
+}
+
+
+
 /*****************************************************************************************\
 *                                Exception and memory handlers                            *
 \*****************************************************************************************/
@@ -449,6 +474,7 @@ static int tsErrorCallback( int status, const char* func_name, const char* err_m
 
 void TS::init( const string& modulename )
 {
+    data_search_subdir.push_back(modulename);
 #ifndef WINRT
     char* datapath_dir = getenv("OPENCV_TEST_DATA_PATH");
 #else
@@ -457,11 +483,7 @@ void TS::init( const string& modulename )
 
     if( datapath_dir )
     {
-        char buf[1024];
-        size_t l = strlen(datapath_dir);
-        bool haveSlash = l > 0 && (datapath_dir[l-1] == '/' || datapath_dir[l-1] == '\\');
-        sprintf( buf, "%s%s%s/", datapath_dir, haveSlash ? "" : "/", modulename.c_str() );
-        data_path = string(buf);
+        data_path = path_join(path_join(datapath_dir, modulename), "");
     }
 
     cv::redirectError((cv::ErrorCallback)tsErrorCallback, this);
@@ -583,7 +605,7 @@ void TS::printf( int streams, const char* fmt, ... )
 }
 
 
-TS ts;
+static TS ts;
 TS* TS::ptr() { return &ts; }
 
 void fillGradient(Mat& img, int delta)
@@ -659,7 +681,6 @@ void smoothBorder(Mat& img, const Scalar& color, int delta)
     }
 }
 
-} //namespace cvtest
 
 bool test_ipp_check = false;
 
@@ -676,6 +697,7 @@ void parseCustomOptions(int argc, char **argv)
 {
     const char * const command_line_keys =
         "{ ipp test_ipp_check |false    |check whether IPP works without failures }"
+        "{ test_seed          |809564   |seed for random numbers generator }"
         "{ h   help           |false    |print help info                          }";
 
     cv::CommandLineParser parser(argc, argv, command_line_keys);
@@ -692,6 +714,119 @@ void parseCustomOptions(int argc, char **argv)
 #else
         test_ipp_check = false;
 #endif
+
+    param_seed = parser.get<unsigned int>("test_seed");
+}
+
+
+static bool isDirectory(const std::string& path)
+{
+#if defined WIN32 || defined _WIN32 || defined WINCE
+    WIN32_FILE_ATTRIBUTE_DATA all_attrs;
+#ifdef WINRT
+    wchar_t wpath[MAX_PATH];
+    size_t copied = mbstowcs(wpath, path.c_str(), MAX_PATH);
+    CV_Assert((copied != MAX_PATH) && (copied != (size_t)-1));
+    BOOL status = ::GetFileAttributesExW(wpath, GetFileExInfoStandard, &all_attrs);
+#else
+    BOOL status = ::GetFileAttributesExA(path.c_str(), GetFileExInfoStandard, &all_attrs);
+#endif
+    DWORD attributes = all_attrs.dwFileAttributes;
+    return status && ((attributes & FILE_ATTRIBUTE_DIRECTORY) != 0);
+#else
+    struct stat s;
+    if (0 != stat(path.c_str(), &s))
+        return false;
+    return S_ISDIR(s.st_mode);
+#endif
 }
 
+CV_EXPORTS void addDataSearchPath(const std::string& path)
+{
+    if (isDirectory(path))
+        TS::ptr()->data_search_path.push_back(path);
+}
+CV_EXPORTS void addDataSearchSubDirectory(const std::string& subdir)
+{
+    TS::ptr()->data_search_subdir.push_back(subdir);
+}
+
+std::string findDataFile(const std::string& relative_path, bool required)
+{
+#define TEST_TRY_FILE_WITH_PREFIX(prefix) \
+{ \
+    std::string path = path_join(prefix, relative_path); \
+    /*printf("Trying %s\n", path.c_str());*/ \
+    FILE* f = fopen(path.c_str(), "rb"); \
+    if(f) { \
+       fclose(f); \
+       return path; \
+    } \
+}
+
+    const std::vector<std::string>& search_path = TS::ptr()->data_search_path;
+    for(size_t i = search_path.size(); i > 0; i--)
+    {
+        const std::string& prefix = search_path[i - 1];
+        TEST_TRY_FILE_WITH_PREFIX(prefix);
+    }
+
+    const std::vector<std::string>& search_subdir = TS::ptr()->data_search_subdir;
+
+#ifndef WINRT
+    char* datapath_dir = getenv("OPENCV_TEST_DATA_PATH");
+#else
+    char* datapath_dir = OPENCV_TEST_DATA_PATH;
+#endif
+
+    std::string datapath;
+    if (datapath_dir)
+    {
+        datapath = datapath_dir;
+        //CV_Assert(isDirectory(datapath) && "OPENCV_TEST_DATA_PATH is specified but it doesn't exist");
+        if (isDirectory(datapath))
+        {
+            for(size_t i = search_subdir.size(); i > 0; i--)
+            {
+                const std::string& subdir = search_subdir[i - 1];
+                std::string prefix = path_join(datapath, subdir);
+                TEST_TRY_FILE_WITH_PREFIX(prefix);
+            }
+        }
+    }
+#ifdef OPENCV_TEST_DATA_INSTALL_PATH
+    datapath = path_join("./", OPENCV_TEST_DATA_INSTALL_PATH);
+    if (isDirectory(datapath))
+    {
+        for(size_t i = search_subdir.size(); i > 0; i--)
+        {
+            const std::string& subdir = search_subdir[i - 1];
+            std::string prefix = path_join(datapath, subdir);
+            TEST_TRY_FILE_WITH_PREFIX(prefix);
+        }
+    }
+#ifdef OPENCV_INSTALL_PREFIX
+    else
+    {
+        datapath = path_join(OPENCV_INSTALL_PREFIX, OPENCV_TEST_DATA_INSTALL_PATH);
+        if (isDirectory(datapath))
+        {
+            for(size_t i = search_subdir.size(); i > 0; i--)
+            {
+                const std::string& subdir = search_subdir[i - 1];
+                std::string prefix = path_join(datapath, subdir);
+                TEST_TRY_FILE_WITH_PREFIX(prefix);
+            }
+        }
+    }
+#endif
+#endif
+    if (required)
+        CV_ErrorNoReturn(cv::Error::StsError, cv::format("OpenCV tests: Can't find required data file: %s", relative_path.c_str()));
+    throw SkipTestException(cv::format("OpenCV tests: Can't find data file: %s", relative_path.c_str()));
+}
+
+
+} //namespace cvtest
+
 /* End of file. */
diff --git a/modules/ts/src/ts_func.cpp b/modules/ts/src/ts_func.cpp
index c74065b..a8f1460 100644
--- a/modules/ts/src/ts_func.cpp
+++ b/modules/ts/src/ts_func.cpp
@@ -1772,7 +1772,8 @@ cmpUlpsFlt_(const int* src1, const int* src2, size_t total, int imaxdiff, size_t
     for( i = 0; i < total; i++ )
     {
         int a = src1[i], b = src2[i];
-        if( a < 0 ) a ^= C; if( b < 0 ) b ^= C;
+        if( a < 0 ) a ^= C;
+        if( b < 0 ) b ^= C;
         int diff = std::abs(a - b);
         if( realmaxdiff < diff )
         {
@@ -1794,7 +1795,8 @@ cmpUlpsFlt_(const int64* src1, const int64* src2, size_t total, int imaxdiff, si
     for( i = 0; i < total; i++ )
     {
         int64 a = src1[i], b = src2[i];
-        if( a < 0 ) a ^= C; if( b < 0 ) b ^= C;
+        if( a < 0 ) a ^= C;
+        if( b < 0 ) b ^= C;
         double diff = fabs((double)a - (double)b);
         if( realmaxdiff < diff )
         {
@@ -3033,35 +3035,38 @@ void printVersionInfo(bool useStdOut)
     if (checkHardwareSupport(CV_CPU_FMA3)) cpu_features += " fma3";
 #endif
 #if CV_AVX_512F
-    if (checkHardwareSupport(CV_CPU_AVX_512F) cpu_features += " avx-512f";
+    if (checkHardwareSupport(CV_CPU_AVX_512F)) cpu_features += " avx-512f";
 #endif
 #if CV_AVX_512BW
-    if (checkHardwareSupport(CV_CPU_AVX_512BW) cpu_features += " avx-512bw";
+    if (checkHardwareSupport(CV_CPU_AVX_512BW)) cpu_features += " avx-512bw";
 #endif
 #if CV_AVX_512CD
-    if (checkHardwareSupport(CV_CPU_AVX_512CD) cpu_features += " avx-512cd";
+    if (checkHardwareSupport(CV_CPU_AVX_512CD)) cpu_features += " avx-512cd";
 #endif
 #if CV_AVX_512DQ
-    if (checkHardwareSupport(CV_CPU_AVX_512DQ) cpu_features += " avx-512dq";
+    if (checkHardwareSupport(CV_CPU_AVX_512DQ)) cpu_features += " avx-512dq";
 #endif
 #if CV_AVX_512ER
-    if (checkHardwareSupport(CV_CPU_AVX_512ER) cpu_features += " avx-512er";
+    if (checkHardwareSupport(CV_CPU_AVX_512ER)) cpu_features += " avx-512er";
 #endif
 #if CV_AVX_512IFMA512
-    if (checkHardwareSupport(CV_CPU_AVX_512IFMA512) cpu_features += " avx-512ifma512";
+    if (checkHardwareSupport(CV_CPU_AVX_512IFMA512)) cpu_features += " avx-512ifma512";
 #endif
 #if CV_AVX_512PF
-    if (checkHardwareSupport(CV_CPU_AVX_512PF) cpu_features += " avx-512pf";
+    if (checkHardwareSupport(CV_CPU_AVX_512PF)) cpu_features += " avx-512pf";
 #endif
 #if CV_AVX_512VBMI
-    if (checkHardwareSupport(CV_CPU_AVX_512VBMI) cpu_features += " avx-512vbmi";
+    if (checkHardwareSupport(CV_CPU_AVX_512VBMI)) cpu_features += " avx-512vbmi";
 #endif
 #if CV_AVX_512VL
-    if (checkHardwareSupport(CV_CPU_AVX_512VL) cpu_features += " avx-512vl";
+    if (checkHardwareSupport(CV_CPU_AVX_512VL)) cpu_features += " avx-512vl";
 #endif
 #if CV_NEON
     if (checkHardwareSupport(CV_CPU_NEON)) cpu_features += " neon";
 #endif
+#if CV_FP16
+    if (checkHardwareSupport(CV_CPU_FP16)) cpu_features += " fp16";
+#endif
 
     cpu_features.erase(0, 1); // erase initial space
 
diff --git a/modules/ts/src/ts_gtest.cpp b/modules/ts/src/ts_gtest.cpp
index 29a3996..6597d30 100644
--- a/modules/ts/src/ts_gtest.cpp
+++ b/modules/ts/src/ts_gtest.cpp
@@ -321,6 +321,8 @@ class GTEST_API_ SingleFailureChecker {
 #include <algorithm>
 #include <iomanip>
 #include <limits>
+#include <list>
+#include <map>
 #include <ostream>  // NOLINT
 #include <sstream>
 #include <vector>
@@ -355,6 +357,7 @@ class GTEST_API_ SingleFailureChecker {
 #elif GTEST_OS_WINDOWS_MOBILE  // We are on Windows CE.
 
 # include <windows.h>  // NOLINT
+# undef min
 
 #elif GTEST_OS_WINDOWS  // We are on Windows proper.
 
@@ -377,6 +380,7 @@ class GTEST_API_ SingleFailureChecker {
 // cpplint thinks that the header is already included, so we want to
 // silence it.
 # include <windows.h>  // NOLINT
+# undef min
 
 #else
 
@@ -399,6 +403,8 @@ class GTEST_API_ SingleFailureChecker {
 #if GTEST_CAN_STREAM_RESULTS_
 # include <arpa/inet.h>  // NOLINT
 # include <netdb.h>  // NOLINT
+# include <sys/socket.h>  // NOLINT
+# include <sys/types.h>  // NOLINT
 #endif
 
 // Indicates that this translation unit is part of Google Test's
@@ -449,7 +455,7 @@ class GTEST_API_ SingleFailureChecker {
 // GTEST_IMPLEMENTATION_ is defined to 1 iff the current translation unit is
 // part of Google Test's implementation; otherwise it's undefined.
 #if !GTEST_IMPLEMENTATION_
-// A user is trying to include this from his code - just say no.
+// If this file is included from the user's code, just say no.
 # error "gtest-internal-inl.h is part of Google Test's internal implementation."
 # error "It must not be included except by Google Test itself."
 #endif  // GTEST_IMPLEMENTATION_
@@ -507,6 +513,7 @@ const char kShuffleFlag[] = "shuffle";
 const char kStackTraceDepthFlag[] = "stack_trace_depth";
 const char kStreamResultToFlag[] = "stream_result_to";
 const char kThrowOnFailureFlag[] = "throw_on_failure";
+const char kFlagfileFlag[] = "flagfile";
 
 // A valid random seed must be in [1, kMaxRandomSeed].
 const int kMaxRandomSeed = 99999;
@@ -842,6 +849,10 @@ class OsStackTraceGetterInterface {
   // CurrentStackTrace() will use to find and hide Google Test stack frames.
   virtual void UponLeavingGTest() = 0;
 
+  // This string is inserted in place of stack frames that are part of
+  // Google Test's implementation.
+  static const char* const kElidedFramesMarker;
+
  private:
   GTEST_DISALLOW_COPY_AND_ASSIGN_(OsStackTraceGetterInterface);
 };
@@ -849,26 +860,12 @@ class OsStackTraceGetterInterface {
 // A working implementation of the OsStackTraceGetterInterface interface.
 class OsStackTraceGetter : public OsStackTraceGetterInterface {
  public:
-  OsStackTraceGetter() : caller_frame_(NULL) {}
-
-  virtual string CurrentStackTrace(int max_depth, int skip_count)
-      GTEST_LOCK_EXCLUDED_(mutex_);
-
-  virtual void UponLeavingGTest() GTEST_LOCK_EXCLUDED_(mutex_);
+  OsStackTraceGetter() {}
 
-  // This string is inserted in place of stack frames that are part of
-  // Google Test's implementation.
-  static const char* const kElidedFramesMarker;
+  virtual string CurrentStackTrace(int max_depth, int skip_count);
+  virtual void UponLeavingGTest();
 
  private:
-  Mutex mutex_;  // protects all internal state
-
-  // We save the stack frame below the frame that calls user code.
-  // We do this because the address of the frame immediately below
-  // the user code changes between the call to UponLeavingGTest()
-  // and any calls to CurrentStackTrace() from within the user code.
-  void* caller_frame_;
-
   GTEST_DISALLOW_COPY_AND_ASSIGN_(OsStackTraceGetter);
 };
 
@@ -1379,32 +1376,6 @@ GTEST_API_ void ParseGoogleTestFlagsOnly(int* argc, wchar_t** argv);
 // platform.
 GTEST_API_ std::string GetLastErrnoDescription();
 
-# if GTEST_OS_WINDOWS
-// Provides leak-safe Windows kernel handle ownership.
-class AutoHandle {
- public:
-  AutoHandle() : handle_(INVALID_HANDLE_VALUE) {}
-  explicit AutoHandle(HANDLE handle) : handle_(handle) {}
-
-  ~AutoHandle() { Reset(); }
-
-  HANDLE Get() const { return handle_; }
-  void Reset() { Reset(INVALID_HANDLE_VALUE); }
-  void Reset(HANDLE handle) {
-    if (handle != handle_) {
-      if (handle_ != INVALID_HANDLE_VALUE)
-        ::CloseHandle(handle_);
-      handle_ = handle;
-    }
-  }
-
- private:
-  HANDLE handle_;
-
-  GTEST_DISALLOW_COPY_AND_ASSIGN_(AutoHandle);
-};
-# endif  // GTEST_OS_WINDOWS
-
 // Attempts to parse a string into a positive integer pointed to by the
 // number parameter.  Returns true if that is possible.
 // GTEST_HAS_DEATH_TEST implies that we have ::std::string, so we can use
@@ -1478,7 +1449,7 @@ class TestResultAccessor {
 #if GTEST_CAN_STREAM_RESULTS_
 
 // Streams test results to the given port on the given host machine.
-class StreamingListener : public EmptyTestEventListener {
+class GTEST_API_ StreamingListener : public EmptyTestEventListener {
  public:
   // Abstract base class for writing strings to a socket.
   class AbstractSocketWriter {
@@ -1677,6 +1648,12 @@ bool g_help_flag = false;
 }  // namespace internal
 
 static const char* GetDefaultFilter() {
+#ifdef GTEST_TEST_FILTER_ENV_VAR_
+  const char* const testbridge_test_only = getenv(GTEST_TEST_FILTER_ENV_VAR_);
+  if (testbridge_test_only != NULL) {
+    return testbridge_test_only;
+  }
+#endif  // GTEST_TEST_FILTER_ENV_VAR_
   return kUniversalFilter;
 }
 
@@ -1783,6 +1760,13 @@ GTEST_DEFINE_bool_(
     "if exceptions are enabled or exit the program with a non-zero code "
     "otherwise.");
 
+#if GTEST_USE_OWN_FLAGFILE_FLAG_
+GTEST_DEFINE_string_(
+    flagfile,
+    internal::StringFromGTestEnv("flagfile", ""),
+    "This flag specifies the flagfile to read command-line flags from.");
+#endif  // GTEST_USE_OWN_FLAGFILE_FLAG_
+
 namespace internal {
 
 // Generates a random number from [0, range), using a Linear
@@ -1807,13 +1791,7 @@ UInt32 Random::Generate(UInt32 range) {
 // GTestIsInitialized() returns true iff the user has initialized
 // Google Test.  Useful for catching the user mistake of not initializing
 // Google Test before calling RUN_ALL_TESTS().
-//
-// A user must call testing::InitGoogleTest() to initialize Google
-// Test.  g_init_gtest_count is set to the number of times
-// InitGoogleTest() has been called.  We don't protect this variable
-// under a mutex as it is only accessed in the main thread.
-GTEST_API_ int g_init_gtest_count = 0;
-static bool GTestIsInitialized() { return g_init_gtest_count != 0; }
+static bool GTestIsInitialized() { return GetArgvs().size() > 0; }
 
 // Iterates over a vector of TestCases, keeping a running sum of the
 // results of calling a given int-returning method on each.
@@ -1869,8 +1847,16 @@ void AssertHelper::operator=(const Message& message) const {
 // Mutex for linked pointers.
 GTEST_API_ GTEST_DEFINE_STATIC_MUTEX_(g_linked_ptr_mutex);
 
-// Application pathname gotten in InitGoogleTest.
-std::string g_executable_path;
+// A copy of all command line arguments.  Set by InitGoogleTest().
+::std::vector<testing::internal::string> g_argvs;
+
+const ::std::vector<testing::internal::string>& GetArgvs() {
+#if defined(GTEST_CUSTOM_GET_ARGVS_)
+  return GTEST_CUSTOM_GET_ARGVS_();
+#else  // defined(GTEST_CUSTOM_GET_ARGVS_)
+  return g_argvs;
+#endif  // defined(GTEST_CUSTOM_GET_ARGVS_)
+}
 
 // Returns the current application's name, removing directory path if that
 // is present.
@@ -1878,9 +1864,9 @@ FilePath GetCurrentExecutableName() {
   FilePath result;
 
 #if GTEST_OS_WINDOWS
-  result.Set(FilePath(g_executable_path).RemoveExtension("exe"));
+  result.Set(FilePath(GetArgvs()[0]).RemoveExtension("exe"));
 #else
-  result.Set(FilePath(g_executable_path));
+  result.Set(FilePath(GetArgvs()[0]));
 #endif  // GTEST_OS_WINDOWS
 
   return result.RemoveDirectoryName();
@@ -2272,8 +2258,12 @@ int UnitTestImpl::test_to_run_count() const {
 // CurrentOsStackTraceExceptTop(1), Foo() will be included in the
 // trace but Bar() and CurrentOsStackTraceExceptTop() won't.
 std::string UnitTestImpl::CurrentOsStackTraceExceptTop(int skip_count) {
-  (void)skip_count;
-  return "";
+  return os_stack_trace_getter()->CurrentStackTrace(
+      static_cast<int>(GTEST_FLAG(stack_trace_depth)),
+      skip_count + 1
+      // Skips the user-specified number of frames plus this function
+      // itself.
+      );  // NOLINT
 }
 
 // Returns the current time in milliseconds.
@@ -2302,21 +2292,13 @@ TimeInMillis GetTimeInMillis() {
 #elif GTEST_OS_WINDOWS && !GTEST_HAS_GETTIMEOFDAY_
   __timeb64 now;
 
-# ifdef _MSC_VER
-
   // MSVC 8 deprecates _ftime64(), so we want to suppress warning 4996
   // (deprecated function) there.
   // TODO(kenton at google.com): Use GetTickCount()?  Or use
   //   SystemTimeToFileTime()
-#  pragma warning(push)          // Saves the current warning state.
-#  pragma warning(disable:4996)  // Temporarily disables warning 4996.
-  _ftime64(&now);
-#  pragma warning(pop)           // Restores the warning state.
-# else
-
+  GTEST_DISABLE_MSC_WARNINGS_PUSH_(4996)
   _ftime64(&now);
-
-# endif  // _MSC_VER
+  GTEST_DISABLE_MSC_WARNINGS_POP_()
 
   return static_cast<TimeInMillis>(now.time) * 1000 + now.millitm;
 #elif GTEST_HAS_GETTIMEOFDAY_
@@ -2401,6 +2383,23 @@ static void StreamWideCharsToMessage(const wchar_t* wstr, size_t length,
 
 #endif  // GTEST_HAS_STD_WSTRING || GTEST_HAS_GLOBAL_WSTRING
 
+void SplitString(const ::std::string& str, char delimiter,
+                 ::std::vector< ::std::string>* dest) {
+  ::std::vector< ::std::string> parsed;
+  ::std::string::size_type pos = 0;
+  while (::testing::internal::AlwaysTrue()) {
+    const ::std::string::size_type colon = str.find(delimiter, pos);
+    if (colon == ::std::string::npos) {
+      parsed.push_back(str.substr(pos));
+      break;
+    } else {
+      parsed.push_back(str.substr(pos, colon - pos));
+      pos = colon + 1;
+    }
+  }
+  dest->swap(parsed);
+}
+
 }  // namespace internal
 
 // Constructs an empty Message.
@@ -2456,6 +2455,13 @@ AssertionResult::AssertionResult(const AssertionResult& other)
                static_cast< ::std::string*>(NULL)) {
 }
 
+// Swaps two AssertionResults.
+void AssertionResult::swap(AssertionResult& other) {
+  using std::swap;
+  swap(success_, other.success_);
+  swap(message_, other.message_);
+}
+
 // Returns the assertion's negation. Used with EXPECT/ASSERT_FALSE.
 AssertionResult AssertionResult::operator!() const {
   AssertionResult negation(!success_);
@@ -2482,6 +2488,276 @@ AssertionResult AssertionFailure(const Message& message) {
 
 namespace internal {
 
+namespace edit_distance {
+std::vector<EditType> CalculateOptimalEdits(const std::vector<size_t>& left,
+                                            const std::vector<size_t>& right) {
+  std::vector<std::vector<double> > costs(
+      left.size() + 1, std::vector<double>(right.size() + 1));
+  std::vector<std::vector<EditType> > best_move(
+      left.size() + 1, std::vector<EditType>(right.size() + 1));
+
+  // Populate for empty right.
+  for (size_t l_i = 0; l_i < costs.size(); ++l_i) {
+    costs[l_i][0] = static_cast<double>(l_i);
+    best_move[l_i][0] = kRemove;
+  }
+  // Populate for empty left.
+  for (size_t r_i = 1; r_i < costs[0].size(); ++r_i) {
+    costs[0][r_i] = static_cast<double>(r_i);
+    best_move[0][r_i] = kAdd;
+  }
+
+  for (size_t l_i = 0; l_i < left.size(); ++l_i) {
+    for (size_t r_i = 0; r_i < right.size(); ++r_i) {
+      if (left[l_i] == right[r_i]) {
+        // Found a match. Consume it.
+        costs[l_i + 1][r_i + 1] = costs[l_i][r_i];
+        best_move[l_i + 1][r_i + 1] = kMatch;
+        continue;
+      }
+
+      const double add = costs[l_i + 1][r_i];
+      const double remove = costs[l_i][r_i + 1];
+      const double replace = costs[l_i][r_i];
+      if (add < remove && add < replace) {
+        costs[l_i + 1][r_i + 1] = add + 1;
+        best_move[l_i + 1][r_i + 1] = kAdd;
+      } else if (remove < add && remove < replace) {
+        costs[l_i + 1][r_i + 1] = remove + 1;
+        best_move[l_i + 1][r_i + 1] = kRemove;
+      } else {
+        // We make replace a little more expensive than add/remove to lower
+        // their priority.
+        costs[l_i + 1][r_i + 1] = replace + 1.00001;
+        best_move[l_i + 1][r_i + 1] = kReplace;
+      }
+    }
+  }
+
+  // Reconstruct the best path. We do it in reverse order.
+  std::vector<EditType> best_path;
+  for (size_t l_i = left.size(), r_i = right.size(); l_i > 0 || r_i > 0;) {
+    EditType move = best_move[l_i][r_i];
+    best_path.push_back(move);
+    l_i -= move != kAdd;
+    r_i -= move != kRemove;
+  }
+  std::reverse(best_path.begin(), best_path.end());
+  return best_path;
+}
+
+namespace {
+
+// Helper class to convert string into ids with deduplication.
+class InternalStrings {
+ public:
+  size_t GetId(const std::string& str) {
+    IdMap::iterator it = ids_.find(str);
+    if (it != ids_.end()) return it->second;
+    size_t id = ids_.size();
+    return ids_[str] = id;
+  }
+
+ private:
+  typedef std::map<std::string, size_t> IdMap;
+  IdMap ids_;
+};
+
+}  // namespace
+
+std::vector<EditType> CalculateOptimalEdits(
+    const std::vector<std::string>& left,
+    const std::vector<std::string>& right) {
+  std::vector<size_t> left_ids, right_ids;
+  {
+    InternalStrings intern_table;
+    for (size_t i = 0; i < left.size(); ++i) {
+      left_ids.push_back(intern_table.GetId(left[i]));
+    }
+    for (size_t i = 0; i < right.size(); ++i) {
+      right_ids.push_back(intern_table.GetId(right[i]));
+    }
+  }
+  return CalculateOptimalEdits(left_ids, right_ids);
+}
+
+namespace {
+
+// Helper class that holds the state for one hunk and prints it out to the
+// stream.
+// It reorders adds/removes when possible to group all removes before all
+// adds. It also adds the hunk header before printint into the stream.
+class Hunk {
+ public:
+  Hunk(size_t left_start, size_t right_start)
+      : left_start_(left_start),
+        right_start_(right_start),
+        adds_(),
+        removes_(),
+        common_() {}
+
+  void PushLine(char edit, const char* line) {
+    switch (edit) {
+      case ' ':
+        ++common_;
+        FlushEdits();
+        hunk_.push_back(std::make_pair(' ', line));
+        break;
+      case '-':
+        ++removes_;
+        hunk_removes_.push_back(std::make_pair('-', line));
+        break;
+      case '+':
+        ++adds_;
+        hunk_adds_.push_back(std::make_pair('+', line));
+        break;
+    }
+  }
+
+  void PrintTo(std::ostream* os) {
+    PrintHeader(os);
+    FlushEdits();
+    for (std::list<std::pair<char, const char*> >::const_iterator it =
+             hunk_.begin();
+         it != hunk_.end(); ++it) {
+      *os << it->first << it->second << "\n";
+    }
+  }
+
+  bool has_edits() const { return adds_ || removes_; }
+
+ private:
+  void FlushEdits() {
+    hunk_.splice(hunk_.end(), hunk_removes_);
+    hunk_.splice(hunk_.end(), hunk_adds_);
+  }
+
+  // Print a unified diff header for one hunk.
+  // The format is
+  //   "@@ -<left_start>,<left_length> +<right_start>,<right_length> @@"
+  // where the left/right parts are ommitted if unnecessary.
+  void PrintHeader(std::ostream* ss) const {
+    *ss << "@@ ";
+    if (removes_) {
+      *ss << "-" << left_start_ << "," << (removes_ + common_);
+    }
+    if (removes_ && adds_) {
+      *ss << " ";
+    }
+    if (adds_) {
+      *ss << "+" << right_start_ << "," << (adds_ + common_);
+    }
+    *ss << " @@\n";
+  }
+
+  size_t left_start_, right_start_;
+  size_t adds_, removes_, common_;
+  std::list<std::pair<char, const char*> > hunk_, hunk_adds_, hunk_removes_;
+};
+
+}  // namespace
+
+// Create a list of diff hunks in Unified diff format.
+// Each hunk has a header generated by PrintHeader above plus a body with
+// lines prefixed with ' ' for no change, '-' for deletion and '+' for
+// addition.
+// 'context' represents the desired unchanged prefix/suffix around the diff.
+// If two hunks are close enough that their contexts overlap, then they are
+// joined into one hunk.
+std::string CreateUnifiedDiff(const std::vector<std::string>& left,
+                              const std::vector<std::string>& right,
+                              size_t context) {
+  const std::vector<EditType> edits = CalculateOptimalEdits(left, right);
+
+  size_t l_i = 0, r_i = 0, edit_i = 0;
+  std::stringstream ss;
+  while (edit_i < edits.size()) {
+    // Find first edit.
+    while (edit_i < edits.size() && edits[edit_i] == kMatch) {
+      ++l_i;
+      ++r_i;
+      ++edit_i;
+    }
+
+    // Find the first line to include in the hunk.
+    const size_t prefix_context = std::min(l_i, context);
+    Hunk hunk(l_i - prefix_context + 1, r_i - prefix_context + 1);
+    for (size_t i = prefix_context; i > 0; --i) {
+      hunk.PushLine(' ', left[l_i - i].c_str());
+    }
+
+    // Iterate the edits until we found enough suffix for the hunk or the input
+    // is over.
+    size_t n_suffix = 0;
+    for (; edit_i < edits.size(); ++edit_i) {
+      if (n_suffix >= context) {
+        // Continue only if the next hunk is very close.
+        std::vector<EditType>::const_iterator it = edits.begin() + edit_i;
+        while (it != edits.end() && *it == kMatch) ++it;
+        if (it == edits.end() || (it - edits.begin()) - edit_i >= context) {
+          // There is no next edit or it is too far away.
+          break;
+        }
+      }
+
+      EditType edit = edits[edit_i];
+      // Reset count when a non match is found.
+      n_suffix = edit == kMatch ? n_suffix + 1 : 0;
+
+      if (edit == kMatch || edit == kRemove || edit == kReplace) {
+        hunk.PushLine(edit == kMatch ? ' ' : '-', left[l_i].c_str());
+      }
+      if (edit == kAdd || edit == kReplace) {
+        hunk.PushLine('+', right[r_i].c_str());
+      }
+
+      // Advance indices, depending on edit type.
+      l_i += edit != kAdd;
+      r_i += edit != kRemove;
+    }
+
+    if (!hunk.has_edits()) {
+      // We are done. We don't want this hunk.
+      break;
+    }
+
+    hunk.PrintTo(&ss);
+  }
+  return ss.str();
+}
+
+}  // namespace edit_distance
+
+namespace {
+
+// The string representation of the values received in EqFailure() are already
+// escaped. Split them on escaped '\n' boundaries. Leave all other escaped
+// characters the same.
+std::vector<std::string> SplitEscapedString(const std::string& str) {
+  std::vector<std::string> lines;
+  size_t start = 0, end = str.size();
+  if (end > 2 && str[0] == '"' && str[end - 1] == '"') {
+    ++start;
+    --end;
+  }
+  bool escaped = false;
+  for (size_t i = start; i + 1 < end; ++i) {
+    if (escaped) {
+      escaped = false;
+      if (str[i] == 'n') {
+        lines.push_back(str.substr(start, i - start - 1));
+        start = i + 1;
+      }
+    } else {
+      escaped = str[i] == '\\';
+    }
+  }
+  lines.push_back(str.substr(start, end - start));
+  return lines;
+}
+
+}  // namespace
+
 // Constructs and returns the message for an equality assertion
 // (e.g. ASSERT_EQ, EXPECT_STREQ, etc) failure.
 //
@@ -2489,31 +2765,42 @@ namespace internal {
 // and their values, as strings.  For example, for ASSERT_EQ(foo, bar)
 // where foo is 5 and bar is 6, we have:
 //
-//   expected_expression: "foo"
-//   actual_expression:   "bar"
-//   expected_value:      "5"
-//   actual_value:        "6"
+//   lhs_expression: "foo"
+//   rhs_expression: "bar"
+//   lhs_value:      "5"
+//   rhs_value:      "6"
 //
 // The ignoring_case parameter is true iff the assertion is a
-// *_STRCASEEQ*.  When it's true, the string " (ignoring case)" will
+// *_STRCASEEQ*.  When it's true, the string "Ignoring case" will
 // be inserted into the message.
-AssertionResult EqFailure(const char* expected_expression,
-                          const char* actual_expression,
-                          const std::string& expected_value,
-                          const std::string& actual_value,
+AssertionResult EqFailure(const char* lhs_expression,
+                          const char* rhs_expression,
+                          const std::string& lhs_value,
+                          const std::string& rhs_value,
                           bool ignoring_case) {
   Message msg;
-  msg << "Value of: " << actual_expression;
-  if (actual_value != actual_expression) {
-    msg << "\n  Actual: " << actual_value;
+  msg << "      Expected: " << lhs_expression;
+  if (lhs_value != lhs_expression) {
+    msg << "\n      Which is: " << lhs_value;
+  }
+  msg << "\nTo be equal to: " << rhs_expression;
+  if (rhs_value != rhs_expression) {
+    msg << "\n      Which is: " << rhs_value;
   }
 
-  msg << "\nExpected: " << expected_expression;
   if (ignoring_case) {
-    msg << " (ignoring case)";
+    msg << "\nIgnoring case";
   }
-  if (expected_value != expected_expression) {
-    msg << "\nWhich is: " << expected_value;
+
+  if (!lhs_value.empty() && !rhs_value.empty()) {
+    const std::vector<std::string> lhs_lines =
+        SplitEscapedString(lhs_value);
+    const std::vector<std::string> rhs_lines =
+        SplitEscapedString(rhs_value);
+    if (lhs_lines.size() > 1 || rhs_lines.size() > 1) {
+      msg << "\nWith diff:\n"
+          << edit_distance::CreateUnifiedDiff(lhs_lines, rhs_lines);
+    }
   }
 
   return AssertionFailure() << msg;
@@ -2611,18 +2898,18 @@ namespace internal {
 
 // The helper function for {ASSERT|EXPECT}_EQ with int or enum
 // arguments.
-AssertionResult CmpHelperEQ(const char* expected_expression,
-                            const char* actual_expression,
-                            BiggestInt expected,
-                            BiggestInt actual) {
-  if (expected == actual) {
+AssertionResult CmpHelperEQ(const char* lhs_expression,
+                            const char* rhs_expression,
+                            BiggestInt lhs,
+                            BiggestInt rhs) {
+  if (lhs == rhs) {
     return AssertionSuccess();
   }
 
-  return EqFailure(expected_expression,
-                   actual_expression,
-                   FormatForComparisonFailureMessage(expected, actual),
-                   FormatForComparisonFailureMessage(actual, expected),
+  return EqFailure(lhs_expression,
+                   rhs_expression,
+                   FormatForComparisonFailureMessage(lhs, rhs),
+                   FormatForComparisonFailureMessage(rhs, lhs),
                    false);
 }
 
@@ -2661,34 +2948,34 @@ GTEST_IMPL_CMP_HELPER_(GT, > )
 #undef GTEST_IMPL_CMP_HELPER_
 
 // The helper function for {ASSERT|EXPECT}_STREQ.
-AssertionResult CmpHelperSTREQ(const char* expected_expression,
-                               const char* actual_expression,
-                               const char* expected,
-                               const char* actual) {
-  if (String::CStringEquals(expected, actual)) {
+AssertionResult CmpHelperSTREQ(const char* lhs_expression,
+                               const char* rhs_expression,
+                               const char* lhs,
+                               const char* rhs) {
+  if (String::CStringEquals(lhs, rhs)) {
     return AssertionSuccess();
   }
 
-  return EqFailure(expected_expression,
-                   actual_expression,
-                   PrintToString(expected),
-                   PrintToString(actual),
+  return EqFailure(lhs_expression,
+                   rhs_expression,
+                   PrintToString(lhs),
+                   PrintToString(rhs),
                    false);
 }
 
 // The helper function for {ASSERT|EXPECT}_STRCASEEQ.
-AssertionResult CmpHelperSTRCASEEQ(const char* expected_expression,
-                                   const char* actual_expression,
-                                   const char* expected,
-                                   const char* actual) {
-  if (String::CaseInsensitiveCStringEquals(expected, actual)) {
+AssertionResult CmpHelperSTRCASEEQ(const char* lhs_expression,
+                                   const char* rhs_expression,
+                                   const char* lhs,
+                                   const char* rhs) {
+  if (String::CaseInsensitiveCStringEquals(lhs, rhs)) {
     return AssertionSuccess();
   }
 
-  return EqFailure(expected_expression,
-                   actual_expression,
-                   PrintToString(expected),
-                   PrintToString(actual),
+  return EqFailure(lhs_expression,
+                   rhs_expression,
+                   PrintToString(lhs),
+                   PrintToString(rhs),
                    true);
 }
 
@@ -3043,18 +3330,18 @@ bool String::WideCStringEquals(const wchar_t * lhs, const wchar_t * rhs) {
 }
 
 // Helper function for *_STREQ on wide strings.
-AssertionResult CmpHelperSTREQ(const char* expected_expression,
-                               const char* actual_expression,
-                               const wchar_t* expected,
-                               const wchar_t* actual) {
-  if (String::WideCStringEquals(expected, actual)) {
+AssertionResult CmpHelperSTREQ(const char* lhs_expression,
+                               const char* rhs_expression,
+                               const wchar_t* lhs,
+                               const wchar_t* rhs) {
+  if (String::WideCStringEquals(lhs, rhs)) {
     return AssertionSuccess();
   }
 
-  return EqFailure(expected_expression,
-                   actual_expression,
-                   PrintToString(expected),
-                   PrintToString(actual),
+  return EqFailure(lhs_expression,
+                   rhs_expression,
+                   PrintToString(lhs),
+                   PrintToString(rhs),
                    false);
 }
 
@@ -3387,14 +3674,15 @@ int TestResult::test_property_count() const {
 
 // Creates a Test object.
 
-// The c'tor saves the values of all Google Test flags.
+// The c'tor saves the states of all flags.
 Test::Test()
-    : gtest_flag_saver_(new internal::GTestFlagSaver) {
+    : gtest_flag_saver_(new GTEST_FLAG_SAVER_) {
 }
 
-// The d'tor restores the values of all Google Test flags.
+// The d'tor restores the states of all flags.  The actual work is
+// done by the d'tor of the gtest_flag_saver_ field, and thus not
+// visible here.
 Test::~Test() {
-  delete gtest_flag_saver_;
 }
 
 // Sets up the test fixture.
@@ -3463,8 +3751,8 @@ bool Test::HasSameFixtureClass() {
     const bool this_is_TEST = this_fixture_id == internal::GetTestTypeId();
 
     if (first_is_TEST || this_is_TEST) {
-      // The user mixed TEST and TEST_F in this test case - we'll tell
-      // him/her how to fix it.
+      // Both TEST and TEST_F appear in same test case, which is incorrect.
+      // Tell the user how to fix this.
 
       // Gets the name of the TEST and the name of the TEST_F.  Note
       // that first_is_TEST and this_is_TEST cannot both be true, as
@@ -3484,8 +3772,8 @@ bool Test::HasSameFixtureClass() {
           << "want to change the TEST to TEST_F or move it to another test\n"
           << "case.";
     } else {
-      // The user defined two fixture classes with the same name in
-      // two namespaces - we'll tell him/her how to fix it.
+      // Two fixture classes with the same name appear in two different
+      // namespaces, which is not allowed. Tell the user how to fix this.
       ADD_FAILURE()
           << "All tests in the same test case must use the same test fixture\n"
           << "class.  However, in test case "
@@ -3678,12 +3966,14 @@ TestInfo::TestInfo(const std::string& a_test_case_name,
                    const std::string& a_name,
                    const char* a_type_param,
                    const char* a_value_param,
+                   internal::CodeLocation a_code_location,
                    internal::TypeId fixture_class_id,
                    internal::TestFactoryBase* factory)
     : test_case_name_(a_test_case_name),
       name_(a_name),
       type_param_(a_type_param ? new std::string(a_type_param) : NULL),
       value_param_(a_value_param ? new std::string(a_value_param) : NULL),
+      location_(a_code_location),
       fixture_class_id_(fixture_class_id),
       should_run_(false),
       is_disabled_(false),
@@ -3707,6 +3997,7 @@ namespace internal {
 //                     this is not a typed or a type-parameterized test.
 //   value_param:      text representation of the test's value parameter,
 //                     or NULL if this is not a value-parameterized test.
+//   code_location:    code location where the test is defined
 //   fixture_class_id: ID of the test fixture class
 //   set_up_tc:        pointer to the function that sets up the test case
 //   tear_down_tc:     pointer to the function that tears down the test case
@@ -3718,20 +4009,21 @@ TestInfo* MakeAndRegisterTestInfo(
     const char* name,
     const char* type_param,
     const char* value_param,
+    CodeLocation code_location,
     TypeId fixture_class_id,
     SetUpTestCaseFunc set_up_tc,
     TearDownTestCaseFunc tear_down_tc,
     TestFactoryBase* factory) {
   TestInfo* const test_info =
       new TestInfo(test_case_name, name, type_param, value_param,
-                   fixture_class_id, factory);
+                   code_location, fixture_class_id, factory);
   GetUnitTestImpl()->AddTestInfo(set_up_tc, tear_down_tc, test_info);
   return test_info;
 }
 
 #if GTEST_HAS_PARAM_TEST
 void ReportInvalidTestCaseType(const char* test_case_name,
-                               const char* file, int line) {
+                               CodeLocation code_location) {
   Message errors;
   errors
       << "Attempted redefinition of test case " << test_case_name << ".\n"
@@ -3743,7 +4035,9 @@ void ReportInvalidTestCaseType(const char* test_case_name,
       << "probably rename one of the classes to put the tests into different\n"
       << "test cases.";
 
-  fprintf(stderr, "%s %s", FormatFileLocation(file, line).c_str(),
+  fprintf(stderr, "%s %s",
+          FormatFileLocation(code_location.file.c_str(),
+                             code_location.line).c_str(),
           errors.GetString().c_str());
 }
 #endif  // GTEST_HAS_PARAM_TEST
@@ -4054,7 +4348,8 @@ enum GTestColor {
   COLOR_YELLOW
 };
 
-#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE && !defined WINRT
+#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE && \
+    !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT
 
 // Returns the character attribute for the given color.
 WORD GetColorAttribute(GTestColor color) {
@@ -4099,6 +4394,10 @@ bool ShouldUseColor(bool stdout_is_tty) {
         String::CStringEquals(term, "xterm-256color") ||
         String::CStringEquals(term, "screen") ||
         String::CStringEquals(term, "screen-256color") ||
+        String::CStringEquals(term, "tmux") ||
+        String::CStringEquals(term, "tmux-256color") ||
+        String::CStringEquals(term, "rxvt-unicode") ||
+        String::CStringEquals(term, "rxvt-unicode-256color") ||
         String::CStringEquals(term, "linux") ||
         String::CStringEquals(term, "cygwin");
     return stdout_is_tty && term_supports_color;
@@ -4122,8 +4421,9 @@ static void ColoredPrintf(GTestColor color, const char* fmt, ...) {
   va_list args;
   va_start(args, fmt);
 
-#if GTEST_OS_WINDOWS_MOBILE || WINRT || GTEST_OS_SYMBIAN || GTEST_OS_ZOS || GTEST_OS_IOS
-  const bool use_color = false;
+#if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_SYMBIAN || GTEST_OS_ZOS || \
+    GTEST_OS_IOS || GTEST_OS_WINDOWS_PHONE || GTEST_OS_WINDOWS_RT
+  const bool use_color = AlwaysFalse();
 #else
   static const bool in_color_mode =
       ShouldUseColor(posix::IsATTY(posix::FileNo(stdout)) != 0);
@@ -4137,7 +4437,8 @@ static void ColoredPrintf(GTestColor color, const char* fmt, ...) {
     return;
   }
 
-#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE && !defined WINRT
+#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE && \
+    !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT
   const HANDLE stdout_handle = GetStdHandle(STD_OUTPUT_HANDLE);
 
   // Gets the current text color.
@@ -4720,34 +5021,39 @@ std::string XmlUnitTestResultPrinter::RemoveInvalidXmlCharacters(
 // Formats the given time in milliseconds as seconds.
 std::string FormatTimeInMillisAsSeconds(TimeInMillis ms) {
   ::std::stringstream ss;
-  ss << ms/1000.0;
+  ss << (static_cast<double>(ms) * 1e-3);
   return ss.str();
 }
 
-// Converts the given epoch time in milliseconds to a date string in the ISO
-// 8601 format, without the timezone information.
-std::string FormatEpochTimeInMillisAsIso8601(TimeInMillis ms) {
-  // Using non-reentrant version as localtime_r is not portable.
-  time_t seconds = static_cast<time_t>(ms / 1000);
-#ifdef _MSC_VER
-# pragma warning(push)          // Saves the current warning state.
-# pragma warning(disable:4996)  // Temporarily disables warning 4996
-                                // (function or variable may be unsafe).
-  const struct tm* const time_struct = localtime(&seconds);  // NOLINT
-# pragma warning(pop)           // Restores the warning state again.
+static bool PortableLocaltime(time_t seconds, struct tm* out) {
+#if defined(_MSC_VER)
+  return localtime_s(out, &seconds) == 0;
+#elif defined(__MINGW32__) || defined(__MINGW64__)
+  // MINGW <time.h> provides neither localtime_r nor localtime_s, but uses
+  // Windows' localtime(), which has a thread-local tm buffer.
+  struct tm* tm_ptr = localtime(&seconds);  // NOLINT
+  if (tm_ptr == NULL)
+    return false;
+  *out = *tm_ptr;
+  return true;
 #else
-  const struct tm* const time_struct = localtime(&seconds);  // NOLINT
+  return localtime_r(&seconds, out) != NULL;
 #endif
-  if (time_struct == NULL)
-    return "";  // Invalid ms value
+}
 
+// Converts the given epoch time in milliseconds to a date string in the ISO
+// 8601 format, without the timezone information.
+std::string FormatEpochTimeInMillisAsIso8601(TimeInMillis ms) {
+  struct tm time_struct;
+  if (!PortableLocaltime(static_cast<time_t>(ms / 1000), &time_struct))
+    return "";
   // YYYY-MM-DDThh:mm:ss
-  return StreamableToString(time_struct->tm_year + 1900) + "-" +
-      String::FormatIntWidth2(time_struct->tm_mon + 1) + "-" +
-      String::FormatIntWidth2(time_struct->tm_mday) + "T" +
-      String::FormatIntWidth2(time_struct->tm_hour) + ":" +
-      String::FormatIntWidth2(time_struct->tm_min) + ":" +
-      String::FormatIntWidth2(time_struct->tm_sec);
+  return StreamableToString(time_struct.tm_year + 1900) + "-" +
+      String::FormatIntWidth2(time_struct.tm_mon + 1) + "-" +
+      String::FormatIntWidth2(time_struct.tm_mday) + "T" +
+      String::FormatIntWidth2(time_struct.tm_hour) + ":" +
+      String::FormatIntWidth2(time_struct.tm_min) + ":" +
+      String::FormatIntWidth2(time_struct.tm_sec);
 }
 
 // Streams an XML CDATA section, escaping invalid CDATA sequences as needed.
@@ -5010,26 +5316,15 @@ ScopedTrace::~ScopedTrace()
 
 // class OsStackTraceGetter
 
-// Returns the current OS stack trace as an std::string.  Parameters:
-//
-//   max_depth  - the maximum number of stack frames to be included
-//                in the trace.
-//   skip_count - the number of top frames to be skipped; doesn't count
-//                against max_depth.
-//
-string OsStackTraceGetter::CurrentStackTrace(int /* max_depth */,
-                                             int /* skip_count */)
-    GTEST_LOCK_EXCLUDED_(mutex_) {
-  return "";
-}
+const char* const OsStackTraceGetterInterface::kElidedFramesMarker =
+    "... " GTEST_NAME_ " internal frames ...";
 
-void OsStackTraceGetter::UponLeavingGTest()
-    GTEST_LOCK_EXCLUDED_(mutex_) {
+string OsStackTraceGetter::CurrentStackTrace(int /*max_depth*/,
+                                             int /*skip_count*/) {
+  return "";
 }
 
-const char* const
-OsStackTraceGetter::kElidedFramesMarker =
-    "... " GTEST_NAME_ " internal frames ...";
+void OsStackTraceGetter::UponLeavingGTest() {}
 
 // A helper class that creates the premature-exit file in its
 // constructor and deletes the file in its destructor.
@@ -5320,7 +5615,7 @@ void UnitTest::AddTestPartResult(
     // with another testing framework) and specify the former on the
     // command line for debugging.
     if (GTEST_FLAG(break_on_failure)) {
-#if GTEST_OS_WINDOWS && !defined WINRT
+#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT
       // Using DebugBreak on Windows allows gtest to still break into a debugger
       // when a failure happens and both the --gtest_break_on_failure and
       // the --gtest_catch_exceptions flags are specified.
@@ -5398,7 +5693,7 @@ int UnitTest::Run() {
   // process. In either case the user does not want to see pop-up dialogs
   // about crashes - they are expected.
   if (impl()->catch_exceptions() || in_death_test_child_process) {
-# if !GTEST_OS_WINDOWS_MOBILE && !defined WINRT
+# if !GTEST_OS_WINDOWS_MOBILE && !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT
     // SetErrorMode doesn't exist on CE.
     SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOALIGNMENTFAULTEXCEPT |
                  SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX);
@@ -5501,17 +5796,10 @@ namespace internal {
 
 UnitTestImpl::UnitTestImpl(UnitTest* parent)
     : parent_(parent),
-#ifdef _MSC_VER
-# pragma warning(push)                    // Saves the current warning state.
-# pragma warning(disable:4355)            // Temporarily disables warning 4355
-                                         // (using this in initializer).
-      default_global_test_part_result_reporter_(this),
-      default_per_thread_test_part_result_reporter_(this),
-# pragma warning(pop)                     // Restores the warning state again.
-#else
+      GTEST_DISABLE_MSC_WARNINGS_PUSH_(4355 /* using this in initializer */)
       default_global_test_part_result_reporter_(this),
       default_per_thread_test_part_result_reporter_(this),
-#endif  // _MSC_VER
+      GTEST_DISABLE_MSC_WARNINGS_POP_()
       global_test_part_result_repoter_(
           &default_global_test_part_result_reporter_),
       per_thread_test_part_result_reporter_(
@@ -5622,6 +5910,11 @@ void UnitTestImpl::PostFlagParsingInit() {
   if (!post_flag_parse_init_performed_) {
     post_flag_parse_init_performed_ = true;
 
+#if defined(GTEST_CUSTOM_TEST_EVENT_LISTENER_)
+    // Register to send notifications about key process state changes.
+    listeners()->Append(new GTEST_CUSTOM_TEST_EVENT_LISTENER_());
+#endif  // defined(GTEST_CUSTOM_TEST_EVENT_LISTENER_)
+
 #if GTEST_HAS_DEATH_TEST
     InitDeathTestSubprocessControlInfo();
     SuppressTestEventsIfInSubprocess();
@@ -5755,6 +6048,11 @@ bool UnitTestImpl::RunAllTests() {
 
 #if GTEST_HAS_DEATH_TEST
   in_subprocess_for_death_test = (internal_run_death_test_flag_.get() != NULL);
+# if defined(GTEST_EXTRA_DEATH_TEST_CHILD_SETUP_)
+  if (in_subprocess_for_death_test) {
+    GTEST_EXTRA_DEATH_TEST_CHILD_SETUP_();
+  }
+# endif  // defined(GTEST_EXTRA_DEATH_TEST_CHILD_SETUP_)
 #endif  // GTEST_HAS_DEATH_TEST
 
   const bool should_shard = ShouldShard(kTestTotalShards, kTestShardIndex,
@@ -6097,7 +6395,11 @@ void UnitTestImpl::set_os_stack_trace_getter(
 // getter, and returns it.
 OsStackTraceGetterInterface* UnitTestImpl::os_stack_trace_getter() {
   if (os_stack_trace_getter_ == NULL) {
+#ifdef GTEST_OS_STACK_TRACE_GETTER_
+    os_stack_trace_getter_ = new GTEST_OS_STACK_TRACE_GETTER_;
+#else
     os_stack_trace_getter_ = new OsStackTraceGetter;
+#endif  // GTEST_OS_STACK_TRACE_GETTER_
   }
 
   return os_stack_trace_getter_;
@@ -6402,6 +6704,59 @@ static const char kColorEncodedHelpMessage[] =
 "(not one in your own code or tests), please report it to\n"
 "@G<" GTEST_DEV_EMAIL_ ">@D.\n";
 
+static bool ParseGoogleTestFlag(const char* const arg) {
+  return ParseBoolFlag(arg, kAlsoRunDisabledTestsFlag,
+                       &GTEST_FLAG(also_run_disabled_tests)) ||
+      ParseBoolFlag(arg, kBreakOnFailureFlag,
+                    &GTEST_FLAG(break_on_failure)) ||
+      ParseBoolFlag(arg, kCatchExceptionsFlag,
+                    &GTEST_FLAG(catch_exceptions)) ||
+      ParseStringFlag(arg, kColorFlag, &GTEST_FLAG(color)) ||
+      ParseStringFlag(arg, kDeathTestStyleFlag,
+                      &GTEST_FLAG(death_test_style)) ||
+      ParseBoolFlag(arg, kDeathTestUseFork,
+                    &GTEST_FLAG(death_test_use_fork)) ||
+      ParseStringFlag(arg, kFilterFlag, &GTEST_FLAG(filter)) ||
+      ParseStringFlag(arg, kParamFilterFlag, &GTEST_FLAG(param_filter)) ||
+      ParseStringFlag(arg, kInternalRunDeathTestFlag,
+                      &GTEST_FLAG(internal_run_death_test)) ||
+      ParseBoolFlag(arg, kListTestsFlag, &GTEST_FLAG(list_tests)) ||
+      ParseStringFlag(arg, kOutputFlag, &GTEST_FLAG(output)) ||
+      ParseBoolFlag(arg, kPrintTimeFlag, &GTEST_FLAG(print_time)) ||
+      ParseInt32Flag(arg, kRandomSeedFlag, &GTEST_FLAG(random_seed)) ||
+      ParseInt32Flag(arg, kRepeatFlag, &GTEST_FLAG(repeat)) ||
+      ParseBoolFlag(arg, kShuffleFlag, &GTEST_FLAG(shuffle)) ||
+      ParseInt32Flag(arg, kStackTraceDepthFlag,
+                     &GTEST_FLAG(stack_trace_depth)) ||
+      ParseStringFlag(arg, kStreamResultToFlag,
+                      &GTEST_FLAG(stream_result_to)) ||
+      ParseBoolFlag(arg, kThrowOnFailureFlag,
+                    &GTEST_FLAG(throw_on_failure));
+}
+
+#if GTEST_USE_OWN_FLAGFILE_FLAG_
+static void LoadFlagsFromFile(const std::string& path) {
+  FILE* flagfile = posix::FOpen(path.c_str(), "r");
+  if (!flagfile) {
+    fprintf(stderr,
+            "Unable to open file \"%s\"\n",
+            GTEST_FLAG(flagfile).c_str());
+    fflush(stderr);
+    exit(EXIT_FAILURE);
+  }
+  std::string contents(ReadEntireFile(flagfile));
+  posix::FClose(flagfile);
+  std::vector<std::string> lines;
+  SplitString(contents, '\n', &lines);
+  for (size_t i = 0; i < lines.size(); ++i) {
+    if (lines[i].empty())
+      continue;
+    if (!ParseGoogleTestFlag(lines[i].c_str()))
+      g_help_flag = true;
+  }
+}
+#endif  // GTEST_USE_OWN_FLAGFILE_FLAG_
+
 // Parses the command line for Google Test flags, without initializing
 // other parts of Google Test.  The type parameter CharType can be
 // instantiated to either char or wchar_t.
@@ -6415,36 +6770,24 @@ void ParseGoogleTestFlagsOnlyImpl(int* argc, CharType** argv) {
     using internal::ParseInt32Flag;
     using internal::ParseStringFlag;
 
-    // Do we see a Google Test flag?
-    if (ParseBoolFlag(arg, kAlsoRunDisabledTestsFlag,
-                      &GTEST_FLAG(also_run_disabled_tests)) ||
-        ParseBoolFlag(arg, kBreakOnFailureFlag,
-                      &GTEST_FLAG(break_on_failure)) ||
-        ParseBoolFlag(arg, kCatchExceptionsFlag,
-                      &GTEST_FLAG(catch_exceptions)) ||
-        ParseStringFlag(arg, kColorFlag, &GTEST_FLAG(color)) ||
-        ParseStringFlag(arg, kDeathTestStyleFlag,
-                        &GTEST_FLAG(death_test_style)) ||
-        ParseBoolFlag(arg, kDeathTestUseFork,
-                      &GTEST_FLAG(death_test_use_fork)) ||
-        ParseStringFlag(arg, kFilterFlag, &GTEST_FLAG(filter)) ||
-        ParseStringFlag(arg, kParamFilterFlag, &GTEST_FLAG(param_filter)) ||
-        ParseStringFlag(arg, kInternalRunDeathTestFlag,
-                        &GTEST_FLAG(internal_run_death_test)) ||
-        ParseBoolFlag(arg, kListTestsFlag, &GTEST_FLAG(list_tests)) ||
-        ParseStringFlag(arg, kOutputFlag, &GTEST_FLAG(output)) ||
-        ParseBoolFlag(arg, kPrintTimeFlag, &GTEST_FLAG(print_time)) ||
-        ParseInt32Flag(arg, kRandomSeedFlag, &GTEST_FLAG(random_seed)) ||
-        ParseInt32Flag(arg, kRepeatFlag, &GTEST_FLAG(repeat)) ||
-        ParseBoolFlag(arg, kShuffleFlag, &GTEST_FLAG(shuffle)) ||
-        ParseInt32Flag(arg, kStackTraceDepthFlag,
-                       &GTEST_FLAG(stack_trace_depth)) ||
-        ParseStringFlag(arg, kStreamResultToFlag,
-                        &GTEST_FLAG(stream_result_to)) ||
-        ParseBoolFlag(arg, kThrowOnFailureFlag,
-                      &GTEST_FLAG(throw_on_failure))
-        ) {
-      // Yes.  Shift the remainder of the argv list left by one.  Note
+    bool remove_flag = false;
+    if (ParseGoogleTestFlag(arg)) {
+      remove_flag = true;
+#if GTEST_USE_OWN_FLAGFILE_FLAG_
+    } else if (ParseStringFlag(arg, kFlagfileFlag, &GTEST_FLAG(flagfile))) {
+      LoadFlagsFromFile(GTEST_FLAG(flagfile));
+      remove_flag = true;
+#endif  // GTEST_USE_OWN_FLAGFILE_FLAG_
+    } else if (arg_string == "--help" || arg_string == "-h" ||
+               arg_string == "-?" || arg_string == "/?" ||
+               HasGoogleTestFlagPrefix(arg)) {
+      // Both help flag and unrecognized Google Test flags (excluding
+      // internal ones) trigger help display.
+      g_help_flag = true;
+    }
+
+    if (remove_flag) {
+      // Shift the remainder of the argv list left by one.  Note
       // that argv has (*argc + 1) elements, the last one always being
       // NULL.  The following loop moves the trailing NULL element as
       // well.
@@ -6458,12 +6801,6 @@ void ParseGoogleTestFlagsOnlyImpl(int* argc, CharType** argv) {
       // We also need to decrement the iterator as we just removed
       // an element.
       i--;
-    } else if (arg_string == "--help" || arg_string == "-h" ||
-               arg_string == "-?" || arg_string == "/?" ||
-               HasGoogleTestFlagPrefix(arg)) {
-      // Both help flag and unrecognized Google Test flags (excluding
-      // internal ones) trigger help display.
-      g_help_flag = true;
     }
   }
 
@@ -6490,24 +6827,16 @@ void ParseGoogleTestFlagsOnly(int* argc, wchar_t** argv) {
 // wchar_t.
 template <typename CharType>
 void InitGoogleTestImpl(int* argc, CharType** argv) {
-  g_init_gtest_count++;
-
   // We don't want to run the initialization code twice.
-  if (g_init_gtest_count != 1) return;
+  if (GTestIsInitialized()) return;
 
   if (*argc <= 0) return;
 
-  internal::g_executable_path = internal::StreamableToString(argv[0]);
-
-#if GTEST_HAS_DEATH_TEST
-
   g_argvs.clear();
   for (int i = 0; i != *argc; i++) {
     g_argvs.push_back(StreamableToString(argv[i]));
   }
 
-#endif  // GTEST_HAS_DEATH_TEST
-
   ParseGoogleTestFlagsOnly(argc, argv);
   GetUnitTestImpl()->PostFlagParsingInit();
 }
@@ -6524,13 +6853,21 @@ void InitGoogleTestImpl(int* argc, CharType** argv) {
 //
 // Calling the function for the second time has no user-visible effect.
 void InitGoogleTest(int* argc, char** argv) {
+#if defined(GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_)
+  GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_(argc, argv);
+#else  // defined(GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_)
   internal::InitGoogleTestImpl(argc, argv);
+#endif  // defined(GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_)
 }
 
 // This overloaded version can be used in Windows programs compiled in
 // UNICODE mode.
 void InitGoogleTest(int* argc, wchar_t** argv) {
+#if defined(GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_)
+  GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_(argc, argv);
+#else  // defined(GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_)
   internal::InitGoogleTestImpl(argc, argv);
+#endif  // defined(GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_)
 }
 
 }  // namespace testing
@@ -6600,9 +6937,9 @@ void InitGoogleTest(int* argc, wchar_t** argv) {
 
 // Indicates that this translation unit is part of Google Test's
 // implementation.  It must come before gtest-internal-inl.h is
-// included, or there will be a compiler error.  This trick is to
-// prevent a user from accidentally including gtest-internal-inl.h in
-// his code.
+// included, or there will be a compiler error.  This trick exists to
+// prevent the accidental inclusion of gtest-internal-inl.h in the
+// user's code.
 #define GTEST_IMPLEMENTATION_ 1
 #undef GTEST_IMPLEMENTATION_
 
@@ -6702,6 +7039,14 @@ KilledBySignal::KilledBySignal(int signum) : signum_(signum) {
 
 // KilledBySignal function-call operator.
 bool KilledBySignal::operator()(int exit_status) const {
+#  if defined(GTEST_KILLED_BY_SIGNAL_OVERRIDE_)
+  {
+    bool result;
+    if (GTEST_KILLED_BY_SIGNAL_OVERRIDE_(signum_, exit_status, &result)) {
+      return result;
+    }
+  }
+#  endif  // defined(GTEST_KILLED_BY_SIGNAL_OVERRIDE_)
   return WIFSIGNALED(exit_status) && WTERMSIG(exit_status) == signum_;
 }
 # endif  // !GTEST_OS_WINDOWS
@@ -7110,7 +7455,6 @@ bool DeathTestImpl::Passed(bool status_ok) {
 }
 
 # if GTEST_OS_WINDOWS
-#ifndef WINRT
 // WindowsDeathTest implements death tests on Windows. Due to the
 // specifics of starting new processes on Windows, death tests there are
 // always threadsafe, and Google Test considers the
@@ -7302,7 +7646,6 @@ DeathTest::TestRole WindowsDeathTest::AssumeRole() {
   set_spawned(true);
   return OVERSEE_TEST;
 }
-#endif
 # else  // We are not on Windows.
 
 // ForkingDeathTest provides implementations for most of the abstract
@@ -7410,6 +7753,11 @@ class ExecDeathTest : public ForkingDeathTest {
   static ::std::vector<testing::internal::string>
   GetArgvsForDeathTestChildProcess() {
     ::std::vector<testing::internal::string> args = GetInjectableArgvs();
+#  if defined(GTEST_EXTRA_DEATH_TEST_COMMAND_LINE_ARGS_)
+    ::std::vector<testing::internal::string> extra_args =
+        GTEST_EXTRA_DEATH_TEST_COMMAND_LINE_ARGS_();
+    args.insert(args.end(), extra_args.begin(), extra_args.end());
+#  endif  // defined(GTEST_EXTRA_DEATH_TEST_COMMAND_LINE_ARGS_)
     return args;
   }
   // The name of the file in which the death test is located.
@@ -7521,6 +7869,7 @@ void StackLowerThanAddress(const void* ptr, bool* result) {
 }
 
 #if GTEST_HAS_CLONE
+GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_
 static bool StackGrowsDown() {
   int dummy;
   bool result;
@@ -7715,12 +8064,7 @@ bool DefaultDeathTestFactory::Create(const char* statement, const RE* regex,
 # if GTEST_OS_WINDOWS
   if (GTEST_FLAG(death_test_style) == "threadsafe" ||
       GTEST_FLAG(death_test_style) == "fast") {
-#ifndef WINRT
     *test = new WindowsDeathTest(statement, regex, file, line);
-#else
-    printf("DeathTest is not supported on winrt!\n");
-    return false;
-#endif
   }
 
 # else
@@ -7743,28 +8087,7 @@ bool DefaultDeathTestFactory::Create(const char* statement, const RE* regex,
   return true;
 }
 
-// Splits a given string on a given delimiter, populating a given
-// vector with the fields.  GTEST_HAS_DEATH_TEST implies that we have
-// ::std::string, so we can use it here.
-static void SplitString(const ::std::string& str, char delimiter,
-                        ::std::vector< ::std::string>* dest) {
-  ::std::vector< ::std::string> parsed;
-  ::std::string::size_type pos = 0;
-  while (::testing::internal::AlwaysTrue()) {
-    const ::std::string::size_type colon = str.find(delimiter, pos);
-    if (colon == ::std::string::npos) {
-      parsed.push_back(str.substr(pos));
-      break;
-    } else {
-      parsed.push_back(str.substr(pos, colon - pos));
-      pos = colon + 1;
-    }
-  }
-  dest->swap(parsed);
-}
-
 # if GTEST_OS_WINDOWS
-#ifndef WINRT
 // Recreates the pipe and event handles from the provided parameters,
 // signals the event, and returns a file descriptor wrapped around the pipe
 // handle. This function is called in the child process only.
@@ -7830,7 +8153,6 @@ int GetStatusFileDescriptor(unsigned int parent_process_id,
 
   return write_fd;
 }
-#endif
 # endif  // GTEST_OS_WINDOWS
 
 // Returns a newly created InternalRunDeathTestFlag object with fields
@@ -7848,7 +8170,6 @@ InternalRunDeathTestFlag* ParseInternalRunDeathTestFlag() {
   int write_fd = -1;
 
 # if GTEST_OS_WINDOWS
-#ifndef WINRT
   unsigned int parent_process_id = 0;
   size_t write_handle_as_size_t = 0;
   size_t event_handle_as_size_t = 0;
@@ -7865,7 +8186,6 @@ InternalRunDeathTestFlag* ParseInternalRunDeathTestFlag() {
   write_fd = GetStatusFileDescriptor(parent_process_id,
                                      write_handle_as_size_t,
                                      event_handle_as_size_t);
-#endif
 # else
 
   if (fields.size() != 4
@@ -7954,7 +8274,7 @@ namespace internal {
 // of them.
 const char kPathSeparator = '\\';
 const char kAlternatePathSeparator = '/';
-const char kPathSeparatorString[] = "\\";
+//const char kPathSeparatorString[] = "\\";
 const char kAlternatePathSeparatorString[] = "/";
 # if GTEST_OS_WINDOWS_MOBILE
 // Windows CE doesn't have a current directory. You should not use
@@ -7968,7 +8288,7 @@ const char kCurrentDirectoryString[] = ".\\";
 # endif  // GTEST_OS_WINDOWS_MOBILE
 #else
 const char kPathSeparator = '/';
-const char kPathSeparatorString[] = "/";
+//const char kPathSeparatorString[] = "/";
 const char kCurrentDirectoryString[] = "./";
 #endif  // GTEST_OS_WINDOWS
 
@@ -7983,7 +8303,7 @@ static bool IsPathSeparator(char c) {
 
 // Returns the current working directory, or "" if unsuccessful.
 FilePath FilePath::GetCurrentDir() {
-#if GTEST_OS_WINDOWS_MOBILE || WINRT
+#if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_WINDOWS_PHONE || GTEST_OS_WINDOWS_RT
   // Windows CE doesn't have a current directory, so we just return
   // something reasonable.
   return FilePath(kCurrentDirectoryString);
@@ -7992,7 +8312,14 @@ FilePath FilePath::GetCurrentDir() {
   return FilePath(_getcwd(cwd, sizeof(cwd)) == NULL ? "" : cwd);
 #else
   char cwd[GTEST_PATH_MAX_ + 1] = { '\0' };
-  return FilePath(getcwd(cwd, sizeof(cwd)) == NULL ? "" : cwd);
+  char* result = getcwd(cwd, sizeof(cwd));
+# if GTEST_OS_NACL
+  // getcwd will likely fail in NaCl due to the sandbox, so return something
+  // reasonable. The user may have provided a shim implementation for getcwd,
+  // however, so fallback only when failure is detected.
+  return FilePath(result == NULL ? kCurrentDirectoryString : cwd);
+# endif  // GTEST_OS_NACL
+  return FilePath(result == NULL ? "" : cwd);
 #endif  // GTEST_OS_WINDOWS_MOBILE
 }
 
@@ -8300,15 +8627,16 @@ void FilePath::Normalize() {
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
+#include <fstream>
 
-#if GTEST_OS_WINDOWS_MOBILE
-# include <windows.h>  // For TerminateProcess()
-#elif GTEST_OS_WINDOWS
+#if GTEST_OS_WINDOWS
+# include <windows.h>
 # include <io.h>
 # include <sys/stat.h>
+# include <map>  // Used in ThreadLocal.
 #else
 # include <unistd.h>
-#endif  // GTEST_OS_WINDOWS_MOBILE
+#endif  // GTEST_OS_WINDOWS
 
 #if GTEST_OS_MAC
 # include <mach/mach_init.h>
@@ -8318,15 +8646,21 @@ void FilePath::Normalize() {
 
 #if GTEST_OS_QNX
 # include <devctl.h>
+# include <fcntl.h>
 # include <sys/procfs.h>
 #endif  // GTEST_OS_QNX
 
+#if GTEST_OS_AIX
+# include <procinfo.h>
+# include <sys/types.h>
+#endif  // GTEST_OS_AIX
+
 
 // Indicates that this translation unit is part of Google Test's
 // implementation.  It must come before gtest-internal-inl.h is
-// included, or there will be a compiler error.  This trick is to
-// prevent a user from accidentally including gtest-internal-inl.h in
-// his code.
+// included, or there will be a compiler error.  This trick exists to
+// prevent the accidental inclusion of gtest-internal-inl.h in the
+// user's code.
 #define GTEST_IMPLEMENTATION_ 1
 #undef GTEST_IMPLEMENTATION_
 
@@ -8342,10 +8676,31 @@ const int kStdOutFileno = STDOUT_FILENO;
 const int kStdErrFileno = STDERR_FILENO;
 #endif  // _MSC_VER
 
-#if GTEST_OS_MAC
+#if GTEST_OS_LINUX
+
+namespace {
+template <typename T>
+T ReadProcFileField(const string& filename, int field) {
+  std::string dummy;
+  std::ifstream file(filename.c_str());
+  while (field-- > 0) {
+    file >> dummy;
+  }
+  T output = 0;
+  file >> output;
+  return output;
+}
+}  // namespace
+
+// Returns the number of active threads, or 0 when there is an error.
+size_t GetThreadCount() {
+  const string filename =
+      (Message() << "/proc/" << getpid() << "/stat").GetString();
+  return ReadProcFileField<int>(filename, 19);
+}
+
+#elif GTEST_OS_MAC
 
-// Returns the number of threads running in the process, or 0 to indicate that
-// we cannot detect it.
 size_t GetThreadCount() {
   const task_t task = mach_task_self();
   mach_msg_type_number_t thread_count;
@@ -8383,6 +8738,19 @@ size_t GetThreadCount() {
   }
 }
 
+#elif GTEST_OS_AIX
+
+size_t GetThreadCount() {
+  struct procentry64 entry;
+  pid_t pid = getpid();
+  int status = getprocs64(&entry, sizeof(entry), NULL, 0, &pid, 1);
+  if (status == 1) {
+    return entry.pi_thcount;
+  } else {
+    return 0;
+  }
+}
+
 #else
 
 size_t GetThreadCount() {
@@ -8391,7 +8759,390 @@ size_t GetThreadCount() {
   return 0;
 }
 
-#endif  // GTEST_OS_MAC
+#endif  // GTEST_OS_LINUX
+
+#if GTEST_IS_THREADSAFE && GTEST_OS_WINDOWS
+
+void SleepMilliseconds(int n) {
+  ::Sleep(n);
+}
+
+AutoHandle::AutoHandle()
+    : handle_(INVALID_HANDLE_VALUE) {}
+
+AutoHandle::AutoHandle(Handle handle)
+    : handle_(handle) {}
+
+AutoHandle::~AutoHandle() {
+  Reset();
+}
+
+AutoHandle::Handle AutoHandle::Get() const {
+  return handle_;
+}
+
+void AutoHandle::Reset() {
+  Reset(INVALID_HANDLE_VALUE);
+}
+
+void AutoHandle::Reset(HANDLE handle) {
+  // Resetting with the same handle we already own is invalid.
+  if (handle_ != handle) {
+    if (IsCloseable()) {
+      ::CloseHandle(handle_);
+    }
+    handle_ = handle;
+  } else {
+    GTEST_CHECK_(!IsCloseable())
+        << "Resetting a valid handle to itself is likely a programmer error "
+            "and thus not allowed.";
+  }
+}
+
+bool AutoHandle::IsCloseable() const {
+  // Different Windows APIs may use either of these values to represent an
+  // invalid handle.
+  return handle_ != NULL && handle_ != INVALID_HANDLE_VALUE;
+}
+
+Notification::Notification()
+    : event_(::CreateEvent(NULL,   // Default security attributes.
+                           TRUE,   // Do not reset automatically.
+                           FALSE,  // Initially unset.
+                           NULL)) {  // Anonymous event.
+  GTEST_CHECK_(event_.Get() != NULL);
+}
+
+void Notification::Notify() {
+  GTEST_CHECK_(::SetEvent(event_.Get()) != FALSE);
+}
+
+void Notification::WaitForNotification() {
+  GTEST_CHECK_(
+      ::WaitForSingleObject(event_.Get(), INFINITE) == WAIT_OBJECT_0);
+}
+
+Mutex::Mutex()
+    : owner_thread_id_(0),
+      type_(kDynamic),
+      critical_section_init_phase_(0),
+      critical_section_(new CRITICAL_SECTION) {
+  ::InitializeCriticalSection(critical_section_);
+}
+
+Mutex::~Mutex() {
+  // Static mutexes are leaked intentionally. It is not thread-safe to try
+  // to clean them up.
+  // TODO(yukawa): Switch to Slim Reader/Writer (SRW) Locks, which requires
+  // nothing to clean it up but is available only on Vista and later.
+  // http://msdn.microsoft.com/en-us/library/windows/desktop/aa904937.aspx
+  if (type_ == kDynamic) {
+    ::DeleteCriticalSection(critical_section_);
+    delete critical_section_;
+    critical_section_ = NULL;
+  }
+}
+
+void Mutex::Lock() {
+  ThreadSafeLazyInit();
+  ::EnterCriticalSection(critical_section_);
+  owner_thread_id_ = ::GetCurrentThreadId();
+}
+
+void Mutex::Unlock() {
+  ThreadSafeLazyInit();
+  // We don't protect writing to owner_thread_id_ here, as it's the
+  // caller's responsibility to ensure that the current thread holds the
+  // mutex when this is called.
+  owner_thread_id_ = 0;
+  ::LeaveCriticalSection(critical_section_);
+}
+
+// Does nothing if the current thread holds the mutex. Otherwise, crashes
+// with high probability.
+void Mutex::AssertHeld() {
+  ThreadSafeLazyInit();
+  GTEST_CHECK_(owner_thread_id_ == ::GetCurrentThreadId())
+      << "The current thread is not holding the mutex @" << this;
+}
+
+// Initializes owner_thread_id_ and critical_section_ in static mutexes.
+void Mutex::ThreadSafeLazyInit() {
+  // Dynamic mutexes are initialized in the constructor.
+  if (type_ == kStatic) {
+    switch (
+        ::InterlockedCompareExchange(&critical_section_init_phase_, 1L, 0L)) {
+      case 0:
+        // If critical_section_init_phase_ was 0 before the exchange, we
+        // are the first to test it and need to perform the initialization.
+        owner_thread_id_ = 0;
+        critical_section_ = new CRITICAL_SECTION;
+        ::InitializeCriticalSection(critical_section_);
+        // Updates the critical_section_init_phase_ to 2 to signal
+        // initialization complete.
+        GTEST_CHECK_(::InterlockedCompareExchange(
+                          &critical_section_init_phase_, 2L, 1L) ==
+                      1L);
+        break;
+      case 1:
+        // Somebody else is already initializing the mutex; spin until they
+        // are done.
+        while (::InterlockedCompareExchange(&critical_section_init_phase_,
+                                            2L,
+                                            2L) != 2L) {
+          // Possibly yields the rest of the thread's time slice to other
+          // threads.
+          ::Sleep(0);
+        }
+        break;
+
+      case 2:
+        break;  // The mutex is already initialized and ready for use.
+
+      default:
+        GTEST_CHECK_(false)
+            << "Unexpected value of critical_section_init_phase_ "
+            << "while initializing a static mutex.";
+    }
+  }
+}
+
+namespace {
+
+class ThreadWithParamSupport : public ThreadWithParamBase {
+ public:
+  static HANDLE CreateThread(Runnable* runnable,
+                             Notification* thread_can_start) {
+    ThreadMainParam* param = new ThreadMainParam(runnable, thread_can_start);
+    DWORD thread_id;
+    // TODO(yukawa): Consider to use _beginthreadex instead.
+    HANDLE thread_handle = ::CreateThread(
+        NULL,    // Default security.
+        0,       // Default stack size.
+        &ThreadWithParamSupport::ThreadMain,
+        param,   // Parameter to ThreadMainStatic
+        0x0,     // Default creation flags.
+        &thread_id);  // Need a valid pointer for the call to work under Win98.
+    GTEST_CHECK_(thread_handle != NULL) << "CreateThread failed with error "
+                                        << ::GetLastError() << ".";
+    if (thread_handle == NULL) {
+      delete param;
+    }
+    return thread_handle;
+  }
+
+ private:
+  struct ThreadMainParam {
+    ThreadMainParam(Runnable* runnable, Notification* thread_can_start)
+        : runnable_(runnable),
+          thread_can_start_(thread_can_start) {
+    }
+    scoped_ptr<Runnable> runnable_;
+    // Does not own.
+    Notification* thread_can_start_;
+  };
+
+  static DWORD WINAPI ThreadMain(void* ptr) {
+    // Transfers ownership.
+    scoped_ptr<ThreadMainParam> param(static_cast<ThreadMainParam*>(ptr));
+    if (param->thread_can_start_ != NULL)
+      param->thread_can_start_->WaitForNotification();
+    param->runnable_->Run();
+    return 0;
+  }
+
+  // Prohibit instantiation.
+  ThreadWithParamSupport();
+
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadWithParamSupport);
+};
+
+}  // namespace
+
+ThreadWithParamBase::ThreadWithParamBase(Runnable *runnable,
+                                         Notification* thread_can_start)
+      : thread_(ThreadWithParamSupport::CreateThread(runnable,
+                                                     thread_can_start)) {
+}
+
+ThreadWithParamBase::~ThreadWithParamBase() {
+  Join();
+}
+
+void ThreadWithParamBase::Join() {
+  GTEST_CHECK_(::WaitForSingleObject(thread_.Get(), INFINITE) == WAIT_OBJECT_0)
+      << "Failed to join the thread with error " << ::GetLastError() << ".";
+}
+
+// Maps a thread to a set of ThreadIdToThreadLocals that have values
+// instantiated on that thread and notifies them when the thread exits.  A
+// ThreadLocal instance is expected to persist until all threads it has
+// values on have terminated.
+class ThreadLocalRegistryImpl {
+ public:
+  // Registers thread_local_instance as having value on the current thread.
+  // Returns a value that can be used to identify the thread from other threads.
+  static ThreadLocalValueHolderBase* GetValueOnCurrentThread(
+      const ThreadLocalBase* thread_local_instance) {
+    DWORD current_thread = ::GetCurrentThreadId();
+    MutexLock lock(&mutex_);
+    ThreadIdToThreadLocals* const thread_to_thread_locals =
+        GetThreadLocalsMapLocked();
+    ThreadIdToThreadLocals::iterator thread_local_pos =
+        thread_to_thread_locals->find(current_thread);
+    if (thread_local_pos == thread_to_thread_locals->end()) {
+      thread_local_pos = thread_to_thread_locals->insert(
+          std::make_pair(current_thread, ThreadLocalValues())).first;
+      StartWatcherThreadFor(current_thread);
+    }
+    ThreadLocalValues& thread_local_values = thread_local_pos->second;
+    ThreadLocalValues::iterator value_pos =
+        thread_local_values.find(thread_local_instance);
+    if (value_pos == thread_local_values.end()) {
+      value_pos =
+          thread_local_values
+              .insert(std::make_pair(
+                  thread_local_instance,
+                  linked_ptr<ThreadLocalValueHolderBase>(
+                      thread_local_instance->NewValueForCurrentThread())))
+              .first;
+    }
+    return value_pos->second.get();
+  }
+
+  static void OnThreadLocalDestroyed(
+      const ThreadLocalBase* thread_local_instance) {
+    std::vector<linked_ptr<ThreadLocalValueHolderBase> > value_holders;
+    // Clean up the ThreadLocalValues data structure while holding the lock, but
+    // defer the destruction of the ThreadLocalValueHolderBases.
+    {
+      MutexLock lock(&mutex_);
+      ThreadIdToThreadLocals* const thread_to_thread_locals =
+          GetThreadLocalsMapLocked();
+      for (ThreadIdToThreadLocals::iterator it =
+          thread_to_thread_locals->begin();
+          it != thread_to_thread_locals->end();
+          ++it) {
+        ThreadLocalValues& thread_local_values = it->second;
+        ThreadLocalValues::iterator value_pos =
+            thread_local_values.find(thread_local_instance);
+        if (value_pos != thread_local_values.end()) {
+          value_holders.push_back(value_pos->second);
+          thread_local_values.erase(value_pos);
+          // This 'if' can only be successful at most once, so theoretically we
+          // could break out of the loop here, but we don't bother doing so.
+        }
+      }
+    }
+    // Outside the lock, let the destructor for 'value_holders' deallocate the
+    // ThreadLocalValueHolderBases.
+  }
+
+  static void OnThreadExit(DWORD thread_id) {
+    GTEST_CHECK_(thread_id != 0) << ::GetLastError();
+    std::vector<linked_ptr<ThreadLocalValueHolderBase> > value_holders;
+    // Clean up the ThreadIdToThreadLocals data structure while holding the
+    // lock, but defer the destruction of the ThreadLocalValueHolderBases.
+    {
+      MutexLock lock(&mutex_);
+      ThreadIdToThreadLocals* const thread_to_thread_locals =
+          GetThreadLocalsMapLocked();
+      ThreadIdToThreadLocals::iterator thread_local_pos =
+          thread_to_thread_locals->find(thread_id);
+      if (thread_local_pos != thread_to_thread_locals->end()) {
+        ThreadLocalValues& thread_local_values = thread_local_pos->second;
+        for (ThreadLocalValues::iterator value_pos =
+            thread_local_values.begin();
+            value_pos != thread_local_values.end();
+            ++value_pos) {
+          value_holders.push_back(value_pos->second);
+        }
+        thread_to_thread_locals->erase(thread_local_pos);
+      }
+    }
+    // Outside the lock, let the destructor for 'value_holders' deallocate the
+    // ThreadLocalValueHolderBases.
+  }
+
+ private:
+  // In a particular thread, maps a ThreadLocal object to its value.
+  typedef std::map<const ThreadLocalBase*,
+                   linked_ptr<ThreadLocalValueHolderBase> > ThreadLocalValues;
+  // Stores all ThreadIdToThreadLocals having values in a thread, indexed by
+  // thread's ID.
+  typedef std::map<DWORD, ThreadLocalValues> ThreadIdToThreadLocals;
+
+  // Holds the thread id and thread handle that we pass from
+  // StartWatcherThreadFor to WatcherThreadFunc.
+  typedef std::pair<DWORD, HANDLE> ThreadIdAndHandle;
+
+  static void StartWatcherThreadFor(DWORD thread_id) {
+    // The returned handle will be kept in thread_map and closed by
+    // watcher_thread in WatcherThreadFunc.
+    HANDLE thread = ::OpenThread(SYNCHRONIZE | THREAD_QUERY_INFORMATION,
+                                 FALSE,
+                                 thread_id);
+    GTEST_CHECK_(thread != NULL);
+    // We need to to pass a valid thread ID pointer into CreateThread for it
+    // to work correctly under Win98.
+    DWORD watcher_thread_id;
+    HANDLE watcher_thread = ::CreateThread(
+        NULL,   // Default security.
+        0,      // Default stack size
+        &ThreadLocalRegistryImpl::WatcherThreadFunc,
+        reinterpret_cast<LPVOID>(new ThreadIdAndHandle(thread_id, thread)),
+        CREATE_SUSPENDED,
+        &watcher_thread_id);
+    GTEST_CHECK_(watcher_thread != NULL);
+    // Give the watcher thread the same priority as ours to avoid being
+    // blocked by it.
+    ::SetThreadPriority(watcher_thread,
+                        ::GetThreadPriority(::GetCurrentThread()));
+    ::ResumeThread(watcher_thread);
+    ::CloseHandle(watcher_thread);
+  }
+
+  // Monitors exit from a given thread and notifies those
+  // ThreadIdToThreadLocals about thread termination.
+  static DWORD WINAPI WatcherThreadFunc(LPVOID param) {
+    const ThreadIdAndHandle* tah =
+        reinterpret_cast<const ThreadIdAndHandle*>(param);
+    GTEST_CHECK_(
+        ::WaitForSingleObject(tah->second, INFINITE) == WAIT_OBJECT_0);
+    OnThreadExit(tah->first);
+    ::CloseHandle(tah->second);
+    delete tah;
+    return 0;
+  }
+
+  // Returns map of thread local instances.
+  static ThreadIdToThreadLocals* GetThreadLocalsMapLocked() {
+    mutex_.AssertHeld();
+    static ThreadIdToThreadLocals* map = new ThreadIdToThreadLocals;
+    return map;
+  }
+
+  // Protects access to GetThreadLocalsMapLocked() and its return value.
+  static Mutex mutex_;
+  // Protects access to GetThreadMapLocked() and its return value.
+  static Mutex thread_map_mutex_;
+};
+
+Mutex ThreadLocalRegistryImpl::mutex_(Mutex::kStaticMutex);
+Mutex ThreadLocalRegistryImpl::thread_map_mutex_(Mutex::kStaticMutex);
+
+ThreadLocalValueHolderBase* ThreadLocalRegistry::GetValueOnCurrentThread(
+      const ThreadLocalBase* thread_local_instance) {
+  return ThreadLocalRegistryImpl::GetValueOnCurrentThread(
+      thread_local_instance);
+}
+
+void ThreadLocalRegistry::OnThreadLocalDestroyed(
+      const ThreadLocalBase* thread_local_instance) {
+  ThreadLocalRegistryImpl::OnThreadLocalDestroyed(thread_local_instance);
+}
+
+#endif  // GTEST_IS_THREADSAFE && GTEST_OS_WINDOWS
 
 #if GTEST_USES_POSIX_RE
 
@@ -8741,7 +9492,6 @@ GTEST_API_ ::std::string FormatCompilerIndependentFileLocation(
     return file_name + ":" + StreamableToString(line);
 }
 
-
 GTestLog::GTestLog(GTestLogSeverity severity, const char* file, int line)
     : severity_(severity) {
   const char* const marker =
@@ -8762,10 +9512,7 @@ GTestLog::~GTestLog() {
 }
 // Disable Microsoft deprecation warnings for POSIX functions called from
 // this class (creat, dup, dup2, and close)
-#ifdef _MSC_VER
-# pragma warning(push)
-# pragma warning(disable: 4996)
-#endif  // _MSC_VER
+GTEST_DISABLE_MSC_WARNINGS_PUSH_(4996)
 
 #if GTEST_HAS_STREAM_REDIRECTION
 
@@ -8774,7 +9521,6 @@ class CapturedStream {
  public:
   // The ctor redirects the stream to a temporary file.
   explicit CapturedStream(int fd) : fd_(fd), uncaptured_fd_(dup(fd)) {
-#ifndef WINRT
 # if GTEST_OS_WINDOWS
     char temp_dir_path[MAX_PATH + 1] = { '\0' };  // NOLINT
     char temp_file_path[MAX_PATH + 1] = { '\0' };  // NOLINT
@@ -8820,7 +9566,6 @@ class CapturedStream {
     fflush(NULL);
     dup2(captured_fd, fd_);
     close(captured_fd);
-#endif
   }
 
   ~CapturedStream() {
@@ -8843,12 +9588,6 @@ class CapturedStream {
   }
 
  private:
-  // Reads the entire content of a file as an std::string.
-  static std::string ReadEntireFile(FILE* file);
-
-  // Returns the size (in bytes) of a file.
-  static size_t GetFileSize(FILE* file);
-
   const int fd_;  // A stream to capture.
   int uncaptured_fd_;
   // Name of the temporary file holding the stderr output.
@@ -8857,38 +9596,7 @@ class CapturedStream {
   GTEST_DISALLOW_COPY_AND_ASSIGN_(CapturedStream);
 };
 
-// Returns the size (in bytes) of a file.
-size_t CapturedStream::GetFileSize(FILE* file) {
-  fseek(file, 0, SEEK_END);
-  return static_cast<size_t>(ftell(file));
-}
-
-// Reads the entire content of a file as a string.
-std::string CapturedStream::ReadEntireFile(FILE* file) {
-  const size_t file_size = GetFileSize(file);
-  char* const buffer = new char[file_size];
-
-  size_t bytes_last_read = 0;  // # of bytes read in the last fread()
-  size_t bytes_read = 0;       // # of bytes read so far
-
-  fseek(file, 0, SEEK_SET);
-
-  // Keeps reading the file until we cannot read further or the
-  // pre-determined file size is reached.
-  do {
-    bytes_last_read = fread(buffer+bytes_read, 1, file_size-bytes_read, file);
-    bytes_read += bytes_last_read;
-  } while (bytes_last_read > 0 && bytes_read < file_size);
-
-  const std::string content(buffer, bytes_read);
-  delete[] buffer;
-
-  return content;
-}
-
-# ifdef _MSC_VER
-#  pragma warning(pop)
-# endif  // _MSC_VER
+GTEST_DISABLE_MSC_WARNINGS_POP_()
 
 static CapturedStream* g_captured_stderr = NULL;
 static CapturedStream* g_captured_stdout = NULL;
@@ -8934,10 +9642,52 @@ std::string GetCapturedStderr() {
 
 #endif  // GTEST_HAS_STREAM_REDIRECTION
 
-#if GTEST_HAS_DEATH_TEST
+std::string TempDir() {
+#if GTEST_OS_WINDOWS_MOBILE
+  return "\\temp\\";
+#elif GTEST_OS_WINDOWS
+  const char* temp_dir = posix::GetEnv("TEMP");
+  if (temp_dir == NULL || temp_dir[0] == '\0')
+    return "\\temp\\";
+  else if (temp_dir[strlen(temp_dir) - 1] == '\\')
+    return temp_dir;
+  else
+    return std::string(temp_dir) + "\\";
+#elif GTEST_OS_LINUX_ANDROID
+  return "/sdcard/";
+#else
+  return "/tmp/";
+#endif  // GTEST_OS_WINDOWS_MOBILE
+}
 
-// A copy of all command line arguments.  Set by InitGoogleTest().
-::std::vector<testing::internal::string> g_argvs;
+size_t GetFileSize(FILE* file) {
+  fseek(file, 0, SEEK_END);
+  return static_cast<size_t>(ftell(file));
+}
+
+std::string ReadEntireFile(FILE* file) {
+  const size_t file_size = GetFileSize(file);
+  char* const buffer = new char[file_size];
+
+  size_t bytes_last_read = 0;  // # of bytes read in the last fread()
+  size_t bytes_read = 0;       // # of bytes read so far
+
+  fseek(file, 0, SEEK_SET);
+
+  // Keeps reading the file until we cannot read further or the
+  // pre-determined file size is reached.
+  do {
+    bytes_last_read = fread(buffer+bytes_read, 1, file_size-bytes_read, file);
+    bytes_read += bytes_last_read;
+  } while (bytes_last_read > 0 && bytes_read < file_size);
+
+  const std::string content(buffer, bytes_read);
+  delete[] buffer;
+
+  return content;
+}
+
+#if GTEST_HAS_DEATH_TEST
 
 static const ::std::vector<testing::internal::string>* g_injected_test_argvs =
                                         NULL;  // Owned.
@@ -8952,7 +9702,7 @@ const ::std::vector<testing::internal::string>& GetInjectableArgvs() {
   if (g_injected_test_argvs != NULL) {
     return *g_injected_test_argvs;
   }
-  return g_argvs;
+  return GetArgvs();
 }
 #endif  // GTEST_HAS_DEATH_TEST
 
@@ -9026,6 +9776,9 @@ bool ParseInt32(const Message& src_text, const char* str, Int32* value) {
 //
 // The value is considered true iff it's not "0".
 bool BoolFromGTestEnv(const char* flag, bool default_value) {
+#if defined(GTEST_GET_BOOL_FROM_ENV_)
+  return GTEST_GET_BOOL_FROM_ENV_(flag, default_value);
+#endif  // defined(GTEST_GET_BOOL_FROM_ENV_)
   const std::string env_var = FlagToEnvVar(flag);
   const char* const string_value = posix::GetEnv(env_var.c_str());
   return string_value == NULL ?
@@ -9036,6 +9789,9 @@ bool BoolFromGTestEnv(const char* flag, bool default_value) {
 // variable corresponding to the given flag; if it isn't set or
 // doesn't represent a valid 32-bit integer, returns default_value.
 Int32 Int32FromGTestEnv(const char* flag, Int32 default_value) {
+#if defined(GTEST_GET_INT32_FROM_ENV_)
+  return GTEST_GET_INT32_FROM_ENV_(flag, default_value);
+#endif  // defined(GTEST_GET_INT32_FROM_ENV_)
   const std::string env_var = FlagToEnvVar(flag);
   const char* const string_value = posix::GetEnv(env_var.c_str());
   if (string_value == NULL) {
@@ -9057,10 +9813,33 @@ Int32 Int32FromGTestEnv(const char* flag, Int32 default_value) {
 
 // Reads and returns the string environment variable corresponding to
 // the given flag; if it's not set, returns default_value.
-const char* StringFromGTestEnv(const char* flag, const char* default_value) {
+std::string StringFromGTestEnv(const char* flag, const char* default_value) {
+#if defined(GTEST_GET_STRING_FROM_ENV_)
+  return GTEST_GET_STRING_FROM_ENV_(flag, default_value);
+#endif  // defined(GTEST_GET_STRING_FROM_ENV_)
   const std::string env_var = FlagToEnvVar(flag);
-  const char* const value = posix::GetEnv(env_var.c_str());
-  return value == NULL ? default_value : value;
+  const char* value = posix::GetEnv(env_var.c_str());
+  if (value != NULL) {
+    return value;
+  }
+
+  // As a special case for the 'output' flag, if GTEST_OUTPUT is not
+  // set, we look for XML_OUTPUT_FILE, which is set by the Bazel build
+  // system.  The value of XML_OUTPUT_FILE is a filename without the
+  // "xml:" prefix of GTEST_OUTPUT.
+  //
+  // The net priority order after flag processing is thus:
+  //   --gtest_output command line flag
+  //   GTEST_OUTPUT environment variable
+  //   XML_OUTPUT_FILE environment variable
+  //   'default_value'
+  if (strcmp(flag, "output") == 0) {
+    value = posix::GetEnv("XML_OUTPUT_FILE");
+    if (value != NULL) {
+      return std::string("xml:") + value;
+    }
+  }
+  return default_value;
 }
 
 }  // namespace internal
@@ -9111,6 +9890,7 @@ const char* StringFromGTestEnv(const char* flag, const char* default_value) {
 
 #include <ctype.h>
 #include <stdio.h>
+#include <cwchar>
 #include <ostream>  // NOLINT
 #include <string>
 
@@ -9121,6 +9901,9 @@ namespace {
 using ::std::ostream;
 
 // Prints a segment of bytes in the given object.
+GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_
+GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_
+GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_
 void PrintByteSegmentInObjectTo(const unsigned char* obj_bytes, size_t start,
                                 size_t count, ostream* os) {
   char text[5] = "";
@@ -9317,6 +10100,9 @@ void PrintTo(wchar_t wc, ostream* os) {
 // The array starts at begin, the length is len, it may include '\0' characters
 // and may not be NUL-terminated.
 template <typename CharType>
+GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_
+GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_
+GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_
 static void PrintCharsAsStringTo(
     const CharType* begin, size_t len, ostream* os) {
   const char* const kQuoteBegin = sizeof(CharType) == 1 ? "\"" : "L\"";
@@ -9338,6 +10124,9 @@ static void PrintCharsAsStringTo(
 // Prints a (const) char/wchar_t array of 'len' elements, starting at address
 // 'begin'.  CharType must be either char or wchar_t.
 template <typename CharType>
+GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_
+GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_
+GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_
 static void UniversalPrintCharArray(
     const CharType* begin, size_t len, ostream* os) {
   // The code
@@ -9394,7 +10183,7 @@ void PrintTo(const wchar_t* s, ostream* os) {
     *os << "NULL";
   } else {
     *os << ImplicitCast_<const void*>(s) << " pointing to ";
-    PrintCharsAsStringTo(s, wcslen(s), os);
+    PrintCharsAsStringTo(s, std::wcslen(s), os);
   }
 }
 #endif  // wchar_t is native
@@ -9462,9 +10251,9 @@ void PrintWideStringTo(const ::std::wstring& s, ostream* os) {
 
 // Indicates that this translation unit is part of Google Test's
 // implementation.  It must come before gtest-internal-inl.h is
-// included, or there will be a compiler error.  This trick is to
-// prevent a user from accidentally including gtest-internal-inl.h in
-// his code.
+// included, or there will be a compiler error.  This trick exists to
+// prevent the accidental inclusion of gtest-internal-inl.h in the
+// user's code.
 #define GTEST_IMPLEMENTATION_ 1
 #undef GTEST_IMPLEMENTATION_
 
@@ -9579,33 +10368,41 @@ static const char* SkipSpaces(const char* str) {
   return str;
 }
 
+static std::vector<std::string> SplitIntoTestNames(const char* src) {
+  std::vector<std::string> name_vec;
+  src = SkipSpaces(src);
+  for (; src != NULL; src = SkipComma(src)) {
+    name_vec.push_back(StripTrailingSpaces(GetPrefixUntilComma(src)));
+  }
+  return name_vec;
+}
+
 // Verifies that registered_tests match the test names in
-// defined_test_names_; returns registered_tests if successful, or
+// registered_tests_; returns registered_tests if successful, or
 // aborts the program otherwise.
 const char* TypedTestCasePState::VerifyRegisteredTestNames(
     const char* file, int line, const char* registered_tests) {
-  typedef ::std::set<const char*>::const_iterator DefinedTestIter;
+  typedef RegisteredTestsMap::const_iterator RegisteredTestIter;
   registered_ = true;
 
-  // Skip initial whitespace in registered_tests since some
-  // preprocessors prefix stringizied literals with whitespace.
-  registered_tests = SkipSpaces(registered_tests);
+  std::vector<std::string> name_vec = SplitIntoTestNames(registered_tests);
 
   Message errors;
-  ::std::set<std::string> tests;
-  for (const char* names = registered_tests; names != NULL;
-       names = SkipComma(names)) {
-    const std::string name = GetPrefixUntilComma(names);
+
+  std::set<std::string> tests;
+  for (std::vector<std::string>::const_iterator name_it = name_vec.begin();
+       name_it != name_vec.end(); ++name_it) {
+    const std::string& name = *name_it;
     if (tests.count(name) != 0) {
       errors << "Test " << name << " is listed more than once.\n";
       continue;
     }
 
     bool found = false;
-    for (DefinedTestIter it = defined_test_names_.begin();
-         it != defined_test_names_.end();
+    for (RegisteredTestIter it = registered_tests_.begin();
+         it != registered_tests_.end();
          ++it) {
-      if (name == *it) {
+      if (name == it->first) {
         found = true;
         break;
       }
@@ -9619,11 +10416,11 @@ const char* TypedTestCasePState::VerifyRegisteredTestNames(
     }
   }
 
-  for (DefinedTestIter it = defined_test_names_.begin();
-       it != defined_test_names_.end();
+  for (RegisteredTestIter it = registered_tests_.begin();
+       it != registered_tests_.end();
        ++it) {
-    if (tests.count(*it) == 0) {
-      errors << "You forgot to list test " << *it << ".\n";
+    if (tests.count(it->first) == 0) {
+      errors << "You forgot to list test " << it->first << ".\n";
     }
   }
 
diff --git a/modules/ts/src/ts_perf.cpp b/modules/ts/src/ts_perf.cpp
index 1a959f1..6a41bc9 100644
--- a/modules/ts/src/ts_perf.cpp
+++ b/modules/ts/src/ts_perf.cpp
@@ -19,6 +19,7 @@
 # include <sys/time.h>
 #endif
 
+using namespace cvtest;
 using namespace perf;
 
 int64 TestBase::timeLimitDefault = 0;
@@ -37,7 +38,6 @@ static double       param_max_outliers;
 static double       param_max_deviation;
 static unsigned int param_min_samples;
 static unsigned int param_force_samples;
-static uint64       param_seed;
 static double       param_time_limit;
 static int          param_threads;
 static bool         param_write_sanity;
@@ -45,7 +45,13 @@ static bool         param_verify_sanity;
 #ifdef CV_COLLECT_IMPL_DATA
 static bool         param_collect_impl;
 #endif
+#ifdef ENABLE_INSTRUMENTATION
+static int          param_instrument;
+#endif
+
+namespace cvtest {
 extern bool         test_ipp_check;
+}
 
 #ifdef HAVE_CUDA
 static int          param_cuda_device;
@@ -57,6 +63,7 @@ static bool         log_power_checkpoints;
 
 #include <sys/syscall.h>
 #include <pthread.h>
+#include <cerrno>
 static void setCurrentThreadAffinityMask(int mask)
 {
     pid_t pid=gettid();
@@ -727,7 +734,210 @@ public:
     }
 };
 
+#ifdef ENABLE_INSTRUMENTATION
+static void printShift(cv::instr::InstrNode *pNode, cv::instr::InstrNode* pRoot)
+{
+    // Print empty line for a big tree nodes
+    if(pNode->m_pParent)
+    {
+        int parendIdx = pNode->m_pParent->findChild(pNode);
+        if(parendIdx > 0 && pNode->m_pParent->m_childs[parendIdx-1]->m_childs.size())
+        {
+            printShift(pNode->m_pParent->m_childs[parendIdx-1]->m_childs[0], pRoot);
+            printf("\n");
+        }
+    }
+
+    // Check if parents have more childes
+    std::vector<cv::instr::InstrNode*> cache;
+    cv::instr::InstrNode *pTmpNode = pNode;
+    while(pTmpNode->m_pParent && pTmpNode->m_pParent != pRoot)
+    {
+        cache.push_back(pTmpNode->m_pParent);
+        pTmpNode = pTmpNode->m_pParent;
+    }
+    for(int i = (int)cache.size()-1; i >= 0; i--)
+    {
+        if(cache[i]->m_pParent)
+        {
+            if(cache[i]->m_pParent->findChild(cache[i]) == (int)cache[i]->m_pParent->m_childs.size()-1)
+                printf("    ");
+            else
+                printf("|   ");
+        }
+    }
+}
+
+static double calcLocalWeight(cv::instr::InstrNode *pNode)
+{
+    if(pNode->m_pParent && pNode->m_pParent->m_pParent)
+        return ((double)pNode->m_payload.m_ticksTotal*100/pNode->m_pParent->m_payload.m_ticksTotal);
+    else
+        return 100;
+}
+
+static double calcGlobalWeight(cv::instr::InstrNode *pNode)
+{
+    cv::instr::InstrNode* globNode = pNode;
+
+    while(globNode->m_pParent && globNode->m_pParent->m_pParent)
+        globNode = globNode->m_pParent;
+
+    return ((double)pNode->m_payload.m_ticksTotal*100/(double)globNode->m_payload.m_ticksTotal);
+}
+
+static void printNodeRec(cv::instr::InstrNode *pNode, cv::instr::InstrNode *pRoot)
+{
+    printf("%s", (pNode->m_payload.m_funName.substr(0, 40) + ((pNode->m_payload.m_funName.size()>40)?"...":"")).c_str());
+
+    // Write instrumentation flags
+    if(pNode->m_payload.m_instrType != cv::instr::TYPE_GENERAL || pNode->m_payload.m_implType != cv::instr::IMPL_PLAIN)
+    {
+        printf("<");
+        if(pNode->m_payload.m_instrType == cv::instr::TYPE_WRAPPER)
+            printf("W");
+        else if(pNode->m_payload.m_instrType == cv::instr::TYPE_FUN)
+            printf("F");
+        else if(pNode->m_payload.m_instrType == cv::instr::TYPE_MARKER)
+            printf("MARK");
+
+        if(pNode->m_payload.m_instrType != cv::instr::TYPE_GENERAL && pNode->m_payload.m_implType != cv::instr::IMPL_PLAIN)
+            printf("_");
+
+        if(pNode->m_payload.m_implType == cv::instr::IMPL_IPP)
+            printf("IPP");
+        else if(pNode->m_payload.m_implType == cv::instr::IMPL_OPENCL)
+            printf("OCL");
+
+        printf(">");
+    }
+
+    if(pNode->m_pParent)
+    {
+        printf(" - TC:%d C:%d", pNode->m_payload.m_threads, pNode->m_payload.m_counter);
+        printf(" T:%.2fms", pNode->m_payload.getTotalMs());
+        if(pNode->m_pParent->m_pParent)
+            printf(" L:%.0f%% G:%.0f%%", calcLocalWeight(pNode), calcGlobalWeight(pNode));
+    }
+    printf("\n");
+
+    {
+        // Group childes by name
+        for(size_t i = 1; i < pNode->m_childs.size(); i++)
+        {
+            if(pNode->m_childs[i-1]->m_payload.m_funName == pNode->m_childs[i]->m_payload.m_funName )
+                continue;
+            for(size_t j = i+1; j < pNode->m_childs.size(); j++)
+            {
+                if(pNode->m_childs[i-1]->m_payload.m_funName == pNode->m_childs[j]->m_payload.m_funName )
+                {
+                    cv::swap(pNode->m_childs[i], pNode->m_childs[j]);
+                    i++;
+                }
+            }
+        }
+    }
+
+    for(size_t i = 0; i < pNode->m_childs.size(); i++)
+    {
+        printShift(pNode->m_childs[i], pRoot);
+
+        if(i == pNode->m_childs.size()-1)
+            printf("\\---");
+        else
+            printf("|---");
+        printNodeRec(pNode->m_childs[i], pRoot);
+    }
+}
+
+template <typename T>
+std::string to_string_with_precision(const T value, const int p = 3)
+{
+    std::ostringstream out;
+    out << std::fixed << std::setprecision(p) << value;
+    return out.str();
+}
+
+static cv::String nodeToString(cv::instr::InstrNode *pNode)
+{
+    cv::String string;
+    if (pNode->m_payload.m_funName == "ROOT")
+        string = pNode->m_payload.m_funName;
+    else
+    {
+        string = "#";
+        string += std::to_string((int)pNode->m_payload.m_instrType);
+        string += pNode->m_payload.m_funName;
+        string += " - L:";
+        string += to_string_with_precision(calcLocalWeight(pNode));
+        string += ", G:";
+        string += to_string_with_precision(calcGlobalWeight(pNode));
+    }
+    string += "(";
+    for(size_t i = 0; i < pNode->m_childs.size(); i++)
+        string += nodeToString(pNode->m_childs[i]);
+    string += ")";
+
+    return string;
+}
+
+static uint64 getNodeTimeRec(cv::instr::InstrNode *pNode, cv::instr::TYPE type, cv::instr::IMPL impl)
+{
+    uint64 ticks = 0;
+
+    if (pNode->m_pParent && (type < 0 || pNode->m_payload.m_instrType == type) && pNode->m_payload.m_implType == impl)
+    {
+        ticks = pNode->m_payload.m_ticksTotal;
+        return ticks;
+    }
+
+    for(size_t i = 0; i < pNode->m_childs.size(); i++)
+        ticks += getNodeTimeRec(pNode->m_childs[i], type, impl);
+
+    return ticks;
+}
+
+static uint64 getImplTime(cv::instr::IMPL impl)
+{
+    uint64 ticks = 0;
+    cv::instr::InstrNode *pRoot = cv::instr::getTrace();
+
+    ticks = getNodeTimeRec(pRoot, cv::instr::TYPE_FUN, impl);
+
+    return ticks;
+}
+
+static uint64 getTotalTime()
+{
+    uint64 ticks = 0;
+    cv::instr::InstrNode *pRoot = cv::instr::getTrace();
+
+    for(size_t i = 0; i < pRoot->m_childs.size(); i++)
+        ticks += pRoot->m_childs[i]->m_payload.m_ticksTotal;
+
+    return ticks;
+}
+
+::cv::String InstumentData::treeToString()
+{
+    cv::String string = nodeToString(cv::instr::getTrace());
+    return string;
+}
 
+void InstumentData::printTree()
+{
+    printf("[ TRACE    ]\n");
+    printNodeRec(cv::instr::getTrace(), cv::instr::getTrace());
+#ifdef HAVE_IPP
+    printf("\nIPP weight: %.1f%%", ((double)getImplTime(cv::instr::IMPL_IPP)*100/(double)getTotalTime()));
+#endif
+#ifdef HAVE_OPENCL
+    printf("\nOPENCL weight: %.1f%%", ((double)getImplTime(cv::instr::IMPL_OPENCL)*100/(double)getTotalTime()));
+#endif
+    printf("\n[/TRACE    ]\n");
+    fflush(stdout);
+}
+#endif
 
 /*****************************************************************************************\
 *                                   ::perf::TestBase
@@ -775,6 +985,9 @@ void TestBase::Init(const std::vector<std::string> & availableImpls,
 #ifdef CV_COLLECT_IMPL_DATA
         "{   perf_collect_impl           |false    |collect info about executed implementations}"
 #endif
+#ifdef ENABLE_INSTRUMENTATION
+        "{   perf_instrument             |0        |instrument code to collect implementations trace: 1 - perform instrumentation; 2 - separate functions with the same name }"
+#endif
         "{   help h                      |false    |print help info}"
 #ifdef HAVE_CUDA
         "{   perf_cuda_device            |0        |run CUDA test suite onto specific CUDA capable device}"
@@ -826,6 +1039,9 @@ void TestBase::Init(const std::vector<std::string> & availableImpls,
 #ifdef CV_COLLECT_IMPL_DATA
     param_collect_impl  = args.get<bool>("perf_collect_impl");
 #endif
+#ifdef ENABLE_INSTRUMENTATION
+    param_instrument    = args.get<int>("perf_instrument");
+#endif
 #ifdef ANDROID
     param_affinity_mask   = args.get<int>("perf_affinity_mask");
     log_power_checkpoints = args.has("perf_log_power_checkpoints");
@@ -856,6 +1072,16 @@ void TestBase::Init(const std::vector<std::string> & availableImpls,
     else
         cv::setUseCollection(0);
 #endif
+#ifdef ENABLE_INSTRUMENTATION
+    if(param_instrument > 0)
+    {
+        if(param_instrument == 2)
+            cv::instr::setFlags(cv::instr::getFlags()|cv::instr::FLAGS_EXPAND_SAME_NAMES);
+        cv::instr::setUseInstrumentation(true);
+    }
+    else
+        cv::instr::setUseInstrumentation(false);
+#endif
 
 #ifdef HAVE_CUDA
 
@@ -969,13 +1195,13 @@ int64 TestBase::_calibrate()
             cv::Mat b(2048, 2048, CV_32S, cv::Scalar(2));
             declare.time(30);
             double s = 0;
-            for(declare.iterations(20); startTimer(), next(); stopTimer())
+            for(declare.iterations(20); next() && startTimer(); stopTimer())
                 s+=a.dot(b);
             declare.time(s);
 
             //self calibration
             SetUp();
-            for(declare.iterations(1000); startTimer(), next(); stopTimer()){}
+            for(declare.iterations(1000); next() && startTimer(); stopTimer()){}
         }
     };
 
@@ -1242,8 +1468,6 @@ bool TestBase::next()
     }
 #endif
 
-    if (has_next)
-        startTimer(); // really we should measure activity from this moment, so reset start time
     return has_next;
 }
 
@@ -1281,9 +1505,17 @@ unsigned int TestBase::getTotalOutputSize() const
     return res;
 }
 
-void TestBase::startTimer()
+bool TestBase::startTimer()
 {
+#ifdef ENABLE_INSTRUMENTATION
+    if(currentIter == 0)
+    {
+        cv::instr::setFlags(cv::instr::getFlags()|cv::instr::FLAGS_MAPPING); // enable mapping for the first run
+        cv::instr::resetTrace();
+    }
+#endif
     lastTime = cv::getTickCount();
+    return true; // dummy true for conditional loop
 }
 
 void TestBase::stopTimer()
@@ -1297,6 +1529,10 @@ void TestBase::stopTimer()
     if (lastTime < 0) lastTime = 0;
     times.push_back(lastTime);
     lastTime = 0;
+
+#ifdef ENABLE_INSTRUMENTATION
+    cv::instr::setFlags(cv::instr::getFlags()&~cv::instr::FLAGS_MAPPING); // disable mapping to decrease overhead for +1 run
+#endif
 }
 
 performance_metrics& TestBase::calcMetrics()
@@ -1469,6 +1705,16 @@ void TestBase::reportMetrics(bool toJUnitXML)
         RecordProperty("gstddev", cv::format("%.6f", m.gstddev).c_str());
         RecordProperty("mean", cv::format("%.0f", m.mean).c_str());
         RecordProperty("stddev", cv::format("%.0f", m.stddev).c_str());
+#ifdef ENABLE_INSTRUMENTATION
+        if(cv::instr::useInstrumentation())
+        {
+            cv::String tree = InstumentData::treeToString();
+            RecordProperty("functions_hierarchy", tree.c_str());
+            RecordProperty("total_ipp_weight",    cv::format("%.1f", ((double)getImplTime(cv::instr::IMPL_IPP)*100/(double)getTotalTime())));
+            RecordProperty("total_opencl_weight", cv::format("%.1f", ((double)getImplTime(cv::instr::IMPL_OPENCL)*100/(double)getTotalTime())));
+            cv::instr::resetTrace();
+        }
+#endif
 #ifdef CV_COLLECT_IMPL_DATA
         if(param_collect_impl)
         {
@@ -1606,6 +1852,11 @@ void TestBase::TearDown()
         if (HasFailure())
         {
             reportMetrics(false);
+
+#ifdef ENABLE_INSTRUMENTATION
+            if(cv::instr::useInstrumentation())
+                InstumentData::printTree();
+#endif
             return;
         }
     }
@@ -1639,6 +1890,12 @@ void TestBase::TearDown()
         fflush(stdout);
     }
 #endif
+
+#ifdef ENABLE_INSTRUMENTATION
+    if(cv::instr::useInstrumentation())
+        InstumentData::printTree();
+#endif
+
     reportMetrics(true);
 }
 
diff --git a/modules/video/include/opencv2/video.hpp b/modules/video/include/opencv2/video.hpp
index a593815..aa644a9 100644
--- a/modules/video/include/opencv2/video.hpp
+++ b/modules/video/include/opencv2/video.hpp
@@ -41,8 +41,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_VIDEO_HPP__
-#define __OPENCV_VIDEO_HPP__
+#ifndef OPENCV_VIDEO_HPP
+#define OPENCV_VIDEO_HPP
 
 /**
   @defgroup video Video Analysis
@@ -60,4 +60,4 @@
 #include "opencv2/video/tracking_c.h"
 #endif
 
-#endif //__OPENCV_VIDEO_HPP__
+#endif //OPENCV_VIDEO_HPP
diff --git a/modules/video/include/opencv2/video/background_segm.hpp b/modules/video/include/opencv2/video/background_segm.hpp
index dbeccbd..2952d57 100644
--- a/modules/video/include/opencv2/video/background_segm.hpp
+++ b/modules/video/include/opencv2/video/background_segm.hpp
@@ -41,8 +41,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_BACKGROUND_SEGM_HPP__
-#define __OPENCV_BACKGROUND_SEGM_HPP__
+#ifndef OPENCV_BACKGROUND_SEGM_HPP
+#define OPENCV_BACKGROUND_SEGM_HPP
 
 #include "opencv2/core.hpp"
 
diff --git a/modules/video/include/opencv2/video/tracking.hpp b/modules/video/include/opencv2/video/tracking.hpp
index d6954fe..c6ead3a 100644
--- a/modules/video/include/opencv2/video/tracking.hpp
+++ b/modules/video/include/opencv2/video/tracking.hpp
@@ -41,8 +41,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_TRACKING_HPP__
-#define __OPENCV_TRACKING_HPP__
+#ifndef OPENCV_TRACKING_HPP
+#define OPENCV_TRACKING_HPP
 
 #include "opencv2/core.hpp"
 #include "opencv2/imgproc.hpp"
@@ -226,7 +226,7 @@ CV_EXPORTS_W void calcOpticalFlowFarneback( InputArray prev, InputArray next, In
 @param dst Second input 2D point set of the same size and the same type as A, or another image.
 @param fullAffine If true, the function finds an optimal affine transformation with no additional
 restrictions (6 degrees of freedom). Otherwise, the class of transformations to choose from is
-limited to combinations of translation, rotation, and uniform scaling (5 degrees of freedom).
+limited to combinations of translation, rotation, and uniform scaling (4 degrees of freedom).
 
 The function finds an optimal affine transform *[A|b]* (a 2 x 3 floating-point matrix) that
 approximates best the affine transformation between:
@@ -245,7 +245,7 @@ where src[i] and dst[i] are the i-th points in src and dst, respectively
 when fullAffine=false.
 
 @sa
-getAffineTransform, getPerspectiveTransform, findHomography
+estimateAffine2D, estimateAffinePartial2D, getAffineTransform, getPerspectiveTransform, findHomography
  */
 CV_EXPORTS_W Mat estimateRigidTransform( InputArray src, InputArray dst, bool fullAffine );
 
@@ -306,7 +306,7 @@ sample image_alignment.cpp that demonstrates the use of the function. Note that
 an exception if algorithm does not converges.
 
 @sa
-estimateRigidTransform, findHomography
+estimateAffine2D, estimateAffinePartial2D, findHomography
  */
 CV_EXPORTS_W double findTransformECC( InputArray templateImage, InputArray inputImage,
                                       InputOutputArray warpMatrix, int motionType = MOTION_AFFINE,
@@ -397,6 +397,27 @@ public:
     CV_WRAP virtual void collectGarbage() = 0;
 };
 
+/** @brief Base interface for sparse optical flow algorithms.
+ */
+class CV_EXPORTS_W SparseOpticalFlow : public Algorithm
+{
+public:
+    /** @brief Calculates a sparse optical flow.
+
+    @param prevImg First input image.
+    @param nextImg Second input image of the same size and the same type as prevImg.
+    @param prevPts Vector of 2D points for which the flow needs to be found.
+    @param nextPts Output vector of 2D points containing the calculated new positions of input features in the second image.
+    @param status Output status vector. Each element of the vector is set to 1 if the
+                  flow for the corresponding features has been found. Otherwise, it is set to 0.
+    @param err Optional output vector that contains error response for each point (inverse confidence).
+     */
+    CV_WRAP virtual void calc(InputArray prevImg, InputArray nextImg,
+                      InputArray prevPts, InputOutputArray nextPts,
+                      OutputArray status,
+                      OutputArray err = cv::noArray()) = 0;
+};
+
 /** @brief "Dual TV L1" Optical Flow Algorithm.
 
 The class implements the "Dual TV L1" optical flow algorithm described in @cite Zach2007 and
@@ -444,70 +465,160 @@ class CV_EXPORTS_W DualTVL1OpticalFlow : public DenseOpticalFlow
 public:
     //! @brief Time step of the numerical scheme
     /** @see setTau */
-    virtual double getTau() const = 0;
+    CV_WRAP virtual double getTau() const = 0;
     /** @copybrief getTau @see getTau */
-    virtual void setTau(double val) = 0;
+    CV_WRAP virtual void setTau(double val) = 0;
     //! @brief Weight parameter for the data term, attachment parameter
     /** @see setLambda */
-    virtual double getLambda() const = 0;
+    CV_WRAP virtual double getLambda() const = 0;
     /** @copybrief getLambda @see getLambda */
-    virtual void setLambda(double val) = 0;
+    CV_WRAP virtual void setLambda(double val) = 0;
     //! @brief Weight parameter for (u - v)^2, tightness parameter
     /** @see setTheta */
-    virtual double getTheta() const = 0;
+    CV_WRAP virtual double getTheta() const = 0;
     /** @copybrief getTheta @see getTheta */
-    virtual void setTheta(double val) = 0;
+    CV_WRAP virtual void setTheta(double val) = 0;
     //! @brief coefficient for additional illumination variation term
     /** @see setGamma */
-    virtual double getGamma() const = 0;
+    CV_WRAP virtual double getGamma() const = 0;
     /** @copybrief getGamma @see getGamma */
-    virtual void setGamma(double val) = 0;
+    CV_WRAP virtual void setGamma(double val) = 0;
     //! @brief Number of scales used to create the pyramid of images
     /** @see setScalesNumber */
-    virtual int getScalesNumber() const = 0;
+    CV_WRAP virtual int getScalesNumber() const = 0;
     /** @copybrief getScalesNumber @see getScalesNumber */
-    virtual void setScalesNumber(int val) = 0;
+    CV_WRAP virtual void setScalesNumber(int val) = 0;
     //! @brief Number of warpings per scale
     /** @see setWarpingsNumber */
-    virtual int getWarpingsNumber() const = 0;
+    CV_WRAP virtual int getWarpingsNumber() const = 0;
     /** @copybrief getWarpingsNumber @see getWarpingsNumber */
-    virtual void setWarpingsNumber(int val) = 0;
+    CV_WRAP virtual void setWarpingsNumber(int val) = 0;
     //! @brief Stopping criterion threshold used in the numerical scheme, which is a trade-off between precision and running time
     /** @see setEpsilon */
-    virtual double getEpsilon() const = 0;
+    CV_WRAP virtual double getEpsilon() const = 0;
     /** @copybrief getEpsilon @see getEpsilon */
-    virtual void setEpsilon(double val) = 0;
+    CV_WRAP virtual void setEpsilon(double val) = 0;
     //! @brief Inner iterations (between outlier filtering) used in the numerical scheme
     /** @see setInnerIterations */
-    virtual int getInnerIterations() const = 0;
+    CV_WRAP virtual int getInnerIterations() const = 0;
     /** @copybrief getInnerIterations @see getInnerIterations */
-    virtual void setInnerIterations(int val) = 0;
+    CV_WRAP virtual void setInnerIterations(int val) = 0;
     //! @brief Outer iterations (number of inner loops) used in the numerical scheme
     /** @see setOuterIterations */
-    virtual int getOuterIterations() const = 0;
+    CV_WRAP virtual int getOuterIterations() const = 0;
     /** @copybrief getOuterIterations @see getOuterIterations */
-    virtual void setOuterIterations(int val) = 0;
+    CV_WRAP virtual void setOuterIterations(int val) = 0;
     //! @brief Use initial flow
     /** @see setUseInitialFlow */
-    virtual bool getUseInitialFlow() const = 0;
+    CV_WRAP virtual bool getUseInitialFlow() const = 0;
     /** @copybrief getUseInitialFlow @see getUseInitialFlow */
-    virtual void setUseInitialFlow(bool val) = 0;
+    CV_WRAP virtual void setUseInitialFlow(bool val) = 0;
     //! @brief Step between scales (<1)
     /** @see setScaleStep */
-    virtual double getScaleStep() const = 0;
+    CV_WRAP virtual double getScaleStep() const = 0;
     /** @copybrief getScaleStep @see getScaleStep */
-    virtual void setScaleStep(double val) = 0;
+    CV_WRAP virtual void setScaleStep(double val) = 0;
     //! @brief Median filter kernel size (1 = no filter) (3 or 5)
     /** @see setMedianFiltering */
-    virtual int getMedianFiltering() const = 0;
+    CV_WRAP virtual int getMedianFiltering() const = 0;
     /** @copybrief getMedianFiltering @see getMedianFiltering */
-    virtual void setMedianFiltering(int val) = 0;
+    CV_WRAP virtual void setMedianFiltering(int val) = 0;
+
+    /** @brief Creates instance of cv::DualTVL1OpticalFlow*/
+    CV_WRAP static Ptr<DualTVL1OpticalFlow> create(
+                                            double tau = 0.25,
+                                            double lambda = 0.15,
+                                            double theta = 0.3,
+                                            int nscales = 5,
+                                            int warps = 5,
+                                            double epsilon = 0.01,
+                                            int innnerIterations = 30,
+                                            int outerIterations = 10,
+                                            double scaleStep = 0.8,
+                                            double gamma = 0.0,
+                                            int medianFiltering = 5,
+                                            bool useInitialFlow = false);
 };
 
 /** @brief Creates instance of cv::DenseOpticalFlow
 */
 CV_EXPORTS_W Ptr<DualTVL1OpticalFlow> createOptFlow_DualTVL1();
 
+/** @brief Class computing a dense optical flow using the Gunnar Farneback’s algorithm.
+ */
+class CV_EXPORTS_W FarnebackOpticalFlow : public DenseOpticalFlow
+{
+public:
+    CV_WRAP virtual int getNumLevels() const = 0;
+    CV_WRAP virtual void setNumLevels(int numLevels) = 0;
+
+    CV_WRAP virtual double getPyrScale() const = 0;
+    CV_WRAP virtual void setPyrScale(double pyrScale) = 0;
+
+    CV_WRAP virtual bool getFastPyramids() const = 0;
+    CV_WRAP virtual void setFastPyramids(bool fastPyramids) = 0;
+
+    CV_WRAP virtual int getWinSize() const = 0;
+    CV_WRAP virtual void setWinSize(int winSize) = 0;
+
+    CV_WRAP virtual int getNumIters() const = 0;
+    CV_WRAP virtual void setNumIters(int numIters) = 0;
+
+    CV_WRAP virtual int getPolyN() const = 0;
+    CV_WRAP virtual void setPolyN(int polyN) = 0;
+
+    CV_WRAP virtual double getPolySigma() const = 0;
+    CV_WRAP virtual void setPolySigma(double polySigma) = 0;
+
+    CV_WRAP virtual int getFlags() const = 0;
+    CV_WRAP virtual void setFlags(int flags) = 0;
+
+    CV_WRAP static Ptr<FarnebackOpticalFlow> create(
+            int numLevels = 5,
+            double pyrScale = 0.5,
+            bool fastPyramids = false,
+            int winSize = 13,
+            int numIters = 10,
+            int polyN = 5,
+            double polySigma = 1.1,
+            int flags = 0);
+};
+
+
+/** @brief Class used for calculating a sparse optical flow.
+
+The class can calculate an optical flow for a sparse feature set using the
+iterative Lucas-Kanade method with pyramids.
+
+ at sa calcOpticalFlowPyrLK
+
+*/
+class CV_EXPORTS_W SparsePyrLKOpticalFlow : public SparseOpticalFlow
+{
+public:
+    CV_WRAP virtual Size getWinSize() const = 0;
+    CV_WRAP virtual void setWinSize(Size winSize) = 0;
+
+    CV_WRAP virtual int getMaxLevel() const = 0;
+    CV_WRAP virtual void setMaxLevel(int maxLevel) = 0;
+
+    CV_WRAP virtual TermCriteria getTermCriteria() const = 0;
+    CV_WRAP virtual void setTermCriteria(TermCriteria& crit) = 0;
+
+    CV_WRAP virtual int getFlags() const = 0;
+    CV_WRAP virtual void setFlags(int flags) = 0;
+
+    CV_WRAP virtual double getMinEigThreshold() const = 0;
+    CV_WRAP virtual void setMinEigThreshold(double minEigThreshold) = 0;
+
+    CV_WRAP static Ptr<SparsePyrLKOpticalFlow> create(
+            Size winSize = Size(21, 21),
+            int maxLevel = 3, TermCriteria crit =
+            TermCriteria(TermCriteria::COUNT+TermCriteria::EPS, 30, 0.01),
+            int flags = 0,
+            double minEigThreshold = 1e-4);
+};
+
 //! @} video_track
 
 } // cv
diff --git a/modules/video/include/opencv2/video/tracking_c.h b/modules/video/include/opencv2/video/tracking_c.h
index b355352..3e32fbd 100644
--- a/modules/video/include/opencv2/video/tracking_c.h
+++ b/modules/video/include/opencv2/video/tracking_c.h
@@ -41,8 +41,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_TRACKING_C_H__
-#define __OPENCV_TRACKING_C_H__
+#ifndef OPENCV_TRACKING_C_H
+#define OPENCV_TRACKING_C_H
 
 #include "opencv2/imgproc/types_c.h"
 
@@ -229,4 +229,4 @@ CVAPI(const CvMat*)  cvKalmanCorrect( CvKalman* kalman, const CvMat* measurement
 #endif
 
 
-#endif // __OPENCV_TRACKING_C_H__
+#endif // OPENCV_TRACKING_C_H
diff --git a/modules/video/perf/opencl/perf_optflow_pyrlk.cpp b/modules/video/perf/opencl/perf_optflow_pyrlk.cpp
index 6041a4b..81c8ed9 100644
--- a/modules/video/perf/opencl/perf_optflow_pyrlk.cpp
+++ b/modules/video/perf/opencl/perf_optflow_pyrlk.cpp
@@ -54,9 +54,6 @@ using std::tr1::make_tuple;
 namespace cvtest {
 namespace ocl {
 
-///////////// FarnebackOpticalFlow ////////////////////////
-CV_ENUM(farneFlagType, 0, OPTFLOW_FARNEBACK_GAUSSIAN)
-
 typedef tuple< int > PyrLKOpticalFlowParams;
 typedef TestBaseWithParam<PyrLKOpticalFlowParams> PyrLKOpticalFlowFixture;
 
diff --git a/modules/video/perf/perf_tvl1optflow.cpp b/modules/video/perf/perf_tvl1optflow.cpp
index 0a0f74a..4895ff4 100644
--- a/modules/video/perf/perf_tvl1optflow.cpp
+++ b/modules/video/perf/perf_tvl1optflow.cpp
@@ -24,7 +24,7 @@ PERF_TEST_P(ImagePair, OpticalFlowDual_TVL1, testing::Values(impair("cv/optflow/
 
     Ptr<DenseOpticalFlow> tvl1 = createOptFlow_DualTVL1();
 
-    TEST_CYCLE_N(10) tvl1->calc(frame1, frame2, flow);
+    TEST_CYCLE() tvl1->calc(frame1, frame2, flow);
 
-    SANITY_CHECK(flow, 0.8);
+    SANITY_CHECK_NOTHING();
 }
diff --git a/modules/video/src/bgfg_KNN.cpp b/modules/video/src/bgfg_KNN.cpp
index 334810b..66be34a 100755
--- a/modules/video/src/bgfg_KNN.cpp
+++ b/modules/video/src/bgfg_KNN.cpp
@@ -183,6 +183,7 @@ public:
 
     virtual void write(FileStorage& fs) const
     {
+        writeFormat(fs);
         fs << "name" << name_
         << "history" << history
         << "nsamples" << nN
@@ -318,7 +319,7 @@ CV_INLINE void
     {
         m_nNextShortUpdate[pixel] = (uchar)( rand() % m_nShortUpdate );
     };
-};
+}
 
 CV_INLINE int
         _cvCheckPixelBackgroundNP(long pixel,
@@ -435,7 +436,7 @@ CV_INLINE int
         };
     }
     return 0;
-};
+}
 
 CV_INLINE void
         icvUpdatePixelBackgroundNP(const Mat& _src, Mat& _dst,
@@ -553,12 +554,14 @@ CV_INLINE void
             i++;
         }
     }
-};
+}
 
 
 
 void BackgroundSubtractorKNNImpl::apply(InputArray _image, OutputArray _fgmask, double learningRate)
 {
+    CV_INSTRUMENT_REGION()
+
     Mat image = _image.getMat();
     bool needToInitialize = nframes == 0 || learningRate >= 1 || image.size() != frameSize || image.type() != frameType;
 
@@ -597,6 +600,8 @@ void BackgroundSubtractorKNNImpl::apply(InputArray _image, OutputArray _fgmask,
 
 void BackgroundSubtractorKNNImpl::getBackgroundImage(OutputArray backgroundImage) const
 {
+    CV_INSTRUMENT_REGION()
+
     int nchannels = CV_MAT_CN(frameType);
     //CV_Assert( nchannels == 3 );
     Mat meanBackground(frameSize, CV_8UC3, Scalar::all(0));
diff --git a/modules/video/src/bgfg_gaussmix2.cpp b/modules/video/src/bgfg_gaussmix2.cpp
index b713e8c..ebe4498 100644
--- a/modules/video/src/bgfg_gaussmix2.cpp
+++ b/modules/video/src/bgfg_gaussmix2.cpp
@@ -196,7 +196,9 @@ public:
         if (ocl::useOpenCL() && opencl_ON)
         {
             create_ocl_apply_kernel();
-            kernel_getBg.create("getBackgroundImage2_kernel", ocl::video::bgfg_mog2_oclsrc, format( "-D CN=%d -D NMIXTURES=%d", nchannels, nmixtures));
+
+            bool isFloat = CV_MAKETYPE(CV_32F,nchannels) == frameType;
+            kernel_getBg.create("getBackgroundImage2_kernel", ocl::video::bgfg_mog2_oclsrc, format( "-D CN=%d -D FL=%d -D NMIXTURES=%d", nchannels, isFloat, nmixtures));
 
             if (kernel_apply.empty() || kernel_getBg.empty())
                 opencl_ON = false;
@@ -284,6 +286,7 @@ public:
 
     virtual void write(FileStorage& fs) const
     {
+        writeFormat(fs);
         fs << "name" << name_
         << "history" << history
         << "nmixtures" << nmixtures
@@ -387,6 +390,9 @@ protected:
 
     String name_;
 
+    template <typename T, int CN>
+    void getBackgroundImage_intern(OutputArray backgroundImage) const;
+
 #ifdef HAVE_OPENCL
     bool ocl_getBackgroundImage(OutputArray backgroundImage) const;
     bool ocl_apply(InputArray _image, OutputArray _fgmask, double learningRate=-1);
@@ -588,7 +594,7 @@ public:
 
                 //internal:
                 bool fitsPDF = false;//if it remains zero a new GMM mode will be added
-                int nmodes = modesUsed[x], nNewModes = nmodes;//current number of modes in GMM
+                int nmodes = modesUsed[x];//current number of modes in GMM
                 float totalWeight = 0.f;
 
                 float* mean_m = mean;
@@ -694,8 +700,6 @@ public:
                     gmm[mode].weight *= totalWeight;
                 }
 
-                nmodes = nNewModes;
-
                 //make new mode if needed and exit
                 if( !fitsPDF && alphaT > 0.f )
                 {
@@ -803,8 +807,6 @@ bool BackgroundSubtractorMOG2Impl::ocl_apply(InputArray _image, OutputArray _fgm
 
 bool BackgroundSubtractorMOG2Impl::ocl_getBackgroundImage(OutputArray _backgroundImage) const
 {
-    CV_Assert(frameType == CV_8UC1 || frameType == CV_8UC3);
-
     _backgroundImage.create(frameSize, frameType);
     UMat dst = _backgroundImage.getUMat();
 
@@ -823,7 +825,8 @@ bool BackgroundSubtractorMOG2Impl::ocl_getBackgroundImage(OutputArray _backgroun
 void BackgroundSubtractorMOG2Impl::create_ocl_apply_kernel()
 {
     int nchannels = CV_MAT_CN(frameType);
-    String opts = format("-D CN=%d -D NMIXTURES=%d%s", nchannels, nmixtures, bShadowDetection ? " -D SHADOW_DETECT" : "");
+    bool isFloat = CV_MAKETYPE(CV_32F,nchannels) == frameType;
+    String opts = format("-D CN=%d -D FL=%d -D NMIXTURES=%d%s", nchannels, isFloat, nmixtures, bShadowDetection ? " -D SHADOW_DETECT" : "");
     kernel_apply.create("mog2_kernel", ocl::video::bgfg_mog2_oclsrc, opts);
 }
 
@@ -831,6 +834,8 @@ void BackgroundSubtractorMOG2Impl::create_ocl_apply_kernel()
 
 void BackgroundSubtractorMOG2Impl::apply(InputArray _image, OutputArray _fgmask, double learningRate)
 {
+    CV_INSTRUMENT_REGION()
+
     bool needToInitialize = nframes == 0 || learningRate >= 1 || _image.size() != frameSize || _image.type() != frameType;
 
     if( needToInitialize )
@@ -839,7 +844,7 @@ void BackgroundSubtractorMOG2Impl::apply(InputArray _image, OutputArray _fgmask,
 #ifdef HAVE_OPENCL
     if (opencl_ON)
     {
-        CV_OCL_RUN(opencl_ON, ocl_apply(_image, _fgmask, learningRate))
+        CV_OCL_RUN(_image.isUMat(), ocl_apply(_image, _fgmask, learningRate))
 
         opencl_ON = false;
         initialize(_image.size(), _image.type());
@@ -866,25 +871,16 @@ void BackgroundSubtractorMOG2Impl::apply(InputArray _image, OutputArray _fgmask,
                               image.total()/(double)(1 << 16));
 }
 
-void BackgroundSubtractorMOG2Impl::getBackgroundImage(OutputArray backgroundImage) const
+template <typename T, int CN>
+void BackgroundSubtractorMOG2Impl::getBackgroundImage_intern(OutputArray backgroundImage) const
 {
-#ifdef HAVE_OPENCL
-    if (opencl_ON)
-    {
-        CV_OCL_RUN(opencl_ON, ocl_getBackgroundImage(backgroundImage))
-
-        opencl_ON = false;
-        return;
-    }
-#endif
+    CV_INSTRUMENT_REGION()
 
-    int nchannels = CV_MAT_CN(frameType);
-    CV_Assert(nchannels == 1 || nchannels == 3);
-    Mat meanBackground(frameSize, CV_MAKETYPE(CV_8U, nchannels), Scalar::all(0));
+    Mat meanBackground(frameSize, frameType, Scalar::all(0));
     int firstGaussianIdx = 0;
     const GMM* gmm = bgmodel.ptr<GMM>();
     const float* mean = reinterpret_cast<const float*>(gmm + frameSize.width*frameSize.height*nmixtures);
-    std::vector<float> meanVal(nchannels, 0.f);
+    Vec<float,CN> meanVal(0.f);
     for(int row=0; row<meanBackground.rows; row++)
     {
         for(int col=0; col<meanBackground.cols; col++)
@@ -894,10 +890,10 @@ void BackgroundSubtractorMOG2Impl::getBackgroundImage(OutputArray backgroundImag
             for(int gaussianIdx = firstGaussianIdx; gaussianIdx < firstGaussianIdx + nmodes; gaussianIdx++)
             {
                 GMM gaussian = gmm[gaussianIdx];
-                size_t meanPosition = gaussianIdx*nchannels;
-                for(int chn = 0; chn < nchannels; chn++)
+                size_t meanPosition = gaussianIdx*CN;
+                for(int chn = 0; chn < CN; chn++)
                 {
-                    meanVal[chn] += gaussian.weight * mean[meanPosition + chn];
+                    meanVal(chn) += gaussian.weight * mean[meanPosition + chn];
                 }
                 totalWeight += gaussian.weight;
 
@@ -905,24 +901,46 @@ void BackgroundSubtractorMOG2Impl::getBackgroundImage(OutputArray backgroundImag
                     break;
             }
             float invWeight = 1.f/totalWeight;
-            switch(nchannels)
-            {
-            case 1:
-                meanBackground.at<uchar>(row, col) = (uchar)(meanVal[0] * invWeight);
-                meanVal[0] = 0.f;
-                break;
-            case 3:
-                Vec3f& meanVec = *reinterpret_cast<Vec3f*>(&meanVal[0]);
-                meanBackground.at<Vec3b>(row, col) = Vec3b(meanVec * invWeight);
-                meanVec = 0.f;
-                break;
-            }
+
+            meanBackground.at<Vec<T,CN> >(row, col) = Vec<T,CN>(meanVal * invWeight);
+            meanVal = 0.f;
+
             firstGaussianIdx += nmixtures;
         }
     }
     meanBackground.copyTo(backgroundImage);
 }
 
+void BackgroundSubtractorMOG2Impl::getBackgroundImage(OutputArray backgroundImage) const
+{
+    CV_Assert(frameType == CV_8UC1 || frameType == CV_8UC3 || frameType == CV_32FC1 || frameType == CV_32FC3);
+
+#ifdef HAVE_OPENCL
+    if (opencl_ON)
+    {
+        CV_OCL_RUN(opencl_ON, ocl_getBackgroundImage(backgroundImage))
+
+        opencl_ON = false;
+    }
+#endif
+
+    switch(frameType)
+    {
+    case CV_8UC1:
+        getBackgroundImage_intern<uchar,1>(backgroundImage);
+        break;
+    case CV_8UC3:
+        getBackgroundImage_intern<uchar,3>(backgroundImage);
+        break;
+    case CV_32FC1:
+        getBackgroundImage_intern<float,1>(backgroundImage);
+        break;
+    case CV_32FC3:
+        getBackgroundImage_intern<float,3>(backgroundImage);
+        break;
+    }
+}
+
 Ptr<BackgroundSubtractorMOG2> createBackgroundSubtractorMOG2(int _history, double _varThreshold,
                                                              bool _bShadowDetection)
 {
diff --git a/modules/video/src/camshift.cpp b/modules/video/src/camshift.cpp
index 5449a1b..4a7017c 100644
--- a/modules/video/src/camshift.cpp
+++ b/modules/video/src/camshift.cpp
@@ -43,6 +43,8 @@
 
 int cv::meanShift( InputArray _probImage, Rect& window, TermCriteria criteria )
 {
+    CV_INSTRUMENT_REGION()
+
     Size size;
     int cn;
     Mat mat;
@@ -108,6 +110,8 @@ int cv::meanShift( InputArray _probImage, Rect& window, TermCriteria criteria )
 cv::RotatedRect cv::CamShift( InputArray _probImage, Rect& window,
                               TermCriteria criteria )
 {
+    CV_INSTRUMENT_REGION()
+
     const int TOLERANCE = 10;
     Size size;
     Mat mat;
diff --git a/modules/video/src/kalman.cpp b/modules/video/src/kalman.cpp
index 3b86771..d0fba8f 100644
--- a/modules/video/src/kalman.cpp
+++ b/modules/video/src/kalman.cpp
@@ -81,6 +81,8 @@ void KalmanFilter::init(int DP, int MP, int CP, int type)
 
 const Mat& KalmanFilter::predict(const Mat& control)
 {
+    CV_INSTRUMENT_REGION()
+
     // update the state: x'(k) = A*x(k)
     statePre = transitionMatrix*statePost;
 
@@ -103,6 +105,8 @@ const Mat& KalmanFilter::predict(const Mat& control)
 
 const Mat& KalmanFilter::correct(const Mat& measurement)
 {
+    CV_INSTRUMENT_REGION()
+
     // temp2 = H*P'(k)
     temp2 = measurementMatrix * errorCovPre;
 
diff --git a/modules/video/src/lkpyramid.cpp b/modules/video/src/lkpyramid.cpp
index 891ae78..7c89bc3 100644
--- a/modules/video/src/lkpyramid.cpp
+++ b/modules/video/src/lkpyramid.cpp
@@ -44,6 +44,9 @@
 #include <stdio.h>
 #include "lkpyramid.hpp"
 #include "opencl_kernels_video.hpp"
+#include "opencv2/core/hal/intrin.hpp"
+
+#include "opencv2/core/openvx/ovx_defs.hpp"
 
 #define  CV_DESCALE(x,n)     (((x) + (1 << ((n)-1))) >> (n))
 
@@ -66,16 +69,9 @@ static void calcSharrDeriv(const cv::Mat& src, cv::Mat& dst)
     AutoBuffer<deriv_type> _tempBuf(delta*2 + 64);
     deriv_type *trow0 = alignPtr(_tempBuf + cn, 16), *trow1 = alignPtr(trow0 + delta, 16);
 
-#if CV_SSE2
-    __m128i z = _mm_setzero_si128(), c3 = _mm_set1_epi16(3), c10 = _mm_set1_epi16(10);
-#endif
-
-#if CV_NEON
-    const uint16x8_t q8 = vdupq_n_u16(3);
-    const uint8x8_t d18 = vdup_n_u8(10);
-
-    const int16x8_t q8i = vdupq_n_s16(3);
-    const int16x8_t q9 = vdupq_n_s16(10);
+#if CV_SIMD128
+    v_int16x8 c3 = v_setall_s16(3), c10 = v_setall_s16(10);
+    bool haveSIMD = checkHardwareSupport(CV_CPU_SSE2) || checkHardwareSupport(CV_CPU_NEON);
 #endif
 
     for( y = 0; y < rows; y++ )
@@ -87,33 +83,21 @@ static void calcSharrDeriv(const cv::Mat& src, cv::Mat& dst)
 
         // do vertical convolution
         x = 0;
-#if CV_SSE2
-        for( ; x <= colsn - 8; x += 8 )
+#if CV_SIMD128
+        if(haveSIMD)
         {
-            __m128i s0 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i*)(srow0 + x)), z);
-            __m128i s1 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i*)(srow1 + x)), z);
-            __m128i s2 = _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i*)(srow2 + x)), z);
-            __m128i t0 = _mm_add_epi16(_mm_mullo_epi16(_mm_add_epi16(s0, s2), c3), _mm_mullo_epi16(s1, c10));
-            __m128i t1 = _mm_sub_epi16(s2, s0);
-            _mm_store_si128((__m128i*)(trow0 + x), t0);
-            _mm_store_si128((__m128i*)(trow1 + x), t1);
-        }
-#endif
+            for( ; x <= colsn - 8; x += 8 )
+            {
+                v_int16x8 s0 = v_reinterpret_as_s16(v_load_expand(srow0 + x));
+                v_int16x8 s1 = v_reinterpret_as_s16(v_load_expand(srow1 + x));
+                v_int16x8 s2 = v_reinterpret_as_s16(v_load_expand(srow2 + x));
 
-#if CV_NEON
-        for( ; x <= colsn - 8; x += 8)
-        {
-            uint8x8_t d0 = vld1_u8((const uint8_t*)&srow0[x]);
-            uint8x8_t d1 = vld1_u8((const uint8_t*)&srow1[x]);
-            uint8x8_t d2 = vld1_u8((const uint8_t*)&srow2[x]);
-            uint16x8_t q4 = vaddl_u8(d0, d2);
-            uint16x8_t q11 = vsubl_u8(d2, d0);
-            uint16x8_t q5 = vmulq_u16(q4, q8);
-            uint16x8_t q6 = vmull_u8(d1, d18);
-            uint16x8_t q10 = vaddq_u16(q6, q5);
-            vst1q_u16((uint16_t*)&trow0[x], q10);
-            vst1q_u16((uint16_t*)&trow1[x], q11);
+                v_int16x8 t1 = s2 - s0;
+                v_int16x8 t0 = (s0 + s2) * c3 + s1 * c10;
 
+                v_store(trow0 + x, t0);
+                v_store(trow1 + x, t1);
+            }
         }
 #endif
 
@@ -135,49 +119,22 @@ static void calcSharrDeriv(const cv::Mat& src, cv::Mat& dst)
 
         // do horizontal convolution, interleave the results and store them to dst
         x = 0;
-#if CV_SSE2
-        for( ; x <= colsn - 8; x += 8 )
-        {
-            __m128i s0 = _mm_loadu_si128((const __m128i*)(trow0 + x - cn));
-            __m128i s1 = _mm_loadu_si128((const __m128i*)(trow0 + x + cn));
-            __m128i s2 = _mm_loadu_si128((const __m128i*)(trow1 + x - cn));
-            __m128i s3 = _mm_load_si128((const __m128i*)(trow1 + x));
-            __m128i s4 = _mm_loadu_si128((const __m128i*)(trow1 + x + cn));
-
-            __m128i t0 = _mm_sub_epi16(s1, s0);
-            __m128i t1 = _mm_add_epi16(_mm_mullo_epi16(_mm_add_epi16(s2, s4), c3), _mm_mullo_epi16(s3, c10));
-            __m128i t2 = _mm_unpacklo_epi16(t0, t1);
-            t0 = _mm_unpackhi_epi16(t0, t1);
-            // this can probably be replaced with aligned stores if we aligned dst properly.
-            _mm_storeu_si128((__m128i*)(drow + x*2), t2);
-            _mm_storeu_si128((__m128i*)(drow + x*2 + 8), t0);
-        }
-#endif
-
-#if CV_NEON
-        for( ; x <= colsn - 8; x += 8 )
+#if CV_SIMD128
+        if(haveSIMD)
         {
+            for( ; x <= colsn - 8; x += 8 )
+            {
+                v_int16x8 s0 = v_load(trow0 + x - cn);
+                v_int16x8 s1 = v_load(trow0 + x + cn);
+                v_int16x8 s2 = v_load(trow1 + x - cn);
+                v_int16x8 s3 = v_load(trow1 + x);
+                v_int16x8 s4 = v_load(trow1 + x + cn);
 
-            int16x8_t q0 = vld1q_s16((const int16_t*)&trow0[x+cn]);
-            int16x8_t q1 = vld1q_s16((const int16_t*)&trow0[x-cn]);
-            int16x8_t q2 = vld1q_s16((const int16_t*)&trow1[x+cn]);
-            int16x8_t q3 = vld1q_s16((const int16_t*)&trow1[x-cn]);
-            int16x8_t q5 = vsubq_s16(q0, q1);
-            int16x8_t q6 = vaddq_s16(q2, q3);
-            int16x8_t q4 = vld1q_s16((const int16_t*)&trow1[x]);
-            int16x8_t q7 = vmulq_s16(q6, q8i);
-            int16x8_t q10 = vmulq_s16(q4, q9);
-            int16x8_t q11 = vaddq_s16(q7, q10);
-            int16x4_t d22 = vget_low_s16(q11);
-            int16x4_t d23 = vget_high_s16(q11);
-            int16x4_t d11 = vget_high_s16(q5);
-            int16x4_t d10 = vget_low_s16(q5);
-            int16x4x2_t q5x2, q11x2;
-            q5x2.val[0] = d10; q5x2.val[1] = d22;
-            q11x2.val[0] = d11; q11x2.val[1] = d23;
-            vst2_s16((int16_t*)&drow[x*2], q5x2);
-            vst2_s16((int16_t*)&drow[(x*2)+8], q11x2);
+                v_int16x8 t0 = s1 - s0;
+                v_int16x8 t1 = ((s2 + s4) * c3) + (s3 * c10);
 
+                v_store_interleave((drow + x*2), t0, t1);
+            }
         }
 #endif
         for( ; x < colsn; x++ )
@@ -223,6 +180,8 @@ typedef float itemtype;
 
 void cv::detail::LKTrackerInvoker::operator()(const Range& range) const
 {
+    CV_INSTRUMENT_REGION()
+
     Point2f halfWin((winSize.width-1)*0.5f, (winSize.height-1)*0.5f);
     const Mat& I = *prevImg;
     const Mat& J = *nextImg;
@@ -294,7 +253,7 @@ void cv::detail::LKTrackerInvoker::operator()(const Range& range) const
 
 #if CV_NEON
 
-        int CV_DECL_ALIGNED(16) nA11[] = {0, 0, 0, 0}, nA12[] = {0, 0, 0, 0}, nA22[] = {0, 0, 0, 0};
+        float CV_DECL_ALIGNED(16) nA11[] = { 0, 0, 0, 0 }, nA12[] = { 0, 0, 0, 0 }, nA22[] = { 0, 0, 0, 0 };
         const int shifter1 = -(W_BITS - 5); //negative so it shifts right
         const int shifter2 = -(W_BITS);
 
@@ -406,19 +365,19 @@ void cv::detail::LKTrackerInvoker::operator()(const Range& range) const
                 q6 = vaddq_s32(q6, q8);
 
                 q7 = vmull_s16(d4d5.val[0], d28);
-                int32x4_t nq0 = vmull_s16(d4d5.val[1], d28);
+                int32x4_t q14 = vmull_s16(d4d5.val[1], d28);
                 q8 = vmull_s16(d6d7.val[0], d29);
                 int32x4_t q15 = vmull_s16(d6d7.val[1], d29);
 
                 q7 = vaddq_s32(q7, q8);
-                nq0 = vaddq_s32(nq0, q15);
+                q14 = vaddq_s32(q14, q15);
 
                 q4 = vaddq_s32(q4, q7);
-                q6 = vaddq_s32(q6, nq0);
+                q6 = vaddq_s32(q6, q14);
 
-                int32x4_t nq1 = vld1q_s32(nA12);
-                int32x4_t nq2 = vld1q_s32(nA22);
-                nq0 = vld1q_s32(nA11);
+                float32x4_t nq0 = vld1q_f32(nA11);
+                float32x4_t nq1 = vld1q_f32(nA12);
+                float32x4_t nq2 = vld1q_f32(nA22);
 
                 q4 = vqrshlq_s32(q4, q12);
                 q6 = vqrshlq_s32(q6, q12);
@@ -427,13 +386,13 @@ void cv::detail::LKTrackerInvoker::operator()(const Range& range) const
                 q8 = vmulq_s32(q4, q6);
                 q15 = vmulq_s32(q6, q6);
 
-                nq0 = vaddq_s32(nq0, q7);
-                nq1 = vaddq_s32(nq1, q8);
-                nq2 = vaddq_s32(nq2, q15);
+                nq0 = vaddq_f32(nq0, vcvtq_f32_s32(q7));
+                nq1 = vaddq_f32(nq1, vcvtq_f32_s32(q8));
+                nq2 = vaddq_f32(nq2, vcvtq_f32_s32(q15));
 
-                vst1q_s32(nA11, nq0);
-                vst1q_s32(nA12, nq1);
-                vst1q_s32(nA22, nq2);
+                vst1q_f32(nA11, nq0);
+                vst1q_f32(nA12, nq1);
+                vst1q_f32(nA22, nq2);
 
                 int16x4_t d8 = vmovn_s32(q4);
                 int16x4_t d12 = vmovn_s32(q6);
@@ -474,9 +433,9 @@ void cv::detail::LKTrackerInvoker::operator()(const Range& range) const
 #endif
 
 #if CV_NEON
-        iA11 += (float)(nA11[0] + nA11[1] + nA11[2] + nA11[3]);
-        iA12 += (float)(nA12[0] + nA12[1] + nA12[2] + nA12[3]);
-        iA22 += (float)(nA22[0] + nA22[1] + nA22[2] + nA22[3]);
+        iA11 += nA11[0] + nA11[1] + nA11[2] + nA11[3];
+        iA12 += nA12[0] + nA12[1] + nA12[2] + nA12[3];
+        iA22 += nA22[0] + nA22[1] + nA22[2] + nA22[3];
 #endif
 
         A11 = iA11*FLT_SCALE;
@@ -530,7 +489,7 @@ void cv::detail::LKTrackerInvoker::operator()(const Range& range) const
 #endif
 
 #if CV_NEON
-            int CV_DECL_ALIGNED(16) nB1[] = {0,0,0,0}, nB2[] = {0,0,0,0};
+            float CV_DECL_ALIGNED(16) nB1[] = { 0,0,0,0 }, nB2[] = { 0,0,0,0 };
 
             const int16x4_t d26_2 = vdup_n_s16((int16_t)iw00);
             const int16x4_t d27_2 = vdup_n_s16((int16_t)iw01);
@@ -567,18 +526,14 @@ void cv::detail::LKTrackerInvoker::operator()(const Range& range) const
                     diff0 = _mm_unpacklo_epi16(diff0, diff0); // It0 It0 It1 It1 ...
                     v00 = _mm_loadu_si128((const __m128i*)(dIptr)); // Ix0 Iy0 Ix1 Iy1 ...
                     v01 = _mm_loadu_si128((const __m128i*)(dIptr + 8));
-                    v10 = _mm_mullo_epi16(v00, diff0);
-                    v11 = _mm_mulhi_epi16(v00, diff0);
-                    v00 = _mm_unpacklo_epi16(v10, v11);
-                    v10 = _mm_unpackhi_epi16(v10, v11);
-                    qb0 = _mm_add_ps(qb0, _mm_cvtepi32_ps(v00));
-                    qb1 = _mm_add_ps(qb1, _mm_cvtepi32_ps(v10));
-                    v10 = _mm_mullo_epi16(v01, diff1);
-                    v11 = _mm_mulhi_epi16(v01, diff1);
-                    v00 = _mm_unpacklo_epi16(v10, v11);
-                    v10 = _mm_unpackhi_epi16(v10, v11);
+                    v10 = _mm_unpacklo_epi16(v00, v01);
+                    v11 = _mm_unpackhi_epi16(v00, v01);
+                    v00 = _mm_unpacklo_epi16(diff0, diff1);
+                    v01 = _mm_unpackhi_epi16(diff0, diff1);
+                    v00 = _mm_madd_epi16(v00, v10);
+                    v11 = _mm_madd_epi16(v01, v11);
                     qb0 = _mm_add_ps(qb0, _mm_cvtepi32_ps(v00));
-                    qb1 = _mm_add_ps(qb1, _mm_cvtepi32_ps(v10));
+                    qb1 = _mm_add_ps(qb1, _mm_cvtepi32_ps(v11));
                 }
 #endif
 
@@ -625,8 +580,8 @@ void cv::detail::LKTrackerInvoker::operator()(const Range& range) const
                     nq5 = vqrshlq_s32(nq5, q11);
 
                     int16x8x2_t q0q1 = vld2q_s16(dIptr);
-                    nq11 = vld1q_s32(nB1);
-                    int32x4_t nq15 = vld1q_s32(nB2);
+                    float32x4_t nB1v = vld1q_f32(nB1);
+                    float32x4_t nB2v = vld1q_f32(nB2);
 
                     nq4 = vsubq_s32(nq4, nq6);
                     nq5 = vsubq_s32(nq5, nq8);
@@ -646,11 +601,11 @@ void cv::detail::LKTrackerInvoker::operator()(const Range& range) const
                     nq9 = vaddq_s32(nq9, nq10);
                     nq4 = vaddq_s32(nq4, nq5);
 
-                    nq11 = vaddq_s32(nq11, nq9);
-                    nq15 = vaddq_s32(nq15, nq4);
+                    nB1v = vaddq_f32(nB1v, vcvtq_f32_s32(nq9));
+                    nB2v = vaddq_f32(nB2v, vcvtq_f32_s32(nq4));
 
-                    vst1q_s32(nB1, nq11);
-                    vst1q_s32(nB2, nq15);
+                    vst1q_f32(nB1, nB1v);
+                    vst1q_f32(nB2, nB2v);
                 }
 #endif
 
@@ -744,6 +699,8 @@ void cv::detail::LKTrackerInvoker::operator()(const Range& range) const
 int cv::buildOpticalFlowPyramid(InputArray _img, OutputArrayOfArrays pyramid, Size winSize, int maxLevel, bool withDerivatives,
                                 int pyrBorder, int derivBorder, bool tryReuseInputImage)
 {
+    CV_INSTRUMENT_REGION()
+
     Mat img = _img.getMat();
     CV_Assert(img.depth() == CV_8U && winSize.width > 2 && winSize.height > 2 );
     int pyrstep = withDerivatives ? 2 : 1;
@@ -837,10 +794,11 @@ int cv::buildOpticalFlowPyramid(InputArray _img, OutputArrayOfArrays pyramid, Si
     return maxLevel;
 }
 
-#ifdef HAVE_OPENCL
 namespace cv
 {
-    class PyrLKOpticalFlow
+namespace
+{
+    class SparsePyrLKOpticalFlowImpl : public SparsePyrLKOpticalFlow
     {
         struct dim3
         {
@@ -848,17 +806,40 @@ namespace cv
             dim3() : x(0), y(0), z(0) { }
         };
     public:
-        PyrLKOpticalFlow()
+        SparsePyrLKOpticalFlowImpl(Size winSize_ = Size(21,21),
+                         int maxLevel_ = 3,
+                         TermCriteria criteria_ = TermCriteria(TermCriteria::COUNT+TermCriteria::EPS, 30, 0.01),
+                         int flags_ = 0,
+                         double minEigThreshold_ = 1e-4) :
+          winSize(winSize_), maxLevel(maxLevel_), criteria(criteria_), flags(flags_), minEigThreshold(minEigThreshold_)
+#ifdef HAVE_OPENCL
+          , iters(criteria_.maxCount), derivLambda(criteria_.epsilon), useInitialFlow(0 != (flags_ & OPTFLOW_LK_GET_MIN_EIGENVALS)), waveSize(0)
+#endif
         {
-            winSize = Size(21, 21);
-            maxLevel = 3;
-            iters = 30;
-            derivLambda = 0.5;
-            useInitialFlow = false;
-
-            waveSize = 0;
         }
 
+        virtual Size getWinSize() const {return winSize;}
+        virtual void setWinSize(Size winSize_){winSize = winSize_;}
+
+        virtual int getMaxLevel() const {return maxLevel;}
+        virtual void setMaxLevel(int maxLevel_){maxLevel = maxLevel_;}
+
+        virtual TermCriteria getTermCriteria() const {return criteria;}
+        virtual void setTermCriteria(TermCriteria& crit_){criteria=crit_;}
+
+        virtual int getFlags() const {return flags; }
+        virtual void setFlags(int flags_){flags=flags_;}
+
+        virtual double getMinEigThreshold() const {return minEigThreshold;}
+        virtual void setMinEigThreshold(double minEigThreshold_){minEigThreshold=minEigThreshold_;}
+
+        virtual void calc(InputArray prevImg, InputArray nextImg,
+                          InputArray prevPts, InputOutputArray nextPts,
+                          OutputArray status,
+                          OutputArray err = cv::noArray());
+
+    private:
+#ifdef HAVE_OPENCL
         bool checkParam()
         {
             iters = std::min(std::max(iters, 0), 100);
@@ -930,14 +911,17 @@ namespace cv
             }
             return true;
         }
+#endif
 
         Size winSize;
         int maxLevel;
+        TermCriteria criteria;
+        int flags;
+        double minEigThreshold;
+#ifdef HAVE_OPENCL
         int iters;
         double derivLambda;
         bool useInitialFlow;
-
-    private:
         int waveSize;
         bool initWaveSize()
         {
@@ -1017,15 +1001,11 @@ namespace cv
         {
             return (cv::ocl::Device::TYPE_CPU == cv::ocl::Device::getDefault().type());
         }
-    };
 
 
-    static bool ocl_calcOpticalFlowPyrLK(InputArray _prevImg, InputArray _nextImg,
-                                  InputArray _prevPts, InputOutputArray _nextPts,
-                                  OutputArray _status, OutputArray _err,
-                                  Size winSize, int maxLevel,
-                                  TermCriteria criteria,
-                                  int flags/*, double minEigThreshold*/ )
+    bool ocl_calcOpticalFlowPyrLK(InputArray _prevImg, InputArray _nextImg,
+                                         InputArray _prevPts, InputOutputArray _nextPts,
+                                         OutputArray _status, OutputArray _err)
     {
         if (0 != (OPTFLOW_LK_GET_MIN_EIGENVALS & flags))
             return false;
@@ -1045,7 +1025,6 @@ namespace cv
         if ((1 != _prevPts.size().height) && (1 != _prevPts.size().width))
             return false;
         size_t npoints = _prevPts.total();
-        bool useInitialFlow  = (0 != (flags & OPTFLOW_USE_INITIAL_FLOW));
         if (useInitialFlow)
         {
             if (_nextPts.empty() || _nextPts.type() != CV_32FC2 || (!_prevPts.isContinuous()))
@@ -1060,14 +1039,7 @@ namespace cv
             _nextPts.create(_prevPts.size(), _prevPts.type());
         }
 
-        PyrLKOpticalFlow opticalFlow;
-        opticalFlow.winSize     = winSize;
-        opticalFlow.maxLevel    = maxLevel;
-        opticalFlow.iters       = criteria.maxCount;
-        opticalFlow.derivLambda = criteria.epsilon;
-        opticalFlow.useInitialFlow  = useInitialFlow;
-
-        if (!opticalFlow.checkParam())
+        if (!checkParam())
             return false;
 
         UMat umatErr;
@@ -1082,28 +1054,173 @@ namespace cv
         _status.create((int)npoints, 1, CV_8UC1);
         UMat umatNextPts = _nextPts.getUMat();
         UMat umatStatus = _status.getUMat();
-        return opticalFlow.sparse(_prevImg.getUMat(), _nextImg.getUMat(), _prevPts.getUMat(), umatNextPts, umatStatus, umatErr);
+        return sparse(_prevImg.getUMat(), _nextImg.getUMat(), _prevPts.getUMat(), umatNextPts, umatStatus, umatErr);
     }
-};
 #endif
 
-void cv::calcOpticalFlowPyrLK( InputArray _prevImg, InputArray _nextImg,
-                           InputArray _prevPts, InputOutputArray _nextPts,
-                           OutputArray _status, OutputArray _err,
-                           Size winSize, int maxLevel,
-                           TermCriteria criteria,
-                           int flags, double minEigThreshold )
-{
-#ifdef HAVE_OPENCL
-    bool use_opencl = ocl::useOpenCL() &&
-                      (_prevImg.isUMat() || _nextImg.isUMat()) &&
-                      ocl::Image2D::isFormatSupported(CV_32F, 1, false);
-    if ( use_opencl && ocl_calcOpticalFlowPyrLK(_prevImg, _nextImg, _prevPts, _nextPts, _status, _err, winSize, maxLevel, criteria, flags/*, minEigThreshold*/))
+#ifdef HAVE_OPENVX
+    bool openvx_pyrlk(InputArray _prevImg, InputArray _nextImg, InputArray _prevPts, InputOutputArray _nextPts,
+                             OutputArray _status, OutputArray _err)
     {
-        CV_IMPL_ADD(CV_IMPL_OCL);
-        return;
+        using namespace ivx;
+
+        // Pyramids as inputs are not acceptable because there's no (direct or simple) way
+        // to build vx_pyramid on user data
+        if(_prevImg.kind() != _InputArray::MAT || _nextImg.kind() != _InputArray::MAT)
+            return false;
+
+        Mat prevImgMat = _prevImg.getMat(), nextImgMat = _nextImg.getMat();
+
+        if(prevImgMat.type() != CV_8UC1 || nextImgMat.type() != CV_8UC1)
+            return false;
+
+        CV_Assert(prevImgMat.size() == nextImgMat.size());
+        Mat prevPtsMat = _prevPts.getMat();
+        int checkPrev = prevPtsMat.checkVector(2, CV_32F, false);
+        CV_Assert( checkPrev >= 0 );
+        size_t npoints = checkPrev;
+
+        if( !(flags & OPTFLOW_USE_INITIAL_FLOW) )
+            _nextPts.create(prevPtsMat.size(), prevPtsMat.type(), -1, true);
+        Mat nextPtsMat = _nextPts.getMat();
+        CV_Assert( nextPtsMat.checkVector(2, CV_32F, false) == (int)npoints );
+
+        _status.create((int)npoints, 1, CV_8U, -1, true);
+        Mat statusMat = _status.getMat();
+        uchar* status = statusMat.ptr();
+        for(size_t i = 0; i < npoints; i++ )
+            status[i] = true;
+
+        // OpenVX doesn't return detection errors
+        if( _err.needed() )
+        {
+            return false;
+        }
+
+        try
+        {
+            Context context = Context::create();
+
+            if(context.vendorID() == VX_ID_KHRONOS)
+            {
+                // PyrLK in OVX 1.0.1 performs vxCommitImagePatch incorrecty and crashes
+                if(VX_VERSION == VX_VERSION_1_0)
+                    return false;
+                // Implementation ignores border mode
+                // So check that minimal size of image in pyramid is big enough
+                int width = prevImgMat.cols, height = prevImgMat.rows;
+                for(int i = 0; i < maxLevel+1; i++)
+                {
+                    if(width < winSize.width + 1 || height < winSize.height + 1)
+                        return false;
+                    else
+                    {
+                        width /= 2; height /= 2;
+                    }
+                }
+            }
+
+            Image prevImg = Image::createFromHandle(context, Image::matTypeToFormat(prevImgMat.type()),
+                                                    Image::createAddressing(prevImgMat), (void*)prevImgMat.data);
+            Image nextImg = Image::createFromHandle(context, Image::matTypeToFormat(nextImgMat.type()),
+                                                    Image::createAddressing(nextImgMat), (void*)nextImgMat.data);
+
+            Graph graph = Graph::create(context);
+
+            Pyramid prevPyr = Pyramid::createVirtual(graph, (vx_size)maxLevel+1, VX_SCALE_PYRAMID_HALF,
+                                                     prevImg.width(), prevImg.height(), prevImg.format());
+            Pyramid nextPyr = Pyramid::createVirtual(graph, (vx_size)maxLevel+1, VX_SCALE_PYRAMID_HALF,
+                                                     nextImg.width(), nextImg.height(), nextImg.format());
+
+            ivx::Node::create(graph, VX_KERNEL_GAUSSIAN_PYRAMID, prevImg, prevPyr);
+            ivx::Node::create(graph, VX_KERNEL_GAUSSIAN_PYRAMID, nextImg, nextPyr);
+
+            Array prevPts = Array::create(context, VX_TYPE_KEYPOINT, npoints);
+            Array estimatedPts = Array::create(context, VX_TYPE_KEYPOINT, npoints);
+            Array nextPts = Array::create(context, VX_TYPE_KEYPOINT, npoints);
+
+            std::vector<vx_keypoint_t> vxPrevPts(npoints), vxEstPts(npoints), vxNextPts(npoints);
+            for(size_t i = 0; i < npoints; i++)
+            {
+                vx_keypoint_t& prevPt = vxPrevPts[i]; vx_keypoint_t& estPt  = vxEstPts[i];
+                prevPt.x = prevPtsMat.at<Point2f>(i).x; prevPt.y = prevPtsMat.at<Point2f>(i).y;
+                 estPt.x = nextPtsMat.at<Point2f>(i).x;  estPt.y = nextPtsMat.at<Point2f>(i).y;
+                prevPt.tracking_status = estPt.tracking_status = vx_true_e;
+            }
+            prevPts.addItems(vxPrevPts); estimatedPts.addItems(vxEstPts);
+
+            if( (criteria.type & TermCriteria::COUNT) == 0 )
+                criteria.maxCount = 30;
+            else
+                criteria.maxCount = std::min(std::max(criteria.maxCount, 0), 100);
+            if( (criteria.type & TermCriteria::EPS) == 0 )
+                criteria.epsilon = 0.01;
+            else
+                criteria.epsilon = std::min(std::max(criteria.epsilon, 0.), 10.);
+            criteria.epsilon *= criteria.epsilon;
+
+            vx_enum termEnum = (criteria.type == TermCriteria::COUNT) ? VX_TERM_CRITERIA_ITERATIONS :
+                               (criteria.type == TermCriteria::EPS) ? VX_TERM_CRITERIA_EPSILON :
+                               VX_TERM_CRITERIA_BOTH;
+
+            //minEigThreshold is fixed to 0.0001f
+            ivx::Scalar termination = ivx::Scalar::create<VX_TYPE_ENUM>(context, termEnum);
+            ivx::Scalar epsilon = ivx::Scalar::create<VX_TYPE_FLOAT32>(context, criteria.epsilon);
+            ivx::Scalar numIterations = ivx::Scalar::create<VX_TYPE_UINT32>(context, criteria.maxCount);
+            ivx::Scalar useInitial = ivx::Scalar::create<VX_TYPE_BOOL>(context, (vx_bool)(flags & OPTFLOW_USE_INITIAL_FLOW));
+            //assume winSize is square
+            ivx::Scalar windowSize = ivx::Scalar::create<VX_TYPE_SIZE>(context, (vx_size)winSize.width);
+
+            ivx::Node::create(graph, VX_KERNEL_OPTICAL_FLOW_PYR_LK, prevPyr, nextPyr, prevPts, estimatedPts,
+                              nextPts, termination, epsilon, numIterations, useInitial, windowSize);
+
+            graph.verify();
+            graph.process();
+
+            nextPts.copyTo(vxNextPts);
+            for(size_t i = 0; i < npoints; i++)
+            {
+                vx_keypoint_t kp = vxNextPts[i];
+                nextPtsMat.at<Point2f>(i) = Point2f(kp.x, kp.y);
+                statusMat.at<uchar>(i) = (bool)kp.tracking_status;
+            }
+
+#ifdef VX_VERSION_1_1
+        //we should take user memory back before release
+        //(it's not done automatically according to standard)
+        prevImg.swapHandle(); nextImg.swapHandle();
+#endif
+        }
+        catch (RuntimeError & e)
+        {
+            VX_DbgThrow(e.what());
+        }
+        catch (WrapperError & e)
+        {
+            VX_DbgThrow(e.what());
+        }
+
+        return true;
     }
 #endif
+};
+
+
+
+void SparsePyrLKOpticalFlowImpl::calc( InputArray _prevImg, InputArray _nextImg,
+                           InputArray _prevPts, InputOutputArray _nextPts,
+                           OutputArray _status, OutputArray _err)
+{
+    CV_INSTRUMENT_REGION()
+
+    CV_OCL_RUN(ocl::useOpenCL() &&
+               (_prevImg.isUMat() || _nextImg.isUMat()) &&
+               ocl::Image2D::isFormatSupported(CV_32F, 1, false),
+               ocl_calcOpticalFlowPyrLK(_prevImg, _nextImg, _prevPts, _nextPts, _status, _err))
+
+    // Disabled due to bad accuracy
+    CV_OVX_RUN(false,
+               openvx_pyrlk(_prevImg, _nextImg, _prevPts, _nextPts, _status, _err))
 
     Mat prevPtsMat = _prevPts.getMat();
     const int derivDepth = DataType<cv::detail::deriv_type>::depth;
@@ -1262,6 +1379,22 @@ void cv::calcOpticalFlowPyrLK( InputArray _prevImg, InputArray _nextImg,
     }
 }
 
+} // namespace
+} // namespace cv
+cv::Ptr<cv::SparsePyrLKOpticalFlow> cv::SparsePyrLKOpticalFlow::create(Size winSize, int maxLevel, TermCriteria crit, int flags, double minEigThreshold){
+    return makePtr<SparsePyrLKOpticalFlowImpl>(winSize,maxLevel,crit,flags,minEigThreshold);
+}
+void cv::calcOpticalFlowPyrLK( InputArray _prevImg, InputArray _nextImg,
+                               InputArray _prevPts, InputOutputArray _nextPts,
+                               OutputArray _status, OutputArray _err,
+                               Size winSize, int maxLevel,
+                               TermCriteria criteria,
+                               int flags, double minEigThreshold )
+{
+    Ptr<cv::SparsePyrLKOpticalFlow> optflow = cv::SparsePyrLKOpticalFlow::create(winSize,maxLevel,criteria,flags,minEigThreshold);
+    optflow->calc(_prevImg,_nextImg,_prevPts,_nextPts,_status,_err);
+}
+
 namespace cv
 {
 
@@ -1286,8 +1419,6 @@ getRTMatrix( const Point2f* a, const Point2f* b,
             sa[1][1] += a[i].y*a[i].y;
             sa[1][2] += a[i].y;
 
-            sa[2][2] += 1;
-
             sb[0] += a[i].x*b[i].x;
             sb[1] += a[i].y*b[i].x;
             sb[2] += b[i].x;
@@ -1302,7 +1433,7 @@ getRTMatrix( const Point2f* a, const Point2f* b,
 
         sa[3][3] = sa[0][0];
         sa[4][4] = sa[1][1];
-        sa[5][5] = sa[2][2];
+        sa[5][5] = sa[2][2] = count;
 
         solve( A, B, MM, DECOMP_EIG );
     }
@@ -1318,14 +1449,6 @@ getRTMatrix( const Point2f* a, const Point2f* b,
             sa[0][2] += a[i].x;
             sa[0][3] += a[i].y;
 
-
-            sa[2][1] += -a[i].y;
-            sa[2][2] += 1;
-
-            sa[3][0] += a[i].y;
-            sa[3][1] += a[i].x;
-            sa[3][3] += 1;
-
             sb[0] += a[i].x*b[i].x + a[i].y*b[i].y;
             sb[1] += a[i].x*b[i].y - a[i].y*b[i].x;
             sb[2] += b[i].x;
@@ -1353,6 +1476,8 @@ getRTMatrix( const Point2f* a, const Point2f* b,
 
 cv::Mat cv::estimateRigidTransform( InputArray src1, InputArray src2, bool fullAffine )
 {
+    CV_INSTRUMENT_REGION()
+
     Mat M(2, 3, CV_64F), A = src1.getMat(), B = src2.getMat();
 
     const int COUNT = 15;
diff --git a/modules/video/src/opencl/bgfg_mog2.cl b/modules/video/src/opencl/bgfg_mog2.cl
index 629f82d..641e92b 100644
--- a/modules/video/src/opencl/bgfg_mog2.cl
+++ b/modules/video/src/opencl/bgfg_mog2.cl
@@ -5,7 +5,11 @@
 #define cnMode 1
 
 #define frameToMean(a, b) (b) = *(a);
+#if FL==0
 #define meanToFrame(a, b) *b = convert_uchar_sat(a);
+#else
+#define meanToFrame(a, b) *b = (float)a;
+#endif
 
 inline float sum(float val)
 {
@@ -18,10 +22,17 @@ inline float sum(float val)
 #define F_ZERO (0.0f, 0.0f, 0.0f, 0.0f)
 #define cnMode 4
 
+#if FL == 0
 #define meanToFrame(a, b)\
     b[0] = convert_uchar_sat(a.x); \
     b[1] = convert_uchar_sat(a.y); \
     b[2] = convert_uchar_sat(a.z);
+#else
+#define meanToFrame(a, b)\
+    b[0] = a.x; \
+    b[1] = a.y; \
+    b[2] = a.z;
+#endif
 
 #define frameToMean(a, b)\
     b.x = a[0]; \
@@ -55,7 +66,11 @@ __kernel void mog2_kernel(__global const uchar* frame, int frame_step, int frame
 
     if( x < frame_col && y < frame_row)
     {
+        #if FL==0
         __global const uchar* _frame = (frame + mad24(y, frame_step, mad24(x, CN, frame_offset)));
+        #else
+        __global const float* _frame = ((__global const float*)( frame + mad24(y, frame_step, frame_offset)) + mad24(x, CN, 0));
+        #endif
         T_MEAN pix;
         frameToMean(_frame, pix);
 
@@ -267,7 +282,13 @@ __kernel void getBackgroundImage2_kernel(__global const uchar* modesUsed,
             meanVal = meanVal / totalWeight;
         else
             meanVal = (T_MEAN)(0.f);
+
+        #if FL==0
         __global uchar* _dst = dst + mad24(y, dst_step, mad24(x, CN, dst_offset));
         meanToFrame(meanVal, _dst);
+        #else
+        __global float* _dst = ((__global float*)( dst + mad24(y, dst_step, dst_offset)) + mad24(x, CN, 0));
+        meanToFrame(meanVal, _dst);
+        #endif
     }
-}
\ No newline at end of file
+}
diff --git a/modules/video/src/opencl/optical_flow_tvl1.cl b/modules/video/src/opencl/optical_flow_tvl1.cl
index 472c4fa..ce67879 100644
--- a/modules/video/src/opencl/optical_flow_tvl1.cl
+++ b/modules/video/src/opencl/optical_flow_tvl1.cl
@@ -148,7 +148,7 @@ __kernel void warpBackwardKernel(__global const float* I0, int I0_step, int I0_c
     }
 }
 
-inline float readImage(__global float *image,  int x,  int y,  int rows,  int cols, int elemCntPerRow)
+inline float readImage(__global const float *image,  int x,  int y,  int rows,  int cols, int elemCntPerRow)
 {
     int i0 = clamp(x, 0, cols - 1);
     int j0 = clamp(y, 0, rows - 1);
diff --git a/modules/video/src/opencl/pyrlk.cl b/modules/video/src/opencl/pyrlk.cl
index 44707aa..80ec48a 100644
--- a/modules/video/src/opencl/pyrlk.cl
+++ b/modules/video/src/opencl/pyrlk.cl
@@ -266,7 +266,7 @@ inline void GetError(image2d_t J, const float x, const float y, const float* Pch
 
 
 //macro to read pixel value into local memory.
-#define READI(_y,_x) IPatchLocal[mad24(mad24((_y), LSy, yid), LM_W, mad24((_x), LSx, xid))] = read_imagef(I, sampler, (float2)(mad((_x), LSx, Point.x + xid - 0.5f), mad((_y), LSy, Point.y + yid - 0.5f))).x;
+#define READI(_y,_x) IPatchLocal[mad24(mad24((_y), LSy, yid), LM_W, mad24((_x), LSx, xid))] = read_imagef(I, sampler, (float2)(mad((float)(_x), (float)LSx, Point.x + xid - 0.5f), mad((float)(_y), (float)LSy, Point.y + yid - 0.5f))).x;
 void ReadPatchIToLocalMem(image2d_t I, float2 Point, local float* IPatchLocal)
 {
     int xid=get_local_id(0);
@@ -528,4 +528,4 @@ __kernel void lkSparse(image2d_t I, image2d_t J,
         if (calcErr)
             err[gid] = smem1[0] / (float)(c_winSize_x * c_winSize_y);
     }
-}
\ No newline at end of file
+}
diff --git a/modules/video/src/optflowgf.cpp b/modules/video/src/optflowgf.cpp
index 3b61bb2..69a7ea6 100644
--- a/modules/video/src/optflowgf.cpp
+++ b/modules/video/src/optflowgf.cpp
@@ -583,39 +583,63 @@ FarnebackUpdateFlow_GaussianBlur( const Mat& _R0, const Mat& _R1,
 
 }
 
-#ifdef HAVE_OPENCL
 namespace cv
 {
-class FarnebackOpticalFlow
+namespace
+{
+class FarnebackOpticalFlowImpl : public FarnebackOpticalFlow
 {
 public:
-    FarnebackOpticalFlow()
+    FarnebackOpticalFlowImpl(int numLevels=5, double pyrScale=0.5, bool fastPyramids=false, int winSize=13,
+                             int numIters=10, int polyN=5, double polySigma=1.1, int flags=0) :
+        numLevels_(numLevels), pyrScale_(pyrScale), fastPyramids_(fastPyramids), winSize_(winSize),
+        numIters_(numIters), polyN_(polyN), polySigma_(polySigma), flags_(flags)
     {
-        numLevels = 5;
-        pyrScale = 0.5;
-        fastPyramids = false;
-        winSize = 13;
-        numIters = 10;
-        polyN = 5;
-        polySigma = 1.1;
-        flags = 0;
     }
 
-    int numLevels;
-    double pyrScale;
-    bool fastPyramids;
-    int winSize;
-    int numIters;
-    int polyN;
-    double polySigma;
-    int flags;
+    virtual int getNumLevels() const { return numLevels_; }
+    virtual void setNumLevels(int numLevels) { numLevels_ = numLevels; }
+
+    virtual double getPyrScale() const { return pyrScale_; }
+    virtual void setPyrScale(double pyrScale) { pyrScale_ = pyrScale; }
+
+    virtual bool getFastPyramids() const { return fastPyramids_; }
+    virtual void setFastPyramids(bool fastPyramids) { fastPyramids_ = fastPyramids; }
+
+    virtual int getWinSize() const { return winSize_; }
+    virtual void setWinSize(int winSize) { winSize_ = winSize; }
+
+    virtual int getNumIters() const { return numIters_; }
+    virtual void setNumIters(int numIters) { numIters_ = numIters; }
+
+    virtual int getPolyN() const { return polyN_; }
+    virtual void setPolyN(int polyN) { polyN_ = polyN; }
 
+    virtual double getPolySigma() const { return polySigma_; }
+    virtual void setPolySigma(double polySigma) { polySigma_ = polySigma; }
+
+    virtual int getFlags() const { return flags_; }
+    virtual void setFlags(int flags) { flags_ = flags; }
+
+    virtual void calc(InputArray I0, InputArray I1, InputOutputArray flow);
+
+private:
+    int numLevels_;
+    double pyrScale_;
+    bool fastPyramids_;
+    int winSize_;
+    int numIters_;
+    int polyN_;
+    double polySigma_;
+    int flags_;
+
+#ifdef HAVE_OPENCL
     bool operator ()(const UMat &frame0, const UMat &frame1, UMat &flowx, UMat &flowy)
     {
         CV_Assert(frame0.channels() == 1 && frame1.channels() == 1);
         CV_Assert(frame0.size() == frame1.size());
-        CV_Assert(polyN == 5 || polyN == 7);
-        CV_Assert(!fastPyramids || std::abs(pyrScale - 0.5) < 1e-6);
+        CV_Assert(polyN_ == 5 || polyN_ == 7);
+        CV_Assert(!fastPyramids_ || std::abs(pyrScale_ - 0.5) < 1e-6);
 
         const int min_size = 32;
 
@@ -630,9 +654,9 @@ public:
         // Crop unnecessary levels
         double scale = 1;
         int numLevelsCropped = 0;
-        for (; numLevelsCropped < numLevels; numLevelsCropped++)
+        for (; numLevelsCropped < numLevels_; numLevelsCropped++)
         {
-            scale *= pyrScale;
+            scale *= pyrScale_;
             if (size.width*scale < min_size || size.height*scale < min_size)
                 break;
         }
@@ -640,7 +664,7 @@ public:
         frame0.convertTo(frames_[0], CV_32F);
         frame1.convertTo(frames_[1], CV_32F);
 
-        if (fastPyramids)
+        if (fastPyramids_)
         {
             // Build Gaussian pyramids using pyrDown()
             pyramid0_.resize(numLevelsCropped + 1);
@@ -654,13 +678,13 @@ public:
             }
         }
 
-        setPolynomialExpansionConsts(polyN, polySigma);
+        setPolynomialExpansionConsts(polyN_, polySigma_);
 
         for (int k = numLevelsCropped; k >= 0; k--)
         {
             scale = 1;
             for (int i = 0; i < k; i++)
-                scale *= pyrScale;
+                scale *= pyrScale_;
 
             double sigma = (1./scale - 1) * 0.5;
             int smoothSize = cvRound(sigma*5) | 1;
@@ -669,7 +693,7 @@ public:
             int width = cvRound(size.width*scale);
             int height = cvRound(size.height*scale);
 
-            if (fastPyramids)
+            if (fastPyramids_)
             {
                 width = pyramid0_[k].cols;
                 height = pyramid0_[k].rows;
@@ -688,7 +712,7 @@ public:
 
             if (prevFlowX.empty())
             {
-                if (flags & cv::OPTFLOW_USE_INITIAL_FLOW)
+                if (flags_ & cv::OPTFLOW_USE_INITIAL_FLOW)
                 {
                     resize(flowx0, curFlowX, Size(width, height), 0, 0, INTER_LINEAR);
                     resize(flowy0, curFlowY, Size(width, height), 0, 0, INTER_LINEAR);
@@ -705,8 +729,8 @@ public:
             {
                 resize(prevFlowX, curFlowX, Size(width, height), 0, 0, INTER_LINEAR);
                 resize(prevFlowY, curFlowY, Size(width, height), 0, 0, INTER_LINEAR);
-                multiply(1./pyrScale, curFlowX, curFlowX);
-                multiply(1./pyrScale, curFlowY, curFlowY);
+                multiply(1./pyrScale_, curFlowX, curFlowX);
+                multiply(1./pyrScale_, curFlowY, curFlowY);
             }
 
             UMat M = allocMatFromBuf(5*height, width, CV_32F, M_);
@@ -717,7 +741,7 @@ public:
                 allocMatFromBuf(5*height, width, CV_32F, R_[1])
             };
 
-            if (fastPyramids)
+            if (fastPyramids_)
             {
                 if (!polynomialExpansionOcl(pyramid0_[k], R[0]))
                     return false;
@@ -752,18 +776,18 @@ public:
             if (!updateMatricesOcl(curFlowX, curFlowY, R[0], R[1], M))
                 return false;
 
-            if (flags & OPTFLOW_FARNEBACK_GAUSSIAN)
-                setGaussianBlurKernel(winSize, winSize/2*0.3f);
-            for (int i = 0; i < numIters; i++)
+            if (flags_ & OPTFLOW_FARNEBACK_GAUSSIAN)
+                setGaussianBlurKernel(winSize_, winSize_/2*0.3f);
+            for (int i = 0; i < numIters_; i++)
             {
-                if (flags & OPTFLOW_FARNEBACK_GAUSSIAN)
+                if (flags_ & OPTFLOW_FARNEBACK_GAUSSIAN)
                 {
-                    if (!updateFlow_gaussianBlur(R[0], R[1], curFlowX, curFlowY, M, bufM, winSize, i < numIters-1))
+                    if (!updateFlow_gaussianBlur(R[0], R[1], curFlowX, curFlowY, M, bufM, winSize_, i < numIters_-1))
                         return false;
                 }
                 else
                 {
-                    if (!updateFlow_boxFilter(R[0], R[1], curFlowX, curFlowY, M, bufM, winSize, i < numIters-1))
+                    if (!updateFlow_boxFilter(R[0], R[1], curFlowX, curFlowY, M, bufM, winSize_, i < numIters_-1))
                         return false;
                 }
             }
@@ -776,7 +800,9 @@ public:
         flowy = curFlowY;
         return true;
     }
-
+    virtual void collectGarbage(){
+        releaseMemory();
+    }
     void releaseMemory()
     {
         frames_[0].release();
@@ -898,15 +924,15 @@ private:
 #else
         size_t localsize[2] = { 256, 1};
 #endif
-        size_t globalsize[2] = { DIVUP((size_t)src.cols, localsize[0] - 2*polyN) * localsize[0], (size_t)src.rows};
+        size_t globalsize[2] = { DIVUP((size_t)src.cols, localsize[0] - 2*polyN_) * localsize[0], (size_t)src.rows};
 
 #if 0
         const cv::ocl::Device &device = cv::ocl::Device::getDefault();
         bool useDouble = (0 != device.doubleFPConfig());
 
-        cv::String build_options = cv::format("-D polyN=%d -D USE_DOUBLE=%d", polyN, useDouble ? 1 : 0);
+        cv::String build_options = cv::format("-D polyN=%d -D USE_DOUBLE=%d", polyN_, useDouble ? 1 : 0);
 #else
-        cv::String build_options = cv::format("-D polyN=%d", polyN);
+        cv::String build_options = cv::format("-D polyN=%d", polyN_);
 #endif
         ocl::Kernel kernel;
         if (!kernel.create("polynomialExpansion", cv::ocl::video::optical_flow_farneback_oclsrc, build_options))
@@ -1036,60 +1062,45 @@ private:
                 return false;
         return true;
     }
-};
-
-static bool ocl_calcOpticalFlowFarneback( InputArray _prev0, InputArray _next0,
-                            InputOutputArray _flow0, double pyr_scale, int levels, int winsize,
-                            int iterations, int poly_n, double poly_sigma, int flags )
-{
-    if ((5 != poly_n) && (7 != poly_n))
-        return false;
-    if (_next0.size() != _prev0.size())
-        return false;
-    int typePrev = _prev0.type();
-    int typeNext = _next0.type();
-    if ((1 != CV_MAT_CN(typePrev)) || (1 != CV_MAT_CN(typeNext)))
-        return false;
-
-    FarnebackOpticalFlow opticalFlow;
-    opticalFlow.numLevels   = levels;
-    opticalFlow.pyrScale    = pyr_scale;
-    opticalFlow.fastPyramids= false;
-    opticalFlow.winSize     = winsize;
-    opticalFlow.numIters    = iterations;
-    opticalFlow.polyN       = poly_n;
-    opticalFlow.polySigma   = poly_sigma;
-    opticalFlow.flags       = flags;
-
-    std::vector<UMat> flowar;
-    if (!_flow0.empty())
-        split(_flow0, flowar);
-    else
+    bool calc_ocl( InputArray _prev0, InputArray _next0,
+                   InputOutputArray _flow0)
     {
-        flowar.push_back(UMat());
-        flowar.push_back(UMat());
-    }
-    if (!opticalFlow(_prev0.getUMat(), _next0.getUMat(), flowar[0], flowar[1]))
-        return false;
-    merge(flowar, _flow0);
-    return true;
-}
-}
-#endif // HAVE_OPENCL
+        if ((5 != polyN_) && (7 != polyN_))
+            return false;
+        if (_next0.size() != _prev0.size())
+            return false;
+        int typePrev = _prev0.type();
+        int typeNext = _next0.type();
+        if ((1 != CV_MAT_CN(typePrev)) || (1 != CV_MAT_CN(typeNext)))
+            return false;
 
-void cv::calcOpticalFlowFarneback( InputArray _prev0, InputArray _next0,
-                               InputOutputArray _flow0, double pyr_scale, int levels, int winsize,
-                               int iterations, int poly_n, double poly_sigma, int flags )
-{
-#ifdef HAVE_OPENCL
-    bool use_opencl = ocl::useOpenCL() && _flow0.isUMat();
-    if( use_opencl && ocl_calcOpticalFlowFarneback(_prev0, _next0, _flow0, pyr_scale, levels, winsize, iterations, poly_n, poly_sigma, flags))
-    {
-        CV_IMPL_ADD(CV_IMPL_OCL);
-        return;
+        std::vector<UMat> flowar;
+        if (!_flow0.empty())
+            split(_flow0, flowar);
+        else
+        {
+            flowar.push_back(UMat());
+            flowar.push_back(UMat());
+        }
+        if(!this->operator()(_prev0.getUMat(), _next0.getUMat(), flowar[0], flowar[1])){
+            return false;
+        }
+        merge(flowar, _flow0);
+        return true;
     }
+#else // HAVE_OPENCL
+    virtual void collectGarbage(){}
 #endif
+};
 
+void FarnebackOpticalFlowImpl::calc(InputArray _prev0, InputArray _next0,
+                                    InputOutputArray _flow0)
+{
+    CV_INSTRUMENT_REGION()
+
+    CV_OCL_RUN(_flow0.isUMat() &&
+               ocl::Image2D::isFormatSupported(CV_32F, 1, false),
+               calc_ocl(_prev0,_next0,_flow0))
     Mat prev0 = _prev0.getMat(), next0 = _next0.getMat();
     const int min_size = 32;
     const Mat* img[2] = { &prev0, &next0 };
@@ -1097,15 +1108,16 @@ void cv::calcOpticalFlowFarneback( InputArray _prev0, InputArray _next0,
     int i, k;
     double scale;
     Mat prevFlow, flow, fimg;
+    int levels = numLevels_;
 
     CV_Assert( prev0.size() == next0.size() && prev0.channels() == next0.channels() &&
-        prev0.channels() == 1 && pyr_scale < 1 );
+               prev0.channels() == 1 && pyrScale_ < 1 );
     _flow0.create( prev0.size(), CV_32FC2 );
     Mat flow0 = _flow0.getMat();
 
     for( k = 0, scale = 1; k < levels; k++ )
     {
-        scale *= pyr_scale;
+        scale *= pyrScale_;
         if( prev0.cols*scale < min_size || prev0.rows*scale < min_size )
             break;
     }
@@ -1115,7 +1127,7 @@ void cv::calcOpticalFlowFarneback( InputArray _prev0, InputArray _next0,
     for( k = levels; k >= 0; k-- )
     {
         for( i = 0, scale = 1; i < k; i++ )
-            scale *= pyr_scale;
+            scale *= pyrScale_;
 
         double sigma = (1./scale-1)*0.5;
         int smooth_sz = cvRound(sigma*5)|1;
@@ -1131,7 +1143,7 @@ void cv::calcOpticalFlowFarneback( InputArray _prev0, InputArray _next0,
 
         if( prevFlow.empty() )
         {
-            if( flags & OPTFLOW_USE_INITIAL_FLOW )
+            if( flags_ & OPTFLOW_USE_INITIAL_FLOW )
             {
                 resize( flow0, flow, Size(width, height), 0, 0, INTER_AREA );
                 flow *= scale;
@@ -1142,7 +1154,7 @@ void cv::calcOpticalFlowFarneback( InputArray _prev0, InputArray _next0,
         else
         {
             resize( prevFlow, flow, Size(width, height), 0, 0, INTER_LINEAR );
-            flow *= 1./pyr_scale;
+            flow *= 1./pyrScale_;
         }
 
         Mat R[2], I, M;
@@ -1151,19 +1163,40 @@ void cv::calcOpticalFlowFarneback( InputArray _prev0, InputArray _next0,
             img[i]->convertTo(fimg, CV_32F);
             GaussianBlur(fimg, fimg, Size(smooth_sz, smooth_sz), sigma, sigma);
             resize( fimg, I, Size(width, height), INTER_LINEAR );
-            FarnebackPolyExp( I, R[i], poly_n, poly_sigma );
+            FarnebackPolyExp( I, R[i], polyN_, polySigma_ );
         }
 
         FarnebackUpdateMatrices( R[0], R[1], flow, M, 0, flow.rows );
 
-        for( i = 0; i < iterations; i++ )
+        for( i = 0; i < numIters_; i++ )
         {
-            if( flags & OPTFLOW_FARNEBACK_GAUSSIAN )
-                FarnebackUpdateFlow_GaussianBlur( R[0], R[1], flow, M, winsize, i < iterations - 1 );
+            if( flags_ & OPTFLOW_FARNEBACK_GAUSSIAN )
+                FarnebackUpdateFlow_GaussianBlur( R[0], R[1], flow, M, winSize_, i < numIters_ - 1 );
             else
-                FarnebackUpdateFlow_Blur( R[0], R[1], flow, M, winsize, i < iterations - 1 );
+                FarnebackUpdateFlow_Blur( R[0], R[1], flow, M, winSize_, i < numIters_ - 1 );
         }
 
         prevFlow = flow;
     }
 }
+} // namespace
+} // namespace cv
+
+void cv::calcOpticalFlowFarneback( InputArray _prev0, InputArray _next0,
+                               InputOutputArray _flow0, double pyr_scale, int levels, int winsize,
+                               int iterations, int poly_n, double poly_sigma, int flags )
+{
+    CV_INSTRUMENT_REGION()
+
+    Ptr<cv::FarnebackOpticalFlow> optflow;
+    optflow = makePtr<FarnebackOpticalFlowImpl>(levels,pyr_scale,false,winsize,iterations,poly_n,poly_sigma,flags);
+    optflow->calc(_prev0,_next0,_flow0);
+}
+
+
+cv::Ptr<cv::FarnebackOpticalFlow> cv::FarnebackOpticalFlow::create(int numLevels, double pyrScale, bool fastPyramids, int winSize,
+                                                               int numIters, int polyN, double polySigma, int flags)
+{
+    return makePtr<FarnebackOpticalFlowImpl>(numLevels, pyrScale, fastPyramids, winSize,
+                                             numIters, polyN, polySigma, flags);
+}
diff --git a/modules/video/src/tvl1flow.cpp b/modules/video/src/tvl1flow.cpp
index b10dc3f..03d215d 100644
--- a/modules/video/src/tvl1flow.cpp
+++ b/modules/video/src/tvl1flow.cpp
@@ -89,6 +89,17 @@ namespace {
 class OpticalFlowDual_TVL1 : public DualTVL1OpticalFlow
 {
 public:
+
+    OpticalFlowDual_TVL1(double tau_, double lambda_, double theta_, int nscales_, int warps_,
+                         double epsilon_, int innerIterations_, int outerIterations_,
+                         double scaleStep_, double gamma_, int medianFiltering_,
+                         bool useInitialFlow_) :
+        tau(tau_), lambda(lambda_), theta(theta_), gamma(gamma_), nscales(nscales_),
+        warps(warps_), epsilon(epsilon_), innerIterations(innerIterations_),
+        outerIterations(outerIterations_), useInitialFlow(useInitialFlow_),
+        scaleStep(scaleStep_), medianFiltering(medianFiltering_)
+    {
+    }
     OpticalFlowDual_TVL1();
 
     void calc(InputArray I0, InputArray I1, InputOutputArray flow);
@@ -379,6 +390,8 @@ OpticalFlowDual_TVL1::OpticalFlowDual_TVL1()
 
 void OpticalFlowDual_TVL1::calc(InputArray _I0, InputArray _I1, InputOutputArray _flow)
 {
+    CV_INSTRUMENT_REGION()
+
     CV_OCL_RUN(_flow.isUMat() &&
                ocl::Image2D::isFormatSupported(CV_32F, 1, false),
                calc_ocl(_I0, _I1, _flow))
@@ -1450,3 +1463,13 @@ Ptr<DualTVL1OpticalFlow> cv::createOptFlow_DualTVL1()
 {
     return makePtr<OpticalFlowDual_TVL1>();
 }
+
+Ptr<DualTVL1OpticalFlow> cv::DualTVL1OpticalFlow::create(
+    double tau, double lambda, double theta, int nscales, int warps,
+    double epsilon, int innerIterations, int outerIterations, double scaleStep,
+    double gamma, int medianFilter, bool useInitialFlow)
+{
+    return makePtr<OpticalFlowDual_TVL1>(tau, lambda, theta, nscales, warps,
+                                         epsilon, innerIterations, outerIterations,
+                                         scaleStep, gamma, medianFilter, useInitialFlow);
+}
diff --git a/modules/video/test/ocl/test_bgfg_mog2.cpp b/modules/video/test/ocl/test_bgfg_mog2.cpp
index 49539ac..030cd09 100644
--- a/modules/video/test/ocl/test_bgfg_mog2.cpp
+++ b/modules/video/test/ocl/test_bgfg_mog2.cpp
@@ -26,16 +26,19 @@ namespace
 {
     IMPLEMENT_PARAM_CLASS(UseGray, bool)
     IMPLEMENT_PARAM_CLASS(DetectShadow, bool)
+    IMPLEMENT_PARAM_CLASS(UseFloat, bool)
 }
 
-PARAM_TEST_CASE(Mog2_Update, UseGray, DetectShadow)
+PARAM_TEST_CASE(Mog2_Update, UseGray, DetectShadow,UseFloat)
 {
     bool useGray;
     bool detectShadow;
+    bool useFloat;
     virtual void SetUp()
     {
         useGray = GET_PARAM(0);
         detectShadow = GET_PARAM(1);
+        useFloat = GET_PARAM(2);
     }
 };
 
@@ -66,6 +69,13 @@ OCL_TEST_P(Mog2_Update, Accuracy)
             swap(temp, frame);
         }
 
+        if(useFloat)
+        {
+            Mat temp;
+            frame.convertTo(temp,CV_32F);
+            swap(temp,frame);
+        }
+
         OCL_OFF(mog2_cpu->apply(frame, foreground));
         OCL_ON (mog2_ocl->apply(frame, u_foreground));
 
@@ -78,12 +88,14 @@ OCL_TEST_P(Mog2_Update, Accuracy)
 
 //////////////////////////Mog2_getBackgroundImage///////////////////////////////////
 
-PARAM_TEST_CASE(Mog2_getBackgroundImage, DetectShadow)
+PARAM_TEST_CASE(Mog2_getBackgroundImage, DetectShadow, UseFloat)
 {
     bool detectShadow;
+    bool useFloat;
     virtual void SetUp()
     {
         detectShadow = GET_PARAM(0);
+        useFloat = GET_PARAM(1);
     }
 };
 
@@ -107,6 +119,13 @@ OCL_TEST_P(Mog2_getBackgroundImage, Accuracy)
         cap >> frame;
         ASSERT_FALSE(frame.empty());
 
+        if(useFloat)
+        {
+            Mat temp;
+            frame.convertTo(temp,CV_32F);
+            swap(temp,frame);
+        }
+
         OCL_OFF(mog2_cpu->apply(frame, foreground));
         OCL_ON (mog2_ocl->apply(frame, u_foreground));
     }
@@ -123,11 +142,14 @@ OCL_TEST_P(Mog2_getBackgroundImage, Accuracy)
 ///////////////////////////////////////////////////////////////////////////////////////////
 
 OCL_INSTANTIATE_TEST_CASE_P(OCL_Video, Mog2_Update, Combine(
-                                    Values(UseGray(true), UseGray(false)),
-                                    Values(DetectShadow(true), DetectShadow(false)))
+                                    Values(UseGray(true),UseGray(false)),
+                                    Values(DetectShadow(true), DetectShadow(false)),
+                                    Values(UseFloat(false),UseFloat(true)))
                            );
 
-OCL_INSTANTIATE_TEST_CASE_P(OCL_Video, Mog2_getBackgroundImage, (Values(DetectShadow(true), DetectShadow(false)))
+OCL_INSTANTIATE_TEST_CASE_P(OCL_Video, Mog2_getBackgroundImage, Combine(
+                                                     Values(DetectShadow(true), DetectShadow(false)),
+                                                     Values(UseFloat(false),UseFloat(true)))
                            );
 
 }}// namespace cvtest::ocl
diff --git a/modules/video/test/test_accum.cpp b/modules/video/test/test_accum.cpp
index 6895bb4..fe045c6 100644
--- a/modules/video/test/test_accum.cpp
+++ b/modules/video/test/test_accum.cpp
@@ -72,11 +72,11 @@ void CV_AccumBaseTest::get_test_array_types_and_sizes( int test_case_idx,
                         vector<vector<Size> >& sizes, vector<vector<int> >& types )
 {
     RNG& rng = ts->get_rng();
-    int depth = cvtest::randInt(rng) % 3, cn = cvtest::randInt(rng) & 1 ? 3 : 1;
-    int accdepth = std::max((int)(cvtest::randInt(rng) % 2 + 1), depth);
+    int depth = cvtest::randInt(rng) % 4, cn = cvtest::randInt(rng) & 1 ? 3 : 1;
+    int accdepth = (int)(cvtest::randInt(rng) % 2 + 1);
     int i, input_count = (int)test_array[INPUT].size();
     cvtest::ArrayTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
-    depth = depth == 0 ? CV_8U : depth == 1 ? CV_32F : CV_64F;
+    depth = depth == 0 ? CV_8U : depth == 1 ? CV_16U : depth == 2 ? CV_32F : CV_64F;
     accdepth = accdepth == 1 ? CV_32F : CV_64F;
     accdepth = MAX(accdepth, depth);
 
diff --git a/modules/video/test/test_ecc.cpp b/modules/video/test/test_ecc.cpp
index 675b6a6..b1e951a 100644
--- a/modules/video/test/test_ecc.cpp
+++ b/modules/video/test/test_ecc.cpp
@@ -82,7 +82,7 @@ bool CV_ECC_BaseTest::isMapCorrect(const Mat& map)
             tr = tr & (!cvIsNaN(mapVal) && (fabs(mapVal) < 1e9));
         }
 
-        return tr;
+    return tr;
 }
 
 double CV_ECC_BaseTest::computeRMS(const Mat& mat1, const Mat& mat2){
diff --git a/modules/video/test/test_optflowpyrlk.cpp b/modules/video/test/test_optflowpyrlk.cpp
index e4aa5e5..34652f6 100644
--- a/modules/video/test/test_optflowpyrlk.cpp
+++ b/modules/video/test/test_optflowpyrlk.cpp
@@ -66,7 +66,7 @@ void CV_OptFlowPyrLKTest::run( int )
     double  max_err = 0., sum_err = 0;
     int     pt_cmpd = 0;
     int     pt_exceed = 0;
-    int     merr_i = 0, merr_j = 0, merr_k = 0;
+    int     merr_i = 0, merr_j = 0, merr_k = 0, merr_nan = 0;
     char    filename[1000];
 
     CvPoint2D32f *u = 0, *v = 0, *v2 = 0;
@@ -153,12 +153,18 @@ void CV_OptFlowPyrLKTest::run( int )
         if( status[i] != 0 )
         {
             double err;
-            if( cvIsNaN(v[i].x) )
+            if( cvIsNaN(v[i].x) || cvIsNaN(v[i].y) )
             {
                 merr_j++;
                 continue;
             }
 
+            if( cvIsNaN(v2[i].x) || cvIsNaN(v2[i].y) )
+            {
+                merr_nan++;
+                continue;
+            }
+
             err = fabs(v2[i].x - v[i].x) + fabs(v2[i].y - v[i].y);
             if( err > max_err )
             {
@@ -198,6 +204,13 @@ void CV_OptFlowPyrLKTest::run( int )
         goto _exit_;
     }
 
+    if( merr_nan > 0 )
+    {
+        ts->printf( cvtest::TS::LOG, "NAN tracking result with status != 0 (%d times)\n", merr_nan );
+        code = cvtest::TS::FAIL_BAD_ACCURACY;
+        goto _exit_;
+    }
+
 _exit_:
 
     cvFree( &status );
diff --git a/modules/video/test/test_tvl1optflow.cpp b/modules/video/test/test_tvl1optflow.cpp
index e4b8063..b0b962c 100644
--- a/modules/video/test/test_tvl1optflow.cpp
+++ b/modules/video/test/test_tvl1optflow.cpp
@@ -116,34 +116,39 @@ namespace
         return !cvIsNaN(u.x) && !cvIsNaN(u.y) && (fabs(u.x) < 1e9) && (fabs(u.y) < 1e9);
     }
 
-    double calcRMSE(const Mat_<Point2f>& flow1, const Mat_<Point2f>& flow2)
+    void check(const Mat_<Point2f>& gold, const Mat_<Point2f>& flow, double threshold = 0.1, double expectedAccuracy = 0.95)
     {
-        double sum = 0.0;
-        int counter = 0;
+        threshold = threshold*threshold;
 
-        for (int i = 0; i < flow1.rows; ++i)
+        size_t gold_counter = 0;
+        size_t valid_counter = 0;
+
+        for (int i = 0; i < gold.rows; ++i)
         {
-            for (int j = 0; j < flow1.cols; ++j)
+            for (int j = 0; j < gold.cols; ++j)
             {
-                const Point2f u1 = flow1(i, j);
-                const Point2f u2 = flow2(i, j);
+                const Point2f u1 = gold(i, j);
+                const Point2f u2 = flow(i, j);
 
-                if (isFlowCorrect(u1) && isFlowCorrect(u2))
+                if (isFlowCorrect(u1))
                 {
-                    const Point2f diff = u1 - u2;
-                    sum += diff.ddot(diff);
-                    ++counter;
+                    gold_counter++;
+                    if (isFlowCorrect(u2))
+                    {
+                        const Point2f diff = u1 - u2;
+                        double err = diff.ddot(diff);
+                        if (err <= threshold)
+                            valid_counter++;
+                    }
                 }
             }
         }
-        return sqrt(sum / (1e-9 + counter));
+        EXPECT_GE(valid_counter, expectedAccuracy * gold_counter);
     }
 }
 
 TEST(Video_calcOpticalFlowDual_TVL1, Regression)
 {
-    const double MAX_RMSE = 0.03;
-
     const string frame1_path = TS::ptr()->get_data_path() + "optflow/RubberWhale1.png";
     const string frame2_path = TS::ptr()->get_data_path() + "optflow/RubberWhale2.png";
     const string gold_flow_path = TS::ptr()->get_data_path() + "optflow/tvl1_flow.flo";
@@ -154,7 +159,7 @@ TEST(Video_calcOpticalFlowDual_TVL1, Regression)
     ASSERT_FALSE(frame2.empty());
 
     Mat_<Point2f> flow;
-    Ptr<DenseOpticalFlow> tvl1 = createOptFlow_DualTVL1();
+    Ptr<DualTVL1OpticalFlow> tvl1 = cv::DualTVL1OpticalFlow::create();
 
     tvl1->calc(frame1, frame2, flow);
 
@@ -167,7 +172,6 @@ TEST(Video_calcOpticalFlowDual_TVL1, Regression)
     ASSERT_EQ(gold.rows, flow.rows);
     ASSERT_EQ(gold.cols, flow.cols);
 
-    double err = calcRMSE(gold, flow);
-    EXPECT_LE(err, MAX_RMSE);
+    check(gold, flow);
 #endif
 }
diff --git a/modules/videoio/CMakeLists.txt b/modules/videoio/CMakeLists.txt
index b5da8d0..fb64894 100644
--- a/modules/videoio/CMakeLists.txt
+++ b/modules/videoio/CMakeLists.txt
@@ -131,10 +131,12 @@ if(HAVE_XIMEA)
   endif()
   if(WIN32 AND X86_64)
     list(APPEND VIDEOIO_LIBRARIES xiapi64)
+  elseif(WIN32)
+    list(APPEND VIDEOIO_LIBRARIES xiapi32)
   elseif(APPLE)
     list(APPEND VIDEOIO_LIBRARIES "-framework m3api")
   else()
-    list(APPEND VIDEOIO_LIBRARIES xiapi32)
+    list(APPEND VIDEOIO_LIBRARIES m3api)
   endif()
 endif(HAVE_XIMEA)
 
@@ -165,9 +167,22 @@ if(HAVE_GIGE_API)
   list(APPEND videoio_srcs ${CMAKE_CURRENT_LIST_DIR}/src/cap_giganetix.cpp)
 endif(HAVE_GIGE_API)
 
+if(HAVE_ARAVIS_API)
+  add_definitions(-DHAVE_ARAVIS_API)
+  ocv_include_directories(${ARAVIS_INCLUDE_PATH})
+  set(videoio_srcs ${CMAKE_CURRENT_LIST_DIR}/src/cap_aravis.cpp ${videoio_srcs})
+  list(APPEND VIDEOIO_LIBRARIES ${ARAVIS_LIBRARIES})
+  list(APPEND videoio_srcs ${CMAKE_CURRENT_LIST_DIR}/src/cap_aravis.cpp)
+endif(HAVE_ARAVIS_API)
+
 if(HAVE_AVFOUNDATION)
-  list(APPEND videoio_srcs ${CMAKE_CURRENT_LIST_DIR}/src/cap_avfoundation.mm)
-  list(APPEND VIDEOIO_LIBRARIES "-framework AVFoundation" "-framework QuartzCore")
+  if(IOS)
+    list(APPEND videoio_srcs ${CMAKE_CURRENT_LIST_DIR}/src/cap_avfoundation.mm)
+    list(APPEND VIDEOIO_LIBRARIES "-framework AVFoundation" "-framework QuartzCore")
+  else()
+    list(APPEND videoio_srcs ${CMAKE_CURRENT_LIST_DIR}/src/cap_avfoundation_mac.mm)
+    list(APPEND VIDEOIO_LIBRARIES "-framework Cocoa" "-framework Accelerate" "-framework AVFoundation" "-framework CoreGraphics" "-framework CoreMedia" "-framework CoreVideo" "-framework QuartzCore")
+  endif()
 endif()
 
 if(HAVE_QUICKTIME)
diff --git a/modules/videoio/doc/pics/videoio_overview.svg b/modules/videoio/doc/pics/videoio_overview.svg
new file mode 100644
index 0000000..f6b376e
--- /dev/null
+++ b/modules/videoio/doc/pics/videoio_overview.svg
@@ -0,0 +1,877 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="559.99994"
+   height="520"
+   viewBox="0 0 559.99993 520"
+   id="svg2"
+   version="1.1"
+   inkscape:version="0.91 r13725"
+   sodipodi:docname="opencv-videoio-structure.svg"
+   inkscape:export-filename="./opencv-videoio-structure.png"
+   inkscape:export-xdpi="90"
+   inkscape:export-ydpi="90">
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="1.3701928"
+     inkscape:cx="397.12938"
+     inkscape:cy="243.08432"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     showgrid="true"
+     showguides="true"
+     inkscape:guide-bbox="true"
+     inkscape:snap-page="false"
+     inkscape:snap-bbox="true"
+     inkscape:bbox-nodes="true"
+     inkscape:snap-bbox-edge-midpoints="false"
+     inkscape:bbox-paths="false"
+     inkscape:object-nodes="true"
+     inkscape:snap-intersection-paths="true"
+     inkscape:snap-midpoints="true"
+     inkscape:object-paths="true"
+     inkscape:snap-object-midpoints="true"
+     inkscape:snap-bbox-midpoints="false"
+     inkscape:snap-center="true"
+     inkscape:snap-global="true"
+     inkscape:window-width="1920"
+     inkscape:window-height="1028"
+     inkscape:window-x="1912"
+     inkscape:window-y="-8"
+     inkscape:window-maximized="1"
+     inkscape:snap-nodes="false"
+     inkscape:snap-others="false"
+     inkscape:snap-grids="true"
+     fit-margin-top="10"
+     fit-margin-left="10"
+     fit-margin-right="10"
+     fit-margin-bottom="10"
+     units="px">
+    <inkscape:grid
+       originy="-179.99988"
+       originx="-1620"
+       visible="true"
+       empspacing="1"
+       spacingy="10"
+       spacingx="9.9999999"
+       dotted="false"
+       id="grid6826"
+       type="xygrid" />
+  </sodipodi:namedview>
+  <title
+     id="title7860">OpenCV video I/O Structure</title>
+  <defs
+     id="defs4" />
+  <metadata
+     id="metadata7">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title>OpenCV video I/O Structure</dc:title>
+        <cc:license
+           rdf:resource="http://creativecommons.org/licenses/by/3.0/" />
+        <dc:creator>
+          <cc:Agent>
+            <dc:title>PkLab.net</dc:title>
+          </cc:Agent>
+        </dc:creator>
+        <dc:language>English</dc:language>
+        <dc:subject>
+          <rdf:Bag>
+            <rdf:li>OpenCV</rdf:li>
+            <rdf:li>Video I/O</rdf:li>
+          </rdf:Bag>
+        </dc:subject>
+        <dc:description />
+      </cc:Work>
+      <cc:License
+         rdf:about="http://creativecommons.org/licenses/by/3.0/">
+        <cc:permits
+           rdf:resource="http://creativecommons.org/ns#Reproduction" />
+        <cc:permits
+           rdf:resource="http://creativecommons.org/ns#Distribution" />
+        <cc:requires
+           rdf:resource="http://creativecommons.org/ns#Notice" />
+        <cc:requires
+           rdf:resource="http://creativecommons.org/ns#Attribution" />
+        <cc:permits
+           rdf:resource="http://creativecommons.org/ns#DerivativeWorks" />
+      </cc:License>
+    </rdf:RDF>
+  </metadata>
+  <g
+     transform="translate(-1620.0001,-352.36227)"
+     id="layer1"
+     inkscape:groupmode="layer"
+     inkscape:label="Layer 1">
+    <rect
+       ry="10"
+       rx="10"
+       y="372.86224"
+       x="1640.5001"
+       height="79"
+       width="518.99982"
+       id="rect4136-9-7"
+       style="fill:#9aba59;fill-opacity:1;stroke:#6f00c7;stroke-width:1.00000012;stroke-miterlimit:4;stroke-dasharray:1.00000003, 1.00000003;stroke-dashoffset:0;stroke-opacity:1" />
+    <rect
+       ry="10"
+       rx="10"
+       y="402.86224"
+       x="1820.5001"
+       height="39"
+       width="99"
+       id="rect4615-2-7-5-2-1-4-4-6"
+       style="fill:#809f41;fill-opacity:1;stroke:#000000;stroke-width:0.99999994;stroke-miterlimit:4;stroke-dasharray:2.99999982, 2.99999982;stroke-dashoffset:0;stroke-opacity:1" />
+    <rect
+       ry="10"
+       rx="10"
+       y="772.86224"
+       x="1640.5001"
+       height="79"
+       width="519"
+       id="rect4136-8-5-3-3-3"
+       style="fill:#cccccc;fill-opacity:1;stroke:#6f00c7;stroke-width:0.99999994;stroke-miterlimit:4;stroke-dasharray:1.00000001, 1.00000001;stroke-dashoffset:0;stroke-opacity:1" />
+    <text
+       sodipodi:linespacing="125%"
+       id="text5457-0-7-9"
+       y="792.29303"
+       x="1899.3917"
+       style="font-style:normal;font-weight:normal;font-size:15px;line-height:125%;font-family:Verdana;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       xml:space="preserve"
+       transform="scale(1.0001622,0.99983783)"><tspan
+         style="font-size:15px"
+         y="792.29303"
+         x="1899.3917"
+         id="tspan5459-7-2-3"
+         sodipodi:role="line">MEDIA DEVICES</tspan></text>
+    <rect
+       ry="10"
+       rx="10"
+       y="682.86224"
+       x="1640.5001"
+       height="79"
+       width="519"
+       id="rect4136-8-5-3-8"
+       style="fill:#ffb380;fill-opacity:1;stroke:#6f00c7;stroke-width:0.99999994;stroke-miterlimit:4;stroke-dasharray:1.00000003, 1.00000003;stroke-dashoffset:0;stroke-opacity:1" />
+    <text
+       sodipodi:linespacing="125%"
+       id="text5457-0-6"
+       y="702.27844"
+       x="1899.941"
+       style="font-style:normal;font-weight:normal;font-size:15px;line-height:125%;font-family:Verdana;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       xml:space="preserve"
+       transform="scale(1.0001622,0.99983783)"><tspan
+         style="font-size:15px"
+         y="702.27844"
+         x="1899.941"
+         id="tspan5459-7-3"
+         sodipodi:role="line">SYSTEM</tspan></text>
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-weight:normal;font-size:17.5px;line-height:125%;font-family:Verdana;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="1330.3986"
+       y="308.75192"
+       id="text5748"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan5750"
+         x="1330.3986"
+         y="308.75192" /></text>
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-weight:normal;font-size:17.5px;line-height:125%;font-family:Verdana;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="1330.3986"
+       y="308.75192"
+       id="text5752"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan5754"
+         x="1330.3986"
+         y="308.75192" /></text>
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-weight:normal;font-size:17.5px;line-height:125%;font-family:Verdana;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="1490.257"
+       y="308.75192"
+       id="text5748-3"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan5750-9"
+         x="1490.257"
+         y="308.75192" /></text>
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-weight:normal;font-size:17.5px;line-height:125%;font-family:Verdana;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="1490.257"
+       y="308.75192"
+       id="text5752-1"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan5754-8"
+         x="1490.257"
+         y="308.75192" /></text>
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-weight:normal;font-size:17.5px;line-height:125%;font-family:Verdana;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="1170.5402"
+       y="308.75192"
+       id="text5748-3-9"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan5750-9-4"
+         x="1170.5402"
+         y="308.75192" /></text>
+    <text
+       xml:space="preserve"
+       style="font-style:normal;font-weight:normal;font-size:17.5px;line-height:125%;font-family:Verdana;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       x="1170.5402"
+       y="308.75192"
+       id="text5752-1-5"
+       sodipodi:linespacing="125%"><tspan
+         sodipodi:role="line"
+         id="tspan5754-8-4"
+         x="1170.5402"
+         y="308.75192" /></text>
+    <text
+       transform="scale(0.96032163,1.0413178)"
+       sodipodi:linespacing="125%"
+       id="text4165-3-0"
+       y="376.56689"
+       x="1978.5697"
+       style="font-style:normal;font-weight:normal;font-size:15px;line-height:125%;font-family:Verdana;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       xml:space="preserve"><tspan
+         y="376.56689"
+         x="1978.5697"
+         id="tspan4167-5-0"
+         sodipodi:role="line"
+         style="font-size:15px;text-align:center;text-anchor:middle">USER APPLICATION</tspan></text>
+    <rect
+       ry="10"
+       rx="10"
+       y="462.86221"
+       x="1820.5001"
+       height="209"
+       width="339"
+       id="rect4136-8-4-82-8"
+       style="fill:#80b3ff;fill-opacity:1;stroke:#6f00c7;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:0.99999996, 0.99999996;stroke-dashoffset:0;stroke-opacity:1" />
+    <text
+       sodipodi:linespacing="125%"
+       id="text4577-6-1"
+       y="478.42764"
+       x="2061.6013"
+       style="font-style:normal;font-weight:normal;font-size:15px;line-height:125%;font-family:Verdana;text-align:end;letter-spacing:0px;word-spacing:0px;text-anchor:end;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       xml:space="preserve"
+       transform="scale(1.0001622,0.99983783)"><tspan
+         style="font-size:15px"
+         id="tspan4581-0-0"
+         y="478.42764"
+         x="2061.6013"
+         sodipodi:role="line">OpenCV Video I/O</tspan></text>
+    <path
+       inkscape:connector-curvature="0"
+       id="path4789-4-4"
+       d="m 1820.0815,567.77306 340,0"
+       style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:1.99999991, 0.99999995;stroke-dashoffset:0;stroke-opacity:1" />
+    <text
+       transform="scale(1.0001622,0.99983783)"
+       sodipodi:linespacing="125%"
+       id="text4577-9-3-2"
+       y="581.95209"
+       x="1990.1963"
+       style="font-style:normal;font-weight:normal;font-size:12.5px;line-height:125%;font-family:Verdana;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       xml:space="preserve"><tspan
+         id="tspan4581-2-5-1"
+         y="581.95209"
+         x="1990.1963"
+         sodipodi:role="line">OpenCV Video I/O API Backends</tspan></text>
+    <rect
+       ry="5"
+       rx="5"
+       y="592.86224"
+       x="1913.8334"
+       height="29.000002"
+       width="69"
+       id="rect4615-4-6-4"
+       style="fill:#999999;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+    <text
+       sodipodi:linespacing="125%"
+       id="text4363-9-4"
+       y="612.11469"
+       x="1947.6696"
+       style="font-style:normal;font-weight:normal;font-size:12.5px;line-height:125%;font-family:Verdana;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#4d4d4d;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       xml:space="preserve"
+       transform="scale(1.0001622,0.99983783)"><tspan
+         y="612.11469"
+         x="1947.6696"
+         id="tspan4365-0-2"
+         sodipodi:role="line">DShow</tspan></text>
+    <rect
+       ry="5"
+       rx="5"
+       y="592.86224"
+       x="2080.5"
+       height="29.000002"
+       width="69"
+       id="rect4615-5-7-0"
+       style="fill:#999999;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+    <text
+       sodipodi:linespacing="125%"
+       id="text4363-6-1-4"
+       y="612.00482"
+       x="2114.123"
+       style="font-style:normal;font-weight:normal;font-size:12.5px;line-height:125%;font-family:Verdana;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#4d4d4d;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       xml:space="preserve"
+       transform="scale(1.0001622,0.99983783)"><tspan
+         y="612.00482"
+         x="2114.123"
+         id="tspan4365-8-0-4"
+         sodipodi:role="line">MSMF</tspan></text>
+    <rect
+       ry="5"
+       rx="5"
+       y="592.86224"
+       x="1830.5001"
+       height="29"
+       width="69"
+       id="rect4615-11-0"
+       style="fill:#999999;fill-opacity:1;stroke:#000000;stroke-width:0.99999994;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+    <text
+       transform="scale(1.0001622,0.99983783)"
+       sodipodi:linespacing="125%"
+       id="text4363-5-6-4"
+       y="611.99872"
+       x="1864.5328"
+       style="font-style:normal;font-weight:normal;font-size:12.5px;line-height:125%;font-family:Verdana;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#4d4d4d;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       xml:space="preserve"><tspan
+         y="611.99872"
+         x="1864.5328"
+         id="tspan4365-6-9-6"
+         sodipodi:role="line">FFMPEG</tspan></text>
+    <rect
+       ry="5"
+       rx="5"
+       y="632.79645"
+       x="1913.8334"
+       height="29"
+       width="69"
+       id="rect4615-94-7-1"
+       style="fill:#999999;fill-opacity:1;stroke:#000000;stroke-width:0.99999988;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+    <text
+       sodipodi:linespacing="125%"
+       id="text4363-4-8-8"
+       y="651.9455"
+       x="1947.932"
+       style="font-style:normal;font-weight:normal;font-size:12.5px;line-height:125%;font-family:Verdana;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#4d4d4d;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       xml:space="preserve"
+       transform="scale(1.0001622,0.99983783)"><tspan
+         y="651.9455"
+         x="1947.932"
+         id="tspan4365-7-09-1"
+         sodipodi:role="line">V4L</tspan></text>
+    <rect
+       ry="5"
+       rx="5"
+       y="592.86224"
+       x="1997.1666"
+       height="29.000002"
+       width="69"
+       id="rect4615-9-6-4"
+       style="fill:#999999;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+    <text
+       sodipodi:linespacing="125%"
+       id="text4363-7-5-3"
+       y="612.00482"
+       x="2031.5355"
+       style="font-style:normal;font-weight:normal;font-size:12.5px;line-height:125%;font-family:Verdana;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#4d4d4d;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       xml:space="preserve"
+       transform="scale(1.0001622,0.99983783)"><tspan
+         y="612.00482"
+         x="2031.5355"
+         id="tspan4365-9-0-9"
+         sodipodi:role="line">VFW</tspan></text>
+    <rect
+       ry="5"
+       rx="5"
+       y="632.79645"
+       x="1830.5001"
+       height="29"
+       width="69"
+       id="rect4615-0-7-6"
+       style="fill:#999999;fill-opacity:1;stroke:#000000;stroke-width:0.99999988;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+    <text
+       sodipodi:linespacing="125%"
+       id="text4363-4-6-1-7"
+       y="651.22223"
+       x="1864.9784"
+       style="font-style:normal;font-weight:normal;font-size:12.5px;line-height:125%;font-family:Verdana;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#4d4d4d;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       xml:space="preserve"
+       transform="scale(1.0001622,0.99983783)"><tspan
+         y="651.22223"
+         x="1864.9784"
+         id="tspan4365-7-0-4-1"
+         sodipodi:role="line">AVF/IOS</tspan></text>
+    <rect
+       ry="5"
+       rx="5"
+       y="632.79645"
+       x="2080.5"
+       height="29"
+       width="69"
+       id="rect4615-1-2-1"
+       style="fill:#999999;fill-opacity:1;stroke:#000000;stroke-width:0.99999988;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+    <text
+       sodipodi:linespacing="125%"
+       id="text4363-4-6-7-6-2"
+       y="651.71051"
+       x="2115.1025"
+       style="font-style:normal;font-weight:normal;font-size:12.5px;line-height:125%;font-family:Verdana;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#4d4d4d;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       xml:space="preserve"
+       transform="scale(1.0001622,0.99983783)"><tspan
+         y="651.71051"
+         x="2115.1025"
+         id="tspan4365-7-0-1-8-6"
+         sodipodi:role="line">etc...</tspan></text>
+    <rect
+       ry="5"
+       rx="5"
+       y="632.79645"
+       x="1997.1666"
+       height="29"
+       width="69"
+       id="rect4615-6-6-4"
+       style="fill:#999999;fill-opacity:1;stroke:#000000;stroke-width:0.99999988;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+    <text
+       sodipodi:linespacing="125%"
+       id="text4409-2-7"
+       y="651.9455"
+       x="2031.4104"
+       style="font-style:normal;font-weight:normal;font-size:12.5px;line-height:125%;font-family:Verdana;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#4d4d4d;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       xml:space="preserve"
+       transform="scale(1.0001622,0.99983783)"><tspan
+         y="651.9455"
+         x="2031.4104"
+         id="tspan4411-9-8"
+         sodipodi:role="line">OPENNI</tspan></text>
+    <rect
+       ry="10"
+       rx="10"
+       y="462.86221"
+       x="1640.5001"
+       height="209"
+       width="169"
+       id="rect4136-8-4-8-3-9"
+       style="fill:#e9afaf;fill-opacity:1;stroke:#6f00c7;stroke-width:0.99999964;stroke-miterlimit:4;stroke-dasharray:1.00000002, 1.00000002;stroke-dashoffset:0;stroke-opacity:1" />
+    <text
+       transform="scale(1.0001622,0.99983783)"
+       sodipodi:linespacing="125%"
+       id="text4577-8-4-3"
+       y="479.85953"
+       x="1723.9659"
+       style="font-style:normal;font-weight:normal;font-size:15px;line-height:125%;font-family:Verdana;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       xml:space="preserve"><tspan
+         style="font-size:15px;text-align:center;text-anchor:middle"
+         id="tspan4581-5-1-7"
+         y="479.85953"
+         x="1723.9659"
+         sodipodi:role="line">Manufacturer Driver</tspan></text>
+    <rect
+       ry="10"
+       rx="10"
+       y="557.86224"
+       x="1650.5001"
+       height="39"
+       width="149"
+       id="rect4615-2-7-1-9"
+       style="fill:#d35f5f;fill-opacity:1;stroke:#000000;stroke-width:0.99999982;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+    <text
+       sodipodi:linespacing="125%"
+       id="text4363-5-2-2-8-9"
+       y="581.27667"
+       x="1724.7936"
+       style="font-style:normal;font-weight:normal;font-size:12.5px;line-height:125%;font-family:Verdana;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       xml:space="preserve"
+       transform="scale(1.0001622,0.99983783)"><tspan
+         y="581.27667"
+         x="1724.7936"
+         id="tspan4365-6-3-6-7-2"
+         sodipodi:role="line">C / C++ / JAVA API</tspan></text>
+    <rect
+       ry="10"
+       rx="10"
+       y="402.86224"
+       x="1665.5001"
+       height="39"
+       width="119"
+       id="rect4615-2-7-5-2-0"
+       style="fill:#809f41;fill-opacity:1;stroke:#000000;stroke-width:0.99999994;stroke-miterlimit:4;stroke-dasharray:2.99999982, 2.99999982;stroke-dashoffset:0;stroke-opacity:1" />
+    <text
+       sodipodi:linespacing="125%"
+       id="text4363-5-2-2-7-3-4"
+       y="419.3027"
+       x="1724.9401"
+       style="font-style:normal;font-weight:normal;font-size:12.5px;line-height:125%;font-family:Verdana;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       xml:space="preserve"
+       transform="scale(1.0001622,0.99983783)"><tspan
+         y="419.3027"
+         x="1724.9401"
+         id="tspan4365-6-3-6-2-2-2"
+         sodipodi:role="line"
+         style="font-size:12.5px;text-align:center;text-anchor:middle">cv::Mat from</tspan><tspan
+         y="434.9277"
+         x="1724.9401"
+         sodipodi:role="line"
+         id="tspan5401-7-0"
+         style="font-size:12.5px;text-align:center;text-anchor:middle">buffer</tspan></text>
+    <rect
+       ry="10"
+       rx="10"
+       y="712.86224"
+       x="1650.5001"
+       height="39"
+       width="149"
+       id="rect4615-2-7-0-6-8"
+       style="fill:#d35f5f;fill-opacity:1;stroke:#000000;stroke-width:0.99999994;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+    <text
+       sodipodi:linespacing="125%"
+       id="text4363-5-2-2-6-5-7"
+       y="728.19025"
+       x="1724.0917"
+       style="font-style:normal;font-weight:normal;font-size:12.5px;line-height:125%;font-family:Verdana;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       xml:space="preserve"
+       transform="scale(1.0001622,0.99983783)"><tspan
+         y="728.19025"
+         x="1724.0917"
+         id="tspan4365-6-3-6-6-1-0"
+         sodipodi:role="line"
+         style="font-size:12.5px;text-align:center;text-anchor:middle">Manufacturer</tspan><tspan
+         y="743.81525"
+         x="1724.0917"
+         sodipodi:role="line"
+         id="tspan5372-4-1">Library</tspan></text>
+    <rect
+       ry="10"
+       rx="10"
+       y="712.86224"
+       x="1825.5001"
+       height="39"
+       width="99"
+       id="rect4615-2-7-0-2-8-7"
+       style="fill:#c87137;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+    <text
+       sodipodi:linespacing="125%"
+       id="text4363-5-2-2-6-7-2-5"
+       y="729.32245"
+       x="1874.3451"
+       style="font-style:normal;font-weight:normal;font-size:12.5px;line-height:125%;font-family:Verdana;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       xml:space="preserve"
+       transform="scale(1.0001622,0.99983783)"><tspan
+         y="729.32245"
+         x="1874.3451"
+         id="tspan4365-6-3-6-6-8-7-6"
+         sodipodi:role="line"
+         style="font-size:12.5px;text-align:center;text-anchor:middle;fill:#ffffff">Backends</tspan><tspan
+         y="744.94745"
+         x="1874.3451"
+         sodipodi:role="line"
+         id="tspan5372-3-26-8">Libraries</tspan></text>
+    <rect
+       ry="10"
+       rx="10"
+       y="712.86224"
+       x="2050.5"
+       height="39"
+       width="99.000038"
+       id="rect4615-2-7-0-2-5-1-6"
+       style="fill:#c87137;fill-opacity:1;stroke:#000000;stroke-width:0.99999994;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+    <text
+       sodipodi:linespacing="125%"
+       id="text4363-5-2-2-6-7-1-6-4"
+       y="729.21259"
+       x="2099.3086"
+       style="font-style:normal;font-weight:normal;font-size:12.5px;line-height:125%;font-family:Verdana;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       xml:space="preserve"
+       transform="scale(1.0001622,0.99983783)"><tspan
+         y="729.21259"
+         x="2099.3086"
+         id="tspan4365-6-3-6-6-8-6-5-6"
+         sodipodi:role="line"
+         style="font-size:12.5px;text-align:center;text-anchor:middle;fill:#ffffff">O.S.</tspan><tspan
+         y="744.83759"
+         x="2099.3086"
+         sodipodi:role="line"
+         id="tspan5372-3-2-4-8">Libraries</tspan></text>
+    <rect
+       ry="10"
+       rx="10"
+       y="402.86224"
+       x="1935.5"
+       height="39"
+       width="99"
+       id="rect4615-2-7-5-2-1-2"
+       style="fill:#809f41;fill-opacity:1;stroke:#000000;stroke-width:0.99999994;stroke-miterlimit:4;stroke-dasharray:2.99999982, 2.99999982;stroke-dashoffset:0;stroke-opacity:1" />
+    <rect
+       ry="10"
+       rx="10"
+       y="402.86224"
+       x="2050.5"
+       height="39"
+       width="99"
+       id="rect4615-2-7-5-2-1-4-8"
+       style="fill:#809f41;fill-opacity:1;stroke:#000000;stroke-width:0.99999994;stroke-miterlimit:4;stroke-dasharray:2.99999982, 2.99999982;stroke-dashoffset:0;stroke-opacity:1" />
+    <text
+       sodipodi:linespacing="125%"
+       id="text4363-5-2-2-7-3-0-1-3"
+       y="423.06659"
+       x="1961.3533"
+       style="font-style:normal;font-weight:normal;font-size:12.5px;line-height:125%;font-family:Verdana;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       xml:space="preserve"
+       transform="scale(1.0118989,0.98824102)"><tspan
+         y="423.06659"
+         x="1961.3533"
+         id="tspan4365-6-3-6-2-2-1-7-5"
+         sodipodi:role="line"
+         style="font-size:12.5px;text-align:center;text-anchor:middle">set / get</tspan><tspan
+         y="438.69159"
+         x="1961.3533"
+         sodipodi:role="line"
+         id="tspan5401-7-6-4-7"
+         style="font-size:12.5px;text-align:center;text-anchor:middle">properties</tspan></text>
+    <text
+       sodipodi:linespacing="125%"
+       id="text4363-5-2-2-7-3-0-1-4-5"
+       y="419.27219"
+       x="2099.635"
+       style="font-style:normal;font-weight:normal;font-size:12.5px;line-height:125%;font-family:Verdana;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       xml:space="preserve"
+       transform="scale(1.0001622,0.99983783)"><tspan
+         y="419.27219"
+         x="2099.635"
+         id="tspan4365-6-3-6-2-2-1-7-4-3"
+         sodipodi:role="line"
+         style="font-size:12.5px;text-align:center;text-anchor:middle">grab / write</tspan><tspan
+         y="434.89719"
+         x="2099.635"
+         sodipodi:role="line"
+         id="tspan5401-7-6-4-3-2"
+         style="font-size:12.5px;text-align:center;text-anchor:middle">frame</tspan></text>
+    <rect
+       ry="10"
+       rx="10"
+       y="802.86224"
+       x="1650.5001"
+       height="39"
+       width="149"
+       id="rect4615-2-7-0-6-6-5"
+       style="fill:#4d4d4d;fill-opacity:1;stroke:#000000;stroke-width:0.99999994;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+    <text
+       sodipodi:linespacing="125%"
+       id="text4363-5-2-2-6-5-2-08"
+       y="827.02747"
+       x="1724.9156"
+       style="font-style:normal;font-weight:normal;font-size:12.5px;line-height:125%;font-family:Verdana;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       xml:space="preserve"
+       transform="scale(1.0001622,0.99983783)"><tspan
+         y="827.02747"
+         x="1724.9156"
+         sodipodi:role="line"
+         id="tspan5372-4-2-73">Camera</tspan></text>
+    <rect
+       ry="10"
+       rx="10"
+       y="802.86224"
+       x="1825.5001"
+       height="39"
+       width="149"
+       id="rect4615-2-7-0-6-6-4-6"
+       style="fill:#4d4d4d;fill-opacity:1;stroke:#000000;stroke-width:0.99999994;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+    <text
+       sodipodi:linespacing="125%"
+       id="text4363-5-2-2-6-5-2-0-1"
+       y="827.14954"
+       x="1899.9178"
+       style="font-style:normal;font-weight:normal;font-size:12.5px;line-height:125%;font-family:Verdana;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       xml:space="preserve"
+       transform="scale(1.0001622,0.99983783)"><tspan
+         y="827.14954"
+         x="1899.9178"
+         sodipodi:role="line"
+         id="tspan5372-4-2-7-0">Video File</tspan></text>
+    <rect
+       ry="10"
+       rx="10"
+       y="802.86224"
+       x="2000.5001"
+       height="39"
+       width="149"
+       id="rect4615-2-7-0-6-6-6-6"
+       style="fill:#4d4d4d;fill-opacity:1;stroke:#000000;stroke-width:0.99999994;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+    <text
+       sodipodi:linespacing="125%"
+       id="text4363-5-2-2-6-5-2-03-1"
+       y="827.14954"
+       x="2074.5935"
+       style="font-style:normal;font-weight:normal;font-size:12.5px;line-height:125%;font-family:Verdana;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       xml:space="preserve"
+       transform="scale(1.0001622,0.99983783)"><tspan
+         y="827.14954"
+         x="2074.5935"
+         sodipodi:role="line"
+         id="tspan5372-4-2-6-7">Network Stream</tspan></text>
+    <rect
+       style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+       id="rect8223"
+       width="538.99994"
+       height="499.00003"
+       x="1630.5001"
+       y="362.86227"
+       rx="10"
+       ry="10" />
+    <text
+       sodipodi:linespacing="125%"
+       id="text4363-5-2-2-7-3-0-2"
+       y="419.27219"
+       x="1869.9166"
+       style="font-style:normal;font-weight:normal;font-size:12.5px;line-height:125%;font-family:Verdana;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       xml:space="preserve"
+       transform="scale(1.0001622,0.99983783)"><tspan
+         y="419.27219"
+         x="1869.9166"
+         id="tspan4365-6-3-6-2-2-1-2"
+         sodipodi:role="line"
+         style="font-size:12.5px;text-align:center;text-anchor:middle">create / open</tspan><tspan
+         y="434.89719"
+         x="1869.9166"
+         sodipodi:role="line"
+         id="tspan5401-7-6-8"
+         style="font-size:12.5px;text-align:center;text-anchor:middle">device</tspan></text>
+    <rect
+       ry="10"
+       rx="10"
+       y="712.86224"
+       x="1938"
+       height="39"
+       width="99"
+       id="rect4615-2-7-0-2-8-7-8"
+       style="fill:#c87137;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+    <text
+       sodipodi:linespacing="125%"
+       id="text4363-5-2-2-6-7-2-5-2"
+       y="729.32245"
+       x="1986.8268"
+       style="font-style:normal;font-weight:normal;font-size:12.5px;line-height:125%;font-family:Verdana;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       xml:space="preserve"
+       transform="scale(1.0001622,0.99983783)"><tspan
+         y="729.32245"
+         x="1986.8268"
+         sodipodi:role="line"
+         id="tspan5372-3-26-8-5">CODECS</tspan><tspan
+         y="744.94745"
+         x="1986.8268"
+         sodipodi:role="line"
+         id="tspan4295">(fourcc)</tspan></text>
+    <rect
+       ry="10"
+       rx="9.3800001"
+       y="507.86713"
+       x="1841.6537"
+       height="43.995113"
+       width="90.999962"
+       id="rect4615-2-8-4-2"
+       style="fill:#6b98c9;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:1, 1;stroke-dashoffset:0;stroke-opacity:1" />
+    <rect
+       ry="10"
+       rx="9.3800011"
+       y="507.86713"
+       x="1945.6538"
+       height="43.995113"
+       width="198.99985"
+       id="rect4615-2-8-4-2-4"
+       style="fill:#6b98c9;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:1, 1;stroke-dashoffset:0;stroke-opacity:1" />
+    <rect
+       ry="10"
+       rx="9.3800001"
+       y="483.86713"
+       x="1833.6537"
+       height="29"
+       width="149"
+       id="rect4615-2-8-4"
+       style="fill:#4d82be;fill-opacity:1;stroke:#000000;stroke-width:0.99999988;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+    <text
+       sodipodi:linespacing="125%"
+       id="text4363-5-2-3-3"
+       y="501.93918"
+       x="1908.0701"
+       style="font-style:normal;font-weight:normal;font-size:12.5px;line-height:125%;font-family:Verdana;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       xml:space="preserve"
+       transform="scale(1.0001622,0.99983783)"><tspan
+         y="501.93918"
+         x="1908.0701"
+         id="tspan4365-6-3-90-7"
+         sodipodi:role="line">VideoCapture</tspan></text>
+    <rect
+       ry="10"
+       rx="9.3800001"
+       y="483.86713"
+       x="2003.6537"
+       height="29"
+       width="149"
+       id="rect4615-2-9-5-7"
+       style="fill:#4d82be;fill-opacity:1;stroke:#000000;stroke-width:0.99999982;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
+    <text
+       sodipodi:linespacing="125%"
+       id="text4363-5-2-8-1-8"
+       y="503.1019"
+       x="2077.719"
+       style="font-style:normal;font-weight:normal;font-size:12.5px;line-height:125%;font-family:Verdana;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       xml:space="preserve"
+       transform="scale(1.0001622,0.99983783)"><tspan
+         y="503.1019"
+         x="2077.719"
+         id="tspan4365-6-3-9-0-6"
+         sodipodi:role="line">VideoWriter</tspan></text>
+    <text
+       sodipodi:linespacing="125%"
+       id="text4363-5-2-3-3-4"
+       y="534.48248"
+       x="1887.043"
+       style="font-style:normal;font-weight:normal;font-size:12.5px;line-height:125%;font-family:Verdana;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       xml:space="preserve"
+       transform="scale(1.0001622,0.99983783)"><tspan
+         y="534.48248"
+         x="1887.043"
+         id="tspan4365-6-3-90-7-2"
+         sodipodi:role="line">Camera</tspan></text>
+    <text
+       sodipodi:linespacing="125%"
+       id="text4363-5-2-3-3-6"
+       y="526.79205"
+       x="2044.752"
+       style="font-style:normal;font-weight:normal;font-size:12.5px;line-height:125%;font-family:Verdana;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       xml:space="preserve"
+       transform="scale(1.0001622,0.99983783)"><tspan
+         y="526.79205"
+         x="2044.752"
+         sodipodi:role="line"
+         id="tspan4367">File or URL stream</tspan><tspan
+         y="542.41705"
+         x="2044.752"
+         sodipodi:role="line"
+         id="tspan4371">+ fourcc codec</tspan></text>
+  </g>
+</svg>
diff --git a/modules/videoio/doc/videoio_overview.markdown b/modules/videoio/doc/videoio_overview.markdown
new file mode 100644
index 0000000..b96d060
--- /dev/null
+++ b/modules/videoio/doc/videoio_overview.markdown
@@ -0,0 +1,94 @@
+Video I/O with OpenCV Overview {#videoio_overview}
+===================================
+
+### See also:
+  - @ref videoio "Video I/O Code Reference"
+  - Tutorials: @ref tutorial_table_of_content_videoio
+
+General Information
+===================
+
+The OpenCV @ref videoio module is a set of classes and functions to read and write video or images sequence.
+
+Basically, the module provides the cv::VideoCapture and cv::VideoWriter classes as 2-layer interface to many video
+I/O APIs used as backend.
+
+![Video I/O with OpenCV](pics/videoio_overview.svg)
+
+Some backends such as (DSHOW) Direct Show, Video For Windows (VFW), Microsoft Media Foundation (MSMF),
+Video 4 Linux (V4L), etc... are interfaces to the video I/O library provided by the operating system.
+
+Some others backends like OpenNI2 for Kinect, Intel Perceptual Computing SDK, GStreamer,
+XIMEA Camera API, etc...  are interfaces to proprietary drivers or to external library.
+
+See the list of supported backends here: cv::VideoCaptureAPIs
+
+ at warning Some backends are experimental use them at your own risk
+ at note Each backend supports devices properties (cv::VideoCaptureProperties) in a different way or might not support any property at all.
+
+
+Select the backend at runtime
+-----------------------------
+
+OpenCV automatically selects and uses first available backend (`apiPreference=cv::CAP_ANY`).
+
+As advanced usage you can select the backend to use at runtime. Currently this option is
+available only with %VideoCapture.
+
+For example to grab from default camera using Direct Show as backend
+
+```cpp
+//declare a capture object
+cv::VideoCapture cap(0 + cv::CAP_DSHOW);
+
+//or specify the apiPreference with open
+cap.open(0 + cv::CAP_DSHOW);
+```
+
+If you want to grab from a file using the Direct Show as backend:
+
+```cpp
+//declare a capture object
+cv::VideoCapture cap(filename, cv::CAP_DSHOW);
+
+//or specify the apiPreference with open
+cap.open(filename, cv::CAP_DSHOW);
+```
+
+ at sa cv::VideoCapture::open() , cv::VideoCapture::VideoCapture()
+
+#### Enable backends
+
+Backends are available only if they have been built with your OpenCV binaries.
+
+Check in `opencv2/cvconfig.h` to know which APIs are currently available
+(e.g. `HAVE_MSMF, HAVE_VFW, HAVE_LIBV4L`, etc...).
+
+To enable/disable APIs, you have to:
+  1. re-configure OpenCV using appropriates CMake switches
+     (e.g. `-DWITH_MSMF=ON -DWITH_VFW=ON ... `) or checking related switch in cmake-gui
+  2. rebuild OpenCV itself
+
+#### Use 3rd party drivers or cameras
+
+Many industrial cameras or some video I/O devices don't provide standard driver interfaces
+for the operating system. Thus you can't use  VideoCapture or VideoWriter with these devices.
+
+To get access to their devices, manufactures provide their own C++ API and library that you have to
+include and link with your OpenCV application.
+
+Is common case that this libraries read/write images from/to a memory buffer. If it so, it is
+possible to make a `Mat` header for memory buffer (user-allocated data) and process it
+in-place using OpenCV functions. See cv::Mat::Mat() for more details.
+
+The FFmpeg library
+------------------
+
+OpenCV can use the FFmpeg library (http://ffmpeg.org/) as backend to record, convert and stream audio and video.
+FFMpeg is a complete, cross-reference solution. If you enable FFmpeg while configuring OpenCV than
+CMake will download and install the binaries in `OPENCV_SOURCE_CODE/3rdparty/ffmpeg/`. To use
+FFMpeg at runtime, you must deploy the FFMepg binaries with your application.
+
+ at note FFmpeg is licensed under the GNU Lesser General Public License (LGPL) version 2.1 or later.
+See `OPENCV_SOURCE_CODE/3rdparty/ffmpeg/readme.txt` and http://ffmpeg.org/legal.html for details and
+licensing information
diff --git a/modules/videoio/include/opencv2/videoio.hpp b/modules/videoio/include/opencv2/videoio.hpp
index ccd6c06..458e63d 100644
--- a/modules/videoio/include/opencv2/videoio.hpp
+++ b/modules/videoio/include/opencv2/videoio.hpp
@@ -40,17 +40,25 @@
 //
 //M*/
 
-#ifndef __OPENCV_VIDEOIO_HPP__
-#define __OPENCV_VIDEOIO_HPP__
+#ifndef OPENCV_VIDEOIO_HPP
+#define OPENCV_VIDEOIO_HPP
 
 #include "opencv2/core.hpp"
 
 /**
-  @defgroup videoio Media I/O
+  @defgroup videoio Video I/O
+
+  @brief Read and write video or images sequence with OpenCV
+
+  ### See also:
+  - @ref videoio_overview
+  - Tutorials: @ref tutorial_table_of_content_videoio
   @{
-    @defgroup videoio_c C API
-    @defgroup videoio_ios iOS glue
-    @defgroup videoio_winrt WinRT glue
+    @defgroup videoio_flags_base Flags for video I/O
+    @defgroup videoio_flags_others Additional flags for video I/O API backends
+    @defgroup videoio_c C API for video I/O
+    @defgroup videoio_ios iOS glue for video I/O
+    @defgroup videoio_winrt WinRT glue for video I/O
   @}
 */
 
@@ -65,60 +73,76 @@ namespace cv
 //! @addtogroup videoio
 //! @{
 
-// Camera API
-enum { CAP_ANY          = 0,     // autodetect
-       CAP_VFW          = 200,   // platform native
-       CAP_V4L          = 200,
-       CAP_V4L2         = CAP_V4L,
-       CAP_FIREWARE     = 300,   // IEEE 1394 drivers
-       CAP_FIREWIRE     = CAP_FIREWARE,
-       CAP_IEEE1394     = CAP_FIREWARE,
-       CAP_DC1394       = CAP_FIREWARE,
-       CAP_CMU1394      = CAP_FIREWARE,
-       CAP_QT           = 500,   // QuickTime
-       CAP_UNICAP       = 600,   // Unicap drivers
-       CAP_DSHOW        = 700,   // DirectShow (via videoInput)
-       CAP_PVAPI        = 800,   // PvAPI, Prosilica GigE SDK
-       CAP_OPENNI       = 900,   // OpenNI (for Kinect)
-       CAP_OPENNI_ASUS  = 910,   // OpenNI (for Asus Xtion)
-       CAP_ANDROID      = 1000,  // Android - not used
-       CAP_XIAPI        = 1100,  // XIMEA Camera API
-       CAP_AVFOUNDATION = 1200,  // AVFoundation framework for iOS (OS X Lion will have the same API)
-       CAP_GIGANETIX    = 1300,  // Smartek Giganetix GigEVisionSDK
-       CAP_MSMF         = 1400,  // Microsoft Media Foundation (via videoInput)
-       CAP_WINRT        = 1410,  // Microsoft Windows Runtime using Media Foundation
-       CAP_INTELPERC    = 1500,  // Intel Perceptual Computing SDK
-       CAP_OPENNI2      = 1600,  // OpenNI2 (for Kinect)
-       CAP_OPENNI2_ASUS = 1610,  // OpenNI2 (for Asus Xtion and Occipital Structure sensors)
-       CAP_GPHOTO2      = 1700,  // gPhoto2 connection
-       CAP_GSTREAMER    = 1800,  // GStreamer
-       CAP_FFMPEG       = 1900,  // FFMPEG
-       CAP_IMAGES       = 2000   // OpenCV Image Sequence (e.g. img_%02d.jpg)
+//! @addtogroup videoio_flags_base
+//! @{
+
+
+/** @brief %VideoCapture API backends identifier.
+
+Select preferred API for a capture object.
+To be used in the VideoCapture::VideoCapture() constructor or VideoCapture::open()
+
+ at note Backends are available only if they have been built with your OpenCV binaries.
+See @ref videoio_overview for more information.
+*/
+enum VideoCaptureAPIs {
+       CAP_ANY          = 0,            //!< Auto detect == 0
+       CAP_VFW          = 200,          //!< Video For Windows (platform native)
+       CAP_V4L          = 200,          //!< V4L/V4L2 capturing support via libv4l
+       CAP_V4L2         = CAP_V4L,      //!< Same as CAP_V4L
+       CAP_FIREWIRE     = 300,          //!< IEEE 1394 drivers
+       CAP_FIREWARE     = CAP_FIREWIRE, //!< Same as CAP_FIREWIRE
+       CAP_IEEE1394     = CAP_FIREWIRE, //!< Same as CAP_FIREWIRE
+       CAP_DC1394       = CAP_FIREWIRE, //!< Same as CAP_FIREWIRE
+       CAP_CMU1394      = CAP_FIREWIRE, //!< Same as CAP_FIREWIRE
+       CAP_QT           = 500,          //!< QuickTime
+       CAP_UNICAP       = 600,          //!< Unicap drivers
+       CAP_DSHOW        = 700,          //!< DirectShow (via videoInput)
+       CAP_PVAPI        = 800,          //!< PvAPI, Prosilica GigE SDK
+       CAP_OPENNI       = 900,          //!< OpenNI (for Kinect)
+       CAP_OPENNI_ASUS  = 910,          //!< OpenNI (for Asus Xtion)
+       CAP_ANDROID      = 1000,         //!< Android - not used
+       CAP_XIAPI        = 1100,         //!< XIMEA Camera API
+       CAP_AVFOUNDATION = 1200,         //!< AVFoundation framework for iOS (OS X Lion will have the same API)
+       CAP_GIGANETIX    = 1300,         //!< Smartek Giganetix GigEVisionSDK
+       CAP_MSMF         = 1400,         //!< Microsoft Media Foundation (via videoInput)
+       CAP_WINRT        = 1410,         //!< Microsoft Windows Runtime using Media Foundation
+       CAP_INTELPERC    = 1500,         //!< Intel Perceptual Computing SDK
+       CAP_OPENNI2      = 1600,         //!< OpenNI2 (for Kinect)
+       CAP_OPENNI2_ASUS = 1610,         //!< OpenNI2 (for Asus Xtion and Occipital Structure sensors)
+       CAP_GPHOTO2      = 1700,         //!< gPhoto2 connection
+       CAP_GSTREAMER    = 1800,         //!< GStreamer
+       CAP_FFMPEG       = 1900,         //!< Open and record video file or stream using the FFMPEG library
+       CAP_IMAGES       = 2000,         //!< OpenCV Image Sequence (e.g. img_%02d.jpg)
+       CAP_ARAVIS       = 2100          //!< Aravis SDK
      };
 
-// generic properties (based on DC1394 properties)
-enum { CAP_PROP_POS_MSEC       =0,
-       CAP_PROP_POS_FRAMES     =1,
-       CAP_PROP_POS_AVI_RATIO  =2,
-       CAP_PROP_FRAME_WIDTH    =3,
-       CAP_PROP_FRAME_HEIGHT   =4,
-       CAP_PROP_FPS            =5,
-       CAP_PROP_FOURCC         =6,
-       CAP_PROP_FRAME_COUNT    =7,
-       CAP_PROP_FORMAT         =8,
-       CAP_PROP_MODE           =9,
-       CAP_PROP_BRIGHTNESS    =10,
-       CAP_PROP_CONTRAST      =11,
-       CAP_PROP_SATURATION    =12,
-       CAP_PROP_HUE           =13,
-       CAP_PROP_GAIN          =14,
-       CAP_PROP_EXPOSURE      =15,
-       CAP_PROP_CONVERT_RGB   =16,
-       CAP_PROP_WHITE_BALANCE_BLUE_U =17,
-       CAP_PROP_RECTIFICATION =18,
+/** @brief %VideoCapture generic properties identifier.
+ @sa videoio_flags_others, VideoCapture::get(), VideoCapture::set()
+*/
+enum VideoCaptureProperties {
+       CAP_PROP_POS_MSEC       =0, //!< Current position of the video file in milliseconds.
+       CAP_PROP_POS_FRAMES     =1, //!< 0-based index of the frame to be decoded/captured next.
+       CAP_PROP_POS_AVI_RATIO  =2, //!< Relative position of the video file: 0=start of the film, 1=end of the film.
+       CAP_PROP_FRAME_WIDTH    =3, //!< Width of the frames in the video stream.
+       CAP_PROP_FRAME_HEIGHT   =4, //!< Height of the frames in the video stream.
+       CAP_PROP_FPS            =5, //!< Frame rate.
+       CAP_PROP_FOURCC         =6, //!< 4-character code of codec. see VideoWriter::fourcc .
+       CAP_PROP_FRAME_COUNT    =7, //!< Number of frames in the video file.
+       CAP_PROP_FORMAT         =8, //!< Format of the %Mat objects returned by VideoCapture::retrieve().
+       CAP_PROP_MODE           =9, //!< Backend-specific value indicating the current capture mode.
+       CAP_PROP_BRIGHTNESS    =10, //!< Brightness of the image (only for cameras).
+       CAP_PROP_CONTRAST      =11, //!< Contrast of the image (only for cameras).
+       CAP_PROP_SATURATION    =12, //!< Saturation of the image (only for cameras).
+       CAP_PROP_HUE           =13, //!< Hue of the image (only for cameras).
+       CAP_PROP_GAIN          =14, //!< Gain of the image (only for cameras).
+       CAP_PROP_EXPOSURE      =15, //!< Exposure (only for cameras).
+       CAP_PROP_CONVERT_RGB   =16, //!< Boolean flags indicating whether images should be converted to RGB.
+       CAP_PROP_WHITE_BALANCE_BLUE_U =17, //!< Currently unsupported.
+       CAP_PROP_RECTIFICATION =18, //!< Rectification flag for stereo cameras (note: only supported by DC1394 v 2.x backend currently).
        CAP_PROP_MONOCHROME    =19,
        CAP_PROP_SHARPNESS     =20,
-       CAP_PROP_AUTO_EXPOSURE =21, // DC1394: exposure control done by camera, user can adjust refernce level using this feature
+       CAP_PROP_AUTO_EXPOSURE =21, //!< DC1394: exposure control done by camera, user can adjust reference level using this feature.
        CAP_PROP_GAMMA         =22,
        CAP_PROP_TEMPERATURE   =23,
        CAP_PROP_TRIGGER       =24,
@@ -133,46 +157,72 @@ enum { CAP_PROP_POS_MSEC       =0,
        CAP_PROP_TILT          =34,
        CAP_PROP_ROLL          =35,
        CAP_PROP_IRIS          =36,
-       CAP_PROP_SETTINGS      =37,
+       CAP_PROP_SETTINGS      =37, //! Pop up video/camera filter dialog (note: only supported by DSHOW backend currently. Property value is ignored)
        CAP_PROP_BUFFERSIZE    =38,
        CAP_PROP_AUTOFOCUS     =39
      };
 
 
-// Generic camera output modes.
-// Currently, these are supported through the libv4l interface only.
-enum { CAP_MODE_BGR  = 0, // BGR24 (default)
-       CAP_MODE_RGB  = 1, // RGB24
-       CAP_MODE_GRAY = 2, // Y8
-       CAP_MODE_YUYV = 3  // YUYV
+/** @brief Generic camera output modes identifier.
+ at note Currently, these are supported through the libv4l backend only.
+*/
+enum VideoCaptureModes {
+       CAP_MODE_BGR  = 0, //!< BGR24 (default)
+       CAP_MODE_RGB  = 1, //!< RGB24
+       CAP_MODE_GRAY = 2, //!< Y8
+       CAP_MODE_YUYV = 3  //!< YUYV
      };
 
+/** @brief %VideoWriter generic properties identifier.
+ @sa VideoWriter::get(), VideoWriter::set()
+*/
+enum VideoWriterProperties {
+  VIDEOWRITER_PROP_QUALITY = 1,    //!< Current quality (0..100%) of the encoded videostream. Can be adjusted dynamically in some codecs.
+  VIDEOWRITER_PROP_FRAMEBYTES = 2, //!< (Read-only): Size of just encoded video frame. Note that the encoding order may be different from representation order.
+  VIDEOWRITER_PROP_NSTRIPES = 3    //!< Number of stripes for parallel encoding. -1 for auto detection.
+};
 
-// DC1394 only
-// modes of the controlling registers (can be: auto, manual, auto single push, absolute Latter allowed with any other mode)
-// every feature can have only one mode turned on at a time
-enum { CAP_PROP_DC1394_OFF                = -4, //turn the feature off (not controlled manually nor automatically)
-       CAP_PROP_DC1394_MODE_MANUAL        = -3, //set automatically when a value of the feature is set by the user
+//! @} videoio_flags_base
+
+//! @addtogroup videoio_flags_others
+//! @{
+
+/** @name IEEE 1394 drivers
+    @{
+*/
+
+/** @brief Modes of the IEEE 1394 controlling registers
+(can be: auto, manual, auto single push, absolute Latter allowed with any other mode)
+every feature can have only one mode turned on at a time
+*/
+enum { CAP_PROP_DC1394_OFF                = -4, //!< turn the feature off (not controlled manually nor automatically).
+       CAP_PROP_DC1394_MODE_MANUAL        = -3, //!< set automatically when a value of the feature is set by the user.
        CAP_PROP_DC1394_MODE_AUTO          = -2,
        CAP_PROP_DC1394_MODE_ONE_PUSH_AUTO = -1,
        CAP_PROP_DC1394_MAX                = 31
      };
 
+//! @} IEEE 1394 drivers
 
-// OpenNI map generators
+/** @name OpenNI (for Kinect)
+    @{
+*/
+
+//! OpenNI map generators
 enum { CAP_OPENNI_DEPTH_GENERATOR = 1 << 31,
        CAP_OPENNI_IMAGE_GENERATOR = 1 << 30,
-       CAP_OPENNI_GENERATORS_MASK = CAP_OPENNI_DEPTH_GENERATOR + CAP_OPENNI_IMAGE_GENERATOR
+       CAP_OPENNI_IR_GENERATOR    = 1 << 29,
+       CAP_OPENNI_GENERATORS_MASK = CAP_OPENNI_DEPTH_GENERATOR + CAP_OPENNI_IMAGE_GENERATOR + CAP_OPENNI_IR_GENERATOR
      };
 
-// Properties of cameras available through OpenNI interfaces
+//! Properties of cameras available through OpenNI backend
 enum { CAP_PROP_OPENNI_OUTPUT_MODE       = 100,
-       CAP_PROP_OPENNI_FRAME_MAX_DEPTH   = 101, // in mm
-       CAP_PROP_OPENNI_BASELINE          = 102, // in mm
-       CAP_PROP_OPENNI_FOCAL_LENGTH      = 103, // in pixels
-       CAP_PROP_OPENNI_REGISTRATION      = 104, // flag that synchronizes the remapping depth map to image map
-                                                // by changing depth generator's view point (if the flag is "on") or
-                                                // sets this view point to its normal one (if the flag is "off").
+       CAP_PROP_OPENNI_FRAME_MAX_DEPTH   = 101, //!< In mm
+       CAP_PROP_OPENNI_BASELINE          = 102, //!< In mm
+       CAP_PROP_OPENNI_FOCAL_LENGTH      = 103, //!< In pixels
+       CAP_PROP_OPENNI_REGISTRATION      = 104, //!< Flag that synchronizes the remapping depth map to image map
+                                                //!< by changing depth generator's view point (if the flag is "on") or
+                                                //!< sets this view point to its normal one (if the flag is "off").
        CAP_PROP_OPENNI_REGISTRATION_ON   = CAP_PROP_OPENNI_REGISTRATION,
        CAP_PROP_OPENNI_APPROX_FRAME_SYNC = 105,
        CAP_PROP_OPENNI_MAX_BUFFER_SIZE   = 106,
@@ -183,28 +233,31 @@ enum { CAP_PROP_OPENNI_OUTPUT_MODE       = 100,
        CAP_PROP_OPENNI2_MIRROR           = 111
      };
 
-// OpenNI shortcats
+//! OpenNI shortcuts
 enum { CAP_OPENNI_IMAGE_GENERATOR_PRESENT         = CAP_OPENNI_IMAGE_GENERATOR + CAP_PROP_OPENNI_GENERATOR_PRESENT,
        CAP_OPENNI_IMAGE_GENERATOR_OUTPUT_MODE     = CAP_OPENNI_IMAGE_GENERATOR + CAP_PROP_OPENNI_OUTPUT_MODE,
+       CAP_OPENNI_DEPTH_GENERATOR_PRESENT         = CAP_OPENNI_DEPTH_GENERATOR + CAP_PROP_OPENNI_GENERATOR_PRESENT,
        CAP_OPENNI_DEPTH_GENERATOR_BASELINE        = CAP_OPENNI_DEPTH_GENERATOR + CAP_PROP_OPENNI_BASELINE,
        CAP_OPENNI_DEPTH_GENERATOR_FOCAL_LENGTH    = CAP_OPENNI_DEPTH_GENERATOR + CAP_PROP_OPENNI_FOCAL_LENGTH,
        CAP_OPENNI_DEPTH_GENERATOR_REGISTRATION    = CAP_OPENNI_DEPTH_GENERATOR + CAP_PROP_OPENNI_REGISTRATION,
-       CAP_OPENNI_DEPTH_GENERATOR_REGISTRATION_ON = CAP_OPENNI_DEPTH_GENERATOR_REGISTRATION
+       CAP_OPENNI_DEPTH_GENERATOR_REGISTRATION_ON = CAP_OPENNI_DEPTH_GENERATOR_REGISTRATION,
+       CAP_OPENNI_IR_GENERATOR_PRESENT            = CAP_OPENNI_IR_GENERATOR + CAP_PROP_OPENNI_GENERATOR_PRESENT,
      };
 
-// OpenNI data given from depth generator
-enum { CAP_OPENNI_DEPTH_MAP         = 0, // Depth values in mm (CV_16UC1)
-       CAP_OPENNI_POINT_CLOUD_MAP   = 1, // XYZ in meters (CV_32FC3)
-       CAP_OPENNI_DISPARITY_MAP     = 2, // Disparity in pixels (CV_8UC1)
-       CAP_OPENNI_DISPARITY_MAP_32F = 3, // Disparity in pixels (CV_32FC1)
-       CAP_OPENNI_VALID_DEPTH_MASK  = 4, // CV_8UC1
+//! OpenNI data given from depth generator
+enum { CAP_OPENNI_DEPTH_MAP         = 0, //!< Depth values in mm (CV_16UC1)
+       CAP_OPENNI_POINT_CLOUD_MAP   = 1, //!< XYZ in meters (CV_32FC3)
+       CAP_OPENNI_DISPARITY_MAP     = 2, //!< Disparity in pixels (CV_8UC1)
+       CAP_OPENNI_DISPARITY_MAP_32F = 3, //!< Disparity in pixels (CV_32FC1)
+       CAP_OPENNI_VALID_DEPTH_MASK  = 4, //!< CV_8UC1
+
+       CAP_OPENNI_BGR_IMAGE         = 5, //!< Data given from RGB image generator
+       CAP_OPENNI_GRAY_IMAGE        = 6, //!< Data given from RGB image generator
 
-       // Data given from RGB image generator
-       CAP_OPENNI_BGR_IMAGE         = 5,
-       CAP_OPENNI_GRAY_IMAGE        = 6
+       CAP_OPENNI_IR_IMAGE          = 7  //!< Data given from IR image generator
      };
 
-// Supported output modes of OpenNI image generator
+//! Supported output modes of OpenNI image generator
 enum { CAP_OPENNI_VGA_30HZ  = 0,
        CAP_OPENNI_SXGA_15HZ = 1,
        CAP_OPENNI_SXGA_30HZ = 2,
@@ -212,73 +265,224 @@ enum { CAP_OPENNI_VGA_30HZ  = 0,
        CAP_OPENNI_QVGA_60HZ = 4
      };
 
+//! @} OpenNI
+
+/** @name GStreamer
+    @{
+*/
 
-// GStreamer
-enum { CAP_PROP_GSTREAMER_QUEUE_LENGTH = 200 // default is 1
+enum { CAP_PROP_GSTREAMER_QUEUE_LENGTH = 200 //!< Default is 1
      };
 
+//! @} GStreamer
 
-// PVAPI
-enum { CAP_PROP_PVAPI_MULTICASTIP           = 300, // ip for anable multicast master mode. 0 for disable multicast
-       CAP_PROP_PVAPI_FRAMESTARTTRIGGERMODE = 301, // FrameStartTriggerMode: Determines how a frame is initiated
-       CAP_PROP_PVAPI_DECIMATIONHORIZONTAL  = 302, // Horizontal sub-sampling of the image
-       CAP_PROP_PVAPI_DECIMATIONVERTICAL    = 303, // Vertical sub-sampling of the image
-       CAP_PROP_PVAPI_BINNINGX              = 304, // Horizontal binning factor
-       CAP_PROP_PVAPI_BINNINGY              = 305, // Vertical binning factor
-       CAP_PROP_PVAPI_PIXELFORMAT           = 306  // Pixel format
+/** @name PvAPI, Prosilica GigE SDK
+    @{
+*/
+
+//! PVAPI
+enum { CAP_PROP_PVAPI_MULTICASTIP           = 300, //!< IP for enable multicast master mode. 0 for disable multicast.
+       CAP_PROP_PVAPI_FRAMESTARTTRIGGERMODE = 301, //!< FrameStartTriggerMode: Determines how a frame is initiated.
+       CAP_PROP_PVAPI_DECIMATIONHORIZONTAL  = 302, //!< Horizontal sub-sampling of the image.
+       CAP_PROP_PVAPI_DECIMATIONVERTICAL    = 303, //!< Vertical sub-sampling of the image.
+       CAP_PROP_PVAPI_BINNINGX              = 304, //!< Horizontal binning factor.
+       CAP_PROP_PVAPI_BINNINGY              = 305, //!< Vertical binning factor.
+       CAP_PROP_PVAPI_PIXELFORMAT           = 306  //!< Pixel format.
      };
 
-// PVAPI: FrameStartTriggerMode
-enum { CAP_PVAPI_FSTRIGMODE_FREERUN     = 0,    // Freerun
-       CAP_PVAPI_FSTRIGMODE_SYNCIN1     = 1,    // SyncIn1
-       CAP_PVAPI_FSTRIGMODE_SYNCIN2     = 2,    // SyncIn2
-       CAP_PVAPI_FSTRIGMODE_FIXEDRATE   = 3,    // FixedRate
-       CAP_PVAPI_FSTRIGMODE_SOFTWARE    = 4     // Software
+//! PVAPI: FrameStartTriggerMode
+enum { CAP_PVAPI_FSTRIGMODE_FREERUN     = 0,    //!< Freerun
+       CAP_PVAPI_FSTRIGMODE_SYNCIN1     = 1,    //!< SyncIn1
+       CAP_PVAPI_FSTRIGMODE_SYNCIN2     = 2,    //!< SyncIn2
+       CAP_PVAPI_FSTRIGMODE_FIXEDRATE   = 3,    //!< FixedRate
+       CAP_PVAPI_FSTRIGMODE_SOFTWARE    = 4     //!< Software
      };
 
-// PVAPI: DecimationHorizontal, DecimationVertical
-enum { CAP_PVAPI_DECIMATION_OFF       = 1,    // Off
-       CAP_PVAPI_DECIMATION_2OUTOF4   = 2,    // 2 out of 4 decimation
-       CAP_PVAPI_DECIMATION_2OUTOF8   = 4,    // 2 out of 8 decimation
-       CAP_PVAPI_DECIMATION_2OUTOF16  = 8     // 2 out of 16 decimation
+//! PVAPI: DecimationHorizontal, DecimationVertical
+enum { CAP_PVAPI_DECIMATION_OFF       = 1,    //!< Off
+       CAP_PVAPI_DECIMATION_2OUTOF4   = 2,    //!< 2 out of 4 decimation
+       CAP_PVAPI_DECIMATION_2OUTOF8   = 4,    //!< 2 out of 8 decimation
+       CAP_PVAPI_DECIMATION_2OUTOF16  = 8     //!< 2 out of 16 decimation
      };
 
-// PVAPI: PixelFormat
-enum { CAP_PVAPI_PIXELFORMAT_MONO8    = 1,    // Mono8
-       CAP_PVAPI_PIXELFORMAT_MONO16   = 2,    // Mono16
-       CAP_PVAPI_PIXELFORMAT_BAYER8   = 3,    // Bayer8
-       CAP_PVAPI_PIXELFORMAT_BAYER16  = 4,    // Bayer16
-       CAP_PVAPI_PIXELFORMAT_RGB24    = 5,    // Rgb24
-       CAP_PVAPI_PIXELFORMAT_BGR24    = 6,    // Bgr24
-       CAP_PVAPI_PIXELFORMAT_RGBA32   = 7,    // Rgba32
-       CAP_PVAPI_PIXELFORMAT_BGRA32   = 8,    // Bgra32
+//! PVAPI: PixelFormat
+enum { CAP_PVAPI_PIXELFORMAT_MONO8    = 1,    //!< Mono8
+       CAP_PVAPI_PIXELFORMAT_MONO16   = 2,    //!< Mono16
+       CAP_PVAPI_PIXELFORMAT_BAYER8   = 3,    //!< Bayer8
+       CAP_PVAPI_PIXELFORMAT_BAYER16  = 4,    //!< Bayer16
+       CAP_PVAPI_PIXELFORMAT_RGB24    = 5,    //!< Rgb24
+       CAP_PVAPI_PIXELFORMAT_BGR24    = 6,    //!< Bgr24
+       CAP_PVAPI_PIXELFORMAT_RGBA32   = 7,    //!< Rgba32
+       CAP_PVAPI_PIXELFORMAT_BGRA32   = 8,    //!< Bgra32
      };
 
-// Properties of cameras available through XIMEA SDK interface
-enum { CAP_PROP_XI_DOWNSAMPLING  = 400, // Change image resolution by binning or skipping.
-       CAP_PROP_XI_DATA_FORMAT   = 401, // Output data format.
-       CAP_PROP_XI_OFFSET_X      = 402, // Horizontal offset from the origin to the area of interest (in pixels).
-       CAP_PROP_XI_OFFSET_Y      = 403, // Vertical offset from the origin to the area of interest (in pixels).
-       CAP_PROP_XI_TRG_SOURCE    = 404, // Defines source of trigger.
-       CAP_PROP_XI_TRG_SOFTWARE  = 405, // Generates an internal trigger. PRM_TRG_SOURCE must be set to TRG_SOFTWARE.
-       CAP_PROP_XI_GPI_SELECTOR  = 406, // Selects general purpose input
-       CAP_PROP_XI_GPI_MODE      = 407, // Set general purpose input mode
-       CAP_PROP_XI_GPI_LEVEL     = 408, // Get general purpose level
-       CAP_PROP_XI_GPO_SELECTOR  = 409, // Selects general purpose output
-       CAP_PROP_XI_GPO_MODE      = 410, // Set general purpose output mode
-       CAP_PROP_XI_LED_SELECTOR  = 411, // Selects camera signalling LED
-       CAP_PROP_XI_LED_MODE      = 412, // Define camera signalling LED functionality
-       CAP_PROP_XI_MANUAL_WB     = 413, // Calculates White Balance(must be called during acquisition)
-       CAP_PROP_XI_AUTO_WB       = 414, // Automatic white balance
-       CAP_PROP_XI_AEAG          = 415, // Automatic exposure/gain
-       CAP_PROP_XI_EXP_PRIORITY  = 416, // Exposure priority (0.5 - exposure 50%, gain 50%).
-       CAP_PROP_XI_AE_MAX_LIMIT  = 417, // Maximum limit of exposure in AEAG procedure
-       CAP_PROP_XI_AG_MAX_LIMIT  = 418, // Maximum limit of gain in AEAG procedure
-       CAP_PROP_XI_AEAG_LEVEL    = 419, // Average intensity of output signal AEAG should achieve(in %)
-       CAP_PROP_XI_TIMEOUT       = 420  // Image capture timeout in milliseconds
+//! @} PvAPI
+
+/** @name XIMEA Camera API
+    @{
+*/
+
+//! Properties of cameras available through XIMEA SDK backend
+enum { CAP_PROP_XI_DOWNSAMPLING                                 = 400, //!< Change image resolution by binning or skipping.
+       CAP_PROP_XI_DATA_FORMAT                                  = 401, //!< Output data format.
+       CAP_PROP_XI_OFFSET_X                                     = 402, //!< Horizontal offset from the origin to the area of interest (in pixels).
+       CAP_PROP_XI_OFFSET_Y                                     = 403, //!< Vertical offset from the origin to the area of interest (in pixels).
+       CAP_PROP_XI_TRG_SOURCE                                   = 404, //!< Defines source of trigger.
+       CAP_PROP_XI_TRG_SOFTWARE                                 = 405, //!< Generates an internal trigger. PRM_TRG_SOURCE must be set to TRG_SOFTWARE.
+       CAP_PROP_XI_GPI_SELECTOR                                 = 406, //!< Selects general purpose input.
+       CAP_PROP_XI_GPI_MODE                                     = 407, //!< Set general purpose input mode.
+       CAP_PROP_XI_GPI_LEVEL                                    = 408, //!< Get general purpose level.
+       CAP_PROP_XI_GPO_SELECTOR                                 = 409, //!< Selects general purpose output.
+       CAP_PROP_XI_GPO_MODE                                     = 410, //!< Set general purpose output mode.
+       CAP_PROP_XI_LED_SELECTOR                                 = 411, //!< Selects camera signalling LED.
+       CAP_PROP_XI_LED_MODE                                     = 412, //!< Define camera signalling LED functionality.
+       CAP_PROP_XI_MANUAL_WB                                    = 413, //!< Calculates White Balance(must be called during acquisition).
+       CAP_PROP_XI_AUTO_WB                                      = 414, //!< Automatic white balance.
+       CAP_PROP_XI_AEAG                                         = 415, //!< Automatic exposure/gain.
+       CAP_PROP_XI_EXP_PRIORITY                                 = 416, //!< Exposure priority (0.5 - exposure 50%, gain 50%).
+       CAP_PROP_XI_AE_MAX_LIMIT                                 = 417, //!< Maximum limit of exposure in AEAG procedure.
+       CAP_PROP_XI_AG_MAX_LIMIT                                 = 418, //!< Maximum limit of gain in AEAG procedure.
+       CAP_PROP_XI_AEAG_LEVEL                                   = 419, //!< Average intensity of output signal AEAG should achieve(in %).
+       CAP_PROP_XI_TIMEOUT                                      = 420, //!< Image capture timeout in milliseconds.
+       CAP_PROP_XI_EXPOSURE                                     = 421, //!< Exposure time in microseconds.
+       CAP_PROP_XI_EXPOSURE_BURST_COUNT                         = 422, //!< Sets the number of times of exposure in one frame.
+       CAP_PROP_XI_GAIN_SELECTOR                                = 423, //!< Gain selector for parameter Gain allows to select different type of gains.
+       CAP_PROP_XI_GAIN                                         = 424, //!< Gain in dB.
+       CAP_PROP_XI_DOWNSAMPLING_TYPE                            = 426, //!< Change image downsampling type.
+       CAP_PROP_XI_BINNING_SELECTOR                             = 427, //!< Binning engine selector.
+       CAP_PROP_XI_BINNING_VERTICAL                             = 428, //!< Vertical Binning - number of vertical photo-sensitive cells to combine together.
+       CAP_PROP_XI_BINNING_HORIZONTAL                           = 429, //!< Horizontal Binning - number of horizontal photo-sensitive cells to combine together.
+       CAP_PROP_XI_BINNING_PATTERN                              = 430, //!< Binning pattern type.
+       CAP_PROP_XI_DECIMATION_SELECTOR                          = 431, //!< Decimation engine selector.
+       CAP_PROP_XI_DECIMATION_VERTICAL                          = 432, //!< Vertical Decimation - vertical sub-sampling of the image - reduces the vertical resolution of the image by the specified vertical decimation factor.
+       CAP_PROP_XI_DECIMATION_HORIZONTAL                        = 433, //!< Horizontal Decimation - horizontal sub-sampling of the image - reduces the horizontal resolution of the image by the specified vertical decimation factor.
+       CAP_PROP_XI_DECIMATION_PATTERN                           = 434, //!< Decimation pattern type.
+       CAP_PROP_XI_TEST_PATTERN_GENERATOR_SELECTOR              = 587, //!< Selects which test pattern generator is controlled by the TestPattern feature.
+       CAP_PROP_XI_TEST_PATTERN                                 = 588, //!< Selects which test pattern type is generated by the selected generator.
+       CAP_PROP_XI_IMAGE_DATA_FORMAT                            = 435, //!< Output data format.
+       CAP_PROP_XI_SHUTTER_TYPE                                 = 436, //!< Change sensor shutter type(CMOS sensor).
+       CAP_PROP_XI_SENSOR_TAPS                                  = 437, //!< Number of taps.
+       CAP_PROP_XI_AEAG_ROI_OFFSET_X                            = 439, //!< Automatic exposure/gain ROI offset X.
+       CAP_PROP_XI_AEAG_ROI_OFFSET_Y                            = 440, //!< Automatic exposure/gain ROI offset Y.
+       CAP_PROP_XI_AEAG_ROI_WIDTH                               = 441, //!< Automatic exposure/gain ROI Width.
+       CAP_PROP_XI_AEAG_ROI_HEIGHT                              = 442, //!< Automatic exposure/gain ROI Height.
+       CAP_PROP_XI_BPC                                          = 445, //!< Correction of bad pixels.
+       CAP_PROP_XI_WB_KR                                        = 448, //!< White balance red coefficient.
+       CAP_PROP_XI_WB_KG                                        = 449, //!< White balance green coefficient.
+       CAP_PROP_XI_WB_KB                                        = 450, //!< White balance blue coefficient.
+       CAP_PROP_XI_WIDTH                                        = 451, //!< Width of the Image provided by the device (in pixels).
+       CAP_PROP_XI_HEIGHT                                       = 452, //!< Height of the Image provided by the device (in pixels).
+       CAP_PROP_XI_REGION_SELECTOR                              = 589, //!< Selects Region in Multiple ROI which parameters are set by width, height, ... ,region mode.
+       CAP_PROP_XI_REGION_MODE                                  = 595, //!< Activates/deactivates Region selected by Region Selector.
+       CAP_PROP_XI_LIMIT_BANDWIDTH                              = 459, //!< Set/get bandwidth(datarate)(in Megabits).
+       CAP_PROP_XI_SENSOR_DATA_BIT_DEPTH                        = 460, //!< Sensor output data bit depth.
+       CAP_PROP_XI_OUTPUT_DATA_BIT_DEPTH                        = 461, //!< Device output data bit depth.
+       CAP_PROP_XI_IMAGE_DATA_BIT_DEPTH                         = 462, //!< bitdepth of data returned by function xiGetImage.
+       CAP_PROP_XI_OUTPUT_DATA_PACKING                          = 463, //!< Device output data packing (or grouping) enabled. Packing could be enabled if output_data_bit_depth > 8 and packing capability is available.
+       CAP_PROP_XI_OUTPUT_DATA_PACKING_TYPE                     = 464, //!< Data packing type. Some cameras supports only specific packing type.
+       CAP_PROP_XI_IS_COOLED                                    = 465, //!< Returns 1 for cameras that support cooling.
+       CAP_PROP_XI_COOLING                                      = 466, //!< Start camera cooling.
+       CAP_PROP_XI_TARGET_TEMP                                  = 467, //!< Set sensor target temperature for cooling.
+       CAP_PROP_XI_CHIP_TEMP                                    = 468, //!< Camera sensor temperature.
+       CAP_PROP_XI_HOUS_TEMP                                    = 469, //!< Camera housing temperature.
+       CAP_PROP_XI_HOUS_BACK_SIDE_TEMP                          = 590, //!< Camera housing back side temperature.
+       CAP_PROP_XI_SENSOR_BOARD_TEMP                            = 596, //!< Camera sensor board temperature.
+       CAP_PROP_XI_CMS                                          = 470, //!< Mode of color management system.
+       CAP_PROP_XI_APPLY_CMS                                    = 471, //!< Enable applying of CMS profiles to xiGetImage (see XI_PRM_INPUT_CMS_PROFILE, XI_PRM_OUTPUT_CMS_PROFILE).
+       CAP_PROP_XI_IMAGE_IS_COLOR                               = 474, //!< Returns 1 for color cameras.
+       CAP_PROP_XI_COLOR_FILTER_ARRAY                           = 475, //!< Returns color filter array type of RAW data.
+       CAP_PROP_XI_GAMMAY                                       = 476, //!< Luminosity gamma.
+       CAP_PROP_XI_GAMMAC                                       = 477, //!< Chromaticity gamma.
+       CAP_PROP_XI_SHARPNESS                                    = 478, //!< Sharpness Strength.
+       CAP_PROP_XI_CC_MATRIX_00                                 = 479, //!< Color Correction Matrix element [0][0].
+       CAP_PROP_XI_CC_MATRIX_01                                 = 480, //!< Color Correction Matrix element [0][1].
+       CAP_PROP_XI_CC_MATRIX_02                                 = 481, //!< Color Correction Matrix element [0][2].
+       CAP_PROP_XI_CC_MATRIX_03                                 = 482, //!< Color Correction Matrix element [0][3].
+       CAP_PROP_XI_CC_MATRIX_10                                 = 483, //!< Color Correction Matrix element [1][0].
+       CAP_PROP_XI_CC_MATRIX_11                                 = 484, //!< Color Correction Matrix element [1][1].
+       CAP_PROP_XI_CC_MATRIX_12                                 = 485, //!< Color Correction Matrix element [1][2].
+       CAP_PROP_XI_CC_MATRIX_13                                 = 486, //!< Color Correction Matrix element [1][3].
+       CAP_PROP_XI_CC_MATRIX_20                                 = 487, //!< Color Correction Matrix element [2][0].
+       CAP_PROP_XI_CC_MATRIX_21                                 = 488, //!< Color Correction Matrix element [2][1].
+       CAP_PROP_XI_CC_MATRIX_22                                 = 489, //!< Color Correction Matrix element [2][2].
+       CAP_PROP_XI_CC_MATRIX_23                                 = 490, //!< Color Correction Matrix element [2][3].
+       CAP_PROP_XI_CC_MATRIX_30                                 = 491, //!< Color Correction Matrix element [3][0].
+       CAP_PROP_XI_CC_MATRIX_31                                 = 492, //!< Color Correction Matrix element [3][1].
+       CAP_PROP_XI_CC_MATRIX_32                                 = 493, //!< Color Correction Matrix element [3][2].
+       CAP_PROP_XI_CC_MATRIX_33                                 = 494, //!< Color Correction Matrix element [3][3].
+       CAP_PROP_XI_DEFAULT_CC_MATRIX                            = 495, //!< Set default Color Correction Matrix.
+       CAP_PROP_XI_TRG_SELECTOR                                 = 498, //!< Selects the type of trigger.
+       CAP_PROP_XI_ACQ_FRAME_BURST_COUNT                        = 499, //!< Sets number of frames acquired by burst. This burst is used only if trigger is set to FrameBurstStart.
+       CAP_PROP_XI_DEBOUNCE_EN                                  = 507, //!< Enable/Disable debounce to selected GPI.
+       CAP_PROP_XI_DEBOUNCE_T0                                  = 508, //!< Debounce time (x * 10us).
+       CAP_PROP_XI_DEBOUNCE_T1                                  = 509, //!< Debounce time (x * 10us).
+       CAP_PROP_XI_DEBOUNCE_POL                                 = 510, //!< Debounce polarity (pol = 1 t0 - falling edge, t1 - rising edge).
+       CAP_PROP_XI_LENS_MODE                                    = 511, //!< Status of lens control interface. This shall be set to XI_ON before any Lens operations.
+       CAP_PROP_XI_LENS_APERTURE_VALUE                          = 512, //!< Current lens aperture value in stops. Examples: 2.8, 4, 5.6, 8, 11.
+       CAP_PROP_XI_LENS_FOCUS_MOVEMENT_VALUE                    = 513, //!< Lens current focus movement value to be used by XI_PRM_LENS_FOCUS_MOVE in motor steps.
+       CAP_PROP_XI_LENS_FOCUS_MOVE                              = 514, //!< Moves lens focus motor by steps set in XI_PRM_LENS_FOCUS_MOVEMENT_VALUE.
+       CAP_PROP_XI_LENS_FOCUS_DISTANCE                          = 515, //!< Lens focus distance in cm.
+       CAP_PROP_XI_LENS_FOCAL_LENGTH                            = 516, //!< Lens focal distance in mm.
+       CAP_PROP_XI_LENS_FEATURE_SELECTOR                        = 517, //!< Selects the current feature which is accessible by XI_PRM_LENS_FEATURE.
+       CAP_PROP_XI_LENS_FEATURE                                 = 518, //!< Allows access to lens feature value currently selected by XI_PRM_LENS_FEATURE_SELECTOR.
+       CAP_PROP_XI_DEVICE_MODEL_ID                              = 521, //!< Returns device model id.
+       CAP_PROP_XI_DEVICE_SN                                    = 522, //!< Returns device serial number.
+       CAP_PROP_XI_IMAGE_DATA_FORMAT_RGB32_ALPHA                = 529, //!< The alpha channel of RGB32 output image format.
+       CAP_PROP_XI_IMAGE_PAYLOAD_SIZE                           = 530, //!< Buffer size in bytes sufficient for output image returned by xiGetImage.
+       CAP_PROP_XI_TRANSPORT_PIXEL_FORMAT                       = 531, //!< Current format of pixels on transport layer.
+       CAP_PROP_XI_SENSOR_CLOCK_FREQ_HZ                         = 532, //!< Sensor clock frequency in Hz.
+       CAP_PROP_XI_SENSOR_CLOCK_FREQ_INDEX                      = 533, //!< Sensor clock frequency index. Sensor with selected frequencies have possibility to set the frequency only by this index.
+       CAP_PROP_XI_SENSOR_OUTPUT_CHANNEL_COUNT                  = 534, //!< Number of output channels from sensor used for data transfer.
+       CAP_PROP_XI_FRAMERATE                                    = 535, //!< Define framerate in Hz.
+       CAP_PROP_XI_COUNTER_SELECTOR                             = 536, //!< Select counter.
+       CAP_PROP_XI_COUNTER_VALUE                                = 537, //!< Counter status.
+       CAP_PROP_XI_ACQ_TIMING_MODE                              = 538, //!< Type of sensor frames timing.
+       CAP_PROP_XI_AVAILABLE_BANDWIDTH                          = 539, //!< Calculate and returns available interface bandwidth(int Megabits).
+       CAP_PROP_XI_BUFFER_POLICY                                = 540, //!< Data move policy.
+       CAP_PROP_XI_LUT_EN                                       = 541, //!< Activates LUT.
+       CAP_PROP_XI_LUT_INDEX                                    = 542, //!< Control the index (offset) of the coefficient to access in the LUT.
+       CAP_PROP_XI_LUT_VALUE                                    = 543, //!< Value at entry LUTIndex of the LUT.
+       CAP_PROP_XI_TRG_DELAY                                    = 544, //!< Specifies the delay in microseconds (us) to apply after the trigger reception before activating it.
+       CAP_PROP_XI_TS_RST_MODE                                  = 545, //!< Defines how time stamp reset engine will be armed.
+       CAP_PROP_XI_TS_RST_SOURCE                                = 546, //!< Defines which source will be used for timestamp reset. Writing this parameter will trigger settings of engine (arming).
+       CAP_PROP_XI_IS_DEVICE_EXIST                              = 547, //!< Returns 1 if camera connected and works properly.
+       CAP_PROP_XI_ACQ_BUFFER_SIZE                              = 548, //!< Acquisition buffer size in buffer_size_unit. Default bytes.
+       CAP_PROP_XI_ACQ_BUFFER_SIZE_UNIT                         = 549, //!< Acquisition buffer size unit in bytes. Default 1. E.g. Value 1024 means that buffer_size is in KiBytes.
+       CAP_PROP_XI_ACQ_TRANSPORT_BUFFER_SIZE                    = 550, //!< Acquisition transport buffer size in bytes.
+       CAP_PROP_XI_BUFFERS_QUEUE_SIZE                           = 551, //!< Queue of field/frame buffers.
+       CAP_PROP_XI_ACQ_TRANSPORT_BUFFER_COMMIT                  = 552, //!< Number of buffers to commit to low level.
+       CAP_PROP_XI_RECENT_FRAME                                 = 553, //!< GetImage returns most recent frame.
+       CAP_PROP_XI_DEVICE_RESET                                 = 554, //!< Resets the camera to default state.
+       CAP_PROP_XI_COLUMN_FPN_CORRECTION                        = 555, //!< Correction of column FPN.
+       CAP_PROP_XI_ROW_FPN_CORRECTION                           = 591, //!< Correction of row FPN.
+       CAP_PROP_XI_SENSOR_MODE                                  = 558, //!< Current sensor mode. Allows to select sensor mode by one integer. Setting of this parameter affects: image dimensions and downsampling.
+       CAP_PROP_XI_HDR                                          = 559, //!< Enable High Dynamic Range feature.
+       CAP_PROP_XI_HDR_KNEEPOINT_COUNT                          = 560, //!< The number of kneepoints in the PWLR.
+       CAP_PROP_XI_HDR_T1                                       = 561, //!< Position of first kneepoint(in % of XI_PRM_EXPOSURE).
+       CAP_PROP_XI_HDR_T2                                       = 562, //!< Position of second kneepoint (in % of XI_PRM_EXPOSURE).
+       CAP_PROP_XI_KNEEPOINT1                                   = 563, //!< Value of first kneepoint (% of sensor saturation).
+       CAP_PROP_XI_KNEEPOINT2                                   = 564, //!< Value of second kneepoint (% of sensor saturation).
+       CAP_PROP_XI_IMAGE_BLACK_LEVEL                            = 565, //!< Last image black level counts. Can be used for Offline processing to recall it.
+       CAP_PROP_XI_HW_REVISION                                  = 571, //!< Returns hardware revision number.
+       CAP_PROP_XI_DEBUG_LEVEL                                  = 572, //!< Set debug level.
+       CAP_PROP_XI_AUTO_BANDWIDTH_CALCULATION                   = 573, //!< Automatic bandwidth calculation.
+       CAP_PROP_XI_FFS_FILE_ID                                  = 594, //!< File number.
+       CAP_PROP_XI_FFS_FILE_SIZE                                = 580, //!< Size of file.
+       CAP_PROP_XI_FREE_FFS_SIZE                                = 581, //!< Size of free camera FFS.
+       CAP_PROP_XI_USED_FFS_SIZE                                = 582, //!< Size of used camera FFS.
+       CAP_PROP_XI_FFS_ACCESS_KEY                               = 583, //!< Setting of key enables file operations on some cameras.
+       CAP_PROP_XI_SENSOR_FEATURE_SELECTOR                      = 585, //!< Selects the current feature which is accessible by XI_PRM_SENSOR_FEATURE_VALUE.
+       CAP_PROP_XI_SENSOR_FEATURE_VALUE                         = 586, //!< Allows access to sensor feature value currently selected by XI_PRM_SENSOR_FEATURE_SELECTOR.
      };
 
-// Properties of cameras available through AVFOUNDATION interface
+//! @} XIMEA
+
+/** @name AVFoundation framework for iOS
+    OS X Lion will have the same API
+    @{
+*/
+
+//! Properties of cameras available through AVFOUNDATION backend
 enum { CAP_PROP_IOS_DEVICE_FOCUS        = 9001,
        CAP_PROP_IOS_DEVICE_EXPOSURE     = 9002,
        CAP_PROP_IOS_DEVICE_FLASH        = 9003,
@@ -286,8 +490,11 @@ enum { CAP_PROP_IOS_DEVICE_FOCUS        = 9001,
        CAP_PROP_IOS_DEVICE_TORCH        = 9005
      };
 
+/** @name Smartek Giganetix GigEVisionSDK
+    @{
+*/
 
-// Properties of cameras available through Smartek Giganetix Ethernet Vision interface
+//! Properties of cameras available through Smartek Giganetix Ethernet Vision backend
 /* --- Vladimir Litvinenko (litvinenko.vladimir at gmail.com) --- */
 enum { CAP_PROP_GIGA_FRAME_OFFSET_X   = 10001,
        CAP_PROP_GIGA_FRAME_OFFSET_Y   = 10002,
@@ -297,6 +504,11 @@ enum { CAP_PROP_GIGA_FRAME_OFFSET_X   = 10001,
        CAP_PROP_GIGA_FRAME_SENS_HEIGH = 10006
      };
 
+//! @} Smartek
+
+/** @name Intel Perceptual Computing SDK
+    @{
+*/
 enum { CAP_PROP_INTELPERC_PROFILE_COUNT               = 11001,
        CAP_PROP_INTELPERC_PROFILE_IDX                 = 11002,
        CAP_PROP_INTELPERC_DEPTH_LOW_CONFIDENCE_VALUE  = 11003,
@@ -306,144 +518,172 @@ enum { CAP_PROP_INTELPERC_PROFILE_COUNT               = 11001,
        CAP_PROP_INTELPERC_DEPTH_FOCAL_LENGTH_VERT     = 11007
      };
 
-// Intel PerC streams
+//! Intel Perceptual Streams
 enum { CAP_INTELPERC_DEPTH_GENERATOR = 1 << 29,
        CAP_INTELPERC_IMAGE_GENERATOR = 1 << 28,
        CAP_INTELPERC_GENERATORS_MASK = CAP_INTELPERC_DEPTH_GENERATOR + CAP_INTELPERC_IMAGE_GENERATOR
      };
 
-enum { CAP_INTELPERC_DEPTH_MAP              = 0, // Each pixel is a 16-bit integer. The value indicates the distance from an object to the camera's XY plane or the Cartesian depth.
-       CAP_INTELPERC_UVDEPTH_MAP            = 1, // Each pixel contains two 32-bit floating point values in the range of 0-1, representing the mapping of depth coordinates to the color coordinates.
-       CAP_INTELPERC_IR_MAP                 = 2, // Each pixel is a 16-bit integer. The value indicates the intensity of the reflected laser beam.
+enum { CAP_INTELPERC_DEPTH_MAP              = 0, //!< Each pixel is a 16-bit integer. The value indicates the distance from an object to the camera's XY plane or the Cartesian depth.
+       CAP_INTELPERC_UVDEPTH_MAP            = 1, //!< Each pixel contains two 32-bit floating point values in the range of 0-1, representing the mapping of depth coordinates to the color coordinates.
+       CAP_INTELPERC_IR_MAP                 = 2, //!< Each pixel is a 16-bit integer. The value indicates the intensity of the reflected laser beam.
        CAP_INTELPERC_IMAGE                  = 3
      };
 
-enum { VIDEOWRITER_PROP_QUALITY = 1,    // Quality (0..100%) of the videostream encoded
-       VIDEOWRITER_PROP_FRAMEBYTES = 2, // (Read-only): Size of just encoded video frame
-       VIDEOWRITER_PROP_NSTRIPES = 3    // Number of stripes for parallel encoding. -1 for auto detection
+//! @} Intel Perceptual
+
+/** @name gPhoto2 connection
+    @{
+*/
+
+/** @brief gPhoto2 properties
+
+If `propertyId` is less than 0 then work on widget with that __additive inversed__ camera setting ID
+Get IDs by using CAP_PROP_GPHOTO2_WIDGET_ENUMERATE.
+ at see CvCaptureCAM_GPHOTO2 for more info
+*/
+enum { CAP_PROP_GPHOTO2_PREVIEW           = 17001, //!< Capture only preview from liveview mode.
+       CAP_PROP_GPHOTO2_WIDGET_ENUMERATE  = 17002, //!< Readonly, returns (const char *).
+       CAP_PROP_GPHOTO2_RELOAD_CONFIG     = 17003, //!< Trigger, only by set. Reload camera settings.
+       CAP_PROP_GPHOTO2_RELOAD_ON_CHANGE  = 17004, //!< Reload all settings on set.
+       CAP_PROP_GPHOTO2_COLLECT_MSGS      = 17005, //!< Collect messages with details.
+       CAP_PROP_GPHOTO2_FLUSH_MSGS        = 17006, //!< Readonly, returns (const char *).
+       CAP_PROP_SPEED                     = 17007, //!< Exposure speed. Can be readonly, depends on camera program.
+       CAP_PROP_APERTURE                  = 17008, //!< Aperture. Can be readonly, depends on camera program.
+       CAP_PROP_EXPOSUREPROGRAM           = 17009, //!< Camera exposure program.
+       CAP_PROP_VIEWFINDER                = 17010  //!< Enter liveview mode.
      };
 
-// gPhoto2 properties, if propertyId is less than 0 then work on widget with that __additive inversed__ camera setting ID
-// Get IDs by using CAP_PROP_GPHOTO2_WIDGET_ENUMERATE.
-// @see CvCaptureCAM_GPHOTO2 for more info
-enum { CAP_PROP_GPHOTO2_PREVIEW           = 17001, // Capture only preview from liveview mode.
-       CAP_PROP_GPHOTO2_WIDGET_ENUMERATE  = 17002, // Readonly, returns (const char *).
-       CAP_PROP_GPHOTO2_RELOAD_CONFIG     = 17003, // Trigger, only by set. Reload camera settings.
-       CAP_PROP_GPHOTO2_RELOAD_ON_CHANGE  = 17004, // Reload all settings on set.
-       CAP_PROP_GPHOTO2_COLLECT_MSGS      = 17005, // Collect messages with details.
-       CAP_PROP_GPHOTO2_FLUSH_MSGS        = 17006, // Readonly, returns (const char *).
-       CAP_PROP_SPEED                     = 17007, // Exposure speed. Can be readonly, depends on camera program.
-       CAP_PROP_APERTURE                  = 17008, // Aperture. Can be readonly, depends on camera program.
-       CAP_PROP_EXPOSUREPROGRAM           = 17009, // Camera exposure program.
-       CAP_PROP_VIEWFINDER                = 17010  // Enter liveview mode.
+//! @} gPhoto2
+
+
+/** @name Images backend
+    @{
+*/
+
+/** @brief Images backend properties
+
+*/
+enum { CAP_PROP_IMAGES_BASE = 18000,
+       CAP_PROP_IMAGES_LAST = 19000 // excluding
      };
 
-//enum {
+//! @} Images
+
+//! @} videoio_flags_others
+
 
 class IVideoCapture;
 
-/** @brief Class for video capturing from video files, image sequences or cameras. The class provides C++ API
-for capturing video from cameras or for reading video files and image sequences. Here is how the
-class can be used: :
- at code
-    #include "opencv2/opencv.hpp"
-
-    using namespace cv;
-
-    int main(int, char**)
-    {
-        VideoCapture cap(0); // open the default camera
-        if(!cap.isOpened())  // check if we succeeded
-            return -1;
-
-        Mat edges;
-        namedWindow("edges",1);
-        for(;;)
-        {
-            Mat frame;
-            cap >> frame; // get a new frame from camera
-            cvtColor(frame, edges, COLOR_BGR2GRAY);
-            GaussianBlur(edges, edges, Size(7,7), 1.5, 1.5);
-            Canny(edges, edges, 0, 30, 3);
-            imshow("edges", edges);
-            if(waitKey(30) >= 0) break;
-        }
-        // the camera will be deinitialized automatically in VideoCapture destructor
-        return 0;
-    }
- at endcode
- at note In C API the black-box structure CvCapture is used instead of VideoCapture.
+/** @brief Class for video capturing from video files, image sequences or cameras.
+
+The class provides C++ API for capturing video from cameras or for reading video files and image sequences.
+
+Here is how the class can be used:
+ at include samples/cpp/videocapture_basic.cpp
 
+ at note In @ref videoio_c "C API" the black-box structure `CvCapture` is used instead of %VideoCapture.
 @note
--   A basic sample on using the VideoCapture interface can be found at
-    opencv_source_code/samples/cpp/starter_video.cpp
--   Another basic video processing sample can be found at
-    opencv_source_code/samples/cpp/video_dmtx.cpp
--   (Python) A basic sample on using the VideoCapture interface can be found at
-    opencv_source_code/samples/python/video.py
--   (Python) Another basic video processing sample can be found at
-    opencv_source_code/samples/python/video_dmtx.py
+-   (C++) A basic sample on using the %VideoCapture interface can be found at
+    `OPENCV_SOURCE_CODE/samples/cpp/videocapture_starter.cpp`
+-   (Python) A basic sample on using the %VideoCapture interface can be found at
+    `OPENCV_SOURCE_CODE/samples/python/video.py`
 -   (Python) A multi threaded video processing sample can be found at
-    opencv_source_code/samples/python/video_threaded.py
+    `OPENCV_SOURCE_CODE/samples/python/video_threaded.py`
+-   (Python) %VideoCapture sample showcasing some features of the Video4Linux2 backend
+    `OPENCV_SOURCE_CODE/samples/python/video_v4l2.py`
  */
 class CV_EXPORTS_W VideoCapture
 {
 public:
-    /** @brief
-    @note In C API, when you finished working with video, release CvCapture structure with
+    /** @brief Default constructor
+    @note In @ref videoio_c "C API", when you finished working with video, release CvCapture structure with
     cvReleaseCapture(), or use Ptr\<CvCapture\> that calls cvReleaseCapture() automatically in the
     destructor.
      */
     CV_WRAP VideoCapture();
 
     /** @overload
-    @param filename name of the opened video file (eg. video.avi) or image sequence (eg.
-    img_%02d.jpg, which will read samples like img_00.jpg, img_01.jpg, img_02.jpg, ...)
+    @brief  Open video file or a capturing device or a IP video stream for video capturing
+
+    Same as VideoCapture(const String& filename, int apiPreference) but using default Capture API backends
     */
     CV_WRAP VideoCapture(const String& filename);
 
     /** @overload
-    @param filename name of the opened video file (eg. video.avi) or image sequence (eg.
-    img_%02d.jpg, which will read samples like img_00.jpg, img_01.jpg, img_02.jpg, ...)
-
-    @param apiPreference preferred Capture API to use. Can be used to enforce a specific reader
-    implementation if multiple are available: e.g. CAP_FFMPEG or CAP_IMAGES
+    @brief  Open video file or a capturing device or a IP video stream for video capturing with API Preference
+
+    @param filename it can be:
+    - name of video file (eg. `video.avi`)
+    - or image sequence (eg. `img_%02d.jpg`, which will read samples like `img_00.jpg, img_01.jpg, img_02.jpg, ...`)
+    - or URL of video stream (eg. `protocol://host:port/script_name?script_params|auth`).
+      Note that each video stream or IP camera feed has its own URL scheme. Please refer to the
+      documentation of source stream to know the right URL.
+    @param apiPreference preferred Capture API backends to use. Can be used to enforce a specific reader
+    implementation if multiple are available: e.g. cv::CAP_FFMPEG or cv::CAP_IMAGES or cv::CAP_DSHOW.
+    @sa The list of supported API backends cv::VideoCaptureAPIs
     */
     CV_WRAP VideoCapture(const String& filename, int apiPreference);
 
     /** @overload
-    @param index = camera_id + domain_offset (CAP_*). id of the video capturing device to open. If there is a single
-    camera connected, just pass 0. Advanced Usage: to open Camera 1 using the MS Media Foundation API: index = 1 + CAP_MSMF
+    @brief  Open a camera for video capturing
+
+    @param index camera_id + domain_offset (CAP_*) id of the video capturing device to open. To open default camera using default backend just pass 0.
+    Use a `domain_offset` to enforce a specific reader implementation if multiple are available like cv::CAP_FFMPEG or cv::CAP_IMAGES or cv::CAP_DSHOW.
+    e.g. to open Camera 1 using the MS Media Foundation API use `index = 1 + cv::CAP_MSMF`
+
+    @sa The list of supported API backends cv::VideoCaptureAPIs
     */
     CV_WRAP VideoCapture(int index);
 
+    /** @brief Default destructor
+
+    The method first calls VideoCapture::release to close the already opened file or camera.
+    */
     virtual ~VideoCapture();
 
-    /** @brief Open video file or a capturing device for video capturing
+    /** @brief  Open video file or a capturing device or a IP video stream for video capturing
 
-    @param filename name of the opened video file (eg. video.avi) or image sequence (eg.
-    img_%02d.jpg, which will read samples like img_00.jpg, img_01.jpg, img_02.jpg, ...)
+    @overload
 
-    The methods first call VideoCapture::release to close the already opened file or camera.
+    Parameters are same as the constructor VideoCapture(const String& filename)
+    @return `true` if the file has been successfully opened
+
+    The method first calls VideoCapture::release to close the already opened file or camera.
      */
     CV_WRAP virtual bool open(const String& filename);
 
-    /** @overload
-    @param index = camera_id + domain_offset (CAP_*). id of the video capturing device to open. If there is a single
-    camera connected, just pass 0. Advanced Usage: to open Camera 1 using the MS Media Foundation API: index = 1 + CAP_MSMF
+    /** @brief  Open a camera for video capturing
+
+    @overload
+
+    Parameters are same as the constructor VideoCapture(int index)
+    @return `true` if the camera has been successfully opened.
+
+    The method first calls VideoCapture::release to close the already opened file or camera.
     */
     CV_WRAP virtual bool open(int index);
 
+   /** @brief  Open a camera for video capturing
+
+    @overload
+
+    This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.
+    Parameters are similar as the constructor VideoCapture(int index),except it takes an additional argument apiPreference.
+    @return open(cameraNum + apiPreference).
+    */
+    CV_WRAP bool open(int cameraNum, int apiPreference);
+
     /** @brief Returns true if video capturing has been initialized already.
 
-    If the previous call to VideoCapture constructor or VideoCapture::open succeeded, the method returns
+    If the previous call to VideoCapture constructor or VideoCapture::open() succeeded, the method returns
     true.
      */
     CV_WRAP virtual bool isOpened() const;
 
     /** @brief Closes video file or capturing device.
 
-    The methods are automatically called by subsequent VideoCapture::open and by VideoCapture
+    The method is automatically called by subsequent VideoCapture::open and by VideoCapture
     destructor.
 
     The C function also deallocates memory and clears \*capture pointer.
@@ -452,7 +692,9 @@ public:
 
     /** @brief Grabs the next frame from video file or capturing device.
 
-    The methods/functions grab the next frame from video file or camera and return true (non-zero) in
+    @return `true` (non-zero) in the case of success.
+
+    The method/function grabs the next frame from video file or camera and returns true (non-zero) in
     the case of success.
 
     The primary use of the function is in multi-camera environments, especially when the cameras do not
@@ -462,34 +704,52 @@ public:
     from different cameras will be closer in time.
 
     Also, when a connected camera is multi-head (for example, a stereo camera or a Kinect device), the
-    correct way of retrieving data from it is to call VideoCapture::grab first and then call
-    VideoCapture::retrieve one or more times with different values of the channel parameter. See
-    <https://github.com/Itseez/opencv/tree/master/samples/cpp/openni_capture.cpp>
+    correct way of retrieving data from it is to call VideoCapture::grab() first and then call
+    VideoCapture::retrieve() one or more times with different values of the channel parameter.
+
+    @ref tutorial_kinect_openni
      */
     CV_WRAP virtual bool grab();
 
     /** @brief Decodes and returns the grabbed video frame.
 
-    The methods/functions decode and return the just grabbed frame. If no frames has been grabbed
-    (camera has been disconnected, or there are no more frames in video file), the methods return false
-    and the functions return NULL pointer.
+    @param [out] image the video frame is returned here. If no frames has been grabbed the image will be empty.
+    @param flag it could be a frame index or a driver specific flag
+    @return `false` if no frames has been grabbed
+
+    The method decodes and returns the just grabbed frame. If no frames has been grabbed
+    (camera has been disconnected, or there are no more frames in video file), the method returns false
+    and the function returns an empty image (with %cv::Mat, test it with Mat::empty()).
 
-    @note OpenCV 1.x functions cvRetrieveFrame and cv.RetrieveFrame return image stored inside the video
+    @sa read()
+
+    @note In @ref videoio_c "C API", functions cvRetrieveFrame() and cv.RetrieveFrame() return image stored inside the video
     capturing structure. It is not allowed to modify or release the image! You can copy the frame using
     :ocvcvCloneImage and then do whatever you want with the copy.
      */
     CV_WRAP virtual bool retrieve(OutputArray image, int flag = 0);
+
+    /** @brief Stream operator to read the next video frame.
+    @sa read()
+    */
     virtual VideoCapture& operator >> (CV_OUT Mat& image);
+
+    /** @overload
+    @sa read()
+    */
     virtual VideoCapture& operator >> (CV_OUT UMat& image);
 
     /** @brief Grabs, decodes and returns the next video frame.
 
-    The methods/functions combine VideoCapture::grab and VideoCapture::retrieve in one call. This is the
-    most convenient method for reading video files or capturing data from decode and return the just
+    @param [out] image the video frame is returned here. If no frames has been grabbed the image will be empty.
+    @return `false` if no frames has been grabbed
+
+    The method/function combines VideoCapture::grab() and VideoCapture::retrieve() in one call. This is the
+    most convenient method for reading video files or capturing data from decode and returns the just
     grabbed frame. If no frames has been grabbed (camera has been disconnected, or there are no more
-    frames in video file), the methods return false and the functions return NULL pointer.
+    frames in video file), the method returns false and the function returns empty image (with %cv::Mat, test it with Mat::empty()).
 
-    @note OpenCV 1.x functions cvRetrieveFrame and cv.RetrieveFrame return image stored inside the video
+    @note In @ref videoio_c "C API", functions cvRetrieveFrame() and cv.RetrieveFrame() return image stored inside the video
     capturing structure. It is not allowed to modify or release the image! You can copy the frame using
     :ocvcvCloneImage and then do whatever you want with the copy.
      */
@@ -497,75 +757,43 @@ public:
 
     /** @brief Sets a property in the VideoCapture.
 
-    @param propId Property identifier. It can be one of the following:
-     -   **CAP_PROP_POS_MSEC** Current position of the video file in milliseconds.
-     -   **CAP_PROP_POS_FRAMES** 0-based index of the frame to be decoded/captured next.
-     -   **CAP_PROP_POS_AVI_RATIO** Relative position of the video file: 0 - start of the
-         film, 1 - end of the film.
-     -   **CAP_PROP_FRAME_WIDTH** Width of the frames in the video stream.
-     -   **CAP_PROP_FRAME_HEIGHT** Height of the frames in the video stream.
-     -   **CAP_PROP_FPS** Frame rate.
-     -   **CAP_PROP_FOURCC** 4-character code of codec.
-     -   **CAP_PROP_FRAME_COUNT** Number of frames in the video file.
-     -   **CAP_PROP_FORMAT** Format of the Mat objects returned by retrieve() .
-     -   **CAP_PROP_MODE** Backend-specific value indicating the current capture mode.
-     -   **CAP_PROP_BRIGHTNESS** Brightness of the image (only for cameras).
-     -   **CAP_PROP_CONTRAST** Contrast of the image (only for cameras).
-     -   **CAP_PROP_SATURATION** Saturation of the image (only for cameras).
-     -   **CAP_PROP_HUE** Hue of the image (only for cameras).
-     -   **CAP_PROP_GAIN** Gain of the image (only for cameras).
-     -   **CAP_PROP_EXPOSURE** Exposure (only for cameras).
-     -   **CAP_PROP_CONVERT_RGB** Boolean flags indicating whether images should be converted
-         to RGB.
-     -   **CAP_PROP_WHITE_BALANCE** Currently unsupported
-     -   **CAP_PROP_RECTIFICATION** Rectification flag for stereo cameras (note: only supported
-         by DC1394 v 2.x backend currently)
+    @param propId Property identifier from cv::VideoCaptureProperties (eg. cv::CAP_PROP_POS_MSEC, cv::CAP_PROP_POS_FRAMES, ...)
+    or one from @ref videoio_flags_others
     @param value Value of the property.
+    @return `true` if the property is supported by backend used by the VideoCapture instance.
+    @note Even if it returns `true` this doesn't ensure that the property
+    value has been accepted by the capture device. See note in VideoCapture::get()
      */
     CV_WRAP virtual bool set(int propId, double value);
 
     /** @brief Returns the specified VideoCapture property
 
-    @param propId Property identifier. It can be one of the following:
-     -   **CAP_PROP_POS_MSEC** Current position of the video file in milliseconds or video
-         capture timestamp.
-     -   **CAP_PROP_POS_FRAMES** 0-based index of the frame to be decoded/captured next.
-     -   **CAP_PROP_POS_AVI_RATIO** Relative position of the video file: 0 - start of the
-         film, 1 - end of the film.
-     -   **CAP_PROP_FRAME_WIDTH** Width of the frames in the video stream.
-     -   **CAP_PROP_FRAME_HEIGHT** Height of the frames in the video stream.
-     -   **CAP_PROP_FPS** Frame rate.
-     -   **CAP_PROP_FOURCC** 4-character code of codec.
-     -   **CAP_PROP_FRAME_COUNT** Number of frames in the video file.
-     -   **CAP_PROP_FORMAT** Format of the Mat objects returned by retrieve() .
-     -   **CAP_PROP_MODE** Backend-specific value indicating the current capture mode.
-     -   **CAP_PROP_BRIGHTNESS** Brightness of the image (only for cameras).
-     -   **CAP_PROP_CONTRAST** Contrast of the image (only for cameras).
-     -   **CAP_PROP_SATURATION** Saturation of the image (only for cameras).
-     -   **CAP_PROP_HUE** Hue of the image (only for cameras).
-     -   **CAP_PROP_GAIN** Gain of the image (only for cameras).
-     -   **CAP_PROP_EXPOSURE** Exposure (only for cameras).
-     -   **CAP_PROP_CONVERT_RGB** Boolean flags indicating whether images should be converted
-         to RGB.
-     -   **CAP_PROP_WHITE_BALANCE** Currently not supported
-     -   **CAP_PROP_RECTIFICATION** Rectification flag for stereo cameras (note: only supported
-         by DC1394 v 2.x backend currently)
-
-    @note When querying a property that is not supported by the backend used by the VideoCapture
-    class, value 0 is returned.
-     */
+    @param propId Property identifier from cv::VideoCaptureProperties (eg. cv::CAP_PROP_POS_MSEC, cv::CAP_PROP_POS_FRAMES, ...)
+    or one from @ref videoio_flags_others
+    @return Value for the specified property. Value 0 is returned when querying a property that is
+    not supported by the backend used by the VideoCapture instance.
+
+    @note Reading / writing properties involves many layers. Some unexpected result might happens
+    along this chain.
+    @code {.txt}
+    `VideoCapture -> API Backend -> Operating System -> Device Driver -> Device Hardware`
+    @endcode
+    The returned value might be different from what really used by the device or it could be encoded
+    using device dependant rules (eg. steps or percentage). Effective behaviour depends from device
+    driver and API Backend
+
+    */
     CV_WRAP virtual double get(int propId) const;
 
-    /** @overload
+    /** @brief Open video file or a capturing device or a IP video stream for video capturing with API Preference
 
-    @param filename name of the opened video file (eg. video.avi) or image sequence (eg.
-    img_%02d.jpg, which will read samples like img_00.jpg, img_01.jpg, img_02.jpg, ...)
+    @overload
 
-    @param apiPreference preferred Capture API to use. Can be used to enforce a specific reader
-    implementation if multiple are available: e.g. CAP_FFMPEG or CAP_IMAGES
+    Parameters are same as the constructor VideoCapture(const String& filename, int apiPreference)
+    @return `true` if the file has been successfully opened
 
-    The methods first call VideoCapture::release to close the already opened file or camera.
-     */
+    The method first calls VideoCapture::release to close the already opened file or camera.
+    */
     CV_WRAP virtual bool open(const String& filename, int apiPreference);
 
 protected:
@@ -576,14 +804,21 @@ protected:
 class IVideoWriter;
 
 /** @brief Video writer class.
+
+The class provides C++ API for writing video files or image sequences.
+
+Here is how the class can be used:
+ at include samples/cpp/videowriter_basic.cpp
  */
 class CV_EXPORTS_W VideoWriter
 {
 public:
-    /** @brief VideoWriter constructors
+    /** @brief Default constructors
 
-    The constructors/functions initialize video writers. On Linux FFMPEG is used to write videos; on
-    Windows FFMPEG or VFW is used; on MacOSX QTKit is used.
+    The constructors/functions initialize video writers.
+    -   On Linux FFMPEG is used to write videos;
+    -   On Windows FFMPEG or VFW is used;
+    -   On MacOSX QTKit is used.
      */
     CV_WRAP VideoWriter();
 
@@ -599,16 +834,31 @@ public:
     @param frameSize Size of the video frames.
     @param isColor If it is not zero, the encoder will expect and encode color frames, otherwise it
     will work with grayscale frames (the flag is currently supported on Windows only).
+
+    @b Tips:
+    - With some backends `fourcc=-1` pops up the codec selection dialog from the system.
+    - To save image sequence use a proper filename (eg. `img_%02d.jpg`) and `fourcc=0`
+      OR `fps=0`. Use uncompressed image format (eg. `img_%02d.BMP`) to save raw frames.
+    - Most codecs are lossy. If you want lossless video file you need to use a lossless codecs
+      (eg. FFMPEG FFV1, Huffman HFYU, Lagarith LAGS, etc...)
+    - If FFMPEG is enabled, using `codec=0; fps=0;` you can create an uncompressed (raw) video file.
     */
     CV_WRAP VideoWriter(const String& filename, int fourcc, double fps,
                 Size frameSize, bool isColor = true);
 
+    /** @brief Default destructor
+
+    The method first calls VideoWriter::release to close the already opened file.
+    */
     virtual ~VideoWriter();
 
     /** @brief Initializes or reinitializes video writer.
 
     The method opens video writer. Parameters are the same as in the constructor
     VideoWriter::VideoWriter.
+    @return `true` if video writer has been successfully initialized
+
+    The method first calls VideoWriter::release to close the already opened file.
      */
     CV_WRAP virtual bool open(const String& filename, int fourcc, double fps,
                       Size frameSize, bool isColor = true);
@@ -619,44 +869,49 @@ public:
 
     /** @brief Closes the video writer.
 
-    The methods are automatically called by subsequent VideoWriter::open and by the VideoWriter
+    The method is automatically called by subsequent VideoWriter::open and by the VideoWriter
     destructor.
      */
     CV_WRAP virtual void release();
+
+    /** @brief Stream operator to write the next video frame.
+    @sa write
+    */
     virtual VideoWriter& operator << (const Mat& image);
 
     /** @brief Writes the next video frame
 
     @param image The written frame
 
-    The functions/methods write the specified image to video file. It must have the same size as has
+    The function/method writes the specified image to video file. It must have the same size as has
     been specified when opening the video writer.
      */
     CV_WRAP virtual void write(const Mat& image);
 
     /** @brief Sets a property in the VideoWriter.
 
-     @param propId Property identifier. It can be one of the following:
-     -   **VIDEOWRITER_PROP_QUALITY** Quality (0..100%) of the videostream encoded. Can be adjusted dynamically in some codecs.
-     -   **VIDEOWRITER_PROP_NSTRIPES** Number of stripes for parallel encoding
+     @param propId Property identifier from cv::VideoWriterProperties (eg. cv::VIDEOWRITER_PROP_QUALITY)
+     or one of @ref videoio_flags_others
+
      @param value Value of the property.
+     @return  `true` if the property is supported by the backend used by the VideoWriter instance.
      */
     CV_WRAP virtual bool set(int propId, double value);
 
     /** @brief Returns the specified VideoWriter property
 
-     @param propId Property identifier. It can be one of the following:
-     -   **VIDEOWRITER_PROP_QUALITY** Current quality of the encoded videostream.
-     -   **VIDEOWRITER_PROP_FRAMEBYTES** (Read-only) Size of just encoded video frame; note that the encoding order may be different from representation order.
-     -   **VIDEOWRITER_PROP_NSTRIPES** Number of stripes for parallel encoding
+     @param propId Property identifier from cv::VideoWriterProperties (eg. cv::VIDEOWRITER_PROP_QUALITY)
+     or one of @ref videoio_flags_others
 
-     @note When querying a property that is not supported by the backend used by the VideoWriter
-     class, value 0 is returned.
+     @return Value for the specified property. Value 0 is returned when querying a property that is
+     not supported by the backend used by the VideoWriter instance.
      */
     CV_WRAP virtual double get(int propId) const;
 
     /** @brief Concatenates 4 chars to a fourcc code
 
+    @return a fourcc code
+
     This static method constructs the fourcc code of the codec to be used in the constructor
     VideoWriter::VideoWriter or VideoWriter::open.
      */
@@ -677,4 +932,4 @@ template<> CV_EXPORTS void DefaultDeleter<CvVideoWriter>::operator ()(CvVideoWri
 
 } // cv
 
-#endif //__OPENCV_VIDEOIO_HPP__
+#endif //OPENCV_VIDEOIO_HPP
diff --git a/modules/videoio/include/opencv2/videoio/cap_ios.h b/modules/videoio/include/opencv2/videoio/cap_ios.h
index 1a9875b..c90ad2e 100644
--- a/modules/videoio/include/opencv2/videoio/cap_ios.h
+++ b/modules/videoio/include/opencv2/videoio/cap_ios.h
@@ -41,31 +41,13 @@
 
 @interface CvAbstractCamera : NSObject
 {
-    AVCaptureSession* captureSession;
-    AVCaptureConnection* videoCaptureConnection;
-    AVCaptureVideoPreviewLayer *captureVideoPreviewLayer;
-
     UIDeviceOrientation currentDeviceOrientation;
 
     BOOL cameraAvailable;
-    BOOL captureSessionLoaded;
-    BOOL running;
-    BOOL useAVCaptureVideoPreviewLayer;
-
-    AVCaptureDevicePosition defaultAVCaptureDevicePosition;
-    AVCaptureVideoOrientation defaultAVCaptureVideoOrientation;
-    NSString *const defaultAVCaptureSessionPreset;
-
-    int defaultFPS;
-
-    UIView* parentView;
-
-    int imageWidth;
-    int imageHeight;
 }
 
- at property (nonatomic, retain) AVCaptureSession* captureSession;
- at property (nonatomic, retain) AVCaptureConnection* videoCaptureConnection;
+ at property (nonatomic, strong) AVCaptureSession* captureSession;
+ at property (nonatomic, strong) AVCaptureConnection* videoCaptureConnection;
 
 @property (nonatomic, readonly) BOOL running;
 @property (nonatomic, readonly) BOOL captureSessionLoaded;
@@ -80,7 +62,7 @@
 @property (nonatomic, assign) int imageWidth;
 @property (nonatomic, assign) int imageHeight;
 
- at property (nonatomic, retain) UIView* parentView;
+ at property (nonatomic, strong) UIView* parentView;
 
 - (void)start;
 - (void)stop;
@@ -121,26 +103,18 @@
     dispatch_queue_t videoDataOutputQueue;
     CALayer *customPreviewLayer;
 
-    BOOL grayscaleMode;
-
-    BOOL recordVideo;
-    BOOL rotateVideo;
-    AVAssetWriterInput* recordAssetWriterInput;
-    AVAssetWriterInputPixelBufferAdaptor* recordPixelBufferAdaptor;
-    AVAssetWriter* recordAssetWriter;
-
     CMTime lastSampleTime;
 
 }
 
- at property (nonatomic, assign) id<CvVideoCameraDelegate> delegate;
+ at property (nonatomic, weak) id<CvVideoCameraDelegate> delegate;
 @property (nonatomic, assign) BOOL grayscaleMode;
 
 @property (nonatomic, assign) BOOL recordVideo;
 @property (nonatomic, assign) BOOL rotateVideo;
- at property (nonatomic, retain) AVAssetWriterInput* recordAssetWriterInput;
- at property (nonatomic, retain) AVAssetWriterInputPixelBufferAdaptor* recordPixelBufferAdaptor;
- at property (nonatomic, retain) AVAssetWriter* recordAssetWriter;
+ at property (nonatomic, strong) AVAssetWriterInput* recordAssetWriterInput;
+ at property (nonatomic, strong) AVAssetWriterInputPixelBufferAdaptor* recordPixelBufferAdaptor;
+ at property (nonatomic, strong) AVAssetWriter* recordAssetWriter;
 
 - (void)adjustLayoutToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation;
 - (void)layoutPreviewLayer;
@@ -167,7 +141,7 @@
     AVCaptureStillImageOutput *stillImageOutput;
 }
 
- at property (nonatomic, assign) id<CvPhotoCameraDelegate> delegate;
+ at property (nonatomic, weak) id<CvPhotoCameraDelegate> delegate;
 
 - (void)takePicture;
 
diff --git a/modules/videoio/include/opencv2/videoio/videoio_c.h b/modules/videoio/include/opencv2/videoio/videoio_c.h
index 47f46fa..024633c 100644
--- a/modules/videoio/include/opencv2/videoio/videoio_c.h
+++ b/modules/videoio/include/opencv2/videoio/videoio_c.h
@@ -39,8 +39,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_VIDEOIO_H__
-#define __OPENCV_VIDEOIO_H__
+#ifndef OPENCV_VIDEOIO_H
+#define OPENCV_VIDEOIO_H
 
 #include "opencv2/core/core_c.h"
 
@@ -57,13 +57,18 @@ extern "C" {
 *                         Working with Video Files and Cameras                           *
 \****************************************************************************************/
 
-/* "black box" capture structure */
+/** @brief "black box" capture structure
+
+In C++ use cv::VideoCapture
+*/
 typedef struct CvCapture CvCapture;
 
-/* start capturing frames from video file */
+/** @brief start capturing frames from video file
+*/
 CVAPI(CvCapture*) cvCreateFileCapture( const char* filename );
 
-/* start capturing frames from video file. allows specifying a preferred API to use */
+/** @brief start capturing frames from video file. allows specifying a preferred API to use
+*/
 CVAPI(CvCapture*) cvCreateFileCaptureWithPreference( const char* filename , int apiPreference);
 
 enum
@@ -117,27 +122,37 @@ enum
     CV_CAP_GPHOTO2 = 1700,
     CV_CAP_GSTREAMER = 1800, // GStreamer
     CV_CAP_FFMPEG = 1900,    // FFMPEG
-    CV_CAP_IMAGES = 2000     // OpenCV Image Sequence (e.g. img_%02d.jpg)
+    CV_CAP_IMAGES = 2000,    // OpenCV Image Sequence (e.g. img_%02d.jpg)
+
+    CV_CAP_ARAVIS = 2100     // Aravis GigE SDK
 };
 
-/* start capturing frames from camera: index = camera_index + domain_offset (CV_CAP_*) */
+/** @brief start capturing frames from camera: index = camera_index + domain_offset (CV_CAP_*)
+*/
 CVAPI(CvCapture*) cvCreateCameraCapture( int index );
 
-/* grab a frame, return 1 on success, 0 on fail.
-  this function is thought to be fast               */
+/** @brief grab a frame, return 1 on success, 0 on fail.
+
+  this function is thought to be fast
+*/
 CVAPI(int) cvGrabFrame( CvCapture* capture );
 
-/* get the frame grabbed with cvGrabFrame(..)
+/** @brief get the frame grabbed with cvGrabFrame(..)
+
   This function may apply some frame processing like
   frame decompression, flipping etc.
-  !!!DO NOT RELEASE or MODIFY the retrieved frame!!! */
+  @warning !!!DO NOT RELEASE or MODIFY the retrieved frame!!!
+*/
 CVAPI(IplImage*) cvRetrieveFrame( CvCapture* capture, int streamIdx CV_DEFAULT(0) );
 
-/* Just a combination of cvGrabFrame and cvRetrieveFrame
-   !!!DO NOT RELEASE or MODIFY the retrieved frame!!!      */
+/** @brief Just a combination of cvGrabFrame and cvRetrieveFrame
+
+  @warning !!!DO NOT RELEASE or MODIFY the retrieved frame!!!
+*/
 CVAPI(IplImage*) cvQueryFrame( CvCapture* capture );
 
-/* stop capturing/reading and free resources */
+/** @brief stop capturing/reading and free resources
+*/
 CVAPI(void) cvReleaseCapture( CvCapture** capture );
 
 enum
@@ -200,7 +215,8 @@ enum
     // OpenNI map generators
     CV_CAP_OPENNI_DEPTH_GENERATOR = 1 << 31,
     CV_CAP_OPENNI_IMAGE_GENERATOR = 1 << 30,
-    CV_CAP_OPENNI_GENERATORS_MASK = CV_CAP_OPENNI_DEPTH_GENERATOR + CV_CAP_OPENNI_IMAGE_GENERATOR,
+    CV_CAP_OPENNI_IR_GENERATOR    = 1 << 29,
+    CV_CAP_OPENNI_GENERATORS_MASK = CV_CAP_OPENNI_DEPTH_GENERATOR + CV_CAP_OPENNI_IMAGE_GENERATOR + CV_CAP_OPENNI_IR_GENERATOR,
 
     // Properties of cameras available through OpenNI interfaces
     CV_CAP_PROP_OPENNI_OUTPUT_MODE     = 100,
@@ -222,10 +238,12 @@ enum
 
     CV_CAP_OPENNI_IMAGE_GENERATOR_PRESENT         = CV_CAP_OPENNI_IMAGE_GENERATOR + CV_CAP_PROP_OPENNI_GENERATOR_PRESENT,
     CV_CAP_OPENNI_IMAGE_GENERATOR_OUTPUT_MODE     = CV_CAP_OPENNI_IMAGE_GENERATOR + CV_CAP_PROP_OPENNI_OUTPUT_MODE,
+    CV_CAP_OPENNI_DEPTH_GENERATOR_PRESENT         = CV_CAP_OPENNI_DEPTH_GENERATOR + CV_CAP_PROP_OPENNI_GENERATOR_PRESENT,
     CV_CAP_OPENNI_DEPTH_GENERATOR_BASELINE        = CV_CAP_OPENNI_DEPTH_GENERATOR + CV_CAP_PROP_OPENNI_BASELINE,
     CV_CAP_OPENNI_DEPTH_GENERATOR_FOCAL_LENGTH    = CV_CAP_OPENNI_DEPTH_GENERATOR + CV_CAP_PROP_OPENNI_FOCAL_LENGTH,
     CV_CAP_OPENNI_DEPTH_GENERATOR_REGISTRATION    = CV_CAP_OPENNI_DEPTH_GENERATOR + CV_CAP_PROP_OPENNI_REGISTRATION,
     CV_CAP_OPENNI_DEPTH_GENERATOR_REGISTRATION_ON = CV_CAP_OPENNI_DEPTH_GENERATOR_REGISTRATION,
+    CV_CAP_OPENNI_IR_GENERATOR_PRESENT            = CV_CAP_OPENNI_IR_GENERATOR + CV_CAP_PROP_OPENNI_GENERATOR_PRESENT,
 
     // Properties of cameras available through GStreamer interface
     CV_CAP_GSTREAMER_QUEUE_LENGTH           = 200, // default is 1
@@ -274,6 +292,8 @@ enum
     CV_CAP_PROP_XI_DECIMATION_VERTICAL                          = 432, // Vertical Decimation - vertical sub-sampling of the image - reduces the vertical resolution of the image by the specified vertical decimation factor.
     CV_CAP_PROP_XI_DECIMATION_HORIZONTAL                        = 433, // Horizontal Decimation - horizontal sub-sampling of the image - reduces the horizontal resolution of the image by the specified vertical decimation factor.
     CV_CAP_PROP_XI_DECIMATION_PATTERN                           = 434, // Decimation pattern type.
+    CV_CAP_PROP_XI_TEST_PATTERN_GENERATOR_SELECTOR              = 587, // Selects which test pattern generator is controlled by the TestPattern feature.
+    CV_CAP_PROP_XI_TEST_PATTERN                                 = 588, // Selects which test pattern type is generated by the selected generator.
     CV_CAP_PROP_XI_IMAGE_DATA_FORMAT                            = 435, // Output data format.
     CV_CAP_PROP_XI_SHUTTER_TYPE                                 = 436, // Change sensor shutter type(CMOS sensor).
     CV_CAP_PROP_XI_SENSOR_TAPS                                  = 437, // Number of taps
@@ -287,6 +307,8 @@ enum
     CV_CAP_PROP_XI_WB_KB                                        = 450, // White balance blue coefficient
     CV_CAP_PROP_XI_WIDTH                                        = 451, // Width of the Image provided by the device (in pixels).
     CV_CAP_PROP_XI_HEIGHT                                       = 452, // Height of the Image provided by the device (in pixels).
+    CV_CAP_PROP_XI_REGION_SELECTOR                              = 589, // Selects Region in Multiple ROI which parameters are set by width, height, ... ,region mode
+    CV_CAP_PROP_XI_REGION_MODE                                  = 595, // Activates/deactivates Region selected by Region Selector
     CV_CAP_PROP_XI_LIMIT_BANDWIDTH                              = 459, // Set/get bandwidth(datarate)(in Megabits)
     CV_CAP_PROP_XI_SENSOR_DATA_BIT_DEPTH                        = 460, // Sensor output data bit depth.
     CV_CAP_PROP_XI_OUTPUT_DATA_BIT_DEPTH                        = 461, // Device output data bit depth.
@@ -298,6 +320,8 @@ enum
     CV_CAP_PROP_XI_TARGET_TEMP                                  = 467, // Set sensor target temperature for cooling.
     CV_CAP_PROP_XI_CHIP_TEMP                                    = 468, // Camera sensor temperature
     CV_CAP_PROP_XI_HOUS_TEMP                                    = 469, // Camera housing tepmerature
+    CV_CAP_PROP_XI_HOUS_BACK_SIDE_TEMP                          = 590, // Camera housing back side tepmerature
+    CV_CAP_PROP_XI_SENSOR_BOARD_TEMP                            = 596, // Camera sensor board temperature
     CV_CAP_PROP_XI_CMS                                          = 470, // Mode of color management system.
     CV_CAP_PROP_XI_APPLY_CMS                                    = 471, // Enable applying of CMS profiles to xiGetImage (see XI_PRM_INPUT_CMS_PROFILE, XI_PRM_OUTPUT_CMS_PROFILE).
     CV_CAP_PROP_XI_IMAGE_IS_COLOR                               = 474, // Returns 1 for color cameras.
@@ -365,6 +389,7 @@ enum
     CV_CAP_PROP_XI_RECENT_FRAME                                 = 553, // GetImage returns most recent frame
     CV_CAP_PROP_XI_DEVICE_RESET                                 = 554, // Resets the camera to default state.
     CV_CAP_PROP_XI_COLUMN_FPN_CORRECTION                        = 555, // Correction of column FPN
+    CV_CAP_PROP_XI_ROW_FPN_CORRECTION                           = 591, // Correction of row FPN
     CV_CAP_PROP_XI_SENSOR_MODE                                  = 558, // Current sensor mode. Allows to select sensor mode by one integer. Setting of this parameter affects: image dimensions and downsampling.
     CV_CAP_PROP_XI_HDR                                          = 559, // Enable High Dynamic Range feature.
     CV_CAP_PROP_XI_HDR_KNEEPOINT_COUNT                          = 560, // The number of kneepoints in the PWLR.
@@ -376,12 +401,15 @@ enum
     CV_CAP_PROP_XI_HW_REVISION                                  = 571, // Returns hardware revision number.
     CV_CAP_PROP_XI_DEBUG_LEVEL                                  = 572, // Set debug level
     CV_CAP_PROP_XI_AUTO_BANDWIDTH_CALCULATION                   = 573, // Automatic bandwidth calculation,
+    CV_CAP_PROP_XI_FFS_FILE_ID                                  = 594, // File number.
+    CV_CAP_PROP_XI_FFS_FILE_SIZE                                = 580, // Size of file.
     CV_CAP_PROP_XI_FREE_FFS_SIZE                                = 581, // Size of free camera FFS.
     CV_CAP_PROP_XI_USED_FFS_SIZE                                = 582, // Size of used camera FFS.
     CV_CAP_PROP_XI_FFS_ACCESS_KEY                               = 583, // Setting of key enables file operations on some cameras.
     CV_CAP_PROP_XI_SENSOR_FEATURE_SELECTOR                      = 585, // Selects the current feature which is accessible by XI_PRM_SENSOR_FEATURE_VALUE.
     CV_CAP_PROP_XI_SENSOR_FEATURE_VALUE                         = 586, // Allows access to sensor feature value currently selected by XI_PRM_SENSOR_FEATURE_SELECTOR.
 
+
     // Properties for Android cameras
     CV_CAP_PROP_ANDROID_FLASH_MODE = 8001,
     CV_CAP_PROP_ANDROID_FOCUS_MODE = 8002,
@@ -445,7 +473,10 @@ enum
 
     // Data given from RGB image generator.
     CV_CAP_OPENNI_BGR_IMAGE                 = 5,
-    CV_CAP_OPENNI_GRAY_IMAGE                = 6
+    CV_CAP_OPENNI_GRAY_IMAGE                = 6,
+
+    // Data given from IR image generator.
+    CV_CAP_OPENNI_IR_IMAGE                  = 7
 };
 
 // Supported output modes of OpenNI image generator
@@ -483,51 +514,74 @@ enum
     CV_CAP_PROP_VIEWFINDER                = 17010  // Enter liveview mode.
 };
 
-/* retrieve or set capture properties */
+/** @brief retrieve capture properties
+*/
 CVAPI(double) cvGetCaptureProperty( CvCapture* capture, int property_id );
+/** @brief set capture properties
+*/
 CVAPI(int)    cvSetCaptureProperty( CvCapture* capture, int property_id, double value );
 
-// Return the type of the capturer (eg, CV_CAP_V4W, CV_CAP_UNICAP), which is unknown if created with CV_CAP_ANY
+/** @brief Return the type of the capturer (eg, ::CV_CAP_VFW, ::CV_CAP_UNICAP)
+
+It is unknown if created with ::CV_CAP_ANY
+*/
 CVAPI(int)    cvGetCaptureDomain( CvCapture* capture);
 
-/* "black box" video file writer structure */
+/** @brief "black box" video file writer structure
+
+In C++ use cv::VideoWriter
+*/
 typedef struct CvVideoWriter CvVideoWriter;
 
+//! Macro to construct the fourcc code of the codec. Same as CV_FOURCC()
 #define CV_FOURCC_MACRO(c1, c2, c3, c4) (((c1) & 255) + (((c2) & 255) << 8) + (((c3) & 255) << 16) + (((c4) & 255) << 24))
 
+/** @brief Constructs the fourcc code of the codec function
+
+Simply call it with 4 chars fourcc code like `CV_FOURCC('I', 'Y', 'U', 'V')`
+
+List of codes can be obtained at [Video Codecs by FOURCC](http://www.fourcc.org/codecs.php) page.
+FFMPEG backend with MP4 container natively uses other values as fourcc code:
+see [ObjectType](http://www.mp4ra.org/codecs.html).
+*/
 CV_INLINE int CV_FOURCC(char c1, char c2, char c3, char c4)
 {
     return CV_FOURCC_MACRO(c1, c2, c3, c4);
 }
 
-#define CV_FOURCC_PROMPT -1  /* Open Codec Selection Dialog (Windows only) */
-#define CV_FOURCC_DEFAULT CV_FOURCC('I', 'Y', 'U', 'V') /* Use default codec for specified filename (Linux only) */
+//! (Windows only) Open Codec Selection Dialog
+#define CV_FOURCC_PROMPT -1
+//! (Linux only) Use default codec for specified filename
+#define CV_FOURCC_DEFAULT CV_FOURCC('I', 'Y', 'U', 'V')
 
-/* initialize video file writer */
+/** @brief initialize video file writer
+*/
 CVAPI(CvVideoWriter*) cvCreateVideoWriter( const char* filename, int fourcc,
                                            double fps, CvSize frame_size,
                                            int is_color CV_DEFAULT(1));
 
-/* write frame to video file */
+/** @brief write frame to video file
+*/
 CVAPI(int) cvWriteFrame( CvVideoWriter* writer, const IplImage* image );
 
-/* close video file writer */
+/** @brief close video file writer
+*/
 CVAPI(void) cvReleaseVideoWriter( CvVideoWriter** writer );
 
-/****************************************************************************************\
-*                              Obsolete functions/synonyms                               *
-\****************************************************************************************/
-
-#define cvCaptureFromFile cvCreateFileCapture
-#define cvCaptureFromCAM cvCreateCameraCapture
-#define cvCaptureFromAVI cvCaptureFromFile
-#define cvCreateAVIWriter cvCreateVideoWriter
-#define cvWriteToAVI cvWriteFrame
+// ***************************************************************************************
+//! @name Obsolete functions/synonyms
+//! @{
+#define cvCaptureFromCAM cvCreateCameraCapture //!< @deprecated use cvCreateCameraCapture() instead
+#define cvCaptureFromFile cvCreateFileCapture  //!< @deprecated use cvCreateFileCapture() instead
+#define cvCaptureFromAVI cvCaptureFromFile     //!< @deprecated use cvCreateFileCapture() instead
+#define cvCreateAVIWriter cvCreateVideoWriter  //!< @deprecated use cvCreateVideoWriter() instead
+#define cvWriteToAVI cvWriteFrame              //!< @deprecated use cvWriteFrame() instead
+//!  @} Obsolete...
 
-/** @} videoio_c */
+//! @} videoio_c
 
 #ifdef __cplusplus
 }
 #endif
 
-#endif //__OPENCV_VIDEOIO_H__
+#endif //OPENCV_VIDEOIO_H
diff --git a/modules/videoio/src/cap.cpp b/modules/videoio/src/cap.cpp
index 3211bad..f1218fd 100644
--- a/modules/videoio/src/cap.cpp
+++ b/modules/videoio/src/cap.cpp
@@ -117,6 +117,36 @@ CV_IMPL int cvGetCaptureDomain( CvCapture* capture)
     return capture ? capture->getCaptureDomain() : 0;
 }
 
+static bool get_capture_debug_flag()
+{
+    static bool initialized = false;
+    static bool flag = false;
+    if (!initialized)
+    {
+#ifndef NO_GETENV
+        flag = getenv("OPENCV_VIDEOCAPTURE_DEBUG") ? true : false; // TODO Use getBoolParameter
+#endif
+        initialized = true;
+    }
+    return flag;
+}
+
+#define TRY_OPEN(capture, backend_func) \
+{ \
+    if (!capture) \
+        try { \
+            if (get_capture_debug_flag()) fprintf(stderr, "VIDEOIO(%s): trying ...\n", #backend_func); \
+            capture = backend_func; \
+            if (get_capture_debug_flag()) fprintf(stderr, "VIDEOIO(%s): result=%p ...\n", #backend_func, capture); \
+        } catch (const cv::Exception& e) { \
+            fprintf(stderr, "VIDEOIO(%s): raised OpenCV exception:\n\n%s\n", #backend_func, e.what()); \
+        } catch (const std::exception& e) { \
+            fprintf(stderr, "VIDEOIO(%s): raised C++ exception:\n\n%s\n", #backend_func, e.what()); \
+        } catch (...) { \
+            fprintf(stderr, "VIDEOIO(%s): raised unknown C++ exception!\n\n", #backend_func); \
+        } \
+}
+
 
 /**
  * Camera dispatching method: index is the camera number.
@@ -144,122 +174,109 @@ CV_IMPL CvCapture * cvCreateCameraCapture (int index)
 
 #ifdef HAVE_MSMF
     case CV_CAP_MSMF:
-        if (!capture)
-            capture = cvCreateCameraCapture_MSMF(index);
+        TRY_OPEN(capture, cvCreateCameraCapture_MSMF(index))
         if (pref) break;
 #endif
 #ifdef HAVE_TYZX
     case CV_CAP_STEREO:
-        if (!capture)
-            capture = cvCreateCameraCapture_TYZX(index);
+        TRY_OPEN(capture, cvCreateCameraCapture_TYZX(index))
         if (pref) break;
 #endif
     case CV_CAP_VFW:
 #ifdef HAVE_VFW
-        if (!capture)
-            capture = cvCreateCameraCapture_VFW(index);
+        TRY_OPEN(capture, cvCreateCameraCapture_VFW(index))
 #endif
+
 #if defined HAVE_LIBV4L || defined HAVE_CAMV4L || defined HAVE_CAMV4L2 || defined HAVE_VIDEOIO
-        if (!capture)
-            capture = cvCreateCameraCapture_V4L(index);
+        TRY_OPEN(capture, cvCreateCameraCapture_V4L(index))
 #endif
+        if (pref) break; // CV_CAP_VFW
 
 #ifdef HAVE_GSTREAMER
-        if (!capture)
-            capture = cvCreateCapture_GStreamer(CV_CAP_GSTREAMER_V4L2,
-                                                reinterpret_cast<char *>(index));
+        TRY_OPEN(capture, cvCreateCapture_GStreamer(CV_CAP_GSTREAMER_V4L2, reinterpret_cast<char *>(index)))
 
-        if (!capture)
-            capture = cvCreateCapture_GStreamer(CV_CAP_GSTREAMER_V4L,
-                                                reinterpret_cast<char *>(index));
+        TRY_OPEN(capture, cvCreateCapture_GStreamer(CV_CAP_GSTREAMER_V4L, reinterpret_cast<char *>(index)))
 #endif
-        if (pref) break; // CV_CAP_VFW
 
     case CV_CAP_FIREWIRE:
 #ifdef HAVE_DC1394_2
-        if (!capture)
-            capture = cvCreateCameraCapture_DC1394_2(index);
+        TRY_OPEN(capture, cvCreateCameraCapture_DC1394_2(index))
 #endif
 
 #ifdef HAVE_DC1394
-        if (!capture)
-            capture = cvCreateCameraCapture_DC1394(index);
+        TRY_OPEN(capture, cvCreateCameraCapture_DC1394(index))
 #endif
 
 #ifdef HAVE_CMU1394
-        if (!capture)
-            capture = cvCreateCameraCapture_CMU(index);
+        TRY_OPEN(capture, cvCreateCameraCapture_CMU(index))
 #endif
 
 #if defined(HAVE_GSTREAMER) && 0
         // Re-enable again when gstreamer 1394 support will land in the backend code
-        if (!capture)
-            capture = cvCreateCapture_GStreamer(CV_CAP_GSTREAMER_1394, 0);
+        TRY_OPEN(capture, cvCreateCapture_GStreamer(CV_CAP_GSTREAMER_1394, 0))
 #endif
+
         if (pref) break; // CV_CAP_FIREWIRE
 
 #ifdef HAVE_MIL
     case CV_CAP_MIL:
-        if (!capture)
-            capture = cvCreateCameraCapture_MIL(index);
+        TRY_OPEN(capture, cvCreateCameraCapture_MIL(index))
         if (pref) break;
 #endif
 
 #if defined(HAVE_QUICKTIME) || defined(HAVE_QTKIT)
     case CV_CAP_QT:
-        if (!capture)
-            capture = cvCreateCameraCapture_QT(index);
+        TRY_OPEN(capture, cvCreateCameraCapture_QT(index))
         if (pref) break;
 #endif
 
 #ifdef HAVE_UNICAP
     case CV_CAP_UNICAP:
-        if (!capture)
-            capture = cvCreateCameraCapture_Unicap(index);
+        TRY_OPEN(capture, cvCreateCameraCapture_Unicap(index))
         if (pref) break;
 #endif
 
 #ifdef HAVE_PVAPI
     case CV_CAP_PVAPI:
-        if (!capture)
-            capture = cvCreateCameraCapture_PvAPI(index);
+        TRY_OPEN(capture, cvCreateCameraCapture_PvAPI(index))
         if (pref) break;
 #endif
 
 #ifdef HAVE_OPENNI
     case CV_CAP_OPENNI:
-        if (!capture)
-            capture = cvCreateCameraCapture_OpenNI(index);
+        TRY_OPEN(capture, cvCreateCameraCapture_OpenNI(index))
         if (pref) break;
 #endif
 
 #ifdef HAVE_OPENNI2
     case CV_CAP_OPENNI2:
-        if (!capture)
-            capture = cvCreateCameraCapture_OpenNI2(index);
+        TRY_OPEN(capture, cvCreateCameraCapture_OpenNI2(index))
         if (pref) break;
 #endif
 
 #ifdef HAVE_XIMEA
     case CV_CAP_XIAPI:
-        if (!capture)
-            capture = cvCreateCameraCapture_XIMEA(index);
+        TRY_OPEN(capture, cvCreateCameraCapture_XIMEA(index))
         if (pref) break;
 #endif
 
 #ifdef HAVE_AVFOUNDATION
     case CV_CAP_AVFOUNDATION:
-        if (!capture)
-            capture = cvCreateCameraCapture_AVFoundation(index);
+        TRY_OPEN(capture, cvCreateCameraCapture_AVFoundation(index))
         if (pref) break;
 #endif
 
 #ifdef HAVE_GIGE_API
     case CV_CAP_GIGANETIX:
-        if (!capture)
-            capture = cvCreateCameraCapture_Giganetix(index);
+        TRY_OPEN(capture, cvCreateCameraCapture_Giganetix(index))
         if (pref) break; // CV_CAP_GIGANETIX
 #endif
+
+#ifdef HAVE_ARAVIS_API
+    case CV_CAP_ARAVIS:
+        TRY_OPEN(capture, cvCreateCameraCapture_Aravis(index))
+        if (pref) break;
+#endif
     }
 
     return capture;
@@ -281,61 +298,62 @@ CV_IMPL CvCapture * cvCreateFileCaptureWithPreference (const char * filename, in
 
 #ifdef HAVE_FFMPEG
     case CV_CAP_FFMPEG:
-        if (! result)
-            result = cvCreateFileCapture_FFMPEG_proxy (filename);
+        TRY_OPEN(result, cvCreateFileCapture_FFMPEG_proxy (filename))
         if (apiPreference) break;
 #endif
 
-#ifdef HAVE_VFW
     case CV_CAP_VFW:
-        if (! result)
-            result = cvCreateFileCapture_VFW (filename);
-        if (apiPreference) break;
+#ifdef HAVE_VFW
+        TRY_OPEN(result, cvCreateFileCapture_VFW (filename))
+#endif
+
+#if defined HAVE_LIBV4L || defined HAVE_CAMV4L || defined HAVE_CAMV4L2 || defined HAVE_VIDEOIO
+        TRY_OPEN(result, cvCreateCameraCapture_V4L(filename))
 #endif
+        if (apiPreference) break;
 
     case CV_CAP_MSMF:
 #ifdef HAVE_MSMF
-        if (! result)
-            result = cvCreateFileCapture_MSMF (filename);
+        TRY_OPEN(result, cvCreateFileCapture_MSMF (filename))
 #endif
 
 #ifdef HAVE_XINE
-        if (! result)
-            result = cvCreateFileCapture_XINE (filename);
+        TRY_OPEN(result, cvCreateFileCapture_XINE (filename))
 #endif
         if (apiPreference) break;
 
 #ifdef HAVE_GSTREAMER
     case CV_CAP_GSTREAMER:
-        if (! result)
-            result = cvCreateCapture_GStreamer (CV_CAP_GSTREAMER_FILE, filename);
+        TRY_OPEN(result, cvCreateCapture_GStreamer (CV_CAP_GSTREAMER_FILE, filename))
         if (apiPreference) break;
 #endif
 
 #if defined(HAVE_QUICKTIME) || defined(HAVE_QTKIT)
     case CV_CAP_QT:
-        if (! result)
-            result = cvCreateFileCapture_QT (filename);
+        TRY_OPEN(result, cvCreateFileCapture_QT (filename))
         if (apiPreference) break;
 #endif
 
 #ifdef HAVE_AVFOUNDATION
     case CV_CAP_AVFOUNDATION:
-        if (! result)
-            result = cvCreateFileCapture_AVFoundation (filename);
+        TRY_OPEN(result, cvCreateFileCapture_AVFoundation (filename))
         if (apiPreference) break;
 #endif
 
 #ifdef HAVE_OPENNI
     case CV_CAP_OPENNI:
-        if (! result)
-            result = cvCreateFileCapture_OpenNI (filename);
+        TRY_OPEN(result, cvCreateFileCapture_OpenNI (filename))
+        if (apiPreference) break;
+#endif
+
+#ifdef HAVE_OPENNI2
+    case CV_CAP_OPENNI2:
+        TRY_OPEN(result, cvCreateFileCapture_OpenNI2 (filename))
         if (apiPreference) break;
 #endif
 
     case CV_CAP_IMAGES:
-        if (! result)
-            result = cvCreateFileCapture_Images (filename);
+        TRY_OPEN(result, cvCreateFileCapture_Images (filename))
     }
 
     return result;
@@ -353,63 +371,47 @@ CV_IMPL CvCapture * cvCreateFileCapture (const char * filename)
 CV_IMPL CvVideoWriter* cvCreateVideoWriter( const char* filename, int fourcc,
                                             double fps, CvSize frameSize, int is_color )
 {
+    // If none of the writers is used
+    // these statements suppress 'unused parameter' warnings.
+    CV_UNUSED(frameSize);
+    CV_UNUSED(is_color);
+
     //CV_FUNCNAME( "cvCreateVideoWriter" );
 
     CvVideoWriter *result = 0;
 
     if(!fourcc || !fps)
-        result = cvCreateVideoWriter_Images(filename);
+        TRY_OPEN(result, cvCreateVideoWriter_Images(filename))
 
 #ifdef HAVE_FFMPEG
-    if(!result)
-        result = cvCreateVideoWriter_FFMPEG_proxy (filename, fourcc, fps, frameSize, is_color);
+    TRY_OPEN(result, cvCreateVideoWriter_FFMPEG_proxy (filename, fourcc, fps, frameSize, is_color))
 #endif
 
 #ifdef HAVE_VFW
-    if(!result)
-        result = cvCreateVideoWriter_VFW(filename, fourcc, fps, frameSize, is_color);
+    TRY_OPEN(result, cvCreateVideoWriter_VFW(filename, fourcc, fps, frameSize, is_color))
 #endif
 
 #ifdef HAVE_MSMF
-    if (!result)
-        result = cvCreateVideoWriter_MSMF(filename, fourcc, fps, frameSize, is_color);
+    TRY_OPEN(result, cvCreateVideoWriter_MSMF(filename, fourcc, fps, frameSize, is_color))
 #endif
 
 /*  #ifdef HAVE_XINE
-    if(!result)
-        result = cvCreateVideoWriter_XINE(filename, fourcc, fps, frameSize, is_color);
+    TRY_OPEN(result, cvCreateVideoWriter_XINE(filename, fourcc, fps, frameSize, is_color))
     #endif
 */
 #ifdef HAVE_AVFOUNDATION
-    if (! result)
-        result = cvCreateVideoWriter_AVFoundation(filename, fourcc, fps, frameSize, is_color);
+    TRY_OPEN(result, cvCreateVideoWriter_AVFoundation(filename, fourcc, fps, frameSize, is_color))
 #endif
 
 #if defined(HAVE_QUICKTIME) || defined(HAVE_QTKIT)
-    if(!result)
-        result = cvCreateVideoWriter_QT(filename, fourcc, fps, frameSize, is_color);
+    TRY_OPEN(result, cvCreateVideoWriter_QT(filename, fourcc, fps, frameSize, is_color))
 #endif
 
 #ifdef HAVE_GSTREAMER
-    if (! result)
-        result = cvCreateVideoWriter_GStreamer(filename, fourcc, fps, frameSize, is_color);
-#endif
-
-#if !defined(HAVE_FFMPEG) && \
-    !defined(HAVE_VFW) && \
-    !defined(HAVE_MSMF) && \
-    !defined(HAVE_AVFOUNDATION) && \
-    !defined(HAVE_QUICKTIME) && \
-    !defined(HAVE_QTKIT) && \
-    !defined(HAVE_GSTREAMER)
-// If none of the writers is used
-// these statements suppress 'unused parameter' warnings.
-    (void)frameSize;
-    (void)is_color;
+    TRY_OPEN(result, cvCreateVideoWriter_GStreamer(filename, fourcc, fps, frameSize, is_color))
 #endif
 
-    if(!result)
-        result = cvCreateVideoWriter_Images(filename);
+    TRY_OPEN(result, cvCreateVideoWriter_Images(filename))
 
     return result;
 }
@@ -575,6 +577,8 @@ VideoCapture::~VideoCapture()
 
 bool VideoCapture::open(const String& filename, int apiPreference)
 {
+    CV_INSTRUMENT_REGION()
+
     if (isOpened()) release();
     icap = IVideoCapture_create(filename);
     if (!icap.empty())
@@ -586,11 +590,15 @@ bool VideoCapture::open(const String& filename, int apiPreference)
 
 bool VideoCapture::open(const String& filename)
 {
+    CV_INSTRUMENT_REGION()
+
     return open(filename, CAP_ANY);
 }
 
 bool VideoCapture::open(int index)
 {
+    CV_INSTRUMENT_REGION()
+
     if (isOpened()) release();
     icap = IVideoCapture_create(index);
     if (!icap.empty())
@@ -598,6 +606,11 @@ bool VideoCapture::open(int index)
     cap.reset(cvCreateCameraCapture(index));
     return isOpened();
 }
+bool  VideoCapture::open(int cameraNum, int apiPreference)
+{
+    cameraNum = cameraNum + apiPreference;
+    return open(cameraNum);
+}
 
 bool VideoCapture::isOpened() const
 {
@@ -612,6 +625,8 @@ void VideoCapture::release()
 
 bool VideoCapture::grab()
 {
+    CV_INSTRUMENT_REGION()
+
     if (!icap.empty())
         return icap->grabFrame();
     return cvGrabFrame(cap) != 0;
@@ -619,6 +634,8 @@ bool VideoCapture::grab()
 
 bool VideoCapture::retrieve(OutputArray image, int channel)
 {
+    CV_INSTRUMENT_REGION()
+
     if (!icap.empty())
         return icap->retrieveFrame(channel, image);
 
@@ -640,6 +657,8 @@ bool VideoCapture::retrieve(OutputArray image, int channel)
 
 bool VideoCapture::read(OutputArray image)
 {
+    CV_INSTRUMENT_REGION()
+
     if(grab())
         retrieve(image);
     else
@@ -677,6 +696,8 @@ VideoCapture& VideoCapture::operator >> (Mat& image)
 
 VideoCapture& VideoCapture::operator >> (UMat& image)
 {
+    CV_INSTRUMENT_REGION()
+
     read(image);
     return *this;
 }
@@ -717,6 +738,8 @@ VideoWriter::~VideoWriter()
 
 bool VideoWriter::open(const String& filename, int _fourcc, double fps, Size frameSize, bool isColor)
 {
+    CV_INSTRUMENT_REGION()
+
     if (isOpened()) release();
     iwriter = IVideoWriter_create(filename, _fourcc, fps, frameSize, isColor);
     if (!iwriter.empty())
@@ -747,6 +770,8 @@ double VideoWriter::get(int propId) const
 
 void VideoWriter::write(const Mat& image)
 {
+    CV_INSTRUMENT_REGION()
+
     if( iwriter )
         iwriter->write(image);
     else
@@ -758,6 +783,8 @@ void VideoWriter::write(const Mat& image)
 
 VideoWriter& VideoWriter::operator << (const Mat& image)
 {
+    CV_INSTRUMENT_REGION()
+
     write(image);
     return *this;
 }
diff --git a/modules/videoio/src/cap_aravis.cpp b/modules/videoio/src/cap_aravis.cpp
new file mode 100644
index 0000000..c272bee
--- /dev/null
+++ b/modules/videoio/src/cap_aravis.cpp
@@ -0,0 +1,592 @@
+////////////////////////////////////////////////////////////////////////////////////////
+//
+//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+//  By downloading, copying, installing or using the software you agree to this license.
+//  If you do not agree to this license, do not download, install,
+//  copy or use the software.
+//
+//
+//                        Intel License Agreement
+//                For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+//   * Redistribution's of source code must retain the above copyright notice,
+//     this list of conditions and the following disclaimer.
+//
+//   * Redistribution's in binary form must reproduce the above copyright notice,
+//     this list of conditions and the following disclaimer in the documentation
+//     and/or other materials provided with the distribution.
+//
+//   * The name of Intel Corporation may not be used to endorse or promote products
+//     derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//
+
+//
+// The code has been contributed by Arkadiusz Raj on 2016 Oct
+//
+
+#include "precomp.hpp"
+
+#ifdef HAVE_ARAVIS_API
+
+#include <arv.h>
+
+//
+// This file provides wrapper for using Aravis SDK library to access GigE Vision cameras.
+// Aravis library (version 0.4 or 0.6) shall be installed else this code will not be included in build.
+//
+// To include this module invoke cmake with -DWITH_ARAVIS=ON
+//
+// Please obvserve, that jumbo frames are required when high fps & 16bit data is selected.
+// (camera, switches/routers and the computer this software is running on)
+//
+// Basic usage: VideoCapture cap(CAP_ARAVIS + <camera id>);
+//
+// Supported properties:
+//  read/write
+//      CAP_PROP_AUTO_EXPOSURE(0|1)
+//      CAP_PROP_EXPOSURE(t), t in seconds
+//      CAP_PROP_GAIN(g), g >=0 or -1 for automatic control if CAP_PROP_AUTO_EXPOSURE is true
+//      CAP_PROP_FPS(f)
+//      CAP_PROP_FOURCC(type)
+//      CAP_PROP_BUFFERSIZE(n)
+//  read only:
+//      CAP_PROP_POS_MSEC
+//      CAP_PROP_FRAME_WIDTH
+//      CAP_PROP_FRAME_HEIGHT
+//
+//  Supported types of data:
+//      video/x-raw, fourcc:'GREY'  -> 8bit, 1 channel
+//      video/x-raw, fourcc:'Y800'  -> 8bit, 1 channel
+//      video/x-raw, fourcc:'Y12 '  -> 12bit, 1 channel
+//
+
+#define MODE_GREY   CV_FOURCC_MACRO('G','R','E','Y')
+#define MODE_Y800   CV_FOURCC_MACRO('Y','8','0','0')
+#define MODE_Y12    CV_FOURCC_MACRO('Y','1','2',' ')
+
+#define CLIP(a,b,c) (cv::max(cv::min((a),(c)),(b)))
+
+/********************* Capturing video from camera via Aravis *********************/
+
+class CvCaptureCAM_Aravis : public CvCapture
+{
+public:
+    CvCaptureCAM_Aravis();
+    virtual ~CvCaptureCAM_Aravis()
+    {
+        close();
+    }
+
+    virtual bool open(int);
+    virtual void close();
+    virtual double getProperty(int) const;
+    virtual bool setProperty(int, double);
+    virtual bool grabFrame();
+    virtual IplImage* retrieveFrame(int);
+    virtual int getCaptureDomain()
+    {
+        return CV_CAP_ARAVIS;
+    }
+
+protected:
+    bool create(int);
+    bool init_buffers();
+
+    void stopCapture();
+    bool startCapture();
+
+    bool getDeviceNameById(int id, std::string &device);
+
+    void autoExposureControl(IplImage*);
+
+    ArvCamera       *camera;                // Camera to control.
+    ArvStream       *stream;                // Object for video stream reception.
+    void            *framebuffer;           //
+
+    unsigned int    payload;                // Width x height x Pixel width.
+
+    int             widthMin;               // Camera sensor minium width.
+    int             widthMax;               // Camera sensor maximum width.
+    int             heightMin;              // Camera sensor minium height.
+    int             heightMax;              // Camera sensor maximum height.
+    bool            fpsAvailable;
+    double          fpsMin;                 // Camera minium fps.
+    double          fpsMax;                 // Camera maximum fps.
+    bool            gainAvailable;
+    double          gainMin;                // Camera minimum gain.
+    double          gainMax;                // Camera maximum gain.
+    bool            exposureAvailable;
+    double          exposureMin;            // Camera's minimum exposure time.
+    double          exposureMax;            // Camera's maximum exposure time.
+
+    bool            controlExposure;        // Flag if automatic exposure shall be done by this SW
+    bool            autoGain;
+    double          targetGrey;             // Target grey value (mid grey))
+
+    gint64          *pixelFormats;
+    guint           pixelFormatsCnt;
+
+
+    int             num_buffers;            // number of payload transmission buffers
+
+    ArvPixelFormat  pixelFormat;            // pixel format
+
+    int             xoffset;                // current frame region x offset
+    int             yoffset;                // current frame region y offset
+    int             width;                  // current frame width of frame
+    int             height;                 // current frame height of image
+
+    double          fps;                    // current value of fps
+    double          exposure;               // current value of exposure time
+    double          gain;                   // current value of gain
+    double          midGrey;                // current value of mid grey (brightness)
+
+    unsigned        frameID;                // current frame id
+    unsigned        prevFrameID;
+
+    IplImage        *frame;                 // local frame copy
+};
+
+
+CvCaptureCAM_Aravis::CvCaptureCAM_Aravis()
+{
+    camera = NULL;
+    stream = NULL;
+    framebuffer = NULL;
+
+    payload = 0;
+
+    widthMin = widthMax = heightMin = heightMax = 0;
+    xoffset = yoffset = width = height = 0;
+    fpsMin = fpsMax = gainMin = gainMax = exposureMin = exposureMax = 0;
+    controlExposure = false;
+    targetGrey = 0;
+    frameID = prevFrameID = 0;
+
+    num_buffers = 50;
+    frame = NULL;
+}
+
+void CvCaptureCAM_Aravis::close()
+{
+    if(camera) {
+        stopCapture();
+
+        g_object_unref(camera);
+        camera = NULL;
+    }
+}
+
+bool CvCaptureCAM_Aravis::getDeviceNameById(int id, std::string &device)
+{
+    arv_update_device_list();
+
+    if((id >= 0) && (id < (int)arv_get_n_devices())) {
+        device = arv_get_device_id(id);
+        return true;
+    }
+
+    return false;
+}
+
+bool CvCaptureCAM_Aravis::create( int index )
+{
+    std::string deviceName;
+    if(!getDeviceNameById(index, deviceName))
+        return false;
+
+    return NULL != (camera = arv_camera_new(deviceName.c_str()));
+}
+
+bool CvCaptureCAM_Aravis::init_buffers()
+{
+    if(stream) {
+        g_object_unref(stream);
+        stream = NULL;
+    }
+    if( (stream = arv_camera_create_stream(camera, NULL, NULL)) ) {
+        g_object_set(stream,
+            "socket-buffer", ARV_GV_STREAM_SOCKET_BUFFER_AUTO,
+            "socket-buffer-size", 0, NULL);
+        g_object_set(stream,
+            "packet-resend", ARV_GV_STREAM_PACKET_RESEND_NEVER, NULL);
+        g_object_set(stream,
+            "packet-timeout", (unsigned) 40000,
+            "frame-retention", (unsigned) 200000, NULL);
+
+        payload = arv_camera_get_payload (camera);
+
+        for (int i = 0; i < num_buffers; i++)
+            arv_stream_push_buffer(stream, arv_buffer_new(payload, NULL));
+
+        return true;
+    }
+
+    return false;
+}
+
+bool CvCaptureCAM_Aravis::open( int index )
+{
+    if(create(index)) {
+        // fetch properties bounds
+        pixelFormats = arv_camera_get_available_pixel_formats(camera, &pixelFormatsCnt);
+
+        arv_camera_get_width_bounds(camera, &widthMin, &widthMax);
+        arv_camera_get_height_bounds(camera, &heightMin, &heightMax);
+        arv_camera_set_region(camera, 0, 0, widthMax, heightMax);
+
+        if( (fpsAvailable = arv_camera_is_frame_rate_available(camera)) )
+            arv_camera_get_frame_rate_bounds(camera, &fpsMin, &fpsMax);
+        if( (gainAvailable = arv_camera_is_gain_available(camera)) )
+            arv_camera_get_gain_bounds (camera, &gainMin, &gainMax);
+        if( (exposureAvailable = arv_camera_is_exposure_time_available(camera)) )
+            arv_camera_get_exposure_time_bounds (camera, &exposureMin, &exposureMax);
+
+        // get initial values
+        pixelFormat = arv_camera_get_pixel_format(camera);
+        exposure = exposureAvailable ? arv_camera_get_exposure_time(camera) : 0;
+        gain = gainAvailable ? arv_camera_get_gain(camera) : 0;
+        fps = arv_camera_get_frame_rate(camera);
+
+        return startCapture();
+    }
+    return false;
+}
+
+bool CvCaptureCAM_Aravis::grabFrame()
+{
+    // remove content of previous frame
+    framebuffer = NULL;
+
+    if(stream) {
+        ArvBuffer *arv_buffer = NULL;
+        int max_tries = 10;
+        int tries = 0;
+        for(; tries < max_tries; tries ++) {
+            arv_buffer = arv_stream_timeout_pop_buffer (stream, 200000);
+            if (arv_buffer != NULL && arv_buffer_get_status (arv_buffer) != ARV_BUFFER_STATUS_SUCCESS) {
+                arv_stream_push_buffer (stream, arv_buffer);
+            } else break;
+        }
+        if(arv_buffer != NULL && tries < max_tries) {
+            size_t buffer_size;
+            framebuffer = (void*)arv_buffer_get_data (arv_buffer, &buffer_size);
+
+            // retieve image size properites
+            arv_buffer_get_image_region (arv_buffer, &xoffset, &yoffset, &width, &height);
+
+            // retieve image ID set by camera
+            frameID = arv_buffer_get_frame_id(arv_buffer);
+
+            arv_stream_push_buffer(stream, arv_buffer);
+            return true;
+        }
+    }
+    return false;
+}
+
+IplImage* CvCaptureCAM_Aravis::retrieveFrame(int)
+{
+    if(framebuffer) {
+        int depth = 0, channels = 0;
+        switch(pixelFormat) {
+            case ARV_PIXEL_FORMAT_MONO_8:
+                depth = IPL_DEPTH_8U;
+                channels = 1;
+                break;
+            case ARV_PIXEL_FORMAT_MONO_12:
+                depth = IPL_DEPTH_16U;
+                channels = 1;
+                break;
+        }
+        if(depth && channels) {
+            IplImage src;
+            cvInitImageHeader( &src, cvSize( width, height ), depth, channels, IPL_ORIGIN_TL, 4 );
+
+            cvSetData( &src, framebuffer, src.widthStep );
+            if( !frame ||
+                 frame->width != src.width ||
+                 frame->height != src.height ||
+                 frame->depth != src.depth ||
+                 frame->nChannels != src.nChannels) {
+
+                cvReleaseImage( &frame );
+                frame = cvCreateImage( cvGetSize(&src), src.depth, channels );
+            }
+            cvCopy(&src, frame);
+
+            if(controlExposure && ((frameID - prevFrameID) > 1)) {
+                // control exposure every second frame
+                // i.e. skip frame taken with previous exposure setup
+                autoExposureControl(frame);
+            }
+
+            return frame;
+        }
+    }
+    return NULL;
+}
+
+void CvCaptureCAM_Aravis::autoExposureControl(IplImage* image)
+{
+    // Software control of exposure parameters utilizing
+    // automatic change of exposure time & gain
+
+    // Priority is set as follows:
+    // - to increase brightness, first increase time then gain
+    // - to decrease brightness, first decrease gain then time
+
+    cv::Mat m = cv::cvarrToMat(image);
+
+    // calc mean value for luminance or green channel
+    double brightness = cv::mean(m)[image->nChannels > 1 ? 1 : 0];
+    if(brightness < 1) brightness = 1;
+
+    // mid point - 100 % means no change
+    static const double dmid = 100;
+
+    // distance from optimal value as a percentage
+    double d = (targetGrey * dmid) / brightness;
+    if(d >= dmid) d = ( d + (dmid * 2) ) / 3;
+
+    prevFrameID = frameID;
+    midGrey = brightness;
+
+    double maxe = 1e6 / fps;
+    double ne = CLIP( ( exposure * d ) / dmid, exposureMin, maxe);
+
+    // if change of value requires intervention
+    if(fabs(d-dmid) > 5) {
+        double ev, ng = 0;
+
+        if(gainAvailable && autoGain) {
+            ev = log( d / dmid ) / log(2);
+            ng = CLIP( gain + ev, gainMin, gainMax);
+
+            if( ng < gain ) {
+                // piority 1 - reduce gain
+                arv_camera_set_gain(camera, (gain = ng));
+                return;
+            }
+        }
+
+        if(exposureAvailable) {
+            if(abs(exposure - ne) > 2) {
+                // priority 2 - control of exposure time
+                arv_camera_set_exposure_time(camera, (exposure = ne) );
+                return;
+            }
+        }
+
+        if(gainAvailable && autoGain) {
+            if(exposureAvailable) {
+                // exposure at maximum - increase gain if possible
+                if(ng > gain && ng < gainMax && ne >= maxe) {
+                    arv_camera_set_gain(camera, (gain = ng));
+                    return;
+                }
+            } else {
+                // priority 3 - increase gain
+                arv_camera_set_gain(camera, (gain = ng));
+                return;
+            }
+        }
+    }
+
+    // if gain can be reduced - do it
+    if(gainAvailable && autoGain && exposureAvailable) {
+        if(gain > gainMin && exposure < maxe) {
+            exposure = CLIP( ne * 1.05, exposureMin, maxe);
+            arv_camera_set_exposure_time(camera, exposure );
+        }
+    }
+}
+
+double CvCaptureCAM_Aravis::getProperty( int property_id ) const
+{
+    switch(property_id) {
+        case CV_CAP_PROP_POS_MSEC:
+            return (double)frameID/fps;
+
+        case CV_CAP_PROP_FRAME_WIDTH:
+            return width;
+
+        case CV_CAP_PROP_FRAME_HEIGHT:
+            return height;
+
+        case CV_CAP_PROP_AUTO_EXPOSURE:
+            return (controlExposure ? 1 : 0);
+
+        case CV_CAP_PROP_EXPOSURE:
+            if(exposureAvailable) {
+                /* exposure time in seconds, like 1/100 s */
+                return arv_camera_get_exposure_time(camera) / 1e6;
+            }
+            break;
+
+        case CV_CAP_PROP_FPS:
+            if(fpsAvailable) {
+                return arv_camera_get_frame_rate(camera);
+            }
+            break;
+
+        case CV_CAP_PROP_GAIN:
+            if(gainAvailable) {
+                return arv_camera_get_gain(camera);
+            }
+            break;
+
+        case CV_CAP_PROP_FOURCC:
+            {
+                ArvPixelFormat currFormat = arv_camera_get_pixel_format(camera);
+                switch( currFormat ) {
+                    case ARV_PIXEL_FORMAT_MONO_8:
+                        return MODE_Y800;
+                    case ARV_PIXEL_FORMAT_MONO_12:
+                        return MODE_Y12;
+                }
+            }
+            break;
+
+        case CV_CAP_PROP_BUFFERSIZE:
+            if(stream) {
+                int in, out;
+                arv_stream_get_n_buffers(stream, &in, &out);
+                // return number of available buffers in Aravis output queue
+                return out;
+            }
+            break;
+    }
+    return -1.0;
+}
+
+bool CvCaptureCAM_Aravis::setProperty( int property_id, double value )
+{
+    switch(property_id) {
+        case CV_CAP_PROP_AUTO_EXPOSURE:
+            if(exposureAvailable || gainAvailable) {
+                if( (controlExposure = (bool)(int)value) ) {
+                    exposure = exposureAvailable ? arv_camera_get_exposure_time(camera) : 0;
+                    gain = gainAvailable ? arv_camera_get_gain(camera) : 0;
+                }
+            }
+            break;
+
+        case CV_CAP_PROP_EXPOSURE:
+            if(exposureAvailable) {
+                /* exposure time in seconds, like 1/100 s */
+                value *= 1e6; // -> from s to us
+
+                arv_camera_set_exposure_time(camera, exposure = CLIP(value, exposureMin, exposureMax));
+                break;
+            } else return false;
+
+        case CV_CAP_PROP_FPS:
+            if(fpsAvailable) {
+                arv_camera_set_frame_rate(camera, fps = CLIP(value, fpsMin, fpsMax));
+                break;
+            } else return false;
+
+        case CV_CAP_PROP_GAIN:
+            if(gainAvailable) {
+                if ( (autoGain = (-1 == value) ) )
+                    break;
+
+                arv_camera_set_gain(camera, gain = CLIP(value, gainMin, gainMax));
+                break;
+            } else return false;
+
+        case CV_CAP_PROP_FOURCC:
+            {
+                ArvPixelFormat newFormat = pixelFormat;
+                switch((int)value) {
+                    case MODE_GREY:
+                    case MODE_Y800:
+                        newFormat = ARV_PIXEL_FORMAT_MONO_8;
+                        targetGrey = 128;
+                        break;
+                    case MODE_Y12:
+                        newFormat = ARV_PIXEL_FORMAT_MONO_12;
+                        targetGrey = 2048;
+                        break;
+                }
+                if(newFormat != pixelFormat) {
+                    stopCapture();
+                    arv_camera_set_pixel_format(camera, pixelFormat = newFormat);
+                    startCapture();
+                }
+            }
+            break;
+
+        case CV_CAP_PROP_BUFFERSIZE:
+            {
+                int x = (int)value;
+                if((x > 0) && (x != num_buffers)) {
+                    stopCapture();
+                    num_buffers = x;
+                    startCapture();
+                }
+            }
+            break;
+
+
+        default:
+            return false;
+    }
+
+    return true;
+}
+
+void CvCaptureCAM_Aravis::stopCapture()
+{
+    arv_camera_stop_acquisition(camera);
+
+    if(stream) {
+        g_object_unref(stream);
+        stream = NULL;
+    }
+}
+
+bool CvCaptureCAM_Aravis::startCapture()
+{
+    if(init_buffers() ) {
+        arv_camera_set_acquisition_mode(camera, ARV_ACQUISITION_MODE_CONTINUOUS);
+        arv_device_set_string_feature_value(arv_camera_get_device (camera), "TriggerMode" , "Off");
+        arv_camera_start_acquisition(camera);
+
+        return true;
+    }
+    return false;
+}
+
+CvCapture* cvCreateCameraCapture_Aravis( int index )
+{
+    CvCaptureCAM_Aravis* capture = new CvCaptureCAM_Aravis;
+
+    if(capture->open(index)) {
+        return capture;
+    }
+
+    delete capture;
+    return NULL;
+}
+#endif
diff --git a/modules/videoio/src/cap_avfoundation_mac.mm b/modules/videoio/src/cap_avfoundation_mac.mm
new file mode 100644
index 0000000..ce6e3d0
--- /dev/null
+++ b/modules/videoio/src/cap_avfoundation_mac.mm
@@ -0,0 +1,1320 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+//                          License Agreement
+//                For Open Source Computer Vision Library
+//
+// Copyright (C) 2013, OpenCV Foundation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of the copyright holders may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the contributor be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*////////////////////////////////////////////////////////////////////////////////////////
+
+
+#include "precomp.hpp"
+#include "opencv2/imgproc.hpp"
+#include <stdio.h>
+#import <AVFoundation/AVFoundation.h>
+
+/********************** Declaration of class headers ************************/
+
+/*****************************************************************************
+ *
+ * CaptureDelegate Declaration.
+ *
+ * CaptureDelegate is notified on a separate thread by the OS whenever there
+ *   is a new frame. When "updateImage" is called from the main thread, it
+ *   copies this new frame into an IplImage, but only if this frame has not
+ *   been copied before. When "getOutput" is called from the main thread,
+ *   it gives the last copied IplImage.
+ *
+ *****************************************************************************/
+
+
+ at interface CaptureDelegate : NSObject <AVCaptureVideoDataOutputSampleBufferDelegate>
+{
+    NSCondition *mHasNewFrame;
+    CVPixelBufferRef mGrabbedPixels;
+    CVImageBufferRef mCurrentImageBuffer;
+    IplImage *mDeviceImage;
+    uint8_t  *mOutImagedata;
+    IplImage *mOutImage;
+    size_t    currSize;
+}
+
+- (void)captureOutput:(AVCaptureOutput *)captureOutput
+didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer
+       fromConnection:(AVCaptureConnection *)connection;
+
+- (BOOL)grabImageUntilDate: (NSDate *)limit;
+- (int)updateImage;
+- (IplImage*)getOutput;
+
+ at end
+
+/*****************************************************************************
+ *
+ * CvCaptureCAM Declaration.
+ *
+ * CvCaptureCAM is the instantiation of a capture source for cameras.
+ *
+ *****************************************************************************/
+
+class CvCaptureCAM : public CvCapture {
+public:
+    CvCaptureCAM(int cameraNum = -1) ;
+    ~CvCaptureCAM();
+    virtual bool grabFrame();
+    virtual IplImage* retrieveFrame(int);
+    virtual double getProperty(int property_id) const;
+    virtual bool setProperty(int property_id, double value);
+    virtual int didStart();
+
+
+private:
+    AVCaptureSession            *mCaptureSession;
+    AVCaptureDeviceInput        *mCaptureDeviceInput;
+    AVCaptureVideoDataOutput    *mCaptureVideoDataOutput;
+    AVCaptureDevice             *mCaptureDevice;
+    CaptureDelegate             *mCapture;
+
+    int startCaptureDevice(int cameraNum);
+    void stopCaptureDevice();
+
+    void setWidthHeight();
+    bool grabFrame(double timeOut);
+
+    int camNum;
+    int width;
+    int height;
+    int settingWidth;
+    int settingHeight;
+
+    int started;
+};
+
+
+/*****************************************************************************
+ *
+ * CvCaptureFile Declaration.
+ *
+ * CvCaptureFile is the instantiation of a capture source for video files.
+ *
+ *****************************************************************************/
+
+class CvCaptureFile : public CvCapture {
+public:
+    CvCaptureFile(const char* filename) ;
+    ~CvCaptureFile();
+    virtual bool grabFrame();
+    virtual IplImage* retrieveFrame(int);
+    virtual double getProperty(int property_id) const;
+    virtual bool setProperty(int property_id, double value);
+    virtual int didStart();
+
+
+private:
+    AVAsset                  *mAsset;
+    AVAssetTrack             *mAssetTrack;
+    AVAssetReader            *mAssetReader;
+    AVAssetReaderTrackOutput *mTrackOutput;
+
+    CMSampleBufferRef mCurrentSampleBuffer;
+    CVImageBufferRef  mGrabbedPixels;
+    IplImage *mDeviceImage;
+    uint8_t  *mOutImagedata;
+    IplImage *mOutImage;
+    size_t    currSize;
+    int       mMode;
+    int       mFormat;
+
+    bool setupReadingAt(CMTime position);
+    IplImage* retrieveFramePixelBuffer();
+
+    CMTime mFrameTimestamp;
+    size_t mFrameNum;
+
+    int started;
+};
+
+
+/*****************************************************************************
+ *
+ * CvVideoWriter_AVFoundation Declaration.
+ *
+ * CvVideoWriter_AVFoundation is the instantiation of a video output class.
+ *
+ *****************************************************************************/
+
+class CvVideoWriter_AVFoundation : public CvVideoWriter {
+    public:
+        CvVideoWriter_AVFoundation(const char* filename, int fourcc,
+                double fps, CvSize frame_size,
+                int is_color=1);
+        ~CvVideoWriter_AVFoundation();
+        bool writeFrame(const IplImage* image);
+    private:
+        IplImage* argbimage;
+
+        AVAssetWriter *mMovieWriter;
+        AVAssetWriterInput* mMovieWriterInput;
+        AVAssetWriterInputPixelBufferAdaptor* mMovieWriterAdaptor;
+
+        NSString* path;
+        NSString* codec;
+        NSString* fileType;
+        double mMovieFPS;
+        CvSize movieSize;
+        int movieColor;
+        unsigned long mFrameNum;
+};
+
+/****************** Implementation of interface functions ********************/
+
+
+CvCapture* cvCreateFileCapture_AVFoundation(const char* filename) {
+    CvCaptureFile *retval = new CvCaptureFile(filename);
+
+    if(retval->didStart())
+        return retval;
+    delete retval;
+    return NULL;
+}
+
+CvCapture* cvCreateCameraCapture_AVFoundation(int index ) {
+    CvCapture* retval = new CvCaptureCAM(index);
+    if (!((CvCaptureCAM *)retval)->didStart())
+        cvReleaseCapture(&retval);
+    return retval;
+}
+
+CvVideoWriter* cvCreateVideoWriter_AVFoundation(const char* filename, int fourcc,
+                                     double fps, CvSize frame_size,
+                                     int is_color) {
+    return new CvVideoWriter_AVFoundation(filename, fourcc, fps, frame_size,is_color);
+}
+
+/********************** Implementation of Classes ****************************/
+
+/*****************************************************************************
+ *
+ * CvCaptureCAM Implementation.
+ *
+ * CvCaptureCAM is the instantiation of a capture source for cameras.
+ *
+ *****************************************************************************/
+
+CvCaptureCAM::CvCaptureCAM(int cameraNum) {
+    mCaptureSession = nil;
+    mCaptureDeviceInput = nil;
+    mCaptureVideoDataOutput = nil;
+    mCaptureDevice = nil;
+    mCapture = nil;
+
+    width = 0;
+    height = 0;
+    settingWidth = 0;
+    settingHeight = 0;
+
+    camNum = cameraNum;
+
+    if ( ! startCaptureDevice(camNum) ) {
+        fprintf(stderr, "OpenCV: camera failed to properly initialize!\n");
+        started = 0;
+    } else {
+        started = 1;
+    }
+}
+
+CvCaptureCAM::~CvCaptureCAM() {
+    stopCaptureDevice();
+}
+
+int CvCaptureCAM::didStart() {
+    return started;
+}
+
+
+bool CvCaptureCAM::grabFrame() {
+    return grabFrame(1);
+}
+
+bool CvCaptureCAM::grabFrame(double timeOut) {
+    NSAutoreleasePool *localpool = [[NSAutoreleasePool alloc] init];
+
+    bool isGrabbed = false;
+    NSDate *limit = [NSDate dateWithTimeIntervalSinceNow: timeOut];
+    if ( [mCapture grabImageUntilDate: limit] ) {
+        [mCapture updateImage];
+        isGrabbed = true;
+    }
+
+    [localpool drain];
+    return isGrabbed;
+}
+
+IplImage* CvCaptureCAM::retrieveFrame(int) {
+    return [mCapture getOutput];
+}
+
+void CvCaptureCAM::stopCaptureDevice() {
+    NSAutoreleasePool *localpool = [[NSAutoreleasePool alloc] init];
+
+    [mCaptureSession stopRunning];
+
+    [mCaptureSession release];
+    [mCaptureDeviceInput release];
+    [mCaptureDevice release];
+
+    [mCaptureVideoDataOutput release];
+    [mCapture release];
+
+    [localpool drain];
+}
+
+int CvCaptureCAM::startCaptureDevice(int cameraNum) {
+    NSAutoreleasePool *localpool = [[NSAutoreleasePool alloc] init];
+
+    // get capture device
+    NSArray *devices = [AVCaptureDevice devicesWithMediaType: AVMediaTypeVideo];
+
+    if ( devices.count == 0 ) {
+        fprintf(stderr, "OpenCV: AVFoundation didn't find any attached Video Input Devices!\n");
+        [localpool drain];
+        return 0;
+    }
+
+    if ( cameraNum < 0 || devices.count <= NSUInteger(cameraNum) ) {
+        fprintf(stderr, "OpenCV: out device of bound (0-%ld): %d\n", devices.count-1, cameraNum);
+        [localpool drain];
+        return 0;
+    }
+
+    mCaptureDevice = devices[cameraNum];
+
+    if ( ! mCaptureDevice ) {
+        fprintf(stderr, "OpenCV: device %d not able to use.\n", cameraNum);
+        [localpool drain];
+        return 0;
+    }
+
+    // get input device
+    NSError *error = nil;
+    mCaptureDeviceInput = [[AVCaptureDeviceInput alloc] initWithDevice: mCaptureDevice
+                                                                 error: &error];
+    if ( error ) {
+        fprintf(stderr, "OpenCV: error in [AVCaptureDeviceInput initWithDevice:error:]\n");
+        NSLog(@"OpenCV: %@", error.localizedDescription);
+        [localpool drain];
+        return 0;
+    }
+
+    // create output
+    mCapture = [[CaptureDelegate alloc] init];
+    mCaptureVideoDataOutput = [[AVCaptureVideoDataOutput alloc] init];
+    dispatch_queue_t queue = dispatch_queue_create("cameraQueue", DISPATCH_QUEUE_SERIAL);
+    [mCaptureVideoDataOutput setSampleBufferDelegate: mCapture queue: queue];
+    dispatch_release(queue);
+
+    OSType pixelFormat = kCVPixelFormatType_32BGRA;
+    //OSType pixelFormat = kCVPixelFormatType_422YpCbCr8;
+    NSDictionary *pixelBufferOptions;
+    if (width > 0 && height > 0) {
+        pixelBufferOptions =
+            @{
+                (id)kCVPixelBufferWidthKey:  @(1.0*width),
+                (id)kCVPixelBufferHeightKey: @(1.0*height),
+                (id)kCVPixelBufferPixelFormatTypeKey: @(pixelFormat)
+            };
+    } else {
+        pixelBufferOptions =
+            @{
+                (id)kCVPixelBufferPixelFormatTypeKey: @(pixelFormat)
+            };
+    }
+    mCaptureVideoDataOutput.videoSettings = pixelBufferOptions;
+    mCaptureVideoDataOutput.alwaysDiscardsLateVideoFrames = YES;
+
+    // create session
+    mCaptureSession = [[AVCaptureSession alloc] init];
+    mCaptureSession.sessionPreset = AVCaptureSessionPresetMedium;
+    [mCaptureSession addInput: mCaptureDeviceInput];
+    [mCaptureSession addOutput: mCaptureVideoDataOutput];
+
+    [mCaptureSession startRunning];
+
+    // flush old position image
+    grabFrame(1);
+
+    [localpool drain];
+    return 1;
+}
+
+void CvCaptureCAM::setWidthHeight() {
+    NSMutableDictionary *pixelBufferOptions = [mCaptureVideoDataOutput.videoSettings mutableCopy];
+
+    while ( true ) {
+        // auto matching
+        pixelBufferOptions[(id)kCVPixelBufferWidthKey]  = @(1.0*width);
+        pixelBufferOptions[(id)kCVPixelBufferHeightKey] = @(1.0*height);
+        mCaptureVideoDataOutput.videoSettings = pixelBufferOptions;
+
+        // compare matched size and my options
+        CMFormatDescriptionRef format = mCaptureDevice.activeFormat.formatDescription;
+        CMVideoDimensions deviceSize = CMVideoFormatDescriptionGetDimensions(format);
+        if ( deviceSize.width == width && deviceSize.height == height ) {
+            break;
+        }
+
+        // fit my options to matched size
+        width = deviceSize.width;
+        height = deviceSize.height;
+    }
+
+    // flush old size image
+    grabFrame(1);
+
+    [pixelBufferOptions release];
+}
+
+
+double CvCaptureCAM::getProperty(int property_id) const{
+    NSAutoreleasePool *localpool = [[NSAutoreleasePool alloc] init];
+
+    CMFormatDescriptionRef format = mCaptureDevice.activeFormat.formatDescription;
+    CMVideoDimensions s1 = CMVideoFormatDescriptionGetDimensions(format);
+    double retval = 0;
+
+    switch (property_id) {
+        case CV_CAP_PROP_FRAME_WIDTH:
+            retval = s1.width;
+            break;
+        case CV_CAP_PROP_FRAME_HEIGHT:
+            retval = s1.height;
+            break;
+        case CV_CAP_PROP_FPS:
+            {
+                CMTime frameDuration = mCaptureDevice.activeVideoMaxFrameDuration;
+                retval = frameDuration.timescale / double(frameDuration.value);
+            }
+            break;
+        case CV_CAP_PROP_FORMAT:
+            retval = CV_8UC3;
+            break;
+        default:
+            break;
+    }
+
+    [localpool drain];
+    return retval;
+}
+
+bool CvCaptureCAM::setProperty(int property_id, double value) {
+    NSAutoreleasePool *localpool = [[NSAutoreleasePool alloc] init];
+
+    bool isSucceeded = false;
+
+    switch (property_id) {
+        case CV_CAP_PROP_FRAME_WIDTH:
+            width = value;
+            settingWidth = 1;
+            if (settingWidth && settingHeight) {
+                setWidthHeight();
+                settingWidth = 0;
+                settingHeight = 0;
+            }
+            isSucceeded = true;
+            break;
+        case CV_CAP_PROP_FRAME_HEIGHT:
+            height = value;
+            settingHeight = 1;
+            if (settingWidth && settingHeight) {
+                setWidthHeight();
+                settingWidth = 0;
+                settingHeight = 0;
+            }
+            isSucceeded = true;
+            break;
+        case CV_CAP_PROP_FPS:
+            if ( [mCaptureDevice lockForConfiguration: NULL] ) {
+                NSArray * ranges = mCaptureDevice.activeFormat.videoSupportedFrameRateRanges;
+                AVFrameRateRange *matchedRange = ranges[0];
+                double minDiff = fabs(matchedRange.maxFrameRate - value);
+                for ( AVFrameRateRange *range in ranges ) {
+                    double diff = fabs(range.maxFrameRate - value);
+                    if ( diff < minDiff ) {
+                        minDiff = diff;
+                        matchedRange = range;
+                    }
+                }
+                mCaptureDevice.activeVideoMinFrameDuration = matchedRange.minFrameDuration;
+                mCaptureDevice.activeVideoMaxFrameDuration = matchedRange.minFrameDuration;
+                isSucceeded = true;
+                [mCaptureDevice unlockForConfiguration];
+            }
+            break;
+        default:
+            break;
+    }
+
+    [localpool drain];
+    return isSucceeded;
+}
+
+
+/*****************************************************************************
+ *
+ * CaptureDelegate Implementation.
+ *
+ * CaptureDelegate is notified on a separate thread by the OS whenever there
+ *   is a new frame. When "updateImage" is called from the main thread, it
+ *   copies this new frame into an IplImage, but only if this frame has not
+ *   been copied before. When "getOutput" is called from the main thread,
+ *   it gives the last copied IplImage.
+ *
+ *****************************************************************************/
+
+
+ at implementation CaptureDelegate
+
+- (id)init {
+    [super init];
+    mHasNewFrame = [[NSCondition alloc] init];
+    mCurrentImageBuffer = NULL;
+    mGrabbedPixels = NULL;
+    mDeviceImage = NULL;
+    mOutImagedata = NULL;
+    mOutImage = NULL;
+    currSize = 0;
+    return self;
+}
+
+-(void)dealloc {
+    free(mOutImagedata);
+    cvReleaseImage(&mOutImage);
+    cvReleaseImage(&mDeviceImage);
+    CVBufferRelease(mCurrentImageBuffer);
+    CVBufferRelease(mGrabbedPixels);
+    [mHasNewFrame release];
+    [super dealloc];
+}
+
+- (void)captureOutput:(AVCaptureOutput *)captureOutput
+didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer
+       fromConnection:(AVCaptureConnection *)connection {
+    (void)captureOutput;
+    (void)sampleBuffer;
+    (void)connection;
+
+    CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
+    CVBufferRetain(imageBuffer);
+
+    [mHasNewFrame lock];
+
+    CVBufferRelease(mCurrentImageBuffer);
+    mCurrentImageBuffer = imageBuffer;
+    [mHasNewFrame signal];
+
+    [mHasNewFrame unlock];
+
+}
+
+-(IplImage*) getOutput {
+    return mOutImage;
+}
+
+-(BOOL) grabImageUntilDate: (NSDate *)limit {
+    BOOL isGrabbed = NO;
+    [mHasNewFrame lock];
+
+    if ( mGrabbedPixels ) {
+        CVBufferRelease(mGrabbedPixels);
+    }
+    if ( [mHasNewFrame waitUntilDate: limit] ) {
+        isGrabbed = YES;
+        mGrabbedPixels = CVBufferRetain(mCurrentImageBuffer);
+    }
+
+    [mHasNewFrame unlock];
+    return isGrabbed;
+}
+
+-(int) updateImage {
+    if ( ! mGrabbedPixels ) {
+        return 0;
+    }
+
+    CVPixelBufferLockBaseAddress(mGrabbedPixels, 0);
+    void *baseaddress = CVPixelBufferGetBaseAddress(mGrabbedPixels);
+
+    size_t width = CVPixelBufferGetWidth(mGrabbedPixels);
+    size_t height = CVPixelBufferGetHeight(mGrabbedPixels);
+    size_t rowBytes = CVPixelBufferGetBytesPerRow(mGrabbedPixels);
+    OSType pixelFormat = CVPixelBufferGetPixelFormatType(mGrabbedPixels);
+
+    if ( rowBytes == 0 ) {
+        fprintf(stderr, "OpenCV: error: rowBytes == 0\n");
+        CVPixelBufferUnlockBaseAddress(mGrabbedPixels, 0);
+        CVBufferRelease(mGrabbedPixels);
+        mGrabbedPixels = NULL;
+        return 0;
+    }
+
+    if ( currSize != width*3*height ) {
+        currSize = width*3*height;
+        free(mOutImagedata);
+        mOutImagedata = reinterpret_cast<uint8_t*>(malloc(currSize));
+    }
+
+    if (mOutImage == NULL) {
+        mOutImage = cvCreateImageHeader(cvSize((int)width,(int)height), IPL_DEPTH_8U, 3);
+    }
+    mOutImage->width = int(width);
+    mOutImage->height = int(height);
+    mOutImage->nChannels = 3;
+    mOutImage->depth = IPL_DEPTH_8U;
+    mOutImage->widthStep = int(width*3);
+    mOutImage->imageData = reinterpret_cast<char *>(mOutImagedata);
+    mOutImage->imageSize = int(currSize);
+
+    if ( pixelFormat == kCVPixelFormatType_32BGRA ) {
+        if (mDeviceImage == NULL) {
+            mDeviceImage = cvCreateImageHeader(cvSize(int(width),int(height)), IPL_DEPTH_8U, 4);
+        }
+        mDeviceImage->width = int(width);
+        mDeviceImage->height = int(height);
+        mDeviceImage->nChannels = 4;
+        mDeviceImage->depth = IPL_DEPTH_8U;
+        mDeviceImage->widthStep = int(rowBytes);
+        mDeviceImage->imageData = reinterpret_cast<char *>(baseaddress);
+        mDeviceImage->imageSize = int(rowBytes*height);
+
+        cvCvtColor(mDeviceImage, mOutImage, CV_BGRA2BGR);
+    } else if ( pixelFormat == kCVPixelFormatType_422YpCbCr8 ) {
+        if ( currSize != width*3*height ) {
+            currSize = width*3*height;
+            free(mOutImagedata);
+            mOutImagedata = reinterpret_cast<uint8_t*>(malloc(currSize));
+        }
+
+        if (mDeviceImage == NULL) {
+            mDeviceImage = cvCreateImageHeader(cvSize(int(width),int(height)), IPL_DEPTH_8U, 2);
+        }
+        mDeviceImage->width = int(width);
+        mDeviceImage->height = int(height);
+        mDeviceImage->nChannels = 2;
+        mDeviceImage->depth = IPL_DEPTH_8U;
+        mDeviceImage->widthStep = int(rowBytes);
+        mDeviceImage->imageData = reinterpret_cast<char *>(baseaddress);
+        mDeviceImage->imageSize = int(rowBytes*height);
+
+        cvCvtColor(mDeviceImage, mOutImage, CV_YUV2BGR_UYVY);
+    } else {
+        fprintf(stderr, "OpenCV: unknown pixel format 0x%08X\n", pixelFormat);
+        CVPixelBufferUnlockBaseAddress(mGrabbedPixels, 0);
+        CVBufferRelease(mGrabbedPixels);
+        mGrabbedPixels = NULL;
+        return 0;
+    }
+
+    CVPixelBufferUnlockBaseAddress(mGrabbedPixels, 0);
+    CVBufferRelease(mGrabbedPixels);
+    mGrabbedPixels = NULL;
+
+    return 1;
+}
+
+ at end
+
+
+/*****************************************************************************
+ *
+ * CvCaptureFile Implementation.
+ *
+ * CvCaptureFile is the instantiation of a capture source for video files.
+ *
+ *****************************************************************************/
+
+CvCaptureFile::CvCaptureFile(const char* filename) {
+    NSAutoreleasePool *localpool = [[NSAutoreleasePool alloc] init];
+
+    mAsset = nil;
+    mAssetTrack = nil;
+    mAssetReader = nil;
+    mTrackOutput = nil;
+    mDeviceImage = NULL;
+    mOutImage = NULL;
+    mOutImagedata = NULL;
+    currSize = 0;
+    mMode = CV_CAP_MODE_BGR;
+    mFormat = CV_8UC3;
+    mCurrentSampleBuffer = NULL;
+    mGrabbedPixels = NULL;
+    mFrameTimestamp = kCMTimeZero;
+    mFrameNum = 0;
+
+    started = 0;
+
+    mAsset = [[AVAsset assetWithURL:[NSURL fileURLWithPath: @(filename)]] retain];
+
+    if ( mAsset == nil ) {
+        fprintf(stderr, "OpenCV: Couldn't read movie file \"%s\"\n", filename);
+        [localpool drain];
+        started = 0;
+        return;
+    }
+
+    mAssetTrack = [[mAsset tracksWithMediaType: AVMediaTypeVideo][0] retain];
+
+    if ( ! setupReadingAt(kCMTimeZero) ) {
+        fprintf(stderr, "OpenCV: Couldn't read movie file \"%s\"\n", filename);
+        [localpool drain];
+        started = 0;
+        return;
+    }
+
+    started = 1;
+    [localpool drain];
+}
+
+CvCaptureFile::~CvCaptureFile() {
+    NSAutoreleasePool *localpool = [[NSAutoreleasePool alloc] init];
+
+    free(mOutImagedata);
+    cvReleaseImage(&mOutImage);
+    cvReleaseImage(&mDeviceImage);
+    [mAssetReader release];
+    [mTrackOutput release];
+    [mAssetTrack release];
+    [mAsset release];
+    CVBufferRelease(mGrabbedPixels);
+    if ( mCurrentSampleBuffer ) {
+        CFRelease(mCurrentSampleBuffer);
+    }
+
+    [localpool drain];
+}
+
+bool CvCaptureFile::setupReadingAt(CMTime position) {
+    if (mAssetReader) {
+        if (mAssetReader.status == AVAssetReaderStatusReading) {
+            [mAssetReader cancelReading];
+        }
+        [mAssetReader release];
+        mAssetReader = nil;
+    }
+    if (mTrackOutput) {
+        [mTrackOutput release];
+        mTrackOutput = nil;
+    }
+
+    // Capture in a pixel format that can be converted efficiently to the output mode.
+    OSType pixelFormat;
+    if (mMode == CV_CAP_MODE_BGR || mMode == CV_CAP_MODE_RGB) {
+        // For CV_CAP_MODE_BGR, read frames as BGRA (AV Foundation's YUV->RGB conversion is slightly faster than OpenCV's CV_YUV2BGR_YV12)
+        // kCVPixelFormatType_32ABGR is reportedly faster on OS X, but OpenCV doesn't have a CV_ABGR2BGR conversion.
+        // kCVPixelFormatType_24RGB is significanly slower than kCVPixelFormatType_32BGRA.
+        pixelFormat = kCVPixelFormatType_32BGRA;
+        mFormat = CV_8UC3;
+    } else if (mMode == CV_CAP_MODE_GRAY) {
+        // For CV_CAP_MODE_GRAY, read frames as 420v (faster than 420f or 422 -- at least for H.264 files)
+        pixelFormat = kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange;
+        mFormat = CV_8UC1;
+    } else if (mMode == CV_CAP_MODE_YUYV) {
+        // For CV_CAP_MODE_YUYV, read frames directly as 422.
+        pixelFormat = kCVPixelFormatType_422YpCbCr8;
+        mFormat = CV_8UC2;
+    } else {
+        fprintf(stderr, "VIDEOIO ERROR: AVF Mac: Unsupported mode: %d\n", mMode);
+        return false;
+    }
+
+    NSDictionary *settings =
+        @{
+            (id)kCVPixelBufferPixelFormatTypeKey: @(pixelFormat)
+        };
+    mTrackOutput = [[AVAssetReaderTrackOutput assetReaderTrackOutputWithTrack: mAssetTrack
+                                                               outputSettings: settings] retain];
+
+    if ( !mTrackOutput ) {
+        fprintf(stderr, "OpenCV: error in [AVAssetReaderTrackOutput assetReaderTrackOutputWithTrack:outputSettings:]\n");
+        return false;
+    }
+
+    NSError *error = nil;
+    mAssetReader = [[AVAssetReader assetReaderWithAsset: mAsset
+                                                  error: &error] retain];
+    if ( error ) {
+        fprintf(stderr, "OpenCV: error in [AVAssetReader assetReaderWithAsset:error:]\n");
+        NSLog(@"OpenCV: %@", error.localizedDescription);
+        return false;
+    }
+
+    mAssetReader.timeRange = CMTimeRangeMake(position, kCMTimePositiveInfinity);
+    mFrameTimestamp = position;
+    mFrameNum = round((mFrameTimestamp.value * mAssetTrack.nominalFrameRate) / double(mFrameTimestamp.timescale));
+    [mAssetReader addOutput: mTrackOutput];
+    [mAssetReader startReading];
+
+    return true;
+}
+
+int CvCaptureFile::didStart() {
+    return started;
+}
+
+bool CvCaptureFile::grabFrame() {
+    NSAutoreleasePool *localpool = [[NSAutoreleasePool alloc] init];
+
+    CVBufferRelease(mGrabbedPixels);
+    if ( mCurrentSampleBuffer ) {
+        CFRelease(mCurrentSampleBuffer);
+    }
+    mCurrentSampleBuffer = [mTrackOutput copyNextSampleBuffer];
+    mGrabbedPixels = CMSampleBufferGetImageBuffer(mCurrentSampleBuffer);
+    CVBufferRetain(mGrabbedPixels);
+    mFrameTimestamp = CMSampleBufferGetOutputPresentationTimeStamp(mCurrentSampleBuffer);
+    mFrameNum++;
+
+    bool isReading = (mAssetReader.status == AVAssetReaderStatusReading);
+    [localpool drain];
+    return isReading;
+}
+
+
+IplImage* CvCaptureFile::retrieveFramePixelBuffer() {
+    if ( ! mGrabbedPixels ) {
+        return 0;
+    }
+
+    NSAutoreleasePool *localpool = [[NSAutoreleasePool alloc] init];
+
+    CVPixelBufferLockBaseAddress(mGrabbedPixels, 0);
+    void *baseaddress;
+    size_t width, height, rowBytes;
+
+    OSType pixelFormat = CVPixelBufferGetPixelFormatType(mGrabbedPixels);
+
+    if (CVPixelBufferIsPlanar(mGrabbedPixels)) {
+        baseaddress = CVPixelBufferGetBaseAddressOfPlane(mGrabbedPixels, 0);
+        width = CVPixelBufferGetWidthOfPlane(mGrabbedPixels, 0);
+        height = CVPixelBufferGetHeightOfPlane(mGrabbedPixels, 0);
+        rowBytes = CVPixelBufferGetBytesPerRowOfPlane(mGrabbedPixels, 0);
+    } else {
+        baseaddress = CVPixelBufferGetBaseAddress(mGrabbedPixels);
+        width = CVPixelBufferGetWidth(mGrabbedPixels);
+        height = CVPixelBufferGetHeight(mGrabbedPixels);
+        rowBytes = CVPixelBufferGetBytesPerRow(mGrabbedPixels);
+    }
+
+    if ( rowBytes == 0 ) {
+        fprintf(stderr, "OpenCV: error: rowBytes == 0\n");
+        CVPixelBufferUnlockBaseAddress(mGrabbedPixels, 0);
+        CVBufferRelease(mGrabbedPixels);
+        mGrabbedPixels = NULL;
+        return 0;
+    }
+
+     // Output image paramaters.
+     int outChannels;
+     if (mMode == CV_CAP_MODE_BGR || mMode == CV_CAP_MODE_RGB) {
+         outChannels = 3;
+     } else if (mMode == CV_CAP_MODE_GRAY) {
+         outChannels = 1;
+     } else if (mMode == CV_CAP_MODE_YUYV) {
+         outChannels = 2;
+     } else {
+         fprintf(stderr, "VIDEOIO ERROR: AVF Mac: Unsupported mode: %d\n", mMode);
+         CVPixelBufferUnlockBaseAddress(mGrabbedPixels, 0);
+         CVBufferRelease(mGrabbedPixels);
+         mGrabbedPixels = NULL;
+         return 0;
+     }
+
+     if ( currSize != width*outChannels*height ) {
+         currSize = width*outChannels*height;
+        free(mOutImagedata);
+        mOutImagedata = reinterpret_cast<uint8_t*>(malloc(currSize));
+    }
+
+    // Build the header for the output image.
+    if (mOutImage == NULL) {
+        mOutImage = cvCreateImageHeader(cvSize((int)width,(int)height), IPL_DEPTH_8U, outChannels);
+    }
+    mOutImage->width = int(width);
+    mOutImage->height = int(height);
+    mOutImage->nChannels = outChannels;
+    mOutImage->depth = IPL_DEPTH_8U;
+    mOutImage->widthStep = int(width*outChannels);
+    mOutImage->imageData = reinterpret_cast<char *>(mOutImagedata);
+    mOutImage->imageSize = int(currSize);
+
+    // Device image paramaters and conversion code.
+    // (Not all of these conversions are used in production, but they were all tested to find the fastest options.)
+    int deviceChannels;
+    int cvtCode;
+
+    if ( pixelFormat == kCVPixelFormatType_32BGRA ) {
+        deviceChannels = 4;
+
+        if (mMode == CV_CAP_MODE_BGR) {
+            cvtCode = CV_BGRA2BGR;
+        } else if (mMode == CV_CAP_MODE_RGB) {
+            cvtCode = CV_BGRA2RGB;
+        } else if (mMode == CV_CAP_MODE_GRAY) {
+            cvtCode = CV_BGRA2GRAY;
+        } else {
+            CVPixelBufferUnlockBaseAddress(mGrabbedPixels, 0);
+            CVBufferRelease(mGrabbedPixels);
+            mGrabbedPixels = NULL;
+            fprintf(stderr, "OpenCV: unsupported pixel conversion mode\n");
+            return 0;
+        }
+    } else if ( pixelFormat == kCVPixelFormatType_24RGB ) {
+        deviceChannels = 3;
+
+        if (mMode == CV_CAP_MODE_BGR) {
+            cvtCode = CV_RGB2BGR;
+        } else if (mMode == CV_CAP_MODE_RGB) {
+            cvtCode = 0;
+        } else if (mMode == CV_CAP_MODE_GRAY) {
+            cvtCode = CV_RGB2GRAY;
+        } else {
+            CVPixelBufferUnlockBaseAddress(mGrabbedPixels, 0);
+            CVBufferRelease(mGrabbedPixels);
+            mGrabbedPixels = NULL;
+            fprintf(stderr, "OpenCV: unsupported pixel conversion mode\n");
+            return 0;
+        }
+    } else if ( pixelFormat == kCVPixelFormatType_422YpCbCr8 ) {    // 422 (2vuy, UYVY)
+        deviceChannels = 2;
+
+        if (mMode == CV_CAP_MODE_BGR) {
+            cvtCode = CV_YUV2BGR_UYVY;
+        } else if (mMode == CV_CAP_MODE_RGB) {
+            cvtCode = CV_YUV2RGB_UYVY;
+        } else if (mMode == CV_CAP_MODE_GRAY) {
+            cvtCode = CV_YUV2GRAY_UYVY;
+        } else if (mMode == CV_CAP_MODE_YUYV) {
+            cvtCode = -1;    // Copy
+        } else {
+            CVPixelBufferUnlockBaseAddress(mGrabbedPixels, 0);
+            CVBufferRelease(mGrabbedPixels);
+            mGrabbedPixels = NULL;
+            fprintf(stderr, "OpenCV: unsupported pixel conversion mode\n");
+            return 0;
+        }
+    } else if ( pixelFormat == kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange ||   // 420v
+                pixelFormat == kCVPixelFormatType_420YpCbCr8BiPlanarFullRange ) {   // 420f
+        // cvCvtColor(CV_YUV2GRAY_420) is expecting a single buffer with both the Y plane and the CrCb planes.
+        // So, lie about the height of the buffer.  cvCvtColor(CV_YUV2GRAY_420) will only read the first 2/3 of it.
+        height = height * 3 / 2;
+        deviceChannels = 1;
+
+        if (mMode == CV_CAP_MODE_BGR) {
+            cvtCode = CV_YUV2BGR_YV12;
+        } else if (mMode == CV_CAP_MODE_RGB) {
+            cvtCode = CV_YUV2RGB_YV12;
+        } else if (mMode == CV_CAP_MODE_GRAY) {
+            cvtCode = CV_YUV2GRAY_420;
+        } else {
+            CVPixelBufferUnlockBaseAddress(mGrabbedPixels, 0);
+            CVBufferRelease(mGrabbedPixels);
+            mGrabbedPixels = NULL;
+            fprintf(stderr, "OpenCV: unsupported pixel conversion mode\n");
+            return 0;
+        }
+    } else {
+        fprintf(stderr, "OpenCV: unsupported pixel format 0x%08X\n", pixelFormat);
+        CVPixelBufferUnlockBaseAddress(mGrabbedPixels, 0);
+        CVBufferRelease(mGrabbedPixels);
+        mGrabbedPixels = NULL;
+        return 0;
+    }
+
+    // Build the header for the device image.
+    if (mDeviceImage == NULL) {
+        mDeviceImage = cvCreateImageHeader(cvSize(int(width),int(height)), IPL_DEPTH_8U, deviceChannels);
+    }
+    mDeviceImage->width = int(width);
+    mDeviceImage->height = int(height);
+    mDeviceImage->nChannels = deviceChannels;
+    mDeviceImage->depth = IPL_DEPTH_8U;
+    mDeviceImage->widthStep = int(rowBytes);
+    mDeviceImage->imageData = reinterpret_cast<char *>(baseaddress);
+    mDeviceImage->imageSize = int(rowBytes*height);
+
+    // Convert the device image into the output image.
+    if (cvtCode == -1) {
+        // Copy.
+        cv::cvarrToMat(mDeviceImage).copyTo(cv::cvarrToMat(mOutImage));
+    } else {
+        cvCvtColor(mDeviceImage, mOutImage, cvtCode);
+    }
+
+
+    CVPixelBufferUnlockBaseAddress(mGrabbedPixels, 0);
+
+    [localpool drain];
+
+    return mOutImage;
+}
+
+
+IplImage* CvCaptureFile::retrieveFrame(int) {
+    return retrieveFramePixelBuffer();
+}
+
+double CvCaptureFile::getProperty(int property_id) const{
+    if (mAsset == nil) return 0;
+
+    CMTime t;
+
+    switch (property_id) {
+        case CV_CAP_PROP_POS_MSEC:
+            return mFrameTimestamp.value * 1000.0 / mFrameTimestamp.timescale;
+        case CV_CAP_PROP_POS_FRAMES:
+            return  mFrameNum;
+        case CV_CAP_PROP_POS_AVI_RATIO:
+            t = [mAsset duration];
+            return (mFrameTimestamp.value * t.timescale) / double(mFrameTimestamp.timescale * t.value);
+        case CV_CAP_PROP_FRAME_WIDTH:
+            return mAssetTrack.naturalSize.width;
+        case CV_CAP_PROP_FRAME_HEIGHT:
+            return mAssetTrack.naturalSize.height;
+        case CV_CAP_PROP_FPS:
+            return mAssetTrack.nominalFrameRate;
+        case CV_CAP_PROP_FRAME_COUNT:
+            t = [mAsset duration];
+            return round((t.value * mAssetTrack.nominalFrameRate) / double(t.timescale));
+        case CV_CAP_PROP_FORMAT:
+            return mFormat;
+        case CV_CAP_PROP_MODE:
+            return mMode;
+        default:
+            break;
+    }
+
+    return 0;
+}
+
+bool CvCaptureFile::setProperty(int property_id, double value) {
+    if (mAsset == nil) return false;
+
+    NSAutoreleasePool* localpool = [[NSAutoreleasePool alloc] init];
+
+    bool retval = false;
+    CMTime t;
+
+    switch (property_id) {
+        case CV_CAP_PROP_POS_MSEC:
+            t = mAsset.duration;
+            t.value = value * t.timescale / 1000;
+            setupReadingAt(t);
+            retval = true;
+            break;
+        case CV_CAP_PROP_POS_FRAMES:
+            setupReadingAt(CMTimeMake(value, mAssetTrack.nominalFrameRate));
+            retval = true;
+            break;
+        case CV_CAP_PROP_POS_AVI_RATIO:
+            t = mAsset.duration;
+            t.value = round(t.value * value);
+            setupReadingAt(t);
+            retval = true;
+            break;
+        case CV_CAP_PROP_MODE:
+            int mode;
+            mode = cvRound(value);
+            if (mMode == mode) {
+                retval = true;
+            } else {
+                switch (mode) {
+                    case CV_CAP_MODE_BGR:
+                    case CV_CAP_MODE_RGB:
+                    case CV_CAP_MODE_GRAY:
+                    case CV_CAP_MODE_YUYV:
+                        mMode = mode;
+                        setupReadingAt(mFrameTimestamp);
+                        retval = true;
+                        break;
+                    default:
+                        fprintf(stderr, "VIDEOIO ERROR: AVF Mac: Unsupported mode: %d\n", mode);
+                        retval=false;
+                        break;
+                }
+            }
+            break;
+        default:
+            break;
+    }
+
+    [localpool drain];
+    return retval;
+}
+
+
+/*****************************************************************************
+ *
+ * CvVideoWriter_AVFoundation Implementation.
+ *
+ * CvVideoWriter_AVFoundation is the instantiation of a video output class.
+ *
+ *****************************************************************************/
+
+
+CvVideoWriter_AVFoundation::CvVideoWriter_AVFoundation(const char* filename, int fourcc,
+        double fps, CvSize frame_size,
+        int is_color) {
+
+    NSAutoreleasePool* localpool = [[NSAutoreleasePool alloc] init];
+
+
+    mFrameNum = 0;
+    mMovieFPS = fps;
+    movieSize = frame_size;
+    movieColor = is_color;
+    argbimage = cvCreateImage(movieSize, IPL_DEPTH_8U, 4);
+    path = [[[NSString stringWithCString:filename encoding:NSASCIIStringEncoding] stringByExpandingTildeInPath] retain];
+
+
+    /*
+         AVFileTypeQuickTimeMovie
+         UTI for the QuickTime movie file format.
+         The value of this UTI is com.apple.quicktime-movie. Files are identified with the .mov and .qt extensions.
+
+         AVFileTypeMPEG4
+         UTI for the MPEG-4 file format.
+         The value of this UTI is public.mpeg-4. Files are identified with the .mp4 extension.
+
+         AVFileTypeAppleM4V
+         UTI for the iTunes video file format.
+         The value of this UTI is com.apple.mpeg-4-video. Files are identified with the .m4v extension.
+
+         AVFileType3GPP
+         UTI for the 3GPP file format.
+         The value of this UTI is public.3gpp. Files are identified with the .3gp, .3gpp, and .sdv extensions.
+     */
+
+    NSString *fileExt =[[[path pathExtension] lowercaseString] copy];
+    if ([fileExt isEqualToString:@"mov"] || [fileExt isEqualToString:@"qt"]){
+        fileType = [AVFileTypeQuickTimeMovie copy];
+    }else if ([fileExt isEqualToString:@"mp4"]){
+        fileType = [AVFileTypeMPEG4 copy];
+    }else if ([fileExt isEqualToString:@"m4v"]){
+        fileType = [AVFileTypeAppleM4V copy];
+#if TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR
+    }else if ([fileExt isEqualToString:@"3gp"] || [fileExt isEqualToString:@"3gpp"] || [fileExt isEqualToString:@"sdv"]  ){
+        fileType = [AVFileType3GPP copy];
+#endif
+    } else{
+        fileType = [AVFileTypeMPEG4 copy];  //default mp4
+    }
+    [fileExt release];
+
+    char cc[5];
+    cc[0] = fourcc & 255;
+    cc[1] = (fourcc >> 8) & 255;
+    cc[2] = (fourcc >> 16) & 255;
+    cc[3] = (fourcc >> 24) & 255;
+    cc[4] = 0;
+    int cc2 = CV_FOURCC(cc[0], cc[1], cc[2], cc[3]);
+    if (cc2!=fourcc) {
+        fprintf(stderr, "OpenCV: Didn't properly encode FourCC. Expected 0x%08X but got 0x%08X.\n", fourcc, cc2);
+        //exception;
+    }
+
+    // Two codec supported AVVideoCodecH264 AVVideoCodecJPEG
+    // On iPhone 3G H264 is not supported.
+    if (fourcc == CV_FOURCC('J','P','E','G') || fourcc == CV_FOURCC('j','p','e','g') ||
+            fourcc == CV_FOURCC('M','J','P','G') || fourcc == CV_FOURCC('m','j','p','g') ){
+        codec = [AVVideoCodecJPEG copy]; // Use JPEG codec if specified, otherwise H264
+    }else if(fourcc == CV_FOURCC('H','2','6','4') || fourcc == CV_FOURCC('a','v','c','1')){
+            codec = [AVVideoCodecH264 copy];
+    }else{
+        codec = [AVVideoCodecH264 copy]; // default canonical H264.
+
+    }
+
+    //NSLog(@"Path: %@", path);
+
+    NSError *error = nil;
+
+
+    // Make sure the file does not already exist. Necessary to overwirte??
+    /*
+    NSFileManager *fileManager = [NSFileManager defaultManager];
+    if ([fileManager fileExistsAtPath:path]){
+        [fileManager removeItemAtPath:path error:&error];
+    }
+    */
+
+    // Wire the writer:
+    // Supported file types:
+    //      AVFileTypeQuickTimeMovie AVFileTypeMPEG4 AVFileTypeAppleM4V AVFileType3GPP
+
+    mMovieWriter = [[AVAssetWriter alloc] initWithURL:[NSURL fileURLWithPath:path]
+        fileType:fileType
+        error:&error];
+    //NSParameterAssert(mMovieWriter);
+
+    NSDictionary *videoSettings = [NSDictionary dictionaryWithObjectsAndKeys:
+        codec, AVVideoCodecKey,
+        [NSNumber numberWithInt:movieSize.width], AVVideoWidthKey,
+        [NSNumber numberWithInt:movieSize.height], AVVideoHeightKey,
+        nil];
+
+    mMovieWriterInput = [[AVAssetWriterInput
+        assetWriterInputWithMediaType:AVMediaTypeVideo
+        outputSettings:videoSettings] retain];
+
+    //NSParameterAssert(mMovieWriterInput);
+    //NSParameterAssert([mMovieWriter canAddInput:mMovieWriterInput]);
+
+    [mMovieWriter addInput:mMovieWriterInput];
+
+    mMovieWriterAdaptor = [[AVAssetWriterInputPixelBufferAdaptor alloc] initWithAssetWriterInput:mMovieWriterInput sourcePixelBufferAttributes:nil];
+
+
+    //Start a session:
+    [mMovieWriter startWriting];
+    [mMovieWriter startSessionAtSourceTime:kCMTimeZero];
+
+
+    if(mMovieWriter.status == AVAssetWriterStatusFailed){
+        NSLog(@"AVF: AVAssetWriter status: %@", [mMovieWriter.error localizedDescription]);
+        // TODO: error handling, cleanup. Throw execption?
+        // return;
+    }
+
+    [localpool drain];
+}
+
+
+CvVideoWriter_AVFoundation::~CvVideoWriter_AVFoundation() {
+    NSAutoreleasePool* localpool = [[NSAutoreleasePool alloc] init];
+
+    [mMovieWriterInput markAsFinished];
+    [mMovieWriter finishWriting];
+    [mMovieWriter release];
+    [mMovieWriterInput release];
+    [mMovieWriterAdaptor release];
+    [path release];
+    [codec release];
+    [fileType release];
+    cvReleaseImage(&argbimage);
+
+    [localpool drain];
+
+}
+
+static void releaseCallback( void *releaseRefCon, const void * ) {
+    CFRelease((CFDataRef)releaseRefCon);
+}
+
+bool CvVideoWriter_AVFoundation::writeFrame(const IplImage* iplimage) {
+    NSAutoreleasePool* localpool = [[NSAutoreleasePool alloc] init];
+
+    // writer status check
+    if (mMovieWriter.status !=  AVAssetWriterStatusWriting ) {
+        NSLog(@"mMovieWriter.status: %d. Error: %@", (int)mMovieWriter.status, [mMovieWriter.error localizedDescription]);
+        [localpool drain];
+        return false;
+    }
+
+    // Make writeFrame() a blocking call.
+    while (![mMovieWriterInput isReadyForMoreMediaData]) {
+        fprintf(stderr, "OpenCV: AVF: waiting to write video data.\n");
+        // Sleep 1 msec.
+        usleep(1000);
+    }
+
+    BOOL success = FALSE;
+
+    if (iplimage->height!=movieSize.height || iplimage->width!=movieSize.width){
+        fprintf(stderr, "OpenCV: Frame size does not match video size.\n");
+        [localpool drain];
+        return false;
+    }
+
+    if (movieColor) {
+        //assert(iplimage->nChannels == 3);
+        cvCvtColor(iplimage, argbimage, CV_BGR2BGRA);
+    }else{
+        //assert(iplimage->nChannels == 1);
+        cvCvtColor(iplimage, argbimage, CV_GRAY2BGRA);
+    }
+    //IplImage -> CGImage conversion
+    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
+    NSData *nsData = [NSData dataWithBytes:argbimage->imageData length:argbimage->imageSize];
+    CGDataProviderRef provider = CGDataProviderCreateWithCFData((CFDataRef)nsData);
+    CGImageRef cgImage = CGImageCreate(argbimage->width, argbimage->height,
+            argbimage->depth, argbimage->depth * argbimage->nChannels, argbimage->widthStep,
+            colorSpace, kCGImageAlphaLast|kCGBitmapByteOrderDefault,
+            provider, NULL, false, kCGRenderingIntentDefault);
+
+    //CGImage -> CVPixelBufferRef coversion
+    CVPixelBufferRef pixelBuffer = NULL;
+    CFDataRef cfData = CGDataProviderCopyData(CGImageGetDataProvider(cgImage));
+    int status = CVPixelBufferCreateWithBytes(NULL,
+            movieSize.width,
+            movieSize.height,
+            kCVPixelFormatType_32BGRA,
+            (void*)CFDataGetBytePtr(cfData),
+            CGImageGetBytesPerRow(cgImage),
+            &releaseCallback,
+            (void *)cfData,
+            NULL,
+            &pixelBuffer);
+    if(status == kCVReturnSuccess){
+        success = [mMovieWriterAdaptor appendPixelBuffer:pixelBuffer
+            withPresentationTime:CMTimeMake(mFrameNum, mMovieFPS)];
+    }
+
+    //cleanup
+    CVPixelBufferRelease(pixelBuffer);
+    CGImageRelease(cgImage);
+    CGDataProviderRelease(provider);
+    CGColorSpaceRelease(colorSpace);
+
+    [localpool drain];
+
+    if (success) {
+        mFrameNum ++;
+        //NSLog(@"Frame #%d", mFrameNum);
+        return true;
+    }else{
+        NSLog(@"Frame appendPixelBuffer failed.");
+        return false;
+    }
+
+}
diff --git a/modules/videoio/src/cap_dc1394.cpp b/modules/videoio/src/cap_dc1394.cpp
index 6789cde..06fbe43 100644
--- a/modules/videoio/src/cap_dc1394.cpp
+++ b/modules/videoio/src/cap_dc1394.cpp
@@ -907,10 +907,10 @@ b = b > 255 ? 255 : b
 uyv2bgr(const unsigned char *src, unsigned char *dest,
         unsigned long long int NumPixels)
 {
-    register int i = NumPixels + (NumPixels << 1) - 1;
-    register int j = NumPixels + (NumPixels << 1) - 1;
-    register int y, u, v;
-    register int r, g, b;
+    int i = NumPixels + (NumPixels << 1) - 1;
+    int j = NumPixels + (NumPixels << 1) - 1;
+    int y, u, v;
+    int r, g, b;
 
     while (i > 0) {
         v = src[i--] - 128;
@@ -927,10 +927,10 @@ uyv2bgr(const unsigned char *src, unsigned char *dest,
 uyvy2bgr(const unsigned char *src, unsigned char *dest,
         unsigned long long int NumPixels)
 {
-    register int i = (NumPixels << 1) - 1;
-    register int j = NumPixels + (NumPixels << 1) - 1;
-    register int y0, y1, u, v;
-    register int r, g, b;
+    int i = (NumPixels << 1) - 1;
+    int j = NumPixels + (NumPixels << 1) - 1;
+    int y0, y1, u, v;
+    int r, g, b;
 
     while (i > 0) {
         y1 = src[i--];
@@ -953,10 +953,10 @@ uyvy2bgr(const unsigned char *src, unsigned char *dest,
 uyyvyy2bgr(const unsigned char *src, unsigned char *dest,
         unsigned long long int NumPixels)
 {
-    register int i = NumPixels + (NumPixels >> 1) - 1;
-    register int j = NumPixels + (NumPixels << 1) - 1;
-    register int y0, y1, y2, y3, u, v;
-    register int r, g, b;
+    int i = NumPixels + (NumPixels >> 1) - 1;
+    int j = NumPixels + (NumPixels << 1) - 1;
+    int y0, y1, y2, y3, u, v;
+    int r, g, b;
 
     while (i > 0) {
         y3 = src[i--];
@@ -988,9 +988,9 @@ uyyvyy2bgr(const unsigned char *src, unsigned char *dest,
 y2bgr(const unsigned char *src, unsigned char *dest,
         unsigned long long int NumPixels)
 {
-    register int i = NumPixels - 1;
-    register int j = NumPixels + (NumPixels << 1) - 1;
-    register int y;
+    int i = NumPixels - 1;
+    int j = NumPixels + (NumPixels << 1) - 1;
+    int y;
 
     while (i > 0) {
         y = src[i--];
@@ -1004,9 +1004,9 @@ y2bgr(const unsigned char *src, unsigned char *dest,
 y162bgr(const unsigned char *src, unsigned char *dest,
         unsigned long long int NumPixels, int bits)
 {
-    register int i = (NumPixels << 1) - 1;
-    register int j = NumPixels + (NumPixels << 1) - 1;
-    register int y;
+    int i = (NumPixels << 1) - 1;
+    int j = NumPixels + (NumPixels << 1) - 1;
+    int y;
 
     while (i > 0) {
         y = src[i--];
@@ -1022,9 +1022,9 @@ y162bgr(const unsigned char *src, unsigned char *dest,
 rgb482bgr(const unsigned char *src, unsigned char *dest,
         unsigned long long int NumPixels, int bits)
 {
-    register int i = (NumPixels << 1) - 1;
-    register int j = NumPixels + (NumPixels << 1) - 1;
-    register int y;
+    int i = (NumPixels << 1) - 1;
+    int j = NumPixels + (NumPixels << 1) - 1;
+    int y;
 
     while (i > 0) {
         y = src[i--];
diff --git a/modules/videoio/src/cap_dshow.cpp b/modules/videoio/src/cap_dshow.cpp
index 4380b9b..8360e43 100644
--- a/modules/videoio/src/cap_dshow.cpp
+++ b/modules/videoio/src/cap_dshow.cpp
@@ -204,6 +204,7 @@ DEFINE_GUID(IID_ICreateDevEnum,0x29840822,0x5b84,0x11d0,0xbd,0x3b,0x00,0xa0,0xc9
 DEFINE_GUID(IID_IGraphBuilder,0x56a868a9,0x0ad4,0x11ce,0xb0,0x3a,0x00,0x20,0xaf,0x0b,0xa7,0x70);
 DEFINE_GUID(IID_IMPEG2PIDMap,0xafb6c2a1,0x2c41,0x11d3,0x8a,0x60,0x00,0x00,0xf8,0x1e,0x0e,0x4a);
 DEFINE_GUID(IID_IMediaControl,0x56a868b1,0x0ad4,0x11ce,0xb0,0x3a,0x00,0x20,0xaf,0x0b,0xa7,0x70);
+DEFINE_GUID(IID_IMediaEventEx, 0x56a868c0,0x0ad4,0x11ce,0xb0,0x3a,0x00,0x20,0xaf,0x0b,0xa7,0x70);
 DEFINE_GUID(IID_IMediaFilter,0x56a86899,0x0ad4,0x11ce,0xb0,0x3a,0x00,0x20,0xaf,0x0b,0xa7,0x70);
 DEFINE_GUID(IID_ISampleGrabber,0x6b652fff,0x11fe,0x4fce,0x92,0xad,0x02,0x66,0xb5,0xd7,0xc7,0x8f);
 DEFINE_GUID(LOOK_UPSTREAM_ONLY,0xac798be0,0x98e3,0x11d1,0xb3,0xf1,0x00,0xaa,0x00,0x37,0x61,0xc5);
@@ -573,6 +574,8 @@ class videoInput{
         int getVideoPropertyFromCV(int cv_property);
         int getCameraPropertyFromCV(int cv_property);
 
+        bool isDeviceDisconnected(int deviceID);
+
     private:
         void setPhyCon(int deviceID, int conn);
         void setAttemptCaptureSize(int deviceID, int w, int h,GUID mediaType=MEDIASUBTYPE_RGB24);
@@ -2309,6 +2312,27 @@ int videoInput::getCameraPropertyFromCV(int cv_property){
     return -1;
 }
 
+bool videoInput::isDeviceDisconnected(int deviceNumber)
+{
+    if (!isDeviceSetup(deviceNumber)) return true;
+    long evCode;
+    LONG_PTR param1, param2;
+    bool disconnected = false;
+
+    while (S_OK == VDList[deviceNumber]->pMediaEvent->GetEvent(&evCode, &param1, &param2, 0))
+    {
+        DebugPrintOut("Event: Code: %#04x Params: %d, %d\n", evCode, param1, param2);
+
+        VDList[deviceNumber]->pMediaEvent->FreeEventParams(evCode, param1, param2);
+        if (evCode == EC_DEVICE_LOST)
+        {
+           DebugPrintOut("ERROR: Device disconnected\n");
+           disconnected = true;
+        }
+    }
+    return disconnected;
+}
+
 void videoInput::getCameraPropertyAsString(int prop, char * propertyAsString){
 
     char tmpStr[16];
@@ -2447,13 +2471,15 @@ static bool setSizeAndSubtype(videoDevice * VD, int attemptWidth, int attemptHei
     VD->pAmMediaType->subtype     = mediatype;
 
     //buffer size
-    if (mediatype == MEDIASUBTYPE_RGB24)
-    {
-        VD->pAmMediaType->lSampleSize = attemptWidth*attemptHeight*3;
+    if (mediatype == MEDIASUBTYPE_RGB24){
+        VD->pAmMediaType->lSampleSize = attemptWidth*attemptHeight * 3;
     }
-    else
-    {
-        // For compressed data, the value can be zero.
+    else if ((mediatype == MEDIASUBTYPE_YUY2) || (mediatype == MEDIASUBTYPE_YVYU) ||
+        (mediatype == MEDIASUBTYPE_UYVY)){
+
+        VD->pAmMediaType->lSampleSize = attemptWidth*attemptHeight * 2;
+    }
+    else{
         VD->pAmMediaType->lSampleSize = 0;
     }
 
@@ -2509,6 +2535,16 @@ int videoInput::start(int deviceID, videoDevice *VD){
         return hr;
     }
 
+    //MEDIA EVENT//
+    //Used to obtain event when capture device is disconnected
+    hr = VD->pGraph->QueryInterface(IID_IMediaEventEx, (void**)&VD->pMediaEvent);
+    if (FAILED(hr))
+    {
+        DebugPrintOut("ERROR - Could not create media event object\n");
+        stopDevice(deviceID);
+        return hr;
+    }
+
     //SET THE FILTERGRAPH//
     hr = VD->pCaptureGraph->SetFiltergraph(VD->pGraph);
     if (FAILED(hr))
@@ -3307,7 +3343,7 @@ bool VideoCapture_DShow::setProperty(int propIdx, double propVal)
 
 bool VideoCapture_DShow::grabFrame()
 {
-    return true;
+    return !g_VI.isDeviceDisconnected(m_index);
 }
 bool VideoCapture_DShow::retrieveFrame(int, OutputArray frame)
 {
diff --git a/modules/videoio/src/cap_ffmpeg.cpp b/modules/videoio/src/cap_ffmpeg.cpp
index b4348ea..26e2ead 100644
--- a/modules/videoio/src/cap_ffmpeg.cpp
+++ b/modules/videoio/src/cap_ffmpeg.cpp
@@ -41,6 +41,8 @@
 
 #include "precomp.hpp"
 
+#include <string>
+
 #if defined HAVE_FFMPEG && !defined WIN32
 #include "cap_ffmpeg_impl.hpp"
 #else
@@ -59,6 +61,19 @@ static CvWriteFrame_Plugin icvWriteFrame_FFMPEG_p = 0;
 
 static cv::Mutex _icvInitFFMPEG_mutex;
 
+#if defined WIN32 || defined _WIN32
+static const HMODULE cv_GetCurrentModule()
+{
+    HMODULE h = 0;
+#if _WIN32_WINNT >= 0x0501
+    ::GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
+        reinterpret_cast<LPCTSTR>(cv_GetCurrentModule),
+        &h);
+#endif
+    return h;
+}
+#endif
+
 class icvInitFFMPEG
 {
 public:
@@ -85,24 +100,43 @@ private:
     icvInitFFMPEG()
     {
     #if defined WIN32 || defined _WIN32
-    # ifdef WINRT
-        const wchar_t* module_name = L"opencv_ffmpeg"
+        const wchar_t* module_name_ = L"opencv_ffmpeg"
             CVAUX_STRW(CV_MAJOR_VERSION) CVAUX_STRW(CV_MINOR_VERSION) CVAUX_STRW(CV_SUBMINOR_VERSION)
         #if (defined _MSC_VER && defined _M_X64) || (defined __GNUC__ && defined __x86_64__)
             L"_64"
         #endif
             L".dll";
-
-        icvFFOpenCV = LoadPackagedLibrary( module_name, 0 );
+    # ifdef WINRT
+        icvFFOpenCV = LoadPackagedLibrary( module_name_, 0 );
     # else
-        const char* module_name = "opencv_ffmpeg"
-            CVAUX_STR(CV_MAJOR_VERSION) CVAUX_STR(CV_MINOR_VERSION) CVAUX_STR(CV_SUBMINOR_VERSION)
-        #if (defined _MSC_VER && defined _M_X64) || (defined __GNUC__ && defined __x86_64__)
-            "_64"
-        #endif
-            ".dll";
+        const std::wstring module_name(module_name_);
+
+        const wchar_t* ffmpeg_env_path = _wgetenv(L"OPENCV_FFMPEG_DLL_DIR");
+        std::wstring module_path =
+                ffmpeg_env_path
+                ? ((std::wstring(ffmpeg_env_path) + L"\\") + module_name)
+                : module_name;
 
-        icvFFOpenCV = LoadLibrary( module_name );
+        icvFFOpenCV = LoadLibraryW(module_path.c_str());
+        if(!icvFFOpenCV && !ffmpeg_env_path)
+        {
+            HMODULE m = cv_GetCurrentModule();
+            if (m)
+            {
+                wchar_t path[MAX_PATH];
+                size_t sz = GetModuleFileNameW(m, path, sizeof(path));
+                if (sz > 0 && ERROR_SUCCESS == GetLastError())
+                {
+                    wchar_t* s = wcsrchr(path, L'\\');
+                    if (s)
+                    {
+                        s[0] = 0;
+                        module_path = (std::wstring(path) + L"\\") + module_name;
+                        icvFFOpenCV = LoadLibraryW(module_path.c_str());
+                    }
+                }
+            }
+        }
     # endif
 
         if( icvFFOpenCV )
diff --git a/modules/videoio/src/cap_ffmpeg_impl.hpp b/modules/videoio/src/cap_ffmpeg_impl.hpp
index cf8a1c6..fc5141e 100644
--- a/modules/videoio/src/cap_ffmpeg_impl.hpp
+++ b/modules/videoio/src/cap_ffmpeg_impl.hpp
@@ -70,48 +70,13 @@ extern "C" {
   #include <libavutil/opt.h>
 #endif
 
-#ifdef WIN32
-  #define HAVE_FFMPEG_SWSCALE 1
-  #include <libavcodec/avcodec.h>
-  #include <libswscale/swscale.h>
-#else
-
-#ifndef HAVE_FFMPEG_SWSCALE
-    #error "libswscale is necessary to build the newer OpenCV ffmpeg wrapper"
-#endif
-
-// if the header path is not specified explicitly, let's deduce it
-#if !defined HAVE_FFMPEG_AVCODEC_H && !defined HAVE_LIBAVCODEC_AVCODEC_H
-
-#if defined(HAVE_GENTOO_FFMPEG)
-  #define HAVE_LIBAVCODEC_AVCODEC_H 1
-  #if defined(HAVE_FFMPEG_SWSCALE)
-    #define HAVE_LIBSWSCALE_SWSCALE_H 1
-  #endif
-#elif defined HAVE_FFMPEG
-  #define HAVE_FFMPEG_AVCODEC_H 1
-  #if defined(HAVE_FFMPEG_SWSCALE)
-    #define HAVE_FFMPEG_SWSCALE_H 1
-  #endif
-#endif
-
-#endif
-
-#if defined(HAVE_FFMPEG_AVCODEC_H)
-  #include <ffmpeg/avcodec.h>
-#endif
-#if defined(HAVE_FFMPEG_SWSCALE_H)
-  #include <ffmpeg/swscale.h>
-#endif
-
-#if defined(HAVE_LIBAVCODEC_AVCODEC_H)
-  #include <libavcodec/avcodec.h>
-#endif
-#if defined(HAVE_LIBSWSCALE_SWSCALE_H)
-  #include <libswscale/swscale.h>
+#if LIBAVUTIL_BUILD >= (LIBAVUTIL_VERSION_MICRO >= 100 \
+    ? CALC_FFMPEG_VERSION(51, 63, 100) : CALC_FFMPEG_VERSION(54, 6, 0))
+#include <libavutil/imgutils.h>
 #endif
 
-#endif
+#include <libavcodec/avcodec.h>
+#include <libswscale/swscale.h>
 
 #ifdef __cplusplus
 }
@@ -129,12 +94,22 @@ extern "C" {
 
 #if defined WIN32 || defined _WIN32
     #include <windows.h>
+    #if defined _MSC_VER && _MSC_VER < 1900
+    struct timespec
+    {
+        time_t tv_sec;
+        long   tv_nsec;
+    };
+  #endif
 #elif defined __linux__ || defined __APPLE__
     #include <unistd.h>
     #include <stdio.h>
     #include <sys/types.h>
+    #include <sys/time.h>
 #if defined __APPLE__
     #include <sys/sysctl.h>
+    #include <mach/clock.h>
+    #include <mach/mach.h>
 #endif
 #endif
 
@@ -174,6 +149,142 @@ extern "C" {
 #define AV_PIX_FMT_GRAY16BE PIX_FMT_GRAY16BE
 #endif
 
+#if LIBAVUTIL_BUILD >= (LIBAVUTIL_VERSION_MICRO >= 100 \
+    ? CALC_FFMPEG_VERSION(52, 38, 100) : CALC_FFMPEG_VERSION(52, 13, 0))
+#define USE_AV_FRAME_GET_BUFFER 1
+#else
+#define USE_AV_FRAME_GET_BUFFER 0
+#ifndef AV_NUM_DATA_POINTERS // required for 0.7.x/0.8.x ffmpeg releases
+#define AV_NUM_DATA_POINTERS 4
+#endif
+#endif
+
+
+#ifndef USE_AV_INTERRUPT_CALLBACK
+#if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(53, 21, 0)
+#define USE_AV_INTERRUPT_CALLBACK 1
+#else
+#define USE_AV_INTERRUPT_CALLBACK 0
+#endif
+#endif
+
+#if USE_AV_INTERRUPT_CALLBACK
+#define LIBAVFORMAT_INTERRUPT_OPEN_TIMEOUT_MS 30000
+#define LIBAVFORMAT_INTERRUPT_READ_TIMEOUT_MS 30000
+
+#ifdef WIN32
+// http://stackoverflow.com/questions/5404277/porting-clock-gettime-to-windows
+
+static
+inline LARGE_INTEGER get_filetime_offset()
+{
+    SYSTEMTIME s;
+    FILETIME f;
+    LARGE_INTEGER t;
+
+    s.wYear = 1970;
+    s.wMonth = 1;
+    s.wDay = 1;
+    s.wHour = 0;
+    s.wMinute = 0;
+    s.wSecond = 0;
+    s.wMilliseconds = 0;
+    SystemTimeToFileTime(&s, &f);
+    t.QuadPart = f.dwHighDateTime;
+    t.QuadPart <<= 32;
+    t.QuadPart |= f.dwLowDateTime;
+    return t;
+}
+
+static
+inline void get_monotonic_time(timespec *tv)
+{
+    LARGE_INTEGER           t;
+    FILETIME				f;
+    double                  microseconds;
+    static LARGE_INTEGER    offset;
+    static double           frequencyToMicroseconds;
+    static int              initialized = 0;
+    static BOOL             usePerformanceCounter = 0;
+
+    if (!initialized)
+    {
+        LARGE_INTEGER performanceFrequency;
+        initialized = 1;
+        usePerformanceCounter = QueryPerformanceFrequency(&performanceFrequency);
+        if (usePerformanceCounter)
+        {
+            QueryPerformanceCounter(&offset);
+            frequencyToMicroseconds = (double)performanceFrequency.QuadPart / 1000000.;
+        }
+        else
+        {
+            offset = get_filetime_offset();
+            frequencyToMicroseconds = 10.;
+        }
+    }
+
+    if (usePerformanceCounter)
+    {
+        QueryPerformanceCounter(&t);
+    } else {
+        GetSystemTimeAsFileTime(&f);
+        t.QuadPart = f.dwHighDateTime;
+        t.QuadPart <<= 32;
+        t.QuadPart |= f.dwLowDateTime;
+    }
+
+    t.QuadPart -= offset.QuadPart;
+    microseconds = (double)t.QuadPart / frequencyToMicroseconds;
+    t.QuadPart = microseconds;
+    tv->tv_sec = t.QuadPart / 1000000;
+    tv->tv_nsec = (t.QuadPart % 1000000) * 1000;
+}
+#else
+static
+inline void get_monotonic_time(timespec *time)
+{
+#if defined(__APPLE__) && defined(__MACH__)
+    clock_serv_t cclock;
+    mach_timespec_t mts;
+    host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock);
+    clock_get_time(cclock, &mts);
+    mach_port_deallocate(mach_task_self(), cclock);
+    time->tv_sec = mts.tv_sec;
+    time->tv_nsec = mts.tv_nsec;
+#else
+    clock_gettime(CLOCK_MONOTONIC, time);
+#endif
+}
+#endif
+
+static
+inline timespec get_monotonic_time_diff(timespec start, timespec end)
+{
+    timespec temp;
+    if (end.tv_nsec - start.tv_nsec < 0)
+    {
+        temp.tv_sec = end.tv_sec - start.tv_sec - 1;
+        temp.tv_nsec = 1000000000 + end.tv_nsec - start.tv_nsec;
+    }
+    else
+    {
+        temp.tv_sec = end.tv_sec - start.tv_sec;
+        temp.tv_nsec = end.tv_nsec - start.tv_nsec;
+    }
+    return temp;
+}
+
+static
+inline double get_monotonic_time_diff_ms(timespec time1, timespec time2)
+{
+    timespec delta = get_monotonic_time_diff(time1, time2);
+    double milliseconds = delta.tv_sec * 1000 + (double)delta.tv_nsec / 1000000.0;
+
+    return milliseconds;
+}
+#endif // USE_AV_INTERRUPT_CALLBACK
+
 static int get_number_of_cpus(void)
 {
 #if LIBAVFORMAT_BUILD < CALC_FFMPEG_VERSION(52, 111, 0)
@@ -223,12 +334,74 @@ struct Image_FFMPEG
 };
 
 
+#if USE_AV_INTERRUPT_CALLBACK
+struct AVInterruptCallbackMetadata
+{
+    timespec value;
+    unsigned int timeout_after_ms;
+    int timeout;
+};
+
+static
 inline void _opencv_ffmpeg_free(void** ptr)
 {
     if(*ptr) free(*ptr);
     *ptr = 0;
 }
 
+static
+inline int _opencv_ffmpeg_interrupt_callback(void *ptr)
+{
+    AVInterruptCallbackMetadata* metadata = (AVInterruptCallbackMetadata*)ptr;
+    assert(metadata);
+
+    if (metadata->timeout_after_ms == 0)
+    {
+        return 0; // timeout is disabled
+    }
+
+    timespec now;
+    get_monotonic_time(&now);
+
+    metadata->timeout = get_monotonic_time_diff_ms(metadata->value, now) > metadata->timeout_after_ms;
+
+    return metadata->timeout ? -1 : 0;
+}
+#endif
+
+static
+inline void _opencv_ffmpeg_av_packet_unref(AVPacket *pkt)
+{
+#if LIBAVCODEC_BUILD >= (LIBAVCODEC_VERSION_MICRO >= 100 \
+    ? CALC_FFMPEG_VERSION(55, 25, 100) : CALC_FFMPEG_VERSION(55, 16, 0))
+    av_packet_unref(pkt);
+#else
+    av_free_packet(pkt);
+#endif
+};
+
+static
+inline void _opencv_ffmpeg_av_image_fill_arrays(void *frame, uint8_t *ptr, enum AVPixelFormat pix_fmt, int width, int height)
+{
+#if LIBAVUTIL_BUILD >= (LIBAVUTIL_VERSION_MICRO >= 100 \
+    ? CALC_FFMPEG_VERSION(51, 63, 100) : CALC_FFMPEG_VERSION(54, 6, 0))
+    av_image_fill_arrays(((AVFrame*)frame)->data, ((AVFrame*)frame)->linesize, ptr, pix_fmt, width, height, 1);
+#else
+    avpicture_fill((AVPicture*)frame, ptr, pix_fmt, width, height);
+#endif
+};
+
+static
+inline int _opencv_ffmpeg_av_image_get_buffer_size(enum AVPixelFormat pix_fmt, int width, int height)
+{
+#if LIBAVUTIL_BUILD >= (LIBAVUTIL_VERSION_MICRO >= 100 \
+    ? CALC_FFMPEG_VERSION(51, 63, 100) : CALC_FFMPEG_VERSION(54, 6, 0))
+    return av_image_get_buffer_size(pix_fmt, width, height, 1);
+#else
+    return avpicture_get_size(pix_fmt, width, height);
+#endif
+};
+
 
 struct CvCapture_FFMPEG
 {
@@ -283,6 +456,9 @@ struct CvCapture_FFMPEG
 #if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(52, 111, 0)
     AVDictionary *dict;
 #endif
+#if USE_AV_INTERRUPT_CALLBACK
+    AVInterruptCallbackMetadata interrupt_metadata;
+#endif
 };
 
 void CvCapture_FFMPEG::init()
@@ -354,15 +530,19 @@ void CvCapture_FFMPEG::close()
         ic = NULL;
     }
 
+#if USE_AV_FRAME_GET_BUFFER
+    av_frame_unref(&rgb_picture);
+#else
     if( rgb_picture.data[0] )
     {
         free( rgb_picture.data[0] );
         rgb_picture.data[0] = 0;
     }
+#endif
 
     // free last packet if exist
     if (packet.data) {
-        av_free_packet (&packet);
+        _opencv_ffmpeg_av_packet_unref (&packet);
         packet.data = NULL;
     }
 
@@ -577,6 +757,16 @@ bool CvCapture_FFMPEG::open( const char* _filename )
 
     close();
 
+#if USE_AV_INTERRUPT_CALLBACK
+    /* interrupt callback */
+    interrupt_metadata.timeout_after_ms = LIBAVFORMAT_INTERRUPT_OPEN_TIMEOUT_MS;
+    get_monotonic_time(&interrupt_metadata.value);
+
+    ic = avformat_alloc_context();
+    ic->interrupt_callback.callback = _opencv_ffmpeg_interrupt_callback;
+    ic->interrupt_callback.opaque = &interrupt_metadata;
+#endif
+
 #if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(52, 111, 0)
     av_dict_set(&dict, "rtsp_transport", "tcp", 0);
     int err = avformat_open_input(&ic, _filename, NULL, &dict);
@@ -648,17 +838,11 @@ bool CvCapture_FFMPEG::open( const char* _filename )
             picture = avcodec_alloc_frame();
 #endif
 
-            rgb_picture.data[0] = (uint8_t*)malloc(
-                    avpicture_get_size( AV_PIX_FMT_BGR24,
-                                        enc->width, enc->height ));
-            avpicture_fill( (AVPicture*)&rgb_picture, rgb_picture.data[0],
-                            AV_PIX_FMT_BGR24, enc->width, enc->height );
-
             frame.width = enc->width;
             frame.height = enc->height;
             frame.cn = 3;
-            frame.step = rgb_picture.linesize[0];
-            frame.data = rgb_picture.data[0];
+            frame.step = 0;
+            frame.data = NULL;
             break;
         }
     }
@@ -667,6 +851,11 @@ bool CvCapture_FFMPEG::open( const char* _filename )
 
 exit_func:
 
+#if USE_AV_INTERRUPT_CALLBACK
+    // deactivate interrupt callback
+    interrupt_metadata.timeout_after_ms = 0;
+#endif
+
     if( !valid )
         close();
 
@@ -690,11 +879,26 @@ bool CvCapture_FFMPEG::grabFrame()
 
     picture_pts = AV_NOPTS_VALUE_;
 
+#if USE_AV_INTERRUPT_CALLBACK
+    // activate interrupt callback
+    get_monotonic_time(&interrupt_metadata.value);
+    interrupt_metadata.timeout_after_ms = LIBAVFORMAT_INTERRUPT_READ_TIMEOUT_MS;
+#endif
+
     // get the next frame
     while (!valid)
     {
 
-        av_free_packet (&packet);
+        _opencv_ffmpeg_av_packet_unref (&packet);
+
+#if USE_AV_INTERRUPT_CALLBACK
+        if (interrupt_metadata.timeout)
+        {
+            valid = false;
+            break;
+        }
+#endif
+
         int ret = av_read_frame(ic, &packet);
         if (ret == AVERROR(EAGAIN)) continue;
 
@@ -702,7 +906,7 @@ bool CvCapture_FFMPEG::grabFrame()
 
         if( packet.stream_index != video_stream )
         {
-            av_free_packet (&packet);
+            _opencv_ffmpeg_av_packet_unref (&packet);
             count_errs++;
             if (count_errs > max_number_of_attempts)
                 break;
@@ -727,7 +931,8 @@ bool CvCapture_FFMPEG::grabFrame()
         {
             //picture_pts = picture->best_effort_timestamp;
             if( picture_pts == AV_NOPTS_VALUE_ )
-                picture_pts = packet.pts != AV_NOPTS_VALUE_ && packet.pts != 0 ? packet.pts : packet.dts;
+                picture_pts = picture->pkt_pts != AV_NOPTS_VALUE_ && picture->pkt_pts != 0 ? picture->pkt_pts : picture->pkt_dts;
+
             frame_number++;
             valid = true;
         }
@@ -742,6 +947,11 @@ bool CvCapture_FFMPEG::grabFrame()
     if( valid && first_frame_number < 0 )
         first_frame_number = dts_to_frame_number(picture_pts);
 
+#if USE_AV_INTERRUPT_CALLBACK
+    // deactivate interrupt callback
+    interrupt_metadata.timeout_after_ms = 0;
+#endif
+
     // return if we have a new picture or not
     return valid;
 }
@@ -754,19 +964,18 @@ bool CvCapture_FFMPEG::retrieveFrame(int, unsigned char** data, int* step, int*
 
     if( img_convert_ctx == NULL ||
         frame.width != video_st->codec->width ||
-        frame.height != video_st->codec->height )
+        frame.height != video_st->codec->height ||
+        frame.data == NULL )
     {
-        if( img_convert_ctx )
-            sws_freeContext(img_convert_ctx);
-
-        frame.width = video_st->codec->width;
-        frame.height = video_st->codec->height;
+        // Some sws_scale optimizations have some assumptions about alignment of data/step/width/height
+        // Also we use coded_width/height to workaround problem with legacy ffmpeg versions (like n0.8)
+        int buffer_width = video_st->codec->coded_width, buffer_height = video_st->codec->coded_height;
 
         img_convert_ctx = sws_getCachedContext(
-                NULL,
-                video_st->codec->width, video_st->codec->height,
+                img_convert_ctx,
+                buffer_width, buffer_height,
                 video_st->codec->pix_fmt,
-                video_st->codec->width, video_st->codec->height,
+                buffer_width, buffer_height,
                 AV_PIX_FMT_BGR24,
                 SWS_BICUBIC,
                 NULL, NULL, NULL
@@ -775,21 +984,37 @@ bool CvCapture_FFMPEG::retrieveFrame(int, unsigned char** data, int* step, int*
         if (img_convert_ctx == NULL)
             return false;//CV_Error(0, "Cannot initialize the conversion context!");
 
+#if USE_AV_FRAME_GET_BUFFER
+        av_frame_unref(&rgb_picture);
+        rgb_picture.format = AV_PIX_FMT_BGR24;
+        rgb_picture.width = buffer_width;
+        rgb_picture.height = buffer_height;
+        if (0 != av_frame_get_buffer(&rgb_picture, 32))
+        {
+            CV_WARN("OutOfMemory");
+            return false;
+        }
+#else
+        int aligns[AV_NUM_DATA_POINTERS];
+        avcodec_align_dimensions2(video_st->codec, &buffer_width, &buffer_height, aligns);
         rgb_picture.data[0] = (uint8_t*)realloc(rgb_picture.data[0],
-                avpicture_get_size( AV_PIX_FMT_BGR24,
-                                    video_st->codec->width, video_st->codec->height ));
+                _opencv_ffmpeg_av_image_get_buffer_size( AV_PIX_FMT_BGR24,
+                                    buffer_width, buffer_height ));
+        _opencv_ffmpeg_av_image_fill_arrays(&rgb_picture, rgb_picture.data[0],
+                        AV_PIX_FMT_BGR24, buffer_width, buffer_height );
+#endif
+        frame.width = video_st->codec->width;
+        frame.height = video_st->codec->height;
+        frame.cn = 3;
         frame.data = rgb_picture.data[0];
+        frame.step = rgb_picture.linesize[0];
     }
 
-    avpicture_fill((AVPicture*)&rgb_picture, rgb_picture.data[0], AV_PIX_FMT_RGB24,
-                   video_st->codec->width, video_st->codec->height);
-    frame.step = rgb_picture.linesize[0];
-
     sws_scale(
             img_convert_ctx,
             picture->data,
             picture->linesize,
-            0, video_st->codec->height,
+            0, video_st->codec->coded_height,
             rgb_picture.data,
             rgb_picture.linesize
             );
@@ -870,6 +1095,9 @@ int CvCapture_FFMPEG::get_bitrate() const
 
 double CvCapture_FFMPEG::get_fps() const
 {
+#if 0 && LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(55, 1, 100) && LIBAVFORMAT_VERSION_MICRO >= 100
+    double fps = r2d(av_guess_frame_rate(ic, ic->streams[video_stream], NULL));
+#else
 #if LIBAVCODEC_BUILD >= CALC_FFMPEG_VERSION(54, 1, 0)
     double fps = r2d(ic->streams[video_stream]->avg_frame_rate);
 #else
@@ -887,7 +1115,7 @@ double CvCapture_FFMPEG::get_fps() const
     {
         fps = 1.0 / r2d(ic->streams[video_stream]->codec->time_base);
     }
-
+#endif
     return fps;
 }
 
@@ -1055,7 +1283,7 @@ struct CvVideoWriter_FFMPEG
     uint8_t         * picbuf;
     AVStream        * video_st;
     int               input_pix_fmt;
-    Image_FFMPEG      temp_image;
+    unsigned char   * aligned_input;
     int               frame_width, frame_height;
     int               frame_idx;
     bool              ok;
@@ -1132,7 +1360,7 @@ void CvVideoWriter_FFMPEG::init()
     picbuf = 0;
     video_st = 0;
     input_pix_fmt = 0;
-    memset(&temp_image, 0, sizeof(temp_image));
+    aligned_input = NULL;
     img_convert_ctx = 0;
     frame_width = frame_height = 0;
     frame_idx = 0;
@@ -1162,7 +1390,7 @@ static AVFrame * icv_alloc_picture_FFMPEG(int pix_fmt, int width, int height, bo
     picture->width = width;
     picture->height = height;
 
-    size = avpicture_get_size( (AVPixelFormat) pix_fmt, width, height);
+    size = _opencv_ffmpeg_av_image_get_buffer_size( (AVPixelFormat) pix_fmt, width, height);
     if(alloc){
         picture_buf = (uint8_t *) malloc(size);
         if (!picture_buf)
@@ -1170,7 +1398,7 @@ static AVFrame * icv_alloc_picture_FFMPEG(int pix_fmt, int width, int height, bo
             av_free(picture);
             return NULL;
         }
-        avpicture_fill((AVPicture *)picture, picture_buf,
+        _opencv_ffmpeg_av_image_fill_arrays(picture, picture_buf,
                        (AVPixelFormat) pix_fmt, width, height);
     }
     else {
@@ -1314,6 +1542,10 @@ static AVStream *icv_add_video_stream_FFMPEG(AVFormatContext *oc,
     }
 #endif
 
+#if LIBAVCODEC_BUILD >= CALC_FFMPEG_VERSION(52, 42, 0)
+    st->avg_frame_rate = (AVRational){frame_rate, frame_rate_base};
+#endif
+
     return st;
 }
 
@@ -1370,7 +1602,7 @@ static int icv_av_write_frame_FFMPEG( AVFormatContext * oc, AVStream * video_st,
                 pkt.duration = av_rescale_q(pkt.duration, c->time_base, video_st->time_base);
             pkt.stream_index= video_st->index;
             ret = av_write_frame(oc, &pkt);
-            av_free_packet(&pkt);
+            _opencv_ffmpeg_av_packet_unref(&pkt);
         }
         else
             ret = OPENCV_NO_FRAMES_WRITTEN_CODE;
@@ -1401,7 +1633,20 @@ static int icv_av_write_frame_FFMPEG( AVFormatContext * oc, AVStream * video_st,
 /// write a frame with FFMPEG
 bool CvVideoWriter_FFMPEG::writeFrame( const unsigned char* data, int step, int width, int height, int cn, int origin )
 {
-    bool ret = false;
+    // check parameters
+    if (input_pix_fmt == AV_PIX_FMT_BGR24) {
+        if (cn != 3) {
+            return false;
+        }
+    }
+    else if (input_pix_fmt == AV_PIX_FMT_GRAY8) {
+        if (cn != 1) {
+            return false;
+        }
+    }
+    else {
+        assert(false);
+    }
 
     if( (width & -2) != frame_width || (height & -2) != frame_height || !data )
         return false;
@@ -1415,65 +1660,37 @@ bool CvVideoWriter_FFMPEG::writeFrame( const unsigned char* data, int step, int
     AVCodecContext *c = &(video_st->codec);
 #endif
 
-#if LIBAVFORMAT_BUILD < 5231
-    // It is not needed in the latest versions of the ffmpeg
-    if( c->codec_id == CV_CODEC(CODEC_ID_RAWVIDEO) && origin != 1 )
+    // FFmpeg contains SIMD optimizations which can sometimes read data past
+    // the supplied input buffer. To ensure that doesn't happen, we pad the
+    // step to a multiple of 32 (that's the minimal alignment for which Valgrind
+    // doesn't raise any warnings).
+    const int STEP_ALIGNMENT = 32;
+    if( step % STEP_ALIGNMENT != 0 )
     {
-        if( !temp_image.data )
-        {
-            temp_image.step = (width*cn + 3) & -4;
-            temp_image.width = width;
-            temp_image.height = height;
-            temp_image.cn = cn;
-            temp_image.data = (unsigned char*)malloc(temp_image.step*temp_image.height);
-        }
-        for( int y = 0; y < height; y++ )
-            memcpy(temp_image.data + y*temp_image.step, data + (height-1-y)*step, width*cn);
-        data = temp_image.data;
-        step = temp_image.step;
-    }
-#else
-    if( width*cn != step )
-    {
-        if( !temp_image.data )
+        int aligned_step = (step + STEP_ALIGNMENT - 1) & -STEP_ALIGNMENT;
+
+        if( !aligned_input )
         {
-            temp_image.step = width*cn;
-            temp_image.width = width;
-            temp_image.height = height;
-            temp_image.cn = cn;
-            temp_image.data = (unsigned char*)malloc(temp_image.step*temp_image.height);
+            aligned_input = (unsigned char*)av_mallocz(aligned_step * height);
         }
+
         if (origin == 1)
             for( int y = 0; y < height; y++ )
-                memcpy(temp_image.data + y*temp_image.step, data + (height-1-y)*step, temp_image.step);
+                memcpy(aligned_input + y*aligned_step, data + (height-1-y)*step, step);
         else
             for( int y = 0; y < height; y++ )
-                memcpy(temp_image.data + y*temp_image.step, data + y*step, temp_image.step);
-        data = temp_image.data;
-        step = temp_image.step;
-    }
-#endif
+                memcpy(aligned_input + y*aligned_step, data + y*step, step);
 
-    // check parameters
-    if (input_pix_fmt == AV_PIX_FMT_BGR24) {
-        if (cn != 3) {
-            return false;
-        }
-    }
-    else if (input_pix_fmt == AV_PIX_FMT_GRAY8) {
-        if (cn != 1) {
-            return false;
-        }
-    }
-    else {
-        assert(false);
+        data = aligned_input;
+        step = aligned_step;
     }
 
     if ( c->pix_fmt != input_pix_fmt ) {
         assert( input_picture );
         // let input_picture point to the raw data buffer of 'image'
-        avpicture_fill((AVPicture *)input_picture, (uint8_t *) data,
+        _opencv_ffmpeg_av_image_fill_arrays(input_picture, (uint8_t *) data,
                        (AVPixelFormat)input_pix_fmt, width, height);
+        input_picture->linesize[0] = step;
 
         if( !img_convert_ctx )
         {
@@ -1496,12 +1713,13 @@ bool CvVideoWriter_FFMPEG::writeFrame( const unsigned char* data, int step, int
             return false;
     }
     else{
-        avpicture_fill((AVPicture *)picture, (uint8_t *) data,
+        _opencv_ffmpeg_av_image_fill_arrays(picture, (uint8_t *) data,
                        (AVPixelFormat)input_pix_fmt, width, height);
+        picture->linesize[0] = step;
     }
 
     picture->pts = frame_idx;
-    ret = icv_av_write_frame_FFMPEG( oc, video_st, outbuf, outbuf_size, picture) >= 0;
+    bool ret = icv_av_write_frame_FFMPEG( oc, video_st, outbuf, outbuf_size, picture) >= 0;
     frame_idx++;
 
     return ret;
@@ -1584,11 +1802,7 @@ void CvVideoWriter_FFMPEG::close()
     /* free the stream */
     avformat_free_context(oc);
 
-    if( temp_image.data )
-    {
-        free(temp_image.data);
-        temp_image.data = 0;
-    }
+    av_freep(&aligned_input);
 
     init();
 }
@@ -2201,11 +2415,14 @@ bool OutputMediaStream_FFMPEG::open(const char* fileName, int width, int height,
     }
 
     // write the stream header, if any
+    int header_err =
     #if LIBAVFORMAT_BUILD < CALC_FFMPEG_VERSION(53, 2, 0)
         av_write_header(oc_);
     #else
         avformat_write_header(oc_, NULL);
     #endif
+    if (header_err != 0)
+        return false;
 
     return true;
 }
@@ -2300,6 +2517,10 @@ private:
     AVFormatContext* ctx_;
     int video_stream_id_;
     AVPacket pkt_;
+
+#if USE_AV_INTERRUPT_CALLBACK
+    AVInterruptCallbackMetadata interrupt_metadata;
+#endif
 };
 
 bool InputMediaStream_FFMPEG::open(const char* fileName, int* codec, int* chroma_format, int* width, int* height)
@@ -2310,6 +2531,16 @@ bool InputMediaStream_FFMPEG::open(const char* fileName, int* codec, int* chroma
     video_stream_id_ = -1;
     memset(&pkt_, 0, sizeof(AVPacket));
 
+#if USE_AV_INTERRUPT_CALLBACK
+    /* interrupt callback */
+    interrupt_metadata.timeout_after_ms = LIBAVFORMAT_INTERRUPT_OPEN_TIMEOUT_MS;
+    get_monotonic_time(&interrupt_metadata.value);
+
+    ctx_ = avformat_alloc_context();
+    ctx_->interrupt_callback.callback = _opencv_ffmpeg_interrupt_callback;
+    ctx_->interrupt_callback.opaque = &interrupt_metadata;
+#endif
+
     #if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(53, 13, 0)
         avformat_network_init();
     #endif
@@ -2398,6 +2629,11 @@ bool InputMediaStream_FFMPEG::open(const char* fileName, int* codec, int* chroma
 
     av_init_packet(&pkt_);
 
+#if USE_AV_INTERRUPT_CALLBACK
+    // deactivate interrupt callback
+    interrupt_metadata.timeout_after_ms = 0;
+#endif
+
     return true;
 }
 
@@ -2414,18 +2650,33 @@ void InputMediaStream_FFMPEG::close()
 
     // free last packet if exist
     if (pkt_.data)
-        av_free_packet(&pkt_);
+        _opencv_ffmpeg_av_packet_unref(&pkt_);
 }
 
 bool InputMediaStream_FFMPEG::read(unsigned char** data, int* size, int* endOfFile)
 {
+    bool result = false;
+
+#if USE_AV_INTERRUPT_CALLBACK
+    // activate interrupt callback
+    get_monotonic_time(&interrupt_metadata.value);
+    interrupt_metadata.timeout_after_ms = LIBAVFORMAT_INTERRUPT_READ_TIMEOUT_MS;
+#endif
+
     // free last packet if exist
     if (pkt_.data)
-        av_free_packet(&pkt_);
+        _opencv_ffmpeg_av_packet_unref(&pkt_);
 
     // get the next frame
     for (;;)
     {
+#if USE_AV_INTERRUPT_CALLBACK
+        if(interrupt_metadata.timeout)
+        {
+            break;
+        }
+#endif
+
         int ret = av_read_frame(ctx_, &pkt_);
 
         if (ret == AVERROR(EAGAIN))
@@ -2435,23 +2686,32 @@ bool InputMediaStream_FFMPEG::read(unsigned char** data, int* size, int* endOfFi
         {
             if (ret == (int)AVERROR_EOF)
                 *endOfFile = true;
-            return false;
+            break;
         }
 
         if (pkt_.stream_index != video_stream_id_)
         {
-            av_free_packet(&pkt_);
+            _opencv_ffmpeg_av_packet_unref(&pkt_);
             continue;
         }
 
+        result = true;
         break;
     }
 
-    *data = pkt_.data;
-    *size = pkt_.size;
-    *endOfFile = false;
+#if USE_AV_INTERRUPT_CALLBACK
+    // deactivate interrupt callback
+    interrupt_metadata.timeout_after_ms = 0;
+#endif
 
-    return true;
+    if (result)
+    {
+        *data = pkt_.data;
+        *size = pkt_.size;
+        *endOfFile = false;
+    }
+
+    return result;
 }
 
 InputMediaStream_FFMPEG* create_InputMediaStream_FFMPEG(const char* fileName, int* codec, int* chroma_format, int* width, int* height)
diff --git a/modules/videoio/src/cap_gphoto2.cpp b/modules/videoio/src/cap_gphoto2.cpp
index fd1b302..7fa94f5 100644
--- a/modules/videoio/src/cap_gphoto2.cpp
+++ b/modules/videoio/src/cap_gphoto2.cpp
@@ -981,7 +981,7 @@ CameraWidget * DigitalCameraCapture::findWidgetByName(
                 CR(gp_widget_get_name(it->second, &name));
                 if (strstr(name, subName))
                     break;
-                it++;
+                ++it;
             }
             return (it != end) ? it->second : NULL;
         }
diff --git a/modules/videoio/src/cap_gstreamer.cpp b/modules/videoio/src/cap_gstreamer.cpp
index 41754ea..552c1cb 100644
--- a/modules/videoio/src/cap_gstreamer.cpp
+++ b/modules/videoio/src/cap_gstreamer.cpp
@@ -292,18 +292,22 @@ IplImage * CvCapture_GStreamer::retrieveFrame(int)
         const gchar* name = gst_structure_get_name(structure);
         const gchar* format = gst_structure_get_string(structure, "format");
 
-        if (!name || !format)
+        if (!name)
             return 0;
 
         // we support 3 types of data:
         //     video/x-raw, format=BGR   -> 8bit, 3 channels
         //     video/x-raw, format=GRAY8 -> 8bit, 1 channel
         //     video/x-bayer             -> 8bit, 1 channel
+        //     image/jpeg                -> 8bit, mjpeg: buffer_size x 1 x 1
         // bayer data is never decoded, the user is responsible for that
         // everything is 8 bit, so we just test the caps for bit depth
 
         if (strcasecmp(name, "video/x-raw") == 0)
         {
+            if (!format)
+                return 0;
+
             if (strcasecmp(format, "BGR") == 0) {
                 depth = 3;
             }
@@ -314,6 +318,9 @@ IplImage * CvCapture_GStreamer::retrieveFrame(int)
         else if (strcasecmp(name, "video/x-bayer") == 0)
         {
             depth = 1;
+        } else if(strcasecmp(name, "image/jpeg") == 0) {
+            depth = 1;
+            // the correct size will be set once the first frame arrives
         }
 #endif
         if (depth > 0) {
@@ -334,6 +341,13 @@ IplImage * CvCapture_GStreamer::retrieveFrame(int)
     // info.data ptr is valid until next grabFrame where the associated sample is unref'd
     GstMapInfo info = GstMapInfo();
     gboolean success = gst_buffer_map(buffer,&info, (GstMapFlags)GST_MAP_READ);
+
+    // with MJPEG streams frame size can change arbitrarily
+    if(int(info.size) != frame->imageSize) {
+        cvReleaseImageHeader(&frame);
+        frame = cvCreateImageHeader(cvSize(info.size, 1), IPL_DEPTH_8U, 1);
+    }
+
     if (!success){
         //something weird went wrong here. abort. abort.
         //fprintf(stderr,"GStreamer: unable to map buffer");
@@ -608,7 +622,7 @@ bool CvCapture_GStreamer::open( int type, const char* filename )
         struct stat buf;
         if (pathSize == 0 || stat(uri, &buf) != 0)
         {
-            delete uri;
+            delete[] uri;
             uri = NULL;
         }
 #else
@@ -797,7 +811,7 @@ bool CvCapture_GStreamer::open( int type, const char* filename )
                                NULL);
 #else
     // support 1 and 3 channel 8 bit data, as well as bayer (also  1 channel, 8bit)
-    caps = gst_caps_from_string("video/x-raw, format=(string){BGR, GRAY8}; video/x-bayer,format=(string){rggb,bggr,grbg,gbrg}");
+    caps = gst_caps_from_string("video/x-raw, format=(string){BGR, GRAY8}; video/x-bayer,format=(string){rggb,bggr,grbg,gbrg}; image/jpeg");
 #endif
     gst_app_sink_set_caps(GST_APP_SINK(sink), caps);
     gst_caps_unref(caps);
@@ -833,7 +847,7 @@ bool CvCapture_GStreamer::open( int type, const char* filename )
             duration = -1;
         }
 
-        GstPad* pad = gst_element_get_static_pad(color, "src");
+        GstPad* pad = gst_element_get_static_pad(sink, "sink");
 #if GST_VERSION_MAJOR == 0
         GstCaps* buffer_caps = gst_pad_get_caps(pad);
 #else
@@ -860,8 +874,8 @@ bool CvCapture_GStreamer::open( int type, const char* filename )
         fps = (double)num/(double)denom;
 
          // GST_DEBUG_BIN_TO_DOT_FILE(GST_BIN(pipeline), GST_DEBUG_GRAPH_SHOW_ALL, "pipeline")
-
-        stopPipeline();
+        if (file)
+            stopPipeline();
     }
 
     __END__;
@@ -1400,7 +1414,19 @@ bool CvVideoWriter_GStreamer::open( const char * filename, int fourcc,
         g_object_set(G_OBJECT(file), "location", filename, NULL);
     }
 
-    if (is_color)
+    if (fourcc == CV_FOURCC('M','J','P','G') && frameSize.height == 1)
+    {
+#if GST_VERSION_MAJOR > 0
+        input_pix_fmt = GST_VIDEO_FORMAT_ENCODED;
+        caps = gst_caps_new_simple("image/jpeg",
+                                   "framerate", GST_TYPE_FRACTION, int(fps), 1,
+                                   NULL);
+        caps = gst_caps_fixate(caps);
+#else
+        CV_ERROR( CV_StsUnsupportedFormat, "Gstreamer 0.10 Opencv backend does not support writing encoded MJPEG data.");
+#endif
+    }
+    else if(is_color)
     {
         input_pix_fmt = GST_VIDEO_FORMAT_BGR;
         bufsize = frameSize.width * frameSize.height * 3;
@@ -1561,7 +1587,15 @@ bool CvVideoWriter_GStreamer::writeFrame( const IplImage * image )
 
     handleMessage(pipeline);
 
-    if (input_pix_fmt == GST_VIDEO_FORMAT_BGR) {
+#if GST_VERSION_MAJOR > 0
+    if (input_pix_fmt == GST_VIDEO_FORMAT_ENCODED) {
+        if (image->nChannels != 1 || image->depth != IPL_DEPTH_8U || image->height != 1) {
+            CV_ERROR(CV_StsUnsupportedFormat, "cvWriteFrame() needs images with depth = IPL_DEPTH_8U, nChannels = 1 and height = 1.");
+        }
+    }
+    else
+#endif
+    if(input_pix_fmt == GST_VIDEO_FORMAT_BGR) {
         if (image->nChannels != 3 || image->depth != IPL_DEPTH_8U) {
             CV_ERROR(CV_StsUnsupportedFormat, "cvWriteFrame() needs images with depth = IPL_DEPTH_8U and nChannels = 3.");
         }
diff --git a/modules/videoio/src/cap_images.cpp b/modules/videoio/src/cap_images.cpp
index 00d5af4..f87c554 100644
--- a/modules/videoio/src/cap_images.cpp
+++ b/modules/videoio/src/cap_images.cpp
@@ -124,7 +124,7 @@ bool CvCapture_Images::grabFrame()
     }
 
     cvReleaseImage(&frame);
-    frame = cvLoadImage(str, CV_LOAD_IMAGE_ANYDEPTH | CV_LOAD_IMAGE_ANYCOLOR);
+    frame = cvLoadImage(str, CV_LOAD_IMAGE_UNCHANGED);
     if( frame )
         currentframe++;
 
@@ -332,18 +332,23 @@ public:
 
     virtual bool open( const char* _filename );
     virtual void close();
+    virtual bool setProperty( int, double );
     virtual bool writeFrame( const IplImage* );
 
 protected:
     char* filename;
     unsigned currentframe;
+    std::vector<int> params;
 };
 
 bool CvVideoWriter_Images::writeFrame( const IplImage* image )
 {
     char str[_MAX_PATH];
     sprintf(str, filename, currentframe);
-    int ret = cvSaveImage(str, image);
+    std::vector<int> image_params = params;
+    image_params.push_back(0); // append parameters 'stop' mark
+    image_params.push_back(0);
+    int ret = cvSaveImage(str, image, &image_params[0]);
 
     currentframe++;
 
@@ -358,6 +363,7 @@ void CvVideoWriter_Images::close()
         filename = 0;
     }
     currentframe = 0;
+    params.clear();
 }
 
 
@@ -380,10 +386,23 @@ bool CvVideoWriter_Images::open( const char* _filename )
     }
 
     currentframe = offset;
+    params.clear();
     return true;
 }
 
 
+bool CvVideoWriter_Images::setProperty( int id, double value )
+{
+    if (id >= cv::CAP_PROP_IMAGES_BASE && id < cv::CAP_PROP_IMAGES_LAST)
+    {
+        params.push_back( id - cv::CAP_PROP_IMAGES_BASE );
+        params.push_back( static_cast<int>( value ) );
+        return true;
+    }
+    return false; // not supported
+}
+
+
 CvVideoWriter* cvCreateVideoWriter_Images( const char* filename )
 {
     CvVideoWriter_Images *writer = new CvVideoWriter_Images;
diff --git a/modules/videoio/src/cap_ios_abstract_camera.mm b/modules/videoio/src/cap_ios_abstract_camera.mm
index 565807c..032ab85 100644
--- a/modules/videoio/src/cap_ios_abstract_camera.mm
+++ b/modules/videoio/src/cap_ios_abstract_camera.mm
@@ -37,7 +37,7 @@
 
 @interface CvAbstractCamera ()
 
- at property (nonatomic, retain) AVCaptureVideoPreviewLayer* captureVideoPreviewLayer;
+ at property (nonatomic, strong) AVCaptureVideoPreviewLayer* captureVideoPreviewLayer;
 
 - (void)deviceOrientationDidChange:(NSNotification*)notification;
 - (void)startCaptureSession;
@@ -170,7 +170,7 @@
     }
     running = YES;
 
-    // TOOD update image size data before actually starting (needed for recording)
+    // TODO: update image size data before actually starting (needed for recording)
     [self updateSize];
 
     if (cameraAvailable) {
@@ -193,18 +193,21 @@
 
     // Release any retained subviews of the main view.
     // e.g. self.myOutlet = nil;
-    for (AVCaptureInput *input in self.captureSession.inputs) {
-        [self.captureSession removeInput:input];
-    }
+    if (self.captureSession) {
+        for (AVCaptureInput *input in self.captureSession.inputs) {
+            [self.captureSession removeInput:input];
+        }
 
-    for (AVCaptureOutput *output in self.captureSession.outputs) {
-        [self.captureSession removeOutput:output];
+        for (AVCaptureOutput *output in self.captureSession.outputs) {
+            [self.captureSession removeOutput:output];
+        }
+
+        [self.captureSession stopRunning];
+        [captureSession release];
     }
 
-    [self.captureSession stopRunning];
-    self.captureSession = nil;
-    self.captureVideoPreviewLayer = nil;
-    self.videoCaptureConnection = nil;
+    [captureVideoPreviewLayer release];
+    [videoCaptureConnection release];
     captureSessionLoaded = NO;
 }
 
@@ -320,7 +323,7 @@
             NSError* error = nil;
             AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:device error:&error];
             if (!input) {
-                NSLog(@"error creating input %@", [error localizedDescription]);
+                NSLog(@"error creating input %@", [error description]);
             }
 
             // support for autofocus
@@ -330,7 +333,7 @@
                     device.focusMode = AVCaptureFocusModeContinuousAutoFocus;
                     [device unlockForConfiguration];
                 } else {
-                    NSLog(@"unable to lock device for autofocos configuration %@", [error localizedDescription]);
+                    NSLog(@"unable to lock device for autofocus configuration %@", [error description]);
                 }
             }
             [self.captureSession addInput:input];
@@ -376,13 +379,13 @@
 - (void)createCaptureOutput;
 {
     [NSException raise:NSInternalInconsistencyException
-                format:@"You must override %@ in a subclass", NSStringFromSelector(_cmd)];
+                format:@"You must override %s in a subclass", __FUNCTION__];
 }
 
 - (void)createCustomVideoPreview;
 {
     [NSException raise:NSInternalInconsistencyException
-                format:@"You must override %@ in a subclass", NSStringFromSelector(_cmd)];
+                format:@"You must override %s in a subclass", __FUNCTION__];
 }
 
 - (void)updateOrientation;
@@ -433,7 +436,7 @@
             device.focusMode = AVCaptureFocusModeLocked;
             [device unlockForConfiguration];
         } else {
-            NSLog(@"unable to lock device for locked focus configuration %@", [error localizedDescription]);
+            NSLog(@"unable to lock device for locked focus configuration %@", [error description]);
         }
     }
 }
@@ -447,7 +450,7 @@
             device.focusMode = AVCaptureFocusModeContinuousAutoFocus;
             [device unlockForConfiguration];
         } else {
-            NSLog(@"unable to lock device for autofocus configuration %@", [error localizedDescription]);
+            NSLog(@"unable to lock device for autofocus configuration %@", [error description]);
         }
     }
 }
@@ -461,7 +464,7 @@
             device.exposureMode = AVCaptureExposureModeLocked;
             [device unlockForConfiguration];
         } else {
-            NSLog(@"unable to lock device for locked exposure configuration %@", [error localizedDescription]);
+            NSLog(@"unable to lock device for locked exposure configuration %@", [error description]);
         }
     }
 }
@@ -475,7 +478,7 @@
             device.exposureMode = AVCaptureExposureModeContinuousAutoExposure;
             [device unlockForConfiguration];
         } else {
-            NSLog(@"unable to lock device for autoexposure configuration %@", [error localizedDescription]);
+            NSLog(@"unable to lock device for autoexposure configuration %@", [error description]);
         }
     }
 }
@@ -489,7 +492,7 @@
             device.whiteBalanceMode = AVCaptureWhiteBalanceModeLocked;
             [device unlockForConfiguration];
         } else {
-            NSLog(@"unable to lock device for locked white balance configuration %@", [error localizedDescription]);
+            NSLog(@"unable to lock device for locked white balance configuration %@", [error description]);
         }
     }
 }
@@ -503,7 +506,7 @@
             device.whiteBalanceMode = AVCaptureWhiteBalanceModeContinuousAutoWhiteBalance;
             [device unlockForConfiguration];
         } else {
-            NSLog(@"unable to lock device for auto white balance configuration %@", [error localizedDescription]);
+            NSLog(@"unable to lock device for auto white balance configuration %@", [error description]);
         }
     }
 }
diff --git a/modules/videoio/src/cap_ios_photo_camera.mm b/modules/videoio/src/cap_ios_photo_camera.mm
index c6c93a8..9b44156 100644
--- a/modules/videoio/src/cap_ios_photo_camera.mm
+++ b/modules/videoio/src/cap_ios_photo_camera.mm
@@ -36,8 +36,11 @@
 
 
 @interface CvPhotoCamera ()
+{
+    id<CvPhotoCameraDelegate> _delegate;
+}
 
- at property (nonatomic, retain) AVCaptureStillImageOutput* stillImageOutput;
+ at property (nonatomic, strong) AVCaptureStillImageOutput* stillImageOutput;
 
 @end
 
@@ -53,8 +56,14 @@
 #pragma mark Public
 
 @synthesize stillImageOutput;
- at synthesize delegate;
 
+- (void)setDelegate:(id<CvPhotoCameraDelegate>)newDelegate {
+    _delegate = newDelegate;
+}
+
+- (id<CvPhotoCameraDelegate>)delegate {
+    return _delegate;
+}
 
 #pragma mark - Public interface
 
@@ -106,9 +115,7 @@
                  cameraAvailable = YES;
 
                  NSLog(@"CvPhotoCamera captured image");
-                 if (self.delegate) {
-                     [self.delegate photoCamera:self capturedImage:newImage];
-                 }
+                 [self.delegate photoCamera:self capturedImage:newImage];
 
                  [self.captureSession startRunning];
              });
diff --git a/modules/videoio/src/cap_ios_video_camera.mm b/modules/videoio/src/cap_ios_video_camera.mm
index 1ae70e2..8a19a47 100644
--- a/modules/videoio/src/cap_ios_video_camera.mm
+++ b/modules/videoio/src/cap_ios_video_camera.mm
@@ -49,8 +49,8 @@ static CGFloat DegreesToRadians(CGFloat degrees) {return degrees * M_PI / 180;}
 - (void)createVideoFileOutput;
 
 
- at property (nonatomic, retain) CALayer *customPreviewLayer;
- at property (nonatomic, retain) AVCaptureVideoDataOutput *videoDataOutput;
+ at property (nonatomic, strong) CALayer *customPreviewLayer;
+ at property (nonatomic, strong) AVCaptureVideoDataOutput *videoDataOutput;
 
 @end
 
@@ -61,11 +61,12 @@ static CGFloat DegreesToRadians(CGFloat degrees) {return degrees * M_PI / 180;}
 
 
 @implementation CvVideoCamera
+{
+    id<CvVideoCameraDelegate> _delegate;
+}
 
 
 
-
- at synthesize delegate;
 @synthesize grayscaleMode;
 
 @synthesize customPreviewLayer;
@@ -78,7 +79,13 @@ static CGFloat DegreesToRadians(CGFloat degrees) {return degrees * M_PI / 180;}
 @synthesize recordPixelBufferAdaptor;
 @synthesize recordAssetWriter;
 
+- (void)setDelegate:(id<CvVideoCameraDelegate>)newDelegate {
+    _delegate = newDelegate;
+}
 
+- (id<CvVideoCameraDelegate>)delegate {
+    return _delegate;
+}
 
 #pragma mark - Constructors
 
@@ -100,6 +107,10 @@ static CGFloat DegreesToRadians(CGFloat degrees) {return degrees * M_PI / 180;}
 
 - (void)start;
 {
+    if (self.running == YES) {
+        return;
+    }
+
     recordingCountDown = 10;
     [super start];
 
@@ -118,29 +129,34 @@ static CGFloat DegreesToRadians(CGFloat degrees) {return degrees * M_PI / 180;}
 
 - (void)stop;
 {
-    [super stop];
+    if (self.running == YES) {
+        [super stop];
 
-    self.videoDataOutput = nil;
-    if (videoDataOutputQueue) {
-        dispatch_release(videoDataOutputQueue);
-    }
+        [videoDataOutput release];
+        if (videoDataOutputQueue) {
+            dispatch_release(videoDataOutputQueue);
+        }
 
-    if (self.recordVideo == YES) {
+        if (self.recordVideo == YES) {
+            if (self.recordAssetWriter) {
+                if (self.recordAssetWriter.status == AVAssetWriterStatusWriting) {
+                    [self.recordAssetWriter finishWriting];
+                    NSLog(@"[Camera] recording stopped");
+                } else {
+                    NSLog(@"[Camera] Recording Error: asset writer status is not writing");
+                }
+                [recordAssetWriter release];
+            }
 
-        if (self.recordAssetWriter.status == AVAssetWriterStatusWriting) {
-            [self.recordAssetWriter finishWriting];
-            NSLog(@"[Camera] recording stopped");
-        } else {
-            NSLog(@"[Camera] Recording Error: asset writer status is not writing");
+            [recordAssetWriterInput release];
+            [recordPixelBufferAdaptor release];
         }
 
-        self.recordAssetWriter = nil;
-        self.recordAssetWriterInput = nil;
-        self.recordPixelBufferAdaptor = nil;
+        if (self.customPreviewLayer) {
+            [self.customPreviewLayer removeFromSuperlayer];
+            self.customPreviewLayer = nil;
+        }
     }
-
-    [self.customPreviewLayer removeFromSuperlayer];
-    self.customPreviewLayer = nil;
 }
 
 // TODO fix
@@ -176,7 +192,7 @@ static CGFloat DegreesToRadians(CGFloat degrees) {return degrees * M_PI / 180;}
                 break; // leave the layer in its last known orientation
         }
 
-        switch (defaultAVCaptureVideoOrientation) {
+        switch (self.defaultAVCaptureVideoOrientation) {
             case AVCaptureVideoOrientationLandscapeRight:
                 rotation_angle += 180;
                 break;
@@ -242,7 +258,7 @@ static CGFloat DegreesToRadians(CGFloat degrees) {return degrees * M_PI / 180;}
                 break; // leave the layer in its last known orientation
         }
 
-        switch (defaultAVCaptureVideoOrientation) {
+        switch (self.defaultAVCaptureVideoOrientation) {
             case AVCaptureVideoOrientationLandscapeRight:
                 rotation_angle += 180;
                 break;
@@ -443,7 +459,8 @@ static CGFloat DegreesToRadians(CGFloat degrees) {return degrees * M_PI / 180;}
 {
     (void)captureOutput;
     (void)connection;
-    if (self.delegate) {
+    auto strongDelegate = self.delegate;
+    if (strongDelegate) {
 
         // convert from Core Media to Core Video
         CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
@@ -485,8 +502,8 @@ static CGFloat DegreesToRadians(CGFloat degrees) {return degrees * M_PI / 180;}
 
         CGImage* dstImage;
 
-        if ([self.delegate respondsToSelector:@selector(processImage:)]) {
-            [self.delegate processImage:image];
+        if ([strongDelegate respondsToSelector:@selector(processImage:)]) {
+            [strongDelegate processImage:image];
         }
 
         // check if matrix data pointer or dimensions were changed by the delegate
diff --git a/modules/videoio/src/cap_libv4l.cpp b/modules/videoio/src/cap_libv4l.cpp
index 46fac95..3ff564b 100644
--- a/modules/videoio/src/cap_libv4l.cpp
+++ b/modules/videoio/src/cap_libv4l.cpp
@@ -16,7 +16,7 @@ For Release:  OpenCV-Linux Beta4  opencv-0.9.6
 Tested On:    LMLBT44 with 8 video inputs
 Problems?     Post your questions at answers.opencv.org,
               Report bugs at code.opencv.org,
-              Submit your fixes at https://github.com/Itseez/opencv/
+              Submit your fixes at https://github.com/opencv/opencv/
 Patched Comments:
 
 TW: The cv cam utils that came with the initial release of OpenCV for LINUX Beta4
@@ -350,6 +350,7 @@ typedef struct CvCaptureCAM_V4L
 }
 CvCaptureCAM_V4L;
 
+static CvCaptureCAM_V4L * icvCaptureFromCAM_V4L (const char* deviceName);
 static void icvCloseCAM_V4L( CvCaptureCAM_V4L* capture );
 
 static int icvGrabFrameCAM_V4L( CvCaptureCAM_V4L* capture );
@@ -416,7 +417,7 @@ static void icvInitCapture_V4L() {
 }; /* End icvInitCapture_V4L */
 
 
-static int try_init_v4l(CvCaptureCAM_V4L* capture, char *deviceName)
+static int try_init_v4l(CvCaptureCAM_V4L* capture, const char *deviceName)
 
 {
 
@@ -460,7 +461,7 @@ static int try_init_v4l(CvCaptureCAM_V4L* capture, char *deviceName)
 }
 
 
-static int try_init_v4l2(CvCaptureCAM_V4L* capture, char *deviceName)
+static int try_init_v4l2(CvCaptureCAM_V4L* capture, const char *deviceName)
 {
 
   // if detect = -1 then unable to open device
@@ -662,7 +663,7 @@ static inline int channels_for_mode(int mode)
     }
 }
 
-static int _capture_V4L2 (CvCaptureCAM_V4L *capture, char *deviceName)
+static int _capture_V4L2 (CvCaptureCAM_V4L *capture, const char *deviceName)
 {
    int detect_v4l2 = 0;
 
@@ -870,7 +871,7 @@ static int _capture_V4L2 (CvCaptureCAM_V4L *capture, char *deviceName)
 }; /* End _capture_V4L2 */
 
 
-static int _capture_V4L (CvCaptureCAM_V4L *capture, char *deviceName)
+static int _capture_V4L (CvCaptureCAM_V4L *capture, const char *deviceName)
 {
    int detect_v4l = 0;
 
@@ -1041,17 +1042,6 @@ static CvCaptureCAM_V4L * icvCaptureFromCAM_V4L (int index)
      fprintf( stderr, "VIDEOIO ERROR: V4L: index %d is not correct!\n",index);
      return NULL; /* Did someone ask for not correct video source number? */
    }
-   /* Allocate memory for this humongus CvCaptureCAM_V4L structure that contains ALL
-      the handles for V4L processing */
-   CvCaptureCAM_V4L * capture = (CvCaptureCAM_V4L*)cvAlloc(sizeof(CvCaptureCAM_V4L));
-   if (!capture) {
-      fprintf( stderr, "VIDEOIO ERROR: V4L: Could not allocate memory for capture process.\n");
-      return NULL;
-   }
-
-#ifdef USE_TEMP_BUFFER
-   capture->buffers[MAX_V4L_BUFFERS].start = NULL;
-#endif
 
    /* Select camera, or rather, V4L video source */
    if (index<0) { // Asking for the first device available
@@ -1065,9 +1055,26 @@ static CvCaptureCAM_V4L * icvCaptureFromCAM_V4L (int index)
    }
    /* Print the CameraNumber at the end of the string with a width of one character */
    sprintf(deviceName, "/dev/video%1d", index);
+   return icvCaptureFromCAM_V4L(deviceName);
+}
+
+static CvCaptureCAM_V4L * icvCaptureFromCAM_V4L (const char* deviceName)
+{
+   /* Allocate memory for this humongus CvCaptureCAM_V4L structure that contains ALL
+      the handles for V4L processing */
+   CvCaptureCAM_V4L * capture = (CvCaptureCAM_V4L*)cvAlloc(sizeof(CvCaptureCAM_V4L));
+   if (!capture) {
+      fprintf( stderr, "VIDEOIO ERROR: V4L: Could not allocate memory for capture process.\n");
+      return NULL;
+   }
+
+#ifdef USE_TEMP_BUFFER
+   capture->buffers[MAX_V4L_BUFFERS].start = NULL;
+#endif
 
    /* w/o memset some parts  arent initialized - AKA: Fill it with zeros so it is clean */
    memset(capture,0,sizeof(CvCaptureCAM_V4L));
+
    /* Present the routines needed for V4L funtionality.  They are inserted as part of
       the standard set of cv calls promoting transparency.  "Vector Table" insertion. */
    capture->FirstCapture = 1;
@@ -1113,7 +1120,7 @@ static int read_frame_v4l2(CvCaptureCAM_V4L* capture) {
         default:
             /* display the error and stop processing */
             perror ("VIDIOC_DQBUF");
-            return 1;
+            return -1;
         }
    }
 
@@ -1141,7 +1148,7 @@ static int read_frame_v4l2(CvCaptureCAM_V4L* capture) {
    return 1;
 }
 
-static void mainloop_v4l2(CvCaptureCAM_V4L* capture) {
+static int mainloop_v4l2(CvCaptureCAM_V4L* capture) {
     unsigned int count;
 
     count = 1;
@@ -1175,10 +1182,14 @@ static void mainloop_v4l2(CvCaptureCAM_V4L* capture) {
                 break;
             }
 
-            if (read_frame_v4l2 (capture))
-                break;
+            int returnCode=read_frame_v4l2(capture);
+            if (returnCode == -1)
+                return -1;
+            if (returnCode == 1)
+                return 0;
         }
     }
+    return 0;
 }
 
 static int icvGrabFrameCAM_V4L(CvCaptureCAM_V4L* capture) {
@@ -1246,7 +1257,7 @@ static int icvGrabFrameCAM_V4L(CvCaptureCAM_V4L* capture) {
    if (capture->is_v4l2_device == 1)
    {
 
-     mainloop_v4l2(capture);
+     if(mainloop_v4l2(capture) == -1) return 0;
 
    } else
    {
@@ -1352,6 +1363,29 @@ static IplImage* icvRetrieveFrameCAM_V4L( CvCaptureCAM_V4L* capture, int) {
    return(&capture->frame);
 }
 
+static int zeroPropertyQuietly(CvCaptureCAM_V4L* capture, int property_id, int value)
+{
+  struct v4l2_control c;
+  int v4l2_min;
+  int v4l2_max;
+  //we need to make sure that the autocontrol is switch off, if available.
+  capture->control.id = property_id;
+  v4l2_min = v4l2_get_ctrl_min(capture, capture->control.id);
+  v4l2_max = v4l2_get_ctrl_max(capture, capture->control.id);
+  if ( !((v4l2_min == -1) && (v4l2_max == -1)) ) {
+    //autocontrol capability is supported, switch it off.
+    c.id    = capture->control.id;
+    c.value = value;
+    if( v4l2_ioctl(capture->deviceHandle, VIDIOC_S_CTRL, &c) != 0 ){
+      if (errno != ERANGE) {
+        fprintf(stderr, "VIDEOIO ERROR: V4L2: Failed to set autocontrol \"%d\": %s (value %d)\n", c.id, strerror(errno), c.value);
+        return -1;
+      }
+    }
+  }//lack of support should not be considerred an error.
+  return 0;
+}
+
 /* TODO: review this adaptation */
 static double icvGetPropertyCAM_V4L (CvCaptureCAM_V4L* capture,
                                      int property_id ) {
@@ -1431,32 +1465,15 @@ static double icvGetPropertyCAM_V4L (CvCaptureCAM_V4L* capture,
       break;
     case CV_CAP_PROP_EXPOSURE:
       sprintf(name, "Exposure");
-      capture->control.id = V4L2_CID_EXPOSURE;
+      capture->control.id = V4L2_CID_EXPOSURE_ABSOLUTE;
       break;
-    case CV_CAP_PROP_FOCUS: {
-      struct v4l2_control c;
-      int v4l2_min;
-      int v4l2_max;
-      //we need to make sure that the autofocus is switch off, if available.
-      capture->control.id = V4L2_CID_FOCUS_AUTO;
-      v4l2_min = v4l2_get_ctrl_min(capture, capture->control.id);
-      v4l2_max = v4l2_get_ctrl_max(capture, capture->control.id);
-      if ( !((v4l2_min == -1) && (v4l2_max == -1)) ) {
-        //autofocus capability is supported, switch it off.
-        c.id    = capture->control.id;
-        c.value = 0;//off
-        if( v4l2_ioctl(capture->deviceHandle, VIDIOC_S_CTRL, &c) != 0 ){
-          if (errno != ERANGE) {
-            fprintf(stderr, "VIDEOIO ERROR: V4L2: Failed to set control \"%d\"(FOCUS_AUTO): %s (value %d)\n", c.id, strerror(errno), c.value);
-            return -1;
-          }
-        }
-      }//lack of support should not be considerred an error.
-
+    case CV_CAP_PROP_FOCUS:
       sprintf(name, "Focus");
       capture->control.id = V4L2_CID_FOCUS_ABSOLUTE;
       break;
-    }
+    case CV_CAP_PROP_AUTOFOCUS:
+      sprintf(name, "Autofocus");
+      capture->control.id = V4L2_CID_FOCUS_AUTO;
     default:
       sprintf(name, "<unknown property string>");
       capture->control.id = property_id;
@@ -1671,30 +1688,22 @@ static int icvSetControl (CvCaptureCAM_V4L* capture, int property_id, double val
       capture->control.id = V4L2_CID_GAIN;
       break;
     case CV_CAP_PROP_EXPOSURE:
+      //we need to make sure that the autoexposure is switch off, if available.
+      zeroPropertyQuietly(capture, V4L2_CID_EXPOSURE_AUTO, V4L2_EXPOSURE_MANUAL);
+      //now get the manual exposure value
       sprintf(name, "Exposure");
-      capture->control.id = V4L2_CID_EXPOSURE;
+      capture->control.id = V4L2_CID_EXPOSURE_ABSOLUTE;
       break;
     case CV_CAP_PROP_FOCUS:
       //we need to make sure that the autofocus is switch off, if available.
-      capture->control.id = V4L2_CID_FOCUS_AUTO;
-      v4l2_min = v4l2_get_ctrl_min(capture, capture->control.id);
-      v4l2_max = v4l2_get_ctrl_max(capture, capture->control.id);
-      if ( !((v4l2_min == -1) && (v4l2_max == -1)) ) {
-        //autofocus capability is supported, switch it off.
-        c.id    = capture->control.id;
-        c.value = 0;//off
-        if( v4l2_ioctl(capture->deviceHandle, VIDIOC_S_CTRL, &c) != 0 ){
-          if (errno != ERANGE) {
-            fprintf(stderr, "VIDEOIO ERROR: V4L2: Failed to set control \"%d\"(FOCUS_AUTO): %s (value %d)\n", c.id, strerror(errno), c.value);
-            return -1;
-          }
-        }
-      }//lack of support should not be considerred an error.
-
+      zeroPropertyQuietly(capture, V4L2_CID_FOCUS_AUTO, 0 /*off*/);
       //now set the manual focus
       sprintf(name, "Focus");
       capture->control.id = V4L2_CID_FOCUS_ABSOLUTE;
       break;
+    case CV_CAP_PROP_AUTOFOCUS:
+      sprintf(name, "Autofocus");
+      capture->control.id = V4L2_CID_FOCUS_AUTO;
     default:
       sprintf(name, "<unknown property string>");
       capture->control.id = property_id;
@@ -1905,6 +1914,7 @@ public:
     virtual ~CvCaptureCAM_V4L_CPP() { close(); }
 
     virtual bool open( int index );
+    virtual bool open( const char* deviceName );
     virtual void close();
 
     virtual double getProperty(int) const;
@@ -1923,6 +1933,13 @@ bool CvCaptureCAM_V4L_CPP::open( int index )
     return captureV4L != 0;
 }
 
+bool CvCaptureCAM_V4L_CPP::open( const char* deviceName )
+{
+    close();
+    captureV4L = icvCaptureFromCAM_V4L(deviceName);
+    return captureV4L != 0;
+}
+
 void CvCaptureCAM_V4L_CPP::close()
 {
     if( captureV4L )
@@ -1963,4 +1980,15 @@ CvCapture* cvCreateCameraCapture_V4L( int index )
     return 0;
 }
 
+CvCapture* cvCreateCameraCapture_V4L( const char * deviceName )
+{
+    CvCaptureCAM_V4L_CPP* capture = new CvCaptureCAM_V4L_CPP;
+
+    if( capture->open( deviceName ))
+        return (CvCapture*)capture;
+
+    delete capture;
+    return 0;
+}
+
 #endif
diff --git a/modules/videoio/src/cap_mjpeg_decoder.cpp b/modules/videoio/src/cap_mjpeg_decoder.cpp
index 77e5d21..7abce20 100644
--- a/modules/videoio/src/cap_mjpeg_decoder.cpp
+++ b/modules/videoio/src/cap_mjpeg_decoder.cpp
@@ -790,7 +790,7 @@ std::vector<char> MotionJpegCapture::readFrame(frame_iterator it)
     result.reserve(chunk.m_size);
     result.resize(chunk.m_size);
 
-    m_file_stream.read(result.data(), chunk.m_size);
+    m_file_stream.read(&(result[0]), chunk.m_size); // result.data() failed with MSVS2008
 
     return result;
 }
diff --git a/modules/videoio/src/cap_msmf.cpp b/modules/videoio/src/cap_msmf.cpp
index 0694a75..a63e4fa 100644
--- a/modules/videoio/src/cap_msmf.cpp
+++ b/modules/videoio/src/cap_msmf.cpp
@@ -103,7 +103,7 @@
 #ifdef HAVE_CONCURRENCY
 #include <concrt.h>
 #ifndef __cplusplus_winrt
-#include "wrl.h
+#include "wrl.h"
 #endif
 #include "ppltasks_winrt.hpp"
 #endif
@@ -1986,13 +1986,17 @@ long videoDevice::resetDevice(IMFActivate *pActivate)
                 &vd_pFriendlyName,
                 NULL
                 );
-        hr = pActivate->ActivateObject(
-            __uuidof(IMFMediaSource),
-            (void**)&pSource
-            );
-        enumerateCaptureFormats(pSource);
-        buildLibraryofTypes();
-        SafeRelease(&pSource);
+        if (SUCCEEDED(hr))
+          hr = pActivate->ActivateObject(
+              __uuidof(IMFMediaSource),
+              (void**)&pSource
+              );
+        if (SUCCEEDED(hr) && pSource)
+        {
+          enumerateCaptureFormats(pSource);
+          buildLibraryofTypes();
+          SafeRelease(&pSource);
+        }//end if (SUCCEEDED(hr) && pSource)
         if(FAILED(hr))
         {
             vd_pFriendlyName = NULL;
@@ -2580,7 +2584,7 @@ bool videoDevice::setupDevice(unsigned int id)
 
 bool videoDevice::setupDevice(unsigned int w, unsigned int h, unsigned int idealFramerate)
 {
-    unsigned int id = findType(w * h, idealFramerate);
+    int id = findType(w * h, idealFramerate);
     if( id < 0 )
         return false;
 
@@ -2638,7 +2642,12 @@ HRESULT videoDevice::enumerateCaptureFormats(IMFMediaSource *pSource)
     _ComPtr<IMFStreamDescriptor> pSD = NULL;
     _ComPtr<IMFMediaTypeHandler> pHandler = NULL;
     _ComPtr<IMFMediaType> pType = NULL;
-    HRESULT hr = pSource->CreatePresentationDescriptor(pPD.GetAddressOf());
+    HRESULT hr = !pSource ? E_POINTER : S_OK;
+    if (FAILED(hr))
+    {
+        goto done;
+    }
+    hr = pSource->CreatePresentationDescriptor(pPD.GetAddressOf());
     if (FAILED(hr))
     {
         goto done;
@@ -3815,7 +3824,12 @@ HRESULT CvCaptureFile_MSMF::enumerateCaptureFormats(IMFMediaSource *pSource)
     _ComPtr<IMFStreamDescriptor> pSD = NULL;
     _ComPtr<IMFMediaTypeHandler> pHandler = NULL;
     _ComPtr<IMFMediaType> pType = NULL;
-    HRESULT hr = pSource->CreatePresentationDescriptor(pPD.GetAddressOf());
+    HRESULT hr = !pSource ? E_POINTER : S_OK;
+    if (FAILED(hr))
+    {
+        goto done;
+    }
+    hr = pSource->CreatePresentationDescriptor(pPD.GetAddressOf());
     if (FAILED(hr))
     {
         goto done;
diff --git a/modules/videoio/src/cap_openni.cpp b/modules/videoio/src/cap_openni.cpp
index 6c91df9..50cab02 100644
--- a/modules/videoio/src/cap_openni.cpp
+++ b/modules/videoio/src/cap_openni.cpp
@@ -44,10 +44,6 @@
 
 #ifdef HAVE_OPENNI
 
-#if defined TBB_INTERFACE_VERSION && TBB_INTERFACE_VERSION < 5000
-# undef HAVE_TBB
-#endif
-
 #include <queue>
 
 #ifndef i386
diff --git a/modules/videoio/src/cap_openni2.cpp b/modules/videoio/src/cap_openni2.cpp
index a39b897..c9a8dba 100644
--- a/modules/videoio/src/cap_openni2.cpp
+++ b/modules/videoio/src/cap_openni2.cpp
@@ -44,10 +44,6 @@
 
 #ifdef HAVE_OPENNI2
 
-#if defined TBB_INTERFACE_VERSION && TBB_INTERFACE_VERSION < 5000
-# undef HAVE_TBB
-#endif
-
 #include <queue>
 
 #ifndef i386
@@ -65,8 +61,10 @@
 
 #define CV_STREAM_TIMEOUT 2000
 
-#define CV_DEPTH_STREAM 0
-#define CV_COLOR_STREAM 1
+#define CV_DEPTH_STREAM     0
+#define CV_COLOR_STREAM     1
+#define CV_IR_STREAM        2
+#define CV_MAX_NUM_STREAMS  3
 
 #include "OpenNI.h"
 #include "PS1080.h"
@@ -109,10 +107,9 @@ protected:
         IplImage iplHeader;
     };
 
-    static const int outputMapsTypesCount = 7;
+    static const int outputMapsTypesCount = 8;
 
-    static openni::VideoMode defaultColorOutputMode();
-    static openni::VideoMode defaultDepthOutputMode();
+    static openni::VideoMode defaultStreamOutputMode(int stream);
 
     IplImage* retrieveDepthMap();
     IplImage* retrievePointCloudMap();
@@ -121,13 +118,17 @@ protected:
     IplImage* retrieveValidDepthMask();
     IplImage* retrieveBGRImage();
     IplImage* retrieveGrayImage();
+    IplImage* retrieveIrImage();
 
+    openni::Status toggleStream(int stream, bool toggle);
     bool readCamerasParams();
 
     double getDepthGeneratorProperty(int propIdx) const;
     bool setDepthGeneratorProperty(int propIdx, double propVal);
     double getImageGeneratorProperty(int propIdx) const;
     bool setImageGeneratorProperty(int propIdx, double propVal);
+    double getIrGeneratorProperty(int propIdx) const;
+    bool setIrGeneratorProperty(int propIdx, double propVal);
     double getCommonProperty(int propIdx) const;
     bool setCommonProperty(int propIdx, double propVal);
 
@@ -137,9 +138,9 @@ protected:
     openni::Recorder recorder;
 
     // Data generators with its metadata
-    openni::VideoStream depth, color, **streams;
-    openni::VideoFrameRef depthFrame, colorFrame;
-    cv::Mat depthImage, colorImage;
+    openni::VideoStream streams[CV_MAX_NUM_STREAMS];
+    openni::VideoFrameRef streamFrames[CV_MAX_NUM_STREAMS];
+    cv::Mat streamImages[CV_MAX_NUM_STREAMS];
 
     int maxBufferSize, maxTimeDuration; // for approx sync
     bool isCircleBuffer;
@@ -157,9 +158,6 @@ protected:
     // The value for pixels without a valid disparity measurement
     int noSampleValue;
 
-    int currentStream;
-
-    int numStream;
     std::vector<OutputMap> outputMaps;
 };
 
@@ -177,27 +175,28 @@ bool CvCapture_OpenNI2::isOpened() const
     return isContextOpened;
 }
 
-openni::VideoMode CvCapture_OpenNI2::defaultColorOutputMode()
-{
-    openni::VideoMode mode;
-    mode.setResolution(640, 480);
-    mode.setFps(30);
-    mode.setPixelFormat(openni::PIXEL_FORMAT_RGB888);
-    return mode;
-}
-
-openni::VideoMode CvCapture_OpenNI2::defaultDepthOutputMode()
+openni::VideoMode CvCapture_OpenNI2::defaultStreamOutputMode(int stream)
 {
     openni::VideoMode mode;
     mode.setResolution(640, 480);
     mode.setFps(30);
-    mode.setPixelFormat(openni::PIXEL_FORMAT_DEPTH_1_MM);
+    switch (stream)
+    {
+    case CV_DEPTH_STREAM:
+        mode.setPixelFormat(openni::PIXEL_FORMAT_DEPTH_1_MM);
+        break;
+    case CV_COLOR_STREAM:
+        mode.setPixelFormat(openni::PIXEL_FORMAT_RGB888);
+        break;
+    case CV_IR_STREAM:
+        mode.setPixelFormat(openni::PIXEL_FORMAT_GRAY16);
+        break;
+    }
     return mode;
 }
 
 CvCapture_OpenNI2::CvCapture_OpenNI2( int index )
 {
-    numStream = 2;
     const char* deviceURI = openni::ANY_DEVICE;
     openni::Status status;
     int deviceType = DEVICE_DEFAULT;
@@ -215,13 +214,6 @@ CvCapture_OpenNI2::CvCapture_OpenNI2( int index )
         index %= 10;
     }
 
-    // Asus XTION and Occipital Structure Sensor do not have an image generator
-    if (deviceType == DEVICE_ASUS_XTION)
-        numStream = 1;
-
-    if( deviceType > DEVICE_MAX )
-        return;
-
     // Initialize and configure the context.
     status = openni::OpenNI::initialize();
 
@@ -231,6 +223,14 @@ CvCapture_OpenNI2::CvCapture_OpenNI2( int index )
         return;
     }
 
+    // find appropriate device URI
+    openni::Array<openni::DeviceInfo> ldevs;
+    if (index > 0)
+    {
+        openni::OpenNI::enumerateDevices(&ldevs);
+        deviceURI = ldevs[index].getUri();
+    }
+
     status = device.open(deviceURI);
     if( status != openni::STATUS_OK )
     {
@@ -239,83 +239,98 @@ CvCapture_OpenNI2::CvCapture_OpenNI2( int index )
         return;
     }
 
-    //device.setDepthColorSyncEnabled(true);
-
-
-    status = depth.create(device, openni::SENSOR_DEPTH);
-    if (status == openni::STATUS_OK)
+    status = toggleStream(CV_DEPTH_STREAM, true);
+    // Asus XTION and Occipital Structure Sensor do not have an image generator
+    if (deviceType != DEVICE_ASUS_XTION)
+        status = openni::Status(status | toggleStream(CV_COLOR_STREAM, true));
+    if (status != openni::STATUS_OK)
     {
-        if (depth.isValid())
-        {
-            CV_Assert(depth.setVideoMode(defaultDepthOutputMode()) == openni::STATUS_OK); // xn::DepthGenerator supports VGA only! (Jan 2011)
-        }
-
-        status = depth.start();
-        if (status != openni::STATUS_OK)
-        {
-            CV_Error(CV_StsError, cv::format("CvCapture_OpenNI2::CvCapture_OpenNI2 : Couldn't start depth stream: %s\n", openni::OpenNI::getExtendedError()));
-            depth.destroy();
-            return;
-        }
+        openni::OpenNI::shutdown();
+        return;
     }
-    else
+
+    if (!readCamerasParams())
     {
-        CV_Error(CV_StsError, cv::format("CvCapture_OpenNI2::CvCapture_OpenNI2 : Couldn't find depth stream:: %s\n", openni::OpenNI::getExtendedError()));
+        CV_Error(CV_StsError, cv::format("CvCapture_OpenNI2::CvCapture_OpenNI2 : Could not read cameras parameters\n"));
         return;
     }
 
-    streams = new openni::VideoStream*[numStream];
-    streams[CV_DEPTH_STREAM] = &depth;
 
-    // create a color object
-    status = color.create(device, openni::SENSOR_COLOR);
-    if (status == openni::STATUS_OK)
+    outputMaps.resize( outputMapsTypesCount );
+
+    isContextOpened = true;
+
+    setProperty(CV_CAP_PROP_OPENNI_REGISTRATION, 1.0);
+}
+
+openni::Status CvCapture_OpenNI2::toggleStream(int stream, bool toggle)
+{
+    openni::Status status;
+
+    // for logging
+    static const char* stream_names[CV_MAX_NUM_STREAMS] = {
+        "depth",
+        "color",
+        "IR"
+    };
+
+    static const openni::SensorType stream_sensor_types[CV_MAX_NUM_STREAMS] = {
+        openni::SENSOR_DEPTH,
+        openni::SENSOR_COLOR,
+        openni::SENSOR_IR
+    };
+
+    if (toggle) // want to open stream
     {
-        // Set map output mode.
-        if (color.isValid())
+        // already opened
+        if (streams[stream].isValid())
+            return openni::STATUS_OK;
+
+        // open stream
+        status = streams[stream].create(device, stream_sensor_types[stream]);
+        if (status == openni::STATUS_OK)
         {
-            CV_Assert(color.setVideoMode(defaultColorOutputMode()) == openni::STATUS_OK);
+            // set video mode
+            status = streams[stream].setVideoMode(defaultStreamOutputMode(stream)); // xn::DepthGenerator supports VGA only! (Jan 2011)
+            if (status != openni::STATUS_OK)
+            {
+                CV_Error(CV_StsError, cv::format("CvCapture_OpenNI2::CvCapture_OpenNI2 : Couldn't set %s stream output mode: %s\n",
+                                                 stream_names[stream],
+                                                 openni::OpenNI::getExtendedError()));
+                streams[stream].destroy();
+                return status;
+            }
+
+            // start stream
+            status = streams[stream].start();
+            if (status != openni::STATUS_OK)
+            {
+                CV_Error(CV_StsError, cv::format("CvCapture_OpenNI2::CvCapture_OpenNI2 : Couldn't start %s stream: %s\n",
+                                                 stream_names[stream],
+                                                 openni::OpenNI::getExtendedError()));
+                streams[stream].destroy();
+                return status;
+            }
         }
-        status = color.start();
-        if (status != openni::STATUS_OK)
+        else
         {
-            CV_Error(CV_StsError, cv::format("CvCapture_OpenNI2::CvCapture_OpenNI2 : Couldn't start color stream: %s\n", openni::OpenNI::getExtendedError()));
-            color.destroy();
-            return;
+            CV_Error(CV_StsError, cv::format("CvCapture_OpenNI2::CvCapture_OpenNI2 : Couldn't find %s stream:: %s\n",
+                                             stream_names[stream],
+                                             openni::OpenNI::getExtendedError()));
+            return status;
         }
-        streams[CV_COLOR_STREAM] = &color;
-    }
-    else if (numStream == 2)
-    {
-        CV_Error(CV_StsError, cv::format("CvCapture_OpenNI2::CvCapture_OpenNI2 : Couldn't find color stream: %s\n", openni::OpenNI::getExtendedError()));
-        return;
     }
-
-    if( !readCamerasParams() )
+    else if (streams[stream].isValid()) // want to close stream
     {
-        CV_Error(CV_StsError, cv::format("CvCapture_OpenNI2::CvCapture_OpenNI2 : Could not read cameras parameters\n"));
-        return;
+        streams[stream].stop();
+        streams[stream].destroy();
     }
 
-//    if( deviceType == DEVICE_ASUS_XTION )
-//    {
-//        //ps/asus specific
-//        imageGenerator.SetIntProperty("InputFormat", 1 /*XN_IO_IMAGE_FORMAT_YUV422*/);
-//        imageGenerator.SetPixelFormat(XN_PIXEL_FORMAT_RGB24);
-//        depthGenerator.SetIntProperty("RegistrationType", 1 /*XN_PROCESSING_HARDWARE*/);
-//    }
-
-
-    outputMaps.resize( outputMapsTypesCount );
-
-    isContextOpened = true;
-
-    setProperty(CV_CAP_PROP_OPENNI_REGISTRATION, 1.0);
+    return openni::STATUS_OK;
 }
 
 CvCapture_OpenNI2::CvCapture_OpenNI2(const char * filename)
 {
-    numStream = 2;
     openni::Status status;
 
     isContextOpened = false;
@@ -340,6 +355,13 @@ CvCapture_OpenNI2::CvCapture_OpenNI2(const char * filename)
         return;
     }
 
+    status = openni::Status(toggleStream(CV_DEPTH_STREAM, true) | toggleStream(CV_COLOR_STREAM, true));
+    if (status != openni::STATUS_OK)
+    {
+        openni::OpenNI::shutdown();
+        return;
+    }
+
     if( !readCamerasParams() )
     {
         CV_Error(CV_StsError, cv::format("CvCapture_OpenNI2::CvCapture_OpenNI2 : Could not read cameras parameters\n"));
@@ -353,17 +375,20 @@ CvCapture_OpenNI2::CvCapture_OpenNI2(const char * filename)
 
 CvCapture_OpenNI2::~CvCapture_OpenNI2()
 {
-    this->depthFrame.release();
-    this->colorFrame.release();
-    this->depth.stop();
-    this->color.stop();
+    for (int i = 0; i < CV_MAX_NUM_STREAMS; ++i)
+    {
+        streamFrames[i].release();
+        streams[i].stop();
+        streams[i].destroy();
+    }
+    device.close();
     openni::OpenNI::shutdown();
 }
 
 bool CvCapture_OpenNI2::readCamerasParams()
 {
     double pixelSize = 0;
-    if (depth.getProperty<double>(XN_STREAM_PROPERTY_ZERO_PLANE_PIXEL_SIZE, &pixelSize) != openni::STATUS_OK)
+    if (streams[CV_DEPTH_STREAM].getProperty<double>(XN_STREAM_PROPERTY_ZERO_PLANE_PIXEL_SIZE, &pixelSize) != openni::STATUS_OK)
     {
         CV_Error(CV_StsError, cv::format("CvCapture_OpenNI2::readCamerasParams : Could not read pixel size!\n"));
         return false;
@@ -374,13 +399,13 @@ bool CvCapture_OpenNI2::readCamerasParams()
 
     // focal length of IR camera in pixels for VGA resolution
     int zeroPlanDistance; // in mm
-    if (depth.getProperty(XN_STREAM_PROPERTY_ZERO_PLANE_DISTANCE, &zeroPlanDistance) != openni::STATUS_OK)
+    if (streams[CV_DEPTH_STREAM].getProperty(XN_STREAM_PROPERTY_ZERO_PLANE_DISTANCE, &zeroPlanDistance) != openni::STATUS_OK)
     {
         CV_Error(CV_StsError, cv::format("CvCapture_OpenNI2::readCamerasParams : Could not read virtual plane distance!\n"));
         return false;
     }
 
-    if (depth.getProperty<double>(XN_STREAM_PROPERTY_EMITTER_DCMOS_DISTANCE, &baseline) != openni::STATUS_OK)
+    if (streams[CV_DEPTH_STREAM].getProperty<double>(XN_STREAM_PROPERTY_EMITTER_DCMOS_DISTANCE, &baseline) != openni::STATUS_OK)
     {
         CV_Error(CV_StsError, cv::format("CvCapture_OpenNI2::readCamerasParams : Could not read base line!\n"));
         return false;
@@ -411,6 +436,10 @@ double CvCapture_OpenNI2::getProperty( int propIdx ) const
         {
             propValue = getDepthGeneratorProperty( purePropIdx );
         }
+        else if ((propIdx & CV_CAP_OPENNI_GENERATORS_MASK) == CV_CAP_OPENNI_IR_GENERATOR)
+        {
+            propValue = getIrGeneratorProperty(purePropIdx);
+        }
         else
         {
             propValue = getCommonProperty( purePropIdx );
@@ -435,6 +464,10 @@ bool CvCapture_OpenNI2::setProperty( int propIdx, double propValue )
         {
             isSet = setDepthGeneratorProperty( purePropIdx, propValue );
         }
+        else if ((propIdx & CV_CAP_OPENNI_GENERATORS_MASK) == CV_CAP_OPENNI_IR_GENERATOR)
+        {
+            isSet = setIrGeneratorProperty(purePropIdx, propValue);
+        }
         else
         {
             isSet = setCommonProperty( purePropIdx, propValue );
@@ -450,12 +483,6 @@ double CvCapture_OpenNI2::getCommonProperty( int propIdx ) const
 
     switch( propIdx )
     {
-    // There is a set of properties that correspond to depth generator by default
-    // (is they are pass without particular generator flag). Two reasons of this:
-    // 1) We can assume that depth generator is the main one for depth sensor.
-    // 2) In the initial vertions of OpenNI integration to OpenCV the value of
-    //    flag CV_CAP_OPENNI_DEPTH_GENERATOR was 0 (it isn't zero now).
-    case CV_CAP_PROP_OPENNI_GENERATOR_PRESENT :
     case CV_CAP_PROP_FRAME_WIDTH :
     case CV_CAP_PROP_FRAME_HEIGHT :
     case CV_CAP_PROP_FPS :
@@ -469,7 +496,9 @@ double CvCapture_OpenNI2::getCommonProperty( int propIdx ) const
         propValue = const_cast<CvCapture_OpenNI2 *>(this)->device.getDepthColorSyncEnabled();
     case CV_CAP_PROP_OPENNI2_MIRROR:
     {
-        bool isMirroring = color.getMirroringEnabled() && depth.getMirroringEnabled();
+        bool isMirroring = false;
+        for (int i = 0; i < CV_MAX_NUM_STREAMS; ++i)
+            isMirroring |= streams[i].getMirroringEnabled();
         propValue = isMirroring ? 1.0 : 0.0;
         break;
     }
@@ -489,8 +518,11 @@ bool CvCapture_OpenNI2::setCommonProperty( int propIdx, double propValue )
     case CV_CAP_PROP_OPENNI2_MIRROR:
     {
         bool mirror = propValue > 0.0 ? true : false;
-        isSet = color.setMirroringEnabled(mirror) == openni::STATUS_OK;
-        isSet = depth.setMirroringEnabled(mirror) == openni::STATUS_OK;
+        for (int i = 0; i < CV_MAX_NUM_STREAMS; ++i)
+        {
+            if (streams[i].isValid())
+                isSet |= streams[i].setMirroringEnabled(mirror) == openni::STATUS_OK;
+        }
     }
         break;
     // There is a set of properties that correspond to depth generator by default
@@ -501,6 +533,7 @@ bool CvCapture_OpenNI2::setCommonProperty( int propIdx, double propValue )
     case CV_CAP_PROP_OPENNI2_SYNC:
         isSet = device.setDepthColorSyncEnabled(propValue > 0.0) == openni::STATUS_OK;
         break;
+
     default:
         CV_Error( CV_StsBadArg, cv::format("Such parameter (propIdx=%d) isn't supported for setting.\n", propIdx) );
     }
@@ -511,29 +544,28 @@ bool CvCapture_OpenNI2::setCommonProperty( int propIdx, double propValue )
 double CvCapture_OpenNI2::getDepthGeneratorProperty( int propIdx ) const
 {
     double propValue = 0;
-    if( !depth.isValid() )
+    if( !streams[CV_DEPTH_STREAM].isValid() )
         return propValue;
 
     openni::VideoMode mode;
 
     switch( propIdx )
     {
-    case CV_CAP_PROP_OPENNI_GENERATOR_PRESENT :
-        CV_DbgAssert(depth.isValid());
-        propValue = 1.;
+    case CV_CAP_PROP_OPENNI_GENERATOR_PRESENT:
+        propValue = streams[CV_DEPTH_STREAM].isValid();
         break;
     case CV_CAP_PROP_FRAME_WIDTH :
-        propValue = depth.getVideoMode().getResolutionX();
+        propValue = streams[CV_DEPTH_STREAM].getVideoMode().getResolutionX();
         break;
     case CV_CAP_PROP_FRAME_HEIGHT :
-            propValue = depth.getVideoMode().getResolutionY();
+            propValue = streams[CV_DEPTH_STREAM].getVideoMode().getResolutionY();
         break;
     case CV_CAP_PROP_FPS :
-        mode = depth.getVideoMode();
+        mode = streams[CV_DEPTH_STREAM].getVideoMode();
         propValue = mode.getFps();
         break;
     case CV_CAP_PROP_OPENNI_FRAME_MAX_DEPTH :
-        propValue = depth.getMaxPixelValue();
+        propValue = streams[CV_DEPTH_STREAM].getMaxPixelValue();
         break;
     case CV_CAP_PROP_OPENNI_BASELINE :
         propValue = baseline;
@@ -545,10 +577,10 @@ double CvCapture_OpenNI2::getDepthGeneratorProperty( int propIdx ) const
         propValue = device.getImageRegistrationMode();
         break;
     case CV_CAP_PROP_POS_MSEC :
-        propValue = (double)depthFrame.getTimestamp();
+        propValue = (double)streamFrames[CV_DEPTH_STREAM].getTimestamp();
         break;
     case CV_CAP_PROP_POS_FRAMES :
-        propValue = depthFrame.getFrameIndex();
+        propValue = streamFrames[CV_DEPTH_STREAM].getFrameIndex();
         break;
     default :
         CV_Error( CV_StsBadArg, cv::format("Depth generator does not support such parameter (propIdx=%d) for getting.\n", propIdx) );
@@ -561,17 +593,20 @@ bool CvCapture_OpenNI2::setDepthGeneratorProperty( int propIdx, double propValue
 {
     bool isSet = false;
 
-    CV_Assert( depth.isValid() );
-
     switch( propIdx )
     {
+    case CV_CAP_PROP_OPENNI_GENERATOR_PRESENT:
+        if (isContextOpened)
+            isSet = toggleStream(CV_DEPTH_STREAM, propValue > 0.0) == openni::STATUS_OK;
+        break;
     case CV_CAP_PROP_OPENNI_REGISTRATION:
         {
+            CV_Assert(streams[CV_DEPTH_STREAM].isValid());
             if( propValue != 0.0 ) // "on"
             {
                 // if there isn't image generator (i.e. ASUS XtionPro doesn't have it)
                 // then the property isn't avaliable
-                if ( color.isValid() )
+                if ( streams[CV_COLOR_STREAM].isValid() )
                 {
                     openni::ImageRegistrationMode mode = propValue != 0.0 ? openni::IMAGE_REGISTRATION_DEPTH_TO_COLOR : openni::IMAGE_REGISTRATION_OFF;
                     if( !device.getImageRegistrationMode() == mode )
@@ -611,30 +646,29 @@ bool CvCapture_OpenNI2::setDepthGeneratorProperty( int propIdx, double propValue
 double CvCapture_OpenNI2::getImageGeneratorProperty( int propIdx ) const
 {
     double propValue = 0.;
-    if( !color.isValid() )
+    if( !streams[CV_COLOR_STREAM].isValid() )
         return propValue;
 
     openni::VideoMode mode;
     switch( propIdx )
     {
-    case CV_CAP_PROP_OPENNI_GENERATOR_PRESENT :
-        CV_DbgAssert( color.isValid() );
-        propValue = 1.;
+    case CV_CAP_PROP_OPENNI_GENERATOR_PRESENT:
+        propValue = streams[CV_COLOR_STREAM].isValid();
         break;
     case CV_CAP_PROP_FRAME_WIDTH :
-            propValue = color.getVideoMode().getResolutionX();
+            propValue = streams[CV_COLOR_STREAM].getVideoMode().getResolutionX();
         break;
     case CV_CAP_PROP_FRAME_HEIGHT :
-            propValue = color.getVideoMode().getResolutionY();
+            propValue = streams[CV_COLOR_STREAM].getVideoMode().getResolutionY();
         break;
     case CV_CAP_PROP_FPS :
-            propValue = color.getVideoMode().getFps();
+            propValue = streams[CV_COLOR_STREAM].getVideoMode().getFps();
         break;
     case CV_CAP_PROP_POS_MSEC :
-        propValue = (double)colorFrame.getTimestamp();
+        propValue = (double)streamFrames[CV_COLOR_STREAM].getTimestamp();
         break;
     case CV_CAP_PROP_POS_FRAMES :
-        propValue = (double)colorFrame.getFrameIndex();
+        propValue = (double)streamFrames[CV_COLOR_STREAM].getFrameIndex();
         break;
     default :
         CV_Error( CV_StsBadArg, cv::format("Image generator does not support such parameter (propIdx=%d) for getting.\n", propIdx) );
@@ -646,14 +680,18 @@ double CvCapture_OpenNI2::getImageGeneratorProperty( int propIdx ) const
 bool CvCapture_OpenNI2::setImageGeneratorProperty(int propIdx, double propValue)
 {
     bool isSet = false;
-        if( !color.isValid() )
-            return isSet;
 
         switch( propIdx )
         {
+        case CV_CAP_PROP_OPENNI_GENERATOR_PRESENT:
+            if (isContextOpened)
+                isSet = toggleStream(CV_COLOR_STREAM, propValue > 0.0) == openni::STATUS_OK;
+            break;
         case CV_CAP_PROP_OPENNI_OUTPUT_MODE :
         {
-            openni::VideoMode mode = color.getVideoMode();
+            if (!streams[CV_COLOR_STREAM].isValid())
+                return isSet;
+            openni::VideoMode mode = streams[CV_COLOR_STREAM].getVideoMode();
 
             switch( cvRound(propValue) )
             {
@@ -681,7 +719,7 @@ bool CvCapture_OpenNI2::setImageGeneratorProperty(int propIdx, double propValue)
                 CV_Error( CV_StsBadArg, "Unsupported image generator output mode.\n");
             }
 
-            openni::Status status = color.setVideoMode( mode );
+            openni::Status status = streams[CV_COLOR_STREAM].setVideoMode( mode );
             if( status != openni::STATUS_OK )
                 CV_Error(CV_StsError, cv::format("CvCapture_OpenNI2::setImageGeneratorProperty : %s\n", openni::OpenNI::getExtendedError()));
             else
@@ -695,6 +733,96 @@ bool CvCapture_OpenNI2::setImageGeneratorProperty(int propIdx, double propValue)
     return isSet;
 }
 
+double CvCapture_OpenNI2::getIrGeneratorProperty(int propIdx) const
+{
+    double propValue = 0.;
+    if (!streams[CV_IR_STREAM].isValid())
+        return propValue;
+
+    openni::VideoMode mode;
+    switch (propIdx)
+    {
+    case CV_CAP_PROP_OPENNI_GENERATOR_PRESENT:
+        propValue = streams[CV_IR_STREAM].isValid();
+        break;
+    case CV_CAP_PROP_FRAME_WIDTH:
+        propValue = streams[CV_IR_STREAM].getVideoMode().getResolutionX();
+        break;
+    case CV_CAP_PROP_FRAME_HEIGHT:
+        propValue = streams[CV_IR_STREAM].getVideoMode().getResolutionY();
+        break;
+    case CV_CAP_PROP_FPS:
+        propValue = streams[CV_IR_STREAM].getVideoMode().getFps();
+        break;
+    case CV_CAP_PROP_POS_MSEC:
+        propValue = (double)streamFrames[CV_IR_STREAM].getTimestamp();
+        break;
+    case CV_CAP_PROP_POS_FRAMES:
+        propValue = (double)streamFrames[CV_IR_STREAM].getFrameIndex();
+        break;
+    default:
+        CV_Error(CV_StsBadArg, cv::format("Image generator does not support such parameter (propIdx=%d) for getting.\n", propIdx));
+    }
+
+    return propValue;
+}
+
+bool CvCapture_OpenNI2::setIrGeneratorProperty(int propIdx, double propValue)
+{
+    bool isSet = false;
+
+    switch (propIdx)
+    {
+    case CV_CAP_PROP_OPENNI_GENERATOR_PRESENT:
+        if (isContextOpened)
+            isSet = toggleStream(CV_IR_STREAM, propValue > 0.0) == openni::STATUS_OK;
+        break;
+    case CV_CAP_PROP_OPENNI_OUTPUT_MODE:
+    {
+        if (!streams[CV_IR_STREAM].isValid())
+            return isSet;
+        openni::VideoMode mode = streams[CV_IR_STREAM].getVideoMode();
+
+        switch (cvRound(propValue))
+        {
+        case CV_CAP_OPENNI_VGA_30HZ:
+            mode.setResolution(640, 480);
+            mode.setFps(30);
+            break;
+        case CV_CAP_OPENNI_SXGA_15HZ:
+            mode.setResolution(1280, 960);
+            mode.setFps(15);
+            break;
+        case CV_CAP_OPENNI_SXGA_30HZ:
+            mode.setResolution(1280, 960);
+            mode.setFps(30);
+            break;
+        case CV_CAP_OPENNI_QVGA_30HZ:
+            mode.setResolution(320, 240);
+            mode.setFps(30);
+            break;
+        case CV_CAP_OPENNI_QVGA_60HZ:
+            mode.setResolution(320, 240);
+            mode.setFps(60);
+            break;
+        default:
+            CV_Error(CV_StsBadArg, "Unsupported image generator output mode.\n");
+        }
+
+        openni::Status status = streams[CV_IR_STREAM].setVideoMode(mode);
+        if (status != openni::STATUS_OK)
+            CV_Error(CV_StsError, cv::format("CvCapture_OpenNI2::setImageGeneratorProperty : %s\n", openni::OpenNI::getExtendedError()));
+        else
+            isSet = true;
+        break;
+    }
+    default:
+        CV_Error(CV_StsBadArg, cv::format("Image generator does not support such parameter (propIdx=%d) for setting.\n", propIdx));
+    }
+
+    return isSet;
+}
+
 bool CvCapture_OpenNI2::grabFrame()
 {
     if( !isOpened() )
@@ -702,14 +830,22 @@ bool CvCapture_OpenNI2::grabFrame()
 
     bool isGrabbed = false;
 
-    openni::Status status = openni::OpenNI::waitForAnyStream(streams, numStream, &currentStream, CV_STREAM_TIMEOUT);
+    int numActiveStreams = 0;
+    openni::VideoStream* streamPtrs[CV_MAX_NUM_STREAMS];
+    for (int i = 0; i < CV_MAX_NUM_STREAMS; ++i) {
+        streamPtrs[numActiveStreams++] = &streams[i];
+    }
+
+    int currentStream;
+    openni::Status status = openni::OpenNI::waitForAnyStream(streamPtrs, numActiveStreams, &currentStream, CV_STREAM_TIMEOUT);
     if( status != openni::STATUS_OK )
         return false;
 
-    if( depth.isValid() )
-        depth.readFrame(&depthFrame);
-    if (color.isValid())
-        color.readFrame(&colorFrame);
+    for (int i = 0; i < CV_MAX_NUM_STREAMS; ++i)
+    {
+        if (streams[i].isValid())
+            streams[i].readFrame(&streamFrames[i]);
+    }
     isGrabbed = true;
 
     return isGrabbed;
@@ -728,25 +864,25 @@ inline void getDepthMapFromMetaData(const openni::VideoFrameRef& depthMetaData,
 
 IplImage* CvCapture_OpenNI2::retrieveDepthMap()
 {
-    if( !depth.isValid() )
+    if( !streamFrames[CV_DEPTH_STREAM].isValid() )
         return 0;
 
-    getDepthMapFromMetaData( depthFrame, outputMaps[CV_CAP_OPENNI_DEPTH_MAP].mat, noSampleValue, shadowValue );
+    getDepthMapFromMetaData(streamFrames[CV_DEPTH_STREAM], outputMaps[CV_CAP_OPENNI_DEPTH_MAP].mat, noSampleValue, shadowValue );
 
     return outputMaps[CV_CAP_OPENNI_DEPTH_MAP].getIplImagePtr();
 }
 
 IplImage* CvCapture_OpenNI2::retrievePointCloudMap()
 {
-    if( !depthFrame.isValid() )
+    if( !streamFrames[CV_DEPTH_STREAM].isValid() )
         return 0;
 
     cv::Mat depthImg;
-    getDepthMapFromMetaData(depthFrame, depthImg, noSampleValue, shadowValue);
+    getDepthMapFromMetaData(streamFrames[CV_DEPTH_STREAM], depthImg, noSampleValue, shadowValue);
 
     const int badPoint = INVALID_PIXEL_VAL;
     const float badCoord = INVALID_COORDINATE_VAL;
-    int cols = depthFrame.getWidth(), rows = depthFrame.getHeight();
+    int cols = streamFrames[CV_DEPTH_STREAM].getWidth(), rows = streamFrames[CV_DEPTH_STREAM].getHeight();
     cv::Mat pointCloud_XYZ( rows, cols, CV_32FC3, cv::Scalar::all(badPoint) );
 
     float worldX, worldY, worldZ;
@@ -754,7 +890,7 @@ IplImage* CvCapture_OpenNI2::retrievePointCloudMap()
     {
         for (int x = 0; x < cols; x++)
         {
-            openni::CoordinateConverter::convertDepthToWorld(depth, x, y, depthImg.at<unsigned short>(y, x), &worldX, &worldY, &worldZ);
+            openni::CoordinateConverter::convertDepthToWorld(streams[CV_DEPTH_STREAM], x, y, depthImg.at<unsigned short>(y, x), &worldX, &worldY, &worldZ);
 
             if (depthImg.at<unsigned short>(y, x) == badPoint) // not valid
                 pointCloud_XYZ.at<cv::Point3f>(y, x) = cv::Point3f(badCoord, badCoord, badCoord);
@@ -795,11 +931,11 @@ static void computeDisparity_32F( const openni::VideoFrameRef& depthMetaData, cv
 
 IplImage* CvCapture_OpenNI2::retrieveDisparityMap()
 {
-    if (!depthFrame.isValid())
+    if (!streamFrames[CV_DEPTH_STREAM].isValid())
         return 0;
 
     cv::Mat disp32;
-    computeDisparity_32F(depthFrame, disp32, baseline, depthFocalLength_VGA, noSampleValue, shadowValue);
+    computeDisparity_32F(streamFrames[CV_DEPTH_STREAM], disp32, baseline, depthFocalLength_VGA, noSampleValue, shadowValue);
 
     disp32.convertTo( outputMaps[CV_CAP_OPENNI_DISPARITY_MAP].mat, CV_8UC1 );
 
@@ -808,21 +944,21 @@ IplImage* CvCapture_OpenNI2::retrieveDisparityMap()
 
 IplImage* CvCapture_OpenNI2::retrieveDisparityMap_32F()
 {
-    if (!depthFrame.isValid())
+    if (!streamFrames[CV_DEPTH_STREAM].isValid())
         return 0;
 
-    computeDisparity_32F(depthFrame, outputMaps[CV_CAP_OPENNI_DISPARITY_MAP_32F].mat, baseline, depthFocalLength_VGA, noSampleValue, shadowValue);
+    computeDisparity_32F(streamFrames[CV_DEPTH_STREAM], outputMaps[CV_CAP_OPENNI_DISPARITY_MAP_32F].mat, baseline, depthFocalLength_VGA, noSampleValue, shadowValue);
 
     return outputMaps[CV_CAP_OPENNI_DISPARITY_MAP_32F].getIplImagePtr();
 }
 
 IplImage* CvCapture_OpenNI2::retrieveValidDepthMask()
 {
-    if (!depthFrame.isValid())
+    if (!streamFrames[CV_DEPTH_STREAM].isValid())
         return 0;
 
     cv::Mat d;
-    getDepthMapFromMetaData(depthFrame, d, noSampleValue, shadowValue);
+    getDepthMapFromMetaData(streamFrames[CV_DEPTH_STREAM], d, noSampleValue, shadowValue);
 
     outputMaps[CV_CAP_OPENNI_VALID_DEPTH_MASK].mat = d != CvCapture_OpenNI2::INVALID_PIXEL_VAL;
 
@@ -842,30 +978,58 @@ inline void getBGRImageFromMetaData( const openni::VideoFrameRef& imageMetaData,
    cv::cvtColor(bufferImage, bgrImage, cv::COLOR_RGB2BGR);
 }
 
+inline void getGrayImageFromMetaData(const openni::VideoFrameRef& imageMetaData, cv::Mat& grayImage)
+{
+    if (imageMetaData.getVideoMode().getPixelFormat() == openni::PIXEL_FORMAT_GRAY8)
+    {
+        grayImage.create(imageMetaData.getHeight(), imageMetaData.getWidth(), CV_8UC1);
+        grayImage.data = (uchar*)imageMetaData.getData();
+    }
+    else if (imageMetaData.getVideoMode().getPixelFormat() == openni::PIXEL_FORMAT_GRAY16)
+    {
+        grayImage.create(imageMetaData.getHeight(), imageMetaData.getWidth(), CV_16UC1);
+        grayImage.data = (uchar*)imageMetaData.getData();
+    }
+    else
+    {
+        CV_Error(CV_StsUnsupportedFormat, "Unsupported format of grabbed image\n");
+    }
+}
+
 IplImage* CvCapture_OpenNI2::retrieveBGRImage()
 {
-    if( !color.isValid() )
+    if( !streamFrames[CV_COLOR_STREAM].isValid() )
         return 0;
 
-    getBGRImageFromMetaData( colorFrame, outputMaps[CV_CAP_OPENNI_BGR_IMAGE].mat );
+    getBGRImageFromMetaData(streamFrames[CV_COLOR_STREAM], outputMaps[CV_CAP_OPENNI_BGR_IMAGE].mat );
 
     return outputMaps[CV_CAP_OPENNI_BGR_IMAGE].getIplImagePtr();
 }
 
 IplImage* CvCapture_OpenNI2::retrieveGrayImage()
 {
-    if (!colorFrame.isValid())
+    if (!streamFrames[CV_COLOR_STREAM].isValid())
         return 0;
 
-    CV_Assert(colorFrame.getVideoMode().getPixelFormat() == openni::PIXEL_FORMAT_RGB888); // RGB
+    CV_Assert(streamFrames[CV_COLOR_STREAM].getVideoMode().getPixelFormat() == openni::PIXEL_FORMAT_RGB888); // RGB
 
     cv::Mat rgbImage;
-    getBGRImageFromMetaData(colorFrame, rgbImage);
+    getBGRImageFromMetaData(streamFrames[CV_COLOR_STREAM], rgbImage);
     cv::cvtColor( rgbImage, outputMaps[CV_CAP_OPENNI_GRAY_IMAGE].mat, CV_BGR2GRAY );
 
     return outputMaps[CV_CAP_OPENNI_GRAY_IMAGE].getIplImagePtr();
 }
 
+IplImage* CvCapture_OpenNI2::retrieveIrImage()
+{
+    if (!streamFrames[CV_IR_STREAM].isValid())
+        return 0;
+
+    getGrayImageFromMetaData(streamFrames[CV_IR_STREAM], outputMaps[CV_CAP_OPENNI_IR_IMAGE].mat);
+
+    return outputMaps[CV_CAP_OPENNI_IR_IMAGE].getIplImagePtr();
+}
+
 IplImage* CvCapture_OpenNI2::retrieveFrame( int outputType )
 {
     IplImage* image = 0;
@@ -899,6 +1063,10 @@ IplImage* CvCapture_OpenNI2::retrieveFrame( int outputType )
     {
         image = retrieveGrayImage();
     }
+    else if( outputType == CV_CAP_OPENNI_IR_IMAGE )
+    {
+        image = retrieveIrImage();
+    }
 
     return image;
 }
@@ -914,7 +1082,7 @@ CvCapture* cvCreateCameraCapture_OpenNI2( int index )
     return 0;
 }
 
-CvCapture* cvCreateFileCapture_OpenNI( const char* filename )
+CvCapture* cvCreateFileCapture_OpenNI2( const char* filename )
 {
     CvCapture_OpenNI2* capture = new CvCapture_OpenNI2( filename );
 
diff --git a/modules/videoio/src/cap_qtkit.mm b/modules/videoio/src/cap_qtkit.mm
index bdbbd2d..ad6037b 100644
--- a/modules/videoio/src/cap_qtkit.mm
+++ b/modules/videoio/src/cap_qtkit.mm
@@ -93,6 +93,8 @@ didDropVideoFrameWithSampleBuffer:(QTSampleBuffer *)sampleBuffer
 - (int)updateImage;
 - (IplImage*)getOutput;
 
+- (void)doFireTimer:(NSTimer *)timer;
+
 @end
 
 /*****************************************************************************
@@ -622,6 +624,11 @@ didDropVideoFrameWithSampleBuffer:(QTSampleBuffer *)sampleBuffer
     return 1;
 }
 
+- (void)doFireTimer:(NSTimer *)timer {
+    (void)timer;
+    // dummy
+}
+
 @end
 
 
diff --git a/modules/videoio/src/cap_v4l.cpp b/modules/videoio/src/cap_v4l.cpp
index 36dd928..59202e2 100644
--- a/modules/videoio/src/cap_v4l.cpp
+++ b/modules/videoio/src/cap_v4l.cpp
@@ -16,7 +16,7 @@ For Release:  OpenCV-Linux Beta4  opencv-0.9.6
 Tested On:    LMLBT44 with 8 video inputs
 Problems?     Post your questions at answers.opencv.org,
               Report bugs at code.opencv.org,
-              Submit your fixes at https://github.com/Itseez/opencv/
+              Submit your fixes at https://github.com/opencv/opencv/
 Patched Comments:
 
 TW: The cv cam utils that came with the initial release of OpenCV for LINUX Beta4
@@ -270,12 +270,12 @@ struct CvCaptureCAM_V4L : public CvCapture
     int deviceHandle;
     int bufferIndex;
     int FirstCapture;
+    String deviceName;
 
     char *memoryMap;
     IplImage frame;
 
    __u32 palette;
-   int index;
    int width, height;
    __u32 fps;
    bool convert_rgb;
@@ -298,6 +298,7 @@ struct CvCaptureCAM_V4L : public CvCapture
    Range focus, brightness, contrast, saturation, hue, gain, exposure;
 
    bool open(int _index);
+   bool open(const char* deviceName);
 
    virtual double getProperty(int) const;
    virtual bool setProperty(int, double);
@@ -322,6 +323,8 @@ struct CvCaptureCAM_V4L : public CvCapture
            return focus;
        case CV_CAP_PROP_AUTOFOCUS:
            return Range(0, 1);
+       case CV_CAP_PROP_AUTO_EXPOSURE:
+           return Range(0, 4);
        default:
            return Range(0, 255);
        }
@@ -371,8 +374,8 @@ static void icvInitCapture_V4L() {
     }
     if (deviceHandle != -1)
       close(deviceHandle);
-      /* Set up to test the next /dev/video source in line */
-      CameraNumber++;
+    /* Set up to test the next /dev/video source in line */
+    CameraNumber++;
    } /* End while */
 
 }; /* End icvInitCapture_V4L */
@@ -392,7 +395,7 @@ static bool try_palette_v4l2(CvCaptureCAM_V4L* capture)
   return capture->palette == capture->form.fmt.pix.pixelformat;
 }
 
-static int try_init_v4l2(CvCaptureCAM_V4L* capture, char *deviceName)
+static int try_init_v4l2(CvCaptureCAM_V4L* capture, const char *deviceName)
 {
   // Test device for V4L2 compability
   // Return value:
@@ -450,6 +453,10 @@ static int try_init_v4l2(CvCaptureCAM_V4L* capture, char *deviceName)
 }
 
 static int autosetup_capture_mode_v4l2(CvCaptureCAM_V4L* capture) {
+    //in case palette is already set and works, no need to setup.
+    if(capture->palette != 0 and try_palette_v4l2(capture)){
+        return 0;
+    }
     __u32 try_order[] = {
             V4L2_PIX_FMT_BGR24,
             V4L2_PIX_FMT_YVU420,
@@ -463,7 +470,8 @@ static int autosetup_capture_mode_v4l2(CvCaptureCAM_V4L* capture) {
             V4L2_PIX_FMT_SN9C10X,
             V4L2_PIX_FMT_SBGGR8,
             V4L2_PIX_FMT_SGBRG8,
-            V4L2_PIX_FMT_RGB24
+            V4L2_PIX_FMT_RGB24,
+            V4L2_PIX_FMT_Y16
     };
 
     for (size_t i = 0; i < sizeof(try_order) / sizeof(__u32); i++) {
@@ -512,7 +520,7 @@ static void v4l2_control_range(CvCaptureCAM_V4L* cap, __u32 id)
     case V4L2_CID_GAIN:
         cap->gain = range;
         break;
-    case V4L2_CID_EXPOSURE:
+    case V4L2_CID_EXPOSURE_ABSOLUTE:
         cap->exposure = range;
         break;
     case V4L2_CID_FOCUS_ABSOLUTE:
@@ -555,6 +563,7 @@ static int v4l2_num_channels(__u32 palette) {
     case V4L2_PIX_FMT_YVU420:
     case V4L2_PIX_FMT_MJPEG:
     case V4L2_PIX_FMT_JPEG:
+    case V4L2_PIX_FMT_Y16:
         return 1;
     case V4L2_PIX_FMT_YUYV:
     case V4L2_PIX_FMT_UYVY:
@@ -570,6 +579,7 @@ static int v4l2_num_channels(__u32 palette) {
 static void v4l2_create_frame(CvCaptureCAM_V4L *capture) {
     CvSize size(capture->form.fmt.pix.width, capture->form.fmt.pix.height);
     int channels = 3;
+    int depth = IPL_DEPTH_8U;
 
     if (!capture->convert_rgb) {
         channels = v4l2_num_channels(capture->palette);
@@ -582,11 +592,16 @@ static void v4l2_create_frame(CvCaptureCAM_V4L *capture) {
         case V4L2_PIX_FMT_YVU420:
             size.height = size.height * 3 / 2; // "1.5" channels
             break;
+        case V4L2_PIX_FMT_Y16:
+            if(!capture->convert_rgb){
+                depth = IPL_DEPTH_16U;
+            }
+            break;
         }
     }
 
     /* Set up Image data */
-    cvInitImageHeader(&capture->frame, size, IPL_DEPTH_8U, channels);
+    cvInitImageHeader(&capture->frame, size, depth, channels);
 
     /* Allocate space for pixelformat we convert to.
      * If we do not convert frame is just points to the buffer
@@ -600,10 +615,7 @@ static void v4l2_create_frame(CvCaptureCAM_V4L *capture) {
 
 static int _capture_V4L2 (CvCaptureCAM_V4L *capture)
 {
-   char deviceName[MAX_DEVICE_DRIVER_NAME];
-   /* Print the CameraNumber at the end of the string with a width of one character */
-   sprintf(deviceName, "/dev/video%1d", capture->index);
-
+   const char* deviceName = capture->deviceName.c_str();
    if (try_init_v4l2(capture, deviceName) != 1) {
        /* init of the v4l2 device is not OK */
        return -1;
@@ -761,17 +773,16 @@ static int _capture_V4L2 (CvCaptureCAM_V4L *capture)
  * this also causes buffers to be reallocated if the frame size was changed.
  */
 static bool v4l2_reset( CvCaptureCAM_V4L* capture) {
-    int index = capture->index;
+    String deviceName = capture->deviceName;
     icvCloseCAM_V4L(capture);
-    capture->index = index;
+    capture->deviceName = deviceName;
     return _capture_V4L2(capture) == 1;
 }
 
 bool CvCaptureCAM_V4L::open(int _index)
 {
    int autoindex = 0;
-
-   index = -1; // set the capture to closed state
+   char _deviceName[MAX_DEVICE_DRIVER_NAME];
 
    if (!numCameras)
       icvInitCapture_V4L(); /* Havent called icvInitCapture yet - do it now! */
@@ -796,14 +807,21 @@ bool CvCaptureCAM_V4L::open(int _index)
      autoindex++;// i can recall icvOpenCAM_V4l with index=-1 for next camera
    }
 
-   index = _index;
-   FirstCapture = 1;
-   width = DEFAULT_V4L_WIDTH;
-   height = DEFAULT_V4L_HEIGHT;
-   fps = DEFAULT_V4L_FPS;
-   convert_rgb = true;
+   /* Print the CameraNumber at the end of the string with a width of one character */
+   sprintf(_deviceName, "/dev/video%1d", _index);
+   return open(_deviceName);
+}
 
-   return _capture_V4L2(this) == 1;
+bool CvCaptureCAM_V4L::open(const char* _deviceName)
+{
+    FirstCapture = 1;
+    width = DEFAULT_V4L_WIDTH;
+    height = DEFAULT_V4L_HEIGHT;
+    fps = DEFAULT_V4L_FPS;
+    convert_rgb = true;
+    deviceName = _deviceName;
+
+    return _capture_V4L2(this) == 1;
 }
 
 static int read_frame_v4l2(CvCaptureCAM_V4L* capture) {
@@ -830,7 +848,7 @@ static int read_frame_v4l2(CvCaptureCAM_V4L* capture) {
         default:
             /* display the error and stop processing */
             perror ("VIDIOC_DQBUF");
-            return 1;
+            return -1;
         }
    }
 
@@ -852,7 +870,7 @@ static int read_frame_v4l2(CvCaptureCAM_V4L* capture) {
    return 1;
 }
 
-static void mainloop_v4l2(CvCaptureCAM_V4L* capture) {
+static int mainloop_v4l2(CvCaptureCAM_V4L* capture) {
     unsigned int count;
 
     count = 1;
@@ -886,10 +904,14 @@ static void mainloop_v4l2(CvCaptureCAM_V4L* capture) {
                 break;
             }
 
-            if (read_frame_v4l2 (capture))
+            int returnCode = read_frame_v4l2 (capture);
+            if(returnCode == -1)
+                return -1;
+            if(returnCode == 1)
                 break;
         }
     }
+    return 0;
 }
 
 static bool icvGrabFrameCAM_V4L(CvCaptureCAM_V4L* capture) {
@@ -931,14 +953,15 @@ static bool icvGrabFrameCAM_V4L(CvCaptureCAM_V4L* capture) {
 #if defined(V4L_ABORT_BADJPEG)
         // skip first frame. it is often bad -- this is unnotied in traditional apps,
         //  but could be fatal if bad jpeg is enabled
-        mainloop_v4l2(capture);
+        if(mainloop_v4l2(capture) == -1)
+                return false;
 #endif
 
       /* preparation is ok */
       capture->FirstCapture = 0;
    }
 
-   mainloop_v4l2(capture);
+   if(mainloop_v4l2(capture) == -1) return false;
 
    return true;
 }
@@ -1078,6 +1101,15 @@ uyvy_to_rgb24 (int width, int height, unsigned char *src, unsigned char *dst)
     cvtColor(Mat(height, width, CV_8UC2, src), Mat(height, width, CV_8UC3, dst),
              COLOR_YUV2BGR_UYVY);
 }
+
+static inline void
+y16_to_rgb24 (int width, int height, unsigned char* src, unsigned char* dst)
+{
+    Mat gray8;
+    Mat(height, width, CV_16UC1, src).convertTo(gray8, CV_8U, 0.00390625);
+    cvtColor(gray8,Mat(height, width, CV_8UC3, dst),COLOR_GRAY2BGR);
+}
+
 #ifdef HAVE_JPEG
 
 /* convert from mjpeg to rgb24 */
@@ -1535,6 +1567,18 @@ static IplImage* icvRetrieveFrameCAM_V4L( CvCaptureCAM_V4L* capture, int) {
                 (unsigned char*)capture->buffers[(capture->bufferIndex+1) % capture->req.count].start,
                 (unsigned char*)capture->frame.imageData);
         break;
+    case V4L2_PIX_FMT_Y16:
+        if(capture->convert_rgb){
+            y16_to_rgb24(capture->form.fmt.pix.width,
+                         capture->form.fmt.pix.height,
+                         (unsigned char*)capture->buffers[capture->bufferIndex].start,
+                         (unsigned char*)capture->frame.imageData);
+        }else{
+            memcpy((char *)capture->frame.imageData,
+                   (char *)capture->buffers[capture->bufferIndex].start,
+                   capture->frame.imageSize);
+        }
+        break;
     }
 
     return(&capture->frame);
@@ -1552,8 +1596,10 @@ static inline __u32 capPropertyToV4L2(int prop) {
         return V4L2_CID_HUE;
     case CV_CAP_PROP_GAIN:
         return V4L2_CID_GAIN;
+    case CV_CAP_PROP_AUTO_EXPOSURE:
+        return V4L2_CID_EXPOSURE_AUTO;
     case CV_CAP_PROP_EXPOSURE:
-        return V4L2_CID_EXPOSURE;
+        return V4L2_CID_EXPOSURE_ABSOLUTE;
     case CV_CAP_PROP_AUTOFOCUS:
         return V4L2_CID_FOCUS_AUTO;
     case CV_CAP_PROP_FOCUS:
@@ -1567,6 +1613,7 @@ static double icvGetPropertyCAM_V4L (const CvCaptureCAM_V4L* capture,
                                      int property_id ) {
   {
       v4l2_format form;
+      memset(&form, 0, sizeof(v4l2_format));
       form.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
       if (-1 == ioctl (capture->deviceHandle, VIDIOC_G_FMT, &form)) {
           /* display an error message, and return an error code */
@@ -1640,6 +1687,9 @@ static double icvGetPropertyCAM_V4L (const CvCaptureCAM_V4L* capture,
           case CV_CAP_PROP_GAIN:
               fprintf (stderr, "Gain");
               break;
+          case CV_CAP_PROP_AUTO_EXPOSURE:
+              fprintf (stderr, "Auto Exposure");
+              break;
           case CV_CAP_PROP_EXPOSURE:
               fprintf (stderr, "Exposure");
               break;
@@ -1699,6 +1749,13 @@ static bool icvSetControl (CvCaptureCAM_V4L* capture,
         return false;
     }
 
+    if(control.id == V4L2_CID_EXPOSURE_AUTO && control.value == V4L2_EXPOSURE_MANUAL) {
+        // update the control range for expose after disabling autoexposure
+        // as it is not read correctly at startup
+        // TODO check this again as it might be fixed with Linux 4.5
+        v4l2_control_range(capture, V4L2_CID_EXPOSURE_ABSOLUTE);
+    }
+
     /* all was OK */
     return true;
 }
@@ -1741,6 +1798,20 @@ static int icvSetPropertyCAM_V4L( CvCaptureCAM_V4L* capture,
         capture->convert_rgb = bool(value) && possible;
         retval = possible || !bool(value);
         break;
+    case CV_CAP_PROP_FOURCC:
+        {
+            __u32 old_palette = capture->palette;
+            __u32 new_palette = static_cast<__u32>(value);
+            capture->palette = new_palette;
+            if (v4l2_reset(capture)) {
+                retval = true;
+            } else {
+                capture->palette = old_palette;
+                v4l2_reset(capture);
+                retval = false;
+            }
+        }
+        break;
     default:
         retval = icvSetControl(capture, property_id, value);
         break;
@@ -1753,7 +1824,7 @@ static int icvSetPropertyCAM_V4L( CvCaptureCAM_V4L* capture,
 static void icvCloseCAM_V4L( CvCaptureCAM_V4L* capture ){
    /* Deallocate space - Hopefully, no leaks */
 
-   if (capture->index > -1)
+   if (!capture->deviceName.empty())
    {
        if (capture->deviceHandle != -1)
        {
@@ -1779,10 +1850,10 @@ static void icvCloseCAM_V4L( CvCaptureCAM_V4L* capture ){
      if (capture->deviceHandle != -1)
        close(capture->deviceHandle);
 
-     if (capture->frame.imageData)
+     if (capture->frame_allocated && capture->frame.imageData)
          cvFree(&capture->frame.imageData);
 
-     capture->index = -1; // flag that the capture is closed
+     capture->deviceName.clear(); // flag that the capture is closed
    }
 };
 
@@ -1819,4 +1890,15 @@ CvCapture* cvCreateCameraCapture_V4L( int index )
     return NULL;
 }
 
+CvCapture* cvCreateCameraCapture_V4L( const char * deviceName )
+{
+    cv::CvCaptureCAM_V4L* capture = new cv::CvCaptureCAM_V4L();
+
+    if(capture->open( deviceName ))
+        return capture;
+
+    delete capture;
+    return NULL;
+}
+
 #endif
diff --git a/modules/videoio/src/cap_vfw.cpp b/modules/videoio/src/cap_vfw.cpp
index ca5500c..555e848 100644
--- a/modules/videoio/src/cap_vfw.cpp
+++ b/modules/videoio/src/cap_vfw.cpp
@@ -498,8 +498,17 @@ IplImage* CvCaptureCAM_VFW::retrieveFrame(int)
         frame = cvCreateImage( cvSize( vfmt0.biWidth, vfmt0.biHeight ), 8, 3 );
     }
 
-    if( vfmt0.biCompression != BI_RGB ||
-        vfmt0.biBitCount != 24 )
+    if ( vfmt0.biCompression == MAKEFOURCC('N','V','1','2') )
+    {
+        // Frame is in YUV 4:2:0 NV12 format, convert to BGR color space
+        // See https://msdn.microsoft.com/en-us/library/windows/desktop/dd206750(v=vs.85).aspx#nv12)
+        IplImage src;
+        cvInitImageHeader( &src, cvSize( vfmt0.biWidth, vfmt0.biHeight * 3 / 2 ), IPL_DEPTH_8U, 1, IPL_ORIGIN_BL, 4 );
+        cvSetData( &src, hdr->lpData, src.widthStep );
+        cvCvtColor( &src, frame, CV_YUV2BGR_NV12 );
+    }
+    else if( vfmt0.biCompression != BI_RGB ||
+             vfmt0.biBitCount != 24 )
     {
         BITMAPINFOHEADER vfmt1 = icvBitmapHeader( vfmt0.biWidth, vfmt0.biHeight, 24 );
 
diff --git a/modules/videoio/src/cap_ximea.cpp b/modules/videoio/src/cap_ximea.cpp
index bf3fdf5..e31c01a 100644
--- a/modules/videoio/src/cap_ximea.cpp
+++ b/modules/videoio/src/cap_ximea.cpp
@@ -2,7 +2,7 @@
 #include "precomp.hpp"
 
 #ifdef WIN32
-#include "xiApi.h"
+#include <xiApi.h>
 #else
 #include <m3api/xiApi.h>
 #endif
@@ -19,7 +19,7 @@ public:
 
     virtual bool open( int index );
     virtual void close();
-    virtual double getProperty(int);
+    virtual double getProperty(int) const;
     virtual bool setProperty(int, double);
     virtual bool grabFrame();
     virtual IplImage* retrieveFrame(int);
@@ -27,9 +27,9 @@ public:
 
 private:
     void init();
-    void errMsg(const char* msg, int errNum);
+    void errMsg(const char* msg, int errNum) const;
     void resetCvImage();
-    int  ocvParamtoXimeaParam(int value);
+    int  ocvParamtoXimeaParam(int value) const;
     IplImage* frame;
 
     HANDLE    hmv;
@@ -284,7 +284,7 @@ void CvCaptureCAM_XIMEA::resetCvImage()
 
 /**********************************************************************************/
 
-int CvCaptureCAM_XIMEA::ocvParamtoXimeaParam(int property_id)
+int CvCaptureCAM_XIMEA::ocvParamtoXimeaParam(int property_id) const
 {
     XI_RETURN stat = XI_OK;
     switch (property_id)
@@ -399,6 +399,16 @@ bool CvCaptureCAM_XIMEA::setProperty( int property_id, double value )
         value_type = xiTypeEnum;
         doAcqReset = true;
         break;
+    case CV_CAP_PROP_XI_TEST_PATTERN_GENERATOR_SELECTOR:
+        ximea_param = "test_pattern_generator_selector";
+        value_type = xiTypeEnum;
+        doAcqReset = true;
+        break;
+    case CV_CAP_PROP_XI_TEST_PATTERN:
+        ximea_param = "test_pattern";
+        value_type = xiTypeEnum;
+        doAcqReset = true;
+        break;
     case CV_CAP_PROP_XI_IMAGE_DATA_FORMAT:
         ximea_param = "imgdataformat";
         value_type = xiTypeEnum;
@@ -478,6 +488,16 @@ bool CvCaptureCAM_XIMEA::setProperty( int property_id, double value )
         value_type = xiTypeInteger;
         doAcqReset = true;
         break;
+    case CV_CAP_PROP_XI_REGION_SELECTOR :
+        ximea_param = "region_selector";
+        value_type = xiTypeInteger;
+        doAcqReset = true;
+        break;
+    case CV_CAP_PROP_XI_REGION_MODE :
+        ximea_param = "region_mode";
+        value_type = xiTypeInteger;
+        doAcqReset = true;
+        break;
     case CV_CAP_PROP_XI_EXP_PRIORITY:
         ximea_param = "exp_priority";
         value_type = xiTypeFloat;
@@ -544,6 +564,14 @@ bool CvCaptureCAM_XIMEA::setProperty( int property_id, double value )
         ximea_param = "hous_temp";
         value_type = xiTypeFloat;
         break;
+    case CV_CAP_PROP_XI_HOUS_BACK_SIDE_TEMP:
+        ximea_param = "hous_back_side_temp";
+        value_type = xiTypeFloat;
+        break;
+    case CV_CAP_PROP_XI_SENSOR_BOARD_TEMP:
+        ximea_param = "sensor_board_temp";
+        value_type = xiTypeFloat;
+        break;
     case CV_CAP_PROP_XI_CMS:
         ximea_param = "cms";
         value_type = xiTypeEnum;
@@ -652,6 +680,7 @@ bool CvCaptureCAM_XIMEA::setProperty( int property_id, double value )
     case CV_CAP_PROP_XI_TRG_SELECTOR:
         ximea_param = "trigger_selector";
         value_type = xiTypeEnum;
+        doAcqReset = true;
         break;
     case CV_CAP_PROP_XI_ACQ_FRAME_BURST_COUNT:
         ximea_param = "acq_frame_burst_count";
@@ -756,14 +785,17 @@ bool CvCaptureCAM_XIMEA::setProperty( int property_id, double value )
     case CV_CAP_PROP_XI_SENSOR_CLOCK_FREQ_HZ:
         ximea_param = "sensor_clock_freq_hz";
         value_type = xiTypeFloat;
+        doAcqReset = true;
         break;
     case CV_CAP_PROP_XI_SENSOR_CLOCK_FREQ_INDEX:
         ximea_param = "sensor_clock_freq_index";
         value_type = xiTypeInteger;
+        doAcqReset = true;
         break;
     case CV_CAP_PROP_XI_SENSOR_OUTPUT_CHANNEL_COUNT:
         ximea_param = "sensor_output_channel_count";
         value_type = xiTypeEnum;
+        doAcqReset = true;
         break;
     case CV_CAP_PROP_XI_FRAMERATE:
         ximea_param = "framerate";
@@ -784,6 +816,7 @@ bool CvCaptureCAM_XIMEA::setProperty( int property_id, double value )
     case CV_CAP_PROP_XI_AVAILABLE_BANDWIDTH:
         ximea_param = "available_bandwidth";
         value_type = xiTypeInteger;
+        doAcqReset = true;
         break;
     case CV_CAP_PROP_XI_BUFFER_POLICY:
         ximea_param = "buffer_policy";
@@ -792,14 +825,17 @@ bool CvCaptureCAM_XIMEA::setProperty( int property_id, double value )
     case CV_CAP_PROP_XI_LUT_EN:
         ximea_param = "LUTEnable";
         value_type = xiTypeBoolean;
+        doAcqReset = true;
         break;
     case CV_CAP_PROP_XI_LUT_INDEX:
         ximea_param = "LUTIndex";
         value_type = xiTypeInteger;
+        doAcqReset = true;
         break;
     case CV_CAP_PROP_XI_LUT_VALUE:
         ximea_param = "LUTValue";
         value_type = xiTypeInteger;
+        doAcqReset = true;
         break;
     case CV_CAP_PROP_XI_TRG_DELAY:
         ximea_param = "trigger_delay";
@@ -820,22 +856,27 @@ bool CvCaptureCAM_XIMEA::setProperty( int property_id, double value )
     case CV_CAP_PROP_XI_ACQ_BUFFER_SIZE:
         ximea_param = "acq_buffer_size";
         value_type = xiTypeInteger;
+        doAcqReset = true;
         break;
     case CV_CAP_PROP_XI_ACQ_BUFFER_SIZE_UNIT:
         ximea_param = "acq_buffer_size_unit";
         value_type = xiTypeInteger;
+        doAcqReset = true;
         break;
     case CV_CAP_PROP_XI_ACQ_TRANSPORT_BUFFER_SIZE:
         ximea_param = "acq_transport_buffer_size";
         value_type = xiTypeInteger;
+        doAcqReset = true;
         break;
     case CV_CAP_PROP_XI_BUFFERS_QUEUE_SIZE:
         ximea_param = "buffers_queue_size";
         value_type = xiTypeInteger;
+        doAcqReset = true;
         break;
     case CV_CAP_PROP_XI_ACQ_TRANSPORT_BUFFER_COMMIT:
         ximea_param = "acq_transport_buffer_commit";
         value_type = xiTypeInteger;
+        doAcqReset = true;
         break;
     case CV_CAP_PROP_XI_RECENT_FRAME:
         ximea_param = "recent_frame";
@@ -850,9 +891,14 @@ bool CvCaptureCAM_XIMEA::setProperty( int property_id, double value )
         ximea_param = "column_fpn_correction";
         value_type = xiTypeEnum;
         break;
+    case CV_CAP_PROP_XI_ROW_FPN_CORRECTION:
+        ximea_param = "row_fpn_correction";
+        value_type = xiTypeEnum;
+        break;
     case CV_CAP_PROP_XI_SENSOR_MODE:
         ximea_param = "sensor_mode";
         value_type = xiTypeEnum;
+        doAcqReset = true;
         break;
     case CV_CAP_PROP_XI_HDR:
         ximea_param = "hdr";
@@ -894,6 +940,14 @@ bool CvCaptureCAM_XIMEA::setProperty( int property_id, double value )
         ximea_param = "auto_bandwidth_calculation";
         value_type = xiTypeBoolean;
         break;
+    case CV_CAP_PROP_XI_FFS_FILE_ID:
+        ximea_param = "ffs_file_id";
+        value_type = xiTypeInteger;
+        break;
+    case CV_CAP_PROP_XI_FFS_FILE_SIZE:
+        ximea_param = "ffs_file_size";
+        value_type = xiTypeInteger;
+        break;
     case CV_CAP_PROP_XI_FREE_FFS_SIZE:
         ximea_param = "free_ffs_size";
         value_type = xiTypeInteger;
@@ -963,7 +1017,7 @@ bool CvCaptureCAM_XIMEA::setProperty( int property_id, double value )
 
 /**********************************************************************************/
 
-double CvCaptureCAM_XIMEA::getProperty( int property_id )
+double CvCaptureCAM_XIMEA::getProperty( int property_id ) const
 {
     XI_RETURN stat = XI_OK;
     double getPropVal = 0;
@@ -1042,6 +1096,14 @@ double CvCaptureCAM_XIMEA::getProperty( int property_id )
         ximea_param = "decimation_pattern";
         value_type = xiTypeEnum;
         break;
+    case CV_CAP_PROP_XI_TEST_PATTERN_GENERATOR_SELECTOR:
+        ximea_param = "test_pattern_generator_selector";
+        value_type = xiTypeEnum;
+        break;
+    case CV_CAP_PROP_XI_TEST_PATTERN:
+        ximea_param = "test_pattern";
+        value_type = xiTypeEnum;
+        break;
     case CV_CAP_PROP_XI_IMAGE_DATA_FORMAT:
         ximea_param = "imgdataformat";
         value_type = xiTypeEnum;
@@ -1114,6 +1176,14 @@ double CvCaptureCAM_XIMEA::getProperty( int property_id )
         ximea_param = "offsetY";
         value_type = xiTypeInteger;
         break;
+    case CV_CAP_PROP_XI_REGION_SELECTOR :
+        ximea_param = "region_selector";
+        value_type = xiTypeInteger;
+        break;
+    case CV_CAP_PROP_XI_REGION_MODE :
+        ximea_param = "region_mode";
+        value_type = xiTypeInteger;
+        break;
     case CV_CAP_PROP_XI_EXP_PRIORITY:
         ximea_param = "exp_priority";
         value_type = xiTypeFloat;
@@ -1174,6 +1244,14 @@ double CvCaptureCAM_XIMEA::getProperty( int property_id )
         ximea_param = "hous_temp";
         value_type = xiTypeFloat;
         break;
+    case CV_CAP_PROP_XI_HOUS_BACK_SIDE_TEMP:
+        ximea_param = "hous_back_side_temp";
+        value_type = xiTypeFloat;
+        break;
+    case CV_CAP_PROP_XI_SENSOR_BOARD_TEMP:
+        ximea_param = "sensor_board_temp";
+        value_type = xiTypeFloat;
+        break;
     case CV_CAP_PROP_XI_CMS:
         ximea_param = "cms";
         value_type = xiTypeEnum;
@@ -1478,6 +1556,10 @@ double CvCaptureCAM_XIMEA::getProperty( int property_id )
         ximea_param = "column_fpn_correction";
         value_type = xiTypeEnum;
         break;
+    case CV_CAP_PROP_XI_ROW_FPN_CORRECTION:
+        ximea_param = "row_fpn_correction";
+        value_type = xiTypeEnum;
+        break;
     case CV_CAP_PROP_XI_SENSOR_MODE:
         ximea_param = "sensor_mode";
         value_type = xiTypeEnum;
@@ -1522,6 +1604,14 @@ double CvCaptureCAM_XIMEA::getProperty( int property_id )
         ximea_param = "auto_bandwidth_calculation";
         value_type = xiTypeBoolean;
         break;
+    case CV_CAP_PROP_XI_FFS_FILE_ID:
+        ximea_param = "ffs_file_id";
+        value_type = xiTypeInteger;
+        break;
+    case CV_CAP_PROP_XI_FFS_FILE_SIZE:
+        ximea_param = "ffs_file_size";
+        value_type = xiTypeInteger;
+        break;
     case CV_CAP_PROP_XI_FREE_FFS_SIZE:
         ximea_param = "free_ffs_size";
         value_type = xiTypeInteger;
@@ -1572,7 +1662,7 @@ double CvCaptureCAM_XIMEA::getProperty( int property_id )
 
 /**********************************************************************************/
 
-void CvCaptureCAM_XIMEA::errMsg(const char* msg, int errNum)
+void CvCaptureCAM_XIMEA::errMsg(const char* msg, int errNum) const
 {
     // with XI_OK there is nothing to report
     if(errNum == XI_OK) return;
@@ -1640,6 +1730,7 @@ void CvCaptureCAM_XIMEA::errMsg(const char* msg, int errNum)
     case XI_BUFFER_SIZE_TOO_SMALL : error_message = "Buffer provided by user is too small"; break;
     case XI_COULDNT_INIT_PROCESSOR : error_message = "Couldnt initialize processor."; break;
     case XI_NOT_INITIALIZED : error_message = "The object/module/procedure/process being referred to has not been started."; break;
+    case XI_RESOURCE_NOT_FOUND : error_message = "Resource not found(could be processor, file, item..)."; break;
     case XI_UNKNOWN_PARAM : error_message = "Unknown parameter"; break;
     case XI_WRONG_PARAM_VALUE : error_message = "Wrong parameter value"; break;
     case XI_WRONG_PARAM_TYPE : error_message = "Wrong parameter type"; break;
diff --git a/modules/videoio/src/ffmpeg_codecs.hpp b/modules/videoio/src/ffmpeg_codecs.hpp
index 42eded7..a2a7a3b 100644
--- a/modules/videoio/src/ffmpeg_codecs.hpp
+++ b/modules/videoio/src/ffmpeg_codecs.hpp
@@ -60,24 +60,7 @@ extern "C" {
 #include <errno.h>
 #endif
 
-// if the header path is not specified explicitly, let's deduce it
-#if !defined HAVE_FFMPEG_AVCODEC_H && !defined HAVE_LIBAVCODEC_AVCODEC_H
-
-#if defined(HAVE_GENTOO_FFMPEG)
-  #define HAVE_LIBAVFORMAT_AVFORMAT_H 1
-#elif defined HAVE_FFMPEG
-  #define HAVE_FFMPEG_AVFORMAT_H 1
-#endif
-
-#if defined(HAVE_FFMPEG_AVFORMAT_H)
-  #include <ffmpeg/avformat.h>
-#endif
-
-#if defined(HAVE_LIBAVFORMAT_AVFORMAT_H) || defined(WIN32)
-  #include <libavformat/avformat.h>
-#endif
-
-#endif
+#include <libavformat/avformat.h>
 
 #ifdef __cplusplus
 }
diff --git a/modules/videoio/src/precomp.hpp b/modules/videoio/src/precomp.hpp
index 442eaa1..8a10d20 100644
--- a/modules/videoio/src/precomp.hpp
+++ b/modules/videoio/src/precomp.hpp
@@ -66,7 +66,7 @@
         #ifdef HAVE_MSMF
             #define _WIN32_WINNT 0x0600 // Windows Vista
         #else
-            #define _WIN32_WINNT 0x0500 // Windows 2000
+            #define _WIN32_WINNT 0x0501 // Windows XP
         #endif
     #endif
 
@@ -102,6 +102,7 @@ struct CvVideoWriter
 };
 
 CvCapture * cvCreateCameraCapture_V4L( int index );
+CvCapture * cvCreateCameraCapture_V4L( const char* deviceName );
 CvCapture * cvCreateCameraCapture_DC1394( int index );
 CvCapture * cvCreateCameraCapture_DC1394_2( int index );
 CvCapture* cvCreateCameraCapture_MIL( int index );
@@ -123,9 +124,11 @@ CvVideoWriter* cvCreateVideoWriter_MSMF( const char* filename, int fourcc,
 CvCapture* cvCreateCameraCapture_OpenNI( int index );
 CvCapture* cvCreateCameraCapture_OpenNI2( int index );
 CvCapture* cvCreateFileCapture_OpenNI( const char* filename );
+CvCapture* cvCreateFileCapture_OpenNI2( const char* filename );
 CvCapture* cvCreateCameraCapture_Android( int index );
 CvCapture* cvCreateCameraCapture_XIMEA( int index );
 CvCapture* cvCreateCameraCapture_AVFoundation(int index);
+CvCapture* cvCreateCameraCapture_Aravis( int index );
 
 CvCapture* cvCreateFileCapture_Images(const char* filename);
 CvVideoWriter* cvCreateVideoWriter_Images(const char* filename);
@@ -191,6 +194,6 @@ namespace cv
 
     Ptr<IVideoCapture> createGPhoto2Capture(int index);
     Ptr<IVideoCapture> createGPhoto2Capture(const String& deviceName);
-};
+}
 
 #endif /* __VIDEOIO_H_ */
diff --git a/modules/videoio/test/test_ffmpeg.cpp b/modules/videoio/test/test_ffmpeg.cpp
index 4238177..fce8cf4 100644
--- a/modules/videoio/test/test_ffmpeg.cpp
+++ b/modules/videoio/test/test_ffmpeg.cpp
@@ -118,6 +118,9 @@ public:
                     frame_s = Size(352, 288);
                 else if( tag == VideoWriter::fourcc('H', '2', '6', '3') )
                     frame_s = Size(704, 576);
+                else if( tag == VideoWriter::fourcc('H', '2', '6', '4') )
+                    // OpenH264 1.5.0 has resolution limitations, so lets use DCI 4K resolution
+                    frame_s = Size(4096, 2160);
                 /*else if( tag == CV_FOURCC('M', 'J', 'P', 'G') ||
                          tag == CV_FOURCC('j', 'p', 'e', 'g') )
                     frame_s = Size(1920, 1080);*/
diff --git a/modules/videostab/CMakeLists.txt b/modules/videostab/CMakeLists.txt
index 49e75f9..c31fcfc 100644
--- a/modules/videostab/CMakeLists.txt
+++ b/modules/videostab/CMakeLists.txt
@@ -4,7 +4,7 @@ if(HAVE_CUDA)
   ocv_warnings_disable(CMAKE_CXX_FLAGS -Wundef -Wmissing-declarations -Wshadow -Wunused-parameter)
 endif()
 
-if(WINRT_8_1)
+if(DEFINED WINRT AND NOT DEFINED ENABLE_WINRT_MODE_NATIVE)
   set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /ZW")
 endif()
 
diff --git a/modules/videostab/include/opencv2/videostab.hpp b/modules/videostab/include/opencv2/videostab.hpp
index 17b061f..ca3f5ad 100644
--- a/modules/videostab/include/opencv2/videostab.hpp
+++ b/modules/videostab/include/opencv2/videostab.hpp
@@ -40,15 +40,15 @@
 //
 //M*/
 
-#ifndef __OPENCV_VIDEOSTAB_HPP__
-#define __OPENCV_VIDEOSTAB_HPP__
+#ifndef OPENCV_VIDEOSTAB_HPP
+#define OPENCV_VIDEOSTAB_HPP
 
 /**
   @defgroup videostab Video Stabilization
 
 The video stabilization module contains a set of functions and classes that can be used to solve the
-problem of video stabilization. There are a few methods implemented, most of them are descibed in
-the papers @cite OF06 and @cite G11 . However, there are some extensions and deviations from the orginal
+problem of video stabilization. There are a few methods implemented, most of them are described in
+the papers @cite OF06 and @cite G11 . However, there are some extensions and deviations from the original
 paper methods.
 
 ### References
diff --git a/modules/videostab/include/opencv2/videostab/deblurring.hpp b/modules/videostab/include/opencv2/videostab/deblurring.hpp
index 8028c1d..b383f0d 100644
--- a/modules/videostab/include/opencv2/videostab/deblurring.hpp
+++ b/modules/videostab/include/opencv2/videostab/deblurring.hpp
@@ -40,8 +40,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_VIDEOSTAB_DEBLURRING_HPP__
-#define __OPENCV_VIDEOSTAB_DEBLURRING_HPP__
+#ifndef OPENCV_VIDEOSTAB_DEBLURRING_HPP
+#define OPENCV_VIDEOSTAB_DEBLURRING_HPP
 
 #include <vector>
 #include "opencv2/core.hpp"
diff --git a/modules/videostab/include/opencv2/videostab/fast_marching.hpp b/modules/videostab/include/opencv2/videostab/fast_marching.hpp
index c0c7985..526b10b 100644
--- a/modules/videostab/include/opencv2/videostab/fast_marching.hpp
+++ b/modules/videostab/include/opencv2/videostab/fast_marching.hpp
@@ -40,8 +40,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_VIDEOSTAB_FAST_MARCHING_HPP__
-#define __OPENCV_VIDEOSTAB_FAST_MARCHING_HPP__
+#ifndef OPENCV_VIDEOSTAB_FAST_MARCHING_HPP
+#define OPENCV_VIDEOSTAB_FAST_MARCHING_HPP
 
 #include <cmath>
 #include <queue>
diff --git a/modules/videostab/include/opencv2/videostab/fast_marching_inl.hpp b/modules/videostab/include/opencv2/videostab/fast_marching_inl.hpp
index 6388e69..fdd488a 100644
--- a/modules/videostab/include/opencv2/videostab/fast_marching_inl.hpp
+++ b/modules/videostab/include/opencv2/videostab/fast_marching_inl.hpp
@@ -40,8 +40,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_VIDEOSTAB_FAST_MARCHING_INL_HPP__
-#define __OPENCV_VIDEOSTAB_FAST_MARCHING_INL_HPP__
+#ifndef OPENCV_VIDEOSTAB_FAST_MARCHING_INL_HPP
+#define OPENCV_VIDEOSTAB_FAST_MARCHING_INL_HPP
 
 #include "opencv2/videostab/fast_marching.hpp"
 
diff --git a/modules/videostab/include/opencv2/videostab/frame_source.hpp b/modules/videostab/include/opencv2/videostab/frame_source.hpp
index 612fbdb..e4e00b5 100644
--- a/modules/videostab/include/opencv2/videostab/frame_source.hpp
+++ b/modules/videostab/include/opencv2/videostab/frame_source.hpp
@@ -40,8 +40,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_VIDEOSTAB_FRAME_SOURCE_HPP__
-#define __OPENCV_VIDEOSTAB_FRAME_SOURCE_HPP__
+#ifndef OPENCV_VIDEOSTAB_FRAME_SOURCE_HPP
+#define OPENCV_VIDEOSTAB_FRAME_SOURCE_HPP
 
 #include <vector>
 #include "opencv2/core.hpp"
diff --git a/modules/videostab/include/opencv2/videostab/global_motion.hpp b/modules/videostab/include/opencv2/videostab/global_motion.hpp
index 5d51e42..80b147a 100644
--- a/modules/videostab/include/opencv2/videostab/global_motion.hpp
+++ b/modules/videostab/include/opencv2/videostab/global_motion.hpp
@@ -40,8 +40,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_VIDEOSTAB_GLOBAL_MOTION_HPP__
-#define __OPENCV_VIDEOSTAB_GLOBAL_MOTION_HPP__
+#ifndef OPENCV_VIDEOSTAB_GLOBAL_MOTION_HPP
+#define OPENCV_VIDEOSTAB_GLOBAL_MOTION_HPP
 
 #include <vector>
 #include <fstream>
diff --git a/modules/videostab/include/opencv2/videostab/inpainting.hpp b/modules/videostab/include/opencv2/videostab/inpainting.hpp
index 844c68c..61eeec3 100644
--- a/modules/videostab/include/opencv2/videostab/inpainting.hpp
+++ b/modules/videostab/include/opencv2/videostab/inpainting.hpp
@@ -40,8 +40,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_VIDEOSTAB_INPAINTINT_HPP__
-#define __OPENCV_VIDEOSTAB_INPAINTINT_HPP__
+#ifndef OPENCV_VIDEOSTAB_INPAINTINT_HPP
+#define OPENCV_VIDEOSTAB_INPAINTINT_HPP
 
 #include <vector>
 #include "opencv2/core.hpp"
diff --git a/modules/videostab/include/opencv2/videostab/log.hpp b/modules/videostab/include/opencv2/videostab/log.hpp
index 28625ed..81c634a 100644
--- a/modules/videostab/include/opencv2/videostab/log.hpp
+++ b/modules/videostab/include/opencv2/videostab/log.hpp
@@ -40,8 +40,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_VIDEOSTAB_LOG_HPP__
-#define __OPENCV_VIDEOSTAB_LOG_HPP__
+#ifndef OPENCV_VIDEOSTAB_LOG_HPP
+#define OPENCV_VIDEOSTAB_LOG_HPP
 
 #include "opencv2/core.hpp"
 
diff --git a/modules/videostab/include/opencv2/videostab/motion_core.hpp b/modules/videostab/include/opencv2/videostab/motion_core.hpp
index 17448e3..4525cc7 100644
--- a/modules/videostab/include/opencv2/videostab/motion_core.hpp
+++ b/modules/videostab/include/opencv2/videostab/motion_core.hpp
@@ -40,8 +40,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_VIDEOSTAB_MOTION_CORE_HPP__
-#define __OPENCV_VIDEOSTAB_MOTION_CORE_HPP__
+#ifndef OPENCV_VIDEOSTAB_MOTION_CORE_HPP
+#define OPENCV_VIDEOSTAB_MOTION_CORE_HPP
 
 #include <cmath>
 #include "opencv2/core.hpp"
diff --git a/modules/videostab/include/opencv2/videostab/motion_stabilizing.hpp b/modules/videostab/include/opencv2/videostab/motion_stabilizing.hpp
index 3bdbfbd..5ea5a65 100644
--- a/modules/videostab/include/opencv2/videostab/motion_stabilizing.hpp
+++ b/modules/videostab/include/opencv2/videostab/motion_stabilizing.hpp
@@ -40,8 +40,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_VIDEOSTAB_MOTION_STABILIZING_HPP__
-#define __OPENCV_VIDEOSTAB_MOTION_STABILIZING_HPP__
+#ifndef OPENCV_VIDEOSTAB_MOTION_STABILIZING_HPP
+#define OPENCV_VIDEOSTAB_MOTION_STABILIZING_HPP
 
 #include <vector>
 #include <utility>
diff --git a/modules/videostab/include/opencv2/videostab/optical_flow.hpp b/modules/videostab/include/opencv2/videostab/optical_flow.hpp
index 41d1953..d631488 100644
--- a/modules/videostab/include/opencv2/videostab/optical_flow.hpp
+++ b/modules/videostab/include/opencv2/videostab/optical_flow.hpp
@@ -40,8 +40,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_VIDEOSTAB_OPTICAL_FLOW_HPP__
-#define __OPENCV_VIDEOSTAB_OPTICAL_FLOW_HPP__
+#ifndef OPENCV_VIDEOSTAB_OPTICAL_FLOW_HPP
+#define OPENCV_VIDEOSTAB_OPTICAL_FLOW_HPP
 
 #include "opencv2/core.hpp"
 #include "opencv2/opencv_modules.hpp"
diff --git a/modules/videostab/include/opencv2/videostab/outlier_rejection.hpp b/modules/videostab/include/opencv2/videostab/outlier_rejection.hpp
index 9e40f85..9b9b384 100644
--- a/modules/videostab/include/opencv2/videostab/outlier_rejection.hpp
+++ b/modules/videostab/include/opencv2/videostab/outlier_rejection.hpp
@@ -40,8 +40,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_VIDEOSTAB_OUTLIER_REJECTION_HPP__
-#define __OPENCV_VIDEOSTAB_OUTLIER_REJECTION_HPP__
+#ifndef OPENCV_VIDEOSTAB_OUTLIER_REJECTION_HPP
+#define OPENCV_VIDEOSTAB_OUTLIER_REJECTION_HPP
 
 #include <vector>
 #include "opencv2/core.hpp"
diff --git a/modules/videostab/include/opencv2/videostab/ring_buffer.hpp b/modules/videostab/include/opencv2/videostab/ring_buffer.hpp
index 7cc3f03..55d5244 100644
--- a/modules/videostab/include/opencv2/videostab/ring_buffer.hpp
+++ b/modules/videostab/include/opencv2/videostab/ring_buffer.hpp
@@ -40,8 +40,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_VIDEOSTAB_RING_BUFFER_HPP__
-#define __OPENCV_VIDEOSTAB_RING_BUFFER_HPP__
+#ifndef OPENCV_VIDEOSTAB_RING_BUFFER_HPP
+#define OPENCV_VIDEOSTAB_RING_BUFFER_HPP
 
 #include <vector>
 #include "opencv2/imgproc.hpp"
diff --git a/modules/videostab/include/opencv2/videostab/stabilizer.hpp b/modules/videostab/include/opencv2/videostab/stabilizer.hpp
index c18d314..b78b4ea 100644
--- a/modules/videostab/include/opencv2/videostab/stabilizer.hpp
+++ b/modules/videostab/include/opencv2/videostab/stabilizer.hpp
@@ -40,8 +40,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_VIDEOSTAB_STABILIZER_HPP__
-#define __OPENCV_VIDEOSTAB_STABILIZER_HPP__
+#ifndef OPENCV_VIDEOSTAB_STABILIZER_HPP
+#define OPENCV_VIDEOSTAB_STABILIZER_HPP
 
 #include <vector>
 #include <ctime>
diff --git a/modules/videostab/include/opencv2/videostab/wobble_suppression.hpp b/modules/videostab/include/opencv2/videostab/wobble_suppression.hpp
index 3f0a943..a44410b 100644
--- a/modules/videostab/include/opencv2/videostab/wobble_suppression.hpp
+++ b/modules/videostab/include/opencv2/videostab/wobble_suppression.hpp
@@ -40,8 +40,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_VIDEOSTAB_WOBBLE_SUPPRESSION_HPP__
-#define __OPENCV_VIDEOSTAB_WOBBLE_SUPPRESSION_HPP__
+#ifndef OPENCV_VIDEOSTAB_WOBBLE_SUPPRESSION_HPP
+#define OPENCV_VIDEOSTAB_WOBBLE_SUPPRESSION_HPP
 
 #include <vector>
 #include "opencv2/core.hpp"
diff --git a/modules/videostab/src/deblurring.cpp b/modules/videostab/src/deblurring.cpp
index 2f4cfd0..dd6cfac 100644
--- a/modules/videostab/src/deblurring.cpp
+++ b/modules/videostab/src/deblurring.cpp
@@ -52,6 +52,8 @@ namespace videostab
 
 float calcBlurriness(const Mat &frame)
 {
+    CV_INSTRUMENT_REGION()
+
     Mat Gx, Gy;
     Sobel(frame, Gx, CV_32F, 1, 0);
     Sobel(frame, Gy, CV_32F, 0, 1);
@@ -70,6 +72,8 @@ WeightingDeblurer::WeightingDeblurer()
 
 void WeightingDeblurer::deblur(int idx, Mat &frame)
 {
+    CV_INSTRUMENT_REGION()
+
     CV_Assert(frame.type() == CV_8UC3);
 
     bSum_.create(frame.size());
diff --git a/modules/videostab/src/global_motion.cpp b/modules/videostab/src/global_motion.cpp
index f7938d5..5360338 100644
--- a/modules/videostab/src/global_motion.cpp
+++ b/modules/videostab/src/global_motion.cpp
@@ -356,6 +356,8 @@ static Mat estimateGlobMotionLeastSquaresAffine(
 Mat estimateGlobalMotionLeastSquares(
         InputOutputArray points0, InputOutputArray points1, int model, float *rmse)
 {
+    CV_INSTRUMENT_REGION()
+
     CV_Assert(model <= MM_AFFINE);
     CV_Assert(points0.type() == points1.type());
     const int npoints = points0.getMat().checkVector(2);
@@ -380,6 +382,8 @@ Mat estimateGlobalMotionRansac(
         InputArray points0, InputArray points1, int model, const RansacParams &params,
         float *rmse, int *ninliers)
 {
+    CV_INSTRUMENT_REGION()
+
     CV_Assert(model <= MM_AFFINE);
     CV_Assert(points0.type() == points1.type());
     const int npoints = points0.getMat().checkVector(2);
@@ -844,6 +848,8 @@ Mat KeypointBasedMotionEstimatorGpu::estimate(const cuda::GpuMat &frame0, const
 
 Mat getMotion(int from, int to, const std::vector<Mat> &motions)
 {
+    CV_INSTRUMENT_REGION()
+
     Mat M = Mat::eye(3, 3, CV_32F);
     if (to > from)
     {
diff --git a/modules/videostab/src/inpainting.cpp b/modules/videostab/src/inpainting.cpp
index 9911127..19f8e51 100644
--- a/modules/videostab/src/inpainting.cpp
+++ b/modules/videostab/src/inpainting.cpp
@@ -103,6 +103,8 @@ void InpaintingPipeline::setStabilizationMotions(const std::vector<Mat> &val)
 
 void InpaintingPipeline::inpaint(int idx, Mat &frame, Mat &mask)
 {
+    CV_INSTRUMENT_REGION()
+
     for (size_t i = 0; i < inpainters_.size(); ++i)
         inpainters_[i]->inpaint(idx, frame, mask);
 }
@@ -124,6 +126,8 @@ ConsistentMosaicInpainter::ConsistentMosaicInpainter()
 
 void ConsistentMosaicInpainter::inpaint(int idx, Mat &frame, Mat &mask)
 {
+    CV_INSTRUMENT_REGION()
+
     CV_Assert(frame.type() == CV_8UC3);
     CV_Assert(mask.size() == frame.size() && mask.type() == CV_8U);
 
@@ -336,6 +340,8 @@ MotionInpainter::MotionInpainter()
 
 void MotionInpainter::inpaint(int idx, Mat &frame, Mat &mask)
 {
+    CV_INSTRUMENT_REGION()
+
     std::priority_queue<std::pair<float,int> > neighbors;
     std::vector<Mat> vmotions(2*radius_ + 1);
 
@@ -456,6 +462,8 @@ public:
 
 void ColorAverageInpainter::inpaint(int /*idx*/, Mat &frame, Mat &mask)
 {
+    CV_INSTRUMENT_REGION()
+
     ColorAverageInpaintBody body;
     body.mask = mask;
     body.frame = frame;
@@ -465,6 +473,8 @@ void ColorAverageInpainter::inpaint(int /*idx*/, Mat &frame, Mat &mask)
 
 void ColorInpainter::inpaint(int /*idx*/, Mat &frame, Mat &mask)
 {
+    CV_INSTRUMENT_REGION()
+
     bitwise_not(mask, invMask_);
     cv::inpaint(frame, invMask_, frame, radius_, method_);
 }
@@ -474,6 +484,8 @@ void calcFlowMask(
         const Mat &flowX, const Mat &flowY, const Mat &errors, float maxError,
         const Mat &mask0, const Mat &mask1, Mat &flowMask)
 {
+    CV_INSTRUMENT_REGION()
+
     CV_Assert(flowX.type() == CV_32F && flowX.size() == mask0.size());
     CV_Assert(flowY.type() == CV_32F && flowY.size() == mask0.size());
     CV_Assert(errors.type() == CV_32F && errors.size() == mask0.size());
@@ -508,6 +520,8 @@ void completeFrameAccordingToFlow(
         const Mat &flowMask, const Mat &flowX, const Mat &flowY, const Mat &frame1, const Mat &mask1,
         float distThresh, Mat &frame0, Mat &mask0)
 {
+    CV_INSTRUMENT_REGION()
+
     CV_Assert(flowMask.type() == CV_8U);
     CV_Assert(flowX.type() == CV_32F && flowX.size() == flowMask.size());
     CV_Assert(flowY.type() == CV_32F && flowY.size() == flowMask.size());
diff --git a/modules/videostab/src/motion_stabilizing.cpp b/modules/videostab/src/motion_stabilizing.cpp
index 65bbd73..025b7d5 100644
--- a/modules/videostab/src/motion_stabilizing.cpp
+++ b/modules/videostab/src/motion_stabilizing.cpp
@@ -602,13 +602,12 @@ static inline bool isGoodMotion(const float M[], float w, float h, float dx, flo
 {
     Point2f pt[4] = {Point2f(0,0), Point2f(w,0), Point2f(w,h), Point2f(0,h)};
     Point2f Mpt[4];
-    float z;
 
     for (int i = 0; i < 4; ++i)
     {
         Mpt[i].x = M[0]*pt[i].x + M[1]*pt[i].y + M[2];
         Mpt[i].y = M[3]*pt[i].x + M[4]*pt[i].y + M[5];
-        z = M[6]*pt[i].x + M[7]*pt[i].y + M[8];
+        float z = M[6]*pt[i].x + M[7]*pt[i].y + M[8];
         Mpt[i].x /= z;
         Mpt[i].y /= z;
     }
@@ -638,6 +637,8 @@ static inline void relaxMotion(const float M[], float t, float res[])
 
 Mat ensureInclusionConstraint(const Mat &M, Size size, float trimRatio)
 {
+    CV_INSTRUMENT_REGION()
+
     CV_Assert(M.size() == Size(3,3) && M.type() == CV_32F);
 
     const float w = static_cast<float>(size.width);
@@ -673,6 +674,8 @@ Mat ensureInclusionConstraint(const Mat &M, Size size, float trimRatio)
 // TODO can be estimated for O(1) time
 float estimateOptimalTrimRatio(const Mat &M, Size size)
 {
+    CV_INSTRUMENT_REGION()
+
     CV_Assert(M.size() == Size(3,3) && M.type() == CV_32F);
 
     const float w = static_cast<float>(size.width);
diff --git a/modules/videostab/src/outlier_rejection.cpp b/modules/videostab/src/outlier_rejection.cpp
index ee37a93..0e9769c 100644
--- a/modules/videostab/src/outlier_rejection.cpp
+++ b/modules/videostab/src/outlier_rejection.cpp
@@ -51,6 +51,8 @@ namespace videostab
 void NullOutlierRejector::process(
         Size /*frameSize*/, InputArray points0, InputArray points1, OutputArray mask)
 {
+    CV_INSTRUMENT_REGION()
+
     CV_Assert(points0.type() == points1.type());
     CV_Assert(points0.getMat().checkVector(2) == points1.getMat().checkVector(2));
 
@@ -70,6 +72,8 @@ TranslationBasedLocalOutlierRejector::TranslationBasedLocalOutlierRejector()
 void TranslationBasedLocalOutlierRejector::process(
         Size frameSize, InputArray points0, InputArray points1, OutputArray mask)
 {
+    CV_INSTRUMENT_REGION()
+
     CV_Assert(points0.type() == points1.type());
     CV_Assert(points0.getMat().checkVector(2) == points1.getMat().checkVector(2));
 
@@ -84,16 +88,14 @@ void TranslationBasedLocalOutlierRejector::process(
     Size ncells((frameSize.width + cellSize_.width - 1) / cellSize_.width,
                 (frameSize.height + cellSize_.height - 1) / cellSize_.height);
 
-    int cx, cy;
-
     // fill grid cells
 
     grid_.assign(ncells.area(), Cell());
 
     for (int i = 0; i < npoints; ++i)
     {
-        cx = std::min(cvRound(points0_[i].x / cellSize_.width), ncells.width - 1);
-        cy = std::min(cvRound(points0_[i].y / cellSize_.height), ncells.height - 1);
+        int cx = std::min(cvRound(points0_[i].x / cellSize_.width), ncells.width - 1);
+        int cy = std::min(cvRound(points0_[i].y / cellSize_.height), ncells.height - 1);
         grid_[cy * ncells.width + cx].push_back(i);
     }
 
@@ -101,19 +103,16 @@ void TranslationBasedLocalOutlierRejector::process(
 
     RNG rng(0);
     int niters = ransacParams_.niters();
-    int ninliers, ninliersMax;
     std::vector<int> inliers;
-    float dx, dy, dxBest, dyBest;
-    float x1, y1;
-    int idx;
 
     for (size_t ci = 0; ci < grid_.size(); ++ci)
     {
         // estimate translation model at the current cell using RANSAC
 
+        float x1, y1;
         const Cell &cell = grid_[ci];
-        ninliersMax = 0;
-        dxBest = dyBest = 0.f;
+        int ninliers, ninliersMax = 0;
+        float dxBest = 0.f, dyBest = 0.f;
 
         // find the best hypothesis
 
@@ -121,9 +120,9 @@ void TranslationBasedLocalOutlierRejector::process(
         {
             for (int iter = 0; iter < niters; ++iter)
             {
-                idx = cell[static_cast<unsigned>(rng) % cell.size()];
-                dx = points1_[idx].x - points0_[idx].x;
-                dy = points1_[idx].y - points0_[idx].y;
+                int idx = cell[static_cast<unsigned>(rng) % cell.size()];
+                float dx = points1_[idx].x - points0_[idx].x;
+                float dy = points1_[idx].y - points0_[idx].y;
 
                 ninliers = 0;
                 for (size_t i = 0; i < cell.size(); ++i)
diff --git a/modules/viz/include/opencv2/viz.hpp b/modules/viz/include/opencv2/viz.hpp
index 3f8353e..b896ef7 100644
--- a/modules/viz/include/opencv2/viz.hpp
+++ b/modules/viz/include/opencv2/viz.hpp
@@ -43,8 +43,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_VIZ_HPP__
-#define __OPENCV_VIZ_HPP__
+#ifndef OPENCV_VIZ_HPP
+#define OPENCV_VIZ_HPP
 
 #include <opencv2/viz/types.hpp>
 #include <opencv2/viz/widgets.hpp>
@@ -81,4 +81,4 @@ cw.setColor(viz::Color::yellow());
   @}
 */
 
-#endif /* __OPENCV_VIZ_HPP__ */
+#endif /* OPENCV_VIZ_HPP */
diff --git a/modules/viz/include/opencv2/viz/types.hpp b/modules/viz/include/opencv2/viz/types.hpp
index 3c88fba..f485442 100644
--- a/modules/viz/include/opencv2/viz/types.hpp
+++ b/modules/viz/include/opencv2/viz/types.hpp
@@ -43,8 +43,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_VIZ_TYPES_HPP__
-#define __OPENCV_VIZ_TYPES_HPP__
+#ifndef OPENCV_VIZ_TYPES_HPP
+#define OPENCV_VIZ_TYPES_HPP
 
 #include <string>
 #include <opencv2/core.hpp>
diff --git a/modules/viz/include/opencv2/viz/viz3d.hpp b/modules/viz/include/opencv2/viz/viz3d.hpp
index 33c278e..86e4a38 100644
--- a/modules/viz/include/opencv2/viz/viz3d.hpp
+++ b/modules/viz/include/opencv2/viz/viz3d.hpp
@@ -43,8 +43,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_VIZ_VIZ3D_HPP__
-#define __OPENCV_VIZ_VIZ3D_HPP__
+#ifndef OPENCV_VIZ_VIZ3D_HPP
+#define OPENCV_VIZ_VIZ3D_HPP
 
 #if !defined YES_I_AGREE_THAT_VIZ_API_IS_NOT_STABLE_NOW_AND_BINARY_COMPARTIBILITY_WONT_BE_SUPPORTED && !defined CVAPI_EXPORTS
     //#error "Viz is in beta state now. Please define macro above to use it"
diff --git a/modules/viz/include/opencv2/viz/vizcore.hpp b/modules/viz/include/opencv2/viz/vizcore.hpp
index 76f1ba2..c32802c 100644
--- a/modules/viz/include/opencv2/viz/vizcore.hpp
+++ b/modules/viz/include/opencv2/viz/vizcore.hpp
@@ -43,8 +43,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_VIZCORE_HPP__
-#define __OPENCV_VIZCORE_HPP__
+#ifndef OPENCV_VIZCORE_HPP
+#define OPENCV_VIZCORE_HPP
 
 #include <opencv2/viz/types.hpp>
 #include <opencv2/viz/widgets.hpp>
@@ -173,4 +173,4 @@ namespace cv
     } /* namespace viz */
 } /* namespace cv */
 
-#endif /* __OPENCV_VIZCORE_HPP__ */
+#endif /* OPENCV_VIZCORE_HPP */
diff --git a/modules/viz/include/opencv2/viz/widget_accessor.hpp b/modules/viz/include/opencv2/viz/widget_accessor.hpp
index ccc5b28..7b4be54 100644
--- a/modules/viz/include/opencv2/viz/widget_accessor.hpp
+++ b/modules/viz/include/opencv2/viz/widget_accessor.hpp
@@ -43,8 +43,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_VIZ_WIDGET_ACCESSOR_HPP__
-#define __OPENCV_VIZ_WIDGET_ACCESSOR_HPP__
+#ifndef OPENCV_VIZ_WIDGET_ACCESSOR_HPP
+#define OPENCV_VIZ_WIDGET_ACCESSOR_HPP
 
 #include <opencv2/core/cvdef.h>
 #include <vtkSmartPointer.h>
diff --git a/modules/viz/include/opencv2/viz/widgets.hpp b/modules/viz/include/opencv2/viz/widgets.hpp
index fde4fc2..dc05d77 100644
--- a/modules/viz/include/opencv2/viz/widgets.hpp
+++ b/modules/viz/include/opencv2/viz/widgets.hpp
@@ -43,8 +43,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_VIZ_WIDGETS_HPP__
-#define __OPENCV_VIZ_WIDGETS_HPP__
+#ifndef OPENCV_VIZ_WIDGETS_HPP
+#define OPENCV_VIZ_WIDGETS_HPP
 
 #include <opencv2/viz/types.hpp>
 
@@ -67,7 +67,8 @@ namespace cv
             REPRESENTATION,
             IMMEDIATE_RENDERING,
             SHADING,
-            AMBIENT
+            AMBIENT,
+            LIGHTING
         };
 
         enum RepresentationValues
diff --git a/modules/viz/src/precomp.hpp b/modules/viz/src/precomp.hpp
index 9af052a..369db19 100644
--- a/modules/viz/src/precomp.hpp
+++ b/modules/viz/src/precomp.hpp
@@ -282,7 +282,7 @@ namespace cv
                 scalars->SetName("Colors");
                 scalars->SetNumberOfComponents(3);
                 scalars->SetNumberOfTuples((vtkIdType)size);
-                scalars->SetArray(color_data->val, (vtkIdType)(size * 3), 0);
+                scalars->SetArray(color_data->val, (vtkIdType)(size * 3), 0, vtkUnsignedCharArray::VTK_DATA_ARRAY_DELETE);
                 return scalars;
             }
 
diff --git a/modules/viz/src/vtk/vtkCloudMatSink.cpp b/modules/viz/src/vtk/vtkCloudMatSink.cpp
index 8bd1011..aa3d34c 100644
--- a/modules/viz/src/vtk/vtkCloudMatSink.cpp
+++ b/modules/viz/src/vtk/vtkCloudMatSink.cpp
@@ -42,7 +42,7 @@
 //
 //M*/
 
-#include "precomp.hpp"
+#include "../precomp.hpp"
 
 namespace cv { namespace viz
 {
diff --git a/modules/viz/src/vtk/vtkCloudMatSource.cpp b/modules/viz/src/vtk/vtkCloudMatSource.cpp
index 1d8ab78..e0e7a82 100644
--- a/modules/viz/src/vtk/vtkCloudMatSource.cpp
+++ b/modules/viz/src/vtk/vtkCloudMatSource.cpp
@@ -42,7 +42,7 @@
 //
 //M*/
 
-#include "precomp.hpp"
+#include "../precomp.hpp"
 
 namespace cv { namespace viz
 {
@@ -235,7 +235,7 @@ void cv::viz::vtkCloudMatSource::filterNanColorsCopy(const Mat& cloud_colors, co
     scalars->SetName("Colors");
     scalars->SetNumberOfComponents(3);
     scalars->SetNumberOfTuples(total);
-    scalars->SetArray(array->val, total * 3, 0);
+    scalars->SetArray(array->val, total * 3, 0, vtkUnsignedCharArray::VTK_DATA_ARRAY_DELETE);
 }
 
 template<typename _Tn, typename _Msk>
diff --git a/modules/viz/src/vtk/vtkCocoaInteractorFix.mm b/modules/viz/src/vtk/vtkCocoaInteractorFix.mm
index 481baf9..99e3c0d 100644
--- a/modules/viz/src/vtk/vtkCocoaInteractorFix.mm
+++ b/modules/viz/src/vtk/vtkCocoaInteractorFix.mm
@@ -1,54 +1,48 @@
 /*M///////////////////////////////////////////////////////////////////////////////////////
- //
- //  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
- //
- //  By downloading, copying, installing or using the software you agree to this license.
- //  If you do not agree to this license, do not download, install,
- //  copy or use the software.
- //
- //
- //                           License Agreement
- //                For Open Source Computer Vision Library
- //
- // Copyright (C) 2013, OpenCV Foundation, all rights reserved.
- // Third party copyrights are property of their respective owners.
- //
- // Redistribution and use in source and binary forms, with or without modification,
- // are permitted provided that the following conditions are met:
- //
- //   * Redistribution's of source code must retain the above copyright notice,
- //     this list of conditions and the following disclaimer.
- //
- //   * Redistribution's in binary form must reproduce the above copyright notice,
- //     this list of conditions and the following disclaimer in the documentation
- //     and/or other materials provided with the distribution.
- //
- //   * The name of the copyright holders may not be used to endorse or promote products
- //     derived from this software without specific prior written permission.
- //
- // This software is provided by the copyright holders and contributors "as is" and
- // any express or implied warranties, including, but not limited to, the implied
- // warranties of merchantability and fitness for a particular purpose are disclaimed.
- // In no event shall the Intel Corporation or contributors be liable for any direct,
- // indirect, incidental, special, exemplary, or consequential damages
- // (including, but not limited to, procurement of substitute goods or services;
- // loss of use, data, or profits; or business interruption) however caused
- // and on any theory of liability, whether in contract, strict liability,
- // or tort (including negligence or otherwise) arising in any way out of
- // the use of this software, even if advised of the possibility of such damage.
- //
- // Authors:
- //  * Anatoly Baksheev, Itseez Inc.  myname.mysurname <> mycompany.com
- //
- //  This workaround code was taken from PCL library(www.pointclouds.org)
- //
- //  Modified by Jasper Shemilt to work with VTK 6.2
- //  The fix was needed because GetCocoaServer has been moved from
- //  vtkCocoaRenderWindowInteractor to vtkCocoaRenderWindow in VTK 6.2.
- //  This alteration to VTK happened almost a year ago according to the gitHub
- //  commit a3e9fc9.
- //
- //M*/
+//
+//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+//  By downloading, copying, installing or using the software you agree to this license.
+//  If you do not agree to this license, do not download, install,
+//  copy or use the software.
+//
+//
+//                           License Agreement
+//                For Open Source Computer Vision Library
+//
+// Copyright (C) 2013, OpenCV Foundation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+//   * Redistribution's of source code must retain the above copyright notice,
+//     this list of conditions and the following disclaimer.
+//
+//   * Redistribution's in binary form must reproduce the above copyright notice,
+//     this list of conditions and the following disclaimer in the documentation
+//     and/or other materials provided with the distribution.
+//
+//   * The name of the copyright holders may not be used to endorse or promote products
+//     derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+// Authors:
+//  * Anatoly Baksheev, Itseez Inc.  myname.mysurname <> mycompany.com
+//
+//  This workaround code was taken from PCL library(www.pointclouds.org)
+//
+//M*/
 
 #import <Cocoa/Cocoa.h>
 #include <vtkCocoaRenderWindow.h>
@@ -56,6 +50,13 @@
 #include <vtkObjectFactory.h>
 #include <vtkSmartPointer.h>
 
+namespace cv { namespace viz {
+    vtkSmartPointer<vtkRenderWindowInteractor> vtkCocoaRenderWindowInteractorNew();
+}} // namespace
+
+#if ((VTK_MAJOR_VERSION < 6) || ((VTK_MAJOR_VERSION == 6) && (VTK_MINOR_VERSION < 2)))
+
+
 //----------------------------------------------------------------------------
 @interface vtkCocoaServerFix : NSObject
 {
@@ -124,14 +125,14 @@
     [application stop:application];
 
     NSEvent *event = [NSEvent otherEventWithType:NSApplicationDefined
-                                        location:NSMakePoint(0.0,0.0)
-                                   modifierFlags:0
-                                       timestamp:0
-                                    windowNumber:-1
-                                         context:nil
-                                         subtype:0
-                                           data1:0
-                                           data2:0];
+            location:NSMakePoint(0.0,0.0)
+            modifierFlags:0
+            timestamp:0
+            windowNumber:-1
+            context:nil
+            subtype:0
+            data1:0
+            data2:0];
     [application postEvent:event atStart:YES];
 }
 
@@ -160,121 +161,28 @@
 
 //----------------------------------------------------------------------------
 
-#if VTK_MAJOR_VERSION >= 6 && VTK_MINOR_VERSION  >=2
-
 namespace cv { namespace viz
-    {
-        class vtkCocoaRenderWindowInteractorFix : public vtkCocoaRenderWindowInteractor
-        {
-        public:
-            static vtkCocoaRenderWindowInteractorFix *New ();
-            vtkTypeMacro (vtkCocoaRenderWindowInteractorFix, vtkCocoaRenderWindowInteractor)
-
-            virtual void Start ();
-            virtual void TerminateApp ();
-
-        protected:
-            vtkCocoaRenderWindowInteractorFix () {}
-            ~vtkCocoaRenderWindowInteractorFix () {}
-
-        private:
-            vtkCocoaRenderWindowInteractorFix (const vtkCocoaRenderWindowInteractorFix&);  // Not implemented.
-            void operator = (const vtkCocoaRenderWindowInteractorFix&);  // Not implemented.
-        };
-
-        vtkStandardNewMacro (vtkCocoaRenderWindowInteractorFix)
-
-        vtkSmartPointer<vtkRenderWindowInteractor> vtkCocoaRenderWindowInteractorNew();
-
-        class vtkCocoaRenderWindowFix : public vtkCocoaRenderWindow
-        {
-        public:
-            static vtkCocoaRenderWindowFix *New ();
-            vtkTypeMacro ( vtkCocoaRenderWindowFix, vtkCocoaRenderWindow)
-
-            virtual vtkCocoaServerFix * GetCocoaServer ();
-            virtual void SetCocoaServer (void* );
-
-        protected:
-            vtkCocoaRenderWindowFix () {}
-            ~vtkCocoaRenderWindowFix () {}
-
-        private:
-            vtkCocoaRenderWindowFix (const vtkCocoaRenderWindowInteractorFix&);  // Not implemented.
-            void operator = (const vtkCocoaRenderWindowFix&);  // Not implemented.
-        };
-
-        vtkStandardNewMacro (vtkCocoaRenderWindowFix)
-
-        vtkSmartPointer<vtkRenderWindow> vtkCocoaRenderWindowNew();
-    }}
-
-vtkCocoaServerFix * cv::viz::vtkCocoaRenderWindowFix::GetCocoaServer ()
-{
-    return reinterpret_cast<vtkCocoaServerFix*> (this->GetCocoaServer ());
-}
-
-void cv::viz::vtkCocoaRenderWindowFix::SetCocoaServer (void* server)
-{
-    this->SetCocoaServer (server);
-}
-
-void cv::viz::vtkCocoaRenderWindowInteractorFix::Start ()
-{
-    vtkCocoaRenderWindowFix* renWin = vtkCocoaRenderWindowFix::SafeDownCast(this->GetRenderWindow ());
-    if (renWin != NULL)
-    {
-        vtkCocoaServerFix *server = reinterpret_cast<vtkCocoaServerFix*> (renWin->GetCocoaServer ());
-        if (!renWin->GetCocoaServer ())
-        {
-            server = [vtkCocoaServerFix cocoaServerWithRenderWindow:renWin];
-            renWin->SetCocoaServer (reinterpret_cast<void*> (server));
-        }
-
-        [server start];
-    }
-}
-
-void cv::viz::vtkCocoaRenderWindowInteractorFix::TerminateApp ()
-{
-    vtkCocoaRenderWindowFix *renWin = vtkCocoaRenderWindowFix::SafeDownCast (this->RenderWindow);
-    if (renWin)
-    {
-        vtkCocoaServerFix *server = reinterpret_cast<vtkCocoaServerFix*> (renWin->GetCocoaServer ());
-        [server stop];
-    }
-}
-
-vtkSmartPointer<vtkRenderWindowInteractor> cv::viz::vtkCocoaRenderWindowInteractorNew()
 {
-    return vtkSmartPointer<vtkCocoaRenderWindowInteractorFix>::New();
-}
-
-#else
-namespace cv { namespace viz
+    class vtkCocoaRenderWindowInteractorFix : public vtkCocoaRenderWindowInteractor
     {
-        class vtkCocoaRenderWindowInteractorFix : public vtkCocoaRenderWindowInteractor
-        {
-        public:
-            static vtkCocoaRenderWindowInteractorFix *New ();
-            vtkTypeMacro (vtkCocoaRenderWindowInteractorFix, vtkCocoaRenderWindowInteractor)
-
-            virtual void Start ();
-            virtual void TerminateApp ();
+    public:
+        static vtkCocoaRenderWindowInteractorFix *New ();
+        vtkTypeMacro (vtkCocoaRenderWindowInteractorFix, vtkCocoaRenderWindowInteractor)
 
-        protected:
-            vtkCocoaRenderWindowInteractorFix () {}
-            ~vtkCocoaRenderWindowInteractorFix () {}
+        virtual void Start ();
+        virtual void TerminateApp ();
 
-        private:
-            vtkCocoaRenderWindowInteractorFix (const vtkCocoaRenderWindowInteractorFix&);  // Not implemented.
-            void operator = (const vtkCocoaRenderWindowInteractorFix&);  // Not implemented.
-        };
+    protected:
+        vtkCocoaRenderWindowInteractorFix () {}
+        ~vtkCocoaRenderWindowInteractorFix () {}
 
-        vtkStandardNewMacro (vtkCocoaRenderWindowInteractorFix)
+    private:
+        vtkCocoaRenderWindowInteractorFix (const vtkCocoaRenderWindowInteractorFix&);  // Not implemented.
+        void operator = (const vtkCocoaRenderWindowInteractorFix&);  // Not implemented.
+    };
 
-        vtkSmartPointer<vtkRenderWindowInteractor> vtkCocoaRenderWindowInteractorNew();
-    }}
+    vtkStandardNewMacro (vtkCocoaRenderWindowInteractorFix)
+}}
 
 void cv::viz::vtkCocoaRenderWindowInteractorFix::Start ()
 {
@@ -307,4 +215,12 @@ vtkSmartPointer<vtkRenderWindowInteractor> cv::viz::vtkCocoaRenderWindowInteract
     return vtkSmartPointer<vtkCocoaRenderWindowInteractorFix>::New();
 }
 
+
+#else
+
+vtkSmartPointer<vtkRenderWindowInteractor> cv::viz::vtkCocoaRenderWindowInteractorNew()
+{
+    return vtkSmartPointer<vtkCocoaRenderWindowInteractor>::New();
+}
+
 #endif
diff --git a/modules/viz/src/vtk/vtkImageMatSource.cpp b/modules/viz/src/vtk/vtkImageMatSource.cpp
index 6586175..d9de698 100644
--- a/modules/viz/src/vtk/vtkImageMatSource.cpp
+++ b/modules/viz/src/vtk/vtkImageMatSource.cpp
@@ -42,7 +42,7 @@
 //
 //M*/
 
-#include "precomp.hpp"
+#include "../precomp.hpp"
 
 namespace cv { namespace viz
 {
diff --git a/modules/viz/src/vtk/vtkImageMatSource.h b/modules/viz/src/vtk/vtkImageMatSource.h
index db0c093..a7a41e0 100644
--- a/modules/viz/src/vtk/vtkImageMatSource.h
+++ b/modules/viz/src/vtk/vtkImageMatSource.h
@@ -42,7 +42,7 @@
 //
 //M*/
 
-#include "precomp.hpp"
+#include "../precomp.hpp"
 
 #ifndef __vtkImageMatSource_h
 #define __vtkImageMatSource_h
diff --git a/modules/viz/src/vtk/vtkOBJWriter.cpp b/modules/viz/src/vtk/vtkOBJWriter.cpp
index 7480b11..296b6eb 100644
--- a/modules/viz/src/vtk/vtkOBJWriter.cpp
+++ b/modules/viz/src/vtk/vtkOBJWriter.cpp
@@ -42,7 +42,7 @@
 //
 //M*/
 
-#include "precomp.hpp"
+#include "../precomp.hpp"
 
 namespace cv { namespace viz
 {
diff --git a/modules/viz/src/vtk/vtkTrajectorySource.cpp b/modules/viz/src/vtk/vtkTrajectorySource.cpp
index 2036e09..d0e180a 100644
--- a/modules/viz/src/vtk/vtkTrajectorySource.cpp
+++ b/modules/viz/src/vtk/vtkTrajectorySource.cpp
@@ -42,7 +42,7 @@
 //
 //M*/
 
-#include "precomp.hpp"
+#include "../precomp.hpp"
 
 namespace cv { namespace viz
 {
diff --git a/modules/viz/src/vtk/vtkVizInteractorStyle.cpp b/modules/viz/src/vtk/vtkVizInteractorStyle.cpp
index 9b5eca2..e2d3380 100644
--- a/modules/viz/src/vtk/vtkVizInteractorStyle.cpp
+++ b/modules/viz/src/vtk/vtkVizInteractorStyle.cpp
@@ -43,7 +43,7 @@
 //
 //M*/
 
-#include "precomp.hpp"
+#include "../precomp.hpp"
 
 namespace cv { namespace viz
 {
diff --git a/modules/viz/src/vtk/vtkXYZReader.cpp b/modules/viz/src/vtk/vtkXYZReader.cpp
index 283a592..57726ea 100644
--- a/modules/viz/src/vtk/vtkXYZReader.cpp
+++ b/modules/viz/src/vtk/vtkXYZReader.cpp
@@ -42,7 +42,7 @@
 //
 //M*/
 
-#include "precomp.hpp"
+#include "../precomp.hpp"
 
 namespace cv { namespace viz
 {
diff --git a/modules/viz/src/vtk/vtkXYZWriter.cpp b/modules/viz/src/vtk/vtkXYZWriter.cpp
index 5a3d7d5..cf95e3c 100644
--- a/modules/viz/src/vtk/vtkXYZWriter.cpp
+++ b/modules/viz/src/vtk/vtkXYZWriter.cpp
@@ -42,7 +42,7 @@
 //
 //M*/
 
-#include "precomp.hpp"
+#include "../precomp.hpp"
 
 namespace cv { namespace viz
 {
diff --git a/modules/viz/src/widget.cpp b/modules/viz/src/widget.cpp
index 698f21c..3423ba8 100644
--- a/modules/viz/src/widget.cpp
+++ b/modules/viz/src/widget.cpp
@@ -115,6 +115,14 @@ void cv::viz::Widget::setRenderingProperty(int property, double value)
         case LINE_WIDTH:          actor->GetProperty()->SetLineWidth(float(value)); break;
         case IMMEDIATE_RENDERING: actor->GetMapper()->SetImmediateModeRendering(int(value)); break;
         case AMBIENT:             actor->GetProperty()->SetAmbient(float(value)); break;
+        case LIGHTING:
+        {
+            if (value == 0)
+                actor->GetProperty()->LightingOff();
+            else
+                actor->GetProperty()->LightingOn();
+            break;
+        }
         case FONT_SIZE:
         {
             vtkTextActor* text_actor = vtkTextActor::SafeDownCast(actor);
diff --git a/modules/world/CMakeLists.txt b/modules/world/CMakeLists.txt
index 7783151..db8928d 100644
--- a/modules/world/CMakeLists.txt
+++ b/modules/world/CMakeLists.txt
@@ -14,19 +14,20 @@ function(include_one_module m)
 endfunction()
 
 if(NOT OPENCV_INITIAL_PASS)
+  set(ENABLE_PRECOMPILED_HEADERS OFF CACHE INTERNAL "" FORCE)
   project(opencv_world)
 
   message(STATUS "Processing WORLD modules...")
   foreach(m ${OPENCV_MODULES_BUILD})
     if(OPENCV_MODULE_${m}_IS_PART_OF_WORLD)
       message(STATUS "    module ${m}...")
-      set(CMAKE_CURRENT_SOURCE_DIR ${OPENCV_MODULE_${m}_LOCATION})
+      set(CMAKE_CURRENT_SOURCE_DIR "${OPENCV_MODULE_${m}_LOCATION}")
       #add_subdirectory("${OPENCV_MODULE_${m}_LOCATION}" ${CMAKE_CURRENT_BINARY_DIR}/${m})
       include_one_module(${m})
     endif()
   endforeach()
   message(STATUS "Processing WORLD modules... DONE")
-  set(CMAKE_CURRENT_SOURCE_DIR OPENCV_MODULE_${opencv_world}_LOCATION)
+  set(CMAKE_CURRENT_SOURCE_DIR "${OPENCV_MODULE_opencv_world_LOCATION}")
 endif()
 
 ocv_add_module(world opencv_core)
diff --git a/modules/world/include/opencv2/world.hpp b/modules/world/include/opencv2/world.hpp
index 2442f2c..4902c2f 100644
--- a/modules/world/include/opencv2/world.hpp
+++ b/modules/world/include/opencv2/world.hpp
@@ -40,8 +40,8 @@
 //
 //M*/
 
-#ifndef __OPENCV_WORLD_HPP__
-#define __OPENCV_WORLD_HPP__
+#ifndef OPENCV_WORLD_HPP
+#define OPENCV_WORLD_HPP
 
 #include "opencv2/core.hpp"
 
diff --git a/platforms/android/android.toolchain.cmake b/platforms/android/android.toolchain.cmake
index 6dca10d..1d69b75 100644
--- a/platforms/android/android.toolchain.cmake
+++ b/platforms/android/android.toolchain.cmake
@@ -155,6 +155,10 @@
 #                          Implies -frtti -fno-exceptions.
 #                          Available for NDK r7b and newer.
 #                          Silently degrades to gnustl_static if not available.
+#        c++_static     -> Use the LLVM libc++ runtime as a static library.
+#                          Implies -frtti -fexceptions.
+#        c++_shared     -> Use the LLVM libc++ runtime as a static library.
+#                          Implies -frtti -fno-exceptions.
 #
 #    ANDROID_STL_FORCE_FEATURES=ON - turn rtti and exceptions support based on
 #      chosen runtime. If disabled, then the user is responsible for settings
@@ -240,7 +244,7 @@ set( ANDROID_SUPPORTED_ABIS_mips "mips" )
 set( ANDROID_SUPPORTED_ABIS_mips64 "mips64" )
 
 # API level defaults
-set( ANDROID_DEFAULT_NDK_API_LEVEL 8 )
+set( ANDROID_DEFAULT_NDK_API_LEVEL 9 )
 set( ANDROID_DEFAULT_NDK_API_LEVEL_arm64 21 )
 set( ANDROID_DEFAULT_NDK_API_LEVEL_x86 9 )
 set( ANDROID_DEFAULT_NDK_API_LEVEL_x86_64 21 )
@@ -842,7 +846,7 @@ set( ANDROID_STL_FORCE_FEATURES ON CACHE BOOL "automatically configure rtti and
 mark_as_advanced( ANDROID_STL ANDROID_STL_FORCE_FEATURES )
 
 if( BUILD_WITH_ANDROID_NDK )
- if( NOT "${ANDROID_STL}" MATCHES "^(none|system|system_re|gabi\\+\\+_static|gabi\\+\\+_shared|stlport_static|stlport_shared|gnustl_static|gnustl_shared)$")
+ if( NOT "${ANDROID_STL}" MATCHES "^(none|system|system_re|gabi\\+\\+_static|gabi\\+\\+_shared|stlport_static|stlport_shared|gnustl_static|gnustl_shared|c\\+\\+_static|c\\+\\+_shared)$")
   message( FATAL_ERROR "ANDROID_STL is set to invalid value \"${ANDROID_STL}\".
 The possible values are:
   none           -> Do not configure the runtime.
@@ -854,15 +858,19 @@ The possible values are:
   stlport_shared -> Use the STLport runtime as a shared library.
   gnustl_static  -> (default) Use the GNU STL as a static library.
   gnustl_shared  -> Use the GNU STL as a shared library.
+  c++_shared     -> Use the LLVM libc++ runtime as a shared library.
+  c++_static     -> Use the LLVM libc++ runtime as a static library.
 " )
  endif()
 elseif( BUILD_WITH_STANDALONE_TOOLCHAIN )
- if( NOT "${ANDROID_STL}" MATCHES "^(none|gnustl_static|gnustl_shared)$")
+ if( NOT "${ANDROID_STL}" MATCHES "^(none|gnustl_static|gnustl_shared|c\\+\\+_static|c\\+\\+_shared)$")
   message( FATAL_ERROR "ANDROID_STL is set to invalid value \"${ANDROID_STL}\".
 The possible values are:
   none           -> Do not configure the runtime.
   gnustl_static  -> (default) Use the GNU STL as a static library.
   gnustl_shared  -> Use the GNU STL as a shared library.
+  c++_shared     -> Use the LLVM libc++ runtime as a shared library.
+  c++_static     -> Use the LLVM libc++ runtime as a static library.
 " )
  endif()
 endif()
@@ -1035,9 +1043,16 @@ if( BUILD_WITH_ANDROID_NDK )
   else()
    set( __libstl                "${__libstl}/libs/${ANDROID_NDK_ABI_NAME}/libstdc++.a" )
   endif()
+ elseif( ANDROID_STL MATCHES "c\\+\\+" )
+  set( ANDROID_EXCEPTIONS       ON )
+  set( ANDROID_RTTI             ON )
+  set( __libstl                "${ANDROID_NDK}/sources/cxx-stl/llvm-libc++" )
+  set( __libstl                "${__libstl}/libs/${ANDROID_NDK_ABI_NAME}/libc++_static.a" )
+  set( ANDROID_STL_INCLUDE_DIRS "${ANDROID_NDK}/sources/android/support/include" "${ANDROID_NDK}/sources/cxx-stl/llvm-libc++/libcxx/include" "${ANDROID_NDK}/sources/cxx-stl/llvm-libc++abi/libcxxabi/include" )
  else()
   message( FATAL_ERROR "Unknown runtime: ${ANDROID_STL}" )
  endif()
+
  # find libsupc++.a - rtti & exceptions
  if( ANDROID_STL STREQUAL "system_re" OR ANDROID_STL MATCHES "gnustl" )
   set( __libsupcxx "${ANDROID_NDK}/sources/cxx-stl/gnu-libstdc++/${ANDROID_COMPILER_VERSION}/libs/${ANDROID_NDK_ABI_NAME}/libsupc++.a" ) # r8b or newer
@@ -1067,7 +1082,9 @@ endif()
 # case of shared STL linkage
 if( ANDROID_STL MATCHES "shared" AND DEFINED __libstl )
  string( REPLACE "_static.a" "_shared.so" __libstl "${__libstl}" )
- # TODO: check if .so file exists before the renaming
+ if( NOT EXISTS "${__libstl}" )
+   message( FATAL_ERROR "Unable to find shared library ${__libstl}" )
+ endif()
 endif()
 
 
diff --git a/platforms/android/build-tests/test_cmake_build.py b/platforms/android/build-tests/test_cmake_build.py
index 0e84928..f02915c 100644
--- a/platforms/android/build-tests/test_cmake_build.py
+++ b/platforms/android/build-tests/test_cmake_build.py
@@ -2,6 +2,9 @@
 
 import unittest
 import os, sys, subprocess, argparse, shutil, re
+import logging as log
+
+log.basicConfig(format='%(message)s', level=log.DEBUG)
 
 CMAKE_TEMPLATE='''\
 CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
@@ -83,10 +86,12 @@ class TestCmakeBuild(unittest.TestCase):
             "-DANDROID_TOOLCHAIN_NAME=%s" % self.toolchain,
             self.srcdir
         ]
+        log.info("Executing: %s" % cmd)
         retcode = subprocess.call(cmd)
         self.assertEqual(retcode, 0, "cmake failed")
 
         cmd = ["ninja"]
+        log.info("Executing: %s" % cmd)
         retcode = subprocess.call(cmd)
         self.assertEqual(retcode, 0, "make failed")
 
diff --git a/platforms/android/build_sdk.py b/platforms/android/build_sdk.py
index f262a45..e78e3b9 100755
--- a/platforms/android/build_sdk.py
+++ b/platforms/android/build_sdk.py
@@ -73,8 +73,7 @@ class ABI:
     def __str__(self):
         return "%s (%s)" % (self.name, self.toolchain)
     def haveIPP(self):
-        return False
-        # return self.name == "x86" or self.name == "x86_64"
+        return self.name == "x86" or self.name == "x86_64"
 
 ABIs = [
     ABI("2", "armeabi-v7a", "arm-linux-androideabi-4.8", cmake_name="armeabi-v7a with NEON"),
@@ -92,6 +91,7 @@ class Builder:
     def __init__(self, workdir, opencvdir):
         self.workdir = check_dir(workdir, create=True)
         self.opencvdir = check_dir(opencvdir)
+        self.extra_modules_path = None
         self.libdest = check_dir(os.path.join(self.workdir, "o4a"), create=True, clean=True)
         self.docdest = check_dir(os.path.join(self.workdir, "javadoc"), create=True, clean=True)
         self.resultdest = check_dir(os.path.join(self.workdir, "OpenCV-android-sdk"), create=True, clean=True)
@@ -130,14 +130,19 @@ class Builder:
             "-DBUILD_ANDROID_EXAMPLES=ON",
             "-DINSTALL_ANDROID_EXAMPLES=ON",
             "-DANDROID_STL=gnustl_static",
-            "-DANDROID_NATIVE_API_LEVEL=8",
+            "-DANDROID_NATIVE_API_LEVEL=9",
             "-DANDROID_ABI='%s'" % abi.cmake_name,
             "-DWITH_TBB=ON",
-            "-DANDROID_TOOLCHAIN_NAME=%s" % abi.toolchain,
-            self.opencvdir
+            "-DANDROID_TOOLCHAIN_NAME=%s" % abi.toolchain
         ]
+
+        if self.extra_modules_path is not None:
+            cmd.append("-DOPENCV_EXTRA_MODULES_PATH='%s'" % self.extra_modules_path)
+
+        cmd.append(self.opencvdir)
+
         if self.use_ccache == True:
-            cmd.extend(["-DNDK_CCACHE=ccache", "-DENABLE_PRECOMPILED_HEADERS=OFF"])
+            cmd.append("-DNDK_CCACHE=ccache")
         if do_install:
             cmd.extend(["-DBUILD_TESTS=ON", "-DINSTALL_TESTS=ON"])
         execute(cmd)
@@ -166,7 +171,7 @@ class Builder:
         # Add extra data
         apkxmldest = check_dir(os.path.join(apkdest, "res", "xml"), create=True)
         apklibdest = check_dir(os.path.join(apkdest, "libs", abi.name), create=True)
-        for ver, d in self.extra_packs + [("3.1.0", os.path.join(self.libdest, "lib"))]:
+        for ver, d in self.extra_packs + [("3.2.0", os.path.join(self.libdest, "lib"))]:
             r = ET.Element("library", attrib={"version": ver})
             log.info("Adding libraries from %s", d)
 
@@ -232,15 +237,6 @@ class Builder:
         log.info("Copy docs: %s", self.docdest)
         shutil.copytree(self.docdest, os.path.join(self.resultdest, "sdk", "java", "javadoc"))
 
-        # Patch cmake config
-        with open(os.path.join(self.resultdest, "sdk", "native", "jni", "OpenCVConfig.cmake"), "r+t") as f:
-            contents = f.read()
-            contents, count = re.subn(r'OpenCV_ANDROID_NATIVE_API_LEVEL \d+', "OpenCV_ANDROID_NATIVE_API_LEVEL 8", contents)
-            f.seek(0)
-            f.write(contents)
-            f.truncate()
-            log.info("Patch cmake config: %s (%d changes)", f.name, count)
-
         # Clean samples
         path = os.path.join(self.resultdest, "samples")
         for item in os.listdir(path):
@@ -258,6 +254,7 @@ if __name__ == "__main__":
     parser.add_argument("opencv_dir", help="Path to OpenCV source dir")
     parser.add_argument('--ndk_path', help="Path to Android NDK to use for build")
     parser.add_argument('--sdk_path', help="Path to Android SDK to use for build")
+    parser.add_argument("--extra_modules_path", help="Path to extra modules to use for build")
     parser.add_argument('--sign_with', help="Sertificate to sign the Manager apk")
     parser.add_argument('--build_doc', action="store_true", help="Build javadoc")
     parser.add_argument('--no_ccache', action="store_true", help="Do not use ccache during library build")
@@ -277,6 +274,9 @@ if __name__ == "__main__":
 
     builder = Builder(args.work_dir, args.opencv_dir)
 
+    if args.extra_modules_path is not None:
+        builder.extra_modules_path = os.path.abspath(args.extra_modules_path)
+
     if args.no_ccache:
         builder.use_ccache = False
 
diff --git a/platforms/android/service/engine/AndroidManifest.xml b/platforms/android/service/engine/AndroidManifest.xml
index ef1cab2..6c90858 100644
--- a/platforms/android/service/engine/AndroidManifest.xml
+++ b/platforms/android/service/engine/AndroidManifest.xml
@@ -1,8 +1,8 @@
 <?xml version="1.0" encoding="utf-8"?>
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="org.opencv.engine"
-    android:versionCode="310 at ANDROID_PLATFORM_ID@"
-    android:versionName="3.10">
+    android:versionCode="320 at ANDROID_PLATFORM_ID@"
+    android:versionName="3.20">
 
     <uses-sdk android:minSdkVersion="@ANDROID_NATIVE_API_LEVEL@" android:targetSdkVersion="22"/>
     <uses-feature android:name="android.hardware.touchscreen" android:required="false"/>
diff --git a/platforms/android/service/engine/src/org/opencv/engine/OpenCVEngineService.java b/platforms/android/service/engine/src/org/opencv/engine/OpenCVEngineService.java
index 917a641..c604fa9 100644
--- a/platforms/android/service/engine/src/org/opencv/engine/OpenCVEngineService.java
+++ b/platforms/android/service/engine/src/org/opencv/engine/OpenCVEngineService.java
@@ -134,7 +134,7 @@ public class OpenCVEngineService extends Service {
 
             @Override
             public int getEngineVersion() throws RemoteException {
-                int version = 3100;
+                int version = 3200;
                 try {
                     version = getPackageManager().getPackageInfo(getPackageName(), 0).versionCode;
                 } catch (NameNotFoundException e) {
diff --git a/platforms/android/service/readme.txt b/platforms/android/service/readme.txt
index 82cac62..f7e886a 100644
--- a/platforms/android/service/readme.txt
+++ b/platforms/android/service/readme.txt
@@ -10,14 +10,16 @@ from Google Play.
 If Google Play is not available (i.e. on emulator, developer board, etc), you can install it
 manually using adb tool:
 
-    adb install <path-to-OpenCV-sdk>/apk/OpenCV_3.1.0_Manager_3.10_<platform>.apk
+    adb install <path-to-OpenCV-sdk>/apk/OpenCV_<version>_Manager_<app_version>_<platform>.apk
 
-Use the list below to determine proper OpenCV Manager package for your device:
+Example: OpenCV_3.2.0-dev_Manager_3.20_armeabi-v7a.apk
 
-- OpenCV_3.1.0-dev_Manager_3.10_armeabi.apk - armeabi (ARMv5, ARMv6)
-- OpenCV_3.1.0-dev_Manager_3.10_armeabi-v7a.apk - armeabi-v7a (ARMv7-A + NEON)
-- OpenCV_3.1.0-dev_Manager_3.10_arm64-v8a.apk - arm64-v8a (ARM64-v8a)
-- OpenCV_3.1.0-dev_Manager_3.10_mips.apk - mips (MIPS)
-- OpenCV_3.1.0-dev_Manager_3.10_mips64.apk - mips64 (MIPS64)
-- OpenCV_3.1.0-dev_Manager_3.10_x86.apk - x86
-- OpenCV_3.1.0-dev_Manager_3.10_x86_64.apk - x86_64
+Use the list of platforms below to determine proper OpenCV Manager package for your device:
+
+- armeabi (ARMv5, ARMv6)
+- armeabi-v7a (ARMv7-A + NEON)
+- arm64-v8a
+- mips
+- mips64
+- x86
+- x86_64
diff --git a/platforms/ios/build_framework.py b/platforms/ios/build_framework.py
index 2a8dc7e..f8886b6 100644
--- a/platforms/ios/build_framework.py
+++ b/platforms/ios/build_framework.py
@@ -43,7 +43,7 @@ def getXCodeMajor():
     return 0
 
 class Builder:
-    def __init__(self, opencv, contrib, targets):
+    def __init__(self, opencv, contrib, exclude, targets):
         self.opencv = os.path.abspath(opencv)
         self.contrib = None
         if contrib:
@@ -52,6 +52,7 @@ class Builder:
                 self.contrib = os.path.abspath(modpath)
             else:
                 print("Note: contrib repository is bad - modules subfolder not found", file=sys.stderr)
+        self.exclude = exclude
         self.targets = targets
 
     def getBD(self, parent, t):
@@ -93,8 +94,7 @@ class Builder:
             sys.exit(1)
 
     def getToolchain(self, arch, target):
-        toolchain = os.path.join(self.opencv, "platforms", "ios", "cmake", "Toolchains", "Toolchain-%s_Xcode.cmake" % target)
-        return toolchain
+        return None
 
     def getCMakeArgs(self, arch, target):
         args = [
@@ -104,6 +104,11 @@ class Builder:
             "-DCMAKE_INSTALL_PREFIX=install",
             "-DCMAKE_BUILD_TYPE=Release",
         ]
+
+        if len(self.exclude) > 0:
+            args += ["-DBUILD_opencv_world=OFF"]
+            args += ("-DBUILD_opencv_%s=OFF" % m for m in self.exclude)
+
         return args
 
     def getBuildCommand(self, arch, target):
@@ -126,7 +131,7 @@ class Builder:
         toolchain = self.getToolchain(arch, target)
         cmakecmd = self.getCMakeArgs(arch, target) + \
             (["-DCMAKE_TOOLCHAIN_FILE=%s" % toolchain] if toolchain is not None else [])
-        if arch.startswith("armv"):
+        if arch.startswith("armv") or arch.startswith("arm64"):
             cmakecmd.append("-DENABLE_NEON=ON")
         cmakecmd.append(self.opencv)
         cmakecmd.extend(cmakeargs)
@@ -186,15 +191,34 @@ class Builder:
             d = os.path.join(framework_dir, *l[1])
             os.symlink(s, d)
 
+class iOSBuilder(Builder):
+
+    def getToolchain(self, arch, target):
+        toolchain = os.path.join(self.opencv, "platforms", "ios", "cmake", "Toolchains", "Toolchain-%s_Xcode.cmake" % target)
+        return toolchain
+
+    def getCMakeArgs(self, arch, target):
+        args = Builder.getCMakeArgs(self, arch, target)
+        args = args + [
+            '-DIOS_ARCH=%s' % arch
+        ]
+        return args
+
+
 if __name__ == "__main__":
     folder = os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]), "../.."))
     parser = argparse.ArgumentParser(description='The script builds OpenCV.framework for iOS.')
     parser.add_argument('out', metavar='OUTDIR', help='folder to put built framework')
     parser.add_argument('--opencv', metavar='DIR', default=folder, help='folder with opencv repository (default is "../.." relative to script location)')
     parser.add_argument('--contrib', metavar='DIR', default=None, help='folder with opencv_contrib repository (default is "None" - build only main framework)')
+    parser.add_argument('--without', metavar='MODULE', default=[], action='append', help='OpenCV modules to exclude from the framework')
     args = parser.parse_args()
 
-    b = Builder(args.opencv, args.contrib,
+    b = iOSBuilder(args.opencv, args.contrib, args.without,
+        [
+            ("armv7", "iPhoneOS"),
+            ("arm64", "iPhoneOS"),
+        ] if os.environ.get('BUILD_PRECOMMIT', None) else
         [
             ("armv7", "iPhoneOS"),
             ("armv7s", "iPhoneOS"),
diff --git a/platforms/ios/cmake/Toolchains/Toolchain-iPhoneOS_Xcode.cmake b/platforms/ios/cmake/Toolchains/Toolchain-iPhoneOS_Xcode.cmake
index 14555cd..ec8d4fa 100644
--- a/platforms/ios/cmake/Toolchains/Toolchain-iPhoneOS_Xcode.cmake
+++ b/platforms/ios/cmake/Toolchains/Toolchain-iPhoneOS_Xcode.cmake
@@ -1,31 +1,4 @@
-message (STATUS "Setting up iPhoneOS toolchain")
-set (IPHONEOS TRUE)
-
-# Standard settings
-set (CMAKE_SYSTEM_NAME iOS)
-# Include extra modules for the iOS platform files
-set (CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/platforms/ios/cmake/Modules")
-
-# Force the compilers to clang for iOS
-include (CMakeForceCompiler)
-#CMAKE_FORCE_C_COMPILER (clang GNU)
-#CMAKE_FORCE_CXX_COMPILER (clang++ GNU)
-
-set (CMAKE_C_SIZEOF_DATA_PTR 4)
-set (CMAKE_C_HAS_ISYSROOT 1)
-set (CMAKE_C_COMPILER_ABI ELF)
-set (CMAKE_CXX_SIZEOF_DATA_PTR 4)
-set (CMAKE_CXX_HAS_ISYSROOT 1)
-set (CMAKE_CXX_COMPILER_ABI ELF)
-
-# Skip the platform compiler checks for cross compiling
-set (CMAKE_CXX_COMPILER_WORKS TRUE)
-set (CMAKE_C_COMPILER_WORKS TRUE)
-
-# Search for programs in the build host directories
-SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM ONLY)
-#   for libraries and headers in the target directories
-SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
-SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
-
-message (STATUS "iPhoneOS toolchain loaded")
+message(STATUS "Setting up iPhoneOS toolchain for IOS_ARCH='${IOS_ARCH}'")
+set(IPHONEOS TRUE)
+include(${CMAKE_CURRENT_LIST_DIR}/common-ios-toolchain.cmake)
+message(STATUS "iPhoneOS toolchain loaded")
diff --git a/platforms/ios/cmake/Toolchains/Toolchain-iPhoneSimulator_Xcode.cmake b/platforms/ios/cmake/Toolchains/Toolchain-iPhoneSimulator_Xcode.cmake
index 937079d..4eb212d 100644
--- a/platforms/ios/cmake/Toolchains/Toolchain-iPhoneSimulator_Xcode.cmake
+++ b/platforms/ios/cmake/Toolchains/Toolchain-iPhoneSimulator_Xcode.cmake
@@ -1,31 +1,4 @@
-message (STATUS "Setting up iPhoneSimulator toolchain")
-set (IPHONESIMULATOR TRUE)
-
-# Standard settings
-set (CMAKE_SYSTEM_NAME iOS)
-# Include extra modules for the iOS platform files
-set (CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/platforms/ios/cmake/Modules")
-
-# Force the compilers to clang for iOS
-include (CMakeForceCompiler)
-#CMAKE_FORCE_C_COMPILER (clang GNU)
-#CMAKE_FORCE_CXX_COMPILER (clang++ GNU)
-
-set (CMAKE_C_SIZEOF_DATA_PTR 4)
-set (CMAKE_C_HAS_ISYSROOT 1)
-set (CMAKE_C_COMPILER_ABI ELF)
-set (CMAKE_CXX_SIZEOF_DATA_PTR 4)
-set (CMAKE_CXX_HAS_ISYSROOT 1)
-set (CMAKE_CXX_COMPILER_ABI ELF)
-
-# Skip the platform compiler checks for cross compiling
-set (CMAKE_CXX_COMPILER_WORKS TRUE)
-set (CMAKE_C_COMPILER_WORKS TRUE)
-
-# Search for programs in the build host directories
-SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM ONLY)
-#   for libraries and headers in the target directories
-SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
-SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
-
-message (STATUS "iPhoneSimulator toolchain loaded")
+message(STATUS "Setting up iPhoneSimulator toolchain for IOS_ARCH='${IOS_ARCH}'")
+set(IPHONESIMULATOR TRUE)
+include(${CMAKE_CURRENT_LIST_DIR}/common-ios-toolchain.cmake)
+message(STATUS "iPhoneSimulator toolchain loaded")
diff --git a/platforms/ios/cmake/Toolchains/common-ios-toolchain.cmake b/platforms/ios/cmake/Toolchains/common-ios-toolchain.cmake
new file mode 100644
index 0000000..24dab91
--- /dev/null
+++ b/platforms/ios/cmake/Toolchains/common-ios-toolchain.cmake
@@ -0,0 +1,137 @@
+# load settings in case of "try compile"
+set(TOOLCHAIN_CONFIG_FILE "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/toolchain.config.cmake")
+get_property(__IN_TRY_COMPILE GLOBAL PROPERTY IN_TRY_COMPILE)
+if(__IN_TRY_COMPILE)
+  set(TOOLCHAIN_CONFIG_FILE "${CMAKE_CURRENT_SOURCE_DIR}/../toolchain.config.cmake")
+  if(NOT EXISTS "${TOOLCHAIN_CONFIG_FILE}")
+    # Hack for "try_compile" commands with other binary directory
+    set(TOOLCHAIN_CONFIG_FILE "${CMAKE_PLATFORM_INFO_DIR}/../toolchain.config.cmake")
+    if(NOT EXISTS "${TOOLCHAIN_CONFIG_FILE}")
+      message(FATAL_ERROR "Current CMake version (${CMAKE_VERSION}) is not supported")
+    endif()
+  endif()
+  include("${TOOLCHAIN_CONFIG_FILE}")
+  macro(toolchain_save_config)
+    # nothing
+  endmacro()
+else()
+  macro(toolchain_save_config)
+    set(__config "#message(\"Load TOOLCHAIN config...\")\n")
+    get_cmake_property(__variableNames VARIABLES)
+    set(__vars_list ${ARGN})
+    list(APPEND __vars_list
+        ${TOOLCHAIN_CONFIG_VARS}
+        CMAKE_SYSTEM_NAME
+        CMAKE_SYSTEM_VERSION
+        CMAKE_SYSTEM_PROCESSOR
+        CMAKE_C_COMPILER
+        CMAKE_CXX_COMPILER
+        CMAKE_C_FLAGS
+        CMAKE_CXX_FLAGS
+        CMAKE_SHARED_LINKER_FLAGS
+        CMAKE_MODULE_LINKER_FLAGS
+        CMAKE_EXE_LINKER_FLAGS
+        CMAKE_SKIP_RPATH
+        CMAKE_FIND_ROOT_PATH
+    )
+    foreach(__var ${__variableNames})
+      foreach(_v ${__vars_list})
+        if("x${__var}" STREQUAL "x${_v}")
+          if(${__var} MATCHES " ")
+            set(__config "${__config}set(${__var} \"${${__var}}\")\n")
+          else()
+            set(__config "${__config}set(${__var} ${${__var}})\n")
+          endif()
+        endif()
+      endforeach()
+    endforeach()
+    if(EXISTS "${TOOLCHAIN_CONFIG_FILE}")
+      file(READ "${TOOLCHAIN_CONFIG_FILE}" __config_old)
+    endif()
+    if("${__config_old}" STREQUAL "${__config}")
+      # nothing
+    else()
+      #message("Update TOOLCHAIN config: ${__config}")
+      file(WRITE "${TOOLCHAIN_CONFIG_FILE}" "${__config}")
+    endif()
+    unset(__config)
+    unset(__config_old)
+    unset(__vars_list)
+    unset(__variableNames)
+  endmacro()
+endif() # IN_TRY_COMPILE
+
+if(NOT DEFINED IOS_ARCH)
+  message(FATAL_ERROR "iOS toolchain requires ARCH option for proper configuration of compiler flags")
+endif()
+if(IOS_ARCH MATCHES "^arm64")
+  set(AARCH64 1)
+elseif(IOS_ARCH MATCHES "^armv")
+  set(ARM 1)
+elseif(IOS_ARCH MATCHES "^x86_64")
+  set(X86_64 1)
+elseif(IOS_ARCH MATCHES "^i386")
+  set(X86 1)
+else()
+  message(FATAL_ERROR "iOS toolchain doesn't recognize ARCH='${IOS_ARCH}' value")
+endif()
+
+if(NOT DEFINED CMAKE_OSX_SYSROOT)
+  if(IPHONEOS)
+    set(CMAKE_OSX_SYSROOT "iphoneos")
+  else()
+    set(CMAKE_OSX_SYSROOT "iphonesimulator")
+  endif()
+endif()
+set(CMAKE_MACOSX_BUNDLE YES)
+set(CMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_REQUIRED "NO")
+
+set(CMAKE_OSX_ARCHITECTURES "${IOS_ARCH}" CACHE INTERNAL "Build architecture for iOS" FORCE)
+
+if(NOT __IN_TRY_COMPILE)
+  set(_xcodebuild_wrapper "${CMAKE_BINARY_DIR}/xcodebuild_wrapper")
+  if(NOT CMAKE_MAKE_PROGRAM STREQUAL _xcodebuild_wrapper)
+    set(_xcodebuild_wrapper_tmp "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/xcodebuild_wrapper")
+    file(WRITE "${_xcodebuild_wrapper_tmp}" "#!/bin/sh
+${CMAKE_MAKE_PROGRAM} IPHONEOS_DEPLOYMENT_TARGET=6.0 ARCHS=${IOS_ARCH} -sdk ${CMAKE_OSX_SYSROOT} \$*")
+    # Make executable
+    file(COPY "${_xcodebuild_wrapper_tmp}" DESTINATION ${CMAKE_BINARY_DIR} FILE_PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)
+    set(CMAKE_MAKE_PROGRAM "${_xcodebuild_wrapper}" CACHE INTERNAL "" FORCE)
+  endif()
+endif()
+
+# Standard settings
+set(CMAKE_SYSTEM_NAME iOS)
+set(CMAKE_SYSTEM_VERSION 6.0)
+set(CMAKE_SYSTEM_PROCESSOR "${IOS_ARCH}")
+# Include extra modules for the iOS platform files
+set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/platforms/ios/cmake/Modules")
+
+# Force the compilers to clang for iOS
+include(CMakeForceCompiler)
+#CMAKE_FORCE_C_COMPILER (clang GNU)
+#CMAKE_FORCE_CXX_COMPILER (clang++ GNU)
+
+if(AARCH64 OR X86_64)
+  set(CMAKE_C_SIZEOF_DATA_PTR 8)
+  set(CMAKE_CXX_SIZEOF_DATA_PTR 8)
+else()
+  set(CMAKE_C_SIZEOF_DATA_PTR 4)
+  set(CMAKE_CXX_SIZEOF_DATA_PTR 4)
+endif()
+set(CMAKE_C_HAS_ISYSROOT 1)
+set(CMAKE_CXX_HAS_ISYSROOT 1)
+set(CMAKE_C_COMPILER_ABI ELF)
+set(CMAKE_CXX_COMPILER_ABI ELF)
+
+# Skip the platform compiler checks for cross compiling
+set(CMAKE_CXX_COMPILER_WORKS TRUE)
+set(CMAKE_C_COMPILER_WORKS TRUE)
+
+# Search for programs in the build host directories
+set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM ONLY)
+#   for libraries and headers in the target directories
+set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
+set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
+
+toolchain_save_config(IOS_ARCH)
diff --git a/platforms/linux/aarch64-gnu.toolchain.cmake b/platforms/linux/aarch64-gnu.toolchain.cmake
new file mode 100644
index 0000000..ae16337
--- /dev/null
+++ b/platforms/linux/aarch64-gnu.toolchain.cmake
@@ -0,0 +1,4 @@
+set(CMAKE_SYSTEM_PROCESSOR aarch64)
+set(GCC_COMPILER_VERSION "" CACHE STRING "GCC Compiler version")
+set(GNU_MACHINE "aarch64-linux-gnu" CACHE STRING "GNU compiler triple")
+include("${CMAKE_CURRENT_LIST_DIR}/arm.toolchain.cmake")
diff --git a/platforms/linux/arm-gnueabi.toolchain.cmake b/platforms/linux/arm-gnueabi.toolchain.cmake
index 448dfa6..90217f0 100644
--- a/platforms/linux/arm-gnueabi.toolchain.cmake
+++ b/platforms/linux/arm-gnueabi.toolchain.cmake
@@ -1,88 +1,3 @@
-set(CMAKE_SYSTEM_NAME Linux)
-set(CMAKE_SYSTEM_VERSION 1)
-set(CMAKE_SYSTEM_PROCESSOR arm)
-
-set(GCC_COMPILER_VERSION "4.6" CACHE STRING "GCC Compiler version")
-
-set(FLOAT_ABI_SUFFIX "")
-if (NOT SOFTFP)
-  set(FLOAT_ABI_SUFFIX "hf")
-endif()
-
-find_program(CMAKE_C_COMPILER NAMES arm-linux-gnueabi${FLOAT_ABI_SUFFIX}-gcc-${GCC_COMPILER_VERSION})
-find_program(CMAKE_CXX_COMPILER NAMES arm-linux-gnueabi${FLOAT_ABI_SUFFIX}-g++-${GCC_COMPILER_VERSION})
-set(ARM_LINUX_SYSROOT /usr/arm-linux-gnueabi${FLOAT_ABI_SUFFIX} CACHE PATH "ARM cross compilation system root")
-
-set(CMAKE_CXX_FLAGS           ""                    CACHE STRING "c++ flags")
-set(CMAKE_C_FLAGS             ""                    CACHE STRING "c flags")
-set(CMAKE_SHARED_LINKER_FLAGS ""                    CACHE STRING "shared linker flags")
-set(CMAKE_MODULE_LINKER_FLAGS ""                    CACHE STRING "module linker flags")
-set(CMAKE_EXE_LINKER_FLAGS    "-Wl,-z,nocopyreloc"  CACHE STRING "executable linker flags")
-
-set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mthumb -fdata-sections -Wa,--noexecstack -fsigned-char -Wno-psabi")
-set(CMAKE_C_FLAGS   "${CMAKE_C_FLAGS} -mthumb -fdata-sections -Wa,--noexecstack -fsigned-char -Wno-psabi")
-
-set(CMAKE_SHARED_LINKER_FLAGS "-Wl,--fix-cortex-a8 -Wl,--no-undefined -Wl,--gc-sections -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,now ${CMAKE_SHARED_LINKER_FLAGS}")
-set(CMAKE_MODULE_LINKER_FLAGS "-Wl,--fix-cortex-a8 -Wl,--no-undefined -Wl,--gc-sections -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,now ${CMAKE_MODULE_LINKER_FLAGS}")
-set(CMAKE_EXE_LINKER_FLAGS    "-Wl,--fix-cortex-a8 -Wl,--no-undefined -Wl,--gc-sections -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,now ${CMAKE_EXE_LINKER_FLAGS}")
-
-if(USE_NEON)
-  message(WARNING "You use obsolete variable USE_NEON to enable NEON instruction set. Use -DENABLE_NEON=ON instead." )
-  set(ENABLE_NEON TRUE)
-elseif(USE_VFPV3)
-  message(WARNING "You use obsolete variable USE_VFPV3 to enable VFPV3 instruction set. Use -DENABLE_VFPV3=ON instead." )
-  set(ENABLE_VFPV3 TRUE)
-endif()
-
-set(CMAKE_FIND_ROOT_PATH ${CMAKE_FIND_ROOT_PATH} ${ARM_LINUX_SYSROOT})
-
-if(EXISTS ${CUDA_TOOLKIT_ROOT_DIR})
-    set(CMAKE_FIND_ROOT_PATH ${CMAKE_FIND_ROOT_PATH} ${CUDA_TOOLKIT_ROOT_DIR})
-endif()
-
-set( CMAKE_SKIP_RPATH TRUE CACHE BOOL "If set, runtime paths are not added when using shared libraries." )
-set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
-set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
-set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM ONLY)
-
-# macro to find programs on the host OS
-macro( find_host_program )
- set( CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER )
- set( CMAKE_FIND_ROOT_PATH_MODE_LIBRARY NEVER )
- set( CMAKE_FIND_ROOT_PATH_MODE_INCLUDE NEVER )
- if( CMAKE_HOST_WIN32 )
-  SET( WIN32 1 )
-  SET( UNIX )
- elseif( CMAKE_HOST_APPLE )
-  SET( APPLE 1 )
-  SET( UNIX )
- endif()
- find_program( ${ARGN} )
- SET( WIN32 )
- SET( APPLE )
- SET( UNIX 1 )
- set( CMAKE_FIND_ROOT_PATH_MODE_PROGRAM ONLY )
- set( CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY )
- set( CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY )
-endmacro()
-
-# macro to find packages on the host OS
-macro( find_host_package )
- set( CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER )
- set( CMAKE_FIND_ROOT_PATH_MODE_LIBRARY NEVER )
- set( CMAKE_FIND_ROOT_PATH_MODE_INCLUDE NEVER )
- if( CMAKE_HOST_WIN32 )
-  SET( WIN32 1 )
-  SET( UNIX )
- elseif( CMAKE_HOST_APPLE )
-  SET( APPLE 1 )
-  SET( UNIX )
- endif()
- find_package( ${ARGN} )
- SET( WIN32 )
- SET( APPLE )
- SET( UNIX 1 )
- set( CMAKE_FIND_ROOT_PATH_MODE_PROGRAM ONLY )
- set( CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY )
- set( CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY )
-endmacro()
+set(GCC_COMPILER_VERSION "" CACHE STRING "GCC Compiler version")
+set(GNU_MACHINE "arm-linux-gnueabi" CACHE STRING "GNU compiler triple")
+include("${CMAKE_CURRENT_LIST_DIR}/arm.toolchain.cmake")
diff --git a/platforms/linux/arm.toolchain.cmake b/platforms/linux/arm.toolchain.cmake
new file mode 100644
index 0000000..75c9194
--- /dev/null
+++ b/platforms/linux/arm.toolchain.cmake
@@ -0,0 +1,97 @@
+if(COMMAND toolchain_save_config)
+  return() # prevent recursive call
+endif()
+
+set(CMAKE_SYSTEM_NAME Linux)
+set(CMAKE_SYSTEM_VERSION 1)
+if(NOT DEFINED CMAKE_SYSTEM_PROCESSOR)
+  set(CMAKE_SYSTEM_PROCESSOR arm)
+else()
+  #message("CMAKE_SYSTEM_PROCESSOR=${CMAKE_SYSTEM_PROCESSOR}")
+endif()
+
+include("${CMAKE_CURRENT_LIST_DIR}/gnu.toolchain.cmake")
+
+if(CMAKE_SYSTEM_PROCESSOR STREQUAL arm AND NOT ARM_IGNORE_FP)
+  set(FLOAT_ABI_SUFFIX "")
+  if(NOT SOFTFP)
+    set(FLOAT_ABI_SUFFIX "hf")
+  endif()
+endif()
+
+if(NOT "x${GCC_COMPILER_VERSION}" STREQUAL "x")
+  set(__GCC_VER_SUFFIX "-${GCC_COMPILER_VERSION}")
+endif()
+
+if(NOT DEFINED CMAKE_C_COMPILER)
+  find_program(CMAKE_C_COMPILER NAMES ${GNU_MACHINE}${FLOAT_ABI_SUFFIX}-gcc${__GCC_VER_SUFFIX})
+else()
+  #message(WARNING "CMAKE_C_COMPILER=${CMAKE_C_COMPILER} is defined")
+endif()
+if(NOT DEFINED CMAKE_CXX_COMPILER)
+  find_program(CMAKE_CXX_COMPILER NAMES ${GNU_MACHINE}${FLOAT_ABI_SUFFIX}-g++${__GCC_VER_SUFFIX})
+else()
+  #message(WARNING "CMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER} is defined")
+endif()
+if(NOT DEFINED CMAKE_LINKER)
+  find_program(CMAKE_LINKER NAMES ${GNU_MACHINE}${FLOAT_ABI_SUFFIX}-ld${__GCC_VER_SUFFIX} ${GNU_MACHINE}${FLOAT_ABI_SUFFIX}-ld)
+else()
+  #message(WARNING "CMAKE_LINKER=${CMAKE_LINKER} is defined")
+endif()
+if(NOT DEFINED CMAKE_AR)
+  find_program(CMAKE_AR NAMES ${GNU_MACHINE}${FLOAT_ABI_SUFFIX}-ar${__GCC_VER_SUFFIX} ${GNU_MACHINE}${FLOAT_ABI_SUFFIX}-ar)
+else()
+  #message(WARNING "CMAKE_AR=${CMAKE_AR} is defined")
+endif()
+
+if(NOT DEFINED ARM_LINUX_SYSROOT AND DEFINED GNU_MACHINE)
+  set(ARM_LINUX_SYSROOT /usr/${GNU_MACHINE}${FLOAT_ABI_SUFFIX})
+endif()
+
+if(NOT DEFINED CMAKE_CXX_FLAGS)
+  set(CMAKE_CXX_FLAGS           "" CACHE INTERAL "")
+  set(CMAKE_C_FLAGS             "" CACHE INTERAL "")
+  set(CMAKE_SHARED_LINKER_FLAGS "" CACHE INTERAL "")
+  set(CMAKE_MODULE_LINKER_FLAGS "" CACHE INTERAL "")
+  set(CMAKE_EXE_LINKER_FLAGS    "" CACHE INTERAL "")
+
+  set(CMAKE_CXX_FLAGS           "${CMAKE_CXX_FLAGS} -fdata-sections -Wa,--noexecstack -fsigned-char -Wno-psabi")
+  set(CMAKE_C_FLAGS             "${CMAKE_C_FLAGS} -fdata-sections -Wa,--noexecstack -fsigned-char -Wno-psabi")
+  if(CMAKE_SYSTEM_PROCESSOR STREQUAL arm)
+    set(CMAKE_CXX_FLAGS           "-mthumb ${CMAKE_CXX_FLAGS}")
+    set(CMAKE_C_FLAGS             "-mthumb ${CMAKE_C_FLAGS}")
+    set(CMAKE_EXE_LINKER_FLAGS    "${CMAKE_EXE_LINKER_FLAGS} -Wl,-z,nocopyreloc")
+  endif()
+  if(CMAKE_SYSTEM_PROCESSOR STREQUAL arm)
+    set(ARM_LINKER_FLAGS "-Wl,--fix-cortex-a8 -Wl,--no-undefined -Wl,--gc-sections -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,now")
+  elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL aarch64)
+    set(ARM_LINKER_FLAGS "-Wl,--no-undefined -Wl,--gc-sections -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,now")
+  endif()
+  set(CMAKE_SHARED_LINKER_FLAGS "${ARM_LINKER_FLAGS} ${CMAKE_SHARED_LINKER_FLAGS}")
+  set(CMAKE_MODULE_LINKER_FLAGS "${ARM_LINKER_FLAGS} ${CMAKE_MODULE_LINKER_FLAGS}")
+  set(CMAKE_EXE_LINKER_FLAGS    "${ARM_LINKER_FLAGS} ${CMAKE_EXE_LINKER_FLAGS}")
+else()
+  #message(WARNING "CMAKE_CXX_FLAGS='${CMAKE_CXX_FLAGS}' is defined")
+endif()
+
+if(USE_NEON)
+  message(WARNING "You use obsolete variable USE_NEON to enable NEON instruction set. Use -DENABLE_NEON=ON instead." )
+  set(ENABLE_NEON TRUE)
+elseif(USE_VFPV3)
+  message(WARNING "You use obsolete variable USE_VFPV3 to enable VFPV3 instruction set. Use -DENABLE_VFPV3=ON instead." )
+  set(ENABLE_VFPV3 TRUE)
+endif()
+
+set(CMAKE_FIND_ROOT_PATH ${CMAKE_FIND_ROOT_PATH} ${ARM_LINUX_SYSROOT})
+
+if(EXISTS ${CUDA_TOOLKIT_ROOT_DIR})
+  set(CMAKE_FIND_ROOT_PATH ${CMAKE_FIND_ROOT_PATH} ${CUDA_TOOLKIT_ROOT_DIR})
+endif()
+
+set(TOOLCHAIN_CONFIG_VARS ${TOOLCHAIN_CONFIG_VARS}
+    ARM_LINUX_SYSROOT
+    ENABLE_NEON
+    ENABLE_VFPV3
+    CUDA_TOOLKIT_ROOT_DIR
+)
+toolchain_save_config()
diff --git a/platforms/linux/gnu.toolchain.cmake b/platforms/linux/gnu.toolchain.cmake
new file mode 100644
index 0000000..4050d83
--- /dev/null
+++ b/platforms/linux/gnu.toolchain.cmake
@@ -0,0 +1,106 @@
+cmake_minimum_required(VERSION 2.8)
+
+# load settings in case of "try compile"
+set(TOOLCHAIN_CONFIG_FILE "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/toolchain.config.cmake")
+get_property(__IN_TRY_COMPILE GLOBAL PROPERTY IN_TRY_COMPILE)
+if(__IN_TRY_COMPILE)
+  include("${CMAKE_CURRENT_SOURCE_DIR}/../toolchain.config.cmake" OPTIONAL) # CMAKE_BINARY_DIR is different
+  macro(toolchain_save_config)
+    # nothing
+  endmacro()
+else()
+  macro(toolchain_save_config)
+    set(__config "#message(\"Load TOOLCHAIN config...\")\n")
+    get_cmake_property(__variableNames VARIABLES)
+    set(__vars_list ${ARGN})
+    list(APPEND __vars_list
+        ${TOOLCHAIN_CONFIG_VARS}
+        CMAKE_SYSTEM_NAME
+        CMAKE_SYSTEM_VERSION
+        CMAKE_SYSTEM_PROCESSOR
+        CMAKE_C_COMPILER
+        CMAKE_CXX_COMPILER
+        CMAKE_C_FLAGS
+        CMAKE_CXX_FLAGS
+        CMAKE_SHARED_LINKER_FLAGS
+        CMAKE_MODULE_LINKER_FLAGS
+        CMAKE_EXE_LINKER_FLAGS
+        CMAKE_SKIP_RPATH
+        CMAKE_FIND_ROOT_PATH
+        GCC_COMPILER_VERSION
+    )
+    foreach(__var ${__variableNames})
+      foreach(_v ${__vars_list})
+        if("x${__var}" STREQUAL "x${_v}")
+          if(${__var} MATCHES " ")
+            set(__config "${__config}set(${__var} \"${${__var}}\")\n")
+          else()
+            set(__config "${__config}set(${__var} ${${__var}})\n")
+          endif()
+        endif()
+      endforeach()
+    endforeach()
+    if(EXISTS "${TOOLCHAIN_CONFIG_FILE}")
+      file(READ "${TOOLCHAIN_CONFIG_FILE}" __config_old)
+    endif()
+    if("${__config_old}" STREQUAL "${__config}")
+      # nothing
+    else()
+      #message("Update TOOLCHAIN config: ${__config}")
+      file(WRITE "${TOOLCHAIN_CONFIG_FILE}" "${__config}")
+    endif()
+    unset(__config)
+    unset(__config_old)
+    unset(__vars_list)
+    unset(__variableNames)
+  endmacro()
+endif() # IN_TRY_COMPILE
+
+set(CMAKE_SKIP_RPATH TRUE)
+set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
+set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
+set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM ONLY)
+
+# macro to find programs on the host OS
+macro(find_host_program)
+ set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
+ set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY NEVER)
+ set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE NEVER)
+ if(CMAKE_HOST_WIN32)
+  SET(WIN32 1)
+  SET(UNIX)
+ elseif(CMAKE_HOST_APPLE)
+  SET(APPLE 1)
+  SET(UNIX)
+ endif()
+ find_program(${ARGN})
+ SET(WIN32)
+ SET(APPLE)
+ SET(UNIX 1)
+ set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM ONLY)
+ set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
+ set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
+endmacro()
+
+# macro to find packages on the host OS
+macro(find_host_package)
+ set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
+ set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY NEVER)
+ set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE NEVER)
+ if(CMAKE_HOST_WIN32)
+  SET(WIN32 1)
+  SET(UNIX)
+ elseif(CMAKE_HOST_APPLE)
+  SET(APPLE 1)
+  SET(UNIX)
+ endif()
+ find_package(${ARGN})
+ SET(WIN32)
+ SET(APPLE)
+ SET(UNIX 1)
+ set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM ONLY)
+ set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
+ set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
+endmacro()
+
+set(CMAKE_SKIP_RPATH TRUE CACHE BOOL "If set, runtime paths are not added when using shared libraries.")
diff --git a/platforms/maven/README.md b/platforms/maven/README.md
new file mode 100644
index 0000000..54f151a
--- /dev/null
+++ b/platforms/maven/README.md
@@ -0,0 +1,64 @@
+# Using Maven to build OpenCV
+
+This page describes the how to build OpenCV using [Apache Maven](http://maven.apache.org/index.html). The Maven build is simply a wrapper around the existing CMake process but has the additional aims of creating Java OSGi-compatible bundles with included native support and also allow the build to be carried out on RaspberryPi (ARM) architecture. There is nothing preventing using the POM on x86 Linux however.
+
+The following assumes building on Debian-based Linux platform.
+
+## Overview
+The Maven build process aims to:
+  1. Provide a simpler route to build OpenCV and Java bundles.
+  2. Automatically check the required native dependencies.
+  3. Make the Java libraries OSGi compatible.
+  4. Include the native OpenCV native library inside the Java bundle.
+  5. Allow the build to function on x86, x86_64 or amd architectures, Debian-based Linux platform.
+
+### Starting the build
+#### Environment variables
+**Applicability:** All processors.
+
+   The following environment variables must be set otherwise the build will fail and halt:
+
+   * `$JAVA_HOME` (the absolute path to the JDK root directory)
+   * `$ANT_HOME` (the absolute path to the Ant root directory)
+
+It is recommended that advantage is taken of multiple processor cores to reduce build time. This can be done by setting a MAKEFLAGS environment variable specifying the number of parallel builds e.g.:
+
+   * `$MAKEFLAGS="-j8"`
+
+However if this flag is not set the build will NOT fail. On a RaspberryPi 2 typical build times are 5 hours with `-j1` (which is the default if `$MAKEFLAGS` is not specified) and a little over 2 hours with `-j4`.
+
+All of the above environment variables can be set on an ad-hoc basis using 'export'.
+#### Build Directory
+**Applicability:** All processors
+
+By default the following build directories are created.
+
+`<OpenCV_root_dir>/build`
+
+`<OpenCV_root_dir>/build/target`
+
+Under `build` are the standard OpenCV artifacts. Under `build/target` can be found the OSGi compatible Java bundle. When deploying the bundle into an OSGi framework e.g. [Apache Karaf](http://karaf.apache.org/), loading of the native library is automatically taken care of. The standard Java library as created by the CMake process is also available as specified in the existing OpenCV documentation.
+
+The Maven build is initiated from the directory contain the `pom.xml` file.
+#### x86 or x86_64 Architecture:
+Generally all that is required is the standard Maven command:
+
+`mvn clean install`
+
+One of the first things the build will do is check the required native dependencies. The Maven build indicates the status of the required dependencies and will fail at this point if any are missing. Install using the package manager e.g. aptitude or apt-get, and restart the build with the above command.
+
+Once the build succesfully completes the OSGi compatible artifacts are available as described above in 'Build Directory'.
+
+#### ARM 32-bit Architecture - Raspbian Distribution
+Similar to the x86 architecture the native dependencies are first checked so install any that are missing, however at the time of writing there are no official `libtbb2` and `libtbb-dev` packages in Raspbian. Version 4.4.3 of Intel's Thread Building Blocks library are available [here](http://www.javatechnics.com/thread-building-blocks-tbb-4-4-3-for-raspbian) as a Raspbian-compatible Debian packages.
+
+**PLEASE NOTE THESE ARE NOT OFFICIAL RASPBIAN PACKAGES. INSTALL AT YOUR OWN RISK.**
+
+OpenCV is built using CMake and the Maven build process uses the the [cmake-maven plugin](https://github.com/cmake-maven-project/cmake-maven-project). The cmake-maven plugin by default downloads CMake at build time but unfortunately there is no binary for ARM architecture currently available. As a work around it is possible to use the native CMake (which is checked for availability in the above dependency checks). Assuming all native dependencies are available the build can be started wi [...]
+
+`mvn clean install -Duse.native.cmake=true`
+
+Upon a successful build the libraries will be available as described above in 'Build Directory'.
+
+#### cmake-mave-plugin 3.4.1-b2-SNAPSHOT
+Should this plugin not be available in Maven central, the source can be found at my GitHub page [here](https://github.com/jtkb/cmake-maven-project), checkout the `raspberrypi` branch and install. On x86 it is a standard Maven build and install command. If building on Raspbian you also need to supply the `-Duse.native.cmake=true` command-line option.
diff --git a/platforms/maven/pom.xml b/platforms/maven/pom.xml
new file mode 100644
index 0000000..d070acf
--- /dev/null
+++ b/platforms/maven/pom.xml
@@ -0,0 +1,263 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <groupId>opencv.org</groupId>
+    <artifactId>opencv</artifactId>
+    <packaging>bundle</packaging>
+    <version>3.2.0</version>
+    <name>OpenCV</name>
+    <licenses>
+        <license>
+            <name>License Agreement For Open Source Computer Vision Library (3-clause BSD License)</name>
+            <url></url>
+        </license>
+    </licenses>
+    <url>http://opencv.org/</url>
+    <scm>
+        <connection>scm:git:https://github.com/Itseez/opencv.git</connection>
+        <url>https://github.com/Itseez/opencv</url>
+    </scm>
+    <contributors>
+        <contributor>
+            <name>Kerry Billingham</name>
+            <email>contact (at) AvionicEngineers (d0t) c(0)m</email>
+            <organization>Java Technics</organization>
+            <url>www.javatechnics.com</url>
+        </contributor>
+    </contributors>
+    <dependencies>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <version>3.8.1</version>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+    <properties>
+        <build.directory>../../build</build.directory>
+        <nativelibrary.name>libopencv_java${lib.version.string}.so</nativelibrary.name>
+    </properties>
+    <distributionManagement>
+        <snapshotRepository>
+            <id>${repo.name}</id>
+            <url>${repo.url}</url>
+        </snapshotRepository>
+    </distributionManagement>
+    <build>
+        <directory>../../build/target</directory>
+        <outputDirectory>../../build/src</outputDirectory>
+        <sourceDirectory>../../build/src</sourceDirectory>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-clean-plugin</artifactId>
+                <version>3.0.0</version>
+                <configuration>
+                    <filesets>
+                        <fileset>
+                            <directory>${build.directory}</directory>
+                        </fileset>
+                    </filesets>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>com.github.maven-nar</groupId>
+                <artifactId>nar-maven-plugin</artifactId>
+                <version>3.3.0</version>
+                <extensions>true</extensions>
+                <executions>
+                    <execution>
+                        <id>nar-initiliase</id>
+                        <phase>validate</phase>
+                        <goals>
+                            <goal>nar-validate</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.codehaus.mojo</groupId>
+                <artifactId>exec-maven-plugin</artifactId>
+                <version>1.4.0</version>
+                <executions>
+                    <execution>
+                        <id>get-opencv-version</id>
+                        <phase>generate-resources</phase>
+                        <goals>
+                            <goal>exec</goal>
+                        </goals>
+                        <configuration>
+                            <executable>bash</executable>
+                            <workingDirectory>${project.basedir}/scripts</workingDirectory>
+                            <arguments>
+                                <argument>properties</argument>
+                                <argument>../../../modules/core/include/opencv2/core/version.hpp</argument>
+                                <argument>${build.directory}</argument>
+                                <argument>build.properties</argument>
+                            </arguments>
+                        </configuration>
+                    </execution>
+                    <execution>
+                        <id>setup-environment</id>
+                        <phase>validate</phase>
+                        <goals>
+                            <goal>exec</goal>
+                        </goals>
+                        <configuration>
+                            <executable>bash</executable>
+                            <workingDirectory>${project.basedir}/scripts</workingDirectory>
+                            <arguments>
+                                <argument>deb_package_check</argument>
+                                <argument>build-essential</argument>
+                                <argument>cmake</argument>
+                                <argument>git</argument>
+                                <argument>libgtk2.0-dev</argument>
+                                <argument>pkg-config</argument>
+                                <argument>libavcodec-dev</argument>
+                                <argument>libavformat-dev</argument>
+                                <argument>libswscale-dev</argument>
+                                <argument>python-dev</argument>
+                                <argument>python-numpy</argument>
+                                <argument>libtbb2</argument>
+                                <argument>libtbb-dev</argument>
+                                <argument>libjpeg-dev</argument>
+                                <argument>libpng12-dev</argument>
+                                <argument>libtiff5-dev</argument>
+                                <argument>libjasper-dev</argument>
+                                <argument>libdc1394-22-dev</argument>
+                                <argument>ant</argument>
+                            </arguments>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.codehaus.mojo</groupId>
+                <artifactId>properties-maven-plugin</artifactId>
+                <version>1.0.0</version>
+                <executions>
+                    <execution>
+                        <id>set-arch-properties</id>
+                        <phase>process-resources</phase>
+                        <goals>
+                            <goal>read-project-properties</goal>
+                        </goals>
+                        <configuration>
+                            <files>
+                                <file>${build.directory}/build.properties</file>
+                            </files>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-enforcer-plugin</artifactId>
+                <version>1.4.1</version>
+                <executions>
+                    <execution>
+                        <phase>validate</phase>
+                        <id>enforce-os</id>
+                        <goals>
+                            <goal>enforce</goal>
+                        </goals>
+                        <configuration>
+                            <rules>
+                                <requireOS>
+                                    <family>unix</family>
+                                    <message>This POM is written to function on UNIX family of OS.
+                                            More specifically it should be a Debian flavour of Linux.</message>
+                                </requireOS>
+                            </rules>
+                        </configuration>
+                    </execution>
+                    <execution>
+                        <id>enforce-environment</id>
+                        <goals>
+                            <goal>enforce</goal>
+                        </goals>
+                        <configuration>
+                            <rules>
+                                <requireEnvironmentVariable>
+                                    <variableName>ANT_HOME</variableName>
+                                    <message>$ANT_HOME is not set. Build may fail.</message>
+                                </requireEnvironmentVariable>
+                                <requireEnvironmentVariable>
+                                    <variableName>JAVA_HOME</variableName>
+                                    <message>$JAVA_HOME is not set. Build WILL fail.</message>
+                                </requireEnvironmentVariable>
+                                <requireEnvironmentVariable>
+                                    <level>WARN</level>
+                                    <variableName>MAKEFLAGS</variableName>
+                                    <message>No MAKEFLAGS environment variable. Build may be slow.
+To speed up the build you can try exporting MAKEFLAGS=-jX where X equals the number of parallel builds.</message>
+                                </requireEnvironmentVariable>
+                            </rules>
+                        </configuration>
+                    </execution>
+                    <execution>
+                        <phase>process-resources</phase>
+                        <id>check-versions-match</id>
+                        <goals>
+                            <goal>enforce</goal>
+                        </goals>
+                        <configuration>
+                            <rules>
+                                <requireProperty>
+                                    <property>project.version</property>
+                                    <regex>${opencv.version}</regex>
+                                    <regexMessage>The Maven POM version ${project.version} does not match the extracted OpenCV version ${opencv.version}.</regexMessage>
+                                </requireProperty>
+                            </rules>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <version>2.3.7</version>
+                <extensions>true</extensions>
+                <configuration>
+                    <instructions>
+                        <Export-Package>*</Export-Package>
+                        <Bundle-NativeCode>${nativelibrary.name};osname=linux;processor=${osgi.processor}</Bundle-NativeCode>
+                        <Include-Resource>${build.directory}/lib/${nativelibrary.name}</Include-Resource>
+                    </instructions>
+                    <manifestLocation>${build.directory}/manifest</manifestLocation>
+                    <niceManifest>true</niceManifest>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>com.googlecode.cmake-maven-project</groupId>
+                <artifactId>cmake-maven-plugin</artifactId>
+                <version>3.4.1-b2-SNAPSHOT</version>
+                <executions>
+                    <execution>
+                        <id>cmake-generate</id>
+                        <goals>
+                            <goal>generate</goal>
+                        </goals>
+                        <configuration>
+                            <sourcePath>../..</sourcePath>
+                            <targetPath>../../build</targetPath>
+                            <generator>Unix Makefiles</generator>
+                            <options>
+                                <option>-DBUILD_SHARED_LIBS:BOOL=OFF</option>
+                            </options>
+                        </configuration>
+                    </execution>
+                    <execution>
+                        <id>cmake-compile</id>
+                        <goals>
+                            <goal>compile</goal>
+                        </goals>
+                        <configuration>
+                            <projectDirectory>../../build</projectDirectory>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+</project>
diff --git a/platforms/maven/scripts/deb_package_check b/platforms/maven/scripts/deb_package_check
new file mode 100755
index 0000000..504e758
--- /dev/null
+++ b/platforms/maven/scripts/deb_package_check
@@ -0,0 +1,42 @@
+#!/bin/bash
+###########################################################################################
+#
+# 		This script checks for the required Debian packages are installed
+# 		to build OpenCV.
+# Commandline parameters:
+# $@ - These are the names of the packages to check with 'dpkg'
+#
+# Returns:
+#   0 - All packages installed (success)
+#   1 - One or more packages missing (failure)
+#
+#   Kerry Billingham <contact (at) avionicengineers (d0t) com>
+#   20 April 2016
+#
+###########################################################################################
+red=$'\e[1;31m'
+green=$'\e[1;32m'
+end=$'\e[0m'
+check_message="Checking for 'dpkg'"
+dpkg -? &>/dev/null
+if [ $? -ne 0 ]; then
+    printf "%-80s%s\n" "${check_message}" "${red} MISSING.${end}"
+    exit 1
+else
+    printf "%-80s%s\n" "${check_message}" "${green} INSTALLED.${end}"
+fi
+
+declare -i packageMissing=0
+packageArray=( "$@" )
+for package in ${packageArray[@]}; do
+    check_message="Checking for package ${package}"
+    dpkg -s ${package} &>/dev/null
+    if [ $? -ne 0 ]; then
+        printf "%-80s%s\n" "${check_message}" "${red} MISSING.${end}"
+        packageMissing=1
+    else
+        printf "%-80s%s\n" "${check_message}" "${green} INSTALLED.${end}"
+    fi
+done
+
+exit $packageMissing
diff --git a/platforms/maven/scripts/properties b/platforms/maven/scripts/properties
new file mode 100755
index 0000000..a413c2a
--- /dev/null
+++ b/platforms/maven/scripts/properties
@@ -0,0 +1,90 @@
+#!/bin/bash
+#####################################################################
+# This script extracts several properties and then writes them to a
+# to a file, 'build.properties'. These properties include:
+#
+#	1. OpenCV version.
+#	2. OpenVC version as a string for use by Maven.
+#	3. The CPU binary word size.
+#	4. Architecture string.
+#	4. OSGi compatible CPU architecture string.
+#
+# There is no need to execute this script directly as it will be
+# called during the Maven build process.
+#
+# Command-line parameters:
+#   $1 - Absolute path to the file containing Open CV version
+#   $2 - The build directory and where the output file will be written
+#   $3 - The name of the output file to write to.
+#
+# Returns:
+#   0 - Successfully written the properties file.
+#   1 - Error occured such as build directory does not exist
+#	or OpenCV version could not be determined or an
+#	unexpected error.
+#
+#   Kerry Billingham <contact (at) avionicengineers (d0t) com>
+#   20 April 2016
+#
+#####################################################################
+
+majorHashDefine="#define CV_VERSION_MAJOR"
+minorHashDefine="#define CV_VERSION_MINOR"
+revisionHashDefine="#define CV_VERSION_REVISION"
+statusHashDefine="#define CV_VERSION_STATUS"
+
+#Test build directory exists
+if [  ! -n "$2" ] || [ ! -d $2 ];then
+    echo "Build directory not specified or does not exist!"
+    exit 1
+fi
+
+if [ -n "$1" ] && [ -e $1 ];then
+    minorVersion=$(grep "${minorHashDefine}" $1 | grep -o ".$")
+    majorVersion=$(grep "${majorHashDefine}" $1 | grep -o ".$")
+    revision=$(grep "${revisionHashDefine}" $1 | grep -o ".$")
+
+    bits=$(getconf LONG_BIT)
+    architecture=$(arch)
+    osgiProcessor="Not Set"
+
+    case ${architecture} in
+        x86*)
+            echo "This is x86 (32 | 64) bit"
+            case ${bits} in
+                32)
+                    osgiProcessor="x86"
+                    ;;
+                64)
+                    osgiProcessor="x86_64"
+                    ;;
+                *)
+                    osgiProcessor="Unknown"
+            esac
+            ;;
+        arm*)
+            echo "This is ARM"
+            byteOrder=$(lscpu | grep -i "byte order")
+            shopt -s nocasematch
+            if [[ "${byteOrder}" == *little* ]]; then
+                osgiProcessor="arm_le"
+            elif [[ "${byteOrder}}" == *big* ]]; then
+                osgiProcessor="arm_be"
+            fi
+            shopt -u nocasematch
+            ;;
+        *)
+            echo "This is unknown architecture"
+        esac
+
+    echo "The version number will be ${majorVersion}.${minorVersion}.${revision}"
+    echo "opencv.version=${majorVersion}.${minorVersion}.${revision}" > ${2}/${3}
+    echo "lib.version.string=${majorVersion}${minorVersion}${revision}" >> ${2}/${3}
+    echo "bits=${bits}" >> ${2}/${3}
+    echo "architecture=$(arch)" >> ${2}/${3}
+    echo "osgi.processor=${osgiProcessor}" >> ${2}/${3}
+    exit 0
+else
+    echo "Could not locate file $1 to determine versioning."
+    exit 1
+fi
diff --git a/platforms/osx/build_framework.py b/platforms/osx/build_framework.py
index 94886a2..2d39be5 100644
--- a/platforms/osx/build_framework.py
+++ b/platforms/osx/build_framework.py
@@ -36,9 +36,10 @@ if __name__ == "__main__":
     parser.add_argument('out', metavar='OUTDIR', help='folder to put built framework')
     parser.add_argument('--opencv', metavar='DIR', default=folder, help='folder with opencv repository (default is "../.." relative to script location)')
     parser.add_argument('--contrib', metavar='DIR', default=None, help='folder with opencv_contrib repository (default is "None" - build only main framework)')
+    parser.add_argument('--without', metavar='MODULE', default=[], action='append', help='OpenCV modules to exclude from the framework')
     args = parser.parse_args()
 
-    b = OSXBuilder(args.opencv, args.contrib,
+    b = OSXBuilder(args.opencv, args.contrib, args.without,
         [
             ("x86_64", "MacOSX")
         ])
diff --git a/platforms/scripts/valgrind.supp b/platforms/scripts/valgrind.supp
index b37ca20..54833e0 100644
--- a/platforms/scripts/valgrind.supp
+++ b/platforms/scripts/valgrind.supp
@@ -4,3 +4,10 @@
    fun:ippicvGetCpuFeatures
    fun:ippicvStaticInit
 }
+
+{
+   TBB - allocate_via_handler_v3 issue
+   Memcheck:Leak
+   fun:malloc
+   fun:_ZN3tbb8internal23allocate_via_handler_v3Em
+}
diff --git a/platforms/winrt/readme.txt b/platforms/winrt/readme.txt
index c35d18d..2fb4ce1 100644
--- a/platforms/winrt/readme.txt
+++ b/platforms/winrt/readme.txt
@@ -124,7 +124,7 @@ Running tests for Windows Store
 ===============================
 1. You might need to install this if you haven't already: http://www.microsoft.com/en-US/download/details.aspx?id=40784
 
-2. Set OPENCV_TEST_DATA_PATH environment variable to location of opencv_extra/testdata (cloning of https://github.com/Itseez/opencv_extra repo required) to get tests work correctly. Also, set OPENCV_PERF_VALIDATION_DIR environment variable in case you are planning to have place where to store performance test results and compare them with the future test runs.
+2. Set OPENCV_TEST_DATA_PATH environment variable to location of opencv_extra/testdata (cloning of https://github.com/opencv/opencv_extra repo required) to get tests work correctly. Also, set OPENCV_PERF_VALIDATION_DIR environment variable in case you are planning to have place where to store performance test results and compare them with the future test runs.
 
 3. In case you'd like to adjust some flags that are defaulted by setup_winrt script, go to "Manual build" section. Otherwise go to platforms/winrt and execute
 
diff --git a/samples/CMakeLists.txt b/samples/CMakeLists.txt
index 70b85ee..b1f98e9 100644
--- a/samples/CMakeLists.txt
+++ b/samples/CMakeLists.txt
@@ -22,6 +22,10 @@ if((NOT ANDROID) AND HAVE_OPENGL)
   add_subdirectory(opengl)
 endif()
 
+if(HAVE_OPENVX)
+  add_subdirectory(openvx)
+endif()
+
 if(UNIX AND NOT ANDROID AND (HAVE_VA OR HAVE_VA_INTEL))
   add_subdirectory(va_intel)
 endif()
diff --git a/samples/android/CMakeLists.txt b/samples/android/CMakeLists.txt
index 3913fd3..6135eaa 100644
--- a/samples/android/CMakeLists.txt
+++ b/samples/android/CMakeLists.txt
@@ -19,8 +19,8 @@ add_subdirectory(tutorial-4-opencl)
 # hello-android sample
 if(HAVE_opencv_highgui)
   add_executable(hello-android hello-android/main.cpp)
-  ocv_target_include_modules_recurse(hello-android opencv_imgcodecs opencv_videoio opencv_highgui opencv_core)
-  ocv_target_link_libraries(hello-android ${OPENCV_LINKER_LIBS} opencv_imgcodecs opencv_videoio opencv_highgui opencv_core)
+  ocv_target_include_modules_recurse(hello-android opencv_imgcodecs opencv_videoio opencv_highgui opencv_core opencv_imgproc)
+  ocv_target_link_libraries(hello-android ${OPENCV_LINKER_LIBS} opencv_imgcodecs opencv_videoio opencv_highgui opencv_core opencv_imgproc)
   set_target_properties(hello-android PROPERTIES OUTPUT_NAME hello-android RUNTIME_OUTPUT_DIRECTORY "${EXECUTABLE_OUTPUT_PATH}")
   add_dependencies(opencv_android_examples hello-android)
 endif()
diff --git a/samples/android/camera-calibration/src/org/opencv/samples/cameracalibration/CameraCalibrationActivity.java b/samples/android/camera-calibration/src/org/opencv/samples/cameracalibration/CameraCalibrationActivity.java
index aa90504..af0853a 100644
--- a/samples/android/camera-calibration/src/org/opencv/samples/cameracalibration/CameraCalibrationActivity.java
+++ b/samples/android/camera-calibration/src/org/opencv/samples/cameracalibration/CameraCalibrationActivity.java
@@ -2,7 +2,7 @@
 // http://docs.opencv.org/doc/tutorials/calib3d/camera_calibration/camera_calibration.html
 //
 // It uses standard OpenCV asymmetric circles grid pattern 11x4:
-// https://github.com/Itseez/opencv/blob/2.4/doc/acircles_pattern.png.
+// https://github.com/opencv/opencv/blob/2.4/doc/acircles_pattern.png.
 // The results are the camera matrix and 5 distortion coefficients.
 //
 // Tap on highlighted pattern to capture pattern corners for calibration.
diff --git a/samples/android/face-detection/jni/DetectionBasedTracker_jni.cpp b/samples/android/face-detection/jni/DetectionBasedTracker_jni.cpp
index 9fd8494..7d198dc 100644
--- a/samples/android/face-detection/jni/DetectionBasedTracker_jni.cpp
+++ b/samples/android/face-detection/jni/DetectionBasedTracker_jni.cpp
@@ -1,5 +1,5 @@
 #include <DetectionBasedTracker_jni.h>
-#include <opencv2/core/core.hpp>
+#include <opencv2/core.hpp>
 #include <opencv2/objdetect.hpp>
 
 #include <string>
diff --git a/samples/android/tutorial-2-mixedprocessing/jni/jni_part.cpp b/samples/android/tutorial-2-mixedprocessing/jni/jni_part.cpp
index 2c09961..72fa0b2 100644
--- a/samples/android/tutorial-2-mixedprocessing/jni/jni_part.cpp
+++ b/samples/android/tutorial-2-mixedprocessing/jni/jni_part.cpp
@@ -1,7 +1,7 @@
 #include <jni.h>
-#include <opencv2/core/core.hpp>
-#include <opencv2/imgproc/imgproc.hpp>
-#include <opencv2/features2d/features2d.hpp>
+#include <opencv2/core.hpp>
+#include <opencv2/imgproc.hpp>
+#include <opencv2/features2d.hpp>
 #include <vector>
 
 using namespace std;
diff --git a/samples/cpp/3calibration.cpp b/samples/cpp/3calibration.cpp
index 12f2c81..8affef1 100644
--- a/samples/cpp/3calibration.cpp
+++ b/samples/cpp/3calibration.cpp
@@ -2,10 +2,10 @@
  * 3calibration.cpp -- Calibrate 3 cameras in a horizontal line together.
  */
 
-#include "opencv2/calib3d/calib3d.hpp"
-#include "opencv2/imgproc/imgproc.hpp"
-#include "opencv2/imgcodecs/imgcodecs.hpp"
-#include "opencv2/highgui/highgui.hpp"
+#include "opencv2/calib3d.hpp"
+#include "opencv2/imgproc.hpp"
+#include "opencv2/imgcodecs.hpp"
+#include "opencv2/highgui.hpp"
 #include "opencv2/core/utility.hpp"
 
 #include <stdio.h>
@@ -351,7 +351,7 @@ int main( int argc, char** argv )
         for( k = 0; k < small_canvas.rows; k += 16 )
             line(small_canvas, Point(0, k), Point(small_canvas.cols, k), Scalar(0,255,0), 1);
         imshow("rectified", small_canvas);
-        int c = waitKey(0);
+        char c = (char)waitKey(0);
         if( c == 27 || c == 'q' || c == 'Q' )
             break;
     }
diff --git a/samples/cpp/CMakeLists.txt b/samples/cpp/CMakeLists.txt
index d93d019..c75a5c7 100644
--- a/samples/cpp/CMakeLists.txt
+++ b/samples/cpp/CMakeLists.txt
@@ -31,7 +31,8 @@ if(BUILD_EXAMPLES AND OCV_DEPENDENCIES_FOUND)
   endif()
 
   if(CMAKE_COMPILER_IS_GNUCXX AND NOT ENABLE_NOISY_WARNINGS)
-    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-unused-function")
+    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-unused-function -Wno-missing-declarations")
+    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unused-function -Wno-missing-declarations")
   endif()
 
   # ---------------------------------------------
@@ -57,8 +58,10 @@ if(BUILD_EXAMPLES AND OCV_DEPENDENCIES_FOUND)
       ocv_target_link_libraries(${the_target} opencv_cudaarithm opencv_cudafilters)
     endif()
 
-    if(HAVE_opencv_ocl)
-      ocv_target_link_libraries(${the_target} opencv_ocl)
+    if("${srcs}" MATCHES "viz/" AND VTK_USE_FILE)
+      include(${VTK_USE_FILE})
+      ocv_target_link_libraries(${the_target} ${VTK_LIBRARIES})
+      add_definitions(-DUSE_VTK)
     endif()
 
     set_target_properties(${the_target} PROPERTIES
@@ -88,7 +91,9 @@ if(BUILD_EXAMPLES AND OCV_DEPENDENCIES_FOUND)
     ocv_list_filterout(cpp_samples "/gpu/")
   endif()
 
-  ocv_list_filterout(cpp_samples "viz")
+  if(NOT TARGET opencv_viz)
+    ocv_list_filterout(cpp_samples "/viz/")
+  endif()
 
   if(NOT HAVE_IPP_A)
     ocv_list_filterout(cpp_samples "/ippasync/")
diff --git a/samples/cpp/calibration.cpp b/samples/cpp/calibration.cpp
index 415d8bb..251ab83 100644
--- a/samples/cpp/calibration.cpp
+++ b/samples/cpp/calibration.cpp
@@ -493,9 +493,9 @@ int main( int argc, char** argv )
         }
 
         imshow("Image View", view);
-        int key = 0xff & waitKey(capture.isOpened() ? 50 : 500);
+        char key = (char)waitKey(capture.isOpened() ? 50 : 500);
 
-        if( (key & 255) == 27 )
+        if( key == 27 )
             break;
 
         if( key == 'u' && mode == CALIBRATED )
@@ -536,8 +536,8 @@ int main( int argc, char** argv )
             //undistort( view, rview, cameraMatrix, distCoeffs, cameraMatrix );
             remap(view, rview, map1, map2, INTER_LINEAR);
             imshow("Image View", rview);
-            int c = 0xff & waitKey();
-            if( (c & 255) == 27 || c == 'q' || c == 'Q' )
+            char c = (char)waitKey();
+            if( c == 27 || c == 'q' || c == 'Q' )
                 break;
         }
     }
diff --git a/samples/cpp/camshiftdemo.cpp b/samples/cpp/camshiftdemo.cpp
index 4286e25..22ce7f8 100644
--- a/samples/cpp/camshiftdemo.cpp
+++ b/samples/cpp/camshiftdemo.cpp
@@ -20,6 +20,7 @@ Point origin;
 Rect selection;
 int vmin = 10, vmax = 256, smin = 30;
 
+// User draws box around object to track. This triggers CAMShift to start tracking
 static void onMouse( int event, int x, int y, int, void* )
 {
     if( selectObject )
@@ -42,7 +43,7 @@ static void onMouse( int event, int x, int y, int, void* )
     case EVENT_LBUTTONUP:
         selectObject = false;
         if( selection.width > 0 && selection.height > 0 )
-            trackObject = -1;
+            trackObject = -1;   // Set up CAMShift properties in main() loop
         break;
     }
 }
@@ -133,12 +134,13 @@ int main( int argc, const char** argv )
 
                 if( trackObject < 0 )
                 {
+                    // Object has been selected by user, set up CAMShift search properties once
                     Mat roi(hue, selection), maskroi(mask, selection);
                     calcHist(&roi, 1, 0, maskroi, hist, 1, &hsize, &phranges);
                     normalize(hist, hist, 0, 255, NORM_MINMAX);
 
                     trackWindow = selection;
-                    trackObject = 1;
+                    trackObject = 1; // Don't set up again, unless user selects new ROI
 
                     histimg = Scalar::all(0);
                     int binW = histimg.cols / hsize;
@@ -156,6 +158,7 @@ int main( int argc, const char** argv )
                     }
                 }
 
+                // Perform CAMShift
                 calcBackProject(&hue, 1, 0, hist, backproj, &phranges);
                 backproj &= mask;
                 RotatedRect trackBox = CamShift(backproj, trackWindow,
diff --git a/samples/cpp/cloning_gui.cpp b/samples/cpp/cloning_gui.cpp
index 289eae8..4358abc 100644
--- a/samples/cpp/cloning_gui.cpp
+++ b/samples/cpp/cloning_gui.cpp
@@ -453,7 +453,7 @@ int main()
 
     for(;;)
     {
-        char key = (char) waitKey(0);
+        char key = (char)waitKey(0);
 
         if(key == 'd' && flag3 == 0)
         {
diff --git a/samples/cpp/contours2.cpp b/samples/cpp/contours2.cpp
index c5a1fa7..437f76c 100644
--- a/samples/cpp/contours2.cpp
+++ b/samples/cpp/contours2.cpp
@@ -1,5 +1,5 @@
-#include "opencv2/imgproc/imgproc.hpp"
-#include "opencv2/highgui/highgui.hpp"
+#include "opencv2/imgproc.hpp"
+#include "opencv2/highgui.hpp"
 #include <math.h>
 #include <iostream>
 
diff --git a/samples/cpp/convexhull.cpp b/samples/cpp/convexhull.cpp
index 36e5544..f89e5b2 100644
--- a/samples/cpp/convexhull.cpp
+++ b/samples/cpp/convexhull.cpp
@@ -1,6 +1,5 @@
-#include "opencv2/imgproc/imgproc.hpp"
-#include "opencv2/highgui/highgui.hpp"
-#include <fstream>
+#include "opencv2/imgproc.hpp"
+#include "opencv2/highgui.hpp"
 #include <iostream>
 
 using namespace cv;
@@ -26,7 +25,6 @@ int main( int argc, char** argv )
 
     for(;;)
     {
-        char key;
         int i, count = (unsigned)rng%100 + 1;
 
         vector<Point> points;
@@ -59,7 +57,7 @@ int main( int argc, char** argv )
 
         imshow("hull", img);
 
-        key = (char)waitKey();
+        char key = (char)waitKey();
         if( key == 27 || key == 'q' || key == 'Q' ) // 'ESC'
             break;
     }
diff --git a/samples/cpp/cout_mat.cpp b/samples/cpp/cout_mat.cpp
index bf1dfb2..ed2cd71 100644
--- a/samples/cpp/cout_mat.cpp
+++ b/samples/cpp/cout_mat.cpp
@@ -5,7 +5,7 @@
  *
  */
 
-#include "opencv2/core/core.hpp"
+#include "opencv2/core.hpp"
 #include <iostream>
 
 using namespace std;
diff --git a/samples/cpp/dbt_face_detection.cpp b/samples/cpp/dbt_face_detection.cpp
index d7409bf..be61b87 100644
--- a/samples/cpp/dbt_face_detection.cpp
+++ b/samples/cpp/dbt_face_detection.cpp
@@ -1,11 +1,11 @@
-#if defined(__linux__) || defined(LINUX) || defined(__APPLE__) || defined(ANDROID)
+#if defined(__linux__) || defined(LINUX) || defined(__APPLE__) || defined(ANDROID) || (defined(_MSC_VER) && _MSC_VER>=1800)
 
-#include <opencv2/imgproc/imgproc.hpp>  // Gaussian Blur
-#include <opencv2/core/core.hpp>        // Basic OpenCV structures (cv::Mat, Scalar)
-#include <opencv2/videoio/videoio.hpp>
-#include <opencv2/highgui/highgui.hpp>  // OpenCV window I/O
-#include <opencv2/features2d/features2d.hpp>
-#include <opencv2/objdetect/objdetect.hpp>
+#include <opencv2/imgproc.hpp>  // Gaussian Blur
+#include <opencv2/core.hpp>        // Basic OpenCV structures (cv::Mat, Scalar)
+#include <opencv2/videoio.hpp>
+#include <opencv2/highgui.hpp>  // OpenCV window I/O
+#include <opencv2/features2d.hpp>
+#include <opencv2/objdetect.hpp>
 
 #include <stdio.h>
 #include <string>
@@ -54,9 +54,19 @@ int main(int , char** )
     std::string cascadeFrontalfilename = "../../data/lbpcascades/lbpcascade_frontalface.xml";
     cv::Ptr<cv::CascadeClassifier> cascade = makePtr<cv::CascadeClassifier>(cascadeFrontalfilename);
     cv::Ptr<DetectionBasedTracker::IDetector> MainDetector = makePtr<CascadeDetectorAdapter>(cascade);
+    if ( cascade->empty() )
+    {
+      printf("Error: Cannot load %s\n", cascadeFrontalfilename.c_str());
+      return 2;
+    }
 
     cascade = makePtr<cv::CascadeClassifier>(cascadeFrontalfilename);
     cv::Ptr<DetectionBasedTracker::IDetector> TrackingDetector = makePtr<CascadeDetectorAdapter>(cascade);
+    if ( cascade->empty() )
+    {
+      printf("Error: Cannot load %s\n", cascadeFrontalfilename.c_str());
+      return 2;
+    }
 
     DetectionBasedTracker::Parameters params;
     DetectionBasedTracker Detector(MainDetector, TrackingDetector, params);
@@ -71,7 +81,7 @@ int main(int , char** )
     Mat GrayFrame;
     vector<Rect> Faces;
 
-    while(true)
+    do
     {
         VideoStream >> ReferenceFrame;
         cvtColor(ReferenceFrame, GrayFrame, COLOR_RGB2GRAY);
@@ -84,9 +94,7 @@ int main(int , char** )
         }
 
         imshow(WindowName, ReferenceFrame);
-
-        if (waitKey(30) >= 0) break;
-    }
+    } while (waitKey(30) < 0);
 
     Detector.stop();
 
@@ -98,7 +106,7 @@ int main(int , char** )
 #include <stdio.h>
 int main()
 {
-    printf("This sample works for UNIX or ANDROID only\n");
+    printf("This sample works for UNIX or ANDROID or Visual Studio 2013+ only\n");
     return 0;
 }
 
diff --git a/samples/cpp/delaunay2.cpp b/samples/cpp/delaunay2.cpp
index a370feb..4807cd3 100644
--- a/samples/cpp/delaunay2.cpp
+++ b/samples/cpp/delaunay2.cpp
@@ -1,5 +1,5 @@
-#include <opencv2/imgproc/imgproc.hpp>
-#include <opencv2/highgui/highgui.hpp>
+#include <opencv2/imgproc.hpp>
+#include <opencv2/highgui.hpp>
 #include <iostream>
 
 using namespace cv;
diff --git a/samples/cpp/detect_blob.cpp b/samples/cpp/detect_blob.cpp
index 879b47e..6abe03b 100644
--- a/samples/cpp/detect_blob.cpp
+++ b/samples/cpp/detect_blob.cpp
@@ -21,14 +21,14 @@ static String Legende(SimpleBlobDetector::Params &pAct)
     String s = "";
     if (pAct.filterByArea)
     {
-        String inf = static_cast<ostringstream*>(&(ostringstream() << pAct.minArea))->str();
-        String sup = static_cast<ostringstream*>(&(ostringstream() << pAct.maxArea))->str();
+        String inf = static_cast<const ostringstream&>(ostringstream() << pAct.minArea).str();
+        String sup = static_cast<const ostringstream&>(ostringstream() << pAct.maxArea).str();
         s = " Area range [" + inf + " to  " + sup + "]";
     }
     if (pAct.filterByCircularity)
     {
-        String inf = static_cast<ostringstream*>(&(ostringstream() << pAct.minCircularity))->str();
-        String sup = static_cast<ostringstream*>(&(ostringstream() << pAct.maxCircularity))->str();
+        String inf = static_cast<const ostringstream&>(ostringstream() << pAct.minCircularity).str();
+        String sup = static_cast<const ostringstream&>(ostringstream() << pAct.maxCircularity).str();
         if (s.length() == 0)
             s = " Circularity range [" + inf + " to  " + sup + "]";
         else
@@ -36,7 +36,7 @@ static String Legende(SimpleBlobDetector::Params &pAct)
     }
     if (pAct.filterByColor)
     {
-        String inf = static_cast<ostringstream*>(&(ostringstream() << (int)pAct.blobColor))->str();
+        String inf = static_cast<const ostringstream&>(ostringstream() << (int)pAct.blobColor).str();
         if (s.length() == 0)
             s = " Blob color " + inf;
         else
@@ -44,8 +44,8 @@ static String Legende(SimpleBlobDetector::Params &pAct)
     }
     if (pAct.filterByConvexity)
     {
-        String inf = static_cast<ostringstream*>(&(ostringstream() << pAct.minConvexity))->str();
-        String sup = static_cast<ostringstream*>(&(ostringstream() << pAct.maxConvexity))->str();
+        String inf = static_cast<const ostringstream&>(ostringstream() << pAct.minConvexity).str();
+        String sup = static_cast<const ostringstream&>(ostringstream() << pAct.maxConvexity).str();
         if (s.length() == 0)
             s = " Convexity range[" + inf + " to  " + sup + "]";
         else
@@ -53,8 +53,8 @@ static String Legende(SimpleBlobDetector::Params &pAct)
     }
     if (pAct.filterByInertia)
     {
-        String inf = static_cast<ostringstream*>(&(ostringstream() << pAct.minInertiaRatio))->str();
-        String sup = static_cast<ostringstream*>(&(ostringstream() << pAct.maxInertiaRatio))->str();
+        String inf = static_cast<const ostringstream&>(ostringstream() << pAct.minInertiaRatio).str();
+        String sup = static_cast<const ostringstream&>(ostringstream() << pAct.maxInertiaRatio).str();
         if (s.length() == 0)
             s = " Inertia ratio range [" + inf + " to  " + sup + "]";
         else
@@ -159,14 +159,14 @@ int main(int argc, char *argv[])
     String label;
     // Descriptor loop
     vector<String>::iterator itDesc;
-    for (itDesc = typeDesc.begin(); itDesc != typeDesc.end(); itDesc++)
+    for (itDesc = typeDesc.begin(); itDesc != typeDesc.end(); ++itDesc)
     {
         vector<KeyPoint> keyImg1;
         if (*itDesc == "BLOB")
         {
             b = SimpleBlobDetector::create(*itBLOB);
             label = Legende(*itBLOB);
-            itBLOB++;
+            ++itBLOB;
         }
         try
         {
@@ -181,7 +181,7 @@ int main(int argc, char *argv[])
                 sbd->detect(img, keyImg, Mat());
                 drawKeypoints(img, keyImg, result);
                 int i = 0;
-                for (vector<KeyPoint>::iterator k = keyImg.begin(); k != keyImg.end(); k++, i++)
+                for (vector<KeyPoint>::iterator k = keyImg.begin(); k != keyImg.end(); ++k, ++i)
                     circle(result, k->pt, (int)k->size, palette[i % 65536]);
             }
             namedWindow(*itDesc + label, WINDOW_AUTOSIZE);
diff --git a/samples/cpp/detect_mser.cpp b/samples/cpp/detect_mser.cpp
index a9a3fa3..04429cc 100644
--- a/samples/cpp/detect_mser.cpp
+++ b/samples/cpp/detect_mser.cpp
@@ -73,32 +73,34 @@ struct MSERParams
 static String Legende(MSERParams &pAct)
 {
     String s="";
-    String inf = static_cast<ostringstream*>(&(ostringstream() << pAct.minArea))->str();
-    String sup = static_cast<ostringstream*>(&(ostringstream() << pAct.maxArea))->str();
+    String inf = static_cast<const ostringstream&>(ostringstream() << pAct.minArea).str();
+    String sup = static_cast<const ostringstream&>(ostringstream() << pAct.maxArea).str();
     s = " Area[" + inf + "," + sup + "]";
 
-    inf = static_cast<ostringstream*>(&(ostringstream() << pAct.delta))->str();
+    inf = static_cast<const ostringstream&>(ostringstream() << pAct.delta).str();
     s += " del. [" + inf + "]";
-    inf = static_cast<ostringstream*>(&(ostringstream() << pAct.maxVariation))->str();
+    inf = static_cast<const ostringstream&>(ostringstream() << pAct.maxVariation).str();
     s += " var. [" + inf + "]";
-    inf = static_cast<ostringstream*>(&(ostringstream() << (int)pAct.minDiversity))->str();
+    inf = static_cast<const ostringstream&>(ostringstream() << (int)pAct.minDiversity).str();
     s += " div. [" + inf + "]";
-    inf = static_cast<ostringstream*>(&(ostringstream() << (int)pAct.pass2Only))->str();
+    inf = static_cast<const ostringstream&>(ostringstream() << (int)pAct.pass2Only).str();
     s += " pas. [" + inf + "]";
-    inf = static_cast<ostringstream*>(&(ostringstream() << (int)pAct.maxEvolution))->str();
+    inf = static_cast<const ostringstream&>(ostringstream() << (int)pAct.maxEvolution).str();
     s += "RGb-> evo. [" + inf + "]";
-    inf = static_cast<ostringstream*>(&(ostringstream() << (int)pAct.areaThreshold))->str();
+    inf = static_cast<const ostringstream&>(ostringstream() << (int)pAct.areaThreshold).str();
     s += " are. [" + inf + "]";
-    inf = static_cast<ostringstream*>(&(ostringstream() << (int)pAct.minMargin))->str();
+    inf = static_cast<const ostringstream&>(ostringstream() << (int)pAct.minMargin).str();
     s += " mar. [" + inf + "]";
-    inf = static_cast<ostringstream*>(&(ostringstream() << (int)pAct.edgeBlurSize))->str();
+    inf = static_cast<const ostringstream&>(ostringstream() << (int)pAct.edgeBlurSize).str();
     s += " siz. [" + inf + "]";
     return s;
 }
 
 
+#ifdef HAVE_OPENGL
 const int win_width = 800;
 const int win_height = 640;
+#endif
 bool    rotateEnable=true;
 bool    keyPressed=false;
 
@@ -187,7 +189,7 @@ static void onMouse(int event, int x, int y, int flags, void*)
         else
             rObs -= (float)0.1;
     }
-    float pi = (float)acos(-1.0);
+    float pi = static_cast<float>(CV_PI);
     if (thetaObs>pi)
     {
         thetaObs = -2 * pi + thetaObs;
@@ -277,12 +279,12 @@ static void DrawOpenGLMSER(Mat img, Mat result)
     for (;;)
         {
         updateWindow("OpenGL");
-        int key = waitKey(40);
-        if ((key & 0xff) == 27)
+        char key = (char)waitKey(40);
+        if (key == 27)
             break;
         if (key == 0x20)
             rotateEnable = !rotateEnable;
-        float	pi = (float)acos(-1);
+        float pi = static_cast<float>(CV_PI);
 
         switch (key) {
             case '5':
@@ -466,7 +468,7 @@ int main(int argc, char *argv[])
     // Descriptor loop
     vector<String>::iterator itDesc;
     Mat result(img.rows, img.cols, CV_8UC3);
-    for (itDesc = typeDesc.begin(); itDesc != typeDesc.end(); itDesc++)
+    for (itDesc = typeDesc.begin(); itDesc != typeDesc.end(); ++itDesc)
     {
         vector<KeyPoint> keyImg1;
         if (*itDesc == "MSER"){
@@ -475,7 +477,7 @@ int main(int argc, char *argv[])
                 b = MSER::create(itMSER->delta, itMSER->minArea, itMSER->maxArea, itMSER->maxVariation, itMSER->minDiversity, itMSER->maxEvolution,
                                  itMSER->areaThreshold, itMSER->minMargin, itMSER->edgeBlurSize);
                 label = Legende(*itMSER);
-                itMSER++;
+                ++itMSER;
 
             }
             else
@@ -483,7 +485,7 @@ int main(int argc, char *argv[])
                 b = MSER::create(itMSER->delta, itMSER->minArea, itMSER->maxArea, itMSER->maxVariation, itMSER->minDiversity);
                 b.dynamicCast<MSER>()->setPass2Only(itMSER->pass2Only);
                 label = Legende(*itMSER);
-                itMSER++;
+                ++itMSER;
             }
         }
         if (img.type()==CV_8UC3)
@@ -513,9 +515,9 @@ int main(int argc, char *argv[])
                 int i = 0;
                 //result = Scalar(0, 0, 0);
                 int nbPixelInMSER=0;
-                for (vector<vector <Point> >::iterator itr = region.begin(); itr != region.end(); itr++, i++)
+                for (vector<vector <Point> >::iterator itr = region.begin(); itr != region.end(); ++itr, ++i)
                 {
-                    for (vector <Point>::iterator itp = region[i].begin(); itp != region[i].end(); itp ++)
+                    for (vector <Point>::iterator itp = region[i].begin(); itp != region[i].end(); ++itp)
                     {
                         // all pixels belonging to region become blue
                         result.at<Vec3b>(itp->y, itp->x) = Vec3b(128, 0, 0);
diff --git a/samples/cpp/distrans.cpp b/samples/cpp/distrans.cpp
index 4bf4707..2143264 100644
--- a/samples/cpp/distrans.cpp
+++ b/samples/cpp/distrans.cpp
@@ -133,7 +133,7 @@ int main( int argc, const char** argv )
         // Call to update the view
         onTrackbar(0, 0);
 
-        int c = waitKey(0) & 255;
+        char c = (char)waitKey(0);
 
         if( c == 27 )
             break;
diff --git a/samples/cpp/edge.cpp b/samples/cpp/edge.cpp
index 88abd8b..4fbef93 100644
--- a/samples/cpp/edge.cpp
+++ b/samples/cpp/edge.cpp
@@ -9,19 +9,34 @@ using namespace cv;
 using namespace std;
 
 int edgeThresh = 1;
-Mat image, gray, edge, cedge;
+int edgeThreshScharr=1;
+
+Mat image, gray, blurImage, edge1, edge2, cedge;
+
+const char* window_name1 = "Edge map : Canny default (Sobel gradient)";
+const char* window_name2 = "Edge map : Canny with custom gradient (Scharr)";
 
 // define a trackbar callback
 static void onTrackbar(int, void*)
 {
-    blur(gray, edge, Size(3,3));
+    blur(gray, blurImage, Size(3,3));
 
     // Run the edge detector on grayscale
-    Canny(edge, edge, edgeThresh, edgeThresh*3, 3);
+    Canny(blurImage, edge1, edgeThresh, edgeThresh*3, 3);
     cedge = Scalar::all(0);
 
-    image.copyTo(cedge, edge);
-    imshow("Edge map", cedge);
+    image.copyTo(cedge, edge1);
+    imshow(window_name1, cedge);
+
+    /// Canny detector with scharr
+    Mat dx,dy;
+    Scharr(blurImage,dx,CV_16S,1,0);
+    Scharr(blurImage,dy,CV_16S,0,1);
+    Canny( dx,dy, edge2, edgeThreshScharr, edgeThreshScharr*3 );
+    /// Using Canny's output as a mask, we display our result
+    cedge = Scalar::all(0);
+    image.copyTo(cedge, edge2);
+    imshow(window_name2, cedge);
 }
 
 static void help()
@@ -57,10 +72,12 @@ int main( int argc, const char** argv )
     cvtColor(image, gray, COLOR_BGR2GRAY);
 
     // Create a window
-    namedWindow("Edge map", 1);
+    namedWindow(window_name1, 1);
+    namedWindow(window_name2, 1);
 
     // create a toolbar
-    createTrackbar("Canny threshold", "Edge map", &edgeThresh, 100, onTrackbar);
+    createTrackbar("Canny threshold default", window_name1, &edgeThresh, 100, onTrackbar);
+    createTrackbar("Canny threshold Scharr", window_name2, &edgeThreshScharr, 400, onTrackbar);
 
     // Show the image
     onTrackbar(0, 0);
diff --git a/samples/cpp/facedetect.cpp b/samples/cpp/facedetect.cpp
index 39717b7..86d3284 100644
--- a/samples/cpp/facedetect.cpp
+++ b/samples/cpp/facedetect.cpp
@@ -72,9 +72,9 @@ int main( int argc, const char** argv )
     }
     if( inputName.empty() || (isdigit(inputName[0]) && inputName.size() == 1) )
     {
-        int c = inputName.empty() ? 0 : inputName[0] - '0';
-        if(!capture.open(c))
-            cout << "Capture from camera #" <<  c << " didn't work" << endl;
+        int camera = inputName.empty() ? 0 : inputName[0] - '0';
+        if(!capture.open(camera))
+            cout << "Capture from camera #" <<  camera << " didn't work" << endl;
     }
     else if( inputName.size() )
     {
@@ -104,7 +104,7 @@ int main( int argc, const char** argv )
             Mat frame1 = frame.clone();
             detectAndDraw( frame1, cascade, nestedCascade, scale, tryflip );
 
-            int c = waitKey(10);
+            char c = (char)waitKey(10);
             if( c == 27 || c == 'q' || c == 'Q' )
                 break;
         }
@@ -127,7 +127,7 @@ int main( int argc, const char** argv )
                 char buf[1000+1];
                 while( fgets( buf, 1000, f ) )
                 {
-                    int len = (int)strlen(buf), c;
+                    int len = (int)strlen(buf);
                     while( len > 0 && isspace(buf[len-1]) )
                         len--;
                     buf[len] = '\0';
@@ -136,7 +136,7 @@ int main( int argc, const char** argv )
                     if( !image.empty() )
                     {
                         detectAndDraw( image, cascade, nestedCascade, scale, tryflip );
-                        c = waitKey(0);
+                        char c = (char)waitKey(0);
                         if( c == 27 || c == 'q' || c == 'Q' )
                             break;
                     }
@@ -177,7 +177,7 @@ void detectAndDraw( Mat& img, CascadeClassifier& cascade,
     resize( gray, smallImg, Size(), fx, fx, INTER_LINEAR );
     equalizeHist( smallImg, smallImg );
 
-    t = (double)cvGetTickCount();
+    t = (double)getTickCount();
     cascade.detectMultiScale( smallImg, faces,
         1.1, 2, 0
         //|CASCADE_FIND_BIGGEST_OBJECT
@@ -193,13 +193,13 @@ void detectAndDraw( Mat& img, CascadeClassifier& cascade,
                                  //|CASCADE_DO_ROUGH_SEARCH
                                  |CASCADE_SCALE_IMAGE,
                                  Size(30, 30) );
-        for( vector<Rect>::const_iterator r = faces2.begin(); r != faces2.end(); r++ )
+        for( vector<Rect>::const_iterator r = faces2.begin(); r != faces2.end(); ++r )
         {
             faces.push_back(Rect(smallImg.cols - r->x - r->width, r->y, r->width, r->height));
         }
     }
-    t = (double)cvGetTickCount() - t;
-    printf( "detection time = %g ms\n", t/((double)cvGetTickFrequency()*1000.) );
+    t = (double)getTickCount() - t;
+    printf( "detection time = %g ms\n", t*1000/getTickFrequency());
     for ( size_t i = 0; i < faces.size(); i++ )
     {
         Rect r = faces[i];
diff --git a/samples/cpp/facial_features.cpp b/samples/cpp/facial_features.cpp
index f46fa3f..6dbef75 100644
--- a/samples/cpp/facial_features.cpp
+++ b/samples/cpp/facial_features.cpp
@@ -6,9 +6,9 @@
  *
  */
 
-#include "opencv2/objdetect/objdetect.hpp"
-#include "opencv2/highgui/highgui.hpp"
-#include "opencv2/imgproc/imgproc.hpp"
+#include "opencv2/objdetect.hpp"
+#include "opencv2/highgui.hpp"
+#include "opencv2/imgproc.hpp"
 
 #include <iostream>
 #include <cstdio>
@@ -89,10 +89,10 @@ static void help()
         "\tThis will detect only the face in image.jpg.\n";
 
     cout << " \n\nThe classifiers for face and eyes can be downloaded from : "
-        " \nhttps://github.com/Itseez/opencv/tree/master/data/haarcascades";
+        " \nhttps://github.com/opencv/opencv/tree/master/data/haarcascades";
 
     cout << "\n\nThe classifiers for nose and mouth can be downloaded from : "
-        " \nhttps://github.com/Itseez/opencv_contrib/tree/master/modules/face/data/cascades\n";
+        " \nhttps://github.com/opencv/opencv_contrib/tree/master/modules/face/data/cascades\n";
 }
 
 static void detectFaces(Mat& img, vector<Rect_<int> >& faces, string cascade_path)
diff --git a/samples/cpp/fback.cpp b/samples/cpp/fback.cpp
index 5fbec69..a044844 100644
--- a/samples/cpp/fback.cpp
+++ b/samples/cpp/fback.cpp
@@ -1,7 +1,7 @@
 #include "opencv2/video/tracking.hpp"
-#include "opencv2/imgproc/imgproc.hpp"
-#include "opencv2/videoio/videoio.hpp"
-#include "opencv2/highgui/highgui.hpp"
+#include "opencv2/imgproc.hpp"
+#include "opencv2/videoio.hpp"
+#include "opencv2/highgui.hpp"
 
 #include <iostream>
 
diff --git a/samples/cpp/ffilldemo.cpp b/samples/cpp/ffilldemo.cpp
index 93bdd67..0cf3155 100644
--- a/samples/cpp/ffilldemo.cpp
+++ b/samples/cpp/ffilldemo.cpp
@@ -1,7 +1,7 @@
-#include "opencv2/imgproc/imgproc.hpp"
+#include "opencv2/imgproc.hpp"
 #include "opencv2/imgcodecs.hpp"
-#include "opencv2/videoio/videoio.hpp"
-#include "opencv2/highgui/highgui.hpp"
+#include "opencv2/videoio.hpp"
+#include "opencv2/highgui.hpp"
 
 #include <iostream>
 
@@ -105,13 +105,13 @@ int main( int argc, char** argv )
     {
         imshow("image", isColor ? image : gray);
 
-        int c = waitKey(0);
-        if( (c & 255) == 27 )
+        char c = (char)waitKey(0);
+        if( c == 27 )
         {
             cout << "Exiting ...\n";
             break;
         }
-        switch( (char)c )
+        switch( c )
         {
         case 'c':
             if( isColor )
diff --git a/samples/cpp/filestorage.cpp b/samples/cpp/filestorage.cpp
index 60ea51a..46b4da2 100644
--- a/samples/cpp/filestorage.cpp
+++ b/samples/cpp/filestorage.cpp
@@ -2,7 +2,7 @@
  * filestorage_sample demonstrate the usage of the opencv serialization functionality
  */
 
-#include "opencv2/core/core.hpp"
+#include "opencv2/core.hpp"
 #include <iostream>
 #include <string>
 
diff --git a/samples/cpp/filestorage_base64.cpp b/samples/cpp/filestorage_base64.cpp
new file mode 100644
index 0000000..dcd4654
--- /dev/null
+++ b/samples/cpp/filestorage_base64.cpp
@@ -0,0 +1,71 @@
+#include "opencv2/core.hpp"
+#include <iostream>
+#include <string>
+
+static CvFileStorage * three_same_ways_of_write_base64()
+{
+    CvFileStorage * fs = 0;
+    cv::RNG rng;
+    switch ( rng.uniform( 0, 2 ) )
+    {
+    case 0:
+        //! [suffix_in_file_name]
+        fs = cvOpenFileStorage( "example.yml?base64", 0, CV_STORAGE_WRITE );
+        //! [suffix_in_file_name]
+        break;
+    case 1:
+        //! [flag_write_base64]
+        fs = cvOpenFileStorage( "example.yml"       , 0, CV_STORAGE_WRITE_BASE64 );
+        //! [flag_write_base64]
+        break;
+    case 2:
+        //! [flag_write_and_flag_base64]
+        fs = cvOpenFileStorage( "example.yml"       , 0, CV_STORAGE_WRITE | CV_STORAGE_BASE64 );
+        //! [flag_write_and_flag_base64]
+        break;
+    default:
+        break;
+    }
+    return fs;
+}
+
+static void two_ways_to_write_rawdata_in_base64()
+{
+    std::vector<int> rawdata(10, 0x00010203);
+
+    {   // [1]
+        //! [without_base64_flag]
+        CvFileStorage* fs = cvOpenFileStorage( "example.xml", 0, CV_STORAGE_WRITE );
+        // both CV_NODE_SEQ and "binary" are necessary.
+        cvStartWriteStruct(fs, "rawdata", CV_NODE_SEQ | CV_NODE_FLOW, "binary");
+        cvWriteRawDataBase64(fs, rawdata.data(), static_cast<int>(rawdata.size()), "i");
+        cvEndWriteStruct(fs);
+        cvReleaseFileStorage( &fs );
+        //! [without_base64_flag]
+    }
+
+    {   // [2]
+        //! [with_write_base64_flag]
+        CvFileStorage* fs = cvOpenFileStorage( "example.xml", 0, CV_STORAGE_WRITE_BASE64);
+        // parameter, typename "binary" could be omitted.
+        cvStartWriteStruct(fs, "rawdata", CV_NODE_SEQ | CV_NODE_FLOW);
+        cvWriteRawData(fs, rawdata.data(), static_cast<int>(rawdata.size()), "i");
+        cvEndWriteStruct(fs);
+        cvReleaseFileStorage( &fs );
+        //! [with_write_base64_flag]
+    }
+}
+
+int main(int /* argc */, char** /* argv */)
+{
+    {   // base64 mode
+        CvFileStorage * fs = three_same_ways_of_write_base64();
+        cvReleaseFileStorage( &fs );
+    }
+
+    {   // output rawdata by `cvWriteRawdata*`
+        two_ways_to_write_rawdata_in_base64();
+    }
+
+    return 0;
+}
diff --git a/samples/cpp/fitellipse.cpp b/samples/cpp/fitellipse.cpp
index b83f617..0cd6c4a 100644
--- a/samples/cpp/fitellipse.cpp
+++ b/samples/cpp/fitellipse.cpp
@@ -14,10 +14,11 @@
 *
 *
 ********************************************************************************/
-#include "opencv2/imgproc/imgproc.hpp"
+#include "opencv2/imgproc.hpp"
 #include "opencv2/imgcodecs.hpp"
-#include "opencv2/highgui/highgui.hpp"
+#include "opencv2/highgui.hpp"
 #include <iostream>
+
 using namespace cv;
 using namespace std;
 
diff --git a/samples/cpp/grabcut.cpp b/samples/cpp/grabcut.cpp
index b6b4060..54edbf6 100644
--- a/samples/cpp/grabcut.cpp
+++ b/samples/cpp/grabcut.cpp
@@ -1,6 +1,6 @@
 #include "opencv2/imgcodecs.hpp"
-#include "opencv2/highgui/highgui.hpp"
-#include "opencv2/imgproc/imgproc.hpp"
+#include "opencv2/highgui.hpp"
+#include "opencv2/imgproc.hpp"
 
 #include <iostream>
 
@@ -306,8 +306,8 @@ int main( int argc, char** argv )
 
     for(;;)
     {
-        int c = waitKey(0);
-        switch( (char) c )
+        char c = (char)waitKey(0);
+        switch( c )
         {
         case '\x1b':
             cout << "Exiting ..." << endl;
diff --git a/samples/cpp/houghcircles.cpp b/samples/cpp/houghcircles.cpp
index bdafffe..f749b0e 100644
--- a/samples/cpp/houghcircles.cpp
+++ b/samples/cpp/houghcircles.cpp
@@ -1,6 +1,6 @@
 #include "opencv2/imgcodecs.hpp"
-#include "opencv2/highgui/highgui.hpp"
-#include "opencv2/imgproc/imgproc.hpp"
+#include "opencv2/highgui.hpp"
+#include "opencv2/imgproc.hpp"
 
 #include <iostream>
 
@@ -24,39 +24,48 @@ int main(int argc, char** argv)
         help();
         return 0;
     }
+    //![load]
     string filename = parser.get<string>("@image");
-    if (filename.empty())
-    {
-        help();
-        cout << "no image_name provided" << endl;
-        return -1;
-    }
-    Mat img = imread(filename, 0);
+    Mat img = imread(filename, IMREAD_COLOR);
     if(img.empty())
     {
         help();
         cout << "can not open " << filename << endl;
         return -1;
     }
+    //![load]
+
+    //![convert_to_gray]
+    Mat gray;
+    cvtColor(img, gray, COLOR_BGR2GRAY);
+    //![convert_to_gray]
 
-    Mat cimg;
-    medianBlur(img, img, 5);
-    cvtColor(img, cimg, COLOR_GRAY2BGR);
+    //![reduce_noise]
+    medianBlur(gray, gray, 5);
+    //![reduce_noise]
 
+    //![houghcircles]
     vector<Vec3f> circles;
-    HoughCircles(img, circles, HOUGH_GRADIENT, 1, 10,
+    HoughCircles(gray, circles, HOUGH_GRADIENT, 1,
+                 gray.rows/16, // change this value to detect circles with different distances to each other
                  100, 30, 1, 30 // change the last two parameters
                                 // (min_radius & max_radius) to detect larger circles
                  );
+    //![houghcircles]
+
+    //![draw]
     for( size_t i = 0; i < circles.size(); i++ )
     {
         Vec3i c = circles[i];
-        circle( cimg, Point(c[0], c[1]), c[2], Scalar(0,0,255), 3, LINE_AA);
-        circle( cimg, Point(c[0], c[1]), 2, Scalar(0,255,0), 3, LINE_AA);
+        circle( img, Point(c[0], c[1]), c[2], Scalar(0,0,255), 3, LINE_AA);
+        circle( img, Point(c[0], c[1]), 2, Scalar(0,255,0), 3, LINE_AA);
     }
+    //![draw]
 
-    imshow("detected circles", cimg);
+    //![display]
+    imshow("detected circles", img);
     waitKey();
+    //![display]
 
     return 0;
 }
diff --git a/samples/cpp/houghlines.cpp b/samples/cpp/houghlines.cpp
index ddeb3bd..94eec86 100644
--- a/samples/cpp/houghlines.cpp
+++ b/samples/cpp/houghlines.cpp
@@ -1,6 +1,6 @@
 #include "opencv2/imgcodecs.hpp"
-#include "opencv2/highgui/highgui.hpp"
-#include "opencv2/imgproc/imgproc.hpp"
+#include "opencv2/highgui.hpp"
+#include "opencv2/imgproc.hpp"
 
 #include <iostream>
 
diff --git a/samples/cpp/image.cpp b/samples/cpp/image.cpp
index b5925c6..fc57738 100644
--- a/samples/cpp/image.cpp
+++ b/samples/cpp/image.cpp
@@ -1,7 +1,7 @@
 #include <stdio.h>
 #include <iostream>
-#include <opencv2/imgproc/imgproc.hpp>
-#include <opencv2/highgui/highgui.hpp>
+#include <opencv2/imgproc.hpp>
+#include <opencv2/highgui.hpp>
 #include <opencv2/core/utility.hpp>
 
 using namespace cv; // all the new API is put into "cv" namespace. Export its content
diff --git a/samples/cpp/image_sequence.cpp b/samples/cpp/image_sequence.cpp
index 14b63e3..6a84fab 100644
--- a/samples/cpp/image_sequence.cpp
+++ b/samples/cpp/image_sequence.cpp
@@ -1,6 +1,6 @@
-#include <opencv2/core/core.hpp>
-#include <opencv2/videoio/videoio.hpp>
-#include <opencv2/highgui/highgui.hpp>
+#include <opencv2/core.hpp>
+#include <opencv2/videoio.hpp>
+#include <opencv2/highgui.hpp>
 
 #include <iostream>
 
diff --git a/samples/cpp/imagelist_creator.cpp b/samples/cpp/imagelist_creator.cpp
index bdb0231..5b2dc38 100644
--- a/samples/cpp/imagelist_creator.cpp
+++ b/samples/cpp/imagelist_creator.cpp
@@ -1,9 +1,9 @@
 /*this creates a yaml or xml list of files from the command line args
  */
 
-#include "opencv2/core/core.hpp"
+#include "opencv2/core.hpp"
 #include "opencv2/imgcodecs.hpp"
-#include "opencv2/highgui/highgui.hpp"
+#include "opencv2/highgui.hpp"
 #include <string>
 #include <iostream>
 
diff --git a/samples/cpp/inpaint.cpp b/samples/cpp/inpaint.cpp
index 62d7521..86e6e37 100644
--- a/samples/cpp/inpaint.cpp
+++ b/samples/cpp/inpaint.cpp
@@ -1,7 +1,7 @@
 #include "opencv2/imgcodecs.hpp"
-#include "opencv2/highgui/highgui.hpp"
-#include "opencv2/imgproc/imgproc.hpp"
-#include "opencv2/photo/photo.hpp"
+#include "opencv2/highgui.hpp"
+#include "opencv2/imgproc.hpp"
+#include "opencv2/photo.hpp"
 
 #include <iostream>
 
diff --git a/samples/cpp/intelperc_capture.cpp b/samples/cpp/intelperc_capture.cpp
index daae442..d8a1c32 100644
--- a/samples/cpp/intelperc_capture.cpp
+++ b/samples/cpp/intelperc_capture.cpp
@@ -1,8 +1,8 @@
 // testOpenCVCam.cpp : Defines the entry point for the console application.
 //
 
-#include "opencv2/videoio/videoio.hpp"
-#include "opencv2/highgui/highgui.hpp"
+#include "opencv2/videoio.hpp"
+#include "opencv2/highgui.hpp"
 
 #include <iostream>
 
diff --git a/samples/cpp/kalman.cpp b/samples/cpp/kalman.cpp
index 8f9adc6..501a749 100644
--- a/samples/cpp/kalman.cpp
+++ b/samples/cpp/kalman.cpp
@@ -1,5 +1,5 @@
 #include "opencv2/video/tracking.hpp"
-#include "opencv2/highgui/highgui.hpp"
+#include "opencv2/highgui.hpp"
 
 #include <stdio.h>
 
diff --git a/samples/cpp/laplace.cpp b/samples/cpp/laplace.cpp
index b33b49c..958fccb 100644
--- a/samples/cpp/laplace.cpp
+++ b/samples/cpp/laplace.cpp
@@ -1,6 +1,6 @@
-#include "opencv2/videoio/videoio.hpp"
-#include "opencv2/highgui/highgui.hpp"
-#include "opencv2/imgproc/imgproc.hpp"
+#include "opencv2/videoio.hpp"
+#include "opencv2/highgui.hpp"
+#include "opencv2/imgproc.hpp"
 
 #include <ctype.h>
 #include <stdio.h>
@@ -83,10 +83,10 @@ int main( int argc, char** argv )
         convertScaleAbs(laplace, result, (sigma+1)*0.25);
         imshow("Laplacian", result);
 
-        int c = waitKey(30);
+        char c = (char)waitKey(30);
         if( c == ' ' )
             smoothType = smoothType == GAUSSIAN ? BLUR : smoothType == BLUR ? MEDIAN : GAUSSIAN;
-        if( c == 'q' || c == 'Q' || (c & 255) == 27 )
+        if( c == 'q' || c == 'Q' || c == 27 )
             break;
     }
 
diff --git a/samples/cpp/letter_recog.cpp b/samples/cpp/letter_recog.cpp
index 3d7e34a..0eb67d1 100644
--- a/samples/cpp/letter_recog.cpp
+++ b/samples/cpp/letter_recog.cpp
@@ -1,5 +1,5 @@
-#include "opencv2/core/core.hpp"
-#include "opencv2/ml/ml.hpp"
+#include "opencv2/core.hpp"
+#include "opencv2/ml.hpp"
 
 #include <cstdio>
 #include <vector>
diff --git a/samples/cpp/lkdemo.cpp b/samples/cpp/lkdemo.cpp
index 3881aa8..5e57aa8 100644
--- a/samples/cpp/lkdemo.cpp
+++ b/samples/cpp/lkdemo.cpp
@@ -1,7 +1,7 @@
 #include "opencv2/video/tracking.hpp"
-#include "opencv2/imgproc/imgproc.hpp"
-#include "opencv2/videoio/videoio.hpp"
-#include "opencv2/highgui/highgui.hpp"
+#include "opencv2/imgproc.hpp"
+#include "opencv2/videoio.hpp"
+#include "opencv2/highgui.hpp"
 
 #include <iostream>
 #include <ctype.h>
diff --git a/samples/cpp/lsd_lines.cpp b/samples/cpp/lsd_lines.cpp
index 4c8c7e0..e0db6c3 100644
--- a/samples/cpp/lsd_lines.cpp
+++ b/samples/cpp/lsd_lines.cpp
@@ -1,11 +1,8 @@
 #include <iostream>
-#include <string>
 
-#include "opencv2/core/core.hpp"
-#include "opencv2/core/utility.hpp"
-#include "opencv2/imgproc/imgproc.hpp"
+#include "opencv2/imgproc.hpp"
 #include "opencv2/imgcodecs.hpp"
-#include "opencv2/highgui/highgui.hpp"
+#include "opencv2/highgui.hpp"
 
 using namespace std;
 using namespace cv;
@@ -23,6 +20,9 @@ int main(int argc, char** argv)
 
     Mat image = imread(in, IMREAD_GRAYSCALE);
 
+    if( image.empty() )
+    { return -1; }
+
 #if 0
     Canny(image, image, 50, 200, 3); // Apply canny edge
 #endif
diff --git a/samples/cpp/matchmethod_orb_akaze_brisk.cpp b/samples/cpp/matchmethod_orb_akaze_brisk.cpp
index 379b53a..d96ad51 100644
--- a/samples/cpp/matchmethod_orb_akaze_brisk.cpp
+++ b/samples/cpp/matchmethod_orb_akaze_brisk.cpp
@@ -59,7 +59,7 @@ int main(int argc, char *argv[])
 
     // Descriptor loop
     vector<String>::iterator itDesc;
-    for (itDesc = typeDesc.begin(); itDesc != typeDesc.end(); itDesc++)
+    for (itDesc = typeDesc.begin(); itDesc != typeDesc.end(); ++itDesc)
     {
         Ptr<DescriptorMatcher> descriptorMatcher;
         // Match between img1 and img2
@@ -90,7 +90,7 @@ int main(int argc, char *argv[])
             // or detect and compute descriptors in one step
             b->detectAndCompute(img2, Mat(),keyImg2, descImg2,false);
             // Match method loop
-            for (itMatcher = typeAlgoMatch.begin(); itMatcher != typeAlgoMatch.end(); itMatcher++){
+            for (itMatcher = typeAlgoMatch.begin(); itMatcher != typeAlgoMatch.end(); ++itMatcher){
                 descriptorMatcher = DescriptorMatcher::create(*itMatcher);
                 if ((*itMatcher == "BruteForce-Hamming" || *itMatcher == "BruteForce-Hamming(2)") && (b->descriptorType() == CV_32F || b->defaultNorm() <= NORM_L2SQR))
                 {
@@ -135,7 +135,7 @@ int main(int argc, char *argv[])
                     cout << "in img1\tin img2\n";
                     // Use to compute distance between keyPoint matches and to evaluate match algorithm
                     double cumSumDist2=0;
-                    for (it = bestMatches.begin(); it != bestMatches.end(); it++)
+                    for (it = bestMatches.begin(); it != bestMatches.end(); ++it)
                     {
                         cout << it->queryIdx << "\t" <<  it->trainIdx << "\t"  <<  it->distance << "\n";
                         Point2d p=keyImg1[it->queryIdx].pt-keyImg2[it->trainIdx].pt;
@@ -165,15 +165,15 @@ int main(int argc, char *argv[])
     int i=0;
     cout << "Cumulative distance between keypoint match for different algorithm and feature detector \n\t";
     cout << "We cannot say which is the best but we can say results are differents! \n\t";
-    for (vector<String>::iterator itMatcher = typeAlgoMatch.begin(); itMatcher != typeAlgoMatch.end(); itMatcher++)
+    for (vector<String>::iterator itMatcher = typeAlgoMatch.begin(); itMatcher != typeAlgoMatch.end(); ++itMatcher)
     {
         cout<<*itMatcher<<"\t";
     }
     cout << "\n";
-    for (itDesc = typeDesc.begin(); itDesc != typeDesc.end(); itDesc++)
+    for (itDesc = typeDesc.begin(); itDesc != typeDesc.end(); ++itDesc)
     {
         cout << *itDesc << "\t";
-        for (vector<String>::iterator itMatcher = typeAlgoMatch.begin(); itMatcher != typeAlgoMatch.end(); itMatcher++, i++)
+        for (vector<String>::iterator itMatcher = typeAlgoMatch.begin(); itMatcher != typeAlgoMatch.end(); ++itMatcher, ++i)
         {
             cout << desMethCmp[i]<<"\t";
         }
diff --git a/samples/cpp/minarea.cpp b/samples/cpp/minarea.cpp
index 91ad5a3..ac79db5 100644
--- a/samples/cpp/minarea.cpp
+++ b/samples/cpp/minarea.cpp
@@ -1,5 +1,5 @@
-#include "opencv2/highgui/highgui.hpp"
-#include "opencv2/imgproc/imgproc.hpp"
+#include "opencv2/highgui.hpp"
+#include "opencv2/imgproc.hpp"
 
 #include <iostream>
 
diff --git a/samples/cpp/morphology2.cpp b/samples/cpp/morphology2.cpp
index 04e916c..b7dc68f 100644
--- a/samples/cpp/morphology2.cpp
+++ b/samples/cpp/morphology2.cpp
@@ -1,6 +1,6 @@
-#include "opencv2/imgproc/imgproc.hpp"
+#include "opencv2/imgproc.hpp"
 #include "opencv2/imgcodecs.hpp"
-#include "opencv2/highgui/highgui.hpp"
+#include "opencv2/highgui.hpp"
 #include <stdlib.h>
 #include <stdio.h>
 #include <string>
@@ -66,7 +66,7 @@ int main( int argc, char** argv )
         return 0;
     }
     std::string filename = parser.get<std::string>("@image");
-    if( (src = imread(filename,1)).empty() )
+    if( (src = imread(filename,IMREAD_COLOR)).empty() )
     {
         help();
         return -1;
@@ -82,21 +82,19 @@ int main( int argc, char** argv )
 
     for(;;)
     {
-        int c;
-
         OpenClose(open_close_pos, 0);
         ErodeDilate(erode_dilate_pos, 0);
-        c = waitKey(0);
+        char c = (char)waitKey(0);
 
-        if( (char)c == 27 )
+        if( c == 27 )
             break;
-        if( (char)c == 'e' )
+        if( c == 'e' )
             element_shape = MORPH_ELLIPSE;
-        else if( (char)c == 'r' )
+        else if( c == 'r' )
             element_shape = MORPH_RECT;
-        else if( (char)c == 'c' )
+        else if( c == 'c' )
             element_shape = MORPH_CROSS;
-        else if( (char)c == ' ' )
+        else if( c == ' ' )
             element_shape = (element_shape + 1) % 3;
     }
 
diff --git a/samples/cpp/neural_network.cpp b/samples/cpp/neural_network.cpp
new file mode 100644
index 0000000..d6e681b
--- /dev/null
+++ b/samples/cpp/neural_network.cpp
@@ -0,0 +1,65 @@
+#include <opencv2/ml/ml.hpp>
+
+using namespace std;
+using namespace cv;
+using namespace cv::ml;
+
+int main()
+{
+    //create random training data
+    Mat_<float> data(100, 100);
+    randn(data, Mat::zeros(1, 1, data.type()), Mat::ones(1, 1, data.type()));
+
+    //half of the samples for each class
+    Mat_<float> responses(data.rows, 2);
+    for (int i = 0; i<data.rows; ++i)
+    {
+        if (i < data.rows/2)
+        {
+            responses(i, 0) = 1;
+            responses(i, 1) = 0;
+        }
+        else
+        {
+            responses(i, 0) = 0;
+            responses(i, 1) = 1;
+        }
+    }
+
+    /*
+    //example code for just a single response (regression)
+    Mat_<float> responses(data.rows, 1);
+    for (int i=0; i<responses.rows; ++i)
+        responses(i, 0) = i < responses.rows / 2 ? 0 : 1;
+    */
+
+    //create the neural network
+    Mat_<int> layerSizes(1, 3);
+    layerSizes(0, 0) = data.cols;
+    layerSizes(0, 1) = 20;
+    layerSizes(0, 2) = responses.cols;
+
+    Ptr<ANN_MLP> network = ANN_MLP::create();
+    network->setLayerSizes(layerSizes);
+    network->setActivationFunction(ANN_MLP::SIGMOID_SYM, 0.1, 0.1);
+    network->setTrainMethod(ANN_MLP::BACKPROP, 0.1, 0.1);
+    Ptr<TrainData> trainData = TrainData::create(data, ROW_SAMPLE, responses);
+
+    network->train(trainData);
+    if (network->isTrained())
+    {
+        printf("Predict one-vector:\n");
+        Mat result;
+        network->predict(Mat::ones(1, data.cols, data.type()), result);
+        cout << result << endl;
+
+        printf("Predict training data:\n");
+        for (int i=0; i<data.rows; ++i)
+        {
+            network->predict(data.row(i), result);
+            cout << result << endl;
+        }
+    }
+
+    return 0;
+}
diff --git a/samples/cpp/openni_capture.cpp b/samples/cpp/openni_capture.cpp
index 70d4a7c..0d0a967 100644
--- a/samples/cpp/openni_capture.cpp
+++ b/samples/cpp/openni_capture.cpp
@@ -1,6 +1,6 @@
 #include "opencv2/videoio/videoio.hpp"
-#include "opencv2/highgui/highgui.hpp"
-#include "opencv2/imgproc/imgproc.hpp"
+#include "opencv2/highgui.hpp"
+#include "opencv2/imgproc.hpp"
 
 #include <iostream>
 
@@ -21,6 +21,8 @@ static void help()
             "2.) Data given from RGB image generator\n"
             "   CAP_OPENNI_BGR_IMAGE            - color image (CV_8UC3)\n"
             "   CAP_OPENNI_GRAY_IMAGE           - gray image (CV_8UC1)\n"
+            "2.) Data given from IR image generator\n"
+            "   CAP_OPENNI_IR_IMAGE             - gray image (CV_16UC1)\n"
          << endl;
 }
 
@@ -92,8 +94,8 @@ static void printCommandLineParams()
     cout << "-mode=     image mode: resolution and fps, supported three values:  0 - CAP_OPENNI_VGA_30HZ, 1 - CAP_OPENNI_SXGA_15HZ," << endl;
     cout << "          2 - CAP_OPENNI_SXGA_30HZ (0 by default). Ignored if rgb image or gray image are not selected to show." << endl;
     cout << "-m=        Mask to set which output images are need. It is a string of size 5. Each element of this is '0' or '1' and" << endl;
-    cout << "          determine: is depth map, disparity map, valid pixels mask, rgb image, gray image need or not (correspondently)?" << endl ;
-    cout << "          By default -m=01010 i.e. disparity map and rgb image will be shown." << endl ;
+    cout << "          determine: is depth map, disparity map, valid pixels mask, rgb image, gray image need or not (correspondently), ir image" << endl ;
+    cout << "          By default -m=010100 i.e. disparity map and rgb image will be shown." << endl ;
     cout << "-r=        Filename of .oni video file. The data will grabbed from it." << endl ;
 }
 
@@ -101,7 +103,7 @@ static void parseCommandLine( int argc, char* argv[], bool& isColorizeDisp, bool
                        string& filename, bool& isFileReading )
 {
     filename.clear();
-    cv::CommandLineParser parser(argc, argv, "{h help||}{cd|1|}{fmd|0|}{mode|0|}{m|01010|}{r||}");
+    cv::CommandLineParser parser(argc, argv, "{h help||}{cd|1|}{fmd|0|}{mode|-1|}{m|010100|}{r||}");
     if (parser.has("h"))
     {
         help();
@@ -121,14 +123,14 @@ static void parseCommandLine( int argc, char* argv[], bool& isColorizeDisp, bool
         help();
         exit(-1);
     }
-    if (flags % 100000 == 0)
+    if (flags % 1000000 == 0)
     {
         cout << "No one output image is selected." << endl;
         exit(0);
     }
-    for (int i = 0; i < 5; i++)
+    for (int i = 0; i < 6; i++)
     {
-        retrievedImageFlags[4 - i] = (flags % 10 != 0);
+        retrievedImageFlags[5 - i] = (flags % 10 != 0);
         flags /= 10;
     }
 }
@@ -141,7 +143,7 @@ int main( int argc, char* argv[] )
 {
     bool isColorizeDisp, isFixedMaxDisp;
     int imageMode;
-    bool retrievedImageFlags[5];
+    bool retrievedImageFlags[6];
     string filename;
     bool isVideoReading;
     parseCommandLine( argc, argv, isColorizeDisp, isFixedMaxDisp, imageMode, retrievedImageFlags, filename, isVideoReading );
@@ -165,7 +167,7 @@ int main( int argc, char* argv[] )
         return -1;
     }
 
-    if( !isVideoReading )
+    if( !isVideoReading && imageMode >= 0 )
     {
         bool modeRes=false;
         switch ( imageMode )
@@ -193,13 +195,35 @@ int main( int argc, char* argv[] )
             cout << "\nThis image mode is not supported by the device, the default value (CV_CAP_OPENNI_SXGA_15HZ) will be used.\n" << endl;
     }
 
+    // turn on depth, color and IR if needed
+    if (retrievedImageFlags[0] || retrievedImageFlags[1] || retrievedImageFlags[2])
+        capture.set(CAP_OPENNI_DEPTH_GENERATOR_PRESENT, true);
+    else
+        capture.set(CAP_OPENNI_DEPTH_GENERATOR_PRESENT, false);
+    if (retrievedImageFlags[3] || retrievedImageFlags[4])
+        capture.set(CAP_OPENNI_IMAGE_GENERATOR_PRESENT, true);
+    else
+        capture.set(CAP_OPENNI_IMAGE_GENERATOR_PRESENT, false);
+    if (retrievedImageFlags[5])
+        capture.set(CAP_OPENNI_IR_GENERATOR_PRESENT, true);
+    else
+        capture.set(CAP_OPENNI_IR_GENERATOR_PRESENT, false);
+
     // Print some avalible device settings.
-    cout << "\nDepth generator output mode:" << endl <<
-            "FRAME_WIDTH      " << capture.get( CAP_PROP_FRAME_WIDTH ) << endl <<
-            "FRAME_HEIGHT     " << capture.get( CAP_PROP_FRAME_HEIGHT ) << endl <<
-            "FRAME_MAX_DEPTH  " << capture.get( CAP_PROP_OPENNI_FRAME_MAX_DEPTH ) << " mm" << endl <<
-            "FPS              " << capture.get( CAP_PROP_FPS ) << endl <<
-            "REGISTRATION     " << capture.get( CAP_PROP_OPENNI_REGISTRATION ) << endl;
+    if (capture.get(CAP_OPENNI_DEPTH_GENERATOR_PRESENT))
+    {
+        cout << "\nDepth generator output mode:" << endl <<
+            "FRAME_WIDTH      " << capture.get(CAP_PROP_FRAME_WIDTH) << endl <<
+            "FRAME_HEIGHT     " << capture.get(CAP_PROP_FRAME_HEIGHT) << endl <<
+            "FRAME_MAX_DEPTH  " << capture.get(CAP_PROP_OPENNI_FRAME_MAX_DEPTH) << " mm" << endl <<
+            "FPS              " << capture.get(CAP_PROP_FPS) << endl <<
+            "REGISTRATION     " << capture.get(CAP_PROP_OPENNI_REGISTRATION) << endl;
+    }
+    else
+    {
+        cout << "\nDevice doesn't contain depth generator or it is not selected." << endl;
+    }
+
     if( capture.get( CAP_OPENNI_IMAGE_GENERATOR_PRESENT ) )
     {
         cout <<
@@ -210,9 +234,20 @@ int main( int argc, char* argv[] )
     }
     else
     {
-        cout << "\nDevice doesn't contain image generator." << endl;
-        if (!retrievedImageFlags[0] && !retrievedImageFlags[1] && !retrievedImageFlags[2])
-            return 0;
+        cout << "\nDevice doesn't contain image generator or it is not selected." << endl;
+    }
+
+    if( capture.get(CAP_OPENNI_IR_GENERATOR_PRESENT) )
+    {
+        cout <<
+            "\nIR generator output mode:" << endl <<
+            "FRAME_WIDTH   " << capture.get(CAP_OPENNI_IR_GENERATOR + CAP_PROP_FRAME_WIDTH) << endl <<
+            "FRAME_HEIGHT  " << capture.get(CAP_OPENNI_IR_GENERATOR + CAP_PROP_FRAME_HEIGHT) << endl <<
+            "FPS           " << capture.get(CAP_OPENNI_IR_GENERATOR + CAP_PROP_FPS) << endl;
+    }
+    else
+    {
+        cout << "\nDevice doesn't contain IR generator or it is not selected." << endl;
     }
 
     for(;;)
@@ -222,6 +257,7 @@ int main( int argc, char* argv[] )
         Mat disparityMap;
         Mat bgrImage;
         Mat grayImage;
+        Mat irImage;
 
         if( !capture.grab() )
         {
@@ -261,6 +297,13 @@ int main( int argc, char* argv[] )
 
             if( retrievedImageFlags[4] && capture.retrieve( grayImage, CAP_OPENNI_GRAY_IMAGE ) )
                 imshow( "gray image", grayImage );
+
+            if( retrievedImageFlags[5] && capture.retrieve( irImage, CAP_OPENNI_IR_IMAGE ) )
+            {
+                Mat ir8;
+                irImage.convertTo(ir8, CV_8U, 256.0 / 3500, 0.0);
+                imshow("IR image", ir8);
+            }
         }
 
         if( waitKey( 30 ) >= 0 )
diff --git a/samples/cpp/pca.cpp b/samples/cpp/pca.cpp
index 35fd0c1..fb2f585 100644
--- a/samples/cpp/pca.cpp
+++ b/samples/cpp/pca.cpp
@@ -42,9 +42,9 @@
 #include <fstream>
 #include <sstream>
 
-#include <opencv2/core/core.hpp>
+#include <opencv2/core.hpp>
 #include "opencv2/imgcodecs.hpp"
-#include <opencv2/highgui/highgui.hpp>
+#include <opencv2/highgui.hpp>
 
 using namespace cv;
 using namespace std;
@@ -183,9 +183,9 @@ int main(int argc, char** argv)
     // display until user presses q
     imshow(winName, reconstruction);
 
-    int key = 0;
+    char key = 0;
     while(key != 'q')
-        key = waitKey();
+        key = (char)waitKey();
 
    return 0;
 }
diff --git a/samples/cpp/peopledetect.cpp b/samples/cpp/peopledetect.cpp
new file mode 100644
index 0000000..5fa2382
--- /dev/null
+++ b/samples/cpp/peopledetect.cpp
@@ -0,0 +1,177 @@
+#include <iostream>
+#include <stdexcept>
+#include <opencv2/objdetect.hpp>
+#include <opencv2/highgui.hpp>
+#include <opencv2/imgproc.hpp>
+#include <opencv2/imgcodecs.hpp>
+#include <opencv2/video.hpp>
+#include <opencv2/videoio.hpp>
+
+using namespace cv;
+using namespace std;
+
+
+const char* keys =
+{
+    "{ help h      |                     | print help message }"
+    "{ image i     |                     | specify input image}"
+    "{ camera c    |                     | enable camera capturing }"
+    "{ video v     | ../data/vtest.avi   | use video as input }"
+    "{ directory d |                     | images directory}"
+};
+
+static void detectAndDraw(const HOGDescriptor &hog, Mat &img)
+{
+    vector<Rect> found, found_filtered;
+    double t = (double) getTickCount();
+    // Run the detector with default parameters. to get a higher hit-rate
+    // (and more false alarms, respectively), decrease the hitThreshold and
+    // groupThreshold (set groupThreshold to 0 to turn off the grouping completely).
+    hog.detectMultiScale(img, found, 0, Size(8,8), Size(32,32), 1.05, 2);
+    t = (double) getTickCount() - t;
+    cout << "detection time = " << (t*1000./cv::getTickFrequency()) << " ms" << endl;
+
+    for(size_t i = 0; i < found.size(); i++ )
+    {
+        Rect r = found[i];
+
+        size_t j;
+        // Do not add small detections inside a bigger detection.
+        for ( j = 0; j < found.size(); j++ )
+            if ( j != i && (r & found[j]) == r )
+                break;
+
+        if ( j == found.size() )
+            found_filtered.push_back(r);
+    }
+
+    for (size_t i = 0; i < found_filtered.size(); i++)
+    {
+        Rect r = found_filtered[i];
+
+        // The HOG detector returns slightly larger rectangles than the real objects,
+        // so we slightly shrink the rectangles to get a nicer output.
+        r.x += cvRound(r.width*0.1);
+        r.width = cvRound(r.width*0.8);
+        r.y += cvRound(r.height*0.07);
+        r.height = cvRound(r.height*0.8);
+        rectangle(img, r.tl(), r.br(), cv::Scalar(0,255,0), 3);
+    }
+}
+
+int main(int argc, char** argv)
+{
+    CommandLineParser parser(argc, argv, keys);
+
+    if (parser.has("help"))
+    {
+        cout << "\nThis program demonstrates the use of the HoG descriptor using\n"
+            " HOGDescriptor::hog.setSVMDetector(HOGDescriptor::getDefaultPeopleDetector());\n";
+        parser.printMessage();
+        cout << "During execution:\n\tHit q or ESC key to quit.\n"
+            "\tUsing OpenCV version " << CV_VERSION << "\n"
+            "Note: camera device number must be different from -1.\n" << endl;
+        return 0;
+    }
+
+    HOGDescriptor hog;
+    hog.setSVMDetector(HOGDescriptor::getDefaultPeopleDetector());
+    namedWindow("people detector", 1);
+
+    string pattern_glob = "";
+    string video_filename = "../data/vtest.avi";
+    int camera_id = -1;
+    if (parser.has("directory"))
+    {
+        pattern_glob = parser.get<string>("directory");
+    }
+    else if (parser.has("image"))
+    {
+        pattern_glob = parser.get<string>("image");
+    }
+    else if (parser.has("camera"))
+    {
+        camera_id = parser.get<int>("camera");
+    }
+    else if (parser.has("video"))
+    {
+        video_filename = parser.get<string>("video");
+    }
+
+    if (!pattern_glob.empty() || camera_id != -1 || !video_filename.empty())
+    {
+        //Read from input image files
+        vector<String> filenames;
+        //Read from video file
+        VideoCapture vc;
+        Mat frame;
+
+        if (!pattern_glob.empty())
+        {
+            String folder(pattern_glob);
+            glob(folder, filenames);
+        }
+        else if (camera_id != -1)
+        {
+            vc.open(camera_id);
+            if (!vc.isOpened())
+            {
+                stringstream msg;
+                msg << "can't open camera: " << camera_id;
+                throw runtime_error(msg.str());
+            }
+        }
+        else
+        {
+            vc.open(video_filename.c_str());
+            if (!vc.isOpened())
+                throw runtime_error(string("can't open video file: " + video_filename));
+        }
+
+        vector<String>::const_iterator it_image = filenames.begin();
+
+        for (;;)
+        {
+            if (!pattern_glob.empty())
+            {
+                bool read_image_ok = false;
+                for (; it_image != filenames.end(); ++it_image)
+                {
+                    cout << "\nRead: " << *it_image << endl;
+                    // Read current image
+                    frame = imread(*it_image);
+
+                    if (!frame.empty())
+                    {
+                        ++it_image;
+                        read_image_ok = true;
+                        break;
+                    }
+                }
+
+                //No more valid images
+                if (!read_image_ok)
+                {
+                    //Release the image in order to exit the while loop
+                    frame.release();
+                }
+            }
+            else
+            {
+                vc >> frame;
+            }
+
+            if (frame.empty())
+                break;
+
+            detectAndDraw(hog, frame);
+
+            imshow("people detector", frame);
+            int c = waitKey( vc.isOpened() ? 30 : 0 ) & 255;
+            if ( c == 'q' || c == 'Q' || c == 27)
+                break;
+        }
+    }
+
+    return 0;
+}
diff --git a/samples/cpp/phase_corr.cpp b/samples/cpp/phase_corr.cpp
index 5e8685f..f735666 100644
--- a/samples/cpp/phase_corr.cpp
+++ b/samples/cpp/phase_corr.cpp
@@ -1,7 +1,7 @@
-#include "opencv2/core/core.hpp"
-#include "opencv2/videoio/videoio.hpp"
-#include "opencv2/highgui/highgui.hpp"
-#include "opencv2/imgproc/imgproc.hpp"
+#include "opencv2/core.hpp"
+#include "opencv2/videoio.hpp"
+#include "opencv2/highgui.hpp"
+#include "opencv2/imgproc.hpp"
 
 using namespace cv;
 
@@ -9,7 +9,7 @@ int main(int, char* [])
 {
     VideoCapture video(0);
     Mat frame, curr, prev, curr64f, prev64f, hann;
-    int key = 0;
+    char key;
 
     do
     {
@@ -37,10 +37,10 @@ int main(int, char* [])
         }
 
         imshow("phase shift", frame);
-        key = waitKey(2);
+        key = (char)waitKey(2);
 
         prev = curr.clone();
-    } while((char)key != 27); // Esc to exit...
+    } while(key != 27); // Esc to exit...
 
     return 0;
 }
diff --git a/samples/cpp/points_classifier.cpp b/samples/cpp/points_classifier.cpp
index c0270d0..9945ba2 100644
--- a/samples/cpp/points_classifier.cpp
+++ b/samples/cpp/points_classifier.cpp
@@ -312,7 +312,7 @@ int main()
 
     for(;;)
     {
-        uchar key = (uchar)waitKey();
+        char key = (char)waitKey();
 
         if( key == 27 ) break;
 
diff --git a/samples/cpp/polar_transforms.cpp b/samples/cpp/polar_transforms.cpp
index 872dda8..adbc955 100644
--- a/samples/cpp/polar_transforms.cpp
+++ b/samples/cpp/polar_transforms.cpp
@@ -1,94 +1,76 @@
-#include "opencv2/imgproc/imgproc_c.h"
-#include "opencv2/videoio/videoio_c.h"
-#include "opencv2/highgui/highgui_c.h"
-#include "opencv2/core/utility.hpp"
+#include "opencv2/imgproc.hpp"
+#include "opencv2/highgui.hpp"
+#include <iostream>
 
-#include <ctype.h>
-#include <stdio.h>
+using namespace cv;
 
 static void help( void )
 {
     printf("\nThis program illustrates Linear-Polar and Log-Polar image transforms\n"
             "Usage :\n"
-            "./polar_transforms [[camera number -- Default 0],[AVI path_filename]]\n\n"
-            );
+            "./polar_transforms [[camera number -- Default 0],[path_to_filename]]\n\n");
 }
+
 int main( int argc, char** argv )
 {
-    CvCapture* capture = 0;
-    IplImage*  log_polar_img = 0;
-    IplImage*  lin_polar_img = 0;
-    IplImage*  recovered_img = 0;
+    VideoCapture capture;
+    Mat log_polar_img, lin_polar_img, recovered_log_polar, recovered_lin_polar_img;
 
     help();
-    cv::CommandLineParser parser(argc, argv, "{help h||}{@input|0|}");
-    if (parser.has("help"))
-    {
-        help();
-        return 0;
-    }
+
+    CommandLineParser parser(argc, argv, "{@input|0|}");
     std::string arg = parser.get<std::string>("@input");
+
     if( arg.size() == 1 && isdigit(arg[0]) )
-        capture = cvCaptureFromCAM( arg[0] - '0' );
+        capture.open( arg[0] - '0' );
     else
-        capture = cvCaptureFromAVI( arg.c_str() );
-    if( !capture )
+        capture.open( arg.c_str() );
+
+    if( !capture.isOpened() )
     {
         const char* name = argv[0];
         fprintf(stderr,"Could not initialize capturing...\n");
         fprintf(stderr,"Usage: %s <CAMERA_NUMBER>    , or \n       %s <VIDEO_FILE>\n", name, name);
-        help();
         return -1;
     }
 
-    cvNamedWindow( "Linear-Polar", 0 );
-    cvNamedWindow( "Log-Polar", 0 );
-    cvNamedWindow( "Recovered image", 0 );
+    namedWindow( "Linear-Polar", WINDOW_AUTOSIZE );
+    namedWindow( "Log-Polar", WINDOW_AUTOSIZE);
+    namedWindow( "Recovered Linear-Polar", WINDOW_AUTOSIZE);
+    namedWindow( "Recovered Log-Polar", WINDOW_AUTOSIZE);
 
-    cvMoveWindow( "Linear-Polar", 20,20 );
-    cvMoveWindow( "Log-Polar", 700,20 );
-    cvMoveWindow( "Recovered image", 20,700 );
+    moveWindow( "Linear-Polar", 20,20 );
+    moveWindow( "Log-Polar", 700,20 );
+    moveWindow( "Recovered Linear-Polar", 20, 350 );
+    moveWindow( "Recovered Log-Polar", 700, 350 );
 
     for(;;)
     {
-        IplImage* frame = 0;
+        Mat frame;
+        capture >> frame;
 
-        frame = cvQueryFrame( capture );
-        if( !frame )
+        if( frame.empty() )
             break;
 
-        if( !log_polar_img )
-        {
-            log_polar_img = cvCreateImage( cvSize(frame->width,frame->height), IPL_DEPTH_8U, frame->nChannels );
-            lin_polar_img = cvCreateImage( cvSize(frame->width,frame->height), IPL_DEPTH_8U, frame->nChannels );
-            recovered_img = cvCreateImage( cvSize(frame->width,frame->height), IPL_DEPTH_8U, frame->nChannels );
-        }
+        Point2f center( (float)frame.cols / 2, (float)frame.rows / 2 );
+        double radius = (double)frame.cols / 4;
+        double M = (double)frame.cols / log(radius);
 
-        cvLogPolar(frame,log_polar_img,cvPoint2D32f(frame->width >> 1,frame->height >> 1),70, CV_INTER_LINEAR+CV_WARP_FILL_OUTLIERS);
-        cvLinearPolar(frame,lin_polar_img,cvPoint2D32f(frame->width >> 1,frame->height >> 1),70, CV_INTER_LINEAR+CV_WARP_FILL_OUTLIERS);
+        logPolar(frame,log_polar_img, center, M, INTER_LINEAR + WARP_FILL_OUTLIERS);
+        linearPolar(frame,lin_polar_img, center, radius, INTER_LINEAR + WARP_FILL_OUTLIERS);
 
-#if 0
-        cvLogPolar(log_polar_img,recovered_img,cvPoint2D32f(frame->width >> 1,frame->height >> 1),70, CV_WARP_INVERSE_MAP+CV_INTER_LINEAR);
-#else
-        cvLinearPolar(lin_polar_img,recovered_img,cvPoint2D32f(frame->width >> 1,frame->height >> 1),70, CV_WARP_INVERSE_MAP+CV_INTER_LINEAR+CV_WARP_FILL_OUTLIERS);
-#endif
+        logPolar(log_polar_img, recovered_log_polar, center, M, WARP_INVERSE_MAP + INTER_LINEAR);
+        linearPolar(lin_polar_img, recovered_lin_polar_img, center, radius, WARP_INVERSE_MAP + INTER_LINEAR + WARP_FILL_OUTLIERS);
 
-        cvShowImage("Log-Polar", log_polar_img );
-        cvShowImage("Linear-Polar", lin_polar_img );
-        cvShowImage("Recovered image", recovered_img );
+        imshow("Log-Polar", log_polar_img );
+        imshow("Linear-Polar", lin_polar_img );
+        imshow("Recovered Linear-Polar", recovered_lin_polar_img );
+        imshow("Recovered Log-Polar", recovered_log_polar );
 
-        if( cvWaitKey(10) >= 0 )
+        if( waitKey(10) >= 0 )
             break;
     }
 
-    cvReleaseCapture( &capture );
-    cvDestroyWindow("Linear-Polar");
-    cvDestroyWindow("Log-Polar");
-    cvDestroyWindow("Recovered image");
-
+    waitKey(0);
     return 0;
 }
-
-#ifdef _EiC
-main(1,"laplace.c");
-#endif
diff --git a/samples/cpp/segment_objects.cpp b/samples/cpp/segment_objects.cpp
index 3c217f6..32b2598 100644
--- a/samples/cpp/segment_objects.cpp
+++ b/samples/cpp/segment_objects.cpp
@@ -1,6 +1,6 @@
-#include "opencv2/imgproc/imgproc.hpp"
-#include "opencv2/videoio/videoio.hpp"
-#include "opencv2/highgui/highgui.hpp"
+#include "opencv2/imgproc.hpp"
+#include "opencv2/videoio.hpp"
+#include "opencv2/highgui.hpp"
 #include "opencv2/video/background_segm.hpp"
 #include <stdio.h>
 #include <string>
@@ -105,7 +105,7 @@ int main(int argc, char** argv)
         refineSegments(tmp_frame, bgmask, out_frame);
         imshow("video", tmp_frame);
         imshow("segmented", out_frame);
-        int keycode = waitKey(30);
+        char keycode = (char)waitKey(30);
         if( keycode == 27 )
             break;
         if( keycode == ' ' )
diff --git a/samples/cpp/select3dobj.cpp b/samples/cpp/select3dobj.cpp
index b13697f..7df366b 100644
--- a/samples/cpp/select3dobj.cpp
+++ b/samples/cpp/select3dobj.cpp
@@ -285,8 +285,8 @@ static int select3DBox(const string& windowname, const string& selWinName, const
         imshow(windowname, shownFrame);
         imshow(selWinName, selectedObjFrame);
 
-        int c = waitKey(30);
-        if( (c & 255) == 27 )
+        char c = (char)waitKey(30);
+        if( c == 27 )
         {
             nobjpt = 0;
         }
@@ -593,7 +593,7 @@ int main(int argc, char** argv)
 
         imshow("View", shownFrame);
         imshow("Selected Object", selectedObjFrame);
-        int c = waitKey(imageList.empty() && !box.empty() ? 30 : 300);
+        char c = (char)waitKey(imageList.empty() && !box.empty() ? 30 : 300);
         if( c == 'q' || c == 'Q' )
             break;
         if( c == '\r' || c == '\n' )
diff --git a/samples/cpp/smiledetect.cpp b/samples/cpp/smiledetect.cpp
index f3f8576..9e0c3c8 100644
--- a/samples/cpp/smiledetect.cpp
+++ b/samples/cpp/smiledetect.cpp
@@ -99,7 +99,7 @@ int main( int argc, const char** argv )
             Mat frame1 = frame.clone();
             detectAndDraw( frame1, cascade, nestedCascade, scale, tryflip );
 
-            int c = waitKey(10);
+            char c = (char)waitKey(10);
             if( c == 27 || c == 'q' || c == 'Q' )
                 break;
         }
@@ -153,7 +153,7 @@ void detectAndDraw( Mat& img, CascadeClassifier& cascade,
                                  //|CASCADE_DO_ROUGH_SEARCH
                                  |CASCADE_SCALE_IMAGE,
                                  Size(30, 30) );
-        for( vector<Rect>::const_iterator r = faces2.begin(); r != faces2.end(); r++ )
+        for( vector<Rect>::const_iterator r = faces2.begin(); r != faces2.end(); ++r )
         {
             faces.push_back(Rect(smallImg.cols - r->x - r->width, r->y, r->width, r->height));
         }
diff --git a/samples/cpp/squares.cpp b/samples/cpp/squares.cpp
index f53e931..dfa3c61 100644
--- a/samples/cpp/squares.cpp
+++ b/samples/cpp/squares.cpp
@@ -2,10 +2,10 @@
 // It loads several images sequentially and tries to find squares in
 // each image
 
-#include "opencv2/core/core.hpp"
-#include "opencv2/imgproc/imgproc.hpp"
+#include "opencv2/core.hpp"
+#include "opencv2/imgproc.hpp"
 #include "opencv2/imgcodecs.hpp"
-#include "opencv2/highgui/highgui.hpp"
+#include "opencv2/highgui.hpp"
 
 #include <iostream>
 #include <math.h>
@@ -23,8 +23,8 @@ static void help()
     "Returns sequence of squares detected on the image.\n"
     "the sequence is stored in the specified memory storage\n"
     "Call:\n"
-    "./squares\n"
-    "Using OpenCV version %s\n" << CV_VERSION << "\n" << endl;
+    "./squares [file_name (optional)]\n"
+    "Using OpenCV version " << CV_VERSION << "\n" << endl;
 }
 
 
@@ -140,11 +140,18 @@ static void drawSquares( Mat& image, const vector<vector<Point> >& squares )
 }
 
 
-int main(int /*argc*/, char** /*argv*/)
+int main(int argc, char** argv)
 {
     static const char* names[] = { "../data/pic1.png", "../data/pic2.png", "../data/pic3.png",
         "../data/pic4.png", "../data/pic5.png", "../data/pic6.png", 0 };
     help();
+
+    if( argc > 1)
+    {
+     names[0] =  argv[1];
+     names[1] =  "0";
+    }
+
     namedWindow( wndname, 1 );
     vector<vector<Point> > squares;
 
@@ -160,8 +167,8 @@ int main(int /*argc*/, char** /*argv*/)
         findSquares(image, squares);
         drawSquares(image, squares);
 
-        int c = waitKey();
-        if( (char)c == 27 )
+        char c = (char)waitKey();
+        if( c == 27 )
             break;
     }
 
diff --git a/samples/cpp/starter_imagelist.cpp b/samples/cpp/starter_imagelist.cpp
index 89df0cc..6f4f714 100644
--- a/samples/cpp/starter_imagelist.cpp
+++ b/samples/cpp/starter_imagelist.cpp
@@ -9,7 +9,7 @@
  * easy as CV_PI right?
  */
 #include "opencv2/imgcodecs.hpp"
-#include "opencv2/highgui/highgui.hpp"
+#include "opencv2/highgui.hpp"
 #include <iostream>
 #include <vector>
 
diff --git a/samples/cpp/starter_video.cpp b/samples/cpp/starter_video.cpp
deleted file mode 100644
index d6bf1b7..0000000
--- a/samples/cpp/starter_video.cpp
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
-* starter_video.cpp
-*
-*  Created on: Nov 23, 2010
-*      Author: Ethan Rublee
-*
-*  Modified on: April 17, 2013
-*      Author: Kevin Hughes
-*
-* A starter sample for using OpenCV VideoCapture with capture devices, video files or image sequences
-* easy as CV_PI right?
-*/
-
-#include <opencv2/imgcodecs.hpp>
-#include <opencv2/videoio/videoio.hpp>
-#include <opencv2/highgui/highgui.hpp>
-
-#include <iostream>
-#include <stdio.h>
-
-using namespace cv;
-using namespace std;
-
-//hide the local functions in an anon namespace
-namespace {
-    void help(char** av) {
-        cout << "The program captures frames from a video file, image sequence (01.jpg, 02.jpg ... 10.jpg) or camera connected to your computer." << endl
-             << "Usage:\n" << av[0] << " <video file, image sequence or device number>" << endl
-             << "q,Q,esc -- quit" << endl
-             << "space   -- save frame" << endl << endl
-             << "\tTo capture from a camera pass the device number. To find the device number, try ls /dev/video*" << endl
-             << "\texample: " << av[0] << " 0" << endl
-             << "\tYou may also pass a video file instead of a device number" << endl
-             << "\texample: " << av[0] << " video.avi" << endl
-             << "\tYou can also pass the path to an image sequence and OpenCV will treat the sequence just like a video." << endl
-             << "\texample: " << av[0] << " right%%02d.jpg" << endl;
-    }
-
-    int process(VideoCapture& capture) {
-        int n = 0;
-        char filename[200];
-        string window_name = "video | q or esc to quit";
-        cout << "press space to save a picture. q or esc to quit" << endl;
-        namedWindow(window_name, WINDOW_KEEPRATIO); //resizable window;
-        Mat frame;
-
-        for (;;) {
-            capture >> frame;
-            if (frame.empty())
-                break;
-
-            imshow(window_name, frame);
-            char key = (char)waitKey(30); //delay N millis, usually long enough to display and capture input
-
-            switch (key) {
-            case 'q':
-            case 'Q':
-            case 27: //escape key
-                return 0;
-            case ' ': //Save an image
-                sprintf(filename,"filename%.3d.jpg",n++);
-                imwrite(filename,frame);
-                cout << "Saved " << filename << endl;
-                break;
-            default:
-                break;
-            }
-        }
-        return 0;
-    }
-}
-
-int main(int ac, char** av) {
-    cv::CommandLineParser parser(ac, av, "{help h||}{@input||}");
-    if (parser.has("help"))
-    {
-        help(av);
-        return 0;
-    }
-    std::string arg = parser.get<std::string>("@input");
-    if (arg.empty()) {
-        help(av);
-        return 1;
-    }
-    VideoCapture capture(arg); //try to open string, this will attempt to open it as a video file or image sequence
-    if (!capture.isOpened()) //if this fails, try to open as a video camera, through the use of an integer param
-        capture.open(atoi(arg.c_str()));
-    if (!capture.isOpened()) {
-        cerr << "Failed to open the video device, video file or image sequence!\n" << endl;
-        help(av);
-        return 1;
-    }
-    return process(capture);
-}
diff --git a/samples/cpp/stereo_calib.cpp b/samples/cpp/stereo_calib.cpp
index 117c9ba..000928c 100644
--- a/samples/cpp/stereo_calib.cpp
+++ b/samples/cpp/stereo_calib.cpp
@@ -19,13 +19,13 @@
      Online docs:   http://docs.opencv.org
      Q&A forum:     http://answers.opencv.org
      Issue tracker: http://code.opencv.org
-     GitHub:        https://github.com/Itseez/opencv/
+     GitHub:        https://github.com/opencv/opencv/
    ************************************************** */
 
-#include "opencv2/calib3d/calib3d.hpp"
+#include "opencv2/calib3d.hpp"
 #include "opencv2/imgcodecs.hpp"
-#include "opencv2/highgui/highgui.hpp"
-#include "opencv2/imgproc/imgproc.hpp"
+#include "opencv2/highgui.hpp"
+#include "opencv2/imgproc.hpp"
 
 #include <vector>
 #include <string>
@@ -50,13 +50,13 @@ static int print_help()
             "         matrix separately) stereo. \n"
             " Calibrate the cameras and display the\n"
             " rectified results along with the computed disparity images.   \n" << endl;
-    cout << "Usage:\n ./stereo_calib -w=<board_width default=9> -h=<board_height default=6> <image list XML/YML file default=../data/stereo_calib.xml>\n" << endl;
+    cout << "Usage:\n ./stereo_calib -w=<board_width default=9> -h=<board_height default=6> -s=<square_size default=1.0> <image list XML/YML file default=../data/stereo_calib.xml>\n" << endl;
     return 0;
 }
 
 
 static void
-StereoCalib(const vector<string>& imagelist, Size boardSize,bool displayCorners = false, bool useCalibrated=true, bool showRectified=true)
+StereoCalib(const vector<string>& imagelist, Size boardSize, float squareSize, bool displayCorners = false, bool useCalibrated=true, bool showRectified=true)
 {
     if( imagelist.size() % 2 != 0 )
     {
@@ -65,7 +65,6 @@ StereoCalib(const vector<string>& imagelist, Size boardSize,bool displayCorners
     }
 
     const int maxScale = 2;
-    const float squareSize = 1.f;  // Set this to your actual square size
     // ARRAY AND VECTOR STORAGE:
 
     vector<vector<Point2f> > imagePoints[2];
@@ -212,7 +211,7 @@ StereoCalib(const vector<string>& imagelist, Size boardSize,bool displayCorners
     cout << "average epipolar err = " <<  err/npoints << endl;
 
     // save intrinsic parameters
-    FileStorage fs("../data/intrinsics.yml", FileStorage::WRITE);
+    FileStorage fs("intrinsics.yml", FileStorage::WRITE);
     if( fs.isOpened() )
     {
         fs << "M1" << cameraMatrix[0] << "D1" << distCoeffs[0] <<
@@ -348,13 +347,14 @@ int main(int argc, char** argv)
     Size boardSize;
     string imagelistfn;
     bool showRectified;
-    cv::CommandLineParser parser(argc, argv, "{w|9|}{h|6|}{nr||}{help||}{@input|../data/stereo_calib.xml|}");
+    cv::CommandLineParser parser(argc, argv, "{w|9|}{h|6|}{s|1.0|}{nr||}{help||}{@input|../data/stereo_calib.xml|}");
     if (parser.has("help"))
         return print_help();
     showRectified = !parser.has("nr");
     imagelistfn = parser.get<string>("@input");
     boardSize.width = parser.get<int>("w");
     boardSize.height = parser.get<int>("h");
+    float squareSize = parser.get<float>("s");
     if (!parser.check())
     {
         parser.printErrors();
@@ -368,6 +368,6 @@ int main(int argc, char** argv)
         return print_help();
     }
 
-    StereoCalib(imagelist, boardSize,false, true, showRectified);
+    StereoCalib(imagelist, boardSize, squareSize, false, true, showRectified);
     return 0;
 }
diff --git a/samples/cpp/stereo_match.cpp b/samples/cpp/stereo_match.cpp
index e3ebb5d..4868a63 100644
--- a/samples/cpp/stereo_match.cpp
+++ b/samples/cpp/stereo_match.cpp
@@ -8,9 +8,9 @@
  */
 
 #include "opencv2/calib3d/calib3d.hpp"
-#include "opencv2/imgproc/imgproc.hpp"
+#include "opencv2/imgproc.hpp"
 #include "opencv2/imgcodecs.hpp"
-#include "opencv2/highgui/highgui.hpp"
+#include "opencv2/highgui.hpp"
 #include "opencv2/core/utility.hpp"
 
 #include <stdio.h>
@@ -59,7 +59,7 @@ int main(int argc, char** argv)
     Ptr<StereoBM> bm = StereoBM::create(16,9);
     Ptr<StereoSGBM> sgbm = StereoSGBM::create(0,16,3);
     cv::CommandLineParser parser(argc, argv,
-        "{help h||}{algorithm||}{max-disparity|0|}{blocksize|0|}{no-display||}{scale|1|}{i||}{e||}{o||}{p||}");
+        "{@arg1||}{@arg2||}{help h||}{algorithm||}{max-disparity|0|}{blocksize|0|}{no-display||}{scale|1|}{i||}{e||}{o||}{p||}");
     if(parser.has("help"))
     {
         print_help();
diff --git a/samples/cpp/stitching.cpp b/samples/cpp/stitching.cpp
index 5b4437a..d0b38b4 100644
--- a/samples/cpp/stitching.cpp
+++ b/samples/cpp/stitching.cpp
@@ -50,6 +50,7 @@ using namespace std;
 using namespace cv;
 
 bool try_use_gpu = false;
+Stitcher::Mode mode = Stitcher::PANORAMA;
 vector<Mat> imgs;
 string result_name = "result.jpg";
 
@@ -62,8 +63,8 @@ int main(int argc, char* argv[])
     if (retval) return -1;
 
     Mat pano;
-    Stitcher stitcher = Stitcher::createDefault(try_use_gpu);
-    Stitcher::Status status = stitcher.stitch(imgs, pano);
+    Ptr<Stitcher> stitcher = Stitcher::create(mode, try_use_gpu);
+    Stitcher::Status status = stitcher->stitch(imgs, pano);
 
     if (status != Stitcher::OK)
     {
@@ -79,12 +80,16 @@ int main(int argc, char* argv[])
 void printUsage()
 {
     cout <<
-        "Rotation model images stitcher.\n\n"
+        "Images stitcher.\n\n"
         "stitching img1 img2 [...imgN]\n\n"
         "Flags:\n"
         "  --try_use_gpu (yes|no)\n"
         "      Try to use GPU. The default value is 'no'. All default values\n"
         "      are for CPU mode.\n"
+        "  --mode (panorama|scans)\n"
+        "      Determines configuration of stitcher. The default is 'panorama',\n"
+        "      mode suitable for creating photo panoramas. Option 'scans' is suitable\n"
+        "      for stitching materials under affine transformation, such as scans.\n"
         "  --output <result_img>\n"
         "      The default is 'result.jpg'.\n";
 }
@@ -122,6 +127,19 @@ int parseCmdArgs(int argc, char** argv)
             result_name = argv[i + 1];
             i++;
         }
+        else if (string(argv[i]) == "--mode")
+        {
+            if (string(argv[i + 1]) == "panorama")
+                mode = Stitcher::PANORAMA;
+            else if (string(argv[i + 1]) == "scans")
+                mode = Stitcher::SCANS;
+            else
+            {
+                cout << "Bad --mode flag value\n";
+                return -1;
+            }
+            i++;
+        }
         else
         {
             Mat img = imread(argv[i]);
diff --git a/samples/cpp/stitching_detailed.cpp b/samples/cpp/stitching_detailed.cpp
index 8fc489e..df412e1 100644
--- a/samples/cpp/stitching_detailed.cpp
+++ b/samples/cpp/stitching_detailed.cpp
@@ -56,10 +56,13 @@
 #include "opencv2/stitching/detail/matchers.hpp"
 #include "opencv2/stitching/detail/motion_estimators.hpp"
 #include "opencv2/stitching/detail/seam_finders.hpp"
-#include "opencv2/stitching/detail/util.hpp"
 #include "opencv2/stitching/detail/warpers.hpp"
 #include "opencv2/stitching/warpers.hpp"
 
+#define ENABLE_LOG 1
+#define LOG(msg) std::cout << msg
+#define LOGLN(msg) std::cout << msg << std::endl
+
 using namespace std;
 using namespace cv;
 using namespace cv::detail;
@@ -81,12 +84,16 @@ static void printUsage()
         "      Resolution for image registration step. The default is 0.6 Mpx.\n"
         "  --features (surf|orb)\n"
         "      Type of features used for images matching. The default is surf.\n"
+        "  --matcher (homography|affine)\n"
+        "      Matcher used for pairwise image matching.\n"
+        "  --estimator (homography|affine)\n"
+        "      Type of estimator used for transformation estimation.\n"
         "  --match_conf <float>\n"
         "      Confidence for feature matching step. The default is 0.65 for surf and 0.3 for orb.\n"
         "  --conf_thresh <float>\n"
         "      Threshold for two images are from the same panorama confidence.\n"
         "      The default is 1.0.\n"
-        "  --ba (reproj|ray)\n"
+        "  --ba (no|reproj|ray|affine)\n"
         "      Bundle adjustment cost function. The default is ray.\n"
         "  --ba_refine_mask (mask)\n"
         "      Set refinement mask for bundle adjustment. It looks like 'x_xxx',\n"
@@ -102,7 +109,7 @@ static void printUsage()
         "      Labels description: Nm is number of matches, Ni is number of inliers,\n"
         "      C is confidence.\n"
         "\nCompositing Flags:\n"
-        "  --warp (plane|cylindrical|spherical|fisheye|stereographic|compressedPlaneA2B1|compressedPlaneA1.5B1|compressedPlanePortraitA2B1|compressedPlanePortraitA1.5B1|paniniA2B1|paniniA1.5B1|paniniPortraitA2B1|paniniPortraitA1.5B1|mercator|transverseMercator)\n"
+        "  --warp (affine|plane|cylindrical|spherical|fisheye|stereographic|compressedPlaneA2B1|compressedPlaneA1.5B1|compressedPlanePortraitA2B1|compressedPlanePortraitA1.5B1|paniniA2B1|paniniA1.5B1|paniniPortraitA2B1|paniniPortraitA1.5B1|mercator|transverseMercator)\n"
         "      Warp surface type. The default is 'spherical'.\n"
         "  --seam_megapix <float>\n"
         "      Resolution for seam estimation step. The default is 0.1 Mpx.\n"
@@ -135,6 +142,8 @@ double seam_megapix = 0.1;
 double compose_megapix = -1;
 float conf_thresh = 1.f;
 string features_type = "surf";
+string matcher_type = "homography";
+string estimator_type = "homography";
 string ba_cost_func = "ray";
 string ba_refine_mask = "xxxxx";
 bool do_wave_correct = true;
@@ -211,6 +220,28 @@ static int parseCmdArgs(int argc, char** argv)
                 match_conf = 0.3f;
             i++;
         }
+        else if (string(argv[i]) == "--matcher")
+        {
+            if (string(argv[i + 1]) == "homography" || string(argv[i + 1]) == "affine")
+                matcher_type = argv[i + 1];
+            else
+            {
+                cout << "Bad --matcher flag value\n";
+                return -1;
+            }
+            i++;
+        }
+        else if (string(argv[i]) == "--estimator")
+        {
+            if (string(argv[i + 1]) == "homography" || string(argv[i + 1]) == "affine")
+                estimator_type = argv[i + 1];
+            else
+            {
+                cout << "Bad --estimator flag value\n";
+                return -1;
+            }
+            i++;
+        }
         else if (string(argv[i]) == "--match_conf")
         {
             match_conf = static_cast<float>(atof(argv[i + 1]));
@@ -462,18 +493,16 @@ int main(int argc, char* argv[])
     t = getTickCount();
 #endif
     vector<MatchesInfo> pairwise_matches;
-    if (range_width==-1)
-    {
-        BestOf2NearestMatcher matcher(try_cuda, match_conf);
-        matcher(features, pairwise_matches);
-        matcher.collectGarbage();
-    }
+    Ptr<FeaturesMatcher> matcher;
+    if (matcher_type == "affine")
+        matcher = makePtr<AffineBestOf2NearestMatcher>(false, try_cuda, match_conf);
+    else if (range_width==-1)
+        matcher = makePtr<BestOf2NearestMatcher>(try_cuda, match_conf);
     else
-    {
-        BestOf2NearestRangeMatcher matcher(range_width, try_cuda, match_conf);
-        matcher(features, pairwise_matches);
-        matcher.collectGarbage();
-    }
+        matcher = makePtr<BestOf2NearestRangeMatcher>(range_width, try_cuda, match_conf);
+
+    (*matcher)(features, pairwise_matches);
+    matcher->collectGarbage();
 
     LOGLN("Pairwise matching, time: " << ((getTickCount() - t) / getTickFrequency()) << " sec");
 
@@ -509,9 +538,14 @@ int main(int argc, char* argv[])
         return -1;
     }
 
-    HomographyBasedEstimator estimator;
+    Ptr<Estimator> estimator;
+    if (estimator_type == "affine")
+        estimator = makePtr<AffineBasedEstimator>();
+    else
+        estimator = makePtr<HomographyBasedEstimator>();
+
     vector<CameraParams> cameras;
-    if (!estimator(features, pairwise_matches, cameras))
+    if (!(*estimator)(features, pairwise_matches, cameras))
     {
         cout << "Homography estimation failed.\n";
         return -1;
@@ -522,12 +556,14 @@ int main(int argc, char* argv[])
         Mat R;
         cameras[i].R.convertTo(R, CV_32F);
         cameras[i].R = R;
-        LOGLN("Initial intrinsics #" << indices[i]+1 << ":\n" << cameras[i].K());
+        LOGLN("Initial camera intrinsics #" << indices[i]+1 << ":\nK:\n" << cameras[i].K() << "\nR:\n" << cameras[i].R);
     }
 
     Ptr<detail::BundleAdjusterBase> adjuster;
     if (ba_cost_func == "reproj") adjuster = makePtr<detail::BundleAdjusterReproj>();
     else if (ba_cost_func == "ray") adjuster = makePtr<detail::BundleAdjusterRay>();
+    else if (ba_cost_func == "affine") adjuster = makePtr<detail::BundleAdjusterAffinePartial>();
+    else if (ba_cost_func == "no") adjuster = makePtr<NoBundleAdjuster>();
     else
     {
         cout << "Unknown bundle adjustment cost function: '" << ba_cost_func << "'.\n";
@@ -552,7 +588,7 @@ int main(int argc, char* argv[])
     vector<double> focals;
     for (size_t i = 0; i < cameras.size(); ++i)
     {
-        LOGLN("Camera #" << indices[i]+1 << ":\n" << cameras[i].K());
+        LOGLN("Camera #" << indices[i]+1 << ":\nK:\n" << cameras[i].K() << "\nR:\n" << cameras[i].R);
         focals.push_back(cameras[i].focal);
     }
 
@@ -609,6 +645,8 @@ int main(int argc, char* argv[])
     {
         if (warp_type == "plane")
             warper_creator = makePtr<cv::PlaneWarper>();
+        else if (warp_type == "affine")
+            warper_creator = makePtr<cv::AffineWarper>();
         else if (warp_type == "cylindrical")
             warper_creator = makePtr<cv::CylindricalWarper>();
         else if (warp_type == "spherical")
diff --git a/samples/cpp/train_svmsgd.cpp b/samples/cpp/train_svmsgd.cpp
new file mode 100644
index 0000000..810f061
--- /dev/null
+++ b/samples/cpp/train_svmsgd.cpp
@@ -0,0 +1,210 @@
+#include <opencv2/opencv.hpp>
+#include "opencv2/video/tracking.hpp"
+#include "opencv2/imgproc/imgproc.hpp"
+#include "opencv2/highgui/highgui.hpp"
+
+using namespace cv;
+using namespace cv::ml;
+
+
+struct Data
+{
+    Mat img;
+    Mat samples;          //Set of train samples. Contains points on image
+    Mat responses;        //Set of responses for train samples
+
+    Data()
+    {
+        const int WIDTH = 841;
+        const int HEIGHT = 594;
+        img = Mat::zeros(HEIGHT, WIDTH, CV_8UC3);
+        imshow("Train svmsgd", img);
+    }
+};
+
+//Train with SVMSGD algorithm
+//(samples, responses) is a train set
+//weights is a required vector for decision function of SVMSGD algorithm
+bool doTrain(const Mat samples, const Mat responses, Mat &weights, float &shift);
+
+//function finds two points for drawing line (wx = 0)
+bool findPointsForLine(const Mat &weights, float shift, Point points[], int width, int height);
+
+// function finds cross point of line (wx = 0) and segment ( (y = HEIGHT, 0 <= x <= WIDTH) or (x = WIDTH, 0 <= y <= HEIGHT) )
+bool findCrossPointWithBorders(const Mat &weights, float shift, const std::pair<Point,Point> &segment, Point &crossPoint);
+
+//segments' initialization ( (y = HEIGHT, 0 <= x <= WIDTH) and (x = WIDTH, 0 <= y <= HEIGHT) )
+void fillSegments(std::vector<std::pair<Point,Point> > &segments, int width, int height);
+
+//redraw points' set and line (wx = 0)
+void redraw(Data data, const Point points[2]);
+
+//add point in train set, train SVMSGD algorithm and draw results on image
+void addPointRetrainAndRedraw(Data &data, int x, int y, int response);
+
+
+bool doTrain( const Mat samples, const Mat responses, Mat &weights, float &shift)
+{
+    cv::Ptr<SVMSGD> svmsgd = SVMSGD::create();
+
+    cv::Ptr<TrainData> trainData = TrainData::create(samples, cv::ml::ROW_SAMPLE, responses);
+    svmsgd->train( trainData );
+
+    if (svmsgd->isTrained())
+    {
+        weights = svmsgd->getWeights();
+        shift = svmsgd->getShift();
+
+        return true;
+    }
+    return false;
+}
+
+void fillSegments(std::vector<std::pair<Point,Point> > &segments, int width, int height)
+{
+    std::pair<Point,Point> currentSegment;
+
+    currentSegment.first = Point(width, 0);
+    currentSegment.second = Point(width, height);
+    segments.push_back(currentSegment);
+
+    currentSegment.first = Point(0, height);
+    currentSegment.second = Point(width, height);
+    segments.push_back(currentSegment);
+
+    currentSegment.first = Point(0, 0);
+    currentSegment.second = Point(width, 0);
+    segments.push_back(currentSegment);
+
+    currentSegment.first = Point(0, 0);
+    currentSegment.second = Point(0, height);
+    segments.push_back(currentSegment);
+}
+
+
+bool findCrossPointWithBorders(const Mat &weights, float shift, const std::pair<Point,Point> &segment, Point &crossPoint)
+{
+    int x = 0;
+    int y = 0;
+    int xMin = std::min(segment.first.x, segment.second.x);
+    int xMax = std::max(segment.first.x, segment.second.x);
+    int yMin = std::min(segment.first.y, segment.second.y);
+    int yMax = std::max(segment.first.y, segment.second.y);
+
+    CV_Assert(weights.type() == CV_32FC1);
+    CV_Assert(xMin == xMax || yMin == yMax);
+
+    if (xMin == xMax && weights.at<float>(1) != 0)
+    {
+        x = xMin;
+        y = static_cast<int>(std::floor( - (weights.at<float>(0) * x + shift) / weights.at<float>(1)));
+        if (y >= yMin && y <= yMax)
+        {
+            crossPoint.x = x;
+            crossPoint.y = y;
+            return true;
+        }
+    }
+    else if (yMin == yMax && weights.at<float>(0) != 0)
+    {
+        y = yMin;
+        x = static_cast<int>(std::floor( - (weights.at<float>(1) * y + shift) / weights.at<float>(0)));
+        if (x >= xMin && x <= xMax)
+        {
+            crossPoint.x = x;
+            crossPoint.y = y;
+            return true;
+        }
+    }
+    return false;
+}
+
+bool findPointsForLine(const Mat &weights, float shift, Point points[2], int width, int height)
+{
+    if (weights.empty())
+    {
+        return false;
+    }
+
+    int foundPointsCount = 0;
+    std::vector<std::pair<Point,Point> > segments;
+    fillSegments(segments, width, height);
+
+    for (uint i = 0; i < segments.size(); i++)
+    {
+        if (findCrossPointWithBorders(weights, shift, segments[i], points[foundPointsCount]))
+            foundPointsCount++;
+        if (foundPointsCount >= 2)
+            break;
+    }
+
+    return true;
+}
+
+void redraw(Data data, const Point points[2])
+{
+    data.img.setTo(0);
+    Point center;
+    int radius = 3;
+    Scalar color;
+    CV_Assert((data.samples.type() == CV_32FC1) && (data.responses.type() == CV_32FC1));
+    for (int i = 0; i < data.samples.rows; i++)
+    {
+        center.x = static_cast<int>(data.samples.at<float>(i,0));
+        center.y = static_cast<int>(data.samples.at<float>(i,1));
+        color = (data.responses.at<float>(i) > 0) ? Scalar(128,128,0) : Scalar(0,128,128);
+        circle(data.img, center, radius, color, 5);
+    }
+    line(data.img, points[0], points[1],cv::Scalar(1,255,1));
+
+    imshow("Train svmsgd", data.img);
+}
+
+void addPointRetrainAndRedraw(Data &data, int x, int y, int response)
+{
+    Mat currentSample(1, 2, CV_32FC1);
+
+    currentSample.at<float>(0,0) = (float)x;
+    currentSample.at<float>(0,1) = (float)y;
+    data.samples.push_back(currentSample);
+    data.responses.push_back(static_cast<float>(response));
+
+    Mat weights(1, 2, CV_32FC1);
+    float shift = 0;
+
+    if (doTrain(data.samples, data.responses, weights, shift))
+    {
+        Point points[2];
+        findPointsForLine(weights, shift, points, data.img.cols, data.img.rows);
+
+        redraw(data, points);
+    }
+}
+
+
+static void onMouse( int event, int x, int y, int, void* pData)
+{
+    Data &data = *(Data*)pData;
+
+    switch( event )
+    {
+    case CV_EVENT_LBUTTONUP:
+        addPointRetrainAndRedraw(data, x, y, 1);
+        break;
+
+    case CV_EVENT_RBUTTONDOWN:
+        addPointRetrainAndRedraw(data, x, y, -1);
+        break;
+    }
+
+}
+
+int main()
+{
+    Data data;
+
+    setMouseCallback( "Train svmsgd", onMouse, &data );
+    waitKey();
+
+    return 0;
+}
diff --git a/samples/cpp/tree_engine.cpp b/samples/cpp/tree_engine.cpp
index 4412588..96b2adf 100644
--- a/samples/cpp/tree_engine.cpp
+++ b/samples/cpp/tree_engine.cpp
@@ -1,5 +1,5 @@
-#include "opencv2/ml/ml.hpp"
-#include "opencv2/core/core.hpp"
+#include "opencv2/ml.hpp"
+#include "opencv2/core.hpp"
 #include "opencv2/core/utility.hpp"
 #include <stdio.h>
 #include <string>
diff --git a/samples/cpp/tutorial_code/HighGUI/AddingImagesTrackbar.cpp b/samples/cpp/tutorial_code/HighGUI/AddingImagesTrackbar.cpp
index 9e04dd9..51522fa 100644
--- a/samples/cpp/tutorial_code/HighGUI/AddingImagesTrackbar.cpp
+++ b/samples/cpp/tutorial_code/HighGUI/AddingImagesTrackbar.cpp
@@ -5,7 +5,7 @@
  */
 
 #include "opencv2/imgcodecs.hpp"
-#include "opencv2/highgui/highgui.hpp"
+#include "opencv2/highgui.hpp"
 #include <stdio.h>
 
 using namespace cv;
@@ -21,6 +21,7 @@ Mat src1;
 Mat src2;
 Mat dst;
 
+//![on_trackbar]
 /**
  * @function on_trackbar
  * @brief Callback for trackbar
@@ -35,7 +36,7 @@ static void on_trackbar( int, void* )
 
    imshow( "Linear Blend", dst );
 }
-
+//![on_trackbar]
 
 /**
  * @function main
@@ -43,9 +44,11 @@ static void on_trackbar( int, void* )
  */
 int main( void )
 {
-   /// Read image ( same size, same type )
+   //![load]
+   /// Read images ( both have to be of the same size and type )
    src1 = imread("../data/LinuxLogo.jpg");
    src2 = imread("../data/WindowsLogo.jpg");
+   //![load]
 
    if( src1.empty() ) { printf("Error loading src1 \n"); return -1; }
    if( src2.empty() ) { printf("Error loading src2 \n"); return -1; }
@@ -53,13 +56,15 @@ int main( void )
    /// Initialize values
    alpha_slider = 0;
 
-   /// Create Windows
-   namedWindow("Linear Blend", 1);
+   //![window]
+   namedWindow("Linear Blend", WINDOW_AUTOSIZE); // Create Window
+   //![window]
 
-   /// Create Trackbars
+   //![create_trackbar]
    char TrackbarName[50];
    sprintf( TrackbarName, "Alpha x %d", alpha_slider_max );
    createTrackbar( TrackbarName, "Linear Blend", &alpha_slider, alpha_slider_max, on_trackbar );
+   //![create_trackbar]
 
    /// Show some stuff
    on_trackbar( alpha_slider, 0 );
diff --git a/samples/cpp/tutorial_code/HighGUI/BasicLinearTransformsTrackbar.cpp b/samples/cpp/tutorial_code/HighGUI/BasicLinearTransformsTrackbar.cpp
index 213850f..1834e35 100644
--- a/samples/cpp/tutorial_code/HighGUI/BasicLinearTransformsTrackbar.cpp
+++ b/samples/cpp/tutorial_code/HighGUI/BasicLinearTransformsTrackbar.cpp
@@ -6,7 +6,7 @@
  */
 
 #include "opencv2/imgcodecs.hpp"
-#include "opencv2/highgui/highgui.hpp"
+#include "opencv2/highgui.hpp"
 
 using namespace cv;
 
diff --git a/samples/cpp/tutorial_code/HighGUI/GDAL_IO/gdal-image.cpp b/samples/cpp/tutorial_code/HighGUI/GDAL_IO/gdal-image.cpp
deleted file mode 100644
index 6e7c950..0000000
--- a/samples/cpp/tutorial_code/HighGUI/GDAL_IO/gdal-image.cpp
+++ /dev/null
@@ -1,242 +0,0 @@
-/*
- * gdal_image.cpp -- Load GIS data into OpenCV Containers using the Geospatial Data Abstraction Library
-*/
-
-// OpenCV Headers
-#include "opencv2/core/core.hpp"
-#include "opencv2/imgproc/imgproc.hpp"
-#include "opencv2/highgui/highgui.hpp"
-
-// C++ Standard Libraries
-#include <cmath>
-#include <iostream>
-#include <stdexcept>
-#include <vector>
-
-using namespace std;
-
-// define the corner points
-//    Note that GDAL library can natively determine this
-cv::Point2d tl( -122.441017, 37.815664 );
-cv::Point2d tr( -122.370919, 37.815311 );
-cv::Point2d bl( -122.441533, 37.747167 );
-cv::Point2d br( -122.3715,   37.746814 );
-
-// determine dem corners
-cv::Point2d dem_bl( -122.0, 38);
-cv::Point2d dem_tr( -123.0, 37);
-
-// range of the heat map colors
-std::vector<std::pair<cv::Vec3b,double> > color_range;
-
-
-// List of all function prototypes
-cv::Point2d lerp( const cv::Point2d&, const cv::Point2d&, const double& );
-
-cv::Vec3b get_dem_color( const double& );
-
-cv::Point2d world2dem( const cv::Point2d&, const cv::Size&);
-
-cv::Point2d pixel2world( const int&, const int&, const cv::Size& );
-
-void add_color( cv::Vec3b& pix, const uchar& b, const uchar& g, const uchar& r );
-
-
-
-/*
- * Linear Interpolation
- * p1 - Point 1
- * p2 - Point 2
- * t  - Ratio from Point 1 to Point 2
-*/
-cv::Point2d lerp( cv::Point2d const& p1, cv::Point2d const& p2, const double& t ){
-    return cv::Point2d( ((1-t)*p1.x) + (t*p2.x),
-                        ((1-t)*p1.y) + (t*p2.y));
-}
-
-/*
- * Interpolate Colors
-*/
-template <typename DATATYPE, int N>
-cv::Vec<DATATYPE,N> lerp( cv::Vec<DATATYPE,N> const& minColor,
-                          cv::Vec<DATATYPE,N> const& maxColor,
-                          double const& t ){
-
-    cv::Vec<DATATYPE,N> output;
-    for( int i=0; i<N; i++ ){
-        output[i] = (uchar)(((1-t)*minColor[i]) + (t * maxColor[i]));
-    }
-    return output;
-}
-
-/*
- * Compute the dem color
-*/
-cv::Vec3b get_dem_color( const double& elevation ){
-
-    // if the elevation is below the minimum, return the minimum
-    if( elevation < color_range[0].second ){
-        return color_range[0].first;
-    }
-    // if the elevation is above the maximum, return the maximum
-    if( elevation > color_range.back().second ){
-        return color_range.back().first;
-    }
-
-    // otherwise, find the proper starting index
-    int idx=0;
-    double t = 0;
-    for( int x=0; x<(int)(color_range.size()-1); x++ ){
-
-        // if the current elevation is below the next item, then use the current
-        // two colors as our range
-        if( elevation < color_range[x+1].second ){
-            idx=x;
-            t = (color_range[x+1].second - elevation)/
-                (color_range[x+1].second - color_range[x].second);
-
-            break;
-        }
-    }
-
-    // interpolate the color
-    return lerp( color_range[idx].first, color_range[idx+1].first, t);
-}
-
-/*
- * Given a pixel coordinate and the size of the input image, compute the pixel location
- * on the DEM image.
-*/
-cv::Point2d world2dem( cv::Point2d const& coordinate, const cv::Size& dem_size   ){
-
-
-    // relate this to the dem points
-    // ASSUMING THAT DEM DATA IS ORTHORECTIFIED
-    double demRatioX = ((dem_tr.x - coordinate.x)/(dem_tr.x - dem_bl.x));
-    double demRatioY = 1-((dem_tr.y - coordinate.y)/(dem_tr.y - dem_bl.y));
-
-    cv::Point2d output;
-    output.x = demRatioX * dem_size.width;
-    output.y = demRatioY * dem_size.height;
-
-    return output;
-}
-
-/*
- * Convert a pixel coordinate to world coordinates
-*/
-cv::Point2d pixel2world( const int& x, const int& y, const cv::Size& size ){
-
-    // compute the ratio of the pixel location to its dimension
-    double rx = (double)x / size.width;
-    double ry = (double)y / size.height;
-
-    // compute LERP of each coordinate
-    cv::Point2d rightSide = lerp(tr, br, ry);
-    cv::Point2d leftSide  = lerp(tl, bl, ry);
-
-    // compute the actual Lat/Lon coordinate of the interpolated coordinate
-    return lerp( leftSide, rightSide, rx );
-}
-
-/*
- * Add color to a specific pixel color value
-*/
-void add_color( cv::Vec3b& pix, const uchar& b, const uchar& g, const uchar& r ){
-
-    if( pix[0] + b < 255 && pix[0] + b >= 0 ){ pix[0] += b; }
-    if( pix[1] + g < 255 && pix[1] + g >= 0 ){ pix[1] += g; }
-    if( pix[2] + r < 255 && pix[2] + r >= 0 ){ pix[2] += r; }
-}
-
-
-/*
- * Main Function
-*/
-int main( int argc, char* argv[] ){
-
-    /*
-     * Check input arguments
-    */
-    if( argc < 3 ){
-        cout << "usage: " << argv[0] << " <image> <dem>" << endl;
-        return 1;
-    }
-
-    // load the image (note that we don't have the projection information.  You will
-    // need to load that yourself or use the full GDAL driver.  The values are pre-defined
-    // at the top of this file
-    cv::Mat image = cv::imread(argv[1], cv::IMREAD_LOAD_GDAL | cv::IMREAD_COLOR );
-
-    // load the dem model
-    cv::Mat dem = cv::imread(argv[2], cv::IMREAD_LOAD_GDAL | cv::IMREAD_ANYDEPTH );
-
-    // create our output products
-    cv::Mat output_dem(   image.size(), CV_8UC3 );
-    cv::Mat output_dem_flood(   image.size(), CV_8UC3 );
-
-    // for sanity sake, make sure GDAL Loads it as a signed short
-    if( dem.type() != CV_16SC1 ){ throw std::runtime_error("DEM image type must be CV_16SC1"); }
-
-    // define the color range to create our output DEM heat map
-    //  Pair format ( Color, elevation );  Push from low to high
-    //  Note:  This would be perfect for a configuration file, but is here for a working demo.
-    color_range.push_back( std::pair<cv::Vec3b,double>(cv::Vec3b( 188, 154,  46),   -1));
-    color_range.push_back( std::pair<cv::Vec3b,double>(cv::Vec3b( 110, 220, 110), 0.25));
-    color_range.push_back( std::pair<cv::Vec3b,double>(cv::Vec3b( 150, 250, 230),   20));
-    color_range.push_back( std::pair<cv::Vec3b,double>(cv::Vec3b( 160, 220, 200),   75));
-    color_range.push_back( std::pair<cv::Vec3b,double>(cv::Vec3b( 220, 190, 170),  100));
-    color_range.push_back( std::pair<cv::Vec3b,double>(cv::Vec3b( 250, 180, 140),  200));
-
-    // define a minimum elevation
-    double minElevation = -10;
-
-    // iterate over each pixel in the image, computing the dem point
-    for( int y=0; y<image.rows; y++ ){
-    for( int x=0; x<image.cols; x++ ){
-
-        // convert the pixel coordinate to lat/lon coordinates
-        cv::Point2d coordinate = pixel2world( x, y, image.size() );
-
-        // compute the dem image pixel coordinate from lat/lon
-        cv::Point2d dem_coordinate = world2dem( coordinate, dem.size() );
-
-        // extract the elevation
-        double dz;
-        if( dem_coordinate.x >=    0    && dem_coordinate.y >=    0     &&
-            dem_coordinate.x < dem.cols && dem_coordinate.y < dem.rows ){
-            dz = dem.at<short>(dem_coordinate);
-        }else{
-            dz = minElevation;
-        }
-
-        // write the pixel value to the file
-        output_dem_flood.at<cv::Vec3b>(y,x) = image.at<cv::Vec3b>(y,x);
-
-        // compute the color for the heat map output
-        cv::Vec3b actualColor = get_dem_color(dz);
-        output_dem.at<cv::Vec3b>(y,x) = actualColor;
-
-        // show effect of a 10 meter increase in ocean levels
-        if( dz < 10 ){
-            add_color( output_dem_flood.at<cv::Vec3b>(y,x), 90, 0, 0 );
-        }
-        // show effect of a 50 meter increase in ocean levels
-        else if( dz < 50 ){
-            add_color( output_dem_flood.at<cv::Vec3b>(y,x), 0, 90, 0 );
-        }
-        // show effect of a 100 meter increase in ocean levels
-        else if( dz < 100 ){
-            add_color( output_dem_flood.at<cv::Vec3b>(y,x), 0, 0, 90 );
-        }
-
-    }}
-
-    // print our heat map
-    cv::imwrite( "heat-map.jpg"   ,  output_dem );
-
-    // print the flooding effect image
-    cv::imwrite( "flooded.jpg",  output_dem_flood);
-
-    return 0;
-}
diff --git a/samples/cpp/tutorial_code/HighGUI/video-input-psnr-ssim/video-input-psnr-ssim.cpp b/samples/cpp/tutorial_code/HighGUI/video-input-psnr-ssim/video-input-psnr-ssim.cpp
deleted file mode 100644
index 4c5bf9f..0000000
--- a/samples/cpp/tutorial_code/HighGUI/video-input-psnr-ssim/video-input-psnr-ssim.cpp
+++ /dev/null
@@ -1,208 +0,0 @@
-#include <iostream> // for standard I/O
-#include <string>   // for strings
-#include <iomanip>  // for controlling float print precision
-#include <sstream>  // string to number conversion
-
-#include <opencv2/core/core.hpp>        // Basic OpenCV structures (cv::Mat, Scalar)
-#include <opencv2/imgproc/imgproc.hpp>  // Gaussian Blur
-#include <opencv2/videoio/videoio.hpp>
-#include <opencv2/highgui/highgui.hpp>  // OpenCV window I/O
-
-using namespace std;
-using namespace cv;
-
-double getPSNR ( const Mat& I1, const Mat& I2);
-Scalar getMSSIM( const Mat& I1, const Mat& I2);
-
-static void help()
-{
-    cout
-        << "------------------------------------------------------------------------------" << endl
-        << "This program shows how to read a video file with OpenCV. In addition, it "
-        << "tests the similarity of two input videos first with PSNR, and for the frames "
-        << "below a PSNR trigger value, also with MSSIM."                                   << endl
-        << "Usage:"                                                                         << endl
-        << "./video-source referenceVideo useCaseTestVideo PSNR_Trigger_Value Wait_Between_Frames " << endl
-        << "--------------------------------------------------------------------------"     << endl
-        << endl;
-}
-
-int main(int argc, char *argv[])
-{
-    help();
-
-    if (argc != 5)
-    {
-        cout << "Not enough parameters" << endl;
-        return -1;
-    }
-
-    stringstream conv;
-
-    const string sourceReference = argv[1], sourceCompareWith = argv[2];
-    int psnrTriggerValue, delay;
-    conv << argv[3] << endl << argv[4];       // put in the strings
-    conv >> psnrTriggerValue >> delay;        // take out the numbers
-
-    char c;
-    int frameNum = -1;          // Frame counter
-
-    VideoCapture captRefrnc(sourceReference), captUndTst(sourceCompareWith);
-
-    if (!captRefrnc.isOpened())
-    {
-        cout  << "Could not open reference " << sourceReference << endl;
-        return -1;
-    }
-
-    if (!captUndTst.isOpened())
-    {
-        cout  << "Could not open case test " << sourceCompareWith << endl;
-        return -1;
-    }
-
-    Size refS = Size((int) captRefrnc.get(CAP_PROP_FRAME_WIDTH),
-                     (int) captRefrnc.get(CAP_PROP_FRAME_HEIGHT)),
-         uTSi = Size((int) captUndTst.get(CAP_PROP_FRAME_WIDTH),
-                     (int) captUndTst.get(CAP_PROP_FRAME_HEIGHT));
-
-    if (refS != uTSi)
-    {
-        cout << "Inputs have different size!!! Closing." << endl;
-        return -1;
-    }
-
-    const char* WIN_UT = "Under Test";
-    const char* WIN_RF = "Reference";
-
-    // Windows
-    namedWindow(WIN_RF, WINDOW_AUTOSIZE);
-    namedWindow(WIN_UT, WINDOW_AUTOSIZE);
-    moveWindow(WIN_RF, 400       , 0);         //750,  2 (bernat =0)
-    moveWindow(WIN_UT, refS.width, 0);         //1500, 2
-
-    cout << "Reference frame resolution: Width=" << refS.width << "  Height=" << refS.height
-         << " of nr#: " << captRefrnc.get(CAP_PROP_FRAME_COUNT) << endl;
-
-    cout << "PSNR trigger value " << setiosflags(ios::fixed) << setprecision(3)
-         << psnrTriggerValue << endl;
-
-    Mat frameReference, frameUnderTest;
-    double psnrV;
-    Scalar mssimV;
-
-    for(;;) //Show the image captured in the window and repeat
-    {
-        captRefrnc >> frameReference;
-        captUndTst >> frameUnderTest;
-
-        if (frameReference.empty() || frameUnderTest.empty())
-        {
-            cout << " < < <  Game over!  > > > ";
-            break;
-        }
-
-        ++frameNum;
-        cout << "Frame: " << frameNum << "# ";
-
-        ///////////////////////////////// PSNR ////////////////////////////////////////////////////
-        psnrV = getPSNR(frameReference,frameUnderTest);
-        cout << setiosflags(ios::fixed) << setprecision(3) << psnrV << "dB";
-
-        //////////////////////////////////// MSSIM /////////////////////////////////////////////////
-        if (psnrV < psnrTriggerValue && psnrV)
-        {
-            mssimV = getMSSIM(frameReference, frameUnderTest);
-
-            cout << " MSSIM: "
-                << " R " << setiosflags(ios::fixed) << setprecision(2) << mssimV.val[2] * 100 << "%"
-                << " G " << setiosflags(ios::fixed) << setprecision(2) << mssimV.val[1] * 100 << "%"
-                << " B " << setiosflags(ios::fixed) << setprecision(2) << mssimV.val[0] * 100 << "%";
-        }
-
-        cout << endl;
-
-        ////////////////////////////////// Show Image /////////////////////////////////////////////
-        imshow(WIN_RF, frameReference);
-        imshow(WIN_UT, frameUnderTest);
-
-        c = (char)waitKey(delay);
-        if (c == 27) break;
-    }
-
-    return 0;
-}
-
-double getPSNR(const Mat& I1, const Mat& I2)
-{
-    Mat s1;
-    absdiff(I1, I2, s1);       // |I1 - I2|
-    s1.convertTo(s1, CV_32F);  // cannot make a square on 8 bits
-    s1 = s1.mul(s1);           // |I1 - I2|^2
-
-    Scalar s = sum(s1);        // sum elements per channel
-
-    double sse = s.val[0] + s.val[1] + s.val[2]; // sum channels
-
-    if( sse <= 1e-10) // for small values return zero
-        return 0;
-    else
-    {
-        double mse  = sse / (double)(I1.channels() * I1.total());
-        double psnr = 10.0 * log10((255 * 255) / mse);
-        return psnr;
-    }
-}
-
-Scalar getMSSIM( const Mat& i1, const Mat& i2)
-{
-    const double C1 = 6.5025, C2 = 58.5225;
-    /***************************** INITS **********************************/
-    int d = CV_32F;
-
-    Mat I1, I2;
-    i1.convertTo(I1, d);            // cannot calculate on one byte large values
-    i2.convertTo(I2, d);
-
-    Mat I2_2   = I2.mul(I2);        // I2^2
-    Mat I1_2   = I1.mul(I1);        // I1^2
-    Mat I1_I2  = I1.mul(I2);        // I1 * I2
-
-    /*************************** END INITS **********************************/
-
-    Mat mu1, mu2;                   // PRELIMINARY COMPUTING
-    GaussianBlur(I1, mu1, Size(11, 11), 1.5);
-    GaussianBlur(I2, mu2, Size(11, 11), 1.5);
-
-    Mat mu1_2   =   mu1.mul(mu1);
-    Mat mu2_2   =   mu2.mul(mu2);
-    Mat mu1_mu2 =   mu1.mul(mu2);
-
-    Mat sigma1_2, sigma2_2, sigma12;
-
-    GaussianBlur(I1_2, sigma1_2, Size(11, 11), 1.5);
-    sigma1_2 -= mu1_2;
-
-    GaussianBlur(I2_2, sigma2_2, Size(11, 11), 1.5);
-    sigma2_2 -= mu2_2;
-
-    GaussianBlur(I1_I2, sigma12, Size(11, 11), 1.5);
-    sigma12 -= mu1_mu2;
-
-    ///////////////////////////////// FORMULA ////////////////////////////////
-    Mat t1, t2, t3;
-
-    t1 = 2 * mu1_mu2 + C1;
-    t2 = 2 * sigma12 + C2;
-    t3 = t1.mul(t2);                 // t3 = ((2*mu1_mu2 + C1).*(2*sigma12 + C2))
-
-    t1 = mu1_2 + mu2_2 + C1;
-    t2 = sigma1_2 + sigma2_2 + C2;
-    t1 = t1.mul(t2);                 // t1 =((mu1_2 + mu2_2 + C1).*(sigma1_2 + sigma2_2 + C2))
-
-    Mat ssim_map;
-    divide(t3, t1, ssim_map);        // ssim_map =  t3./t1;
-
-    Scalar mssim = mean(ssim_map);   // mssim = average of ssim map
-    return mssim;
-}
diff --git a/samples/cpp/tutorial_code/HighGUI/video-write/video-write.cpp b/samples/cpp/tutorial_code/HighGUI/video-write/video-write.cpp
deleted file mode 100644
index 9218cf2..0000000
--- a/samples/cpp/tutorial_code/HighGUI/video-write/video-write.cpp
+++ /dev/null
@@ -1,95 +0,0 @@
-#include <iostream>	// for standard I/O
-#include <string>   // for strings
-
-#include <opencv2/core/core.hpp>        // Basic OpenCV structures (cv::Mat)
-#include <opencv2/videoio/videoio.hpp>  // Video write
-
-using namespace std;
-using namespace cv;
-
-static void help()
-{
-    cout
-        << "------------------------------------------------------------------------------" << endl
-        << "This program shows how to write video files."                                   << endl
-        << "You can extract the R or G or B color channel of the input video."              << endl
-        << "Usage:"                                                                         << endl
-        << "./video-write inputvideoName [ R | G | B] [Y | N]"                              << endl
-        << "------------------------------------------------------------------------------" << endl
-        << endl;
-}
-
-int main(int argc, char *argv[])
-{
-    help();
-
-    if (argc != 4)
-    {
-        cout << "Not enough parameters" << endl;
-        return -1;
-    }
-
-    const string source      = argv[1];           // the source file name
-    const bool askOutputType = argv[3][0] =='Y';  // If false it will use the inputs codec type
-
-    VideoCapture inputVideo(source);              // Open input
-    if (!inputVideo.isOpened())
-    {
-        cout  << "Could not open the input video: " << source << endl;
-        return -1;
-    }
-
-    string::size_type pAt = source.find_last_of('.');                  // Find extension point
-    const string NAME = source.substr(0, pAt) + argv[2][0] + ".avi";   // Form the new name with container
-    int ex = static_cast<int>(inputVideo.get(CAP_PROP_FOURCC));     // Get Codec Type- Int form
-
-    // Transform from int to char via Bitwise operators
-    char EXT[] = {(char)(ex & 0XFF) , (char)((ex & 0XFF00) >> 8),(char)((ex & 0XFF0000) >> 16),(char)((ex & 0XFF000000) >> 24), 0};
-
-    Size S = Size((int) inputVideo.get(CAP_PROP_FRAME_WIDTH),    // Acquire input size
-                  (int) inputVideo.get(CAP_PROP_FRAME_HEIGHT));
-
-    VideoWriter outputVideo;                                        // Open the output
-    if (askOutputType)
-        outputVideo.open(NAME, ex=-1, inputVideo.get(CAP_PROP_FPS), S, true);
-    else
-        outputVideo.open(NAME, ex, inputVideo.get(CAP_PROP_FPS), S, true);
-
-    if (!outputVideo.isOpened())
-    {
-        cout  << "Could not open the output video for write: " << source << endl;
-        return -1;
-    }
-
-    cout << "Input frame resolution: Width=" << S.width << "  Height=" << S.height
-         << " of nr#: " << inputVideo.get(CAP_PROP_FRAME_COUNT) << endl;
-    cout << "Input codec type: " << EXT << endl;
-
-    int channel = 2; // Select the channel to save
-    switch(argv[2][0])
-    {
-    case 'R' : channel = 2; break;
-    case 'G' : channel = 1; break;
-    case 'B' : channel = 0; break;
-    }
-    Mat src, res;
-    vector<Mat> spl;
-
-    for(;;) //Show the image captured in the window and repeat
-    {
-        inputVideo >> src;              // read
-        if (src.empty()) break;         // check if at end
-
-        split(src, spl);                // process - extract only the correct channel
-        for (int i =0; i < 3; ++i)
-            if (i != channel)
-                spl[i] = Mat::zeros(S, spl[0].type());
-       merge(spl, res);
-
-       //outputVideo.write(res); //save or
-       outputVideo << res;
-    }
-
-    cout << "Finished writing" << endl;
-    return 0;
-}
diff --git a/samples/cpp/tutorial_code/Histograms_Matching/EqualizeHist_Demo.cpp b/samples/cpp/tutorial_code/Histograms_Matching/EqualizeHist_Demo.cpp
index 45db585..80d4d46 100644
--- a/samples/cpp/tutorial_code/Histograms_Matching/EqualizeHist_Demo.cpp
+++ b/samples/cpp/tutorial_code/Histograms_Matching/EqualizeHist_Demo.cpp
@@ -5,10 +5,9 @@
  */
 
 #include "opencv2/imgcodecs.hpp"
-#include "opencv2/highgui/highgui.hpp"
-#include "opencv2/imgproc/imgproc.hpp"
+#include "opencv2/highgui.hpp"
+#include "opencv2/imgproc.hpp"
 #include <iostream>
-#include <stdio.h>
 
 using namespace cv;
 using namespace std;
@@ -24,10 +23,10 @@ int main( int, char** argv )
   const char* equalized_window = "Equalized Image";
 
   /// Load image
-  src = imread( argv[1], 1 );
+  src = imread( argv[1], IMREAD_COLOR );
 
   if( src.empty() )
-    { cout<<"Usage: ./Histogram_Demo <path_to_image>"<<endl;
+    { cout<<"Usage: ./EqualizeHist_Demo <path_to_image>"<<endl;
       return -1;
     }
 
diff --git a/samples/cpp/tutorial_code/Histograms_Matching/MatchTemplate_Demo.cpp b/samples/cpp/tutorial_code/Histograms_Matching/MatchTemplate_Demo.cpp
index e106cb4..1042e2c 100644
--- a/samples/cpp/tutorial_code/Histograms_Matching/MatchTemplate_Demo.cpp
+++ b/samples/cpp/tutorial_code/Histograms_Matching/MatchTemplate_Demo.cpp
@@ -5,16 +5,16 @@
  */
 
 #include "opencv2/imgcodecs.hpp"
-#include "opencv2/highgui/highgui.hpp"
-#include "opencv2/imgproc/imgproc.hpp"
+#include "opencv2/highgui.hpp"
+#include "opencv2/imgproc.hpp"
 #include <iostream>
-#include <stdio.h>
 
 using namespace std;
 using namespace cv;
 
 /// Global Variables
-Mat img; Mat templ; Mat result;
+bool use_mask;
+Mat img; Mat templ; Mat mask; Mat result;
 const char* image_window = "Source Image";
 const char* result_window = "Result window";
 
@@ -27,11 +27,29 @@ void MatchingMethod( int, void* );
 /**
  * @function main
  */
-int main( int, char** argv )
+int main( int argc, char** argv )
 {
+  if (argc < 3)
+  {
+    cout << "Not enough parameters" << endl;
+    cout << "Usage:\n./MatchTemplate_Demo <image_name> <template_name> [<mask_name>]" << endl;
+    return -1;
+  }
+
   /// Load image and template
-  img = imread( argv[1], 1 );
-  templ = imread( argv[2], 1 );
+  img = imread( argv[1], IMREAD_COLOR );
+  templ = imread( argv[2], IMREAD_COLOR );
+
+  if(argc > 3) {
+    use_mask = true;
+    mask = imread( argv[3], IMREAD_COLOR );
+  }
+
+  if(img.empty() || templ.empty() || (use_mask && mask.empty()))
+  {
+    cout << "Can't read one of the images" << endl;
+    return -1;
+  }
 
   /// Create windows
   namedWindow( image_window, WINDOW_AUTOSIZE );
@@ -64,7 +82,12 @@ void MatchingMethod( int, void* )
   result.create( result_rows, result_cols, CV_32FC1 );
 
   /// Do the Matching and Normalize
-  matchTemplate( img, templ, result, match_method );
+  bool method_accepts_mask = (CV_TM_SQDIFF == match_method || match_method == CV_TM_CCORR_NORMED);
+  if (use_mask && method_accepts_mask)
+    { matchTemplate( img, templ, result, match_method, mask); }
+  else
+    { matchTemplate( img, templ, result, match_method); }
+
   normalize( result, result, 0, 1, NORM_MINMAX, -1, Mat() );
 
   /// Localizing the best match with minMaxLoc
diff --git a/samples/cpp/tutorial_code/Histograms_Matching/calcBackProject_Demo1.cpp b/samples/cpp/tutorial_code/Histograms_Matching/calcBackProject_Demo1.cpp
index ce0e911..1e2fe92 100644
--- a/samples/cpp/tutorial_code/Histograms_Matching/calcBackProject_Demo1.cpp
+++ b/samples/cpp/tutorial_code/Histograms_Matching/calcBackProject_Demo1.cpp
@@ -4,9 +4,9 @@
  * @author OpenCV team
  */
 
-#include "opencv2/imgproc/imgproc.hpp"
+#include "opencv2/imgproc.hpp"
 #include "opencv2/imgcodecs.hpp"
-#include "opencv2/highgui/highgui.hpp"
+#include "opencv2/highgui.hpp"
 
 #include <iostream>
 
@@ -27,7 +27,13 @@ void Hist_and_Backproj(int, void* );
 int main( int, char** argv )
 {
   /// Read the image
-  src = imread( argv[1], 1 );
+  src = imread( argv[1], IMREAD_COLOR );
+
+  if( src.empty() )
+    { cout<<"Usage: ./calcBackProject_Demo1 <path_to_image>"<<endl;
+      return -1;
+    }
+
   /// Transform it to HSV
   cvtColor( src, hsv, COLOR_BGR2HSV );
 
diff --git a/samples/cpp/tutorial_code/Histograms_Matching/calcBackProject_Demo2.cpp b/samples/cpp/tutorial_code/Histograms_Matching/calcBackProject_Demo2.cpp
index ff7b369..ecb7737 100644
--- a/samples/cpp/tutorial_code/Histograms_Matching/calcBackProject_Demo2.cpp
+++ b/samples/cpp/tutorial_code/Histograms_Matching/calcBackProject_Demo2.cpp
@@ -4,9 +4,9 @@
  * @author OpenCV team
  */
 
-#include "opencv2/imgproc/imgproc.hpp"
+#include "opencv2/imgproc.hpp"
 #include "opencv2/imgcodecs.hpp"
-#include "opencv2/highgui/highgui.hpp"
+#include "opencv2/highgui.hpp"
 
 #include <iostream>
 
@@ -30,7 +30,7 @@ void pickPoint (int event, int x, int y, int, void* );
 int main( int, char** argv )
 {
   /// Read the image
-  src = imread( argv[1], 1 );
+  src = imread( argv[1], IMREAD_COLOR );
   /// Transform it to HSV
   cvtColor( src, hsv, COLOR_BGR2HSV );
 
diff --git a/samples/cpp/tutorial_code/Histograms_Matching/calcHist_Demo.cpp b/samples/cpp/tutorial_code/Histograms_Matching/calcHist_Demo.cpp
index 1540cd8..27e21e7 100644
--- a/samples/cpp/tutorial_code/Histograms_Matching/calcHist_Demo.cpp
+++ b/samples/cpp/tutorial_code/Histograms_Matching/calcHist_Demo.cpp
@@ -4,11 +4,10 @@
  * @author
  */
 
-#include "opencv2/highgui/highgui.hpp"
+#include "opencv2/highgui.hpp"
 #include "opencv2/imgcodecs.hpp"
-#include "opencv2/imgproc/imgproc.hpp"
+#include "opencv2/imgproc.hpp"
 #include <iostream>
-#include <stdio.h>
 
 using namespace std;
 using namespace cv;
@@ -16,12 +15,19 @@ using namespace cv;
 /**
  * @function main
  */
-int main( int, char** argv )
+int main(int argc, char** argv)
 {
   Mat src, dst;
 
   /// Load image
-  src = imread( argv[1], 1 );
+  String imageName( "../data/lena.jpg" ); // by default
+
+  if (argc > 1)
+  {
+      imageName = argv[1];
+  }
+
+  src = imread( imageName, IMREAD_COLOR );
 
   if( src.empty() )
     { return -1; }
diff --git a/samples/cpp/tutorial_code/Histograms_Matching/compareHist_Demo.cpp b/samples/cpp/tutorial_code/Histograms_Matching/compareHist_Demo.cpp
index 122e19b..4d0123b 100644
--- a/samples/cpp/tutorial_code/Histograms_Matching/compareHist_Demo.cpp
+++ b/samples/cpp/tutorial_code/Histograms_Matching/compareHist_Demo.cpp
@@ -5,10 +5,9 @@
  */
 
 #include "opencv2/imgcodecs.hpp"
-#include "opencv2/highgui/highgui.hpp"
-#include "opencv2/imgproc/imgproc.hpp"
+#include "opencv2/highgui.hpp"
+#include "opencv2/imgproc.hpp"
 #include <iostream>
-#include <stdio.h>
 
 using namespace std;
 using namespace cv;
@@ -26,13 +25,19 @@ int main( int argc, char** argv )
     /// Load three images with different environment settings
     if( argc < 4 )
     {
-        printf("** Error. Usage: ./compareHist_Demo <image_settings0> <image_setting1> <image_settings2>\n");
+        printf("** Error. Usage: ./compareHist_Demo <image_settings0> <image_settings1> <image_settings2>\n");
         return -1;
     }
 
-    src_base = imread( argv[1], 1 );
-    src_test1 = imread( argv[2], 1 );
-    src_test2 = imread( argv[3], 1 );
+    src_base = imread( argv[1], IMREAD_COLOR );
+    src_test1 = imread( argv[2], IMREAD_COLOR );
+    src_test2 = imread( argv[3], IMREAD_COLOR );
+
+    if(src_base.empty() || src_test1.empty() || src_test2.empty())
+    {
+      cout << "Can't read one of the images" << endl;
+      return -1;
+    }
 
     /// Convert to HSV
     cvtColor( src_base, hsv_base, COLOR_BGR2HSV );
diff --git a/samples/cpp/tutorial_code/ImgProc/AddingImages.cpp b/samples/cpp/tutorial_code/ImgProc/AddingImages.cpp
deleted file mode 100644
index 32ce10f..0000000
--- a/samples/cpp/tutorial_code/ImgProc/AddingImages.cpp
+++ /dev/null
@@ -1,52 +0,0 @@
-/**
- * @file AddingImages.cpp
- * @brief Simple linear blender ( dst = alpha*src1 + beta*src2 )
- * @author OpenCV team
- */
-
-#include "opencv2/imgcodecs.hpp"
-#include "opencv2/highgui/highgui.hpp"
-#include <iostream>
-
-using namespace cv;
-
-/**
- * @function main
- * @brief Main function
- */
-int main( void )
-{
-
-   double alpha = 0.5; double beta; double input;
-
-   Mat src1, src2, dst;
-
-   /// Ask the user enter alpha
-   std::cout<<" Simple Linear Blender "<<std::endl;
-   std::cout<<"-----------------------"<<std::endl;
-   std::cout<<"* Enter alpha [0-1]: ";
-   std::cin>>input;
-
-   // We use the alpha provided by the user iff it is between 0 and 1
-   if( alpha >= 0 && alpha <= 1 )
-     { alpha = input; }
-
-   /// Read image ( same size, same type )
-   src1 = imread("../data/LinuxLogo.jpg");
-   src2 = imread("../data/WindowsLogo.jpg");
-
-   if( src1.empty() ) { std::cout<< "Error loading src1"<<std::endl; return -1; }
-   if( src2.empty() ) { std::cout<< "Error loading src2"<<std::endl; return -1; }
-
-   /// Create Windows
-   namedWindow("Linear Blend", 1);
-
-   beta = ( 1.0 - alpha );
-   addWeighted( src1, alpha, src2, beta, 0.0, dst);
-
-   imshow( "Linear Blend", dst );
-
-
-   waitKey(0);
-   return 0;
-}
diff --git a/samples/cpp/tutorial_code/ImgProc/BasicLinearTransforms.cpp b/samples/cpp/tutorial_code/ImgProc/BasicLinearTransforms.cpp
index 9ffe156..b24451d 100644
--- a/samples/cpp/tutorial_code/ImgProc/BasicLinearTransforms.cpp
+++ b/samples/cpp/tutorial_code/ImgProc/BasicLinearTransforms.cpp
@@ -5,7 +5,7 @@
  */
 
 #include "opencv2/imgcodecs.hpp"
-#include "opencv2/highgui/highgui.hpp"
+#include "opencv2/highgui.hpp"
 #include <iostream>
 
 using namespace cv;
diff --git a/samples/cpp/tutorial_code/ImgProc/Morphology_1.cpp b/samples/cpp/tutorial_code/ImgProc/Morphology_1.cpp
index e8fac91..cfcd755 100644
--- a/samples/cpp/tutorial_code/ImgProc/Morphology_1.cpp
+++ b/samples/cpp/tutorial_code/ImgProc/Morphology_1.cpp
@@ -4,11 +4,9 @@
  * @author OpenCV team
  */
 
-#include "opencv2/imgproc/imgproc.hpp"
+#include "opencv2/imgproc.hpp"
 #include "opencv2/imgcodecs.hpp"
-#include "opencv2/highgui/highgui.hpp"
-#include <stdlib.h>
-#include <stdio.h>
+#include "opencv2/highgui.hpp"
 
 using namespace cv;
 
@@ -32,7 +30,7 @@ void Dilation( int, void* );
 int main( int, char** argv )
 {
   /// Load an image
-  src = imread( argv[1] );
+  src = imread( argv[1], IMREAD_COLOR );
 
   if( src.empty() )
     { return -1; }
@@ -68,6 +66,7 @@ int main( int, char** argv )
   return 0;
 }
 
+//![erosion]
 /**
  * @function Erosion
  */
@@ -78,14 +77,19 @@ void Erosion( int, void* )
   else if( erosion_elem == 1 ){ erosion_type = MORPH_CROSS; }
   else if( erosion_elem == 2) { erosion_type = MORPH_ELLIPSE; }
 
+  //![kernel]
   Mat element = getStructuringElement( erosion_type,
                        Size( 2*erosion_size + 1, 2*erosion_size+1 ),
                        Point( erosion_size, erosion_size ) );
+  //![kernel]
+
   /// Apply the erosion operation
   erode( src, erosion_dst, element );
   imshow( "Erosion Demo", erosion_dst );
 }
+//![erosion]
 
+//![dilation]
 /**
  * @function Dilation
  */
@@ -99,7 +103,9 @@ void Dilation( int, void* )
   Mat element = getStructuringElement( dilation_type,
                        Size( 2*dilation_size + 1, 2*dilation_size+1 ),
                        Point( dilation_size, dilation_size ) );
+
   /// Apply the dilation operation
   dilate( src, dilation_dst, element );
   imshow( "Dilation Demo", dilation_dst );
 }
+//![dilation]
diff --git a/samples/cpp/tutorial_code/ImgProc/Morphology_2.cpp b/samples/cpp/tutorial_code/ImgProc/Morphology_2.cpp
index 3f43eee..7a8fb57 100644
--- a/samples/cpp/tutorial_code/ImgProc/Morphology_2.cpp
+++ b/samples/cpp/tutorial_code/ImgProc/Morphology_2.cpp
@@ -4,11 +4,9 @@
  * @author OpenCV team
  */
 
-#include "opencv2/imgproc/imgproc.hpp"
+#include "opencv2/imgproc.hpp"
 #include "opencv2/imgcodecs.hpp"
-#include "opencv2/highgui/highgui.hpp"
-#include <stdlib.h>
-#include <stdio.h>
+#include "opencv2/highgui.hpp"
 
 using namespace cv;
 
@@ -33,27 +31,35 @@ void Morphology_Operations( int, void* );
  */
 int main( int, char** argv )
 {
-  /// Load an image
-  src = imread( argv[1] );
+  //![load]
+  src = imread( argv[1], IMREAD_COLOR ); // Load an image
 
   if( src.empty() )
     { return -1; }
+  //![load]
 
-  /// Create window
-  namedWindow( window_name, WINDOW_AUTOSIZE );
+  //![window]
+  namedWindow( window_name, WINDOW_AUTOSIZE ); // Create window
+  //![window]
 
+  //![create_trackbar1]
   /// Create Trackbar to select Morphology operation
   createTrackbar("Operator:\n 0: Opening - 1: Closing  \n 2: Gradient - 3: Top Hat \n 4: Black Hat", window_name, &morph_operator, max_operator, Morphology_Operations );
+  //![create_trackbar1]
 
+  //![create_trackbar2]
   /// Create Trackbar to select kernel type
   createTrackbar( "Element:\n 0: Rect - 1: Cross - 2: Ellipse", window_name,
                   &morph_elem, max_elem,
                   Morphology_Operations );
+  //![create_trackbar2]
 
+  //![create_trackbar3]
   /// Create Trackbar to choose kernel size
   createTrackbar( "Kernel size:\n 2n +1", window_name,
                   &morph_size, max_kernel_size,
                   Morphology_Operations );
+  //![create_trackbar3]
 
   /// Default start
   Morphology_Operations( 0, 0 );
@@ -62,14 +68,16 @@ int main( int, char** argv )
   return 0;
 }
 
+//![morphology_operations]
 /**
  * @function Morphology_Operations
  */
 void Morphology_Operations( int, void* )
 {
-
   // Since MORPH_X : 2,3,4,5 and 6
+  //![operation]
   int operation = morph_operator + 2;
+  //![operation]
 
   Mat element = getStructuringElement( morph_elem, Size( 2*morph_size + 1, 2*morph_size+1 ), Point( morph_size, morph_size ) );
 
@@ -77,3 +85,4 @@ void Morphology_Operations( int, void* )
   morphologyEx( src, dst, operation, element );
   imshow( window_name, dst );
 }
+//![morphology_operations]
diff --git a/samples/cpp/tutorial_code/ImgProc/Pyramids.cpp b/samples/cpp/tutorial_code/ImgProc/Pyramids.cpp
index c52c0e0..62c2fe5 100644
--- a/samples/cpp/tutorial_code/ImgProc/Pyramids.cpp
+++ b/samples/cpp/tutorial_code/ImgProc/Pyramids.cpp
@@ -4,12 +4,9 @@
  * @author OpenCV team
  */
 
-#include "opencv2/imgproc/imgproc.hpp"
+#include "opencv2/imgproc.hpp"
 #include "opencv2/imgcodecs.hpp"
-#include "opencv2/highgui/highgui.hpp"
-#include <math.h>
-#include <stdlib.h>
-#include <stdio.h>
+#include "opencv2/highgui.hpp"
 
 using namespace cv;
 
@@ -31,39 +28,46 @@ int main( void )
   printf( " * [d] -> Zoom out \n" );
   printf( " * [ESC] -> Close program \n \n" );
 
-  /// Test image - Make sure it s divisible by 2^{n}
-  src = imread( "../data/chicky_512.png" );
+  //![load]
+  src = imread( "../data/chicky_512.png" ); // Loads the test image
   if( src.empty() )
     { printf(" No data! -- Exiting the program \n");
       return -1; }
+  //![load]
 
   tmp = src;
   dst = tmp;
 
-  /// Create window
-  namedWindow( window_name, WINDOW_AUTOSIZE );
+  //![create_window]
   imshow( window_name, dst );
+  //![create_window]
 
-  /// Loop
+  //![infinite_loop]
   for(;;)
   {
-    int c;
-    c = waitKey(10);
+    char c = (char)waitKey(0);
 
-    if( (char)c == 27 )
+    if( c == 27 )
       { break; }
-    if( (char)c == 'u' )
+    //![pyrup]
+    if( c == 'u' )
       { pyrUp( tmp, dst, Size( tmp.cols*2, tmp.rows*2 ) );
         printf( "** Zoom In: Image x 2 \n" );
       }
-    else if( (char)c == 'd' )
+    //![pyrup]
+    //![pyrdown]
+    else if( c == 'd' )
       { pyrDown( tmp, dst, Size( tmp.cols/2, tmp.rows/2 ) );
         printf( "** Zoom Out: Image / 2 \n" );
       }
-
+    //![pyrdown]
     imshow( window_name, dst );
+
+    //![update_tmp]
     tmp = dst;
+    //![update_tmp]
    }
+   //![infinite_loop]
 
    return 0;
 }
diff --git a/samples/cpp/tutorial_code/ImgProc/Smoothing.cpp b/samples/cpp/tutorial_code/ImgProc/Smoothing.cpp
index e7ac4d4..58aa474 100644
--- a/samples/cpp/tutorial_code/ImgProc/Smoothing.cpp
+++ b/samples/cpp/tutorial_code/ImgProc/Smoothing.cpp
@@ -3,13 +3,10 @@
  * brief Sample code for simple filters
  * author OpenCV team
  */
-#include <iostream>
-#include <vector>
 
-#include "opencv2/imgproc/imgproc.hpp"
+#include "opencv2/imgproc.hpp"
 #include "opencv2/imgcodecs.hpp"
-#include "opencv2/highgui/highgui.hpp"
-#include "opencv2/features2d/features2d.hpp"
+#include "opencv2/highgui.hpp"
 
 using namespace std;
 using namespace cv;
@@ -35,7 +32,7 @@ int main( void )
   namedWindow( window_name, WINDOW_AUTOSIZE );
 
   /// Load the source image
-  src = imread( "../data/lena.jpg", 1 );
+  src = imread( "../data/lena.jpg", IMREAD_COLOR );
 
   if( display_caption( "Original Image" ) != 0 ) { return 0; }
 
@@ -46,33 +43,38 @@ int main( void )
   /// Applying Homogeneous blur
   if( display_caption( "Homogeneous Blur" ) != 0 ) { return 0; }
 
+  //![blur]
   for ( int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2 )
       { blur( src, dst, Size( i, i ), Point(-1,-1) );
         if( display_dst( DELAY_BLUR ) != 0 ) { return 0; } }
-
+  //![blur]
 
   /// Applying Gaussian blur
   if( display_caption( "Gaussian Blur" ) != 0 ) { return 0; }
 
+  //![gaussianblur]
   for ( int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2 )
       { GaussianBlur( src, dst, Size( i, i ), 0, 0 );
         if( display_dst( DELAY_BLUR ) != 0 ) { return 0; } }
-
+  //![gaussianblur]
 
   /// Applying Median blur
   if( display_caption( "Median Blur" ) != 0 ) { return 0; }
 
+  //![medianblur]
   for ( int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2 )
       { medianBlur ( src, dst, i );
         if( display_dst( DELAY_BLUR ) != 0 ) { return 0; } }
-
+  //![medianblur]
 
   /// Applying Bilateral Filter
   if( display_caption( "Bilateral Blur" ) != 0 ) { return 0; }
 
+  //![bilateralfilter]
   for ( int i = 1; i < MAX_KERNEL_LENGTH; i = i + 2 )
       { bilateralFilter ( src, dst, i, i*2, i/2 );
         if( display_dst( DELAY_BLUR ) != 0 ) { return 0; } }
+  //![bilateralfilter]
 
   /// Wait until user press a key
   display_caption( "End: Press a key!" );
diff --git a/samples/cpp/tutorial_code/ImgProc/Threshold.cpp b/samples/cpp/tutorial_code/ImgProc/Threshold.cpp
index 0944f6c..d057ebc 100644
--- a/samples/cpp/tutorial_code/ImgProc/Threshold.cpp
+++ b/samples/cpp/tutorial_code/ImgProc/Threshold.cpp
@@ -4,11 +4,9 @@
  * @author OpenCV team
  */
 
-#include "opencv2/imgproc/imgproc.hpp"
+#include "opencv2/imgproc.hpp"
 #include "opencv2/imgcodecs.hpp"
-#include "opencv2/highgui/highgui.hpp"
-#include <stdlib.h>
-#include <stdio.h>
+#include "opencv2/highgui.hpp"
 
 using namespace cv;
 
@@ -34,39 +32,42 @@ void Threshold_Demo( int, void* );
  */
 int main( int, char** argv )
 {
-  /// Load an image
-  src = imread( argv[1], 1 );
+  //! [load]
+  src = imread( argv[1], IMREAD_COLOR ); // Load an image
 
-  /// Convert the image to Gray
-  cvtColor( src, src_gray, COLOR_RGB2GRAY );
+  if( src.empty() )
+    { return -1; }
 
-  /// Create a window to display results
-  namedWindow( window_name, WINDOW_AUTOSIZE );
+  cvtColor( src, src_gray, COLOR_BGR2GRAY ); // Convert the image to Gray
+  //! [load]
 
-  /// Create Trackbar to choose type of Threshold
+  //! [window]
+  namedWindow( window_name, WINDOW_AUTOSIZE ); // Create a window to display results
+  //! [window]
+
+  //! [trackbar]
   createTrackbar( trackbar_type,
                   window_name, &threshold_type,
-                  max_type, Threshold_Demo );
+                  max_type, Threshold_Demo ); // Create Trackbar to choose type of Threshold
 
   createTrackbar( trackbar_value,
                   window_name, &threshold_value,
-                  max_value, Threshold_Demo );
+                  max_value, Threshold_Demo ); // Create Trackbar to choose Threshold value
+  //! [trackbar]
 
-  /// Call the function to initialize
-  Threshold_Demo( 0, 0 );
+  Threshold_Demo( 0, 0 ); // Call the function to initialize
 
   /// Wait until user finishes program
   for(;;)
     {
-      int c;
-      c = waitKey( 20 );
-      if( (char)c == 27 )
+      char c = (char)waitKey( 20 );
+      if( c == 27 )
     { break; }
     }
 
 }
 
-
+//![Threshold_Demo]
 /**
  * @function Threshold_Demo
  */
@@ -83,3 +84,4 @@ void Threshold_Demo( int, void* )
 
   imshow( window_name, dst );
 }
+//![Threshold_Demo]
diff --git a/samples/cpp/tutorial_code/ImgProc/Threshold_inRange.cpp b/samples/cpp/tutorial_code/ImgProc/Threshold_inRange.cpp
new file mode 100644
index 0000000..8935a04
--- /dev/null
+++ b/samples/cpp/tutorial_code/ImgProc/Threshold_inRange.cpp
@@ -0,0 +1,102 @@
+#include "opencv2/imgproc.hpp"
+#include "opencv2/highgui.hpp"
+
+#include <iostream>
+#include <stdlib.h>
+
+using namespace std;
+using namespace cv;
+
+/** Function Headers */
+void on_low_r_thresh_trackbar(int, void *);
+void on_high_r_thresh_trackbar(int, void *);
+void on_low_g_thresh_trackbar(int, void *);
+void on_high_g_thresh_trackbar(int, void *);
+void on_low_b_thresh_trackbar(int, void *);
+void on_high_b_thresh_trackbar(int, void *);
+
+/** Global Variables */
+int low_r=30, low_g=30, low_b=30;
+int high_r=100, high_g=100, high_b=100;
+
+/** @function main */
+int main()
+{
+    //! [mat]
+    Mat frame, frame_threshold;
+    //! [mat]
+    //! [cap]
+    VideoCapture cap(0);
+    //! [cap]
+    //! [window]
+    namedWindow("Video Capture", WINDOW_NORMAL);
+    namedWindow("Object Detection", WINDOW_NORMAL);
+    //! [window]
+    //! [trackbar]
+    //-- Trackbars to set thresholds for RGB values
+    createTrackbar("Low R","Object Detection", &low_r, 255, on_low_r_thresh_trackbar);
+    createTrackbar("High R","Object Detection", &high_r, 255, on_high_r_thresh_trackbar);
+    createTrackbar("Low G","Object Detection", &low_g, 255, on_low_g_thresh_trackbar);
+    createTrackbar("High G","Object Detection", &high_g, 255, on_high_g_thresh_trackbar);
+    createTrackbar("Low B","Object Detection", &low_b, 255, on_low_b_thresh_trackbar);
+    createTrackbar("High B","Object Detection", &high_b, 255, on_high_b_thresh_trackbar);
+    //! [trackbar]
+    while((char)waitKey(1)!='q'){
+        //! [while]
+        cap>>frame;
+        if(frame.empty())
+            break;
+        //-- Detect the object based on RGB Range Values
+        inRange(frame,Scalar(low_b,low_g,low_r), Scalar(high_b,high_g,high_r),frame_threshold);
+        //! [while]
+        //! [show]
+        //-- Show the frames
+        imshow("Video Capture",frame);
+        imshow("Object Detection",frame_threshold);
+        //! [show]
+    }
+    return 0;
+}
+//! [low]
+/** @function on_low_r_thresh_trackbar */
+void on_low_r_thresh_trackbar(int, void *)
+{
+    low_r = min(high_r-1, low_r);
+    setTrackbarPos("Low R","Object Detection", low_r);
+}
+//! [low]
+//! [high]
+/** @function on_high_r_thresh_trackbar */
+void on_high_r_thresh_trackbar(int, void *)
+{
+    high_r = max(high_r, low_r+1);
+    setTrackbarPos("High R", "Object Detection", high_r);
+}
+//![high]
+/** @function on_low_g_thresh_trackbar */
+void on_low_g_thresh_trackbar(int, void *)
+{
+    low_g = min(high_g-1, low_g);
+    setTrackbarPos("Low G","Object Detection", low_g);
+}
+
+/** @function on_high_g_thresh_trackbar */
+void on_high_g_thresh_trackbar(int, void *)
+{
+    high_g = max(high_g, low_g+1);
+    setTrackbarPos("High G", "Object Detection", high_g);
+}
+
+/** @function on_low_b_thresh_trackbar */
+void on_low_b_thresh_trackbar(int, void *)
+{
+    low_b= min(high_b-1, low_b);
+    setTrackbarPos("Low B","Object Detection", low_b);
+}
+
+/** @function on_high_b_thresh_trackbar */
+void on_high_b_thresh_trackbar(int, void *)
+{
+    high_b = max(high_b, low_b+1);
+    setTrackbarPos("High B", "Object Detection", high_b);
+}
diff --git a/samples/cpp/tutorial_code/ImgTrans/CannyDetector_Demo.cpp b/samples/cpp/tutorial_code/ImgTrans/CannyDetector_Demo.cpp
index 92e10e4..efdeca1 100644
--- a/samples/cpp/tutorial_code/ImgTrans/CannyDetector_Demo.cpp
+++ b/samples/cpp/tutorial_code/ImgTrans/CannyDetector_Demo.cpp
@@ -4,16 +4,13 @@
  * @author OpenCV team
  */
 
-#include "opencv2/imgproc/imgproc.hpp"
+#include "opencv2/imgproc.hpp"
 #include "opencv2/imgcodecs.hpp"
-#include "opencv2/highgui/highgui.hpp"
-#include <stdlib.h>
-#include <stdio.h>
+#include "opencv2/highgui.hpp"
 
 using namespace cv;
 
-/// Global variables
-
+//![variables]
 Mat src, src_gray;
 Mat dst, detected_edges;
 
@@ -23,6 +20,7 @@ int const max_lowThreshold = 100;
 int ratio = 3;
 int kernel_size = 3;
 const char* window_name = "Edge Map";
+//![variables]
 
 /**
  * @function CannyThreshold
@@ -30,17 +28,28 @@ const char* window_name = "Edge Map";
  */
 static void CannyThreshold(int, void*)
 {
+    //![reduce_noise]
     /// Reduce noise with a kernel 3x3
     blur( src_gray, detected_edges, Size(3,3) );
+    //![reduce_noise]
 
+    //![canny]
     /// Canny detector
     Canny( detected_edges, detected_edges, lowThreshold, lowThreshold*ratio, kernel_size );
+    //![canny]
 
     /// Using Canny's output as a mask, we display our result
+    //![fill]
     dst = Scalar::all(0);
+    //![fill]
 
+    //![copyto]
     src.copyTo( dst, detected_edges);
+    //![copyto]
+
+    //![display]
     imshow( window_name, dst );
+    //![display]
 }
 
 
@@ -49,23 +58,30 @@ static void CannyThreshold(int, void*)
  */
 int main( int, char** argv )
 {
-  /// Load an image
-  src = imread( argv[1] );
+  //![load]
+  src = imread( argv[1], IMREAD_COLOR ); // Load an image
 
   if( src.empty() )
     { return -1; }
+  //![load]
 
+  //![create_mat]
   /// Create a matrix of the same type and size as src (for dst)
   dst.create( src.size(), src.type() );
+  //![create_mat]
 
-  /// Convert the image to grayscale
+  //![convert_to_gray]
   cvtColor( src, src_gray, COLOR_BGR2GRAY );
+  //![convert_to_gray]
 
-  /// Create a window
+  //![create_window]
   namedWindow( window_name, WINDOW_AUTOSIZE );
+  //![create_window]
 
+  //![create_trackbar]
   /// Create a Trackbar for user to enter threshold
   createTrackbar( "Min Threshold:", window_name, &lowThreshold, max_lowThreshold, CannyThreshold );
+  //![create_trackbar]
 
   /// Show the image
   CannyThreshold(0, 0);
diff --git a/samples/cpp/tutorial_code/ImgTrans/Geometric_Transforms_Demo.cpp b/samples/cpp/tutorial_code/ImgTrans/Geometric_Transforms_Demo.cpp
index 00184a3..edbb1e7 100644
--- a/samples/cpp/tutorial_code/ImgTrans/Geometric_Transforms_Demo.cpp
+++ b/samples/cpp/tutorial_code/ImgTrans/Geometric_Transforms_Demo.cpp
@@ -5,10 +5,9 @@
  */
 
 #include "opencv2/imgcodecs.hpp"
-#include "opencv2/highgui/highgui.hpp"
-#include "opencv2/imgproc/imgproc.hpp"
+#include "opencv2/highgui.hpp"
+#include "opencv2/imgproc.hpp"
 #include <iostream>
-#include <stdio.h>
 
 using namespace cv;
 using namespace std;
@@ -31,7 +30,7 @@ int main( int, char** argv )
   Mat src, warp_dst, warp_rotate_dst;
 
   /// Load the image
-  src = imread( argv[1], 1 );
+  src = imread( argv[1], IMREAD_COLOR );
 
   /// Set the dst image the same type and size as src
   warp_dst = Mat::zeros( src.rows, src.cols, src.type() );
diff --git a/samples/cpp/tutorial_code/ImgTrans/HoughCircle_Demo.cpp b/samples/cpp/tutorial_code/ImgTrans/HoughCircle_Demo.cpp
index 02f0381..2911b9d 100644
--- a/samples/cpp/tutorial_code/ImgTrans/HoughCircle_Demo.cpp
+++ b/samples/cpp/tutorial_code/ImgTrans/HoughCircle_Demo.cpp
@@ -5,8 +5,8 @@
  */
 
 #include "opencv2/imgcodecs.hpp"
-#include "opencv2/highgui/highgui.hpp"
-#include "opencv2/imgproc/imgproc.hpp"
+#include "opencv2/highgui.hpp"
+#include "opencv2/imgproc.hpp"
 #include <iostream>
 
 using namespace std;
@@ -63,7 +63,7 @@ int main(int argc, char** argv)
     }
 
     // Read the image
-    src = imread( argv[1], 1 );
+    src = imread( argv[1], IMREAD_COLOR );
 
     if( src.empty() )
     {
@@ -90,7 +90,7 @@ int main(int argc, char** argv)
     // infinite loop to display
     // and refresh the content of the output image
     // until the user presses q or Q
-    int key = 0;
+    char key = 0;
     while(key != 'q' && key != 'Q')
     {
         // those paramaters cannot be =0
@@ -102,7 +102,7 @@ int main(int argc, char** argv)
         HoughDetection(src_gray, src, cannyThreshold, accumulatorThreshold);
 
         // get user key
-        key = waitKey(10);
+        key = (char)waitKey(10);
     }
 
     return 0;
diff --git a/samples/cpp/tutorial_code/ImgTrans/HoughLines_Demo.cpp b/samples/cpp/tutorial_code/ImgTrans/HoughLines_Demo.cpp
index 2d9b7b6..5610cfe 100644
--- a/samples/cpp/tutorial_code/ImgTrans/HoughLines_Demo.cpp
+++ b/samples/cpp/tutorial_code/ImgTrans/HoughLines_Demo.cpp
@@ -5,10 +5,9 @@
  */
 
 #include "opencv2/imgcodecs.hpp"
-#include "opencv2/highgui/highgui.hpp"
-#include "opencv2/imgproc/imgproc.hpp"
+#include "opencv2/highgui.hpp"
+#include "opencv2/imgproc.hpp"
 #include <iostream>
-#include <stdio.h>
 
 using namespace cv;
 using namespace std;
@@ -39,7 +38,7 @@ void Probabilistic_Hough( int, void* );
 int main( int, char** argv )
 {
    /// Read the image
-   src = imread( argv[1], 1 );
+   src = imread( argv[1], IMREAD_COLOR );
 
    if( src.empty() )
      { help();
diff --git a/samples/cpp/tutorial_code/ImgTrans/Laplace_Demo.cpp b/samples/cpp/tutorial_code/ImgTrans/Laplace_Demo.cpp
index f0d45e7..6a41c3a 100644
--- a/samples/cpp/tutorial_code/ImgTrans/Laplace_Demo.cpp
+++ b/samples/cpp/tutorial_code/ImgTrans/Laplace_Demo.cpp
@@ -4,11 +4,9 @@
  * @author OpenCV team
  */
 
-#include "opencv2/imgproc/imgproc.hpp"
+#include "opencv2/imgproc.hpp"
 #include "opencv2/imgcodecs.hpp"
-#include "opencv2/highgui/highgui.hpp"
-#include <stdlib.h>
-#include <stdio.h>
+#include "opencv2/highgui.hpp"
 
 using namespace cv;
 
@@ -17,39 +15,45 @@ using namespace cv;
  */
 int main( int, char** argv )
 {
-
+  //![variables]
   Mat src, src_gray, dst;
   int kernel_size = 3;
   int scale = 1;
   int delta = 0;
   int ddepth = CV_16S;
   const char* window_name = "Laplace Demo";
+  //![variables]
 
-  /// Load an image
-  src = imread( argv[1] );
+  //![load]
+  src = imread( argv[1], IMREAD_COLOR ); // Load an image
 
   if( src.empty() )
     { return -1; }
+  //![load]
 
-  /// Remove noise by blurring with a Gaussian filter
+  //![reduce_noise]
+  /// Reduce noise by blurring with a Gaussian filter
   GaussianBlur( src, src, Size(3,3), 0, 0, BORDER_DEFAULT );
+  //![reduce_noise]
 
-  /// Convert the image to grayscale
-  cvtColor( src, src_gray, COLOR_RGB2GRAY );
-
-  /// Create window
-  namedWindow( window_name, WINDOW_AUTOSIZE );
+  //![convert_to_gray]
+  cvtColor( src, src_gray, COLOR_BGR2GRAY ); // Convert the image to grayscale
+  //![convert_to_gray]
 
   /// Apply Laplace function
   Mat abs_dst;
-
+  //![laplacian]
   Laplacian( src_gray, dst, ddepth, kernel_size, scale, delta, BORDER_DEFAULT );
+  //![laplacian]
+
+  //![convert]
   convertScaleAbs( dst, abs_dst );
+  //![convert]
 
-  /// Show what you got
+  //![display]
   imshow( window_name, abs_dst );
-
   waitKey(0);
+  //![display]
 
   return 0;
 }
diff --git a/samples/cpp/tutorial_code/ImgTrans/Remap_Demo.cpp b/samples/cpp/tutorial_code/ImgTrans/Remap_Demo.cpp
index 49727e9..afe7024 100644
--- a/samples/cpp/tutorial_code/ImgTrans/Remap_Demo.cpp
+++ b/samples/cpp/tutorial_code/ImgTrans/Remap_Demo.cpp
@@ -5,10 +5,9 @@
  */
 
 #include "opencv2/imgcodecs.hpp"
-#include "opencv2/highgui/highgui.hpp"
-#include "opencv2/imgproc/imgproc.hpp"
+#include "opencv2/highgui.hpp"
+#include "opencv2/imgproc.hpp"
 #include <iostream>
-#include <stdio.h>
 
 using namespace cv;
 
@@ -27,7 +26,7 @@ void update_map( void );
 int main( int, char** argv )
 {
   /// Load the image
-  src = imread( argv[1], 1 );
+  src = imread( argv[1], IMREAD_COLOR );
 
   /// Create dst, map_x and map_y with the same size as src:
   dst.create( src.size(), src.type() );
@@ -41,9 +40,9 @@ int main( int, char** argv )
   for(;;)
   {
     /// Each 1 sec. Press ESC to exit the program
-    int c = waitKey( 1000 );
+    char c = (char)waitKey( 1000 );
 
-    if( (char)c == 27 )
+    if( c == 27 )
       { break; }
 
     /// Update map_x & map_y. Then apply remap
diff --git a/samples/cpp/tutorial_code/ImgTrans/Sobel_Demo.cpp b/samples/cpp/tutorial_code/ImgTrans/Sobel_Demo.cpp
index 7d57e8e..ad45452 100644
--- a/samples/cpp/tutorial_code/ImgTrans/Sobel_Demo.cpp
+++ b/samples/cpp/tutorial_code/ImgTrans/Sobel_Demo.cpp
@@ -1,14 +1,12 @@
 /**
  * @file Sobel_Demo.cpp
- * @brief Sample code using Sobel and/orScharr OpenCV functions to make a simple Edge Detector
+ * @brief Sample code using Sobel and/or Scharr OpenCV functions to make a simple Edge Detector
  * @author OpenCV team
  */
 
-#include "opencv2/imgproc/imgproc.hpp"
+#include "opencv2/imgproc.hpp"
 #include "opencv2/imgcodecs.hpp"
-#include "opencv2/highgui/highgui.hpp"
-#include <stdlib.h>
-#include <stdio.h>
+#include "opencv2/highgui.hpp"
 
 using namespace cv;
 
@@ -17,28 +15,31 @@ using namespace cv;
  */
 int main( int, char** argv )
 {
-
+  //![variables]
   Mat src, src_gray;
   Mat grad;
   const char* window_name = "Sobel Demo - Simple Edge Detector";
   int scale = 1;
   int delta = 0;
   int ddepth = CV_16S;
+  //![variables]
 
-  /// Load an image
-  src = imread( argv[1] );
+  //![load]
+  src = imread( argv[1], IMREAD_COLOR ); // Load an image
 
   if( src.empty() )
     { return -1; }
+  //![load]
 
+  //![reduce_noise]
   GaussianBlur( src, src, Size(3,3), 0, 0, BORDER_DEFAULT );
+  //![reduce_noise]
 
-  /// Convert it to gray
-  cvtColor( src, src_gray, COLOR_RGB2GRAY );
-
-  /// Create window
-  namedWindow( window_name, WINDOW_AUTOSIZE );
+  //![convert_to_gray]
+  cvtColor( src, src_gray, COLOR_BGR2GRAY );
+  //![convert_to_gray]
 
+  //![sobel]
   /// Generate grad_x and grad_y
   Mat grad_x, grad_y;
   Mat abs_grad_x, abs_grad_y;
@@ -46,19 +47,26 @@ int main( int, char** argv )
   /// Gradient X
   //Scharr( src_gray, grad_x, ddepth, 1, 0, scale, delta, BORDER_DEFAULT );
   Sobel( src_gray, grad_x, ddepth, 1, 0, 3, scale, delta, BORDER_DEFAULT );
-  convertScaleAbs( grad_x, abs_grad_x );
 
   /// Gradient Y
   //Scharr( src_gray, grad_y, ddepth, 0, 1, scale, delta, BORDER_DEFAULT );
   Sobel( src_gray, grad_y, ddepth, 0, 1, 3, scale, delta, BORDER_DEFAULT );
+  //![sobel]
+
+  //![convert]
+  convertScaleAbs( grad_x, abs_grad_x );
   convertScaleAbs( grad_y, abs_grad_y );
+  //![convert]
 
+  //![blend]
   /// Total Gradient (approximate)
   addWeighted( abs_grad_x, 0.5, abs_grad_y, 0.5, 0, grad );
+  //![blend]
 
+  //![display]
   imshow( window_name, grad );
-
   waitKey(0);
+  //![display]
 
   return 0;
 }
diff --git a/samples/cpp/tutorial_code/ImgTrans/copyMakeBorder_demo.cpp b/samples/cpp/tutorial_code/ImgTrans/copyMakeBorder_demo.cpp
index 5f786d5..3b9ad0d 100644
--- a/samples/cpp/tutorial_code/ImgTrans/copyMakeBorder_demo.cpp
+++ b/samples/cpp/tutorial_code/ImgTrans/copyMakeBorder_demo.cpp
@@ -4,37 +4,34 @@
  * @author OpenCV team
  */
 
-#include "opencv2/imgproc/imgproc.hpp"
+#include "opencv2/imgproc.hpp"
 #include "opencv2/imgcodecs.hpp"
-#include "opencv2/highgui/highgui.hpp"
-#include <stdlib.h>
-#include <stdio.h>
+#include "opencv2/highgui.hpp"
 
 using namespace cv;
 
-/// Global Variables
+//![variables]
 Mat src, dst;
 int top, bottom, left, right;
 int borderType;
 const char* window_name = "copyMakeBorder Demo";
 RNG rng(12345);
+//![variables]
 
 /**
  * @function main
  */
 int main( int, char** argv )
 {
-
-  int c;
-
-  /// Load an image
-  src = imread( argv[1] );
+  //![load]
+  src = imread( argv[1], IMREAD_COLOR ); // Load an image
 
   if( src.empty() )
     {
       printf(" No data entered, please enter the path to an image file \n");
       return -1;
     }
+  //![load]
 
   /// Brief how-to for this program
   printf( "\n \t copyMakeBorder Demo: \n" );
@@ -43,31 +40,42 @@ int main( int, char** argv )
   printf( " ** Press 'r' to set the border to be replicated \n");
   printf( " ** Press 'ESC' to exit the program \n");
 
-  /// Create window
+  //![create_window]
   namedWindow( window_name, WINDOW_AUTOSIZE );
+  //![create_window]
 
+  //![init_arguments]
   /// Initialize arguments for the filter
   top = (int) (0.05*src.rows); bottom = (int) (0.05*src.rows);
   left = (int) (0.05*src.cols); right = (int) (0.05*src.cols);
-  dst = src;
+  //![init_arguments]
 
+  dst = src;
   imshow( window_name, dst );
 
   for(;;)
        {
-         c = waitKey(500);
-
-         if( (char)c == 27 )
+         //![check_keypress]
+         char c = (char)waitKey(500);
+         if( c == 27 )
            { break; }
-         else if( (char)c == 'c' )
+         else if( c == 'c' )
            { borderType = BORDER_CONSTANT; }
-         else if( (char)c == 'r' )
+         else if( c == 'r' )
            { borderType = BORDER_REPLICATE; }
+         //![check_keypress]
 
+         //![update_value]
          Scalar value( rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255) );
+         //![update_value]
+
+         //![copymakeborder]
          copyMakeBorder( src, dst, top, bottom, left, right, borderType, value );
+         //![copymakeborder]
 
+         //![display]
          imshow( window_name, dst );
+         //![display]
        }
 
   return 0;
diff --git a/samples/cpp/tutorial_code/ImgTrans/filter2D_demo.cpp b/samples/cpp/tutorial_code/ImgTrans/filter2D_demo.cpp
index 3c580bb..81a6fc0 100644
--- a/samples/cpp/tutorial_code/ImgTrans/filter2D_demo.cpp
+++ b/samples/cpp/tutorial_code/ImgTrans/filter2D_demo.cpp
@@ -4,11 +4,9 @@
  * @author OpenCV team
  */
 
-#include "opencv2/imgproc/imgproc.hpp"
+#include "opencv2/imgproc.hpp"
 #include "opencv2/imgcodecs.hpp"
-#include "opencv2/highgui/highgui.hpp"
-#include <stdlib.h>
-#include <stdio.h>
+#include "opencv2/highgui.hpp"
 
 using namespace cv;
 
@@ -27,37 +25,38 @@ int main ( int, char** argv )
   int kernel_size;
   const char* window_name = "filter2D Demo";
 
-  int c;
-
-  /// Load an image
-  src = imread( argv[1] );
+  //![load]
+  src = imread( argv[1], IMREAD_COLOR ); // Load an image
 
   if( src.empty() )
     { return -1; }
+  //![load]
 
-  /// Create window
-  namedWindow( window_name, WINDOW_AUTOSIZE );
-
+  //![init_arguments]
   /// Initialize arguments for the filter
   anchor = Point( -1, -1 );
   delta = 0;
   ddepth = -1;
+  //![init_arguments]
 
   /// Loop - Will filter the image with different kernel sizes each 0.5 seconds
   int ind = 0;
   for(;;)
        {
-         c = waitKey(500);
+         char c = (char)waitKey(500);
          /// Press 'ESC' to exit the program
-         if( (char)c == 27 )
+         if( c == 27 )
            { break; }
 
+         //![update_kernel]
          /// Update kernel size for a normalized box filter
          kernel_size = 3 + 2*( ind%5 );
          kernel = Mat::ones( kernel_size, kernel_size, CV_32F )/ (float)(kernel_size*kernel_size);
+         //![update_kernel]
 
-         /// Apply filter
+         //![apply_filter]
          filter2D(src, dst, ddepth , kernel, anchor, delta, BORDER_DEFAULT );
+         //![apply_filter]
          imshow( window_name, dst );
          ind++;
        }
diff --git a/samples/cpp/tutorial_code/ShapeDescriptors/findContours_demo.cpp b/samples/cpp/tutorial_code/ShapeDescriptors/findContours_demo.cpp
index 6a6de95..b831441 100644
--- a/samples/cpp/tutorial_code/ShapeDescriptors/findContours_demo.cpp
+++ b/samples/cpp/tutorial_code/ShapeDescriptors/findContours_demo.cpp
@@ -5,11 +5,9 @@
  */
 
 #include "opencv2/imgcodecs.hpp"
-#include "opencv2/highgui/highgui.hpp"
-#include "opencv2/imgproc/imgproc.hpp"
+#include "opencv2/highgui.hpp"
+#include "opencv2/imgproc.hpp"
 #include <iostream>
-#include <stdio.h>
-#include <stdlib.h>
 
 using namespace cv;
 using namespace std;
@@ -28,7 +26,7 @@ void thresh_callback(int, void* );
 int main( int, char** argv )
 {
   /// Load source image
-  src = imread(argv[1]);
+  src = imread(argv[1], IMREAD_COLOR);
   if (src.empty())
   {
     cerr << "No image supplied ..." << endl;
diff --git a/samples/cpp/tutorial_code/ShapeDescriptors/generalContours_demo1.cpp b/samples/cpp/tutorial_code/ShapeDescriptors/generalContours_demo1.cpp
index a9c22e6..1e5585a 100644
--- a/samples/cpp/tutorial_code/ShapeDescriptors/generalContours_demo1.cpp
+++ b/samples/cpp/tutorial_code/ShapeDescriptors/generalContours_demo1.cpp
@@ -5,11 +5,9 @@
  */
 
 #include "opencv2/imgcodecs.hpp"
-#include "opencv2/highgui/highgui.hpp"
-#include "opencv2/imgproc/imgproc.hpp"
+#include "opencv2/highgui.hpp"
+#include "opencv2/imgproc.hpp"
 #include <iostream>
-#include <stdio.h>
-#include <stdlib.h>
 
 using namespace cv;
 using namespace std;
@@ -27,22 +25,34 @@ void thresh_callback(int, void* );
  */
 int main( int, char** argv )
 {
-  /// Load source image and convert it to gray
-  src = imread( argv[1], 1 );
+  //![setup]
+  /// Load source image
+  src = imread( argv[1], IMREAD_COLOR );
 
   /// Convert image to gray and blur it
   cvtColor( src, src_gray, COLOR_BGR2GRAY );
   blur( src_gray, src_gray, Size(3,3) );
+  //![setup]
 
+  //![createWindow]
   /// Create Window
   const char* source_window = "Source";
   namedWindow( source_window, WINDOW_AUTOSIZE );
   imshow( source_window, src );
+  //![createWindow]
 
+  //![taskbar]
   createTrackbar( " Threshold:", "Source", &thresh, max_thresh, thresh_callback );
+  //![taskbar]
+
+  //![callback00]
   thresh_callback( 0, 0 );
+  //![callback00]
 
+  //![waitForIt]
   waitKey(0);
+  //![waitForIt]
+
   return(0);
 }
 
@@ -55,10 +65,15 @@ void thresh_callback(int, void* )
   vector<vector<Point> > contours;
   vector<Vec4i> hierarchy;
 
+  //![threshold]
   /// Detect edges using Threshold
   threshold( src_gray, threshold_output, thresh, 255, THRESH_BINARY );
+  //![threshold]
+
+  //![findContours]
   /// Find contours
   findContours( threshold_output, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0) );
+  //![findContours]
 
   /// Approximate contours to polygons + get bounding rects and circles
   vector<vector<Point> > contours_poly( contours.size() );
@@ -66,24 +81,33 @@ void thresh_callback(int, void* )
   vector<Point2f>center( contours.size() );
   vector<float>radius( contours.size() );
 
+  //![allthework]
   for( size_t i = 0; i < contours.size(); i++ )
-     { approxPolyDP( Mat(contours[i]), contours_poly[i], 3, true );
-       boundRect[i] = boundingRect( Mat(contours_poly[i]) );
-       minEnclosingCircle( contours_poly[i], center[i], radius[i] );
-     }
-
-
+  {
+    approxPolyDP( Mat(contours[i]), contours_poly[i], 3, true );
+    boundRect[i] = boundingRect( Mat(contours_poly[i]) );
+    minEnclosingCircle( contours_poly[i], center[i], radius[i] );
+  }
+  //![allthework]
+
+  //![zeroMat]
   /// Draw polygonal contour + bonding rects + circles
   Mat drawing = Mat::zeros( threshold_output.size(), CV_8UC3 );
-  for( size_t i = 0; i< contours.size(); i++ )
-     {
-       Scalar color = Scalar( rng.uniform(0, 255), rng.uniform(0,255), rng.uniform(0,255) );
-       drawContours( drawing, contours_poly, (int)i, color, 1, 8, vector<Vec4i>(), 0, Point() );
-       rectangle( drawing, boundRect[i].tl(), boundRect[i].br(), color, 2, 8, 0 );
-       circle( drawing, center[i], (int)radius[i], color, 2, 8, 0 );
-     }
+  //![zeroMat]
 
+  //![forContour]
+  for( size_t i = 0; i< contours.size(); i++ )
+  {
+    Scalar color = Scalar( rng.uniform(0, 255), rng.uniform(0,255), rng.uniform(0,255) );
+    drawContours( drawing, contours_poly, (int)i, color, 1, 8, vector<Vec4i>(), 0, Point() );
+    rectangle( drawing, boundRect[i].tl(), boundRect[i].br(), color, 2, 8, 0 );
+    circle( drawing, center[i], (int)radius[i], color, 2, 8, 0 );
+  }
+  //![forContour]
+
+  //![showDrawings]
   /// Show in a window
   namedWindow( "Contours", WINDOW_AUTOSIZE );
   imshow( "Contours", drawing );
+  //![showDrawings]
 }
diff --git a/samples/cpp/tutorial_code/ShapeDescriptors/generalContours_demo2.cpp b/samples/cpp/tutorial_code/ShapeDescriptors/generalContours_demo2.cpp
index c6fd379..742c6cf 100644
--- a/samples/cpp/tutorial_code/ShapeDescriptors/generalContours_demo2.cpp
+++ b/samples/cpp/tutorial_code/ShapeDescriptors/generalContours_demo2.cpp
@@ -5,11 +5,9 @@
  */
 
 #include "opencv2/imgcodecs.hpp"
-#include "opencv2/highgui/highgui.hpp"
-#include "opencv2/imgproc/imgproc.hpp"
+#include "opencv2/highgui.hpp"
+#include "opencv2/imgproc.hpp"
 #include <iostream>
-#include <stdio.h>
-#include <stdlib.h>
 
 using namespace cv;
 using namespace std;
@@ -28,7 +26,7 @@ void thresh_callback(int, void* );
 int main( int, char** argv )
 {
   /// Load source image and convert it to gray
-  src = imread( argv[1], 1 );
+  src = imread( argv[1], IMREAD_COLOR );
 
   /// Convert image to gray and blur it
   cvtColor( src, src_gray, COLOR_BGR2GRAY );
diff --git a/samples/cpp/tutorial_code/ShapeDescriptors/hull_demo.cpp b/samples/cpp/tutorial_code/ShapeDescriptors/hull_demo.cpp
index 0b35429..e583791 100644
--- a/samples/cpp/tutorial_code/ShapeDescriptors/hull_demo.cpp
+++ b/samples/cpp/tutorial_code/ShapeDescriptors/hull_demo.cpp
@@ -5,11 +5,9 @@
  */
 
 #include "opencv2/imgcodecs.hpp"
-#include "opencv2/highgui/highgui.hpp"
-#include "opencv2/imgproc/imgproc.hpp"
+#include "opencv2/highgui.hpp"
+#include "opencv2/imgproc.hpp"
 #include <iostream>
-#include <stdio.h>
-#include <stdlib.h>
 
 using namespace cv;
 using namespace std;
@@ -28,7 +26,7 @@ void thresh_callback(int, void* );
 int main( int, char** argv )
 {
   /// Load source image and convert it to gray
-  src = imread( argv[1], 1 );
+  src = imread( argv[1], IMREAD_COLOR );
 
   /// Convert image to gray and blur it
   cvtColor( src, src_gray, COLOR_BGR2GRAY );
@@ -51,7 +49,6 @@ int main( int, char** argv )
  */
 void thresh_callback(int, void* )
 {
-  Mat src_copy = src.clone();
   Mat threshold_output;
   vector<vector<Point> > contours;
   vector<Vec4i> hierarchy;
diff --git a/samples/cpp/tutorial_code/ShapeDescriptors/moments_demo.cpp b/samples/cpp/tutorial_code/ShapeDescriptors/moments_demo.cpp
index c3a5cbf..4064048 100644
--- a/samples/cpp/tutorial_code/ShapeDescriptors/moments_demo.cpp
+++ b/samples/cpp/tutorial_code/ShapeDescriptors/moments_demo.cpp
@@ -5,11 +5,9 @@
  */
 
 #include "opencv2/imgcodecs.hpp"
-#include "opencv2/highgui/highgui.hpp"
-#include "opencv2/imgproc/imgproc.hpp"
+#include "opencv2/highgui.hpp"
+#include "opencv2/imgproc.hpp"
 #include <iostream>
-#include <stdio.h>
-#include <stdlib.h>
 
 using namespace cv;
 using namespace std;
@@ -28,7 +26,7 @@ void thresh_callback(int, void* );
 int main( int, char** argv )
 {
   /// Load source image and convert it to gray
-  src = imread( argv[1], 1 );
+  src = imread( argv[1], IMREAD_COLOR );
 
   /// Convert image to gray and blur it
   cvtColor( src, src_gray, COLOR_BGR2GRAY );
diff --git a/samples/cpp/tutorial_code/ShapeDescriptors/pointPolygonTest_demo.cpp b/samples/cpp/tutorial_code/ShapeDescriptors/pointPolygonTest_demo.cpp
index f55f8f6..757b8dc 100644
--- a/samples/cpp/tutorial_code/ShapeDescriptors/pointPolygonTest_demo.cpp
+++ b/samples/cpp/tutorial_code/ShapeDescriptors/pointPolygonTest_demo.cpp
@@ -4,11 +4,9 @@
  * @author OpenCV team
  */
 
-#include "opencv2/highgui/highgui.hpp"
-#include "opencv2/imgproc/imgproc.hpp"
+#include "opencv2/highgui.hpp"
+#include "opencv2/imgproc.hpp"
 #include <iostream>
-#include <stdio.h>
-#include <stdlib.h>
 
 using namespace cv;
 using namespace std;
diff --git a/samples/cpp/tutorial_code/TrackingMotion/cornerDetector_Demo.cpp b/samples/cpp/tutorial_code/TrackingMotion/cornerDetector_Demo.cpp
index c5dceab..52d7561 100644
--- a/samples/cpp/tutorial_code/TrackingMotion/cornerDetector_Demo.cpp
+++ b/samples/cpp/tutorial_code/TrackingMotion/cornerDetector_Demo.cpp
@@ -3,12 +3,11 @@
  * @brief Demo code for detecting corners using OpenCV built-in functions
  * @author OpenCV team
  */
+
 #include "opencv2/imgcodecs.hpp"
-#include "opencv2/highgui/highgui.hpp"
-#include "opencv2/imgproc/imgproc.hpp"
+#include "opencv2/highgui.hpp"
+#include "opencv2/imgproc.hpp"
 #include <iostream>
-#include <stdio.h>
-#include <stdlib.h>
 
 using namespace cv;
 using namespace std;
@@ -40,7 +39,7 @@ void myHarris_function( int, void* );
 int main( int, char** argv )
 {
   /// Load source image and convert it to gray
-  src = imread( argv[1], 1 );
+  src = imread( argv[1], IMREAD_COLOR );
   cvtColor( src, src_gray, COLOR_BGR2GRAY );
 
   /// Set some parameters
diff --git a/samples/cpp/tutorial_code/TrackingMotion/cornerHarris_Demo.cpp b/samples/cpp/tutorial_code/TrackingMotion/cornerHarris_Demo.cpp
index 4314a97..4f1df4b 100644
--- a/samples/cpp/tutorial_code/TrackingMotion/cornerHarris_Demo.cpp
+++ b/samples/cpp/tutorial_code/TrackingMotion/cornerHarris_Demo.cpp
@@ -5,11 +5,9 @@
  */
 
 #include "opencv2/imgcodecs.hpp"
-#include "opencv2/highgui/highgui.hpp"
-#include "opencv2/imgproc/imgproc.hpp"
+#include "opencv2/highgui.hpp"
+#include "opencv2/imgproc.hpp"
 #include <iostream>
-#include <stdio.h>
-#include <stdlib.h>
 
 using namespace cv;
 using namespace std;
@@ -31,7 +29,7 @@ void cornerHarris_demo( int, void* );
 int main( int, char** argv )
 {
   /// Load source image and convert it to gray
-  src = imread( argv[1], 1 );
+  src = imread( argv[1], IMREAD_COLOR );
   cvtColor( src, src_gray, COLOR_BGR2GRAY );
 
   /// Create a window and a trackbar
diff --git a/samples/cpp/tutorial_code/TrackingMotion/cornerSubPix_Demo.cpp b/samples/cpp/tutorial_code/TrackingMotion/cornerSubPix_Demo.cpp
index 775e566..8e4876b 100644
--- a/samples/cpp/tutorial_code/TrackingMotion/cornerSubPix_Demo.cpp
+++ b/samples/cpp/tutorial_code/TrackingMotion/cornerSubPix_Demo.cpp
@@ -5,11 +5,9 @@
  */
 
 #include "opencv2/imgcodecs.hpp"
-#include "opencv2/highgui/highgui.hpp"
-#include "opencv2/imgproc/imgproc.hpp"
+#include "opencv2/highgui.hpp"
+#include "opencv2/imgproc.hpp"
 #include <iostream>
-#include <stdio.h>
-#include <stdlib.h>
 
 using namespace cv;
 using namespace std;
@@ -32,7 +30,7 @@ void goodFeaturesToTrack_Demo( int, void* );
 int main( int, char** argv )
 {
   /// Load source image and convert it to gray
-  src = imread( argv[1], 1 );
+  src = imread( argv[1], IMREAD_COLOR );
   cvtColor( src, src_gray, COLOR_BGR2GRAY );
 
   /// Create Window
diff --git a/samples/cpp/tutorial_code/TrackingMotion/goodFeaturesToTrack_Demo.cpp b/samples/cpp/tutorial_code/TrackingMotion/goodFeaturesToTrack_Demo.cpp
index cff59f5..da357e7 100644
--- a/samples/cpp/tutorial_code/TrackingMotion/goodFeaturesToTrack_Demo.cpp
+++ b/samples/cpp/tutorial_code/TrackingMotion/goodFeaturesToTrack_Demo.cpp
@@ -5,11 +5,9 @@
  */
 
 #include "opencv2/imgcodecs.hpp"
-#include "opencv2/highgui/highgui.hpp"
-#include "opencv2/imgproc/imgproc.hpp"
+#include "opencv2/highgui.hpp"
+#include "opencv2/imgproc.hpp"
 #include <iostream>
-#include <stdio.h>
-#include <stdlib.h>
 
 using namespace cv;
 using namespace std;
@@ -32,7 +30,7 @@ void goodFeaturesToTrack_Demo( int, void* );
 int main( int, char** argv )
 {
   /// Load source image and convert it to gray
-  src = imread( argv[1], 1 );
+  src = imread( argv[1], IMREAD_COLOR );
   cvtColor( src, src_gray, COLOR_BGR2GRAY );
 
   /// Create Window
diff --git a/samples/cpp/tutorial_code/calib3d/camera_calibration/camera_calibration.cpp b/samples/cpp/tutorial_code/calib3d/camera_calibration/camera_calibration.cpp
index 0322519..b5647b5 100644
--- a/samples/cpp/tutorial_code/calib3d/camera_calibration/camera_calibration.cpp
+++ b/samples/cpp/tutorial_code/calib3d/camera_calibration/camera_calibration.cpp
@@ -1,7 +1,8 @@
 #include <iostream>
 #include <sstream>
-#include <time.h>
-#include <stdio.h>
+#include <string>
+#include <ctime>
+#include <cstdio>
 
 #include <opencv2/core.hpp>
 #include <opencv2/core/utility.hpp>
@@ -11,17 +12,13 @@
 #include <opencv2/videoio.hpp>
 #include <opencv2/highgui.hpp>
 
-#ifndef _CRT_SECURE_NO_WARNINGS
-# define _CRT_SECURE_NO_WARNINGS
-#endif
-
 using namespace cv;
 using namespace std;
 
 static void help()
 {
     cout <<  "This is a camera calibration sample." << endl
-         <<  "Usage: calibration configurationFile"  << endl
+         <<  "Usage: camera_calibration [configuration_file -- default ./default.xml]"  << endl
          <<  "Near the sample file you'll find the configuration file, which has detailed help of "
              "how to edit it.  It may be any OpenCV supported file format XML/YAML." << endl;
 }
@@ -73,6 +70,12 @@ public:
         node["Show_UndistortedImage"] >> showUndistorsed;
         node["Input"] >> input;
         node["Input_Delay"] >> delay;
+        node["Fix_K1"] >> fixK1;
+        node["Fix_K2"] >> fixK2;
+        node["Fix_K3"] >> fixK3;
+        node["Fix_K4"] >> fixK4;
+        node["Fix_K5"] >> fixK5;
+
         validate();
     }
     void validate()
@@ -127,16 +130,23 @@ public:
             goodInput = false;
         }
 
-        flag = CALIB_FIX_K4 | CALIB_FIX_K5;
+        flag = 0;
         if(calibFixPrincipalPoint) flag |= CALIB_FIX_PRINCIPAL_POINT;
         if(calibZeroTangentDist)   flag |= CALIB_ZERO_TANGENT_DIST;
         if(aspectRatio)            flag |= CALIB_FIX_ASPECT_RATIO;
+        if(fixK1)                  flag |= CALIB_FIX_K1;
+        if(fixK2)                  flag |= CALIB_FIX_K2;
+        if(fixK3)                  flag |= CALIB_FIX_K3;
+        if(fixK4)                  flag |= CALIB_FIX_K4;
+        if(fixK5)                  flag |= CALIB_FIX_K5;
 
         if (useFisheye) {
             // the fisheye model has its own enum, so overwrite the flags
-            flag = fisheye::CALIB_FIX_SKEW | fisheye::CALIB_RECOMPUTE_EXTRINSIC |
-                   // fisheye::CALIB_FIX_K1 |
-                   fisheye::CALIB_FIX_K2 | fisheye::CALIB_FIX_K3 | fisheye::CALIB_FIX_K4;
+            flag = fisheye::CALIB_FIX_SKEW | fisheye::CALIB_RECOMPUTE_EXTRINSIC;
+            if(fixK1)                  flag |= fisheye::CALIB_FIX_K1;
+            if(fixK2)                  flag |= fisheye::CALIB_FIX_K2;
+            if(fixK3)                  flag |= fisheye::CALIB_FIX_K3;
+            if(fixK4)                  flag |= fisheye::CALIB_FIX_K4;
         }
 
         calibrationPattern = NOT_EXISTING;
@@ -196,6 +206,11 @@ public:
     bool showUndistorsed;        // Show undistorted images after calibration
     string input;                // The input ->
     bool useFisheye;             // use fisheye camera model for calibration
+    bool fixK1;                  // fix K1 distortion coefficient
+    bool fixK2;                  // fix K2 distortion coefficient
+    bool fixK3;                  // fix K3 distortion coefficient
+    bool fixK4;                  // fix K4 distortion coefficient
+    bool fixK5;                  // fix K5 distortion coefficient
 
     int cameraID;
     vector<string> imageList;
@@ -369,7 +384,10 @@ int main(int argc, char* argv[])
         if( mode == CALIBRATED && s.showUndistorsed )
         {
             Mat temp = view.clone();
-            undistort(temp, view, cameraMatrix, distCoeffs);
+            if (s.useFisheye)
+              cv::fisheye::undistortImage(temp, view, cameraMatrix, distCoeffs);
+            else
+              undistort(temp, view, cameraMatrix, distCoeffs);
         }
         //! [output_undistorted]
         //------------------------------ Show image and check for input commands -------------------
@@ -415,7 +433,7 @@ int main(int argc, char* argv[])
 
         for(size_t i = 0; i < s.imageList.size(); i++ )
         {
-            view = imread(s.imageList[i], 1);
+            view = imread(s.imageList[i], IMREAD_COLOR);
             if(view.empty())
                 continue;
             remap(view, rview, map1, map2, INTER_LINEAR);
@@ -567,25 +585,31 @@ static void saveCameraParams( Settings& s, Size& imageSize, Mat& cameraMatrix, M
 
     if (s.flag)
     {
+        std::stringstream flagsStringStream;
         if (s.useFisheye)
         {
-            sprintf(buf, "flags:%s%s%s%s%s%s",
-                     s.flag & fisheye::CALIB_FIX_SKEW ? " +fix_skew" : "",
-                     s.flag & fisheye::CALIB_FIX_K1 ? " +fix_k1" : "",
-                     s.flag & fisheye::CALIB_FIX_K2 ? " +fix_k2" : "",
-                     s.flag & fisheye::CALIB_FIX_K3 ? " +fix_k3" : "",
-                     s.flag & fisheye::CALIB_FIX_K4 ? " +fix_k4" : "",
-                     s.flag & fisheye::CALIB_RECOMPUTE_EXTRINSIC ? " +recompute_extrinsic" : "");
+            flagsStringStream << "flags:"
+                << (s.flag & fisheye::CALIB_FIX_SKEW ? " +fix_skew" : "")
+                << (s.flag & fisheye::CALIB_FIX_K1 ? " +fix_k1" : "")
+                << (s.flag & fisheye::CALIB_FIX_K2 ? " +fix_k2" : "")
+                << (s.flag & fisheye::CALIB_FIX_K3 ? " +fix_k3" : "")
+                << (s.flag & fisheye::CALIB_FIX_K4 ? " +fix_k4" : "")
+                << (s.flag & fisheye::CALIB_RECOMPUTE_EXTRINSIC ? " +recompute_extrinsic" : "");
         }
         else
         {
-            sprintf(buf, "flags:%s%s%s%s",
-                     s.flag & CALIB_USE_INTRINSIC_GUESS ? " +use_intrinsic_guess" : "",
-                     s.flag & CALIB_FIX_ASPECT_RATIO ? " +fix_aspectRatio" : "",
-                     s.flag & CALIB_FIX_PRINCIPAL_POINT ? " +fix_principal_point" : "",
-                     s.flag & CALIB_ZERO_TANGENT_DIST ? " +zero_tangent_dist" : "");
+            flagsStringStream << "flags:"
+                << (s.flag & CALIB_USE_INTRINSIC_GUESS ? " +use_intrinsic_guess" : "")
+                << (s.flag & CALIB_FIX_ASPECT_RATIO ? " +fix_aspectRatio" : "")
+                << (s.flag & CALIB_FIX_PRINCIPAL_POINT ? " +fix_principal_point" : "")
+                << (s.flag & CALIB_ZERO_TANGENT_DIST ? " +zero_tangent_dist" : "")
+                << (s.flag & CALIB_FIX_K1 ? " +fix_k1" : "")
+                << (s.flag & CALIB_FIX_K2 ? " +fix_k2" : "")
+                << (s.flag & CALIB_FIX_K3 ? " +fix_k3" : "")
+                << (s.flag & CALIB_FIX_K4 ? " +fix_k4" : "")
+                << (s.flag & CALIB_FIX_K5 ? " +fix_k5" : "");
         }
-        cvWriteComment(*fs, buf, 0);
+        fs.writeComment(flagsStringStream.str());
     }
 
     fs << "flags" << s.flag;
@@ -602,19 +626,33 @@ static void saveCameraParams( Settings& s, Size& imageSize, Mat& cameraMatrix, M
     if(s.writeExtrinsics && !rvecs.empty() && !tvecs.empty() )
     {
         CV_Assert(rvecs[0].type() == tvecs[0].type());
-        Mat bigmat((int)rvecs.size(), 6, rvecs[0].type());
+        Mat bigmat((int)rvecs.size(), 6, CV_MAKETYPE(rvecs[0].type(), 1));
+        bool needReshapeR = rvecs[0].depth() != 1 ? true : false;
+        bool needReshapeT = tvecs[0].depth() != 1 ? true : false;
+
         for( size_t i = 0; i < rvecs.size(); i++ )
         {
             Mat r = bigmat(Range(int(i), int(i+1)), Range(0,3));
             Mat t = bigmat(Range(int(i), int(i+1)), Range(3,6));
 
-            CV_Assert(rvecs[i].rows == 3 && rvecs[i].cols == 1);
-            CV_Assert(tvecs[i].rows == 3 && tvecs[i].cols == 1);
-            //*.t() is MatExpr (not Mat) so we can use assignment operator
-            r = rvecs[i].t();
-            t = tvecs[i].t();
+            if(needReshapeR)
+                rvecs[i].reshape(1, 1).copyTo(r);
+            else
+            {
+                //*.t() is MatExpr (not Mat) so we can use assignment operator
+                CV_Assert(rvecs[i].rows == 3 && rvecs[i].cols == 1);
+                r = rvecs[i].t();
+            }
+
+            if(needReshapeT)
+                tvecs[i].reshape(1, 1).copyTo(t);
+            else
+            {
+                CV_Assert(tvecs[i].rows == 3 && tvecs[i].cols == 1);
+                t = tvecs[i].t();
+            }
         }
-        //cvWriteComment( *fs, "a set of 6-tuples (rotation vector + translation vector) for each view", 0 );
+        fs.writeComment("a set of 6-tuples (rotation vector + translation vector) for each view");
         fs << "extrinsic_parameters" << bigmat;
     }
 
diff --git a/samples/cpp/tutorial_code/calib3d/camera_calibration/in_VID5.xml b/samples/cpp/tutorial_code/calib3d/camera_calibration/in_VID5.xml
index 98269ec..5659651 100644
--- a/samples/cpp/tutorial_code/calib3d/camera_calibration/in_VID5.xml
+++ b/samples/cpp/tutorial_code/calib3d/camera_calibration/in_VID5.xml
@@ -41,6 +41,17 @@
   <Write_extrinsicParameters>1</Write_extrinsicParameters>
   <!-- If true (non-zero) we show after calibration the undistorted images.-->
   <Show_UndistortedImage>1</Show_UndistortedImage>
- 
+  <!-- If true (non-zero) will be used fisheye camera model.-->
+  <Calibrate_UseFisheyeModel>0</Calibrate_UseFisheyeModel>
+  <!-- If true (non-zero) distortion coefficient k1 will be equals to zero.-->
+  <Fix_K1>0</Fix_K1>
+  <!-- If true (non-zero) distortion coefficient k2 will be equals to zero.-->
+  <Fix_K2>0</Fix_K2>
+  <!-- If true (non-zero) distortion coefficient k3 will be equals to zero.-->
+  <Fix_K3>0</Fix_K3>
+  <!-- If true (non-zero) distortion coefficient k4 will be equals to zero.-->
+  <Fix_K4>1</Fix_K4>
+  <!-- If true (non-zero) distortion coefficient k5 will be equals to zero.-->
+  <Fix_K5>1</Fix_K5>
 </Settings>
 </opencv_storage>
diff --git a/samples/cpp/tutorial_code/calib3d/real_time_pose_estimation/src/Utils.cpp b/samples/cpp/tutorial_code/calib3d/real_time_pose_estimation/src/Utils.cpp
index fa2bad4..b548bed 100644
--- a/samples/cpp/tutorial_code/calib3d/real_time_pose_estimation/src/Utils.cpp
+++ b/samples/cpp/tutorial_code/calib3d/real_time_pose_estimation/src/Utils.cpp
@@ -11,8 +11,8 @@
 #include "ModelRegistration.h"
 #include "Utils.h"
 
-#include <opencv2/imgproc/imgproc.hpp>
-#include <opencv2/calib3d/calib3d.hpp>
+#include <opencv2/imgproc.hpp>
+#include <opencv2/calib3d.hpp>
 
 // For text
 int fontFace = cv::FONT_ITALIC;
diff --git a/samples/cpp/tutorial_code/calib3d/real_time_pose_estimation/src/main_detection.cpp b/samples/cpp/tutorial_code/calib3d/real_time_pose_estimation/src/main_detection.cpp
index 6de590e..de6f72b 100644
--- a/samples/cpp/tutorial_code/calib3d/real_time_pose_estimation/src/main_detection.cpp
+++ b/samples/cpp/tutorial_code/calib3d/real_time_pose_estimation/src/main_detection.cpp
@@ -2,11 +2,11 @@
 #include <iostream>
 #include <time.h>
 // OpenCV
-#include <opencv2/core/core.hpp>
+#include <opencv2//core.hpp>
 #include <opencv2/core/utility.hpp>
-#include <opencv2/highgui/highgui.hpp>
-#include <opencv2/imgproc/imgproc.hpp>
-#include <opencv2/calib3d/calib3d.hpp>
+#include <opencv2/highgui.hpp>
+#include <opencv2/imgproc.hpp>
+#include <opencv2/calib3d.hpp>
 #include <opencv2/video/tracking.hpp>
 // PnP Tutorial
 #include "Mesh.h"
@@ -180,7 +180,7 @@ int main(int argc, char *argv[])
 
   Mat frame, frame_vis;
 
-  while(cap.read(frame) && waitKey(30) != 27) // capture frame until ESC is pressed
+  while(cap.read(frame) && (char)waitKey(30) != 27) // capture frame until ESC is pressed
   {
 
     frame_vis = frame.clone();    // refresh visualisation frame
diff --git a/samples/cpp/tutorial_code/calib3d/real_time_pose_estimation/src/main_registration.cpp b/samples/cpp/tutorial_code/calib3d/real_time_pose_estimation/src/main_registration.cpp
index da775a0..5ddb83f 100644
--- a/samples/cpp/tutorial_code/calib3d/real_time_pose_estimation/src/main_registration.cpp
+++ b/samples/cpp/tutorial_code/calib3d/real_time_pose_estimation/src/main_registration.cpp
@@ -1,10 +1,10 @@
 // C++
 #include <iostream>
 // OpenCV
-#include <opencv2/core/core.hpp>
-#include <opencv2/imgproc/imgproc.hpp>
-#include <opencv2/calib3d/calib3d.hpp>
-#include <opencv2/features2d/features2d.hpp>
+#include <opencv2/core.hpp>
+#include <opencv2/imgproc.hpp>
+#include <opencv2/calib3d.hpp>
+#include <opencv2/features2d.hpp>
 // PnP Tutorial
 #include "Mesh.h"
 #include "Model.h"
diff --git a/samples/cpp/tutorial_code/calib3d/stereoBM/SBM_Sample.cpp b/samples/cpp/tutorial_code/calib3d/stereoBM/SBM_Sample.cpp
index 90fa280..d114a95 100644
--- a/samples/cpp/tutorial_code/calib3d/stereoBM/SBM_Sample.cpp
+++ b/samples/cpp/tutorial_code/calib3d/stereoBM/SBM_Sample.cpp
@@ -4,12 +4,10 @@
  * @author A. Huaman
  */
 
-#include <stdio.h>
 #include <iostream>
-#include "opencv2/calib3d/calib3d.hpp"
-#include "opencv2/core/core.hpp"
+#include "opencv2/calib3d.hpp"
 #include "opencv2/imgcodecs.hpp"
-#include "opencv2/highgui/highgui.hpp"
+#include "opencv2/highgui.hpp"
 
 using namespace cv;
 
diff --git a/samples/cpp/tutorial_code/core/AddingImages/AddingImages.cpp b/samples/cpp/tutorial_code/core/AddingImages/AddingImages.cpp
new file mode 100644
index 0000000..491ae7a
--- /dev/null
+++ b/samples/cpp/tutorial_code/core/AddingImages/AddingImages.cpp
@@ -0,0 +1,53 @@
+/**
+ * @file AddingImages.cpp
+ * @brief Simple linear blender ( dst = alpha*src1 + beta*src2 )
+ * @author OpenCV team
+ */
+
+#include "opencv2/imgcodecs.hpp"
+#include "opencv2/highgui.hpp"
+#include <iostream>
+
+using namespace cv;
+
+/**
+ * @function main
+ * @brief Main function
+ */
+int main( void )
+{
+   double alpha = 0.5; double beta; double input;
+
+   Mat src1, src2, dst;
+
+   /// Ask the user enter alpha
+   std::cout<<" Simple Linear Blender "<<std::endl;
+   std::cout<<"-----------------------"<<std::endl;
+   std::cout<<"* Enter alpha [0-1]: ";
+   std::cin>>input;
+
+   // We use the alpha provided by the user if it is between 0 and 1
+   if( alpha >= 0 && alpha <= 1 )
+     { alpha = input; }
+
+   //![load]
+   /// Read images ( both have to be of the same size and type )
+   src1 = imread("../data/LinuxLogo.jpg");
+   src2 = imread("../data/WindowsLogo.jpg");
+   //![load]
+
+   if( src1.empty() ) { std::cout<< "Error loading src1"<<std::endl; return -1; }
+   if( src2.empty() ) { std::cout<< "Error loading src2"<<std::endl; return -1; }
+
+   //![blend_images]
+   beta = ( 1.0 - alpha );
+   addWeighted( src1, alpha, src2, beta, 0.0, dst);
+   //![blend_images]
+
+   //![display]
+   imshow( "Linear Blend", dst );
+   waitKey(0);
+   //![display]
+
+   return 0;
+}
diff --git a/samples/cpp/tutorial_code/core/Matrix/Drawing_1.cpp b/samples/cpp/tutorial_code/core/Matrix/Drawing_1.cpp
index 00da530..7e184dd 100644
--- a/samples/cpp/tutorial_code/core/Matrix/Drawing_1.cpp
+++ b/samples/cpp/tutorial_code/core/Matrix/Drawing_1.cpp
@@ -23,6 +23,7 @@ void MyLine( Mat img, Point start, Point end );
  */
 int main( void ){
 
+  //![create_images]
   /// Windows names
   char atom_window[] = "Drawing 1: Atom";
   char rook_window[] = "Drawing 2: Rook";
@@ -30,10 +31,12 @@ int main( void ){
   /// Create black empty images
   Mat atom_image = Mat::zeros( w, w, CV_8UC3 );
   Mat rook_image = Mat::zeros( w, w, CV_8UC3 );
+  //![create_images]
 
   /// 1. Draw a simple atom:
   /// -----------------------
 
+  //![draw_atom]
   /// 1.a. Creating ellipses
   MyEllipse( atom_image, 90 );
   MyEllipse( atom_image, 0 );
@@ -42,26 +45,31 @@ int main( void ){
 
   /// 1.b. Creating circles
   MyFilledCircle( atom_image, Point( w/2, w/2) );
+  //![draw_atom]
 
   /// 2. Draw a rook
   /// ------------------
 
+  //![draw_rook]
   /// 2.a. Create a convex polygon
   MyPolygon( rook_image );
 
+  //![rectangle]
   /// 2.b. Creating rectangles
   rectangle( rook_image,
          Point( 0, 7*w/8 ),
          Point( w, w),
          Scalar( 0, 255, 255 ),
-         -1,
-         8 );
+         FILLED,
+         LINE_8 );
+  //![rectangle]
 
   /// 2.c. Create a few lines
   MyLine( rook_image, Point( 0, 15*w/16 ), Point( w, 15*w/16 ) );
   MyLine( rook_image, Point( w/4, 7*w/8 ), Point( w/4, w ) );
   MyLine( rook_image, Point( w/2, 7*w/8 ), Point( w/2, w ) );
   MyLine( rook_image, Point( 3*w/4, 7*w/8 ), Point( 3*w/4, w ) );
+  //![draw_rook]
 
   /// 3. Display your stuff!
   imshow( atom_window, atom_image );
@@ -75,6 +83,7 @@ int main( void ){
 
 /// Function Declaration
 
+//![myellipse]
 /**
  * @function MyEllipse
  * @brief Draw a fixed-size ellipse with different angles
@@ -94,31 +103,32 @@ void MyEllipse( Mat img, double angle )
        thickness,
        lineType );
 }
+//![myellipse]
 
+//![myfilledcircle]
 /**
  * @function MyFilledCircle
  * @brief Draw a fixed-size filled circle
  */
 void MyFilledCircle( Mat img, Point center )
 {
-  int thickness = -1;
-  int lineType = 8;
-
   circle( img,
       center,
       w/32,
       Scalar( 0, 0, 255 ),
-      thickness,
-      lineType );
+      FILLED,
+      LINE_8 );
 }
+//![myfilledcircle]
 
+//![mypolygon]
 /**
  * @function MyPolygon
- * @function Draw a simple concave polygon (rook)
+ * @brief Draw a simple concave polygon (rook)
  */
 void MyPolygon( Mat img )
 {
-  int lineType = 8;
+  int lineType = LINE_8;
 
   /** Create some points */
   Point rook_points[1][20];
@@ -149,11 +159,13 @@ void MyPolygon( Mat img )
   fillPoly( img,
         ppt,
         npt,
-            1,
+        1,
         Scalar( 255, 255, 255 ),
         lineType );
 }
+//![mypolygon]
 
+//![myline]
 /**
  * @function MyLine
  * @brief Draw a simple line
@@ -161,7 +173,7 @@ void MyPolygon( Mat img )
 void MyLine( Mat img, Point start, Point end )
 {
   int thickness = 2;
-  int lineType = 8;
+  int lineType = LINE_8;
   line( img,
     start,
     end,
@@ -169,3 +181,4 @@ void MyLine( Mat img, Point start, Point end )
     thickness,
     lineType );
 }
+//![myline]
diff --git a/samples/cpp/tutorial_code/core/discrete_fourier_transform/discrete_fourier_transform.cpp b/samples/cpp/tutorial_code/core/discrete_fourier_transform/discrete_fourier_transform.cpp
index dbebeea..e23ab1c 100644
--- a/samples/cpp/tutorial_code/core/discrete_fourier_transform/discrete_fourier_transform.cpp
+++ b/samples/cpp/tutorial_code/core/discrete_fourier_transform/discrete_fourier_transform.cpp
@@ -1,7 +1,7 @@
-#include "opencv2/core/core.hpp"
-#include "opencv2/imgproc/imgproc.hpp"
+#include "opencv2/core.hpp"
+#include "opencv2/imgproc.hpp"
 #include "opencv2/imgcodecs.hpp"
-#include "opencv2/highgui/highgui.hpp"
+#include "opencv2/highgui.hpp"
 
 #include <iostream>
 
diff --git a/samples/cpp/tutorial_code/core/file_input_output/file_input_output.cpp b/samples/cpp/tutorial_code/core/file_input_output/file_input_output.cpp
index 8fc722d..faeacfb 100644
--- a/samples/cpp/tutorial_code/core/file_input_output/file_input_output.cpp
+++ b/samples/cpp/tutorial_code/core/file_input_output/file_input_output.cpp
@@ -1,4 +1,4 @@
-#include <opencv2/core/core.hpp>
+#include <opencv2/core.hpp>
 #include <iostream>
 #include <string>
 
diff --git a/samples/cpp/tutorial_code/core/how_to_scan_images/how_to_scan_images.cpp b/samples/cpp/tutorial_code/core/how_to_scan_images/how_to_scan_images.cpp
index c673c66..47a5547 100644
--- a/samples/cpp/tutorial_code/core/how_to_scan_images/how_to_scan_images.cpp
+++ b/samples/cpp/tutorial_code/core/how_to_scan_images/how_to_scan_images.cpp
@@ -16,7 +16,7 @@ static void help()
         << " we take an input image and divide the native color palette (255) with the "  << endl
         << "input. Shows C operator[] method, iterators and at function for on-the-fly item address calculation."<< endl
         << "Usage:"                                                                       << endl
-        << "./howToScanImages imageNameToUse divideWith [G]"                              << endl
+        << "./how_to_scan_images <imageNameToUse> <divideWith> [G]"                       << endl
         << "if you add a G parameter the image is processed in gray scale"                << endl
         << "--------------------------------------------------------------------------"   << endl
         << endl;
diff --git a/samples/cpp/tutorial_code/core/interoperability_with_OpenCV_1/interoperability_with_OpenCV_1.cpp b/samples/cpp/tutorial_code/core/interoperability_with_OpenCV_1/interoperability_with_OpenCV_1.cpp
index b6aa613..79e7c99 100644
--- a/samples/cpp/tutorial_code/core/interoperability_with_OpenCV_1/interoperability_with_OpenCV_1.cpp
+++ b/samples/cpp/tutorial_code/core/interoperability_with_OpenCV_1/interoperability_with_OpenCV_1.cpp
@@ -1,12 +1,9 @@
 //! [head]
-#include <stdio.h>
 #include <iostream>
 
-#include <opencv2/core/core.hpp>
-#include <opencv2/imgproc/imgproc.hpp>
+#include <opencv2/imgproc.hpp>
 #include "opencv2/imgcodecs.hpp"
-#include <opencv2/highgui/highgui.hpp>
-#include <opencv2/core/utility.hpp>
+#include <opencv2/highgui.hpp>
 
 using namespace cv;  // The new C++ interface API is inside this namespace. Import it.
 using namespace std;
diff --git a/samples/cpp/tutorial_code/core/mat_mask_operations/mat_mask_operations.cpp b/samples/cpp/tutorial_code/core/mat_mask_operations/mat_mask_operations.cpp
index f0cbca1..5493393 100644
--- a/samples/cpp/tutorial_code/core/mat_mask_operations/mat_mask_operations.cpp
+++ b/samples/cpp/tutorial_code/core/mat_mask_operations/mat_mask_operations.cpp
@@ -1,5 +1,3 @@
-#include <opencv2/core.hpp>
-#include <opencv2/core/utility.hpp>
 #include <opencv2/imgcodecs.hpp>
 #include <opencv2/highgui.hpp>
 #include <opencv2/imgproc.hpp>
@@ -25,47 +23,65 @@ int main( int argc, char* argv[])
     help(argv[0]);
     const char* filename = argc >=2 ? argv[1] : "../data/lena.jpg";
 
-    Mat I, J, K;
+    Mat src, dst0, dst1;
 
     if (argc >= 3 && !strcmp("G", argv[2]))
-        I = imread( filename, IMREAD_GRAYSCALE);
+        src = imread( filename, IMREAD_GRAYSCALE);
     else
-        I = imread( filename, IMREAD_COLOR);
+        src = imread( filename, IMREAD_COLOR);
+
+    if (src.empty())
+    {
+        cerr << "Can't open image ["  << filename << "]" << endl;
+        return -1;
+    }
 
     namedWindow("Input", WINDOW_AUTOSIZE);
     namedWindow("Output", WINDOW_AUTOSIZE);
 
-    imshow("Input", I);
+    imshow( "Input", src );
     double t = (double)getTickCount();
 
-    Sharpen(I, J);
+    Sharpen( src, dst0 );
 
     t = ((double)getTickCount() - t)/getTickFrequency();
     cout << "Hand written function times passed in seconds: " << t << endl;
 
-    imshow("Output", J);
-    waitKey(0);
+    imshow( "Output", dst0 );
+    waitKey();
 
-    Mat kern = (Mat_<char>(3,3) <<  0, -1,  0,
+  //![kern]
+    Mat kernel = (Mat_<char>(3,3) <<  0, -1,  0,
                                    -1,  5, -1,
                                     0, -1,  0);
+  //![kern]
+
     t = (double)getTickCount();
-    filter2D(I, K, I.depth(), kern );
+
+  //![filter2D]
+    filter2D( src, dst1, src.depth(), kernel );
+  //![filter2D]
     t = ((double)getTickCount() - t)/getTickFrequency();
     cout << "Built-in filter2D time passed in seconds:      " << t << endl;
 
-    imshow("Output", K);
+    imshow( "Output", dst1 );
 
-    waitKey(0);
+    waitKey();
     return 0;
 }
+//! [basic_method]
 void Sharpen(const Mat& myImage,Mat& Result)
 {
+  //! [8_bit]
     CV_Assert(myImage.depth() == CV_8U);  // accept only uchar images
+  //! [8_bit]
 
+  //! [create_channels]
     const int nChannels = myImage.channels();
     Result.create(myImage.size(),myImage.type());
+  //! [create_channels]
 
+  //! [basic_method_loop]
     for(int j = 1 ; j < myImage.rows-1; ++j)
     {
         const uchar* previous = myImage.ptr<uchar>(j - 1);
@@ -80,9 +96,13 @@ void Sharpen(const Mat& myImage,Mat& Result)
                          -current[i-nChannels] - current[i+nChannels] - previous[i] - next[i]);
         }
     }
+  //! [basic_method_loop]
 
+  //! [borders]
     Result.row(0).setTo(Scalar(0));
     Result.row(Result.rows-1).setTo(Scalar(0));
     Result.col(0).setTo(Scalar(0));
     Result.col(Result.cols-1).setTo(Scalar(0));
+  //! [borders]
 }
+//! [basic_method]
diff --git a/samples/cpp/tutorial_code/core/mat_the_basic_image_container/mat_the_basic_image_container.cpp b/samples/cpp/tutorial_code/core/mat_the_basic_image_container/mat_the_basic_image_container.cpp
index 7fb060b..77ea938 100644
--- a/samples/cpp/tutorial_code/core/mat_the_basic_image_container/mat_the_basic_image_container.cpp
+++ b/samples/cpp/tutorial_code/core/mat_the_basic_image_container/mat_the_basic_image_container.cpp
@@ -1,6 +1,6 @@
 /*  For description look into the help() function. */
 
-#include "opencv2/core/core.hpp"
+#include "opencv2/core.hpp"
 #include <iostream>
 
 using namespace std;
@@ -15,7 +15,7 @@ static void help()
     << "That is, cv::Mat M(...); M.create and cout << M. "                            << endl
     << "Shows how output can be formated to OpenCV, python, numpy, csv and C styles." << endl
     << "Usage:"                                                                       << endl
-    << "./cvout_sample"                                                               << endl
+    << "./mat_the_basic_image_container"                                              << endl
     << "--------------------------------------------------------------------------"   << endl
     << endl;
 }
diff --git a/samples/cpp/tutorial_code/features2D/AKAZE_tracking/planar_tracking.cpp b/samples/cpp/tutorial_code/features2D/AKAZE_tracking/planar_tracking.cpp
index ba845dc..77bd9a6 100755
--- a/samples/cpp/tutorial_code/features2D/AKAZE_tracking/planar_tracking.cpp
+++ b/samples/cpp/tutorial_code/features2D/AKAZE_tracking/planar_tracking.cpp
@@ -1,6 +1,7 @@
 #include <opencv2/features2d.hpp>
 #include <opencv2/videoio.hpp>
 #include <opencv2/opencv.hpp>
+#include <opencv2/highgui.hpp>      //for imshow
 #include <vector>
 #include <iostream>
 #include <iomanip>
@@ -17,6 +18,7 @@ const double nn_match_ratio = 0.8f; // Nearest-neighbour matching ratio
 const int bb_min_inliers = 100; // Minimal number of inliers to draw bounding box
 const int stats_update_period = 10; // On-screen statistics are updated every 10 frames
 
+namespace example {
 class Tracker
 {
 public:
@@ -40,12 +42,22 @@ protected:
 
 void Tracker::setFirstFrame(const Mat frame, vector<Point2f> bb, string title, Stats& stats)
 {
+    cv::Point *ptMask = new cv::Point[bb.size()];
+    const Point* ptContain = { &ptMask[0] };
+    int iSize = static_cast<int>(bb.size());
+    for (size_t i=0; i<bb.size(); i++) {
+        ptMask[i].x = static_cast<int>(bb[i].x);
+        ptMask[i].y = static_cast<int>(bb[i].y);
+    }
     first_frame = frame.clone();
-    detector->detectAndCompute(first_frame, noArray(), first_kp, first_desc);
+    cv::Mat matMask = cv::Mat::zeros(frame.size(), CV_8UC1);
+    cv::fillPoly(matMask, &ptContain, &iSize, 1, cv::Scalar::all(255));
+    detector->detectAndCompute(first_frame, matMask, first_kp, first_desc);
     stats.keypoints = (int)first_kp.size();
     drawBoundingBox(first_frame, bb);
     putText(first_frame, title, Point(0, 60), FONT_HERSHEY_PLAIN, 5, Scalar::all(0), 4);
     object_bb = bb;
+    delete[] ptMask;
 }
 
 Mat Tracker::process(const Mat frame, Stats& stats)
@@ -104,58 +116,67 @@ Mat Tracker::process(const Mat frame, Stats& stats)
                 Scalar(255, 0, 0), Scalar(255, 0, 0));
     return res;
 }
+}
 
 int main(int argc, char **argv)
 {
-    if(argc < 4) {
-        cerr << "Usage: " << endl <<
-                "akaze_track input_path output_path bounding_box" << endl;
+    if(argc < 2) {
+        cerr << "Usage: " << endl
+             << "akaze_track input_path" << endl
+             << "  (input_path can be a camera id, like 0,1,2 or a video filename)" << endl;
         return 1;
     }
-    VideoCapture video_in(argv[1]);
-    VideoWriter  video_out(argv[2],
-                           (int)video_in.get(CAP_PROP_FOURCC),
-                           (int)video_in.get(CAP_PROP_FPS),
-                           Size(2 * (int)video_in.get(CAP_PROP_FRAME_WIDTH),
-                                2 * (int)video_in.get(CAP_PROP_FRAME_HEIGHT)));
 
-    if(!video_in.isOpened()) {
-        cerr << "Couldn't open " << argv[1] << endl;
-        return 1;
+    std::string video_name = argv[1];
+    std::stringstream ssFormat;
+    ssFormat << atoi(argv[1]);
+
+    VideoCapture video_in;
+    if (video_name.compare(ssFormat.str())==0) {    //test str==str(num)
+        video_in.open(atoi(argv[1]));
     }
-    if(!video_out.isOpened()) {
-        cerr << "Couldn't open " << argv[2] << endl;
-        return 1;
+    else {
+        video_in.open(video_name);
     }
 
-    vector<Point2f> bb;
-    FileStorage fs(argv[3], FileStorage::READ);
-    if(fs["bounding_box"].empty()) {
-        cerr << "Couldn't read bounding_box from " << argv[3] << endl;
+    if(!video_in.isOpened()) {
+        cerr << "Couldn't open " << argv[1] << endl;
         return 1;
     }
-    fs["bounding_box"] >> bb;
 
     Stats stats, akaze_stats, orb_stats;
     Ptr<AKAZE> akaze = AKAZE::create();
     akaze->setThreshold(akaze_thresh);
     Ptr<ORB> orb = ORB::create();
-    orb->setMaxFeatures(stats.keypoints);
     Ptr<DescriptorMatcher> matcher = DescriptorMatcher::create("BruteForce-Hamming");
-    Tracker akaze_tracker(akaze, matcher);
-    Tracker orb_tracker(orb, matcher);
+    example::Tracker akaze_tracker(akaze, matcher);
+    example::Tracker orb_tracker(orb, matcher);
 
     Mat frame;
     video_in >> frame;
+    namedWindow(video_name, WINDOW_NORMAL);
+    cv::resizeWindow(video_name, frame.cols, frame.rows);
+
+    cout << "Please select a bounding box, and press any key to continue." << endl;
+    vector<Point2f> bb;
+    cv::Rect2d uBox = selectROI(video_name, frame);
+    bb.push_back(cv::Point2f(static_cast<float>(uBox.x), static_cast<float>(uBox.y)));
+    bb.push_back(cv::Point2f(static_cast<float>(uBox.x+uBox.width), static_cast<float>(uBox.y)));
+    bb.push_back(cv::Point2f(static_cast<float>(uBox.x+uBox.width), static_cast<float>(uBox.y+uBox.height)));
+    bb.push_back(cv::Point2f(static_cast<float>(uBox.x), static_cast<float>(uBox.y+uBox.height)));
+
     akaze_tracker.setFirstFrame(frame, bb, "AKAZE", stats);
     orb_tracker.setFirstFrame(frame, bb, "ORB", stats);
 
     Stats akaze_draw_stats, orb_draw_stats;
-    int frame_count = (int)video_in.get(CAP_PROP_FRAME_COUNT);
     Mat akaze_res, orb_res, res_frame;
-    for(int i = 1; i < frame_count; i++) {
+    int i = 0;
+    for(;;) {
+        i++;
         bool update_stats = (i % stats_update_period == 0);
         video_in >> frame;
+        // stop the program if no more images
+        if(frame.empty()) break;
 
         akaze_res = akaze_tracker.process(frame, stats);
         akaze_stats += stats;
@@ -173,11 +194,11 @@ int main(int argc, char **argv)
         drawStatistics(akaze_res, akaze_draw_stats);
         drawStatistics(orb_res, orb_draw_stats);
         vconcat(akaze_res, orb_res, res_frame);
-        video_out << res_frame;
-        cout << i << "/" << frame_count - 1 << endl;
+        cv::imshow(video_name, res_frame);
+        if(waitKey(1)==27) break; //quit on ESC button
     }
-    akaze_stats /= frame_count - 1;
-    orb_stats /= frame_count - 1;
+    akaze_stats /= i - 1;
+    orb_stats /= i - 1;
     printStatistics("AKAZE", akaze_stats);
     printStatistics("ORB", orb_stats);
     return 0;
diff --git a/samples/cpp/tutorial_code/features2D/AKAZE_tracking/utils.h b/samples/cpp/tutorial_code/features2D/AKAZE_tracking/utils.h
index fbd897e..2142e98 100644
--- a/samples/cpp/tutorial_code/features2D/AKAZE_tracking/utils.h
+++ b/samples/cpp/tutorial_code/features2D/AKAZE_tracking/utils.h
@@ -12,6 +12,7 @@ void drawBoundingBox(Mat image, vector<Point2f> bb);
 void drawStatistics(Mat image, const Stats& stats);
 void printStatistics(string name, Stats stats);
 vector<Point2f> Points(vector<KeyPoint> keypoints);
+Rect2d selectROI(const String &video_name, const Mat &frame);
 
 void drawBoundingBox(Mat image, vector<Point2f> bb)
 {
@@ -56,4 +57,58 @@ vector<Point2f> Points(vector<KeyPoint> keypoints)
     return res;
 }
 
+Rect2d selectROI(const String &video_name, const Mat &frame)
+{
+    struct Data
+    {
+        Point center;
+        Rect2d box;
+
+        static void mouseHandler(int event, int x, int y, int flags, void *param)
+        {
+            Data *data = (Data*)param;
+            switch( event )
+            {
+            // start to select the bounding box
+            case EVENT_LBUTTONDOWN:
+                data->box = cvRect( x, y, 0, 0 );
+                data->center = Point2f((float)x,(float)y);
+                break;
+            // update the selected bounding box
+            case EVENT_MOUSEMOVE:
+                if(flags == 1)
+                {
+                    data->box.width  = 2 * (x - data->center.x);
+                    data->box.height = 2 * (y - data->center.y);
+                    data->box.x = data->center.x - data->box.width / 2.0;
+                    data->box.y = data->center.y - data->box.height / 2.0;
+                }
+                break;
+            // cleaning up the selected bounding box
+            case EVENT_LBUTTONUP:
+                if( data->box.width < 0 )
+                {
+                    data->box.x += data->box.width;
+                    data->box.width *= -1;
+                }
+                if( data->box.height < 0 )
+                {
+                    data->box.y += data->box.height;
+                    data->box.height *= -1;
+                }
+                break;
+            }
+        }
+    } data;
+
+    setMouseCallback(video_name, Data::mouseHandler, &data);
+    while(waitKey(1) < 0)
+    {
+        Mat draw = frame.clone();
+        rectangle(draw, data.box, Scalar(255,0,0), 2, 1);
+        imshow(video_name, draw);
+    }
+    return data.box;
+}
+
 #endif // UTILS_H
diff --git a/samples/cpp/tutorial_code/imgcodecs/GDAL_IO/gdal-image.cpp b/samples/cpp/tutorial_code/imgcodecs/GDAL_IO/gdal-image.cpp
new file mode 100644
index 0000000..f1080c0
--- /dev/null
+++ b/samples/cpp/tutorial_code/imgcodecs/GDAL_IO/gdal-image.cpp
@@ -0,0 +1,246 @@
+/*
+ * gdal_image.cpp -- Load GIS data into OpenCV Containers using the Geospatial Data Abstraction Library
+*/
+
+// OpenCV Headers
+#include "opencv2/core.hpp"
+#include "opencv2/imgproc.hpp"
+#include "opencv2/highgui.hpp"
+
+// C++ Standard Libraries
+#include <cmath>
+#include <iostream>
+#include <stdexcept>
+#include <vector>
+
+using namespace std;
+
+// define the corner points
+//    Note that GDAL library can natively determine this
+cv::Point2d tl( -122.441017, 37.815664 );
+cv::Point2d tr( -122.370919, 37.815311 );
+cv::Point2d bl( -122.441533, 37.747167 );
+cv::Point2d br( -122.3715,   37.746814 );
+
+// determine dem corners
+cv::Point2d dem_bl( -122.0, 38);
+cv::Point2d dem_tr( -123.0, 37);
+
+// range of the heat map colors
+std::vector<std::pair<cv::Vec3b,double> > color_range;
+
+
+// List of all function prototypes
+cv::Point2d lerp( const cv::Point2d&, const cv::Point2d&, const double& );
+
+cv::Vec3b get_dem_color( const double& );
+
+cv::Point2d world2dem( const cv::Point2d&, const cv::Size&);
+
+cv::Point2d pixel2world( const int&, const int&, const cv::Size& );
+
+void add_color( cv::Vec3b& pix, const uchar& b, const uchar& g, const uchar& r );
+
+
+
+/*
+ * Linear Interpolation
+ * p1 - Point 1
+ * p2 - Point 2
+ * t  - Ratio from Point 1 to Point 2
+*/
+cv::Point2d lerp( cv::Point2d const& p1, cv::Point2d const& p2, const double& t ){
+    return cv::Point2d( ((1-t)*p1.x) + (t*p2.x),
+                        ((1-t)*p1.y) + (t*p2.y));
+}
+
+/*
+ * Interpolate Colors
+*/
+template <typename DATATYPE, int N>
+cv::Vec<DATATYPE,N> lerp( cv::Vec<DATATYPE,N> const& minColor,
+                          cv::Vec<DATATYPE,N> const& maxColor,
+                          double const& t ){
+
+    cv::Vec<DATATYPE,N> output;
+    for( int i=0; i<N; i++ ){
+        output[i] = (uchar)(((1-t)*minColor[i]) + (t * maxColor[i]));
+    }
+    return output;
+}
+
+/*
+ * Compute the dem color
+*/
+cv::Vec3b get_dem_color( const double& elevation ){
+
+    // if the elevation is below the minimum, return the minimum
+    if( elevation < color_range[0].second ){
+        return color_range[0].first;
+    }
+    // if the elevation is above the maximum, return the maximum
+    if( elevation > color_range.back().second ){
+        return color_range.back().first;
+    }
+
+    // otherwise, find the proper starting index
+    int idx=0;
+    double t = 0;
+    for( int x=0; x<(int)(color_range.size()-1); x++ ){
+
+        // if the current elevation is below the next item, then use the current
+        // two colors as our range
+        if( elevation < color_range[x+1].second ){
+            idx=x;
+            t = (color_range[x+1].second - elevation)/
+                (color_range[x+1].second - color_range[x].second);
+
+            break;
+        }
+    }
+
+    // interpolate the color
+    return lerp( color_range[idx].first, color_range[idx+1].first, t);
+}
+
+/*
+ * Given a pixel coordinate and the size of the input image, compute the pixel location
+ * on the DEM image.
+*/
+cv::Point2d world2dem( cv::Point2d const& coordinate, const cv::Size& dem_size   ){
+
+
+    // relate this to the dem points
+    // ASSUMING THAT DEM DATA IS ORTHORECTIFIED
+    double demRatioX = ((dem_tr.x - coordinate.x)/(dem_tr.x - dem_bl.x));
+    double demRatioY = 1-((dem_tr.y - coordinate.y)/(dem_tr.y - dem_bl.y));
+
+    cv::Point2d output;
+    output.x = demRatioX * dem_size.width;
+    output.y = demRatioY * dem_size.height;
+
+    return output;
+}
+
+/*
+ * Convert a pixel coordinate to world coordinates
+*/
+cv::Point2d pixel2world( const int& x, const int& y, const cv::Size& size ){
+
+    // compute the ratio of the pixel location to its dimension
+    double rx = (double)x / size.width;
+    double ry = (double)y / size.height;
+
+    // compute LERP of each coordinate
+    cv::Point2d rightSide = lerp(tr, br, ry);
+    cv::Point2d leftSide  = lerp(tl, bl, ry);
+
+    // compute the actual Lat/Lon coordinate of the interpolated coordinate
+    return lerp( leftSide, rightSide, rx );
+}
+
+/*
+ * Add color to a specific pixel color value
+*/
+void add_color( cv::Vec3b& pix, const uchar& b, const uchar& g, const uchar& r ){
+
+    if( pix[0] + b < 255 && pix[0] + b >= 0 ){ pix[0] += b; }
+    if( pix[1] + g < 255 && pix[1] + g >= 0 ){ pix[1] += g; }
+    if( pix[2] + r < 255 && pix[2] + r >= 0 ){ pix[2] += r; }
+}
+
+
+/*
+ * Main Function
+*/
+int main( int argc, char* argv[] ){
+
+    /*
+     * Check input arguments
+    */
+    if( argc < 3 ){
+        cout << "usage: " << argv[0] << " <image_name> <dem_model_name>" << endl;
+        return -1;
+    }
+
+    // load the image (note that we don't have the projection information.  You will
+    // need to load that yourself or use the full GDAL driver.  The values are pre-defined
+    // at the top of this file
+    //![load1]
+    cv::Mat image = cv::imread(argv[1], cv::IMREAD_LOAD_GDAL | cv::IMREAD_COLOR );
+    //![load1]
+
+    //![load2]
+    // load the dem model
+    cv::Mat dem = cv::imread(argv[2], cv::IMREAD_LOAD_GDAL | cv::IMREAD_ANYDEPTH );
+    //![load2]
+
+    // create our output products
+    cv::Mat output_dem(   image.size(), CV_8UC3 );
+    cv::Mat output_dem_flood(   image.size(), CV_8UC3 );
+
+    // for sanity sake, make sure GDAL Loads it as a signed short
+    if( dem.type() != CV_16SC1 ){ throw std::runtime_error("DEM image type must be CV_16SC1"); }
+
+    // define the color range to create our output DEM heat map
+    //  Pair format ( Color, elevation );  Push from low to high
+    //  Note:  This would be perfect for a configuration file, but is here for a working demo.
+    color_range.push_back( std::pair<cv::Vec3b,double>(cv::Vec3b( 188, 154,  46),   -1));
+    color_range.push_back( std::pair<cv::Vec3b,double>(cv::Vec3b( 110, 220, 110), 0.25));
+    color_range.push_back( std::pair<cv::Vec3b,double>(cv::Vec3b( 150, 250, 230),   20));
+    color_range.push_back( std::pair<cv::Vec3b,double>(cv::Vec3b( 160, 220, 200),   75));
+    color_range.push_back( std::pair<cv::Vec3b,double>(cv::Vec3b( 220, 190, 170),  100));
+    color_range.push_back( std::pair<cv::Vec3b,double>(cv::Vec3b( 250, 180, 140),  200));
+
+    // define a minimum elevation
+    double minElevation = -10;
+
+    // iterate over each pixel in the image, computing the dem point
+    for( int y=0; y<image.rows; y++ ){
+    for( int x=0; x<image.cols; x++ ){
+
+        // convert the pixel coordinate to lat/lon coordinates
+        cv::Point2d coordinate = pixel2world( x, y, image.size() );
+
+        // compute the dem image pixel coordinate from lat/lon
+        cv::Point2d dem_coordinate = world2dem( coordinate, dem.size() );
+
+        // extract the elevation
+        double dz;
+        if( dem_coordinate.x >=    0    && dem_coordinate.y >=    0     &&
+            dem_coordinate.x < dem.cols && dem_coordinate.y < dem.rows ){
+            dz = dem.at<short>(dem_coordinate);
+        }else{
+            dz = minElevation;
+        }
+
+        // write the pixel value to the file
+        output_dem_flood.at<cv::Vec3b>(y,x) = image.at<cv::Vec3b>(y,x);
+
+        // compute the color for the heat map output
+        cv::Vec3b actualColor = get_dem_color(dz);
+        output_dem.at<cv::Vec3b>(y,x) = actualColor;
+
+        // show effect of a 10 meter increase in ocean levels
+        if( dz < 10 ){
+            add_color( output_dem_flood.at<cv::Vec3b>(y,x), 90, 0, 0 );
+        }
+        // show effect of a 50 meter increase in ocean levels
+        else if( dz < 50 ){
+            add_color( output_dem_flood.at<cv::Vec3b>(y,x), 0, 90, 0 );
+        }
+        // show effect of a 100 meter increase in ocean levels
+        else if( dz < 100 ){
+            add_color( output_dem_flood.at<cv::Vec3b>(y,x), 0, 0, 90 );
+        }
+
+    }}
+
+    // print our heat map
+    cv::imwrite( "heat-map.jpg"   ,  output_dem );
+
+    // print the flooding effect image
+    cv::imwrite( "flooded.jpg",  output_dem_flood);
+
+    return 0;
+}
diff --git a/samples/cpp/tutorial_code/introduction/display_image/display_image.cpp b/samples/cpp/tutorial_code/introduction/display_image/display_image.cpp
index 558cb66..4562867 100644
--- a/samples/cpp/tutorial_code/introduction/display_image/display_image.cpp
+++ b/samples/cpp/tutorial_code/introduction/display_image/display_image.cpp
@@ -1,7 +1,7 @@
 //! [includes]
-#include <opencv2/core/core.hpp>
+#include <opencv2/core.hpp>
 #include <opencv2/imgcodecs.hpp>
-#include <opencv2/highgui/highgui.hpp>
+#include <opencv2/highgui.hpp>
 
 #include <iostream>
 #include <string>
@@ -16,7 +16,7 @@ using namespace std;
 int main( int argc, char** argv )
 {
     //! [load]
-    string imageName("../data/HappyFish.jpg"); // by default
+    String imageName( "../data/HappyFish.jpg" ); // by default
     if( argc > 1)
     {
         imageName = argv[1];
@@ -28,7 +28,7 @@ int main( int argc, char** argv )
     //! [mat]
 
     //! [imread]
-    image = imread(imageName.c_str(), IMREAD_COLOR); // Read the file
+    image = imread( imageName, IMREAD_COLOR ); // Read the file
     //! [imread]
 
     if( image.empty() )                      // Check for invalid input
diff --git a/samples/cpp/tutorial_code/introduction/documentation/documentation.cpp b/samples/cpp/tutorial_code/introduction/documentation/documentation.cpp
new file mode 100644
index 0000000..23d8c02
--- /dev/null
+++ b/samples/cpp/tutorial_code/introduction/documentation/documentation.cpp
@@ -0,0 +1,14 @@
+#include <iostream>
+
+/**
+ * @function main
+ * @brief Main function
+ */
+int main( void )
+{
+    //! [hello_world]
+    std::cout << "Hello World!";
+    //! [hello_world]
+
+    return 0;
+}
diff --git a/samples/cpp/tutorial_code/ml/non_linear_svms/non_linear_svms.cpp b/samples/cpp/tutorial_code/ml/non_linear_svms/non_linear_svms.cpp
index b221ab5..d046b50 100644
--- a/samples/cpp/tutorial_code/ml/non_linear_svms/non_linear_svms.cpp
+++ b/samples/cpp/tutorial_code/ml/non_linear_svms/non_linear_svms.cpp
@@ -128,7 +128,7 @@ int main()
     //! [show_vectors]
     thick = 2;
     lineType  = 8;
-    Mat sv = svm->getSupportVectors();
+    Mat sv = svm->getUncompressedSupportVectors();
 
     for (int i = 0; i < sv.rows; ++i)
     {
diff --git a/samples/cpp/tutorial_code/objectDetection/objectDetection.cpp b/samples/cpp/tutorial_code/objectDetection/objectDetection.cpp
index fbd76e4..fe321ec 100644
--- a/samples/cpp/tutorial_code/objectDetection/objectDetection.cpp
+++ b/samples/cpp/tutorial_code/objectDetection/objectDetection.cpp
@@ -44,8 +44,8 @@ int main( void )
         //-- 3. Apply the classifier to the frame
         detectAndDisplay( frame );
 
-        int c = waitKey(10);
-        if( (char)c == 27 ) { break; } // escape
+        char c = (char)waitKey(10);
+        if( c == 27 ) { break; } // escape
     }
     return 0;
 }
diff --git a/samples/cpp/tutorial_code/objectDetection/objectDetection2.cpp b/samples/cpp/tutorial_code/objectDetection/objectDetection2.cpp
index d28fa2b..e57139b 100644
--- a/samples/cpp/tutorial_code/objectDetection/objectDetection2.cpp
+++ b/samples/cpp/tutorial_code/objectDetection/objectDetection2.cpp
@@ -51,8 +51,8 @@ int main( void )
         detectAndDisplay( frame );
 
         //-- bail out if escape was pressed
-        int c = waitKey(10);
-        if( (char)c == 27 ) { break; }
+        char c = (char)waitKey(10);
+        if( c == 27 ) { break; }
     }
     return 0;
 }
diff --git a/samples/cpp/tutorial_code/photo/decolorization/decolor.cpp b/samples/cpp/tutorial_code/photo/decolorization/decolor.cpp
index 067bad1..13c1b0c 100644
--- a/samples/cpp/tutorial_code/photo/decolorization/decolor.cpp
+++ b/samples/cpp/tutorial_code/photo/decolorization/decolor.cpp
@@ -27,13 +27,13 @@ using namespace cv;
 int main(int argc, char *argv[])
 {
     CV_Assert(argc == 2);
-    Mat I;
-    I = imread(argv[1]);
+    Mat src;
+    src = imread(argv[1], IMREAD_COLOR);
 
-    Mat gray = Mat(I.size(),CV_8UC1);
-    Mat color_boost = Mat(I.size(),CV_8UC3);
+    Mat gray = Mat(src.size(),CV_8UC1);
+    Mat color_boost = Mat(src.size(),CV_8UC3);
 
-    decolor(I,gray,color_boost);
+    decolor(src,gray,color_boost);
     imshow("grayscale",gray);
     imshow("color_boost",color_boost);
     waitKey(0);
diff --git a/samples/cpp/tutorial_code/photo/non_photorealistic_rendering/npr_demo.cpp b/samples/cpp/tutorial_code/photo/non_photorealistic_rendering/npr_demo.cpp
index f81204c..8a24ddb 100644
--- a/samples/cpp/tutorial_code/photo/non_photorealistic_rendering/npr_demo.cpp
+++ b/samples/cpp/tutorial_code/photo/non_photorealistic_rendering/npr_demo.cpp
@@ -35,9 +35,9 @@ int main(int argc, char* argv[])
 
     int num,type;
 
-    Mat I = imread(argv[1]);
+    Mat src = imread(argv[1], IMREAD_COLOR);
 
-    if(I.empty())
+    if(src.empty())
     {
         cout <<  "Image not found" << endl;
         exit(0);
@@ -71,25 +71,25 @@ int main(int argc, char* argv[])
 
         cin >> type;
 
-        edgePreservingFilter(I,img,type);
+        edgePreservingFilter(src,img,type);
         imshow("Edge Preserve Smoothing",img);
 
     }
     else if(num == 2)
     {
-        detailEnhance(I,img);
+        detailEnhance(src,img);
         imshow("Detail Enhanced",img);
     }
     else if(num == 3)
     {
         Mat img1;
-        pencilSketch(I,img1, img, 10 , 0.1f, 0.03f);
+        pencilSketch(src,img1, img, 10 , 0.1f, 0.03f);
         imshow("Pencil Sketch",img1);
         imshow("Color Pencil Sketch",img);
     }
     else if(num == 4)
     {
-        stylization(I,img);
+        stylization(src,img);
         imshow("Stylization",img);
     }
     waitKey(0);
diff --git a/samples/cpp/tutorial_code/photo/seamless_cloning/cloning_gui.cpp b/samples/cpp/tutorial_code/photo/seamless_cloning/cloning_gui.cpp
index 180cd69..38ce295 100644
--- a/samples/cpp/tutorial_code/photo/seamless_cloning/cloning_gui.cpp
+++ b/samples/cpp/tutorial_code/photo/seamless_cloning/cloning_gui.cpp
@@ -452,7 +452,7 @@ int main()
 
     for(;;)
     {
-        char key = (char) waitKey(0);
+        char key = (char)waitKey(0);
 
         if(key == 'd' && flag3 == 0)
         {
diff --git a/samples/cpp/tutorial_code/video/bg_sub.cpp b/samples/cpp/tutorial_code/video/bg_sub.cpp
index d37c7bd..bd511eb 100644
--- a/samples/cpp/tutorial_code/video/bg_sub.cpp
+++ b/samples/cpp/tutorial_code/video/bg_sub.cpp
@@ -23,7 +23,7 @@ using namespace std;
 Mat frame; //current frame
 Mat fgMaskMOG2; //fg mask fg mask generated by MOG2 method
 Ptr<BackgroundSubtractor> pMOG2; //MOG2 Background subtractor
-int keyboard; //input from keyboard
+char keyboard; //input from keyboard
 
 /** Function Headers */
 void help();
@@ -38,9 +38,9 @@ void help()
     << " OpenCV. You can process both videos (-vid) and images (-img)."             << endl
                                                                                     << endl
     << "Usage:"                                                                     << endl
-    << "./bs {-vid <video filename>|-img <image filename>}"                         << endl
-    << "for example: ./bs -vid video.avi"                                           << endl
-    << "or: ./bs -img /data/images/1.png"                                           << endl
+    << "./bg_sub {-vid <video filename>|-img <image filename>}"                     << endl
+    << "for example: ./bg_sub -vid video.avi"                                       << endl
+    << "or: ./bg_sub -img /data/images/1.png"                                       << endl
     << "--------------------------------------------------------------------------" << endl
     << endl;
 }
@@ -98,7 +98,8 @@ void processVideo(char* videoFilename) {
         exit(EXIT_FAILURE);
     }
     //read input data. ESC or 'q' for quitting
-    while( (char)keyboard != 'q' && (char)keyboard != 27 ){
+    keyboard = 0;
+    while( keyboard != 'q' && keyboard != 27 ){
         //read the current frame
         if(!capture.read(frame)) {
             cerr << "Unable to read next frame." << endl;
@@ -119,7 +120,7 @@ void processVideo(char* videoFilename) {
         imshow("Frame", frame);
         imshow("FG Mask MOG 2", fgMaskMOG2);
         //get the input from the keyboard
-        keyboard = waitKey( 30 );
+        keyboard = (char)waitKey( 30 );
     }
     //delete capture object
     capture.release();
@@ -139,7 +140,8 @@ void processImages(char* fistFrameFilename) {
     //current image filename
     string fn(fistFrameFilename);
     //read input data. ESC or 'q' for quitting
-    while( (char)keyboard != 'q' && (char)keyboard != 27 ){
+    keyboard = 0;
+    while( keyboard != 'q' && keyboard != 27 ){
         //update the background model
         pMOG2->apply(frame, fgMaskMOG2);
         //get the frame number and write it on the current frame
@@ -162,7 +164,7 @@ void processImages(char* fistFrameFilename) {
         imshow("Frame", frame);
         imshow("FG Mask MOG 2", fgMaskMOG2);
         //get the input from the keyboard
-        keyboard = waitKey( 30 );
+        keyboard = (char)waitKey( 30 );
         //search for the next image in the sequence
         ostringstream oss;
         oss << (frameNumber + 1);
diff --git a/samples/cpp/tutorial_code/videoio/video-input-psnr-ssim/video-input-psnr-ssim.cpp b/samples/cpp/tutorial_code/videoio/video-input-psnr-ssim/video-input-psnr-ssim.cpp
new file mode 100644
index 0000000..be0b1a8
--- /dev/null
+++ b/samples/cpp/tutorial_code/videoio/video-input-psnr-ssim/video-input-psnr-ssim.cpp
@@ -0,0 +1,207 @@
+#include <iostream> // for standard I/O
+#include <string>   // for strings
+#include <iomanip>  // for controlling float print precision
+#include <sstream>  // string to number conversion
+
+#include <opencv2/core.hpp>     // Basic OpenCV structures (cv::Mat, Scalar)
+#include <opencv2/imgproc.hpp>  // Gaussian Blur
+#include <opencv2/videoio.hpp>
+#include <opencv2/highgui.hpp>  // OpenCV window I/O
+
+using namespace std;
+using namespace cv;
+
+double getPSNR ( const Mat& I1, const Mat& I2);
+Scalar getMSSIM( const Mat& I1, const Mat& I2);
+
+static void help()
+{
+    cout
+        << "------------------------------------------------------------------------------" << endl
+        << "This program shows how to read a video file with OpenCV. In addition, it "
+        << "tests the similarity of two input videos first with PSNR, and for the frames "
+        << "below a PSNR trigger value, also with MSSIM."                                   << endl
+        << "Usage:"                                                                         << endl
+        << "./video-input-psnr-ssim <referenceVideo> <useCaseTestVideo> <PSNR_Trigger_Value> <Wait_Between_Frames> " << endl
+        << "--------------------------------------------------------------------------"     << endl
+        << endl;
+}
+
+int main(int argc, char *argv[])
+{
+    help();
+
+    if (argc != 5)
+    {
+        cout << "Not enough parameters" << endl;
+        return -1;
+    }
+
+    stringstream conv;
+
+    const string sourceReference = argv[1], sourceCompareWith = argv[2];
+    int psnrTriggerValue, delay;
+    conv << argv[3] << endl << argv[4];       // put in the strings
+    conv >> psnrTriggerValue >> delay;        // take out the numbers
+
+    int frameNum = -1;          // Frame counter
+
+    VideoCapture captRefrnc(sourceReference), captUndTst(sourceCompareWith);
+
+    if (!captRefrnc.isOpened())
+    {
+        cout  << "Could not open reference " << sourceReference << endl;
+        return -1;
+    }
+
+    if (!captUndTst.isOpened())
+    {
+        cout  << "Could not open case test " << sourceCompareWith << endl;
+        return -1;
+    }
+
+    Size refS = Size((int) captRefrnc.get(CAP_PROP_FRAME_WIDTH),
+                     (int) captRefrnc.get(CAP_PROP_FRAME_HEIGHT)),
+         uTSi = Size((int) captUndTst.get(CAP_PROP_FRAME_WIDTH),
+                     (int) captUndTst.get(CAP_PROP_FRAME_HEIGHT));
+
+    if (refS != uTSi)
+    {
+        cout << "Inputs have different size!!! Closing." << endl;
+        return -1;
+    }
+
+    const char* WIN_UT = "Under Test";
+    const char* WIN_RF = "Reference";
+
+    // Windows
+    namedWindow(WIN_RF, WINDOW_AUTOSIZE);
+    namedWindow(WIN_UT, WINDOW_AUTOSIZE);
+    moveWindow(WIN_RF, 400       , 0);         //750,  2 (bernat =0)
+    moveWindow(WIN_UT, refS.width, 0);         //1500, 2
+
+    cout << "Reference frame resolution: Width=" << refS.width << "  Height=" << refS.height
+         << " of nr#: " << captRefrnc.get(CAP_PROP_FRAME_COUNT) << endl;
+
+    cout << "PSNR trigger value " << setiosflags(ios::fixed) << setprecision(3)
+         << psnrTriggerValue << endl;
+
+    Mat frameReference, frameUnderTest;
+    double psnrV;
+    Scalar mssimV;
+
+    for(;;) //Show the image captured in the window and repeat
+    {
+        captRefrnc >> frameReference;
+        captUndTst >> frameUnderTest;
+
+        if (frameReference.empty() || frameUnderTest.empty())
+        {
+            cout << " < < <  Game over!  > > > ";
+            break;
+        }
+
+        ++frameNum;
+        cout << "Frame: " << frameNum << "# ";
+
+        ///////////////////////////////// PSNR ////////////////////////////////////////////////////
+        psnrV = getPSNR(frameReference,frameUnderTest);
+        cout << setiosflags(ios::fixed) << setprecision(3) << psnrV << "dB";
+
+        //////////////////////////////////// MSSIM /////////////////////////////////////////////////
+        if (psnrV < psnrTriggerValue && psnrV)
+        {
+            mssimV = getMSSIM(frameReference, frameUnderTest);
+
+            cout << " MSSIM: "
+                << " R " << setiosflags(ios::fixed) << setprecision(2) << mssimV.val[2] * 100 << "%"
+                << " G " << setiosflags(ios::fixed) << setprecision(2) << mssimV.val[1] * 100 << "%"
+                << " B " << setiosflags(ios::fixed) << setprecision(2) << mssimV.val[0] * 100 << "%";
+        }
+
+        cout << endl;
+
+        ////////////////////////////////// Show Image /////////////////////////////////////////////
+        imshow(WIN_RF, frameReference);
+        imshow(WIN_UT, frameUnderTest);
+
+        char c = (char)waitKey(delay);
+        if (c == 27) break;
+    }
+
+    return 0;
+}
+
+double getPSNR(const Mat& I1, const Mat& I2)
+{
+    Mat s1;
+    absdiff(I1, I2, s1);       // |I1 - I2|
+    s1.convertTo(s1, CV_32F);  // cannot make a square on 8 bits
+    s1 = s1.mul(s1);           // |I1 - I2|^2
+
+    Scalar s = sum(s1);        // sum elements per channel
+
+    double sse = s.val[0] + s.val[1] + s.val[2]; // sum channels
+
+    if( sse <= 1e-10) // for small values return zero
+        return 0;
+    else
+    {
+        double mse  = sse / (double)(I1.channels() * I1.total());
+        double psnr = 10.0 * log10((255 * 255) / mse);
+        return psnr;
+    }
+}
+
+Scalar getMSSIM( const Mat& i1, const Mat& i2)
+{
+    const double C1 = 6.5025, C2 = 58.5225;
+    /***************************** INITS **********************************/
+    int d = CV_32F;
+
+    Mat I1, I2;
+    i1.convertTo(I1, d);            // cannot calculate on one byte large values
+    i2.convertTo(I2, d);
+
+    Mat I2_2   = I2.mul(I2);        // I2^2
+    Mat I1_2   = I1.mul(I1);        // I1^2
+    Mat I1_I2  = I1.mul(I2);        // I1 * I2
+
+    /*************************** END INITS **********************************/
+
+    Mat mu1, mu2;                   // PRELIMINARY COMPUTING
+    GaussianBlur(I1, mu1, Size(11, 11), 1.5);
+    GaussianBlur(I2, mu2, Size(11, 11), 1.5);
+
+    Mat mu1_2   =   mu1.mul(mu1);
+    Mat mu2_2   =   mu2.mul(mu2);
+    Mat mu1_mu2 =   mu1.mul(mu2);
+
+    Mat sigma1_2, sigma2_2, sigma12;
+
+    GaussianBlur(I1_2, sigma1_2, Size(11, 11), 1.5);
+    sigma1_2 -= mu1_2;
+
+    GaussianBlur(I2_2, sigma2_2, Size(11, 11), 1.5);
+    sigma2_2 -= mu2_2;
+
+    GaussianBlur(I1_I2, sigma12, Size(11, 11), 1.5);
+    sigma12 -= mu1_mu2;
+
+    ///////////////////////////////// FORMULA ////////////////////////////////
+    Mat t1, t2, t3;
+
+    t1 = 2 * mu1_mu2 + C1;
+    t2 = 2 * sigma12 + C2;
+    t3 = t1.mul(t2);                 // t3 = ((2*mu1_mu2 + C1).*(2*sigma12 + C2))
+
+    t1 = mu1_2 + mu2_2 + C1;
+    t2 = sigma1_2 + sigma2_2 + C2;
+    t1 = t1.mul(t2);                 // t1 =((mu1_2 + mu2_2 + C1).*(sigma1_2 + sigma2_2 + C2))
+
+    Mat ssim_map;
+    divide(t3, t1, ssim_map);        // ssim_map =  t3./t1;
+
+    Scalar mssim = mean(ssim_map);   // mssim = average of ssim map
+    return mssim;
+}
diff --git a/samples/cpp/tutorial_code/videoio/video-write/video-write.cpp b/samples/cpp/tutorial_code/videoio/video-write/video-write.cpp
new file mode 100644
index 0000000..56676fc
--- /dev/null
+++ b/samples/cpp/tutorial_code/videoio/video-write/video-write.cpp
@@ -0,0 +1,95 @@
+#include <iostream>	// for standard I/O
+#include <string>   // for strings
+
+#include <opencv2/core.hpp>     // Basic OpenCV structures (cv::Mat)
+#include <opencv2/videoio.hpp>  // Video write
+
+using namespace std;
+using namespace cv;
+
+static void help()
+{
+    cout
+        << "------------------------------------------------------------------------------" << endl
+        << "This program shows how to write video files."                                   << endl
+        << "You can extract the R or G or B color channel of the input video."              << endl
+        << "Usage:"                                                                         << endl
+        << "./video-write <input_video_name> [ R | G | B] [Y | N]"                          << endl
+        << "------------------------------------------------------------------------------" << endl
+        << endl;
+}
+
+int main(int argc, char *argv[])
+{
+    help();
+
+    if (argc != 4)
+    {
+        cout << "Not enough parameters" << endl;
+        return -1;
+    }
+
+    const string source      = argv[1];           // the source file name
+    const bool askOutputType = argv[3][0] =='Y';  // If false it will use the inputs codec type
+
+    VideoCapture inputVideo(source);              // Open input
+    if (!inputVideo.isOpened())
+    {
+        cout  << "Could not open the input video: " << source << endl;
+        return -1;
+    }
+
+    string::size_type pAt = source.find_last_of('.');                  // Find extension point
+    const string NAME = source.substr(0, pAt) + argv[2][0] + ".avi";   // Form the new name with container
+    int ex = static_cast<int>(inputVideo.get(CAP_PROP_FOURCC));     // Get Codec Type- Int form
+
+    // Transform from int to char via Bitwise operators
+    char EXT[] = {(char)(ex & 0XFF) , (char)((ex & 0XFF00) >> 8),(char)((ex & 0XFF0000) >> 16),(char)((ex & 0XFF000000) >> 24), 0};
+
+    Size S = Size((int) inputVideo.get(CAP_PROP_FRAME_WIDTH),    // Acquire input size
+                  (int) inputVideo.get(CAP_PROP_FRAME_HEIGHT));
+
+    VideoWriter outputVideo;                                        // Open the output
+    if (askOutputType)
+        outputVideo.open(NAME, ex=-1, inputVideo.get(CAP_PROP_FPS), S, true);
+    else
+        outputVideo.open(NAME, ex, inputVideo.get(CAP_PROP_FPS), S, true);
+
+    if (!outputVideo.isOpened())
+    {
+        cout  << "Could not open the output video for write: " << source << endl;
+        return -1;
+    }
+
+    cout << "Input frame resolution: Width=" << S.width << "  Height=" << S.height
+         << " of nr#: " << inputVideo.get(CAP_PROP_FRAME_COUNT) << endl;
+    cout << "Input codec type: " << EXT << endl;
+
+    int channel = 2; // Select the channel to save
+    switch(argv[2][0])
+    {
+    case 'R' : channel = 2; break;
+    case 'G' : channel = 1; break;
+    case 'B' : channel = 0; break;
+    }
+    Mat src, res;
+    vector<Mat> spl;
+
+    for(;;) //Show the image captured in the window and repeat
+    {
+        inputVideo >> src;              // read
+        if (src.empty()) break;         // check if at end
+
+        split(src, spl);                // process - extract only the correct channel
+        for (int i =0; i < 3; ++i)
+            if (i != channel)
+                spl[i] = Mat::zeros(S, spl[0].type());
+       merge(spl, res);
+
+       //outputVideo.write(res); //save or
+       outputVideo << res;
+    }
+
+    cout << "Finished writing" << endl;
+    return 0;
+}
diff --git a/samples/cpp/tutorial_code/viz/creating_widgets.cpp b/samples/cpp/tutorial_code/viz/creating_widgets.cpp
index 63f572e..37e9598 100644
--- a/samples/cpp/tutorial_code/viz/creating_widgets.cpp
+++ b/samples/cpp/tutorial_code/viz/creating_widgets.cpp
@@ -4,6 +4,14 @@
  * @author Ozan Cagri Tonkal
  */
 
+#ifndef USE_VTK
+#include <iostream>
+int main()
+{
+    std::cout << "This sample requires direct compilation with VTK. Stop" << std::endl;
+    return 0;
+}
+#else
 #include <opencv2/viz.hpp>
 #include <opencv2/viz/widget_accessor.hpp>
 #include <iostream>
@@ -24,7 +32,7 @@ using namespace std;
  * @function help
  * @brief Display instructions to use this tutorial program
  */
-void help()
+static void help()
 {
     cout
     << "--------------------------------------------------------------------------"   << endl
@@ -111,3 +119,4 @@ int main()
 
     return 0;
 }
+#endif
diff --git a/samples/cpp/tutorial_code/viz/launching_viz.cpp b/samples/cpp/tutorial_code/viz/launching_viz.cpp
index d19967e..6309710 100644
--- a/samples/cpp/tutorial_code/viz/launching_viz.cpp
+++ b/samples/cpp/tutorial_code/viz/launching_viz.cpp
@@ -14,7 +14,7 @@ using namespace std;
  * @function help
  * @brief Display instructions to use this tutorial program
  */
-void help()
+static void help()
 {
     cout
     << "--------------------------------------------------------------------------" << endl
@@ -41,7 +41,7 @@ int main()
     cout << "First event loop is over" << endl;
 
     /// Access window via its name
-    viz::Viz3d sameWindow = viz::get("Viz Demo");
+    viz::Viz3d sameWindow = viz::getWindowByName("Viz Demo");
 
     /// Start event loop
     sameWindow.spin();
diff --git a/samples/cpp/tutorial_code/viz/transformations.cpp b/samples/cpp/tutorial_code/viz/transformations.cpp
index 0d7450a..84a1985 100644
--- a/samples/cpp/tutorial_code/viz/transformations.cpp
+++ b/samples/cpp/tutorial_code/viz/transformations.cpp
@@ -15,7 +15,7 @@ using namespace std;
  * @function help
  * @brief Display instructions to use this tutorial program
  */
-void help()
+static void help()
 {
     cout
     << "--------------------------------------------------------------------------"   << endl
@@ -31,7 +31,7 @@ void help()
  * @function cvcloud_load
  * @brief load bunny.ply
  */
-Mat cvcloud_load()
+static Mat cvcloud_load()
 {
     Mat cloud(1, 1889, CV_32FC3);
     ifstream ifs("bunny.ply");
@@ -71,7 +71,7 @@ int main(int argn, char **argv)
     myWindow.showWidget("Coordinate Widget", viz::WCoordinateSystem());
 
     /// Let's assume camera has the following properties
-    Point3f cam_pos(3.0f,3.0f,3.0f), cam_focal_point(3.0f,3.0f,2.0f), cam_y_dir(-1.0f,0.0f,0.0f);
+    Vec3f cam_pos(3.0f,3.0f,3.0f), cam_focal_point(3.0f,3.0f,2.0f), cam_y_dir(-1.0f,0.0f,0.0f);
 
     /// We can get the pose of the cam using makeCameraPose
     Affine3f cam_pose = viz::makeCameraPose(cam_pos, cam_focal_point, cam_y_dir);
diff --git a/samples/cpp/tutorial_code/viz/widget_pose.cpp b/samples/cpp/tutorial_code/viz/widget_pose.cpp
index 0fe9d81..529a842 100644
--- a/samples/cpp/tutorial_code/viz/widget_pose.cpp
+++ b/samples/cpp/tutorial_code/viz/widget_pose.cpp
@@ -15,7 +15,7 @@ using namespace std;
  * @function help
  * @brief Display instructions to use this tutorial program
  */
-void help()
+static void help()
 {
     cout
     << "--------------------------------------------------------------------------"   << endl
diff --git a/samples/cpp/tvl1_optical_flow.cpp b/samples/cpp/tvl1_optical_flow.cpp
index 55b5558..95871c7 100644
--- a/samples/cpp/tvl1_optical_flow.cpp
+++ b/samples/cpp/tvl1_optical_flow.cpp
@@ -185,7 +185,7 @@ int main(int argc, const char* argv[])
     }
 
     Mat_<Point2f> flow;
-    Ptr<DenseOpticalFlow> tvl1 = createOptFlow_DualTVL1();
+    Ptr<DualTVL1OpticalFlow> tvl1 = cv::DualTVL1OpticalFlow::create();
 
     const double start = (double)getTickCount();
     tvl1->calc(frame0, frame1, flow);
diff --git a/samples/cpp/videocapture_basic.cpp b/samples/cpp/videocapture_basic.cpp
new file mode 100644
index 0000000..ae77b05
--- /dev/null
+++ b/samples/cpp/videocapture_basic.cpp
@@ -0,0 +1,52 @@
+/**
+  @file videocapture_basic.cpp
+  @brief A very basic sample for using VideoCapture and VideoWriter
+  @author PkLab.net
+  @date Aug 24, 2016
+*/
+
+#include <opencv2/opencv.hpp>
+#include <iostream>
+#include <stdio.h>
+
+using namespace cv;
+using namespace std;
+
+int main(int, char**)
+{
+    Mat frame;
+    //--- INITIALIZE VIDEOCAPTURE
+    VideoCapture cap;
+    // open the default camera using default API
+    cap.open(0);
+    // OR advance usage: select any API backend
+    int deviceID = 0;             // 0 = open default camera
+    int apiID = cv::CAP_ANY;      // 0 = autodetect default API
+    // open selected camera using selected API
+    cap.open(deviceID + apiID);
+    // check if we succeeded
+    if (!cap.isOpened()) {
+        cerr << "ERROR! Unable to open camera\n";
+        return -1;
+    }
+
+    //--- GRAB AND WRITE LOOP
+    cout << "Start grabbing" << endl
+        << "Press any key to terminate" << endl;
+    for (;;)
+    {
+        // wait for a new frame from camera and store it into 'frame'
+        cap.read(frame);
+        // check if we succeeded
+        if (frame.empty()) {
+            cerr << "ERROR! blank frame grabbed\n";
+            break;
+        }
+        // show live and wait for a key with timeout long enough to show images
+        imshow("Live", frame);
+        if (waitKey(5) >= 0)
+            break;
+    }
+    // the camera will be deinitialized automatically in VideoCapture destructor
+    return 0;
+}
\ No newline at end of file
diff --git a/samples/cpp/videocapture_starter.cpp b/samples/cpp/videocapture_starter.cpp
new file mode 100644
index 0000000..58f1145
--- /dev/null
+++ b/samples/cpp/videocapture_starter.cpp
@@ -0,0 +1,93 @@
+/**
+* @file videocapture_starter.cpp
+* @brief A starter sample for using OpenCV VideoCapture with capture devices, video files or image sequences
+* easy as CV_PI right?
+*
+*  Created on: Nov 23, 2010
+*      Author: Ethan Rublee
+*
+*  Modified on: April 17, 2013
+*      Author: Kevin Hughes
+*/
+
+#include <opencv2/imgcodecs.hpp>
+#include <opencv2/videoio.hpp>
+#include <opencv2/highgui.hpp>
+
+#include <iostream>
+#include <stdio.h>
+
+using namespace cv;
+using namespace std;
+
+//hide the local functions in an anon namespace
+namespace {
+    void help(char** av) {
+        cout << "The program captures frames from a video file, image sequence (01.jpg, 02.jpg ... 10.jpg) or camera connected to your computer." << endl
+             << "Usage:\n" << av[0] << " <video file, image sequence or device number>" << endl
+             << "q,Q,esc -- quit" << endl
+             << "space   -- save frame" << endl << endl
+             << "\tTo capture from a camera pass the device number. To find the device number, try ls /dev/video*" << endl
+             << "\texample: " << av[0] << " 0" << endl
+             << "\tYou may also pass a video file instead of a device number" << endl
+             << "\texample: " << av[0] << " video.avi" << endl
+             << "\tYou can also pass the path to an image sequence and OpenCV will treat the sequence just like a video." << endl
+             << "\texample: " << av[0] << " right%%02d.jpg" << endl;
+    }
+
+    int process(VideoCapture& capture) {
+        int n = 0;
+        char filename[200];
+        string window_name = "video | q or esc to quit";
+        cout << "press space to save a picture. q or esc to quit" << endl;
+        namedWindow(window_name, WINDOW_KEEPRATIO); //resizable window;
+        Mat frame;
+
+        for (;;) {
+            capture >> frame;
+            if (frame.empty())
+                break;
+
+            imshow(window_name, frame);
+            char key = (char)waitKey(30); //delay N millis, usually long enough to display and capture input
+
+            switch (key) {
+            case 'q':
+            case 'Q':
+            case 27: //escape key
+                return 0;
+            case ' ': //Save an image
+                sprintf(filename,"filename%.3d.jpg",n++);
+                imwrite(filename,frame);
+                cout << "Saved " << filename << endl;
+                break;
+            default:
+                break;
+            }
+        }
+        return 0;
+    }
+}
+
+int main(int ac, char** av) {
+    cv::CommandLineParser parser(ac, av, "{help h||}{@input||}");
+    if (parser.has("help"))
+    {
+        help(av);
+        return 0;
+    }
+    std::string arg = parser.get<std::string>("@input");
+    if (arg.empty()) {
+        help(av);
+        return 1;
+    }
+    VideoCapture capture(arg); //try to open string, this will attempt to open it as a video file or image sequence
+    if (!capture.isOpened()) //if this fails, try to open as a video camera, through the use of an integer param
+        capture.open(atoi(arg.c_str()));
+    if (!capture.isOpened()) {
+        cerr << "Failed to open the video device, video file or image sequence!\n" << endl;
+        help(av);
+        return 1;
+    }
+    return process(capture);
+}
diff --git a/samples/cpp/videostab.cpp b/samples/cpp/videostab.cpp
index 3fb7fb4..1bb3fc2 100644
--- a/samples/cpp/videostab.cpp
+++ b/samples/cpp/videostab.cpp
@@ -224,6 +224,8 @@ public:
             kbest->setOutlierRejector(outlierRejector);
             return kbest;
         }
+#else
+        CV_Assert(gpu == false && "CUDA modules are not available");
 #endif
 
         Ptr<KeypointBasedMotionEstimator> kbest = makePtr<KeypointBasedMotionEstimator>(est);
@@ -265,6 +267,8 @@ public:
             kbest->setOutlierRejector(outlierRejector);
             return kbest;
         }
+#else
+        CV_Assert(gpu == false && "CUDA modules are not available");
 #endif
 
         Ptr<KeypointBasedMotionEstimator> kbest = makePtr<KeypointBasedMotionEstimator>(est);
diff --git a/samples/cpp/videowriter_basic.cpp b/samples/cpp/videowriter_basic.cpp
new file mode 100644
index 0000000..9ab4efc
--- /dev/null
+++ b/samples/cpp/videowriter_basic.cpp
@@ -0,0 +1,65 @@
+/**
+  @file videowriter_basic.cpp
+  @brief A very basic sample for using VideoWriter and VideoCapture
+  @author PkLab.net
+  @date Aug 24, 2016
+*/
+
+#include <opencv2/opencv.hpp>
+#include <iostream>
+#include <stdio.h>
+
+using namespace cv;
+using namespace std;
+
+int main(int, char**)
+{
+    Mat src;
+    // use default camera as video source
+    VideoCapture cap(0);
+    // check if we succeeded
+    if (!cap.isOpened()) {
+        cerr << "ERROR! Unable to open camera\n";
+        return -1;
+    }
+    // get one frame from camera to know frame size and type
+    cap >> src;
+    // check if we succeeded
+    if (src.empty()) {
+        cerr << "ERROR! blank frame grabbed\n";
+        return -1;
+    }
+    bool isColor = (src.type() == CV_8UC3);
+
+    //--- INITIALIZE VIDEOWRITER
+    VideoWriter writer;
+    int codec = CV_FOURCC('M', 'J', 'P', 'G');  // select desired codec (must be available at runtime)
+    double fps = 25.0;                          // framerate of the created video stream
+    string filename = "./live.avi";             // name of the output video file
+    writer.open(filename, codec, fps, src.size(), isColor);
+    // check if we succeeded
+    if (!writer.isOpened()) {
+        cerr << "Could not open the output video file for write\n";
+        return -1;
+    }
+
+    //--- GRAB AND WRITE LOOP
+    cout << "Writing videofile: " << filename << endl
+         << "Press any key to terminate" << endl;
+    for (;;)
+    {
+        // check if we succeeded
+        if (!cap.read(src)) {
+            cerr << "ERROR! blank frame grabbed\n";
+            break;
+        }
+        // encode the frame into the videofile stream
+        writer.write(src);
+        // show live and wait for a key with timeout long enough to show images
+        imshow("Live", src);
+        if (waitKey(5) >= 0)
+            break;
+    }
+    // the videofile will be closed and released automatically in VideoWriter destructor
+    return 0;
+}
\ No newline at end of file
diff --git a/samples/cpp/watershed.cpp b/samples/cpp/watershed.cpp
index 9f2e69e..0991bb0 100644
--- a/samples/cpp/watershed.cpp
+++ b/samples/cpp/watershed.cpp
@@ -74,19 +74,19 @@ int main( int argc, char** argv )
 
     for(;;)
     {
-        int c = waitKey(0);
+        char c = (char)waitKey(0);
 
-        if( (char)c == 27 )
+        if( c == 27 )
             break;
 
-        if( (char)c == 'r' )
+        if( c == 'r' )
         {
             markerMask = Scalar::all(0);
             img0.copyTo(img);
             imshow( "image", img );
         }
 
-        if( (char)c == 'w' || (char)c == ' ' )
+        if( c == 'w' || c == ' ' )
         {
             int i, j, compCount = 0;
             vector<vector<Point> > contours;
diff --git a/samples/cpp/tutorial_code/HighGUI/video-input-psnr-ssim/video/Megamind.avi b/samples/data/Megamind.avi
similarity index 100%
rename from samples/cpp/tutorial_code/HighGUI/video-input-psnr-ssim/video/Megamind.avi
rename to samples/data/Megamind.avi
diff --git a/samples/cpp/tutorial_code/HighGUI/video-input-psnr-ssim/video/Megamind_bugy.avi b/samples/data/Megamind_bugy.avi
similarity index 100%
rename from samples/cpp/tutorial_code/HighGUI/video-input-psnr-ssim/video/Megamind_bugy.avi
rename to samples/data/Megamind_bugy.avi
diff --git a/samples/data/apple.jpg b/samples/data/apple.jpg
new file mode 100644
index 0000000..2ff27ee
Binary files /dev/null and b/samples/data/apple.jpg differ
diff --git a/samples/data/gradient.png b/samples/data/gradient.png
new file mode 100644
index 0000000..255e77f
Binary files /dev/null and b/samples/data/gradient.png differ
diff --git a/samples/data/lena_tmpl.jpg b/samples/data/lena_tmpl.jpg
new file mode 100644
index 0000000..0c9fc20
Binary files /dev/null and b/samples/data/lena_tmpl.jpg differ
diff --git a/samples/data/ml.png b/samples/data/ml.png
new file mode 100644
index 0000000..6420b44
Binary files /dev/null and b/samples/data/ml.png differ
diff --git a/samples/data/opencv-logo-white.png b/samples/data/opencv-logo-white.png
new file mode 100644
index 0000000..3c70984
Binary files /dev/null and b/samples/data/opencv-logo-white.png differ
diff --git a/samples/data/opencv-logo.png b/samples/data/opencv-logo.png
index 8cd8155..bc71a2a 100644
Binary files a/samples/data/opencv-logo.png and b/samples/data/opencv-logo.png differ
diff --git a/samples/data/orange.jpg b/samples/data/orange.jpg
new file mode 100644
index 0000000..773a846
Binary files /dev/null and b/samples/data/orange.jpg differ
diff --git a/samples/data/sudoku.png b/samples/data/sudoku.png
new file mode 100644
index 0000000..763e518
Binary files /dev/null and b/samples/data/sudoku.png differ
diff --git a/samples/data/tree.avi b/samples/data/tree.avi
index 8c7ff14..ded3608 100644
Binary files a/samples/data/tree.avi and b/samples/data/tree.avi differ
diff --git a/samples/data/768x576.avi b/samples/data/vtest.avi
similarity index 100%
rename from samples/data/768x576.avi
rename to samples/data/vtest.avi
diff --git a/samples/gpu/CMakeLists.txt b/samples/gpu/CMakeLists.txt
index 6085cac..8c97ea8 100644
--- a/samples/gpu/CMakeLists.txt
+++ b/samples/gpu/CMakeLists.txt
@@ -81,9 +81,9 @@ if(BUILD_EXAMPLES AND OCV_DEPENDENCIES_FOUND)
 
   file(GLOB all_samples RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.cpp)
 
-  if(NOT WITH_OPENGL)
+  if(NOT HAVE_OPENGL)
     list(REMOVE_ITEM all_samples "opengl.cpp")
-  endif(NOT WITH_OPENGL)
+  endif()
 
   foreach(sample_filename ${all_samples})
     get_filename_component(sample ${sample_filename} NAME_WE)
@@ -96,9 +96,9 @@ endif()
 
 if(INSTALL_C_EXAMPLES AND NOT WIN32)
   file(GLOB install_list *.c *.cpp *.jpg *.png *.data makefile.* build_all.sh *.dsp *.cmd )
-  if(NOT WITH_OPENGL)
-    list(REMOVE_ITEM all_samples "opengl.cpp")
-  endif(NOT WITH_OPENGL)
+  if(NOT HAVE_OPENGL)
+    list(REMOVE_ITEM install_list "opengl.cpp")
+  endif()
   install(FILES ${install_list}
           DESTINATION ${OPENCV_SAMPLES_SRC_INSTALL_PATH}/gpu
           PERMISSIONS OWNER_READ GROUP_READ WORLD_READ COMPONENT samples)
diff --git a/samples/gpu/alpha_comp.cpp b/samples/gpu/alpha_comp.cpp
index 816c0a7..3f7966d 100644
--- a/samples/gpu/alpha_comp.cpp
+++ b/samples/gpu/alpha_comp.cpp
@@ -1,7 +1,7 @@
 #include <iostream>
 
 #include "opencv2/core/opengl.hpp"
-#include "opencv2/highgui/highgui.hpp"
+#include "opencv2/highgui.hpp"
 #include "opencv2/cudaimgproc.hpp"
 
 using namespace std;
diff --git a/samples/gpu/bgfg_segm.cpp b/samples/gpu/bgfg_segm.cpp
index 00bb59e..b7d9d7e 100644
--- a/samples/gpu/bgfg_segm.cpp
+++ b/samples/gpu/bgfg_segm.cpp
@@ -23,10 +23,10 @@ enum Method
 int main(int argc, const char** argv)
 {
     cv::CommandLineParser cmd(argc, argv,
-        "{ c camera |             | use camera }"
-        "{ f file   | ../data/768x576.avi | input video file }"
-        "{ m method | mog         | method (mog, mog2, gmg, fgd) }"
-        "{ h help   |             | print help message }");
+        "{ c camera |                    | use camera }"
+        "{ f file   | ../data/vtest.avi  | input video file }"
+        "{ m method | mog                | method (mog, mog2, gmg, fgd) }"
+        "{ h help   |                    | print help message }");
 
     if (cmd.has("help") || !cmd.check())
     {
@@ -161,7 +161,7 @@ int main(int argc, const char** argv)
         if (!bgimg.empty())
             imshow("mean background image", bgimg);
 
-        int key = waitKey(30);
+        char key = (char)waitKey(30);
         if (key == 27)
             break;
     }
diff --git a/samples/gpu/cascadeclassifier.cpp b/samples/gpu/cascadeclassifier.cpp
index f6209f9..f59ff55 100644
--- a/samples/gpu/cascadeclassifier.cpp
+++ b/samples/gpu/cascadeclassifier.cpp
@@ -6,15 +6,13 @@
 
 #include <iostream>
 #include <iomanip>
-#include "opencv2/objdetect/objdetect.hpp"
-#include "opencv2/highgui/highgui.hpp"
-#include "opencv2/imgproc/imgproc.hpp"
+#include "opencv2/objdetect.hpp"
+#include "opencv2/highgui.hpp"
+#include "opencv2/imgproc.hpp"
 #include "opencv2/cudaobjdetect.hpp"
 #include "opencv2/cudaimgproc.hpp"
 #include "opencv2/cudawarping.hpp"
 
-#include "tick_meter.hpp"
-
 using namespace std;
 using namespace cv;
 using namespace cv::cuda;
diff --git a/samples/gpu/driver_api_multi.cpp b/samples/gpu/driver_api_multi.cpp
index 7018eea..6d49ee9 100644
--- a/samples/gpu/driver_api_multi.cpp
+++ b/samples/gpu/driver_api_multi.cpp
@@ -8,19 +8,14 @@
 
 #include <iostream>
 #include "opencv2/cvconfig.h"
-#include "opencv2/core/core.hpp"
+#include "opencv2/core.hpp"
 #include "opencv2/cudaarithm.hpp"
 
 #ifdef HAVE_TBB
-#  include "tbb/tbb_stddef.h"
-#  if TBB_VERSION_MAJOR*100 + TBB_VERSION_MINOR >= 202
-#    include "tbb/tbb.h"
-#    include "tbb/task.h"
-#    undef min
-#    undef max
-#  else
-#    undef HAVE_TBB
-#  endif
+#  include "tbb/tbb.h"
+#  include "tbb/task.h"
+#  undef min
+#  undef max
 #endif
 
 #if !defined(HAVE_CUDA) || !defined(HAVE_TBB) || defined(__arm__)
diff --git a/samples/gpu/driver_api_stereo_multi.cpp b/samples/gpu/driver_api_stereo_multi.cpp
index 6c55e36..e487c31 100644
--- a/samples/gpu/driver_api_stereo_multi.cpp
+++ b/samples/gpu/driver_api_stereo_multi.cpp
@@ -9,20 +9,15 @@
 
 #include <iostream>
 #include "opencv2/cvconfig.h"
-#include "opencv2/core/core.hpp"
-#include "opencv2/highgui/highgui.hpp"
+#include "opencv2/core.hpp"
+#include "opencv2/highgui.hpp"
 #include "opencv2/cudastereo.hpp"
 
 #ifdef HAVE_TBB
-#  include "tbb/tbb_stddef.h"
-#  if TBB_VERSION_MAJOR*100 + TBB_VERSION_MINOR >= 202
-#    include "tbb/tbb.h"
-#    include "tbb/task.h"
-#    undef min
-#    undef max
-#  else
-#    undef HAVE_TBB
-#  endif
+#  include "tbb/tbb.h"
+#  include "tbb/task.h"
+#  undef min
+#  undef max
 #endif
 
 #if !defined(HAVE_CUDA) || !defined(HAVE_TBB) || defined(__arm__)
diff --git a/samples/gpu/generalized_hough.cpp b/samples/gpu/generalized_hough.cpp
index fb1cb89..7b7e80a 100644
--- a/samples/gpu/generalized_hough.cpp
+++ b/samples/gpu/generalized_hough.cpp
@@ -8,8 +8,6 @@
 #include "opencv2/cudaimgproc.hpp"
 #include "opencv2/highgui.hpp"
 
-#include "tick_meter.hpp"
-
 using namespace std;
 using namespace cv;
 
diff --git a/samples/gpu/multi.cpp b/samples/gpu/multi.cpp
index 85349eb..9c0e15f 100644
--- a/samples/gpu/multi.cpp
+++ b/samples/gpu/multi.cpp
@@ -8,19 +8,14 @@
 
 #include <iostream>
 #include "opencv2/cvconfig.h"
-#include "opencv2/core/core.hpp"
+#include "opencv2/core.hpp"
 #include "opencv2/cudaarithm.hpp"
 
 #ifdef HAVE_TBB
-#  include "tbb/tbb_stddef.h"
-#  if TBB_VERSION_MAJOR*100 + TBB_VERSION_MINOR >= 202
-#    include "tbb/tbb.h"
-#    include "tbb/task.h"
-#    undef min
-#    undef max
-#  else
-#    undef HAVE_TBB
-#  endif
+#  include "tbb/tbb.h"
+#  include "tbb/task.h"
+#  undef min
+#  undef max
 #endif
 
 #if !defined(HAVE_CUDA) || !defined(HAVE_TBB)
diff --git a/samples/gpu/opengl.cpp b/samples/gpu/opengl.cpp
index 061cc58..6bed4e3 100644
--- a/samples/gpu/opengl.cpp
+++ b/samples/gpu/opengl.cpp
@@ -17,10 +17,10 @@
     #include <GL/glu.h>
 #endif
 
-#include "opencv2/core/core.hpp"
+#include "opencv2/core.hpp"
 #include "opencv2/core/opengl.hpp"
 #include "opencv2/core/cuda.hpp"
-#include "opencv2/highgui/highgui.hpp"
+#include "opencv2/highgui.hpp"
 
 using namespace std;
 using namespace cv;
@@ -105,8 +105,8 @@ int main(int argc, char* argv[])
     for (;;)
     {
         updateWindow("OpenGL");
-        int key = waitKey(40);
-        if ((key & 0xff) == 27)
+        char key = (char)waitKey(40);
+        if (key == 27)
             break;
     }
 
diff --git a/samples/gpu/opticalflow_nvidia_api.cpp b/samples/gpu/opticalflow_nvidia_api.cpp
index 63eebfd..77f70ae 100644
--- a/samples/gpu/opticalflow_nvidia_api.cpp
+++ b/samples/gpu/opticalflow_nvidia_api.cpp
@@ -14,8 +14,7 @@
 #include <iomanip>
 #include "opencv2/core/cuda.hpp"
 #include "opencv2/cudalegacy.hpp"
-#include "opencv2/highgui/highgui.hpp"
-#include "opencv2/highgui/highgui_c.h"
+#include "opencv2/highgui.hpp"
 
 #if !defined(HAVE_CUDA)
 int main( int, const char** )
diff --git a/samples/gpu/performance/tests.cpp b/samples/gpu/performance/tests.cpp
index b4bf4cf..aad40bf 100644
--- a/samples/gpu/performance/tests.cpp
+++ b/samples/gpu/performance/tests.cpp
@@ -1191,10 +1191,10 @@ TEST(GoodFeaturesToTrack)
 
 TEST(MOG)
 {
-    const std::string inputFile = abspath("../data/768x576.avi");
+    const std::string inputFile = abspath("../data/vtest.avi");
 
     cv::VideoCapture cap(inputFile);
-    if (!cap.isOpened()) throw runtime_error("can't open ../data/768x576.avi");
+    if (!cap.isOpened()) throw runtime_error("can't open ../data/vtest.avi");
 
     cv::Mat frame;
     cap >> frame;
diff --git a/samples/gpu/stereo_multi.cpp b/samples/gpu/stereo_multi.cpp
index bfb3e8a..7ef6567 100644
--- a/samples/gpu/stereo_multi.cpp
+++ b/samples/gpu/stereo_multi.cpp
@@ -17,8 +17,6 @@
 #include "opencv2/imgproc.hpp"
 #include "opencv2/cudastereo.hpp"
 
-#include "tick_meter.hpp"
-
 using namespace std;
 using namespace cv;
 using namespace cv::cuda;
diff --git a/samples/gpu/super_resolution.cpp b/samples/gpu/super_resolution.cpp
index 026afd9..94a922c 100644
--- a/samples/gpu/super_resolution.cpp
+++ b/samples/gpu/super_resolution.cpp
@@ -11,8 +11,6 @@
 #include "opencv2/superres/optical_flow.hpp"
 #include "opencv2/opencv_modules.hpp"
 
-#include "tick_meter.hpp"
-
 using namespace std;
 using namespace cv;
 using namespace cv::superres;
diff --git a/samples/gpu/surf_keypoint_matcher.cpp b/samples/gpu/surf_keypoint_matcher.cpp
index 522c8a1..009568b 100644
--- a/samples/gpu/surf_keypoint_matcher.cpp
+++ b/samples/gpu/surf_keypoint_matcher.cpp
@@ -4,9 +4,9 @@
 
 #ifdef HAVE_OPENCV_XFEATURES2D
 
-#include "opencv2/core/core.hpp"
-#include "opencv2/features2d/features2d.hpp"
-#include "opencv2/highgui/highgui.hpp"
+#include "opencv2/core.hpp"
+#include "opencv2/features2d.hpp"
+#include "opencv2/highgui.hpp"
 #include "opencv2/cudafeatures2d.hpp"
 #include "opencv2/xfeatures2d/cuda.hpp"
 
diff --git a/samples/gpu/tick_meter.hpp b/samples/gpu/tick_meter.hpp
deleted file mode 100644
index c11a22d..0000000
--- a/samples/gpu/tick_meter.hpp
+++ /dev/null
@@ -1,48 +0,0 @@
-#ifndef OPENCV_CUDA_SAMPLES_TICKMETER_
-#define OPENCV_CUDA_SAMPLES_TICKMETER_
-
-class CV_EXPORTS TickMeter
-{
-public:
-    TickMeter();
-    void start();
-    void stop();
-
-    int64 getTimeTicks() const;
-    double getTimeMicro() const;
-    double getTimeMilli() const;
-    double getTimeSec()   const;
-    int64 getCounter() const;
-
-    void reset();
-private:
-    int64 counter;
-    int64 sumTime;
-    int64 startTime;
-};
-
-std::ostream& operator << (std::ostream& out, const TickMeter& tm);
-
-
-TickMeter::TickMeter() { reset(); }
-int64 TickMeter::getTimeTicks() const { return sumTime; }
-double TickMeter::getTimeMicro() const { return  getTimeMilli()*1e3;}
-double TickMeter::getTimeMilli() const { return getTimeSec()*1e3; }
-double TickMeter::getTimeSec() const { return (double)getTimeTicks()/cv::getTickFrequency();}
-int64 TickMeter::getCounter() const { return counter; }
-void TickMeter::reset() {startTime = 0; sumTime = 0; counter = 0; }
-
-void TickMeter::start(){ startTime = cv::getTickCount(); }
-void TickMeter::stop()
-{
-    int64 time = cv::getTickCount();
-    if ( startTime == 0 )
-        return;
-    ++counter;
-    sumTime += ( time - startTime );
-    startTime = 0;
-}
-
-std::ostream& operator << (std::ostream& out, const TickMeter& tm) { return out << tm.getTimeSec() << "sec"; }
-
-#endif
diff --git a/samples/gpu/video_reader.cpp b/samples/gpu/video_reader.cpp
index d8d6e13..c4c1928 100644
--- a/samples/gpu/video_reader.cpp
+++ b/samples/gpu/video_reader.cpp
@@ -14,8 +14,6 @@
 #include <opencv2/cudacodec.hpp>
 #include <opencv2/highgui.hpp>
 
-#include "tick_meter.hpp"
-
 int main(int argc, const char* argv[])
 {
     if (argc != 2)
@@ -33,7 +31,7 @@ int main(int argc, const char* argv[])
     cv::cuda::GpuMat d_frame;
     cv::Ptr<cv::cudacodec::VideoReader> d_reader = cv::cudacodec::createVideoReader(fname);
 
-    TickMeter tm;
+    cv::TickMeter tm;
     std::vector<double> cpu_times;
     std::vector<double> gpu_times;
 
diff --git a/samples/gpu/video_writer.cpp b/samples/gpu/video_writer.cpp
index 6c5d141..6b9cca3 100644
--- a/samples/gpu/video_writer.cpp
+++ b/samples/gpu/video_writer.cpp
@@ -11,8 +11,7 @@
 #include "opencv2/cudacodec.hpp"
 #include "opencv2/highgui.hpp"
 
-#include "tick_meter.hpp"
-
+using namespace cv;
 int main(int argc, const char* argv[])
 {
     if (argc != 2)
diff --git a/samples/hal/README.md b/samples/hal/README.md
index c48eda4..8e05283 100644
--- a/samples/hal/README.md
+++ b/samples/hal/README.md
@@ -23,8 +23,7 @@ Build OpenCV with HAL replacement
 2. Go to the created folder and run cmake:
     ```
     cmake \
-        -DOPENCV_HAL_HEADERS="<opencv-src>/samples/hal/slow_hal/impl.hpp" \
-        -DOPENCV_HAL_LIBS="<home-dir>/my-hal-build/libslow_hal.a" \
+        -DOpenCV_HAL_DIR="<home-dir>/my-hal-build/" \
         <opencv-src>
     ```
 3. Run make (or `make opencv_perf_core` to build the demonstration test executable only)
diff --git a/samples/hal/c_hal/CMakeLists.txt b/samples/hal/c_hal/CMakeLists.txt
index 51ebcee..8502779 100644
--- a/samples/hal/c_hal/CMakeLists.txt
+++ b/samples/hal/c_hal/CMakeLists.txt
@@ -1,11 +1,18 @@
 cmake_minimum_required(VERSION 2.8.8 FATAL_ERROR)
 
-if(UNIX)
-  if(CMAKE_COMPILER_IS_GNUC OR CV_ICC)
-    set(CMAKE_C_FLAGS "${CMAKE_CXX_FLAGS} -fPIC")
-  endif()
-endif()
+set(PROJECT_NAME "c_hal")
+set(HAL_LIB_NAME "c_hal")
 
-add_library(c_hal impl.c)
+add_library(${HAL_LIB_NAME} impl.c)
+set_target_properties(${HAL_LIB_NAME} PROPERTIES POSITION_INDEPENDENT_CODE TRUE)
 set(OPENCV_SRC_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../..")
-target_include_directories(c_hal PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} ${OPENCV_SRC_DIR}/modules/core/include)
+target_include_directories(${HAL_LIB_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} ${OPENCV_SRC_DIR}/modules/core/include)
+
+set(OpenCV_HAL_FOUND TRUE)
+set(OpenCV_HAL_VERSION 0.0.1)
+set(OpenCV_HAL_LIBRARIES ${CMAKE_CURRENT_BINARY_DIR}/lib${HAL_LIB_NAME}.a)
+set(OpenCV_HAL_HEADERS "impl.h")
+set(OpenCV_HAL_INCLUDE_DIRS ${CMAKE_CURRENT_LIST_DIR})
+
+configure_file("impl.h" "${CMAKE_BINARY_DIR}/impl.h" COPYONLY)
+configure_file("config.cmake" "${CMAKE_BINARY_DIR}/OpenCV_HALConfig.cmake")
diff --git a/samples/hal/c_hal/config.cmake b/samples/hal/c_hal/config.cmake
new file mode 100644
index 0000000..d57b7ef
--- /dev/null
+++ b/samples/hal/c_hal/config.cmake
@@ -0,0 +1,5 @@
+set(OpenCV_HAL_FOUND @OpenCV_HAL_FOUND@)
+set(OpenCV_HAL_VERSION @OpenCV_HAL_VERSION@)
+set(OpenCV_HAL_LIBRARIES @OpenCV_HAL_LIBRARIES@)
+set(OpenCV_HAL_HEADERS @OpenCV_HAL_HEADERS@)
+set(OpenCV_HAL_INCLUDE_DIRS @OpenCV_HAL_INCLUDE_DIRS@)
diff --git a/samples/hal/c_hal/impl.c b/samples/hal/c_hal/impl.c
index d2fcc5a..7bf34ae 100644
--- a/samples/hal/c_hal/impl.c
+++ b/samples/hal/c_hal/impl.c
@@ -300,37 +300,37 @@ int wrong_div64f(const double* src1, size_t sz1, const double* src2, size_t sz2,
     return CV_HAL_ERROR_UNKNOWN; // to test how OpenCV handles errors from external HAL
 }
 
-int wrong_recip8u(const uchar* src1, size_t sz1, const uchar* src2, size_t sz2, uchar* dst, size_t sz, int w, int h, double scale)
+int wrong_recip8u(const uchar* src2, size_t sz2, uchar* dst, size_t sz, int w, int h, double scale)
 {
     return CV_HAL_ERROR_UNKNOWN; // to test how OpenCV handles errors from external HAL
 }
 
-int wrong_recip8s(const schar* src1, size_t sz1, const schar* src2, size_t sz2, schar* dst, size_t sz, int w, int h, double scale)
+int wrong_recip8s(const schar* src2, size_t sz2, schar* dst, size_t sz, int w, int h, double scale)
 {
     return CV_HAL_ERROR_UNKNOWN; // to test how OpenCV handles errors from external HAL
 }
 
-int wrong_recip16u(const ushort* src1, size_t sz1, const ushort* src2, size_t sz2, ushort* dst, size_t sz, int w, int h, double scale)
+int wrong_recip16u(const ushort* src2, size_t sz2, ushort* dst, size_t sz, int w, int h, double scale)
 {
     return CV_HAL_ERROR_UNKNOWN; // to test how OpenCV handles errors from external HAL
 }
 
-int wrong_recip16s(const short* src1, size_t sz1, const short* src2, size_t sz2, short* dst, size_t sz, int w, int h, double scale)
+int wrong_recip16s(const short* src2, size_t sz2, short* dst, size_t sz, int w, int h, double scale)
 {
     return CV_HAL_ERROR_UNKNOWN; // to test how OpenCV handles errors from external HAL
 }
 
-int wrong_recip32s(const int* src1, size_t sz1, const int* src2, size_t sz2, int* dst, size_t sz, int w, int h, double scale)
+int wrong_recip32s(const int* src2, size_t sz2, int* dst, size_t sz, int w, int h, double scale)
 {
     return CV_HAL_ERROR_UNKNOWN; // to test how OpenCV handles errors from external HAL
 }
 
-int wrong_recip32f(const float* src1, size_t sz1, const float* src2, size_t sz2, float* dst, size_t sz, int w, int h, double scale)
+int wrong_recip32f(const float* src2, size_t sz2, float* dst, size_t sz, int w, int h, double scale)
 {
     return CV_HAL_ERROR_UNKNOWN; // to test how OpenCV handles errors from external HAL
 }
 
-int wrong_recip64f(const double* src1, size_t sz1, const double* src2, size_t sz2, double* dst, size_t sz, int w, int h, double scale)
+int wrong_recip64f(const double* src2, size_t sz2, double* dst, size_t sz, int w, int h, double scale)
 {
     return CV_HAL_ERROR_UNKNOWN; // to test how OpenCV handles errors from external HAL
 }
diff --git a/samples/hal/c_hal/impl.h b/samples/hal/c_hal/impl.h
index 9fc4f19..91d7e82 100644
--- a/samples/hal/c_hal/impl.h
+++ b/samples/hal/c_hal/impl.h
@@ -164,13 +164,13 @@ int wrong_div16s(const short* src1, size_t sz1, const short* src2, size_t sz2, s
 int wrong_div32s(const int* src1, size_t sz1, const int* src2, size_t sz2, int* dst, size_t sz, int w, int h, double scale);
 int wrong_div32f(const float* src1, size_t sz1, const float* src2, size_t sz2, float* dst, size_t sz, int w, int h, double scale);
 int wrong_div64f(const double* src1, size_t sz1, const double* src2, size_t sz2, double* dst, size_t sz, int w, int h, double scale);
-int wrong_recip8u(const uchar* src1, size_t sz1, const uchar* src2, size_t sz2, uchar* dst, size_t sz, int w, int h, double scale);
-int wrong_recip8s(const schar* src1, size_t sz1, const schar* src2, size_t sz2, schar* dst, size_t sz, int w, int h, double scale);
-int wrong_recip16u(const ushort* src1, size_t sz1, const ushort* src2, size_t sz2, ushort* dst, size_t sz, int w, int h, double scale);
-int wrong_recip16s(const short* src1, size_t sz1, const short* src2, size_t sz2, short* dst, size_t sz, int w, int h, double scale);
-int wrong_recip32s(const int* src1, size_t sz1, const int* src2, size_t sz2, int* dst, size_t sz, int w, int h, double scale);
-int wrong_recip32f(const float* src1, size_t sz1, const float* src2, size_t sz2, float* dst, size_t sz, int w, int h, double scale);
-int wrong_recip64f(const double* src1, size_t sz1, const double* src2, size_t sz2, double* dst, size_t sz, int w, int h, double scale);
+int wrong_recip8u(const uchar* src2, size_t sz2, uchar* dst, size_t sz, int w, int h, double scale);
+int wrong_recip8s(const schar* src2, size_t sz2, schar* dst, size_t sz, int w, int h, double scale);
+int wrong_recip16u(const ushort* src2, size_t sz2, ushort* dst, size_t sz, int w, int h, double scale);
+int wrong_recip16s(const short* src2, size_t sz2, short* dst, size_t sz, int w, int h, double scale);
+int wrong_recip32s(const int* src2, size_t sz2, int* dst, size_t sz, int w, int h, double scale);
+int wrong_recip32f(const float* src2, size_t sz2, float* dst, size_t sz, int w, int h, double scale);
+int wrong_recip64f(const double* src2, size_t sz2, double* dst, size_t sz, int w, int h, double scale);
 
 #undef cv_hal_mul8u
 #define cv_hal_mul8u wrong_mul8u
diff --git a/samples/hal/slow_hal/CMakeLists.txt b/samples/hal/slow_hal/CMakeLists.txt
index d001c42..d42fb0b 100644
--- a/samples/hal/slow_hal/CMakeLists.txt
+++ b/samples/hal/slow_hal/CMakeLists.txt
@@ -1,11 +1,18 @@
 cmake_minimum_required(VERSION 2.8.8 FATAL_ERROR)
 
-if(UNIX)
-  if(CMAKE_COMPILER_IS_GNUCXX OR CV_ICC)
-    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC")
-  endif()
-endif()
+set(PROJECT_NAME "slow_hal")
+set(HAL_LIB_NAME "slow_hal")
 
-add_library(slow_hal impl.cpp)
+add_library(${HAL_LIB_NAME} impl.cpp)
+set_target_properties(${HAL_LIB_NAME} PROPERTIES POSITION_INDEPENDENT_CODE TRUE)
 set(OPENCV_SRC_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../..")
-target_include_directories(slow_hal PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} ${OPENCV_SRC_DIR}/modules/core/include)
+target_include_directories(${HAL_LIB_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} ${OPENCV_SRC_DIR}/modules/core/include)
+
+set(OpenCV_HAL_FOUND TRUE)
+set(OpenCV_HAL_VERSION 0.0.1)
+set(OpenCV_HAL_LIBRARIES ${CMAKE_CURRENT_BINARY_DIR}/lib${HAL_LIB_NAME}.a)
+set(OpenCV_HAL_HEADERS "impl.hpp")
+set(OpenCV_HAL_INCLUDE_DIRS ${CMAKE_CURRENT_LIST_DIR})
+
+configure_file("impl.hpp" "${CMAKE_BINARY_DIR}/impl.hpp" COPYONLY)
+configure_file("config.cmake" "${CMAKE_BINARY_DIR}/OpenCV_HALConfig.cmake")
diff --git a/samples/hal/slow_hal/config.cmake b/samples/hal/slow_hal/config.cmake
new file mode 100644
index 0000000..d57b7ef
--- /dev/null
+++ b/samples/hal/slow_hal/config.cmake
@@ -0,0 +1,5 @@
+set(OpenCV_HAL_FOUND @OpenCV_HAL_FOUND@)
+set(OpenCV_HAL_VERSION @OpenCV_HAL_VERSION@)
+set(OpenCV_HAL_LIBRARIES @OpenCV_HAL_LIBRARIES@)
+set(OpenCV_HAL_HEADERS @OpenCV_HAL_HEADERS@)
+set(OpenCV_HAL_INCLUDE_DIRS @OpenCV_HAL_INCLUDE_DIRS@)
diff --git a/samples/java/tutorial_code/core/mat_mask_operations/MatMaskOperations.java b/samples/java/tutorial_code/core/mat_mask_operations/MatMaskOperations.java
new file mode 100644
index 0000000..804968e
--- /dev/null
+++ b/samples/java/tutorial_code/core/mat_mask_operations/MatMaskOperations.java
@@ -0,0 +1,139 @@
+import org.opencv.core.*;
+import org.opencv.imgcodecs.Imgcodecs;
+import org.opencv.imgproc.Imgproc;
+
+import javax.swing.*;
+import java.awt.Image;
+import java.awt.image.BufferedImage;
+import java.awt.image.DataBufferByte;
+
+class MatMaskOperationsRun {
+
+    public void run() {
+
+    //! [laod_image]
+        Mat I = Imgcodecs.imread("../data/lena.jpg");
+        if(I.empty())
+            System.out.println("Error opening image");
+    //! [laod_image]
+
+        Image img = toBufferedImage( I );
+        displayImage("Input Image" , img, 0, 200 );
+
+        double t = System.currentTimeMillis();
+
+        Mat J = sharpen(I, new Mat());
+
+        t = ((double)System.currentTimeMillis() - t)/1000;
+        System.out.println("Hand written function times passed in seconds: " + t);
+
+        Image img2 = toBufferedImage( J );
+        displayImage("Output Image" , img2, 400, 400 );
+
+        Mat K = new Mat();
+    //![kern]
+        Mat kern = new Mat( 3, 3, CvType.CV_8S );
+        int row = 0, col = 0;
+        kern.put(row ,col, 0, -1, 0, -1, 5, -1, 0, -1, 0 );
+    //![kern]
+
+        System.out.println("kern = \n" + kern.dump());
+
+        t = System.currentTimeMillis();
+
+    //![filter2D]
+        Imgproc.filter2D(I, K, I.depth(), kern );
+    //![filter2D]
+
+        t = ((double)System.currentTimeMillis() - t)/1000;
+        System.out.println("Built-in filter2D time passed in seconds:      " + t);
+
+        Image img3 = toBufferedImage( J );
+        displayImage("filter2D Output Image" , img3, 800, 400 );
+    }
+
+    //! [basic_method]
+    public static double saturateCastUchar(double x) {
+        return x > 255.0 ? 255.0 : (x < 0.0 ? 0.0 : x);
+    }
+
+    public Mat sharpen(Mat myImage, Mat Result)
+    {
+      //! [8_bit]
+        myImage.convertTo(myImage, CvType.CV_8U);
+      //! [8_bit]
+
+      //! [create_channels]
+        int nChannels = myImage.channels();
+        Result.create(myImage.size(),myImage.type());
+      //! [create_channels]
+
+      //! [basic_method_loop]
+        for(int j = 1 ; j < myImage.rows()-1; ++j)
+        {
+            for(int i = 1 ; i < myImage.cols()-1; ++i)
+            {
+                double sum[] = new double[nChannels];
+
+                for(int k = 0; k < nChannels; ++k) {
+
+                    double top = -myImage.get(j - 1, i)[k];
+                    double bottom = -myImage.get(j + 1, i)[k];
+                    double center = (5 * myImage.get(j, i)[k]);
+                    double left = -myImage.get(j , i - 1)[k];
+                    double right = -myImage.get(j , i + 1)[k];
+
+                    sum[k] = saturateCastUchar(top + bottom + center + left + right);
+                }
+
+                Result.put(j, i, sum);
+            }
+        }
+      //! [basic_method_loop]
+
+      //! [borders]
+        Result.row(0).setTo(new Scalar(0));
+        Result.row(Result.rows()-1).setTo(new Scalar(0));
+        Result.col(0).setTo(new Scalar(0));
+        Result.col(Result.cols()-1).setTo(new Scalar(0));
+      //! [borders]
+
+        return Result;
+    }
+    //! [basic_method]
+
+    public Image toBufferedImage(Mat m) {
+        int type = BufferedImage.TYPE_BYTE_GRAY;
+        if ( m.channels() > 1 ) {
+            type = BufferedImage.TYPE_3BYTE_BGR;
+        }
+        int bufferSize = m.channels()*m.cols()*m.rows();
+        byte [] b = new byte[bufferSize];
+        m.get(0,0,b); // get all the pixels
+        BufferedImage image = new BufferedImage(m.cols(),m.rows(), type);
+        final byte[] targetPixels = ((DataBufferByte) image.getRaster().getDataBuffer()).getData();
+        System.arraycopy(b, 0, targetPixels, 0, b.length);
+        return image;
+    }
+
+    public void displayImage(String title, Image img, int x, int y)
+    {
+        ImageIcon icon=new ImageIcon(img);
+        JFrame frame=new JFrame(title);
+        JLabel lbl=new JLabel(icon);
+        frame.add(lbl);
+        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+        frame.pack();
+        frame.setLocation(x, y);
+        frame.setVisible(true);
+    }
+}
+
+public class MatMaskOperations {
+    public static void main(String[] args) {
+
+        // Load the native library.
+        System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
+        new MatMaskOperationsRun().run();
+    }
+}
diff --git a/samples/java/tutorial_code/introduction/documentation/Documentation.java b/samples/java/tutorial_code/introduction/documentation/Documentation.java
new file mode 100644
index 0000000..f3f90a1
--- /dev/null
+++ b/samples/java/tutorial_code/introduction/documentation/Documentation.java
@@ -0,0 +1,9 @@
+public class Documentation {
+
+    public static void main (String[] args) {
+
+        //! [hello_world]
+        System.out.println ("Hello World!");
+        //! [hello_world]
+    }
+}
diff --git a/samples/openvx/CMakeLists.txt b/samples/openvx/CMakeLists.txt
new file mode 100644
index 0000000..f2a5680
--- /dev/null
+++ b/samples/openvx/CMakeLists.txt
@@ -0,0 +1,37 @@
+cmake_minimum_required(VERSION 2.8.9)
+
+set(OPENCV_OPENVX_SAMPLE_REQUIRED_DEPS opencv_core opencv_imgproc opencv_imgcodecs opencv_videoio opencv_highgui)
+
+ocv_check_dependencies(${OPENCV_OPENVX_SAMPLE_REQUIRED_DEPS})
+
+if(BUILD_EXAMPLES AND OCV_DEPENDENCIES_FOUND)
+  set(group "openvx")
+  set(name_wrapped "interop")
+  set(name_orig "interop_orig")
+  set(name_video "interop_video")
+
+  project("${group}_sample")
+
+  ocv_include_modules_recurse(${OPENCV_OPENVX_SAMPLE_REQUIRED_DEPS})
+
+  add_definitions(-DIVX_USE_OPENCV)
+  add_definitions(-DIVX_HIDE_INFO_WARNINGS)
+
+  file(GLOB srcs_wrapped wrappers.cpp *.hpp)
+  file(GLOB srcs_orig  no_wrappers.cpp *.hpp)
+  file(GLOB srcs_video wrappers_video.cpp *.hpp)
+
+  MACRO(OPENVX_DEFINE_SAMPLE name srcs)
+    set(target "example_${group}_${name}")
+	add_executable(${target} ${srcs})
+    ocv_target_link_libraries(${target} ${OPENCV_LINKER_LIBS} ${OPENCV_OPENVX_SAMPLE_REQUIRED_DEPS} ${OPENVX_LIBRARIES})
+    if(ENABLE_SOLUTION_FOLDERS)
+        set_target_properties(${target} PROPERTIES FOLDER "samples//${group}")
+    endif()
+  ENDMACRO()
+
+  OPENVX_DEFINE_SAMPLE(${name_wrapped} ${srcs_wrapped})
+  OPENVX_DEFINE_SAMPLE(${name_orig} ${srcs_orig})
+  OPENVX_DEFINE_SAMPLE(${name_video} ${srcs_video})
+
+endif()
diff --git a/samples/openvx/no_wrappers.cpp b/samples/openvx/no_wrappers.cpp
new file mode 100644
index 0000000..7809f7b
--- /dev/null
+++ b/samples/openvx/no_wrappers.cpp
@@ -0,0 +1,385 @@
+#include <iostream>
+#include <stdexcept>
+
+//OpenVX includes
+#include <VX/vx.h>
+
+//OpenCV includes
+#include "opencv2/core.hpp"
+#include "opencv2/imgproc.hpp"
+#include "opencv2/imgcodecs.hpp"
+#include "opencv2/highgui.hpp"
+
+#ifndef VX_VERSION_1_1
+const vx_enum VX_IMAGE_FORMAT = VX_IMAGE_ATTRIBUTE_FORMAT;
+const vx_enum VX_IMAGE_WIDTH  = VX_IMAGE_ATTRIBUTE_WIDTH;
+const vx_enum VX_IMAGE_HEIGHT = VX_IMAGE_ATTRIBUTE_HEIGHT;
+const vx_enum VX_MEMORY_TYPE_HOST = VX_IMPORT_TYPE_HOST;
+const vx_enum VX_MEMORY_TYPE_NONE = VX_IMPORT_TYPE_NONE;
+const vx_enum VX_THRESHOLD_THRESHOLD_VALUE = VX_THRESHOLD_ATTRIBUTE_THRESHOLD_VALUE;
+const vx_enum VX_THRESHOLD_THRESHOLD_LOWER = VX_THRESHOLD_ATTRIBUTE_THRESHOLD_LOWER;
+const vx_enum VX_THRESHOLD_THRESHOLD_UPPER = VX_THRESHOLD_ATTRIBUTE_THRESHOLD_UPPER;
+typedef uintptr_t vx_map_id;
+#endif
+
+enum UserMemoryMode
+{
+    COPY, USER_MEM
+};
+
+vx_image convertCvMatToVxImage(vx_context context, cv::Mat image, bool toCopy);
+cv::Mat copyVxImageToCvMat(vx_image ovxImage);
+void swapVxImage(vx_image ovxImage);
+vx_status createProcessingGraph(vx_image inputImage, vx_image outputImage, vx_graph& graph);
+int ovxDemo(std::string inputPath, UserMemoryMode mode);
+
+
+vx_image convertCvMatToVxImage(vx_context context, cv::Mat image, bool toCopy)
+{
+    if (!(!image.empty() && image.dims <= 2 && image.channels() == 1))
+        throw std::runtime_error("Invalid format");
+
+    vx_uint32 width  = image.cols;
+    vx_uint32 height = image.rows;
+
+    vx_df_image color;
+    switch (image.depth())
+    {
+    case CV_8U:
+        color = VX_DF_IMAGE_U8;
+        break;
+    case CV_16U:
+        color = VX_DF_IMAGE_U16;
+        break;
+    case CV_16S:
+        color = VX_DF_IMAGE_S16;
+        break;
+    case CV_32S:
+        color = VX_DF_IMAGE_S32;
+        break;
+    default:
+        throw std::runtime_error("Invalid format");
+        break;
+    }
+
+    vx_imagepatch_addressing_t addr;
+    addr.dim_x = width;
+    addr.dim_y = height;
+    addr.stride_x = (vx_uint32)image.elemSize();
+    addr.stride_y = (vx_uint32)image.step.p[0];
+    vx_uint8* ovxData = image.data;
+
+    vx_image ovxImage;
+    if (toCopy)
+    {
+        ovxImage = vxCreateImage(context, width, height, color);
+        if (vxGetStatus((vx_reference)ovxImage) != VX_SUCCESS)
+            throw std::runtime_error("Failed to create image");
+        vx_rectangle_t rect;
+
+        vx_status status = vxGetValidRegionImage(ovxImage, &rect);
+        if (status != VX_SUCCESS)
+            throw std::runtime_error("Failed to get valid region");
+
+#ifdef VX_VERSION_1_1
+        status = vxCopyImagePatch(ovxImage, &rect, 0, &addr, ovxData, VX_WRITE_ONLY, VX_MEMORY_TYPE_HOST);
+        if (status != VX_SUCCESS)
+            throw std::runtime_error("Failed to copy image patch");
+#else
+        status = vxAccessImagePatch(ovxImage, &rect, 0, &addr, (void**)&ovxData, VX_WRITE_ONLY);
+        if (status != VX_SUCCESS)
+            throw std::runtime_error("Failed to access image patch");
+        status = vxCommitImagePatch(ovxImage, &rect, 0, &addr, ovxData);
+        if (status != VX_SUCCESS)
+            throw std::runtime_error("Failed to commit image patch");
+#endif
+    }
+    else
+    {
+        ovxImage = vxCreateImageFromHandle(context, color, &addr, (void**)&ovxData, VX_MEMORY_TYPE_HOST);
+        if (vxGetStatus((vx_reference)ovxImage) != VX_SUCCESS)
+            throw std::runtime_error("Failed to create image from handle");
+    }
+
+    return ovxImage;
+}
+
+
+cv::Mat copyVxImageToCvMat(vx_image ovxImage)
+{
+    vx_status status;
+    vx_df_image df_image = 0;
+    vx_uint32 width, height;
+    status = vxQueryImage(ovxImage, VX_IMAGE_FORMAT, &df_image, sizeof(vx_df_image));
+    if (status != VX_SUCCESS)
+        throw std::runtime_error("Failed to query image");
+    status = vxQueryImage(ovxImage, VX_IMAGE_WIDTH, &width, sizeof(vx_uint32));
+    if (status != VX_SUCCESS)
+        throw std::runtime_error("Failed to query image");
+    status = vxQueryImage(ovxImage, VX_IMAGE_HEIGHT, &height, sizeof(vx_uint32));
+    if (status != VX_SUCCESS)
+        throw std::runtime_error("Failed to query image");
+
+    if (!(width > 0 && height > 0)) throw std::runtime_error("Invalid format");
+
+    int depth;
+    switch (df_image)
+    {
+    case VX_DF_IMAGE_U8:
+        depth = CV_8U;
+        break;
+    case VX_DF_IMAGE_U16:
+        depth = CV_16U;
+        break;
+    case VX_DF_IMAGE_S16:
+        depth = CV_16S;
+        break;
+    case VX_DF_IMAGE_S32:
+        depth = CV_32S;
+        break;
+    default:
+        throw std::runtime_error("Invalid format");
+        break;
+    }
+
+    cv::Mat image(height, width, CV_MAKE_TYPE(depth, 1));
+
+    vx_rectangle_t rect;
+    rect.start_x = rect.start_y = 0;
+    rect.end_x = width; rect.end_y = height;
+
+    vx_imagepatch_addressing_t addr;
+    addr.dim_x = width;
+    addr.dim_y = height;
+    addr.stride_x = (vx_uint32)image.elemSize();
+    addr.stride_y = (vx_uint32)image.step.p[0];
+    vx_uint8* matData = image.data;
+
+#ifdef VX_VERSION_1_1
+    status = vxCopyImagePatch(ovxImage, &rect, 0, &addr, matData, VX_READ_ONLY, VX_MEMORY_TYPE_HOST);
+    if (status != VX_SUCCESS)
+        throw std::runtime_error("Failed to copy image patch");
+#else
+    status = vxAccessImagePatch(ovxImage, &rect, 0, &addr, (void**)&matData, VX_READ_ONLY);
+    if (status != VX_SUCCESS)
+        throw std::runtime_error("Failed to access image patch");
+    status = vxCommitImagePatch(ovxImage, &rect, 0, &addr, matData);
+    if (status != VX_SUCCESS)
+        throw std::runtime_error("Failed to commit image patch");
+#endif
+
+    return image;
+}
+
+
+void swapVxImage(vx_image ovxImage)
+{
+#ifdef VX_VERSION_1_1
+    vx_status status;
+    vx_memory_type_e memType;
+    status = vxQueryImage(ovxImage, VX_IMAGE_MEMORY_TYPE, &memType, sizeof(vx_memory_type_e));
+    if (status != VX_SUCCESS)
+        throw std::runtime_error("Failed to query image");
+    if (memType == VX_MEMORY_TYPE_NONE)
+    {
+        //was created by copying user data
+        throw std::runtime_error("Image wasn't created from user handle");
+    }
+    else
+    {
+        //was created from user handle
+        status = vxSwapImageHandle(ovxImage, NULL, NULL, 0);
+        if (status != VX_SUCCESS)
+            throw std::runtime_error("Failed to swap image handle");
+    }
+#else
+    //not supported until OpenVX 1.1
+    (void) ovxImage;
+#endif
+}
+
+
+vx_status createProcessingGraph(vx_image inputImage, vx_image outputImage, vx_graph& graph)
+{
+    vx_status status;
+    vx_context context = vxGetContext((vx_reference)inputImage);
+    status = vxGetStatus((vx_reference)context);
+    if(status != VX_SUCCESS) return status;
+
+    graph = vxCreateGraph(context);
+    status = vxGetStatus((vx_reference)graph);
+    if (status != VX_SUCCESS) return status;
+
+    vx_uint32 width, height;
+    status = vxQueryImage(inputImage, VX_IMAGE_WIDTH, &width, sizeof(vx_uint32));
+    if (status != VX_SUCCESS) return status;
+    status = vxQueryImage(inputImage, VX_IMAGE_HEIGHT, &height, sizeof(vx_uint32));
+    if (status != VX_SUCCESS) return status;
+
+    // Intermediate images
+    vx_image
+        smoothed  = vxCreateVirtualImage(graph, 0, 0, VX_DF_IMAGE_VIRT),
+        cannied   = vxCreateVirtualImage(graph, 0, 0, VX_DF_IMAGE_VIRT),
+        halfImg   = vxCreateImage(context, width, height, VX_DF_IMAGE_U8),
+        halfCanny = vxCreateImage(context, width, height, VX_DF_IMAGE_U8);
+
+    vx_image virtualImages[] = {smoothed, cannied, halfImg, halfCanny};
+    for(size_t i = 0; i < sizeof(virtualImages)/sizeof(vx_image); i++)
+    {
+        status = vxGetStatus((vx_reference)virtualImages[i]);
+        if (status != VX_SUCCESS) return status;
+    }
+
+    // Constants
+    vx_uint32 threshValue = 50;
+    vx_threshold thresh = vxCreateThreshold(context, VX_THRESHOLD_TYPE_BINARY, VX_TYPE_UINT8);
+    vxSetThresholdAttribute(thresh, VX_THRESHOLD_THRESHOLD_VALUE,
+                            &threshValue, sizeof(threshValue));
+
+    vx_uint32 threshCannyMin = 127;
+    vx_uint32 threshCannyMax = 192;
+    vx_threshold threshCanny = vxCreateThreshold(context, VX_THRESHOLD_TYPE_RANGE, VX_TYPE_UINT8);
+    vxSetThresholdAttribute(threshCanny, VX_THRESHOLD_THRESHOLD_LOWER, &threshCannyMin,
+                            sizeof(threshCannyMin));
+    vxSetThresholdAttribute(threshCanny, VX_THRESHOLD_THRESHOLD_UPPER, &threshCannyMax,
+                            sizeof(threshCannyMax));
+    vx_float32 alphaValue = 0.5;
+    vx_scalar alpha = vxCreateScalar(context, VX_TYPE_FLOAT32, &alphaValue);
+
+    // Sequence of meaningless image operations
+    vx_node nodes[] = {
+        vxGaussian3x3Node(graph, inputImage, smoothed),
+        vxCannyEdgeDetectorNode(graph, smoothed, threshCanny, 3, VX_NORM_L2, cannied),
+        vxAccumulateWeightedImageNode(graph, inputImage, alpha, halfImg),
+        vxAccumulateWeightedImageNode(graph, cannied, alpha, halfCanny),
+        vxAddNode(graph, halfImg, halfCanny, VX_CONVERT_POLICY_SATURATE, outputImage)
+    };
+
+    for (size_t i = 0; i < sizeof(nodes) / sizeof(vx_node); i++)
+    {
+        status = vxGetStatus((vx_reference)nodes[i]);
+        if (status != VX_SUCCESS) return status;
+    }
+
+    status = vxVerifyGraph(graph);
+    return status;
+}
+
+
+int ovxDemo(std::string inputPath, UserMemoryMode mode)
+{
+    cv::Mat image = cv::imread(inputPath, cv::IMREAD_GRAYSCALE);
+    if (image.empty()) return -1;
+
+    //check image format
+    if (image.depth() != CV_8U || image.channels() != 1) return -1;
+
+    vx_status status;
+    vx_context context = vxCreateContext();
+    status = vxGetStatus((vx_reference)context);
+    if (status != VX_SUCCESS) return status;
+
+    //put user data from cv::Mat to vx_image
+    vx_image ovxImage;
+    ovxImage = convertCvMatToVxImage(context, image, mode == COPY);
+
+    vx_uint32 width = image.cols, height = image.rows;
+
+    vx_image ovxResult;
+    cv::Mat output;
+    if (mode == COPY)
+    {
+        //we will copy data from vx_image to cv::Mat
+        ovxResult = vxCreateImage(context, width, height, VX_DF_IMAGE_U8);
+        if (vxGetStatus((vx_reference)ovxResult) != VX_SUCCESS)
+            throw std::runtime_error("Failed to create image");
+    }
+    else
+    {
+        //create vx_image based on user data, no copying required
+        output = cv::Mat(height, width, CV_8U, cv::Scalar(0));
+        ovxResult = convertCvMatToVxImage(context, output, false);
+    }
+
+    vx_graph graph;
+    status = createProcessingGraph(ovxImage, ovxResult, graph);
+    if (status != VX_SUCCESS) return status;
+
+    // Graph execution
+    status = vxProcessGraph(graph);
+    if (status != VX_SUCCESS) return status;
+
+    //getting resulting image in cv::Mat
+    if (mode == COPY)
+    {
+        output = copyVxImageToCvMat(ovxResult);
+    }
+    else
+    {
+        //we should take user memory back from vx_image before using it (even before reading)
+        swapVxImage(ovxResult);
+    }
+
+    //here output goes
+    cv::imshow("processing result", output);
+    cv::waitKey(0);
+
+    //we need to take user memory back before releasing the image
+    if (mode == USER_MEM)
+        swapVxImage(ovxImage);
+
+    cv::destroyAllWindows();
+
+    status = vxReleaseContext(&context);
+    return status;
+}
+
+
+int main(int argc, char *argv[])
+{
+    const std::string keys =
+        "{help h usage ? | | }"
+        "{image    | <none> | image to be processed}"
+        "{mode | copy | user memory interaction mode: \n"
+        "copy: create VX images and copy data to/from them\n"
+        "user_mem: use handles to user-allocated memory}"
+        ;
+
+    cv::CommandLineParser parser(argc, argv, keys);
+    parser.about("OpenVX interoperability sample demonstrating standard OpenVX API."
+                 "The application loads an image, processes it with OpenVX graph and outputs result in a window");
+    if (parser.has("help"))
+    {
+        parser.printMessage();
+        return 0;
+    }
+    std::string imgPath = parser.get<std::string>("image");
+    std::string modeString = parser.get<std::string>("mode");
+    UserMemoryMode mode;
+    if(modeString == "copy")
+    {
+        mode = COPY;
+    }
+    else if(modeString == "user_mem")
+    {
+        mode = USER_MEM;
+    }
+    else if(modeString == "map")
+    {
+        std::cerr << modeString << " is not implemented in this sample" << std::endl;
+        return -1;
+    }
+    else
+    {
+        std::cerr << modeString << ": unknown memory mode" << std::endl;
+        return -1;
+    }
+
+    if (!parser.check())
+    {
+        parser.printErrors();
+        return -1;
+    }
+
+    return ovxDemo(imgPath, mode);
+}
diff --git a/samples/openvx/wrappers.cpp b/samples/openvx/wrappers.cpp
new file mode 100644
index 0000000..b591862
--- /dev/null
+++ b/samples/openvx/wrappers.cpp
@@ -0,0 +1,214 @@
+#include <iostream>
+#include <stdexcept>
+
+//wrappers
+#include "ivx.hpp"
+
+//OpenCV includes
+#include "opencv2/core.hpp"
+#include "opencv2/imgproc.hpp"
+#include "opencv2/imgcodecs.hpp"
+#include "opencv2/highgui.hpp"
+
+enum UserMemoryMode
+{
+    COPY, USER_MEM, MAP
+};
+
+ivx::Graph createProcessingGraph(ivx::Image& inputImage, ivx::Image& outputImage);
+int ovxDemo(std::string inputPath, UserMemoryMode mode);
+
+
+ivx::Graph createProcessingGraph(ivx::Image& inputImage, ivx::Image& outputImage)
+{
+    using namespace ivx;
+
+    Context context = inputImage.get<Context>();
+    Graph graph = Graph::create(context);
+
+    vx_uint32 width  = inputImage.width();
+    vx_uint32 height = inputImage.height();
+
+    // Intermediate images
+    Image
+        smoothed  = Image::createVirtual(graph),
+        cannied   = Image::createVirtual(graph),
+        halfImg   = Image::create(context, width, height, VX_DF_IMAGE_U8),
+        halfCanny = Image::create(context, width, height, VX_DF_IMAGE_U8);
+
+    // Constants
+    vx_uint32 threshCannyMin = 127;
+    vx_uint32 threshCannyMax = 192;
+    Threshold threshCanny = Threshold::createRange(context, VX_TYPE_UINT8, threshCannyMin, threshCannyMax);
+
+    ivx::Scalar alpha = ivx::Scalar::create<VX_TYPE_FLOAT32>(context, 0.5);
+
+    // Sequence of some image operations
+    // Node can also be added in function-like style
+    nodes::gaussian3x3(graph, inputImage, smoothed);
+    Node::create(graph, VX_KERNEL_CANNY_EDGE_DETECTOR, smoothed, threshCanny,
+                 ivx::Scalar::create<VX_TYPE_INT32>(context, 3),
+                 ivx::Scalar::create<VX_TYPE_ENUM>(context, VX_NORM_L2), cannied);
+    Node::create(graph, VX_KERNEL_ACCUMULATE_WEIGHTED, inputImage, alpha, halfImg);
+    Node::create(graph, VX_KERNEL_ACCUMULATE_WEIGHTED, cannied, alpha, halfCanny);
+    Node::create(graph, VX_KERNEL_ADD, halfImg, halfCanny,
+                 ivx::Scalar::create<VX_TYPE_ENUM>(context, VX_CONVERT_POLICY_SATURATE), outputImage);
+
+    graph.verify();
+
+    return graph;
+}
+
+
+int ovxDemo(std::string inputPath, UserMemoryMode mode)
+{
+    using namespace cv;
+    using namespace ivx;
+
+    Mat image = imread(inputPath, IMREAD_GRAYSCALE);
+    if (image.empty()) return -1;
+
+    //check image format
+    if (image.depth() != CV_8U || image.channels() != 1) return -1;
+
+    try
+    {
+        Context context = Context::create();
+        //put user data from cv::Mat to vx_image
+        vx_df_image color = Image::matTypeToFormat(image.type());
+        vx_uint32 width = image.cols, height = image.rows;
+        Image ivxImage;
+        if (mode == COPY)
+        {
+            ivxImage = Image::create(context, width, height, color);
+            ivxImage.copyFrom(0, image);
+        }
+        else
+        {
+            ivxImage = Image::createFromHandle(context, color, Image::createAddressing(image), image.data);
+        }
+
+        Image ivxResult;
+        Image::Patch resultPatch;
+        Mat output;
+        if (mode == COPY || mode == MAP)
+        {
+            //we will copy or map data from vx_image to cv::Mat
+            ivxResult = ivx::Image::create(context, width, height, VX_DF_IMAGE_U8);
+        }
+        else // if (mode == MAP_TO_VX)
+        {
+            //create vx_image based on user data, no copying required
+            output = cv::Mat(height, width, CV_8U, cv::Scalar(0));
+            ivxResult = Image::createFromHandle(context, Image::matTypeToFormat(CV_8U),
+                                                Image::createAddressing(output), output.data);
+        }
+
+        Graph graph = createProcessingGraph(ivxImage, ivxResult);
+
+        // Graph execution
+        graph.process();
+
+        //getting resulting image in cv::Mat
+        if (mode == COPY)
+        {
+            ivxResult.copyTo(0, output);
+        }
+        else if (mode == MAP)
+        {
+            //create cv::Mat based on vx_image mapped data
+            resultPatch.map(ivxResult, 0, ivxResult.getValidRegion());
+            //generally this is very bad idea!
+            //but in our case unmap() won't happen until output is in use
+            output = resultPatch.getMat();
+        }
+        else // if (mode == MAP_TO_VX)
+        {
+#ifdef VX_VERSION_1_1
+            //we should take user memory back from vx_image before using it (even before reading)
+            ivxResult.swapHandle();
+#endif
+        }
+
+        //here output goes
+        cv::imshow("processing result", output);
+        cv::waitKey(0);
+
+        cv::destroyAllWindows();
+
+#ifdef VX_VERSION_1_1
+        if (mode != COPY)
+        {
+            //we should take user memory back before release
+            //(it's not done automatically according to standard)
+            ivxImage.swapHandle();
+            if (mode == USER_MEM) ivxResult.swapHandle();
+        }
+#endif
+
+        //the line is unnecessary since unmapping is done on destruction of patch
+        //resultPatch.unmap();
+    }
+    catch (const ivx::RuntimeError& e)
+    {
+        std::cerr << "Error: code = " << e.status() << ", message = " << e.what() << std::endl;
+        return e.status();
+    }
+    catch (const ivx::WrapperError& e)
+    {
+        std::cerr << "Error: message = " << e.what() << std::endl;
+        return -1;
+    }
+
+    return 0;
+}
+
+
+int main(int argc, char *argv[])
+{
+    const std::string keys =
+        "{help h usage ? | | }"
+        "{image    | <none> | image to be processed}"
+        "{mode | copy | user memory interaction mode: \n"
+        "copy: create VX images and copy data to/from them\n"
+        "user_mem: use handles to user-allocated memory\n"
+        "map: map resulting VX image to user memory}"
+        ;
+
+    cv::CommandLineParser parser(argc, argv, keys);
+    parser.about("OpenVX interoperability sample demonstrating OpenVX wrappers usage."
+                 "The application loads an image, processes it with OpenVX graph and outputs result in a window");
+    if (parser.has("help"))
+    {
+        parser.printMessage();
+        return 0;
+    }
+    std::string imgPath = parser.get<std::string>("image");
+    std::string modeString = parser.get<std::string>("mode");
+    UserMemoryMode mode;
+    if(modeString == "copy")
+    {
+        mode = COPY;
+    }
+    else if(modeString == "user_mem")
+    {
+        mode = USER_MEM;
+    }
+    else if(modeString == "map")
+    {
+        mode = MAP;
+    }
+    else
+    {
+        std::cerr << modeString << ": unknown memory mode" << std::endl;
+        return -1;
+    }
+
+    if (!parser.check())
+    {
+        parser.printErrors();
+        return -1;
+    }
+
+    return ovxDemo(imgPath, mode);
+}
diff --git a/samples/openvx/wrappers_video.cpp b/samples/openvx/wrappers_video.cpp
new file mode 100644
index 0000000..737f052
--- /dev/null
+++ b/samples/openvx/wrappers_video.cpp
@@ -0,0 +1,250 @@
+#include <iostream>
+#include <stdexcept>
+
+//wrappers
+#include "ivx.hpp"
+
+//OpenCV includes
+#include "opencv2/core.hpp"
+#include "opencv2/imgproc.hpp"
+#include "opencv2/imgcodecs.hpp"
+#include "opencv2/highgui.hpp"
+
+enum UserMemoryMode
+{
+    COPY, USER_MEM, MAP
+};
+
+ivx::Graph createProcessingGraph(ivx::Image& inputImage, ivx::Image& outputImage);
+int ovxDemo(std::string inputPath, UserMemoryMode mode);
+
+
+ivx::Graph createProcessingGraph(ivx::Image& inputImage, ivx::Image& outputImage)
+{
+    using namespace ivx;
+
+    Context context = inputImage.get<Context>();
+    Graph graph = Graph::create(context);
+
+    vx_uint32 width  = inputImage.width();
+    vx_uint32 height = inputImage.height();
+
+    // Intermediate images
+    Image
+        yuv       = Image::createVirtual(graph, 0, 0, VX_DF_IMAGE_YUV4),
+        gray      = Image::createVirtual(graph),
+        smoothed  = Image::createVirtual(graph),
+        cannied   = Image::createVirtual(graph),
+        halfImg   = Image::create(context, width, height, VX_DF_IMAGE_U8),
+        halfCanny = Image::create(context, width, height, VX_DF_IMAGE_U8);
+
+    // Constants
+    vx_uint32 threshCannyMin = 127;
+    vx_uint32 threshCannyMax = 192;
+    Threshold threshCanny = Threshold::createRange(context, VX_TYPE_UINT8, threshCannyMin, threshCannyMax);
+
+    ivx::Scalar alpha = ivx::Scalar::create<VX_TYPE_FLOAT32>(context, 0.5);
+
+    // Sequence of some image operations
+    Node::create(graph, VX_KERNEL_COLOR_CONVERT, inputImage, yuv);
+    Node::create(graph, VX_KERNEL_CHANNEL_EXTRACT, yuv,
+                 ivx::Scalar::create<VX_TYPE_ENUM>(context, VX_CHANNEL_Y), gray);
+    //node can also be added in function-like style
+    nodes::gaussian3x3(graph, gray, smoothed);
+    Node::create(graph, VX_KERNEL_CANNY_EDGE_DETECTOR, smoothed, threshCanny,
+                 ivx::Scalar::create<VX_TYPE_INT32>(context, 3),
+                 ivx::Scalar::create<VX_TYPE_ENUM>(context, VX_NORM_L2), cannied);
+    Node::create(graph, VX_KERNEL_ACCUMULATE_WEIGHTED, gray, alpha, halfImg);
+    Node::create(graph, VX_KERNEL_ACCUMULATE_WEIGHTED, cannied, alpha, halfCanny);
+    Node::create(graph, VX_KERNEL_ADD, halfImg, halfCanny,
+                 ivx::Scalar::create<VX_TYPE_ENUM>(context, VX_CONVERT_POLICY_SATURATE), outputImage);
+
+    graph.verify();
+
+    return graph;
+}
+
+
+int ovxDemo(std::string inputPath, UserMemoryMode mode)
+{
+    using namespace cv;
+    using namespace ivx;
+
+    Mat frame;
+    VideoCapture vc(inputPath);
+    if (!vc.isOpened())
+        return -1;
+
+    vc >> frame;
+    if (frame.empty()) return -1;
+
+    //check frame format
+    if (frame.type() != CV_8UC3) return -1;
+
+    try
+    {
+        Context context = Context::create();
+        //put user data from cv::Mat to vx_image
+        vx_df_image color = Image::matTypeToFormat(frame.type());
+        vx_uint32 width = frame.cols, height = frame.rows;
+        Image ivxImage;
+        if (mode == COPY)
+        {
+            ivxImage = Image::create(context, width, height, color);
+        }
+        else
+        {
+            ivxImage = Image::createFromHandle(context, color, Image::createAddressing(frame), frame.data);
+        }
+
+        Image ivxResult;
+
+        Mat output;
+        if (mode == COPY || mode == MAP)
+        {
+            //we will copy or map data from vx_image to cv::Mat
+            ivxResult = ivx::Image::create(context, width, height, VX_DF_IMAGE_U8);
+        }
+        else // if (mode == MAP_TO_VX)
+        {
+            //create vx_image based on user data, no copying required
+            output = cv::Mat(height, width, CV_8U, cv::Scalar(0));
+            ivxResult = Image::createFromHandle(context, Image::matTypeToFormat(CV_8U),
+                                                Image::createAddressing(output), output.data);
+        }
+
+        Graph graph = createProcessingGraph(ivxImage, ivxResult);
+
+        bool stop = false;
+        while (!stop)
+        {
+            if (mode == COPY) ivxImage.copyFrom(0, frame);
+
+            // Graph execution
+            graph.process();
+
+            //getting resulting image in cv::Mat
+            Image::Patch resultPatch;
+            std::vector<void*> ptrs;
+            std::vector<void*> prevPtrs(ivxResult.planes());
+            if (mode == COPY)
+            {
+                ivxResult.copyTo(0, output);
+            }
+            else if (mode == MAP)
+            {
+                //create cv::Mat based on vx_image mapped data
+                resultPatch.map(ivxResult, 0, ivxResult.getValidRegion(), VX_READ_AND_WRITE);
+                //generally this is very bad idea!
+                //but in our case unmap() won't happen until output is in use
+                output = resultPatch.getMat();
+            }
+            else // if(mode == MAP_TO_VX)
+            {
+#ifdef VX_VERSION_1_1
+                //we should take user memory back from vx_image before using it (even before reading)
+                ivxResult.swapHandle(ptrs, prevPtrs);
+#endif
+            }
+
+            //here output goes
+            imshow("press q to quit", output);
+            if ((char)waitKey(1) == 'q') stop = true;
+
+#ifdef VX_VERSION_1_1
+            //restore handle
+            if (mode == USER_MEM)
+            {
+                ivxResult.swapHandle(prevPtrs, ptrs);
+            }
+#endif
+
+            //this line is unnecessary since unmapping is done on destruction of patch
+            //resultPatch.unmap();
+
+            //grab next frame
+            Mat temp = frame;
+            vc >> frame;
+            if (frame.empty()) stop = true;
+            if (mode != COPY && frame.data != temp.data)
+            {
+                //frame was reallocated, pointer to data changed
+                frame.copyTo(temp);
+            }
+        }
+
+        destroyAllWindows();
+
+#ifdef VX_VERSION_1_1
+        if (mode != COPY)
+        {
+            //we should take user memory back before release
+            //(it's not done automatically according to standard)
+            ivxImage.swapHandle();
+            if (mode == USER_MEM) ivxResult.swapHandle();
+        }
+#endif
+    }
+    catch (const ivx::RuntimeError& e)
+    {
+        std::cerr << "Error: code = " << e.status() << ", message = " << e.what() << std::endl;
+        return e.status();
+    }
+    catch (const ivx::WrapperError& e)
+    {
+        std::cerr << "Error: message = " << e.what() << std::endl;
+        return -1;
+    }
+
+    return 0;
+}
+
+
+int main(int argc, char *argv[])
+{
+    const std::string keys =
+        "{help h usage ? | | }"
+        "{video    | <none> | video file to be processed}"
+        "{mode | copy | user memory interaction mode: \n"
+        "copy: create VX images and copy data to/from them\n"
+        "user_mem: use handles to user-allocated memory\n"
+        "map: map resulting VX image to user memory}"
+        ;
+
+    cv::CommandLineParser parser(argc, argv, keys);
+    parser.about("OpenVX interoperability sample demonstrating OpenVX wrappers usage."
+                 "The application opens a video and processes it with OpenVX graph while outputting result in a window");
+    if (parser.has("help"))
+    {
+        parser.printMessage();
+        return 0;
+    }
+    std::string videoPath = parser.get<std::string>("video");
+    std::string modeString = parser.get<std::string>("mode");
+    UserMemoryMode mode;
+    if(modeString == "copy")
+    {
+        mode = COPY;
+    }
+    else if(modeString == "user_mem")
+    {
+        mode = USER_MEM;
+    }
+    else if(modeString == "map")
+    {
+        mode = MAP;
+    }
+    else
+    {
+        std::cerr << modeString << ": unknown memory mode" << std::endl;
+        return -1;
+    }
+
+    if (!parser.check())
+    {
+        parser.printErrors();
+        return -1;
+    }
+
+    return ovxDemo(videoPath, mode);
+}
diff --git a/samples/python/asift.py b/samples/python/asift.py
index 8d2774a..ec74930 100755
--- a/samples/python/asift.py
+++ b/samples/python/asift.py
@@ -112,7 +112,7 @@ if __name__ == '__main__':
     import sys, getopt
     opts, args = getopt.getopt(sys.argv[1:], '', ['feature='])
     opts = dict(opts)
-    feature_name = opts.get('--feature', 'sift-flann')
+    feature_name = opts.get('--feature', 'brisk-flann')
     try:
         fn1, fn2 = args
     except:
diff --git a/samples/python/camshift.py b/samples/python/camshift.py
index 867cee9..d55c1ac 100755
--- a/samples/python/camshift.py
+++ b/samples/python/camshift.py
@@ -35,39 +35,34 @@ import cv2
 
 # local module
 import video
+from video import presets
 
 
 class App(object):
     def __init__(self, video_src):
-        self.cam = video.create_capture(video_src)
+        self.cam = video.create_capture(video_src, presets['cube'])
         ret, self.frame = self.cam.read()
         cv2.namedWindow('camshift')
         cv2.setMouseCallback('camshift', self.onmouse)
 
         self.selection = None
         self.drag_start = None
-        self.tracking_state = 0
         self.show_backproj = False
+        self.track_window = None
 
     def onmouse(self, event, x, y, flags, param):
-        x, y = np.int16([x, y]) # BUG
         if event == cv2.EVENT_LBUTTONDOWN:
             self.drag_start = (x, y)
-            self.tracking_state = 0
-            return
+            self.track_window = None
         if self.drag_start:
-            if flags & cv2.EVENT_FLAG_LBUTTON:
-                h, w = self.frame.shape[:2]
-                xo, yo = self.drag_start
-                x0, y0 = np.maximum(0, np.minimum([xo, yo], [x, y]))
-                x1, y1 = np.minimum([w, h], np.maximum([xo, yo], [x, y]))
-                self.selection = None
-                if x1-x0 > 0 and y1-y0 > 0:
-                    self.selection = (x0, y0, x1, y1)
-            else:
-                self.drag_start = None
-                if self.selection is not None:
-                    self.tracking_state = 1
+            xmin = min(x, self.drag_start[0])
+            ymin = min(y, self.drag_start[1])
+            xmax = max(x, self.drag_start[0])
+            ymax = max(y, self.drag_start[1])
+            self.selection = (xmin, ymin, xmax, ymax)
+        if event == cv2.EVENT_LBUTTONUP:
+            self.drag_start = None
+            self.track_window = (xmin, ymin, xmax - xmin, ymax - ymin)
 
     def show_hist(self):
         bin_count = self.hist.shape[0]
@@ -88,7 +83,6 @@ class App(object):
 
             if self.selection:
                 x0, y0, x1, y1 = self.selection
-                self.track_window = (x0, y0, x1-x0, y1-y0)
                 hsv_roi = hsv[y0:y1, x0:x1]
                 mask_roi = mask[y0:y1, x0:x1]
                 hist = cv2.calcHist( [hsv_roi], [0], mask_roi, [16], [0, 180] )
@@ -100,7 +94,7 @@ class App(object):
                 cv2.bitwise_not(vis_roi, vis_roi)
                 vis[mask == 0] = 0
 
-            if self.tracking_state == 1:
+            if self.track_window and self.track_window[2] > 0 and self.track_window[3] > 0:
                 self.selection = None
                 prob = cv2.calcBackProject([hsv], [0], self.hist, [0, 180], 1)
                 prob &= mask
@@ -116,7 +110,7 @@ class App(object):
 
             cv2.imshow('camshift', vis)
 
-            ch = 0xFF & cv2.waitKey(5)
+            ch = cv2.waitKey(5)
             if ch == 27:
                 break
             if ch == ord('b'):
diff --git a/samples/python/coherence.py b/samples/python/coherence.py
index 8ca61fc..a1e34b8 100755
--- a/samples/python/coherence.py
+++ b/samples/python/coherence.py
@@ -77,7 +77,7 @@ if __name__ == '__main__':
     cv2.imshow('src', src)
     update()
     while True:
-        ch = 0xFF & cv2.waitKey()
+        ch = cv2.waitKey()
         if ch == ord(' '):
             update()
         if ch == 27:
diff --git a/samples/python/color_histogram.py b/samples/python/color_histogram.py
index 9e691b7..c1e5d56 100755
--- a/samples/python/color_histogram.py
+++ b/samples/python/color_histogram.py
@@ -56,7 +56,7 @@ if __name__ == '__main__':
         vis = hsv_map*h[:,:,np.newaxis] / 255.0
         cv2.imshow('hist', vis)
 
-        ch = 0xFF & cv2.waitKey(1)
+        ch = cv2.waitKey(1)
         if ch == 27:
             break
     cv2.destroyAllWindows()
diff --git a/samples/python/common.py b/samples/python/common.py
index 785fb6c..09159bb 100755
--- a/samples/python/common.py
+++ b/samples/python/common.py
@@ -173,6 +173,7 @@ class RectSelector:
         x, y = np.int16([x, y]) # BUG
         if event == cv2.EVENT_LBUTTONDOWN:
             self.drag_start = (x, y)
+            return
         if self.drag_start:
             if flags & cv2.EVENT_FLAG_LBUTTON:
                 xo, yo = self.drag_start
diff --git a/samples/python/contours.py b/samples/python/contours.py
index 619108b..73b9f2f 100755
--- a/samples/python/contours.py
+++ b/samples/python/contours.py
@@ -66,5 +66,5 @@ if __name__ == '__main__':
     update(3)
     cv2.createTrackbar( "levels+3", "contours", 3, 7, update )
     cv2.imshow('image', img)
-    0xFF & cv2.waitKey()
+    cv2.waitKey()
     cv2.destroyAllWindows()
diff --git a/samples/python/deconvolution.py b/samples/python/deconvolution.py
index ce79853..74f51a7 100755
--- a/samples/python/deconvolution.py
+++ b/samples/python/deconvolution.py
@@ -122,7 +122,7 @@ if __name__ == '__main__':
     update(None)
 
     while True:
-        ch = cv2.waitKey() & 0xFF
+        ch = cv2.waitKey()
         if ch == 27:
             break
         if ch == ord(' '):
diff --git a/samples/python/demo.py b/samples/python/demo.py
index 864953a..81c6a85 100755
--- a/samples/python/demo.py
+++ b/samples/python/demo.py
@@ -87,8 +87,11 @@ class App:
         for fn in glob('*.py'):
             name = splitfn(fn)[1]
             if fn[0] != '_' and name not in exclude_list:
-                demos_lb.insert(tk.END, name)
                 self.samples[name] = fn
+
+        for name in sorted(self.samples):
+            demos_lb.insert(tk.END, name)
+
         demos_lb.bind('<<ListboxSelect>>', self.on_demo_select)
 
         self.cmd_entry = cmd_entry = tk.Entry(right)
diff --git a/samples/python/digits.py b/samples/python/digits.py
index 04397a1..5cc98b7 100755
--- a/samples/python/digits.py
+++ b/samples/python/digits.py
@@ -71,7 +71,7 @@ def deskew(img):
 
 class StatModel(object):
     def load(self, fn):
-        self.model.load(fn)  # Known bug: https://github.com/Itseez/opencv/issues/4969
+        self.model.load(fn)  # Known bug: https://github.com/opencv/opencv/issues/4969
     def save(self, fn):
         self.model.save(fn)
 
diff --git a/samples/python/digits_video.py b/samples/python/digits_video.py
index 5f57cb8..2f79cb5 100755
--- a/samples/python/digits_video.py
+++ b/samples/python/digits_video.py
@@ -27,9 +27,12 @@ def main():
     if not os.path.exists(classifier_fn):
         print('"%s" not found, run digits.py first' % classifier_fn)
         return
-    model = SVM()
-    model.load(classifier_fn)
 
+    if True:
+        model = cv2.ml.SVM_load(classifier_fn)
+    else:
+        model = cv2.ml.SVM_create()
+        model.load_(classifier_fn) #Known bug: https://github.com/opencv/opencv/issues/4969
 
     while True:
         ret, frame = cap.read()
@@ -89,7 +92,7 @@ def main():
 
         cv2.imshow('frame', frame)
         cv2.imshow('bin', bin)
-        ch = cv2.waitKey(1) & 0xFF
+        ch = cv2.waitKey(1)
         if ch == 27:
             break
 
diff --git a/samples/python/distrans.py b/samples/python/distrans.py
index 00e173d..8abe460 100755
--- a/samples/python/distrans.py
+++ b/samples/python/distrans.py
@@ -59,7 +59,7 @@ if __name__ == '__main__':
 
 
     while True:
-        ch = 0xFF & cv2.waitKey(50)
+        ch = cv2.waitKey(50)
         if ch == 27:
             break
         if ch == ord('v'):
diff --git a/samples/python/edge.py b/samples/python/edge.py
index c096fb4..b597729 100755
--- a/samples/python/edge.py
+++ b/samples/python/edge.py
@@ -49,7 +49,7 @@ if __name__ == '__main__':
         vis = np.uint8(vis/2.)
         vis[edge != 0] = (0, 255, 0)
         cv2.imshow('edge', vis)
-        ch = cv2.waitKey(5) & 0xFF
+        ch = cv2.waitKey(5)
         if ch == 27:
             break
     cv2.destroyAllWindows()
diff --git a/samples/python/facedetect.py b/samples/python/facedetect.py
index 15187c6..0f79663 100755
--- a/samples/python/facedetect.py
+++ b/samples/python/facedetect.py
@@ -68,6 +68,6 @@ if __name__ == '__main__':
         draw_str(vis, (20, 20), 'time: %.1f ms' % (dt*1000))
         cv2.imshow('facedetect', vis)
 
-        if 0xFF & cv2.waitKey(5) == 27:
+        if cv2.waitKey(5) == 27:
             break
     cv2.destroyAllWindows()
diff --git a/samples/python/feature_homography.py b/samples/python/feature_homography.py
index 4a5e319..37f269f 100755
--- a/samples/python/feature_homography.py
+++ b/samples/python/feature_homography.py
@@ -30,6 +30,7 @@ import cv2
 
 # local modules
 import video
+from video import presets
 import common
 from common import getsize, draw_keypoints
 from plane_tracker import PlaneTracker
@@ -37,7 +38,7 @@ from plane_tracker import PlaneTracker
 
 class App:
     def __init__(self, src):
-        self.cap = video.create_capture(src)
+        self.cap = video.create_capture(src, presets['book'])
         self.frame = None
         self.paused = False
         self.tracker = PlaneTracker()
diff --git a/samples/python/find_obj.py b/samples/python/find_obj.py
index d8d3d41..a77024c 100755
--- a/samples/python/find_obj.py
+++ b/samples/python/find_obj.py
@@ -3,7 +3,7 @@
 '''
 Feature-based image matching sample.
 
-Note, that you will need the https://github.com/Itseez/opencv_contrib repo for SIFT and SURF
+Note, that you will need the https://github.com/opencv/opencv_contrib repo for SIFT and SURF
 
 USAGE
   find_obj.py [--feature=<sift|surf|orb|akaze|brisk>[-flann]] [ <image1> <image2> ]
@@ -68,7 +68,7 @@ def filter_matches(kp1, kp2, matches, ratio = 0.75):
     p1 = np.float32([kp.pt for kp in mkp1])
     p2 = np.float32([kp.pt for kp in mkp2])
     kp_pairs = zip(mkp1, mkp2)
-    return p1, p2, kp_pairs
+    return p1, p2, list(kp_pairs)
 
 def explore_match(win, img1, img2, kp_pairs, status = None, H = None):
     h1, w1 = img1.shape[:2]
@@ -119,7 +119,7 @@ def explore_match(win, img1, img2, kp_pairs, status = None, H = None):
         if flags & cv2.EVENT_FLAG_LBUTTON:
             cur_vis = vis0.copy()
             r = 8
-            m = (anorm(p1 - (x, y)) < r) | (anorm(p2 - (x, y)) < r)
+            m = (anorm(np.array(p1) - (x, y)) < r) | (anorm(np.array(p2) - (x, y)) < r)
             idxs = np.where(m)[0]
             kp1s, kp2s = [], []
             for i in idxs:
@@ -143,7 +143,7 @@ if __name__ == '__main__':
     import sys, getopt
     opts, args = getopt.getopt(sys.argv[1:], '', ['feature='])
     opts = dict(opts)
-    feature_name = opts.get('--feature', 'sift')
+    feature_name = opts.get('--feature', 'brisk')
     try:
         fn1, fn2 = args
     except:
diff --git a/samples/python/fitline.py b/samples/python/fitline.py
index 95fb2b8..c91144c 100755
--- a/samples/python/fitline.py
+++ b/samples/python/fitline.py
@@ -88,7 +88,7 @@ if __name__ == '__main__':
     cv2.createTrackbar('outlier %', 'fit line', 30, 100, update)
     while True:
         update()
-        ch = cv2.waitKey(0) & 0xFF
+        ch = cv2.waitKey(0)
         if ch == ord('f'):
             if PY3:
                 cur_func_name = next(dist_func_names)
diff --git a/samples/python/floodfill.py b/samples/python/floodfill.py
index 161c632..1b988d3 100755
--- a/samples/python/floodfill.py
+++ b/samples/python/floodfill.py
@@ -66,7 +66,7 @@ if __name__ == '__main__':
     cv2.createTrackbar('hi', 'floodfill', 20, 255, update)
 
     while True:
-        ch = 0xFF & cv2.waitKey()
+        ch = cv2.waitKey()
         if ch == 27:
             break
         if ch == ord('f'):
diff --git a/samples/python/gaussian_mix.py b/samples/python/gaussian_mix.py
index b0c2874..79c69fc 100755
--- a/samples/python/gaussian_mix.py
+++ b/samples/python/gaussian_mix.py
@@ -50,7 +50,7 @@ if __name__ == '__main__':
         em.setCovarianceMatrixType(cv2.ml.EM_COV_MAT_GENERIC)
         em.trainEM(points)
         means = em.getMeans()
-        covs = em.getCovs()  # Known bug: https://github.com/Itseez/opencv/pull/4232
+        covs = em.getCovs()  # Known bug: https://github.com/opencv/opencv/pull/4232
         found_distrs = zip(means, covs)
         print('ready!\n')
 
@@ -63,7 +63,7 @@ if __name__ == '__main__':
             draw_gaussain(img, m, cov, (0, 0, 255))
 
         cv2.imshow('gaussian mixture', img)
-        ch = 0xFF & cv2.waitKey(0)
+        ch = cv2.waitKey(0)
         if ch == 27:
             break
     cv2.destroyAllWindows()
diff --git a/samples/python/grabcut.py b/samples/python/grabcut.py
index 19378e6..1a5c2d0 100644
--- a/samples/python/grabcut.py
+++ b/samples/python/grabcut.py
@@ -129,7 +129,7 @@ if __name__ == '__main__':
 
         cv2.imshow('output',output)
         cv2.imshow('input',img)
-        k = 0xFF & cv2.waitKey(1)
+        k = cv2.waitKey(1)
 
         # key bindings
         if k == 27:         # esc to exit
diff --git a/samples/python/hist.py b/samples/python/hist.py
index 80cc6b4..d1801c7 100755
--- a/samples/python/hist.py
+++ b/samples/python/hist.py
@@ -84,7 +84,7 @@ if __name__ == '__main__':
 
     cv2.imshow('image',im)
     while True:
-        k = cv2.waitKey(0)&0xFF
+        k = cv2.waitKey(0)
         if k == ord('a'):
             curve = hist_curve(im)
             cv2.imshow('histogram',curve)
diff --git a/samples/python/houghcircles.py b/samples/python/houghcircles.py
index 5386fc2..c766c1c 100755
--- a/samples/python/houghcircles.py
+++ b/samples/python/houghcircles.py
@@ -29,11 +29,14 @@ if __name__ == '__main__':
     cimg = src.copy() # numpy function
 
     circles = cv2.HoughCircles(img, cv2.HOUGH_GRADIENT, 1, 10, np.array([]), 100, 30, 1, 30)
-    a, b, c = circles.shape
-    for i in range(b):
-        cv2.circle(cimg, (circles[0][i][0], circles[0][i][1]), circles[0][i][2], (0, 0, 255), 3, cv2.LINE_AA)
-        cv2.circle(cimg, (circles[0][i][0], circles[0][i][1]), 2, (0, 255, 0), 3, cv2.LINE_AA)  # draw center of circle
+
+    if circles is not None: # Check if circles have been found and only then iterate over these and add them to the image
+        a, b, c = circles.shape
+        for i in range(b):
+            cv2.circle(cimg, (circles[0][i][0], circles[0][i][1]), circles[0][i][2], (0, 0, 255), 3, cv2.LINE_AA)
+            cv2.circle(cimg, (circles[0][i][0], circles[0][i][1]), 2, (0, 255, 0), 3, cv2.LINE_AA)  # draw center of circle
+
+        cv2.imshow("detected circles", cimg)
 
     cv2.imshow("source", src)
-    cv2.imshow("detected circles", cimg)
     cv2.waitKey(0)
diff --git a/samples/python/houghlines.py b/samples/python/houghlines.py
index 120d8bb..76e074c 100755
--- a/samples/python/houghlines.py
+++ b/samples/python/houghlines.py
@@ -36,17 +36,19 @@ if __name__ == '__main__':
 
     else:    # HoughLines
         lines = cv2.HoughLines(dst, 1, math.pi/180.0, 50, np.array([]), 0, 0)
-        a,b,c = lines.shape
-        for i in range(a):
-            rho = lines[i][0][0]
-            theta = lines[i][0][1]
-            a = math.cos(theta)
-            b = math.sin(theta)
-            x0, y0 = a*rho, b*rho
-            pt1 = ( int(x0+1000*(-b)), int(y0+1000*(a)) )
-            pt2 = ( int(x0-1000*(-b)), int(y0-1000*(a)) )
-            cv2.line(cdst, pt1, pt2, (0, 0, 255), 3, cv2.LINE_AA)
+        if lines is not None:
+            a,b,c = lines.shape
+            for i in range(a):
+                rho = lines[i][0][0]
+                theta = lines[i][0][1]
+                a = math.cos(theta)
+                b = math.sin(theta)
+                x0, y0 = a*rho, b*rho
+                pt1 = ( int(x0+1000*(-b)), int(y0+1000*(a)) )
+                pt2 = ( int(x0-1000*(-b)), int(y0-1000*(a)) )
+                cv2.line(cdst, pt1, pt2, (0, 0, 255), 3, cv2.LINE_AA)
+
+            cv2.imshow("detected lines", cdst)
 
     cv2.imshow("source", src)
-    cv2.imshow("detected lines", cdst)
     cv2.waitKey(0)
diff --git a/samples/python/inpaint.py b/samples/python/inpaint.py
index 0ca72f1..3b738bb 100755
--- a/samples/python/inpaint.py
+++ b/samples/python/inpaint.py
@@ -41,7 +41,7 @@ if __name__ == '__main__':
     sketch = Sketcher('img', [img_mark, mark], lambda : ((255, 255, 255), 255))
 
     while True:
-        ch = 0xFF & cv2.waitKey()
+        ch = cv2.waitKey()
         if ch == 27:
             break
         if ch == ord(' '):
diff --git a/samples/python/kalman.py b/samples/python/kalman.py
index 8e3748b..96a6fa6 100755
--- a/samples/python/kalman.py
+++ b/samples/python/kalman.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python
 """
    Tracking of rotating point.
    Rotation speed is constant.
@@ -19,7 +19,7 @@ if PY3:
     long = int
 
 import cv2
-from math import cos, sin
+from math import cos, sin, sqrt
 import numpy as np
 
 if __name__ == "__main__":
@@ -81,12 +81,12 @@ if __name__ == "__main__":
 
             kalman.correct(measurement)
 
-            process_noise = kalman.processNoiseCov * np.random.randn(2, 1)
+            process_noise = sqrt(kalman.processNoiseCov[0,0]) * np.random.randn(2, 1)
             state = np.dot(kalman.transitionMatrix, state) + process_noise
 
             cv2.imshow("Kalman", img)
 
-            code = cv2.waitKey(100) % 0x100
+            code = cv2.waitKey(100)
             if code != -1:
                 break
 
diff --git a/samples/python/kmeans.py b/samples/python/kmeans.py
index b2e6b66..0fdc759 100755
--- a/samples/python/kmeans.py
+++ b/samples/python/kmeans.py
@@ -44,7 +44,7 @@ if __name__ == '__main__':
             cv2.circle(img, (x, y), 1, c, -1)
 
         cv2.imshow('gaussian mixture', img)
-        ch = 0xFF & cv2.waitKey(0)
+        ch = cv2.waitKey(0)
         if ch == 27:
             break
     cv2.destroyAllWindows()
diff --git a/samples/python/lappyr.py b/samples/python/lappyr.py
index d8fde0f..c68e5e8 100755
--- a/samples/python/lappyr.py
+++ b/samples/python/lappyr.py
@@ -70,5 +70,5 @@ if __name__ == '__main__':
 
         cv2.imshow('laplacian pyramid filter', res)
 
-        if cv2.waitKey(1) & 0xFF == 27:
+        if cv2.waitKey(1) == 27:
             break
diff --git a/samples/python/letter_recog.py b/samples/python/letter_recog.py
index e68c095..7d0c437 100755
--- a/samples/python/letter_recog.py
+++ b/samples/python/letter_recog.py
@@ -65,13 +65,12 @@ class RTrees(LetterStatModel):
 
     def train(self, samples, responses):
         sample_n, var_n = samples.shape
-        var_types = np.array([cv2.ml.VAR_NUMERICAL] * var_n + [cv2.ml.VAR_CATEGORICAL], np.uint8)
-        #CvRTParams(10,10,0,false,15,0,true,4,100,0.01f,CV_TERMCRIT_ITER));
-        params = dict(max_depth=10 )
-        self.model.train(samples, cv2.ml.ROW_SAMPLE, responses, varType = var_types, params = params)
+        self.model.setMaxDepth(20)
+        self.model.train(samples, cv2.ml.ROW_SAMPLE, responses.astype(int))
 
     def predict(self, samples):
-        return [self.model.predict(s) for s in samples]
+        ret, resp = self.model.predict(samples)
+        return resp.ravel()
 
 
 class KNearest(LetterStatModel):
@@ -79,10 +78,10 @@ class KNearest(LetterStatModel):
         self.model = cv2.ml.KNearest_create()
 
     def train(self, samples, responses):
-        self.model.train(samples, responses)
+        self.model.train(samples, cv2.ml.ROW_SAMPLE, responses)
 
     def predict(self, samples):
-        retval, results, neigh_resp, dists = self.model.find_nearest(samples, k = 10)
+        retval, results, neigh_resp, dists = self.model.findNearest(samples, k = 10)
         return results.ravel()
 
 
@@ -95,15 +94,16 @@ class Boost(LetterStatModel):
         new_samples = self.unroll_samples(samples)
         new_responses = self.unroll_responses(responses)
         var_types = np.array([cv2.ml.VAR_NUMERICAL] * var_n + [cv2.ml.VAR_CATEGORICAL, cv2.ml.VAR_CATEGORICAL], np.uint8)
-        #CvBoostParams(CvBoost::REAL, 100, 0.95, 5, false, 0 )
-        params = dict(max_depth=5) #, use_surrogates=False)
-        self.model.train(new_samples, cv2.ml.ROW_SAMPLE, new_responses, varType = var_types, params=params)
+
+        self.model.setWeakCount(15)
+        self.model.setMaxDepth(10)
+        self.model.train(cv2.ml.TrainData_create(new_samples, cv2.ml.ROW_SAMPLE, new_responses.astype(int), varType = var_types))
 
     def predict(self, samples):
         new_samples = self.unroll_samples(samples)
-        pred = np.array( [self.model.predict(s, returnSum = True) for s in new_samples] )
-        pred = pred.reshape(-1, self.class_n).argmax(1)
-        return pred
+        ret, resp = self.model.predict(new_samples)
+
+        return resp.ravel().reshape(-1, self.class_n).argmax(1)
 
 
 class SVM(LetterStatModel):
@@ -111,13 +111,15 @@ class SVM(LetterStatModel):
         self.model = cv2.ml.SVM_create()
 
     def train(self, samples, responses):
-        params = dict( kernel_type = cv2.ml.SVM_LINEAR,
-                       svm_type = cv2.ml.SVM_C_SVC,
-                       C = 1 )
-        self.model.train(samples, responses, params = params)
+        self.model.setType(cv2.ml.SVM_C_SVC)
+        self.model.setC(1)
+        self.model.setKernel(cv2.ml.SVM_RBF)
+        self.model.setGamma(.1)
+        self.model.train(samples, cv2.ml.ROW_SAMPLE, responses.astype(int))
 
     def predict(self, samples):
-        return self.model.predict_all(samples).ravel()
+        ret, resp = self.model.predict(samples)
+        return resp.ravel()
 
 
 class MLP(LetterStatModel):
@@ -127,22 +129,23 @@ class MLP(LetterStatModel):
     def train(self, samples, responses):
         sample_n, var_n = samples.shape
         new_responses = self.unroll_responses(responses).reshape(-1, self.class_n)
-
         layer_sizes = np.int32([var_n, 100, 100, self.class_n])
-        self.model.create(layer_sizes)
 
-        # CvANN_MLP_TrainParams::BACKPROP,0.001
-        params = dict( term_crit = (cv2.TERM_CRITERIA_COUNT, 300, 0.01),
-                       train_method = cv2.ml.ANN_MLP_TRAIN_PARAMS_BACKPROP,
-                       bp_dw_scale = 0.001,
-                       bp_moment_scale = 0.0 )
-        self.model.train(samples, np.float32(new_responses), None, params = params)
+        self.model.setLayerSizes(layer_sizes)
+        self.model.setTrainMethod(cv2.ml.ANN_MLP_BACKPROP)
+        self.model.setBackpropMomentumScale(0.0)
+        self.model.setBackpropWeightScale(0.001)
+        self.model.setTermCriteria((cv2.TERM_CRITERIA_COUNT, 20, 0.01))
+        self.model.setActivationFunction(cv2.ml.ANN_MLP_SIGMOID_SYM, 2, 1)
+
+        self.model.train(samples, cv2.ml.ROW_SAMPLE, np.float32(new_responses))
 
     def predict(self, samples):
         ret, resp = self.model.predict(samples)
         return resp.argmax(-1)
 
 
+
 if __name__ == '__main__':
     import getopt
     import sys
@@ -155,7 +158,7 @@ if __name__ == '__main__':
 
     args, dummy = getopt.getopt(sys.argv[1:], '', ['model=', 'data=', 'load=', 'save='])
     args = dict(args)
-    args.setdefault('--model', 'rtrees')
+    args.setdefault('--model', 'svm')
     args.setdefault('--data', '../data/letter-recognition.data')
 
     print('loading data %s ...' % args['--data'])
@@ -173,8 +176,8 @@ if __name__ == '__main__':
         model.train(samples[:train_n], responses[:train_n])
 
     print('testing...')
-    train_rate = np.mean(model.predict(samples[:train_n]) == responses[:train_n])
-    test_rate  = np.mean(model.predict(samples[train_n:]) == responses[train_n:])
+    train_rate = np.mean(model.predict(samples[:train_n]) == responses[:train_n].astype(int))
+    test_rate  = np.mean(model.predict(samples[train_n:]) == responses[train_n:].astype(int))
 
     print('train rate: %f  test rate: %f' % (train_rate*100, test_rate*100))
 
diff --git a/samples/python/lk_homography.py b/samples/python/lk_homography.py
index a9e9254..8cc3b69 100755
--- a/samples/python/lk_homography.py
+++ b/samples/python/lk_homography.py
@@ -27,6 +27,7 @@ import numpy as np
 import cv2
 import video
 from common import draw_str
+from video import presets
 
 lk_params = dict( winSize  = (19, 19),
                   maxLevel = 2,
@@ -49,7 +50,7 @@ red = (0, 0, 255)
 
 class App:
     def __init__(self, video_src):
-        self.cam = video.create_capture(video_src)
+        self.cam = self.cam = video.create_capture(video_src, presets['book'])
         self.p0 = None
         self.use_ransac = True
 
@@ -89,7 +90,7 @@ class App:
 
             cv2.imshow('lk_homography', vis)
 
-            ch = 0xFF & cv2.waitKey(1)
+            ch = cv2.waitKey(1)
             if ch == 27:
                 break
             if ch == ord(' '):
diff --git a/samples/python/lk_track.py b/samples/python/lk_track.py
index 8aa94fe..ffa7dfa 100755
--- a/samples/python/lk_track.py
+++ b/samples/python/lk_track.py
@@ -85,7 +85,7 @@ class App:
             self.prev_gray = frame_gray
             cv2.imshow('lk_track', vis)
 
-            ch = 0xFF & cv2.waitKey(1)
+            ch = cv2.waitKey(1)
             if ch == 27:
                 break
 
diff --git a/samples/python/morphology.py b/samples/python/morphology.py
index be287d3..0b62784 100755
--- a/samples/python/morphology.py
+++ b/samples/python/morphology.py
@@ -79,7 +79,7 @@ if __name__ == '__main__':
     cv2.createTrackbar('iters', 'morphology', 1, 10, update)
     update()
     while True:
-        ch = 0xFF & cv2.waitKey()
+        ch = cv2.waitKey()
         if ch == 27:
             break
         if ch == ord('1'):
diff --git a/samples/python/mosse.py b/samples/python/mosse.py
index 29a3a69..46e22d3 100755
--- a/samples/python/mosse.py
+++ b/samples/python/mosse.py
@@ -176,7 +176,7 @@ class App:
             self.rect_sel.draw(vis)
 
             cv2.imshow('frame', vis)
-            ch = cv2.waitKey(10) & 0xFF
+            ch = cv2.waitKey(10)
             if ch == 27:
                 break
             if ch == ord(' '):
diff --git a/samples/python/mouse_and_match.py b/samples/python/mouse_and_match.py
index adbd8ba..f75b64c 100755
--- a/samples/python/mouse_and_match.py
+++ b/samples/python/mouse_and_match.py
@@ -78,6 +78,6 @@ if __name__ == '__main__':
             drag_start = None
             gray=cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
             cv2.imshow("gray",gray)
-            if (cv2.waitKey() & 255) == 27:
+            if cv2.waitKey() == 27:
                 break
     cv2.destroyAllWindows()
diff --git a/samples/python/mser.py b/samples/python/mser.py
index 9d7a65c..1c5c69b 100755
--- a/samples/python/mser.py
+++ b/samples/python/mser.py
@@ -17,9 +17,9 @@ Keys:
 import numpy as np
 import cv2
 import video
+import sys
 
 if __name__ == '__main__':
-    import sys
     try:
         video_src = sys.argv[1]
     except:
@@ -27,16 +27,19 @@ if __name__ == '__main__':
 
     cam = video.create_capture(video_src)
     mser = cv2.MSER_create()
+
     while True:
         ret, img = cam.read()
+        if ret == 0:
+            break
         gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
         vis = img.copy()
 
-        regions = mser.detectRegions(gray, None)
+        regions, _ = mser.detectRegions(gray)
         hulls = [cv2.convexHull(p.reshape(-1, 1, 2)) for p in regions]
         cv2.polylines(vis, hulls, 1, (0, 255, 0))
 
         cv2.imshow('img', vis)
-        if 0xFF & cv2.waitKey(5) == 27:
+        if cv2.waitKey(5) == 27:
             break
     cv2.destroyAllWindows()
diff --git a/samples/python/opt_flow.py b/samples/python/opt_flow.py
index be85262..3d4ef34 100755
--- a/samples/python/opt_flow.py
+++ b/samples/python/opt_flow.py
@@ -83,7 +83,7 @@ if __name__ == '__main__':
             cur_glitch = warp_flow(cur_glitch, flow)
             cv2.imshow('glitch', cur_glitch)
 
-        ch = 0xFF & cv2.waitKey(5)
+        ch = cv2.waitKey(5)
         if ch == 27:
             break
         if ch == ord('1'):
diff --git a/samples/python/peopledetect.py b/samples/python/peopledetect.py
index 1cad952..84db096 100755
--- a/samples/python/peopledetect.py
+++ b/samples/python/peopledetect.py
@@ -65,7 +65,7 @@ if __name__ == '__main__':
         draw_detections(img, found_filtered, 3)
         print('%d (%d) found' % (len(found_filtered), len(found)))
         cv2.imshow('img', img)
-        ch = 0xFF & cv2.waitKey()
+        ch = cv2.waitKey()
         if ch == 27:
             break
     cv2.destroyAllWindows()
diff --git a/samples/python/plane_ar.py b/samples/python/plane_ar.py
index ef6c870..8994833 100755
--- a/samples/python/plane_ar.py
+++ b/samples/python/plane_ar.py
@@ -30,8 +30,9 @@ import cv2
 import video
 import common
 from plane_tracker import PlaneTracker
+from video import presets
 
-
+# Simple model of a house - cube with a triangular prism "roof"
 ar_verts = np.float32([[0, 0, 0], [0, 1, 0], [1, 1, 0], [1, 0, 0],
                        [0, 0, 1], [0, 1, 1], [1, 1, 1], [1, 0, 1],
                        [0, 0.5, 2], [1, 0.5, 2]])
@@ -42,7 +43,7 @@ ar_edges = [(0, 1), (1, 2), (2, 3), (3, 0),
 
 class App:
     def __init__(self, src):
-        self.cap = video.create_capture(src)
+        self.cap = video.create_capture(src, presets['book'])
         self.frame = None
         self.paused = False
         self.tracker = PlaneTracker()
@@ -74,7 +75,7 @@ class App:
 
             self.rect_sel.draw(vis)
             cv2.imshow('plane', vis)
-            ch = cv2.waitKey(1) & 0xFF
+            ch = cv2.waitKey(1)
             if ch == ord(' '):
                 self.paused = not self.paused
             if ch == ord('c'):
diff --git a/samples/python/plane_tracker.py b/samples/python/plane_tracker.py
index d8c2218..e285c08 100755
--- a/samples/python/plane_tracker.py
+++ b/samples/python/plane_tracker.py
@@ -38,6 +38,7 @@ from collections import namedtuple
 # local modules
 import video
 import common
+from video import presets
 
 
 FLANN_INDEX_KDTREE = 1
@@ -139,7 +140,7 @@ class PlaneTracker:
 
 class App:
     def __init__(self, src):
-        self.cap = video.create_capture(src)
+        self.cap = video.create_capture(src, presets['book'])
         self.frame = None
         self.paused = False
         self.tracker = PlaneTracker()
@@ -169,7 +170,7 @@ class App:
 
             self.rect_sel.draw(vis)
             cv2.imshow('plane', vis)
-            ch = cv2.waitKey(1) & 0xFF
+            ch = cv2.waitKey(1)
             if ch == ord(' '):
                 self.paused = not self.paused
             if ch == ord('c'):
diff --git a/samples/python/squares.py b/samples/python/squares.py
index cc33144..be28f1a 100755
--- a/samples/python/squares.py
+++ b/samples/python/squares.py
@@ -49,7 +49,7 @@ if __name__ == '__main__':
         squares = find_squares(img)
         cv2.drawContours( img, squares, -1, (0, 255, 0), 3 )
         cv2.imshow('squares', img)
-        ch = 0xFF & cv2.waitKey()
+        ch = cv2.waitKey()
         if ch == 27:
             break
     cv2.destroyAllWindows()
diff --git a/samples/python/tst_scene_render.py b/samples/python/tst_scene_render.py
new file mode 100644
index 0000000..ce956f5
--- /dev/null
+++ b/samples/python/tst_scene_render.py
@@ -0,0 +1,116 @@
+#!/usr/bin/env python
+
+
+# Python 2/3 compatibility
+from __future__ import print_function
+
+import numpy as np
+from numpy import pi, sin, cos
+
+import cv2
+
+defaultSize = 512
+
+class TestSceneRender():
+
+    def __init__(self, bgImg = None, fgImg = None,
+        deformation = False, speed = 0.25, **params):
+        self.time = 0.0
+        self.timeStep = 1.0 / 30.0
+        self.foreground = fgImg
+        self.deformation = deformation
+        self.speed = speed
+
+        if bgImg is not None:
+            self.sceneBg = bgImg.copy()
+        else:
+            self.sceneBg = np.zeros(defaultSize, defaultSize, np.uint8)
+
+        self.w = self.sceneBg.shape[0]
+        self.h = self.sceneBg.shape[1]
+
+        if fgImg is not None:
+            self.foreground = fgImg.copy()
+            self.center = self.currentCenter = (int(self.w/2 - fgImg.shape[0]/2), int(self.h/2 - fgImg.shape[1]/2))
+
+            self.xAmpl = self.sceneBg.shape[0] - (self.center[0] + fgImg.shape[0])
+            self.yAmpl = self.sceneBg.shape[1] - (self.center[1] + fgImg.shape[1])
+
+        self.initialRect = np.array([ (self.h/2, self.w/2), (self.h/2, self.w/2 + self.w/10),
+         (self.h/2 + self.h/10, self.w/2 + self.w/10), (self.h/2 + self.h/10, self.w/2)]).astype(int)
+        self.currentRect = self.initialRect
+
+    def getXOffset(self, time):
+        return int( self.xAmpl*cos(time*self.speed))
+
+
+    def getYOffset(self, time):
+        return int(self.yAmpl*sin(time*self.speed))
+
+    def setInitialRect(self, rect):
+        self.initialRect = rect
+
+    def getRectInTime(self, time):
+
+        if self.foreground is not None:
+            tmp = np.array(self.center) + np.array((self.getXOffset(time), self.getYOffset(time)))
+            x0, y0 = tmp
+            x1, y1 = tmp + self.foreground.shape[0:2]
+            return np.array([y0, x0, y1, x1])
+        else:
+            x0, y0 = self.initialRect[0] + np.array((self.getXOffset(time), self.getYOffset(time)))
+            x1, y1 = self.initialRect[2] + np.array((self.getXOffset(time), self.getYOffset(time)))
+            return np.array([y0, x0, y1, x1])
+
+    def getCurrentRect(self):
+
+        if self.foreground is not None:
+
+            x0 = self.currentCenter[0]
+            y0 = self.currentCenter[1]
+            x1 = self.currentCenter[0] + self.foreground.shape[0]
+            y1 = self.currentCenter[1] + self.foreground.shape[1]
+            return np.array([y0, x0, y1, x1])
+        else:
+            x0, y0 = self.currentRect[0]
+            x1, y1 = self.currentRect[2]
+            return np.array([x0, y0, x1, y1])
+
+    def getNextFrame(self):
+        img = self.sceneBg.copy()
+
+        if self.foreground is not None:
+            self.currentCenter = (self.center[0] + self.getXOffset(self.time), self.center[1] + self.getYOffset(self.time))
+            img[self.currentCenter[0]:self.currentCenter[0]+self.foreground.shape[0],
+             self.currentCenter[1]:self.currentCenter[1]+self.foreground.shape[1]] = self.foreground
+        else:
+            self.currentRect = self.initialRect + np.int( 30*cos(self.time*self.speed) + 50*sin(self.time*self.speed))
+            if self.deformation:
+                self.currentRect[1:3] += self.h/20*cos(self.time)
+            cv2.fillConvexPoly(img, self.currentRect, (0, 0, 255))
+
+        self.time += self.timeStep
+        return img
+
+    def resetTime(self):
+        self.time = 0.0
+
+
+if __name__ == '__main__':
+
+    backGr = cv2.imread('../data/graf1.png')
+    fgr = cv2.imread('../data/box.png')
+
+    render = TestSceneRender(backGr, fgr)
+
+    while True:
+
+        img = render.getNextFrame()
+        cv2.imshow('img', img)
+
+        ch = cv2.waitKey(3)
+        if  ch == 27:
+            break
+    #import os
+    #print (os.environ['PYTHONPATH'])
+    cv2.destroyAllWindows()
diff --git a/samples/python/turing.py b/samples/python/turing.py
index f9926ba..5733d05 100755
--- a/samples/python/turing.py
+++ b/samples/python/turing.py
@@ -69,6 +69,6 @@ if __name__ == '__main__':
         vis = a.copy()
         draw_str(vis, (20, 20), 'frame %d' % frame_i)
         cv2.imshow('a', vis)
-        if 0xFF & cv2.waitKey(5) == 27:
+        if cv2.waitKey(5) == 27:
             break
     cv2.destroyAllWindows()
diff --git a/samples/python/tutorial_code/core/mat_mask_operations/mat_mask_operations.py b/samples/python/tutorial_code/core/mat_mask_operations/mat_mask_operations.py
new file mode 100644
index 0000000..82208fa
--- /dev/null
+++ b/samples/python/tutorial_code/core/mat_mask_operations/mat_mask_operations.py
@@ -0,0 +1,57 @@
+import time
+import numpy as np
+import cv2
+## [basic_method]
+def sharpen(my_image):
+    my_image = cv2.cvtColor(my_image, cv2.CV_8U)
+
+    height, width, n_channels = my_image.shape
+    result = np.zeros(my_image.shape, my_image.dtype)
+
+    ## [basic_method_loop]
+    for j in range  (1, height-1):
+        for i in range  (1, width-1):
+            for k in range  (0, n_channels):
+                sum = 5 * my_image[j, i, k] - my_image[j + 1, i, k] - my_image[j - 1, i, k]\
+                     - my_image[j, i + 1, k] - my_image[j, i - 1, k];
+
+                if sum > 255:
+                    sum = 255
+                if sum < 0:
+                    sum = 0
+
+                result[j, i, k] = sum
+    ## [basic_method_loop]
+
+    return result
+## [basic_method]
+
+
+I = cv2.imread("../data/lena.jpg")
+cv2.imshow('Input Image', I)
+
+t = round(time.time())
+J = sharpen(I)
+t = (time.time() - t)/1000
+print "Hand written function times passed in seconds: %s" % t
+
+cv2.imshow('Output Image', J)
+
+t = time.time()
+## [kern]
+kernel = np.array([ [0,-1,0],
+                    [-1,5,-1],
+                    [0,-1,0] ],np.float32) # kernel should be floating point type
+## [kern]
+
+## [filter2D]
+K = cv2.filter2D(I, -1, kernel) # ddepth = -1, means destination image has depth same as input image.
+## [filter2D]
+
+t = (time.time() - t)/1000
+print "Built-in filter2D time passed in seconds:      %s" % t
+
+cv2.imshow('filter2D Output Image', K)
+
+cv2.waitKey(0)
+cv2.destroyAllWindows()
diff --git a/samples/python/tutorial_code/introduction/documentation/documentation.py b/samples/python/tutorial_code/introduction/documentation/documentation.py
new file mode 100644
index 0000000..bbd3e17
--- /dev/null
+++ b/samples/python/tutorial_code/introduction/documentation/documentation.py
@@ -0,0 +1,5 @@
+print('Not showing this text because it is outside the snippet')
+
+## [hello_world]
+print('Hello world!')
+## [hello_world]
diff --git a/samples/python/video.py b/samples/python/video.py
index 52faaae..be15641 100755
--- a/samples/python/video.py
+++ b/samples/python/video.py
@@ -41,6 +41,7 @@ import cv2
 from time import clock
 
 # local modules
+from tst_scene_render import TestSceneRender
 import common
 
 class VideoSynthBase(object):
@@ -81,6 +82,30 @@ class VideoSynthBase(object):
     def isOpened(self):
         return True
 
+class Book(VideoSynthBase):
+    def __init__(self, **kw):
+        super(Book, self).__init__(**kw)
+        backGr = cv2.imread('../data/graf1.png')
+        fgr = cv2.imread('../data/box.png')
+        self.render = TestSceneRender(backGr, fgr, speed = 1)
+
+    def read(self, dst=None):
+        noise = np.zeros(self.render.sceneBg.shape, np.int8)
+        cv2.randn(noise, np.zeros(3), np.ones(3)*255*self.noise)
+
+        return True, cv2.add(self.render.getNextFrame(), noise, dtype=cv2.CV_8UC3)
+
+class Cube(VideoSynthBase):
+    def __init__(self, **kw):
+        super(Cube, self).__init__(**kw)
+        self.render = TestSceneRender(cv2.imread('../data/pca_test1.jpg'), deformation = True,  speed = 1)
+
+    def read(self, dst=None):
+        noise = np.zeros(self.render.sceneBg.shape, np.int8)
+        cv2.randn(noise, np.zeros(3), np.ones(3)*255*self.noise)
+
+        return True, cv2.add(self.render.getNextFrame(), noise, dtype=cv2.CV_8UC3)
+
 class Chess(VideoSynthBase):
     def __init__(self, **kw):
         super(Chess, self).__init__(**kw)
@@ -129,12 +154,14 @@ class Chess(VideoSynthBase):
         self.draw_quads(dst, self.black_quads, (10, 10, 10))
 
 
-classes = dict(chess=Chess)
+classes = dict(chess=Chess, book=Book, cube=Cube)
 
 presets = dict(
     empty = 'synth:',
     lena = 'synth:bg=../data/lena.jpg:noise=0.1',
-    chess = 'synth:class=chess:bg=../data/lena.jpg:noise=0.1:size=640x480'
+    chess = 'synth:class=chess:bg=../data/lena.jpg:noise=0.1:size=640x480',
+    book = 'synth:class=book:bg=../data/graf1.png:noise=0.1:size=640x480',
+    cube = 'synth:class=cube:bg=../data/pca_test1.jpg:noise=0.0:size=640x480'
 )
 
 
@@ -190,7 +217,7 @@ if __name__ == '__main__':
             ret, img = cap.read()
             imgs.append(img)
             cv2.imshow('capture %d' % i, img)
-        ch = 0xFF & cv2.waitKey(1)
+        ch = cv2.waitKey(1)
         if ch == 27:
             break
         if ch == ord(' '):
diff --git a/samples/python/video_threaded.py b/samples/python/video_threaded.py
index 76d764b..896a5c3 100755
--- a/samples/python/video_threaded.py
+++ b/samples/python/video_threaded.py
@@ -81,7 +81,7 @@ if __name__ == '__main__':
             else:
                 task = DummyTask(process_frame(frame, t))
             pending.append(task)
-        ch = 0xFF & cv2.waitKey(1)
+        ch = cv2.waitKey(1)
         if ch == ord(' '):
             threaded_mode = not threaded_mode
         if ch == 27:
diff --git a/samples/python/video_v4l2.py b/samples/python/video_v4l2.py
index 9ef958e..0af68e5 100644
--- a/samples/python/video_v4l2.py
+++ b/samples/python/video_v4l2.py
@@ -27,7 +27,7 @@ font = cv2.FONT_HERSHEY_SIMPLEX
 color = (0, 255, 0)
 
 cap = cv2.VideoCapture(0)
-cap.set(cv2.CAP_PROP_AUTOFOCUS, False)  # Known bug: https://github.com/Itseez/opencv/pull/5474
+cap.set(cv2.CAP_PROP_AUTOFOCUS, False)  # Known bug: https://github.com/opencv/opencv/pull/5474
 
 cv2.namedWindow("Video")
 
@@ -58,10 +58,10 @@ while True:
     cv2.putText(img, "FPS: {}".format(fps), (15, 80), font, 1.0, color)
     cv2.imshow("Video", img)
 
-    k = 0xFF & cv2.waitKey(1)
+    k = cv2.waitKey(1)
 
     if k == 27:
         break
-    elif k == ord("g"):
+    elif k == ord('g'):
         convert_rgb = not convert_rgb
         cap.set(cv2.CAP_PROP_CONVERT_RGB, convert_rgb)
diff --git a/samples/python/watershed.py b/samples/python/watershed.py
index 6d349e1..30be82c 100755
--- a/samples/python/watershed.py
+++ b/samples/python/watershed.py
@@ -55,8 +55,8 @@ class App:
         cv2.imshow('watershed', vis)
 
     def run(self):
-        while True:
-            ch = 0xFF & cv2.waitKey(50)
+        while cv2.getWindowProperty('img', 0) != -1 or cv2.getWindowProperty('watershed', 0) != -1:
+            ch = cv2.waitKey(50)
             if ch == 27:
                 break
             if ch >= ord('1') and ch <= ord('7'):
diff --git a/samples/tapi/bgfg_segm.cpp b/samples/tapi/bgfg_segm.cpp
index 4058771..ff097dc 100644
--- a/samples/tapi/bgfg_segm.cpp
+++ b/samples/tapi/bgfg_segm.cpp
@@ -17,11 +17,11 @@ using namespace cv;
 int main(int argc, const char** argv)
 {
     CommandLineParser cmd(argc, argv,
-        "{ c camera   | false       | use camera }"
-        "{ f file     | ../data/768x576.avi | input video file }"
-        "{ t type     | mog2        | method's type (knn, mog2) }"
-        "{ h help     | false       | print help message }"
-        "{ m cpu_mode | false       | press 'm' to switch OpenCL<->CPU}");
+        "{ c camera   |                    | use camera }"
+        "{ f file     | ../data/vtest.avi  | input video file }"
+        "{ t type     | mog2               | method's type (knn, mog2) }"
+        "{ h help     |                    | print help message }"
+        "{ m cpu_mode | false              | press 'm' to switch OpenCL<->CPU}");
 
     if (cmd.has("help"))
     {
diff --git a/samples/tapi/camshift.cpp b/samples/tapi/camshift.cpp
index c0f1d8f..324e073 100644
--- a/samples/tapi/camshift.cpp
+++ b/samples/tapi/camshift.cpp
@@ -1,9 +1,9 @@
 #include "opencv2/core/utility.hpp"
 #include "opencv2/core/ocl.hpp"
 #include "opencv2/video/tracking.hpp"
-#include "opencv2/imgproc/imgproc.hpp"
-#include "opencv2/videoio/videoio.hpp"
-#include "opencv2/highgui/highgui.hpp"
+#include "opencv2/imgproc.hpp"
+#include "opencv2/videoio.hpp"
+#include "opencv2/highgui.hpp"
 
 #include <iostream>
 #include <cctype>
diff --git a/samples/tapi/clahe.cpp b/samples/tapi/clahe.cpp
index 905ea1f..b663b02 100644
--- a/samples/tapi/clahe.cpp
+++ b/samples/tapi/clahe.cpp
@@ -1,11 +1,11 @@
 #include <iostream>
-#include "opencv2/core/core.hpp"
+#include "opencv2/core.hpp"
 #include "opencv2/core/ocl.hpp"
 #include "opencv2/core/utility.hpp"
-#include "opencv2/imgproc/imgproc.hpp"
+#include "opencv2/imgproc.hpp"
 #include "opencv2/imgcodecs.hpp"
 #include "opencv2/videoio.hpp"
-#include "opencv2/highgui/highgui.hpp"
+#include "opencv2/highgui.hpp"
 
 using namespace cv;
 using namespace std;
@@ -33,7 +33,7 @@ int main(int argc, char** argv)
         "{ i input    |                    | specify input image }"
         "{ c camera   |  0                 | specify camera id   }"
         "{ o output   | clahe_output.jpg   | specify output save path}"
-        "{ h help     | false              | print help message }";
+        "{ h help     |                    | print help message }";
 
     cv::CommandLineParser cmd(argc, argv, keys);
     if (cmd.has("help"))
diff --git a/samples/tapi/hog.cpp b/samples/tapi/hog.cpp
index e361c2b..1ead0d9 100644
--- a/samples/tapi/hog.cpp
+++ b/samples/tapi/hog.cpp
@@ -68,18 +68,16 @@ private:
 int main(int argc, char** argv)
 {
     const char* keys =
-        "{ h help      | false          | print help message }"
+        "{ h help      |                | print help message }"
         "{ i input     |                | specify input image}"
         "{ c camera    | -1             | enable camera capturing }"
-        "{ v video     | ../data/768x576.avi | use video as input }"
-        "{ g gray      | false          | convert image to gray one or not}"
+        "{ v video     | ../data/vtest.avi | use video as input }"
+        "{ g gray      |                | convert image to gray one or not}"
         "{ s scale     | 1.0            | resize the image before detect}"
         "{ o output    |                | specify output path when input is images}";
     CommandLineParser cmd(argc, argv, keys);
     if (cmd.has("help"))
     {
-        cout << "Usage : hog [options]" << endl;
-        cout << "Available options:" << endl;
         cmd.printMessage();
         return EXIT_SUCCESS;
     }
diff --git a/samples/tapi/pyrlk_optical_flow.cpp b/samples/tapi/pyrlk_optical_flow.cpp
index 9cdbd7c..bb426cb 100644
--- a/samples/tapi/pyrlk_optical_flow.cpp
+++ b/samples/tapi/pyrlk_optical_flow.cpp
@@ -75,7 +75,7 @@ static void drawArrows(UMat& _frame, const vector<Point2f>& prevPts, const vecto
 int main(int argc, const char* argv[])
 {
     const char* keys =
-        "{ h help           | false           | print help message }"
+        "{ h help           |                 | print help message }"
         "{ l left           |                 | specify left image }"
         "{ r right          |                 | specify right image }"
         "{ c camera         | 0               | enable camera capturing }"
diff --git a/samples/tapi/squares.cpp b/samples/tapi/squares.cpp
index e18e533..8300b9c 100644
--- a/samples/tapi/squares.cpp
+++ b/samples/tapi/squares.cpp
@@ -5,9 +5,9 @@
 #include "opencv2/core.hpp"
 #include "opencv2/core/ocl.hpp"
 #include "opencv2/core/utility.hpp"
-#include "opencv2/imgproc/imgproc.hpp"
+#include "opencv2/imgproc.hpp"
 #include "opencv2/imgcodecs.hpp"
-#include "opencv2/highgui/highgui.hpp"
+#include "opencv2/highgui.hpp"
 #include <iostream>
 #include <string.h>
 
@@ -143,8 +143,8 @@ int main(int argc, char** argv)
     const char* keys =
         "{ i input    | ../data/pic1.png   | specify input image }"
         "{ o output   | squares_output.jpg | specify output save path}"
-        "{ h help     | false              | print help message }"
-        "{ m cpu_mode | false              | run without OpenCL }";
+        "{ h help     |                    | print help message }"
+        "{ m cpu_mode |                    | run without OpenCL }";
 
     CommandLineParser cmd(argc, argv, keys);
 
diff --git a/samples/tapi/tvl1_optical_flow.cpp b/samples/tapi/tvl1_optical_flow.cpp
index f7bebac..5efa4e2 100644
--- a/samples/tapi/tvl1_optical_flow.cpp
+++ b/samples/tapi/tvl1_optical_flow.cpp
@@ -6,8 +6,8 @@
 #include "opencv2/core/utility.hpp"
 #include "opencv2/imgcodecs.hpp"
 #include "opencv2/videoio.hpp"
-#include "opencv2/highgui/highgui.hpp"
-#include "opencv2/video/video.hpp"
+#include "opencv2/highgui.hpp"
+#include "opencv2/video.hpp"
 
 using namespace std;
 using namespace cv;
@@ -83,12 +83,12 @@ static void getFlowField(const Mat& u, const Mat& v, Mat& flowField)
 int main(int argc, const char* argv[])
 {
     const char* keys =
-        "{ h help     | false           | print help message }"
+        "{ h help     |                 | print help message }"
         "{ l left     |                 | specify left image }"
         "{ r right    |                 | specify right image }"
         "{ o output   | tvl1_output.jpg | specify output save path }"
         "{ c camera   | 0               | enable camera capturing }"
-        "{ m cpu_mode | false           | run without OpenCL }"
+        "{ m cpu_mode |                 | run without OpenCL }"
         "{ v video    |                 | use video as input }";
 
     CommandLineParser cmd(argc, argv, keys);
diff --git a/samples/tapi/ufacedetect.cpp b/samples/tapi/ufacedetect.cpp
index f6dc0ce..874300a 100644
--- a/samples/tapi/ufacedetect.cpp
+++ b/samples/tapi/ufacedetect.cpp
@@ -78,9 +78,9 @@ int main( int argc, const char** argv )
 
     if( inputName.empty() || (isdigit(inputName[0]) && inputName.size() == 1) )
     {
-        int c = inputName.empty() ? 0 : inputName[0] - '0';
-        if(!capture.open(c))
-            cout << "Capture from camera #" <<  c << " didn't work" << endl;
+        int camera = inputName.empty() ? 0 : inputName[0] - '0';
+        if(!capture.open(camera))
+            cout << "Capture from camera #" <<  camera << " didn't work" << endl;
     }
     else
     {
@@ -105,7 +105,7 @@ int main( int argc, const char** argv )
 
             detectAndDraw( frame, canvas, cascade, nestedCascade, scale, tryflip );
 
-            int c = waitKey(10);
+            char c = (char)waitKey(10);
             if( c == 27 || c == 'q' || c == 'Q' )
                 break;
         }
@@ -128,7 +128,7 @@ int main( int argc, const char** argv )
                 char buf[1000+1];
                 while( fgets( buf, 1000, f ) )
                 {
-                    int len = (int)strlen(buf), c;
+                    int len = (int)strlen(buf);
                     while( len > 0 && isspace(buf[len-1]) )
                         len--;
                     buf[len] = '\0';
@@ -137,7 +137,7 @@ int main( int argc, const char** argv )
                     if( !image.empty() )
                     {
                         detectAndDraw( image, canvas, cascade, nestedCascade, scale, tryflip );
-                        c = waitKey(0);
+                        char c = (char)waitKey(0);
                         if( c == 27 || c == 'q' || c == 'Q' )
                             break;
                     }
@@ -195,7 +195,7 @@ void detectAndDraw( UMat& img, Mat& canvas, CascadeClassifier& cascade,
                                  //|CASCADE_DO_ROUGH_SEARCH
                                  |CASCADE_SCALE_IMAGE,
                                  Size(30, 30) );
-        for( vector<Rect>::const_iterator r = faces2.begin(); r != faces2.end(); r++ )
+        for( vector<Rect>::const_iterator r = faces2.begin(); r != faces2.end(); ++r )
         {
             faces.push_back(Rect(smallImg.cols - r->x - r->width, r->y, r->width, r->height));
         }
diff --git a/samples/winrt/FaceDetection/FaceDetection/MainPage.xaml.cpp b/samples/winrt/FaceDetection/FaceDetection/MainPage.xaml.cpp
index ed5e8d7..e0ec27a 100644
--- a/samples/winrt/FaceDetection/FaceDetection/MainPage.xaml.cpp
+++ b/samples/winrt/FaceDetection/FaceDetection/MainPage.xaml.cpp
@@ -7,9 +7,9 @@
 #include "MainPage.xaml.h"
 
 #include <opencv2\imgproc\types_c.h>
-#include <opencv2\imgcodecs\imgcodecs.hpp>
-#include <opencv2\core\core.hpp>
-#include <opencv2\imgproc\imgproc.hpp>
+#include <opencv2\imgcodecs.hpp>
+#include <opencv2\core.hpp>
+#include <opencv2\imgproc.hpp>
 #include <opencv2\highgui.hpp>
 #include <opencv2\highgui\highgui_winrt.hpp>
 
@@ -78,4 +78,4 @@ void FaceDetection::MainPage::detectBtn_Click(Platform::Object^ sender, Windows:
     } else {
         Windows::UI::Popups::MessageDialog("Initialize image before processing \n").ShowAsync();
     }
-}
\ No newline at end of file
+}
diff --git a/samples/winrt/ImageManipulations/MediaExtensions/OcvTransform/OcvTransform.cpp b/samples/winrt/ImageManipulations/MediaExtensions/OcvTransform/OcvTransform.cpp
index 56193c1..a2854d2 100644
--- a/samples/winrt/ImageManipulations/MediaExtensions/OcvTransform/OcvTransform.cpp
+++ b/samples/winrt/ImageManipulations/MediaExtensions/OcvTransform/OcvTransform.cpp
@@ -8,9 +8,9 @@
 #include "OcvTransform.h"
 #include "bufferlock.h"
 
-#include <opencv2\core\core.hpp>
-#include <opencv2\imgproc\imgproc.hpp>
-#include <opencv2\features2d\features2d.hpp>
+#include <opencv2\core.hpp>
+#include <opencv2\imgproc.hpp>
+#include <opencv2\features2d.hpp>
 
 
 
diff --git a/samples/winrt/OcvImageProcessing/OcvImageProcessing/MainPage.xaml.cpp b/samples/winrt/OcvImageProcessing/OcvImageProcessing/MainPage.xaml.cpp
index fc7440f..c911787 100644
--- a/samples/winrt/OcvImageProcessing/OcvImageProcessing/MainPage.xaml.cpp
+++ b/samples/winrt/OcvImageProcessing/OcvImageProcessing/MainPage.xaml.cpp
@@ -10,8 +10,8 @@
 #include <Robuffer.h>
 #include <vector>
 #include <opencv2\imgproc\types_c.h>
-#include <opencv2\imgcodecs\imgcodecs.hpp>
-#include <opencv2\core\core.hpp>
+#include <opencv2\imgcodecs.hpp>
+#include <opencv2\core.hpp>
 
 #include <windows.storage.h>
 
diff --git a/samples/winrt_universal/PhoneTutorial/MainPage.xaml.cpp b/samples/winrt_universal/PhoneTutorial/MainPage.xaml.cpp
index 045698b..de3c554 100644
--- a/samples/winrt_universal/PhoneTutorial/MainPage.xaml.cpp
+++ b/samples/winrt_universal/PhoneTutorial/MainPage.xaml.cpp
@@ -7,8 +7,8 @@
 #include "MainPage.xaml.h"
 
 #include <opencv2\imgproc\types_c.h>
-#include <opencv2\core\core.hpp>
-#include <opencv2\imgproc\imgproc.hpp>
+#include <opencv2\core.hpp>
+#include <opencv2\imgproc.hpp>
 #include <Robuffer.h>
 #include <ppl.h>
 #include <ppltasks.h>
diff --git a/samples/wp8/OcvImageManipulation/PhoneXamlDirect3DApp1/PhoneXamlDirect3DApp1Comp/Direct3DInterop.cpp b/samples/wp8/OcvImageManipulation/PhoneXamlDirect3DApp1/PhoneXamlDirect3DApp1Comp/Direct3DInterop.cpp
index cb00c7d..f3e3a01 100644
--- a/samples/wp8/OcvImageManipulation/PhoneXamlDirect3DApp1/PhoneXamlDirect3DApp1Comp/Direct3DInterop.cpp
+++ b/samples/wp8/OcvImageManipulation/PhoneXamlDirect3DApp1/PhoneXamlDirect3DApp1Comp/Direct3DInterop.cpp
@@ -4,9 +4,9 @@
 #include <windows.storage.streams.h>
 #include <wrl.h>
 #include <robuffer.h>
-#include <opencv2\core\core.hpp>
-#include <opencv2\imgproc\imgproc.hpp>
-#include <opencv2\features2d\features2d.hpp>
+#include <opencv2\core.hpp>
+#include <opencv2\imgproc.hpp>
+#include <opencv2\features2d.hpp>
 #include <algorithm>
 
 using namespace Windows::Storage::Streams;
diff --git a/samples/wp8/OpenCVXaml/OpenCVComponent/OpenCVComponent.cpp b/samples/wp8/OpenCVXaml/OpenCVComponent/OpenCVComponent.cpp
index ce309d5..7e0c0df 100644
--- a/samples/wp8/OpenCVXaml/OpenCVComponent/OpenCVComponent.cpp
+++ b/samples/wp8/OpenCVXaml/OpenCVComponent/OpenCVComponent.cpp
@@ -3,8 +3,8 @@
 #include "OpenCVComponent.h"
 
 #include <opencv2\imgproc\types_c.h>
-#include <opencv2\core\core.hpp>
-#include <opencv2\imgproc\imgproc.hpp>
+#include <opencv2\core.hpp>
+#include <opencv2\imgproc.hpp>
 #include <vector>
 #include <algorithm>
 
@@ -63,5 +63,4 @@ void CopyMatrixToVector(const cv::Mat& mat, std::vector<int>& vector, int size)
     {
         vector.push_back(data[i]);
     }
-
-}
\ No newline at end of file
+}

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-science/packages/opencv.git



More information about the debian-science-commits mailing list